[
  {
    "path": ".clang-format",
    "content": "---\nLanguage: Cpp\nBasedOnStyle: LLVM\nDisableFormat: false\n\n# Indentation\nIndentWidth: 4\nContinuationIndentWidth: 4\nTabWidth: 4\nUseTab: Never\n\n# Braces\nBreakBeforeBraces: Attach\nBraceWrapping:\n  AfterControlStatement: false\n  AfterFunction: false\n  AfterEnum: false\n  AfterClass: false\n  AfterStruct: false\n  AfterUnion: false\n  BeforeElse: false\n  BeforeCatch: false\n  BeforeLambdaBody: false\n\n# Alignment\nAlignAfterOpenBracket: Align\nAlignTrailingComments: true\nAlignConsecutiveAssignments: None\nAlignConsecutiveBitFields: None\nAlignConsecutiveDeclarations: None\nAlignConsecutiveMacros: None\n\n# Spacing\nSpaceAfterCStyleCast: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nSpacesBeforeTrailingComments: 1\n\n# Column limit\nColumnLimit: 120\n\n# Short constructs\nAllowShortBlocksOnASingleLine: Never\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortEnumsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: None\nAllowShortIfStatementsOnASingleLine: Never\nAllowShortLoopsOnASingleLine: false\n\n# Line breaking\nAlwaysBreakAfterReturnType: None\nBreakBeforeBinaryOperators: None\nBreakBeforeTernaryOperators: true\n\n# Functions\nIndentWrappedFunctionNames: false\nMaxEmptyLinesToKeep: 1\n\n# Includes\nIncludeBlocks: Preserve\nSortIncludes: Never\n\n# Initializers\nAllowAllConstructorInitializersOnNextLine: true\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nConstructorInitializerIndentWidth: 4\nCpp11BracedListStyle: false\nBinPackArguments: false\nBinPackParameters: false\n\n# Preprocessor/Macros\nIndentPPDirectives: None\n\n# Misc\nKeepEmptyLinesAtTheStartOfBlocks: false\nReflowComments: false\nSeparateDefinitionBlocks: Leave\n\n# Penalties\nPenaltyBreakAssignment: 100\nPenaltyBreakBeforeFirstCallParameter: 100\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 1000\nPenaltyBreakTemplateDeclaration: 1000\n\n---\nLanguage: ObjC\nBasedOnStyle: LLVM\nDisableFormat: true\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.mpp linguist-language=C++\n*.cppm linguist-language=C++\n*.ixx linguist-language=C++\n"
  },
  {
    "path": ".github/workflows/alpine.yml",
    "content": "name: Alpine\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.ALPINE_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n\n    container: alpine:latest\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Alpine\n        cancel-in-progress: true\n    steps:\n      - name: Prepare build tools\n        run: |\n          uname -a\n          apk --no-cache add grep linux-headers bash curl git unzip build-base tar 7zip perl\n\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: prepare local xmake\n        run: |\n          cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n\n      - name: Tests\n        env:\n          XMAKE_ROOT: y\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n"
  },
  {
    "path": ".github/workflows/archlinux.yml",
    "content": "name: Archlinux\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.ARCHLINUX_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n\n    container: archlinux:base-devel\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Archlinux\n        cancel-in-progress: true\n    steps:\n      - name: Prepare build tools\n        run: |\n          pacman -Syu --noconfirm --needed openssl\n          pacman -Sy --noconfirm --needed glibc git base-devel perl make unzip\n          pacman -Sy --noconfirm --needed mesa gcc-fortran glu\n          git config --global --add safe.directory /__w/xmake/xmake\n\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: prepare local xmake\n        run: |\n          cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n\n      - name: Tests\n        env:\n          XMAKE_ROOT: y\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n"
  },
  {
    "path": ".github/workflows/cosmocc.yml",
    "content": "name: Cosmocc\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 50%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.COSMOCC_RUN_PROBABILITY || '0.5' }}\n\n  build:\n    #needs: check\n    #if: needs.check.outputs.should-run == 'true'\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-15-intel]\n        arch: [x86_64]\n\n    runs-on: ${{ matrix.os }}\n\n    concurrency:\n      group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Cosmocc-${{ matrix.os }}-${{ matrix.arch }}\n      cancel-in-progress: true\n\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Prepare local xmake\n        run: cp -rf . ../xmake-source\n\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n\n      - uses: bjia56/setup-cosmocc@main\n        with:\n          version: \"4.0.2\"\n\n      - name: Build\n        run: |\n          cd core\n          xmake f -p linux --cosmocc=y --embed=y -y -cvD\n          xmake -v\n          cd ..\n\n      - name: Prepare (Linux)\n        if: matrix.os == 'ubuntu-latest'\n        run: |\n          sudo apt update\n          sudo apt install -y ruby ruby-dev rubygems build-essential llvm libc++-dev\n          sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev\n          clang --version\n\n      # In the tests, cmake tries to use make from the cosmopolitan toolchain and fails, so uninstall it\n      - name: Remove cosmocc\n        if: startsWith(matrix.os, 'macos')\n        run: |\n          INSTALL_DIR=\"${{runner.temp}}/cosmocc-4.0.2\"\n          echo \"Removing cosmocc from PATH\"\n          echo \"::remove-path::${INSTALL_DIR}/bin\"\n          rm -r \"${INSTALL_DIR}\"\n\n      - name: Tests\n        run: |\n          ls -l core/build/\n          cmake --version\n          core/build/xmake --version\n          core/build/xmake lua -v -D tests/run.lua\n\n      - name: Artifact\n        if: matrix.os == 'ubuntu-latest'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-bundle.cosmocc\n          path: core/build/xmake\n\n      - name: Publish bundle binary\n        if: github.event.action == 'published' && matrix.os == 'ubuntu-latest'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: core/build/xmake\n          asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.cosmocc\n          asset_content_type: application/zip\n"
  },
  {
    "path": ".github/workflows/dragonflybsd.yml",
    "content": "name: DragonflyBSD\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.DRAGONFLYBSD_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-DragonflyBSD\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/dragonflybsd-vm@v1\n        with:\n          usesh: true\n          mem: 4096\n          copyback: false\n          prepare: |\n            pkg install -y git curl unzip gmake llvm libc++ gsed bash perl5\n          run: |\n            ./configure\n            gmake -j4\n            gmake install\n            export XMAKE_ROOT=y\n            xrepo --version\n            xmake l os.meminfo\n            xmake lua -v -D tests/run.lua\n"
  },
  {
    "path": ".github/workflows/fedora.yml",
    "content": "name: Fedora\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n            \n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n            \n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n            \n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n            \n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.FEDORA_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n\n    container: fedora:latest\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Fedora\n        cancel-in-progress: true\n    steps:\n      - name: Prepare build tools\n        run: |\n          uname -a\n          dnf -y install @development-tools @rpm-development-tools\n          dnf -y install mesa-libGL-devel mesa-libGLU-devel\n          dnf -y install copr-cli make gcc-c++\n          dnf -y install perl\n          dnf -y upgrade git\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n      - name: Prepare local xmake\n        run: |\n          cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n\n      - name: Tests\n        env:\n          XMAKE_ROOT: y\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n"
  },
  {
    "path": ".github/workflows/freebsd.yml",
    "content": "name: FreeBSD\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 50%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.FREEBSD_RUN_PROBABILITY || '0.5' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-FreeBSD\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/freebsd-vm@v1\n        with:\n          usesh: true\n          mem: 4096\n          copyback: false\n          prepare: pkg install -y git curl unzip gmake llvm gsed bash perl5\n          run: |\n            ./configure\n            gmake -j4\n            gmake install\n            export XMAKE_ROOT=y\n            xrepo --version\n            xmake l os.meminfo\n            xmake lua -v -D tests/run.lua\n\n\n"
  },
  {
    "path": ".github/workflows/haiku.yml",
    "content": "name: Haiku\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60));\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0;\n            }\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.HAIKU_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n      group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Haiku\n      cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/haiku-vm@v1\n        with:\n          usesh: true\n          mem: 4096\n          copyback: false\n          prepare: |\n            pkgman install -y git curl unzip make bash perl\n          run: |\n            ./configure --prefix=`pwd`/dist\n            make -j2\n            make install\n            export XMAKE_ROOT=y\n            export PATH=`pwd`/dist/bin:$PATH\n            xrepo --version\n            xmake lua -v -D tests/run.lua\n"
  },
  {
    "path": ".github/workflows/issue-translator.yml",
    "content": "name: 'issue-translator'\non:\n  issue_comment:\n    types: [created]\n  issues:\n    types: [opened]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: usthe/issues-translate-action@v2.7\n        with:\n          IS_MODIFY_TITLE: false\n          CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically.\n"
  },
  {
    "path": ".github/workflows/linux.yml",
    "content": "name: Linux\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Linux\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n      - name: prepare local xmake\n        run: cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n      - uses: dlang-community/setup-dlang@v1\n        with:\n          compiler: dmd-latest\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Prepare\n        run: |\n          sudo apt update\n          sudo apt install -y ruby ruby-dev rubygems build-essential llvm libc++-dev\n          sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev\n          clang --version\n          xrepo install -y zig\n\n      - name: Tests\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n\n      - name: Artifact\n        run: |\n          cd core\n          xrepo env -b zig xmake f --embed=y --toolchain=zig --cross=x86_64-linux-musl -c\n          xmake\n          mkdir ../artifacts\n          cp build/xmake ../artifacts/xmake-bundle\n          cd ..\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-bundle.linux.x86_64\n          path: artifacts/xmake-bundle\n\n      - name: Publish\n        if: github.event.action == 'published'\n        env:\n          PPA_GPG_PRIKEY_2C0C68C9: ${{ secrets.PPA_GPG_PRIKEY_2C0C68C9 }}\n        run: |\n          # upload ubuntu/ppa\n          sudo apt install -y dh-make rng-tools devscripts lintian\n          echo \"$PPA_GPG_PRIKEY_2C0C68C9\" > ppa_gpg.key\n          gpg --import ppa_gpg.key\n          scripts/makeppa questing # 25.10\n          scripts/makeppa plucky # 25.04\n          scripts/makeppa noble # 24.04\n          scripts/makeppa mantic # 23.10\n          scripts/makeppa lunar # 23.04\n          scripts/makeppa kinetic # 22.10\n          scripts/makeppa jammy # 22.04\n          scripts/makeppa focal # 20.04\n          scripts/makeppa bionic # 18.04\n          scripts/makeppa xenial # 16.04\n          scripts/makeppa trusty # 14.04\n\n      - name: Publish bundle binary\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake-bundle\n          asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.linux.x86_64\n          asset_content_type: application/zip\n"
  },
  {
    "path": ".github/workflows/linux_arm64.yml",
    "content": "name: Linux (Arm64)\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  build:\n    runs-on: ubuntu-24.04-arm\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Ubuntu-Arm64\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n      - name: prepare local xmake\n        run: cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n\n      - name: Prepare\n        run: |\n          sudo apt update\n          sudo apt install -y unzip build-essential llvm libc++-dev\n\n      - name: Tests\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n\n"
  },
  {
    "path": ".github/workflows/linux_luajit.yml",
    "content": "name: Linux (Luajit)\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n            \n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n            \n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n            \n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n            \n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.LINUX_LUAJIT_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Linux-Luajit\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n      - uses: dlang-community/setup-dlang@v1\n        with:\n          compiler: dmd-latest\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Installation\n        run: |\n          ./configure --runtime=luajit\n          make -j`nproc`\n          ./scripts/get.sh __local__ __install_only__\n          source ~/.xmake/profile\n          xmake --version\n\n      - name: Prepare\n        run: |\n          sudo apt update\n          sudo apt install -y build-essential llvm libc++-dev\n          sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev\n\n      - name: Tests\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n"
  },
  {
    "path": ".github/workflows/macos.yml",
    "content": "name: macOS (x86_64)\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  build:\n\n    strategy:\n      matrix:\n        os: [macos-15-intel]\n        arch: [x86_64]\n\n    runs-on: ${{ matrix.os }}\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-macOS-${{ matrix.arch }}\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          # WyriHaximus/github-action-get-previous-tag@master need it\n          fetch-depth: 0\n          submodules: true\n\n      - name: Prepare local xmake\n        run: cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Tests\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n\n      - name: Artifact\n        run: |\n          brew install gnu-tar\n          cd core\n          xmake pack -y --autobuild=n --basename=xmake -o ../artifacts xmakesrc\n          xmake f --embed=y -c\n          xmake\n          cp build/xmake ../artifacts/xmake-bundle\n          cd ..\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.gz.run\n          path: artifacts/xmake.gz.run\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.tar.gz\n          path: artifacts/xmake.tar.gz\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.zip\n          path: artifacts/xmake.zip\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-bundle.macos.x86_64\n          path: artifacts/xmake-bundle\n\n        # upload artifacts to latest release\n      - name: Get Previous tag\n        id: previoustag\n        uses: WyriHaximus/github-action-get-previous-tag@master\n\n      - name: Upload artifacts to lastest release\n        if: github.ref == 'refs/heads/master'\n        uses: svenstaro/upload-release-action@v2\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: artifacts/xmake.zip\n          asset_name: xmake-master.zip\n          tag: ${{ steps.previoustag.outputs.tag }}\n          overwrite: true\n\n      - name: Upload artifacts to lastest release\n        if: github.ref == 'refs/heads/master'\n        uses: svenstaro/upload-release-action@v2\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: artifacts/xmake.tar.gz\n          asset_name: xmake-master.tar.gz\n          tag: ${{ steps.previoustag.outputs.tag }}\n          overwrite: true\n\n      - name: Publish gz runfile\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake.gz.run\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.gz.run\n          asset_content_type: application/zip\n\n      - name: Publish gz archive\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake.tar.gz\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.tar.gz\n          asset_content_type: application/zip\n\n      - name: Publish zip archive\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake.zip\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.zip\n          asset_content_type: application/zip\n\n      - name: Publish bundle binary\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake-bundle\n          asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.macos.x86_64\n          asset_content_type: application/zip\n"
  },
  {
    "path": ".github/workflows/macos_arm64.yml",
    "content": "name: macOS (arm64)\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  build:\n\n    strategy:\n      matrix:\n        os: [macos-latest]\n        arch: [arm64]\n\n    runs-on: ${{ matrix.os }}\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-macOS-${{ matrix.arch }}\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          # WyriHaximus/github-action-get-previous-tag@master need it\n          fetch-depth: 0\n          submodules: true\n      - name: Prepare local xmake\n        run: cp -rf . ../xmake-source\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          xmake-version: local#../xmake-source\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Tests\n        run: |\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n\n      - name: Artifact\n        run: |\n          cd core\n          xmake f --embed=y -c\n          xmake\n          mkdir ../artifacts\n          cp build/xmake ../artifacts/xmake-bundle\n          cd ..\n      - uses: actions/upload-artifact@v4\n        with:\n          name: xmake-bundle.macos.arm64\n          path: artifacts/xmake-bundle\n\n      - name: Publish bundle binary\n        if: github.event.action == 'published'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/xmake-bundle\n          asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.macos.arm64\n          asset_content_type: application/zip\n"
  },
  {
    "path": ".github/workflows/msys2_mingw.yml",
    "content": "name: MSYS2 (MingW)\n\non:\n  push:\n  pull_request:\n\njobs:\n  build:\n    runs-on: windows-latest\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-MSYS2_MINGW-${{ matrix.arch }}\n        cancel-in-progress: true\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include: [\n          { msystem: MINGW64, arch: x86_64, prefix: /mingw64 },\n          { msystem: MINGW32, arch: i686, prefix: /mingw32   }\n        ]\n\n    steps:\n\n      - uses: actions/checkout@v2\n        with:\n          path: temp\n          submodules: true\n\n      - uses: msys2/setup-msys2@v2\n        with:\n          msystem: ${{ matrix.msystem }}\n          install: git base-devel unzip mingw-w64-${{ matrix.arch }}-toolchain\n          update: true\n\n      - name: Move Checkout\n        run: |\n          Copy-Item -Path \".\\temp\" -Destination \"C:\\_\" -Recurse\n      - name: Build\n        shell: msys2 {0}\n        run: |\n          cd /C/_\n          ./configure --prefix=${{ matrix.prefix }}\n          make\n          make install\n          xmake --version\n\n      - name: Tests\n        shell: msys2 {0}\n        run: |\n          cd /C/_\n          xmake lua -v -D tests/run.lua\n          xrepo --version\n"
  },
  {
    "path": ".github/workflows/netbsd.yml",
    "content": "name: NetBSD\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n            \n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n            \n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n            \n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n            \n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.NETBSD_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-NetBSD\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/netbsd-vm@v1\n        with:\n          usesh: true\n          mem: 4096\n          copyback: false\n          prepare: |\n            /usr/sbin/pkg_add -u curl git unzip gmake llvm libcxx gsed bash perl\n            ln -sf /usr/pkg/bin/gmake /usr/pkg/bin/make\n          run: |\n            ./configure\n            gmake -j4\n            gmake install\n            export XMAKE_ROOT=y\n            xrepo --version\n            xmake l os.meminfo\n            xmake lua -v -D tests/run.lua\n"
  },
  {
    "path": ".github/workflows/openbsd.yml",
    "content": "name: OpenBSD\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n            \n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n            \n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n            \n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n            \n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.OPENBSD_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-OpenBSD\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/openbsd-vm@v1\n        with:\n          usesh: true\n          mem: 4096\n          copyback: false\n          prepare: |\n            pkg_add curl git unzip gmake llvm libc++ gsed bash perl\n            ln -sf /usr/local/bin/gmake /usr/local/bin/make\n          run: |\n            ./configure\n            gmake -j4\n            gmake install\n            export XMAKE_ROOT=y\n            xrepo --version\n            xmake l os.meminfo\n            xmake lua -v -D tests/run.lua\n"
  },
  {
    "path": ".github/workflows/solaris.yml",
    "content": "name: Solaris\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 50%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.5');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.SOLARIS_RUN_PROBABILITY || '0.5' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    runs-on: ubuntu-latest\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Solaris\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: true\n\n      - name: Tests\n        uses: vmactions/solaris-vm@v1\n        with:\n          usesh: true\n          prepare: |\n            # Try OpenCSW first (for older Solaris)\n            if command -v pkgutil >/dev/null 2>&1; then\n              pkgutil -U || true\n              pkgutil -y -i socat git gmake bash gcc4g++ 2>/dev/null || pkgutil -y -i socat git gmake bash gcc5g++ 2>/dev/null || true\n            fi\n            # Try IPS (for newer Solaris)\n            if command -v pkg >/dev/null 2>&1; then\n              pkg install --accept developer/gcc developer/build/gnu-make developer/versioning/git || true\n            fi\n          run: |\n            cd $GITHUB_WORKSPACE\n            bash ./configure\n            gmake -j4\n            gmake install\n            export XMAKE_ROOT=y\n            xrepo --version\n            xmake l os.meminfo\n            xmake lua -v -D tests/run.lua\n\n"
  },
  {
    "path": ".github/workflows/windows.yml",
    "content": "name: Windows\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  build:\n    strategy:\n      matrix:\n        os: [windows-2022, windows-2025]\n        arch: [x64, x86, arm64]\n\n    runs-on: ${{ matrix.os }}\n\n    concurrency:\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-${{ matrix.os }}-${{ matrix.arch }}-Windows\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          # WyriHaximus/github-action-get-previous-tag@master need it\n          fetch-depth: 0\n          submodules: true\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          # this is not supported, use dev branch instead\n          # xmake-version: local#\n          xmake-version: branch@dev\n      - uses: dlang-community/setup-dlang@v1\n        with:\n          compiler: dmd-latest\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      # Force xmake to a specific folder (for cache)\n      - name: Set xmake package cache path\n        run: echo \"XMAKE_PKG_CACHEDIR=$(pwd)/xmake-cache\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n      # Cache xmake dependencies\n      - name: Retrieve xmake cache for packages\n        uses: actions/cache@v3\n        with:\n          path: xmake-cache\n          key: ${{ matrix.os }}-${{ matrix.arch }}\n\n      - name: Set release arch name\n        run: |\n          if (\"${{ matrix.arch }}\" -eq \"x64\") {\n            Write-Output \"RELEASE_NAME=win64\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          } elseif (\"${{ matrix.arch }}\" -eq \"arm64\") {\n            Write-Output \"RELEASE_NAME=arm64\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          } else {\n            Write-Output \"RELEASE_NAME=win32\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          }\n\n      - name: Build\n        run: |\n          cd core\n          xmake f -vD -a ${{ matrix.arch }} --embed=y -c\n          xmake\n          xmake l os.cp build/xmake.exe ../artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe\n          xmake f -vD -a ${{ matrix.arch }} -c\n          xmake -vD\n          cd ..\n\n      - name: Artifact\n        run: |\n          cd core\n          xrepo update-repo\n          xmake pack -vD -y --formats=nsis,zip --autobuild=n -o ../artifacts/${{env.RELEASE_NAME}} --basename=xmake xmake\n          (Get-FileHash ../artifacts/${{env.RELEASE_NAME}}/xmake.zip -Algorithm SHA256).Hash.ToLower() + \" *xmake.zip`n\" | Out-File ./shafile -Encoding ASCII -NoNewLine -Append\n          Copy-Item shafile ../artifacts/${{env.RELEASE_NAME}}\n          cd ..\n\n      - name: Tests\n        if: matrix.arch != 'arm64'\n        run: |\n          Copy-Item ./core/build/xmake.exe ./xmake\n          Copy-Item ./scripts/xrepo.bat ./xmake\n          Copy-Item ./scripts/xrepo.ps1 ./xmake\n          $Env:XMAKE_MAIN_REPO = \"https://github.com/xmake-io/xmake-repo.git\"\n          $Env:XMAKE_PROGRAM_DIR = $(Resolve-Path ./xmake)\n          Set-Item -Path Env:Path -Value ($Env:XMAKE_PROGRAM_DIR + \";\" + $Env:Path)\n          xrepo --version\n          xmake show\n          xmake lua -v -D tests/run.lua\n\n        # upload artifacts\n      - name: Upload artifacts (exe)\n        if: matrix.os == 'windows-2025'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{env.RELEASE_NAME}}.exe\n          path: artifacts/${{env.RELEASE_NAME}}/xmake.exe\n\n      - name: Upload artifacts (zip)\n        if: matrix.os == 'windows-2025'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{ env.RELEASE_NAME }}.zip\n          path: artifacts/${{env.RELEASE_NAME}}/xmake.zip\n\n      - name: Upload artifacts (sha256)\n        if: matrix.os == 'windows-2025'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{ env.RELEASE_NAME }}.sha256\n          path: artifacts/${{env.RELEASE_NAME}}/shafile\n\n      - name: Upload artifacts (bundle)\n        if: matrix.os == 'windows-2025'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-bundle-latest.${{env.RELEASE_NAME}}.exe\n          path: artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe\n\n        # upload artifacts to latest release\n      - name: Inject slug/short variables\n        uses: rlespinasse/github-slug-action@v3.x\n\n      - name: Get Previous tag\n        id: previoustag\n        uses: WyriHaximus/github-action-get-previous-tag@master\n\n      - name: Upload artifacts to lastest release\n        if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev') && matrix.os == 'windows-2025'\n        uses: svenstaro/upload-release-action@v2\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: artifacts/${{env.RELEASE_NAME}}/xmake.exe\n          asset_name: xmake-${{ env.GITHUB_REF_SLUG }}.${{ env.RELEASE_NAME }}.exe\n          tag: ${{ steps.previoustag.outputs.tag }}\n          overwrite: true\n\n      - name: Upload artifacts to lastest release\n        if: github.ref == 'refs/heads/master' && matrix.os == 'windows-2025'\n        uses: svenstaro/upload-release-action@v2\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: artifacts/${{env.RELEASE_NAME}}/xmake.zip\n          asset_name: xmake-${{ env.GITHUB_REF_SLUG }}.${{ env.RELEASE_NAME }}.zip\n          tag: ${{ steps.previoustag.outputs.tag }}\n          overwrite: true\n\n        # publish release\n      - name: Publish\n        if: github.event.action == 'published' && matrix.os == 'windows-2025'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/${{env.RELEASE_NAME}}/xmake.exe\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.exe\n          asset_content_type: application/zip\n\n      - name: Publish\n        if: github.event.action == 'published' && matrix.os == 'windows-2025'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/${{env.RELEASE_NAME}}/xmake.zip\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.zip\n          asset_content_type: application/zip\n\n      - name: Publish\n        if: github.event.action == 'published' && matrix.os == 'windows-2025'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/${{env.RELEASE_NAME}}/shafile\n          asset_name: xmake-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.sha256\n          asset_content_type: application/zip\n\n      - name: Publish\n        if: github.event.action == 'published' && matrix.os == 'windows-2025'\n        uses: actions/upload-release-asset@v1.0.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ github.event.release.upload_url }}\n          asset_path: artifacts/${{env.RELEASE_NAME}}/xmake-bundle.exe\n          asset_name: xmake-bundle-${{ steps.tagName.outputs.tag }}.${{ env.RELEASE_NAME }}.exe\n          asset_content_type: application/zip\n\n"
  },
  {
    "path": ".github/workflows/windows_luajit.yml",
    "content": "name: Windows (Luajit)\n\non:\n  pull_request:\n  push:\n  release:\n    types: [published]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    outputs:\n      should-run: ${{ steps.check.outputs.should-run }}\n    steps:\n      - name: Random execution check\n        id: check\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const outputFile = process.env.GITHUB_OUTPUT;\n\n            // Always run for release events\n            if (context.eventName === 'release') {\n              fs.appendFileSync(outputFile, `should-run=true\\n`);\n              core.info('Release event detected. Will run tests.');\n              return;\n            }\n\n            // Execution probability (default 20%, can be overridden via env)\n            const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');\n\n            // Generate deterministic \"random\" number based on commit SHA, run ID, and current time\n            // Adding time ensures better randomness while keeping same commit/run consistent\n            const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60)); // Round to hour for consistency\n            const seed = context.sha + context.runId + timeSeed;\n            let hash = 0;\n            for (let i = 0; i < seed.length; i++) {\n              const char = seed.charCodeAt(i);\n              hash = ((hash << 5) - hash) + char;\n              hash = hash | 0; // Convert to 32-bit integer\n            }\n            // Normalize to 0-1 range\n            const random = Math.abs(hash) / 2147483647;\n            const shouldRun = random < probability;\n\n            // Use environment file instead of deprecated set-output\n            fs.appendFileSync(outputFile, `should-run=${shouldRun}\\n`);\n            if (shouldRun) {\n              core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);\n            } else {\n              core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);\n            }\n        env:\n          RUN_PROBABILITY: ${{ vars.WINDOWS_LUAJIT_RUN_PROBABILITY || '0.2' }}\n\n  build:\n    needs: check\n    if: needs.check.outputs.should-run == 'true'\n    strategy:\n      matrix:\n        os: [windows-2022, windows-2025]\n        arch: [x64, x86]\n\n    runs-on: ${{ matrix.os }}\n\n    concurrency:\n        # Prevent concurrent runs of the same workflow\n        group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-${{ matrix.os }}-${{ matrix.arch }}-Windows-Luajit\n        cancel-in-progress: true\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          # WyriHaximus/github-action-get-previous-tag@master need it\n          fetch-depth: 0\n          submodules: true\n      - uses: xmake-io/github-action-setup-xmake@v1\n        with:\n          # this is not supported, use dev branch instead\n          # xmake-version: local#\n          xmake-version: branch@dev\n      - uses: dlang-community/setup-dlang@v1\n        with:\n          compiler: dmd-latest\n      - uses: little-core-labs/get-git-tag@v3.0.2\n        id: tagName\n\n      - name: Set release arch name\n        run: |\n          if (\"${{ matrix.arch }}\" -eq \"x64\") {\n            Write-Output \"RELEASE_NAME=win64\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          } elseif (\"${{ matrix.arch }}\" -eq \"arm64\") {\n            Write-Output \"RELEASE_NAME=arm64\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          } else {\n            Write-Output \"RELEASE_NAME=win32\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf-8 -Append\n          }\n\n      - name: Build\n        run: |\n          cd core\n          xmake f -vD -a ${{ matrix.arch }} --runtime=luajit\n          xmake -vD\n          cd ..\n\n      - name: Artifact\n        run: |\n          cd core\n          xrepo update-repo\n          xmake pack -vD -y --formats=nsis,zip --autobuild=n -o ../artifacts/${{env.RELEASE_NAME}} --basename=xmake xmake\n          (Get-FileHash ../artifacts/${{env.RELEASE_NAME}}/xmake.zip -Algorithm SHA256).Hash.ToLower() + \" *xmake.zip`n\" | Out-File ./shafile -Encoding ASCII -NoNewLine -Append\n          Copy-Item shafile ../artifacts/${{env.RELEASE_NAME}}\n          cd ..\n\n      - name: Tests\n        run: |\n          Copy-Item ./core/build/xmake.exe ./xmake\n          Copy-Item ./scripts/xrepo.bat ./xmake\n          Copy-Item ./scripts/xrepo.ps1 ./xmake\n          $Env:XMAKE_PROGRAM_DIR = $(Resolve-Path ./xmake)\n          Set-Item -Path Env:Path -Value ($Env:XMAKE_PROGRAM_DIR + \";\" + $Env:Path)\n          xrepo --version\n          xmake show\n          xmake lua -v -D tests/run.lua\n\n        # upload artifacts\n      - name: Upload artifacts (exe)\n        if: matrix.os == 'windows-2022'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{env.RELEASE_NAME}}.exe\n          path: artifacts/${{env.RELEASE_NAME}}/xmake.exe\n\n      - name: Upload artifacts (zip)\n        if: matrix.os == 'windows-2022'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{ env.RELEASE_NAME }}.zip\n          path: artifacts/${{env.RELEASE_NAME}}/xmake.zip\n\n      - name: Upload artifacts (sha256)\n        if: matrix.os == 'windows-2022'\n        uses: actions/upload-artifact@v4\n        with:\n          name: xmake-latest.${{ env.RELEASE_NAME }}.sha256\n          path: artifacts/${{env.RELEASE_NAME}}/shafile\n"
  },
  {
    "path": ".gitignore",
    "content": "# MacOS Cache\n.DS_Store\n\n# Xmake cache\n.xmake/\nbuild/\nmakefile\nMakefile\nbuild.ninja\n\n# gcc cache\ngcm.cache\n\n# for VS Code\n.vscode/\n\n# for vim\n*.swp\n*.swo\ntags\n!tags/\n\n# Ignore packaging files\nwinenv/\n*.exe\n*.zip\n*.gz\n*.bz2\n*.xz\n*.7z\n*.run\n\n# for compiler\ncompile_commands.json\n.cache/\n\n# Makefile generation\n/core/xmake.config.h\n/core/.config.mak\n/core/**/*.o\n/core/**/*.b\n/core/**/*.a\n/core/**/*.obj\n/core/**/*.lib\n/core/**/*.exe\n\n# for fortran\n/tests/**/*.mod\n\n!/xmake/actions/build/\n\n# for linux driver\n*.o\n*.ko\n*.mod\n.*.cmd\n*.mod.c\nModule.symvers\nmodules.order\n\n# ai\n.claude\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"core/src/tbox/tbox\"]\n\tpath = core/src/tbox/tbox\n\turl = ../../tboox/tbox.git\n[submodule \"core/src/luajit/luajit\"]\n\tpath = core/src/luajit/luajit\n\turl = ../../xmake-io/xmake-core-luajit.git\n[submodule \"core/src/sv/sv\"]\n\tpath = core/src/sv/sv\n\turl = ../../xmake-io/xmake-core-sv.git\n[submodule \"core/src/pdcurses/pdcurses\"]\n\tpath = core/src/pdcurses/pdcurses\n\turl = ../../xmake-io/xmake-core-pdcurses.git\n[submodule \"core/src/lua-cjson/lua-cjson\"]\n\tpath = core/src/lua-cjson/lua-cjson\n\turl = ../../xmake-io/xmake-core-lua-cjson.git\n[submodule \"core/src/lua/lua\"]\n\tpath = core/src/lua/lua\n\turl = ../../xmake-io/xmake-core-lua.git\n[submodule \"core/src/lz4/lz4\"]\n\tpath = core/src/lz4/lz4\n\turl = ../../xmake-io/xmake-core-lz4.git\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog ([中文](#中文))\n\n## master (unreleased)\n\n### New features\n\n* [#7398](https://github.com/xmake-io/xmake/pull/7398): Add C# language and dotnet toolchain support\n* [#7410](https://github.com/xmake-io/xmake/pull/7410): Add C# and C/C++ interop support via P/Invoke\n* [#7360](https://github.com/xmake-io/xmake/pull/7360): Support custom templates\n* [#7367](https://github.com/xmake-io/xmake/pull/7367): Add `xmake create --list` and remote template distribution\n* [#7313](https://github.com/xmake-io/xmake/pull/7313): Add `build.release.strip` policy\n* [#7333](https://github.com/xmake-io/xmake/pull/7333): Add `winos.file_signature` function\n* [#7336](https://github.com/xmake-io/xmake/pull/7336): Add support for running wasi target\n* [#7346](https://github.com/xmake-io/xmake/pull/7346): Add nnd debugger support\n* [#7366](https://github.com/xmake-io/xmake/pull/7366): Add tarxz pack format\n\n### Changes\n\n* [#7309](https://github.com/xmake-io/xmake/pull/7309): Keep package source\n* [#7310](https://github.com/xmake-io/xmake/pull/7310): Improve check tips\n* [#7311](https://github.com/xmake-io/xmake/pull/7311): Improve Xcode toolchain\n* [#7312](https://github.com/xmake-io/xmake/pull/7312): Improve binutils to support wasm\n* [#7320](https://github.com/xmake-io/xmake/pull/7320): Add haiku ci\n* [#7329](https://github.com/xmake-io/xmake/pull/7329): Improve qt deploy for macapp\n* [#7349](https://github.com/xmake-io/xmake/pull/7349): Strip embed-dir on clang/gcc for C++ modules\n* [#7368](https://github.com/xmake-io/xmake/pull/7368): Move templates to repository\n* [#7383](https://github.com/xmake-io/xmake/pull/7383): Split zig toolchain to zig/zigcc\n* [#7384](https://github.com/xmake-io/xmake/pull/7384): Improve find_hdk\n* [#7387](https://github.com/xmake-io/xmake/pull/7387): Show target name in progress\n* [#7391](https://github.com/xmake-io/xmake/pull/7391): Improve to find package with vcpkg features\n* [#7392](https://github.com/xmake-io/xmake/pull/7392): Fix zig for shared libraries\n* [#7396](https://github.com/xmake-io/xmake/pull/7396): Improve vcpkg\n* [#7399](https://github.com/xmake-io/xmake/pull/7399): Extend formatting to C++ modules\n* [#7409](https://github.com/xmake-io/xmake/pull/7409): Improve ldc on windows\n\n### Bugs fixed\n\n* [#7299](https://github.com/xmake-io/xmake/pull/7299): Fix dependency handling for vcpkg\n* [#7316](https://github.com/xmake-io/xmake/pull/7316): Fix components typo\n* [#7318](https://github.com/xmake-io/xmake/pull/7318): Update tbox to fix tolower/toupper\n* [#7339](https://github.com/xmake-io/xmake/pull/7339): Update tbox to fix start process on win7\n* [#7344](https://github.com/xmake-io/xmake/pull/7344): Fix swig jar package module\n* [#7345](https://github.com/xmake-io/xmake/pull/7345): Fix check clang info\n* [#7341](https://github.com/xmake-io/xmake/pull/7341): Fix WASM QT 6.9\n* [#7356](https://github.com/xmake-io/xmake/pull/7356): Fix issue #7354\n* [#7371](https://github.com/xmake-io/xmake/pull/7371): Fix test verbose output\n* [#7386](https://github.com/xmake-io/xmake/pull/7386): Fix install script incompatibility with coreutils 9.10\n* [#7393](https://github.com/xmake-io/xmake/pull/7393): Fix build target validation\n\n## v3.0.7\n\n### New features\n\n* [#7178](https://github.com/xmake-io/xmake/pull/7178): Switch Verilator build file parsing from cmake to json format\n* [#7186](https://github.com/xmake-io/xmake/pull/7186): Add alpine ci\n* [#7187](https://github.com/xmake-io/xmake/pull/7187): Add suffix support for CUDA architecture\n* [#7190](https://github.com/xmake-io/xmake/pull/7190): Nix Package Manager: Add Semantic Versioning and Improve Version Selection\n* [#7189](https://github.com/xmake-io/xmake/pull/7189): Add package schemes\n* [#7208](https://github.com/xmake-io/xmake/pull/7208): Support dynamic mkspec selection for Qt SDK\n* [#7219](https://github.com/xmake-io/xmake/pull/7219): Add cli.iconv module\n* [#7235](https://github.com/xmake-io/xmake/pull/7235): Add string case conversion functions: lower and upper\n* [#7246](https://github.com/xmake-io/xmake/pull/7246): Add utf8 module\n* [#7268](https://github.com/xmake-io/xmake/pull/7268): Add dependency file generation for Nim source files\n* [#7269](https://github.com/xmake-io/xmake/pull/7269): Add target architecture validation for cross-compilation in zig toolchain\n* [#7274](https://github.com/xmake-io/xmake/pull/7274): Add os.access function for file access checking\n* [#7284](https://github.com/xmake-io/xmake/pull/7284): Add `--stdin`\n* [#7293](https://github.com/xmake-io/xmake/pull/7293): Add support for running wasm target in browser\n* [#7300](https://github.com/xmake-io/xmake/pull/7300): Add libdir,includedir,bindir support for install/uninstall\n* [#7295](https://github.com/xmake-io/xmake/pull/7295): Support test output files\n\n### Changes\n\n* [#7203](https://github.com/xmake-io/xmake/pull/7203): Improve mingw toolchain\n* [#7206](https://github.com/xmake-io/xmake/pull/7206): WDK: Add shared directory to KMDF include path\n* [#7214](https://github.com/xmake-io/xmake/pull/7214): Improve warnings output\n* [#7216](https://github.com/xmake-io/xmake/pull/7216): Improve requirelock\n* [#7223](https://github.com/xmake-io/xmake/pull/7223): Improve NuGet library file matching with score-based selection\n* [#7226](https://github.com/xmake-io/xmake/pull/7226): Improve to find clang-tidy\n* [#7232](https://github.com/xmake-io/xmake/pull/7232): Improve linker.link_scripts\n* [#7237](https://github.com/xmake-io/xmake/pull/7237): Update tbox to support case\n* [#7240](https://github.com/xmake-io/xmake/pull/7240): Improve verilator flags\n* [#7258](https://github.com/xmake-io/xmake/pull/7258): Improve qt xpack\n* [#7262](https://github.com/xmake-io/xmake/pull/7262): Improve pch concurrently to other targets\n* [#7260](https://github.com/xmake-io/xmake/pull/7260): Improve fpc\n* [#7270](https://github.com/xmake-io/xmake/pull/7270): Improve to select scheme version\n* [#7272](https://github.com/xmake-io/xmake/pull/7272): Enhance Nim support for shared libraries and rpath handling\n* [#7273](https://github.com/xmake-io/xmake/pull/7273): Improve io.read and io.readfile\n* [#7267](https://github.com/xmake-io/xmake/pull/7267): Enhance shell detection for Linux by checking parent process\n* [#7278](https://github.com/xmake-io/xmake/pull/7278): Improve os.isexec\n* [#7283](https://github.com/xmake-io/xmake/pull/7283): Enhance compile_commands support and add test cases\n* [#7285](https://github.com/xmake-io/xmake/pull/7285): Improve Windows shell detection for cmd/powershell\n* [#7286](https://github.com/xmake-io/xmake/pull/7286): Check long env values when detecting vs\n* [#7280](https://github.com/xmake-io/xmake/pull/7280): Add target flags only for cross-compilation\n* [#7290](https://github.com/xmake-io/xmake/pull/7290): Improve vcvars\n* [#7302](https://github.com/xmake-io/xmake/pull/7302): Improve run process errors\n* [#7306](https://github.com/xmake-io/xmake/pull/7306): Improve remote build with multi-host configuration and `--host` option\n* [#7298](https://github.com/xmake-io/xmake/pull/7298): Add initial implementation for Windows DLL foo/main example\n\n### Bugs fixed\n\n* [#7210](https://github.com/xmake-io/xmake/pull/7210): Fix package version\n* [#7213](https://github.com/xmake-io/xmake/pull/7213): Fix installdir of imporfiles\n* [#7231](https://github.com/xmake-io/xmake/pull/7231): Fix get flag in module support\n* [#7245](https://github.com/xmake-io/xmake/pull/7245): Fix to select scheme version\n* [#7259](https://github.com/xmake-io/xmake/pull/7259): Fix export c++ function symbols\n* [#7266](https://github.com/xmake-io/xmake/pull/7266): Fix pch header extension\n* [#7282](https://github.com/xmake-io/xmake/pull/7282): find_cuda: revert breaking change\n* [#7294](https://github.com/xmake-io/xmake/pull/7294): Fix package toolchain\n* [#7296](https://github.com/xmake-io/xmake/pull/7296): Fix find emsdk\n* [#7202](https://github.com/xmake-io/xmake/pull/7202): Fix getfenv\n\n## v3.0.6\n\n### New features\n\n* [#7141](https://github.com/xmake-io/xmake/pull/7141): Support disabling native app glue for Android\n* [#7139](https://github.com/xmake-io/xmake/pull/7139): Add Android native app build support\n* [#7127](https://github.com/xmake-io/xmake/pull/7127): Add deplibs support in binutils\n* [#7120](https://github.com/xmake-io/xmake/pull/7120): Add extractlib support in binutils\n* [#7106](https://github.com/xmake-io/xmake/pull/7106): Add `/std:c++23preview` support for MSVC\n* [#7105](https://github.com/xmake-io/xmake/pull/7105): Add `bin2obj` support for glsl/hlsl2spv\n* [#7103](https://github.com/xmake-io/xmake/pull/7103): Add `bin2obj` rule (faster than `bin2c`)\n* [#7096](https://github.com/xmake-io/xmake/pull/7096): Add Flang toolchain support\n* [#7094](https://github.com/xmake-io/xmake/pull/7094): Add `xmake check syntax` support\n* [#7091](https://github.com/xmake-io/xmake/pull/7091): Add dynamic debugging support for MSVC\n* [#7083](https://github.com/xmake-io/xmake/pull/7083): Add support for CUDA 11~13\n* [#7071](https://github.com/xmake-io/xmake/pull/7071): Add Qt pack support\n* [#7064](https://github.com/xmake-io/xmake/pull/7064): Add AppImage xpack format for Linux application packaging\n* [#7062](https://github.com/xmake-io/xmake/pull/7062): Add dmg xpack format for macOS application packaging\n\n### Changes\n\n* [#7149](https://github.com/xmake-io/xmake/pull/7149): Improve binutils to optimize rpath parsing\n* [#7148](https://github.com/xmake-io/xmake/pull/7148): Update Zig examples\n* [#7145](https://github.com/xmake-io/xmake/pull/7145): Improve Clang/LLVM runtime support\n* [#7136](https://github.com/xmake-io/xmake/pull/7136): Improve clang-cl depfiles generation\n* [#7135](https://github.com/xmake-io/xmake/pull/7135): Improve `xrepo env` to add session ID\n* [#7155](https://github.com/xmake-io/xmake/pull/7155): Refactor Windows ASan for clang-cl (runtime linking, linker flags, PATH/CMAKE_LINKER_TYPE setup, toolchain streamlining)\n* [#7109](https://github.com/xmake-io/xmake/pull/7109): Improve binutils to read symbols from binary file\n* [#7102](https://github.com/xmake-io/xmake/pull/7102): Improve bin2c rule\n* [#7098](https://github.com/xmake-io/xmake/pull/7098): Refactor and improve Golang support\n* [#7095](https://github.com/xmake-io/xmake/pull/7095): Mark target/package/toolchain:memcache as public\n* [#7093](https://github.com/xmake-io/xmake/pull/7093): Improve mirror repo URL\n* [#7088](https://github.com/xmake-io/xmake/pull/7088): Improve C++/ObjC rules\n* [#7087](https://github.com/xmake-io/xmake/pull/7087): Add type constraint for policy `package.download.http_headers`\n* [#7069](https://github.com/xmake-io/xmake/pull/7069): Save Qt rules for LLVM toolchain\n* [#7061](https://github.com/xmake-io/xmake/pull/7061): Update CI configuration\n* [#7039](https://github.com/xmake-io/xmake/pull/7039): Update macOS CI\n\n### Bugs fixed\n\n* [#7132](https://github.com/xmake-io/xmake/pull/7132): Fix clang-cl toolchain with ASan\n* [#7125](https://github.com/xmake-io/xmake/pull/7125): Fix cosmocc CI\n* [#7124](https://github.com/xmake-io/xmake/pull/7124): Fix default MSVC runtime for Clang toolchain\n* [#7112](https://github.com/xmake-io/xmake/pull/7112): Fix change directory on Windows\n* [#7104](https://github.com/xmake-io/xmake/pull/7104): Fix prepare for project generators\n* [#7092](https://github.com/xmake-io/xmake/pull/7092): Fix Solaris build\n* [#7086](https://github.com/xmake-io/xmake/pull/7086): Fix targetdir in Qt QML rule\n* [#7085](https://github.com/xmake-io/xmake/pull/7085): Fix CMake flags for Clang toolchain\n* [#7084](https://github.com/xmake-io/xmake/pull/7084): Fix pacman find_package\n* [#7082](https://github.com/xmake-io/xmake/pull/7082): Fix checking Clang CUDA flags\n* [#7081](https://github.com/xmake-io/xmake/pull/7081): Fix `get_headerunit_key`\n* [#7074](https://github.com/xmake-io/xmake/pull/7074): Fix libc++ cannot find std module\n* [#7067](https://github.com/xmake-io/xmake/pull/7067): Fix get_stdmodules with cross toolchain\n\n## v3.0.5\n\n### New features\n\n* [#7055](https://github.com/xmake-io/xmake/pull/7055): Add Solaris platform support (i386, x86_64)\n* [#7054](https://github.com/xmake-io/xmake/pull/7054): Add support for additional BSD systems (NetBSD, OpenBSD, DragonflyBSD)\n* [#6929](https://github.com/xmake-io/xmake/pull/6929): Add support for GCC 15 toolchain\n* [#6967](https://github.com/xmake-io/xmake/pull/6967): Add Swift interop support for C++ and Objective-C\n* [#6964](https://github.com/xmake-io/xmake/pull/6964): Support specifying CUDA SDK version via cuda_sdkver\n* [#6963](https://github.com/xmake-io/xmake/pull/6963): Add libtool patch support for cross compilation\n* [#6974](https://github.com/xmake-io/xmake/pull/6974): Support multi-row refresh for progress output\n* [#7024](https://github.com/xmake-io/xmake/pull/7024): Add JSON output format for `xmake show -t target`\n* [#7025](https://github.com/xmake-io/xmake/pull/7025): Add XML module with parsing and encoding support\n* [#6989](https://github.com/xmake-io/xmake/pull/6989): Add async support for os APIs\n\n### Changes\n\n* [#6924](https://github.com/xmake-io/xmake/pull/6924): Improve toolchain configuration with add_toolchains(\"name[configs]\") syntax\n* [#6935](https://github.com/xmake-io/xmake/pull/6935): Refactor toolchain: separate gcc/clang registration from definition\n* [#6942](https://github.com/xmake-io/xmake/pull/6942): Improve file reading performance\n* [#6946](https://github.com/xmake-io/xmake/pull/6946): Add LLD linker support for Clang toolchain\n* [#6970](https://github.com/xmake-io/xmake/pull/6970): Improve TTY handling and output\n* [#6977](https://github.com/xmake-io/xmake/pull/6977): Refactor Xcode toolchain and integrate it into LLVM toolchain for Apple devices\n* [#6987](https://github.com/xmake-io/xmake/pull/6987): Add Ghostty terminal detection support\n* [#7003](https://github.com/xmake-io/xmake/pull/7003): Limit build environment retrieval in package configurations\n* [#7008](https://github.com/xmake-io/xmake/pull/7008): Format code style\n* [#7004](https://github.com/xmake-io/xmake/pull/7004): Skip rebuilding packages and std modules when using -r flag\n* [#7019](https://github.com/xmake-io/xmake/pull/7019): Improve xmake.sh/configure script and add Ninja generator support\n* [#7023](https://github.com/xmake-io/xmake/pull/7023): Update Qt TypeScript rule\n* [#7022](https://github.com/xmake-io/xmake/pull/7022): Make zig-cc toolchain inherit from clang\n* [#7027](https://github.com/xmake-io/xmake/pull/7027): Improve graph module performance\n* [#7031](https://github.com/xmake-io/xmake/pull/7031): Improve require parsing\n* [#7032](https://github.com/xmake-io/xmake/pull/7032): Improve symbol extraction\n* [#6952](https://github.com/xmake-io/xmake/pull/6952): Add realtime output support for tests\n* [#6998](https://github.com/xmake-io/xmake/pull/6998): Update tbox library for process/argv support\n* [#7037](https://github.com/xmake-io/xmake/pull/7037): Improve xmake format\n* [#7038](https://github.com/xmake-io/xmake/pull/7038): Improve clang-tidy output handling\n\n### Bugs fixed\n\n* [#6926](https://github.com/xmake-io/xmake/pull/6926): Fix loading Unicode main script path on Windows\n* [#6931](https://github.com/xmake-io/xmake/pull/6931): Fix C++ modules: fallback to system-wide clang-scan-deps when toolchain version is not installed\n* [#6937](https://github.com/xmake-io/xmake/pull/6937): Fix target jobs handling\n* [#6954](https://github.com/xmake-io/xmake/pull/6954): Fix modules support for vsxmake/vs generators\n* [#6955](https://github.com/xmake-io/xmake/pull/6955): Fix build number sorting in packages\n* [#6956](https://github.com/xmake-io/xmake/pull/6956): Fix build failure when using zigcc linker that doesn't support depfile\n* [#6959](https://github.com/xmake-io/xmake/pull/6959): Fix using zigcc with autotools for dynamic linking\n* [#6983](https://github.com/xmake-io/xmake/pull/6983): Fix modules: strip sanitizer flags for module reuse\n* [#6984](https://github.com/xmake-io/xmake/pull/6984): Fix libdir path in installed CMake import files\n* [#6993](https://github.com/xmake-io/xmake/pull/6993): Fix xmake test modules\n* [#6992](https://github.com/xmake-io/xmake/pull/6992): Fix modules: add all supported platforms for clang get_cpp_library_name\n* [#6999](https://github.com/xmake-io/xmake/pull/6999): Fix rootdir handling\n* [#7002](https://github.com/xmake-io/xmake/pull/7002): Fix asn1c: include generated output as system headers\n* [#6996](https://github.com/xmake-io/xmake/pull/6996): Fix Nimble find_package to use latest package list format\n* [#7012](https://github.com/xmake-io/xmake/pull/7012): Fix sparse checkout handling\n* [#7013](https://github.com/xmake-io/xmake/pull/7013): Fix removing dependencies when packaging\n* [#7017](https://github.com/xmake-io/xmake/pull/7017): Fix lock_packages typo\n* [#7016](https://github.com/xmake-io/xmake/pull/7016): Fix project default configuration in vsxmake\n* [#7018](https://github.com/xmake-io/xmake/pull/7018): Fix build order: only disable when dependency linking inheritance is disabled\n* [#7035](https://github.com/xmake-io/xmake/pull/7035): Fix process redirection issues by updating tbox\n\n## v3.0.4\n\n### New features\n\n* [#6864](https://github.com/xmake-io/xmake/pull/6864): Add default file filter for `format` task\n* [#6843](https://github.com/xmake-io/xmake/pull/6843): Improve clang-tidy support\n* [#6861](https://github.com/xmake-io/xmake/pull/6861): Rewrite of Nix Package Manager Support\n* [#6850](https://github.com/xmake-io/xmake/pull/6850): Add package api checking\n* [#6874](https://github.com/xmake-io/xmake/pull/6874): Add scriptdir to project packages\n* [#6876](https://github.com/xmake-io/xmake/pull/6876): Add versionfiles checker\n* [#6884](https://github.com/xmake-io/xmake/pull/6884): Add msystem support on msys2\n* [#6891](https://github.com/xmake-io/xmake/pull/6891): Add coroutine semaphore\n* [#6894](https://github.com/xmake-io/xmake/pull/6894): Add llvm-nm for clang toolchain\n* [#6918](https://github.com/xmake-io/xmake/pull/6918): Add copy_if_different in os.cp\n\n### Changes\n\n* [#6846](https://github.com/xmake-io/xmake/pull/6846): Improve cmake default flags\n* [#6849](https://github.com/xmake-io/xmake/pull/6849): Improve jobgraph\n* [#6859](https://github.com/xmake-io/xmake/pull/6859): Improve to check target flags\n* [#6858](https://github.com/xmake-io/xmake/pull/6858): Modify config flags order\n* [#6854](https://github.com/xmake-io/xmake/pull/6854): Improve os.curdir/os.cd\n* [#6866](https://github.com/xmake-io/xmake/pull/6866): Improve os.getenvs\n* [#6867](https://github.com/xmake-io/xmake/pull/6867): Make sure generic options are always inserted\n* [#6870](https://github.com/xmake-io/xmake/pull/6870): chore(vcpkg): bump default baseline hash of vcpkg\n* [#6880](https://github.com/xmake-io/xmake/pull/6880): Update cmake_importfiles.lua\n* [#6872](https://github.com/xmake-io/xmake/pull/6872): Improve hash\n* [#6886](https://github.com/xmake-io/xmake/pull/6886): Decrease jobs count in jobgraph\n* [#6890](https://github.com/xmake-io/xmake/pull/6890): Update cmake_importfiles.lua\n* [#6892](https://github.com/xmake-io/xmake/pull/6892): Improve runjobs to reduce the time spent on coroutine scheduling\n* [#6896](https://github.com/xmake-io/xmake/pull/6896): Add hash test\n* [#6904](https://github.com/xmake-io/xmake/pull/6904): Improve clang to support for msvc envs\n* [#6915](https://github.com/xmake-io/xmake/pull/6915): Improve to export def rules for binary\n\n### Bugs fixed\n\n* [#6844](https://github.com/xmake-io/xmake/pull/6844): Fix version in auto-generated .pc.\n* [#6851](https://github.com/xmake-io/xmake/pull/6851): Fix finding clang-scan-deps\n* [#6857](https://github.com/xmake-io/xmake/pull/6857): Fix rc compiler with cmake in cross-compilation\n* [#6809](https://github.com/xmake-io/xmake/pull/6809): fix(C++ modules) fix stdmodule priority\n* [#6882](https://github.com/xmake-io/xmake/pull/6882): Fix: write package manifest.pathenvs in deterministic order\n* [#6888](https://github.com/xmake-io/xmake/pull/6888): Fix clang toolchain package\n* [#6889](https://github.com/xmake-io/xmake/pull/6889): Fix os.getenvs compat\n* [#6900](https://github.com/xmake-io/xmake/pull/6900): package.tools.xmake: fix policies not being passed\n* [#6901](https://github.com/xmake-io/xmake/pull/6901): package download: don't get submodules if disabled\n* [#6907](https://github.com/xmake-io/xmake/pull/6907): package download: don't get submodules if disabled (branch version)\n\n## v3.0.3\n\n### New features\n\n* [#6778](https://github.com/xmake-io/xmake/pull/6778): Add build.linker.output\n* [#6779](https://github.com/xmake-io/xmake/pull/6779): Add #embed and embedirs support\n* [#6787](https://github.com/xmake-io/xmake/pull/6787): Support for vs2026\n* [#6785](https://github.com/xmake-io/xmake/pull/6785): Support clang and llvm for wdk rules\n* [#6791](https://github.com/xmake-io/xmake/pull/6791): Add Nix Package Manager Support\n* [#6800](https://github.com/xmake-io/xmake/pull/6800): Support nushell for xrepo env\n* [#6796](https://github.com/xmake-io/xmake/pull/6796): Enable support of incomplete wdk\n\n### Changes\n\n* [#6765](https://github.com/xmake-io/xmake/pull/6765): Improve bin2c to use native thread\n* [#6771](https://github.com/xmake-io/xmake/pull/6771): Fix find gcc/gxx cache\n* [#6777](https://github.com/xmake-io/xmake/pull/6777): Fix executable path for cmake\n* [#6783](https://github.com/xmake-io/xmake/pull/6783): Fix build.c++.modules.std policy\n* [#6744](https://github.com/xmake-io/xmake/pull/6744): Use a file for requires flags when --verbose or --diagnosis is supplied\n* [#6780](https://github.com/xmake-io/xmake/pull/6780): Add benchmarks and optimize config/build targets\n* [#6784](https://github.com/xmake-io/xmake/pull/6784): Continue to optimize building targets speed\n* [#6793](https://github.com/xmake-io/xmake/pull/6793): Use musl to avoid glibc's version issue\n* [#6788](https://github.com/xmake-io/xmake/pull/6788): Improve incremental build clang\n* [#6811](https://github.com/xmake-io/xmake/pull/6811): Improve clang-tidy\n* [#6810](https://github.com/xmake-io/xmake/pull/6810): Improve the default flags for cmake\n* [#6801](https://github.com/xmake-io/xmake/pull/6801): Change compilers priority for gcc and clang\n* [#6819](https://github.com/xmake-io/xmake/pull/6819): Improve show target\n* [#6817](https://github.com/xmake-io/xmake/pull/6817): Improve build targets speed\n* [#6822](https://github.com/xmake-io/xmake/pull/6822): Prioritize envs over repo cache\n* [#6824](https://github.com/xmake-io/xmake/pull/6824): Improve has_flags\n* [#6832](https://github.com/xmake-io/xmake/pull/6832): Optimize codesign\n\n### Bugs fixed\n\n* [#6808](https://github.com/xmake-io/xmake/pull/6808): Fix xrepo env\n* [#6821](https://github.com/xmake-io/xmake/pull/6821): Clean undefined vsvers\n* [#6818](https://github.com/xmake-io/xmake/pull/6818): Fix Nix Package Detection in nix-shell Environment\n* [#6798](https://github.com/xmake-io/xmake/pull/6798): Add external to the strippeable_flags for msvc\n\n## v3.0.2\n\n### New features\n\n* [#6755](https://github.com/xmake-io/xmake/issues/6755): Add native thread support\n* [#6641](https://github.com/xmake-io/xmake/pull/6641): Add pkgenvs to target/config\n* [#6644](https://github.com/xmake-io/xmake/pull/6644): Support .def file with clang\n* [#6695](https://github.com/xmake-io/xmake/pull/6695): Add /uselocaltime to inf2cat args\n* [#6709](https://github.com/xmake-io/xmake/pull/6709): Support for wasm64\n* [#6737](https://github.com/xmake-io/xmake/pull/6737): Add python stub file extension to cython rule\n\n### Changes\n\n* [#6651](https://github.com/xmake-io/xmake/pull/6651): Improve depfiles\n* [#6656](https://github.com/xmake-io/xmake/pull/6656): Make build tools support passing in `opt.targets`\n* [#6688](https://github.com/xmake-io/xmake/pull/6688): Improve to install targets\n* [#6692](https://github.com/xmake-io/xmake/pull/6692): Improve protobuf test\n* [#6714](https://github.com/xmake-io/xmake/pull/6714): Improve tests for c++ modules\n* [#6719](https://github.com/xmake-io/xmake/pull/6719): Improve comax for config\n* [#6725](https://github.com/xmake-io/xmake/pull/6725): Improve target:extrafiles\n\n### Bugs fixed\n\n* [#6648](https://github.com/xmake-io/xmake/pull/6648): Fix(qt.qmltyperegistrar): Collect metatypes info\n* [#6661](https://github.com/xmake-io/xmake/pull/6661): Fix prolonged blocking in _ping_via_wget by setting \"--tries=1\"\n* [#6665](https://github.com/xmake-io/xmake/pull/6665): Fix cmake/mingw\n* [#6674](https://github.com/xmake-io/xmake/pull/6674): Attempt to fix linkgroups in package\n* [#6686](https://github.com/xmake-io/xmake/pull/6686): Fix compiler cache\n* [#6698](https://github.com/xmake-io/xmake/pull/6698): Fix(c++ modules) handle empty modules\n* [#6699](https://github.com/xmake-io/xmake/pull/6699): Fix(c++ modules) fix xmake not updating module mapper when module file is removed\n* [#6706](https://github.com/xmake-io/xmake/pull/6706): Fix find_cudadevices for CUDA 13\n* [#6707](https://github.com/xmake-io/xmake/pull/6707): Fix(c++ modules) fix sourcebatch caching\n* [#6712](https://github.com/xmake-io/xmake/pull/6712): Fix(c++ modules) fix disabled target getting configured for module compilation\n* [#6713](https://github.com/xmake-io/xmake/pull/6713): Fix(c++ modules) fix non .cpp file stealed from c++.build sourcebatch\n* [#6715](https://github.com/xmake-io/xmake/pull/6715): Fix(c++ modules) fix public culled module incorrectly emiting a warning\n* [#6718](https://github.com/xmake-io/xmake/pull/6718): Ignore pch flags\n* [#6732](https://github.com/xmake-io/xmake/pull/6732): Fix: android ndk rust link-args\n* [#6735](https://github.com/xmake-io/xmake/pull/6735): Fix(qt.qmltyperegistrar): Extend dependencies for rebuild\n* [#6738](https://github.com/xmake-io/xmake/pull/6738): Fix protobuf for target deps\n* [#6741](https://github.com/xmake-io/xmake/pull/6741): Fix vsxmake options\n* [#6747](https://github.com/xmake-io/xmake/pull/6747): meminfo.c: no vmstat.compressor_page_count on < 10.7\n\n## v3.0.1\n\n### New features\n\n* [#4810](https://github.com/xmake-io/xmake/issues/4810): Add Native XCode project generator plugin\n\n### Bugs fixed\n\n* [#6592](https://github.com/xmake-io/xmake/pull/6592): Fix objects only links\n* [#6586](https://github.com/xmake-io/xmake/issues/6586): Fix build.fence policy\n* [#6600](https://github.com/xmake-io/xmake/issues/6600): Fix compile_commands generator for c++modules\n* [#6621](https://github.com/xmake-io/xmake/issues/6621): Fix android build for ndk r17c\n* [#6635](https://github.com/xmake-io/xmake/discussions/6635): Fix batchcmds for qt/moc\n\n## v3.0.0\n\n### New features\n\n* [#5926](https://github.com/xmake-io/xmake/issues/5926): Add MIDL support\n* [#6414](https://github.com/xmake-io/xmake/pull/6414): Add platform.windows.subsystem rule\n* [#5527](https://github.com/xmake-io/xmake/issues/5527): Switch to 3.0 policies\n\n### Changes\n\n* [#6202](https://github.com/xmake-io/xmake/issues/6202): Improve rule API and build dependency order\n* [#5624](https://github.com/xmake-io/xmake/discussions/5624): Enable auto build when calling xmake run by default\n* [#5526](https://github.com/xmake-io/xmake/discussions/5526): Use MD/MDd runtimes for msvc by default\n* [#5545](https://github.com/xmake-io/xmake/discussions/5545): Use ninja generator for cmake package by default\n* [#6355](https://github.com/xmake-io/xmake/pull/6355): Support customizing implib path of MinGW/MSVC\n* [#6373](https://github.com/xmake-io/xmake/pull/6373): Improve c++ modules support\n* [#6376](https://github.com/xmake-io/xmake/issues/6476): Improve vsxmake generators for namespaces\n* [#6209](https://github.com/xmake-io/xmake/pull/6209): Add build jobgraph support\n* [#6361](https://github.com/xmake-io/xmake/pull/6361): Rename buildir to builddir\n\n## v2.9.9\n\n### New features\n\n* [#6137](https://github.com/xmake-io/xmake/issues/6137): IDE integration\n* [#6138](https://github.com/xmake-io/xmake/issues/6138): Use libxmake to build binary with xmake lua apis\n* [#6154](https://github.com/xmake-io/xmake/issues/6154): Add kotlin language and kotlin-native compiler and packages support\n* [#6279](https://github.com/xmake-io/xmake/pull/6279): Add msvc midl support\n\n### Changes\n\n* [#6182](https://github.com/xmake-io/xmake/pull/6182): Support msstl modules for clang\n* [#6281](https://github.com/xmake-io/xmake/pull/6281): Support Verilator target build to shared library\n* [#6270](https://github.com/xmake-io/xmake/pull/6270): Improve conan generator\n* [#6243](https://github.com/xmake-io/xmake/pull/6243): Improve llvm toolchain to support for cross platform\n* Support for CMake 4.0\n\n### Bugs fixed\n\n* [#6292](https://github.com/xmake-io/xmake/issues/6292): Fix namespace issue\n\n## v2.9.8\n\n### New features\n\n* [#5994](https://github.com/xmake-io/xmake/issues/5994): Profile process performance\n* [#5995](https://github.com/xmake-io/xmake/pull/5995): Add profile support for vs generator\n* [#5949](https://github.com/xmake-io/xmake/pull/5949): Add rule nodejs.module\n* [#3380](https://github.com/xmake-io/xmake/issues/3380): Add namespace support\n* [#5945](https://github.com/xmake-io/xmake/issues/5945): Check pkgconfig/cmake importfiles for package\n* [#6054](https://github.com/xmake-io/xmake/issues/6054): Add xmake bundle for linux\n* [#6071](https://github.com/xmake-io/xmake/issues/6071): Improve to download package for git url, support for sparse-checkout\n* [#5163](https://github.com/xmake-io/xmake/issues/5163): Support TI-CGT C2000/C6000 compiler\n* [#5344](https://github.com/xmake-io/xmake/issues/5344): Support IAR ARM C/C++ compiler\n* [#5554](https://github.com/xmake-io/xmake/issues/5554): Add custom unknown toolchains support\n\n### Changes\n\n* [#6056](https://github.com/xmake-io/xmake/pull/6056): Build and release xmake/arm64 on windows.\n* [#6097](https://github.com/xmake-io/xmake/pull/6097): Add qt_host Option to Enable Cross-Platform Qt Builds Using Host SDK Tools\n* [#6120](https://github.com/xmake-io/xmake/issues/6120): Add custom preprocessor for configfiles\n* [#6088](https://github.com/xmake-io/xmake/issues/6088): Improve configfiles to generate export macro\n\n### Bugs fixed\n\n* [#272](https://github.com/tboox/tbox/issues/272): Fix xmake stuck when readfile always return zero for msvc + /O1\n* [#6089](https://github.com/tboox/tbox/issues/6089): Fix depend.is_changed for cuda\n\n## v2.9.7\n\n### New features\n\n* [#5813](https://github.com/xmake-io/xmake/pull/5813): Add `before_config` and `after_config` for rule\n* [#5848](https://github.com/xmake-io/xmake/issues/5848): Support custom MSVC build tools, e.g. PortableBuildTools and msvc-wine\n* [#5880](https://github.com/xmake-io/xmake/pull/5880): Use msvc package to build project\n* [#5884](https://github.com/xmake-io/xmake/issues/5884): Add installtips for package\n* [#5894](https://github.com/xmake-io/xmake/issues/5894): Add package.merge_staticlibs policy to merge package libs\n* [#5948](https://github.com/xmake-io/xmake/pull/5948): Add `lua.native-object` rule\n* [#5911](https://github.com/xmake-io/xmake/issues/5911): Support for nuget packages\n\n### Changes\n\n* [#5817](https://github.com/xmake-io/xmake/pull/5817): Improve default pic for packages\n* [#5869](https://github.com/xmake-io/xmake/pull/5869): Add libstdc++ standard library modules support for gcc\n* [#5923](https://github.com/xmake-io/xmake/pull/5923): Solve the package version and configs conflict\n\n### Bugs fixed\n\n* [#5856](https://github.com/xmake-io/xmake/issues/5856): Fix compile c++modules for clang\n* [#5858](https://github.com/xmake-io/xmake/issues/5858): Fix the precompiled header for gcc\n\n## v2.9.6\n\n### New features\n\n* [#5527](https://github.com/xmake-io/xmake/issues/5527): Add `set_policy(\"compatibility.version\", \"3.0\")` to preview v3.0 features.\n* [#5649](https://github.com/xmake-io/xmake/pull/5649): Add `package.check_fcsnippets`\n\n### Changes\n\n* [#5631](https://github.com/xmake-io/xmake/pull/5631): Add `as_needed` for `add_linkgroups`\n* [#5702](https://github.com/xmake-io/xmake/issues/5702): Improve hash module\n* [#5688](https://github.com/xmake-io/xmake/pull/5688): Improve hashset module\n* [#5711](https://github.com/xmake-io/xmake/issues/5711): Support to parse include deps for sdcc\n* [#5727](https://github.com/xmake-io/xmake/issues/5727): Improve configs for add_requires\n* [#5762](https://github.com/xmake-io/xmake/pull/5762): Improve bin2c speed\n\n### Bugs fixed\n\n* [#5645](https://github.com/xmake-io/xmake/issues/5645): Fix `xmake watch` for linux\n* [#5686](https://github.com/xmake-io/xmake/pull/5686): Fix module scanning\n\n## v2.9.5\n\n### New features\n\n* [#5462](https://github.com/xmake-io/xmake/pull/5462): Add `xmake l cli.bisect`\n* [#5488](https://github.com/xmake-io/xmake/pull/5488): Support for using cosmocc to build xmake binary\n* [#5491](https://github.com/xmake-io/xmake/pull/5491): Provide single xmake binary with embeded lua files\n* [#5580](https://github.com/xmake-io/xmake/issues/5580): Add `@builtin/xrepo` to add envs for `xrepo env shell`\n\n### Changes\n\n* [#5507](https://github.com/xmake-io/xmake/issues/5507): Use treeless to improve git.clone\n* [#5536](https://github.com/xmake-io/xmake/pull/5536): Add jar generate in swig mode\n* [#5573](https://github.com/xmake-io/xmake/issues/5573): Improve vsxmake generator performance\n* [#5601](https://github.com/xmake-io/xmake/issues/5601): Improve utils.symbols.export_all rule to filter sourcefile path\n\n### Bugs fixed\n\n* [#4750](https://github.com/xmake-io/xmake/issues/4750): Fix compile_commands generator for `xmake tests`\n* [#5465](https://github.com/xmake-io/xmake/pull/5465): Fix lock package requires\n* [#4760](https://github.com/xmake-io/xmake/issues/4760): Fix distcc client issue\n\n## v2.9.4\n\n### New features\n\n* [#5278](https://github.com/xmake-io/xmake/issues/5278): Add `build.intermediate_directory` policy to disable and custom intermediate directory\n* [#5313](https://github.com/xmake-io/xmake/issues/5313): Add windows arm/arm64ec support\n* [#5296](https://github.com/xmake-io/xmake/issues/5296): Add Intel LLVM Fortran Compiler support\n* [#5384](https://github.com/xmake-io/xmake/issues/5384): Add `add_bindirs` for package\n\n### Changes\n\n* [#5280](https://github.com/xmake-io/xmake/issues/5280): Add missing C++20 Modules file extension\n* [#5251](https://github.com/xmake-io/xmake/issues/5251): Update 7z/curl for windows installer\n* [#5286](https://github.com/xmake-io/xmake/issues/5286): Improve json to parse hex string\n* [#5302](https://github.com/xmake-io/xmake/pull/5302): Improve Vala support\n* [#5335](https://github.com/xmake-io/xmake/pull/5335): Improve `xmake install` and `xpack`, Add `set_prefixdir` api for target\n* [#5387](https://github.com/xmake-io/xmake/pull/5387): Improve `xmake test`\n* [#5376](https://github.com/xmake-io/xmake/pull/5376): Improve module objectfiles handling and moduleonly package\n\n### Bugs Fixed\n\n* [#5288](https://github.com/xmake-io/xmake/issues/5288): Fix `xmake test` for unity build\n* [#5270](https://github.com/xmake-io/xmake/issues/5270): Fix pch/include for gcc/clang\n* [#5276](https://github.com/xmake-io/xmake/issues/5276): Fix find vc6\n* [#5259](https://github.com/xmake-io/xmake/issues/5259): Fix the failure of the command line completion function\n\n## v2.9.3\n\n### New features\n\n* [#4637](https://github.com/xmake-io/xmake/issues/4637): Add mix generator for xpack\n* [#5107](https://github.com/xmake-io/xmake/issues/5107): Add deb generator for xpack\n* [#5148](https://github.com/xmake-io/xmake/issues/5148): Add on_source in package\n\n### Changes\n\n* [#5156](https://github.com/xmake-io/xmake/issues/5156): Improve to install cargo packages for rust\n\n### Bugs fixed\n\n* [#5176](https://github.com/xmake-io/xmake/pull/5176): Fix VS toolset v144\n\n## v2.9.2\n\n### New features\n\n* [#5005](https://github.com/xmake-io/xmake/pull/5005): Show all apis\n* [#5003](https://github.com/xmake-io/xmake/issues/5003): Add build.fence policy\n* [#5060](https://github.com/xmake-io/xmake/issues/5060): Support Verilator target build to static library\n* [#5074](https://github.com/xmake-io/xmake/pull/5074): Add `xrepo download` command to download package source\n* [#5086](https://github.com/xmake-io/xmake/issues/5986): Add check support for package\n* [#5103](https://github.com/xmake-io/xmake/pull/5103): Add qt ts files building\n* [#5104](https://github.com/xmake-io/xmake/pull/5104): Call where in find_program\n\n### Changes\n\n* [#5077](https://github.com/xmake-io/xmake/issues/5077): Use x64 host compiler for msvc when building x86 target\n* [#5109](https://github.com/xmake-io/xmake/issues/5109): Support runpath/rpath for add_rpathdirs\n* [#5132](https://github.com/xmake-io/xmake/pull/5132): Improve ifort/icc/icx support on windows\n\n### Bugs Fixed\n\n* [#5059](https://github.com/xmake-io/xmake/issues/5059): Fix load huge targets stuck\n* [#5029](https://github.com/xmake-io/xmake/issues/5029): Fix crash on termux\n\n## v2.9.1\n\n### New features\n\n* [#4874](https://github.com/xmake-io/xmake/pull/4874): Add Harmony SDK support\n* [#4889](https://github.com/xmake-io/xmake/issues/4889): Add signal module to register signal handler in lua\n* [#4925](https://github.com/xmake-io/xmake/issues/4925): Add native modules support\n* [#4938](https://github.com/xmake-io/xmake/issues/4938): Support for cppfront/h2\n\n### Changes\n\n* Improve packages to support for clang-cl\n* [#4893](https://github.com/xmake-io/xmake/issues/4893): Improve rc includes deps\n* [#4928](https://github.com/xmake-io/xmake/issues/4928): Improve to build and link speed\n* [#4931](https://github.com/xmake-io/xmake/pull/4931): Update pdcurses\n* [#4973](https://github.com/xmake-io/xmake/issues/4973): Improve to select script\n\n### Bugs fixed\n\n* [#4882](https://github.com/xmake-io/xmake/issues/4882): Fix install deps with --group\n* [#4877](https://github.com/xmake-io/xmake/issues/4877): Fix compile error for xpack with unity build\n* [#4887](https://github.com/xmake-io/xmake/issues/4887): Fix object deps\n\n## v2.8.9\n\n### New features\n\n* [#4843](https://github.com/xmake-io/xmake/issues/4843): Endianness/Byte-order detection on build machine\n\n### Changes\n\n* [#4798](https://github.com/xmake-io/xmake/issues/4798): Improve wasi sdk detect\n* [#4772](https://github.com/xmake-io/xmake/issues/4772): Improve tools.cmake to support vs2022 preview (v144)\n* [#4813](https://github.com/xmake-io/xmake/issues/4813): Add gb2312 encoding\n* [#4864](https://github.com/xmake-io/xmake/issues/4864): Improve to extract symbols for gdb\n* [#4831](https://github.com/xmake-io/xmake/issues/4831): Allow target:fileconfig() for headerfiles\n* [#4846](https://github.com/xmake-io/xmake/issues/4846): Improve to show progress\n\n### Bugs Fixed\n\n* Fix select_script match pattern\n* [#4763](https://github.com/xmake-io/xmake/issues/4763): Fix {force = true}\n* [#4807](https://github.com/xmake-io/xmake/issues/4807): Fix nimble::find_package\n* [#4857](https://github.com/xmake-io/xmake/issues/4857): Fix parse basic options\n\n## v2.8.8\n\n### Changes\n\n* Add `package:check_sizeof()`\n\n### Bugs Fixed\n\n* [#4774](https://github.com/xmake-io/xmake/issues/4774): Fix android symbol strip\n* [#4769](https://github.com/xmake-io/xmake/issues/4769): Fix cross toolchain and format\n* [#4776](https://github.com/xmake-io/xmake/issues/4776): Fix soname for linux\n* [#4638](https://github.com/xmake-io/xmake/issues/4638): Fix vsxmake with --menu config\n\n## v2.8.7\n\n### New features\n\n* [#4544](https://github.com/xmake-io/xmake/issues/4544): Support to wait process timeout for `xmake test`\n* [#4606](https://github.com/xmake-io/xmake/pull/4606): Add `add_versionfiles` api in package\n* [#4709](https://github.com/xmake-io/xmake/issues/4709): Add cosmocc toolchain support\n* [#4715](https://github.com/xmake-io/xmake/issues/4715): Add is_cross() api in description scope\n* [#4747](https://github.com/xmake-io/xmake/issues/4747): Add `build.always_update_configfiles` policy\n\n### Changes\n\n* [#4575](https://github.com/xmake-io/xmake/issues/4575): Check invalid scope name\n* Add more loong64 support\n* Improve dlang/dmd support for frameworks\n* [#4571](https://github.com/xmake-io/xmake/issues/4571): Improve `xmake test` output\n* [#4609](https://github.com/xmake-io/xmake/issues/4609): Improve to detect vs build tool envirnoments\n* [#4614](https://github.com/xmake-io/xmake/issues/4614): Support android ndk 26b\n* [#4473](https://github.com/xmake-io/xmake/issues/4473): Enable warning output by default\n* [#4477](https://github.com/xmake-io/xmake/issues/4477): Improve runtimes to support libc++/libstdc++\n* [#4657](https://github.com/xmake-io/xmake/issues/4657): Improve to select script pattern\n* [#4673](https://github.com/xmake-io/xmake/pull/4673): Refactor modules support\n* [#4746](https://github.com/xmake-io/xmake/pull/4746): Add native modules support for cmake generator\n\n### Bugs Fixed\n\n* [#4596](https://github.com/xmake-io/xmake/issues/4596): Fix remote build cache\n* [#4689](https://github.com/xmake-io/xmake/issues/4689): Fix deps inherit\n\n## v2.8.6\n\n### New features\n\n* Add `network.mode` policy\n* [#1433](https://github.com/xmake-io/xmake/issues/1433): Add `xmake pack` command to generate NSIS/zip/tar.gz/rpm/srpm/runself packages like cmake/cpack\n* [#4435](https://github.com/xmake-io/xmake/issues/4435): Support batchsize for UnityBuild in Group Mode\n* [#4485](https://github.com/xmake-io/xmake/pull/4485): Support package.install_locally\n* Support NetBSD\n\n### Changes\n\n* [#4484](https://github.com/xmake-io/xmake/pull/4484): Improve swig rule\n* Improve Haiku support\n\n### Bugs fixed\n\n* [#4372](https://github.com/xmake-io/xmake/issues/4372): Fix protobuf rules\n* [#4439](https://github.com/xmake-io/xmake/issues/4439): Fix asn1c rules\n\n## v2.8.5\n\n### New features\n\n* [#1452](https://github.com/xmake-io/xmake/issues/1452): Improve link mechanism and order\n* [#1438](https://github.com/xmake-io/xmake/issues/1438): Support code amalgamation\n* [#3381](https://github.com/xmake-io/xmake/issues/3381): Add `xmake test` support\n* [#4276](https://github.com/xmake-io/xmake/issues/4276): Support custom scope api\n* [#4286](https://github.com/xmake-io/xmake/pull/4286): Add Apple XROS support\n* [#4345](https://github.com/xmake-io/xmake/issues/4345): Support check sizeof\n* [#4369](https://github.com/xmake-io/xmake/pull/4369): Add windows.manifest.uac policy\n\n### Changes\n\n* [#4284](https://github.com/xmake-io/xmake/issues/4284): Improve builtin includes\n\n### Bugs fixed\n\n* [#4256](https://github.com/xmake-io/xmake/issues/4256): Fix intellisense for vsxmake/c++modules\n\n## v2.8.3\n\n### New features\n\n* [#4122](https://github.com/xmake-io/xmake/issues/4122): Support Lua Debugger (EmmyLua)\n* [#4132](https://github.com/xmake-io/xmake/pull/4132): Support cppfront\n* [#4147](https://github.com/xmake-io/xmake/issues/4147): Add hlsl2spv rule\n* [#4226](https://github.com/xmake-io/xmake/issues/4226): Support sanitizers for package and policy\n* Add lib.lua.package module\n* Add `run.autobuild` policy\n* Add global policies `xmake g --policies=`\n\n### Changes\n\n* [#4119](https://github.com/xmake-io/xmake/issues/4119): Improve to support emcc toolchain and emscripten package\n* [#4154](https://github.com/xmake-io/xmake/issues/4154): Add `xmake -r --shallow target` to rebuild target without deps\n* Add global ccache storage directory\n* [#4137](https://github.com/xmake-io/xmake/issues/4137): Support Qt6 for Wasm\n* [#4173](https://github.com/xmake-io/xmake/issues/4173): Add recheck argument to on_config\n* [#4200](https://github.com/xmake-io/xmake/pull/4200): Improve remote build to support debugging xmake source code.\n* [#4209](https://github.com/xmake-io/xmake/issues/4209): Add extra and pedantic warnings\n\n### Bugs fixed\n\n* [#4110](https://github.com/xmake-io/xmake/issues/4110): Fix extrafiles\n* [#4115](https://github.com/xmake-io/xmake/issues/4115): Fix compile_commands generator for clangd\n* [#4199](https://github.com/xmake-io/xmake/pull/4199): Fix compile_commands generator for c++ modules\n* Fix os.mv fail on window\n* [#4214](https://github.com/xmake-io/xmake/issues/4214): Fix rust workspace build error\n\n## v2.8.2\n\n### New features\n\n* [#4002](https://github.com/xmake-io/xmake/issues/4002): Add soname and version support\n* [#1613](https://github.com/xmake-io/xmake/issues/1613): Add avx512 and sse4.2 for add_vectorexts\n* [#2471](https://github.com/xmake-io/xmake/issues/2471): Add set_encodings to set source/target encodings\n* [#4071](https://github.com/xmake-io/xmake/pull/4071): Support the stm8 assembler on the sdcc toolchain.\n* [#4101](https://github.com/xmake-io/xmake/issues/4101): Add force includes for c/c++\n* [#2384](https://github.com/xmake-io/xmake/issues/2384): Add extrafiles for vs/vsxmake generator\n\n### Changes\n\n* [#3960](https://github.com/xmake-io/xmake/issues/3960): Improve msys2/crt64 support\n* [#4032](https://github.com/xmake-io/xmake/pull/4032): Remove some old deprecated apis\n* Improve to upgrade vcproj files in tools.msbuild\n* Support add_requires(\"xmake::xxx\") package\n* [#4049](https://github.com/xmake-io/xmake/issues/4049): Improve rust to support cross-compilation\n* Improve clang modules support\n\n### Bugs fixed\n\n* Fix exit all child processes on macOS/Linux\n\n## v2.8.1\n\n### New features\n\n* [#3821](https://github.com/xmake-io/xmake/pull/3821): Add longpath option for windows installer\n* [#3828](https://github.com/xmake-io/xmake/pull/3828): Add support for zypper package manager\n* [#3871](https://github.com/xmake-io/xmake/issues/3871): Improve tools.msbuild to support for upgrading vsproj\n* [#3148](https://github.com/xmake-io/xmake/issues/3148): Support grpc for protobuf\n* [#3889](https://github.com/xmake-io/xmake/issues/3889): Support to add library path for add_links\n* [#3912](https://github.com/orgs/xmake-io/issues/3912): Add set_pmxxheader to support objc precompiled header\n* add_links support library file path\n\n### Changes\n\n* [#3752](https://github.com/xmake-io/xmake/issues/3752): Improve os.getenvs for windows\n* [#3371](https://github.com/xmake-io/xmake/issues/3371): Improve tools.cmake to support ninja generator for wasm\n* [#3777](https://github.com/xmake-io/xmake/issues/3777): Improve to find package from pkg-config\n* [#3815](https://github.com/xmake-io/xmake/pull/3815): Improve tools.xmake to pass toolchains for windows\n* [#3857](https://github.com/xmake-io/xmake/issues/3857): Improve to generate compile_commands.json\n* [#3892](https://github.com/xmake-io/xmake/issues/3892): Improve to search packages from description\n* [#3916](https://github.com/xmake-io/xmake/issues/3916): Improve to build swift program, support for multiple modules\n* Update lua runtime to 5.4.6\n\n### Bugs fixed\n\n* [#3755](https://github.com/xmake-io/xmake/pull/3755): Fix find_tool from xmake/packages\n* [#3787](https://github.com/xmake-io/xmake/issues/3787): Fix packages from conan 2.x\n* [#3839](https://github.com/orgs/xmake-io/discussions/3839): Fix vs_runtime for conan 2.x\n\n## v2.7.9\n\n### New features\n\n* [#3613](https://github.com/xmake-io/xmake/issues/3613): Add `wasm.preloadfiles` configuration for wasm\n* [#3703](https://github.com/xmake-io/xmake/pull/3703): Support for conan >=2.0.5\n\n### Changes\n\n* [#3669](https://github.com/xmake-io/xmake/issues/3669): Improve cmake generator to support add_cxflags with the given tool\n* [#3679](https://github.com/xmake-io/xmake/issues/3679): Improve `xrepo clean`\n* [#3662](https://github.com/xmake-io/xmake/issues/3662): Improve cmake/make generator for lex/yacc project\n* [#3697](https://github.com/xmake-io/xmake/issues/3662): Improve trybuild/cmake\n* [#3730](https://github.com/xmake-io/xmake/issues/3730): Improve c++modules package installation\n\n### Bugs fixed\n\n* [#3596](https://github.com/xmake-io/xmake/issues/3596): Fix check_cxxfuncs and check_cxxsnippets\n* [#3603](https://github.com/xmake-io/xmake/issues/3603): Fix `xmake update`\n* [#3614](https://github.com/xmake-io/xmake/issues/3614): Fix qt envirnoment when running target\n* [#3628](https://github.com/xmake-io/xmake/issues/3628): Fix msys2/mingw setenv and os.exec issue\n* Fix setenv for msys/mingw\n\n## v2.7.8\n\n### New features\n\n* [#3518](https://github.com/xmake-io/xmake/issues/3518): Profile compile and link performance\n* [#3522](https://github.com/xmake-io/xmake/issues/3522): Add has_cflags, has_xxx for target\n* [#3537](https://github.com/xmake-io/xmake/issues/3537): Add --fix for clang.tidy checker\n\n### Changes\n\n* [#3433](https://github.com/xmake-io/xmake/issues/3433): Improve to build Qt project on msys2/mingw64 and wasm\n* [#3419](https://github.com/xmake-io/xmake/issues/3419): Support fish shell envirnoment\n* [#3455](https://github.com/xmake-io/xmake/issues/3455): Dlang incremental build support\n* [#3498](https://github.com/xmake-io/xmake/issues/3498): Improve to bind package virtual envirnoments\n* [#3504](https://github.com/xmake-io/xmake/pull/3504): Add swig java support\n* [#3508](https://github.com/xmake-io/xmake/issues/3508): Improve trybuild/cmake to support for switching toolchain\n* disable build cache for msvc, because msvc's preprocessor is too slow.\n\n### Bugs fixed\n\n* [#3436](https://github.com/xmake-io/xmake/issues/3436): Fix complete and menuconf\n* [#3463](https://github.com/xmake-io/xmake/issues/3463): Fix c++modules cache issue\n* [#3545](https://github.com/xmake-io/xmake/issues/3545): Fix parsedeps for armcc\n\n## v2.7.7\n\n### New features\n\n* Add Haiku support\n* [#3326](https://github.com/xmake-io/xmake/issues/3326): Add `xmake check` to check project code (clang-tidy) and configuration\n* [#3332](https://github.com/xmake-io/xmake/pull/3332): add custom http headers when downloading packages\n\n### Changes\n\n* [#3318](https://github.com/xmake-io/xmake/pull/3318): Improve dlang toolchains\n* [#2591](https://github.com/xmake-io/xmake/issues/2591): Improve target analysis\n* [#3342](https://github.com/xmake-io/xmake/issues/3342): Improve to configure working and build directories\n* [#3373](https://github.com/xmake-io/xmake/issues/3373): Improve std modules support for clang-17\n* Improve to strip/optimization for dmd/ldc2\n\n### Bugs fixed\n\n* [#3317](https://github.com/xmake-io/xmake/pull/3317): Fix languages for qt project.\n* [#3321](https://github.com/xmake-io/xmake/issues/3321): Fix dependfile when generating configiles\n* [#3296](https://github.com/xmake-io/xmake/issues/3296): Fix build error on macOS arm64\n\n## v2.7.6\n\n### New features\n\n* [#3228](https://github.com/xmake-io/xmake/pull/3228): Add support of importing modules from packages\n* [#3257](https://github.com/xmake-io/xmake/issues/3257): Add support for iverilog and verilator\n* Support for xp and vc6.0\n* [#3214](https://github.com/xmake-io/xmake/pull/3214): Completion on xrepo install packages\n\n### Changes\n\n* [#3255](https://github.com/xmake-io/xmake/pull/3225): Improve clang libc++ module support\n* Support for compiling xmake using mingw\n* Improve compatibility issues with xmake running on win xp\n* Add pure lua json implementation instead of lua-cjson if the external dependencies are enabled\n\n### Bugs fixed\n\n* [#3229](https://github.com/xmake-io/xmake/issues/3229): Fix find rc.exe for vs2015\n* [#3271](https://github.com/xmake-io/xmake/issues/3271): Fix macro defines with spaces\n* [#3273](https://github.com/xmake-io/xmake/issues/3273): Fix nim link error\n* [#3286](https://github.com/xmake-io/xmake/issues/3286): Fix compile_commands for clangd\n\n## v2.7.5\n\n### New features\n\n* [#3201](https://github.com/xmake-io/xmake/pull/3201): Add completer and xrepo complete\n* [#3233](https://github.com/xmake-io/xmake/issues/3233): Add MASM32 sdk toolchain\n\n### Changes\n\n* [#3216](https://github.com/xmake-io/xmake/pull/3216): Add intel one api toolkits detection\n* [#3020](https://github.com/xmake-io/xmake/issues/3020): Add `--lsp=clangd` to improve to generate compile_commands.json\n* [#3215](https://github.com/xmake-io/xmake/issues/3215): Add includedirs and defines to c51\n* [#3251](https://github.com/xmake-io/xmake/issues/3251): Improve to build zig and c program\n\n### Bugs fixed\n\n* [#3203](https://github.com/xmake-io/xmake/issues/3203): Fix compile_commands\n* [#3222](https://github.com/xmake-io/xmake/issues/3222): Fix precompiled headers in ObjC\n* [#3240](https://github.com/xmake-io/xmake/pull/3240): Fix target run with single arguments\n* [#3238](https://github.com/xmake-io/xmake/pull/3238): Fix clang module mapper\n\n## v2.7.4\n\n### New features\n\n* [#3049](https://github.com/xmake-io/xmake/pull/3049): Add `xmake format` plugin\n* Add `plugin.compile_commands.autoupdate` rule\n* [#3172](https://github.com/xmake-io/xmake/pull/3172): Add xmake.sh\n* [#3168](https://github.com/xmake-io/xmake/pull/3168): add support of C++23 standard modules on msvc\n\n### Changes\n\n* [#3056](https://github.com/xmake-io/xmake/issues/3056): Improve zig support\n* [#3060](https://github.com/xmake-io/xmake/issues/3060): Improve to detect msys2 for clang toolchains envirnoment\n* [#3071](https://github.com/xmake-io/xmake/issues/3071): Support rc for llvm/clang toolchain\n* [#3122](https://github.com/xmake-io/xmake/pull/3122): Generate dependencies of preprocessed modules to avoid importing #ifdef import\n* [#3125](https://github.com/xmake-io/xmake/pull/3125): Compile private C++20 modules\n* [#3133](https://github.com/xmake-io/xmake/pull/3133): Add support of internal partitions\n* [#3146](https://github.com/xmake-io/xmake/issues/3146): Add default components for packages\n* [#3192](https://github.com/xmake-io/xmake/issues/3192): JSON output for auto complete\n\n### Bugs fixed\n\n* Fix requires-lock bug\n* [#3065](https://github.com/xmake-io/xmake/issues/3065): Fix missing package dependences\n* [#3082](https://github.com/xmake-io/xmake/issues/3082): Fix build.ninja generator\n* [#3092](https://github.com/xmake-io/xmake/issues/3092): Fix xrepo add-repo error handing\n* [#3013](https://github.com/xmake-io/xmake/issues/3013): Fix and support windows UNC path\n* [#2902](https://github.com/xmake-io/xmake/issues/2902): Fix file not access by another process occupied\n* [#3074](https://github.com/xmake-io/xmake/issues/3074): Fix CMakelists generator\n* [#3141](https://github.com/xmake-io/xmake/pull/3141): Fix import order on GCC and force it on clang and msvc #3141\n* Fix tools/xmake package build directory\n* [#3159](https://github.com/xmake-io/xmake/issues/3159): Fix compile_commands for CLion\n\n## v2.7.3\n\n### New features\n\n* A new optional configuration syntax. It is LSP friendly, automatically calls target_end() to achieve scope isolation.\n* [#2944](https://github.com/xmake-io/xmake/issues/2944): Add `gnu-rm.binary` and `gnu-rm.static` rules and tests for embed project\n* [#2636](https://github.com/xmake-io/xmake/issues/2636): Support package components\n* Support armasm/armasm64 for msvc\n* [#3023](https://github.com/xmake-io/xmake/pull/3023): Add support for debugging with renderdoc\n* [#3022](https://github.com/xmake-io/xmake/issues/3022): Add flags for specific compilers and linkers\n* [#3025](https://github.com/xmake-io/xmake/pull/3025): C++ exception enabled/disabled switch method\n* [#3017](https://github.com/xmake-io/xmake/pull/3017): Support ispc compiler\n\n### Changes\n\n* [#2925](https://github.com/xmake-io/xmake/issues/2925): Improve doxygen plugin\n* [#2948](https://github.com/xmake-io/xmake/issues/2948): Support OpenBSD\n* Add `xmake g --insecure-ssl=y` option to disable ssl certificate when downloading packages\n* [#2971](https://github.com/xmake-io/xmake/pull/2971): Stabilize vs and vsxmake project generation\n* [#3000](https://github.com/xmake-io/xmake/issues/3000): Incremental compilation support for modules\n* [#3016](https://github.com/xmake-io/xmake/pull/3016): Improve clang/msvc to better support std modules\n\n### Bugs fixed\n\n* [#2949](https://github.com/xmake-io/xmake/issues/2949): Fix vs group\n* [#2952](https://github.com/xmake-io/xmake/issues/2952): Fix armlink for long args\n* [#2954](https://github.com/xmake-io/xmake/issues/2954): Fix c++ module partitions path issue\n* [#3033](https://github.com/xmake-io/xmake/issues/3033): Detect circular modules dependency\n\n## v2.7.2\n\n### New features\n\n* [#2140](https://github.com/xmake-io/xmake/issues/2140): Support Windows Arm64\n* [#2719](https://github.com/xmake-io/xmake/issues/2719): Add `package.librarydeps.strict_compatibility` to strict compatibility for package linkdeps\n* [#2810](https://github.com/xmake-io/xmake/pull/2810): Support os.execv to run shell script file\n* [#2817](https://github.com/xmake-io/xmake/pull/2817): Improve rule to support dependence order\n* [#2824](https://github.com/xmake-io/xmake/pull/2824): Pass cross-file to meson.install and trybuild\n* [#2856](https://github.com/xmake-io/xmake/pull/2856): Improve to debug package using the debug source directory\n* [#2859](https://github.com/xmake-io/xmake/issues/2859): Improve trybuild to build 3rd source library using xmake-repo scripts\n* [#2879](https://github.com/xmake-io/xmake/issues/2879): Support for dynamic creation and injection of rules and targets in script scope\n* [#2374](https://github.com/xmake-io/xmake/issues/2374): Allow xmake package to embed rules and scripts\n* Add clang-cl toolchain\n\n### Changes\n\n* [#2745](https://github.com/xmake-io/xmake/pull/2745): Improve os.cp to support symlink\n* [#2773](https://github.com/xmake-io/xmake/pull/2773): Improve vcpkg packages to support freebsd\n* [#2778](https://github.com/xmake-io/xmake/pull/2778): Improve Improve xrepo.env for target\n* [#2783](https://github.com/xmake-io/xmake/issues/2783): Add digest algorithm option for wdk signtool\n* [#2787](https://github.com/xmake-io/xmake/pull/2787): Improve json to support empty array\n* [#2782](https://github.com/xmake-io/xmake/pull/2782): Improve to find matlab and runtime\n* [#2793](https://github.com/xmake-io/xmake/issues/2793): Improve mconfdialog\n* [#2804](https://github.com/xmake-io/xmake/issues/2804): Support macOS arm64/x86_64 cross-compilation for installing packages\n* [#2809](https://github.com/xmake-io/xmake/issues/2809): Improve cl optimization option\n* Improve trybuild for meson/cmake/autoconf\n* [#2846](https://github.com/xmake-io/xmake/discussions/2846): Improve to generate config files\n* [#2866](https://github.com/xmake-io/xmake/issues/2866): Better control over the order of execution of rules\n\n### Bugs fixed\n\n* [#2740](https://github.com/xmake-io/xmake/issues/2740): Fix build c++ modules stuck and slower for msvc\n* [#2875](https://github.com/xmake-io/xmake/issues/2875): Fix build linux driver error\n* [#2885](https://github.com/xmake-io/xmake/issues/2885): Fix pch not found with msvc/ccache\n\n## v2.7.1\n\n### New features\n\n* [#2555](https://github.com/xmake-io/xmake/issues/2555): Add fwatcher module and `xmake watch` plugin command\n* Add `xmake service --pull 'build/**' outputdir` to pull the given files in remote server\n* [#2641](https://github.com/xmake-io/xmake/pull/2641): Improve C++20 modules, support headerunits and project generators\n* [#2679](https://github.com/xmake-io/xmake/issues/2679): Support Mac Catalyst\n\n### Changes\n\n* [#2576](https://github.com/xmake-io/xmake/issues/2576): More flexible package fetching from cmake\n* [#2577](https://github.com/xmake-io/xmake/issues/2577): Improve add_headerfiles(), add `{install = false}` support\n* [#2603](https://github.com/xmake-io/xmake/issues/2603): Disable `-fdirectives-only` for ccache by default\n* [#2580](https://github.com/xmake-io/xmake/issues/2580): Set stdout to line buffering\n* [#2571](https://github.com/xmake-io/xmake/issues/2571): Improve task scheduling for parallel and distributed compilation based on memory/cpu usage\n* [#2410](https://github.com/xmake-io/xmake/issues/2410): Improve cmakelists generator\n* [#2690](https://github.com/xmake-io/xmake/issues/2690): Improve to pass toolchains to packages\n* [#2686](https://github.com/xmake-io/xmake/issues/2686): Support for incremental compilation and parse header file deps for keil/armcc/armclang\n* [#2562](https://github.com/xmake-io/xmake/issues/2562): Improve include deps for rc.exe\n* Improve the default parallel building jobs number\n\n### Bugs fixed\n\n* [#2614](https://github.com/xmake-io/xmake/issues/2614): Fix building submodules2 tests for msvc\n* [#2620](https://github.com/xmake-io/xmake/issues/2620): Fix build cache for incremental compilation\n* [#2177](https://github.com/xmake-io/xmake/issues/2177): Fix python.library segmentation fault for macosx\n* [#2708](https://github.com/xmake-io/xmake/issues/2708): Fix link error for mode.coverage rule\n* Fix rpath for macos/iphoneos frameworks and application\n\n## v2.6.9\n\n### New features\n\n* [#2474](https://github.com/xmake-io/xmake/issues/2474): Add icx and dpcpp toolchains\n* [#2523](https://github.com/xmake-io/xmake/issues/2523): Improve LTO support\n* [#2527](https://github.com/xmake-io/xmake/issues/2527): Add set_runargs api\n\n### Changes\n\n* Improve tools.cmake to support wasm\n* [#2491](https://github.com/xmake-io/xmake/issues/2491): Fallback to local compiler/cache from remote if server is unreachable\n* [#2514](https://github.com/xmake-io/xmake/issues/2514): Disable Unity Build for project generator\n* [#2473](https://github.com/xmake-io/xmake/issues/2473): Improve apt::find_package to find it from pc files\n* [#2512](https://github.com/xmake-io/xmake/issues/2512): Improve remote service to support timeout configuration\n\n### Bugs fixed\n\n* [#2488](https://github.com/xmake-io/xmake/issues/2488): Fix remote compilation from windows to linux\n* [#2504](https://github.com/xmake-io/xmake/issues/2504): Fix remote build bug on msys2/cygwin\n* [#2525](https://github.com/xmake-io/xmake/issues/2525): Fix install package deps and stuck\n* [#2557](https://github.com/xmake-io/xmake/issues/2557): Fix cmake.find_package links bug\n* Fix cache-induced path conflicts in preprocessed files\n\n## v2.6.8\n\n### New features\n\n* [#2447](https://github.com/xmake-io/xmake/pull/2447): Add qt.qmlplugin rule and support of qmltypesregistrar\n* [#2446](https://github.com/xmake-io/xmake/issues/2446): Support target group for `xmake install`\n* [#2469](https://github.com/xmake-io/xmake/issues/2469): Generate vcpkg-configuration.json\n\n### Changes\n\n* Add `preprocessor.linemarkers` policy to disable linemarkers to speed up ccache/distcc\n* [#2389](https://github.com/xmake-io/xmake/issues/2389): Improve `xmake run` to parallel running of targets\n* [#2417](https://github.com/xmake-io/xmake/issues/2417): Switch the default value of option/showmenu\n* [#2440](https://github.com/xmake-io/xmake/pull/2440): Improve package installation error messages\n* [#2438](https://github.com/xmake-io/xmake/pull/2438): Make sure the solution and project file unchanged by sorting those tables\n* [#2434](https://github.com/xmake-io/xmake/issues/2434): Improve plugins manager, allow to handle multiples plugin repositories\n* [#2421](https://github.com/xmake-io/xmake/issues/2421): Improve config option menu\n* [#2425](https://github.com/xmake-io/xmake/issues/2425): Add `preprocessor.gcc.directives_only` policy\n* [#2455](https://github.com/xmake-io/xmake/issues/2455): Improve optimize options for emcc\n* [#2467](https://github.com/xmake-io/xmake/issues/2467): Add compile fallback for msvc/ccache\n* [#2452](https://github.com/xmake-io/xmake/issues/2452): Add build.warning policy\n\n### Bugs Fixed\n\n* [#2435](https://github.com/xmake-io/xmake/pull/2435): fix the search bug when the package name has an extension name.\n* [#2445](https://github.com/xmake-io/xmake/issues/2445): Fix ccache bug for msvc\n* [#2452](https://github.com/xmake-io/xmake/issues/2452): Fix warnings output for ccache\n\n## v2.6.7\n\n### New features\n\n* [#2318](https://github.com/xmake-io/xmake/issues/2318): Add `xmake f --policies=` config argument to modify project policies\n\n### Changes\n\n* fallback to source code build if the precompiled package is error\n* [#2387](https://github.com/xmake-io/xmake/issues/2387): Improve pkgconfig and find_package\n* Add `build.ccache` policy\n\n### Bugs fixed\n\n* [#2382](https://github.com/xmake-io/xmake/issues/2382): Fix headeronly package configs\n* [#2388](https://github.com/xmake-io/xmake/issues/2388): Fix path bug\n* [#2385](https://github.com/xmake-io/xmake/issues/2385): Fix cmake/find_package\n* [#2395](https://github.com/xmake-io/xmake/issues/2395): Fix c++modules\n* Fix find_qt bug\n\n## v2.6.6\n\n### New features\n\n* [#2327](https://github.com/xmake-io/xmake/issues/2327): Support nvc/nvc++/nvfortran in nvidia-hpc-sdk\n* Add path instance interfaces\n* [#2344](https://github.com/xmake-io/xmake/pull/2344): Add lz4 compress module\n* [#2349](https://github.com/xmake-io/xmake/pull/2349): Add keil/c51 project support\n* [#274](https://github.com/xmake-io/xmake/issues/274): Distributed compilation support\n* Use builtin local cache instead of ccache\n\n### Changes\n\n* [#2309](https://github.com/xmake-io/xmake/issues/2309): Support user authorization for remote compilation\n* Improve remote compilation to support lz4 compression\n\n### Bugs fixed\n\n* Fix lua stack when select package versions\n\n## v2.6.5\n\n### New features\n\n* [#2138](https://github.com/xmake-io/xmake/issues/2138): Support template package\n* [#2185](https://github.com/xmake-io/xmake/issues/2185): Add `--appledev=simulator` to improve apple simulator support\n* [#2227](https://github.com/xmake-io/xmake/issues/2227): Improve cargo package with Cargo.toml file\n* Improve `add_requires` to support git commit as version\n* [#622](https://github.com/xmake-io/xmake/issues/622): Support remote compilation\n* [#2282](https://github.com/xmake-io/xmake/issues/2282): Add `add_filegroups` to support file group for vs/vsxmake/cmake generator\n\n### Changes\n\n* [#2137](https://github.com/xmake-io/xmake/pull/2137): Improve path module\n* Reduce 50% xmake binary size on macOS\n* Improve tools/autoconf,cmake to support toolchain switching.\n* [#2221](https://github.com/xmake-io/xmake/pull/2221): Improve registry api to support unicode\n* [#2225](https://github.com/xmake-io/xmake/issues/2225): Support to parse import dependencies for protobuf\n* [#2265](https://github.com/xmake-io/xmake/issues/2265): Sort CMakeLists.txt\n* Speed up `os.files`\n\n### Bugs fixed\n\n* [#2233](https://github.com/xmake-io/xmake/issues/2233): Fix c++ modules deps\n\n## v2.6.4\n\n### New features\n\n* [#2011](https://github.com/xmake-io/xmake/issues/2011): Support to inherit base package\n* Support to build and run xmake on sparc, alpha, powerpc, s390x and sh4\n* Add on_download for package()\n* [#2021](https://github.com/xmake-io/xmake/issues/2021): Support Swift for linux and windows\n* [#2024](https://github.com/xmake-io/xmake/issues/2024): Add asn1c support\n* [#2031](https://github.com/xmake-io/xmake/issues/2031): Support linker scripts and version scripts for add_files\n* [#2033](https://github.com/xmake-io/xmake/issues/2033): Catch ctrl-c to get current backtrace for debugging stuck\n* [#2059](https://github.com/xmake-io/xmake/pull/2059): Add `xmake update --integrate` to integrate for shell\n* [#2070](https://github.com/xmake-io/xmake/issues/2070): Add built-in xrepo environments\n* [#2117](https://github.com/xmake-io/xmake/pull/2117): Support to pass toolchains to package for other platforms\n* [#2121](https://github.com/xmake-io/xmake/issues/2121): Support to export the given symbols list\n\n### Changes\n\n* [#2036](https://github.com/xmake-io/xmake/issues/2036): Improve xrepo to install packages from configuration file, e.g. `xrepo install xxx.lua`\n* [#2039](https://github.com/xmake-io/xmake/issues/2039): Improve filter directory for vs generator\n* [#2025](https://github.com/xmake-io/xmake/issues/2025): Support phony and headeronly target for vs generator\n* Improve to find vstudio and codesign speed\n* [#2077](https://github.com/xmake-io/xmake/issues/2077): Improve vs project generator to support cuda\n\n### Bugs fixed\n\n* [#2005](https://github.com/xmake-io/xmake/issues/2005): Fix path.extension\n* [#2008](https://github.com/xmake-io/xmake/issues/2008): Fix windows manifest\n* [#2016](https://github.com/xmake-io/xmake/issues/2016): Fix object filename confict for vs project generator\n\n## v2.6.3\n\n### New features\n\n* [#1298](https://github.com/xmake-io/xmake/issues/1928): Support vcpkg manifest mode and select version for package/install\n* [#1896](https://github.com/xmake-io/xmake/issues/1896): Add `python.library` rule to build pybind modules\n* [#1939](https://github.com/xmake-io/xmake/issues/1939): Add `remove_files`, `remove_headerfiles` and mark `del_files` as deprecated\n* Made on_config as the official api for rule/target\n* Add riscv32/64 support\n* [#1970](https://github.com/xmake-io/xmake/issues/1970): Add CMake wrapper for Xrepo C and C++ package manager.\n* Add builtin github mirror pac files, `xmake g --proxy_pac=github_mirror.lua`\n\n### Changes\n\n* [#1923](https://github.com/xmake-io/xmake/issues/1923): Improve to build linux driver, support set custom linux-headers path\n* [#1962](https://github.com/xmake-io/xmake/issues/1962): Improve armclang toolchain to support to build asm\n* [#1959](https://github.com/xmake-io/xmake/pull/1959): Improve vstudio project generator\n* [#1969](https://github.com/xmake-io/xmake/issues/1969): Add default option description\n\n### Bugs fixed\n\n* [#1875](https://github.com/xmake-io/xmake/issues/1875): Fix deploy android qt apk issue\n* [#1973](https://github.com/xmake-io/xmake/issues/1973): Fix merge static archive\n\n## v2.6.2\n\n### New features\n\n* [#1902](https://github.com/xmake-io/xmake/issues/1902): Support to build linux kernel driver modules\n* [#1913](https://github.com/xmake-io/xmake/issues/1913): Build and run targets with given group pattern\n* [#1982](https://github.com/xmake-io/xmake/pull/1982): Fix build c++20 submodules for clang\n\n### Change\n\n* [#1872](https://github.com/xmake-io/xmake/issues/1872): Escape characters for set_configvar\n* [#1888](https://github.com/xmake-io/xmake/issues/1888): Improve windows installer to avoid remove other files\n* [#1895](https://github.com/xmake-io/xmake/issues/1895): Improve `plugin.vsxmake.autoupdate` rule\n* [#1893](https://github.com/xmake-io/xmake/issues/1893): Improve to detect icc and ifort toolchains\n* [#1905](https://github.com/xmake-io/xmake/pull/1905): Add support of external headers without experimental for msvc\n* [#1904](https://github.com/xmake-io/xmake/pull/1904): Improve vs201x generator\n* Add `XMAKE_THEME` envirnoment variable to switch theme\n* [#1907](https://github.com/xmake-io/xmake/issues/1907): Add `-f/--force` to force to create project in a non-empty directory\n* [#1917](https://github.com/xmake-io/xmake/pull/1917): Improve to find_package and configurations\n\n### Bugs fixed\n\n* [#1885](https://github.com/xmake-io/xmake/issues/1885): Fix package:fetch_linkdeps\n* [#1903](https://github.com/xmake-io/xmake/issues/1903): Fix package link order\n\n## v2.6.1\n\n### New features\n\n* [#1799](https://github.com/xmake-io/xmake/issues/1799): Support mixed rust & c++ target and cargo dependences\n* Add `utils.glsl2spv` rules to compile *.vert/*.frag shader files to spirv file and binary c header file\n\n### Changes\n\n* Switch to Lua5.4 runtime by default\n* [#1776](https://github.com/xmake-io/xmake/issues/1776): Improve system::find_package, support to find package from envs\n* [#1786](https://github.com/xmake-io/xmake/issues/1786): Improve apt:find_package, support to find alias package\n* [#1819](https://github.com/xmake-io/xmake/issues/1819): Add precompiled header to cmake generator\n* Improve C++20 module to support std libraries for msvc\n* [#1792](https://github.com/xmake-io/xmake/issues/1792): Add custom command in vs project generator\n* [#1835](https://github.com/xmake-io/xmake/issues/1835): Improve MDK program supports and add `set_runtimes(\"microlib\")`\n* [#1858](https://github.com/xmake-io/xmake/issues/1858): Improve to build c++20 modules with libraries\n* Add $XMAKE_BINARY_REPO and $XMAKE_MAIN_REPO repositories envs\n* [#1865](https://github.com/xmake-io/xmake/issues/1865): Improve openmp projects\n* [#1845](https://github.com/xmake-io/xmake/issues/1845): Install pdb files for static library\n\n### Bugs Fixed\n\n* Fix semver to parse build string with zero prefix\n* [#50](https://github.com/libbpf/libbpf-bootstrap/issues/50): Fix rule and build bpf program errors\n* [#1610](https://github.com/xmake-io/xmake/issues/1610): Fix `xmake f --menu` not responding in vscode and support ConPTY terminal virtkeys\n\n## v2.5.9\n\n### New features\n\n* [#1736](https://github.com/xmake-io/xmake/issues/1736): Support wasi-sdk toolchain\n* Support Lua 5.4 runtime\n* Add gcc-8, gcc-9, gcc-10, gcc-11 toolchains\n* [#1623](https://github.com/xmake-io/xmake/issues/1632): Support find_package from cmake\n* [#1747](https://github.com/xmake-io/xmake/issues/1747): Add `set_kind(\"headeronly\")` for target to install files for headeronly library\n* [#1019](https://github.com/xmake-io/xmake/issues/1019): Support Unity build\n* [#1438](https://github.com/xmake-io/xmake/issues/1438): Support code amalgamation, `xmake l cli.amalgamate`\n* [#1765](https://github.com/xmake-io/xmake/issues/1756): Support nim language\n* [#1762](https://github.com/xmake-io/xmake/issues/1762): Manage and switch the given package envs for `xrepo env`\n* [#1767](https://github.com/xmake-io/xmake/issues/1767): Support Circle compiler\n* [#1753](https://github.com/xmake-io/xmake/issues/1753): Support armcc/armclang toolchains for Keil/MDK\n* [#1774](https://github.com/xmake-io/xmake/issues/1774): Add table.contains api\n* [#1735](https://github.com/xmake-io/xmake/issues/1735): Add custom command in cmake generator\n\n### Changes\n\n* [#1528](https://github.com/xmake-io/xmake/issues/1528): Check c++17/20 features\n* [#1729](https://github.com/xmake-io/xmake/issues/1729): Improve C++20 modules for clang/gcc/msvc, support inter-module dependency compilation and parallel optimization\n* [#1779](https://github.com/xmake-io/xmake/issues/1779): Remove builtin `-Gd` for ml.exe/x86\n* [#1781](https://github.com/xmake-io/xmake/issues/1781): Improve get.sh installation script to support nixos\n\n## v2.5.8\n\n### New features\n\n* [#388](https://github.com/xmake-io/xmake/issues/388): Pascal Language Support\n* [#1682](https://github.com/xmake-io/xmake/issues/1682): Add optional lua5.3 backend instead of luajit to provide better compatibility\n* [#1622](https://github.com/xmake-io/xmake/issues/1622): Support Swig\n* [#1714](https://github.com/xmake-io/xmake/issues/1714): Support build local embed cmake projects\n* [#1715](https://github.com/xmake-io/xmake/issues/1715): Support to detect compiler language standards as features and add `check_macros`\n* Support Loongarch\n\n### Change\n\n* [#1618](https://github.com/xmake-io/xmake/issues/1618): Improve vala to support to generate libraries and bindings\n* Improve Qt rules to support Qt 4.x\n* Improve `set_symbols(\"debug\")` to generate pdb file for clang on windows\n* [#1638](https://github.com/xmake-io/xmake/issues/1638): Improve to merge static library\n* Improve on_load/after_load to support to add target deps dynamically\n* [#1675](https://github.com/xmake-io/xmake/pull/1675): Rename dynamic and import library suffix for mingw\n* [#1694](https://github.com/xmake-io/xmake/issues/1694): Support to define a variable without quotes for configuration files\n* Support Android NDK r23\n* Add `c++latest` and `clatest` for `set_languages`\n* [#1720](https://github.com/xmake-io/xmake/issues/1720): Add `save_scope` and `restore_scope` to fix `check_xxx` apis\n* [#1726](https://github.com/xmake-io/xmake/issues/1726): Improve compile_commands generator to support nvcc\n\n### Bugs fixed\n\n* [#1671](https://github.com/xmake-io/xmake/issues/1671): Fix incorrect absolute path after installing precompiled packages\n* [#1689](https://github.com/xmake-io/xmake/issues/1689): Fix unicode chars bug for vsxmake\n\n## v2.5.7\n\n### New features\n\n* [#1534](https://github.com/xmake-io/xmake/issues/1534): Support to compile Vala lanuage project\n* [#1544](https://github.com/xmake-io/xmake/issues/1544): Add utils.bin2c rule to generate header from binary file\n* [#1547](https://github.com/xmake-io/xmake/issues/1547): Support to run and get output of c/c++ snippets in option\n* [#1567](https://github.com/xmake-io/xmake/issues/1567): Package \"lock file\" support to freeze dependencies\n* [#1597](https://github.com/xmake-io/xmake/issues/1597): Support to compile *.metal files to generate *.metalib and improve xcode.application rule\n\n### Change\n\n* [#1540](https://github.com/xmake-io/xmake/issues/1540): Better support for compilation of automatically generated code\n* [#1578](https://github.com/xmake-io/xmake/issues/1578): Improve add_repositories to support relative path better\n* [#1582](https://github.com/xmake-io/xmake/issues/1582): Improve installation and os.cp to reserve symlink\n\n### Bugs fixed\n\n* [#1531](https://github.com/xmake-io/xmake/issues/1531): Fix error info when loading targets failed\n\n## v2.5.6\n\n### New features\n\n* [#1483](https://github.com/xmake-io/xmake/issues/1483): Add `os.joinenvs()` and improve package tools envirnoments\n* [#1523](https://github.com/xmake-io/xmake/issues/1523): Add `set_allowedmodes`, `set_allowedplats` and `set_allowedarchs`\n* [#1523](https://github.com/xmake-io/xmake/issues/1523): Add `set_defaultmode`, `set_defaultplat` and `set_defaultarch`\n\n### Change\n\n* Improve vs/vsxmake project generator to support vs2022\n* [#1513](https://github.com/xmake-io/xmake/issues/1513): Improve precompiled binary package compatibility on windows/msvc\n* Improve to find vcpkg root directory on windows\n* Improve to support Qt6\n\n### Bugs fixed\n\n* [#489](https://github.com/xmake-io/xmake-repo/pull/489): Fix run os.execv with too long envirnoment value on windows\n\n## v2.5.5\n\n### New features\n\n* [#1421](https://github.com/xmake-io/xmake/issues/1421): Add prefix, suffix and extension options for target names\n* [#1422](https://github.com/xmake-io/xmake/issues/1422): Support search packages from vcpkg, conan\n* [#1424](https://github.com/xmake-io/xmake/issues/1424): Set binary as default target kind\n* [#1140](https://github.com/xmake-io/xmake/issues/1140): Add a way to ask xmake to try to download dependencies from a certain package manager\n* [#1339](https://github.com/xmake-io/xmake/issues/1339): Improve `xmake package` to generate new local/remote packages\n* Add `appletvos` platform support for AppleTV, `xmake f -p appletvos`\n* [#1437](https://github.com/xmake-io/xmake/issues/1437): Add headeronly library type for package to ignore `vs_runtime`\n* [#1351](https://github.com/xmake-io/xmake/issues/1351): Support export/import current configs\n* [#1454](https://github.com/xmake-io/xmake/issues/1454): Support to download and install precompiled image packages from xmake-mirror\n\n### Change\n\n* [#1425](https://github.com/xmake-io/xmake/issues/1425): Improve tools/meson to load msvc envirnoments\n* [#1442](https://github.com/xmake-io/xmake/issues/1442): Support to clone package resources from git url\n* [#1389](https://github.com/xmake-io/xmake/issues/1389): Support to add toolchain envs to `xrepo env`\n* [#1453](https://github.com/xmake-io/xmake/issues/1453): Support to export protobuf includedirs\n* Support vs2022\n\n### Bugs fixed\n\n* [#1413](https://github.com/xmake-io/xmake/issues/1413): Fix hangs on fetching packages\n* [#1420](https://github.com/xmake-io/xmake/issues/1420): Fix config and packages cache\n* [#1445](https://github.com/xmake-io/xmake/issues/1445): Fix WDK driver sign error\n* [#1465](https://github.com/xmake-io/xmake/issues/1465): Fix missing link directory\n\n## v2.5.4\n\n### New features\n\n* [#1323](https://github.com/xmake-io/xmake/issues/1323): Support find and install package from `apt`, `add_requires(\"apt::zlib1g-dev\")`\n* [#1337](https://github.com/xmake-io/xmake/issues/1337): Add environment vars to change package directories\n* [#1338](https://github.com/xmake-io/xmake/issues/1338): Support import and export installed packages\n* [#1087](https://github.com/xmake-io/xmake/issues/1087): Add `xrepo env shell` and support load envs from `add_requires/xmake.lua`\n* [#1313](https://github.com/xmake-io/xmake/issues/1313): Support private package for `add_requires/add_deps`\n* [#1358](https://github.com/xmake-io/xmake/issues/1358): Support to set mirror url to speedup download package\n* [#1369](https://github.com/xmake-io/xmake/pull/1369): Support arm/arm64 packages for vcpkg, thanks @fallending\n* [#1405](https://github.com/xmake-io/xmake/pull/1405): Add portage package manager support, thanks @Phate6660\n\n### Change\n\n* Improve `find_package` and add `package:find_package` for xmake package\n* Remove deprecated `set_config_h` and `set_config_h_prefix` apis\n* [#1343](https://github.com/xmake-io/xmake/issues/1343): Improve to search local package files\n* [#1347](https://github.com/xmake-io/xmake/issues/1347): Improve to vs_runtime configs for binary package\n* [#1353](https://github.com/xmake-io/xmake/issues/1353): Improve del_files() to speedup matching files\n* [#1349](https://github.com/xmake-io/xmake/issues/1349): Improve `xrepo env shell` to support powershell\n\n### Bugs fixed\n\n* [#1380](https://github.com/xmake-io/xmake/issues/1380): Fix add packages errors\n* [#1381](https://github.com/xmake-io/xmake/issues/1381): Fix add local git source for package\n* [#1391](https://github.com/xmake-io/xmake/issues/1391): Fix cuda/nvcc toolchain\n\n### v2.5.3\n\n### New features\n\n* [#1259](https://github.com/xmake-io/xmake/issues/1259): Support `add_files(\"*.def\")` to export symbols for windows/dll\n* [#1267](https://github.com/xmake-io/xmake/issues/1267): add `find_package(\"nvtx\")`\n* [#1274](https://github.com/xmake-io/xmake/issues/1274): add `platform.linux.bpf` rule to build linux/bpf program\n* [#1280](https://github.com/xmake-io/xmake/issues/1280): Support fetchonly package to improve find_package\n* Support to fetch remote ndk toolchain package\n* [#1268](https://github.com/xmake-io/xmake/issues/1268): Add `utils.install.pkgconfig_importfiles` rule to install `*.pc` import file\n* [#1268](https://github.com/xmake-io/xmake/issues/1268): Add `utils.install.cmake_importfiles` rule to install `*.cmake` import files\n* [#348](https://github.com/xmake-io/xmake-repo/pull/348): Add `platform.longpaths` policy to support git longpaths\n* [#1314](https://github.com/xmake-io/xmake/issues/1314): Support to install and use conda packages\n* [#1120](https://github.com/xmake-io/xmake/issues/1120): Add `core.base.cpu` module and improve `os.cpuinfo()`\n* [#1325](https://github.com/xmake-io/xmake/issues/1325): Add builtin git variables for `add_configfiles`\n\n### Change\n\n* [#1275](https://github.com/xmake-io/xmake/issues/1275): Support conditionnal targets for vsxmake plugin\n* [#1290](https://github.com/xmake-io/xmake/pull/1290): Improve android ndk to support >= r22\n* [#1311](https://github.com/xmake-io/xmake/issues/1311): Add packages lib folder to PATH for vsxmake project\n\n### Bugs fixed\n\n* [#1266](https://github.com/xmake-io/xmake/issues/1266): Fix relative repo path in `add_repositories`\n* [#1288](https://github.com/xmake-io/xmake/issues/1288): Fix vsxmake generator with option configs\n\n## v2.5.2\n\n### New features\n\n* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-766481512): Support `zig cc` and `zig c++` as c/c++ compiler\n* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-768193083): Support zig cross-compilation\n* [#1177](https://github.com/xmake-io/xmake/issues/1177): Improve to detect terminal and color codes\n* [#1216](https://github.com/xmake-io/xmake/issues/1216): Pass custom configuration scripts to xrepo\n* Add linuxos builtin module to get linux system information\n* [#1217](https://github.com/xmake-io/xmake/issues/1217): Support to fetch remote toolchain package when building project\n* [#1123](https://github.com/xmake-io/xmake/issues/1123): Add `rule(\"utils.symbols.export_all\")` to export all symbols for windows/dll\n* [#1181](https://github.com/xmake-io/xmake/issues/1181): Add `utils.platform.gnu2mslib(mslib, gnulib)` module api to convert mingw/xxx.dll.a to msvc xxx.lib\n* [#1246](https://github.com/xmake-io/xmake/issues/1246): Improve rules and generators to support commands list\n* [#1239](https://github.com/xmake-io/xmake/issues/1239): Add `add_extsources` to improve find external packages\n* [#1241](https://github.com/xmake-io/xmake/issues/1241): Support add .manifest files for windows program\n* Support to use `xrepo remove --all` to remove all packages\n* [#1254](https://github.com/xmake-io/xmake/issues/1254): Support to export packages to parent target\n\n### Change\n\n* [#1226](https://github.com/xmake-io/xmake/issues/1226): Add missing qt include directories\n* [#1183](https://github.com/xmake-io/xmake/issues/1183): Improve c++ lanuages to support Qt6\n* [#1237](https://github.com/xmake-io/xmake/issues/1237): Add qt.ui files for vsxmake plugin\n* Improve vs/vsxmake plugins to support precompiled header and intellisense\n* [#1090](https://github.com/xmake-io/xmake/issues/1090): Simplify integration of custom code generators\n* [#1065](https://github.com/xmake-io/xmake/issues/1065): Improve protobuf rule to support compile_commands generators\n* [#1249](https://github.com/xmake-io/xmake/issues/1249): Improve vs/vsxmake generator to support startproject\n* [#605](https://github.com/xmake-io/xmake/issues/605): Improve to link orders for add_deps/add_packages\n* Remove deprecated `add_defines_h_if_ok` and `add_defines_h` apis for option\n\n### Bugs fixed\n\n* [#1219](https://github.com/xmake-io/xmake/issues/1219): Fix version check and update\n* [#1235](https://github.com/xmake-io/xmake/issues/1235): Fix include directories with spaces\n\n## v2.5.1\n\n### New features\n\n* [#1035](https://github.com/xmake-io/xmake/issues/1035): The graphics configuration menu fully supports mouse events, and support scroll bar\n* [#1098](https://github.com/xmake-io/xmake/issues/1098): Support stdin for os.execv\n* [#1079](https://github.com/xmake-io/xmake/issues/1079): Add autoupdate plugin rule for vsxmake, `add_rules(\"plugin.vsxmake.autoupdate\")`\n* Add `xmake f --vs_runtime=MT` and `set_runtimes(\"MT\")` to set vs runtime for targets and packages\n* [#1032](https://github.com/xmake-io/xmake/issues/1032): Support to enum registry keys and values\n* [#1026](https://github.com/xmake-io/xmake/issues/1026): Support group for vs/vsxmake project\n* [#1178](https://github.com/xmake-io/xmake/issues/1178): Add `add_requireconfs()` api to rewrite configs of depend packages\n* [#1043](https://github.com/xmake-io/xmake/issues/1043): Add `luarocks.module` rule for luarocks-build-xmake\n* [#1190](https://github.com/xmake-io/xmake/issues/1190): Support for Apple Silicon (macOS ARM)\n* [#1145](https://github.com/xmake-io/xmake/pull/1145): Support Qt deploy for Windows, thanks @SirLynix\n\n### Change\n\n* [#1072](https://github.com/xmake-io/xmake/issues/1072): Fix and improve to parse cl deps\n* Support utf8 for ui modules and `xmake f --menu`\n* Improve to support zig on macOS\n* [#1135](https://github.com/xmake-io/xmake/issues/1135): Improve multi-toolchain and multi-platforms for targets\n* [#1153](https://github.com/xmake-io/xmake/issues/1153): Improve llvm toolchain to support sysroot on macOS\n* [#1071](https://github.com/xmake-io/xmake/issues/1071): Improve to generate vs/vsxmake project to support for remote packages\n* Improve vs/vsxmake project plugin to support global `set_arch()` setting\n* [#1164](https://github.com/xmake-io/xmake/issues/1164): Improve to launch console programs for vsxmake project\n* [#1179](https://github.com/xmake-io/xmake/issues/1179): Improve llvm toolchain and add isysroot\n\n### Bugs fixed\n\n* [#1091](https://github.com/xmake-io/xmake/issues/1091): Fix incorrect ordering of inherited library dependencies\n* [#1105](https://github.com/xmake-io/xmake/issues/1105): Fix c++ language intellisense for vsxmake\n* [#1132](https://github.com/xmake-io/xmake/issues/1132): Fix TrimEnd bug for vsxmake\n* [#1142](https://github.com/xmake-io/xmake/issues/1142): Fix git not found when installing packages\n* Fix macos.version bug for macOS Big Sur\n* [#1084](https://github.com/xmake-io/xmake/issues/1084): Fix `add_defines()` bug (contain spaces)\n* [#1195](https://github.com/xmake-io/xmake/pull/1195): Fix unicode problem for vs and improve find_vstudio/os.exec\n\n## v2.3.9\n\n### New features\n\n* Add new [xrepo](https://github.com/xmake-io/xrepo) command to manage C/C++ packages\n* Support for installing packages of cross-compilation\n* Add musl.cc toolchains\n* [#1009](https://github.com/xmake-io/xmake/issues/1009): Support select and install any version package, e.g. `add_requires(\"libcurl 7.73.0\", {verify = false})`\n* [#1016](https://github.com/xmake-io/xmake/issues/1016): Add license checking for target/packages\n* [#1017](https://github.com/xmake-io/xmake/issues/1017): Support external/system include directories `add_sysincludedirs` for package and toolchains\n* [#1020](https://github.com/xmake-io/xmake/issues/1020): Support to find and install pacman package on archlinux and msys2\n* Support mouse for `xmake f --menu`\n\n### Change\n\n* [#997](https://github.com/xmake-io/xmake/issues/997): Support to set std lanuages for `xmake project -k cmake`\n* [#998](https://github.com/xmake-io/xmake/issues/998): Support to install vcpkg packages with windows-static-md\n* [#996](https://github.com/xmake-io/xmake/issues/996): Improve to find vcpkg directory\n* [#1008](https://github.com/xmake-io/xmake/issues/1008): Improve cross toolchains\n* [#1030](https://github.com/xmake-io/xmake/issues/1030): Improve xcode.framework and xcode.application rules\n* [#1051](https://github.com/xmake-io/xmake/issues/1051): Add `edit` and `embed` to `set_symbols()` only for msvc\n* [#1062](https://github.com/xmake-io/xmake/issues/1062): Improve `xmake project -k vs` plugin.\n\n## v2.3.8\n\n### New features\n\n* [#955](https://github.com/xmake-io/xmake/issues/955): Add zig project templates\n* [#956](https://github.com/xmake-io/xmake/issues/956): Add wasm platform and support Qt/Wasm SDK\n* Upgrade luajit vm and support for runing on mips64 device\n* [#972](https://github.com/xmake-io/xmake/issues/972): Add `depend.on_changed()` api to simplify adding dependent files\n* [#981](https://github.com/xmake-io/xmake/issues/981): Add `set_fpmodels()` for math optimization mode\n* [#980](https://github.com/xmake-io/xmake/issues/980): Support Intel C/C++ and Fortran Compiler\n* [#986](https://github.com/xmake-io/xmake/issues/986): Support for `c11` and `c17` for MSVC Version 16.8 and Above\n* [#979](https://github.com/xmake-io/xmake/issues/979): Add Abstraction for OpenMP. `add_rules(\"c++.openmp\")`\n\n### Change\n\n* [#958](https://github.com/xmake-io/xmake/issues/958): Improve mingw platform to support llvm-mingw toolchain\n* Improve `add_requires(\"zlib~xxx\")` to support for installing multi-packages at same time\n* [#977](https://github.com/xmake-io/xmake/issues/977): Improve find_mingw for windows\n* [#978](https://github.com/xmake-io/xmake/issues/978): Improve toolchain flags order\n* Improve Xcode toolchain to support for macOS/arm64\n\n### Bugs fixed\n\n* [#951](https://github.com/xmake-io/xmake/issues/951): Fix emcc support for windows\n* [#992](https://github.com/xmake-io/xmake/issues/992): Fix filelock bug\n\n## v2.3.7\n\n### New features\n\n* [#2941](https://github.com/microsoft/winget-pkgs/pull/2941): Add support for winget\n* Add xmake-tinyc installer without msvc compiler for windows\n* Add tinyc compiler toolchain\n* Add emcc compiler toolchain (emscripten) to compiling to asm.js and WebAssembly\n* [#947](https://github.com/xmake-io/xmake/issues/947): Add `xmake g --network=private` to enable the private network\n\n### Change\n\n* [#907](https://github.com/xmake-io/xmake/issues/907): Improve to the linker optimization for msvc\n* Improve to detect qt sdk environment\n* [#918](https://github.com/xmake-io/xmake/pull/918): Improve to support cuda11 toolchains\n* Improve Qt support for ubuntu/apt\n* Improve CMake project generator\n* [#931](https://github.com/xmake-io/xmake/issues/931): Support to export packages with all dependences\n* [#930](https://github.com/xmake-io/xmake/issues/930): Support to download package without version list directly\n* [#927](https://github.com/xmake-io/xmake/issues/927): Support to switch arm/thumb mode for android ndk\n* Improve trybuild/cmake to support android/mingw/iphoneos/watchos toolchains\n\n### Bugs fixed\n\n* [#903](https://github.com/xmake-io/xmake/issues/903): Fix install vcpkg packages fails\n* [#912](https://github.com/xmake-io/xmake/issues/912): Fix the custom toolchain\n* [#914](https://github.com/xmake-io/xmake/issues/914): Fix bad light userdata pointer for lua on some aarch64 devices\n\n## v2.3.6\n\n### New features\n\n* Add `xmake project -k xcode` generator (use cmake)\n* [#870](https://github.com/xmake-io/xmake/issues/870): Support gfortran compiler\n* [#887](https://github.com/xmake-io/xmake/pull/887): Support zig compiler\n* [#893](https://github.com/xmake-io/xmake/issues/893): Add json module\n* [#898](https://github.com/xmake-io/xmake/issues/898): Support cross-compilation for golang\n* [#275](https://github.com/xmake-io/xmake/issues/275): Support go package manager to install go packages\n* [#581](https://github.com/xmake-io/xmake/issues/581): Support dub package manager to install dlang packages\n\n### Change\n\n* [#868](https://github.com/xmake-io/xmake/issues/868): Support new cl.exe dependency report files, `/sourceDependencies xxx.json`\n* [#902](https://github.com/xmake-io/xmake/issues/902): Improve to detect cross-compilation toolchain\n\n## v2.3.5\n\n### New features\n\n* Add `xmake show -l envs` to show all builtin envirnoment variables\n* [#861](https://github.com/xmake-io/xmake/issues/861): Support search local package file to install remote package\n* [#854](https://github.com/xmake-io/xmake/issues/854): Support global proxy settings for curl, wget and git\n\n### Change\n\n* [#828](https://github.com/xmake-io/xmake/issues/828): Support to import sub-directory files for protobuf rules\n* [#835](https://github.com/xmake-io/xmake/issues/835): Improve mode.minsizerel to add /GL flags for msvc\n* [#828](https://github.com/xmake-io/xmake/issues/828): Support multi-level directories for protobuf/import\n* [#838](https://github.com/xmake-io/xmake/issues/838#issuecomment-643570920): Support to override builtin-rules for `add_files(\"src/*.c\", {rules = {\"xx\", override = true}})`\n* [#847](https://github.com/xmake-io/xmake/issues/847): Support to parse include deps for rc file\n* Improve msvc tool chain, remove the dependence of global environment variables\n* [#857](https://github.com/xmake-io/xmake/pull/857): Improved `set_toolchains()` when cross-compilation is supported, specific target can be switched to host toolchain and compiled at the same time\n\n### Bugs fixed\n\n* Fix the progress bug for theme\n* [#829](https://github.com/xmake-io/xmake/issues/829): Fix invalid sysroot path for macOS\n* [#832](https://github.com/xmake-io/xmake/issues/832): Fix find_packages bug for the debug mode\n\n## v2.3.4\n\n### New features\n\n* [#630](https://github.com/xmake-io/xmake/issues/630): Support *BSD system, e.g. FreeBSD, ..\n* Add wprint builtin api to show warnings\n* [#784](https://github.com/xmake-io/xmake/issues/784): Add `set_policy()` to set and modify some builtin policies\n* [#780](https://github.com/xmake-io/xmake/issues/780): Add set_toolchains/set_toolsets for target and improve to detect cross-compilation toolchains\n* [#798](https://github.com/xmake-io/xmake/issues/798): Add `xmake show` plugin to show some builtin configuration values and infos\n* [#797](https://github.com/xmake-io/xmake/issues/797): Add ninja theme style, e.g. `xmake g --theme=ninja`\n* [#816](https://github.com/xmake-io/xmake/issues/816): Add mode.releasedbg and mode.minsizerel rules\n* [#819](https://github.com/xmake-io/xmake/issues/819): Support ansi/vt100 terminal control\n\n### Change\n\n* [#771](https://github.com/xmake-io/xmake/issues/771): Check includedirs, linkdirs and frameworkdirs\n* [#774](https://github.com/xmake-io/xmake/issues/774): Support ltui windows resize for `xmake f --menu`\n* [#782](https://github.com/xmake-io/xmake/issues/782): Add check flags failed tips for add_cxflags, ..\n* [#808](https://github.com/xmake-io/xmake/issues/808): Support add_frameworks for cmakelists\n* [#820](https://github.com/xmake-io/xmake/issues/820): Support independent working/build directory\n\n### Bugs fixed\n\n* [#786](https://github.com/xmake-io/xmake/issues/786): Fix check header file deps\n* [#810](https://github.com/xmake-io/xmake/issues/810): Fix strip debug bug for linux\n\n## v2.3.3\n\n### New features\n\n* [#727](https://github.com/xmake-io/xmake/issues/727): Strip and generate debug symbols file (.so/.dSYM) for android/ios program\n* [#687](https://github.com/xmake-io/xmake/issues/687): Support to generate objc/bundle program.\n* [#743](https://github.com/xmake-io/xmake/issues/743): Support to generate objc/framework program.\n* Support to compile bundle, framework, mac application and ios application, and all some project templates\n* Support generate ios *.ipa file and codesign\n* Add xmake.cli rule to develop lua program with xmake core engine\n\n### Change\n\n* [#750](https://github.com/xmake-io/xmake/issues/750): Improve qt.widgetapp rule to support private slot\n* Improve Qt/deploy for android and support Qt 5.14.0\n\n## v2.3.2\n\n### New features\n\n* Add powershell theme for powershell terminal\n* Add `xmake --dry-run -v` to dry run building target and only show verbose build command.\n* [#712](https://github.com/xmake-io/xmake/issues/712): Add sdcc platform and support sdcc compiler\n\n### Change\n\n* [#589](https://github.com/xmake-io/xmake/issues/589): Improve and optimize build speed, supports parallel compilation and linking across targets\n* Improve the ninja/cmake generator\n* [#728](https://github.com/xmake-io/xmake/issues/728): Improve os.cp to support reserve source directory structure\n* [#732](https://github.com/xmake-io/xmake/issues/732): Improve find_package to support `homebrew/cmake` pacakges\n* [#695](https://github.com/xmake-io/xmake/issues/695): Improve android abi\n\n### Bugs fixed\n\n* Fix the link errors output issues for msvc\n* [#718](https://github.com/xmake-io/xmake/issues/718): Fix download cache bug for package\n* [#722](https://github.com/xmake-io/xmake/issues/722): Fix invalid package deps\n* [#719](https://github.com/xmake-io/xmake/issues/719): Fix process exit bug\n* [#720](https://github.com/xmake-io/xmake/issues/720): Fix compile_commands generator\n\n## v2.3.1\n\n### New features\n\n* [#675](https://github.com/xmake-io/xmake/issues/675): Support to compile `*.c` as c++, `add_files(\"*.c\", {sourcekind = \"cxx\"})`.\n* [#681](https://github.com/xmake-io/xmake/issues/681): Support compile xmake on msys/cygwin and add msys/cygwin platform\n* Add socket/pipe io modules and support to schedule socket/process/pipe in coroutine\n* [#192](https://github.com/xmake-io/xmake/issues/192): Try building project with the third-party buildsystem\n* Enable color diagnostics output for gcc/clang\n* [#588](https://github.com/xmake-io/xmake/issues/588): Improve project generator, `xmake project -k ninja`, support for build.ninja\n\n### Change\n\n* [#665](https://github.com/xmake-io/xmake/issues/665): Support to parse *nix style command options, thanks [@OpportunityLiu](https://github.com/OpportunityLiu)\n* [#673](https://github.com/xmake-io/xmake/pull/673): Improve tab complete to support argument values\n* [#680](https://github.com/xmake-io/xmake/issues/680): Improve get.sh scripts and add download mirrors\n* Improve process scheduler\n* [#651](https://github.com/xmake-io/xmake/issues/651): Improve os/io module syserrors tips\n\n### Bugs fixed\n\n* Fix incremental compilation for checking the dependent file\n* Fix log output for parsing xmake-vscode/problem info\n* [#684](https://github.com/xmake-io/xmake/issues/684): Fix linker errors for android ndk on windows\n\n## v2.2.9\n\n### New features\n\n* [#569](https://github.com/xmake-io/xmake/pull/569): Add c++ modules build rules\n* Add `xmake project -k xmakefile` generator\n* [620](https://github.com/xmake-io/xmake/issues/620): Add global `~/.xmakerc.lua` for all projects.\n* [593](https://github.com/xmake-io/xmake/pull/593): Add `core.base.socket` module.\n\n### Change\n\n* [#563](https://github.com/xmake-io/xmake/pull/563): Separate build rules for specific language files from action/build\n* [#570](https://github.com/xmake-io/xmake/issues/570): Add `qt.widgetapp` and `qt.quickapp` rules\n* [#576](https://github.com/xmake-io/xmake/issues/576): Uses `set_toolchain` instead of `add_tools` and `set_tools`\n* Improve `xmake create` action\n* [#589](https://github.com/xmake-io/xmake/issues/589): Improve the default build jobs number to optimize build speed\n* [#598](https://github.com/xmake-io/xmake/issues/598): Improve find_package to support .tbd libraries on macOS\n* [#615](https://github.com/xmake-io/xmake/issues/615): Support to install and use other archs and ios conan packages\n* [#629](https://github.com/xmake-io/xmake/issues/629): Improve hash.uuid and implement uuid v4\n* [#639](https://github.com/xmake-io/xmake/issues/639): Improve to parse argument options to support -jN\n\n### Bugs fixed\n\n* [#567](https://github.com/xmake-io/xmake/issues/567): Fix out of memory for serialize\n* [#566](https://github.com/xmake-io/xmake/issues/566): Fix link order problem with remote packages\n* [#565](https://github.com/xmake-io/xmake/issues/565): Fix run path for vcpkg packages\n* [#597](https://github.com/xmake-io/xmake/issues/597): Fix run `xmake require` command too slowly\n* [#634](https://github.com/xmake-io/xmake/issues/634): Fix mode.coverage rule and check flags\n\n## v2.2.8\n\n### New features\n\n* Add protobuf c/c++ rules\n* [#468](https://github.com/xmake-io/xmake/pull/468): Add utf-8 support for io module on windows\n* [#472](https://github.com/xmake-io/xmake/pull/472): Add `xmake project -k vsxmake` plugin to support call xmake from vs/msbuild\n* [#487](https://github.com/xmake-io/xmake/issues/487): Support to build the selected files for the given target\n* Add filelock for io\n* [#513](https://github.com/xmake-io/xmake/issues/513): Support for android/termux\n* [#517](https://github.com/xmake-io/xmake/issues/517): Add `add_cleanfiles` api for target\n* [#537](https://github.com/xmake-io/xmake/pull/537): Add `set_runenv` api to override os/envs\n\n### Changes\n\n* [#257](https://github.com/xmake-io/xmake/issues/257): Lock the whole project to avoid other process to access.\n* Attempt to enable /dev/shm for the os.tmpdir\n* [#542](https://github.com/xmake-io/xmake/pull/542): Improve vs unicode output for link/cl\n* Improve binary bitcode lua scripts in the program directory\n\n### Bugs fixed\n\n* [#549](https://github.com/xmake-io/xmake/issues/549): Fix error caused by the new vsDevCmd.bat of vs2019\n\n## v2.2.7\n\n### New features\n\n* [#455](https://github.com/xmake-io/xmake/pull/455): support clang as cuda compiler, try `xmake f --cu=clang`\n* [#440](https://github.com/xmake-io/xmake/issues/440): Add `set_rundir()` and `add_runenvs()` api for target/run\n* [#443](https://github.com/xmake-io/xmake/pull/443): Add tab completion support\n* Add `on_link`, `before_link` and `after_link` for rule and target\n* [#190](https://github.com/xmake-io/xmake/issues/190): Add `add_rules(\"lex\", \"yacc\")` rules to support lex/yacc projects\n\n### Changes\n\n* [#430](https://github.com/xmake-io/xmake/pull/430): Add `add_cugencodes()` api to improve set codegen for cuda\n* [#432](https://github.com/xmake-io/xmake/pull/432): support deps analyze for cu file (for CUDA 10.1+)\n* [#437](https://github.com/xmake-io/xmake/issues/437): Support explict git source for xmake update, `xmake update github:xmake-io/xmake#dev`\n* [#438](https://github.com/xmake-io/xmake/pull/438): Support to only update scripts, `xmake update --scriptonly dev`\n* [#433](https://github.com/xmake-io/xmake/issues/433): Improve cuda to support device-link\n* [#442](https://github.com/xmake-io/xmake/issues/442): Improve test library\n\n## v2.2.6\n\n### New features\n\n* [#380](https://github.com/xmake-io/xmake/pull/380): Add support to export compile_flags.txt\n* [#382](https://github.com/xmake-io/xmake/issues/382): Simplify simple scope settings\n* [#397](https://github.com/xmake-io/xmake/issues/397): Add clib package manager support\n* [#404](https://github.com/xmake-io/xmake/issues/404): Support Qt for android and deploy android apk\n* Add some qt empty project templates, e.g. `widgetapp_qt`, `quickapp_qt_static` and `widgetapp_qt_static`\n* [#415](https://github.com/xmake-io/xmake/issues/415): Add `--cu-cxx` config arguments to `nvcc/-ccbin`\n* Add `--ndk_stdcxx=y` and `--ndk_cxxstl=gnustl_static` argument options for android NDK\n\n### Changes\n\n* Improve remote package manager\n* Improve `target:on_xxx` scripts to support to match `android|armv7-a@macosx,linux|x86_64` pattern\n* Improve loadfile to optimize startup speed, decrease 98% time\n\n### Bugs fixed\n\n* [#400](https://github.com/xmake-io/xmake/issues/400): fix c++ languages bug for qt rules\n\n## v2.2.5\n\n### New features\n\n* Add `string.serialize` and `string.deserialize` to serialize and deserialize object, function and others.\n* Add `xmake g --menu`\n* [#283](https://github.com/xmake-io/xmake/issues/283): Add `target:installdir()` and `set_installdir()` api for target\n* [#260](https://github.com/xmake-io/xmake/issues/260): Add `add_platformdirs` api, we can define custom platforms\n* [#310](https://github.com/xmake-io/xmake/issues/310): Add theme feature\n* [#318](https://github.com/xmake-io/xmake/issues/318): Add `add_installfiles` api to target\n* [#339](https://github.com/xmake-io/xmake/issues/339): Improve `add_requires` and `find_package` to integrate the 3rd package manager\n* [#327](https://github.com/xmake-io/xmake/issues/327): Integrate with Conan package manager\n* Add the builtin api `find_packages(\"pcre2\", \"zlib\")` to find multiple packages\n* [#320](https://github.com/xmake-io/xmake/issues/320): Add template configuration files and replace all variables before building\n* [#179](https://github.com/xmake-io/xmake/issues/179): Generate CMakelist.txt file for `xmake project` plugin\n* [#361](https://github.com/xmake-io/xmake/issues/361): Support vs2019 preview\n* [#368](https://github.com/xmake-io/xmake/issues/368): Support `private, public, interface` to improve dependency inheritance like cmake\n* [#284](https://github.com/xmake-io/xmake/issues/284): Add passing user configs description for `package()`\n* [#319](https://github.com/xmake-io/xmake/issues/319): Add `add_headerfiles` to improve to set header files and directories\n* [#342](https://github.com/xmake-io/xmake/issues/342): Add some builtin help functions for `includes()`, e.g. `check_cfuncs`\n\n### Changes\n\n* Improve to switch version and debug mode for the dependent packages\n* [#264](https://github.com/xmake-io/xmake/issues/264): Support `xmake update dev` on windows\n* [#293](https://github.com/xmake-io/xmake/issues/293): Add `xmake f/g --mingw=xxx` configuration option and improve to find_mingw\n* [#301](https://github.com/xmake-io/xmake/issues/301): Improve precompiled header file\n* [#322](https://github.com/xmake-io/xmake/issues/322): Add `option.add_features`, `option.add_cxxsnippets` and `option.add_csnippets`\n* Remove some deprecated interfaces of xmake 1.x, e.g. `add_option_xxx`\n* [#327](https://github.com/xmake-io/xmake/issues/327): Support conan package manager for `lib.detect.find_package`\n* Improve `lib.detect.find_package` and add builtin `find_packages(\"zlib 1.x\", \"openssl\", {xxx = ...})` api\n* Mark `set_modes()` as deprecated, we use `add_rules(\"mode.debug\", \"mode.release\")` instead of it\n* [#353](https://github.com/xmake-io/xmake/issues/353): Improve `target:set`, `target:add` and add `target:del` to modify target configuration\n* [#356](https://github.com/xmake-io/xmake/issues/356): Add `qt_add_static_plugins()` api to support static Qt sdk\n* [#351](https://github.com/xmake-io/xmake/issues/351): Support yasm for generating vs201x project\n* Improve the remote package manager.\n\n### Bugs fixed\n\n* Fix cannot call `set_optimize()` to set optimization flags when exists `add_rules(\"mode.release\")`\n* [#289](https://github.com/xmake-io/xmake/issues/289): Fix unarchive gzip file failed on windows\n* [#296](https://github.com/xmake-io/xmake/issues/296): Fix `option.add_includedirs` for cuda\n* [#321](https://github.com/xmake-io/xmake/issues/321): Fix find program bug with $PATH envirnoment\n\n## v2.2.3\n\n### New features\n\n* [#233](https://github.com/xmake-io/xmake/issues/233): Support windres for mingw platform\n* [#239](https://github.com/xmake-io/xmake/issues/239): Add cparser compiler support\n* Add plugin manager `xmake plugin --help`\n* Add `add_syslinks` api to add system libraries dependence\n* Add `xmake l time xmake [--rebuild]` to record compilation time\n* [#250](https://github.com/xmake-io/xmake/issues/250): Add `xmake f --vs_sdkver=10.0.15063.0` to change windows sdk version\n* Add `lib.luajit.ffi` and `lib.luajit.jit` extension modules\n* [#263](https://github.com/xmake-io/xmake/issues/263): Add new target kind: object to only compile object files\n\n### Changes\n\n* [#229](https://github.com/xmake-io/xmake/issues/229): Improve to select toolset for vcproj plugin\n* Improve compilation dependences\n* Support *.xz for extractor\n* [#249](https://github.com/xmake-io/xmake/pull/249): revise progress formatting to space-leading three digit percentages\n* [#247](https://github.com/xmake-io/xmake/pull/247): Add `-D` and `--diagnosis` instead of `--backtrace`\n* [#259](https://github.com/xmake-io/xmake/issues/259): Improve on_build, on_build_file and on_xxx for target and rule\n* [#269](https://github.com/xmake-io/xmake/issues/269): Clean up the temporary files at last 30 days\n* Improve remote package manager\n* Support to add packages with only header file\n* Support to modify builtin package links, e.g. `add_packages(\"xxx\", {links = {}})`\n\n### Bugs fixed\n\n* Fix state inconsistency after failed outage of installation dependency package\n\n## v2.2.2\n\n### New features\n\n* Support fasm assembler\n* Add `has_config`, `get_config`, and `is_config` apis\n* Add `set_config` to set the default configuration\n* Add `$xmake --try` to try building project using third-party buildsystem\n* Add `set_enabled(false)` to disable target\n* [#69](https://github.com/xmake-io/xmake/issues/69): Add remote package management, `add_requires(\"tbox ~1.6.1\")`\n* [#216](https://github.com/xmake-io/xmake/pull/216): Add windows mfc rules\n\n### Changes\n\n* Improve to detect Qt envirnoment and support mingw\n* Add debug and release rules to the auto-generated xmake.lua\n* [#178](https://github.com/xmake-io/xmake/issues/178): Modify the shared library name for mingw.\n* Support case-insensitive path pattern-matching for `add_files()` on windows\n* Improve to detect Qt sdk directory for `detect.sdks.find_qt`\n* [#184](https://github.com/xmake-io/xmake/issues/184): Improve `lib.detect.find_package` to support vcpkg\n* [#208](https://github.com/xmake-io/xmake/issues/208): Improve rpath for shared library\n* [#225](https://github.com/xmake-io/xmake/issues/225): Improve to detect vs envirnoment\n\n### Bug fixed\n\n* [#177](https://github.com/xmake-io/xmake/issues/177): Fix the dependent target link bug\n* Fix high cpu usage bug and Exit issues for `$ xmake f --menu`\n* [#197](https://github.com/xmake-io/xmake/issues/197): Fix Chinese path for generating vs201x project\n* Fix wdk rules bug\n* [#205](https://github.com/xmake-io/xmake/pull/205): Fix targetdir,objectdir not used in vsproject\n\n## v2.2.1\n\n### New features\n\n* [#158](https://github.com/xmake-io/xmake/issues/158): Support CUDA Toolkit and Compiler\n* Add `set_tools` and `add_tools` apis to change the toolchains for special target\n* Add builtin rules: `mode.debug`, `mode.release`, `mode.profile` and `mode.check`\n* Add `is_mode`, `is_arch` and `is_plat` builtin apis in the custom scripts\n* Add color256 codes\n* [#160](https://github.com/xmake-io/xmake/issues/160): Support Qt compilation environment and add `qt.console`, `qt.application` rules\n* Add some Qt project templates\n* [#169](https://github.com/xmake-io/xmake/issues/169): Support yasm for linux, macosx and windows\n* [#159](https://github.com/xmake-io/xmake/issues/159): Support WDK driver compilation environment\n\n### Changes\n\n* Add FAQ to the auto-generated xmake.lua\n* Support android NDK >= r14\n* Improve warning flags for swiftc\n* [#167](https://github.com/xmake-io/xmake/issues/167): Improve custom rules\n* Improve `os.files` and `os.dirs` api\n* [#171](https://github.com/xmake-io/xmake/issues/171): Improve build dependence for qt rule\n* Implement `make clean` for generating makefile plugin\n\n### Bugs fixed\n\n* Fix force to add flags bug\n* [#157](https://github.com/xmake-io/xmake/issues/157): Fix generate pdb file error if it's output directory does not exists\n* Fix strip all symbols bug for macho target file\n* [#168](https://github.com/xmake-io/xmake/issues/168): Fix generate vs201x project bug with x86/x64 architectures\n\n## v2.1.9\n\n### New features\n\n* Add `del_files()` api to delete files in the files list\n* Add `rule()`, `add_rules()` api to implement the custom build rule and improve `add_files(\"src/*.md\", {rule = \"markdown\"})`\n* Add `os.filesize()` api\n* Add `core.ui.xxx` cui components\n* Add `xmake f --menu` to configure project with a menu configuration interface\n* Add `set_values` api to `option()`\n* Support to generate a menu configuration interface from user custom project options\n* Add source file position to interpreter and search results in menu\n\n### Changes\n\n* Improve to configure cross-toolchains, add tool alias to support unknown tool name, e.g. `xmake f --cc=gcc@ccmips.exe`\n* [#151](https://github.com/xmake-io/xmake/issues/151): Improve to build the share library for the mingw platform\n* Improve to generate makefile plugin\n* Improve the checking errors tips\n* Improve `add_cxflags` .., force to set flags without auto checking: `add_cxflags(\"-DTEST\", {force = true})`\n* Improve `add_files`, add force block to force to set flags without auto checking: `add_files(\"src/*.c\", {force = {cxflags = \"-DTEST\"}})`\n* Improve to search the root project directory\n* Improve to detect vs environment\n* Upgrade luajit to 2.1.0-beta3\n* Support to run xmake on linux (arm, arm64)\n* Improve to generate vs201x project plugin\n\n### Bugs fixed\n\n* Fix complation dependence\n* [#151](https://github.com/xmake-io/xmake/issues/151): Fix `os.nuldev()` for gcc on mingw\n* [#150](https://github.com/xmake-io/xmake/issues/150): Fix the command line string limitation for `ar.exe`\n* Fix `xmake f --cross` error\n* Fix `os.cd` to the windows root path bug\n\n## v2.1.8\n\n### New features\n\n* Add `XMAKE_LOGFILE` environment variable to dump the output info to file\n* Support tinyc compiler\n\n### Changes\n\n* Improve support for IDE/editor plugins (e.g. vscode, sublime, intellij-idea)\n* Add `.gitignore` file when creating new projects\n* Improve to create template project\n* Improve to detect toolchains on macosx without xcode\n* Improve `set_config_header` to support `set_config_header(\"config\", {version = \"2.1.8\", build = \"%Y%m%d%H%M\"})`\n\n### Bugs fixed\n\n* [#145](https://github.com/xmake-io/xmake/issues/145): Fix the current directory when running target\n\n## v2.1.7\n\n### New features\n\n* Add `add_imports` to bulk import modules for the target, option and package script\n* Add `xmake -y/--yes` to confirm the user input by default\n* Add `xmake l package.manager.install xxx` to install software package\n* Add xmake plugin for vscode editor, [xmake-vscode](https://marketplace.visualstudio.com/items?itemName=tboox.xmake-vscode#overview)\n* Add `xmake macro ..` to run the last command\n\n### Changes\n\n* Support 24bits truecolors for `cprint()`\n* Support `@loader_path` and `$ORIGIN` for `add_rpathdirs()`\n* Improve `set_version(\"x.x.x\", {build = \"%Y%m%d%H%M\"})` and add build version\n* Move docs directory to xmake-docs repo\n* Improve install and uninstall actions and support DESTDIR and PREFIX envirnoment variables\n* Optimize to detect flags\n* Add `COLORTERM=nocolor` to disable color output\n* Remove `and_bindings` and `add_rbindings` api\n* Disable to output colors code to file\n* Update project templates with tbox\n* Improve `lib.detect.find_program` interface\n* Enable colors output for windows cmd\n* Add `-w|--warning` arguments to enable the warnings output\n\n### Bugs fixed\n\n* Fix `set_pcxxheader` bug\n* [#140](https://github.com/xmake-io/xmake/issues/140): Fix `os.tmpdir()` in fakeroot\n* [#142](https://github.com/xmake-io/xmake/issues/142): Fix `os.getenv` charset bug on windows\n* Fix compile error with spaces path\n* Fix setenv empty value bug\n\n## v2.1.6\n\n### Changes\n\n* Improve `add_files` to configure the compile option of the given files\n* Inherit links and linkdirs from the dependent targets and options\n* Improve `target.add_deps` and add inherit config, e.g. `add_deps(\"test\", {inherit = false})`\n* Remove the binary files of `tbox.pkg`\n* Use `/Zi` instead of `/ZI` for msvc\n\n### Bugs fixed\n\n* Fix target deps\n* Fix `target:add` and `option:add` bug\n* Fix compilation and installation bug on archlinux\n\n## v2.1.5\n\n### New features\n\n* [#83](https://github.com/xmake-io/xmake/issues/83): Add `add_csnippet` and `add_cxxsnippet` into `option` for detecting some compiler features.\n* [#83](https://github.com/xmake-io/xmake/issues/83): Add user extension modules to detect program, libraries and files.\n* Add `find_program`, `find_file`, `find_library`, `find_tool` and `find_package` module interfaces.\n* Add `net.*` and `devel.*` extension modules\n* Add `val()` api to get the value of builtin-variable, e.g. `val(\"host\")`, `val(\"env PATH\")`, `val(\"shell echo hello\")` and `val(\"reg HKEY_LOCAL_MACHINE\\\\XX;Value\")`\n* Support to compile the microsoft resource file (.rc)\n* Add `has_flags`, `features` and `has_features` for detect module interfaces.\n* Add `option.on_check`, `option.after_check` and `option.before_check` api\n* Add `target.on_load` api\n* [#132](https://github.com/xmake-io/xmake/issues/132): Add `add_frameworkdirs` api\n* Add `lib.detect.has_xxx` and `lib.detect.find_xxx` apis.\n* Add `add_moduledirs` api\n* Add `includes` api instead of `add_subdirs` and `add_subfiles`\n* [#133](https://github.com/xmake-io/xmake/issues/133): Improve the project plugin to generate `compile_commands.json` by run  `xmake project -k compile_commands`\n* Add `set_pcheader` and `set_pcxxheader` to support the precompiled header, support gcc, clang, msvc\n* Add `xmake f -p cross` platform and support the custom platform\n\n### Changes\n\n* [#87](https://github.com/xmake-io/xmake/issues/87): Add includes and links from target deps automatically\n* Improve `import` to load user extension and global modules\n* [#93](https://github.com/xmake-io/xmake/pull/93): Improve `xmake lua` to run a single line command\n* Improve to print gcc error and warning info\n* Improve `print` interface to dump table\n* [#111](https://github.com/xmake-io/xmake/issues/111): Add `--root` common option to allow run xmake command as root\n* [#113](https://github.com/xmake-io/xmake/pull/113): Privilege manage when running as root, store the root privilege and degrade.\n* Improve `xxx_script` in `xmake.lua` to support pattern match, e.g. `on_build(\"iphoneos|arm*\", function (target) end)`\n* improve builtin-variables to support to get the value envirnoment and registry\n* Improve to detect vstudio sdk and cross toolchains envirnoment\n* [#71](https://github.com/xmake-io/xmake/issues/71): Improve to detect compiler and linker from env vars\n* Improve the option detection (cache and multi-jobs) and increase 70% speed\n* [#129](https://github.com/xmake-io/xmake/issues/129): Check link deps and cache the target file\n* Support `*.asm` source files for vs201x project plugin\n* Mark `add_bindings` and `add_rbindings` as deprecated\n* Optimize `xmake rebuild` speed on windows\n* Move `core.project.task` to `core.base.task`\n* Move `echo` and `app2ipa` plugins to [xmake-plugins](https://github.com/xmake-io/xmake-plugins) repo.\n* Add new api `set_config_header(\"config.h\", {prefix = \"\"})` instead of `set_config_h` and `set_config_h_prefix`\n\n### Bugs fixed\n\n* Fix `try-catch-finally`\n* Fix interpreter bug when parsing multi-level subdirs\n* [#115](https://github.com/xmake-io/xmake/pull/115): Fix the path problem of the install script `get.sh`\n* Fix cache bug for import()\n\n## v2.1.4\n\n### New features\n\n* [#68](https://github.com/xmake-io/xmake/issues/68): Add `$(programdir)` and `$(xmake)` builtin variables\n* add `is_host` api to get current host operating system\n* [#79](https://github.com/xmake-io/xmake/issues/79): Improve `xmake lua` to run interactive commands, read-eval-print (REPL)\n\n### Changes\n\n* Modify option menu color.\n* [#71](https://github.com/xmake-io/xmake/issues/71): Improve to map optimization flags for cl.exe\n* [#73](https://github.com/xmake-io/xmake/issues/73): Attempt to get executable path as xmake's program directory\n* Improve the scope of `xmake.lua` in `add_subdirs` and use independent sub-scope to avoid dirty scope\n* [#78](https://github.com/xmake-io/xmake/pull/78): Get terminal size in runtime and soft-wrap the help printing\n* Avoid generate `.xmake` directory if be not in project\n\n### Bugs fixed\n\n* [#67](https://github.com/xmake-io/xmake/issues/67): Fix `sudo make install` permission problem\n* [#70](https://github.com/xmake-io/xmake/issues/70): Fix check android compiler error\n* Fix temporary file path conflict\n* Fix `os.host` and `os.arch` interfaces\n* Fix interpreter bug for loading root api\n* [#77](https://github.com/xmake-io/xmake/pull/77): fix `cprint` no color reset eol\n\n## v2.1.3\n\n### New features\n\n* [#65](https://github.com/xmake-io/xmake/pull/65): Add `set_default` api for target to modify default build and install behavior\n* Allows to run `xmake` command in project subdirectories, it will find the project root directory automatically\n* Add `add_rpathdirs` for target and option\n\n### Changes\n\n* [#61](https://github.com/xmake-io/xmake/pull/61): Provide safer `xmake install` and `xmake uninstall` task with administrator permission\n* Provide `rpm`, `deb` and `osxpkg` install package\n* [#63](https://github.com/xmake-io/xmake/pull/63): More safer build and install xmake\n* [#61](https://github.com/xmake-io/xmake/pull/61): Check run command as root\n* Improve check toolchains and implement delay checking\n* Add user tips when scanning and generating `xmake.lua` automatically\n\n### Bugs fixed\n\n* Fix error tips for checking xmake min version\n* [#60](https://github.com/xmake-io/xmake/issues/60): Fix self-build for macosx and windows\n* [#64](https://github.com/xmake-io/xmake/issues/64): Fix compile android `armv8-a` error\n* [#50](https://github.com/xmake-io/xmake/issues/50): Fix only position independent executables issue for android program\n\n## v2.1.2\n\n### New features\n\n* Add aur package script and support to install xmake from yaourt\n* Add [set_basename](#http://xmake.io/#/manual?id=targetset_basename) api for target\n\n### Changes\n\n* Support vs2017\n* Support compile rust for android\n* Improve vs201x project plugin and support multi-modes compilation.\n\n### Bugs fixed\n\n* Fix cannot find android sdk header files\n* Fix checking option bug\n* [#57](https://github.com/xmake-io/xmake/issues/57): Fix code files mode to 0644\n\n## v2.1.1\n\n### New features\n\n* Add `--links`, `--linkdirs` and `--includedirs` configure arguments\n* Add app2ipa plugin\n* Add dictionary syntax style for `xmake.lua`\n* Provide smart scanning and building mode without `xmake.lua`\n* Add `set_xmakever` api for `xmake.lua`\n* Add `add_frameworks` api for `objc` and `swift`\n* Support multi-languages extension and add `golang`, `dlang` and `rust` language\n* Add optional `target_end`, `option_end`, `task_end` apis for scope\n* Add `golang`, `dlang` and `rust` project templates\n\n### Changes\n\n* Support vs2017 for the project plugin\n* Improve gcc error and warning tips\n* Improve lanuage module\n* Improve print interface, support lua print and format output\n* Automatically scan project files and generate it for building if xmake.lua not exists\n* Modify license to Apache License 2.0\n* Remove some binary tools\n* Remove install.bat script and provide nsis install package\n* Rewrite [documents](http://www.xmake.io/#/home/) using [docute](https://github.com/egoist/docute)\n* Improve `os.run`, `os.exec`, `os.cp`, `os.mv` and `os.rm` interfaces and support wildcard pattern\n* Optimize the output info and add `-q|--quiet` option\n* Improve makefile generator, uses $(XX) variables for tools and flags\n\n### Bugs fixed\n\n* [#41](https://github.com/waruqi/xmake/issues/41): Fix checker bug for windows\n* [#43](https://github.com/waruqi/xmake/issues/43): Avoid generating unnecessary .xmake directory\n* Add c++ stl search directories for android\n* Fix compile error for rhel 5.10\n* Fix `os.iorun` bug\n\n## v2.0.5\n\n### New features\n\n* Add some interpreter builtin-modules\n* Support ml64 assembler for windows x64\n\n### Changes\n\n* Improve ipairs and pairs interfaces and support filter\n* Add filters for generating vs201x project\n* Remove `core/tools` (msys toolchains) and uses xmake to compile core sources on windows\n* Remove `xmake/packages` for templates\n\n### Bugs fixed\n\n* Fix `-def:xxx.def` flags failed for msvc\n* Fix ml.exe assembler script\n* Fix options linking order bug\n\n## v2.0.4\n\n### New features\n\n* Add native shell support for `xmake.lua`. e.g. `add_ldflags(\"$(shell pkg-config --libs sqlite3)\")`\n* Enable pdb symbol files for windows\n* Add debugger support on windows (vsjitdebugger, ollydbg, windbg ... )\n* Add `getenv` interface for the global scope of `xmake.lua`\n* Add plugin for generating vstudio project file (vs2002 - vs2015)\n* Add `set_default` api for option\n\n### Changes\n\n* Improve builtin-variable format\n* Support option for string type\n\n### Bugs fixed\n\n* Fix check ld failed without g++ on linux\n* Fix compile `*.cxx` files failed\n\n## v2.0.3\n\n### New features\n\n* Add check includes dependence automatically\n* Add print colors\n* Add debugger support, e.g. `xmake run -d program ...`\n\n### Changes\n\n* Improve the interfaces of run shell\n* Upgrade luajit to v2.0.4\n* Improve to generate makefile plugin\n* Optimizate the multitasking compiling speed\n\n### Bugs fixed\n\n* Fix install directory bug\n* Fix the root directory error for `import` interface\n* Fix check visual stdio error on windows\n\n## v2.0.2\n\n### Changes\n\n* Change install and uninstall actions\n* Update templates\n* Improve to check function\n\n### Bugs fixed\n\n* [#7](https://github.com/waruqi/xmake/issues/7): Fix create project bug with '[targetname]'\n* [#9](https://github.com/waruqi/xmake/issues/9): Support clang with c++11\n* Fix api scope leaks bug\n* Fix path bug for windows\n* Fix check function bug\n* Fix check toolchains failed\n* Fix compile failed for android on windows\n\n## v2.0.1\n\n### New features\n\n* Add task api for running custom tasks\n* Add plugin expansion and provide some builtin plugins\n* Add export ide project plugin(e.g. makefile and will support to export other projects for vs, xcode in feature)\n* Add demo plugin for printing 'hello xmake'\n* Add make doxygen documents plugin\n* Add macro script plugin\n* Add more modules for developing plugin\n* Add exception using try/catch and simplify grammar for plugin script\n* Add option bindings\n* Show progress when building\n\n### Changes\n\n* Rewrite interpreter for xmake.lua\n* More strict syntax detection mechanism\n* More strict api scope for xmake.lua\n* Simplify template development\n* Extend platforms, tools, templates and actions fastly\n* Simplify api and support import modules\n* Remove dependence for gnu make/nmake, no longer need makefile\n* Optimize speed for building and faster x4 than v1.0.4\n* Optimize automatic detection\n* Modify some api name, but be compatible with the old version\n* Optimize merging static library\n* Simplify cross compilation using argument `--sdk=xxx`\n* Simplify boolean option for command line, e.g. `xmake config --xxx=[y|n|yes|no|true|false]`\n* Merge iphoneos and iphonesimulator platforms\n* Merge watchos and watchsimulator platformss\n\n### Bugs fixed\n\n* [#3](https://github.com/waruqi/xmake/issues/3): ArchLinux compilation failed\n* [#4](https://github.com/waruqi/xmake/issues/4): Install failed for windows\n* Fix envirnoment variable bug for windows\n\n## v1.0.4\n\n### New features\n\n* Support windows assembler\n* Add some project templates\n* Support swift codes\n* Add -v argument for outputing more verbose info\n* Add apple platforms：watchos, watchsimulator\n* Add architecture x64, amd64, x86_amd64 for windows\n* Support switch static and share library\n* Add `-j/--jobs` argument for supporting multi-jobs\n\n### Changes\n\n* Improve `add_files` api and support to add `*.o/obj/a/lib` files for merging static library and object files\n* Optimize installation and remove some binary files\n\n### Bugs fixed\n\n* [#1](https://github.com/waruqi/xmake/issues/4): Install failed for win7\n* Fix checking toolchains bug\n* Fix install script bug\n* Fix install bug for linux x86_64\n\n## v1.0.3\n\n### New features\n\n* Add `set_runscript` api and support custom action\n* Add import api and support import modules in xmake.lua, e.g. os, path, utils ...\n* Add new architecture: arm64-v8a for android\n\n### Bugs fixed\n\n* Fix api bug for `set_installscript`\n* Fix install bug for windows `x86_64`\n* Fix relative path bug\n\n<h1 id=\"中文\"></h1>\n\n# 更新日志\n\n## master (开发中)\n\n### 新特性\n\n* [#7398](https://github.com/xmake-io/xmake/pull/7398): 添加 C# 语言和 dotnet 工具链支持\n* [#7410](https://github.com/xmake-io/xmake/pull/7410): 添加 C# 和 C/C++ 通过 P/Invoke 互操作支持\n* [#7360](https://github.com/xmake-io/xmake/pull/7360): 支持自定义模板\n* [#7367](https://github.com/xmake-io/xmake/pull/7367): 添加 `xmake create --list` 和远程模板分发\n* [#7313](https://github.com/xmake-io/xmake/pull/7313): 添加 `build.release.strip` 策略\n* [#7333](https://github.com/xmake-io/xmake/pull/7333): 添加 `winos.file_signature` 函数\n* [#7336](https://github.com/xmake-io/xmake/pull/7336): 添加运行 wasi 目标支持\n* [#7346](https://github.com/xmake-io/xmake/pull/7346): 添加 nnd 调试器支持\n* [#7366](https://github.com/xmake-io/xmake/pull/7366): 添加 tarxz 打包格式\n\n### 改进\n\n* [#7309](https://github.com/xmake-io/xmake/pull/7309): 保持包源信息\n* [#7310](https://github.com/xmake-io/xmake/pull/7310): 改进检测提示\n* [#7311](https://github.com/xmake-io/xmake/pull/7311): 改进 Xcode 工具链\n* [#7312](https://github.com/xmake-io/xmake/pull/7312): 改进 binutils 支持 wasm\n* [#7320](https://github.com/xmake-io/xmake/pull/7320): 添加 haiku ci\n* [#7329](https://github.com/xmake-io/xmake/pull/7329): 改进 qt deploy 对 macapp 的支持\n* [#7349](https://github.com/xmake-io/xmake/pull/7349): 改进 C++ 模块的 clang/gcc embed-dir 处理\n* [#7368](https://github.com/xmake-io/xmake/pull/7368): 迁移模板到仓库\n* [#7383](https://github.com/xmake-io/xmake/pull/7383): 拆分 zig 工具链为 zig/zigcc\n* [#7384](https://github.com/xmake-io/xmake/pull/7384): 改进 find_hdk\n* [#7387](https://github.com/xmake-io/xmake/pull/7387): 在进度中显示目标名称\n* [#7391](https://github.com/xmake-io/xmake/pull/7391): 改进通过 vcpkg features 查找包\n* [#7392](https://github.com/xmake-io/xmake/pull/7392): 修复 zig 共享库\n* [#7396](https://github.com/xmake-io/xmake/pull/7396): 改进 vcpkg\n* [#7399](https://github.com/xmake-io/xmake/pull/7399): 扩展格式化到 C++ 模块\n* [#7409](https://github.com/xmake-io/xmake/pull/7409): 改进 Windows 上的 ldc\n\n### Bugs 修复\n\n* [#7299](https://github.com/xmake-io/xmake/pull/7299): 修复 vcpkg 依赖处理\n* [#7316](https://github.com/xmake-io/xmake/pull/7316): 修复 components 拼写错误\n* [#7318](https://github.com/xmake-io/xmake/pull/7318): 更新 tbox 修复 tolower/toupper\n* [#7339](https://github.com/xmake-io/xmake/pull/7339): 更新 tbox 修复 win7 启动进程问题\n* [#7344](https://github.com/xmake-io/xmake/pull/7344): 修复 swig jar 包模块\n* [#7345](https://github.com/xmake-io/xmake/pull/7345): 修复检测 clang 信息\n* [#7341](https://github.com/xmake-io/xmake/pull/7341): 修复 WASM QT 6.9\n* [#7356](https://github.com/xmake-io/xmake/pull/7356): 修复 issue #7354\n* [#7371](https://github.com/xmake-io/xmake/pull/7371): 修复测试详细输出\n* [#7386](https://github.com/xmake-io/xmake/pull/7386): 修复安装脚本与 coreutils 9.10 的不兼容\n* [#7393](https://github.com/xmake-io/xmake/pull/7393): 修复构建目标验证\n\n## v3.0.7\n\n### 新特性\n\n* [#7178](https://github.com/xmake-io/xmake/pull/7178): 改进 Verilator 构建文件解析，从 cmake 格式切换到 json 格式\n* [#7186](https://github.com/xmake-io/xmake/pull/7186): 添加 Alpine CI 支持\n* [#7187](https://github.com/xmake-io/xmake/pull/7187): 为 CUDA 架构添加后缀支持\n* [#7190](https://github.com/xmake-io/xmake/pull/7190): Nix 包管理器：添加语义化版本控制并改进版本选择\n* [#7189](https://github.com/xmake-io/xmake/pull/7189): 添加包方案（package schemes）支持\n* [#7208](https://github.com/xmake-io/xmake/pull/7208): 支持 Qt SDK 动态 mkspec 选择\n* [#7219](https://github.com/xmake-io/xmake/pull/7219): 添加 cli.iconv 模块\n* [#7235](https://github.com/xmake-io/xmake/pull/7235): 添加字符串大小写转换函数：lower 和 upper\n* [#7246](https://github.com/xmake-io/xmake/pull/7246): 添加 utf8 模块\n* [#7268](https://github.com/xmake-io/xmake/pull/7268): 为 Nim 源文件添加依赖文件生成\n* [#7269](https://github.com/xmake-io/xmake/pull/7269): 为 zig 工具链添加交叉编译的目标架构验证\n* [#7274](https://github.com/xmake-io/xmake/pull/7274): 添加 os.access 函数用于文件访问检查\n* [#7284](https://github.com/xmake-io/xmake/pull/7284): 添加 `--stdin` 支持\n* [#7293](https://github.com/xmake-io/xmake/pull/7293): 添加在浏览器中运行 wasm 目标的支持\n* [#7300](https://github.com/xmake-io/xmake/pull/7300): 为安装/卸载添加 libdir、includedir、bindir 支持\n* [#7295](https://github.com/xmake-io/xmake/pull/7295): 支持测试输出文件\n\n### 改进\n\n* [#7203](https://github.com/xmake-io/xmake/pull/7203): 改进 MinGW 工具链\n* [#7206](https://github.com/xmake-io/xmake/pull/7206): WDK：为 KMDF 包含路径添加共享目录\n* [#7214](https://github.com/xmake-io/xmake/pull/7214): 改进警告输出\n* [#7216](https://github.com/xmake-io/xmake/pull/7216): 改进依赖锁定（requirelock）\n* [#7223](https://github.com/xmake-io/xmake/pull/7223): 改进 NuGet 库文件匹配，采用基于分数的选择机制\n* [#7226](https://github.com/xmake-io/xmake/pull/7226): 改进 clang-tidy 查找\n* [#7232](https://github.com/xmake-io/xmake/pull/7232): 改进链接器脚本配置\n* [#7237](https://github.com/xmake-io/xmake/pull/7237): 更新 tbox 库以支持大小写敏感\n* [#7240](https://github.com/xmake-io/xmake/pull/7240): 改进 Verilator 标志处理\n* [#7258](https://github.com/xmake-io/xmake/pull/7258): 改进 Qt xpack 打包\n* [#7262](https://github.com/xmake-io/xmake/pull/7262): 改进预编译头文件（PCH）与其他目标的并发处理\n* [#7260](https://github.com/xmake-io/xmake/pull/7260): 改进 Free Pascal 编译器支持\n* [#7270](https://github.com/xmake-io/xmake/pull/7270): 改进方案版本选择机制\n* [#7272](https://github.com/xmake-io/xmake/pull/7272): 增强 Nim 对共享库和 rpath 处理的支持\n* [#7273](https://github.com/xmake-io/xmake/pull/7273): 改进 io.read 和 io.readfile 函数\n* [#7267](https://github.com/xmake-io/xmake/pull/7267): 通过检查父进程增强 Linux 的 shell 检测\n* [#7278](https://github.com/xmake-io/xmake/pull/7278): 改进 os.isexec 函数\n* [#7283](https://github.com/xmake-io/xmake/pull/7283): 增强 compile_commands 支持并添加测试用例\n* [#7285](https://github.com/xmake-io/xmake/pull/7285): 改进 Windows 的 cmd/powershell shell 检测\n* [#7286](https://github.com/xmake-io/xmake/pull/7286): 检测 VS 时检查长环境变量值\n* [#7280](https://github.com/xmake-io/xmake/pull/7280): 仅在交叉编译时添加目标标志\n* [#7290](https://github.com/xmake-io/xmake/pull/7290): 改进 vcvars 处理\n* [#7302](https://github.com/xmake-io/xmake/pull/7302): 改进运行进程错误处理\n* [#7306](https://github.com/xmake-io/xmake/pull/7306): 改进远程构建，支持多主机配置和 `--host` 选项\n* [#7298](https://github.com/xmake-io/xmake/pull/7298): 为 Windows DLL 的 foo/main 示例添加初始实现\n\n### Bugs 修复\n\n* [#7210](https://github.com/xmake-io/xmake/pull/7210): 修复包版本问题\n* [#7213](https://github.com/xmake-io/xmake/pull/7213): 修复导入文件的安装目录问题\n* [#7231](https://github.com/xmake-io/xmake/pull/7231): 修复模块支持中的标志获取问题\n* [#7245](https://github.com/xmake-io/xmake/pull/7245): 修复方案版本选择问题\n* [#7259](https://github.com/xmake-io/xmake/pull/7259): 修复 C++ 函数符号导出问题\n* [#7266](https://github.com/xmake-io/xmake/pull/7266): 修复预编译头文件扩展名问题\n* [#7282](https://github.com/xmake-io/xmake/pull/7282): find_cuda：回滚破坏性变更\n* [#7294](https://github.com/xmake-io/xmake/pull/7294): 修复包工具链问题\n* [#7296](https://github.com/xmake-io/xmake/pull/7296): 修复 emsdk 查找问题\n* [#7202](https://github.com/xmake-io/xmake/pull/7202): 修复 getfenv 函数\n\n## v3.0.6\n\n### 新特性\n\n* [#7141](https://github.com/xmake-io/xmake/pull/7141): 支持禁用 Android 原生应用 glue\n* [#7139](https://github.com/xmake-io/xmake/pull/7139): 添加 Android 原生应用构建支持\n* [#7127](https://github.com/xmake-io/xmake/pull/7127): 为 binutils 添加 deplibs 支持\n* [#7120](https://github.com/xmake-io/xmake/pull/7120): 为 binutils 添加 extractlib 支持\n* [#7106](https://github.com/xmake-io/xmake/pull/7106): 为 MSVC 添加 `/std:c++23preview` 支持\n* [#7105](https://github.com/xmake-io/xmake/pull/7105): 为 glsl/hlsl2spv 添加 `bin2obj` 支持\n* [#7103](https://github.com/xmake-io/xmake/pull/7103): 添加 `bin2obj` 规则（比 `bin2c` 更快）\n* [#7096](https://github.com/xmake-io/xmake/pull/7096): 添加 Flang 工具链支持\n* [#7094](https://github.com/xmake-io/xmake/pull/7094): 添加 `xmake check syntax` 支持\n* [#7091](https://github.com/xmake-io/xmake/pull/7091): 为 MSVC 添加动态调试支持\n* [#7083](https://github.com/xmake-io/xmake/pull/7083): 添加对 CUDA 11~13 的支持\n* [#7071](https://github.com/xmake-io/xmake/pull/7071): 添加 Qt 打包支持\n* [#7064](https://github.com/xmake-io/xmake/pull/7064): 添加 AppImage xpack 格式用于 Linux 应用程序打包\n* [#7062](https://github.com/xmake-io/xmake/pull/7062): 添加 dmg xpack 格式用于 macOS 应用程序打包\n\n### 改进\n\n* [#7149](https://github.com/xmake-io/xmake/pull/7149): 改进 binutils 优化 rpath 解析\n* [#7148](https://github.com/xmake-io/xmake/pull/7148): 更新 Zig 示例\n* [#7145](https://github.com/xmake-io/xmake/pull/7145): 改进 Clang/LLVM 运行时支持\n* [#7136](https://github.com/xmake-io/xmake/pull/7136): 改进 clang-cl 依赖文件生成\n* [#7135](https://github.com/xmake-io/xmake/pull/7135): 改进 `xrepo env` 以添加会话 ID\n* [#7155](https://github.com/xmake-io/xmake/pull/7155): 重构 Windows 上 clang-cl 的 ASan 支持（改进运行库链接、链接器标志、完善 PATH/CMAKE_LINKER_TYPE 配置、精简工具链）\n* [#7109](https://github.com/xmake-io/xmake/pull/7109): 改进 binutils 以从二进制文件读取符号\n* [#7102](https://github.com/xmake-io/xmake/pull/7102): 改进 bin2c 规则\n* [#7098](https://github.com/xmake-io/xmake/pull/7098): 重构并改进 Golang 支持\n* [#7095](https://github.com/xmake-io/xmake/pull/7095): 将 target/package/toolchain:memcache 标记为公开\n* [#7093](https://github.com/xmake-io/xmake/pull/7093): 改进镜像仓库 URL\n* [#7088](https://github.com/xmake-io/xmake/pull/7088): 改进 C++/ObjC 规则\n* [#7087](https://github.com/xmake-io/xmake/pull/7087): 为策略 `package.download.http_headers` 添加类型约束\n* [#7069](https://github.com/xmake-io/xmake/pull/7069): 为 LLVM 工具链保存 Qt 规则\n* [#7061](https://github.com/xmake-io/xmake/pull/7061): 更新 CI 配置\n* [#7039](https://github.com/xmake-io/xmake/pull/7039): 更新 macOS CI\n\n### Bugs 修复\n\n* [#7132](https://github.com/xmake-io/xmake/pull/7132): 修复带有 ASan 的 clang-cl 工具链\n* [#7125](https://github.com/xmake-io/xmake/pull/7125): 修复 cosmocc CI\n* [#7124](https://github.com/xmake-io/xmake/pull/7124): 修复 Clang 工具链的默认 MSVC 运行时\n* [#7112](https://github.com/xmake-io/xmake/pull/7112): 修复 Windows 上的目录切换\n* [#7104](https://github.com/xmake-io/xmake/pull/7104): 修复项目生成器的准备工作\n* [#7092](https://github.com/xmake-io/xmake/pull/7092): 修复 Solaris 构建\n* [#7086](https://github.com/xmake-io/xmake/pull/7086): 修复 Qt QML 规则中的 targetdir\n* [#7085](https://github.com/xmake-io/xmake/pull/7085): 修复 Clang 工具链的 CMake 标志\n* [#7084](https://github.com/xmake-io/xmake/pull/7084): 修复 pacman find_package\n* [#7082](https://github.com/xmake-io/xmake/pull/7082): 修复 Clang CUDA 标志检查\n* [#7081](https://github.com/xmake-io/xmake/pull/7081): 修复 `get_headerunit_key`\n* [#7074](https://github.com/xmake-io/xmake/pull/7074): 修复 libc++ 找不到 std 模块\n* [#7067](https://github.com/xmake-io/xmake/pull/7067): 修复交叉编译工具链的 get_stdmodules\n\n## v3.0.5\n\n### 新特性\n\n* [#7055](https://github.com/xmake-io/xmake/pull/7055): 添加 Solaris 平台支持 (i386, x86_64)\n* [#7054](https://github.com/xmake-io/xmake/pull/7054): 添加更多 BSD 系统支持 (NetBSD, OpenBSD, DragonflyBSD)\n* [#6929](https://github.com/xmake-io/xmake/pull/6929): 添加 GCC 15 工具链支持\n* [#6967](https://github.com/xmake-io/xmake/pull/6967): 为 C++ 和 Objective-C 添加 Swift 互操作支持\n* [#6964](https://github.com/xmake-io/xmake/pull/6964): 支持通过 cuda_sdkver 参数指定 CUDA SDK 版本\n* [#6963](https://github.com/xmake-io/xmake/pull/6963): 为交叉编译添加 libtool 补丁支持\n* [#6974](https://github.com/xmake-io/xmake/pull/6974): 支持多行刷新进度输出显示\n* [#7024](https://github.com/xmake-io/xmake/pull/7024): 为 `xmake show -t target` 命令添加 JSON 格式输出\n* [#7025](https://github.com/xmake-io/xmake/pull/7025): 添加 XML 模块，支持解析和编码功能\n* [#6989](https://github.com/xmake-io/xmake/pull/6989): 为 os API 添加异步操作支持\n\n### 改进\n\n* [#6924](https://github.com/xmake-io/xmake/pull/6924): 改进工具链配置，支持 add_toolchains(\"name[configs]\") 语法\n* [#6935](https://github.com/xmake-io/xmake/pull/6935): 重构工具链：将 gcc/clang 的注册与定义分离\n* [#6942](https://github.com/xmake-io/xmake/pull/6942): 改进文件读取性能\n* [#6946](https://github.com/xmake-io/xmake/pull/6946): 为 Clang 工具链添加 LLD 链接器支持\n* [#6970](https://github.com/xmake-io/xmake/pull/6970): 改进 TTY 处理和输出显示\n* [#6977](https://github.com/xmake-io/xmake/pull/6977): 重构 Xcode 工具链，并将其集成到针对 Apple 设备的 LLVM 工具链中\n* [#6987](https://github.com/xmake-io/xmake/pull/6987): 添加 Ghostty 终端检测支持\n* [#7003](https://github.com/xmake-io/xmake/pull/7003): 限制在包配置中获取构建环境变量\n* [#7008](https://github.com/xmake-io/xmake/pull/7008): 统一代码格式风格\n* [#7004](https://github.com/xmake-io/xmake/pull/7004): 使用 -r 标志时跳过重建包和 std 模块\n* [#7019](https://github.com/xmake-io/xmake/pull/7019): 改进 xmake.sh/configure 脚本并添加 Ninja 生成器支持\n* [#7023](https://github.com/xmake-io/xmake/pull/7023): 更新 Qt TypeScript 规则\n* [#7022](https://github.com/xmake-io/xmake/pull/7022): 使 zig-cc 工具链继承自 clang\n* [#7027](https://github.com/xmake-io/xmake/pull/7027): 改进 graph 模块性能\n* [#7031](https://github.com/xmake-io/xmake/pull/7031): 改进 require 解析功能\n* [#7032](https://github.com/xmake-io/xmake/pull/7032): 改进符号提取功能\n* [#6952](https://github.com/xmake-io/xmake/pull/6952): 为测试添加实时输出支持\n* [#6998](https://github.com/xmake-io/xmake/pull/6998): 更新 tbox 库以支持 process/argv\n* [#7037](https://github.com/xmake-io/xmake/pull/7037): 改进 xmake format 功能\n* [#7038](https://github.com/xmake-io/xmake/pull/7038): 改进 clang-tidy 输出处理\n\n### Bugs 修复\n\n* [#6926](https://github.com/xmake-io/xmake/pull/6926): 修复在 Windows 上加载包含 Unicode 字符的主脚本路径问题\n* [#6931](https://github.com/xmake-io/xmake/pull/6931): 修复 C++ 模块：当工具链的 clang-scan-deps 未安装时，自动回退到系统级的 clang-scan-deps\n* [#6937](https://github.com/xmake-io/xmake/pull/6937): 修复目标任务处理问题\n* [#6954](https://github.com/xmake-io/xmake/pull/6954): 修复 vsxmake/vs 生成器的模块支持问题\n* [#6955](https://github.com/xmake-io/xmake/pull/6955): 修复包中构建号的排序问题\n* [#6956](https://github.com/xmake-io/xmake/pull/6956): 修复使用不支持 depfile 的 zigcc 链接器导致的构建失败\n* [#6959](https://github.com/xmake-io/xmake/pull/6959): 修复在动态链接场景下使用 zigcc 与 autotools 的问题\n* [#6983](https://github.com/xmake-io/xmake/pull/6983): 修复模块：为模块重用场景去除 sanitizer 标志\n* [#6984](https://github.com/xmake-io/xmake/pull/6984): 修复已安装的 CMake 导入文件中的 libdir 路径问题\n* [#6993](https://github.com/xmake-io/xmake/pull/6993): 修复 xmake 测试模块相关问题\n* [#6992](https://github.com/xmake-io/xmake/pull/6992): 修复模块：为 clang get_cpp_library_name 添加所有支持的平台\n* [#6999](https://github.com/xmake-io/xmake/pull/6999): 修复 rootdir 处理问题\n* [#7002](https://github.com/xmake-io/xmake/pull/7002): 修复 asn1c：将生成的输出文件作为系统头文件包含\n* [#6996](https://github.com/xmake-io/xmake/pull/6996): 修复 Nimble find_package 以使用最新的包列表格式\n* [#7012](https://github.com/xmake-io/xmake/pull/7012): 修复稀疏检出处理问题\n* [#7013](https://github.com/xmake-io/xmake/pull/7013): 修复打包时移除依赖项的问题\n* [#7017](https://github.com/xmake-io/xmake/pull/7017): 修复 lock_packages 的拼写错误\n* [#7016](https://github.com/xmake-io/xmake/pull/7016): 修复 vsxmake 中的项目默认配置问题\n* [#7018](https://github.com/xmake-io/xmake/pull/7018): 修复构建顺序：仅在禁用依赖链接继承时才禁用构建顺序\n* [#7035](https://github.com/xmake-io/xmake/pull/7035): 通过更新 tbox 修复进程重定向问题\n\n## v3.0.4\n\n### 新特性\n\n* [#6864](https://github.com/xmake-io/xmake/pull/6864): 为 `format` 任务添加默认文件过滤器\n* [#6843](https://github.com/xmake-io/xmake/pull/6843): 改进 clang-tidy 支持\n* [#6861](https://github.com/xmake-io/xmake/pull/6861): 重写 Nix 包管理器支持\n* [#6850](https://github.com/xmake-io/xmake/pull/6850): 添加包 API 检查\n* [#6874](https://github.com/xmake-io/xmake/pull/6874): 为项目包添加 scriptdir\n* [#6876](https://github.com/xmake-io/xmake/pull/6876): 添加 versionfiles 检查器\n* [#6884](https://github.com/xmake-io/xmake/pull/6884): 在 msys2 上添加 msystem 支持\n* [#6891](https://github.com/xmake-io/xmake/pull/6891): 添加协程信号量\n* [#6894](https://github.com/xmake-io/xmake/pull/6894): 为 clang 工具链添加 llvm-nm\n* [#6918](https://github.com/xmake-io/xmake/pull/6918): 为 os.cp 添加 copy_if_different 支持\n\n### 改进\n\n* [#6846](https://github.com/xmake-io/xmake/pull/6846): 改进 cmake 默认标志\n* [#6849](https://github.com/xmake-io/xmake/pull/6849): 改进 jobgraph\n* [#6859](https://github.com/xmake-io/xmake/pull/6859): 改进检查目标标志\n* [#6858](https://github.com/xmake-io/xmake/pull/6858): 修改配置标志顺序\n* [#6854](https://github.com/xmake-io/xmake/pull/6854): 改进 os.curdir/os.cd\n* [#6866](https://github.com/xmake-io/xmake/pull/6866): 改进 os.getenvs\n* [#6867](https://github.com/xmake-io/xmake/pull/6867): 确保通用选项总是被插入\n* [#6870](https://github.com/xmake-io/xmake/pull/6870): chore(vcpkg): 提升 vcpkg 的默认 baseline\n* [#6880](https://github.com/xmake-io/xmake/pull/6880): 更新 cmake_importfiles.lua\n* [#6872](https://github.com/xmake-io/xmake/pull/6872): 改进哈希\n* [#6886](https://github.com/xmake-io/xmake/pull/6886): 减少 jobgraph 中的任务数\n* [#6890](https://github.com/xmake-io/xmake/pull/6890): 更新 cmake_importfiles.lua\n* [#6892](https://github.com/xmake-io/xmake/pull/6892): 改进 runjobs 以减少协程调度所花费的时间\n* [#6896](https://github.com/xmake-io/xmake/pull/6896): 添加哈希测试\n* [#6904](https://github.com/xmake-io/xmake/pull/6904): 改进 clang 以支持 msvc 环境\n* [#6915](https://github.com/xmake-io/xmake/pull/6915): 改进为二进制文件导出 def 规则\n\n### Bugs 修复\n\n* [#6844](https://github.com/xmake-io/xmake/pull/6844): 修复自动生成的 .pc 文件中的版本\n* [#6851](https://github.com/xmake-io/xmake/pull/6851): 修复查找 clang-scan-deps\n* [#6857](https://github.com/xmake-io/xmake/pull/6857): 修复在交叉编译中使用 cmake 的 rc 编译器\n* [#6809](https://github.com/xmake-io/xmake/pull/6809): fix(C++ modules) 修复 stdmodule 优先级\n* [#6882](https://github.com/xmake-io/xmake/pull/6882): 修复：以确定性顺序写入包清单 manifest.pathenvs\n* [#6888](https://github.com/xmake-io/xmake/pull/6888): 修复 clang 工具链包\n* [#6889](https://github.com/xmake-io/xmake/pull/6889): 修复 os.getenvs 兼容性\n* [#6900](https://github.com/xmake-io/xmake/pull/6900): package.tools.xmake: 修复策略未被传递的问题\n* [#6901](https://github.com/xmake-io/xmake/pull/6901): package download: 如果禁用，则不获取子模块\n* [#6907](https://github.com/xmake-io/xmake/pull/6907): package download: 如果禁用，则不获取子模块 (分支版本)\n\n## v3.0.3\n\n### 新特性\n\n* [#6778](https://github.com/xmake-io/xmake/pull/6778): 添加 build.linker.output\n* [#6779](https://github.com/xmake-io/xmake/pull/6779): 添加 #embed 和 embedirs 支持\n* [#6787](https://github.com/xmake-io/xmake/pull/6787): 支持 vs2026\n* [#6785](https://github.com/xmake-io/xmake/pull/6785): 为 wdk 规则支持 clang 和 llvm\n* [#6791](https://github.com/xmake-io/xmake/pull/6791): 添加 Nix 包管理器支持\n* [#6800](https://github.com/xmake-io/xmake/pull/6800): 为 xrepo env 支持 nushell\n* [#6796](https://github.com/xmake-io/xmake/pull/6796): 启用不完整 wdk 的支持\n\n### 改进\n\n* [#6765](https://github.com/xmake-io/xmake/pull/6765): 改进 bin2c 使用原生线程\n* [#6771](https://github.com/xmake-io/xmake/pull/6771): 修复 find gcc/gxx 缓存\n* [#6777](https://github.com/xmake-io/xmake/pull/6777): 修复 cmake 的可执行文件路径\n* [#6783](https://github.com/xmake-io/xmake/pull/6783): 修复 build.c++.modules.std 策略\n* [#6744](https://github.com/xmake-io/xmake/pull/6744): 当提供 --verbose 或 --diagnosis 时使用文件来存储 requires 标志\n* [#6780](https://github.com/xmake-io/xmake/pull/6780): 添加基准测试并优化配置/构建目标\n* [#6784](https://github.com/xmake-io/xmake/pull/6784): 继续优化构建目标速度\n* [#6793](https://github.com/xmake-io/xmake/pull/6793): 使用 musl 避免 glibc 版本问题\n* [#6788](https://github.com/xmake-io/xmake/pull/6788): 改进 clang 增量构建\n* [#6811](https://github.com/xmake-io/xmake/pull/6811): 改进 clang-tidy\n* [#6810](https://github.com/xmake-io/xmake/pull/6810): 改进 cmake 的默认标志\n* [#6801](https://github.com/xmake-io/xmake/pull/6801): 更改 gcc 和 clang 的编译器优先级\n* [#6819](https://github.com/xmake-io/xmake/pull/6819): 改进 show target\n* [#6817](https://github.com/xmake-io/xmake/pull/6817): 改进构建速度\n* [#6822](https://github.com/xmake-io/xmake/pull/6822): 优先使用环境变量而不是仓库缓存\n* [#6824](https://github.com/xmake-io/xmake/pull/6824): 改进 has_flags\n* [#6832](https://github.com/xmake-io/xmake/pull/6832): 优化代码签名\n\n### Bugs 修复\n\n* [#6808](https://github.com/xmake-io/xmake/pull/6808): 修复 xrepo env\n* [#6821](https://github.com/xmake-io/xmake/pull/6821): 清理未定义的 vsvers\n* [#6818](https://github.com/xmake-io/xmake/pull/6818): 修复 nix-shell 环境中的 Nix 包检测\n* [#6798](https://github.com/xmake-io/xmake/pull/6798): 为 msvc 的 strippeable_flags 添加 external\n\n## v3.0.2\n\n### 新特性\n\n* [#6755](https://github.com/xmake-io/xmake/issues/6755): 添加原生线程支持\n* [#6641](https://github.com/xmake-io/xmake/pull/6641): 为 `target/config` 添加 `pkgenvs`\n* [#6644](https://github.com/xmake-io/xmake/pull/6644): 支持使用 clang 编译 .def 文件\n* [#6695](https://github.com/xmake-io/xmake/pull/6695): 为 inf2cat 添加 `/uselocaltime` 参数\n* [#6709](https://github.com/xmake-io/xmake/pull/6709): 支持 wasm64 架构\n* [#6737](https://github.com/xmake-io/xmake/pull/6737): 为 cython 规则添加 python 存根文件扩展\n\n### 改进\n\n* [#6651](https://github.com/xmake-io/xmake/pull/6651): 改进依赖文件\n* [#6656](https://github.com/xmake-io/xmake/pull/6656): 使构建工具支持传入 `opt.targets`\n* [#6688](https://github.com/xmake-io/xmake/pull/6688): 改进安装目标\n* [#6692](https://github.com/xmake-io/xmake/pull/6692): 改进 protobuf 测试\n* [#6714](https://github.com/xmake-io/xmake/pull/6714): 改进 C++ 模块测试\n* [#6719](https://github.com/xmake-io/xmake/pull/6719): 改进 comax 配置\n* [#6725](https://github.com/xmake-io/xmake/pull/6725): 改进 `target:extrafiles`\n\n### Bugs 修复\n\n* [#6648](https://github.com/xmake-io/xmake/pull/6648): 修复(qt.qmltyperegistrar): 收集 metatypes 信息\n* [#6661](https://github.com/xmake-io/xmake/pull/6661): 通过设置 \"--tries=1\" 修复 `_ping_via_wget` 长时间阻塞的问题\n* [#6665](https://github.com/xmake-io/xmake/pull/6665): 修复 cmake/mingw\n* [#6674](https://github.com/xmake-io/xmake/pull/6674): 尝试修复包中的 linkgroups\n* [#6686](https://github.com/xmake-io/xmake/pull/6686): 修复编译器缓存\n* [#6698](https://github.com/xmake-io/xmake/pull/6698): 修复(C++ 模块) 处理空模块\n* [#6699](https://github.com/xmake-io/xmake/pull/6699): 修复(C++ 模块) 修复删除模块文件时 xmake 不更新模块映射器的问题\n* [#6706](https://github.com/xmake-io/xmake/pull/6706): 修复 CUDA 13 的 `find_cudadevices`\n* [#6707](https://github.com/xmake-io/xmake/pull/6707): 修复(C++ 模块) 修复 sourcebatch 缓存\n* [#6712](https://github.com/xmake-io/xmake/pull/6712): 修复(C++ 模块) 修复禁用的目标被配置用于模块编译的问题\n* [#6713](https://github.com/xmake-io/xmake/pull/6713): 修复(C++ 模块) 修复非 .cpp 文件从 `c++.build` sourcebatch 中被窃取的问题\n* [#6715](https://github.com/xmake-io/xmake/pull/6715): 修复(C++ 模块) 修复公共剔除模块错误地发出警告的问题\n* [#6718](https://github.com/xmake-io/xmake/pull/6718): 忽略 pch 标志\n* [#6732](https://github.com/xmake-io/xmake/pull/6732): 修复: android ndk rust link-args\n* [#6735](https://github.com/xmake-io/xmake/pull/6735): 修复(qt.qmltyperegistrar): 扩展依赖项以进行重建\n* [#6738](https://github.com/xmake-io/xmake/pull/6738): 修复 protobuf 的目标依赖\n* [#6741](https://github.com/xmake-io/xmake/pull/6741): 修复 vsxmake 选项\n* [#6747](https://github.com/xmake-io/xmake/pull/6747): `meminfo.c`: < 10.7 版本上没有 `vmstat.compressor_page_count`\n\n## v3.0.1\n\n### 新特性\n\n* [#4810](https://github.com/xmake-io/xmake/issues/4810): 添加新的原生 Xcode 工程生成插件\n\n### Bugs 修复\n\n* [#6592](https://github.com/xmake-io/xmake/pull/6592): 修复 object 目标的链接问题\n* [#6586](https://github.com/xmake-io/xmake/issues/6586): 修复 build.fence 策略\n* [#6600](https://github.com/xmake-io/xmake/issues/6600): 修复 compile_commands 生成器\n* [#6621](https://github.com/xmake-io/xmake/issues/6621): 修复 android ndk r17c 构建失败问题\n* [#6635](https://github.com/xmake-io/xmake/discussions/6635): 修复 batchcmds 导致的 qt/moc 增量构建问题\n\n## v3.0.0\n\n### 新特性\n\n* [#5926](https://github.com/xmake-io/xmake/issues/5926): 添加 MIDL 支持\n* [#6414](https://github.com/xmake-io/xmake/pull/6414): 添加 platform.windows.subsystem 规则\n* [#5527](https://github.com/xmake-io/xmake/issues/5527): 切换到 3.0 行为策略\n\n### 改进\n\n* [#6202](https://github.com/xmake-io/xmake/issues/6202): 改进 rule API 和构建顺序支持，提供统一 jobgraph 调度\n* [#5624](https://github.com/xmake-io/xmake/discussions/5624): `xmake run` 运行默认自动构建\n* [#5526](https://github.com/xmake-io/xmake/discussions/5526): msvc 默认切换到 MD/MDd 运行时\n* [#5545](https://github.com/xmake-io/xmake/discussions/5545): 构建 cmake 包，默认使用 Ninja 生成器\n* [#6355](https://github.com/xmake-io/xmake/pull/6355): 支持自定义 implib 路径和访问\n* [#6373](https://github.com/xmake-io/xmake/pull/6373): 改进 c++ modules 支持\n* [#6376](https://github.com/xmake-io/xmake/issues/6476): 改进 vsxmake 生成器，支持命名空间\n* [#6209](https://github.com/xmake-io/xmake/pull/6209): 添加 jobgraph 支持\n* [#6361](https://github.com/xmake-io/xmake/pull/6361): 重命名 buildir 到 builddir\n\n## v2.9.9\n\n### 新特性\n\n* [#6137](https://github.com/xmake-io/xmake/issues/6137): IDE 整合\n* [#6138](https://github.com/xmake-io/xmake/issues/6138): 使用 libxmake/xmake APIs 去构建二进制\n* [#6154](https://github.com/xmake-io/xmake/issues/6154): 添加 kotlin native 构建支持和包依赖集成支持\n* [#6279](https://github.com/xmake-io/xmake/pull/6279): 添加 msvc midl 支持\n\n### 改进\n\n* [#6182](https://github.com/xmake-io/xmake/pull/6182): 改进 clang/clang-cl 支持 msstl 模块\n* [#6281](https://github.com/xmake-io/xmake/pull/6281): 支持 Verilator 动态库\n* [#6270](https://github.com/xmake-io/xmake/pull/6270): 改进 conan 生成器\n* [#6243](https://github.com/xmake-io/xmake/pull/6243): 改进 llvm 工具链对交叉编译的支持\n* 三方包安装支持 CMake 4.0\n\n### Bugs 修复\n\n* [#6292](https://github.com/xmake-io/xmake/issues/6292): 修复 namespace 问题\n\n## v2.9.8\n\n### 新特性\n\n* [#5994](https://github.com/xmake-io/xmake/issues/5994): 分析进程执行性能\n* [#5995](https://github.com/xmake-io/xmake/pull/5995): 为 vs generator 添加 profile 支持\n* [#5949](https://github.com/xmake-io/xmake/pull/5949): 添加 nodejs.module 规则\n* [#3380](https://github.com/xmake-io/xmake/issues/3380): 添加命名空间支持\n* [#5945](https://github.com/xmake-io/xmake/issues/5945): 检测 pkgconfig/cmake 导入文件\n* [#6054](https://github.com/xmake-io/xmake/issues/6054): 为 linux 添加 xmake bundle 包\n* [#6071](https://github.com/xmake-io/xmake/issues/6071): 改进 git 包下载，支持仅仅 clone 指定子目录\n* [#5163](https://github.com/xmake-io/xmake/issues/5163): 支持 TI-CGT C2000/C6000 编译器\n* [#5344](https://github.com/xmake-io/xmake/issues/5344): 支持 IAR ARM C/C++ 编译器\n* [#5554](https://github.com/xmake-io/xmake/issues/5554): 添加自定义未知工具链支持\n\n### 改进\n\n* [#6056](https://github.com/xmake-io/xmake/pull/6056): 添加 CI 去构建发布 windows arm64 版本。\n* [#6097](https://github.com/xmake-io/xmake/pull/6097): 添加 qt_host 支持交叉编译 Qt 项目\n* [#6120](https://github.com/xmake-io/xmake/issues/6120): 改进 configfiles 添加自定义预处理支持\n* [#6088](https://github.com/xmake-io/xmake/issues/6088): 改进 configfiles 去生成导出宏\n\n### Bugs 修复\n\n* [#272](https://github.com/tboox/tbox/issues/272): 修复 msvc + /O1 时候，错误的编译器优化导致 xmake 加载卡住\n* [#6089](https://github.com/tboox/tbox/issues/6089): 修复 depend.is_changed\n\n## v2.9.7\n\n### 新特性\n\n* [#5813](https://github.com/xmake-io/xmake/pull/5813): 为 rule 添加 `before_config` 和 `after_config`\n* [#5848](https://github.com/xmake-io/xmake/issues/5848): 支持自定义 MSVC 构建工具, PortableBuildTools 和 msvc-wine\n* [#5880](https://github.com/xmake-io/xmake/pull/5880): 支持使用 msvc 包去构建工程\n* [#5884](https://github.com/xmake-io/xmake/issues/5884): 为包添加自定义安装提示\n* [#5894](https://github.com/xmake-io/xmake/issues/5894): 添加 package.merge_staticlibs 策略去合并包安装的静态库\n* [#5948](https://github.com/xmake-io/xmake/pull/5948): 添加 `lua.native-object` 规则\n* [#5911](https://github.com/xmake-io/xmake/issues/5911): 支持 nuget 包集成\n\n### 改进\n\n* [#5817](https://github.com/xmake-io/xmake/pull/5817): 改进安装包的默认 pic 配置\n* [#5869](https://github.com/xmake-io/xmake/pull/5869): 为 gcc 添加 libstdc++ 标准库模块的支持\n* [#5923](https://github.com/xmake-io/xmake/pull/5923): 解决包依赖链中版本和配置冲突\n\n### Bugs 修复\n\n* [#5856](https://github.com/xmake-io/xmake/issues/5856): 修复 c++modules 在 clang 下的编译\n* [#5858](https://github.com/xmake-io/xmake/issues/5858): 修复 gcc 的头文件预编译问题\n\n## v2.9.6\n\n### 新特性\n\n* [#5527](https://github.com/xmake-io/xmake/issues/5527): 添加 `set_policy(\"compatibility.version\", \"3.0\")` 提前预览体验 3.0 特性\n* [#5649](https://github.com/xmake-io/xmake/pull/5649): 添加 `package.check_fcsnippets`\n\n### 改进\n\n* [#5631](https://github.com/xmake-io/xmake/pull/5631): 为 `add_linkgroups` 添加 `as_needed`\n* [#5702](https://github.com/xmake-io/xmake/issues/5702): 改进 hash 模块\n* [#5688](https://github.com/xmake-io/xmake/pull/5688): 改进 hashset\n* [#5711](https://github.com/xmake-io/xmake/issues/5711): 为 sdcc 支持解析 include 依赖\n* [#5727](https://github.com/xmake-io/xmake/issues/5727): 为 add_requires 改进 configs 配置\n* [#5762](https://github.com/xmake-io/xmake/pull/5762): 改进 bin2c 速度\n\n### Bugs 修复\n\n* [#5645](https://github.com/xmake-io/xmake/issues/5645): 修复 `xmake watch` 在 linux 无法监听递归文件问题\n* [#5686](https://github.com/xmake-io/xmake/pull/5686): 修复模块扫描\n\n## v2.9.5\n\n### 新特性\n\n* [#5462](https://github.com/xmake-io/xmake/pull/5462): 添加 `xmake l cli.bisect`\n* [#5488](https://github.com/xmake-io/xmake/pull/5488): 支持使用 cosmocc 去构建 xmake 自身二进制\n* [#5491](https://github.com/xmake-io/xmake/pull/5491): 支持提供内嵌 lua 文件的单个 xmake 二进制文件\n* [#5580](https://github.com/xmake-io/xmake/issues/5580): 添加 `@builtin/xrepo` 辅助模块，为 `xrepo env shell` 实现快速设置环境变量\n\n### 改进\n\n* [#5507](https://github.com/xmake-io/xmake/issues/5507): 改进 git clone 下载速度\n* [#5536](https://github.com/xmake-io/xmake/pull/5536): 在 swig 模式中添加 jar 生成支持\n* [#5573](https://github.com/xmake-io/xmake/issues/5573): 改进 vsxmake generator 性能\n* [#5601](https://github.com/xmake-io/xmake/issues/5601): 改进 utils.symbols.export_all 规则去过滤源文件路径\n\n### Bugs 修复\n\n* [#4750](https://github.com/xmake-io/xmake/issues/4750): 修复 compile_commands 生成器，支持 `xmake tests`\n* [#5465](https://github.com/xmake-io/xmake/pull/5465): 修复 package requires lock\n* [#4760](https://github.com/xmake-io/xmake/issues/4760): 修复 distcc 分布式编译问题\n\n## v2.9.4\n\n### 新特性\n\n* [#5278](https://github.com/xmake-io/xmake/issues/5278): 添加 `build.intermediate_directory` 策略去禁用中间目录生成\n* [#5313](https://github.com/xmake-io/xmake/issues/5313): 添加 windows arm/arm64ec 支持\n* [#5296](https://github.com/xmake-io/xmake/issues/5296): 添加 Intel LLVM Fortran 编译器支持\n* [#5384](https://github.com/xmake-io/xmake/issues/5384): 为包添加 `add_bindirs` 配置支持\n\n### 改进\n\n* [#5280](https://github.com/xmake-io/xmake/issues/5280): 添加缺失的 C++20 Modules 文件扩展\n* [#5251](https://github.com/xmake-io/xmake/issues/5251): 为 windows installer 更新内置的 7z/curl\n* [#5286](https://github.com/xmake-io/xmake/issues/5286): 改进 json 支持16进制解析\n* [#5302](https://github.com/xmake-io/xmake/pull/5302): 改进 Vala 支持\n* [#5335](https://github.com/xmake-io/xmake/pull/5335): 改进 `xmake install` 和 `xpack`，添加 `set_prefixdir` 接口\n* [#5387](https://github.com/xmake-io/xmake/pull/5387): 改进 `xmake test`\n* [#5376](https://github.com/xmake-io/xmake/pull/5376): 改进 C++ module 对象列表处理和 moduleonly 包支持\n\n### Bugs 修复\n\n* [#5288](https://github.com/xmake-io/xmake/issues/5288): 修复 `xmake test` 对 Unity Build 的支持\n* [#5270](https://github.com/xmake-io/xmake/issues/5270): 修复 gcc/clang 对 pch 的支持\n* [#5276](https://github.com/xmake-io/xmake/issues/5276): 修复查找 vc6 环境\n* [#5259](https://github.com/xmake-io/xmake/issues/5259): 修复命令补全失效问题\n\n## v2.9.3\n\n### 新特性\n\n* [#4637](https://github.com/xmake-io/xmake/issues/4637): 为 xpack 添加 mix 支持\n* [#5107](https://github.com/xmake-io/xmake/issues/5107): 为 xpack 添加 deb 支持\n* [#5148](https://github.com/xmake-io/xmake/issues/5148): 为包添加 on_source 配置域\n\n### 改进\n\n* [#5156](https://github.com/xmake-io/xmake/issues/5156): 改进安装 cargo 包\n\n### 问题修复\n\n* [#5176](https://github.com/xmake-io/xmake/pull/5176): 修复 VS toolset v144 支持\n\n## v2.9.2\n\n### 新特性\n\n* [#5005](https://github.com/xmake-io/xmake/pull/5005): 显示所有 API\n* [#5003](https://github.com/xmake-io/xmake/issues/5003): 添加 build.fence 策略\n* [#5060](https://github.com/xmake-io/xmake/issues/5060): 支持 Verilator 静态库目标构建\n* [#5074](https://github.com/xmake-io/xmake/pull/5074): 添加 `xrepo download` 命令去快速下载包源码\n* [#5086](https://github.com/xmake-io/xmake/issues/5986): 添加包检测支持\n* [#5103](https://github.com/xmake-io/xmake/pull/5103): 添加 qt ts 构建支持\n* [#5104](https://github.com/xmake-io/xmake/pull/5104): 改进 find_program，在 windows 上调用 where 改进查找\n\n### 改进\n\n* [#5077](https://github.com/xmake-io/xmake/issues/5077): 当构建 x86 目标时，使用 x64 的 msvc 编译工具\n* [#5109](https://github.com/xmake-io/xmake/issues/5109): 改进 add_rpathdirs 支持 runpath/rpath 切换\n* [#5132](https://github.com/xmake-io/xmake/pull/5132): 改进 ifort/icc/icx 在 windows 上的支持\n\n### Bugs 修复\n\n* [#5059](https://github.com/xmake-io/xmake/issues/5059): 修复加载大量 targets 时候卡住\n* [#5029](https://github.com/xmake-io/xmake/issues/5029): 修复在 termux 上崩溃问题\n\n## v2.9.1\n\n### 新特性\n\n* [#4874](https://github.com/xmake-io/xmake/pull/4874): 添加鸿蒙 SDK 支持\n* [#4889](https://github.com/xmake-io/xmake/issues/4889): 添加 signal 模块 去注册信号处理\n* [#4925](https://github.com/xmake-io/xmake/issues/4925): 添加 native 模块支持\n* [#4938](https://github.com/xmake-io/xmake/issues/4938): 增加对 cppfront/h2 的支持\n\n### 改进\n\n* 改进包管理，支持切换 clang-cl\n* [#4893](https://github.com/xmake-io/xmake/issues/4893): 改进 rc 头文件依赖检测\n* [#4928](https://github.com/xmake-io/xmake/issues/4928): 改进构建和链接速度，增量编译时候效果更加明显\n* [#4931](https://github.com/xmake-io/xmake/pull/4931): 更新 pdcurses\n* [#4973](https://github.com/xmake-io/xmake/issues/4973): 改进选择脚本的匹配模式\n\n### Bugs 修复\n\n* [#4882](https://github.com/xmake-io/xmake/issues/4882): 修复安装组依赖问题\n* [#4877](https://github.com/xmake-io/xmake/issues/4877): 修复 xpack 打包时，unit build 编译失败问题\n* [#4887](https://github.com/xmake-io/xmake/issues/4887): 修复 object 依赖链接\n\n## v2.8.9\n\n### 新特性\n\n* [#4843](https://github.com/xmake-io/xmake/issues/4843): 添加 check_bigendian 接口实现大小端探测\n\n### 改进\n\n* [#4798](https://github.com/xmake-io/xmake/issues/4798): 改进 wasi sdk 检测\n* [#4772](https://github.com/xmake-io/xmake/issues/4772): 改进 tools.cmake 去兼容支持 vs2022 preview (v144)\n* [#4813](https://github.com/xmake-io/xmake/issues/4813): 添加 gb2312 编码\n* [#4864](https://github.com/xmake-io/xmake/issues/4864): 改进抽取符号，支持 gdb 断点调试\n* [#4831](https://github.com/xmake-io/xmake/issues/4831): 改进 target:fileconfig() 支持 headerfiles\n* [#4846](https://github.com/xmake-io/xmake/issues/4846): 改进进度显示，解决顺序错乱问题\n\n### Bugs 修复\n\n* 修复 select_script 的脚本模式匹配\n* [#4763](https://github.com/xmake-io/xmake/issues/4763): 修复 {force = true}\n* [#4807](https://github.com/xmake-io/xmake/issues/4807): 修复 nimble::find_package\n* [#4857](https://github.com/xmake-io/xmake/issues/4857): 修复对 -P/-F 等基础选项的解析\n\n## v2.8.8\n\n### 改进\n\n* 添加 `package:check_sizeof()`\n\n### Bugs 修复\n\n* [#4774](https://github.com/xmake-io/xmake/issues/4774): 修复 Android NDK r26b 上的 strip 支持\n* [#4769](https://github.com/xmake-io/xmake/issues/4769): 修复交叉编译工具链问题\n* [#4776](https://github.com/xmake-io/xmake/issues/4776): 修复 soname\n* [#4638](https://github.com/xmake-io/xmake/issues/4638): 修复 vsxmake generator\n\n## v2.8.7\n\n### 新特性\n\n* [#4544](https://github.com/xmake-io/xmake/issues/4544): 改进 `xmake test`，支持等待进程超时\n* [#4606](https://github.com/xmake-io/xmake/pull/4606): 为 package 添加 `add_versionfiles` 接口\n* [#4709](https://github.com/xmake-io/xmake/issues/4709): 添加 cosmocc 工具链支持\n* [#4715](https://github.com/xmake-io/xmake/issues/4715): 在描述域添加 is_cross() 接口\n* [#4747](https://github.com/xmake-io/xmake/issues/4747): 添加 `build.always_update_configfiles` 策略\n\n### 改进\n\n* [#4575](https://github.com/xmake-io/xmake/issues/4575): 检测无效的域参数\n* 添加更多的 loong64 支持\n* 改进 dlang/dmd 对 frameworks 的支持\n* [#4571](https://github.com/xmake-io/xmake/issues/4571): 改进 `xmake test` 的输出支持\n* [#4609](https://github.com/xmake-io/xmake/issues/4609): 改进探测 vs 构建工具环境\n* [#4614](https://github.com/xmake-io/xmake/issues/4614): 改进支持 android ndk 26b\n* [#4473](https://github.com/xmake-io/xmake/issues/4473): 默认启用警告输出\n* [#4477](https://github.com/xmake-io/xmake/issues/4477): 改进 runtimes 去支持 libc++/libstdc++\n* [#4657](https://github.com/xmake-io/xmake/issues/4657): 改进脚本的模式匹配\n* [#4673](https://github.com/xmake-io/xmake/pull/4673): 重构模块支持\n* [#4746](https://github.com/xmake-io/xmake/pull/4746): 为 cmake generator 添加原生 c++ modules 支持\n\n### Bugs 修复\n\n* [#4596](https://github.com/xmake-io/xmake/issues/4596): 修复远程构建缓存\n* [#4689](https://github.com/xmake-io/xmake/issues/4689): 修复目标依赖继承\n\n## v2.8.6\n\n### 新特性\n\n* 添加 `network.mode` 策略\n* [#1433](https://github.com/xmake-io/xmake/issues/1433): 添加 `xmake pack` 命令去生成 NSIS/zip/tar.gz/rpm/srpm/runself 安装包\n* [#4435](https://github.com/xmake-io/xmake/issues/4435): 为 UnityBuild 的组模式增加 batchsize 支持\n* [#4485](https://github.com/xmake-io/xmake/pull/4485): 新增 package.install_locally 策略支持\n* 新增 NetBSD 支持\n\n### Changes\n\n* [#4484](https://github.com/xmake-io/xmake/pull/4484): 改进 swig 规则\n* 改进 Haiku 支持\n\n### Bugs 修复\n\n* [#4372](https://github.com/xmake-io/xmake/issues/4372): 修复 protobuf 规则\n* [#4439](https://github.com/xmake-io/xmake/issues/4439): 修复 asn1c 规则\n\n## v2.8.5\n\n### 新特性\n\n* [#1452](https://github.com/xmake-io/xmake/issues/1452): 支持链接顺序调整，链接组\n* [#1438](https://github.com/xmake-io/xmake/issues/1438): 支持代码 amalgamation\n* [#3381](https://github.com/xmake-io/xmake/issues/3381): 添加 `xmake test` 支持\n* [#4276](https://github.com/xmake-io/xmake/issues/4276): 支持自定义域 API\n* [#4286](https://github.com/xmake-io/xmake/pull/4286): 添加 Apple XROS 支持\n* [#4345](https://github.com/xmake-io/xmake/issues/4345): 支持检测类型大小 sizeof\n* [#4369](https://github.com/xmake-io/xmake/pull/4369): 添加 windows.manifest.uac 策略\n\n### 改进\n\n* [#4284](https://github.com/xmake-io/xmake/issues/4284): 改进内置 includes 模块\n\n### Bugs 修复\n\n* [#4256](https://github.com/xmake-io/xmake/issues/4256): 为 vsxmake 生成器修复 c++ modules intellisense\n\n## v2.8.3\n\n### 新特性\n\n* [#4122](https://github.com/xmake-io/xmake/issues/4122): 支持 Lua 调试 (EmmyLua)\n* [#4132](https://github.com/xmake-io/xmake/pull/4132): 支持 cppfront\n* [#4147](https://github.com/xmake-io/xmake/issues/4147): 添加 hlsl2spv 规则\n* 添加 lib.lua.package 模块\n* [#4226](https://github.com/xmake-io/xmake/issues/4226): 新增 asan 相关策略和对包的支持\n* 添加 `run.autobuild` 策略开启运行前自动构建\n* 添加全局策略 `xmake g --policies=`\n\n### 改进\n\n* [#4119](https://github.com/xmake-io/xmake/issues/4119): 改进支持 emcc 工具链和 emscripten 包的整合\n* [#4154](https://github.com/xmake-io/xmake/issues/4154): 添加 `xmake -r --shallow target` 去改进重建目标，避免重建所有依赖目标\n* 添加全局 ccache 存储目录\n* [#4137](https://github.com/xmake-io/xmake/issues/4137): 改进 Qt，支持 Qt6 for Wasm\n* [#4173](https://github.com/xmake-io/xmake/issues/4173): 添加 recheck 参数到 on_config\n* [#4200](https://github.com/xmake-io/xmake/pull/4200): 改进远程构建，支持调试本地 xmake 源码\n* [#4209](https://github.com/xmake-io/xmake/issues/4209): 添加 extra 和 pedantic 警告\n\n### Bugs 修复\n\n* [#4110](https://github.com/xmake-io/xmake/issues/4110): 修复 extrafiles\n* [#4115](https://github.com/xmake-io/xmake/issues/4115): 修复 compile_commands 生成器\n* [#4199](https://github.com/xmake-io/xmake/pull/4199): 修复 compile_commands 生成器对 c++ modules 的支持\n* 修复 os.mv 在 windows 上跨驱动盘失败问题\n* [#4214](https://github.com/xmake-io/xmake/issues/4214): 修复 rust workspace 构建问题\n\n## v2.8.2\n\n### 新特性\n\n* [#4002](https://github.com/xmake-io/xmake/issues/4002): 增加 soname 支持\n* [#1613](https://github.com/xmake-io/xmake/issues/1613): 为 add_vectorexts 增加 avx512 和 sse4.2 支持\n* [#2471](https://github.com/xmake-io/xmake/issues/2471): 添加 set_encodings API 去设置源文件和目标文件的编码\n* [#4071](https://github.com/xmake-io/xmake/pull/4071): 支持 sdcc 的 stm8 汇编器\n* [#4101](https://github.com/xmake-io/xmake/issues/4101): 为 c/c++ 添加 force includes\n* [#2384](https://github.com/xmake-io/xmake/issues/2384): 为 vs/vsxmake 生成器添加 add_extrafiles 接口\n\n### 改进\n\n* [#3960](https://github.com/xmake-io/xmake/issues/3960): 改进 msys2/crt64 支持\n* [#4032](https://github.com/xmake-io/xmake/pull/4032): 移除一些非常老的废弃接口\n* 改进 tools.msbuild 升级 vcproj 文件\n* 支持 add_requires(\"xmake::xxx\") 包\n* [#4049](https://github.com/xmake-io/xmake/issues/4049): 改进 Rust 支持交叉编译\n* 改进 clang 下 c++ modules 支持\n\n### Bugs 修复\n\n* 修复 macOS/Linux 上子子进程无法快速退出问题\n\n## v2.8.1\n\n### 新特性\n\n* [#3821](https://github.com/xmake-io/xmake/pull/3821): windows 安装器添加长路径支持选项\n* [#3828](https://github.com/xmake-io/xmake/pull/3828): 添加 zypper 包管理器支持\n* [#3871](https://github.com/xmake-io/xmake/issues/3871): 改进 tools.msbuild 支持对 vsproj 进行自动升级\n* [#3148](https://github.com/xmake-io/xmake/issues/3148): 改进 protobuf 支持 grpc\n* [#3889](https://github.com/xmake-io/xmake/issues/3889): add_links 支持库路径添加\n* [#3912](https://github.com/orgs/xmake-io/issues/3912): 添加 set_pmxxheader 去支持 objc 预编译头\n* add_links 支持库文件路径\n\n### 改进\n\n* [#3752](https://github.com/xmake-io/xmake/issues/3752): 改进 windows 上 os.getenvs 的获取\n* [#3371](https://github.com/xmake-io/xmake/issues/3371): 改进 tools.cmake 支持使用 ninja 去构建 wasm 包\n* [#3777](https://github.com/xmake-io/xmake/issues/3777): 改进从 pkg-config 中查找包\n* [#3815](https://github.com/xmake-io/xmake/pull/3815): 改进 tools.xmake 支持为 windows 平台传递工具链\n* [#3857](https://github.com/xmake-io/xmake/issues/3857): 改进生成 compile_commands.json\n* [#3892](https://github.com/xmake-io/xmake/issues/3892): 改进包搜索，支持从描述中找包\n* [#3916](https://github.com/xmake-io/xmake/issues/3916): 改进构建 swift 程序，支持模块间符号调用\n* 更新 lua 运行时到 5.4.6\n\n### Bugs 修复\n\n* [#3755](https://github.com/xmake-io/xmake/pull/3755): 修复 find_tool 从 xmake/packages 中查找程序\n* [#3787](https://github.com/xmake-io/xmake/issues/3787): 修复从 conan 2.x 中使用包\n* [#3839](https://github.com/orgs/xmake-io/discussions/3839): 修复 conan 2.x 包的 vs_runtime 设置\n\n## v2.7.9\n\n### 新特性\n\n* [#3613](https://github.com/xmake-io/xmake/issues/3613): 添加 `wasm.preloadfiles` 扩展配置\n* [#3703](https://github.com/xmake-io/xmake/pull/3703): 支持 conan >=2.0.5\n\n### 改进\n\n* [#3669](https://github.com/xmake-io/xmake/issues/3669): 改进 cmake 生成器支持特定工具的 cxflags\n* [#3679](https://github.com/xmake-io/xmake/issues/3679): 改进 `xrepo clean`\n* [#3662](https://github.com/xmake-io/xmake/issues/3662): 改进 cmake/make 生成器去更好的支持 lex/yacc 工程\n* [#3697](https://github.com/xmake-io/xmake/issues/3662): 改进 trybuild/cmake\n* [#3730](https://github.com/xmake-io/xmake/issues/3730): 改进 c++modules 包安装，解决不同目录同名文件分发冲突问题\n\n### Bugs 修复\n\n* [#3596](https://github.com/xmake-io/xmake/issues/3596): 修复 check_cxxfuncs 和 check_cxxsnippets\n* [#3603](https://github.com/xmake-io/xmake/issues/3603): 修复 xmake update 的无效 url\n* [#3614](https://github.com/xmake-io/xmake/issues/3614): 修复 xmake run 对 Qt 环境的加载\n* [#3628](https://github.com/xmake-io/xmake/issues/3628): 修复 msys2/mingw 下 os.exec 总是优先查找错误的可执行程序\n* 修复 msys/mingw 下环境变量设置问题\n\n## v2.7.8\n\n### 新特性\n\n* [#3518](https://github.com/xmake-io/xmake/issues/3518): 分析编译和链接性能\n* [#3522](https://github.com/xmake-io/xmake/issues/3522): 为 target 添加 has_cflags, has_xxx 等辅助接口\n* [#3537](https://github.com/xmake-io/xmake/issues/3537): 为 clang.tidy 检测器添加 `--fix` 自动修复\n\n### 改进\n\n* [#3433](https://github.com/xmake-io/xmake/issues/3433): 改进 QT 在 msys2/mingw64 和 wasm 上的构建支持\n* [#3419](https://github.com/xmake-io/xmake/issues/3419): 支持 fish shell 环境\n* [#3455](https://github.com/xmake-io/xmake/issues/3455): Dlang 增量编译支持\n* [#3498](https://github.com/xmake-io/xmake/issues/3498): 改进绑定包虚拟环境\n* [#3504](https://github.com/xmake-io/xmake/pull/3504): 添加 swig java 支持\n* [#3508](https://github.com/xmake-io/xmake/issues/3508): 改进 trybuild/cmake 去支持工具链切换\n* 为 msvc 禁用 build cache 加速，因为 msvc 的预处理器太慢，反而极大影响构建性能。\n\n### Bugs 修复\n\n* [#3436](https://github.com/xmake-io/xmake/issues/3436): 修复自动补全和 menuconf\n* [#3463](https://github.com/xmake-io/xmake/issues/3463): 修复 c++modules 缓存问题\n* [#3545](https://github.com/xmake-io/xmake/issues/3545): 修复 armcc 的头文件依赖解析\n\n## v2.7.7\n\n### 新特性\n\n* 添加 Haiku 支持\n* [#3326](https://github.com/xmake-io/xmake/issues/3326): 添加 `xmake check` 去检测工程代码 (clang-tidy) 和 API 参数配置\n* [#3332](https://github.com/xmake-io/xmake/pull/3332): 在包中配置添加自定义 http headers\n\n### 改进\n\n* [#3318](https://github.com/xmake-io/xmake/pull/3318): 改进 dlang 工具链\n* [#2591](https://github.com/xmake-io/xmake/issues/2591): 改进 target 配置来源分析\n* 为 dmd/ldc2 改进 strip/optimization\n* [#3342](https://github.com/xmake-io/xmake/issues/3342): 改进配置构建目录，支持外置目录构建，保持远吗目录更加干净\n* [#3373](https://github.com/xmake-io/xmake/issues/3373): 为 clang-17 改进 std 模块支持\n\n### Bugs 修复\n\n* [#3317](https://github.com/xmake-io/xmake/pull/3317): 针对 Qt 工程，修复 lanuages 设置\n* [#3321](https://github.com/xmake-io/xmake/issues/3321): 修复隔天 configfiles 重新生成导致重编问题\n* [#3296](https://github.com/xmake-io/xmake/issues/3296): 修复 macOS arm64 上构建失败\n\n## v2.7.6\n\n### 新特性\n\n* [#3228](https://github.com/xmake-io/xmake/pull/3228): C++ modules 的安装发布，以及从包中导入 C++ modules 支持\n* [#3257](https://github.com/xmake-io/xmake/issues/3257): 增加对 iverilog 和 verilator 的支持\n* 支持 xp 和 vc6.0\n* [#3214](https://github.com/xmake-io/xmake/pull/3214): xrepo install 的自动补全支持\n\n### 改进\n\n* [#3255](https://github.com/xmake-io/xmake/pull/3225): 改进 clang libc++ 模块支持\n* 支持使用 mingw 编译 xmake\n* 改进 xmake 在 win xp 上的兼容性\n* 如果外部依赖被启用，切换 json 模块到纯 lua 实现，移除对 lua-cjson 的依赖\n\n### Bugs 修复\n\n* [#3229](https://github.com/xmake-io/xmake/issues/3229): 修复 vs2015 下找不到 rc.exe 问题\n* [#3271](https://github.com/xmake-io/xmake/issues/3271): 修复支持带有空格的宏定义\n* [#3273](https://github.com/xmake-io/xmake/issues/3273): 修复 nim 链接错误\n* [#3286](https://github.com/xmake-io/xmake/issues/3286): 修复 compile_commands 对 clangd 的支持\n\n## v2.7.5\n\n### 新特性\n\n* [#3201](https://github.com/xmake-io/xmake/pull/3201): 为 xrepo 添加命令自动补全\n* [#3233](https://github.com/xmake-io/xmake/issues/3233): 添加 MASM32 sdk 工具链\n\n### 改进\n\n* [#3216](https://github.com/xmake-io/xmake/pull/3216): 改进 intel one api toolkits 探测\n* [#3020](https://github.com/xmake-io/xmake/issues/3020): 添加 `--lsp=clangd` 去改进 compile_commands.json 的生成\n* [#3215](https://github.com/xmake-io/xmake/issues/3215): 添加 includedirs 和 defines 到 c51 编译器\n* [#3251](https://github.com/xmake-io/xmake/issues/3251): 改进 zig and c 混合编译\n\n### Bugs 修复\n\n* [#3203](https://github.com/xmake-io/xmake/issues/3203): 修复 compile_commands\n* [#3222](https://github.com/xmake-io/xmake/issues/3222): 修复 objc 的预编译头支持\n* [#3240](https://github.com/xmake-io/xmake/pull/3240): 修复 `xmake run` 处理单个参数不正确问题\n* [#3238](https://github.com/xmake-io/xmake/pull/3238): 修复 clang 构建 module 时候，并行写入 mapper 冲突问题\n\n## v2.7.4\n\n### 新特性\n\n* [#3049](https://github.com/xmake-io/xmake/pull/3049): 添加 `xmake format` 插件\n* 添加 `plugin.compile_commands.autoupdate` 规则\n* [#3172](https://github.com/xmake-io/xmake/pull/3172): 添加 xmake.sh\n* [#3168](https://github.com/xmake-io/xmake/pull/3168): 为 msvc 添加 C++23 标准模块支持\n\n### 改进\n\n* [#3056](https://github.com/xmake-io/xmake/issues/3056): 改进 Zig 支持\n* [#3060](https://github.com/xmake-io/xmake/issues/3060): 改进支持 msys2 的环境探测\n* [#3071](https://github.com/xmake-io/xmake/issues/3071): 为 llvm/clang 工具链支持 rc 编译\n* [#3122](https://github.com/xmake-io/xmake/pull/3122): 改进 c++20 模块依赖图的源码分析，支持预处理\n* [#3125](https://github.com/xmake-io/xmake/pull/3125): 增加私有 C++20 模块的编译支持\n* [#3133](https://github.com/xmake-io/xmake/pull/3133): 增加 internal partitions 模块支持\n* [#3146](https://github.com/xmake-io/xmake/issues/3146): 添加默认包组件支持\n* [#3192](https://github.com/xmake-io/xmake/issues/3192): 为 auto complete 增加 json 输出支持\n\n### Bugs 修复\n\n* 修复 requires-lock 问题\n* [#3065](https://github.com/xmake-io/xmake/issues/3065): 修复部分依赖包没有被安装的问题\n* [#3082](https://github.com/xmake-io/xmake/issues/3082): 修复 build.ninja 生成器\n* [#3092](https://github.com/xmake-io/xmake/issues/3092): 修复 xrepo add-repo 添加失败逻辑\n* [#3013](https://github.com/xmake-io/xmake/issues/3013): 修复支持 windows UNC 路径\n* [#2902](https://github.com/xmake-io/xmake/issues/2902): 修复文件被其他子进程占用问题\n* [#3074](https://github.com/xmake-io/xmake/issues/3074): 修复 CMakelists 生成器链接参数设置不对问题\n* [#3141](https://github.com/xmake-io/xmake/pull/3141): 修复 C++ 模块的导入顺序\n* 修复 tools/xmake 包安装构建目录\n* [#3159](https://github.com/xmake-io/xmake/issues/3159): 为 CLion 修复 compile_commands\n\n## v2.7.3\n\n### 新特性\n\n* 一种新的可选域配置语法，对 LSP 友好，并且支持域隔离。\n* [#2944](https://github.com/xmake-io/xmake/issues/2944): 为嵌入式工程添加 `gnu-rm.binary` 和 `gnu-rm.static` 规则和测试工程\n* [#2636](https://github.com/xmake-io/xmake/issues/2636): 支持包组件\n* 支持 msvc 的 armasm/armasm64\n* [#3023](https://github.com/xmake-io/xmake/pull/3023): 改进 xmake run -d，添加 renderdoc 调试器支持\n* [#3022](https://github.com/xmake-io/xmake/issues/3022): 为特定编译器添加 flags\n* [#3025](https://github.com/xmake-io/xmake/pull/3025): 新增 C++ 异常接口配置\n* [#3017](https://github.com/xmake-io/xmake/pull/3017): 支持 ispc 编译器规则\n\n### 改进\n\n* [#2925](https://github.com/xmake-io/xmake/issues/2925): 改进 doxygen 插件\n* [#2948](https://github.com/xmake-io/xmake/issues/2948): 支持 OpenBSD\n* 添加 `xmake g --insecure-ssl=y` 配置选项去禁用 ssl 证书检测\n* [#2971](https://github.com/xmake-io/xmake/pull/2971): 使 vs/vsxmake 工程生成的结果每次保持一致\n* [#3000](https://github.com/xmake-io/xmake/issues/3000): 改进 C++ 模块构建支持，实现增量编译支持\n* [#3016](https://github.com/xmake-io/xmake/pull/3016): 改进 clang/msvc 去更好地支持 std 模块\n\n### Bugs 修复\n\n* [#2949](https://github.com/xmake-io/xmake/issues/2949): 修复 vs 分组\n* [#2952](https://github.com/xmake-io/xmake/issues/2952): 修复 armlink 处理长命令失败问题\n* [#2954](https://github.com/xmake-io/xmake/issues/2954): 修复 c++ module partitions 路径无效问题\n* [#3033](https://github.com/xmake-io/xmake/issues/3033): 探测循环模块依赖\n\n## v2.7.2\n\n### 新特性\n\n* [#2140](https://github.com/xmake-io/xmake/issues/2140): 支持 Windows Arm64\n* [#2719](https://github.com/xmake-io/xmake/issues/2719): 添加 `package.librarydeps.strict_compatibility` 策略严格限制包依赖兼容性\n* [#2810](https://github.com/xmake-io/xmake/pull/2810): 支持 os.execv 去执行 shell 脚本文件\n* [#2817](https://github.com/xmake-io/xmake/pull/2817): 改进规则支持依赖顺序执行\n* [#2824](https://github.com/xmake-io/xmake/pull/2824): 传递 cross-file 交叉编译环境给 meson.install 和 trybuild\n* [#2856](https://github.com/xmake-io/xmake/pull/2856): xrepo 支持从当前指定源码目录调试程序\n* [#2859](https://github.com/xmake-io/xmake/issues/2859): 改进对三方库的 trybuild 构建，利用 xmake-repo 仓库脚本更加智能化地构建三方库\n* [#2879](https://github.com/xmake-io/xmake/issues/2879): 更好的动态创建和配置 target 和 rule\n* [#2374](https://github.com/xmake-io/xmake/issues/2374): 允许 xmake 包中引入自定义规则\n* 添加 clang-cl 工具链\n\n### 改进\n\n* [#2745](https://github.com/xmake-io/xmake/pull/2745): 改进 os.cp 支持符号链接复制\n* [#2773](https://github.com/xmake-io/xmake/pull/2773): 改进 vcpkg 包安装，支持 freebsd 平台\n* [#2778](https://github.com/xmake-io/xmake/pull/2778): 改进 xrepo.env 支持 target 的运行环境加载\n* [#2783](https://github.com/xmake-io/xmake/issues/2783): 添加摘要算法选项到 WDK 的 signtool 签名工具\n* [#2787](https://github.com/xmake-io/xmake/pull/2787): 改进 json 支持空数组\n* [#2782](https://github.com/xmake-io/xmake/pull/2782): 改进查找 matlib sdk 和运行时\n* [#2793](https://github.com/xmake-io/xmake/issues/2793): 改进 mconfdialog 配置操作体验\n* [#2804](https://github.com/xmake-io/xmake/issues/2804): 安装依赖包支持 macOS arm64/x86_64 交叉编译\n* [#2809](https://github.com/xmake-io/xmake/issues/2809): 改进 msvc 的编译优化选项\n* 改进 trybuild 模式，为 meson/autoconf/cmake 提供更好的交叉编译支持\n* [#2846](https://github.com/xmake-io/xmake/discussions/2846): 改进对 configfiles 的生成\n* [#2866](https://github.com/xmake-io/xmake/issues/2866): 更好地控制 rule 规则执行顺序\n\n### Bugs 修复\n\n* [#2740](https://github.com/xmake-io/xmake/issues/2740): 修复 msvc 构建 C++ modules 卡死问题\n* [#2875](https://github.com/xmake-io/xmake/issues/2875): 修复构建 linux 驱动错误\n* [#2885](https://github.com/xmake-io/xmake/issues/2885): 修复 ccache 下，msvc 编译 pch 失败问题\n\n## v2.7.1\n\n### 新特性\n\n* [#2555](https://github.com/xmake-io/xmake/issues/2555): 添加 fwatcher 模块和 `xmake watch` 插件命令\n* 添加 `xmake service --pull 'build/**' outputdir` 命令去拉取远程构建服务器上的文件\n* [#2641](https://github.com/xmake-io/xmake/pull/2641): 改进 C++20 模块, 支持 headerunits 和 project 生成\n* [#2679](https://github.com/xmake-io/xmake/issues/2679): 支持 Mac Catalyst 构建\n\n### 改进\n\n* [#2576](https://github.com/xmake-io/xmake/issues/2576): 改进从 cmake 中查找包，提供更过灵活的可选配置\n* [#2577](https://github.com/xmake-io/xmake/issues/2577): 改进 add_headerfiles()，增加 `{install = false}` 支持\n* [#2603](https://github.com/xmake-io/xmake/issues/2603): 为 ccache 默认禁用 `-fdirectives-only`\n* [#2580](https://github.com/xmake-io/xmake/issues/2580): 设置 stdout 到 line 缓冲输出\n* [#2571](https://github.com/xmake-io/xmake/issues/2571): 改进分布式编译的调度算法，增加 cpu/memory 状态权重\n* [#2410](https://github.com/xmake-io/xmake/issues/2410): 改进 cmakelists 生成\n* [#2690](https://github.com/xmake-io/xmake/issues/2690): 改机传递 toolchains 到包\n* [#2686](https://github.com/xmake-io/xmake/issues/2686): 改进 armcc/armclang 支持增量编译\n* [#2562](https://github.com/xmake-io/xmake/issues/2562): 改进 rc.exe 对引用文件依赖的解析和增量编译支持\n* 改进默认的并行构建任务数\n\n### Bugs 修复\n\n* [#2614](https://github.com/xmake-io/xmake/issues/2614): 为 msvc 修复构建 submodules2 测试工程\n* [#2620](https://github.com/xmake-io/xmake/issues/2620): 修复构建缓存导致的增量编译问题\n* [#2177](https://github.com/xmake-io/xmake/issues/2177): 修复 python.library 在 macOS 上段错误崩溃\n* [#2708](https://github.com/xmake-io/xmake/issues/2708): 修复 mode.coverage 规则的链接错误\n* 修复 ios/macOS framework 和 application 的 rpath 加载路径\n\n## v2.6.9\n\n### 新特性\n\n* [#2474](https://github.com/xmake-io/xmake/issues/2474): 添加 icx 和 dpcpp 工具链\n* [#2523](https://github.com/xmake-io/xmake/issues/2523): 改进对 LTO 的支持\n* [#2527](https://github.com/xmake-io/xmake/issues/2527): 添加 set_runargs 接口\n\n### 改进\n\n* 改进 tools.cmake 支持 wasm 库构建\n* [#2491](https://github.com/xmake-io/xmake/issues/2491): 如果服务器不可访问，自动回退到本地编译和缓存\n* [#2514](https://github.com/xmake-io/xmake/issues/2514): 为工程生成器禁用 Unity Build\n* [#2473](https://github.com/xmake-io/xmake/issues/2473): 改进 apt::find_package，支持从 pc 文件中查找\n* [#2512](https://github.com/xmake-io/xmake/issues/2512): 改进远程服务支持超时配置\n\n### Bugs 修复\n\n* [#2488](https://github.com/xmake-io/xmake/issues/2488): 修复从 windows 到 linux 的远程编译路径问题\n* [#2504](https://github.com/xmake-io/xmake/issues/2504): 修复在 msys2 上远程编译失败问题\n* [#2525](https://github.com/xmake-io/xmake/issues/2525): 修复安装依赖包时候卡死问题\n* [#2557](https://github.com/xmake-io/xmake/issues/2557): 修复 cmake.find_package 查找 links 错误\n* 修复缓存导致的预处理文件路径冲突问题\n\n## v2.6.8\n\n### 新特性\n\n* [#2447](https://github.com/xmake-io/xmake/pull/2447): 添加 qt.qmlplugin 规则和 qmltypesregistrar 支持\n* [#2446](https://github.com/xmake-io/xmake/issues/2446): 支持 target 分组安装\n* [#2469](https://github.com/xmake-io/xmake/issues/2469): 产生 vcpkg-configuration.json\n\n### 改进\n\n* 添加 `preprocessor.linemarkers` 策略去禁用 linemarkers 去加速 ccache/distcc\n* [#2389](https://github.com/xmake-io/xmake/issues/2389): 改进 `xmake run` 支持并行运行目标程序\n* [#2417](https://github.com/xmake-io/xmake/issues/2417): 切换 option/showmenu 的默认值，默认开启\n* [#2440](https://github.com/xmake-io/xmake/pull/2440): 改进安装包的失败错误信息\n* [#2438](https://github.com/xmake-io/xmake/pull/2438): 确保生成的 vsxmake 工程不会随机变动\n* [#2434](https://github.com/xmake-io/xmake/issues/2434): 改进插件管理器，允许多插件管理\n* [#2421](https://github.com/xmake-io/xmake/issues/2421): 改进配置选项菜单\n* [#2425](https://github.com/xmake-io/xmake/issues/2425): 添加 `preprocessor.gcc.directives_only` 策略\n* [#2455](https://github.com/xmake-io/xmake/issues/2455): 改进 emcc 的优化选项\n* [#2467](https://github.com/xmake-io/xmake/issues/2467): 支持回退到原始文件编译，兼容 msvc 预处理器的一些问题\n* [#2452](https://github.com/xmake-io/xmake/issues/2452): 添加 build.warning 策略\n\n### Bugs 修复\n\n* [#2435](https://github.com/xmake-io/xmake/pull/2435): 修复无法搜索带有 `.` 的包名\n* [#2445](https://github.com/xmake-io/xmake/issues/2445): 修复 windows 上 ccache 构建失败问题\n* [#2452](https://github.com/xmake-io/xmake/issues/2452): 修复 ccache 下，警告无法输出的问题\n\n## v2.6.7\n\n### 新特性\n\n* [#2318](https://github.com/xmake-io/xmake/issues/2318): 添加 `xmake f --policies=` 配置参数去修改默认策略\n\n### 改进\n\n* 如果预编译包构建失败，自动回退到源码包构建\n* [#2387](https://github.com/xmake-io/xmake/issues/2387): 改进 pkgconfig 和 find_package\n* 添加 `build.ccache` 策略，用于在工程中配置编译缓存\n\n### Bugs 修复\n\n* [#2382](https://github.com/xmake-io/xmake/issues/2382): 修改 headeronly 包配置\n* [#2388](https://github.com/xmake-io/xmake/issues/2388): 修复路径问题\n* [#2385](https://github.com/xmake-io/xmake/issues/2385): 修复 cmake/find_package\n* [#2395](https://github.com/xmake-io/xmake/issues/2395): 修复 c++ modules\n* 修复 find_qt 问题\n\n## v2.6.6\n\n### 新特性\n\n* [#2327](https://github.com/xmake-io/xmake/issues/2327): 支持 nvidia-hpc-sdk 工具链中的 nvc/nvc++/nvfortran 编译器\n* 添加 path 实例接口\n* [#2344](https://github.com/xmake-io/xmake/pull/2344): 添加 lz4 压缩模块\n* [#2349](https://github.com/xmake-io/xmake/pull/2349): 添加 keil/c51 工程支持\n* [#274](https://github.com/xmake-io/xmake/issues/274): 跨平台分布式编译支持\n* 使用内置的本地缓存替代 ccache\n\n### 改进\n\n* [#2309](https://github.com/xmake-io/xmake/issues/2309): 远程编译支持用户授权验证\n* 改进远程编译，增加对 lz4 压缩支持\n\n### Bugs 修复\n\n* 修复选择包版本时候 lua 栈不平衡导致的崩溃问题\n\n## v2.6.5\n\n### 新特性\n\n* [#2138](https://github.com/xmake-io/xmake/issues/2138): 支持模板包\n* [#2185](https://github.com/xmake-io/xmake/issues/2185): 添加 `--appledev=simulator` 去改进 Apple 模拟器目标编译支持\n* [#2227](https://github.com/xmake-io/xmake/issues/2227): 改进 cargo 包，支持指定 Cargo.toml 文件\n* 改进 `add_requires` 支持 git command 作为版本\n* [#622](https://github.com/xmake-io/xmake/issues/622): 支持远程编译\n* [#2282](https://github.com/xmake-io/xmake/issues/2282): 添加 `add_filegroups` 接口为 vs/vsxmake/cmake generator 增加文件组支持\n\n### 改进\n\n* [#2137](https://github.com/xmake-io/xmake/pull/2137): 改进 path 模块\n* macOS 下，减少 50% 的 Xmake 二进制文件大小\n* 改进 tools/autoconf,cmake 去更好地支持工具链切换\n* [#2221](https://github.com/xmake-io/xmake/pull/2221): 改进注册表 api 去支持 unicode\n* [#2225](https://github.com/xmake-io/xmake/issues/2225): 增加对 protobuf 的依赖分析和构建支持\n* [#2265](https://github.com/xmake-io/xmake/issues/2265): 排序 CMakeLists.txt\n* 改进 os.files 的文件遍历速度\n\n### Bugs 修复\n\n* [#2233](https://github.com/xmake-io/xmake/issues/2233): 修复 c++ modules 依赖\n\n## v2.6.4\n\n### 新特性\n\n* [#2011](https://github.com/xmake-io/xmake/issues/2011): 支持继承和局部修改官方包，例如对现有的包更换 urls 和 versions\n* 支持在 sparc, alpha, powerpc, s390x 和 sh4 上编译运行 xmake\n* 为 package() 添加 on_download 自定义下载\n* [#2021](https://github.com/xmake-io/xmake/issues/2021): 支持 Linux/Windows 下构建 Swift 程序\n* [#2024](https://github.com/xmake-io/xmake/issues/2024): 添加 asn1c 支持\n* [#2031](https://github.com/xmake-io/xmake/issues/2031): 为 add_files 增加 linker scripts 和 version scripts 支持\n* [#2033](https://github.com/xmake-io/xmake/issues/2033): 捕获 ctrl-c 去打印当前运行栈，用于调试分析卡死问题\n* [#2059](https://github.com/xmake-io/xmake/pull/2059): 添加 `xmake update --integrate` 命令去整合 shell\n* [#2070](https://github.com/xmake-io/xmake/issues/2070): 添加一些内置的 xrepo env 环境配置\n* [#2117](https://github.com/xmake-io/xmake/pull/2117): 支持为任意平台传递工具链到包\n* [#2121](https://github.com/xmake-io/xmake/issues/2121): 支持导出指定的符号列表，可用于减少动态库的大小\n\n### 改进\n\n* [#2036](https://github.com/xmake-io/xmake/issues/2036): 改进 xrepo 支持从配置文件批量安装包，例如：`xrepo install xxx.lua`\n* [#2039](https://github.com/xmake-io/xmake/issues/2039): 改进 vs generator 的 filter 目录展示\n* [#2025](https://github.com/xmake-io/xmake/issues/2025): 支持为 phony 和 headeronly 目标生成 vs 工程\n* 优化 vs 和 codesign 的探测速度\n* [#2077](https://github.com/xmake-io/xmake/issues/2077): 改进 vs 工程生成器去支持 cuda\n\n### Bugs 修复\n\n* [#2005](https://github.com/xmake-io/xmake/issues/2005): 修复 path.extension\n* [#2008](https://github.com/xmake-io/xmake/issues/2008): 修复 windows manifest 文件编译\n* [#2016](https://github.com/xmake-io/xmake/issues/2016): 修复 vs project generator 里，对象文件名冲突导致的编译失败\n\n## v2.6.3\n\n### 新特性\n\n* [#1298](https://github.com/xmake-io/xmake/issues/1928): 支持 vcpkg 清单模式安装包，实现安装包的版本选择\n* [#1896](https://github.com/xmake-io/xmake/issues/1896): 添加 `python.library` 规则去构建 pybind 模块，并且支持 soabi\n* [#1939](https://github.com/xmake-io/xmake/issues/1939): 添加 `remove_files`, `remove_headerfiles` 并且标记 `del_files` 作为废弃接口\n* 将 on_config 作为正式的公开接口，用于 target 和 rule\n* 添加 riscv32/64 支持\n* [#1970](https://github.com/xmake-io/xmake/issues/1970): 添加 CMake wrapper 支持在 CMakelists 中去调用 xrepo 集成 C/C++ 包\n* 添加内置的 github 镜像加速 pac 代理文件, `xmake g --proxy_pac=github_mirror.lua`\n\n### 改进\n\n* [#1923](https://github.com/xmake-io/xmake/issues/1923): 改进构建 linux 驱动，支持设置自定义 linux-headers 路径\n* [#1962](https://github.com/xmake-io/xmake/issues/1962): 改进 armclang 工具链去支持构建 asm\n* [#1959](https://github.com/xmake-io/xmake/pull/1959): 改进 vstudio 工程生成器\n* [#1969](https://github.com/xmake-io/xmake/issues/1969): 添加默认的 option 描述\n\n### Bugs 修复\n\n* [#1875](https://github.com/xmake-io/xmake/issues/1875): 修复部署生成 Android Qt 程序包失败问题\n* [#1973](https://github.com/xmake-io/xmake/issues/1973): 修复合并静态库\n* [#1982](https://github.com/xmake-io/xmake/pull/1982): 修复 clang 下对 c++20 子模块的依赖构建\n\n## v2.6.2\n\n### 新特性\n\n* [#1902](https://github.com/xmake-io/xmake/issues/1902): 支持构建 linux 内核驱动模块\n* [#1913](https://github.com/xmake-io/xmake/issues/1913): 通过 group 模式匹配，指定构建和运行一批目标程序\n\n### 改进\n\n* [#1872](https://github.com/xmake-io/xmake/issues/1872): 支持转义 set_configvar 中字符串值\n* [#1888](https://github.com/xmake-io/xmake/issues/1888): 改进 windows 安装器，避免错误删除其他安装目录下的文件\n* [#1895](https://github.com/xmake-io/xmake/issues/1895): 改进 `plugin.vsxmake.autoupdate` 规则\n* [#1893](https://github.com/xmake-io/xmake/issues/1893): 改进探测 icc 和 ifort 工具链\n* [#1905](https://github.com/xmake-io/xmake/pull/1905): 改进 msvc 对 external 头文件搜索探测支持\n* [#1904](https://github.com/xmake-io/xmake/pull/1904): 改进 vs201x 工程生成器\n* 添加 `XMAKE_THEME` 环境变量去切换主题配置\n* [#1907](https://github.com/xmake-io/xmake/issues/1907): 添加 `-f/--force` 参数使得 `xmake create` 可以在费控目录被强制创建\n* [#1917](https://github.com/xmake-io/xmake/pull/1917): 改进 find_package 和配置\n\n### Bugs 修复\n\n* [#1885](https://github.com/xmake-io/xmake/issues/1885): 修复 package:fetch_linkdeps 链接顺序问题\n* [#1903](https://github.com/xmake-io/xmake/issues/1903): 修复包链接顺序\n\n## v2.6.1\n\n### 新特性\n\n* [#1799](https://github.com/xmake-io/xmake/issues/1799): 支持混合 Rust 和 C++ 程序，以及集成 Cargo 依赖库\n* 添加 `utils.glsl2spv` 规则去编译 *.vert/*.frag shader 文件生成 spirv 文件和二进制 C 头文件\n\n### 改进\n\n* 默认切换到 Lua5.4 运行时\n* [#1776](https://github.com/xmake-io/xmake/issues/1776): 改进 system::find_package，支持从环境变量中查找系统库\n* [#1786](https://github.com/xmake-io/xmake/issues/1786): 改进 apt:find_package，支持查找 alias 包\n* [#1819](https://github.com/xmake-io/xmake/issues/1819): 添加预编译头到 cmake 生成器\n* 改进 C++20 Modules 为 msvc 支持 std 标准库\n* [#1792](https://github.com/xmake-io/xmake/issues/1792): 添加自定义命令到 vs 工程生成器\n* [#1835](https://github.com/xmake-io/xmake/issues/1835): 改进 MDK 程序构建支持，增加 `set_runtimes(\"microlib\")`\n* [#1858](https://github.com/xmake-io/xmake/issues/1858): 改进构建 c++20 modules，修复跨 target 构建问题\n* 添加 $XMAKE_BINARY_REPO 和 $XMAKE_MAIN_REPO 仓库设置环境变量\n* [#1865](https://github.com/xmake-io/xmake/issues/1865): 改进 openmp 工程\n* [#1845](https://github.com/xmake-io/xmake/issues/1845): 为静态库安装 pdb 文件\n\n### Bugs 修复\n\n* 修复语义版本中解析带有 0 前缀的 build 字符串问题\n* [#50](https://github.com/libbpf/libbpf-bootstrap/issues/50): 修复 rule 和构建 bpf 程序 bug\n* [#1610](https://github.com/xmake-io/xmake/issues/1610): 修复 `xmake f --menu` 在 vscode 终端下按键无响应，并且支持 ConPTY 终端虚拟按键\n\n## v2.5.9\n\n### 新特性\n\n* [#1736](https://github.com/xmake-io/xmake/issues/1736): 支持 wasi-sdk 工具链\n* 支持 Lua 5.4 运行时\n* 添加 gcc-8, gcc-9, gcc-10, gcc-11 工具链\n* [#1623](https://github.com/xmake-io/xmake/issues/1632): 支持 find_package 从 cmake 查找包\n* [#1747](https://github.com/xmake-io/xmake/issues/1747): 添加 `set_kind(\"headeronly\")` 更好的处理 headeronly 库的安装\n* [#1019](https://github.com/xmake-io/xmake/issues/1019): 支持 Unity build\n* [#1438](https://github.com/xmake-io/xmake/issues/1438): 增加 `xmake l cli.amalgamate` 命令支持代码合并\n* [#1765](https://github.com/xmake-io/xmake/issues/1756): 支持 nim 语言\n* [#1762](https://github.com/xmake-io/xmake/issues/1762): 为 `xrepo env` 管理和切换指定的环境配置\n* [#1767](https://github.com/xmake-io/xmake/issues/1767): 支持 Circle 编译器\n* [#1753](https://github.com/xmake-io/xmake/issues/1753): 支持 Keil/MDK 的 armcc/armclang 工具链\n* [#1774](https://github.com/xmake-io/xmake/issues/1774): 添加 table.contains api\n* [#1735](https://github.com/xmake-io/xmake/issues/1735): 添加自定义命令到 cmake 生成器\n* [#1781](https://github.com/xmake-io/xmake/issues/1781): 改进 get.sh 安装脚本支持 nixos\n\n### 改进\n\n* [#1528](https://github.com/xmake-io/xmake/issues/1528): 检测 c++17/20 特性\n* [#1729](https://github.com/xmake-io/xmake/issues/1729): 改进 C++20 modules 对 clang/gcc/msvc 的支持，支持模块间依赖编译和并行优化\n* [#1779](https://github.com/xmake-io/xmake/issues/1779): 改进 ml.exe/x86，移除内置的 `-Gd` 选项\n\n## v2.5.8\n\n### 新特性\n\n* [#388](https://github.com/xmake-io/xmake/issues/388): Pascal 语言支持，可以使用 fpc 来编译 free pascal\n* [#1682](https://github.com/xmake-io/xmake/issues/1682): 添加可选的额lua5.3 运行时替代 luajit，提供更好的平台兼容性。\n* [#1622](https://github.com/xmake-io/xmake/issues/1622): 支持 Swig\n* [#1714](https://github.com/xmake-io/xmake/issues/1714): 支持内置 cmake 等第三方项目的混合编译\n* [#1715](https://github.com/xmake-io/xmake/issues/1715): 支持探测编译器语言标准特性，并且新增 `check_macros` 检测接口\n* xmake 支持在 Loongarch 架构上运行\n\n### 改进\n\n* [#1618](https://github.com/xmake-io/xmake/issues/1618): 改进 vala 支持构建动态库和静态库程序\n* 改进 Qt 规则去支持 Qt 4.x\n* 改进 `set_symbols(\"debug\")` 支持 clang/windows 生成 pdb 文件\n* [#1638](https://github.com/xmake-io/xmake/issues/1638): 改进合并静态库\n* 改进 on_load/after_load 去支持动态的添加 target deps\n* [#1675](https://github.com/xmake-io/xmake/pull/1675): 针对 mingw 平台，重命名动态库和导入库文件名后缀\n* [#1694](https://github.com/xmake-io/xmake/issues/1694): 支持在 set_configvar 中定义一个不带引号的字符串变量\n* 改进对 Android NDK r23 的支持\n* 为 `set_languages` 新增 `c++latest` 和 `clatest` 配置值\n* [#1720](https://github.com/xmake-io/xmake/issues/1720): 添加 `save_scope` 和 `restore_scope` 去修复 `check_xxx` 相关接口\n* [#1726](https://github.com/xmake-io/xmake/issues/1726): 改进 compile_commands 生成器去支持 nvcc\n\n### Bugs 修复\n\n* [#1671](https://github.com/xmake-io/xmake/issues/1671): 修复安装预编译包后，*.cmake 里面的一些不正确的绝对路径\n* [#1689](https://github.com/xmake-io/xmake/issues/1689): 修复 vsxmake 插件的 unicode 字符显示和加载问题\n\n## v2.5.7\n\n### 新特性\n\n* [#1534](https://github.com/xmake-io/xmake/issues/1534): 新增对 Vala 语言的支持\n* [#1544](https://github.com/xmake-io/xmake/issues/1544): 添加 utils.bin2c 规则去自动从二进制资源文件产生 .h 头文件并引入到 C/C++ 代码中\n* [#1547](https://github.com/xmake-io/xmake/issues/1547): option/snippets 支持运行检测模式，并且可以获取输出\n* [#1567](https://github.com/xmake-io/xmake/issues/1567): 新增 xmake-requires.lock 包依赖锁定支持\n* [#1597](https://github.com/xmake-io/xmake/issues/1597): 支持编译 metal 文件到 metallib，并改进 xcode.application 规则去生成内置的 default.metallib 到 app\n\n### 改进\n\n* [#1540](https://github.com/xmake-io/xmake/issues/1540): 更好更方便地编译自动生成的代码\n* [#1578](https://github.com/xmake-io/xmake/issues/1578): 改进 add_repositories 去更好地支持相对路径\n* [#1582](https://github.com/xmake-io/xmake/issues/1582): 改进安装和 os.cp 支持符号链接\n\n### Bugs 修复\n\n* [#1531](https://github.com/xmake-io/xmake/issues/1531): 修复 targets 加载失败的错误信息提示错误\n\n## v2.5.6\n\n### 新特性\n\n* [#1483](https://github.com/xmake-io/xmake/issues/1483): 添加 `os.joinenvs()` 和改进包工具环境\n* [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_allowedmodes`, `set_allowedplats` 和 `set_allowedarchs`\n* [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_defaultmode`, `set_defaultplat` 和 `set_defaultarch`\n\n### 改进\n\n* 改进 vs/vsxmake 工程插件支持 vs2022\n* [#1513](https://github.com/xmake-io/xmake/issues/1513): 改进 windows 预编译包的兼容性问题\n* 改进 vcpkg 包在 windows 上的查找\n* 改进对 Qt6 的支持\n\n### Bugs 修复\n\n* [#489](https://github.com/xmake-io/xmake-repo/pull/489): 修复 run os.execv 带有过长环境变量值出现的一些问题\n\n\n## v2.5.5\n\n### 新特性\n\n* [#1421](https://github.com/xmake-io/xmake/issues/1421): 针对 target 目标，增加目标文件名的前缀，后缀和扩展名设置接口。\n* [#1422](https://github.com/xmake-io/xmake/issues/1422): 支持从 vcpkg, conan 中搜索包\n* [#1424](https://github.com/xmake-io/xmake/issues/1424): 设置 binary 作为默认的 target 目标类型\n* [#1140](https://github.com/xmake-io/xmake/issues/1140): 支持安装时候，手动选择从第三包包管理器安装包\n* [#1339](https://github.com/xmake-io/xmake/issues/1339): 改进 `xmake package` 去产生新的本地包格式，无缝集成 `add_requires`，并且新增生成远程包支持\n* 添加 `appletvos` 编译平台支持, `xmake f -p appletvos`\n* [#1437](https://github.com/xmake-io/xmake/issues/1437): 为包添加 headeronly 库类型去忽略 `vs_runtime`\n* [#1351](https://github.com/xmake-io/xmake/issues/1351): 支持导入导出当前配置\n* [#1454](https://github.com/xmake-io/xmake/issues/1454): 支持下载安装 windows 预编译包\n\n### 改进\n\n* [#1425](https://github.com/xmake-io/xmake/issues/1425): 改进 tools/meson 去加载 msvc 环境，并且增加一些内置配置。\n* [#1442](https://github.com/xmake-io/xmake/issues/1442): 支持从 git url 去下载包资源文件\n* [#1389](https://github.com/xmake-io/xmake/issues/1389): 支持添加工具链环境到 `xrepo env`\n* [#1453](https://github.com/xmake-io/xmake/issues/1453): 支持 protobuf 规则导出头文件搜索目录\n* 新增对 vs2022 的支持\n\n### Bugs 修复\n\n* [#1413](https://github.com/xmake-io/xmake/issues/1413): 修复查找包过程中出现的挂起卡死问题\n* [#1420](https://github.com/xmake-io/xmake/issues/1420): 修复包检测和配置缓存\n* [#1445](https://github.com/xmake-io/xmake/issues/1445): 修复 WDK 驱动签名错误\n* [#1465](https://github.com/xmake-io/xmake/issues/1465): 修复缺失的链接目录\n\n## v2.5.4\n\n### 新特性\n\n* [#1323](https://github.com/xmake-io/xmake/issues/1323): 支持从 apt 查找安装包，`add_requires(\"apt::zlib1g-dev\")`\n* [#1337](https://github.com/xmake-io/xmake/issues/1337): 添加环境变量去改进包安装和缓存目录\n* [#1338](https://github.com/xmake-io/xmake/issues/1338): 支持导入导出已安装的包\n* [#1087](https://github.com/xmake-io/xmake/issues/1087): 添加 `xrepo env shell` 并且支持从 `add_requires/xmake.lua` 加载包环境\n* [#1313](https://github.com/xmake-io/xmake/issues/1313): 为 `add_requires/add_deps` 添加私有包支持\n* [#1358](https://github.com/xmake-io/xmake/issues/1358): 支持设置镜像 url 站点加速包下载\n* [#1369](https://github.com/xmake-io/xmake/pull/1369): 为 vcpkg 增加 arm/arm64 包集成支持，感谢 @fallending\n* [#1405](https://github.com/xmake-io/xmake/pull/1405): 添加 portage 包管理器支持，感谢 @Phate6660\n\n### 改进\n\n* 改进 `find_package` 并且添加 `package:find_package` 接口在包定义中方便查找包\n* 移除废弃的 `set_config_h` 和 `set_config_h_prefix` 接口\n* [#1343](https://github.com/xmake-io/xmake/issues/1343): 改进搜索本地包文件\n* [#1347](https://github.com/xmake-io/xmake/issues/1347): 针对 binary 包改进 vs_runtime 配置\n* [#1353](https://github.com/xmake-io/xmake/issues/1353): 改进 del_files() 去加速匹配文件\n* [#1349](https://github.com/xmake-io/xmake/issues/1349): 改进 xrepo env shell 支持，更好的支持 powershell\n\n### Bugs 修复\n\n* [#1380](https://github.com/xmake-io/xmake/issues/1380): 修复 `add_packages()` 失败问题\n* [#1381](https://github.com/xmake-io/xmake/issues/1381): 修复添加本地 git 包源问题\n* [#1391](https://github.com/xmake-io/xmake/issues/1391): 修复 cuda/nvcc 工具链\n\n## v2.5.3\n\n### 新特性\n\n* [#1259](https://github.com/xmake-io/xmake/issues/1259): 支持 `add_files(\"*.def\")` 添加 def 文件去导出 windows/dll 符号\n* [#1267](https://github.com/xmake-io/xmake/issues/1267): 添加 `find_package(\"nvtx\")`\n* [#1274](https://github.com/xmake-io/xmake/issues/1274): 添加 `platform.linux.bpf` 规则去构建 linux/bpf 程序\n* [#1280](https://github.com/xmake-io/xmake/issues/1280): 支持 fetchonly 包去扩展改进 find_package\n* 支持自动拉取远程 ndk 工具链包和集成\n* [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.pkgconfig_importfiles` 规则去安装 `*.pc` 文件\n* [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.cmake_importfiles` 规则去安装 `*.cmake` 导入文件\n* [#348](https://github.com/xmake-io/xmake-repo/pull/348): 添加 `platform.longpaths` 策略去支持 git longpaths\n* [#1314](https://github.com/xmake-io/xmake/issues/1314): 支持安装使用 conda 包\n* [#1120](https://github.com/xmake-io/xmake/issues/1120): 添加 `core.base.cpu` 模块并且改进 `os.cpuinfo()`\n* [#1325](https://github.com/xmake-io/xmake/issues/1325): 为 `add_configfiles` 添加内建的 git 变量\n\n### 改进\n\n* [#1275](https://github.com/xmake-io/xmake/issues/1275): 改进 vsxmake 生成器，支持条件化编译 targets\n* [#1290](https://github.com/xmake-io/xmake/pull/1290): 增加对 Android ndk r22 以上版本支持\n* [#1311](https://github.com/xmake-io/xmake/issues/1311): 为 vsxmake 工程添加包 dll 路径，确保调试运行加载正常\n\n### Bugs 修复\n\n* [#1266](https://github.com/xmake-io/xmake/issues/1266): 修复在 `add_repositories` 中的 repo 相对路径\n* [#1288](https://github.com/xmake-io/xmake/issues/1288): 修复 vsxmake 插件处理 option 配置问题\n\n## v2.5.2\n\n### 新特性\n\n* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-766481512): 支持 `zig cc` 和 `zig c++` 作为 c/c++ 编译器\n* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-768193083): 支持使用 zig 进行交叉编译\n* [#1177](https://github.com/xmake-io/xmake/issues/1177): 改进终端和 color codes 探测\n* [#1216](https://github.com/xmake-io/xmake/issues/1216): 传递自定义 includes 脚本给 xrepo\n* 添加 linuxos 内置模块获取 linux 系统信息\n* [#1217](https://github.com/xmake-io/xmake/issues/1217): 支持当编译项目时自动拉取工具链\n* [#1123](https://github.com/xmake-io/xmake/issues/1123): 添加 `rule(\"utils.symbols.export_all\")` 自动导出所有 windows/dll 中的符号\n* [#1181](https://github.com/xmake-io/xmake/issues/1181): 添加 `utils.platform.gnu2mslib(mslib, gnulib)` 模块接口去转换 mingw/xxx.dll.a 到 msvc xxx.lib\n* [#1246](https://github.com/xmake-io/xmake/issues/1246): 改进规则支持新的批处理命令去简化自定义规则实现\n* [#1239](https://github.com/xmake-io/xmake/issues/1239): 添加 `add_extsources` 去改进外部包的查找\n* [#1241](https://github.com/xmake-io/xmake/issues/1241): 支持为 windows 程序添加 .manifest 文件参与链接\n* 支持使用 `xrepo remove --all` 命令去移除所有的包，并且支持模式匹配\n* [#1254](https://github.com/xmake-io/xmake/issues/1254): 支持导出包配置给父 target，实现包配置的依赖继承\n\n### 改进\n\n* [#1226](https://github.com/xmake-io/xmake/issues/1226): 添加缺失的 Qt 头文件搜索路径\n* [#1183](https://github.com/xmake-io/xmake/issues/1183): 改进 C++ 语言标准，以便支持 Qt6\n* [#1237](https://github.com/xmake-io/xmake/issues/1237): 为 vsxmake 插件添加 qt.ui 文件\n* 改进 vs/vsxmake 插件去支持预编译头文件和智能提示\n* [#1090](https://github.com/xmake-io/xmake/issues/1090): 简化自定义规则\n* [#1065](https://github.com/xmake-io/xmake/issues/1065): 改进 protobuf 规则，支持 compile_commands 生成器\n* [#1249](https://github.com/xmake-io/xmake/issues/1249): 改进 vs/vsxmake 生成器去支持启动工程设置\n* [#605](https://github.com/xmake-io/xmake/issues/605): 改进 add_deps 和 add_packages 直接的导出 links 顺序\n* 移除废弃的 `add_defines_h_if_ok` and `add_defines_h` 接口\n\n### Bugs 修复\n\n* [#1219](https://github.com/xmake-io/xmake/issues/1219): 修复版本检测和更新\n* [#1235](https://github.com/xmake-io/xmake/issues/1235): 修复 includes 搜索路径中带有空格编译不过问题\n\n## v2.5.1\n\n### 新特性\n\n* [#1035](https://github.com/xmake-io/xmake/issues/1035): 图形配置菜单完整支持鼠标事件，并且新增滚动栏\n* [#1098](https://github.com/xmake-io/xmake/issues/1098): 支持传递 stdin 到 os.execv 进行输入重定向\n* [#1079](https://github.com/xmake-io/xmake/issues/1079): 为 vsxmake 插件添加工程自动更新插件，`add_rules(\"plugin.vsxmake.autoupdate\")`\n* 添加 `xmake f --vs_runtime=MT` 和 `set_runtimes(\"MT\")` 去更方便的对 target 和 package 进行设置\n* [#1032](https://github.com/xmake-io/xmake/issues/1032): 支持枚举注册表 keys 和 values\n* [#1026](https://github.com/xmake-io/xmake/issues/1026): 支持对 vs/vsmake 工程增加分组设置\n* [#1178](https://github.com/xmake-io/xmake/issues/1178): 添加 `add_requireconfs()` 接口去重写依赖包的配置\n* [#1043](https://github.com/xmake-io/xmake/issues/1043): 为 luarocks 模块添加 `luarocks.module` 构建规则\n* [#1190](https://github.com/xmake-io/xmake/issues/1190): 添加对 Apple Silicon (macOS ARM) 设备的支持\n* [#1145](https://github.com/xmake-io/xmake/pull/1145): 支持在 windows 上安装部署 Qt 程序, 感谢 @SirLynix\n\n### 改进\n\n* [#1072](https://github.com/xmake-io/xmake/issues/1072): 修复并改进 cl 编译器头文件依赖信息\n* 针对 ui 模块和 `xmake f --menu` 增加 utf8 支持\n* 改进 zig 语言在 macOS 上的支持\n* [#1135](https://github.com/xmake-io/xmake/issues/1135): 针对特定 target 改进多平台多工具链同时配置支持\n* [#1153](https://github.com/xmake-io/xmake/issues/1153): 改进 llvm 工具链，针对 macos 上编译增加 isysroot 支持\n* [#1071](https://github.com/xmake-io/xmake/issues/1071): 改进 vs/vsxmake 生成插件去支持远程依赖包\n* 改进 vs/vsxmake 工程生成插件去支持全局的 `set_arch()` 设置\n* [#1164](https://github.com/xmake-io/xmake/issues/1164): 改进 vsxmake 插件调试加载 console 程序\n* [#1179](https://github.com/xmake-io/xmake/issues/1179): 改进 llvm 工具链，添加 isysroot\n\n### Bugs 修复\n\n* [#1091](https://github.com/xmake-io/xmake/issues/1091): 修复不正确的继承链接依赖\n* [#1105](https://github.com/xmake-io/xmake/issues/1105): 修复 vsxmake 插件 c++ 语言标准智能提示错误\n* [#1132](https://github.com/xmake-io/xmake/issues/1132): 修复 vsxmake 插件中配置路径被截断问题\n* [#1142](https://github.com/xmake-io/xmake/issues/1142): 修复安装包的时候，出现git找不到问题\n* 修复在 macOS Big Sur 上 macos.version 问题\n* [#1084](https://github.com/xmake-io/xmake/issues/1084): 修复 `add_defines()` 中带有双引号和空格导致无法正确处理宏定义的问题\n* [#1195](https://github.com/xmake-io/xmake/pull/1195): 修复 unicode 编码问题，改进 vs 环境查找和进程执行\n\n## v2.3.9\n\n### 新特性\n\n* 添加新的 [xrepo](https://github.com/xmake-io/xrepo) 命令去管理安装 C/C++ 包\n* 支持安装交叉编译的依赖包\n* 新增musl.cc上的工具链支持\n* [#1009](https://github.com/xmake-io/xmake/issues/1009): 支持忽略校验去安装任意版本的包，`add_requires(\"libcurl 7.73.0\", {verify = false})`\n* [#1016](https://github.com/xmake-io/xmake/issues/1016): 针对依赖包增加license兼容性检测\n* [#1017](https://github.com/xmake-io/xmake/issues/1017): 支持外部/系统头文件支持 `add_sysincludedirs`，依赖包默认使用`-isystem`\n* [#1020](https://github.com/xmake-io/xmake/issues/1020): 支持在 archlinux 和 msys2 上查找安装 pacman 包\n* 改进 `xmake f --menu` 菜单配置，支持鼠标操作\n\n### 改进\n\n* [#997](https://github.com/xmake-io/xmake/issues/997): `xmake project -k cmake` 插件增加对 `set_languages` 的支持\n* [#998](https://github.com/xmake-io/xmake/issues/998): 支持安装 windows-static-md 类型的 vcpkg 包\n* [#996](https://github.com/xmake-io/xmake/issues/996): 改进 vcpkg 目录查找\n* [#1008](https://github.com/xmake-io/xmake/issues/1008): 改进交叉编译工具链\n* [#1030](https://github.com/xmake-io/xmake/issues/1030): 改进 xcode.framework and xcode.application 规则\n* [#1051](https://github.com/xmake-io/xmake/issues/1051): 为 msvc 编译器添加 `edit` 和 `embed` 调试信息格式类型到 `set_symbols()`\n* [#1062](https://github.com/xmake-io/xmake/issues/1062): 改进 `xmake project -k vs` 插件\n\n## v2.3.8\n\n### 新特性\n\n* [#955](https://github.com/xmake-io/xmake/issues/955): 添加 Zig 空工程模板\n* [#956](https://github.com/xmake-io/xmake/issues/956): 添加 Wasm 编译平台，并且支持 Qt/Wasm SDK\n* 升级luajit到v2.1最新分支版本，并且支持mips64上运行xmake\n* [#972](https://github.com/xmake-io/xmake/issues/972): 添加`depend.on_changed()`去简化依赖文件的处理\n* [#981](https://github.com/xmake-io/xmake/issues/981): 添加`set_fpmodels()`去抽象化设置math/float-point编译优化模式\n* [#980](https://github.com/xmake-io/xmake/issues/980): 添加对 Intel C/C++ 和 Fortran 编译器的全平台支持\n* [#986](https://github.com/xmake-io/xmake/issues/986): 对16.8以上msvc编译器增加 `c11`/`c17` 支持\n* [#979](https://github.com/xmake-io/xmake/issues/979): 添加对OpenMP的跨平台抽象配置。`add_rules(\"c++.openmp\")`\n\n### 改进\n\n* [#958](https://github.com/xmake-io/xmake/issues/958): 改进mingw平台，增加对 llvm-mingw 工具链的支持，以及 arm64/arm 架构的支持\n* 增加 `add_requires(\"zlib~xxx\")` 模式使得能够支持同时安装带有多种配置的同一个包，作为独立包存在\n* [#977](https://github.com/xmake-io/xmake/issues/977): 改进 find_mingw 在 windows 上的探测\n* [#978](https://github.com/xmake-io/xmake/issues/978): 改进工具链的flags顺序\n* 改进XCode工具链，支持macOS/arm64\n\n### Bugs 修复\n\n* [#951](https://github.com/xmake-io/xmake/issues/951): 修复 emcc (WebAssembly) 工具链在windows上的支持\n* [#992](https://github.com/xmake-io/xmake/issues/992): 修复文件锁偶尔打开失败问题\n\n## v2.3.7\n\n### 新特性\n\n* [#2941](https://github.com/microsoft/winget-pkgs/pull/2941): 支持通过 winget 来安装 xmake\n* 添加 xmake-tinyc 安装包，内置tinyc编译器，支持windows上无msvc环境也可直接编译c代码\n* 添加 tinyc 编译工具链\n* 添加 emcc (emscripten) 编译工具链去编译 asm.js 和 WebAssembly\n* [#947](https://github.com/xmake-io/xmake/issues/947): 通过 `xmake g --network=private` 配置设置私有网络模式，避免远程依赖包下载访问外网导致编译失败\n\n### 改进\n\n* [#907](https://github.com/xmake-io/xmake/issues/907): 改进msvc的链接器优化选项，生成更小的可执行程序\n* 改进ubuntu下Qt环境的支持\n* [#918](https://github.com/xmake-io/xmake/pull/918): 改进cuda11工具链的支持\n* 改进Qt支持，对通过 ubuntu/apt 安装的Qt sdk也进行了探测支持，并且检测效率也优化了下\n* 改进 CMake 工程文件生成器\n* [#931](https://github.com/xmake-io/xmake/issues/931): 改进导出包，支持导出所有依赖包\n* [#930](https://github.com/xmake-io/xmake/issues/930): 如果私有包定义没有版本定义，支持直接尝试下载包\n* [#927](https://github.com/xmake-io/xmake/issues/927): 改进android ndk，支持arm/thumb指令模式切换\n* 改进 trybuild/cmake 支持 Android/Mingw/iPhoneOS/WatchOS 工具链\n\n### Bugs 修复\n\n* [#903](https://github.com/xmake-io/xmake/issues/903): 修复vcpkg包安装失败问题\n* [#912](https://github.com/xmake-io/xmake/issues/912): 修复自定义工具链\n* [#914](https://github.com/xmake-io/xmake/issues/914): 修复部分aarch64设备上运行lua出现bad light userdata pointer问题\n\n## v2.3.6\n\n### 新特性\n\n* 添加xcode工程生成器插件，`xmake project -k cmake` （当前采用cmake生成）\n* [#870](https://github.com/xmake-io/xmake/issues/870): 支持gfortran编译器\n* [#887](https://github.com/xmake-io/xmake/pull/887): 支持zig编译器\n* [#893](https://github.com/xmake-io/xmake/issues/893): 添加json模块\n* [#898](https://github.com/xmake-io/xmake/issues/898): 改进golang项目构建，支持交叉编译\n* [#275](https://github.com/xmake-io/xmake/issues/275): 支持go包管理器去集成第三方go依赖包\n* [#581](https://github.com/xmake-io/xmake/issues/581): 支持dub包管理器去集成第三方dlang依赖包\n\n### 改进\n\n* [#868](https://github.com/xmake-io/xmake/issues/868): 支持新的cl.exe的头文件依赖输出文件格式，`/sourceDependencies xxx.json`\n* [#902](https://github.com/xmake-io/xmake/issues/902): 改进交叉编译工具链\n\n## v2.3.5\n\n### 新特性\n\n* 添加`xmake show -l envs`去显示xmake内置的环境变量列表\n* [#861](https://github.com/xmake-io/xmake/issues/861): 支持从指定目录搜索本地包去直接安装远程依赖包\n* [#854](https://github.com/xmake-io/xmake/issues/854): 针对wget, curl和git支持全局代理设置\n\n### 改进\n\n* [#828](https://github.com/xmake-io/xmake/issues/828): 针对protobuf规则增加导入子目录proto文件支持\n* [#835](https://github.com/xmake-io/xmake/issues/835): 改进mode.minsizerel模式，针对msvc增加/GL支持，进一步优化目标程序大小\n* [#828](https://github.com/xmake-io/xmake/issues/828): protobuf规则支持import多级子目录\n* [#838](https://github.com/xmake-io/xmake/issues/838#issuecomment-643570920): 支持完全重写内置的构建规则，`add_files(\"src/*.c\", {rules = {\"xx\", override = true}})`\n* [#847](https://github.com/xmake-io/xmake/issues/847): 支持rc文件的头文件依赖解析\n* 改进msvc工具链，去除全局环境变量的依赖\n* [#857](https://github.com/xmake-io/xmake/pull/857): 改进`set_toolchains()`支持交叉编译的时候，特定target可以切换到host工具链同时编译\n\n### Bugs 修复\n\n* 修复进度字符显示\n* [#829](https://github.com/xmake-io/xmake/issues/829): 修复由于macOS大小写不敏感系统导致的sysroot无效路径问题\n* [#832](https://github.com/xmake-io/xmake/issues/832): 修复find_packages在debug模式下找不到的问题\n\n## v2.3.4\n\n### 新特性\n\n* [#630](https://github.com/xmake-io/xmake/issues/630): 支持*BSD系统，例如：FreeBSD, ..\n* 添加wprint接口去显示警告信息\n* [#784](https://github.com/xmake-io/xmake/issues/784): 添加`set_policy()`去设置修改一些内置的策略，比如：禁用自动flags检测和映射\n* [#780](https://github.com/xmake-io/xmake/issues/780): 针对target添加set_toolchains/set_toolsets实现更完善的工具链设置，并且实现platform和toolchains分离\n* [#798](https://github.com/xmake-io/xmake/issues/798): 添加`xmake show`插件去显示xmake内置的各种信息\n* [#797](https://github.com/xmake-io/xmake/issues/797): 添加ninja主题风格，显示ninja风格的构建进度条，`xmake g --theme=ninja`\n* [#816](https://github.com/xmake-io/xmake/issues/816): 添加mode.releasedbg和mode.minsizerel编译模式规则\n* [#819](https://github.com/xmake-io/xmake/issues/819): 支持ansi/vt100终端字符控制\n\n### 改进\n\n* [#771](https://github.com/xmake-io/xmake/issues/771): 检测includedirs,linkdirs和frameworkdirs的输入有效性\n* [#774](https://github.com/xmake-io/xmake/issues/774): `xmake f --menu`可视化配置菜单支持窗口大小Resize调整\n* [#782](https://github.com/xmake-io/xmake/issues/782): 添加add_cxflags等配置flags自动检测失败提示\n* [#808](https://github.com/xmake-io/xmake/issues/808): 生成cmakelists插件增加对add_frameworks的支持\n* [#820](https://github.com/xmake-io/xmake/issues/820): 支持独立的工作目录和构建目录，保持项目目录完全干净\n\n### Bugs 修复\n\n* [#786](https://github.com/xmake-io/xmake/issues/786): 修复头文件依赖检测\n* [#810](https://github.com/xmake-io/xmake/issues/810): 修复linux下gcc strip debug符号问题\n\n## v2.3.3\n\n### 新特性\n\n* [#727](https://github.com/xmake-io/xmake/issues/727): 支持为android, ios程序生成.so/.dSYM符号文件\n* [#687](https://github.com/xmake-io/xmake/issues/687): 支持编译生成objc/bundle程序\n* [#743](https://github.com/xmake-io/xmake/issues/743): 支持编译生成objc/framework程序\n* 支持编译bundle, framework程序，以及mac, ios应用程序，并新增一些工程模板\n* 支持对ios应用程序打包生成ipa文件，以及代码签名支持\n* 增加一些ipa打包、安装、重签名等辅助工具\n* 添加xmake.cli规则来支持开发带有xmake/core引擎的lua扩展程序\n\n### 改进\n\n* [#750](https://github.com/xmake-io/xmake/issues/750): 改进qt.widgetapp规则，支持qt私有槽\n* 改进Qt/android的apk部署，并且支持Qt5.14.0新版本sdk\n\n## v2.3.2\n\n### 新特性\n\n* 添加powershell色彩主题用于powershell终端下背景色显示\n* 添加`xmake --dry-run -v`命令去空运行构建，仅仅为了查看详细的构建命令\n* [#712](https://github.com/xmake-io/xmake/issues/712): 添加sdcc平台，并且支持sdcc编译器\n\n### 改进\n\n* [#589](https://github.com/xmake-io/xmake/issues/589): 改进优化构建速度，支持跨目标间并行编译和link，编译速度和ninja基本持平\n* 改进ninja/cmake工程文件生成器插件\n* [#728](https://github.com/xmake-io/xmake/issues/728): 改进os.cp支持保留源目录结构层级的递归复制\n* [#732](https://github.com/xmake-io/xmake/issues/732): 改进find_package支持查找homebrew/cmake安装的包\n* [#695](https://github.com/xmake-io/xmake/issues/695): 改进采用android ndk最新的abi命名\n\n### Bugs 修复\n\n* 修复windows下link error显示问题\n* [#718](https://github.com/xmake-io/xmake/issues/718): 修复依赖包下载在多镜像时一定概率缓存失效问题\n* [#722](https://github.com/xmake-io/xmake/issues/722): 修复无效的包依赖导致安装死循环问题\n* [#719](https://github.com/xmake-io/xmake/issues/719): 修复windows下主进程收到ctrlc后，.bat子进程没能立即退出的问题\n* [#720](https://github.com/xmake-io/xmake/issues/720): 修复compile_commands生成器的路径转义问题\n\n## v2.3.1\n\n### 新特性\n\n* [#675](https://github.com/xmake-io/xmake/issues/675): 支持通过设置强制将`*.c`作为c++代码编译, `add_files(\"*.c\", {sourcekind = \"cxx\"})`。\n* [#681](https://github.com/xmake-io/xmake/issues/681): 支持在msys/cygwin上编译xmake，以及添加msys/cygwin编译平台\n* 添加socket/pipe模块，并且支持在协程中同时调度process/socket/pipe\n* [#192](https://github.com/xmake-io/xmake/issues/192): 尝试构建带有第三方构建系统的项目，还支持autotools项目的交叉编译\n* 启用gcc/clang的编译错误色彩高亮输出\n* [#588](https://github.com/xmake-io/xmake/issues/588): 改进工程生成插件`xmake project -k ninja`，增加对build.ninja生成支持\n\n### 改进\n\n* [#665](https://github.com/xmake-io/xmake/issues/665): 支持 *nix style 的参数输入，感谢[@OpportunityLiu](https://github.com/OpportunityLiu)的贡献\n* [#673](https://github.com/xmake-io/xmake/pull/673): 改进tab命令补全，增加对参数values的补全支持\n* [#680](https://github.com/xmake-io/xmake/issues/680): 优化get.sh安装脚本，添加国内镜像源，加速下载\n* 改进process调度器\n* [#651](https://github.com/xmake-io/xmake/issues/651): 改进os/io模块系统操作错误提示\n\n### Bugs 修复\n\n* 修复增量编译检测依赖文件的一些问题\n* 修复log输出导致xmake-vscode插件解析编译错误信息失败问题\n* [#684](https://github.com/xmake-io/xmake/issues/684): 修复windows下android ndk的一些linker错误\n\n## v2.2.9\n\n### 新特性\n\n* [#569](https://github.com/xmake-io/xmake/pull/569): 增加对c++模块的实验性支持\n* 添加`xmake project -k xmakefile`生成器\n* [620](https://github.com/xmake-io/xmake/issues/620): 添加全局`~/.xmakerc.lua`配置文件，对所有本地工程生效.\n* [593](https://github.com/xmake-io/xmake/pull/593): 添加`core.base.socket`模块，为下一步远程编译和分布式编译做准备。\n\n### 改进\n\n* [#563](https://github.com/xmake-io/xmake/pull/563): 重构构建逻辑，将特定语言的构建抽离到独立的rules中去\n* [#570](https://github.com/xmake-io/xmake/issues/570): 改进Qt构建，将`qt.application`拆分成`qt.widgetapp`和`qt.quickapp`两个构建规则\n* [#576](https://github.com/xmake-io/xmake/issues/576): 使用`set_toolchain`替代`add_tools`和`set_tools`，解决老接口使用歧义，提供更加易理解的设置方式\n* 改进`xmake create`创建模板工程\n* [#589](https://github.com/xmake-io/xmake/issues/589): 改进默认的构建任务数，充分利用cpu core来提速整体编译速度\n* [#598](https://github.com/xmake-io/xmake/issues/598): 改进`find_package`支持在macOS上对.tbd系统库文件的查找\n* [#615](https://github.com/xmake-io/xmake/issues/615): 支持安装和使用其他arch和ios的conan包\n* [#629](https://github.com/xmake-io/xmake/issues/629): 改进hash.uuid并且实现uuid v4\n* [#639](https://github.com/xmake-io/xmake/issues/639): 改进参数解析器支持`-jN`风格传参\n\n### Bugs 修复\n\n* [#567](https://github.com/xmake-io/xmake/issues/567): 修复序列化对象时候出现的内存溢出问题\n* [#566](https://github.com/xmake-io/xmake/issues/566): 修复安装远程依赖的链接顺序问题\n* [#565](https://github.com/xmake-io/xmake/issues/565): 修复vcpkg包的运行PATH设置问题\n* [#597](https://github.com/xmake-io/xmake/issues/597): 修复xmake require安装包时间过长问题\n* [#634](https://github.com/xmake-io/xmake/issues/634): 修复mode.coverage构建规则，并且改进flags检测\n\n## v2.2.8\n\n### 新特性\n\n* 添加protobuf c/c++构建规则\n* [#468](https://github.com/xmake-io/xmake/pull/468): 添加对 Windows 的 UTF-8 支持\n* [#472](https://github.com/xmake-io/xmake/pull/472): 添加`xmake project -k vsxmake`去更好的支持vs工程的生成，内部直接调用xmake来编译\n* [#487](https://github.com/xmake-io/xmake/issues/487): 通过`xmake --files=\"src/*.c\"`支持指定一批文件进行编译。\n* 针对io模块增加文件锁接口\n* [#513](https://github.com/xmake-io/xmake/issues/513): 增加对android/termux终端的支持，可在android设备上执行xmake来构建项目\n* [#517](https://github.com/xmake-io/xmake/issues/517): 为target增加`add_cleanfiles`接口，实现快速定制化清理文件\n* [#537](https://github.com/xmake-io/xmake/pull/537): 添加`set_runenv`接口去覆盖写入系统envs\n\n### 改进\n\n* [#257](https://github.com/xmake-io/xmake/issues/257): 锁定当前正在构建的工程，避免其他xmake进程同时对其操作\n* 尝试采用/dev/shm作为os.tmpdir去改善构建过程中临时文件的读写效率\n* [#542](https://github.com/xmake-io/xmake/pull/542): 改进vs系列工具链的unicode输出问题\n* 对于安装的lua脚本，启用lua字节码存储，减少安装包大小（<2.4M），提高运行加载效率。\n\n### Bugs 修复\n\n* [#549](https://github.com/xmake-io/xmake/issues/549): 修复新版vs2019下检测环境会卡死的问题\n\n## v2.2.7\n\n### 新特性\n\n* [#455](https://github.com/xmake-io/xmake/pull/455): 支持使用 clang 作为 cuda 编译器，`xmake f --cu=clang`\n* [#440](https://github.com/xmake-io/xmake/issues/440): 为target/run添加`set_rundir()`和`add_runenvs()`接口设置\n* [#443](https://github.com/xmake-io/xmake/pull/443): 添加命令行tab自动完成支持\n* 为rule/target添加`on_link`,`before_link`和`after_link`阶段自定义脚本支持\n* [#190](https://github.com/xmake-io/xmake/issues/190): 添加`add_rules(\"lex\", \"yacc\")`规则去支持lex/yacc项目\n\n### 改进\n\n* [#430](https://github.com/xmake-io/xmake/pull/430): 添加`add_cugencodes()`api为cuda改进设置codegen\n* [#432](https://github.com/xmake-io/xmake/pull/432): 针对cuda编译支持依赖分析检测（仅支持 CUDA 10.1+）\n* [#437](https://github.com/xmake-io/xmake/issues/437): 支持指定更新源，`xmake update github:xmake-io/xmake#dev`\n* [#438](https://github.com/xmake-io/xmake/pull/438): 支持仅更新脚本，`xmake update --scriptonly dev`\n* [#433](https://github.com/xmake-io/xmake/issues/433): 改进cuda构建支持device-link设备代码链接\n* [#442](https://github.com/xmake-io/xmake/issues/442): 改进tests测试框架\n\n## v2.2.6\n\n### 新特性\n\n* [#380](https://github.com/xmake-io/xmake/pull/380): 添加导出compile_flags.txt\n* [#382](https://github.com/xmake-io/xmake/issues/382): 简化域设置语法\n* [#397](https://github.com/xmake-io/xmake/issues/397): 添加clib包集成支持\n* [#404](https://github.com/xmake-io/xmake/issues/404): 增加Qt/Android编译支持，并且支持android apk生成和部署\n* 添加一些Qt空工程模板，例如：`widgetapp_qt`, `quickapp_qt_static` and `widgetapp_qt_static`\n* [#415](https://github.com/xmake-io/xmake/issues/415): 添加`--cu-cxx`配置参数到`nvcc/-ccbin`\n* 为Android NDK添加`--ndk_stdcxx=y`和`--ndk_cxxstl=gnustl_static`参数选项\n\n### 改进\n\n* 改进远程依赖包管理，丰富包仓库\n* 改进`target:on_xxx`自定义脚本，去支持匹配`android|armv7-a@macosx,linux|x86_64`模式\n* 改进loadfile，优化启动速度，windows上启动xmake时间提速98%\n\n### Bugs 修复\n\n* [#400](https://github.com/xmake-io/xmake/issues/400): 修复qt项目c++语言标准设置无效问题\n\n## v2.2.5\n\n### 新特性\n\n* 添加`string.serialize`和`string.deserialize`去序列化，反序列化对象，函数以及其他类型\n* 添加`xmake g --menu`去图形化配置全局选项\n* [#283](https://github.com/xmake-io/xmake/issues/283): 添加`target:installdir()`和`set_installdir()`接口\n* [#260](https://github.com/xmake-io/xmake/issues/260): 添加`add_platformdirs`接口，用户现在可以自定义扩展编译平台\n* [#310](https://github.com/xmake-io/xmake/issues/310): 新增主题设置支持，用户可随意切换和扩展主题样式\n* [#318](https://github.com/xmake-io/xmake/issues/318): 添加`add_installfiles`接口到target去自定义安装文件\n* [#339](https://github.com/xmake-io/xmake/issues/339): 改进`add_requires`和`find_package`使其支持对第三方包管理的集成支持\n* [#327](https://github.com/xmake-io/xmake/issues/327): 实现对conan包管理的集成支持\n* 添加内置API `find_packages(\"pcre2\", \"zlib\")`去同时查找多个依赖包，不需要通过import导入即可直接调用\n* [#320](https://github.com/xmake-io/xmake/issues/320): 添加模板配置文件相关接口，`add_configfiles`和`set_configvar`\n* [#179](https://github.com/xmake-io/xmake/issues/179): 扩展`xmake project`插件，新增CMakelist.txt生成支持\n* [#361](https://github.com/xmake-io/xmake/issues/361): 增加对vs2019 preview的支持\n* [#368](https://github.com/xmake-io/xmake/issues/368): 支持`private, public, interface`属性设置去继承target配置\n* [#284](https://github.com/xmake-io/xmake/issues/284): 通过`add_configs()`添加和传递用户自定义配置到`package()`\n* [#319](https://github.com/xmake-io/xmake/issues/319): 添加`add_headerfiles`接口去改进头文件的设置\n* [#342](https://github.com/xmake-io/xmake/issues/342): 为`includes()`添加一些内置的辅助函数，例如：`check_cfuncs`\n\n### 改进\n\n* 针对远程依赖包，改进版本和调试模式切换\n* [#264](https://github.com/xmake-io/xmake/issues/264): 支持在windows上更新dev/master版本，`xmake update dev`\n* [#293](https://github.com/xmake-io/xmake/issues/293): 添加`xmake f/g --mingw=xxx` 配置选线，并且改进find_mingw检测\n* [#301](https://github.com/xmake-io/xmake/issues/301): 改进编译预处理头文件以及依赖头文件生成，编译速度提升30%\n* [#322](https://github.com/xmake-io/xmake/issues/322): 添加`option.add_features`, `option.add_cxxsnippets` 和 `option.add_csnippets`\n* 移除xmake 1.x的一些废弃接口, 例如：`add_option_xxx`\n* [#327](https://github.com/xmake-io/xmake/issues/327): 改进`lib.detect.find_package`增加对conan包管理器的支持\n* 改进`lib.detect.find_package`并且添加内建的`find_packages(\"zlib 1.x\", \"openssl\", {xxx = ...})`接口\n* 标记`set_modes()`作为废弃接口， 我们使用`add_rules(\"mode.debug\", \"mode.release\")`来替代它\n* [#353](https://github.com/xmake-io/xmake/issues/353): 改进`target:set`, `target:add` 并且添加`target:del`去动态修改target配置\n* [#356](https://github.com/xmake-io/xmake/issues/356): 添加`qt_add_static_plugins()`接口去支持静态Qt sdk\n* [#351](https://github.com/xmake-io/xmake/issues/351): 生成vs201x插件增加对yasm的支持\n* 重构改进整个远程依赖包管理器，更加快速、稳定、可靠，并提供更多的常用包\n\n### Bugs 修复\n\n* 修复无法通过 `set_optimize()` 设置优化选项，如果存在`add_rules(\"mode.release\")`的情况下\n* [#289](https://github.com/xmake-io/xmake/issues/289): 修复在windows下解压gzip文件失败\n* [#296](https://github.com/xmake-io/xmake/issues/296): 修复`option.add_includedirs`对cuda编译不生效\n* [#321](https://github.com/xmake-io/xmake/issues/321): 修复PATH环境改动后查找工具不对问题\n\n## v2.2.3\n\n### 新特性\n\n* [#233](https://github.com/xmake-io/xmake/issues/233): 对mingw平台增加windres的支持\n* [#239](https://github.com/xmake-io/xmake/issues/239): 添加cparser编译器支持\n* 添加插件管理器，`xmake plugin --help`\n* 添加`add_syslinks`接口去设置系统库依赖，分离与`add_links`添加的库依赖之间的链接顺序\n* 添加 `xmake l time xmake [--rebuild]` 去记录编译耗时\n* [#250](https://github.com/xmake-io/xmake/issues/250): 添加`xmake f --vs_sdkver=10.0.15063.0`去改变windows sdk版本\n* 添加`lib.luajit.ffi`和`lib.luajit.jit`扩展模块\n* [#263](https://github.com/xmake-io/xmake/issues/263): 添加object目标类型，仅仅用于编译生成object对象文件\n* [#269](https://github.com/xmake-io/xmake/issues/269): 每天第一次构建时候后台进程自动清理最近30天的临时文件\n\n### 改进\n\n* [#229](https://github.com/xmake-io/xmake/issues/229): 改进vs toolset选择已经vcproj工程文件生成\n* 改进编译依赖，对源文件列表的改动进行依赖判断\n* 支持解压*.xz文件\n* [#249](https://github.com/xmake-io/xmake/pull/249): 改进编译进度信息显示格式\n* [#247](https://github.com/xmake-io/xmake/pull/247): 添加`-D`和`--diagnosis`去替换`--backtrace`，改进诊断信息显示\n* [#259](https://github.com/xmake-io/xmake/issues/259): 改进 on_build, on_build_file 和 on_xxx 等接口\n* 改进远程包管理器，更加方便的包依赖配置切换\n* 支持only头文件依赖包的安装\n* 支持对包内置links的手动调整，`add_packages(\"xxx\", {links = {}})`\n\n### Bugs 修复\n\n* 修复安装依赖包失败中断后的状态不一致性问题\n\n## v2.2.2\n\n### 新特性\n\n* 新增fasm汇编器支持\n* 添加`has_config`, `get_config`和`is_config`接口去快速判断option和配置值\n* 添加`set_config`接口去设置默认配置\n* 添加`$xmake --try`去尝试构建工程\n* 添加`set_enabled(false)`去显示的禁用target\n* [#69](https://github.com/xmake-io/xmake/issues/69): 添加远程依赖包管理, `add_requires(\"tbox ~1.6.1\")`\n* [#216](https://github.com/xmake-io/xmake/pull/216): 添加windows mfc编译规则\n\n### 改进\n\n* 改进Qt编译编译环境探测，增加对mingw sdk的支持\n* 在自动扫描生成的xmake.lua中增加默认debug/release规则\n* [#178](https://github.com/xmake-io/xmake/issues/178): 修改mingw平台下的目标名\n* 对于`add_files()`在windows上支持大小写不敏感路径模式匹配\n* 改进`detect.sdks.find_qt`对于Qt根目录的探测\n* [#184](https://github.com/xmake-io/xmake/issues/184): 改进`lib.detect.find_package`支持vcpkg\n* [#208](https://github.com/xmake-io/xmake/issues/208): 改进rpath对动态库的支持\n* [#225](https://github.com/xmake-io/xmake/issues/225): 改进vs环境探测\n\n### Bugs 修复\n\n* [#177](https://github.com/xmake-io/xmake/issues/177): 修复被依赖的动态库target，如果设置了basename后链接失败问题\n* 修复`$ xmake f --menu`中Exit问题以及cpu过高问题\n* [#197](https://github.com/xmake-io/xmake/issues/197): 修复生成的vs201x工程文件带有中文路径乱码问题\n* 修复WDK规则编译生成的驱动在Win7下运行蓝屏问题\n* [#205](https://github.com/xmake-io/xmake/pull/205): 修复vcproj工程生成targetdir, objectdir路径设置不匹配问题\n\n## v2.2.1\n\n### 新特性\n\n* [#158](https://github.com/xmake-io/xmake/issues/158): 增加对Cuda编译环境的支持\n* 添加`set_tools`和`add_tools`接口为指定target目标设置编译工具链\n* 添加内建规则：`mode.debug`, `mode.release`, `mode.profile`和`mode.check`\n* 添加`is_mode`, `is_arch` 和`is_plat`内置接口到自定义脚本域\n* 添加color256代码\n* [#160](https://github.com/xmake-io/xmake/issues/160): 增加对Qt SDK编译环境的跨平台支持，并且增加`qt.console`, `qt.application`等规则\n* 添加一些Qt工程模板\n* [#169](https://github.com/xmake-io/xmake/issues/169): 支持yasm汇编器\n* [#159](https://github.com/xmake-io/xmake/issues/159): 增加对WDK驱动编译环境支持\n\n### 改进\n\n* 添加FAQ到自动生成的xmake.lua文件，方便用户快速上手\n* 支持Android NDK >= r14的版本\n* 改进swiftc对warning flags的支持\n* [#167](https://github.com/xmake-io/xmake/issues/167): 改进自定义规则：`rule()`\n* 改进`os.files`和`os.dirs`接口，加速文件模式匹配\n* [#171](https://github.com/xmake-io/xmake/issues/171): 改进Qt环境的构建依赖\n* 在makefile生成插件中实现`make clean`\n\n### Bugs 修复\n\n* 修复无法通过`add_ldflags(\"xx\", \"xx\", {force = true})`强制设置多个flags的问题\n* [#157](https://github.com/xmake-io/xmake/issues/157): 修复pdb符号输出目录不存在情况下编译失败问题\n* 修复对macho格式目标strip all符号失效问题\n* [#168](https://github.com/xmake-io/xmake/issues/168): 修复生成vs201x工程插件，在x64下失败的问题\n\n## v2.1.9\n\n### 新特性\n\n* 添加`del_files()`接口去从已添加的文件列表中移除一些文件\n* 添加`rule()`, `add_rules()`接口实现自定义构建规则，并且改进`add_files(\"src/*.md\", {rule = \"markdown\"})`\n* 添加`os.filesize()`接口\n* 添加`core.ui.xxx`等cui组件模块，实现终端可视化界面，用于实现跟用户进行短暂的交互\n* 通过`xmake f --menu`实现可视化菜单交互配置，简化工程的编译配置\n* 添加`set_values`接口到option\n* 改进option，支持根据工程中用户自定义的option，自动生成可视化配置菜单\n* 在调用api设置工程配置时以及在配置菜单中添加源文件位置信息\n\n### 改进\n\n* 改进交叉工具链配置，通过指定工具别名定向到已知的工具链来支持未知编译工具名配置, 例如: `xmake f --cc=gcc@ccmips.exe`\n* [#151](https://github.com/xmake-io/xmake/issues/151): 改进mingw平台下动态库生成\n* 改进生成makefile插件\n* 改进检测错误提示\n* 改进`add_cxflags`等flags api的设置，添加force参数，来禁用自动检测和映射，强制设置选项：`add_cxflags(\"-DTEST\", {force = true})`\n* 改进`add_files`的flags设置，添加force域，用于设置不带自动检测和映射的原始flags：`add_files(\"src/*.c\", {force = {cxflags = \"-DTEST\"}})`\n* 改进搜索工程根目录策略\n* 改进vs环境探测，支持加密文件系统下vs环境的探测\n* 升级luajit到最新2.1.0-beta3\n* 增加对linux/arm, arm64的支持，可以在arm linux上运行xmake\n* 改进vs201x工程生成插件，更好的includedirs设置支持\n\n### Bugs 修复\n\n* 修复依赖修改编译和链接问题\n* [#151](https://github.com/xmake-io/xmake/issues/151): 修复`os.nuldev()`在mingw上传入gcc时出现问题\n* [#150](https://github.com/xmake-io/xmake/issues/150): 修复windows下ar.exe打包过长obj列表参数，导致失败问题\n* 修复`xmake f --cross`无法配置问题\n* 修复`os.cd`到windows根路径问题\n\n## v2.1.8\n\n### 新特性\n\n* 添加`XMAKE_LOGFILE`环境变量，启用输出到日志文件\n* 添加对tinyc编译器的支持\n\n### 改进\n\n* 改进对IDE和编辑器插件的集成支持，例如：Visual Studio Code, Sublime Text 以及 IntelliJ IDEA\n* 当生成新工程的时候，自动生成一个`.gitignore`文件，忽略一些xmake的临时文件和目录\n* 改进创建模板工程，使用模板名代替模板id作为参数\n* 改进macOS编译平台的探测，如果没有安装xcode也能够进行编译构建，如果有编译器的话\n* 改进`set_config_header`接口，支持局部版本号设置，优先于全局`set_version`，例如：`set_config_header(\"config\", {version = \"2.1.8\", build = \"%Y%m%d%H%M\"})`\n\n### Bugs 修复\n\n* [#145](https://github.com/xmake-io/xmake/issues/145): 修复运行target的当前目录环境\n\n## v2.1.7\n\n### 新特性\n\n* 添加`add_imports`去为target，option和package的自定义脚本批量导入模块，简化自定义脚本\n* 添加`xmake -y/--yes`去确认用户输入\n* 添加`xmake l package.manager.install xxx`模块，进行跨平台一致性安装软件包\n* 添加vscode编辑器插件支持，更加方便的使用xmake，[xmake-vscode](https://marketplace.visualstudio.com/items?itemName=tboox.xmake-vscode#overview)\n* 添加`xmake macro ..`快速运行最近一次命令\n\n### 改进\n\n* 改进`cprint()`，支持24位真彩色输出\n* 对`add_rpathdirs()`增加对`@loader_path`和`$ORIGIN`的内置变量支持，提供可迁移动态库加载\n* 改进`set_version(\"x.x.x\", {build = \"%Y%m%d%H%M\"})` 支持buildversion设置\n* 移除docs目录，将其放置到独立xmake-docs仓库中，减少xmake.zip的大小，优化下载安装的效率\n* 改进安装和卸载脚本，支持DESTDIR和PREFIX环境变量设置\n* 通过缓存优化flags探测，加速编译效率\n* 添加`COLORTERM=nocolor`环境变量开关，禁用彩色输出\n* 移除`add_rbindings`和`add_bindings`接口\n* 禁止在重定向的时候进行彩色输出，避免输出文件中带有色彩代码干扰\n* 更新tbox工程模板\n* 改进`lib.detect.find_program`模块接口\n* 为windows cmd终端增加彩色输出\n* 增加`-w|--warning`参数来启用实时警告输出\n\n### Bugs 修复\n\n* 修复`set_pcxxheader`编译没有继承flags配置问题\n* [#140](https://github.com/xmake-io/xmake/issues/140): 修复`os.tmpdir()`在fakeroot下的冲突问题\n* [#142](https://github.com/xmake-io/xmake/issues/142): 修复`os.getenv` 在windows上的中文编码问题\n* 修复在带有空格路径的情况下，编译错误问题\n* 修复setenv空值的崩溃问题\n\n## v2.1.6\n\n### 改进\n\n* 改进`add_files`，支持对files粒度进行编译选项的各种配置，更加灵活。\n* 从依赖的target和option中继承links和linkdirs。\n* 改进`target.add_deps`接口，添加继承配置，允许手动禁止依赖继承，例如：`add_deps(\"test\", {inherit = false})`\n* 移除`tbox.pkg`二进制依赖，直接集成tbox源码进行编译\n\n### Bugs 修复\n\n* 修复目标级联依赖问题\n* 修复`target:add`和`option:add`问题\n* 修复在archlinux上的编译和安装问题\n* 修复`/ZI`的兼容性问题，用`/Zi`替代\n\n## v2.1.5\n\n### 新特性\n\n* [#83](https://github.com/xmake-io/xmake/issues/83): 添加 `add_csnippet`，`add_cxxsnippet`到`option`来检测一些编译器特性\n* [#83](https://github.com/xmake-io/xmake/issues/83): 添加用户扩展模块去探测程序，库文件以及其他主机环境\n* 添加`find_program`, `find_file`, `find_library`, `find_tool`和`find_package` 等模块接口\n* 添加`net.*`和`devel.*`扩展模块\n* 添加`val()`接口去获取内置变量，例如：`val(\"host\")`, `val(\"env PATH\")`, `val(\"shell echo hello\")` and `val(\"reg HKEY_LOCAL_MACHINE\\\\XX;Value\")`\n* 增加对微软.rc资源文件的编译支持，当在windows上编译时，可以增加资源文件了\n* 增加`has_flags`, `features`和`has_features`等探测模块接口\n* 添加`option.on_check`, `option.after_check` 和 `option.before_check` 接口\n* 添加`target.on_load`接口\n* [#132](https://github.com/xmake-io/xmake/issues/132): 添加`add_frameworkdirs`接口\n* 添加`lib.detect.has_xxx`和`lib.detect.find_xxx`接口\n* 添加`add_moduledirs`接口在工程中定义和加载扩展模块\n* 添加`includes`接口替换`add_subdirs`和`add_subfiles`\n* [#133](https://github.com/xmake-io/xmake/issues/133): 改进工程插件，通过运行`xmake project -k compile_commands`来导出`compile_commands.json`\n* 添加`set_pcheader`和`set_pcxxheader`去支持跨编译器预编译头文件，支持`gcc`, `clang`和`msvc`\n* 添加`xmake f -p cross`平台用于交叉编译，并且支持自定义平台名\n\n### 改进\n\n* [#87](https://github.com/xmake-io/xmake/issues/87): 为依赖库目标自动添加：`includes` 和 `links`\n* 改进`import`接口，去加载用户扩展模块\n* [#93](https://github.com/xmake-io/xmake/pull/93): 改进 `xmake lua`，支持运行单行命令和模块\n* 改进编译错误提示信息输出\n* 改进`print`接口去更好些显示table数据\n* [#111](https://github.com/xmake-io/xmake/issues/111): 添加`--root`通用选项去临时支持作为root运行\n* [#113](https://github.com/xmake-io/xmake/pull/113): 改进权限管理，现在作为root运行也是非常安全的\n* 改进`xxx_script`工程描述api，支持多平台模式选择, 例如：`on_build(\"iphoneos|arm*\", function (target) end)`\n* 改进内置变量，支持环境变量和注册表数据的获取\n* 改进vstudio环境和交叉工具链的探测\n* [#71](https://github.com/xmake-io/xmake/issues/71): 改进从环境变量中探测链接器和编译器\n* 改进option选项检测，通过多任务检测，提升70%的检测速度\n* [#129](https://github.com/xmake-io/xmake/issues/129): 检测链接依赖，如果源文件没有改变，就不必重新链接目标文件了\n* 在vs201x工程插件中增加对`*.asm`文件的支持\n* 标记`add_bindings`和`add_rbindings`为废弃接口\n* 优化`xmake rebuild`在windows上的构建速度\n* 将`core.project.task`模块迁移至`core.base.task`\n* 将`echo` 和 `app2ipa` 插件迁移到 [xmake-plugins](https://github.com/xmake-io/xmake-plugins) 仓库\n* 添加`set_config_header(\"config.h\", {prefix = \"\"})` 代替 `set_config_h` 和 `set_config_h_prefix`\n\n### Bugs 修复\n\n* 修复`try-catch-finally`\n* 修复解释器bug，解决当加载多级子目录时，根域属性设置不对\n* [#115](https://github.com/xmake-io/xmake/pull/115): 修复安装脚本`get.sh`的路径问题\n* 修复`import()`导入接口的缓存问题\n\n## v2.1.4\n\n### 新特性\n\n* [#68](https://github.com/xmake-io/xmake/issues/68): 增加`$(programdir)`和`$(xmake)`内建变量\n* 添加`is_host`接口去判断当前的主机环境\n* [#79](https://github.com/xmake-io/xmake/issues/79): 增强`xmake lua`，支持交互式解释执行\n\n### 改进\n\n* 修改菜单选项颜色\n* [#71](https://github.com/xmake-io/xmake/issues/71): 针对widows编译器改进优化选项映射\n* [#73](https://github.com/xmake-io/xmake/issues/73): 尝试获取可执行文件路径来作为xmake的脚本目录\n* 在`add_subdirs`中的子`xmake.lua`中，使用独立子作用域，避免作用域污染导致的干扰问题\n* [#78](https://github.com/xmake-io/xmake/pull/78): 美化非全屏终端窗口下的`xmake --help`输出\n* 避免产生不必要的`.xmake`目录，如果不在工程中的时候\n\n### Bugs 修复\n\n* [#67](https://github.com/xmake-io/xmake/issues/67): 修复 `sudo make install` 命令权限问题\n* [#70](https://github.com/xmake-io/xmake/issues/70): 修复检测android编译器错误\n* 修复临时文件路径冲突问题\n* 修复`os.host`, `os.arch`等接口\n* 修复根域api加载干扰其他子作用域问题\n* [#77](https://github.com/xmake-io/xmake/pull/77): 修复`cprint`色彩打印中断问题\n\n## v2.1.3\n\n### 新特性\n\n* [#65](https://github.com/xmake-io/xmake/pull/65): 为target添加`set_default`接口用于修改默认的构建所有targets行为\n* 允许在工程子目录执行`xmake`命令进行构建，xmake会自动检测所在的工程根目录\n* 添加`add_rpathdirs` api到target和option，支持动态库的自动加载运行\n\n### 改进\n\n* [#61](https://github.com/xmake-io/xmake/pull/61): 提供更加安全的`xmake install` and `xmake uninstall`任务，更友好的处理root安装问题\n* 提供`rpm`, `deb`和`osxpkg`安装包\n* [#63](https://github.com/xmake-io/xmake/pull/63): 改进安装脚本，实现更加安全的构建和安装xmake\n* [#61](https://github.com/xmake-io/xmake/pull/61): 禁止在root权限下运行xmake命令，增强安全性\n* 改进工具链检测，通过延迟延迟检测提升整体检测效率\n* 当自动扫面生成`xmake.lua`时，添加更友好的用户提示，避免用户无操作\n\n### Bugs 修复\n\n* 修复版本检测的错误提示信息\n* [#60](https://github.com/xmake-io/xmake/issues/60): 修复macosx和windows平台的xmake自举编译\n* [#64](https://github.com/xmake-io/xmake/issues/64): 修复构建android `armv8-a`架构失败问题\n* [#50](https://github.com/xmake-io/xmake/issues/50): 修复构建android可执行程序，无法运行问题\n\n## v2.1.2\n\n### 新特性\n\n* 添加aur打包脚本，并支持用`yaourt`包管理器进行安装。\n* 添加[set_basename](#http://xmake.io/#/zh/manual?id=targetset_basename)接口，便于定制化修改生成后的目标文件名\n\n### 改进\n\n* 支持vs2017编译环境\n* 支持编译android版本的rust程序\n* 增强vs201x工程生成插件，支持同时多模式、架构编译\n\n### Bugs 修复\n\n* 修复编译android程序，找不到系统头文件问题\n* 修复检测选项行为不正确问题\n* [#57](https://github.com/xmake-io/xmake/issues/57): 修复代码文件权限到0644\n\n## v2.1.1\n\n### 新特性\n\n* 添加`--links`, `--linkdirs` and `--includedirs` 配置参数\n* 添加app2ipa插件\n* 为`xmake.lua`工程描述增加dictionay语法风格\n* 提供智能扫描编译模式，在无任何`xmake.lua`等工程描述文件的情况下，也能直接快速编译\n* 为`xmake.lua`工程描述添加`set_xmakever`接口，更加友好的处理版本兼容性问题\n* 为`objc`和`swift`程序添加`add_frameworks`接口\n* 更加快速方便的多语言扩展支持，增加`golang`, `dlang`和`rust`程序构建的支持\n* 添加`target_end`, `option_end` 和`task_end`等可选api，用于显示结束描述域，进入根域设置，提高可读性\n* 添加`golang`, `dlang`和`rust`工程模板\n\n### 改进\n\n* 工程生成插件支持vs2017\n* 改进gcc/clang编译器警告和错误提示\n* 重构代码架构，改进多语言支持，更加方便灵活的扩展语言支持\n* 改进print接口，同时支持原生lua print以及格式化打印\n* 如果xmake.lua不存在，自动扫描工程代码文件，并且生成xmake.lua进行编译\n* 修改license，使用更加宽松的Apache License 2.0\n* 移除一些二进制工具文件\n* 移除install.bat脚本，提供windows nsis安装包支持\n* 使用[docute](https://github.com/egoist/docute)重写[文档](http://www.xmake.io/#/zh/)，提供更加完善的文档支持\n* 增强`os.run`, `os.exec`, `os.cp`, `os.mv` 和 `os.rm` 等接口，支持通配符模式匹配和批量文件操作\n* 精简和优化构建输出信息，添加`-q|--quiet`选项实现静默构建\n* 改进`makefile`生成插件，抽取编译工具和编译选项到全局变量\n\n### Bugs 修复\n\n* [#41](https://github.com/waruqi/xmake/issues/41): 修复在windows下自动检测x64失败问题\n* [#43](https://github.com/waruqi/xmake/issues/43): 避免创建不必要的.xmake工程缓存目录\n* 针对android版本添加c++ stl搜索目录，解决编译c++失败问题\n* 修复在rhel 5.10上编译失败问题\n* 修复`os.iorun`返回数据不对问题\n\n## v2.0.5\n\n### 新特性\n\n* 为解释器作用域增加一些内建模块支持\n* 针对windows x64平台，支持ml64汇编器\n\n### 改进\n\n* 增强ipairs和pairs接口，支持过滤器模式，简化脚本代码\n* 为vs201x工程生成增加文件filter\n* 移除`core/tools`目录以及msys工具链，在windows上使用xmake自编译core源码进行安装，优化xmake源码磁盘空间\n* 移除`xmake/packages`，默认模板安装不再内置二进制packages，暂时需要手动放置，以后再做成自动包依赖下载编译\n\n### Bugs 修复\n\n* 修复msvc的编译选项不支持问题：`-def:xxx.def`\n* 修复ml.exe汇编器脚本\n* 修复选项链接顺序问题\n\n## v2.0.4\n\n### 新特性\n\n* 在`xmake.lua`中添加原生shell支持，例如：`add_ldflags(\"$(shell pkg-config --libs sqlite3)\")`\n* 编译windows目标程序，默认默认启用pdb符号文件\n* 在windows上添加调试器支持（vsjitdebugger, ollydbg, windbg ... ）\n* 添加`getenv`接口到`xmake.lua`的全局作用域中\n* 添加生成vstudio工程插件(支持：vs2002 - vs2015)\n* 为option添加`set_default`接口\n\n### 改进\n\n* 增强内建变量的处理\n* 支持字符串类型的选项option设置\n\n### Bugs 修复\n\n* 修复在linux下检测ld连接器失败，如果没装g++的话\n* 修复`*.cxx`编译失败问题\n\n## v2.0.3\n\n### 新特性\n\n* 增加头文件依赖自动检测和增量编译，提高编译速度\n* 在终端中进行颜色高亮提示\n* 添加调试器支持，`xmake run -d program ...`\n\n### 改进\n\n* 增强运行shell的系列接口\n* 更新luajit到v2.0.4版本\n* 改进makefile生成插件，移除对xmake的依赖，并且支持`windows/linux/macosx`等大部分pc平台\n* 优化多任务编译速度，在windows下编译提升较为明显\n\n### Bugs 修复\n\n* 修复安装目录错误问题\n* 修复`import`根目录错误问题\n* 修复在多版本vs同时存在的情况下，检测vs环境失败问题\n\n## v2.0.2\n\n### 改进\n\n* 修改安装和卸载的action处理\n* 更新工程模板\n* 增强函数检测\n\n### Bugs 修复\n\n* [#7](https://github.com/waruqi/xmake/issues/7): 修复用模板创建工程后，target名不对问题：'[targetname]'\n* [#9](https://github.com/waruqi/xmake/issues/9): 修复clang不支持c++11的问题\n* 修复api作用域泄露问题\n* 修复在windows上的一些路径问题\n* 修复检测宏函数失败问题\n* 修复检测工具链失败问题\n* 修复windows上编译android版本失败\n\n## v2.0.1\n\n### 新特性\n\n* 增加task任务机制，可运行自定义任务脚本\n* 实现plugin扩展机制，可以很方便扩展实现自定义插件，目前已实现的一些内置插件\n* 增加project文件导出插件(目前已支持makefile的生成，后续会支持：vs, xcode等工程的生成)\n* 增加hello xmake插件（插件demo）\n* 增加doxygen文档生成插件\n* 增加自定义宏脚本插件（支持动态宏记录、宏回放、匿名宏、批量导入、导出等功能）\n* 增加更多的类库用于插件化开发\n* 实现异常捕获机制，简化上层调用逻辑\n* 增加多个option进行宏绑定，实现配置一个参数，就可以同时对多个配置进行生效\n* 增加显示全局构建进度\n\n### 改进\n\n* 重构整个xmake.lua描述文件的解释器，更加的灵活可扩展\n* 更加严格的语法检测机制\n* 更加严格的作用域管理，实现沙盒引擎，对xmake.lua中脚本进行沙盒化处理，使得xmake.lua更加的安全\n* 简化模板的开发，简单几行描述就可以扩展一个新的自定义工程模板\n* 完全模块化platforms、tools、templates、actions，以及通过自注册机制，只需把自定义的脚本放入对应目录，就可实现快速扩展\n* 针对所有可扩展脚本所需api进行大量简化，并实现大量类库，通过import机制进行导入使用\n* 移除对gnu make/nmake等make工具的依赖，不再需要makefile，实现自己的make算法，\n* 优化构建速度，支持多任务编译(支持vs编译器)（实测：比v1.0.4提升x4倍的构建性能）\n* 优化自动检测机制，更加的稳定和准确\n* 修改部分工程描述api，增强扩展性，减少一些命名歧义（对低版本向下兼容）\n* 优化静态库合并：`add_files(\"*.a\")`，修复一些bug\n* 优化交叉编译，通过`--sdk=xxx`参数实现更加方便智能的进行交叉编译配置，简化mingw平台的编译配置\n* 简化命令行配置开关, 支持`xmake config --xxx=[y|n|yes|no|true|false]`等开关值\n* 合并iphoneos和iphonesimulator平台，以及watchos和watchsimulator平台，通过arch来区分，使得打包更加方便，能够支持一次性打包iphoneos的所有arch到一个包中\n\n### Bugs 修复\n\n* [#3](https://github.com/waruqi/xmake/issues/3): 修复ArchLinux 编译失败问题\n* [#4](https://github.com/waruqi/xmake/issues/4): 修复windows上安装失败问题\n* 修复windows上环境变量设置问题\n\n## v1.0.4\n\n### 新特性\n\n* 增加对windows汇编器的支持\n* 为xmake create增加一些新的工程模板，支持tbox版本\n* 支持swift代码\n* 针对-v参数，增加错误输出信息\n* 增加apple编译平台：watchos, watchsimulator的编译支持\n* 增加对windows: x64, amd64, x86_amd64架构的编译支持\n* 实现动态库和静态库的快速切换\n* 添加-j/--jobs参数，手动指定是否多任务编译，默认改为单任务编译\n\n### 改进\n\n* 增强`add_files`接口，支持直接添加`*.o/obj/a/lib`文件，并且支持静态库的合并\n* 裁剪xmake的安装过程，移除一些预编译的二进制程序\n\n### Bugs 修复\n\n* [#1](https://github.com/waruqi/xmake/issues/4): 修复win7上安装失败问题\n* 修复和增强工具链检测\n* 修复一些安装脚本的bug, 改成外置sudo进行安装\n* 修复linux x86_64下安装失败问题\n\n## v1.0.3\n\n### 新特性\n\n* 添加set_runscript接口，支持自定义运行脚本扩展\n* 添加import接口，使得在xmake.lua中可以导入一些扩展模块，例如：os，path，utils等等，使得脚本更灵活\n* 添加android平台arm64-v8a支持\n\n### Bugs 修复\n\n* 修复set_installscript接口的一些bug\n* 修复在windows x86_64下，安装失败的问题\n* 修复相对路径的一些bug\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at [waruqi@gmail.com]. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\n# Contributor Covenant行为准则\n\n# 参与者公约\n\n## 我们的保证\n\n为了促进一个开放透明且友好的环境，我们作为贡献者和维护者保证：无论年龄、种族、民族、性别认同和表达（方式）、体型、身体健全与否、经验水平、国籍、个人表现、宗教或性别取向，参与者在我们项目和社区中都免于骚扰。\n\n## 我们的标准\n\n有助于创造正面环境的行为包括但不限于：\n\n* 使用友好和包容性语言\n* 尊重不同的观点和经历\n* 耐心地接受建设性批评\n* 关注对社区最有利的事情\n* 友善对待其他社区成员\n\n身为参与者不能接受的行为包括但不限于：\n\n* 使用与性有关的言语或是图像，以及不受欢迎的性骚扰\n* 捣乱/煽动/造谣的行为或进行侮辱/贬损的评论，人身攻击及政治攻击\n* 公开或私下的骚扰\n* 未经许可地发布他人的个人资料，例如住址或是电子地址\n* 其他可以被合理地认定为不恰当或者违反职业操守的行为\n\n## 我们的责任\n\n项目维护者有责任为「可接受的行为」标准做出诠释，以及对已发生的不被接受的行为采取恰当且公平的纠正措施。\n\n项目维护者有权利及责任去删除、编辑、拒绝与本行为标准有所违背的评论 (comments)、提交 (commits)、代码、wiki 编辑、问题 (issues) 和其他贡献，以及项目维护者可暂时或永久性的禁止任何他们认为有不适当、威胁、冒犯、有害行为的贡献者。\n\n## 使用范围\n\n当一个人代表该项目或是其社区时，本行为标准适用于其项目平台和公共平台。\n\n代表项目或是社区的情况，举例来说包括使用官方项目的电子邮件地址、通过官方的社区媒体账号发布或线上或线下事件中担任指定代表。\n\n该项目的呈现方式可由其项目维护者进行进一步的定义及解释。\n\n## 强制执行\n\n可以通过[waruqi@gmail.com]，来联系项目团队来举报滥用、骚扰或其他不被接受的行为。\n\n任何维护团队认为有必要且适合的所有投诉都将进行审查及调查，并做出相对应的回应。项目小组有对事件回报者有保密的义务。具体执行的方针近一步细节可能会单独公布。\n\n没有切实地遵守或是执行本行为标准的项目维护人员，可能会因项目领导人或是其他成员的决定，暂时或是永久地取消其参与资格。\n\n## 来源\n\n本行为标准改编自[贡献者公约][主页]，版本 1.4\n可在此观看https://www.contributor-covenant.org/zh-cn/version/1/4/code-of-conduct.html\n\n[主页]: https://www.contributor-covenant.org\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nIf you discover issues, have ideas for improvements or new features, or\nwant to contribute a new module, please report them to the\n[issue tracker][1] of the repository or submit a pull request. Please,\ntry to follow these guidelines when you do so.\n\n## Issue reporting\n\n* Check that the issue has not already been reported.\n* Check that the issue has not already been fixed in the latest code\n  (a.k.a. `master`).\n* Be clear, concise and precise in your description of the problem.\n* Open an issue with a descriptive title and a summary in grammatically correct,\n  complete sentences.\n* Include any relevant code to the issue summary.\n\n## Pull requests\n\n* Please update your local branch to the latest before submitting a pull request to ensure no merge conflicts.\n* Use a topic branch to easily amend a pull request later, if necessary.\n* Write good commit messages.\n* Please use English for commit messages to standardize the log format.\n* Use the same coding conventions as the rest of the project.\n* Ensure your edited codes with four spaces instead of TAB.\n* Please commit code to `dev` branch and we will merge into `master` branch in future.\n* If it involves public API changes, please create a corresponding feature request in issues first, then describe the design of the new API in detail. It needs to be approved before you can start creating a PR to add and implement them, rather than directly opening a PR to add or modify new APIs at will.\n\n## Development Guide\n\n### Compiling Source Code\n\n1. Download source code\n\n```bash\ngit clone --recursive https://github.com/xmake-io/xmake.git\ncd xmake\n```\n\n2. Compile\n\n* Linux/macOS\n\n```bash\n./configure\nmake\n```\n\n* Windows\n\n```bash\ncd core\nxmake\n```\n\n### Local Debugging\n\nIf you want to debug the local xmake source code, you can run the following command to load the local environment.\n\n* Linux/macOS\n\n```bash\nsource scripts/srcenv.profile\nxmake --version\n```\n\n* Windows\n\nRun `scripts\\srcenv.bat` directly.\n\nAfter loading the environment, we can directly modify the Lua script in the source code directory, and then run `xmake` to verify the modification effect in real time, without reinstalling.\n\n### Environment Variables for Debugging\n\n* `XMAKE_PROGRAM_DIR`: This environment variable specifies the directory containing Xmake's Lua scripts. By setting this to your local `xmake` source directory (e.g., `path/to/xmake/xmake`), you can force Xmake to use your local scripts. This allows you to test changes to Lua scripts immediately without re-compiling or re-installing.\n* `XMAKE_PROGRAM_FILE`: This environment variable specifies the path to the `xmake` executable. It ensures that the correct binary is used, which is useful when you have multiple Xmake versions or want to test a locally compiled binary.\n\nThe `source scripts/srcenv.profile` (or `srcenv.bat`) command automatically sets these variables for you.\n\n### Run Tests\n\nRun the tests using the following command (Please ensure the local environment is loaded):\n\n```bash\nxmake l tests/run.lua [testname]\n```\n\n### Source Code Structure\n\nThe xmake source code is mainly divided into two parts: the C core and the Lua scripts.\n\n* `core/`: The C core implementation, including the Lua runtime, cross-platform abstraction layer, and native API implementation.\n* `xmake/`: The Lua script implementation, containing the core logic, modules, actions, and platforms.\n\n#### Architecture Design\n\nXmake adopts a separation of concern design, where the performance-critical parts are implemented in C, and the build logic is implemented in Lua.\n\n* **Sandbox**: User's `xmake.lua` and plugin scripts run in a sandbox environment to ensure safety and isolation. The sandbox API is defined in `xmake/core/sandbox`.\n* **Core Modules**: The core Lua modules are located in `xmake/core`.\n* **Actions**: Built-in actions (like `build`, `run`, `install`) are in `xmake/actions`.\n* **Modules**: Extension modules are in `xmake/modules`.\n* **Base API**: Utility scripts run in a base lua environment. Base API is in `xmake/core/base`.\n* **Native API**: The Lua API and Xmake extension API, written in C, are located in `core/src/xmake`.\n\nFor example, when you call `os.cp()` in `xmake.lua`:\n`sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox)\n\n## Financial contributions\n\nIf you want to contribute to Xmake but are unable to contribute code due to technical or time constraints, you can also support the further development of the community through [financial contributions](https://xmake.io/about/sponsor).\n\n# 贡献代码\n\n如果你发现一些问题，或者想新增或者改进某些新特性，或者想贡献一个新的模块\n那么你可以在[issues][1]上提交反馈，或者发起一个提交代码的请求(pull request).\n\n## 问题反馈\n\n* 确认这个问题没有被反馈过\n* 确认这个问题最近还没有被修复，请先检查下 `master` 的最新提交\n* 请清晰详细地描述你的问题\n* 请使用语法正确、完整的句子，开启一个带有描述性标题和摘要的 issue\n* 如果发现某些代码存在问题，请在issue上引用相关代码\n\n## 提交代码\n\n* 请先更新你的本地分支到最新，再进行提交代码请求，确保没有合并冲突\n* 如果需要，使用 topic 分支以便稍后轻松修改 pull request\n* 编写友好可读的提交信息\n* 请使用与工程代码相同的代码规范\n* 确保提交的代码缩进是四个空格，而不是tab\n* 请提交代码到`dev`分支，如果通过，我们会在特定时间合并到`master`分支上\n* 为了规范化提交日志的格式，commit消息，不要用中文，请用英文描述\n* 如果涉及公开的 API 改动，请先在 issues 中创建对应的 feature request ，然后详细描述下 新 API 的设计，并且需要经过赞同后，才能开始创建 pr 去添加和实现它们，而不是直接打开 pr 去随意添加修改新的 API\n\n## 开发指南\n\n### 源码编译\n\n1. 下载源码\n\n```bash\ngit clone --recursive https://github.com/xmake-io/xmake.git\ncd xmake\n```\n\n2. 编译\n\n* Linux/macOS\n\n```bash\n./configure\nmake\n```\n\n* Windows\n\n```bash\ncd core\nxmake\n```\n\n### 本地调试\n\n如果想要调试本地 xmake 源码，可以运行以下命令加载本地环境。\n\n* Linux/macOS\n\n```bash\nsource scripts/srcenv.profile\nxmake --version\n```\n\n* Windows\n\n直接运行 `scripts\\srcenv.bat`。\n\n加载环境后，我们就可以直接修改源码目录下的 Lua 脚本，然后运行 `xmake` 即可实时验证修改效果，无需重新安装。\n\n### 调试环境变量\n\n* `XMAKE_PROGRAM_DIR`: 指定 Xmake 的 Lua 脚本目录。将其设置为本地源码中的 `xmake` 目录（例如 `path/to/xmake/xmake`），可以让 Xmake 直接加载本地脚本。这样修改 Lua 脚本后无需重新编译安装即可生效，非常适合调试脚本逻辑。\n* `XMAKE_PROGRAM_FILE`: 指定 `xmake` 可执行文件的路径。确保使用指定的二进制文件运行，适用于多版本共存或测试本地编译生成的二进制文件。\n\n`source scripts/srcenv.profile` (或 `srcenv.bat`) 脚本会自动为你设置这些环境变量。\n\n### 运行测试\n\n使用以下命令运行测试（请确保本地环境已经加载）：\n\n```bash\nxmake l tests/run.lua [testname]\n```\n\n### 源码结构\n\nXmake 的源码主要分为两部分：C 核心和 Lua 脚本。\n\n* `core/`: C 核心实现，包括 Lua 运行时、跨平台抽象层和原生 API 实现。\n* `xmake/`: Lua 脚本实现，包含核心逻辑、模块、操作和平台支持。\n\n#### 架构设计\n\nXmake 采用关注点分离的设计，性能敏感的部分由 C 实现，而构建逻辑由 Lua 实现。\n\n* **沙盒 (Sandbox)**: 用户的 `xmake.lua` 和插件脚本运行在沙盒环境中，以确保安全性和隔离性。沙盒 API 定义在 `xmake/core/sandbox` 中。\n* **核心模块 (Core Modules)**: 核心 Lua 模块位于 `xmake/core`。\n* **操作 (Actions)**: 内置操作（如 `build`, `run`, `install`）位于 `xmake/actions`。\n* **模块 (Modules)**: 扩展模块位于 `xmake/modules`。\n* **基础 API (Base API)**: 工具脚本运行在基础 Lua 环境中。基础 API 位于 `xmake/core/base`。\n* **原生 API (Native API)**: 包含 Lua API 和 Xmake 扩展 API，用 C 编写，位于 `core/src/xmake`。\n\n例如，当你在 `xmake.lua` 中调用 `os.cp()` 时：\n`sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox)\n\n## 资金赞助\n\n如果您想要为 Xmake 做贡献，但受限于技术能力或时间无法参与代码开发，也可以通过[资金赞助](https://xmake.io/about/sponsor)来支持社区的进一步发展。\n\n[1]: https://github.com/xmake-io/xmake/issues\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2015-present Xmake Open Source Community\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "NOTICE.md",
    "content": "A cross-platform build utility based on Lua\nCopyright 2015-present, The Xmake Open Source Community\n\nThis product includes software developed by The Xmake Open Source Community (https://xmake.io/).\n\n-------------------------------------------------------------------------------\n\nThis product depends on 'lua-cjson', The Lua CJSON module provides JSON support for Lua,\nwhich can be obtained at:\n\n  * LICENSE:\n    * core/src/lua-cjson/lua-cjson/LICENSE (MIT License)\n  * HOMEPAGE:\n    * https://www.kyne.com.au/~mark/software/lua-cjson.php\n\nThis product depends on 'pdcurses', an implementation of X/Open curses for multiple platforms,\nwhich can be obtained at:\n\n  * LICENSE:\n    * Public Domain License\n  * HOMEPAGE:\n    * http://pdcurses.org/\n\nThis product depends on 'libsv', Public domain semantic versioning in c,\nwhich can be obtained at:\n\n  * LICENSE:\n    * core/src/sv/sv/UNLICENSE (Public Domain License)\n  * HOMEPAGE:\n    * https://github.com/uael/sv\n\nThis product depends on 'LuaJIT', a Just-In-Time Compiler for Lua,\nwhich can be obtained at:\n\n  * LICENSE:\n    * core/src/luajit/luajit/COPYRIGHT (MIT License)\n  * HOMEPAGE:\n    * http://luajit.org/\n\nThis product depends on 'Lua', The Lua Programming Language,\nwhich can be obtained at:\n\n  * LICENSE:\n    * https://www.lua.org/license.html (MIT License)\n  * HOMEPAGE:\n    * http://lua.org/\n\nThis product depends on 'lz4', Extremely Fast Compression algorithm,\nwhich can be obtained at:\n\n  * LICENSE:\n    * https://github.com/lz4/lz4/blob/dev/LICENSE\n  * HOMEPAGE:\n    * https://www.lz4.org/\n\nThis product depends on 'xxHash', Extremely fast non-cryptographic hash algorithm,\nwhich can be obtained at:\n\n  * LICENSE:\n    * https://github.com/Cyan4973/xxHash/blob/dev/LICENSE\n  * HOMEPAGE:\n    * https://www.xxhash.com/\n\nThis product depends on 'tbox', The Treasure Box Library,\nwhich can be obtained at:\n\n  * LICENSE:\n    * core/src/tbox/tbox/LICENSE.md (Apache License 2.0)\n  * HOMEPAGE:\n    * https://tboox.org/\n\n\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <a href=\"https://xmake.io\">\n    <img width=\"160\" height=\"160\" src=\"https://xmake.io/assets/img/logo.png\">\n  </a>\n\n  <h1>xmake</h1>\n\n  <div>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3AWindows\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/windows.yml?branch=master&style=flat-square&logo=windows\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3ALinux\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/linux.yml?branch=master&style=flat-square&logo=linux\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3AmacOS\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/macos.yml?branch=master&style=flat-square&logo=apple\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/releases\">\n      <img src=\"https://img.shields.io/github/release/xmake-io/xmake.svg?style=flat-square\" alt=\"Github All Releases\" />\n    </a>\n  </div>\n  <div>\n    <a href=\"https://github.com/xmake-io/xmake/blob/master/LICENSE.md\">\n      <img src=\"https://img.shields.io/github/license/xmake-io/xmake.svg?colorB=f48041&style=flat-square\" alt=\"license\" />\n    </a>\n    <a href=\"https://www.reddit.com/r/xmake/\">\n      <img src=\"https://img.shields.io/badge/chat-on%20reddit-ff3f34.svg?style=flat-square\" alt=\"Reddit\" />\n    </a>\n    <a href=\"https://t.me/tbooxorg\">\n      <img src=\"https://img.shields.io/badge/chat-on%20telegram-blue.svg?style=flat-square\" alt=\"Telegram\" />\n    </a>\n    <a href=\"https://jq.qq.com/?_wv=1027&k=5hpwWFv\">\n      <img src=\"https://img.shields.io/badge/chat-on%20QQ-ff69b4.svg?style=flat-square\" alt=\"QQ\" />\n    </a>\n    <a href=\"https://discord.gg/xmake\">\n      <img src=\"https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square\" alt=\"Discord\" />\n    </a>\n    <a href=\"https://xmake.io/about/sponsor.html\">\n      <img src=\"https://img.shields.io/badge/donate-us-orange.svg?style=flat-square\" alt=\"Donate\" />\n    </a>\n  </div>\n\n  <b>A cross-platform build utility based on Lua</b><br/>\n  <i>Modern C/C++ build tool: Simple, Fast, Powerful dependency package integration</i><br/>\n</div>\n\n## Support this project\n\nSupport this project by [becoming a sponsor](https://xmake.io/about/sponsor.html). Your logo will show up here with a link to your website. 🙏\n\n## Introduction ([中文](/README_zh.md))\n\nWhat is Xmake?\n\n1. Xmake is a cross-platform build utility based on the Lua scripting language.\n2. Xmake is very lightweight and has no dependencies outside of the standard library.\n3. Uses the `xmake.lua` file to maintain project builds with a simple and readable syntax.\n\nXmake can be used to directly build source code (like with Make or Ninja), or it can generate project source files like CMake or Meson. It also has a *built-in* package management system to help users integrate C/C++ dependencies.\n\n```\nXmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache\n```\n\nAlthough less precise, one can still understand Xmake in the following way:\n\n```\nXmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache\n```\n\nIf you want to know more, please refer to the [Documentation](https://xmake.io/guide/quick-start), [GitHub](https://github.com/xmake-io/xmake) or [Gitee](https://gitee.com/tboox/xmake). You are also welcome to join our [community](https://xmake.io/about/contact).\n\nThe official Xmake repository can be found at [xmake-io/xmake-repo](https://github.com/xmake-io/xmake-repo).\n\n![](https://github.com/xmake-io/xmake-docs/raw/master/docs/public/assets/img/index/xmake-basic-render.gif)\n\n## Installation\n\n### With cURL\n\n```bash\ncurl -fsSL https://xmake.io/shget.text | bash\n```\n\n### With Wget\n\n```bash\nwget https://xmake.io/shget.text -O - | bash\n```\n\n### With PowerShell\n\n```sh\nirm https://xmake.io/psget.text | iex\n```\n\n### Other installation methods\n\nIf you don't want to use the above scripts to install Xmake, visit the [Installation Guide](https://xmake.io/guide/quick-start.html#installation) for other installation methods (building from source, package managers, etc.).\n\n## Simple Project Description\n\n```lua\ntarget(\"console\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n```\n\nCreates a new target `console` of kind `binary`, and adds all the files ending in `.c` in the `src` directory.\n\n## Package dependencies\n\n```lua\nadd_requires(\"tbox 1.6.*\", \"zlib\", \"libpng ~1.6\")\n```\n\nAdds a requirement of tbox v1.6, zlib (any version), and libpng v1.6.\n\nThe official xmake package repository exists at: [xmake-repo](https://github.com/xmake-io/xmake-repo)\n\n<p align=\"center\">\n<img src=\"https://github.com/xmake-io/xmake-docs/raw/master/assets/img/index/package.gif\" width=\"650px\" />\n</p>\n\n## Command line interface reference\n\nThe below assumes you are currently in the project's root directory.\n\n### Build a project\n\n```bash\n$ xmake\n```\n\n### Run target\n\n```bash\n$ xmake run console\n```\n\n### Debug target\n\n```bash\n$ xmake run -d console\n```\n\n### Run test\n\n```bash\n$ xmake test\n```\n\n### Configure platform\n\n```bash\n$ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release]\n$ xmake\n```\n\n### Menu configuration\n\n```bash\n$ xmake f --menu\n```\n\n<p align=\"center\">\n<img src=\"https://xmake.io/assets/img/index/menuconf.png\" width=\"650px\"/>\n</p>\n\n## Supported platforms\n\n* Windows (x86, x64, arm, arm64, arm64ec)\n* macOS (i386, x86_64, arm64)\n* Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...)\n* FreeBSD (i386, x86_64)\n* NetBSD (i386, x86_64)\n* OpenBSD (i386, x86_64)\n* DragonflyBSD (i386, x86_64)\n* Solaris (i386, x86_64)\n* Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a)\n* iOS (armv7, armv7s, arm64, i386, x86_64)\n* WatchOS (armv7k, i386)\n* AppleTVOS (armv7, arm64, i386, x86_64)\n* AppleXROS (arm64, x86_64)\n* MSYS (i386, x86_64)\n* MinGW (i386, x86_64, arm, arm64)\n* Cygwin (i386, x86_64)\n* Wasm (wasm32, wasm64)\n* Haiku (i386, x86_64)\n* Harmony (x86_64, armeabi-v7a, arm64-v8a)\n* Cross (cross-toolchains ..)\n\n## Supported toolchains\n\n```bash\n$ xmake show -l toolchains\nxcode         Xcode IDE\nmsvc          Microsoft Visual C/C++ Compiler\nclang-cl      LLVM Clang C/C++ Compiler compatible with msvc\nyasm          The Yasm Modular Assembler\nclang         A C language family frontend for LLVM\ngo            Go Programming Language Compiler\ndlang         D Programming Language Compiler (Auto)\ndmd           D Programming Language Compiler\nldc           The LLVM-based D Compiler\ngdc           The GNU D Compiler (GDC)\ngfortran      GNU Fortran Programming Language Compiler\nflang         LLVM Fortran Compiler\nzig           Zig Programming Language Compiler\nzigcc         Use zig cc/c++ as C/C++ Compiler\nsdcc          Small Device C Compiler\ncuda          CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)\nndk           Android NDK\nrust          Rust Programming Language Compiler\nswift         Swift Programming Language Compiler\nllvm          A collection of modular and reusable compiler and toolchain technologies\ncross         Common cross compilation toolchain\nnasm          NASM Assembler\ngcc           GNU Compiler Collection\nmingw         Minimalist GNU for Windows\ngnu-rm        GNU Arm Embedded Toolchain\nenvs          Environment variables toolchain\nfasm          Flat Assembler\ntinycc        Tiny C Compiler\nemcc          A toolchain for compiling to asm.js and WebAssembly\nicc           Intel C/C++ Compiler\nifort         Intel Fortran Compiler\nifx           Intel LLVM Fortran Compiler\nmuslcc        The musl-based cross-compilation toolchain\nfpc           Free Pascal Programming Language Compiler\nwasi          WASI-enabled WebAssembly C/C++ toolchain\nnim           Nim Programming Language Compiler\ndotnet        .NET SDK Toolchain\ncircle        A new C++20 compiler\narmcc         ARM Compiler Version 5 of Keil MDK\narmclang      ARM Compiler Version 6 of Keil MDK\nc51           Keil development tools for the 8051 Microcontroller Architecture\nicx           Intel LLVM C/C++ Compiler\ndpcpp         Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL\nmasm32        The MASM32 SDK\niverilog      Icarus Verilog\nverilator     Verilator open-source SystemVerilog simulator and lint system\ncosmocc       build-once run-anywhere\nhdk           Harmony SDK\nti-c2000      TI-CGT C2000 compiler\nti-c6000      TI-CGT C6000 compiler\niararm        IAR ARM C/C++ Compiler\nkotlin-native Kotlin Native Programming Language Compiler\n```\n\n## Supported languages\n\n* C and C++\n* Objective-C and Objective-C++\n* Swift\n* Assembly\n* Golang\n* Rust\n* Dlang\n* Fortran\n* Cuda\n* Zig\n* Vala\n* Pascal\n* Nim\n* Verilog\n* FASM\n* NASM\n* YASM\n* MASM32\n* Cppfront\n* Kotlin\n* C#\n\n## Features\n\nXmake exhibits:\n\n* Simple yet flexible configuration grammar.\n* Quick, dependency-free installation.\n* Easy compilation for most all supported platforms.\n* Supports cross-compilation with intelligent analysis of cross toolchain information.\n* Extremely fast parallel compilation support.\n* Supports C++ modules (new in C++20).\n* Supports cross-platform C/C++ dependencies with built-in package manager.\n* Multi-language compilation support including mixed-language projects.\n* Rich plug-in support with various project generators (ex. Visual Studio/Makefiles/CMake/`compile_commands.json`)\n* REPL interactive execution support\n* Incremental compilation support with automatic analysis of header files\n* Built-in toolchain management\n* A large number of expansion modules\n* Remote compilation support\n* Distributed compilation support\n* Local and remote build cache support\n\n## Supported Project Types\n\nXmake supports the below types of projects:\n\n* Static libraries\n* Shared libraries\n* Console/CLI applications\n* CUDA programs\n* Qt applications\n* WDK drivers (umdf/kmdf/wdm)\n* WinSDK applications\n* MFC applications\n* Darwin applications (with metal support)\n* Frameworks and bundles (in Darwin)\n* SWIG modules (Lua, Python, ...)\n* LuaRocks modules\n* Protobuf programs\n* Lex/Yacc programs\n* Linux kernel modules\n\n## Package management\n\n### Download and build\n\nXmake can automatically fetch and install dependencies!\n\n<p align=\"center\">\n<img src=\"https://xmake.io/assets/img/index/package_manage.png\" width=\"650px\" />\n</p>\n\n### Supported package repositories\n\n* Official package repository [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1)\n* Official package manager [Xrepo](https://github.com/xmake-io/xrepo)\n* [User-built repositories](https://xmake.io/guide/package-management/using-official-packages.html#using-self-built-private-package-repository)\n* Conan (conan::openssl/1.1.1g)\n* Conda (conda::libpng 1.3.67)\n* Vcpkg (vcpkg:ffmpeg)\n* Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)\n* Pacman on archlinux/msys2 (pacman::libcurl)\n* Apt on ubuntu/debian (apt::zlib1g-dev)\n* Clib (clib::clibs/bytes@0.0.4)\n* Dub (dub::log 0.4.3)\n* Portage on Gentoo/Linux (portage::libhandy)\n* Nimble for nimlang (nimble::zip >1.3)\n* Cargo for rust (cargo::base64 0.13.0)\n* Zypper on openSUSE (zypper::libsfml2 2.5)\n\n### Package management features\n\n* The official repository provides nearly 500+ packages with simple compilation on all supported platforms\n* Full platform package support, support for cross-compiled dependent packages\n* Support package virtual environment using `xrepo env shell`\n* Precompiled package acceleration for Windows (NT)\n* Support self-built package repositories and private repository deployment\n* Third-party package repository support for repositories such as: vcpkg, conan, conda, etc.\n* Supports automatic pulling of remote toolchains\n* Supports dependency version locking\n\n## Processing architecture\n\nBelow is a diagram showing roughly the architecture of Xmake, and thus how it functions.\n\n<p align=\"center\">\n<img src=\"https://xmake.io/assets/img/index/package_arch.png\" width=\"650px\" />\n</p>\n\n## Distributed Compilation\n\n- [X] Cross-platform support.\n- [X] Support for MSVC, Clang, GCC and other cross-compilation toolchains.\n- [X] Support for building for Android, Linux, Windows NT, and Darwin hosts.\n- [X] No dependencies other than the compilation toolchain.\n- [X] Support for build server load balancing scheduling.\n- [X] Support for real time compressed transfer of large files (lz4).\n- [X] Almost zero configuration cost, no shared filesystem required, for convenience and security.\n\nFor more details see: [Distributed Compilation](https://xmake.io/guide/extras/distributed-compilation.html)\n\n## Remote Compilation\n\nFor more details see: [Remote Compilation](https://xmake.io/guide/extras/remote-compilation.html)\n\n## Local/Remote Build Cache\n\nFor more details see: [Build Cache Acceleration](https://xmake.io/guide/extras/build-cache.html)\n\n## Benchmark\n\nXmake's speed on is par with Ninja! The test project: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core)\n\n### Multi-task parallel compilation\n\n\n| buildsystem      | Termux (8core/-j12) | buildsystem      | MacOS (8core/-j12) |\n| ------------------ | --------------------- | ------------------ | -------------------- |\n| xmake            | 24.890s             | xmake            | 12.264s            |\n| ninja            | 25.682s             | ninja            | 11.327s            |\n| cmake(gen+make)  | 5.416s+28.473s      | cmake(gen+make)  | 1.203s+14.030s     |\n| cmake(gen+ninja) | 4.458s+24.842s      | cmake(gen+ninja) | 0.988s+11.644s     |\n\n## Single task compilation\n\n\n| buildsystem      | Termux (-j1)     | buildsystem      | MacOS (-j1)    |\n| ------------------ | ------------------ | ------------------ | ---------------- |\n| xmake            | 1m57.707s        | xmake            | 39.937s        |\n| ninja            | 1m52.845s        | ninja            | 38.995s        |\n| cmake(gen+make)  | 5.416s+2m10.539s | cmake(gen+make)  | 1.203s+41.737s |\n| cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s |\n\n## More Examples\n\n### Debug and release profiles\n\n```lua\nadd_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"console\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    if is_mode(\"debug\") then\n        add_defines(\"DEBUG\")\n    end\n```\n\n### Custom scripts\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    after_build(function (target)\n        print(\"hello: %s\", target:name())\n        os.exec(\"echo %s\", target:targetfile())\n    end)\n```\n\n### Automatic integration of dependent packages\n\nDownload and use packages in [xmake-repo](https://github.com/xmake-io/xmake-repo) or third-party repositories:\n\n```lua\nadd_requires(\"tbox >1.6.1\", \"libuv master\", \"vcpkg::ffmpeg\", \"brew::pcre2/libpcre2-8\")\nadd_requires(\"conan::openssl/1.1.1g\", {alias = \"openssl\", optional = true, debug = true})\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"tbox\", \"libuv\", \"vcpkg::ffmpeg\", \"brew::pcre2/libpcre2-8\", \"openssl\")\n```\n\nIn addition, we can also use the [xrepo](https://github.com/xmake-io/xrepo) command to quickly install dependencies.\n\n### Qt QuickApp Program\n\n```lua\ntarget(\"test\")\n    add_rules(\"qt.quickapp\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n```\n\n### Cuda Program\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cu\")\n    add_cugencodes(\"native\")\n    add_cugencodes(\"compute_75\")\n```\n\n### WDK/UMDF Driver Program\n\n```lua\ntarget(\"echo\")\n    add_rules(\"wdk.driver\", \"wdk.env.umdf\")\n    add_files(\"driver/*.c\")\n    add_files(\"driver/*.inx\")\n    add_includedirs(\"exe\")\n\ntarget(\"app\")\n    add_rules(\"wdk.binary\", \"wdk.env.umdf\")\n    add_files(\"exe/*.cpp\")\n```\n\nFor more WDK driver examples (UMDF/KMDF/WDM), please visit [WDK Program Examples](https://xmake.io/examples/cpp/wdk.html)\n\n### Darwin Applications\n\n```lua\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n```\n\n### Framework and Bundle Program (Darwin)\n\n```lua\ntarget(\"test\")\n    add_rules(\"xcode.framework\") -- or xcode.bundle\n    add_files(\"src/*.m\")\n    add_files(\"src/Info.plist\")\n```\n\n### OpenMP Program\n\n```lua\nadd_requires(\"libomp\", {optional = true})\ntarget(\"loop\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_rules(\"c++.openmp\")\n    add_packages(\"libomp\")\n```\n\n### Zig Program\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.zig\")\n```\n\n### Automatically fetch remote toolchain\n\n#### fetch a special version of LLVM\n\nRequire the Clang version packaged with LLM-10 to compile a project.\n\n```lua\nadd_requires(\"llvm 10.x\", {alias = \"llvm-10\"})\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"llvm@llvm-10\")\n```\n\n#### Fetch a cross-compilation toolchain\n\nWe can also pull a specified cross-compilation toolchain in to compile the project.\n\n```lua\nadd_requires(\"muslcc\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@muslcc\")\n```\n\n#### Fetch toolchain and packages\n\nWe can also use the specified `muslcc` cross-compilation toolchain to compile and integrate all dependent packages.\n\n```lua\nadd_requires(\"muslcc\")\nadd_requires(\"zlib\", \"libogg\", {system = false})\n\nset_toolchains(\"@muslcc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\", \"libogg\")\n```\n\n## Plugins\n\n#### Generate IDE project file plugin（makefile, vs2002 - vs2026 .. ）\n\n```bash\n$ xmake project -k vsxmake -m \"debug,release\" # New vsproj generator (Recommended)\n$ xmake project -k vs -m \"debug,release\"\n$ xmake project -k cmake\n$ xmake project -k ninja\n$ xmake project -k compile_commands\n```\n\n#### Run a custom lua script plugin\n\n```bash\n$ xmake l ./test.lua\n$ xmake l -c \"print('hello xmake!')\"\n$ xmake l lib.detect.find_tool gcc\n$ xmake l\n> print(\"hello xmake!\")\n> {1, 2, 3}\n< {\n    1,\n    2,\n    3\n  }\n```\n\nTo see a list of builtin plugins, please visit [Builtin plugins](https://xmake.io/guide/extensions/builtin-plugins.html).\n\nPlease download and install other plugins from the plugins repository [xmake-plugins](https://github.com/xmake-io/xmake-plugins).\n\n## IDE/Editor Integration\n\n* [xmake-vscode](https://github.com/xmake-io/xmake-vscode)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-vscode/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-sublime](https://github.com/xmake-io/xmake-sublime)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-sublime/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-idea](https://github.com/xmake-io/xmake-idea)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-idea/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai))\n* [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon))\n* [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886))\n* [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz))\n\n### Xmake Gradle Plugin (JNI)\n\nWe can use the [xmake-gradle](https://github.com/xmake-io/xmake-gradle) plugin to compile JNI libraries via gradle.\n\n```\nplugins {\n  id 'org.tboox.gradle-xmake-plugin' version '1.1.5'\n}\n\nandroid {\n    externalNativeBuild {\n        xmake {\n            path \"jni/xmake.lua\"\n        }\n    }\n}\n```\n\nThe `xmakeBuild` task will be injected into the `assemble` task automatically if the `gradle-xmake-plugin` has been applied.\n\n```console\n$ ./gradlew app:assembleDebug\n> Task :nativelib:xmakeConfigureForArm64\n> Task :nativelib:xmakeBuildForArm64\n>> xmake build\n[ 50%]: cache compiling.debug nativelib.cc\n[ 75%]: linking.debug libnativelib.so\n[100%]: build ok!\n>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a\n> Task :nativelib:xmakeConfigureForArmv7\n> Task :nativelib:xmakeBuildForArmv7\n>> xmake build\n[ 50%]: cache compiling.debug nativelib.cc\n[ 75%]: linking.debug libnativelib.so\n[100%]: build ok!\n>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a\n> Task :nativelib:preBuild\n> Task :nativelib:assemble\n> Task :app:assembleDebug\n```\n\n## CI Integration\n\n### GitHub Action\n\nThe [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) plugin for GitHub Actions can allow you to use Xmake with minimal efforts if you use GitHub Actions for your CI pipeline.\n\n```yaml\nuses: xmake-io/github-action-setup-xmake@v1\nwith:\n  xmake-version: latest\n```\n\n## Who is using Xmake?\n\nThe list of people and projects who are using Xmake is available [here](https://xmake.io/about/who_is_using_xmake.html).\n\nIf you are using Xmake, you are welcome to submit your information to the above list through a PR, so that other users and the developers can gauge interest.  This also lets users use xmake more confidently and gives us motivation to continue to maintain it.\n\nThis will help the Xmake project and it's community grow stronger and expand!\n\n## Contacts\n\n* Email：[waruqi@gmail.com](mailto:waruqi@gmail.com)\n* Homepage：[xmake.io](https://xmake.io)\n* Community\n  - [Chat on Reddit](https://www.reddit.com/r/xmake/)\n  - [Chat on Telegram](https://t.me/tbooxorg)\n  - [Chat on Discord](https://discord.gg/xmake)\n  - Chat on QQ Group: 343118190, 662147501\n* Source Code：[GitHub](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake)\n* WeChat Public: tboox-os\n\n## Thanks\n\nThis project exists thanks to all the people who have [contributed](CONTRIBUTING.md):\n<a href=\"https://github.com/xmake-io/xmake/graphs/contributors\"><img src=\"https://opencollective.com/xmake/contributors.svg?width=890&button=false\" /></a>\n\n* [TitanSnow](https://github.com/TitanSnow): Provide the xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) and install scripts\n* [uael](https://github.com/uael): Provide the semantic versioning library [sv](https://github.com/uael/sv)\n* [OpportunityLiu](https://github.com/OpportunityLiu): Improve cuda, tests and ci\n* [xq144](https://github.com/xq114): Improve `xrepo env shell`, and contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository.\n* [star-hengxing](https://github.com/star-hengxing): Contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository.\n* [Arthapz](https://github.com/Arthapz): Contribute new C++ Modules implementation.\n* [SirLynix](https://github.com/SirLynix): Contributed many packages and let more people know about xmake.\n* `enderger`: Helped smooth out the edges on the English translation of the README\n\n### Powered by\n\n[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource)\n"
  },
  {
    "path": "README_zh.md",
    "content": "<div align=\"center\">\n  <a href=\"https://xmake.io/zh\">\n    <img width=\"160\" height=\"160\" src=\"https://xmake.io/assets/img/logo.png\">\n  </a>\n\n  <h1>xmake</h1>\n\n  <div>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3AWindows\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/windows.yml?branch=master&style=flat-square&logo=windows\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3ALinux\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/linux.yml?branch=master&style=flat-square&logo=linux\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/actions?query=workflow%3AmacOS\">\n      <img src=\"https://img.shields.io/github/actions/workflow/status/xmake-io/xmake/macos.yml?branch=master&style=flat-square&logo=apple\" alt=\"github-ci\" />\n    </a>\n    <a href=\"https://github.com/xmake-io/xmake/releases\">\n      <img src=\"https://img.shields.io/github/release/xmake-io/xmake.svg?style=flat-square\" alt=\"Github All Releases\" />\n    </a>\n  </div>\n  <div>\n    <a href=\"https://github.com/xmake-io/xmake/blob/master/LICENSE.md\">\n      <img src=\"https://img.shields.io/github/license/xmake-io/xmake.svg?colorB=f48041&style=flat-square\" alt=\"license\" />\n    </a>\n    <a href=\"https://www.reddit.com/r/xmake/\">\n      <img src=\"https://img.shields.io/badge/chat-on%20reddit-ff3f34.svg?style=flat-square\" alt=\"Reddit\" />\n    </a>\n    <a href=\"https://t.me/tbooxorg\">\n      <img src=\"https://img.shields.io/badge/chat-on%20telegram-blue.svg?style=flat-square\" alt=\"Telegram\" />\n    </a>\n    <a href=\"https://jq.qq.com/?_wv=1027&k=5hpwWFv\">\n      <img src=\"https://img.shields.io/badge/chat-on%20QQ-ff69b4.svg?style=flat-square\" alt=\"QQ\" />\n    </a>\n    <a href=\"https://discord.gg/xmake\">\n      <img src=\"https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square\" alt=\"Discord\" />\n    </a>\n    <a href=\"https://xmake.io/zh/about/sponsor.html\">\n      <img src=\"https://img.shields.io/badge/donate-us-orange.svg?style=flat-square\" alt=\"Donate\" />\n    </a>\n  </div>\n\n  <b>A cross-platform build utility based on Lua</b><br/>\n  <i>Modern C/C++ build tools, Simple, Fast, Powerful dependency package integration</i><br/>\n</div>\n\n## 项目支持\n\n通过[成为赞助者](https://xmake.io/zh/about/sponsor.html)来支持该项目。您的logo将显示在此处，并带有指向您网站的链接。🙏\n\n## 简介\n\nXmake 是一个基于 Lua 的轻量级跨平台构建工具。\n\n它非常的轻量，没有任何依赖，因为它内置了 Lua 运行时。\n\n它使用 xmake.lua 维护项目构建，相比 makefile/CMakeLists.txt，配置语法更加简洁直观，对新手非常友好，短时间内就能快速入门，能够让用户把更多的精力集中在实际的项目开发上。\n\n我们能够使用它像 Make/Ninja 那样可以直接编译项目，也可以像 CMake/Meson 那样生成工程文件，另外它还有内置的包管理系统来帮助用户解决 C/C++ 依赖库的集成使用问题。\n\n目前，Xmake 主要用于 C/C++ 项目的构建，但是同时也支持其他 native 语言的构建，可以实现跟 C/C++ 进行混合编译，同时编译速度也是非常的快，可以跟 Ninja 持平。\n\n```\nXmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache\n```\n\n尽管不是很准确，但我们还是可以把 Xmake 按下面的方式来理解：\n\n```\nXmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache\n```\n\n\n如果你想要了解更多，请参考：[在线文档](https://xmake.io/zh/guide/quick-start.html), [Github](https://github.com/xmake-io/xmake)以及[Gitee](https://gitee.com/tboox/xmake) 和 [GitCode](https://gitcode.com/xmake-io/xmake)，同时也欢迎加入我们的 [社区](https://xmake.io/zh/about/contact)。\n\n![](https://github.com/xmake-io/xmake-docs/raw/master/docs/public/assets/img/index/xmake-basic-render.gif)\n\n## 课程\n\nxmake 官方也推出了一些入门课程，带你一步步快速上手 xmake，课程列表如下：\n\n* [Xmake 带你轻松构建 C/C++ 项目](https://xmake.io/zh/about/course)\n\n## 安装\n\n#### 使用curl\n\n```bash\ncurl -fsSL https://xmake.io/shget.text | bash\n```\n\n#### 使用wget\n\n```bash\nwget https://xmake.io/shget.text -O - | bash\n```\n\n#### 使用powershell\n\n```powershell\nirm https://xmake.io/psget.text | iex\n```\n\n#### 其他安装方式\n\n如果不想使用脚本安装，也可以点击查看 [安装文档](https://xmake.io/zh/guide/quick-start.html#installation)，了解其他安装方法。\n\n## 简单的工程描述\n\n```lua\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n```\n\n## 包依赖描述\n\n```lua\nadd_requires(\"tbox 1.6.*\", \"zlib\", \"libpng ~1.6\")\n```\n\n官方的xmake包管理仓库: [xmake-repo](https://github.com/xmake-io/xmake-repo)\n\n<img src=\"https://github.com/xmake-io/xmake-docs/raw/master/assets/img/index/package.gif\" width=\"650px\" />\n\n## 命令行使用\n\n### 创建工程\n\n```bash\n$ xmake create hello\n$ cd hello\n```\n\n### 构建工程\n\n```bash\n$ xmake\n```\n\n### 运行目标\n\n```bash\n$ xmake run console\n```\n\n### 调试程序\n\n```bash\n$ xmake run -d console\n```\n\n### 运行测试\n\n```bash\n$ xmake test\n```\n\n### 配置平台\n\n```bash\n$ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release]\n$ xmake\n```\n\n### 图形化菜单配置\n\n```bash\n$ xmake f --menu\n```\n\n<img src=\"https://xmake.io/assets/img/index/menuconf.png\" width=\"650px\" />\n\n## 跟ninja一样快的构建速度\n\n测试工程: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core)\n\n### 多任务并行编译测试\n\n| 构建系统        | Termux (8core/-j12) | 构建系统         | MacOS (8core/-j12) |\n|-----            | ----                | ---              | ---                |\n|xmake            | 24.890s             | xmake            | 12.264s            |\n|ninja            | 25.682s             | ninja            | 11.327s            |\n|cmake(gen+make)  | 5.416s+28.473s      | cmake(gen+make)  | 1.203s+14.030s     |\n|cmake(gen+ninja) | 4.458s+24.842s      | cmake(gen+ninja) | 0.988s+11.644s     |\n\n### 单任务编译测试\n\n| 构建系统        | Termux (-j1)     | 构建系统         | MacOS (-j1)    |\n|-----            | ----             | ---              | ---            |\n|xmake            | 1m57.707s        | xmake            | 39.937s        |\n|ninja            | 1m52.845s        | ninja            | 38.995s        |\n|cmake(gen+make)  | 5.416s+2m10.539s | cmake(gen+make)  | 1.203s+41.737s |\n|cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s |\n\n\n## 包依赖管理\n\n### 架构和流程\n\n<img src=\"https://xmake.io/assets/img/index/package_arch.png\" width=\"650px\" />\n\n### 支持的包管理仓库\n\n* 官方自建仓库 [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1)\n* 官方包管理器 [Xrepo](https://github.com/xmake-io/xrepo)\n* [用户自建仓库](https://xmake.io/package/remote_package?id=using-self-built-private-package-repository)\n* Conan (conan::openssl/1.1.1g)\n* Conda (conda::libpng 1.3.67)\n* Vcpkg (vcpkg::ffmpeg)\n* Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)\n* Pacman on archlinux/msys2 (pacman::libcurl)\n* Apt on ubuntu/debian (apt::zlib1g-dev)\n* Clib (clib::clibs/bytes@0.0.4)\n* Dub (dub::log 0.4.3)\n* Portage on Gentoo/Linux (portage::libhandy)\n* Nimble for nimlang (nimble::zip >1.3)\n* Cargo for rust (cargo::base64 0.13.0)\n\n### 包管理特性\n\n* 官方仓库提供近 800+ 常用包，真正做到全平台一键下载集成编译\n* 全平台包支持，支持交叉编译的依赖包集成\n* 支持包虚拟环境管理和加载，`xrepo env shell`\n* Windows 云端预编译包加速\n* 支持自建包仓库，私有仓库部署\n* 第三方包仓库支持，提供更加丰富的包源，例如：vcpkg, conan, conda 等等\n* 支持自动拉取使用云端工具链\n* 支持包依赖锁定\n\n## 支持平台\n\n* Windows (x86, x64, arm, arm64, arm64ec)\n* macOS (i386, x86_64, arm64)\n* Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...)\n* FreeBSD (i386, x86_64)\n* NetBSD (i386, x86_64)\n* OpenBSD (i386, x86_64)\n* DragonflyBSD (i386, x86_64)\n* Solaris (i386, x86_64)\n* Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a)\n* iOS (armv7, armv7s, arm64, i386, x86_64)\n* WatchOS (armv7k, i386)\n* AppleTVOS (armv7, arm64, i386, x86_64)\n* AppleXROS (arm64, x86_64)\n* MSYS (i386, x86_64)\n* MinGW (i386, x86_64, arm, arm64)\n* Cygwin (i386, x86_64)\n* Wasm (wasm32, wasm64)\n* Haiku (i386, x86_64)\n* Harmony (x86_64, armeabi-v7a, arm64-v8a)\n* Cross (cross-toolchains ..)\n\n## 支持工具链\n\n```bash\n$ xmake show -l toolchains\nxcode         Xcode IDE\nmsvc          Microsoft Visual C/C++ Compiler\nclang-cl      LLVM Clang C/C++ Compiler compatible with msvc\nyasm          The Yasm Modular Assembler\nclang         A C language family frontend for LLVM\ngo            Go Programming Language Compiler\ndlang         D Programming Language Compiler (Auto)\ndmd           D Programming Language Compiler\nldc           The LLVM-based D Compiler\ngdc           The GNU D Compiler (GDC)\ngfortran      GNU Fortran Programming Language Compiler\nflang         LLVM Fortran Compiler\nzig           Zig Programming Language Compiler\nzigcc         Use zig cc/c++ as C/C++ Compiler\nsdcc          Small Device C Compiler\ncuda          CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)\nndk           Android NDK\nrust          Rust Programming Language Compiler\nswift         Swift Programming Language Compiler\nllvm          A collection of modular and reusable compiler and toolchain technologies\ncross         Common cross compilation toolchain\nnasm          NASM Assembler\ngcc           GNU Compiler Collection\nmingw         Minimalist GNU for Windows\ngnu-rm        GNU Arm Embedded Toolchain\nenvs          Environment variables toolchain\nfasm          Flat Assembler\ntinycc        Tiny C Compiler\nemcc          A toolchain for compiling to asm.js and WebAssembly\nicc           Intel C/C++ Compiler\nifort         Intel Fortran Compiler\nifx           Intel LLVM Fortran Compiler\nmuslcc        The musl-based cross-compilation toolchain\nfpc           Free Pascal Programming Language Compiler\nwasi          WASI-enabled WebAssembly C/C++ toolchain\nnim           Nim Programming Language Compiler\ndotnet        .NET SDK Toolchain\ncircle        A new C++20 compiler\narmcc         ARM Compiler Version 5 of Keil MDK\narmclang      ARM Compiler Version 6 of Keil MDK\nc51           Keil development tools for the 8051 Microcontroller Architecture\nicx           Intel LLVM C/C++ Compiler\ndpcpp         Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL\nmasm32        The MASM32 SDK\niverilog      Icarus Verilog\nverilator     Verilator open-source SystemVerilog simulator and lint system\ncosmocc       build-once run-anywhere\nhdk           Harmony SDK\nti-c2000      TI-CGT C2000 compiler\nti-c6000      TI-CGT C6000 compiler\niararm        IAR ARM C/C++ Compiler\nkotlin-native Kotlin Native Programming Language Compiler\n```\n\n## 支持语言\n\n* C/C++\n* Objc/Objc++\n* Swift\n* Assembly\n* Golang\n* Rust\n* Dlang\n* Fortran\n* Cuda\n* Zig\n* Vala\n* Pascal\n* Nim\n* Verilog\n* FASM\n* NASM\n* YASM\n* MASM32\n* Cppfront\n* Kotlin\n* C#\n\n## 支持特性\n\n* 语法简单易上手\n* 快速安装，无任何依赖\n* 全平台一键编译\n* 支持交叉编译，智能分析交叉工具链信息\n* 极速，多任务并行编译支持\n* C++20 Module 支持\n* 支持跨平台的 C/C++ 依赖包快速集成，内置包管理器\n* 多语言混合编译支持\n* 丰富的插件支持，提供各种工程生成器，例如：vs/makefile/cmakelists/compile_commands 生成插件\n* REPL 交互式执行支持\n* 增量编译支持，头文件依赖自动分析\n* 工具链的快速切换、定制化支持\n* 丰富的扩展模块支持\n* 远程编译支持\n* 分布式编译支持\n* 内置的本地和远程编译缓存支持\n\n## 工程类型\n\n* 静态库程序\n* 动态库类型\n* 控制台程序\n* Cuda 程序\n* Qt 应用程序\n* WDK Windows 驱动程序\n* WinSDK 应用程序\n* MFC 应用程序\n* iOS/MacOS 应用程序（支持.metal）\n* Framework和Bundle程序（iOS/MacOS）\n* SWIG/Pybind11 模块 (Lua, python, ...)\n* Luarocks 模块\n* Protobuf 程序\n* Lex/yacc 程序\n* C++20 模块\n* Linux 内核驱动模块\n* Keil MDK/C51 嵌入式程序\n* Verilog 仿真程序\n\n## 分布式编译和缓存\n\n- [x] 跨平台支持\n- [x] 支持 msvc, clang, gcc 和交叉编译工具链\n- [x] 支持构建 android, ios, linux, win, macOS 程序\n- [x] 除了编译工具链，无任何其他依赖\n- [x] 支持编译服务器负载均衡调度\n- [x] 支持大文件实时压缩传输 (lz4)\n- [x] 几乎零配置成本，无需共享文件系统，更加方便和安全\n\n关于分布式编译和缓存，可以见下面的文档。\n\n- [分布式编译](https://xmake.io/zh/guide/extras/distributed-compilation.html)\n- [编译缓存](https://xmake.io/zh/guide/extras/build-cache.html)\n\n## 远程编译\n\n更多详情见：[远程编译](https://xmake.io/zh/guide/extras/remote-compilation.html)\n\n## 更多例子\n\n#### Debug 和 Release 模式\n\n```lua\nadd_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"console\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    if is_mode(\"debug\") then\n        add_defines(\"DEBUG\")\n    end\n```\n\n#### 自定义脚本\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    after_build(function (target)\n        print(\"hello: %s\", target:name())\n        os.exec(\"echo %s\", target:targetfile())\n    end)\n```\n\n#### 依赖包自动集成\n\n下载和使用在 [xmake-repo](https://github.com/xmake-io/xmake-repo) 和第三方包仓库的依赖包：\n\n```lua\nadd_requires(\"tbox >1.6.1\", \"libuv master\", \"vcpkg::ffmpeg\", \"brew::pcre2/libpcre2-8\")\nadd_requires(\"conan::openssl/1.1.1g\", {alias = \"openssl\", optional = true, debug = true})\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"tbox\", \"libuv\", \"vcpkg::ffmpeg\", \"brew::pcre2/libpcre2-8\", \"openssl\")\n```\n\n另外，我们也可以使用 [xrepo](https://github.com/xmake-io/xrepo) 命令来快速安装依赖包。\n\n#### Qt QuickApp 应用程序\n\n```lua\ntarget(\"test\")\n    add_rules(\"qt.quickapp\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n```\n\n#### Cuda 程序\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cu\")\n    add_cugencodes(\"native\")\n    add_cugencodes(\"compute_75\")\n```\n\n#### WDK/UMDF 驱动程序\n\n```lua\ntarget(\"echo\")\n    add_rules(\"wdk.driver\", \"wdk.env.umdf\")\n    add_files(\"driver/*.c\")\n    add_files(\"driver/*.inx\")\n    add_includedirs(\"exe\")\n\ntarget(\"app\")\n    add_rules(\"wdk.binary\", \"wdk.env.umdf\")\n    add_files(\"exe/*.cpp\")\n```\n\n更多WDK驱动程序例子(umdf/kmdf/wdm)，见：[WDK工程例子](https://xmake.io/zh/examples/cpp/wdk.html)\n\n#### iOS/MacOS 应用程序\n\n```lua\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n```\n\n#### Framework 和 Bundle 程序（iOS/MacOS）\n\n```lua\ntarget(\"test\")\n    add_rules(\"xcode.framework\") -- 或者 xcode.bundle\n    add_files(\"src/*.m\")\n    add_files(\"src/Info.plist\")\n```\n\n#### OpenMP 程序\n\n```lua\nadd_requires(\"libomp\", {optional = true})\ntarget(\"loop\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_rules(\"c++.openmp\")\n    add_packages(\"libomp\")\n```\n\n#### Zig 程序\n\n```lua\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.zig\")\n```\n\n### 自动拉取远程工具链\n\n#### 拉取指定版本的 llvm 工具链\n\n我们使用 llvm-10 中的 clang 来编译项目。\n\n```lua\nadd_requires(\"llvm 10.x\", {alias = \"llvm-10\"})\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"llvm@llvm-10\")\n```\n\n#### 拉取交叉编译工具链\n\n我们也可以拉取指定的交叉编译工具链来编译项目。\n\n```lua\nadd_requires(\"muslcc\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@muslcc\")\n```\n\n#### 拉取工具链并且集成对应工具链编译的依赖包\n\n我们也可以使用指定的muslcc交叉编译工具链去编译和集成所有的依赖包。\n\n```lua\nadd_requires(\"muslcc\")\nadd_requires(\"zlib\", \"libogg\", {system = false})\n\nset_toolchains(\"@muslcc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\", \"libogg\")\n```\n\n## 插件\n\n#### 生成IDE工程文件插件（makefile, vs2002 - vs2026, ...）\n\n```bash\n$ xmake project -k vsxmake -m \"debug,release\" # 新版vs工程生成插件（推荐）\n$ xmake project -k vs -m \"debug,release\"\n$ xmake project -k cmake\n$ xmake project -k ninja\n$ xmake project -k compile_commands\n```\n\n#### 加载自定义lua脚本插件\n\n```bash\n$ xmake l ./test.lua\n$ xmake l -c \"print('hello xmake!')\"\n$ xmake l lib.detect.find_tool gcc\n$ xmake l\n> print(\"hello xmake!\")\n> {1, 2, 3}\n< {\n    1,\n    2,\n    3\n  }\n```\n\n更多内置插件见相关文档：[内置插件文档](https://xmake.io/zh/guide/extensions/builtin-plugins.html)\n\n其他扩展插件，请到插件仓库进行下载安装: [xmake-plugins](https://github.com/xmake-io/xmake-plugins).\n\n## IDE和编辑器插件\n\n* [xmake-vscode](https://github.com/xmake-io/xmake-vscode)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-vscode/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-sublime](https://github.com/xmake-io/xmake-sublime)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-sublime/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-idea](https://github.com/xmake-io/xmake-idea)\n\n<img src=\"https://raw.githubusercontent.com/xmake-io/xmake-idea/master/res/problem.gif\" width=\"650px\" />\n\n* [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai))\n* [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon))\n\n* [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886))\n\n* [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz))\n\n### XMake Gradle插件 (JNI)\n\n我们也可以在Gradle中使用[xmake-gradle](https://github.com/xmake-io/xmake-gradle)插件来集成编译JNI库\n\n```\nplugins {\n  id 'org.tboox.gradle-xmake-plugin' version '1.1.5'\n}\n\nandroid {\n    externalNativeBuild {\n        xmake {\n            path \"jni/xmake.lua\"\n        }\n    }\n}\n```\n\n当`gradle-xmake-plugin`插件被应用生效后，`xmakeBuild`任务会自动注入到现有的`assemble`任务中去，自动执行jni库编译和集成。\n\n```console\n$ ./gradlew app:assembleDebug\n> Task :nativelib:xmakeConfigureForArm64\n> Task :nativelib:xmakeBuildForArm64\n>> xmake build\n[ 50%]: ccache compiling.debug nativelib.cc\n[ 75%]: linking.debug libnativelib.so\n[100%]: build ok!\n>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a\n> Task :nativelib:xmakeConfigureForArmv7\n> Task :nativelib:xmakeBuildForArmv7\n>> xmake build\n[ 50%]: ccache compiling.debug nativelib.cc\n[ 75%]: linking.debug libnativelib.so\n[100%]: build ok!\n>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a\n> Task :nativelib:preBuild\n> Task :nativelib:assemble\n> Task :app:assembleDebug\n```\n\n## CI 集成\n\n### GitHub Action\n\n我们可以使用 [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) 在 Github Action 上实现跨平台安装集成 Xmake。\n\n```\nuses: xmake-io/github-action-setup-xmake@v1\nwith:\n  xmake-version: latest\n```\n\n## 谁在使用 Xmake?\n\n请点击 [用户列表](https://xmake.io/zh/about/who_is_using_xmake) 查看完整用户使用列表。\n\n如果您在使用 xmake，也欢迎通过 PR 将信息提交至上面的列表，让更多的用户了解有多少用户在使用 xmake，也能让用户更加安心使用 xmake。\n\n我们也会有更多的动力去持续投入，让 xmake 项目和社区更加繁荣。\n\n## 联系方式\n\n* 邮箱：[waruqi@gmail.com](mailto:waruqi@gmail.com)\n* 主页：[xmake.io](https://xmake.io/zh/)\n* 社区\n  - [Reddit论坛](https://www.reddit.com/r/xmake/)\n  - [Telegram群组](https://t.me/tbooxorg)\n  - [Discord聊天室](https://discord.gg/xmake)\n  - QQ群：343118190, 662147501\n* 源码：[Github](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake)\n* 微信公众号：tboox-os\n\n## 感谢\n\n感谢所有对xmake有所[贡献](CONTRIBUTING.md)的人:\n<a href=\"https://github.com/xmake-io/xmake/graphs/contributors\"><img src=\"https://opencollective.com/xmake/contributors.svg?width=890&button=false\" /></a>\n\n* [TitanSnow](https://github.com/TitanSnow): 提供xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) 和安装脚本。\n* [uael](https://github.com/uael): 提供语义版本跨平台c库 [sv](https://github.com/uael/sv)。\n* [OpportunityLiu](https://github.com/OpportunityLiu): 改进cuda构建, tests框架和ci。\n* [xq144](https://github.com/xq114): 改进 `xrepo env shell`，并贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。\n* [star-hengxing](https://github.com/star-hengxing): 贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。\n* [SirLynix](https://github.com/SirLynix): 贡献了许多的包，并且让更多的人知道和了解 xmake。\n* [Arthapz](https://github.com/Arthapz): 贡献新的 C++ Modules 实现。\n\n"
  },
  {
    "path": "configure",
    "content": "#!/bin/sh\n# A script-only build utility like autotools\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki\n# @homepage    https://github.com/xmake-io/xmake.sh\n#\n\n#-----------------------------------------------------------------------------\n# some constants\n#\nxmake_sh_projectdir=$(X= cd -- \"$(dirname -- \"$0\")\" && pwd -P)\nxmake_sh_builddir=\"build\"\nxmake_sh_version=\"1.0.5\"\nxmake_sh_verbose=false\nxmake_sh_diagnosis=false\nxmake_sh_copyright=\"Copyright (C) 2022-present Ruki Wang, https://xmake.io.\"\nxmake_sh_makefile=\"${xmake_sh_projectdir}/Makefile\"\nxmake_sh_ninjafile=\"${xmake_sh_projectdir}/build.ninja\"\n\n#-----------------------------------------------------------------------------\n# some helper functions\n#\nraise() {\n    echo \"$@\" 1>&2 ; exit 1\n}\n\nvprint() {\n    if \"${xmake_sh_verbose}\"; then\n        echo \"$@\"\n    fi\n}\n\ndprint() {\n    if \"${xmake_sh_diagnosis}\"; then\n        echo \"$@\"\n    fi\n}\n\n# show and escape string instead of `echo -e`, because sh does not support it\nprint() {\n    printf \"${@}\\n\"\n}\n\nwprint() {\n    if \"${xmake_sh_verbose}\"; then\n        printf \"warning: ${@}\\n\"\n    fi\n}\n\n# test empty string\ntest_z() {\n    if test \"x${1}\" = \"x\"; then\n        return 0\n    fi\n    return 1\n}\n\n# test non-empty string\ntest_nz() {\n    if test \"x${1}\" != \"x\"; then\n        return 0\n    fi\n    return 1\n}\n\n# test string is equal\ntest_eq() {\n    if test \"x${1}\" = \"x${2}\"; then\n        return 0\n    fi\n    return 1\n}\n\n# test string is not equal\ntest_nq() {\n    if test \"x${1}\" != \"x${2}\"; then\n        return 0\n    fi\n    return 1\n}\n\nstring_toupper() {\n    _ret=$(echo \"$1\" | tr '[a-z]' '[A-Z]')\n}\n\nstring_tolower() {\n    _ret=$(echo \"$1\" | tr '[A-Z]' '[a-z]')\n}\n\nstring_replace() {\n    local src=\"${1}\"\n    local search=\"${2}\"\n    local replace=\"${3}\"\n    if test_z \"${search}\"; then\n        _ret=\"${src}\"\n        return\n    fi\n    local rest=\"${src}\"\n    local result=\"\"\n    local prefix=\"\"\n    while :; do\n        case \"${rest}\" in\n            *\"${search}\"*)\n                prefix=\"${rest%%\"${search}\"*}\"\n                result=\"${result}${prefix}${replace}\"\n                rest=\"${rest#*\"${search}\"}\"\n                ;;\n            *)\n                result=\"${result}${rest}\"\n                break\n                ;;\n        esac\n    done\n    _ret=\"${result}\"\n}\n\n# escape value for writing into ninja files\n_ninja_escape() {\n    local rest=\"${1}\"\n    case \"${rest}\" in\n        *\\$*)\n            local result=\"\"\n            while :; do\n                case \"${rest}\" in\n                    *\\$*)\n                        result=\"${result}${rest%%\\$*}\\$\\$\"\n                        rest=\"${rest#*\\$}\"\n                        ;;\n                    *)\n                        result=\"${result}${rest}\"\n                        break\n                        ;;\n                esac\n            done\n            _ret=\"${result}\"\n            ;;\n        *)\n            _ret=\"${rest}\"\n            ;;\n    esac\n}\n\n_shell_escape_single_quotes() {\n    local value=\"${1}\"\n    case \"${value}\" in\n        *\"'\"*)\n            local escaped=\"\"\n            while :; do\n                case \"${value}\" in\n                    *\"'\"*)\n                        escaped=\"${escaped}${value%%\\'*}'\\\"'\\\"'\"\n                        value=\"${value#*\\'}\"\n                        ;;\n                    *)\n                        escaped=\"${escaped}${value}\"\n                        break\n                        ;;\n                esac\n            done\n            _ret=\"'${escaped}'\"\n            ;;\n        *)\n            _ret=\"'${value}'\"\n            ;;\n    esac\n}\n\n# we avoid use `cut` command, because it's slow\nstring_split() {\n    local str=\"${1}\"\n    local sep=\"${2}\"\n    local idx=\"${3}\"\n    local oldifs=\"${IFS}\"\n    IFS=\"${sep}\"\n    set -- ${str}\n    if test_nz \"${idx}\"; then\n        case \"${idx}\" in\n            1) _ret=\"$1\";;\n            2) _ret=\"$2\";;\n            3) _ret=\"$3\";;\n            4) _ret=\"$4\";;\n            5) _ret=\"$5\";;\n            6) _ret=\"$6\";;\n        esac\n    else\n        _ret=\"$1\"\n        _ret2=\"$2\"\n        _ret3=\"$3\"\n        _ret4=\"$4\"\n        _ret5=\"$5\"\n        _ret6=\"$6\"\n    fi\n    IFS=\"${oldifs}\"\n}\n\n# does contain sub-string?\n# e.g.\n# str=\"src/*.cpp\"\n# string_contains \"$str\" \"src\"\nstring_contains() {\n    case \"${1}\" in\n        *${2}*) return 0;;\n        *) return 1;;\n    esac\n    return 1\n}\n\n# does contain \"*\"?\nstring_contains_star() {\n    case \"${1}\" in\n        *\\**) return 0;; # bash\n        *'*'*) return 0;; # csh\n        *) return 1;;\n    esac\n    return 1\n}\n\n# does contain \"**\"?\nstring_contains_star2() {\n    case \"${1}\" in\n        *\\*\\**) return 0;; # bash\n        *'**'*) return 0;; # csh\n        *) return 1;;\n    esac\n    return 1\n}\n\n# does startswith sub-string?\n# e.g.\n# str=\"src/*.cpp\"\n# string_startswith \"$str\" \"src\"\nstring_startswith() {\n    case \"${1}\" in\n        ${2}*) return 0;;\n        *) return 1;;\n    esac\n    return 1\n}\n\n# duplicate characters\n# e.g. string_dupch 10 \".\" => ...........\nstring_dupch() {\n    local count=${1}\n    local ch=${2}\n    local result=\"\"\n    while [ \"${count:-0}\" -gt 0 ]; do\n        result=\"${result}${ch}\"\n        count=$((count - 1))\n    done\n    printf '%s' \"${result}\"\n}\n\n# replace file content\n_io_replace_file() {\n    local infile=\"${1}\"\n    local outfile=\"${2}\"\n    local patterns=\"${3}\"\n    sed \"/./ {${patterns}}\" \"${infile}\" > \"${outfile}\"\n}\n\n# try remove file or directory\n_os_tryrm() {\n    if test -f \"${1}\"; then\n        rm \"${1}\"\n    elif test -d \"${1}\"; then\n        rm -r \"${1}\"\n    fi\n}\n\n# get temporary file\n# https://github.com/xmake-io/xmake/issues/5464\n_os_tmpfile() {\n    _ret=$(mktemp \"${TMPDIR-/tmp}/tmp.XXXXXXXX\")\n}\n\n# try run program\n_os_runv() {\n    if ${xmake_sh_diagnosis}; then\n        ${@}\n    else\n        ${@} >/dev/null 2>&1\n    fi\n    local ok=$?\n    if test \"${ok}\" -ne \"0\"; then\n        return 1\n    fi\n    return 0\n}\n\n# try run program and get output\n_os_iorunv() {\n    _os_tmpfile\n    local tmpfile=\"${_ret}\"\n    ${@} >\"${tmpfile}\" 2>&1\n    local ok=$?\n    if test \"${ok}\" -ne \"0\"; then\n        _ret=\"\"\n    else\n        local result=$(cat \"${tmpfile}\")\n        _ret=\"${result}\"\n    fi\n    _os_tryrm \"${tmpfile}\"\n}\n\n# find file in the given directory\n# e.g. _os_find . xmake.sh [depth]\n_os_find() {\n    local dir=\"${1}\"\n    local name=\"${2}\"\n    local depth=\"${3}\"\n    if test_nz \"${depth}\"; then\n        # Solaris doesn't support -maxdepth, use shell to filter depth\n        if is_host \"solaris\"; then\n            _ret=\"\"\n            local file=\"\"\n            for file in $(find \"${dir}\" -type f -name \"${name}\" | LC_ALL=C sort); do\n                local relpath=\"${file#${dir}/}\"\n                local slash_count=$(echo \"${relpath}\" | tr -cd '/' | wc -c | tr -d ' ')\n                if test \"${slash_count}\" = \"$((${depth} - 1))\"; then\n                    if test -z \"${_ret}\"; then\n                        _ret=\"${file}\"\n                    else\n                        _ret=\"${_ret}\n${file}\"\n                    fi\n                fi\n            done\n        else\n            _ret=$(find \"${dir}\" -maxdepth \"${depth}\" -mindepth \"${depth}\" -type f -name \"${name}\" | LC_ALL=C sort)\n        fi\n    else\n        _ret=$(find \"${dir}\" -type f -name \"${name}\" | LC_ALL=C sort)\n    fi\n}\n\n# get date, \"%Y%m%d%H%M\" -> 202212072222\n# Use deterministic timestamp from SOURCE_DATE_EPOCH if available\n# https://reproducible-builds.org/docs/source-date-epoch/\n_os_date() {\n    if test_z \"${SOURCE_DATE_EPOCH}\"; then\n        _ret=$(date +\"${1}\")\n    else\n        # Use GNU date options first, then fallback to BSD's, and finally fallback to current time.\n        _ret=$(date -u -d \"@$SOURCE_DATE_EPOCH\" +\"${1}\" 2>/dev/null || date -u -r \"$SOURCE_DATE_EPOCH\" +\"${1}\" 2>/dev/null || date +\"${1}\")\n    fi\n}\n\n# we avoid use `basename`, because it's slow\npath_filename() {\n    local path=\"${1}\"\n    if test_eq \"${path}\" \"/\"; then\n        _ret=\"/\"\n    else\n        _ret=\"${path##*/}\"\n    fi\n}\n\npath_extension() {\n    path_filename \"${1}\"; local filename=\"${_ret}\"\n    _ret=\".${filename##*.}\"\n}\n\npath_basename() {\n    path_filename \"${1}\"; local filename=\"${_ret}\"\n    _ret=\"${filename%.*}\"\n}\n\n# we avoid use `dirname -- ${1}`, because it's too slow\npath_directory() {\n    local path=\"${1}\"\n    if test_z \"${path}\"; then\n        raise \"invalid empty path in path_directory().\"\n    fi\n    path=\"${path%/}\"\n    local dir=\"${path%/*}\"\n    if string_startswith \"${path}\" \"/\"; then\n        if test_z \"${dir}\"; then\n            dir=\"/\"\n        fi\n    else\n        dir=\"${dir#/}\"\n        if test_z \"${dir}\"; then\n            dir=\".\"\n        fi\n    fi\n    _ret=\"${dir}\"\n}\n\n# e.g. path_filename_fromdir \"/tmp/file\" \"/tmp\" -> \"file\"\npath_filename_fromdir() {\n    _ret=\"${1#${2}/}\"\n}\n\npath_is_absolute() {\n    if string_startswith \"${1}\" \"/\"; then\n        return 0\n    fi\n    return 1\n}\n\n# get relative path, e.g $(path_relative ${rootdir} ${absolute_path}`\npath_relative() {\n    local source=\"${1}\"\n    local target=\"${2}\"\n    if test_z \"${source}\" || test_z \"${target}\"; then\n        raise \"invalid empty path in path_relative()\"\n    fi\n\n    # patch missing \"./\"\n    source=${source#./}\n    source=${source#.}\n    target=${target#./}\n    target=${target#.}\n    if test_z \"${source}\"; then\n        _ret=\"${target}\"\n        return\n    fi\n\n    # find common path\n    local result=\"\"\n    local common_part=$source\n    while test_eq \"${target#$common_part}\" \"${target}\"; do\n        # no match, means that candidate common part is not correct\n        # go up one level (reduce common part)\n        path_directory \"${common_part}\"; common_part=\"${_ret}\"\n        # and record that we went back, with correct / handling\n        if test_z \"${result}\"; then\n            result=\"..\"\n        else\n            result=\"../${result}\"\n        fi\n    done\n\n    if test_eq \"${common_part}\" \"/\"; then\n        # special case for root (no common path)\n        result=\"${result}/\"\n    fi\n\n    # since we now have identified the common part,\n    # compute the non-common part\n    local forward_part=\"${target#$common_part}\"\n\n    # and now stick all parts together\n    if test_nz \"${result}\" && test_nz \"${forward_part}\"; then\n        result=\"${result}${forward_part}\"\n    elif test_nz \"${forward_part}\"; then\n        result=\"${forward_part#*/}\"\n    fi\n\n    # same directory?\n    if test_z \"${result}\" && test_eq \"${source}\" \"${target}\"; then\n        result=\".\"\n    fi\n\n    _ret=\"${result}\"\n}\n\npath_sourcekind() {\n    local sourcekind=\"\"\n    case \"${1}\" in\n        *.cpp) sourcekind=\"cxx\";;\n        *.cc) sourcekind=\"cxx\";;\n        *.c) sourcekind=\"cc\";;\n        *.ixx) sourcekind=\"cxx\";;\n        *.mm) sourcekind=\"mxx\";;\n        *.m) sourcekind=\"mm\";;\n        *.S) sourcekind=\"as\";;\n        *.s) sourcekind=\"as\";;\n        *.asm) sourcekind=\"as\";;\n        *) raise \"unknown sourcekind for ${1}\" ;;\n    esac\n    _ret=\"${sourcekind}\"\n}\n\npath_toolname() {\n    local toolname=\"\"\n    case \"${1}\" in\n        *-gcc) toolname=\"gcc\";;\n        */gcc) toolname=\"gcc\";;\n        gcc) toolname=\"gcc\";;\n        gcc-*) toolname=\"gcc\";;\n        */gcc-*) toolname=\"gcc\";;\n        *-g++) toolname=\"gxx\";;\n        */g++) toolname=\"gxx\";;\n        g++) toolname=\"gxx\";;\n        g++-*) toolname=\"gxx\";;\n        */g++-*) toolname=\"gxx\";;\n        xcrun*clang++) toolname=\"clangxx\";;\n        xcrun*clang) toolname=\"clang\";;\n        *-clang++) toolname=\"clangxx\";;\n        */clang++) toolname=\"clangxx\";;\n        clang++) toolname=\"clangxx\";;\n        clang++-*) toolname=\"clangxx\";;\n        */clang++-*) toolname=\"clangxx\";;\n        *-clang) toolname=\"clang\";;\n        */clang) toolname=\"clang\";;\n        clang) toolname=\"clang\";;\n        clang-*) toolname=\"clang\";;\n        */clang-*) toolname=\"clang\";;\n        */emcc) toolname=\"emcc\";;\n        emcc) toolname=\"emcc\";;\n        */em++) toolname=\"emxx\";;\n        em++) toolname=\"emxx\";;\n        */cosmocc) toolname=\"cosmocc\";;\n        cosmocc) toolname=\"cosmocc\";;\n        */cosmoc++) toolname=\"cosmocxx\";;\n        cosmoc++) toolname=\"cosmocxx\";;\n        *-ar) toolname=\"ar\";;\n        */ar) toolname=\"ar\";;\n        ar) toolname=\"ar\";;\n        */emar) toolname=\"emar\";;\n        emar) toolname=\"emar\";;\n        */cosmoar) toolname=\"cosmoar\";;\n        cosmoar) toolname=\"cosmoar\";;\n        cc) toolname=\"gcc\";;\n        */cc) toolname=\"gcc\";;\n        c++) toolname=\"gxx\";;\n        */c++) toolname=\"gxx\";;\n        tcc) toolname=\"tcc\";;\n        */tcc) toolname=\"tcc\";;\n        *) raise \"unknown tool ${1}\";;\n    esac\n    _ret=\"${toolname}\"\n}\n\n# get flag name from toolkind, e.g. cc => cflags, cxx => cxxflags\n_get_flagname() {\n    local toolkind=\"${1}\"\n    local flagname=\"\"\n    case \"${toolkind}\" in\n        cc) flagname=\"cflags\";;\n        cxx) flagname=\"cxxflags\";;\n        as) flagname=\"asflags\";;\n        mm) flagname=\"mflags\";;\n        mxx) flagname=\"mxxflags\";;\n        ar) flagname=\"arflags\";;\n        sh) flagname=\"shflags\";;\n        ld) flagname=\"ldflags\";;\n        *) raise \"unknown toolkind(${toolkind})!\" ;;\n    esac\n    _ret=\"${flagname}\"\n}\n\n# is enabled? true, yes, y\n_is_enabled() {\n    local value=${1}\n    if test_eq \"${value}\" \"true\"; then\n        return 0\n    elif test_eq \"${value}\" \"yes\"; then\n        return 0\n    elif test_eq \"${value}\" \"y\"; then\n        return 0\n    fi\n    return 1\n}\n\n# deduplicate string list\n# .e.g \"hello world hello how are you world\" -> hello world how are you\n_dedup() {\n    _ret=$(echo \"${1}\" | awk '{for (i = 1; i <= NF; ++i) if (!seen[$i]++) printf $i \" \"}')\n}\n\n# deduplicate string list from the reverse order\n# .e.g \"hello world hello how are you world\" -> hello how are you world\n_dedup_reverse() {\n    local result=\"\"\n    local list=\"\"\n    local item=\"\"\n    list=$(echo \"${1}\" | awk '{for (i = NF; i > 0; --i) if (!seen[$i]++) printf $i \" \"}')\n    for item in ${list}; do\n        result=\"${item} ${result}\"\n    done\n    _ret=\"${result}\"\n}\n\n#-----------------------------------------------------------------------------\n# map functions\n#\n\n# define map, @note we can not use bash/declare to define map, because sh does not support it.\n#\n# _map \"options\"\n# _map_set \"options\" \"key1\" \"value1\"\n# _map_set \"options\" \"key2\" \"value2\"\n# _map_set \"options\" \"key2\" \"value3\"\n# _map_set \"options\" \"key3\" \"value3\"\n# _map_set \"options\" \"key4\" \"__empty__\"\n# _map_set \"options\" \"key4\" \"__empty__\"\n# _map_count \"options\"; _count=\"${_ret}\"\n# _map_keys \"options\"; _keys=\"${_ret}\"\n# echo ${_count}\n# for key in ${_keys}; do\n#     _map_get \"options\" ${key}; value=\"{_ret}\"\n#     echo ${key} \"->\" ${value}\n# done\n#\n# echo \"------\"\n# _map_remove \"options\" \"key3\"\n# _map_count \"options\"; _count=\"${_ret}\"\n# _map_keys \"options\"; _keys=\"${_ret}\"\n# echo ${_count}\n# for key in ${_keys}; do\n#     _map_get \"options\" ${key}; value=\"{_ret}\"\n#     echo ${key} \"->\" ${value}\n# done\n#\n_map() {\n    local name=${1}\n#    eval _map_${name}_count=0\n#    eval _map_${name}_keys=\"\"\n}\n\n# because the shell is slow, we have to temporarily\n# disable some of the map features for performance.\n#\n#_map_count() {\n#    local name=${1}\n#    local count=$(eval echo \\$_map_${name}_count)\n#    _ret=\"${count}\"\n#}\n\n_map_get() {\n    local name=\"${1}\"\n    local key=\"${2}\"\n    _ret=$(eval echo \\$_map_${name}_value_${key})\n    if test_eq \"${_ret}\" \"__empty__\"; then\n        _ret=\"\"\n    fi\n}\n\n_map_has() {\n    local name=\"${1}\"\n    local key=\"${2}\"\n    local value=\"\"\n    value=$(eval echo \\$_map_${name}_value_${key})\n    if test_nz \"${value}\"; then\n        return 0\n    fi\n    return 1\n}\n\n_map_set() {\n    local name=\"${1}\"\n    local key=\"${2}\"\n    local value=\"${3}\"\n#    if ! _map_has ${name} ${key}; then\n#        _map_count \"options\"; local count=\"${_ret}\"\n#        eval _map_${name}_count=$((${count} + 1))\n#        local keys=$(eval echo \\$_map_${name}_keys)\n#        keys=\"${keys} ${key}\"\n#        eval _map_${name}_keys=\\${keys}\n#    fi\n    eval _map_${name}_value_${key}=\\${value}\n}\n\n#_map_remove() {\n#    local name=\"${1}\"\n#    local key=\"${2}\"\n#    if _map_has ${name} ${key}; then\n#        _map_count \"options\"; local count=\"${_ret}\"\n#        eval _map_${name}_count=$((${count} - 1))\n#        eval _map_${name}_value_${key}=\"\"\n#        local keys=$(eval echo \\$_map_${name}_keys)\n#        local keys_new=\"\"\n#        local k=\"\"\n#        for k in ${keys}; do\n#            if test_nq \"${k}\" \"${key}\"; then\n#                keys_new=\"${keys_new} ${k}\"\n#            fi\n#        done\n#        eval _map_${name}_keys=\\${keys_new}\n#    fi\n#}\n\n#_map_keys() {\n#    local name=\"${1}\"\n#    local keys=$(eval echo \\$_map_${name}_keys)\n#    _ret=\"${keys}\"\n#}\n\n#-----------------------------------------------------------------------------\n# detect default environments\n#\n\n# detect hosts\nos_host=`uname`\nstring_tolower ${os_host}; os_host=\"${_ret}\"\ncase \"${os_host}\" in\n    *cygwin*) os_host=\"cygwin\" ;;\n    *mingw*|*msys*) os_host=\"msys\" ;;\n    *darwin*) os_host=\"macosx\" ;;\n    *linux*) os_host=\"linux\" ;;\n    *freebsd*) os_host=\"freebsd\" ;;\n    *netbsd*) os_host=\"netbsd\" ;;\n    *openbsd*) os_host=\"openbsd\" ;;\n    *dragonfly*) os_host=\"dragonflybsd\" ;;\n    *bsd*) os_host=\"bsd\" ;;\n    *sunos*) os_host=\"solaris\" ;;\n    *haiku*) os_host=\"haiku\" ;;\nesac\n\n# determining host\n# e.g.\n# if is_host \"linux\" \"macosx\"; then\n#     ...\n# fi\nis_host() {\n    local host=\"\"\n    for host in $@; do\n        if test_eq \"${os_host}\" \"${host}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n# detect host architecture\nos_arch=`uname -m | tr '[A-Z]' '[a-z]'`\nif test_eq \"${os_arch}\" \"i686\" || test_eq \"${os_arch}\" \"i86pc\"; then\n    os_arch=\"i386\"\nelif test_eq \"${os_arch}\" \"amd64\"; then\n    os_arch=\"x86_64\"\nelif test_eq \"${os_arch}\" \"aarch64\" || test_eq \"${os_arch}\" \"arm64\"; then\n    os_arch=\"arm64\"\nelif string_contains \"${os_arch}\" \"armv7\"; then\n    os_arch=\"armv7\"\nelif string_contains \"${os_arch}\" \"arm\"; then\n    os_arch=\"arm\"\nelif string_contains \"${os_arch}\" \"power macintosh\"; then\n    os_arch=\"ppc\"\nfi\n\n# set the default target platform\n_target_plat_default=${os_host}\nif is_host \"msys\"; then\n    _target_plat_default=\"mingw\"\nelif is_host \"freebsd\" \"openbsd\" \"dragonflybsd\" \"netbsd\"; then\n    _target_plat_default=\"bsd\"\nelif test_nz \"${EMSDK}\"; then\n    _target_plat_default=\"wasm\"\nfi\n\n# set the default target architecture\n_target_arch_default=${os_arch}\nif is_host \"msys\" && test_nz \"${MSYSTEM_CARCH}\"; then\n    _target_arch_default=\"${MSYSTEM_CARCH}\"\nelif test_nz \"${TERMUX_ARCH}\"; then\n    _target_arch_default=\"${TERMUX_ARCH}\"\nelif test_nz \"${EMSDK}\"; then\n    _target_arch_default=\"wasm32\"\nfi\nif test_eq \"${_target_arch_default}\" \"i686\"; then\n    _target_arch_default=\"i386\"\nelif test_eq \"${_target_arch_default}\" \"aarch64\" || test_eq \"${_target_arch_default}\" \"arm64\"; then\n    _target_arch_default=\"arm64\"\nelif string_contains \"${_target_arch_default}\" \"armv7\"; then\n    _target_arch_default=\"armv7\"\nelif string_contains \"${_target_arch_default}\" \"arm\"; then\n    _target_arch_default=\"arm\"\nfi\n\n# set the default target mode\n_target_mode_default=\"release\"\n\n# set the default target kind\n_target_kind_default=\"static\"\n\n# set the default project generator and build program\nif is_host \"freebsd\" \"netbsd\" \"openbsd\" \"dragonflybsd\" \"bsd\" \"solaris\"; then\n    project_generator=\"gmake\"\n    _make_program_default=\"gmake\"\n    _ninja_program_default=\"ninja\"\nelif is_host \"msys\" \"cygwin\"; then\n    project_generator=\"gmake\"\n    _make_program_default=\"make.exe\"\n    _ninja_program_default=\"ninja.exe\"\nelse\n    project_generator=\"gmake\"\n    _make_program_default=\"make\"\n    _ninja_program_default=\"ninja\"\nfi\n\n# set the default directories\nif test -d \"/usr/local\"; then\n    _install_prefix_default=\"/usr/local\"\nelif test -d \"/usr\"; then\n    _install_prefix_default=\"/usr\"\nfi\n_install_bindir_default=\"\\${prefix}/bin\"\n_install_libdir_default=\"\\${prefix}/lib\"\n_install_includedir_default=\"\\${prefix}/include\"\n\n# determining target platform\n# e.g.\n# if is_plat \"linux\" \"macosx\"; then\n#     ...\n# fi\nis_plat() {\n    local plat=\"\"\n    for plat in $@; do\n        if test_eq \"${_target_plat}\" \"${plat}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n# determining target architecture\n# e.g.\n# if is_arch \"x86_64\" \"i386\"; then\n#     ...\n# fi\nis_arch() {\n    local arch=\"\"\n    for arch in $@; do\n        if test_eq \"${_target_arch}\" \"${arch}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n# determining target mode\n# e.g.\n# if is_mode \"release\"; then\n#     ...\n# fi\nis_mode() {\n    local mode=\"\"\n    for mode in $@; do\n        if test_eq \"${_target_mode}\" \"${mode}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n# determining target kind\n# e.g.\n# if is_kind \"release\"; then\n#     ...\n# fi\nis_kind() {\n    local kind=\"\"\n    for kind in $@; do\n        if test_eq \"${_target_kind}\" \"${kind}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n# determining target toolchain\n# e.g.\n# if is_toolchain \"clang\"; then\n#     ...\n# fi\nis_toolchain() {\n    local toolchain=\"\"\n    for toolchain in $@; do\n        if test_eq \"${_target_toolchain}\" \"${toolchain}\"; then\n            return 0\n        fi\n    done\n    return 1\n}\n\n#-----------------------------------------------------------------------------\n# project configuration apis\n#\n\n# set project name\nset_project() {\n    _xmake_sh_project_name=\"${1}\"\n}\n\n# include the given xmake.sh file or directory\n# e.g. includes \"src\" \"tests\"\nincludes() {\n    local path=\"\"\n    for path in $@; do\n        if test -f \"${path}\"; then\n            path_directory \"${path}\"; xmake_sh_scriptdir=\"${_ret}\"\n            . \"${path}\"\n        else\n            local xmake_sh_scriptdir_cur=${xmake_sh_scriptdir}\n            if test \"x${xmake_sh_scriptdir}\" != \"x\"; then\n                xmake_sh_scriptdir=\"${xmake_sh_scriptdir_cur}/${path}\"\n                . \"${xmake_sh_scriptdir}/xmake.sh\"\n            else\n                . \"${xmake_sh_projectdir}/${path}/xmake.sh\"\n            fi\n            xmake_sh_scriptdir=${xmake_sh_scriptdir_cur}\n        fi\n    done\n}\n\n#-----------------------------------------------------------------------------\n# some helper functions\n#\n\n# split flags\n_split_flags() {\n    string_replace \"${1}\" \":\" \" \"\n}\n\n# get abstract flag for gcc/clang\n_get_abstract_flag_for_gcc_clang() {\n    local toolkind=\"${1}\"\n    local toolname=\"${2}\"\n    local itemname=\"${3}\"\n    local value=\"${4}\"\n    local flag=\"\"\n    case \"${itemname}\" in\n        defines)\n            string_replace \"${value}\" '\"' '\\\"'; value=\"${_ret}\"\n            flag=\"-D${value}\"\n            ;;\n        undefines) flag=\"-U${value}\";;\n        includedirs) flag=\"-I${value}\";;\n        linkdirs) flag=\"-L${value}\";;\n        links) flag=\"-l${value}\";;\n        syslinks) flag=\"-l${value}\";;\n        frameworks) flag=\"-framework ${value}\";;\n        frameworkdirs) flag=\"-F${value}\";;\n        rpathdirs)\n            if is_plat \"macosx\"; then\n                string_replace \"${value}\" \"\\$ORIGIN\" \"@loader_path\"; value=\"${_ret}\"\n                flag=\"-Xlinker -rpath -Xlinker ${value}\"\n            else\n                # escape $ORIGIN in makefile, TODO we need also handle it for ninja\n                string_replace \"${value}\" \"@loader_path\" '$$ORIGIN'; value=\"${_ret}\"\n                if is_plat \"bsd\"; then\n                    flag=\"-Wl,-zorigin -Wl,-rpath='${value}'\"\n                else\n                    flag=\"-Wl,-rpath='${value}'\"\n                fi\n            fi\n            ;;\n        symbols)\n            if test_eq \"${value}\" \"debug\"; then\n                flag=\"-g\"\n            elif test_eq \"${value}\" \"hidden\"; then\n                flag=\"-fvisibility=hidden\"\n            fi\n            ;;\n        strip)\n            if test_eq \"${value}\" \"debug\"; then\n                flag=\"-Wl,-S\"\n            elif test_eq \"${value}\" \"all\"; then\n                if is_plat \"macosx\"; then\n                    flag=\"-Wl,-x -Wl,-dead_strip\"\n                else\n                    flag=\"-s\"\n                fi\n            fi\n            ;;\n        warnings)\n            if test_eq \"${value}\" \"all\" || test_eq \"${value}\" \"more\" || test_eq \"${value}\" \"less\"; then\n                flag=\"-Wall\"\n            elif test_eq \"${value}\" \"allextra\"; then\n                flag=\"-Wall -Wextra\"\n            elif test_eq \"${value}\" \"error\"; then\n                flag=\"-Werror\"\n            elif test_eq \"${value}\" \"everything\"; then\n                flag=\"-Wall -Wextra\"\n            elif test_eq \"${value}\" \"none\"; then\n                flag=\"-w\"\n            fi\n            ;;\n        optimizes)\n            if test_eq \"${value}\" \"fast\"; then\n                flag=\"-O1\"\n            elif test_eq \"${value}\" \"faster\"; then\n                flag=\"-O2\"\n            elif test_eq \"${value}\" \"fastest\"; then\n                flag=\"-O3\"\n            elif test_eq \"${value}\" \"smallest\"; then\n                if test_eq \"${toolname}\" \"clang\" || test_eq \"${toolname}\" \"clangxx\"; then\n                    flag=\"-Oz\"\n                else\n                    flag=\"-Os\"\n                fi\n            elif test_eq \"${value}\" \"aggressive\"; then\n                flag=\"-Ofast\"\n            elif test_eq \"${value}\" \"none\"; then\n                flag=\"-O0\"\n            fi\n            ;;\n        languages)\n            if test_eq \"${toolkind}\" \"cc\" || test_eq \"${toolkind}\" \"mm\"; then\n                case \"${value}\" in\n                    ansi) flag=\"-ansi\";;\n                    c89) flag=\"-std=c89\";;\n                    gnu89) flag=\"-std=gnu89\";;\n                    c99) flag=\"-std=c99\";;\n                    gnu99) flag=\"-std=gnu99\";;\n                    c11) flag=\"-std=c11\";;\n                    gnu11) flag=\"-std=gnu11\";;\n                    c17) flag=\"-std=c17\";;\n                    gnu17) flag=\"-std=gnu17\";;\n                esac\n            elif test_eq \"${toolkind}\" \"cxx\" || test_eq \"${toolkind}\" \"mxx\"; then\n                case \"${value}\" in\n                    cxx98) flag=\"-std=c++98\";;\n                    c++98) flag=\"-std=c++98\";;\n                    gnuxx98) flag=\"-std=gnu++98\";;\n                    gnu++98) flag=\"-std=gnu++98\";;\n\n                    cxx11) flag=\"-std=c++11\";;\n                    c++11) flag=\"-std=c++11\";;\n                    gnuxx11) flag=\"-std=gnu++11\";;\n                    gnu++11) flag=\"-std=gnu++11\";;\n\n                    cxx14) flag=\"-std=c++14\";;\n                    c++14) flag=\"-std=c++14\";;\n                    gnuxx14) flag=\"-std=gnu++14\";;\n                    gnu++14) flag=\"-std=gnu++14\";;\n\n                    cxx17) flag=\"-std=c++17\";;\n                    c++17) flag=\"-std=c++17\";;\n                    gnuxx17) flag=\"-std=gnu++17\";;\n                    gnu++17) flag=\"-std=gnu++17\";;\n\n                    cxx1z) flag=\"-std=c++1z\";;\n                    c++1z) flag=\"-std=c++1z\";;\n                    gnuxx1z) flag=\"-std=gnu++1z\";;\n                    gnu++1z) flag=\"-std=gnu++1z\";;\n\n                    cxx2a) flag=\"-std=c++2a\";;\n                    c++2a) flag=\"-std=c++2a\";;\n                    gnuxx2a) flag=\"-std=gnu++2a\";;\n                    gnu++2a) flag=\"-std=gnu++2a\";;\n\n                    cxx20) flag=\"-std=c++20\";;\n                    c++20) flag=\"-std=c++20\";;\n                    gnuxx20) flag=\"-std=gnu++20\";;\n                    gnu++20) flag=\"-std=gnu++20\";;\n                    cxx*) raise \"unknown language value(${value})!\" ;;\n                    c++*) raise \"unknown language value(${value})!\" ;;\n                esac\n            fi\n            ;;\n        *) raise \"unknown itemname(${itemname})!\" ;;\n    esac\n    _ret=\"${flag}\"\n}\n\n# get abstract flags\n_get_abstract_flags() {\n    local toolkind=\"${1}\"\n    local toolname=\"${2}\"\n    local itemname=\"${3}\"\n    local values=\"${4}\"\n    local flags=\"\"\n    local value=\"\"\n    for value in ${values}; do\n        local flag=\"\"\n        case \"${toolname}\" in\n            gcc) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            gxx) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            clang) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            clangxx) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            emcc) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            emxx) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            cosmocc) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            cosmocxx) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            tcc) _get_abstract_flag_for_gcc_clang \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${value}\"; flag=\"${_ret}\";;\n            *) raise \"unknown toolname(${toolname})!\" ;;\n        esac\n        if test_nz \"${flag}\"; then\n            flags=\"${flags} ${flag}\"\n        fi\n    done\n    _ret=\"${flags}\"\n}\n\n#-----------------------------------------------------------------------------\n# option configuration apis\n#\n\n# define option\noption() {\n    local name=\"${1}\"\n    local description=\"${2}\"\n    local default=${3}\n    _xmake_sh_option_current=\"${name}\"\n    if ! ${_loading_options}; then\n        if test_nz \"${description}\"; then\n            _xmake_sh_option_current=\"\"\n        fi\n        return\n    fi\n    if ! _map_has \"options\" \"${name}_name\"; then\n        _xmake_sh_options=\"${_xmake_sh_options} ${name}\"\n    fi\n    _map_set \"options\" \"${name}_name\" \"${name}\"\n    _map_set \"options\" \"${name}_description\" \"${description}\"\n    _map_set \"options\" \"${name}_default\" \"${default}\"\n    # we end option if it's just one line\n    if test_nz \"${description}\"; then\n        _xmake_sh_option_current=\"\"\n    fi\n    return 0\n}\noption_end() {\n    _xmake_sh_option_current=\"\"\n}\n_map \"options\"\n\n# has the given option?\n_has_option() {\n    local name=${1}\n    if _map_has \"options\" \"${name}_name\"; then\n        return 0\n    fi\n    return 1\n}\n\n# get the given option item\n_get_option_item() {\n    local name=${1}\n    local key=${2}\n    _map_get \"options\" \"${name}_${key}\"\n}\n\n# set the given option item\n_set_option_item() {\n    local name=${1}\n    local key=${2}\n    shift\n    shift\n    if test_nz \"${name}\"; then\n        _map_set \"options\" \"${name}_${key}\" \"${@}\"\n    else\n        raise \"please call set_${key}(${@}) in the option scope!\"\n    fi\n}\n\n# add values to the given option item\n_add_option_item() {\n    local name=${1}\n    local key=${2}\n    shift\n    shift\n    if test_nz \"${name}\"; then\n        _map_get \"options\" \"${name}_${key}\"; local values=\"${_ret}\"\n        values=\"${values} ${@}\"\n        _map_set \"options\" \"${name}_${key}\" \"${values}\"\n    else\n        raise \"please call add_${key}(${@}) in the option scope!\"\n    fi\n}\n\n# get the give option value\n_get_option_value() {\n    local name=${1}\n    _get_option_item \"${name}\" \"value\"\n    if test \"x${_ret}\" = \"x\"; then\n        _get_option_item \"${name}\" \"default\"\n    fi\n}\n\n# set the give option value\n_set_option_value() {\n    local name=${1}\n    local value=${2}\n    _set_option_item \"${name}\" \"value\" \"${value}\"\n}\n\n# this option need checking?\n_option_need_checking() {\n    local name=\"${1}\"\n    _get_option_item \"${name}\" \"default\"; local default=\"${_ret}\"\n    if test_nz \"${default}\"; then\n        return 1\n    fi\n    _get_option_item \"${name}\" \"cfuncs\"; local cfuncs=\"${_ret}\"\n    _get_option_item \"${name}\" \"cxxfuncs\"; local cxxfuncs=\"${_ret}\"\n    _get_option_item \"${name}\" \"cincludes\"; local cincludes=\"${_ret}\"\n    _get_option_item \"${name}\" \"cxxincludes\"; local cxxincludes=\"${_ret}\"\n    _get_option_item \"${name}\" \"ctypes\"; local ctypes=\"${_ret}\"\n    _get_option_item \"${name}\" \"cxxtypes\"; local cxxtypes=\"${_ret}\"\n    _get_option_item \"${name}\" \"csnippets\"; local csnippets=\"${_ret}\"\n    _get_option_item \"${name}\" \"cxxsnippets\"; local cxxsnippets=\"${_ret}\"\n    _get_option_item \"${name}\" \"links\"; local links=\"${_ret}\"\n    _get_option_item \"${name}\" \"syslinks\"; local syslinks=\"${_ret}\"\n    if test_nz \"${cfuncs}\" || test_nz \"${cxxfuncs}\" ||\n       test_nz \"${cincludes}\" || test_nz \"${cxxincludes}\" ||\n       test_nz \"${ctypes}\" || test_nz \"${cxxtypes}\" ||\n       test_nz \"${csnippets}\" || test_nz \"${cxxsnippets}\" ||\n       test_nz \"${links}\" || test_nz \"${syslinks}\"; then\n        return 0\n    fi\n    return 1\n}\n\n# get options for the help menu\n_get_options_for_menu() {\n    local options=\"\"\n    local name=\"\"\n    for name in ${_xmake_sh_options}; do\n        _get_option_item \"${name}\" \"showmenu\"; local showmenu=\"${_ret}\"\n        if _is_enabled \"${showmenu}\"; then\n            options=\"${options} ${name}\"\n        elif test_z \"${showmenu}\" && ! _option_need_checking \"${name}\"; then\n            options=\"${options} ${name}\"\n        fi\n    done\n    _ret=\"${options}\"\n}\n\n# get options for checking\n_get_options_for_checking() {\n    local options=\"\"\n    local name=\"\"\n    for name in ${_xmake_sh_options}; do\n        _get_option_item \"${name}\" \"showmenu\"; local showmenu=\"${_ret}\"\n        if test_z \"${showmenu}\" && _option_need_checking \"${name}\"; then\n            options=\"${options} ${name}\"\n        fi\n    done\n    _ret=\"${options}\"\n}\n\n# get abstract flags in option\n_get_option_abstract_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local toolname=\"${3}\"\n    local itemname=\"${4}\"\n    local values=\"${5}\"\n    if test_z \"${values}\"; then\n        _get_option_item \"${name}\" \"${itemname}\"; values=\"${_ret}\"\n    fi\n    _get_abstract_flags \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${values}\"\n}\n\n# is config for option\nis_config() {\n    if ! ${_loading_targets}; then\n        return 1\n    fi\n    local name=${1}\n    local value=${2}\n    _get_option_value \"${name}\"; local value_cur=\"${_ret}\"\n    if test_eq \"${value_cur}\" \"${value}\"; then\n        return 0\n    fi\n    return 1\n}\n\n# has config for option\nhas_config() {\n    if ! ${_loading_targets}; then\n        return 1\n    fi\n    local name=${1}\n    _get_option_value \"${name}\"; local value_cur=\"${_ret}\"\n    if _is_enabled ${value_cur}; then\n        return 0\n    fi\n    return 1\n}\n\n# set config for option, we can use it to modify option status when loading targets\nset_config() {\n    local name=${1}\n    local value=${2}\n    _set_option_value \"${name}\" \"${value}\"\n}\n\n# set showmenu in option\nset_showmenu() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    local show=\"${1}\"\n    _set_option_item \"${_xmake_sh_option_current}\" \"showmenu\" \"${show}\"\n}\n\n# set description in option\nset_description() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    local description=\"${1}\"\n    _set_option_item \"${_xmake_sh_option_current}\" \"description\" \"${description}\"\n}\n\n# add cfuncs in option\nadd_cfuncs() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"cfuncs\" \"${@}\"\n}\n\n# add cxxfuncs in option\nadd_cxxfuncs() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"cxxfuncs\" \"${@}\"\n}\n\n# add cincludes in option\nadd_cincludes() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"cincludes\" \"${@}\"\n}\n\n# add cxxincludes in option\nadd_cxxincludes() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"cxxincludes\" \"${@}\"\n}\n\n# add ctypes in option\nadd_ctypes() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"ctypes\" \"${@}\"\n}\n\n# add cxxtypes in option\nadd_cxxtypes() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    _add_option_item \"${_xmake_sh_option_current}\" \"cxxtypes\" \"${@}\"\n}\n\n# add csnippets in option\nadd_csnippets() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    local csnippets=\"${1}\"\n    _add_option_item \"${_xmake_sh_option_current}\" \"csnippets\" \"${csnippets}\"\n}\n\n# add cxxsnippets in option\nadd_cxxsnippets() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    local cxxsnippets=\"${1}\"\n    _add_option_item \"${_xmake_sh_option_current}\" \"cxxsnippets\" \"${cxxsnippets}\"\n}\n\n# before_check in option\nbefore_check() {\n    if ! ${_loading_options}; then\n        return\n    fi\n    local funcname=\"${1}\"\n    _add_option_item \"${_xmake_sh_option_current}\" \"before_check\" \"${funcname}\"\n}\n\n#-----------------------------------------------------------------------------\n# target configuration apis\n#\n\n# define target\ntarget() {\n    local name=\"${1}\"\n    _xmake_sh_target_current=\"${name}\"\n    if ! ${_loading_targets}; then\n        return\n    fi\n    if ! _map_has \"targets\" \"${name}_name\"; then\n        _xmake_sh_targets=\"${_xmake_sh_targets} ${name}\"\n    fi\n    _map_set \"targets\" \"${name}_name\" \"${name}\"\n    return 0\n}\ntarget_end() {\n    _xmake_sh_target_current=\"\"\n}\n_map \"targets\"\n\n# has the given target?\n_has_target() {\n    local name=${1}\n    if _map_has \"targets\" \"${name}_name\"; then\n        return 0\n    fi\n    return 1\n}\n\n# has the given target item\n_has_target_item() {\n    local name=${1}\n    local key=${2}\n    if _map_has \"targets\" \"${name}_${key}\"; then\n        return 0\n    elif _map_has \"targets\" \"__root_${key}\"; then\n        return 0\n    fi\n    return 1\n}\n\n# get the given target item\n_get_target_item() {\n    local name=${1}\n    local key=${2}\n    _map_get \"targets\" \"${name}_${key}\"\n    local values=\"${_ret}\"\n    if _map_has \"targets\" \"__root_${key}\"; then\n        _map_get \"targets\" \"__root_${key}\"; local root_values=\"${_ret}\"\n        if test_nz \"${values}\"; then\n            values=\"${root_values} ${values}\"\n        else\n            values=\"${root_values}\"\n        fi\n    fi\n    _ret=\"${values}\"\n}\n\n# set the given target item\n_set_target_item() {\n    local name=${1}\n    local key=${2}\n    shift\n    shift\n    if test_nz \"${name}\"; then\n        _map_set \"targets\" \"${name}_${key}\" \"${@}\"\n    else\n        _map_set \"targets\" \"__root_${key}\" \"${@}\"\n    fi\n}\n\n# add values to the given target item\n_add_target_item() {\n    local name=${1}\n    local key=${2}\n    shift\n    shift\n    if test_nz \"${name}\"; then\n        _map_get \"targets\" \"${name}_${key}\"; local values=\"${_ret}\"\n        values=\"${values} ${@}\"\n        _map_set \"targets\" \"${name}_${key}\" \"${values}\"\n    else\n        _map_get \"targets\" \"__root_${key}\"; local values=\"${_ret}\"\n        values=\"${values} ${@}\"\n        _map_set \"targets\" \"__root_${key}\" \"${values}\"\n    fi\n}\n\n# is default?\n_is_target_default() {\n    local name=\"${1}\"\n    if _has_target_item \"${name}\" \"default\"; then\n        _get_target_item \"${target}\" \"default\"; local default=\"${_ret}\"\n        if _is_enabled ${default}; then\n            return 0\n        fi\n        return 1\n    fi\n    return 0\n}\n\n# get target basename\n_get_target_basename() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"basename\"; local basename=\"${_ret}\"\n    if test_z \"${basename}\"; then\n        basename=\"${name}\"\n    fi\n    _ret=\"${basename}\"\n}\n\n# get target extension\n_get_target_extension() {\n    local name=\"${1}\"\n    local extension=\"\"\n    if _has_target_item \"${name}\" \"extension\"; then\n        _get_target_item \"${name}\" \"extension\"; extension=\"${_ret}\"\n    elif is_plat \"mingw\"; then\n        _get_target_item \"${name}\" \"kind\"; local kind=\"${_ret}\"\n        if test \"x${kind}\" = \"xbinary\"; then\n            extension=\".exe\"\n        elif test \"x${kind}\" = \"xstatic\"; then\n            extension=\".a\"\n        elif test \"x${kind}\" = \"xshared\"; then\n            extension=\".dll\"\n        fi\n    else\n        _get_target_item \"${name}\" \"kind\"; local kind=\"${_ret}\"\n        if test \"x${kind}\" = \"xstatic\"; then\n            extension=\".a\"\n        elif test \"x${kind}\" = \"xshared\"; then\n            if is_plat \"macosx\"; then\n                extension=\".dylib\"\n            else\n                extension=\".so\"\n            fi\n        fi\n    fi\n    _ret=\"${extension}\"\n}\n\n# get target prefixname\n_get_target_prefixname() {\n    local name=\"${1}\"\n    local prefixname=\"\"\n    if _has_target_item \"${name}\" \"prefixname\"; then\n        _get_target_item \"${name}\" \"prefixname\"; prefixname=\"${_ret}\"\n    elif is_plat \"mingw\"; then\n        _get_target_item \"${name}\" \"kind\"; local kind=\"${_ret}\"\n        if test \"x${kind}\" = \"xstatic\"; then\n            prefixname=\"lib\"\n        elif test \"x${kind}\" = \"xshared\"; then\n            prefixname=\"lib\"\n        fi\n    else\n        _get_target_item \"${name}\" \"kind\"; local kind=\"${_ret}\"\n        if test \"x${kind}\" = \"xstatic\"; then\n            prefixname=\"lib\"\n        elif test \"x${kind}\" = \"xshared\"; then\n            prefixname=\"lib\"\n        fi\n    fi\n    _ret=\"${prefixname}\"\n}\n\n# get target filename\n_get_target_filename() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"filename\"; local filename=\"${_ret}\"\n    if test_z \"${filename}\"; then\n        _get_target_basename \"${name}\"; local basename=\"${_ret}\"\n        _get_target_extension \"${name}\"; local extension=\"${_ret}\"\n        _get_target_prefixname \"${name}\"; local prefixname=\"${_ret}\"\n        filename=\"${prefixname}${basename}${extension}\"\n    fi\n    _ret=\"${filename}\"\n}\n\n# get target soname\n# @see https://github.com/tboox/tbox/issues/214\n#\n# set_version \"1.0.1\" \"\" \"1\" -> libfoo.so.1, libfoo.1.dylib\n# set_version \"1.0.1\" \"\" \"A\" -> libfoo.so.A, libfoo.A.dylib\n_get_target_soname() {\n    local soname=\"\"\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\" && is_plat \"macosx\" \"linux\" \"bsd\"; then\n        _get_target_item \"${name}\" \"version\"; local version=\"${_ret}\"\n        _get_target_item \"${name}\" \"version_soname\"; local version_soname=\"${_ret}\"\n        if test_nz \"${version}\" && test_nz \"${version_soname}\"; then\n            _get_target_filename \"${name}\"; soname=\"${_ret}\"\n            _get_target_extension \"${name}\"; local extension=\"${_ret}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${soname}\"; local basename=\"${_ret}\"\n                soname=\"${basename}.${version_soname}${extension}\"\n            else\n                soname=\"${soname}.${version_soname}\"\n            fi\n        fi\n    fi\n    _ret=\"${soname}\"\n}\n\n# get target directory\n_get_targetdir() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"targetdir\"; local targetdir=\"${_ret}\"\n    if test_z \"${targetdir}\"; then\n        targetdir=\"${xmake_sh_builddir}/${_target_plat}/${_target_arch}/${_target_mode}\"\n    fi\n    _ret=\"${targetdir}\"\n}\n\n# get target object directory\n_get_target_objectdir() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"objectdir\"; local objectdir=\"${_ret}\"\n    if test_z \"${objectdir}\"; then\n        objectdir=\"${xmake_sh_builddir}/.objs/${name}/${_target_plat}/${_target_arch}/${_target_mode}\"\n    fi\n    _ret=\"${objectdir}\"\n}\n\n# get target file path\n_get_target_file() {\n    local name=\"${1}\"\n    _get_target_filename \"${name}\"; local filename=\"${_ret}\"\n    _get_targetdir \"${name}\"; local targetdir=\"${_ret}\"\n    local targetfile=\"${targetdir}/${filename}\"\n    _ret=\"${targetfile}\"\n}\n\n# get target librarydeps\n_get_target_librarydeps_impl() {\n    local name=\"${1}\"\n    local librarydeps=\"\"\n    local dep=\"\"\n    _get_target_item \"${name}\" \"deps\"; local deps=\"${_ret}\"\n    for dep in ${deps}; do\n        _get_target_item \"${dep}\" \"kind\"; local dep_kind=\"${_ret}\"\n        if test_eq \"${dep_kind}\" \"static\" || test_eq \"${dep_kind}\" \"shared\"; then\n            librarydeps=\"${librarydeps} ${dep}\"\n            _get_target_librarydeps_impl \"${dep}\"; local dep_librarydeps=\"${_ret}\"\n            if test_nz \"${dep_librarydeps}\"; then\n                librarydeps=\"${librarydeps} ${dep_librarydeps}\"\n            fi\n        fi\n    done\n    _ret=\"${librarydeps}\"\n}\n\n_get_target_librarydeps() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"librarydeps\"; local librarydeps=\"${_ret}\"\n    if test_z \"${librarydeps}\" && test_nq \"${librarydeps}\" \"__none__\"; then\n        _get_target_librarydeps_impl \"${name}\"; librarydeps=\"${_ret}\"\n        if test_nz \"${librarydeps}\"; then\n            _dedup_reverse \"${librarydeps}\"; librarydeps=\"${_ret}\"\n            _set_target_item \"${name}\" \"librarydeps\" \"${librarydeps}\"\n        else\n            _set_target_item \"${name}\" \"librarydeps\" \"__none__\"\n        fi\n    fi\n    if test_eq \"${librarydeps}\" \"__none__\"; then\n        librarydeps=\"\"\n    fi\n    _ret=\"${librarydeps}\"\n}\n\n# get sourcefiles in target\n_get_target_sourcefiles() {\n    local name=\"${1}\"\n    _get_target_item \"${name}\" \"files\"\n}\n\n# get objectfile in target\n_get_target_objectfile() {\n    local name=\"${1}\"\n    local sourcefile=\"${2}\"\n    local extension=\".o\"\n    if is_plat \"mingw\"; then\n        extension=\".obj\"\n    fi\n    _get_target_objectdir \"${name}\"; local objectdir=\"${_ret}\"\n    local objectfile=\"${objectdir}/${sourcefile}${extension}\"\n    _ret=\"${objectfile}\"\n}\n\n# get objectfiles in target\n_get_target_objectfiles() {\n    local name=\"${1}\"\n    _get_target_sourcefiles \"${name}\"; local sourcefiles=\"${_ret}\"\n    local objectfiles=\"\"\n    local sourcefile=\"\"\n    for sourcefile in ${sourcefiles}; do\n        _get_target_objectfile \"${name}\" \"${sourcefile}\"; local objectfile=\"${_ret}\"\n        objectfiles=\"${objectfiles} ${objectfile}\"\n    done\n    _ret=\"${objectfiles}\"\n}\n\n# get abstract flags in target\n_get_target_abstract_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local toolname=\"${3}\"\n    local itemname=\"${4}\"\n    local values=\"${5}\"\n    if test_z \"${values}\"; then\n\n        # get values from target\n        _get_target_item \"${name}\" \"${itemname}\"; values=\"${_ret}\"\n\n        # get values from target deps\n        _get_target_librarydeps \"${name}\"; local deps=\"${_ret}\"\n        local dep=\"\"\n        for dep in ${deps}; do\n            _get_target_item \"${dep}\" \"kind\"; local dep_kind=\"${_ret}\"\n            if test_eq \"${dep_kind}\" \"static\" || test_eq \"${dep_kind}\" \"shared\"; then\n                _get_target_item \"${dep}\" \"${itemname}_public\"; local depvalues=\"${_ret}\"\n                if test_nz \"${depvalues}\"; then\n                    values=\"${values} ${depvalues}\"\n                fi\n            fi\n        done\n    fi\n    if test_nz \"${values}\"; then\n        _get_abstract_flags \"${toolkind}\" \"${toolname}\" \"${itemname}\" \"${values}\"\n    else\n        _ret=\"\"\n    fi\n}\n\n# get toolchain flags for ar in target\n_get_target_toolchain_flags_for_ar() {\n    _ret=\"-cr\"\n}\n\n# get toolchain flags for gcc in target\n_get_target_toolchain_flags_for_gcc() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local flags=\"\"\n    if is_arch \"i386\"; then\n        flags=\"${flags} -m32\"\n    fi\n    _get_target_item \"${name}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        if test_eq \"${toolkind}\" \"sh\"; then\n            flags=\"${flags} -shared -fPIC\"\n        elif test_eq \"${toolkind}\" \"cc\" || test_eq \"${toolkind}\" \"cxx\"; then\n            flags=\"${flags} -fPIC\"\n        fi\n        # @see https://github.com/tboox/tbox/issues/214\n        if test_eq \"${toolkind}\" \"sh\"; then\n            _get_target_soname \"${name}\"; local soname=\"${_ret}\"\n            if test_nz \"${soname}\"; then\n                if is_plat \"macosx\"; then\n                    flags=\"${flags} -Wl,-install_name,${soname}\"\n                else\n                    flags=\"${flags} -Wl,-soname,${soname}\"\n                fi\n            fi\n        fi\n    fi\n    _ret=\"${flags}\"\n}\n\n# get macOS sysroot and target flags for clang\n# usage: _get_macosx_sysroot_flags [quoted]\n# if quoted is \"quoted\", the sysroot path will be wrapped in escaped quotes (for eval)\n_get_macosx_sysroot_flags() {\n    local flags=\"\"\n    if is_plat \"macosx\"; then\n        _os_iorunv \"xcrun\" \"-sdk\" \"macosx\" \"--show-sdk-path\"; local sdkdir=\"${_ret}\"\n        if test_nz \"${sdkdir}\"; then\n            if test_eq \"${1}\" \"quoted\"; then\n                flags=\"${flags} -isysroot \\\"${sdkdir}\\\"\"\n            else\n                flags=\"${flags} -isysroot ${sdkdir}\"\n            fi\n            path_basename \"${sdkdir}\"; local basename=\"${_ret}\"\n            if test_nz \"${basename}\" && string_startswith \"${basename}\" \"MacOSX\"; then\n                string_replace \"${basename}\" \"MacOSX\" \"\"; local target_minver=\"${_ret}\"\n                if test_nz \"${target_minver}\"; then\n                    flags=\"${flags} -target ${_target_arch}-apple-macos${target_minver}\"\n                fi\n            fi\n        fi\n    fi\n    _ret=\"${flags}\"\n}\n\n# get toolchain flags for clang in target\n_get_target_toolchain_flags_for_clang() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local flags=\"-Qunused-arguments\"\n    if is_arch \"i386\"; then\n        flags=\"${flags} -m32\"\n    fi\n    _get_target_item \"${name}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        if test_eq \"${toolkind}\" \"sh\"; then\n            flags=\"${flags} -shared -fPIC\"\n        elif test_eq \"${toolkind}\" \"cc\" || test_eq \"${toolkind}\" \"cxx\"; then\n            flags=\"${flags} -fPIC\"\n        fi\n        # @see https://github.com/tboox/tbox/issues/214\n        if test_eq \"${toolkind}\" \"sh\"; then\n            _get_target_soname \"${name}\"; local soname=\"${_ret}\"\n            if test_nz \"${soname}\"; then\n                if is_plat \"macosx\"; then\n                    flags=\"${flags} -Wl,-install_name,${soname}\"\n                else\n                    flags=\"${flags} -Wl,-soname,${soname}\"\n                fi\n            fi\n        fi\n    fi\n    # set target and sysroot\n    _get_macosx_sysroot_flags \"quoted\"; flags=\"${flags}${_ret}\"\n    _ret=\"${flags}\"\n}\n\n# get toolchain flags for tcc in target\n_get_target_toolchain_flags_for_tcc() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local flags=\"\"\n    if is_arch \"i386\"; then\n        flags=\"${flags} -m32\"\n    fi\n    _get_target_item \"${name}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        if test_eq \"${toolkind}\" \"sh\"; then\n            flags=\"${flags} -shared -fPIC\"\n        elif test_eq \"${toolkind}\" \"cc\" || test_eq \"${toolkind}\" \"cxx\"; then\n            flags=\"${flags} -fPIC\"\n        fi\n        # @see https://github.com/tboox/tbox/issues/214\n        if test_eq \"${toolkind}\" \"sh\"; then\n            _get_target_soname \"${name}\"; local soname=\"${_ret}\"\n            if test_nz \"${soname}\"; then\n                if is_plat \"macosx\"; then\n                    flags=\"${flags} -Wl,-install_name,${soname}\"\n                else\n                    flags=\"${flags} -Wl,-soname,${soname}\"\n                fi\n            fi\n        fi\n    fi\n    # set target and sysroot\n    _get_macosx_sysroot_flags \"quoted\"; flags=\"${flags}${_ret}\"\n    _ret=\"${flags}\"\n}\n\n# get toolchain flags in target\n_get_target_toolchain_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local toolname=\"${3}\"\n    local flags=\"\"\n    case \"${toolname}\" in\n        gcc) _get_target_toolchain_flags_for_gcc \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        gxx) _get_target_toolchain_flags_for_gcc \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        clang) _get_target_toolchain_flags_for_clang \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        clangxx) _get_target_toolchain_flags_for_clang \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        emcc) _get_target_toolchain_flags_for_clang \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        emxx) _get_target_toolchain_flags_for_clang \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        cosmocc) _get_target_toolchain_flags_for_gcc \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        cosmocxx) _get_target_toolchain_flags_for_gcc \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        tcc) _get_target_toolchain_flags_for_tcc \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        ar) _get_target_toolchain_flags_for_ar \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        emar) _get_target_toolchain_flags_for_ar \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        cosmoar) _get_target_toolchain_flags_for_ar \"${name}\" \"${toolkind}\"; flags=\"${_ret}\";;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n    _ret=\"${flags}\"\n}\n\n# get compiler flags in target\n_get_target_compiler_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    local result=\"\"\n\n    # get toolchain flags\n    _get_target_toolchain_flags \"${name}\" \"${toolkind}\" \"${toolname}\"; local toolchain_flags=\"${_ret}\"\n    if test_nz \"${toolchain_flags}\"; then\n        result=\"${result} ${toolchain_flags}\"\n    fi\n\n    # get abstract flags\n    local itemnames=\"symbols optimizes warnings languages defines undefines includedirs frameworkdirs frameworks\"\n    local itemname=\"\"\n    for itemname in ${itemnames}; do\n        _get_target_abstract_flags \"${name}\" \"${toolkind}\" \"${toolname}\" \"${itemname}\"; local flags=\"${_ret}\"\n        if test_nz \"${flags}\"; then\n            result=\"${result} ${flags}\"\n        fi\n    done\n\n    # get raw flags, e.g. add_cflags, add_cxxflags\n    _get_flagname \"${toolkind}\"; local flagname=\"${_ret}\"\n    _get_target_item \"${name}\" \"${flagname}\"; local flags=\"${_ret}\"\n    # get flags from target deps\n    _get_target_librarydeps \"${name}\"; local deps=\"${_ret}\"\n    local dep=\"\"\n    for dep in ${deps}; do\n        _get_target_item \"${dep}\" \"kind\"; local dep_kind=\"${_ret}\"\n        if test_eq \"${dep_kind}\" \"static\" || test_eq \"${dep_kind}\" \"shared\"; then\n            _get_target_item \"${dep}\" \"${flagname}_public\"; local depflags=\"${_ret}\"\n            if test_nz \"${depflags}\"; then\n                flags=\"${flags} ${depflags}\"\n            fi\n        fi\n    done\n    if test_nz \"${flags}\"; then\n        result=\"${result} ${flags}\"\n    fi\n    if test_eq \"${flagname}\" \"cflags\" || test_eq \"${flagname}\" \"cxxflags\"; then\n        _get_target_item \"${name}\" \"cxflags\"; flags=\"${_ret}\"\n        if test_nz \"${flags}\"; then\n            result=\"${result} ${flags}\"\n        fi\n    elif test_eq \"${flagname}\" \"mflags\" || test_eq \"${flagname}\" \"mxxflags\"; then\n        _get_target_item \"${name}\" \"mxflags\"; flags=\"${_ret}\"\n        if test_nz \"${flags}\"; then\n            result=\"${result} ${flags}\"\n        fi\n    fi\n\n    # get flags from environments, e.g. $CFLAGS, $CXXFLAGS\n    if test_nz \"${CPPFLAGS}\"; then\n        result=\"${result} ${CPPFLAGS}\"\n    fi\n    if test_eq \"${flagname}\" \"cflags\" && test_nz \"${CFLAGS}\"; then\n        result=\"${result} ${CFLAGS}\"\n    fi\n    if test_eq \"${flagname}\" \"cxxflags\" && test_nz \"${CXXFLAGS}\"; then\n        result=\"${result} ${CXXFLAGS}\"\n    fi\n    if test_eq \"${flagname}\" \"mflags\" && test_nz \"${MFLAGS}\"; then\n        result=\"${result} ${MFLAGS}\"\n    fi\n    if test_eq \"${flagname}\" \"mxxflags\" && test_nz \"${MXXFLAGS}\"; then\n        result=\"${result} ${MXXFLAGS}\"\n    fi\n    _ret=\"${result}\"\n}\n\n# get linker flags in target\n_get_target_linker_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    local result=\"\"\n\n    # get toolchain flags\n    _get_target_toolchain_flags \"${name}\" \"${toolkind}\" \"${toolname}\"; local toolchain_flags=\"${_ret}\"\n    if test_nz \"${toolchain_flags}\"; then\n        result=\"${result} ${toolchain_flags}\"\n    fi\n\n    # get flags from target deps\n    _get_target_librarydeps \"${name}\"; local deps=\"${_ret}\"\n    local dep=\"\"\n    for dep in ${deps}; do\n        _get_target_item \"${dep}\" \"kind\"; local dep_kind=\"${_ret}\"\n        if test_eq \"${dep_kind}\" \"static\" || test_eq \"${dep_kind}\" \"shared\"; then\n            _get_targetdir \"${dep}\"; local dep_targetdir=\"${_ret}\"\n            _get_target_basename \"${dep}\"; local dep_basename=\"${_ret}\"\n            _get_target_abstract_flags \"${dep}\" \"${toolkind}\" \"${toolname}\" \"linkdirs\" \"${dep_targetdir}\"; local linkdirs_flags=\"${_ret}\"\n            _get_target_abstract_flags \"${dep}\" \"${toolkind}\" \"${toolname}\" \"links\" \"${dep_basename}\"; local links_flags=\"${_ret}\"\n            if test_eq \"${dep_kind}\" \"shared\"; then\n                local rpathdir=\"@loader_path\"\n                _get_targetdir \"${name}\"; local targetdir=\"${_ret}\"\n                path_relative \"${targetdir}\" \"${dep_targetdir}\"; local subdir=\"${_ret}\"\n                if test_nz \"${subdir}\"; then\n                    rpathdir=\"${rpathdir}/${subdir}\"\n                fi\n                _get_target_abstract_flags \"${dep}\" \"${toolkind}\" \"${toolname}\" \"rpathdirs\" \"${rpathdir}\"; local rpathdirs_flags=\"${_ret}\"\n                result=\"${result} ${rpathdirs_flags}\"\n            fi\n            result=\"${result} ${linkdirs_flags} ${links_flags}\"\n        fi\n    done\n\n    # get abstract flags\n    local itemnames=\"strip frameworkdirs linkdirs links rpathdirs frameworks syslinks\"\n    local itemname=\"\"\n    for itemname in ${itemnames}; do\n        _get_target_abstract_flags \"${name}\" \"${toolkind}\" \"${toolname}\" \"${itemname}\"; local flags=\"${_ret}\"\n        if test_nz \"${flags}\"; then\n            result=\"${result} ${flags}\"\n        fi\n    done\n\n    # get raw flags, e.g. add_ldflags, add_shflags\n    _get_flagname \"${toolkind}\"; local flagname=\"${_ret}\"\n    _get_target_item \"${name}\" \"${flagname}\"; local flags=\"${_ret}\"\n    # get flags from target deps\n    for dep in ${deps}; do\n        _get_target_item \"${dep}\" \"kind\"; local dep_kind=\"${_ret}\"\n        if test_eq \"${dep_kind}\" \"static\" || test_eq \"${dep_kind}\" \"shared\"; then\n            _get_target_item \"${dep}\" \"${flagname}_public\"; local depflags=\"${_ret}\"\n            if test_nz \"${depflags}\"; then\n                flags=\"${flags} ${depflags}\"\n            fi\n        fi\n    done\n    if test_nz \"${flags}\"; then\n        result=\"${result} ${flags}\"\n    fi\n\n    # get flags from environments, e.g. $LDFLAGS\n    if test_eq \"${flagname}\" \"ldflags\" && test_nz \"${LDFLAGS}\"; then\n        result=\"${result} ${LDFLAGS}\"\n    fi\n    if test_eq \"${flagname}\" \"shflags\" && test_nz \"${LDFLAGS}\"; then\n        result=\"${result} ${LDFLAGS}\"\n    fi\n    _ret=\"${result}\"\n}\n\n# get archiver flags in target\n_get_target_archiver_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    local result=\"\"\n\n    # get toolchain flags\n    _get_target_toolchain_flags \"${name}\" \"${toolkind}\" \"${toolname}\"; local toolchain_flags=\"${_ret}\"\n    if test_nz \"${toolchain_flags}\"; then\n        result=\"${result} ${toolchain_flags}\"\n    fi\n\n    # get raw flags, e.g. add_arflags\n    _get_flagname \"${toolkind}\"; local flagname=\"${_ret}\"\n    _get_target_item \"${name}\" \"${flagname}\"; local flags=\"${_ret}\"\n    if test_nz \"${flags}\"; then\n        result=\"${result} ${flags}\"\n    fi\n\n    _ret=\"${result}\"\n}\n\n# get target flags\n_get_target_flags() {\n    local name=\"${1}\"\n    local toolkind=\"${2}\"\n    local flags=\"\"\n    if test_eq \"${toolkind}\" \"sh\"; then\n        _get_target_linker_flags \"${name}\" \"${toolkind}\"; flags=\"${_ret}\"\n    elif test_eq \"${toolkind}\" \"ld\"; then\n        _get_target_linker_flags \"${name}\" \"${toolkind}\"; flags=\"${_ret}\"\n    elif test_eq \"${toolkind}\" \"ar\"; then\n        _get_target_archiver_flags \"${name}\" \"${toolkind}\"; flags=\"${_ret}\"\n    else\n        _get_target_compiler_flags \"${name}\" \"${toolkind}\"; flags=\"${_ret}\"\n    fi\n    _ret=\"${flags}\"\n}\n\n# add file paths in target\n_add_target_filepaths() {\n    local key=\"$1\"\n    shift\n    # we need avoid escape `*` automatically in for-loop\n    local file=\"\"\n    string_replace \"${@}\" \"\\*\" \"?\"; local list=\"${_ret}\"\n    if test_eq \"${key}\" \"files\"; then\n        for file in ${list}; do\n            path_sourcekind \"${file}\"; local sourcekind=\"${_ret}\"\n            _targets_toolkinds=\"${_targets_toolkinds} ${sourcekind}\"\n        done\n    fi\n    for file in ${list}; do\n        string_replace \"${file}\" \"?\" \"*\"; file=\"${_ret}\"\n        if ! path_is_absolute \"${file}\"; then\n            file=\"${xmake_sh_scriptdir}/${file}\"\n        fi\n        local files=\"\"\n        if string_contains_star2 \"${file}\"; then\n            path_directory \"${file}\"; local dir=\"${_ret}\"\n            path_filename_fromdir \"${file}\" \"${dir}\"; local name=\"${_ret}\"\n            _os_find \"${dir}\" \"${name}\"; files=\"${_ret}\"\n        elif string_contains_star \"${file}\"; then\n            path_directory \"${file}\"; local dir=\"${_ret}\"\n            path_filename_fromdir \"${file}\" \"${dir}\"; local name=\"${_ret}\"\n            _os_find \"${dir}\" \"${name}\" 1; files=\"${_ret}\"\n        else\n            files=\"${file}\"\n        fi\n        for file in ${files}; do\n            path_relative \"${xmake_sh_projectdir}\" \"${file}\"; file=\"${_ret}\"\n            _add_target_item \"${_xmake_sh_target_current}\" \"${key}\" \"${file}\"\n        done\n    done\n}\n\n# add install paths in target\n_add_target_installpaths() {\n    local key=\"$1\"\n    local filepattern=\"${2}\"\n    local prefixdir=\"${3}\"\n    local filename=${4}\n\n    # get root directory, e.g. \"src/foo/(*.h)\" -> \"src/foo\"\n    local rootdir=\"\"\n    if string_contains \"${filepattern}\" \"(\"; then\n        string_split \"${filepattern}\" \"(\" 1; rootdir=\"${_ret}\"\n        rootdir=${rootdir%/}\n        if ! path_is_absolute \"${rootdir}\"; then\n            rootdir=\"${xmake_sh_scriptdir}/${rootdir}\"\n        fi\n        path_relative \"${xmake_sh_projectdir}\" \"${rootdir}\"; rootdir=\"${_ret}\"\n        rootdir=${rootdir%/}\n    fi\n\n    # remove (), e.g. \"src/(*.h)\" -> \"src/*.h\"\n    string_replace ${filepattern} \"(\" \"\"; filepattern=\"${_ret}\"\n    string_replace ${filepattern} \")\" \"\"; filepattern=\"${_ret}\"\n\n    # get real path\n    if ! path_is_absolute \"${filepattern}\"; then\n        filepattern=\"${xmake_sh_scriptdir}/${filepattern}\"\n    fi\n    local files=\"\"\n    if string_contains_star2 \"${filepattern}\"; then\n        path_directory \"${filepattern}\"; local dir=\"${_ret}\"\n        path_filename_fromdir \"${filepattern}\" \"${dir}\"; local name=\"${_ret}\"\n        _os_find \"${dir}\" \"${name}\"; files=\"${_ret}\"\n    elif string_contains_star \"${filepattern}\"; then\n        path_directory \"${filepattern}\"; local dir=\"${_ret}\"\n        path_filename_fromdir \"${filepattern}\" \"${dir}\"; local name=\"${_ret}\"\n        _os_find \"${dir}\" \"${name}\" 1; files=\"${_ret}\"\n    else\n        files=\"${filepattern}\"\n    fi\n    for file in ${files}; do\n        path_relative \"${xmake_sh_projectdir}\" \"${file}\"; file=\"${_ret}\"\n        _add_target_item \"${_xmake_sh_target_current}\" \"${key}\" \"${file}:${rootdir}:${prefixdir}:${filename}\"\n    done\n}\n\n# set target file path\n_set_target_filepath() {\n    local key=\"${1}\"\n    local path=\"${2}\"\n    if ! path_is_absolute \"${path}\"; then\n        path=\"${xmake_sh_scriptdir}/${path}\"\n    fi\n    path_relative ${xmake_sh_projectdir} \"${path}\"; path=\"${_ret}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"${key}\" \"${path}\"\n}\n\n# set kind in target\nset_kind() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local kind=${1}\n    _set_target_item \"${_xmake_sh_target_current}\" \"kind\" \"${kind}\"\n    case \"${kind}\" in\n        binary) _targets_toolkinds=\"${_targets_toolkinds} ld\";;\n        static) _targets_toolkinds=\"${_targets_toolkinds} ar\";;\n        shared) _targets_toolkinds=\"${_targets_toolkinds} sh\";;\n        *) raise \"unknown target kind ${kind}\";;\n    esac\n}\n\n# set version in target\nset_version() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local version=\"${1}\"\n    local version_build=\"${2}\"\n    local version_soname=\"${3}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"version\" \"${version}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"version_build\" \"${version_build}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"version_soname\" \"${version_soname}\"\n}\n\n# set default in target\nset_default() {\n    local default=${1}\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _set_target_item \"${_xmake_sh_target_current}\" \"default\" \"${default}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _set_option_item \"${_xmake_sh_option_current}\" \"default\" \"${default}\"\n    fi\n}\n\n# set configvar in target\nset_configvar() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local name=\"${1}\"\n    local value=\"${2}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"configvar_${name}\" \"${value}\"\n    _add_target_item \"${_xmake_sh_target_current}\" \"configvars\" \"${name}\"\n}\n\n# set filename in target\nset_filename() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local filename=\"${1}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"filename\" \"${filename}\"\n}\n\n# set basename in target\nset_basename() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local basename=\"${1}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"basename\" \"${basename}\"\n}\n\n# set extension in target\nset_extension() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local extension=${1}\n    _set_target_item \"${_xmake_sh_target_current}\" \"extension\" \"${extension}\"\n}\n\n# set prefixname in target\nset_prefixname() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local prefixname=${1}\n    _set_target_item \"${_xmake_sh_target_current}\" \"prefixname\" \"${prefixname}\"\n}\n\n# set target directory\nset_targetdir() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _set_target_filepath \"targetdir\" \"${1}\"\n}\n\n# set target object directory\nset_objectdir() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _set_target_filepath \"objectdir\" \"${1}\"\n}\n\n# set target config directory\nset_configdir() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _set_target_filepath \"configdir\" \"${1}\"\n}\n\n# set target install directory\nset_installdir() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _set_target_filepath \"installdir\" \"${1}\"\n}\n\n# add deps in target\nadd_deps() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"deps\" \"${@}\"\n}\n\n# add files in target\nadd_files() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_filepaths \"files\" \"$@\"\n}\n\n# add install files in target\nadd_installfiles() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_installpaths \"installfiles\" \"$@\"\n}\n\n# add header files in target\nadd_headerfiles() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_installpaths \"headerfiles\" \"$@\"\n}\n\n# add config files in target\nadd_configfiles() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_filepaths \"configfiles\" \"$@\"\n}\n\n# add defines in target\nadd_defines() {\n    local define=\"\"\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        local public=false\n        for define in $@; do\n            if test_nq \"${define}\" \"{public}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"defines\" \"${define}\"\n            else\n                public=true\n            fi\n        done\n        if ${public}; then\n            for define in $@; do\n                if test_nq \"${define}\" \"{public}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"defines_public\" \"${define}\"\n                fi\n            done\n        fi\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"defines\" \"${@}\"\n    fi\n}\n\n# add undefines in target\nadd_undefines() {\n    local undefine=\"\"\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        local public=false\n        for undefine in $@; do\n            if test_nq \"${undefine}\" \"{public}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"undefines\" \"${undefine}\"\n            else\n                public=true\n            fi\n        done\n        if ${public}; then\n            for undefine in $@; do\n                if test_nq \"${undefine}\" \"{public}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"undefines_public\" \"${undefine}\"\n                fi\n            done\n        fi\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"undefines\" \"${@}\"\n    fi\n}\n\n# add includedirs in target\nadd_includedirs() {\n    local public=false\n    local dir=\"\"\n    for dir in $@; do\n        if test_nq \"${dir}\" \"{public}\"; then\n            if ! path_is_absolute \"${dir}\"; then\n                dir=\"${xmake_sh_scriptdir}/${dir}\"\n            fi\n            if string_startswith \"${dir}\" \"${xmake_sh_projectdir}\"; then\n                path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n            fi\n            if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"includedirs\" \"${dir}\"\n            elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n                _add_option_item \"${_xmake_sh_option_current}\" \"includedirs\" \"${dir}\"\n            fi\n        else\n            public=true\n        fi\n    done\n    if ${public}; then\n        for dir in $@; do\n            if test_nq \"${dir}\" \"{public}\"; then\n                if ! path_is_absolute \"${dir}\"; then\n                    dir=\"${xmake_sh_scriptdir}/${dir}\"\n                fi\n                if string_startswith \"${dir}\" \"${xmake_sh_projectdir}\"; then\n                    path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n                fi\n                if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"includedirs_public\" \"${dir}\"\n                fi\n            fi\n        done\n    fi\n}\n\n# add links in target\nadd_links() {\n    local link=\"\"\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        local public=false\n        for link in $@; do\n            if test_nq \"${link}\" \"{public}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"links\" \"${link}\"\n            else\n                public=true\n            fi\n        done\n        if ${public}; then\n            for link in $@; do\n                if test_nq \"${link}\" \"{public}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"links_public\" \"${link}\"\n                fi\n            done\n        fi\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"links\" \"${@}\"\n    fi\n}\n\n# add syslinks in target\nadd_syslinks() {\n    local syslink=\"\"\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        local public=false\n        for syslink in $@; do\n            if test_nq \"${syslink}\" \"{public}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"syslinks\" \"${syslink}\"\n            else\n                public=true\n            fi\n        done\n        if ${public}; then\n            for syslink in $@; do\n                if test_nq \"${syslink}\" \"{public}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"syslinks_public\" \"${syslink}\"\n                fi\n            done\n        fi\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"syslinks\" \"${@}\"\n    fi\n}\n\n# add linkdirs in target\nadd_linkdirs() {\n    local dir=\"\"\n    local public=false\n    for dir in $@; do\n        if test_nq \"${dir}\" \"{public}\"; then\n            if ! path_is_absolute \"${dir}\"; then\n                dir=\"${xmake_sh_scriptdir}/${dir}\"\n            fi\n            if string_startswith \"${dir}\" \"${xmake_sh_projectdir}\"; then\n                path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n            fi\n            if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"linkdirs\" \"${dir}\"\n            elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n                _add_option_item \"${_xmake_sh_option_current}\" \"linkdirs\" \"${dir}\"\n            fi\n        else\n            public=true\n        fi\n    done\n    if ${public}; then\n        for dir in $@; do\n            if test_nq \"${dir}\" \"{public}\"; then\n                if ! path_is_absolute \"${dir}\"; then\n                    dir=\"${xmake_sh_scriptdir}/${dir}\"\n                fi\n                if string_startswith \"${dir}\" \"${xmake_sh_projectdir}\"; then\n                    path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n                fi\n                if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"linkdirs_public\" \"${dir}\"\n                fi\n            fi\n        done\n    fi\n}\n\n# add rpathdirs in target\nadd_rpathdirs() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local dir=\"\"\n    for dir in $@; do\n        if ! path_is_absolute \"${dir}\"; then\n            dir=\"${xmake_sh_scriptdir}/${dir}\"\n        fi\n        path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n        _add_target_item \"${_xmake_sh_target_current}\" \"rpathdirs\" \"${dir}\"\n    done\n}\n\n# add frameworks in target\nadd_frameworks() {\n    local framework=\"\"\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        local public=false\n        for framework in $@; do\n            if test_nq \"${framework}\" \"{public}\"; then\n                _add_target_item \"${_xmake_sh_target_current}\" \"frameworks\" \"${framework}\"\n            else\n                public=true\n            fi\n        done\n        if ${public}; then\n            for framework in $@; do\n                if test_nq \"${framework}\" \"{public}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"frameworks_public\" \"${framework}\"\n                fi\n            done\n        fi\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"frameworks\" \"${@}\"\n    fi\n}\n\n# add frameworkdirs in target\nadd_frameworkdirs() {\n    local dir=\"\"\n    for dir in $@; do\n        if ! path_is_absolute \"${dir}\"; then\n            dir=\"${xmake_sh_scriptdir}/${dir}\"\n        fi\n        path_relative ${xmake_sh_projectdir} \"${dir}\"; dir=\"${_ret}\"\n        if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n            _add_target_item \"${_xmake_sh_target_current}\" \"frameworkdirs\" \"${dir}\"\n        elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n            _add_option_item \"${_xmake_sh_option_current}\" \"frameworkdirs\" \"${dir}\"\n        fi\n    done\n}\n\n# set strip in target\nset_strip() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local strip=${1}\n    _set_target_item \"${_xmake_sh_target_current}\" \"strip\" \"${strip}\"\n}\n\n# set symbols in target\nset_symbols() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local symbols=\"${1}\"\n    _set_target_item \"${_xmake_sh_target_current}\" \"symbols\" \"${symbols}\"\n}\n\n# set languages in target\nset_languages() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _set_target_item \"${_xmake_sh_target_current}\" \"languages\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _set_option_item \"${_xmake_sh_option_current}\" \"languages\" \"${@}\"\n    fi\n}\n\n# set warnings in target\nset_warnings() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _set_target_item \"${_xmake_sh_target_current}\" \"warnings\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _set_option_item \"${_xmake_sh_option_current}\" \"warnings\" \"${@}\"\n    fi\n}\n\n# set optimizes in target\nset_optimizes() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _set_target_item \"${_xmake_sh_target_current}\" \"optimizes\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _set_option_item \"${_xmake_sh_option_current}\" \"optimizes\" \"${@}\"\n    fi\n}\n\n# add cflags in target\nadd_cflags() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _add_target_item \"${_xmake_sh_target_current}\" \"cflags\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"cflags\" \"${@}\"\n    fi\n}\n\n# add cxflags in target\nadd_cxflags() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _add_target_item \"${_xmake_sh_target_current}\" \"cxflags\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"cxflags\" \"${@}\"\n    fi\n}\n\n# add cxxflags in target\nadd_cxxflags() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _add_target_item \"${_xmake_sh_target_current}\" \"cxxflags\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"cxxflags\" \"${@}\"\n    fi\n}\n\n# add asflags in target\nadd_asflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"asflags\" \"${@}\"\n}\n\n# add mflags in target\nadd_mflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"mflags\" \"${@}\"\n}\n\n# add mxflags in target\nadd_mxflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"mxflags\" \"${@}\"\n}\n\n# add mxxflags in target\nadd_mxxflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"mxxflags\" \"${@}\"\n}\n\n# add ldflags in target\nadd_ldflags() {\n    if ${_loading_targets} && test_z \"${_xmake_sh_option_current}\"; then\n        _add_target_item \"${_xmake_sh_target_current}\" \"ldflags\" \"${@}\"\n    elif ${_loading_options} && test_nz \"${_xmake_sh_option_current}\"; then\n        _add_option_item \"${_xmake_sh_option_current}\" \"ldflags\" \"${@}\"\n    fi\n}\n\n# add shflags in target\nadd_shflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"shflags\" \"${@}\"\n}\n\n# add arflags in target\nadd_arflags() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    _add_target_item \"${_xmake_sh_target_current}\" \"arflags\" \"${@}\"\n}\n\n# add options in target\nadd_options() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local name=\"\"\n    local public=false\n    for name in $@; do\n        if test_nq \"${name}\" \"{public}\"; then\n            public=true\n            break\n        fi\n    done\n    for name in $@; do\n        if has_config \"${name}\"; then\n            local itemname=\"\"\n            local itemnames=\"includedirs linkdirs links defines cflags cxflags cxxflags ldflags\"\n            for itemname in ${itemnames}; do\n                _get_option_item \"${name}\" \"${itemname}\"; local values=\"${_ret}\"\n                if test_nz \"${values}\"; then\n                    _add_target_item \"${_xmake_sh_target_current}\" \"${itemname}\" \"${values}\"\n                    if $public; then\n                        _add_target_item \"${_xmake_sh_target_current}\" \"${itemname}_public\" \"${values}\"\n                    fi\n                fi\n            done\n        fi\n    done\n}\n\n# before_install in target\nbefore_install() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local funcname=\"${1}\"\n    _add_target_item \"${_xmake_sh_target_current}\" \"before_install\" \"${funcname}\"\n}\n\n# after_install in target\nafter_install() {\n    if ! ${_loading_targets}; then\n        return\n    fi\n    local funcname=\"${1}\"\n    _add_target_item \"${_xmake_sh_target_current}\" \"after_install\" \"${funcname}\"\n}\n\n#-----------------------------------------------------------------------------\n# toolchain configuration apis\n#\n\n# define toolchain\ntoolchain() {\n    local name=\"${1}\"\n    _xmake_sh_toolchain_current=\"${name}\"\n    if ! ${_loading_toolchains}; then\n        return\n    fi\n    _xmake_sh_toolchains=\"${_xmake_sh_toolchains} ${name}\"\n    _map_set \"toolchains\" \"${name}_name\" \"${name}\"\n    return 0\n}\ntoolchain_end() {\n    _xmake_sh_toolchain_current=\"\"\n}\n_map \"toolchains\"\n\n# has the given toolchain?\n_has_toolchain() {\n    local name=${1}\n    if _map_has \"toolchains\" \"${name}_name\"; then\n        return 0\n    fi\n    return 1\n}\n\n# get the given toolchain item\n_get_toolchain_item() {\n    local name=${1}\n    local key=${2}\n    _map_get \"toolchains\" \"${name}_${key}\"\n}\n\n# set the given toolchain item\n_set_toolchain_item() {\n    local name=${1}\n    local key=${2}\n    local value=\"${3}\"\n    if test_nz \"${name}\"; then\n        _map_set \"toolchains\" \"${name}_${key}\" \"${value}\"\n    else\n        raise \"please set toolchain in the toolchain scope!\"\n    fi\n}\n\n# get the give toolchain toolset\n_get_toolchain_toolset() {\n    local name=${1}\n    local kind=${2}\n    _get_toolchain_item \"${name}\" \"toolset_${kind}\"\n}\n\n# set the give toolchain toolset\n_set_toolchain_toolset() {\n    local name=${1}\n    local kind=${2}\n    local programs=\"${3}\"\n    _set_toolchain_item \"${name}\" \"toolset_${kind}\" \"${programs}\"\n}\n\n# add the give toolchain toolset\n_add_toolchain_toolset() {\n    local name=${1}\n    local kind=${2}\n    local program=\"${3}\"\n    _get_toolchain_item \"${name}\" \"toolset_${kind}\"; local programs=\"${_ret}\"\n    if test_nz \"${programs}\"; then\n        programs=\"${programs}:${program}\"\n    else\n        programs=\"${program}\"\n    fi\n    _set_toolchain_item \"${name}\" \"toolset_${kind}\" \"${programs}\"\n}\n\n# set toolset in toolchain\nset_toolset() {\n    if ! ${_loading_toolchains}; then\n        return\n    fi\n    local kind=${1}\n    shift\n    local idx=0\n    while test $# != 0; do\n        local program=\"${1}\"\n        local key=\"${kind}\"\n        if test_nq \"${idx}\" \"0\"; then\n            key=\"${key}_${idx}\"\n        fi\n        _set_toolchain_toolset \"${_xmake_sh_toolchain_current}\" \"${key}\" \"${program}\"\n        idx=$((idx+1))\n        shift\n    done\n}\n\n#-----------------------------------------------------------------------------\n# load options\n#\n\n# load options and toolchains\n_load_options_and_toolchains() {\n    _loading_options=true\n    _loading_toolchains=true\n    _loading_targets=false\n    local file=${xmake_sh_projectdir}/xmake.sh\n    if test -f \"${file}\"; then\n        includes \"${file}\"\n    else\n        # include all xmake.sh files in next sub-directories\n        _os_find \"${xmake_sh_projectdir}\" \"xmake.sh\" \"2\"\n        local files=\"${_ret}\"\n        for file in ${files}; do\n            includes \"${file}\"\n        done\n    fi\n}\n_load_options_and_toolchains\n\n# show option usage\n_show_options_usage() {\n    _get_options_for_menu; local options=\"${_ret}\"\n    for name in ${options}; do\n        _get_option_item \"${name}\" \"description\"; local description=\"${_ret}\"\n        _get_option_item \"${name}\" \"default\"; local default=\"${_ret}\"\n        string_toupper ${name}; local head=\"--${name}=\"${_ret}\"\"\n        local headsize=${#head}\n        local tail=\"${description}\"\n        if test \"x${default}\" != \"x\"; then\n            local defval=${default}\n            if test \"x${defval}\" = \"xtrue\"; then\n                defval=\"yes\"\n            elif test \"x${defval}\" = \"xfalse\"; then\n                defval=\"no\"\n            fi\n            tail=\"${tail} (default: ${defval})\"\n        fi\n        local width=24\n        local padding_width=$((${width} - ${headsize}))\n        local padding=$(string_dupch ${padding_width} \" \")\n        echo \"  ${head}${padding}${tail}\"\n    done\n}\n\n# show configure usage\n_show_usage() {\necho '\nUsage: '\"$0\"' [<options>...]\nOptions: [defaults in brackets after descriptions]\nCommon options:\n  --help                  Print this message.\n  --version               Only print version information.\n  --verbose               Display more information.\n  --diagnosis             Display lots of diagnosis information.\n\n  --generator=GENERATOR   Set the project generator. (default: '\"${project_generator}\"')\n                            - gmake\n                            - ninja\n  --make=MAKE             Set the make program. (default: '\"${_make_program_default}\"')\n  --ninja=NINJA           Set the Ninja program. (default: '\"${_ninja_program_default}\"')\n  --plat=PLAT             Compile for the given platform. (default: '\"${_target_plat_default}\"')\n                            - msys\n                            - cross\n                            - bsd\n                            - mingw\n                            - macosx\n                            - linux\n                            - wasm\n  --arch=ARCH             Compile for the given architecture. (default: '\"${_target_arch_default}\"')\n                            - msys: i386 x86_64\n                            - cross: i386 x86_64 arm arm64 mips mips64 riscv riscv64 loong64 s390x ppc ppc64 sh4\n                            - bsd: i386 x86_64\n                            - mingw: i386 x86_64 arm arm64\n                            - macosx: x86_64 arm64\n                            - linux: i386 x86_64 armv7 armv7s arm64-v8a mips mips64 mipsel mips64el\n  --mode=MODE             Set the given compilation mode. (default: '\"${_target_mode_default}\"')\n                            - release\n                            - debug\n  --kind=KIND             Set the given target kind. (default: '\"${_target_kind_default}\"')\n                            - static\n                            - shared\n                            - binary\n  --toolchain=TOOLCHAIN   Set toolchain name.\n                            - clang\n                            - gcc\n                            - emcc\n                            - tinycc\n                            - cosmocc\n  --builddir=DIR           Set build directory. (default: '\"${xmake_sh_builddir}\"')\n\nAutoconf options:\n  --build=BUILD           Configure for building on BUILD [guessed]\n  --host=HOST             Cross-compile to build programs to run on HOST [BUILD]\n  --prefix=PREFIX         Set install files directory in tree rooted at PREFIX. (default: '\"${_install_prefix_default}\"')\n  --bindir=DIR            Set install binaries directory in PREFIX/DIR. (default: '\"${_install_bindir_default}\"')\n  --libdir=DIR            Set install libraries directory in PREFIX/DIR. (default: '\"${_install_libdir_default}\"')\n  --includedir=DIR        Set install includes directory in PREFIX/DIR. (default: '\"${_install_includedir_default}\"')\n\nProject options:\n'\"$(_show_options_usage)\"'\n'\n    exit 1\n}\n\n# show xmake.sh version\n_show_version() {\n    echo \"xmake.sh v${xmake_sh_version}, A script-only build utility like autotools\"\n    echo \"${xmake_sh_copyright}\"\n    echo '                         _               _            '\n    echo \"    __  ___ __  __  __ _| | ______   ___| |__         \"\n    echo \"    \\ \\/ / |  \\/  |/ _  | |/ / __ \\ / __| '_  \\       \"\n    echo \"     >  <  | \\__/ | /_| |   <  ___/_\\__ \\ | | |       \"\n    echo \"    /_/\\_\\_|_|  |_|\\__ \\|_|\\_\\____(_)___/_| |_|       \"\n    echo '                                     by ruki, xmake.io'\n    echo '                                                      '\n    echo '   👉  Manual: https://xmake.io/guide/quick-start     '\n    echo '   🙏  Donate: https://xmake.io/about/sponsor         '\n    echo '                                                      '\n    exit 2\n}\n\n# --foo=yes => foo\n_parse_argument_name() {\n    local arg=\"${1#--}\"\n    case \"${arg}\" in\n        *=*) arg=\"${arg%%=*}\" ;;\n    esac\n    string_replace \"${arg}\" \"-\" \"_\"\n}\n\n# --foo=yes => yes\n_parse_argument_value() {\n    case \"${1}\" in\n        *=*) _ret=\"${1#*=}\" ;;\n        *) _ret=\"\" ;;\n    esac\n}\n\n# parse input arguments\n_handle_option() {\n    _parse_argument_name ${1}; local name=\"${_ret}\"\n    _parse_argument_value ${1}; local value=\"${_ret}\"\n    if test_eq \"${name}\" \"help\"; then\n        _show_usage\n        return 0\n    elif test_eq \"${name}\" \"version\"; then\n        _show_version\n        return 0\n    elif test_eq \"${name}\" \"verbose\"; then\n        xmake_sh_verbose=true\n        return 0\n    elif test_eq \"${name}\" \"diagnosis\"; then\n        xmake_sh_diagnosis=true\n        return 0\n    elif test_eq \"${name}\" \"plat\"; then\n        _target_plat=${value}\n        return 0\n    elif test_eq \"${name}\" \"arch\"; then\n        _target_arch=${value}\n        return 0\n    elif test_eq \"${name}\" \"mode\"; then\n        _target_mode=${value}\n        return 0\n    elif test_eq \"${name}\" \"kind\"; then\n        _target_kind=${value}\n        return 0\n    elif test_eq \"${name}\" \"toolchain\"; then\n        _target_toolchain=${value}\n        return 0\n    elif test_eq \"${name}\" \"generator\"; then\n        project_generator=${value}\n        return 0\n    elif test_eq \"${name}\" \"make\"; then\n        _make_program=${value}\n        return 0\n    elif test_eq \"${name}\" \"ninja\"; then\n        _ninja_program=${value}\n        return 0\n    elif test_eq \"${name}\" \"prefix\"; then\n        _install_prefix_default=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"bindir\"; then\n        _install_bindir_default=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"libdir\"; then\n        _install_libdir_default=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"includedir\"; then\n        _install_includedir_default=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"builddir\" || test_eq \"${name}\" \"buildir\"; then\n        xmake_sh_builddir=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"build\"; then\n        _autoconf_build_type=\"${value}\"\n        return 0\n    elif test_eq \"${name}\" \"host\"; then\n        _autoconf_host_type=\"${value}\"\n        return 0\n    elif _has_option \"${name}\"; then\n        _set_option_value \"${name}\" \"${value}\"\n        return 0\n    fi\n    return 1\n}\nwhile test $# != 0; do\n    if ! _handle_option ${1}; then\n        wprint \"unknown option: $1\"\n    fi\n    shift\ndone\n\n#-----------------------------------------------------------------------------\n# handle some autoconf configurations\n#\n\n# parse triplet\n# https://github.com/xmake-io/xmake/issues/3869\n# e.g. i686-linux-gnu, aarch64-apple-darwin, x86_64-w64-mingw32, i686-redhat-linux-gnu\n_parse_triplet() {\n    local triplet=\"${1}\"\n    string_split \"${triplet}\" \"-\"\n}\n\n_get_arch_from_cpu() {\n    local cpu=\"${1}\"\n    case \"${cpu}\" in\n        i686) _ret=\"i386\";;\n        i386) _ret=\"i386\";;\n        x86_64) _ret=\"x86_64\";;\n        aarch64) _ret=\"arm64\";;\n        arm64) _ret=\"arm64\";;\n        arm*) _ret=\"arm\";;\n        *) _ret=\"${cpu}\";;\n    esac\n}\n\n_get_plat_from_vendor_os() {\n    local vendor=\"${1}\"\n    local os=\"${2}\"\n    case \"${vendor}\" in\n        linux)\n            if string_contains \"${os}\" \"android\"; then\n                _ret=\"android\"\n            else\n                _ret=\"linux\"\n            fi\n            ;;\n        apple)\n            if test_eq \"${os}\" \"darwin\"; then\n                _ret=\"macosx\"\n            fi\n            ;;\n        w64) _ret=\"mingw\";;\n        *) _ret=\"${os}\";;\n    esac\n}\n\n_handle_autoconf_configs() {\n    if test_z \"${_autoconf_host_type}\"; then\n        _autoconf_host_type=\"${_autoconf_build_type}\"\n    fi\n\n    if test_nz \"${_autoconf_build_type}\"; then\n        _parse_triplet \"${_autoconf_build_type}\"; local cpu=\"${_ret}\"; local vendor=\"${_ret2}\"; local os=\"${_ret3}\"\n        _get_arch_from_cpu \"${cpu}\"\n        if test_nz \"${_ret}\"; then\n            os_arch=\"${_ret}\"\n        else\n            wprint \"unknown cpu: ${cpu} in --build=${value}\"\n        fi\n        _get_plat_from_vendor_os \"${vendor}\" \"${os}\"\n        if test_nz \"${_ret}\"; then\n            os_host=\"${_ret}\"\n        else\n            wprint \"unknown vendor-os: ${vendor}-${os} in --build=${value}\"\n        fi\n    fi\n\n    if test_nz \"${_autoconf_host_type}\"; then\n        _parse_triplet \"${_autoconf_host_type}\"; local cpu=\"${_ret}\"; local vendor=\"${_ret2}\"; local os=\"${_ret3}\"\n        _get_arch_from_cpu \"${cpu}\"\n        if test_nz \"${_ret}\"; then\n            _target_arch_default=\"${_ret}\"\n        else\n            wprint \"unknown cpu: ${cpu} in --host=${value}\"\n        fi\n        _get_plat_from_vendor_os \"${vendor}\" \"${os}\"\n        if test_nz \"${_ret}\"; then\n            _target_plat_default=\"${_ret}\"\n        else\n            wprint \"unknown vendor-os: ${vendor}-${os} in --build=${value}\"\n        fi\n    fi\n}\n_handle_autoconf_configs\n\n#-----------------------------------------------------------------------------\n# detect platform and toolchains\n#\n\n# envs toolchain\ntoolchain \"envs\"\n    set_toolset \"as\" \"$CC\" \"$CXX\" \"$AS\"\n    set_toolset \"cc\" \"$CC\"\n    set_toolset \"cxx\" \"$CC\" \"$CXX\"\n    set_toolset \"mm\" \"$CC\" \"$CXX\"\n    set_toolset \"mxx\" \"$CC\" \"$CXX\"\n    set_toolset \"ld\" \"$CXX\" \"$CC\" \"$LD\"\n    set_toolset \"sh\" \"$CXX\" \"$CC\" \"$LD\"\n    set_toolset \"ar\" \"$AR\" \"ar\"\ntoolchain_end\n\n# clang toolchain\ntoolchain \"clang\"\n    set_toolset \"as\" \"clang\"\n    set_toolset \"cc\" \"clang\"\n    set_toolset \"cxx\" \"clang\" \"clang++\"\n    set_toolset \"mm\" \"clang\"\n    set_toolset \"mxx\" \"clang\" \"clang++\"\n    set_toolset \"ld\" \"clang++\" \"clang\"\n    set_toolset \"sh\" \"clang++\" \"clang\"\n    set_toolset \"ar\" \"ar\"\ntoolchain_end\n\n# gcc toolchain\ntoolchain \"gcc\"\n    set_toolset \"as\" \"gcc\"\n    set_toolset \"cc\" \"gcc\"\n    set_toolset \"cxx\" \"gcc\" \"g++\"\n    set_toolset \"mm\" \"gcc\"\n    set_toolset \"mxx\" \"gcc\" \"g++\"\n    set_toolset \"ld\" \"g++\" \"gcc\"\n    set_toolset \"sh\" \"g++\" \"gcc\"\n    set_toolset \"ar\" \"ar\"\ntoolchain_end\n\n# mingw toolchain (x86_64)\ntoolchain \"x86_64_w64_mingw32\"\n    set_toolset \"as\" \"x86_64-w64-mingw32-gcc\"\n    set_toolset \"cc\" \"x86_64-w64-mingw32-gcc\"\n    set_toolset \"cxx\" \"x86_64-w64-mingw32-gcc\" \"x86_64-w64-mingw32-g++\"\n    set_toolset \"mm\" \"x86_64-w64-mingw32-gcc\"\n    set_toolset \"mxx\" \"x86_64-w64-mingw32-gcc\" \"x86_64-w64-mingw32-g++\"\n    set_toolset \"ld\" \"x86_64-w64-mingw32-g++\" \"x86_64-w64-mingw32-gcc\"\n    set_toolset \"sh\" \"x86_64-w64-mingw32-g++\" \"x86_64-w64-mingw32-gcc\"\n    set_toolset \"ar\" \"x86_64-w64-mingw32-ar\" \"ar\"\ntoolchain_end\n\n# mingw toolchain (i686)\ntoolchain \"i686_w64_mingw32\"\n    set_toolset \"as\" \"i686-w64-mingw32-gcc\"\n    set_toolset \"cc\" \"i686-w64-mingw32-gcc\"\n    set_toolset \"cxx\" \"i686-w64-mingw32-gcc\" \"i686-w64-mingw32-g++\"\n    set_toolset \"mm\" \"i686-w64-mingw32-gcc\"\n    set_toolset \"mxx\" \"i686-w64-mingw32-gcc\" \"i686-w64-mingw32-g++\"\n    set_toolset \"ld\" \"i686-w64-mingw32-g++\" \"i686-w64-mingw32-gcc\"\n    set_toolset \"sh\" \"i686-w64-mingw32-g++\" \"i686-w64-mingw32-gcc\"\n    set_toolset \"ar\" \"i686-w64-mingw32-ar\" \"ar\"\ntoolchain_end\n\n# aarch64 toolchain (aarch64)\ntoolchain \"aarch64_linux_gnu\"\n    set_toolset \"as\" \"aarch64-linux-gnu-gcc\"\n    set_toolset \"cc\" \"aarch64-linux-gnu-gcc\"\n    set_toolset \"cxx\" \"aarch64-linux-gnu-gcc\" \"aarch64-linux-gnu-g++\"\n    set_toolset \"mm\" \"aarch64-linux-gnu-gcc\"\n    set_toolset \"mxx\" \"aarch64-linux-gnu-gcc\" \"aarch64-linux-gnu-g++\"\n    set_toolset \"ld\" \"aarch64-linux-gnu-g++\" \"aarch64-linux-gnu-gcc\"\n    set_toolset \"sh\" \"aarch64-linux-gnu-g++\" \"aarch64-linux-gnu-gcc\"\n    set_toolset \"ar\" \"aarch64-linux-gnu-ar\" \"ar\"\ntoolchain_end\n\n# emcc toolchain (wasm32)\ntoolchain \"emcc\"\n    set_toolset \"as\" \"emcc\"\n    set_toolset \"cc\" \"emcc\"\n    set_toolset \"cxx\" \"emcc\" \"em++\"\n    set_toolset \"mm\" \"emcc\"\n    set_toolset \"mxx\" \"emcc\" \"em++\"\n    set_toolset \"ld\" \"em++\" \"emcc\"\n    set_toolset \"sh\" \"em++\" \"emcc\"\n    set_toolset \"ar\" \"emar\" \"ar\"\ntoolchain_end\n\n# cosmocc toolchain, e.g. ./configure --plat=linux --toolchain=cosmocc\ntoolchain \"cosmocc\"\n    set_toolset \"as\" \"cosmocc\"\n    set_toolset \"cc\" \"cosmocc\"\n    set_toolset \"cxx\" \"cosmocc\" \"cosmoc++\"\n    set_toolset \"mm\" \"cosmocc\"\n    set_toolset \"mxx\" \"cosmocc\" \"cosmoc++\"\n    set_toolset \"ld\" \"cosmoc++\" \"cosmocc\"\n    set_toolset \"sh\" \"cosmoc++\" \"cosmocc\"\n    set_toolset \"ar\" \"cosmoar\"\ntoolchain_end\n\n# tinycc toolchain\ntoolchain \"tinycc\"\n    set_toolset \"as\" \"tcc\" \"gcc\" \"clang\"\n    set_toolset \"cc\" \"tcc\"\n    set_toolset \"cxx\" \"gcc\" \"g++\" \"clang\" \"clang++\"\n    set_toolset \"mm\" \"gcc\" \"clang\"\n    set_toolset \"mxx\" \"gcc\" \"g++\" \"clang\" \"clang++\"\n    set_toolset \"ld\" \"tcc\"\n    set_toolset \"sh\" \"tcc\"\n    set_toolset \"ar\" \"tcc -ar\" \"ar\"\ntoolchain_end\n\n# check platform\n_check_platform() {\n    if test \"x${_target_plat}\" = \"x\"; then\n        _target_plat=${_target_plat_default}\n    fi\n    if test \"x${_target_arch}\" = \"x\"; then\n        _target_arch=${_target_arch_default}\n    fi\n    if test \"x${_target_mode}\" = \"x\"; then\n        _target_mode=${_target_mode_default}\n    fi\n    if test \"x${_target_kind}\" = \"x\"; then\n        _target_kind=${_target_kind_default}\n    fi\n    echo \"checking for platform ... ${_target_plat}\"\n    echo \"checking for architecture ... ${_target_arch}\"\n}\n\n# get toolchain compile command for gcc/clang\n_toolchain_compcmd_for_gcc_clang() {\n    local program=\"${1}\"\n    local objectfile=\"${2}\"\n    local sourcefile=\"${3}\"\n    local flags=\"${4}\"\n    _ret=\"${program} -c ${flags} -o ${objectfile} ${sourcefile}\"\n}\n\n# get toolchain link command for gcc/clang\n_toolchain_linkcmd_for_gcc_clang() {\n    local toolkind=\"${1}\"\n    local program=\"${2}\"\n    local binaryfile=\"${3}\"\n    local objectfiles=\"${4}\"\n    local flags=\"${5}\"\n    if test_eq \"${toolkind}\" \"sh\"; then\n        flags=\"-shared -fPIC ${flags}\"\n    fi\n    _ret=\"${program} -o ${binaryfile} ${objectfiles} ${flags}\"\n}\n\n# get toolchain link command for ar\n_toolchain_linkcmd_for_ar() {\n    local toolkind=\"${1}\"\n    local program=\"${2}\"\n    local binaryfile=\"${3}\"\n    local objectfiles=\"${4}\"\n    local flags=\"${5}\"\n    _ret=\"${program} ${flags} ${binaryfile} ${objectfiles}\"\n}\n\n# get toolchain compile command\n_toolchain_compcmd() {\n    local sourcekind=\"${1}\"\n    local objectfile=\"${2}\"\n    local sourcefile=\"${3}\"\n    local flags=\"${4}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${sourcekind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    local compcmd=\"\"\n    case \"${toolname}\" in\n        gcc) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        gxx) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        clang) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        clangxx) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        emcc) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        emxx) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        cosmocc) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        cosmocxx) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        tcc) _toolchain_compcmd_for_gcc_clang \"${program}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; compcmd=\"${_ret}\";;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n    _ret=\"${compcmd}\"\n}\n\n# get toolchain link command\n_toolchain_linkcmd() {\n    local toolkind=\"${1}\"\n    local binaryfile=\"${2}\"\n    local objectfiles=\"${3}\"\n    local flags=\"${4}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    case \"${toolname}\" in\n        gcc) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        gxx) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        clang) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        clangxx) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        emcc) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        emxx) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        cosmocc) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        cosmocxx) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        tcc) _toolchain_linkcmd_for_gcc_clang \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        ar) _toolchain_linkcmd_for_ar \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        emar) _toolchain_linkcmd_for_ar \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        cosmoar) _toolchain_linkcmd_for_ar \"${toolkind}\" \"${program}\" \"${binaryfile}\" \"${objectfiles}\" \"${flags}\"; linkcmd=\"${_ret}\";;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n    _ret=\"${linkcmd}\"\n}\n\n# try make\n_toolchain_try_make() {\n    local program=\"${1}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        return 0\n    fi\n    return 1\n}\n\n# try ninja\n_toolchain_try_ninja() {\n    local program=\"${1}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        return 0\n    fi\n    return 1\n}\n\n# try gcc\n_toolchain_try_gcc() {\n    if test \"x${_toolchain_try_gcc_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_gcc_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        _toolchain_try_gcc_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_gcc_result=\"no\"\n    return 1\n}\n\n# try g++\n_toolchain_try_gxx() {\n    if test \"x${_toolchain_try_gxx_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_gxx_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        _toolchain_try_gxx_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_gxx_result=\"no\"\n    return 1\n}\n\n# try clang\n_toolchain_try_clang() {\n    if test \"x${_toolchain_try_clang_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_clang_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        _toolchain_try_clang_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_clang_result=\"no\"\n    return 1\n}\n\n# try clang++\n_toolchain_try_clangxx() {\n    if test \"x${_toolchain_try_clangxx_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_clangxx_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        _toolchain_try_clangxx_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_clangxx_result=\"no\"\n    return 1\n}\n\n# try tcc\n_toolchain_try_tcc() {\n    if test \"x${_toolchain_try_tcc_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_tcc_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"-v\"; then\n        _toolchain_try_tcc_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_tcc_result=\"no\"\n    return 1\n}\n\n# try ar\n_toolchain_try_ar() {\n    local kind=\"${1}\"\n    local program=\"${2}\"\n\n    # generate the source file\n    _os_tmpfile\n    local tmpfile=\"${_ret}\"\n    local objectfile=\"${tmpfile}.o\"\n    local libraryfile=\"${tmpfile}.a\"\n    echo \"\" > \"${objectfile}\"\n\n    # try linking it\n    local ok=false\n    if _os_runv \"${program}\" \"-cr\" \"${libraryfile}\" \"${objectfile}\"; then\n        ok=true\n    fi\n\n    # remove files\n    _os_tryrm \"${objectfile}\"\n    _os_tryrm \"${libraryfile}\"\n    if ${ok}; then\n        return 0\n    fi\n    return 1\n}\n\n# try cosmoar\n_toolchain_try_cosmoar() {\n    if test \"x${_toolchain_try_cosmoar_result}\" = \"xok\"; then\n        return 0\n    elif test \"x${_toolchain_try_cosmoar_result}\" = \"xno\"; then\n        return 1\n    fi\n\n    local kind=\"${1}\"\n    local program=\"${2}\"\n    if _os_runv \"${program}\" \"--version\"; then\n        _toolchain_try_cosmoar_result=\"ok\"\n        return 0\n    fi\n    _toolchain_try_cosmoar_result=\"no\"\n    return 1\n}\n\n# try program\n_toolchain_try_program() {\n    local toolchain=\"${1}\"\n    local kind=\"${2}\"\n    local program=\"${3}\"\n    local ok=false\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    case \"${toolname}\" in\n        gcc) _toolchain_try_gcc \"${kind}\" \"${program}\" && ok=true;;\n        gxx) _toolchain_try_gxx \"${kind}\" \"${program}\" && ok=true;;\n        clang) _toolchain_try_clang \"${kind}\" \"${program}\" && ok=true;;\n        clangxx) _toolchain_try_clangxx \"${kind}\" \"${program}\" && ok=true;;\n        emcc) _toolchain_try_clang \"${kind}\" \"${program}\" && ok=true;;\n        emxx) _toolchain_try_clangxx \"${kind}\" \"${program}\" && ok=true;;\n        cosmocc) _toolchain_try_gcc \"${kind}\" \"${program}\" && ok=true;;\n        cosmocxx) _toolchain_try_gxx \"${kind}\" \"${program}\" && ok=true;;\n        tcc) _toolchain_try_tcc \"${kind}\" \"${program}\" && ok=true;;\n        ar) _toolchain_try_ar \"${kind}\" \"${program}\" && ok=true;;\n        emar) _toolchain_try_ar \"${kind}\" \"${program}\" && ok=true;;\n        cosmoar) _toolchain_try_cosmoar \"${kind}\" \"${program}\" && ok=true;;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n    if ${ok}; then\n        vprint \"checking for ${program} ... ok\"\n        return 0\n    fi\n    vprint \"checking for ${program} ... no\"\n    return 1\n}\n\n# try toolset\n_toolchain_try_toolset() {\n    local toolchain=${1}\n    local kind=${2}\n    local description=${3}\n    local indices=\"0 1 2 3 4 5\"\n    for idx in ${indices}; do\n        local key=\"${kind}\"\n        if test_nq \"${idx}\" \"0\"; then\n            key=\"${key}_${idx}\"\n        fi\n        _get_toolchain_toolset \"${toolchain}\" \"${key}\"; local program=\"${_ret}\"\n        if test_nz \"${program}\"; then\n            if _toolchain_try_program \"${toolchain}\" \"${kind}\" \"${program}\"; then\n                _set_toolchain_toolset \"${toolchain}\" \"${kind}\" \"${program}\"\n                echo \"checking for the ${description} (${kind}) ... ${program}\"\n                return 0\n            fi\n        fi\n    done\n    return 1\n}\n\n# try toolchain\n_toolchain_try() {\n    local toolchain=${1}\n    vprint \"checking for $toolchain toolchain ...\"\n    if _toolchain_try_toolset \"${toolchain}\" \"cc\" \"c compiler\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"cxx\" \"c++ compiler\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"as\" \"assembler\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"mm\" \"objc compiler\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"mxx\" \"objc++ compiler\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"ld\" \"linker\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"ar\" \"static library archiver\" &&\n       _toolchain_try_toolset \"${toolchain}\" \"sh\" \"shared library linker\"; then\n        return 0\n    fi\n    return 1\n}\n\n# detect make\n_toolchain_detect_make() {\n    if test \"x${_make_program}\" = \"x\"; then\n        _make_program=${_make_program_default}\n    fi\n    if _toolchain_try_make \"${_make_program}\"; then\n        echo \"checking for make ... ok\"\n    else\n        echo \"checking for make ... no\"\n        raise \"make not found!\"\n    fi\n}\n\n# detect ninja\n_toolchain_detect_ninja() {\n    if test \"x${_ninja_program}\" = \"x\"; then\n        _ninja_program=${_ninja_program_default}\n    fi\n    if _toolchain_try_ninja \"${_ninja_program}\"; then\n        echo \"checking for ninja ... ok\"\n    else\n        echo \"checking for ninja ... no\"\n        raise \"ninja not found!\"\n    fi\n}\n\n# detect build backend\n_toolchain_detect_backend() {\n    if test \"x${project_generator}\" = \"xgmake\"; then\n        _toolchain_detect_make\n    elif test \"x${project_generator}\" = \"xninja\"; then\n        _toolchain_detect_ninja\n    fi\n}\n\n# detect toolchain\n_toolchain_detect() {\n    # detect build backend\n    _toolchain_detect_backend\n\n    # detect toolchains\n    local toolchains=\"${1}\"\n    if test \"x${toolchains}\" = \"x\"; then\n        if is_plat \"macosx\"; then\n            toolchains=\"envs clang gcc\"\n        elif is_plat \"mingw\"; then\n            if is_arch \"i386\"; then\n                toolchains=\"i686_w64_mingw32\"\n            else\n                toolchains=\"x86_64_w64_mingw32\"\n            fi\n        elif is_plat \"wasm\"; then\n            toolchains=\"emcc\"\n        elif is_plat \"linux\" && ! is_arch \"${os_arch}\"; then\n            toolchains=\"envs\"\n            if is_arch \"arm64\"; then\n                toolchains=\"${toolchains} aarch64_linux_gnu\"\n            fi\n        else\n            toolchains=\"envs gcc clang\"\n        fi\n    fi\n    for toolchain in ${toolchains}; do\n        if _toolchain_try \"$toolchain\"; then\n            _target_toolchain=${toolchain}\n            break\n        fi\n    done\n}\n\n# check toolchain\n_check_toolchain() {\n    local toolchain=${_target_toolchain}\n    _target_toolchain=\"\"\n    _toolchain_detect ${toolchain}\n\n    if test \"x${_target_toolchain}\" != \"x\"; then\n        echo \"checking for toolchain ... ${_target_toolchain}\"\n    else\n        echo \"checking for toolchain ... no\"\n        raise \"toolchain not found!\"\n    fi\n}\n\n# get function code\n#\n# sigsetjmp\n# sigsetjmp((void*)0, 0)\n#\n_get_funccode() {\n    local func=\"${1}\"\n    local code=\"\"\n    if string_contains \"${func}\" \"(\"; then\n        code=\"${func}\"\n    else\n        code=\"typedef void (*func_t)(); volatile func_t p${func} = (func_t)${func}; while (p${func}) {break;};\"\n    fi\n    _ret=\"${code}\"\n}\n\n# generate cxsnippets source code\n_generate_cxsnippets_sourcecode() {\n    local funcs=\"${1}\"\n    local includes=\"${2}\"\n    local types=\"${3}\"\n    local snippets=\"${4}\"\n\n    local snippet_includes=\"\"\n    for include in $includes; do\n        snippet_includes=\"${snippet_includes}#include \\\"${include}\\\"\\n\"\n    done\n\n    local snippet_types=\"\"\n    for type in $types; do\n        string_replace \"${type}\" '[^a-zA-Z]' \"_\"; local typevar=\"${_ret}\"\n        snippet_types=\"${snippet_types}typedef ${type} __type_${typevar};\\n\"\n    done\n\n    local snippet_funcs=\"\"\n    for func in $funcs; do\n        _get_funccode \"${func}\"; func=\"${_ret}\"\n        snippet_funcs=\"${snippet_funcs}${func}\\n    \"\n    done\n\n    local snippets_code=\"\"\n    if test_nz \"${snippet_includes}\"; then\n        snippets_code=\"${snippets_code}${snippet_includes}\\n\"\n    fi\n    if test_nz \"${snippet_types}\"; then\n        snippets_code=\"${snippets_code}${snippet_types}\\n\"\n    fi\n    if test_nz \"${snippets}\"; then\n        snippets_code=\"${snippets_code}${snippets}\\n\"\n    fi\n\n    _ret='\n'\"${snippets_code}\"'int main(int argc, char** argv) {\n    '\"${snippet_funcs}\"'\n    return 0;\n}'\n}\n\n# check cxsnippets\n_check_cxsnippets() {\n    local name=\"${1}\"\n    local kind=\"${2}\"\n    _get_option_item \"${name}\" \"${kind}funcs\"; local funcs=\"${_ret}\"\n    _get_option_item \"${name}\" \"${kind}includes\"; local includes=\"${_ret}\"\n    _get_option_item \"${name}\" \"${kind}types\"; local types=\"${_ret}\"\n    _get_option_item \"${name}\" \"${kind}snippets\"; local snippets=\"${_ret}\"\n    if test_z \"${funcs}\" && test_z \"${includes}\" &&\n       test_z \"${types}\" && test_z \"${snippets}\"; then\n        return 0\n    fi\n\n    # get c/c++ extension\n    local extension=\".c\"\n    local sourcekind=\"cc\"\n    if test_eq \"${kind}\" \"cxx\"; then\n        extension=\".cpp\"\n        sourcekind=\"cxx\"\n    fi\n\n    # generate source code\n    _generate_cxsnippets_sourcecode \"${funcs}\" \"${includes}\" \"${types}\" \"${snippets}\"; local sourcecode=\"${_ret}\"\n    dprint \"${sourcecode}\"\n\n    # generate the source file\n    _os_tmpfile\n    local tmpfile=\"${_ret}\"\n    local sourcefile=\"${tmpfile}${extension}\"\n    local objectfile=\"${tmpfile}.o\"\n    local binaryfile=\"${tmpfile}.bin\"\n    print \"${sourcecode}\" > \"${sourcefile}\"\n\n    # try compiling it\n    local ok=false\n    if ! ${ok}; then\n        local compflags=\"\"\n        _get_toolchain_toolset \"${_target_toolchain}\" \"${sourcekind}\"; local program=\"${_ret}\"\n        path_toolname \"${program}\"; local toolname=\"${_ret}\"\n        local itemnames=\"languages warnings optimizes defines undefines includedirs\"\n        for itemname in ${itemnames}; do\n            _get_option_abstract_flags \"${name}\" \"${sourcekind}\" \"${toolname}\" \"${itemname}\"; local flags=\"${_ret}\"\n            if test_nz \"${flags}\"; then\n                _split_flags \"${flags}\"; flags=\"${_ret}\"\n                compflags=\"${compflags} ${flags}\"\n            fi\n        done\n        local flagnames=\"cxflags\"\n        if test_eq \"${sourcekind}\" \"cxx\"; then\n            flagnames=\"${flagnames} cxxflags\"\n        else\n            flagnames=\"${flagnames} cflags\"\n        fi\n        for flagname in $flagnames; do\n            _get_option_item \"${name}\" \"${flagname}\"; local flags=\"${_ret}\"\n            if test_nz \"${flags}\"; then\n                compflags=\"${compflags} ${flags}\"\n            fi\n        done\n        if test_eq \"${sourcekind}\" \"cxx\"; then\n            if test_nz \"${CXXFLAGS}\"; then\n                compflags=\"${compflags} ${CXXFLAGS}\"\n            fi\n        else\n            if test_nz \"${CFLAGS}\"; then\n                compflags=\"${compflags} ${CFLAGS}\"\n            fi\n        fi\n        if test_nz \"${CPPFLAGS}\"; then\n            compflags=\"${compflags} ${CPPFLAGS}\"\n        fi\n        # add -isysroot and -target on macOS to ensure system SDK headers are used for option checking\n        _get_macosx_sysroot_flags; compflags=\"${_ret} ${compflags}\"\n        _toolchain_compcmd \"${sourcekind}\" \"${objectfile}\" \"${sourcefile}\" \"${compflags}\"; local compcmd=\"${_ret}\"\n        if ${xmake_sh_diagnosis}; then\n            print \"> ${compcmd}\"\n        fi\n        if _os_runv ${compcmd}; then\n            ok=true\n        fi\n    fi\n\n    # try linking it\n    _get_option_item \"${name}\" \"links\"; local links=\"${_ret}\"\n    _get_option_item \"${name}\" \"syslinks\"; local syslinks=\"${_ret}\"\n    _get_option_item \"${name}\" \"ldflags\"; local ldflags=\"${_ret}\"\n    if test_nz \"${syslinks}\"; then\n        links=\"${links} ${syslinks}\"\n    fi\n    if ${ok} && (test_nz \"${links}\" || test_nz \"${ldflags}\"); then\n        local toolkind=\"ld\"\n        _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n        path_toolname \"${program}\"; local toolname=\"${_ret}\"\n        local itemnames=\"linkdirs links syslinks\"\n        local linkflags=\"\"\n        for itemname in ${itemnames}; do\n            _get_option_abstract_flags \"${name}\" \"${toolkind}\" \"${toolname}\" \"${itemname}\"; local flags=\"${_ret}\"\n            if test_nz \"${flags}\"; then\n                _split_flags \"${flags}\"; flags=\"${_ret}\"\n                linkflags=\"${linkflags} ${flags}\"\n            fi\n        done\n        _get_option_item \"${name}\" \"ldflags\"; local flags=\"${_ret}\"\n        if test_nz \"${flags}\"; then\n            linkflags=\"${linkflags} ${flags}\"\n        fi\n        if test_nz \"${LDFLAGS}\"; then\n            linkflags=\"${linkflags} ${LDFLAGS}\"\n        fi\n        _toolchain_linkcmd \"${toolkind}\" \"${binaryfile}\" \"${objectfile}\" \"${linkflags}\"; local linkcmd=\"${_ret}\"\n        if ${xmake_sh_diagnosis}; then\n            print \"> ${linkcmd}\"\n        fi\n        if _os_runv ${linkcmd}; then\n            ok=true\n        else\n            ok=false\n        fi\n    fi\n\n    # trace\n    if ${xmake_sh_verbose} || ${xmake_sh_diagnosis}; then\n        if test_nz \"${includes}\"; then\n            print \"> checking for ${kind} includes(${includes})\"\n        fi\n        if test_nz \"${types}\"; then\n            print \"> checking for ${kind} types(${types})\"\n        fi\n        if test_nz \"${funcs}\"; then\n            print \"> checking for ${kind} funcs(${funcs})\"\n        fi\n        if test_nz \"${links}\"; then\n            print \"> checking for ${kind} links(${links})\"\n        fi\n    fi\n\n    # remove files\n    _os_tryrm \"${sourcefile}\"\n    _os_tryrm \"${objectfile}\"\n    _os_tryrm \"${binaryfile}\"\n    if ${ok}; then\n        return 0\n    fi\n    return 1\n}\n\n# check csnippets\n_check_csnippets() {\n    local name=\"${1}\"\n    if _check_cxsnippets \"${name}\" \"c\"; then\n        return 0\n    fi\n    return 1\n}\n\n# check cxxsnippets\n_check_cxxsnippets() {\n    local name=\"${1}\"\n    if _check_cxsnippets \"${name}\" \"cxx\"; then\n        return 0\n    fi\n    return 1\n}\n\n# check option\n_check_option() {\n    local name=\"${1}\"\n    _get_option_value \"${name}\"; local value=\"${_ret}\"\n    _get_option_item \"${name}\" \"default\"; local default=\"${_ret}\"\n    if test_nz \"${value}\"; then\n        if _is_enabled \"${value}\"; then\n            return 0\n        else\n            return 1\n        fi\n    elif test_nz \"${default}\"; then\n        if _is_enabled \"${default}\"; then\n            return 0\n        else\n            return 1\n        fi\n    else\n        _get_option_item \"${name}\" \"before_check\"; local before_check=\"${_ret}\"\n        if test_nz \"${before_check}\"; then\n            eval ${before_check}\n        fi\n        if _check_csnippets \"${name}\" && _check_cxxsnippets \"${name}\"; then\n            return 0\n        fi\n    fi\n    return 1\n}\n\n# check options\n_check_options() {\n    _get_options_for_checking; local options=\"${_ret}\"\n    for name in $options; do\n        if _check_option \"$name\"; then\n            echo \"checking for ${name} .. ok\"\n            _set_option_value \"${name}\" true\n        else\n            echo \"checking for ${name} .. no\"\n            _set_option_value \"${name}\" false\n        fi\n    done\n}\n\n# check all\n_check_all() {\n    _check_platform\n    _check_toolchain\n    _check_options\n}\n_check_all\n\n#-----------------------------------------------------------------------------\n# init builtin variables, e.g. add_headerfiles \"${builddir}/config.h\"\n#\nprojectdir=\"${xmake_sh_projectdir}\"\nif path_is_absolute \"${xmake_sh_builddir}\"; then\n    builddir=\"${xmake_sh_builddir}\"\nelse\n    builddir=\"${xmake_sh_projectdir}/${xmake_sh_builddir}\"\nfi\nbuildir=${builddir} # deprecated\nplat=\"${_target_plat}\"\narch=\"${_target_arch}\"\nmode=\"${_target_mode}\"\nkind=\"${_target_kind}\"\n\n#-----------------------------------------------------------------------------\n# load project targets\n#\n\n# load targets\n_load_targets() {\n    echo \"analyzing project configuration ..\"\n    _loading_options=false\n    _loading_toolchains=false\n    _loading_targets=true\n    _xmake_sh_option_current=\"\"\n    _xmake_sh_target_current=\"\"\n    _xmake_sh_toolchain_current=\"\"\n    local file=${xmake_sh_projectdir}/xmake.sh\n    if test -f \"${file}\"; then\n        includes \"${file}\"\n    else\n        # include all xmake.sh files in next sub-directories\n        _os_find \"${xmake_sh_projectdir}\" \"xmake.sh\" 2; local files=\"${_ret}\"\n        for file in ${files}; do\n            includes \"${file}\"\n        done\n    fi\n}\n_load_targets\n\n# get toolset kinds for all targets\n# e.g. cc cxx as mm mxx ld sh ar\n_get_targets_toolkinds() {\n    if test_z \"${_targets_toolkinds_dedup}\"; then\n        _dedup \"${_targets_toolkinds}\"; _targets_toolkinds_dedup=\"${_ret}\"\n    fi\n    _ret=\"${_targets_toolkinds_dedup}\"\n}\n\n#-----------------------------------------------------------------------------\n# generate configfiles\n#\n\n# vprint config variable in `${name}`\n_vprint_configvar_value() {\n    local name=\"${1}\"\n    local value=\"${2}\"\n    vprint \"  > replace ${name} -> ${value}\"\n}\n\n# vprint config variable in `${define name}`\n_vprint_configvar_define() {\n    local name=\"${1}\"\n    local value=\"${2}\"\n    if test_z \"${value}\"; then\n        vprint \"  > replace ${name} -> /* #undef ${name} */\"\n    elif test_eq \"${value}\" \"1\" || test_eq \"${value}\" \"true\"; then\n        vprint \"  > replace ${name} -> #define ${name} 1\"\n    elif test_eq \"${value}\" \"0\" || test_eq \"${value}\" \"false\"; then\n        vprint \"  > replace ${name} -> /*#define ${name} 0*/\"\n    else\n        vprint \"  > replace ${name} -> #define ${name} ${value}\"\n    fi\n}\n\n# replace config variable in `${define name}`\n_replace_configvar_define() {\n    local name=\"${1}\"\n    local value=\"${2}\"\n    if test_z \"${value}\"; then\n        _ret=\"s/\\${define ${name}}/\\/*#undef ${name}*\\//g\"\n    elif test_eq \"${value}\" \"1\" || test_eq \"${value}\" \"true\"; then\n        _ret=\"s/\\${define ${name}}/#define ${name} 1/g\"\n    elif test_eq \"${value}\" \"0\" || test_eq \"${value}\" \"false\"; then\n        _ret=\"s/\\${define ${name}}/\\/*#define ${name} 0*\\//g\"\n    else\n        _ret=\"s/\\${define ${name}}/#define ${name} ${value}/g\"\n    fi\n}\n\n# replace config variable in `${name}`\n_replace_configvar_value() {\n    local name=\"${1}\"\n    local value=\"${2}\"\n    _ret=\"s@\\${${name}}@${value}@g\"\n}\n\n# generate configfile for the given target\n_generate_configfile() {\n    local target=\"${1}\"\n    local configfile_in=\"${2}\"\n    _get_target_item \"${target}\" \"configdir\"; local configdir=\"${_ret}\"\n    if test_z \"${configdir}\"; then\n        path_directory configfile_in; configdir=\"${_ret}\"\n    fi\n    if ! test -d \"${configdir}\"; then\n        mkdir -p \"${configdir}\"\n    fi\n    path_basename \"${configfile_in}\"; local filename=\"${_ret}\"\n    local configfile=\"${configdir}/${filename}\"\n    echo \"generating ${configfile} ..\"\n\n    # replace builtin variables\n    local patterns=\"\"\n    local target_os=\"\"\n    if is_plat \"mingw\"; then\n        target_os=\"windows\"\n    else\n        target_os=\"${_target_plat}\"\n    fi\n    string_toupper ${target_os}; target_os=\"${_ret}\"\n    _vprint_configvar_value \"OS\" \"${target_os}\"\n    _replace_configvar_value \"OS\" \"${target_os}\"; patterns=\"${_ret};${patterns}\"\n\n    # replace version\n    _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n    _get_target_item \"${target}\" \"version_build\"; local version_build=\"${_ret}\"\n    string_split \"${version}\" \".\"\n    local version_major=\"${_ret}\"\n    local version_minor=\"${_ret2}\"\n    local version_alter=\"${_ret3}\"\n    if test_nz \"${version}\"; then\n        _vprint_configvar_value \"VERSION\" \"${version}\"\n        _replace_configvar_value \"VERSION\" \"${version}\"; patterns=\"${_ret};${patterns}\"\n    fi\n    if test_nz \"${version_major}\"; then\n        _vprint_configvar_value \"VERSION_MAJOR\" \"${version_major}\"\n        _replace_configvar_value \"VERSION_MAJOR\" \"${version_major}\"; patterns=\"${_ret};${patterns}\"\n    fi\n    if test_nz \"${version_minor}\"; then\n        _vprint_configvar_value \"VERSION_MINOR\" \"${version_minor}\"\n        _replace_configvar_value \"VERSION_MINOR\" \"${version_minor}\"; patterns=\"${_ret};${patterns}\"\n    fi\n    if test_nz \"${version_alter}\"; then\n        _vprint_configvar_value \"VERSION_ALTER\" \"${version_alter}\"\n        _replace_configvar_value \"VERSION_ALTER\" \"${version_alter}\"; patterns=\"${_ret};${patterns}\"\n    fi\n    if test_nz \"${version_build}\"; then\n        _os_date \"${version_build}\"; version_build=\"${_ret}\"\n        _vprint_configvar_value \"VERSION_BUILD\" \"${version_build}\"\n        _replace_configvar_value \"VERSION_BUILD\" \"${version_build}\"; patterns=\"${_ret};${patterns}\"\n    fi\n\n    # replace git variables\n    local content=\"\"\n    content=$(cat \"${configfile_in}\")\n    if string_contains \"${content}\" \"GIT_\"; then\n        _os_iorunv \"git\" \"describe\" \"--tags\"; local git_tag=\"${_ret}\"\n        _vprint_configvar_value \"GIT_TAG\" \"${git_tag}\"\n        _replace_configvar_value \"GIT_TAG\" \"${git_tag}\"; patterns=\"${_ret};${patterns}\"\n\n        _os_iorunv \"git\" \"describe\" \"--tags\" \"--long\"; local git_tag_long=\"${_ret}\"\n        _vprint_configvar_value \"GIT_TAG_LONG\" \"${git_tag_long}\"\n        _replace_configvar_value \"GIT_TAG_LONG\" \"${git_tag_long}\"; patterns=\"${_ret};${patterns}\"\n\n        _os_iorunv \"git\" \"rev-parse\" \"--abbrev-ref\" \"HEAD\"; local git_branch=\"${_ret}\"\n        _vprint_configvar_value \"GIT_BRANCH\" \"${git_branch}\"\n        _replace_configvar_value \"GIT_BRANCH\" \"${git_branch}\"; patterns=\"${_ret};${patterns}\"\n\n        _os_iorunv \"git\" \"rev-parse\" \"--short\" \"HEAD\"; local git_commit=\"${_ret}\"\n        _vprint_configvar_value \"GIT_COMMIT\" \"${git_commit}\"\n        _replace_configvar_value \"GIT_COMMIT\" \"${git_commit}\"; patterns=\"${_ret};${patterns}\"\n\n        _os_iorunv \"git\" \"rev-parse\" \"HEAD\"; local git_commit_long=\"${_ret}\"\n        _vprint_configvar_value \"GIT_COMMIT_LONG\" \"${git_commit_long}\"\n        _replace_configvar_value \"GIT_COMMIT_LONG\" \"${git_commit_long}\"; patterns=\"${_ret};${patterns}\"\n\n        _os_iorunv \"log\" \"-1\" \"--date=format:%Y%m%d%H%M%S\" \"--format=%ad\"; local git_commit_date=\"${_ret}\"\n        _vprint_configvar_value \"GIT_COMMIT_DATE\" \"${git_commit_date}\"\n        _replace_configvar_value \"GIT_COMMIT_DATE\" \"${git_commit_date}\"; patterns=\"${_ret};${patterns}\"\n    fi\n\n    # replace configvars in target\n    local count=0\n    local configfile_dst=\"${configfile}\"\n    _os_tmpfile; local tmpfile=\"${_ret}\"\n    cp \"${configfile_in}\" \"${tmpfile}\"\n    _get_target_item \"${target}\" \"configvars\"; local configvars=\"${_ret}\"\n    for name in ${configvars}; do\n        _get_target_item \"${target}\" \"configvar_${name}\"; local value=\"${_ret}\"\n        _vprint_configvar_define \"${name}\" \"${value}\"\n        _vprint_configvar_value \"${name}\" \"${value}\"\n        _replace_configvar_define \"${name}\" \"${value}\"; patterns=\"${_ret};${patterns}\"\n        _replace_configvar_value \"${name}\" \"${value}\"; patterns=\"${_ret};${patterns}\"\n        count=$((count + 1))\n\n        # do replace\n        if test_eq \"$count\" \"10\"; then\n            _io_replace_file \"${tmpfile}\" \"${configfile}\" \"${patterns}\"\n            local swapfile=\"${tmpfile}\"\n            tmpfile=\"${configfile}\"\n            configfile=\"${swapfile}\"\n            patterns=\"\"\n            count=0\n        fi\n    done\n\n    # do replace (left)\n    if test_nz \"${patterns}\"; then\n        _io_replace_file \"${tmpfile}\" \"${configfile}\" \"${patterns}\"\n        local swapfile=\"${tmpfile}\"\n        tmpfile=\"${configfile}\"\n        configfile=\"${swapfile}\"\n        patterns=\"\"\n        count=0\n    fi\n\n    # replace fallback\n    patterns='s/${define \\(.*\\)}/\\/*#undef \\1*\\//g;'\n    _io_replace_file \"${tmpfile}\" \"${configfile}\" \"${patterns}\"\n    if test_nq \"${configfile}\" \"${configfile_dst}\"; then\n        cp \"${configfile}\" \"${configfile_dst}\"\n    fi\n    echo \"${configfile_dst} is generated!\"\n}\n\n# generate configfiles\n_generate_configfiles() {\n    for target in ${_xmake_sh_targets}; do\n        _get_target_item \"${target}\" \"configfiles\"; local configfiles=\"${_ret}\"\n        for configfile in ${configfiles}; do\n            _generate_configfile \"${target}\" \"${configfile}\"\n        done\n    done\n}\n_generate_configfiles\n\n#-----------------------------------------------------------------------------\n# generate gmake file\n#\n\n_gmake_begin() {\n    echo \"generating makefile ..\"\n}\n\n_gmake_add_header() {\n    echo \"# this is the build file for this project\n# it is autogenerated by the xmake.sh build system.\n# do not edit by hand.\n\" > \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_switches() {\n    echo \"ifneq (\\$(VERBOSE),1)\" >> \"${xmake_sh_makefile}\"\n    echo \"VV=@\" >> \"${xmake_sh_makefile}\"\n    echo \"endif\" >> \"${xmake_sh_makefile}\"\n    echo \"\" >> \"${xmake_sh_makefile}\"\n    echo \"ifeq (\\$(PREFIX),)\" >> \"${xmake_sh_makefile}\"\n    echo \"PREFIX=${_install_prefix_default}\" >> \"${xmake_sh_makefile}\"\n    echo \"endif\" >> \"${xmake_sh_makefile}\"\n    echo \"\" >> \"${xmake_sh_makefile}\"\n    echo \"INSTALLDIR:=\\$(DESTDIR)\" >> \"${xmake_sh_makefile}\"\n    echo \"ifneq (\\$(PREFIX),)\" >> \"${xmake_sh_makefile}\"\n    echo \"ifneq (\\$(INSTALLDIR),)\" >> \"${xmake_sh_makefile}\"\n    echo \"PREFIX_:=\\$(patsubst /%,%,\\$(PREFIX))\" >> \"${xmake_sh_makefile}\"\n    echo \"INSTALLDIR:=\\$(INSTALLDIR)/\\$(PREFIX_)\" >> \"${xmake_sh_makefile}\"\n    echo \"else\" >> \"${xmake_sh_makefile}\"\n    echo \"INSTALLDIR:=\\$(PREFIX)\" >> \"${xmake_sh_makefile}\"\n    echo \"endif\" >> \"${xmake_sh_makefile}\"\n    echo \"endif\" >> \"${xmake_sh_makefile}\"\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_flags() {\n    _get_targets_toolkinds; local kinds=\"${_ret}\"\n    for target in ${_xmake_sh_targets}; do\n        for kind in ${kinds}; do\n            _get_target_flags \"${target}\" \"${kind}\"; local flags=\"${_ret}\"\n            _get_flagname \"${kind}\"; local flagname=\"${_ret}\"\n            local key=\"${target}_${flagname}\"\n            echo \"${key}=${flags}\" >> \"${xmake_sh_makefile}\"\n        done\n        echo \"\" >> \"${xmake_sh_makefile}\"\n    done\n}\n\n_gmake_add_toolchains() {\n    _get_targets_toolkinds; local kinds=\"${_ret}\"\n    for kind in ${kinds}; do\n        _get_toolchain_toolset \"${_target_toolchain}\" \"${kind}\"; local program=\"${_ret}\"\n        local key=\"${kind}\"\n        echo \"${key}=${program}\" >> \"${xmake_sh_makefile}\"\n    done\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_build_object_for_gcc_clang() {\n    local kind=\"${1}\"\n    local sourcefile=\"${2}\"\n    local objectfile=\"${3}\"\n    local flagname=\"${4}\"\n    path_directory \"${objectfile}\"; local objectdir=\"${_ret}\"\n    print \"\\t@mkdir -p ${objectdir}\" >> \"${xmake_sh_makefile}\"\n    print \"\\t\\$(VV)\\$(${kind}) -c \\$(${flagname}) -o ${objectfile} ${sourcefile}\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_build_object() {\n    local target=${1}\n    local sourcefile=\"${2}\"\n    local objectfile=\"${3}\"\n    path_sourcekind \"${sourcefile}\"; local sourcekind=\"${_ret}\"\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${sourcekind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n    _get_flagname \"${sourcekind}\"; local flagname=\"${_ret}\"\n    flagname=\"${target}_${flagname}\"\n    echo \"${objectfile}: ${sourcefile}\" >> \"${xmake_sh_makefile}\"\n    print \"\\t@echo compiling.${_target_mode} ${sourcefile}\" >> \"${xmake_sh_makefile}\"\n    case \"${toolname}\" in\n        gcc) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        gxx) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        clang) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        clangxx) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        emcc) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        emxx) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        cosmocc) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        cosmocxx) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        tcc) _gmake_add_build_object_for_gcc_clang \"${sourcekind}\" \"${sourcefile}\" \"${objectfile}\" \"${flagname}\";;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_build_objects() {\n    local target=${1}\n    _get_target_sourcefiles \"${target}\"; local sourcefiles=\"${_ret}\"\n    for sourcefile in ${sourcefiles}; do\n        _get_target_objectfile \"${target}\" \"${sourcefile}\"; local objectfile=\"${_ret}\"\n        _gmake_add_build_object \"${target}\" \"${sourcefile}\" \"${objectfile}\"\n    done\n}\n\n_gmake_add_build_target_for_gcc_clang() {\n    local kind=\"${1}\"\n    local targetfile=\"${2}\"\n    local objectfiles=\"${3}\"\n    local flagname=\"${4}\"\n    path_directory \"${targetfile}\"; local targetdir=\"${_ret}\"\n    print \"\\t@mkdir -p ${targetdir}\" >> \"${xmake_sh_makefile}\"\n    print \"\\t\\$(VV)\\$(${kind}) -o ${targetfile} ${objectfiles} \\$(${flagname})\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_build_target_for_ar() {\n    local kind=\"${1}\"\n    local targetfile=\"${2}\"\n    local objectfiles=\"${3}\"\n    local flagname=\"${4}\"\n    path_directory \"${targetfile}\"; local targetdir=\"${_ret}\"\n    print \"\\t@mkdir -p ${targetdir}\" >> \"${xmake_sh_makefile}\"\n    print \"\\t\\$(VV)\\$(${kind}) \\$(${flagname}) ${flags} ${targetfile} ${objectfiles}\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_build_target() {\n    local target=${1}\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    _get_target_item \"${target}\" \"deps\"; local deps=\"${_ret}\"\n    _get_target_objectfiles \"${target}\"; local objectfiles=\"${_ret}\"\n\n    # get linker\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n    local toolkind=\"\"\n    case \"${targetkind}\" in\n        binary) toolkind=\"ld\";;\n        static) toolkind=\"ar\";;\n        shared) toolkind=\"sh\";;\n        *) raise \"unknown targetkind(${targetkind})!\" ;;\n    esac\n    _get_toolchain_toolset \"${_target_toolchain}\" \"${toolkind}\"; local program=\"${_ret}\"\n    path_toolname \"${program}\"; local toolname=\"${_ret}\"\n\n    # get linker flags\n    _get_flagname \"${toolkind}\"; local flagname=\"${_ret}\"\n    flagname=\"${target}_${flagname}\"\n\n    # get depfiles\n    local dep=\"\"\n    local depfiles=\"\"\n    for dep in ${deps}; do\n        _get_target_file \"${dep}\"; local depfile=\"${_ret}\"\n        if test_nz \"${depfiles}\"; then\n            depfiles=\"${depfiles} ${depfile}\"\n        else\n            depfiles=\"${depfile}\"\n        fi\n    done\n\n    # link target\n    echo \"${target}: ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    echo \"${targetfile}: ${depfiles}${objectfiles}\" >> \"${xmake_sh_makefile}\"\n    if test_eq \"${targetkind}\" \"static\"; then\n        print \"\\t@echo archiving.${_target_mode} ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    else\n        print \"\\t@echo linking.${_target_mode} ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    fi\n    case \"${toolname}\" in\n        gcc) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        gxx) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        clang) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        clangxx) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        emcc) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        emxx) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        cosmocc) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        cosmocxx) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        tcc) _gmake_add_build_target_for_gcc_clang \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        ar) _gmake_add_build_target_for_ar \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        emar) _gmake_add_build_target_for_ar \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        cosmoar) _gmake_add_build_target_for_ar \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${flagname}\";;\n        *) raise \"unknown toolname(${toolname})!\" ;;\n    esac\n\n    # @see https://github.com/tboox/tbox/issues/214\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n        _get_target_soname \"${target}\"; local soname=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            _get_target_filename \"${target}\"; local filename=\"${_ret}\"\n            _get_target_extension \"${target}\"; local extension=\"${_ret}\"\n            local targetfile_with_version=\"${targetdir}/${filename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${filename}\"; local basename=\"${_ret}\"\n                targetfile_with_version=\"${targetdir}/${basename}.${version}${extension}\"\n            fi\n            local targetfile_with_soname=\"${targetdir}/${soname}\"\n            path_filename \"${targetfile_with_version}\"; local targetfilename_with_version=\"${_ret}\"\n            if test_nq \"${soname}\" \"${filename}\" && test_nq \"${soname}\" \"${targetfilename_with_version}\"; then\n                print \"\\t@cp -p ${targetfile} ${targetfile_with_version}\" >> \"${xmake_sh_makefile}\"\n                print \"\\t@cd ${targetdir} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}\" >> \"${xmake_sh_makefile}\"\n            fi\n        fi\n    fi\n\n    # end\n    echo \"\" >> \"${xmake_sh_makefile}\"\n\n    # build objects\n    _gmake_add_build_objects \"${target}\"\n}\n\n_gmake_add_build_targets() {\n    local target=\"\"\n    local defaults=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            defaults=\"${defaults} ${target}\"\n        fi\n    done\n    echo \"default:${defaults}\" >> \"${xmake_sh_makefile}\"\n    echo \"all:${_xmake_sh_targets}\" >> \"${xmake_sh_makefile}\"\n    echo \".PHONY: default all\" >> \"${xmake_sh_makefile}\"\n    echo \"\" >> \"${xmake_sh_makefile}\"\n    for target in ${_xmake_sh_targets}; do\n        _gmake_add_build_target \"${target}\"\n    done\n}\n\n_gmake_add_build() {\n    _gmake_add_build_targets\n}\n\n_gmake_add_run_target() {\n    local target=${1}\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    if is_plat \"macosx\"; then\n        print \"\\t@DYLD_LIBRARY_PATH=${targetdir} ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    elif is_plat \"linux\" \"bsd\"; then\n        print \"\\t@LD_LIBRARY_PATH=${targetdir} ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    else\n        print \"\\t@${targetfile}\" >> \"${xmake_sh_makefile}\"\n    fi\n}\n\n_gmake_add_run_targets() {\n    local target=\"\"\n    local targets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        _get_target_item \"${target}\" \"kind\"; local kind=\"${_ret}\"\n        if test \"x${kind}\" = \"xbinary\"; then\n            if _is_target_default \"${target}\"; then\n                targets=\"${targets} ${target}\"\n            fi\n        fi\n    done\n    echo \"run:${targets}\" >> \"${xmake_sh_makefile}\"\n    for target in ${targets}; do\n        _gmake_add_run_target \"${target}\"\n    done\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_run() {\n    _gmake_add_run_targets\n}\n\n_gmake_add_clean_target() {\n    local target=${1}\n    local objectfile=\"\"\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    _get_target_objectfiles \"${target}\"; local objectfiles=\"${_ret}\"\n    print \"\\t@rm ${targetfile}\" >> \"${xmake_sh_makefile}\"\n    for objectfile in ${objectfiles}; do\n        print \"\\t@rm ${objectfile}\" >> \"${xmake_sh_makefile}\"\n    done\n\n    # @see https://github.com/tboox/tbox/issues/214\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n        _get_target_soname \"${target}\"; local soname=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            _get_target_filename \"${target}\"; local filename=\"${_ret}\"\n            _get_target_extension \"${target}\"; local extension=\"${_ret}\"\n            local targetfile_with_version=\"${targetdir}/${filename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${filename}\"; local basename=\"${_ret}\"\n                targetfile_with_version=\"${targetdir}/${basename}.${version}${extension}\"\n            fi\n            local targetfile_with_soname=\"${targetdir}/${soname}\"\n            print \"\\t@if test -f ${targetfile_with_soname}; then rm ${targetfile_with_soname}; fi\" >> \"${xmake_sh_makefile}\"\n            print \"\\t@if test -f ${targetfile_with_version}; then rm ${targetfile_with_version}; fi\" >> \"${xmake_sh_makefile}\"\n        fi\n    fi\n}\n\n_gmake_add_clean_targets() {\n    local target=\"\"\n    local targets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            targets=\"${targets} ${target}\"\n        fi\n    done\n    echo \"clean:${targets}\" >> \"${xmake_sh_makefile}\"\n    for target in ${targets}; do\n        _gmake_add_clean_target \"${target}\"\n    done\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_clean() {\n    _gmake_add_clean_targets\n}\n\n_gmake_add_install_target() {\n    local target=${1}\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    path_filename \"${targetfile}\"; local filename=\"${_ret}\"\n    _get_target_item \"${target}\" \"installdir\"; local installdir=\"${_ret}\"\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_z \"${installdir}\"; then\n        installdir=\"\\$(INSTALLDIR)\"\n    fi\n\n    # before install\n    _get_target_item \"${target}\" \"before_install\"; local before_install=\"${_ret}\"\n    if test_nz \"${before_install}\"; then\n        eval ${before_install} \"\\${target}\" \"\\${installdir}\"\n    fi\n\n    # @see https://github.com/tboox/tbox/issues/214\n    install_for_soname=false\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n        _get_target_soname \"${target}\"; local soname=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            _get_target_extension \"${target}\"; local extension=\"${_ret}\"\n            string_replace \"${_install_libdir_default}\" \"\\${prefix}\" \"${installdir}\"; _install_libdir_default=\"${_ret}\"\n            local targetfile_with_version=\"${_install_libdir_default}/${filename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${filename}\"; local basename=\"${_ret}\"\n                targetfile_with_version=\"${_install_libdir_default}/${basename}.${version}${extension}\"\n            fi\n            local targetfile_with_soname=\"${_install_libdir_default}/${soname}\"\n            path_filename \"${targetfile_with_version}\"; local targetfilename_with_version=\"${_ret}\"\n            if test_nq \"${soname}\" \"${filename}\" && test_nq \"${soname}\" \"${targetfilename_with_version}\"; then\n                install_for_soname=true\n            fi\n        fi\n    fi\n\n    # install target file\n    if test_eq \"${targetkind}\" \"binary\"; then\n        string_replace \"${_install_bindir_default}\" \"\\${prefix}\" \"${installdir}\"; _install_bindir_default=\"${_ret}\"\n        print \"\\t@echo installing ${targetfile} to ${_install_bindir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@mkdir -p ${_install_bindir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp -p ${targetfile} ${_install_bindir_default}/${filename}\" >> \"${xmake_sh_makefile}\"\n    elif ${install_for_soname}; then\n        string_replace \"${_install_libdir_default}\" \"\\${prefix}\" \"${installdir}\"; _install_libdir_default=\"${_ret}\"\n        print \"\\t@echo installing ${targetfile} to ${_install_libdir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@mkdir -p ${_install_libdir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp -p ${targetfile} ${targetfile_with_version}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cd ${_install_libdir_default} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}\" >> \"${xmake_sh_makefile}\"\n    elif test_eq \"${targetkind}\" \"static\" || test_eq \"${targetkind}\" \"shared\"; then\n        string_replace \"${_install_libdir_default}\" \"\\${prefix}\" \"${installdir}\"; _install_libdir_default=\"${_ret}\"\n        print \"\\t@echo installing ${targetfile} to ${_install_libdir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@mkdir -p ${_install_libdir_default}\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp -p ${targetfile} ${_install_libdir_default}/${filename}\" >> \"${xmake_sh_makefile}\"\n    fi\n\n    # install header files\n    _get_target_item \"${target}\" \"headerfiles\"; local headerfiles=\"${_ret}\"\n    if test_nz \"${headerfiles}\"; then\n        string_replace \"${_install_includedir_default}\" \"\\${prefix}\" \"${installdir}\"; _install_includedir_default=\"${_ret}\"\n        local srcheaderfile=\"\"\n        local includedir=\"${_install_includedir_default}\"\n        for srcheaderfile in ${headerfiles}; do\n            string_split \"${srcheaderfile}\" \":\"\n            local srcheaderfile=\"${_ret}\"\n            local rootdir=\"${_ret2}\"\n            local prefixdir=\"${_ret3}\"\n            local filename=\"${_ret4}\"\n            if test_z \"${filename}\"; then\n                path_filename \"${srcheaderfile}\"; filename=\"${_ret}\"\n            fi\n            local dstheaderdir=\"${includedir}\"\n            if test_nz \"${prefixdir}\"; then\n                dstheaderdir=\"${dstheaderdir}/${prefixdir}\"\n            fi\n            local dstheaderfile=\"${dstheaderdir}/${filename}\"\n            if test_nz \"${rootdir}\"; then\n                path_relative \"${rootdir}\" \"${srcheaderfile}\"; local subfile=\"${_ret}\"\n                dstheaderfile=\"${dstheaderdir}/${subfile}\"\n            fi\n            path_directory \"${dstheaderfile}\"; dstheaderdir=\"${_ret}\"\n            print \"\\t@mkdir -p ${dstheaderdir}\" >> \"${xmake_sh_makefile}\"\n            print \"\\t@cp -p ${srcheaderfile} ${dstheaderfile}\" >> \"${xmake_sh_makefile}\"\n        done\n    fi\n\n    # install user files\n    _get_target_item \"${target}\" \"installfiles\"; local installfiles=\"${_ret}\"\n    if test_nz \"${installfiles}\"; then\n        local srcinstallfile=\"\"\n        for srcinstallfile in ${installfiles}; do\n            string_split \"${srcinstallfile}\" \":\"\n            local srcinstallfile=\"${_ret}\"\n            local rootdir=\"${_ret2}\"\n            local prefixdir=\"${_ret3}\"\n            local filename=\"${_ret4}\"\n            if test_z \"${filename}\"; then\n                path_filename \"${srcinstallfile}\"; filename=\"${_ret}\"\n            fi\n            local dstinstalldir=\"${installdir}\"\n            if test_nz \"${prefixdir}\"; then\n                dstinstalldir=\"${dstinstalldir}/${prefixdir}\"\n            fi\n            local dstinstallfile=\"${dstinstalldir}/${filename}\"\n            if test_nz \"${rootdir}\"; then\n                path_relative \"${rootdir}\" \"${srcinstallfile}\"; local subfile=\"${_ret}\"\n                dstinstallfile=\"${dstinstalldir}/${subfile}\"\n            fi\n            path_directory \"${dstinstallfile}\"; dstinstalldir=\"${_ret}\"\n            print \"\\t@mkdir -p ${dstinstalldir}\" >> \"${xmake_sh_makefile}\"\n            print \"\\t@cp -p ${srcinstallfile} ${dstinstallfile}\" >> \"${xmake_sh_makefile}\"\n        done\n    fi\n\n    # after install\n    _get_target_item \"${target}\" \"after_install\"; local after_install=\"${_ret}\"\n    if test_nz \"${after_install}\"; then\n        eval ${after_install} \"\\${target}\" \"\\${installdir}\"\n    fi\n}\n\n_gmake_add_install_targets() {\n    local target=\"\"\n    local targets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            targets=\"${targets} ${target}\"\n        fi\n    done\n    echo \"install:${targets}\" >> \"${xmake_sh_makefile}\"\n    for target in ${targets}; do\n        _gmake_add_install_target \"${target}\"\n    done\n    echo \"\" >> \"${xmake_sh_makefile}\"\n}\n\n_gmake_add_install() {\n    _gmake_add_install_targets\n}\n\n_gmake_done() {\n    echo \"makefile is generated!\"\n    if \"${xmake_sh_diagnosis}\"; then\n        cat \"${xmake_sh_makefile}\"\n    fi\n}\n\n# generate build file for gmake\n_generate_for_gmake() {\n    _gmake_begin\n    _gmake_add_header\n    _gmake_add_switches\n    _gmake_add_toolchains\n    _gmake_add_flags\n    _gmake_add_build\n    _gmake_add_clean\n    _gmake_add_install\n    _gmake_add_run\n    _gmake_done\n}\n\n#-----------------------------------------------------------------------------\n# generate ninja file\n#\n\n_ninja_begin() {\n    echo \"generating ninja build file ..\"\n}\n\n_ninja_add_header() {\n    echo \"# this is the build file for this project\n# it is autogenerated by the xmake.sh build system.\n# do not edit by hand.\n\" > \"${xmake_sh_ninjafile}\"\n    echo \"ninja_required_version = 1.3\" >> \"${xmake_sh_ninjafile}\"\n    echo \"builddir = ${xmake_sh_builddir}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_switches() {\n    local value=\"\"\n    value=\"${_install_prefix_default}\"; _ninja_escape \"${value}\"; value=\"${_ret}\"\n    echo \"prefix_default = ${value}\" >> \"${xmake_sh_ninjafile}\"\n    value=\"${_install_bindir_default}\"; _ninja_escape \"${value}\"; value=\"${_ret}\"\n    echo \"bindir_default = ${value}\" >> \"${xmake_sh_ninjafile}\"\n    value=\"${_install_libdir_default}\"; _ninja_escape \"${value}\"; value=\"${_ret}\"\n    echo \"libdir_default = ${value}\" >> \"${xmake_sh_ninjafile}\"\n    value=\"${_install_includedir_default}\"; _ninja_escape \"${value}\"; value=\"${_ret}\"\n    echo \"includedir_default = ${value}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_rules() {\n    echo \"rule command\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  command = \\$command\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = \\$description\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = \\$restat\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_toolchains() {\n    _get_targets_toolkinds; local kinds=\"${_ret}\"\n    if test_nz \"${kinds}\"; then\n        echo \"# toolchain programs\" >> \"${xmake_sh_ninjafile}\"\n        for kind in ${kinds}; do\n            _get_toolchain_toolset \"${_target_toolchain}\" \"${kind}\"; local program=\"${_ret}\"\n            echo \"${kind} = ${program}\" >> \"${xmake_sh_ninjafile}\"\n        done\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n    fi\n}\n\n_ninja_add_flags() {\n    _get_targets_toolkinds; local kinds=\"${_ret}\"\n    for target in ${_xmake_sh_targets}; do\n        for kind in ${kinds}; do\n            _get_target_flags \"${target}\" \"${kind}\"; local flags=\"${_ret}\"\n            if test_nz \"${flags}\"; then\n                _get_flagname \"${kind}\"; local flagname=\"${_ret}\"\n                local key=\"${target}_${flagname}\"\n                _ninja_escape \"${flags}\"; flags=\"${_ret}\"\n                echo \"${key} = ${flags}\" >> \"${xmake_sh_ninjafile}\"\n            fi\n        done\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n    done\n}\n\n_ninja_add_build_object() {\n    local target=${1}\n    local sourcefile=\"${2}\"\n    local objectfile=\"${3}\"\n    path_sourcekind \"${sourcefile}\"; local sourcekind=\"${_ret}\"\n    _get_target_flags \"${target}\" \"${sourcekind}\"; local flags=\"${_ret}\"\n    _toolchain_compcmd \"${sourcekind}\" \"${objectfile}\" \"${sourcefile}\" \"${flags}\"; local compcmd=\"${_ret}\"\n    path_directory \"${objectfile}\"; local objectdir=\"${_ret}\"\n    local use_shell_wrapper=false\n    local command=\"mkdir -p \\\"${objectdir}\\\" && ${compcmd}\"\n    if is_host \"msys\" \"cygwin\" \"mingw\"; then\n        use_shell_wrapper=true\n    fi\n    if ${use_shell_wrapper}; then\n        _shell_escape_single_quotes \"${command}\"; local command_script=\"${_ret}\"\n        command=\"sh -lc ${command_script}\"\n    fi\n    local description=\"compiling.${_target_mode} ${sourcefile}\"\n    _ninja_escape \"${command}\"; command=\"${_ret}\"\n    _ninja_escape \"${description}\"; description=\"${_ret}\"\n    echo \"build ${objectfile}: command ${sourcefile}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  command = ${command}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = ${description}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = 0\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_build_objects() {\n    local target=${1}\n    _get_target_sourcefiles \"${target}\"; local sourcefiles=\"${_ret}\"\n    for sourcefile in ${sourcefiles}; do\n        _get_target_objectfile \"${target}\" \"${sourcefile}\"; local objectfile=\"${_ret}\"\n        _ninja_add_build_object \"${target}\" \"${sourcefile}\" \"${objectfile}\"\n    done\n}\n\n_ninja_add_build_target() {\n    local target=${1}\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    _get_target_item \"${target}\" \"deps\"; local deps=\"${_ret}\"\n    _get_target_objectfiles \"${target}\"; local objectfiles=\"${_ret}\"\n\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n    local toolkind=\"\"\n    case \"${targetkind}\" in\n        binary) toolkind=\"ld\";;\n        static) toolkind=\"ar\";;\n        shared) toolkind=\"sh\";;\n        *) raise \"unknown targetkind(${targetkind})!\" ;;\n    esac\n    _get_target_flags \"${target}\" \"${toolkind}\"; local linkflags=\"${_ret}\"\n    _toolchain_linkcmd \"${toolkind}\" \"${targetfile}\" \"${objectfiles}\" \"${linkflags}\"; local linkcmd=\"${_ret}\"\n\n    local use_shell_wrapper=false\n    local command=\"mkdir -p \\\"${targetdir}\\\" && ${linkcmd}\"\n    if is_host \"msys\" \"cygwin\" \"mingw\"; then\n        use_shell_wrapper=true\n    fi\n    local description=\"linking.${_target_mode} ${targetfile}\"\n\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n        _get_target_soname \"${target}\"; local soname=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            _get_target_filename \"${target}\"; local targetfilename=\"${_ret}\"\n            _get_target_extension \"${target}\"; local extension=\"${_ret}\"\n            local targetfile_with_version=\"${targetdir}/${targetfilename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${targetfilename}\"; local basename=\"${_ret}\"\n                targetfile_with_version=\"${targetdir}/${basename}.${version}${extension}\"\n            fi\n            local targetfile_with_soname=\"${targetdir}/${soname}\"\n            path_filename \"${targetfile_with_version}\"; local targetfilename_with_version=\"${_ret}\"\n            if test_nq \"${soname}\" \"${targetfilename}\" && test_nq \"${soname}\" \"${targetfilename_with_version}\"; then\n                command=\"${command} && cp -p ${targetfile} ${targetfile_with_version} && cd \\\"${targetdir}\\\" && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${targetfilename}\"\n            fi\n        fi\n    fi\n\n    if ${use_shell_wrapper}; then\n        _shell_escape_single_quotes \"${command}\"; local command_script=\"${_ret}\"\n        command=\"sh -lc ${command_script}\"\n    fi\n    _ninja_escape \"${command}\"; command=\"${_ret}\"\n    _ninja_escape \"${description}\"; description=\"${_ret}\"\n\n    local orderdeps=\"\"\n    local dep=\"\"\n    for dep in ${deps}; do\n        _get_target_file \"${dep}\"; local depfile=\"${_ret}\"\n        if test_nz \"${orderdeps}\"; then\n            orderdeps=\"${orderdeps} ${depfile}\"\n        else\n            orderdeps=\"${depfile}\"\n        fi\n    done\n\n    if test_nz \"${orderdeps}\"; then\n        echo \"build ${targetfile}: command ${objectfiles} | ${orderdeps}\" >> \"${xmake_sh_ninjafile}\"\n    else\n        echo \"build ${targetfile}: command ${objectfiles}\" >> \"${xmake_sh_ninjafile}\"\n    fi\n    echo \"  command = ${command}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = ${description}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = 0\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n\n    echo \"build ${target}: phony ${targetfile}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n\n    _ninja_add_build_objects \"${target}\"\n}\n\n_ninja_add_build_targets() {\n    local target=\"\"\n    local defaults=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            if test_nz \"${defaults}\"; then\n                defaults=\"${defaults} ${target}\"\n            else\n                defaults=\"${target}\"\n            fi\n        fi\n    done\n    if test_nz \"${defaults}\"; then\n        echo \"build default: phony ${defaults}\" >> \"${xmake_sh_ninjafile}\"\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n        echo \"default default\" >> \"${xmake_sh_ninjafile}\"\n    else\n        echo \"default all\" >> \"${xmake_sh_ninjafile}\"\n    fi\n    echo \"build all: phony ${_xmake_sh_targets}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n    for target in ${_xmake_sh_targets}; do\n        _ninja_add_build_target \"${target}\"\n    done\n}\n\n_ninja_add_build() {\n    _ninja_add_build_targets\n}\n\n_ninja_add_run_target() {\n    local target=${1}\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    local command=\"\"\n    if is_host \"msys\" \"cygwin\" \"mingw\"; then\n        local projectdir=\"${xmake_sh_projectdir}\"\n        local targetfile_rel=\"./${targetfile}\"\n        local targetfile_alt=\"./build/${targetfile#*/}\"\n        local targetbuilddir=\"${targetfile%/*}\"\n        local targetbuilddir_rel=\"./${targetbuilddir}\"\n        local targetbuilddir_alt=\"./build/${targetbuilddir#*/}\"\n        local run_script=\"cd \\\"${projectdir}\\\" && target=\\\"${targetfile_rel}\\\"; alt=\\\"${targetfile_alt}\\\"; if [ ! -f \\\"\\$target\\\" ] && [ -f \\\"\\$alt\\\" ]; then target=\\\"\\$alt\\\"; fi; if [ ! -f \\\"\\$target\\\" ]; then echo \\\"[ninja run] missing ${targetfile_rel} (and fallback ${targetfile_alt})\\\"; ls -l \\\"${targetbuilddir_rel}\\\" || true; ls -l \\\"${targetbuilddir_alt}\\\" || true; exit 1; fi; \\\"\\$target\\\"\"\n        _shell_escape_single_quotes \"${run_script}\"; local run_script_escaped=\"${_ret}\"\n        command=\"sh -lc ${run_script_escaped}\"\n    elif is_plat \"macosx\"; then\n        command=\"DYLD_LIBRARY_PATH=${targetdir} ${targetfile}\"\n    elif is_plat \"linux\" \"bsd\"; then\n        command=\"LD_LIBRARY_PATH=${targetdir} ${targetfile}\"\n    else\n        command=\"${targetfile}\"\n    fi\n    local description=\"running.${_target_mode} ${targetfile}\"\n    _ninja_escape \"${command}\"; command=\"${_ret}\"\n    _ninja_escape \"${description}\"; description=\"${_ret}\"\n    echo \"build run.${target}: command | ${targetfile}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  command = ${command}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = ${description}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = 0\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_run_targets() {\n    local target=\"\"\n    local runtargets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        _get_target_item \"${target}\" \"kind\"; local kind=\"${_ret}\"\n        if test_eq \"${kind}\" \"binary\"; then\n            if _is_target_default \"${target}\"; then\n                if test_nz \"${runtargets}\"; then\n                    runtargets=\"${runtargets} run.${target}\"\n                else\n                    runtargets=\"run.${target}\"\n                fi\n                _ninja_add_run_target \"${target}\"\n            fi\n        fi\n    done\n    if test_nz \"${runtargets}\"; then\n        echo \"build run: phony ${runtargets}\" >> \"${xmake_sh_ninjafile}\"\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n    fi\n}\n\n_ninja_add_run() {\n    _ninja_add_run_targets\n}\n\n_ninja_add_clean_target() {\n    local target=${1}\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    _get_target_objectfiles \"${target}\"; local objectfiles=\"${_ret}\"\n    local removefiles=\"${targetfile}\"\n    local objectfile=\"\"\n    for objectfile in ${objectfiles}; do\n        removefiles=\"${removefiles} ${objectfile}\"\n    done\n\n    _get_targetdir \"${target}\"; local targetdir=\"${_ret}\"\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; local version=\"${_ret}\"\n        _get_target_soname \"${target}\"; local soname=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            _get_target_filename \"${target}\"; local filename=\"${_ret}\"\n            _get_target_extension \"${target}\"; local extension=\"${_ret}\"\n            local targetfile_with_version=\"${targetdir}/${filename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                path_basename \"${filename}\"; local basename=\"${_ret}\"\n                targetfile_with_version=\"${targetdir}/${basename}.${version}${extension}\"\n            fi\n            local targetfile_with_soname=\"${targetdir}/${soname}\"\n            removefiles=\"${removefiles} ${targetfile_with_soname} ${targetfile_with_version}\"\n        fi\n    fi\n\n    local command=\"rm -f ${removefiles}\"\n    local description=\"cleaning.${_target_mode} ${target}\"\n    _ninja_escape \"${command}\"; command=\"${_ret}\"\n    _ninja_escape \"${description}\"; description=\"${_ret}\"\n    echo \"build clean.${target}: command\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  command = ${command}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = ${description}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = 0\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_clean_targets() {\n    local target=\"\"\n    local cleantargets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            if test_nz \"${cleantargets}\"; then\n                cleantargets=\"${cleantargets} clean.${target}\"\n            else\n                cleantargets=\"clean.${target}\"\n            fi\n            _ninja_add_clean_target \"${target}\"\n        fi\n    done\n    if test_nz \"${cleantargets}\"; then\n        echo \"build clean: phony ${cleantargets}\" >> \"${xmake_sh_ninjafile}\"\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n    fi\n}\n\n_ninja_add_clean() {\n    _ninja_add_clean_targets\n}\n\n_ninja_install_prepare_script() {\n    local target=\"${1}\"\n    local ninjadir=\"${xmake_sh_builddir}/.ninja\"\n    local scriptdir=\"${xmake_sh_projectdir}/${ninjadir}\"\n    mkdir -p \"${scriptdir}\"\n    _ret=\"${scriptdir}/install_${target}.sh\"\n    _ret2=\"${ninjadir}/install_${target}.sh\"\n}\n\n_ninja_install_write_header() {\n    local scriptfile=\"${1}\"\n    local escaped_prefix_default=\"${2}\"\n    local escaped_installdir_template=\"${3}\"\n    local escaped_projectdir=\"${4}\"\n    local escaped_bindir_template=\"${5}\"\n    local escaped_libdir_template=\"${6}\"\n    local escaped_includedir_template=\"${7}\"\n\n    cat > \"${scriptfile}\" <<EOF\n#!/bin/sh\nset -e\n\nprefix=${escaped_prefix_default}\nif [ -n \"\\${PREFIX}\" ]; then\n    prefix=\"\\${PREFIX}\"\nfi\ndestdir=\"\\${DESTDIR}\"\ninstalldir_template=${escaped_installdir_template}\nplaceholder='\\${prefix}'\n_rp_value=\"\"\n_rp_replacement=\"\"\n_rp_before=\"\"\n_rp_after=\"\"\n_rp_result=\"\"\n\nreplace_placeholder() {\n    _rp_value=\"\\$1\"\n    _rp_replacement=\"\\$2\"\n    while :; do\n        case \"\\${_rp_value}\" in\n            *\\${placeholder}*)\n                _rp_before=\"\\${_rp_value%%\\${placeholder}*}\"\n                _rp_after=\"\\${_rp_value#*\\${placeholder}}\"\n                _rp_value=\"\\${_rp_before}\\${_rp_replacement}\\${_rp_after}\"\n                ;;\n            *)\n                break\n                ;;\n        esac\n    done\n    _rp_result=\"\\${_rp_value}\"\n}\n\nprojectdir=${escaped_projectdir}\ncd \"\\${projectdir}\"\n\ninstalldir=\"\"\nif [ -z \"\\${installdir_template}\" ]; then\n    installdir=\"\\${destdir}\"\n    if [ -n \"\\${installdir}\" ]; then\n        prefix_trim=\"\\${prefix#/}\"\n        installdir=\"\\${installdir}/\\${prefix_trim}\"\n    else\n        installdir=\"\\${prefix}\"\n    fi\nelse\n    installdir=\"\\${installdir_template}\"\n    replace_placeholder \"\\${installdir}\" \"\\${prefix}\"\n    installdir=\"\\${_rp_result}\"\n    if [ -n \"\\${destdir}\" ]; then\n        case \"\\${installdir}\" in\n            /*) ;;\n            *) installdir=\"\\${destdir}/\\${installdir}\" ;;\n        esac\n    fi\nfi\n\nresolve_prefix_path() {\n    replace_placeholder \"\\$1\" \"\\${installdir}\"\n    printf '%s' \"\\${_rp_result}\"\n}\n\ncopy_file() {\n    local src=\"\\$1\"\n    local dst_template=\"\\$2\"\n    local dst\n    dst=\\$(resolve_prefix_path \"\\${dst_template}\")\n    echo \"installing \\${src} to \\${dst}\"\n    mkdir -p \"\\$(dirname \"\\${dst}\")\"\n    cp -p \"\\${src}\" \"\\${dst}\"\n}\n\nbindir_template=${escaped_bindir_template}\nlibdir_template=${escaped_libdir_template}\nincludedir_template=${escaped_includedir_template}\nEOF\n}\n\n_ninja_install_append_target_artifacts() {\n    local scriptfile=\"${1}\"\n    local targetkind=\"${2}\"\n    local install_for_soname=\"${3}\"\n    local targetfile=\"${4}\"\n    local filename=\"${5}\"\n    local version=\"${6}\"\n    local soname=\"${7}\"\n    local extension=\"${8}\"\n    local filename_basename=\"${9}\"\n\n    if test_eq \"${targetkind}\" \"binary\"; then\n        _shell_escape_single_quotes \"${targetfile}\"; local escaped_targetfile=\"${_ret}\"\n        local dest_template=\"${_install_bindir_default}/${filename}\"\n        _shell_escape_single_quotes \"${dest_template}\"; local escaped_dest_template=\"${_ret}\"\n        echo \"copy_file ${escaped_targetfile} ${escaped_dest_template}\" >> \"${scriptfile}\"\n    elif ${install_for_soname}; then\n        local version_template=\"${_install_libdir_default}/${filename}.${version}\"\n        if test_eq \"${extension}\" \".dylib\"; then\n            version_template=\"${_install_libdir_default}/${filename_basename}.${version}${extension}\"\n        fi\n        _shell_escape_single_quotes \"${targetfile}\"; local escaped_targetfile=\"${_ret}\"\n        _shell_escape_single_quotes \"${version_template}\"; local escaped_version_template=\"${_ret}\"\n        _shell_escape_single_quotes \"${soname}\"; local escaped_soname=\"${_ret}\"\n        _shell_escape_single_quotes \"${filename}\"; local escaped_filename=\"${_ret}\"\n        cat >> \"${scriptfile}\" <<EOF\ncopy_file ${escaped_targetfile} ${escaped_version_template}\ndst_version=\\$(resolve_prefix_path ${escaped_version_template})\ndst_dir=\\$(dirname \"\\${dst_version}\")\nfilename_version=\\$(basename \"\\${dst_version}\")\n(\n    cd \"\\${dst_dir}\"\n    ln -sf \"\\${filename_version}\" ${escaped_soname}\n    ln -sf ${escaped_soname} ${escaped_filename}\n)\nEOF\n    elif test_eq \"${targetkind}\" \"static\" || test_eq \"${targetkind}\" \"shared\"; then\n        _shell_escape_single_quotes \"${targetfile}\"; local escaped_targetfile=\"${_ret}\"\n        local dest_template=\"${_install_libdir_default}/${filename}\"\n        _shell_escape_single_quotes \"${dest_template}\"; local escaped_dest_template=\"${_ret}\"\n        echo \"copy_file ${escaped_targetfile} ${escaped_dest_template}\" >> \"${scriptfile}\"\n    fi\n}\n\n_ninja_install_append_headerfiles() {\n    local scriptfile=\"${1}\"\n    local headerfiles=\"${2}\"\n    if test_nz \"${headerfiles}\"; then\n        local srcheaderfile=\"\"\n        for srcheaderfile in ${headerfiles}; do\n            string_split \"${srcheaderfile}\" \":\"\n            local srcheaderpath=\"${_ret}\"\n            local rootdir=\"${_ret2}\"\n            local prefixdir=\"${_ret3}\"\n            local headername=\"${_ret4}\"\n            if test_z \"${headername}\"; then\n                path_filename \"${srcheaderpath}\"; headername=\"${_ret}\"\n            fi\n            local dstheaderdir_template=\"${_install_includedir_default}\"\n            if test_nz \"${prefixdir}\"; then\n                dstheaderdir_template=\"${dstheaderdir_template}/${prefixdir}\"\n            fi\n            local dstheaderfile_template=\"\"\n            if test_nz \"${rootdir}\"; then\n                path_relative \"${rootdir}\" \"${srcheaderpath}\"; local subfile=\"${_ret}\"\n                dstheaderfile_template=\"${dstheaderdir_template}/${subfile}\"\n            else\n                dstheaderfile_template=\"${dstheaderdir_template}/${headername}\"\n            fi\n            _shell_escape_single_quotes \"${srcheaderpath}\"; local escaped_src=\"${_ret}\"\n            _shell_escape_single_quotes \"${dstheaderfile_template}\"; local escaped_dst=\"${_ret}\"\n            echo \"copy_file ${escaped_src} ${escaped_dst}\" >> \"${scriptfile}\"\n        done\n    fi\n}\n\n_ninja_install_append_installfiles() {\n    local scriptfile=\"${1}\"\n    local installdir=\"${2}\"\n    local installfiles=\"${3}\"\n    if test_nz \"${installfiles}\"; then\n        local srcinstallfile=\"\"\n        for srcinstallfile in ${installfiles}; do\n            string_split \"${srcinstallfile}\" \":\"\n            local srcfilepath=\"${_ret}\"\n            local rootdir=\"${_ret2}\"\n            local prefixdir=\"${_ret3}\"\n            local installname=\"${_ret4}\"\n            if test_z \"${installname}\"; then\n                path_filename \"${srcfilepath}\"; installname=\"${_ret}\"\n            fi\n            local dst_template=\"${installdir}\"\n            if test_z \"${dst_template}\"; then\n                dst_template=\"\\${prefix}\"\n            fi\n            if test_nz \"${prefixdir}\"; then\n                dst_template=\"${dst_template}/${prefixdir}\"\n            fi\n            if test_nz \"${rootdir}\"; then\n                path_relative \"${rootdir}\" \"${srcfilepath}\"; local subfile=\"${_ret}\"\n                dst_template=\"${dst_template}/${subfile}\"\n            else\n                dst_template=\"${dst_template}/${installname}\"\n            fi\n            _shell_escape_single_quotes \"${srcfilepath}\"; local escaped_src=\"${_ret}\"\n            _shell_escape_single_quotes \"${dst_template}\"; local escaped_dst=\"${_ret}\"\n            echo \"copy_file ${escaped_src} ${escaped_dst}\" >> \"${scriptfile}\"\n        done\n    fi\n}\n\n_ninja_add_install_target() {\n    local target=${1}\n    _get_target_file \"${target}\"; local targetfile=\"${_ret}\"\n    path_filename \"${targetfile}\"; local filename=\"${_ret}\"\n    _get_target_item \"${target}\" \"installdir\"; local installdir=\"${_ret}\"\n    _get_target_item \"${target}\" \"kind\"; local targetkind=\"${_ret}\"\n\n    local install_for_soname=false\n    local version=\"\"\n    local soname=\"\"\n    local extension=\"\"\n    local filename_basename=\"\"\n    if test_eq \"${targetkind}\" \"shared\"; then\n        _get_target_item \"${target}\" \"version\"; version=\"${_ret}\"\n        _get_target_soname \"${target}\"; soname=\"${_ret}\"\n        _get_target_extension \"${target}\"; extension=\"${_ret}\"\n        path_basename \"${filename}\"; filename_basename=\"${_ret}\"\n        if test_nz \"${soname}\" && test_nz \"${version}\"; then\n            local targetfilename_with_version_guess=\"${filename}.${version}\"\n            if test_eq \"${extension}\" \".dylib\"; then\n                targetfilename_with_version_guess=\"${filename_basename}.${version}${extension}\"\n            fi\n            if test_nq \"${soname}\" \"${filename}\" && test_nq \"${soname}\" \"${targetfilename_with_version_guess}\"; then\n                install_for_soname=true\n            fi\n        fi\n    fi\n\n    _ninja_install_prepare_script \"${target}\"\n    local scriptfile=\"${_ret}\"\n    local scriptfile_rel=\"${_ret2}\"\n\n    _shell_escape_single_quotes \"${_install_prefix_default}\"; local escaped_prefix_default=\"${_ret}\"\n    _shell_escape_single_quotes \"${installdir}\"; local escaped_installdir_template=\"${_ret}\"\n    _shell_escape_single_quotes \"${xmake_sh_projectdir}\"; local escaped_projectdir=\"${_ret}\"\n    _shell_escape_single_quotes \"${_install_bindir_default}\"; local escaped_bindir_template=\"${_ret}\"\n    _shell_escape_single_quotes \"${_install_libdir_default}\"; local escaped_libdir_template=\"${_ret}\"\n    _shell_escape_single_quotes \"${_install_includedir_default}\"; local escaped_includedir_template=\"${_ret}\"\n\n    _ninja_install_write_header \"${scriptfile}\" \\\n        \"${escaped_prefix_default}\" \\\n        \"${escaped_installdir_template}\" \\\n        \"${escaped_projectdir}\" \\\n        \"${escaped_bindir_template}\" \\\n        \"${escaped_libdir_template}\" \\\n        \"${escaped_includedir_template}\"\n\n    _ninja_install_append_target_artifacts \"${scriptfile}\" \"${targetkind}\" \"${install_for_soname}\" \\\n        \"${targetfile}\" \"${filename}\" \"${version}\" \"${soname}\" \"${extension}\" \"${filename_basename}\"\n\n    _get_target_item \"${target}\" \"headerfiles\"; local headerfiles=\"${_ret}\"\n    _ninja_install_append_headerfiles \"${scriptfile}\" \"${headerfiles}\"\n\n    _get_target_item \"${target}\" \"installfiles\"; local installfiles=\"${_ret}\"\n    _ninja_install_append_installfiles \"${scriptfile}\" \"${installdir}\" \"${installfiles}\"\n\n    echo \"\" >> \"${scriptfile}\"\n    chmod +x \"${scriptfile}\"\n\n    local command=\"sh ${scriptfile_rel}\"\n    local description=\"installing.${_target_mode} ${target}\"\n    _ninja_escape \"${command}\"; command=\"${_ret}\"\n    _ninja_escape \"${description}\"; description=\"${_ret}\"\n    echo \"build install.${target}: command | ${targetfile}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  command = ${command}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  description = ${description}\" >> \"${xmake_sh_ninjafile}\"\n    echo \"  restat = 0\" >> \"${xmake_sh_ninjafile}\"\n    echo \"\" >> \"${xmake_sh_ninjafile}\"\n}\n\n_ninja_add_install_targets() {\n    local target=\"\"\n    local installtargets=\"\"\n    for target in ${_xmake_sh_targets}; do\n        if _is_target_default \"${target}\"; then\n            if test_nz \"${installtargets}\"; then\n                installtargets=\"${installtargets} install.${target}\"\n            else\n                installtargets=\"install.${target}\"\n            fi\n            _ninja_add_install_target \"${target}\"\n        fi\n    done\n    if test_nz \"${installtargets}\"; then\n        echo \"build install: phony ${installtargets}\" >> \"${xmake_sh_ninjafile}\"\n        echo \"\" >> \"${xmake_sh_ninjafile}\"\n    fi\n}\n\n_ninja_add_install() {\n    _ninja_add_install_targets\n}\n\n_ninja_done() {\n    echo \"ninja build file is generated!\"\n    if \"${xmake_sh_diagnosis}\"; then\n        cat \"${xmake_sh_ninjafile}\"\n    fi\n}\n\n# generate build file for ninja\n_generate_for_ninja() {\n    _ninja_begin\n    _ninja_add_header\n    _ninja_add_switches\n    _ninja_add_toolchains\n    _ninja_add_flags\n    _ninja_add_rules\n    _ninja_add_build\n    _ninja_add_clean\n    _ninja_add_install\n    _ninja_add_run\n    _ninja_done\n}\n\n#-----------------------------------------------------------------------------\n# generate build file\n#\n\n_generate_build_file() {\n    if test_eq \"${project_generator}\" \"gmake\"; then\n        _generate_for_gmake\n    elif test_eq \"${project_generator}\" \"ninja\"; then\n        _generate_for_ninja\n    else\n        raise \"unknown generator: ${project_generator}\"\n    fi\n}\n_generate_build_file\n\n"
  },
  {
    "path": "core/src/cli/xmake.c",
    "content": "/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmake/xmake.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * main\n */\ntb_int_t main(tb_int_t argc, tb_char_t** argv) {\n    return xm_engine_run(\"xmake\", argc, argv, tb_null, tb_null);\n}\n"
  },
  {
    "path": "core/src/cli/xmake.lua",
    "content": "target(\"cli\")\n\n    -- disable this target if only build libaries\n    if has_config(\"onlylib\") then\n        set_default(false)\n    end\n\n    -- add deps\n    add_deps(\"xmake\")\n\n    -- make as a binary\n    set_kind(\"binary\")\n    set_basename(\"xmake\")\n    set_targetdir(\"$(builddir)\")\n\n    -- add definitions\n    add_defines(\"__tb_prefix__=\\\"xmake\\\"\")\n\n    -- add includes directory\n    add_includedirs(\"$(projectdir)\", \"$(projectdir)/src\")\n\n    -- add common source files\n    add_files(\"**.c\")\n\n    -- add resource files (it will be enabled after publishing new version)\n    if is_plat(\"windows\") then\n        add_files(\"*.rc\")\n    end\n\n    -- add links\n    if is_plat(\"windows\") then\n        add_syslinks(\"ws2_32\", \"advapi32\", \"shell32\", \"wintrust\", \"crypt32\")\n        add_ldflags(\"/export:malloc\", \"/export:free\", \"/export:memmove\")\n    elseif is_plat(\"android\") then\n        add_syslinks(\"m\", \"c\")\n    elseif is_plat(\"macosx\") and is_config(\"runtime\", \"luajit\") then\n        add_ldflags(\"-all_load\", \"-pagezero_size 10000\", \"-image_base 100000000\")\n    elseif is_plat(\"mingw\") then\n        add_ldflags(\"-static-libgcc\", {force = true})\n    elseif is_plat(\"haiku\") then\n        add_syslinks(\"pthread\", \"network\", \"m\", \"c\")\n    else\n        add_syslinks(\"pthread\", \"dl\", \"m\", \"c\")\n    end\n\n    -- enable xp compatibility mode\n    if is_plat(\"windows\") then\n        if is_arch(\"x86\") then\n            add_ldflags(\"/subsystem:console,5.01\")\n        else\n            add_ldflags(\"/subsystem:console,5.02\")\n        end\n    end\n\n    -- add install files\n    if is_plat(\"windows\") then\n        add_installfiles(\"$(projectdir)/../LICENSE.md\")\n        add_installfiles(\"$(projectdir)/../NOTICE.md\")\n        add_installfiles(\"$(projectdir)/../xmake/(**.lua)\")\n        add_installfiles(\"$(projectdir)/../xmake/(scripts/**)\")\n        add_installfiles(\"$(projectdir)/../xmake/(repository/templates/**)\")\n        add_installfiles(\"$(projectdir)/../scripts/xrepo.bat\")\n        add_installfiles(\"$(projectdir)/../scripts/xrepo.ps1\")\n        set_prefixdir(\"/\", {bindir = \"/\"})\n        after_install(function (target)\n            os.cp(path.join(os.programdir(), \"winenv\"), target:installdir())\n        end)\n    else\n        add_installfiles(\"$(projectdir)/../(xmake/**.lua)\", {prefixdir = \"share\"})\n        add_installfiles(\"$(projectdir)/../(xmake/scripts/**)\", {prefixdir = \"share\"})\n        add_installfiles(\"$(projectdir)/../(xmake/repository/templates/**)\", {prefixdir = \"share\"})\n        add_installfiles(\"$(projectdir)/../scripts/xrepo.sh\", {prefixdir = \"bin\", filename = \"xrepo\"})\n    end\n\n    before_installcmd(function (target, batchcmds, opt)\n        -- we need to avoid some old files interfering with xmake's module import.\n        local package = opt.package\n        if target:is_plat(\"windows\") then\n            batchcmds:rmdir(package:installdir(\"actions\"))\n            batchcmds:rmdir(package:installdir(\"core\"))\n            batchcmds:rmdir(package:installdir(\"includes\"))\n            batchcmds:rmdir(package:installdir(\"languages\"))\n            batchcmds:rmdir(package:installdir(\"modules\"))\n            batchcmds:rmdir(package:installdir(\"platforms\"))\n            batchcmds:rmdir(package:installdir(\"plugins\"))\n            batchcmds:rmdir(package:installdir(\"repository\"))\n            batchcmds:rmdir(package:installdir(\"rules\"))\n            batchcmds:rmdir(package:installdir(\"templates\"))\n            batchcmds:rmdir(package:installdir(\"scripts\"))\n            batchcmds:rmdir(package:installdir(\"themes\"))\n            batchcmds:rmdir(package:installdir(\"toolchains\"))\n        end\n    end)\n"
  },
  {
    "path": "core/src/cli/xmake.rc",
    "content": "#include \"xmake.config.h\"\n#include \"winres.h\"\n\n#define _STR(x) #x\n#define STR(x) _STR(x)\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0\n PRODUCTVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS_NT_WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE VFT2_UNKNOWN\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"000004B0\"\n        BEGIN\n            VALUE \"Comments\", \"A cross-platform build utility based on Lua\\nwebsite: https://xmake.io\"\n            VALUE \"CompanyName\", \"The Xmake Open Source Community\"\n            VALUE \"FileDescription\", \"XMake build utility\"\n            VALUE \"FileVersion\", XM_CONFIG_VERSION \"+\" STR(XM_CONFIG_VERSION_BUILD)\n            VALUE \"InternalName\", \"xmake\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2015-present Ruki Wang, https://xmake.io\"\n            VALUE \"LegalTrademarks\", \"\"\n            VALUE \"OriginalFilename\", \"xmake.exe\"\n            VALUE \"ProductName\", \"XMake\"\n            VALUE \"ProductVersion\", XM_CONFIG_VERSION \"+\" STR(XM_CONFIG_VERSION_BUILD)\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0, 1200\n    END\nEND\n\n\nIDI_APP ICON DISCARDABLE \"xmake.ico\"\n"
  },
  {
    "path": "core/src/cli/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"cli\"\n    add_deps \"xmake\"\n    set_kind \"binary\"\n    set_basename \"xmake\"\n    set_targetdir \"${builddir}\"\n\n    # add definitions\n    add_defines \"__tb_prefix__=\\\"xmake\\\"\"\n\n    # add includes directory\n    add_includedirs \"${projectdir}/core\" \"${projectdir}/core/src\"\n\n    # add the common source files\n    add_files \"**.c\"\n\n    # add links\n    if is_plat \"macosx\" && is_config \"runtime\" \"luajit\"; then\n        add_ldflags \"-all_load\" \"-pagezero_size 10000\" \"-image_base 100000000\"\n    elif is_plat \"mingw\"; then\n        add_ldflags \"-static-libgcc\" \"-lwintrust\" \"-lcrypt32\"\n    fi\n\n    # add install files\n    add_installfiles \"${projectdir}/(xmake/**.lua)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/*)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/cmake_importfiles/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/completions/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/xpack/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/xrepo/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/virtualenvs/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/conan/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/scripts/module/**)\" \"share\"\n    add_installfiles \"${projectdir}/(xmake/repository/templates/**)\" \"share\"\n    add_installfiles \"${projectdir}/scripts/xrepo.sh\" \"bin\" \"xrepo\"\n\n    # fix os.exec() call incorrect program from /mingw64/bin. e.g. python, ..\n    #\n    # because xmake is installed to /mingw64/bin/xmake,\n    # os.exec/CreateProcess always gives the highest priority to finding the process from /mingw64/bin (if it exists),\n    # rather than from the $PATH environment variable.\n    #\n    # we install the xmake executable into a separate directory to ensure\n    # that os.exec() does not look for additional executables.\n    #\n    # @see https://github.com/xmake-io/xmake/issues/3628\n    if is_host \"msys\"; then\n        after_install \"xmake_after_install\"\n    fi\n\n    # add syslinks\n    add_options \"atomic\"\n    if is_plat \"mingw\" \"msys\" \"cygwin\"; then\n        add_syslinks \"ws2_32\" \"pthread\" \"m\"\n    elif is_plat \"bsd\" \"solaris\"; then\n        add_syslinks \"pthread\" \"m\"\n    elif is_plat \"haiku\"; then\n        add_syslinks \"pthread\" \"network\" \"m\"\n    elif test_nz \"${TERMUX_ARCH}\"; then\n        add_syslinks \"m\" \"dl\"\n    else\n        add_syslinks \"pthread\" \"dl\" \"m\" \"c\"\n    fi\n\nxmake_after_install() {\n    local target=${1}\n    local installdir=${2}\n    if test_eq \"${project_generator}\" \"gmake\"; then\n        print \"\\t@if test -f ${installdir}/bin/xmake.exe; then rm ${installdir}/bin/xmake.exe; fi\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp ${projectdir}/scripts/msys/xmake.sh ${installdir}/bin/xmake\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp ${projectdir}/scripts/msys/xmake.cmd ${installdir}/bin/xmake.cmd\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp ${projectdir}/scripts/msys/xmake.ps1 ${installdir}/bin/xmake.ps1\" >> \"${xmake_sh_makefile}\"\n        print \"\\t@cp ${builddir}/xmake.exe ${installdir}/share/xmake\" >> \"${xmake_sh_makefile}\"\n    fi\n}\n"
  },
  {
    "path": "core/src/lua/xmake.lua",
    "content": "target(\"lua\")\n    set_kind(\"static\")\n    set_warnings(\"all\")\n\n    -- disable c99(/TP) for windows\n    if is_plat(\"windows\") then\n        set_languages(\"c89\")\n    end\n\n    -- add header files\n    add_headerfiles(\"lua/(*.h)\", {prefixdir = \"lua\"})\n\n    -- add include directories\n    add_includedirs(\"lua\", {public = true})\n\n    -- add the common source files\n    add_files(\"lua/*.c|lua.c|onelua.c|loslib.c\")\n    if not is_plat(\"iphoneos\") then\n        add_files(\"lua/loslib.c\")\n    end\n\n    -- add definitions\n    add_defines(\"LUA_COMPAT_5_1\", \"LUA_COMPAT_5_2\", \"LUA_COMPAT_5_3\", {public = true})\n    if is_plat(\"windows\", \"mingw\") then\n        -- it has been defined in luaconf.h\n        --add_defines(\"LUA_USE_WINDOWS\")\n    elseif is_plat(\"macosx\", \"iphoneos\") then\n        add_defines(\"LUA_USE_MACOSX\")\n    else\n        add_defines(\"LUA_USE_LINUX\")\n    end\n\n    -- we just disable os.execute for ios, because os.execv do not use it\n    -- @see https://github.com/xmake-io/xmake/issues/2187\n    on_load(\"iphoneos\", function (target)\n        local loslib_file = target:autogenfile(\"loslib.c\")\n        os.cp(path.join(os.scriptdir(), \"lua\", \"loslib.c\"), loslib_file)\n        io.replace(loslib_file, \"system(cmd)\", \"0\", {plain = true})\n        target:add(\"files\", loslib_file)\n    end)\n"
  },
  {
    "path": "core/src/lua/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"lua\"\n    set_kind \"static\"\n    set_default false\n    set_warnings \"all\"\n\n    # add include directories\n    add_includedirs \"lua\" \"{public}\"\n\n    # add the common source files\n    add_files \"lua/lapi.c\"\n    add_files \"lua/lauxlib.c\"\n    add_files \"lua/lbaselib.c\"\n    add_files \"lua/lcode.c\"\n    add_files \"lua/lcorolib.c\"\n    add_files \"lua/lctype.c\"\n    add_files \"lua/ldblib.c\"\n    add_files \"lua/ldebug.c\"\n    add_files \"lua/ldo.c\"\n    add_files \"lua/ldump.c\"\n    add_files \"lua/lfunc.c\"\n    add_files \"lua/lgc.c\"\n    add_files \"lua/linit.c\"\n    add_files \"lua/liolib.c\"\n    add_files \"lua/llex.c\"\n    add_files \"lua/lmathlib.c\"\n    add_files \"lua/lmem.c\"\n    add_files \"lua/loadlib.c\"\n    add_files \"lua/lobject.c\"\n    add_files \"lua/lopcodes.c\"\n    add_files \"lua/loslib.c\"\n    add_files \"lua/lparser.c\"\n    add_files \"lua/lstate.c\"\n    add_files \"lua/lstring.c\"\n    add_files \"lua/lstrlib.c\"\n    add_files \"lua/ltable.c\"\n    add_files \"lua/ltablib.c\"\n    add_files \"lua/ltm.c\"\n    add_files \"lua/lundump.c\"\n    add_files \"lua/lutf8lib.c\"\n    add_files \"lua/lvm.c\"\n    add_files \"lua/lzio.c\"\n\n    # add definitions\n    add_defines \"LUA_COMPAT_5_1\" \"LUA_COMPAT_5_2\" \"LUA_COMPAT_5_3\" \"{public}\"\n    if is_plat \"mingw\"; then true\n        # it has been defined in luaconf.h\n        #add_defines \"LUA_USE_WINDOWS\"\n    elif is_plat \"macosx\"; then\n        add_defines \"LUA_USE_MACOSX\"\n    else\n        add_defines \"LUA_USE_LINUX\"\n    fi\n\n"
  },
  {
    "path": "core/src/lua-cjson/xmake.lua",
    "content": "target(\"lua-cjson\")\n    set_kind(\"static\")\n    set_warnings(\"all\")\n    if is_config(\"runtime\", \"luajit\") then\n        add_deps(\"luajit\")\n    else\n        add_deps(\"lua\")\n    end\n    if is_plat(\"windows\") then\n        set_languages(\"c89\")\n    end\n    add_files(\"lua-cjson/*.c|fpconv.c\")\n    -- Use internal strtod() / g_fmt() code for performance and disable multi-thread\n    add_defines(\"NDEBUG\", \"USE_INTERNAL_FPCONV\")\n    add_defines(\"XM_CONFIG_API_HAVE_LUA_CJSON\", {public = true})\n    if is_plat(\"windows\") then\n        add_defines(\"inline=__inline\")\n    end\n\n"
  },
  {
    "path": "core/src/lua-cjson/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"lua_cjson\"\n    set_kind \"static\"\n    set_default false\n    set_warnings \"all\"\n    if has_config \"external\"; then\n        if is_config \"runtime\" \"luajit\"; then\n            if has_config \"luajit\"; then\n                add_options \"luajit\" \"{public}\"\n            fi\n        else\n            if has_config \"lua\"; then\n                add_options \"lua\" \"{public}\"\n            fi\n        fi\n    else\n        if is_config \"runtime\" \"luajit\"; then\n            add_deps \"luajit\"\n        else\n            add_deps \"lua\"\n        fi\n    fi\n    add_files \"lua-cjson/dtoa.c\"\n    add_files \"lua-cjson/lua_cjson.c\"\n    add_files \"lua-cjson/strbuf.c\"\n    add_files \"lua-cjson/g_fmt.c\"\n    # Use internal strtod() / g_fmt() code for performance and disable multi-thread\n    add_defines \"NDEBUG\" \"USE_INTERNAL_FPCONV\"\n    add_defines \"XM_CONFIG_API_HAVE_LUA_CJSON\" \"{public}\"\n\n"
  },
  {
    "path": "core/src/luajit/xmake.lua",
    "content": "-- disable jit compiler for redhat and centos\nlocal jit = true\nlocal plat = \"$(plat)\"\nlocal arch = \"$(arch)\"\nif is_plat(\"msys\", \"mingw\", \"cygwin\") then\n    plat = \"windows\"\n    arch = is_arch(\"x86_64\") and \"x64\" or \"x86\"\nelseif is_plat(\"android\") then\n    plat = \"linux\"\nend\nif is_arch(\"arm64\", \"arm64-v8a\") then\n    arch = \"arm64\"\nelseif is_arch(\"arm.*\") then\n    arch = \"arm\"\nelseif is_arch(\"mips64.*\") then\n    arch = \"mips64\"\n    jit = false\nend\nif os.isfile(\"/etc/redhat-release\") then\n    jit = false\nend\nlocal autogendir = path.join(\"luajit\", \"autogen\", plat, jit and \"jit\" or \"nojit\", arch)\n\n-- add target\ntarget(\"luajit\")\n\n    -- make as a static library\n    set_kind(\"static\")\n\n    -- set warning all and disable error\n    set_warnings(\"all\")\n\n    -- disable c99(/TP) for windows\n    if is_plat(\"windows\") then\n        set_languages(\"c89\")\n    end\n\n    -- add header files\n    add_headerfiles(\"luajit/src/(*.h)\", {prefixdir = \"luajit\"})\n\n    -- add include directories\n    add_includedirs(autogendir)\n    add_includedirs(\"luajit/src\", {public = true})\n\n    -- add the common source files\n    add_files(\"luajit/src/*.c|ljamalg.c|luajit.c\")\n    if is_plat(\"windows\") then\n        add_files(autogendir .. \"/lj_vm.obj\")\n    elseif is_plat(\"msys\", \"cygwin\", \"mingw\") then\n        add_files(autogendir .. \"/lj_vm.o\")\n    else\n        add_files(autogendir .. \"/*.S\")\n    end\n\n    add_defines(\"USE_LUAJIT\", {interface = true})\n\n    -- disable jit compiler?\n    if not jit then\n        add_defines(\"LUAJIT_DISABLE_JIT\")\n    end\n\n    -- using internal memory management under armv7, gc will cause a crash when free strings in lua_close()\n    if arch == \"arm\" then\n        add_defines(\"LUAJIT_USE_SYSMALLOC\")\n    end\n\n    -- fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags\n    if is_plat(\"linux\") and is_arch(\"i386\") then\n        add_asflags(\"-fPIE\")\n        add_ldflags(\"-fPIE\")\n    end\n\n    -- enable lua5.2 compat, @see http://luajit.org/extensions.html\n    --[[\n    add_defines(\"LUAJIT_ENABLE_LUA52COMPAT\")\n    if not is_plat(\"windows\") then\n        add_cflags(\"-Wno-error=unused-function\")\n    end]]\n\n\n"
  },
  {
    "path": "core/src/luajit/xmake.sh",
    "content": "#!/bin/sh\n\n# disable jit compiler for redhat and centos\njit=true\njit_plat=\"${plat}\"\njit_arch=\"${arch}\"\nif is_plat \"mingw\"; then\n    jit_plat=\"windows\"\n    if is_arch \"x86_64\"; then\n        jit_arch=\"x64\"\n    else\n        jit_arch=\"x86\"\n    fi\nfi\nif is_arch \"arm64\" \"arm64-v8a\"; then\n    jit_arch=\"arm64\"\nelif is_arch \"arm\" \"armv7\"; then\n    jit_arch=\"arm\"\nelif is_arch \"mips64\"; then\n    jit_arch=\"mips64\"\n    jit=false\nfi\nif test -f \"/etc/redhat-release\"; then\n    jit=false\nfi\nif $jit; then\n    jit_dir=\"jit\"\nelse\n    jit_dir=\"nojit\"\nfi\njit_autogendir=\"luajit/autogen/${jit_plat}/${jit_dir}/${jit_arch}\"\n\ntarget \"luajit\"\n    set_kind \"static\"\n    set_default false\n    set_warnings \"all\"\n\n    # add include directories\n    add_includedirs \"${jit_autogendir}\"\n    add_includedirs \"luajit/src\" \"{public}\"\n\n    # add the common source files\n    add_files \"luajit/src/lj_*.c\"\n    add_files \"luajit/src/lib_*.c\"\n    if is_plat \"mingw\"; then\n        add_files \"${jit_autogendir}/lj_vm.o\"\n    else\n        add_files \"${jit_autogendir}/*.S\"\n    fi\n\n    add_defines \"USE_LUAJIT\" \"{public}\"\n\n    # disable jit compiler?\n    if ! $jit; then\n        add_defines \"LUAJIT_DISABLE_JIT\"\n    fi\n\n    # using internal memory management under armv7 gc will cause a crash when free strings in lua_close\n    if test_eq \"${jit_arch}\" \"arm\"; then\n        add_defines \"LUAJIT_USE_SYSMALLOC\"\n    fi\n\n    # fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags\n    if is_plat \"linux\" && is_arch \"i386\"; then\n        add_asflags \"-fPIE\"\n        add_ldflags \"-fPIE\"\n    fi\n\n"
  },
  {
    "path": "core/src/lz4/xmake.lua",
    "content": "target(\"lz4\")\n    set_kind(\"static\")\n    set_warnings(\"all\")\n\n    -- disable c99(/TP) for windows\n    if is_plat(\"windows\") then\n        set_languages(\"c89\")\n    end\n\n    -- add header files\n    add_headerfiles(\"lz4/lib/(*.h)\")\n\n    -- add include directories\n    add_includedirs(\"lz4/lib\", {public = true})\n\n    -- add the common source files\n    add_files(\"lz4/lib/*.c|lz4file.c\")\n\n    -- add definitions\n    add_defines(\"XXH_NAMESPACE=LZ4_\")\n\n"
  },
  {
    "path": "core/src/lz4/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"lz4\"\n    set_kind \"static\"\n    set_default false\n    set_warnings \"all\"\n    add_includedirs \"lz4/lib\" \"{public}\"\n    add_files \"lz4/lib/lz4.c\"\n    add_files \"lz4/lib/lz4frame.c\"\n    add_files \"lz4/lib/lz4hc.c\"\n    add_files \"lz4/lib/xxhash.c\"\n    add_defines \"XXH_NAMESPACE=LZ4_\"\n\n\n"
  },
  {
    "path": "core/src/pdcurses/xmake.lua",
    "content": "-- add target\ntarget(\"pdcurses\")\n\n    -- enable this target\n    if not has_config(\"pdcurses\") then\n        set_default(false)\n    end\n\n    -- make as a static library\n    set_kind(\"static\")\n\n    -- add includes directory\n    add_includedirs(\"pdcurses\", {public = true})\n\n    -- add the common source files\n    add_files(\"pdcurses/pdcurses/*.c\", \"pdcurses/wincon/*.c\")\n\n    -- add definitions\n    add_defines(\"PDC_WIDE\")\n\n    -- set languages\n    set_languages(\"c89\")\n\n    -- unset warnings\n    set_warnings(\"none\")\n"
  },
  {
    "path": "core/src/sv/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Autotools template\n# http://www.gnu.org/software/automake\n\nMakefile.in\n/ar-lib\n/mdate-sh\n/py-compile\n/test-driver\n/ylwrap\n\n# http://www.gnu.org/software/autoconf\n\n/autom4te.cache\n/autoscan.log\n/autoscan-*.log\n/aclocal.m4\n/compile\n/config.guess\n/config.h.in\n/config.sub\n/configure\n/configure.scan\n/depcomp\n/install-sh\n/missing\n/stamp-h1\n\n# https://www.gnu.org/software/libtool/\n\n/ltmain.sh\n\n# http://www.gnu.org/software/texinfo\n\n/texinfo.tex\n### CMake template\nCMakeCache.txt\nCMakeFiles\nCMakeScripts\nTesting\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ncompile_commands.json\nCTestTestfile.cmake\n### C template\n# Prerequisites\n*.d\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Linker output\n*.ilk\n*.map\n*.exp\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n*.idb\n*.pdb\n\n# Kernel Module Compile Results\n*.mod*\n*.cmd\nmodules.order\nModule.symvers\nMkfile.old\ndkms.conf\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff:\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/dictionaries\n\n# Sensitive or high-churn files:\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.xml\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n\n# Gradle:\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Mongo Explorer plugin:\n.idea/**/mongoSettings.xml\n\n## File-based project format:\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Clion\n.idea/\ncmake-build-debug/\n\n# xmake\n.xmake/\nbuild/\n"
  },
  {
    "path": "core/src/sv/.travis.yml",
    "content": "sudo: false\nlanguage: c\n\nbefore_install:\n  - bash <(curl -s https://raw.githubusercontent.com/xmake-io/xmake/master/scripts/get.sh)\n\ninstall:\n  - xmake\n  - cd build\n  - cmake ..\n  - make all\n\nscript:\n - ctest --verbose\n - cd .. && xmake check\n\nmatrix:\n  include:\n    - os: linux\n    - os: linux\n      compiler: gcc-4.9\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-4.9\n    - os: linux\n      compiler: gcc-5\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-5\n    - os: linux\n      compiler: gcc-6\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-6\n    - os: linux\n      compiler: clang-3.5\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-precise-3.5\n          packages:\n            - clang-3.5\n    - os: linux\n      compiler: clang-3.6\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-precise-3.6\n          packages:\n            - clang-3.6\n    - os: linux\n      compiler: clang-3.7\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-precise-3.7\n          packages:\n            - clang-3.7\n    - os: linux\n      compiler: clang-3.8\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-precise-3.8\n          packages:\n            - clang-3.8\n    - os: linux\n      compiler: clang-3.9\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-precise-3.9\n          packages:\n            - clang-3.9\n    - os: linux\n      dist: trusty\n      compiler: clang-4.0\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n            - llvm-toolchain-trusty-4.0\n          packages:\n            - clang-4.0\n    - os: osx\n      osx_image: xcode6.4\n      compiler: clang\n    - os: osx\n      osx_image: xcode7.3\n      compiler: clang\n    - os: osx\n      osx_image: xcode8.3\n      compiler: clang\n"
  },
  {
    "path": "core/src/sv/xmake.lua",
    "content": "includes(\"sv\")\n"
  },
  {
    "path": "core/src/sv/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"sv\"\n    set_kind \"static\"\n    set_default false\n    set_languages \"c99\"\n    add_includedirs \"sv/include\" \"{public}\"\n    add_files \"sv/src/*.c\"\n\n"
  },
  {
    "path": "core/src/tbox/inc/bsd/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_BSD 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/* #undef TB_CONFIG_API_HAVE_DEPRECATED */\n/* #undef TB_CONFIG_EXCEPTION_ENABLE */\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n#define TB_CONFIG_LIBC_HAVE_MEMMEM 1\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSNLEN */\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1\n#define TB_CONFIG_LIBC_HAVE_KILL 1\n#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n#define TB_CONFIG_LIBC_HAVE_SRANDOM 1\n#define TB_CONFIG_LIBC_HAVE_RANDOM 1\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n#define TB_CONFIG_POSIX_HAVE_PREADV 1\n#define TB_CONFIG_POSIX_HAVE_PWRITEV 1\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1\n/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n#define TB_CONFIG_POSIX_HAVE_PIPE2 1\n#define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#define TB_CONFIG_POSIX_HAVE_MMAP 1\n#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1\n#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1\n\n// windows functions\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/cygwin/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_WINDOWS 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/* #undef TB_CONFIG_API_HAVE_DEPRECATED */\n/* #undef TB_CONFIG_EXCEPTION_ENABLE */\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_KILL */\n/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */\n/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n/* #undef TB_CONFIG_POSIX_HAVE_POLL */\n/* #undef TB_CONFIG_POSIX_HAVE_SELECT */\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */\n/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */\n/* #undef TB_CONFIG_POSIX_HAVE_READV */\n/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREADV */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */\n/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */\n/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE */\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */\n/* #undef TB_CONFIG_POSIX_HAVE_MMAP */\n/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */\n/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */\n\n// windows functions\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/haiku/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230201\n\n// defines\n#define TB_CONFIG_OS_HAIKU 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/*#undef TB_CONFIG_MICRO_ENABLE*/\n/*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/*#undef TB_CONFIG_API_HAVE_DEPRECATED*/\n/*#undef TB_CONFIG_EXCEPTION_ENABLE*/\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n#define TB_CONFIG_LIBC_HAVE_MEMMEM 1\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRUPR*/\n/*#undef TB_CONFIG_LIBC_HAVE_STRLWR*/\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/\n/*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1\n#define TB_CONFIG_LIBC_HAVE_KILL 1\n/*#undef TB_CONFIG_LIBC_HAVE_BACKTRACE*/\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n#define TB_CONFIG_LIBC_HAVE_SRANDOM 1\n#define TB_CONFIG_LIBC_HAVE_RANDOM 1\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/*#undef TB_CONFIG_POSIX_HAVE_STAT64*/\n/*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n/*#undef TB_CONFIG_POSIX_HAVE_PREADV*/\n/*#undef TB_CONFIG_POSIX_HAVE_PWRITEV*/\n/*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/\n/*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/\n/*#undef TB_CONFIG_POSIX_HAVE_FDATASYNC*/\n/*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/\n/*#undef TB_CONFIG_POSIX_HAVE_SENDFILE*/\n/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/\n/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1\n#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)\n#   undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15\n#endif\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n/*#undef TB_CONFIG_POSIX_HAVE_PIPE2*/\n#define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#define TB_CONFIG_POSIX_HAVE_MMAP 1\n#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1\n#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1\n\n// windows functions\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n/*#undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP*/\n\n// linux functions\n/*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/\n\n// valgrind functions\n/*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/iphoneos/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_IOS 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/* #undef TB_CONFIG_API_HAVE_DEPRECATED */\n/* #undef TB_CONFIG_EXCEPTION_ENABLE */\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n#define TB_CONFIG_LIBC_HAVE_MEMMEM 1\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1\n#define TB_CONFIG_LIBC_HAVE_KILL 1\n#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n#define TB_CONFIG_LIBC_HAVE_SRANDOM 1\n#define TB_CONFIG_LIBC_HAVE_RANDOM 1\n\n// libm functions\n/* #undef TB_CONFIG_LIBM_HAVE_SINCOS */\n/* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1\n/* #undef TB_CONFIG_POSIX_HAVE_SEM_INIT */\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n/* #undef TB_CONFIG_POSIX_HAVE_PREADV */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */\n#define TB_CONFIG_POSIX_HAVE_COPYFILE 1\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n/* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP */\n#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)\n#   undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15\n#endif\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n#define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#define TB_CONFIG_POSIX_HAVE_MMAP 1\n#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1\n#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1\n\n// windows functions\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/linux/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_LINUX 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n#define TB_CONFIG_LIBC_HAVE_MEMMEM 1\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1\n#define TB_CONFIG_LIBC_HAVE_KILL 1\n/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n#define TB_CONFIG_LIBC_HAVE_SRANDOM 1\n#define TB_CONFIG_LIBC_HAVE_RANDOM 1\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n#if defined(__ANDROID__)\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n#else\n#   define TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP 1\n#endif\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n// alpine does not support\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n/* #undef TB_CONFIG_POSIX_HAVE_LSTAT64 */\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n// alpine does not support\n/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */\n/* #undef TB_CONFIG_LINUX_HAVE_IFADDRS */\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY 1\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n#define TB_CONFIG_POSIX_HAVE_PREADV 1\n#define TB_CONFIG_POSIX_HAVE_PWRITEV 1\n// alpine does not support\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1\n/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */\n#define TB_CONFIG_POSIX_HAVE_SENDFILE 1\n#ifdef __COSMOPOLITAN__\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#else\n#   define TB_CONFIG_POSIX_HAVE_EPOLL_CREATE 1\n#   define TB_CONFIG_POSIX_HAVE_EPOLL_WAIT 1\n#endif\n#if defined(__ANDROID__)\n/* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP */\n#else\n#   define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#endif\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#if defined(__ANDROID__)\n/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */\n#else\n#    define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#endif\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n#ifdef __COSMOPOLITAN__\n/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */\n#else\n#   define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#endif\n#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1\n#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n#define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n// linux functions\n#ifdef __COSMOPOLITAN__\n/* #undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT */\n#else\n#   define TB_CONFIG_LINUX_HAVE_INOTIFY_INIT 1\n#endif\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/macosx/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_MACOSX 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n#define TB_CONFIG_LIBC_HAVE_MEMMEM 1\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1\n#define TB_CONFIG_LIBC_HAVE_KILL 1\n#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n#define TB_CONFIG_LIBC_HAVE_SRANDOM 1\n#define TB_CONFIG_LIBC_HAVE_RANDOM 1\n\n// libm functions\n/* #undef TB_CONFIG_LIBM_HAVE_SINCOS */\n/* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n#if !defined(__arm64__) && !defined(__aarch64__)\n#   define TB_CONFIG_POSIX_HAVE_STAT64 1\n#   define TB_CONFIG_POSIX_HAVE_LSTAT64 1\n#else\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n#endif\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n/* #undef TB_CONFIG_POSIX_HAVE_PREADV */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */\n#define TB_CONFIG_POSIX_HAVE_COPYFILE 1\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n#define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1\n#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/mingw/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_WINDOWS 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/* #undef TB_CONFIG_API_HAVE_DEPRECATED */\n/* #undef TB_CONFIG_EXCEPTION_ENABLE */\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_KILL */\n/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */\n/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n/* #undef TB_CONFIG_POSIX_HAVE_POLL */\n/* #undef TB_CONFIG_POSIX_HAVE_SELECT */\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */\n/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */\n/* #undef TB_CONFIG_POSIX_HAVE_READV */\n/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREADV */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */\n/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */\n/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE */\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */\n/* #undef TB_CONFIG_POSIX_HAVE_MMAP */\n/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */\n/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */\n\n// windows functions\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/msys/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.3\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 3\n#define TB_CONFIG_VERSION_BUILD 20230119\n\n// defines\n#define TB_CONFIG_OS_WINDOWS 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/* #undef TB_CONFIG_MICRO_ENABLE */\n/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/* #undef TB_CONFIG_API_HAVE_DEPRECATED */\n/* #undef TB_CONFIG_EXCEPTION_ENABLE */\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */\n/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */\n/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRNLEN 1\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */\n/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */\n/* #undef TB_CONFIG_LIBC_HAVE_KILL */\n/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */\n/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */\n\n// libm functions\n#define TB_CONFIG_LIBM_HAVE_SINCOS 1\n#define TB_CONFIG_LIBM_HAVE_SINCOSF 1\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n/* #undef TB_CONFIG_POSIX_HAVE_POLL */\n/* #undef TB_CONFIG_POSIX_HAVE_SELECT */\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */\n/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */\n/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */\n/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */\n/* #undef TB_CONFIG_POSIX_HAVE_READV */\n/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREADV */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */\n/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */\n/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */\n/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */\n/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */\n/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n#define TB_CONFIG_POSIX_HAVE_VFORK 1\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */\n/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */\n/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */\n/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE */\n/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */\n/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */\n/* #undef TB_CONFIG_POSIX_HAVE_MMAP */\n/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */\n/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */\n\n// windows functions\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */\n/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */\n\n// bsd functions\n#define TB_CONFIG_BSD_HAVE_FLOCK 1\n\n// systemv functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */\n/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */\n\n// valgrind functions\n/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/inc/solaris/tbox.config.h",
    "content": "#ifndef TB_CONFIG_H\n#define TB_CONFIG_H\n\n// version\n#define TB_CONFIG_VERSION \"1.7.7\"\n#define TB_CONFIG_VERSION_MAJOR 1\n#define TB_CONFIG_VERSION_MINOR 7\n#define TB_CONFIG_VERSION_ALTER 7\n#define TB_CONFIG_VERSION_BUILD 20251123\n\n// defines\n#define TB_CONFIG_OS_SOLARIS 1\n#define _GNU_SOURCE 1\n#define _REENTRANT 1\n#define TB_CONFIG_SMALL 1\n/*#undef TB_CONFIG_MICRO_ENABLE*/\n/*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/\n#define TB_CONFIG_TYPE_HAVE_FLOAT 1\n#define TB_CONFIG_FORCE_UTF8 1\n/*#undef TB_CONFIG_API_HAVE_DEPRECATED*/\n/*#undef TB_CONFIG_EXCEPTION_ENABLE*/\n\n// keywords\n#define TB_CONFIG_KEYWORD_HAVE__thread 1\n#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1\n\n// features\n#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1\n\n// modules\n/* #undef TB_CONFIG_MODULE_HAVE_XML */\n/* #undef TB_CONFIG_MODULE_HAVE_ZIP */\n#define TB_CONFIG_MODULE_HAVE_HASH 1\n/* #undef TB_CONFIG_MODULE_HAVE_REGEX */\n/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */\n#define TB_CONFIG_MODULE_HAVE_CHARSET 1\n/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */\n/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */\n\n// packages\n/*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/\n/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/\n\n// libc functions\n#define TB_CONFIG_LIBC_HAVE_MEMCPY 1\n#define TB_CONFIG_LIBC_HAVE_MEMSET 1\n#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1\n#define TB_CONFIG_LIBC_HAVE_MEMCMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_MEMMEM*/\n#define TB_CONFIG_LIBC_HAVE_STRCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRNCAT 1\n#define TB_CONFIG_LIBC_HAVE_STRCPY 1\n#define TB_CONFIG_LIBC_HAVE_STRNCPY 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRLCPY*/\n#define TB_CONFIG_LIBC_HAVE_STRLEN 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRNLEN*/\n#define TB_CONFIG_LIBC_HAVE_STRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRRCHR 1\n#define TB_CONFIG_LIBC_HAVE_STRSTR 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRCASESTR*/\n#define TB_CONFIG_LIBC_HAVE_STRCMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRCASECMP*/\n#define TB_CONFIG_LIBC_HAVE_STRNCMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_STRNCASECMP*/\n\n#define TB_CONFIG_LIBC_HAVE_WCSCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1\n#define TB_CONFIG_LIBC_HAVE_WCSCPY 1\n#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSLCPY*/\n#define TB_CONFIG_LIBC_HAVE_WCSLEN 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSNLEN*/\n#define TB_CONFIG_LIBC_HAVE_WCSSTR 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/\n#define TB_CONFIG_LIBC_HAVE_WCSCMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSCASECMP*/\n#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP*/\n#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1\n#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1\n#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1\n#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1\n/*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/\n/*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/\n\n#define TB_CONFIG_LIBC_HAVE_GMTIME 1\n#define TB_CONFIG_LIBC_HAVE_MKTIME 1\n#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1\n#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1\n#define TB_CONFIG_LIBC_HAVE_SIGNAL 1\n#define TB_CONFIG_LIBC_HAVE_SETJMP 1\n/*#undef TB_CONFIG_LIBC_HAVE_SIGSETJMP*/\n/*#undef TB_CONFIG_LIBC_HAVE_KILL*/\n#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1\n#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1\n#define TB_CONFIG_LIBC_HAVE_FPUTC 1\n#define TB_CONFIG_LIBC_HAVE_FGETC 1\n#define TB_CONFIG_LIBC_HAVE_UNGETC 1\n#define TB_CONFIG_LIBC_HAVE_FPUTS 1\n#define TB_CONFIG_LIBC_HAVE_FGETS 1\n#define TB_CONFIG_LIBC_HAVE_FREAD 1\n#define TB_CONFIG_LIBC_HAVE_FWRITE 1\n/*#undef TB_CONFIG_LIBC_HAVE_SRANDOM*/\n/*#undef TB_CONFIG_LIBC_HAVE_RANDOM*/\n\n// libm functions\n/*#undef TB_CONFIG_LIBM_HAVE_SINCOS*/\n/*#undef TB_CONFIG_LIBM_HAVE_SINCOSF*/\n#define TB_CONFIG_LIBM_HAVE_LOG2 1\n#define TB_CONFIG_LIBM_HAVE_LOG2F 1\n#define TB_CONFIG_LIBM_HAVE_SQRT 1\n#define TB_CONFIG_LIBM_HAVE_SQRTF 1\n#define TB_CONFIG_LIBM_HAVE_ACOS 1\n#define TB_CONFIG_LIBM_HAVE_ACOSF 1\n#define TB_CONFIG_LIBM_HAVE_ASIN 1\n#define TB_CONFIG_LIBM_HAVE_ASINF 1\n#define TB_CONFIG_LIBM_HAVE_POW 1\n#define TB_CONFIG_LIBM_HAVE_POWF 1\n#define TB_CONFIG_LIBM_HAVE_FMOD 1\n#define TB_CONFIG_LIBM_HAVE_FMODF 1\n#define TB_CONFIG_LIBM_HAVE_TAN 1\n#define TB_CONFIG_LIBM_HAVE_TANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN 1\n#define TB_CONFIG_LIBM_HAVE_ATANF 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2 1\n#define TB_CONFIG_LIBM_HAVE_ATAN2F 1\n#define TB_CONFIG_LIBM_HAVE_COS 1\n#define TB_CONFIG_LIBM_HAVE_COSF 1\n#define TB_CONFIG_LIBM_HAVE_SIN 1\n#define TB_CONFIG_LIBM_HAVE_SINF 1\n#define TB_CONFIG_LIBM_HAVE_EXP 1\n#define TB_CONFIG_LIBM_HAVE_EXPF 1\n\n// posix functions\n#define TB_CONFIG_POSIX_HAVE_POLL 1\n#define TB_CONFIG_POSIX_HAVE_SELECT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1\n#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1\n/*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/\n#define TB_CONFIG_POSIX_HAVE_SOCKET 1\n#define TB_CONFIG_POSIX_HAVE_OPENDIR 1\n#define TB_CONFIG_POSIX_HAVE_DLOPEN 1\n#define TB_CONFIG_POSIX_HAVE_OPEN 1\n/*#undef TB_CONFIG_POSIX_HAVE_STAT64*/\n/*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/\n#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1\n#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1\n#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1\n#define TB_CONFIG_POSIX_HAVE_SYSCONF 1\n#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1\n/*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/\n#define TB_CONFIG_POSIX_HAVE_REGCOMP 1\n#define TB_CONFIG_POSIX_HAVE_REGEXEC 1\n#define TB_CONFIG_POSIX_HAVE_READV 1\n#define TB_CONFIG_POSIX_HAVE_WRITEV 1\n#define TB_CONFIG_POSIX_HAVE_PREADV 1\n#define TB_CONFIG_POSIX_HAVE_PWRITEV 1\n/*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/\n/*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/\n#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1\n/*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/\n#define TB_CONFIG_POSIX_HAVE_SENDFILE 1\n/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/\n/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/\n#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1\n/*#undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP*/\n#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)\n#   undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15\n#endif\n#define TB_CONFIG_POSIX_HAVE_EXECVP 1\n#define TB_CONFIG_POSIX_HAVE_EXECVPE 1\n#define TB_CONFIG_POSIX_HAVE_FORK 1\n/*#undef TB_CONFIG_POSIX_HAVE_VFORK*/\n#define TB_CONFIG_POSIX_HAVE_WAITPID 1\n#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1\n#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1\n#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1\n#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1\n#define TB_CONFIG_POSIX_HAVE_FCNTL 1\n#define TB_CONFIG_POSIX_HAVE_PIPE 1\n#define TB_CONFIG_POSIX_HAVE_PIPE2 1\n#define TB_CONFIG_POSIX_HAVE_MKFIFO 1\n#define TB_CONFIG_POSIX_HAVE_MMAP 1\n/*#undef TB_CONFIG_POSIX_HAVE_FUTIMENS*/\n/*#undef TB_CONFIG_POSIX_HAVE_UTIMENSAT*/\n\n// windows functions\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/\n/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/\n\n// bsd functions\n/*#undef TB_CONFIG_BSD_HAVE_FLOCK*/\n\n// systemv functions\n#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1\n#define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1\n\n// linux functions\n/*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/\n/*#undef TB_CONFIG_LINUX_HAVE_IFADDRS*/\n\n// valgrind functions\n/*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/\n\n#endif\n"
  },
  {
    "path": "core/src/tbox/xmake.lua",
    "content": "includes(\"tbox\")\n\n-- enable hash, charset, utf8 modules\nfor _, name in ipairs({ \"hash\", \"charset\", \"force-utf8\" }) do\n    option(name)\n        set_default(true)\n        after_check(function (option)\n            option:enable(true)\n        end)\n    option_end()\nend\n\n-- disable demo\noption(\"demo\")\n    set_default(false)\noption_end()\n"
  },
  {
    "path": "core/src/tbox/xmake.sh",
    "content": "#!/bin/sh\n\nset_config \"hash\" true\nset_config \"charset\" true\nset_config \"force_utf8\" true\nset_config \"float\" true\nset_config \"demo\" false\n\ncheck_interfaces_enabled=false\nincludes \"tbox/src\"\n\nhide_options() {\n    local name=\"\"\n    local options=\"demo small micro float info exception deprecated force_utf8 xml zip hash regex object charset database coroutine\"\n    for name in $options; do\n        option \"${name}\"\n            set_showmenu false\n        option_end\n    done\n}\nhide_options\n\ntarget \"tbox\"\n    set_default false\n    set_configvar \"TB_CONFIG_MODULE_HAVE_HASH\" 1\n    set_configvar \"TB_CONFIG_MODULE_HAVE_CHARSET\" 1\n    set_configvar \"TB_CONFIG_FORCE_UTF8\" 1\n    set_configvar \"TB_CONFIG_TYPE_HAVE_FLOAT\" 1\n    add_includedirs \"inc/${plat}\" \"{public}\"\n    if is_mode \"debug\"; then\n        add_defines \"__tb_debug__\"\n    fi\n"
  },
  {
    "path": "core/src/xmake/base64/decode.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        base64.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"base64\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_base64_decode(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the string\n    size_t size = 0;\n    tb_char_t const *cstr = luaL_checklstring(lua, 1, &size);\n    tb_check_return_val(cstr && size, 0);\n\n    // decode it\n    tb_byte_t buff[8192];\n    if (size < sizeof(buff)) {\n        tb_size_t real = tb_base64_decode(cstr, size, buff, sizeof(buff));\n        if (real > 0) {\n            lua_pushlstring(lua, (tb_char_t const *)buff, (tb_int_t)real);\n            return 1;\n        }\n    }\n    lua_pushnil(lua);\n    lua_pushstring(lua, \"buffer is too small\");\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/base64/encode.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        base64.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"base64\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_base64_encode(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 1)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n    }\n    if (xm_lua_isinteger(lua, 2)) {\n        size = (tb_size_t)lua_tointeger(lua, 2);\n    }\n    if (!data || !size) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // encode it\n    tb_char_t buff[8192];\n    if (size * 3 / 2 < sizeof(buff)) {\n        tb_size_t real = tb_base64_encode(data, size, buff, sizeof(buff));\n        if (real > 0) {\n            lua_pushlstring(lua, buff, (tb_int_t)real);\n            return 1;\n        }\n    }\n    lua_pushnil(lua);\n    lua_pushstring(lua, \"buffer is too small\");\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/base64/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BASE64_PREFIX_H\n#define XM_BASE64_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/ar/extractlib.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        extractlib.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"extractlib\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n\n/* generate unique filename to handle name conflicts\n *\n * @param base_name  the base filename\n * @param id         the unique ID\n * @param output     output buffer\n * @param output_size size of output buffer\n * @param output_len output: actual output length\n * @return           tb_true on success\n */\nstatic tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) {\n    tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false);\n\n    // find the last dot for extension\n    tb_char_t const *ext = tb_strrchr(base_name, '.');\n    tb_long_t n = -1;\n    if (ext) {\n        tb_size_t base_len = (tb_size_t)(ext - base_name);\n        tb_size_t ext_len = tb_strlen(ext);\n        if (base_len + ext_len + 16 < output_size) {\n            n = tb_snprintf(output, output_size, \"%.*s_%u%s\", (tb_int_t)base_len, base_name, id, ext);\n        }\n    } else {\n        // no extension\n        if (tb_strlen(base_name) + 16 < output_size) {\n            n = tb_snprintf(output, output_size, \"%s_%u\", base_name, id);\n        }\n    }\n\n    if (n >= 0) {\n        *output_len = (tb_size_t)n;\n        return tb_true;\n    }\n    return tb_false;\n}\n\n/* extract AR archive to directory\n *\n * @param istream    the input stream\n * @param outputdir  the output directory\n * @return           tb_true on success, tb_false on failure\n */\ntb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) {\n    tb_assert_and_check_return_val(istream && outputdir, tb_false);\n\n    // get output directory length\n    tb_size_t outputdir_len = tb_strlen(outputdir);\n\n    // check AR magic (!<arch>\\n)\n    if (!xm_binutils_ar_check_magic(istream, 0)) {\n        return tb_false;\n    }\n\n    // ensure output directory exists\n    // check if directory already exists\n    if (!tb_file_info(outputdir, tb_null)) {\n        // directory doesn't exist, create it\n        if (!tb_directory_create(outputdir)) {\n            return tb_false;\n        }\n    }\n\n    tb_bool_t ok = tb_true;\n\n    // iterate through AR members\n    while (ok) {\n        // read AR header\n        // AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2]\n        xm_ar_header_t header;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {\n            // end of file\n            break;\n        }\n\n        // parse member size\n        tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10);\n        if (member_size < 0) {\n            ok = tb_false;\n            break;\n        }\n\n        // get member name\n        tb_char_t member_name[256] = {0};\n        tb_size_t name_len = 0;\n        tb_hize_t name_bytes_read = 0;\n\n        // get member name (handles both regular and extended name formats)\n        tb_bool_t skip = tb_false;\n        if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) {\n            skip = tb_true;\n        } else if (xm_binutils_ar_is_symbol_table(member_name)) {\n            // skip symbol tables\n            skip = tb_true;\n        } else if (!xm_binutils_ar_is_object_file(member_name)) {\n             // only extract object files\n            skip = tb_true;\n        }\n\n        if (skip) {\n            // skip remaining data + padding using sequential read\n            tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read;\n            if (member_size % 2) {\n                skip_size++; // add padding\n            }\n            if (!tb_stream_skip(istream, skip_size)) {\n                ok = tb_false;\n                break;\n            }\n            continue;\n        }\n\n        // handle name conflicts by checking if file exists and renaming with ID\n        tb_char_t output_name[512] = {0};\n        tb_char_t output_path_check[1024] = {0};\n        if (outputdir_len + 1 + name_len >= sizeof(output_path_check)) {\n            ok = tb_false;\n            break;\n        }\n        tb_snprintf(output_path_check, sizeof(output_path_check), \"%s/%s\", outputdir, member_name);\n\n        // check if file already exists\n        tb_uint32_t conflict_id = 1;\n        tb_size_t output_name_len = name_len;\n        if (tb_file_info(output_path_check, tb_null)) {\n            // name conflict, try different IDs until we find an available name\n            while (conflict_id < 10000) {  // reasonable limit\n                if (!xm_binutils_ar_generate_unique_name(member_name, conflict_id, output_name, sizeof(output_name), &output_name_len)) {\n                    ok = tb_false;\n                    break;\n                }\n                if (outputdir_len + 1 + output_name_len >= sizeof(output_path_check)) {\n                    ok = tb_false;\n                    break;\n                }\n                tb_snprintf(output_path_check, sizeof(output_path_check), \"%s/%s\", outputdir, output_name);\n                if (!tb_file_info(output_path_check, tb_null)) {\n                    // found available name\n                    break;\n                }\n                conflict_id++;\n            }\n            if (conflict_id >= 10000) {\n                ok = tb_false;\n                break;\n            }\n        } else {\n            // first occurrence, use original name\n            tb_strlcpy(output_name, member_name, sizeof(output_name));\n        }\n\n        // build output path\n        tb_char_t output_path[1024] = {0};\n        if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {\n            ok = tb_false;\n            break;\n        }\n        tb_snprintf(output_path, sizeof(output_path), \"%s/%s\", outputdir, output_name);\n\n        // create output file\n        tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n        if (!ostream) {\n            ok = tb_false;\n            break;\n        }\n\n        if (!tb_stream_open(ostream)) {\n            tb_stream_exit(ostream);\n            ok = tb_false;\n            break;\n        }\n\n        // copy member data to output file\n        // member_size includes the name if extended format was used, so subtract name_bytes_read\n        tb_hize_t remaining = (tb_hize_t)member_size - name_bytes_read;\n        if (!xm_binutils_stream_copy(istream, ostream, remaining)) {\n            ok = tb_false;\n        }\n\n        tb_stream_clos(ostream);\n        tb_stream_exit(ostream);\n\n        tb_check_break(ok);\n\n        // align to 2-byte boundary (AR format requirement)\n        if (member_size % 2) {\n             if (!tb_stream_skip(istream, 1)) {\n                ok = tb_false;\n                break;\n            }\n        }\n    }\n\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/ar/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_AR_PREFIX_H\n#define XM_BINUTILS_AR_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n#include \"../coff/prefix.h\"\n#include \"../elf/prefix.h\"\n#include \"../macho/prefix.h\"\n#include \"../wasm/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * forward declarations\n */\nextern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n#include \"tbox/prefix/packed.h\"\ntypedef struct __xm_ar_header_t {\n    tb_char_t name[16];   // file name (null-padded)\n    tb_char_t date[12];   // modification time (decimal)\n    tb_char_t uid[6];     // user ID (decimal)\n    tb_char_t gid[6];     // group ID (decimal)\n    tb_char_t mode[8];    // file mode (octal)\n    tb_char_t size[10];   // file size (decimal)\n    tb_char_t fmag[2];    // magic: \"`\\n\"\n} __tb_packed__ xm_ar_header_t;\n#include \"tbox/prefix/packed.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n/* parse decimal number from string\n *\n * @param str the string\n * @param len the length\n * @return    the parsed number, or -1 on error\n */\nstatic __tb_inline__ tb_int64_t xm_binutils_ar_parse_decimal(tb_char_t const *str, tb_size_t len) {\n    tb_assert_and_check_return_val(str && len > 0, -1);\n\n    tb_int64_t result = 0;\n    for (tb_size_t i = 0; i < len; i++) {\n        if (str[i] == ' ' || str[i] == '\\0') {\n            break;\n        }\n        if (str[i] < '0' || str[i] > '9') {\n            return -1;\n        }\n        result = result * 10 + (str[i] - '0');\n    }\n    return result;\n}\n\n/* get member name from AR header, handling extended names (#N/L format)\n *\n * @param istream        the input stream\n * @param header         the AR header\n * @param name           output buffer for the name\n * @param name_size      size of the name buffer\n * @param name_len       output: actual name length\n * @param bytes_read     output: total bytes read from stream (including newline, for extended names)\n * @return               tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const* header, tb_char_t* name, tb_size_t name_size, tb_size_t* name_len, tb_hize_t* bytes_read) {\n    tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len && bytes_read, tb_false);\n    *bytes_read = 0;\n\n    /* check for extended name format (#N/L or #1/N)\n     * In BSD AR format:\n     * - #1/N means name is directly after header, N is total length (including name)\n     * - #N/L means name length is N, total length is L\n     * - #1/N can also mean name is in long name table at offset 1\n     * We'll try to read the name directly from stream first\n     */\n    if (header->name[0] == '#') {\n        // find the '/' separator\n        tb_size_t slash_pos = 0;\n        for (tb_size_t i = 1; i < 16; i++) {\n            if (header->name[i] == '/') {\n                slash_pos = i;\n                break;\n            }\n        }\n\n        if (slash_pos > 0 && slash_pos < 16) {\n            // parse the number before '/' (could be name length or offset)\n            tb_int64_t first_num = xm_binutils_ar_parse_decimal(header->name + 1, slash_pos - 1);\n            // parse the number after '/' (total length)\n            tb_int64_t total_length = xm_binutils_ar_parse_decimal(header->name + slash_pos + 1, 16 - slash_pos - 1);\n\n            if (first_num <= 0 || total_length <= 0) {\n                return tb_false;\n            }\n\n            /* In BSD AR format, extended name is directly after header\n             * The name data starts immediately after the header, no newline\n             * Read exactly total_length bytes for the name section\n             */\n            tb_byte_t c;\n            tb_size_t name_bytes = 0;\n            tb_hize_t bytes_read_so_far = 0;\n\n            // Read name characters until we hit null terminator or reach total_length\n            while (bytes_read_so_far < (tb_hize_t)total_length && name_bytes < name_size - 1) {\n                if (!tb_stream_bread(istream, &c, 1)) {\n                    return tb_false;\n                }\n                bytes_read_so_far++;\n\n                if (c == '\\0') {\n                    // Stop reading name at null terminator, but continue reading to reach total_length\n                    break;\n                }\n                // Include all characters in the name, including newlines if present\n                name[name_bytes++] = (tb_char_t)c;\n            }\n            name[name_bytes] = '\\0';\n            *name_len = name_bytes;\n\n            // Skip remaining bytes to reach total_length (there may be padding or null terminators)\n            if (bytes_read_so_far < (tb_hize_t)total_length) {\n                tb_hize_t remaining_to_read = (tb_hize_t)total_length - bytes_read_so_far;\n                if (!tb_stream_skip(istream, remaining_to_read)) {\n                    return tb_false;\n                }\n            }\n\n            // Total bytes read = name + padding = total_length\n            *bytes_read = (tb_hize_t)total_length;\n            return tb_true;\n        }\n    }\n\n    if (header->name[0] == '/') {\n        if (header->name[1] == '/') {\n            tb_strlcpy(name, \"//\", name_size);\n            *name_len = 2;\n        } else {\n            tb_strlcpy(name, \"/\", name_size);\n            *name_len = 1;\n        }\n        *bytes_read = 0;\n        return tb_true;\n    }\n\n    // regular name (null-terminated or space-padded)\n    tb_size_t i = 0;\n    for (i = 0; i < 16 && i < name_size - 1; i++) {\n        if (header->name[i] == ' ' || header->name[i] == '\\0' || header->name[i] == '/') {\n            break;\n        }\n        name[i] = header->name[i];\n    }\n    name[i] = '\\0';\n    *name_len = i;\n    *bytes_read = 0; // Regular names are in header, not read from stream\n    return tb_true;\n}\n\n/* check AR magic (!<arch>\\n)\n *\n * @param istream    the input stream\n * @param base_offset the base offset\n * @return           tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream, tb_hize_t base_offset) {\n    tb_uint8_t magic[8];\n    if (!tb_stream_seek(istream, base_offset)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, magic, 8)) {\n        return tb_false;\n    }\n    if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' ||\n        magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\\n') ||\n        (magic[7] != '\\n' && magic[7] != '\\r')) {\n        return tb_false;\n    }\n    return tb_true;\n}\n\n/* check if member is a symbol table (should be skipped)\n *\n * @param name the member name\n * @return     tb_true if it's a symbol table, tb_false otherwise\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *name) {\n    tb_assert_and_check_return_val(name, tb_false);\n    return (tb_strcmp(name, \"__.SYMDEF\") == 0 || tb_strcmp(name, \"__.SYMDEF SORTED\") == 0 ||\n            tb_strcmp(name, \"/\") == 0 || tb_strcmp(name, \"//\") == 0 ||\n            tb_strncmp(name, \"__.SYMDEF\", 9) == 0);\n}\n\n/* check if member is an object file (based on extension)\n *\n * @param name the member name\n * @return     tb_true if it's likely an object file, tb_false otherwise\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *name) {\n    tb_assert_and_check_return_val(name, tb_false);\n    tb_size_t len = tb_strlen(name);\n    if (len == 0) {\n        return tb_false;\n    }\n\n    // check common object file extensions\n    if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') {\n        return tb_true;\n    }\n    if (len >= 4 && tb_strcmp(name + len - 4, \".obj\") == 0) {\n        return tb_true;\n    }\n\n    // check if it's a COFF/ELF/Mach-O file by detecting format\n    // For now, we'll extract all non-symbol-table members\n    return tb_true;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/ar/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n#define TB_TRACE_MODULE_NAME \"readsyms_ar\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nstatic tb_int_t xm_binutils_ar_detect_member_format(tb_stream_ref_t istream, tb_hize_t base_offset) {\n    tb_uint8_t magic[8] = {0};\n    if (!tb_stream_seek(istream, base_offset)) {\n        return -1;\n    }\n    if (!tb_stream_bread(istream, magic, 8)) {\n        tb_stream_seek(istream, base_offset);\n        return -1;\n    }\n    tb_stream_seek(istream, base_offset);\n\n    if (magic[0] == XM_WASM_MAGIC0 && magic[1] == XM_WASM_MAGIC1 && magic[2] == XM_WASM_MAGIC2 && magic[3] == XM_WASM_MAGIC3) {\n        return XM_BINUTILS_FORMAT_WASM;\n    }\n    if (magic[0] == XM_ELF_MAGIC0 && magic[1] == XM_ELF_MAGIC1 && magic[2] == XM_ELF_MAGIC2 && magic[3] == XM_ELF_MAGIC3) {\n        return XM_BINUTILS_FORMAT_ELF;\n    }\n    tb_uint32_t macho_magic = tb_bits_get_u32_be(magic);\n    if (macho_magic == XM_MACHO_MAGIC_32 || macho_magic == XM_MACHO_MAGIC_64 ||\n        macho_magic == XM_MACHO_MAGIC_32_BE || macho_magic == XM_MACHO_MAGIC_64_BE) {\n        return XM_BINUTILS_FORMAT_MACHO;\n    }\n    return XM_BINUTILS_FORMAT_UNKNOWN;\n}\n\n/* parse BSD symbol table (__.SYMDEF or __.SYMDEF SORTED)\n *\n * Header:\n * - ranlib_size (uint32_t)\n * - ranlibs (struct ranlib[ranlib_size/8])\n * - strtab_size (uint32_t)\n * - strtab (char[strtab_size])\n *\n * struct ranlib {\n *     uint32_t ran_strx; // offset into string table\n *     uint32_t ran_off;  // offset into archive\n * };\n */\nstatic tb_bool_t xm_binutils_ar_parse_bsd_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {\n    tb_hize_t start_pos = tb_stream_offset(istream);\n\n    // read size of ranlib array\n    tb_uint32_t ranlib_size = 0;\n    if (!tb_stream_bread_u32_le(istream, &ranlib_size)) {\n        return tb_false;\n    }\n\n    // sanity check\n    if (ranlib_size == 0 || ranlib_size >= member_size) {\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    // read ranlib array\n    tb_size_t num_ranlibs = ranlib_size / 8;\n\n    // allocate buffers\n    tb_uint32_t* ran_strx = tb_nalloc_type(num_ranlibs, tb_uint32_t);\n    tb_uint32_t* ran_off = tb_nalloc_type(num_ranlibs, tb_uint32_t);\n\n    if (!ran_strx || !ran_off) {\n        if (ran_strx) {\n            tb_free(ran_strx);\n        }\n        if (ran_off) {\n            tb_free(ran_off);\n        }\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    tb_size_t i;\n    for (i = 0; i < num_ranlibs; i++) {\n        if (!tb_stream_bread_u32_le(istream, &ran_strx[i]) ||\n            !tb_stream_bread_u32_le(istream, &ran_off[i])) {\n            tb_free(ran_strx);\n            tb_free(ran_off);\n            tb_stream_seek(istream, start_pos);\n            return tb_false;\n        }\n    }\n\n    // read string table size\n    tb_uint32_t strtab_size = 0;\n    if (!tb_stream_bread_u32_le(istream, &strtab_size)) {\n        tb_free(ran_strx);\n        tb_free(ran_off);\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    // read string table\n    tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes(strtab_size);\n    if (!strtab) {\n        tb_free(ran_strx);\n        tb_free(ran_off);\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)strtab, strtab_size)) {\n        tb_free(strtab);\n        tb_free(ran_strx);\n        tb_free(ran_off);\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    // populate map\n    for (i = 0; i < num_ranlibs; i++) {\n        tb_uint32_t off = ran_off[i];\n        tb_uint32_t strx = ran_strx[i];\n\n        if (strx < strtab_size) {\n            tb_char_t* name = strtab + strx;\n\n            // add to map: map[off] = { {name=name, type=\"T\"}, ... }\n            lua_pushinteger(lua, off);\n            lua_rawget(lua, map_idx);\n            if (lua_isnil(lua, -1)) {\n                lua_pop(lua, 1);\n                lua_newtable(lua);\n                lua_pushinteger(lua, off);\n                lua_pushvalue(lua, -2);\n                lua_rawset(lua, map_idx);\n            }\n\n            int count = (int)lua_objlen(lua, -1);\n            lua_newtable(lua);\n            lua_pushstring(lua, \"name\");\n            lua_pushstring(lua, name);\n            lua_settable(lua, -3);\n            lua_pushstring(lua, \"type\");\n            lua_pushstring(lua, \"T\");\n            lua_settable(lua, -3);\n\n            lua_rawseti(lua, -2, count + 1);\n            lua_pop(lua, 1); // pop list\n        }\n    }\n\n    tb_free(strtab);\n    tb_free(ran_strx);\n    tb_free(ran_off);\n    return tb_true;\n}\n\n/* parse SysV symbol table (/)\n *\n * Header:\n * - num_symbols (uint32_t BE)\n * - offsets (uint32_t[num_symbols] BE)\n * - string table (null-terminated strings)\n */\nstatic tb_bool_t xm_binutils_ar_parse_sysv_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {\n    tb_hize_t start_pos = tb_stream_offset(istream);\n\n    // read number of symbols\n    tb_uint32_t num_symbols = 0;\n    if (!tb_stream_bread_u32_be(istream, &num_symbols)) {\n        return tb_false;\n    }\n\n    // sanity check\n    if (num_symbols == 0 || num_symbols * 4 >= member_size) {\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    // read offsets\n    tb_uint32_t* offsets = tb_nalloc_type(num_symbols, tb_uint32_t);\n    if (!offsets) {\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    tb_size_t i;\n    for (i = 0; i < num_symbols; i++) {\n        if (!tb_stream_bread_u32_be(istream, &offsets[i])) {\n            tb_free(offsets);\n            tb_stream_seek(istream, start_pos);\n            return tb_false;\n        }\n    }\n\n    // read string table\n    tb_hize_t current = tb_stream_offset(istream);\n    tb_hize_t strtab_size = member_size - (current - start_pos);\n\n    tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes((tb_size_t)strtab_size);\n    if (!strtab) {\n        tb_free(offsets);\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)strtab, (tb_size_t)strtab_size)) {\n        tb_free(strtab);\n        tb_free(offsets);\n        tb_stream_seek(istream, start_pos);\n        return tb_false;\n    }\n\n    // populate map\n    tb_char_t* p = strtab;\n    tb_char_t* end = strtab + strtab_size;\n\n    for (i = 0; i < num_symbols; i++) {\n        if (p >= end) {\n            break;\n        }\n\n        tb_char_t* name = p;\n        tb_size_t len = tb_strlen(name);\n        p += len + 1;\n\n        tb_uint32_t off = offsets[i];\n\n        // add to map\n        lua_pushinteger(lua, off);\n        lua_rawget(lua, map_idx);\n        if (lua_isnil(lua, -1)) {\n            lua_pop(lua, 1);\n            lua_newtable(lua);\n            lua_pushinteger(lua, off);\n            lua_pushvalue(lua, -2);\n            lua_rawset(lua, map_idx);\n        }\n\n        int count = (int)lua_objlen(lua, -1);\n        lua_newtable(lua);\n        lua_pushstring(lua, \"name\");\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n        lua_pushstring(lua, \"type\");\n        lua_pushstring(lua, \"T\");\n        lua_settable(lua, -3);\n\n        lua_rawseti(lua, -2, count + 1);\n        lua_pop(lua, 1); // pop list\n    }\n\n    tb_free(strtab);\n    tb_free(offsets);\n    return tb_true;\n}\n\n/* read symbols from AR archive\n *\n * @param istream     the input stream\n * @param base_offset the base offset\n * @param lua         the lua state\n * @return            tb_true on success, tb_false on failure\n */\ntb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // check AR magic (!<arch>\\n)\n    if (!xm_binutils_ar_check_magic(istream, base_offset)) {\n        return tb_false;\n    }\n\n    // get result list index\n    int list_idx = lua_gettop(lua);\n\n    // init map table for symbol table\n    lua_newtable(lua);\n    int map_idx = lua_gettop(lua);\n\n    tb_bool_t ok = tb_true;\n    tb_size_t object_count = 0;\n\n    // iterate through AR members\n    while (ok) {\n        // save member header position\n        tb_hize_t member_header_pos = tb_stream_offset(istream);\n\n        /* read AR header\n         * AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2]\n         */\n        xm_ar_header_t header;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {\n            // end of file\n            break;\n        }\n\n        // parse member size\n        tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10);\n        if (member_size < 0) {\n            ok = tb_false;\n            break;\n        }\n\n        // get member name\n        tb_char_t member_name[256] = {0};\n        tb_size_t name_len = 0;\n        tb_hize_t name_bytes_read = 0;\n\n        // get member name (handles both regular and extended name formats)\n        tb_bool_t skip = tb_false;\n        if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) {\n            skip = tb_true;\n        } else {\n            if (xm_binutils_ar_is_symbol_table(member_name)) {\n                /* parse symbol table\n                 *\n                 * The symbol table in the archive only contains symbol names and their offsets,\n                 * but lacks detailed symbol type information (e.g., distinguishing between code and data).\n                 * However, for object files that cannot be parsed (e.g., LTO bitcode) or unknown formats,\n                 * parsing the symbol table serves as a robust fallback to ensure symbols are extracted.\n                 */\n                tb_hize_t current = tb_stream_offset(istream);\n                if (tb_strcmp(member_name, \"/\") == 0) {\n                    xm_binutils_ar_parse_sysv_symdef(istream, member_size, lua, map_idx);\n                } else if (tb_strcmp(member_name, \"//\") != 0) {\n                    xm_binutils_ar_parse_bsd_symdef(istream, member_size, lua, map_idx);\n                }\n                tb_stream_seek(istream, current); // restore position for skip\n                skip = tb_true;\n            } else if (!xm_binutils_ar_is_object_file(member_name)) {\n                 // only extract object files\n                skip = tb_true;\n            }\n        }\n\n        if (skip) {\n            // skip remaining data + padding using sequential read\n            tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read;\n            if (member_size % 2) {\n                skip_size++; // add padding\n            }\n            if (!tb_stream_skip(istream, skip_size)) {\n                ok = tb_false;\n                break;\n            }\n            continue;\n        }\n\n        // save current position\n        tb_hize_t current_pos = tb_stream_offset(istream);\n\n        // detect format\n        tb_int_t format = xm_binutils_ar_detect_member_format(istream, current_pos);\n        if (format != XM_BINUTILS_FORMAT_AR) {\n            // create entry table\n            lua_newtable(lua);\n\n            // object name\n            lua_pushstring(lua, \"objectfile\");\n            lua_pushstring(lua, member_name);\n            lua_settable(lua, -3);\n\n            // symbols\n            lua_pushstring(lua, \"symbols\");\n            tb_bool_t read_ok = tb_false;\n            if (format == XM_BINUTILS_FORMAT_COFF) {\n                read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua);\n            } else if (format == XM_BINUTILS_FORMAT_ELF) {\n                read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua);\n            } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n                read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua);\n            } else if (format == XM_BINUTILS_FORMAT_WASM) {\n                read_ok = xm_binutils_wasm_read_symbols(istream, current_pos, lua);\n            }\n\n            if (!read_ok) {\n                /* try get from map\n                 *\n                 * If parsing the object file fails (e.g. for LTO bitcode or unsupported formats),\n                 * we fall back to using the symbols parsed from the archive symbol table.\n                 * Although the type information is less accurate (defaulting to \"T\"),\n                 * it guarantees that symbols are not lost.\n                 *\n                 * cast to lua_Integer to avoid warning C4244 on 32-bit MSVC\n                 * member_header_pos is tb_hize_t (64-bit), but AR offsets are usually 32-bit\n                 */\n                lua_pushinteger(lua, (lua_Integer)member_header_pos);\n                lua_rawget(lua, map_idx);\n                if (!lua_isnil(lua, -1)) {\n                    read_ok = tb_true;\n                } else {\n                    lua_pop(lua, 1);\n                }\n            }\n\n            if (read_ok) {\n                lua_settable(lua, -3);\n                lua_rawseti(lua, list_idx, (int)(++object_count));\n            } else {\n                lua_pop(lua, 2); // pop symbols key and entry table\n            }\n        }\n\n        // skip to next member\n        tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos;\n        tb_hize_t remaining_size = (tb_hize_t)member_size - name_bytes_read - member_data_read;\n        if (member_size % 2) {\n            remaining_size++; // add padding\n        }\n\n        if (remaining_size > 0) {\n            if (!tb_stream_skip(istream, remaining_size)) {\n                ok = tb_false;\n                break;\n            }\n        } else if (remaining_size < 0) {\n            /* should not happen if readsyms functions respect boundaries, but just in case\n             * seek back to correct position\n             */\n             if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size - name_bytes_read + (member_size % 2))) {\n                ok = tb_false;\n                break;\n             }\n        }\n    }\n\n    lua_remove(lua, map_idx);\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/bin2c.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bin2c.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bin2c\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n#define XM_BIN2C_DATA_SIZE      (8 * 1024)\n#define XM_BIN2C_LINE_SIZE      (4 * 1024)\n#define XM_BIN2C_LINEWIDTH_MAX  ((XM_BIN2C_LINE_SIZE - 2) / 6)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\n// optimized hex conversion table\nstatic tb_char_t const *xm_binutils_bin2c_digits = \"0123456789ABCDEF\";\n\n// inline hex conversion for better performance\nstatic __tb_inline__ tb_void_t xm_binutils_bin2c_write_hex(tb_char_t *str, tb_byte_t value) {\n    str[0] = ' ';\n    str[1] = '0';\n    str[2] = 'x';\n    str[3] = xm_binutils_bin2c_digits[(value >> 4) & 15];\n    str[4] = xm_binutils_bin2c_digits[value & 15];\n}\n\nstatic tb_bool_t xm_binutils_bin2c_dump(tb_stream_ref_t istream,\n                                        tb_stream_ref_t ostream,\n                                        tb_int_t        linewidth,\n                                        tb_bool_t       nozeroend) {\n\n    tb_bool_t first = tb_true;\n    tb_bool_t zero_pending = tb_false;\n    tb_byte_t data[XM_BIN2C_DATA_SIZE];\n    tb_char_t line[XM_BIN2C_LINE_SIZE];\n    tb_size_t linesize = 0;\n    tb_size_t bytes_in_line = 0;\n    tb_size_t data_pos = 0;\n    tb_size_t data_size = 0;\n    tb_assert_and_check_return_val(linewidth > 0 && linewidth <= XM_BIN2C_LINEWIDTH_MAX, tb_false);\n\n    while (!tb_stream_beof(istream) || data_pos < data_size || zero_pending) {\n        // read a large chunk of data if buffer is empty\n        if (data_pos >= data_size) {\n            // handle pending zero terminator\n            if (zero_pending) {\n                data[0] = '\\0';\n                data_size = 1;\n                data_pos = 0;\n                zero_pending = tb_false;\n            } else {\n                tb_hong_t left = tb_stream_left(istream);\n                tb_size_t to_read = (tb_size_t)tb_min(left, (tb_hong_t)XM_BIN2C_DATA_SIZE);\n                tb_check_break(to_read);\n\n                if (!tb_stream_bread(istream, data, to_read)) {\n                    break;\n                }\n                data_size = to_read;\n                data_pos = 0;\n\n                // check if we need to add zero terminator at the end\n                if (!nozeroend && tb_stream_beof(istream)) {\n                    if (data_size < XM_BIN2C_DATA_SIZE) {\n                        // can add directly to current buffer\n                        data[data_size++] = '\\0';\n                    } else {\n                        // buffer is full, need to add zero in next iteration\n                        zero_pending = tb_true;\n                    }\n                }\n            }\n        }\n\n        // process bytes from buffer\n        while (data_pos < data_size) {\n            // check if we need a new line\n            if (bytes_in_line >= (tb_size_t)linewidth) {\n                // write line (tb_stream_bwrit_line will add newline automatically)\n                if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {\n                    return tb_false;\n                }\n\n                linesize = 0;\n                bytes_in_line = 0;\n                first = tb_false;\n            }\n\n            // ensure we have enough space in line buffer (6 chars per byte: \", 0xXX\")\n            if (linesize + 6 > sizeof(line)) {\n                // flush partial line if buffer is full\n                if (linesize > 0) {\n                    if (!tb_stream_bwrit(ostream, (tb_byte_t *)line, linesize)) {\n                        return tb_false;\n                    }\n                    linesize = 0;\n                }\n            }\n\n            // add separator\n            if (bytes_in_line == 0 && first) {\n                line[linesize++] = ' ';\n                first = tb_false;\n            } else {\n                line[linesize++] = ',';\n            }\n\n            // write hex value (inline for performance)\n            xm_binutils_bin2c_write_hex(line + linesize, data[data_pos]);\n            linesize += 5;\n            bytes_in_line++;\n            data_pos++;\n        }\n    }\n\n    // flush remaining line\n    if (linesize > 0) {\n        // write line (tb_stream_bwrit_line will add newline automatically)\n        if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {\n            return tb_false;\n        }\n    }\n\n    return tb_stream_beof(istream);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* generate c/c++ code from the binary file\n *\n * local ok, errors = binutils.bin2c(binaryfile, outputfile, linewidth, nozeroend)\n */\ntb_int_t xm_binutils_bin2c(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binaryfile\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // get the outputfile\n    tb_char_t const *outputfile = luaL_checkstring(lua, 2);\n    tb_check_return_val(outputfile, 0);\n\n    // get line width\n    tb_int_t linewidth = (tb_int_t)lua_tointeger(lua, 3);\n\n    // no zero end?\n    tb_bool_t nozeroend = (tb_bool_t)lua_toboolean(lua, 4);\n\n    // do dump\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2c: open %s failed\", binaryfile);\n            break;\n        }\n\n        if (!tb_stream_open(ostream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2c: open %s failed\", outputfile);\n            break;\n        }\n\n        if (!xm_binutils_bin2c_dump(istream, ostream, linewidth, nozeroend)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2c: dump data failed\");\n            break;\n        }\n\n        ok = tb_true;\n        lua_pushboolean(lua, ok);\n\n    } while (0);\n\n    if (istream) {\n        tb_stream_clos(istream);\n    }\n    istream = tb_null;\n\n    if (ostream) {\n        tb_stream_clos(ostream);\n    }\n    ostream = tb_null;\n\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/coff/bin2coff.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bin2coff.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bin2coff\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t xm_binutils_bin2coff_dump(tb_stream_ref_t istream,\n                                        tb_stream_ref_t ostream,\n                                        tb_char_t const *symbol_prefix,\n                                        tb_char_t const *arch,\n                                        tb_char_t const *basename,\n                                        tb_bool_t zeroend) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n\n    // get file size\n    tb_hong_t filesize = tb_stream_size(istream);\n    if (filesize < 0 || filesize > 0xffffffffU) {\n        return tb_false;\n    }\n    tb_uint32_t datasize = (tb_uint32_t)filesize;\n    // add null terminator if zeroend is true\n    if (zeroend) {\n        if (datasize >= 0xffffffffU) {\n            return tb_false; // would overflow\n        }\n        datasize++;\n    }\n\n    // determine architecture for symbol prefix adjustment\n    tb_uint16_t machine = xm_binutils_coff_get_machine(arch);\n    tb_bool_t is_i386 = (machine == XM_COFF_MACHINE_I386);\n\n    // generate symbol names from filename\n    tb_char_t symbol_name[256] = {0};\n    tb_char_t symbol_start[256] = {0};\n    tb_char_t symbol_end[256] = {0};\n\n    // use basename or default to \"data\"\n    if (!basename || !basename[0]) {\n        basename = \"data\";\n    }\n\n    // build symbol name\n    // note: on i386 Windows, C compiler automatically adds an underscore prefix to external symbols\n    // so if we use \"_binary_\", the actual symbol becomes \"__binary_\" after compilation\n    // to match, we need to ensure the prefix has two underscores for i386\n    if (symbol_prefix) {\n        if (is_i386 && symbol_prefix[0] == '_' && symbol_prefix[1] != '_') {\n            // i386: if prefix starts with single underscore, add another one\n            tb_snprintf(symbol_name, sizeof(symbol_name), \"_%s%s\", symbol_prefix, basename);\n        } else {\n            tb_snprintf(symbol_name, sizeof(symbol_name), \"%s%s\", symbol_prefix, basename);\n        }\n    } else {\n        if (is_i386) {\n            tb_snprintf(symbol_name, sizeof(symbol_name), \"__binary_%s\", basename);\n        } else {\n            tb_snprintf(symbol_name, sizeof(symbol_name), \"_binary_%s\", basename);\n        }\n    }\n\n    // replace non-alphanumeric with underscore\n    xm_binutils_sanitize_symbol_name(symbol_name);\n\n    tb_snprintf(symbol_start, sizeof(symbol_start), \"%s_start\", symbol_name);\n    tb_snprintf(symbol_end, sizeof(symbol_end), \"%s_end\", symbol_name);\n\n    // calculate offsets\n    tb_uint32_t header_size = sizeof(xm_coff_header_t);\n    tb_uint32_t section_header_size = sizeof(xm_coff_section_t);\n    tb_uint32_t section_data_ofs = header_size + section_header_size;\n    tb_uint32_t section_data_size = datasize;\n    tb_uint32_t section_data_padding = (4 - (section_data_size & 3)) & 3;\n    tb_uint32_t symbol_table_ofs = section_data_ofs + section_data_size + section_data_padding;\n\n    // calculate string table size (content only, excluding the 4-byte size field)\n    tb_uint32_t string_table_content_size = 0;\n    tb_size_t start_len = tb_strlen(symbol_start);\n    tb_size_t end_len = tb_strlen(symbol_end);\n    if (start_len > 8) {\n        string_table_content_size += (tb_uint32_t)(start_len + 1);\n    }\n    if (end_len > 8) {\n        string_table_content_size += (tb_uint32_t)(end_len + 1);\n    }\n    // string table size field should include the size field itself\n    tb_uint32_t string_table_size = 4 + string_table_content_size;\n\n    // write COFF header\n    xm_coff_header_t header;\n    tb_memset(&header, 0, sizeof(header));\n    header.machine = machine;\n    header.nsects = 1;\n    header.time = 0;\n    header.symtabofs = symbol_table_ofs;\n    // note: COFF spec says nsyms is the number of symbol table entries (including aux entries)\n    // section symbol (1) + aux entry (1) + start symbol (1) + end symbol (1) = 4 entries\n    // total size: 4 * 18 = 72 bytes\n    // i386 linker calculates string table as symtabofs + nsyms * 18 = symtabofs + 72 (correct)\n    // when reading symbols, linker follows naux fields to skip aux entries correctly\n    // from mingw i386 analysis: section symbols MUST have aux entry (naux=1)\n    header.nsyms = 4; // 3 symbols + 1 aux entry\n    header.opthdr = 0;\n    header.flags = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // write section header (.rdata)\n    xm_coff_section_t section;\n    tb_memset(&section, 0, sizeof(section));\n    tb_strncpy(section.name, \".rdata\", 8);\n    section.vsize = datasize;\n    section.vaddr = 0;\n    section.size = datasize;\n    section.ofs = section_data_ofs;\n    section.relocofs = 0;\n    section.linenoofs = 0;\n    section.nreloc = 0;\n    section.nlineno = 0;\n    section.flags = XM_COFF_SECTION_RDATA;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section, sizeof(section))) {\n        return tb_false;\n    }\n\n    // write section data\n    if (!xm_binutils_stream_copy(istream, ostream, filesize)) {\n        return tb_false;\n    }\n    // append null terminator if zeroend is true\n    if (zeroend) {\n        tb_byte_t zero = 0;\n        if (!tb_stream_bwrit(ostream, &zero, 1)) {\n            return tb_false;\n        }\n    }\n\n    // align to 4 bytes\n    if (section_data_padding > 0) {\n        xm_binutils_coff_write_padding(ostream, section_data_padding);\n    }\n\n    // write symbol table\n    // symbol 0: .rdata section symbol\n    xm_coff_symbol_t sym_section;\n    tb_memset(&sym_section, 0, sizeof(sym_section));\n    tb_strncpy(sym_section.n.shortname.name, \".rdata\", 8);\n    sym_section.value = 0;\n    sym_section.sect = 1; // section index (1-based)\n    sym_section.type = 0; // IMAGE_SYM_TYPE_NULL\n    sym_section.scl = 3; // IMAGE_SYM_CLASS_STATIC\n    // section symbol MUST have auxiliary entry for i386 compatibility (as seen in mingw-generated files)\n    sym_section.naux = 1; // auxiliary entry (required for i386)\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_section, sizeof(sym_section))) {\n        return tb_false;\n    }\n    // auxiliary entry for section (18 bytes total)\n    xm_coff_aux_section_t aux_section;\n    tb_memset(&aux_section, 0, sizeof(aux_section));\n    aux_section.length = datasize;\n    aux_section.nreloc = 0;\n    aux_section.nlineno = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&aux_section, sizeof(aux_section))) {\n        return tb_false;\n    }\n\n    // symbol 1: _binary_xxx_start (or __binary_xxx_start for i386)\n    tb_uint32_t strtab_offset = 4; // start after size field\n    xm_binutils_coff_write_symbol_name(ostream, symbol_start, &strtab_offset);\n    xm_coff_symbol_tail_t sym_start_tail;\n    tb_memset(&sym_start_tail, 0, sizeof(sym_start_tail));\n    sym_start_tail.value = 0;\n    sym_start_tail.sect = 1;\n    sym_start_tail.type = 0; // IMAGE_SYM_TYPE_NULL\n    sym_start_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL\n    sym_start_tail.naux = 0; // no auxiliary entry\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start_tail, sizeof(sym_start_tail))) {\n        return tb_false;\n    }\n\n    // symbol 2: _binary_xxx_end (or __binary_xxx_end for i386)\n    xm_binutils_coff_write_symbol_name(ostream, symbol_end, &strtab_offset);\n    xm_coff_symbol_tail_t sym_end_tail;\n    tb_memset(&sym_end_tail, 0, sizeof(sym_end_tail));\n    sym_end_tail.value = datasize;\n    sym_end_tail.sect = 1;\n    sym_end_tail.type = 0; // IMAGE_SYM_TYPE_NULL\n    sym_end_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL\n    sym_end_tail.naux = 0; // no auxiliary entry\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end_tail, sizeof(sym_end_tail))) {\n        return tb_false;\n    }\n\n    // write string table\n    // symbol table size: section symbol (18) + aux entry (18) + start symbol (18) + end symbol (18) = 72 bytes\n    // string table starts at symtabofs + 72, which matches nsyms * 18 = 4 * 18 = 72\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&string_table_size, 4)) {\n        return tb_false;\n    }\n    if (start_len > 8) {\n        xm_binutils_coff_write_string(ostream, symbol_start, start_len);\n        tb_byte_t null = 0;\n        tb_stream_bwrit(ostream, &null, 1);\n    }\n    if (end_len > 8) {\n        xm_binutils_coff_write_string(ostream, symbol_end, end_len);\n        tb_byte_t null = 0;\n        tb_stream_bwrit(ostream, &null, 1);\n    }\n\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* generate COFF object file from binary file\n *\n * @param lua the lua state\n * @return 1 on success, 2 on failure (with error message on stack)\n */\ntb_int_t xm_binutils_bin2coff(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binaryfile\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // get the outputfile\n    tb_char_t const *outputfile = luaL_checkstring(lua, 2);\n    tb_check_return_val(outputfile, 0);\n\n    // get symbol prefix (optional)\n    tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;\n\n    // get arch (optional)\n    tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;\n\n    // get basename (optional)\n    tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;\n\n    // get zeroend (optional, default: false)\n    tb_bool_t zeroend = lua_toboolean(lua, 6);\n\n    // do dump\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2coff: open %s failed\", binaryfile);\n            break;\n        }\n\n        if (!tb_stream_open(ostream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2coff: open %s failed\", outputfile);\n            break;\n        }\n\n        if (!xm_binutils_bin2coff_dump(istream, ostream, symbol_prefix, arch, basename, zeroend)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2coff: dump data failed\");\n            break;\n        }\n\n        ok = tb_true;\n        lua_pushboolean(lua, ok);\n\n    } while (0);\n\n    if (istream) {\n        tb_stream_clos(istream);\n    }\n    istream = tb_null;\n\n    if (ostream) {\n        tb_stream_clos(ostream);\n    }\n    ostream = tb_null;\n\n    return ok ? 1 : 2;\n}\n\n"
  },
  {
    "path": "core/src/xmake/binutils/coff/deplibs.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        deplibs.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"deplibs_coff\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_uint32_t xm_binutils_coff_get_import_rva(tb_stream_ref_t istream, tb_uint16_t opthdr_size) {\n    \n    // save current offset\n    tb_hize_t opt_offset = tb_stream_offset(istream);\n    tb_uint32_t import_rva = 0;\n\n    // read magic\n    tb_uint16_t magic = 0;\n    if (tb_stream_bread(istream, (tb_byte_t*)&magic, sizeof(magic))) {\n        // seek back\n        if (tb_stream_seek(istream, opt_offset)) {\n            if (magic == XM_PE32_MAGIC) {\n                xm_pe32_opt_header_t opt_header = {0};\n                if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) {\n                    if (opt_header.number_of_rva_and_sizes > 1) {\n                        import_rva = opt_header.data_directory[1].vaddr;\n                    }\n                }\n            } else if (magic == XM_PE32P_MAGIC) {\n                xm_pe32p_opt_header_t opt_header = {0};\n                if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) {\n                    if (opt_header.number_of_rva_and_sizes > 1) {\n                        import_rva = opt_header.data_directory[1].vaddr;\n                    }\n                }\n            }\n        }\n    }\n    return import_rva;\n}\n\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    tb_bool_t          ok = tb_false;\n    xm_coff_section_t* sections = tb_null;\n    do {\n        // read COFF header\n        xm_coff_header_t header;\n        if (!tb_stream_seek(istream, base_offset)) break;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) break;\n\n        // read optional header and import rva\n        tb_uint32_t import_rva = 0;\n        if (header.opthdr > 0) {\n            import_rva = xm_binutils_coff_get_import_rva(istream, header.opthdr);\n        }\n\n        // read section headers\n        if (header.nsects > 0) {\n            sections = tb_nalloc_type(header.nsects, xm_coff_section_t);\n            if (!sections) break;\n\n            tb_hize_t section_offset = base_offset + sizeof(xm_coff_header_t) + header.opthdr;\n            if (!tb_stream_seek(istream, section_offset)) break;\n            if (!tb_stream_bread(istream, (tb_byte_t*)sections, header.nsects * sizeof(xm_coff_section_t))) break;\n        }\n\n        if (!sections) {\n            if (header.nsects > 0) break;\n            ok = tb_true;\n            break;\n        }\n\n        tb_size_t result_count = 0;\n        tb_bool_t failed = tb_false;\n        for (tb_uint16_t i = 0; i < header.nsects; i++) {\n            xm_coff_section_t* section = &sections[i];\n\n            // check if it is .idata section (import directory table)\n            tb_bool_t found_idt = tb_false;\n            tb_uint32_t idt_offset = 0;\n            if (import_rva != 0) {\n                // check if import rva is in this section\n                if (import_rva >= section->vaddr && import_rva < section->vaddr + section->vsize) {\n                    idt_offset = section->ofs + (import_rva - section->vaddr);\n                    found_idt = tb_true;\n                }\n            } else {\n                // fallback to check section name\n                if (tb_strncmp(section->name, \".idata\", 6) == 0) {\n                    idt_offset = section->ofs;\n                    found_idt = tb_true;\n                }\n            }\n\n            if (found_idt) {\n                /* read import directory table\n                 * The .idata section contains the Import Directory Table.\n                 * Each entry is 20 bytes (IMAGE_IMPORT_DESCRIPTOR).\n                 * The table ends with a null entry.\n                 */\n\n                /* We need to iterate over IMAGE_IMPORT_DESCRIPTOR entries.\n                 * struct IMAGE_IMPORT_DESCRIPTOR {\n                 *     DWORD   OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)\n                 *     DWORD   TimeDateStamp;      // 0 if not bound,\n                 *     DWORD   ForwarderChain;     // -1 if no forwarders\n                 *     DWORD   Name;               // RVA to DLL name\n                 *     DWORD   FirstThunk;         // RVA to IAT (if bound this IAT has actual addresses)\n                 * };\n                 */\n\n                if (!tb_stream_seek(istream, idt_offset)) {\n                    failed = tb_true;\n                    break;\n                }\n\n                while (1) {\n                    xm_coff_import_directory_table_t entry;\n                    if (!tb_stream_bread(istream, (tb_byte_t*)&entry, sizeof(entry))) {\n                        break;\n                    }\n\n                    // check for null entry (end of table)\n                    if (entry.original_first_thunk == 0 && entry.name_rva == 0) {\n                        break;\n                    }\n\n                    tb_uint32_t name_rva = tb_bits_le_to_ne_u32(entry.name_rva);\n\n                    if (name_rva != 0) {\n                        /* map RVA to file offset to read the name\n                         * We need to find the section that contains this RVA.\n                         */\n\n                        tb_hize_t saved_pos_inner = tb_stream_offset(istream);\n                        tb_uint32_t name_file_offset = 0;\n\n                        // Find the section containing name_rva\n                        for (tb_uint16_t k = 0; k < header.nsects; k++) {\n                            xm_coff_section_t* s = &sections[k];\n                            if (name_rva >= s->vaddr && name_rva < s->vaddr + s->vsize) {\n                                name_file_offset = s->ofs + (name_rva - s->vaddr);\n                                break;\n                            }\n                        }\n\n                        if (name_file_offset != 0) {\n                             tb_char_t dll_name[256];\n                             if (xm_binutils_read_string(istream, name_file_offset, dll_name, sizeof(dll_name)) && dll_name[0]) {\n                                 lua_pushinteger(lua, result_count + 1);\n                                 lua_pushstring(lua, dll_name);\n                                 lua_settable(lua, -3);\n                                 result_count++;\n                             }\n                        }\n\n                        tb_stream_seek(istream, saved_pos_inner);\n                    }\n                }\n                break;\n            }\n        }\n\n        tb_check_break(!failed);\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (sections) tb_free(sections);\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/coff/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_COFF_PREFIX_H\n#define XM_BINUTILS_COFF_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_COFF_MACHINE_I386    0x014c\n#define XM_COFF_MACHINE_AMD64   0x8664\n#define XM_COFF_MACHINE_ARM     0x01c0\n#define XM_COFF_MACHINE_ARM64   0xaa64\n\n// PE Optional Header Magic\n#define XM_PE32_MAGIC           0x10b\n#define XM_PE32P_MAGIC          0x20b\n\n// COFF section flags\n#define XM_COFF_SCN_CNT_CODE                0x20  // IMAGE_SCN_CNT_CODE\n#define XM_COFF_SCN_CNT_INITIALIZED_DATA     0x40  // IMAGE_SCN_CNT_INITIALIZED_DATA\n#define XM_COFF_SCN_CNT_UNINITIALIZED_DATA   0x80  // IMAGE_SCN_CNT_UNINITIALIZED_DATA\n\n#define XM_COFF_SECTION_RDATA   0x40000040  // IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n#include \"tbox/prefix/packed.h\"\ntypedef struct __xm_coff_header_t {\n    tb_uint16_t machine;\n    tb_uint16_t nsects;\n    tb_uint32_t time;\n    tb_uint32_t symtabofs;\n    tb_uint32_t nsyms;\n    tb_uint16_t opthdr;\n    tb_uint16_t flags;\n} __tb_packed__ xm_coff_header_t;\n\ntypedef struct __xm_pe32_data_directory_t {\n    tb_uint32_t vaddr;\n    tb_uint32_t size;\n} __tb_packed__ xm_pe32_data_directory_t;\n\ntypedef struct __xm_pe32_opt_header_t {\n    tb_uint16_t magic;\n    tb_uint8_t  major_linker_version;\n    tb_uint8_t  minor_linker_version;\n    tb_uint32_t size_of_code;\n    tb_uint32_t size_of_initialized_data;\n    tb_uint32_t size_of_uninitialized_data;\n    tb_uint32_t address_of_entry_point;\n    tb_uint32_t base_of_code;\n    tb_uint32_t base_of_data;\n    tb_uint32_t image_base;\n    tb_uint32_t section_alignment;\n    tb_uint32_t file_alignment;\n    tb_uint16_t major_operating_system_version;\n    tb_uint16_t minor_operating_system_version;\n    tb_uint16_t major_image_version;\n    tb_uint16_t minor_image_version;\n    tb_uint16_t major_subsystem_version;\n    tb_uint16_t minor_subsystem_version;\n    tb_uint32_t win32_version_value;\n    tb_uint32_t size_of_image;\n    tb_uint32_t size_of_headers;\n    tb_uint32_t checksum;\n    tb_uint16_t subsystem;\n    tb_uint16_t dll_characteristics;\n    tb_uint32_t size_of_stack_reserve;\n    tb_uint32_t size_of_stack_commit;\n    tb_uint32_t size_of_heap_reserve;\n    tb_uint32_t size_of_heap_commit;\n    tb_uint32_t loader_flags;\n    tb_uint32_t number_of_rva_and_sizes;\n    xm_pe32_data_directory_t data_directory[16];\n} __tb_packed__ xm_pe32_opt_header_t;\n\ntypedef struct __xm_pe32p_opt_header_t {\n    tb_uint16_t magic;\n    tb_uint8_t  major_linker_version;\n    tb_uint8_t  minor_linker_version;\n    tb_uint32_t size_of_code;\n    tb_uint32_t size_of_initialized_data;\n    tb_uint32_t size_of_uninitialized_data;\n    tb_uint32_t address_of_entry_point;\n    tb_uint32_t base_of_code;\n    tb_uint64_t image_base;\n    tb_uint32_t section_alignment;\n    tb_uint32_t file_alignment;\n    tb_uint16_t major_operating_system_version;\n    tb_uint16_t minor_operating_system_version;\n    tb_uint16_t major_image_version;\n    tb_uint16_t minor_image_version;\n    tb_uint16_t major_subsystem_version;\n    tb_uint16_t minor_subsystem_version;\n    tb_uint32_t win32_version_value;\n    tb_uint32_t size_of_image;\n    tb_uint32_t size_of_headers;\n    tb_uint32_t checksum;\n    tb_uint16_t subsystem;\n    tb_uint16_t dll_characteristics;\n    tb_uint64_t size_of_stack_reserve;\n    tb_uint64_t size_of_stack_commit;\n    tb_uint64_t size_of_heap_reserve;\n    tb_uint64_t size_of_heap_commit;\n    tb_uint32_t loader_flags;\n    tb_uint32_t number_of_rva_and_sizes;\n    xm_pe32_data_directory_t data_directory[16];\n} __tb_packed__ xm_pe32p_opt_header_t;\n\ntypedef struct __xm_coff_import_directory_table_t {\n    tb_uint32_t original_first_thunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)\n    tb_uint32_t time_date_stamp;      // 0 if not bound, -1 if bound, and real date\\time stamp in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) O.W. date/time stamp of DLL bound to (Old BIND)\n    tb_uint32_t forwarder_chain;      // -1 if no forwarders\n    tb_uint32_t name_rva;             // RVA to name\n    tb_uint32_t first_thunk;          // RVA to IAT (if bound this IAT has actual addresses)\n} __tb_packed__ xm_coff_import_directory_table_t;\n\ntypedef struct __xm_coff_import_header_t {\n    tb_uint16_t sig1;     // 0\n    tb_uint16_t sig2;     // 0xffff\n    tb_uint16_t version;\n    tb_uint16_t machine;\n    tb_uint32_t time;\n    tb_uint32_t size;     // size of data\n    tb_uint16_t ordinal;  // ordinal or hint\n    tb_uint16_t type;     // type\n} __tb_packed__ xm_coff_import_header_t;\n\ntypedef struct __xm_coff_anon_header_t {\n    tb_uint16_t sig1;     // 0\n    tb_uint16_t sig2;     // 0xffff\n    tb_uint16_t version;\n    tb_uint16_t machine;\n    tb_uint32_t time;\n    tb_uint8_t  clsid[16];\n    tb_uint32_t size;     // size of data\n} __tb_packed__ xm_coff_anon_header_t;\n\ntypedef struct __xm_coff_section_t {\n    tb_char_t name[8];\n    tb_uint32_t vsize;\n    tb_uint32_t vaddr;\n    tb_uint32_t size;\n    tb_uint32_t ofs;\n    tb_uint32_t relocofs;\n    tb_uint32_t linenoofs;\n    tb_uint16_t nreloc;\n    tb_uint16_t nlineno;\n    tb_uint32_t flags;\n} __tb_packed__ xm_coff_section_t;\n\ntypedef struct __xm_coff_symbol_t {\n    union {\n        struct {\n            tb_char_t name[8];\n        } shortname;\n        struct {\n            tb_uint32_t zeros;\n            tb_uint32_t offset;\n        } longname;\n    } n;\n    tb_uint32_t value;\n    tb_int16_t sect;\n    tb_uint16_t type;\n    tb_uint8_t scl;\n    tb_uint8_t naux;\n} __tb_packed__ xm_coff_symbol_t;\n\ntypedef struct __xm_coff_aux_section_t {\n    tb_uint32_t length;\n    tb_uint16_t nreloc;\n    tb_uint16_t nlineno;\n    tb_uint8_t reserved[10];\n} __tb_packed__ xm_coff_aux_section_t;\n\ntypedef struct __xm_coff_symbol_tail_t {\n    tb_uint32_t value;\n    tb_int16_t  sect;\n    tb_uint16_t type;\n    tb_uint8_t  scl;\n    tb_uint8_t  naux;\n} __tb_packed__ xm_coff_symbol_tail_t;\n#include \"tbox/prefix/packed.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n/* get machine type from architecture string\n *\n * @param arch    the architecture string (e.g., \"x86_64\", \"i386\", \"arm64\")\n * @return        the machine type\n */\nstatic __tb_inline__ tb_uint16_t xm_binutils_coff_get_machine(tb_char_t const *arch) {\n    if (!arch) {\n        return XM_COFF_MACHINE_I386;\n    }\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return XM_COFF_MACHINE_AMD64;\n    } else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0) {\n        return XM_COFF_MACHINE_ARM64;\n    } else if (tb_strcmp(arch, \"arm\") == 0) {\n        return XM_COFF_MACHINE_ARM;\n    } else if (tb_strcmp(arch, \"i386\") == 0 || tb_strcmp(arch, \"x86\") == 0) {\n        return XM_COFF_MACHINE_I386;\n    }\n    return XM_COFF_MACHINE_I386;\n}\n\n/* write string to stream\n *\n * @param ostream the output stream\n * @param str     the string to write\n * @param len     the length (0 for auto-detect)\n */\nstatic __tb_inline__ tb_void_t xm_binutils_coff_write_string(tb_stream_ref_t ostream, tb_char_t const *str, tb_size_t len) {\n    tb_assert_and_check_return(ostream && str);\n    if (len == 0) {\n        len = tb_strlen(str);\n    }\n    tb_stream_bwrit(ostream, (tb_byte_t const *)str, len);\n}\n\n/* write padding bytes to stream\n *\n * @param ostream the output stream\n * @param count   the number of padding bytes\n */\nstatic __tb_inline__ tb_void_t xm_binutils_coff_write_padding(tb_stream_ref_t ostream, tb_size_t count) {\n    tb_assert_and_check_return(ostream);\n    tb_byte_t zero = 0;\n    while (count-- > 0) {\n        tb_stream_bwrit(ostream, &zero, 1);\n    }\n}\n\n/* write symbol name to stream (handles short and long names)\n *\n * @param ostream       the output stream\n * @param name          the symbol name\n * @param strtab_offset the string table offset (updated if long name)\n */\nstatic __tb_inline__ tb_void_t xm_binutils_coff_write_symbol_name(tb_stream_ref_t ostream, tb_char_t const *name, tb_uint32_t *strtab_offset) {\n    tb_assert_and_check_return(ostream && name && strtab_offset);\n    tb_size_t len = tb_strlen(name);\n    if (len <= 8) {\n        // short name: store directly in symbol name field\n        xm_binutils_coff_write_string(ostream, name, len);\n        if (len < 8) {\n            xm_binutils_coff_write_padding(ostream, 8 - len);\n        }\n    } else {\n        // long name: store offset in string table\n        tb_uint32_t zeros = 0;\n        tb_stream_bwrit(ostream, (tb_byte_t const *)&zeros, 4);\n        tb_stream_bwrit(ostream, (tb_byte_t const *)strtab_offset, 4);\n        *strtab_offset += (tb_uint32_t)(len + 1); // +1 for null terminator\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * readsyms inline implementation\n */\n\n/* read string from COFF string table\n *\n * @param istream       the input stream\n * @param strtab_offset the string table offset (including 4-byte size field)\n * @param offset        the string offset (from start of string table content, after size field)\n * @return              the string (static buffer, valid until next call)\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_coff_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) {\n    tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);\n\n    // In COFF format, the offset in symbol table is from the start of string table\n    // (including the 4-byte size field). So offset=4 points to the first string after\n    // the size field, offset=74 points to a string at position 74 from the start.\n\n    // read string table size first to validate offset\n    tb_uint32_t strtab_size = 0;\n    tb_hize_t saved_pos = tb_stream_offset(istream);\n    if (!tb_stream_seek(istream, strtab_offset)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)&strtab_size, 4)) {\n        tb_stream_seek(istream, saved_pos);\n        return tb_false;\n    }\n\n    // check offset (must be >= 4 to skip the size field, and < strtab_size)\n    if (offset < 4 || offset >= strtab_size) {\n        tb_stream_seek(istream, saved_pos);\n        return tb_false;\n    }\n\n    // restore position and use common implementation\n    tb_stream_seek(istream, saved_pos);\n    return xm_binutils_read_string(istream, strtab_offset + offset, name, name_size);\n}\n\n/* get symbol name from COFF symbol entry\n *\n * @param istream       the input stream\n * @param sym           the symbol entry\n * @param strtab_offset the string table offset\n * @param name          the buffer to store the symbol name\n * @param name_size     the size of the buffer\n * @return              tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_coff_get_symbol_name(tb_stream_ref_t istream, xm_coff_symbol_t const *sym, tb_hize_t strtab_offset, tb_char_t *name, tb_size_t name_size) {\n    tb_assert_and_check_return_val(istream && sym && name && name_size > 0, tb_false);\n\n    // check if it's a long name (first 4 bytes are zeros)\n    if (sym->n.longname.zeros == 0) {\n        // long name: read from string table\n        return xm_binutils_coff_read_string(istream, strtab_offset, sym->n.longname.offset, name, name_size);\n    } else {\n        // short name: use directly\n        tb_size_t len = tb_min(8, name_size - 1);\n        tb_strncpy(name, sym->n.shortname.name, len);\n        name[len] = '\\0';\n        // trim trailing nulls\n        while (len > 0 && name[len - 1] == '\\0') {\n            len--;\n        }\n        name[len] = '\\0';\n        return tb_true;\n    }\n}\n\n/* get symbol type character (nm-style) from COFF symbol\n *\n * @param scl      the storage class\n * @param sect     the section number (0 = undefined, 1-based)\n * @param sections the section headers array\n * @param nsects   the number of sections\n * @return         the type character (T/t/D/d/B/b/U)\n */\nstatic __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t scl, tb_int16_t sect, xm_coff_section_t const *sections, tb_uint16_t nsects) {\n    // undefined symbol\n    if (sect == 0) {\n        return 'U';\n    }\n\n    // check if external\n    tb_bool_t is_external = (scl == 2); // IMAGE_SYM_CLASS_EXTERNAL\n\n    // check section flags to determine type\n    if (sections && sect > 0 && sect <= nsects) {\n        tb_uint32_t flags = sections[sect - 1].flags; // section numbers are 1-based\n        // IMAGE_SCN_CNT_CODE (0x20) - code section\n        if (flags & XM_COFF_SCN_CNT_CODE) {\n            return is_external ? 'T' : 't';  // text section\n        }\n        // IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) - bss section\n        if (flags & XM_COFF_SCN_CNT_UNINITIALIZED_DATA) {\n            return is_external ? 'B' : 'b';  // bss section\n        }\n        // IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) - data section\n        if (flags & XM_COFF_SCN_CNT_INITIALIZED_DATA) {\n            return is_external ? 'D' : 'd';  // data section\n        }\n    }\n\n    // fallback: use section number heuristic\n    if (sect == 1) {\n        return is_external ? 'T' : 't';  // text section\n    } else if (sect == 2) {\n        return is_external ? 'D' : 'd';  // data section\n    } else if (sect == 3) {\n        return is_external ? 'B' : 'b';  // bss section\n    }\n\n    return is_external ? 'S' : 's';  // other section\n}\n\n#endif\n\n"
  },
  {
    "path": "core/src/xmake/binutils/coff/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readsyms_coff\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_coff_header_t const* header) {\n\n    // create result table\n    lua_newtable(lua);\n\n    /* check version\n     * version is the low 16 bits of the time field (offset 4)\n     * xm_coff_header_t: machine(2), nsects(2), time(4)\n     * xm_coff_import_header_t: sig1(2), sig2(2), version(2), machine(2)\n     */\n    tb_uint16_t version = header->time & 0xffff;\n    if (version == 1) {\n        // anonymous object header (used for CLSID)\n        /*\n         * @note we can not read symbols from the anonymous object (LTO/GL/LTCG),\n         * because it does not contain the symbol table.\n         */\n        xm_coff_anon_header_t anon_header;\n        if (!tb_stream_seek(istream, base_offset)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&anon_header, sizeof(anon_header))) {\n            return tb_false;\n        }\n    } else {\n        // import header\n        xm_coff_import_header_t import_header;\n        if (!tb_stream_seek(istream, base_offset)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&import_header, sizeof(import_header))) {\n            return tb_false;\n        }\n\n        // read symbol name (it follows the header)\n        tb_char_t name[256] = {0};\n        tb_size_t pos = 0;\n        tb_byte_t c;\n        while (pos < sizeof(name) - 1) {\n            if (!tb_stream_bread(istream, &c, 1)) {\n                break;\n            }\n            if (c == 0) {\n                break;\n            }\n            name[pos++] = (tb_char_t)c;\n        }\n        name[pos] = '\\0';\n\n        if (name[0]) {\n            lua_pushinteger(lua, 1);\n            lua_newtable(lua);\n\n            // name\n            lua_pushstring(lua, \"name\");\n            lua_pushstring(lua, name);\n            lua_settable(lua, -3);\n\n            // type\n            lua_pushstring(lua, \"type\");\n            lua_pushstring(lua, \"I\");\n            lua_settable(lua, -3);\n\n            lua_settable(lua, -3);\n        }\n    }\n    return tb_true;\n}\n\ntb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // read COFF header\n    xm_coff_header_t header;\n    if (!tb_stream_seek(istream, base_offset)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // check if it is an import object\n    if (header.machine == 0 && header.nsects == 0xffff) {\n        return xm_binutils_coff_read_import_symbols(istream, base_offset, lua, &header);\n    }\n\n    // check if there are symbols\n    if (header.nsyms == 0 || header.symtabofs == 0) {\n        lua_newtable(lua);\n        return tb_true;\n    }\n\n    // create result table\n    lua_newtable(lua);\n\n    // read string table offset (after symbol table)\n    tb_uint32_t strtab_offset = header.symtabofs + header.nsyms * 18; // each symbol is 18 bytes\n\n    // read section headers to determine section types\n    xm_coff_section_t *sections = tb_null;\n    if (header.nsects > 0) {\n        sections = (xm_coff_section_t*)tb_malloc(header.nsects * sizeof(xm_coff_section_t));\n        if (sections) {\n            tb_hize_t saved_pos = tb_stream_offset(istream);\n            // section headers are after COFF header and optional header\n            tb_uint32_t section_offset = sizeof(xm_coff_header_t) + (header.opthdr > 0 ? header.opthdr : 0);\n            if (tb_stream_seek(istream, base_offset + section_offset)) {\n                for (tb_uint16_t i = 0; i < header.nsects; i++) {\n                    if (!tb_stream_bread(istream, (tb_byte_t*)&sections[i], sizeof(xm_coff_section_t))) {\n                        break;\n                    }\n                }\n            }\n            tb_stream_seek(istream, saved_pos);\n        }\n    }\n\n    // read symbols\n    if (!tb_stream_seek(istream, base_offset + header.symtabofs)) {\n        if (sections) {\n            tb_free(sections);\n        }\n        return tb_false;\n    }\n\n    tb_uint32_t sym_index = 0;\n    tb_uint32_t sym_count = 0;\n    while (sym_index < header.nsyms) {\n        // read symbol\n        xm_coff_symbol_t sym;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {\n            if (sections) {\n                tb_free(sections);\n            }\n            return tb_false;\n        }\n\n        tb_bool_t skip = tb_false;\n        tb_char_t name[256] = {0};\n        if (!xm_binutils_coff_get_symbol_name(istream, &sym, base_offset + strtab_offset, name, sizeof(name)) || !name[0]) {\n            skip = tb_true;\n        } else if (name[0] == '.') {\n            skip = tb_true;\n        } else if (tb_strchr(name, '$') != tb_null ||\n                   tb_strstr(name, \".constprop\") != tb_null ||\n                   tb_strstr(name, \".startup\") != tb_null ||\n                   tb_strstr(name, \"ta$\") != tb_null) {\n            skip = tb_true;\n        }\n\n        if (!skip) {\n            // create symbol table entry\n            lua_pushinteger(lua, sym_count + 1);\n            lua_newtable(lua);\n\n            // name\n            lua_pushstring(lua, \"name\");\n            lua_pushstring(lua, name);\n            lua_settable(lua, -3);\n\n            // type (nm-style: T/t/D/d/B/b/U)\n            tb_char_t type_char = xm_binutils_coff_get_symbol_type_char(sym.scl, sym.sect, sections, header.nsects);\n            tb_char_t type_str[2] = {type_char, '\\0'};\n            lua_pushstring(lua, \"type\");\n            lua_pushstring(lua, type_str);\n            lua_settable(lua, -3);\n\n            lua_settable(lua, -3);\n            sym_count++;\n        }\n\n        // skip to the next symbol, including auxiliary entries\n        sym_index++;\n        if (sym.naux > 0) {\n            sym_index += sym.naux;\n            if (!tb_stream_seek(istream, tb_stream_offset(istream) + sym.naux * 18)) {\n                if (sections) {\n                    tb_free(sections);\n                }\n                return tb_false;\n            }\n        }\n    }\n\n    if (sections) {\n        tb_free(sections);\n    }\n\n    return tb_true;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/deplibs.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        deplibs.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"deplibs\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"coff/prefix.h\"\n#include \"elf/prefix.h\"\n#include \"macho/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * forward declarations\n */\nextern tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get dependent libraries from binary file (auto-detect format)\n *\n * @param lua the lua state\n * @return 1 on success (table on stack), 2 on failure (with error message on stack)\n */\ntb_int_t xm_binutils_deplibs(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binary file path\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // open file\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    if (!istream) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"open %s failed\", binaryfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"open %s failed\", binaryfile);\n            break;\n        }\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"cannot detect file format\");\n            break;\n        }\n\n        // create result list\n        lua_newtable(lua);\n\n        // get dependents based on format\n        if (format == XM_BINUTILS_FORMAT_COFF) {\n            if (!xm_binutils_coff_deplibs(istream, 0, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to parse COFF\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_PE) {\n            // seek to e_lfanew\n            if (!tb_stream_seek(istream, 0x3c)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to seek to e_lfanew\");\n                 break;\n            }\n\n            // read e_lfanew\n            tb_uint32_t e_lfanew = 0;\n            if (!tb_stream_bread(istream, (tb_byte_t*)&e_lfanew, 4)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to read e_lfanew\");\n                 break;\n            }\n\n            // e_lfanew is little endian\n            e_lfanew = tb_bits_le_to_ne_u32(e_lfanew);\n\n            // call coff deplibs with offset = e_lfanew + 4 (skip PE signature)\n            if (!xm_binutils_coff_deplibs(istream, e_lfanew + 4, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to parse PE/COFF\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n            if (!xm_binutils_macho_deplibs(istream, 0, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to parse Mach-O\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_ELF) {\n            if (!xm_binutils_elf_deplibs(istream, 0, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"failed to parse ELF\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_WASM) {\n        } else {\n            lua_pop(lua, 1); // pop table\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"unsupported format %d\", format);\n            break;\n        }\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (istream) {\n        tb_stream_exit(istream);\n    }\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/elf/bin2elf.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bin2elf.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bin2elf\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream,\n                                          tb_stream_ref_t ostream,\n                                          tb_char_t const *symbol_prefix,\n                                          tb_char_t const *arch,\n                                          tb_char_t const *basename,\n                                          tb_bool_t zeroend) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n\n    // get file size\n    tb_hong_t filesize = tb_stream_size(istream);\n    if (filesize < 0 || filesize > 0xffffffffU) {\n        return tb_false;\n    }\n    tb_uint32_t datasize = (tb_uint32_t)filesize;\n    // add null terminator if zeroend is true\n    if (zeroend) {\n        if (datasize >= 0xffffffffU) {\n            return tb_false; // would overflow\n        }\n        datasize++;\n    }\n\n    // generate symbol names from filename\n    tb_char_t symbol_name[256] = {0};\n    tb_char_t symbol_start[256] = {0};\n    tb_char_t symbol_end[256] = {0};\n\n    // use basename or default to \"data\"\n    if (!basename || !basename[0]) {\n        basename = \"data\";\n    }\n\n    // build symbol name\n    if (symbol_prefix) {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"%s%s\", symbol_prefix, basename);\n    } else {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"_binary_%s\", basename);\n    }\n\n    // replace non-alphanumeric with underscore\n    xm_binutils_sanitize_symbol_name(symbol_name);\n\n    tb_snprintf(symbol_start, sizeof(symbol_start), \"%s_start\", symbol_name);\n    tb_snprintf(symbol_end, sizeof(symbol_end), \"%s_end\", symbol_name);\n\n    // calculate offsets\n    tb_uint32_t header_size = sizeof(xm_elf32_header_t);\n    tb_uint32_t section_header_size = sizeof(xm_elf32_section_t);\n    tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack\n    tb_uint32_t section_headers_ofs = header_size;\n    tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size;\n    tb_uint32_t rodata_size = datasize;\n    tb_uint32_t rodata_padding = (4 - (rodata_size & 3)) & 3; // align to 4 bytes for 32-bit\n    tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding;\n    tb_uint32_t symtab_size = 3 * sizeof(xm_elf32_symbol_t); // NULL, start, end\n    tb_uint32_t symtab_padding = (4 - (symtab_size & 3)) & 3; // align to 4 bytes\n    tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding;\n\n    // calculate string table size\n    tb_size_t start_len = tb_strlen(symbol_start);\n    tb_size_t end_len = tb_strlen(symbol_end);\n    tb_uint32_t strtab_size = 1; // initial null byte\n    strtab_size += (tb_uint32_t)(start_len + 1);\n    strtab_size += (tb_uint32_t)(end_len + 1);\n    tb_uint32_t strtab_padding = (4 - (strtab_size & 3)) & 3; // align to 4 bytes\n    tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding;\n\n    // calculate section header string table size\n    tb_uint32_t shstrtab_size = 1; // initial null byte\n    shstrtab_size += 8; // \".rodata\\0\" (7 + 1)\n    shstrtab_size += 8; // \".symtab\\0\" (7 + 1)\n    shstrtab_size += 8; // \".strtab\\0\" (7 + 1)\n    shstrtab_size += 10; // \".shstrtab\\0\" (9 + 1)\n    shstrtab_size += 16; // \".note.GNU-stack\\0\" (15 + 1)\n\n    // write ELF header\n    xm_elf32_header_t header;\n    tb_memset(&header, 0, sizeof(header));\n    header.e_ident[0] = 0x7f;\n    header.e_ident[1] = 'E';\n    header.e_ident[2] = 'L';\n    header.e_ident[3] = 'F';\n    header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS32;\n    header.e_ident[5] = 1; // ELFDATA2LSB\n    header.e_ident[6] = 1; // EV_CURRENT\n    header.e_ident[7] = 0; // ELFOSABI_SYSV\n    header.e_type = 1; // ET_REL\n    header.e_machine = xm_binutils_elf_get_machine(arch);\n    header.e_version = 1;\n    header.e_shoff = section_headers_ofs;\n    header.e_ehsize = header_size;\n    header.e_shentsize = section_header_size;\n    header.e_shnum = section_count;\n    header.e_shstrndx = 4; // .shstrtab section index\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // write section headers\n    xm_elf32_section_t section_null;\n    tb_memset(&section_null, 0, sizeof(section_null));\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_null, sizeof(section_null))) {\n        return tb_false;\n    }\n\n    // write .rodata section header\n    xm_elf32_section_t section_rodata;\n    tb_memset(&section_rodata, 0, sizeof(section_rodata));\n    section_rodata.sh_name = 1; // \".rodata\" in shstrtab\n    section_rodata.sh_type = XM_ELF_SHT_PROGBITS;\n    section_rodata.sh_flags = XM_ELF_SHF_ALLOC;\n    section_rodata.sh_offset = rodata_ofs;\n    section_rodata.sh_size = rodata_size;\n    section_rodata.sh_addralign = 4;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_rodata, sizeof(section_rodata))) {\n        return tb_false;\n    }\n\n    // write .symtab section header\n    xm_elf32_section_t section_symtab;\n    tb_memset(&section_symtab, 0, sizeof(section_symtab));\n    section_symtab.sh_name = 9; // \".symtab\" in shstrtab\n    section_symtab.sh_type = XM_ELF_SHT_SYMTAB;\n    section_symtab.sh_offset = symtab_ofs;\n    section_symtab.sh_size = symtab_size;\n    section_symtab.sh_link = 3; // .strtab section index\n    section_symtab.sh_info = 1; // first global symbol index\n    section_symtab.sh_addralign = 4;\n    section_symtab.sh_entsize = sizeof(xm_elf32_symbol_t);\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_symtab, sizeof(section_symtab))) {\n        return tb_false;\n    }\n\n    // write .strtab section header\n    xm_elf32_section_t section_strtab;\n    tb_memset(&section_strtab, 0, sizeof(section_strtab));\n    section_strtab.sh_name = 17; // \".strtab\" in shstrtab\n    section_strtab.sh_type = XM_ELF_SHT_STRTAB;\n    section_strtab.sh_offset = strtab_ofs;\n    section_strtab.sh_size = strtab_size;\n    section_strtab.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_strtab, sizeof(section_strtab))) {\n        return tb_false;\n    }\n\n    // write .shstrtab section header\n    xm_elf32_section_t section_shstrtab;\n    tb_memset(&section_shstrtab, 0, sizeof(section_shstrtab));\n    section_shstrtab.sh_name = 25; // \".shstrtab\" in shstrtab\n    section_shstrtab.sh_type = XM_ELF_SHT_STRTAB;\n    section_shstrtab.sh_offset = shstrtab_ofs;\n    section_shstrtab.sh_size = shstrtab_size;\n    section_shstrtab.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_shstrtab, sizeof(section_shstrtab))) {\n        return tb_false;\n    }\n\n    // write .note.GNU-stack section header (empty section to mark stack as non-executable)\n    xm_elf32_section_t section_note_gnu_stack;\n    tb_memset(&section_note_gnu_stack, 0, sizeof(section_note_gnu_stack));\n    section_note_gnu_stack.sh_name = 35; // \".note.GNU-stack\" in shstrtab (25 + 10)\n    section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS;\n    section_note_gnu_stack.sh_flags = 0; // no flags\n    section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab\n    section_note_gnu_stack.sh_size = 0; // empty section\n    section_note_gnu_stack.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_note_gnu_stack, sizeof(section_note_gnu_stack))) {\n        return tb_false;\n    }\n\n    // write .rodata section data\n    if (!xm_binutils_stream_copy(istream, ostream, filesize)) {\n        return tb_false;\n    }\n    // append null terminator if zeroend is true\n    if (zeroend) {\n        tb_byte_t zero = 0;\n        if (!tb_stream_bwrit(ostream, &zero, 1)) {\n            return tb_false;\n        }\n    }\n\n    // align .rodata to 4 bytes\n    if (rodata_padding > 0) {\n        tb_byte_t zero = 0;\n        while (rodata_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write symbol table\n    // symbol 0: NULL symbol\n    xm_elf32_symbol_t sym_null;\n    tb_memset(&sym_null, 0, sizeof(sym_null));\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) {\n        return tb_false;\n    }\n\n    // symbol 1: _binary_xxx_start\n    xm_elf32_symbol_t sym_start;\n    tb_memset(&sym_start, 0, sizeof(sym_start));\n    sym_start.st_name = 1; // offset in .strtab (after initial null)\n    sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;\n    sym_start.st_shndx = 1; // .rodata section index\n    sym_start.st_value = 0;\n    sym_start.st_size = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) {\n        return tb_false;\n    }\n\n    // symbol 2: _binary_xxx_end\n    xm_elf32_symbol_t sym_end;\n    tb_memset(&sym_end, 0, sizeof(sym_end));\n    sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab\n    sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;\n    sym_end.st_shndx = 1; // .rodata section index\n    sym_end.st_value = rodata_size;\n    sym_end.st_size = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) {\n        return tb_false;\n    }\n\n    // align .symtab to 4 bytes\n    if (symtab_padding > 0) {\n        tb_byte_t zero = 0;\n        while (symtab_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write string table\n    tb_byte_t null = 0;\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n\n    // align .strtab to 4 bytes\n    if (strtab_padding > 0) {\n        tb_byte_t zero = 0;\n        while (strtab_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write section header string table\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".rodata\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".symtab\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".strtab\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".shstrtab\", 9)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".note.GNU-stack\", 15)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n\n    return tb_true;\n}\n\nstatic tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream,\n                                          tb_stream_ref_t ostream,\n                                          tb_char_t const *symbol_prefix,\n                                          tb_char_t const *arch,\n                                          tb_char_t const *basename,\n                                          tb_bool_t zeroend) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n\n    // get file size\n    tb_hong_t filesize = tb_stream_size(istream);\n    if (filesize < 0 || filesize > 0xffffffffU) {\n        return tb_false;\n    }\n    tb_uint32_t datasize = (tb_uint32_t)filesize;\n    // add null terminator if zeroend is true\n    if (zeroend) {\n        if (datasize >= 0xffffffffU) {\n            return tb_false; // would overflow\n        }\n        datasize++;\n    }\n\n    // generate symbol names from filename\n    tb_char_t symbol_name[256] = {0};\n    tb_char_t symbol_start[256] = {0};\n    tb_char_t symbol_end[256] = {0};\n\n    // use basename or default to \"data\"\n    if (!basename || !basename[0]) {\n        basename = \"data\";\n    }\n\n    // build symbol name\n    if (symbol_prefix) {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"%s%s\", symbol_prefix, basename);\n    } else {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"_binary_%s\", basename);\n    }\n\n    // replace non-alphanumeric with underscore\n    xm_binutils_sanitize_symbol_name(symbol_name);\n\n    tb_snprintf(symbol_start, sizeof(symbol_start), \"%s_start\", symbol_name);\n    tb_snprintf(symbol_end, sizeof(symbol_end), \"%s_end\", symbol_name);\n\n    // calculate offsets\n    tb_uint32_t header_size = sizeof(xm_elf64_header_t);\n    tb_uint32_t section_header_size = sizeof(xm_elf64_section_t);\n    tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack\n    tb_uint32_t section_headers_ofs = header_size;\n    tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size;\n    tb_uint32_t rodata_size = datasize;\n    tb_uint32_t rodata_padding = (8 - (rodata_size & 7)) & 7;\n    tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding;\n    tb_uint32_t symtab_size = 3 * sizeof(xm_elf64_symbol_t); // NULL, start, end\n    tb_uint32_t symtab_padding = (8 - (symtab_size & 7)) & 7;\n    tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding;\n\n    // calculate string table size\n    tb_size_t start_len = tb_strlen(symbol_start);\n    tb_size_t end_len = tb_strlen(symbol_end);\n    tb_uint32_t strtab_size = 1; // initial null byte\n    strtab_size += (tb_uint32_t)(start_len + 1);\n    strtab_size += (tb_uint32_t)(end_len + 1);\n    tb_uint32_t strtab_padding = (8 - (strtab_size & 7)) & 7;\n\n    // calculate section header string table size\n    tb_uint32_t shstrtab_size = 1; // initial null byte\n    shstrtab_size += 8; // \".rodata\\0\" (7 + 1)\n    shstrtab_size += 8; // \".symtab\\0\" (7 + 1)\n    shstrtab_size += 8; // \".strtab\\0\" (7 + 1)\n    shstrtab_size += 10; // \".shstrtab\\0\" (9 + 1)\n    shstrtab_size += 16; // \".note.GNU-stack\\0\" (15 + 1)\n    tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding;\n\n    // write ELF header\n    xm_elf64_header_t header;\n    tb_memset(&header, 0, sizeof(header));\n    header.e_ident[0] = 0x7f;\n    header.e_ident[1] = 'E';\n    header.e_ident[2] = 'L';\n    header.e_ident[3] = 'F';\n    header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS64;\n    header.e_ident[5] = 1; // ELFDATA2LSB\n    header.e_ident[6] = 1; // EV_CURRENT\n    header.e_ident[7] = 0; // ELFOSABI_SYSV\n    header.e_type = 1; // ET_REL\n    header.e_machine = xm_binutils_elf_get_machine(arch);\n    header.e_version = 1;\n    header.e_shoff = section_headers_ofs;\n    header.e_ehsize = header_size;\n    header.e_shentsize = section_header_size;\n    header.e_shnum = section_count;\n    header.e_shstrndx = 4; // .shstrtab section index\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // write section headers\n    xm_elf64_section_t section_null;\n    tb_memset(&section_null, 0, sizeof(section_null));\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_null, sizeof(section_null))) {\n        return tb_false;\n    }\n\n    // write .rodata section header\n    xm_elf64_section_t section_rodata;\n    tb_memset(&section_rodata, 0, sizeof(section_rodata));\n    section_rodata.sh_name = 1; // \".rodata\" in shstrtab\n    section_rodata.sh_type = XM_ELF_SHT_PROGBITS;\n    section_rodata.sh_flags = XM_ELF_SHF_ALLOC;\n    section_rodata.sh_offset = rodata_ofs;\n    section_rodata.sh_size = rodata_size;\n    section_rodata.sh_addralign = 8;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_rodata, sizeof(section_rodata))) {\n        return tb_false;\n    }\n\n    // write .symtab section header\n    xm_elf64_section_t section_symtab;\n    tb_memset(&section_symtab, 0, sizeof(section_symtab));\n    section_symtab.sh_name = 9; // \".symtab\" in shstrtab\n    section_symtab.sh_type = XM_ELF_SHT_SYMTAB;\n    section_symtab.sh_offset = symtab_ofs;\n    section_symtab.sh_size = symtab_size;\n    section_symtab.sh_link = 3; // .strtab section index\n    section_symtab.sh_info = 1; // first global symbol index\n    section_symtab.sh_addralign = 8;\n    section_symtab.sh_entsize = sizeof(xm_elf64_symbol_t);\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_symtab, sizeof(section_symtab))) {\n        return tb_false;\n    }\n\n    // write .strtab section header\n    xm_elf64_section_t section_strtab;\n    tb_memset(&section_strtab, 0, sizeof(section_strtab));\n    section_strtab.sh_name = 17; // \".strtab\" in shstrtab\n    section_strtab.sh_type = XM_ELF_SHT_STRTAB;\n    section_strtab.sh_offset = strtab_ofs;\n    section_strtab.sh_size = strtab_size;\n    section_strtab.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_strtab, sizeof(section_strtab))) {\n        return tb_false;\n    }\n\n    // write .shstrtab section header\n    xm_elf64_section_t section_shstrtab;\n    tb_memset(&section_shstrtab, 0, sizeof(section_shstrtab));\n    section_shstrtab.sh_name = 25; // \".shstrtab\" in shstrtab\n    section_shstrtab.sh_type = XM_ELF_SHT_STRTAB;\n    section_shstrtab.sh_offset = shstrtab_ofs; // points to initial null byte\n    section_shstrtab.sh_size = shstrtab_size; // size includes initial null and all strings\n    section_shstrtab.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_shstrtab, sizeof(section_shstrtab))) {\n        return tb_false;\n    }\n\n    // write .note.GNU-stack section header (empty section to mark stack as non-executable)\n    xm_elf64_section_t section_note_gnu_stack;\n    tb_memset(&section_note_gnu_stack, 0, sizeof(section_note_gnu_stack));\n    section_note_gnu_stack.sh_name = 35; // \".note.GNU-stack\" in shstrtab (25 + 10)\n    section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS;\n    section_note_gnu_stack.sh_flags = 0; // no flags\n    section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab\n    section_note_gnu_stack.sh_size = 0; // empty section\n    section_note_gnu_stack.sh_addralign = 1;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section_note_gnu_stack, sizeof(section_note_gnu_stack))) {\n        return tb_false;\n    }\n\n    // write .rodata section data\n    if (!xm_binutils_stream_copy(istream, ostream, filesize)) {\n        return tb_false;\n    }\n    // append null terminator if zeroend is true\n    if (zeroend) {\n        tb_byte_t zero = 0;\n        if (!tb_stream_bwrit(ostream, &zero, 1)) {\n            return tb_false;\n        }\n    }\n\n    // align .rodata to 8 bytes\n    if (rodata_padding > 0) {\n        tb_byte_t zero = 0;\n        while (rodata_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write symbol table\n    // symbol 0: NULL symbol\n    xm_elf64_symbol_t sym_null;\n    tb_memset(&sym_null, 0, sizeof(sym_null));\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) {\n        return tb_false;\n    }\n\n    // symbol 1: _binary_xxx_start\n    xm_elf64_symbol_t sym_start;\n    tb_memset(&sym_start, 0, sizeof(sym_start));\n    sym_start.st_name = 1; // offset in .strtab (after initial null)\n    sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;\n    sym_start.st_shndx = 1; // .rodata section index\n    sym_start.st_value = 0;\n    sym_start.st_size = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) {\n        return tb_false;\n    }\n\n    // symbol 2: _binary_xxx_end\n    xm_elf64_symbol_t sym_end;\n    tb_memset(&sym_end, 0, sizeof(sym_end));\n    sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab\n    sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;\n    sym_end.st_shndx = 1; // .rodata section index\n    sym_end.st_value = rodata_size;\n    sym_end.st_size = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) {\n        return tb_false;\n    }\n\n    // align .symtab to 8 bytes\n    if (symtab_padding > 0) {\n        tb_byte_t zero = 0;\n        while (symtab_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write string table\n    tb_byte_t null = 0;\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n\n    // align .strtab to 8 bytes\n    if (strtab_padding > 0) {\n        tb_byte_t zero = 0;\n        while (strtab_padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write section header string table\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".rodata\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".symtab\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".strtab\", 7)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".shstrtab\", 9)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)\".note.GNU-stack\", 15)) {\n        return tb_false;\n    }\n    if (!tb_stream_bwrit(ostream, &null, 1)) {\n        return tb_false;\n    }\n\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* generate ELF object file from binary file\n *\n * local ok, errors = binutils.bin2elf(binaryfile, outputfile, symbol_prefix, arch, basename, zeroend)\n */\ntb_int_t xm_binutils_bin2elf(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binaryfile\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // get the outputfile\n    tb_char_t const *outputfile = luaL_checkstring(lua, 2);\n    tb_check_return_val(outputfile, 0);\n\n    // get symbol prefix (optional)\n    tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;\n\n    // get arch (optional)\n    tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;\n\n    // get basename (optional)\n    tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;\n\n    // get zeroend (optional, default: false)\n    tb_bool_t zeroend = lua_toboolean(lua, 6);\n\n    // do dump\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2elf: open %s failed\", binaryfile);\n            break;\n        }\n\n        if (!tb_stream_open(ostream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2elf: open %s failed\", outputfile);\n            break;\n        }\n\n        // choose 32-bit or 64-bit ELF based on architecture\n        tb_bool_t is_64bit = xm_binutils_elf_is_64bit(arch);\n        if (is_64bit) {\n            if (!xm_binutils_bin2elf_dump_64(istream, ostream, symbol_prefix, arch, basename, zeroend)) {\n                lua_pushboolean(lua, tb_false);\n                lua_pushfstring(lua, \"bin2elf: dump data failed\");\n                break;\n            }\n        } else {\n            if (!xm_binutils_bin2elf_dump_32(istream, ostream, symbol_prefix, arch, basename, zeroend)) {\n                lua_pushboolean(lua, tb_false);\n                lua_pushfstring(lua, \"bin2elf: dump data failed\");\n                break;\n            }\n        }\n\n        ok = tb_true;\n        lua_pushboolean(lua, ok);\n\n    } while (0);\n\n    if (istream)\n        tb_stream_clos(istream);\n    istream = tb_null;\n\n    if (ostream)\n        tb_stream_clos(ostream);\n    ostream = tb_null;\n\n    return ok ? 1 : 2;\n}\n\n"
  },
  {
    "path": "core/src/xmake/binutils/elf/deplibs.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        deplibs.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"deplibs_elf\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t xm_binutils_elf_check_path(tb_char_t const* path, tb_char_t const* name, tb_char_t* output, tb_size_t output_size) {\n    tb_char_t fullpath[TB_PATH_MAXN];\n    tb_snprintf(fullpath, sizeof(fullpath), \"%s/%s\", path, name);\n    if (tb_file_info(fullpath, tb_null)) {\n        if (output) {\n            tb_strlcpy(output, fullpath, output_size);\n        }\n        return tb_true;\n    }\n    return tb_false;\n}\n\nstatic tb_void_t xm_binutils_elf_resolve_path(tb_char_t const* name, tb_char_t const* rpath, tb_char_t const* binary_dir, tb_char_t* output, tb_size_t output_size) {\n    \n    // absolute path?\n    if (tb_path_is_absolute(name)) {\n        tb_strlcpy(output, name, output_size);\n        return;\n    }\n\n    // try rpath/runpath\n    if (rpath && binary_dir) {\n        tb_char_t const* p = rpath;\n        tb_char_t const* e = tb_null;\n        while (*p) {\n            e = tb_strchr(p, ':');\n            tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p);\n            if (n > 0) {\n                tb_char_t path[TB_PATH_MAXN];\n                tb_char_t expanded_path[TB_PATH_MAXN];\n                tb_strncpy(path, p, n);\n                path[n] = '\\0';\n\n                // replace $ORIGIN\n                tb_char_t* origin = tb_strstr(path, \"$ORIGIN\");\n                if (origin) {\n                    tb_long_t len = tb_snprintf(expanded_path, sizeof(expanded_path), \"%.*s%s%s\", (tb_int_t)(origin - path), path, binary_dir, origin + 7);\n                    if (len >= 0) {\n                        if (xm_binutils_elf_check_path(expanded_path, name, output, output_size)) {\n                            return;\n                        }\n                    }\n                } else {\n                    if (xm_binutils_elf_check_path(path, name, output, output_size)) {\n                        return;\n                    }\n                }\n            }\n            if (e) p = e + 1;\n            else break;\n        }\n    }\n\n    // try system paths\n    static tb_char_t const* s_sys_paths[] = {\n        \"/lib\",\n        \"/usr/lib\",\n        \"/lib64\",\n        \"/usr/lib64\",\n        \"/usr/local/lib\",\n        \"/usr/local/lib64\",\n        \"/lib/x86_64-linux-gnu\", // Debian/Ubuntu\n        \"/usr/lib/x86_64-linux-gnu\",\n        \"/lib/i386-linux-gnu\",\n        \"/usr/lib/i386-linux-gnu\",\n        \"/lib/aarch64-linux-gnu\",\n        \"/usr/lib/aarch64-linux-gnu\",\n        \"/lib/arm-linux-gnueabihf\",\n        \"/usr/lib/arm-linux-gnueabihf\",\n        tb_null\n    };\n\n    for (tb_char_t const** sys_path = s_sys_paths; *sys_path; sys_path++) {\n        if (xm_binutils_elf_check_path(*sys_path, name, output, output_size)) {\n            return;\n        }\n    }\n\n    // not found, return original name\n    tb_strlcpy(output, name, output_size);\n}\n\nstatic tb_bool_t xm_binutils_elf_deplibs_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // read ELF header\n    xm_elf32_header_t header;\n    if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) {\n        return tb_false;\n    }\n\n    // find program interpreter (PT_INTERP) and push\n    tb_char_t name[256];\n    tb_size_t result_count = 0;\n    if (xm_binutils_elf_find_interp_32(istream, base_offset, &header, name, sizeof(name))) {\n        lua_pushinteger(lua, result_count + 1);\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    // build dynamic/string table context\n    xm_elf_context_t ctx;\n    if (!xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {\n        return tb_true;\n    }\n\n    // scan .dynamic entries: collect NEEDED and read RPATH/RUNPATH\n    tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf32_dynamic_t));\n    if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) {\n        return tb_false;\n    }\n\n    tb_char_t rpath[8192] = {0};\n    tb_char_t runpath[8192] = {0};\n    tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true));\n    if (needed_libs) {\n        for (tb_uint32_t i = 0; i < count; i++) {\n            xm_elf32_dynamic_t dyn;\n            if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) {\n                break;\n            }\n\n            if (dyn.d_tag == XM_ELF_DT_NULL) {\n                break;\n            }\n\n            if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) {\n                tb_char_t name[256];\n                if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, name, sizeof(name)) && name[0]) {\n                    tb_vector_insert_tail(needed_libs, name);\n                }\n            } else if (dyn.d_tag == XM_ELF_DT_RPATH) {\n                xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, rpath, sizeof(rpath));\n            } else if (dyn.d_tag == XM_ELF_DT_RUNPATH) {\n                xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, runpath, sizeof(runpath));\n            }\n        }\n\n        tb_char_t const* binary_path = tb_null;\n        tb_char_t binary_dir[TB_PATH_MAXN] = {0};\n        if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) {\n            tb_path_directory(binary_path, binary_dir, sizeof(binary_dir));\n        }\n\n        // resolve $ORIGIN and rpath/runpath, push full paths\n        tb_for_all (tb_char_t const*, name, needed_libs) {\n            tb_char_t fullpath[TB_PATH_MAXN];\n            xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath));\n            lua_pushinteger(lua, result_count + 1);\n            lua_pushstring(lua, fullpath);\n            lua_settable(lua, -3);\n            result_count++;\n        }\n        tb_vector_exit(needed_libs);\n    }\n\n    return tb_true;\n}\n\nstatic tb_bool_t xm_binutils_elf_deplibs_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // read ELF header\n    xm_elf64_header_t header;\n    if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) {\n        return tb_false;\n    }\n\n    // find program interpreter (PT_INTERP) and push\n    tb_char_t name[256];\n    tb_size_t result_count = 0;\n    if (xm_binutils_elf_find_interp_64(istream, base_offset, &header, name, sizeof(name))) {\n        lua_pushinteger(lua, result_count + 1);\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    // build dynamic/string table context\n    xm_elf_context_t ctx;\n    if (!xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {\n        return tb_true;\n    }\n\n    // read dynamic entries\n    tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf64_dynamic_t));\n    if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) {\n        return tb_false;\n    }\n\n    tb_char_t rpath[8192] = {0};\n    tb_char_t runpath[8192] = {0};\n    tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true));\n    if (needed_libs) {\n        for (tb_uint32_t i = 0; i < count; i++) {\n            xm_elf64_dynamic_t dyn;\n            if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) {\n                break;\n            }\n\n            if (dyn.d_tag == XM_ELF_DT_NULL) {\n                break;\n            }\n\n            if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) {\n                 tb_char_t name[256];\n                 if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, name, sizeof(name)) && name[0]) {\n                     tb_vector_insert_tail(needed_libs, name);\n                 }\n            } else if (dyn.d_tag == XM_ELF_DT_RPATH) {\n                 xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, rpath, sizeof(rpath));\n            } else if (dyn.d_tag == XM_ELF_DT_RUNPATH) {\n                 xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, runpath, sizeof(runpath));\n            }\n        }\n\n        // get binary directory\n        tb_char_t const* binary_path = tb_null;\n        tb_char_t binary_dir[TB_PATH_MAXN] = {0};\n        if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) {\n            tb_path_directory(binary_path, binary_dir, sizeof(binary_dir));\n        }\n\n        // resolve and push paths\n        tb_for_all (tb_char_t const*, name, needed_libs) {\n            tb_char_t fullpath[TB_PATH_MAXN];\n            xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath));\n            lua_pushinteger(lua, result_count + 1);\n            lua_pushstring(lua, fullpath);\n            lua_settable(lua, -3);\n            result_count++;\n        }\n        tb_vector_exit(needed_libs);\n    }\n\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // read and check ELF magic\n    tb_uint8_t magic[4];\n    if (!tb_stream_seek(istream, base_offset)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, magic, 4)) {\n        return tb_false;\n    }\n    if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {\n        return tb_false;\n    }\n\n    // check ELF class (32-bit or 64-bit)\n    tb_uint8_t elf_class;\n    if (!tb_stream_seek(istream, base_offset + 4)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) {\n        return tb_false;\n    }\n\n    if (elf_class == 1) {\n        return xm_binutils_elf_deplibs_32(istream, base_offset, lua);\n    } else if (elf_class == 2) {\n        return xm_binutils_elf_deplibs_64(istream, base_offset, lua);\n    }\n\n    return tb_false;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/elf/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_ELF_PREFIX_H\n#define XM_BINUTILS_ELF_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_ELF_MAGIC0 0x7f\n#define XM_ELF_MAGIC1 'E'\n#define XM_ELF_MAGIC2 'L'\n#define XM_ELF_MAGIC3 'F'\n\n// ELF class\n#define XM_ELF_EI_CLASS 4\n#define XM_ELF_CLASS32  1\n#define XM_ELF_CLASS64  2\n\n#define XM_ELF_MACHINE_NONE      0x00\n#define XM_ELF_MACHINE_SPARC     0x02\n#define XM_ELF_MACHINE_I386      0x03\n#define XM_ELF_MACHINE_MIPS      0x08\n#define XM_ELF_MACHINE_POWERPC   0x14\n#define XM_ELF_MACHINE_POWERPC64 0x15\n#define XM_ELF_MACHINE_S390      0x16\n#define XM_ELF_MACHINE_ARM       0x28\n#define XM_ELF_MACHINE_SUPERH    0x2a\n#define XM_ELF_MACHINE_SPARC64   0x2b\n#define XM_ELF_MACHINE_IA_64     0x32\n#define XM_ELF_MACHINE_X86_64    0x3e\n#define XM_ELF_MACHINE_RISCV     0xf3\n#define XM_ELF_MACHINE_ARM64     0xb7\n#define XM_ELF_MACHINE_WASM      0xe7\n#define XM_ELF_MACHINE_LOONGARCH 0x102\n\n#define XM_ELF_SHT_PROGBITS      0x1\n#define XM_ELF_SHT_SYMTAB        0x2\n#define XM_ELF_SHT_STRTAB        0x3\n#define XM_ELF_SHT_DYNAMIC       0x6\n\n#define XM_ELF_PT_LOAD           1\n#define XM_ELF_PT_DYNAMIC        2\n#define XM_ELF_PT_INTERP         3\n\n#define XM_ELF_DT_NULL           0\n#define XM_ELF_DT_NEEDED         1\n#define XM_ELF_DT_STRTAB         5\n#define XM_ELF_DT_STRSZ          10\n#define XM_ELF_DT_SONAME         14\n#define XM_ELF_DT_RPATH          15\n#define XM_ELF_DT_RUNPATH        29\n#define XM_ELF_DT_AUXILIARY      0x7ffffffd\n#define XM_ELF_DT_FILTER         0x7fffffff\n\n#define XM_ELF_SHF_ALLOC         0x2\n#define XM_ELF_SHF_WRITE         0x1\n\n#define XM_ELF_STB_GLOBAL        0x1\n#define XM_ELF_STT_OBJECT        0x1\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n#include \"tbox/prefix/packed.h\"\ntypedef struct __xm_elf_context_t {\n    tb_hize_t dynamic_offset; // file offset of .dynamic\n    tb_hize_t dynamic_size;   // size of .dynamic\n    tb_hize_t strtab_offset;  // file offset of .dynstr\n    tb_hize_t strtab_size;    // size of .dynstr\n    tb_hize_t symtab_offset;  // file offset of .symtab\n    tb_hize_t symtab_size;    // size of .symtab\n    tb_hize_t symstr_offset;  // file offset of .strtab (for .symtab)\n    tb_hize_t symstr_size;    // size of .strtab (for .symtab)\n    tb_bool_t is64;\n} xm_elf_context_t;\n\ntypedef struct __xm_elf32_header_t {\n    tb_uint8_t  e_ident[16];\n    tb_uint16_t e_type;\n    tb_uint16_t e_machine;\n    tb_uint32_t e_version;\n    tb_uint32_t e_entry;\n    tb_uint32_t e_phoff;\n    tb_uint32_t e_shoff;\n    tb_uint32_t e_flags;\n    tb_uint16_t e_ehsize;\n    tb_uint16_t e_phentsize;\n    tb_uint16_t e_phnum;\n    tb_uint16_t e_shentsize;\n    tb_uint16_t e_shnum;\n    tb_uint16_t e_shstrndx;\n} __tb_packed__ xm_elf32_header_t;\n\ntypedef struct __xm_elf32_section_t {\n    tb_uint32_t sh_name;\n    tb_uint32_t sh_type;\n    tb_uint32_t sh_flags;\n    tb_uint32_t sh_addr;\n    tb_uint32_t sh_offset;\n    tb_uint32_t sh_size;\n    tb_uint32_t sh_link;\n    tb_uint32_t sh_info;\n    tb_uint32_t sh_addralign;\n    tb_uint32_t sh_entsize;\n} __tb_packed__ xm_elf32_section_t;\n\ntypedef struct __xm_elf32_symbol_t {\n    tb_uint32_t st_name;\n    tb_uint32_t st_value;\n    tb_uint32_t st_size;\n    tb_uint8_t  st_info;\n    tb_uint8_t  st_other;\n    tb_uint16_t st_shndx;\n} __tb_packed__ xm_elf32_symbol_t;\n\ntypedef struct __xm_elf32_phdr_t {\n    tb_uint32_t p_type;\n    tb_uint32_t p_offset;\n    tb_uint32_t p_vaddr;\n    tb_uint32_t p_paddr;\n    tb_uint32_t p_filesz;\n    tb_uint32_t p_memsz;\n    tb_uint32_t p_flags;\n    tb_uint32_t p_align;\n} __tb_packed__ xm_elf32_phdr_t;\n\ntypedef struct __xm_elf64_header_t {\n    tb_uint8_t  e_ident[16];\n    tb_uint16_t e_type;\n    tb_uint16_t e_machine;\n    tb_uint32_t e_version;\n    tb_uint64_t e_entry;\n    tb_uint64_t e_phoff;\n    tb_uint64_t e_shoff;\n    tb_uint32_t e_flags;\n    tb_uint16_t e_ehsize;\n    tb_uint16_t e_phentsize;\n    tb_uint16_t e_phnum;\n    tb_uint16_t e_shentsize;\n    tb_uint16_t e_shnum;\n    tb_uint16_t e_shstrndx;\n} __tb_packed__ xm_elf64_header_t;\n\ntypedef struct __xm_elf64_section_t {\n    tb_uint32_t sh_name;\n    tb_uint32_t sh_type;\n    tb_uint64_t sh_flags;\n    tb_uint64_t sh_addr;\n    tb_uint64_t sh_offset;\n    tb_uint64_t sh_size;\n    tb_uint32_t sh_link;\n    tb_uint32_t sh_info;\n    tb_uint64_t sh_addralign;\n    tb_uint64_t sh_entsize;\n} __tb_packed__ xm_elf64_section_t;\n\ntypedef struct __xm_elf64_symbol_t {\n    tb_uint32_t st_name;\n    tb_uint8_t  st_info;\n    tb_uint8_t  st_other;\n    tb_uint16_t st_shndx;\n    tb_uint64_t st_value;\n    tb_uint64_t st_size;\n} __tb_packed__ xm_elf64_symbol_t;\n\ntypedef struct __xm_elf64_phdr_t {\n    tb_uint32_t p_type;\n    tb_uint32_t p_flags;\n    tb_uint64_t p_offset;\n    tb_uint64_t p_vaddr;\n    tb_uint64_t p_paddr;\n    tb_uint64_t p_filesz;\n    tb_uint64_t p_memsz;\n    tb_uint64_t p_align;\n} __tb_packed__ xm_elf64_phdr_t;\n\ntypedef struct __xm_elf32_dynamic_t {\n    tb_int32_t  d_tag;\n    union {\n        tb_uint32_t d_val;\n        tb_uint32_t d_ptr;\n    } d_un;\n} __tb_packed__ xm_elf32_dynamic_t;\n\ntypedef struct __xm_elf64_dynamic_t {\n    tb_int64_t  d_tag;\n    union {\n        tb_uint64_t d_val;\n        tb_uint64_t d_ptr;\n    } d_un;\n} __tb_packed__ xm_elf64_dynamic_t;\n#include \"tbox/prefix/packed.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n/* get machine type from architecture string\n *\n * @param arch    the architecture string (e.g., \"x86_64\", \"i386\", \"arm64\", \"riscv\")\n * @return        the machine type\n */\nstatic __tb_inline__ tb_uint16_t xm_binutils_elf_get_machine(tb_char_t const *arch) {\n    if (!arch) {\n        return XM_ELF_MACHINE_X86_64;\n    }\n    // x86/x86_64\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return XM_ELF_MACHINE_X86_64;\n    } else if (tb_strcmp(arch, \"i386\") == 0 || tb_strcmp(arch, \"x86\") == 0) {\n        return XM_ELF_MACHINE_I386;\n    }\n    // ARM\n    else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0 ||\n             tb_strcmp(arch, \"arm64-v8a\") == 0) {\n        return XM_ELF_MACHINE_ARM64;\n    } else if (tb_strcmp(arch, \"arm\") == 0 || tb_strcmp(arch, \"armv7\") == 0 ||\n               tb_strcmp(arch, \"armeabi-v7a\") == 0 || tb_strcmp(arch, \"armv6\") == 0 ||\n               tb_strcmp(arch, \"armv5\") == 0) {\n        return XM_ELF_MACHINE_ARM;\n    }\n    // MIPS (MIPS and MIPS64 use same machine type, distinguished by ELF class)\n    else if (tb_strncmp(arch, \"mips\", 4) == 0) {\n        return XM_ELF_MACHINE_MIPS;\n    }\n    // PowerPC\n    else if (tb_strncmp(arch, \"ppc64\", 5) == 0 || tb_strncmp(arch, \"powerpc64\", 9) == 0) {\n        return XM_ELF_MACHINE_POWERPC64;\n    } else if (tb_strncmp(arch, \"ppc\", 3) == 0 || tb_strncmp(arch, \"powerpc\", 7) == 0) {\n        return XM_ELF_MACHINE_POWERPC;\n    }\n    // RISC-V (RISC-V and RISC-V64 use different machine types)\n    else if (tb_strncmp(arch, \"riscv64\", 7) == 0 ||\n             (tb_strncmp(arch, \"riscv\", 5) == 0 && tb_strstr(arch, \"64\"))) {\n        return XM_ELF_MACHINE_RISCV; // RISC-V 64-bit uses same machine type, distinguished by ELF class\n    } else if (tb_strncmp(arch, \"riscv\", 5) == 0) {\n        return XM_ELF_MACHINE_RISCV;\n    }\n    // SPARC\n    else if (tb_strncmp(arch, \"sparc64\", 7) == 0) {\n        return XM_ELF_MACHINE_SPARC64;\n    } else if (tb_strncmp(arch, \"sparc\", 5) == 0) {\n        return XM_ELF_MACHINE_SPARC;\n    }\n    // s390x\n    else if (tb_strcmp(arch, \"s390x\") == 0 || tb_strcmp(arch, \"s390\") == 0) {\n        return XM_ELF_MACHINE_S390;\n    }\n    // LoongArch (LoongArch and LoongArch64 use same machine type, distinguished by ELF class)\n    else if (tb_strncmp(arch, \"loongarch\", 9) == 0 || tb_strncmp(arch, \"loong64\", 7) == 0) {\n        return XM_ELF_MACHINE_LOONGARCH;\n    }\n    // WebAssembly (WASM and WASM64 use same machine type, distinguished by ELF class)\n    else if (tb_strncmp(arch, \"wasm\", 4) == 0) {\n        return XM_ELF_MACHINE_WASM;\n    }\n    // SuperH\n    else if (tb_strncmp(arch, \"sh\", 2) == 0 || tb_strncmp(arch, \"superh\", 6) == 0) {\n        return XM_ELF_MACHINE_SUPERH;\n    }\n    // IA-64 (Itanium)\n    else if (tb_strcmp(arch, \"ia64\") == 0 || tb_strcmp(arch, \"itanium\") == 0) {\n        return XM_ELF_MACHINE_IA_64;\n    }\n    return XM_ELF_MACHINE_X86_64;\n}\n\n/* check if architecture is 64-bit\n *\n * @param arch    the architecture string\n * @return        tb_true if 64-bit, tb_false otherwise\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) {\n    return xm_binutils_arch_is_64bit(arch);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * readsyms inline implementation\n */\n\n/* get symbol type character (nm-style) from ELF symbol\n *\n * @param st_info  the symbol info byte\n * @param st_shndx the section index (0 = undefined)\n * @return         the type character (T/t/D/d/B/b/U)\n */\nstatic __tb_inline__ tb_char_t xm_binutils_elf_get_symbol_type_char(tb_uint8_t st_info, tb_uint16_t st_shndx) {\n    // undefined symbol\n    if (st_shndx == 0) {\n        return 'U';\n    }\n\n    // check bind (global = uppercase, local = lowercase)\n    tb_uint8_t bind = (st_info >> 4) & 0xf;\n    tb_bool_t is_global = (bind == 1); // STB_GLOBAL\n\n    // check type\n    tb_uint8_t type = st_info & 0xf;\n    if (type == 2) { // STT_FUNC\n        return is_global ? 'T' : 't';  // text (function)\n    } else if (type == 1) { // STT_OBJECT\n        // For object symbols, we need section info to determine data/bss\n        // For simplicity, we'll use 'D' for data, 'B' for bss\n        // This is a heuristic - in practice, we'd need to check section flags\n        return is_global ? 'D' : 'd';  // data (assume data section)\n    }\n\n    // other types\n    return is_global ? 'S' : 's';  // other section\n}\n\n/* get symbol bind string from ELF symbol info\n *\n * @param st_info the symbol info byte\n * @return         the bind string\n */\nstatic __tb_inline__ tb_char_t const *xm_binutils_elf_get_symbol_bind(tb_uint8_t st_info) {\n    tb_uint8_t bind = (st_info >> 4) & 0xf;\n    switch (bind) {\n    case 0: return \"local\";\n    case 1: return \"global\";\n    case 2: return \"weak\";\n    default: return \"unknown\";\n    }\n}\n\n// read ELF header (32-bit)\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_read_header_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t* header) {\n    if (!tb_stream_seek(istream, base_offset)) return tb_false;\n    if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false;\n    return tb_true;\n}\n\n// read ELF header (64-bit)\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_read_header_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t* header) {\n    if (!tb_stream_seek(istream, base_offset)) return tb_false;\n    if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false;\n    return tb_true;\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_get_context_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {\n    tb_memset(ctx, 0, sizeof(xm_elf_context_t));\n    ctx->is64 = tb_false;\n\n    // read ELF header\n    xm_elf32_header_t header;\n    if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) return tb_false;\n\n    // try to find from section headers first\n    if (header.e_shoff != 0 && header.e_shnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header.e_shoff)) {\n            for (tb_uint16_t i = 0; i < header.e_shnum; i++) {\n                xm_elf32_section_t section;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&section, sizeof(section))) break;\n\n                if (section.sh_type == XM_ELF_SHT_DYNAMIC) {\n                    ctx->dynamic_offset = section.sh_offset;\n                    ctx->dynamic_size = section.sh_size;\n\n                    // find string table via sh_link\n                    xm_elf32_section_t strtab_section;\n                    if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) &&\n                        tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {\n                        ctx->strtab_offset = strtab_section.sh_offset;\n                        ctx->strtab_size = strtab_section.sh_size;\n                    }\n                } else if (section.sh_type == XM_ELF_SHT_SYMTAB) {\n                    ctx->symtab_offset = section.sh_offset;\n                    ctx->symtab_size = section.sh_size;\n                    xm_elf32_section_t symstr_section;\n                    if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) &&\n                        tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) {\n                        ctx->symstr_offset = symstr_section.sh_offset;\n                        ctx->symstr_size = symstr_section.sh_size;\n                    }\n                }\n            }\n        }\n    }\n\n    // fallback to program headers\n    if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header.e_phoff)) {\n            for (tb_uint16_t i = 0; i < header.e_phnum; i++) {\n                xm_elf32_phdr_t phdr;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                if (phdr.p_type == XM_ELF_PT_DYNAMIC) {\n                    ctx->dynamic_offset = phdr.p_offset;\n                    ctx->dynamic_size = phdr.p_memsz;\n                    break;\n                }\n            }\n        }\n\n        if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) {\n            // read dynamic entries to find strtab address and size\n            tb_uint64_t strtab_vaddr = 0;\n            tb_uint64_t strtab_sz = 0;\n            tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf32_dynamic_t));\n            if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {\n                for (tb_uint32_t i = 0; i < count; i++) {\n                    xm_elf32_dynamic_t dyn;\n                    if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;\n                    if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val;\n                    else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val;\n                }\n            }\n\n            if (strtab_vaddr > 0) {\n                // map strtab vaddr to file offset using PT_LOAD\n                if (tb_stream_seek(istream, base_offset + header.e_phoff)) {\n                    for (tb_uint16_t i = 0; i < header.e_phnum; i++) {\n                        xm_elf32_phdr_t phdr;\n                        if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                        if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) {\n                            ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr);\n                            ctx->strtab_size = strtab_sz;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0);\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_get_context_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {\n    tb_memset(ctx, 0, sizeof(xm_elf_context_t));\n    ctx->is64 = tb_true;\n\n    // read ELF header\n    xm_elf64_header_t header;\n    if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) return tb_false;\n\n    // try to find from section headers first\n    if (header.e_shoff != 0 && header.e_shnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header.e_shoff)) {\n            for (tb_uint16_t i = 0; i < header.e_shnum; i++) {\n                xm_elf64_section_t section;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&section, sizeof(section))) break;\n\n                if (section.sh_type == XM_ELF_SHT_DYNAMIC) {\n                    ctx->dynamic_offset = section.sh_offset;\n                    ctx->dynamic_size = section.sh_size;\n\n                    // find string table via sh_link\n                    xm_elf64_section_t strtab_section;\n                    if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) &&\n                        tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {\n                        ctx->strtab_offset = strtab_section.sh_offset;\n                        ctx->strtab_size = strtab_section.sh_size;\n                    }\n                } else if (section.sh_type == XM_ELF_SHT_SYMTAB) {\n                    ctx->symtab_offset = section.sh_offset;\n                    ctx->symtab_size = section.sh_size;\n                    xm_elf64_section_t symstr_section;\n                    if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) &&\n                        tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) {\n                        ctx->symstr_offset = symstr_section.sh_offset;\n                        ctx->symstr_size = symstr_section.sh_size;\n                    }\n                }\n            }\n        }\n    }\n\n    // fallback to program headers\n    if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header.e_phoff)) {\n            for (tb_uint16_t i = 0; i < header.e_phnum; i++) {\n                xm_elf64_phdr_t phdr;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                if (phdr.p_type == XM_ELF_PT_DYNAMIC) {\n                    ctx->dynamic_offset = phdr.p_offset;\n                    ctx->dynamic_size = phdr.p_memsz;\n                    break;\n                }\n            }\n        }\n\n        if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) {\n            // read dynamic entries to find strtab address and size\n            tb_uint64_t strtab_vaddr = 0;\n            tb_uint64_t strtab_sz = 0;\n            tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf64_dynamic_t));\n            if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {\n                for (tb_uint32_t i = 0; i < count; i++) {\n                    xm_elf64_dynamic_t dyn;\n                    if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;\n                    if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val;\n                    else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val;\n                }\n            }\n\n            if (strtab_vaddr > 0) {\n                // map strtab vaddr to file offset using PT_LOAD\n                if (tb_stream_seek(istream, base_offset + header.e_phoff)) {\n                    for (tb_uint16_t i = 0; i < header.e_phnum; i++) {\n                        xm_elf64_phdr_t phdr;\n                        if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                        if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) {\n                            ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr);\n                            ctx->strtab_size = strtab_sz;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0);\n}\n\n\n// find PT_INTERP and read interpreter path (32-bit)\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t const* header, tb_char_t* name, tb_size_t size) {\n    if (header->e_phoff != 0 && header->e_phnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header->e_phoff)) {\n            for (tb_uint16_t i = 0; i < header->e_phnum; i++) {\n                xm_elf32_phdr_t phdr;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                if (phdr.p_type == XM_ELF_PT_INTERP) {\n                    return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0];\n                }\n            }\n        }\n    }\n    return tb_false;\n}\n\n// find PT_INTERP and read interpreter path (64-bit)\nstatic __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t const* header, tb_char_t* name, tb_size_t size) {\n    if (header->e_phoff != 0 && header->e_phnum > 0) {\n        if (tb_stream_seek(istream, base_offset + header->e_phoff)) {\n            for (tb_uint16_t i = 0; i < header->e_phnum; i++) {\n                xm_elf64_phdr_t phdr;\n                if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;\n                if (phdr.p_type == XM_ELF_PT_INTERP) {\n                    return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0];\n                }\n            }\n        }\n    }\n    return tb_false;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/elf/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readsyms_elf\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\ntb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // build context and ensure .symtab/.strtab are available\n    xm_elf_context_t ctx;\n    xm_binutils_elf_get_context_32(istream, base_offset, &ctx);\n\n    if (!ctx.symtab_offset || !ctx.symstr_offset) {\n        // no symbol table present: return empty result\n        lua_newtable(lua);\n        return tb_true;\n    }\n\n    // create result table\n    lua_newtable(lua);\n\n    // compute symbol count and seek to .symtab\n    tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf32_symbol_t));\n    if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) {\n        return tb_false;\n    }\n\n    tb_uint32_t result_count = 0;\n    for (tb_uint32_t i = 0; i < sym_count; i++) {\n        xm_elf32_symbol_t sym;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {\n            return tb_false;\n        }\n\n        // skip NULL symbol entries\n        if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {\n            continue;\n        }\n\n        // skip section/file symbols\n        tb_uint8_t type = sym.st_info & 0xf;\n        if (type == 3 || type == 4) {\n            continue;\n        }\n\n        // read symbol name from .strtab\n        tb_char_t name[256];\n        if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) {\n            continue;\n        }\n\n        // skip internal ('.', '$') and local-defined symbols\n        if (name[0] == '.' || name[0] == '$') {\n            continue;\n        }\n\n        tb_uint8_t bind = (sym.st_info >> 4) & 0xf;\n        if (bind == 0 && sym.st_shndx != 0) {\n            continue;\n        }\n\n        // push symbol entry: name + nm-style type\n        lua_pushinteger(lua, result_count + 1);\n        lua_newtable(lua);\n\n        lua_pushstring(lua, \"name\");\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n\n        tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx);\n        tb_char_t type_str[2] = {type_char, '\\0'};\n        lua_pushstring(lua, \"type\");\n        lua_pushstring(lua, type_str);\n        lua_settable(lua, -3);\n\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    return tb_true;\n}\n\ntb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // build context and ensure .symtab/.strtab are available\n    xm_elf_context_t ctx;\n    xm_binutils_elf_get_context_64(istream, base_offset, &ctx);\n\n    if (!ctx.symtab_offset || !ctx.symstr_offset) {\n        // no symbol table present: return empty result\n        lua_newtable(lua);\n        return tb_true;\n    }\n\n    // create result table\n    lua_newtable(lua);\n\n    // compute symbol count and seek to .symtab\n    tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf64_symbol_t));\n    if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) {\n        return tb_false;\n    }\n\n    tb_uint32_t result_count = 0;\n    for (tb_uint32_t i = 0; i < sym_count; i++) {\n        xm_elf64_symbol_t sym;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {\n            return tb_false;\n        }\n\n        // skip NULL symbol entries\n        if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {\n            continue;\n        }\n\n        // skip section/file symbols\n        tb_uint8_t type = sym.st_info & 0xf;\n        if (type == 3 || type == 4) {\n            continue;\n        }\n\n        // read symbol name from .strtab\n        tb_char_t name[256];\n        if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) {\n            continue;\n        }\n\n        // skip internal ('.', '$') and local-defined symbols\n        if (name[0] == '.' || name[0] == '$') {\n            continue;\n        }\n\n        tb_uint8_t bind = (sym.st_info >> 4) & 0xf;\n        if (bind == 0 && sym.st_shndx != 0) {\n            continue;\n        }\n\n        // push symbol entry: name + nm-style type\n        lua_pushinteger(lua, result_count + 1);\n        lua_newtable(lua);\n\n        lua_pushstring(lua, \"name\");\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n\n        tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx);\n        tb_char_t type_str[2] = {type_char, '\\0'};\n        lua_pushstring(lua, \"type\");\n        lua_pushstring(lua, type_str);\n        lua_settable(lua, -3);\n\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    return tb_true;\n}\n\ntb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // read and check ELF magic\n    tb_uint8_t magic[4];\n    if (!tb_stream_seek(istream, base_offset)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, magic, 4)) {\n        return tb_false;\n    }\n    if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {\n        return tb_false;\n    }\n\n    // check ELF class (32-bit or 64-bit)\n    tb_uint8_t elf_class;\n    if (!tb_stream_seek(istream, base_offset + 4)) {\n        return tb_false;\n    }\n    if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) {\n        return tb_false;\n    }\n\n    if (elf_class == 1) {\n        return xm_binutils_elf_read_symbols_32(istream, base_offset, lua);\n    } else if (elf_class == 2) {\n        return xm_binutils_elf_read_symbols_64(istream, base_offset, lua);\n    }\n\n    return tb_false;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/elf/rpath.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rpath.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rpath_elf\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_binutils_elf_add_rpaths(lua_State *lua, tb_char_t const* rpath, tb_size_t* pcount) {\n    if (!rpath || !*rpath) return;\n\n    tb_char_t path[TB_PATH_MAXN];\n    tb_char_t const* p = rpath;\n    tb_char_t const* e = tb_null;\n    while (*p) {\n        e = tb_strchr(p, ':');\n        tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p);\n        if (n > 0) {\n            if (n > sizeof(path) - 1) n = sizeof(path) - 1;\n            tb_strncpy(path, p, n);\n            path[n] = '\\0';\n            \n            lua_pushinteger(lua, *pcount + 1);\n            lua_pushstring(lua, path);\n            lua_settable(lua, -3);\n            (*pcount)++;\n        }\n        if (e) p = e + 1;\n        else break;\n    }\n}\n\n// parse .dynamic section and read DT_RPATH/DT_RUNPATH to build rpath list\nstatic tb_bool_t xm_binutils_elf_rpath_list_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx, lua_State *lua) {\n    tb_bool_t ok = tb_false;\n    do {\n        tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t)));\n        if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break;\n\n        tb_char_t rpath[8192] = {0};\n        tb_char_t runpath[8192] = {0};\n\n        // scan dynamic entries\n        for (tb_uint32_t i = 0; i < count; i++) {\n            tb_hize_t val = 0;\n            tb_hize_t tag = 0;\n            \n            if (ctx->is64) {\n                 xm_elf64_dynamic_t dyn;\n                 if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;\n                 tag = dyn.d_tag;\n                 val = dyn.d_un.d_val;\n            } else {\n                 xm_elf32_dynamic_t dyn;\n                 if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;\n                 tag = dyn.d_tag;\n                 val = dyn.d_un.d_val;\n            }\n\n            if (tag == XM_ELF_DT_NULL) break;\n            // read rpath/runpath string from strtab\n            if (tag == XM_ELF_DT_RPATH) {\n                 xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, rpath, sizeof(rpath));\n            } else if (tag == XM_ELF_DT_RUNPATH) {\n                 xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, runpath, sizeof(runpath));\n            }\n        }\n\n        // split rpath(s) and push into Lua table\n        tb_size_t result_count = 0;\n        if (runpath[0]) {\n            xm_binutils_elf_add_rpaths(lua, runpath, &result_count);\n        } else if (rpath[0]) {\n            xm_binutils_elf_add_rpaths(lua, rpath, &result_count);\n        }\n        ok = tb_true;\n    } while (0);\n    return ok;\n}\n\n// remove DT_RPATH/DT_RUNPATH entries from .dynamic and write back\nstatic tb_bool_t xm_binutils_elf_rpath_clean_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {\n    tb_bool_t ok = tb_false;\n    tb_byte_t* buffer = tb_null;\n    do {\n        tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t)));\n        \n        // allocate buffer for all dynamic entries\n        tb_size_t dyn_size = (tb_size_t)ctx->dynamic_size;\n        buffer = (tb_byte_t*)tb_malloc(dyn_size);\n        if (!buffer) break;\n\n        if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break;\n        if (!tb_stream_bread(istream, buffer, dyn_size)) break;\n\n        // p: read pointer, w: write pointer after filtering\n        tb_byte_t* p = buffer;\n        tb_byte_t* w = buffer;\n        tb_size_t entry_size = ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t);\n        \n        for (tb_uint32_t i = 0; i < count; i++) {\n            tb_hize_t tag = 0;\n            if (ctx->is64) {\n                 tag = ((xm_elf64_dynamic_t*)p)->d_tag;\n            } else {\n                 tag = ((xm_elf32_dynamic_t*)p)->d_tag;\n            }\n\n            if (tag == XM_ELF_DT_NULL) {\n                // copy NULL entry and stop\n                tb_memcpy(w, p, entry_size);\n                w += entry_size;\n                p += entry_size;\n                break;\n            }\n\n            // keep entries except rpath/runpath\n            if (tag != XM_ELF_DT_RPATH && tag != XM_ELF_DT_RUNPATH) {\n                if (w != p) tb_memcpy(w, p, entry_size);\n                w += entry_size;\n            }\n            p += entry_size;\n        }\n\n        // fill remaining with NULLs\n        if (w < buffer + dyn_size) {\n            tb_memset(w, 0, (buffer + dyn_size) - w);\n        }\n\n        // write back\n        if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {\n            tb_stream_bwrit(istream, buffer, dyn_size);\n        }\n\n        ok = tb_true;\n    } while (0);\n\n    if (buffer) tb_free(buffer);\n    return ok;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    tb_bool_t ok = tb_false;\n    do {\n        // read ident\n        tb_byte_t ident[16];\n        if (!tb_stream_seek(istream, base_offset)) break;\n        if (!tb_stream_bread(istream, ident, sizeof(ident))) break;\n\n        // build ELF context (dynamic, strtab offsets)\n        xm_elf_context_t ctx;\n        if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) {\n            if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {\n                if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true;\n            }\n        } else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) {\n            if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {\n                if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true;\n            }\n        }\n    } while (0);\n    return ok;\n}\n\ntb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) {\n    tb_assert_and_check_return_val(istream, tb_false);\n\n    tb_bool_t ok = tb_false;\n    do {\n        // read ident\n        tb_byte_t ident[16];\n        if (!tb_stream_seek(istream, base_offset)) break;\n        if (!tb_stream_bread(istream, ident, sizeof(ident))) break;\n\n        // build ELF context and cleanup rpath entries\n        xm_elf_context_t ctx;\n        if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) {\n            if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {\n                if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true;\n            }\n        } else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) {\n            if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {\n                if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true;\n            }\n        }\n    } while (0);\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/extractlib.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        extractlib.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"extractlib\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"ar/prefix.h\"\n#include \"mslib/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * forward declarations\n */\nextern tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir);\nextern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* extract static library to directory (Lua interface)\n * Supports AR format (.a) and MSVC lib format (.lib)\n *\n * @param lua the lua state\n *\n * libraryfile = lua[1]\n * outputdir   = lua[2]\n * plain       = lua[3] (optional, default: true)\n *\n * @return 1 on success, 2 on failure (with error message)\n */\ntb_int_t xm_binutils_extractlib(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the library file path\n    tb_char_t const *libraryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(libraryfile, 0);\n\n    // get the output directory\n    tb_char_t const *outputdir = luaL_checkstring(lua, 2);\n    tb_check_return_val(outputdir, 0);\n\n    // get the plain mode (optional)\n    tb_bool_t plain = tb_true;\n    if (lua_gettop(lua) >= 3 && !lua_isnil(lua, 3)) {\n        plain = lua_toboolean(lua, 3);\n    }\n\n    // open library file\n    tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO);\n    if (!istream) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"open %s failed\", libraryfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    tb_char_t const* error_msg = tb_null;\n    do {\n        if (!tb_stream_open(istream)) {\n            error_msg = \"open failed\";\n            break;\n        }\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            error_msg = \"cannot detect format\";\n            break;\n        }\n\n        // extract based on format\n        if (format == XM_BINUTILS_FORMAT_AR) {\n            // AR archive format (.a or .lib in AR format)\n            // if the file extension is .lib, we use the msvc lib extractor to support long paths and subdirectories\n            tb_size_t n = tb_strlen(libraryfile);\n            if (n > 4 && !tb_strnicmp(libraryfile + n - 4, \".lib\", 4)) {\n                if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {\n                    error_msg = \"extract MSVC lib failed\";\n                    break;\n                }\n            } else {\n                if (!xm_binutils_ar_extract(istream, outputdir)) {\n                    error_msg = \"extract AR archive failed\";\n                    break;\n                }\n            }\n            ok = tb_true;\n        } else if (format == XM_BINUTILS_FORMAT_COFF) {\n            // MSVC lib format (.lib in COFF format)\n            // Check if it's actually a library (not just a single object file)\n            // MSVC lib files can be:\n            // 1. Import libraries (different format)\n            // 2. Static libraries (COFF archive format, similar to AR but different)\n            if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {\n                error_msg = \"extract MSVC lib failed\";\n                break;\n            }\n            ok = tb_true;\n        } else {\n            error_msg = \"unsupported format (only AR and MSVC lib are supported)\";\n            break;\n        }\n\n    } while (0);\n\n    if (istream) {\n        tb_stream_clos(istream);\n        tb_stream_exit(istream);\n    }\n\n    if (ok) {\n        lua_pushboolean(lua, tb_true);\n        return 1;\n    } else {\n        lua_pushboolean(lua, tb_false);\n        if (error_msg) {\n             lua_pushfstring(lua, \"%s %s\", error_msg, libraryfile);\n        } else {\n             lua_pushfstring(lua, \"unknown error for %s\", libraryfile);\n        }\n        return 2;\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/format.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        format.c\n *\n */\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"format\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n/* check PE by validating DOS header (MZ/ZM) and PE signature at e_lfanew\n *\n * note: unlike ELF/Mach-O/AR, PE needs an additional read/peek to locate the PE signature.\n */\nstatic tb_bool_t xm_binutils_format_is_pe(tb_stream_ref_t istream, tb_byte_t* first8) {\n    tb_assert_and_check_return_val(istream && first8, tb_false);\n    tb_bool_t ok = tb_false;\n    do {\n        // fast reject: DOS magic\n        tb_check_break((first8[0] == 'M' && first8[1] == 'Z') || (first8[0] == 'Z' && first8[1] == 'M'));\n\n        // ensure we can read enough for DOS stub + PE signature\n        tb_hong_t size = tb_stream_size(istream);\n        if (size > 0 && size < XM_BINUTILS_PE_DOS_STUB_MIN_SIZE + 4) {\n            break;\n        }\n\n        // peek a bounded prefix to locate e_lfanew and PE\\\\0\\\\0 signature\n        tb_size_t max_peek = 4096;\n        if (size > 0) {\n            max_peek = (tb_size_t)tb_min((tb_hize_t)max_peek, (tb_hize_t)size);\n        }\n\n        tb_byte_t* p = tb_null;\n        if (!tb_stream_peek(istream, &p, max_peek)) {\n            break;\n        }\n\n        // e_lfanew points to PE signature offset\n        tb_uint32_t e_lfanew = tb_bits_get_u32_le(p + XM_BINUTILS_PE_DOS_ELFANEW_OFFSET);\n        tb_check_break(e_lfanew >= XM_BINUTILS_PE_DOS_STUB_MIN_SIZE);\n        tb_check_break((tb_size_t)e_lfanew + 4 <= max_peek);\n        tb_check_break(size <= 0 || (tb_hize_t)e_lfanew + 4 <= (tb_hize_t)size);\n\n        tb_byte_t const* signature = p + (tb_size_t)e_lfanew;\n        ok = (signature[0] == 'P' && signature[1] == 'E' && signature[2] == 0 && signature[3] == 0);\n    } while (0);\n\n    return ok;\n}\n\n// quick header checks from the first 8 bytes\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_ar(tb_byte_t const* first8) {\n    return first8[0] == '!' && first8[1] == '<' && first8[2] == 'a' &&\n           first8[3] == 'r' && first8[4] == 'c' && first8[5] == 'h' &&\n           (first8[6] == '>' || first8[6] == '\\n') &&\n           (first8[7] == '\\n' || first8[7] == '\\r');\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_shebang(tb_byte_t const* first2) {\n    return first2[0] == '#' && first2[1] == '!';\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_ape(tb_byte_t const* first8) {\n    return first8[0] == 'M' && first8[1] == 'Z' &&\n           first8[2] == 'q' && first8[3] == 'F' &&\n           first8[4] == 'p' && first8[5] == 'D';\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_wasm(tb_byte_t const* first8) {\n    return first8[0] == 0x00 && first8[1] == 0x61 && first8[2] == 0x73 && first8[3] == 0x6d;\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_elf(tb_byte_t const* first8) {\n    return first8[0] == 0x7f && first8[1] == 'E' && first8[2] == 'L' && first8[3] == 'F';\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_macho(tb_byte_t const* first8) {\n    return (first8[0] == 0xfe && first8[1] == 0xed && first8[2] == 0xfa && (first8[3] == 0xce || first8[3] == 0xcf)) ||\n           (first8[0] == 0xce && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe) ||\n           (first8[0] == 0xcf && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe);\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_format_is_coff(tb_byte_t const* first8) {\n    tb_uint16_t machine = tb_bits_get_u16_le(first8);\n    if (machine == 0x0000) {\n        tb_uint16_t machine2 = tb_bits_get_u16_le(first8 + 2);\n        if (machine2 == 0xffff) {\n            return tb_true;\n        }\n    }\n\n    return machine == XM_BINUTILS_COFF_MACHINE_I386 ||\n           machine == XM_BINUTILS_COFF_MACHINE_AMD64 ||\n           machine == XM_BINUTILS_COFF_MACHINE_ARM ||\n           machine == XM_BINUTILS_COFF_MACHINE_ARM64;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* detect object file format from stream\n *\n * @param istream the input stream\n * @return        XM_BINUTILS_FORMAT_COFF, XM_BINUTILS_FORMAT_ELF, XM_BINUTILS_FORMAT_MACHO,\n *                XM_BINUTILS_FORMAT_AR, XM_BINUTILS_FORMAT_PE, XM_BINUTILS_FORMAT_UNKNOWN, or -1 on error\n */\ntb_int_t xm_binutils_format_detect(tb_stream_ref_t istream) {\n    tb_assert_and_check_return_val(istream, -1);\n    tb_assert_and_check_return_val(tb_stream_offset(istream) == 0, -1);\n\n    tb_int_t format = -1;\n    do {\n        tb_byte_t* p2 = tb_null;\n        if (!tb_stream_peek(istream, &p2, 2)) {\n            tb_hong_t size = tb_stream_size(istream);\n            if (size > 0 && size < 2) {\n                format = XM_BINUTILS_FORMAT_UNKNOWN;\n            }\n            break;\n        }\n        if (xm_binutils_format_is_shebang(p2)) {\n            format = XM_BINUTILS_FORMAT_SHEBANG;\n            break;\n        }\n\n        tb_byte_t* p = tb_null;\n        if (!tb_stream_peek(istream, &p, 8)) {\n            tb_hong_t size = tb_stream_size(istream);\n            if (size > 0 && size < 8) {\n                format = XM_BINUTILS_FORMAT_UNKNOWN;\n            }\n            break;\n        }\n\n        if (xm_binutils_format_is_ar(p)) {\n            format = XM_BINUTILS_FORMAT_AR;\n            break;\n        }\n\n        if (xm_binutils_format_is_ape(p)) {\n            format = XM_BINUTILS_FORMAT_APE;\n            break;\n        }\n\n        if (xm_binutils_format_is_wasm(p)) {\n            format = XM_BINUTILS_FORMAT_WASM;\n            break;\n        }\n\n        if (xm_binutils_format_is_elf(p)) {\n            format = XM_BINUTILS_FORMAT_ELF;\n            break;\n        }\n\n        if (xm_binutils_format_is_macho(p)) {\n            format = XM_BINUTILS_FORMAT_MACHO;\n            break;\n        }\n\n        if (xm_binutils_format_is_pe(istream, p)) {\n            format = XM_BINUTILS_FORMAT_PE;\n            break;\n        }\n\n        if (xm_binutils_format_is_coff(p)) {\n            format = XM_BINUTILS_FORMAT_COFF;\n            break;\n        }\n\n        format = XM_BINUTILS_FORMAT_UNKNOWN;\n\n    } while (0);\n\n    return format;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * lua implementation\n */\n\n/* get binary file format (auto-detect format)\n *\n * local format, errors = binutils.format(filepath)\n */\ntb_int_t xm_binutils_format(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binary file path\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // open file\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    if (!istream) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"open %s failed\", binaryfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"open %s failed\", binaryfile);\n            break;\n        }\n\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            lua_pushnil(lua);\n            lua_pushliteral(lua, \"cannot detect file format\");\n            break;\n        }\n\n        switch (format) {\n        case XM_BINUTILS_FORMAT_COFF:  lua_pushliteral(lua, \"coff\"); break;\n        case XM_BINUTILS_FORMAT_ELF:   lua_pushliteral(lua, \"elf\"); break;\n        case XM_BINUTILS_FORMAT_MACHO: lua_pushliteral(lua, \"macho\"); break;\n        case XM_BINUTILS_FORMAT_AR:    lua_pushliteral(lua, \"ar\"); break;\n        case XM_BINUTILS_FORMAT_PE:    lua_pushliteral(lua, \"pe\"); break;\n        case XM_BINUTILS_FORMAT_SHEBANG: lua_pushliteral(lua, \"shebang\"); break;\n        case XM_BINUTILS_FORMAT_APE:   lua_pushliteral(lua, \"ape\"); break;\n        case XM_BINUTILS_FORMAT_WASM:  lua_pushliteral(lua, \"wasm\"); break;\n        default:                       lua_pushliteral(lua, \"unknown\"); break;\n        }\n\n        ok = tb_true;\n    } while (0);\n\n    if (istream) {\n        tb_stream_exit(istream);\n    }\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/macho/bin2macho.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bin2macho.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bin2macho\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t xm_binutils_bin2macho_dump_64(tb_stream_ref_t istream,\n                                             tb_stream_ref_t ostream,\n                                             tb_char_t const *symbol_prefix,\n                                             tb_char_t const *plat,\n                                             tb_char_t const *arch,\n                                             tb_char_t const *basename,\n                                             tb_uint32_t minos,\n                                             tb_uint32_t sdk,\n                                             tb_bool_t zeroend) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n\n    // get file size\n    tb_hong_t filesize = tb_stream_size(istream);\n    if (filesize < 0 || filesize > 0xffffffffU) {\n        return tb_false;\n    }\n    tb_uint32_t datasize = (tb_uint32_t)filesize;\n    // add null terminator if zeroend is true\n    if (zeroend) {\n        if (datasize >= 0xffffffffU) {\n            return tb_false; // would overflow\n        }\n        datasize++;\n    }\n\n    // generate symbol names from filename\n    tb_char_t symbol_name[256] = {0};\n    tb_char_t symbol_start[256] = {0};\n    tb_char_t symbol_end[256] = {0};\n\n    // use basename or default to \"data\"\n    if (!basename || !basename[0]) {\n        basename = \"data\";\n    }\n\n    // build symbol name\n    // On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores\n    // (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx)\n    if (symbol_prefix) {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"_%s%s\", symbol_prefix, basename);\n    } else {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"__binary_%s\", basename);\n    }\n\n    // replace non-alphanumeric with underscore\n    xm_binutils_sanitize_symbol_name(symbol_name);\n\n    tb_snprintf(symbol_start, sizeof(symbol_start), \"%s_start\", symbol_name);\n    tb_snprintf(symbol_end, sizeof(symbol_end), \"%s_end\", symbol_name);\n\n    // calculate offsets\n    tb_uint32_t header_size = sizeof(xm_macho_header_64_t);\n    tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_64_t);\n    tb_uint32_t section_size = sizeof(xm_macho_section_64_t);\n    tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t);\n    tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t);\n    tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size;\n    tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 8);\n    tb_uint32_t data_size = datasize;\n    tb_uint32_t data_end_offset = data_offset + data_size;\n    tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 8);\n    tb_uint32_t nlist_size = sizeof(xm_macho_nlist_64_t);\n    tb_uint32_t nlist_count = 2; // start, end\n    tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count;\n    tb_uint32_t strtab_size = 4; // initial 4-byte size field\n    tb_size_t start_len = tb_strlen(symbol_start);\n    tb_size_t end_len = tb_strlen(symbol_end);\n    strtab_size += (tb_uint32_t)(start_len + 1);\n    strtab_size += (tb_uint32_t)(end_len + 1);\n    strtab_size = xm_binutils_macho_align(strtab_size, 8);\n\n    // write Mach-O header\n    xm_macho_header_64_t header;\n    tb_memset(&header, 0, sizeof(header));\n    header.magic = XM_MACHO_MAGIC_64;\n    header.cputype = xm_binutils_macho_get_cputype(arch);\n    header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch);\n    header.filetype = XM_MACHO_FILE_TYPE_OBJECT;\n    header.ncmds = 3; // segment + symtab + build_version\n    header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size;\n    header.flags = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // write segment command\n    xm_macho_segment_command_64_t segment;\n    tb_memset(&segment, 0, sizeof(segment));\n    segment.cmd = XM_MACHO_LC_SEGMENT_64;\n    segment.cmdsize = segment_cmd_total_size;\n    tb_strncpy(segment.segname, \"__TEXT\", 16);\n    segment.vmaddr = 0;\n    segment.vmsize = data_size;\n    segment.fileoff = data_offset;\n    segment.filesize = data_size;\n    segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)\n    segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)\n    segment.nsects = 1;\n    segment.flags = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) {\n        return tb_false;\n    }\n\n    // write section\n    xm_macho_section_64_t section;\n    tb_memset(&section, 0, sizeof(section));\n    tb_strncpy(section.sectname, \"__const\", 16);\n    tb_strncpy(section.segname, \"__TEXT\", 16);\n    section.addr = 0;\n    section.size = data_size;\n    section.offset = data_offset;\n    section.align = 3; // 2^3 = 8 bytes\n    section.reloff = 0;\n    section.nreloc = 0;\n    section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section, sizeof(section))) {\n        return tb_false;\n    }\n\n    // write symtab command\n    xm_macho_symtab_command_t symtab;\n    tb_memset(&symtab, 0, sizeof(symtab));\n    symtab.cmd = XM_MACHO_LC_SYMTAB;\n    symtab.cmdsize = symtab_cmd_size;\n    symtab.symoff = symtab_offset;\n    symtab.nsyms = nlist_count;\n    symtab.stroff = strtab_offset;\n    symtab.strsize = strtab_size;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) {\n        return tb_false;\n    }\n\n    // write build version command\n    xm_macho_build_version_command_t build_version;\n    tb_memset(&build_version, 0, sizeof(build_version));\n    build_version.cmd = XM_MACHO_LC_BUILD_VERSION;\n    build_version.cmdsize = build_version_cmd_size;\n    build_version.platform = xm_binutils_macho_get_platform(plat);\n    build_version.minos = minos;\n    build_version.sdk = sdk;\n    build_version.ntools = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) {\n        return tb_false;\n    }\n\n    // align to 8 bytes\n    tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write section data\n    if (!xm_binutils_stream_copy(istream, ostream, filesize)) {\n        return tb_false;\n    }\n    // append null terminator if zeroend is true\n    if (zeroend) {\n        tb_byte_t zero = 0;\n        if (!tb_stream_bwrit(ostream, &zero, 1)) {\n            return tb_false;\n        }\n    }\n\n    // align to 8 bytes\n    padding = symtab_offset - data_end_offset;\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write symbol table\n    // strx starts from 4 (after 4-byte size field)\n    tb_uint32_t strx = 4;\n    // symbol 0: _binary_xxx_start\n    xm_macho_nlist_64_t nlist_start;\n    tb_memset(&nlist_start, 0, sizeof(nlist_start));\n    nlist_start.strx = strx;\n    nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT\n    nlist_start.sect = 1;\n    nlist_start.desc = 0;\n    nlist_start.value = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) {\n        return tb_false;\n    }\n    strx += (tb_uint32_t)(start_len + 1);\n\n    // symbol 1: _binary_xxx_end\n    xm_macho_nlist_64_t nlist_end;\n    tb_memset(&nlist_end, 0, sizeof(nlist_end));\n    nlist_end.strx = strx;\n    nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT\n    nlist_end.sect = 1;\n    nlist_end.desc = 0;\n    nlist_end.value = data_size;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) {\n        return tb_false;\n    }\n    strx += (tb_uint32_t)(end_len + 1);\n\n    // align to 8 bytes\n    padding = strtab_offset - (symtab_offset + nlist_size * nlist_count);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write string table\n    tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4);\n    tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len);\n    tb_byte_t null = 0;\n    tb_stream_bwrit(ostream, &null, 1);\n    tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len);\n    tb_stream_bwrit(ostream, &null, 1);\n\n    // align string table to 8 bytes\n    padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    return tb_true;\n}\n\nstatic tb_bool_t xm_binutils_bin2macho_dump_32(tb_stream_ref_t istream,\n                                             tb_stream_ref_t ostream,\n                                             tb_char_t const *symbol_prefix,\n                                             tb_char_t const *plat,\n                                             tb_char_t const *arch,\n                                             tb_char_t const *basename,\n                                             tb_uint32_t minos,\n                                             tb_uint32_t sdk,\n                                             tb_bool_t zeroend) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n\n    // get file size\n    tb_hong_t filesize = tb_stream_size(istream);\n    if (filesize < 0 || filesize > 0xffffffffU) {\n        return tb_false;\n    }\n    tb_uint32_t datasize = (tb_uint32_t)filesize;\n    // add null terminator if zeroend is true\n    if (zeroend) {\n        if (datasize >= 0xffffffffU) {\n            return tb_false; // would overflow\n        }\n        datasize++;\n    }\n\n    // generate symbol names from filename\n    tb_char_t symbol_name[256] = {0};\n    tb_char_t symbol_start[256] = {0};\n    tb_char_t symbol_end[256] = {0};\n\n    // use basename or default to \"data\"\n    if (!basename || !basename[0]) {\n        basename = \"data\";\n    }\n\n    // build symbol name\n    // On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores\n    // (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx)\n    if (symbol_prefix) {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"_%s%s\", symbol_prefix, basename);\n    } else {\n        tb_snprintf(symbol_name, sizeof(symbol_name), \"__binary_%s\", basename);\n    }\n\n    // replace non-alphanumeric with underscore\n    xm_binutils_sanitize_symbol_name(symbol_name);\n\n    tb_snprintf(symbol_start, sizeof(symbol_start), \"%s_start\", symbol_name);\n    tb_snprintf(symbol_end, sizeof(symbol_end), \"%s_end\", symbol_name);\n\n    // calculate offsets\n    tb_uint32_t header_size = sizeof(xm_macho_header_32_t);\n    tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_t);\n    tb_uint32_t section_size = sizeof(xm_macho_section_t);\n    tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t);\n    tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t);\n    tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size;\n    tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 4);\n    tb_uint32_t data_size = datasize;\n    tb_uint32_t data_end_offset = data_offset + data_size;\n    tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 4);\n    tb_uint32_t nlist_size = sizeof(xm_macho_nlist_t);\n    tb_uint32_t nlist_count = 2; // start, end\n    tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count;\n    tb_uint32_t strtab_size = 4; // initial 4-byte size field\n    tb_size_t start_len = tb_strlen(symbol_start);\n    tb_size_t end_len = tb_strlen(symbol_end);\n    strtab_size += (tb_uint32_t)(start_len + 1);\n    strtab_size += (tb_uint32_t)(end_len + 1);\n    strtab_size = xm_binutils_macho_align(strtab_size, 4);\n\n    // write Mach-O header\n    xm_macho_header_32_t header;\n    tb_memset(&header, 0, sizeof(header));\n    header.magic = XM_MACHO_MAGIC_32;\n    header.cputype = xm_binutils_macho_get_cputype(arch);\n    header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch);\n    header.filetype = XM_MACHO_FILE_TYPE_OBJECT;\n    header.ncmds = 3; // segment + symtab + build_version\n    header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size;\n    header.flags = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {\n        return tb_false;\n    }\n\n    // write segment command\n    xm_macho_segment_command_t segment;\n    tb_memset(&segment, 0, sizeof(segment));\n    segment.cmd = XM_MACHO_LC_SEGMENT;\n    segment.cmdsize = segment_cmd_total_size;\n    tb_strncpy(segment.segname, \"__TEXT\", 16);\n    segment.vmaddr = 0;\n    segment.vmsize = data_size;\n    segment.fileoff = data_offset;\n    segment.filesize = data_size;\n    segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)\n    segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)\n    segment.nsects = 1;\n    segment.flags = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) {\n        return tb_false;\n    }\n\n    // write section\n    xm_macho_section_t section;\n    tb_memset(&section, 0, sizeof(section));\n    tb_strncpy(section.sectname, \"__const\", 16);\n    tb_strncpy(section.segname, \"__TEXT\", 16);\n    section.addr = 0;\n    section.size = data_size;\n    section.offset = data_offset;\n    section.align = 2; // 2^2 = 4 bytes\n    section.reloff = 0;\n    section.nreloc = 0;\n    section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS;\n    section.reserved1 = 0;\n    section.reserved2 = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&section, sizeof(section))) {\n        return tb_false;\n    }\n\n    // write symtab command\n    xm_macho_symtab_command_t symtab;\n    tb_memset(&symtab, 0, sizeof(symtab));\n    symtab.cmd = XM_MACHO_LC_SYMTAB;\n    symtab.cmdsize = symtab_cmd_size;\n    symtab.symoff = symtab_offset;\n    symtab.nsyms = nlist_count;\n    symtab.stroff = strtab_offset;\n    symtab.strsize = strtab_size;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) {\n        return tb_false;\n    }\n\n    // write build version command\n    xm_macho_build_version_command_t build_version;\n    tb_memset(&build_version, 0, sizeof(build_version));\n    build_version.cmd = XM_MACHO_LC_BUILD_VERSION;\n    build_version.cmdsize = build_version_cmd_size;\n    build_version.platform = xm_binutils_macho_get_platform(plat);\n    build_version.minos = minos;\n    build_version.sdk = sdk;\n    build_version.ntools = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) {\n        return tb_false;\n    }\n\n    // align to 4 bytes\n    tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write section data\n    if (!xm_binutils_stream_copy(istream, ostream, filesize)) {\n        return tb_false;\n    }\n    // append null terminator if zeroend is true\n    if (zeroend) {\n        tb_byte_t zero = 0;\n        if (!tb_stream_bwrit(ostream, &zero, 1)) {\n            return tb_false;\n        }\n    }\n\n    // align to 4 bytes\n    padding = symtab_offset - data_end_offset;\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write symbol table\n    // strx starts from 4 (after 4-byte size field)\n    tb_uint32_t strx = 4;\n    // symbol 0: _binary_xxx_start\n    xm_macho_nlist_t nlist_start;\n    tb_memset(&nlist_start, 0, sizeof(nlist_start));\n    nlist_start.strx = strx;\n    nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT\n    nlist_start.sect = 1;\n    nlist_start.desc = 0;\n    nlist_start.value = 0;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) {\n        return tb_false;\n    }\n    strx += (tb_uint32_t)(start_len + 1);\n\n    // symbol 1: _binary_xxx_end\n    xm_macho_nlist_t nlist_end;\n    tb_memset(&nlist_end, 0, sizeof(nlist_end));\n    nlist_end.strx = strx;\n    nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT\n    nlist_end.sect = 1;\n    nlist_end.desc = 0;\n    nlist_end.value = data_size;\n    if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) {\n        return tb_false;\n    }\n    strx += (tb_uint32_t)(end_len + 1);\n\n    // align to 4 bytes\n    padding = strtab_offset - (symtab_offset + nlist_size * nlist_count);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    // write string table\n    tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4);\n    tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len);\n    tb_byte_t null = 0;\n    tb_stream_bwrit(ostream, &null, 1);\n    tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len);\n    tb_stream_bwrit(ostream, &null, 1);\n\n    // align string table to 4 bytes\n    padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1);\n    if (padding > 0) {\n        tb_byte_t zero = 0;\n        while (padding-- > 0) {\n            if (!tb_stream_bwrit(ostream, &zero, 1)) {\n                return tb_false;\n            }\n        }\n    }\n\n    return tb_true;\n}\n\nstatic tb_bool_t xm_binutils_bin2macho_dump(tb_stream_ref_t istream,\n                                         tb_stream_ref_t ostream,\n                                         tb_char_t const *symbol_prefix,\n                                         tb_char_t const *plat,\n                                         tb_char_t const *arch,\n                                         tb_char_t const *basename,\n                                         tb_uint32_t minos,\n                                         tb_uint32_t sdk,\n                                         tb_bool_t zeroend) {\n    if (xm_binutils_macho_is_64bit(arch)) {\n        return xm_binutils_bin2macho_dump_64(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend);\n    } else {\n        return xm_binutils_bin2macho_dump_32(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend);\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* generate Mach-O object file from binary file\n *\n * local ok, errors = binutils.bin2macho(binaryfile, outputfile, symbol_prefix, plat, arch, basename)\n */\ntb_int_t xm_binutils_bin2macho(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binaryfile\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // get the outputfile\n    tb_char_t const *outputfile = luaL_checkstring(lua, 2);\n    tb_check_return_val(outputfile, 0);\n\n    // get symbol prefix (optional)\n    tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;\n\n    // get plat (optional)\n    tb_char_t const *plat = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;\n\n    // get arch (optional)\n    tb_char_t const *arch = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;\n\n    // get basename (optional)\n    tb_char_t const *basename = lua_isstring(lua, 6) ? lua_tostring(lua, 6) : tb_null;\n\n    // get minos version string (optional)\n    tb_char_t const *minos_str = lua_isstring(lua, 7) ? lua_tostring(lua, 7) : tb_null;\n    tb_uint32_t minos = xm_binutils_macho_parse_version(minos_str);\n\n    // get sdk version string (optional)\n    tb_char_t const *sdk_str = lua_isstring(lua, 8) ? lua_tostring(lua, 8) : tb_null;\n    tb_uint32_t sdk = xm_binutils_macho_parse_version(sdk_str);\n\n    // get zeroend (optional, default: false)\n    tb_bool_t zeroend = lua_toboolean(lua, 9);\n\n    // do dump\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2macho: open %s failed\", binaryfile);\n            break;\n        }\n\n        if (!tb_stream_open(ostream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2macho: open %s failed\", outputfile);\n            break;\n        }\n\n        if (!xm_binutils_bin2macho_dump(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"bin2macho: dump data failed\");\n            break;\n        }\n\n        ok = tb_true;\n        lua_pushboolean(lua, ok);\n\n    } while (0);\n\n    if (istream) {\n        tb_stream_clos(istream);\n    }\n    istream = tb_null;\n\n    if (ostream) {\n        tb_stream_clos(ostream);\n    }\n    ostream = tb_null;\n\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/macho/deplibs.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        deplibs.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"deplibs_macho\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // init Mach-O context\n    xm_macho_context_t context;\n    if (!xm_binutils_macho_context_init(istream, base_offset, &context)) {\n        return tb_false;\n    }\n\n    // skip header to reach load commands\n    tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);\n    if (!tb_stream_seek(istream, base_offset + header_size)) {\n        return tb_false;\n    }\n\n    lua_newtable(lua);\n    tb_size_t result_count = 0;\n\n    // iterate load commands\n    for (tb_uint32_t i = 0; i < context.ncmds; i++) {\n        xm_macho_load_command_t lc;\n        tb_hize_t current_cmd_offset = tb_stream_offset(istream);\n        \n        if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) {\n            return tb_false;\n        }\n        xm_binutils_macho_swap_load_command(&lc, context.swap);\n\n        // check for LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_ID_DYLIB\n        if (lc.cmd == XM_MACHO_LC_LOAD_DYLIB || lc.cmd == XM_MACHO_LC_ID_DYLIB || \n            lc.cmd == XM_MACHO_LC_LOAD_WEAK_DYLIB || lc.cmd == XM_MACHO_LC_REEXPORT_DYLIB) {\n            \n            xm_macho_dylib_command_t dc;\n            if (tb_stream_seek(istream, current_cmd_offset)) {\n                 if (tb_stream_bread(istream, (tb_byte_t*)&dc, sizeof(dc))) {\n                     xm_binutils_macho_swap_dylib_command(&dc, context.swap);\n                     \n                     tb_uint32_t name_offset = dc.dylib.offset;\n                     if (name_offset < lc.cmdsize) {\n                         // name is at current_cmd_offset + name_offset\n                         if (tb_stream_seek(istream, current_cmd_offset + name_offset)) {\n                             tb_char_t dylib_path[1024];\n                             tb_size_t max_len = lc.cmdsize - name_offset;\n                             if (max_len > sizeof(dylib_path) - 1) max_len = sizeof(dylib_path) - 1;\n                             \n                             tb_size_t pos = 0;\n                             tb_byte_t c;\n                             while (pos < max_len) {\n                                 if (!tb_stream_bread(istream, &c, 1)) break;\n                                 if (c == 0) break;\n                                 dylib_path[pos++] = (tb_char_t)c;\n                             }\n                             dylib_path[pos] = '\\0';\n                             \n                             if (pos > 0) {\n                                 lua_pushinteger(lua, result_count + 1);\n                                 lua_pushstring(lua, dylib_path);\n                                 lua_settable(lua, -3);\n                                 result_count++;\n                             }\n                         }\n                     }\n                 }\n            }\n        }\n\n        // move to next command\n        if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) {\n            break;\n        }\n    }\n\n    return tb_true;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/macho/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_MACHO_PREFIX_H\n#define XM_BINUTILS_MACHO_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_MACHO_MAGIC_32        0xfeedface  // MH_MAGIC - little endian\n#define XM_MACHO_MAGIC_64        0xfeedfacf  // MH_MAGIC_64 - little endian\n#define XM_MACHO_MAGIC_32_BE     0xcefaedfe  // MH_CIGAM - big endian\n#define XM_MACHO_MAGIC_64_BE     0xcffaedfe  // MH_CIGAM_64 - big endian\n#define XM_MACHO_MAGIC_FAT       0xcafebabe\n\n#define XM_MACHO_CPU_TYPE_X86    7\n#define XM_MACHO_CPU_TYPE_X86_64 0x01000007\n#define XM_MACHO_CPU_TYPE_ARM   12\n#define XM_MACHO_CPU_TYPE_ARM64  0x0100000c\n\n#define XM_MACHO_CPU_SUBTYPE_X86     3\n#define XM_MACHO_CPU_SUBTYPE_X86_64  3\n#define XM_MACHO_CPU_SUBTYPE_ARM     9\n#define XM_MACHO_CPU_SUBTYPE_ARM64   0\n\n#define XM_MACHO_FILE_TYPE_OBJECT   1\n\n#define XM_MACHO_LC_SEGMENT          0x1\n#define XM_MACHO_LC_SEGMENT_64       0x19\n#define XM_MACHO_LC_SYMTAB           0x2\n#define XM_MACHO_LC_LOAD_DYLIB       0xc\n#define XM_MACHO_LC_ID_DYLIB         0xd\n#define XM_MACHO_LC_RPATH            (0x1c | 0x80000000)\n#define XM_MACHO_LC_LOAD_WEAK_DYLIB  (0x18 | 0x80000000)\n#define XM_MACHO_LC_REEXPORT_DYLIB   (0x1f | 0x80000000)\n#define XM_MACHO_LC_BUILD_VERSION    0x32\n\n#define XM_MACHO_PLATFORM_MACOS      1\n#define XM_MACHO_PLATFORM_IOS        2\n#define XM_MACHO_PLATFORM_TVOS       3\n#define XM_MACHO_PLATFORM_WATCHOS    4\n\n#define XM_MACHO_SECT_TYPE_REGULAR   0x0\n#define XM_MACHO_SECT_ATTR_SOME_INITS 0x400\n#define XM_MACHO_SECT_ATTR_PURE_INSTRUCTIONS 0x80000000\n\n#define XM_MACHO_N_TYPE_MASK        0x0e\n#define XM_MACHO_N_TYPE_SECT        0x0e\n#define XM_MACHO_N_EXT               0x01\n\n#define XM_MACHO_VM_PROT_READ       1\n#define XM_MACHO_VM_PROT_WRITE      2\n#define XM_MACHO_VM_PROT_EXECUTE    4\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n#include \"tbox/prefix/packed.h\"\ntypedef struct __xm_macho_header_32_t {\n    tb_uint32_t magic;\n    tb_uint32_t cputype;\n    tb_uint32_t cpusubtype;\n    tb_uint32_t filetype;\n    tb_uint32_t ncmds;\n    tb_uint32_t sizeofcmds;\n    tb_uint32_t flags;\n} __tb_packed__ xm_macho_header_32_t;\n\ntypedef struct __xm_macho_header_64_t {\n    tb_uint32_t magic;\n    tb_uint32_t cputype;\n    tb_uint32_t cpusubtype;\n    tb_uint32_t filetype;\n    tb_uint32_t ncmds;\n    tb_uint32_t sizeofcmds;\n    tb_uint32_t flags;\n    tb_uint32_t reserved;\n} __tb_packed__ xm_macho_header_64_t;\n\ntypedef struct __xm_macho_rpath_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    tb_uint32_t path_offset;\n} __tb_packed__ xm_macho_rpath_command_t;\n\ntypedef struct __xm_macho_segment_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    tb_char_t segname[16];\n    tb_uint32_t vmaddr;\n    tb_uint32_t vmsize;\n    tb_uint32_t fileoff;\n    tb_uint32_t filesize;\n    tb_uint32_t maxprot;\n    tb_uint32_t initprot;\n    tb_uint32_t nsects;\n    tb_uint32_t flags;\n} __tb_packed__ xm_macho_segment_command_t;\n\ntypedef struct __xm_macho_segment_command_64_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    tb_char_t segname[16];\n    tb_uint64_t vmaddr;\n    tb_uint64_t vmsize;\n    tb_uint64_t fileoff;\n    tb_uint64_t filesize;\n    tb_uint32_t maxprot;\n    tb_uint32_t initprot;\n    tb_uint32_t nsects;\n    tb_uint32_t flags;\n} __tb_packed__ xm_macho_segment_command_64_t;\n\ntypedef struct __xm_macho_section_t {\n    tb_char_t sectname[16];\n    tb_char_t segname[16];\n    tb_uint32_t addr;\n    tb_uint32_t size;\n    tb_uint32_t offset;\n    tb_uint32_t align;\n    tb_uint32_t reloff;\n    tb_uint32_t nreloc;\n    tb_uint32_t flags;\n    tb_uint32_t reserved1;\n    tb_uint32_t reserved2;\n} __tb_packed__ xm_macho_section_t;\n\ntypedef struct __xm_macho_section_64_t {\n    tb_char_t sectname[16];\n    tb_char_t segname[16];\n    tb_uint64_t addr;\n    tb_uint64_t size;\n    tb_uint32_t offset;\n    tb_uint32_t align;\n    tb_uint32_t reloff;\n    tb_uint32_t nreloc;\n    tb_uint32_t flags;\n    tb_uint32_t reserved1;\n    tb_uint32_t reserved2;\n    tb_uint32_t reserved3;\n} __tb_packed__ xm_macho_section_64_t;\n\ntypedef struct __xm_macho_symtab_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    tb_uint32_t symoff;\n    tb_uint32_t nsyms;\n    tb_uint32_t stroff;\n    tb_uint32_t strsize;\n} __tb_packed__ xm_macho_symtab_command_t;\n\ntypedef struct __xm_macho_build_version_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    tb_uint32_t platform;\n    tb_uint32_t minos;\n    tb_uint32_t sdk;\n    tb_uint32_t ntools;\n} __tb_packed__ xm_macho_build_version_command_t;\n\ntypedef struct __xm_macho_nlist_t {\n    tb_uint32_t strx;\n    tb_uint8_t type;\n    tb_uint8_t sect;\n    tb_int16_t desc;\n    tb_uint32_t value;\n} __tb_packed__ xm_macho_nlist_t;\n\ntypedef struct __xm_macho_nlist_64_t {\n    tb_uint32_t strx;\n    tb_uint8_t type;\n    tb_uint8_t sect;\n    tb_uint16_t desc;\n    tb_uint64_t value;\n} __tb_packed__ xm_macho_nlist_64_t;\n\ntypedef struct __xm_macho_load_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n} __tb_packed__ xm_macho_load_command_t;\n\ntypedef struct __xm_macho_dylib_t {\n    tb_uint32_t offset;\n    tb_uint32_t timestamp;\n    tb_uint32_t current_version;\n    tb_uint32_t compatibility_version;\n} __tb_packed__ xm_macho_dylib_t;\n\ntypedef struct __xm_macho_dylib_command_t {\n    tb_uint32_t cmd;\n    tb_uint32_t cmdsize;\n    xm_macho_dylib_t dylib;\n} __tb_packed__ xm_macho_dylib_command_t;\n\ntypedef struct __xm_macho_context_t {\n    union {\n        xm_macho_header_32_t header32;\n        xm_macho_header_64_t header64;\n    } header;\n    tb_bool_t   is64;\n    tb_bool_t   swap;\n    tb_uint32_t ncmds;\n    tb_uint32_t sizeofcmds;\n} __tb_packed__ xm_macho_context_t;\n#include \"tbox/prefix/packed.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n// byte-swap Mach-O header fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_header_32(xm_macho_header_32_t *header, tb_bool_t swap) {\n    if (swap) {\n        header->magic = tb_bits_swap_u32(header->magic);\n        header->cputype = tb_bits_swap_u32(header->cputype);\n        header->cpusubtype = tb_bits_swap_u32(header->cpusubtype);\n        header->filetype = tb_bits_swap_u32(header->filetype);\n        header->ncmds = tb_bits_swap_u32(header->ncmds);\n        header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds);\n        header->flags = tb_bits_swap_u32(header->flags);\n    }\n}\n\n// byte-swap Mach-O header 64 fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_header_64(xm_macho_header_64_t *header, tb_bool_t swap) {\n    if (swap) {\n        header->magic = tb_bits_swap_u32(header->magic);\n        header->cputype = tb_bits_swap_u32(header->cputype);\n        header->cpusubtype = tb_bits_swap_u32(header->cpusubtype);\n        header->filetype = tb_bits_swap_u32(header->filetype);\n        header->ncmds = tb_bits_swap_u32(header->ncmds);\n        header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds);\n        header->flags = tb_bits_swap_u32(header->flags);\n        header->reserved = tb_bits_swap_u32(header->reserved);\n    }\n}\n\n// init Mach-O context\nstatic __tb_inline__ tb_bool_t xm_binutils_macho_context_init(tb_stream_ref_t istream, tb_hize_t base_offset, xm_macho_context_t* context) {\n    tb_assert_and_check_return_val(istream && context, tb_false);\n\n    // read Mach-O header\n    if (!tb_stream_seek(istream, base_offset)) return tb_false;\n    if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header32, sizeof(xm_macho_header_32_t))) return tb_false;\n\n    // check magic\n    tb_uint32_t magic = context->header.header32.magic;\n    if (magic == XM_MACHO_MAGIC_32) {\n        context->is64 = tb_false;\n        context->swap = tb_false;\n    } else if (magic == XM_MACHO_MAGIC_32_BE) {\n        context->is64 = tb_false;\n        context->swap = tb_true;\n    } else if (magic == XM_MACHO_MAGIC_64) {\n        context->is64 = tb_true;\n        context->swap = tb_false;\n    } else if (magic == XM_MACHO_MAGIC_64_BE) {\n        context->is64 = tb_true;\n        context->swap = tb_true;\n    } else {\n        return tb_false; // Not a Mach-O file\n    }\n\n    if (context->is64) {\n        if (!tb_stream_seek(istream, base_offset)) return tb_false;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header64, sizeof(xm_macho_header_64_t))) return tb_false;\n        xm_binutils_macho_swap_header_64(&context->header.header64, context->swap);\n        context->ncmds = context->header.header64.ncmds;\n        context->sizeofcmds = context->header.header64.sizeofcmds;\n    } else {\n        xm_binutils_macho_swap_header_32(&context->header.header32, context->swap);\n        context->ncmds = context->header.header32.ncmds;\n        context->sizeofcmds = context->header.header32.sizeofcmds;\n    }\n    return tb_true;\n}\n\n// byte-swap load command fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_load_command(xm_macho_load_command_t *lc, tb_bool_t swap) {\n    if (swap) {\n        lc->cmd = tb_bits_swap_u32(lc->cmd);\n        lc->cmdsize = tb_bits_swap_u32(lc->cmdsize);\n    }\n}\n\n// byte-swap dylib command fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_dylib_command(xm_macho_dylib_command_t *dc, tb_bool_t swap) {\n    if (swap) {\n        dc->cmd = tb_bits_swap_u32(dc->cmd);\n        dc->cmdsize = tb_bits_swap_u32(dc->cmdsize);\n        dc->dylib.offset = tb_bits_swap_u32(dc->dylib.offset);\n        dc->dylib.timestamp = tb_bits_swap_u32(dc->dylib.timestamp);\n        dc->dylib.current_version = tb_bits_swap_u32(dc->dylib.current_version);\n        dc->dylib.compatibility_version = tb_bits_swap_u32(dc->dylib.compatibility_version);\n    }\n}\n\n// byte-swap rpath command fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_rpath_command(xm_macho_rpath_command_t *rc, tb_bool_t swap) {\n    if (swap) {\n        rc->cmd = tb_bits_swap_u32(rc->cmd);\n        rc->cmdsize = tb_bits_swap_u32(rc->cmdsize);\n        rc->path_offset = tb_bits_swap_u32(rc->path_offset);\n    }\n}\n\n// byte-swap symtab command fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_symtab_command(xm_macho_symtab_command_t *cmd, tb_bool_t swap) {\n    if (swap) {\n        cmd->cmd = tb_bits_swap_u32(cmd->cmd);\n        cmd->cmdsize = tb_bits_swap_u32(cmd->cmdsize);\n        cmd->symoff = tb_bits_swap_u32(cmd->symoff);\n        cmd->nsyms = tb_bits_swap_u32(cmd->nsyms);\n        cmd->stroff = tb_bits_swap_u32(cmd->stroff);\n        cmd->strsize = tb_bits_swap_u32(cmd->strsize);\n    }\n}\n\n// byte-swap nlist 32 fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_32(xm_macho_nlist_t *nlist, tb_bool_t swap) {\n    if (swap) {\n        nlist->strx = tb_bits_swap_u32(nlist->strx);\n        nlist->desc = tb_bits_swap_u16(nlist->desc);\n        nlist->value = tb_bits_swap_u32(nlist->value);\n    }\n}\n\n// byte-swap nlist 64 fields if needed\nstatic __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_64(xm_macho_nlist_64_t *nlist, tb_bool_t swap) {\n    if (swap) {\n        nlist->strx = tb_bits_swap_u32(nlist->strx);\n        nlist->desc = tb_bits_swap_u16(nlist->desc);\n        nlist->value = tb_bits_swap_u64(nlist->value);\n    }\n}\n\n/* get CPU type from architecture string\n *\n * @param arch    the architecture string (e.g., \"x86_64\", \"i386\", \"arm64\")\n * @return        the CPU type\n */\nstatic __tb_inline__ tb_uint32_t xm_binutils_macho_get_cputype(tb_char_t const *arch) {\n    if (!arch) {\n        return XM_MACHO_CPU_TYPE_X86_64;\n    }\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return XM_MACHO_CPU_TYPE_X86_64;\n    } else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0) {\n        return XM_MACHO_CPU_TYPE_ARM64;\n    } else if (tb_strcmp(arch, \"arm\") == 0) {\n        return XM_MACHO_CPU_TYPE_ARM;\n    } else if (tb_strcmp(arch, \"x86\") == 0 || tb_strcmp(arch, \"i386\") == 0) {\n        return XM_MACHO_CPU_TYPE_X86;\n    }\n    return XM_MACHO_CPU_TYPE_X86_64;\n}\n\n/* get CPU subtype from architecture string\n *\n * @param arch    the architecture string\n * @return        the CPU subtype\n */\nstatic __tb_inline__ tb_uint32_t xm_binutils_macho_get_cpusubtype(tb_char_t const *arch) {\n    if (!arch) {\n        return XM_MACHO_CPU_SUBTYPE_X86_64;\n    }\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return XM_MACHO_CPU_SUBTYPE_X86_64;\n    } else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0) {\n        return XM_MACHO_CPU_SUBTYPE_ARM64;\n    } else if (tb_strcmp(arch, \"arm\") == 0) {\n        return XM_MACHO_CPU_SUBTYPE_ARM;\n    } else if (tb_strcmp(arch, \"x86\") == 0 || tb_strcmp(arch, \"i386\") == 0) {\n        return XM_MACHO_CPU_SUBTYPE_X86;\n    }\n    return XM_MACHO_CPU_SUBTYPE_X86_64;\n}\n\n/* check if architecture is 64-bit\n *\n * @param arch    the architecture string\n * @return        tb_true if 64-bit, tb_false otherwise\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_macho_is_64bit(tb_char_t const *arch) {\n    if (!arch) {\n        return tb_true;\n    }\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return tb_true;\n    } else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0) {\n        return tb_true;\n    } else if (tb_strcmp(arch, \"arm\") == 0) {\n        return tb_false;\n    } else if (tb_strcmp(arch, \"x86\") == 0 || tb_strcmp(arch, \"i386\") == 0) {\n        return tb_false;\n    }\n    return tb_true;\n}\n\n/* align value to specified alignment\n *\n * @param value   the value to align\n * @param align   the alignment (must be power of 2)\n * @return        the aligned value\n */\nstatic __tb_inline__ tb_uint32_t xm_binutils_macho_align(tb_uint32_t value, tb_uint32_t align) {\n    return ((value + align - 1) & ~(align - 1));\n}\n\n/* get platform from platform string\n *\n * @param platform the platform string (e.g., \"macosx\", \"ios\", \"tvos\", \"watchos\")\n * @return         the platform constant\n */\nstatic __tb_inline__ tb_uint32_t xm_binutils_macho_get_platform(tb_char_t const *platform) {\n    if (!platform) {\n        return XM_MACHO_PLATFORM_MACOS;\n    }\n    if (tb_strcmp(platform, \"macosx\") == 0 || tb_strcmp(platform, \"macos\") == 0) {\n        return XM_MACHO_PLATFORM_MACOS;\n    } else if (tb_strcmp(platform, \"iphoneos\") == 0 || tb_strcmp(platform, \"ios\") == 0) {\n        return XM_MACHO_PLATFORM_IOS;\n    } else if (tb_strcmp(platform, \"appletvos\") == 0 || tb_strcmp(platform, \"tvos\") == 0) {\n        return XM_MACHO_PLATFORM_TVOS;\n    } else if (tb_strcmp(platform, \"watchos\") == 0) {\n        return XM_MACHO_PLATFORM_WATCHOS;\n    }\n    return XM_MACHO_PLATFORM_MACOS;\n}\n\n/* parse version string to Mach-O format\n *\n * @param version_str the version string (e.g., \"10.0\" or \"18.2\")\n * @return            the version in Mach-O format (major << 16) | (minor << 8) | patch\n */\nstatic __tb_inline__ tb_uint32_t xm_binutils_macho_parse_version(tb_char_t const *version_str) {\n    if (!version_str || !version_str[0]) {\n        return 0x000a0000; // default: 10.0.0\n    }\n    tb_uint32_t major = 0;\n    tb_uint32_t minor = 0;\n    tb_uint32_t patch = 0;\n    tb_char_t const *p = version_str;\n    // parse major\n    while (*p && tb_isdigit(*p)) {\n        major = major * 10 + (*p - '0');\n        p++;\n    }\n    if (*p == '.') {\n        p++;\n        // parse minor\n        while (*p && tb_isdigit(*p)) {\n            minor = minor * 10 + (*p - '0');\n            p++;\n        }\n        if (*p == '.') {\n            p++;\n            // parse patch\n            while (*p && tb_isdigit(*p)) {\n                patch = patch * 10 + (*p - '0');\n                p++;\n            }\n        }\n    }\n    return (major << 16) | (minor << 8) | patch;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * readsyms inline implementation\n */\n\n\n\n/* read string from Mach-O string table\n *\n * @param istream       the input stream\n * @param strtab_offset the string table offset\n * @param offset        the string offset (nlist.strx, relative to string table start, including 4-byte size field)\n * @param name          the buffer to store the string\n * @param name_size     the size of the buffer\n * @return              tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_macho_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) {\n    tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);\n\n    // nlist.strx is offset from string table start (including 4-byte size field)\n    tb_hize_t saved_pos = tb_stream_offset(istream);\n    if (!tb_stream_seek(istream, strtab_offset + offset)) {\n        return tb_false;\n    }\n\n    tb_size_t pos = 0;\n    tb_byte_t c;\n    while (pos < name_size - 1) {\n        if (!tb_stream_bread(istream, &c, 1)) {\n            tb_stream_seek(istream, saved_pos);\n            return tb_false;\n        }\n        if (c == 0) {\n            break;\n        }\n        name[pos++] = (tb_char_t)c;\n    }\n    name[pos] = '\\0';\n\n    tb_stream_seek(istream, saved_pos);\n    return tb_true;\n}\n\n/* get symbol type character (nm-style) from Mach-O symbol\n *\n * @param type  the symbol type byte\n * @param sect  the section number (0 = undefined)\n * @return      the type character (T/t/D/d/B/b/U)\n */\nstatic __tb_inline__ tb_char_t xm_binutils_macho_get_symbol_type_char(tb_uint8_t type, tb_uint8_t sect) {\n    // undefined symbol\n    if (sect == 0) {\n        return 'U';\n    }\n\n    // check if external\n    tb_bool_t is_external = (type & XM_MACHO_N_EXT) != 0;\n\n    // check if in section\n    tb_uint8_t n_type = type & XM_MACHO_N_TYPE_MASK;\n    if (n_type == XM_MACHO_N_TYPE_SECT) {\n        // section 1 is usually __TEXT,__text (text)\n        // section 2 is usually __DATA,__data (data)\n        // section 3 is usually __DATA,__bss (bss)\n        // For simplicity, we'll use section number to determine type\n        // This is a heuristic and may not be 100% accurate\n        if (sect == 1) {\n            return is_external ? 'T' : 't';  // text section\n        } else if (sect == 2) {\n            return is_external ? 'D' : 'd';  // data section\n        } else if (sect == 3) {\n            return is_external ? 'B' : 'b';  // bss section\n        } else {\n            return is_external ? 'S' : 's';  // other section\n        }\n    }\n\n    return '?';  // unknown\n}\n\n/* get symbol bind string from Mach-O symbol type\n *\n * @param type the symbol type byte\n * @return      the bind string\n */\nstatic __tb_inline__ tb_char_t const *xm_binutils_macho_get_symbol_bind(tb_uint8_t type) {\n    if (type & XM_MACHO_N_EXT) {\n        return \"external\";\n    }\n    return \"local\";\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/macho/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readsyms_macho\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\ntb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) {\n    tb_assert_and_check_return_val(istream && lua && context, tb_false);\n\n    // find LC_SYMTAB command\n    xm_macho_symtab_command_t symtab_cmd;\n    tb_bool_t found_symtab = tb_false;\n\n    tb_uint32_t offset = sizeof(xm_macho_header_32_t);\n    for (tb_uint32_t i = 0; i < context->ncmds; i++) {\n        tb_uint32_t cmd;\n        tb_uint32_t cmdsize;\n\n        if (!tb_stream_seek(istream, base_offset + offset)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) {\n            return tb_false;\n        }\n\n        if (context->swap) {\n            cmd = tb_bits_swap_u32(cmd);\n            cmdsize = tb_bits_swap_u32(cmdsize);\n        }\n\n        if (cmd == XM_MACHO_LC_SYMTAB) {\n            if (!tb_stream_seek(istream, base_offset + offset)) {\n                return tb_false;\n            }\n            if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) {\n                return tb_false;\n            }\n            xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap);\n            found_symtab = tb_true;\n            break;\n        }\n\n        offset += cmdsize;\n    }\n\n    if (!found_symtab) {\n        lua_newtable(lua);\n        return tb_true;\n    }\n\n    // create result table\n    lua_newtable(lua);\n\n    // read symbols\n    if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) {\n        return tb_false;\n    }\n\n    tb_uint32_t result_count = 0;\n    for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) {\n        xm_macho_nlist_t nlist;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) {\n            return tb_false;\n        }\n        xm_binutils_macho_swap_nlist_32(&nlist, context->swap);\n\n        // skip NULL symbols\n        if (nlist.strx == 0) {\n            continue;\n        }\n\n        // get symbol name\n        tb_char_t name[256];\n        if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) {\n            continue;\n        }\n\n        // skip internal symbols (starting with .)\n        if (name[0] == '.') {\n            continue;\n        }\n\n        // create symbol table entry\n        lua_pushinteger(lua, result_count + 1);\n        lua_newtable(lua);\n\n        // name\n        lua_pushstring(lua, \"name\");\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n\n        // type (nm-style: T/t/D/d/B/b/U)\n        tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect);\n        tb_char_t type_str[2] = {type_char, '\\0'};\n        lua_pushstring(lua, \"type\");\n        lua_pushstring(lua, type_str);\n        lua_settable(lua, -3);\n\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    return tb_true;\n}\n\ntb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) {\n    tb_assert_and_check_return_val(istream && lua && context, tb_false);\n\n    // find LC_SYMTAB command\n    xm_macho_symtab_command_t symtab_cmd;\n    tb_bool_t found_symtab = tb_false;\n\n    tb_uint32_t offset = sizeof(xm_macho_header_64_t);\n    for (tb_uint32_t i = 0; i < context->ncmds; i++) {\n        tb_uint32_t cmd;\n        tb_uint32_t cmdsize;\n\n        if (!tb_stream_seek(istream, base_offset + offset)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) {\n            return tb_false;\n        }\n        if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) {\n            return tb_false;\n        }\n\n        if (context->swap) {\n            cmd = tb_bits_swap_u32(cmd);\n            cmdsize = tb_bits_swap_u32(cmdsize);\n        }\n\n        if (cmd == XM_MACHO_LC_SYMTAB) {\n            if (!tb_stream_seek(istream, base_offset + offset)) {\n                return tb_false;\n            }\n            if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) {\n                return tb_false;\n            }\n            xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap);\n            found_symtab = tb_true;\n            break;\n        }\n\n        offset += cmdsize;\n    }\n\n    if (!found_symtab) {\n        lua_newtable(lua);\n        return tb_true;\n    }\n\n    // create result table\n    lua_newtable(lua);\n\n    // read symbols\n    if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) {\n        return tb_false;\n    }\n\n    tb_uint32_t result_count = 0;\n    for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) {\n        xm_macho_nlist_64_t nlist;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) {\n            return tb_false;\n        }\n        xm_binutils_macho_swap_nlist_64(&nlist, context->swap);\n\n        // skip NULL symbols\n        if (nlist.strx == 0) {\n            continue;\n        }\n\n        // get symbol name\n        tb_char_t name[256];\n        if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) {\n            continue;\n        }\n\n        // skip internal symbols (starting with .)\n        if (name[0] == '.') {\n            continue;\n        }\n\n        // create symbol table entry\n        lua_pushinteger(lua, result_count + 1);\n        lua_newtable(lua);\n\n        // name\n        lua_pushstring(lua, \"name\");\n        lua_pushstring(lua, name);\n        lua_settable(lua, -3);\n\n        // type (nm-style: T/t/D/d/B/b/U)\n        tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect);\n        tb_char_t type_str[2] = {type_char, '\\0'};\n        lua_pushstring(lua, \"type\");\n        lua_pushstring(lua, type_str);\n        lua_settable(lua, -3);\n\n        lua_settable(lua, -3);\n        result_count++;\n    }\n\n    return tb_true;\n}\n\ntb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // init Mach-O context\n    xm_macho_context_t context;\n    if (!xm_binutils_macho_context_init(istream, base_offset, &context)) {\n        return tb_false;\n    }\n\n    if (!context.is64) {\n        return xm_binutils_macho_read_symbols_32(istream, base_offset, lua, &context);\n    } else {\n        return xm_binutils_macho_read_symbols_64(istream, base_offset, lua, &context);\n    }\n}\n\n"
  },
  {
    "path": "core/src/xmake/binutils/macho/rpath.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rpath.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rpath_macho\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    tb_bool_t ok = tb_false;\n    do {\n        // init Mach-O context\n        xm_macho_context_t context;\n        if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break;\n\n        // skip header to reach load commands\n        tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);\n        if (!tb_stream_seek(istream, base_offset + header_size)) break;\n\n        tb_size_t result_count = 0;\n\n        // iterate load commands\n        tb_uint32_t i = 0;\n        for (i = 0; i < context.ncmds; i++) {\n            xm_macho_load_command_t lc;\n            tb_hize_t current_cmd_offset = tb_stream_offset(istream);\n\n            if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break;\n            xm_binutils_macho_swap_load_command(&lc, context.swap);\n\n            // check for LC_RPATH\n            if (lc.cmd == XM_MACHO_LC_RPATH) {\n\n                xm_macho_rpath_command_t rc;\n                if (tb_stream_seek(istream, current_cmd_offset)) {\n                     if (tb_stream_bread(istream, (tb_byte_t*)&rc, sizeof(rc))) {\n                         xm_binutils_macho_swap_rpath_command(&rc, context.swap);\n\n                         tb_uint32_t name_offset = rc.path_offset;\n                         if (name_offset < lc.cmdsize) {\n                             // name is at current_cmd_offset + name_offset\n                             tb_char_t rpath[TB_PATH_MAXN];\n                             if (xm_binutils_read_string(istream, current_cmd_offset + name_offset, rpath, sizeof(rpath))) {\n                                 if (tb_strlen(rpath) > 0) {\n                                     lua_pushinteger(lua, result_count + 1);\n                                     lua_pushstring(lua, rpath);\n                                     lua_settable(lua, -3);\n                                     result_count++;\n                                 }\n                             }\n                         }\n                     }\n                }\n            }\n\n            // move to next command\n            if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) break;\n        }\n        if (i < context.ncmds) break;\n\n        ok = tb_true;\n    } while (0);\n\n    return ok;\n}\n\ntb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) {\n    tb_assert_and_check_return_val(istream, tb_false);\n\n    tb_bool_t ok = tb_false;\n    tb_byte_t* buffer = tb_null;\n    do {\n        // init Mach-O context\n        xm_macho_context_t context;\n        if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break;\n\n        tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);\n        if (!tb_stream_seek(istream, base_offset + header_size)) break;\n\n        tb_hize_t read_offset = base_offset + header_size;\n        tb_hize_t write_offset = read_offset;\n        tb_uint32_t new_ncmds = 0;\n        tb_uint32_t new_sizeofcmds = 0;\n        tb_bool_t found = tb_false;\n\n        buffer = (tb_byte_t*)tb_malloc(64 * 1024); // 64KB should be enough for any load command\n        if (!buffer) break;\n\n        tb_uint32_t i = 0;\n        for (i = 0; i < context.ncmds; i++) {\n            xm_macho_load_command_t lc;\n            if (!tb_stream_seek(istream, read_offset)) break;\n            if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break;\n            xm_binutils_macho_swap_load_command(&lc, context.swap);\n\n            tb_bool_t remove = tb_false;\n            if (lc.cmd == XM_MACHO_LC_RPATH) {\n                remove = tb_true;\n                found = tb_true;\n            }\n\n            if (!remove) {\n                // copy command to write_offset\n                if (read_offset != write_offset) {\n                    if (lc.cmdsize > 64 * 1024) break;\n\n                    if (!tb_stream_seek(istream, read_offset)) break;\n                    if (!tb_stream_bread(istream, buffer, lc.cmdsize)) break;\n                    if (!tb_stream_seek(istream, write_offset)) break;\n                    if (!tb_stream_bwrit(istream, buffer, lc.cmdsize)) break;\n                }\n                write_offset += lc.cmdsize;\n                new_ncmds++;\n                new_sizeofcmds += lc.cmdsize;\n            }\n\n            read_offset += lc.cmdsize;\n        }\n        if (i < context.ncmds) break;\n\n        if (found) {\n            // zero out the remaining space\n            if (read_offset > write_offset) {\n                tb_hize_t diff = read_offset - write_offset;\n                if (!tb_stream_seek(istream, write_offset)) break;\n\n                tb_byte_t zero = 0;\n                tb_bool_t write_ok = tb_true;\n                for (tb_hize_t k = 0; k < diff; k++) {\n                    if (!tb_stream_bwrit(istream, &zero, 1)) {\n                        write_ok = tb_false;\n                        break;\n                    }\n                }\n                if (!write_ok) break;\n            }\n\n            // update header\n            if (context.is64) {\n                context.header.header64.ncmds = new_ncmds;\n                context.header.header64.sizeofcmds = new_sizeofcmds;\n                xm_binutils_macho_swap_header_64(&context.header.header64, context.swap);\n                if (!tb_stream_seek(istream, base_offset)) break;\n                if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header64, sizeof(xm_macho_header_64_t))) break;\n            } else {\n                context.header.header32.ncmds = new_ncmds;\n                context.header.header32.sizeofcmds = new_sizeofcmds;\n                xm_binutils_macho_swap_header_32(&context.header.header32, context.swap);\n                if (!tb_stream_seek(istream, base_offset)) break;\n                if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header32, sizeof(xm_macho_header_32_t))) break;\n            }\n        }\n\n        ok = tb_true;\n    } while (0);\n\n    if (buffer) tb_free(buffer);\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/mslib/extractlib.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        extractlib.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"mslib_extract\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* generate unique name for output file\n *\n * @param base_name      the base name\n * @param id             the unique id\n * @param output         output buffer\n * @param output_size    output buffer size\n * @param output_len     output: actual output length\n * @return               tb_true on success, tb_false on failure\n */\nstatic tb_bool_t xm_binutils_mslib_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) {\n    tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false);\n\n    // find the last dot for extension\n    tb_char_t const *ext = tb_strrchr(base_name, '.');\n    tb_long_t n = -1;\n    if (ext) {\n        tb_size_t base_len = (tb_size_t)(ext - base_name);\n        tb_size_t ext_len = tb_strlen(ext);\n        if (base_len + ext_len + 16 < output_size) {\n            n = tb_snprintf(output, output_size, \"%.*s_%u%s\", (tb_int_t)base_len, base_name, id, ext);\n        }\n    } else {\n        // no extension\n        if (tb_strlen(base_name) + 16 < output_size) {\n            n = tb_snprintf(output, output_size, \"%s_%u\", base_name, id);\n        }\n    }\n\n    if (n >= 0) {\n        *output_len = (tb_size_t)n;\n        return tb_true;\n    }\n    return tb_false;\n}\n\n/* extract MSVC lib archive to directory\n *\n * @param istream    the input stream\n * @param outputdir  the output directory\n * @param plain      extract all object files to the same directory\n * @return           tb_true on success, tb_false on failure\n */\ntb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain) {\n    tb_assert_and_check_return_val(istream && outputdir, tb_false);\n\n    // check magic (!<arch>\\n)\n    if (!xm_binutils_mslib_check_magic(istream)) {\n        return tb_false;\n    }\n\n    /* ensure output directory exists\n     * check if directory already exists\n     */\n    if (!tb_file_info(outputdir, tb_null)) {\n        // directory doesn't exist, create it\n        if (!tb_directory_create(outputdir)) {\n            return tb_false;\n        }\n    }\n\n    tb_bool_t ok = tb_true;\n    tb_char_t* longnames = tb_null;\n    tb_size_t  longnames_size = 0;\n\n    // iterate through members\n    while (ok) {\n        // read header\n        xm_mslib_header_t header;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {\n            // end of file\n            break;\n        }\n\n        // parse member size\n        tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10);\n        if (member_size < 0) {\n            ok = tb_false;\n            break;\n        }\n\n        // parse member name\n        tb_char_t member_name[256] = {0};\n        tb_bool_t is_longname_table = tb_false;\n\n        if (header.name[0] == '/') {\n            if (header.name[1] == '/') {\n                // long name table (//)\n                is_longname_table = tb_true;\n            } else if (tb_isdigit(header.name[1])) {\n                // offset into long name table (/123)\n                tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15);\n                if (offset >= 0 && (tb_size_t)offset < longnames_size) {\n                    /* copy from longnames\n                     * names in longnames are null-terminated\n                     */\n                    tb_strlcpy(member_name, longnames + offset, sizeof(member_name));\n                }\n            } else {\n                 /* symbol table or other special member (/)\n                  * usually symbol table is just \"/\"\n                  */\n                 tb_strlcpy(member_name, \"/\", sizeof(member_name));\n            }\n        } else {\n             // short name, ends with /\n             tb_size_t i = 0;\n             for (i = 0; i < 16 && header.name[i] != '/'; i++) {\n                 member_name[i] = header.name[i];\n             }\n             member_name[i] = '\\0';\n        }\n\n        if (is_longname_table) {\n            tb_char_t* new_longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1);\n            if (!new_longnames) {\n                ok = tb_false;\n                break;\n            }\n            longnames = new_longnames;\n            if (!tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) {\n                ok = tb_false;\n                break;\n            }\n            longnames[member_size] = '\\0';\n            longnames_size = (tb_size_t)member_size;\n\n            // align\n            if (member_size % 2) {\n                if (!tb_stream_skip(istream, 1)) {\n                    ok = tb_false;\n                    break;\n                }\n            }\n            continue;\n        }\n\n        /* check if we should extract\n         * skip empty names, symbol tables (/), long name table (//) - handled above,\n         * and __.SYMDEF (SysV/BSD style symbol table, just in case)\n         */\n        if (member_name[0] == '\\0' || tb_strcmp(member_name, \"/\") == 0 || tb_strcmp(member_name, \"//\") == 0 ||\n            tb_strncmp(member_name, \"__.SYMDEF\", 9) == 0) {\n\n            // skip member data\n            if (!tb_stream_skip(istream, member_size)) {\n                ok = tb_false;\n                break;\n            }\n\n             // align\n            if (member_size % 2) {\n                 if (!tb_stream_skip(istream, 1)) {\n                    ok = tb_false;\n                    break;\n                }\n            }\n            continue;\n        }\n\n        /* construct output path\n         * replace \\ with /\n         */\n        tb_size_t name_len = tb_strlen(member_name);\n        for (tb_size_t i = 0; i < name_len; i++) {\n            if (member_name[i] == '\\\\') {\n                member_name[i] = '/';\n            }\n        }\n\n        // check output path length\n        tb_char_t output_path[1024];\n        if (plain) {\n            // get filename only\n            tb_char_t const* name = tb_strrchr(member_name, '/');\n            if (name) {\n                name++;\n            } else {\n                name = member_name;\n            }\n\n            // check conflicts\n            tb_char_t output_name[512];\n            tb_size_t output_name_len = tb_strlen(name);\n            tb_size_t outputdir_len = tb_strlen(outputdir);\n\n            if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {\n                 ok = tb_false;\n                 break;\n            }\n            tb_snprintf(output_path, sizeof(output_path), \"%s/%s\", outputdir, name);\n\n            if (tb_file_info(output_path, tb_null)) {\n                // name conflict, try different IDs\n                tb_uint32_t conflict_id = 1;\n                while (conflict_id < 10000) {\n                    if (!xm_binutils_mslib_generate_unique_name(name, conflict_id, output_name, sizeof(output_name), &output_name_len)) {\n                        ok = tb_false;\n                        break;\n                    }\n                    if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {\n                         ok = tb_false;\n                         break;\n                    }\n                    tb_snprintf(output_path, sizeof(output_path), \"%s/%s\", outputdir, output_name);\n                    if (!tb_file_info(output_path, tb_null)) {\n                        break;\n                    }\n                    conflict_id++;\n                }\n                tb_check_break(ok);\n                if (conflict_id >= 10000) {\n                    ok = tb_false;\n                    break;\n                }\n            }\n        } else {\n            if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) {\n                 ok = tb_false;\n                 break;\n            }\n            tb_snprintf(output_path, sizeof(output_path), \"%s/%s\", outputdir, member_name);\n        }\n\n        // ensure directory exists\n        tb_char_t const* p = tb_strrchr(output_path, '/');\n        if (p) {\n            tb_char_t dir[1024];\n            tb_size_t len = p - output_path;\n            if (len < sizeof(dir)) {\n                tb_strncpy(dir, output_path, len);\n                dir[len] = '\\0';\n                if (!tb_file_info(dir, tb_null)) {\n                    if (!tb_directory_create(dir)) {\n                        ok = tb_false;\n                        break;\n                    }\n                }\n            }\n        }\n\n        // write file\n        tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n        if (ostream) {\n            if (tb_stream_open(ostream)) {\n                if (!xm_binutils_stream_copy(istream, ostream, member_size)) {\n                    ok = tb_false;\n                }\n            } else {\n                ok = tb_false;\n            }\n            tb_stream_exit(ostream);\n        } else {\n            ok = tb_false;\n        }\n        tb_check_break(ok);\n\n        // align to 2-byte boundary\n        if (member_size % 2) {\n             if (!tb_stream_skip(istream, 1)) {\n                ok = tb_false;\n                break;\n            }\n        }\n    }\n\n    if (longnames) {\n        tb_free(longnames);\n    }\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/mslib/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_MSLIB_PREFIX_H\n#define XM_BINUTILS_MSLIB_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// MSVC lib header\n#include \"tbox/prefix/packed.h\"\ntypedef struct __xm_mslib_header_t {\n    tb_char_t   name[16];\n    tb_char_t   date[12];\n    tb_char_t   uid[6];\n    tb_char_t   gid[6];\n    tb_char_t   mode[8];\n    tb_char_t   size[10];\n    tb_char_t   fmag[2];\n} __tb_packed__ xm_mslib_header_t;\n#include \"tbox/prefix/packed.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\nstatic __tb_inline__ tb_int64_t xm_binutils_mslib_parse_decimal(tb_char_t const *p, tb_size_t n) {\n    tb_assert_and_check_return_val(p && n > 0, -1);\n    tb_int64_t v = 0;\n    tb_char_t const* e = p + n;\n    while (p < e && *p == ' ') {\n        p++;\n    }\n    while (p < e && *p >= '0' && *p <= '9') {\n        v = v * 10 + (*p - '0');\n        p++;\n    }\n    return v;\n}\n\nstatic __tb_inline__ tb_bool_t xm_binutils_mslib_check_magic(tb_stream_ref_t istream) {\n    tb_char_t magic[8];\n    if (!tb_stream_bread(istream, (tb_byte_t*)magic, 8)) {\n        return tb_false;\n    }\n    return tb_strncmp(magic, \"!<arch>\\n\", 8) == 0;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/mslib/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"mslib_readsyms\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * forward declarations\n */\nextern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nstatic tb_bool_t xm_binutils_mslib_parse_archive_symbols(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {\n    // try to parse as Second Linker Member (LE)\n    tb_hize_t start_pos = tb_stream_offset(istream);\n    tb_uint32_t* offsets = tb_null;\n    tb_uint16_t* indices = tb_null;\n    tb_char_t* string_table = tb_null;\n    tb_bool_t ok = tb_false;\n\n    do {\n        // read number of members\n        tb_uint32_t num_members = 0;\n        if (!tb_stream_bread_u32_le(istream, &num_members)) {\n            break;\n        }\n\n        // sanity check\n        if (num_members == 0 || num_members > 65536 || num_members * 4 >= member_size) {\n            break;\n        }\n\n        // read offsets\n        offsets = tb_nalloc_type(num_members, tb_uint32_t);\n        tb_check_break(offsets);\n\n        tb_size_t i;\n        for (i = 0; i < num_members; i++) {\n            if (!tb_stream_bread_u32_le(istream, &offsets[i])) {\n                break;\n            }\n        }\n        if (i < num_members) {\n            break;\n        }\n\n        // read number of symbols\n        tb_uint32_t num_symbols = 0;\n        if (!tb_stream_bread_u32_le(istream, &num_symbols)) {\n            break;\n        }\n\n        if (num_symbols == 0 || num_symbols > 1000000) {\n            break;\n        }\n\n        // read indices\n        indices = tb_nalloc_type(num_symbols, tb_uint16_t);\n        tb_check_break(indices);\n\n        for (i = 0; i < num_symbols; i++) {\n            if (!tb_stream_bread_u16_le(istream, &indices[i])) {\n                break;\n            }\n        }\n        if (i < num_symbols) {\n            break;\n        }\n\n        // read string table\n        tb_hize_t current = tb_stream_offset(istream);\n        tb_hize_t string_table_size = member_size - (current - start_pos);\n\n        string_table = (tb_char_t*)tb_malloc_bytes((tb_size_t)string_table_size);\n        tb_check_break(string_table);\n\n        if (!tb_stream_bread(istream, (tb_byte_t*)string_table, (tb_size_t)string_table_size)) {\n            break;\n        }\n\n        // populate map\n        tb_char_t* p = string_table;\n        tb_char_t* end = string_table + string_table_size;\n\n        for (i = 0; i < num_symbols; i++) {\n            if (p >= end) {\n                break;\n            }\n\n            tb_char_t* sym_name = p;\n            tb_size_t sym_len = tb_strlen(sym_name);\n            p += sym_len + 1;\n\n            tb_uint16_t idx = indices[i];\n            if (idx > 0 && idx <= num_members) {\n                tb_uint32_t offset = offsets[idx - 1];\n\n                lua_pushinteger(lua, offset);\n                lua_rawget(lua, map_idx);\n                if (lua_isnil(lua, -1)) {\n                    lua_pop(lua, 1);\n                    lua_newtable(lua);\n                    lua_pushinteger(lua, offset);\n                    lua_pushvalue(lua, -2);\n                    lua_rawset(lua, map_idx);\n                }\n                int count = (int)lua_objlen(lua, -1);\n                lua_pushstring(lua, sym_name);\n                lua_rawseti(lua, -2, count + 1);\n                lua_pop(lua, 1); // pop list\n            }\n        }\n        ok = tb_true;\n\n    } while (0);\n\n    if (offsets) {\n        tb_free(offsets);\n    }\n    if (indices) {\n        tb_free(indices);\n    }\n    if (string_table) {\n        tb_free(string_table);\n    }\n\n    if (!ok) {\n        tb_stream_seek(istream, start_pos);\n    }\n    return ok;\n}\n\n/* read symbols from MSVC lib archive\n *\n * @param istream     the input stream\n * @param base_offset the base offset\n * @param lua         the lua state\n * @return            tb_true on success, tb_false on failure\n */\ntb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n\n    // check magic (!<arch>\\n)\n    if (!xm_binutils_mslib_check_magic(istream)) {\n        return tb_false;\n    }\n\n    // create map table (offset -> symbols)\n    lua_newtable(lua);\n    int map_idx = lua_gettop(lua);\n\n    tb_bool_t ok = tb_true;\n    tb_size_t object_count = 0;\n    tb_char_t* longnames = tb_null;\n    tb_size_t  longnames_size = 0;\n\n    // iterate through members\n    while (ok) {\n        // read header\n        xm_mslib_header_t header;\n        if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {\n            // end of file\n            break;\n        }\n\n        // parse member size\n        tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10);\n        if (member_size < 0) {\n            ok = tb_false;\n            break;\n        }\n\n        // parse member name\n        tb_char_t member_name[256] = {0};\n        tb_bool_t is_longname_table = tb_false;\n\n        if (header.name[0] == '/') {\n            if (header.name[1] == '/') {\n                // long name table (//)\n                is_longname_table = tb_true;\n            } else if (tb_isdigit(header.name[1])) {\n                // offset into long name table (/123)\n                tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15);\n                if (offset >= 0 && (tb_size_t)offset < longnames_size) {\n                    /* copy from longnames\n                     * names in longnames are null-terminated\n                     */\n                    tb_strlcpy(member_name, longnames + offset, sizeof(member_name));\n                }\n            } else {\n                 /* symbol table or other special member (/)\n                  * usually symbol table is just \"/\"\n                  */\n                 tb_strlcpy(member_name, \"/\", sizeof(member_name));\n            }\n        } else {\n             // short name, ends with /\n             tb_size_t i = 0;\n             for (i = 0; i < 16 && header.name[i] != '/'; i++) {\n                 member_name[i] = header.name[i];\n             }\n             member_name[i] = '\\0';\n        }\n\n        if (is_longname_table) {\n            longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1);\n            if (!longnames || !tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) {\n                ok = tb_false;\n                break;\n            }\n            longnames[member_size] = '\\0';\n            longnames_size = (tb_size_t)member_size;\n\n            // align\n            if (member_size % 2) {\n                if (!tb_stream_skip(istream, 1)) {\n                    ok = tb_false;\n                    break;\n                }\n            }\n            continue;\n        }\n\n        // check if we should process\n        /* skip empty names, long name table (//) - handled above,\n         * and __.SYMDEF (SysV/BSD style symbol table, just in case)\n         */\n        if (member_name[0] == '\\0' || tb_strcmp(member_name, \"//\") == 0 ||\n            tb_strncmp(member_name, \"__.SYMDEF\", 9) == 0) {\n\n            // skip member data\n            if (!tb_stream_skip(istream, member_size)) {\n                ok = tb_false;\n                break;\n            }\n\n             // align\n            if (member_size % 2) {\n                 if (!tb_stream_skip(istream, 1)) {\n                    ok = tb_false;\n                    break;\n                }\n            }\n            continue;\n        }\n\n        if (tb_strcmp(member_name, \"/\") == 0) {\n             // try to parse archive symbols\n             if (!xm_binutils_mslib_parse_archive_symbols(istream, (tb_hize_t)member_size, lua, map_idx)) {\n                 // if failed, skip member data\n                 if (!tb_stream_skip(istream, member_size)) {\n                    ok = tb_false;\n                    break;\n                 }\n             }\n             // align\n             if (member_size % 2) {\n                  if (!tb_stream_skip(istream, 1)) {\n                     ok = tb_false;\n                     break;\n                 }\n             }\n             continue;\n        }\n\n        // save current position\n        tb_hize_t current_pos = tb_stream_offset(istream);\n        tb_hize_t header_offset = current_pos - sizeof(xm_mslib_header_t);\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) {\n            // create entry table\n            lua_newtable(lua);\n\n            // object name\n            lua_pushstring(lua, \"objectfile\");\n            lua_pushstring(lua, member_name);\n            lua_settable(lua, -3);\n\n            // symbols\n            lua_pushstring(lua, \"symbols\");\n            tb_bool_t read_ok = tb_false;\n            if (format == XM_BINUTILS_FORMAT_COFF) {\n                read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua);\n            } else if (format == XM_BINUTILS_FORMAT_ELF) {\n                read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua);\n            } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n                read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua);\n            }\n\n            // if read failed or empty, try map\n            tb_bool_t has_symbols = tb_false;\n            if (read_ok) {\n                 if (lua_objlen(lua, -1) > 0) {\n                     has_symbols = tb_true;\n                 } else {\n                     lua_pop(lua, 1); // pop empty table\n                 }\n            }\n\n            if (!has_symbols) {\n                // check map\n                lua_pushinteger(lua, (lua_Integer)header_offset);\n                lua_rawget(lua, map_idx);\n                if (lua_istable(lua, -1)) {\n                    // convert list of names to list of {name=..., type=\"global\"}\n                    lua_newtable(lua); // result table\n                    int count = (int)lua_objlen(lua, -2);\n                    for (int i = 1; i <= count; i++) {\n                        lua_rawgeti(lua, -2, i);\n                        const char* name = lua_tostring(lua, -1);\n                        if (name) {\n                            lua_newtable(lua);\n                            lua_pushstring(lua, \"name\");\n                            lua_pushstring(lua, name);\n                            lua_settable(lua, -3);\n\n                            lua_pushstring(lua, \"type\");\n                            lua_pushstring(lua, \"T\");\n                            lua_settable(lua, -3);\n\n                            lua_rawseti(lua, -3, i);\n                        }\n                        lua_pop(lua, 1); // pop name\n                    }\n                    lua_remove(lua, -2); // remove map entry list\n                    has_symbols = tb_true;\n                } else {\n                    lua_pop(lua, 1); // pop nil\n                }\n            }\n\n            if (has_symbols) {\n                lua_settable(lua, -3);\n                lua_rawseti(lua, map_idx - 1, (int)(++object_count));\n            } else {\n                lua_pop(lua, 2); // pop symbols key and entry table\n            }\n        }\n\n        // skip to next member\n        tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos;\n        tb_hize_t remaining_size = (tb_hize_t)member_size - member_data_read;\n\n        if (remaining_size > 0) {\n            if (!tb_stream_skip(istream, remaining_size)) {\n                ok = tb_false;\n                break;\n            }\n        } else if (remaining_size < 0) {\n             if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size)) {\n                ok = tb_false;\n                break;\n             }\n        }\n\n        // align to 2-byte boundary\n        if (member_size % 2) {\n             if (!tb_stream_skip(istream, 1)) {\n                ok = tb_false;\n                break;\n            }\n        }\n    }\n\n    if (longnames) {\n        tb_free(longnames);\n    }\n    lua_remove(lua, map_idx);\n    return ok;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_PREFIX_H\n#define XM_BINUTILS_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_BINUTILS_FORMAT_COFF    1\n#define XM_BINUTILS_FORMAT_ELF     2\n#define XM_BINUTILS_FORMAT_MACHO   3\n#define XM_BINUTILS_FORMAT_AR      4\n#define XM_BINUTILS_FORMAT_PE      5\n#define XM_BINUTILS_FORMAT_SHEBANG 6\n#define XM_BINUTILS_FORMAT_APE     7\n#define XM_BINUTILS_FORMAT_WASM    8\n#define XM_BINUTILS_FORMAT_UNKNOWN 0\n\n// COFF machine types (for format detection)\n#define XM_BINUTILS_COFF_MACHINE_I386    0x014c\n#define XM_BINUTILS_COFF_MACHINE_AMD64   0x8664\n#define XM_BINUTILS_COFF_MACHINE_ARM     0x01c0\n#define XM_BINUTILS_COFF_MACHINE_ARM64   0xaa64\n\n// PE/DOS offsets/signatures (for format detection)\n#define XM_BINUTILS_PE_DOS_STUB_MIN_SIZE  (0x40)\n#define XM_BINUTILS_PE_DOS_ELFANEW_OFFSET (0x3c)\n#define XM_BINUTILS_PE_NT_SIGNATURE       (0x00004550) // \"PE\\0\\0\" little endian\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\ntb_int_t xm_binutils_format_detect(tb_stream_ref_t istream);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n/* read magic bytes from stream (preserves stream position)\n *\n * @param istream    the input stream\n * @param magic      the buffer to store magic bytes (must be at least 4 bytes)\n * @param size       the number of bytes to read (typically 4)\n *\n * @return           tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_read_magic(tb_stream_ref_t istream, tb_uint8_t *magic, tb_size_t size) {\n    tb_assert_and_check_return_val(istream && magic && size > 0, tb_false);\n\n    tb_hize_t saved_pos = tb_stream_offset(istream);\n    if (!tb_stream_seek(istream, 0)) {\n        return tb_false;\n    }\n\n    tb_bool_t ok = tb_false;\n    if (tb_stream_bread(istream, magic, size)) {\n        ok = tb_true;\n    }\n\n    tb_stream_seek(istream, saved_pos);\n    return ok;\n}\n\n/* copy data from input stream to output stream\n *\n * @param istream    the input stream\n * @param ostream    the output stream\n * @param size       the size to copy\n *\n * @return           tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_stream_copy(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_hize_t size) {\n    tb_assert_and_check_return_val(istream && ostream, tb_false);\n    if (size == 0) {\n        return tb_true;\n    }\n\n    tb_byte_t data[TB_STREAM_BLOCK_MAXN];\n    tb_hize_t writ = 0;\n    do {\n        tb_size_t need = (tb_size_t)tb_min(size - writ, (tb_hize_t)TB_STREAM_BLOCK_MAXN);\n        tb_check_break(need);\n\n        if (!tb_stream_bread(istream, data, need)) {\n            return tb_false;\n        }\n        if (!tb_stream_bwrit(ostream, data, need)) {\n            return tb_false;\n        }\n        writ += need;\n\n        tb_check_break(writ < size);\n    } while (1);\n\n    return tb_true;\n}\n\n/* sanitize symbol name (replace non-alphanumeric characters with underscores)\n *\n * @param name       the symbol name\n */\nstatic __tb_inline__ void xm_binutils_sanitize_symbol_name(tb_char_t* name) {\n    tb_assert_and_check_return(name);\n    for (tb_size_t i = 0; name[i]; i++) {\n        if (!tb_isalpha(name[i]) && !tb_isdigit(name[i]) && name[i] != '_') {\n            name[i] = '_';\n        }\n    }\n}\n\n/* read string from stream at specified offset\n *\n * @param istream    the input stream\n * @param offset     the offset to read from\n * @param name       the buffer to store the string\n * @param name_size  the size of the buffer\n *\n * @return           tb_true on success, tb_false on failure\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_read_string(tb_stream_ref_t istream, tb_hize_t offset, tb_char_t *name, tb_size_t name_size) {\n    tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);\n\n    tb_hize_t saved_pos = tb_stream_offset(istream);\n    if (!tb_stream_seek(istream, offset)) {\n        return tb_false;\n    }\n\n    tb_size_t pos = 0;\n    tb_byte_t c;\n    while (pos < name_size - 1) {\n        if (!tb_stream_bread(istream, &c, 1)) {\n            tb_stream_seek(istream, saved_pos);\n            return tb_false;\n        }\n        if (c == 0) {\n            break;\n        }\n        name[pos++] = (tb_char_t)c;\n    }\n    name[pos] = '\\0';\n\n    tb_stream_seek(istream, saved_pos);\n    return tb_true;\n}\n\n/* check if architecture is 64-bit\n *\n * @param arch    the architecture string\n * @return        tb_true if 64-bit, tb_false otherwise\n */\nstatic __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) {\n    if (!arch) {\n        return tb_true;\n    }\n    // x86_64\n    if (tb_strcmp(arch, \"x86_64\") == 0 || tb_strcmp(arch, \"x64\") == 0) {\n        return tb_true;\n    }\n    // ARM64\n    else if (tb_strcmp(arch, \"arm64\") == 0 || tb_strcmp(arch, \"aarch64\") == 0 ||\n             tb_strcmp(arch, \"arm64-v8a\") == 0) {\n        return tb_true;\n    }\n    // MIPS64\n    else if (tb_strncmp(arch, \"mips64\", 6) == 0) {\n        return tb_true;\n    }\n    // PowerPC64\n    else if (tb_strncmp(arch, \"ppc64\", 5) == 0 || tb_strncmp(arch, \"powerpc64\", 9) == 0) {\n        return tb_true;\n    }\n    // RISC-V 64\n    else if (tb_strncmp(arch, \"riscv64\", 7) == 0 ||\n             (tb_strncmp(arch, \"riscv\", 5) == 0 && tb_strstr(arch, \"64\"))) {\n        return tb_true;\n    }\n    // SPARC64\n    else if (tb_strncmp(arch, \"sparc64\", 7) == 0) {\n        return tb_true;\n    }\n    // s390x\n    else if (tb_strcmp(arch, \"s390x\") == 0) {\n        return tb_true;\n    }\n    // LoongArch64\n    else if (tb_strncmp(arch, \"loongarch64\", 11) == 0) {\n        return tb_true;\n    }\n    // WebAssembly 64\n    else if (tb_strcmp(arch, \"wasm64\") == 0) {\n        return tb_true;\n    }\n    // IA-64\n    else if (tb_strcmp(arch, \"ia64\") == 0 || tb_strcmp(arch, \"itanium\") == 0) {\n        return tb_true;\n    }\n    return tb_false;\n}\n\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readsyms\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"coff/prefix.h\"\n#include \"elf/prefix.h\"\n#include \"macho/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * forward declarations\n */\nextern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\nextern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* read symbols from object file (auto-detect format)\n *\n * @param lua the lua state\n * @return 1 on success (table on stack), 2 on failure (with error message on stack)\n */\ntb_int_t xm_binutils_readsyms(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the object file path\n    tb_char_t const *objectfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(objectfile, 0);\n\n    // open file\n    tb_stream_ref_t istream = tb_stream_init_from_file(objectfile, TB_FILE_MODE_RO);\n    if (!istream) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"open %s failed\", objectfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"open %s failed\", objectfile);\n            break;\n        }\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"cannot detect file format\");\n            break;\n        }\n        \n        // create result list\n        lua_newtable(lua);\n\n        // read symbols based on format\n        if (format == XM_BINUTILS_FORMAT_AR) {\n            // AR archive (.a or .lib)\n            tb_bool_t is_mslib = tb_false;\n            if (objectfile) {\n                tb_size_t len = tb_strlen(objectfile);\n                if (len > 4 && tb_stricmp(objectfile + len - 4, \".lib\") == 0) {\n                    is_mslib = tb_true;\n                }\n            }\n\n            if (is_mslib) {\n                 if (!xm_binutils_mslib_read_symbols(istream, 0, lua)) {\n                     // fallback to ar\n                     if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {\n                        lua_pushboolean(lua, tb_false);\n                        lua_pushfstring(lua, \"read AR/MSLIB archive symbols failed\");\n                        break;\n                     }\n                 }\n            } else {\n                if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {\n                    lua_pushboolean(lua, tb_false);\n                    lua_pushfstring(lua, \"read AR archive symbols failed\");\n                    break;\n                }\n            }\n        } else {\n            // single object file (COFF, ELF, Mach-O)\n            // create entry table\n            lua_newtable(lua);\n\n            // object name\n            lua_pushstring(lua, \"objectfile\");\n            tb_char_t const* name = tb_strrchr(objectfile, '/');\n            if (!name) {\n                name = tb_strrchr(objectfile, '\\\\');\n            }\n            if (!name) {\n                name = objectfile;\n            } else {\n                name++;\n            }\n            lua_pushstring(lua, name);\n            lua_settable(lua, -3);\n\n            // symbols\n            lua_pushstring(lua, \"symbols\");\n            tb_bool_t read_ok = tb_false;\n            if (format == XM_BINUTILS_FORMAT_COFF) {\n                read_ok = xm_binutils_coff_read_symbols(istream, 0, lua);\n            } else if (format == XM_BINUTILS_FORMAT_ELF) {\n                read_ok = xm_binutils_elf_read_symbols(istream, 0, lua);\n            } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n                read_ok = xm_binutils_macho_read_symbols(istream, 0, lua);\n            } else if (format == XM_BINUTILS_FORMAT_WASM) {\n                read_ok = xm_binutils_wasm_read_symbols(istream, 0, lua);\n            }\n\n            if (read_ok) {\n                lua_settable(lua, -3);\n                lua_rawseti(lua, -2, 1);\n            } else {\n                lua_pop(lua, 2); // pop entry table and result list\n                lua_pushboolean(lua, tb_false);\n                lua_pushfstring(lua, \"read symbols failed\");\n                break;\n            }\n        }\n\n        ok = tb_true;\n    } while (0);\n\n    if (istream) {\n        tb_stream_clos(istream);\n    }\n    istream = tb_null;\n\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/rpath.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rpath.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rpath\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"elf/prefix.h\"\n#include \"macho/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\ntb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\ntb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);\n\ntb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset);\ntb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get rpath list from binary file (auto-detect format)\n *\n * @param lua the lua state\n * @return 1 on success (table on stack), 2 on failure (with error message on stack)\n */\ntb_int_t xm_binutils_rpath_list(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the binary file path\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // open file\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);\n    if (!istream) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"rpath_list: open %s failed\", binaryfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"rpath_list: open %s failed\", binaryfile);\n            break;\n        }\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"rpath_list: cannot detect file format\");\n            break;\n        }\n\n        // create result list\n        lua_newtable(lua);\n\n        // get rpath list based on format\n        if (format == XM_BINUTILS_FORMAT_ELF) {\n            if (!xm_binutils_elf_rpath_list(istream, 0, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"rpath_list: failed to parse ELF\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n            if (!xm_binutils_macho_rpath_list(istream, 0, lua)) {\n                 lua_pop(lua, 1); // pop table\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"rpath_list: failed to parse Mach-O\");\n                 break;\n            }\n        } else {\n            /* not supported or no rpath for this format\n             * return empty table\n             */\n        }\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (istream) tb_stream_exit(istream);\n    return ok ? 1 : 2;\n}\n\n/* clean all rpaths from binary file\n *\n * @param lua the lua state\n * @return 1 on success, 2 on failure\n */\ntb_int_t xm_binutils_rpath_clean(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get arguments\n    tb_char_t const *binaryfile = luaL_checkstring(lua, 1);\n    tb_check_return_val(binaryfile, 0);\n\n    // open file\n    tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RW);\n    if (!istream) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"rpath_clean: open %s failed\", binaryfile);\n        return 2;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        if (!tb_stream_open(istream)) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"rpath_clean: open %s failed\", binaryfile);\n            break;\n        }\n\n        // detect format\n        tb_int_t format = xm_binutils_format_detect(istream);\n        if (format < 0) {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"rpath_clean: cannot detect file format\");\n            break;\n        }\n\n        // clean rpath\n        if (format == XM_BINUTILS_FORMAT_ELF) {\n            if (!xm_binutils_elf_rpath_clean(istream, 0)) {\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"rpath_clean: failed to clean ELF\");\n                 break;\n            }\n        } else if (format == XM_BINUTILS_FORMAT_MACHO) {\n            if (!xm_binutils_macho_rpath_clean(istream, 0)) {\n                 lua_pushboolean(lua, tb_false);\n                 lua_pushfstring(lua, \"rpath_clean: failed to clean Mach-O\");\n                 break;\n            }\n        } else {\n            lua_pushboolean(lua, tb_false);\n            lua_pushfstring(lua, \"rpath_clean: format not supported\");\n            break;\n        }\n\n        lua_pushboolean(lua, tb_true);\n        ok = tb_true;\n\n    } while (0);\n\n    if (istream) tb_stream_exit(istream);\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/binutils/wasm/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BINUTILS_WASM_PREFIX_H\n#define XM_BINUTILS_WASM_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// wasm file magic: \\0asm\n#define XM_WASM_MAGIC0         0x00\n#define XM_WASM_MAGIC1         0x61\n#define XM_WASM_MAGIC2         0x73\n#define XM_WASM_MAGIC3         0x6d\n\n// wasm header size: magic(4) + version(4)\n#define XM_WASM_HEADER_SIZE    8\n\n// wasm section ids\n#define XM_WASM_SECTION_IMPORT 2\n#define XM_WASM_SECTION_EXPORT 7\n\n// wasm custom section names\n#define XM_WASM_CUSTOM_LINKING \"linking\"\n#define XM_WASM_CUSTOM_NAME    \"name\"\n\n// wasm import/export kinds\n#define XM_WASM_KIND_FUNC      0\n#define XM_WASM_KIND_TABLE     1\n#define XM_WASM_KIND_MEMORY    2\n#define XM_WASM_KIND_GLOBAL    3\n#define XM_WASM_KIND_TAG       4\n\n// wasm limits flags\n#define XM_WASM_LIMITS_HAS_MAX 0x01\n#define XM_WASM_LIMITS_MEM64   0x04\n\n// leb128 max bytes\n#define XM_WASM_U32_LEB_MAX    5\n#define XM_WASM_U64_LEB_MAX    10\n\n// linking custom section\n#define XM_WASM_LINKING_VERSION_2         2\n#define XM_WASM_LINKING_SUBSEC_SYMTAB     8\n\n// symbol table kinds (linking section)\n#define XM_WASM_SYMTAB_KIND_FUNCTION      0\n#define XM_WASM_SYMTAB_KIND_DATA          1\n#define XM_WASM_SYMTAB_KIND_GLOBAL        2\n#define XM_WASM_SYMTAB_KIND_SECTION       3\n#define XM_WASM_SYMTAB_KIND_EVENT         4\n#define XM_WASM_SYMTAB_KIND_TABLE         5\n#define XM_WASM_SYMTAB_KIND_TAG           6\n\n// symbol table flags (linking section)\n#define XM_WASM_SYMTAB_FLAG_UNDEFINED     0x10\n\n// symbol types for binutils.readsyms\n#define XM_WASM_SYM_UNDEF      \"U\"\n#define XM_WASM_SYM_TEXT       \"T\"\n#define XM_WASM_SYM_DATA       \"D\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline implementation\n */\n\n// decode unsigned leb128 (u32) from current stream offset\nstatic __tb_inline__ tb_bool_t xm_binutils_wasm_read_u32_leb(tb_stream_ref_t istream, tb_uint32_t* out) {\n    tb_uint32_t result = 0;\n    tb_uint32_t shift = 0;\n    tb_byte_t byte = 0;\n    for (tb_size_t i = 0; i < XM_WASM_U32_LEB_MAX; i++) {\n        if (!tb_stream_bread(istream, &byte, 1)) {\n            return tb_false;\n        }\n        result |= ((tb_uint32_t)(byte & 0x7f)) << shift;\n        if (!(byte & 0x80)) {\n            *out = result;\n            return tb_true;\n        }\n        shift += 7;\n    }\n    return tb_false;\n}\n\n// decode unsigned leb128 (u64) from current stream offset\nstatic __tb_inline__ tb_bool_t xm_binutils_wasm_read_u64_leb(tb_stream_ref_t istream, tb_uint64_t* out) {\n    tb_uint64_t result = 0;\n    tb_uint32_t shift = 0;\n    tb_byte_t byte = 0;\n    for (tb_size_t i = 0; i < XM_WASM_U64_LEB_MAX; i++) {\n        if (!tb_stream_bread(istream, &byte, 1)) {\n            return tb_false;\n        }\n        result |= ((tb_uint64_t)(byte & 0x7f)) << shift;\n        if (!(byte & 0x80)) {\n            *out = result;\n            return tb_true;\n        }\n        shift += 7;\n    }\n    return tb_false;\n}\n\n// read wasm \"name\" (u32 leb length + bytes), truncate to fit buffer and skip remaining bytes\nstatic __tb_inline__ tb_bool_t xm_binutils_wasm_read_name(tb_stream_ref_t istream, tb_char_t* name, tb_size_t name_size) {\n    tb_uint32_t len = 0;\n    if (!xm_binutils_wasm_read_u32_leb(istream, &len)) {\n        return tb_false;\n    }\n    tb_size_t readn = (tb_size_t)tb_min((tb_uint32_t)(name_size > 0 ? name_size - 1 : 0), len);\n    if (readn && !tb_stream_bread(istream, (tb_byte_t*)name, readn)) {\n        return tb_false;\n    }\n    if (name_size) {\n        name[readn] = '\\0';\n    }\n    if (len > readn) {\n        if (!tb_stream_skip(istream, (tb_hize_t)(len - readn))) {\n            return tb_false;\n        }\n    }\n    return tb_true;\n}\n\n// skip wasm limits used by table/memory types, supports wasm32 and wasm64(memory64)\nstatic __tb_inline__ tb_bool_t xm_binutils_wasm_skip_limits(tb_stream_ref_t istream) {\n    tb_uint32_t flags = 0;\n    if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) {\n        return tb_false;\n    }\n    if (flags & XM_WASM_LIMITS_MEM64) {\n        tb_uint64_t tmp64 = 0;\n        if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) {\n            return tb_false;\n        }\n        if (flags & XM_WASM_LIMITS_HAS_MAX) {\n            if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) {\n                return tb_false;\n            }\n        }\n    } else {\n        tb_uint32_t tmp32 = 0;\n        if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) {\n            return tb_false;\n        }\n        if (flags & XM_WASM_LIMITS_HAS_MAX) {\n            if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) {\n                return tb_false;\n            }\n        }\n    }\n    return tb_true;\n}\n\n// add one symbol table entry: {name=..., type=...}\nstatic __tb_inline__ tb_void_t xm_binutils_wasm_add_symbol(lua_State* lua, tb_size_t* result_count, tb_char_t const* name, tb_char_t const* type) {\n    lua_pushinteger(lua, (lua_Integer)(*result_count + 1));\n    lua_newtable(lua);\n\n    lua_pushstring(lua, \"name\");\n    lua_pushstring(lua, name);\n    lua_settable(lua, -3);\n\n    lua_pushstring(lua, \"type\");\n    lua_pushstring(lua, type);\n    lua_settable(lua, -3);\n\n    lua_settable(lua, -3);\n    (*result_count)++;\n}\n\n// seek and validate wasm header at base_offset, leave stream offset after header\nstatic __tb_inline__ tb_bool_t xm_binutils_wasm_check_header(tb_stream_ref_t istream, tb_hize_t base_offset) {\n    if (!tb_stream_seek(istream, base_offset)) {\n        return tb_false;\n    }\n\n    tb_uint8_t header[XM_WASM_HEADER_SIZE];\n    if (!tb_stream_bread(istream, header, XM_WASM_HEADER_SIZE)) {\n        return tb_false;\n    }\n    if (header[0] != XM_WASM_MAGIC0 || header[1] != XM_WASM_MAGIC1 || header[2] != XM_WASM_MAGIC2 || header[3] != XM_WASM_MAGIC3) {\n        return tb_false;\n    }\n    return tb_true;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/binutils/wasm/readsyms.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readsyms.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"wasm_readsyms\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nstatic tb_bool_t xm_binutils_wasm_parse_linking_symtab(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {\n    tb_uint32_t symcount = 0;\n    if (!xm_binutils_wasm_read_u32_leb(istream, &symcount)) {\n        return tb_false;\n    }\n\n    for (tb_uint32_t i = 0; i < symcount; i++) {\n        tb_byte_t kind = 0;\n        if (!tb_stream_bread(istream, &kind, 1)) {\n            return tb_false;\n        }\n\n        tb_uint32_t flags = 0;\n        if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) {\n            return tb_false;\n        }\n\n        tb_bool_t is_undef = (flags & XM_WASM_SYMTAB_FLAG_UNDEFINED) != 0;\n        tb_char_t name[256] = {0};\n\n        if (kind == XM_WASM_SYMTAB_KIND_FUNCTION || kind == XM_WASM_SYMTAB_KIND_GLOBAL ||\n            kind == XM_WASM_SYMTAB_KIND_EVENT || kind == XM_WASM_SYMTAB_KIND_TABLE ||\n            kind == XM_WASM_SYMTAB_KIND_TAG) {\n\n            if (!is_undef) {\n                tb_uint32_t index = 0;\n                if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {\n                    return tb_false;\n                }\n            }\n            if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {\n                return tb_false;\n            }\n        } else if (kind == XM_WASM_SYMTAB_KIND_DATA) {\n            if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {\n                return tb_false;\n            }\n            if (!is_undef) {\n                tb_uint32_t tmp = 0;\n                if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // segment\n                    return tb_false;\n                }\n                if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // offset\n                    return tb_false;\n                }\n                if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // size\n                    return tb_false;\n                }\n            }\n        } else if (kind == XM_WASM_SYMTAB_KIND_SECTION) {\n            tb_uint32_t section_index = 0;\n            if (!xm_binutils_wasm_read_u32_leb(istream, &section_index)) {\n                return tb_false;\n            }\n            if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {\n                return tb_false;\n            }\n        } else {\n            return tb_false;\n        }\n\n        if (name[0]) {\n            tb_char_t const* type = XM_WASM_SYM_DATA;\n            if (is_undef) {\n                type = XM_WASM_SYM_UNDEF;\n            } else if (kind == XM_WASM_SYMTAB_KIND_FUNCTION) {\n                type = XM_WASM_SYM_TEXT;\n            }\n            xm_binutils_wasm_add_symbol(lua, result_count, name, type);\n        }\n\n        if (tb_stream_offset(istream) > payload_end) {\n            return tb_false;\n        }\n    }\n    return tb_true;\n}\n\nstatic tb_bool_t xm_binutils_wasm_parse_custom_linking(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {\n    tb_uint32_t version = 0;\n    if (!xm_binutils_wasm_read_u32_leb(istream, &version)) {\n        return tb_false;\n    }\n\n    while (tb_stream_offset(istream) < payload_end) {\n        tb_byte_t subsec_type = 0;\n        if (!tb_stream_bread(istream, &subsec_type, 1)) {\n            return tb_false;\n        }\n\n        tb_uint32_t subsec_size = 0;\n        if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) {\n            return tb_false;\n        }\n\n        tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size;\n        if (subsec_end > payload_end) {\n            return tb_false;\n        }\n\n        if (subsec_type == XM_WASM_LINKING_SUBSEC_SYMTAB) {\n            if (!xm_binutils_wasm_parse_linking_symtab(istream, subsec_end, lua, result_count)) {\n                return tb_false;\n            }\n        }\n\n        if (tb_stream_offset(istream) < subsec_end) {\n            if (!tb_stream_seek(istream, subsec_end)) {\n                return tb_false;\n            }\n        }\n    }\n\n    return version > 0 ? tb_true : tb_false;\n}\n\nstatic tb_bool_t xm_binutils_wasm_parse_custom_name(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {\n    // only use the name section as a fallback when we have no symbols yet\n    if (*result_count != 0) {\n        return tb_true;\n    }\n\n    while (tb_stream_offset(istream) < payload_end) {\n        tb_byte_t subsec_type = 0;\n        if (!tb_stream_bread(istream, &subsec_type, 1)) {\n            return tb_false;\n        }\n        tb_uint32_t subsec_size = 0;\n        if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) {\n            return tb_false;\n        }\n        tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size;\n        if (subsec_end > payload_end) {\n            return tb_false;\n        }\n\n        if (subsec_type == 1) {\n            tb_uint32_t count = 0;\n            if (!xm_binutils_wasm_read_u32_leb(istream, &count)) {\n                return tb_false;\n            }\n            for (tb_uint32_t i = 0; i < count; i++) {\n                tb_uint32_t index = 0;\n                if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {\n                    return tb_false;\n                }\n                tb_char_t name[256] = {0};\n                if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {\n                    return tb_false;\n                }\n                if (name[0]) {\n                    xm_binutils_wasm_add_symbol(lua, result_count, name, XM_WASM_SYM_TEXT);\n                }\n                if (tb_stream_offset(istream) > subsec_end) {\n                    return tb_false;\n                }\n            }\n        }\n\n        if (tb_stream_offset(istream) < subsec_end) {\n            if (!tb_stream_seek(istream, subsec_end)) {\n                return tb_false;\n            }\n        }\n    }\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\ntb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {\n    tb_assert_and_check_return_val(istream && lua, tb_false);\n    if (!xm_binutils_wasm_check_header(istream, base_offset)) {\n        return tb_false;\n    }\n\n    lua_newtable(lua);\n    tb_size_t result_count = 0;\n\n    // parse wasm sections until EOF, collect imports/exports as symbols\n    for (;;) {\n        tb_byte_t section_id = 0;\n        if (!tb_stream_bread(istream, &section_id, 1)) {\n            break;\n        }\n\n        tb_uint32_t payload_len = 0;\n        if (!xm_binutils_wasm_read_u32_leb(istream, &payload_len)) {\n            break;\n        }\n\n        tb_hize_t payload_start = tb_stream_offset(istream);\n        tb_hize_t payload_end = payload_start + (tb_hize_t)payload_len;\n        if (payload_len == 0) {\n            continue;\n        }\n\n        if (section_id == 0) {\n            // custom section: name + custom payload\n            tb_char_t custom_name[64] = {0};\n            if (!xm_binutils_wasm_read_name(istream, custom_name, sizeof(custom_name))) {\n                break;\n            }\n\n            if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_LINKING)) {\n                if (!xm_binutils_wasm_parse_custom_linking(istream, payload_end, lua, &result_count)) {\n                    break;\n                }\n            } else if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_NAME)) {\n                if (!xm_binutils_wasm_parse_custom_name(istream, payload_end, lua, &result_count)) {\n                    break;\n                }\n            }\n        } else if (section_id == XM_WASM_SECTION_IMPORT) {\n            // import section: (vec import), each import => undefined symbol\n            tb_uint32_t count = 0;\n            if (xm_binutils_wasm_read_u32_leb(istream, &count)) {\n                for (tb_uint32_t i = 0; i < count; i++) {\n                    tb_char_t module[256] = {0};\n                    tb_char_t field[256] = {0};\n                    if (!xm_binutils_wasm_read_name(istream, module, sizeof(module))) {\n                        break;\n                    }\n                    if (!xm_binutils_wasm_read_name(istream, field, sizeof(field))) {\n                        break;\n                    }\n                    tb_byte_t kind = 0;\n                    if (!tb_stream_bread(istream, &kind, 1)) {\n                        break;\n                    }\n                    tb_uint32_t tmp = 0;\n                    if (kind == XM_WASM_KIND_FUNC) {\n                        // type index (u32)\n                        if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) {\n                            break;\n                        }\n                    } else if (kind == XM_WASM_KIND_TABLE) {\n                        // table type: elemtype + limits\n                        if (!tb_stream_bread(istream, (tb_byte_t*)&kind, 1)) {\n                            break;\n                        }\n                        if (!xm_binutils_wasm_skip_limits(istream)) {\n                            break;\n                        }\n                    } else if (kind == XM_WASM_KIND_MEMORY) {\n                        // memory type: limits\n                        if (!xm_binutils_wasm_skip_limits(istream)) {\n                            break;\n                        }\n                    } else if (kind == XM_WASM_KIND_GLOBAL) {\n                        // global type: valtype + mut\n                        tb_byte_t b = 0;\n                        if (!tb_stream_bread(istream, &b, 1)) {\n                            break;\n                        }\n                        if (!tb_stream_bread(istream, &b, 1)) {\n                            break;\n                        }\n                    } else if (kind == XM_WASM_KIND_TAG) {\n                        // tag: attribute + type index\n                        if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) {\n                            break;\n                        }\n                    } else {\n                        break;\n                    }\n\n                    // keep consistent with nm-style output: use the imported field name as symbol name\n                    if (field[0]) {\n                        xm_binutils_wasm_add_symbol(lua, &result_count, field, XM_WASM_SYM_UNDEF);\n                    } else if (module[0]) {\n                        xm_binutils_wasm_add_symbol(lua, &result_count, module, XM_WASM_SYM_UNDEF);\n                    }\n                }\n            }\n        } else if (section_id == XM_WASM_SECTION_EXPORT) {\n            // export section: (vec export), each export => defined symbol\n            tb_uint32_t count = 0;\n            if (xm_binutils_wasm_read_u32_leb(istream, &count)) {\n                for (tb_uint32_t i = 0; i < count; i++) {\n                    tb_char_t name[256] = {0};\n                    if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {\n                        break;\n                    }\n                    tb_byte_t kind = 0;\n                    if (!tb_stream_bread(istream, &kind, 1)) {\n                        break;\n                    }\n                    tb_uint32_t index = 0;\n                    if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {\n                        break;\n                    }\n                    if (name[0]) {\n                        // keep consistent with other formats: function => \"T\", others => \"D\"\n                        tb_char_t const* type = XM_WASM_SYM_DATA;\n                        if (kind == XM_WASM_KIND_FUNC) {\n                            type = XM_WASM_SYM_TEXT;\n                        }\n                        xm_binutils_wasm_add_symbol(lua, &result_count, name, type);\n                    }\n                }\n            }\n        }\n\n        // always seek to end of section payload to continue scanning\n        if (tb_stream_offset(istream) < payload_end) {\n            if (!tb_stream_seek(istream, payload_end)) {\n                break;\n            }\n        }\n    }\n\n    return tb_true;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_clear.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_clear.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_clear\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_clear(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // clear filter\n    tb_bloom_filter_clear(filter);\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // exit filter\n    tb_bloom_filter_exit(filter);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_data.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_data.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_data\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_data(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // get data\n    tb_pointer_t data = (tb_pointer_t)tb_bloom_filter_data(filter);\n    if (data) {\n        xm_lua_pushpointer(lua, data);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_data_set.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_data_set.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_data_set\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_data_set(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // set data\n    tb_bool_t ok = tb_bloom_filter_data_set(filter, data, size);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_get.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_get.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_get\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_get(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // get item\n    tb_char_t const *item = luaL_checkstring(lua, 2);\n    tb_assert_and_check_return_val(item, 0);\n\n    // get item\n    tb_bool_t ok = tb_bloom_filter_get(filter, item);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get arguments\n    tb_int_t probability = (tb_int_t)lua_tointeger(lua, 1);\n    tb_int_t hash_count  = (tb_int_t)lua_tointeger(lua, 2);\n    tb_int_t item_maxn   = (tb_int_t)lua_tointeger(lua, 3);\n    if (hash_count > 16 || item_maxn < 0) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid hash count(%p) and item maxn(%d)!\", hash_count, item_maxn);\n        return 2;\n    }\n\n    // init the bloom filter\n    tb_bloom_filter_ref_t filter = tb_bloom_filter_init(probability, hash_count, item_maxn, tb_element_str(tb_true));\n    if (filter) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)filter);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_set.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_set.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_set\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_set(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // get item\n    tb_char_t const *item = luaL_checkstring(lua, 2);\n    tb_assert_and_check_return_val(item, 0);\n\n    // set item\n    tb_bool_t ok = tb_bloom_filter_set(filter, item);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/bloom_filter_size.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        bloom_filter_size.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"bloom_filter_size\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_bloom_filter_size(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the bloom filter\n    tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(filter, 0);\n\n    // get size\n    tb_size_t size = tb_bloom_filter_size(filter);\n    lua_pushinteger(lua, (tb_int_t)size);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/bloom_filter/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except idata compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to idata writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_BLOOM_FILTER_PREFIX_H\n#define XM_BLOOM_FILTER_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/config.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        config.h\n *\n */\n#ifndef XM_CORE_CONFIG_H\n#define XM_CORE_CONFIG_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmake.config.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/curses/curses.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        curses.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"curses\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#ifdef XM_CONFIG_API_HAVE_CURSES\n#include \"prefix.h\"\n#include <stdlib.h>\n#if defined(PDCURSES)\n// fix macro redefinition\n#undef MOUSE_MOVED\n#endif\n#define NCURSES_MOUSE_VERSION 2\n#ifdef TB_COMPILER_IS_MINGW\n#include <ncursesw/curses.h>\n#else\n#include <curses.h>\n#endif\n#if defined(NCURSES_VERSION)\n#include <locale.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n#define XM_CURSES_STDSCR \"curses.stdscr\"\n#define XM_CURSES_WINDOW \"curses.window\"\n#define XM_CURSES_OK(v) (((v) == ERR) ? 0 : 1)\n\n// define functions\n#define XM_CURSES_NUMBER(n)                                                                                            \\\n    static int xm_curses_##n(lua_State *lua) {                                                                         \\\n        lua_pushnumber(lua, n());                                                                                      \\\n        return 1;                                                                                                      \\\n    }\n\n#define XM_CURSES_NUMBER2(n, v)                                                                                        \\\n    static int xm_curses_##n(lua_State *lua) {                                                                         \\\n        lua_pushnumber(lua, v);                                                                                        \\\n        return 1;                                                                                                      \\\n    }\n\n#define XM_CURSES_BOOL(n)                                                                                              \\\n    static int xm_curses_##n(lua_State *lua) {                                                                         \\\n        lua_pushboolean(lua, n());                                                                                     \\\n        return 1;                                                                                                      \\\n    }\n\n#define XM_CURSES_BOOLOK(n)                                                                                            \\\n    static int xm_curses_##n(lua_State *lua) {                                                                         \\\n        lua_pushboolean(lua, XM_CURSES_OK(n()));                                                                       \\\n        return 1;                                                                                                      \\\n    }\n\n#define XM_CURSES_WINDOW_BOOLOK(n)                                                                                     \\\n    static int xm_curses_window_##n(lua_State *lua) {                                                                  \\\n        WINDOW *w = xm_curses_window_check(lua, 1);                                                                    \\\n        lua_pushboolean(lua, XM_CURSES_OK(n(w)));                                                                      \\\n        return 1;                                                                                                      \\\n    }\n\n// define constants\n#define XM_CURSES_CONST_(n, v)                                                                                         \\\n    lua_pushstring(lua, n);                                                                                            \\\n    lua_pushnumber(lua, v);                                                                                            \\\n    lua_settable(lua, lua_upvalueindex(1));\n\n#define XM_CURSES_CONST(s) XM_CURSES_CONST_(#s, s)\n#define XM_CURSES_CONST2(s, v) XM_CURSES_CONST_(#s, v)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\n\n// map key for pdcurses, keeping the keys consistent with ncurses\nstatic int g_mapkey = 0;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic chtype xm_curses_checkch(lua_State *lua, int index) {\n    if (lua_type(lua, index) == LUA_TNUMBER) {\n        return (chtype)luaL_checknumber(lua, index);\n    }\n    if (lua_type(lua, index) == LUA_TSTRING) {\n        return *lua_tostring(lua, index);\n    }\n#ifdef USE_LUAJIT\n    luaL_typerror(lua, index, \"chtype\");\n#endif\n    return (chtype)0;\n}\n\n// get character and map key\nstatic int xm_curses_window_getch_impl(WINDOW *w) {\n#ifdef PDCURSES\n    static int has_key  = 0;\n    static int temp_key = 0;\n\n    int key;\n    if (g_mapkey && has_key) {\n        has_key = 0;\n        return temp_key;\n    }\n\n    key = wgetch(w);\n    if (key == KEY_RESIZE)\n        resize_term(0, 0);\n    if (key == ERR || !g_mapkey)\n        return key;\n    if (key >= ALT_A && key <= ALT_Z) {\n        has_key  = 1;\n        temp_key = key - ALT_A + 'A';\n    } else if (key >= ALT_0 && key <= ALT_9) {\n        has_key  = 1;\n        temp_key = key - ALT_0 + '0';\n    } else {\n        switch (key) {\n        case ALT_DEL:\n            temp_key = KEY_DC;\n            break;\n        case ALT_INS:\n            temp_key = KEY_IC;\n            break;\n        case ALT_HOME:\n            temp_key = KEY_HOME;\n            break;\n        case ALT_END:\n            temp_key = KEY_END;\n            break;\n        case ALT_PGUP:\n            temp_key = KEY_PPAGE;\n            break;\n        case ALT_PGDN:\n            temp_key = KEY_NPAGE;\n            break;\n        case ALT_UP:\n            temp_key = KEY_UP;\n            break;\n        case ALT_DOWN:\n            temp_key = KEY_DOWN;\n            break;\n        case ALT_RIGHT:\n            temp_key = KEY_RIGHT;\n            break;\n        case ALT_LEFT:\n            temp_key = KEY_LEFT;\n            break;\n        case ALT_BKSP:\n            temp_key = KEY_BACKSPACE;\n            break;\n        default:\n            return key;\n        }\n    }\n    has_key = 1;\n    return 27;\n#else\n    return wgetch(w);\n#endif\n}\n\n// new a window object\nstatic void xm_curses_window_new(lua_State *lua, WINDOW *nw) {\n    if (nw) {\n        WINDOW **w = (WINDOW **)lua_newuserdata(lua, sizeof(WINDOW *));\n        luaL_getmetatable(lua, XM_CURSES_WINDOW);\n        lua_setmetatable(lua, -2);\n        *w = nw;\n    } else {\n        lua_pushliteral(lua, \"failed to create window\");\n        lua_error(lua);\n    }\n}\n\n// get window\nstatic WINDOW **xm_curses_window_get(lua_State *lua, int index) {\n    WINDOW **w = (WINDOW **)luaL_checkudata(lua, index, XM_CURSES_WINDOW);\n    if (w == NULL)\n        luaL_argerror(lua, index, \"bad curses window\");\n    return w;\n}\n\n// get and check window\nstatic WINDOW *xm_curses_window_check(lua_State *lua, int index) {\n    WINDOW **w = xm_curses_window_get(lua, index);\n    if (*w == NULL)\n        luaL_argerror(lua, index, \"attempt to use closed curses window\");\n    return *w;\n}\n\n// tostring(window)\nstatic int xm_curses_window_tostring(lua_State *lua) {\n    WINDOW **w = xm_curses_window_get(lua, 1);\n    char const *s = NULL;\n    if (*w)\n        s = (char const *)lua_touserdata(lua, 1);\n    lua_pushfstring(lua, \"curses window (%s)\", s ? s : \"closed\");\n    return 1;\n}\n\n// window:move(y, x)\nstatic int xm_curses_window_move(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int y = luaL_checkint(lua, 2);\n    int x = luaL_checkint(lua, 3);\n    lua_pushboolean(lua, XM_CURSES_OK(wmove(w, y, x)));\n    return 1;\n}\n\n// window:getyx(y, x)\nstatic int xm_curses_window_getyx(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int y, x;\n    getyx(w, y, x);\n    lua_pushnumber(lua, y);\n    lua_pushnumber(lua, x);\n    return 2;\n}\n\n// window:getmaxyx(y, x)\nstatic int xm_curses_window_getmaxyx(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int y, x;\n    getmaxyx(w, y, x);\n    lua_pushnumber(lua, y);\n    lua_pushnumber(lua, x);\n    return 2;\n}\n\n// window:delwin()\nstatic int xm_curses_window_delwin(lua_State *lua) {\n    WINDOW **w = xm_curses_window_get(lua, 1);\n    if (*w && *w != stdscr) {\n        delwin(*w);\n        *w = NULL;\n    }\n    return 0;\n}\n\n// window:addch(ch)\nstatic int xm_curses_window_addch(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    chtype ch = xm_curses_checkch(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(waddch(w, ch)));\n    return 1;\n}\n\n// window:addnstr(str)\nstatic int xm_curses_window_addnstr(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    const char *str = luaL_checkstring(lua, 2);\n    int n = luaL_optint(lua, 3, -1);\n    if (n < 0)\n        n = (int)lua_strlen(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(waddnstr(w, str, n)));\n    return 1;\n}\n\n// window:keypad(true)\nstatic int xm_curses_window_keypad(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2);\n    if (enabled) {\n        // on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys,\n        // only makes sense when using keypad(true) and echo(false)\n        g_mapkey = 1;\n    }\n    lua_pushboolean(lua, XM_CURSES_OK(keypad(w, enabled)));\n    return 1;\n}\n\n// window:meta(true)\nstatic int xm_curses_window_meta(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int enabled = lua_toboolean(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(meta(w, enabled)));\n    return 1;\n}\n\n// window:nodelay(true)\nstatic int xm_curses_window_nodelay(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int enabled = lua_toboolean(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(nodelay(w, enabled)));\n    return 1;\n}\n\n// window:leaveok(true)\nstatic int xm_curses_window_leaveok(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int enabled = lua_toboolean(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(leaveok(w, enabled)));\n    return 1;\n}\n\n// window:getch()\nstatic int xm_curses_window_getch(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int c = xm_curses_window_getch_impl(w);\n    if (c == ERR)\n        return 0;\n    lua_pushnumber(lua, c);\n    return 1;\n}\n\n// window:attroff(attrs)\nstatic int xm_curses_window_attroff(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int attrs = luaL_checkint(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(wattroff(w, attrs)));\n    return 1;\n}\n\n// window:attron(attrs)\nstatic int xm_curses_window_attron(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int attrs = luaL_checkint(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(wattron(w, attrs)));\n    return 1;\n}\n\n// window:attrset(attrs)\nstatic int xm_curses_window_attrset(lua_State *lua) {\n    WINDOW *w = xm_curses_window_check(lua, 1);\n    int attrs = luaL_checkint(lua, 2);\n    lua_pushboolean(lua, XM_CURSES_OK(wattrset(w, attrs)));\n    return 1;\n}\n\n// window:copywin(...)\nstatic int xm_curses_window_copywin(lua_State *lua) {\n    WINDOW *srcwin = xm_curses_window_check(lua, 1);\n    WINDOW *dstwin = xm_curses_window_check(lua, 2);\n    int sminrow = luaL_checkint(lua, 3);\n    int smincol = luaL_checkint(lua, 4);\n    int dminrow = luaL_checkint(lua, 5);\n    int dmincol = luaL_checkint(lua, 6);\n    int dmaxrow = luaL_checkint(lua, 7);\n    int dmaxcol = luaL_checkint(lua, 8);\n    int overlay = lua_toboolean(lua, 9);\n    lua_pushboolean(lua,\n                    XM_CURSES_OK(\n                        copywin(srcwin, dstwin, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay)));\n    return 1;\n}\n\n// clean window after exiting program\nstatic void xm_curses_cleanup() {\n    if (!isendwin()) {\n        wclear(stdscr);\n        wrefresh(stdscr);\n        endwin();\n    }\n}\n\n// register constants\nstatic void xm_curses_register_constants(lua_State *lua) {\n    // colors\n    XM_CURSES_CONST(COLOR_BLACK)\n    XM_CURSES_CONST(COLOR_RED)\n    XM_CURSES_CONST(COLOR_GREEN)\n    XM_CURSES_CONST(COLOR_YELLOW)\n    XM_CURSES_CONST(COLOR_BLUE)\n    XM_CURSES_CONST(COLOR_MAGENTA)\n    XM_CURSES_CONST(COLOR_CYAN)\n    XM_CURSES_CONST(COLOR_WHITE)\n\n    // alternate character set\n    XM_CURSES_CONST(ACS_BLOCK)\n    XM_CURSES_CONST(ACS_BOARD)\n    XM_CURSES_CONST(ACS_BTEE)\n    XM_CURSES_CONST(ACS_TTEE)\n    XM_CURSES_CONST(ACS_LTEE)\n    XM_CURSES_CONST(ACS_RTEE)\n    XM_CURSES_CONST(ACS_LLCORNER)\n    XM_CURSES_CONST(ACS_LRCORNER)\n    XM_CURSES_CONST(ACS_URCORNER)\n    XM_CURSES_CONST(ACS_ULCORNER)\n    XM_CURSES_CONST(ACS_LARROW)\n    XM_CURSES_CONST(ACS_RARROW)\n    XM_CURSES_CONST(ACS_UARROW)\n    XM_CURSES_CONST(ACS_DARROW)\n    XM_CURSES_CONST(ACS_HLINE)\n    XM_CURSES_CONST(ACS_VLINE)\n    XM_CURSES_CONST(ACS_BULLET)\n    XM_CURSES_CONST(ACS_CKBOARD)\n    XM_CURSES_CONST(ACS_LANTERN)\n    XM_CURSES_CONST(ACS_DEGREE)\n    XM_CURSES_CONST(ACS_DIAMOND)\n    XM_CURSES_CONST(ACS_PLMINUS)\n    XM_CURSES_CONST(ACS_PLUS)\n    XM_CURSES_CONST(ACS_S1)\n    XM_CURSES_CONST(ACS_S9)\n\n    // attributes\n    XM_CURSES_CONST(A_NORMAL)\n    XM_CURSES_CONST(A_STANDOUT)\n    XM_CURSES_CONST(A_UNDERLINE)\n    XM_CURSES_CONST(A_REVERSE)\n    XM_CURSES_CONST(A_BLINK)\n    XM_CURSES_CONST(A_DIM)\n    XM_CURSES_CONST(A_BOLD)\n    XM_CURSES_CONST(A_PROTECT)\n    XM_CURSES_CONST(A_INVIS)\n    XM_CURSES_CONST(A_ALTCHARSET)\n    XM_CURSES_CONST(A_CHARTEXT)\n\n    // key functions\n    XM_CURSES_CONST(KEY_BREAK)\n    XM_CURSES_CONST(KEY_DOWN)\n    XM_CURSES_CONST(KEY_UP)\n    XM_CURSES_CONST(KEY_LEFT)\n    XM_CURSES_CONST(KEY_RIGHT)\n    XM_CURSES_CONST(KEY_HOME)\n    XM_CURSES_CONST(KEY_BACKSPACE)\n\n    XM_CURSES_CONST(KEY_DL)\n    XM_CURSES_CONST(KEY_IL)\n    XM_CURSES_CONST(KEY_DC)\n    XM_CURSES_CONST(KEY_IC)\n    XM_CURSES_CONST(KEY_EIC)\n    XM_CURSES_CONST(KEY_CLEAR)\n    XM_CURSES_CONST(KEY_EOS)\n    XM_CURSES_CONST(KEY_EOL)\n    XM_CURSES_CONST(KEY_SF)\n    XM_CURSES_CONST(KEY_SR)\n    XM_CURSES_CONST(KEY_NPAGE)\n    XM_CURSES_CONST(KEY_PPAGE)\n    XM_CURSES_CONST(KEY_STAB)\n    XM_CURSES_CONST(KEY_CTAB)\n    XM_CURSES_CONST(KEY_CATAB)\n    XM_CURSES_CONST(KEY_ENTER)\n    XM_CURSES_CONST(KEY_SRESET)\n    XM_CURSES_CONST(KEY_RESET)\n    XM_CURSES_CONST(KEY_PRINT)\n    XM_CURSES_CONST(KEY_LL)\n    XM_CURSES_CONST(KEY_A1)\n    XM_CURSES_CONST(KEY_A3)\n    XM_CURSES_CONST(KEY_B2)\n    XM_CURSES_CONST(KEY_C1)\n    XM_CURSES_CONST(KEY_C3)\n    XM_CURSES_CONST(KEY_BTAB)\n    XM_CURSES_CONST(KEY_BEG)\n    XM_CURSES_CONST(KEY_CANCEL)\n    XM_CURSES_CONST(KEY_CLOSE)\n    XM_CURSES_CONST(KEY_COMMAND)\n    XM_CURSES_CONST(KEY_COPY)\n    XM_CURSES_CONST(KEY_CREATE)\n    XM_CURSES_CONST(KEY_END)\n    XM_CURSES_CONST(KEY_EXIT)\n    XM_CURSES_CONST(KEY_FIND)\n    XM_CURSES_CONST(KEY_HELP)\n    XM_CURSES_CONST(KEY_MARK)\n    XM_CURSES_CONST(KEY_MESSAGE)\n#ifdef PDCURSES\n    // https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885\n    XM_CURSES_CONST(KEY_C2)\n    XM_CURSES_CONST(KEY_A2)\n    XM_CURSES_CONST(KEY_B1)\n    XM_CURSES_CONST(KEY_B3)\n#endif\n#if !defined(XCURSES)\n#ifndef NOMOUSE\n    XM_CURSES_CONST(KEY_MOUSE)\n#endif\n#endif\n    XM_CURSES_CONST(KEY_MOVE)\n    XM_CURSES_CONST(KEY_NEXT)\n    XM_CURSES_CONST(KEY_OPEN)\n    XM_CURSES_CONST(KEY_OPTIONS)\n    XM_CURSES_CONST(KEY_PREVIOUS)\n    XM_CURSES_CONST(KEY_REDO)\n    XM_CURSES_CONST(KEY_REFERENCE)\n    XM_CURSES_CONST(KEY_REFRESH)\n    XM_CURSES_CONST(KEY_REPLACE)\n    XM_CURSES_CONST(KEY_RESIZE)\n    XM_CURSES_CONST(KEY_RESTART)\n    XM_CURSES_CONST(KEY_RESUME)\n    XM_CURSES_CONST(KEY_SAVE)\n    XM_CURSES_CONST(KEY_SBEG)\n    XM_CURSES_CONST(KEY_SCANCEL)\n    XM_CURSES_CONST(KEY_SCOMMAND)\n    XM_CURSES_CONST(KEY_SCOPY)\n    XM_CURSES_CONST(KEY_SCREATE)\n    XM_CURSES_CONST(KEY_SDC)\n    XM_CURSES_CONST(KEY_SDL)\n    XM_CURSES_CONST(KEY_SELECT)\n    XM_CURSES_CONST(KEY_SEND)\n    XM_CURSES_CONST(KEY_SEOL)\n    XM_CURSES_CONST(KEY_SEXIT)\n    XM_CURSES_CONST(KEY_SFIND)\n    XM_CURSES_CONST(KEY_SHELP)\n    XM_CURSES_CONST(KEY_SHOME)\n    XM_CURSES_CONST(KEY_SIC)\n    XM_CURSES_CONST(KEY_SLEFT)\n    XM_CURSES_CONST(KEY_SMESSAGE)\n    XM_CURSES_CONST(KEY_SMOVE)\n    XM_CURSES_CONST(KEY_SNEXT)\n    XM_CURSES_CONST(KEY_SOPTIONS)\n    XM_CURSES_CONST(KEY_SPREVIOUS)\n    XM_CURSES_CONST(KEY_SPRINT)\n    XM_CURSES_CONST(KEY_SREDO)\n    XM_CURSES_CONST(KEY_SREPLACE)\n    XM_CURSES_CONST(KEY_SRIGHT)\n    XM_CURSES_CONST(KEY_SRSUME)\n    XM_CURSES_CONST(KEY_SSAVE)\n    XM_CURSES_CONST(KEY_SSUSPEND)\n    XM_CURSES_CONST(KEY_SUNDO)\n    XM_CURSES_CONST(KEY_SUSPEND)\n    XM_CURSES_CONST(KEY_UNDO)\n\n    // KEY_Fx  0 <= x <= 63\n    XM_CURSES_CONST(KEY_F0)\n    XM_CURSES_CONST2(KEY_F1, KEY_F(1))\n    XM_CURSES_CONST2(KEY_F2, KEY_F(2))\n    XM_CURSES_CONST2(KEY_F3, KEY_F(3))\n    XM_CURSES_CONST2(KEY_F4, KEY_F(4))\n    XM_CURSES_CONST2(KEY_F5, KEY_F(5))\n    XM_CURSES_CONST2(KEY_F6, KEY_F(6))\n    XM_CURSES_CONST2(KEY_F7, KEY_F(7))\n    XM_CURSES_CONST2(KEY_F8, KEY_F(8))\n    XM_CURSES_CONST2(KEY_F9, KEY_F(9))\n    XM_CURSES_CONST2(KEY_F10, KEY_F(10))\n    XM_CURSES_CONST2(KEY_F11, KEY_F(11))\n    XM_CURSES_CONST2(KEY_F12, KEY_F(12))\n\n#if !defined(XCURSES)\n#ifndef NOMOUSE\n    // mouse constants\n    XM_CURSES_CONST(BUTTON1_RELEASED)\n    XM_CURSES_CONST(BUTTON1_PRESSED)\n    XM_CURSES_CONST(BUTTON1_CLICKED)\n    XM_CURSES_CONST(BUTTON1_DOUBLE_CLICKED)\n    XM_CURSES_CONST(BUTTON1_TRIPLE_CLICKED)\n    XM_CURSES_CONST(BUTTON2_RELEASED)\n    XM_CURSES_CONST(BUTTON2_PRESSED)\n    XM_CURSES_CONST(BUTTON2_CLICKED)\n    XM_CURSES_CONST(BUTTON2_DOUBLE_CLICKED)\n    XM_CURSES_CONST(BUTTON2_TRIPLE_CLICKED)\n    XM_CURSES_CONST(BUTTON3_RELEASED)\n    XM_CURSES_CONST(BUTTON3_PRESSED)\n    XM_CURSES_CONST(BUTTON3_CLICKED)\n    XM_CURSES_CONST(BUTTON3_DOUBLE_CLICKED)\n    XM_CURSES_CONST(BUTTON3_TRIPLE_CLICKED)\n    XM_CURSES_CONST(BUTTON4_RELEASED)\n    XM_CURSES_CONST(BUTTON4_PRESSED)\n    XM_CURSES_CONST(BUTTON4_CLICKED)\n    XM_CURSES_CONST(BUTTON4_DOUBLE_CLICKED)\n    XM_CURSES_CONST(BUTTON4_TRIPLE_CLICKED)\n    XM_CURSES_CONST(BUTTON_CTRL)\n    XM_CURSES_CONST(BUTTON_SHIFT)\n    XM_CURSES_CONST(BUTTON_ALT)\n    XM_CURSES_CONST(REPORT_MOUSE_POSITION)\n    XM_CURSES_CONST(ALL_MOUSE_EVENTS)\n#if NCURSES_MOUSE_VERSION > 1\n    XM_CURSES_CONST(BUTTON5_RELEASED)\n    XM_CURSES_CONST(BUTTON5_PRESSED)\n    XM_CURSES_CONST(BUTTON5_CLICKED)\n    XM_CURSES_CONST(BUTTON5_DOUBLE_CLICKED)\n    XM_CURSES_CONST(BUTTON5_TRIPLE_CLICKED)\n#endif\n#endif\n#endif\n}\n\n// init curses\nstatic int xm_curses_initscr(lua_State *lua) {\n    WINDOW *w = initscr();\n    if (!w)\n        return 0;\n    xm_curses_window_new(lua, w);\n\n#if defined(NCURSES_VERSION)\n    //    ESCDELAY = 0;\n    set_escdelay(0);\n#endif\n\n    lua_pushstring(lua, XM_CURSES_STDSCR);\n    lua_pushvalue(lua, -2);\n    lua_rawset(lua, LUA_REGISTRYINDEX);\n\n    xm_curses_register_constants(lua);\n\n#ifndef PDCURSES\n    atexit(xm_curses_cleanup);\n#endif\n    return 1;\n}\n\nstatic int xm_curses_endwin(lua_State *lua) {\n    endwin();\n#ifdef XCURSES\n    XCursesExit();\n    exit(0);\n#endif\n    return 0;\n}\n\nstatic int xm_curses_stdscr(lua_State *lua) {\n    lua_pushstring(lua, XM_CURSES_STDSCR);\n    lua_rawget(lua, LUA_REGISTRYINDEX);\n    return 1;\n}\n\n#if !defined(XCURSES) && !defined(NOMOUSE)\nstatic int xm_curses_getmouse(lua_State *lua) {\n    MEVENT e;\n    if (getmouse(&e) == OK) {\n        lua_pushinteger(lua, e.bstate);\n        lua_pushinteger(lua, e.x);\n        lua_pushinteger(lua, e.y);\n        lua_pushinteger(lua, e.z);\n        lua_pushinteger(lua, e.id);\n        return 5;\n    }\n\n    lua_pushnil(lua);\n    return 1;\n}\n\nstatic int xm_curses_mousemask(lua_State *lua) {\n    mmask_t m = luaL_checkint(lua, 1);\n    mmask_t om;\n    m = mousemask(m, &om);\n    lua_pushinteger(lua, m);\n    lua_pushinteger(lua, om);\n    return 2;\n}\n#endif\n\nstatic int xm_curses_init_pair(lua_State *lua) {\n    short pair = luaL_checkint(lua, 1);\n    short f    = luaL_checkint(lua, 2);\n    short b    = luaL_checkint(lua, 3);\n\n    lua_pushboolean(lua, XM_CURSES_OK(init_pair(pair, f, b)));\n    return 1;\n}\n\nstatic int xm_curses_COLOR_PAIR(lua_State *lua) {\n    int n = luaL_checkint(lua, 1);\n    lua_pushnumber(lua, COLOR_PAIR(n));\n    return 1;\n}\n\nstatic int xm_curses_curs_set(lua_State *lua) {\n    int vis   = luaL_checkint(lua, 1);\n    int state = curs_set(vis);\n    if (state == ERR)\n        return 0;\n\n    lua_pushnumber(lua, state);\n    return 1;\n}\n\nstatic int xm_curses_napms(lua_State *lua) {\n    int ms = luaL_checkint(lua, 1);\n    lua_pushboolean(lua, XM_CURSES_OK(napms(ms)));\n    return 1;\n}\n\nstatic int xm_curses_cbreak(lua_State *lua) {\n    if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {\n        lua_pushboolean(lua, XM_CURSES_OK(cbreak()));\n    } else {\n        lua_pushboolean(lua, XM_CURSES_OK(nocbreak()));\n    }\n    return 1;\n}\n\nstatic int xm_curses_echo(lua_State *lua) {\n    if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {\n        lua_pushboolean(lua, XM_CURSES_OK(echo()));\n    } else {\n        lua_pushboolean(lua, XM_CURSES_OK(noecho()));\n    }\n    return 1;\n}\n\nstatic int xm_curses_nl(lua_State *lua) {\n    if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {\n        lua_pushboolean(lua, XM_CURSES_OK(nl()));\n    } else {\n        lua_pushboolean(lua, XM_CURSES_OK(nonl()));\n    }\n    return 1;\n}\n\nstatic int xm_curses_newpad(lua_State *lua) {\n    int nlines = luaL_checkint(lua, 1);\n    int ncols  = luaL_checkint(lua, 2);\n    xm_curses_window_new(lua, newpad(nlines, ncols));\n    return 1;\n}\n\nXM_CURSES_NUMBER2(COLS, COLS)\nXM_CURSES_NUMBER2(LINES, LINES)\nXM_CURSES_BOOL(isendwin)\nXM_CURSES_BOOLOK(start_color)\nXM_CURSES_BOOL(has_colors)\nXM_CURSES_BOOLOK(doupdate)\nXM_CURSES_WINDOW_BOOLOK(wclear)\nXM_CURSES_WINDOW_BOOLOK(wnoutrefresh)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\n\nstatic const luaL_Reg g_window_functions[] = {\n    { \"close\", xm_curses_window_delwin },\n    { \"keypad\", xm_curses_window_keypad },\n    { \"meta\", xm_curses_window_meta },\n    { \"nodelay\", xm_curses_window_nodelay },\n    { \"leaveok\", xm_curses_window_leaveok },\n    { \"move\", xm_curses_window_move },\n    { \"clear\", xm_curses_window_wclear },\n    { \"noutrefresh\", xm_curses_window_wnoutrefresh },\n    { \"attroff\", xm_curses_window_attroff },\n    { \"attron\", xm_curses_window_attron },\n    { \"attrset\", xm_curses_window_attrset },\n    { \"getch\", xm_curses_window_getch },\n    { \"getyx\", xm_curses_window_getyx },\n    { \"getmaxyx\", xm_curses_window_getmaxyx },\n    { \"addch\", xm_curses_window_addch },\n    { \"addstr\", xm_curses_window_addnstr },\n    { \"copy\", xm_curses_window_copywin },\n    { \"__gc\", xm_curses_window_delwin },\n    { \"__tostring\", xm_curses_window_tostring },\n    { NULL, NULL },\n};\n\nstatic const luaL_Reg g_curses_functions[] = {\n    { \"done\", xm_curses_endwin },\n    { \"isdone\", xm_curses_isendwin },\n    { \"main_window\", xm_curses_stdscr },\n    { \"columns\", xm_curses_COLS },\n    { \"lines\", xm_curses_LINES },\n    { \"start_color\", xm_curses_start_color },\n    { \"has_colors\", xm_curses_has_colors },\n    { \"init_pair\", xm_curses_init_pair },\n    { \"color_pair\", xm_curses_COLOR_PAIR },\n    { \"napms\", xm_curses_napms },\n    { \"cursor_set\", xm_curses_curs_set },\n    { \"new_pad\", xm_curses_newpad },\n    { \"doupdate\", xm_curses_doupdate },\n    { \"cbreak\", xm_curses_cbreak },\n    { \"echo\", xm_curses_echo },\n    { \"nl\", xm_curses_nl },\n#if !defined(XCURSES)\n#ifndef NOMOUSE\n    { \"mousemask\", xm_curses_mousemask },\n    { \"getmouse\", xm_curses_getmouse },\n#endif\n#endif\n    { NULL, NULL },\n};\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementations\n */\nint xm_lua_curses_register(lua_State *lua, const char *module) {\n    // create new metatable for window objects\n    luaL_newmetatable(lua, XM_CURSES_WINDOW);\n    lua_pushliteral(lua, \"__index\");\n    lua_pushvalue(lua, -2); /* push metatable */\n    lua_rawset(lua, -3);    /* metatable.__index = metatable */\n    luaL_setfuncs(lua, g_window_functions, 0);\n    lua_pop(lua, 1); /* remove metatable from stack */\n\n    // create global table with curses methods/variables/constants\n    lua_newtable(lua);\n    luaL_setfuncs(lua, g_curses_functions, 0);\n\n    // add curses.init()\n    lua_pushstring(lua, \"init\");\n    lua_pushvalue(lua, -2);\n    lua_pushcclosure(lua, xm_curses_initscr, 1);\n    lua_settable(lua, -3);\n\n    // register global curses module\n    lua_setglobal(lua, module);\n\n    /* since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function.\n     * that means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings.\n     *\n     * and we need to link libncurses_window.so for drawing vline, hline characters\n     */\n#if defined(NCURSES_VERSION)\n    setlocale(LC_ALL, \"\");\n#endif\n    return 1;\n}\n#endif\n"
  },
  {
    "path": "core/src/xmake/curses/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        prefix.h\n *\n */\n#ifndef XM_CURSES_PREFIX_H\n#define XM_CURSES_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/engine.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        engine.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"engine\"\n#define TB_TRACE_MODULE_DEBUG (1)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmake.h\"\n#include \"io/poller.h\"\n#if defined(TB_CONFIG_OS_WINDOWS)\n#include <windows.h>\n#include <io.h>\n#include <fcntl.h>\n#elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)\n#include <unistd.h>\n#include <mach-o/dyld.h>\n#include <signal.h>\n#elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) ||                     \\\n    defined(TB_CONFIG_OS_HAIKU) || defined(TB_CONFIG_OS_SOLARIS)\n#include <unistd.h>\n#include <signal.h>\n#endif\n#ifdef TB_CONFIG_OS_BSD\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <signal.h>\n#endif\n#ifdef TB_CONFIG_OS_SOLARIS\n#include <sys/types.h>\n#include <signal.h>\n#endif\n#ifdef TB_CONFIG_OS_HAIKU\n#include <image.h>\n#endif\n#ifdef __COSMOPOLITAN__\n#include <sys/utsname.h>\n#endif\n\n// for uid\n#ifndef TB_CONFIG_OS_WINDOWS\n#include <unistd.h>\n#include <errno.h>\n#endif\n\n// for embed files\n#ifdef XM_EMBED_ENABLE\n#include \"lz4/prefix.h\"\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// proc/self\n#if defined(TB_CONFIG_OS_LINUX)\n#define XM_PROC_SELF_FILE \"/proc/self/exe\"\n#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__) && !defined(__FreeBSD__)\n#if defined(__NetBSD__)\n#define XM_PROC_SELF_FILE \"/proc/curproc/exe\"\n#else\n#define XM_PROC_SELF_FILE \"/proc/curproc/file\"\n#endif\n#elif defined(TB_CONFIG_OS_SOLARIS)\n#define XM_PROC_SELF_FILE \"/proc/self/path/a.out\"\n#endif\n\n// hook lua memory allocator\n#define XM_HOOK_LUA_MEMALLOC (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the engine type\ntypedef struct __xm_engine_t {\n    // the lua\n    lua_State *lua;\n\n    // the engine name\n    tb_char_t name[64];\n\n    // the io poller\n    tb_poller_ref_t   poller;\n    xm_poller_state_t poller_state;\n\n#ifdef XM_EMBED_ENABLE\n    // the temporary directory\n    tb_char_t tmpdir[TB_PATH_MAXN];\n\n    // the embed files\n    tb_byte_t const *embeddata[32];\n    tb_size_t        embedsize[32];\n    tb_size_t        embedcount;\n#endif\n} xm_engine_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * declaration\n */\n\n// the os functions\ntb_int_t xm_os_argv(lua_State *lua);\ntb_int_t xm_os_args(lua_State *lua);\ntb_int_t xm_os_find(lua_State *lua);\ntb_int_t xm_os_link(lua_State *lua);\ntb_int_t xm_os_isdir(lua_State *lua);\ntb_int_t xm_os_rmdir(lua_State *lua);\ntb_int_t xm_os_mkdir(lua_State *lua);\ntb_int_t xm_os_cpdir(lua_State *lua);\ntb_int_t xm_os_chdir(lua_State *lua);\ntb_int_t xm_os_mtime(lua_State *lua);\ntb_int_t xm_os_sleep(lua_State *lua);\ntb_int_t xm_os_mclock(lua_State *lua);\ntb_int_t xm_os_curdir(lua_State *lua);\ntb_int_t xm_os_tmpdir(lua_State *lua);\ntb_int_t xm_os_islink(lua_State *lua);\ntb_int_t xm_os_isfile(lua_State *lua);\ntb_int_t xm_os_touch(lua_State *lua);\ntb_int_t xm_os_rmfile(lua_State *lua);\ntb_int_t xm_os_cpfile(lua_State *lua);\ntb_int_t xm_os_fscase(lua_State *lua);\ntb_int_t xm_os_rename(lua_State *lua);\ntb_int_t xm_os_exists(lua_State *lua);\ntb_int_t xm_os_setenv(lua_State *lua);\ntb_int_t xm_os_getenv(lua_State *lua);\ntb_int_t xm_os_getenvs(lua_State *lua);\ntb_int_t xm_os_cpuinfo(lua_State *lua);\ntb_int_t xm_os_meminfo(lua_State *lua);\ntb_int_t xm_os_readlink(lua_State *lua);\ntb_int_t xm_os_filesize(lua_State *lua);\ntb_int_t xm_os_access(lua_State *lua);\ntb_int_t xm_os_emptydir(lua_State *lua);\ntb_int_t xm_os_syserror(lua_State *lua);\ntb_int_t xm_os_strerror(lua_State *lua);\ntb_int_t xm_os_getwinsize(lua_State *lua);\ntb_int_t xm_os_getpid(lua_State *lua);\ntb_int_t xm_os_signal(lua_State *lua);\n#ifndef TB_CONFIG_OS_WINDOWS\ntb_int_t xm_os_uid(lua_State *lua);\ntb_int_t xm_os_gid(lua_State *lua);\ntb_int_t xm_os_getown(lua_State *lua);\n#endif\n\n// the io/file functions\ntb_int_t xm_io_stdfile(lua_State *lua);\ntb_int_t xm_io_file_open(lua_State *lua);\ntb_int_t xm_io_file_read(lua_State *lua);\ntb_int_t xm_io_file_readable(lua_State *lua);\ntb_int_t xm_io_file_seek(lua_State *lua);\ntb_int_t xm_io_file_size(lua_State *lua);\ntb_int_t xm_io_file_rawfd(lua_State *lua);\ntb_int_t xm_io_file_write(lua_State *lua);\ntb_int_t xm_io_file_flush(lua_State *lua);\ntb_int_t xm_io_file_close(lua_State *lua);\ntb_int_t xm_io_file_convert(lua_State *lua);\ntb_int_t xm_io_file_isatty(lua_State *lua);\n\n// the io/filelock functions\ntb_int_t xm_io_filelock_open(lua_State *lua);\ntb_int_t xm_io_filelock_lock(lua_State *lua);\ntb_int_t xm_io_filelock_unlock(lua_State *lua);\ntb_int_t xm_io_filelock_trylock(lua_State *lua);\ntb_int_t xm_io_filelock_close(lua_State *lua);\n\n// the io/socket functions\ntb_int_t xm_io_socket_open(lua_State *lua);\ntb_int_t xm_io_socket_rawfd(lua_State *lua);\ntb_int_t xm_io_socket_peeraddr(lua_State *lua);\ntb_int_t xm_io_socket_wait(lua_State *lua);\ntb_int_t xm_io_socket_bind(lua_State *lua);\ntb_int_t xm_io_socket_ctrl(lua_State *lua);\ntb_int_t xm_io_socket_listen(lua_State *lua);\ntb_int_t xm_io_socket_accept(lua_State *lua);\ntb_int_t xm_io_socket_connect(lua_State *lua);\ntb_int_t xm_io_socket_send(lua_State *lua);\ntb_int_t xm_io_socket_sendto(lua_State *lua);\ntb_int_t xm_io_socket_sendfile(lua_State *lua);\ntb_int_t xm_io_socket_recv(lua_State *lua);\ntb_int_t xm_io_socket_recvfrom(lua_State *lua);\ntb_int_t xm_io_socket_kill(lua_State *lua);\ntb_int_t xm_io_socket_close(lua_State *lua);\n\n// the io/pipe functions\ntb_int_t xm_io_pipe_open(lua_State *lua);\ntb_int_t xm_io_pipe_openpair(lua_State *lua);\ntb_int_t xm_io_pipe_close(lua_State *lua);\ntb_int_t xm_io_pipe_read(lua_State *lua);\ntb_int_t xm_io_pipe_write(lua_State *lua);\ntb_int_t xm_io_pipe_wait(lua_State *lua);\ntb_int_t xm_io_pipe_connect(lua_State *lua);\n\n// the io/poller functions\ntb_int_t xm_io_poller_insert(lua_State *lua);\ntb_int_t xm_io_poller_modify(lua_State *lua);\ntb_int_t xm_io_poller_remove(lua_State *lua);\ntb_int_t xm_io_poller_spank(lua_State *lua);\ntb_int_t xm_io_poller_support(lua_State *lua);\ntb_int_t xm_io_poller_wait(lua_State *lua);\n\n// the path functions\ntb_int_t xm_path_relative(lua_State *lua);\ntb_int_t xm_path_absolute(lua_State *lua);\ntb_int_t xm_path_translate(lua_State *lua);\ntb_int_t xm_path_directory(lua_State *lua);\ntb_int_t xm_path_is_absolute(lua_State *lua);\n\n// the hash functions\ntb_int_t xm_hash_uuid4(lua_State *lua);\ntb_int_t xm_hash_sha(lua_State *lua);\ntb_int_t xm_hash_md5(lua_State *lua);\ntb_int_t xm_hash_xxhash(lua_State *lua);\ntb_int_t xm_hash_rand32(lua_State *lua);\ntb_int_t xm_hash_rand64(lua_State *lua);\ntb_int_t xm_hash_rand128(lua_State *lua);\n\n// the base64 functions\ntb_int_t xm_base64_encode(lua_State *lua);\ntb_int_t xm_base64_decode(lua_State *lua);\n\n// the lz4 functions\ntb_int_t xm_lz4_compress(lua_State *lua);\ntb_int_t xm_lz4_decompress(lua_State *lua);\ntb_int_t xm_lz4_block_compress(lua_State *lua);\ntb_int_t xm_lz4_block_decompress(lua_State *lua);\ntb_int_t xm_lz4_compress_file(lua_State *lua);\ntb_int_t xm_lz4_decompress_file(lua_State *lua);\ntb_int_t xm_lz4_compress_stream_open(lua_State *lua);\ntb_int_t xm_lz4_compress_stream_read(lua_State *lua);\ntb_int_t xm_lz4_compress_stream_write(lua_State *lua);\ntb_int_t xm_lz4_compress_stream_close(lua_State *lua);\ntb_int_t xm_lz4_decompress_stream_open(lua_State *lua);\ntb_int_t xm_lz4_decompress_stream_read(lua_State *lua);\ntb_int_t xm_lz4_decompress_stream_write(lua_State *lua);\ntb_int_t xm_lz4_decompress_stream_close(lua_State *lua);\n\n// the bloom filter functions\ntb_int_t xm_bloom_filter_open(lua_State *lua);\ntb_int_t xm_bloom_filter_close(lua_State *lua);\ntb_int_t xm_bloom_filter_clear(lua_State *lua);\ntb_int_t xm_bloom_filter_data(lua_State *lua);\ntb_int_t xm_bloom_filter_size(lua_State *lua);\ntb_int_t xm_bloom_filter_get(lua_State *lua);\ntb_int_t xm_bloom_filter_set(lua_State *lua);\ntb_int_t xm_bloom_filter_data_set(lua_State *lua);\n\n// the windows functions\n#ifdef TB_CONFIG_OS_WINDOWS\ntb_int_t xm_winos_cp_info(lua_State *lua);\ntb_int_t xm_winos_console_cp(lua_State *lua);\ntb_int_t xm_winos_console_output_cp(lua_State *lua);\ntb_int_t xm_winos_ansi_cp(lua_State *lua);\ntb_int_t xm_winos_oem_cp(lua_State *lua);\ntb_int_t xm_winos_logical_drives(lua_State *lua);\ntb_int_t xm_winos_registry_query(lua_State *lua);\ntb_int_t xm_winos_registry_keys(lua_State *lua);\ntb_int_t xm_winos_registry_values(lua_State *lua);\ntb_int_t xm_winos_short_path(lua_State *lua);\ntb_int_t xm_winos_processes(lua_State* lua);\ntb_int_t xm_winos_set_error_mode(lua_State *lua);\ntb_int_t xm_winos_file_signature(lua_State *lua);\n#endif\n\n// the utf8 functions\ntb_int_t xm_utf8_len(lua_State *lua);\ntb_int_t xm_utf8_char(lua_State *lua);\ntb_int_t xm_utf8_byte(lua_State *lua);\ntb_int_t xm_utf8_codepoint(lua_State *lua);\ntb_int_t xm_utf8_offset(lua_State *lua);\ntb_int_t xm_utf8_codes(lua_State *lua);\ntb_int_t xm_utf8_sub(lua_State *lua);\ntb_int_t xm_utf8_reverse(lua_State *lua);\ntb_int_t xm_utf8_lastof(lua_State *lua);\ntb_int_t xm_utf8_find(lua_State *lua);\ntb_int_t xm_utf8_width(lua_State *lua);\n\n// the string functions\ntb_int_t xm_string_trim(lua_State *lua);\ntb_int_t xm_string_split(lua_State *lua);\ntb_int_t xm_string_lastof(lua_State *lua);\ntb_int_t xm_string_convert(lua_State *lua);\ntb_int_t xm_string_endswith(lua_State *lua);\ntb_int_t xm_string_startswith(lua_State *lua);\ntb_int_t xm_string_lower(lua_State *lua);\ntb_int_t xm_string_upper(lua_State *lua);\n\n// the process functions\ntb_int_t xm_process_open(lua_State *lua);\ntb_int_t xm_process_openv(lua_State *lua);\ntb_int_t xm_process_wait(lua_State *lua);\ntb_int_t xm_process_kill(lua_State *lua);\ntb_int_t xm_process_close(lua_State *lua);\n\n// the fwatcher functions\ntb_int_t xm_fwatcher_open(lua_State *lua);\ntb_int_t xm_fwatcher_add(lua_State *lua);\ntb_int_t xm_fwatcher_remove(lua_State *lua);\ntb_int_t xm_fwatcher_wait(lua_State *lua);\ntb_int_t xm_fwatcher_close(lua_State *lua);\n\n// the sandbox functions\ntb_int_t xm_sandbox_interactive(lua_State *lua);\n\n#ifdef XM_CONFIG_API_HAVE_READLINE\n// the readline functions\ntb_int_t xm_readline_readline(lua_State *lua);\ntb_int_t xm_readline_history_list(lua_State *lua);\ntb_int_t xm_readline_add_history(lua_State *lua);\ntb_int_t xm_readline_clear_history(lua_State *lua);\n#endif\n\n// the semver functions\ntb_int_t xm_semver_parse(lua_State *lua);\ntb_int_t xm_semver_compare(lua_State *lua);\ntb_int_t xm_semver_satisfies(lua_State *lua);\ntb_int_t xm_semver_select(lua_State *lua);\n\n// the libc functions\ntb_int_t xm_libc_malloc(lua_State *lua);\ntb_int_t xm_libc_free(lua_State *lua);\ntb_int_t xm_libc_memcpy(lua_State *lua);\ntb_int_t xm_libc_memmov(lua_State *lua);\ntb_int_t xm_libc_memset(lua_State *lua);\ntb_int_t xm_libc_strndup(lua_State *lua);\ntb_int_t xm_libc_dataptr(lua_State *lua);\ntb_int_t xm_libc_byteof(lua_State *lua);\ntb_int_t xm_libc_setbyte(lua_State *lua);\n\n// the tty functions\ntb_int_t xm_tty_term_mode(lua_State *lua);\ntb_int_t xm_tty_session_id(lua_State *lua);\n\n// the package functions\ntb_int_t xm_package_loadxmi(lua_State *lua);\n\n// the binutils functions\ntb_int_t xm_binutils_bin2c(lua_State *lua);\ntb_int_t xm_binutils_bin2coff(lua_State *lua);\ntb_int_t xm_binutils_bin2macho(lua_State *lua);\ntb_int_t xm_binutils_bin2elf(lua_State *lua);\ntb_int_t xm_binutils_readsyms(lua_State *lua);\ntb_int_t xm_binutils_deplibs(lua_State *lua);\ntb_int_t xm_binutils_rpath_list(lua_State *lua);\ntb_int_t xm_binutils_rpath_clean(lua_State *lua);\ntb_int_t xm_binutils_extractlib(lua_State *lua);\ntb_int_t xm_binutils_format(lua_State *lua);\n\n#ifdef XM_CONFIG_API_HAVE_CURSES\n// register curses functions\ntb_int_t xm_lua_curses_register(lua_State *lua, tb_char_t const *module);\n#endif\n\n// the thread functions\ntb_int_t xm_thread_init(lua_State *lua);\ntb_int_t xm_thread_exit(lua_State *lua);\ntb_int_t xm_thread_wait(lua_State *lua);\ntb_int_t xm_thread_suspend(lua_State *lua);\ntb_int_t xm_thread_resume(lua_State *lua);\n\n// the thread/mutex functions\ntb_int_t xm_thread_mutex_init(lua_State *lua);\ntb_int_t xm_thread_mutex_exit(lua_State *lua);\ntb_int_t xm_thread_mutex_lock(lua_State *lua);\ntb_int_t xm_thread_mutex_trylock(lua_State *lua);\ntb_int_t xm_thread_mutex_unlock(lua_State *lua);\ntb_int_t xm_thread_mutex_incref(lua_State *lua);\n\n// the thread/event functions\ntb_int_t xm_thread_event_init(lua_State *lua);\ntb_int_t xm_thread_event_exit(lua_State *lua);\ntb_int_t xm_thread_event_post(lua_State *lua);\ntb_int_t xm_thread_event_wait(lua_State *lua);\ntb_int_t xm_thread_event_incref(lua_State *lua);\n\n// the thread/semaphore functions\ntb_int_t xm_thread_semaphore_init(lua_State *lua);\ntb_int_t xm_thread_semaphore_exit(lua_State *lua);\ntb_int_t xm_thread_semaphore_post(lua_State *lua);\ntb_int_t xm_thread_semaphore_wait(lua_State *lua);\ntb_int_t xm_thread_semaphore_incref(lua_State *lua);\n\n// the thread/queue functions\ntb_int_t xm_thread_queue_init(lua_State *lua);\ntb_int_t xm_thread_queue_exit(lua_State *lua);\ntb_int_t xm_thread_queue_size(lua_State *lua);\ntb_int_t xm_thread_queue_clear(lua_State *lua);\ntb_int_t xm_thread_queue_incref(lua_State *lua);\ntb_int_t xm_thread_queue_push(lua_State *lua);\ntb_int_t xm_thread_queue_pop(lua_State *lua);\n\n// the thread/sharedata functions\ntb_int_t xm_thread_sharedata_init(lua_State *lua);\ntb_int_t xm_thread_sharedata_exit(lua_State *lua);\ntb_int_t xm_thread_sharedata_clear(lua_State *lua);\ntb_int_t xm_thread_sharedata_incref(lua_State *lua);\ntb_int_t xm_thread_sharedata_set(lua_State *lua);\ntb_int_t xm_thread_sharedata_get_(lua_State *lua);\n\n// open cjson\n__tb_extern_c_enter__\ntb_int_t luaopen_cjson(lua_State *l);\n__tb_extern_c_leave__\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\n\n// the os functions\nstatic luaL_Reg const g_os_functions[] = {\n    { \"argv\", xm_os_argv },\n    { \"args\", xm_os_args },\n    { \"find\", xm_os_find },\n    { \"link\", xm_os_link },\n    { \"isdir\", xm_os_isdir },\n    { \"rmdir\", xm_os_rmdir },\n    { \"mkdir\", xm_os_mkdir },\n    { \"cpdir\", xm_os_cpdir },\n    { \"chdir\", xm_os_chdir },\n    { \"mtime\", xm_os_mtime },\n    { \"sleep\", xm_os_sleep },\n    { \"mclock\", xm_os_mclock },\n    { \"curdir\", xm_os_curdir },\n    { \"tmpdir\", xm_os_tmpdir },\n    { \"islink\", xm_os_islink },\n    { \"isfile\", xm_os_isfile },\n    { \"touch\", xm_os_touch },\n    { \"rmfile\", xm_os_rmfile },\n    { \"cpfile\", xm_os_cpfile },\n    { \"fscase\", xm_os_fscase },\n    { \"rename\", xm_os_rename },\n    { \"exists\", xm_os_exists },\n    { \"access\", xm_os_access },\n    { \"setenv\", xm_os_setenv },\n    { \"getenv\", xm_os_getenv },\n    { \"getenvs\", xm_os_getenvs },\n    { \"cpuinfo\", xm_os_cpuinfo },\n    { \"meminfo\", xm_os_meminfo },\n    { \"readlink\", xm_os_readlink },\n    { \"emptydir\", xm_os_emptydir },\n    { \"strerror\", xm_os_strerror },\n    { \"syserror\", xm_os_syserror },\n    { \"filesize\", xm_os_filesize },\n    { \"getwinsize\", xm_os_getwinsize },\n    { \"getpid\", xm_os_getpid },\n    { \"signal\", xm_os_signal },\n#ifndef TB_CONFIG_OS_WINDOWS\n    { \"uid\", xm_os_uid },\n    { \"gid\", xm_os_gid },\n    { \"getown\", xm_os_getown },\n#endif\n    { tb_null, tb_null },\n};\n\n// the windows functions\n#ifdef TB_CONFIG_OS_WINDOWS\nstatic luaL_Reg const g_winos_functions[] = {\n    { \"cp_info\", xm_winos_cp_info },\n    { \"console_cp\", xm_winos_console_cp },\n    { \"console_output_cp\", xm_winos_console_output_cp },\n    { \"oem_cp\", xm_winos_oem_cp },\n    { \"ansi_cp\", xm_winos_ansi_cp },\n    { \"logical_drives\", xm_winos_logical_drives },\n    { \"registry_query\", xm_winos_registry_query },\n    { \"registry_keys\", xm_winos_registry_keys },\n    { \"registry_values\", xm_winos_registry_values },\n    { \"short_path\", xm_winos_short_path },\n    { \"processes\", xm_winos_processes },\n    { \"set_error_mode\", xm_winos_set_error_mode },\n    { \"file_signature\", xm_winos_file_signature },\n    { tb_null, tb_null },\n};\n#endif\n\n// the io functions\nstatic luaL_Reg const g_io_functions[] = {\n    { \"stdfile\", xm_io_stdfile },\n    { \"file_open\", xm_io_file_open },\n    { \"file_read\", xm_io_file_read },\n    { \"file_readable\", xm_io_file_readable },\n    { \"file_seek\", xm_io_file_seek },\n    { \"file_size\", xm_io_file_size },\n    { \"file_write\", xm_io_file_write },\n    { \"file_flush\", xm_io_file_flush },\n    { \"file_isatty\", xm_io_file_isatty },\n    { \"file_close\", xm_io_file_close },\n    { \"file_convert\", xm_io_file_convert },\n    { \"file_rawfd\", xm_io_file_rawfd },\n    { \"filelock_open\", xm_io_filelock_open },\n    { \"filelock_lock\", xm_io_filelock_lock },\n    { \"filelock_trylock\", xm_io_filelock_trylock },\n    { \"filelock_unlock\", xm_io_filelock_unlock },\n    { \"filelock_close\", xm_io_filelock_close },\n    { \"socket_open\", xm_io_socket_open },\n    { \"socket_rawfd\", xm_io_socket_rawfd },\n    { \"socket_peeraddr\", xm_io_socket_peeraddr },\n    { \"socket_wait\", xm_io_socket_wait },\n    { \"socket_bind\", xm_io_socket_bind },\n    { \"socket_ctrl\", xm_io_socket_ctrl },\n    { \"socket_listen\", xm_io_socket_listen },\n    { \"socket_accept\", xm_io_socket_accept },\n    { \"socket_connect\", xm_io_socket_connect },\n    { \"socket_send\", xm_io_socket_send },\n    { \"socket_sendto\", xm_io_socket_sendto },\n    { \"socket_sendfile\", xm_io_socket_sendfile },\n    { \"socket_recv\", xm_io_socket_recv },\n    { \"socket_recvfrom\", xm_io_socket_recvfrom },\n    { \"socket_kill\", xm_io_socket_kill },\n    { \"socket_close\", xm_io_socket_close },\n    { \"pipe_open\", xm_io_pipe_open },\n    { \"pipe_openpair\", xm_io_pipe_openpair },\n    { \"pipe_close\", xm_io_pipe_close },\n    { \"pipe_read\", xm_io_pipe_read },\n    { \"pipe_write\", xm_io_pipe_write },\n    { \"pipe_wait\", xm_io_pipe_wait },\n    { \"pipe_connect\", xm_io_pipe_connect },\n    { \"poller_insert\", xm_io_poller_insert },\n    { \"poller_modify\", xm_io_poller_modify },\n    { \"poller_remove\", xm_io_poller_remove },\n    { \"poller_spank\", xm_io_poller_spank },\n    { \"poller_support\", xm_io_poller_support },\n    { \"poller_wait\", xm_io_poller_wait },\n    { tb_null, tb_null },\n};\n\n// the path functions\nstatic luaL_Reg const g_path_functions[] = {\n    { \"relative\", xm_path_relative },\n    { \"absolute\", xm_path_absolute },\n    { \"translate\", xm_path_translate },\n    { \"directory\", xm_path_directory },\n    { \"is_absolute\", xm_path_is_absolute },\n    { tb_null, tb_null },\n};\n\n// the hash functions\nstatic luaL_Reg const g_hash_functions[] = {\n    { \"uuid4\", xm_hash_uuid4 },\n    { \"sha\", xm_hash_sha },\n    { \"md5\", xm_hash_md5 },\n    { \"xxhash\", xm_hash_xxhash },\n    { \"rand32\", xm_hash_rand32 },\n    { \"rand64\", xm_hash_rand64 },\n    { \"rand128\", xm_hash_rand128 },\n    { tb_null, tb_null },\n};\n\n// the base64 functions\nstatic luaL_Reg const g_base64_functions[] = {\n    { \"encode\", xm_base64_encode },\n    { \"decode\", xm_base64_decode },\n    { tb_null, tb_null },\n};\n\n// the lz4 functions\nstatic luaL_Reg const g_lz4_functions[] = {\n    { \"compress\", xm_lz4_compress },\n    { \"decompress\", xm_lz4_decompress },\n    { \"block_compress\", xm_lz4_block_compress },\n    { \"block_decompress\", xm_lz4_block_decompress },\n    { \"compress_file\", xm_lz4_compress_file },\n    { \"decompress_file\", xm_lz4_decompress_file },\n    { \"compress_stream_open\", xm_lz4_compress_stream_open },\n    { \"compress_stream_read\", xm_lz4_compress_stream_read },\n    { \"compress_stream_write\", xm_lz4_compress_stream_write },\n    { \"compress_stream_close\", xm_lz4_compress_stream_close },\n    { \"decompress_stream_open\", xm_lz4_decompress_stream_open },\n    { \"decompress_stream_read\", xm_lz4_decompress_stream_read },\n    { \"decompress_stream_write\", xm_lz4_decompress_stream_write },\n    { \"decompress_stream_close\", xm_lz4_decompress_stream_close },\n    { tb_null, tb_null },\n};\n\n// the bloom filter functions\nstatic luaL_Reg const g_bloom_filter_functions[] = {\n    { \"open\", xm_bloom_filter_open },\n    { \"close\", xm_bloom_filter_close },\n    { \"clear\", xm_bloom_filter_clear },\n    { \"data\", xm_bloom_filter_data },\n    { \"size\", xm_bloom_filter_size },\n    { \"get\", xm_bloom_filter_get },\n    { \"set\", xm_bloom_filter_set },\n    { \"data_set\", xm_bloom_filter_data_set },\n    { tb_null, tb_null },\n};\n\n// the utf8 functions\nstatic luaL_Reg const g_utf8_functions[] = {\n    {\"char\", xm_utf8_char},\n    {\"byte\", xm_utf8_byte},\n    {\"codes\", xm_utf8_codes},\n    {\"codepoint\", xm_utf8_codepoint},\n    {\"len\", xm_utf8_len},\n    {\"offset\", xm_utf8_offset},\n    {\"sub\", xm_utf8_sub},\n    {\"reverse\", xm_utf8_reverse},\n    {\"lastof\", xm_utf8_lastof},\n    {\"find\", xm_utf8_find},\n    {\"width\", xm_utf8_width},\n    {\"wcwidth\", xm_utf8_width},\n    {\"wcswidth\", xm_utf8_width},\n    {tb_null, tb_null}\n};\n\n// the string functions\nstatic luaL_Reg const g_string_functions[] = {\n    { \"trim\", xm_string_trim },\n    { \"split\", xm_string_split },\n    { \"lastof\", xm_string_lastof },\n    { \"convert\", xm_string_convert },\n    { \"endswith\", xm_string_endswith },\n    { \"startswith\", xm_string_startswith },\n    { \"lower\", xm_string_lower },\n    { \"upper\", xm_string_upper },\n    { tb_null, tb_null },\n};\n\n// the process functions\nstatic luaL_Reg const g_process_functions[] = {\n    { \"open\", xm_process_open },\n    { \"openv\", xm_process_openv },\n    { \"wait\", xm_process_wait },\n    { \"kill\", xm_process_kill },\n    { \"close\", xm_process_close },\n    { tb_null, tb_null },\n};\n\n// the fwatcher functions\nstatic luaL_Reg const g_fwatcher_functions[] = {\n    { \"open\", xm_fwatcher_open },\n    { \"add\", xm_fwatcher_add },\n    { \"remove\", xm_fwatcher_remove },\n    { \"wait\", xm_fwatcher_wait },\n    { \"close\", xm_fwatcher_close },\n    { tb_null, tb_null },\n};\n\n// the sandbox functions\nstatic luaL_Reg const g_sandbox_functions[] = {\n    { \"interactive\", xm_sandbox_interactive },\n    { tb_null, tb_null },\n};\n\n#ifdef XM_CONFIG_API_HAVE_READLINE\n// the readline functions\nstatic luaL_Reg const g_readline_functions[] = {\n    { \"readline\", xm_readline_readline },\n    { \"history_list\", xm_readline_history_list },\n    { \"add_history\", xm_readline_add_history },\n    { \"clear_history\", xm_readline_clear_history },\n    { tb_null, tb_null },\n};\n#endif\n\n// the semver functions\nstatic luaL_Reg const g_semver_functions[] = {\n    { \"parse\", xm_semver_parse },\n    { \"compare\", xm_semver_compare },\n    { \"satisfies\", xm_semver_satisfies },\n    { \"select\", xm_semver_select },\n    { tb_null, tb_null },\n};\n\n// the libc functions\nstatic luaL_Reg const g_libc_functions[] = {\n    { \"malloc\", xm_libc_malloc },\n    { \"free\", xm_libc_free },\n    { \"memcpy\", xm_libc_memcpy },\n    { \"memset\", xm_libc_memset },\n    { \"memmov\", xm_libc_memmov },\n    { \"strndup\", xm_libc_strndup },\n    { \"dataptr\", xm_libc_dataptr },\n    { \"byteof\", xm_libc_byteof },\n    { \"setbyte\", xm_libc_setbyte },\n    { tb_null, tb_null },\n};\n\n// the tty functions\nstatic luaL_Reg const g_tty_functions[] = {\n    { \"term_mode\", xm_tty_term_mode },\n    { \"session_id\", xm_tty_session_id },\n    { tb_null, tb_null },\n};\n\n// the package functions\nstatic luaL_Reg const g_package_functions[] = {\n    { \"loadxmi\", xm_package_loadxmi },\n    { tb_null, tb_null },\n};\n\n// the binutils functions\nstatic luaL_Reg const g_binutils_functions[] = {\n    { \"bin2c\", xm_binutils_bin2c },\n    { \"bin2coff\", xm_binutils_bin2coff },\n    { \"bin2macho\", xm_binutils_bin2macho },\n    { \"bin2elf\", xm_binutils_bin2elf },\n    { \"readsyms\", xm_binutils_readsyms },\n    { \"deplibs\", xm_binutils_deplibs },\n    { \"rpath_list\", xm_binutils_rpath_list },\n    { \"rpath_clean\", xm_binutils_rpath_clean },\n    { \"extractlib\", xm_binutils_extractlib },\n    { \"format\", xm_binutils_format },\n    { tb_null, tb_null },\n};\n\n// the thread functions\nstatic luaL_Reg const g_thread_functions[] = {\n    { \"thread_init\", xm_thread_init },\n    { \"thread_exit\", xm_thread_exit },\n    { \"thread_wait\", xm_thread_wait },\n    { \"thread_resume\", xm_thread_resume },\n    { \"thread_suspend\", xm_thread_suspend },\n    { \"mutex_init\", xm_thread_mutex_init },\n    { \"mutex_exit\", xm_thread_mutex_exit },\n    { \"mutex_lock\", xm_thread_mutex_lock },\n    { \"mutex_trylock\", xm_thread_mutex_trylock },\n    { \"mutex_unlock\", xm_thread_mutex_unlock },\n    { \"mutex_incref\", xm_thread_mutex_incref },\n    { \"event_init\", xm_thread_event_init },\n    { \"event_exit\", xm_thread_event_exit },\n    { \"event_post\", xm_thread_event_post },\n    { \"event_wait\", xm_thread_event_wait },\n    { \"event_incref\", xm_thread_event_incref },\n    { \"semaphore_init\", xm_thread_semaphore_init },\n    { \"semaphore_exit\", xm_thread_semaphore_exit },\n    { \"semaphore_post\", xm_thread_semaphore_post },\n    { \"semaphore_wait\", xm_thread_semaphore_wait },\n    { \"semaphore_incref\", xm_thread_semaphore_incref },\n    { \"queue_init\", xm_thread_queue_init },\n    { \"queue_exit\", xm_thread_queue_exit },\n    { \"queue_size\", xm_thread_queue_size },\n    { \"queue_clear\", xm_thread_queue_clear },\n    { \"queue_incref\", xm_thread_queue_incref },\n    { \"queue_push\", xm_thread_queue_push },\n    { \"queue_pop\", xm_thread_queue_pop },\n    { \"sharedata_init\", xm_thread_sharedata_init },\n    { \"sharedata_exit\", xm_thread_sharedata_exit },\n    { \"sharedata_clear\", xm_thread_sharedata_clear },\n    { \"sharedata_incref\", xm_thread_sharedata_incref },\n    { \"sharedata_set\", xm_thread_sharedata_set },\n    { \"sharedata_get\", xm_thread_sharedata_get_ },\n    { tb_null, tb_null },\n};\n\n// the utf8 functions\n\n\n// the lua global instance for signal handler\nstatic lua_State *g_lua = tb_null;\n\n// the xmake script files data\n#ifdef XM_EMBED_ENABLE\n__tb_extern_c_enter__\nextern tb_byte_t _binary_xmake_xmz_start[];\nextern tb_byte_t _binary_xmake_xmz_end[];\n__tb_extern_c_leave__\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_bool_t xm_engine_save_arguments(xm_engine_t *engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) {\n    tb_assert_and_check_return_val(engine && engine->lua && argc >= 1 && argv, tb_false);\n\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    tb_wchar_t **argvw = CommandLineToArgvW(GetCommandLineW(), &argc);\n#endif\n\n    // put a new table into the stack\n    lua_newtable(engine->lua);\n\n    // patch the task arguments list\n    if (taskargv) {\n        tb_char_t **taskarg = taskargv;\n        while (*taskarg) {\n            lua_pushstring(engine->lua, *taskarg);\n            lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1);\n            taskarg++;\n        }\n    }\n\n    // save all arguments to the new table\n    tb_int_t i = 0;\n    for (i = 1; i < argc; i++) {\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n        tb_char_t argvbuf[4096] = { 0 };\n        tb_wcstombs(argvbuf, argvw[i], tb_arrayn(argvbuf));\n        // table_new[table.getn(table_new) + 1] = argv[i]\n        lua_pushstring(engine->lua, argvbuf);\n#else\n        lua_pushstring(engine->lua, argv[i]);\n#endif\n        lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1);\n    }\n\n    // _ARGV = table_new\n    lua_setglobal(engine->lua, \"_ARGV\");\n    return tb_true;\n}\n\nstatic tb_bool_t xm_engine_get_program_file(xm_engine_t *engine, tb_char_t **argv, tb_char_t *path, tb_size_t maxn) {\n    tb_assert_and_check_return_val(engine && path && maxn, tb_false);\n\n    /* we cache it, because the current path will be changed in thread.\n     *\n     * The executable file compiled using cosmocc on macOS might retrieve a relative path to the programfile.\n     * If the root directory has been changed, the retrieved programfile will be a non-existent path.\n     */\n    static tb_char_t s_program_filepath[TB_PATH_MAXN] = { 0 };\n    if (s_program_filepath[0]) {\n        tb_strlcpy(path, s_program_filepath, maxn);\n        lua_pushstring(engine->lua, s_program_filepath);\n        lua_setglobal(engine->lua, \"_PROGRAM_FILE\");\n        return tb_true;\n    }\n\n    tb_bool_t ok = tb_false;\n    do {\n        // get it from the environment variable first\n        if (tb_environment_first(\"XMAKE_PROGRAM_FILE\", path, maxn) && tb_file_info(path, tb_null)) {\n            ok = tb_true;\n            break;\n        }\n\n#if defined(TB_CONFIG_OS_WINDOWS)\n        // get the executale file path as program directory\n        tb_wchar_t buf[TB_PATH_MAXN] = { 0 };\n        tb_size_t size = (tb_size_t)GetModuleFileNameW(tb_null, buf, (DWORD)TB_PATH_MAXN);\n        tb_assert_and_check_break(size < TB_PATH_MAXN);\n        buf[size] = L'\\0';\n        size = tb_wcstombs(path, buf, maxn);\n        tb_assert_and_check_break(size < maxn);\n        path[size] = '\\0';\n\n        ok = tb_true;\n\n#elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)\n        /*\n         * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter\n         * should initially be the size of the buffer.  The function returns 0 if the path was successfully copied,\n         * and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set\n         * to the size required.\n         *\n         * Note that _NSGetExecutablePath will return \"a path\" to the executable not a \"real path\" to the executable.\n         * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize\n         * needed could be more than MAXPATHLEN.\n         */\n        tb_uint32_t bufsize = (tb_uint32_t)maxn;\n        if (!_NSGetExecutablePath(path, &bufsize)) {\n            ok = tb_true;\n        }\n#elif defined(XM_PROC_SELF_FILE)\n        /* get the executale file path as program directory\n         *\n         * @see it may be a relative path\n         */\n        ssize_t size = readlink(XM_PROC_SELF_FILE, path, (size_t)maxn);\n        if (size > 0 && size < maxn) {\n            path[size] = '\\0';\n            // ignore cosmocc ape binary, we fallback to argv[0], .e.g /usr/bin/ape, /home/ruki/.ape-1.10\n            tb_char_t const* filename = tb_strrchr(path, '/');\n            if (!tb_strstr(filename ? filename + 1 : path, \"ape\")) {\n                ok = tb_true;\n            }\n        }\n#elif defined(TB_CONFIG_OS_BSD) && defined(KERN_PROC_PATHNAME)\n        // only for FreeBSD and OpenBSD, https://github.com/xmake-io/xmake/issues/2948\n        tb_int_t mib[4];\n        mib[0] = CTL_KERN;\n        mib[1] = KERN_PROC;\n        mib[2] = KERN_PROC_PATHNAME;\n        mib[3] = -1;\n        size_t size = maxn;\n        if (sysctl(mib, 4, path, &size, tb_null, 0) == 0 && size < maxn) {\n            path[size] = '\\0';\n            ok = tb_true;\n        }\n#elif defined(TB_CONFIG_OS_HAIKU)\n        int32 cookie = 0;\n        image_info info;\n        while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {\n            if (info.type == B_APP_IMAGE) {\n                tb_strlcpy(path, info.name, maxn);\n                ok = tb_true;\n                break;\n            }\n        }\n#else\n        static tb_char_t const *s_paths[] = {\n            \"~/.local/bin/xmake\",\n            \"/usr/local/bin/xmake\",\n            \"/usr/bin/xmake\",\n        };\n        for (tb_size_t i = 0; i < tb_arrayn(s_paths); i++) {\n            tb_char_t const *p = s_paths[i];\n            if (tb_file_info(p, tb_null)) {\n                tb_strlcpy(path, p, maxn);\n                ok = tb_true;\n                break;\n            }\n        }\n#endif\n\n        if (!ok && argv) {\n            tb_char_t const *p = argv[0];\n            if (p && tb_file_info(p, tb_null)) {\n                if (tb_path_is_absolute(p)) {\n                    tb_strlcpy(path, p, maxn);\n                } else {\n                    if (!tb_path_absolute(p, path, maxn)) {\n                        tb_strlcpy(path, p, maxn);\n                    }\n                }\n                ok = tb_true;\n            }\n        }\n\n    } while (0);\n\n    if (ok) {\n        tb_trace_d(\"programfile: %s\", path);\n\n        // cache it\n        tb_strlcpy(s_program_filepath, path, sizeof(s_program_filepath));\n\n        // save the directory to the global variable: _PROGRAM_FILE\n        lua_pushstring(engine->lua, path);\n        lua_setglobal(engine->lua, \"_PROGRAM_FILE\");\n    }\n    return ok;\n}\n\n#ifdef XM_EMBED_ENABLE\nstatic tb_bool_t xm_engine_get_temporary_directory(tb_char_t *path,\n                                                   tb_size_t maxn,\n                                                   tb_char_t const *name,\n                                                   tb_char_t const *version_cstr) {\n    tb_char_t data[TB_PATH_MAXN] = { 0 };\n    if (tb_directory_temporary(data, sizeof(data))) {\n        // get euid\n        tb_int_t euid = 0;\n#ifndef TB_CONFIG_OS_WINDOWS\n        euid = geteuid();\n#endif\n\n        tb_snprintf(path, maxn, \"%s/.%s%d/%s\", data, name, euid, version_cstr);\n        return tb_true;\n    }\n    return tb_false;\n}\n#endif\n\nstatic tb_bool_t xm_engine_get_program_directory(xm_engine_t *engine,\n                                                 tb_char_t *path,\n                                                 tb_size_t maxn,\n                                                 tb_char_t const *programfile) {\n    tb_assert_and_check_return_val(engine && path && maxn, tb_false);\n\n    static tb_char_t s_program_directory[TB_PATH_MAXN] = { 0 };\n    if (s_program_directory[0]) {\n        tb_strlcpy(path, s_program_directory, maxn);\n        lua_pushstring(engine->lua, s_program_directory);\n        lua_setglobal(engine->lua, \"_PROGRAM_DIR\");\n        return tb_true;\n    }\n\n    tb_bool_t ok = tb_false;\n    tb_char_t data[TB_PATH_MAXN] = { 0 };\n    do {\n#ifdef XM_EMBED_ENABLE\n        tb_size_t embedcount = engine->embedcount;\n        if (embedcount) {\n            tb_uint32_t crc32 = 0;\n            for (tb_size_t i = 0; i < embedcount; i++) {\n                crc32 += tb_crc32_make(engine->embeddata[i], engine->embedsize[i], 0);\n            }\n            tb_snprintf(path, maxn, \"%s/%x\", engine->tmpdir, crc32);\n        } else {\n            tb_strlcpy(path, engine->tmpdir, maxn);\n        }\n        ok = tb_true;\n        break;\n#endif\n\n        // get it from the environment variable first\n        if (tb_environment_first(\"XMAKE_PROGRAM_DIR\", data, sizeof(data)) && tb_path_absolute(data, path, maxn)) {\n            ok = tb_true;\n            break;\n        }\n\n        // get it from program file path\n        if (programfile) {\n            // get real program file path from the symbol link\n#if !defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_CONFIG_OS_IOS)\n            tb_char_t programpath[TB_PATH_MAXN];\n            tb_long_t size = readlink(programfile, programpath, sizeof(programpath));\n            if (size >= 0 && size < sizeof(programpath)) {\n                programpath[size] = '\\0';\n\n                // soft link to relative path? fix it\n                if (!tb_path_is_absolute(programpath)) {\n                    tb_char_t buff[TB_PATH_MAXN];\n                    tb_char_t const *rootdir = tb_path_directory(programfile, buff, sizeof(buff));\n                    if (rootdir && tb_path_absolute_to(\n                                       rootdir,\n                                       programpath,\n                                       path,\n                                       maxn)) { // @note path and programfile are same buffer\n                        tb_strlcpy(programpath, path, maxn);\n                    }\n                }\n            } else\n                tb_strlcpy(programpath, programfile, sizeof(programpath));\n#else\n            tb_char_t const *programpath = programfile;\n#endif\n\n            // get the root directory\n            tb_char_t data[TB_PATH_MAXN];\n            tb_char_t const *rootdir = tb_path_directory(programpath, data, sizeof(data));\n            tb_assert_and_check_break(rootdir);\n\n            // init share/name sub-directory\n            tb_char_t sharedir[128];\n            tb_snprintf(sharedir, sizeof(sharedir), \"../share/%s\", engine->name);\n\n            // find the program (lua) directory\n            tb_size_t i;\n            tb_file_info_t info;\n            tb_char_t scriptpath[TB_PATH_MAXN];\n            tb_char_t const *subdirs[] = {\n                \".\",\n                sharedir,\n            };\n            for (i = 0; i < tb_arrayn(subdirs); i++) {\n                // get program directory\n                if (tb_path_absolute_to(rootdir, subdirs[i], path, maxn) &&\n                    tb_path_absolute_to(path, \"core/_xmake_main.lua\", scriptpath, sizeof(scriptpath)) &&\n                    tb_file_info(scriptpath, &info) && info.type == TB_FILE_TYPE_FILE) {\n                    ok = tb_true;\n                    break;\n                }\n            }\n        }\n\n    } while (0);\n\n    if (ok) {\n        tb_trace_d(\"programdir: %s\", path);\n\n        // cache it\n        tb_strlcpy(s_program_directory, path, sizeof(s_program_directory));\n\n        // save the directory to the global variable: _PROGRAM_DIR\n        lua_pushstring(engine->lua, path);\n        lua_setglobal(engine->lua, \"_PROGRAM_DIR\");\n    }\n\n    return ok;\n}\n\nstatic tb_bool_t xm_engine_get_project_directory(xm_engine_t *engine, tb_char_t *path, tb_size_t maxn) {\n    tb_assert_and_check_return_val(engine && path && maxn, tb_false);\n\n    tb_bool_t ok = tb_false;\n    do {\n        // attempt to get it from the environment variable first\n        tb_char_t data[TB_PATH_MAXN] = { 0 };\n        if (!tb_environment_first(\"XMAKE_PROJECT_DIR\", data, sizeof(data)) || !tb_path_absolute(data, path, maxn)) {\n            // get it from the current directory\n            if (!tb_directory_current(path, maxn)) {\n                break;\n            }\n        }\n\n        tb_trace_d(\"project: %s\", path);\n\n        // save the directory to the global variable: _PROJECT_DIR\n        lua_pushstring(engine->lua, path);\n        lua_setglobal(engine->lua, \"_PROJECT_DIR\");\n\n        ok = tb_true;\n\n    } while (0);\n\n    // failed?\n    if (!ok) {\n        tb_printf(\"error: not found the project directory!\\n\");\n    }\n\n    return ok;\n}\n\n#if defined(TB_CONFIG_OS_WINDOWS) || defined(SIGINT)\nstatic tb_void_t xm_engine_dump_traceback(lua_State *lua) {\n    // @note it's not safe, but it doesn't matter, we're just trying to get the stack backtrace for debugging\n    lua_getglobal(lua, \"debug\");\n    lua_getfield(lua, -1, \"traceback\");\n    lua_replace(lua, -2);\n    lua_pushvalue(lua, 1);\n    lua_call(lua, 1, 1);\n    tb_trace_i(\"%s\", lua_tostring(lua, -1));\n}\n#endif\n\n#if defined(TB_CONFIG_OS_WINDOWS)\nstatic BOOL WINAPI xm_engine_signal_handler(DWORD signo) {\n    if (signo == CTRL_C_EVENT && g_lua) {\n        xm_engine_dump_traceback(g_lua);\n        tb_abort();\n    }\n    return TRUE;\n}\n#elif defined(SIGINT)\nstatic tb_void_t xm_engine_signal_handler(tb_int_t signo) {\n    if (signo == SIGINT && g_lua) {\n        xm_engine_dump_traceback(g_lua);\n        tb_abort();\n    }\n}\n#endif\n\nstatic tb_void_t xm_engine_init_host(xm_engine_t *engine) {\n    tb_assert_and_check_return(engine && engine->lua);\n\n    // init system host\n    tb_char_t const *syshost = tb_null;\n#if defined(__COSMOPOLITAN__)\n    struct utsname buffer;\n    if (uname(&buffer) == 0) {\n        if (tb_strstr(buffer.sysname, \"Darwin\")) {\n            syshost = \"macosx\";\n        } else if (tb_strstr(buffer.sysname, \"Linux\")) {\n            syshost = \"linux\";\n        } else if (tb_strstr(buffer.sysname, \"Windows\")) {\n            syshost = \"windows\";\n        }\n    }\n#elif defined(TB_CONFIG_OS_WINDOWS)\n    syshost = \"windows\";\n#elif defined(TB_CONFIG_OS_MACOSX)\n    syshost = \"macosx\";\n#elif defined(TB_CONFIG_OS_LINUX)\n    syshost = \"linux\";\n#elif defined(TB_CONFIG_OS_BSD)\n    syshost = \"bsd\";\n#elif defined(TB_CONFIG_OS_SOLARIS)\n    syshost = \"solaris\";\n#elif defined(TB_CONFIG_OS_IOS)\n    syshost = \"ios\";\n#elif defined(TB_CONFIG_OS_ANDROID)\n    syshost = \"android\";\n#elif defined(TB_CONFIG_OS_HAIKU)\n    syshost = \"haiku\";\n#endif\n    lua_pushstring(engine->lua, syshost ? syshost : \"unknown\");\n    lua_setglobal(engine->lua, \"_HOST\");\n\n    // init subsystem host\n    tb_char_t const *subhost = syshost;\n#if defined(TB_CONFIG_OS_WINDOWS)\n#if defined(TB_COMPILER_ON_MSYS)\n    subhost = \"msys\";\n#elif defined(TB_COMPILER_ON_CYGWIN)\n    subhost = \"cygwin\";\n#else\n    {\n        tb_char_t data[64] = { 0 };\n        if (tb_environment_first(\"MSYSTEM\", data, sizeof(data))) {\n            // on msys?\n            if (!tb_strnicmp(data, \"mingw\", 5) // mingw32/64 on msys2\n                || !tb_strnicmp(data,\n                                \"clang\",\n                                5) // clang32/64 on msys2, @see https://github.com/xmake-io/xmake/issues/3060\n                || !tb_stricmp(data, \"ucrt64\") // ucrt64 https://www.msys2.org/docs/environments/\n                || !tb_stricmp(data, \"msys\")) { // on msys2\n                subhost = \"msys\";\n            }\n        }\n    }\n#endif\n#endif\n    lua_pushstring(engine->lua, subhost ? subhost : \"unknown\");\n    lua_setglobal(engine->lua, \"_SUBHOST\");\n}\n\nstatic __tb_inline__ tb_char_t const *xm_engine_xmake_arch() {\n    tb_char_t const *arch = tb_null;\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#if defined(TB_ARCH_x64)\n    arch = \"x64\";\n#elif defined(TB_ARCH_ARM64)\n    arch = \"arm64\";\n#elif defined(TB_ARCH_ARM)\n    arch = \"arm\";\n#else\n    arch = \"x86\";\n#endif\n#elif defined(TB_ARCH_x64)\n    arch = \"x86_64\";\n#elif defined(TB_ARCH_x86)\n    arch = \"i386\";\n#elif defined(TB_ARCH_ARM64)\n    arch = \"arm64\";\n#else\n    arch = TB_ARCH_STRING;\n#endif\n    return arch;\n}\n\nstatic tb_void_t xm_engine_init_arch(xm_engine_t *engine) {\n    tb_assert_and_check_return(engine && engine->lua);\n\n    // init xmake arch\n    tb_char_t const *xmakearch = xm_engine_xmake_arch();\n    lua_pushstring(engine->lua, xmakearch);\n    lua_setglobal(engine->lua, \"_XMAKE_ARCH\");\n\n    // init system architecture\n    tb_char_t const *sysarch = tb_null;\n#if defined(__COSMOPOLITAN__)\n    struct utsname buffer;\n    if (uname(&buffer) == 0) {\n        sysarch = buffer.machine;\n        if (tb_strstr(buffer.sysname, \"Windows\")) {\n            if (!tb_strcmp(buffer.machine, \"x86_64\")) {\n                sysarch = \"x64\";\n            } else if (!tb_strcmp(buffer.machine, \"i686\") || !tb_strcmp(buffer.machine, \"i386\")) {\n                sysarch = \"x86\";\n            }\n        } else if (!tb_strcmp(buffer.machine, \"aarch64\")) {\n            sysarch = \"arm64\";\n        }\n    }\n#elif defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    // the GetNativeSystemInfo function type\n    typedef void(WINAPI * GetNativeSystemInfo_t)(LPSYSTEM_INFO);\n\n    // get system info\n    SYSTEM_INFO systeminfo = { 0 };\n    GetNativeSystemInfo_t pGetNativeSystemInfo = tb_null;\n    tb_dynamic_ref_t kernel32 = tb_dynamic_init(\"kernel32.dll\");\n    if (kernel32) {\n        pGetNativeSystemInfo = (GetNativeSystemInfo_t)tb_dynamic_func(kernel32, \"GetNativeSystemInfo\");\n    }\n    if (pGetNativeSystemInfo) {\n        pGetNativeSystemInfo(&systeminfo);\n    } else {\n        GetSystemInfo(&systeminfo);\n    }\n\n    // init architecture\n    switch (systeminfo.wProcessorArchitecture) {\n    case PROCESSOR_ARCHITECTURE_AMD64:\n        sysarch = \"x64\";\n        break;\n#if defined(PROCESSOR_ARCHITECTURE_ARM64)\n    case PROCESSOR_ARCHITECTURE_ARM64:\n        sysarch = \"arm64\";\n        break;\n#endif\n    case PROCESSOR_ARCHITECTURE_ARM:\n        sysarch = \"arm\";\n        break;\n    case PROCESSOR_ARCHITECTURE_INTEL:\n        sysarch = \"x86\";\n        break;\n    default:\n        break;\n    }\n#endif\n    if (!sysarch) {\n        sysarch = xmakearch;\n    }\n    lua_pushstring(engine->lua, sysarch);\n    lua_setglobal(engine->lua, \"_ARCH\");\n\n    // init subsystem architecture\n    tb_char_t const *subarch = sysarch;\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    // get architecture from msys environment\n    tb_char_t data[64] = { 0 };\n    if (tb_environment_first(\"MSYSTEM_CARCH\", data, sizeof(data))) {\n        if (!tb_strcmp(data, \"i686\")) {\n            subarch = \"i386\";\n        } else {\n            subarch = data;\n        }\n    }\n#endif\n    lua_pushstring(engine->lua, subarch);\n    lua_setglobal(engine->lua, \"_SUBARCH\");\n}\n\nstatic tb_void_t xm_engine_init_features(xm_engine_t *engine) {\n    tb_assert_and_check_return(engine && engine->lua);\n\n    // init features\n    lua_newtable(engine->lua);\n\n    // get path seperator\n    lua_pushstring(engine->lua, \"path_sep\");\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    lua_pushstring(engine->lua, \"\\\\\");\n#else\n    lua_pushstring(engine->lua, \"/\");\n#endif\n    lua_settable(engine->lua, -3);\n\n    // get environment path seperator\n    lua_pushstring(engine->lua, \"path_envsep\");\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    lua_pushstring(engine->lua, \";\");\n#else\n    lua_pushstring(engine->lua, \":\");\n#endif\n    lua_settable(engine->lua, -3);\n\n    lua_setglobal(engine->lua, \"_FEATURES\");\n}\n\nstatic tb_void_t xm_engine_init_signal(xm_engine_t *engine) {\n    // we enable it to catch the current lua stack in ctrl-c signal handler if XMAKE_PROFILE=stuck\n    tb_char_t data[64] = { 0 };\n    if (!tb_environment_first(\"XMAKE_PROFILE\", data, sizeof(data)) || tb_strcmp(data, \"stuck\")) {\n        return;\n    }\n\n    g_lua = engine->lua;\n#if defined(TB_CONFIG_OS_WINDOWS)\n    SetConsoleCtrlHandler(xm_engine_signal_handler, TRUE);\n#elif defined(SIGINT)\n    signal(SIGINT, xm_engine_signal_handler);\n#endif\n}\n\n#if XM_HOOK_LUA_MEMALLOC\n// udata is unused, it has been used by engine. see xm_engine_bind_to_lua()\nstatic tb_pointer_t xm_engine_lua_realloc(tb_pointer_t udata, tb_pointer_t data, size_t osize, size_t nsize) {\n    tb_pointer_t ptr = tb_null;\n    if (nsize == 0 && data) {\n        tb_free(data);\n    } else if (!data) {\n        ptr = tb_malloc((tb_size_t)nsize);\n    } else if (nsize != osize) {\n        ptr = tb_ralloc(data, (tb_size_t)nsize);\n    } else {\n        ptr = data;\n    }\n    return ptr;\n}\n#endif\n\n#ifdef XM_EMBED_ENABLE\nstatic tb_bool_t xm_engine_extract_programfiles_impl(xm_engine_t *engine,\n                                                     tb_char_t const *programdir,\n                                                     tb_byte_t const *data,\n                                                     tb_size_t size) {\n    // do decompress\n    tb_bool_t ok = tb_false;\n    LZ4F_errorCode_t code;\n    LZ4F_decompressionContext_t ctx = tb_null;\n    tb_buffer_t result;\n    do {\n        tb_buffer_init(&result);\n\n        code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);\n        if (LZ4F_isError(code)) {\n            break;\n        }\n\n        tb_byte_t buffer[8192];\n        tb_bool_t failed = tb_false;\n        while (1) {\n            size_t advance = (size_t)size;\n            size_t buffer_size = sizeof(buffer);\n            code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null);\n            if (LZ4F_isError(code)) {\n                failed = tb_true;\n                break;\n            }\n\n            if (buffer_size == 0) {\n                break;\n            }\n            data += advance;\n            size -= advance;\n\n            tb_buffer_memncat(&result, buffer, buffer_size);\n        }\n        tb_assert_and_check_break(!failed && tb_buffer_size(&result));\n\n        ok = tb_true;\n    } while (0);\n\n    // extract files to programdir\n    if (ok) {\n        data = tb_buffer_data(&result);\n        size = tb_buffer_size(&result);\n        tb_byte_t const *p = data;\n        tb_byte_t const *e = data + size;\n        tb_size_t n = 0;\n        tb_char_t filepath[TB_PATH_MAXN];\n        tb_long_t pos = tb_snprintf(filepath, sizeof(filepath), \"%s/\", programdir);\n        while (p < e) {\n            // get filepath\n            n = (tb_size_t)tb_bits_get_u16_be(p);\n            p += 2;\n            tb_assert_and_check_break(pos + n + 1 < sizeof(filepath));\n            tb_strncpy(filepath + pos, (tb_char_t const *)p, n);\n            filepath[pos + n] = '\\0';\n            p += n;\n\n            // get filedata\n            n = (tb_size_t)tb_bits_get_u32_be(p);\n            p += 4;\n\n            // write file\n            tb_trace_d(\"extracting %s, %lu bytes ..\", filepath, n);\n            tb_stream_ref_t stream = tb_stream_init_from_file(filepath,\n                                                              TB_FILE_MODE_RW | TB_FILE_MODE_CREAT |\n                                                                  TB_FILE_MODE_TRUNC);\n            tb_assert_and_check_break(stream);\n\n            if (tb_stream_open(stream)) {\n                tb_stream_bwrit(stream, p, n);\n                tb_stream_exit(stream);\n            }\n\n            p += n;\n        }\n        ok = (p == e);\n        if (!ok) {\n            tb_trace_e(\"extract program files failed\");\n        }\n    } else {\n        tb_trace_e(\"decompress program files failed, %s\", LZ4F_getErrorName(code));\n    }\n\n    if (ctx) {\n        LZ4F_freeDecompressionContext(ctx);\n        ctx = tb_null;\n    }\n    tb_buffer_exit(&result);\n    return ok;\n}\n\nstatic tb_bool_t xm_engine_extract_programfiles(xm_engine_t *engine, tb_char_t const *programdir) {\n    tb_file_info_t info = { 0 };\n    if (!tb_file_info(programdir, &info)) {\n        tb_byte_t const *data = _binary_xmake_xmz_start;\n        tb_size_t size = _binary_xmake_xmz_end - _binary_xmake_xmz_start;\n        if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) {\n            return tb_false;\n        }\n\n        tb_size_t embedcount = engine->embedcount;\n        for (tb_size_t i = 0; i < embedcount; i++) {\n            data = engine->embeddata[i];\n            size = engine->embedsize[i];\n            if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) {\n                return tb_false;\n            }\n        }\n    }\n    return tb_true;\n}\n#endif\n\nstatic tb_void_t xm_engine_bind_to_lua(lua_State *lua, xm_engine_t *engine) {\n    lua_pushlightuserdata(lua, engine);\n    lua_setglobal(lua, \"__global_engine\");\n}\n\n// load and execute the main script\nstatic tb_bool_t xm_engine_load_main_script(xm_engine_t *engine, tb_char_t const *mainfile) {\n#ifdef TB_CONFIG_OS_WINDOWS\n    // use tb_file_init to support unicode file path on windows\n    tb_bool_t ok = tb_false;\n    tb_file_ref_t file = tb_null;\n    tb_byte_t *data = tb_null;\n\n    do {\n        // open file\n        file = tb_file_init(mainfile, TB_FILE_MODE_RO);\n        if (!file) {\n            tb_printf(\"error: cannot open file: %s\\n\", mainfile);\n            break;\n        }\n\n        // get file size\n        tb_size_t size = (tb_size_t)tb_file_size(file);\n        tb_assert_and_check_break(size);\n\n        // allocate buffer\n        data = (tb_byte_t *)tb_malloc(size);\n        tb_assert_and_check_break(data);\n\n        // read file content\n        if (!tb_file_read(file, data, size)) {\n            tb_printf(\"error: cannot read file: %s\\n\", mainfile);\n            break;\n        }\n\n        // load lua buffer\n        if (luaL_loadbuffer(engine->lua, (tb_char_t const *)data, size, mainfile)) {\n            tb_printf(\"error: %s\\n\", lua_tostring(engine->lua, -1));\n            break;\n        }\n\n        // execute lua script\n        if (lua_pcall(engine->lua, 0, LUA_MULTRET, 0)) {\n            tb_printf(\"error: %s\\n\", lua_tostring(engine->lua, -1));\n            break;\n        }\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (data) {\n        tb_free(data);\n    }\n    if (file) {\n        tb_file_exit(file);\n    }\n    return ok;\n#else\n    if (luaL_dofile(engine->lua, mainfile)) {\n        tb_printf(\"error: %s\\n\", lua_tostring(engine->lua, -1));\n        return tb_false;\n    }\n    return tb_true;\n#endif\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nxm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer) {\n    tb_bool_t ok = tb_false;\n    xm_engine_t *engine = tb_null;\n    do {\n        // init self\n        engine = tb_malloc0_type(xm_engine_t);\n        tb_assert_and_check_break(engine);\n\n        // init name\n        tb_strlcpy(engine->name, name, sizeof(engine->name));\n\n        // init lua\n#if XM_HOOK_LUA_MEMALLOC\n        engine->lua = lua_newstate(xm_engine_lua_realloc, tb_null);\n#else\n        engine->lua = luaL_newstate();\n#endif\n        tb_assert_and_check_break(engine->lua);\n\n        // open lua libraries\n        luaL_openlibs(engine->lua);\n\n        // bind os functions\n        xm_lua_register(engine->lua, \"os\", g_os_functions);\n\n        // bind io functions\n        xm_lua_register(engine->lua, \"io\", g_io_functions);\n\n        // bind path functions\n        xm_lua_register(engine->lua, \"path\", g_path_functions);\n\n        // bind hash functions\n        xm_lua_register(engine->lua, \"hash\", g_hash_functions);\n\n        // bind lz4 functions\n        xm_lua_register(engine->lua, \"lz4\", g_lz4_functions);\n\n        // bind bloom filter functions\n        xm_lua_register(engine->lua, \"bloom_filter\", g_bloom_filter_functions);\n\n        // bind base64 functions\n        xm_lua_register(engine->lua, \"base64\", g_base64_functions);\n\n        // bind utf8 functions\n        xm_lua_register(engine->lua, \"utf8\", g_utf8_functions);\n\n        // bind string functions\n        xm_lua_register(engine->lua, \"string\", g_string_functions);\n\n        // bind process functions\n        xm_lua_register(engine->lua, \"process\", g_process_functions);\n\n        // bind fwatcher functions\n        xm_lua_register(engine->lua, \"fwatcher\", g_fwatcher_functions);\n\n        // bind sandbox functions\n        xm_lua_register(engine->lua, \"sandbox\", g_sandbox_functions);\n\n        // bind windows functions\n#ifdef TB_CONFIG_OS_WINDOWS\n        xm_lua_register(engine->lua, \"winos\", g_winos_functions);\n#endif\n\n#ifdef XM_CONFIG_API_HAVE_READLINE\n        // bind readline functions\n        xm_lua_register(engine->lua, \"readline\", g_readline_functions);\n#endif\n\n        // bind semver functions\n        xm_lua_register(engine->lua, \"semver\", g_semver_functions);\n\n        // bind libc functions\n        xm_lua_register(engine->lua, \"libc\", g_libc_functions);\n\n        // bind tty functions\n        xm_lua_register(engine->lua, \"tty\", g_tty_functions);\n\n        // bind package functions\n        xm_lua_register(engine->lua, \"package\", g_package_functions);\n\n        // bind binutils functions\n        xm_lua_register(engine->lua, \"binutils\", g_binutils_functions);\n\n        // bind thread functions\n        xm_lua_register(engine->lua, \"thread\", g_thread_functions);\n\n#ifdef XM_CONFIG_API_HAVE_CURSES\n        // bind curses\n        xm_lua_curses_register(engine->lua, \"curses\");\n#endif\n\n#ifdef XM_CONFIG_API_HAVE_LUA_CJSON\n        // bind cjson\n        luaopen_cjson(engine->lua);\n        lua_setglobal(engine->lua, \"cjson\");\n#endif\n\n        // bind engine to lua\n        xm_engine_bind_to_lua(engine->lua, engine);\n\n        // init host\n        xm_engine_init_host(engine);\n\n        // init architecture\n        xm_engine_init_arch(engine);\n\n        // init features\n        xm_engine_init_features(engine);\n\n        // init signal\n        xm_engine_init_signal(engine);\n\n        // get version\n        tb_version_t const *version = xm_version();\n        tb_assert_and_check_break(version);\n\n        // init version string\n        tb_char_t version_cstr[256] = { 0 };\n        if (tb_strcmp(XM_CONFIG_VERSION_BRANCH, \"\") && tb_strcmp(XM_CONFIG_VERSION_COMMIT, \"\")) {\n            tb_snprintf(version_cstr,\n                        sizeof(version_cstr),\n                        \"%u.%u.%u+%s.%s\",\n                        version->major,\n                        version->minor,\n                        version->alter,\n                        XM_CONFIG_VERSION_BRANCH,\n                        XM_CONFIG_VERSION_COMMIT);\n        } else {\n            tb_snprintf(version_cstr,\n                        sizeof(version_cstr),\n                        \"%u.%u.%u+%llu\",\n                        version->major,\n                        version->minor,\n                        version->alter,\n                        (unsigned long long)version->build);\n        }\n        lua_pushstring(engine->lua, version_cstr);\n        lua_setglobal(engine->lua, \"_VERSION\");\n\n#ifdef XM_EMBED_ENABLE\n        // init the temporary directory\n        if (!xm_engine_get_temporary_directory(engine->tmpdir,\n                                               sizeof(engine->tmpdir),\n                                               name,\n                                               version_cstr)) {\n            break;\n        }\n\n        lua_pushboolean(engine->lua, tb_true);\n        lua_setglobal(engine->lua, \"_EMBED\");\n#endif\n\n        // init short version string\n        tb_snprintf(version_cstr, sizeof(version_cstr), \"%u.%u.%u\", version->major, version->minor, version->alter);\n        lua_pushstring(engine->lua, version_cstr);\n        lua_setglobal(engine->lua, \"_VERSION_SHORT\");\n\n        // init engine name\n        lua_pushstring(engine->lua, name ? name : \"xmake\");\n        lua_setglobal(engine->lua, \"_NAME\");\n\n        // use luajit as runtime?\n#ifdef USE_LUAJIT\n        lua_pushboolean(engine->lua, tb_true);\n#else\n        lua_pushboolean(engine->lua, tb_false);\n#endif\n        lua_setglobal(engine->lua, \"_LUAJIT\");\n\n        // init namespace: xmake\n        lua_newtable(engine->lua);\n        lua_setglobal(engine->lua, \"xmake\");\n\n        /* do lua initializer and init namespace: _lni\n         *\n         * we can get the lni modules for _lni or `import(\"lib.lni.xxx\")` in sandbox\n         */\n        lua_newtable(engine->lua);\n        if (lni_initalizer) {\n            lni_initalizer((xm_engine_ref_t)engine, engine->lua);\n        }\n        lua_setglobal(engine->lua, \"_lni\");\n\n#ifdef TB_CONFIG_OS_WINDOWS\n        // enable terminal colors output for windows cmd\n        HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);\n        if (output != INVALID_HANDLE_VALUE) {\n            DWORD mode;\n            if (GetConsoleMode(output, &mode)) {\n                // attempt to enable 0x4: ENABLE_VIRTUAL_TERMINAL_PROCESSING\n                if (SetConsoleMode(output, mode | 0x4)) {\n                    tb_environment_set(\"COLORTERM\", \"color256\");\n                }\n            }\n        }\n#endif\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (engine) {\n            xm_engine_exit((xm_engine_ref_t)engine);\n        }\n        engine = tb_null;\n    }\n    return (xm_engine_ref_t)engine;\n}\ntb_void_t xm_engine_exit(xm_engine_ref_t self) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return(engine);\n\n    // exit lua\n    if (engine->lua) {\n        lua_close(engine->lua);\n    }\n    engine->lua = tb_null;\n\n    // exit poller\n    if (engine->poller) {\n        tb_poller_exit(engine->poller);\n    }\n    engine->poller = tb_null;\n\n    // exit it\n    tb_free(engine);\n}\ntb_int_t xm_engine_main(xm_engine_ref_t self, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return_val(engine && engine->lua, -1);\n\n#if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_IS_MSVC)\n    // set \"stdin\" to have unicode mode\n    if (_isatty(_fileno(stdin))) {\n        _setmode(_fileno(stdin), _O_U16TEXT);\n    }\n#endif\n\n    // save main arguments to the global variable: _ARGV\n    if (!xm_engine_save_arguments(engine, argc, argv, taskargv)) {\n        return -1;\n    }\n\n    // get the project directory\n    tb_char_t path[TB_PATH_MAXN] = { 0 };\n    if (!xm_engine_get_project_directory(engine, path, sizeof(path))) {\n        return -1;\n    }\n\n    // get the program file\n    if (!xm_engine_get_program_file(engine, argv, path, sizeof(path))) {\n        return -1;\n    }\n\n    // get the program directory\n    if (!xm_engine_get_program_directory(engine, path, sizeof(path), path)) {\n        return -1;\n    }\n\n#ifdef XM_EMBED_ENABLE\n    if (!xm_engine_extract_programfiles(engine, path)) {\n        return -1;\n    }\n#endif\n\n    // append the main script path\n    tb_strcat(path, \"/core/_xmake_main.lua\");\n\n    // exists this script?\n    if (!tb_file_info(path, tb_null)) {\n        tb_printf(\"not found main script: %s\\n\", path);\n        return -1;\n    }\n\n    tb_trace_d(\"main: %s\", path);\n\n    // load and execute the main script\n    if (!xm_engine_load_main_script(engine, path)) {\n        return -1;\n    }\n\n    // set the error function\n    lua_getglobal(engine->lua, \"debug\");\n    lua_getfield(engine->lua, -1, \"traceback\");\n\n    // call the main function\n    lua_getglobal(engine->lua, \"_xmake_main\");\n    if (lua_pcall(engine->lua, 0, 1, -2)) {\n        tb_printf(\"error: %s\\n\", lua_tostring(engine->lua, -1));\n        return -1;\n    }\n\n    // get the error code\n    return (tb_int_t)lua_tonumber(engine->lua, -1);\n}\ntb_void_t xm_engine_register(xm_engine_ref_t self, tb_char_t const *module, luaL_Reg const funcs[]) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return(engine && engine->lua && module && funcs);\n\n    // do register\n    lua_pushstring(engine->lua, module);\n    lua_newtable(engine->lua);\n    xm_lua_register(engine->lua, tb_null, funcs);\n    lua_rawset(engine->lua, -3);\n}\n#ifdef XM_EMBED_ENABLE\ntb_void_t xm_engine_add_embedfiles(xm_engine_ref_t self, tb_byte_t const *data, tb_size_t size) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return(engine && engine->embedcount < tb_arrayn(engine->embedsize) && data && size);\n\n    engine->embeddata[engine->embedcount] = data;\n    engine->embedsize[engine->embedcount] = size;\n    engine->embedcount++;\n}\n#endif\nlua_State *xm_engine_lua(xm_engine_ref_t self) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return_val(engine, tb_null);\n\n    return engine->lua;\n}\ntb_poller_ref_t xm_engine_poller(xm_engine_ref_t self) {\n    xm_engine_t *engine = (xm_engine_t *)self;\n    tb_assert_and_check_return_val(engine, tb_null);\n\n    if (!engine->poller) {\n        // init poller\n        engine->poller_state.lua = engine->lua;\n        tb_poller_ref_t poller = tb_poller_init(&engine->poller_state);\n        tb_assert_and_check_return_val(poller, tb_null);\n\n        // attach poller to the current thread\n        tb_poller_attach(poller);\n        engine->poller = poller;\n    }\n    return engine->poller;\n}\ntb_int_t xm_engine_run(tb_char_t const *name,\n                       tb_int_t argc,\n                       tb_char_t **argv,\n                       tb_char_t **taskargv,\n                       xm_engine_lni_initalizer_cb_t lni_initalizer) {\n    tb_int_t ok = -1;\n    if (xm_init()) {\n        xm_engine_ref_t engine = xm_engine_init(name, lni_initalizer);\n        if (engine) {\n            ok = xm_engine_main(engine, argc, argv, taskargv);\n            xm_engine_exit(engine);\n        }\n        xm_exit();\n    }\n    return ok;\n}\nxm_engine_ref_t xm_engine_get(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, tb_null);\n\n    lua_getglobal(lua, \"__global_engine\");\n    return (xm_engine_ref_t)lua_touserdata(lua, -1);\n}\n"
  },
  {
    "path": "core/src/xmake/engine.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        engine.h\n *\n */\n#ifndef XM_ENGINE_H\n#define XM_ENGINE_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_enter__\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n/// the xmake engine type\ntypedef struct {\n    tb_int_t dummy;\n} const *xm_engine_ref_t;\n\n/// the lni initializer callback type\ntypedef tb_void_t (*xm_engine_lni_initalizer_cb_t)(xm_engine_ref_t engine, lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/*! init the engine\n *\n * @param name              the engine name\n * @param lni_initalizer    the lni initializer\n *\n * @return                  the engine\n */\nxm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer);\n\n/*! exit the engine\n *\n * @param engine            the engine\n */\ntb_void_t xm_engine_exit(xm_engine_ref_t engine);\n\n/*! do the main entry of the engine\n *\n * @param engine            the engine\n * @param argc              the argument count of the console\n * @param argv              the argument list of the console\n * @param taskargv          the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 ..\n *\n * @return                  the error code of main()\n */\ntb_int_t xm_engine_main(xm_engine_ref_t engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv);\n\n/*! register lni modules in the engine, @note we need to call it in lni_initalizer()\n *\n * @param engine            the engine\n * @param module            the lni module name\n * @param funcs             the lni module functions\n */\ntb_void_t xm_engine_register(xm_engine_ref_t engine, tb_char_t const *module, luaL_Reg const funcs[]);\n\n/*! add the embed files\n *\n * @param engine            the engine\n * @param data              the embedfiles data\n * @param size              the data size\n */\ntb_void_t xm_engine_add_embedfiles(xm_engine_ref_t engine, tb_byte_t const *data, tb_size_t size);\n\n/* get lua state from engine\n *\n * @param engine            the engine\n *\n * @return                  the lua state\n */\nlua_State *xm_engine_lua(xm_engine_ref_t engine);\n\n/* get poller from engine\n *\n * @param engine            the engine\n *\n * @return                  the poller\n */\ntb_poller_ref_t xm_engine_poller(xm_engine_ref_t engine);\n\n/*! run main entry of the engine singleton\n *\n * @param name              the engine name\n * @param argc              the argument count of the console\n * @param argv              the argument list of the console\n * @param taskargv          the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 ..\n * @param lni_initalizer    the lni initializer\n *\n * @return                  the error code of main()\n */\ntb_int_t xm_engine_run(tb_char_t const              *name,\n                       tb_int_t                      argc,\n                       tb_char_t                   **argv,\n                       tb_char_t                   **taskargv,\n                       xm_engine_lni_initalizer_cb_t lni_initalizer);\n\n/*! get engine from the given lua state\n *\n * @param lua               the lua state\n *\n * @return                  the engine\n */\nxm_engine_ref_t xm_engine_get(lua_State *lua);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_leave__\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/engine_pool.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        engine_pool.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"engine_pool\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmake.h\"\n#include \"engine.h\"\n#include \"engine_pool.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// the max engine pool count\n#define XM_ENGINE_POOL_MAXN (128)\n\n// the singleton type of engine pool\n#define XM_ENGINE_POOL (TB_SINGLETON_TYPE_USER + 4)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_handle_t xm_engine_pool_instance_init(tb_cpointer_t *ppriv) {\n    xm_engine_pool_ref_t engine_pool = xm_engine_pool_init();\n    tb_assert_and_check_return_val(engine_pool, tb_null);\n\n    return (tb_handle_t)engine_pool;\n}\n\nstatic tb_void_t xm_engine_pool_instance_exit(tb_handle_t engine_pool, tb_cpointer_t priv) {\n    if (engine_pool) {\n        xm_engine_pool_exit((xm_engine_pool_ref_t)engine_pool);\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nxm_engine_pool_ref_t xm_engine_pool() {\n    return (xm_engine_pool_ref_t)tb_singleton_instance(\n        XM_ENGINE_POOL, xm_engine_pool_instance_init, xm_engine_pool_instance_exit, tb_null, tb_null);\n}\n\nxm_engine_pool_ref_t xm_engine_pool_init() {\n    return tb_single_list_init(0, tb_element_ptr(tb_null, tb_null));\n}\n\ntb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool) {\n    if (engine_pool) {\n        tb_for_all(xm_engine_ref_t, engine, engine_pool) {\n            if (engine) {\n                xm_engine_exit(engine);\n            }\n        }\n        tb_single_list_exit(engine_pool);\n    }\n}\n\nxm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool) {\n    xm_engine_ref_t engine = tb_null;\n    if (tb_single_list_size(engine_pool) > 0) {\n        engine = (xm_engine_ref_t)tb_single_list_head(engine_pool);\n        tb_single_list_remove_head(engine_pool);\n    }\n    return engine;\n}\n\ntb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine) {\n    if (tb_single_list_size(engine_pool) < XM_ENGINE_POOL_MAXN) {\n        tb_single_list_insert_tail(engine_pool, engine);\n        return tb_true;\n    }\n    return tb_false;\n}\n"
  },
  {
    "path": "core/src/xmake/engine_pool.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        engine_pool.h\n *\n */\n#ifndef XM_ENGINE_POOL_H\n#define XM_ENGINE_POOL_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_enter__\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n/// the xmake engine pool type\ntypedef tb_single_list_ref_t xm_engine_pool_ref_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// get the engine pool singleton\nxm_engine_pool_ref_t xm_engine_pool(tb_void_t);\n\n/*! init the engine_pool\n *\n * @return                  the engine pool\n */\nxm_engine_pool_ref_t xm_engine_pool_init(tb_void_t);\n\n/*! exit the engine_pool\n *\n * @param engine_pool       the engine_pool\n */\ntb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool);\n\n/*! alloc a engine from the engine_pool\n *\n * @param engine_pool       the engine_pool\n *\n * @return                  the engine\n */\nxm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool);\n\n/*! free a engine to the engine_pool\n *\n * @param engine_pool       the engine_pool\n * @param engine            the engine\n *\n * @return                  tb_true or tb_false\n */\ntb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_leave__\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/fwatcher/add.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        add.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fwatcher.add\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// fwatcher.add(watchdir, recursion)\ntb_int_t xm_fwatcher_add(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the fwatcher\n    tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(fwatcher, 0);\n\n    // get watchdir\n    tb_char_t const *watchdir = luaL_checkstring(lua, 2);\n    tb_check_return_val(watchdir, 0);\n\n    // get recursion\n    tb_bool_t recursion = lua_toboolean(lua, 3);\n\n    // add watchdir\n    tb_bool_t ok = tb_fwatcher_add(fwatcher, watchdir, recursion);\n\n    // save result\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/fwatcher/close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fwatcher.close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// fwatcher.close(p)\ntb_int_t xm_fwatcher_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the fwatcher\n    tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(fwatcher, 0);\n\n    // exit fwatcher\n    tb_fwatcher_exit(fwatcher);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/fwatcher/open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fwatcher.open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_fwatcher_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // init fwatcher\n    tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)tb_fwatcher_init();\n    if (fwatcher) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)fwatcher);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/fwatcher/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_FWATCHER_PREFIX_H\n#define XM_FWATCHER_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/fwatcher/remove.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        remove.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fwatcher.remove\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// fwatcher.remove(watchdir)\ntb_int_t xm_fwatcher_remove(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the fwatcher\n    tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(fwatcher, 0);\n\n    // get watchdir\n    tb_char_t const *watchdir = luaL_checkstring(lua, 2);\n    tb_check_return_val(watchdir, 0);\n\n    // remove watchdir\n    tb_bool_t ok = tb_fwatcher_remove(fwatcher, watchdir);\n\n    // save result\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/fwatcher/wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fwatcher.wait\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// fwatcher.wait(p)\ntb_int_t xm_fwatcher_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the fwatcher\n    tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(fwatcher, 0);\n\n    // get the timeout\n    tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2);\n\n    // wait fwatcher event\n    tb_fwatcher_event_t event;\n    tb_long_t ok = tb_fwatcher_wait(fwatcher, &event, timeout);\n\n    // save result\n    lua_pushinteger(lua, ok);\n    if (ok > 0) {\n        lua_newtable(lua);\n        lua_pushstring(lua, \"path\");\n        lua_pushstring(lua, event.filepath);\n        lua_settable(lua, -3);\n\n        lua_pushstring(lua, \"type\");\n        lua_pushinteger(lua, event.event);\n        lua_settable(lua, -3);\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/md5.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        md5.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"md5\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_md5(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is bytes? get data and size\n    if (xm_lua_isinteger(lua, 1) && xm_lua_isinteger(lua, 2)) {\n        tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n        tb_size_t size = (tb_size_t)lua_tointeger(lua, 2);\n        if (!data || !size) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n            return 2;\n        }\n        tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n        // compute md5\n        tb_byte_t buffer[16];\n        tb_md5_make(data, size, buffer, sizeof(buffer));\n\n        // make md5 string\n        tb_char_t s[256];\n        tb_size_t n = xm_hash_make_cstr(s, buffer, 16);\n\n        // save result\n        lua_pushlstring(lua, s, n);\n        return 1;\n    }\n\n    // get the filename\n    tb_char_t const *filename = luaL_checkstring(lua, 1);\n    tb_check_return_val(filename, 0);\n\n    // load data from file\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);\n    if (stream) {\n        // open stream\n        if (tb_stream_open(stream)) {\n            // init md5\n            tb_md5_t md5;\n            tb_md5_init(&md5, 0);\n\n            // read data and update md5\n            tb_byte_t data[TB_STREAM_BLOCK_MAXN];\n            while (!tb_stream_beof(stream)) {\n                // read data\n                tb_long_t real = tb_stream_read(stream, data, sizeof(data));\n\n                if (real > 0) {\n                    tb_md5_spak(&md5, data, real);\n                // no data? continue it\n                } else if (!real) {\n                    // wait\n                    real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));\n                    tb_check_break(real > 0);\n\n                    // has read?\n                    tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);\n                }\n                // failed or end?\n                else {\n                    break;\n                }\n            }\n\n            // exit md5\n            tb_byte_t buffer[16];\n            tb_md5_exit(&md5, buffer, sizeof(buffer));\n\n            // make md5 string\n            tb_char_t s[256];\n            tb_size_t n = xm_hash_make_cstr(s, buffer, 16);\n\n            // save result\n            lua_pushlstring(lua, s, n);\n            ok = tb_true;\n        }\n\n        // exit stream\n        tb_stream_exit(stream);\n    }\n    if (!ok) {\n        lua_pushnil(lua);\n        // check if file exists to provide more specific error message\n        if (!tb_file_info(filename, tb_null)) {\n            lua_pushfstring(lua, \"file not found: %s\", filename);\n        } else {\n            lua_pushfstring(lua, \"failed to read file: %s\", filename);\n        }\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_HASH_PREFIX_H\n#define XM_HASH_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * helper implementation\n */\n\nstatic __tb_inline__ tb_uint64_t xm_hash_xorshift64(tb_uint64_t x) {\n    x ^= x << 13;\n    x ^= x >> 7;\n    x ^= x << 17;\n    return x;\n}\n\n// http://xorshift.di.unimi.it/xorshift128plus.c\nstatic __tb_inline__ tb_uint64_t xm_hash_xorshift128(tb_uint64_t *s) {\n    tb_uint64_t s1 = s[0];\n    tb_uint64_t const s0 = s[1];\n    s[0] = s0;\n    s1 ^= s1 << 23;\n    s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5);\n    return s[1] + s0;\n}\n\nstatic __tb_inline__ tb_size_t xm_hash_make_cstr(tb_char_t hash[256], tb_byte_t const *data, tb_size_t size) {\n    static tb_char_t const *digits_table = \"0123456789abcdef\";\n    tb_size_t i = 0;\n    tb_byte_t value;\n    tb_char_t *s = hash;\n    for (i = 0; i < size; ++i) {\n        value = data[i];\n        s[0] = digits_table[(value >> 4) & 15];\n        s[1] = digits_table[value & 15];\n        s += 2;\n    }\n    *s = '\\0';\n    return s - hash;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/hash/rand128.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rand128.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rand128\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_rand128(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    static union {\n        tb_byte_t b[16];\n        tb_uint64_t word[2];\n    } s_seed = { 0 };\n    if (!s_seed.word[0] && !s_seed.word[1]) {\n        s_seed.word[0] = (tb_uint64_t)tb_uclock();\n        s_seed.word[1] = (tb_uint64_t)tb_uclock();\n    }\n    s_seed.word[0] = xm_hash_xorshift128(s_seed.word);\n    s_seed.word[1] = xm_hash_xorshift128(s_seed.word);\n\n    tb_char_t s[256];\n    tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 16);\n\n    lua_pushlstring(lua, s, n);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/rand32.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rand32.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rand32\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_rand32(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    static tb_uint64_t s_seed = 0;\n    if (!s_seed) {\n        s_seed = (tb_uint64_t)tb_uclock();\n    }\n    s_seed = xm_hash_xorshift64(s_seed);\n\n    tb_char_t s[256];\n    tb_uint32_t word = (s_seed >> 32) ^ (s_seed & 0xffffffff);\n    tb_size_t n = xm_hash_make_cstr(s, (tb_byte_t const *)&word, 4);\n\n    lua_pushlstring(lua, s, n);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/rand64.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rand64.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rand64\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_rand64(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    static union {\n        tb_byte_t b[8];\n        tb_uint64_t word;\n    } s_seed = { 0 };\n    if (!s_seed.word) {\n        s_seed.word = (tb_uint64_t)tb_uclock();\n    }\n    s_seed.word = xm_hash_xorshift64(s_seed.word);\n\n    tb_char_t s[256];\n    tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 8);\n\n    lua_pushlstring(lua, s, n);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/sha.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sha.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"sha\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_sha(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get mode\n    tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1);\n\n    // is bytes? get data and size\n    if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) {\n        tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n        tb_size_t size = (tb_size_t)lua_tointeger(lua, 3);\n        if (!data || !size) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n            return 2;\n        }\n        tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n        // compute sha\n        tb_sha_t sha;\n        tb_byte_t buffer[32];\n        tb_sha_init(&sha, mode);\n        tb_sha_spak(&sha, data, size);\n        tb_sha_exit(&sha, buffer, sizeof(buffer));\n\n        // make sha string\n        tb_char_t s[256];\n        tb_size_t n = sha.digest_len << 2;\n        tb_size_t len = xm_hash_make_cstr(s, buffer, n);\n\n        // save result\n        lua_pushlstring(lua, s, len);\n        return 1;\n    }\n\n    // get the filename\n    tb_char_t const *filename = luaL_checkstring(lua, 2);\n    tb_check_return_val(filename, 0);\n\n    // load data from file\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);\n    if (stream) {\n        // open stream\n        if (tb_stream_open(stream)) {\n            // init sha\n            tb_sha_t sha;\n            tb_sha_init(&sha, mode);\n\n            // read data and update sha\n            tb_byte_t data[TB_STREAM_BLOCK_MAXN];\n            while (!tb_stream_beof(stream)) {\n                // read data\n                tb_long_t real = tb_stream_read(stream, data, sizeof(data));\n\n                if (real > 0) {\n                    tb_sha_spak(&sha, data, real);\n                // no data? continue it\n                } else if (!real) {\n                    // wait\n                    real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));\n                    tb_check_break(real > 0);\n\n                    // has read?\n                    tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);\n                }\n                // failed or end?\n                else {\n                    break;\n                }\n            }\n\n            // exit sha\n            tb_byte_t buffer[32];\n            tb_sha_exit(&sha, buffer, sizeof(buffer));\n\n            // make sha string\n            tb_char_t s[256];\n            tb_size_t n   = sha.digest_len << 2;\n            tb_size_t len = xm_hash_make_cstr(s, buffer, n);\n\n            // save result\n            lua_pushlstring(lua, s, len);\n            ok = tb_true;\n        }\n\n        // exit stream\n        tb_stream_exit(stream);\n    }\n    if (!ok) {\n        lua_pushnil(lua);\n        // check if file exists to provide more specific error message\n        if (!tb_file_info(filename, tb_null)) {\n            lua_pushfstring(lua, \"file not found: %s\", filename);\n        } else {\n            lua_pushfstring(lua, \"failed to read file: %s\", filename);\n        }\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/uuid4.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        uuid4.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"uuid4\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_uuid4(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the name\n    tb_char_t const *name = luaL_optstring(lua, 1, tb_null);\n\n    // make uuid, use version 4\n    tb_char_t uuid[37];\n    lua_pushstring(lua, tb_uuid4_make_cstr(uuid, name));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/hash/xxhash.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        xxhash.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"xxhash\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#define XXH_NAMESPACE XM_\n#define XXH_STATIC_LINKING_ONLY\n#define XXH_IMPLEMENTATION\n#include \"xxhash/xxhash.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_hash_xxhash(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get mode\n    tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1);\n    if (mode != 32 && mode != 64 && mode != 128) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid mode(%d)!\", (tb_int_t)mode);\n        return 2;\n    }\n\n    // is bytes? get data and size\n    if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) {\n        tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n        tb_size_t size = (tb_size_t)lua_tointeger(lua, 3);\n        if (!data || !size) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n            return 2;\n        }\n        tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n        // compuate hash\n        tb_byte_t const *buffer = tb_null;\n        tb_uint32_t value32;\n        XXH64_hash_t value64;\n        XXH128_hash_t value128;\n        if (mode == 128) {\n            value128 = XM_XXH3_128bits(data, size);\n            buffer = (tb_byte_t const *)&value128;\n        } else if (mode == 64) {\n            value64 = XM_XXH3_64bits(data, size);\n            buffer = (tb_byte_t const *)&value64;\n        } else if (mode == 32) {\n            value64 = XM_XXH3_64bits(data, size);\n            value32 = (value64 >> 32) ^ (value64 & 0xffffffff);\n            buffer = (tb_byte_t const *)&value32;\n        }\n        if (!buffer) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"empty buffer!\");\n            return 2;\n        }\n\n        // make xxhash string\n        tb_char_t s[256];\n        tb_size_t n = mode >> 3;\n        tb_size_t len = xm_hash_make_cstr(s, buffer, n);\n\n        // save result\n        lua_pushlstring(lua, s, len);\n        return 1;\n    }\n\n    // get the filename\n    tb_char_t const *filename = luaL_checkstring(lua, 2);\n    tb_check_return_val(filename, 0);\n\n    // load data from file\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);\n    if (stream) {\n        // open stream\n        XXH3_state_t *state = XM_XXH3_createState();\n        if (tb_stream_open(stream) && state) {\n            // reset xxhash\n            if (mode == 32 || mode == 64) {\n                XM_XXH3_64bits_reset(state);\n            } else {\n                XM_XXH3_128bits_reset(state);\n            }\n\n            // read data and update xxhash\n            tb_byte_t data[TB_STREAM_BLOCK_MAXN];\n            while (!tb_stream_beof(stream)) {\n                // read data\n                tb_long_t real = tb_stream_read(stream, data, sizeof(data));\n\n                if (real > 0) {\n                    if (mode == 32 || mode == 64) {\n                        XM_XXH3_64bits_update(state, data, real);\n                    } else {\n                        XM_XXH3_128bits_update(state, data, real);\n                    }\n                }\n                // no data? continue it\n                else if (!real) {\n                    // wait\n                    real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));\n                    tb_check_break(real > 0);\n\n                    // has read?\n                    tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);\n                }\n                // failed or end?\n                else {\n                    break;\n                }\n            }\n\n            // compuate hash\n            tb_byte_t const *buffer;\n            tb_uint32_t value32;\n            XXH64_hash_t value64;\n            XXH128_hash_t value128;\n            if (mode == 128) {\n                value128 = XM_XXH3_128bits_digest(state);\n                buffer = (tb_byte_t const *)&value128;\n            } else if (mode == 64) {\n                value64 = XM_XXH3_64bits_digest(state);\n                buffer = (tb_byte_t const *)&value64;\n            } else if (mode == 32) {\n                value64 = XM_XXH3_64bits_digest(state);\n                value32 = (value64 >> 32) ^ (value64 & 0xffffffff);\n                buffer = (tb_byte_t const *)&value32;\n            }\n\n            // make xxhash string\n            tb_char_t s[256];\n            tb_size_t n = mode >> 3;\n            tb_size_t len = xm_hash_make_cstr(s, buffer, n);\n\n            // save result\n            lua_pushlstring(lua, s, len);\n            ok = tb_true;\n        }\n\n        // exit stream\n        tb_stream_exit(stream);\n\n        // exit xxhash\n        if (state) {\n            XM_XXH3_freeState(state);\n        }\n    }\n    if (!ok) {\n        lua_pushnil(lua);\n        // check if file exists to provide more specific error message\n        if (!tb_file_info(filename, tb_null)) {\n            lua_pushfstring(lua, \"file not found: %s\", filename);\n        } else {\n            lua_pushfstring(lua, \"failed to read file: %s\", filename);\n        }\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.file_close(file)\ntb_int_t xm_io_file_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1))\n        xm_io_return_error(lua, \"close(invalid file)!\");\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // close file\n    if (xm_io_file_is_file(file)) {\n        tb_assert(file->u.file_ref);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n        // write cached data first\n        tb_byte_t const *odata = tb_buffer_data(&file->wcache);\n        tb_size_t osize = tb_buffer_size(&file->wcache);\n        if (odata && osize) {\n            if (!tb_stream_bwrit(file->u.file_ref, odata, osize))\n                return tb_false;\n            tb_buffer_clear(&file->wcache);\n        }\n#endif\n\n        // flush filter stream cache, TODO we should fix it in tbox/stream\n        if ((file->mode & TB_FILE_MODE_RW) == TB_FILE_MODE_RW && file->fstream) {\n            if (!tb_stream_sync(file->u.file_ref, tb_false))\n                return tb_false;\n        }\n\n        // close file\n        tb_stream_clos(file->u.file_ref);\n        file->u.file_ref = tb_null;\n\n        // exit fstream\n        if (file->fstream) {\n            tb_stream_exit(file->fstream);\n        }\n        file->fstream = tb_null;\n\n        // exit stream\n        if (file->stream) {\n            tb_stream_exit(file->stream);\n        }\n        file->stream = tb_null;\n\n        // exit the line cache buffer\n        tb_buffer_exit(&file->rcache);\n        tb_buffer_exit(&file->wcache);\n\n        // gc will free it if no any refs for lua_newuserdata()\n        // ...\n\n        lua_pushboolean(lua, tb_true);\n        return 1;\n    } else // for stdfile (gc/close)\n    {\n        // exit the line cache buffer\n        tb_buffer_exit(&file->rcache);\n        tb_buffer_exit(&file->wcache);\n\n        // gc will free it if no any refs for lua_newuserdata()\n        // ...\n\n        lua_pushboolean(lua, tb_true);\n        return 1;\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_convert.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        file_convert.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_convert\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../utils/charset.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* convert file\n *\n * @param srcpath   the srcpath\n * @param dstpath   the dstpath\n * @param ftype     the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32\n * @param ttype     the to-charset type\n *\n * @code\n *      io.convert(srcpath, dstpath, \"gbk\", \"utf8\")\n *      io.convert(srcpath, dstpath, \"utf8\", \"gb2312\")\n * @endcode\n */\ntb_int_t xm_io_file_convert(lua_State *lua) {\n    // check\n    tb_assert_and_check_return_val(lua, 0);\n\n#ifdef TB_CONFIG_MODULE_HAVE_CHARSET\n    // get arguments\n    tb_char_t const *srcpath = luaL_checkstring(lua, 1);\n    tb_char_t const *dstpath = luaL_checkstring(lua, 2);\n    tb_char_t const *fname   = luaL_checkstring(lua, 3);\n    tb_char_t const *tname   = luaL_checkstring(lua, 4);\n    tb_check_return_val(srcpath && dstpath && fname && tname, 0);\n\n    // get charset type\n    tb_size_t            ftype = TB_CHARSET_TYPE_UTF8;\n    tb_size_t            ttype = TB_CHARSET_TYPE_UTF8;\n    xm_charset_entry_ref_t fentry = xm_charset_find_by_name(fname);\n    if (fentry) ftype = fentry->type;\n    else {\n        lua_pushfstring(lua, \"invalid charset: %s\", fname);\n        lua_error(lua);\n    }\n    xm_charset_entry_ref_t tentry = xm_charset_find_by_name(tname);\n    if (tentry) ttype = tentry->type;\n    else {\n        lua_pushfstring(lua, \"invalid charset: %s\", tname);\n        lua_error(lua);\n    }\n\n    // done\n    tb_bool_t       ok      = tb_false;\n    tb_stream_ref_t istream = tb_null;\n    tb_stream_ref_t ostream = tb_null;\n    tb_stream_ref_t fstream = tb_null;\n    do {\n        // init istream\n        istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);\n        tb_assert_and_check_break(istream);\n\n        // open istream\n        if (!tb_stream_open(istream)) break;\n\n        // skip bom\n        tb_size_t skip = 0;\n        tb_byte_t* bom_data = tb_null;\n        tb_long_t bom_size = tb_stream_peek(istream, &bom_data, 3);\n        if (bom_size >= 3 && ftype == TB_CHARSET_TYPE_UTF8 && bom_data[0] == 0xef && bom_data[1] == 0xbb && bom_data[2] == 0xbf) {\n            skip = 3;\n        } else if (bom_size >= 2 && (ftype & TB_CHARSET_TYPE_UTF16)) {\n             if (bom_data[0] == 0xff && bom_data[1] == 0xfe) skip = 2;\n             else if (bom_data[0] == 0xfe && bom_data[1] == 0xff) skip = 2;\n        }\n        if (skip > 0 && !tb_stream_skip(istream, skip)) break;\n\n        // init ostream\n        ostream = tb_stream_init_from_file(dstpath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n        tb_assert_and_check_break(ostream);\n\n        // open ostream\n        if (!tb_stream_open(ostream)) break;\n\n        // write bom\n        if (!tb_strcmp(tname, \"utf8bom\")) {\n            static tb_byte_t const k_bom[] = {0xef, 0xbb, 0xbf};\n            if (!tb_stream_bwrit(ostream, k_bom, 3)) break;\n        } else if (!tb_strcmp(tname, \"utf16lebom\")) {\n            static tb_byte_t const k_bom[] = {0xff, 0xfe};\n            if (!tb_stream_bwrit(ostream, k_bom, 2)) break;\n        } else if (!tb_strcmp(tname, \"utf16bom\")) {\n#ifndef TB_WORDS_BIGENDIAN\n            static tb_byte_t const k_bom[] = {0xff, 0xfe};\n#else\n            static tb_byte_t const k_bom[] = {0xfe, 0xff};\n#endif\n            if (!tb_stream_bwrit(ostream, k_bom, 2)) break;\n        }\n\n        // init fstream\n        fstream = tb_stream_init_filter_from_charset(istream, ftype, ttype);\n        tb_assert_and_check_break(fstream);\n\n        // open fstream\n        if (!tb_stream_open(fstream)) break;\n\n        // transfer\n        tb_byte_t data[TB_STREAM_BLOCK_MAXN];\n        while (1) {\n            tb_long_t real = tb_stream_read(fstream, data, sizeof(data));\n            if (real > 0) {\n                if (!tb_stream_bwrit(ostream, data, real)) break;\n            } else if (real == 0) {\n                tb_long_t wait = tb_stream_wait(fstream, TB_STREAM_WAIT_READ, tb_stream_timeout(fstream));\n                if (wait <= 0) break;\n            } else break;\n        }\n\n        // ok\n        ok = tb_true;\n\n    } while (0);\n\n    // exit fstream\n    if (fstream) tb_stream_exit(fstream);\n    fstream = tb_null;\n\n    // exit istream\n    if (istream) tb_stream_exit(istream);\n    istream = tb_null;\n\n    // exit ostream\n    if (ostream) tb_stream_exit(ostream);\n    ostream = tb_null;\n\n    // ok?\n    lua_pushboolean(lua, ok);\n    return 1;\n#else\n    lua_pushboolean(lua, tb_false);\n    return 1;\n#endif\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_flush.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_flush.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_flush\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_bool_t xm_io_std_flush_impl(xm_io_file_t *file) {\n    tb_assert_and_check_return_val(xm_io_file_is_std(file), tb_false);\n    return (file->u.std_ref != tb_stdfile_input()) ? tb_stdfile_flush(file->u.std_ref) : tb_false;\n}\n\nstatic tb_bool_t xm_io_file_flush_impl(xm_io_file_t *file) {\n    tb_assert_and_check_return_val(xm_io_file_is_file(file), tb_false);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n    // write cached data first\n    tb_byte_t const *odata = tb_buffer_data(&file->wcache);\n    tb_size_t osize = tb_buffer_size(&file->wcache);\n    if (odata && osize) {\n        if (!tb_stream_bwrit(file->u.file_ref, odata, osize))\n            return tb_false;\n        tb_buffer_clear(&file->wcache);\n    }\n#endif\n    return tb_stream_sync(file->u.file_ref, tb_false);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.file_flush(file)\ntb_int_t xm_io_file_flush(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"flush(invalid file)!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // flush file\n    tb_bool_t ok = xm_io_file_is_file(file) ? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file);\n    if (ok) {\n        lua_pushboolean(lua, tb_true);\n        return 1;\n    } else {\n        xm_io_return_error(lua, \"failed to flush file\");\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_isatty.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu\n * @file        file_isatty.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_isatty\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.file_isatty(file)\ntb_int_t xm_io_file_isatty(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"isatty(invalid file)!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // is tty?\n    lua_pushboolean(lua, xm_io_file_is_tty(file));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// num of bytes read to guess encoding\n#define CHECK_SIZE (1024)\n\n// is utf-8 tail character\n#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_size_t xm_io_file_detect_charset(tb_byte_t const **data_ptr, tb_long_t size) {\n    tb_assert(data_ptr && *data_ptr);\n\n    tb_byte_t const *data = *data_ptr;\n    tb_size_t charset = XM_IO_FILE_ENCODING_BINARY;\n    do {\n        // is luajit bitcode? open as binary\n        if (size >= 3 && data[0] == 27 && data[1] == 'L' && data[2] == 'J') {\n            break;\n        }\n\n        // utf-8 with bom\n        if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) {\n            charset = TB_CHARSET_TYPE_UTF8;\n            data += 3; // skip bom\n            break;\n        }\n        if (size >= 2) {\n            // utf16be\n            if (data[0] == 254 && data[1] == 255) {\n                charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;\n                data += 2; // skip bom\n                break;\n            }\n            // utf16le\n            else if (data[0] == 255 && data[1] == 254) {\n                charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;\n                data += 2; // skip bom\n                break;\n            }\n        }\n\n        tb_sint16_t utf16be_conf = 0;\n        tb_sint16_t utf16le_conf = 0;\n        tb_sint16_t utf8_conf = 0;\n        tb_sint16_t ascii_conf = 0;\n        tb_sint16_t zero_count = 0;\n        for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) {\n            if (data[i] == 0) {\n                zero_count++;\n            }\n\n            if (data[i] < 0x80) {\n                ascii_conf++;\n            } else {\n                ascii_conf = TB_MINS16;\n            }\n\n            if (i % 2 == 0) {\n                if (data[i] == 0) {\n                    utf16be_conf++;\n                }\n                if (data[i + 1] == 0) {\n                    utf16le_conf++;\n                }\n            }\n\n            if (IS_UTF8_TAIL(data[i])) {\n                // continue\n            } else if (data[i] < 0x80) {\n                utf8_conf++;\n            } else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) {\n                utf8_conf++;\n            } else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) {\n                utf8_conf++;\n            } else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) &&\n                       IS_UTF8_TAIL(data[i + 3])) {\n                utf8_conf++;\n            } else {\n                utf8_conf = TB_MINS16;\n            }\n        }\n\n        if (ascii_conf > 0 && zero_count <= 1) {\n            charset = TB_CHARSET_TYPE_UTF8;\n            break;\n        }\n        if (utf8_conf > 0 && zero_count <= 1) {\n            charset = TB_CHARSET_TYPE_UTF8;\n            break;\n        }\n        if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) {\n            charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;\n            break;\n        }\n        if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) {\n            charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;\n            break;\n        }\n        if (utf8_conf > 0) {\n            charset = TB_CHARSET_TYPE_UTF8;\n            break;\n        }\n\n#ifdef TB_CONFIG_OS_WINDOWS\n        charset = TB_CHARSET_TYPE_ANSI;\n#endif\n\n    } while (0);\n\n    *data_ptr = data;\n    return charset;\n}\nstatic tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t *pbomoff) {\n    tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY);\n\n    // detect encoding\n    tb_byte_t *data = tb_null;\n    tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY;\n    tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE);\n    if (size > 0) {\n        tb_byte_t const *p = data;\n        encoding = xm_io_file_detect_charset(&p, size);\n        *pbomoff = p - data;\n    }\n    return encoding;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.file_open(path, modestr)\ntb_int_t xm_io_file_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get file path and mode\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_char_t const *modestr = luaL_optstring(lua, 2, \"r\");\n    tb_assert_and_check_return_val(path && modestr, 0);\n\n    // get file mode value\n    tb_size_t mode;\n    switch (modestr[0]) {\n    case 'w':\n        mode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC;\n        break;\n    case 'a':\n        mode = TB_FILE_MODE_RW | TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT;\n        break;\n    case 'r':\n    default:\n        mode = TB_FILE_MODE_RO;\n        break;\n    }\n\n    // get file encoding\n    tb_long_t bomoff = 0;\n    tb_stream_ref_t stream = tb_null;\n    tb_bool_t update = !!tb_strchr(modestr, '+');\n    tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN;\n    if (modestr[1] == 'b' || (update && modestr[2] == 'b')) {\n        encoding = XM_IO_FILE_ENCODING_BINARY;\n    } else if (tb_strstr(modestr, \"utf8\") || tb_strstr(modestr, \"utf-8\")) {\n        encoding = TB_CHARSET_TYPE_UTF8;\n    } else if (tb_strstr(modestr, \"utf16le\") || tb_strstr(modestr, \"utf-16le\")) {\n        encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;\n    } else if (tb_strstr(modestr, \"utf16be\") || tb_strstr(modestr, \"utf-16be\")) {\n        encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;\n    } else if (tb_strstr(modestr, \"utf16\") || tb_strstr(modestr, \"utf-16\")) {\n        encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE;\n    } else if (tb_strstr(modestr, \"ansi\")) {\n        encoding = TB_CHARSET_TYPE_ANSI;\n    } else if (tb_strstr(modestr, \"gbk\")) {\n        encoding = TB_CHARSET_TYPE_GBK;\n    } else if (tb_strstr(modestr, \"gb2312\")) {\n        encoding = TB_CHARSET_TYPE_GB2312;\n    } else if (tb_strstr(modestr, \"iso8859\")) {\n        encoding = TB_CHARSET_TYPE_ISO8859;\n    } else if (modestr[0] == 'w' || modestr[0] == 'a') { // set to utf-8 if not specified for the writing mode\n        encoding = TB_CHARSET_TYPE_UTF8;\n    } else if (modestr[0] == 'r') { // detect encoding if not specified for the reading mode\n        stream = tb_stream_init_from_file(path, mode);\n        if (stream && tb_stream_open(stream)) {\n            encoding = xm_io_file_detect_encoding(stream, &bomoff);\n        } else {\n            if (stream) {\n                tb_stream_exit(stream);\n            }\n            xm_io_return_error(lua, \"file not found!\");\n        }\n    } else {\n        xm_io_return_error(lua, \"invalid open mode!\");\n    }\n    tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0);\n\n    // write data with utf bom? e.g. utf8bom, utf16lebom, utf16bom\n    tb_bool_t utfbom = tb_false;\n    if (tb_strstr(modestr, \"bom\")) {\n        utfbom = tb_true;\n    }\n\n    // open file\n    tb_bool_t open_ok = tb_false;\n    tb_stream_ref_t file_ref = tb_null;\n    tb_stream_ref_t fstream = tb_null;\n    do {\n        // init stream from file\n        stream = stream ? stream : tb_stream_init_from_file(path, mode);\n        tb_assert_and_check_break(stream);\n\n        // is transcode?\n        tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY;\n        if (is_transcode) {\n            if (modestr[0] == 'r') {\n                fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8);\n            } else {\n                fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding);\n            }\n            tb_assert_and_check_break(fstream);\n\n            // use fstream as file\n            file_ref = fstream;\n        } else {\n            file_ref = stream;\n        }\n\n        // open file stream\n        if (!tb_stream_open(file_ref)) {\n            break;\n        }\n\n        // skip bom characters if exists\n        if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) {\n            break;\n        }\n\n        open_ok = tb_true;\n\n    } while (0);\n\n    // open failed?\n    if (!open_ok) {\n        // exit stream\n        if (stream) {\n            tb_stream_exit(stream);\n        }\n        stream = tb_null;\n\n        // exit charset stream filter\n        if (fstream) {\n            tb_stream_exit(fstream);\n        }\n        fstream = tb_null;\n\n        // return errors\n        xm_io_return_error(lua, \"failed to open file!\");\n    }\n\n    // make file\n    xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t));\n    tb_assert_and_check_return_val(file, 0);\n\n    // init file\n    file->u.file_ref = file_ref;\n    file->stream = stream;\n    file->fstream = fstream;\n    file->mode = mode;\n    file->type = XM_IO_FILE_TYPE_FILE;\n    file->encoding = encoding;\n    file->utfbom = utfbom;\n\n    // init the read/write line cache buffer\n    tb_buffer_init(&file->rcache);\n    tb_buffer_init(&file->wcache);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_rawfd.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        file_rawfd.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_rawfd\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// file to fd\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#define xm_io_file2fd(file) (lua_Number)((tb_size_t)(file))\n#else\n#define xm_io_file2fd(file) (lua_Number) tb_file2fd(file)\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* io.file_rawfd(file)\n *\n * @note this interface is very dangerous and is only used in some special/hacking cases.\n *\n * e.g. set VS_UNICODE_OUTPUT=fd to enable vs unicode output, @see https://github.com/xmake-io/xmake/issues/528\n */\ntb_int_t xm_io_file_rawfd(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"get rawfd for invalid file!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // get file raw fd\n    if (xm_io_file_is_file(file)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile)) {\n            lua_pushnumber(lua, xm_io_file2fd(rawfile));\n            return 1;\n        }\n    }\n\n    // get rawfd failed\n    xm_io_return_error(lua, \"get rawfd for invalid file!\");\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_read.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_read.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_read\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef enum __xm_pushline_state_e {\n    PL_EOF,\n    PL_FIN,\n    PL_CONL,\n    PL_FAIL,\n} xm_pushline_state_e;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nstatic tb_bool_t xm_io_file_stream_skip_sequential(tb_stream_ref_t stream, tb_hize_t size) {\n    tb_byte_t discard[TB_STREAM_BLOCK_MAXN];\n    tb_hize_t left = size;\n    while (left) {\n        tb_size_t need = left > (tb_hize_t)sizeof(discard) ? (tb_size_t)sizeof(discard) : (tb_size_t)left;\n        tb_long_t read = tb_stream_read(stream, discard, need);\n        if (read > 0) {\n            left -= read;\n        } else if (!read) {\n            read = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);\n            tb_check_return_val(read > 0, tb_false);\n        } else {\n            return tb_false;\n        }\n    }\n    return tb_true;\n}\n\nstatic tb_bool_t xm_io_file_stream_skip(tb_stream_ref_t stream, tb_hize_t size, tb_bool_t sequential) {\n    if (sequential) {\n        return xm_io_file_stream_skip_sequential(stream, size);\n    }\n    return tb_stream_skip(stream, size);\n}\n\nstatic tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_ref_t line) {\n    tb_assert_and_check_return_val(stream && line, -1);\n\n    // read line and reserve crlf\n    tb_bool_t eof = tb_false;\n    tb_hize_t offset = 0;\n    tb_byte_t *data = tb_null;\n    tb_hong_t size = tb_stream_size(stream);\n    tb_bool_t sequential_consume = (size == 0);\n    while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {\n        tb_long_t real = tb_stream_peek(stream, &data, XM_IO_BLOCK_MAXN);\n        if (real > 0) {\n            tb_char_t const *e = tb_strnchr((tb_char_t const *)data, real, '\\n');\n            if (e) {\n                tb_size_t n = (tb_byte_t const *)e + 1 - data;\n                tb_buffer_memncat(line, data, n);\n                if (!xm_io_file_stream_skip(stream, n, sequential_consume))\n                    return -1;\n                break;\n            } else {\n                tb_buffer_memncat(line, data, real);\n                if (!xm_io_file_stream_skip(stream, (tb_hize_t)real, sequential_consume))\n                    return -1;\n            }\n        } else if (!real) {\n            real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);\n            if (real <= 0) {\n                eof = tb_true;\n                break;\n            }\n        } else {\n            eof = tb_true;\n            break;\n        }\n    }\n\n    tb_size_t linesize = tb_buffer_size(line);\n    if (linesize) {\n        return linesize;\n    } else {\n        return (eof || tb_stream_beof(stream)) ? -1 : 0;\n    }\n}\nstatic tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf,\n                                           xm_io_file_t *file,\n                                           tb_char_t const *continuation,\n                                           tb_bool_t keep_crlf) {\n    tb_assert(buf && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // is binary?\n    tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;\n    if (is_binary) {\n        continuation = \"\";\n        keep_crlf = tb_true;\n    }\n\n    // clear line buffer\n    tb_buffer_clear(&file->rcache);\n\n    // read line data\n    tb_long_t size = xm_io_file_buffer_readline(file->u.file_ref, &file->rcache);\n\n    // translate line data\n    tb_int_t result = PL_FAIL;\n    tb_char_t *data = tb_null;\n    tb_size_t conlen = tb_strlen(continuation);\n    do {\n        // eof?\n        if (size < 0) {\n            result = PL_EOF;\n            break;\n        }\n\n        // patch two '\\0'\n        tb_buffer_memncat(&file->rcache, (tb_byte_t const *)\"\\0\\0\", 2);\n\n        // get line data\n        data = (tb_char_t *)tb_buffer_data(&file->rcache);\n        tb_assert_and_check_break(data);\n\n        // no lf found\n        if (size > 0 && data[size - 1] != '\\n') {\n            result = PL_FIN;\n        } else if (size > 1) {\n            // crlf? => lf\n            if (!is_binary && data[size - 2] == '\\r') {\n                data[size - 2] = '\\n';\n                size--;\n            }\n\n            // has continuation?\n            tb_bool_t has_conline = conlen && size >= conlen + 1 &&\n                                    tb_strncmp(continuation, (tb_char_t const *)(data + size - conlen - 1), conlen) ==\n                                        0;\n\n            // do not keep crlf, strip the last lf\n            if (!keep_crlf && !has_conline) {\n                size--;\n            }\n\n            // strip it if has continuation?\n            if (has_conline) {\n                size -= conlen + 1;\n            }\n            data[size] = '\\0';\n\n            result = has_conline ? PL_CONL : PL_FIN;\n        } else {\n            // a single '\\n'\n            if (!keep_crlf) {\n                size = 0;\n            }\n            result = PL_FIN;\n        }\n\n    } while (0);\n\n    // push line data\n    if (data && size > 0 && (result == PL_FIN || result == PL_CONL)) {\n        tb_buffer_memncat(buf, (tb_byte_t const *)data, size);\n    }\n\n    // return result\n    return result;\n}\nstatic tb_int_t xm_io_file_read_all_directly(lua_State *lua, xm_io_file_t *file) {\n    tb_assert(lua && file && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // init buffer\n    tb_buffer_t buf;\n    if (!tb_buffer_init(&buf)) {\n        xm_io_return_error(lua, \"init buffer failed!\");\n    }\n\n    tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN);\n    if (!data) {\n        tb_buffer_exit(&buf);\n        xm_io_return_error(lua, \"out of memory: failed to resize read cache\");\n    }\n\n    // read all\n    tb_stream_ref_t stream = file->u.file_ref;\n    tb_hize_t offset = 0;\n    tb_hong_t size = tb_stream_size(stream);\n    tb_bool_t sequential_consume = (size == 0);\n    while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {\n        tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN);\n        if (real > 0) {\n            tb_buffer_memncat(&buf, data, real);\n        } else if (!real) {\n            real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);\n            tb_check_break(real > 0);\n        } else {\n            break;\n        }\n    }\n\n    if (tb_buffer_size(&buf)) {\n        lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n    } else {\n        lua_pushliteral(lua, \"\");\n    }\n    tb_buffer_exit(&buf);\n    return 1;\n}\n\nstatic tb_bool_t xm_io_file_read_all_to_buffer(xm_io_file_t *file, tb_buffer_ref_t buf) {\n    tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref && buf);\n\n    tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN);\n    tb_assert_and_check_return_val(data, tb_false);\n\n    tb_stream_ref_t stream = file->u.file_ref;\n    tb_hize_t offset = 0;\n    tb_hong_t size = tb_stream_size(stream);\n    tb_bool_t sequential_consume = (size == 0);\n    while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {\n        tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN);\n        if (real > 0) {\n            tb_buffer_memncat(buf, data, real);\n        } else if (!real) {\n            real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);\n            tb_check_break(real > 0);\n        } else {\n            break;\n        }\n    }\n    return tb_true;\n}\n\nstatic tb_int_t xm_io_file_read_all_with_continuation(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {\n    tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);\n\n    tb_buffer_t buf;\n    if (!tb_buffer_init(&buf)) {\n        xm_io_return_error(lua, \"init buffer failed!\");\n    }\n    while (1) {\n        tb_int_t state = xm_io_file_buffer_pushline(&buf, file, continuation, tb_true);\n        if (state == PL_EOF) {\n            break;\n        }\n        if (state == PL_FAIL) {\n            tb_buffer_exit(&buf);\n            xm_io_return_error(lua, \"failed to readall\");\n        }\n    }\n    if (tb_buffer_size(&buf)) {\n        lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n    } else {\n        lua_pushliteral(lua, \"\");\n    }\n    tb_buffer_exit(&buf);\n    return 1;\n}\n\nstatic tb_int_t xm_io_file_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {\n    tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // is binary? read all directly\n    tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;\n    if (is_binary) {\n        return xm_io_file_read_all_directly(lua, file);\n    }\n\n    if (*continuation != '\\0') {\n        return xm_io_file_read_all_with_continuation(lua, file, continuation);\n    }\n\n    tb_buffer_t raw;\n    tb_buffer_t out;\n    tb_bool_t raw_ok = tb_false;\n    tb_bool_t out_ok = tb_false;\n    tb_int_t result = 0;\n    tb_char_t const *errors = tb_null;\n    do {\n        if (!tb_buffer_init(&raw)) {\n            errors = \"init buffer failed!\";\n            result = 2;\n            break;\n        }\n        raw_ok = tb_true;\n\n        if (!xm_io_file_read_all_to_buffer(file, &raw)) {\n            errors = \"failed to read all\";\n            result = 2;\n            break;\n        }\n\n        tb_size_t rawsize = tb_buffer_size(&raw);\n\n        if (!tb_buffer_init(&out)) {\n            errors = \"init buffer failed!\";\n            result = 2;\n            break;\n        }\n        out_ok = tb_true;\n\n        if (!rawsize) {\n            lua_pushliteral(lua, \"\");\n            result = 1;\n            break;\n        }\n\n        tb_byte_t const *rawdata = (tb_byte_t const *)tb_buffer_data(&raw);\n        tb_byte_t const *p = rawdata;\n        tb_byte_t const *b = rawdata;\n        tb_byte_t const *e = rawdata + rawsize;\n        while (p < e) {\n            if (*p == '\\r' && p + 1 < e && p[1] == '\\n') {\n                if (p > b) {\n                    tb_buffer_memncat(&out, b, p - b);\n                }\n                tb_buffer_memncat(&out, (tb_byte_t const *)\"\\n\", 1);\n                p += 2;\n                b = p;\n            } else {\n                p++;\n            }\n        }\n        if (tb_buffer_size(&out)) {\n            if (e > b) {\n                tb_buffer_memncat(&out, b, e - b);\n            }\n            lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&out), tb_buffer_size(&out));\n            result = 1;\n            break;\n        }\n\n        lua_pushlstring(lua, (tb_char_t const *)rawdata, rawsize);\n        result = 1;\n\n    } while (0);\n\n    if (out_ok) {\n        tb_buffer_exit(&out);\n    }\n    if (raw_ok) {\n        tb_buffer_exit(&raw);\n    }\n    if (result == 2) {\n        lua_pushnil(lua);\n        lua_pushstring(lua, errors);\n    }\n    return result;\n}\n\nstatic tb_int_t xm_io_file_read_line(lua_State *lua,\n                                     xm_io_file_t *file,\n                                     tb_char_t const *continuation,\n                                     tb_bool_t keep_crlf) {\n    tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // init buffer\n    tb_buffer_t buf;\n    if (!tb_buffer_init(&buf)) {\n        xm_io_return_error(lua, \"init buffer failed!\");\n    }\n\n    // read line\n    tb_bool_t has_content = tb_false;\n    while (1) {\n        switch (xm_io_file_buffer_pushline(&buf, file, continuation, keep_crlf)) {\n        case PL_EOF:\n            if (!has_content) {\n                lua_pushnil(lua);\n            } else {\n                lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n            }\n            tb_buffer_exit(&buf);\n            return 1;\n        case PL_FIN:\n            lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n            tb_buffer_exit(&buf);\n            return 1;\n        case PL_CONL:\n            has_content = tb_true;\n            continue;\n        case PL_FAIL:\n        default:\n            tb_buffer_exit(&buf);\n            xm_io_return_error(lua, \"failed to readline\");\n            break;\n        }\n    }\n}\n\nstatic tb_int_t xm_io_file_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) {\n    tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // check continuation\n    if (*continuation != '\\0') {\n        xm_io_return_error(lua, \"continuation is not supported for read number of bytes\");\n    }\n\n    // check encoding\n    if (file->encoding != XM_IO_FILE_ENCODING_BINARY) {\n        xm_io_return_error(lua, \"read number of bytes only allows binary file, reopen with 'rb' and try again\");\n    }\n\n    tb_bool_t ok = tb_false;\n    if (n == 0) {\n        tb_byte_t *data = tb_null;\n        if (tb_stream_need(file->u.file_ref, &data, 1)) {\n            lua_pushliteral(lua, \"\");\n            ok = tb_true;\n        }\n    } else {\n        tb_byte_t *bufptr = tb_buffer_resize(&file->rcache, n + 1);\n        if (bufptr) {\n            if (tb_stream_bread(file->u.file_ref, bufptr, n)) {\n                lua_pushlstring(lua, (tb_char_t const *)bufptr, n);\n                ok = tb_true;\n            }\n        }\n    }\n    if (!ok) {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n\nstatic tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf,\n                                                xm_io_file_t *file,\n                                                tb_char_t const *continuation,\n                                                tb_bool_t keep_crlf) {\n    tb_assert(buf && file && continuation && xm_io_file_is_std(file));\n\n    // get input buffer\n    tb_char_t strbuf[8192];\n    tb_size_t buflen = 0;\n    tb_size_t result = PL_FAIL;\n    if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf) - 1)) {\n        buflen = tb_strlen(strbuf);\n    } else {\n        return PL_EOF;\n    }\n\n    tb_size_t conlen = tb_strlen(continuation);\n    if (buflen > 0 && strbuf[buflen - 1] != '\\n') {\n        // end of file, no lf found\n        result = PL_FIN;\n    } else if (buflen > 1) {\n        // crlf? => lf\n        if (strbuf[buflen - 2] == '\\r') {\n            strbuf[buflen - 2] = '\\n';\n            buflen--;\n        }\n\n        // has continuation?\n        tb_bool_t has_conline = conlen && buflen >= conlen + 1 &&\n                                tb_strncmp(continuation, (strbuf + buflen - conlen - 1), conlen) == 0;\n\n        // do not keep crlf, strip the last lf\n        if (!keep_crlf && !has_conline) {\n            buflen--;\n        }\n\n        // strip it if has continuation?\n        if (has_conline) {\n            buflen -= conlen + 1;\n        }\n        strbuf[buflen] = '\\0';\n\n        result = has_conline ? PL_CONL : PL_FIN;\n    } else {\n        // a single '\\n'\n        if (!keep_crlf) {\n            buflen = 0;\n        }\n        result = PL_FIN;\n    }\n\n    if (result == PL_FIN || result == PL_CONL) {\n        tb_buffer_memncat(buf, (tb_byte_t const *)strbuf, buflen);\n    }\n    return result;\n}\n\nstatic tb_int_t xm_io_file_std_read_line(lua_State *lua,\n                                         xm_io_file_t *file,\n                                         tb_char_t const *continuation,\n                                         tb_bool_t keep_crlf) {\n    tb_assert(lua && file && continuation && xm_io_file_is_std(file));\n\n    // init buffer\n    tb_buffer_t buf;\n    if (!tb_buffer_init(&buf)) {\n        xm_io_return_error(lua, \"init buffer failed!\");\n    }\n\n    // read line\n    tb_bool_t has_content = tb_false;\n    while (1) {\n        switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, keep_crlf)) {\n        case PL_EOF:\n            if (!has_content) {\n                lua_pushnil(lua);\n            } else {\n                lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n            }\n            tb_buffer_exit(&buf);\n            return 1;\n        case PL_FIN:\n            lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n            tb_buffer_exit(&buf);\n            return 1;\n        case PL_CONL:\n            has_content = tb_true;\n            continue;\n        case PL_FAIL:\n        default:\n            tb_buffer_exit(&buf);\n            xm_io_return_error(lua, \"failed to readline\");\n            break;\n        }\n    }\n}\n\nstatic tb_int_t xm_io_file_std_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {\n    tb_assert(lua && file && continuation && xm_io_file_is_std(file));\n\n    // init buffer\n    tb_buffer_t buf;\n    if (!tb_buffer_init(&buf))\n        xm_io_return_error(lua, \"init buffer failed!\");\n\n    // read all\n    tb_bool_t has_content = tb_false;\n    while (1) {\n        switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, tb_true)) {\n        case PL_EOF:\n            if (!has_content)\n                lua_pushliteral(lua, \"\");\n            else\n                lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));\n            tb_buffer_exit(&buf);\n            return 1;\n        case PL_FIN:\n        case PL_CONL:\n            has_content = tb_true;\n            continue;\n        case PL_FAIL:\n        default:\n            tb_buffer_exit(&buf);\n            xm_io_return_error(lua, \"failed to readline\");\n            break;\n        }\n    }\n}\n\nstatic tb_int_t xm_io_file_std_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) {\n    tb_assert(lua && file && continuation && xm_io_file_is_std(file));\n\n    // check continuation\n    if (*continuation != '\\0')\n        xm_io_return_error(lua, \"continuation is not supported for std streams\");\n\n    // io.read(0)\n    if (n == 0) {\n        tb_char_t ch;\n        if (!tb_stdfile_peek(file->u.std_ref, &ch))\n            lua_pushnil(lua);\n        else\n            lua_pushliteral(lua, \"\");\n        return 1;\n    }\n\n    // get line buffer\n    tb_byte_t *buf_ptr = tb_buffer_resize(&file->rcache, (tb_size_t)n);\n    tb_assert(buf_ptr);\n\n    // io.read(n)\n    if (tb_stdfile_read(file->u.std_ref, buf_ptr, (tb_size_t)n))\n        lua_pushlstring(lua, (tb_char_t const *)buf_ptr, (size_t)n);\n    else\n        lua_pushnil(lua);\n    return 1;\n}\n\nstatic tb_int_t xm_io_file_std_read_num(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {\n    tb_assert(lua && file && continuation && xm_io_file_is_std(file));\n\n    // check continuation\n    if (*continuation != '\\0')\n        xm_io_return_error(lua, \"continuation is not supported for std streams\");\n\n    // read number\n    tb_char_t strbuf[512];\n    if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf)))\n        lua_pushnumber(lua, tb_s10tod(strbuf)); // TODO check invalid float number string and push nil\n    else\n        lua_pushnil(lua);\n    return 1;\n}\n\n/* io.file_read(file, [mode, [continuation]])\n * io.file_read(file, \"all\", \"\\\\\")\n * io.file_read(file, \"L\")\n * io.file_read(file, \"l\")\n * io.file_read(file, \"n\")\n * io.file_read(file, 10)\n */\ntb_int_t xm_io_file_read(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1))\n        xm_io_return_error(lua, \"read(invalid file)!\");\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // get arguments\n    tb_char_t const *mode         = luaL_optstring(lua, 2, \"l\");\n    tb_char_t const *continuation = luaL_optstring(lua, 3, \"\");\n    tb_assert_and_check_return_val(mode && continuation, 0);\n\n    tb_long_t count = -1;\n    if (lua_isnumber(lua, 2)) {\n        count = (tb_long_t)lua_tointeger(lua, 2);\n        if (count < 0)\n            xm_io_return_error(lua, \"invalid read size, must be positive nubmber or 0\");\n    } else if (*mode == '*')\n        mode++;\n\n    if (xm_io_file_is_file(file)) {\n        if (count >= 0)\n            return xm_io_file_read_n(lua, file, continuation, count);\n        switch (*mode) {\n        case 'a':\n            return xm_io_file_read_all(lua, file, continuation);\n        case 'L':\n            return xm_io_file_read_line(lua, file, continuation, tb_true);\n        case 'n':\n            xm_io_return_error(lua, \"read number is not implemented\");\n        case 'l':\n            return xm_io_file_read_line(lua, file, continuation, tb_false);\n        default:\n            xm_io_return_error(lua, \"unknonwn read mode\");\n            return 0;\n        }\n    } else {\n        if (count >= 0)\n            return xm_io_file_std_read_n(lua, file, continuation, count);\n        switch (*mode) {\n        case 'a':\n            return xm_io_file_std_read_all(lua, file, continuation);\n        case 'L':\n            return xm_io_file_std_read_line(lua, file, continuation, tb_true);\n        case 'n':\n            return xm_io_file_std_read_num(lua, file, continuation);\n        case 'l':\n            return xm_io_file_std_read_line(lua, file, continuation, tb_false);\n        default:\n            xm_io_return_error(lua, \"unknonwn read mode\");\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_readable.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        file_readable.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_readable\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_io_file_readable(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"read(invalid file)!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // has readable data?\n    tb_bool_t ok = tb_false;\n    if (xm_io_file_is_file(file)) {\n        ok = tb_stream_left(file->u.file_ref) > 0;\n    } else {\n        ok = tb_stdfile_readable(file->u.std_ref);\n    }\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_seek.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_seek.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_seek\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.file_seek(file, [whence [, offset]])\ntb_int_t xm_io_file_seek(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"seek(invalid file)!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // get whence and offset\n    tb_char_t const *whence = luaL_optstring(lua, 2, \"cur\");\n    tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0);\n    tb_assert_and_check_return_val(whence, 0);\n\n    // seek file\n    if (xm_io_file_is_file(file)) {\n        tb_assert(file->u.file_ref);\n        switch (*whence) {\n        case 's': // \"set\"\n            break;\n        case 'e': // \"end\"\n        {\n            tb_hong_t size = tb_stream_size(file->u.file_ref);\n            if (size > 0 && size + offset <= size) {\n                offset = size + offset;\n            } else {\n                xm_io_return_error(lua, \"seek failed, invalid offset!\");\n            }\n        } break;\n        default: // \"cur\"\n            offset = tb_stream_offset(file->u.file_ref) + offset;\n            break;\n        }\n\n        if (tb_stream_seek(file->u.file_ref, offset)) {\n            lua_pushnumber(lua, (lua_Number)offset);\n            return 1;\n        } else {\n            xm_io_return_error(lua, \"seek failed!\");\n        }\n    } else {\n        xm_io_return_error(lua, \"seek is not supported on this file\");\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_size.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_size.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_size\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.file_size(file)\ntb_int_t xm_io_file_size(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1)) {\n        xm_io_return_error(lua, \"get size for invalid file!\");\n    }\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // get file length\n    if (xm_io_file_is_file(file)) {\n        // get size from raw file stream, because we cannot get size from fstream\n        tb_assert(file->stream);\n        lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream));\n        return 1;\n    } else {\n        xm_io_return_error(lua, \"get size for invalid file!\");\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/io/file_write.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        file_write.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_write\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_io_file_write_file_utfbom(xm_io_file_t *file) {\n    tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref);\n\n    // write bom\n    switch (file->encoding) {\n    case TB_CHARSET_TYPE_UTF8: {\n        static tb_byte_t bom[] = { 0xef, 0xbb, 0xbf };\n        tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));\n    } break;\n    case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE: {\n        static tb_byte_t bom[] = { 0xff, 0xfe };\n        tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));\n    } break;\n    case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE: {\n        static tb_byte_t bom[] = { 0xfe, 0xff };\n        tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));\n    } break;\n    default:\n        break;\n    }\n}\nstatic tb_void_t xm_io_file_write_file_directly(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {\n    tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref);\n    tb_stream_bwrit(file->u.file_ref, data, size);\n}\nstatic tb_void_t xm_io_file_write_file_transcrlf(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {\n    tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n\n    // write cached data first\n    tb_byte_t const *odata = tb_buffer_data(&file->wcache);\n    tb_size_t osize = tb_buffer_size(&file->wcache);\n    if (odata && osize) {\n        if (!tb_stream_bwrit(file->u.file_ref, odata, osize))\n            return;\n        tb_buffer_clear(&file->wcache);\n    }\n\n    // write data by lines\n    tb_char_t const *p = (tb_char_t const *)data;\n    tb_char_t const *e = p + size;\n    tb_char_t const *lf = tb_null;\n    while (p < e) {\n        lf = tb_strnchr(p, e - p, '\\n');\n        if (lf) {\n            if (lf > p && lf[-1] == '\\r') {\n                if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf + 1 - p))\n                    break;\n            } else {\n                if (lf > p && !tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf - p))\n                    break;\n                if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)\"\\r\\n\", 2))\n                    break;\n            }\n\n            // next line\n            p = lf + 1;\n        } else {\n            // cache the left data\n            tb_buffer_memncat(&file->wcache, (tb_byte_t const *)p, e - p);\n            p = e;\n            break;\n        }\n    }\n#else\n    return xm_io_file_write_file_directly(file, data, size);\n#endif\n}\nstatic tb_void_t xm_io_file_write_std(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {\n    tb_assert(file && data && xm_io_file_is_std(file));\n\n    // check type\n    tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY);\n    tb_check_return(type != XM_IO_FILE_TYPE_STDIN);\n\n    // write data to stdout/stderr\n    tb_stdfile_writ(file->u.std_ref, data, size);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.file_write(file, ...)\ntb_int_t xm_io_file_write(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is user data?\n    if (!lua_isuserdata(lua, 1))\n        xm_io_return_error(lua, \"write(invalid file)!\");\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);\n    tb_check_return_val(file, 0);\n\n    // write file data\n    tb_int_t narg = lua_gettop(lua);\n    if (narg > 1) {\n        tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;\n        for (tb_int_t i = 2; i <= narg; i++) {\n            // get data\n            size_t datasize = 0;\n            tb_byte_t const *data = tb_null;\n            if (lua_isstring(lua, i)) {\n                data = (tb_byte_t const *)luaL_checklstring(lua, i, &datasize);\n            } else if (lua_istable(lua, i)) {\n                // get bytes data\n                lua_pushstring(lua, \"data\");\n                lua_gettable(lua, i);\n                if (xm_lua_isinteger(lua, -1)) {\n                    data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, -1);\n                }\n                lua_pop(lua, 1);\n                tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n                lua_pushstring(lua, \"size\");\n                lua_gettable(lua, i);\n                if (xm_lua_isinteger(lua, -1)) {\n                    datasize = (tb_size_t)lua_tointeger(lua, -1);\n                }\n                lua_pop(lua, 1);\n\n                // mark as binary data\n                is_binary = tb_true;\n            }\n\n            tb_check_continue(datasize);\n            tb_assert_and_check_break(data);\n\n            // write data to std or file\n            if (xm_io_file_is_std(file)) {\n                xm_io_file_write_std(file, data, (tb_size_t)datasize);\n            } else if (is_binary) {\n                xm_io_file_write_file_directly(file, data, (tb_size_t)datasize);\n            } else {\n                // write utf bom first?\n                if (file->utfbom) {\n                    xm_io_file_write_file_utfbom(file);\n                    file->utfbom = tb_false;\n                }\n                xm_io_file_write_file_transcrlf(file, data, (tb_size_t)datasize);\n            }\n        }\n    }\n    lua_settop(lua, 1);\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/filelock_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filelock_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filelock_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.filelock_close(lock)\ntb_int_t xm_io_filelock_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check lock?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get lock\n    tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(lock, 0);\n\n    // exit lock\n    tb_filelock_exit(lock);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/filelock_lock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filelock_lock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filelock_lock\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* lock file\n *\n * exclusive lock:  io.filelock_lock(lock, \"/xxxx/filelock\")\n * shared lock:     io.filelock_lock(lock, \"/xxxx/filelock\", {shared = true})\n */\ntb_int_t xm_io_filelock_lock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get option argument\n    tb_bool_t is_shared = tb_false;\n    if (lua_istable(lua, 2)) {\n        // is shared lock?\n        lua_pushstring(lua, \"shared\");\n        lua_gettable(lua, 2);\n        is_shared = (tb_bool_t)lua_toboolean(lua, -1);\n        lua_pop(lua, 1);\n    }\n\n    // check lock?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get lock\n    tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(lock, 0);\n\n    // lock it\n    tb_bool_t ok = tb_filelock_enter(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/filelock_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filelock_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filelock_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/*\n * io.filelock_open(path)\n */\ntb_int_t xm_io_filelock_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get file path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_assert_and_check_return_val(path, 0);\n\n    // init file lock\n    tb_long_t tryn = 2;\n    tb_filelock_ref_t lock = tb_null;\n    while (!lock && tryn-- > 0) {\n        lock = tb_filelock_init_from_path(path,\n                                          tb_file_info(path, tb_null) ? TB_FILE_MODE_RW\n                                                                      : TB_FILE_MODE_RW | TB_FILE_MODE_CREAT);\n    }\n    if (lock) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)lock);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/filelock_trylock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filelock_trylock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filelock_trylock\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* try to lock file\n *\n * exclusive lock:  io.filelock_trylock(\"/xxxx/filelock\")\n * shared lock:     io.filelock_trylock(\"/xxxx/filelock\", {shared = true})\n */\ntb_int_t xm_io_filelock_trylock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get option argument\n    tb_bool_t is_shared = tb_false;\n    if (lua_istable(lua, 2)) {\n        // is shared lock?\n        lua_pushstring(lua, \"shared\");\n        lua_gettable(lua, 2);\n        is_shared = (tb_bool_t)lua_toboolean(lua, -1);\n        lua_pop(lua, 1);\n    }\n\n    // check lock?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get lock\n    tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(lock, 0);\n\n    // try to lock it\n    tb_bool_t ok = tb_filelock_enter_try(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/filelock_unlock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filelock_unlock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filelock_unlock\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.filelock_unlock(lock)\ntb_int_t xm_io_filelock_unlock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check lock?\n    if (!xm_lua_topointer(lua, 1)) {\n        return 0;\n    }\n\n    // get lock\n    tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(lock, 0);\n\n    // unlock it\n    tb_bool_t ok = tb_filelock_leave(lock);\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/iscygpty.c",
    "content": "/*\n * iscygpty.c -- part of ptycheck\n * https://github.com/k-takata/ptycheck\n *\n * Copyright (c) 2015-2017 K.Takata\n *\n * You can redistribute it and/or modify it under the terms of either\n * the MIT license (as described below) or the Vim license.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifdef _WIN32\n\n#include <ctype.h>\n#include <io.h>\n#include <wchar.h>\n#include <windows.h>\n\n#ifdef USE_FILEEXTD\n/* VC 7.1 or earlier doesn't support SAL. */\n#if !defined(_MSC_VER) || (_MSC_VER < 1400)\n#define __out\n#define __in\n#define __in_opt\n#endif\n/* Win32 FileID API Library:\n * http://www.microsoft.com/en-us/download/details.aspx?id=22599\n * Needed for WinXP. */\n#include <fileextd.h>\n#else /* USE_FILEEXTD */\n/* VC 8 or earlier. */\n#if defined(_MSC_VER) && (_MSC_VER < 1500)\n#ifdef ENABLE_STUB_IMPL\n#define STUB_IMPL\n#else\n#error \"Win32 FileID API Library is required for VC2005 or earlier.\"\n#endif\n#endif\n#endif /* USE_FILEEXTD */\n\n#if _WIN32_WINNT >= 0x0600\n#define USE_DYNFILEID // we need to enable it for supporting xp\n#endif\n#ifdef USE_DYNFILEID\ntypedef BOOL(WINAPI *pfnGetFileInformationByHandleEx)(HANDLE hFile,\n                                                      FILE_INFO_BY_HANDLE_CLASS FileInformationClass,\n                                                      LPVOID lpFileInformation,\n                                                      DWORD dwBufferSize);\nstatic pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;\n\n#ifndef USE_FILEEXTD\nstatic BOOL WINAPI stub_GetFileInformationByHandleEx(HANDLE hFile,\n                                                     FILE_INFO_BY_HANDLE_CLASS FileInformationClass,\n                                                     LPVOID lpFileInformation,\n                                                     DWORD dwBufferSize) {\n    return FALSE;\n}\n#endif\n\nstatic void setup_fileid_api(void) {\n    if (pGetFileInformationByHandleEx != NULL) {\n        return;\n    }\n    pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx)\n        GetProcAddress(GetModuleHandle(TEXT(\"kernel32.dll\")), \"GetFileInformationByHandleEx\");\n    if (pGetFileInformationByHandleEx == NULL) {\n#ifdef USE_FILEEXTD\n        pGetFileInformationByHandleEx = GetFileInformationByHandleEx;\n#else\n        pGetFileInformationByHandleEx = stub_GetFileInformationByHandleEx;\n#endif\n    }\n}\n#else\n#define pGetFileInformationByHandleEx GetFileInformationByHandleEx\n#define setup_fileid_api()\n#endif\n\n#define is_wprefix(s, prefix) (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)\n\n/* Check if the fd handle is a cygwin/msys's pty. */\nint is_cygpty(HANDLE h) {\n#if defined(STUB_IMPL)\n    return 0;\n#elif _WIN32_WINNT >= 0x0600\n    int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1);\n    FILE_NAME_INFO *nameinfo;\n    WCHAR *p = NULL;\n\n    setup_fileid_api();\n\n    if (h == INVALID_HANDLE_VALUE) {\n        return 0;\n    }\n    /* Cygwin/msys's pty is a pipe. */\n    if (GetFileType(h) != FILE_TYPE_PIPE) {\n        return 0;\n    }\n    nameinfo = (FILE_NAME_INFO *)malloc(size + sizeof(WCHAR));\n    if (nameinfo == NULL) {\n        return 0;\n    }\n    /* Check the name of the pipe:\n     * '\\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' */\n    if (pGetFileInformationByHandleEx(h, FileNameInfo, nameinfo, size)) {\n        nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\\0';\n        p = nameinfo->FileName;\n        if (is_wprefix(p, L\"\\\\cygwin-\")) { /* Cygwin */\n            p += 8;\n        } else if (is_wprefix(p, L\"\\\\msys-\")) { /* MSYS and MSYS2 */\n            p += 6;\n        } else {\n            p = NULL;\n        }\n        if (p != NULL) {\n            while (*p && isxdigit(*p)) { /* Skip 16-digit hexadecimal. */\n                ++p;\n            }\n            if (is_wprefix(p, L\"-pty\")) {\n                p += 4;\n            } else {\n                p = NULL;\n            }\n        }\n        if (p != NULL) {\n            while (*p && isdigit(*p)) { /* Skip pty number. */\n                ++p;\n            }\n            if (is_wprefix(p, L\"-from-master\")) {\n                //p += 12;\n            } else if (is_wprefix(p, L\"-to-master\")) {\n                //p += 10;\n            } else {\n                p = NULL;\n            }\n        }\n    }\n    free(nameinfo);\n    return (p != NULL);\n#else\n    return 0;\n#endif\n}\n\n#endif /* _WIN32 */\n"
  },
  {
    "path": "core/src/xmake/io/pipe_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.pipe_close(pipe)\ntb_int_t xm_io_pipe_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check pipe?\n    if (!xm_pipe_file_is_valid(lua, 1)) {\n        return 0;\n    }\n\n    // get the pipe file\n    tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);\n    tb_check_return_val(pipefile, 0);\n\n    // exit pipe file\n    lua_pushboolean(lua, tb_pipe_file_exit(pipefile));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_connect.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_connect.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_connect\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.pipe_connect(pipefile)\ntb_int_t xm_io_pipe_connect(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check pipe\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushnumber(lua, -1);\n        lua_pushliteral(lua, \"invalid pipe!\");\n        return 2;\n    }\n\n    // get pipe file\n    tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(pipefile, 0);\n\n    // connect pipe\n    lua_pushnumber(lua, (tb_int_t)tb_pipe_file_connect(pipefile));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/*\n * io.pipe_open(name, mode, buffsize)\n */\ntb_int_t xm_io_pipe_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get pipe name and mode\n    tb_char_t const *name    = luaL_checkstring(lua, 1);\n    tb_char_t const *modestr = luaL_optstring(lua, 2, \"r\");\n    tb_assert_and_check_return_val(name && modestr, 0);\n\n    // get pipe mode value\n    tb_size_t mode = TB_PIPE_MODE_RO;\n    if (modestr[0] == 'w') {\n        mode = TB_PIPE_MODE_WO;\n    }\n\n    // set block mode\n    if (modestr[1] == 'B') {\n        mode |= TB_PIPE_MODE_BLOCK;\n    }\n\n    // get buffer size\n    tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 3);\n\n    // open pipe file\n    tb_pipe_file_ref_t pipefile = tb_pipe_file_init(name, mode, buffsize);\n    if (pipefile) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)pipefile);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_openpair.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_openpair.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_openpair\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/*\n * io.pipe_openpair(mode, buffsize)\n */\ntb_int_t xm_io_pipe_openpair(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get pipe mode\n    tb_char_t const *modestr = luaL_optstring(lua, 1, \"AA\");\n    tb_assert_and_check_return_val(modestr, 0);\n\n    // init mode\n    tb_size_t mode[2] = { 0 };\n    if (modestr[0] == 'B') {\n        mode[0] |= TB_PIPE_MODE_BLOCK;\n    }\n    if (modestr[1] == 'B') {\n        mode[1] |= TB_PIPE_MODE_BLOCK;\n    }\n\n    // get buffer size\n    tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 2);\n\n    // init pipe\n    tb_pipe_file_ref_t pipefile[2];\n    if (tb_pipe_file_init_pair(pipefile, mode, buffsize)) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[0]);\n        xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[1]);\n    } else {\n        lua_pushnil(lua);\n        lua_pushnil(lua);\n    }\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_read.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_read.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_read\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// real, data_or_errors = io.pipe_read(pipefile, size)\ntb_int_t xm_io_pipe_read(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check pipe file\n    if (!xm_pipe_file_is_valid(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid pipe file!\");\n        return 2;\n    }\n\n    // get pipe file\n    tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);\n    tb_check_return_val(pipefile, 0);\n\n    // get data\n    tb_byte_t *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (!data) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p)!\", data);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get size\n    tb_long_t size = 0;\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_long_t)lua_tointeger(lua, 3);\n    }\n    if (size <= 0) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid size(%d)!\", (tb_int_t)size);\n        return 2;\n    }\n\n    // read data\n    tb_long_t real = tb_pipe_file_read(pipefile, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_wait\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.pipe_wait(pipefile, events, timeout)\ntb_int_t xm_io_pipe_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check pipe?\n    if (!xm_pipe_file_is_valid(lua, 1)) {\n        return 0;\n    }\n\n    // get pipe file\n    tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);\n    tb_check_return_val(pipefile, 0);\n\n    // get events\n    tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2);\n\n    // get timeout\n    tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3);\n\n    // wait pipe\n    lua_pushnumber(lua, (tb_int_t)tb_pipe_file_wait(pipefile, events, timeout));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/pipe_write.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        pipe_write.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"pipe_write\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.pipe_write(pipefile, data, start, last)\ntb_int_t xm_io_pipe_write(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check pipe\n    if (!xm_pipe_file_is_valid(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid pipe file!\");\n        return 2;\n    }\n\n    // get pipe file\n    tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);\n    tb_check_return_val(pipefile, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // write data\n    tb_long_t real = tb_pipe_file_write(pipefile, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"poller.h\"\n#include \"../engine.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_poller_ref_t xm_io_poller(lua_State *lua) {\n    tb_poller_ref_t poller = tb_null;\n    xm_engine_ref_t engine = xm_engine_get(lua);\n    if (engine) {\n        poller = xm_engine_poller(engine);\n    }\n    tb_assert(poller);\n    return poller;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller.h\n *\n */\n#ifndef XM_IO_POLLER_H\n#define XM_IO_POLLER_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the poller state in wait events\ntypedef struct __xm_poller_state_t {\n    lua_State *lua;\n    tb_int_t events_count;\n} xm_poller_state_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/* get io poller\n *\n * @return          the io poller\n */\ntb_poller_ref_t xm_io_poller(lua_State *lua);\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/io/poller_insert.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_insert.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_insert\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.poller_insert(obj:otype(), obj:cdata(), events)\ntb_int_t xm_io_poller_insert(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 2)) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"invalid poller object!\");\n        return 2;\n    }\n\n    // get otype\n    tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);\n\n    // get cdata\n    tb_char_t const *cdata_str = tb_null;\n    tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str);\n    tb_check_return_val(cdata, 0);\n\n    // get events\n    tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3);\n\n    // insert events to poller\n    tb_poller_object_t object;\n    object.type    = otype;\n    object.ref.ptr = cdata;\n    lua_pushboolean(lua, tb_poller_insert(xm_io_poller(lua), &object, events, cdata_str));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller_modify.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_modify.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_modify\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.poller_modify(obj:otype(), obj:cdata(), events)\ntb_int_t xm_io_poller_modify(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 2)) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"invalid poller object!\");\n        return 2;\n    }\n\n    // get otype\n    tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);\n\n    // get cdata\n    tb_char_t const *cdata_str = tb_null;\n    tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str);\n    tb_check_return_val(cdata, 0);\n\n    // get events\n    tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3);\n\n    // modify events in poller\n    tb_poller_object_t object;\n    object.type    = otype;\n    object.ref.ptr = cdata;\n    lua_pushboolean(lua, tb_poller_modify(xm_io_poller(lua), &object, events, cdata_str));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller_remove.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_remove.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_remove\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.poller_remove(obj:otype(), obj)\ntb_int_t xm_io_poller_remove(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 2)) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushfstring(lua, \"invalid poller object!\");\n        return 2;\n    }\n\n    // get otype\n    tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);\n\n    // get cdata\n    tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer(lua, 2);\n    tb_check_return_val(cdata, 0);\n\n    // remove events from poller\n    tb_poller_object_t object;\n    object.type    = otype;\n    object.ref.ptr = cdata;\n    lua_pushboolean(lua, tb_poller_remove(xm_io_poller(lua), &object));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller_spank.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_spank.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_spank\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.poller_spank()\ntb_int_t xm_io_poller_spank(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // spank the poller, break the tb_poller_wait() and return all events\n    tb_poller_spak(xm_io_poller(lua));\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller_support.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_support.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_support\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.poller_support(events)\ntb_int_t xm_io_poller_support(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get events\n    tb_size_t events = (tb_size_t)luaL_checknumber(lua, 1);\n\n    // support events for poller\n    lua_pushboolean(lua, tb_poller_support(xm_io_poller(lua), events));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/poller_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        poller_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"poller_wait\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"poller.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_io_poller_event(tb_poller_ref_t poller,\n                                    tb_poller_object_ref_t object,\n                                    tb_long_t events,\n                                    tb_cpointer_t priv) {\n    xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller);\n    tb_assert_and_check_return(state && state->lua);\n\n    // save object and events\n    lua_State *lua = state->lua;\n    lua_newtable(lua);\n    lua_pushinteger(lua, (tb_int_t)object->type);\n    lua_rawseti(lua, -2, 1);\n    if (priv) {\n        lua_pushstring(lua, (tb_char_t const *)priv);\n    } else {\n        lua_pushlightuserdata(lua, object->ref.ptr);\n    }\n    lua_rawseti(lua, -2, 2);\n    if (object->type == TB_POLLER_OBJECT_FWATCHER) {\n        lua_newtable(lua);\n        tb_fwatcher_event_t *event = (tb_fwatcher_event_t *)events;\n        if (event) {\n            lua_pushstring(lua, \"path\");\n            lua_pushstring(lua, event->filepath);\n            lua_settable(lua, -3);\n\n            lua_pushstring(lua, \"type\");\n            lua_pushinteger(lua, event->event);\n            lua_settable(lua, -3);\n        }\n    } else {\n        lua_pushinteger(lua, (tb_int_t)events);\n    }\n    lua_rawseti(lua, -2, 3);\n    lua_rawseti(lua, -2, ++state->events_count);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// local events, count = io.poller_wait(timeout)\ntb_int_t xm_io_poller_wait(lua_State *lua) {\n    tb_poller_ref_t poller = xm_io_poller(lua);\n    tb_assert_and_check_return_val(poller && lua, 0);\n\n    // get timeout\n    tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 1);\n\n    // reset events count\n    xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller);\n    state->events_count = 0;\n\n    // wait it\n    lua_newtable(lua);\n    tb_long_t count = tb_poller_wait(poller, xm_io_poller_event, timeout);\n    if (count > 0) {\n        lua_pushinteger(lua, (tb_int_t)count);\n        return 2;\n    } else if (!count) {\n        // timeout\n        lua_pop(lua, 1);\n        lua_pushnil(lua);\n        lua_pushinteger(lua, 0);\n        return 2;\n    }\n\n    lua_pop(lua, 1);\n    lua_pushnil(lua);\n    lua_pushinteger(lua, -1);\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/io/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_IO_PREFIX_H\n#define XM_IO_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_IO_BLOCK_MAXN (TB_STREAM_BLOCK_MAXN * 10)\n\n// return io error\n#define xm_io_return_error(lua, error)                                                                                 \\\n    do {                                                                                                               \\\n        lua_pushnil(lua);                                                                                              \\\n        lua_pushliteral(lua, error);                                                                                   \\\n        return 2;                                                                                                      \\\n    } while (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef enum __xm_io_file_type_e {\n    XM_IO_FILE_TYPE_FILE = 0 //!< disk file\n\n        ,\n    XM_IO_FILE_TYPE_STDIN  = 1,\n    XM_IO_FILE_TYPE_STDOUT = 2,\n    XM_IO_FILE_TYPE_STDERR = 3\n\n        ,\n    XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream\n} xm_io_file_type_e;\n\n/* use negetive numbers for this enum, its a extension for tb_charset_type_e\n * before adding new values, make sure they have not conflicts with values in tb_charset_type_e\n */\ntypedef enum __xm_io_file_encoding_e {\n    XM_IO_FILE_ENCODING_UNKNOWN = -1,\n    XM_IO_FILE_ENCODING_BINARY  = -2\n} xm_io_file_encoding_e;\n\n// the file type\ntypedef struct __xm_io_file_t {\n    union {\n        /* the normal file for XM_IO_FILE_TYPE_FILE\n         *\n         * direct:    file_ref -> stream -> file\n         * transcode: file_ref -> fstream -> stream -> file\n         */\n        tb_stream_ref_t file_ref;\n\n        // the standard io file\n        tb_stdfile_ref_t std_ref;\n    } u;\n\n    tb_stream_ref_t stream;   // the file stream for XM_IO_FILE_TYPE_FILE\n    tb_stream_ref_t fstream;  // the file charset stream filter\n    tb_size_t mode;     // tb_file_mode_t\n    tb_size_t type;     // xm_io_file_type_e\n    tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e\n    tb_bool_t utfbom;   // write utf-bom for utf encoding?\n    tb_buffer_t rcache; // the read line cache buffer\n    tb_buffer_t wcache; // the write line cache buffer\n} xm_io_file_t;\n\nstatic __tb_inline__ tb_bool_t xm_io_file_is_file(xm_io_file_t const *file) {\n    return file && file->type == XM_IO_FILE_TYPE_FILE;\n}\n\nstatic __tb_inline__ tb_bool_t xm_io_file_is_std(xm_io_file_t const *file) {\n    return file && file->type != XM_IO_FILE_TYPE_FILE;\n}\n\nstatic __tb_inline__ tb_bool_t xm_io_file_is_tty(xm_io_file_t const *file) {\n    return file && (file->type & XM_IO_FILE_FLAG_TTY);\n}\n\n// check pipe file\nstatic __tb_inline__ tb_bool_t xm_pipe_file_is_valid(lua_State *lua, tb_int_t index) {\n    return xm_lua_ispointer(lua, index) || xm_lua_isinteger(lua, index);\n}\n\n// get the pipe file from arguments\nstatic __tb_inline__ tb_pipe_file_ref_t xm_pipe_file_get(lua_State *lua, tb_int_t index) {\n    tb_pipe_file_ref_t pipe_file = tb_null;\n    if (xm_lua_isinteger(lua, index))\n        pipe_file = (tb_pipe_file_ref_t)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    else if (xm_lua_ispointer(lua, index))\n        pipe_file = (tb_pipe_file_ref_t)xm_lua_topointer(lua, index);\n    return pipe_file;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/io/socket_accept.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_accept.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_accept\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// local sock = io.socket_accept(sock)\ntb_int_t xm_io_socket_accept(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // accept socket\n    tb_socket_ref_t client = tb_socket_accept(sock, tb_null);\n    if (client) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)client);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_bind.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_bind.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_bind\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_bind(sock, addr, port, family)\ntb_int_t xm_io_socket_bind(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get address\n    tb_char_t const *address = lua_tostring(lua, 2);\n    tb_assert_and_check_return_val(address, 0);\n\n    // get family\n    tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4);\n\n    // init address\n    tb_ipaddr_t addr;\n    if (family == TB_IPADDR_FAMILY_UNIX) {\n        tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3);\n        tb_ipaddr_unix_set_cstr(&addr, address, is_abstract);\n    } else {\n        tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3);\n        tb_ipaddr_set(&addr, address, port, family);\n    }\n\n    // bind socket\n    lua_pushboolean(lua, tb_socket_bind(sock, &addr));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_close(sock)\ntb_int_t xm_io_socket_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // exit socket\n    lua_pushboolean(lua, tb_socket_exit(sock));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_connect.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_connect.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_connect\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_connect(sock, addr, port, family)\ntb_int_t xm_io_socket_connect(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushnumber(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get address\n    tb_char_t const *address = lua_tostring(lua, 2);\n    tb_assert_and_check_return_val(address, 0);\n\n    // get family\n    tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4);\n\n    // init address\n    tb_ipaddr_t addr;\n    if (family == TB_IPADDR_FAMILY_UNIX) {\n        tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3);\n        tb_ipaddr_unix_set_cstr(&addr, address, is_abstract);\n    } else {\n        tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3);\n        tb_ipaddr_set(&addr, address, port, family);\n    }\n\n    // connect socket\n    lua_pushnumber(lua, (tb_int_t)tb_socket_connect(sock, &addr));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_ctrl.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_ctrl.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_ctrl\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_ctrl(sock, code, value)\ntb_int_t xm_io_socket_ctrl(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushnumber(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get code\n    tb_size_t code = (tb_size_t)luaL_checkinteger(lua, 2);\n\n    // get value\n    tb_size_t value = (tb_size_t)luaL_checkinteger(lua, 3);\n\n    // control socket\n    lua_pushboolean(lua, tb_socket_ctrl(sock, code, value));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_kill.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_kill.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_kill\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// local sock = io.socket_kill(sock)\ntb_int_t xm_io_socket_kill(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // kill socket\n    tb_socket_kill(sock, TB_SOCKET_KILL_RW);\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_listen.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_listen.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_listen\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_listen(sock, backlog)\ntb_int_t xm_io_socket_listen(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get backlog\n    tb_size_t backlog = (tb_size_t)luaL_checknumber(lua, 2);\n\n    // listen socket\n    lua_pushnumber(lua, (tb_int_t)tb_socket_listen(sock, backlog));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/*\n * io.socket_open(socktype, family)\n */\ntb_int_t xm_io_socket_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get socket type\n    tb_size_t socktype = (tb_size_t)luaL_checknumber(lua, 1);\n\n    // get address family\n    tb_size_t family = (tb_size_t)luaL_checknumber(lua, 2);\n\n    // map socket type\n    switch (socktype) {\n    case 2:\n        socktype = TB_SOCKET_TYPE_UDP;\n        break;\n    case 3:\n        socktype = TB_SOCKET_TYPE_ICMP;\n        break;\n    default:\n        socktype = TB_SOCKET_TYPE_TCP;\n        break;\n    }\n\n    // init socket\n    tb_socket_ref_t sock = tb_socket_init(socktype, family);\n    if (sock) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)sock);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_peeraddr.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this sock except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @sock        socket_peeraddr.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_peeraddr\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// socket to fd\n#define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* io.socket_peeraddr(sock)\n */\ntb_int_t xm_io_socket_peeraddr(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        xm_io_return_error(lua, \"get peer address for invalid sock!\");\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get peer address\n    tb_ipaddr_t addr;\n    tb_char_t data[256];\n    tb_char_t const *cstr = tb_null;\n    if (tb_socket_peer(sock, &addr) && (cstr = tb_ipaddr_cstr(&addr, data, sizeof(data)))) {\n        lua_pushstring(lua, cstr);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_rawfd.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this sock except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @sock        socket_rawfd.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_rawfd\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// socket to fd\n#define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* io.socket_rawfd(sock)\n */\ntb_int_t xm_io_socket_rawfd(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1))\n        xm_io_return_error(lua, \"get rawfd for invalid sock!\");\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // return result\n    lua_pushnumber(lua, xm_io_sock2fd(sock));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_recv.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_recv.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_recv\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// real, data_or_errors = io.socket_recv(sock, size)\ntb_int_t xm_io_socket_recv(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get data\n    tb_byte_t *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (!data) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p)!\", data);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get size\n    tb_long_t size = 0;\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_long_t)lua_tointeger(lua, 3);\n    }\n    if (size <= 0) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid size(%d)!\", (tb_int_t)size);\n        return 2;\n    }\n\n    // recv data\n    tb_long_t real = tb_socket_recv(sock, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_recvfrom.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_recvfrom.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_recvfrom\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// real, data_or_errors, addr, port = io.socket_recvfrom(sock, size)\ntb_int_t xm_io_socket_recvfrom(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get data\n    tb_byte_t *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (!data) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p)!\", data);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get size\n    tb_long_t size = 0;\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_long_t)lua_tointeger(lua, 3);\n    }\n    if (size <= 0) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid size(%d)!\", (tb_int_t)size);\n        return 2;\n    }\n\n    // recv data\n    tb_ipaddr_t ipaddr;\n    tb_ipaddr_clear(&ipaddr);\n    tb_int_t retn = 1;\n    tb_long_t real = tb_socket_urecv(sock, &ipaddr, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    if (real > 0) {\n        retn = 2;\n        lua_pushnil(lua);\n        if (!tb_ipaddr_is_empty(&ipaddr)) {\n            tb_char_t buffer[256];\n            tb_char_t const *ipstr = tb_ipaddr_ip_cstr(&ipaddr, buffer, sizeof(buffer));\n            if (ipstr) {\n                lua_pushstring(lua, ipstr);\n                lua_pushinteger(lua, (tb_int_t)tb_ipaddr_port(&ipaddr));\n                retn = 4;\n            }\n        }\n    }\n    return retn;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_send.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_send.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_send\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.socket_send(sock, data, start, last)\ntb_int_t xm_io_socket_send(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // send data\n    tb_long_t real = tb_socket_send(sock, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_sendfile.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_sendfile.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_sendfile\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.socket_sendfile(sock, file, start, last)\ntb_int_t xm_io_socket_sendfile(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // check file\n    if (!lua_isuserdata(lua, 2)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid file!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get file\n    xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 2);\n    tb_check_return_val(file, 0);\n\n    // does not support stdfile\n    if (!xm_io_file_is_file(file) || !file->stream) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid file type!\");\n        return 2;\n    }\n\n    // get file reference\n    tb_file_ref_t rawfile = tb_null;\n    if (!tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) || !rawfile) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"cannot get file reference!\");\n        return 2;\n    }\n\n    // get file size\n    tb_hize_t filesize = tb_file_size(rawfile);\n    if (!filesize) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"cannot send empty file!\");\n        return 2;\n    }\n\n    // get start\n    tb_long_t start = 1;\n    if (lua_isnumber(lua, 3)) {\n        start = (tb_long_t)lua_tonumber(lua, 3);\n    }\n    if (start < 1 || start > filesize) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid start position(%d)!\", (tb_int_t)start);\n        return 2;\n    }\n\n    // get last\n    tb_long_t last = (tb_long_t)filesize;\n    if (lua_isnumber(lua, 4)) {\n        last = (tb_long_t)lua_tonumber(lua, 4);\n    }\n    if (last < start - 1 || last > filesize + start - 1) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid last position(%d)!\", (tb_int_t)last);\n        return 2;\n    }\n\n    // send file data\n    tb_long_t real = (tb_long_t)tb_socket_sendf(sock, rawfile, start - 1, last - start + 1);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_sendto.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_sendto.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_sendto\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// io.socket_sendto(sock, data, addr, port)\ntb_int_t xm_io_socket_sendto(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid socket!\");\n        return 2;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get address\n    tb_char_t const *addr = lua_tostring(lua, 4);\n    tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 5);\n    if (!addr || !port) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid address!\");\n        return 2;\n    }\n\n    // get address family\n    tb_size_t family = (tb_size_t)luaL_checknumber(lua, 6);\n\n    // init ip address\n    tb_ipaddr_t ipaddr;\n    tb_ipaddr_set(&ipaddr, addr, port, (tb_uint8_t)family);\n\n    // send data\n    tb_long_t real = tb_socket_usend(sock, &ipaddr, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/socket_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        socket_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"socket_wait\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.socket_wait(sock, events, timeout)\ntb_int_t xm_io_socket_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check socket?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get socket\n    tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(sock, 0);\n\n    // get events\n    tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2);\n\n    // get timeout\n    tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3);\n\n    // wait socket\n    lua_pushnumber(lua, (tb_int_t)tb_socket_wait(sock, events, timeout));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/io/stdfile.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu, ruki\n * @file        stdfile.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"stdfile\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <io.h>\n#include \"iscygpty.c\"\n#else\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// the singleton type of stdfile\n#define XM_IO_STDFILE_STDIN (TB_SINGLETON_TYPE_USER + 1)\n#define XM_IO_STDFILE_STDOUT (TB_SINGLETON_TYPE_USER + 2)\n#define XM_IO_STDFILE_STDERR (TB_SINGLETON_TYPE_USER + 3)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_size_t xm_io_stdfile_isatty(tb_size_t type) {\n    tb_bool_t answer = tb_false;\n#if defined(TB_CONFIG_OS_WINDOWS)\n    DWORD mode;\n    HANDLE console_handle = tb_null;\n    switch (type) {\n    case XM_IO_FILE_TYPE_STDIN:\n        console_handle = GetStdHandle(STD_INPUT_HANDLE);\n        break;\n    case XM_IO_FILE_TYPE_STDOUT:\n        console_handle = GetStdHandle(STD_OUTPUT_HANDLE);\n        break;\n    case XM_IO_FILE_TYPE_STDERR:\n        console_handle = GetStdHandle(STD_ERROR_HANDLE);\n        break;\n    }\n    answer = GetConsoleMode(console_handle, &mode);\n    /* we cannot call is_cygpty for stdin, because it will cause io.readable is always true\n     * https://github.com/xmake-io/xmake/issues/2504#issuecomment-1170130756\n     */\n    if (!answer && type != XM_IO_FILE_TYPE_STDIN) {\n        answer = is_cygpty(console_handle);\n    }\n#else\n    switch (type) {\n    case XM_IO_FILE_TYPE_STDIN:\n        answer = isatty(fileno(stdin));\n        break;\n    case XM_IO_FILE_TYPE_STDOUT:\n        answer = isatty(fileno(stdout));\n        break;\n    case XM_IO_FILE_TYPE_STDERR:\n        answer = isatty(fileno(stderr));\n        break;\n    }\n#endif\n\n    if (answer) {\n        type |= XM_IO_FILE_FLAG_TTY;\n    }\n    return type;\n}\n\n// @see https://github.com/xmake-io/xmake/issues/2580\nstatic tb_void_t xm_io_stdfile_init_buffer(tb_size_t type) {\n#if !defined(TB_CONFIG_OS_WINDOWS)\n    struct stat stats;\n    tb_int_t size = BUFSIZ;\n    if (fstat(fileno(stdout), &stats) != -1) {\n        size = stats.st_blksize;\n    }\n    setvbuf(stdout, tb_null, _IOLBF, size);\n#endif\n}\n\nstatic xm_io_file_t *xm_io_stdfile_new(lua_State *lua, tb_size_t type) {\n    // init stdfile\n    tb_stdfile_ref_t fp = tb_null;\n    switch (type) {\n    case XM_IO_FILE_TYPE_STDIN:\n        fp = tb_stdfile_input();\n        break;\n    case XM_IO_FILE_TYPE_STDOUT:\n        fp = tb_stdfile_output();\n        break;\n    case XM_IO_FILE_TYPE_STDERR:\n        fp = tb_stdfile_error();\n        break;\n    }\n\n    // new file\n    xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t));\n    tb_assert_and_check_return_val(file, tb_null);\n\n    // init file\n    file->u.std_ref = fp;\n    file->stream    = tb_null;\n    file->fstream   = tb_null;\n    file->type      = xm_io_stdfile_isatty(type);\n    file->encoding  = TB_CHARSET_TYPE_UTF8;\n\n    // init stdio buffer\n    xm_io_stdfile_init_buffer(type);\n\n    // init the read/write line cache buffer\n    tb_buffer_init(&file->rcache);\n    tb_buffer_init(&file->wcache);\n    return file;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n// io.stdfile(stdin: 1, stdout: 2, stderr: 3)\ntb_int_t xm_io_stdfile(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get std type\n    tb_long_t type = (tb_long_t)lua_tointeger(lua, 1);\n\n    /* push a new stdfile\n     *\n     * @note we need to ensure that it is a singleton in the external lua script, and will only be created once, e.g. io.stdin, io.stdout, io.stderr\n     */\n    xm_io_file_t *file = xm_io_stdfile_new(lua, type);\n    if (file) {\n        return 1;\n    } else {\n        xm_io_return_error(lua, \"invalid stdfile type!\");\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/libc/byteof.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        byteof.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"byteof\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_byteof(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data\n    tb_pointer_t data = tb_null;\n    if (lua_isnumber(lua, 1)) {\n        data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);\n    } else if (lua_isstring(lua, 1)) {\n        data = (tb_pointer_t)luaL_checkstring(lua, 1);\n    } else {\n        xm_libc_return_error(lua, \"libc.byteof(invalid data)!\");\n    }\n\n    // get offset\n    tb_int_t offset = 0;\n    if (lua_isnumber(lua, 2)) {\n        offset = (tb_int_t)lua_tointeger(lua, 2);\n    } else {\n        xm_libc_return_error(lua, \"libc.byteof(invalid offset)!\");\n    }\n    lua_pushinteger(lua, ((tb_byte_t const *)data)[offset]);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/dataptr.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        dataptr.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"dataptr\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_dataptr(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_pointer_t data = tb_null;\n    if (lua_isstring(lua, 1)) {\n        data = (tb_pointer_t)luaL_checkstring(lua, 1);\n    } else if (lua_isnumber(lua, 1)) {\n        data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);\n    } else if (xm_lua_ispointer(lua, 1)) {\n        data = (tb_pointer_t)xm_lua_topointer(lua, 1);\n    } else {\n        xm_libc_return_error(lua, \"libc.dataptr(invalid data)!\");\n    }\n    lua_pushinteger(lua, (lua_Integer)(tb_long_t)data);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/free.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        free.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"free\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_free(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do free\n    tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);\n    if (data) {\n        tb_free(data);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/malloc.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        malloc.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"malloc\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_malloc(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do malloc\n    tb_pointer_t data = tb_null;\n    tb_long_t size = (tb_long_t)luaL_checkinteger(lua, 1);\n    if (size > 0) {\n        data = tb_malloc(size);\n    }\n    lua_pushinteger(lua, (lua_Integer)(tb_long_t)data);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/memcpy.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        memcpy.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"memcpy\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_memcpy(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do memcpy\n    tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);\n    tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2);\n    tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);\n    if (dst && src && size > 0) {\n        tb_memcpy(dst, src, size);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/memmov.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        memmov.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"memmov\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_memmov(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do memmov\n    tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);\n    tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2);\n    tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);\n    if (dst && src && size > 0) {\n        tb_memmov(dst, src, size);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/memset.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        memset.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"memset\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_memset(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do memset\n    tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);\n    tb_char_t ch = (tb_char_t)lua_tointeger(lua, 2);\n    tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);\n    if (data && size > 0) {\n        tb_memset(data, ch, size);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_LIBC_PREFIX_H\n#define XM_LIBC_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// return libc error\n#define xm_libc_return_error(lua, error)                                                                               \\\n    do {                                                                                                               \\\n        lua_pushnil(lua);                                                                                              \\\n        lua_pushliteral(lua, error);                                                                                   \\\n        return 2;                                                                                                      \\\n    } while (0)\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/libc/setbyte.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        setbyte.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"setbyte\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_setbyte(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data\n    tb_pointer_t data = tb_null;\n    if (lua_isnumber(lua, 1)) {\n        data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);\n    } else if (lua_isstring(lua, 1)) {\n        data = (tb_pointer_t)luaL_checkstring(lua, 1);\n    } else {\n        xm_libc_return_error(lua, \"libc.setbyte(invalid data)!\");\n    }\n\n    // get offset\n    tb_int_t offset = 0;\n    if (lua_isnumber(lua, 2)) {\n        offset = (tb_int_t)lua_tointeger(lua, 2);\n    } else {\n        xm_libc_return_error(lua, \"libc.setbyte(invalid offset)!\");\n    }\n\n    // set byte\n    if (lua_isnumber(lua, 3)) {\n        ((tb_byte_t *)data)[offset] = (tb_byte_t)lua_tointeger(lua, 3);\n    } else {\n        xm_libc_return_error(lua, \"libc.setbyte(invalid value)!\");\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/libc/strndup.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        strndup.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"strndup\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_libc_strndup(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // do strndup\n    tb_char_t const *s = tb_null;\n    if (lua_isnumber(lua, 1)) {\n        s = (tb_char_t const *)(tb_size_t)lua_tointeger(lua, 1);\n    } else if (lua_isstring(lua, 2)) {\n        s = lua_tostring(lua, 2);\n    } else {\n        xm_libc_return_error(lua, \"libc.strndup(invalid args)!\");\n    }\n    tb_int_t n = (tb_int_t)lua_tointeger(lua, 2);\n    if (s && n >= 0) {\n        lua_pushlstring(lua, s, n);\n    } else {\n        lua_pushliteral(lua, \"\");\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/block_compress.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        block_compress.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"block_compress\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_block_compress(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data and size\n    tb_int_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 1)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n    }\n    if (xm_lua_isinteger(lua, 2)) {\n        size = (tb_int_t)lua_tointeger(lua, 2);\n    }\n    if (!data || !size || size > LZ4_MAX_INPUT_SIZE) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // do compress\n    tb_bool_t ok = tb_false;\n    tb_byte_t *output_data = tb_null;\n    tb_byte_t  buffer[8192];\n    do {\n        tb_int_t output_size = LZ4_compressBound(size);\n        tb_assert_and_check_break(output_size);\n\n        output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size);\n        tb_assert_and_check_break(output_data);\n\n        tb_int_t real = LZ4_compress_default((tb_char_t const *)data, (tb_char_t *)output_data, size, output_size);\n        tb_assert_and_check_break(real > 0);\n\n        lua_pushlstring(lua, (tb_char_t const *)output_data, real);\n        ok = tb_true;\n    } while (0);\n\n    if (output_data && output_data != buffer) {\n        tb_free(output_data);\n        output_data = tb_null;\n    }\n\n    if (!ok) {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/block_decompress.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        block_decompress.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"block_decompress\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_block_decompress(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 1)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n    }\n    if (xm_lua_isinteger(lua, 2)) {\n        size = (tb_size_t)lua_tointeger(lua, 2);\n    }\n    if (!data || !size) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get real size\n    tb_int_t real = (tb_int_t)lua_tointeger(lua, 3);\n    if (real <= 0) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid output size(%d)!\", real);\n        return 2;\n    }\n\n    // do decompress\n    tb_bool_t ok = tb_false;\n    tb_byte_t *output_data = tb_null;\n    tb_byte_t  buffer[8192];\n    do {\n        output_data = real <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(real);\n        tb_assert_and_check_break(output_data);\n\n        tb_int_t r = LZ4_decompress_safe((tb_char_t const *)data, (tb_char_t *)output_data, (tb_int_t)size, real);\n        tb_assert_and_check_break(r > 0);\n\n        lua_pushlstring(lua, (tb_char_t const *)output_data, r);\n        ok = tb_true;\n    } while (0);\n\n    if (output_data && output_data != buffer) {\n        tb_free(output_data);\n        output_data = tb_null;\n    }\n\n    if (!ok) {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_compress(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 1)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n    }\n    if (xm_lua_isinteger(lua, 2)) {\n        size = (tb_size_t)lua_tointeger(lua, 2);\n    }\n    if (!data || !size) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // do compress\n    tb_bool_t ok = tb_false;\n    tb_char_t const *error = tb_null;\n    tb_byte_t *output_data = tb_null;\n    tb_byte_t buffer[8192];\n    do {\n        tb_size_t output_size = LZ4F_compressFrameBound(size, tb_null);\n        tb_assert_and_check_break(output_size);\n\n        output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size);\n        tb_assert_and_check_break(output_data);\n\n        tb_size_t real_or_errs = LZ4F_compressFrame(output_data, output_size, data, size, tb_null);\n        if (LZ4F_isError(real_or_errs)) {\n            error = LZ4F_getErrorName(real_or_errs);\n            break;\n        }\n\n        lua_pushlstring(lua, (tb_char_t const *)output_data, real_or_errs);\n        ok = tb_true;\n    } while (0);\n\n    if (output_data && output_data != buffer) {\n        tb_free(output_data);\n        output_data = tb_null;\n    }\n\n    if (!ok) {\n        lua_pushnil(lua);\n        lua_pushstring(lua, error ? error : \"unknown\");\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress_file.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress_file.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress_file\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_compress_file(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the file paths\n    tb_char_t const *srcpath = luaL_checkstring(lua, 1);\n    tb_char_t const *dstpath = luaL_checkstring(lua, 2);\n    tb_check_return_val(srcpath && dstpath, 0);\n\n    // init lz4 stream\n    xm_lz4_cstream_t *stream_lz4 = xm_lz4_cstream_init();\n    tb_check_return_val(stream_lz4, 0);\n\n    // do compress\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) {\n        tb_bool_t write_ok = tb_false;\n        tb_byte_t idata[TB_STREAM_BLOCK_MAXN];\n        tb_byte_t odata[TB_STREAM_BLOCK_MAXN];\n        while (!tb_stream_beof(istream)) {\n            write_ok        = tb_false;\n            tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata));\n            if (ireal > 0) {\n                tb_long_t r = xm_lz4_cstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream));\n                tb_assert_and_check_break(r >= 0);\n                tb_check_continue(r > 0);\n\n                tb_long_t oreal;\n                while ((oreal = xm_lz4_cstream_read(stream_lz4, odata, sizeof(odata))) > 0) {\n                    if (!tb_stream_bwrit(ostream, odata, oreal)) {\n                        oreal = -1;\n                        break;\n                    }\n                }\n                tb_assert_and_check_break(oreal >= 0);\n            } else {\n                break;\n            }\n            write_ok = tb_true;\n        }\n\n        if (tb_stream_beof(istream) && write_ok) {\n            ok = tb_true;\n        }\n    }\n\n    // exit stream\n    if (istream) {\n        tb_stream_exit(istream);\n        istream = tb_null;\n    }\n    if (ostream) {\n        tb_stream_exit(ostream);\n        ostream = tb_null;\n    }\n    xm_lz4_cstream_exit(stream_lz4);\n\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress_stream_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress_stream_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress_stream_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_compress_stream_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the stream\n    xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // exit stream\n    xm_lz4_cstream_exit(stream);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress_stream_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress_stream_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress_stream_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_compress_stream_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_lz4_cstream_t *stream = xm_lz4_cstream_init();\n    if (stream) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)stream);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress_stream_read.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress_stream_read.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress_stream_read\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_lz4_compress_stream_read(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check handle\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid handle!\");\n        return 2;\n    }\n\n    // get stream\n    xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // get data\n    tb_byte_t *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (!data) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p)!\", data);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get size\n    tb_long_t size = 0;\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_long_t)lua_tointeger(lua, 3);\n    }\n    if (size <= 0) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid size(%d)!\", (tb_int_t)size);\n        return 2;\n    }\n\n    // read data\n    tb_long_t real = xm_lz4_cstream_read(stream, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/compress_stream_write.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        compress_stream_write.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compress_stream_write\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_lz4_compress_stream_write(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check handle\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid handle!\");\n        return 2;\n    }\n\n    // get stream\n    xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // is end?\n    tb_bool_t end = tb_false;\n    if (lua_isboolean(lua, 4)) {\n        end = lua_toboolean(lua, 4);\n    }\n\n    // write data\n    tb_long_t real = xm_lz4_cstream_write(stream, data, size, end);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        decompress.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"decompress\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_decompress(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 1)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);\n    }\n    if (xm_lua_isinteger(lua, 2)) {\n        size = (tb_size_t)lua_tointeger(lua, 2);\n    }\n    if (!data || !size) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // do decompress\n    tb_bool_t ok = tb_false;\n    LZ4F_errorCode_t code;\n    LZ4F_decompressionContext_t ctx = tb_null;\n    tb_buffer_t result;\n    do {\n        tb_buffer_init(&result);\n\n        code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);\n        if (LZ4F_isError(code)) {\n            break;\n        }\n\n        tb_byte_t buffer[8192];\n        tb_bool_t failed = tb_false;\n        while (1) {\n            size_t advance = (size_t)size;\n            size_t buffer_size = sizeof(buffer);\n            code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null);\n            if (LZ4F_isError(code)) {\n                failed = tb_true;\n                break;\n            }\n\n            if (buffer_size == 0) {\n                break;\n            }\n            data += advance;\n            size -= advance;\n\n            tb_buffer_memncat(&result, buffer, buffer_size);\n        }\n        tb_assert_and_check_break(!failed && tb_buffer_size(&result));\n\n        lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&result), tb_buffer_size(&result));\n        ok = tb_true;\n    } while (0);\n\n    if (ctx) {\n        LZ4F_freeDecompressionContext(ctx);\n        ctx = tb_null;\n    }\n    tb_buffer_exit(&result);\n\n    if (!ok) {\n        tb_char_t const *error = LZ4F_getErrorName(code);\n        lua_pushnil(lua);\n        lua_pushstring(lua, error ? error : \"unknown\");\n        return 2;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress_file.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        dedecompress_file.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"dedecompress_file\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_decompress_file(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the file paths\n    tb_char_t const *srcpath = luaL_checkstring(lua, 1);\n    tb_char_t const *dstpath = luaL_checkstring(lua, 2);\n    tb_check_return_val(srcpath && dstpath, 0);\n\n    // init lz4 stream\n    xm_lz4_dstream_t *stream_lz4 = xm_lz4_dstream_init();\n    tb_check_return_val(stream_lz4, 0);\n\n    // do decompress\n    tb_bool_t ok = tb_false;\n    tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);\n    tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath,\n                                                       TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);\n    if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) {\n        tb_bool_t write_ok = tb_false;\n        tb_byte_t idata[TB_STREAM_BLOCK_MAXN];\n        tb_byte_t odata[TB_STREAM_BLOCK_MAXN];\n        while (!tb_stream_beof(istream)) {\n            write_ok        = tb_false;\n            tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata));\n            if (ireal > 0) {\n                tb_long_t r = xm_lz4_dstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream));\n                tb_assert_and_check_break(r >= 0);\n                tb_check_continue(r > 0);\n\n                tb_long_t oreal;\n                while ((oreal = xm_lz4_dstream_read(stream_lz4, odata, sizeof(odata))) > 0) {\n                    if (!tb_stream_bwrit(ostream, odata, oreal)) {\n                        oreal = -1;\n                        break;\n                    }\n                }\n                tb_assert_and_check_break(oreal >= 0);\n            } else {\n                break;\n            }\n            write_ok = tb_true;\n        }\n\n        if (tb_stream_beof(istream) && write_ok) {\n            ok = tb_true;\n        }\n    }\n\n    // exit stream\n    if (istream) {\n        tb_stream_exit(istream);\n        istream = tb_null;\n    }\n    if (ostream) {\n        tb_stream_exit(ostream);\n        ostream = tb_null;\n    }\n    xm_lz4_dstream_exit(stream_lz4);\n\n    lua_pushboolean(lua, ok);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress_stream_close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        decompress_stream_close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"decompress_stream_close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_decompress_stream_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the stream\n    xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // exit stream\n    xm_lz4_dstream_exit(stream);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress_stream_open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        decompress_stream_open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"decompress_stream_open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_lz4_decompress_stream_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_lz4_dstream_t *stream = xm_lz4_dstream_init();\n    if (stream) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)stream);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress_stream_read.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        decompress_stream_read.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"decompress_stream_read\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_lz4_decompress_stream_read(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check handle\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid handle!\");\n        return 2;\n    }\n\n    // get stream\n    xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // get data\n    tb_byte_t *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (!data) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p)!\", data);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // get size\n    tb_long_t size = 0;\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_long_t)lua_tointeger(lua, 3);\n    }\n    if (size <= 0) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid size(%d)!\", (tb_int_t)size);\n        return 2;\n    }\n\n    // read data\n    tb_long_t real = xm_lz4_dstream_read(stream, data, size);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/decompress_stream_write.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        decompress_stream_write.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"decompress_stream_write\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_lz4_decompress_stream_write(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check handle\n    if (!xm_lua_ispointer(lua, 1)) {\n        lua_pushinteger(lua, -1);\n        lua_pushliteral(lua, \"invalid handle!\");\n        return 2;\n    }\n\n    // get stream\n    xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(stream, 0);\n\n    // get data and size\n    tb_size_t size = 0;\n    tb_byte_t const *data = tb_null;\n    if (xm_lua_isinteger(lua, 2)) {\n        data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);\n    }\n    if (xm_lua_isinteger(lua, 3)) {\n        size = (tb_size_t)lua_tointeger(lua, 3);\n    }\n    if (!data || !size) {\n        lua_pushinteger(lua, -1);\n        lua_pushfstring(lua, \"invalid data(%p) and size(%d)!\", data, (tb_int_t)size);\n        return 2;\n    }\n    tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));\n\n    // write data\n    tb_long_t real = xm_lz4_dstream_write(stream, data, size, tb_false);\n    lua_pushinteger(lua, (tb_int_t)real);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/lz4/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except idata compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to idata writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_LZ4_PREFIX_H\n#define XM_LZ4_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n#include \"lz4frame.h\"\n#include \"lz4.h\"\n#include \"lz4hc.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// we need to define LZ4_byte if < 1.9.3\n#if defined(LZ4_VERSION_NUMBER) && LZ4_VERSION_NUMBER < (1 * 100 * 100 + 9 * 100 + 3)\n#if defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n#include <stdint.h>\ntypedef int8_t   LZ4_i8;\ntypedef uint8_t  LZ4_byte;\ntypedef uint16_t LZ4_u16;\ntypedef uint32_t LZ4_u32;\n#else\ntypedef signed char    LZ4_i8;\ntypedef unsigned char  LZ4_byte;\ntypedef unsigned short LZ4_u16;\ntypedef unsigned int   LZ4_u32;\n#endif\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the lz4 compress stream type\ntypedef struct __xm_lz4_cstream_t {\n    LZ4F_cctx *cctx;\n    LZ4_byte *buffer;\n    tb_size_t buffer_size;\n    tb_size_t buffer_maxn;\n    tb_size_t write_maxn;\n    tb_size_t header_size;\n    LZ4_byte header[LZ4F_HEADER_SIZE_MAX];\n} xm_lz4_cstream_t;\n\n// the lz4 decompress stream type\ntypedef struct __xm_lz4_dstream_t {\n    LZ4F_dctx *dctx;\n    LZ4_byte *buffer;\n    tb_size_t buffer_size;\n    tb_size_t buffer_maxn;\n    tb_size_t header_size;\n    LZ4_byte header[LZ4F_HEADER_SIZE_MAX];\n} xm_lz4_dstream_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\nstatic __tb_inline__ tb_void_t xm_lz4_cstream_exit(xm_lz4_cstream_t *stream) {\n    if (stream) {\n        if (stream->cctx) {\n            LZ4F_freeCompressionContext(stream->cctx);\n            stream->cctx = tb_null;\n        }\n        if (stream->buffer) {\n            tb_free(stream->buffer);\n            stream->buffer = tb_null;\n        }\n        tb_free(stream);\n    }\n}\n\nstatic __tb_inline__ xm_lz4_cstream_t *xm_lz4_cstream_init() {\n    tb_size_t ret;\n    tb_bool_t ok = tb_false;\n    xm_lz4_cstream_t *stream = tb_null;\n    LZ4F_preferences_t const *prefsPtr = tb_null;\n    do {\n        stream = tb_malloc0_type(xm_lz4_cstream_t);\n        tb_assert_and_check_break(stream);\n\n        stream->write_maxn = 64 * 1024;\n        stream->buffer_maxn = LZ4F_compressBound(stream->write_maxn, prefsPtr);\n        stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn);\n        tb_assert_and_check_break(stream->buffer);\n\n        ret = LZ4F_createCompressionContext(&stream->cctx, LZ4F_getVersion());\n        if (LZ4F_isError(ret))\n            break;\n\n        ret = LZ4F_compressBegin(stream->cctx, stream->header, LZ4F_HEADER_SIZE_MAX, prefsPtr);\n        if (LZ4F_isError(ret))\n            break;\n\n        stream->header_size = ret;\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok && stream) {\n        xm_lz4_cstream_exit(stream);\n        stream = tb_null;\n    }\n    return stream;\n}\n\nstatic __tb_inline__ tb_long_t xm_lz4_cstream_write(xm_lz4_cstream_t *stream,\n                                                    tb_byte_t const  *idata,\n                                                    tb_size_t         isize,\n                                                    tb_bool_t         end) {\n    tb_assert_and_check_return_val(stream && stream->cctx && idata && isize, -1);\n    tb_assert_and_check_return_val(isize <= stream->write_maxn, -1);\n    tb_assert_and_check_return_val(stream->buffer_size + isize < stream->buffer_maxn, -1);\n\n    tb_size_t real = LZ4F_compressUpdate(stream->cctx,\n                                         stream->buffer + stream->buffer_size,\n                                         stream->buffer_maxn - stream->buffer_size,\n                                         idata,\n                                         isize,\n                                         tb_null);\n    if (LZ4F_isError(real))\n        return -1;\n    stream->buffer_size += real;\n\n    if (end) {\n        tb_size_t ret = LZ4F_compressEnd(stream->cctx,\n                                         stream->buffer + stream->buffer_size,\n                                         stream->buffer_maxn - stream->buffer_size,\n                                         tb_null);\n        if (LZ4F_isError(ret))\n            return -1;\n\n        real += ret;\n        stream->buffer_size += ret;\n    }\n\n    return isize;\n}\n\nstatic __tb_inline__ tb_long_t xm_lz4_cstream_read(xm_lz4_cstream_t *stream, tb_byte_t *odata, tb_size_t osize) {\n    tb_assert_and_check_return_val(stream && stream->cctx && odata && osize, -1);\n    tb_assert_and_check_return_val(osize >= stream->header_size, -1);\n\n    tb_size_t read = 0;\n    if (stream->header_size) {\n        tb_memcpy(odata, stream->header, stream->header_size);\n        read += stream->header_size;\n        osize -= stream->header_size;\n        stream->header_size = 0;\n    }\n\n    tb_size_t need = tb_min(stream->buffer_size, osize);\n    tb_memcpy(odata + read, stream->buffer, need);\n    if (need < stream->buffer_size)\n        tb_memmov(stream->buffer, stream->buffer + need, stream->buffer_size - need);\n    stream->buffer_size -= need;\n    read += need;\n    return read;\n}\n\nstatic __tb_inline__ tb_void_t xm_lz4_dstream_exit(xm_lz4_dstream_t *stream) {\n    if (stream) {\n        if (stream->dctx) {\n            LZ4F_freeDecompressionContext(stream->dctx);\n            stream->dctx = tb_null;\n        }\n        if (stream->buffer) {\n            tb_free(stream->buffer);\n            stream->buffer = tb_null;\n        }\n        tb_free(stream);\n    }\n}\n\nstatic __tb_inline__ xm_lz4_dstream_t *xm_lz4_dstream_init() {\n    LZ4F_errorCode_t  ret;\n    tb_bool_t         ok     = tb_false;\n    xm_lz4_dstream_t *stream = tb_null;\n    do {\n        stream = tb_malloc0_type(xm_lz4_dstream_t);\n        tb_assert_and_check_break(stream);\n\n        ret = LZ4F_createDecompressionContext(&stream->dctx, LZ4F_getVersion());\n        if (LZ4F_isError(ret))\n            break;\n\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok && stream) {\n        xm_lz4_dstream_exit(stream);\n        stream = tb_null;\n    }\n    return stream;\n}\n\nstatic __tb_inline__ tb_long_t xm_lz4_dstream_write(xm_lz4_dstream_t *stream,\n                                                    tb_byte_t const  *idata,\n                                                    tb_size_t         isize,\n                                                    tb_bool_t         end) {\n    tb_assert_and_check_return_val(stream && stream->dctx && idata && isize, -1);\n\n    // read header first\n    const tb_size_t header_size = sizeof(stream->header);\n    if (stream->header_size < header_size) {\n        tb_size_t size = tb_min(header_size - stream->header_size, isize);\n        tb_memcpy(stream->header + stream->header_size, idata, size);\n        stream->header_size += size;\n        idata += size;\n        isize -= size;\n\n        // get frame info if header is ok\n        if (stream->header_size == header_size) {\n            LZ4F_frameInfo_t info;\n            size_t           consumed_size = header_size;\n            LZ4F_errorCode_t ret           = LZ4F_getFrameInfo(stream->dctx, &info, stream->header, &consumed_size);\n            if (LZ4F_isError(ret))\n                return -1;\n\n            switch (info.blockSizeID) {\n            case LZ4F_default:\n            case LZ4F_max64KB:\n                stream->buffer_maxn = 64 * 1024;\n                break;\n            case LZ4F_max256KB:\n                stream->buffer_maxn = 256 * 1024;\n                break;\n            case LZ4F_max1MB:\n                stream->buffer_maxn = 1 * 1024 * 1024;\n                break;\n            case LZ4F_max4MB:\n                stream->buffer_maxn = 4 * 1024 * 1024;\n                break;\n            default:\n                return -1;\n            }\n\n            stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn);\n            tb_assert_and_check_return_val(stream->buffer, -1);\n\n            stream->buffer_size = header_size - consumed_size;\n            tb_memcpy(stream->buffer, stream->header + consumed_size, stream->buffer_size);\n        }\n    }\n    tb_check_return_val(stream->header_size == header_size && isize, 0);\n    tb_assert_and_check_return_val(stream->buffer && stream->buffer_size + isize <= stream->buffer_maxn, -1);\n\n    // append the input data\n    tb_memcpy(stream->buffer + stream->buffer_size, idata, isize);\n    stream->buffer_size += isize;\n    return isize;\n}\n\nstatic __tb_inline__ tb_long_t xm_lz4_dstream_read(xm_lz4_dstream_t *stream, tb_byte_t *odata, tb_size_t osize) {\n    tb_assert_and_check_return_val(stream && stream->dctx && stream->buffer && odata && osize, -1);\n    tb_check_return_val(stream->buffer_size, 0);\n\n    // do decompress\n    size_t    srcsize = stream->buffer_size;\n    size_t    dstsize = osize;\n    tb_size_t ret     = LZ4F_decompress(stream->dctx, odata, &dstsize, stream->buffer, &srcsize, tb_null);\n    if (LZ4F_isError(ret))\n        return -1;\n\n    // move the left input data\n    if (srcsize < stream->buffer_size)\n        tb_memmov(stream->buffer, stream->buffer + srcsize, stream->buffer_size - srcsize);\n    stream->buffer_size -= srcsize;\n    return dstsize;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/os/access.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        access.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"access\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_access(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const* path = luaL_checkstring(lua, 1);\n    tb_char_t const* mode_str = luaL_checkstring(lua, 2);\n    tb_check_return_val(path && mode_str, 0);\n\n    // parse mode\n    tb_size_t mode = 0;\n    while (*mode_str) {\n        switch (*mode_str) {\n        case 'r': mode |= TB_FILE_MODE_RO; break;\n        case 'w': mode |= TB_FILE_MODE_WO; break;\n        case 'x': mode |= TB_FILE_MODE_EXEC; break;\n        default: break;\n        }\n        mode_str++;\n    }\n\n    // os.access(path, mode)\n    lua_pushboolean(lua, tb_file_access(path, mode));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/args.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        args.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"os.args\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t tb_os_args_append(\n    tb_string_ref_t result, tb_char_t const *cstr, tb_size_t size, tb_bool_t escape, tb_bool_t nowrap) {\n    tb_assert_and_check_return(size < TB_PATH_MAXN);\n\n    // need wrap quote?\n    tb_char_t ch;\n    tb_char_t const *p = cstr;\n    tb_bool_t wrap_quote = tb_false;\n    if (!nowrap) {\n        while ((ch = *p)) {\n            if (ch == ' ') {\n                wrap_quote = tb_true;\n            }\n            p++;\n        }\n    }\n\n    // wrap begin quote\n    if (wrap_quote) {\n        tb_string_chrcat(result, '\\\"');\n    }\n\n    // escape characters\n    p = cstr;\n    while ((ch = *p)) {\n        // escape '\"' or '\\\\'\n        if (ch == '\\\"' || ((escape || wrap_quote) && ch == '\\\\')) {\n            tb_string_chrcat(result, '\\\\');\n        }\n        tb_string_chrcat(result, ch);\n        p++;\n    }\n\n    // wrap end quote\n    if (wrap_quote) {\n        tb_string_chrcat(result, '\\\"');\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n// os.args({\"xx\", \"yy\"}, {escape = true})\ntb_int_t xm_os_args(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // escape '\\\\' characters in global?\n    tb_bool_t escape = tb_false;\n    if (lua_istable(lua, 2)) {\n        // is escape?\n        lua_pushstring(lua, \"escape\");\n        lua_gettable(lua, 2);\n        escape = lua_toboolean(lua, -1);\n        lua_pop(lua, 1);\n    }\n\n    // disable to wrap quote characters in global?\n    tb_bool_t nowrap = tb_false;\n    if (lua_istable(lua, 2)) {\n        // is nowrap?\n        lua_pushstring(lua, \"nowrap\");\n        lua_gettable(lua, 2);\n        nowrap = lua_toboolean(lua, -1);\n        lua_pop(lua, 1);\n    }\n\n    // init result\n    tb_string_t result;\n    tb_string_init(&result);\n\n    // make string from arguments list\n    if (lua_istable(lua, 1)) {\n        tb_size_t i = 0;\n        tb_size_t n = (tb_size_t)lua_objlen(lua, 1);\n        for (i = 1; i <= n; i++) {\n            // add space\n            if (i != 1) {\n                tb_string_chrcat(&result, ' ');\n            }\n\n            // add argument\n            lua_pushnumber(lua, (tb_int_t)i);\n            lua_rawget(lua, 1);\n            if (lua_istable(lua, -1)) { // is path instance?\n                lua_pushstring(lua, \"_STR\");\n                lua_gettable(lua, -2);\n                size_t size = 0;\n                tb_char_t const *cstr = luaL_checklstring(lua, -1, &size);\n                if (cstr && size) {\n                    tb_os_args_append(&result, cstr, size, escape, nowrap);\n                }\n                lua_pop(lua, 1);\n            } else {\n                size_t size = 0;\n                tb_char_t const *cstr = luaL_checklstring(lua, -1, &size);\n                if (cstr && size) {\n                    tb_os_args_append(&result, cstr, size, escape, nowrap);\n                }\n            }\n            lua_pop(lua, 1);\n        }\n    } else {\n        size_t size = 0;\n        tb_char_t const *cstr = luaL_checklstring(lua, 1, &size);\n        if (cstr && size) {\n            tb_os_args_append(&result, cstr, size, escape, nowrap);\n        }\n    }\n\n    // return result\n    tb_size_t size = tb_string_size(&result);\n    if (size) {\n        lua_pushlstring(lua, tb_string_cstr(&result), size);\n    } else {\n        lua_pushliteral(lua, \"\");\n    }\n    tb_string_exit(&result);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/argv.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        argv.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"os.argv\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_argv(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the argument string\n    tb_char_t const *args = luaL_checkstring(lua, 1);\n    tb_check_return_val(args, 0);\n\n    // split only? do not escape\n    tb_bool_t splitonly = tb_false;\n    if (lua_istable(lua, 2)) {\n        lua_pushstring(lua, \"splitonly\");\n        lua_gettable(lua, 2);\n        splitonly = lua_toboolean(lua, -1);\n        lua_pop(lua, 1);\n    }\n\n    // parse argument list\n    tb_string_t arg;\n    do {\n        // init table\n        lua_newtable(lua);\n\n        // init arg\n        if (!tb_string_init(&arg)) {\n            break;\n        }\n\n        // parse command to the arguments\n        tb_int_t i = 1;\n        tb_int_t skip = 0;\n        tb_int_t escape = 0;\n        tb_char_t quote = 0;\n        tb_char_t ch = 0;\n        tb_char_t const *p = args;\n        while ((ch = *p)) {\n            // no escape now?\n            if (!escape) {\n                // enter quote?\n                if (!quote && (ch == '\\\"' || ch == '\\'')) {\n                    quote = ch;\n                    skip  = 1;\n                } else if (ch == quote) { // leave quote?\n                    quote = 0;\n                    skip  = 1;\n                } else if (ch == '\\\\' && (p[1] == '\\\\' || p[1] == '\\\"')) { // escape character? only escape \\\\ and \\\"\n                    escape = 1;\n                    skip   = 1;\n                } else if (!quote && tb_isspace(ch)) { // is argument end with ' '?\n                    // save this argument\n                    tb_string_ltrim(&arg);\n                    if (tb_string_size(&arg)) {\n                        // save argument\n                        lua_pushstring(lua, tb_string_cstr(&arg));\n                        lua_rawseti(lua, -2, i++);\n                    }\n\n                    // clear argument\n                    tb_string_clear(&arg);\n                }\n            }\n\n            // save this charactor to argument\n            if (splitonly || !skip) {\n                tb_string_chrcat(&arg, ch);\n            }\n\n            // step and cancel escape\n            if (escape == 1) {\n                escape++;\n            } else if (escape == 2) {\n                escape = 0;\n            }\n\n            // clear skip\n            skip = 0;\n\n            // next\n            p++;\n        }\n\n        // save this argument\n        tb_string_ltrim(&arg);\n        if (tb_string_size(&arg)) {\n            // save argument\n            lua_pushstring(lua, tb_string_cstr(&arg));\n            lua_rawseti(lua, -2, i++);\n        }\n\n    } while (0);\n\n    // exit arg\n    tb_string_exit(&arg);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/chdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        chdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"chdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_chdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // done os.chdir(path)\n    lua_pushboolean(lua, tb_directory_current_set(path));\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/cpdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        cpdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"cpdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_cpdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the source and destination\n    tb_char_t const *src = luaL_checkstring(lua, 1);\n    tb_char_t const *dst = luaL_checkstring(lua, 2);\n    tb_check_return_val(src && dst, 0);\n\n    // init copy flags\n    tb_size_t flags      = TB_FILE_COPY_NONE;\n    tb_bool_t is_symlink = lua_toboolean(lua, 3);\n    if (is_symlink) {\n        flags |= TB_FILE_COPY_LINK;\n    }\n\n    tb_bool_t copy_if_different = lua_toboolean(lua, 4);\n    if (copy_if_different) {\n        flags |= TB_FILE_COPY_IF_DIFFERENT;\n    }\n\n    // do copy\n    lua_pushboolean(lua, tb_directory_copy(src, dst, flags));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/cpfile.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        cpfile.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"cpfile\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_cpfile(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the source and destination\n    tb_char_t const *src = luaL_checkstring(lua, 1);\n    tb_char_t const *dst = luaL_checkstring(lua, 2);\n    tb_check_return_val(src && dst, 0);\n\n    // init copy flags\n    tb_size_t flags      = TB_FILE_COPY_NONE;\n    tb_bool_t is_symlink = lua_toboolean(lua, 3);\n    if (is_symlink) {\n        flags |= TB_FILE_COPY_LINK;\n    }\n\n    tb_bool_t is_writeable = lua_toboolean(lua, 4);\n    if (is_writeable) {\n        flags |= TB_FILE_COPY_WRITEABLE;\n    }\n\n    tb_bool_t copy_if_different = lua_toboolean(lua, 5);\n    if (copy_if_different) {\n        flags |= TB_FILE_COPY_IF_DIFFERENT;\n    }\n\n    // do copy\n    lua_pushboolean(lua, tb_file_copy(src, dst, flags));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/cpuinfo.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        cpuinfo.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"cpuinfo\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_MACOSX)\n#include <sys/sysctl.h>\n#include <sys/types.h>\n#include <mach/mach.h>\n#include <mach/processor_info.h>\n#include <mach/mach_host.h>\n#elif defined(TB_CONFIG_OS_WINDOWS)\n#include <windows.h>\n#elif defined(TB_CONFIG_OS_LINUX)\n#include <stdio.h>\n#elif defined(TB_CONFIG_OS_BSD)\n#include <stdio.h>\n#include <string.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <unistd.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n#if defined(TB_CONFIG_OS_WINDOWS)\nstatic tb_uint64_t xm_os_cpuinfo_subtract_times(FILETIME const *one, FILETIME const *two) {\n    LARGE_INTEGER a, b;\n    a.LowPart  = one->dwLowDateTime;\n    a.HighPart = one->dwHighDateTime;\n\n    b.LowPart  = two->dwLowDateTime;\n    b.HighPart = two->dwHighDateTime;\n\n    return (tb_uint64_t)(a.QuadPart - b.QuadPart);\n}\n#endif\n\nstatic tb_float_t xm_os_cpuinfo_usagerate() {\n#if defined(TB_CONFIG_OS_MACOSX)\n    tb_float_t usagerate = 0;\n    natural_t cpu_count = 0;\n    processor_info_array_t cpuinfo;\n    mach_msg_type_number_t cpuinfo_count;\n    static tb_hong_t s_time = 0;\n    if (tb_mclock() - s_time > 1000 &&\n        host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, &cpuinfo, &cpuinfo_count) ==\n            KERN_SUCCESS) {\n        static processor_info_array_t s_cpuinfo_prev = tb_null;\n        static mach_msg_type_number_t s_cpuinfo_count_prev = 0;\n        for (tb_int_t i = 0; i < cpu_count; ++i) {\n            tb_int_t use, total;\n            if (s_cpuinfo_prev) {\n                use = (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] -\n                       s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_USER]) +\n                      (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] -\n                       s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM]) +\n                      (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE] -\n                       s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_NICE]);\n                total = use + (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] -\n                               s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);\n            } else {\n                use = cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] +\n                      cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];\n                total = use + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];\n            }\n            usagerate += total > 0 ? ((tb_float_t)use / (tb_float_t)total) : 0;\n        }\n        if (s_cpuinfo_prev) {\n            vm_deallocate(mach_task_self(), (vm_address_t)s_cpuinfo_prev, sizeof(integer_t) * s_cpuinfo_count_prev);\n        }\n        s_time = tb_mclock();\n        s_cpuinfo_prev = cpuinfo;\n        s_cpuinfo_count_prev = cpuinfo_count;\n    }\n    return cpu_count > 0 ? usagerate / cpu_count : 0;\n#elif defined(TB_CONFIG_OS_WINDOWS)\n    // kernel include idle_time\n    tb_float_t usagerate = 0;\n    FILETIME idle, kernel, user;\n    if (GetSystemTimes(&idle, &kernel, &user)) {\n        static FILETIME idle_prev = { 0 };\n        static FILETIME kernel_prev = { 0 };\n        static FILETIME user_prev = { 0 };\n\n        if (idle_prev.dwLowDateTime != 0 && idle_prev.dwHighDateTime != 0) {\n            tb_uint64_t idle_diff = xm_os_cpuinfo_subtract_times(&idle, &idle_prev);\n            tb_uint64_t kernel_diff = xm_os_cpuinfo_subtract_times(&kernel, &kernel_prev);\n            tb_uint64_t user_diff = xm_os_cpuinfo_subtract_times(&user, &user_prev);\n\n            // kernel_time - idle_time = kernel_time, because kernel include idle_time\n            tb_uint64_t sys_total = kernel_diff + user_diff;\n            tb_uint64_t kernel_total = kernel_diff - idle_diff;\n\n            // sometimes kernel_time > idle_time\n            if (sys_total > 0) {\n                usagerate = (tb_float_t)((tb_double_t)(kernel_total + user_diff) / sys_total);\n            }\n        }\n\n        idle_prev = idle;\n        kernel_prev = kernel;\n        user_prev   = user;\n    }\n    return usagerate;\n#elif defined(TB_CONFIG_OS_LINUX)\n    tb_float_t usagerate = 0;\n    if (tb_file_info(\"/proc/stat\", tb_null)) {\n        FILE *fp = fopen(\"/proc/stat\", \"r\");\n        if (fp) {\n            tb_char_t line[8192];\n            static tb_int64_t total_prev = 0;\n            static tb_int64_t active_prev = 0;\n            while (!feof(fp)) {\n                /* cpu  548760 0 867417 102226682 12430 0 9089 0 0 0\n                 * cpu0 136863 0 218110 25632388 2706 0 2328 0 0 0\n                 * cpu1 148383 0 213941 25627686 3925 0 2129 0 0 0\n                 *\n                 * The meanings of the columns are as follows, from left to right:\n                 *\n                 * user: normal processes executing in user mode\n                 * nice: niced processes executing in user mode\n                 * system: processes executing in kernel mode\n                 * idle: twiddling thumbs\n                 * iowait: waiting for I/O to complete\n                 * irq: servicing interrupts\n                 * softirq: servicing softirqs\n                 * steal\n                 * guest\n                 * guest_nice\n                 */\n                if (fgets(line, sizeof(line), fp) && !tb_strncmp(line, \"cpu \", 4)) {\n                    long long user, nice, sys, idle, iowait, irq, softirq, steal, guest, guest_nice;\n                    if (10 == sscanf(line,\n                                     \"cpu  %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\",\n                                     &user,\n                                     &nice,\n                                     &sys,\n                                     &idle,\n                                     &iowait,\n                                     &irq,\n                                     &softirq,\n                                     &steal,\n                                     &guest,\n                                     &guest_nice)) {\n                        tb_int64_t active = (tb_int64_t)(user + nice + sys + irq + softirq + steal + guest +\n                                                         guest_nice);\n                        tb_int64_t total = (tb_int64_t)(user + nice + sys + idle + iowait + irq + softirq + steal +\n                                                        guest + guest_nice);\n                        if (total_prev > 0 && active_prev > 0) {\n                            tb_int64_t total_diff = total - total_prev;\n                            tb_int64_t active_diff = active - active_prev;\n                            if (total_diff > 0) {\n                                usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff);\n                            }\n                        }\n                        total_prev  = total;\n                        active_prev = active;\n                    }\n                    break;\n                }\n            }\n            fclose(fp);\n        }\n    }\n    return usagerate;\n#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__)\n#define CP_USER 0\n#define CP_NICE 1\n#define CP_SYS 2\n#define CP_INTR 3\n#define CP_IDLE 4\n#define CPUSTATES 5\n\n    static tb_int64_t total_prev = 0;\n    static tb_int64_t active_prev = 0;\n\n    tb_float_t usagerate = 0;\n    long states[CPUSTATES] = { 0 };\n    size_t states_size = sizeof(states);\n    if (sysctlbyname(\"kern.cp_time\", &states, &states_size, tb_null, 0) == 0) {\n        tb_long_t user = states[CP_USER];\n        tb_long_t nice = states[CP_NICE];\n        tb_long_t sys = states[CP_SYS];\n        tb_long_t intr = states[CP_INTR];\n        tb_long_t idle = states[CP_IDLE];\n\n        tb_int64_t active = user + nice + sys + intr;\n        tb_int64_t total = user + nice + sys + idle + intr;\n        if (total_prev > 0 && active_prev > 0) {\n            tb_int64_t total_diff = total - total_prev;\n            tb_int64_t active_diff = active - active_prev;\n            if (total_diff > 0) {\n                usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff);\n            }\n        }\n        total_prev = total;\n        active_prev = active;\n    }\n    return usagerate;\n#else\n    return 0;\n#endif\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* local cpuinfo = os.cpuinfo()\n * {\n *      ncpu = 4,\n *      ...\n * }\n */\ntb_int_t xm_os_cpuinfo(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // init table\n    lua_newtable(lua);\n\n    // get cpu number\n    tb_int_t ncpu = (tb_int_t)tb_cpu_count();\n    lua_pushstring(lua, \"ncpu\");\n    lua_pushinteger(lua, ncpu > 0 ? ncpu : 1);\n    lua_settable(lua, -3);\n\n    // get cpu usage rate\n    tb_float_t usagerate = xm_os_cpuinfo_usagerate();\n    if (usagerate >= 0) {\n        lua_pushstring(lua, \"usagerate\");\n        lua_pushnumber(lua, usagerate);\n        lua_settable(lua, -3);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/curdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        curdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"curdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_curdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // os.curdir()\n    tb_char_t path[TB_PATH_MAXN];\n    if (tb_directory_current(path, sizeof(path))) {\n        lua_pushstring(lua, path);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/emptydir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        emptydir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"emptydir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_long_t xm_os_emptydir_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {\n    tb_bool_t *is_emptydir = (tb_bool_t *)priv;\n    tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END);\n\n    // is emptydir?\n    if (info->type == TB_FILE_TYPE_FILE || info->type == TB_FILE_TYPE_DIRECTORY) {\n        *is_emptydir = tb_false;\n        return tb_false;\n    }\n    return TB_DIRECTORY_WALK_CODE_CONTINUE;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_emptydir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the directory\n    tb_char_t const *dir = luaL_checkstring(lua, 1);\n    tb_check_return_val(dir, 0);\n\n    // os.emptydir(dir)\n    tb_bool_t is_emptydir = tb_true;\n    tb_directory_walk(dir, tb_true, tb_true, xm_os_emptydir_walk, &is_emptydir);\n\n    // is emptydir?\n    lua_pushboolean(lua, is_emptydir);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/exists.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        exists.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"exists\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_exists(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // os.exists(path)\n    lua_pushboolean(lua, tb_file_info(path, tb_null));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/filesize.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        filesize.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"filesize\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_filesize(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // os.filesize(path)\n    tb_file_info_t info = { 0 };\n    if (tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE)) {\n        lua_pushinteger(lua, (lua_Integer)info.size);\n    } else {\n        lua_pushinteger(lua, 0);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/find.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        find.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"find\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_long_t xm_os_find_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {\n    tb_value_ref_t tuple = (tb_value_ref_t)priv;\n    tb_assert_and_check_return_val(path && info && tuple, TB_DIRECTORY_WALK_CODE_END);\n\n    // the lua\n    lua_State *lua = (lua_State *)tuple[0].ptr;\n    tb_assert_and_check_return_val(lua, TB_DIRECTORY_WALK_CODE_END);\n\n    // the pattern\n    tb_char_t const *pattern = (tb_char_t const *)tuple[1].cstr;\n    tb_assert_and_check_return_val(pattern, TB_DIRECTORY_WALK_CODE_END);\n\n    // remove ./ for path\n    if (path[0] == '.' && (path[1] == '/' || path[1] == '\\\\')) {\n        path = path + 2;\n    }\n\n    // the match mode\n    tb_long_t mode = tuple[2].l;\n\n    // the count\n    tb_size_t *pcount = &(tuple[3].ul);\n\n    tb_trace_d(\"path[%c]: %s\", info->type == TB_FILE_TYPE_DIRECTORY ? 'd' : 'f', path);\n\n    // we can ignore it directly if this path is file, but we need directory\n    tb_size_t needtype = (mode == 1) ? TB_FILE_TYPE_DIRECTORY\n                                     : ((mode == 0) ? TB_FILE_TYPE_FILE : (TB_FILE_TYPE_FILE | TB_FILE_TYPE_DIRECTORY));\n    if (info->type == TB_FILE_TYPE_FILE && needtype == TB_FILE_TYPE_DIRECTORY) {\n        return TB_DIRECTORY_WALK_CODE_CONTINUE;\n    }\n\n    // do path:match(pattern)\n    lua_getfield(lua, -1, \"match\");\n    lua_pushstring(lua, path);\n    lua_pushstring(lua, pattern);\n    if (lua_pcall(lua, 2, 1, 0)) {\n        tb_printf(\"error: call string.match(%s, %s) failed: %s!\\n\", path, pattern, lua_tostring(lua, -1));\n        return TB_DIRECTORY_WALK_CODE_END;\n    }\n\n    // match ok?\n    tb_bool_t matched        = tb_false;\n    tb_bool_t skip_recursion = tb_false;\n    if (lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1))) {\n        // exists excludes?\n        tb_bool_t excluded = tb_false;\n        if (lua_istable(lua, 5)) {\n            // the root directory\n            size_t rootlen = 0;\n            tb_char_t const *rootdir = luaL_checklstring(lua, 1, &rootlen);\n            tb_assert_and_check_return_val(rootdir && rootlen, TB_DIRECTORY_WALK_CODE_END);\n\n            tb_assert(!tb_strncmp(path, rootdir, rootlen));\n            tb_assert(rootlen + 1 <= tb_strlen(path));\n\n            // skip the rootdir if not \".\"\n            if (tb_strcmp(rootdir, \".\")) {\n                path += rootlen + 1;\n            }\n\n            // exclude paths\n            tb_int_t i = 0;\n            tb_int_t count = (tb_int_t)lua_objlen(lua, 5);\n            for (i = 0; i < count && !excluded; i++) {\n                // get exclude\n                lua_rawgeti(lua, 5, i + 1);\n                tb_char_t const *exclude = lua_tostring(lua, -1);\n                if (exclude) {\n                    // do path:match(exclude)\n                    lua_getfield(lua, -3, \"match\");\n                    lua_pushstring(lua, path);\n                    lua_pushstring(lua, exclude);\n                    if (lua_pcall(lua, 2, 1, 0)) {\n                        tb_printf(\"error: call string.match(%s, %s) failed: %s!\\n\",\n                                  path,\n                                  exclude,\n                                  lua_tostring(lua, -1));\n                    }\n\n                    // matched?\n                    excluded = lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1));\n\n                    // pop the match result\n                    lua_pop(lua, 1);\n                }\n\n                // pop exclude\n                lua_pop(lua, 1);\n            }\n        }\n\n        // does not exclude this path?\n        if (!excluded) {\n            // match file or directory?\n            if (info->type & needtype) {\n                // save it\n                lua_rawseti(lua, -3, (tb_int_t)(++*pcount));\n\n                // do callback function\n                if (lua_isfunction(lua, 6)) {\n                    // do callback(path, isdir)\n                    lua_pushvalue(lua, 6);\n                    lua_pushstring(lua, path);\n                    lua_pushboolean(lua, info->type == TB_FILE_TYPE_DIRECTORY);\n                    lua_call(lua, 2, 1);\n\n                    // is continue?\n                    tb_bool_t is_continue = lua_toboolean(lua, -1);\n                    lua_pop(lua, 1);\n                    if (!is_continue) {\n                        return TB_DIRECTORY_WALK_CODE_END;\n                    }\n                }\n                matched = tb_true;\n            }\n        }\n        // we do not recurse sub-directories if this path has been excluded and it's directory\n        else {\n            skip_recursion = tb_true;\n        }\n    }\n    if (!matched) {\n        lua_pop(lua, 1);\n    }\n    return skip_recursion ? TB_DIRECTORY_WALK_CODE_SKIP_RECURSION : TB_DIRECTORY_WALK_CODE_CONTINUE;\n}\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_find(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the root directory\n    tb_char_t const *rootdir = luaL_checkstring(lua, 1);\n    tb_check_return_val(rootdir, 0);\n\n    // get the pattern\n    tb_char_t const *pattern = luaL_checkstring(lua, 2);\n    tb_check_return_val(pattern, 0);\n\n    // the recursion level\n    tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3);\n\n    // the match mode\n    tb_long_t mode = (tb_long_t)lua_tointeger(lua, 4);\n\n    // init table\n    lua_newtable(lua);\n\n    // get string package\n    lua_getglobal(lua, \"string\");\n\n    // do os.find(root, name)\n    tb_value_t tuple[4];\n    tuple[0].ptr  = lua;\n    tuple[1].cstr = pattern;\n    tuple[2].l    = mode;\n    tuple[3].ul   = 0;\n    tb_directory_walk(rootdir, recursion, tb_true, xm_os_find_walk, tuple);\n\n    // pop string package\n    lua_pop(lua, 1);\n\n    // return count\n    lua_pushinteger(lua, tuple[3].ul);\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/os/fscase.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        fscase.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"fscase\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_fscase(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 174\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    lua_pushinteger(lua, (tb_int_t)tb_file_fscase(path));\n#else\n    lua_pushinteger(lua, -1);\n#endif\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/getenv.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        getenv.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"getenv\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// the separator\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#define XM_OS_ENV_SEP ';'\n#else\n#define XM_OS_ENV_SEP ':'\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_getenv(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the name\n    tb_char_t const *name = luaL_checkstring(lua, 1);\n    tb_check_return_val(name, 0);\n\n    // init values\n    tb_string_t values;\n    if (!tb_string_init(&values)) {\n        return 0;\n    }\n\n    // init environment\n    tb_environment_ref_t environment = tb_environment_init();\n    if (environment) {\n        // load variable\n        if (tb_environment_load(environment, name)) {\n            // make values\n            tb_bool_t is_first = tb_true;\n            tb_for_all_if(tb_char_t const *, value, environment, value) {\n                // append separator\n                if (!is_first) {\n                    tb_string_chrcat(&values, XM_OS_ENV_SEP);\n                } else {\n                    is_first = tb_false;\n                }\n\n                // append value\n                tb_string_cstrcat(&values, value);\n            }\n        }\n\n        // exit environment\n        tb_environment_exit(environment);\n    }\n\n    // save result\n    if (tb_string_size(&values)) {\n        lua_pushstring(lua, tb_string_cstr(&values));\n    } else {\n        lua_pushnil(lua);\n    }\n\n    // exit values\n    tb_string_exit(&values);\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/getenvs.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        getenvs.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"getenvs\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#include <windows.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// the separator\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#define XM_OS_ENV_SEP ';'\n#else\n#define XM_OS_ENV_SEP ':'\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\n\n// the user environment\n#if !defined(TB_CONFIG_OS_WINDOWS) || defined(TB_COMPILER_LIKE_UNIX)\nextern tb_char_t **environ;\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nstatic tb_void_t xm_os_getenvs_trim(tb_char_t const **sstr, tb_char_t const **estr) {\n    tb_assert(sstr && estr && *sstr && *estr);\n\n    tb_char_t const *p = *sstr;\n    tb_char_t const *e = *estr;\n\n    // trim left\n    while (p < e && tb_isspace(*p)) {\n        p++;\n    }\n\n    // trim right\n    while (e > p && tb_isspace(*(e - 1))) {\n        e--;\n    }\n\n    // save trimmed string\n    *sstr = p;\n    *estr = e;\n}\n\nstatic tb_void_t xm_os_getenvs_process_line(lua_State *lua, tb_char_t const *line) {\n    tb_assert_and_check_return(lua && line);\n\n    tb_size_t n = tb_strlen(line);\n    tb_check_return(n > 0);\n\n    // find '=' separator\n    tb_char_t const *p = tb_strchr(line, '=');\n    tb_check_return(p);\n\n    // get key and value parts\n    tb_char_t const *key_start   = line;\n    tb_char_t const *key_end     = p;\n    tb_char_t const *value_start = p + 1;\n    tb_char_t const *value_end   = line + n;\n\n    // trim key\n    xm_os_getenvs_trim(&key_start, &key_end);\n    if (key_start >= key_end) {\n        return;\n    }\n\n    // trim value\n    xm_os_getenvs_trim(&value_start, &value_end);\n\n    // get key and value lengths\n    tb_size_t key_len = key_end - key_start;\n    tb_size_t value_len = value_end > value_start ? value_end - value_start : 0;\n\n    // handle Windows-specific PATH conversion\n    tb_char_t const *final_key_start = key_start;\n    tb_size_t final_key_len = key_len;\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    if (key_len == 4 && tb_strnicmp(key_start, \"path\", 4) == 0) {\n        // use \"PATH\" instead of \"path\"\n        static tb_char_t const PATH_UPPER[] = \"PATH\";\n        final_key_start                     = PATH_UPPER;\n        final_key_len                       = 4;\n    }\n#endif\n\n    // set key-value pair in Lua table using pushlstring to avoid length limits\n    lua_pushlstring(lua, final_key_start, final_key_len);\n    lua_pushlstring(lua, value_start, value_len);\n    lua_rawset(lua, -3);\n}\n\ntb_int_t xm_os_getenvs(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // init table\n    lua_newtable(lua);\n\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    tb_wchar_t const *p = (tb_wchar_t const *)GetEnvironmentStringsW();\n    if (p) {\n        tb_char_t *data = tb_null;\n        tb_size_t maxn = 0;\n        tb_char_t line[TB_PATH_MAXN];\n        tb_size_t n = 0;\n        while (*p) {\n            n = tb_wcslen(p);\n            if (n + 1 < tb_arrayn(line)) {\n                if (tb_wtoa(line, p, tb_arrayn(line)) >= 0) {\n                    xm_os_getenvs_process_line(lua, line);\n                }\n            } else {\n                if (!data) {\n                    maxn = n + 1;\n                    data = (tb_char_t *)tb_malloc(maxn);\n                } else if (n >= maxn) {\n                    maxn = n + TB_PATH_MAXN + 1;\n                    data = (tb_char_t *)tb_ralloc(data, maxn);\n                }\n                tb_assert_and_check_break(data);\n\n                if (tb_wtoa(data, p, maxn) >= 0) {\n                    xm_os_getenvs_process_line(lua, data);\n                }\n            }\n            p += n + 1;\n        }\n        if (data && data != line) {\n            tb_free(data);\n        }\n        data = tb_null;\n    }\n#else\n    tb_char_t const **p = (tb_char_t const **)environ;\n    if (p) {\n        while (*p) {\n            xm_os_getenvs_process_line(lua, *p);\n            p++;\n        }\n    }\n#endif\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/getown.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        getown.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"getown\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifndef TB_CONFIG_OS_WINDOWS\n#include <unistd.h>\n#include <sys/stat.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n#ifndef TB_CONFIG_OS_WINDOWS\n\n// get owner by a given path\ntb_int_t xm_os_getown(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the pathname\n    tb_char_t const *pathname = luaL_checkstring(lua, 1);\n    tb_check_return_val(pathname, 0);\n\n    // get stat\n    struct stat sts;\n    if (stat(pathname, &sts) != 0) {\n        return 0;\n    }\n\n    // push\n    lua_newtable(lua);\n    lua_pushstring(lua, \"uid\");\n    lua_pushinteger(lua, sts.st_uid);\n    lua_settable(lua, -3);\n    lua_pushstring(lua, \"gid\");\n    lua_pushinteger(lua, sts.st_gid);\n    lua_settable(lua, -3);\n\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/os/getpid.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        getpid.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"getpid\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <windows.h>\n#else\n#include <unistd.h>\n#include <errno.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_getpid(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n    lua_pushinteger(lua, (tb_int_t)GetCurrentProcessId());\n#else\n    lua_pushinteger(lua, (tb_int_t)getpid());\n#endif\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/getwinsize.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        getwinsize.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"getwinsize\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#include <windows.h>\n#else\n#include <sys/ioctl.h>\n#include <errno.h>  // for errno\n#include <unistd.h> // for STDOUT_FILENO\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// get console window size\ntb_int_t xm_os_getwinsize(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // init default window size (we will not consider winsize limit if cannot get it)\n    tb_int_t w = TB_MAXS16, h = TB_MAXS16;\n\n    // get winsize\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n    CONSOLE_SCREEN_BUFFER_INFO csbi;\n    if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {\n        w = (tb_int_t)csbi.dwSize.X;\n        h = (tb_int_t)csbi.dwSize.Y;\n    }\n#elif defined(TB_CONFIG_OS_SOLARIS)\n    // Solaris doesn't support winsize/TIOCGWINSZ, use default values\n#else\n    struct winsize size;\n    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) {\n        w = (tb_int_t)size.ws_col;\n        h = (tb_int_t)size.ws_row;\n    }\n#endif\n\n    /* local winsize = os.getwinsize()\n     *\n     * return\n     * {\n     *      width = -1 or ..\n     * ,    height = -1 or ..\n     * }\n     */\n    lua_newtable(lua);\n    lua_pushstring(lua, \"width\");\n    lua_pushinteger(lua, w);\n    lua_settable(lua, -3);\n    lua_pushstring(lua, \"height\");\n    lua_pushinteger(lua, h);\n    lua_settable(lua, -3);\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/gid.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        gid.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"gid\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifndef TB_CONFIG_OS_WINDOWS\n#include <unistd.h>\n#include <errno.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n#ifndef TB_CONFIG_OS_WINDOWS\n\n// get & set gid\ntb_int_t xm_os_gid(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_int_t rgidset = -1;\n    tb_int_t egidset = -1;\n    tb_int_t argc    = lua_gettop(lua);\n    if (argc == 1) {\n        if (lua_istable(lua, 1)) {\n            // os.gid({[\"rgid\"] = rgid, [\"egid\"] = egid})\n            lua_getfield(lua, 1, \"rgid\");\n            lua_getfield(lua, 1, \"egid\");\n            if (!lua_isnil(lua, -1)) {\n                if (!lua_isnumber(lua, -1)) {\n                    lua_pushfstring(lua, \"invalid field type(%s) in `egid` for os.gid\", luaL_typename(lua, -1));\n                    lua_error(lua);\n                    return 0;\n                }\n                egidset = (tb_int_t)lua_tonumber(lua, -1);\n            }\n            lua_pop(lua, 1);\n            if (!lua_isnil(lua, -1)) {\n                if (!lua_isnumber(lua, -1)) {\n                    lua_pushfstring(lua, \"invalid field type(%s) in `rgid` for os.gid\", luaL_typename(lua, -1));\n                    lua_error(lua);\n                    return 0;\n                }\n                rgidset = (tb_int_t)lua_tonumber(lua, -1);\n            }\n            lua_pop(lua, 1);\n        } else if (lua_isnumber(lua, 1)) {\n            // os.gid(gid)\n            rgidset = egidset = (tb_int_t)lua_tonumber(lua, 1);\n        } else {\n            lua_pushfstring(lua, \"invalid argument type(%s) for os.gid\", luaL_typename(lua, 1));\n            lua_error(lua);\n            return 0;\n        }\n    } else if (argc == 2) {\n        // os.gid(rgid, egid)\n        if (!lua_isnil(lua, 1)) {\n            if (!lua_isnumber(lua, 1)) {\n                lua_pushfstring(lua, \"invalid argument type(%s) for os.gid\", luaL_typename(lua, 1));\n                lua_error(lua);\n                return 0;\n            }\n            rgidset = (tb_int_t)lua_tonumber(lua, 1);\n        }\n        if (!lua_isnil(lua, 2)) {\n            if (!lua_isnumber(lua, 2)) {\n                lua_pushfstring(lua, \"invalid argument type(%s) for os.gid\", luaL_typename(lua, 2));\n                lua_error(lua);\n                return 0;\n            }\n            egidset = (tb_int_t)lua_tonumber(lua, 2);\n        }\n    } else if (argc != 0) {\n        lua_pushstring(lua, \"invalid argument count for os.gid\");\n        lua_error(lua);\n        return 0;\n    }\n\n    // store return value\n    lua_newtable(lua);\n\n    if (rgidset != -1 || egidset != -1) {\n        // set rgid & egid\n        lua_pushstring(lua, \"errno\");\n        lua_pushinteger(lua, setregid(rgidset, egidset) != 0 ? errno : 0);\n        lua_settable(lua, -3);\n    }\n\n    // get gid & egid\n    gid_t gid  = getgid();\n    gid_t egid = getegid();\n\n    // push\n    lua_pushstring(lua, \"rgid\");\n    lua_pushinteger(lua, gid);\n    lua_settable(lua, -3);\n    lua_pushstring(lua, \"egid\");\n    lua_pushinteger(lua, egid);\n    lua_settable(lua, -3);\n\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/os/isdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        isdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"isdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_isdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // is directory?\n    tb_file_info_t info = { 0 };\n    lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_DIRECTORY));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/isfile.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        isfile.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"isfile\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_isfile(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // is file?\n    tb_file_info_t info = { 0 };\n    lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/islink.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        islink.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"islink\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_islink(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // is link?\n    tb_file_info_t info = { 0 };\n    lua_pushboolean(lua, tb_file_info(path, &info) && (info.flags & TB_FILE_FLAG_LINK));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/link.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        link.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"link\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_link(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the source and destination\n    tb_char_t const *src = luaL_checkstring(lua, 1);\n    tb_char_t const *dst = luaL_checkstring(lua, 2);\n    tb_check_return_val(src && dst, 0);\n\n    // do os.link(src, dst)\n    lua_pushboolean(lua, tb_file_link(src, dst));\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/mclock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mclock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"mclock\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// os.mclock()\ntb_int_t xm_os_mclock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // save result\n    lua_pushnumber(lua, (lua_Number)tb_mclock());\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/meminfo.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        meminfo.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"meminfo\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_MACOSX)\n#include <mach/mach.h>\n#include <mach/machine.h>\n#include <mach/vm_statistics.h>\n#include <mach-o/dyld.h>\n#include <mach-o/nlist.h>\n#include <AvailabilityMacros.h>\n#elif defined(TB_CONFIG_OS_LINUX)\n#include <stdio.h>\n#include <sys/sysinfo.h>\n#elif defined(TB_CONFIG_OS_WINDOWS)\n#include <windows.h>\n#elif defined(TB_CONFIG_OS_BSD)\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n#ifdef TB_CONFIG_OS_LINUX\nstatic tb_int64_t xm_os_meminfo_get_value(tb_char_t const *buffer, tb_char_t const *name) {\n    tb_char_t const *p = tb_strstr(buffer, name);\n    return p ? tb_stoi64(p + tb_strlen(name)) : 0;\n}\n#endif\n\n// get the used memory size (MB)\nstatic tb_bool_t xm_os_meminfo_stats(tb_int_t *ptotalsize, tb_int_t *pavailsize) {\n#if defined(TB_CONFIG_OS_MACOSX)\n    vm_statistics64_data_t vmstat;\n    mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;\n    if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)&vmstat, &count) == KERN_SUCCESS) {\n        tb_int_t pagesize = (tb_int_t)tb_page_size();\n        tb_int64_t totalsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count + vmstat.active_count +\n                                            vmstat.wire_count\n#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070\n                                            + vmstat.compressor_page_count\n#endif\n                                            ) *\n                               pagesize;\n        /*\n         * NB: speculative pages are already accounted for in \"free_count\",\n         * so \"speculative_count\" is the number of \"free\" pages that are\n         * used to hold data that was read speculatively from disk but\n         * haven't actually been used by anyone so far.\n         *\n         */\n        tb_int64_t availsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count - vmstat.speculative_count) *\n                               pagesize;\n        *ptotalsize = (tb_int_t)(totalsize / (1024 * 1024));\n        *pavailsize = (tb_int_t)(availsize / (1024 * 1024));\n        return tb_true;\n    }\n#elif defined(TB_CONFIG_OS_LINUX)\n    /* we get meminfo from /proc/meminfo\n     *\n     * @see https://github.com/rfjakob/earlyoom/blob/cba1d599e4a7484c45ac017aa7702ff879f15846/meminfo.c#L52\n     */\n    if (tb_file_info(\"/proc/meminfo\", tb_null)) {\n        tb_bool_t ok = tb_false;\n        FILE     *fp = fopen(\"/proc/meminfo\", \"r\");\n        if (fp) {\n            // 8192 should be enough for the foreseeable future.\n            tb_char_t buffer[8192];\n            size_t len = fread(buffer, 1, sizeof(buffer) - 1, fp);\n            if (!ferror(fp) && len) {\n                tb_int64_t totalsize = xm_os_meminfo_get_value(buffer, \"MemTotal:\");\n                tb_int64_t availsize = xm_os_meminfo_get_value(buffer, \"MemAvailable:\");\n                if (availsize <= 0) {\n                    tb_int64_t cachesize = xm_os_meminfo_get_value(buffer, \"Cached:\");\n                    tb_int64_t freesize = xm_os_meminfo_get_value(buffer, \"MemFree:\");\n                    tb_int64_t buffersize = xm_os_meminfo_get_value(buffer, \"Buffers:\");\n                    tb_int64_t shmemsize = xm_os_meminfo_get_value(buffer, \"Shmem:\");\n                    if (cachesize >= 0 && freesize >= 0 && buffersize >= 0 && shmemsize >= 0) {\n                        availsize = freesize + buffersize + cachesize - shmemsize;\n                    }\n                }\n                if (totalsize > 0 && availsize >= 0) {\n                    *ptotalsize = (tb_int_t)(totalsize / 1024);\n                    *pavailsize = (tb_int_t)(availsize / 1024);\n                    ok = tb_true;\n                }\n            }\n            fclose(fp);\n        }\n        return ok;\n    } else {\n        struct sysinfo info = { 0 };\n        if (sysinfo(&info) == 0) {\n            *ptotalsize = (tb_int_t)(info.totalram / (1024 * 1024));\n            *pavailsize = (tb_int_t)((info.freeram + info.bufferram /* + cache size */) / (1024 * 1024));\n            return tb_true;\n        }\n    }\n#elif defined(TB_CONFIG_OS_WINDOWS)\n    MEMORYSTATUSEX statex;\n    statex.dwLength = sizeof(statex);\n    if (GlobalMemoryStatusEx(&statex)) {\n        *ptotalsize = (tb_int_t)(statex.ullTotalPhys / (1024 * 1024));\n        *pavailsize = (tb_int_t)(statex.ullAvailPhys / (1024 * 1024));\n        return tb_true;\n    }\n#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__)\n    unsigned long totalsize;\n    size_t size = sizeof(totalsize);\n    if (sysctlbyname(\"hw.physmem\", &totalsize, &size, tb_null, 0) != 0) {\n        return tb_false;\n    }\n\n    // http://web.mit.edu/freebsd/head/usr.bin/systat/vmstat.c\n    tb_uint32_t v_free_count;\n    size = sizeof(v_free_count);\n    if (sysctlbyname(\"vm.stats.vm.v_free_count\", &v_free_count, &size, tb_null, 0) != 0) {\n        return tb_false;\n    }\n\n    tb_uint32_t v_inactive_count;\n    size = sizeof(v_inactive_count);\n    if (sysctlbyname(\"vm.stats.vm.v_inactive_count\", &v_inactive_count, &size, tb_null, 0) != 0) {\n        return tb_false;\n    }\n\n    *ptotalsize = (tb_int_t)(totalsize / (1024 * 1024));\n    *pavailsize = (tb_int_t)(((tb_int64_t)(v_free_count + v_inactive_count) * tb_page_size()) / (1024 * 1024));\n    return tb_true;\n#endif\n    return tb_false;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_meminfo(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // init table\n    lua_newtable(lua);\n\n    // get the pagesize (bytes)\n    tb_int_t pagesize = (tb_int_t)tb_page_size();\n    lua_pushstring(lua, \"pagesize\");\n    lua_pushinteger(lua, pagesize);\n    lua_settable(lua, -3);\n\n    // get the memory size (MB)\n    tb_int_t availsize = 0;\n    tb_int_t totalsize = 0;\n    if (xm_os_meminfo_stats(&totalsize, &availsize)) {\n        lua_pushstring(lua, \"totalsize\");\n        lua_pushinteger(lua, totalsize);\n        lua_settable(lua, -3);\n\n        lua_pushstring(lua, \"availsize\");\n        lua_pushinteger(lua, availsize);\n        lua_settable(lua, -3);\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/mkdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mkdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"mkdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_mkdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // os.mkdir(path)\n    tb_file_info_t info = { 0 };\n    if (!tb_file_info(path, &info) || (info.type != TB_FILE_TYPE_DIRECTORY)) {\n        lua_pushboolean(lua, tb_directory_create(path));\n    } else {\n        lua_pushboolean(lua, tb_true);\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/mtime.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mtime.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"mtime\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_mtime(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // os.mtime(path)\n    tb_file_info_t info = { 0 };\n    if (tb_file_info(path, &info)) {\n        lua_pushinteger(lua, (lua_Integer)info.mtime);\n    } else {\n        lua_pushinteger(lua, 0);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_OS_PREFIX_H\n#define XM_OS_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/os/processes.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        processes.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"processes\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <windows.h>\n#include <tlhelp32.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_winos_processes(lua_State* lua) {\n#ifdef TB_CONFIG_OS_WINDOWS\n    // init result table\n    lua_newtable(lua);\n\n    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\n    if (hSnapshot != INVALID_HANDLE_VALUE) {\n        PROCESSENTRY32W pe32;\n        pe32.dwSize = sizeof(PROCESSENTRY32W);\n\n        if (Process32FirstW(hSnapshot, &pe32)) {\n            tb_int_t i = 1;\n            do {\n                // new process entry table\n                lua_newtable(lua);\n\n                // name\n                tb_char_t name[MAX_PATH * 4];\n                tb_size_t size = tb_wtoa(name, pe32.szExeFile, sizeof(name));\n                if (size != -1) {\n                    lua_pushlstring(lua, name, size);\n                } else {\n                    lua_pushstring(lua, \"\");\n                }\n                lua_setfield(lua, -2, \"name\");\n\n                // pid\n                lua_pushinteger(lua, (tb_int_t)pe32.th32ProcessID);\n                lua_setfield(lua, -2, \"pid\");\n\n                // ppid\n                lua_pushinteger(lua, (tb_int_t)pe32.th32ParentProcessID);\n                lua_setfield(lua, -2, \"parent_pid\");\n\n                // result[i++] = entry\n                lua_rawseti(lua, -2, i++);\n\n            } while (Process32NextW(hSnapshot, &pe32));\n        }\n        CloseHandle(hSnapshot);\n    }\n    return 1;\n#else\n    return 0;\n#endif\n}\n"
  },
  {
    "path": "core/src/xmake/os/readlink.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        readlink.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readlink\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifndef TB_CONFIG_OS_WINDOWS\n#include <unistd.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_readlink(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // is link?\n#if defined(TB_CONFIG_OS_WINDOWS)\n    lua_pushnil(lua);\n#else\n    tb_char_t srcpath[TB_PATH_MAXN];\n    tb_long_t size = readlink(path, srcpath, TB_PATH_MAXN);\n    if (size == TB_PATH_MAXN) {\n        tb_size_t maxn = TB_PATH_MAXN * 2;\n        tb_char_t *data = (tb_char_t *)tb_malloc(maxn);\n        if (data) {\n            tb_long_t size = readlink(path, data, maxn);\n            if (size > 0 && size < maxn) {\n                data[size] = '\\0';\n                lua_pushstring(lua, data);\n            } else {\n                lua_pushnil(lua);\n            }\n            tb_free(data);\n        }\n    } else if (size >= 0 && size < TB_PATH_MAXN) {\n        srcpath[size] = '\\0';\n        lua_pushstring(lua, srcpath);\n    } else {\n        lua_pushnil(lua);\n    }\n#endif\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/rename.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rename.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rename\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_rename(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the source and destination\n    tb_char_t const *src = luaL_checkstring(lua, 1);\n    tb_char_t const *dst = luaL_checkstring(lua, 2);\n    tb_check_return_val(src && dst, 0);\n\n    // do rename\n    lua_pushboolean(lua, tb_file_rename(src, dst));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/rmdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rmdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rmdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_long_t xm_os_rmdir_empty(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {\n    tb_bool_t *is_emptydir = (tb_bool_t *)priv;\n    tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END);\n\n    // is emptydir?\n    if (info->type == TB_FILE_TYPE_DIRECTORY || info->type == TB_FILE_TYPE_FILE) {\n        // not emptydir\n        *is_emptydir = tb_false;\n        return TB_DIRECTORY_WALK_CODE_END;\n    }\n    return TB_DIRECTORY_WALK_CODE_CONTINUE;\n}\nstatic tb_long_t xm_os_rmdir_remove(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {\n    tb_assert_and_check_return_val(path, TB_DIRECTORY_WALK_CODE_END);\n\n    // is directory?\n    if (info->type == TB_FILE_TYPE_DIRECTORY) {\n        // is emptydir?\n        tb_bool_t is_emptydir = tb_true;\n        tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir);\n\n        tb_trace_d(\"path: %s, emptydir: %u\", path, is_emptydir);\n\n        // remove empty directory\n        if (is_emptydir) {\n            tb_directory_remove(path);\n        }\n    }\n    return TB_DIRECTORY_WALK_CODE_CONTINUE;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_rmdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // only remove empty directory?\n    tb_bool_t rmempty = lua_toboolean(lua, 2);\n    if (rmempty) {\n        // remove all empty directories\n        tb_directory_walk(path, tb_true, tb_false, xm_os_rmdir_remove, tb_null);\n\n        // remove empty root directory\n        tb_bool_t is_emptydir = tb_true;\n        tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir);\n        if (is_emptydir) {\n            tb_directory_remove(path);\n        }\n\n        tb_trace_d(\"path: %s, emptydir: %u\", path, is_emptydir);\n\n        lua_pushboolean(lua, !tb_file_info(path, tb_null));\n    } else {\n        // os.rmdir(path)\n        lua_pushboolean(lua, tb_directory_remove(path));\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/rmfile.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        rmfile.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"rmfile\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_rmfile(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // do remove\n    lua_pushboolean(lua, tb_file_remove(path));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/setenv.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        setenv.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"setenv\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n// ok = os.setenv(name, value)\ntb_int_t xm_os_setenv(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the name and value\n    size_t value_size = 0;\n    tb_char_t const *name = luaL_checkstring(lua, 1);\n    tb_char_t const *value = luaL_checklstring(lua, 2, &value_size);\n    tb_check_return_val(name, 0);\n\n    // set it\n    lua_pushboolean(lua, value ? tb_environment_set(name, value) : tb_false);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/signal.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        signal.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"signal\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)\n#include <unistd.h>\n#include <signal.h>\n#elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) ||                     \\\n    defined(TB_CONFIG_OS_HAIKU)\n#include <unistd.h>\n#include <signal.h>\n#endif\n#ifdef TB_CONFIG_OS_BSD\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <signal.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef enum __xm_os_signal_e {\n    XM_OS_SIGINT = 2\n} xm_os_signal_e;\n\ntypedef enum __xm_os_signal_handler_e {\n    XM_OS_SIGFUN = 0,\n    XM_OS_SIGDFL = 1,\n    XM_OS_SIGIGN = 2,\n} xm_os_signal_handler_e;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\nstatic lua_State *g_lua = tb_null;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_os_signal_handler_impl(tb_int_t signo) {\n    // do callback(signo)\n    lua_State *lua = g_lua;\n    if (lua) {\n        tb_char_t name[64] = { 0 };\n        tb_snprintf(name, sizeof(name), \"_SIGNAL_HANDLER_%d\", signo);\n        lua_getglobal(lua, name);\n        lua_pushinteger(lua, signo);\n        lua_call(lua, 1, 0);\n    }\n}\n\n#if defined(TB_CONFIG_OS_WINDOWS)\nstatic BOOL WINAPI xm_os_signal_handler(DWORD ctrl_type) {\n    if (ctrl_type == CTRL_C_EVENT) {\n        xm_os_signal_handler_impl(XM_OS_SIGINT);\n    }\n    return TRUE;\n}\n#elif defined(SIGINT)\nstatic tb_void_t xm_os_signal_handler(tb_int_t signo_native) {\n    tb_int_t signo = -1;\n    switch (signo_native) {\n    case SIGINT:\n        signo = XM_OS_SIGINT;\n        break;\n    default:\n        break;\n    }\n    if (signo >= 0) {\n        xm_os_signal_handler_impl(signo);\n    }\n}\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_signal(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n    g_lua            = lua;\n    tb_int_t handler = XM_OS_SIGFUN;\n\n    // check signal handler\n    if (lua_isnumber(lua, 2)) {\n        handler = (tb_int_t)luaL_checkinteger(lua, 2);\n    } else if (!lua_isfunction(lua, 2)) {\n        return 0;\n    }\n\n    // save signal handler\n    tb_int_t signo = (tb_int_t)luaL_checkinteger(lua, 1);\n    if (handler == XM_OS_SIGFUN) {\n        tb_char_t name[64] = { 0 };\n        tb_snprintf(name, sizeof(name), \"_SIGNAL_HANDLER_%d\", signo);\n        lua_pushvalue(lua, 2);\n        lua_setglobal(lua, name);\n    }\n\n#if defined(TB_CONFIG_OS_WINDOWS)\n    if (signo != XM_OS_SIGINT) {\n        return 0;\n    }\n\n    switch (handler) {\n    case XM_OS_SIGFUN:\n        SetConsoleCtrlHandler(xm_os_signal_handler, TRUE);\n        break;\n    case XM_OS_SIGDFL:\n        SetConsoleCtrlHandler(NULL, FALSE);\n        break;\n    case XM_OS_SIGIGN:\n        SetConsoleCtrlHandler(NULL, TRUE);\n        break;\n    default:\n        break;\n    }\n#elif defined(SIGINT)\n    switch (signo) {\n    case XM_OS_SIGINT:\n        signo = SIGINT;\n        break;\n    default:\n        return 0;\n    }\n\n    switch (handler) {\n    case XM_OS_SIGFUN:\n        signal(signo, xm_os_signal_handler);\n        break;\n    case XM_OS_SIGDFL:\n        signal(signo, SIG_DFL);\n        break;\n    case XM_OS_SIGIGN:\n        signal(signo, SIG_IGN);\n        break;\n    default:\n        break;\n    }\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/os/sleep.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sleep.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"sleep\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_sleep(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n    tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1);\n    if (interval >= 0) {\n        tb_msleep(interval);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/os/strerror.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        strerror.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"strerror\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n#include <windows.h>\n#else\n#include <errno.h>\n#include <string.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_strerror(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get syserror state\n    tb_size_t syserror = tb_syserror_state();\n    if (syserror != TB_STATE_SYSERROR_UNKNOWN_ERROR) {\n        tb_char_t const *strerr = \"Unknown\";\n        switch (syserror) {\n        case TB_STATE_SYSERROR_NOT_PERM:\n            strerr = \"Permission denied\";\n            break;\n#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173\n        case TB_STATE_SYSERROR_NOT_ACCESS:\n            strerr = \"Not access because it is busy\";\n            break;\n#endif\n        case TB_STATE_SYSERROR_NOT_FILEDIR:\n            strerr = \"No such file or directory\";\n            break;\n        default:\n            break;\n        }\n        lua_pushstring(lua, strerr);\n    } else {\n#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)\n        tb_char_t strerr[128] = { 0 };\n        tb_snprintf(strerr, sizeof(strerr), \"Unknown Error (%lu)\", (tb_size_t)GetLastError());\n        lua_pushstring(lua, strerr);\n#else\n        lua_pushstring(lua, strerror(errno));\n#endif\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/syserror.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        syserror.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"syserror\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_syserror(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get syserror state\n    tb_int_t err = 0;\n    tb_size_t syserror = tb_syserror_state();\n    switch (syserror) {\n    case TB_STATE_SYSERROR_NOT_PERM:\n        err = 1;\n        break;\n    case TB_STATE_SYSERROR_NOT_FILEDIR:\n        err = 2;\n        break;\n#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173\n    case TB_STATE_SYSERROR_NOT_ACCESS:\n        err = 3;\n        break;\n#endif\n    case TB_STATE_SYSERROR_UNKNOWN_ERROR:\n        err = -1;\n        break;\n    }\n    lua_pushinteger(lua, err);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/tmpdir.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        tmpdir.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"tmpdir\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_tmpdir(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // os.tmpdir()\n    tb_char_t path[TB_PATH_MAXN];\n    if (tb_directory_temporary(path, sizeof(path))) {\n        lua_pushstring(lua, path);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/touch.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        touch.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"touch\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_os_touch(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    tb_time_t atime = (tb_time_t)luaL_checknumber(lua, 2);\n    tb_time_t mtime = (tb_time_t)luaL_checknumber(lua, 3);\n\n    lua_pushboolean(lua, tb_file_touch(path, atime, mtime));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/os/uid.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        uid.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"uid\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifndef TB_CONFIG_OS_WINDOWS\n#include <unistd.h>\n#include <errno.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n#ifndef TB_CONFIG_OS_WINDOWS\n\n// get & set uid\ntb_int_t xm_os_uid(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_int_t ruidset = -1;\n    tb_int_t euidset = -1;\n    tb_int_t argc    = lua_gettop(lua);\n    if (argc == 1) {\n        if (lua_istable(lua, 1)) {\n            // os.uid({[\"ruid\"] = ruid, [\"euid\"] = euid})\n            lua_getfield(lua, 1, \"ruid\");\n            lua_getfield(lua, 1, \"euid\");\n            if (!lua_isnil(lua, -1)) {\n                if (!lua_isnumber(lua, -1)) {\n                    lua_pushfstring(lua, \"invalid field type(%s) in `euid` for os.uid\", luaL_typename(lua, -1));\n                    lua_error(lua);\n                    return 0;\n                }\n                euidset = (tb_int_t)lua_tonumber(lua, -1);\n            }\n            lua_pop(lua, 1);\n            if (!lua_isnil(lua, -1)) {\n                if (!lua_isnumber(lua, -1)) {\n                    lua_pushfstring(lua, \"invalid field type(%s) in `ruid` for os.uid\", luaL_typename(lua, -1));\n                    lua_error(lua);\n                    return 0;\n                }\n                ruidset = (tb_int_t)lua_tonumber(lua, -1);\n            }\n            lua_pop(lua, 1);\n        } else if (lua_isnumber(lua, 1)) {\n            // os.uid(uid)\n            ruidset = euidset = (tb_int_t)lua_tonumber(lua, 1);\n        } else {\n            lua_pushfstring(lua, \"invalid argument type(%s) for os.uid\", luaL_typename(lua, 1));\n            lua_error(lua);\n            return 0;\n        }\n    } else if (argc == 2) {\n        // os.uid(ruid, euid)\n        if (!lua_isnil(lua, 1)) {\n            if (!lua_isnumber(lua, 1)) {\n                lua_pushfstring(lua, \"invalid argument type(%s) for os.uid\", luaL_typename(lua, 1));\n                lua_error(lua);\n                return 0;\n            }\n            ruidset = (tb_int_t)lua_tonumber(lua, 1);\n        }\n        if (!lua_isnil(lua, 2)) {\n            if (!lua_isnumber(lua, 2)) {\n                lua_pushfstring(lua, \"invalid argument type(%s) for os.uid\", luaL_typename(lua, 2));\n                lua_error(lua);\n                return 0;\n            }\n            euidset = (tb_int_t)lua_tonumber(lua, 2);\n        }\n    } else if (argc != 0) {\n        lua_pushstring(lua, \"invalid argument count for os.uid\");\n        lua_error(lua);\n        return 0;\n    }\n\n    // store return value\n    lua_newtable(lua);\n\n    if (ruidset != -1 || euidset != -1) {\n        // set ruid & euid\n        lua_pushstring(lua, \"errno\");\n        lua_pushinteger(lua, setreuid(ruidset, euidset) != 0 ? errno : 0);\n        lua_settable(lua, -3);\n    }\n\n    // get uid & euid\n    uid_t uid  = getuid();\n    uid_t euid = geteuid();\n\n    // push\n    lua_pushstring(lua, \"ruid\");\n    lua_pushinteger(lua, uid);\n    lua_settable(lua, -3);\n    lua_pushstring(lua, \"euid\");\n    lua_pushinteger(lua, euid);\n    lua_settable(lua, -3);\n\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/package/loadxmi.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        loadxmi.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"loadxmi\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef USE_LUAJIT\n#define XMI_USE_LUAJIT\n#endif\n#include \"xmi.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef int (*xm_setup_func_t)(xmi_lua_ops_t *ops);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_package_loadxmi(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    tb_char_t const *name = luaL_checkstring(lua, 2);\n    tb_check_return_val(name, 0);\n\n    // load module library\n    tb_dynamic_ref_t lib = tb_dynamic_init(path);\n    if (!lib) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"load %s failed\", path);\n        return 2;\n    }\n\n    // get xmiopen_xxx function\n    lua_CFunction luaopen_func = (lua_CFunction)tb_dynamic_func(lib, name);\n    if (!luaopen_func) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"cannot get symbol %s failed\", name);\n        return 2;\n    }\n\n    // get xmisetup function\n    xm_setup_func_t xmisetup_func = (xm_setup_func_t)tb_dynamic_func(lib, \"xmisetup\");\n    if (!xmisetup_func) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"cannot get symbol xmisetup failed\");\n        return 2;\n    }\n\n    // setup lua interfaces\n    static xmi_lua_ops_t s_luaops = { 0 };\n    static tb_bool_t s_luaops_inited = tb_false;\n    if (!s_luaops_inited) {\n        // get functions\n#ifdef XMI_USE_LUAJIT\n        s_luaops._lua_newuserdata = &lua_newuserdata;\n#else\n        s_luaops._lua_getglobal     = &lua_getglobal;\n        s_luaops._lua_geti          = &lua_geti;\n        s_luaops._lua_rawgetp       = &lua_rawgetp;\n        s_luaops._lua_getiuservalue = &lua_getiuservalue;\n        s_luaops._lua_newuserdatauv = &lua_newuserdatauv;\n#endif\n        s_luaops._lua_gettable     = &lua_gettable;\n        s_luaops._lua_getfield     = &lua_getfield;\n        s_luaops._lua_rawget       = &lua_rawget;\n        s_luaops._lua_rawgeti      = &lua_rawgeti;\n        s_luaops._lua_createtable  = &lua_createtable;\n        s_luaops._lua_getmetatable = &lua_getmetatable;\n\n        // set functions\n#ifndef XMI_USE_LUAJIT\n        s_luaops._lua_setglobal     = &lua_setglobal;\n        s_luaops._lua_seti          = &lua_seti;\n        s_luaops._lua_rawsetp       = &lua_rawsetp;\n        s_luaops._lua_setiuservalue = &lua_setiuservalue;\n#endif\n        s_luaops._lua_settable     = &lua_settable;\n        s_luaops._lua_setfield     = &lua_setfield;\n        s_luaops._lua_rawset       = &lua_rawset;\n        s_luaops._lua_rawseti      = &lua_rawseti;\n        s_luaops._lua_setmetatable = &lua_setmetatable;\n\n        // access functions\n        s_luaops._lua_isnumber    = &lua_isnumber;\n        s_luaops._lua_isstring    = &lua_isstring;\n        s_luaops._lua_iscfunction = &lua_iscfunction;\n        s_luaops._lua_isuserdata  = &lua_isuserdata;\n        s_luaops._lua_type        = &lua_type;\n        s_luaops._lua_typename    = &lua_typename;\n#ifndef XMI_USE_LUAJIT\n        s_luaops._lua_isinteger = &lua_isinteger;\n#endif\n\n        s_luaops._lua_tonumberx   = &lua_tonumberx;\n        s_luaops._lua_tointegerx  = &lua_tointegerx;\n        s_luaops._lua_toboolean   = &lua_toboolean;\n        s_luaops._lua_tolstring   = &lua_tolstring;\n        s_luaops._lua_tocfunction = &lua_tocfunction;\n        s_luaops._lua_touserdata  = &lua_touserdata;\n        s_luaops._lua_tothread    = &lua_tothread;\n        s_luaops._lua_topointer   = &lua_topointer;\n#ifndef XMI_USE_LUAJIT\n        s_luaops._lua_rawlen = &lua_rawlen;\n#endif\n\n        // push functions\n        s_luaops._lua_pushnil           = &lua_pushnil;\n        s_luaops._lua_pushinteger       = &lua_pushinteger;\n        s_luaops._lua_pushboolean       = &lua_pushboolean;\n        s_luaops._lua_pushnumber        = &lua_pushnumber;\n        s_luaops._lua_pushlstring       = &lua_pushlstring;\n        s_luaops._lua_pushstring        = &lua_pushstring;\n        s_luaops._lua_pushvfstring      = &lua_pushvfstring;\n        s_luaops._lua_pushfstring       = &lua_pushfstring;\n        s_luaops._lua_pushcclosure      = &lua_pushcclosure;\n        s_luaops._lua_pushlightuserdata = &lua_pushlightuserdata;\n        s_luaops._lua_pushthread        = &lua_pushthread;\n\n        // stack functions\n#ifdef XMI_USE_LUAJIT\n        s_luaops._lua_insert  = &lua_insert;\n        s_luaops._lua_remove  = &lua_remove;\n        s_luaops._lua_replace = &lua_replace;\n#else\n        s_luaops._lua_absindex = &lua_absindex;\n        s_luaops._lua_rotate   = &lua_rotate;\n#endif\n        s_luaops._lua_gettop     = &lua_gettop;\n        s_luaops._lua_settop     = &lua_settop;\n        s_luaops._lua_pushvalue  = &lua_pushvalue;\n        s_luaops._lua_copy       = &lua_copy;\n        s_luaops._lua_checkstack = &lua_checkstack;\n        s_luaops._lua_xmove      = &lua_xmove;\n\n        // miscellaneous functions\n        s_luaops._lua_error     = &lua_error;\n        s_luaops._lua_next      = &lua_next;\n        s_luaops._lua_concat    = &lua_concat;\n        s_luaops._lua_getallocf = &lua_getallocf;\n        s_luaops._lua_setallocf = &lua_setallocf;\n#ifndef XMI_USE_LUAJIT\n        s_luaops._lua_len            = &lua_len;\n        s_luaops._lua_toclose        = &lua_toclose;\n        s_luaops._lua_closeslot      = &lua_closeslot;\n        s_luaops._lua_stringtonumber = &lua_stringtonumber;\n#endif\n\n        // 'load' and 'call' functions\n#ifdef XMI_USE_LUAJIT\n        s_luaops._lua_call  = &lua_call;\n        s_luaops._lua_pcall = &lua_pcall;\n#else\n        s_luaops._lua_callk  = &lua_callk;\n        s_luaops._lua_pcallk = &lua_pcallk;\n#endif\n        s_luaops._lua_load = &lua_load;\n        s_luaops._lua_dump = &lua_dump;\n\n        // luaL functions\n#ifndef XMI_USE_LUAJIT\n        s_luaops._luaL_tolstring = &luaL_tolstring;\n        s_luaops._luaL_typeerror = &luaL_typeerror;\n#endif\n        s_luaops._luaL_getmetafield = &luaL_getmetafield;\n        s_luaops._luaL_callmeta     = &luaL_callmeta;\n        s_luaops._luaL_argerror     = &luaL_argerror;\n        s_luaops._luaL_checklstring = &luaL_checklstring;\n        s_luaops._luaL_optlstring   = &luaL_optlstring;\n        s_luaops._luaL_checknumber  = &luaL_checknumber;\n        s_luaops._luaL_optnumber    = &luaL_optnumber;\n        s_luaops._luaL_checkinteger = &luaL_checkinteger;\n        s_luaops._luaL_optinteger   = &luaL_optinteger;\n        s_luaops._luaL_checkstack   = &luaL_checkstack;\n        s_luaops._luaL_checktype    = &luaL_checktype;\n        s_luaops._luaL_checkany     = &luaL_checkany;\n        s_luaops._luaL_newmetatable = &luaL_newmetatable;\n        s_luaops._luaL_testudata    = &luaL_testudata;\n        s_luaops._luaL_checkudata   = &luaL_checkudata;\n        s_luaops._luaL_where        = &luaL_where;\n        s_luaops._luaL_error        = &luaL_error;\n        s_luaops._luaL_checkoption  = &luaL_checkoption;\n        s_luaops._luaL_fileresult   = &luaL_fileresult;\n        s_luaops._luaL_execresult   = &luaL_execresult;\n        s_luaops._luaL_setfuncs     = &luaL_setfuncs;\n        s_luaops._luaL_loadfilex    = &luaL_loadfilex;\n        s_luaops._luaL_loadstring   = &luaL_loadstring;\n\n        s_luaops_inited = tb_true;\n    }\n    xmisetup_func(&s_luaops);\n\n    // load module\n    lua_pushcfunction(lua, luaopen_func);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/package/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_PACKAGE_PREFIX_H\n#define XM_PACKAGE_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/path/absolute.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        absolute.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"absolute\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_path_absolute(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // get the root\n    tb_char_t const *root = luaL_optstring(lua, 2, tb_null);\n\n    // do path:absolute(root)\n    tb_char_t data[TB_PATH_MAXN];\n    lua_pushstring(lua, tb_path_absolute_to(root, path, data, sizeof(data) - 1));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/path/directory.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        directory.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"directory\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_path_directory(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // do path:directory()\n    tb_char_t        data[TB_PATH_MAXN];\n    tb_char_t const *dir = tb_path_directory(path, data, sizeof(data));\n    if (dir) {\n        lua_pushstring(lua, dir);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/path/is_absolute.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        is_absolute.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"is_absolute\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_path_is_absolute(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // path:is_absolute()\n    lua_pushboolean(lua, tb_path_is_absolute(path));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/path/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_PATH_PREFIX_H\n#define XM_PATH_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/path/relative.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        relative.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"relative\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_path_relative(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    tb_char_t const *path = luaL_checkstring(lua, 1);\n    tb_check_return_val(path, 0);\n\n    // get the root\n    tb_char_t const *root = luaL_optstring(lua, 2, tb_null);\n\n    // path:relative(root)\n    tb_char_t data[TB_PATH_MAXN];\n    lua_pushstring(lua, tb_path_relative_to(root, path, data, sizeof(data) - 1));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/path/translate.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        translate.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"translate\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_path_translate(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the path\n    size_t path_size = 0;\n    tb_char_t const *path      = luaL_checklstring(lua, 1, &path_size);\n    tb_check_return_val(path, 0);\n\n    // get the option argument, e.g. {normalize = true}\n    tb_bool_t normalize = tb_false;\n    if (lua_istable(lua, 2)) {\n        lua_pushstring(lua, \"normalize\");\n        lua_gettable(lua, 2);\n        if (lua_toboolean(lua, -1)) {\n            normalize = tb_true;\n        }\n        lua_pop(lua, 1);\n    }\n\n    // do path:translate()\n    tb_char_t data[TB_PATH_MAXN];\n    tb_size_t size = tb_path_translate_to(path, (tb_size_t)path_size, data, sizeof(data), normalize);\n    if (size) {\n        lua_pushlstring(lua, data, (size_t)size);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/prefix/config.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        config.h\n *\n */\n#ifndef XM_PREFIX_CONFIG_H\n#define XM_PREFIX_CONFIG_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../config.h\"\n#include \"tbox/tbox.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n/*! @def __xm_small__\n *\n * small mode\n */\n#if XM_CONFIG_SMALL\n#define __xm_small__\n#endif\n\n/*! @def __xm_debug__\n *\n * debug mode\n */\n#ifdef __tb_debug__\n#define __xm_debug__\n#endif\n\n/* unix/gcc on msys/cygwin? do not support it now!\n *\n * @see https://github.com/xmake-io/xmake/issues/681\n *\n * on msys:\n * pacman -S mingw-w64-i686-gcc\n * pacman -S mingw-w64-x86_64-gcc\n *\n * e.g.\n * $ pacman -S mingw-w64-x86_64-gcc\n * $ which gcc\n * /mingw64/bin/gcc\n * $ cd xmake\n * $ make build\n * $ make install prefix=/mingw64\n */\n#if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_LIKE_UNIX)\n#error \"do not support gcc on msys/cygwin, please uses mingw-w64-[i686|x86_64]-gcc\"\n#endif\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/prefix/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_PREFIX_PREFIX_H\n#define XM_PREFIX_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"config.h\"\n#include \"version.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/prefix/version.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        version.h\n *\n */\n#ifndef XM_PREFIX_VERSION_H\n#define XM_PREFIX_VERSION_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"config.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n/// the major version\n#define XM_VERSION_MAJOR XM_CONFIG_VERSION_MAJOR\n\n/// the minor version\n#define XM_VERSION_MINOR XM_CONFIG_VERSION_MINOR\n\n/// the alter version\n#define XM_VERSION_ALTER XM_CONFIG_VERSION_ALTER\n\n/// the build version\n#ifndef XM_CONFIG_VERSION_BUILD\n#define XM_CONFIG_VERSION_BUILD 0\n#endif\n#define XM_VERSION_BUILD XM_CONFIG_VERSION_BUILD\n\n/// the build version string\n#define XM_VERSION_BUILD_STRING __tb_mstring_ex__(XM_CONFIG_VERSION_BUILD)\n\n/// the version string\n#define XM_VERSION_STRING                                                                                              \\\n    __tb_mstrcat6__(\"xmake_\",                                                                                          \\\n                    __tb_mstring_ex__(__tb_mconcat8_ex__(                                                              \\\n                        v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD)),   \\\n                    \"_\",                                                                                               \\\n                    TB_ARCH_VERSION_STRING,                                                                            \\\n                    \" by \",                                                                                            \\\n                    TB_COMPILER_VERSION_STRING)\n\n/// the short version string\n#define XM_VERSION_SHORT_STRING                                                                                        \\\n    __tb_mstrcat__(\"xmake_\",                                                                                           \\\n                   __tb_mstring_ex__(__tb_mconcat8_ex__(                                                               \\\n                       v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD)))\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_PREFIX_H\n#define XM_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix/prefix.h\"\n#include \"luaconf.h\"\n#if defined(TB_CONFIG_OS_WINDOWS) && defined(__cplusplus)\n#undef LUA_API\n#undef LUALIB_API\n#define LUA_API extern \"C\"\n#define LUALIB_API LUA_API\n#endif\n#ifdef USE_LUAJIT\n#include \"luajit.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n#else\n#include \"lua.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// define lua_Unsigned for luajit/lua5.1\n#if defined(USE_LUAJIT) || LUA_VERSION_NUM < 503\ntypedef size_t                      lua_Unsigned;\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private interfaces\n */\n\n// this issue has been fixed, @see https://github.com/LuaJIT/LuaJIT/commit/e9af1abec542e6f9851ff2368e7f196b6382a44c\n#if 0 //TB_CPU_BIT64\n/* we use this interface instead of lua_pushlightuserdata() to fix bad light userdata pointer bug\n *\n * @see https://github.com/xmake-io/xmake/issues/914\n * https://github.com/LuaJIT/LuaJIT/pull/230\n *\n * @note we cannot lua_newuserdata() because we need pass this pointer to the external lua code\n * in poller_wait()/event_callback, but lua_pushuserdata does not exists\n */\nstatic __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State* lua, tb_pointer_t ptr)\n{\n    tb_uint64_t ptrval = (tb_uint64_t)ptr;\n    if ((ptrval >> 47) == 0)\n        lua_pushlightuserdata(lua, ptr);\n    else\n    {\n        tb_char_t str[64];\n        tb_long_t len = tb_snprintf(str, sizeof(str), \"%p\", ptr);\n        lua_pushlstring(lua, str, len);\n    }\n}\nstatic __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State* lua, tb_int_t idx)\n{\n    return lua_isuserdata(lua, idx) || lua_isstring(lua, idx);\n}\nstatic __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State* lua, tb_int_t idx, tb_char_t const** pstr)\n{\n    tb_pointer_t ptr = tb_null;\n    if (lua_isuserdata(lua, idx))\n    {\n        ptr = lua_touserdata(lua, idx);\n        if (pstr) *pstr = tb_null;\n    }\n    else\n    {\n        size_t len = 0;\n        tb_char_t const* str = luaL_checklstring(lua, idx, &len);\n        if (str && len > 2 && str[0] == '0' && str[1] == 'x')\n            ptr = (tb_pointer_t)tb_s16tou64(str);\n        if (pstr) *pstr = str;\n    }\n    return ptr;\n}\nstatic __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State* lua, tb_int_t idx)\n{\n   return xm_lua_topointer2(lua, idx, tb_null);\n}\n#else\nstatic __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State *lua, tb_pointer_t ptr) {\n    lua_pushlightuserdata(lua, ptr);\n}\nstatic __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State *lua, tb_int_t idx) {\n    return lua_isuserdata(lua, idx);\n}\nstatic __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State *lua, tb_int_t idx, tb_char_t const **pstr) {\n    if (pstr)\n        *pstr = tb_null;\n    return lua_touserdata(lua, idx);\n}\nstatic __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State *lua, tb_int_t idx) {\n    return lua_touserdata(lua, idx);\n}\n#endif\n\nstatic __tb_inline__ tb_void_t xm_lua_register(lua_State *lua, tb_char_t const *libname, luaL_Reg const *l) {\n#if LUA_VERSION_NUM >= 504\n    if (libname) {\n        lua_getglobal(lua, libname);\n        if (lua_isnil(lua, -1)) {\n            lua_pop(lua, 1);\n            lua_newtable(lua);\n        }\n        luaL_setfuncs(lua, l, 0);\n        lua_setglobal(lua, libname);\n    } else {\n        luaL_setfuncs(lua, l, 0);\n    }\n#else\n    luaL_register(lua, libname, l);\n#endif\n}\n\nstatic __tb_inline__ tb_int_t xm_lua_isinteger(lua_State *lua, int idx) {\n#ifdef USE_LUAJIT\n    return lua_isnumber(lua, idx);\n#else\n    return lua_isinteger(lua, idx);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/process/close.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        close.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"process.close\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// process.close(p)\ntb_int_t xm_process_close(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the process\n    tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(process, 0);\n\n    // exit process\n    tb_process_exit(process);\n\n    // save result: ok\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/process/kill.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        kill.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"process.kill\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// process.kill(p)\ntb_int_t xm_process_kill(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get the process\n    tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(process, 0);\n\n    // kill process\n    tb_process_kill(process);\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/process/open.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        open.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"process.open\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../io/prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* p = process.open(command,\n * {outpath = \"\", errpath = \"\", outfile = \"\",\n *  errfile = \"\", outpipe = \"\", errpipe = \"\",\n *  infile = \"\", inpipe = \"\", inpipe = \"\",\n *  envs = {\"PATH=xxx\", \"XXX=yyy\"}})\n */\ntb_int_t xm_process_open(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get command\n    size_t command_size = 0;\n    tb_char_t const *command = luaL_checklstring(lua, 1, &command_size);\n    tb_check_return_val(command, 0);\n\n    // init attributes\n    tb_process_attr_t attr = { 0 };\n\n    // get option arguments\n    tb_size_t envn = 0;\n    tb_char_t const *envs[1024] = { 0 };\n    tb_char_t const *inpath = tb_null;\n    tb_char_t const *outpath = tb_null;\n    tb_char_t const *errpath = tb_null;\n    xm_io_file_t *infile = tb_null;\n    xm_io_file_t *outfile = tb_null;\n    xm_io_file_t *errfile = tb_null;\n    tb_pipe_file_ref_t inpipe = tb_null;\n    tb_pipe_file_ref_t outpipe = tb_null;\n    tb_pipe_file_ref_t errpipe = tb_null;\n    if (lua_istable(lua, 2)) {\n        // is detached?\n        lua_pushstring(lua, \"detach\");\n        lua_gettable(lua, 2);\n        if (lua_toboolean(lua, -1)) {\n            attr.flags |= TB_PROCESS_FLAG_DETACH;\n        }\n        lua_pop(lua, 1);\n\n        // get curdir\n        lua_pushstring(lua, \"curdir\");\n        lua_gettable(lua, 3);\n        attr.curdir = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get inpath\n        lua_pushstring(lua, \"inpath\");\n        lua_gettable(lua, 2);\n        inpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get outpath\n        lua_pushstring(lua, \"outpath\");\n        lua_gettable(lua, 2);\n        outpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get errpath\n        lua_pushstring(lua, \"errpath\");\n        lua_gettable(lua, 2);\n        errpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get infile\n        if (!inpath) {\n            lua_pushstring(lua, \"infile\");\n            lua_gettable(lua, 3);\n            infile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get outfile\n        if (!outpath) {\n            lua_pushstring(lua, \"outfile\");\n            lua_gettable(lua, 3);\n            outfile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get errfile\n        if (!errpath) {\n            lua_pushstring(lua, \"errfile\");\n            lua_gettable(lua, 3);\n            errfile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get inpipe\n        if (!inpath && !infile) {\n            lua_pushstring(lua, \"inpipe\");\n            lua_gettable(lua, 3);\n            inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get outpipe\n        if (!outpath && !outfile) {\n            lua_pushstring(lua, \"outpipe\");\n            lua_gettable(lua, 3);\n            outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get errpipe\n        if (!errpath && !errfile) {\n            lua_pushstring(lua, \"errpipe\");\n            lua_gettable(lua, 3);\n            errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get environments\n        lua_pushstring(lua, \"envs\");\n        lua_gettable(lua, 2);\n        if (lua_istable(lua, -1)) {\n            // get environment variables count\n            tb_size_t count = (tb_size_t)lua_objlen(lua, -1);\n\n            // get all passed environment variables\n            tb_size_t i;\n            for (i = 0; i < count; i++) {\n                // get envs[i]\n                lua_pushinteger(lua, i + 1);\n                lua_gettable(lua, -2);\n\n                // is string?\n                if (lua_isstring(lua, -1)) {\n                    // add this environment value\n                    if (envn + 1 < tb_arrayn(envs)) {\n                        envs[envn++] = lua_tostring(lua, -1);\n                    } else {\n                        // error\n                        lua_pushfstring(lua,\n                                        \"envs is too large(%d > %d) for process.openv\",\n                                        (tb_int_t)envn,\n                                        tb_arrayn(envs) - 1);\n                        lua_error(lua);\n                    }\n                } else {\n                    // error\n                    lua_pushfstring(lua,\n                                    \"invalid envs[%d] type(%s) for process.openv\",\n                                    (tb_int_t)i,\n                                    luaL_typename(lua, -1));\n                    lua_error(lua);\n                }\n\n                // pop it\n                lua_pop(lua, 1);\n            }\n        }\n        lua_pop(lua, 1);\n    }\n\n    // redirect stdin?\n    if (inpath) {\n        // redirect stdin to file\n        attr.in.path = inpath;\n        attr.inmode  = TB_FILE_MODE_RO;\n        attr.intype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (infile && xm_io_file_is_file(infile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.in.file = rawfile;\n            attr.intype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (inpipe) {\n        attr.in.pipe = inpipe;\n        attr.intype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // redirect stdout?\n    if (outpath) {\n        // redirect stdout to file\n        attr.out.path = outpath;\n        attr.outmode  = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;\n        attr.outtype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (outfile && xm_io_file_is_file(outfile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.out.file = rawfile;\n            attr.outtype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (outpipe) {\n        attr.out.pipe = outpipe;\n        attr.outtype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // redirect stderr?\n    if (errpath) {\n        // redirect stderr to file\n        attr.err.path = errpath;\n        attr.errmode  = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;\n        attr.errtype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (errfile && xm_io_file_is_file(errfile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.err.file = rawfile;\n            attr.errtype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (errpipe) {\n        attr.err.pipe = errpipe;\n        attr.errtype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // set the new environments\n    if (envn > 0) {\n        attr.envp = envs;\n    }\n\n    // init process\n    tb_process_ref_t process = (tb_process_ref_t)tb_process_init_cmd(command, &attr);\n    if (process) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)process);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/process/openv.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        openv.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"process.openv\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../io/prefix.h\"\n#if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) ||                        \\\n    defined(TB_CONFIG_OS_HAIKU) || defined(TB_COMPILER_IS_MINGW)\n#include <signal.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* p = process.openv(shellname, argv,\n * {outpath = \"\", errpath = \"\", outfile = \"\",\n *  errfile = \"\", outpipe = \"\", errpipe = \"\",\n *  infile = \"\", inpipe = \"\", inpipe = \"\",\n *  envs = {\"PATH=xxx\", \"XXX=yyy\"}})\n */\ntb_int_t xm_process_openv(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // check argv\n    if (!lua_istable(lua, 2)) {\n        // error\n        lua_pushfstring(lua, \"invalid argv type(%s) for process.openv\", luaL_typename(lua, 2));\n        lua_error(lua);\n        return 0;\n    }\n\n    // get shellname\n    tb_char_t const *shellname = lua_tostring(lua, 1);\n    tb_check_return_val(shellname, 0);\n\n    // get the arguments count\n    tb_long_t argn = (tb_long_t)lua_objlen(lua, 2);\n    tb_check_return_val(argn >= 0, 0);\n\n    // get arguments\n    tb_size_t argi = 0;\n    tb_char_t const **argv = tb_nalloc0_type(1 + argn + 1, tb_char_t const *);\n    tb_check_return_val(argv, 0);\n\n    // fill arguments\n    argv[0] = shellname;\n    for (argi = 0; argi < argn; argi++) {\n        // get argv[i]\n        lua_pushinteger(lua, argi + 1);\n        lua_gettable(lua, 2);\n\n        // is string?\n        if (lua_isstring(lua, -1)) {\n            // pass this argument\n            argv[1 + argi] = lua_tostring(lua, -1);\n        }\n        // is path instance?\n        else if (lua_istable(lua, -1)) {\n            lua_pushstring(lua, \"_STR\");\n            lua_gettable(lua, -2);\n            argv[1 + argi] = lua_tostring(lua, -1);\n            lua_pop(lua, 1);\n        } else {\n            // error\n            lua_pushfstring(lua, \"invalid argv[%d] type(%s) for process.openv\", (tb_int_t)argi, luaL_typename(lua, -1));\n            lua_error(lua);\n        }\n\n        // pop it\n        lua_pop(lua, 1);\n    }\n\n    // init attributes\n    tb_process_attr_t attr = { 0 };\n\n    // get option arguments\n    tb_bool_t exclusive = tb_false;\n    tb_size_t envn = 0;\n    tb_char_t const *envs[1024] = { 0 };\n    tb_char_t const *inpath = tb_null;\n    tb_char_t const *outpath = tb_null;\n    tb_char_t const *errpath = tb_null;\n    xm_io_file_t *infile = tb_null;\n    xm_io_file_t *outfile = tb_null;\n    xm_io_file_t *errfile = tb_null;\n    tb_pipe_file_ref_t inpipe = tb_null;\n    tb_pipe_file_ref_t outpipe = tb_null;\n    tb_pipe_file_ref_t errpipe = tb_null;\n    if (lua_istable(lua, 3)) {\n        // is detached?\n        lua_pushstring(lua, \"detach\");\n        lua_gettable(lua, 3);\n        if (lua_toboolean(lua, -1)) {\n            attr.flags |= TB_PROCESS_FLAG_DETACH;\n        }\n        lua_pop(lua, 1);\n\n        // is exclusive?\n        lua_pushstring(lua, \"exclusive\");\n        lua_gettable(lua, 3);\n        if (lua_toboolean(lua, -1)) {\n            exclusive = tb_true;\n        }\n        lua_pop(lua, 1);\n\n        // get curdir\n        lua_pushstring(lua, \"curdir\");\n        lua_gettable(lua, 3);\n        attr.curdir = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get inpath\n        lua_pushstring(lua, \"inpath\");\n        lua_gettable(lua, 3);\n        inpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get outpath\n        lua_pushstring(lua, \"outpath\");\n        lua_gettable(lua, 3);\n        outpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get errpath\n        lua_pushstring(lua, \"errpath\");\n        lua_gettable(lua, 3);\n        errpath = lua_tostring(lua, -1);\n        lua_pop(lua, 1);\n\n        // get infile\n        if (!inpath) {\n            lua_pushstring(lua, \"infile\");\n            lua_gettable(lua, 3);\n            infile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get outfile\n        if (!outpath) {\n            lua_pushstring(lua, \"outfile\");\n            lua_gettable(lua, 3);\n            outfile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get errfile\n        if (!errpath) {\n            lua_pushstring(lua, \"errfile\");\n            lua_gettable(lua, 3);\n            errfile = (xm_io_file_t *)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get inpipe\n        if (!inpath && !infile) {\n            lua_pushstring(lua, \"inpipe\");\n            lua_gettable(lua, 3);\n            inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get outpipe\n        if (!outpath && !outfile) {\n            lua_pushstring(lua, \"outpipe\");\n            lua_gettable(lua, 3);\n            outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get errpipe\n        if (!errpath && !errfile) {\n            lua_pushstring(lua, \"errpipe\");\n            lua_gettable(lua, 3);\n            errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);\n            lua_pop(lua, 1);\n        }\n\n        // get environments\n        lua_pushstring(lua, \"envs\");\n        lua_gettable(lua, 3);\n        if (lua_istable(lua, -1)) {\n            // get environment variables count\n            tb_size_t count = (tb_size_t)lua_objlen(lua, -1);\n\n            // get all passed environment variables\n            tb_size_t i;\n            for (i = 0; i < count; i++) {\n                // get envs[i]\n                lua_pushinteger(lua, i + 1);\n                lua_gettable(lua, -2);\n\n                // is string?\n                if (lua_isstring(lua, -1)) {\n                    // add this environment value\n                    if (envn + 1 < tb_arrayn(envs)) {\n                        envs[envn++] = lua_tostring(lua, -1);\n                    } else {\n                        // error\n                        lua_pushfstring(lua,\n                                        \"envs is too large(%d > %d) for process.openv\",\n                                        (tb_int_t)envn,\n                                        tb_arrayn(envs) - 1);\n                        lua_error(lua);\n                    }\n                } else {\n                    // error\n                    lua_pushfstring(lua,\n                                    \"invalid envs[%d] type(%s) for process.openv\",\n                                    (tb_int_t)i,\n                                    luaL_typename(lua, -1));\n                    lua_error(lua);\n                }\n\n                // pop it\n                lua_pop(lua, 1);\n            }\n        }\n        lua_pop(lua, 1);\n    }\n\n    // redirect stdin?\n    if (inpath) {\n        // redirect stdin to file\n        attr.in.path = inpath;\n        attr.inmode  = TB_FILE_MODE_RO;\n        attr.intype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (infile && xm_io_file_is_file(infile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.in.file = rawfile;\n            attr.intype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (inpipe) {\n        attr.in.pipe = inpipe;\n        attr.intype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // redirect stdout?\n    if (outpath) {\n        // redirect stdout to file\n        attr.out.path = outpath;\n        attr.outmode  = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;\n        attr.outtype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (outfile && xm_io_file_is_file(outfile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.out.file = rawfile;\n            attr.outtype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (outpipe) {\n        attr.out.pipe = outpipe;\n        attr.outtype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // redirect stderr?\n    if (errpath) {\n        // redirect stderr to file\n        attr.err.path = errpath;\n        attr.errmode  = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;\n        attr.errtype  = TB_PROCESS_REDIRECT_TYPE_FILEPATH;\n    } else if (errfile && xm_io_file_is_file(errfile)) {\n        tb_file_ref_t rawfile = tb_null;\n        if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {\n            attr.err.file = rawfile;\n            attr.errtype  = TB_PROCESS_REDIRECT_TYPE_FILE;\n        }\n    } else if (errpipe) {\n        attr.err.pipe = errpipe;\n        attr.errtype  = TB_PROCESS_REDIRECT_TYPE_PIPE;\n    }\n\n    // set the new environments\n    if (envn > 0) {\n        attr.envp = envs;\n    }\n\n    /* we need to ignore SIGINT and SIGQUIT if we enter exclusive mode\n     * @see https://github.com/xmake-io/xmake/discussions/2893\n     */\n#if defined(SIGINT)\n    if (exclusive) {\n        signal(SIGINT, SIG_IGN);\n    }\n#endif\n#if defined(SIGQUIT)\n    if (exclusive) {\n        signal(SIGQUIT, SIG_IGN);\n    }\n#endif\n\n    // init process\n    tb_process_ref_t process = (tb_process_ref_t)tb_process_init(shellname, argv, &attr);\n    if (process) {\n        xm_lua_pushpointer(lua, (tb_pointer_t)process);\n    } else {\n        lua_pushnil(lua);\n    }\n\n    // exit argv\n    if (argv) {\n        tb_free(argv);\n    }\n    argv = tb_null;\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/process/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_PROCESS_PREFIX_H\n#define XM_PROCESS_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/process/wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"process.wait\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// ok, status = process.wait(proc, timeout)\ntb_int_t xm_process_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        // error\n        lua_pushfstring(lua, \"invalid argument type(%s) for process.wait\", luaL_typename(lua, 1));\n        lua_error(lua);\n        return 0;\n    }\n\n    // get the process\n    tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);\n    tb_check_return_val(process, 0);\n\n    // get the timeout\n    tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2);\n\n    // wait it\n    tb_long_t status = 0;\n    tb_long_t ok     = tb_process_wait(process, &status, timeout);\n\n    // save result\n    lua_pushinteger(lua, ok);\n    lua_pushinteger(lua, status);\n\n    return 2;\n}\n"
  },
  {
    "path": "core/src/xmake/readline/add_history.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        add_history.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"add_history\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n#ifdef XM_CONFIG_API_HAVE_READLINE\n\n// add_history wrapper\ntb_int_t xm_readline_add_history(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get history\n    tb_char_t const *history = luaL_checkstring(lua, 1);\n    tb_check_return_val(history, 0);\n\n    // call add_history\n    add_history(history);\n\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "core/src/xmake/readline/clear_history.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        clear_history.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"clear_history\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n#ifdef XM_CONFIG_API_HAVE_READLINE\n\n// clear_history wrapper\ntb_int_t xm_readline_clear_history(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n#ifdef TB_CONFIG_OS_MACOSX\n    // call clear_history (will crash on macOS)\n    for (tb_int_t i = history_length - 1; i >= 0; --i) {\n        remove_history(i);\n    }\n#else\n    clear_history();\n#endif\n\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/readline/history_list.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        history_list.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"history_list\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n#ifdef XM_CONFIG_API_HAVE_READLINE\n\n// history_list wrapper\ntb_int_t xm_readline_history_list(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // history list\n    lua_newtable(lua);\n\n#ifdef TB_CONFIG_OS_MACOSX\n    for (tb_int_t i = 1; i <= history_length; ++i) {\n        lua_newtable(lua);\n\n        // field line\n        lua_pushstring(lua, \"line\");\n        lua_pushstring(lua, history_get(i)->line);\n        lua_settable(lua, -3);\n\n        // set back\n        lua_rawseti(lua, -2, i);\n    }\n#else\n    tb_int_t i = 1;\n    for (HIST_ENTRY **p = history_list(); *p; ++p, ++i) {\n        lua_newtable(lua);\n\n        // field line\n        lua_pushstring(lua, \"line\");\n        lua_pushstring(lua, (*p)->line);\n        lua_settable(lua, -3);\n\n        // set back\n        lua_rawseti(lua, -2, i);\n    }\n#endif\n\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/readline/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        prefix.h\n *\n */\n#ifndef XM_READLINE_PREFIX_H\n#define XM_READLINE_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n#ifdef XM_CONFIG_API_HAVE_READLINE\n#include <stdio.h> // on some OS (like centos) required\n#include <readline/readline.h>\n#include <readline/history.h>\n#endif\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/readline/readline.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow\n * @file        readline.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"readline\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n#ifdef XM_CONFIG_API_HAVE_READLINE\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// readline wrapper\ntb_int_t xm_readline_readline(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the prompt\n    tb_char_t const *prompt = luaL_optstring(lua, 1, tb_null);\n\n    // call readline\n    tb_char_t *line = readline(prompt);\n    if (line) {\n        // return line\n        lua_pushstring(lua, line);\n\n        // free it\n        tb_free(line);\n    } else {\n        lua_pushnil(lua);\n    }\n\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/sandbox/interactive.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        interactive.c\n *\n */\n\n/* Runs interactive commands, read-eval-print (REPL)\n *\n * Major portions taken verbatim or adapted from LuaJIT frontend and the Lua interpreter.\n * Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h\n * Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"sandbox.interactive\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../winos/ansi.h\"\n#ifdef XM_CONFIG_API_HAVE_READLINE\n#include <readline/history.h>\n#include <readline/readline.h>\n#include <stdlib.h>\n#include <stdio.h> // on some OS (like centos) required\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n// buffer size for prompt\n#define LUA_PROMPT_BUFSIZE 4096\n\n// for lua5.4\n#ifndef LUA_QL\n#define LUA_QL(x) \"'\" x \"'\"\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\n// report results\nstatic tb_void_t xm_sandbox_report(lua_State *lua) {\n    if (!lua_isnil(lua, -1)) {\n        // get message\n        tb_char_t const *msg = lua_tostring(lua, -1);\n        if (!msg) {\n            msg = \"(error object is not a string)\";\n        }\n\n        // print it\n        tb_printl(msg);\n        tb_print_sync();\n\n        // pop this message\n        lua_pop(lua, 1);\n    }\n}\n\n// the traceback function\nstatic tb_int_t xm_sandbox_traceback(lua_State *lua) {\n    if (!lua_isstring(lua, 1)) {\n        // non-string error object? try metamethod.\n        if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, \"__tostring\") || !lua_isstring(lua, -1)) {\n            return 1; // return non-string error object.\n        }\n\n        // replace object by result of __tostring metamethod.\n        lua_remove(lua, 1);\n    }\n\n    // return backtrace\n    luaL_traceback(lua, lua, lua_tostring(lua, 1), 1);\n    return 1;\n}\n\n// execute codes\nstatic tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) {\n    /* get error function index\n     *\n     * stack: arg1(sandbox_scope) scriptfunc(top) -> ...\n     */\n    tb_int_t errfunc = lua_gettop(lua) - narg;\n\n    // push traceback function\n    lua_pushcfunction(lua, xm_sandbox_traceback);\n\n    // put it under chunk and args\n    lua_insert(lua, errfunc);\n\n    /* execute it\n     *\n     * stack: errfunc arg1 scriptfunc -> ...\n     * after: errfunc arg1 [results] -> ...\n     */\n    tb_int_t status = lua_pcall(lua, narg, (clear ? 0 : LUA_MULTRET), errfunc);\n\n    // remove traceback function\n    lua_remove(lua, errfunc);\n\n    // force a complete garbage collection in case of errors\n    if (status != 0) {\n        lua_gc(lua, LUA_GCCOLLECT, 0);\n    }\n\n    return status;\n}\n\n// this line is incomplete?\nstatic tb_int_t xm_sandbox_incomplete(lua_State *lua, tb_int_t status) {\n    // syntax error?\n    if (status == LUA_ERRSYNTAX) {\n        size_t           lmsg;\n        tb_char_t const *msg = lua_tolstring(lua, -1, &lmsg);\n        tb_char_t const *tp  = msg + lmsg - (sizeof(LUA_QL(\"<eof>\")) - 1);\n        if (tb_strstr(msg, LUA_QL(\"<eof>\")) == tp) {\n            lua_pop(lua, 1);\n            return 1;\n        }\n    }\n    return 0;\n}\n// read line\nstatic tb_size_t xm_sandbox_readline(tb_char_t *data, tb_size_t maxn, tb_char_t const *prompt) {\n#ifdef XM_CONFIG_API_HAVE_READLINE\n    // get line\n    tb_char_t const *line = readline(prompt);\n    if (line) {\n        // add line to history\n        add_history(line);\n\n        // copy line to data\n        tb_size_t size = tb_strlcpy(data, line, maxn);\n\n        // free line\n        free((void *)line);\n\n        // truncated?\n        if (size >= maxn) {\n            return 0;\n        }\n\n        return size;\n    }\n#else\n\n    // print prompt\n    tb_printf(prompt);\n    tb_print_sync();\n\n    // get input buffer\n    if (tb_stdfile_gets(tb_stdfile_input(), data, maxn)) {\n        return tb_strlen(data);\n    }\n#endif\n\n    // no more input\n    return 0;\n}\n\n// read and push input line\nstatic tb_int_t xm_sandbox_pushline(lua_State *lua, tb_char_t const *prompt2) {\n    // read line\n    tb_char_t data[LUA_PROMPT_BUFSIZE];\n    tb_size_t size = xm_sandbox_readline(data, sizeof(data), prompt2);\n    if (size) {\n        // split line '\\0'\n        if (data[size - 1] == '\\n') {\n            data[size - 1] = '\\0';\n        }\n\n        // push line\n        lua_pushstring(lua, data);\n\n        return 1;\n    }\n\n    // no input\n    return 0;\n}\n\n// load code line\nstatic tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) {\n    // clear stack\n    lua_settop(lua, top);\n\n    // get prompt strings from arg1(sandbox_scope)\n    lua_pushstring(lua, \"$interactive_prompt\");\n    lua_gettable(lua, 1);\n    tb_char_t const *prompt = lua_tostring(lua, -1);\n    lua_pop(lua, 1);\n\n    lua_pushstring(lua, \"$interactive_prompt2\");\n    lua_gettable(lua, 1);\n    tb_char_t const *prompt2 = lua_tostring(lua, -1);\n    lua_pop(lua, 1);\n\n    // read first line\n    tb_int_t status;\n    tb_char_t data[LUA_PROMPT_BUFSIZE];\n    tb_size_t size = xm_sandbox_readline(data + 7, sizeof(data) - 7, prompt);\n    if (size) {\n        // split line '\\0'\n        if (data[size - 1] == '\\n') {\n            data[--size] = '\\0';\n        }\n\n        // patch \"return \"\n        tb_memcpy(data, \"return \", 7);\n\n        // attempt to load \"return ...\"\n        status = luaL_loadbuffer(lua, data, size + 7, \"=stdin\");\n\n        if (status != LUA_ERRSYNTAX) {\n            return status;\n        }\n\n        // pop error msg\n        lua_pop(lua, 1);\n\n        // push line to load it again\n        lua_pushstring(lua, data + 7);\n    } else\n        return -1;\n\n    // load input line\n    while (1) {\n        /* repeat until gets a complete line\n         *\n         * stack: arg1(sandbox_scope) scriptbuffer(top) -> ...\n         * after: arg1(sandbox_scope) scriptbuffer scriptfunc(top) -> ...\n         */\n        status = luaL_loadbuffer(lua, lua_tostring(lua, -1), (size_t)lua_strlen(lua, -1), \"=stdin\");\n\n        // complete?\n        if (!xm_sandbox_incomplete(lua, status)) {\n            break;\n        }\n\n        // get more input\n        if (!xm_sandbox_pushline(lua, prompt2)) {\n            return -1;\n        }\n\n        // cancel multi-line input?\n        if (!tb_strcmp(lua_tostring(lua, -1), \"q\")) {\n            lua_pop(lua, 2);\n            lua_pushstring(lua, \"return \");\n            continue;\n        }\n\n        /* add a new line\n         *\n         * stack: arg1 scriptbuffer scriptfunc scriptbuffer \"\\n\"(top) -> ...\n         */\n        lua_pushliteral(lua, \"\\n\");\n\n        // between the two lines\n        lua_insert(lua, -2);\n\n        /* join them\n         *\n         * stack: arg1 scriptbuffer scriptfunc scriptbuffer scriptbuffer \"\\n\"(top) -> ...\n         * after: arg1 scriptbuffer scriptfunc scriptbuffer+\"\\n\"(top) -> ...\n         */\n        lua_concat(lua, 3);\n    }\n\n    // remove redundant scriptbuffer\n    lua_remove(lua, -2);\n    return status;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// sandbox.interactive()\ntb_int_t xm_sandbox_interactive(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    /* get init stack top\n     *\n     * stack: arg1(sandbox_scope)\n     */\n    tb_int_t top = lua_gettop(lua);\n\n    // enter interactive\n    tb_int_t status;\n    while ((status = xm_sandbox_loadline(lua, top)) != -1) {\n        // execute codes\n        if (status == 0) {\n            /* bind sandbox\n             *\n             * stack: arg1(top) scriptfunc arg1(sandbox_scope) -> ...\n             */\n#ifdef USE_LUAJIT\n            lua_pushvalue(lua, 1);\n            lua_setfenv(lua, -2);\n#else\n            // stack: arg1(top) scriptfunc $interactive_setfenv scriptfunc arg1(sandbox_scope) -> ...\n            lua_getfield(lua, 1, \"$interactive_setfenv\");\n            lua_pushvalue(lua, -2);\n            lua_pushvalue(lua, 1);\n            if (lua_pcall(lua, 2, 0, 0) != 0) {\n                tb_printl(lua_pushfstring(lua,\n                                          \"error calling \" LUA_QL(\"$interactive_setfenv\") \" (%s)\",\n                                          lua_tostring(lua, -1)));\n            }\n#endif\n\n            /* run script\n             *\n             * stack: arg1(top) scriptfunc -> ...\n             */\n            status = xm_sandbox_docall(lua, 0, 0);\n        }\n\n        // report errors\n        if (status) {\n            xm_sandbox_report(lua);\n        }\n\n        // print any results\n        if (status == 0 && lua_gettop(lua) > top) {\n            // get results count\n            tb_int_t count = lua_gettop(lua) - top;\n\n            /* dump results\n             *\n             * stack: arg1(sandbox_scope) [results] -> ...\n             * after: arg1(sandbox_scope) $interactive_dump [results] -> ...\n             */\n            lua_getfield(lua, 1, \"$interactive_dump\"); // load $interactive_dump() from sandbox_scope\n            lua_insert(lua, -(count + 1));\n            if (lua_pcall(lua, count, 0, 0) != 0) {\n                tb_printl(\n                    lua_pushfstring(lua, \"error calling \" LUA_QL(\"$interactive_dump\") \" (%s)\", lua_tostring(lua, -1)));\n            }\n        }\n    }\n\n    // clear stack\n    lua_settop(lua, top);\n    tb_printl(\"\");\n    tb_print_sync();\n\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/sandbox/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_SANDBOX_PREFIX_H\n#define XM_SANDBOX_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/semver/compare.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        compare.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"compare\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// semver.compare(\"v1.0.1-beta\", \"1.2\") > 0?\ntb_int_t xm_semver_compare(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the version1 string\n    tb_char_t const *version1_str = luaL_checkstring(lua, 1);\n    tb_check_return_val(version1_str, 0);\n\n    // get the version2 string\n    tb_char_t const *version2_str = luaL_checkstring(lua, 2);\n    tb_check_return_val(version2_str, 0);\n\n    // try to parse version1 string\n    semver_t semver1 = { 0 };\n    if (semver_tryn(&semver1, version1_str, tb_strlen(version1_str))) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"unable to parse semver '%s'\", version1_str);\n        return 2;\n    }\n\n    // try to parse version2 string\n    semver_t semver2 = { 0 };\n    if (semver_tryn(&semver2, version2_str, tb_strlen(version2_str))) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"unable to parse semver '%s'\", version2_str);\n        return 2;\n    }\n\n    // do compare\n    lua_pushinteger(lua, semver_pcmp(&semver1, &semver2));\n\n    semver_dtor(&semver1);\n    semver_dtor(&semver2);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/semver/parse.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        parse.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"parse\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* version = semver.parse(\"v1.0.1-beta\")\n *\n *\n    {\n        patch = 1\n    ,   raw = v1.0.1-beta\n    ,   version = v1.0.1-beta\n    ,   major = 1\n    ,   build =\n        {\n        }\n\n    ,   minor = 0\n    ,   prerelease =\n        {\n            beta\n        }\n    }\n *\n */\ntb_int_t xm_semver_parse(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the version string\n    tb_char_t const *version_str = luaL_checkstring(lua, 1);\n    tb_check_return_val(version_str, 0);\n\n    // try to parse version string\n    semver_t semver = { 0 };\n    if (semver_tryn(&semver, version_str, tb_strlen(version_str))) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"unable to parse semver '%s'\", version_str);\n        return 2;\n    }\n\n    lua_pushsemver(lua, &semver);\n    semver_dtor(&semver);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/semver/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        prefix.h\n *\n */\n#ifndef XM_SEMVER_PREFIX_H\n#define XM_SEMVER_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n#include \"semver.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_enter__\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/* push struct semver\n *\n * @param lua       the lua context\n * @param semver    the semver struct\n *\n */\ntb_void_t\nlua_pushsemver(lua_State *lua, semver_t const *semver);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * leave\n */\n__tb_extern_c_leave__\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/semver/satisfies.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        satisfies.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"satisfies\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* satisfies the given version range?\n *\n * semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true\n */\ntb_int_t xm_semver_satisfies(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the version string\n    tb_char_t const *version_str = luaL_checkstring(lua, 1);\n    tb_char_t const *range_str   = luaL_checkstring(lua, 2);\n    tb_assert_and_check_return_val(version_str && range_str, 0);\n\n    // parse the version range string\n    semver_range_t range = { 0 };\n    if (semver_rangen(&range, range_str, tb_strlen(range_str))) {\n        // range is branch name? try to match it\n        semver_t range_semver = { 0 };\n        if (!tb_strcmp(version_str, range_str)) {\n            lua_pushboolean(lua, tb_true);\n            return 1;\n        }\n        // range is a single version? try to compare it\n        else if (!semver_tryn(&range_semver, range_str, tb_strlen(range_str))) {\n            semver_t semver = { 0 };\n            if (!semver_tryn(&semver, version_str, tb_strlen(version_str))) {\n                lua_pushboolean(lua, semver_pcmp(&semver, &range_semver) == 0);\n                semver_dtor(&semver);\n                semver_dtor(&range_semver);\n                return 1;\n            } else {\n                semver_dtor(&range_semver);\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"unable to parse semver '%s'\", version_str);\n                return 2;\n            }\n        } else {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"unable to parse semver range '%s'\", range_str);\n            return 2;\n        }\n    }\n\n    // try to parse the version string\n    semver_t semver = { 0 };\n    if (semver_tryn(&semver, version_str, tb_strlen(version_str))) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"unable to parse semver '%s'\", version_str);\n        return 2;\n    }\n\n    // satisfies this range?\n    lua_pushboolean(lua, semver_range_match(semver, range));\n    semver_dtor(&semver);\n    semver_range_dtor(&range);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/semver/select.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        select.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"select\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_bool_t xm_semver_select_from_versions_tags1(\n    lua_State *lua, tb_int_t fromidx, semver_t *semver, semver_range_t const *range, semvers_t *matches) {\n    // clear matches\n    semvers_pclear(matches);\n\n    // select all matches\n    lua_Integer i = 0;\n    luaL_checktype(lua, fromidx, LUA_TTABLE);\n    for (i = lua_objlen(lua, fromidx); i > 0; --i) {\n        lua_pushinteger(lua, i);\n        lua_gettable(lua, fromidx);\n\n        tb_char_t const *source_str = luaL_checkstring(lua, -1);\n        if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) {\n            if (semver_range_pmatch(semver, range)) {\n                semvers_ppush(matches, *semver);\n            } else {\n                semver_dtor(semver);\n            }\n        }\n        lua_pop(lua, 1);\n    }\n\n    // no matches?\n    tb_check_return_val(matches->length, tb_false);\n\n    // sort matches\n    semvers_psort(matches);\n\n    // get the newest version\n    semver_t top = semvers_ppop(matches);\n    lua_createtable(lua, 0, 2);\n\n    // return results\n    lua_pushstring(lua, top.raw);\n    lua_setfield(lua, -2, \"version\");\n\n    lua_pushstring(lua, fromidx == 2 ? \"version\" : \"tag\");\n    lua_setfield(lua, -2, \"source\");\n\n    // exit the popped semver\n    semver_dtor(&top);\n\n    return tb_true;\n}\nstatic tb_bool_t xm_semver_select_from_versions_tags2(\n    lua_State *lua, tb_int_t fromidx, semver_t *semver, tb_char_t const *version_str, tb_size_t version_len) {\n    lua_Integer i = 0;\n    luaL_checktype(lua, fromidx, LUA_TTABLE);\n    for (i = lua_objlen(lua, fromidx); i > 0; --i) {\n        lua_pushinteger(lua, i);\n        lua_gettable(lua, fromidx);\n\n        tb_char_t const *source_str = luaL_checkstring(lua, -1);\n        tb_size_t source_len = tb_strlen(source_str);\n        lua_pop(lua, 1);\n        if (source_len == version_len && tb_strncmp(source_str, version_str, version_len) == 0) {\n            lua_createtable(lua, 0, 2);\n            lua_pushlstring(lua, source_str, source_len);\n            lua_setfield(lua, -2, \"version\");\n            lua_pushstring(lua, fromidx == 2 ? \"version\" : \"tag\");\n            lua_setfield(lua, -2, \"source\");\n            return tb_true;\n        }\n    }\n    return tb_false;\n}\nstatic tb_bool_t xm_semver_select_from_branches(lua_State       *lua,\n                                                tb_int_t         fromidx,\n                                                tb_char_t const *range_str,\n                                                tb_size_t        range_len) {\n    lua_Integer i = 0;\n    luaL_checktype(lua, fromidx, LUA_TTABLE);\n    for (i = lua_objlen(lua, fromidx); i > 0; --i) {\n        lua_pushinteger(lua, i);\n        lua_gettable(lua, fromidx);\n\n        tb_char_t const *source_str = luaL_checkstring(lua, -1);\n        tb_size_t source_len = tb_strlen(source_str);\n        lua_pop(lua, 1);\n        if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) {\n            lua_createtable(lua, 0, 2);\n            lua_pushlstring(lua, source_str, source_len);\n            lua_setfield(lua, -2, \"version\");\n            lua_pushstring(lua, \"branch\");\n            lua_setfield(lua, -2, \"source\");\n            return tb_true;\n        }\n    }\n    return tb_false;\n}\nstatic tb_bool_t xm_semver_select_latest_from_versions_tags(lua_State *lua,\n                                                            tb_int_t   fromidx,\n                                                            semver_t  *semver,\n                                                            semvers_t *matches) {\n    // clear matches\n    semvers_pclear(matches);\n\n    // push all versions to matches\n    lua_Integer i = 0;\n    luaL_checktype(lua, fromidx, LUA_TTABLE);\n    for (i = lua_objlen(lua, fromidx); i > 0; --i) {\n        lua_pushinteger(lua, i);\n        lua_gettable(lua, fromidx);\n\n        tb_char_t const *source_str = luaL_checkstring(lua, -1);\n        if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) {\n            semvers_ppush(matches, *semver);\n        }\n\n        lua_pop(lua, 1);\n    }\n    tb_check_return_val(matches->length, tb_false);\n\n    // sort matches\n    semvers_psort(matches);\n\n    // get the newest match\n    semver_t top = semvers_ppop(matches);\n    lua_createtable(lua, 0, 2);\n\n    // return results\n    lua_pushstring(lua, top.raw);\n    lua_setfield(lua, -2, \"version\");\n\n    lua_pushstring(lua, fromidx == 2 ? \"version\" : \"tag\");\n    lua_setfield(lua, -2, \"source\");\n\n    semver_dtor(&top);\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* select version\n *\n * local versioninfo, errors = semver.select(\">=1.5.0 <1.6\", {\"1.5.0\", \"1.5.1\"}, {\"v1.5.0\", ..}, {\"latest\", \"dev\"})\n */\ntb_int_t xm_semver_select(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // select version\n    tb_bool_t ok = tb_false;\n    tb_bool_t is_range = tb_false;\n    tb_char_t const *range_str = tb_null;\n    semver_t semver = { 0 };\n    semvers_t matches = { 0 };\n    semver_range_t range = { 0 };\n    do {\n        // get the version range string\n        range_str = luaL_checkstring(lua, 1);\n        tb_check_break(range_str);\n\n        // get the range string length\n        tb_size_t range_len = tb_strlen(range_str);\n\n        // parse the version range string\n        is_range = semver_rangen(&range, range_str, range_len) == 0;\n        if (is_range) {\n            // attempt to select version from the versions list first\n            if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) {\n                ok = tb_true;\n                break;\n            }\n\n            // attempt to select version from the tags list\n            if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) {\n                ok = tb_true;\n                break;\n            }\n        } else {\n            // attempt to select version from the versions list first\n            if (xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) {\n                ok = tb_true;\n                break;\n            }\n\n            // attempt to select version from the tags list\n            if (xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) {\n                ok = tb_true;\n                break;\n            }\n        }\n\n        // attempt to select version from the branches\n        if (xm_semver_select_from_branches(lua, 4, range_str, range_len)) {\n            ok = tb_true;\n            break;\n        }\n\n        // select the latest version from the tags and versions if be latest\n        if (!tb_strcmp(range_str, \"latest\")) {\n            // attempt to select latest version from the versions list\n            if (xm_semver_select_latest_from_versions_tags(lua, 2, &semver, &matches)) {\n                ok = tb_true;\n                break;\n            }\n\n            // attempt to select latest version from the tags list\n            if (xm_semver_select_latest_from_versions_tags(lua, 3, &semver, &matches)) {\n                ok = tb_true;\n                break;\n            }\n        }\n\n    } while (0);\n\n    // exit matches\n    semvers_dtor(matches);\n\n    // exit range\n    semver_range_dtor(&range);\n\n    // failed?\n    if (!ok) {\n        if (!is_range) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"unable to parse semver range '%s'\", range_str);\n        }\n\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"unable to select version for range '%s'\", range_str);\n        return 2;\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/semver/semver.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      uael\n * @file        semver.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"semver\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_void_t lua_pushsemver(lua_State *lua, semver_t const *semver) {\n    tb_assert(lua && semver);\n\n    // return a semver table\n    lua_createtable(lua, 0, 7);\n\n    lua_pushstring(lua, semver->raw);\n    lua_setfield(lua, -2, \"raw\");\n\n    lua_pushlstring(lua, semver->raw, semver->len);\n    lua_setfield(lua, -2, \"version\");\n\n    lua_pushinteger(lua, semver->major);\n    lua_setfield(lua, -2, \"major\");\n\n    lua_pushinteger(lua, semver->minor);\n    lua_setfield(lua, -2, \"minor\");\n\n    lua_pushinteger(lua, semver->patch);\n    lua_setfield(lua, -2, \"patch\");\n\n    // push prelease table\n    lua_pushstring(lua, \"prerelease\");\n    lua_newtable(lua);\n\n    tb_uchar_t i = 0;\n    semver_id_t const *id = &semver->prerelease;\n    while (id && id->len) {\n        if (id->numeric) {\n            lua_pushinteger(lua, id->num);\n        } else {\n            lua_pushlstring(lua, id->raw, id->len);\n        }\n        id = id->next;\n        lua_rawseti(lua, -2, ++i);\n    }\n    lua_settable(lua, -3);\n\n    // push the build table\n    i = 0;\n    lua_pushstring(lua, \"build\");\n    lua_newtable(lua);\n    id = &semver->build;\n    while (id && id->len) {\n        if (id->numeric) {\n            lua_pushinteger(lua, id->num);\n        } else {\n            lua_pushlstring(lua, id->raw, id->len);\n        }\n        id = id->next;\n        lua_rawseti(lua, -2, ++i);\n    }\n    lua_settable(lua, -3);\n}\n"
  },
  {
    "path": "core/src/xmake/string/convert.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        convert.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"convert\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../utils/charset.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* convert string\n *\n * @param str       the string\n * @param ftype     the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32\n * @param ttype     the to-charset type\n *\n * @code\n *      local result = string.convert(str, \"gbk\", \"utf8\")\n *      local result = string.convert(str, \"utf8\", \"gb2312\")\n * @endcode\n */\ntb_int_t xm_string_convert(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the string and charset types\n    size_t           src_size   = 0;\n    tb_char_t const *src_cstr   = luaL_checklstring(lua, 1, &src_size);\n    tb_char_t const *ftype_cstr = luaL_checkstring(lua, 2);\n    tb_char_t const *ttype_cstr = luaL_checkstring(lua, 3);\n    tb_check_return_val(src_cstr && ftype_cstr && ttype_cstr, 0);\n\n    // find charsets\n    xm_charset_entry_ref_t fcharset = xm_charset_find_by_name(ftype_cstr);\n    xm_charset_entry_ref_t tcharset = xm_charset_find_by_name(ttype_cstr);\n    luaL_argcheck(lua, fcharset, 2, \"charset not found\");\n    luaL_argcheck(lua, tcharset, 3, \"charset not found\");\n    tb_check_return_val(fcharset && tcharset, 0);\n\n    // empty string?\n    if (!src_size) {\n        lua_pushstring(lua, \"\");\n    } else {\n        // convert string\n        tb_long_t  dst_size = 0;\n        tb_size_t  dst_maxn = (tb_size_t)src_size << 2;\n        tb_byte_t *dst_data = tb_malloc_bytes(dst_maxn);\n        if (dst_data && dst_maxn &&\n            (dst_size = tb_charset_conv_data(fcharset->type,\n                                             tcharset->type,\n                                             (tb_byte_t const *)src_cstr,\n                                             (tb_size_t)src_size,\n                                             dst_data,\n                                             dst_maxn)) >= 0 &&\n            dst_size < dst_maxn) {\n            lua_pushlstring(lua, (tb_char_t const *)dst_data, dst_size);\n        } else {\n            lua_pushnil(lua);\n        }\n        tb_free(dst_data);\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/endswith.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        endswith.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"endswith\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_string_endswith(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the string and suffix\n    size_t string_size = 0;\n    size_t suffix_size = 0;\n    tb_char_t const *string = luaL_checklstring(lua, 1, &string_size);\n    tb_char_t const *suffix = luaL_checklstring(lua, 2, &suffix_size);\n    tb_check_return_val(string && suffix, 0);\n\n    // string:endswith(suffix)?\n    lua_pushboolean(lua, string_size >= suffix_size && !tb_strcmp(string + string_size - suffix_size, suffix));\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/lastof.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        lastof.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"string_lastof\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../utf8/utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* lastof string (only support plain text)\n *\n * @param str             the string\n * @param substr          the substring\n */\ntb_int_t xm_string_lastof(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get string\n    size_t nstr = 0;\n    tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr);\n\n    // get substring\n    size_t nsubstr = 0;\n    tb_char_t const *csubstr = luaL_checklstring(lua, 2, &nsubstr);\n\n    // lastof it\n    tb_long_t char_pos = xm_utf8_lastof_impl(cstr, nstr, csubstr, nsubstr);\n    if (char_pos > 0) {\n        lua_pushinteger(lua, char_pos);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/lower.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      luadebug, ruki\n * @file        lower.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* string.lower\n *\n * @param str       the string\n *\n * @code\n *      local result = string.lower(str)\n * @endcode\n */\ntb_int_t xm_string_lower(lua_State *lua) {\n    // check\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get string\n    size_t           size = 0;\n    tb_char_t const* cstr = luaL_checklstring(lua, 1, &size);\n    tb_check_return_val(cstr, 0);\n\n    // empty?\n    if (!size) {\n        lua_pushstring(lua, \"\");\n        return 1;\n    }\n\n    // copy string to buffer\n    tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1);\n    if (buffer) {\n        tb_memcpy(buffer, cstr, size);\n        buffer[size] = '\\0';\n\n        // to lower\n        tb_long_t real_size = tb_charset_utf8_tolower(buffer, size);\n\n        // push result\n        if (real_size >= 0) {\n            lua_pushlstring(lua, buffer, real_size);\n        } else {\n            lua_pushlstring(lua, cstr, size);\n        }\n        tb_free(buffer);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_STRING_PREFIX_H\n#define XM_STRING_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/string/split.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        split.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"string_split\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_string_split_str(lua_State       *lua,\n                                     tb_char_t const *cstr,\n                                     tb_size_t        nstr,\n                                     tb_char_t const *cdls,\n                                     tb_size_t        ndls,\n                                     tb_bool_t        strict,\n                                     tb_int_t         limit) {\n    tb_int_t num = 0;\n    tb_char_t const *end = cstr + nstr;\n    tb_char_t const *pos = tb_strstr(cstr, cdls); // faster than tb_strnstr()\n    while (pos && pos < end) {\n        if (pos > cstr || strict) {\n            if (limit > 0 && num + 1 >= limit) {\n                break;\n            }\n\n            lua_pushlstring(lua, cstr, pos - cstr);\n            lua_rawseti(lua, -2, ++num);\n        }\n\n        cstr = pos + ndls;\n        pos  = tb_strstr(cstr, cdls);\n    }\n    if (cstr < end) {\n        lua_pushlstring(lua, cstr, end - cstr);\n        lua_rawseti(lua, -2, ++num);\n    } else if (strict && (limit < 0 || num < limit) && cstr == end) {\n        lua_pushliteral(lua, \"\");\n        lua_rawseti(lua, -2, ++num);\n    }\n}\nstatic tb_void_t xm_string_split_chr(\n    lua_State *lua, tb_char_t const *cstr, tb_size_t nstr, tb_char_t ch, tb_bool_t strict, tb_int_t limit) {\n    tb_int_t num = 0;\n    tb_char_t const *end = cstr + nstr;\n    tb_char_t const *pos = tb_strchr(cstr, ch); // faster than tb_strnchr()\n    while (pos && pos < end) {\n        if (pos > cstr || strict) {\n            if (limit > 0 && num + 1 >= limit) {\n                break;\n            }\n\n            lua_pushlstring(lua, cstr, pos - cstr);\n            lua_rawseti(lua, -2, ++num);\n        }\n\n        cstr = pos + 1;\n        pos  = tb_strchr(cstr, ch);\n    }\n    if (cstr < end) {\n        lua_pushlstring(lua, cstr, end - cstr);\n        lua_rawseti(lua, -2, ++num);\n    } else if (strict && (limit < 0 || num < limit) && cstr == end) {\n        lua_pushliteral(lua, \"\");\n        lua_rawseti(lua, -2, ++num);\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* split string (only support plain text)\n *\n * @param str             the string\n * @param delimiter       the delimiter\n * @param strict          is strict?\n * @param limit           the limit count\n */\ntb_int_t xm_string_split(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get string\n    size_t nstr = 0;\n    tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr);\n\n    // get delimiter\n    size_t ndls = 0;\n    tb_char_t const *cdls = luaL_checklstring(lua, 2, &ndls);\n\n    // is strict?\n    tb_bool_t const strict = (tb_bool_t)lua_toboolean(lua, 3);\n\n    // get limit count\n    tb_int_t const limit = (tb_int_t)luaL_optinteger(lua, 4, -1);\n\n    // split it\n    lua_newtable(lua);\n    if (ndls == 1) {\n        xm_string_split_chr(lua, cstr, (tb_size_t)nstr, cdls[0], strict, limit);\n    } else {\n        xm_string_split_str(lua, cstr, (tb_size_t)nstr, cdls, ndls, strict, limit);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/startswith.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        startswith.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"startswith\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_string_startswith(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the string and prefix\n    size_t prefix_size = 0;\n    tb_char_t const *string = luaL_checkstring(lua, 1);\n    tb_char_t const *prefix = luaL_checklstring(lua, 2, &prefix_size);\n    tb_check_return_val(string && prefix, 0);\n\n    // string:startswith(prefix)?\n    lua_pushboolean(lua, !tb_strncmp(string, prefix, (tb_size_t)prefix_size));\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/trim.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu\n * @file        trim.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"string_trim\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_string_trim_space(tb_char_t const **psstr, tb_char_t const **pestr, tb_int_t mode) {\n    tb_assert(psstr && pestr && *psstr && *pestr);\n\n    tb_char_t const *p = *psstr;\n    tb_char_t const *e = *pestr;\n\n    // trim left?\n    if (mode <= 0) {\n        while (p < e && tb_isspace(*p)) {\n            p++;\n        }\n    }\n\n    // trim right\n    if (mode >= 0) {\n        e--;\n        while (e >= p && tb_isspace(*e)) {\n            e--;\n        }\n        e++;\n    }\n\n    // save trimed string\n    *psstr = p;\n    *pestr = e;\n}\n\nstatic tb_char_t const *xm_string_ltrim(tb_char_t const *sstr,\n                                        tb_char_t const *estr,\n                                        tb_char_t const *ctrim,\n                                        size_t           ntrim) {\n    tb_assert(sstr && estr && ctrim);\n\n    tb_char_t const *p = sstr;\n    while (p < estr && tb_strnchr(ctrim, ntrim, *p)) {\n        p++;\n    }\n    return p;\n}\n\nstatic tb_char_t const *xm_string_rtrim(tb_char_t const *sstr,\n                                        tb_char_t const *estr,\n                                        tb_char_t const *ctrim,\n                                        size_t           ntrim) {\n    tb_assert(sstr && estr && ctrim);\n\n    tb_char_t const *p = estr - 1;\n    while (p >= sstr && tb_strnchr(ctrim, ntrim, *p)) {\n        p--;\n    }\n    return p + 1;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* trim string\n *\n * @param str            the string\n * @param trimchars      the chars to trim\n * @param trimtype       0 to trim left and right, -1 to trim left, 1 to trim right\n *\n * @code\n *      local result = string.trim(str, \"\\r\\n \\v\\t\", 0)\n *      local result = string.trim(str, \"(\", -1)\n * @endcode\n */\ntb_int_t xm_string_trim(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    size_t lstr, ltrim;\n    tb_char_t const *sstr = luaL_checklstring(lua, 1, &lstr);\n    tb_char_t const *estr = sstr + lstr;\n    tb_char_t const *trimchars = luaL_optlstring(lua, 2, \"\", &ltrim);\n    tb_int_t const trimtype = (tb_int_t)luaL_optinteger(lua, 3, 0);\n    do {\n        tb_assert_and_check_break(sstr && trimchars);\n        tb_check_break(lstr != 0);\n\n        tb_char_t const *const rsstr = sstr;\n        tb_char_t const *const restr = estr;\n        if (ltrim == 0) {\n            xm_string_trim_space(&sstr, &estr, trimtype);\n        } else {\n            // trim chars\n            if (trimtype <= 0) {\n                sstr = xm_string_ltrim(sstr, estr, trimchars, ltrim);\n            }\n            if (trimtype >= 0) {\n                estr = xm_string_rtrim(sstr, estr, trimchars, ltrim);\n            }\n        }\n\n        // no trimed chars\n        tb_check_break(sstr != rsstr || estr != restr);\n\n        lua_pushlstring(lua, sstr, estr - sstr);\n        return 1;\n\n    } while (0);\n\n    // return orignal value\n    lua_settop(lua, 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/string/upper.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      luadebug, ruki\n * @file        upper.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* string.upper\n *\n * @param str       the string\n *\n * @code\n *      local result = (str)\n * @endcode\n */\ntb_int_t xm_string_upper(lua_State *lua) {\n    // check\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get string\n    size_t           size = 0;\n    tb_char_t const* cstr = luaL_checklstring(lua, 1, &size);\n    tb_check_return_val(cstr, 0);\n\n    // empty?\n    if (!size) {\n        lua_pushstring(lua, \"\");\n        return 1;\n    }\n\n    // copy string to buffer\n    tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1);\n    if (buffer) {\n        tb_memcpy(buffer, cstr, size);\n        buffer[size] = '\\0';\n\n        // to upper\n        tb_long_t real_size = tb_charset_utf8_toupper(buffer, size);\n        \n        // push result\n        if (real_size >= 0) {\n            lua_pushlstring(lua, buffer, real_size);\n        } else {\n            lua_pushlstring(lua, cstr, size);\n        }\n        tb_free(buffer);\n    } else {\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/event_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        event_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_event\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_event_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);\n    tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);\n\n    if (tb_atomic_fetch_and_sub(&thread_event->refn, 1) == 1) {\n        if (thread_event->handle) {\n            tb_event_exit(thread_event->handle);\n            thread_event->handle = tb_null;\n        }\n        tb_free(thread_event);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/event_incref.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        event_incref.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_event\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_event_incref(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);\n    tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);\n\n    lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_event->refn, 1) >= 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/event_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        event_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_event\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_event_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_event_t *thread_event = tb_null;\n    do {\n        thread_event = tb_malloc0_type(xm_thread_event_t);\n        tb_assert_and_check_break(thread_event);\n\n        thread_event->refn   = 1;\n        thread_event->handle = tb_event_init();\n        tb_assert_and_check_break(thread_event->handle);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread_event);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread_event) {\n            if (thread_event->handle) {\n                tb_event_exit(thread_event->handle);\n                thread_event->handle = tb_null;\n            }\n            tb_free(thread_event);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/event_post.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        event_post.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_event\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_event_post(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);\n    tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);\n\n    lua_pushboolean(lua, tb_event_post(thread_event->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/event_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        event_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_event\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_event_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);\n    tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);\n\n    tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2);\n    lua_pushinteger(lua, tb_event_wait(thread_event->handle, timeout));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);\n    tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);\n\n    if (tb_atomic_fetch_and_sub(&thread_mutex->refn, 1) == 1) {\n        if (thread_mutex->handle) {\n            tb_mutex_exit(thread_mutex->handle);\n            thread_mutex->handle = tb_null;\n        }\n        tb_free(thread_mutex);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_incref.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_incref.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_incref(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);\n    tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);\n\n    lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_mutex->refn, 1) >= 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_mutex_t *thread_mutex = tb_null;\n    do {\n        thread_mutex = tb_malloc0_type(xm_thread_mutex_t);\n        tb_assert_and_check_break(thread_mutex);\n\n        thread_mutex->refn   = 1;\n        thread_mutex->handle = tb_mutex_init();\n        tb_assert_and_check_break(thread_mutex->handle);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread_mutex);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread_mutex) {\n            if (thread_mutex->handle) {\n                tb_mutex_exit(thread_mutex->handle);\n                thread_mutex->handle = tb_null;\n            }\n            tb_free(thread_mutex);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_lock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_lock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_lock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);\n    tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);\n\n    lua_pushboolean(lua, tb_mutex_enter(thread_mutex->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_trylock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_trylock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_trylock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);\n    tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);\n\n    lua_pushboolean(lua, tb_mutex_enter_try(thread_mutex->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/mutex_unlock.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        mutex_unlock.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_mutex\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_mutex_unlock(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);\n    tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);\n\n    lua_pushboolean(lua, tb_mutex_leave(thread_mutex->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_THREAD_PREFIX_H\n#define XM_THREAD_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the thread type\ntypedef struct __xm_thread_t {\n    tb_thread_ref_t handle;\n    tb_string_t callback;\n    tb_string_t callinfo;\n} xm_thread_t;\n\n// the thread value kind\ntypedef enum __xm_thread_value_kind_e {\n    XM_THREAD_VALUE_NIL  = 0,\n    XM_THREAD_VALUE_BOOL = 1,\n    XM_THREAD_VALUE_INT  = 2,\n    XM_THREAD_VALUE_NUM  = 3,\n    XM_THREAD_VALUE_STR  = 4\n} xm_thread_value_kind_e;\n\n// the thread value type\ntypedef struct __xm_thread_value_t {\n    tb_uint32_t kind : 3;\n    tb_uint32_t size : 29;\n    union {\n        tb_char_t *string;\n        tb_bool_t boolean;\n        lua_Integer integer;\n        lua_Number number;\n    } u;\n} xm_thread_value_t;\n\n// the thread event type\ntypedef struct __xm_thread_event_t {\n    tb_event_ref_t handle;\n    tb_atomic_t refn;\n} xm_thread_event_t;\n\n// the thread mutex type\ntypedef struct __xm_thread_mutex_t {\n    tb_mutex_ref_t handle;\n    tb_atomic_t refn;\n} xm_thread_mutex_t;\n\n// the thread semaphore type\ntypedef struct __xm_thread_semaphore_t {\n    tb_semaphore_ref_t handle;\n    tb_atomic_t refn;\n} xm_thread_semaphore_t;\n\n// the thread queue type\ntypedef struct __xm_thread_queue_t {\n    tb_queue_ref_t handle;\n    tb_atomic_t refn;\n} xm_thread_queue_t;\n\n// the thread sharedata type\ntypedef struct __xm_thread_sharedata_t {\n    xm_thread_value_t value;\n    tb_buffer_t buffer;\n    tb_atomic_t refn;\n} xm_thread_sharedata_t;\n\n// get the thread event from arguments\nstatic __tb_inline__ xm_thread_event_t *xm_thread_event_get(lua_State *lua, tb_int_t index) {\n    xm_thread_event_t *thread_event = tb_null;\n    if (xm_lua_isinteger(lua, index)) {\n        thread_event = (xm_thread_event_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    } else if (xm_lua_ispointer(lua, index)) {\n        thread_event = (xm_thread_event_t *)xm_lua_topointer(lua, index);\n    }\n    return thread_event;\n}\n\n// get the thread mutex from arguments\nstatic __tb_inline__ xm_thread_mutex_t *xm_thread_mutex_get(lua_State *lua, tb_int_t index) {\n    xm_thread_mutex_t *thread_mutex = tb_null;\n    if (xm_lua_isinteger(lua, index)) {\n        thread_mutex = (xm_thread_mutex_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    } else if (xm_lua_ispointer(lua, index)) {\n        thread_mutex = (xm_thread_mutex_t *)xm_lua_topointer(lua, index);\n    }\n    return thread_mutex;\n}\n\n// get the thread semaphore from arguments\nstatic __tb_inline__ xm_thread_semaphore_t *xm_thread_semaphore_get(lua_State *lua, tb_int_t index) {\n    xm_thread_semaphore_t *thread_semaphore = tb_null;\n    if (xm_lua_isinteger(lua, index)) {\n        thread_semaphore = (xm_thread_semaphore_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    } else if (xm_lua_ispointer(lua, index)) {\n        thread_semaphore = (xm_thread_semaphore_t *)xm_lua_topointer(lua, index);\n    }\n    return thread_semaphore;\n}\n\n// get the thread queue from arguments\nstatic __tb_inline__ xm_thread_queue_t *xm_thread_queue_get(lua_State *lua, tb_int_t index) {\n    xm_thread_queue_t *thread_queue = tb_null;\n    if (xm_lua_isinteger(lua, index)) {\n        thread_queue = (xm_thread_queue_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    } else if (xm_lua_ispointer(lua, index)) {\n        thread_queue = (xm_thread_queue_t *)xm_lua_topointer(lua, index);\n    }\n    return thread_queue;\n}\n\n// get the thread sharedata from arguments\nstatic __tb_inline__ xm_thread_sharedata_t *xm_thread_sharedata_get(lua_State *lua, tb_int_t index) {\n    xm_thread_sharedata_t *thread_sharedata = tb_null;\n    if (xm_lua_isinteger(lua, index)) {\n        thread_sharedata = (xm_thread_sharedata_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);\n    } else if (xm_lua_ispointer(lua, index)) {\n        thread_sharedata = (xm_thread_sharedata_t *)xm_lua_topointer(lua, index);\n    }\n    return thread_sharedata;\n}\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/thread/queue_clear.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_clear.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_clear(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    tb_queue_clear(thread_queue->handle);\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    if (tb_atomic_fetch_and_sub(&thread_queue->refn, 1) == 1) {\n        if (thread_queue->handle) {\n            tb_queue_exit(thread_queue->handle);\n            thread_queue->handle = tb_null;\n        }\n        tb_free(thread_queue);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_incref.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_incref.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_incref(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_queue->refn, 1) >= 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_thread_value_free(tb_element_ref_t element, tb_pointer_t buff) {\n    xm_thread_value_t *item = (xm_thread_value_t *)buff;\n    if (item) {\n        if (item->kind == XM_THREAD_VALUE_STR) {\n            if (item->u.string) {\n                tb_free((tb_pointer_t)item->u.string);\n            }\n            item->u.string = tb_null;\n        }\n        item->size = 0;\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_queue_t *thread_queue = tb_null;\n    do {\n        thread_queue = tb_malloc0_type(xm_thread_queue_t);\n        tb_assert_and_check_break(thread_queue);\n\n        thread_queue->refn   = 1;\n        thread_queue->handle = tb_queue_init(0,\n                                             tb_element_mem(sizeof(xm_thread_value_t), xm_thread_value_free, tb_null));\n        tb_assert_and_check_break(thread_queue->handle);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread_queue);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread_queue) {\n            if (thread_queue->handle) {\n                tb_queue_exit(thread_queue->handle);\n                thread_queue->handle = tb_null;\n            }\n            tb_free(thread_queue);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_pop.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_pop.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_pop(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    if (tb_queue_null(thread_queue->handle)) {\n        lua_pushnil(lua);\n        lua_pushliteral(lua, \"the thread queue is empty\");\n        return 2;\n    }\n\n    xm_thread_value_t *item = (xm_thread_value_t *)tb_queue_get(thread_queue->handle);\n    tb_assert_and_check_return_val(item, 0);\n\n    tb_bool_t ok = tb_false;\n    switch (item->kind) {\n    case XM_THREAD_VALUE_STR:\n        if (item->size) {\n            lua_pushlstring(lua, item->u.string, item->size);\n        } else {\n            lua_pushliteral(lua, \"\");\n        }\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_INT:\n        lua_pushinteger(lua, item->u.integer);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_NUM:\n        lua_pushnumber(lua, item->u.number);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_BOOL:\n        lua_pushboolean(lua, item->u.boolean);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_NIL:\n        lua_pushnil(lua);\n        ok = tb_true;\n        break;\n    default:\n        break;\n    }\n\n    if (!ok) {\n        lua_pushnil(lua);\n        lua_pushliteral(lua, \"invalid thread queue item\");\n        return 2;\n    }\n\n    tb_queue_pop(thread_queue->handle);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_push.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_push.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_push(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    if (tb_queue_full(thread_queue->handle)) {\n        lua_pushboolean(lua, tb_false);\n        lua_pushliteral(lua, \"the thread queue is full\");\n        return 2;\n    }\n\n    xm_thread_value_t item;\n    if (lua_isstring(lua, 2)) {\n        size_t data_size = 0;\n        tb_char_t const *data = luaL_checklstring(lua, 2, &data_size);\n        tb_assert_and_check_return_val(data, 0);\n\n        item.kind = (tb_uint32_t)XM_THREAD_VALUE_STR;\n        item.size = (tb_uint32_t)data_size;\n        if (data_size) {\n            item.u.string = tb_malloc_cstr(data_size);\n            tb_assert_and_check_return_val(item.u.string, 0);\n            tb_memcpy(item.u.string, data, data_size);\n        }\n    } else if (xm_lua_isinteger(lua, 2)) {\n        item.kind      = (tb_uint32_t)XM_THREAD_VALUE_INT;\n        item.u.integer = lua_tointeger(lua, 2);\n    } else if (lua_isnumber(lua, 2)) {\n        item.kind     = (tb_uint32_t)XM_THREAD_VALUE_NUM;\n        item.u.number = lua_tonumber(lua, 2);\n    } else if (lua_isboolean(lua, 2)) {\n        item.kind      = (tb_uint32_t)XM_THREAD_VALUE_BOOL;\n        item.u.boolean = lua_toboolean(lua, 2);\n    } else if (lua_isnil(lua, 2)) {\n        item.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL;\n    } else {\n        lua_pushboolean(lua, tb_false);\n        lua_pushliteral(lua, \"unsupported thread queue item\");\n        return 2;\n    }\n\n    tb_queue_put(thread_queue->handle, &item);\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/queue_size.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        queue_size.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_queue\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_queue_size(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);\n    tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);\n\n    lua_pushinteger(lua, (tb_int_t)tb_queue_size(thread_queue->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/semaphore_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        semaphore_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_semaphore\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_semaphore_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);\n    tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);\n\n    if (tb_atomic_fetch_and_sub(&thread_semaphore->refn, 1) == 1) {\n        if (thread_semaphore->handle) {\n            tb_semaphore_exit(thread_semaphore->handle);\n            thread_semaphore->handle = tb_null;\n        }\n        tb_free(thread_semaphore);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/semaphore_incref.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        semaphore_incref.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_semaphore\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_semaphore_incref(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);\n    tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);\n\n    lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_semaphore->refn, 1) >= 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/semaphore_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        semaphore_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_semaphore\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_semaphore_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_semaphore_t *thread_semaphore = tb_null;\n    do {\n        tb_long_t value = (tb_long_t)luaL_checknumber(lua, 1);\n\n        thread_semaphore = tb_malloc0_type(xm_thread_semaphore_t);\n        tb_assert_and_check_break(thread_semaphore);\n\n        thread_semaphore->refn   = 1;\n        thread_semaphore->handle = tb_semaphore_init(value);\n        tb_assert_and_check_break(thread_semaphore->handle);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread_semaphore);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread_semaphore) {\n            if (thread_semaphore->handle) {\n                tb_semaphore_exit(thread_semaphore->handle);\n                thread_semaphore->handle = tb_null;\n            }\n            tb_free(thread_semaphore);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/semaphore_post.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        semaphore_post.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_semaphore\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_semaphore_post(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);\n    tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);\n\n    tb_long_t value = (tb_long_t)luaL_checknumber(lua, 2);\n    lua_pushboolean(lua, tb_semaphore_post(thread_semaphore->handle, value));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/semaphore_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        semaphore_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_semaphore\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_semaphore_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);\n    tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);\n\n    tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2);\n    lua_pushinteger(lua, tb_semaphore_wait(thread_semaphore->handle, timeout));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_clear.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_clear.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_clear(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);\n    tb_assert_and_check_return_val(thread_sharedata, 0);\n\n    thread_sharedata->value.kind = XM_THREAD_VALUE_NIL;\n    tb_buffer_clear(&thread_sharedata->buffer);\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);\n    tb_assert_and_check_return_val(thread_sharedata, 0);\n\n    if (tb_atomic_fetch_and_sub(&thread_sharedata->refn, 1) == 1) {\n        tb_buffer_exit(&thread_sharedata->buffer);\n        tb_free(thread_sharedata);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_get.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_get.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_get_(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);\n    tb_assert_and_check_return_val(thread_sharedata, 0);\n\n    tb_bool_t ok = tb_false;\n    switch (thread_sharedata->value.kind) {\n    case XM_THREAD_VALUE_STR:\n        if (tb_buffer_size(&thread_sharedata->buffer) > 0) {\n            lua_pushlstring(lua,\n                            (tb_char_t *)tb_buffer_data(&thread_sharedata->buffer),\n                            tb_buffer_size(&thread_sharedata->buffer));\n        } else {\n            lua_pushliteral(lua, \"\");\n        }\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_INT:\n        lua_pushinteger(lua, thread_sharedata->value.u.integer);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_NUM:\n        lua_pushnumber(lua, thread_sharedata->value.u.number);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_BOOL:\n        lua_pushboolean(lua, thread_sharedata->value.u.boolean);\n        ok = tb_true;\n        break;\n    case XM_THREAD_VALUE_NIL:\n        lua_pushnil(lua);\n        ok = tb_true;\n        break;\n    default:\n        break;\n    }\n\n    if (!ok) {\n        lua_pushnil(lua);\n        lua_pushliteral(lua, \"invalid thread sharedata thread_sharedata\");\n        return 2;\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_incref.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_incref.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_incref(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);\n    tb_assert_and_check_return_val(thread_sharedata, 0);\n\n    lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_sharedata->refn, 1) >= 1);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_sharedata_t *thread_sharedata = tb_null;\n    do {\n        thread_sharedata = tb_malloc0_type(xm_thread_sharedata_t);\n        tb_assert_and_check_break(thread_sharedata);\n\n        thread_sharedata->refn       = 1;\n        thread_sharedata->value.kind = XM_THREAD_VALUE_NIL;\n        tb_buffer_init(&thread_sharedata->buffer);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread_sharedata);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread_sharedata) {\n            tb_buffer_exit(&thread_sharedata->buffer);\n            tb_free(thread_sharedata);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/sharedata_set.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sharedata_set.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread_sharedata\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_sharedata_set(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);\n    tb_assert_and_check_return_val(thread_sharedata, 0);\n\n    if (lua_isstring(lua, 2)) {\n        size_t data_size = 0;\n        tb_char_t const *data = luaL_checklstring(lua, 2, &data_size);\n        tb_assert_and_check_return_val(data, 0);\n\n        thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_STR;\n        if (data_size) {\n            tb_buffer_memncpy(&thread_sharedata->buffer, (tb_byte_t const *)data, data_size);\n        } else {\n            tb_buffer_clear(&thread_sharedata->buffer);\n        }\n    } else if (xm_lua_isinteger(lua, 2)) {\n        thread_sharedata->value.kind      = (tb_uint32_t)XM_THREAD_VALUE_INT;\n        thread_sharedata->value.u.integer = lua_tointeger(lua, 2);\n    } else if (lua_isnumber(lua, 2)) {\n        thread_sharedata->value.kind     = (tb_uint32_t)XM_THREAD_VALUE_NUM;\n        thread_sharedata->value.u.number = lua_tonumber(lua, 2);\n    } else if (lua_isboolean(lua, 2)) {\n        thread_sharedata->value.kind      = (tb_uint32_t)XM_THREAD_VALUE_BOOL;\n        thread_sharedata->value.u.boolean = lua_toboolean(lua, 2);\n    } else if (lua_isnil(lua, 2)) {\n        thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL;\n    } else {\n        lua_pushboolean(lua, tb_false);\n        lua_pushliteral(lua, \"unsupported thread sharedata item\");\n        return 2;\n    }\n\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/thread_exit.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        thread_exit.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_exit(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get thread\n    xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(thread, 0);\n\n    // exit thread\n    if (thread) {\n        tb_string_exit(&thread->callback);\n        tb_string_exit(&thread->callinfo);\n        if (thread->handle) {\n            tb_thread_exit(thread->handle);\n            thread->handle = tb_null;\n        }\n        tb_free(thread);\n    }\n    lua_pushboolean(lua, tb_true);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/thread_init.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        thread_init.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"../engine.h\"\n#include \"../engine_pool.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define XM_THREAD_ENGINE_NAME \"xmake\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_int_t xm_thread_func(tb_cpointer_t priv) {\n    xm_thread_t *thread = (xm_thread_t *)priv;\n    tb_assert_and_check_return_val(thread, 0);\n\n    xm_engine_ref_t engine = xm_engine_pool_alloc(xm_engine_pool());\n    if (!engine) {\n        engine = xm_engine_init(XM_THREAD_ENGINE_NAME, tb_null);\n    }\n    if (engine) {\n        lua_State *lua = xm_engine_lua(engine);\n        tb_assert(lua);\n\n        // pass callback\n        tb_char_t const *callback_data = tb_string_cstr(&thread->callback);\n        tb_size_t callback_size = tb_string_size(&thread->callback);\n        if (callback_data && callback_size) {\n            lua_pushlstring(lua, callback_data, callback_size);\n            lua_setglobal(lua, \"_THREAD_CALLBACK\");\n        }\n\n        // pass callinfo\n        tb_char_t const *callinfo_data = tb_string_cstr(&thread->callinfo);\n        tb_size_t callinfo_size = tb_string_size(&thread->callinfo);\n        if (callinfo_data && callinfo_size) {\n            lua_pushlstring(lua, callinfo_data, callinfo_size);\n            lua_setglobal(lua, \"_THREAD_CALLINFO\");\n        }\n\n        // start engine\n        tb_char_t *argv[] = { XM_THREAD_ENGINE_NAME, tb_null };\n        xm_engine_main(engine, 1, argv, tb_null);\n        if (!xm_engine_pool_free(xm_engine_pool(), engine)) {\n            xm_engine_exit(engine);\n        }\n    }\n    return 0;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_init(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_bool_t ok = tb_false;\n    xm_thread_t *thread = tb_null;\n    do {\n        // get thread name\n        tb_char_t const *name = luaL_checkstring(lua, 1);\n\n        // get callback\n        size_t callback_size = 0;\n        tb_char_t const *callback_data = luaL_checklstring(lua, 2, &callback_size);\n        tb_assert_and_check_break(callback_data && callback_size);\n\n        // get callinfo\n        size_t callinfo_size = 0;\n        tb_char_t const *callinfo_data = luaL_checklstring(lua, 3, &callinfo_size);\n        tb_assert_and_check_break(callinfo_data && callinfo_size);\n\n        // get stack size\n        tb_size_t stacksize = (tb_size_t)luaL_checkinteger(lua, 4);\n\n        // init thread\n        thread = tb_malloc0_type(xm_thread_t);\n        tb_assert_and_check_break(thread);\n\n        tb_string_init(&thread->callback);\n        tb_string_cstrncpy(&thread->callback, callback_data, callback_size);\n\n        tb_string_init(&thread->callinfo);\n        tb_string_cstrncpy(&thread->callinfo, callinfo_data, callinfo_size);\n\n        // create and start thread\n        thread->handle = tb_thread_init(name, xm_thread_func, thread, stacksize);\n        tb_assert_and_check_break(thread->handle);\n\n        xm_lua_pushpointer(lua, (tb_pointer_t)thread);\n        ok = tb_true;\n\n    } while (0);\n\n    if (!ok) {\n        if (thread) {\n            tb_string_exit(&thread->callback);\n            tb_string_exit(&thread->callinfo);\n            if (thread->handle) {\n                tb_thread_exit(thread->handle);\n                thread->handle = tb_null;\n            }\n            tb_free(thread);\n        }\n        lua_pushnil(lua);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/thread_resume.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        thread_resume.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_resume(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get thread\n    xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(thread && thread->handle, 0);\n\n    // resume thread\n    lua_pushboolean(lua, tb_thread_resume(thread->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/thread_suspend.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        thread_suspend.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_suspend(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get thread\n    xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(thread && thread->handle, 0);\n\n    // suspend thread\n    lua_pushboolean(lua, tb_thread_suspend(thread->handle));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/thread/thread_wait.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        thread_wait.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"thread\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_int_t xm_thread_wait(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // is pointer?\n    if (!xm_lua_ispointer(lua, 1)) {\n        return 0;\n    }\n\n    // get thread\n    xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);\n    tb_check_return_val(thread->handle, 0);\n\n    // get timeout\n    tb_size_t timeout = (tb_size_t)luaL_checkinteger(lua, 2);\n\n    // wait thread\n    tb_int_t retval;\n    lua_pushinteger(lua, (tb_int_t)tb_thread_wait(thread->handle, timeout, &retval));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/tty/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_TTY_PREFIX_H\n#define XM_TTY_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/tty/session_id.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        session_id.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"session_id\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <windows.h>\n#else\n#include <unistd.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// tty.session_id()\ntb_int_t xm_tty_session_id(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n    HWND hwnd = GetConsoleWindow();\n    if (hwnd) {\n        // use hex string of hwnd as session id\n        lua_pushfstring(lua, \"%p\", hwnd);\n        return 1;\n    }\n#else\n    // we use the tty name as session id\n    tb_char_t const* name = ttyname(STDIN_FILENO);\n    if (name) {\n        lua_pushstring(lua, name);\n        return 1;\n    }\n#endif\n\n    // failed\n    lua_pushnil(lua);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/tty/term_mode.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        term_mode.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"term_mode\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <windows.h>\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* local oldmode = tty.term_mode(stdtype)\n * local oldmode = tty.term_mode(stdtype, newmode)\n */\ntb_int_t xm_tty_term_mode(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n#ifdef TB_CONFIG_OS_WINDOWS\n\n    // get std type, (stdin: 1, stdout: 2, stderr: 3)\n    tb_int_t stdtype = (tb_int_t)luaL_checkinteger(lua, 1);\n\n    // get and set terminal mode\n    DWORD mode = 0;\n    HANDLE console_handle = INVALID_HANDLE_VALUE;\n    switch (stdtype) {\n    case 1:\n        console_handle = GetStdHandle(STD_INPUT_HANDLE);\n        break;\n    case 2:\n        console_handle = GetStdHandle(STD_OUTPUT_HANDLE);\n        break;\n    case 3:\n        console_handle = GetStdHandle(STD_ERROR_HANDLE);\n        break;\n    }\n    GetConsoleMode(console_handle, &mode);\n    if (lua_isnumber(lua, 2)) {\n        tb_int_t newmode = (tb_int_t)lua_tointeger(lua, 2);\n        if (console_handle != INVALID_HANDLE_VALUE) {\n            SetConsoleMode(console_handle, (DWORD)newmode);\n        }\n    }\n#else\n    tb_int_t mode = 0;\n#endif\n    lua_pushinteger(lua, (tb_int_t)mode);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/byte.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        byte.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_bool_t xm_utf8_byte_cb(xm_utf8_int_t code, tb_cpointer_t udata) {\n    lua_State* lua = (lua_State*)udata;\n    tb_assert_and_check_return_val(lua, tb_false);\n\n    luaL_checkstack(lua, 1, \"too many results\");\n    lua_pushinteger(lua, code);\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8.byte(s, i [, j])\n */\ntb_int_t xm_utf8_byte(lua_State* lua) {\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Integer i = luaL_optinteger(lua, 2, 1);\n    lua_Integer j = luaL_optinteger(lua, 3, i);\n\n    return (tb_int_t)xm_utf8_byte_impl(s, len, (tb_long_t)i, (tb_long_t)j, xm_utf8_byte_cb, lua);\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/char.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        char.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic void xm_utf8_char_push(lua_State *lua, tb_int_t arg) {\n    lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(lua, arg);\n    luaL_argcheck(lua, code <= XM_UTF8_MAXUTF, arg, \"value out of range\");\n    \n    tb_char_t buf[8];\n    tb_size_t n = xm_utf8_encode(buf, (xm_utf8_int_t)code);\n    if (n > 0) {\n        lua_pushlstring(lua, buf, n);\n    } else {\n        luaL_error(lua, \"value out of range\");\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utfchar(n1, n2, ...)  -> char(n1)..char(n2)...\n */\ntb_int_t xm_utf8_char(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_int_t n = lua_gettop(lua);  // number of arguments\n    if (n == 1) { // optimize common case of single char\n        xm_utf8_char_push(lua, 1);\n    } else {\n        tb_int_t i;\n        luaL_Buffer b;\n        luaL_buffinit(lua, &b);\n        for (i = 1; i <= n; i++) {\n            xm_utf8_char_push(lua, i);\n            luaL_addvalue(&b);\n        }\n        luaL_pushresult(&b);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/codepoint.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        codepoint.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_bool_t xm_utf8_codepoint_cb(xm_utf8_int_t code, tb_cpointer_t udata) {\n    lua_State* lua = (lua_State*)udata;\n    tb_assert_and_check_return_val(lua, tb_false);\n\n    lua_pushinteger(lua, code);\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all\n * characters that start in the range [i,j]\n */\ntb_int_t xm_utf8_codepoint(lua_State *lua) {\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len);\n    lua_Integer pose = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len);\n    tb_bool_t lax = lua_toboolean(lua, 4);\n\n    luaL_argcheck(lua, posi >= 1, 2, \"out of bounds\");\n    luaL_argcheck(lua, pose <= (lua_Integer)len, 3, \"out of bounds\");\n\n    if (posi > pose) {\n        return 0;  // empty interval; return no values\n    }\n    if (pose - posi >= INT_MAX) { // (lua_Integer -> int) overflow?\n        return luaL_error(lua, \"string slice too long\");\n    }\n    \n    tb_int_t n = (tb_int_t)(pose - posi) + 1;\n    luaL_checkstack(lua, n, \"string slice too long\");\n\n    int nresults = lua_gettop(lua);\n    if (!xm_utf8_codepoint_impl(s, len, (tb_long_t)posi, (tb_long_t)pose, !lax, xm_utf8_codepoint_cb, lua)) {\n        return luaL_error(lua, XM_UTF8_MSGInvalid);\n    }\n    \n    return lua_gettop(lua) - nresults;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/codes.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        codes.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_int_t xm_utf8_codes_iter(lua_State *lua, tb_bool_t strict) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Unsigned n = (lua_Unsigned)lua_tointeger(lua, 2);\n    if (n < len) {\n        while (n < len && xm_utf8_iscontp(s + n)) {\n            n++;  // go to next character\n        }\n    }\n    if (n >= len) { // (also handles original 'n' being negative)\n        return 0;  // no more codepoints\n    } else {\n        xm_utf8_int_t code;\n        tb_char_t const* next = xm_utf8_decode(s + n, &code, strict);\n        if (next == NULL || (next < s + len && xm_utf8_iscontp(next))) {\n            return luaL_error(lua, XM_UTF8_MSGInvalid);\n        }\n        lua_pushinteger(lua, n + 1);\n        lua_pushinteger(lua, code);\n        return 2;\n    }\n}\n\nstatic int xm_utf8_codes_iter_strict(lua_State *lua) {\n    return xm_utf8_codes_iter(lua, tb_true);\n}\n\nstatic int xm_utf8_codes_iter_lax(lua_State *lua) {\n    return xm_utf8_codes_iter(lua, tb_false);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_utf8_codes(lua_State *lua) {\n    tb_bool_t lax = lua_toboolean(lua, 2);\n    tb_char_t const* s = luaL_checkstring(lua, 1);\n    luaL_argcheck(lua, !xm_utf8_iscontp(s), 1, XM_UTF8_MSGInvalid);\n    lua_pushcfunction(lua, lax ? xm_utf8_codes_iter_lax : xm_utf8_codes_iter_strict);\n    lua_pushvalue(lua, 1);\n    lua_pushinteger(lua, 0);\n    return 3;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/find.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        find.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_int_t xm_utf8_find_impl_plain(lua_State* lua, tb_char_t const* s, size_t len, tb_char_t const* sub, size_t sublen, lua_Integer init) {\n    tb_long_t char_end = 0;\n    tb_long_t char_start = xm_utf8_find_impl(s, len, sub, sublen, (tb_long_t)init, &char_end);\n    if (char_start > 0) {\n        lua_pushinteger(lua, char_start);\n        lua_pushinteger(lua, char_end);\n        return 2;\n    }\n    lua_pushnil(lua);\n    return 1;\n}\n\nstatic tb_int_t xm_utf8_find_impl_pattern(lua_State* lua, tb_char_t const* s, size_t len, lua_Integer init) {\n    int base = lua_gettop(lua);\n    tb_long_t byte_init = 1;\n    if (init > 0) {\n        if (init > 1) {\n            byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, 1);\n            if (byte_init <= 0) {\n                lua_pushnil(lua);\n                return 1;\n            }\n        }\n    } else if (init < 0) {\n        byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, len + 1);\n        if (byte_init <= 0) {\n            lua_pushnil(lua);\n            return 1;\n        }\n    }\n    \n    lua_getglobal(lua, \"string\");\n    lua_getfield(lua, -1, \"find\");\n    lua_pushvalue(lua, 1); // s\n    lua_pushvalue(lua, 2); // pattern\n    lua_pushinteger(lua, byte_init); // init (byte)\n    lua_pushboolean(lua, 0); // plain\n    \n    lua_call(lua, 4, LUA_MULTRET);\n    \n    // Stack: [args, string_table, results...]\n    int nres = lua_gettop(lua) - (base + 1);\n    if (nres <= 0 || lua_isnil(lua, base + 2)) {\n         lua_pushnil(lua);\n         lua_remove(lua, base + 1);\n         return 1;\n    }\n    \n    lua_Integer b_start = lua_tointeger(lua, base + 2);\n    lua_Integer b_end = lua_tointeger(lua, base + 3);\n    \n    tb_long_t char_start = 1;\n    if (b_start > 1) {\n        tb_long_t count = xm_utf8_len_impl(s, len, 1, (tb_long_t)b_start - 1, tb_true, tb_null);\n        if (count < 0) { \n            lua_pushnil(lua); \n            lua_remove(lua, base + 1);\n            return 1; \n        }\n        char_start = count + 1;\n    }\n    \n    tb_long_t match_char_len = 0;\n    if (b_end >= b_start) {\n        match_char_len = xm_utf8_len_impl(s, len, (tb_long_t)b_start, (tb_long_t)b_end, tb_true, tb_null);\n        if (match_char_len < 0) { \n            lua_pushnil(lua); \n            lua_remove(lua, base + 1);\n            return 1; \n        }\n    }\n    \n    lua_pushinteger(lua, char_start);\n    lua_replace(lua, base + 2);\n    lua_pushinteger(lua, char_start + match_char_len - 1);\n    lua_replace(lua, base + 3);\n    \n    lua_remove(lua, base + 1);\n    \n    return nres;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8.find(s, target [, init [, plain]])\n */\ntb_int_t xm_utf8_find(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    size_t sublen;\n    tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen);\n    lua_Integer init = luaL_optinteger(lua, 3, 1);\n    tb_int_t plain = lua_toboolean(lua, 4);\n    \n    if (plain) {\n        return xm_utf8_find_impl_plain(lua, s, len, sub, sublen, init);\n    } else {\n        return xm_utf8_find_impl_pattern(lua, s, len, init);\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/lastof.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        lastof.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8.lastof(s, pattern, plain)\n */\ntb_int_t xm_utf8_lastof(lua_State *lua) {\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    size_t sublen;\n    tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen);\n    tb_int_t plain = lua_toboolean(lua, 3);\n    tb_long_t byte_pos = 0;\n\n    if (plain) {\n        byte_pos = xm_utf8_lastof_impl(s, len, sub, sublen);\n    } else {\n        lua_getglobal(lua, \"string\");\n        lua_getfield(lua, -1, \"lastof\");\n        lua_pushvalue(lua, 1); // s\n        lua_pushvalue(lua, 2); // pattern\n        lua_pushboolean(lua, 0); // plain = false\n        lua_call(lua, 3, 1);\n        if (!lua_isnil(lua, -1)) {\n            byte_pos = (tb_long_t)lua_tointeger(lua, -1);\n        }\n    }\n\n    if (byte_pos > 0) {\n        tb_long_t char_pos = xm_utf8_charpos(s, len, byte_pos);\n        if (char_pos > 0) {\n            lua_pushinteger(lua, char_pos);\n            return 1;\n        }\n    }\n\n    lua_pushnil(lua);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/len.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        len.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8len(s [, i [, j [, lax]]]) --> number of characters that\n * start in the range [i,j], or nil + current position if 's' is not\n * well formed in that interval\n */\ntb_int_t xm_utf8_len(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len);\n    lua_Integer posj = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, -1), len);\n    tb_bool_t lax = lua_toboolean(lua, 4);\n    luaL_argcheck(lua, 1 <= posi && --posi <= (lua_Integer)len, 2, \"initial position out of bounds\");\n    luaL_argcheck(lua, --posj < (lua_Integer)len, 3, \"final position out of bounds\");\n\n    tb_size_t errpos = 0;\n    tb_long_t n = xm_utf8_len_impl(s, len, (tb_long_t)posi + 1, (tb_long_t)posj + 1, !lax, &errpos);\n    if (n < 0) {\n        lua_pushnil(lua);\n        lua_pushinteger(lua, errpos);\n        return 2;\n    }\n    lua_pushinteger(lua, n);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/offset.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        offset.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* offset(s, n, [i])  -> index where n-th character counting from\n *   position 'i' starts; 0 means character at 'i'.\n */\ntb_int_t xm_utf8_offset(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Integer n  = luaL_checkinteger(lua, 2);\n    lua_Integer posi = (n >= 0) ? 1 : len + 1;\n    posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len);\n\n    tb_long_t result = xm_utf8_offset_impl(s, len, (tb_long_t)n, (tb_long_t)posi);\n    if (result == -1) {\n        return luaL_argerror(lua, 3, \"position out of bounds\");\n    }\n    if (result == -2) {\n        return luaL_error(lua, \"initial position is a continuation byte\");\n    }\n    if (result == 0) {\n        lua_pushnil(lua);\n        return 1;\n    }\n    lua_pushinteger(lua, result);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/prefix.h",
    "content": "#ifndef XM_UTF8_PREFIX_H\n#define XM_UTF8_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/utf8/reverse.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        reverse.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8.reverse(s)\n */\ntb_int_t xm_utf8_reverse(lua_State *lua) {\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    if (len == 0) {\n        lua_pushliteral(lua, \"\");\n        return 1;\n    }\n\n    // do reverse\n    if (len < 1024) {\n        tb_char_t buf[1024 + 1];\n        xm_utf8_reverse_impl(s, len, buf);\n        lua_pushlstring(lua, buf, len);\n    } else {\n        tb_char_t* buf = (tb_char_t*)tb_malloc_bytes(len + 1);\n        if (buf) {\n            xm_utf8_reverse_impl(s, len, buf);\n            lua_pushlstring(lua, buf, len);\n            tb_free(buf);\n        } else {\n            lua_pushnil(lua);\n        }\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/sub.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        sub.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* utf8.sub(s, i [, j])\n */\ntb_int_t xm_utf8_sub(lua_State *lua) {\n    size_t len;\n    tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n    lua_Integer i = luaL_checkinteger(lua, 2);\n    lua_Integer j = luaL_optinteger(lua, 3, -1);\n\n    tb_size_t sublen = 0;\n    tb_char_t const* sub = xm_utf8_sub_impl(s, len, (tb_long_t)i, (tb_long_t)j, &sublen);\n    if (sub) {\n        lua_pushlstring(lua, sub, sublen);\n    } else {\n        lua_pushliteral(lua, \"\");\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utf8/utf8.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        utf8.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_char_t const* xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict) {\n    static const xm_utf8_int_t limits[] = {~(xm_utf8_int_t)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};\n    tb_uint32_t c = (tb_byte_t)s[0];\n    xm_utf8_int_t res = 0;\n    if (c < 0x80) {\n        res = c;\n    } else {\n        if (xm_utf8_iscont(c)) {\n            return tb_null;\n        }\n        tb_int_t count = 0;\n        for (; c & 0x40; c <<= 1) {\n            tb_uint32_t cc = (tb_byte_t)s[++count];\n            if (!xm_utf8_iscont(cc)) {\n                return tb_null;\n            }\n            res = (res << 6) | (cc & 0x3F);\n        }\n        res |= ((xm_utf8_int_t)(c & 0x7F) << (count * 5));\n        if (count > 5 || res > XM_UTF8_MAXUTF || res < limits[count]) {\n            return tb_null;\n        }\n        s += count;\n    }\n    if (strict) {\n        if (res > XM_UTF8_MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) {\n            return tb_null;\n        }\n    }\n    if (val) {\n        *val = res;\n    }\n    return s + 1;\n}\n\ntb_size_t xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val) {\n    tb_assert_and_check_return_val(s, 0);\n\n    if (val < 0x80) {\n        s[0] = (tb_char_t)val;\n        return 1;\n    }\n    if (val < 0x800) {\n        s[0] = (tb_char_t)(0xc0 | ((val >> 6) & 0x1f));\n        s[1] = (tb_char_t)(0x80 | (val & 0x3f));\n        return 2;\n    }\n    if (val < 0x10000) {\n        s[0] = (tb_char_t)(0xe0 | ((val >> 12) & 0x0f));\n        s[1] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));\n        s[2] = (tb_char_t)(0x80 | (val & 0x3f));\n        return 3;\n    }\n    if (val <= 0x10FFFF) {\n        s[0] = (tb_char_t)(0xf0 | ((val >> 18) & 0x07));\n        s[1] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));\n        s[2] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));\n        s[3] = (tb_char_t)(0x80 | (val & 0x3f));\n        return 4;\n    }\n    if (val <= 0x3FFFFFF) {\n        s[0] = (tb_char_t)(0xf8 | ((val >> 24) & 0x03));\n        s[1] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f));\n        s[2] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));\n        s[3] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));\n        s[4] = (tb_char_t)(0x80 | (val & 0x3f));\n        return 5;\n    }\n    if (val <= 0x7FFFFFFF) {\n        s[0] = (tb_char_t)(0xfc | ((val >> 30) & 0x01));\n        s[1] = (tb_char_t)(0x80 | ((val >> 24) & 0x3f));\n        s[2] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f));\n        s[3] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));\n        s[4] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));\n        s[5] = (tb_char_t)(0x80 | (val & 0x3f));\n        return 6;\n    }\n    return 0;\n}\n\ntb_long_t xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos) {\n    if (byte_pos <= 0) return 0;\n    if (byte_pos > len + 1) byte_pos = len + 1;\n\n    // adjust byte_pos to the start of the character\n    //\n    // performance:\n    // 0(1) complexity, because utf8 sequence is max 4 bytes\n    while (byte_pos > 1 && xm_utf8_iscont(s[byte_pos - 1])) {\n        byte_pos--;\n    }\n\n    // get character position\n    tb_long_t count = xm_utf8_len_impl(s, len, 1, byte_pos - 1, tb_true, tb_null);\n    return count >= 0? count + 1 : -1;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation interfaces\n */\nstatic struct { xm_utf8_int_t first; xm_utf8_int_t last; } const g_non_spacing[] =\n{\n    {0x0300, 0x036F},   {0x0483, 0x0486},   {0x0488, 0x0489},\n    {0x0591, 0x05BD},   {0x05BF, 0x05BF},   {0x05C1, 0x05C2},\n    {0x05C4, 0x05C5},   {0x05C7, 0x05C7},   {0x0600, 0x0603},\n    {0x0610, 0x0615},   {0x064B, 0x065E},   {0x0670, 0x0670},\n    {0x06D6, 0x06E4},   {0x06E7, 0x06E8},   {0x06EA, 0x06ED},\n    {0x070F, 0x070F},   {0x0711, 0x0711},   {0x0730, 0x074A},\n    {0x07A6, 0x07B0},   {0x07EB, 0x07F3},   {0x0901, 0x0902},\n    {0x093C, 0x093C},   {0x0941, 0x0948},   {0x094D, 0x094D},\n    {0x0951, 0x0954},   {0x0962, 0x0963},   {0x0981, 0x0981},\n    {0x09BC, 0x09BC},   {0x09C1, 0x09C4},   {0x09CD, 0x09CD},\n    {0x09E2, 0x09E3},   {0x0A01, 0x0A02},   {0x0A3C, 0x0A3C},\n    {0x0A41, 0x0A42},   {0x0A47, 0x0A48},   {0x0A4B, 0x0A4D},\n    {0x0A70, 0x0A71},   {0x0A81, 0x0A82},   {0x0ABC, 0x0ABC},\n    {0x0AC1, 0x0AC5},   {0x0AC7, 0x0AC8},   {0x0ACD, 0x0ACD},\n    {0x0AE2, 0x0AE3},   {0x0B01, 0x0B01},   {0x0B3C, 0x0B3C},\n    {0x0B3F, 0x0B3F},   {0x0B41, 0x0B43},   {0x0B4D, 0x0B4D},\n    {0x0B56, 0x0B56},   {0x0B82, 0x0B82},   {0x0BC0, 0x0BC0},\n    {0x0BCD, 0x0BCD},   {0x0C3E, 0x0C40},   {0x0C46, 0x0C48},\n    {0x0C4A, 0x0C4D},   {0x0C55, 0x0C56},   {0x0CBC, 0x0CBC},\n    {0x0CBF, 0x0CBF},   {0x0CC6, 0x0CC6},   {0x0CCC, 0x0CCD},\n    {0x0CE2, 0x0CE3},   {0x0D41, 0x0D43},   {0x0D4D, 0x0D4D},\n    {0x0DCA, 0x0DCA},   {0x0DD2, 0x0DD4},   {0x0DD6, 0x0DD6},\n    {0x0E31, 0x0E31},   {0x0E34, 0x0E3A},   {0x0E47, 0x0E4E},\n    {0x0EB1, 0x0EB1},   {0x0EB4, 0x0EB9},   {0x0EBB, 0x0EBC},\n    {0x0EC8, 0x0ECD},   {0x0F18, 0x0F19},   {0x0F35, 0x0F35},\n    {0x0F37, 0x0F37},   {0x0F39, 0x0F39},   {0x0F71, 0x0F7E},\n    {0x0F80, 0x0F84},   {0x0F86, 0x0F87},   {0x0F90, 0x0F97},\n    {0x0F99, 0x0FBC},   {0x0FC6, 0x0FC6},   {0x102D, 0x1030},\n    {0x1032, 0x1032},   {0x1036, 0x1037},   {0x1039, 0x1039},\n    {0x1058, 0x1059},   {0x1160, 0x11FF},   {0x135F, 0x135F},\n    {0x1712, 0x1714},   {0x1732, 0x1734},   {0x1752, 0x1753},\n    {0x1772, 0x1773},   {0x17B4, 0x17B5},   {0x17B7, 0x17BD},\n    {0x17C6, 0x17C6},   {0x17C9, 0x17D3},   {0x17DD, 0x17DD},\n    {0x180B, 0x180D},   {0x18A9, 0x18A9},   {0x1920, 0x1922},\n    {0x1927, 0x1928},   {0x1932, 0x1932},   {0x1939, 0x193B},\n    {0x1A17, 0x1A18},   {0x1B00, 0x1B03},   {0x1B34, 0x1B34},\n    {0x1B36, 0x1B3A},   {0x1B3C, 0x1B3C},   {0x1B42, 0x1B42},\n    {0x1B6B, 0x1B73},   {0x1DC0, 0x1DCA},   {0x1DFE, 0x1DFF},\n    {0x200B, 0x200F},   {0x202A, 0x202E},   {0x2060, 0x2063},\n    {0x206A, 0x206F},   {0x20D0, 0x20EF},   {0x302A, 0x302F},\n    {0x3099, 0x309A},   {0xA806, 0xA806},   {0xA80B, 0xA80B},\n    {0xA825, 0xA826},   {0xFB1E, 0xFB1E},   {0xFE00, 0xFE0F},\n    {0xFE20, 0xFE23},   {0xFEFF, 0xFEFF},   {0xFFF9, 0xFFFB},\n    {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},\n    {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},\n    {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},\n    {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},\n    {0xE0100, 0xE01EF}\n};\n\ntb_long_t xm_utf8_charwidth(xm_utf8_int_t val) {\n\n    // test for 8-bit control characters\n    if (val == 0) return 0;\n    if (val < 32 || (val >= 0x7f && val < 0xa0)) {\n        if (val == 0x09) return 4; // TAB\n        if (val == 0x08) return -1; // BS\n        return 0; // other control chars\n    }\n\n    // binary search in table of non-spacing characters\n    tb_long_t min = 0;\n    tb_long_t max = tb_arrayn(g_non_spacing) - 1;\n    if (val >= g_non_spacing[0].first && val <= g_non_spacing[max].last) {\n        while (max >= min) {\n            tb_long_t mid = (min + max) / 2;\n            if (val > g_non_spacing[mid].last) {\n                min = mid + 1;\n            } else if (val < g_non_spacing[mid].first) {\n                max = mid - 1;\n            } else {\n                return 0;\n            }\n        }\n    }\n\n    if  (val >= 0x1100 && (val <= 0x115f ||  // Hangul Jamo init. consonants\n        val == 0x2329 || val == 0x232a ||\n        (val >= 0x2e80 && val <= 0xa4cf &&\n        val != 0x303f) ||                    // CJK ... Yi\n        (val >= 0xac00 && val <= 0xd7a3) ||  // Hangul Syllables\n        (val >= 0xf900 && val <= 0xfaff) ||  // CJK Compatibility Ideographs\n        (val >= 0xfe10 && val <= 0xfe19) ||  // Vertical forms\n        (val >= 0xfe30 && val <= 0xfe6f) ||  // CJK Compatibility Forms\n        (val >= 0xff00 && val <= 0xff60) ||  // Fullwidth Forms\n        (val >= 0xffe0 && val <= 0xffe6) ||\n        (val >= 0x20000 && val <= 0x2fffd) ||\n        (val >= 0x30000 && val <= 0x3fffd))) {\n        return 2;\n    }\n\n    return 1;\n}\n\ntb_long_t xm_utf8_strwidth(tb_char_t const* s, tb_size_t len) {\n    tb_assert_and_check_return_val(s, -1);\n\n    tb_long_t width = 0;\n    tb_char_t const* p = s;\n    tb_char_t const* e = s + len;\n    while (p < e) {\n        xm_utf8_int_t val;\n        tb_char_t const* next = xm_utf8_decode(p, &val, tb_true);\n        if (next) {\n            tb_long_t w = xm_utf8_charwidth(val);\n            if (w < 0) return -1;\n            width += w;\n            p = next;\n        } else {\n            p++; // invalid byte, skip\n        }\n    }\n    return width;\n}\n\ntb_long_t xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos) {\n    tb_assert_and_check_return_val(s, -1);\n\n    tb_long_t n = 0;\n    while (posi <= posj) {\n        tb_char_t const* s1 = xm_utf8_decode(s + posi - 1, tb_null, strict);\n        if (s1 == tb_null) {\n            if (errpos) {\n                *errpos = posi;\n            }\n            return -1;\n        }\n        posi = s1 - s + 1;\n        n++;\n    }\n    return n;\n}\n\ntb_long_t xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi) {\n    tb_assert_and_check_return_val(s, -1);\n\n    // check\n    if (1 > posi || --posi > (tb_long_t)len) {\n        return -1; // error: position out of bounds\n    }\n\n    if (n == 0) {\n        // find beginning of current byte sequence\n        while (posi > 0 && xm_utf8_iscontp(s + posi)) {\n            posi--;\n        }\n    } else {\n        if (xm_utf8_iscontp(s + posi)) {\n            return -2; // error: initial position is a continuation byte\n        }\n\n        if (n < 0) {\n            while (n < 0 && posi > 0) {\n                do {\n                    posi--;\n                } while (posi > 0 && xm_utf8_iscontp(s + posi));\n                n++;\n            }\n        } else {\n            n--;\n            while (n > 0 && posi < (tb_long_t)len) {\n                do {\n                    posi++;\n                } while (xm_utf8_iscontp(s + posi));\n                n--;\n            }\n        }\n    }\n\n    if (n == 0) {\n        return posi + 1;\n    }\n    return 0; // nil\n}\n\ntb_bool_t xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) {\n    tb_assert_and_check_return_val(s, tb_false);\n\n    if (posi > posj) {\n        return tb_true;\n    }\n\n    tb_char_t const* se = s + posj;\n    for (s += posi - 1; s < se;) {\n        xm_utf8_int_t code;\n        s = xm_utf8_decode(s, &code, strict);\n        if (s == tb_null) {\n            return tb_false;\n        }\n        if (func && !func(code, udata)) {\n            return tb_false;\n        }\n    }\n    return tb_true;\n}\n\ntb_long_t xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end) {\n    tb_assert_and_check_return_val(s && sub, 0);\n\n    if (sublen == 0) {\n        if (init > (tb_long_t)len + 1) init = len + 1;\n\n        tb_long_t start_byte = 1;\n        if (init > 0) {\n            start_byte = xm_utf8_offset_impl(s, len, init, 1);\n        } else if (init < 0) {\n            start_byte = xm_utf8_offset_impl(s, len, init, len + 1);\n        }\n        if (start_byte <= 0) start_byte = 1;\n\n        tb_long_t char_pos = 1;\n        if (start_byte > 1) {\n            tb_long_t c = xm_utf8_len_impl(s, len, 1, start_byte - 1, tb_true, tb_null);\n            if (c >= 0) char_pos = c + 1;\n        }\n\n        if (pchar_end) *pchar_end = char_pos - 1;\n        return char_pos;\n    }\n\n    tb_long_t start_byte = 1;\n    if (init > 0) {\n        start_byte = xm_utf8_offset_impl(s, len, init, 1);\n    } else if (init < 0) {\n        start_byte = xm_utf8_offset_impl(s, len, init, len + 1);\n    }\n    if (start_byte <= 0) return 0;\n\n    tb_char_t const* p = tb_strstr(s + start_byte - 1, sub);\n    if (!p) return 0;\n\n    tb_long_t found_byte_start = p - s + 1;\n\n    tb_long_t char_start = 1;\n    if (found_byte_start > 1) {\n        tb_long_t c = xm_utf8_len_impl(s, len, 1, found_byte_start - 1, tb_true, tb_null);\n        if (c < 0) return 0;\n        char_start = c + 1;\n    }\n\n    if (pchar_end) {\n        tb_long_t match_len = xm_utf8_len_impl(s, len, found_byte_start, found_byte_start + sublen - 1, tb_true, tb_null);\n        if (match_len < 0) return 0;\n        *pchar_end = char_start + match_len - 1;\n    }\n\n    return char_start;\n}\n\ntb_long_t xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen) {\n    tb_assert_and_check_return_val(s && sub, 0);\n    tb_check_return_val(sublen, 0);\n\n    // optimize for single character search\n    if (sublen == 1) {\n        tb_char_t const* p = tb_strrchr(s, sub[0]);\n        return p ? (tb_long_t)(p - s + 1) : 0;\n    }\n\n    tb_char_t const* p = s;\n    tb_char_t const* last = tb_null;\n\n    while (1) {\n        p = tb_strstr(p, sub);\n        if (!p) break;\n        last = p;\n        p += 1;\n    }\n\n    if (last) {\n        return (tb_long_t)(last - s + 1);\n    }\n    return 0;\n}\n\ntb_long_t xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) {\n    tb_size_t sublen = 0;\n    tb_char_t const* sub = xm_utf8_sub_impl(s, len, i, j, &sublen);\n    if (sub && sublen > 0) {\n\n        // decode and push codepoints\n        tb_long_t n = 0;\n        tb_char_t const* p = sub;\n        tb_char_t const* e = sub + sublen;\n        while (p < e) {\n            xm_utf8_int_t val;\n            tb_char_t const* next = xm_utf8_decode(p, &val, tb_true);\n            if (next) {\n                if (func && !func(val, udata)) break;\n                n++;\n                p = next;\n            } else {\n                p++;\n            }\n        }\n        return n;\n    }\n    return 0;\n}\n\ntb_char_t const* xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen) {\n    tb_assert_and_check_return_val(s && psublen, tb_null);\n    *psublen = 0;\n\n    // map i (char index) to byte offset\n    tb_long_t start_byte = 0;\n    if (i > 0) {\n        start_byte = xm_utf8_offset_impl(s, len, i, 1);\n    } else if (i < 0) {\n        start_byte = xm_utf8_offset_impl(s, len, i, len + 1);\n    } else {\n        start_byte = 1;\n    }\n\n    if (start_byte == -1) {\n        if (i > 0) {\n            return \"\";\n        } else {\n            start_byte = 1;\n        }\n    } else if (start_byte == 0) {\n        if (i < 0) {\n            start_byte = 1;\n        } else {\n            return \"\";\n        }\n    }\n\n    // map j (char index) to byte offset (end)\n    tb_long_t end_byte = 0;\n    if (j >= 0) {\n        end_byte = xm_utf8_offset_impl(s, len, j + 1, 1);\n    } else {\n        end_byte = xm_utf8_offset_impl(s, len, j + 1, len + 1);\n    }\n\n    if (end_byte == -1) {\n        if (j >= 0) end_byte = len + 1;\n        else end_byte = 1;\n    } else if (end_byte == 0) {\n         if (j >= 0) end_byte = len + 1;\n         else end_byte = 1;\n    }\n\n    if (end_byte <= start_byte) {\n        return \"\";\n    }\n\n    *psublen = end_byte - start_byte;\n    return s + start_byte - 1;\n}\n\ntb_char_t* xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf) {\n    tb_assert_and_check_return_val(s && len && buf, tb_null);\n\n    tb_char_t const* p = s;\n    tb_char_t const* e = s + len;\n    tb_char_t* d = buf + len;\n\n    while (p < e) {\n        xm_utf8_int_t code;\n        tb_char_t const* next = xm_utf8_decode(p, &code, tb_false);\n\n        // invalid utf8? treat as 1 byte\n        tb_size_t n = 1;\n        if (next) {\n            n = next - p;\n        }\n\n        // safety check\n        if (p + n > e) n = e - p;\n\n        d -= n;\n        tb_memcpy(d, p, n);\n        p += n;\n    }\n    buf[len] = '\\0';\n    return buf;\n}\n\n"
  },
  {
    "path": "core/src/xmake/utf8/utf8.h",
    "content": "#ifndef XM_UTF8_UTF8_H\n#define XM_UTF8_UTF8_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n#define xm_utf8_iscont(c)    (((c) & 0xC0) == 0x80)\n#define xm_utf8_iscontp(p)   xm_utf8_iscont(*(p))\n\n#define XM_UTF8_MAXUNICODE  0x10FFFFu\n#define XM_UTF8_MAXUTF      0x7FFFFFFFu\n#define XM_UTF8_MSGInvalid  \"invalid UTF-8 code\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef tb_uint32_t xm_utf8_int_t;\ntypedef tb_bool_t (*xm_utf8_codepoint_func_t)(xm_utf8_int_t code, tb_cpointer_t udata);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * inline interfaces\n */\nstatic __tb_inline__ tb_long_t xm_utf8_posrelat(tb_long_t pos, tb_size_t len) {\n    if (pos >= 0) {\n        return pos;\n    } else if (0u - (tb_size_t)pos > len) {\n        return 0;\n    } else {\n        return (tb_long_t)len + pos + 1;\n    }\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\ntb_char_t const*    xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict);\ntb_size_t           xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val);\ntb_long_t           xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos);\ntb_long_t           xm_utf8_charwidth(xm_utf8_int_t val);\ntb_long_t           xm_utf8_strwidth(tb_char_t const* s, tb_size_t len);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation interfaces\n */\ntb_long_t           xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos);\ntb_long_t           xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi);\ntb_bool_t           xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata);\ntb_long_t           xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end);\ntb_long_t           xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen);\ntb_long_t           xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata);\ntb_char_t const*    xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen);\ntb_char_t*          xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf);\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/utf8/width.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        width.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"utf8.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/* utf8.width(char)\n * utf8.width(str)\n * utf8.width(codepoint)\n */\ntb_int_t xm_utf8_width(lua_State* lua) {\n    if (lua_isnumber(lua, 1)) {\n        xm_utf8_int_t val = (xm_utf8_int_t)lua_tointeger(lua, 1);\n        lua_pushinteger(lua, xm_utf8_charwidth(val));\n    } else {\n        size_t len = 0;\n        tb_char_t const* s = luaL_checklstring(lua, 1, &len);\n        lua_pushinteger(lua, xm_utf8_strwidth(s, len));\n    }\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/utils/charset.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        charset.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"charset\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"charset.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\n\n// the charsets, @note: type & name is sorted\nstatic xm_charset_entry_t g_charsets[] = {\n    { TB_CHARSET_TYPE_ANSI, \"ansi\" },\n    { TB_CHARSET_TYPE_ASCII, \"ascii\" },\n    { TB_CHARSET_TYPE_GB2312, \"gb2312\" },\n    { TB_CHARSET_TYPE_GBK, \"gbk\" },\n    { TB_CHARSET_TYPE_ISO8859, \"iso8859\" },\n    { TB_CHARSET_TYPE_UCS2 | TB_CHARSET_TYPE_NE, \"ucs2\" },\n    { TB_CHARSET_TYPE_UCS4 | TB_CHARSET_TYPE_NE, \"ucs4\" },\n    { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, \"utf16\" },\n    { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE, \"utf16be\" },\n    { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, \"utf16bom\" },\n    { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, \"utf16le\" },\n    { TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, \"utf16lebom\" },\n    { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_NE, \"utf32\" },\n    { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_BE, \"utf32be\" },\n    { TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_LE, \"utf32le\" },\n    { TB_CHARSET_TYPE_UTF8, \"utf8\" },\n    { TB_CHARSET_TYPE_UTF8, \"utf8bom\" },\n};\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * finder\n */\nstatic tb_long_t xm_charset_comp_by_name(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t name) {\n    return tb_stricmp(((xm_charset_entry_ref_t)item)->name, (tb_char_t const *)name);\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\nxm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name) {\n    // make iterator\n    tb_array_iterator_t array_iterator;\n    tb_iterator_ref_t   iterator =\n        tb_array_iterator_init_mem(&array_iterator, g_charsets, tb_arrayn(g_charsets), sizeof(xm_charset_entry_t));\n    tb_assert_and_check_return_val(iterator, tb_null);\n\n    // find it by the binary search\n    tb_size_t itor = tb_binary_find_all_if(iterator, xm_charset_comp_by_name, name);\n    if (itor != tb_iterator_tail(iterator)) {\n        return (xm_charset_entry_ref_t)tb_iterator_item(iterator, itor);\n    } else {\n        return tb_null;\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/utils/charset.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        charset.h\n *\n */\n#ifndef XM_UTILS_CHARSET_H\n#define XM_UTILS_CHARSET_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the charset entry type\ntypedef struct __xm_charset_entry_t {\n    // the charset type\n    tb_size_t type;\n\n    // the charset name\n    tb_char_t const *name;\n} xm_charset_entry_t, *xm_charset_entry_ref_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/* find charset by name\n *\n * @param name  the charset name\n *\n * @return      the charset entry\n */\nxm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name);\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/utils/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_UTILS_PREFIX_H\n#define XM_UTILS_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/winos/ansi.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu\n * @file        ansi.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"ansi\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"ansi.h\"\n#include <windows.h>\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\nstatic tb_int_t xm_expand_cp(tb_int_t cp) {\n    tb_assert_and_check_return_val(cp >= 0 && cp <= 65535, 0);\n\n    if (cp == CP_OEMCP) {\n        return GetOEMCP();\n    }\n    if (cp == CP_ACP) {\n        return GetACP();\n    }\n    return cp;\n}\n\ntb_int_t xm_winos_console_cp(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_int_t n = lua_gettop(lua);\n    if (n >= 1) {\n        lua_Integer cp = luaL_checkinteger(lua, 1);\n        luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, \"invalid code page\");\n        cp = xm_expand_cp((tb_uint_t)cp);\n        luaL_argcheck(lua, SetConsoleCP((tb_uint_t)cp), 1, \"failed to set code page\");\n        lua_pushinteger(lua, cp);\n        return 1;\n    } else {\n        tb_uint_t cp = GetConsoleCP();\n        lua_pushinteger(lua, (lua_Integer)cp);\n        return 1;\n    }\n}\n\ntb_int_t xm_winos_console_output_cp(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_int_t n = lua_gettop(lua);\n    if (n >= 1) {\n        lua_Integer cp = luaL_checkinteger(lua, 1);\n        luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, \"invalid code page\");\n        cp = xm_expand_cp((tb_uint_t)cp);\n        luaL_argcheck(lua, SetConsoleOutputCP((tb_uint_t)cp), 1, \"failed to set code page\");\n        lua_pushinteger(lua, cp);\n        return 1;\n    } else {\n        tb_uint_t cp = GetConsoleOutputCP();\n        lua_pushinteger(lua, (lua_Integer)cp);\n        return 1;\n    }\n}\n\ntb_int_t xm_winos_cp_info(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    lua_Integer cp = luaL_checkinteger(lua, 1);\n    luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, \"invalid code page\");\n    CPINFOEX cp_info;\n    luaL_argcheck(lua, GetCPInfoEx((tb_uint_t)cp, 0, &cp_info), 1, \"invalid code page\");\n\n    lua_newtable(lua);\n\n    lua_pushliteral(lua, \"name\");\n    tb_char_t *namebuf = tb_malloc_cstr(sizeof(cp_info.CodePageName) * 2);\n    tb_assert_and_check_return_val(namebuf, 0);\n    tb_size_t namelen = tb_wtoa(namebuf, (const tb_wchar_t *)cp_info.CodePageName, sizeof(cp_info.CodePageName) * 2);\n    tb_assert_and_check_return_val(namelen < sizeof(cp_info.CodePageName) * 2, 0);\n    lua_pushlstring(lua, namebuf, namelen);\n    tb_free(namebuf);\n    lua_settable(lua, -3);\n\n    lua_pushliteral(lua, \"max_char_size\");\n    lua_pushinteger(lua, (lua_Integer)cp_info.MaxCharSize);\n    lua_settable(lua, -3);\n\n    lua_pushliteral(lua, \"id\");\n    lua_pushinteger(lua, (lua_Integer)cp_info.CodePage);\n    lua_settable(lua, -3);\n\n    lua_pushliteral(lua, \"default_char\");\n    lua_pushstring(lua, (tb_char_t const *)cp_info.DefaultChar);\n    lua_settable(lua, -3);\n\n    lua_pushliteral(lua, \"lead_byte\");\n    lua_createtable(lua, MAX_LEADBYTES / 2, 0);\n    for (tb_size_t i = 0; i < MAX_LEADBYTES && cp_info.LeadByte[i] != 0 && cp_info.LeadByte[i + 1] != 0; i += 2) {\n        lua_pushinteger(lua, (i / 2) + 1);\n        lua_createtable(lua, 0, 2);\n\n        lua_pushliteral(lua, \"from\");\n        lua_pushinteger(lua, cp_info.LeadByte[i]);\n        lua_settable(lua, -3);\n\n        lua_pushliteral(lua, \"to\");\n        lua_pushinteger(lua, cp_info.LeadByte[i + 1]);\n        lua_settable(lua, -3);\n\n        lua_settable(lua, -3);\n    }\n    lua_settable(lua, -3);\n\n    return 1;\n}\n\ntb_int_t xm_winos_ansi_cp(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_uint_t cp = GetACP();\n    lua_pushinteger(lua, (lua_Integer)cp);\n    return 1;\n}\n\ntb_int_t xm_winos_oem_cp(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    tb_uint_t cp = GetOEMCP();\n    lua_pushinteger(lua, (lua_Integer)cp);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/winos/ansi.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      OpportunityLiu\n * @file        ansi.h\n *\n */\n#ifndef XM_WINOS_ANSI_H\n#define XM_WINOS_ANSI_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/winos/file_signature.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        file_signature.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"file_signature\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include <windows.h>\n#include <wintrust.h>\n#include <softpub.h>\n#include <wincrypt.h>\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the file signature info type\ntypedef struct __tb_file_signature_info_t {\n    // is the file digitally signed?\n    tb_bool_t           is_signed;\n\n    // is the signature valid and trusted by the OS?\n    tb_bool_t           is_trusted;\n\n    /* the name of the signer (e.g., \"Microsoft Corporation\")\n       tbox uses UTF-8 by default for tb_char_t\n     */\n    tb_char_t           signer_name[256];\n} tb_file_signature_info_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\n\nstatic tb_bool_t tb_file_get_signature_info(tb_char_t const* filepath, tb_file_signature_info_t* info) {\n    tb_assert_and_check_return_val(filepath && info, tb_false);\n\n    // init info\n    tb_memset(info, 0, sizeof(tb_file_signature_info_t));\n\n    // convert path\n    tb_wchar_t wide_path[TB_PATH_MAXN];\n    if (!tb_path_absolute_w(filepath, wide_path, TB_PATH_MAXN)) {\n        return tb_false;\n    }\n    \n    // init file info\n    WINTRUST_FILE_INFO file_data = {0};\n    file_data.cbStruct = sizeof(file_data);\n    file_data.pcwszFilePath = wide_path;\n    file_data.hFile = NULL;\n    file_data.pgKnownSubject = NULL;\n\n    // init trust data\n    WINTRUST_DATA trust_data = {0};\n    trust_data.cbStruct = sizeof(trust_data);\n    trust_data.dwUIChoice = WTD_UI_NONE;\n    trust_data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;\n    trust_data.dwUnionChoice = WTD_CHOICE_FILE;\n    trust_data.dwStateAction = WTD_STATEACTION_VERIFY;\n    trust_data.hWVTStateData = NULL;\n    trust_data.pwszURLReference = NULL;\n    trust_data.dwProvFlags = WTD_SAFER_FLAG;\n    trust_data.dwUIContext = 0;\n    trust_data.pFile = &file_data;\n\n    // verify trust\n    GUID guid_action = WINTRUST_ACTION_GENERIC_VERIFY_V2;\n    LONG status = WinVerifyTrust(NULL, &guid_action, &trust_data);\n\n    // clean up\n    trust_data.dwStateAction = WTD_STATEACTION_CLOSE;\n    WinVerifyTrust(NULL, &guid_action, &trust_data);\n\n    // check status\n    if (status == ERROR_SUCCESS) {\n        info->is_signed = tb_true;\n        info->is_trusted = tb_true;\n    } else if (status == TRUST_E_NOSIGNATURE) {\n        return tb_true;\n    } else if (status == TRUST_E_EXPLICIT_DISTRUST || status == TRUST_E_SUBJECT_NOT_TRUSTED) {\n        info->is_signed = tb_true;\n        info->is_trusted = tb_false;\n    } else {\n        return tb_false;\n    }\n\n    // extract signer name\n    if (info->is_signed) {\n        HCERTSTORE hStore = NULL;\n        HCRYPTMSG hMsg = NULL;\n        DWORD dwEncoding = 0;\n        DWORD dwContentType = 0;\n        DWORD dwFormatType = 0;\n        PCMSG_SIGNER_INFO pSignerInfo = NULL;\n        PCCERT_CONTEXT pCertContext = NULL;\n        BOOL bResult = FALSE;\n\n        bResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,\n                                   wide_path,\n                                   CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,\n                                   CERT_QUERY_FORMAT_FLAG_BINARY,\n                                   0,\n                                   &dwEncoding,\n                                   &dwContentType,\n                                   &dwFormatType,\n                                   &hStore,\n                                   &hMsg,\n                                   NULL);\n\n        if (bResult) {\n            DWORD cbSignerInfo = 0;\n            if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cbSignerInfo)) {\n                pSignerInfo = (PCMSG_SIGNER_INFO)tb_malloc(cbSignerInfo);\n                if (pSignerInfo) {\n                    if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (void*)pSignerInfo, &cbSignerInfo)) {\n                        CERT_INFO certInfo;\n                        certInfo.Issuer = pSignerInfo->Issuer;\n                        certInfo.SerialNumber = pSignerInfo->SerialNumber;\n\n                        pCertContext = CertFindCertificateInStore(hStore,\n                                                                  (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),\n                                                                  0,\n                                                                  CERT_FIND_SUBJECT_CERT,\n                                                                  (PVOID)&certInfo,\n                                                                  NULL);\n\n                        if (pCertContext) {\n                            tb_wchar_t wName[256] = {0};\n                            if (CertGetNameStringW(pCertContext,\n                                                   CERT_NAME_SIMPLE_DISPLAY_TYPE,\n                                                   0,\n                                                   NULL,\n                                                   wName,\n                                                   256)) {\n                                tb_wtoa(info->signer_name, wName, sizeof(info->signer_name));\n                            }\n                            CertFreeCertificateContext(pCertContext);\n                        }\n                    }\n                    tb_free(pSignerInfo);\n                }\n            }\n        }\n\n        if (hStore) CertCloseStore(hStore, 0);\n        if (hMsg) CryptMsgClose(hMsg);\n    }\n\n    return tb_true;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get the file signature info\n *\n * local info = winos.file_signature(filepath)\n * {\n *      is_signed = true,\n *      is_trusted = true,\n *      signer_name = \"Microsoft Corporation\"\n * }\n */\ntb_int_t xm_winos_file_signature(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the arguments\n    tb_char_t const *filepath = luaL_checkstring(lua, 1);\n    tb_check_return_val(filepath, 0);\n\n    // get signature info\n    tb_file_signature_info_t info = {0};\n    if (tb_file_get_signature_info(filepath, &info)) {\n        lua_newtable(lua);\n        lua_pushstring(lua, \"is_signed\");\n        lua_pushboolean(lua, info.is_signed);\n        lua_settable(lua, -3);\n\n        lua_pushstring(lua, \"is_trusted\");\n        lua_pushboolean(lua, info.is_trusted);\n        lua_settable(lua, -3);\n\n        if (info.is_signed) {\n            lua_pushstring(lua, \"signer_name\");\n            lua_pushstring(lua, info.signer_name);\n            lua_settable(lua, -3);\n        }\n        return 1;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "core/src/xmake/winos/logical_drives.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        logical_drives.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"logical_drives\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n// get the logical drives\ntb_int_t xm_winos_logical_drives(lua_State *lua) {\n    // init table\n    lua_newtable(lua);\n\n    // get logical drives\n    tb_char_t *data = tb_null;\n    do {\n        // get buffer size\n        DWORD size = GetLogicalDriveStringsA(0, tb_null);\n        tb_assert_and_check_break(size);\n\n        // make data buffer\n        data = (tb_char_t *)tb_malloc0(size + 1);\n        tb_assert_and_check_break(data);\n\n        // get logical drives\n        size = GetLogicalDriveStringsA(size, data);\n        tb_assert_and_check_break(size);\n\n        // parse logical drives\n        tb_size_t i = 1;\n        tb_char_t const *p = data;\n        while (*p) {\n            // save drive\n            lua_pushinteger(lua, i++);\n            lua_pushstring(lua, p);\n            lua_settable(lua, -3);\n\n            // next drive\n            p += tb_strlen(p) + 1;\n        }\n    } while (0);\n\n    // exit data\n    if (data) {\n        tb_free(data);\n    }\n    data = tb_null;\n\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/winos/prefix.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        prefix.h\n *\n */\n#ifndef XM_WINOS_PREFIX_H\n#define XM_WINOS_PREFIX_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"../prefix.h\"\n#ifdef TB_CONFIG_OS_WINDOWS\n#include <windows.h>\n#endif\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/winos/registry_keys.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        registry_keys.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"registry_keys\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n\n// the enum info type\ntypedef struct __xm_winos_registry_enum_info_t {\n    lua_State *lua;\n    HKEY key;\n    tb_int_t ok;\n    tb_char_t const *error;\n    tb_int_t count;\n    tb_wchar_t key_name[1024];\n    tb_char_t key_path_a[TB_PATH_MAXN];\n} xm_winos_registry_enum_info_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic tb_void_t xm_winos_registry_enum_keys(xm_winos_registry_enum_info_t *info,\n                                             tb_wchar_t const              *rootdir,\n                                             tb_long_t                      recursion) {\n    // enum keys\n    HKEY keynew = tb_null;\n    lua_State *lua = info->lua;\n    tb_wchar_t *key_path = tb_null;\n    tb_size_t key_path_maxn = TB_PATH_MAXN;\n    do {\n        // open registry key\n        if (RegOpenKeyExW(info->key, rootdir, 0, KEY_READ, &keynew) != ERROR_SUCCESS && keynew) {\n            info->ok    = -1;\n            info->error = \"open registry key failed\";\n            break;\n        }\n\n        // query keys\n        DWORD key_name_num  = 0;\n        DWORD key_name_maxn = 0;\n        if (RegQueryInfoKeyW(keynew,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             &key_name_num,\n                             &key_name_maxn,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null) != ERROR_SUCCESS) {\n            // cannot query this key, we ignore it\n            break;\n        }\n        key_name_maxn++; // add `\\0`\n\n        // ensure enough key path buffer\n        if (key_name_maxn > tb_arrayn(info->key_name)) {\n            info->ok    = -1;\n            info->error = \"no enough key path buffer\";\n            break;\n        }\n\n        // init key path\n        key_path = (tb_wchar_t *)tb_malloc(key_path_maxn * sizeof(tb_wchar_t));\n        if (!key_path) {\n            info->ok    = -1;\n            info->error = \"no enough key path buffer\";\n            break;\n        }\n\n        // get all keys\n        DWORD i = 0;\n        for (i = 0; i < key_name_num && info->ok > 0; i++) {\n            // get key name\n            info->key_name[0] = L'\\0';\n            DWORD key_name_size = tb_arrayn(info->key_name);\n            if (RegEnumKeyExW(keynew, i, info->key_name, &key_name_size, tb_null, tb_null, tb_null, tb_null) !=\n                ERROR_SUCCESS) {\n                info->ok    = -1;\n                info->error = \"get registry key failed\";\n                break;\n            }\n\n            // get key path\n            tb_swprintf(key_path, key_path_maxn, L\"%s\\\\%s\", rootdir, info->key_name);\n\n            // get key path (mbs)\n            tb_size_t key_path_a_size = tb_wtoa(info->key_path_a, key_path, sizeof(info->key_path_a));\n            if (key_path_a_size == -1) {\n                info->ok    = -1;\n                info->error = \"convert registry key path failed\";\n                break;\n            }\n\n            // do callback(key_name)\n            lua_pushvalue(lua, 4);\n            lua_pushlstring(lua, info->key_path_a, key_path_a_size);\n            lua_call(lua, 1, 1);\n            info->count++;\n\n            // is continue?\n            tb_bool_t is_continue = lua_toboolean(lua, -1);\n            lua_pop(lua, 1);\n            if (!is_continue) {\n                info->ok = 0;\n                break;\n            }\n\n            // enum all subkeys\n            if (recursion > 0 || recursion < 0) {\n                xm_winos_registry_enum_keys(info, key_path, recursion > 0 ? recursion - 1 : recursion);\n            }\n        }\n\n    } while (0);\n\n    // exit registry key\n    if (keynew) {\n        RegCloseKey(keynew);\n    }\n    keynew = tb_null;\n\n    // free key path\n    if (key_path) {\n        tb_free(key_path);\n    }\n    key_path = tb_null;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get registry keys\n *\n * local count, errors = winos.registry_keys(\"HKEY_LOCAL_MACHINE\",\n *                                             \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\",\n *                                             function (key_path)\n *                                                 return true -- continue or break\n *                                             end)\n */\ntb_int_t xm_winos_registry_keys(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the arguments\n    tb_char_t const *rootkey = luaL_checkstring(lua, 1);\n    tb_char_t const *rootdir = luaL_checkstring(lua, 2);\n    tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3);\n    tb_bool_t is_function = lua_isfunction(lua, 4);\n    tb_check_return_val(rootkey && rootdir && is_function, 0);\n\n    // enum keys\n    tb_bool_t ok = tb_false;\n    tb_int_t count = 0;\n    HKEY key = tb_null;\n    do {\n        // get registry rootkey\n        if (!tb_strcmp(rootkey, \"HKEY_CLASSES_ROOT\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKCR\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_CONFIG\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKCC\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_USER\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKCU\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKEY_LOCAL_MACHINE\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKLM\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKEY_USERS\")) {\n            key = HKEY_USERS;\n        } else {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid registry rootkey: %s\", rootkey);\n            break;\n        }\n\n        // do enum\n        tb_wchar_t rootdir_w[TB_PATH_MAXN];\n        if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == -1) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"rootdir is too long: %s\", rootdir);\n            break;\n        }\n        xm_winos_registry_enum_info_t info;\n        info.lua   = lua;\n        info.key   = key;\n        info.count = 0;\n        info.ok    = tb_true;\n        info.error = tb_null;\n        xm_winos_registry_enum_keys(&info, rootdir_w, recursion);\n        count = info.count;\n        ok    = info.ok >= 0;\n        if (!ok) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"%s: %s\\\\%s\", info.error ? info.error : \"enum registry keys failed\", rootkey, rootdir);\n        }\n\n    } while (0);\n\n    if (ok) {\n        lua_pushinteger(lua, count);\n        return 1;\n    } else {\n        return 2;\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/winos/registry_query.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      TitanSnow, ruki\n * @file        registry_query.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"registry_query\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\n// the RegGetValueW func type\ntypedef BOOL(WINAPI *xm_RegGetValueW_t)(\n    HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* query registry\n *\n * local value, errors = winos.registry_query(\"HKEY_LOCAL_MACHINE\", \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\", \"Debugger\")\n */\ntb_int_t xm_winos_registry_query(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the arguments\n    tb_char_t const *rootkey = luaL_checkstring(lua, 1);\n    tb_char_t const *rootdir = luaL_checkstring(lua, 2);\n    tb_char_t const *valuename = luaL_checkstring(lua, 3);\n    tb_check_return_val(rootkey && rootdir && valuename, 0);\n\n    // query key-value\n    tb_bool_t ok = tb_false;\n    HKEY key = tb_null;\n    HKEY keynew = tb_null;\n    tb_char_t *value = tb_null;\n    tb_wchar_t *value_w = tb_null;\n    tb_size_t value_n = (tb_size_t)-1;\n    do {\n        // get registry rootkey\n        if (!tb_strcmp(rootkey, \"HKEY_CLASSES_ROOT\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKCR\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_CONFIG\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKCC\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_USER\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKCU\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKEY_LOCAL_MACHINE\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKLM\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKEY_USERS\")) {\n            key = HKEY_USERS;\n        } else {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid registry rootkey: %s\", rootkey);\n            break;\n        }\n\n        // convert rootdir to wide characters\n        tb_wchar_t rootdir_w[TB_PATH_MAXN];\n        if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == (tb_size_t)-1) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid registry rootkey:: %s\", rootdir);\n            break;\n        }\n\n        // convert valuename to wide characters\n        tb_wchar_t valuename_w[TB_PATH_MAXN];\n        if (tb_atow(valuename_w, valuename, TB_PATH_MAXN) == (tb_size_t)-1) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid registry valuename: %s\", valuename);\n            break;\n        }\n\n        // attempt to load RegGetValueW\n        static xm_RegGetValueW_t s_RegGetValueW = tb_null;\n        if (!s_RegGetValueW) {\n            // load the advapi32 module\n            tb_dynamic_ref_t module = (tb_dynamic_ref_t)GetModuleHandleA(\"advapi32.dll\");\n            if (!module)\n                module = tb_dynamic_init(\"advapi32.dll\");\n            if (module)\n                s_RegGetValueW = (xm_RegGetValueW_t)tb_dynamic_func(module, \"RegGetValueW\");\n        }\n\n        // get registry value\n        DWORD type = 0;\n        if (s_RegGetValueW) {\n            // get registry value size\n            DWORD valuesize_w = 0;\n            if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, 0, tb_null, &valuesize_w) != ERROR_SUCCESS) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"get registry value size failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n\n            // make value buffer\n            DWORD valuesize = valuesize_w * 2;\n            value           = (tb_char_t *)tb_malloc0(valuesize);\n            tb_assert_and_check_break(value);\n            value_w = (tb_wchar_t *)tb_malloc0(valuesize_w);\n            tb_assert_and_check_break(value_w);\n\n            // get value result, we attempt to do not expand value if get failed\n            type = 0;\n            if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, &type, (PVOID)value_w, &valuesize_w) !=\n                    ERROR_SUCCESS &&\n                s_RegGetValueW(\n                    key, rootdir_w, valuename_w, RRF_RT_ANY | RRF_NOEXPAND, &type, (PVOID)value_w, &valuesize_w) !=\n                    ERROR_SUCCESS) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"get registry value failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n\n            value_n = tb_wtoa(value, value_w, valuesize);\n            if (value_n == (tb_size_t)-1) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"wtoa registry value failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n        } else {\n            // open registry key\n            if (RegOpenKeyExW(key, rootdir_w, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"open registry key failed: %s\\\\%s\", rootkey, rootdir);\n                break;\n            }\n\n            // get registry value size\n            DWORD valuesize_w = 0;\n            if (RegQueryValueExW(keynew, valuename_w, tb_null, tb_null, tb_null, &valuesize_w) != ERROR_SUCCESS) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"get registry value size failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n\n            // make value buffer\n            DWORD valuesize = valuesize_w * 2;\n            value           = (tb_char_t *)tb_malloc0(valuesize);\n            tb_assert_and_check_break(value);\n            value_w = (tb_wchar_t *)tb_malloc0(valuesize_w);\n            tb_assert_and_check_break(value_w);\n\n            // get value result\n            type = 0;\n            if (RegQueryValueExW(keynew, valuename_w, tb_null, &type, (LPBYTE)value_w, &valuesize_w) != ERROR_SUCCESS) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"get registry value failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n\n            value_n = tb_wtoa(value, value_w, valuesize);\n            if (value_n == (tb_size_t)-1) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"wtoa registry value failed: %s\\\\%s;%s\", rootkey, rootdir, valuename);\n                break;\n            }\n        }\n\n        // save result\n        switch (type) {\n        case REG_SZ:\n        case REG_EXPAND_SZ:\n            lua_pushlstring(lua, value, value_n);\n            ok = tb_true;\n            break;\n        case REG_DWORD:\n            lua_pushfstring(lua, \"%d\", *((tb_int_t *)value));\n            ok = tb_true;\n            break;\n        case REG_QWORD:\n            lua_pushfstring(lua, \"%lld\", *((tb_int64_t *)value));\n            ok = tb_true;\n            break;\n        default:\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"unsupported registry value type: %d\", type);\n            break;\n        }\n\n    } while (0);\n\n    // exit registry key\n    if (keynew) {\n        RegCloseKey(keynew);\n    }\n    keynew = tb_null;\n\n    // exit value\n    if (value) {\n        tb_free(value);\n    }\n    value = tb_null;\n    if (value_w) {\n        tb_free(value_w);\n    }\n    value_w = tb_null;\n\n    return ok ? 1 : 2;\n}\n"
  },
  {
    "path": "core/src/xmake/winos/registry_values.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        registry_values.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"registry_values\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get registry values\n *\n * local count, errors = winos.registry_values(\"HKEY_LOCAL_MACHINE\",\n *                                             \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\",\n *                                             function (value_name)\n *                                                 return true -- continue or break\n *                                             end)\n */\ntb_int_t xm_winos_registry_values(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the arguments\n    tb_char_t const *rootkey = luaL_checkstring(lua, 1);\n    tb_char_t const *rootdir = luaL_checkstring(lua, 2);\n    tb_bool_t is_function = lua_isfunction(lua, 3);\n    tb_check_return_val(rootkey && rootdir && is_function, 0);\n\n    // enum values\n    tb_bool_t ok = tb_false;\n    tb_int_t count = 0;\n    HKEY key = tb_null;\n    HKEY keynew = tb_null;\n    do {\n        // get registry rootkey\n        if (!tb_strcmp(rootkey, \"HKEY_CLASSES_ROOT\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKCR\")) {\n            key = HKEY_CLASSES_ROOT;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_CONFIG\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKCC\")) {\n            key = HKEY_CURRENT_CONFIG;\n        } else if (!tb_strcmp(rootkey, \"HKEY_CURRENT_USER\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKCU\")) {\n            key = HKEY_CURRENT_USER;\n        } else if (!tb_strcmp(rootkey, \"HKEY_LOCAL_MACHINE\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKLM\")) {\n            key = HKEY_LOCAL_MACHINE;\n        } else if (!tb_strcmp(rootkey, \"HKEY_USERS\")) {\n            key = HKEY_USERS;\n        } else {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"invalid registry rootkey: %s\", rootkey);\n            break;\n        }\n\n        // open registry key\n        if (RegOpenKeyExA(key, rootdir, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"open registry key failed: %s\\\\%s\", rootkey, rootdir);\n            break;\n        }\n\n        // query values\n        DWORD value_name_num  = 0;\n        DWORD value_name_maxn = 0;\n        if (RegQueryInfoKeyW(keynew,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             tb_null,\n                             &value_name_num,\n                             &value_name_maxn,\n                             tb_null,\n                             tb_null,\n                             tb_null) != ERROR_SUCCESS) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"query registry info failed: %s\\\\%s\", rootkey, rootdir);\n            break;\n        }\n        value_name_maxn++; // add `\\0`\n\n        // ensure enough value name buffer\n        tb_wchar_t value_name[1024];\n        if (value_name_maxn > tb_arrayn(value_name)) {\n            lua_pushnil(lua);\n            lua_pushfstring(lua, \"no enough value name buffer: %s\\\\%s\", rootkey, rootdir);\n            break;\n        }\n\n        // get all values\n        DWORD i = 0;\n        tb_char_t value_name_a[1024];\n        for (i = 0; i < value_name_num; i++) {\n            // get value name\n            value_name[0]         = L'\\0';\n            DWORD value_name_size = tb_arrayn(value_name);\n            if (RegEnumValueW(keynew, i, value_name, &value_name_size, tb_null, tb_null, tb_null, tb_null) !=\n                ERROR_SUCCESS) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"get registry value name(%d) failed: %s\\\\%s\", i, rootkey, rootdir);\n                break;\n            }\n\n            // get value name (mbs)\n            tb_size_t value_name_a_size = tb_wtoa(value_name_a, value_name, sizeof(value_name_a));\n            if (value_name_a_size == -1) {\n                lua_pushnil(lua);\n                lua_pushfstring(lua, \"convert registry value name(%d) failed: %s\\\\%s\", i, rootkey, rootdir);\n                break;\n            }\n\n            // do callback(value_name)\n            lua_pushvalue(lua, 3);\n            lua_pushlstring(lua, value_name_a, value_name_a_size);\n            lua_call(lua, 1, 1);\n            count++;\n\n            // is continue?\n            tb_bool_t is_continue = lua_toboolean(lua, -1);\n            lua_pop(lua, 1);\n            if (!is_continue) {\n                ok = tb_true;\n                break;\n            }\n        }\n\n        if (i == value_name_num)\n            ok = tb_true;\n\n    } while (0);\n\n    // exit registry key\n    if (keynew) {\n        RegCloseKey(keynew);\n    }\n    keynew = tb_null;\n\n    if (ok) {\n        lua_pushinteger(lua, count);\n        return 1;\n    } else {\n        return 2;\n    }\n}\n"
  },
  {
    "path": "core/src/xmake/winos/set_error_mode.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        set_error_mode.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"set_error_mode\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\ntb_int_t xm_winos_set_error_mode(lua_State *lua) {\n    tb_size_t mode = (tb_size_t)luaL_checkinteger(lua, 1);\n    lua_pushinteger(lua, (tb_int_t)SetErrorMode((UINT)mode));\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/winos/short_path.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        short_path.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * trace\n */\n#define TB_TRACE_MODULE_NAME \"short_path\"\n#define TB_TRACE_MODULE_DEBUG (0)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\n\n/* get windows short path from long path\n *\n * local short_path, errors = winos.short_path(long_path)\n */\ntb_int_t xm_winos_short_path(lua_State *lua) {\n    tb_assert_and_check_return_val(lua, 0);\n\n    // get the arguments\n    tb_char_t const *long_path = luaL_checkstring(lua, 1);\n    tb_check_return_val(long_path, 0);\n\n    // convert long path to wide characters\n    tb_wchar_t long_path_w[TB_PATH_MAXN];\n    if (tb_atow(long_path_w, long_path, TB_PATH_MAXN) == (tb_size_t)-1) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid long path: %s\", long_path);\n        return 2;\n    }\n\n    // get short path\n    tb_wchar_t short_path_w[TB_PATH_MAXN];\n    if (GetShortPathNameW(long_path_w, short_path_w, TB_PATH_MAXN) == 0) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"cannot get short path from: %s\", long_path);\n        return 2;\n    }\n\n    // return result\n    tb_char_t *short_path_a = (tb_char_t *)long_path_w;\n    tb_size_t short_path_n = tb_wtoa(short_path_a, short_path_w, TB_PATH_MAXN);\n    if (short_path_n == (tb_size_t)-1) {\n        lua_pushnil(lua);\n        lua_pushfstring(lua, \"invalid short path from %s!\", long_path);\n        return 2;\n    }\n    lua_pushlstring(lua, short_path_a, short_path_n);\n    return 1;\n}\n"
  },
  {
    "path": "core/src/xmake/xmake.c",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        xmake.c\n *\n */\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmake.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * private implementation\n */\nstatic __tb_inline__ tb_bool_t xm_check_mode(tb_size_t mode) {\n#ifdef __xm_debug__\n    if (!(mode & TB_MODE_DEBUG)) {\n        tb_trace_e(\"libxmake.a has __tb_debug__ but xmake/xmake.h not\");\n        return tb_false;\n    }\n#else\n    if (mode & TB_MODE_DEBUG) {\n        tb_trace_e(\"xmake/xmake.h has __tb_debug__ but libxmake.a not\");\n        return tb_false;\n    }\n#endif\n\n#ifdef __xm_small__\n    if (!(mode & TB_MODE_SMALL)) {\n        tb_trace_e(\"libxmake.a has __tb_small__ but xmake/xmake.h not\");\n        return tb_false;\n    }\n#else\n    if (mode & TB_MODE_SMALL) {\n        tb_trace_e(\"xmake/xmake.h has __tb_small__ but libxmake.a not\");\n        return tb_false;\n    }\n#endif\n\n    return tb_true;\n}\nstatic __tb_inline__ tb_bool_t xm_version_check(tb_hize_t build) {\n    // the version oly for link the static vtag string\n    tb_version_t const *version = xm_version();\n    tb_used(version);\n\n    if ((build / 100) == (XM_VERSION_BUILD / 100)) {\n        tb_trace_d(\"version: %s\", XM_VERSION_STRING);\n        return tb_true;\n    } else {\n        tb_trace_w(\"version: %s != %llu\", XM_VERSION_STRING, build);\n    }\n\n    // no\n    return tb_false;\n}\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * implementation\n */\ntb_bool_t xm_init_(tb_size_t mode, tb_hize_t build) {\n    tb_trace_d(\"init: ..\");\n\n    // check mode\n    if (!xm_check_mode(mode)) {\n        return tb_false;\n    }\n\n    // check version\n    xm_version_check(build);\n\n#if 0\n    // init tbox, we always use the tbox's default allocator\n    if (!tb_init(tb_null, tb_default_allocator(tb_null, 0))) return tb_false;\n#else\n    // init tbox, since small compilation mode is enabled, it still uses the native allocator\n    if (!tb_init(tb_null, tb_null)) {\n        return tb_false;\n    }\n#endif\n\n    tb_trace_d(\"init: ok\");\n\n    return tb_true;\n}\ntb_void_t xm_exit() {\n    // exit tbox\n    tb_exit();\n}\ntb_version_t const *xm_version() {\n    // init version tag for binary search\n    static __tb_volatile__ tb_char_t const *s_vtag = \"[xmake]: [vtag]: \" XM_VERSION_STRING;\n    tb_used(s_vtag);\n\n    // init version\n    static tb_version_t s_version = { 0 };\n    if (!s_version.major) {\n        s_version.major = XM_VERSION_MAJOR;\n        s_version.minor = XM_VERSION_MINOR;\n        s_version.alter = XM_VERSION_ALTER;\n        s_version.build = (tb_hize_t)tb_atoll(XM_VERSION_BUILD_STRING);\n    }\n\n    return &s_version;\n}\n"
  },
  {
    "path": "core/src/xmake/xmake.config.h.in",
    "content": "#ifndef XM_CONFIG_H\n#define XM_CONFIG_H\n\n// version\n#define XM_CONFIG_VERSION \"${VERSION}\"\n#define XM_CONFIG_VERSION_MAJOR ${VERSION_MAJOR}\n#define XM_CONFIG_VERSION_MINOR ${VERSION_MINOR}\n#define XM_CONFIG_VERSION_ALTER ${VERSION_ALTER}\n#define XM_CONFIG_VERSION_BUILD ${VERSION_BUILD}\n#define XM_CONFIG_VERSION_BRANCH \"${GIT_BRANCH}\"\n#define XM_CONFIG_VERSION_COMMIT \"${GIT_COMMIT}\"\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/xmake.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        xmake.h\n *\n */\n#ifndef XM_XMAKE_H\n#define XM_XMAKE_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"prefix.h\"\n#include \"engine.h\"\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_enter__\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n#ifdef __xm_debug__\n#define __xm_mode_debug__ TB_MODE_DEBUG\n#else\n#define __xm_mode_debug__ (0)\n#endif\n\n#ifdef __xm_small__\n#define __xm_mode_small__ TB_MODE_SMALL\n#else\n#define __xm_mode_small__ (0)\n#endif\n\n/*! init xmake\n *\n * @return          tb_true or tb_false\n *\n * @code\n    #include \"xmake/xmake.h\"\n\n    int main(int argc, char** argv)\n    {\n        // init xmake\n        if (!xm_init()) return 0;\n\n\n        // exit xmake\n        xm_exit();\n        return 0;\n    }\n * @endcode\n */\n#define xm_init() xm_init_((tb_size_t)(__xm_mode_debug__ | __xm_mode_small__), XM_VERSION_BUILD)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\n\n/*! init the xmake library\n *\n * @param mode      the compile mode for check __tb_small__ and __tb_debug__\n * @param build     the build version\n *\n * @return          tb_true or tb_false\n */\ntb_bool_t\nxm_init_(tb_size_t mode, tb_hize_t build);\n\n/// exit the xmake library\ntb_void_t xm_exit(tb_noarg_t);\n\n/*! the xmake version\n *\n * @return          the xmake version\n */\ntb_version_t const *xm_version(tb_noarg_t);\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * extern\n */\n__tb_extern_c_leave__\n\n#endif\n"
  },
  {
    "path": "core/src/xmake/xmake.lua",
    "content": "target(\"xmake\")\n    set_kind(\"static\")\n\n    -- add deps\n    add_deps(\"sv\", \"lz4\")\n    if namespace then\n        add_deps(\"tbox::tbox\")\n    else\n        add_deps(\"tbox\")\n    end\n    if is_config(\"runtime\", \"luajit\") then\n        add_deps(\"luajit\")\n    else\n        add_deps(\"lua\")\n    end\n    if has_config(\"lua_cjson\") then\n        add_deps(\"lua-cjson\")\n    end\n    if is_plat(\"windows\") and has_config(\"pdcurses\") then\n        add_deps(\"pdcurses\")\n    end\n\n    -- add definitions\n    add_defines(\"__tb_prefix__=\\\"xmake\\\"\")\n    if is_mode(\"debug\") then\n        add_defines(\"__tb_debug__\", {public = true})\n    end\n\n    -- set the auto-generated config.h\n    set_configdir(\"$(builddir)/$(plat)/$(arch)/$(mode)\")\n    add_configfiles(\"xmake.config.h.in\")\n\n    -- add includes directory\n    add_includedirs(\"..\", {interface = true})\n    add_includedirs(\"$(builddir)/$(plat)/$(arch)/$(mode)\", {public = true})\n    add_includedirs(\"../xxhash\")\n    add_includedirs(\"$(projectdir)/../xmake/scripts/module\")\n\n    -- add header files\n    add_headerfiles(\"../(xmake/*.h)\")\n    add_headerfiles(\"../(xmake/prefix/*.h)\")\n    add_headerfiles(\"$(builddir)/$(plat)/$(arch)/$(mode)/xmake.config.h\", {prefixdir = \"xmake\"})\n\n    -- add the common source files\n    add_files(\"**.c|winos/*.c\")\n    if is_plat(\"windows\", \"msys\", \"mingw\", \"cygwin\") then\n        add_files(\"winos/*.c\")\n    end\n\n    -- add options\n    add_options(\"readline\")\n    if is_plat(\"windows\") then\n        add_options(\"pdcurses\")\n    else\n        add_options(\"curses\")\n    end\n\n    -- add definitions\n    if is_plat(\"windows\") then\n        add_defines(\"UNICODE\", \"_UNICODE\")\n    end\n\n    -- embed all script files\n    add_rules(\"utils.bin2obj\", {extensions = \".xmz\"})\n    on_config(function (target)\n        import(\"utils.archive.archive\")\n        if has_config(\"embed\") then\n            local archivefile = path.join(target:autogendir(), \"bin2obj\", \"xmake.xmz\")\n            print(\"archiving %s ..\", archivefile)\n            os.tryrm(archivefile)\n            local rootdir = path.normalize(path.join(os.projectdir(), \"..\", \"xmake\"))\n            archive(archivefile, rootdir, {recurse = true, curdir = rootdir})\n            target:add(\"files\", archivefile)\n            target:add(\"defines\", \"XM_EMBED_ENABLE=1\")\n        end\n    end)\n"
  },
  {
    "path": "core/src/xmake/xmake.sh",
    "content": "#!/bin/sh\n\ntarget \"xmake\"\n    set_kind \"static\"\n    set_default false\n\n    # add deps\n    if has_config \"external\"; then\n        local libs=\"lz4 sv tbox\"\n        for lib in $libs; do\n            if has_config \"$lib\"; then\n                add_options \"$lib\" \"{public}\"\n            fi\n        done\n        if is_config \"runtime\" \"luajit\"; then\n            if has_config \"luajit\"; then\n                add_options \"luajit\" \"{public}\"\n            fi\n        else\n            if has_config \"lua\"; then\n                add_options \"lua\" \"{public}\"\n            fi\n        fi\n    else\n        local libs=\"lua_cjson lz4 sv tbox\"\n        for lib in $libs; do\n            add_deps \"$lib\"\n        done\n        if is_config \"runtime\" \"luajit\"; then\n            add_deps \"luajit\"\n        else\n            add_deps \"lua\"\n        fi\n    fi\n\n    # add options\n    add_options \"readline\" \"curses\" \"{public}\"\n\n    # add definitions\n    add_defines \"__tb_prefix__=\\\"xmake\\\"\"\n    if is_mode \"debug\"; then\n        add_defines \"__tb_debug__\" \"{public}\"\n    fi\n\n    # set the auto-generated config.h\n    set_configdir \"${builddir}/${plat}/${arch}/${mode}\"\n    add_configfiles \"xmake.config.h.in\"\n\n    # add includes directory\n    add_includedirs \"..\" \"{public}\"\n    add_includedirs \"${builddir}/${plat}/${arch}/${mode}\" \"{public}\"\n    add_includedirs \"../xxhash\"\n    add_includedirs \"${projectdir}/xmake/scripts/module\"\n\n    # add the common source files\n    add_files \"*.c\"\n    add_files \"base64/*.c\"\n    add_files \"bloom_filter/*.c\"\n    add_files \"curses/*.c\"\n    add_files \"fwatcher/*.c\"\n    add_files \"hash/*.c\"\n    add_files \"io/*.c\"\n    add_files \"libc/*.c\"\n    add_files \"lz4/*.c\"\n    add_files \"os/*.c\"\n    add_files \"path/*.c\"\n    add_files \"package/*.c\"\n    add_files \"process/*.c\"\n    add_files \"readline/*.c\"\n    add_files \"sandbox/*.c\"\n    add_files \"semver/*.c\"\n    add_files \"string/*.c\"\n    add_files \"utf8/*.c\"\n    add_files \"utils/*.c\"\n    add_files \"tty/*.c\"\n    add_files \"binutils/*.c\"\n    add_files \"binutils/coff/*.c\"\n    add_files \"binutils/macho/*.c\"\n    add_files \"binutils/elf/*.c\"\n    add_files \"binutils/wasm/*.c\"\n    add_files \"binutils/ar/*.c\"\n    add_files \"binutils/mslib/*.c\"\n    add_files \"thread/*.c\"\n    if is_plat \"mingw\"; then\n        add_files \"winos/*.c\"\n    fi\n"
  },
  {
    "path": "core/src/xxhash/xxhash/LICENSE",
    "content": "xxHash Library\nCopyright (c) 2012-2021 Yann Collet\nAll rights reserved.\n\nBSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this\n  list of conditions and the following disclaimer in the documentation and/or\n  other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "core/src/xxhash/xxhash/xxhash.h",
    "content": "/*\n * xxHash - Extremely Fast Hash algorithm\n * Header File\n * Copyright (C) 2012-2023 Yann Collet\n *\n * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *    * Redistributions of source code must retain the above copyright\n *      notice, this list of conditions and the following disclaimer.\n *    * Redistributions in binary form must reproduce the above\n *      copyright notice, this list of conditions and the following disclaimer\n *      in the documentation and/or other materials provided with the\n *      distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * You can contact the author at:\n *   - xxHash homepage: https://www.xxhash.com\n *   - xxHash source repository: https://github.com/Cyan4973/xxHash\n */\n\n/*!\n * @mainpage xxHash\n *\n * xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed\n * limits.\n *\n * It is proposed in four flavors, in three families:\n * 1. @ref XXH32_family\n *   - Classic 32-bit hash function. Simple, compact, and runs on almost all\n *     32-bit and 64-bit systems.\n * 2. @ref XXH64_family\n *   - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most\n *     64-bit systems (but _not_ 32-bit systems).\n * 3. @ref XXH3_family\n *   - Modern 64-bit and 128-bit hash function family which features improved\n *     strength and performance across the board, especially on smaller data.\n *     It benefits greatly from SIMD and 64-bit without requiring it.\n *\n * Benchmarks\n * ---\n * The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04.\n * The open source benchmark program is compiled with clang v10.0 using -O3 flag.\n *\n * | Hash Name            | ISA ext | Width | Large Data Speed | Small Data Velocity |\n * | -------------------- | ------- | ----: | ---------------: | ------------------: |\n * | XXH3_64bits()        | @b AVX2 |    64 |        59.4 GB/s |               133.1 |\n * | MeowHash             | AES-NI  |   128 |        58.2 GB/s |                52.5 |\n * | XXH3_128bits()       | @b AVX2 |   128 |        57.9 GB/s |               118.1 |\n * | CLHash               | PCLMUL  |    64 |        37.1 GB/s |                58.1 |\n * | XXH3_64bits()        | @b SSE2 |    64 |        31.5 GB/s |               133.1 |\n * | XXH3_128bits()       | @b SSE2 |   128 |        29.6 GB/s |               118.1 |\n * | RAM sequential read  |         |   N/A |        28.0 GB/s |                 N/A |\n * | ahash                | AES-NI  |    64 |        22.5 GB/s |               107.2 |\n * | City64               |         |    64 |        22.0 GB/s |                76.6 |\n * | T1ha2                |         |    64 |        22.0 GB/s |                99.0 |\n * | City128              |         |   128 |        21.7 GB/s |                57.7 |\n * | FarmHash             | AES-NI  |    64 |        21.3 GB/s |                71.9 |\n * | XXH64()              |         |    64 |        19.4 GB/s |                71.0 |\n * | SpookyHash           |         |    64 |        19.3 GB/s |                53.2 |\n * | Mum                  |         |    64 |        18.0 GB/s |                67.0 |\n * | CRC32C               | SSE4.2  |    32 |        13.0 GB/s |                57.9 |\n * | XXH32()              |         |    32 |         9.7 GB/s |                71.9 |\n * | City32               |         |    32 |         9.1 GB/s |                66.0 |\n * | Blake3*              | @b AVX2 |   256 |         4.4 GB/s |                 8.1 |\n * | Murmur3              |         |    32 |         3.9 GB/s |                56.1 |\n * | SipHash*             |         |    64 |         3.0 GB/s |                43.2 |\n * | Blake3*              | @b SSE2 |   256 |         2.4 GB/s |                 8.1 |\n * | HighwayHash          |         |    64 |         1.4 GB/s |                 6.0 |\n * | FNV64                |         |    64 |         1.2 GB/s |                62.7 |\n * | Blake2*              |         |   256 |         1.1 GB/s |                 5.1 |\n * | SHA1*                |         |   160 |         0.8 GB/s |                 5.6 |\n * | MD5*                 |         |   128 |         0.6 GB/s |                 7.8 |\n * @note\n *   - Hashes which require a specific ISA extension are noted. SSE2 is also noted,\n *     even though it is mandatory on x64.\n *   - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic\n *     by modern standards.\n *   - Small data velocity is a rough average of algorithm's efficiency for small\n *     data. For more accurate information, see the wiki.\n *   - More benchmarks and strength tests are found on the wiki:\n *         https://github.com/Cyan4973/xxHash/wiki\n *\n * Usage\n * ------\n * All xxHash variants use a similar API. Changing the algorithm is a trivial\n * substitution.\n *\n * @pre\n *    For functions which take an input and length parameter, the following\n *    requirements are assumed:\n *    - The range from [`input`, `input + length`) is valid, readable memory.\n *      - The only exception is if the `length` is `0`, `input` may be `NULL`.\n *    - For C++, the objects must have the *TriviallyCopyable* property, as the\n *      functions access bytes directly as if it was an array of `unsigned char`.\n *\n * @anchor single_shot_example\n * **Single Shot**\n *\n * These functions are stateless functions which hash a contiguous block of memory,\n * immediately returning the result. They are the easiest and usually the fastest\n * option.\n *\n * XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits()\n *\n * @code{.c}\n *   #include <string.h>\n *   #include \"xxhash.h\"\n *\n *   // Example for a function which hashes a null terminated string with XXH32().\n *   XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed)\n *   {\n *       // NULL pointers are only valid if the length is zero\n *       size_t length = (string == NULL) ? 0 : strlen(string);\n *       return XXH32(string, length, seed);\n *   }\n * @endcode\n *\n *\n * @anchor streaming_example\n * **Streaming**\n *\n * These groups of functions allow incremental hashing of unknown size, even\n * more than what would fit in a size_t.\n *\n * XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset()\n *\n * @code{.c}\n *   #include <stdio.h>\n *   #include <assert.h>\n *   #include \"xxhash.h\"\n *   // Example for a function which hashes a FILE incrementally with XXH3_64bits().\n *   XXH64_hash_t hashFile(FILE* f)\n *   {\n *       // Allocate a state struct. Do not just use malloc() or new.\n *       XXH3_state_t* state = XXH3_createState();\n *       assert(state != NULL && \"Out of memory!\");\n *       // Reset the state to start a new hashing session.\n *       XXH3_64bits_reset(state);\n *       char buffer[4096];\n *       size_t count;\n *       // Read the file in chunks\n *       while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) {\n *           // Run update() as many times as necessary to process the data\n *           XXH3_64bits_update(state, buffer, count);\n *       }\n *       // Retrieve the finalized hash. This will not change the state.\n *       XXH64_hash_t result = XXH3_64bits_digest(state);\n *       // Free the state. Do not use free().\n *       XXH3_freeState(state);\n *       return result;\n *   }\n * @endcode\n *\n * Streaming functions generate the xxHash value from an incremental input.\n * This method is slower than single-call functions, due to state management.\n * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.\n *\n * An XXH state must first be allocated using `XXH*_createState()`.\n *\n * Start a new hash by initializing the state with a seed using `XXH*_reset()`.\n *\n * Then, feed the hash state by calling `XXH*_update()` as many times as necessary.\n *\n * The function returns an error code, with 0 meaning OK, and any other value\n * meaning there is an error.\n *\n * Finally, a hash value can be produced anytime, by using `XXH*_digest()`.\n * This function returns the nn-bits hash as an int or long long.\n *\n * It's still possible to continue inserting input into the hash state after a\n * digest, and generate new hash values later on by invoking `XXH*_digest()`.\n *\n * When done, release the state using `XXH*_freeState()`.\n *\n *\n * @anchor canonical_representation_example\n * **Canonical Representation**\n *\n * The default return values from XXH functions are unsigned 32, 64 and 128 bit\n * integers.\n * This the simplest and fastest format for further post-processing.\n *\n * However, this leaves open the question of what is the order on the byte level,\n * since little and big endian conventions will store the same number differently.\n *\n * The canonical representation settles this issue by mandating big-endian\n * convention, the same convention as human-readable numbers (large digits first).\n *\n * When writing hash values to storage, sending them over a network, or printing\n * them, it's highly recommended to use the canonical representation to ensure\n * portability across a wider range of systems, present and future.\n *\n * The following functions allow transformation of hash values to and from\n * canonical format.\n *\n * XXH32_canonicalFromHash(), XXH32_hashFromCanonical(),\n * XXH64_canonicalFromHash(), XXH64_hashFromCanonical(),\n * XXH128_canonicalFromHash(), XXH128_hashFromCanonical(),\n *\n * @code{.c}\n *   #include <stdio.h>\n *   #include \"xxhash.h\"\n *\n *   // Example for a function which prints XXH32_hash_t in human readable format\n *   void printXxh32(XXH32_hash_t hash)\n *   {\n *       XXH32_canonical_t cano;\n *       XXH32_canonicalFromHash(&cano, hash);\n *       size_t i;\n *       for(i = 0; i < sizeof(cano.digest); ++i) {\n *           printf(\"%02x\", cano.digest[i]);\n *       }\n *       printf(\"\\n\");\n *   }\n *\n *   // Example for a function which converts XXH32_canonical_t to XXH32_hash_t\n *   XXH32_hash_t convertCanonicalToXxh32(XXH32_canonical_t cano)\n *   {\n *       XXH32_hash_t hash = XXH32_hashFromCanonical(&cano);\n *       return hash;\n *   }\n * @endcode\n *\n *\n * @file xxhash.h\n * xxHash prototypes and implementation\n */\n\n#if defined(__cplusplus) && !defined(XXH_NO_EXTERNC_GUARD)\nextern \"C\" {\n#endif\n\n/* ****************************\n *  INLINE mode\n ******************************/\n/*!\n * @defgroup public Public API\n * Contains details on the public xxHash functions.\n * @{\n */\n#ifdef XXH_DOXYGEN\n/*!\n * @brief Gives access to internal state declaration, required for static allocation.\n *\n * Incompatible with dynamic linking, due to risks of ABI changes.\n *\n * Usage:\n * @code{.c}\n *     #define XXH_STATIC_LINKING_ONLY\n *     #include \"xxhash.h\"\n * @endcode\n */\n#  define XXH_STATIC_LINKING_ONLY\n/* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */\n\n/*!\n * @brief Gives access to internal definitions.\n *\n * Usage:\n * @code{.c}\n *     #define XXH_STATIC_LINKING_ONLY\n *     #define XXH_IMPLEMENTATION\n *     #include \"xxhash.h\"\n * @endcode\n */\n#  define XXH_IMPLEMENTATION\n/* Do not undef XXH_IMPLEMENTATION for Doxygen */\n\n/*!\n * @brief Exposes the implementation and marks all functions as `inline`.\n *\n * Use these build macros to inline xxhash into the target unit.\n * Inlining improves performance on small inputs, especially when the length is\n * expressed as a compile-time constant:\n *\n *  https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html\n *\n * It also keeps xxHash symbols private to the unit, so they are not exported.\n *\n * Usage:\n * @code{.c}\n *     #define XXH_INLINE_ALL\n *     #include \"xxhash.h\"\n * @endcode\n * Do not compile and link xxhash.o as a separate object, as it is not useful.\n */\n#  define XXH_INLINE_ALL\n#  undef XXH_INLINE_ALL\n/*!\n * @brief Exposes the implementation without marking functions as inline.\n */\n#  define XXH_PRIVATE_API\n#  undef XXH_PRIVATE_API\n/*!\n * @brief Emulate a namespace by transparently prefixing all symbols.\n *\n * If you want to include _and expose_ xxHash functions from within your own\n * library, but also want to avoid symbol collisions with other libraries which\n * may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix\n * any public symbol from xxhash library with the value of @ref XXH_NAMESPACE\n * (therefore, avoid empty or numeric values).\n *\n * Note that no change is required within the calling program as long as it\n * includes `xxhash.h`: Regular symbol names will be automatically translated\n * by this header.\n */\n#  define XXH_NAMESPACE /* YOUR NAME HERE */\n#  undef XXH_NAMESPACE\n#endif\n\n#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \\\n    && !defined(XXH_INLINE_ALL_31684351384)\n   /* this section should be traversed only once */\n#  define XXH_INLINE_ALL_31684351384\n   /* give access to the advanced API, required to compile implementations */\n#  undef XXH_STATIC_LINKING_ONLY   /* avoid macro redef */\n#  define XXH_STATIC_LINKING_ONLY\n   /* make all functions private */\n#  undef XXH_PUBLIC_API\n#  if defined(__GNUC__)\n#    define XXH_PUBLIC_API static __inline __attribute__((__unused__))\n#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n#    define XXH_PUBLIC_API static inline\n#  elif defined(_MSC_VER)\n#    define XXH_PUBLIC_API static __inline\n#  else\n     /* note: this version may generate warnings for unused static functions */\n#    define XXH_PUBLIC_API static\n#  endif\n\n   /*\n    * This part deals with the special case where a unit wants to inline xxHash,\n    * but \"xxhash.h\" has previously been included without XXH_INLINE_ALL,\n    * such as part of some previously included *.h header file.\n    * Without further action, the new include would just be ignored,\n    * and functions would effectively _not_ be inlined (silent failure).\n    * The following macros solve this situation by prefixing all inlined names,\n    * avoiding naming collision with previous inclusions.\n    */\n   /* Before that, we unconditionally #undef all symbols,\n    * in case they were already defined with XXH_NAMESPACE.\n    * They will then be redefined for XXH_INLINE_ALL\n    */\n#  undef XXH_versionNumber\n    /* XXH32 */\n#  undef XXH32\n#  undef XXH32_createState\n#  undef XXH32_freeState\n#  undef XXH32_reset\n#  undef XXH32_update\n#  undef XXH32_digest\n#  undef XXH32_copyState\n#  undef XXH32_canonicalFromHash\n#  undef XXH32_hashFromCanonical\n    /* XXH64 */\n#  undef XXH64\n#  undef XXH64_createState\n#  undef XXH64_freeState\n#  undef XXH64_reset\n#  undef XXH64_update\n#  undef XXH64_digest\n#  undef XXH64_copyState\n#  undef XXH64_canonicalFromHash\n#  undef XXH64_hashFromCanonical\n    /* XXH3_64bits */\n#  undef XXH3_64bits\n#  undef XXH3_64bits_withSecret\n#  undef XXH3_64bits_withSeed\n#  undef XXH3_64bits_withSecretandSeed\n#  undef XXH3_createState\n#  undef XXH3_freeState\n#  undef XXH3_copyState\n#  undef XXH3_64bits_reset\n#  undef XXH3_64bits_reset_withSeed\n#  undef XXH3_64bits_reset_withSecret\n#  undef XXH3_64bits_update\n#  undef XXH3_64bits_digest\n#  undef XXH3_generateSecret\n    /* XXH3_128bits */\n#  undef XXH128\n#  undef XXH3_128bits\n#  undef XXH3_128bits_withSeed\n#  undef XXH3_128bits_withSecret\n#  undef XXH3_128bits_reset\n#  undef XXH3_128bits_reset_withSeed\n#  undef XXH3_128bits_reset_withSecret\n#  undef XXH3_128bits_reset_withSecretandSeed\n#  undef XXH3_128bits_update\n#  undef XXH3_128bits_digest\n#  undef XXH128_isEqual\n#  undef XXH128_cmp\n#  undef XXH128_canonicalFromHash\n#  undef XXH128_hashFromCanonical\n    /* Finally, free the namespace itself */\n#  undef XXH_NAMESPACE\n\n    /* employ the namespace for XXH_INLINE_ALL */\n#  define XXH_NAMESPACE XXH_INLINE_\n   /*\n    * Some identifiers (enums, type names) are not symbols,\n    * but they must nonetheless be renamed to avoid redeclaration.\n    * Alternative solution: do not redeclare them.\n    * However, this requires some #ifdefs, and has a more dispersed impact.\n    * Meanwhile, renaming can be achieved in a single place.\n    */\n#  define XXH_IPREF(Id)   XXH_NAMESPACE ## Id\n#  define XXH_OK XXH_IPREF(XXH_OK)\n#  define XXH_ERROR XXH_IPREF(XXH_ERROR)\n#  define XXH_errorcode XXH_IPREF(XXH_errorcode)\n#  define XXH32_canonical_t  XXH_IPREF(XXH32_canonical_t)\n#  define XXH64_canonical_t  XXH_IPREF(XXH64_canonical_t)\n#  define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t)\n#  define XXH32_state_s XXH_IPREF(XXH32_state_s)\n#  define XXH32_state_t XXH_IPREF(XXH32_state_t)\n#  define XXH64_state_s XXH_IPREF(XXH64_state_s)\n#  define XXH64_state_t XXH_IPREF(XXH64_state_t)\n#  define XXH3_state_s  XXH_IPREF(XXH3_state_s)\n#  define XXH3_state_t  XXH_IPREF(XXH3_state_t)\n#  define XXH128_hash_t XXH_IPREF(XXH128_hash_t)\n   /* Ensure the header is parsed again, even if it was previously included */\n#  undef XXHASH_H_5627135585666179\n#  undef XXHASH_H_STATIC_13879238742\n#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */\n\n/* ****************************************************************\n *  Stable API\n *****************************************************************/\n#ifndef XXHASH_H_5627135585666179\n#define XXHASH_H_5627135585666179 1\n\n/*! @brief Marks a global symbol. */\n#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)\n#  if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))\n#    ifdef XXH_EXPORT\n#      define XXH_PUBLIC_API __declspec(dllexport)\n#    elif XXH_IMPORT\n#      define XXH_PUBLIC_API __declspec(dllimport)\n#    endif\n#  else\n#    define XXH_PUBLIC_API   /* do nothing */\n#  endif\n#endif\n\n#ifdef XXH_NAMESPACE\n#  define XXH_CAT(A,B) A##B\n#  define XXH_NAME2(A,B) XXH_CAT(A,B)\n#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)\n/* XXH32 */\n#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)\n#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)\n#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)\n#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)\n#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)\n#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)\n#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)\n#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)\n#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)\n/* XXH64 */\n#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)\n#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)\n#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)\n#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)\n#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)\n#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)\n#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)\n#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)\n#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)\n/* XXH3_64bits */\n#  define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits)\n#  define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret)\n#  define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed)\n#  define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed)\n#  define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState)\n#  define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState)\n#  define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState)\n#  define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset)\n#  define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed)\n#  define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret)\n#  define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed)\n#  define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update)\n#  define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest)\n#  define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret)\n#  define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed)\n/* XXH3_128bits */\n#  define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128)\n#  define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits)\n#  define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed)\n#  define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret)\n#  define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed)\n#  define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset)\n#  define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed)\n#  define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret)\n#  define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed)\n#  define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update)\n#  define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest)\n#  define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual)\n#  define XXH128_cmp     XXH_NAME2(XXH_NAMESPACE, XXH128_cmp)\n#  define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash)\n#  define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical)\n#endif\n\n\n/* *************************************\n*  Compiler specifics\n***************************************/\n\n/* specific declaration modes for Windows */\n#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)\n#  if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))\n#    ifdef XXH_EXPORT\n#      define XXH_PUBLIC_API __declspec(dllexport)\n#    elif XXH_IMPORT\n#      define XXH_PUBLIC_API __declspec(dllimport)\n#    endif\n#  else\n#    define XXH_PUBLIC_API   /* do nothing */\n#  endif\n#endif\n\n#if defined (__GNUC__)\n# define XXH_CONSTF  __attribute__((__const__))\n# define XXH_PUREF   __attribute__((__pure__))\n# define XXH_MALLOCF __attribute__((__malloc__))\n#else\n# define XXH_CONSTF  /* disable */\n# define XXH_PUREF\n# define XXH_MALLOCF\n#endif\n\n/* *************************************\n*  Version\n***************************************/\n#define XXH_VERSION_MAJOR    0\n#define XXH_VERSION_MINOR    8\n#define XXH_VERSION_RELEASE  3\n/*! @brief Version number, encoded as two digits each */\n#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)\n\n/*!\n * @brief Obtains the xxHash version.\n *\n * This is mostly useful when xxHash is compiled as a shared library,\n * since the returned value comes from the library, as opposed to header file.\n *\n * @return @ref XXH_VERSION_NUMBER of the invoked library.\n */\nXXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void);\n\n\n/* ****************************\n*  Common basic types\n******************************/\n#include <stddef.h>   /* size_t */\n/*!\n * @brief Exit code for the streaming API.\n */\ntypedef enum {\n    XXH_OK = 0, /*!< OK */\n    XXH_ERROR   /*!< Error */\n} XXH_errorcode;\n\n\n/*-**********************************************************************\n*  32-bit hash\n************************************************************************/\n#if defined(XXH_DOXYGEN) /* Don't show <stdint.h> include */\n/*!\n * @brief An unsigned 32-bit integer.\n *\n * Not necessarily defined to `uint32_t` but functionally equivalent.\n */\ntypedef uint32_t XXH32_hash_t;\n\n#elif !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   ifdef _AIX\n#     include <inttypes.h>\n#   else\n#     include <stdint.h>\n#   endif\n    typedef uint32_t XXH32_hash_t;\n\n#else\n#   include <limits.h>\n#   if UINT_MAX == 0xFFFFFFFFUL\n      typedef unsigned int XXH32_hash_t;\n#   elif ULONG_MAX == 0xFFFFFFFFUL\n      typedef unsigned long XXH32_hash_t;\n#   else\n#     error \"unsupported platform: need a 32-bit type\"\n#   endif\n#endif\n\n/*!\n * @}\n *\n * @defgroup XXH32_family XXH32 family\n * @ingroup public\n * Contains functions used in the classic 32-bit xxHash algorithm.\n *\n * @note\n *   XXH32 is useful for older platforms, with no or poor 64-bit performance.\n *   Note that the @ref XXH3_family provides competitive speed for both 32-bit\n *   and 64-bit systems, and offers true 64/128 bit hash results.\n *\n * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families\n * @see @ref XXH32_impl for implementation details\n * @{\n */\n\n/*!\n * @brief Calculates the 32-bit hash of @p input using xxHash32.\n *\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n * @param seed The 32-bit seed to alter the hash's output predictably.\n *\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return The calculated 32-bit xxHash32 value.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed);\n\n#ifndef XXH_NO_STREAM\n/*!\n * @typedef struct XXH32_state_s XXH32_state_t\n * @brief The opaque state struct for the XXH32 streaming API.\n *\n * @see XXH32_state_s for details.\n * @see @ref streaming_example \"Streaming Example\"\n */\ntypedef struct XXH32_state_s XXH32_state_t;\n\n/*!\n * @brief Allocates an @ref XXH32_state_t.\n *\n * @return An allocated pointer of @ref XXH32_state_t on success.\n * @return `NULL` on failure.\n *\n * @note Must be freed with XXH32_freeState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void);\n/*!\n * @brief Frees an @ref XXH32_state_t.\n *\n * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState().\n *\n * @return @ref XXH_OK.\n *\n * @note @p statePtr must be allocated with XXH32_createState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n *\n */\nXXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);\n/*!\n * @brief Copies one @ref XXH32_state_t to another.\n *\n * @param dst_state The state to copy to.\n * @param src_state The state to copy from.\n * @pre\n *   @p dst_state and @p src_state must not be `NULL` and must not overlap.\n */\nXXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);\n\n/*!\n * @brief Resets an @ref XXH32_state_t to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n * @param seed The 32-bit seed to alter the hash result predictably.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note This function resets and seeds a state. Call it before @ref XXH32_update().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, XXH32_hash_t seed);\n\n/*!\n * @brief Consumes a block of @p input to an @ref XXH32_state_t.\n *\n * @param statePtr The state struct to update.\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note Call this to incrementally consume blocks of data.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);\n\n/*!\n * @brief Returns the calculated hash value from an @ref XXH32_state_t.\n *\n * @param statePtr The state struct to calculate the hash from.\n *\n * @pre\n *  @p statePtr must not be `NULL`.\n *\n * @return The calculated 32-bit xxHash32 value from that state.\n *\n * @note\n *   Calling XXH32_digest() will not affect @p statePtr, so you can update,\n *   digest, and update again.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);\n#endif /* !XXH_NO_STREAM */\n\n/*******   Canonical representation   *******/\n\n/*!\n * @brief Canonical (big endian) representation of @ref XXH32_hash_t.\n */\ntypedef struct {\n    unsigned char digest[4]; /*!< Hash bytes, big endian */\n} XXH32_canonical_t;\n\n/*!\n * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t.\n *\n * @param dst  The @ref XXH32_canonical_t pointer to be stored to.\n * @param hash The @ref XXH32_hash_t to be converted.\n *\n * @pre\n *   @p dst must not be `NULL`.\n *\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);\n\n/*!\n * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t.\n *\n * @param src The @ref XXH32_canonical_t to convert.\n *\n * @pre\n *   @p src must not be `NULL`.\n *\n * @return The converted hash.\n *\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);\n\n\n/*! @cond Doxygen ignores this part */\n#ifdef __has_attribute\n# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x)\n#else\n# define XXH_HAS_ATTRIBUTE(x) 0\n#endif\n/*! @endcond */\n\n/*! @cond Doxygen ignores this part */\n/*\n * C23 __STDC_VERSION__ number hasn't been specified yet. For now\n * leave as `201711L` (C17 + 1).\n * TODO: Update to correct value when its been specified.\n */\n#define XXH_C23_VN 201711L\n/*! @endcond */\n\n/*! @cond Doxygen ignores this part */\n/* C-language Attributes are added in C23. */\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute)\n# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)\n#else\n# define XXH_HAS_C_ATTRIBUTE(x) 0\n#endif\n/*! @endcond */\n\n/*! @cond Doxygen ignores this part */\n#if defined(__cplusplus) && defined(__has_cpp_attribute)\n# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)\n#else\n# define XXH_HAS_CPP_ATTRIBUTE(x) 0\n#endif\n/*! @endcond */\n\n/*! @cond Doxygen ignores this part */\n/*\n * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute\n * introduced in CPP17 and C23.\n * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough\n * C23   : https://en.cppreference.com/w/c/language/attributes/fallthrough\n */\n#if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough)\n# define XXH_FALLTHROUGH [[fallthrough]]\n#elif XXH_HAS_ATTRIBUTE(__fallthrough__)\n# define XXH_FALLTHROUGH __attribute__ ((__fallthrough__))\n#else\n# define XXH_FALLTHROUGH /* fallthrough */\n#endif\n/*! @endcond */\n\n/*! @cond Doxygen ignores this part */\n/*\n * Define XXH_NOESCAPE for annotated pointers in public API.\n * https://clang.llvm.org/docs/AttributeReference.html#noescape\n * As of writing this, only supported by clang.\n */\n#if XXH_HAS_ATTRIBUTE(noescape)\n# define XXH_NOESCAPE __attribute__((__noescape__))\n#else\n# define XXH_NOESCAPE\n#endif\n/*! @endcond */\n\n\n/*!\n * @}\n * @ingroup public\n * @{\n */\n\n#ifndef XXH_NO_LONG_LONG\n/*-**********************************************************************\n*  64-bit hash\n************************************************************************/\n#if defined(XXH_DOXYGEN) /* don't include <stdint.h> */\n/*!\n * @brief An unsigned 64-bit integer.\n *\n * Not necessarily defined to `uint64_t` but functionally equivalent.\n */\ntypedef uint64_t XXH64_hash_t;\n#elif !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   ifdef _AIX\n#     include <inttypes.h>\n#   else\n#     include <stdint.h>\n#   endif\n   typedef uint64_t XXH64_hash_t;\n#else\n#  include <limits.h>\n#  if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL\n     /* LP64 ABI says uint64_t is unsigned long */\n     typedef unsigned long XXH64_hash_t;\n#  else\n     /* the following type must have a width of 64-bit */\n     typedef unsigned long long XXH64_hash_t;\n#  endif\n#endif\n\n/*!\n * @}\n *\n * @defgroup XXH64_family XXH64 family\n * @ingroup public\n * @{\n * Contains functions used in the classic 64-bit xxHash algorithm.\n *\n * @note\n *   XXH3 provides competitive speed for both 32-bit and 64-bit systems,\n *   and offers true 64/128 bit hash results.\n *   It provides better speed for systems with vector processing capabilities.\n */\n\n/*!\n * @brief Calculates the 64-bit hash of @p input using xxHash64.\n *\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n * @param seed The 64-bit seed to alter the hash's output predictably.\n *\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return The calculated 64-bit xxHash64 value.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);\n\n/*******   Streaming   *******/\n#ifndef XXH_NO_STREAM\n/*!\n * @brief The opaque state struct for the XXH64 streaming API.\n *\n * @see XXH64_state_s for details.\n * @see @ref streaming_example \"Streaming Example\"\n */\ntypedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */\n\n/*!\n * @brief Allocates an @ref XXH64_state_t.\n *\n * @return An allocated pointer of @ref XXH64_state_t on success.\n * @return `NULL` on failure.\n *\n * @note Must be freed with XXH64_freeState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void);\n\n/*!\n * @brief Frees an @ref XXH64_state_t.\n *\n * @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState().\n *\n * @return @ref XXH_OK.\n *\n * @note @p statePtr must be allocated with XXH64_createState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);\n\n/*!\n * @brief Copies one @ref XXH64_state_t to another.\n *\n * @param dst_state The state to copy to.\n * @param src_state The state to copy from.\n * @pre\n *   @p dst_state and @p src_state must not be `NULL` and must not overlap.\n */\nXXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state);\n\n/*!\n * @brief Resets an @ref XXH64_state_t to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n * @param seed The 64-bit seed to alter the hash result predictably.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note This function resets and seeds a state. Call it before @ref XXH64_update().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed);\n\n/*!\n * @brief Consumes a block of @p input to an @ref XXH64_state_t.\n *\n * @param statePtr The state struct to update.\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note Call this to incrementally consume blocks of data.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);\n\n/*!\n * @brief Returns the calculated hash value from an @ref XXH64_state_t.\n *\n * @param statePtr The state struct to calculate the hash from.\n *\n * @pre\n *  @p statePtr must not be `NULL`.\n *\n * @return The calculated 64-bit xxHash64 value from that state.\n *\n * @note\n *   Calling XXH64_digest() will not affect @p statePtr, so you can update,\n *   digest, and update again.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr);\n#endif /* !XXH_NO_STREAM */\n/*******   Canonical representation   *******/\n\n/*!\n * @brief Canonical (big endian) representation of @ref XXH64_hash_t.\n */\ntypedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t;\n\n/*!\n * @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t.\n *\n * @param dst The @ref XXH64_canonical_t pointer to be stored to.\n * @param hash The @ref XXH64_hash_t to be converted.\n *\n * @pre\n *   @p dst must not be `NULL`.\n *\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash);\n\n/*!\n * @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t.\n *\n * @param src The @ref XXH64_canonical_t to convert.\n *\n * @pre\n *   @p src must not be `NULL`.\n *\n * @return The converted hash.\n *\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src);\n\n#ifndef XXH_NO_XXH3\n\n/*!\n * @}\n * ************************************************************************\n * @defgroup XXH3_family XXH3 family\n * @ingroup public\n * @{\n *\n * XXH3 is a more recent hash algorithm featuring:\n *  - Improved speed for both small and large inputs\n *  - True 64-bit and 128-bit outputs\n *  - SIMD acceleration\n *  - Improved 32-bit viability\n *\n * Speed analysis methodology is explained here:\n *\n *    https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html\n *\n * Compared to XXH64, expect XXH3 to run approximately\n * ~2x faster on large inputs and >3x faster on small ones,\n * exact differences vary depending on platform.\n *\n * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,\n * but does not require it.\n * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3\n * at competitive speeds, even without vector support. Further details are\n * explained in the implementation.\n *\n * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD\n * implementations for many common platforms:\n *   - AVX512\n *   - AVX2\n *   - SSE2\n *   - ARM NEON\n *   - WebAssembly SIMD128\n *   - POWER8 VSX\n *   - s390x ZVector\n * This can be controlled via the @ref XXH_VECTOR macro, but it automatically\n * selects the best version according to predefined macros. For the x86 family, an\n * automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c.\n *\n * XXH3 implementation is portable:\n * it has a generic C90 formulation that can be compiled on any platform,\n * all implementations generate exactly the same hash value on all platforms.\n * Starting from v0.8.0, it's also labelled \"stable\", meaning that\n * any future version will also generate the same hash value.\n *\n * XXH3 offers 2 variants, _64bits and _128bits.\n *\n * When only 64 bits are needed, prefer invoking the _64bits variant, as it\n * reduces the amount of mixing, resulting in faster speed on small inputs.\n * It's also generally simpler to manipulate a scalar return type than a struct.\n *\n * The API supports one-shot hashing, streaming mode, and custom secrets.\n */\n\n/*!\n * @ingroup tuning\n * @brief Possible values for @ref XXH_VECTOR.\n *\n * Unless set explicitly, determined automatically.\n */\n#  define XXH_SCALAR 0 /*!< Portable scalar version */\n#  define XXH_SSE2   1 /*!< SSE2 for Pentium 4, Opteron, all x86_64. */\n#  define XXH_AVX2   2 /*!< AVX2 for Haswell and Bulldozer */\n#  define XXH_AVX512 3 /*!< AVX512 for Skylake and Icelake */\n#  define XXH_NEON   4 /*!< NEON for most ARMv7-A, all AArch64, and WASM SIMD128 */\n#  define XXH_VSX    5 /*!< VSX and ZVector for POWER8/z13 (64-bit) */\n#  define XXH_SVE    6 /*!< SVE for some ARMv8-A and ARMv9-A */\n#  define XXH_LSX    7 /*!< LSX (128-bit SIMD) for LoongArch64 */\n#  define XXH_LASX   8 /*!< LASX (256-bit SIMD) for LoongArch64 */\n\n\n/*-**********************************************************************\n*  XXH3 64-bit variant\n************************************************************************/\n\n/*!\n * @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input.\n *\n * @param input  The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n *\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return The calculated 64-bit XXH3 hash value.\n *\n * @note\n *   This is equivalent to @ref XXH3_64bits_withSeed() with a seed of `0`, however\n *   it may have slightly better performance due to constant propagation of the\n *   defaults.\n *\n * @see\n *    XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length);\n\n/*!\n * @brief Calculates 64-bit seeded variant of XXH3 hash of @p input.\n *\n * @param input  The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n * @param seed   The 64-bit seed to alter the hash result predictably.\n *\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return The calculated 64-bit XXH3 hash value.\n *\n * @note\n *    seed == 0 produces the same results as @ref XXH3_64bits().\n *\n * This variant generates a custom secret on the fly based on default secret\n * altered using the @p seed value.\n *\n * While this operation is decently fast, note that it's not completely free.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);\n\n/*!\n * The bare minimum size for a custom secret.\n *\n * @see\n *  XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(),\n *  XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret().\n */\n#define XXH3_SECRET_SIZE_MIN 136\n\n/*!\n * @brief Calculates 64-bit variant of XXH3 with a custom \"secret\".\n *\n * @param data       The block of data to be hashed, at least @p len bytes in size.\n * @param len        The length of @p data, in bytes.\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n *\n * @return The calculated 64-bit XXH3 hash value.\n *\n * @pre\n *   The memory between @p data and @p data + @p len must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p data may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * It's possible to provide any blob of bytes as a \"secret\" to generate the hash.\n * This makes it more difficult for an external actor to prepare an intentional collision.\n * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).\n * However, the quality of the secret impacts the dispersion of the hash algorithm.\n * Therefore, the secret _must_ look like a bunch of random bytes.\n * Avoid \"trivial\" or structured data such as repeated sequences or a text document.\n * Whenever in doubt about the \"randomness\" of the blob of bytes,\n * consider employing @ref XXH3_generateSecret() instead (see below).\n * It will generate a proper high entropy secret derived from the blob of bytes.\n * Another advantage of using XXH3_generateSecret() is that\n * it guarantees that all bits within the initial blob of bytes\n * will impact every bit of the output.\n * This is not necessarily the case when using the blob of bytes directly\n * because, when hashing _small_ inputs, only a portion of the secret is employed.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);\n\n\n/*******   Streaming   *******/\n#ifndef XXH_NO_STREAM\n/*\n * Streaming requires state maintenance.\n * This operation costs memory and CPU.\n * As a consequence, streaming is slower than one-shot hashing.\n * For better performance, prefer one-shot functions whenever applicable.\n */\n\n/*!\n * @brief The opaque state struct for the XXH3 streaming API.\n *\n * @see XXH3_state_s for details.\n * @see @ref streaming_example \"Streaming Example\"\n */\ntypedef struct XXH3_state_s XXH3_state_t;\nXXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void);\nXXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr);\n\n/*!\n * @brief Copies one @ref XXH3_state_t to another.\n *\n * @param dst_state The state to copy to.\n * @param src_state The state to copy from.\n * @pre\n *   @p dst_state and @p src_state must not be `NULL` and must not overlap.\n */\nXXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state);\n\n/*!\n * @brief Resets an @ref XXH3_state_t to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   - This function resets `statePtr` and generate a secret with default parameters.\n *   - Call this function before @ref XXH3_64bits_update().\n *   - Digest will be equivalent to `XXH3_64bits()`.\n *\n * @see @ref streaming_example \"Streaming Example\"\n *\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);\n\n/*!\n * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n * @param seed     The 64-bit seed to alter the hash result predictably.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   - This function resets `statePtr` and generate a secret from `seed`.\n *   - Call this function before @ref XXH3_64bits_update().\n *   - Digest will be equivalent to `XXH3_64bits_withSeed()`.\n *\n * @see @ref streaming_example \"Streaming Example\"\n *\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);\n\n/*!\n * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   `secret` is referenced, it _must outlive_ the hash streaming session.\n *\n * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,\n * and the quality of produced hash values depends on secret's entropy\n * (secret's content should look like a bunch of random bytes).\n * When in doubt about the randomness of a candidate `secret`,\n * consider employing `XXH3_generateSecret()` instead (see below).\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);\n\n/*!\n * @brief Consumes a block of @p input to an @ref XXH3_state_t.\n *\n * @param statePtr The state struct to update.\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n * @pre\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note Call this to incrementally consume blocks of data.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);\n\n/*!\n * @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t.\n *\n * @param statePtr The state struct to calculate the hash from.\n *\n * @pre\n *  @p statePtr must not be `NULL`.\n *\n * @return The calculated XXH3 64-bit hash value from that state.\n *\n * @note\n *   Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update,\n *   digest, and update again.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);\n#endif /* !XXH_NO_STREAM */\n\n/* note : canonical representation of XXH3 is the same as XXH64\n * since they both produce XXH64_hash_t values */\n\n\n/*-**********************************************************************\n*  XXH3 128-bit variant\n************************************************************************/\n\n/*!\n * @brief The return value from 128-bit hashes.\n *\n * Stored in little endian order, although the fields themselves are in native\n * endianness.\n */\ntypedef struct {\n    XXH64_hash_t low64;   /*!< `value & 0xFFFFFFFFFFFFFFFF` */\n    XXH64_hash_t high64;  /*!< `value >> 64` */\n} XXH128_hash_t;\n\n/*!\n * @brief Calculates 128-bit unseeded variant of XXH3 of @p data.\n *\n * @param data The block of data to be hashed, at least @p length bytes in size.\n * @param len  The length of @p data, in bytes.\n *\n * @return The calculated 128-bit variant of XXH3 value.\n *\n * The 128-bit variant of XXH3 has more strength, but it has a bit of overhead\n * for shorter inputs.\n *\n * This is equivalent to @ref XXH3_128bits_withSeed() with a seed of `0`, however\n * it may have slightly better performance due to constant propagation of the\n * defaults.\n *\n * @see XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len);\n/*! @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.\n *\n * @param data The block of data to be hashed, at least @p length bytes in size.\n * @param len  The length of @p data, in bytes.\n * @param seed The 64-bit seed to alter the hash result predictably.\n *\n * @return The calculated 128-bit variant of XXH3 value.\n *\n * @note\n *    seed == 0 produces the same results as @ref XXH3_64bits().\n *\n * This variant generates a custom secret on the fly based on default secret\n * altered using the @p seed value.\n *\n * While this operation is decently fast, note that it's not completely free.\n *\n * @see XXH3_128bits(), XXH3_128bits_withSecret(): other seeding variants\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);\n/*!\n * @brief Calculates 128-bit variant of XXH3 with a custom \"secret\".\n *\n * @param data       The block of data to be hashed, at least @p len bytes in size.\n * @param len        The length of @p data, in bytes.\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n *\n * @return The calculated 128-bit variant of XXH3 value.\n *\n * It's possible to provide any blob of bytes as a \"secret\" to generate the hash.\n * This makes it more difficult for an external actor to prepare an intentional collision.\n * The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).\n * However, the quality of the secret impacts the dispersion of the hash algorithm.\n * Therefore, the secret _must_ look like a bunch of random bytes.\n * Avoid \"trivial\" or structured data such as repeated sequences or a text document.\n * Whenever in doubt about the \"randomness\" of the blob of bytes,\n * consider employing @ref XXH3_generateSecret() instead (see below).\n * It will generate a proper high entropy secret derived from the blob of bytes.\n * Another advantage of using XXH3_generateSecret() is that\n * it guarantees that all bits within the initial blob of bytes\n * will impact every bit of the output.\n * This is not necessarily the case when using the blob of bytes directly\n * because, when hashing _small_ inputs, only a portion of the secret is employed.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);\n\n/*******   Streaming   *******/\n#ifndef XXH_NO_STREAM\n/*\n * Streaming requires state maintenance.\n * This operation costs memory and CPU.\n * As a consequence, streaming is slower than one-shot hashing.\n * For better performance, prefer one-shot functions whenever applicable.\n *\n * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits().\n * Use already declared XXH3_createState() and XXH3_freeState().\n *\n * All reset and streaming functions have same meaning as their 64-bit counterpart.\n */\n\n/*!\n * @brief Resets an @ref XXH3_state_t to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   - This function resets `statePtr` and generate a secret with default parameters.\n *   - Call it before @ref XXH3_128bits_update().\n *   - Digest will be equivalent to `XXH3_128bits()`.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);\n\n/*!\n * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.\n *\n * @param statePtr The state struct to reset.\n * @param seed     The 64-bit seed to alter the hash result predictably.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   - This function resets `statePtr` and generate a secret from `seed`.\n *   - Call it before @ref XXH3_128bits_update().\n *   - Digest will be equivalent to `XXH3_128bits_withSeed()`.\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);\n/*!\n * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.\n *\n * @param statePtr   The state struct to reset.\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * `secret` is referenced, it _must outlive_ the hash streaming session.\n * Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,\n * and the quality of produced hash values depends on secret's entropy\n * (secret's content should look like a bunch of random bytes).\n * When in doubt about the randomness of a candidate `secret`,\n * consider employing `XXH3_generateSecret()` instead (see below).\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);\n\n/*!\n * @brief Consumes a block of @p input to an @ref XXH3_state_t.\n *\n * Call this to incrementally consume blocks of data.\n *\n * @param statePtr The state struct to update.\n * @param input The block of data to be hashed, at least @p length bytes in size.\n * @param length The length of @p input, in bytes.\n *\n * @pre\n *   @p statePtr must not be `NULL`.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @note\n *   The memory between @p input and @p input + @p length must be valid,\n *   readable, contiguous memory. However, if @p length is `0`, @p input may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);\n\n/*!\n * @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t.\n *\n * @param statePtr The state struct to calculate the hash from.\n *\n * @pre\n *  @p statePtr must not be `NULL`.\n *\n * @return The calculated XXH3 128-bit hash value from that state.\n *\n * @note\n *   Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update,\n *   digest, and update again.\n *\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);\n#endif /* !XXH_NO_STREAM */\n\n/* Following helper functions make it possible to compare XXH128_hast_t values.\n * Since XXH128_hash_t is a structure, this capability is not offered by the language.\n * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */\n\n/*!\n * @brief Check equality of two XXH128_hash_t values\n *\n * @param h1 The 128-bit hash value.\n * @param h2 Another 128-bit hash value.\n *\n * @return `1` if `h1` and `h2` are equal.\n * @return `0` if they are not.\n */\nXXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);\n\n/*!\n * @brief Compares two @ref XXH128_hash_t\n *\n * This comparator is compatible with stdlib's `qsort()`/`bsearch()`.\n *\n * @param h128_1 Left-hand side value\n * @param h128_2 Right-hand side value\n *\n * @return >0 if @p h128_1  > @p h128_2\n * @return =0 if @p h128_1 == @p h128_2\n * @return <0 if @p h128_1  < @p h128_2\n */\nXXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2);\n\n\n/*******   Canonical representation   *******/\ntypedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t;\n\n\n/*!\n * @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t.\n *\n * @param dst  The @ref XXH128_canonical_t pointer to be stored to.\n * @param hash The @ref XXH128_hash_t to be converted.\n *\n * @pre\n *   @p dst must not be `NULL`.\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash);\n\n/*!\n * @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t.\n *\n * @param src The @ref XXH128_canonical_t to convert.\n *\n * @pre\n *   @p src must not be `NULL`.\n *\n * @return The converted hash.\n * @see @ref canonical_representation_example \"Canonical Representation Example\"\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src);\n\n\n#endif  /* !XXH_NO_XXH3 */\n#endif  /* XXH_NO_LONG_LONG */\n\n/*!\n * @}\n */\n#endif /* XXHASH_H_5627135585666179 */\n\n\n\n#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742)\n#define XXHASH_H_STATIC_13879238742\n/* ****************************************************************************\n * This section contains declarations which are not guaranteed to remain stable.\n * They may change in future versions, becoming incompatible with a different\n * version of the library.\n * These declarations should only be used with static linking.\n * Never use them in association with dynamic linking!\n ***************************************************************************** */\n\n/*\n * These definitions are only present to allow static allocation\n * of XXH states, on stack or in a struct, for example.\n * Never **ever** access their members directly.\n */\n\n/*!\n * @internal\n * @brief Structure for XXH32 streaming API.\n *\n * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,\n * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is\n * an opaque type. This allows fields to safely be changed.\n *\n * Typedef'd to @ref XXH32_state_t.\n * Do not access the members of this struct directly.\n * @see XXH64_state_s, XXH3_state_s\n */\nstruct XXH32_state_s {\n   XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */\n   XXH32_hash_t large_len;    /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */\n   XXH32_hash_t acc[4];       /*!< Accumulator lanes */\n   unsigned char buffer[16];  /*!< Internal buffer for partial reads. */\n   XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */\n   XXH32_hash_t reserved;     /*!< Reserved field. Do not read nor write to it. */\n};   /* typedef'd to XXH32_state_t */\n\n\n#ifndef XXH_NO_LONG_LONG  /* defined when there is no 64-bit support */\n\n/*!\n * @internal\n * @brief Structure for XXH64 streaming API.\n *\n * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,\n * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is\n * an opaque type. This allows fields to safely be changed.\n *\n * Typedef'd to @ref XXH64_state_t.\n * Do not access the members of this struct directly.\n * @see XXH32_state_s, XXH3_state_s\n */\nstruct XXH64_state_s {\n   XXH64_hash_t total_len;    /*!< Total length hashed. This is always 64-bit. */\n   XXH64_hash_t acc[4];       /*!< Accumulator lanes */\n   unsigned char buffer[32];  /*!< Internal buffer for partial reads.. */\n   XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */\n   XXH32_hash_t reserved32;   /*!< Reserved field, needed for padding anyways*/\n   XXH64_hash_t reserved64;   /*!< Reserved field. Do not read or write to it. */\n};   /* typedef'd to XXH64_state_t */\n\n#ifndef XXH_NO_XXH3\n\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */\n#  define XXH_ALIGN(n)      _Alignas(n)\n#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */\n/* In C++ alignas() is a keyword */\n#  define XXH_ALIGN(n)      alignas(n)\n#elif defined(__GNUC__)\n#  define XXH_ALIGN(n)      __attribute__ ((aligned(n)))\n#elif defined(_MSC_VER)\n#  define XXH_ALIGN(n)      __declspec(align(n))\n#else\n#  define XXH_ALIGN(n)   /* disabled */\n#endif\n\n/* Old GCC versions only accept the attribute after the type in structures. */\n#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))   /* C11+ */ \\\n    && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \\\n    && defined(__GNUC__)\n#   define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align)\n#else\n#   define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type\n#endif\n\n/*!\n * @internal\n * @brief The size of the internal XXH3 buffer.\n *\n * This is the optimal update size for incremental hashing.\n *\n * @see XXH3_64b_update(), XXH3_128b_update().\n */\n#define XXH3_INTERNALBUFFER_SIZE 256\n\n/*!\n * @def XXH3_SECRET_DEFAULT_SIZE\n * @brief Default Secret's size\n *\n * This is the size of internal XXH3_kSecret\n * and is needed by XXH3_generateSecret_fromSeed().\n *\n * Not to be confused with @ref XXH3_SECRET_SIZE_MIN.\n */\n#define XXH3_SECRET_DEFAULT_SIZE 192\n\n/*!\n * @internal\n * @brief Structure for XXH3 streaming API.\n *\n * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,\n * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined.\n * Otherwise it is an opaque type.\n * Never use this definition in combination with dynamic library.\n * This allows fields to safely be changed in the future.\n *\n * @note ** This structure has a strict alignment requirement of 64 bytes!! **\n * Do not allocate this with `malloc()` or `new`,\n * it will not be sufficiently aligned.\n * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation.\n *\n * Typedef'd to @ref XXH3_state_t.\n * Do never access the members of this struct directly.\n *\n * @see XXH3_INITSTATE() for stack initialization.\n * @see XXH3_createState(), XXH3_freeState().\n * @see XXH32_state_s, XXH64_state_s\n */\nstruct XXH3_state_s {\n   XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]);\n       /*!< The 8 accumulators. See @ref XXH32_state_s::acc and @ref XXH64_state_s::acc */\n   XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);\n       /*!< Used to store a custom secret generated from a seed. */\n   XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]);\n       /*!< The internal buffer. @see XXH32_state_s::mem32 */\n   XXH32_hash_t bufferedSize;\n       /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */\n   XXH32_hash_t useSeed;\n       /*!< Reserved field. Needed for padding on 64-bit. */\n   size_t nbStripesSoFar;\n       /*!< Number or stripes processed. */\n   XXH64_hash_t totalLen;\n       /*!< Total length hashed. 64-bit even on 32-bit targets. */\n   size_t nbStripesPerBlock;\n       /*!< Number of stripes per block. */\n   size_t secretLimit;\n       /*!< Size of @ref customSecret or @ref extSecret */\n   XXH64_hash_t seed;\n       /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */\n   XXH64_hash_t reserved64;\n       /*!< Reserved field. */\n   const unsigned char* extSecret;\n       /*!< Reference to an external secret for the _withSecret variants, NULL\n        *   for other variants. */\n   /* note: there may be some padding at the end due to alignment on 64 bytes */\n}; /* typedef'd to XXH3_state_t */\n\n#undef XXH_ALIGN_MEMBER\n\n/*!\n * @brief Initializes a stack-allocated `XXH3_state_s`.\n *\n * When the @ref XXH3_state_t structure is merely emplaced on stack,\n * it should be initialized with XXH3_INITSTATE() or a memset()\n * in case its first reset uses XXH3_NNbits_reset_withSeed().\n * This init can be omitted if the first reset uses default or _withSecret mode.\n * This operation isn't necessary when the state is created with XXH3_createState().\n * Note that this doesn't prepare the state for a streaming operation,\n * it's still necessary to use XXH3_NNbits_reset*() afterwards.\n */\n#define XXH3_INITSTATE(XXH3_state_ptr)                       \\\n    do {                                                     \\\n        XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \\\n        tmp_xxh3_state_ptr->seed = 0;                        \\\n        tmp_xxh3_state_ptr->extSecret = NULL;                \\\n    } while(0)\n\n\n/*!\n * @brief Calculates the 128-bit hash of @p data using XXH3.\n *\n * @param data The block of data to be hashed, at least @p len bytes in size.\n * @param len  The length of @p data, in bytes.\n * @param seed The 64-bit seed to alter the hash's output predictably.\n *\n * @pre\n *   The memory between @p data and @p data + @p len must be valid,\n *   readable, contiguous memory. However, if @p len is `0`, @p data may be\n *   `NULL`. In C++, this also must be *TriviallyCopyable*.\n *\n * @return The calculated 128-bit XXH3 value.\n *\n * @see @ref single_shot_example \"Single Shot Example\" for an example.\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);\n\n\n/* ===   Experimental API   === */\n/* Symbols defined below must be considered tied to a specific library version. */\n\n/*!\n * @brief Derive a high-entropy secret from any user-defined content, named customSeed.\n *\n * @param secretBuffer    A writable buffer for derived high-entropy secret data.\n * @param secretSize      Size of secretBuffer, in bytes.  Must be >= XXH3_SECRET_SIZE_MIN.\n * @param customSeed      A user-defined content.\n * @param customSeedSize  Size of customSeed, in bytes.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * The generated secret can be used in combination with `*_withSecret()` functions.\n * The `_withSecret()` variants are useful to provide a higher level of protection\n * than 64-bit seed, as it becomes much more difficult for an external actor to\n * guess how to impact the calculation logic.\n *\n * The function accepts as input a custom seed of any length and any content,\n * and derives from it a high-entropy secret of length @p secretSize into an\n * already allocated buffer @p secretBuffer.\n *\n * The generated secret can then be used with any `*_withSecret()` variant.\n * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(),\n * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret()\n * are part of this list. They all accept a `secret` parameter\n * which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN)\n * _and_ feature very high entropy (consist of random-looking bytes).\n * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can\n * be employed to ensure proper quality.\n *\n * @p customSeed can be anything. It can have any size, even small ones,\n * and its content can be anything, even \"poor entropy\" sources such as a bunch\n * of zeroes. The resulting `secret` will nonetheless provide all required qualities.\n *\n * @pre\n *   - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN\n *   - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior.\n *\n * Example code:\n * @code{.c}\n *    #include <stdio.h>\n *    #include <stdlib.h>\n *    #include <string.h>\n *    #define XXH_STATIC_LINKING_ONLY // expose unstable API\n *    #include \"xxhash.h\"\n *    // Hashes argv[2] using the entropy from argv[1].\n *    int main(int argc, char* argv[])\n *    {\n *        char secret[XXH3_SECRET_SIZE_MIN];\n *        if (argv != 3) { return 1; }\n *        XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1]));\n *        XXH64_hash_t h = XXH3_64bits_withSecret(\n *             argv[2], strlen(argv[2]),\n *             secret, sizeof(secret)\n *        );\n *        printf(\"%016llx\\n\", (unsigned long long) h);\n *    }\n * @endcode\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize);\n\n/*!\n * @brief Generate the same secret as the _withSeed() variants.\n *\n * @param secretBuffer A writable buffer of @ref XXH3_SECRET_DEFAULT_SIZE bytes\n * @param seed         The 64-bit seed to alter the hash result predictably.\n *\n * The generated secret can be used in combination with\n *`*_withSecret()` and `_withSecretandSeed()` variants.\n *\n * Example C++ `std::string` hash class:\n * @code{.cpp}\n *    #include <string>\n *    #define XXH_STATIC_LINKING_ONLY // expose unstable API\n *    #include \"xxhash.h\"\n *    // Slow, seeds each time\n *    class HashSlow {\n *        XXH64_hash_t seed;\n *    public:\n *        HashSlow(XXH64_hash_t s) : seed{s} {}\n *        size_t operator()(const std::string& x) const {\n *            return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)};\n *        }\n *    };\n *    // Fast, caches the seeded secret for future uses.\n *    class HashFast {\n *        unsigned char secret[XXH3_SECRET_DEFAULT_SIZE];\n *    public:\n *        HashFast(XXH64_hash_t s) {\n *            XXH3_generateSecret_fromSeed(secret, seed);\n *        }\n *        size_t operator()(const std::string& x) const {\n *            return size_t{\n *                XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret))\n *            };\n *        }\n *    };\n * @endcode\n */\nXXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed);\n\n/*!\n * @brief Maximum size of \"short\" key in bytes.\n */\n#define XXH3_MIDSIZE_MAX 240\n\n/*!\n * @brief Calculates 64/128-bit seeded variant of XXH3 hash of @p data.\n *\n * @param data       The block of data to be hashed, at least @p len bytes in size.\n * @param len        The length of @p data, in bytes.\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n * @param seed       The 64-bit seed to alter the hash result predictably.\n *\n * These variants generate hash values using either:\n * - @p seed for \"short\" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes)\n * - @p secret for \"large\" keys (>= @ref XXH3_MIDSIZE_MAX).\n *\n * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`.\n * `_withSeed()` has to generate the secret on the fly for \"large\" keys.\n * It's fast, but can be perceptible for \"not so large\" keys (< 1 KB).\n * `_withSecret()` has to generate the masks on the fly for \"small\" keys,\n * which requires more instructions than _withSeed() variants.\n * Therefore, _withSecretandSeed variant combines the best of both worlds.\n *\n * When @p secret has been generated by XXH3_generateSecret_fromSeed(),\n * this variant produces *exactly* the same results as `_withSeed()` variant,\n * hence offering only a pure speed benefit on \"large\" input,\n * by skipping the need to regenerate the secret for every large input.\n *\n * Another usage scenario is to hash the secret to a 64-bit hash value,\n * for example with XXH3_64bits(), which then becomes the seed,\n * and then employ both the seed and the secret in _withSecretandSeed().\n * On top of speed, an added benefit is that each bit in the secret\n * has a 50% chance to swap each bit in the output, via its impact to the seed.\n *\n * This is not guaranteed when using the secret directly in \"small data\" scenarios,\n * because only portions of the secret are employed for small data.\n */\nXXH_PUBLIC_API XXH_PUREF XXH64_hash_t\nXXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len,\n                              XXH_NOESCAPE const void* secret, size_t secretSize,\n                              XXH64_hash_t seed);\n\n/*!\n * @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.\n *\n * @param input      The memory segment to be hashed, at least @p len bytes in size.\n * @param length     The length of @p data, in bytes.\n * @param secret     The secret used to alter hash result predictably.\n * @param secretSize The length of @p secret, in bytes (must be >= XXH3_SECRET_SIZE_MIN)\n * @param seed64     The 64-bit seed to alter the hash result predictably.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @see XXH3_64bits_withSecretandSeed(): contract is the same.\n */\nXXH_PUBLIC_API XXH_PUREF XXH128_hash_t\nXXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length,\n                               XXH_NOESCAPE const void* secret, size_t secretSize,\n                               XXH64_hash_t seed64);\n\n#ifndef XXH_NO_STREAM\n/*!\n * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.\n *\n * @param statePtr   A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n * @param seed64     The 64-bit seed to alter the hash result predictably.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @see XXH3_64bits_withSecretandSeed(). Contract is identical.\n */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,\n                                    XXH_NOESCAPE const void* secret, size_t secretSize,\n                                    XXH64_hash_t seed64);\n\n/*!\n * @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.\n *\n * @param statePtr   A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().\n * @param secret     The secret data.\n * @param secretSize The length of @p secret, in bytes.\n * @param seed64     The 64-bit seed to alter the hash result predictably.\n *\n * @return @ref XXH_OK on success.\n * @return @ref XXH_ERROR on failure.\n *\n * @see XXH3_64bits_withSecretandSeed(). Contract is identical.\n *\n * Note: there was a bug in an earlier version of this function (<= v0.8.2)\n * that would make it generate an incorrect hash value\n * when @p seed == 0 and @p length < XXH3_MIDSIZE_MAX\n * and @p secret is different from XXH3_generateSecret_fromSeed().\n * As stated in the contract, the correct hash result must be\n * the same as XXH3_128bits_withSeed() when @p length <= XXH3_MIDSIZE_MAX.\n * Results generated by this older version are wrong, hence not comparable.\n */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,\n                                     XXH_NOESCAPE const void* secret, size_t secretSize,\n                                     XXH64_hash_t seed64);\n\n#endif /* !XXH_NO_STREAM */\n\n#endif  /* !XXH_NO_XXH3 */\n#endif  /* XXH_NO_LONG_LONG */\n#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)\n#  define XXH_IMPLEMENTATION\n#endif\n\n#endif  /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */\n\n\n/* ======================================================================== */\n/* ======================================================================== */\n/* ======================================================================== */\n\n\n/*-**********************************************************************\n * xxHash implementation\n *-**********************************************************************\n * xxHash's implementation used to be hosted inside xxhash.c.\n *\n * However, inlining requires implementation to be visible to the compiler,\n * hence be included alongside the header.\n * Previously, implementation was hosted inside xxhash.c,\n * which was then #included when inlining was activated.\n * This construction created issues with a few build and install systems,\n * as it required xxhash.c to be stored in /include directory.\n *\n * xxHash implementation is now directly integrated within xxhash.h.\n * As a consequence, xxhash.c is no longer needed in /include.\n *\n * xxhash.c is still available and is still useful.\n * In a \"normal\" setup, when xxhash is not inlined,\n * xxhash.h only exposes the prototypes and public symbols,\n * while xxhash.c can be built into an object file xxhash.o\n * which can then be linked into the final binary.\n ************************************************************************/\n\n#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \\\n   || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387)\n#  define XXH_IMPLEM_13a8737387\n\n/* *************************************\n*  Tuning parameters\n***************************************/\n\n/*!\n * @defgroup tuning Tuning parameters\n * @{\n *\n * Various macros to control xxHash's behavior.\n */\n#ifdef XXH_DOXYGEN\n/*!\n * @brief Define this to disable 64-bit code.\n *\n * Useful if only using the @ref XXH32_family and you have a strict C90 compiler.\n */\n#  define XXH_NO_LONG_LONG\n#  undef XXH_NO_LONG_LONG /* don't actually */\n/*!\n * @brief Controls how unaligned memory is accessed.\n *\n * By default, access to unaligned memory is controlled by `memcpy()`, which is\n * safe and portable.\n *\n * Unfortunately, on some target/compiler combinations, the generated assembly\n * is sub-optimal.\n *\n * The below switch allow selection of a different access method\n * in the search for improved performance.\n *\n * @par Possible options:\n *\n *  - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy`\n *   @par\n *     Use `memcpy()`. Safe and portable. Note that most modern compilers will\n *     eliminate the function call and treat it as an unaligned access.\n *\n *  - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))`\n *   @par\n *     Depends on compiler extensions and is therefore not portable.\n *     This method is safe _if_ your compiler supports it,\n *     and *generally* as fast or faster than `memcpy`.\n *\n *  - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast\n *  @par\n *     Casts directly and dereferences. This method doesn't depend on the\n *     compiler, but it violates the C standard as it directly dereferences an\n *     unaligned pointer. It can generate buggy code on targets which do not\n *     support unaligned memory accesses, but in some circumstances, it's the\n *     only known way to get the most performance.\n *\n *  - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift\n *  @par\n *     Also portable. This can generate the best code on old compilers which don't\n *     inline small `memcpy()` calls, and it might also be faster on big-endian\n *     systems which lack a native byteswap instruction. However, some compilers\n *     will emit literal byteshifts even if the target supports unaligned access.\n *\n *\n * @warning\n *   Methods 1 and 2 rely on implementation-defined behavior. Use these with\n *   care, as what works on one compiler/platform/optimization level may cause\n *   another to read garbage data or even crash.\n *\n * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details.\n *\n * Prefer these methods in priority order (0 > 3 > 1 > 2)\n */\n#  define XXH_FORCE_MEMORY_ACCESS 0\n\n/*!\n * @def XXH_SIZE_OPT\n * @brief Controls how much xxHash optimizes for size.\n *\n * xxHash, when compiled, tends to result in a rather large binary size. This\n * is mostly due to heavy usage to forced inlining and constant folding of the\n * @ref XXH3_family to increase performance.\n *\n * However, some developers prefer size over speed. This option can\n * significantly reduce the size of the generated code. When using the `-Os`\n * or `-Oz` options on GCC or Clang, this is defined to 1 by default,\n * otherwise it is defined to 0.\n *\n * Most of these size optimizations can be controlled manually.\n *\n * This is a number from 0-2.\n *  - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed\n *    comes first.\n *  - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more\n *    conservative and disables hacks that increase code size. It implies the\n *    options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0,\n *    and @ref XXH3_NEON_LANES == 8 if they are not already defined.\n *  - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible.\n *    Performance may cry. For example, the single shot functions just use the\n *    streaming API.\n */\n#  define XXH_SIZE_OPT 0\n\n/*!\n * @def XXH_FORCE_ALIGN_CHECK\n * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32()\n * and XXH64() only).\n *\n * This is an important performance trick for architectures without decent\n * unaligned memory access performance.\n *\n * It checks for input alignment, and when conditions are met, uses a \"fast\n * path\" employing direct 32-bit/64-bit reads, resulting in _dramatically\n * faster_ read speed.\n *\n * The check costs one initial branch per hash, which is generally negligible,\n * but not zero.\n *\n * Moreover, it's not useful to generate an additional code path if memory\n * access uses the same instruction for both aligned and unaligned\n * addresses (e.g. x86 and aarch64).\n *\n * In these cases, the alignment check can be removed by setting this macro to 0.\n * Then the code will always use unaligned memory access.\n * Align check is automatically disabled on x86, x64, ARM64, and some ARM chips\n * which are platforms known to offer good unaligned memory accesses performance.\n *\n * It is also disabled by default when @ref XXH_SIZE_OPT >= 1.\n *\n * This option does not affect XXH3 (only XXH32 and XXH64).\n */\n#  define XXH_FORCE_ALIGN_CHECK 0\n\n/*!\n * @def XXH_NO_INLINE_HINTS\n * @brief When non-zero, sets all functions to `static`.\n *\n * By default, xxHash tries to force the compiler to inline almost all internal\n * functions.\n *\n * This can usually improve performance due to reduced jumping and improved\n * constant folding, but significantly increases the size of the binary which\n * might not be favorable.\n *\n * Additionally, sometimes the forced inlining can be detrimental to performance,\n * depending on the architecture.\n *\n * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the\n * compiler full control on whether to inline or not.\n *\n * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if\n * @ref XXH_SIZE_OPT >= 1, this will automatically be defined.\n */\n#  define XXH_NO_INLINE_HINTS 0\n\n/*!\n * @def XXH3_INLINE_SECRET\n * @brief Determines whether to inline the XXH3 withSecret code.\n *\n * When the secret size is known, the compiler can improve the performance\n * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret().\n *\n * However, if the secret size is not known, it doesn't have any benefit. This\n * happens when xxHash is compiled into a global symbol. Therefore, if\n * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0.\n *\n * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers\n * that are *sometimes* force inline on -Og, and it is impossible to automatically\n * detect this optimization level.\n */\n#  define XXH3_INLINE_SECRET 0\n\n/*!\n * @def XXH32_ENDJMP\n * @brief Whether to use a jump for `XXH32_finalize`.\n *\n * For performance, `XXH32_finalize` uses multiple branches in the finalizer.\n * This is generally preferable for performance,\n * but depending on exact architecture, a jmp may be preferable.\n *\n * This setting is only possibly making a difference for very small inputs.\n */\n#  define XXH32_ENDJMP 0\n\n/*!\n * @internal\n * @brief Redefines old internal names.\n *\n * For compatibility with code that uses xxHash's internals before the names\n * were changed to improve namespacing. There is no other reason to use this.\n */\n#  define XXH_OLD_NAMES\n#  undef XXH_OLD_NAMES /* don't actually use, it is ugly. */\n\n/*!\n * @def XXH_NO_STREAM\n * @brief Disables the streaming API.\n *\n * When xxHash is not inlined and the streaming functions are not used, disabling\n * the streaming functions can improve code size significantly, especially with\n * the @ref XXH3_family which tends to make constant folded copies of itself.\n */\n#  define XXH_NO_STREAM\n#  undef XXH_NO_STREAM /* don't actually */\n#endif /* XXH_DOXYGEN */\n/*!\n * @}\n */\n\n#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */\n   /* prefer __packed__ structures (method 1) for GCC\n    * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy\n    * which for some reason does unaligned loads. */\n#  if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED))\n#    define XXH_FORCE_MEMORY_ACCESS 1\n#  endif\n#endif\n\n#ifndef XXH_SIZE_OPT\n   /* default to 1 for -Os or -Oz */\n#  if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__)\n#    define XXH_SIZE_OPT 1\n#  else\n#    define XXH_SIZE_OPT 0\n#  endif\n#endif\n\n#ifndef XXH_FORCE_ALIGN_CHECK  /* can be defined externally */\n   /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */\n#  if XXH_SIZE_OPT >= 1 || \\\n      defined(__i386)  || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \\\n   || defined(_M_IX86) || defined(_M_X64)     || defined(_M_ARM64)    || defined(_M_ARM) /* visual */\n#    define XXH_FORCE_ALIGN_CHECK 0\n#  else\n#    define XXH_FORCE_ALIGN_CHECK 1\n#  endif\n#endif\n\n#ifndef XXH_NO_INLINE_HINTS\n#  if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__)  /* -O0, -fno-inline */\n#    define XXH_NO_INLINE_HINTS 1\n#  else\n#    define XXH_NO_INLINE_HINTS 0\n#  endif\n#endif\n\n#ifndef XXH3_INLINE_SECRET\n#  if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \\\n     || !defined(XXH_INLINE_ALL)\n#    define XXH3_INLINE_SECRET 0\n#  else\n#    define XXH3_INLINE_SECRET 1\n#  endif\n#endif\n\n#ifndef XXH32_ENDJMP\n/* generally preferable for performance */\n#  define XXH32_ENDJMP 0\n#endif\n\n/*!\n * @defgroup impl Implementation\n * @{\n */\n\n\n/* *************************************\n*  Includes & Memory related functions\n***************************************/\n#if defined(XXH_NO_STREAM)\n/* nothing */\n#elif defined(XXH_NO_STDLIB)\n\n/* When requesting to disable any mention of stdlib,\n * the library loses the ability to invoked malloc / free.\n * In practice, it means that functions like `XXH*_createState()`\n * will always fail, and return NULL.\n * This flag is useful in situations where\n * xxhash.h is integrated into some kernel, embedded or limited environment\n * without access to dynamic allocation.\n */\n\nstatic XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; }\nstatic void XXH_free(void* p) { (void)p; }\n\n#else\n\n/*\n * Modify the local functions below should you wish to use\n * different memory routines for malloc() and free()\n */\n#include <stdlib.h>\n\n/*!\n * @internal\n * @brief Modify this function to use a different routine than malloc().\n */\nstatic XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); }\n\n/*!\n * @internal\n * @brief Modify this function to use a different routine than free().\n */\nstatic void XXH_free(void* p) { free(p); }\n\n#endif  /* XXH_NO_STDLIB */\n\n#ifndef XXH_memcpy\n/*!\n * @internal\n * @brief XXH_memcpy() macro can be redirected at compile time\n */\n#  include <string.h>\n#  define XXH_memcpy memcpy\n#endif\n\n#ifndef XXH_memset\n/*!\n * @internal\n * @brief XXH_memset() macro can be redirected at compile time\n */\n#  include <string.h>\n#  define XXH_memset memset\n#endif\n\n#ifndef XXH_memcmp\n/*!\n * @internal\n * @brief XXH_memcmp() macro can be redirected at compile time\n * Note: only needed by XXH128.\n */\n#  include <string.h>\n#  define XXH_memcmp memcmp\n#endif\n\n\n\n#include <limits.h>   /* ULLONG_MAX */\n\n\n/* *************************************\n*  Compiler Specific Options\n***************************************/\n#ifdef _MSC_VER /* Visual Studio warning fix */\n#  pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */\n#endif\n\n#if XXH_NO_INLINE_HINTS  /* disable inlining hints */\n#  if defined(__GNUC__) || defined(__clang__)\n#    define XXH_FORCE_INLINE static __attribute__((__unused__))\n#  else\n#    define XXH_FORCE_INLINE static\n#  endif\n#  define XXH_NO_INLINE static\n/* enable inlining hints */\n#elif defined(__GNUC__) || defined(__clang__)\n#  define XXH_FORCE_INLINE static __inline__ __attribute__((__always_inline__, __unused__))\n#  define XXH_NO_INLINE static __attribute__((__noinline__))\n#elif defined(_MSC_VER)  /* Visual Studio */\n#  define XXH_FORCE_INLINE static __forceinline\n#  define XXH_NO_INLINE static __declspec(noinline)\n#elif defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))   /* C99 */\n#  define XXH_FORCE_INLINE static inline\n#  define XXH_NO_INLINE static\n#else\n#  define XXH_FORCE_INLINE static\n#  define XXH_NO_INLINE static\n#endif\n\n#if defined(XXH_INLINE_ALL)\n#  define XXH_STATIC XXH_FORCE_INLINE\n#else\n#  define XXH_STATIC static\n#endif\n\n#if XXH3_INLINE_SECRET\n#  define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE\n#else\n#  define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE\n#endif\n\n#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */\n#  define XXH_RESTRICT   /* disable */\n#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* >= C99 */\n#  define XXH_RESTRICT   restrict\n#elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \\\n   || (defined (__clang__)) \\\n   || (defined (_MSC_VER) && (_MSC_VER >= 1400)) \\\n   || (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300))\n/*\n * There are a LOT more compilers that recognize __restrict but this\n * covers the major ones.\n */\n#  define XXH_RESTRICT   __restrict\n#else\n#  define XXH_RESTRICT   /* disable */\n#endif\n\n/* *************************************\n*  Debug\n***************************************/\n/*!\n * @ingroup tuning\n * @def XXH_DEBUGLEVEL\n * @brief Sets the debugging level.\n *\n * XXH_DEBUGLEVEL is expected to be defined externally, typically via the\n * compiler's command line options. The value must be a number.\n */\n#ifndef XXH_DEBUGLEVEL\n#  ifdef DEBUGLEVEL /* backwards compat */\n#    define XXH_DEBUGLEVEL DEBUGLEVEL\n#  else\n#    define XXH_DEBUGLEVEL 0\n#  endif\n#endif\n\n#if (XXH_DEBUGLEVEL>=1)\n#  include <assert.h>   /* note: can still be disabled with NDEBUG */\n#  define XXH_ASSERT(c)   assert(c)\n#else\n#  if defined(__INTEL_COMPILER)\n#    define XXH_ASSERT(c)   XXH_ASSUME((unsigned char) (c))\n#  else\n#    define XXH_ASSERT(c)   XXH_ASSUME(c)\n#  endif\n#endif\n\n/* note: use after variable declarations */\n#ifndef XXH_STATIC_ASSERT\n#  if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)    /* C11 */\n#    define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0)\n#  elif defined(__cplusplus) && (__cplusplus >= 201103L)            /* C++11 */\n#    define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0)\n#  else\n#    define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0)\n#  endif\n#  define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c)\n#endif\n\n/*!\n * @internal\n * @def XXH_COMPILER_GUARD(var)\n * @brief Used to prevent unwanted optimizations for @p var.\n *\n * It uses an empty GCC inline assembly statement with a register constraint\n * which forces @p var into a general purpose register (eg eax, ebx, ecx\n * on x86) and marks it as modified.\n *\n * This is used in a few places to avoid unwanted autovectorization (e.g.\n * XXH32_round()). All vectorization we want is explicit via intrinsics,\n * and _usually_ isn't wanted elsewhere.\n *\n * We also use it to prevent unwanted constant folding for AArch64 in\n * XXH3_initCustomSecret_scalar().\n */\n#if defined(__GNUC__) || defined(__clang__)\n#  define XXH_COMPILER_GUARD(var) __asm__(\"\" : \"+r\" (var))\n#else\n#  define XXH_COMPILER_GUARD(var) ((void)0)\n#endif\n\n/* Specifically for NEON vectors which use the \"w\" constraint, on\n * Clang. */\n#if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__)\n#  define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__(\"\" : \"+w\" (var))\n#else\n#  define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0)\n#endif\n\n/* *************************************\n*  Basic Types\n***************************************/\n#if !defined (__VMS) \\\n && (defined (__cplusplus) \\\n || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   ifdef _AIX\n#     include <inttypes.h>\n#   else\n#     include <stdint.h>\n#   endif\n    typedef uint8_t xxh_u8;\n#else\n    typedef unsigned char xxh_u8;\n#endif\ntypedef XXH32_hash_t xxh_u32;\n\n#ifdef XXH_OLD_NAMES\n#  warning \"XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly\"\n#  define BYTE xxh_u8\n#  define U8   xxh_u8\n#  define U32  xxh_u32\n#endif\n\n/* ***   Memory access   *** */\n\n/*!\n * @internal\n * @fn xxh_u32 XXH_read32(const void* ptr)\n * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness.\n *\n * Affected by @ref XXH_FORCE_MEMORY_ACCESS.\n *\n * @param ptr The pointer to read from.\n * @return The 32-bit native endian integer from the bytes at @p ptr.\n */\n\n/*!\n * @internal\n * @fn xxh_u32 XXH_readLE32(const void* ptr)\n * @brief Reads an unaligned 32-bit little endian integer from @p ptr.\n *\n * Affected by @ref XXH_FORCE_MEMORY_ACCESS.\n *\n * @param ptr The pointer to read from.\n * @return The 32-bit little endian integer from the bytes at @p ptr.\n */\n\n/*!\n * @internal\n * @fn xxh_u32 XXH_readBE32(const void* ptr)\n * @brief Reads an unaligned 32-bit big endian integer from @p ptr.\n *\n * Affected by @ref XXH_FORCE_MEMORY_ACCESS.\n *\n * @param ptr The pointer to read from.\n * @return The 32-bit big endian integer from the bytes at @p ptr.\n */\n\n/*!\n * @internal\n * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align)\n * @brief Like @ref XXH_readLE32(), but has an option for aligned reads.\n *\n * Affected by @ref XXH_FORCE_MEMORY_ACCESS.\n * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is\n * always @ref XXH_alignment::XXH_unaligned.\n *\n * @param ptr The pointer to read from.\n * @param align Whether @p ptr is aligned.\n * @pre\n *   If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte\n *   aligned.\n * @return The 32-bit little endian integer from the bytes at @p ptr.\n */\n\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))\n/*\n * Manual byteshift. Best for old compilers which don't inline memcpy.\n * We actually directly use XXH_readLE32 and XXH_readBE32.\n */\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))\n\n/*\n * Force direct memory access. Only works on CPU which support unaligned memory\n * access in hardware.\n */\nstatic xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; }\n\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))\n\n/*\n * __attribute__((aligned(1))) is supported by gcc and clang. Originally the\n * documentation claimed that it only increased the alignment, but actually it\n * can decrease it on gcc, clang, and icc:\n * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,\n * https://gcc.godbolt.org/z/xYez1j67Y.\n */\n#ifdef XXH_OLD_NAMES\ntypedef union { xxh_u32 u32; } __attribute__((__packed__)) unalign;\n#endif\nstatic xxh_u32 XXH_read32(const void* ptr)\n{\n    typedef __attribute__((__aligned__(1))) xxh_u32 xxh_unalign32;\n    return *((const xxh_unalign32*)ptr);\n}\n\n#else\n\n/*\n * Portable and safe solution. Generally efficient.\n * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html\n */\nstatic xxh_u32 XXH_read32(const void* memPtr)\n{\n    xxh_u32 val;\n    XXH_memcpy(&val, memPtr, sizeof(val));\n    return val;\n}\n\n#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */\n\n\n/* ***   Endianness   *** */\n\n/*!\n * @ingroup tuning\n * @def XXH_CPU_LITTLE_ENDIAN\n * @brief Whether the target is little endian.\n *\n * Defined to 1 if the target is little endian, or 0 if it is big endian.\n * It can be defined externally, for example on the compiler command line.\n *\n * If it is not defined,\n * a runtime check (which is usually constant folded) is used instead.\n *\n * @note\n *   This is not necessarily defined to an integer constant.\n *\n * @see XXH_isLittleEndian() for the runtime check.\n */\n#ifndef XXH_CPU_LITTLE_ENDIAN\n/*\n * Try to detect endianness automatically, to avoid the nonstandard behavior\n * in `XXH_isLittleEndian()`\n */\n#  if defined(_WIN32) /* Windows is always little endian */ \\\n     || defined(__LITTLE_ENDIAN__) \\\n     || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)\n#    define XXH_CPU_LITTLE_ENDIAN 1\n#  elif defined(__BIG_ENDIAN__) \\\n     || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#    define XXH_CPU_LITTLE_ENDIAN 0\n#  else\n/*!\n * @internal\n * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN.\n *\n * Most compilers will constant fold this.\n */\nstatic int XXH_isLittleEndian(void)\n{\n    /*\n     * Portable and well-defined behavior.\n     * Don't use static: it is detrimental to performance.\n     */\n    const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 };\n    return one.c[0];\n}\n#   define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()\n#  endif\n#endif\n\n\n\n\n/* ****************************************\n*  Compiler-specific Functions and Macros\n******************************************/\n#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\n\n#ifdef __has_builtin\n#  define XXH_HAS_BUILTIN(x) __has_builtin(x)\n#else\n#  define XXH_HAS_BUILTIN(x) 0\n#endif\n\n\n\n/*\n * C23 and future versions have standard \"unreachable()\".\n * Once it has been implemented reliably we can add it as an\n * additional case:\n *\n * ```\n * #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN)\n * #  include <stddef.h>\n * #  ifdef unreachable\n * #    define XXH_UNREACHABLE() unreachable()\n * #  endif\n * #endif\n * ```\n *\n * Note C++23 also has std::unreachable() which can be detected\n * as follows:\n * ```\n * #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L)\n * #  include <utility>\n * #  define XXH_UNREACHABLE() std::unreachable()\n * #endif\n * ```\n * NB: `__cpp_lib_unreachable` is defined in the `<version>` header.\n * We don't use that as including `<utility>` in `extern \"C\"` blocks\n * doesn't work on GCC12\n */\n\n#if XXH_HAS_BUILTIN(__builtin_unreachable)\n#  define XXH_UNREACHABLE() __builtin_unreachable()\n\n#elif defined(_MSC_VER)\n#  define XXH_UNREACHABLE() __assume(0)\n\n#else\n#  define XXH_UNREACHABLE()\n#endif\n\n#if XXH_HAS_BUILTIN(__builtin_assume)\n#  define XXH_ASSUME(c) __builtin_assume(c)\n#else\n#  define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); }\n#endif\n\n/*!\n * @internal\n * @def XXH_rotl32(x,r)\n * @brief 32-bit rotate left.\n *\n * @param x The 32-bit integer to be rotated.\n * @param r The number of bits to rotate.\n * @pre\n *   @p r > 0 && @p r < 32\n * @note\n *   @p x and @p r may be evaluated multiple times.\n * @return The rotated result.\n */\n#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \\\n                               && XXH_HAS_BUILTIN(__builtin_rotateleft64)\n#  define XXH_rotl32 __builtin_rotateleft32\n#  define XXH_rotl64 __builtin_rotateleft64\n#elif XXH_HAS_BUILTIN(__builtin_stdc_rotate_left)\n#  define XXH_rotl32 __builtin_stdc_rotate_left\n#  define XXH_rotl64 __builtin_stdc_rotate_left\n/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */\n#elif defined(_MSC_VER)\n#  define XXH_rotl32(x,r) _rotl(x,r)\n#  define XXH_rotl64(x,r) _rotl64(x,r)\n#else\n#  define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))\n#  define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r))))\n#endif\n\n/*!\n * @internal\n * @fn xxh_u32 XXH_swap32(xxh_u32 x)\n * @brief A 32-bit byteswap.\n *\n * @param x The 32-bit integer to byteswap.\n * @return @p x, byteswapped.\n */\n#if defined(_MSC_VER)     /* Visual Studio */\n#  define XXH_swap32 _byteswap_ulong\n#elif XXH_GCC_VERSION >= 403\n#  define XXH_swap32 __builtin_bswap32\n#else\nstatic xxh_u32 XXH_swap32 (xxh_u32 x)\n{\n    return  ((x << 24) & 0xff000000 ) |\n            ((x <<  8) & 0x00ff0000 ) |\n            ((x >>  8) & 0x0000ff00 ) |\n            ((x >> 24) & 0x000000ff );\n}\n#endif\n\n\n/* ***************************\n*  Memory reads\n*****************************/\n\n/*!\n * @internal\n * @brief Enum to indicate whether a pointer is aligned.\n */\ntypedef enum {\n    XXH_aligned,  /*!< Aligned */\n    XXH_unaligned /*!< Possibly unaligned */\n} XXH_alignment;\n\n/*\n * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load.\n *\n * This is ideal for older compilers which don't inline memcpy.\n */\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))\n\nXXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr)\n{\n    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;\n    return bytePtr[0]\n         | ((xxh_u32)bytePtr[1] << 8)\n         | ((xxh_u32)bytePtr[2] << 16)\n         | ((xxh_u32)bytePtr[3] << 24);\n}\n\nXXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr)\n{\n    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;\n    return bytePtr[3]\n         | ((xxh_u32)bytePtr[2] << 8)\n         | ((xxh_u32)bytePtr[1] << 16)\n         | ((xxh_u32)bytePtr[0] << 24);\n}\n\n#else\nXXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));\n}\n\nstatic xxh_u32 XXH_readBE32(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);\n}\n#endif\n\nXXH_FORCE_INLINE xxh_u32\nXXH_readLE32_align(const void* ptr, XXH_alignment align)\n{\n    if (align==XXH_unaligned) {\n        return XXH_readLE32(ptr);\n    } else {\n        return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr);\n    }\n}\n\n\n/* *************************************\n*  Misc\n***************************************/\n/*! @ingroup public */\nXXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }\n\n\n/* *******************************************************************\n*  32-bit hash functions\n*********************************************************************/\n/*!\n * @}\n * @defgroup XXH32_impl XXH32 implementation\n * @ingroup impl\n *\n * Details on the XXH32 implementation.\n * @{\n */\n /* #define instead of static const, to be used as initializers */\n#define XXH_PRIME32_1  0x9E3779B1U  /*!< 0b10011110001101110111100110110001 */\n#define XXH_PRIME32_2  0x85EBCA77U  /*!< 0b10000101111010111100101001110111 */\n#define XXH_PRIME32_3  0xC2B2AE3DU  /*!< 0b11000010101100101010111000111101 */\n#define XXH_PRIME32_4  0x27D4EB2FU  /*!< 0b00100111110101001110101100101111 */\n#define XXH_PRIME32_5  0x165667B1U  /*!< 0b00010110010101100110011110110001 */\n\n#ifdef XXH_OLD_NAMES\n#  define PRIME32_1 XXH_PRIME32_1\n#  define PRIME32_2 XXH_PRIME32_2\n#  define PRIME32_3 XXH_PRIME32_3\n#  define PRIME32_4 XXH_PRIME32_4\n#  define PRIME32_5 XXH_PRIME32_5\n#endif\n\n/*!\n * @internal\n * @brief Normal stripe processing routine.\n *\n * This shuffles the bits so that any bit from @p input impacts several bits in\n * @p acc.\n *\n * @param acc The accumulator lane.\n * @param input The stripe of input to mix.\n * @return The mixed accumulator lane.\n */\nstatic xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)\n{\n    acc += input * XXH_PRIME32_2;\n    acc  = XXH_rotl32(acc, 13);\n    acc *= XXH_PRIME32_1;\n#if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)\n    /*\n     * UGLY HACK:\n     * A compiler fence is used to prevent GCC and Clang from\n     * autovectorizing the XXH32 loop (pragmas and attributes don't work for some\n     * reason) without globally disabling SSE4.1.\n     *\n     * The reason we want to avoid vectorization is because despite working on\n     * 4 integers at a time, there are multiple factors slowing XXH32 down on\n     * SSE4:\n     * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on\n     *   newer chips!) making it slightly slower to multiply four integers at\n     *   once compared to four integers independently. Even when pmulld was\n     *   fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE\n     *   just to multiply unless doing a long operation.\n     *\n     * - Four instructions are required to rotate,\n     *      movqda tmp,  v // not required with VEX encoding\n     *      pslld  tmp, 13 // tmp <<= 13\n     *      psrld  v,   19 // x >>= 19\n     *      por    v,  tmp // x |= tmp\n     *   compared to one for scalar:\n     *      roll   v, 13    // reliably fast across the board\n     *      shldl  v, v, 13 // Sandy Bridge and later prefer this for some reason\n     *\n     * - Instruction level parallelism is actually more beneficial here because\n     *   the SIMD actually serializes this operation: While v1 is rotating, v2\n     *   can load data, while v3 can multiply. SSE forces them to operate\n     *   together.\n     *\n     * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing\n     * the loop. NEON is only faster on the A53, and with the newer cores, it is less\n     * than half the speed.\n     *\n     * Additionally, this is used on WASM SIMD128 because it JITs to the same\n     * SIMD instructions and has the same issue.\n     */\n    XXH_COMPILER_GUARD(acc);\n#endif\n    return acc;\n}\n\n/*!\n * @internal\n * @brief Mixes all bits to finalize the hash.\n *\n * The final mix ensures that all input bits have a chance to impact any bit in\n * the output digest, resulting in an unbiased distribution.\n *\n * @param hash The hash to avalanche.\n * @return The avalanched hash.\n */\nstatic xxh_u32 XXH32_avalanche(xxh_u32 hash)\n{\n    hash ^= hash >> 15;\n    hash *= XXH_PRIME32_2;\n    hash ^= hash >> 13;\n    hash *= XXH_PRIME32_3;\n    hash ^= hash >> 16;\n    return hash;\n}\n\n#define XXH_get32bits(p) XXH_readLE32_align(p, align)\n\n/*!\n * @internal\n * @brief Sets up the initial accumulator state for XXH32().\n */\nXXH_FORCE_INLINE void\nXXH32_initAccs(xxh_u32 *acc, xxh_u32 seed)\n{\n    XXH_ASSERT(acc != NULL);\n    acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2;\n    acc[1] = seed + XXH_PRIME32_2;\n    acc[2] = seed + 0;\n    acc[3] = seed - XXH_PRIME32_1;\n}\n\n/*!\n * @internal\n * @brief Consumes a block of data for XXH32().\n *\n * @return the end input pointer.\n */\nXXH_FORCE_INLINE const xxh_u8 *\nXXH32_consumeLong(\n    xxh_u32 *XXH_RESTRICT acc,\n    xxh_u8 const *XXH_RESTRICT input,\n    size_t len,\n    XXH_alignment align\n)\n{\n    const xxh_u8* const bEnd = input + len;\n    const xxh_u8* const limit = bEnd - 15;\n    XXH_ASSERT(acc != NULL);\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(len >= 16);\n    do {\n        acc[0] = XXH32_round(acc[0], XXH_get32bits(input)); input += 4;\n        acc[1] = XXH32_round(acc[1], XXH_get32bits(input)); input += 4;\n        acc[2] = XXH32_round(acc[2], XXH_get32bits(input)); input += 4;\n        acc[3] = XXH32_round(acc[3], XXH_get32bits(input)); input += 4;\n    } while (input < limit);\n\n    return input;\n}\n\n/*!\n * @internal\n * @brief Merges the accumulator lanes together for XXH32()\n */\nXXH_FORCE_INLINE XXH_PUREF xxh_u32\nXXH32_mergeAccs(const xxh_u32 *acc)\n{\n    XXH_ASSERT(acc != NULL);\n    return XXH_rotl32(acc[0], 1)  + XXH_rotl32(acc[1], 7)\n         + XXH_rotl32(acc[2], 12) + XXH_rotl32(acc[3], 18);\n}\n\n/*!\n * @internal\n * @brief Processes the last 0-15 bytes of @p ptr.\n *\n * There may be up to 15 bytes remaining to consume from the input.\n * This final stage will digest them to ensure that all input bytes are present\n * in the final mix.\n *\n * @param hash The hash to finalize.\n * @param ptr The pointer to the remaining input.\n * @param len The remaining length, modulo 16.\n * @param align Whether @p ptr is aligned.\n * @return The finalized hash.\n * @see XXH64_finalize().\n */\nstatic XXH_PUREF xxh_u32\nXXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)\n{\n#define XXH_PROCESS1 do {                             \\\n    hash += (*ptr++) * XXH_PRIME32_5;                 \\\n    hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1;      \\\n} while (0)\n\n#define XXH_PROCESS4 do {                             \\\n    hash += XXH_get32bits(ptr) * XXH_PRIME32_3;       \\\n    ptr += 4;                                         \\\n    hash  = XXH_rotl32(hash, 17) * XXH_PRIME32_4;     \\\n} while (0)\n\n    if (ptr==NULL) XXH_ASSERT(len == 0);\n\n    /* Compact rerolled version; generally faster */\n    if (!XXH32_ENDJMP) {\n        len &= 15;\n        while (len >= 4) {\n            XXH_PROCESS4;\n            len -= 4;\n        }\n        while (len > 0) {\n            XXH_PROCESS1;\n            --len;\n        }\n        return XXH32_avalanche(hash);\n    } else {\n         switch(len&15) /* or switch(bEnd - p) */ {\n           case 12:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 8:       XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 4:       XXH_PROCESS4;\n                         return XXH32_avalanche(hash);\n\n           case 13:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 9:       XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 5:       XXH_PROCESS4;\n                         XXH_PROCESS1;\n                         return XXH32_avalanche(hash);\n\n           case 14:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 10:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 6:       XXH_PROCESS4;\n                         XXH_PROCESS1;\n                         XXH_PROCESS1;\n                         return XXH32_avalanche(hash);\n\n           case 15:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 11:      XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 7:       XXH_PROCESS4;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 3:       XXH_PROCESS1;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 2:       XXH_PROCESS1;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 1:       XXH_PROCESS1;\n                         XXH_FALLTHROUGH;  /* fallthrough */\n           case 0:       return XXH32_avalanche(hash);\n        }\n        XXH_ASSERT(0);\n        return hash;   /* reaching this point is deemed impossible */\n    }\n}\n\n#ifdef XXH_OLD_NAMES\n#  define PROCESS1 XXH_PROCESS1\n#  define PROCESS4 XXH_PROCESS4\n#else\n#  undef XXH_PROCESS1\n#  undef XXH_PROCESS4\n#endif\n\n/*!\n * @internal\n * @brief The implementation for @ref XXH32().\n *\n * @param input , len , seed Directly passed from @ref XXH32().\n * @param align Whether @p input is aligned.\n * @return The calculated hash.\n */\nXXH_FORCE_INLINE XXH_PUREF xxh_u32\nXXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)\n{\n    xxh_u32 h32;\n\n    if (input==NULL) XXH_ASSERT(len == 0);\n\n    if (len>=16) {\n        xxh_u32 acc[4];\n        XXH32_initAccs(acc, seed);\n\n        input = XXH32_consumeLong(acc, input, len, align);\n\n        h32 = XXH32_mergeAccs(acc);\n    } else {\n        h32  = seed + XXH_PRIME32_5;\n    }\n\n    h32 += (xxh_u32)len;\n\n    return XXH32_finalize(h32, input, len&15, align);\n}\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed)\n{\n#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2\n    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */\n    XXH32_state_t state;\n    XXH32_reset(&state, seed);\n    XXH32_update(&state, (const xxh_u8*)input, len);\n    return XXH32_digest(&state);\n#else\n    if (XXH_FORCE_ALIGN_CHECK) {\n        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */\n            return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);\n    }   }\n\n    return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);\n#endif\n}\n\n\n\n/*******   Hash streaming   *******/\n#ifndef XXH_NO_STREAM\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)\n{\n    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));\n}\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)\n{\n    XXH_free(statePtr);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)\n{\n    XXH_memcpy(dstState, srcState, sizeof(*dstState));\n}\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed)\n{\n    XXH_ASSERT(statePtr != NULL);\n    XXH_memset(statePtr, 0, sizeof(*statePtr));\n    XXH32_initAccs(statePtr->acc, seed);\n    return XXH_OK;\n}\n\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH32_update(XXH32_state_t* state, const void* input, size_t len)\n{\n    if (input==NULL) {\n        XXH_ASSERT(len == 0);\n        return XXH_OK;\n    }\n\n    state->total_len_32 += (XXH32_hash_t)len;\n    state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16));\n\n    XXH_ASSERT(state->bufferedSize < sizeof(state->buffer));\n    if (len < sizeof(state->buffer) - state->bufferedSize)  {   /* fill in tmp buffer */\n        XXH_memcpy(state->buffer + state->bufferedSize, input, len);\n        state->bufferedSize += (XXH32_hash_t)len;\n        return XXH_OK;\n    }\n\n    {   const xxh_u8* xinput = (const xxh_u8*)input;\n        const xxh_u8* const bEnd = xinput + len;\n\n        if (state->bufferedSize) {   /* non-empty buffer: complete first */\n            XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize);\n            xinput += sizeof(state->buffer) - state->bufferedSize;\n            /* then process one round */\n            (void)XXH32_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned);\n            state->bufferedSize = 0;\n        }\n\n        XXH_ASSERT(xinput <= bEnd);\n        if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) {\n            /* Process the remaining data */\n            xinput = XXH32_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned);\n        }\n\n        if (xinput < bEnd) {\n            /* Copy the leftover to the tmp buffer */\n            XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput));\n            state->bufferedSize = (unsigned)(bEnd-xinput);\n        }\n    }\n\n    return XXH_OK;\n}\n\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)\n{\n    xxh_u32 h32;\n\n    if (state->large_len) {\n        h32 = XXH32_mergeAccs(state->acc);\n    } else {\n        h32 = state->acc[2] /* == seed */ + XXH_PRIME32_5;\n    }\n\n    h32 += state->total_len_32;\n\n    return XXH32_finalize(h32, state->buffer, state->bufferedSize, XXH_aligned);\n}\n#endif /* !XXH_NO_STREAM */\n\n/*******   Canonical representation   *******/\n\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)\n{\n    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));\n    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);\n    XXH_memcpy(dst, &hash, sizeof(*dst));\n}\n/*! @ingroup XXH32_family */\nXXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)\n{\n    return XXH_readBE32(src);\n}\n\n\n#ifndef XXH_NO_LONG_LONG\n\n/* *******************************************************************\n*  64-bit hash functions\n*********************************************************************/\n/*!\n * @}\n * @ingroup impl\n * @{\n */\n/*******   Memory access   *******/\n\ntypedef XXH64_hash_t xxh_u64;\n\n#ifdef XXH_OLD_NAMES\n#  define U64 xxh_u64\n#endif\n\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))\n/*\n * Manual byteshift. Best for old compilers which don't inline memcpy.\n * We actually directly use XXH_readLE64 and XXH_readBE64.\n */\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))\n\n/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */\nstatic xxh_u64 XXH_read64(const void* memPtr)\n{\n    return *(const xxh_u64*) memPtr;\n}\n\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))\n\n/*\n * __attribute__((aligned(1))) is supported by gcc and clang. Originally the\n * documentation claimed that it only increased the alignment, but actually it\n * can decrease it on gcc, clang, and icc:\n * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,\n * https://gcc.godbolt.org/z/xYez1j67Y.\n */\n#ifdef XXH_OLD_NAMES\ntypedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((__packed__)) unalign64;\n#endif\nstatic xxh_u64 XXH_read64(const void* ptr)\n{\n    typedef __attribute__((__aligned__(1))) xxh_u64 xxh_unalign64;\n    return *((const xxh_unalign64*)ptr);\n}\n\n#else\n\n/*\n * Portable and safe solution. Generally efficient.\n * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html\n */\nstatic xxh_u64 XXH_read64(const void* memPtr)\n{\n    xxh_u64 val;\n    XXH_memcpy(&val, memPtr, sizeof(val));\n    return val;\n}\n\n#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */\n\n#if defined(_MSC_VER)     /* Visual Studio */\n#  define XXH_swap64 _byteswap_uint64\n#elif XXH_GCC_VERSION >= 403\n#  define XXH_swap64 __builtin_bswap64\n#else\nstatic xxh_u64 XXH_swap64(xxh_u64 x)\n{\n    return  ((x << 56) & 0xff00000000000000ULL) |\n            ((x << 40) & 0x00ff000000000000ULL) |\n            ((x << 24) & 0x0000ff0000000000ULL) |\n            ((x << 8)  & 0x000000ff00000000ULL) |\n            ((x >> 8)  & 0x00000000ff000000ULL) |\n            ((x >> 24) & 0x0000000000ff0000ULL) |\n            ((x >> 40) & 0x000000000000ff00ULL) |\n            ((x >> 56) & 0x00000000000000ffULL);\n}\n#endif\n\n\n/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))\n\nXXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr)\n{\n    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;\n    return bytePtr[0]\n         | ((xxh_u64)bytePtr[1] << 8)\n         | ((xxh_u64)bytePtr[2] << 16)\n         | ((xxh_u64)bytePtr[3] << 24)\n         | ((xxh_u64)bytePtr[4] << 32)\n         | ((xxh_u64)bytePtr[5] << 40)\n         | ((xxh_u64)bytePtr[6] << 48)\n         | ((xxh_u64)bytePtr[7] << 56);\n}\n\nXXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr)\n{\n    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;\n    return bytePtr[7]\n         | ((xxh_u64)bytePtr[6] << 8)\n         | ((xxh_u64)bytePtr[5] << 16)\n         | ((xxh_u64)bytePtr[4] << 24)\n         | ((xxh_u64)bytePtr[3] << 32)\n         | ((xxh_u64)bytePtr[2] << 40)\n         | ((xxh_u64)bytePtr[1] << 48)\n         | ((xxh_u64)bytePtr[0] << 56);\n}\n\n#else\nXXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));\n}\n\nstatic xxh_u64 XXH_readBE64(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);\n}\n#endif\n\nXXH_FORCE_INLINE xxh_u64\nXXH_readLE64_align(const void* ptr, XXH_alignment align)\n{\n    if (align==XXH_unaligned)\n        return XXH_readLE64(ptr);\n    else\n        return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr);\n}\n\n\n/*******   xxh64   *******/\n/*!\n * @}\n * @defgroup XXH64_impl XXH64 implementation\n * @ingroup impl\n *\n * Details on the XXH64 implementation.\n * @{\n */\n/* #define rather that static const, to be used as initializers */\n#define XXH_PRIME64_1  0x9E3779B185EBCA87ULL  /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */\n#define XXH_PRIME64_2  0xC2B2AE3D27D4EB4FULL  /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */\n#define XXH_PRIME64_3  0x165667B19E3779F9ULL  /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */\n#define XXH_PRIME64_4  0x85EBCA77C2B2AE63ULL  /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */\n#define XXH_PRIME64_5  0x27D4EB2F165667C5ULL  /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */\n\n#ifdef XXH_OLD_NAMES\n#  define PRIME64_1 XXH_PRIME64_1\n#  define PRIME64_2 XXH_PRIME64_2\n#  define PRIME64_3 XXH_PRIME64_3\n#  define PRIME64_4 XXH_PRIME64_4\n#  define PRIME64_5 XXH_PRIME64_5\n#endif\n\n/*! @copydoc XXH32_round */\nstatic xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input)\n{\n    acc += input * XXH_PRIME64_2;\n    acc  = XXH_rotl64(acc, 31);\n    acc *= XXH_PRIME64_1;\n#if (defined(__AVX512F__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)\n    /*\n     * DISABLE AUTOVECTORIZATION:\n     * A compiler fence is used to prevent GCC and Clang from\n     * autovectorizing the XXH64 loop (pragmas and attributes don't work for some\n     * reason) without globally disabling AVX512.\n     *\n     * Autovectorization of XXH64 tends to be detrimental,\n     * though the exact outcome may change depending on exact cpu and compiler version.\n     * For information, it has been reported as detrimental for Skylake-X,\n     * but possibly beneficial for Zen4.\n     *\n     * The default is to disable auto-vectorization,\n     * but you can select to enable it instead using `XXH_ENABLE_AUTOVECTORIZE` build variable.\n     */\n    XXH_COMPILER_GUARD(acc);\n#endif\n    return acc;\n}\n\nstatic xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val)\n{\n    val  = XXH64_round(0, val);\n    acc ^= val;\n    acc  = acc * XXH_PRIME64_1 + XXH_PRIME64_4;\n    return acc;\n}\n\n/*! @copydoc XXH32_avalanche */\nstatic xxh_u64 XXH64_avalanche(xxh_u64 hash)\n{\n    hash ^= hash >> 33;\n    hash *= XXH_PRIME64_2;\n    hash ^= hash >> 29;\n    hash *= XXH_PRIME64_3;\n    hash ^= hash >> 32;\n    return hash;\n}\n\n\n#define XXH_get64bits(p) XXH_readLE64_align(p, align)\n\n/*!\n * @internal\n * @brief Sets up the initial accumulator state for XXH64().\n */\nXXH_FORCE_INLINE void\nXXH64_initAccs(xxh_u64 *acc, xxh_u64 seed)\n{\n    XXH_ASSERT(acc != NULL);\n    acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2;\n    acc[1] = seed + XXH_PRIME64_2;\n    acc[2] = seed + 0;\n    acc[3] = seed - XXH_PRIME64_1;\n}\n\n/*!\n * @internal\n * @brief Consumes a block of data for XXH64().\n *\n * @return the end input pointer.\n */\nXXH_FORCE_INLINE const xxh_u8 *\nXXH64_consumeLong(\n    xxh_u64 *XXH_RESTRICT acc,\n    xxh_u8 const *XXH_RESTRICT input,\n    size_t len,\n    XXH_alignment align\n)\n{\n    const xxh_u8* const bEnd = input + len;\n    const xxh_u8* const limit = bEnd - 31;\n    XXH_ASSERT(acc != NULL);\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(len >= 32);\n    do {\n        /* reroll on 32-bit */\n        if (sizeof(void *) < sizeof(xxh_u64)) {\n            size_t i;\n            for (i = 0; i < 4; i++) {\n                acc[i] = XXH64_round(acc[i], XXH_get64bits(input));\n                input += 8;\n            }\n        } else {\n            acc[0] = XXH64_round(acc[0], XXH_get64bits(input)); input += 8;\n            acc[1] = XXH64_round(acc[1], XXH_get64bits(input)); input += 8;\n            acc[2] = XXH64_round(acc[2], XXH_get64bits(input)); input += 8;\n            acc[3] = XXH64_round(acc[3], XXH_get64bits(input)); input += 8;\n        }\n    } while (input < limit);\n\n    return input;\n}\n\n/*!\n * @internal\n * @brief Merges the accumulator lanes together for XXH64()\n */\nXXH_FORCE_INLINE XXH_PUREF xxh_u64\nXXH64_mergeAccs(const xxh_u64 *acc)\n{\n    XXH_ASSERT(acc != NULL);\n    {\n        xxh_u64 h64 = XXH_rotl64(acc[0], 1) + XXH_rotl64(acc[1], 7)\n                    + XXH_rotl64(acc[2], 12) + XXH_rotl64(acc[3], 18);\n        /* reroll on 32-bit */\n        if (sizeof(void *) < sizeof(xxh_u64)) {\n            size_t i;\n            for (i = 0; i < 4; i++) {\n                h64 = XXH64_mergeRound(h64, acc[i]);\n            }\n        } else {\n            h64 = XXH64_mergeRound(h64, acc[0]);\n            h64 = XXH64_mergeRound(h64, acc[1]);\n            h64 = XXH64_mergeRound(h64, acc[2]);\n            h64 = XXH64_mergeRound(h64, acc[3]);\n        }\n        return h64;\n    }\n}\n\n/*!\n * @internal\n * @brief Processes the last 0-31 bytes of @p ptr.\n *\n * There may be up to 31 bytes remaining to consume from the input.\n * This final stage will digest them to ensure that all input bytes are present\n * in the final mix.\n *\n * @param hash The hash to finalize.\n * @param ptr The pointer to the remaining input.\n * @param len The remaining length, modulo 32.\n * @param align Whether @p ptr is aligned.\n * @return The finalized hash\n * @see XXH32_finalize().\n */\nXXH_STATIC XXH_PUREF xxh_u64\nXXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)\n{\n    if (ptr==NULL) XXH_ASSERT(len == 0);\n    len &= 31;\n    while (len >= 8) {\n        xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr));\n        ptr += 8;\n        hash ^= k1;\n        hash  = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4;\n        len -= 8;\n    }\n    if (len >= 4) {\n        hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;\n        ptr += 4;\n        hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;\n        len -= 4;\n    }\n    while (len > 0) {\n        hash ^= (*ptr++) * XXH_PRIME64_5;\n        hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1;\n        --len;\n    }\n    return  XXH64_avalanche(hash);\n}\n\n#ifdef XXH_OLD_NAMES\n#  define PROCESS1_64 XXH_PROCESS1_64\n#  define PROCESS4_64 XXH_PROCESS4_64\n#  define PROCESS8_64 XXH_PROCESS8_64\n#else\n#  undef XXH_PROCESS1_64\n#  undef XXH_PROCESS4_64\n#  undef XXH_PROCESS8_64\n#endif\n\n/*!\n * @internal\n * @brief The implementation for @ref XXH64().\n *\n * @param input , len , seed Directly passed from @ref XXH64().\n * @param align Whether @p input is aligned.\n * @return The calculated hash.\n */\nXXH_FORCE_INLINE XXH_PUREF xxh_u64\nXXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)\n{\n    xxh_u64 h64;\n    if (input==NULL) XXH_ASSERT(len == 0);\n\n    if (len>=32) {  /* Process a large block of data */\n        xxh_u64 acc[4];\n        XXH64_initAccs(acc, seed);\n\n        input = XXH64_consumeLong(acc, input, len, align);\n\n        h64 = XXH64_mergeAccs(acc);\n    } else {\n        h64  = seed + XXH_PRIME64_5;\n    }\n\n    h64 += (xxh_u64) len;\n\n    return XXH64_finalize(h64, input, len, align);\n}\n\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH64_hash_t XXH64 (XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)\n{\n#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2\n    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */\n    XXH64_state_t state;\n    XXH64_reset(&state, seed);\n    XXH64_update(&state, (const xxh_u8*)input, len);\n    return XXH64_digest(&state);\n#else\n    if (XXH_FORCE_ALIGN_CHECK) {\n        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */\n            return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);\n    }   }\n\n    return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);\n\n#endif\n}\n\n/*******   Hash Streaming   *******/\n#ifndef XXH_NO_STREAM\n/*! @ingroup XXH64_family*/\nXXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)\n{\n    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));\n}\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)\n{\n    XXH_free(statePtr);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState)\n{\n    XXH_memcpy(dstState, srcState, sizeof(*dstState));\n}\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed)\n{\n    XXH_ASSERT(statePtr != NULL);\n    XXH_memset(statePtr, 0, sizeof(*statePtr));\n    XXH64_initAccs(statePtr->acc, seed);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len)\n{\n    if (input==NULL) {\n        XXH_ASSERT(len == 0);\n        return XXH_OK;\n    }\n\n    state->total_len += len;\n\n    XXH_ASSERT(state->bufferedSize <= sizeof(state->buffer));\n    if (len < sizeof(state->buffer) - state->bufferedSize)  {   /* fill in tmp buffer */\n        XXH_memcpy(state->buffer + state->bufferedSize, input, len);\n        state->bufferedSize += (XXH32_hash_t)len;\n        return XXH_OK;\n    }\n\n    {   const xxh_u8* xinput = (const xxh_u8*)input;\n        const xxh_u8* const bEnd = xinput + len;\n\n        if (state->bufferedSize) {   /* non-empty buffer => complete first */\n            XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize);\n            xinput += sizeof(state->buffer) - state->bufferedSize;\n            /* and process one round */\n            (void)XXH64_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned);\n            state->bufferedSize = 0;\n        }\n\n        XXH_ASSERT(xinput <= bEnd);\n        if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) {\n            /* Process the remaining data */\n            xinput = XXH64_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned);\n        }\n\n        if (xinput < bEnd) {\n            /* Copy the leftover to the tmp buffer */\n            XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput));\n            state->bufferedSize = (unsigned)(bEnd-xinput);\n        }\n    }\n\n    return XXH_OK;\n}\n\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state)\n{\n    xxh_u64 h64;\n\n    if (state->total_len >= 32) {\n        h64 = XXH64_mergeAccs(state->acc);\n    } else {\n        h64  = state->acc[2] /*seed*/ + XXH_PRIME64_5;\n    }\n\n    h64 += (xxh_u64) state->total_len;\n\n    return XXH64_finalize(h64, state->buffer, (size_t)state->total_len, XXH_aligned);\n}\n#endif /* !XXH_NO_STREAM */\n\n/******* Canonical representation   *******/\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash)\n{\n    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));\n    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);\n    XXH_memcpy(dst, &hash, sizeof(*dst));\n}\n\n/*! @ingroup XXH64_family */\nXXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src)\n{\n    return XXH_readBE64(src);\n}\n\n#ifndef XXH_NO_XXH3\n\n/* *********************************************************************\n*  XXH3\n*  New generation hash designed for speed on small keys and vectorization\n************************************************************************ */\n/*!\n * @}\n * @defgroup XXH3_impl XXH3 implementation\n * @ingroup impl\n * @{\n */\n\n/* ===   Compiler specifics   === */\n\n\n#if (defined(__GNUC__) && (__GNUC__ >= 3))  \\\n  || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \\\n  || defined(__clang__)\n#    define XXH_likely(x) __builtin_expect(x, 1)\n#    define XXH_unlikely(x) __builtin_expect(x, 0)\n#else\n#    define XXH_likely(x) (x)\n#    define XXH_unlikely(x) (x)\n#endif\n\n#ifndef XXH_HAS_INCLUDE\n#  ifdef __has_include\n/*\n * Not defined as XXH_HAS_INCLUDE(x) (function-like) because\n * this causes segfaults in Apple Clang 4.2 (on Mac OS X 10.7 Lion)\n */\n#    define XXH_HAS_INCLUDE __has_include\n#  else\n#    define XXH_HAS_INCLUDE(x) 0\n#  endif\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#  if defined(__ARM_FEATURE_SVE)\n#    include <arm_sve.h>\n#  endif\n#  if defined(__ARM_NEON__) || defined(__ARM_NEON) \\\n   || (defined(_M_ARM) && _M_ARM >= 7) \\\n   || defined(_M_ARM64) || defined(_M_ARM64EC) \\\n   || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE(<arm_neon.h>)) /* WASM SIMD128 via SIMDe */\n#    define inline __inline__  /* circumvent a clang bug */\n#    include <arm_neon.h>\n#    undef inline\n#  elif defined(__AVX2__)\n#    include <immintrin.h>\n#  elif defined(__SSE2__)\n#    include <emmintrin.h>\n#  elif defined(__loongarch_asx)\n#    include <lasxintrin.h>\n#    include <lsxintrin.h>\n#  elif defined(__loongarch_sx)\n#    include <lsxintrin.h>\n#  endif\n#endif\n\n#if defined(_MSC_VER)\n#  include <intrin.h>\n#endif\n\n/*\n * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while\n * remaining a true 64-bit/128-bit hash function.\n *\n * This is done by prioritizing a subset of 64-bit operations that can be\n * emulated without too many steps on the average 32-bit machine.\n *\n * For example, these two lines seem similar, and run equally fast on 64-bit:\n *\n *   xxh_u64 x;\n *   x ^= (x >> 47); // good\n *   x ^= (x >> 13); // bad\n *\n * However, to a 32-bit machine, there is a major difference.\n *\n * x ^= (x >> 47) looks like this:\n *\n *   x.lo ^= (x.hi >> (47 - 32));\n *\n * while x ^= (x >> 13) looks like this:\n *\n *   // note: funnel shifts are not usually cheap.\n *   x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13));\n *   x.hi ^= (x.hi >> 13);\n *\n * The first one is significantly faster than the second, simply because the\n * shift is larger than 32. This means:\n *  - All the bits we need are in the upper 32 bits, so we can ignore the lower\n *    32 bits in the shift.\n *  - The shift result will always fit in the lower 32 bits, and therefore,\n *    we can ignore the upper 32 bits in the xor.\n *\n * Thanks to this optimization, XXH3 only requires these features to be efficient:\n *\n *  - Usable unaligned access\n *  - A 32-bit or 64-bit ALU\n *      - If 32-bit, a decent ADC instruction\n *  - A 32 or 64-bit multiply with a 64-bit result\n *  - For the 128-bit variant, a decent byteswap helps short inputs.\n *\n * The first two are already required by XXH32, and almost all 32-bit and 64-bit\n * platforms which can run XXH32 can run XXH3 efficiently.\n *\n * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one\n * notable exception.\n *\n * First of all, Thumb-1 lacks support for the UMULL instruction which\n * performs the important long multiply. This means numerous __aeabi_lmul\n * calls.\n *\n * Second of all, the 8 functional registers are just not enough.\n * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need\n * Lo registers, and this shuffling results in thousands more MOVs than A32.\n *\n * A32 and T32 don't have this limitation. They can access all 14 registers,\n * do a 32->64 multiply with UMULL, and the flexible operand allowing free\n * shifts is helpful, too.\n *\n * Therefore, we do a quick sanity check.\n *\n * If compiling Thumb-1 for a target which supports ARM instructions, we will\n * emit a warning, as it is not a \"sane\" platform to compile for.\n *\n * Usually, if this happens, it is because of an accident and you probably need\n * to specify -march, as you likely meant to compile for a newer architecture.\n *\n * Credit: large sections of the vectorial and asm source code paths\n *         have been contributed by @easyaspi314\n */\n#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM)\n#   warning \"XXH3 is highly inefficient without ARM or Thumb-2.\"\n#endif\n\n/* ==========================================\n * Vectorization detection\n * ========================================== */\n\n#ifdef XXH_DOXYGEN\n/*!\n * @ingroup tuning\n * @brief Overrides the vectorization implementation chosen for XXH3.\n *\n * Can be defined to 0 to disable SIMD,\n * or any other authorized value of @ref XXH_VECTOR.\n *\n * If this is not defined, it uses predefined macros to determine the best\n * implementation.\n */\n#  define XXH_VECTOR XXH_SCALAR\n/*!\n * @ingroup tuning\n * @brief Selects the minimum alignment for XXH3's accumulators.\n *\n * When using SIMD, this should match the alignment required for said vector\n * type, so, for example, 32 for AVX2.\n *\n * Default: Auto detected.\n */\n#  define XXH_ACC_ALIGN 8\n#endif\n\n/* Actual definition */\n#ifndef XXH_DOXYGEN\n#endif\n\n#ifndef XXH_VECTOR    /* can be defined on command line */\n#  if defined(__ARM_FEATURE_SVE)\n#    define XXH_VECTOR XXH_SVE\n#  elif ( \\\n        defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \\\n     || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \\\n     || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE(<arm_neon.h>)) /* wasm simd128 via SIMDe */ \\\n   ) && ( \\\n        defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \\\n    || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \\\n   )\n#    define XXH_VECTOR XXH_NEON\n#  elif defined(__AVX512F__)\n#    define XXH_VECTOR XXH_AVX512\n#  elif defined(__AVX2__)\n#    define XXH_VECTOR XXH_AVX2\n#  elif defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2))\n#    define XXH_VECTOR XXH_SSE2\n#  elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \\\n     || (defined(__s390x__) && defined(__VEC__)) \\\n     && defined(__GNUC__) /* TODO: IBM XL */\n#    define XXH_VECTOR XXH_VSX\n#  elif defined(__loongarch_asx)\n#    define XXH_VECTOR XXH_LASX\n#  elif defined(__loongarch_sx)\n#    define XXH_VECTOR XXH_LSX\n#  else\n#    define XXH_VECTOR XXH_SCALAR\n#  endif\n#endif\n\n/* __ARM_FEATURE_SVE is only supported by GCC & Clang. */\n#if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE)\n#  ifdef _MSC_VER\n#    pragma warning(once : 4606)\n#  else\n#    warning \"__ARM_FEATURE_SVE isn't supported. Use SCALAR instead.\"\n#  endif\n#  undef XXH_VECTOR\n#  define XXH_VECTOR XXH_SCALAR\n#endif\n\n/*\n * Controls the alignment of the accumulator,\n * for compatibility with aligned vector loads, which are usually faster.\n */\n#ifndef XXH_ACC_ALIGN\n#  if defined(XXH_X86DISPATCH)\n#     define XXH_ACC_ALIGN 64  /* for compatibility with avx512 */\n#  elif XXH_VECTOR == XXH_SCALAR  /* scalar */\n#     define XXH_ACC_ALIGN 8\n#  elif XXH_VECTOR == XXH_SSE2  /* sse2 */\n#     define XXH_ACC_ALIGN 16\n#  elif XXH_VECTOR == XXH_AVX2  /* avx2 */\n#     define XXH_ACC_ALIGN 32\n#  elif XXH_VECTOR == XXH_NEON  /* neon */\n#     define XXH_ACC_ALIGN 16\n#  elif XXH_VECTOR == XXH_VSX   /* vsx */\n#     define XXH_ACC_ALIGN 16\n#  elif XXH_VECTOR == XXH_AVX512  /* avx512 */\n#     define XXH_ACC_ALIGN 64\n#  elif XXH_VECTOR == XXH_SVE   /* sve */\n#     define XXH_ACC_ALIGN 64\n#  elif XXH_VECTOR == XXH_LASX   /* lasx */\n#     define XXH_ACC_ALIGN 64\n#  elif XXH_VECTOR == XXH_LSX   /* lsx */\n#     define XXH_ACC_ALIGN 64\n#  endif\n#endif\n\n#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \\\n    || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512\n#  define XXH_SEC_ALIGN XXH_ACC_ALIGN\n#elif XXH_VECTOR == XXH_SVE\n#  define XXH_SEC_ALIGN XXH_ACC_ALIGN\n#else\n#  define XXH_SEC_ALIGN 8\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#  define XXH_ALIASING __attribute__((__may_alias__))\n#else\n#  define XXH_ALIASING /* nothing */\n#endif\n\n/*\n * UGLY HACK:\n * GCC usually generates the best code with -O3 for xxHash.\n *\n * However, when targeting AVX2, it is overzealous in its unrolling resulting\n * in code roughly 3/4 the speed of Clang.\n *\n * There are other issues, such as GCC splitting _mm256_loadu_si256 into\n * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which\n * only applies to Sandy and Ivy Bridge... which don't even support AVX2.\n *\n * That is why when compiling the AVX2 version, it is recommended to use either\n *   -O2 -mavx2 -march=haswell\n * or\n *   -O2 -mavx2 -mno-avx256-split-unaligned-load\n * for decent performance, or to use Clang instead.\n *\n * Fortunately, we can control the first one with a pragma that forces GCC into\n * -O2, but the other one we can't control without \"failed to inline always\n * inline function due to target mismatch\" warnings.\n */\n#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \\\n  && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \\\n  && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */\n#  pragma GCC push_options\n#  pragma GCC optimize(\"-O2\")\n#endif\n\n#if XXH_VECTOR == XXH_NEON\n\n/*\n * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3\n * optimizes out the entire hashLong loop because of the aliasing violation.\n *\n * However, GCC is also inefficient at load-store optimization with vld1q/vst1q,\n * so the only option is to mark it as aliasing.\n */\ntypedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING;\n\n/*!\n * @internal\n * @brief `vld1q_u64` but faster and alignment-safe.\n *\n * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only\n * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86).\n *\n * GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it\n * prohibits load-store optimizations. Therefore, a direct dereference is used.\n *\n * Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe\n * unaligned load.\n */\n#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__)\nXXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */\n{\n    return *(xxh_aliasing_uint64x2_t const *)ptr;\n}\n#else\nXXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr)\n{\n    return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr));\n}\n#endif\n\n/*!\n * @internal\n * @brief `vmlal_u32` on low and high halves of a vector.\n *\n * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with\n * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32`\n * with `vmlal_u32`.\n */\n#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11\nXXH_FORCE_INLINE uint64x2_t\nXXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)\n{\n    /* Inline assembly is the only way */\n    __asm__(\"umlal   %0.2d, %1.2s, %2.2s\" : \"+w\" (acc) : \"w\" (lhs), \"w\" (rhs));\n    return acc;\n}\nXXH_FORCE_INLINE uint64x2_t\nXXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)\n{\n    /* This intrinsic works as expected */\n    return vmlal_high_u32(acc, lhs, rhs);\n}\n#else\n/* Portable intrinsic versions */\nXXH_FORCE_INLINE uint64x2_t\nXXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)\n{\n    return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs));\n}\n/*! @copydoc XXH_vmlal_low_u32\n * Assume the compiler converts this to vmlal_high_u32 on aarch64 */\nXXH_FORCE_INLINE uint64x2_t\nXXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)\n{\n    return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs));\n}\n#endif\n\n/*!\n * @ingroup tuning\n * @brief Controls the NEON to scalar ratio for XXH3\n *\n * This can be set to 2, 4, 6, or 8.\n *\n * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used.\n *\n * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those\n * can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU\n * bandwidth.\n *\n * This is even more noticeable on the more advanced cores like the Cortex-A76 which\n * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once.\n *\n * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes\n * and 2 scalar lanes, which is chosen by default.\n *\n * This does not apply to Apple processors or 32-bit processors, which run better with\n * full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes.\n *\n * This change benefits CPUs with large micro-op buffers without negatively affecting\n * most other CPUs:\n *\n *  | Chipset               | Dispatch type       | NEON only | 6:2 hybrid | Diff. |\n *  |:----------------------|:--------------------|----------:|-----------:|------:|\n *  | Snapdragon 730 (A76)  | 2 NEON/8 micro-ops  |  8.8 GB/s |  10.1 GB/s |  ~16% |\n *  | Snapdragon 835 (A73)  | 2 NEON/3 micro-ops  |  5.1 GB/s |   5.3 GB/s |   ~5% |\n *  | Marvell PXA1928 (A53) | In-order dual-issue |  1.9 GB/s |   1.9 GB/s |    0% |\n *  | Apple M1              | 4 NEON/8 micro-ops  | 37.3 GB/s |  36.1 GB/s |  ~-3% |\n *\n * It also seems to fix some bad codegen on GCC, making it almost as fast as clang.\n *\n * When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning\n * it effectively becomes worse 4.\n *\n * @see XXH3_accumulate_512_neon()\n */\n# ifndef XXH3_NEON_LANES\n#  if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \\\n   && !defined(__APPLE__) && XXH_SIZE_OPT <= 0\n#   define XXH3_NEON_LANES 6\n#  else\n#   define XXH3_NEON_LANES XXH_ACC_NB\n#  endif\n# endif\n#endif  /* XXH_VECTOR == XXH_NEON */\n\n/*\n * VSX and Z Vector helpers.\n *\n * This is very messy, and any pull requests to clean this up are welcome.\n *\n * There are a lot of problems with supporting VSX and s390x, due to\n * inconsistent intrinsics, spotty coverage, and multiple endiannesses.\n */\n#if XXH_VECTOR == XXH_VSX\n/* Annoyingly, these headers _may_ define three macros: `bool`, `vector`,\n * and `pixel`. This is a problem for obvious reasons.\n *\n * These keywords are unnecessary; the spec literally says they are\n * equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd\n * after including the header.\n *\n * We use pragma push_macro/pop_macro to keep the namespace clean. */\n#  pragma push_macro(\"bool\")\n#  pragma push_macro(\"vector\")\n#  pragma push_macro(\"pixel\")\n/* silence potential macro redefined warnings */\n#  undef bool\n#  undef vector\n#  undef pixel\n\n#  if defined(__s390x__)\n#    include <s390intrin.h>\n#  else\n#    include <altivec.h>\n#  endif\n\n/* Restore the original macro values, if applicable. */\n#  pragma pop_macro(\"pixel\")\n#  pragma pop_macro(\"vector\")\n#  pragma pop_macro(\"bool\")\n\ntypedef __vector unsigned long long xxh_u64x2;\ntypedef __vector unsigned char xxh_u8x16;\ntypedef __vector unsigned xxh_u32x4;\n\n/*\n * UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue.\n */\ntypedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING;\n\n# ifndef XXH_VSX_BE\n#  if defined(__BIG_ENDIAN__) \\\n  || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#    define XXH_VSX_BE 1\n#  elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__\n#    warning \"-maltivec=be is not recommended. Please use native endianness.\"\n#    define XXH_VSX_BE 1\n#  else\n#    define XXH_VSX_BE 0\n#  endif\n# endif /* !defined(XXH_VSX_BE) */\n\n# if XXH_VSX_BE\n#  if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__))\n#    define XXH_vec_revb vec_revb\n#  else\n/*!\n * A polyfill for POWER9's vec_revb().\n */\nXXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val)\n{\n    xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,\n                                  0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };\n    return vec_perm(val, val, vByteSwap);\n}\n#  endif\n# endif /* XXH_VSX_BE */\n\n/*!\n * Performs an unaligned vector load and byte swaps it on big endian.\n */\nXXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr)\n{\n    xxh_u64x2 ret;\n    XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2));\n# if XXH_VSX_BE\n    ret = XXH_vec_revb(ret);\n# endif\n    return ret;\n}\n\n/*\n * vec_mulo and vec_mule are very problematic intrinsics on PowerPC\n *\n * These intrinsics weren't added until GCC 8, despite existing for a while,\n * and they are endian dependent. Also, their meaning swap depending on version.\n * */\n# if defined(__s390x__)\n /* s390x is always big endian, no issue on this platform */\n#  define XXH_vec_mulo vec_mulo\n#  define XXH_vec_mule vec_mule\n# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__)\n/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */\n /* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */\n#  define XXH_vec_mulo __builtin_altivec_vmulouw\n#  define XXH_vec_mule __builtin_altivec_vmuleuw\n# else\n/* gcc needs inline assembly */\n/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */\nXXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b)\n{\n    xxh_u64x2 result;\n    __asm__(\"vmulouw %0, %1, %2\" : \"=v\" (result) : \"v\" (a), \"v\" (b));\n    return result;\n}\nXXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b)\n{\n    xxh_u64x2 result;\n    __asm__(\"vmuleuw %0, %1, %2\" : \"=v\" (result) : \"v\" (a), \"v\" (b));\n    return result;\n}\n# endif /* XXH_vec_mulo, XXH_vec_mule */\n#endif /* XXH_VECTOR == XXH_VSX */\n\n#if XXH_VECTOR == XXH_SVE\n#define ACCRND(acc, offset) \\\ndo { \\\n    svuint64_t input_vec = svld1_u64(mask, xinput + offset);         \\\n    svuint64_t secret_vec = svld1_u64(mask, xsecret + offset);       \\\n    svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec);     \\\n    svuint64_t swapped = svtbl_u64(input_vec, kSwap);                \\\n    svuint64_t mixed_lo = svextw_u64_x(mask, mixed);                 \\\n    svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32);            \\\n    svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \\\n    acc = svadd_u64_x(mask, acc, mul);                               \\\n} while (0)\n#endif /* XXH_VECTOR == XXH_SVE */\n\n/* prefetch\n * can be disabled, by declaring XXH_NO_PREFETCH build macro */\n#if defined(XXH_NO_PREFETCH)\n#  define XXH_PREFETCH(ptr)  (void)(ptr)  /* disabled */\n#else\n#  if XXH_SIZE_OPT >= 1\n#    define XXH_PREFETCH(ptr) (void)(ptr)\n#  elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))  /* _mm_prefetch() not defined outside of x86/x64 */\n#    include <mmintrin.h>   /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */\n#    define XXH_PREFETCH(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T0)\n#  elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )\n#    define XXH_PREFETCH(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)\n#  else\n#    define XXH_PREFETCH(ptr) (void)(ptr)  /* disabled */\n#  endif\n#endif  /* XXH_NO_PREFETCH */\n\n\n/* ==========================================\n * XXH3 default settings\n * ========================================== */\n\n#define XXH_SECRET_DEFAULT_SIZE 192   /* minimum XXH3_SECRET_SIZE_MIN */\n\n#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN)\n#  error \"default keyset is not large enough\"\n#endif\n\n/*!\n * @internal\n * @def XXH3_kSecret\n * @brief Pseudorandom secret taken directly from FARSH. */\nXXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {\n    0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,\n    0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,\n    0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,\n    0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,\n    0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,\n    0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,\n    0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,\n    0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,\n    0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,\n    0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,\n    0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,\n    0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,\n};\n\nstatic const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL;  /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */\nstatic const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL;  /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */\n\n#ifdef XXH_OLD_NAMES\n#  define kSecret XXH3_kSecret\n#endif\n\n#ifdef XXH_DOXYGEN\n/*!\n * @brief Calculates a 32-bit to 64-bit long multiply.\n *\n * Implemented as a macro.\n *\n * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't\n * need to (but it shouldn't need to anyways, it is about 7 instructions to do\n * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we\n * use that instead of the normal method.\n *\n * If you are compiling for platforms like Thumb-1 and don't have a better option,\n * you may also want to write your own long multiply routine here.\n *\n * @param x, y Numbers to be multiplied\n * @return 64-bit product of the low 32 bits of @p x and @p y.\n */\nXXH_FORCE_INLINE xxh_u64\nXXH_mult32to64(xxh_u64 x, xxh_u64 y)\n{\n   return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF);\n}\n#elif defined(_MSC_VER) && defined(_M_IX86)\n#    define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y))\n#else\n/*\n * Downcast + upcast is usually better than masking on older compilers like\n * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers.\n *\n * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands\n * and perform a full 64x64 multiply -- entirely redundant on 32-bit.\n */\n#    define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y))\n#endif\n\n/*!\n * @brief Calculates a 64->128-bit long multiply.\n *\n * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar\n * version.\n *\n * @param lhs , rhs The 64-bit integers to be multiplied\n * @return The 128-bit result represented in an @ref XXH128_hash_t.\n */\nstatic XXH128_hash_t\nXXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs)\n{\n    /*\n     * GCC/Clang __uint128_t method.\n     *\n     * On most 64-bit targets, GCC and Clang define a __uint128_t type.\n     * This is usually the best way as it usually uses a native long 64-bit\n     * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64.\n     *\n     * Usually.\n     *\n     * Despite being a 32-bit platform, Clang (and emscripten) define this type\n     * despite not having the arithmetic for it. This results in a laggy\n     * compiler builtin call which calculates a full 128-bit multiply.\n     * In that case it is best to use the portable one.\n     * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677\n     */\n#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \\\n    && defined(__SIZEOF_INT128__) \\\n    || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)\n\n    __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs;\n    XXH128_hash_t r128;\n    r128.low64  = (xxh_u64)(product);\n    r128.high64 = (xxh_u64)(product >> 64);\n    return r128;\n\n    /*\n     * MSVC for x64's _umul128 method.\n     *\n     * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct);\n     *\n     * This compiles to single operand MUL on x64.\n     */\n#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC)\n\n#ifndef _MSC_VER\n#   pragma intrinsic(_umul128)\n#endif\n    xxh_u64 product_high;\n    xxh_u64 const product_low = _umul128(lhs, rhs, &product_high);\n    XXH128_hash_t r128;\n    r128.low64  = product_low;\n    r128.high64 = product_high;\n    return r128;\n\n    /*\n     * MSVC for ARM64's __umulh method.\n     *\n     * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method.\n     */\n#elif defined(_M_ARM64) || defined(_M_ARM64EC)\n\n#ifndef _MSC_VER\n#   pragma intrinsic(__umulh)\n#endif\n    XXH128_hash_t r128;\n    r128.low64  = lhs * rhs;\n    r128.high64 = __umulh(lhs, rhs);\n    return r128;\n\n#else\n    /*\n     * Portable scalar method. Optimized for 32-bit and 64-bit ALUs.\n     *\n     * This is a fast and simple grade school multiply, which is shown below\n     * with base 10 arithmetic instead of base 0x100000000.\n     *\n     *           9 3 // D2 lhs = 93\n     *         x 7 5 // D2 rhs = 75\n     *     ----------\n     *           1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15\n     *         4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45\n     *         2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21\n     *     + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63\n     *     ---------\n     *         2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27\n     *     + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67\n     *     ---------\n     *       6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975\n     *\n     * The reasons for adding the products like this are:\n     *  1. It avoids manual carry tracking. Just like how\n     *     (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX.\n     *     This avoids a lot of complexity.\n     *\n     *  2. It hints for, and on Clang, compiles to, the powerful UMAAL\n     *     instruction available in ARM's Digital Signal Processing extension\n     *     in 32-bit ARMv6 and later, which is shown below:\n     *\n     *         void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm)\n     *         {\n     *             xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm;\n     *             *RdLo = (xxh_u32)(product & 0xFFFFFFFF);\n     *             *RdHi = (xxh_u32)(product >> 32);\n     *         }\n     *\n     *     This instruction was designed for efficient long multiplication, and\n     *     allows this to be calculated in only 4 instructions at speeds\n     *     comparable to some 64-bit ALUs.\n     *\n     *  3. It isn't terrible on other platforms. Usually this will be a couple\n     *     of 32-bit ADD/ADCs.\n     */\n\n    /* First calculate all of the cross products. */\n    xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);\n    xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32,        rhs & 0xFFFFFFFF);\n    xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32);\n    xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32,        rhs >> 32);\n\n    /* Now add the products together. These will never overflow. */\n    xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;\n    xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32)        + hi_hi;\n    xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);\n\n    XXH128_hash_t r128;\n    r128.low64  = lower;\n    r128.high64 = upper;\n    return r128;\n#endif\n}\n\n/*!\n * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it.\n *\n * The reason for the separate function is to prevent passing too many structs\n * around by value. This will hopefully inline the multiply, but we don't force it.\n *\n * @param lhs , rhs The 64-bit integers to multiply\n * @return The low 64 bits of the product XOR'd by the high 64 bits.\n * @see XXH_mult64to128()\n */\nstatic xxh_u64\nXXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs)\n{\n    XXH128_hash_t product = XXH_mult64to128(lhs, rhs);\n    return product.low64 ^ product.high64;\n}\n\n/*! Seems to produce slightly better code on GCC for some reason. */\nXXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)\n{\n    XXH_ASSERT(0 <= shift && shift < 64);\n    return v64 ^ (v64 >> shift);\n}\n\n/*\n * This is a fast avalanche stage,\n * suitable when input bits are already partially mixed\n */\nstatic XXH64_hash_t XXH3_avalanche(xxh_u64 h64)\n{\n    h64 = XXH_xorshift64(h64, 37);\n    h64 *= PRIME_MX1;\n    h64 = XXH_xorshift64(h64, 32);\n    return h64;\n}\n\n/*\n * This is a stronger avalanche,\n * inspired by Pelle Evensen's rrmxmx\n * preferable when input has not been previously mixed\n */\nstatic XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len)\n{\n    /* this mix is inspired by Pelle Evensen's rrmxmx */\n    h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);\n    h64 *= PRIME_MX2;\n    h64 ^= (h64 >> 35) + len ;\n    h64 *= PRIME_MX2;\n    return XXH_xorshift64(h64, 28);\n}\n\n\n/* ==========================================\n * Short keys\n * ==========================================\n * One of the shortcomings of XXH32 and XXH64 was that their performance was\n * sub-optimal on short lengths. It used an iterative algorithm which strongly\n * favored lengths that were a multiple of 4 or 8.\n *\n * Instead of iterating over individual inputs, we use a set of single shot\n * functions which piece together a range of lengths and operate in constant time.\n *\n * Additionally, the number of multiplies has been significantly reduced. This\n * reduces latency, especially when emulating 64-bit multiplies on 32-bit.\n *\n * Depending on the platform, this may or may not be faster than XXH32, but it\n * is almost guaranteed to be faster than XXH64.\n */\n\n/*\n * At very short lengths, there isn't enough input to fully hide secrets, or use\n * the entire secret.\n *\n * There is also only a limited amount of mixing we can do before significantly\n * impacting performance.\n *\n * Therefore, we use different sections of the secret and always mix two secret\n * samples with an XOR. This should have no effect on performance on the\n * seedless or withSeed variants because everything _should_ be constant folded\n * by modern compilers.\n *\n * The XOR mixing hides individual parts of the secret and increases entropy.\n *\n * This adds an extra layer of strength for custom secrets.\n */\nXXH_FORCE_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(1 <= len && len <= 3);\n    XXH_ASSERT(secret != NULL);\n    /*\n     * len = 1: combined = { input[0], 0x01, input[0], input[0] }\n     * len = 2: combined = { input[1], 0x02, input[0], input[1] }\n     * len = 3: combined = { input[2], 0x03, input[0], input[1] }\n     */\n    {   xxh_u8  const c1 = input[0];\n        xxh_u8  const c2 = input[len >> 1];\n        xxh_u8  const c3 = input[len - 1];\n        xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2  << 24)\n                               | ((xxh_u32)c3 <<  0) | ((xxh_u32)len << 8);\n        xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;\n        xxh_u64 const keyed = (xxh_u64)combined ^ bitflip;\n        return XXH64_avalanche(keyed);\n    }\n}\n\nXXH_FORCE_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(secret != NULL);\n    XXH_ASSERT(4 <= len && len <= 8);\n    seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;\n    {   xxh_u32 const input1 = XXH_readLE32(input);\n        xxh_u32 const input2 = XXH_readLE32(input + len - 4);\n        xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed;\n        xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32);\n        xxh_u64 const keyed = input64 ^ bitflip;\n        return XXH3_rrmxmx(keyed, len);\n    }\n}\n\nXXH_FORCE_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(secret != NULL);\n    XXH_ASSERT(9 <= len && len <= 16);\n    {   xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed;\n        xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed;\n        xxh_u64 const input_lo = XXH_readLE64(input)           ^ bitflip1;\n        xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2;\n        xxh_u64 const acc = len\n                          + XXH_swap64(input_lo) + input_hi\n                          + XXH3_mul128_fold64(input_lo, input_hi);\n        return XXH3_avalanche(acc);\n    }\n}\n\nXXH_FORCE_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(len <= 16);\n    {   if (XXH_likely(len >  8)) return XXH3_len_9to16_64b(input, len, secret, seed);\n        if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed);\n        if (len) return XXH3_len_1to3_64b(input, len, secret, seed);\n        return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64)));\n    }\n}\n\n/*\n * DISCLAIMER: There are known *seed-dependent* multicollisions here due to\n * multiplication by zero, affecting hashes of lengths 17 to 240.\n *\n * However, they are very unlikely.\n *\n * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all\n * unseeded non-cryptographic hashes, it does not attempt to defend itself\n * against specially crafted inputs, only random inputs.\n *\n * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes\n * cancelling out the secret is taken an arbitrary number of times (addressed\n * in XXH3_accumulate_512), this collision is very unlikely with random inputs\n * and/or proper seeding:\n *\n * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a\n * function that is only called up to 16 times per hash with up to 240 bytes of\n * input.\n *\n * This is not too bad for a non-cryptographic hash function, especially with\n * only 64 bit outputs.\n *\n * The 128-bit variant (which trades some speed for strength) is NOT affected\n * by this, although it is always a good idea to use a proper seed if you care\n * about strength.\n */\nXXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input,\n                                     const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64)\n{\n#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \\\n  && defined(__i386__) && defined(__SSE2__)  /* x86 + SSE2 */ \\\n  && !defined(XXH_ENABLE_AUTOVECTORIZE)      /* Define to disable like XXH32 hack */\n    /*\n     * UGLY HACK:\n     * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in\n     * slower code.\n     *\n     * By forcing seed64 into a register, we disrupt the cost model and\n     * cause it to scalarize. See `XXH32_round()`\n     *\n     * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600,\n     * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on\n     * GCC 9.2, despite both emitting scalar code.\n     *\n     * GCC generates much better scalar code than Clang for the rest of XXH3,\n     * which is why finding a more optimal codepath is an interest.\n     */\n    XXH_COMPILER_GUARD(seed64);\n#endif\n    {   xxh_u64 const input_lo = XXH_readLE64(input);\n        xxh_u64 const input_hi = XXH_readLE64(input+8);\n        return XXH3_mul128_fold64(\n            input_lo ^ (XXH_readLE64(secret)   + seed64),\n            input_hi ^ (XXH_readLE64(secret+8) - seed64)\n        );\n    }\n}\n\n/* For mid range keys, XXH3 uses a Mum-hash variant. */\nXXH_FORCE_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,\n                     const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                     XXH64_hash_t seed)\n{\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;\n    XXH_ASSERT(16 < len && len <= 128);\n\n    {   xxh_u64 acc = len * XXH_PRIME64_1;\n#if XXH_SIZE_OPT >= 1\n        /* Smaller and cleaner, but slightly slower. */\n        unsigned int i = (unsigned int)(len - 1) / 32;\n        do {\n            acc += XXH3_mix16B(input+16 * i, secret+32*i, seed);\n            acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed);\n        } while (i-- != 0);\n#else\n        if (len > 32) {\n            if (len > 64) {\n                if (len > 96) {\n                    acc += XXH3_mix16B(input+48, secret+96, seed);\n                    acc += XXH3_mix16B(input+len-64, secret+112, seed);\n                }\n                acc += XXH3_mix16B(input+32, secret+64, seed);\n                acc += XXH3_mix16B(input+len-48, secret+80, seed);\n            }\n            acc += XXH3_mix16B(input+16, secret+32, seed);\n            acc += XXH3_mix16B(input+len-32, secret+48, seed);\n        }\n        acc += XXH3_mix16B(input+0, secret+0, seed);\n        acc += XXH3_mix16B(input+len-16, secret+16, seed);\n#endif\n        return XXH3_avalanche(acc);\n    }\n}\n\nXXH_NO_INLINE XXH_PUREF XXH64_hash_t\nXXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,\n                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                      XXH64_hash_t seed)\n{\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;\n    XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);\n\n    #define XXH3_MIDSIZE_STARTOFFSET 3\n    #define XXH3_MIDSIZE_LASTOFFSET  17\n\n    {   xxh_u64 acc = len * XXH_PRIME64_1;\n        xxh_u64 acc_end;\n        unsigned int const nbRounds = (unsigned int)len / 16;\n        unsigned int i;\n        XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);\n        for (i=0; i<8; i++) {\n            acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed);\n        }\n        /* last bytes */\n        acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);\n        XXH_ASSERT(nbRounds >= 8);\n        acc = XXH3_avalanche(acc);\n#if defined(__clang__)                                /* Clang */ \\\n    && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \\\n    && !defined(XXH_ENABLE_AUTOVECTORIZE)             /* Define to disable */\n        /*\n         * UGLY HACK:\n         * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86.\n         * In everywhere else, it uses scalar code.\n         *\n         * For 64->128-bit multiplies, even if the NEON was 100% optimal, it\n         * would still be slower than UMAAL (see XXH_mult64to128).\n         *\n         * Unfortunately, Clang doesn't handle the long multiplies properly and\n         * converts them to the nonexistent \"vmulq_u64\" intrinsic, which is then\n         * scalarized into an ugly mess of VMOV.32 instructions.\n         *\n         * This mess is difficult to avoid without turning autovectorization\n         * off completely, but they are usually relatively minor and/or not\n         * worth it to fix.\n         *\n         * This loop is the easiest to fix, as unlike XXH32, this pragma\n         * _actually works_ because it is a loop vectorization instead of an\n         * SLP vectorization.\n         */\n        #pragma clang loop vectorize(disable)\n#endif\n        for (i=8 ; i < nbRounds; i++) {\n            /*\n             * Prevents clang for unrolling the acc loop and interleaving with this one.\n             */\n            XXH_COMPILER_GUARD(acc);\n            acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed);\n        }\n        return XXH3_avalanche(acc + acc_end);\n    }\n}\n\n\n/* =======     Long Keys     ======= */\n\n#define XXH_STRIPE_LEN 64\n#define XXH_SECRET_CONSUME_RATE 8   /* nb of secret bytes consumed at each accumulation */\n#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64))\n\n#ifdef XXH_OLD_NAMES\n#  define STRIPE_LEN XXH_STRIPE_LEN\n#  define ACC_NB XXH_ACC_NB\n#endif\n\n#ifndef XXH_PREFETCH_DIST\n#  ifdef __clang__\n#    define XXH_PREFETCH_DIST 320\n#  else\n#    if (XXH_VECTOR == XXH_AVX512)\n#      define XXH_PREFETCH_DIST 512\n#    else\n#      define XXH_PREFETCH_DIST 384\n#    endif\n#  endif  /* __clang__ */\n#endif  /* XXH_PREFETCH_DIST */\n\n/*\n * These macros are to generate an XXH3_accumulate() function.\n * The two arguments select the name suffix and target attribute.\n *\n * The name of this symbol is XXH3_accumulate_<name>() and it calls\n * XXH3_accumulate_512_<name>().\n *\n * It may be useful to hand implement this function if the compiler fails to\n * optimize the inline function.\n */\n#define XXH3_ACCUMULATE_TEMPLATE(name)                      \\\nvoid                                                        \\\nXXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc,           \\\n                       const xxh_u8* XXH_RESTRICT input,    \\\n                       const xxh_u8* XXH_RESTRICT secret,   \\\n                       size_t nbStripes)                    \\\n{                                                           \\\n    size_t n;                                               \\\n    for (n = 0; n < nbStripes; n++ ) {                      \\\n        const xxh_u8* const in = input + n*XXH_STRIPE_LEN;  \\\n        XXH_PREFETCH(in + XXH_PREFETCH_DIST);               \\\n        XXH3_accumulate_512_##name(                         \\\n                 acc,                                       \\\n                 in,                                        \\\n                 secret + n*XXH_SECRET_CONSUME_RATE);       \\\n    }                                                       \\\n}\n\n\nXXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64)\n{\n    if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64);\n    XXH_memcpy(dst, &v64, sizeof(v64));\n}\n\n/* Several intrinsic functions below are supposed to accept __int64 as argument,\n * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ .\n * However, several environments do not define __int64 type,\n * requiring a workaround.\n */\n#if !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n    typedef int64_t xxh_i64;\n#else\n    /* the following type must have a width of 64-bit */\n    typedef long long xxh_i64;\n#endif\n\n\n/*\n * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized.\n *\n * It is a hardened version of UMAC, based off of FARSH's implementation.\n *\n * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD\n * implementations, and it is ridiculously fast.\n *\n * We harden it by mixing the original input to the accumulators as well as the product.\n *\n * This means that in the (relatively likely) case of a multiply by zero, the\n * original input is preserved.\n *\n * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve\n * cross-pollination, as otherwise the upper and lower halves would be\n * essentially independent.\n *\n * This doesn't matter on 64-bit hashes since they all get merged together in\n * the end, so we skip the extra step.\n *\n * Both XXH3_64bits and XXH3_128bits use this subroutine.\n */\n\n#if (XXH_VECTOR == XXH_AVX512) \\\n     || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0)\n\n#ifndef XXH_TARGET_AVX512\n# define XXH_TARGET_AVX512  /* disable attribute target */\n#endif\n\nXXH_FORCE_INLINE XXH_TARGET_AVX512 void\nXXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,\n                     const void* XXH_RESTRICT input,\n                     const void* XXH_RESTRICT secret)\n{\n    __m512i* const xacc = (__m512i *) acc;\n    XXH_ASSERT((((size_t)acc) & 63) == 0);\n    XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));\n\n    {\n        /* data_vec    = input[0]; */\n        __m512i const data_vec    = _mm512_loadu_si512   (input);\n        /* key_vec     = secret[0]; */\n        __m512i const key_vec     = _mm512_loadu_si512   (secret);\n        /* data_key    = data_vec ^ key_vec; */\n        __m512i const data_key    = _mm512_xor_si512     (data_vec, key_vec);\n        /* data_key_lo = data_key >> 32; */\n        __m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32);\n        /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */\n        __m512i const product     = _mm512_mul_epu32     (data_key, data_key_lo);\n        /* xacc[0] += swap(data_vec); */\n        __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2));\n        __m512i const sum       = _mm512_add_epi64(*xacc, data_swap);\n        /* xacc[0] += product; */\n        *xacc = _mm512_add_epi64(product, sum);\n    }\n}\nXXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512)\n\n/*\n * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing.\n *\n * Multiplication isn't perfect, as explained by Google in HighwayHash:\n *\n *  // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to\n *  // varying degrees. In descending order of goodness, bytes\n *  // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32.\n *  // As expected, the upper and lower bytes are much worse.\n *\n * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291\n *\n * Since our algorithm uses a pseudorandom secret to add some variance into the\n * mix, we don't need to (or want to) mix as often or as much as HighwayHash does.\n *\n * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid\n * extraction.\n *\n * Both XXH3_64bits and XXH3_128bits use this subroutine.\n */\n\nXXH_FORCE_INLINE XXH_TARGET_AVX512 void\nXXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 63) == 0);\n    XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));\n    {   __m512i* const xacc = (__m512i*) acc;\n        const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1);\n\n        /* xacc[0] ^= (xacc[0] >> 47) */\n        __m512i const acc_vec     = *xacc;\n        __m512i const shifted     = _mm512_srli_epi64    (acc_vec, 47);\n        /* xacc[0] ^= secret; */\n        __m512i const key_vec     = _mm512_loadu_si512   (secret);\n        __m512i const data_key    = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */);\n\n        /* xacc[0] *= XXH_PRIME32_1; */\n        __m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32);\n        __m512i const prod_lo     = _mm512_mul_epu32     (data_key, prime32);\n        __m512i const prod_hi     = _mm512_mul_epu32     (data_key_hi, prime32);\n        *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));\n    }\n}\n\nXXH_FORCE_INLINE XXH_TARGET_AVX512 void\nXXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64)\n{\n    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0);\n    XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64);\n    XXH_ASSERT(((size_t)customSecret & 63) == 0);\n    (void)(&XXH_writeLE64);\n    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i);\n        __m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64);\n        __m512i const seed     = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos);\n\n        const __m512i* const src  = (const __m512i*) ((const void*) XXH3_kSecret);\n              __m512i* const dest = (      __m512i*) customSecret;\n        int i;\n        XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */\n        XXH_ASSERT(((size_t)dest & 63) == 0);\n        for (i=0; i < nbRounds; ++i) {\n            dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed);\n    }   }\n}\n\n#endif\n\n#if (XXH_VECTOR == XXH_AVX2) \\\n    || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0)\n\n#ifndef XXH_TARGET_AVX2\n# define XXH_TARGET_AVX2  /* disable attribute target */\n#endif\n\nXXH_FORCE_INLINE XXH_TARGET_AVX2 void\nXXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 31) == 0);\n    {   __m256i* const xacc    =       (__m256i *) acc;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm256_loadu_si256 requires  a const __m256i * pointer for some reason. */\n        const         __m256i* const xinput  = (const __m256i *) input;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */\n        const         __m256i* const xsecret = (const __m256i *) secret;\n\n        size_t i;\n        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {\n            /* data_vec    = xinput[i]; */\n            __m256i const data_vec    = _mm256_loadu_si256    (xinput+i);\n            /* key_vec     = xsecret[i]; */\n            __m256i const key_vec     = _mm256_loadu_si256   (xsecret+i);\n            /* data_key    = data_vec ^ key_vec; */\n            __m256i const data_key    = _mm256_xor_si256     (data_vec, key_vec);\n            /* data_key_lo = data_key >> 32; */\n            __m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32);\n            /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */\n            __m256i const product     = _mm256_mul_epu32     (data_key, data_key_lo);\n            /* xacc[i] += swap(data_vec); */\n            __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2));\n            __m256i const sum       = _mm256_add_epi64(xacc[i], data_swap);\n            /* xacc[i] += product; */\n            xacc[i] = _mm256_add_epi64(product, sum);\n    }   }\n}\nXXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2)\n\nXXH_FORCE_INLINE XXH_TARGET_AVX2 void\nXXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 31) == 0);\n    {   __m256i* const xacc = (__m256i*) acc;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */\n        const         __m256i* const xsecret = (const __m256i *) secret;\n        const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1);\n\n        size_t i;\n        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {\n            /* xacc[i] ^= (xacc[i] >> 47) */\n            __m256i const acc_vec     = xacc[i];\n            __m256i const shifted     = _mm256_srli_epi64    (acc_vec, 47);\n            __m256i const data_vec    = _mm256_xor_si256     (acc_vec, shifted);\n            /* xacc[i] ^= xsecret; */\n            __m256i const key_vec     = _mm256_loadu_si256   (xsecret+i);\n            __m256i const data_key    = _mm256_xor_si256     (data_vec, key_vec);\n\n            /* xacc[i] *= XXH_PRIME32_1; */\n            __m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32);\n            __m256i const prod_lo     = _mm256_mul_epu32     (data_key, prime32);\n            __m256i const prod_hi     = _mm256_mul_epu32     (data_key_hi, prime32);\n            xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32));\n        }\n    }\n}\n\nXXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)\n{\n    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0);\n    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6);\n    XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64);\n    (void)(&XXH_writeLE64);\n    XXH_PREFETCH(customSecret);\n    {   __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64);\n\n        const __m256i* const src  = (const __m256i*) ((const void*) XXH3_kSecret);\n              __m256i*       dest = (      __m256i*) customSecret;\n\n#       if defined(__GNUC__) || defined(__clang__)\n        /*\n         * On GCC & Clang, marking 'dest' as modified will cause the compiler:\n         *   - do not extract the secret from sse registers in the internal loop\n         *   - use less common registers, and avoid pushing these reg into stack\n         */\n        XXH_COMPILER_GUARD(dest);\n#       endif\n        XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */\n        XXH_ASSERT(((size_t)dest & 31) == 0);\n\n        /* GCC -O2 need unroll loop manually */\n        dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed);\n        dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed);\n        dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed);\n        dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed);\n        dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed);\n        dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed);\n    }\n}\n\n#endif\n\n/* x86dispatch always generates SSE2 */\n#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH)\n\n#ifndef XXH_TARGET_SSE2\n# define XXH_TARGET_SSE2  /* disable attribute target */\n#endif\n\nXXH_FORCE_INLINE XXH_TARGET_SSE2 void\nXXH3_accumulate_512_sse2( void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    /* SSE2 is just a half-scale version of the AVX2 version. */\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n    {   __m128i* const xacc    =       (__m128i *) acc;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */\n        const         __m128i* const xinput  = (const __m128i *) input;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */\n        const         __m128i* const xsecret = (const __m128i *) secret;\n\n        size_t i;\n        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {\n            /* data_vec    = xinput[i]; */\n            __m128i const data_vec    = _mm_loadu_si128   (xinput+i);\n            /* key_vec     = xsecret[i]; */\n            __m128i const key_vec     = _mm_loadu_si128   (xsecret+i);\n            /* data_key    = data_vec ^ key_vec; */\n            __m128i const data_key    = _mm_xor_si128     (data_vec, key_vec);\n            /* data_key_lo = data_key >> 32; */\n            __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));\n            /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */\n            __m128i const product     = _mm_mul_epu32     (data_key, data_key_lo);\n            /* xacc[i] += swap(data_vec); */\n            __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2));\n            __m128i const sum       = _mm_add_epi64(xacc[i], data_swap);\n            /* xacc[i] += product; */\n            xacc[i] = _mm_add_epi64(product, sum);\n    }   }\n}\nXXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2)\n\nXXH_FORCE_INLINE XXH_TARGET_SSE2 void\nXXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n    {   __m128i* const xacc = (__m128i*) acc;\n        /* Unaligned. This is mainly for pointer arithmetic, and because\n         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */\n        const         __m128i* const xsecret = (const __m128i *) secret;\n        const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1);\n\n        size_t i;\n        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {\n            /* xacc[i] ^= (xacc[i] >> 47) */\n            __m128i const acc_vec     = xacc[i];\n            __m128i const shifted     = _mm_srli_epi64    (acc_vec, 47);\n            __m128i const data_vec    = _mm_xor_si128     (acc_vec, shifted);\n            /* xacc[i] ^= xsecret[i]; */\n            __m128i const key_vec     = _mm_loadu_si128   (xsecret+i);\n            __m128i const data_key    = _mm_xor_si128     (data_vec, key_vec);\n\n            /* xacc[i] *= XXH_PRIME32_1; */\n            __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));\n            __m128i const prod_lo     = _mm_mul_epu32     (data_key, prime32);\n            __m128i const prod_hi     = _mm_mul_epu32     (data_key_hi, prime32);\n            xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32));\n        }\n    }\n}\n\nXXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)\n{\n    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);\n    (void)(&XXH_writeLE64);\n    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i);\n\n#       if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900\n        /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */\n        XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) };\n        __m128i const seed = _mm_load_si128((__m128i const*)seed64x2);\n#       else\n        __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64);\n#       endif\n        int i;\n\n        const void* const src16 = XXH3_kSecret;\n        __m128i* dst16 = (__m128i*) customSecret;\n#       if defined(__GNUC__) || defined(__clang__)\n        /*\n         * On GCC & Clang, marking 'dest' as modified will cause the compiler:\n         *   - do not extract the secret from sse registers in the internal loop\n         *   - use less common registers, and avoid pushing these reg into stack\n         */\n        XXH_COMPILER_GUARD(dst16);\n#       endif\n        XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */\n        XXH_ASSERT(((size_t)dst16 & 15) == 0);\n\n        for (i=0; i < nbRounds; ++i) {\n            dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed);\n    }   }\n}\n\n#endif\n\n#if (XXH_VECTOR == XXH_NEON)\n\n/* forward declarations for the scalar routines */\nXXH_FORCE_INLINE void\nXXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input,\n                 void const* XXH_RESTRICT secret, size_t lane);\n\nXXH_FORCE_INLINE void\nXXH3_scalarScrambleRound(void* XXH_RESTRICT acc,\n                         void const* XXH_RESTRICT secret, size_t lane);\n\n/*!\n * @internal\n * @brief The bulk processing loop for NEON and WASM SIMD128.\n *\n * The NEON code path is actually partially scalar when running on AArch64. This\n * is to optimize the pipelining and can have up to 15% speedup depending on the\n * CPU, and it also mitigates some GCC codegen issues.\n *\n * @see XXH3_NEON_LANES for configuring this and details about this optimization.\n *\n * NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit\n * integers instead of the other platforms which mask full 64-bit vectors,\n * so the setup is more complicated than just shifting right.\n *\n * Additionally, there is an optimization for 4 lanes at once noted below.\n *\n * Since, as stated, the most optimal amount of lanes for Cortexes is 6,\n * there needs to be *three* versions of the accumulate operation used\n * for the remaining 2 lanes.\n *\n * WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap\n * nearly perfectly.\n */\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_neon( void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n    XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0);\n    {   /* GCC for darwin arm64 does not like aliasing here */\n        xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc;\n        /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */\n        uint8_t const* xinput = (const uint8_t *) input;\n        uint8_t const* xsecret  = (const uint8_t *) secret;\n\n        size_t i;\n#ifdef __wasm_simd128__\n        /*\n         * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret\n         * is constant propagated, which results in it converting it to this\n         * inside the loop:\n         *\n         *    a = v128.load(XXH3_kSecret +  0 + $secret_offset, offset = 0)\n         *    b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0)\n         *    ...\n         *\n         * This requires a full 32-bit address immediate (and therefore a 6 byte\n         * instruction) as well as an add for each offset.\n         *\n         * Putting an asm guard prevents it from folding (at the cost of losing\n         * the alignment hint), and uses the free offset in `v128.load` instead\n         * of adding secret_offset each time which overall reduces code size by\n         * about a kilobyte and improves performance.\n         */\n        XXH_COMPILER_GUARD(xsecret);\n#endif\n        /* Scalar lanes use the normal scalarRound routine */\n        for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {\n            XXH3_scalarRound(acc, input, secret, i);\n        }\n        i = 0;\n        /* 4 NEON lanes at a time. */\n        for (; i+1 < XXH3_NEON_LANES / 2; i+=2) {\n            /* data_vec = xinput[i]; */\n            uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput  + (i * 16));\n            uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput  + ((i+1) * 16));\n            /* key_vec  = xsecret[i];  */\n            uint64x2_t key_vec_1  = XXH_vld1q_u64(xsecret + (i * 16));\n            uint64x2_t key_vec_2  = XXH_vld1q_u64(xsecret + ((i+1) * 16));\n            /* data_swap = swap(data_vec) */\n            uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1);\n            uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1);\n            /* data_key = data_vec ^ key_vec; */\n            uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1);\n            uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2);\n\n            /*\n             * If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a\n             * de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to\n             * get one vector with the low 32 bits of each lane, and one vector\n             * with the high 32 bits of each lane.\n             *\n             * The intrinsic returns a double vector because the original ARMv7-a\n             * instruction modified both arguments in place. AArch64 and SIMD128 emit\n             * two instructions from this intrinsic.\n             *\n             *  [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ]\n             *  [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ]\n             */\n            uint32x4x2_t unzipped = vuzpq_u32(\n                vreinterpretq_u32_u64(data_key_1),\n                vreinterpretq_u32_u64(data_key_2)\n            );\n            /* data_key_lo = data_key & 0xFFFFFFFF */\n            uint32x4_t data_key_lo = unzipped.val[0];\n            /* data_key_hi = data_key >> 32 */\n            uint32x4_t data_key_hi = unzipped.val[1];\n            /*\n             * Then, we can split the vectors horizontally and multiply which, as for most\n             * widening intrinsics, have a variant that works on both high half vectors\n             * for free on AArch64. A similar instruction is available on SIMD128.\n             *\n             * sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi\n             */\n            uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi);\n            uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi);\n            /*\n             * Clang reorders\n             *    a += b * c;     // umlal   swap.2d, dkl.2s, dkh.2s\n             *    c += a;         // add     acc.2d, acc.2d, swap.2d\n             * to\n             *    c += a;         // add     acc.2d, acc.2d, swap.2d\n             *    c += b * c;     // umlal   acc.2d, dkl.2s, dkh.2s\n             *\n             * While it would make sense in theory since the addition is faster,\n             * for reasons likely related to umlal being limited to certain NEON\n             * pipelines, this is worse. A compiler guard fixes this.\n             */\n            XXH_COMPILER_GUARD_CLANG_NEON(sum_1);\n            XXH_COMPILER_GUARD_CLANG_NEON(sum_2);\n            /* xacc[i] = acc_vec + sum; */\n            xacc[i]   = vaddq_u64(xacc[i], sum_1);\n            xacc[i+1] = vaddq_u64(xacc[i+1], sum_2);\n        }\n        /* Operate on the remaining NEON lanes 2 at a time. */\n        for (; i < XXH3_NEON_LANES / 2; i++) {\n            /* data_vec = xinput[i]; */\n            uint64x2_t data_vec = XXH_vld1q_u64(xinput  + (i * 16));\n            /* key_vec  = xsecret[i];  */\n            uint64x2_t key_vec  = XXH_vld1q_u64(xsecret + (i * 16));\n            /* acc_vec_2 = swap(data_vec) */\n            uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1);\n            /* data_key = data_vec ^ key_vec; */\n            uint64x2_t data_key = veorq_u64(data_vec, key_vec);\n            /* For two lanes, just use VMOVN and VSHRN. */\n            /* data_key_lo = data_key & 0xFFFFFFFF; */\n            uint32x2_t data_key_lo = vmovn_u64(data_key);\n            /* data_key_hi = data_key >> 32; */\n            uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32);\n            /* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */\n            uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi);\n            /* Same Clang workaround as before */\n            XXH_COMPILER_GUARD_CLANG_NEON(sum);\n            /* xacc[i] = acc_vec + sum; */\n            xacc[i] = vaddq_u64 (xacc[i], sum);\n        }\n    }\n}\nXXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon)\n\nXXH_FORCE_INLINE void\nXXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n\n    {   xxh_aliasing_uint64x2_t* xacc       = (xxh_aliasing_uint64x2_t*) acc;\n        uint8_t const* xsecret = (uint8_t const*) secret;\n\n        size_t i;\n        /* WASM uses operator overloads and doesn't need these. */\n#ifndef __wasm_simd128__\n        /* { prime32_1, prime32_1 } */\n        uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1);\n        /* { 0, prime32_1, 0, prime32_1 } */\n        uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32));\n#endif\n\n        /* AArch64 uses both scalar and neon at the same time */\n        for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {\n            XXH3_scalarScrambleRound(acc, secret, i);\n        }\n        for (i=0; i < XXH3_NEON_LANES / 2; i++) {\n            /* xacc[i] ^= (xacc[i] >> 47); */\n            uint64x2_t acc_vec  = xacc[i];\n            uint64x2_t shifted  = vshrq_n_u64(acc_vec, 47);\n            uint64x2_t data_vec = veorq_u64(acc_vec, shifted);\n\n            /* xacc[i] ^= xsecret[i]; */\n            uint64x2_t key_vec  = XXH_vld1q_u64(xsecret + (i * 16));\n            uint64x2_t data_key = veorq_u64(data_vec, key_vec);\n            /* xacc[i] *= XXH_PRIME32_1 */\n#ifdef __wasm_simd128__\n            /* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */\n            xacc[i] = data_key * XXH_PRIME32_1;\n#else\n            /*\n             * Expanded version with portable NEON intrinsics\n             *\n             *    lo(x) * lo(y) + (hi(x) * lo(y) << 32)\n             *\n             * prod_hi = hi(data_key) * lo(prime) << 32\n             *\n             * Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector\n             * as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits\n             * and avoid the shift.\n             */\n            uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi);\n            /* Extract low bits for vmlal_u32  */\n            uint32x2_t data_key_lo = vmovn_u64(data_key);\n            /* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */\n            xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo);\n#endif\n        }\n    }\n}\n#endif\n\n#if (XXH_VECTOR == XXH_VSX)\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_vsx(  void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    /* presumed aligned */\n    xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;\n    xxh_u8 const* const xinput   = (xxh_u8 const*) input;   /* no alignment restriction */\n    xxh_u8 const* const xsecret  = (xxh_u8 const*) secret;    /* no alignment restriction */\n    xxh_u64x2 const v32 = { 32, 32 };\n    size_t i;\n    for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {\n        /* data_vec = xinput[i]; */\n        xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i);\n        /* key_vec = xsecret[i]; */\n        xxh_u64x2 const key_vec  = XXH_vec_loadu(xsecret + 16*i);\n        xxh_u64x2 const data_key = data_vec ^ key_vec;\n        /* shuffled = (data_key << 32) | (data_key >> 32); */\n        xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);\n        /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */\n        xxh_u64x2 const product  = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);\n        /* acc_vec = xacc[i]; */\n        xxh_u64x2 acc_vec        = xacc[i];\n        acc_vec += product;\n\n        /* swap high and low halves */\n#ifdef __s390x__\n        acc_vec += vec_permi(data_vec, data_vec, 2);\n#else\n        acc_vec += vec_xxpermdi(data_vec, data_vec, 2);\n#endif\n        xacc[i] = acc_vec;\n    }\n}\nXXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx)\n\nXXH_FORCE_INLINE void\nXXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n\n    {   xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;\n        const xxh_u8* const xsecret = (const xxh_u8*) secret;\n        /* constants */\n        xxh_u64x2 const v32  = { 32, 32 };\n        xxh_u64x2 const v47 = { 47, 47 };\n        xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 };\n        size_t i;\n        for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {\n            /* xacc[i] ^= (xacc[i] >> 47); */\n            xxh_u64x2 const acc_vec  = xacc[i];\n            xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);\n\n            /* xacc[i] ^= xsecret[i]; */\n            xxh_u64x2 const key_vec  = XXH_vec_loadu(xsecret + 16*i);\n            xxh_u64x2 const data_key = data_vec ^ key_vec;\n\n            /* xacc[i] *= XXH_PRIME32_1 */\n            /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF);  */\n            xxh_u64x2 const prod_even  = XXH_vec_mule((xxh_u32x4)data_key, prime);\n            /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32);  */\n            xxh_u64x2 const prod_odd  = XXH_vec_mulo((xxh_u32x4)data_key, prime);\n            xacc[i] = prod_odd + (prod_even << v32);\n    }   }\n}\n\n#endif\n\n#if (XXH_VECTOR == XXH_SVE)\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_sve( void* XXH_RESTRICT acc,\n                   const void* XXH_RESTRICT input,\n                   const void* XXH_RESTRICT secret)\n{\n    uint64_t *xacc = (uint64_t *)acc;\n    const uint64_t *xinput = (const uint64_t *)(const void *)input;\n    const uint64_t *xsecret = (const uint64_t *)(const void *)secret;\n    svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);\n    uint64_t element_count = svcntd();\n    if (element_count >= 8) {\n        svbool_t mask = svptrue_pat_b64(SV_VL8);\n        svuint64_t vacc = svld1_u64(mask, xacc);\n        ACCRND(vacc, 0);\n        svst1_u64(mask, xacc, vacc);\n    } else if (element_count == 2) {   /* sve128 */\n        svbool_t mask = svptrue_pat_b64(SV_VL2);\n        svuint64_t acc0 = svld1_u64(mask, xacc + 0);\n        svuint64_t acc1 = svld1_u64(mask, xacc + 2);\n        svuint64_t acc2 = svld1_u64(mask, xacc + 4);\n        svuint64_t acc3 = svld1_u64(mask, xacc + 6);\n        ACCRND(acc0, 0);\n        ACCRND(acc1, 2);\n        ACCRND(acc2, 4);\n        ACCRND(acc3, 6);\n        svst1_u64(mask, xacc + 0, acc0);\n        svst1_u64(mask, xacc + 2, acc1);\n        svst1_u64(mask, xacc + 4, acc2);\n        svst1_u64(mask, xacc + 6, acc3);\n    } else {\n        svbool_t mask = svptrue_pat_b64(SV_VL4);\n        svuint64_t acc0 = svld1_u64(mask, xacc + 0);\n        svuint64_t acc1 = svld1_u64(mask, xacc + 4);\n        ACCRND(acc0, 0);\n        ACCRND(acc1, 4);\n        svst1_u64(mask, xacc + 0, acc0);\n        svst1_u64(mask, xacc + 4, acc1);\n    }\n}\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc,\n               const xxh_u8* XXH_RESTRICT input,\n               const xxh_u8* XXH_RESTRICT secret,\n               size_t nbStripes)\n{\n    if (nbStripes != 0) {\n        uint64_t *xacc = (uint64_t *)acc;\n        const uint64_t *xinput = (const uint64_t *)(const void *)input;\n        const uint64_t *xsecret = (const uint64_t *)(const void *)secret;\n        svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);\n        uint64_t element_count = svcntd();\n        if (element_count >= 8) {\n            svbool_t mask = svptrue_pat_b64(SV_VL8);\n            svuint64_t vacc = svld1_u64(mask, xacc + 0);\n            do {\n                /* svprfd(svbool_t, void *, enum svfprop); */\n                svprfd(mask, xinput + 128, SV_PLDL1STRM);\n                ACCRND(vacc, 0);\n                xinput += 8;\n                xsecret += 1;\n                nbStripes--;\n           } while (nbStripes != 0);\n\n           svst1_u64(mask, xacc + 0, vacc);\n        } else if (element_count == 2) { /* sve128 */\n            svbool_t mask = svptrue_pat_b64(SV_VL2);\n            svuint64_t acc0 = svld1_u64(mask, xacc + 0);\n            svuint64_t acc1 = svld1_u64(mask, xacc + 2);\n            svuint64_t acc2 = svld1_u64(mask, xacc + 4);\n            svuint64_t acc3 = svld1_u64(mask, xacc + 6);\n            do {\n                svprfd(mask, xinput + 128, SV_PLDL1STRM);\n                ACCRND(acc0, 0);\n                ACCRND(acc1, 2);\n                ACCRND(acc2, 4);\n                ACCRND(acc3, 6);\n                xinput += 8;\n                xsecret += 1;\n                nbStripes--;\n           } while (nbStripes != 0);\n\n           svst1_u64(mask, xacc + 0, acc0);\n           svst1_u64(mask, xacc + 2, acc1);\n           svst1_u64(mask, xacc + 4, acc2);\n           svst1_u64(mask, xacc + 6, acc3);\n        } else {\n            svbool_t mask = svptrue_pat_b64(SV_VL4);\n            svuint64_t acc0 = svld1_u64(mask, xacc + 0);\n            svuint64_t acc1 = svld1_u64(mask, xacc + 4);\n            do {\n                svprfd(mask, xinput + 128, SV_PLDL1STRM);\n                ACCRND(acc0, 0);\n                ACCRND(acc1, 4);\n                xinput += 8;\n                xsecret += 1;\n                nbStripes--;\n           } while (nbStripes != 0);\n\n           svst1_u64(mask, xacc + 0, acc0);\n           svst1_u64(mask, xacc + 4, acc1);\n       }\n    }\n}\n\n#endif\n\n#if (XXH_VECTOR == XXH_LSX)\n#define _LSX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_lsx( void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n    {\n        __m128i* const xacc    =       (__m128i *) acc;\n        const __m128i* const xinput  = (const __m128i *) input;\n        const __m128i* const xsecret = (const __m128i *) secret;\n\n        for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {\n            /* data_vec = xinput[i]; */\n            __m128i const data_vec = __lsx_vld(xinput + i, 0);\n            /* key_vec = xsecret[i]; */\n            __m128i const key_vec = __lsx_vld(xsecret + i, 0);\n            /* data_key = data_vec ^ key_vec; */\n            __m128i const data_key = __lsx_vxor_v(data_vec, key_vec);\n            /* data_key_lo = data_key >> 32; */\n            __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32);\n            // __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32);\n            /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */\n            __m128i const product = __lsx_vmulwev_d_wu(data_key, data_key_lo);\n            /* xacc[i] += swap(data_vec); */\n            __m128i const data_swap = __lsx_vshuf4i_w(data_vec, _LSX_SHUFFLE(1, 0, 3, 2));\n            __m128i const sum = __lsx_vadd_d(xacc[i], data_swap);\n            /* xacc[i] += product; */\n            xacc[i] = __lsx_vadd_d(product, sum);\n        }\n    }\n}\nXXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lsx)\n\nXXH_FORCE_INLINE void\nXXH3_scrambleAcc_lsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 15) == 0);\n    {\n        __m128i* const xacc = (__m128i*) acc;\n        const __m128i* const xsecret = (const __m128i *) secret;\n        const __m128i prime32 = __lsx_vreplgr2vr_d(XXH_PRIME32_1);\n\n        for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {\n            /* xacc[i] ^= (xacc[i] >> 47) */\n            __m128i const acc_vec = xacc[i];\n            __m128i const shifted = __lsx_vsrli_d(acc_vec, 47);\n            __m128i const data_vec = __lsx_vxor_v(acc_vec, shifted);\n            /* xacc[i] ^= xsecret[i]; */\n            __m128i const key_vec = __lsx_vld(xsecret + i, 0);\n            __m128i const data_key = __lsx_vxor_v(data_vec, key_vec);\n\n            /* xacc[i] *= XXH_PRIME32_1; */\n            xacc[i] = __lsx_vmul_d(data_key, prime32);\n        }\n    }\n}\n\n#endif\n\n#if (XXH_VECTOR == XXH_LASX)\n#define _LASX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))\n\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_lasx( void* XXH_RESTRICT acc,\n                    const void* XXH_RESTRICT input,\n                    const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 31) == 0);\n    {\n        __m256i* const xacc    =       (__m256i *) acc;\n        const __m256i* const xinput  = (const __m256i *) input;\n        const __m256i* const xsecret = (const __m256i *) secret;\n\n        for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {\n            /* data_vec = xinput[i]; */\n            __m256i const data_vec = __lasx_xvld(xinput + i, 0);\n            /* key_vec = xsecret[i]; */\n            __m256i const key_vec = __lasx_xvld(xsecret + i, 0);\n            /* data_key = data_vec ^ key_vec; */\n            __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec);\n            /* data_key_lo = data_key >> 32; */\n            __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32);\n            // __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32);\n            /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */\n            __m256i const product = __lasx_xvmulwev_d_wu(data_key, data_key_lo);\n            /* xacc[i] += swap(data_vec); */\n            __m256i const data_swap = __lasx_xvshuf4i_w(data_vec, _LASX_SHUFFLE(1, 0, 3, 2));\n            __m256i const sum = __lasx_xvadd_d(xacc[i], data_swap);\n            /* xacc[i] += product; */\n            xacc[i] = __lasx_xvadd_d(product, sum);\n        }\n    }\n}\nXXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lasx)\n\nXXH_FORCE_INLINE void\nXXH3_scrambleAcc_lasx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    XXH_ASSERT((((size_t)acc) & 31) == 0);\n    {\n        __m256i* const xacc = (__m256i*) acc;\n        const __m256i* const xsecret = (const __m256i *) secret;\n        const __m256i prime32 = __lasx_xvreplgr2vr_d(XXH_PRIME32_1);\n\n        for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {\n            /* xacc[i] ^= (xacc[i] >> 47) */\n            __m256i const acc_vec = xacc[i];\n            __m256i const shifted = __lasx_xvsrli_d(acc_vec, 47);\n            __m256i const data_vec = __lasx_xvxor_v(acc_vec, shifted);\n            /* xacc[i] ^= xsecret[i]; */\n            __m256i const key_vec = __lasx_xvld(xsecret + i, 0);\n            __m256i const data_key = __lasx_xvxor_v(data_vec, key_vec);\n\n            /* xacc[i] *= XXH_PRIME32_1; */\n            xacc[i] = __lasx_xvmul_d(data_key, prime32);\n        }\n    }\n}\n\n#endif\n\n/* scalar variants - universal */\n\n#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__))\n/*\n * In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they\n * emit an excess mask and a full 64-bit multiply-add (MADD X-form).\n *\n * While this might not seem like much, as AArch64 is a 64-bit architecture, only\n * big Cortex designs have a full 64-bit multiplier.\n *\n * On the little cores, the smaller 32-bit multiplier is used, and full 64-bit\n * multiplies expand to 2-3 multiplies in microcode. This has a major penalty\n * of up to 4 latency cycles and 2 stall cycles in the multiply pipeline.\n *\n * Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does\n * not have this penalty and does the mask automatically.\n */\nXXH_FORCE_INLINE xxh_u64\nXXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)\n{\n    xxh_u64 ret;\n    /* note: %x = 64-bit register, %w = 32-bit register */\n    __asm__(\"umaddl %x0, %w1, %w2, %x3\" : \"=r\" (ret) : \"r\" (lhs), \"r\" (rhs), \"r\" (acc));\n    return ret;\n}\n#else\nXXH_FORCE_INLINE xxh_u64\nXXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)\n{\n    return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc;\n}\n#endif\n\n/*!\n * @internal\n * @brief Scalar round for @ref XXH3_accumulate_512_scalar().\n *\n * This is extracted to its own function because the NEON path uses a combination\n * of NEON and scalar.\n */\nXXH_FORCE_INLINE void\nXXH3_scalarRound(void* XXH_RESTRICT acc,\n                 void const* XXH_RESTRICT input,\n                 void const* XXH_RESTRICT secret,\n                 size_t lane)\n{\n    xxh_u64* xacc = (xxh_u64*) acc;\n    xxh_u8 const* xinput  = (xxh_u8 const*) input;\n    xxh_u8 const* xsecret = (xxh_u8 const*) secret;\n    XXH_ASSERT(lane < XXH_ACC_NB);\n    XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0);\n    {\n        xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8);\n        xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8);\n        xacc[lane ^ 1] += data_val; /* swap adjacent lanes */\n        xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]);\n    }\n}\n\n/*!\n * @internal\n * @brief Processes a 64 byte block of data using the scalar path.\n */\nXXH_FORCE_INLINE void\nXXH3_accumulate_512_scalar(void* XXH_RESTRICT acc,\n                     const void* XXH_RESTRICT input,\n                     const void* XXH_RESTRICT secret)\n{\n    size_t i;\n    /* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */\n#if defined(__GNUC__) && !defined(__clang__) \\\n  && (defined(__arm__) || defined(__thumb2__)) \\\n  && defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \\\n  && XXH_SIZE_OPT <= 0\n#  pragma GCC unroll 8\n#endif\n    for (i=0; i < XXH_ACC_NB; i++) {\n        XXH3_scalarRound(acc, input, secret, i);\n    }\n}\nXXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar)\n\n/*!\n * @internal\n * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar().\n *\n * This is extracted to its own function because the NEON path uses a combination\n * of NEON and scalar.\n */\nXXH_FORCE_INLINE void\nXXH3_scalarScrambleRound(void* XXH_RESTRICT acc,\n                         void const* XXH_RESTRICT secret,\n                         size_t lane)\n{\n    xxh_u64* const xacc = (xxh_u64*) acc;   /* presumed aligned */\n    const xxh_u8* const xsecret = (const xxh_u8*) secret;   /* no alignment restriction */\n    XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0);\n    XXH_ASSERT(lane < XXH_ACC_NB);\n    {\n        xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8);\n        xxh_u64 acc64 = xacc[lane];\n        acc64 = XXH_xorshift64(acc64, 47);\n        acc64 ^= key64;\n        acc64 *= XXH_PRIME32_1;\n        xacc[lane] = acc64;\n    }\n}\n\n/*!\n * @internal\n * @brief Scrambles the accumulators after a large chunk has been read\n */\nXXH_FORCE_INLINE void\nXXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)\n{\n    size_t i;\n    for (i=0; i < XXH_ACC_NB; i++) {\n        XXH3_scalarScrambleRound(acc, secret, i);\n    }\n}\n\nXXH_FORCE_INLINE void\nXXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)\n{\n    /*\n     * We need a separate pointer for the hack below,\n     * which requires a non-const pointer.\n     * Any decent compiler will optimize this out otherwise.\n     */\n    const xxh_u8* kSecretPtr = XXH3_kSecret;\n    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);\n\n#if defined(__GNUC__) && defined(__aarch64__)\n    /*\n     * UGLY HACK:\n     * GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are\n     * placed sequentially, in order, at the top of the unrolled loop.\n     *\n     * While MOVK is great for generating constants (2 cycles for a 64-bit\n     * constant compared to 4 cycles for LDR), it fights for bandwidth with\n     * the arithmetic instructions.\n     *\n     *   I   L   S\n     * MOVK\n     * MOVK\n     * MOVK\n     * MOVK\n     * ADD\n     * SUB      STR\n     *          STR\n     * By forcing loads from memory (as the asm line causes the compiler to assume\n     * that XXH3_kSecretPtr has been changed), the pipelines are used more\n     * efficiently:\n     *   I   L   S\n     *      LDR\n     *  ADD LDR\n     *  SUB     STR\n     *          STR\n     *\n     * See XXH3_NEON_LANES for details on the pipsline.\n     *\n     * XXH3_64bits_withSeed, len == 256, Snapdragon 835\n     *   without hack: 2654.4 MB/s\n     *   with hack:    3202.9 MB/s\n     */\n    XXH_COMPILER_GUARD(kSecretPtr);\n#endif\n    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;\n        int i;\n        for (i=0; i < nbRounds; i++) {\n            /*\n             * The asm hack causes the compiler to assume that kSecretPtr aliases with\n             * customSecret, and on aarch64, this prevented LDP from merging two\n             * loads together for free. Putting the loads together before the stores\n             * properly generates LDP.\n             */\n            xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i)     + seed64;\n            xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64;\n            XXH_writeLE64((xxh_u8*)customSecret + 16*i,     lo);\n            XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi);\n    }   }\n}\n\n\ntypedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t);\ntypedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*);\ntypedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64);\n\n\n#if (XXH_VECTOR == XXH_AVX512)\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_avx512\n#define XXH3_accumulate     XXH3_accumulate_avx512\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_avx512\n#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512\n\n#elif (XXH_VECTOR == XXH_AVX2)\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_avx2\n#define XXH3_accumulate     XXH3_accumulate_avx2\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_avx2\n#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2\n\n#elif (XXH_VECTOR == XXH_SSE2)\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_sse2\n#define XXH3_accumulate     XXH3_accumulate_sse2\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_sse2\n#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2\n\n#elif (XXH_VECTOR == XXH_NEON)\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_neon\n#define XXH3_accumulate     XXH3_accumulate_neon\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_neon\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#elif (XXH_VECTOR == XXH_VSX)\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_vsx\n#define XXH3_accumulate     XXH3_accumulate_vsx\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_vsx\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#elif (XXH_VECTOR == XXH_SVE)\n#define XXH3_accumulate_512 XXH3_accumulate_512_sve\n#define XXH3_accumulate     XXH3_accumulate_sve\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_scalar\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#elif (XXH_VECTOR == XXH_LASX)\n#define XXH3_accumulate_512 XXH3_accumulate_512_lasx\n#define XXH3_accumulate     XXH3_accumulate_lasx\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_lasx\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#elif (XXH_VECTOR == XXH_LSX)\n#define XXH3_accumulate_512 XXH3_accumulate_512_lsx\n#define XXH3_accumulate     XXH3_accumulate_lsx\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_lsx\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#else /* scalar */\n\n#define XXH3_accumulate_512 XXH3_accumulate_512_scalar\n#define XXH3_accumulate     XXH3_accumulate_scalar\n#define XXH3_scrambleAcc    XXH3_scrambleAcc_scalar\n#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n\n#endif\n\n#if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */\n#  undef XXH3_initCustomSecret\n#  define XXH3_initCustomSecret XXH3_initCustomSecret_scalar\n#endif\n\nXXH_FORCE_INLINE void\nXXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,\n                      const xxh_u8* XXH_RESTRICT input, size_t len,\n                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                            XXH3_f_accumulate f_acc,\n                            XXH3_f_scrambleAcc f_scramble)\n{\n    size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;\n    size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock;\n    size_t const nb_blocks = (len - 1) / block_len;\n\n    size_t n;\n\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);\n\n    for (n = 0; n < nb_blocks; n++) {\n        f_acc(acc, input + n*block_len, secret, nbStripesPerBlock);\n        f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN);\n    }\n\n    /* last partial block */\n    XXH_ASSERT(len > XXH_STRIPE_LEN);\n    {   size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;\n        XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE));\n        f_acc(acc, input + nb_blocks*block_len, secret, nbStripes);\n\n        /* last stripe */\n        {   const xxh_u8* const p = input + len - XXH_STRIPE_LEN;\n#define XXH_SECRET_LASTACC_START 7  /* not aligned on 8, last secret is different from acc & scrambler */\n            XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);\n    }   }\n}\n\nXXH_FORCE_INLINE xxh_u64\nXXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret)\n{\n    return XXH3_mul128_fold64(\n               acc[0] ^ XXH_readLE64(secret),\n               acc[1] ^ XXH_readLE64(secret+8) );\n}\n\nstatic XXH_PUREF XXH64_hash_t\nXXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start)\n{\n    xxh_u64 result64 = start;\n    size_t i = 0;\n\n    for (i = 0; i < 4; i++) {\n        result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i);\n#if defined(__clang__)                                /* Clang */ \\\n    && (defined(__arm__) || defined(__thumb__))       /* ARMv7 */ \\\n    && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */  \\\n    && !defined(XXH_ENABLE_AUTOVECTORIZE)             /* Define to disable */\n        /*\n         * UGLY HACK:\n         * Prevent autovectorization on Clang ARMv7-a. Exact same problem as\n         * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b.\n         * XXH3_64bits, len == 256, Snapdragon 835:\n         *   without hack: 2063.7 MB/s\n         *   with hack:    2560.7 MB/s\n         */\n        XXH_COMPILER_GUARD(result64);\n#endif\n    }\n\n    return XXH3_avalanche(result64);\n}\n\n/* do not align on 8, so that the secret is different from the accumulator */\n#define XXH_SECRET_MERGEACCS_START 11\n\nstatic XXH_PUREF XXH64_hash_t\nXXH3_finalizeLong_64b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 len)\n{\n    return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, len * XXH_PRIME64_1);\n}\n\n#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \\\n                        XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 }\n\nXXH_FORCE_INLINE XXH64_hash_t\nXXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,\n                           const void* XXH_RESTRICT secret, size_t secretSize,\n                           XXH3_f_accumulate f_acc,\n                           XXH3_f_scrambleAcc f_scramble)\n{\n    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;\n\n    XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble);\n\n    /* converge into final hash */\n    XXH_STATIC_ASSERT(sizeof(acc) == 64);\n    XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);\n    return XXH3_finalizeLong_64b(acc, (const xxh_u8*)secret, (xxh_u64)len);\n}\n\n/*\n * It's important for performance to transmit secret's size (when it's static)\n * so that the compiler can properly optimize the vectorized loop.\n * This makes a big performance difference for \"medium\" keys (<1 KB) when using AVX instruction set.\n * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE\n * breaks -Og, this is XXH_NO_INLINE.\n */\nXXH3_WITH_SECRET_INLINE XXH64_hash_t\nXXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,\n                             XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)seed64;\n    return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc);\n}\n\n/*\n * It's preferable for performance that XXH3_hashLong is not inlined,\n * as it results in a smaller function for small data, easier to the instruction cache.\n * Note that inside this no_inline function, we do inline the internal loop,\n * and provide a statically defined secret size to allow optimization of vector loop.\n */\nXXH_NO_INLINE XXH_PUREF XXH64_hash_t\nXXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,\n                          XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)seed64; (void)secret; (void)secretLen;\n    return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc);\n}\n\n/*\n * XXH3_hashLong_64b_withSeed():\n * Generate a custom key based on alteration of default XXH3_kSecret with the seed,\n * and then use this key for long mode hashing.\n *\n * This operation is decently fast but nonetheless costs a little bit of time.\n * Try to avoid it whenever possible (typically when seed==0).\n *\n * It's important for performance that XXH3_hashLong is not inlined. Not sure\n * why (uop cache maybe?), but the difference is large and easily measurable.\n */\nXXH_FORCE_INLINE XXH64_hash_t\nXXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,\n                                    XXH64_hash_t seed,\n                                    XXH3_f_accumulate f_acc,\n                                    XXH3_f_scrambleAcc f_scramble,\n                                    XXH3_f_initCustomSecret f_initSec)\n{\n#if XXH_SIZE_OPT <= 0\n    if (seed == 0)\n        return XXH3_hashLong_64b_internal(input, len,\n                                          XXH3_kSecret, sizeof(XXH3_kSecret),\n                                          f_acc, f_scramble);\n#endif\n    {   XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];\n        f_initSec(secret, seed);\n        return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),\n                                          f_acc, f_scramble);\n    }\n}\n\n/*\n * It's important for performance that XXH3_hashLong is not inlined.\n */\nXXH_NO_INLINE XXH64_hash_t\nXXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len,\n                           XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)secret; (void)secretLen;\n    return XXH3_hashLong_64b_withSeed_internal(input, len, seed,\n                XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);\n}\n\n\ntypedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t,\n                                          XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t);\n\nXXH_FORCE_INLINE XXH64_hash_t\nXXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len,\n                     XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,\n                     XXH3_hashLong64_f f_hashLong)\n{\n    XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);\n    /*\n     * If an action is to be taken if `secretLen` condition is not respected,\n     * it should be done here.\n     * For now, it's a contract pre-condition.\n     * Adding a check and a branch here would cost performance at every hash.\n     * Also, note that function signature doesn't offer room to return an error.\n     */\n    if (len <= 16)\n        return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);\n    if (len <= 128)\n        return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);\n    if (len <= XXH3_MIDSIZE_MAX)\n        return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);\n    return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen);\n}\n\n\n/* ===   Public entry point   === */\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length)\n{\n    return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH64_hash_t\nXXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize)\n{\n    return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH64_hash_t\nXXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed)\n{\n    return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);\n}\n\nXXH_PUBLIC_API XXH64_hash_t\nXXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)\n{\n    if (length <= XXH3_MIDSIZE_MAX)\n        return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);\n    return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize);\n}\n\n\n/* ===   XXH3 streaming   === */\n#ifndef XXH_NO_STREAM\n/*\n * Malloc's a pointer that is always aligned to @align.\n *\n * This must be freed with `XXH_alignedFree()`.\n *\n * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte\n * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2\n * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON.\n *\n * This underalignment previously caused a rather obvious crash which went\n * completely unnoticed due to XXH3_createState() not actually being tested.\n * Credit to RedSpah for noticing this bug.\n *\n * The alignment is done manually: Functions like posix_memalign or _mm_malloc\n * are avoided: To maintain portability, we would have to write a fallback\n * like this anyways, and besides, testing for the existence of library\n * functions without relying on external build tools is impossible.\n *\n * The method is simple: Overallocate, manually align, and store the offset\n * to the original behind the returned pointer.\n *\n * Align must be a power of 2 and 8 <= align <= 128.\n */\nstatic XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align)\n{\n    XXH_ASSERT(align <= 128 && align >= 8); /* range check */\n    XXH_ASSERT((align & (align-1)) == 0);   /* power of 2 */\n    XXH_ASSERT(s != 0 && s < (s + align));  /* empty/overflow */\n    {   /* Overallocate to make room for manual realignment and an offset byte */\n        xxh_u8* base = (xxh_u8*)XXH_malloc(s + align);\n        if (base != NULL) {\n            /*\n             * Get the offset needed to align this pointer.\n             *\n             * Even if the returned pointer is aligned, there will always be\n             * at least one byte to store the offset to the original pointer.\n             */\n            size_t offset = align - ((size_t)base & (align - 1)); /* base % align */\n            /* Add the offset for the now-aligned pointer */\n            xxh_u8* ptr = base + offset;\n\n            XXH_ASSERT((size_t)ptr % align == 0);\n\n            /* Store the offset immediately before the returned pointer. */\n            ptr[-1] = (xxh_u8)offset;\n            return ptr;\n        }\n        return NULL;\n    }\n}\n/*\n * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass\n * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout.\n */\nstatic void XXH_alignedFree(void* p)\n{\n    if (p != NULL) {\n        xxh_u8* ptr = (xxh_u8*)p;\n        /* Get the offset byte we added in XXH_malloc. */\n        xxh_u8 offset = ptr[-1];\n        /* Free the original malloc'd pointer */\n        xxh_u8* base = ptr - offset;\n        XXH_free(base);\n    }\n}\n/*! @ingroup XXH3_family */\n/*!\n * @brief Allocate an @ref XXH3_state_t.\n *\n * @return An allocated pointer of @ref XXH3_state_t on success.\n * @return `NULL` on failure.\n *\n * @note Must be freed with XXH3_freeState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)\n{\n    XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);\n    if (state==NULL) return NULL;\n    XXH3_INITSTATE(state);\n    return state;\n}\n\n/*! @ingroup XXH3_family */\n/*!\n * @brief Frees an @ref XXH3_state_t.\n *\n * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().\n *\n * @return @ref XXH_OK.\n *\n * @note Must be allocated with XXH3_createState().\n *\n * @see @ref streaming_example \"Streaming Example\"\n */\nXXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)\n{\n    XXH_alignedFree(statePtr);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API void\nXXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state)\n{\n    XXH_memcpy(dst_state, src_state, sizeof(*dst_state));\n}\n\nstatic void\nXXH3_reset_internal(XXH3_state_t* statePtr,\n                    XXH64_hash_t seed,\n                    const void* secret, size_t secretSize)\n{\n    size_t const initStart = offsetof(XXH3_state_t, bufferedSize);\n    size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart;\n    XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart);\n    XXH_ASSERT(statePtr != NULL);\n    /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */\n    XXH_memset((char*)statePtr + initStart, 0, initLength);\n    statePtr->acc[0] = XXH_PRIME32_3;\n    statePtr->acc[1] = XXH_PRIME64_1;\n    statePtr->acc[2] = XXH_PRIME64_2;\n    statePtr->acc[3] = XXH_PRIME64_3;\n    statePtr->acc[4] = XXH_PRIME64_4;\n    statePtr->acc[5] = XXH_PRIME32_2;\n    statePtr->acc[6] = XXH_PRIME64_5;\n    statePtr->acc[7] = XXH_PRIME32_1;\n    statePtr->seed = seed;\n    statePtr->useSeed = (seed != 0);\n    statePtr->extSecret = (const unsigned char*)secret;\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);\n    statePtr->secretLimit = secretSize - XXH_STRIPE_LEN;\n    statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)\n{\n    if (statePtr == NULL) return XXH_ERROR;\n    XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)\n{\n    if (statePtr == NULL) return XXH_ERROR;\n    XXH3_reset_internal(statePtr, 0, secret, secretSize);\n    if (secret == NULL) return XXH_ERROR;\n    if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;\n    return XXH_OK;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)\n{\n    if (statePtr == NULL) return XXH_ERROR;\n    if (seed==0) return XXH3_64bits_reset(statePtr);\n    if ((seed != statePtr->seed) || (statePtr->extSecret != NULL))\n        XXH3_initCustomSecret(statePtr->customSecret, seed);\n    XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);\n    return XXH_OK;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64)\n{\n    if (statePtr == NULL) return XXH_ERROR;\n    if (secret == NULL) return XXH_ERROR;\n    if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;\n    XXH3_reset_internal(statePtr, seed64, secret, secretSize);\n    statePtr->useSeed = 1; /* always, even if seed64==0 */\n    return XXH_OK;\n}\n\n/*!\n * @internal\n * @brief Processes a large input for XXH3_update() and XXH3_digest_long().\n *\n * Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block.\n *\n * @param acc                Pointer to the 8 accumulator lanes\n * @param nbStripesSoFarPtr  In/out pointer to the number of leftover stripes in the block*\n * @param nbStripesPerBlock  Number of stripes in a block\n * @param input              Input pointer\n * @param nbStripes          Number of stripes to process\n * @param secret             Secret pointer\n * @param secretLimit        Offset of the last block in @p secret\n * @param f_acc              Pointer to an XXH3_accumulate implementation\n * @param f_scramble         Pointer to an XXH3_scrambleAcc implementation\n * @return                   Pointer past the end of @p input after processing\n */\nXXH_FORCE_INLINE const xxh_u8 *\nXXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,\n                    size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,\n                    const xxh_u8* XXH_RESTRICT input, size_t nbStripes,\n                    const xxh_u8* XXH_RESTRICT secret, size_t secretLimit,\n                    XXH3_f_accumulate f_acc,\n                    XXH3_f_scrambleAcc f_scramble)\n{\n    const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE;\n    /* Process full blocks */\n    if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) {\n        /* Process the initial partial block... */\n        size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr;\n\n        do {\n            /* Accumulate and scramble */\n            f_acc(acc, input, initialSecret, nbStripesThisIter);\n            f_scramble(acc, secret + secretLimit);\n            input += nbStripesThisIter * XXH_STRIPE_LEN;\n            nbStripes -= nbStripesThisIter;\n            /* Then continue the loop with the full block size */\n            nbStripesThisIter = nbStripesPerBlock;\n            initialSecret = secret;\n        } while (nbStripes >= nbStripesPerBlock);\n        *nbStripesSoFarPtr = 0;\n    }\n    /* Process a partial block */\n    if (nbStripes > 0) {\n        f_acc(acc, input, initialSecret, nbStripes);\n        input += nbStripes * XXH_STRIPE_LEN;\n        *nbStripesSoFarPtr += nbStripes;\n    }\n    /* Return end pointer */\n    return input;\n}\n\n#ifndef XXH3_STREAM_USE_STACK\n# if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */\n#   define XXH3_STREAM_USE_STACK 1\n# endif\n#endif\n/* This function accepts f_acc and f_scramble as function pointers,\n * making it possible to implement multiple variants with different acc & scramble stages.\n * This is notably useful to implement multiple vector variants with different intrinsics.\n */\nXXH_FORCE_INLINE XXH_errorcode\nXXH3_update(XXH3_state_t* XXH_RESTRICT const state,\n            const xxh_u8* XXH_RESTRICT input, size_t len,\n            XXH3_f_accumulate f_acc,\n            XXH3_f_scrambleAcc f_scramble)\n{\n    if (input==NULL) {\n        XXH_ASSERT(len == 0);\n        return XXH_OK;\n    }\n\n    XXH_ASSERT(state != NULL);\n    {   const xxh_u8* const bEnd = input + len;\n        const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;\n#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1\n        /* For some reason, gcc and MSVC seem to suffer greatly\n         * when operating accumulators directly into state.\n         * Operating into stack space seems to enable proper optimization.\n         * clang, on the other hand, doesn't seem to need this trick */\n        XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8];\n        XXH_memcpy(acc, state->acc, sizeof(acc));\n#else\n        xxh_u64* XXH_RESTRICT const acc = state->acc;\n#endif\n        state->totalLen += len;\n        XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);\n\n        /* small input : just fill in tmp buffer */\n        if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) {\n            XXH_memcpy(state->buffer + state->bufferedSize, input, len);\n            state->bufferedSize += (XXH32_hash_t)len;\n            return XXH_OK;\n        }\n\n        /* total input is now > XXH3_INTERNALBUFFER_SIZE */\n        #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN)\n        XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0);   /* clean multiple */\n\n        /*\n         * Internal buffer is partially filled (always, except at beginning)\n         * Complete it, then consume it.\n         */\n        if (state->bufferedSize) {\n            size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize;\n            XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize);\n            input += loadSize;\n            XXH3_consumeStripes(acc,\n                               &state->nbStripesSoFar, state->nbStripesPerBlock,\n                                state->buffer, XXH3_INTERNALBUFFER_STRIPES,\n                                secret, state->secretLimit,\n                                f_acc, f_scramble);\n            state->bufferedSize = 0;\n        }\n        XXH_ASSERT(input < bEnd);\n        if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {\n            size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN;\n            input = XXH3_consumeStripes(acc,\n                                       &state->nbStripesSoFar, state->nbStripesPerBlock,\n                                       input, nbStripes,\n                                       secret, state->secretLimit,\n                                       f_acc, f_scramble);\n            XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);\n\n        }\n        /* Some remaining input (always) : buffer it */\n        XXH_ASSERT(input < bEnd);\n        XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE);\n        XXH_ASSERT(state->bufferedSize == 0);\n        XXH_memcpy(state->buffer, input, (size_t)(bEnd-input));\n        state->bufferedSize = (XXH32_hash_t)(bEnd-input);\n#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1\n        /* save stack accumulators into state */\n        XXH_memcpy(state->acc, acc, sizeof(acc));\n#endif\n    }\n\n    return XXH_OK;\n}\n\n/*\n * Both XXH3_64bits_update and XXH3_128bits_update use this routine.\n */\nXXH_NO_INLINE XXH_errorcode\nXXH3_update_regular(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)\n{\n    return XXH3_update(state, (const xxh_u8*)input, len,\n                       XXH3_accumulate, XXH3_scrambleAcc);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)\n{\n    return XXH3_update_regular(state, input, len);\n}\n\n\nXXH_FORCE_INLINE void\nXXH3_digest_long (XXH64_hash_t* acc,\n                  const XXH3_state_t* state,\n                  const unsigned char* secret)\n{\n    xxh_u8 lastStripe[XXH_STRIPE_LEN];\n    const xxh_u8* lastStripePtr;\n\n    /*\n     * Digest on a local copy. This way, the state remains unaltered, and it can\n     * continue ingesting more input afterwards.\n     */\n    XXH_memcpy(acc, state->acc, sizeof(state->acc));\n    if (state->bufferedSize >= XXH_STRIPE_LEN) {\n        /* Consume remaining stripes then point to remaining data in buffer */\n        size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;\n        size_t nbStripesSoFar = state->nbStripesSoFar;\n        XXH3_consumeStripes(acc,\n                           &nbStripesSoFar, state->nbStripesPerBlock,\n                            state->buffer, nbStripes,\n                            secret, state->secretLimit,\n                            XXH3_accumulate, XXH3_scrambleAcc);\n        lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN;\n    } else {  /* bufferedSize < XXH_STRIPE_LEN */\n        /* Copy to temp buffer */\n        size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;\n        XXH_ASSERT(state->bufferedSize > 0);  /* there is always some input buffered */\n        XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);\n        XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);\n        lastStripePtr = lastStripe;\n    }\n    /* Last stripe */\n    XXH3_accumulate_512(acc,\n                        lastStripePtr,\n                        secret + state->secretLimit - XXH_SECRET_LASTACC_START);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state)\n{\n    const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;\n    if (state->totalLen > XXH3_MIDSIZE_MAX) {\n        XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];\n        XXH3_digest_long(acc, state, secret);\n        return XXH3_finalizeLong_64b(acc, secret, (xxh_u64)state->totalLen);\n    }\n    /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */\n    if (state->useSeed)\n        return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);\n    return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),\n                                  secret, state->secretLimit + XXH_STRIPE_LEN);\n}\n#endif /* !XXH_NO_STREAM */\n\n\n/* ==========================================\n * XXH3 128 bits (a.k.a XXH128)\n * ==========================================\n * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant,\n * even without counting the significantly larger output size.\n *\n * For example, extra steps are taken to avoid the seed-dependent collisions\n * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B).\n *\n * This strength naturally comes at the cost of some speed, especially on short\n * lengths. Note that longer hashes are about as fast as the 64-bit version\n * due to it using only a slight modification of the 64-bit loop.\n *\n * XXH128 is also more oriented towards 64-bit machines. It is still extremely\n * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64).\n */\n\nXXH_FORCE_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    /* A doubled version of 1to3_64b with different constants. */\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(1 <= len && len <= 3);\n    XXH_ASSERT(secret != NULL);\n    /*\n     * len = 1: combinedl = { input[0], 0x01, input[0], input[0] }\n     * len = 2: combinedl = { input[1], 0x02, input[0], input[1] }\n     * len = 3: combinedl = { input[2], 0x03, input[0], input[1] }\n     */\n    {   xxh_u8 const c1 = input[0];\n        xxh_u8 const c2 = input[len >> 1];\n        xxh_u8 const c3 = input[len - 1];\n        xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24)\n                                | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);\n        xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13);\n        xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;\n        xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed;\n        xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl;\n        xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph;\n        XXH128_hash_t h128;\n        h128.low64  = XXH64_avalanche(keyed_lo);\n        h128.high64 = XXH64_avalanche(keyed_hi);\n        return h128;\n    }\n}\n\nXXH_FORCE_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(secret != NULL);\n    XXH_ASSERT(4 <= len && len <= 8);\n    seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;\n    {   xxh_u32 const input_lo = XXH_readLE32(input);\n        xxh_u32 const input_hi = XXH_readLE32(input + len - 4);\n        xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32);\n        xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed;\n        xxh_u64 const keyed = input_64 ^ bitflip;\n\n        /* Shift len to the left to ensure it is even, this avoids even multiplies. */\n        XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2));\n\n        m128.high64 += (m128.low64 << 1);\n        m128.low64  ^= (m128.high64 >> 3);\n\n        m128.low64   = XXH_xorshift64(m128.low64, 35);\n        m128.low64  *= PRIME_MX2;\n        m128.low64   = XXH_xorshift64(m128.low64, 28);\n        m128.high64  = XXH3_avalanche(m128.high64);\n        return m128;\n    }\n}\n\nXXH_FORCE_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(input != NULL);\n    XXH_ASSERT(secret != NULL);\n    XXH_ASSERT(9 <= len && len <= 16);\n    {   xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed;\n        xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed;\n        xxh_u64 const input_lo = XXH_readLE64(input);\n        xxh_u64       input_hi = XXH_readLE64(input + len - 8);\n        XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1);\n        /*\n         * Put len in the middle of m128 to ensure that the length gets mixed to\n         * both the low and high bits in the 128x64 multiply below.\n         */\n        m128.low64 += (xxh_u64)(len - 1) << 54;\n        input_hi   ^= bitfliph;\n        /*\n         * Add the high 32 bits of input_hi to the high 32 bits of m128, then\n         * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to\n         * the high 64 bits of m128.\n         *\n         * The best approach to this operation is different on 32-bit and 64-bit.\n         */\n        if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */\n            /*\n             * 32-bit optimized version, which is more readable.\n             *\n             * On 32-bit, it removes an ADC and delays a dependency between the two\n             * halves of m128.high64, but it generates an extra mask on 64-bit.\n             */\n            m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2);\n        } else {\n            /*\n             * 64-bit optimized (albeit more confusing) version.\n             *\n             * Uses some properties of addition and multiplication to remove the mask:\n             *\n             * Let:\n             *    a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF)\n             *    b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000)\n             *    c = XXH_PRIME32_2\n             *\n             *    a + (b * c)\n             * Inverse Property: x + y - x == y\n             *    a + (b * (1 + c - 1))\n             * Distributive Property: x * (y + z) == (x * y) + (x * z)\n             *    a + (b * 1) + (b * (c - 1))\n             * Identity Property: x * 1 == x\n             *    a + b + (b * (c - 1))\n             *\n             * Substitute a, b, and c:\n             *    input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))\n             *\n             * Since input_hi.hi + input_hi.lo == input_hi, we get this:\n             *    input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))\n             */\n            m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1);\n        }\n        /* m128 ^= XXH_swap64(m128 >> 64); */\n        m128.low64  ^= XXH_swap64(m128.high64);\n\n        {   /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */\n            XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2);\n            h128.high64 += m128.high64 * XXH_PRIME64_2;\n\n            h128.low64   = XXH3_avalanche(h128.low64);\n            h128.high64  = XXH3_avalanche(h128.high64);\n            return h128;\n    }   }\n}\n\n/*\n * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN\n */\nXXH_FORCE_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)\n{\n    XXH_ASSERT(len <= 16);\n    {   if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed);\n        if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed);\n        if (len) return XXH3_len_1to3_128b(input, len, secret, seed);\n        {   XXH128_hash_t h128;\n            xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72);\n            xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88);\n            h128.low64 = XXH64_avalanche(seed ^ bitflipl);\n            h128.high64 = XXH64_avalanche( seed ^ bitfliph);\n            return h128;\n    }   }\n}\n\n/*\n * A bit slower than XXH3_mix16B, but handles multiply by zero better.\n */\nXXH_FORCE_INLINE XXH128_hash_t\nXXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2,\n              const xxh_u8* secret, XXH64_hash_t seed)\n{\n    acc.low64  += XXH3_mix16B (input_1, secret+0, seed);\n    acc.low64  ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8);\n    acc.high64 += XXH3_mix16B (input_2, secret+16, seed);\n    acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8);\n    return acc;\n}\n\n\nXXH_FORCE_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,\n                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                      XXH64_hash_t seed)\n{\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;\n    XXH_ASSERT(16 < len && len <= 128);\n\n    {   XXH128_hash_t acc;\n        acc.low64 = len * XXH_PRIME64_1;\n        acc.high64 = 0;\n\n#if XXH_SIZE_OPT >= 1\n        {\n            /* Smaller, but slightly slower. */\n            unsigned int i = (unsigned int)(len - 1) / 32;\n            do {\n                acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed);\n            } while (i-- != 0);\n        }\n#else\n        if (len > 32) {\n            if (len > 64) {\n                if (len > 96) {\n                    acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed);\n                }\n                acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed);\n            }\n            acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed);\n        }\n        acc = XXH128_mix32B(acc, input, input+len-16, secret, seed);\n#endif\n        {   XXH128_hash_t h128;\n            h128.low64  = acc.low64 + acc.high64;\n            h128.high64 = (acc.low64    * XXH_PRIME64_1)\n                        + (acc.high64   * XXH_PRIME64_4)\n                        + ((len - seed) * XXH_PRIME64_2);\n            h128.low64  = XXH3_avalanche(h128.low64);\n            h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);\n            return h128;\n        }\n    }\n}\n\nXXH_NO_INLINE XXH_PUREF XXH128_hash_t\nXXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,\n                       const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                       XXH64_hash_t seed)\n{\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;\n    XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);\n\n    {   XXH128_hash_t acc;\n        unsigned i;\n        acc.low64 = len * XXH_PRIME64_1;\n        acc.high64 = 0;\n        /*\n         *  We set as `i` as offset + 32. We do this so that unchanged\n         * `len` can be used as upper bound. This reaches a sweet spot\n         * where both x86 and aarch64 get simple agen and good codegen\n         * for the loop.\n         */\n        for (i = 32; i < 160; i += 32) {\n            acc = XXH128_mix32B(acc,\n                                input  + i - 32,\n                                input  + i - 16,\n                                secret + i - 32,\n                                seed);\n        }\n        acc.low64 = XXH3_avalanche(acc.low64);\n        acc.high64 = XXH3_avalanche(acc.high64);\n        /*\n         * NB: `i <= len` will duplicate the last 32-bytes if\n         * len % 32 was zero. This is an unfortunate necessity to keep\n         * the hash result stable.\n         */\n        for (i=160; i <= len; i += 32) {\n            acc = XXH128_mix32B(acc,\n                                input + i - 32,\n                                input + i - 16,\n                                secret + XXH3_MIDSIZE_STARTOFFSET + i - 160,\n                                seed);\n        }\n        /* last bytes */\n        acc = XXH128_mix32B(acc,\n                            input + len - 16,\n                            input + len - 32,\n                            secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,\n                            (XXH64_hash_t)0 - seed);\n\n        {   XXH128_hash_t h128;\n            h128.low64  = acc.low64 + acc.high64;\n            h128.high64 = (acc.low64    * XXH_PRIME64_1)\n                        + (acc.high64   * XXH_PRIME64_4)\n                        + ((len - seed) * XXH_PRIME64_2);\n            h128.low64  = XXH3_avalanche(h128.low64);\n            h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);\n            return h128;\n        }\n    }\n}\n\nstatic XXH_PUREF XXH128_hash_t\nXXH3_finalizeLong_128b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, xxh_u64 len)\n{\n    XXH128_hash_t h128;\n    h128.low64 = XXH3_finalizeLong_64b(acc, secret, len);\n    h128.high64 = XXH3_mergeAccs(acc, secret + secretSize\n                                             - XXH_STRIPE_LEN - XXH_SECRET_MERGEACCS_START,\n                                             ~(len * XXH_PRIME64_2));\n    return h128;\n}\n\nXXH_FORCE_INLINE XXH128_hash_t\nXXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,\n                            const xxh_u8* XXH_RESTRICT secret, size_t secretSize,\n                            XXH3_f_accumulate f_acc,\n                            XXH3_f_scrambleAcc f_scramble)\n{\n    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;\n\n    XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble);\n\n    /* converge into final hash */\n    XXH_STATIC_ASSERT(sizeof(acc) == 64);\n    XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);\n    return XXH3_finalizeLong_128b(acc, secret, secretSize, (xxh_u64)len);\n}\n\n/*\n * It's important for performance that XXH3_hashLong() is not inlined.\n */\nXXH_NO_INLINE XXH_PUREF XXH128_hash_t\nXXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len,\n                           XXH64_hash_t seed64,\n                           const void* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)seed64; (void)secret; (void)secretLen;\n    return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret),\n                                       XXH3_accumulate, XXH3_scrambleAcc);\n}\n\n/*\n * It's important for performance to pass @p secretLen (when it's static)\n * to the compiler, so that it can properly optimize the vectorized loop.\n *\n * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE\n * breaks -Og, this is XXH_NO_INLINE.\n */\nXXH3_WITH_SECRET_INLINE XXH128_hash_t\nXXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len,\n                              XXH64_hash_t seed64,\n                              const void* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)seed64;\n    return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen,\n                                       XXH3_accumulate, XXH3_scrambleAcc);\n}\n\nXXH_FORCE_INLINE XXH128_hash_t\nXXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len,\n                                XXH64_hash_t seed64,\n                                XXH3_f_accumulate f_acc,\n                                XXH3_f_scrambleAcc f_scramble,\n                                XXH3_f_initCustomSecret f_initSec)\n{\n    if (seed64 == 0)\n        return XXH3_hashLong_128b_internal(input, len,\n                                           XXH3_kSecret, sizeof(XXH3_kSecret),\n                                           f_acc, f_scramble);\n    {   XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];\n        f_initSec(secret, seed64);\n        return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret),\n                                           f_acc, f_scramble);\n    }\n}\n\n/*\n * It's important for performance that XXH3_hashLong is not inlined.\n */\nXXH_NO_INLINE XXH128_hash_t\nXXH3_hashLong_128b_withSeed(const void* input, size_t len,\n                            XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen)\n{\n    (void)secret; (void)secretLen;\n    return XXH3_hashLong_128b_withSeed_internal(input, len, seed64,\n                XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);\n}\n\ntypedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t,\n                                            XXH64_hash_t, const void* XXH_RESTRICT, size_t);\n\nXXH_FORCE_INLINE XXH128_hash_t\nXXH3_128bits_internal(const void* input, size_t len,\n                      XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,\n                      XXH3_hashLong128_f f_hl128)\n{\n    XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);\n    /*\n     * If an action is to be taken if `secret` conditions are not respected,\n     * it should be done here.\n     * For now, it's a contract pre-condition.\n     * Adding a check and a branch here would cost performance at every hash.\n     */\n    if (len <= 16)\n        return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);\n    if (len <= 128)\n        return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);\n    if (len <= XXH3_MIDSIZE_MAX)\n        return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);\n    return f_hl128(input, len, seed64, secret, secretLen);\n}\n\n\n/* ===   Public XXH128 API   === */\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len)\n{\n    return XXH3_128bits_internal(input, len, 0,\n                                 XXH3_kSecret, sizeof(XXH3_kSecret),\n                                 XXH3_hashLong_128b_default);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t\nXXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize)\n{\n    return XXH3_128bits_internal(input, len, 0,\n                                 (const xxh_u8*)secret, secretSize,\n                                 XXH3_hashLong_128b_withSecret);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t\nXXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)\n{\n    return XXH3_128bits_internal(input, len, seed,\n                                 XXH3_kSecret, sizeof(XXH3_kSecret),\n                                 XXH3_hashLong_128b_withSeed);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t\nXXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)\n{\n    if (len <= XXH3_MIDSIZE_MAX)\n        return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);\n    return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t\nXXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)\n{\n    return XXH3_128bits_withSeed(input, len, seed);\n}\n\n\n/* ===   XXH3 128-bit streaming   === */\n#ifndef XXH_NO_STREAM\n/*\n * All initialization and update functions are identical to 64-bit streaming variant.\n * The only difference is the finalization routine.\n */\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)\n{\n    return XXH3_64bits_reset(statePtr);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)\n{\n    return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)\n{\n    return XXH3_64bits_reset_withSeed(statePtr, seed);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)\n{\n    return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)\n{\n    return XXH3_update_regular(state, input, len);\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state)\n{\n    const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;\n    if (state->totalLen > XXH3_MIDSIZE_MAX) {\n        XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];\n        XXH3_digest_long(acc, state, secret);\n        XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);\n        return XXH3_finalizeLong_128b(acc, secret, state->secretLimit + XXH_STRIPE_LEN,  (xxh_u64)state->totalLen);\n    }\n    /* len <= XXH3_MIDSIZE_MAX : short code */\n    if (state->useSeed)\n        return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);\n    return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),\n                                   secret, state->secretLimit + XXH_STRIPE_LEN);\n}\n#endif /* !XXH_NO_STREAM */\n/* 128-bit utility functions */\n\n/* return : 1 is equal, 0 if different */\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)\n{\n    /* note : XXH128_hash_t is compact, it has no padding byte */\n    return !(XXH_memcmp(&h1, &h2, sizeof(h1)));\n}\n\n/* This prototype is compatible with stdlib's qsort().\n * @return : >0 if *h128_1  > *h128_2\n *           <0 if *h128_1  < *h128_2\n *           =0 if *h128_1 == *h128_2  */\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2)\n{\n    XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1;\n    XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2;\n    int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64);\n    /* note : bets that, in most cases, hash values are different */\n    if (hcmp) return hcmp;\n    return (h1.low64 > h2.low64) - (h2.low64 > h1.low64);\n}\n\n\n/*======   Canonical representation   ======*/\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API void\nXXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash)\n{\n    XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));\n    if (XXH_CPU_LITTLE_ENDIAN) {\n        hash.high64 = XXH_swap64(hash.high64);\n        hash.low64  = XXH_swap64(hash.low64);\n    }\n    XXH_memcpy(dst, &hash.high64, sizeof(hash.high64));\n    XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH128_hash_t\nXXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src)\n{\n    XXH128_hash_t h;\n    h.high64 = XXH_readBE64(src);\n    h.low64  = XXH_readBE64(src->digest + 8);\n    return h;\n}\n\n\n\n/* ==========================================\n * Secret generators\n * ==========================================\n */\n#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))\n\nXXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128)\n{\n    XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 );\n    XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 );\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API XXH_errorcode\nXXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize)\n{\n#if (XXH_DEBUGLEVEL >= 1)\n    XXH_ASSERT(secretBuffer != NULL);\n    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);\n#else\n    /* production mode, assert() are disabled */\n    if (secretBuffer == NULL) return XXH_ERROR;\n    if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;\n#endif\n\n    if (customSeedSize == 0) {\n        customSeed = XXH3_kSecret;\n        customSeedSize = XXH_SECRET_DEFAULT_SIZE;\n    }\n#if (XXH_DEBUGLEVEL >= 1)\n    XXH_ASSERT(customSeed != NULL);\n#else\n    if (customSeed == NULL) return XXH_ERROR;\n#endif\n\n    /* Fill secretBuffer with a copy of customSeed - repeat as needed */\n    {   size_t pos = 0;\n        while (pos < secretSize) {\n            size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize);\n            XXH_memcpy((char*)secretBuffer + pos, customSeed, toCopy);\n            pos += toCopy;\n    }   }\n\n    {   size_t const nbSeg16 = secretSize / 16;\n        size_t n;\n        XXH128_canonical_t scrambler;\n        XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0));\n        for (n=0; n<nbSeg16; n++) {\n            XXH128_hash_t const h128 = XXH128(&scrambler, sizeof(scrambler), n);\n            XXH3_combine16((char*)secretBuffer + n*16, h128);\n        }\n        /* last segment */\n        XXH3_combine16((char*)secretBuffer + secretSize - 16, XXH128_hashFromCanonical(&scrambler));\n    }\n    return XXH_OK;\n}\n\n/*! @ingroup XXH3_family */\nXXH_PUBLIC_API void\nXXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed)\n{\n    XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];\n    XXH3_initCustomSecret(secret, seed);\n    XXH_ASSERT(secretBuffer != NULL);\n    XXH_memcpy(secretBuffer, secret, XXH_SECRET_DEFAULT_SIZE);\n}\n\n\n\n/* Pop our optimization override from above */\n#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \\\n  && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \\\n  && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */\n#  pragma GCC pop_options\n#endif\n\n#endif  /* XXH_NO_LONG_LONG */\n\n#endif  /* XXH_NO_XXH3 */\n\n/*!\n * @}\n */\n#endif  /* XXH_IMPLEMENTATION */\n\n\n#if defined (__cplusplus) && !defined(XXH_NO_EXTERNC_GUARD)\n} /* extern \"C\" */\n#endif\n"
  },
  {
    "path": "core/xmake.lua",
    "content": "set_project(\"xmake\")\nset_xmakever(\"3.0.5\")\nset_policy(\"build.progress_style\", \"multirow\")\nset_version(\"3.0.7\", {build = \"%Y%m%d\"})\n\n-- set all warnings as errors\nset_warnings(\"all\", \"error\")\n\n-- set language: c99, c++11\nset_languages(\"c99\", \"cxx11\")\n\n-- add release and debug modes\nadd_rules(\"mode.release\", \"mode.debug\")\nif is_mode(\"release\") then\n    set_optimize(\"smallest\")\n    if is_plat(\"windows\") then\n        add_ldflags(\"/LTCG\")\n    end\nend\n\n-- disable some compiler errors\nadd_cxflags(\"-Wno-error=deprecated-declarations\", \"-fno-strict-aliasing\", \"-Wno-error=nullability-completeness\", \"-Wno-error=parentheses-equality\")\n\n-- add definitions\nadd_defines(\"_GNU_SOURCE=1\", \"_FILE_OFFSET_BITS=64\", \"_LARGEFILE_SOURCE\")\n\n-- ensure POSIX/XOPEN features are available on Solaris (for setenv, unsetenv, clock_gettime, etc.)\n-- _XOPEN_SOURCE=600 implicitly sets _POSIX_C_SOURCE=200112L\nif is_plat(\"solaris\") then\n    add_defines(\"_XOPEN_SOURCE=600\")\nend\n\n-- add vectorexts\n--[[\nif is_arch(\"x86\", \"x64\", \"i386\", \"x86_64\") then\n    add_vectorexts(\"sse\", \"sse2\", \"sse3\", \"avx\", \"avx2\")\nelseif is_arch(\"arm.*\") then\n    add_vectorexts(\"neon\")\nend]]\n\n-- for the windows platform (msvc)\nif is_plat(\"windows\") then\n    set_runtimes(\"MT\")\n    add_links(\"kernel32\", \"user32\", \"gdi32\", \"wintrust\", \"crypt32\")\nend\n\n-- for mode coverage\nif is_mode(\"coverage\") then\n    add_ldflags(\"-coverage\", \"-fprofile-arcs\", \"-ftest-coverage\")\nend\n\n-- set cosmocc toolchain, e.g. xmake f -p linux --cosmocc=y\nif has_config(\"cosmocc\") then\n    add_requires(\"cosmocc\")\n    set_toolchains(\"@cosmocc\")\n    set_policy(\"build.ccache\", false)\nend\n\n-- use cosmocc toolchain\noption(\"cosmocc\", {default = false, description = \"Use cosmocc toolchain to build once and run anywhere.\"})\n\n-- embed all script files\noption(\"embed\", {default = false, description = \"Embed all script files.\"})\n\n-- the runtime option\noption(\"runtime\")\n    set_default(\"lua\")\n    set_description(\"Use luajit or lua runtime\")\n    set_values(\"luajit\", \"lua\")\noption_end()\n\n-- the lua-cjson option\noption(\"lua_cjson\")\n    set_default(true)\n    set_description(\"Use lua-cjson as json parser\")\noption_end()\n\n-- the readline option\noption(\"readline\")\n    set_description(\"Enable or disable readline library\")\n    add_links(\"readline\")\n    add_cincludes(\"stdio.h\", \"readline/readline.h\")\n    add_cfuncs(\"readline\")\n    add_defines(\"XM_CONFIG_API_HAVE_READLINE\")\n    add_deps(\"cosmocc\")\n    after_check(function (option)\n        if option:dep(\"cosmocc\"):enabled() then\n            option:enable(false)\n        end\n    end)\noption_end()\n\n-- the curses option\noption(\"curses\")\n    set_description(\"Enable or disable curses library\")\n    add_defines(\"XM_CONFIG_API_HAVE_CURSES\")\n    add_deps(\"cosmocc\")\n    before_check(function (option)\n        if is_plat(\"mingw\") then\n            option:add(\"cincludes\", \"ncursesw/curses.h\")\n            option:add(\"links\", \"ncursesw\")\n        else\n            option:add(\"cincludes\", \"curses.h\")\n            option:add(\"links\", \"curses\")\n        end\n    end)\n    after_check(function (option)\n        if option:dep(\"cosmocc\"):enabled() or is_plat(\"solaris\") then\n            option:enable(false)\n        end\n    end)\noption_end()\n\n-- the pdcurses option\noption(\"pdcurses\")\n    set_default(true)\n    set_description(\"Enable or disable pdcurses library\")\n    add_defines(\"PDCURSES\")\n    add_defines(\"XM_CONFIG_API_HAVE_CURSES\")\noption_end()\n\n-- only build xmake libraries for development?\noption(\"onlylib\")\n    set_default(false)\n    set_description(\"Only build xmake libraries for development\")\noption_end()\n\n-- suppress warnings\nif is_plat(\"windows\") then\n    add_defines(\"_CRT_SECURE_NO_WARNINGS\")\n    add_cxflags(\"/utf-8\")\nend\n\n-- add projects\nincludes(\"src/sv\", \"src/lz4\", \"src/xmake\", \"src/cli\")\nif namespace then\n    namespace(\"tbox\", function ()\n        includes(\"src/tbox\")\n    end)\nelse\n    includes(\"src/tbox\")\nend\nif has_config(\"lua_cjson\") then\n    includes(\"src/lua-cjson\")\nend\nif is_config(\"runtime\", \"luajit\") then\n    includes(\"src/luajit\")\nelse\n    includes(\"src/lua\")\nend\nif is_plat(\"windows\") then\n    includes(\"src/pdcurses\")\nend\n\n-- add xpack\nincludes(\"@builtin/xpack\")\nif xpack then\n    includes(\"xpack.lua\")\nend\n"
  },
  {
    "path": "core/xmake.sh",
    "content": "#!/bin/sh\n\nset_project \"xmake\"\nset_version \"3.0.7\" \"%Y%m%d\"\n\n# set warning all\nset_warnings \"all\"\n\n# set language: c99\nset_languages \"c99\"\n\n# add definitions\nadd_defines \"_GNU_SOURCE=1\"  \"_FILE_OFFSET_BITS=64\"  \"_LARGEFILE_SOURCE\"\n\n# ensure POSIX/XOPEN features are available on Solaris (for setenv, unsetenv, clock_gettime, etc.)\n# _XOPEN_SOURCE=600 implicitly sets _POSIX_C_SOURCE=200112L\nif is_plat \"solaris\"; then\n    add_defines \"_XOPEN_SOURCE=600\"\nfi\n\n# disable some compiler errors\nif is_plat \"macosx\"; then\n    add_cxflags \"-Wno-error=deprecated-declarations\" \"-fno-strict-aliasing\" \"-Wno-error=nullability-completeness\" \"-Wno-error=parentheses-equality\"\nfi\n\n# add build modes\nif is_mode \"debug\"; then\n    set_symbols \"debug\"\n    set_optimizes \"none\"\nelse\n    set_strip \"all\"\n    if ! is_kind \"shared\"; then\n        set_symbols \"hidden\"\n    fi\n    set_optimizes \"smallest\"\nfi\n\n# the runtime option, lua or luajit\noption \"runtime\" \"Use luajit or lua runtime\" \"lua\"\n\n# always use external dependencies\noption \"external\" \"Always use external dependencies\" false\n\n# the readline option\noption \"readline\"\n    add_links \"readline\"\n    add_cincludes \"stdio.h\" \"readline/readline.h\"\n    add_cfuncs \"readline\"\n    add_defines \"XM_CONFIG_API_HAVE_READLINE\"\noption_end\n\n# the curses option\noption \"curses\"\n    add_cfuncs \"initscr\"\n    add_cincludes \"curses.h\"\n    before_check \"option_find_curses\"\n    add_defines \"XM_CONFIG_API_HAVE_CURSES\"\n    if is_host \"solaris\"; then\n        set_default \"false\"\n    fi\noption_end\n\noption_find_curses() {\n    local ncurses=\"ncurses\"\n    if is_plat \"mingw\"; then\n        ncurses=\"ncursesw\"\n    fi\n    local ncurses_ldflags=\"\"\n    ncurses_ldflags=$(pkg-config --libs ${ncurses} 2>/dev/null)\n    option \"curses\"\n        if test_nz \"${ncurses_ldflags}\"; then\n            add_cflags `pkg-config --cflags ${ncurses} 2>/dev/null`\n            add_ldflags \"${ncurses_ldflags}\"\n        else\n            add_links \"curses\"\n        fi\n    option_end\n}\n\n# the atomic option\n# @note some systems need link atomic, e.g. raspberrypi\noption \"atomic\"\n    add_links \"atomic\"\n    add_csnippets \"\nvoid test() {\\n\n    int v;\\n\n    __atomic_load(&v,&v,0);\\n\n}\"\noption_end\n\n# the lua option\noption \"lua\"\n    add_cfuncs \"lua_pushstring\"\n    add_cincludes \"lua.h\" \"lualib.h\" \"lauxlib.h\"\n    add_defines \"LUA_COMPAT_5_1\" \"LUA_COMPAT_5_2\" \"LUA_COMPAT_5_3\"\n    before_check \"option_find_lua\"\noption_end\n\noption_find_lua() {\n    local ldflags=\"\"\n    local cflags=\"\"\n    option \"lua\"\n        # detect lua5.4 on debian\n        cflags=`pkg-config --cflags lua5.4 2>/dev/null`\n        ldflags=`pkg-config --libs lua5.4 2>/dev/null`\n        # detect it on fedora\n        if test_z \"${cflags}\"; then\n            cflags=`pkg-config --cflags lua 2>/dev/null`\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=`pkg-config --libs lua 2>/dev/null`\n        fi\n        if test_z \"${cflags}\"; then\n            cflags=\"-I/usr/include/lua5.4\"\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=\"-llua5.4\"\n        fi\n        add_cflags \"${cflags}\"\n        add_ldflags \"${ldflags}\"\n    option_end\n}\n\n# the luajit option\noption \"luajit\"\n    add_cfuncs \"lua_pushstring\"\n    add_cincludes \"lua.h\" \"lualib.h\" \"lauxlib.h\"\n    add_defines \"USE_LUAJIT\"\n    before_check \"option_find_luajit\"\noption_end\n\noption_find_luajit() {\n    local ldflags=\"\"\n    local cflags=\"\"\n    option \"luajit\"\n        cflags=`pkg-config --cflags luajit 2>/dev/null`\n        ldflags=`pkg-config --libs luajit 2>/dev/null`\n        if test_z \"${cflags}\"; then\n            cflags=\"-I/usr/include/luajit-2.1\"\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=\"-lluajit\"\n        fi\n        add_cflags \"${cflags}\"\n        add_ldflags \"${ldflags}\"\n    option_end\n}\n\n# the lz4 option\noption \"lz4\"\n    add_cfuncs \"LZ4F_compressFrame\"\n    add_cincludes \"lz4.h\" \"lz4frame.h\"\n    before_check \"option_find_lz4\"\noption_end\n\noption_find_lz4() {\n    local ldflags=\"\"\n    local cflags=\"\"\n    option \"lz4\"\n        cflags=`pkg-config --cflags liblz4 2>/dev/null`\n        ldflags=`pkg-config --libs liblz4 2>/dev/null`\n        if test_z \"${cflags}\"; then\n            cflags=\"-I/usr/include\"\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=\"-llz4\"\n        fi\n        add_cflags \"${cflags}\"\n        add_ldflags \"${ldflags}\"\n    option_end\n}\n\n# the sv option\noption \"sv\"\n    add_cfuncs \"semver_tryn\"\n    add_cincludes \"semver.h\"\n    add_links \"sv\"\n    before_check \"option_find_sv\"\noption_end\n\noption_find_sv() {\n    local ldflags=\"\"\n    local cflags=\"\"\n    option \"sv\"\n        cflags=`pkg-config --cflags libsv 2>/dev/null`\n        ldflags=`pkg-config --libs libsv 2>/dev/null`\n        if test_z \"${cflags}\"; then\n            cflags=\"-I/usr/include\"\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=\"-lsv\"\n        fi\n        add_cflags \"${cflags}\"\n        add_ldflags \"${ldflags}\"\n    option_end\n}\n\n# the tbox option\noption \"tbox\"\n    add_cfuncs \"tb_exit\" \"tb_md5_init\" \"tb_charset_conv_data\"\n    add_cincludes \"tbox/tbox.h\"\n    add_links \"tbox\"\n    before_check \"option_find_tbox\"\noption_end\n\noption_find_tbox() {\n    local ldflags=\"\"\n    local cflags=\"\"\n    option \"tbox\"\n        cflags=`pkg-config --cflags libtbox 2>/dev/null`\n        ldflags=`pkg-config --libs libtbox 2>/dev/null`\n        if test_z \"${cflags}\"; then\n            cflags=\"-I/usr/include\"\n        fi\n        if test_z \"${ldflags}\"; then\n            ldflags=\"-ltbox\"\n        fi\n        add_cflags \"${cflags}\"\n        add_ldflags \"${ldflags}\"\n        # ubuntu armv7/armel maybe need it\n        if is_plat \"linux\" && is_arch \"armv7\" \"arm\"; then\n            add_ldflags \"-latomic\"\n        fi\n    option_end\n}\n\n# add projects\nif ! has_config \"external\"; then\n    if is_config \"runtime\" \"luajit\"; then\n        includes \"src/luajit\"\n    else\n        includes \"src/lua\"\n    fi\n    includes \"src/lua-cjson\"\n    includes \"src/lz4\"\n    includes \"src/sv\"\n    includes \"src/tbox\"\nfi\nincludes \"src/xmake\"\nincludes \"src/cli\"\n"
  },
  {
    "path": "core/xpack.lua",
    "content": "xpack(\"xmake\")\n    set_homepage(\"https://xmake.io\")\n    set_title(\"Xmake build utility ($(arch))\")\n    set_description(\"A cross-platform build utility based on Lua.\")\n    set_copyright(\"Copyright (C) 2015-present, Xmake Open Source Community\")\n    set_author(\"ruki <waruqi@gmail.com>\")\n    set_licensefile(\"../LICENSE.md\")\n    set_formats(\"nsis\", \"wix\", \"zip\")\n    add_targets(\"cli\")\n    set_bindir(\".\")\n    set_iconfile(\"src/cli/xmake.ico\")\n\n    add_components(\"LongPath\")\n\n    on_load(function (package)\n        local arch = package:arch()\n        if package:is_plat(\"windows\") then\n            if arch == \"x64\" then\n                arch = \"win64\"\n            elseif arch == \"x86\" then\n                arch = \"win32\"\n            end\n        end\n        package:set(\"basename\", \"xmake-v$(version).\" .. arch)\n        local format = package:format()\n        if format == \"zip\" then\n            package:set(\"prefixdir\", \"xmake\")\n        end\n    end)\n\n    before_package(function (package)\n        import(\"net.http\")\n        import(\"utils.archive\")\n        import(\"core.base.global\")\n        local format = package:format()\n        if package:is_plat(\"windows\") and (format == \"nsis\" or format == \"wix\" or format == \"zip\") then\n            local winenv = path.join(os.programdir(), \"winenv\")\n            if false then -- os.isdir(winenv) then\n                package:add(\"installfiles\", path.join(winenv, \"**\"), {rootdir = path.directory(winenv)})\n            else\n                local arch = package:arch()\n                local url_7z = \"https://github.com/xmake-mirror/7zip/releases/download/24.08/7z24.08-\" .. arch .. \".zip\"\n                local curl_version = \"8.11.0_4\"\n                local url_curl = \"https://curl.se/windows/dl-\" .. curl_version .. \"/curl-\" .. curl_version\n                if package:is_arch(\"x64\", \"x86_64\") then\n                    url_curl = url_curl .. \"-win64-mingw.zip\"\n                elseif package:is_arch(\"arm64\") then\n                    url_curl = url_curl .. \"-win64a-mingw.zip\"\n                else\n                    url_curl = url_curl .. \"-win32-mingw.zip\"\n                end\n                local archive_7z = path.join(package:builddir(), \"7z.zip\")\n                local archive_curl = path.join(package:builddir(), \"curl.zip\")\n                local tmpdir_7z = path.join(package:builddir(), \"7z\")\n                local tmpdir_curl = path.join(package:builddir(), \"curl\")\n                local winenv_bindir = path.join(package:builddir(), \"winenv\", \"bin\")\n                os.mkdir(winenv_bindir)\n                http.download(url_7z, archive_7z, {insecure = global.get(\"insecure-ssl\")})\n                archive.extract(archive_7z, tmpdir_7z)\n                os.cp(path.join(tmpdir_7z, \"*\"), winenv_bindir)\n                http.download(url_curl, archive_curl, {insecure = global.get(\"insecure-ssl\")})\n                archive.extract(archive_curl, tmpdir_curl)\n                os.cp(path.join(tmpdir_curl, \"*\", \"bin\", \"*.exe\"), winenv_bindir)\n                os.cp(path.join(tmpdir_curl, \"*\", \"bin\", \"*.crt\"), winenv_bindir)\n                winenv = path.directory(winenv_bindir)\n                package:add(\"installfiles\", path.join(winenv, \"**\"), {rootdir = path.directory(winenv)})\n            end\n        end\n    end)\n\nxpack_component(\"LongPath\")\n    set_title(\"Enable Long Path\")\n    set_description(\"Increases the maximum path length limit, up to 32,767 characters (before 256).\")\n    on_installcmd(function (component, batchcmds)\n        batchcmds:rawcmd(\"nsis\", [[\n  ${If} $NoAdmin == \"false\"\n    ; Enable long path\n    WriteRegDWORD ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\FileSystem\" \"LongPathsEnabled\" 1\n  ${EndIf}]])\n        batchcmds:rawcmd(\"wix\", [[\n    <RegistryKey Root=\"HKLM\" Key=\"SYSTEM\\CurrentControlSet\\Control\\FileSystem\">\n        <RegistryValue Type=\"integer\" Name=\"LongPathsEnabled\" Value=\"1\" KeyPath=\"yes\"/>\n    </RegistryKey>\n        ]])\n    end)\n\nxpack(\"xmakesrc\")\n    set_homepage(\"https://xmake.io\")\n    set_title(\"Xmake build utility ($(arch))\")\n    set_description(\"A cross-platform build utility based on Lua.\")\n    set_copyright(\"Copyright (C) 2015-present, Xmake Open Source Community\")\n    set_author(\"ruki <waruqi@gmail.com>\")\n    set_formats(\"srczip\", \"srctargz\", \"runself\", \"srpm\", \"deb\")\n    set_basename(\"xmake-v$(version)\")\n    set_prefixdir(\"xmake-$(version)\")\n    set_license(\"Apache-2.0\")\n    before_package(function (package)\n        import(\"devel.git\")\n\n        local rootdir = path.join(os.tmpfile(package:basename() .. \"_\" .. package:format()) .. \".dir\", \"repo\")\n        if not os.isdir(rootdir) then\n            os.tryrm(rootdir)\n            os.cp(path.directory(os.projectdir()), rootdir)\n\n            git.clean({repodir = rootdir, force = true, all = true})\n            git.reset({repodir = rootdir, hard = true})\n            if os.isfile(path.join(rootdir, \".gitmodules\")) then\n                git.submodule.clean({repodir = rootdir, force = true, all = true})\n                git.submodule.reset({repodir = rootdir, hard = true})\n            end\n        end\n\n        local extraconf = {rootdir = rootdir}\n        package:add(\"sourcefiles\", path.join(rootdir, \"core/**|src/pdcurses/**|src/luajit/**|src/tbox/tbox/src/demo/**\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"xmake/**|scripts/vsxmake/**\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"*.md\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"configure\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"scripts/*.sh\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"scripts/man/**\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"scripts/debian/**\"), extraconf)\n        package:add(\"sourcefiles\", path.join(rootdir, \"scripts/msys/**\"), extraconf)\n    end)\n\n    on_buildcmd(function (package, batchcmds)\n        local format = package:format()\n        if format == \"srpm\" or format == \"deb\" then\n            batchcmds:runv(\"./configure\")\n            batchcmds:runv(\"make\", {\"-j4\"})\n        end\n    end)\n\n    on_installcmd(function (package, batchcmds)\n        local format = package:format()\n        if format == \"runself\" then\n            batchcmds:runv(\"./scripts/get.sh\", {\"__local__\"})\n        elseif format == \"srpm\" or format == \"deb\" then\n            batchcmds:runv(\"make\", {\"install\", path(package:install_rootdir(), function (p) return \"PREFIX=\" .. p end)})\n        end\n    end)\n"
  },
  {
    "path": "scripts/debian/README.Debian",
    "content": "xmake for Debian\n---------------\n\n<possible notes regarding this package - if none, delete this file>\n\n -- ruki <waruqi@gmail.com>  Thu, 06 Apr 2017 21:22:12 +0800\n"
  },
  {
    "path": "scripts/debian/README.source",
    "content": "xmake for Debian\n---------------\n\n<this file describes information about the source package, see Debian policy\nmanual section 4.14. You WILL either need to modify or delete this file>\n\n\n\n -- ruki <waruqi@gmail.com>  Thu, 06 Apr 2017 21:22:12 +0800\n\n"
  },
  {
    "path": "scripts/debian/changelog",
    "content": "xmake (2.3.6+2) xenial; urgency=medium\n\n  * update 2.3.6\n\n -- ruki <waruqi@gmail.com>  Thu, 05 Aug 2020 21:22:12 +0800\n"
  },
  {
    "path": "scripts/debian/compat",
    "content": "9\n"
  },
  {
    "path": "scripts/debian/control",
    "content": "Source: xmake\nSection: contrib/devel\nPriority: optional\nMaintainer: ruki <waruqi@gmail.com>\nBuild-Depends: debhelper (>=9)\nStandards-Version: 3.9.7\nHomepage: http://xmake.io\n#Vcs-Git: git@github.com:xmake-io/xmake.git\n#Vcs-Browser: https://github.com/xmake-io/xmake.git\n\nPackage: xmake\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}\nDescription: A cross-platform build utility based on Lua\n xmake is a lightweight cross-platform build utility based on Lua. \n It uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt, \n the configuration syntax is more concise and intuitive. \n It is very friendly to novices and can quickly get started in a short time. \n Let users focus more on actual project development.\n\n \n"
  },
  {
    "path": "scripts/debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: xmake\nSource: https://github.com/xmake-io/xmake\n\nFiles: *\nCopyright: 2015-present ruki <waruqi@gmail.com>\nLicense: Apache-2.0\n .\n\n# Please also look if there are files or directories which have a\n# different copyright/license attached and list them here.\n# Please avoid picking licenses with terms that are more restrictive than the\n# packaged work, as it may make Debian's contributions unacceptable upstream.\n"
  },
  {
    "path": "scripts/debian/init.d.ex",
    "content": "#!/bin/sh\n# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.\nif [ true != \"$INIT_D_SCRIPT_SOURCED\" ] ; then\n    set \"$0\" \"$@\"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script\nfi\n### BEGIN INIT INFO\n# Provides:          xmake\n# Required-Start:    $remote_fs $syslog\n# Required-Stop:     $remote_fs $syslog\n# Default-Start:     2 3 4 5\n# Default-Stop:      0 1 6\n# Short-Description: <Enter a short description of the software>\n# Description:       <Enter a long description of the software>\n#                    <...>\n#                    <...>\n### END INIT INFO\n\n# Author: ruki <waruqi@gmail.com>\n\nDESC=\"xmake\"\nDAEMON=/usr/bin/xmake\n\n# This is an example to start a single forking daemon capable of writing\n# a pid file. To get other behaviors, implement do_start(), do_stop() or\n# other functions to override the defaults in /lib/init/init-d-script.\n# See also init-d-script(5)\n"
  },
  {
    "path": "scripts/debian/manpage.1.ex",
    "content": ".\\\"                                      Hey, EMACS: -*- nroff -*-\n.\\\" (C) Copyright 2017 ruki <waruqi@gmail.com>,\n.\\\"\n.\\\" First parameter, NAME, should be all caps\n.\\\" Second parameter, SECTION, should be 1-8, maybe w/ subsection\n.\\\" other parameters are allowed: see man(7), man(1)\n.TH Xmake SECTION \"April  6 2017\"\n.\\\" Please adjust this date whenever revising the manpage.\n.\\\"\n.\\\" Some roff macros, for reference:\n.\\\" .nh        disable hyphenation\n.\\\" .hy        enable hyphenation\n.\\\" .ad l      left justify\n.\\\" .ad b      justify to both left and right margins\n.\\\" .nf        disable filling\n.\\\" .fi        enable filling\n.\\\" .br        insert line break\n.\\\" .sp <n>    insert n+1 empty lines\n.\\\" for manpage-specific macros, see man(7)\n.SH NAME\nxmake \\- program to do something\n.SH SYNOPSIS\n.B xmake\n.RI [ options ] \" files\" ...\n.br\n.B bar\n.RI [ options ] \" files\" ...\n.SH DESCRIPTION\nThis manual page documents briefly the\n.B xmake\nand\n.B bar\ncommands.\n.PP\n.\\\" TeX users may be more comfortable with the \\fB<whatever>\\fP and\n.\\\" \\fI<whatever>\\fP escape sequences to invode bold face and italics,\n.\\\" respectively.\n\\fBxmake\\fP is a program that...\n.SH OPTIONS\nThese programs follow the usual GNU command line syntax, with long\noptions starting with two dashes (`-').\nA summary of options is included below.\nFor a complete description, see the Info files.\n.TP\n.B \\-h, \\-\\-help\nShow summary of options.\n.TP\n.B \\-v, \\-\\-version\nShow version of program.\n.SH SEE ALSO\n.BR bar (1),\n.BR baz (1).\n.br\nThe programs are documented fully by\n.IR \"The Rise and Fall of a Fooish Bar\" ,\navailable via the Info system.\n"
  },
  {
    "path": "scripts/debian/manpage.sgml.ex",
    "content": "<!doctype refentry PUBLIC \"-//OASIS//DTD DocBook V4.1//EN\" [\n\n<!-- Process this file with docbook-to-man to generate an nroff manual\n     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view\n     the manual page with: `docbook-to-man manpage.sgml | nroff -man |\n     less'.  A typical entry in a Makefile or Makefile.am is:\n\nmanpage.1: manpage.sgml\n\tdocbook-to-man $< > $@\n\n\n\tThe docbook-to-man binary is found in the docbook-to-man package.\n\tPlease remember that if you create the nroff version in one of the\n\tdebian/rules file targets (such as build), you will need to include\n\tdocbook-to-man in your Build-Depends control field.\n\n  -->\n\n  <!-- Fill in your name for FIRSTNAME and SURNAME. -->\n  <!ENTITY dhfirstname \"<firstname>FIRSTNAME</firstname>\">\n  <!ENTITY dhsurname   \"<surname>SURNAME</surname>\">\n  <!-- Please adjust the date whenever revising the manpage. -->\n  <!ENTITY dhdate      \"<date>April  6 2017</date>\">\n  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are\n       allowed: see man(7), man(1). -->\n  <!ENTITY dhsection   \"<manvolnum>SECTION</manvolnum>\">\n  <!ENTITY dhemail     \"<email>waruqi@gmail.com</email>\">\n  <!ENTITY dhusername  \"ruki\">\n  <!ENTITY dhucpackage \"<refentrytitle>Xmake</refentrytitle>\">\n  <!ENTITY dhpackage   \"xmake\">\n\n  <!ENTITY debian      \"<productname>Debian</productname>\">\n  <!ENTITY gnu         \"<acronym>GNU</acronym>\">\n  <!ENTITY gpl         \"&gnu; <acronym>GPL</acronym>\">\n]>\n\n<refentry>\n  <refentryinfo>\n    <address>\n      &dhemail;\n    </address>\n    <author>\n      &dhfirstname;\n      &dhsurname;\n    </author>\n    <copyright>\n      <year>2003</year>\n      <holder>&dhusername;</holder>\n    </copyright>\n    &dhdate;\n  </refentryinfo>\n  <refmeta>\n    &dhucpackage;\n\n    &dhsection;\n  </refmeta>\n  <refnamediv>\n    <refname>&dhpackage;</refname>\n\n    <refpurpose>program to do something</refpurpose>\n  </refnamediv>\n  <refsynopsisdiv>\n    <cmdsynopsis>\n      <command>&dhpackage;</command>\n\n      <arg><option>-e <replaceable>this</replaceable></option></arg>\n\n      <arg><option>--example <replaceable>that</replaceable></option></arg>\n    </cmdsynopsis>\n  </refsynopsisdiv>\n  <refsect1>\n    <title>DESCRIPTION</title>\n\n    <para>This manual page documents briefly the\n      <command>&dhpackage;</command> and <command>bar</command>\n      commands.</para>\n\n    <para>This manual page was written for the &debian; distribution\n      because the original program does not have a manual page.\n      Instead, it has documentation in the &gnu;\n      <application>Info</application> format; see below.</para>\n\n    <para><command>&dhpackage;</command> is a program that...</para>\n\n  </refsect1>\n  <refsect1>\n    <title>OPTIONS</title>\n\n    <para>These programs follow the usual &gnu; command line syntax,\n      with long options starting with two dashes (`-').  A summary of\n      options is included below.  For a complete description, see the\n      <application>Info</application> files.</para>\n\n    <variablelist>\n      <varlistentry>\n        <term><option>-h</option>\n          <option>--help</option>\n        </term>\n        <listitem>\n          <para>Show summary of options.</para>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><option>-v</option>\n          <option>--version</option>\n        </term>\n        <listitem>\n          <para>Show version of program.</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n  </refsect1>\n  <refsect1>\n    <title>SEE ALSO</title>\n\n    <para>bar (1), baz (1).</para>\n\n    <para>The programs are documented fully by <citetitle>The Rise and\n      Fall of a Fooish Bar</citetitle> available via the\n      <application>Info</application> system.</para>\n  </refsect1>\n  <refsect1>\n    <title>AUTHOR</title>\n\n    <para>This manual page was written by &dhusername; &dhemail; for\n      the &debian; system (and may be used by others).  Permission is\n      granted to copy, distribute and/or modify this document under\n      the terms of the &gnu; General Public License, Version 2 any\n      later version published by the Free Software Foundation.\n    </para>\n    <para>\n      On Debian systems, the complete text of the GNU General Public\n      License can be found in /usr/share/common-licenses/GPL.\n    </para>\n\n  </refsect1>\n</refentry>\n\n<!-- Keep this comment at the end of the file\nLocal variables:\nmode: sgml\nsgml-omittag:t\nsgml-shorttag:t\nsgml-minimize-attributes:nil\nsgml-always-quote-attributes:t\nsgml-indent-step:2\nsgml-indent-data:t\nsgml-parent-document:nil\nsgml-default-dtd-file:nil\nsgml-exposed-tags:nil\nsgml-local-catalogs:nil\nsgml-local-ecat-files:nil\nEnd:\n-->\n"
  },
  {
    "path": "scripts/debian/manpage.xml.ex",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.5//EN\"\n\"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd\" [\n\n<!--\n\n`xsltproc -''-nonet \\\n          -''-param man.charmap.use.subset \"0\" \\\n          -''-param make.year.ranges \"1\" \\\n          -''-param make.single.year.ranges \"1\" \\\n          /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl \\\n          manpage.xml'\n\nA manual page <package>.<section> will be generated. You may view the\nmanual page with: nroff -man <package>.<section> | less'. A typical entry\nin a Makefile or Makefile.am is:\n\nDB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl\nXP     = xsltproc -''-nonet -''-param man.charmap.use.subset \"0\"\n\nmanpage.1: manpage.xml\n        $(XP) $(DB2MAN) $<\n\nThe xsltproc binary is found in the xsltproc package. The XSL files are in\ndocbook-xsl. A description of the parameters you can use can be found in the\ndocbook-xsl-doc-* packages. Please remember that if you create the nroff\nversion in one of the debian/rules file targets (such as build), you will need\nto include xsltproc and docbook-xsl in your Build-Depends control field.\nAlternatively use the xmlto command/package. That will also automatically\npull in xsltproc and docbook-xsl.\n\nNotes for using docbook2x: docbook2x-man does not automatically create the\nAUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as\n<refsect1> ... </refsect1>.\n\nTo disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections\nread /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be\nfound in the docbook-xsl-doc-html package.\n\nValidation can be done using: `xmllint -''-noout -''-valid manpage.xml`\n\nGeneral documentation about man-pages and man-page-formatting:\nman(1), man(7), http://www.tldp.org/HOWTO/Man-Page/\n\n-->\n\n  <!-- Fill in your name for FIRSTNAME and SURNAME. -->\n  <!ENTITY dhfirstname \"FIRSTNAME\">\n  <!ENTITY dhsurname   \"SURNAME\">\n  <!-- dhusername could also be set to \"&dhfirstname; &dhsurname;\". -->\n  <!ENTITY dhusername  \"ruki\">\n  <!ENTITY dhemail     \"waruqi@gmail.com\">\n  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are\n       allowed: see man(7), man(1) and\n       http://www.tldp.org/HOWTO/Man-Page/q2.html. -->\n  <!ENTITY dhsection   \"SECTION\">\n  <!-- TITLE should be something like \"User commands\" or similar (see\n       http://www.tldp.org/HOWTO/Man-Page/q2.html). -->\n  <!ENTITY dhtitle     \"xmake User Manual\">\n  <!ENTITY dhucpackage \"Xmake\">\n  <!ENTITY dhpackage   \"xmake\">\n]>\n\n<refentry>\n  <refentryinfo>\n    <title>&dhtitle;</title>\n    <productname>&dhpackage;</productname>\n    <authorgroup>\n      <author>\n       <firstname>&dhfirstname;</firstname>\n        <surname>&dhsurname;</surname>\n        <contrib>Wrote this manpage for the Debian system.</contrib>\n        <address>\n          <email>&dhemail;</email>\n        </address>\n      </author>\n    </authorgroup>\n    <copyright>\n      <year>2007</year>\n      <holder>&dhusername;</holder>\n    </copyright>\n    <legalnotice>\n      <para>This manual page was written for the Debian system\n        (and may be used by others).</para>\n      <para>Permission is granted to copy, distribute and/or modify this\n        document under the terms of the GNU General Public License,\n        Version 2 or (at your option) any later version published by\n        the Free Software Foundation.</para>\n      <para>On Debian systems, the complete text of the GNU General Public\n        License can be found in\n        <filename>/usr/share/common-licenses/GPL</filename>.</para>\n    </legalnotice>\n  </refentryinfo>\n  <refmeta>\n    <refentrytitle>&dhucpackage;</refentrytitle>\n    <manvolnum>&dhsection;</manvolnum>\n  </refmeta>\n  <refnamediv>\n    <refname>&dhpackage;</refname>\n    <refpurpose>program to do something</refpurpose>\n  </refnamediv>\n  <refsynopsisdiv>\n    <cmdsynopsis>\n      <command>&dhpackage;</command>\n      <!-- These are several examples, how syntaxes could look -->\n      <arg choice=\"plain\"><option>-e <replaceable>this</replaceable></option></arg>\n      <arg choice=\"opt\"><option>--example=<parameter>that</parameter></option></arg>\n      <arg choice=\"opt\">\n        <group choice=\"req\">\n          <arg choice=\"plain\"><option>-e</option></arg>\n          <arg choice=\"plain\"><option>--example</option></arg>\n        </group>\n        <replaceable class=\"option\">this</replaceable>\n      </arg>\n      <arg choice=\"opt\">\n        <group choice=\"req\">\n          <arg choice=\"plain\"><option>-e</option></arg>\n          <arg choice=\"plain\"><option>--example</option></arg>\n        </group>\n        <group choice=\"req\">\n          <arg choice=\"plain\"><replaceable>this</replaceable></arg>\n          <arg choice=\"plain\"><replaceable>that</replaceable></arg>\n        </group>\n      </arg>\n    </cmdsynopsis>\n    <cmdsynopsis>\n      <command>&dhpackage;</command>\n      <!-- Normally the help and version options make the programs stop\n           right after outputting the requested information. -->\n      <group choice=\"opt\">\n        <arg choice=\"plain\">\n          <group choice=\"req\">\n            <arg choice=\"plain\"><option>-h</option></arg>\n            <arg choice=\"plain\"><option>--help</option></arg>\n          </group>\n        </arg>\n        <arg choice=\"plain\">\n          <group choice=\"req\">\n            <arg choice=\"plain\"><option>-v</option></arg>\n            <arg choice=\"plain\"><option>--version</option></arg>\n          </group>\n        </arg>\n      </group>\n    </cmdsynopsis>\n  </refsynopsisdiv>\n  <refsect1 id=\"description\">\n    <title>DESCRIPTION</title>\n    <para>This manual page documents briefly the\n      <command>&dhpackage;</command> and <command>bar</command>\n      commands.</para>\n    <para>This manual page was written for the Debian distribution\n      because the original program does not have a manual page.\n      Instead, it has documentation in the GNU <citerefentry>\n        <refentrytitle>info</refentrytitle>\n        <manvolnum>1</manvolnum>\n      </citerefentry> format; see below.</para>\n    <para><command>&dhpackage;</command> is a program that...</para>\n  </refsect1>\n  <refsect1 id=\"options\">\n    <title>OPTIONS</title>\n    <para>The program follows the usual GNU command line syntax,\n      with long options starting with two dashes (`-').  A summary of\n      options is included below.  For a complete description, see the\n      <citerefentry>\n        <refentrytitle>info</refentrytitle>\n        <manvolnum>1</manvolnum>\n      </citerefentry> files.</para>\n    <variablelist>\n      <!-- Use the variablelist.term.separator and the\n           variablelist.term.break.after parameters to\n           control the term elements. -->\n      <varlistentry>\n        <term><option>-e <replaceable>this</replaceable></option></term>\n        <term><option>--example=<replaceable>that</replaceable></option></term>\n        <listitem>\n          <para>Does this and that.</para>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><option>-h</option></term>\n        <term><option>--help</option></term>\n        <listitem>\n          <para>Show summary of options.</para>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><option>-v</option></term>\n        <term><option>--version</option></term>\n        <listitem>\n          <para>Show version of program.</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n  </refsect1>\n  <refsect1 id=\"files\">\n    <title>FILES</title>\n    <variablelist>\n      <varlistentry>\n        <term><filename>/etc/foo.conf</filename></term>\n        <listitem>\n          <para>The system-wide configuration file to control the\n            behaviour of <application>&dhpackage;</application>. See\n            <citerefentry>\n              <refentrytitle>foo.conf</refentrytitle>\n              <manvolnum>5</manvolnum>\n            </citerefentry> for further details.</para>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><filename>${HOME}/.foo.conf</filename></term>\n        <listitem>\n          <para>The per-user configuration file to control the\n             behaviour of <application>&dhpackage;</application>. See\n             <citerefentry>\n               <refentrytitle>foo.conf</refentrytitle>\n               <manvolnum>5</manvolnum>\n             </citerefentry> for further details.</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n  </refsect1>\n  <refsect1 id=\"environment\">\n    <title>ENVIRONMENT</title>\n    <variablelist>\n      <varlistentry>\n        <term><envar>FOO_CONF</envar></term>\n        <listitem>\n          <para>If used, the defined file is used as configuration\n            file (see also <xref linkend=\"files\"/>).</para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n  </refsect1>\n  <refsect1 id=\"diagnostics\">\n    <title>DIAGNOSTICS</title>\n    <para>The following diagnostics may be issued\n      on <filename class=\"devicefile\">stderr</filename>:</para>\n    <variablelist>\n      <varlistentry>\n        <term><errortext>Bad configuration file. Exiting.</errortext></term>\n        <listitem>\n          <para>The configuration file seems to contain a broken configuration\n            line. Use the <option>--verbose</option> option, to get more info.\n          </para>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n    <para><command>&dhpackage;</command> provides some return codes, that can\n      be used in scripts:</para>\n    <segmentedlist>\n      <segtitle>Code</segtitle>\n      <segtitle>Diagnostic</segtitle>\n      <seglistitem>\n        <seg><errorcode>0</errorcode></seg>\n        <seg>Program exited successfully.</seg>\n      </seglistitem>\n      <seglistitem>\n        <seg><errorcode>1</errorcode></seg>\n        <seg>The configuration file seems to be broken.</seg>\n      </seglistitem>\n    </segmentedlist>\n  </refsect1>\n  <refsect1 id=\"bugs\">\n    <!-- Or use this section to tell about upstream BTS. -->\n    <title>BUGS</title>\n    <para>The program is currently limited to only work\n      with the <package>foobar</package> library.</para>\n    <para>The upstreams <acronym>BTS</acronym> can be found\n      at <ulink url=\"http://bugzilla.foo.tld\"/>.</para>\n  </refsect1>\n  <refsect1 id=\"see_also\">\n    <title>SEE ALSO</title>\n    <!-- In alpabetical order. -->\n    <para><citerefentry>\n        <refentrytitle>bar</refentrytitle>\n        <manvolnum>1</manvolnum>\n      </citerefentry>, <citerefentry>\n        <refentrytitle>baz</refentrytitle>\n        <manvolnum>1</manvolnum>\n      </citerefentry>, <citerefentry>\n        <refentrytitle>foo.conf</refentrytitle>\n        <manvolnum>5</manvolnum>\n      </citerefentry></para>\n    <para>The programs are documented fully by <citetitle>The Rise and\n      Fall of a Fooish Bar</citetitle> available via the <citerefentry>\n        <refentrytitle>info</refentrytitle>\n        <manvolnum>1</manvolnum>\n      </citerefentry> system.</para>\n  </refsect1>\n</refentry>\n\n"
  },
  {
    "path": "scripts/debian/menu.ex",
    "content": "?package(xmake):needs=\"X11|text|vc|wm\" section=\"Applications/see-menu-manual\"\\\n  title=\"xmake\" command=\"/usr/bin/xmake\"\n"
  },
  {
    "path": "scripts/debian/postinst.ex",
    "content": "#!/bin/sh\n# postinst script for xmake\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:\n#        * <postinst> `configure' <most-recently-configured-version>\n#        * <old-postinst> `abort-upgrade' <new version>\n#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>\n#          <new-version>\n#        * <postinst> `abort-remove'\n#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'\n#          <failed-install-package> <version> `removing'\n#          <conflicting-package> <version>\n# for details, see https://www.debian.org/doc/debian-policy/ or\n# the debian-policy package\n\n\ncase \"$1\" in\n    configure)\n    ;;\n\n    abort-upgrade|abort-remove|abort-deconfigure)\n    ;;\n\n    *)\n        echo \"postinst called with unknown argument \\`$1'\" >&2\n        exit 1\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "scripts/debian/postrm.ex",
    "content": "#!/bin/sh\n# postrm script for xmake\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:\n#        * <postrm> `remove'\n#        * <postrm> `purge'\n#        * <old-postrm> `upgrade' <new-version>\n#        * <new-postrm> `failed-upgrade' <old-version>\n#        * <new-postrm> `abort-install'\n#        * <new-postrm> `abort-install' <old-version>\n#        * <new-postrm> `abort-upgrade' <old-version>\n#        * <disappearer's-postrm> `disappear' <overwriter>\n#          <overwriter-version>\n# for details, see https://www.debian.org/doc/debian-policy/ or\n# the debian-policy package\n\n\ncase \"$1\" in\n    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)\n    ;;\n\n    *)\n        echo \"postrm called with unknown argument \\`$1'\" >&2\n        exit 1\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "scripts/debian/preinst.ex",
    "content": "#!/bin/sh\n# preinst script for xmake\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:\n#        * <new-preinst> `install'\n#        * <new-preinst> `install' <old-version>\n#        * <new-preinst> `upgrade' <old-version>\n#        * <old-preinst> `abort-upgrade' <new-version>\n# for details, see https://www.debian.org/doc/debian-policy/ or\n# the debian-policy package\n\n\ncase \"$1\" in\n    install|upgrade)\n    ;;\n\n    abort-upgrade)\n    ;;\n\n    *)\n        echo \"preinst called with unknown argument \\`$1'\" >&2\n        exit 1\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "scripts/debian/prerm.ex",
    "content": "#!/bin/sh\n# prerm script for xmake\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:\n#        * <prerm> `remove'\n#        * <old-prerm> `upgrade' <new-version>\n#        * <new-prerm> `failed-upgrade' <old-version>\n#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>\n#        * <deconfigured's-prerm> `deconfigure' `in-favour'\n#          <package-being-installed> <version> `removing'\n#          <conflicting-package> <version>\n# for details, see https://www.debian.org/doc/debian-policy/ or\n# the debian-policy package\n\n\ncase \"$1\" in\n    remove|upgrade|deconfigure)\n    ;;\n\n    failed-upgrade)\n    ;;\n\n    *)\n        echo \"prerm called with unknown argument \\`$1'\" >&2\n        exit 1\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "scripts/debian/rules",
    "content": "#!/usr/bin/make -f\n\n# Uncomment this to turn on verbose mode.\n#export DH_VERBOSE=1\n\n# prefix\nprefix=$(CURDIR)/debian/xmake/usr\n\nconfigure: configure-stamp\nconfigure-stamp:\n\tdh_testdir\n\ttouch configure-stamp\n\nbuild: build-stamp\nbuild-stamp: configure-stamp\n\tdh_testdir\n\t./configure\n\tmake\n\ttouch $@\nclean:\n\tdh_testdir\n\tdh_testroot\n\trm -f build-stamp configure-stamp\n\tdh_clean\n\ninstall: build\n\tdh_testdir\n\tdh_testroot\n\tdh_clean -k\n\tdh_installdirs\n\tmkdir -p $(prefix)/bin\n\tmkdir -p $(prefix)/share\n\tcp -r $(CURDIR)/xmake $(prefix)/share\n\tcp -p $(CURDIR)/build/xmake $(prefix)/bin/xmake\n\tchmod 755 $(prefix)/bin/xmake\n\tcp -p $(CURDIR)/scripts/xrepo.sh $(prefix)/bin/xrepo\n\tchmod 755 $(prefix)/bin/xrepo\n\ndistclean: clean\n\nuninstall:\n\tif [ -f /usr/bin/xmake ]; then rm /usr/bin/xmake; fi\n\tif [ -f /usr/bin/xrepo ]; then rm /usr/bin/xrepo; fi\n\tif [ -d /usr/share/xmake ]; then rm -rf /usr/share/xmake; fi\n\nbinary-indep: build install\n# We have nothing to do by default.\n# # Build architecture-dependent files here.\nbinary-arch: build install\n\tdh_testdir\n\tdh_testroot\n\tdh_installchangelogs $(CURDIR)/CHANGELOG.md\n\tdh_installdocs\n\tdh_installexamples\n\tdh_installman\n\tdh_link\n\tdh_strip\n\tdh_compress\n\tdh_fixperms\n\tdh_installdeb\n\tdh_shlibdeps\n\tdh_gencontrol\n\tdh_md5sums\n\tdh_builddeb\nbinary: binary-indep binary-arch\n.PHONY: build clean binary-indep binary-arch binary install uninstall configure\n"
  },
  {
    "path": "scripts/debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "scripts/debian/watch.ex",
    "content": "# Example watch control file for uscan\n# Rename this file to \"watch\" and then you can run the \"uscan\" command\n# to check for upstream updates and more.\n# See uscan(1) for format\n\n# Compulsory line, this is a version 4 file\nversion=4\n\n# PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig\n#opts=\"pgpsigurlmangle=s%$%.sig%\"\n\n# HTTP site (basic)\n#http://example.com/downloads.html \\\n#  files/xmake-([\\d\\.]+)\\.tar\\.gz debian uupdate\n\n# Uncommment to examine a FTP server\n#ftp://ftp.example.com/pub/xmake-(.*)\\.tar\\.gz debian uupdate\n\n# SourceForge hosted projects\n# http://sf.net/xmake/ xmake-(.*)\\.tar\\.gz debian uupdate\n\n# GitHub hosted projects\n#opts=\"filenamemangle=\"s%(?:.*?)?v?(\\d[\\d.]*)\\.tar\\.gz%<project>-$1.tar.gz%\" \\\n#   https://github.com/<user>/xmake/tags \\\n#   (?:.*?/)?v?(\\d[\\d.]*)\\.tar\\.gz debian uupdate\n\n# PyPI\n# https://pypi.python.org/packages/source/<initial>/xmake/ \\\n#   xmake-(.+)\\.tar\\.gz debian uupdate\n\n# Direct Git\n# opts=\"mode=git\" http://git.example.com/xmake.git \\\n#   refs/tags/v([\\d\\.]+) debian uupdate\n\n\n\n\n# Uncomment to find new files on GooglePages\n# http://example.googlepages.com/foo.html xmake-(.*)\\.tar\\.gz\n"
  },
  {
    "path": "scripts/debian/xmake-docs.docs",
    "content": "README.source\nREADME.Debian\n"
  },
  {
    "path": "scripts/debian/xmake.cron.d.ex",
    "content": "#\n# Regular cron jobs for the xmake package\n#\n0 4\t* * *\troot\t[ -x /usr/bin/xmake_maintenance ] && /usr/bin/xmake_maintenance\n"
  },
  {
    "path": "scripts/debian/xmake.default.ex",
    "content": "# Defaults for xmake initscript\n# sourced by /etc/init.d/xmake\n# installed at /etc/default/xmake by the maintainer scripts\n\n#\n# This is a POSIX shell fragment\n#\n\n# Additional options that are passed to the Daemon.\nDAEMON_OPTS=\"\"\n"
  },
  {
    "path": "scripts/debian/xmake.doc-base.EX",
    "content": "Document: xmake\nTitle: Debian xmake Manual\nAuthor: <insert document author here>\nAbstract: This manual describes what xmake is\n and how it can be used to\n manage online manuals on Debian systems.\nSection: unknown\n\nFormat: debiandoc-sgml\nFiles: /usr/share/doc/xmake/xmake.sgml.gz\n\nFormat: postscript\nFiles: /usr/share/doc/xmake/xmake.ps.gz\n\nFormat: text\nFiles: /usr/share/doc/xmake/xmake.text.gz\n\nFormat: HTML\nIndex: /usr/share/doc/xmake/html/index.html\nFiles: /usr/share/doc/xmake/html/*.html\n"
  },
  {
    "path": "scripts/get.ps1",
    "content": "#!/usr/bin/env pwsh\n#Requires -version 5\n\n# xmake getter\n# usage: (in powershell)\n#  Invoke-Expression (Invoke-Webrequest <my location> -UseBasicParsing).Content\n\nparam (\n    [string]$version = \"master\",\n    [string]$installdir = \"\"\n)\n\n& {\n    $LastRelease = \"v3.0.7\"\n    $ErrorActionPreference = 'Stop'\n\n    function writeErrorTip($msg) {\n        Write-Host $msg -BackgroundColor Red -ForegroundColor White\n    }\n\n    if (-not $env:CI) {\n        $logo = @(\n            '                         _                      '\n            '    __  ___ __  __  __ _| | ______              '\n            '    \\ \\/ / |  \\/  |/ _  | |/ / __ \\             '\n            '     >  <  | \\__/ | /_| |   <  ___/             '\n            '    /_/\\_\\_|_|  |_|\\__ \\|_|\\_\\____| getter      '\n            '                                                '\n            '                                                ')\n        Write-Host $([string]::Join(\"`n\", $logo)) -ForegroundColor Green\n    }\n\n    if ($IsLinux -or $IsMacOS) {\n        writeErrorTip 'Install on *nix is not supported, try '\n        writeErrorTip '(Use curl) \"curl -fsSL https://xmake.io/shget.text | bash\"'\n        writeErrorTip 'or'\n        writeErrorTip '(Use wget) \"wget https://xmake.io/shget.text -O - | bash\"'\n        throw 'Unsupported platform'\n    }\n\n    $temppath = ([System.IO.Path]::GetTempPath(), $env:TMP, $env:TEMP, \"$(Get-Location)\" -ne $null)[0]\n    [Net.ServicePointManager]::SecurityProtocol = \"tls12, tls11, tls\"\n\n    if ($null -eq $installdir -or $installdir -match '^\\s*$') {\n        $installdir = & {\n            # Install to old xmake path\n            $oldXmake = Get-Command xmake -CommandType Application -ErrorAction SilentlyContinue\n            if ($oldXmake) {\n                return Split-Path $oldXmake.Path -Parent\n            }\n            if ($HOME) {\n                return Join-Path $HOME 'xmake'\n            }\n            if ($env:APPDATA) {\n                return Join-Path $env:APPDATA 'xmake'\n            }\n            if ($env:ProgramFiles) {\n                return Join-Path $env:ProgramFiles 'xmake'\n            }\n            return 'C:\\xmake'\n        }\n    }\n    $installdir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($installdir)\n\n    if ($null -eq $version -or $version -match '^\\s*$') {\n        $v = 'master'\n    } else {\n        $v = $version.Trim()\n        if ($v.Contains('.')) {\n            $v = [version]::Parse($version)\n            $v = New-Object -TypeName version -ArgumentList $v.Major, $v.Minor, $v.Build\n        }\n    }\n    function checkTempAccess {\n        $outfile = Join-Path $temppath \"$pid.tmp\"\n        try {\n            Write-Output $pid | Out-File -FilePath $outfile\n            Remove-Item $outfile\n        } catch {\n            writeErrorTip 'Cannot write to temp path'\n            writeErrorTip 'Please set environment var \"TMP\" to another path'\n            throw\n        }\n    }\n\n    function xmakeInstall {\n        $outfile = Join-Path $temppath \"$pid-xmake-installer.exe\"\n        $x64arch = @('AMD64', 'IA64')\n        $arch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'x64' } else { 'x86' }\n        $winarch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'win64' } else { 'win32' }\n        if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {\n            Write-Host \"Unsupported host architecture detected: ARM64.\"\n        }\n        $url = if ($v -is [version]) {\n            \"https://github.com/xmake-io/xmake/releases/download/v$v/xmake-v$v.$winarch.exe\"\n        } else {\n            \"https://github.com/xmake-io/xmake/releases/download/$LastRelease/xmake-$v.$winarch.exe\"\n        }\n        Write-Host \"Start downloading $url ..\"\n        try {\n            Invoke-Webrequest $url -OutFile $outfile -UseBasicParsing\n        } catch {\n            writeErrorTip 'Download failed!'\n            writeErrorTip 'Check your network or... the news of S3 break'\n            throw\n        }\n        Write-Host 'Start installation... Hope your antivirus doesn''t trouble'\n        Write-Host \"Install to $installdir\"\n        try {\n            $adminflag = \"/NOADMIN \"\n            try {\n                $tempfolder = New-Item \"$installdir-$PID-temp\" -ItemType Directory\n                Remove-Item $tempfolder.FullName\n            } catch {\n                $adminflag = \"\"\n            }\n            Start-Process -FilePath $outfile -ArgumentList \"$adminflag/S /D=$installdir\" -Wait\n        } catch {\n            writeErrorTip 'Install failed!'\n            writeErrorTip 'Close your antivirus then try again'\n            throw\n        } finally {\n            Remove-Item $outfile -ErrorAction SilentlyContinue\n        }\n        Write-Host 'Adding to PATH... almost done'\n        $env:Path += \";$installdir\"\n        try {\n            xmake --version\n        } catch {\n            writeErrorTip 'Everything is showing installation has finished'\n            writeErrorTip 'But xmake could not run... Why?'\n            throw\n        }\n    }\n\n    function registerTabCompletion {\n        # TODO: add --global --user choice\n        Write-Host \"Tab completion service\"\n        try {\n            xmake update --integrate\n        } catch {\n            writeErrorTip \"Failed to register tab completion!\"\n            writeErrorTip 'Please try \"xmake update --integrate\" to register manually.'\n            return\n        }\n        Write-Host \"Tab completion installed\"\n    }\n\n    checkTempAccess\n    xmakeInstall\n\n    if (-not $env:CI) {\n        registerTabCompletion\n    } else {\n        Write-Host \"Tab completion registration has been skipped for CI\"\n    }\n\n}\n"
  },
  {
    "path": "scripts/get.sh",
    "content": "#!/usr/bin/env bash\n\n# xmake getter\n# usage: bash <(curl -s <my location>) [branch|__local__|__run__] [commit/__install_only__]\n\nset -o pipefail\n\n#-----------------------------------------------------------------------------\n# some helper functions\n#\n\nraise() {\n    echo \"$@\" 1>&2 ; exit 1\n}\n\ntest_z() {\n    if test \"x${1}\" = \"x\"; then\n        return 0\n    fi\n    return 1\n}\n\ntest_nz() {\n    if test \"x${1}\" != \"x\"; then\n        return 0\n    fi\n    return 1\n}\n\ntest_eq() {\n    if test \"x${1}\" = \"x${2}\"; then\n        return 0\n    fi\n    return 1\n}\n\ntest_nq() {\n    if test \"x${1}\" != \"x${2}\"; then\n        return 0\n    fi\n    return 1\n}\n\n#-----------------------------------------------------------------------------\n# prepare\n#\n\n# print a LOGO!\necho 'xmake, A cross-platform build utility based on Lua.   '\necho 'Copyright (C) 2015-present Ruki Wang, https://xmake.io'\necho '                         _                            '\necho '    __  ___ __  __  __ _| | ______                    '\necho '    \\ \\/ / |  \\/  |/ _  | |/ / __ \\                   '\necho '     >  <  | \\__/ | /_| |   <  ___/                   '\necho '    /_/\\_\\_|_|  |_|\\__ \\|_|\\_\\____|                   '\necho '                         by ruki, xmake.io            '\necho '                                                      '\necho '   👉  Manual: https://xmake.io/guide/quick-start     '\necho '   🙏  Donate: https://xmake.io/about/sponsor         '\necho '                                                      '\n\n# has sudo?\nif [ 0 -ne \"$(id -u)\" ]; then\n    if sudo --version >/dev/null 2>&1\n    then\n        sudoprefix=sudo\n    else\n        sudoprefix=\n    fi\nelse\n    export XMAKE_ROOT=y\n    sudoprefix=\nfi\n\n# make tmpdir\nif [ -z \"$TMPDIR\" ]; then\n    tmpdir=/tmp/.xmake_getter$$\nelse\n    tmpdir=$TMPDIR/.xmake_getter$$\nfi\nif [ -d $tmpdir ]; then\n    rm -rf $tmpdir\nfi\n\n# get make\nif gmake --version >/dev/null 2>&1\nthen\n    make=gmake\nelse\n    make=make\nfi\n\nremote_get_content() {\n    if curl --version >/dev/null 2>&1\n    then\n        curl -fSL \"$1\"\n    elif wget --version >/dev/null 2>&1 || wget --help >/dev/null 2>&1\n    then\n        wget \"$1\" -O -\n    fi\n}\n\nget_host_speed() {\n    if [ `uname` == \"Darwin\" ]; then\n        ping -c 1 -t 1 $1 2>/dev/null | egrep -o 'time=\\d+' | egrep -o \"\\d+\" || echo \"65535\"\n    else\n        ping -c 1 -W 1 $1 2>/dev/null | grep -E -o 'time=[0-9]+' | grep -E -o \"[0-9]+\" || echo \"65535\"\n    fi\n}\n\nget_fast_host() {\n    if test_eq \"$GITHUB_ACTIONS\" \"true\" || test_eq \"$GITHUB_ACTIONS\" \"1\"; then\n        echo \"github.com\"\n    else\n        speed_gitee=$(get_host_speed \"gitee.com\")\n        speed_github=$(get_host_speed \"github.com\")\n        if [ $speed_gitee -le $speed_github ]; then\n            echo \"gitee.com\"\n        else\n            echo \"github.com\"\n        fi\n    fi\n}\n\n# get branch\nbranch=__run__\nif test_nz \"$1\"; then\n    brancharr=($1)\n    if [ ${#brancharr[@]} -eq 1 ]\n    then\n        branch=${brancharr[0]}\n    fi\n    echo \"Branch: $branch\"\nfi\n\n# get fasthost and git repository\nif test_nq \"$branch\" \"__local__\"; then\n    fasthost=$(get_fast_host)\n    if test_eq \"$fasthost\" \"gitee.com\"; then\n        gitrepo=\"https://gitee.com/tboox/xmake.git\"\n        gitrepo_raw=\"https://gitee.com/tboox/xmake/raw/master\"\n    else\n        gitrepo=\"https://github.com/xmake-io/xmake.git\"\n        #gitrepo_raw=\"https://github.com/xmake-io/xmake/raw/master\"\n        gitrepo_raw=\"https://fastly.jsdelivr.net/gh/xmake-io/xmake@master\"\n    fi\nfi\n\n#-----------------------------------------------------------------------------\n# install tools\n#\n\ntest_tools() {\n    prog='#include <stdio.h>\\nint main(){return 0;}'\n    {\n        git --version &&\n        $make --version &&\n        {\n            echo -e \"$prog\" | cc -xc - -o /dev/null ||\n            echo -e \"$prog\" | gcc -xc - -o /dev/null ||\n            echo -e \"$prog\" | clang -xc - -o /dev/null ||\n            echo -e \"$prog\" | cc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include ||\n            echo -e \"$prog\" | gcc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include ||\n            echo -e \"$prog\" | clang -xc -c - -o /dev/null -I/usr/include -I/usr/local/include\n        }\n    } >/dev/null 2>&1\n}\n\ninstall_tools() {\n    { apt --version >/dev/null 2>&1 && $sudoprefix apt install -y git build-essential libreadline-dev; } ||\n    { dnf --version >/dev/null 2>&1 && $sudoprefix dnf install -y git readline-devel bzip2 @development-tools; } ||\n    { yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git readline-devel bzip2 && $sudoprefix yum groupinstall -y 'Development Tools'; } ||\n    { zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git readline-devel && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } ||\n    { pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm --needed git base-devel ncurses readline; } ||\n    { emerge -V >/dev/null 2>&1 && $sudoprefix emerge -atv dev-vcs/git; } ||\n    { pkg list-installed >/dev/null 2>&1 && $sudoprefix pkg install -y git getconf build-essential readline; } || # termux\n    { pkg help >/dev/null 2>&1 && $sudoprefix pkg install -y git readline ncurses; } || # freebsd\n    { nix-env --version >/dev/null 2>&1 && nix-env -i git gcc readline ncurses; } || # nixos\n    { apk --version >/dev/null 2>&1 && $sudoprefix apk add git gcc g++ make readline-dev ncurses-dev libc-dev linux-headers; } ||\n    { xbps-install --version >/dev/null 2>&1 && $sudoprefix xbps-install -Sy git base-devel; } #void\n\n}\ntest_tools || { install_tools && test_tools; } || raise \"$(echo -e 'Dependencies Installation Fail\\nThe getter currently only support these package managers\\n\\t* apt\\n\\t* dnf\\n\\t* yum\\n\\t* zypper\\n\\t* pacman\\n\\t* portage\\n\\t* xbps\\n Please install following dependencies manually:\\n\\t* git\\n\\t* build essential like `make`, `gcc`, etc\\n\\t* libreadline-dev (readline-devel)')\" 1\n\n#-----------------------------------------------------------------------------\n# install xmake\n#\n\nprojectdir=$tmpdir\nif test_eq \"$branch\" \"__local__\"; then\n    if [ -d '.git' ]; then\n        git submodule update --init --recursive\n    fi\n    cp -r . $projectdir\nelif test_eq \"$branch\" \"__run__\"; then\n    version=$(git ls-remote --tags \"$gitrepo\" | tail -c7)\n    pack=gz\n    mkdir -p $projectdir\n    runfile_url=\"https://fastly.jsdelivr.net/gh/xmake-mirror/xmake-releases@$version/xmake-$version.$pack.run\"\n    echo \"downloading $runfile_url ..\"\n    remote_get_content \"$runfile_url\" > $projectdir/xmake.run\n    if [[ $? != 0 ]]; then\n        runfile_url=\"https://github.com/xmake-io/xmake/releases/download/$version/xmake-$version.$pack.run\"\n        echo \"downloading $runfile_url ..\"\n        remote_get_content \"$runfile_url\" > $projectdir/xmake.run\n    fi\n    sh $projectdir/xmake.run --noexec --quiet --target $projectdir\nelse\n    echo \"cloning $gitrepo $branch ..\"\n    if test_nz \"$2\"; then\n        git clone --filter=tree:0 --no-checkout -b \"$branch\" \"$gitrepo\" --recurse-submodules $projectdir || raise \"clone failed, check your network or branch name\"\n        cd $projectdir || raise 'chdir failed!'\n        git checkout -qf \"$2\"\n        cd - || raise 'chdir failed!'\n    else\n        git clone --depth=1 -b \"$branch\" \"$gitrepo\" --recurse-submodules $projectdir || raise \"clone failed, check your network or branch name\"\n    fi\nfi\n\n# do build\nif test_nq \"$2\" \"__install_only__\"; then\n    if [ -f \"$projectdir/configure\" ]; then\n        cd $projectdir || raise 'chdir failed!'\n        ./configure || raise \"configure failed!\"\n        cd - || raise 'chdir failed!'\n    fi\n    $make -C $projectdir --no-print-directory -j4 || raise \"make failed!\"\nfi\n\n# do install\nif test_z \"$prefix\"; then\n    prefix=~/.local\nfi\nif test_nz \"$prefix\"; then\n    $make -C $projectdir --no-print-directory install PREFIX=\"$prefix\" || raise \"install failed!\"\nelse\n    $sudoprefix $make -C $projectdir --no-print-directory install || raise \"install failed!\"\nfi\n\n#-----------------------------------------------------------------------------\n# install profile\n#\ninstall_profile() {\n    export XMAKE_ROOTDIR=\"$prefix/bin\"\n    [[ \"$PATH\" =~ (^|:)\"$XMAKE_ROOTDIR\"(:|$) ]] || export PATH=\"$XMAKE_ROOTDIR:$PATH\"\n    xmake --version\n    xmake update --integrate\n}\n\ninstall_profile\n"
  },
  {
    "path": "scripts/makeppa",
    "content": "#!/usr/bin/env bash\n\n# check\nif [ $# -lt 1 ]; then\n    echo \"Usage: ./scripts/makeppa [serie] [patch]\"\n    exit\nfi\n\n# workdir\nworkdir=./xmake-ppa\nif [ ! -d $workdir ]; then\n    mkdir $workdir\nfi\n\n# version\nversion=`cat ./core/xmake.lua | grep -E \"^set_version\" | grep -oE \"[0-9]*\\.[0-9]*\\.[0-9]*\"`\n\n# serie, e.g. groovy, focal, bionic, xenial, trusty, precise\nserie=\"$1\"\nif [ -z $serie ]; then\n    serie=xenial\nfi\n\n# patch number\npatch=\"$2\"\nif [ -z $patch ]; then\n    patch=1\nfi\n\n# tarball\nbasename=xmake-$version+$patch$serie\ntarball=$workdir/$basename.tar.gz\nif [ ! -f $tarball ]; then\n    cd core\n    xmake pack --autobuild=n -y --formats=srctargz --basename=xmake -o ../artifacts xmakesrc || exit -1\n    cd ..\n    cp ./artifacts/xmake.tar.gz $tarball\nfi\n\n# extract tarball\ncd $workdir\nif [ -d xmakesrc ]; then\n    rm -rf xmakesrc\nfi\nif [ ! -d $basename ]; then\n    mkdir xmakesrc\n    tar -xvf $basename.tar.gz -C xmakesrc\n    mv xmakesrc/xmake-$version $basename\nfi\n\n# enter project directory\ncd $basename\n\n# make template\necho \"making template ..\"\nif [ -d debian ]; then\n    rm -rf debian\nfi\nexport USER=`id -u -n`\ndh_make -e waruqi@gmail.com -c apache -y -s -f ../$basename.tar.gz\n\n# copy debian\necho \"instaling debian ..\"\nif [ -d debian ]; then\n    rm -rf debian\nfi\ncp -r ../../scripts/debian .\n\n# update changelog\nrm debian/changelog\ndch -v $version+$patch$serie \"update $version\" -D $serie --create --package xmake -M $USER\ncat debian/changelog\n\n# build package\necho \"building package ..\"\ndebuild -S -k02713554FA2CE4AADA20AB23167A22F22C0C68C9\n\n# check package\necho \"checking package ..\"\nlintian ../xmake_$version+$patch$serie.dsc\n\n# upload package\necho \"uploading package ..\"\nsource=xmake_$version+\"$patch$serie\"_source\nif [ -f ../$source.ppa.upload ]; then\n    rm ../$source.ppa.upload\nfi\ndput ppa:xmake-io/xmake ../$source.changes\n\n# remove workdir\ncd ../..\nrm -rf xmake-ppa\n\n# install dh-make and gpg\n# sudo apt install dh-make rng-tools\n#\n# @see https://help.ubuntu.com/community/GnuPrivacyGuardHowto\n#\n# generate key\n# gpg --gen-key\n#\n# save public/private key\n# gpg -a --export 2C0C68C9 > /mnt/xmake_ppa_pgp.pub\n# gpg -a --export-secret-keys 2C0C68C9 > /mnt/xmake_ppa_pgp.sec\n#\n# submit to keykserver and import this key to launchpad.net\n# @see https://launchpad.net/+help-registry/import-pgp-key.html\n# gpg --send-keys --keyserver keyserver.ubuntu.com 2C0C68C9\n#\n# recv email and validate this gpg key\n# gpg --decrypt file.txt\n# goto link\n#\n# show gpg\n# gpg --fingerprint\n# pub   2048R/2C0C68C9 2020-09-08\n#      Key fingerprint = 0271 3554 FA2C E4AA DA20  AB23 167A 22F2 2C0C 68C9\n#\n# build package and upload ppa to launchpad.net\n# https://launchpad.net/~xmake-io/+archive/ubuntu/xmake\n#\n# recv and import key on ubuntu\n# gpg --keyserver keyserver.ubuntu.com --recv 2C0C68C9\n# gpg --export --armor 2C0C68C9 | sudo apt-key add -\n#\n# show long key\n# gpg --keyid-format long --list-keys waruqi@gmail.com\n#\n"
  },
  {
    "path": "scripts/man/xmake.1",
    "content": ".TH \"xmake\" \"1\"\n.SH NAME\nxmake \\- cross-platform build utility based on Lua\n\n\n.SH SYNOPSIS\n.B xmake\n.RI [ task \"] [\" options \"] [\" target ]\n\n\n.SH DESCRIPTION\n.B xmake\nis a lightweight cross-platform build utility based on Lua. It uses\n.I xmake.lua\nto maintain project builds. Compared with\n.IR makefile / CMakeLists.txt ,\nthe configuration syntax is more concise and intuitive. It is very friendly to\nnovices and can quickly get started in a short time. Let users focus more on\nactual project development.\n\n\n.SH ACTIONS\n\n.TP\n.B b, build\nBuild targets if no given tasks.\n\n.TP\n.B u, uninstall\nUninstall the project binary files.\n\n.TP\n.B p, package\nPackage target.\n\n.TP\n.B r, run\nRun the project target.\n\n.TP\n.B g, global\nConfigure the global options for xmake.\n\n.TP\n.B i, install\nPackage and install the target binary files.\n\n.TP\n.B c, clean\nRemove all binary and temporary files.\n\n.TP\n.B create\nCreate a new project.\n\n.TP\n.B q, require\nInstall and update required packages.\n\n.TP\n.B update\nUpdate and uninstall the xmake program.\n\n.TP\n.B f, config\nConfigure the project.\n\n\n.SH PLUGINS\n\n.TP\n.B plugin\nManage plugins of xmake.\n\n.TP\n.B m, macro\nRun the given macro.\n\n.TP\n.B doxygen\nGenerate the doxygen document.\n\n.TP\n.B l, lua\nRun the lua script.\n\n.TP\n.B repo\nManage package repositories.\n\n.TP\n.B service\nStart service for remote or distributed compilation and etc. (Experimental, still in development)\n\n.TP\n.B project\nGenerate the project file.\n\n.TP\n.B show\nShow the given project information.\n\n\n.SH OPTIONS\n\n.TP\n.B \\-q, \\-\\-quiet\nQuiet operation.\n\n.TP\n.B \\-y, \\-\\-yes\nInput yes by default if need user confirm.\n\n.TP\n.BR \\-\\-confirm =\\fICONFIRM\nInput the given result if need user confirm.\n  \\- yes\n  \\- no\n  \\- def\n\n.TP\n.B \\-v, \\-\\-verbose\nPrint lots of verbose information for users.\n\n.TP\n.B \\-\\-root\nAllow one to run xmake as root.\n\n.TP\n.B \\-D, \\-\\-diagnosis\nPrint lots of diagnosis information (backtrace, check info ..) only for developers.\nAnd we can append \\fB\\-v\\fR to get more whole information.\n  e.g. $ xmake \\-vD\n\n.TP\n.B \\-\\-version\nPrint the version number and exit.\n\n.TP\n.B \\-h, \\-\\-help\nPrint this help message and exit.\n\n.TP\n.BI \\-F \" FILE\" \", \\-\\-file\\fR=\" FILE\nRead a given\n.B xmake.lua\nfile.\n\n.TP\n.BI \\-P \" PROJECT\" \", \\-\\-project\\fR=\" PROJECT\nChange to the given project directory.\nSearch priority:\n  1. The Given Command Argument\n  2. The Environment Variable: \\fBXMAKE_PROJECT_DIR\\fR\n  3. The Current Directory\n\n\n.SH BUILD OPTIONS\n\n.TP\n.B \\-b, \\-\\-build\nBuild target. This is default building mode and optional.\n\n.TP\n.B \\-r, \\-\\-rebuild\nRebuild the target.\n\n.TP\n.B \\-a, \\-\\-all\nBuild all targets.\n\n.TP\n.B \\-\\-dry\\-run\nDry run to build target.\n\n.TP\n.BI \\-j \" JOBS\" \", \\-\\-jobs\\fR=\" JOBS\nSpecifies the number of jobs to build simultaneously. (default: 6)\n\n.TP\n.B \\-w, \\-\\-warning\nEnable the warnings output.\n\n.TP\n.BI \\-\\-files= FILES\nBuild the given source files.\n\ne.g.\n.RS\n.EX\n  \\- xmake \\-\\-files=src/main.c\n  \\- xmake \\-\\-files='src/*.c' [target]\n  \\- xmake \\-\\-files='src/**c|excluded_file.c'\n  \\- xmake \\-\\-files='src/main.c:src/test.c'\n.EE\n.RE\n\n.TP\n.B target\nThe target name. It will build all default targets if this parameter is not specified.\n\n\n.SH AUTHOR\n.B xmake\nis written by\n.MT waruqi@\\:gmail.com\nruki\n.ME .\n\nThis manual page was written by\n.MT mmyangfl@\\:gmail.com\nYangfl\n.ME\nfor the Debian Project (and may be used by others).\n"
  },
  {
    "path": "scripts/man/xrepo.1",
    "content": ".TH \"xrepo\" \"1\"\n.SH NAME\nxrepo \\- cross-platform build utility based on Lua\n\n\n.SH SYNOPSIS\n.B xrepo\n.RI [ action \"] [\" options ]\n\n\n.SH DESCRIPTION\n.B xrepo\nis a lightweight cross-platform build utility based on Lua. It uses\n.I xrepo.lua\nto maintain project builds. Compared with\n.IR makefile / CMakeLists.txt ,\nthe configuration syntax is more concise and intuitive. It is very friendly to\nnovices and can quickly get started in a short time. Let users focus more on\nactual project development.\n\n\n.SH ACTIONS\n\n.TP\n.B clean\nClear all package caches and remove all not\\-referenced packages.\n\n.TP\n.B env\nSet environment and execute command, or print environment.\n\n.TP\n.B export\nExport the given packages.\n\n.TP\n.B fetch\nFetch library information of the given installed packages.\n\n.TP\n.B import\nImport the given packages.\n\n.TP\n.B info\nShow information of the given packages.\n\n.TP\n.B install\nInstall the given packages.\n\n.TP\n.B remove\nRemove the given packages.\n\n.TP\n.B scan\nScan the given or all installed packages.\n\n.TP\n.B search\nSearch the given packages.\n\n.TP\n.B add\\-repo\nAdd the given remote repository url.\n\n.TP\n.B list\\-repo\nList all remote repositories.\n\n.TP\n.B rm\\-repo\nRemove the given remote repository.\n\n.TP\n.B update\\-repo\nUpdate all local repositories from remote.\n\n\n.SH OPTIONS\n\n.TP\n.B \\-q, \\-\\-quiet\nQuiet operation.\n\n.TP\n.B \\-y, \\-\\-yes\nInput yes by default if need user confirm.\n\n.TP\n.B \\-\\-root\nAllow one to run xrepo as root.\n\n.TP\n.B \\-v, \\-\\-verbose\nPrint lots of verbose information for users.\n\n.TP\n.B \\-D, \\-\\-diagnosis\nPrint lots of diagnosis information.\n\n.TP\n.B \\-\\-version\nPrint the version number and exit.\n\n.TP\n.B \\-h, \\-\\-help\nPrint this help message and exit.\n\n\n.SH AUTHOR\n.B xrepo\nis written by\n.MT waruqi@\\:gmail.com\nruki\n.ME .\n\nThis manual page was written by\n.MT mmyangfl@\\:gmail.com\nYangfl\n.ME\nfor the Debian Project (and may be used by others).\n"
  },
  {
    "path": "scripts/msys/xmake.cmd",
    "content": "@echo off\r\nsetlocal\r\nset BASEDIR=%~dp0\r\nif exist \"%BASEDIR%..\\share\\xmake\\xmake.exe\" (\r\n    \"%BASEDIR%..\\share\\xmake\\xmake.exe\" %*\r\n)\r\nendlocal"
  },
  {
    "path": "scripts/msys/xmake.ps1",
    "content": "$BASEDIR = Split-Path -Parent $MyInvocation.MyCommand.Definition\r\nif (Test-Path \"$BASEDIR\\..\\share\\xmake\\xmake.exe\") {\r\n    & \"$BASEDIR\\..\\share\\xmake\\xmake.exe\" @args\r\n}"
  },
  {
    "path": "scripts/msys/xmake.sh",
    "content": "#!/usr/bin/env bash\nBASEDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nif [ -f \"$BASEDIR/../share/xmake/xmake.exe\" ]; then\n    $BASEDIR/../share/xmake/xmake.exe \"$@\"\nfi\n"
  },
  {
    "path": "scripts/rpmbuild/0001-use-static-libsv-and-tbox.patch",
    "content": "diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh\nindex dc45ecbca..d0e0d0069 100755\n--- a/core/src/xmake/xmake.sh\n+++ b/core/src/xmake/xmake.sh\n@@ -6,6 +6,8 @@ target \"xmake\"\n \n     # add deps\n     if has_config \"external\"; then\n+        add_deps \"sv\"\n+        add_deps \"tbox\"\n         local libs=\"lz4 sv tbox\"\n         for lib in $libs; do\n             if has_config \"$lib\"; then\ndiff --git a/core/xmake.sh b/core/xmake.sh\nindex 2ae2e686b..6ea8c1b69 100755\n--- a/core/xmake.sh\n+++ b/core/xmake.sh\n@@ -214,6 +214,9 @@ if ! has_config \"external\"; then\n     includes \"src/lz4\"\n     includes \"src/sv\"\n     includes \"src/tbox\"\n+else\n+    includes \"src/sv\"\n+    includes \"src/tbox\"\n fi\n includes \"src/xmake\"\n includes \"src/cli\"\n"
  },
  {
    "path": "scripts/rpmbuild/xmake.spec",
    "content": "%global     debug_package %{nil}\n%define     use_luajit 0\n%undefine   __brp_mangle_shebangs\n\nName:       xmake\nVersion:    3.0.7\nRelease:    1%{?dist}\nSummary:    A cross-platform build utility based on Lua\n\n# Application and 3rd-party modules licensing:\n# * xmake - Apache-2.0 -- Main tarball;\n# * libsv - Public Domain -- static dependency;\n# * tbox - Apache-2.0 -- static dependency;\n# * xxHash - BSD -- static dependency;\n\nLicense:    Apache-2.0 AND LicenseRef-Fedora-Public-Domain AND BSD\nURL:        https://xmake.io\nSource0:    https://github.com/xmake-io/xmake/releases/download/v%{version}/%{name}-v%{version}.tar.gz\nPatch0:     0001-use-static-libsv-and-tbox.patch\n\nBuildRequires:  pkgconfig(ncurses)\nBuildRequires:  pkgconfig(liblz4)\n%if %{use_luajit}\nBuildRequires:  pkgconfig(luajit)\n%else\nBuildRequires:  pkgconfig(lua) >= 5.4\n%endif\n\nBuildRequires:  gcc\nBuildRequires:  gcc-c++\n\n# Virtual provides for bundled libraries\nProvides:  bundled(libsv) = 0.0.1\nProvides:  bundled(libtbox) = 1.7.3\n\n%description\nxmake is a lightweight cross-platform build utility based on Lua.\n\nIt uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt,\nthe configuration syntax is more concise and intuitive.\nIt is very friendly to novices and can quickly get started in a short time.\nLet users focus more on actual project development.\n\nIt can compile the project directly like Make/Ninja, or\ngenerate project files like CMake/Meson, and it also has a built-in package management\nsystem to help users solve the integrated use of C/C++ dependent libraries.\n\n%prep\n%autosetup -n %{name}-%{version} -p1\n\n# Cleanup bundled deps\nrm -rf core/src/{lua,luajit,lua-cjson,lz4,pdcurses}/*/\n\n%build\n%set_build_flags\n%if %{use_luajit}\n%configure --external=y --runtime=luajit\n%else\n%configure --external=y --runtime=lua\n%endif\n\n%make_build\n\n%install\n\nmkdir -p %{buildroot}%{_mandir}/man1/\ninstall -Dpm0755 build/xmake \\\n        %{buildroot}%{_bindir}/%{name}\ninstall -Dpm0755 scripts/xrepo.sh \\\n        %{buildroot}%{_bindir}/xrepo\ninstall -Dpm0644 scripts/man/*1 \\\n        %{buildroot}%{_mandir}/man1/\ninstall -Dpm0644 xmake/scripts/completions/register-completions.bash \\\n        %{buildroot}%{_datadir}/bash-completion/completions/xmake\ninstall -Dpm0644 xmake/scripts/completions/register-completions.fish \\\n        %{buildroot}%{_datadir}/fish/vendor_completions.d/xmake.fish\ninstall -Dpm0644 xmake/scripts/completions/register-completions.zsh \\\n        %{buildroot}%{_datadir}/zsh/site-functions/xmake\ncp -rp xmake \\\n        %{buildroot}%{_datadir}/xmake\n\n%check\n%{buildroot}%{_bindir}/%{name} --version\n%{buildroot}%{_bindir}/xrepo --version\n\n%files\n%doc README.md CHANGELOG.md\n%license LICENSE.md NOTICE.md\n%{_bindir}/%{name}\n%{_bindir}/xrepo\n%{_datadir}/%{name}\n%{_datadir}/bash-completion/completions/xmake\n%{_datadir}/zsh/site-functions/xmake\n%{_datadir}/fish/vendor_completions.d/xmake.fish\n%{_mandir}/man1/*.1*\n\n%changelog\n* Tue Jul 11 2023 Zephyr Lykos <fedora@mochaa.ws> - 2.8.1-1\n- Update to 2.8.1\n\n* Sun Jun 04 2023 Zephyr Lykos <fedora@mochaa.ws> - 2.7.9-1\n- Switch to release tarball\n- Use system provided libs if possible\n- Fix docs & manpage installation\n- Install shell completions\n\n* Sun Oct 18 2020 Ruki Wang <waruqi@gmail.com> - 2.3.8-1\n- v2.3.8 released\n\n* Mon Sep 14 2020 Ruki Wang <waruqi@gmail.com> - 2.3.7-1\n- Initial Commit\n\n"
  },
  {
    "path": "scripts/srcenv.bat",
    "content": "@echo off\nsetlocal\nset script_dir=%~dp0\nset PATH=%script_dir%..\\core\\build;%cd%;%PATH%\nset XMAKE_PROGRAM_DIR=%script_dir%..\\xmake\nset XMAKE_PROGRAM_FILE=%script_dir%..\\core\\build\\xmake.exe\nstart cmd /k cd %script_dir%..\\\nendlocal\n"
  },
  {
    "path": "scripts/srcenv.profile",
    "content": "# cd projectdir\nxmake_binaries=(\n    \"build/xmake\"\n    \"build/xmake.exe\"\n    \"core/build/xmake\"\n    \"core/build/xmake.exe\"\n)\n\nexport XMAKE_PROGRAM_DIR=`pwd`/xmake\nxmake_found=0\nfor xmake_binary in \"${xmake_binaries[@]}\"; do\n    if [[ -x \"$xmake_binary\" ]] && (\"$xmake_binary\" --version); then\n        xmake_found=1\n        break\n    fi\ndone\n\nif [ $xmake_found -eq 0 ]; then\n    unset xmake_binaries xmake_binary xmake_found\n    echo \"Error: Cannot find a working xmake executable\"\n    return 1\nfi\n\nalias xmake=`pwd`/$xmake_binary\nexport XMAKE_PROGRAM_FILE=`pwd`/$xmake_binary\nalias xrepo=`pwd`/scripts/xrepo.sh\n\nunset xmake_binaries xmake_binary xmake_found\nxmake l xmake.programdir\nxmake l xmake.programfile\n"
  },
  {
    "path": "scripts/srcenv.ps1",
    "content": "$xmake_root = (Split-Path $PSScriptRoot -Parent)\n$env:PATH = \"$xmake_root\\core\\build;$pwd;$env:PATH\"\n$env:XMAKE_PROGRAM_FILE = \"$xmake_root\\core\\build\\xmake.exe\"\n$env:XMAKE_PROGRAM_DIR = \"$xmake_root\\xmake\"\nSet-Location \"$xmake_root\"\nStart-Process powershell"
  },
  {
    "path": "scripts/xrepo.bat",
    "content": "@set \"XMAKE_ROOTDIR=%~dp0\"\n@if not defined XMAKE_PROGRAM_FILE (\n    @set \"XMAKE_PROGRAM_FILE=%XMAKE_ROOTDIR%xmake.exe\"\n)\n\n@if [%1]==[env] (\n    if [%2]==[quit] (\n        if defined XMAKE_PROMPT_BACKUP (\n            call %XMAKE_ENV_BACKUP%\n            setlocal EnableDelayedExpansion\n            if !errorlevel! neq 0 exit /B !errorlevel!\n            endlocal\n            set \"PROMPT=%XMAKE_PROMPT_BACKUP%\"\n            set XMAKE_ENV_BACKUP=\n            set XMAKE_PROMPT_BACKUP=\n        )\n        goto :ENDXREPO\n    )\n    if [%2]==[shell] (\n        if defined XMAKE_PROMPT_BACKUP (\n            call %XMAKE_ENV_BACKUP%\n            setlocal EnableDelayedExpansion\n            if !errorlevel! neq 0 exit /B !errorlevel!\n            \"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info config\n            if !errorlevel! neq 0 (\n                exit /B !errorlevel!\n            )\n            @\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env.info prompt 1>nul\n            if !errorlevel! neq 0 (\n                echo error: xmake.lua not found^^!\n                exit /B !errorlevel!\n            )\n            endlocal\n            set \"PROMPT=%XMAKE_PROMPT_BACKUP%\"\n            set XMAKE_ENV_BACKUP=\n            set XMAKE_PROMPT_BACKUP=\n            echo Please rerun `xrepo env shell` to enter the environment.\n            exit /B 1\n        ) else (\n            setlocal EnableDelayedExpansion\n            \"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info config\n            if !errorlevel! neq 0 (\n                exit /B !errorlevel!\n            )\n            @\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env | findstr . && (\n                echo error: corrupt xmake.lua detected in the current directory^^!\n                exit /B 1\n            )\n            @\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env.info prompt 1>nul\n            if !errorlevel! neq 0 (\n                echo error: xmake.lua not found^^!\n                exit /B !errorlevel!\n            )\n            endlocal\n            for /f %%i in ('@\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env.info prompt') do @(\n                @set \"PROMPT=%%i %PROMPT%\"\n            )\n            @set \"XMAKE_PROMPT_BACKUP=%PROMPT%\"\n        )\n        for /f %%i in ('@\"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info envfile') do @(\n            @set \"XMAKE_ENV_BACKUP=%%i.bat\"\n            @\"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info backup.cmd 1>\"%%i.bat\"\n        )\n        for /f %%i in ('@\"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info envfile') do @(\n            @\"%XMAKE_PROGRAM_FILE%\" lua private.xrepo.action.env.info script.cmd 1>\"%%i.bat\"\n            call \"%%i.bat\"\n        )\n        goto :ENDXREPO\n    )\n    set XREPO_BIND_FLAG=\n    if [%2]==[-b] if [%4]==[shell] (\n        set XREPO_BIND_FLAG=1\n    )\n    if [%2]==[--bind] if [%4]==[shell] (\n        set XREPO_BIND_FLAG=1\n    )\n    if defined XREPO_BIND_FLAG (\n        set XREPO_BIND_FLAG=\n        if defined XMAKE_PROMPT_BACKUP (\n            call %XMAKE_ENV_BACKUP%\n            setlocal EnableDelayedExpansion\n            if !errorlevel! neq 0 exit /B !errorlevel!\n            endlocal\n            set \"PROMPT=%XMAKE_PROMPT_BACKUP%\"\n            set XMAKE_ENV_BACKUP=\n            set XMAKE_PROMPT_BACKUP=\n            echo Please rerun `xrepo env %2 %3 shell` to enter the environment.\n            exit /B 1\n        ) else (\n            pushd %XMAKE_ROOTDIR%\n            setlocal EnableDelayedExpansion\n            %XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info config %3\n            if !errorlevel! neq 0 (\n                popd\n                exit /B !errorlevel!\n            )\n            @%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3 1>nul\n            if !errorlevel! neq 0 (\n                popd\n                echo error: environment not found^^!\n                exit /B !errorlevel!\n            )\n            endlocal\n            for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3') do @(\n                @set \"PROMPT=%%i %PROMPT%\"\n            )\n            @set \"XMAKE_PROMPT_BACKUP=%PROMPT%\"\n        )\n        for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @(\n            @set \"XMAKE_ENV_BACKUP=%%i.bat\"\n            @\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env.info backup.cmd %3 1>\"%%i.bat\"\n        )\n        for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @(\n            @\"%XMAKE_PROGRAM_FILE%\" lua --quiet private.xrepo.action.env.info script.cmd %3 1>\"%%i.bat\"\n            call \"%%i.bat\"\n        )\n        popd\n        goto :ENDXREPO\n    )\n)\n\n@call \"%XMAKE_PROGRAM_FILE%\" lua private.xrepo %*\n\n:ENDXREPO\n"
  },
  {
    "path": "scripts/xrepo.ps1",
    "content": "$script:SCRIPT_PATH = $myinvocation.mycommand.path\n$script:BASE_DIR = Split-Path $SCRIPT_PATH -Parent\n$Env:XMAKE_PROGRAM_FILE = Join-Path $BASE_DIR xmake.exe\n\n\nif ($Args.Count -eq 0) {\n    # No args, just call the underlying xmake executable.\n    & $Env:XMAKE_PROGRAM_FILE lua private.xrepo;\n} else {\n    $Command = $Args[0];\n    if (($Command -eq \"env\") -and ($Args.Count -ge 2)) {\n        switch ($Args[1]) {\n            \"shell\" {\n                if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) {\n                    $Env:XMAKE_ROOTDIR = $BASE_DIR;\n                    Import-Module \"$Env:XMAKE_ROOTDIR\\scripts\\xrepo-hook.psm1\";\n                    Add-XrepoEnvironmentToPrompt;\n                }\n                if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne \"\")) {\n                    Exit-XrepoEnvironment;\n                }\n                Enter-XrepoEnvironment $Null;\n                return;\n            }\n            \"quit\" {\n                Exit-XrepoEnvironment;\n                return;\n            }\n            {$_ -in \"-b\", \"--bind\"} {\n                if (($Args.Count -ge 4) -and ($Args[3] -eq \"shell\")) {\n                    if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) {\n                        $Env:XMAKE_ROOTDIR = $BASE_DIR;\n                        Import-Module \"$Env:XMAKE_ROOTDIR\\scripts\\xrepo-hook.psm1\";\n                        Add-XrepoEnvironmentToPrompt;\n                    }\n                    if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne \"\")) {\n                        Exit-XrepoEnvironment;\n                    }\n                    Enter-XrepoEnvironment $Args[2];\n                    return;\n                }\n            }\n        }\n    }\n\n    & $Env:XMAKE_PROGRAM_FILE lua private.xrepo $Args;\n}\n"
  },
  {
    "path": "scripts/xrepo.sh",
    "content": "#!/usr/bin/env bash\nBASEDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nif [ -f \"$BASEDIR/xmake\" ]; then\n    $BASEDIR/xmake lua private.xrepo \"$@\"\nelse\n    xmake lua private.xrepo \"$@\"\nfi\n"
  },
  {
    "path": "tests/actions/config/.gitignore",
    "content": "test\n"
  },
  {
    "path": "tests/actions/config/test.lua",
    "content": "\nfunction test_workdir(t)\n    os.tryrm(\"test\")\n    os.tryrm(\"build\")\n    os.tryrm(\"build2\")\n    os.tryrm(\".xmake\")\n    os.exec(\"xmake create test\")\n    os.exec(\"xmake config -P test\")\n    os.exec(\"xmake\")\n    t:require(os.isdir(\"build\"))\n    t:require(os.isdir(\".xmake\"))\n    t:require_not(os.isdir(\"test/build\"))\n    t:require_not(os.isdir(\"test/.xmake\"))\n    os.exec(\"xmake config -o build2\")\n    os.exec(\"xmake\")\n    t:require(os.isdir(\"build2\"))\n    os.tryrm(\"build\")\n    os.tryrm(\"build2\")\n    os.tryrm(\".xmake\")\n    os.cd(\"test\")\n    os.exec(\"xmake create -P subtest\")\n    os.cd(\"subtest\")\n    os.exec(\"xmake config -P .\")\n    os.exec(\"xmake\")\n    t:require(os.isdir(\"build\"))\n    t:require(os.isdir(\".xmake\"))\n    t:require_not(os.isdir(\"../build\"))\n    t:require_not(os.isdir(\"../.xmake\"))\n    t:require_not(os.isdir(\"../../build\"))\n    t:require_not(os.isdir(\"../../.xmake\"))\nend\n\n"
  },
  {
    "path": "tests/actions/install/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/actions/install/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/actions/install/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#   define __export         __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#   define __export         __attribute__((visibility(\"default\")))\n#else\n#   define __export\n#endif\n\n__export int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/actions/install/src/foo.txt",
    "content": ""
  },
  {
    "path": "tests/actions/install/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/install/test.lua",
    "content": "function main(t)\n    if is_host(\"windows\", \"linux\", \"macosx\") and os.arch():startswith(\"x\") then\n        os.vrun(\"xmake -y\")\n        os.vrun(\"xmake run app\")\n        os.vrun(\"xmake install -o build/usr\")\n        if not is_host(\"linux\") then -- TODO, change rpath has been not supported yet on linux.\n            os.vrun(\"./build/usr/app/bin/app\" .. (is_host(\"windows\") and \".exe\" or \"\"))\n        end\n    end\nend\n"
  },
  {
    "path": "tests/actions/install/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_version(\"1.0.1\", {soname = true})\n\nadd_requires(\"libzip\", {system = false, configs = {shared = true}})\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n    add_packages(\"libzip\", {public = true})\n    add_headerfiles(\"src/foo.h\", {public = true})\n    add_installfiles(\"src/foo.txt\", {prefixdir = \"assets\", public = true})\n    set_prefixdir(\"/\", {libdir = \"foo_lib\"})\n\ntarget(\"app\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n    set_prefixdir(\"app\", {libdir = \"app_lib\"})\n    add_rpathdirs(\"@loader_path/../app_lib\", {installonly = true})\n\nincludes(\"@builtin/xpack\")\n\nxpack(\"test\")\n  add_targets(\"app\")\n  set_formats(\"zip\")\n\n"
  },
  {
    "path": "tests/actions/package/localpkg/bar/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/actions/package/localpkg/bar/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"foo(1, 2) = \" << foo(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/package/localpkg/bar/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_repositories(\"local-repo build\")\nadd_requires(\"foo\")\n\ntarget(\"bar\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"foo\")\n\n\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/add.cpp",
    "content": "#include \"add.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/add.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*! calculate add(a, b)\n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\nint             add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/foo.cpp",
    "content": "#include \"add.h\"\n#include \"sub.h\"\n#include \"foo.h\"\n\nint foo(int a, int b)\n{\n    return add(sub(a, b), sub(b, a));\n}\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*! calculate foo(a, b)\n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\nint             foo(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/sub.cpp",
    "content": "#include \"sub.h\"\n\nint sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/src/sub.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*! calculate sub(a, b)\n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\nint             sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/actions/package/localpkg/libfoo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_license(\"Apache-2.0\")\n\ntarget(\"sub\")\n    set_kind(\"static\")\n    add_files(\"src/sub.cpp\")\n    add_headerfiles(\"src/sub.h\")\n\ntarget(\"add\")\n    set_kind(\"static\")\n    add_files(\"src/add.cpp\")\n    add_headerfiles(\"src/add.h\")\n\ntarget(\"foo\")\n    add_deps(\"add\", \"sub\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n    add_headerfiles(\"src/foo.h\")\n\n"
  },
  {
    "path": "tests/actions/package/localpkg/test.lua",
    "content": "function main(t)\n    if (os.subarch():startswith(\"x\") or os.subarch() == \"i386\") and not is_host(\"bsd\", \"solaris\", \"haiku\") then\n        os.cd(\"libfoo\")\n        os.exec(\"xmake package -D -o ../bar/build\")\n        os.cd(\"../bar\")\n        os.exec(\"xmake f -c -D\")\n        os.exec(\"xmake -D\")\n        os.exec(\"xmake run\")\n    end\nend\n"
  },
  {
    "path": "tests/actions/test/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/actions/test/outputs/fail_hello_xmake.txt",
    "content": "hello xmake\n"
  },
  {
    "path": "tests/actions/test/outputs/pass_hello_foo.txt",
    "content": "hello foo\n"
  },
  {
    "path": "tests/actions/test/src/compile_1.cpp",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    static_assert(0, \"error\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/compile_2.cpp",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    static_assert(0, \"error\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/run_timeout.cpp",
    "content": "#ifdef _MSC_VER\n#   include <windows.h>\n#else\n#   include <unistd.h>\n#endif\n\nint main(int argc, char** argv) {\n#ifdef _MSC_VER\n    Sleep(10 * 1000);\n#else\n    usleep(10 * 100 * 1000);\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_1.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_2.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_3.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_4.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_5.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello2 \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_6.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_7.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return -1;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_8.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello xmake\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/src/test_9.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    char const* arg = argc > 1? argv[1] : \"xmake\";\n    cout << \"hello \" << arg << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/actions/test/test.lua",
    "content": "function main(t)\n    os.exec(\"xmake test\")\nend\n\n"
  },
  {
    "path": "tests/actions/test/tests/stub_1.cpp",
    "content": "#ifndef STUB_1\n#error\n#endif\n"
  },
  {
    "path": "tests/actions/test/tests/stub_2.cpp",
    "content": "#ifndef STUB_2\n#error\n#endif\n"
  },
  {
    "path": "tests/actions/test/tests/stub_n1.cpp",
    "content": "#ifndef STUB_N\n#error\n#endif\n"
  },
  {
    "path": "tests/actions/test/tests/stub_n2.cpp",
    "content": "#ifndef STUB_N\n#error\n#endif\n"
  },
  {
    "path": "tests/actions/test/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_policy(\"test.return_zero_on_failure\", true)\n\nfor _, file in ipairs(os.files(\"src/test_*.cpp\")) do\n    local name = path.basename(file)\n    target(name)\n        set_kind(\"binary\")\n        set_default(false)\n        add_files(\"src/\" .. name .. \".cpp\")\n        add_tests(\"default\")\n        add_tests(\"args\", {runargs = {\"foo\", \"bar\"}})\n        add_tests(\"pass_output\", {trim_output = true, runargs = \"foo\", pass_outputs = \"hello foo\"})\n        add_tests(\"fail_output\", {fail_outputs = {\"hello2 .*\", \"hello xmake\"}})\nend\n\ntarget(\"test_output_files\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/test_1.cpp\")\n    add_tests(\"pass_output_file\", {trim_output = true, runargs = \"foo\", pass_output_files = \"outputs/pass_hello_foo.txt\"})\n    add_tests(\"fail_output_file\", {trim_output = true, should_fail = true, fail_output_files = \"outputs/fail_hello_xmake.txt\"})\n\ntarget(\"test_10\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/compile_1.cpp\")\n    add_tests(\"compile_fail\", {build_should_fail = true})\n\ntarget(\"test_11\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/compile_2.cpp\")\n    add_tests(\"compile_pass\", {build_should_pass = true})\n\ntarget(\"test_13\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/test_1.cpp\")\n    add_tests(\"stub_1\", {files = \"tests/stub_1.cpp\", defines = \"STUB_1\"})\n\ntarget(\"test_14\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/test_2.cpp\")\n    add_tests(\"stub_2\", {files = \"tests/stub_2.cpp\", defines = \"STUB_2\"})\n\ntarget(\"test_15\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/test_1.cpp\")\n    add_tests(\"stub_n\", {realtime_output = true, files = \"tests/stub_n*.cpp\", defines = \"STUB_N\"})\n\ntarget(\"test_timeout\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_files(\"src/run_timeout.cpp\")\n    add_tests(\"run_timeout\", {run_timeout = 1000})\n"
  },
  {
    "path": "tests/apis/add_allowedxxx/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/add_allowedxxx/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_allowedxxx/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_defaultmode(\"releasedbg\")\nset_defaultplat(\"linux\")\nset_defaultarchs(\"macosx|arm64\", \"linux|i386\", \"armv7\")\n\nset_allowedmodes(\"releasedbg\", \"debug\")\nset_allowedplats(\"windows\", \"linux\", \"macosx\")\nset_allowedarchs(\"macosx|arm64\", \"macosx|x86_64\", \"linux|i386\", \"linux|x86_64\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/apis/add_configfiles/config.h.in",
    "content": "#define HAVE_${module}_H\n#define HELLO \"${hello} ${ARCH} ${PLAT}\"\n\n${define FOO_ENABLE}\n${define FOO_ENABLE2}\n${define FOO_STRING}\n${define FOO_DEFINE}\n\n${define FOO2_ENABLE}\n${define FOO2_ENABLE2}\n${define FOO2_STRING}\n\n${define_export MYLIB}\n${define_custom FOO_STRING arg1 arg2}\n\n#define HAVE_SSE2 ${default HAVE_SSE2 0}\n"
  },
  {
    "path": "tests/apis/add_configfiles/config2.h.in",
    "content": "#define HAVE_@module@_H\n#define HELLO2 \"@hello@ @ARCH@ @PLAT@\"\n\n@define FOO_ENABLE@\n@define FOO_ENABLE2@\n@define FOO_STRING@\n\n@define FOO2_ENABLE@\n@define FOO2_ENABLE2@\n@define FOO2_STRING@\n\n#define DEFAULT_TEST @default default_test 0@\n"
  },
  {
    "path": "tests/apis/add_configfiles/hello.man",
    "content": "${module} ${ARCH}\n"
  },
  {
    "path": "tests/apis/add_configfiles/main.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include \"config.h\"\n\nint main(int argc, char **argv) {\n    printf(\"hello %s\\n\", HELLO);\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_configfiles/main2.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include \"config2.h\"\n\nint main(int argc, char **argv) {\n    printf(\"hello2 %s\\n\", HELLO2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_configfiles/test.c.in",
    "content": "int test()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_configfiles/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/add_configfiles/xmake.lua",
    "content": "\noption(\"foo\")\n    set_default(\"foo\")\n    set_description(\"The Foo Info\")\noption_end()\n\nif has_config(\"foo\") then\n    set_configvar(\"FOO_ENABLE\", 1)\n    set_configvar(\"FOO_ENABLE2\", false)\n    set_configvar(\"FOO_STRING\", get_config(\"foo\"))\n    set_configvar(\"FOO_DEFINE\", get_config(\"foo\"), {quote = false})\nend\n\noption(\"foo2\")\n    set_default(true)\n    set_description(\"Enable Foo2\")\n    set_configvar(\"FOO2_ENABLE\", true)\n    set_configvar(\"FOO2_STRING\", \"foo\")\noption_end()\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"main.c\")\n\n    set_configvar(\"module\", \"test\")\n    set_configdir(\"$(builddir)/config\")\n    add_configfiles(\"test.c.in\", {filename = \"mytest.c\"})\n    add_configfiles(\"config.h.in\", {variables = {hello = \"xmake\"}, prefixdir = \"header\",\n        preprocessor = function (preprocessor_name, name, value, opt)\n            if preprocessor_name == \"define_custom\" then\n                return string.format(\"#define CUSTOM_%s %s\", name, value)\n            end\n        end})\n    add_configfiles(\"*.man\", {onlycopy = true, prefixdir = \"man\"})\n    add_includedirs(\"$(builddir)/config/header\")\n\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_files(\"main2.c\")\n\n    set_configvar(\"module\", \"test2\")\n    set_configdir(\"$(builddir)/config2\")\n    add_configfiles(\"test.c.in\", {filename = \"mytest.c\"})\n    add_configfiles(\"config2.h.in\", {variables = {hello = \"xmake2\"}, pattern = \"@([^\\n]-)@\", prefixdir = \"header\"})\n    add_configfiles(\"*.man\", {onlycopy = true, prefixdir = \"man\"})\n    add_includedirs(\"$(builddir)/config2/header\")\n\n    add_options(\"foo2\")\n"
  },
  {
    "path": "tests/apis/add_defines/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/add_defines/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << TEST1 << endl;\n    cout << TEST2 << endl;\n    cout << TEST3 << endl;\n    cout << TEST4 << endl;\n    cout << TEST5 << endl;\n    cout << TEST6 << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_defines/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/add_defines/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_defines(\"TEST1=\\\"hello\\\"\")\n    add_defines(\"TEST2=\\\"hello xmake\\\"\")\n    add_defines(\"TEST3=3\")\n    add_cxflags(\"-DTEST4=\\\"hello\\\"\")\n    add_cxflags(\"-DTEST5=\\\"hello xmake\\\" -DTEST6=3\")\n"
  },
  {
    "path": "tests/apis/add_deps/inc1/stub.h",
    "content": ""
  },
  {
    "path": "tests/apis/add_deps/inc2/stub.h",
    "content": ""
  },
  {
    "path": "tests/apis/add_deps/inc3/stub.h",
    "content": ""
  },
  {
    "path": "tests/apis/add_deps/inc4/stub.h",
    "content": ""
  },
  {
    "path": "tests/apis/add_deps/src/interface.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/add_deps/src/interface.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\n__export int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/add_deps/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/add_deps/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/add_deps/xmake.lua",
    "content": "\ntarget(\"dep1\")\n    set_kind(\"static\")\n    add_files(\"src/*.c\")\n    add_cflags(\"-DFLAG1\")\n    add_cflags(\"-DFLAG2\", {interface = true})\n    add_includedirs(\"inc1\", {public = true})\n    add_defines(\"TEST1\", {public = true})\n\ntarget(\"dep2\")\n    set_kind(\"shared\")\n    add_deps(\"dep1\")\n    add_files(\"src/*.c\")\n    add_includedirs(\"inc2\", {interface = true})\n    add_defines(\"TEST2\", {interface = true})\n\n    on_load(function (target)\n        print(target:extraconf(\"includedirs\"))\n        print(target:extraconf(\"defines\", \"TEST2\"))\n        print(target:extraconf(\"defines\", \"TEST2\", \"interface\"))\n        print(target:get(\"files\"))\n        print(target:get(\"files\", {private = true}))\n        print(target:get(\"files\", {public = true}))\n        print(target:get(\"files\", {interface = true}))\n        print(target:get(\"defines\"))\n        print(target:get(\"defines\", {private = true}))\n        print(target:get(\"defines\", {public = true}))\n        print(target:get(\"defines\", {interface = true}))\n    end)\n\ntarget(\"dep3\")\n    set_kind(\"static\")\n    add_files(\"src/*.c\")\n    add_includedirs(\"inc3\")\n\ntarget(\"dep4\")\n    set_kind(\"static\")\n    add_files(\"src/*.c\")\n    add_includedirs(\"inc4\", {public = true})\n    add_defines(\"TEST4\", {public = true})\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"dep2\", \"dep3\")\n    add_deps(\"dep4\", {inherit = false})\n    add_files(\"src/*.c\")\n"
  },
  {
    "path": "tests/apis/add_imports/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/add_imports/xmake.lua",
    "content": "target(\"test\")\n\n    add_imports(\"core.base.option\", \"core.base.task\")\n    before_build(function (target)\n        assert(option)\n        assert(task)\n    end)\n    on_build(function (target)\n        assert(option)\n        assert(task)\n    end)\n    after_build(function (target)\n        assert(option)\n        assert(task)\n    end)\n\n"
  },
  {
    "path": "tests/apis/add_xxx/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/add_xxx/xmake.lua",
    "content": "add_defines(\"TEST1\")\n\ntarget(\"test\")\n\n    add_defines(\"TEST2\")\n    on_build(function (target)\n        local defines = table.concat(target:get(\"defines\"), \" \")\n        assert(defines:find(\"TEST1\", 1, true))\n        assert(defines:find(\"TEST2\", 1, true))\n    end)\n\n"
  },
  {
    "path": "tests/apis/check_xxx/config.h.in",
    "content": "${define HAS_STRING_H}\n${define HAS_STRING_AND_STDIO_H}\n${define HAS_WCHAR_AND_FLOAT}\n${define HAS_PTHREAD}\n${define HAS_STATIC_ASSERT}\n${define HAS_SETJMP}\n${define HAS_CONSTEXPR}\n${define HAS_CONSEXPR_AND_STATIC_ASSERT}\n${define HAS_SSE2}\n${define HAS_LONG_8}\n${define HAS_CXX_STD_98}\n${define HAS_CXX_STD_11}\n${define HAS_CXX_STD_14}\n${define HAS_CXX_STD_17}\n${define HAS_CXX_STD_20}\n${define HAS_C_STD_89}\n${define HAS_C_STD_99}\n${define HAS_C_STD_11}\n${define HAS_C_STD_17}\n${define HAS_GCC}\n${define HAS_CXX20}\n${define IS_BIG_ENDIAN}\n${define NO_GCC}\n${define PTR_SIZE}\n${define HAVE_VISIBILITY}\n${define CUSTOM_ASSERT}\n#define HAS_WCHAR ${default HAS_WCHAR 0}\n"
  },
  {
    "path": "tests/apis/check_xxx/foo.c",
    "content": "#include \"config.h\"\n\nint foo() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/check_xxx/main.c",
    "content": "int main(int argc, char **argv) {\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/check_xxx/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/check_xxx/xmake.lua",
    "content": "includes(\"@builtin/check\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"foo.c\")\n    add_includedirs(\"$(builddir)\")\n    add_configfiles(\"config.h.in\")\n\n    check_bigendian(\"IS_BIG_ENDIAN\")\n    check_ctypes(\"HAS_WCHAR\", \"wchar_t\")\n    check_cincludes(\"HAS_STRING_H\", \"string.h\")\n    check_csnippets(\"HAS_INT_4\", \"return (sizeof(int) == 4)? 0 : -1;\", {tryrun = true})\n    check_csnippets(\"HAS_INT_4_IN_MAIN\", [[\n    int test() {\n        return (sizeof(int) == 4)? 0 : -1;\n    }\n    int main(int argc, char** argv)\n    {\n        return test();\n    }]], {tryrun = true})\n    check_csnippets(\"INT_SIZE\", 'printf(\"%d\", sizeof(int)); return 0;', {output = true, number = true})\n    check_sizeof(\"LONG_SIZE\", \"long\")\n    check_sizeof(\"STRING_SIZE\", \"std::string\", {includes = \"string\"})\n    configvar_check_bigendian(\"IS_BIG_ENDIAN\")\n    configvar_check_cincludes(\"HAS_STRING_AND_STDIO_H\", {\"string.h\", \"stdio.h\"})\n    configvar_check_ctypes(\"HAS_WCHAR_AND_FLOAT\", {\"wchar_t\", \"float\"})\n    configvar_check_links(\"HAS_PTHREAD\", {\"pthread\", \"m\", \"dl\"})\n    configvar_check_csnippets(\"HAS_STATIC_ASSERT\", \"_Static_assert(1, \\\"\\\");\")\n    configvar_check_cfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"signal.h\", \"setjmp.h\"}})\n    configvar_check_features(\"HAS_CONSTEXPR\", \"cxx_constexpr\", {languages = \"c++11\"})\n    configvar_check_features(\"HAS_CONSEXPR_AND_STATIC_ASSERT\", {\"cxx_constexpr\", \"c_static_assert\"}, {languages = \"c++11\"})\n    configvar_check_features(\"HAS_CXX_STD_98\", \"cxx_std_98\")\n    configvar_check_features(\"HAS_CXX_STD_11\", \"cxx_std_11\", {languages = \"c++11\"})\n    configvar_check_features(\"HAS_CXX_STD_14\", \"cxx_std_14\", {languages = \"c++14\"})\n    configvar_check_features(\"HAS_CXX_STD_17\", \"cxx_std_17\", {languages = \"c++17\"})\n    configvar_check_features(\"HAS_CXX_STD_20\", \"cxx_std_20\", {languages = \"c++20\"})\n    configvar_check_features(\"HAS_C_STD_89\", \"c_std_89\")\n    configvar_check_features(\"HAS_C_STD_99\", \"c_std_99\")\n    configvar_check_features(\"HAS_C_STD_11\", \"c_std_11\", {languages = \"c11\"})\n    configvar_check_features(\"HAS_C_STD_17\", \"c_std_17\", {languages = \"c17\"})\n    configvar_check_cflags(\"HAS_SSE2\", \"-msse2\")\n    configvar_check_csnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true})\n    configvar_check_csnippets(\"PTR_SIZE\", 'printf(\"%d\", sizeof(void*)); return 0;', {output = true, number = true})\n    configvar_check_csnippets(\"HAVE_VISIBILITY\", 'extern __attribute__((__visibility__(\"hidden\"))) int hiddenvar;', {default = 0})\n    configvar_check_csnippets(\"CUSTOM_ASSERT=assert\", 'assert(1);', {default = \"\", quote = false})\n    configvar_check_macros(\"HAS_GCC\", \"__GNUC__\")\n    configvar_check_macros(\"NO_GCC\", \"__GNUC__\", {defined = false})\n    configvar_check_macros(\"HAS_CXX20\", \"__cplusplus >= 202002L\", {languages = \"c++20\"})\n\n    local features_cxx17 = {\n        \"cxx_aggregate_bases\",\n        \"cxx_aligned_new\",\n        \"cxx_capture_star_this\",\n        \"cxx_constexpr\",\n        \"cxx_deduction_guides\",\n        \"cxx_enumerator_attributes\",\n        \"cxx_fold_expressions\",\n        \"cxx_guaranteed_copy_elision\",\n        \"cxx_hex_float\",\n        \"cxx_if_constexpr\",\n        \"cxx_inheriting_constructors\",\n        \"cxx_inline_variables\",\n        \"cxx_namespace_attributes\",\n        \"cxx_noexcept_function_type\",\n        \"cxx_nontype_template_args\",\n        \"cxx_nontype_template_parameter_auto\",\n        \"cxx_range_based_for\",\n        \"cxx_static_assert\",\n        \"cxx_structured_bindings\",\n        \"cxx_template_template_args\",\n        \"cxx_variadic_using\"}\n    for _, feature in ipairs(features_cxx17) do\n        check_features(\"HAS_17_\" .. feature:upper(), feature, {languages = \"c++17\"})\n    end\n\n    local features_cxx20 = {\n        \"cxx_aggregate_paren_init\",\n        \"cxx_char8_t\",\n        \"cxx_concepts\",\n        \"cxx_conditional_explicit\",\n        \"cxx_consteval\",\n        \"cxx_constexpr\",\n        \"cxx_constexpr_dynamic_alloc\",\n        \"cxx_constexpr_in_decltype\",\n        \"cxx_constinit\",\n        \"cxx_deduction_guides\",\n        \"cxx_designated_initializers\",\n        \"cxx_generic_lambdas\",\n        \"cxx_impl_coroutine\",\n        \"cxx_impl_destroying_delete\",\n        \"cxx_impl_three_way_comparison\",\n        \"cxx_init_captures\",\n        \"cxx_modules\",\n        \"cxx_nontype_template_args\",\n        \"cxx_using_enum\"}\n    for _, feature in ipairs(features_cxx20) do\n        check_features(\"HAS_20_\" .. feature:upper(), feature, {languages = \"c++20\"})\n    end\n\ntarget(\"test\")\n    add_deps(\"foo\")\n    set_kind(\"binary\")\n    add_files(\"main.c\")\n"
  },
  {
    "path": "tests/apis/clone_target/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/clone_target/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/clone_target/xmake.lua",
    "content": "target(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_defines(\"TEST\")\n    after_load(function (target)\n        import(\"core.project.project\")\n        local t = target:clone()\n        t:name_set(\"test2\")\n        t:add(\"deps\", \"test\")\n        t:add(\"defines\", \"TEST2\")\n        t:set(\"link_before\", function (target)\n            print(\"link1\", target:name())\n            assert(target:dep(\"test\"):data(\"linked\"))\n        end)\n        project.target_add(t)\n    end)\n    before_link(function (target)\n        print(\"link2\", target:name())\n        target:data_set(\"linked\", true)\n    end)\n\n"
  },
  {
    "path": "tests/apis/custom_scopeapis/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/custom_scopeapis/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/custom_scopeapis/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ninterp_add_scopeapis(\"myscope.set_name\", \"myscope.add_list\", {kind = \"values\"})\ninterp_add_scopeapis(\"myscope.on_script\", {kind = \"script\"})\n\nmyscope(\"hello\")\n    set_name(\"foo\")\n    add_list(\"value1\", \"value2\")\n    on_script(function ()\n        print(\"hello\")\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    on_config(function (target)\n        import(\"core.project.project\")\n        local myscope = project.scope(\"myscope\")\n        for name, scope in pairs(myscope) do\n            print(\"myscope(%s)\", name)\n            print(\"    name: %s\", scope:get(\"name\"))\n            print(\"    list: %s\", table.concat(scope:get(\"list\"), \", \"))\n            print(\"    script:\")\n            local script = scope:get(\"script\")\n            if script then\n                script()\n            end\n        end\n    end)\n\n\n"
  },
  {
    "path": "tests/apis/custom_toolchain/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/custom_toolchain/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/custom_toolchain/src/test.cpp",
    "content": "#include \"foo.h\"\n\nint main(int argc, char **argv) {\n    return add(1, 2);\n}\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/core/tools/ar6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ar6x.lua\n--\n\ninherit(\"core.tools.ar\")\n\n-- init it\nfunction init(self)\n    self:set(\"arflags\", \"-r\")\nend\n\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt, islinker)\n    local flag = flags[1]\n    if not islinker then\n        if flag:startswith(\"-D\") or\n           flag:startswith(\"-U\") or\n           flag:startswith(\"-I\") then\n            return true\n        end\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.cl6x.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"cl6x_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-z\", \"--output_file=\" .. tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-c\", \"--output_file=\" .. tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun then\n        if _check_from_arglist(flags, opt, islinker) then\n            return true\n        end\n        if _check_from_knownargs(flags, opt, islinker) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    -- escape characters, e.g. \\#Qt.Widget_pch.h -> #Qt.Widget_pch.h\n    -- @see https://github.com/xmake-io/xmake/issues/4134\n    -- https://github.com/xmake-io/xmake/issues/4273\n    if not is_host(\"windows\") then\n        dep = dep:gsub(\"\\\\(.)\", \"%1\")\n    end\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- parse depsfiles from string\n--\n-- parse_deps(io.readfile(depfile, {continuation = \"\\\\\"}))\n--\n-- eg.\n--\n-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.c\n-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.h\n--\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/main.c\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/foo.h\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/bar.h\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/zoo.h\n--\nfunction main(depsdata, opt)\n    local results = hashset.new()\n    local projectdir = os.projectdir()\n    local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first\n    local plain = {plain = true}\n    for _, includefile in ipairs(line:split('\\n', plain)) do -- it will trim all internal spaces without `{strict = true}`\n        includefile = includefile:split(\": \", plain)[2]\n        if includefile and #includefile > 0 then\n            includefile = _normailize_dep(includefile, projectdir)\n            if includefile then\n                results:insert(includefile)\n            end\n        end\n    end\n    return results:to_array()\nend\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cl6x.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-m3\"\n    ,   aggressive = \"-O3\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if not lib:endswith(\".a\") and not lib:endswith(\".so\") then\n         lib = \"lib\" .. lib .. \".a\"\n    end\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-i\" .. path.translate(dir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir, opt)\n    opt = opt or {}\n    local extra = opt.extra\n    if extra and extra.installonly then\n        return\n    end\n    dir = path.translate(dir)\n    return {\"-rpath=\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    local argv = table.join(\"-z\", \"--output_file=\" .. targetfile, objectfiles, flags)\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n    if option.get(\"verbose\") then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", \"--preproc_with_compile\", flags, \"--output_file=\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-ppd=\" .. depfile)\n            end\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"cl6x\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/detect/tools/find_ar6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ar6x.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- check\nfunction _check(program)\n\n    -- make a stub object file\n    local libraryfile = os.tmpfile() .. \".a\"\n    local objectfile  = os.tmpfile() .. \".o\"\n    io.writefile(objectfile, \"\")\n\n    -- archive it\n    os.execv(program, {\"-r\", libraryfile, objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(libraryfile)\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ar6x()\n-- local ar, version = find_ar6x({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt       = opt or {}\n    opt.check = opt.check or _check\n    return find_program(opt.program or \"ar6x\", opt)\nend\n\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/modules/detect/tools/find_cl6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cl6x.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cl6x\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cl6x = find_cl6x()\n-- local cl6x, version = find_cl6x({program = \"cl6x\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = \"--help\"\n    opt.command = \"--help\"\n    local program = find_program(opt.program or \"cl6x\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake/toolchains/my-c6000/xmake.lua",
    "content": "toolchain(\"my-c6000\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://www.ti.com\")\n    set_description(\"TI-CGT C6000 compiler\")\n\n    set_toolset(\"cc\", \"cl6x\")\n    set_toolset(\"cxx\", \"cl6x\")\n    set_toolset(\"ld\", \"cl6x\")\n    set_toolset(\"sh\", \"cl6x\")\n    set_toolset(\"ar\", \"ar6x\")\n    set_toolset(\"strip\", \"strip6x\")\n    set_toolset(\"as\", \"cl6x\")\n\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"cl6x\")\n    end)\n\n    on_load(function (toolchain)\n        toolchain:add(\"cxflags\", \"-Dxxx\")\n    end)\n"
  },
  {
    "path": "tests/apis/custom_toolchain/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"xmake/modules\")\nadd_toolchaindirs(\"xmake/toolchains\")\n\nset_toolchains(\"my-c6000\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"src/test.cpp\")\n\n\n"
  },
  {
    "path": "tests/apis/namespace/basic/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/basic/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/basic/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/basic/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/basic/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/basic/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/basic/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/basic/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nnamespace(\"ns1\", function ()\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\nend)\n\nnamespace(\"ns2\")\n    target(\"bar\")\n        set_kind(\"static\")\n        add_files(\"src/bar.cpp\")\nnamespace_end()\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"ns1::foo\", \"ns2::bar\")\n    add_files(\"src/main.cpp\")\n\n"
  },
  {
    "path": "tests/apis/namespace/includes/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/includes/src/xmake.lua",
    "content": "namespace(\"ns2\", function ()\n    add_defines(\"NS2_ROOT\")\n    target(\"bar\")\n        set_kind(\"static\")\n        add_files(\"bar.cpp\")\n        add_defines(\"BAR\")\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/includes/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/includes/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_defines(\"ROOT\")\n\nnamespace(\"ns1\", function ()\n    add_defines(\"NS1_ROOT\")\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        add_defines(\"FOO\")\n\n    includes(\"src\")\nend)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"ns1::foo\", \"ns1::ns2::bar\")\n    add_files(\"src/main.cpp\")\n    add_defines(\"TEST\")\n\n"
  },
  {
    "path": "tests/apis/namespace/inner/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/inner/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/inner/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/inner/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/inner/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/inner/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/inner/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/inner/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nnamespace(\"ns1\", function ()\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n\n    namespace(\"ns2\", function()\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n    end)\n\n    target(\"test\")\n        set_kind(\"binary\")\n        add_deps(\"foo\", \"ns2::bar\")\n        add_files(\"src/main.cpp\")\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/nested/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/nested/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/nested/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/nested/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/nested/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/nested/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/nested/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/nested/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nnamespace(\"ns1\", function ()\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n\n    namespace(\"ns2\")\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n    namespace_end()\nend)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"ns1::foo\", \"ns1::ns2::bar\")\n    add_files(\"src/main.cpp\")\n\n"
  },
  {
    "path": "tests/apis/namespace/option/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/option/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/option/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/option/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/option/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/option/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/option/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/option/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\noption(\"opt0\", {default = true, defines = \"OPT0\", description = \"option0\"})\n\nnamespace(\"ns1\", function ()\n    option(\"opt1\", {default = true, defines = \"NS1_OPT1\", description = \"option1\"})\n\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        add_options(\"opt1\")\n        if has_config(\"opt1\") then\n            add_defines(\"HAS_NS1_OPT1\")\n        end\n\n    namespace(\"ns2\", function()\n        option(\"opt2\", {default = true, defines = \"NS2_OPT2\", description = \"option2\"})\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n            add_options(\"opt2\")\n            if has_config(\"opt2\") then\n                add_defines(\"HAS_NS2_OPT2\")\n            end\n    end)\n\n    target(\"test\")\n        set_kind(\"binary\")\n        add_deps(\"foo\", \"ns2::bar\")\n        add_files(\"src/main.cpp\")\n        add_options(\"opt0\", \"opt1\", \"ns2::opt2\")\n        on_load(function (target)\n            if has_config(\"opt0\") then\n                target:add(\"defines\", \"HAS_OPT0\")\n            end\n            if has_config(\"opt1\") then\n                target:add(\"defines\", \"HAS_NS1_OPT1\")\n            end\n            if has_config(\"ns2::opt2\") then\n                target:add(\"defines\", \"HAS_NS2_OPT2\")\n            end\n        end)\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/package/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/package/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/package/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/package/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/package/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/package/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/package/test.lua",
    "content": "function main()\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    os.exec(\"xmake -vD -y\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/package/xmake.lua",
    "content": "\nadd_requires(\"package0\", {system = false})\n\npackage(\"package0\")\n    on_load(function (package)\n        package:add(\"defines\", \"PACKAGE0\")\n    end)\n    on_install(function (package) end)\n\nnamespace(\"ns1\", function ()\n\n    add_requires(\"package1\", {system = false})\n\n    package(\"package1\")\n        on_load(function (package)\n            package:add(\"defines\", \"NS1_PACKAGE1\")\n        end)\n        on_install(function (package) end)\n\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        add_packages(\"package1\")\n        if has_package(\"package1\") then\n            add_defines(\"HAS_PACKAGE1\")\n        end\n\n    namespace(\"ns2\", function()\n\n        add_requires(\"package2\", {system = false})\n\n        package(\"package2\")\n            on_load(function (package)\n                package:add(\"defines\", \"NS2_PACKAGE2\")\n            end)\n            on_install(function (package) end)\n\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n            add_packages(\"package2\")\n            if has_package(\"package2\") then\n                add_defines(\"HAS_PACKAGE2\")\n            end\n    end)\n\n    target(\"test\")\n        set_kind(\"binary\")\n        add_deps(\"foo\", \"ns2::bar\")\n        add_files(\"src/main.cpp\")\n        add_packages(\"package0\", \"package1\", \"ns2::package2\")\n        on_load(function (target)\n            if has_package(\"package0\") then\n                target:add(\"defines\", \"HAS_PACKAGE0\")\n            end\n            if has_package(\"package1\") then\n                target:add(\"defines\", \"HAS_PACKAGE1\")\n            end\n            if has_package(\"ns2::package2\") then\n                target:add(\"defines\", \"HAS_PACKAGE2\")\n            end\n        end)\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/root/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/root/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/root/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/root/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/root/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/root/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/root/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/root/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_defines(\"ROOT\")\n\nnamespace(\"ns1\", function ()\n    add_defines(\"NS1_ROOT\")\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        add_defines(\"FOO\")\n\n    namespace(\"ns2\", function ()\n        add_defines(\"NS2_ROOT\")\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n            add_defines(\"BAR\")\n    end)\nend)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"ns1::foo\", \"ns1::ns2::bar\")\n    add_files(\"src/main.cpp\")\n    add_defines(\"TEST\")\n\n"
  },
  {
    "path": "tests/apis/namespace/rule/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/rule/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/rule/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/rule/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/rule/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/rule/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/rule/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/rule/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nrule(\"rule0\")\n    on_load(function (target)\n        target:add(\"defines\", \"RULE0\")\n    end)\n\nnamespace(\"ns1\", function ()\n    rule(\"rule1\")\n        on_load(function (target)\n            target:add(\"defines\", \"NS1_RULE1\")\n        end)\n\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        add_rules(\"rule1\")\n\n    namespace(\"ns2\", function()\n        rule(\"rule2\")\n            on_load(function (target)\n                target:add(\"defines\", \"NS2_RULE2\")\n            end)\n\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n            add_rules(\"rule2\")\n    end)\n\n    target(\"test\")\n        set_kind(\"binary\")\n        add_deps(\"foo\", \"ns2::bar\")\n        add_files(\"src/main.cpp\")\n        add_rules(\"rule0\", \"rule1\", \"ns2::rule2\")\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/task/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/task/test.lua",
    "content": "function main()\n    os.exec(\"xmake task0\")\n    os.exec(\"xmake ns1::task1\")\n    os.exec(\"xmake ns1::ns2::task2\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/task/xmake.lua",
    "content": "task(\"task0\")\n    set_menu {options = {}}\n    on_run(function ()\n        print(\"task0\")\n    end)\n\nnamespace(\"ns1\", function ()\n    task(\"task1\")\n        set_menu {options = {}}\n        on_run(function ()\n            print(\"NS1_TASK1\")\n        end)\n\n    namespace(\"ns2\", function()\n        task(\"task2\")\n            set_menu {options = {}}\n            on_run(function ()\n                print(\"NS2_TASK2\")\n            end)\n    end)\nend)\n\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint sub(int a, int b) {\n    return a - b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/src/bar.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint sub(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    std::cout << \"sub(2, 1) = \" << sub(2, 1) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/test.lua",
    "content": "function main()\n    os.exec(\"xmake -vD\")\nend\n"
  },
  {
    "path": "tests/apis/namespace/toolchain/xmake.lua",
    "content": "\ntoolchain(\"toolchain0\")\n    on_load(function (toolchain)\n        toolchain:add(\"defines\", \"TOOLCHAIN0\")\n    end)\n\nnamespace(\"ns1\", function ()\n    toolchain(\"toolchain1\")\n        on_load(function (toolchain)\n            toolchain:add(\"defines\", \"NS1_TOOLCHAIN1\")\n        end)\n\n    target(\"foo\")\n        set_kind(\"static\")\n        add_files(\"src/foo.cpp\")\n        set_toolchains(\"toolchain1\")\n\n    namespace(\"ns2\", function()\n        toolchain(\"toolchain2\")\n            on_load(function (toolchain)\n                toolchain:add(\"defines\", \"NS2_TOOLCHAIN2\")\n            end)\n\n        target(\"bar\")\n            set_kind(\"static\")\n            add_files(\"src/bar.cpp\")\n            set_toolchains(\"toolchain2\")\n    end)\n\n    target(\"test\")\n        set_kind(\"binary\")\n        add_deps(\"foo\", \"ns2::bar\")\n        add_files(\"src/main.cpp\")\n        set_toolchains(\"toolchain0\", \"toolchain1\", \"ns2::toolchain2\")\nend)\n\n"
  },
  {
    "path": "tests/apis/rules/src/empty.stub",
    "content": ""
  },
  {
    "path": "tests/apis/rules/src/index.md",
    "content": "## hello xmake\n"
  },
  {
    "path": "tests/apis/rules/src/main.c",
    "content": "#include <stdio.h>\n\nextern int test(int a, int b);\nint        main(int argc, char **argv) {\n    printf(\"1 + 1 = %d\\n\", test(1, 1));\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/rules/src/main2.c",
    "content": "#include <stdio.h>\n\nextern int test(int a, int b);\nint        main(int argc, char **argv) {\n    printf(\"1 + 1 = %d\\n\", test(1, 1));\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/rules/src/man/man1.in",
    "content": "hello [name]!\n"
  },
  {
    "path": "tests/apis/rules/src/man/man2.in",
    "content": "hello [name]!\n"
  },
  {
    "path": "tests/apis/rules/src/man/man3.in",
    "content": "hello [name]!\n"
  },
  {
    "path": "tests/apis/rules/src/test.c.in",
    "content": "int test(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/rules/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/rules/xmake.lua",
    "content": "\n-- define rule: markdown\nrule(\"markdown\")\n    set_extensions(\".md\", \".markdown\")\n    on_load(function (target)\n        print(\"markdown: on_load\")\n    end)\n    on_build_file(function (target, sourcefile)\n        print(\"compile %s\", sourcefile)\n        os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. \".html\"))\n    end)\n\n-- define rule: man\nrule(\"man\")\n    add_imports(\"core.project.rule\")\n    on_build_files(function (target, sourcefiles)\n        for _, sourcefile in ipairs(sourcefiles) do\n            print(\"generating man: %s\", sourcefile)\n        end\n    end)\n\n-- define rule: c code\nrule(\"c code\")\n    add_imports(\"core.tool.compiler\")\n    before_build_file(function (target, sourcefile)\n        print(\"before_build_file: \", sourcefile)\n    end)\n    on_build_file(function (target, sourcefile, opt)\n        import(\"core.theme.theme\")\n        import(\"utils.progress\")\n        progress.show(opt.progress, \"compiling.$(mode) %s\", sourcefile)\n        local objectfile_o = os.tmpfile() .. \".o\"\n        local sourcefile_c = os.tmpfile() .. \".c\"\n        os.cp(sourcefile, sourcefile_c)\n        compiler.compile(sourcefile_c, objectfile_o)\n        table.insert(target:objectfiles(), objectfile_o)\n    end)\n    after_build_file(function (target, sourcefile)\n        print(\"after_build_file: \", sourcefile)\n    end)\n\n-- define rule: stub3\nrule(\"stub3\")\n    add_deps(\"markdown\")\n    on_load(function (target)\n        print(\"rule(stub3): on_load\")\n    end)\n\n-- define rule: stub2\nrule(\"stub2\")\n    add_deps(\"stub3\")\n    on_load(function (target)\n        print(\"rule(stub2): on_load\")\n    end)\n    before_build(function (target)\n        print(\"rule(stub2): before_build\")\n    end)\n    after_build(function (target)\n        print(\"rule(stub2): after_build\")\n    end)\n    before_build_files(function (target)\n        print(\"rule(stub2): before_build_files\")\n    end)\n    after_build_files(function (target)\n        print(\"rule(stub2): after_build_files\")\n    end)\n\n-- define rule: stub1\nrule(\"stub1\")\n    add_deps(\"stub2\")\n    on_load(function (target)\n        print(\"rule(stub1): on_load\")\n    end)\n\n    before_build(function (target)\n        print(\"rule(stub1): before_build\")\n    end)\n    after_build(function (target)\n        print(\"rule(stub1): after_build\")\n    end)\n\n    before_clean(function (target)\n        print(\"rule(stub1): before_clean\")\n    end)\n    after_clean(function (target)\n        print(\"rule(stub1): after_clean\")\n    end)\n\n    before_install(function (target)\n        print(\"rule(stub1): before_install\")\n    end)\n    on_install(function (target)\n        print(\"rule(stub1): on_install\")\n    end)\n    after_install(function (target)\n        print(\"rule(stub1): after_install\")\n    end)\n\n    before_uninstall(function (target)\n        print(\"rule(stub1): before_uninstall\")\n    end)\n    on_uninstall(function (target)\n        print(\"rule(stub1): on_uninstall\")\n    end)\n    after_uninstall(function (target)\n        print(\"rule(stub1): after_uninstall\")\n    end)\n\n    before_package(function (target)\n        print(\"rule(stub1): before_package\")\n    end)\n    on_package(function (target)\n        print(\"rule(stub1): on_package\")\n    end)\n    after_package(function (target)\n        print(\"rule(stub1): after_package\")\n    end)\n\n    before_run(function (target)\n        print(\"rule(stub1): before_run\")\n    end)\n    on_run(function (target)\n        print(\"rule(stub1): on_run\")\n    end)\n    after_run(function (target)\n        print(\"rule(stub1): after_run\")\n    end)\n\n-- define rule: stub0b\nrule(\"stub0b\")\n    before_build_file(function (target, sourcefile)\n        print(\"rule(stub0b): before_build_file\", sourcefile)\n    end)\n\n-- define rule: stub0a\nrule(\"stub0a\")\n    after_build_file(function (target, sourcefile)\n        print(\"rule(stub0a): after_build_file\", sourcefile)\n    end)\n\n-- define target\ntarget(\"test\")\n\n    -- set kind\n    set_kind(\"binary\")\n\n    -- add rules\n    add_rules(\"stub1\")\n\n    -- add files\n    add_files(\"src/*.c|main2.c\", {rules = {\"stub0a\", \"stub0b\"}})\n    add_files(\"src/main2.c\", {rules = {\"stub0a\", \"stub0b\", override = true}})\n    add_files(\"src/man/*.in\",   {rules = \"man\"})\n    add_files(\"src/index.md\")\n    add_files(\"src/test.c.in\",  {rules = \"c code\"})\n\n    before_build(function (target)\n        print(\"target: before_build\")\n    end)\n\n    after_build(function (target)\n        print(\"target: after_build\")\n    end)\n"
  },
  {
    "path": "tests/apis/rules_inject_deps/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/rules_inject_deps/src/main.cpp2",
    "content": ""
  },
  {
    "path": "tests/apis/rules_inject_deps/test.lua",
    "content": "function main()\n    os.exec(\"xmake -j1\")\nend\n"
  },
  {
    "path": "tests/apis/rules_inject_deps/xmake.lua",
    "content": "rule(\"cppfront\")\n    set_extensions(\".cpp2\")\n    add_orders(\"cppfront\", \"c++.build\")\n    on_build_file(function (target, sourcefile, opt)\n        print(\"build cppfront file\")\n        local objectfile = target:objectfile(sourcefile:gsub(\"cpp2\", \"cpp\"))\n        assert(not os.isfile(objectfile), \"invalid rule order!\")\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"cppfront\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/*.cpp2\")\n    before_build_file(function (target, sourcefile, opt)\n        local objectfile = target:objectfile(sourcefile)\n        os.tryrm(objectfile)\n    end)\n\n"
  },
  {
    "path": "tests/apis/rules_order/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char **argv) {\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/rules_order/src/test.man",
    "content": "## hello xmake\n"
  },
  {
    "path": "tests/apis/rules_order/src/test.md",
    "content": "## hello xmake\n"
  },
  {
    "path": "tests/apis/rules_order/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/rules_order/xmake.lua",
    "content": "\nrule(\"markdown\")\n    set_extensions(\".md\", \".markdown\")\n    add_orders(\"man\", \"markdown\")\n\n    before_build(function (target)\n        print(\"before_build: markdown\")\n    end)\n    after_build(function (target)\n        print(\"after_build: markdown\")\n    end)\n\n    before_build_file(function (target, sourcefile)\n        print(\"before_build_file: %s\", sourcefile)\n    end)\n    on_build_file(function (target, sourcefile)\n        print(\"on_build_file: %s\", sourcefile)\n    end)\n    after_build_file(function (target, sourcefile)\n        print(\"after_build_file: %s\", sourcefile)\n    end)\n\nrule(\"man\")\n    set_extensions(\".man\")\n\n    before_build(function (target)\n        print(\"before_build: man\")\n    end)\n    after_build(function (target)\n        print(\"after_build: man\")\n    end)\n\n    before_build_file(function (target, sourcefile)\n        print(\"before_build_file: %s\", sourcefile)\n    end)\n    on_build_file(function (target, sourcefile)\n        print(\"on_build_file: %s\", sourcefile)\n    end)\n    after_build_file(function (target, sourcefile)\n        print(\"after_build_file: %s\", sourcefile)\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"markdown\", \"man\")\n    add_files(\"src/*.c\")\n    add_files(\"src/*.md\")\n    add_files(\"src/*.man\")\n    before_build_file(function (target, sourcefile)\n        print(\"target.before_build_file: %s\", sourcefile)\n    end)\n    --[[\n    on_build_file(function (target, sourcefile)\n        print(\"target.on_build_file: %s\", sourcefile)\n    end)]]\n    after_build_file(function (target, sourcefile)\n        print(\"target.after_build_file: %s\", sourcefile)\n    end)\n\n"
  },
  {
    "path": "tests/apis/rules_override_cxx/src/main.xx",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/rules_override_cxx/src/test.cc",
    "content": ""
  },
  {
    "path": "tests/apis/rules_override_cxx/test.lua",
    "content": "function main()\n    os.exec(\"xmake\")\nend\n"
  },
  {
    "path": "tests/apis/rules_override_cxx/xmake.lua",
    "content": "rule(\"xx\")\n    add_deps(\"c++\")\n    on_load(function (target)\n\n        -- add .xx\n        local rule = target:rule(\"c++.build\"):clone()\n        rule:set(\"extensions\", \".xx\")\n        target:rule_add(rule)\n\n        -- patch sourcebatch for .xx\n        local sourcebatch = target:sourcebatches()[\"c++.build\"]\n        sourcebatch.sourcekind = \"cxx\"\n        sourcebatch.objectfiles = {}\n        sourcebatch.dependfiles = {}\n        for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            local objectfile = target:objectfile(sourcefile)\n            local dependfile = target:dependfile(objectfile)\n            table.insert(sourcebatch.objectfiles, objectfile)\n            table.insert(sourcebatch.dependfiles, dependfile)\n        end\n\n        -- force as c++ source file\n        if target:is_plat(\"windows\") then\n            target:add(\"cxxflags\", \"/TP\")\n        else\n            target:add(\"cxxflags\", \"-x c++\")\n        end\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"xx\")\n    add_files(\"src/*.xx\", \"src/*.cc\")\n\n"
  },
  {
    "path": "tests/apis/set_toolchains/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/set_toolchains/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/set_toolchains/src/test.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/set_toolchains/xmake.lua",
    "content": "toolchain(\"myclang\")\n    set_kind(\"standalone\")\n\n    set_toolset(\"cc\", \"clang\")\n    set_toolset(\"cxx\", \"clang\", \"clang++\")\n    set_toolset(\"ld\", \"clang++\", \"clang\")\n    set_toolset(\"sh\", \"clang++\", \"clang\")\n    set_toolset(\"ar\", \"ar\")\n    set_toolset(\"strip\", \"strip\")\n    set_toolset(\"mm\", \"clang\")\n    set_toolset(\"mxx\", \"clang\", \"clang++\")\n    set_toolset(\"as\", \"clang\")\n\n    add_defines(\"MYCLANG\")\n\ntoolchain_end()\n\nadd_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n    set_toolset(\"ar\", \"ar\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"src/test.cpp\")\n    set_toolchains(\"myclang\")\n\n\n"
  },
  {
    "path": "tests/apis/target_get_from/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/apis/target_get_from/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/apis/target_get_from/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/apis/target_get_from/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/apis/target_get_from/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"zlib\")\n\noption(\"bar\")\n    set_default(true)\n    add_defines(\"BAR\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n    add_defines(\"foo\")\n    add_defines(\"FOO\", {public = true})\n    add_options(\"bar\")\n    add_linkgroups(\"m\", \"pthread\", {group = true})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n    add_defines(\"TEST\")\n    add_packages(\"zlib\")\n    on_config(function (target)\n        print(\"self\", target:get_from(\"defines\", \"self\"))\n        print(\"dep::foo\", target:get_from(\"defines\", \"dep::foo\"))\n        print(\"dep::*\", target:get_from(\"defines\", \"dep::*\"))\n        print(\"dep::foo/option::bar\", target:get_from(\"defines\", \"dep::foo/option::bar\"))\n        print(\"dep::foo/option::*\", target:get_from(\"defines\", \"dep::foo/option::*\"))\n        print(\"*\", target:get_from(\"defines\", \"*\"))\n        print(\"package::zlib\", target:get_from(\"links\", \"package::zlib\"))\n        print(\"extraconf(dep::foo)\", target:extraconf_from(\"linkgroups\", \"dep::foo\"))\n    end)\n\n"
  },
  {
    "path": "tests/apis/xxx_script/test.lua",
    "content": "function main()\n    os.exec(\"xmake f -c\")\n    os.exec(\"xmake\")\n    if os.host() == \"macosx\" then\n        os.exec(\"xmake f -p iphoneos\")\n        os.exec(\"xmake\")\n        os.exec(\"xmake f -p iphoneos -a arm64\")\n        os.exec(\"xmake\")\n    end\nend\n"
  },
  {
    "path": "tests/apis/xxx_script/xmake.lua",
    "content": "target(\"test\")\n\n    before_build(\"iphoneos|arm64\", \"macosx\", function (target)\n        assert(target:is_plat(\"macosx\") or (target:is_plat(\"iphoneos\") and target:is_arch(\"arm64\")))\n    end)\n\n    before_build(function (target)\n        print(\"before_build\")\n    end)\n\n    on_build(\"macosx|native\", function (target)\n        print(\"build macosx:native\")\n    end)\n\n    on_build(function (target)\n        print(\"build\")\n    end)\n\n    after_build(function (target)\n        print(\"after_build\")\n    end)\n\n    after_build(\"!macosx\", function (target)\n        print(\"after_build !macosx\")\n    end)\n\n    after_build(\"!linux\", function (target)\n        print(\"after_build !linux\")\n    end)\n\n    after_build(\"!iphoneos\", function (target)\n        print(\"after_build !iphoneos\")\n    end)\n\n    after_build(\"linux|*\", function (target)\n        assert(target:is_plat(\"linux\"))\n    end)\n"
  },
  {
    "path": "tests/benchmarks/async/runjobs.lua",
    "content": "import(\"async.runjobs\")\n\nfunction test_run(total, comax)\n    local f = function () end\n    local t1 = os.mclock()\n    runjobs(\"test\", f, {total = total, comax = comax})\n    t1 = os.mclock() - t1\n\n    local n = total\n    local t2 = os.mclock()\n    while n ~= 0 do\n        f()\n        n = n - 1\n    end\n    t2 = os.mclock() - t2\n    print(\"runjobs(%d/%d): %d ms, plain: %d ms\", total, comax, t1, t2)\nend\n\nfunction test_run_proc(total, comax)\n    local f = function () os.runv(os.programfile(), {\"--version\"}) end\n    local t1 = os.mclock()\n    runjobs(\"test\", f, {total = total, comax = comax})\n    t1 = os.mclock() - t1\n    print(\"runjobs_proc(%d/%d): %d ms\", total, comax, t1)\nend\n\nfunction main()\n    test_run(10000, 1)\n    test_run(10000, 10)\n    test_run(10000, 100)\n    test_run_proc(1000, 10)\nend\n\n"
  },
  {
    "path": "tests/benchmarks/build_targets/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/benchmarks/build_targets/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(test)\n\nforeach(i RANGE 1 30)\n    add_executable(test${i} src/test_${i}.cpp)\nendforeach()\n"
  },
  {
    "path": "tests/benchmarks/build_targets/meson.build",
    "content": "project('test', 'cpp')\n\nforeach i : range(1, 31)\n    executable('test' + i.to_string(), 'src/test_' + i.to_string() + '.cpp')\nendforeach\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_1.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_10.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_11.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_12.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_13.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_14.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_15.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_16.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_17.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_18.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_19.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_2.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_20.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_21.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_22.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_23.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_24.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_25.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_26.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_27.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_28.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_29.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_3.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_30.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_4.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_5.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_6.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_7.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_8.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/src/test_9.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/build_targets/test.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.tool.toolchain\")\n\nfunction run_test(func)\n    local dt = os.mclock()\n    local n = 2\n    local delta = 0\n    for i = 1, n do\n        local e = func()\n        delta = delta + e\n    end\n    dt = os.mclock() - dt - delta\n    return math.floor(dt / n)\nend\n\nfunction test_build(t)\n\n    -- 20% random trigger\n    if math.random() > 0.2 then\n        return\n    end\n\n    if xmake.is_embed() then\n        return\n    end\n\n    local jobs = tostring(os.default_njob())\n\n    -- xmake\n    local xmake_dt = run_test(function()\n        local dt = os.mclock()\n        os.tryrm(\"build\")\n        os.tryrm(\".xmake\")\n        dt = os.mclock() - dt\n        os.runv(\"xmake\", {\"-j\" .. jobs})\n        return dt\n    end)\n    print(\"build targets/30: xmake: %d ms\", xmake_dt)\n\n    -- cmake\n    local cmake = find_tool(\"cmake\")\n    if cmake then\n        local cmake_default_dt = run_test(function()\n            local dt = os.mclock()\n            os.tryrm(\"build\")\n            os.mkdir(\"build\")\n            dt = os.mclock() - dt\n            os.runv(cmake.program, {\"..\"}, {curdir = \"build\"})\n            os.runv(cmake.program, {\"--build\", \".\", \"-j\" .. jobs}, {curdir = \"build\"})\n            return dt\n        end)\n        print(\"build targets/30: cmake/default: %d ms\", cmake_default_dt)\n        t:require((cmake_default_dt > xmake_dt) or (cmake_default_dt + 3000 > xmake_dt))\n\n        local ninja = find_tool(\"ninja\")\n        if ninja then\n            local configs = {}\n            local envs\n            if is_host(\"windows\") then\n                table.insert(configs, \"-DCMAKE_MAKE_PROGRAM=\" .. ninja.program)\n                local msvc = toolchain.load(\"msvc\")\n                if msvc:check() then\n                    table.insert(configs, \"-DCMAKE_CXX_COMPILER=\" .. (msvc:tool(\"cxx\")))\n                    table.insert(configs, \"-DCMAKE_C_COMPILER=\" .. (msvc:tool(\"cc\")))\n                    envs = os.joinenvs(msvc:runenvs())\n                end\n            end\n            local cmake_ninja_dt = run_test(function ()\n                local dt = os.mclock()\n                os.tryrm(\"build\")\n                os.mkdir(\"build\")\n                dt = os.mclock() - dt\n                os.runv(cmake.program, table.join(\"..\", \"-G\", \"Ninja\", configs), {curdir = \"build\", envs = envs})\n                os.runv(cmake.program, {\"--build\", \".\", \"-j\" .. jobs}, {curdir = \"build\", envs = envs})\n                return dt\n            end)\n            print(\"build targets/30: cmake/ninja: %d ms\", cmake_ninja_dt)\n            t:require((cmake_ninja_dt > xmake_dt) or (cmake_ninja_dt + 3000 > xmake_dt))\n        end\n\n        local make = find_tool(\"make\")\n        if make and not is_subhost(\"windows\") then\n            local cmake_makefile_dt = run_test(function()\n                local dt = os.mclock()\n                os.tryrm(\"build\")\n                os.mkdir(\"build\")\n                dt = os.mclock() - dt\n                os.runv(cmake.program, {\"..\", \"-G\", \"Unix Makefiles\"}, {curdir = \"build\"})\n                os.runv(cmake.program, {\"--build\", \".\", \"-j\" .. jobs}, {curdir = \"build\"})\n                return dt\n            end)\n            print(\"build targets/30: cmake/makefile: %d ms\", cmake_makefile_dt)\n            t:require((cmake_makefile_dt > xmake_dt) or (cmake_makefile_dt + 3000 > xmake_dt))\n        end\n    end\n\n    -- meson\n    local meson = find_tool(\"meson\")\n    if meson then\n        local meson_dt = run_test(function()\n            local dt1 = os.mclock()\n            os.tryrm(\"build\")\n            dt1 = os.mclock() - dt1\n            os.runv(meson.program, {\"setup\", \"build\"})\n            -- ccache will cache object files globally, which may affect the results of the second run.\n            local dt2 = os.mclock()\n            io.replace(\"build/build.ninja\", \"ccache\", \"\")\n            dt2 = os.mclock() - dt2\n            os.runv(meson.program, {\"compile\", \"-j\", jobs, \"-C\", \"build\"})\n            return dt1 + dt2\n        end)\n        print(\"build targets/30: meson: %d ms\", meson_dt)\n        t:require((meson_dt > xmake_dt) or (meson_dt + 3000 > xmake_dt))\n    end\nend\n\n\n"
  },
  {
    "path": "tests/benchmarks/build_targets/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nfor i = 1, 30 do\n    target(\"test\" .. i)\n        set_kind(\"binary\")\n        add_files(\"src/test_\" .. tostring(i) .. \".cpp\")\nend\n"
  },
  {
    "path": "tests/benchmarks/config_targets/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/benchmarks/config_targets/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(test)\n\nforeach(i RANGE 1 1000)\n    add_executable(test${i} src/main.cpp)\nendforeach()\n"
  },
  {
    "path": "tests/benchmarks/config_targets/meson.build",
    "content": "project('test', 'cpp')\n\nforeach i : range(1, 1001)\n    executable('test' + i.to_string(), 'src/main.cpp')\nendforeach\n"
  },
  {
    "path": "tests/benchmarks/config_targets/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/benchmarks/config_targets/test.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.tool.toolchain\")\n\nfunction run_test(func)\n    local dt = os.mclock()\n    local n = 2\n    local delta = 0\n    for i = 1, n do\n        local e = func()\n        delta = delta + e\n    end\n    dt = os.mclock() - dt - delta\n    return math.floor(dt / n)\nend\n\nfunction test_config(t)\n\n    -- 20% random trigger\n    if math.random() > 0.2 then\n        return\n    end\n\n    if xmake.is_embed() then\n        return\n    end\n\n    -- xmake\n    local xmake_dt = run_test(function ()\n        local dt = os.mclock()\n        os.tryrm(\"build\")\n        os.tryrm(\".xmake\")\n        dt = os.mclock() - dt\n        os.runv(\"xmake\", {\"config\", \"-c\"})\n        return dt\n    end)\n    print(\"config targets/1k: xmake: %d ms\", xmake_dt)\n\n    -- cmake\n    local cmake = find_tool(\"cmake\")\n    if cmake then\n        local cmake_default_dt = run_test(function()\n            local dt = os.mclock()\n            os.tryrm(\"build\")\n            os.mkdir(\"build\")\n            dt = os.mclock() - dt\n            os.runv(cmake.program, {\"..\"}, {curdir = \"build\"})\n            return dt\n        end)\n        print(\"config targets/1k: cmake/default: %d ms\", cmake_default_dt)\n        t:require((cmake_default_dt > xmake_dt) or (cmake_default_dt + 2000 > xmake_dt))\n\n        local ninja = find_tool(\"ninja\")\n        if ninja then\n            local configs = {}\n            local envs\n            if is_host(\"windows\") then\n                table.insert(configs, \"-DCMAKE_MAKE_PROGRAM=\" .. ninja.program)\n                local msvc = toolchain.load(\"msvc\")\n                if msvc:check() then\n                    table.insert(configs, \"-DCMAKE_CXX_COMPILER=\" .. (msvc:tool(\"cxx\")))\n                    table.insert(configs, \"-DCMAKE_C_COMPILER=\" .. (msvc:tool(\"cc\")))\n                    envs = os.joinenvs(msvc:runenvs())\n                end\n            end\n            local cmake_ninja_dt = run_test(function()\n                local dt = os.mclock()\n                os.tryrm(\"build\")\n                os.mkdir(\"build\")\n                dt = os.mclock() - dt\n                os.runv(cmake.program, table.join(\"..\", \"-G\", \"Ninja\", configs), {curdir = \"build\", envs = envs})\n                return dt\n            end)\n            print(\"config targets/1k: cmake/ninja: %d ms\", cmake_ninja_dt)\n            t:require((cmake_ninja_dt > xmake_dt) or (cmake_ninja_dt + 2000 > xmake_dt))\n        end\n\n        if find_tool(\"make\") and not is_subhost(\"windows\") then\n            local cmake_makefile_dt = run_test(function ()\n                local dt = os.mclock()\n                os.tryrm(\"build\")\n                os.mkdir(\"build\")\n                dt = os.mclock() - dt\n                os.runv(cmake.program, {\"..\", \"-G\", \"Unix Makefiles\"}, {curdir = \"build\"})\n                return dt\n            end)\n            print(\"config targets/1k: cmake/makefile: %d ms\", cmake_makefile_dt)\n            t:require((cmake_makefile_dt > xmake_dt) or (cmake_makefile_dt + 2000 > xmake_dt))\n        end\n    end\n\n    -- meson\n    local meson = find_tool(\"meson\")\n    if meson then\n        local meson_dt = run_test(function()\n            local dt = os.mclock()\n            os.tryrm(\"build\")\n            dt = os.mclock() - dt\n            os.runv(meson.program, {\"setup\", \"build\"})\n            return dt\n        end)\n        print(\"config targets/1k: meson: %d ms\", meson_dt)\n        t:require((meson_dt > xmake_dt) or (meson_dt + 2000 > xmake_dt))\n    end\nend\n\n\n"
  },
  {
    "path": "tests/benchmarks/config_targets/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nfor i = 1, 1000 do\n    target(\"test\" .. i)\n        set_kind(\"binary\")\n        add_files(\"src/main.cpp\")\nend\n"
  },
  {
    "path": "tests/benchmarks/hash.lua",
    "content": "import(\"core.base.bytes\")\n\nlocal COUNT = 1000000\n\nfunction test_md5(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10000\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.md5(data)\n    end\n    t = os.mclock() - t\n    print(\"md5(%d): %d ms, hash: %s\", COUNT, t * 10000, h)\nend\n\nfunction test_sha1(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10000\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.sha1(data)\n    end\n    t = os.mclock() - t\n    print(\"sha1(%d): %d ms, hash: %s\", COUNT, t * 10000, h)\nend\n\nfunction test_sha256(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10000\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.sha256(data)\n    end\n    t = os.mclock() - t\n    print(\"sha256(%d): %d ms, hash: %s\", COUNT, t * 10000, h)\nend\n\nfunction test_uuid(data)\n    local h\n    local n = COUNT / 10000\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.uuid(data)\n    end\n    t = os.mclock() - t\n    print(\"uuid(%d): %d ms, hash: %s\", COUNT, t * 10000, h)\nend\n\nfunction test_xxhash32(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.xxhash32(data)\n    end\n    t = os.mclock() - t\n    print(\"xxhash32(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_xxhash64(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.xxhash64(data)\n    end\n    t = os.mclock() - t\n    print(\"xxhash64(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_xxhash128(data)\n    data = bytes(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.xxhash128(data)\n    end\n    t = os.mclock() - t\n    print(\"xxhash128(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_strhash32(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.strhash32(data)\n    end\n    t = os.mclock() - t\n    print(\"strhash32(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_strhash64(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.strhash64(data)\n    end\n    t = os.mclock() - t\n    print(\"strhash64(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_strhash128(data)\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.strhash128(data)\n    end\n    t = os.mclock() - t\n    print(\"strhash128(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_random_uuid()\n    local h\n    local n = COUNT / 1000\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.uuid()\n    end\n    t = os.mclock() - t\n    print(\"uuid(%d): %d ms, hash: %s\", COUNT, t * 1000, h)\nend\n\nfunction test_rand32()\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.rand32()\n    end\n    t = os.mclock() - t\n    print(\"rand32(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_rand64()\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.rand64()\n    end\n    t = os.mclock() - t\n    print(\"rand64(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_rand128()\n    local h\n    local n = COUNT / 10\n    local t = os.mclock()\n    for i = 1, n do\n        h = hash.rand128()\n    end\n    t = os.mclock() - t\n    print(\"rand128(%d): %d ms, hash: %s\", COUNT, t * 10, h)\nend\n\nfunction test_longstr()\n    print(\"========================================== test long string ==========================================\")\n    local data = \"\"\n    for i = 1, 10000 do\n        data = data .. \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    end\n    test_md5(data)\n    test_sha1(data)\n    test_sha256(data)\n    test_uuid(data)\n    test_xxhash32(data)\n    test_xxhash64(data)\n    test_xxhash128(data)\n    test_strhash32(data)\n    test_strhash64(data)\n    test_strhash128(data)\nend\n\nfunction test_shortstr()\n    print(\"========================================== test short string ==========================================\")\n    COUNT = COUNT * 100\n    local data = \"\"\n    for i = 1, 10 do\n        data = data .. \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    end\n    test_md5(data)\n    test_sha1(data)\n    test_sha256(data)\n    test_uuid(data)\n    test_xxhash32(data)\n    test_xxhash64(data)\n    test_xxhash128(data)\n    test_strhash32(data)\n    test_strhash64(data)\n    test_strhash128(data)\nend\n\nfunction test_random()\n    print(\"========================================== test random ==========================================\")\n    test_random_uuid()\n    test_rand32()\n    test_rand64()\n    test_rand128()\nend\n\nfunction main()\n    test_longstr()\n    test_shortstr()\n    test_random()\nend\n"
  },
  {
    "path": "tests/cli/test.lua",
    "content": "import(\"core.base.cli\")\n\nfunction test_args(t)\n    local parsed = cli.parse(\"abc def\")\n    t:are_equal(#parsed, 2)\n    t:are_equal(parsed[1].type, \"arg\")\n    t:are_equal(parsed[1].value, \"abc\")\n    t:are_equal(parsed[2].type, \"arg\")\n    t:are_equal(parsed[2].value, \"def\")\nend\n\nfunction test_args_escaped(t)\n    local parsed = cli.parse([[a\\\\bc \"def \\\"g\"]])\n    t:are_equal(#parsed, 2)\n    t:are_equal(parsed[1].type, \"arg\")\n    t:are_equal(parsed[1].value, \"a\\\\bc\")\n    t:are_equal(parsed[2].type, \"arg\")\n    t:are_equal(parsed[2].value, \"def \\\"g\")\nend\n\nfunction test_long(t)\n    local parsed = cli.parse([[--long-flag --long-option=\"1 3\" --long-option:=2 args]])\n    t:are_equal(#parsed, 4)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"long-flag\")\n    t:are_equal(parsed[2].type, \"option\")\n    t:are_equal(parsed[2].key, \"long-option\")\n    t:are_equal(parsed[2].value, \"1 3\")\n    t:are_equal(parsed[3].type, \"option\")\n    t:are_equal(parsed[3].key, \"long-option\")\n    t:are_equal(parsed[3].value, \"=2\")\nend\n\nfunction test_raw(t)\n    local parsed = cli.parse([[--long-flag -- --long-option=\"1 3\" --long-option:=2 args -rx]])\n    t:are_equal(#parsed, 6)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"long-flag\")\n    t:are_equal(parsed[2].type, \"sep\")\n    t:are_equal(parsed[3].type, \"arg\")\n    t:are_equal(parsed[3].value, \"--long-option=1 3\")\n    t:are_equal(parsed[4].type, \"arg\")\n    t:are_equal(parsed[4].value, \"--long-option:=2\")\n    t:are_equal(parsed[5].type, \"arg\")\n    t:are_equal(parsed[5].value, \"args\")\n    t:are_equal(parsed[6].type, \"arg\")\n    t:are_equal(parsed[6].value, \"-rx\")\nend\n\nfunction test_short1(t)\n    local parsed = cli.parse([[-rx args -args]], {})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"option\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[1].value, \"x\")\n    t:are_equal(parsed[3].type, \"arg\")\n    t:are_equal(parsed[3].value, \"-args\")\nend\n\nfunction test_short2(t)\n    local parsed = cli.parse([[-r x args args]], {})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"option\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[1].value, \"x\")\nend\n\nfunction test_short3(t)\n    local parsed = cli.parse([[-r\"x d\" args args]], {})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"option\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[1].value, \"x d\")\nend\n\nfunction test_short4(t)\n    local parsed = cli.parse([[\"-rx d\" args args]], {})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"option\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[1].value, \"x d\")\nend\n\nfunction test_short5(t)\n    local parsed = cli.parse([[-r \"x d\" args args]], {})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"option\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[1].value, \"x d\")\nend\n\n\nfunction test_short_flags1(t)\n    local parsed = cli.parse([[-rx args args]], {\"r\"})\n    t:are_equal(#parsed, 3)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[2].type, \"option\")\n    t:are_equal(parsed[2].key, \"x\")\n    t:are_equal(parsed[2].value, \"args\")\nend\n\nfunction test_short_flags2(t)\n    local parsed = cli.parse([[-r x args args]], {\"r\"})\n    t:are_equal(#parsed, 4)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[2].type, \"arg\")\n    t:are_equal(parsed[2].value, \"x\")\nend\n\nfunction test_short_flags3(t)\n    local parsed = cli.parse([[-r\"x d\" args args]], {\"r\"})\n    t:are_equal(#parsed, 4)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[2].type, \"option\")\n    t:are_equal(parsed[2].key, \"x\")\n    t:are_equal(parsed[2].value, \" d\")\nend\n\nfunction test_short_flags4(t)\n    local parsed = cli.parse([[\"-rx d\" args args]], {\"r\"})\n    t:are_equal(#parsed, 4)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[2].type, \"option\")\n    t:are_equal(parsed[2].key, \"x\")\n    t:are_equal(parsed[2].value, \" d\")\nend\n\nfunction test_short_flags5(t)\n    local parsed = cli.parse([[-r \"x d\" args args]], {\"r\"})\n    t:are_equal(#parsed, 4)\n    t:are_equal(parsed[1].type, \"flag\")\n    t:are_equal(parsed[1].key, \"r\")\n    t:are_equal(parsed[2].type, \"arg\")\n    t:are_equal(parsed[2].value, \"x d\")\nend\n"
  },
  {
    "path": "tests/cli/utils/test.lua",
    "content": "function test_version(t)\n    local output = os.iorunv(\"xmake\", {\"--version\"})\n    local vstr = output:match(\"xmake v(.-),\")\n    t:are_equal(vstr, tostring(xmake.version()))\nend\n\nfunction test_help(t)\n    import(\"core.base.task\")\n    for _, taskname in ipairs(task.names()) do\n        os.runv(\"xmake\", {taskname, \"--help\"})\n    end\nend\n"
  },
  {
    "path": "tests/modules/async/run_callback.lua",
    "content": "import(\"core.base.scheduler\")\nimport(\"async.runjobs\")\n\nfunction _jobfunc(index, total, opt)\n    print(\"%s: run job (%d/%d)\", scheduler.co_running(), index, total)\n    local dt = os.mclock()\n    os.sleep(1000)\n    dt = os.mclock() - dt\n    print(\"%s: run job (%d/%d) end, progress: %s, dt: %d ms\", scheduler.co_running(), index, total, opt.progress, dt)\nend\n\nfunction main()\n    print(\"==================================== test callback ====================================\")\n    local t = os.mclock()\n    runjobs(\"test\", _jobfunc, {total = 100, comax = 6, timeout = 1000, timer = function (running_jobs_indices)\n        print(\"%s: timeout (%d ms), running: %s\", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, \",\"))\n    end})\nend\n\n"
  },
  {
    "path": "tests/modules/async/run_jobgraph.lua",
    "content": "import(\"core.base.scheduler\")\nimport(\"async.jobgraph\")\nimport(\"async.runjobs\")\n\nfunction _jobfunc(index, total, opt)\n    print(\"%s: run job (%d/%d)\", scheduler.co_running(), index, total)\n    local dt = os.mclock()\n    os.sleep(1000)\n    dt = os.mclock() - dt\n    print(\"%s: run job (%d/%d) end, progress: %s, dt: %d ms\", scheduler.co_running(), index, total, opt.progress, dt)\nend\n\nfunction _test_basic()\n    print(\"==================================== test basic ====================================\")\n    local jobs = jobgraph.new()\n    jobs:add(\"job/root\", _jobfunc)\n    for i = 1, 3 do\n        jobs:add(\"job/\" .. i, _jobfunc)\n        for j = 1, 50 do\n            jobs:add(\"job/\" .. i .. \"/\" .. j, _jobfunc)\n            jobs:add_orders(\"job/\" .. i .. \"/\" .. j, \"job/\" .. i, \"job/root\")\n        end\n    end\n    t = os.mclock()\n    runjobs(\"test\", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices)\n        print(\"%s: timeout (%d ms), running: %s\", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, \",\"))\n    end})\nend\n\nfunction _test_group()\n    print(\"==================================== test group ====================================\")\n    local jobs = jobgraph.new()\n    jobs:add(\"job/root\", _jobfunc)\n    for i = 1, 3 do\n        jobs:add(\"job/\" .. i, _jobfunc, {groups = \"bar\"})\n        jobs:group(\"foo\", function ()\n            for j = 1, 50 do\n                jobs:add(\"job/\" .. i .. \"/\" .. j, _jobfunc)\n            end\n        end)\n    end\n    jobs:add_orders(\"foo\", \"bar\", \"job/root\")\n    t = os.mclock()\n    runjobs(\"test\", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices)\n        print(\"%s: timeout (%d ms), running: %s\", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, \",\"))\n    end})\nend\n\nfunction main()\n    _test_basic()\n    _test_group()\nend\n\n"
  },
  {
    "path": "tests/modules/async/run_jobpool.lua",
    "content": "import(\"core.base.scheduler\")\nimport(\"private.async.jobpool\")\nimport(\"async.runjobs\")\n\nfunction _jobfunc(index, total, opt)\n    print(\"%s: run job (%d/%d)\", scheduler.co_running(), index, total)\n    local dt = os.mclock()\n    os.sleep(1000)\n    dt = os.mclock() - dt\n    print(\"%s: run job (%d/%d) end, progress: %s, dt: %d ms\", scheduler.co_running(), index, total, opt.progress, dt)\nend\n\nfunction main()\n    print(\"==================================== test jobpool ====================================\")\n    local jobs = jobpool.new()\n    local root = jobs:addjob(\"job/root\", _jobfunc)\n    for i = 1, 3 do\n        local job = jobs:addjob(\"job/\" .. i, _jobfunc, {rootjob = root})\n        for j = 1, 50 do\n            jobs:addjob(\"job/\" .. i .. \"/\" .. j, _jobfunc, {rootjob = job})\n        end\n    end\n    t = os.mclock()\n    runjobs(\"test\", jobs, {comax = 6, timeout = 1000, timer = function (running_jobs_indices)\n        print(\"%s: timeout (%d ms), running: %s\", scheduler.co_running(), os.mclock() - t, table.concat(running_jobs_indices, \",\"))\n    end})\nend\n\n"
  },
  {
    "path": "tests/modules/binutils/test.lua",
    "content": "import(\"core.base.binutils\")\n\nfunction test_format(t)\n    local tempdir = \"temp/binutils_format\"\n    os.tryrm(tempdir)\n    os.mkdir(tempdir)\n\n    local unknown = path.join(tempdir, \"unknown.bin\")\n    io.writefile(unknown, \"12345678\")\n    local format = binutils.format(unknown)\n    t:are_equal(format, \"unknown\")\n\n    local scriptfile = path.join(tempdir, \"a.sh\")\n    io.writefile(scriptfile, \"#!/bin/sh\\nexit 0\\n\")\n    t:are_equal(binutils.format(scriptfile), \"shebang\")\n\n    local apefile = path.join(tempdir, \"a.ape\")\n    io.writefile(apefile, \"MZqFpD00\")\n    t:are_equal(binutils.format(apefile), \"ape\")\n\n    local apecom = path.join(tempdir, \"a.com\")\n    io.writefile(apecom, \"MZqFpD00\")\n    t:are_equal(binutils.format(apecom), \"ape\")\n\n    local comfile = path.join(tempdir, \"b.com\")\n    io.writefile(comfile, \"12345678\")\n    t:are_equal(binutils.format(comfile), \"unknown\")\n\n    local programfile = os.programfile()\n    if programfile then\n        local expected = \"elf\"\n        if is_host(\"windows\") then\n            expected = \"pe\"\n        elseif is_host(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n            expected = \"macho\"\n        end\n        local format = binutils.format(programfile)\n        if format ~= \"ape\" then\n            t:are_equal(format, expected)\n        end\n    end\n\n    local ar = path.join(tempdir, \"a.a\")\n    io.writefile(ar, \"!<arch>\\n\")\n    t:are_equal(binutils.format(ar), \"ar\")\n\n    local wasmso = path.join(tempdir, \"libfoo.so\")\n    io.writefile(wasmso, string.char(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00))\n    t:are_equal(binutils.format(wasmso), \"wasm\")\n\n    local elf = path.join(tempdir, \"a.elf\")\n    io.writefile(elf, string.char(0x7f, string.byte(\"E\"), string.byte(\"L\"), string.byte(\"F\"), 0, 0, 0, 0))\n    t:are_equal(binutils.format(elf), \"elf\")\n\n    local macho = path.join(tempdir, \"a.macho\")\n    io.writefile(macho, string.char(0xfe, 0xed, 0xfa, 0xcf, 0, 0, 0, 0))\n    t:are_equal(binutils.format(macho), \"macho\")\n\n    local coff = path.join(tempdir, \"a.obj\")\n    io.writefile(coff, string.char(0x4c, 0x01, 0, 0, 0, 0, 0, 0))\n    t:are_equal(binutils.format(coff), \"coff\")\n\n    local pefile = path.join(tempdir, \"a.exe\")\n    local pe = {}\n    for _ = 1, 0x44 do\n        table.insert(pe, 0)\n    end\n    pe[1] = string.byte(\"M\")\n    pe[2] = string.byte(\"Z\")\n    pe[0x3c + 1] = 0x40\n    pe[0x3c + 2] = 0\n    pe[0x3c + 3] = 0\n    pe[0x3c + 4] = 0\n    pe[0x40 + 1] = string.byte(\"P\")\n    pe[0x40 + 2] = string.byte(\"E\")\n    pe[0x40 + 3] = 0\n    pe[0x40 + 4] = 0\n    io.writefile(pefile, string.char(table.unpack(pe)))\n    t:are_equal(binutils.format(pefile), \"pe\")\n\n    os.tryrm(tempdir)\nend\n\nfunction test_deplibs(t)\n    local tempdir = \"temp/binutils_deplibs\"\n    os.tryrm(tempdir)\n    os.mkdir(tempdir)\n\n    local wasmso = path.join(tempdir, \"libfoo.so\")\n    io.writefile(wasmso, string.char(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00))\n    local libs = binutils.deplibs(wasmso)\n    t:are_equal(#libs, 0)\n\n    os.tryrm(tempdir)\nend\n\nfunction test_readsyms(t)\n    local tempdir = \"temp/binutils_readsyms\"\n    os.tryrm(tempdir)\n    os.mkdir(tempdir)\n\n    local function _writebin(filepath, data)\n        io.writefile(filepath, data, {encoding = \"binary\"})\n    end\n\n    local wasmso = path.join(tempdir, \"libfoo.so\")\n    _writebin(wasmso, string.char(\n        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,\n        0x02, 0x0b, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x62, 0x61, 0x72, 0x00, 0x00,\n        0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00))\n    local results = binutils.readsyms(wasmso)\n    t:are_equal(#results, 1)\n    t:are_equal(results[1].objectfile, \"libfoo.so\")\n    t:are_equal(#results[1].symbols, 2)\n    t:are_equal(results[1].symbols[1].name, \"bar\")\n    t:are_equal(results[1].symbols[1].type, \"U\")\n    t:are_equal(results[1].symbols[2].name, \"foo\")\n    t:are_equal(results[1].symbols[2].type, \"T\")\n\n    local wasmso64 = path.join(tempdir, \"libfoo64.so\")\n    _writebin(wasmso64, string.char(\n        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,\n        0x02, 0x0c, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x6d, 0x65, 0x6d, 0x02, 0x04, 0x01,\n        0x07, 0x07, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x00, 0x00))\n    local results64 = binutils.readsyms(wasmso64)\n    t:are_equal(#results64, 1)\n    t:are_equal(results64[1].objectfile, \"libfoo64.so\")\n    t:are_equal(#results64[1].symbols, 2)\n    t:are_equal(results64[1].symbols[1].name, \"mem\")\n    t:are_equal(results64[1].symbols[1].type, \"U\")\n    t:are_equal(results64[1].symbols[2].name, \"foo\")\n    t:are_equal(results64[1].symbols[2].type, \"T\")\n\n    local wasmlink = path.join(tempdir, \"liblink.so\")\n    _writebin(wasmlink, string.char(\n        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,\n        0x01, 0x04, 0x01, 0x60, 0x00, 0x00,\n        0x03, 0x02, 0x01, 0x00,\n        0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,\n        0x00, 0x13, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x02, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x03, 0x61, 0x64, 0x64))\n    local resultslink = binutils.readsyms(wasmlink)\n    t:are_equal(#resultslink, 1)\n    t:are_equal(resultslink[1].objectfile, \"liblink.so\")\n    t:are_equal(#resultslink[1].symbols, 1)\n    t:are_equal(resultslink[1].symbols[1].name, \"add\")\n    t:are_equal(resultslink[1].symbols[1].type, \"T\")\n\n    local wasmar = path.join(tempdir, \"libbar.a\")\n    local function _pad(str, n)\n        if #str < n then\n            return str .. string.rep(\" \", n - #str)\n        end\n        return str:sub(1, n)\n    end\n    local function _ar_header(name, size)\n        return _pad(name, 16) ..\n               _pad(\"0\", 12) ..\n               _pad(\"0\", 6) ..\n               _pad(\"0\", 6) ..\n               _pad(\"644\", 8) ..\n               _pad(tostring(size), 10) ..\n               \"`\\n\"\n    end\n    local wasmobj = string.char(\n        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,\n        0x01, 0x04, 0x01, 0x60, 0x00, 0x00,\n        0x03, 0x02, 0x01, 0x00,\n        0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,\n        0x00, 0x13, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x02, 0x08, 0x08, 0x01, 0x00, 0x00, 0x00, 0x03, 0x61, 0x64, 0x64)\n    local symtab = string.char(0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50) .. \"add\\0\"\n    local ardata = \"!<arch>\\n\" ..\n                   _ar_header(\"/\", #symtab) .. symtab .. ((#symtab % 2 == 1) and \"\\n\" or \"\") ..\n                   _ar_header(\"foo.cpp.o/\", #wasmobj) .. wasmobj .. ((#wasmobj % 2 == 1) and \"\\n\" or \"\")\n    _writebin(wasmar, ardata)\n    local resultsar = binutils.readsyms(wasmar)\n    t:are_equal(#resultsar, 1)\n    t:are_equal(resultsar[1].objectfile, \"foo.cpp.o\")\n    t:are_equal(#resultsar[1].symbols, 1)\n    t:are_equal(resultsar[1].symbols[1].name, \"add\")\n    t:are_equal(resultsar[1].symbols[1].type, \"T\")\n\n    os.tryrm(tempdir)\nend\n"
  },
  {
    "path": "tests/modules/bloom_filter/test.lua",
    "content": "import(\"core.base.bloom_filter\")\n\nfunction test_bloom_filter(t)\n    local filter = bloom_filter.new()\n    t:are_equal(filter:set(\"hello\"), true) -- not found\n    t:are_equal(filter:set(\"hello\"), false)\n    t:are_equal(filter:set(\"hello\"), false)\n    t:are_equal(filter:get(\"hello\"), true)\n\n    t:are_equal(filter:set(\"xmake\"), true) -- not found\n    t:are_equal(filter:set(\"xmake\"), false)\n    t:are_equal(filter:set(\"xmake\"), false)\n    t:are_equal(filter:get(\"xmake\"), true)\n\n    t:are_equal(filter:get(\"not exists\"), false)\n\n    local data = filter:data()\n    local filter2 = bloom_filter.new()\n    filter2:data_set(data)\n    t:are_equal(filter2:get(\"hello\"), true)\n    t:are_equal(filter2:get(\"xmake\"), true)\n    t:are_equal(filter2:get(\"not exists\"), false)\nend\n\n"
  },
  {
    "path": "tests/modules/bytes/test.lua",
    "content": "import(\"core.base.bytes\")\n\nfunction test_ctor(t)\n    t:are_equal(bytes(\"123456789\"):str(), \"123456789\")\n    t:are_equal(bytes(bytes(\"123456789\")):str(), \"123456789\")\n    t:are_equal(bytes(bytes(\"123456789\"), 3, 5):str(), \"345\")\n    t:are_equal(bytes(\"123456789\"):size(), 9)\n    t:are_equal(bytes(10):size(), 10)\n    t:are_equal(bytes(bytes(\"123\"), bytes(\"456\"), bytes(\"789\")):str(), \"123456789\")\n    t:are_equal(bytes({bytes(\"123\"), bytes(\"456\"), bytes(\"789\")}):str(), \"123456789\")\nend\n\nfunction test_clone(t)\n    t:are_equal(bytes(10):clone():size(), 10)\n    t:are_equal(bytes(\"123456789\"):clone():str(), \"123456789\")\nend\n\nfunction test_slice(t)\n    t:are_equal(bytes(10):slice(1, 2):size(), 2)\n    t:are_equal(bytes(\"123456789\"):slice(1, 4):str(), \"1234\")\nend\n\nfunction test_index(t)\n    local b = bytes(\"123456789\")\n    t:are_equal(b[{1, 4}]:str(), \"1234\")\n    t:will_raise(function() b[1] = string.byte('2') end)\n    b = bytes(9)\n    b[{1, 9}] = bytes(\"123456789\")\n    t:are_equal(b:str(), \"123456789\")\n    b[1] = string.byte('2')\n    t:are_equal(b:str(), \"223456789\")\n    t:will_raise(function() b[100] = string.byte('2') end)\nend\n\nfunction test_concat(t)\n    t:are_equal((bytes(\"123\") .. bytes(\"456\")):str(), \"123456\")\n    t:are_equal(bytes(bytes(\"123\"), bytes(\"456\")):str(), \"123456\")\nend\n\nfunction test_copy(t)\n    t:are_equal(bytes(9):copy(\"123456789\"):str(), \"123456789\")\n    t:are_equal(bytes(5):copy(\"123456789\", 5, 9):str(), \"56789\")\nend\n\nfunction test_copy2(t)\n    t:are_equal(bytes(18):copy(\"123456789\"):copy2(10, \"123456789\"):str(), \"123456789123456789\")\n    t:are_equal(bytes(14):copy(\"123456789\"):copy2(10, \"123456789\", 5, 9):str(), \"12345678956789\")\nend\n\nfunction test_move(t)\n    t:are_equal(bytes(9):copy(\"123456789\"):move(5, 9):str(), \"567896789\")\n    t:are_equal(bytes(9):copy(\"123456789\"):move2(2, 5, 9):str(), \"156789789\")\nend\n\nfunction test_int(t)\n    t:are_equal(bytes(1):u8_set(1, 1):u8(1), 1)\n    t:are_equal(bytes(10):u8_set(5, 255):u8(5), 255)\n    t:are_equal(bytes(10):u16le_set(5, 12346):u16le(5), 12346)\n    t:are_equal(bytes(10):u16be_set(5, 12346):u16be(5), 12346)\n    t:are_equal(bytes(20):u32le_set(5, 12345678):u32le(5), 12345678)\n    t:are_equal(bytes(20):u32be_set(5, 12345678):u32be(5), 12345678)\nend\n\n"
  },
  {
    "path": "tests/modules/cache/test.lua",
    "content": "import(\"core.cache.memcache\")\nimport(\"core.cache.localcache\")\nimport(\"core.cache.globalcache\")\n\nfunction test_memcache(t)\n    memcache.set(\"mycache\", \"xyz\", {1, 2, 3})\n    memcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    t:are_equal(memcache.get(\"mycache\", \"xyz\"), {1, 2, 3})\n    t:are_equal(memcache.get2(\"mycache\", \"foo\", \"bar\"), \"1\")\n    memcache.clear(\"mycache\")\n    t:are_equal(memcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\n    memcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    memcache.clear()\n    t:are_equal(memcache.get(\"mycache\", \"xyz\"), nil)\n    t:are_equal(memcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\nend\n\nfunction test_localcache(t)\n    localcache.set(\"mycache\", \"xyz\", {1, 2, 3})\n    localcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    t:are_equal(localcache.get(\"mycache\", \"xyz\"), {1, 2, 3})\n    t:are_equal(localcache.get2(\"mycache\", \"foo\", \"bar\"), \"1\")\n    localcache.clear(\"mycache\")\n    t:are_equal(localcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\n    localcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    localcache.clear()\n    t:are_equal(localcache.get(\"mycache\", \"xyz\"), nil)\n    t:are_equal(localcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\nend\n\nfunction test_globalcache(t)\n    globalcache.set(\"mycache\", \"xyz\", {1, 2, 3})\n    globalcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    t:are_equal(globalcache.get(\"mycache\", \"xyz\"), {1, 2, 3})\n    t:are_equal(globalcache.get2(\"mycache\", \"foo\", \"bar\"), \"1\")\n    globalcache.clear(\"mycache\")\n    t:are_equal(globalcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\n    globalcache.set2(\"mycache\", \"foo\", \"bar\", \"1\")\n    globalcache.clear()\n    t:are_equal(globalcache.get(\"mycache\", \"xyz\"), nil)\n    t:are_equal(globalcache.get2(\"mycache\", \"foo\", \"bar\"), nil)\nend\n"
  },
  {
    "path": "tests/modules/compress/test.lua",
    "content": "import(\"core.compress.lz4\")\n\nfunction test_lz4(t)\n    t:are_equal(lz4.decompress(lz4.compress(\"hello world\")):str(), \"hello world\")\n    t:are_equal(lz4.block_decompress(lz4.block_compress(\"hello world\"), 11):str(), \"hello world\")\n    local srcfile = os.tmpfile() .. \".src\"\n    local dstfile = os.tmpfile() .. \".dst\"\n    local dstfile2 = os.tmpfile() .. \".dst2\"\n    io.writefile(srcfile, \"hello world\")\n    lz4.compress_file(srcfile, dstfile)\n    lz4.decompress_file(dstfile, dstfile2)\n    t:are_equal(io.readfile(srcfile), io.readfile(dstfile2))\nend\n\n"
  },
  {
    "path": "tests/modules/devel/git/test.lua",
    "content": "import(\"devel.git\")\n\n\nfunction test_asgiturl(t)\n    t:are_equal(git.asgiturl(\"http://github.com/a/b\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"http://github.com/a/b/\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"HTTP://github.com//a/b/\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"http://github.com//a/b/s\"), nil)\n    t:are_equal(git.asgiturl(\"https://github.com/a/b\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"https://github.com/a/b.git\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"HTTPS://GITHUB.com/a/b.git.git\"), \"https://github.com/a/b.git.git\")\n\n    t:are_equal(git.asgiturl(\"github:a/b\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"github:a/b.git\"), \"https://github.com/a/b.git.git\")\n    t:are_equal(git.asgiturl(\"GitHub://a/b/\"), \"https://github.com/a/b.git\")\n    t:are_equal(git.asgiturl(\"github:a/b/c\"), nil)\nend"
  },
  {
    "path": "tests/modules/fwatcher/on_created.lua",
    "content": "import(\"core.base.fwatcher\")\n\nfunction main(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.on_created(watchdir, function (filepath)\n        print(filepath, \"created\")\n    end)\nend\n"
  },
  {
    "path": "tests/modules/fwatcher/on_deleted.lua",
    "content": "import(\"core.base.fwatcher\")\n\nfunction main(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.on_deleted(watchdir, function (filepath)\n        print(filepath, \"deleted\")\n    end)\nend\n"
  },
  {
    "path": "tests/modules/fwatcher/on_modified.lua",
    "content": "import(\"core.base.fwatcher\")\n\nfunction main(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.on_modified(watchdir, function (filepath)\n        print(filepath, \"modified\")\n    end)\nend\n"
  },
  {
    "path": "tests/modules/fwatcher/sched_watchdir.lua",
    "content": "import(\"core.base.fwatcher\")\nimport(\"core.base.scheduler\")\n\nfunction _watch(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.add(watchdir)\n    while true do\n        local ok, event = fwatcher.wait(-1)\n        if ok > 0 then\n            print(event)\n        end\n    end\nend\n\nfunction _sleep()\n    while true do\n        print(\"sleep ..\")\n        os.sleep(1000)\n    end\nend\n\nfunction main(watchdir)\n    scheduler.co_start(_watch, watchdir)\n    scheduler.co_start(_sleep)\nend\n"
  },
  {
    "path": "tests/modules/fwatcher/watchdir.lua",
    "content": "import(\"core.base.fwatcher\")\n\nfunction main(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.add(watchdir)\n    while true do\n        local ok, event = fwatcher.wait(-1)\n        if ok > 0 then\n            print(event)\n        end\n    end\nend\n"
  },
  {
    "path": "tests/modules/fwatcher/watchdirs.lua",
    "content": "import(\"core.base.fwatcher\")\n\nfunction main(watchdir)\n    print(\"watch %s ..\", watchdir)\n    fwatcher.watchdirs(watchdir, function (event)\n        local status\n        if event.type == fwatcher.ET_CREATE then\n            status = \"created\"\n        elseif event.type == fwatcher.ET_MODIFY then\n            status = \"modified\"\n        elseif event.type == fwatcher.ET_DELETE then\n            status = \"deleted\"\n        end\n        print(event.path, status)\n    end)\nend\n"
  },
  {
    "path": "tests/modules/graph/test.lua",
    "content": "import(\"core.base.graph\")\n\nfunction test_topo_sort(t)\n    local edges = {\n        {0, 5},\n        {0, 2},\n        {0, 1},\n        {3, 6},\n        {3, 5},\n        {3, 4},\n        {5, 4},\n        {6, 4},\n        {6, 0},\n        {3, 2},\n        {1, 4},\n    }\n    local dag = graph.new(true)\n    for _, e in ipairs(edges) do\n        dag:add_edge(e[1], e[2])\n    end\n    local order_path = dag:topo_sort()\n    local orders = {}\n    for i, v in ipairs(order_path) do\n        orders[v] = i\n    end\n    for _, e in ipairs(edges) do\n        t:require(orders[e[1]] < orders[e[2]])\n    end\n\n    dag = dag:reverse()\n    order_path = dag:topo_sort()\n    orders = {}\n    for i, v in ipairs(order_path) do\n        orders[v] = i\n    end\n    for _, e in ipairs(edges) do\n        t:require(orders[e[1]] > orders[e[2]])\n    end\nend\n\nfunction test_paritail_topo_sort(t)\n    local function partiail_topo_sort(dag)\n        dag:partial_topo_sort_reset()\n\n        local node, has_cycle\n        local order_vertices = {}\n        while true do\n            node, has_cycle = dag:partial_topo_sort_next()\n            if node then\n                table.insert(order_vertices, node)\n                dag:partial_topo_sort_remove(node)\n            else\n                if has_cycle then\n                    raise(\"has cycle!\")\n                end\n                break\n            end\n        end\n\n        return order_vertices, has_cycle\n    end\n\n    local edges = {\n        {0, 5},\n        {0, 2},\n        {0, 1},\n        {3, 6},\n        {3, 5},\n        {3, 4},\n        {5, 4},\n        {6, 4},\n        {6, 0},\n        {3, 2},\n        {1, 4},\n        {2, 9},\n    }\n    local dag = graph.new(true)\n    for _, e in ipairs(edges) do\n        dag:add_edge(e[1], e[2])\n    end\n    local order_path = partiail_topo_sort(dag)\n    local orders = {}\n    for i, v in ipairs(order_path) do\n        orders[v] = i\n    end\n    for _, e in ipairs(edges) do\n        t:require(orders[e[1]] < orders[e[2]])\n    end\n\n    dag = dag:reverse()\n    order_path = partiail_topo_sort(dag)\n    orders = {}\n    for i, v in ipairs(order_path) do\n        orders[v] = i\n    end\n    for _, e in ipairs(edges) do\n        t:require(orders[e[1]] > orders[e[2]])\n    end\nend\n\nfunction test_paritail_topo_sort_dynamic(t)\n    local function partiail_topo_sort(dag)\n        dag:partial_topo_sort_reset()\n\n        local node, has_cycle\n        local order_vertices = {}\n        local dynamic_adjust = false\n        while true do\n            node, has_cycle = dag:partial_topo_sort_next()\n            if node then\n                if not dynamic_adjust then\n                    dag:add_edge(1, 4)\n                    dag:remove_vertex(6)\n                end\n                table.insert(order_vertices, node)\n                dag:partial_topo_sort_remove(node)\n                if not dynamic_adjust then\n                    dag:add_edge(2, 9)\n                    dynamic_adjust = true\n                end\n            else\n                if has_cycle then\n                    raise(\"has cycle!\")\n                end\n                break\n            end\n        end\n\n        assert(#order_vertices == #dag:vertices(), \"vertices count not matched, %d != %d\", #order_vertices, #dag:vertices())\n        return order_vertices, has_cycle\n    end\n\n    local edges = {\n        {0, 5},\n        {0, 2},\n        {0, 1},\n        {3, 6},\n        {3, 5},\n        {3, 4},\n        {5, 4},\n        {6, 4},\n        {6, 0},\n        {3, 2},\n    }\n    local dag = graph.new(true)\n    for _, e in ipairs(edges) do\n        dag:add_edge(e[1], e[2])\n    end\n    local order_path = partiail_topo_sort(dag)\n    local orders = {}\n    for i, v in ipairs(order_path) do\n        orders[v] = i\n    end\n    edges = {\n        {0, 5},\n        {0, 2},\n        {0, 1},\n        -- {3, 6},\n        {3, 5},\n        {3, 4},\n        {5, 4},\n        -- {6, 4},\n        -- {6, 0},\n        {3, 2},\n        {1, 4},\n        {2, 9}\n    }\n    for _, e in ipairs(edges) do\n        t:require(orders[e[1]] < orders[e[2]])\n    end\nend\n\nfunction test_remove_edge_and_vertex(t)\n    local gh = graph.new(true)\n    gh:add_edge(\"a\", \"b\")\n    gh:add_edge(\"b\", \"c\")\n    gh:add_edge(\"c\", \"d\")\n    gh:add_edge(\"a\", \"d\")\n\n    t:require(gh:has_edge(\"a\", \"b\"))\n    gh:remove_edge(\"a\", \"b\")\n    t:require(not gh:has_edge(\"a\", \"b\"))\n    t:require(gh:has_edge(\"a\", \"d\"))\n\n    gh:remove_vertex(\"c\")\n    t:require(not gh:has_edge(\"b\", \"c\"))\n    t:require(not gh:has_edge(\"c\", \"d\"))\n    t:are_equal(#gh:vertices(), 3)\n    local order = gh:topo_sort()\n    t:require(#order == 3)\n\n    gh:add_edge(\"b\", \"a\")\n    gh:add_edge(\"d\", \"b\")\n    local _, has_cycle = gh:topo_sort()\n    t:require(has_cycle)\nend\n\nfunction test_clone_reverse_undirected(t)\n    local ug = graph.new(false)\n    ug:add_edge(1, 2)\n    ug:add_edge(2, 3)\n    ug:add_edge(3, 1)\n\n    local clone = ug:clone()\n    t:require(#clone:edges() == #ug:edges())\n    t:require(clone:has_edge(1, 2))\n    t:require(clone:has_edge(2, 1))\n\n    local rev = ug:reverse()\n    t:require(rev:has_edge(1, 2))\n    t:require(rev:has_edge(2, 1))\n    t:require(#rev:edges() == #ug:edges())\nend\n\nfunction test_find_cycle(t)\n    local edges = {\n        {9, 1},\n        {1, 6},\n        {6, 0},\n        {0, 1},\n        {4, 5}\n    }\n    local dag = graph.new(true)\n    for _, e in ipairs(edges) do\n        dag:add_edge(e[1], e[2])\n    end\n    local cycle = dag:find_cycle()\n    t:are_equal(cycle, {1, 6, 0})\n\n    local _, has_cycle = dag:topo_sort()\n    t:require(has_cycle)\nend\n\n"
  },
  {
    "path": "tests/modules/hash/test.lua",
    "content": "function test_rand32(t)\n    local set = {}\n    for i = 1, 1000 do\n        local r = hash.rand32()\n        t:require(set[r] == nil)\n        set[r] = r\n    end\nend\n\nfunction test_rand64(t)\n    local set = {}\n    for i = 1, 100000 do\n        local r = hash.rand64()\n        t:require(set[r] == nil)\n        set[r] = r\n    end\nend\n\nfunction test_rand128(t)\n    local set = {}\n    for i = 1, 100000 do\n        local r = hash.rand128()\n        t:require(set[r] == nil)\n        set[r] = r\n    end\nend\n\n"
  },
  {
    "path": "tests/modules/hashset/test.lua",
    "content": "import(\"core.base.hashset\")\n\nfunction test_hashset(t)\n    local h = hashset.of(1, 2, 3, 5, 5, 7, 1, 9, 4, 6, 8, 0)\n    t:require(h:size() == 10)\n    t:require_not(h:empty())\n    for item in h:items() do\n        t:require(h:has(item))\n        t:require_not(h:has(item + 10))\n    end\n    local prev = -1\n    for item in h:orderitems() do\n        t:require(item > prev)\n        prev = item\n    end\n    local h2 = h:clone()\n    t:require(h == h2)\n    h2:insert(11)\n    t:require_not(h == h2)\n    h2:remove(11)\n    t:require(h == h2)\n    h2:clear()\n    t:require(h2:empty())\n    t:require(h == hashset.from(h:to_array()))\nend\n\n"
  },
  {
    "path": "tests/modules/heap/test.lua",
    "content": "import(\"core.base.heap\")\n\nfunction test_cdataheap(t)\n    if not xmake.luajit() then\n        return\n    end\n    local h = heap.cdataheap{\n        size = 100,\n        ctype = [[\n            struct {\n                int priority;\n                int order;\n            }\n        ]],\n        cmp = function(a, b)\n            if a.priority == b.priority then\n                return a.order > b.order\n            end\n            return a.priority < b.priority\n        end}\n    h:push{priority = 20, order = 1}\n    h:push{priority = 10, order = 2}\n    h:push{priority = 10, order = 3}\n    h:push{priority = 20, order = 4}\n    t:are_equal(h:pop().order, 3)\n    t:are_equal(h:pop().order, 2)\n    t:are_equal(h:pop().order, 4)\n    t:are_equal(h:pop().order, 1)\nend\n\nfunction test_valueheap(t)\n    local h = heap.valueheap{cmp = function(a, b)\n          return a.priority < b.priority\n       end}\n    h:push{priority = 20, etc = 'bar'}\n    h:push{priority = 10, etc = 'foo'}\n    t:are_equal(h:pop().priority, 10)\n    t:are_equal(h:pop().priority, 20)\nend\n\n"
  },
  {
    "path": "tests/modules/hello/test.lua",
    "content": "\nfunction test_hello(context)\n    print(\"hello\")\nend\n"
  },
  {
    "path": "tests/modules/io/files/.gitattributes",
    "content": "* binary"
  },
  {
    "path": "tests/modules/io/files/utf8-crlf-neleof",
    "content": "123\\\r\n456\r\n789"
  },
  {
    "path": "tests/modules/io/files/utf8-longline-eleof",
    "content": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
  },
  {
    "path": "tests/modules/io/files/utf8-longline-neleof",
    "content": "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
  },
  {
    "path": "tests/modules/io/files/utf8bom-lf-eleof",
    "content": "﻿123\\\n456\n789\n"
  },
  {
    "path": "tests/modules/io/test.lua",
    "content": "function test_read(t)\n    t:are_equal(io.readfile(\"files/utf8bom-lf-eleof\"), \"123\\\\\\n456\\n789\\n\")\n    t:are_equal(io.readfile(\"files/utf8-crlf-neleof\"), \"123\\\\\\n456\\n789\")\n    t:are_equal(io.readfile(\"files/utf8-crlf-neleof\", {encoding = \"binary\"}), \"123\\\\\\r\\n456\\r\\n789\")\n    t:are_equal(io.readfile(\"files/utf8-crlf-neleof\", {continuation = \"\\\\\"}), \"123456\\n789\")\n    t:are_equal(io.readfile(\"files/utf16be-lf-eleof\"), \"123\\\\\\n456\\n789\\n\")\n    t:are_equal(io.readfile(\"files/utf16le-crlf-neleof\"), \"123\\\\\\n456\\n789\")\n\n    local data1 = io.readfile(\"files/utf8-longline-neleof\")\n    t:are_equal(#data1, 10000)\n    t:require(data1:endswith(\"1234567890\"))\n\n    local data2 = io.readfile(\"files/utf8-longline-eleof\")\n    t:are_equal(#data2, 10001)\n    t:require(data2:endswith(\"1234567890\\n\"))\nend\n\nfunction test_lines(t)\n    t:are_equal(table.to_array(io.lines(\"files/utf8bom-lf-eleof\")), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(table.to_array(io.lines(\"files/utf8-crlf-neleof\")), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(table.to_array(io.lines(\"files/utf8-crlf-neleof\", {encoding = \"binary\"})), {\"123\\\\\\r\\n\", \"456\\r\\n\", \"789\"})\n    t:are_equal(table.to_array(io.lines(\"files/utf8-crlf-neleof\", {continuation = \"\\\\\"})), {\"123456\", \"789\"})\n    t:are_equal(table.to_array(io.lines(\"files/utf16be-lf-eleof\")), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(table.to_array(io.lines(\"files/utf16le-crlf-neleof\")), {\"123\\\\\", \"456\", \"789\"})\nend\n\nfunction test_readlines(t)\n\n    function get_all_keep_crlf(file, opt)\n        local fp = io.open(file, \"r\", opt)\n        local r = {}\n        while true do\n            local l = fp:read(\"L\", opt)\n            if l == nil then break end\n            table.insert(r, l)\n        end\n        t:require(fp:close())\n        return r\n    end\n\n    function get_all_without_crlf(file, opt)\n        local r = {}\n        local fp = io.open(file, \"r\", opt)\n        for l in fp:lines(opt) do\n            table.insert(r, l)\n        end\n        t:require(fp:close())\n        return r\n    end\n\n    t:are_equal(get_all_keep_crlf(\"files/utf8bom-lf-eleof\"), {\"123\\\\\\n\", \"456\\n\", \"789\\n\"})\n    t:are_equal(get_all_keep_crlf(\"files/utf8-crlf-neleof\"), {\"123\\\\\\n\", \"456\\n\", \"789\"})\n    t:are_equal(get_all_keep_crlf(\"files/utf8-crlf-neleof\", {encoding = \"binary\"}), {\"123\\\\\\r\\n\", \"456\\r\\n\", \"789\"})\n    t:are_equal(get_all_keep_crlf(\"files/utf8-crlf-neleof\", {continuation = \"\\\\\"}), {\"123456\\n\", \"789\"})\n    t:are_equal(get_all_keep_crlf(\"files/utf16be-lf-eleof\"), {\"123\\\\\\n\", \"456\\n\", \"789\\n\"})\n    t:are_equal(get_all_keep_crlf(\"files/utf16le-crlf-neleof\"), {\"123\\\\\\n\", \"456\\n\", \"789\"})\n\n    t:are_equal(get_all_without_crlf(\"files/utf8bom-lf-eleof\"), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(get_all_without_crlf(\"files/utf8-crlf-neleof\"), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(get_all_without_crlf(\"files/utf8-crlf-neleof\", {encoding = \"binary\"}), {\"123\\\\\\r\\n\", \"456\\r\\n\", \"789\"})\n    t:are_equal(get_all_without_crlf(\"files/utf8-crlf-neleof\", {continuation = \"\\\\\"}), {\"123456\", \"789\"})\n    t:are_equal(get_all_without_crlf(\"files/utf16be-lf-eleof\"), {\"123\\\\\", \"456\", \"789\"})\n    t:are_equal(get_all_without_crlf(\"files/utf16le-crlf-neleof\"), {\"123\\\\\", \"456\", \"789\"})\nend\n\nfunction test_prop(t)\n    t:are_equal(io.open(\"files/utf8bom-lf-eleof\"):size(), 16)\n    t:are_equal(io.open(\"files/utf8-crlf-neleof\"):size(), 14)\n    t:are_equal(io.open(\"files/utf16be-lf-eleof\"):size(), 28)\n    t:are_equal(io.open(\"files/utf16le-crlf-neleof\"):size(), 30)\n\n    t:are_equal(io.open(\"files/utf8bom-lf-eleof\"):path(), path.absolute(\"files/utf8bom-lf-eleof\"))\n    t:are_equal(io.open(\"files/utf8-crlf-neleof\"):path(), path.absolute(\"files/utf8-crlf-neleof\"))\n    t:are_equal(io.open(\"files/utf16be-lf-eleof\"):path(), path.absolute(\"files/utf16be-lf-eleof\"))\n    t:are_equal(io.open(\"files/utf16le-crlf-neleof\"):path(), path.absolute(\"files/utf16le-crlf-neleof\"))\nend\n\nfunction test_write(t)\n\n    function write(fname, opt)\n        local f = io.open(fname, \"w\", opt)\n        f:write(123, \"abc\", 456, \"def\", \"\\n\")\n        f:close()\n\n        -- give encoding info\n        t:are_equal(io.readfile(fname, opt), \"123abc456def\\n\")\n        -- auto detect encoding\n        t:are_equal(io.readfile(fname), \"123abc456def\\n\")\n    end\n    write(\"temp/path/not/exist/utf8\", {encoding = \"utf8\"})\n    write(\"temp/path/not/exist/utf16\", {encoding = \"utf16\"})\n    write(\"temp/path/not/exist/utf16le\", {encoding = \"utf16le\"})\n    write(\"temp/path/not/exist/utf16be\", {encoding = \"utf16be\"})\n\n    os.tryrm(\"temp\")\nend\n\nfunction test_convert(t)\n    local src = \"files/utf8bom-lf-eleof\"\n    local dst = \"temp/convert_test.txt\"\n    os.mkdir(\"temp\")\n    \n    -- utf8 to gbk (strip bom)\n    io.convert(src, dst, {from = \"utf8\", to = \"gbk\"})\n    local content = io.readfile(dst, {encoding = \"binary\"})\n    t:are_equal(content, \"123\\\\\\n456\\n789\\n\")\n    \n    -- gbk to utf8\n    local src_gbk = dst\n    local dst_utf8 = \"temp/convert_test_utf8.txt\"\n    io.convert(src_gbk, dst_utf8, {from = \"gbk\", to = \"utf8\"})\n    content = io.readfile(dst_utf8, {encoding = \"binary\"})\n    t:are_equal(content, \"123\\\\\\n456\\n789\\n\")\n\n    -- utf8 to utf8bom\n    local dst_utf8bom = \"temp/convert_test_utf8bom.txt\"\n    io.convert(src, dst_utf8bom, {from = \"utf8\", to = \"utf8bom\"})\n    content = io.readfile(dst_utf8bom, {encoding = \"binary\"})\n    t:are_equal(content:sub(1, 3), \"\\239\\187\\191\")\n    t:are_equal(content:sub(4), \"123\\\\\\n456\\n789\\n\")\n\n    -- utf16le to utf8\n    local src_utf16le = \"files/utf16le-crlf-neleof\"\n    local dst_utf16le_to_utf8 = \"temp/convert_test_utf16le_to_utf8.txt\"\n    io.convert(src_utf16le, dst_utf16le_to_utf8, {from = \"utf16le\", to = \"utf8\"})\n    content = io.readfile(dst_utf16le_to_utf8, {encoding = \"binary\"})\n    t:are_equal(content, \"123\\\\\\r\\n456\\r\\n789\")\n\n    -- utf16be to utf8\n    local src_utf16be = \"files/utf16be-lf-eleof\"\n    local dst_utf16be_to_utf8 = \"temp/convert_test_utf16be_to_utf8.txt\"\n    io.convert(src_utf16be, dst_utf16be_to_utf8, {from = \"utf16be\", to = \"utf8\"})\n    content = io.readfile(dst_utf16be_to_utf8, {encoding = \"binary\"})\n    t:are_equal(content, \"123\\\\\\n456\\n789\\n\")\n\n    -- utf8 to utf16le\n    local dst_utf8_to_utf16le = \"temp/convert_test_utf8_to_utf16le.txt\"\n    io.convert(src, dst_utf8_to_utf16le, {from = \"utf8\", to = \"utf16le\"})\n    content = io.readfile(dst_utf8_to_utf16le, {encoding = \"binary\"})\n    t:are_equal(content:sub(1, 2), \"1\\0\") \n\n    -- utf8 to utf16be\n    local dst_utf8_to_utf16be = \"temp/convert_test_utf8_to_utf16be.txt\"\n    io.convert(src, dst_utf8_to_utf16be, {from = \"utf8\", to = \"utf16be\"})\n    content = io.readfile(dst_utf8_to_utf16be, {encoding = \"binary\"})\n    t:are_equal(content:sub(1, 2), \"\\0001\")\n\n    -- utf8 to utf16lebom\n    local dst_utf8_to_utf16lebom = \"temp/convert_test_utf8_to_utf16lebom.txt\"\n    io.convert(src, dst_utf8_to_utf16lebom, {from = \"utf8\", to = \"utf16lebom\"})\n    content = io.readfile(dst_utf8_to_utf16lebom, {encoding = \"binary\"})\n    t:are_equal(content:sub(1, 2), \"\\255\\254\")\n\n    -- utf8 to utf16bom\n    local dst_utf8_to_utf16bom = \"temp/convert_test_utf8_to_utf16bom.txt\"\n    io.convert(src, dst_utf8_to_utf16bom, {from = \"utf8\", to = \"utf16bom\"})\n    content = io.readfile(dst_utf8_to_utf16bom, {encoding = \"binary\"})\n    local bom = content:sub(1, 2)\n    t:require(bom == \"\\255\\254\" or bom == \"\\254\\255\")\n\n    os.tryrm(\"temp\")\nend\n\nfunction test_read_proc_cpuinfo(t)\n    if not is_host(\"linux\") then\n        return t:skip(\"wrong host platform\")\n    end\n    if not os.isfile(\"/proc/cpuinfo\") then\n        return t:skip(\"missing /proc/cpuinfo\")\n    end\n    local data = io.readfile(\"/proc/cpuinfo\", {encoding = \"binary\"})\n    t:require(data and #data > 0)\n\n    local data2 = io.readfile(\"/proc/cpuinfo\")\n    t:require(data2 and #data2 > 0)\nend\n"
  },
  {
    "path": "tests/modules/jobgraph/test.lua",
    "content": "import(\"async.jobgraph\")\n\nlocal function dummy_job() end\n\nfunction test_group_bridge_reuse(t)\n    local jobs = jobgraph.new()\n    jobs:group(\"foo\", function ()\n        jobs:add(\"foo/1\", dummy_job)\n        jobs:add(\"foo/2\", dummy_job)\n    end)\n    jobs:group(\"bar\", function ()\n        jobs:add(\"bar/1\", dummy_job)\n    end)\n    jobs:add_orders(\"foo\", \"bar\")\n    local vertices_before = #jobs._dag:vertices()\n    jobs:add_orders(\"foo\", \"bar\")\n    local vertices_after = #jobs._dag:vertices()\n    t:are_equal(vertices_before, vertices_after)\nend\n\nfunction test_group_bridge_updates_with_new_job(t)\n    local jobs = jobgraph.new()\n    jobs:group(\"foo\", function ()\n        jobs:add(\"foo/1\", dummy_job)\n    end)\n    jobs:group(\"bar\", function ()\n        jobs:add(\"bar/1\", dummy_job)\n    end)\n    jobs:add_orders(\"foo\", \"bar\")\n    jobs:group(\"foo\", function ()\n        jobs:add(\"foo/2\", dummy_job)\n    end)\n\n    local queue = jobs:build()\n    local first = queue:getfree()\n    t:require(first.name == \"foo/1\" or first.name == \"foo/2\")\n    queue:remove(first)\n    local second = queue:getfree()\n    t:require(second.name == \"foo/1\" or second.name == \"foo/2\")\n    t:require(second.name ~= first.name)\n    queue:remove(second)\n    local third = queue:getfree()\n    t:are_equal(third.name, \"bar/1\")\nend\n\n"
  },
  {
    "path": "tests/modules/json/test.lua",
    "content": "import(\"core.base.json\")\n\nlocal json_null = json.null\nlocal json_pure_null = json.purenull\n\nfunction json_decode(jsonstr, opt)\n    return json.decode(jsonstr, opt)\nend\n\nfunction json_encode(luatable, opt)\n    return json.encode(luatable, opt)\nend\n\nfunction json_pure_decode(jsonstr, opt)\n    opt = opt or {}\n    opt.pure = true\n    return json.decode(jsonstr, opt)\nend\n\nfunction json_pure_encode(luatable, opt)\n    opt = opt or {}\n    opt.pure = true\n    return json.encode(luatable, opt)\nend\n\nfunction test_json_decode(t)\n    t:are_equal(json_decode('{}'), {})\n    t:are_equal(json_decode('[]'), {})\n    t:are_equal(json.is_marked_as_array(json_decode('[]')), true)\n    t:are_equal(not json.is_marked_as_array(json_decode('{}')), true)\n    t:are_equal(json_decode('{\"a\":1, \"b\":\"2\", \"c\":true, \"d\":false, \"e\":null, \"f\":[]}'), {a = 1, b = \"2\", c = true, d = false, e = json_null, f = {}})\n    t:are_equal(json_decode('{\"a\":[], \"b\":[1,2], \"c\":{\"a\":1}}'), {a = {}, b = {1,2}, c = {a = 1}})\n    t:are_equal(json_decode('[1,\"2\"]'), {1, \"2\"})\n    t:are_equal(json_decode('[1,\"2\", {\"a\":1, \"b\":true}]'), {1, \"2\", {a = 1, b = true}})\n    t:are_equal(json_decode('[1,0xa,0xdeadbeef, 0xffffffff,-1]'), {1, 0xa, 0xdeadbeef, 0xffffffff, -1})\nend\n\nfunction test_json_encode(t)\n    t:are_equal(json_encode({}), '{}')\n    t:are_equal(json_encode(json.mark_as_array({})), '[]')\n    t:are_equal(json_encode({json_null, 1, \"2\", false, true}), '[null,1,\"2\",false,true]')\n    t:are_equal(json_encode({1, \"2\", {a = 1}}), '[1,\"2\",{\"a\":1}]')\n    t:are_equal(json_encode({1, \"2\", {b = true}}), '[1,\"2\",{\"b\":true}]')\n    t:are_equal(json_encode(json.mark_as_array({1, 0xa, 0xdeadbeef, 0xffffffff, -1})), '[1,10,3735928559,4294967295,-1]')\n    local pretty_expected = table.concat({\n        \"{\",\n        \"    \\\"name\\\": \\\"xmake\\\",\",\n        \"    \\\"targets\\\": [\",\n        \"        \\\"foo\\\",\",\n        \"        \\\"bar\\\"\",\n        \"    ]\",\n        \"}\"\n    }, \"\\n\")\n    t:are_equal(json_encode({name = \"xmake\", targets = {\"foo\", \"bar\"}}, {pretty = true, indent = 4}), pretty_expected)\nend\n\nfunction test_pure_json_decode(t)\n    t:are_equal(json_pure_decode('{}'), {})\n    t:are_equal(json_pure_decode('[]'), {})\n    t:are_equal(json.is_marked_as_array(json_pure_decode('[]')), true)\n    t:are_equal(not json.is_marked_as_array(json_pure_decode('{}')), true)\n    t:are_equal(json_pure_decode('{\"a\":1, \"b\":\"2\", \"c\":true, \"d\":false, \"e\":null, \"f\":[]}'), {a = 1, b = \"2\", c = true, d = false, e = json_pure_null, f = {}})\n    t:are_equal(json_pure_decode('{\"a\":[], \"b\":[1,2], \"c\":{\"a\":1}}'), {a = {}, b = {1,2}, c = {a = 1}})\n    t:are_equal(json_pure_decode('[1,\"2\"]'), {1, \"2\"})\n    t:are_equal(json_pure_decode('[1,\"2\", {\"a\":1, \"b\":true}]'), {1, \"2\", {a = 1, b = true}})\n    t:are_equal(json_pure_decode('[1,0xa,0xdeadbeef, 0xffffffff,-1]'), {1, 0xa, 0xdeadbeef, 0xffffffff, -1})\nend\n\nfunction test_pure_json_encode(t)\n    t:are_equal(json_pure_encode({}), '{}')\n    t:are_equal(json_pure_encode(json.mark_as_array({})), '[]')\n    t:are_equal(json_pure_encode({json_pure_null, 1, \"2\", false, true}), '[null,1,\"2\",false,true]')\n    t:are_equal(json_pure_encode({1, \"2\", {a = 1}}), '[1,\"2\",{\"a\":1}]')\n    t:are_equal(json_pure_encode({1, \"2\", {b = true}}), '[1,\"2\",{\"b\":true}]')\n    t:are_equal(json_pure_encode(json.mark_as_array({1, 0xa, 0xdeadbeef, 0xffffffff, -1})), '[1,10,3735928559,4294967295,-1]')\n    local pretty_expected = table.concat({\n        \"{\",\n        \"    \\\"name\\\": \\\"xmake\\\",\",\n        \"    \\\"targets\\\": [\",\n        \"        \\\"foo\\\",\",\n        \"        \\\"bar\\\"\",\n        \"    ]\",\n        \"}\"\n    }, \"\\n\")\n    t:are_equal(json_pure_encode({name = \"xmake\", targets = {\"foo\", \"bar\"}}, {pretty = true, indent = 4}), pretty_expected)\nend\n"
  },
  {
    "path": "tests/modules/lib/detect/test.lua",
    "content": "import(\"lib.detect.find_toolname\")\n\nfunction test_find_toolname(t)\n    t:are_equal(find_toolname(\"xcrun -sdk macosx clang\"), \"clang\")\n    t:are_equal(find_toolname(\"xcrun -sdk macosx clang++\"), \"clangxx\")\n    t:are_equal(find_toolname(\"/usr/bin/arm-linux-gcc\"), \"gcc\")\n    t:are_equal(find_toolname(\"/usr/bin/arm-linux-g++\"), \"gxx\")\n    t:are_equal(find_toolname(\"/usr/bin/arm-linux-ar\"), \"ar\")\n    t:are_equal(find_toolname(\"link.exe -lib\"), \"link\")\n    t:are_equal(find_toolname(\"arm-android-clang++\"), \"clangxx\")\n    t:are_equal(find_toolname(\"pkg-config\"), \"pkg_config\")\n    t:are_equal(find_toolname(\"gcc-5\"), \"gcc\")\nend\n\n"
  },
  {
    "path": "tests/modules/list/test.lua",
    "content": "import(\"core.base.list\")\n\nfunction test_push(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_insert(t)\n    local d = list.new()\n    local v3 = {v = 3}\n    d:insert({v = 1})\n    d:insert({v = 2})\n    d:insert(v3)\n    d:insert({v = 5})\n    d:insert({v = 4}, v3)\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_remove(t)\n    local d = list.new()\n    local v3 = {v = 3}\n    d:insert({v = 1})\n    d:insert({v = 2})\n    d:insert(v3)\n    d:insert({v = 3})\n    d:insert({v = 4})\n    d:insert({v = 5})\n    d:remove(v3)\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_remove_first(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    d:remove_first()\n    t:are_equal(d:first().v, 2)\n    t:are_equal(d:last().v, 5)\n    local idx = 2\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_remove_last(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    d:remove_last()\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 4)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_for_remove(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    local item = d:first()\n    while item ~= nil do\n        local next = d:next(item)\n        t:are_equal(item.v, idx)\n        d:remove(item)\n        item = next\n        idx = idx + 1\n    end\n    t:require(d:empty())\nend\n\nfunction test_rfor_remove(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 5\n    local item = d:last()\n    while item ~= nil do\n        local prev = d:prev(item)\n        t:are_equal(item.v, idx)\n        d:remove(item)\n        item = prev\n        idx = idx - 1\n    end\n    t:require(d:empty())\nend\n\nfunction test_insert_first(t)\n    local d = list.new()\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:push({v = 5})\n    d:insert_first({v = 1})\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_insert_last(t)\n    local d = list.new()\n    d:push({v = 1})\n    d:push({v = 2})\n    d:push({v = 3})\n    d:push({v = 4})\n    d:insert_last({v = 5})\n    t:are_equal(d:first().v, 1)\n    t:are_equal(d:last().v, 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item.v, idx)\n        idx = idx + 1\n    end\nend\n\n"
  },
  {
    "path": "tests/modules/math/test.lua",
    "content": "function test_isinf(t)\n    t:will_raise(function() math.isinf(nil) end)\n    t:will_raise(function() math.isinf(true) end)\n\n    t:require_not(math.isinf(0))\n    t:require_not(math.isinf(math.nan))\n    t:are_same(math.isinf(math.inf), 1)\n    t:are_same(math.isinf(-math.inf), -1)\nend\n\nfunction test_isnan(t)\n    t:will_raise(function() math.isinf(nil) end)\n    t:will_raise(function() math.isinf(true) end)\n\n    t:require_not(math.isnan(0))\n    t:require(math.isnan(math.nan))\n    t:require_not(math.isnan(math.huge))\n    t:require_not(math.isnan(-math.huge))\nend\n\nfunction test_isint(t)\n    t:will_raise(function() math.isint(nil) end)\n    t:will_raise(function() math.isint(true) end)\n\n    t:require(math.isint(0))\n    t:require(math.isint(-10))\n    t:require(math.isint(123456))\n    t:require_not(math.isint(123456.1))\n    t:require_not(math.isint(-9.99))\n    t:require_not(math.isint(math.nan))\n    t:require_not(math.isint(math.huge))\n    t:require_not(math.isint(-math.huge))\nend\n\n"
  },
  {
    "path": "tests/modules/os/async_copy.lua",
    "content": "local function _prepare_source(dir)\n    os.mkdir(dir)\n    io.writefile(path.join(dir, \"foo.txt\"), \"foo\")\n    io.writefile(path.join(dir, \"bar.txt\"), \"bar\")\nend\n\nfunction main()\n    local root = os.tmpfile() .. \".os_async_copy\"\n    local srcdir = path.join(root, \"src\")\n    local dstdir = path.join(root, \"dst\")\n\n    _prepare_source(srcdir)\n    print(\"source prepared: %s\", srcdir)\n\n    local files = os.files(path.join(srcdir, \"*.txt\"), {async = true})\n    assert(files and #files == 2)\n    print(\"async enumerate: %d files\", #files)\n\n    os.cp(srcdir, dstdir, {async = true})\n    assert(os.isdir(dstdir))\n    print(\"async copy done: %s\", dstdir)\n\n    files = os.files(path.join(dstdir, \"*.txt\"), {async = true})\n    assert(files and #files == 2)\n\n    os.rm(dstdir, {async = true})\n    assert(not os.isdir(dstdir))\n    print(\"dst removed async\")\n\n    os.rm(srcdir, {async = true})\n    os.tryrm(root)\n    print(\"async copy test finished\")\nend\n\n"
  },
  {
    "path": "tests/modules/os/async_scheduler.lua",
    "content": "import(\"core.base.scheduler\")\n\nlocal function _prepare_workspace(root)\n    os.mkdir(root)\n    for idx = 1, 4 do\n        io.writefile(path.join(root, string.format(\"file%d.txt\", idx)), \"xmake\")\n    end\nend\n\nfunction main()\n    local root = os.tmpfile() .. \".os_async_sched\"\n    _prepare_workspace(root)\n    print(\"workspace prepared: %s\", root)\n\n    local group = \"os_async_scheduler\"\n    scheduler.co_group_begin(group, function ()\n        for idx = 1, 4 do\n            scheduler.co_start(function ()\n                local matches = os.files(path.join(root, string.format(\"file%d.txt\", idx)), {async = true})\n                assert(matches and #matches == 1)\n                print(\"async match %d finished\", idx)\n            end)\n        end\n\n        scheduler.co_start(function ()\n            print(\"async find all files in programdir...\")\n            local files = os.files(path.join(os.programdir(), \"**\"), {async = true})\n            print(\"files: %d\", #files)\n            print(\"async find all finished\")\n        end)\n    end)\nend\n"
  },
  {
    "path": "tests/modules/os/cpuinfo.lua",
    "content": "function main()\n    print(os.cpuinfo())\n    while true do\n        print(\"total: %d%%\", math.floor(os.cpuinfo(\"usagerate\") * 100))\n        os.sleep(1000)\n    end\nend\n"
  },
  {
    "path": "tests/modules/os/meminfo.lua",
    "content": "function main()\n    while true do\n        print(\"%d%%\", math.floor(os.meminfo(\"usagerate\") * 100))\n        os.sleep(1000)\n    end\nend\n"
  },
  {
    "path": "tests/modules/os/test.lua",
    "content": "function test_cpdir(t)\n    -- get mclock\n    local tm = os.mclock()\n    -- test cpdir\n    os.mkdir(\"test1\")\n    t:require(os.exists(\"test1\"))\n    os.cp(\"test1\",\"test2\")\n    t:require(os.exists(\"test2\"))\n    os.rmdir(\"test1\")\n    t:require_not(os.exists(\"test1\"))\n    io.writefile(\"test2/awd\",\"awd\")\n    os.rmdir(\"test2\")\n    t:require_not(os.exists(\"test2\"))\n    -- assert mclock\n    t:require(os.mclock() >= tm)\nend\n\nfunction test_rename(t)\n    -- get mclock\n    local tm = os.mclock()\n    -- test rename\n    os.mkdir(\"test1\")\n    t:require(os.exists(\"test1\"))\n    os.mv(\"test1\",\"test2\")\n    t:require_not(os.exists(\"test1\"))\n    t:require(os.exists(\"test2\"))\n    os.rmdir(\"test2\")\n    t:require_not(os.exists(\"test2\"))\n    -- assert mclock\n    t:require(os.mclock() >= tm)\nend\n\nfunction test_cp_mvdir_into_another_dir(t)\n    -- get mclock\n    local tm = os.mclock()\n    -- test cp/mvdir into another dir\n    os.mkdir(\"test1\")\n    os.mkdir(\"test2\")\n    t:require(os.exists(\"test1\"))\n    t:require(os.exists(\"test2\"))\n    os.cp(\"test1\",\"test2\")\n    t:require(os.exists(\"test2/test1\"))\n    os.mv(\"test1\",\"test2/test1\")\n    t:require_not(os.exists(\"test1\"))\n    t:require(os.exists(\"test2/test1/test1\"))\n    os.rmdir(\"test2\")\n    t:require_not(os.exists(\"test2\"))\n    -- assert mclock\n    t:require(os.mclock() >= tm)\nend\n\nfunction test_cp_symlink(t)\n    if is_host(\"windows\") then\n        return\n    end\n    os.touch(\"test1\")\n    os.ln(\"test1\", \"test2\")\n    t:require(os.isfile(\"test1\"))\n    t:require(os.isfile(\"test2\"))\n    t:require(os.islink(\"test2\"))\n    os.cp(\"test2\", \"test3\")\n    t:require(os.isfile(\"test3\"))\n    t:require(not os.islink(\"test3\"))\n    os.cp(\"test2\", \"test4\", {symlink = true})\n    t:require(os.isfile(\"test4\"))\n    t:require(os.islink(\"test4\"))\n    os.mkdir(\"dir\")\n    os.touch(\"dir/test1\")\n    os.cd(\"dir\")\n    os.ln(\"test1\", \"test2\")\n    os.cd(\"-\")\n    t:require(os.islink(\"dir/test2\"))\n    os.cp(\"dir\", \"dir2\")\n    t:require(not os.islink(\"dir2/test2\"))\n    os.cp(\"dir\", \"dir3\", {symlink = true})\n    t:require(os.islink(\"dir3/test2\"))\n    os.tryrm(\"test1\")\n    os.tryrm(\"test2\")\n    os.tryrm(\"test3\")\n    os.tryrm(\"test4\")\n    os.tryrm(\"dir\")\n    os.tryrm(\"dir2\")\n    os.tryrm(\"dir3\")\n    t:require(not os.exists(\"test1\"))\n    t:require(not os.exists(\"test2\"))\n    t:require(not os.exists(\"dir\"))\nend\n\nfunction test_setenv(t)\n    -- get mclock\n    local tm = os.mclock()\n    -- test setenv\n    os.setenv(\"__AWD\",\"DWA\")\n    t:are_equal(os.getenv(\"__AWD\"), \"DWA\")\n    os.setenv(\"__AWD\",\"DWA2\")\n    t:are_equal(os.getenv(\"__AWD\"), \"DWA2\")\n    -- assert mclock\n    t:require(os.mclock() >= tm)\nend\n\nfunction test_argv(t)\n    t:are_equal(os.argv(\"\"), {})\n    -- $cli aa bb cc\n    t:are_equal(os.argv(\"aa bb cc\"), {\"aa\", \"bb\", \"cc\"})\n    -- $cli aa --bb=bbb -c\n    t:are_equal(os.argv(\"aa --bb=bbb -c\"), {\"aa\", \"--bb=bbb\", \"-c\"})\n    -- $cli \"aa bb cc\" dd\n    t:are_equal(os.argv('\"aa bb cc\" dd'), {\"aa bb cc\", \"dd\"})\n    -- $cli aa(bb)cc dd\n    t:are_equal(os.argv('aa(bb)cc dd'), {\"aa(bb)cc\", \"dd\"})\n    -- $cli aa\\\\bb/cc dd\n    t:are_equal(os.argv('aa\\\\bb/cc dd'), {\"aa\\\\bb/cc\", \"dd\"})\n    -- $cli \"aa\\\\bb/cc dd\" ee\n    t:are_equal(os.argv('\"aa\\\\\\\\bb/cc dd\" ee'), {\"aa\\\\bb/cc dd\", \"ee\"})\n    -- $cli \"aa\\\\bb/cc (dd)\" ee\n    t:are_equal(os.argv('\"aa\\\\\\\\bb/cc (dd)\" ee'), {\"aa\\\\bb/cc (dd)\", \"ee\"})\n    -- $cli -DTEST=\\\"hello\\\"\n    t:are_equal(os.argv('-DTEST=\\\\\"hello\\\\\"'), {'-DTEST=\"hello\"'})\n    -- $cli -DTEST=\\\"hello\\\" -DTEST=\\\"hello\\\"\n    t:are_equal(os.argv('-DTEST=\\\\\"hello\\\\\" -DTEST2=\\\\\"hello\\\\\"'), {'-DTEST=\"hello\"', '-DTEST2=\"hello\"'})\n    -- $cli -DTEST=\"hello\"\n    t:are_equal(os.argv('-DTEST=\"hello\"'), {'-DTEST=hello'})\n    -- $cli -DTEST=\"hello world\"\n    t:are_equal(os.argv('-DTEST=\"hello world\"'), {'-DTEST=hello world'})\n    -- $cli -DTEST=\\\"hello world\\\"\n    t:are_equal(os.argv('-DTEST=\\\\\"hello world\\\\\"'), {'-DTEST=\"hello', 'world\\\"'})\n    -- $cli \"-DTEST=\\\"hello world\\\"\" \"-DTEST2=\"\\hello world2\\\"\"\n    t:are_equal(os.argv('\"-DTEST=\\\\\\\"hello world\\\\\\\"\" \"-DTEST2=\\\\\\\"hello world2\\\\\\\"\"'), {'-DTEST=\"hello world\"', '-DTEST2=\"hello world2\"'})\n    -- $cli '-DTEST=\"hello world\"' '-DTEST2=\"hello world2\"'\n    t:are_equal(os.argv(\"'-DTEST=\\\"hello world\\\"' '-DTEST2=\\\"hello world2\\\"'\"), {'-DTEST=\"hello world\"', '-DTEST2=\"hello world2\"'})\n    -- only split\n    t:are_equal(os.argv('-DTEST=\"hello world\"', {splitonly = true}), {'-DTEST=\"hello world\"'})\n    t:are_equal(os.argv('-DTEST=\"hello world\" -DTEST2=\"hello world2\"', {splitonly = true}), {'-DTEST=\"hello world\"', '-DTEST2=\"hello world2\"'})\nend\n\nfunction test_args(t)\n    t:are_equal(os.args({}), \"\")\n    t:are_equal(os.args({\"aa\", \"bb\", \"cc\"}), \"aa bb cc\")\n    t:are_equal(os.args({\"aa\", \"--bb=bbb\", \"-c\"}), \"aa --bb=bbb -c\")\n    t:are_equal(os.args({\"aa bb cc\", \"dd\"}), '\"aa bb cc\" dd')\n    t:are_equal(os.args({\"aa(bb)cc\", \"dd\"}), 'aa(bb)cc dd')\n    t:are_equal(os.args({\"aa\\\\bb/cc\", \"dd\"}), \"aa\\\\bb/cc dd\")\n    t:are_equal(os.args({\"aa\\\\bb/cc dd\", \"ee\"}), '\"aa\\\\\\\\bb/cc dd\" ee')\n    t:are_equal(os.args({\"aa\\\\bb/cc (dd)\", \"ee\"}), '\"aa\\\\\\\\bb/cc (dd)\" ee')\n    t:are_equal(os.args({\"aa\\\\bb/cc\", \"dd\"}, {escape = true}), \"aa\\\\\\\\bb/cc dd\")\n    t:are_equal(os.args('-DTEST=\"hello\"'), '-DTEST=\\\\\"hello\\\\\"')\n    t:are_equal(os.args({'-DTEST=\"hello\"', '-DTEST2=\"hello\"'}), '-DTEST=\\\\\"hello\\\\\" -DTEST2=\\\\\"hello\\\\\"')\n    t:are_equal(os.args('-DTEST=hello'), '-DTEST=hello') -- irreversible\n    t:are_equal(os.args({'-DTEST=\"hello world\"', '-DTEST2=\"hello world2\"'}), '\"-DTEST=\\\\\\\"hello world\\\\\\\"\" \"-DTEST2=\\\\\\\"hello world2\\\\\\\"\"')\nend\n\nfunction test_async(t)\n    local tmpdir = os.tmpfile() .. \".dir\"\n    local tmpdir2 = os.tmpfile() .. \".dir\"\n    io.writefile(path.join(tmpdir, \"foo.txt\"), \"foo\")\n    io.writefile(path.join(tmpdir, \"bar.txt\"), \"bar\")\n    local files = os.files(path.join(tmpdir, \"*.txt\"), {async = true})\n    t:require(files and #files == 2)\n\n    os.cp(tmpdir, tmpdir2, {async = true, detach = true})\n\n    os.cp(tmpdir, tmpdir2, {async = true})\n    t:require(os.isdir(tmpdir2))\n\n    t:require(os.isdir(tmpdir))\n    os.rm(tmpdir, {async = true})\n    t:require(not os.isdir(tmpdir))\n\n    t:require(os.isdir(tmpdir2))\n    os.rm(tmpdir2, {async = true, detach = true})\nend\n\nfunction test_isexec(t)\n    local tempdir = \"temp/isexec\"\n    os.tryrm(tempdir)\n    os.mkdir(tempdir)\n\n    local programfile = os.programfile()\n    if programfile then\n        t:require(os.isexec(programfile))\n    end\n\n    local filepath = path.join(tempdir, \"script\")\n    io.writefile(filepath, \"echo test\\n\")\n\n    if is_host(\"windows\") then\n        local batfile = path.join(tempdir, \"a.bat\")\n        io.writefile(batfile, \"echo test\\r\\n\")\n        t:require(os.isexec(batfile))\n\n        local comfile = path.join(tempdir, \"a.com\")\n        io.writefile(comfile, \"12345678\")\n        t:require(os.isexec(comfile))\n\n        local suffix = path.join(tempdir, \"prog\")\n        io.writefile(suffix .. \".exe\", \"\")\n        t:require(os.isexec(suffix))\n\n        local suffix2 = path.join(tempdir, \"prog2\")\n        io.writefile(suffix2 .. \".com\", \"\")\n        t:require(os.isexec(suffix2))\n    else\n        os.vrunv(\"chmod\", {\"-x\", filepath})\n        t:require_not(os.isexec(filepath))\n        os.vrunv(\"chmod\", {\"+x\", filepath})\n        t:require(os.isexec(filepath))\n    end\n\n    os.tryrm(tempdir)\nend\n"
  },
  {
    "path": "tests/modules/path/test.lua",
    "content": "function test_splitenv_win(t)\n    if not is_host(\"windows\") then\n        return t:skip(\"wrong host platform\")\n    end\n    t:are_equal(path.splitenv(\"\"), {})\n    t:are_equal(path.splitenv(\"a\"), {'a'})\n    t:are_equal(path.splitenv(\"a;b\"), {'a','b'})\n    t:are_equal(path.splitenv(\";;a;;b;\"), {'a','b'})\n    t:are_equal(path.splitenv('c:/a;c:\\\\b'), {'c:/a', 'c:\\\\b'})\n    t:are_equal(path.splitenv('\"a;aa;aa;;\"'), {\"a;aa;aa;;\"})\n    t:are_equal(path.splitenv('\"a;aa;aa;;\";bb;;'), {\"a;aa;aa;;\", 'bb'})\n    t:are_equal(path.splitenv('\"a;aa;aa;;\";\"a;cc;aa;;\";bb;\"d\";'), {\"a;aa;aa;;\",\"a;cc;aa;;\", 'bb', 'd' })\nend\n\nfunction test_splitenv_unix(t)\n    if is_host(\"windows\") then\n        return t:skip(\"wrong host platform\")\n    end\n    t:are_equal(path.splitenv(\"\"), {})\n    t:are_equal(path.splitenv(\"a\"), {'a'})\n    t:are_equal(path.splitenv(\"a:b\"), {'a','b'})\n    t:are_equal(path.splitenv(\"::a::b:\"), {'a','b'})\n    t:are_equal(path.splitenv('a%tag:b'), {'a','b'})\n    t:are_equal(path.splitenv('a%tag:b%tag'), {'a','b'})\n    t:are_equal(path.splitenv('a%tag:b%%tag%%'), {'a','b'})\n    t:are_equal(path.splitenv('a%tag:b:%tag:'), {'a','b'})\nend\n\nfunction test_extension(t)\n    t:are_equal(path.extension(\"1.1/abc\"), \"\")\n    t:are_equal(path.extension(\"1.1\\\\abc\"), \"\")\n    t:are_equal(path.extension(\"foo.so\"), \".so\")\n    t:are_equal(path.extension(\"/home/foo.so\"), \".so\")\n    t:are_equal(path.extension(\"\\\\home\\\\foo.so\"), \".so\")\nend\n\nfunction test_filename(t)\n    t:are_equal(path.filename(\"foo\"), \"foo\")\n    t:are_equal(path.filename(\"foo.so\"), \"foo.so\")\n    t:are_equal(path.filename(\"/tmp/foo.so\"), \"foo.so\")\n    t:are_equal(path.filename(\"c:\\\\tmp\\\\foo.so\"), \"foo.so\")\n    t:are_equal(path.filename(\"/tmp/..\"), \"..\")\n    t:are_equal(path.filename(\"/tmp/.\"), \".\")\n    t:are_equal(path.filename(\"/\"), \"\")\n    t:are_equal(path.filename(\"\"), \"\")\n    \n    -- unicode\n    t:are_equal(path.filename(\"Unicode 测试/test.lua\"), \"test.lua\")\n    t:are_equal(path.filename(\"Unicode 测试/foo/test.lua\"), \"test.lua\")\n    t:are_equal(path.filename(\"测试/test.lua\"), \"test.lua\")\n    t:are_equal(path.filename(\"测试\\\\test.lua\"), \"test.lua\")\nend\n\nfunction test_directory(t)\n    t:are_equal(path.directory(\"\"), nil)\n    t:are_equal(path.directory(\".\"), nil)\n    t:are_equal(path.directory(\"foo\"), \".\")\n    if is_host(\"windows\") then\n        t:are_equal(path.directory(\"c:\"), nil)\n        t:are_equal(path.directory(\"c:\\\\\"), nil)\n        t:are_equal(path.directory(\"c:\\\\xxx\"), \"c:\")\n        t:are_equal(path.directory(\"c:\\\\xxx\\\\yyy\"), \"c:\\\\xxx\")\n    else\n        t:are_equal(path.directory(\"/tmp\"), \"/\")\n        t:are_equal(path.directory(\"/tmp/\"), \"/\")\n        t:are_equal(path.directory(\"/tmp/xxx\"), \"/tmp\")\n        t:are_equal(path.directory(\"/tmp/xxx/\"), \"/tmp\")\n        t:are_equal(path.directory(\"/\"), nil)\n    end\nend\n\nfunction test_absolute(t)\n    t:are_equal(path.absolute(\"\", \"\"), nil)\n    t:are_equal(path.absolute(\".\", \".\"), \".\")\n    if is_host(\"windows\") then\n        t:are_equal(path.absolute(\"foo\", \"c:\"), \"c:\\\\foo\")\n        t:are_equal(path.absolute(\"foo\", \"c:\\\\\"), \"c:\\\\foo\")\n        t:are_equal(path.absolute(\"foo\", \"c:\\\\tmp\"), \"c:\\\\tmp\\\\foo\")\n        t:are_equal(path.absolute(\"foo\", \"c:\\\\tmp\\\\\"), \"c:\\\\tmp\\\\foo\")\n    else\n        t:are_equal(path.absolute(\"\", \"/\"), nil)\n        t:are_equal(path.absolute(\"/\", \"/\"), \"/\")\n        t:are_equal(path.absolute(\".\", \"/\"), \"/\")\n        t:are_equal(path.absolute(\"foo\", \"/tmp/\"), \"/tmp/foo\")\n        t:are_equal(path.absolute(\"foo\", \"/tmp\"), \"/tmp/foo\")\n    end\nend\n\nfunction test_relative(t)\n    t:are_equal(path.relative(\"\", \"\"), nil)\n    t:are_equal(path.relative(\".\", \".\"), \".\")\n    if is_host(\"windows\") then\n        t:are_equal(path.relative(\"c:\", \"c:\\\\\"), \".\")\n        t:are_equal(path.relative(\"c:\\\\foo\", \"c:\\\\foo\"), \".\")\n        t:are_equal(path.relative(\"c:\\\\foo\", \"c:\\\\\"), \"foo\")\n        t:are_equal(path.relative(\"c:\\\\tmp\\\\foo\", \"c:\\\\tmp\"), \"foo\")\n        t:are_equal(path.relative(\"c:\\\\tmp\\\\foo\", \"c:\\\\tmp\\\\\"), \"foo\")\n    else\n        t:are_equal(path.relative(\"\", \"/\"), nil)\n        t:are_equal(path.relative(\"/\", \"/\"), \".\")\n        t:are_equal(path.relative(\"/tmp/foo\", \"/tmp/\"), \"foo\")\n        t:are_equal(path.relative(\"/tmp/foo\", \"/tmp\"), \"foo\")\n    end\nend\n\nfunction test_translate(t)\n    t:are_equal(path.translate(\"\"), nil)\n    t:are_equal(path.translate(\".\"), \".\")\n    t:are_equal(path.translate(\"..\"), \"..\")\n    if is_host(\"windows\") then\n        t:are_equal(path.translate(\"c:\"), \"c:\")\n        t:are_equal(path.translate(\"c:\\\\\"), \"c:\")\n        t:are_equal(path.translate(\"c:\\\\foo\\\\\\\\\\\\\"), \"c:\\\\foo\")\n        t:are_equal(path.translate(\"c:\\\\foo\\\\..\\\\..\"), \"c:\\\\foo\\\\..\\\\..\")\n    else\n        t:are_equal(path.translate(\"/\"), \"/\");\n        t:are_equal(path.translate(\"////\"), \"/\");\n        t:are_equal(path.translate(\"/foo//////\"), \"/foo\");\n        t:are_equal(path.translate(\"/foo/../..\"), \"/foo/../..\");\n        t:are_equal(path.translate(\"/foo/../../\"), \"/foo/../..\");\n    end\nend\n\nfunction test_normalize(t)\n    t:are_equal(path.normalize(\"././.\"), \".\")\n    t:are_equal(path.normalize(\"../foo/..\"), \"..\")\n    t:are_equal(path.normalize(\"../foo/bar/../..\"), \"..\")\n    if is_host(\"windows\") then\n        t:are_equal(path.normalize(\"c:\\\\foo\\\\.\\\\.\\\\\"), \"c:\\\\foo\")\n        t:are_equal(path.normalize(\"c:\\\\foo\\\\bar\\\\.\\\\..\\\\xyz\"), \"c:\\\\foo\\\\xyz\")\n        t:are_equal(path.normalize(\"c:\\\\foo\\\\.\\\\..\"), \"c:\")\n        t:are_equal(path.normalize(\"../..\"), \"..\\\\..\")\n        t:are_equal(path.normalize(\"../foo/bar/..\"), \"..\\\\foo\")\n        t:are_equal(path.normalize(\"../foo/bar/../../..\"), \"..\\\\..\")\n    else\n        t:are_equal(path.normalize(\"/foo/././\"), \"/foo\");\n        t:are_equal(path.normalize(\"/./././\"), \"/\");\n        t:are_equal(path.normalize(\"/foo/bar/.//..//xyz\"), \"/foo/xyz\");\n        t:are_equal(path.normalize(\"/foo/../..\"), \"/\");\n        t:are_equal(path.normalize(\"/foo/bar../..\"), \"/foo\");\n        t:are_equal(path.normalize(\"../..\"), \"../..\");\n        t:are_equal(path.normalize(\"../foo/bar/..\"), \"../foo\");\n        t:are_equal(path.normalize(\"../foo/bar/../../..\"), \"../..\");\n    end\nend\n\nfunction test_instance(t)\n    t:are_equal(path(\"/tmp/a\"):str(), \"/tmp/a\")\n    t:are_equal(path(\"/tmp/a\"):directory():str(), \"/tmp\")\n    t:are_equal(path(\"/tmp/a\", function (p) return \"--key=\" .. p end):str(), \"--key=/tmp/a\")\n    t:are_equal(path(\"/tmp/a\", function (p) return \"--key=\" .. p end):rawstr(), \"/tmp/a\")\n    t:are_equal(path(\"/tmp/a\", function (p) return \"--key=\" .. p end):clone():set(\"/tmp/b\"):str(), \"--key=/tmp/b\")\nend\n"
  },
  {
    "path": "tests/modules/pipe/echo_client.lua",
    "content": "import(\"core.base.pipe\")\n\nfunction main(name)\n    local pipefile = pipe.open(name or \"test\", 'w')\n    local count = 0\n    while count < 10000 do\n        local write = pipefile:write(\"hello world..\", {block = true})\n        if write <= 0 then\n            break\n        end\n        count = count + 1\n    end\n    print(\"%s: write ok, count: %d!\", pipefile, count)\n    pipefile:close()\nend\n"
  },
  {
    "path": "tests/modules/pipe/echo_server.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.bytes\")\n\nfunction main(name)\n    local buff = bytes(8192)\n    local pipefile = pipe.open(name or \"test\", 'r')\n    if pipefile:connect() > 0 then\n        print(\"%s: connected\", pipefile)\n        local count = 0\n        local result = nil\n        while count < 10000 do\n            local read, data = pipefile:read(buff, 13, {block = true})\n            if read > 0 then\n                result = data\n                count = count + 1\n            else\n                break\n            end\n        end\n        print(\"%s: read: %d, count: %d\", pipefile, result and result:size() or 0, count)\n        result:dump()\n    end\n    pipefile:close()\nend\n"
  },
  {
    "path": "tests/modules/pipe/pipe_pair.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.bytes\")\n\nfunction main()\n    local buff = bytes(8192)\n    local rpipe, wpipe = pipe.openpair()\n    wpipe:write(\"hello xmake!\", {block = true})\n    local read, data = rpipe:read(buff, 13)\n    if read > 0 and data then\n        data:dump()\n    end\n    rpipe:close()\n    wpipe:close()\nend\n"
  },
  {
    "path": "tests/modules/pipe/sched_echo_client.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.scheduler\")\n\nfunction _session(id)\n    local pipefile = pipe.open(\"test\" .. id, 'w')\n    local count = 0\n    while count < 10000 do\n        local write = pipefile:write(\"hello world..\", {block = true})\n        if write <= 0 then\n            break\n        end\n        count = count + 1\n    end\n    print(\"%s/%d: write ok, count: %d!\", pipefile, id, count)\n    pipefile:close()\nend\n\nfunction main(count)\n    count = count and tonumber(count) or 1\n    for i = 1, count do\n        scheduler.co_start(_session, i)\n    end\nend\n"
  },
  {
    "path": "tests/modules/pipe/sched_echo_server.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.scheduler\")\n\nfunction _session(id)\n\n    local pipefile = pipe.open(\"test\" .. id, 'r')\n    if pipefile:connect() > 0 then\n        print(\"%s/%d: connected\", pipefile, id)\n        local count = 0\n        local result = nil\n        local buff = bytes(8192)\n        while count < 10000 do\n            local read, data = pipefile:read(buff, 13, {block = true})\n            if read > 0 then\n                result = data\n                count = count + 1\n            else\n                break\n            end\n        end\n        print(\"%s/%d: read: %d, count: %d\", pipefile, id, result and result:size() or 0, count)\n        result:dump()\n    end\n    pipefile:close()\nend\n\nfunction main(count)\n    count = count and tonumber(count) or 1\n    for i = 1, count do\n        scheduler.co_start(_session, i)\n    end\nend\n"
  },
  {
    "path": "tests/modules/pipe/sched_pipe_pair.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.scheduler\")\n\nfunction _session_read(id, pipefile)\n    print(\"%s/%d: read ..\", pipefile, id)\n    local result = nil\n    local buff = bytes(8192)\n    for i = 1, 10000 do\n        local read, data = pipefile:read(buff, 12, {block = true})\n        if read > 0 and data then\n            result = data:str()\n        end\n    end\n    print(\"%s/%d: read ok, data: %s\", pipefile, id, result and result or \"\")\n    pipefile:close()\nend\n\nfunction _session_write(id, pipefile)\n    print(\"%s/%d: write ..\", pipefile, id)\n    for i = 1, 10000 do\n        pipefile:write(\"hello xmake!\", {block = true})\n    end\n    print(\"%s/%d: write ok\", pipefile, id)\n    pipefile:close()\nend\n\nfunction _session(id)\n    local rpipe, wpipe = pipe.openpair()\n    scheduler.co_start(_session_read, id, rpipe)\n    scheduler.co_start(_session_write, id, wpipe)\nend\n\nfunction main(count)\n    count = count and tonumber(count) or 1\n    for i = 1, count do\n        scheduler.co_start(_session, i)\n    end\nend\n"
  },
  {
    "path": "tests/modules/private/select_script/test.lua",
    "content": "import(\"private.core.base.select_script\")\n\nfunction _match_patterns(patterns, opt)\n    local scripts = {}\n    for _, pattern in ipairs(patterns) do\n        pattern = pattern:gsub(\"([%+%.%-%^%$%%])\", \"%%%1\")\n        pattern = pattern:gsub(\"%*\", \"\\001\")\n        pattern = pattern:gsub(\"\\001\", \".*\")\n        scripts[pattern] = true\n    end\n    return select_script(scripts, opt) == true\nend\n\nfunction test_plat_only(t)\n    t:require(_match_patterns(\"*\", {plat = \"macosx\"}))\n    t:require(_match_patterns(\"macosx\", {plat = \"macosx\"}))\n    t:require(_match_patterns(\"macosx,linux\", {plat = \"macosx\"}))\n    t:require(_match_patterns(\"mac*\", {plat = \"macosx\"}))\n    t:require_not(_match_patterns(\"macosx\", {plat = \"linux\"}))\n    t:require_not(_match_patterns(\"linux\", {plat = \"macosx\"}))\n    t:require_not(_match_patterns(\"!macosx\", {plat = \"macosx\"}))\n    t:require_not(_match_patterns(\"!mac*\", {plat = \"macosx\"}))\n    t:require(_match_patterns(\"!macosx\", {plat = \"linux\"}))\n    t:require(_match_patterns(\"!macosx,!android\", {plat = \"linux\"}))\n    t:require(_match_patterns(\"!mac*\", {plat = \"linux\"}))\nend\n\nfunction test_plat_arch(t)\n    t:require(_match_patterns(\"!wasm|!arm*\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!wasm|!arm*\", {plat = \"linux\", arch = \"arm64\"}))\n    t:require(_match_patterns(\"*|x86_64\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"macosx|x86_64\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"macosx|x86_64,linux|x86_64\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"macosx|x86_*\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"macosx|x86_64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"macosx|i386\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!macosx|x86_64\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!mac*|x86_64\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!macosx|x86_64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!mac*|x86_64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"macosx|!i386\", {plat = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!macosx|!i386\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"windows|!x86\", {plat = \"windows\", arch = \"x64\"}))\n    t:require_not(_match_patterns(\"windows|!x86\", {plat = \"android\", arch = \"arm64-v8a\"}))\n    t:require(_match_patterns(\"macosx|native\", {plat = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"macosx|!native\", {plat = \"macosx\", arch = \"arm64\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"macosx|!native\", {plat = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"windows|native\", {plat = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\nend\n\nfunction test_subhost_only(t)\n    t:require(_match_patterns(\"@*\", {subhost = \"macosx\"}))\n    t:require(_match_patterns(\"@macosx\", {subhost = \"macosx\"}))\n    t:require(_match_patterns(\"@mac*\", {subhost = \"macosx\"}))\n    t:require_not(_match_patterns(\"@macosx\", {subhost = \"linux\"}))\n    t:require_not(_match_patterns(\"@linux\", {subhost = \"macosx\"}))\n    t:require_not(_match_patterns(\"@!macosx\", {subhost = \"macosx\"}))\n    t:require_not(_match_patterns(\"@!mac*\", {subhost = \"macosx\"}))\n    t:require(_match_patterns(\"@!macosx\", {subhost = \"linux\"}))\n    t:require(_match_patterns(\"@!mac*\", {subhost = \"linux\"}))\nend\n\nfunction test_subhost_subarch(t)\n    t:require(_match_patterns(\"@*|x86_64\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@macosx|x86_64\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@macosx|x86_*\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"@macosx|x86_64\", {subhost = \"linux\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"@macosx|i386\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"@!macosx|x86_64\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"@!mac*|x86_64\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@!macosx|x86_64\", {subhost = \"linux\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@!mac*|x86_64\", {subhost = \"linux\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@macosx|!i386\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@!macosx|!i386\", {subhost = \"linux\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@windows|!x86\", {subhost = \"windows\", subarch = \"x64\"}))\n    t:require_not(_match_patterns(\"@windows|!x86\", {subhost = \"android\", subarch = \"arm64-v8a\"}))\n    t:require(_match_patterns(\"@macosx|native\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@macosx|native\", {subhost = \"macosx\", subarch = \"arm64\"}))\n    t:require_not(_match_patterns(\"@macosx|!native\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"@windows|native\", {subhost = \"macosx\", subarch = \"x86_64\"}))\nend\n\nfunction test_plat_subhost(t)\n    t:require(_match_patterns(\"*@macosx\", {plat = \"macosx\", subhost = \"macosx\"}))\n    t:require(_match_patterns(\"android@macosx\", {plat = \"android\", subhost = \"macosx\"}))\n    t:require(_match_patterns(\"android@macosx,linux\", {plat = \"android\", subhost = \"linux\"}))\n    t:require(_match_patterns(\"android@mac*\", {plat = \"android\", subhost = \"macosx\"}))\n    t:require(_match_patterns(\"android@!macosx\", {plat = \"android\", subhost = \"linux\"}))\n    t:require_not(_match_patterns(\"!android@macosx\", {plat = \"android\", subhost = \"macosx\"}))\n    t:require(_match_patterns(\"!iphon*@macosx\", {plat = \"linux\", subhost = \"macosx\"}))\nend\n\nfunction test_plat_arch_subhost(t)\n    t:require(_match_patterns(\"*|x86_64@macosx\", {plat = \"macosx\", subhost = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|arm64-v8a@macosx\", {plat = \"android\", subhost = \"macosx\", arch = \"arm64-v8a\"}))\n    t:require(_match_patterns(\"android|x86_64@macosx,linux\", {plat = \"android\", subhost = \"linux\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|x86_64@mac*\", {plat = \"android\", subhost = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|x86_64@!macosx\", {plat = \"android\", subhost = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!android|x86_64@macosx\", {plat = \"android\", subhost = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!iphon*|x86_64@macosx\", {plat = \"linux\", subhost = \"macosx\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"iphon*|arm64@macosx\", {plat = \"iphoneos\", subhost = \"macosx\", arch = \"arm64\"}))\n    t:require_not(_match_patterns(\"iphon*|arm64@macosx\", {plat = \"iphoneos\", subhost = \"linux\", arch = \"arm64\"}))\nend\n\nfunction test_plat_arch_subhost_subarch(t)\n    t:require(_match_patterns(\"*|x86_64@macosx|x86_64\", {plat = \"macosx\", subhost = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|arm64-v8a@macosx|x86_64\", {plat = \"android\", subhost = \"macosx\", arch = \"arm64-v8a\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|x86_64@macosx|x86_64,linux|x86_64\", {plat = \"android\", subhost = \"linux\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|x86_64@mac*|x86_64\", {plat = \"android\", subhost = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|x86_64@!macosx|x86_64\", {plat = \"android\", subhost = \"linux\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!android|x86_64@macosx|x86_64\", {plat = \"android\", subhost = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"!iphon*|x86_64@macosx|x86_64\", {plat = \"linux\", subhost = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"iphon*|arm64@macosx|x86_64\", {plat = \"iphoneos\", subhost = \"macosx\", arch = \"arm64\", subarch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"iphon*|arm64@macosx|x86_64\", {plat = \"iphoneos\", subhost = \"linux\", arch = \"arm64\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"android|native@macosx|x86_64\", {plat = \"android\", subhost = \"macosx\", arch = \"x86_64\", subarch = \"x86_64\"}))\nend\n\nfunction test_logical_expr(t)\n    t:require(_match_patterns(\"!macosx|x86_64,!iphoneos|arm64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!wasm|!arm* and !cross|!arm*\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!wasm|!arm* and !cross|!arm*\", {plat = \"linux\", arch = \"arm64\"}))\n    t:require_not(_match_patterns(\"!wasm|!arm* and !cross|!arm*\", {plat = \"wasm\", arch = \"x86_64\"}))\n    t:require(_match_patterns(\"!macosx|x86_64 or !iphoneos|arm64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!android@macosx or !android@linux\", {plat = \"android\", subhost = \"macosx\"}))\n    t:require(_match_patterns(\"@macosx|x86_64 or @linux|x86_64\", {subhost = \"macosx\", subarch = \"x86_64\"}))\n    t:require(_match_patterns(\"@macosx or @linux\", {subhost = \"macosx\"}))\n    t:require(_match_patterns(\"!wasm|!arm* or (!cross|!arm* or linux)\", {plat = \"linux\", arch = \"arm64\"}))\n    t:require_not(_match_patterns(\"!wasm|!arm* or (!cross|!arm* and !linux)\", {plat = \"linux\", arch = \"arm64\"}))\n    t:require_not(_match_patterns(\"!macosx|x86_64 and !linux|x86_64\", {plat = \"linux\", arch = \"x86_64\"}))\n    t:require_not(_match_patterns(\"!macosx and !android\", {plat = \"android\"}))\n    t:require_not(_match_patterns(\"!macosx and !android\", {plat = \"macosx\"}))\nend\n\n"
  },
  {
    "path": "tests/modules/process/process_autoexit.lua",
    "content": "import(\"core.base.process\")\nimport(\"core.base.scheduler\")\n\nfunction main(cmd)\n    for i = 1, 10 do\n        scheduler.co_start(function ()\n            process.open(cmd or \"xmake l os.sleep 60000\")\n            --process.openv(\"xmake\", {\"l\", \"os.sleep\", \"60000\"}, {detach = true}):close()\n        end)\n    end\n    -- check processes status after exiting\n    -- we need to terminate all unclosed processes automatically after parent process is exited\n    -- ps aux | grep sleep\nend\n"
  },
  {
    "path": "tests/modules/process/process_killed.lua",
    "content": "import(\"core.base.process\")\nimport(\"core.base.scheduler\")\n\nfunction main(cmd)\n    for i = 1, 10 do\n        scheduler.co_start(function ()\n            -- @note we need test xx.bat cmd on windows\n            local proc = process.open(cmd or \"xmake l os.sleep 60000\")\n            print(\"%s: wait ..\", proc)\n            -- we need to terminate all unclosed processes automatically after parent process is exited after do ctrl-c\n            proc:wait(-1)\n            print(\"%s: wait ok\", proc)\n            proc:close()\n        end)\n    end\nend\n"
  },
  {
    "path": "tests/modules/process/sched_process.lua",
    "content": "import(\"core.base.process\")\nimport(\"core.base.scheduler\")\n\nfunction _session(id, program, ...)\n    local proc = process.openv(program, table.pack(...))\n    local ok, status = proc:wait(-1)\n    print(\"%s/%d: %d, status: %d\", proc, id, ok, status)\n    proc:close()\nend\n\nfunction main(program, ...)\n    for i = 1, 10 do\n        scheduler.co_start(_session, i, program, ...)\n    end\nend\n"
  },
  {
    "path": "tests/modules/process/sched_process_pipe.lua",
    "content": "import(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.process\")\nimport(\"core.base.scheduler\")\n\nfunction _session_read_pipe(id, rpipeopt)\n    local buff = bytes(8192)\n    local rpipe = rpipeopt.rpipe\n    print(\"%s/%d: read ..\", rpipe, id)\n    local read = 0\n    while not rpipeopt.stop do\n        local real, data = rpipe:read(buff, 8192 - read, {start = read + 1})\n        if real > 0 then\n            read = read + real\n        elseif real == 0 then\n            if rpipe:wait(pipe.EV_READ, -1) < 0 then\n                break\n            end\n        else\n            break\n        end\n    end\n    local results = bytes(buff, 1, read)\n    print(\"%s/%d: read ok, size: %d\", rpipe, id, results:size())\n    if results:size() > 0 then\n        results:dump()\n    end\n    rpipe:close()\nend\n\nfunction _session(id, program, ...)\n    local rpipe, wpipe = pipe.openpair()\n    local rpipeopt = {rpipe = rpipe, stop = false}\n    scheduler.co_start(_session_read_pipe, id, rpipeopt)\n    local proc = process.openv(program, table.pack(...), {stdout = wpipe})\n    local ok, status = proc:wait(-1)\n    rpipeopt.stop = true\n    print(\"%s/%d: %d, status: %d\", proc, id, ok, status)\n    proc:close()\n    wpipe:close()\nend\n\nfunction main(program, ...)\n    for i = 1, 10 do\n        scheduler.co_start(_session, i, program, ...)\n    end\nend\n"
  },
  {
    "path": "tests/modules/process/test.lua",
    "content": "import(\"core.base.process\")\nimport(\"core.base.scheduler\")\n\nlocal inftimeout = 5000\n\nfunction test_single_process(t)\n\n    local stdout = os.tmpfile()\n    local stderr = os.tmpfile()\n    local proc = process.openv(\"xmake\", {\"lua\", \"print\", \"xmake\"}, {stdout = stdout, stderr = stderr})\n    proc:wait(inftimeout)\n    proc:close()\n    t:are_equal(io.readfile(stdout):trim(), \"xmake\")\nend\n\nfunction test_sched_process(t)\n\n    local count = 0\n    local _session = function ()\n        local stdout = io.open(os.tmpfile(), 'w')\n        local stderr = io.open(os.tmpfile(), 'w')\n        local proc = process.openv(\"xmake\", {\"lua\", \"print\", \"xmake\"}, {stdout = stdout, stderr = stderr})\n        local ok, status = proc:wait(inftimeout)\n        proc:close()\n        stdout:close()\n        stderr:close()\n        count = count + 1\n    end\n    scheduler.co_group_begin(\"test\", function ()\n        for i = 1, 3 do\n            scheduler.co_start(_session)\n        end\n    end)\n    scheduler.co_group_wait(\"test\")\n    t:are_equal(count, 3)\nend\n"
  },
  {
    "path": "tests/modules/queue/test.lua",
    "content": "import(\"core.base.queue\")\n\nfunction test_push(t)\n    local d = queue.new()\n    d:push(1)\n    d:push(2)\n    d:push(3)\n    d:push(4)\n    d:push(5)\n    t:are_equal(d:first(), 1)\n    t:are_equal(d:last(), 5)\n    local idx = 1\n    for item in d:items() do\n        t:are_equal(item, idx)\n        idx = idx + 1\n    end\nend\n\nfunction test_pop(t)\n    local d = queue.new()\n    d:push(1)\n    d:push(2)\n    d:push(3)\n    d:push(4)\n    d:push(5)\n    d:pop()\n    t:are_equal(d:first(), 2)\n    t:are_equal(d:last(), 5)\n    local idx = 2\n    for item in d:items() do\n        t:are_equal(item, idx)\n        idx = idx + 1\n    end\nend\n\n"
  },
  {
    "path": "tests/modules/scheduler/semaphore.lua",
    "content": "import(\"core.base.scheduler\")\n\nfunction _loop(semaphore, id)\n    print(\"[%d]: start\", id)\n    while true do\n        print(\"[%d]: wait ..\", id)\n        local value = semaphore:wait(-1)\n        print(\"[%d]:   -> triggered, value: %d ..\", id, value)\n    end\nend\n\nfunction _input(semaphore)\n    while true do\n        if io.readable() then\n            local ch = io.read()\n            print(\"  -> post semaphore\")\n            if ch then\n                semaphore:post(2)\n            end\n        else\n            os.sleep(1000)\n        end\n    end\nend\n\nfunction main()\n    local semaphore = scheduler.co_semaphore(\"\", 1)\n    for i = 1, 10 do\n        scheduler.co_start(_loop, semaphore, i)\n    end\n    scheduler.co_start(_input, semaphore)\nend\n\n"
  },
  {
    "path": "tests/modules/scheduler/sleep.lua",
    "content": "import(\"core.base.scheduler\")\n\nfunction _session2(id)\n    print(\"session2: %d ..\", id)\n    local dt = os.mclock()\n    os.sleep(1000)\n    dt = os.mclock() - dt\n    print(\"session2: %d end, dt: %d ms\", id, dt)\nend\n\nfunction _session1(id)\n    print(\"session1: %d ..\", id)\n    local dt = os.mclock()\n    scheduler.co_sleep(1000)\n    dt = os.mclock() - dt\n    print(\"session1: %d end, dt: %d ms\", id, dt)\nend\n\nfunction main()\n    for i = 1, 10 do\n        scheduler.co_start(_session1, i)\n        scheduler.co_start(_session2, i)\n    end\nend\n\n"
  },
  {
    "path": "tests/modules/scheduler/spinner.lua",
    "content": "import(\"async.runjobs\")\n\nfunction main()\n    printf(\"testing .. \")\n    runjobs(\"test\", function ()\n        os.sleep(10000)\n    end, {waiting_indicator = true})\n    print(\"ok\")\nend\n\n"
  },
  {
    "path": "tests/modules/scheduler/test.lua",
    "content": "import(\"core.base.scheduler\")\n\nfunction test_group(t)\n\n    local count = 0\n    local task = function (a)\n        t:are_equal(a, \"xmake!\")\n        count = count + 1\n    end\n    scheduler.co_group_begin(\"test\", function ()\n        for i = 1, 100 do\n            scheduler.co_start(task, \"xmake!\")\n        end\n    end)\n    scheduler.co_group_wait(\"test\")\n    t:are_equal(count, 100)\nend\n\nfunction test_sleep(t)\n\n    local count = 0\n    local task = function (a)\n        local dt = os.mclock()\n        os.sleep(500)\n        dt = os.mclock() - dt\n        t:require(dt > 100 and dt < 1000)\n        count = count + 1\n    end\n    for i = 1, 3 do\n        scheduler.co_start(task)\n    end\nend\n\nfunction test_yield(t)\n\n    local count = 0\n    local task = function (a)\n        scheduler.co_yield()\n        count = count + 1\n    end\n    scheduler.co_group_begin(\"test\", function ()\n        for i = 1, 10 do\n            scheduler.co_start(task)\n        end\n    end)\n    scheduler.co_group_wait(\"test\")\n    t:are_equal(count, 10)\nend\n\nfunction test_runjobs(t)\n    import(\"async.runjobs\")\n\n    local total = 100\n    local comax = 6\n    local count = 0\n    runjobs(\"test\", function (index)\n        t:require(index >= 1 and index <= total)\n        count = count + 1\n    end, {total = total, comax = comax})\n    t:are_equal(count, total)\nend\n"
  },
  {
    "path": "tests/modules/scheduler/yield.lua",
    "content": "import(\"core.base.scheduler\")\n\nfunction _session(id)\n    print(\"test: %d ..\", id)\n    scheduler.co_yield()\n    print(\"test: %d end\", id)\nend\n\nfunction main()\n    for i = 1, 10 do\n        scheduler.co_start(_session, i)\n    end\nend\n\n"
  },
  {
    "path": "tests/modules/semver/test.lua",
    "content": "import(\"core.base.semver\")\n\n-- select version\nfunction _check_semver_select(t, results, required_ver, versions, tags, branches)\n    local version, source = semver.select(required_ver, versions or {}, tags or {}, branches or {})\n    t:are_equal((version.version or version), results[1])\n    t:are_equal(source, results[2])\nend\n\n-- test select version\nfunction test_semver_select(t)\n\n    _check_semver_select(t, {\"1.5.1\", \"version\"}\n                        , \">=1.5.0 <1.6.0\"\n                        , {\"1.4.0\", \"1.5.0\", \"1.5.1\"})\n\n    _check_semver_select(t, {\"1.5.1\", \"version\"}\n                        , \"^1.5.0\"\n                        ,{\"1.4.0\", \"1.5.0\", \"1.5.1\"})\n\n    _check_semver_select(t, {\"master\", \"branch\"}\n                        , \"master\"\n                        , {\"1.4.0\", \"1.5.0\", \"1.5.1\"}\n                        , {\"v1.2.0\", \"v1.6.0\"}\n                        , {\"master\", \"dev\"})\n\n    _check_semver_select(t, {\"1.5.1\", \"version\"}\n                        , \"latest\"\n                        , {\"1.4.0\", \"1.5.0\", \"1.5.1\"})\nend\n\n-- select version\nfunction _check_semver_satisfies(t, expected, version, range)\n    local result = semver.satisfies(version, range)\n    t:are_equal(result, expected)\nend\n\n-- test satisfies version\nfunction test_semver_satisfies(t)\n\n    _check_semver_satisfies(t, true, \"1.5.1\", \">=1.5.0 <1.6.0\")\n    _check_semver_satisfies(t, true, \"1.5.1\", \"^1.5.0\")\n    _check_semver_satisfies(t, true, \"1.5.1\", \"~1.5.0\")\n    _check_semver_satisfies(t, true, \"1.6.0\", \"^1.5.0\")\n    _check_semver_satisfies(t, true, \"1.6.0\", \"v1.6.0\")\n\n    _check_semver_satisfies(t, false, \"1.6.1\", \"~1.5.0\")\n    _check_semver_satisfies(t, false, \"2.5.1\", \"^1.5.0\")\n    _check_semver_satisfies(t, false, \"1.4.1\", \">=1.5.0 <1.6.0\")\n    _check_semver_satisfies(t, false, \"1.6.0\", \"v1.6.1\")\nend\n\n-- parse version\nfunction _check_semver_parse(t, version_str, major, minor, patch, prerelease, build)\n    local version = semver.new(version_str)\n    t:require(version)\n    t:are_equal(version:major(), major)\n    t:are_equal(version:minor(), minor)\n    t:are_equal(version:patch(), patch)\n    t:are_equal(version:prerelease(), prerelease or {})\n    t:are_equal(version:build(), build or {})\nend\n\n-- match version\nfunction _check_semver_match(t, str, version_str, major, minor, patch, prerelease, build)\n    local version = semver.match(str)\n    t:require(version)\n    t:are_equal(version:rawstr(), version_str)\n    t:are_equal(version:major(), major)\n    t:are_equal(version:minor(), minor)\n    t:are_equal(version:patch(), patch)\n    t:are_equal(version:prerelease(), prerelease or {})\n    t:are_equal(version:build(), build or {})\nend\n\n-- test parse version\nfunction test_semver_parse(t)\n\n    _check_semver_parse(t, \"1.2.3\", 1, 2, 3)\n    _check_semver_parse(t, \"1.2.3-beta\", 1, 2, 3, {\"beta\"})\n    _check_semver_parse(t, \"1.2.3-beta+77\", 1, 2, 3, {\"beta\"}, {77})\n    _check_semver_parse(t, \"v1.2.3-alpha.1+77\", 1, 2, 3, {\"alpha\", 1}, {77})\n    _check_semver_parse(t, \"v3.2.1-alpha.1+77.foo\", 3, 2, 1, {\"alpha\", 1}, {77, \"foo\"})\nend\n\n-- test match version string\nfunction test_semver_match(t)\n    _check_semver_match(t, \"gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0\", \"7.4.0-1ubuntu1\", 7, 4, 0, {\"1ubuntu1\"})\n    _check_semver_match(t, \"gcc (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0\", \"8.1.0\", 8, 1, 0)\n    _check_semver_match(t, \"DMD64 D Compiler v2.090.0\", \"2.090.0\", 2, 90, 0)\n    _check_semver_match(t, \"Apple clang version 11.0.0 (clang-1100.0.33.12)\", \"11.0.0\", 11, 0, 0)\n    _check_semver_match(t, \"curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.5 zlib/1.2.11 nghttp2/1.24.1\", \"7.54.0\", 7, 54, 0)\nend\n"
  },
  {
    "path": "tests/modules/signal/sigint.lua",
    "content": "import(\"core.base.signal\")\n\nfunction main()\n    signal.register(signal.SIGINT, function (signo)\n        print(\"signal.SIGINT(%d)\", signo)\n    end)\n    io.read()\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_tcp/echo_client.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\n\nfunction _session_recv(sock)\n    print(\"%s: recv ..\", sock)\n    local count = 0\n    local result = nil\n    local buff = bytes(8192)\n    while count < 100000 do\n        local recv, data = sock:recv(buff, 13, {block = true})\n        if recv > 0 then\n            result = data\n            count = count + 1\n        else\n            break\n        end\n    end\n    print(\"%s: recv ok, count: %d!\", sock, count)\n    if result then\n        result:dump()\n    end\nend\n\nfunction _session_send(sock)\n    print(\"%s: send ..\", sock)\n    local count = 0\n    while count < 100000 do\n        local send = sock:send(\"hello world..\", {block = true})\n        if send > 0 then\n            count = count + 1\n        else\n            break\n        end\n    end\n    print(\"%s: send ok, count: %d!\", sock, count)\nend\n\nlocal socks = {}\nfunction _session(addr, port)\n    print(\"connect %s:%d ..\", addr, port)\n    local sock = socket.connect(addr, port)\n    if sock then\n        print(\"%s: connected!\", sock)\n        table.insert(socks, sock)\n        sock:ctrl(socket.CTRL_SET_SENDBUFF, 6000000)\n        sock:ctrl(socket.CTRL_SET_RECVBUFF, 6000000)\n        scheduler.co_group_begin(\"test\", function ()\n            scheduler.co_start(_session_recv, sock)\n            scheduler.co_start(_session_send, sock)\n        end)\n    else\n        print(\"connect %s:%d failed\", addr, port)\n    end\nend\n\nfunction main(count)\n    count = count and tonumber(count) or 1\n    scheduler.co_group_begin(\"test\", function ()\n        for i = 1, count do\n            scheduler.co_start(_session, \"127.0.0.1\", 9091)\n        end\n    end)\n    scheduler.co_group_wait(\"test\")\n    for _, sock in ipairs(socks) do\n        sock:close()\n    end\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_tcp/echo_server.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\n\nfunction _session_recv(sock)\n    print(\"%s: recv ..\", sock)\n    local count = 0\n    local result = nil\n    local buff = bytes(8192)\n    while count < 100000 do\n        local recv, data = sock:recv(buff, 13, {block = true})\n        if recv > 0 then\n            result = data\n            count = count + 1\n        else\n            break\n        end\n    end\n    print(\"%s: recv ok, count: %d!\", sock, count)\n    if result then\n        result:dump()\n    end\nend\n\nfunction _session_send(sock)\n    print(\"%s: send ..\", sock)\n    local count = 0\n    while count < 100000 do\n        local send = sock:send(\"hello world..\", {block = true})\n        if send > 0 then\n            count = count + 1\n        else\n            break\n        end\n    end\n    print(\"%s: send ok, count: %d!\", sock, count)\nend\n\nfunction _listen(addr, port)\n\n    local sock_clients = {}\n    local sock = socket.bind(addr, port)\n    sock:listen(100)\n    print(\"%s: listening %s:%d ..\", sock, addr, port)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            table.insert(sock_clients, sock_client)\n            sock_client:ctrl(socket.CTRL_SET_SENDBUFF, 6000000)\n            sock_client:ctrl(socket.CTRL_SET_RECVBUFF, 6000000)\n            scheduler.co_start(_session_recv, sock_client)\n            scheduler.co_start(_session_send, sock_client)\n        end\n    end\n    for _, sock_client in ipairs(sock_clients) do\n        sock_client:close()\n    end\n    sock:close()\nend\n\nfunction main()\n    scheduler.co_start(_listen, \"127.0.0.1\", 9091)\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_tcp/file_client.lua",
    "content": "import(\"core.base.socket\")\nimport(\"core.base.scheduler\")\nimport(\"core.base.bytes\")\n\nfunction _session(addr, port)\n    print(\"connect %s:%d ..\", addr, port)\n    local sock = socket.connect(addr, port)\n    print(\"%s: connected!\", sock)\n    local real = 0\n    local recv = 0\n    local data = nil\n    local wait = false\n    local buff = bytes(8192)\n    while true do\n        real, data = sock:recv(buff, 8192)\n        if real > 0 then\n            recv = recv + real\n            wait = false\n        elseif real == 0 and not wait then\n            if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then\n                wait = true\n            else\n                break\n            end\n        else\n            break\n        end\n    end\n    print(\"%s: recv ok, size: %d!\", sock, recv)\n    sock:close()\nend\n\nfunction main(count)\n    count = count and tonumber(count) or 1\n    for i = 1, count do\n        scheduler.co_start(_session, \"127.0.0.1\", 9092)\n    end\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_tcp/file_server.lua",
    "content": "import(\"core.base.socket\")\nimport(\"core.base.scheduler\")\n\nfunction _session(sock, filepath)\n\n    local file = io.open(filepath, 'rb')\n    if file then\n        local send = sock:sendfile(file, {block = true})\n        print(\"%s: send %s %d bytes!\", sock, filepath, send)\n        file:close()\n    end\n    sock:close()\nend\n\nfunction _listen(addr, port, filepath)\n\n    local sock = socket.bind(addr, port)\n    sock:listen(100)\n    print(\"%s: listening %s:%d ..\", sock, addr, port)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            scheduler.co_start(_session, sock_client, filepath)\n        end\n    end\n    sock:close()\nend\n\nfunction main(filepath)\n    scheduler.co_start(_listen, \"127.0.0.1\", 9092, filepath)\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_udp/echo_client.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\n\nfunction _session(addr, port, data)\n    local buff = bytes(8192)\n    local sock = socket.udp()\n    local send = sock:sendto(data or \"hello xmake!\", addr, port, {block = true})\n    print(\"%s: send to %s:%d %d bytes!\", sock, addr, port, send)\n    local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8112, {block = true})\n    if recv > 0 then\n        print(\"%s: recv %d bytes from %s:%d\", sock, recv, peer_addr, peer_port)\n        data:dump()\n    end\n    sock:close()\nend\n\nfunction main(data)\n    scheduler.co_start(_session, \"127.0.0.1\", 9091, data)\nend\n"
  },
  {
    "path": "tests/modules/socket/sched_udp/echo_server.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\n\nfunction _listen(addr, port)\n    local buff = bytes(8192)\n    local sock = socket.udp()\n    sock:bind(addr, port)\n    while true do\n        print(\"%s: recv in %s:%d ..\", sock, addr, port)\n        local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8192, {block = true})\n        print(\"%s: recv %d bytes from: %s:%d\", sock, recv, peer_addr, peer_port)\n        if data then\n            data:dump()\n            sock:sendto(data, peer_addr, peer_port)\n        end\n    end\n    sock:close()\nend\n\nfunction main()\n    scheduler.co_start(_listen, \"127.0.0.1\", 9091)\nend\n"
  },
  {
    "path": "tests/modules/socket/tcp/echo_client.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main()\n    local addr = \"127.0.0.1\"\n    local port = 9091\n    print(\"connect %s:%d ..\", addr, port)\n    local sock = socket.connect(addr, port)\n    if sock then\n        print(\"%s: connected!\", sock)\n        local count = 0\n        local buff = bytes(8192)\n        while count < 10000 do\n            local send = sock:send(\"hello world..\", {block = true})\n            if send > 0 then\n                sock:recv(buff, 13, {block = true})\n            else\n                break\n            end\n            count = count + 1\n        end\n        print(\"%s: send ok, count: %d!\", sock, count)\n        sock:close()\n    end\nend\n"
  },
  {
    "path": "tests/modules/socket/tcp/echo_server.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main()\n\n    local addr = \"127.0.0.1\"\n    local port = 9091\n    local sock = socket.bind(addr, port)\n    sock:listen(20)\n    print(\"%s: listening %s:%d ..\", sock, addr, port)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            local count = 0\n            local result = nil\n            local buff = bytes(8192)\n            while true do\n                local recv, data = sock_client:recv(buff, 13, {block = true})\n                if recv > 0 then\n                    result = data\n                    sock_client:send(data, {block = true})\n                    count = count + 1\n                else\n                    break\n                end\n            end\n            print(\"%s: recv: %d, count: %d\", sock_client, result and result:size() or 0, count)\n            if result then\n                result:dump()\n            end\n            sock_client:close()\n        end\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/tcp/file_client.lua",
    "content": "import(\"core.base.socket\")\nimport(\"core.base.bytes\")\n\nfunction main()\n    local addr = \"127.0.0.1\"\n    local port = 9092\n    print(\"connect %s:%d ..\", addr, port)\n    local sock = socket.connect(addr, port)\n    print(\"%s: connected!\", sock)\n    local real = 0\n    local recv = 0\n    local data = nil\n    local wait = false\n    local buff = bytes(8192)\n    while true do\n        real, data = sock:recv(buff, 8192)\n        if real > 0 then\n            recv = recv + real\n            wait = false\n        elseif real == 0 and not wait then\n            if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then\n                wait = true\n            else\n                break\n            end\n        else\n            break\n        end\n    end\n    print(\"%s: recv ok, size: %d!\", sock, recv)\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/tcp/file_server.lua",
    "content": "import(\"core.base.socket\")\n\nfunction main(filepath)\n\n    local addr = \"127.0.0.1\"\n    local port = 9092\n    local sock = socket.bind(addr, port)\n    sock:listen(20)\n    print(\"%s: listening %s:%d ..\", sock, addr, port)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            local file = io.open(filepath, 'rb')\n            if file then\n                local send = sock_client:sendfile(file, {block = true})\n                print(\"%s: send %s %d bytes!\", sock_client, filepath, send)\n                file:close()\n            end\n            sock_client:close()\n        end\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/udp/echo_client.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main(data)\n    local addr = \"127.0.0.1\"\n    local port = 9091\n    local buff = bytes(8192)\n    local sock = socket.udp()\n    local send = sock:sendto(data or \"hello xmake!\", addr, port, {block = true})\n    print(\"%s: send to %s:%d %d bytes!\", sock, addr, port, send)\n    local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8112, {block = true})\n    if recv > 0 then\n        print(\"%s: recv %d bytes from %s:%d\", sock, recv, peer_addr, peer_port)\n        data:dump()\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/udp/echo_server.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main()\n    local addr = \"127.0.0.1\"\n    local port = 9091\n    local sock = socket.udp()\n    local buff = bytes(8192)\n    sock:bind(addr, port)\n    while true do\n        print(\"%s: recv in %s:%d ..\", sock, addr, port)\n        local recv, data, peer_addr, peer_port = sock:recvfrom(buff, 8192, {block = true})\n        print(\"%s: recv %d bytes from: %s:%d\", sock, recv, peer_addr, peer_port)\n        if data then\n            data:dump()\n            sock:sendto(data, peer_addr, peer_port)\n        end\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/unix_tcp/echo_client.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main(addr)\n    addr = addr or path.join(os.tmpdir(), \"echo.socket\")\n    print(\"connect %s ..\", addr)\n    local buff = bytes(8192)\n    local sock = socket.connect_unix(addr)\n    if sock then\n        print(\"%s: connected!\", sock)\n        local count = 0\n        while count < 10000 do\n            local send = sock:send(\"hello world..\", {block = true})\n            if send > 0 then\n                sock:recv(buff, 13, {block = true})\n            else\n                break\n            end\n            count = count + 1\n        end\n        print(\"%s: send ok, count: %d!\", sock, count)\n        sock:close()\n    end\nend\n"
  },
  {
    "path": "tests/modules/socket/unix_tcp/echo_server.lua",
    "content": "import(\"core.base.bytes\")\nimport(\"core.base.socket\")\n\nfunction main(addr)\n\n    addr = addr or path.join(os.tmpdir(), \"echo.socket\")\n    os.tryrm(addr)\n    local sock = socket.bind_unix(addr)\n    sock:listen(20)\n    print(\"%s: listening %s ..\", sock, addr)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            local count = 0\n            local result = nil\n            local buff = bytes(8192)\n            while true do\n                local recv, data = sock_client:recv(buff, 13, {block = true})\n                if recv > 0 then\n                    result = data\n                    sock_client:send(data, {block = true})\n                    count = count + 1\n                else\n                    break\n                end\n            end\n            print(\"%s: recv: %d, count: %d\", sock_client, result and result:size() or 0, count)\n            if result then\n                result:dump()\n            end\n            sock_client:close()\n        end\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/unix_tcp/file_client.lua",
    "content": "import(\"core.base.socket\")\nimport(\"core.base.bytes\")\n\nfunction main(addr)\n    addr = addr or path.join(os.tmpdir(), \"file.socket\")\n    print(\"connect %s ..\", addr)\n    local sock = socket.connect_unix(addr)\n    print(\"%s: connected!\", sock)\n    local real = 0\n    local recv = 0\n    local data = nil\n    local wait = false\n    local buff = bytes(8192)\n    while true do\n        real, data = sock:recv(buff, 8192)\n        if real > 0 then\n            recv = recv + real\n            wait = false\n        elseif real == 0 and not wait then\n            if sock:wait(socket.EV_RECV, -1) == socket.EV_RECV then\n                wait = true\n            else\n                break\n            end\n        else\n            break\n        end\n    end\n    print(\"%s: recv ok, size: %d!\", sock, recv)\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/socket/unix_tcp/file_server.lua",
    "content": "import(\"core.base.socket\")\n\nfunction main(filepath, addr)\n    addr = addr or path.join(os.tmpdir(), \"file.socket\")\n    local sock = socket.bind_unix(addr)\n    sock:listen(20)\n    print(\"%s: listening %s ..\", sock, addr)\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            print(\"%s: accepted\", sock_client)\n            local file = io.open(filepath, 'rb')\n            if file then\n                local send = sock_client:sendfile(file, {block = true})\n                print(\"%s: send %s %d bytes!\", sock_client, filepath, send)\n                file:close()\n            end\n            sock_client:close()\n        end\n    end\n    sock:close()\nend\n"
  },
  {
    "path": "tests/modules/stdin/test.lua",
    "content": "import(\"lib.detect.find_tool\")\n\nfunction _run_sh(t, name, cmd, expect)\n    if not is_host(\"windows\") then\n        local xmake = path.translate(os.programfile())\n        local run_stdin = string.format('\"%s\" l --stdin', xmake)\n        local outdata = os.iorunv(\"sh\", {\"-c\", cmd .. \" | \" .. run_stdin}) or \"\"\n        t:are_equal(outdata:trim(), expect)\n    end\nend\n\nfunction _run_cmd(t, name, cmd, expect)\n    if is_host(\"windows\") then\n        local xmake = path.translate(os.programfile())\n        local run_stdin = string.format('%s l --stdin', xmake)\n        local outdata = os.iorunv(\"cmd\", {\"/c\", cmd .. \" | \" .. run_stdin}) or \"\"\n        t:are_equal(outdata:trim(), expect)\n    end\nend\n\nfunction _run_pwsh(t, name, cmd, expect)\n    if is_host(\"windows\") then\n        local xmake = path.translate(os.programfile())\n        local run_stdin = string.format('%s l --stdin', xmake)\n        local pwsh = find_tool(\"powershell\")\n        if pwsh then\n            local outdata = os.iorunv(pwsh.program, {\"-c\", cmd .. \" | \" .. run_stdin}) or \"\"\n            t:are_equal(outdata:trim(), expect)\n        end\n    end\nend\n\nfunction test_sh(t)\n    _run_sh(t, \"sh_single\", \"echo \\\"print('hello_sh')\\\"\", \"hello_sh\")\n    _run_sh(t, \"sh_calc\", \"echo \\\"local f = 1+1; print(f)\\\"\", \"2\")\n    _run_sh(t, \"sh_main\", \"echo \\\"function main() print('in_sh_main') end\\\"\", \"in_sh_main\")\n    _run_sh(t, \"sh_multi\", \"printf \\\"print('shell_line1')\\\\nprint('shell_line2')\\\"\", \"shell_line1\\nshell_line2\")\nend\n\nfunction test_cmd(t)\n    _run_cmd(t, \"cmd_single\", \"echo print 'hello_cmd'\", \"hello_cmd\")\n    _run_cmd(t, \"cmd_calc\", \"echo local f = 1+1; print(f)\", \"2\")\n    _run_cmd(t, \"cmd_multi_lines\", \"(echo print 'line1' && echo print 'line2')\", \"line1\\nline2\")\n    _run_cmd(t, \"cmd_multi_semicolon\", \"echo print('semi1'); print('semi2')\", \"semi1\\nsemi2\")\nend\n\nfunction test_pwsh(t)\n    _run_pwsh(t, \"pwsh_single\", \"echo \\\"print('hello_pwsh')\\\"\", \"hello_pwsh\")\n    _run_pwsh(t, \"pwsh_calc\", \"echo \\\"local f = 1+1; print(f)\\\"\", \"2\")\n    _run_pwsh(t, \"pwsh_main\", \"echo \\\"function main() print('in_pwsh_main') end\\\"\", \"in_pwsh_main\")\n    _run_pwsh(t, \"pwsh_multi\", \"echo \\\"print('pline1')\\\" \\\"print('pline2')\\\"\", \"pline1\\npline2\")\nend\n"
  },
  {
    "path": "tests/modules/string/lastof_perf.lua",
    "content": "\nfunction _lastof_perf(str, pattern, opt)\n    local plain = opt and opt.plain\n    local dt = os.mclock()\n    for i = 0, 1000000 do\n        str:lastof(pattern, plain)\n    end\n    dt = os.mclock() - dt\n    print(\"lastof(%s .., %s, %s): %d ms\", str:sub(1, 16), pattern, string.serialize(opt or {}, {strip = true, indent = false}), dt)\nend\n\nfunction main()\n\n    local str = \"shortstr: 123abc123123xyz[123]+abc123\"\n    _lastof_perf(str, \"1\")\n    _lastof_perf(str, \"123\")\n    _lastof_perf(str, \"[123]+\")\n    print(\"\")\n\n    _lastof_perf(str, \"1\", {plain = true})\n    _lastof_perf(str, \"123\", {plain = true})\n    _lastof_perf(str, \"[123]+\", {plain = true})\n    print(\"\")\n\n    str = \"longstr: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    for i = 0, 100 do\n        str = str .. \"[123]+\"\n    end\n    _lastof_perf(str, \"1\")\n    _lastof_perf(str, \"123\")\n    _lastof_perf(str, \"[123]+\")\n    print(\"\")\n\n    _lastof_perf(str, \"1\", {plain = true})\n    _lastof_perf(str, \"123\", {plain = true})\n    _lastof_perf(str, \"[123]+\", {plain = true})\n    print(\"\")\nend\n"
  },
  {
    "path": "tests/modules/string/serialize/test.lua",
    "content": "\nfunction roundtripimpl(value, opt)\n    local s, serr = string.serialize(value, opt)\n    if serr then\n        raise(serr)\n    end\n    local v, verr = s:deserialize()\n    if verr then\n        raise(verr)\n    end\n    return v\nend\n\nfunction roundtrip(round0)\n    local round1 = roundtripimpl(round0, false)\n    local round2 = roundtripimpl(round1, true)\n    local round3 = roundtripimpl(round2, {binary=true})\n    local round4 = roundtripimpl(round3, {indent=16})\n    local round5 = roundtripimpl(round4, {indent=\"  \\r\\n\\t\"})\n    return round5\nend\n\nfunction test_number(t)\n    t:are_equal(roundtrip(12), 12)\n    t:are_equal(roundtrip(0), 0)\n    t:are_equal(roundtrip(-1), -1)\n    t:are_equal(roundtrip(7.25), 7.25)\n    t:are_equal(roundtrip(math.huge), math.huge)\n    t:are_equal(roundtrip(-math.huge), -math.huge)\n    t:are_equal(roundtrip(math.nan), math.nan)\nend\n\nfunction test_boolean(t)\n    t:are_equal(roundtrip(true), true)\n    t:are_equal(roundtrip(false), false)\nend\n\nfunction test_nil(t)\n    t:are_equal(roundtrip(nil), nil)\nend\n\nfunction test_table(t)\n    t:are_equal(roundtrip({}), {})\n    t:are_equal(roundtrip({{},{1}}), {{},{1}})\n    t:are_equal(roundtrip({[\"true\"] = true}), {[\"true\"] = true})\n    t:are_equal(roundtrip({1, 2, 3}), {1, 2, 3})\n    t:are_equal(roundtrip({1, \"\", 3}), {1, \"\", 3})\n    t:are_equal(roundtrip({{1, 2, 3, nil, 4}}), {{1, 2, 3, nil, 4}})\n    t:are_equal(roundtrip({{1, 2, 3, nil, 4, [100]=5}}), {{1, 2, 3, nil, 4, [100]=5}})\n    t:are_equal(roundtrip({{a=1, b=2, c=3, nil, 4}}), {{a=1, b=2, c=3, nil, 4}})\nend\n\nfunction test_function(t)\n    t:are_equal(roundtrip(function() return {} end)(), {})\n    t:are_equal(roundtrip(function() return {1, 2, 3} end)(), {1, 2, 3})\n    t:are_equal(roundtrip(function() return {{1, 2, 3, nil, 4}} end)(), {{1, 2, 3, nil, 4}})\n    t:are_equal(roundtrip({function() return {{1, 2, 3, nil, 4}} end})[1](), {{1, 2, 3, nil, 4}})\n    t:are_equal(roundtrip({{function() return {{1, 2, 3, nil, 4}} end}})[1][1](), {{1, 2, 3, nil, 4}})\n\n    -- x in fenv\n    x = {}\n    -- return x in fenv\n    function f() return x end\n    -- fenv will restore\n    if xmake.luajit() then\n        -- TODO we need to fix it for lua backend\n        t:are_same(roundtrip(f)(), x)\n    end\n\n    y = {}\n    -- y in fenv\n    local g_y = y\n    -- y in upvalue\n    local y = {}\n    -- return y in upvalue\n    function g() return y end\n    -- upvalue will not restore if striped\n    t:are_same(roundtrip(g)(), nil)\n    -- upvalue will be restored by fenv, so y in fenv is returned\n    t:are_same(roundtripimpl(g)(), g_y)\nend\n\nfunction test_refloop(t)\n    local l1 = {}\n    l1.l = l1\n    local r1 = roundtrip(l1)\n    t:are_same(r1.l, r1)\n\n    local l2 = {{1}, {2}, {3}}\n    l2[1].l = { root = l2, a = l2[1], b = l2[2], c = l2[3] }\n    local r2 = roundtrip(l2)\n    t:are_same(r2[1].l.root, r2)\n    t:are_same(r2[1].l.a, r2[1])\n    t:are_same(r2[1].l.b, r2[2])\n    t:are_same(r2[1].l.c, r2[3])\nend\n"
  },
  {
    "path": "tests/modules/string/split_perf.lua",
    "content": "\nfunction _split_perf(str, delimiter, opt)\n    local dt = os.mclock()\n    for i = 0, 1000000 do\n        str:split(delimiter, opt)\n    end\n    dt = os.mclock() - dt\n    print(\"split(%s .., %s, %s): %d ms\", str:sub(1, 16), delimiter, string.serialize(opt or {}, {strip = true, indent = false}), dt)\nend\n\nfunction main()\n\n    local str = \"shortstr: 123abc123123xyz[123]+abc123\"\n    _split_perf(str, \"1\")\n    _split_perf(str, \"123\")\n    _split_perf(str, \"[123]+\")\n    print(\"\")\n\n    _split_perf(str, \"1\", {plain = true})\n    _split_perf(str, \"123\", {plain = true})\n    _split_perf(str, \"[123]+\", {plain = true})\n    print(\"\")\n\n    str = \"longstr: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    for i = 0, 100 do\n        str = str .. \"[123]+\"\n    end\n    _split_perf(str, \"1\")\n    _split_perf(str, \"123\")\n    _split_perf(str, \"[123]+\")\n    print(\"\")\n\n    _split_perf(str, \"1\", {plain = true})\n    _split_perf(str, \"123\", {plain = true})\n    _split_perf(str, \"[123]+\", {plain = true})\n    print(\"\")\nend\n"
  },
  {
    "path": "tests/modules/string/test.lua",
    "content": "\nfunction test_endswith(t)\n    t:require((\"aaaccc\"):endswith(\"ccc\"))\n    t:require((\"aaaccc\"):endswith(\"aaaccc\"))\n    t:require_not((\"rc\"):endswith(\"xcadas\"))\n    t:require_not((\"aaaccc \"):endswith(\"%s\"))\nend\n\nfunction test_startswith(t)\n    t:require((\"aaaccc\"):startswith(\"aaa\"))\n    t:require((\"aaaccc\"):startswith(\"aaaccc\"))\n    t:require_not((\"rc\"):startswith(\"xcadas\"))\n    t:require_not((\"  aaaccc\"):startswith(\"%s\"))\nend\n\nfunction test_trim(t)\n    t:are_equal((\"\"):trim(), \"\")\n    t:are_equal((\"   \"):trim(), \"\")\n    t:are_equal((\"\"):trim(\"\"), \"\")\n    t:are_equal((\"   \"):trim(\"\"), \"\")\n    t:are_equal((\"   aaa ccc   \"):trim(), \"aaa ccc\")\n    t:are_equal((\"aaa ccc   \"):trim(), \"aaa ccc\")\n    t:are_equal((\"   aaa ccc\"):trim(), \"aaa ccc\")\n    t:are_equal((\"aaa ccc\"):trim(), \"aaa ccc\")\n    t:are_equal((\"\\t\\naaa ccc\\r\\n\"):trim(), \"aaa ccc\")\n    t:are_equal((\"aba\"):trim(\"a\"), \"b\")\nend\n\nfunction test_ltrim(t)\n    t:are_equal((\"\"):ltrim(), \"\")\n    t:are_equal((\"   \"):ltrim(), \"\")\n    t:are_equal((\"\"):ltrim(\"\"), \"\")\n    t:are_equal((\"   \"):ltrim(\"\"), \"\")\n    t:are_equal((\"   aaa ccc   \"):ltrim(), \"aaa ccc   \")\n    t:are_equal((\"aaa ccc   \"):ltrim(), \"aaa ccc   \")\n    t:are_equal((\"   aaa ccc\"):ltrim(), \"aaa ccc\")\n    t:are_equal((\"aaa ccc\"):ltrim(), \"aaa ccc\")\n    t:are_equal((\"\\t\\naaa ccc\\r\\n\"):ltrim(), \"aaa ccc\\r\\n\")\n    t:are_equal((\"aba\"):ltrim(\"a\"), \"ba\")\nend\n\nfunction test_rtrim(t)\n    t:are_equal((\"\"):rtrim(), \"\")\n    t:are_equal((\"   \"):rtrim(), \"\")\n    t:are_equal((\"\"):rtrim(\"\"), \"\")\n    t:are_equal((\"   \"):rtrim(\"\"), \"\")\n    t:are_equal((\"   aaa ccc   \"):rtrim(), \"   aaa ccc\")\n    t:are_equal((\"aaa ccc   \"):rtrim(), \"aaa ccc\")\n    t:are_equal((\"   aaa ccc\"):rtrim(), \"   aaa ccc\")\n    t:are_equal((\"aaa ccc\"):rtrim(), \"aaa ccc\")\n    t:are_equal((\"\\t\\naaa ccc\\r\\n\"):rtrim(), \"\\t\\naaa ccc\")\n    t:are_equal((\"aba\"):rtrim(\"a\"), \"ab\")\nend\n\nfunction test_split(t)\n    -- pattern match and ignore empty string\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n'), {\"1\", \"2\", \"3\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('123'), {\"abc\", \"xyz\", \"abc\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('[123]+'), {\"abc\", \"xyz\", \"abc\"})\n\n    -- plain match and ignore empty string\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n', {plain = true}), {\"1\", \"2\", \"3\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('123', {plain = true}), {\"abc\", \"xyz\", \"abc\"})\n\n    -- pattern match and contains empty string\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n', {strict = true}), {\"1\", \"\", \"2\", \"3\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('123', {strict = true}), {\"abc\", \"\", \"xyz\", \"abc\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('[123]+', {strict = true}), {\"abc\", \"xyz\", \"abc\"})\n    t:are_equal((\"123abc123123xyz123abc123\"):split('[123]+', {strict = true}), {\"\", \"abc\", \"xyz\", \"abc\", \"\"})\n    t:are_equal((\"123123\"):split('[123]+', {strict = true}), {\"\", \"\"})\n    t:are_equal((\"\"):split('[123]+', {strict = true}), {\"\"})\n\n    -- plain match and contains empty string\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n', {plain = true, strict = true}), {\"1\", \"\", \"2\", \"3\"})\n    t:are_equal((\"abc123123xyz123abc\"):split('123', {plain = true, strict = true}), {\"abc\", \"\", \"xyz\", \"abc\"})\n    t:are_equal((\"123abc123123xyz123abc123\"):split('123', {plain = true, strict = true}), {\"\", \"abc\", \"\", \"xyz\", \"abc\", \"\"})\n    t:are_equal((\"123\"):split('123', {plain = true, strict = true}), {\"\", \"\"})\n    t:are_equal((\"\"):split('123', {plain = true, strict = true}), {\"\"})\n\n    -- limit split count\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n', {limit = 2}), {\"1\", \"2\\n3\"})\n    t:are_equal((\"1\\n\\n2\\n3\"):split('\\n', {limit = 2, strict = true}), {\"1\", \"\\n2\\n3\"})\n    t:are_equal((\"\\n1\\n\\n2\\n3\"):split('\\n', {limit = 2, strict = true}), {\"\", \"1\\n\\n2\\n3\"})\n    t:are_equal((\"1.2.3.4.5\"):split('%.', {limit = 3}), {\"1\", \"2\", \"3.4.5\"})\n    t:are_equal((\"123.45\"):split('%.', {limit = 3}), {\"123\", \"45\"})\n    t:are_equal((\"\"):split('123', {plain = true, limit = 2, strict = true}), {\"\"})\n    t:are_equal((\"123123\"):split('123', {plain = true, limit = 2, strict = true}), {\"\", \"123\"})\nend\n\nfunction test_lastof(t)\n    t:are_equal((\"1.2.3.4.5\"):lastof('%.'), 8)\n    t:are_equal((\"1.2.3.4.5\"):lastof('.', true), 8)\n    t:are_equal((\"/home/file.txt\"):lastof('[/\\\\]'), 6)\n    t:are_equal((\"/home/file.txt\"):lastof('/', true), 6)\n    t:are_equal((\"/home/file.txt\"):lastof('/home', true), 1)\n    t:are_equal((\"/home/file.txt\"):lastof('[/\\\\]home'), 1)\n\n    -- long string\n    local longstr = (\"a\"):rep(1000) .. \"b\"\n    t:are_equal(longstr:lastof(\"b\"), 1001)\n    t:are_equal(longstr:lastof(\"a\"), 1000)\n    t:are_equal(longstr:lastof(\"b\", true), 1001)\n    t:are_equal(longstr:lastof(\"a\", true), 1000)\nend\n\nfunction test_replace(t)\n    t:are_equal((\"123xyz456xyz789xyz\"):replace(\"123\", \"000\"), \"000xyz456xyz789xyz\")\n    t:are_equal((\"123xyz456xyz789xyz\"):replace(\"xyz\", \"000\"), \"123000456000789000\")\n    t:are_equal((\"123xyz456xyz789xyz\"):replace(\"123\", \"000\", {plain = true}), \"000xyz456xyz789xyz\")\n    t:are_equal((\"123xyz456xyz789xyz\"):replace(\"xyz\", \"000\", {plain = true}), \"123000456000789000\")\n    t:are_equal((\"123$xyz456xyz789xyz\"):replace(\"123$\", \"000\"), \"123$xyz456xyz789xyz\")\n    t:are_equal((\"123xyz$456xyz$789xyz$\"):replace(\"xyz$\", \"000\"), \"123xyz$456xyz$789xyz$\")\n    t:are_equal((\"123$xyz456xyz789xyz\"):replace(\"123$\", \"000\", {plain = true}), \"000xyz456xyz789xyz\")\n    t:are_equal((\"123xyz$456xyz$789xyz$\"):replace(\"xyz$\", \"000\", {plain = true}), \"123000456000789000\")\nend\n\nfunction test_case(t)\n    t:are_equal((\"Hello\"):lower(), \"hello\")\n    t:are_equal((\"Hello\"):upper(), \"HELLO\")\n    t:are_equal((\"Звезда Хэнсин\"):lower(), \"звезда хэнсин\")\n    t:are_equal((\"Звезда Хэнсин\"):upper(), \"ЗВЕЗДА ХЭНСИН\")\n    t:are_equal((\"Test 源文件🎆 Message\"):lower(), \"test 源文件🎆 message\")\n    t:are_equal((\"Test 源文件🎆 Message\"):upper(), \"TEST 源文件🎆 MESSAGE\")\nend\n"
  },
  {
    "path": "tests/modules/table/test.lua",
    "content": "function test_remove_if(t)\n    t:are_equal(table.remove_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), {1, 3, 5})\n    t:are_equal(table.remove_if({a = 1, b = 2, c = 3}, function (i, v) return (v % 2) == 0 end), {a = 1, c = 3})\nend\n\nfunction test_find_if(t)\n    t:are_equal(table.find_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), {2, 4, 6})\n    t:are_equal(table.find_first_if({1, 2, 3, 4, 5, 6}, function (i, v) return (v % 2) == 0 end), 2)\n    t:are_equal(table.find({1, 2, 4, 4, 5, 6}, 4), {3, 4})\n    t:are_equal(table.find_first({1, 2, 3, 4, 5, 6}, 4), 4)\nend\n\nfunction test_wrap(t)\n    t:are_equal(table.wrap(1), {1})\n    t:are_equal(table.wrap(nil), {})\n    t:are_equal(table.wrap({}), {})\n    t:are_equal(table.wrap({1}), {1})\n    t:are_equal(table.wrap({{}}), {{}})\n    local a = table.wrap_lock({1})\n    t:are_equal(table.wrap({a}), {a})\nend\n\nfunction test_unwrap(t)\n    t:are_equal(table.unwrap(1), 1)\n    t:are_equal(table.unwrap(nil), nil)\n    t:are_equal(table.unwrap({}), {})\n    t:are_equal(table.unwrap({1}), 1)\n    t:are_equal(table.unwrap({{}}), {})\n    local a = table.wrap_lock({1})\n    t:are_equal(table.unwrap(a), a)\nend\n\nfunction test_orderkeys(t)\n    -- sort by modulo 2 then from the smallest to largest\n    local f = function(a, b)\n        if a % 2 == 0 and b % 2 ~= 0 then\n            return true\n        elseif b % 2 == 0 and a % 2 ~= 0 then\n            return false\n        end\n        return a < b\n    end\n\n    t:are_equal(table.orderkeys({[2] = 2, [1] = 1, [4] = 4, [3] = 3}, f), {2, 4, 1, 3})\n    t:are_equal(table.orderkeys({[1] = 1, [2] = 2, [3] = 3, [4] = 4}), {1, 2 , 3, 4})\nend\n"
  },
  {
    "path": "tests/modules/thread/coroutine.lua",
    "content": "import(\"core.base.thread\")\nimport(\"core.base.scheduler\")\n\nfunction thread_loop()\n    import(\"core.base.thread\")\n    print(\"%s: starting ..\", thread.running())\n    local dt = os.mclock()\n    for i = 1, 10 do\n        print(\"%s: %d\", thread.running(), i)\n        os.sleep(1000)\n    end\n    dt = os.mclock() - dt\n    print(\"%s: end, dt: %d ms\", thread.running(), dt)\nend\n\nfunction coroutine_loop()\n    print(\"%s: starting ..\", scheduler.co_running())\n    local dt = os.mclock()\n    for i = 1, 10 do\n        print(\"%s: %d\", scheduler.co_running(), i)\n        os.sleep(1000)\n    end\n    dt = os.mclock() - dt\n    print(\"%s: end, dt: %d ms\", scheduler.co_running(), dt)\nend\n\nfunction main()\n    scheduler.co_start_named(\"coroutine\", coroutine_loop)\n    local t = thread.start_named(\"thread\", thread_loop)\n    t:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/event.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(event)\n    import(\"core.base.thread\")\n    print(\"%s: starting ..\", thread.running())\n    while true do\n        print(\"%s: waiting ..\", thread.running())\n        if event:wait(-1) > 0 then\n            print(\"%s: triggered\", thread.running())\n        end\n    end\nend\n\nfunction main()\n    local event = thread.event()\n    local t = thread.start_named(\"keyboard\", callback, event)\n    while true do\n        local ch = io.read()\n        if ch then\n            event:post()\n        end\n    end\n    t:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/mutex.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(mutex)\n    import(\"core.base.thread\")\n    print(\"%s: starting ..\", thread.running())\n    local dt = os.mclock()\n    for i = 1, 10 do\n        mutex:lock()\n        print(\"%s: %d\", thread.running(), i)\n        mutex:unlock()\n        os.sleep(1000)\n    end\n    dt = os.mclock() - dt\n    print(\"%s: end, dt: %d ms\", thread.running(), dt)\nend\n\nfunction main()\n    local mutex = thread.mutex()\n    local t0 = thread.start_named(\"thread_0\", callback, mutex)\n    local t1 = thread.start_named(\"thread_1\", callback, mutex)\n    t0:wait(-1)\n    t1:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/queue.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(event, queue)\n    print(\"starting ..\")\n    while true do\n        print(\"waiting ..\")\n        if event:wait(-1) > 0 then\n            while not queue:empty() do\n                print(\"  -> %s\", queue:pop())\n            end\n        end\n    end\nend\n\nfunction main()\n    local event = thread.event()\n    local queue = thread.queue()\n    local t = thread.start_named(\"\", callback, event, queue)\n    while true do\n        local ch = io.read()\n        if ch then\n            queue:push(ch)\n            event:post()\n        end\n    end\n    t:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/semaphore.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(semaphore)\n    import(\"core.base.thread\")\n    print(\"%s: starting ..\", thread.running())\n    while true do\n        print(\"%s: waiting ..\", thread.running())\n        if semaphore:wait(-1) > 0 then\n            print(\"%s: triggered\", thread.running())\n        end\n    end\nend\n\nfunction main()\n    local semaphore = thread.semaphore(\"\", 1)\n    local t = thread.start_named(\"keyboard\", callback, semaphore)\n    while true do\n        local ch = io.read()\n        if ch then\n            semaphore:post(2)\n        end\n    end\n    t:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/sharedata.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(event, sharedata)\n    print(\"starting ..\")\n    while true do\n        print(\"waiting ..\")\n        if event:wait(-1) > 0 then\n            print(\"  -> %s\", sharedata:get())\n        end\n    end\nend\n\nfunction main()\n    local event = thread.event()\n    local sharedata = thread.sharedata()\n    local t = thread.start_named(\"\", callback, event, sharedata)\n    while true do\n        local ch = io.read()\n        if ch then\n            sharedata:set(ch)\n            event:post()\n        end\n    end\n    t:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/thread/sleep.lua",
    "content": "import(\"core.base.thread\")\n\nfunction callback(id)\n    import(\"core.base.thread\")\n    print(\"%s: %d starting ..\", thread.running(), id)\n    local dt = os.mclock()\n    for i = 1, 10 do\n        print(\"%s: %d\", thread.running(), i)\n        os.sleep(1000)\n    end\n    dt = os.mclock() - dt\n    print(\"%s: %d end, dt: %d ms\", thread.running(), id, dt)\nend\n\nfunction main()\n    local t0 = thread.start_named(\"thread_0\", callback, 0)\n    local t1 = thread.start_named(\"thread_1\", callback, 1)\n    t0:wait(-1)\n    t1:wait(-1)\nend\n\n"
  },
  {
    "path": "tests/modules/tty/cursor_control.lua",
    "content": "import(\"core.base.tty\")\n\n-- Demo TTY cursor position control features\n-- Implement partial screen refresh\n\nfunction _progress_bar_inline(label, progress)\n    local bar_width = 40\n    local filled = math.floor(progress * bar_width)\n    local bar = string.rep(\"█\", filled) .. string.rep(\"░\", bar_width - filled)\n\n    -- Clear the line and output content\n    tty.cr()\n    tty.erase_line()\n    io.write(string.format(\"%s: [%s] %3d%%\", label, bar, math.floor(progress * 100)))\n    io.flush()\nend\n\nfunction main()\n    -- Check if ANSI control codes are supported\n    if not tty.has_vtansi() then\n        print(\"Terminal does not support ANSI control codes\")\n        return\n    end\n\n    print(\"=== TTY Cursor Control Demo ===\")\n    print(\"This demo shows partial screen refresh using cursor positioning\")\n    print(\"\")\n\n    -- Hide cursor for smoother display\n    tty.cursor_hide()\n\n    print(\"\\nDemo 1: Multiple Progress Bars (Parallel Updates)\")\n    print(\"------------------------------------------------\")\n\n    -- Reserve lines for progress bars\n    io.write(\"Task 1: Downloading\\n\")\n    io.write(\"Task 2: Compiling  \\n\")\n    io.write(\"Task 3: Linking    \\n\")\n    io.flush()\n\n    -- Simulate three parallel task progress bars\n    for step = 1, 100 do\n        -- Move to Task 1 line (3 lines up from current position)\n        tty.cursor_move_up(3)\n\n        -- Update Task 1 progress\n        local progress1 = step / 100\n        _progress_bar_inline(\"Task 1: Downloading\", progress1)\n        io.write(\"\\n\")\n\n        -- Update Task 2 progress (starts later, progresses faster)\n        local progress2 = math.max(0, math.min(1.0, (step - 10) / 80))\n        _progress_bar_inline(\"Task 2: Compiling  \", progress2)\n        io.write(\"\\n\")\n\n        -- Update Task 3 progress (starts even later)\n        local progress3 = math.max(0, math.min(1.0, (step - 30) / 60))\n        _progress_bar_inline(\"Task 3: Linking    \", progress3)\n        io.write(\"\\n\")\n        io.flush()\n\n        os.sleep(30)  -- 30ms delay\n    end\n\n    print(\"\\n\\nDemo 2: Dynamic Status Updates\")\n    print(\"--------------------------------\")\n\n    -- Print initial status and counter\n    io.write(\"Status: Waiting...\\n\")\n    io.write(\"Counter: 0\\n\")\n    io.flush()\n\n    local statuses = {\n        \"Initializing...\",\n        \"Loading configuration...\",\n        \"Parsing files...\",\n        \"Building dependencies...\",\n        \"Compiling sources...\",\n        \"Linking executable...\",\n        \"Done!\"\n    }\n\n    for i, status in ipairs(statuses) do\n        -- Move to status line (2 lines up)\n        tty.cursor_move_up(2)\n\n        -- Update status line\n        tty.cr()\n        tty.erase_line()\n        io.write(string.format(\"Status: %s\", status))\n        io.write(\"\\n\")\n\n        -- Update counter line\n        tty.cr()\n        tty.erase_line()\n        io.write(string.format(\"Counter: %d\", i * 100))\n        io.write(\"\\n\")\n        io.flush()\n\n        os.sleep(500)\n    end\n\n    -- Restore cursor visibility\n    tty.cursor_show()\n\n    print(\"\\n\\nDemo 3: Erase and Update Specific Line\")\n    print(\"----------------------------------------\")\n\n    io.write(\"Line 1: This line will stay\\n\")\n    io.write(\"Line 2: This line will be updated...\\n\")\n    io.write(\"Line 3: This line will stay too\\n\")\n    io.flush()\n\n    os.sleep(1000)\n\n    -- Update only the middle line (2 lines up)\n    tty.cursor_move_up(2)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Line 2: Updated content! ✓\\n\")\n    io.flush()\n\n    -- Move cursor to end\n    tty.cursor_move_down(1)\n    print(\"\\n\\nAll demos completed!\")\n    print(\"\\nKey features demonstrated:\")\n    print(\"  - cursor_move_up/down/left/right: Move cursor relatively\")\n    print(\"  - cursor_save/restore: Save and restore cursor position\")\n    print(\"  - erase_line(): Clear current line\")\n    print(\"  - cursor_hide()/cursor_show(): Control cursor visibility\")\n    print(\"  - Partial screen refresh without clearing entire screen\")\nend\n\n"
  },
  {
    "path": "tests/modules/tty/live_dashboard.lua",
    "content": "import(\"core.base.tty\")\nimport(\"core.base.scheduler\")\n\n-- Demo advanced usage: Live updating dashboard\n-- Similar to build tool real-time output\n\nfunction simulate_build_process()\n    if not tty.has_vtansi() then\n        print(\"Terminal does not support ANSI control codes\")\n        return\n    end\n\n    print(\"\\nBuild Dashboard - Live Updates\")\n    print(string.rep(\"=\", 60))\n\n    -- Hide cursor\n    tty.cursor_hide()\n\n    -- Print task list\n    io.write(\"⏸ Parse project files       [\" .. string.rep(\"░\", 30) .. \"]   0%\\n\")\n    io.write(\"⏸ Resolve dependencies      [\" .. string.rep(\"░\", 30) .. \"]   0%\\n\")\n    io.write(\"⏸ Compile sources           [\" .. string.rep(\"░\", 30) .. \"]   0%\\n\")\n    io.write(\"⏸ Link executable           [\" .. string.rep(\"░\", 30) .. \"]   0%\\n\")\n    io.write(\"⏸ Create package            [\" .. string.rep(\"░\", 30) .. \"]   0%\\n\")\n    io.write(\"\\nRecent logs:\\n\")\n    io.flush()\n\n    local log_count = 0\n\n    local function update_task_line(task_index, icon, name, progress)\n        -- Move to the task line (from current cursor position)\n        -- We need to go up: log_count lines + 1 separator line + (5 - task_index) task lines\n        local lines_up = log_count + 1 + (5 - task_index + 1)\n        tty.cursor_move_up(lines_up)\n\n        tty.cr()\n        tty.erase_line()\n        local bar_width = 30\n        local filled = math.floor(progress * bar_width)\n        local bar = string.rep(\"█\", filled) .. string.rep(\"░\", bar_width - filled)\n        io.write(string.format(\"%s %-24s [%s] %3d%%\\n\", icon, name, bar, math.floor(progress * 100)))\n\n        -- Move back down\n        tty.cursor_move_down(lines_up - 1)\n        io.flush()\n    end\n\n    local function add_log(message)\n        io.write(string.format(\"[%s] %s\\n\", os.date(\"%H:%M:%S\"), message))\n        io.flush()\n        log_count = log_count + 1\n    end\n\n    scheduler.co_start(function()\n        -- Task 1: Parse (index 1, top task)\n        add_log(\"Starting project parsing...\")\n        for i = 1, 20 do\n            update_task_line(1, \"▶\", \"Parse project files\", i / 20)\n            os.sleep(50)\n        end\n        update_task_line(1, \"✓\", \"Parse project files\", 1.0)\n        add_log(\"Project parsed successfully\")\n        os.sleep(200)\n\n        -- Task 2: Dependencies (index 2)\n        add_log(\"Resolving dependencies...\")\n        for i = 1, 15 do\n            update_task_line(2, \"▶\", \"Resolve dependencies\", i / 15)\n            os.sleep(80)\n        end\n        update_task_line(2, \"✓\", \"Resolve dependencies\", 1.0)\n        add_log(\"Dependencies resolved: 12 packages\")\n        os.sleep(200)\n\n        -- Task 3: Compile (index 3)\n        add_log(\"Compiling source files...\")\n        local source_files = {\"main.cpp\", \"utils.cpp\", \"config.cpp\", \"parser.cpp\", \"builder.cpp\"}\n        for i = 1, #source_files do\n            update_task_line(3, \"▶\", \"Compile sources\", i / #source_files)\n            add_log(\"Compiling \" .. source_files[i])\n            os.sleep(300)\n        end\n        update_task_line(3, \"✓\", \"Compile sources\", 1.0)\n        add_log(\"Compilation completed: 5 files\")\n        os.sleep(200)\n\n        -- Task 4: Link (index 4)\n        add_log(\"Linking executable...\")\n        for i = 1, 10 do\n            update_task_line(4, \"▶\", \"Link executable\", i / 10)\n            os.sleep(100)\n        end\n        update_task_line(4, \"✓\", \"Link executable\", 1.0)\n        add_log(\"Executable created: build/myapp\")\n        os.sleep(200)\n\n        -- Task 5: Package (index 5, bottom task)\n        add_log(\"Creating package...\")\n        for i = 1, 8 do\n            update_task_line(5, \"▶\", \"Create package\", i / 8)\n            os.sleep(120)\n        end\n        update_task_line(5, \"✓\", \"Create package\", 1.0)\n        add_log(\"Package created: dist/myapp-1.0.0.tar.gz\")\n\n        -- Done\n        os.sleep(500)\n        add_log(\"Build completed successfully! 🎉\")\n\n        -- Restore cursor\n        os.sleep(1000)\n        tty.cursor_show()\n\n        print(\"\\nBuild process completed!\")\n    end)\nend\n\nfunction demo_spinner()\n    if not tty.has_vtansi() then\n        return\n    end\n\n    print(\"\\n\\n=== Spinner Demo ===\")\n    io.write(\"Loading\\n\")\n    io.flush()\n\n    local frames = {\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"}\n    tty.cursor_hide()\n\n    for round = 1, 3 do\n        for _, frame in ipairs(frames) do\n            tty.cursor_move_up(1)\n            tty.cr()\n            tty.erase_line()\n            io.write(string.format(\"Loading %s [round %d/3]\\n\", frame, round))\n            io.flush()\n            os.sleep(80)\n        end\n    end\n\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Loading ✓ Complete!\\n\")\n    io.flush()\n    tty.cursor_show()\nend\n\nfunction main()\n    print(\"\\n\" .. string.rep(\"=\", 60))\n    print(\"TTY Live Dashboard Demo\")\n    print(string.rep(\"=\", 60))\n\n    -- Demo 1: Spinner\n    demo_spinner()\n\n    os.sleep(1000)\n\n    -- Demo 2: Build Dashboard\n    simulate_build_process()\nend\n\n"
  },
  {
    "path": "tests/modules/tty/quick_example.lua",
    "content": "-- Quick example: Demonstrates the most common use cases\n\nimport(\"core.base.tty\")\n\nfunction example1_simple_progress()\n    print(\"\\n=== Example 1: Simple Progress Bar ===\\n\")\n\n    if not tty.has_vtansi() then\n        print(\"ANSI not supported\")\n        return\n    end\n\n    print(\"Downloading file...\")\n    for i = 0, 100, 5 do\n        local width = 40\n        local filled = math.floor(i / 100 * width)\n        local bar = string.rep(\"█\", filled) .. string.rep(\"░\", width - filled)\n\n        -- Move to start of line, clear it, and redraw\n        tty.cr()\n        tty.erase_line()\n        io.write(string.format(\"[%s] %3d%%\", bar, i))\n        io.flush()\n\n        os.sleep(50)\n    end\n    print(\"\")  -- New line after progress\nend\n\nfunction example2_update_previous_line()\n    print(\"\\n=== Example 2: Update Previous Line ===\\n\")\n\n    if not tty.has_vtansi() then\n        print(\"ANSI not supported\")\n        return\n    end\n\n    io.write(\"Building project...\\n\")\n    io.write(\"Status: Starting...\\n\")\n    io.flush()\n\n    os.sleep(1000)\n\n    -- Go back and update the status line\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Status: Compiling files...\\n\")\n    io.flush()\n\n    os.sleep(1000)\n\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Status: Done! ✓\\n\")\n    io.flush()\nend\n\nfunction example3_multi_line_update()\n    print(\"\\n=== Example 3: Multi-line Updates ===\\n\")\n\n    if not tty.has_vtansi() then\n        print(\"ANSI not supported\")\n        return\n    end\n\n    -- Create a simple status board\n    io.write(\"Task 1: Waiting...\\n\")\n    io.write(\"Task 2: Waiting...\\n\")\n    io.write(\"Task 3: Waiting...\\n\")\n    io.flush()\n\n    tty.cursor_hide()\n\n    -- Update Task 1 to Running\n    tty.cursor_move_up(3)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 1: Running... \\n\")\n    io.flush()\n    os.sleep(500)\n\n    -- Update Task 1 to Done\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 1: Done ✓\\n\")\n    io.flush()\n\n    -- Update Task 2 to Running\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 2: Running... \\n\")\n    io.flush()\n    os.sleep(500)\n\n    -- Update Task 2 to Done\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 2: Done ✓\\n\")\n    io.flush()\n\n    -- Update Task 3 to Running\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 3: Running... \\n\")\n    io.flush()\n    os.sleep(500)\n\n    -- Update Task 3 to Done\n    tty.cursor_move_up(1)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Task 3: Done ✓\\n\")\n    io.flush()\n\n    tty.cursor_show()\nend\n\nfunction main()\n    print(string.rep(\"=\", 60))\n    print(\"TTY Cursor Control - Quick Examples\")\n    print(string.rep(\"=\", 60))\n\n    example1_simple_progress()\n    example2_update_previous_line()\n    example3_multi_line_update()\n\n    print(\"\\n\" .. string.rep(\"=\", 60))\n    print(\"All examples completed!\")\n    print(\"Check test.lua, cursor_control.lua, and live_dashboard.lua\")\n    print(\"for more advanced examples.\")\n    print(string.rep(\"=\", 60))\nend\n\n"
  },
  {
    "path": "tests/modules/tty/test.lua",
    "content": "import(\"core.base.tty\")\n\nfunction test_cursor_move()\n    if not tty.has_vtansi() then\n        print(\"Terminal does not support ANSI control codes, skipping test\")\n        return\n    end\n\n    print(\"\\n=== Test: cursor_move ===\")\n    io.write(\"Line 1\\n\")\n    io.write(\"Line 2\\n\")\n    io.write(\"Line 3\\n\")\n    io.write(\"Line 4\\n\")\n    io.write(\"Line 5\\n\")\n    io.flush()\n\n    os.sleep(1000)\n\n    -- Move to line 3 and update content\n    tty.cursor_move_up(3)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Line 3 - UPDATED!\\n\")\n    io.flush()\n\n    -- Move cursor back to end\n    tty.cursor_move_down(2)\n\n    print(\"\\n✓ cursor_move_up test passed\")\nend\n\nfunction test_cursor_move_directions()\n    if not tty.has_vtansi() then\n        return\n    end\n\n    print(\"\\n=== Test: cursor movement directions ===\")\n\n    -- Create a small coordinate system\n    for i = 1, 5 do\n        io.write(string.rep(\" \", 60) .. \"\\n\")\n    end\n    io.flush()\n\n    -- Move to starting position\n    tty.cursor_move_up(5)\n    tty.cursor_move_right(10)\n    io.write(\"START\")\n    io.flush()\n    os.sleep(500)\n\n    -- Move right\n    tty.cursor_move_right(10)\n    io.write(\"RIGHT\")\n    io.flush()\n    os.sleep(500)\n\n    -- Move down\n    tty.cursor_move_down(2)\n    io.write(\"DOWN\")\n    io.flush()\n    os.sleep(500)\n\n    -- Move left\n    tty.cursor_move_left(5)\n    io.write(\"LEFT\")\n    io.flush()\n    os.sleep(500)\n\n    -- Move up\n    tty.cursor_move_up(1)\n    io.write(\"UP\")\n    io.flush()\n\n    -- Move to end\n    tty.cursor_move_down(3)\n    io.write(\"\\n\")\n    io.flush()\n\n    print(\"✓ cursor movement directions test passed\")\nend\n\nfunction test_cursor_hide_show()\n    if not tty.has_vtansi() then\n        return\n    end\n\n    print(\"\\n=== Test: cursor hide/show ===\")\n\n    print(\"Cursor is visible now...\")\n    os.sleep(1000)\n\n    tty.cursor_hide()\n    print(\"Cursor is hidden now (you shouldn't see it blinking)...\")\n    os.sleep(2000)\n\n    tty.cursor_show()\n    print(\"Cursor is visible again!\")\n\n    print(\"✓ cursor hide/show test passed\")\nend\n\nfunction test_erase_operations()\n    if not tty.has_vtansi() then\n        return\n    end\n\n    print(\"\\n=== Test: erase operations ===\")\n\n    -- Test erase_line_to_end\n    io.write(\"This is a long line that will be partially erased\")\n    io.flush()\n    os.sleep(1000)\n    tty.cursor_move_left(30)\n    tty.erase_line_to_end()\n    io.write(\"<- erased to end\\n\")\n    io.flush()\n\n    os.sleep(1000)\n\n    -- Test full line erase\n    io.write(\"This entire line will be erased\")\n    io.flush()\n    os.sleep(1000)\n    tty.cr()\n    tty.erase_line()\n    io.write(\"Replaced!\\n\")\n    io.flush()\n\n    print(\"✓ erase operations test passed\")\nend\n\nfunction test_partial_screen_update()\n    if not tty.has_vtansi() then\n        return\n    end\n\n    print(\"\\n=== Test: partial screen update ===\")\n\n    -- Create a table\n    io.write(\"┌────────────────────────────────┐\\n\")\n    io.write(\"│ Task         │ Status          │\\n\")\n    io.write(\"├────────────────────────────────┤\\n\")\n    io.write(\"│ Compile      │ Pending...      │\\n\")\n    io.write(\"│ Link         │ Pending...      │\\n\")\n    io.write(\"│ Package      │ Pending...      │\\n\")\n    io.write(\"└────────────────────────────────┘\\n\")\n    io.flush()\n\n    os.sleep(1000)\n    tty.cursor_hide()\n\n    -- Update first task status\n    tty.cursor_move_up(4)\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Running...      │\\n\")\n    io.flush()\n    os.sleep(800)\n\n    tty.cursor_move_up(1)\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Done! ✓         │\\n\")\n    io.flush()\n    os.sleep(500)\n\n    -- Update second task status\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Running...      │\\n\")\n    io.flush()\n    os.sleep(800)\n\n    tty.cursor_move_up(1)\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Done! ✓         │\\n\")\n    io.flush()\n    os.sleep(500)\n\n    -- Update third task status\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Running...      │\\n\")\n    io.flush()\n    os.sleep(800)\n\n    tty.cursor_move_up(1)\n    tty.cursor_move_to_col(32)\n    tty.erase_line_to_end()\n    io.write(\"│ Done! ✓         │\\n\")\n    io.flush()\n\n    tty.cursor_show()\n    tty.cursor_move_down(1)\n\n    print(\"\\n✓ partial screen update test passed\")\nend\n\nfunction main(...)\n    -- Run all tests\n    test_cursor_move()\n    test_cursor_move_directions()\n    test_cursor_hide_show()\n    test_erase_operations()\n    test_partial_screen_update()\n\n    print(\"\\n\" .. string.rep(\"=\", 50))\n    print(\"All TTY cursor control tests completed!\")\n    print(string.rep(\"=\", 50))\nend\n\n"
  },
  {
    "path": "tests/modules/utf8/test.lua",
    "content": "\nfunction test_len(t)\n    t:are_equal(utf8.len(\"A\"), 1)\n    t:are_equal(utf8.len(\"¢\"), 1)\n    t:are_equal(utf8.len(\"€\"), 1)\n    t:are_equal(utf8.len(\"𐍈\"), 1)\n    t:are_equal(utf8.len(\"ab\"), 2)\n    t:are_equal(utf8.len(\"A€B\"), 3)\n    t:are_equal(utf8.len(\"你好\"), 2)\nend\n\nfunction test_char(t)\n    t:are_equal(utf8.char(65), \"A\")\n    t:are_equal(utf8.char(0x20AC), \"€\")\n    t:are_equal(utf8.char(65, 66, 67), \"ABC\")\nend\n\nfunction test_codepoint(t)\n    t:are_equal(utf8.codepoint(\"A\"), 65)\n    t:are_equal(utf8.codepoint(\"€\"), 0x20AC)\n    local c1, c2, c3 = utf8.codepoint(\"ABC\", 1, 3)\n    t:are_equal(c1, 65)\n    t:are_equal(c2, 66)\n    t:are_equal(c3, 67)\n\n    -- test range\n    t:are_equal(utf8.codepoint(\"ABC\", 2), 66)\n    t:are_equal(utf8.codepoint(\"ABC\", 2, 2), 66)\nend\n\nfunction test_offset(t)\n    t:are_equal(utf8.offset(\"ABC\", 1), 1)\n    t:are_equal(utf8.offset(\"ABC\", 2), 2)\n    t:are_equal(utf8.offset(\"ABC\", 4), 4)\n    t:are_equal(utf8.offset(\"ABC\", 5), nil)\n\n    -- \"€\" is 3 bytes (0xE2 0x82 0xAC)\n    t:are_equal(utf8.offset(\"€BC\", 1), 1)\n    t:are_equal(utf8.offset(\"€BC\", 2), 4)\n    t:are_equal(utf8.offset(\"€BC\", 3), 5)\n\n    t:are_equal(utf8.offset(\"你好\", 1), 1)\n    t:are_equal(utf8.offset(\"你好\", 2), 4)\n    t:are_equal(utf8.offset(\"你好\", 3), 7)\nend\n\nfunction test_codes(t)\n    local s = \"A€\"\n    local codes = {}\n    for p, c in utf8.codes(s) do\n        table.insert(codes, {p, c})\n    end\n    t:are_equal(#codes, 2)\n    t:are_equal(codes[1][1], 1)\n    t:are_equal(codes[1][2], 65)\n    -- \"€\" starts at 2? No, byte offset.\n    -- \"A\" is 1 byte. \"€\" starts at 2.\n    t:are_equal(codes[2][1], 2)\n    t:are_equal(codes[2][2], 0x20AC)\nend\n\nfunction test_charpattern(t)\n    t:require(utf8.charpattern)\nend\n\nfunction test_sub(t)\n    t:are_equal(utf8.sub(\"ABC\", 1, 1), \"A\")\n    t:are_equal(utf8.sub(\"ABC\", 2, 2), \"B\")\n    t:are_equal(utf8.sub(\"ABC\", 1, 2), \"AB\")\n    t:are_equal(utf8.sub(\"你好\", 1, 1), \"你\")\n    t:are_equal(utf8.sub(\"你好\", 2, 2), \"好\")\n    t:are_equal(utf8.sub(\"你好\", 1, 2), \"你好\")\n\n    -- mixed\n    t:are_equal(utf8.sub(\"A你好B\", 2, 3), \"你好\")\n    t:are_equal(utf8.sub(\"A你好B\", 1, 3), \"A你好\")\n    t:are_equal(utf8.sub(\"A你好B\", 2, 4), \"你好B\")\n\n    -- negative\n    t:are_equal(utf8.sub(\"ABC\", -1), \"C\")\n    t:are_equal(utf8.sub(\"ABC\", -2), \"BC\")\n    t:are_equal(utf8.sub(\"你好\", -1), \"好\")\n    t:are_equal(utf8.sub(\"你好\", -2), \"你好\")\n    t:are_equal(utf8.sub(\"你好\", 1, -1), \"你好\")\n    t:are_equal(utf8.sub(\"你好\", 1, -2), \"你\")\n\n    -- out of bounds\n    t:are_equal(utf8.sub(\"ABC\", 4), \"\")\n    t:are_equal(utf8.sub(\"ABC\", 1, 5), \"ABC\")\n    t:are_equal(utf8.sub(\"ABC\", 0), \"ABC\")\n    t:are_equal(utf8.sub(\"ABC\", -10), \"ABC\")\nend\n\nfunction test_lastof(t)\n    t:are_equal(utf8.lastof(\"ABC\", \"A\"), 1)\n    t:are_equal(utf8.lastof(\"ABC\", \"B\"), 2)\n    t:are_equal(utf8.lastof(\"ABC\", \"C\"), 3)\n    t:are_equal(utf8.lastof(\"ABCA\", \"A\"), 4)\n\n    t:are_equal(utf8.lastof(\"你好\", \"你\"), 1)\n    t:are_equal(utf8.lastof(\"你好\", \"好\"), 2)\n    t:are_equal(utf8.lastof(\"你好你\", \"你\"), 3)\n\n    t:are_equal(utf8.lastof(\"A你好A\", \"A\"), 4)\n    t:are_equal(utf8.lastof(\"A你好A\", \"好\"), 3)\n\n    t:are_equal(utf8.lastof(\"ABC\", \"D\"), nil)\n\n    -- plain\n    t:are_equal(utf8.lastof(\"ABC\", \"A\", true), 1)\n    t:are_equal(utf8.lastof(\"ABC\", \"B\", true), 2)\n    t:are_equal(utf8.lastof(\"ABC\", \".\", true), nil)\n    t:are_equal(utf8.lastof(\"你好\", \"好\", true), 2)\n    t:are_equal(utf8.lastof(\"C你好D\", \"好\", true), 3)\n    t:are_equal(utf8.lastof(\"C你好D\", \"D\", true), 4)\n\n    -- long string\n    local longstr = (\"你\"):rep(1000) .. \"好\"\n    t:are_equal(utf8.lastof(longstr, \"好\"), 1001)\n    t:are_equal(utf8.lastof(longstr, \"你\"), 1000)\n    t:are_equal(utf8.lastof(longstr, \"好\", true), 1001)\n    t:are_equal(utf8.lastof(longstr, \"你\", true), 1000)\n\n    -- pattern\n    t:are_equal(utf8.lastof(\"ABC\", \".\"), 3)\n    t:are_equal(utf8.lastof(\"你好\", \".\"), 2)\nend\n\nfunction test_find(t)\n    -- plain\n    t:are_equal({utf8.find(\"你好\", \"你\", 1, true)}, {1, 1})\n    t:are_equal({utf8.find(\"你好你\", \"你\", 2, true)}, {3, 3})\n    t:are_equal({utf8.find(\"A你好A\", \"A\", 2, true)}, {4, 4})\n    t:are_equal(utf8.find(\"ABC\", \"D\", 1, true), nil)\n    t:are_equal({utf8.find(\"ABC\", \"\", 1, true)}, {1, 0})\n\n    -- pattern matching (default)\n    t:are_equal({utf8.find(\"ABC\", \"B\")}, {2, 2})\n    t:are_equal({utf8.find(\"ABC\", \"([BC])\")}, {2, 2, \"B\"}) -- Capture\n    t:are_equal({utf8.find(\"ABC\", \"(.)(.)\")}, {1, 2, \"A\", \"B\"})\n\n    -- UTF-8 pattern matching (byte-based)\n    -- \"你\" is 3 bytes. \".\" matches first byte.\n    t:are_equal({utf8.find(\"你好\", \".\")}, {1, 1})\n\n    -- \"你好\", \"好\" -> bytes 4-6.\n    t:are_equal({utf8.find(\"你好\", \"好\")}, {2, 2})\n\n    -- \"你好\", \"...\" (3 dots) -> matches 3 bytes (whole \"你\").\n    t:are_equal({utf8.find(\"你好\", \"...\")}, {1, 1})\n\n    -- \"A你好\", \"%w\" -> matches \"A\".\n    t:are_equal({utf8.find(\"A你好\", \"%w\")}, {1, 1})\nend\n\nfunction test_width(t)\n    -- char/codepoint width\n    t:are_equal(utf8.width(string.byte(\"A\")), 1)\n    t:are_equal(utf8.width(utf8.codepoint(\"€\")), 1)\n    t:are_equal(utf8.width(utf8.codepoint(\"你\")), 2)\n    t:are_equal(utf8.width(0), 0)\n    t:are_equal(utf8.width(0x09), 4) -- TAB\n\n    -- string width\n    t:are_equal(utf8.width(\"A\"), 1)\n    t:are_equal(utf8.width(\"ABC\"), 3)\n    t:are_equal(utf8.width(\"你好\"), 4)\n    t:are_equal(utf8.width(\"A你好\"), 5)\n    t:are_equal(utf8.width(\"A\\tB\"), 6) -- 1 + 4 + 1\nend\n\nfunction test_byte(t)\n    t:are_equal({utf8.byte(\"A\")}, {65})\n    t:are_equal({utf8.byte(\"€\")}, {0x20AC})\n    t:are_equal({utf8.byte(\"ABC\")}, {65})\n    t:are_equal({utf8.byte(\"ABC\", 2)}, {66})\n    t:are_equal({utf8.byte(\"ABC\", 2, 2)}, {66})\n    t:are_equal({utf8.byte(\"ABC\", 1, 3)}, {65, 66, 67})\n    t:are_equal({utf8.byte(\"你好\")}, {utf8.codepoint(\"你好\", 1, 1)})\n    t:are_equal({utf8.byte(\"你好\", 1, 2)}, {20320, 22909})\n\n    -- negative indices\n    t:are_equal({utf8.byte(\"ABC\", -1)}, {67})\n    t:are_equal({utf8.byte(\"ABC\", -2)}, {66})\n    t:are_equal({utf8.byte(\"ABC\", -2, -1)}, {66, 67})\n    t:are_equal({utf8.byte(\"ABC\", 1, -1)}, {65, 66, 67})\n\n    -- out of bounds\n    t:are_equal({utf8.byte(\"ABC\", 4)}, {})\n    t:are_equal({utf8.byte(\"ABC\", 1, 0)}, {})\nend\n\nfunction test_reverse(t)\n    t:are_equal(utf8.reverse(\"hello\"), \"olleh\")\n    t:are_equal(utf8.reverse(\"你好\"), \"好你\")\n    t:are_equal(utf8.reverse(\"hello 你好\"), \"好你 olleh\")\nend\n"
  },
  {
    "path": "tests/modules/xml/test.lua",
    "content": "import(\"core.base.xml\")\n\nfunction test_decode_basic(t)\n    local doc = xml.decode([[<?xml version=\"1.0\"?><root id=\"1\"><item>foo</item><item id=\"2\"/></root>]])\n    t:are_equal(doc.kind, \"element\")\n    t:are_equal(doc.name, \"root\")\n    t:are_equal(doc.attrs.id, \"1\")\n    t:are_equal(#doc.children, 2)\n    t:are_equal(doc.children[1].name, \"item\")\n    t:are_equal(xml.text_of(doc.children[1]), \"foo\")\n    t:are_equal(doc.children[1].attrs, nil)\n    t:are_equal(doc.children[2].attrs.id, \"2\")\nend\n\nfunction test_decode_unquoted_attrs(t)\n    local doc = xml.decode(\"<root flag=true count=42 path=/tmp/file><child data=abc/></root>\")\n    t:are_equal(doc.attrs.flag, \"true\")\n    t:are_equal(doc.attrs.count, \"42\")\n    t:are_equal(doc.attrs.path, \"/tmp/file\")\n    t:are_equal(doc.children[1].attrs.data, \"abc\")\nend\n\nfunction test_decode_mixed_attrs(t)\n    local xmltext = [[<node a=\"1 2\" b='foo &amp; bar' c=bare data-id=abc123 ns:flag=true dashed-name=\"hello-world\"/>]]\n    local doc = xml.decode(xmltext)\n    t:are_equal(doc.attrs.a, \"1 2\")\n    t:are_equal(doc.attrs.b, \"foo & bar\")\n    t:are_equal(doc.attrs.c, \"bare\")\n    t:are_equal(doc.attrs[\"data-id\"], \"abc123\")\n    t:are_equal(doc.attrs[\"ns:flag\"], \"true\")\n    t:are_equal(doc.attrs[\"dashed-name\"], \"hello-world\")\nend\n\nfunction test_encode_basic(t)\n    local doc = xml.new({\n        name = \"root\",\n        attrs = {id = \"1\"},\n        children = {\n            xml.new({name = \"item\", children = {xml.text(\"foo\")}}),\n            xml.new({name = \"item\", attrs = {id = \"2\"}})\n        }\n    })\n    local compact = xml.encode(doc)\n    t:are_equal(compact, '<root id=\"1\"><item>foo</item><item id=\"2\"/></root>')\n    local pretty = xml.encode(doc, {pretty = true, indent = 2})\n    local expected = table.concat({\n        '<root id=\"1\">',\n        '  <item>foo</item>',\n        '  <item id=\"2\"/>',\n        '</root>'\n    }, \"\\n\")\n    t:are_equal(pretty, expected)\nend\n\nfunction test_encode_special_nodes(t)\n    t:are_equal(xml.encode(xml.comment(\"note\")), \"<!--note-->\")\n    t:are_equal(xml.encode(xml.cdata(\"a < b\")), \"<![CDATA[a < b]]>\")\n    t:are_equal(xml.encode(xml.doctype(\"note SYSTEM \\\"note.dtd\\\"\")), \"<!DOCTYPE note SYSTEM \\\"note.dtd\\\">\")\n    t:are_equal(xml.encode(xml.empty(\"br\")), \"<br/>\")\nend\n\nfunction test_decode_special_nodes(t)\n    local doc = xml.decode([=[<root><!--note--><![CDATA[a < b]]><child/></root>]=])\n    t:are_equal(doc.children[1].kind, \"comment\")\n    t:are_equal(doc.children[1].text, \"note\")\n    t:are_equal(doc.children[2].kind, \"cdata\")\n    t:are_equal(doc.children[2].text, \"a < b\")\n    t:are_equal(doc.children[3].name, \"child\")\n    local nodes = xml.decode([=[<!DOCTYPE note SYSTEM \"note.dtd\"><root/>]=])\n    t:are_equal(nodes.kind, \"element\")\n    t:are_equal(nodes.name, \"root\")\n    t:are_equal(nodes.prolog[1].kind, \"doctype\")\nend\n\nfunction test_load_save(t)\n    local tmpdir = os.tmpdir()\n    local filepath = path.join(tmpdir, \"xml_test.xml\")\n    local doc = xml.new({\n        name = \"root\",\n        attrs = {id = \"1\"},\n        children = {xml.text(\"hello\")}\n    })\n    assert(xml.savefile(filepath, doc, {pretty = true}))\n    local reloaded = xml.loadfile(filepath)\n    t:are_equal(reloaded.name, \"root\")\n    t:are_equal(xml.text_of(reloaded), \"hello\")\n    os.tryrm(filepath)\nend\n\nfunction test_plist_sample(t)\n    local plist = [[<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>CFBundleDevelopmentRegion</key>\n    <string>$(DEVELOPMENT_LANGUAGE)</string>\n    <key>CFBundleExecutable</key>\n    <string>$(EXECUTABLE_NAME)</string>\n    <key>CFBundleIdentifier</key>\n    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n    <key>NSHumanReadableCopyright</key>\n    <string>Copyright © 2020 tboox. All rights reserved.</string>\n    <key>NSSupportsAutomaticTermination</key>\n    <true/>\n</dict>\n</plist>]]\n    local doc = xml.decode(plist)\n    t:are_equal(doc.name, \"plist\")\n    t:are_equal(doc.attrs.version, \"1.0\")\n    t:are_equal(doc.prolog[1].kind, \"doctype\")\n    local dict = xml.find(doc, \"plist/dict\")\n    t:are_equal(dict.kind, \"element\")\n    local first_key = dict.children[1]\n    t:are_equal(first_key.name, \"key\")\n    t:are_equal(xml.text_of(first_key), \"CFBundleDevelopmentRegion\")\n    local first_value = dict.children[2]\n    t:are_equal(first_value.name, \"string\")\n    t:are_equal(xml.text_of(first_value), \"$(DEVELOPMENT_LANGUAGE)\")\n    local last_flag = dict.children[#dict.children]\n    t:are_equal(last_flag.name, \"true\")\nend\n\nfunction test_scan_stop(t)\n    local plist = [[\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>CFBundleExecutable</key>\n    <string>$(EXECUTABLE_NAME)</string>\n    <key>NSPrincipalClass</key>\n    <string>NSApplication</string>\n  </dict>\n</plist>]]\n    local found\n    xml.scan(plist, function(node)\n        if node.name == \"key\" and xml.text_of(node) == \"NSPrincipalClass\" then\n            found = node\n            return false\n        end\n    end)\n    t:are_equal(found ~= nil, true)\n    t:are_equal(xml.text_of(found), \"NSPrincipalClass\")\nend\n\nfunction test_find_xpath(t)\n    local doc = xml.decode([[\n<root>\n  <items>\n    <item id=\"a\"><value>foo</value></item>\n    <item id=\"b\"><value>bar</value></item>\n  </items>\n  <extras>\n    <item id=\"c\"/>\n  </extras>\n</root>]])\n    local second = xml.find(doc, \"root/items/item[2]\")\n    t:are_equal(second.attrs.id, \"b\")\n    local descendant = xml.find(doc, \"//item[@id='c']\")\n    t:are_equal(descendant.attrs.id, \"c\")\n    local value = xml.find(doc, \"//value[text()='bar']\")\n    t:are_equal(xml.text_of(value), \"bar\")\nend\n\nfunction test_find_update(t)\n    local doc = xml.decode(\"<root><item id='a'>foo</item><item id='b'/></root>\")\n    local target = xml.find(doc, \"//item[@id='a']\")\n    t:are_not_equal(target, nil)\n    target.attrs.lang = \"en\"\n    target.children = {xml.text(\"bar\")}\n    local new_item = xml.new({name = \"item\", attrs = {id = \"c\"}, children = {xml.text(\"baz\")}})\n    table.insert(doc.children, new_item)\n    local encoded = xml.encode(doc)\n    t:are_equal(encoded, '<root><item id=\"a\" lang=\"en\">bar</item><item id=\"b\"/><item id=\"c\">baz</item></root>')\nend\n\nfunction test_decode_trim_text(t)\n    local doc = xml.decode(\"<root>  foo  </root>\")\n    t:are_equal(xml.text_of(doc), \"  foo  \")\n    local trimmed = xml.decode(\"<root>  foo  </root>\", {trim_text = true})\n    t:are_equal(xml.text_of(trimmed), \"foo\")\n    local formatted = \"<root>\\n  <item/>\\n</root>\"\n    local default = xml.decode(formatted)\n    t:are_equal(#default.children, 1)\n    local keep_ws = xml.decode(formatted, {keep_whitespace_nodes = true})\n    t:are_equal(#keep_ws.children, 3)\n    t:are_equal(keep_ws.children[1].kind, \"text\")\nend\n\n"
  },
  {
    "path": "tests/plugins/create/test.lua",
    "content": "function main ()\n    os.tryrm(\"$(tmpdir)/test_create\")\n    os.exec(\"xmake create -P $(tmpdir)/test_create/test\")\n    os.exec(\"xmake -vD -P $(tmpdir)/test_create/test\")\n    os.exec(\"xmake create -l c++ -P $(tmpdir)/test_create/test_cpp\")\n    os.exec(\"xmake -vD -P $(tmpdir)/test_create/test_cpp\")\n    os.exec(\"xmake create -l c++ -t static -P $(tmpdir)/test_create/test_cpp2\")\n    os.exec(\"xmake -vD -P $(tmpdir)/test_create/test_cpp2\")\n    os.exec(\"xmake create -l c++ -t shared -P $(tmpdir)/test_create/test_cpp3\")\n    os.exec(\"xmake -vD -P $(tmpdir)/test_create/test_cpp3\")\nend\n"
  },
  {
    "path": "tests/plugins/macro/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/plugins/macro/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/plugins/macro/test.lua",
    "content": "function test_macro(t)\n    -- we force to enable ccache to test it on ci\n    os.exec(\"xmake f --mode=debug --policies=build.ccache:y -D -y\")\n    os.exec(\"xmake m -b\")\n    os.exec(\"xmake -r -a -D\")\n    os.exec(\"xmake m -e buildtest\")\n    os.exec(\"xmake m -l\")\n    os.exec(\"xmake m buildtest\")\n    os.exec(\"xmake m -d buildtest\")\nend\n\n"
  },
  {
    "path": "tests/plugins/macro/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"macro\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/plugins/pack/console/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/plugins/pack/console/LICENSE.md",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2015-present Xmake Open Source Community\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "tests/plugins/pack/console/include/foo/foo.h",
    "content": ""
  },
  {
    "path": "tests/plugins/pack/console/include/test.h",
    "content": ""
  },
  {
    "path": "tests/plugins/pack/console/src/assets/file1.txt",
    "content": "hello\n"
  },
  {
    "path": "tests/plugins/pack/console/src/assets/file2.txt",
    "content": "hello\n"
  },
  {
    "path": "tests/plugins/pack/console/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/plugins/pack/console/src/xmake.rc",
    "content": "IDI_APP ICON DISCARDABLE \"assets/xmake.ico\"\n"
  },
  {
    "path": "tests/plugins/pack/console/xmake.lua",
    "content": "set_version(\"1.0.0\")\nadd_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/xpack\")\n\nadd_requires(\"zlib\", {configs = {shared = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    if is_plat(\"windows\") then\n        add_files(\"src/*.rc\")\n    end\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/*.cpp\")\n    add_headerfiles(\"include/(*.h)\")\n    add_packages(\"zlib\")\n\nxpack(\"test\")\n    set_formats(\"nsis\", \"srpm\", \"rpm\", \"deb\", \"zip\", \"targz\", \"tarxz\", \"srczip\", \"srctargz\", \"srctarxz\", \"runself\", \"wix\", \"dmg\", \"appimage\")\n    set_title(\"hello\")\n    set_author(\"ruki <waruqi@gmail.com>\")\n    set_description(\"A test installer.\")\n    set_homepage(\"https://xmake.io\")\n    set_license(\"Apache-2.0\")\n    set_licensefile(\"LICENSE.md\")\n    add_targets(\"test\", \"foo\")\n    add_installfiles(\"src/(assets/*.png)\", {prefixdir = \"images\"})\n    add_sourcefiles(\"(src/**)\")\n    add_sourcefiles(\"xmake.lua\")\n    add_components(\"LongPath\")\n\n    on_load(function (package)\n        if package:with_source() then\n            package:set(\"basename\", \"test-$(plat)-src-v$(version)\")\n        else\n            package:set(\"basename\", \"test-$(plat)-$(arch)-v$(version)\")\n        end\n        -- set icon file based on format (use PNG for appimage, ICO for other formats)\n        local scriptdir = os.scriptdir()\n        if package:format() == \"appimage\" then\n            package:set(\"iconfile\", path.join(scriptdir, \"src/assets/xmake.png\"))\n        else\n            package:set(\"iconfile\", path.join(scriptdir, \"src/assets/xmake.ico\"))\n        end\n    end)\n\n    after_installcmd(function (package, batchcmds)\n        if package:format() == \"runself\" then\n            batchcmds:runv(\"echo\", {\"hello\"})\n        else\n            batchcmds:mkdir(package:installdir(\"resources\"))\n            batchcmds:cp(\"src/assets/*.txt\", package:installdir(\"resources\"), {rootdir = \"src\"})\n            batchcmds:mkdir(package:installdir(\"stub\"))\n        end\n    end)\n\n    after_uninstallcmd(function (package, batchcmds)\n        batchcmds:rmdir(package:installdir(\"resources\"))\n        batchcmds:rmdir(package:installdir(\"stub\"))\n    end)\n\nxpack_component(\"LongPath\")\n    set_default(false)\n    set_title(\"Enable Long Path\")\n    set_description(\"Increases the maximum path length limit, up to 32,767 characters (before 256).\")\n    on_installcmd(function (component, batchcmds)\n        batchcmds:rawcmd(\"wix\", [[\n    <RegistryKey Root=\"HKLM\" Key=\"SYSTEM\\CurrentControlSet\\Control\\FileSystem\">\n        <RegistryValue Type=\"integer\" Name=\"LongPathsEnabled\" Value=\"1\" KeyPath=\"yes\"/>\n    </RegistryKey>\n        ]])\n        batchcmds:rawcmd(\"nsis\", [[\n  ${If} $NoAdmin == \"false\"\n    ; Enable long path\n    WriteRegDWORD ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\FileSystem\" \"LongPathsEnabled\" 1\n  ${EndIf}]])\n    end)\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  macapp\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  macapp\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icon_16x16.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icon_16x16@2x.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"icon_32x32.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icon_32x32@2x.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"icon_128x128.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icon_128x128@2x.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"icon_256x256.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icon_256x256@2x.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"icon_512x512.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"icon_512x512@2x.png\",\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"macapp\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"macapp\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About macapp\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Quit macapp\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string>AppIcon</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  macapp\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  macapp\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/src/main.m",
    "content": "//\n//  main.m\n//  macapp\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n\n"
  },
  {
    "path": "tests/plugins/pack/macapp/xmake.lua",
    "content": "set_version(\"1.0.0\")\nadd_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/xpack\")\n\ntarget(\"macapp\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n\nxpack(\"macapp\")\n    set_formats(\"dmg\")\n    set_title(\"MacApp Test\")\n    set_author(\"ruki <waruqi@gmail.com>\")\n    set_description(\"A test macOS application installer.\")\n    set_homepage(\"https://xmake.io\")\n    set_license(\"Apache-2.0\")\n    add_targets(\"macapp\")\n\n"
  },
  {
    "path": "tests/plugins/pack/qtapp/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n#include <QDebug>\n#include <zlib.h>\n\nint main(int argc, char *argv[]) {\n    QApplication a(argc, argv);\n    qDebug() << \"zlib version:\" << zlibVersion();\n    MainWindow w;\n    w.show();\n    return a.exec();\n}\n\n"
  },
  {
    "path": "tests/plugins/pack/qtapp/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nMainWindow::MainWindow(QWidget *parent)\n    : QMainWindow(parent)\n    , ui(new Ui::MainWindow) {\n    ui->setupUi(this);\n    setWindowTitle(\"Qt Widget App\");\n}\n\nMainWindow::~MainWindow() {\n    delete ui;\n}\n\n"
  },
  {
    "path": "tests/plugins/pack/qtapp/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = nullptr);\n    ~MainWindow();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n\n"
  },
  {
    "path": "tests/plugins/pack/qtapp/src/mainwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>640</width>\n    <height>480</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Qt Widget App</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n    <item>\n     <widget class=\"QLabel\" name=\"label\">\n      <property name=\"text\">\n       <string>Welcome to Qt Widget App!</string>\n      </property>\n      <property name=\"alignment\">\n       <set>Qt::AlignCenter</set>\n      </property>\n     </widget>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menuBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>640</width>\n     <height>22</height>\n    </rect>\n   </property>\n  </widget>\n  <widget class=\"QStatusBar\" name=\"statusBar\"/>\n </widget>\n <layoutdefault spacing=\"6\" margin=\"11\"/>\n <resources/>\n <connections/>\n</ui>\n\n"
  },
  {
    "path": "tests/plugins/pack/qtapp/xmake.lua",
    "content": "set_version(\"1.0.0\")\nadd_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/xpack\")\n\nadd_requires(\"zlib\", {configs = {shared = true}, system = false})\n\ntarget(\"qtapp\")\n    add_rules(\"qt.widgetapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    add_files(\"src/mainwindow.h\")\n    add_packages(\"zlib\")\n\nxpack(\"qtapp\")\n    set_formats(\"nsis\", \"dmg\", \"appimage\", \"zip\", \"targz\")\n    set_title(\"Qt Widget App\")\n    set_author(\"ruki <waruqi@gmail.com>\")\n    set_description(\"A Qt Widget Application example for xpack.\")\n    set_homepage(\"https://xmake.io\")\n    set_license(\"Apache-2.0\")\n    set_licensefile(\"LICENSE.md\")\n    add_targets(\"qtapp\")\n\n    on_load(function (package)\n        package:set(\"basename\", \"qtapp-$(plat)-$(arch)-v$(version)\")\n        -- set icon file based on format (use PNG for appimage, ICO for other formats)\n        local scriptdir = os.scriptdir()\n        if package:format() == \"appimage\" then\n            package:set(\"iconfile\", path.join(scriptdir, \"src/assets/xmake.png\"))\n        else\n            package:set(\"iconfile\", path.join(scriptdir, \"src/assets/xmake.ico\"))\n        end\n    end)\n\n"
  },
  {
    "path": "tests/plugins/project/test.lua",
    "content": "import(\"core.project.config\")\nimport(\"core.platform.platform\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\nfunction test_vsxmake(t)\n\n    if not is_subhost(\"windows\") then\n        return t:skip(\"wrong host platform\")\n    end\n\n    local projname = \"testproj\"\n    local tempdir = os.tmpfile()\n    os.mkdir(tempdir)\n    os.cd(tempdir)\n\n    -- create project\n    os.vrunv(\"xmake\", {\"create\", projname})\n    os.cd(projname)\n\n    -- set config\n    local arch = os.getenv(\"platform\") or \"x86\"\n    config.set(\"arch\", arch, {readonly = true, force = true})\n    platform.load(config.plat(), arch):check()\n\n    -- create sln & vcxproj\n    local vs = config.get(\"vs\")\n    local vstype = \"vsxmake\" .. vs\n    os.execv(\"xmake\", {\"project\", \"-k\", vstype, \"-a\", arch})\n    os.cd(vstype)\n\n    -- run msbuild\n    try\n    {\n        function ()\n            local runenvs = toolchain.load(\"msvc\"):runenvs()\n            local msbuild = find_tool(\"msbuild\", {envs = runenvs})\n            os.execv(msbuild.program, {\"/P:XmakeDiagnosis=true\", \"/P:XmakeVerbose=true\"}, {envs = runenvs})\n        end,\n        catch\n        {\n            function ()\n                print(\"--- sln file ---\")\n                io.cat(projname .. \".sln\")\n                print(\"--- vcx file ---\")\n                io.cat(projname .. \"/\" .. projname .. \".vcxproj\")\n                print(\"--- filter file ---\")\n                io.cat(projname .. \"/\" .. projname .. \".vcxproj.filters\")\n                raise(\"msbuild failed\")\n            end\n        }\n    }\n\n    -- clean up\n    os.cd(os.scriptdir())\n    os.tryrm(tempdir)\nend\n\nfunction test_compile_commands(t)\n    local projname = \"testproj\"\n    local tempdir = os.tmpfile()\n    os.mkdir(tempdir)\n    os.cd(tempdir)\n\n    -- create project\n    os.vrunv(\"xmake\", {\"create\", projname})\n    os.cd(projname)\n\n    -- generate compile_commands\n    os.vrunv(\"xmake\", {\"project\", \"-k\", \"compile_commands\"})\n\n    -- test autoupdate\n    io.insert(\"xmake.lua\", 1, 'add_rules(\"plugin.compile_commands.autoupdate\", {outputdir = \".vscode\", lsp = \"clangd\"})')\n    os.vrun(\"xmake\")\n\n    -- clean up\n    os.cd(os.scriptdir())\n    os.tryrm(tempdir)\nend\n\nfunction test_cmake(t)\n    local cmake = find_tool(\"cmake\")\n    if not cmake then\n        return t:skip(\"cmake not found\")\n    end\n    local projname = \"testproj\"\n    local tempdir = os.tmpfile()\n    os.mkdir(tempdir)\n    os.cd(tempdir)\n\n    -- create project\n    os.vrunv(\"xmake\", {\"create\", projname})\n    os.cd(projname)\n\n    -- generate compile_commands\n    os.vrunv(\"xmake\", {\"project\", \"-k\", \"cmake\"})\n\n    -- test build\n    os.mkdir(\"build\")\n    os.cd(\"build\")\n    os.vrunv(cmake.program, {\"..\"})\n    os.vrunv(cmake.program, {\"--build\", \".\"})\n\n    -- clean up\n    os.cd(os.scriptdir())\n    os.tryrm(tempdir)\nend\n"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.lvgl.basic\"\n\t\t  \n\tandroid:versionCode=\"15\"\n    android:versionName=\"1.5\">\n\t\n\t<uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"30\" />\n\t\n\t<uses-permission android:name=\"android.permission.SET_RELEASE_APP\"/>\n\n    <application \n        android:label=\"LvglBasic\" android:debuggable=\"true\" android:hasCode=\"false\"          \n        tools:replace=\"android:icon,android:theme,android:allowBackup,label\" \n        android:icon=\"@mipmap/icon\">\n\n        <activity android:name=\"android.app.NativeActivity\"\n                  android:label=\"LvglBasic\"\n                  android:configChanges=\"orientation|keyboardHidden|screenSize|screenLayout\"\n                  android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\">\n            <meta-data android:name=\"android.app.lib_name\"\n                       android:value=\"main\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Lvgl Basic</string>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:Theme.NoTitleBar.Fullscreen\">\n        <item name=\"android:windowBackground\">@android:color/black</item>\n        <item name=\"android:colorPrimary\">#FF6200EE</item>\n        <item name=\"android:colorPrimaryDark\">#FF3700B3</item>\n        <item name=\"android:colorAccent\">#FF03DAC5</item>\n    </style>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_basic/src/main.c",
    "content": "#include <lvgl/lvgl.h>\n#include <android/native_window.h>\n#include <android/log.h>\n#include <android_native_app_glue.h>\n#include <time.h>\n#include <stdlib.h>\n#include <unistd.h>\n\n#define LOG_TAG \"lvgl_basic\"\n#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\n\nstatic lv_display_t * display = NULL;\nstatic lv_indev_t * indev = NULL;\nstatic void * disp_buf = NULL;\nstatic ANativeWindow * native_window = NULL;\nstatic int32_t window_width = 0;\nstatic int32_t window_height = 0;\nstatic lv_obj_t * label_fps = NULL;\n\nstatic bool touch_down = false;\nstatic int32_t touch_x = 0;\nstatic int32_t touch_y = 0;\n\nstatic void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) {\n    if (!native_window) {\n        lv_display_flush_ready(disp);\n        return;\n    }\n\n    ANativeWindow_Buffer buffer;\n    if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) {\n        lv_display_flush_ready(disp);\n        return;\n    }\n\n    int32_t width = lv_area_get_width(area);\n    int32_t height = lv_area_get_height(area);\n\n    // Assume 32-bit RGBA\n    uint32_t * dst_base = (uint32_t *)buffer.bits;\n    uint32_t * src = (uint32_t *)px_map;\n    int stride = buffer.stride;\n\n    for (int y = 0; y < height; y++) {\n        uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1;\n        memcpy(dst_line, src + y * width, width * sizeof(uint32_t));\n    }\n\n    ANativeWindow_unlockAndPost(native_window);\n    lv_display_flush_ready(disp);\n}\n\nstatic void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) {\n    data->point.x = touch_x;\n    data->point.y = touch_y;\n    data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;\n}\n\nstatic void create_ui(void) {\n    lv_obj_t * label = lv_label_create(lv_screen_active());\n    lv_label_set_text(label, \"Hello Xmake + LVGL!\");\n    lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0);\n    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50);\n\n    // FPS label\n    label_fps = lv_label_create(lv_screen_active());\n    lv_label_set_text(label_fps, \"FPS: 0\");\n    lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0);\n    lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100);\n}\n\nstatic void handle_cmd(struct android_app* app, int32_t cmd) {\n    switch (cmd) {\n        case APP_CMD_INIT_WINDOW:\n            LOGI(\"Init Window\");\n            native_window = app->window;\n            window_width = ANativeWindow_getWidth(native_window);\n            window_height = ANativeWindow_getHeight(native_window);\n            ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888);\n\n            if (!display) {\n                display = lv_display_create(window_width, window_height);\n                lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888);\n                lv_display_set_flush_cb(display, my_flush_cb);\n\n                size_t buf_size = window_width * window_height * 4;\n                disp_buf = malloc(buf_size);\n                lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL);\n\n                indev = lv_indev_create();\n                lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);\n                lv_indev_set_read_cb(indev, my_input_read);\n\n                create_ui();\n            } else {\n                 lv_display_set_resolution(display, window_width, window_height);\n                 lv_obj_invalidate(lv_scr_act());\n            }\n            break;\n        case APP_CMD_TERM_WINDOW:\n            native_window = NULL;\n            break;\n        case APP_CMD_DESTROY:\n            if (display) {\n                lv_display_delete(display);\n                display = NULL;\n            }\n            if (indev) {\n                lv_indev_delete(indev);\n                indev = NULL;\n            }\n            if (disp_buf) {\n                free(disp_buf);\n                disp_buf = NULL;\n            }\n            break;\n    }\n}\n\nstatic int32_t handle_input(struct android_app* app, AInputEvent* event) {\n    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {\n        int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;\n        touch_x = AMotionEvent_getX(event, 0);\n        touch_y = AMotionEvent_getY(event, 0);\n        if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) {\n            touch_down = true;\n        } else {\n            touch_down = false;\n        }\n        return 1;\n    }\n    return 0;\n}\n\nvoid android_main(struct android_app* app) {\n    lv_init();\n\n    app->onAppCmd = handle_cmd;\n    app->onInputEvent = handle_input;\n\n    int frame_count = 0;\n    time_t last_time = time(NULL);\n\n    while (1) {\n        int ident;\n        int events;\n        struct android_poll_source* source;\n\n        uint32_t timeout = lv_timer_handler();\n        if (timeout > 50) timeout = 50;\n\n        while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) {\n            if (source != NULL) source->process(app, source);\n            if (app->destroyRequested != 0) return;\n        }\n\n        lv_tick_inc(timeout);\n\n        frame_count++;\n        time_t current_time = time(NULL);\n        if (current_time - last_time >= 1) {\n             if (label_fps) {\n                 lv_label_set_text_fmt(label_fps, \"FPS: %d\", frame_count);\n             }\n             frame_count = 0;\n             last_time = current_time;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_basic/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"lvgl 9.1.0\")\n\ntarget(\"lvgl_basic\")\n    set_kind(\"binary\")\n    set_languages(\"c99\")\n    add_files(\"src/main.c\")\n    add_syslinks(\"log\", \"android\", \"EGL\", \"GLESv2\")\n    add_packages(\"lvgl\")\n\n    -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h\n    add_defines(\"LV_CONF_INCLUDE_SIMPLE\")\n\n    add_rules(\"android.native_app\", {\n        android_sdk_version = \"35\",\n        android_manifest = \"android/AndroidManifest.xml\",\n        android_res = \"android/res\",\n        keystore = \"android/debug.jks\",\n        keystore_pass = \"123456\",\n        package_name = \"com.lvgl.basic\",\n        logcat_filters = {\"lvgl_basic\", \"lvgl\"}\n    })\n"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_particles/android/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.lvgl.particles\"\n\t\t  \n\tandroid:versionCode=\"15\"\n    android:versionName=\"1.5\">\n\t\n\t<uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"30\" />\n\t\n\t<uses-permission android:name=\"android.permission.SET_RELEASE_APP\"/>\n\n    <application \n        android:label=\"LvglParticles\" android:debuggable=\"true\" android:hasCode=\"false\"          \n        tools:replace=\"android:icon,android:theme,android:allowBackup,label\" \n        android:icon=\"@mipmap/icon\">\n\n        <activity android:name=\"android.app.NativeActivity\"\n                  android:label=\"LvglParticles\"\n                  android:configChanges=\"orientation|keyboardHidden|screenSize|screenLayout\"\n                  android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\">\n            <meta-data android:name=\"android.app.lib_name\"\n                       android:value=\"main\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_particles/android/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Lvgl Particles</string>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_particles/android/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:Theme.NoTitleBar.Fullscreen\">\n        <item name=\"android:windowBackground\">@android:color/black</item>\n        <item name=\"android:colorPrimary\">#FF6200EE</item>\n        <item name=\"android:colorPrimaryDark\">#FF3700B3</item>\n        <item name=\"android:colorAccent\">#FF03DAC5</item>\n    </style>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_particles/src/main.c",
    "content": "#include <lvgl/lvgl.h>\n#include <android/native_window.h>\n#include <android/log.h>\n#include <android_native_app_glue.h>\n#include <time.h>\n#include <stdlib.h>\n#include <unistd.h>\n\n#define LOG_TAG \"lvgl_particles\"\n#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\n\nstatic lv_display_t * display = NULL;\nstatic lv_indev_t * indev = NULL;\nstatic void * disp_buf = NULL;\nstatic ANativeWindow * native_window = NULL;\nstatic int32_t window_width = 0;\nstatic int32_t window_height = 0;\nstatic lv_obj_t * label_fps = NULL;\n\nstatic bool touch_down = false;\nstatic int32_t touch_x = 0;\nstatic int32_t touch_y = 0;\n\nstatic void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) {\n    if (!native_window) {\n        lv_display_flush_ready(disp);\n        return;\n    }\n\n    ANativeWindow_Buffer buffer;\n    if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) {\n        lv_display_flush_ready(disp);\n        return;\n    }\n\n    int32_t width = lv_area_get_width(area);\n    int32_t height = lv_area_get_height(area);\n\n    // Assume 32-bit RGBA\n    uint32_t * dst_base = (uint32_t *)buffer.bits;\n    uint32_t * src = (uint32_t *)px_map;\n    int stride = buffer.stride;\n\n    for (int y = 0; y < height; y++) {\n        uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1;\n        memcpy(dst_line, src + y * width, width * sizeof(uint32_t));\n    }\n\n    ANativeWindow_unlockAndPost(native_window);\n    lv_display_flush_ready(disp);\n}\n\nstatic void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) {\n    data->point.x = touch_x;\n    data->point.y = touch_y;\n    data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;\n}\n\n#include <math.h>\n\ntypedef struct {\n    int32_t x;\n    int32_t y;\n    int32_t vx;\n    int32_t vy;\n    lv_color_t color;\n    int32_t size;\n    int32_t life;\n} Particle;\n\n#define MAX_PARTICLES 100\nstatic Particle particles[MAX_PARTICLES];\nstatic int particle_count = 0;\n\nstatic void create_particle(int32_t x, int32_t y) {\n    if (particle_count < MAX_PARTICLES) {\n        Particle *p = &particles[particle_count++];\n        p->x = x;\n        p->y = y;\n        p->vx = (rand() % 10) - 5;\n        p->vy = (rand() % 10) - 5;\n        p->color = lv_color_make(rand() % 255, rand() % 255, rand() % 255);\n        p->size = (rand() % 15) + 5;\n        p->life = 100;\n    }\n}\n\nstatic void update_particles(void) {\n    for (int i = 0; i < particle_count; i++) {\n        Particle *p = &particles[i];\n        p->x += p->vx;\n        p->y += p->vy;\n        p->life--;\n\n        if (p->life <= 0 || p->x < 0 || p->x > window_width || p->y < 0 || p->y > window_height) {\n            *p = particles[--particle_count];\n            i--;\n        }\n    }\n}\n\nstatic void draw_particles(lv_layer_t * layer) {\n    lv_draw_rect_dsc_t draw_dsc;\n    lv_draw_rect_dsc_init(&draw_dsc);\n    draw_dsc.radius = LV_RADIUS_CIRCLE;\n\n    for (int i = 0; i < particle_count; i++) {\n        Particle *p = &particles[i];\n        draw_dsc.bg_color = p->color;\n        draw_dsc.bg_opa = (p->life * 255) / 100;\n\n        lv_area_t area;\n        area.x1 = p->x - p->size / 2;\n        area.y1 = p->y - p->size / 2;\n        area.x2 = area.x1 + p->size;\n        area.y2 = area.y1 + p->size;\n\n        lv_draw_rect(layer, &draw_dsc, &area);\n    }\n}\n\nstatic void particle_timer_cb(lv_timer_t * timer) {\n    if (touch_down) {\n        for (int i = 0; i < 5; i++) {\n             create_particle(touch_x, touch_y);\n        }\n    } else {\n         // Auto emit\n         static float t = 0;\n         t += 0.1f;\n         int cx = window_width / 2 + cos(t) * (window_width / 4);\n         int cy = window_height / 2 + sin(t) * (window_height / 4);\n         create_particle(cx, cy);\n    }\n\n    update_particles();\n    lv_obj_invalidate(lv_scr_act()); // Force redraw\n}\n\nstatic void canvas_draw_event_cb(lv_event_t * e) {\n    lv_layer_t * layer = lv_event_get_layer(e);\n    draw_particles(layer);\n}\n\nstatic void create_ui(void) {\n    lv_obj_t * label = lv_label_create(lv_screen_active());\n    lv_label_set_text(label, \"Touch to create particles!\");\n    lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0);\n    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50);\n\n    // FPS label\n    label_fps = lv_label_create(lv_screen_active());\n    lv_label_set_text(label_fps, \"FPS: 0\");\n    lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0);\n    lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100);\n\n    // Add draw event to screen for particles\n    lv_obj_add_event_cb(lv_screen_active(), canvas_draw_event_cb, LV_EVENT_DRAW_POST, NULL);\n\n    lv_timer_create(particle_timer_cb, 16, NULL);\n}\n\nstatic void handle_cmd(struct android_app* app, int32_t cmd) {\n    switch (cmd) {\n        case APP_CMD_INIT_WINDOW:\n            LOGI(\"Init Window\");\n            native_window = app->window;\n            window_width = ANativeWindow_getWidth(native_window);\n            window_height = ANativeWindow_getHeight(native_window);\n            ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888);\n\n            if (!display) {\n                display = lv_display_create(window_width, window_height);\n                lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888);\n                lv_display_set_flush_cb(display, my_flush_cb);\n\n                size_t buf_size = window_width * window_height * 4;\n                disp_buf = malloc(buf_size);\n                lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL);\n\n                indev = lv_indev_create();\n                lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);\n                lv_indev_set_read_cb(indev, my_input_read);\n\n                create_ui();\n            } else {\n                 lv_display_set_resolution(display, window_width, window_height);\n                 lv_obj_invalidate(lv_scr_act());\n            }\n            break;\n        case APP_CMD_TERM_WINDOW:\n            native_window = NULL;\n            break;\n        case APP_CMD_DESTROY:\n            if (display) {\n                lv_display_delete(display);\n                display = NULL;\n            }\n            if (indev) {\n                lv_indev_delete(indev);\n                indev = NULL;\n            }\n            if (disp_buf) {\n                free(disp_buf);\n                disp_buf = NULL;\n            }\n            break;\n    }\n}\n\nstatic int32_t handle_input(struct android_app* app, AInputEvent* event) {\n    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {\n        int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;\n        touch_x = AMotionEvent_getX(event, 0);\n        touch_y = AMotionEvent_getY(event, 0);\n        if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) {\n            touch_down = true;\n        } else {\n            touch_down = false;\n        }\n        return 1;\n    }\n    return 0;\n}\n\nvoid android_main(struct android_app* app) {\n    srand(time(NULL));\n    lv_init();\n\n    app->onAppCmd = handle_cmd;\n    app->onInputEvent = handle_input;\n\n    int frame_count = 0;\n    time_t last_time = time(NULL);\n\n    while (1) {\n        int ident;\n        int events;\n        struct android_poll_source* source;\n\n        uint32_t timeout = lv_timer_handler();\n        if (timeout > 50) timeout = 50;\n\n        while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) {\n            if (source != NULL) source->process(app, source);\n            if (app->destroyRequested != 0) return;\n        }\n\n        lv_tick_inc(timeout);\n\n        frame_count++;\n        time_t current_time = time(NULL);\n        if (current_time - last_time >= 1) {\n            if (label_fps) {\n                lv_label_set_text_fmt(label_fps, \"FPS: %d\", frame_count);\n            }\n            frame_count = 0;\n            last_time = current_time;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/lvgl_particles/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"lvgl 9.1.0\")\n\ntarget(\"lvgl_particles\")\n    set_kind(\"binary\")\n    set_languages(\"c99\")\n    add_files(\"src/main.c\")\n    add_syslinks(\"log\", \"android\", \"EGL\", \"GLESv2\")\n    add_packages(\"lvgl\")\n    \n    -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h\n    add_defines(\"LV_CONF_INCLUDE_SIMPLE\")\n    \n    add_rules(\"android.native_app\", {\n        android_sdk_version = \"35\",\n        android_manifest = \"android/AndroidManifest.xml\",\n        android_res = \"android/res\",\n        keystore = \"android/debug.jks\",\n        keystore_pass = \"123456\",\n        package_name = \"com.lvgl.particles\",\n        logcat_filters = {\"lvgl_particles\", \"lvgl\"}\n    })\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_basic/android/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.raylib.basic\"\n\t\t  \n\tandroid:versionCode=\"15\"\n    android:versionName=\"1.5\">\n\t\n\t<uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"30\" />\n\t\n\t<uses-permission android:name=\"android.permission.SET_RELEASE_APP\"/>\n\n    <application \n        android:label=\"RaylibBasic\" android:debuggable=\"true\" android:hasCode=\"false\"          \n        tools:replace=\"android:icon,android:theme,android:allowBackup,label\" \n        android:icon=\"@mipmap/icon\">\n\n        <activity android:name=\"android.app.NativeActivity\"\n                  android:label=\"RaylibBasic\"\n                  android:configChanges=\"orientation|keyboardHidden|screenSize|screenLayout\"\n                  android:screenOrientation=\"portrait\"\n                  android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\">\n            <meta-data android:name=\"android.app.lib_name\"\n                       android:value=\"main\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_basic/android/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Raylib Basic</string>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_basic/android/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:Theme.NoTitleBar.Fullscreen\">\n        <item name=\"android:windowBackground\">@android:color/black</item>\n        <item name=\"android:colorPrimary\">#FF6200EE</item>\n        <item name=\"android:colorPrimaryDark\">#FF3700B3</item>\n        <item name=\"android:colorAccent\">#FF03DAC5</item>\n    </style>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_basic/src/main.cpp",
    "content": "#include <raylib.h>\n#include <android/log.h>\n\n#define LOG_TAG \"raydemo_basic\"\n#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\n\nint main(int argc, char** argv) {\n    InitWindow(0, 0, \"Hello, xmake for raylib android!\");\n    SetTargetFPS(60);\n    LOGI(\"raylib application is running!\");\n\n    while (!WindowShouldClose()) {\n        BeginDrawing();\n        ClearBackground(BLACK);\n\n        // Draw FPS\n        const char* fpsText = TextFormat(\"%2i FPS\", GetFPS());\n        int fpsWidth = MeasureText(fpsText, 40);\n        DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN);\n\n        // Draw centered text\n        int fontSize = 50;\n        const char* text = \"Hello, xmake for raylib android!\";\n        int textWidth = MeasureText(text, fontSize);\n        DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 100, fontSize, BLUE);\n\n        EndDrawing();\n    }\n\n    CloseWindow();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_basic/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"raylib 5.5.0\")\n\ntarget(\"raydemo_basic\")\n    set_kind(\"binary\")\n    set_languages(\"c++17\")\n    add_files(\"src/main.cpp\")\n    add_syslinks(\"log\")\n    add_packages(\"raylib\")\n    add_rules(\"android.native_app\", {\n        android_sdk_version = \"35\",\n        android_manifest = \"android/AndroidManifest.xml\",\n        android_res = \"android/res\",\n        keystore = \"android/debug.jks\",\n        keystore_pass = \"123456\",\n        package_name = \"com.raylib.basic\",\n        logcat_filters = {\"raydemo_basic\", \"raylib\"}\n    })\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/android/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.raylib.custom_glue\"\n\t\t  \n\tandroid:versionCode=\"15\"\n    android:versionName=\"1.5\">\n\t\n\t<uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"30\" />\n\t\n\t<uses-permission android:name=\"android.permission.SET_RELEASE_APP\"/>\n\n    <application \n        android:label=\"RaylibCustomGlue\" android:debuggable=\"true\" android:hasCode=\"false\"          \n        tools:replace=\"android:icon,android:theme,android:allowBackup,label\" \n        android:icon=\"@mipmap/icon\">\n\n        <activity android:name=\"android.app.NativeActivity\"\n                  android:label=\"RaylibCustomGlue\"\n                  android:configChanges=\"orientation|keyboardHidden|screenSize|screenLayout\"\n                  android:screenOrientation=\"portrait\"\n                  android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\">\n            <meta-data android:name=\"android.app.lib_name\"\n                       android:value=\"raydemo_custom_glue\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/android/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Raylib Basic</string>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/android/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:Theme.NoTitleBar.Fullscreen\">\n        <item name=\"android:windowBackground\">@android:color/black</item>\n        <item name=\"android:colorPrimary\">#FF6200EE</item>\n        <item name=\"android:colorPrimaryDark\">#FF3700B3</item>\n        <item name=\"android:colorAccent\">#FF03DAC5</item>\n    </style>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/src/android_native_app_glue.c",
    "content": "#include <jni.h>\n#include <errno.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/resource.h>\n#include <android/log.h>\n#include <stdlib.h>\n#include \"android_native_app_glue.h\"\n\n#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, \"raydemo_custom_glue\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"raydemo_custom_glue\", __VA_ARGS__))\n#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, \"raydemo_custom_glue\", __VA_ARGS__))\n#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, \"raydemo_custom_glue\", __VA_ARGS__))\n\nstatic void free_saved_state(struct android_app* android_app) {\n    pthread_mutex_lock(&android_app->mutex);\n    if (android_app->savedState != NULL) {\n        free(android_app->savedState);\n        android_app->savedState = NULL;\n        android_app->savedStateSize = 0;\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n}\n\nint8_t android_app_read_cmd(struct android_app* android_app) {\n    int8_t cmd;\n    if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {\n        switch (cmd) {\n            case APP_CMD_SAVE_STATE:\n                free_saved_state(android_app);\n                break;\n        }\n        return cmd;\n    } else {\n        LOGE(\"No data on command pipe!\");\n    }\n    return -1;\n}\n\nstatic void print_cur_config(struct android_app* android_app) {\n    char lang[2], country[2];\n    AConfiguration_getLanguage(android_app->config, lang);\n    AConfiguration_getCountry(android_app->config, country);\n    \n    LOGV(\"Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d \"\n            \"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d \"\n            \"modetype=%d modenight=%d\",\n            AConfiguration_getMcc(android_app->config),\n            AConfiguration_getMnc(android_app->config),\n            lang[0], lang[1], country[0], country[1],\n            AConfiguration_getOrientation(android_app->config),\n            AConfiguration_getTouchscreen(android_app->config),\n            AConfiguration_getDensity(android_app->config),\n            AConfiguration_getKeyboard(android_app->config),\n            AConfiguration_getNavigation(android_app->config),\n            AConfiguration_getKeysHidden(android_app->config),\n            AConfiguration_getNavHidden(android_app->config),\n            AConfiguration_getSdkVersion(android_app->config),\n            AConfiguration_getScreenSize(android_app->config),\n            AConfiguration_getScreenLong(android_app->config),\n            AConfiguration_getUiModeType(android_app->config),\n            AConfiguration_getUiModeNight(android_app->config));\n}\n\nvoid android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {\n    switch (cmd) {\n        case APP_CMD_INPUT_CHANGED:\n            LOGV(\"APP_CMD_INPUT_CHANGED\\n\");\n            pthread_mutex_lock(&android_app->mutex);\n            if (android_app->inputQueue != NULL) {\n                AInputQueue_detachLooper(android_app->inputQueue);\n            }\n            android_app->inputQueue = android_app->pendingInputQueue;\n            if (android_app->inputQueue != NULL) {\n                LOGV(\"Attaching input queue to looper\");\n                AInputQueue_attachLooper(android_app->inputQueue,\n                        android_app->looper, LOOPER_ID_EVENT, NULL,\n                        &android_app->inputPollSource);\n            }\n            pthread_cond_broadcast(&android_app->cond);\n            pthread_mutex_unlock(&android_app->mutex);\n            break;\n\n        case APP_CMD_INIT_WINDOW:\n            LOGV(\"APP_CMD_INIT_WINDOW\\n\");\n            pthread_mutex_lock(&android_app->mutex);\n            android_app->window = android_app->pendingWindow;\n            pthread_cond_broadcast(&android_app->cond);\n            pthread_mutex_unlock(&android_app->mutex);\n            break;\n\n        case APP_CMD_TERM_WINDOW:\n            LOGV(\"APP_CMD_TERM_WINDOW\\n\");\n            pthread_cond_broadcast(&android_app->cond);\n            break;\n\n        case APP_CMD_RESUME:\n        case APP_CMD_START:\n        case APP_CMD_PAUSE:\n        case APP_CMD_STOP:\n            LOGV(\"activityState=%d\\n\", cmd);\n            pthread_mutex_lock(&android_app->mutex);\n            android_app->activityState = cmd;\n            pthread_cond_broadcast(&android_app->cond);\n            pthread_mutex_unlock(&android_app->mutex);\n            break;\n\n        case APP_CMD_CONFIG_CHANGED:\n            LOGV(\"APP_CMD_CONFIG_CHANGED\\n\");\n            AConfiguration_fromAssetManager(android_app->config,\n                    android_app->activity->assetManager);\n            print_cur_config(android_app);\n            break;\n\n        case APP_CMD_DESTROY:\n            LOGV(\"APP_CMD_DESTROY\\n\");\n            android_app->destroyRequested = 1;\n            break;\n    }\n}\n\nvoid android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {\n    switch (cmd) {\n        case APP_CMD_TERM_WINDOW:\n            LOGV(\"APP_CMD_TERM_WINDOW\\n\");\n            pthread_mutex_lock(&android_app->mutex);\n            android_app->window = NULL;\n            pthread_cond_broadcast(&android_app->cond);\n            pthread_mutex_unlock(&android_app->mutex);\n            break;\n\n        case APP_CMD_SAVE_STATE:\n            LOGV(\"APP_CMD_SAVE_STATE\\n\");\n            pthread_mutex_lock(&android_app->mutex);\n            android_app->stateSaved = 1;\n            pthread_cond_broadcast(&android_app->cond);\n            pthread_mutex_unlock(&android_app->mutex);\n            break;\n\n        case APP_CMD_RESUME:\n            free_saved_state(android_app);\n            break;\n    }\n}\n\nvoid app_dummy() {\n\n}\n\nstatic void android_app_destroy(struct android_app* android_app) {\n    LOGV(\"android_app_destroy!\");\n    free_saved_state(android_app);\n    pthread_mutex_lock(&android_app->mutex);\n    if (android_app->inputQueue != NULL) {\n        AInputQueue_detachLooper(android_app->inputQueue);\n    }\n    AConfiguration_delete(android_app->config);\n    android_app->destroyed = 1;\n    pthread_cond_broadcast(&android_app->cond);\n    pthread_mutex_unlock(&android_app->mutex);\n    // Can't touch android_app object after this.\n}\n\nstatic void process_input(struct android_app* app, struct android_poll_source* source) {\n    AInputEvent* event = NULL;\n    while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {\n        LOGV(\"New input event: type=%d\\n\", AInputEvent_getType(event));\n        if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {\n            continue;\n        }\n        int32_t handled = 0;\n        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);\n        AInputQueue_finishEvent(app->inputQueue, event, handled);\n    }\n}\n\nstatic void process_cmd(struct android_app* app, struct android_poll_source* source) {\n    int8_t cmd = android_app_read_cmd(app);\n    android_app_pre_exec_cmd(app, cmd);\n    if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);\n    android_app_post_exec_cmd(app, cmd);\n}\n\nstatic void* android_app_entry(void* param) {\n    struct android_app* android_app = (struct android_app*)param;\n\n    android_app->config = AConfiguration_new();\n    AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);\n\n    print_cur_config(android_app);\n\n    android_app->cmdPollSource.id = LOOPER_ID_MAIN;\n    android_app->cmdPollSource.app = android_app;\n    android_app->cmdPollSource.process = process_cmd;\n    android_app->inputPollSource.id = LOOPER_ID_EVENT;\n    android_app->inputPollSource.app = android_app;\n    android_app->inputPollSource.process = process_input;\n\n    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);\n    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,\n            &android_app->cmdPollSource);\n    android_app->looper = looper;\n\n    pthread_mutex_lock(&android_app->mutex);\n    android_app->running = 1;\n    pthread_cond_broadcast(&android_app->cond);\n    pthread_mutex_unlock(&android_app->mutex);\n\n    android_main(android_app);\n\n    android_app_destroy(android_app);\n    return NULL;\n}\n\n// --------------------------------------------------------------------\n// Native activity interaction (called from main thread)\n// --------------------------------------------------------------------\n\nstatic struct android_app* android_app_create(ANativeActivity* activity,\n        void* savedState, size_t savedStateSize) {\n    struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));\n    memset(android_app, 0, sizeof(struct android_app));\n    android_app->activity = activity;\n\n    pthread_mutex_init(&android_app->mutex, NULL);\n    pthread_cond_init(&android_app->cond, NULL);\n\n    if (savedState != NULL) {\n        android_app->savedState = malloc(savedStateSize);\n        android_app->savedStateSize = savedStateSize;\n        memcpy(android_app->savedState, savedState, savedStateSize);\n    }\n\n    int msgpipe[2];\n    if (pipe(msgpipe)) {\n        LOGE(\"could not create pipe: %s\", strerror(errno));\n        return NULL;\n    }\n    android_app->msgread = msgpipe[0];\n    android_app->msgwrite = msgpipe[1];\n\n    pthread_attr_t attr; \n    pthread_attr_init(&attr);\n    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\n    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);\n\n    // Wait for thread to start.\n    pthread_mutex_lock(&android_app->mutex);\n    while (!android_app->running) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n\n    return android_app;\n}\n\nstatic void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {\n    if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {\n        LOGE(\"Failure writing android_app cmd: %s\\n\", strerror(errno));\n    }\n}\n\nstatic void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {\n    pthread_mutex_lock(&android_app->mutex);\n    android_app->pendingInputQueue = inputQueue;\n    android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);\n    while (android_app->inputQueue != android_app->pendingInputQueue) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n}\n\nstatic void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {\n    pthread_mutex_lock(&android_app->mutex);\n    if (android_app->pendingWindow != NULL) {\n        android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);\n    }\n    android_app->pendingWindow = window;\n    if (window != NULL) {\n        android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);\n    }\n    while (android_app->window != android_app->pendingWindow) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n}\n\nstatic void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {\n    pthread_mutex_lock(&android_app->mutex);\n    android_app_write_cmd(android_app, cmd);\n    while (android_app->activityState != cmd) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n}\n\nstatic void android_app_free(struct android_app* android_app) {\n    pthread_mutex_lock(&android_app->mutex);\n    android_app_write_cmd(android_app, APP_CMD_DESTROY);\n    while (!android_app->destroyed) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n    pthread_mutex_unlock(&android_app->mutex);\n\n    close(android_app->msgread);\n    close(android_app->msgwrite);\n    pthread_cond_destroy(&android_app->cond);\n    pthread_mutex_destroy(&android_app->mutex);\n    free(android_app);\n}\n\nstatic void onDestroy(ANativeActivity* activity) {\n    LOGV(\"Destroy: %p\\n\", activity);\n    android_app_free((struct android_app*)activity->instance);\n}\n\nstatic void onStart(ANativeActivity* activity) {\n    LOGV(\"Start: %p\\n\", activity);\n    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);\n}\n\nstatic void onResume(ANativeActivity* activity) {\n    LOGV(\"Resume: %p\\n\", activity);\n    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);\n}\n\nstatic void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {\n    struct android_app* android_app = (struct android_app*)activity->instance;\n    void* savedState = NULL;\n\n    LOGV(\"SaveInstanceState: %p\\n\", activity);\n    pthread_mutex_lock(&android_app->mutex);\n    android_app->stateSaved = 0;\n    android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);\n    while (!android_app->stateSaved) {\n        pthread_cond_wait(&android_app->cond, &android_app->mutex);\n    }\n\n    if (android_app->savedState != NULL) {\n        savedState = android_app->savedState;\n        *outLen = android_app->savedStateSize;\n        android_app->savedState = NULL;\n        android_app->savedStateSize = 0;\n    }\n\n    pthread_mutex_unlock(&android_app->mutex);\n\n    return savedState;\n}\n\nstatic void onPause(ANativeActivity* activity) {\n    LOGV(\"Pause: %p\\n\", activity);\n    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);\n}\n\nstatic void onStop(ANativeActivity* activity) {\n    LOGV(\"Stop: %p\\n\", activity);\n    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);\n}\n\nstatic void onConfigurationChanged(ANativeActivity* activity) {\n    struct android_app* android_app = (struct android_app*)activity->instance;\n    LOGV(\"ConfigurationChanged: %p\\n\", activity);\n    android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);\n}\n\nstatic void onLowMemory(ANativeActivity* activity) {\n    struct android_app* android_app = (struct android_app*)activity->instance;\n    LOGV(\"LowMemory: %p\\n\", activity);\n    android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);\n}\n\nstatic void onWindowFocusChanged(ANativeActivity* activity, int focused) {\n    LOGV(\"WindowFocusChanged: %p -- %d\\n\", activity, focused);\n    android_app_write_cmd((struct android_app*)activity->instance,\n            focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);\n}\n\nstatic void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {\n    LOGV(\"NativeWindowCreated: %p -- %p\\n\", activity, window);\n    android_app_set_window((struct android_app*)activity->instance, window);\n}\n\nstatic void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {\n    LOGV(\"NativeWindowDestroyed: %p -- %p\\n\", activity, window);\n    android_app_set_window((struct android_app*)activity->instance, NULL);\n}\n\nstatic void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {\n    LOGV(\"InputQueueCreated: %p -- %p\\n\", activity, queue);\n    android_app_set_input((struct android_app*)activity->instance, queue);\n}\n\nstatic void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {\n    LOGV(\"InputQueueDestroyed: %p -- %p\\n\", activity, queue);\n    android_app_set_input((struct android_app*)activity->instance, NULL);\n}\n\nvoid ANativeActivity_onCreate(ANativeActivity* activity,\n        void* savedState, size_t savedStateSize) {\n    LOGV(\"Creating: %p\\n\", activity);\n    activity->callbacks->onDestroy = onDestroy;\n    activity->callbacks->onStart = onStart;\n    activity->callbacks->onResume = onResume;\n    activity->callbacks->onSaveInstanceState = onSaveInstanceState;\n    activity->callbacks->onPause = onPause;\n    activity->callbacks->onStop = onStop;\n    activity->callbacks->onConfigurationChanged = onConfigurationChanged;\n    activity->callbacks->onLowMemory = onLowMemory;\n    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;\n    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;\n    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;\n    activity->callbacks->onInputQueueCreated = onInputQueueCreated;\n    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;\n\n    activity->instance = android_app_create(activity, savedState, savedStateSize);\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/src/android_native_app_glue.h",
    "content": "#ifndef _ANDROID_NATIVE_APP_GLUE_H\n#define _ANDROID_NATIVE_APP_GLUE_H\n\n#include <poll.h>\n#include <pthread.h>\n#include <sched.h>\n\n#include <android/native_activity.h>\n#include <android/looper.h>\n#include <android/configuration.h>\n#include <android/rect.h>\n#include <android/native_window.h>\n#include <android/input.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * The native activity interface provided by <android/native_activity.h>\n * is based on a set of application-provided callbacks that will be called\n * by the Activity's main thread when certain events occur.\n *\n * This means that each one of this callbacks _should_ _not_ block, or they\n * risk having the system force-close the application. This programming\n * model is direct, lightweight, but constraining.\n *\n * The 'threaded_native_app' static library is used to provide a different\n * execution model where the application can implement its own main event\n * loop in a different thread instead. Here's how it works:\n *\n * 1/ The application must provide a function named \"android_main()\" that\n *    will be called when the activity is created, in a new thread that is\n *    distinct from the activity's main thread.\n *\n * 2/ android_main() receives a pointer to a valid \"android_app\" structure\n *    that contains references to other important objects, e.g. the\n *    ANativeActivity obejct instance the application is running in.\n *\n * 3/ the \"android_app\" object holds an ALooper instance that already\n *    listens to two important things:\n *\n *      - activity lifecycle events (e.g. \"pause\", \"resume\"). See APP_CMD_XXX\n *        declarations below.\n *\n *      - input events coming from the AInputQueue attached to the activity.\n *\n *    Each of these correspond to an ALooper callback that returns a \"data\"\n *    value of LOOPER_ID_MAIN and LOOPER_ID_EVENT, respectively.\n *\n *    Your application can use the same ALooper to listen to additionnal\n *    file-descriptors.\n *\n * 4/ Whenever you receive a LOOPER_ID_MAIN event from the ALooper, your\n *    code should call the function android_app_read_cmd() to read the\n *    command value and act upon it. This is normally done by calling\n *    android_app_exec_cmd() directly.\n *\n *    XXX: MAKE THIS STUFF MORE CLEAR !!\n *\n * 5/ Whenever you receive a LOOPER_ID_EVENT event from the ALooper, you\n *    should read one event from the AInputQueue with AInputQueue_getEvent().\n *\n * See the sample named \"native-activity\" that comes with the NDK with a\n * full usage example.\n *\n */\n\n/**\n * Data associated with an ALooper fd that will be returned as the \"outData\"\n * when that source has data ready.\n */\nstruct android_poll_source {\n    // The identifier of this source.  May be LOOPER_ID_MAIN or\n    // LOOPER_ID_EVENT.\n    int32_t id;\n\n    // The android_app structure associated with this source.\n    struct android_app* app;\n\n    // Function to call to process this source when data is available.\n    void (*process)(struct android_app* app, struct android_poll_source* source);\n};\n\nstruct android_app {\n    // The application can place a pointer to its own state object\n    // here if it likes.\n    void* userData;\n\n    // Fill this in with the function to process main app commands (APP_CMD_*)\n    void (*onAppCmd)(struct android_app* app, int32_t cmd);\n\n    // Fill this in with the function to process input events.  At this point\n    // the event has already been pre-dispatched, and it will be finished upon\n    // return.  Return 1 if you have handled the event, 0 for any default\n    // dispatching.\n    int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);\n\n    // The ANativeActivity object instance that this app is running in.\n    ANativeActivity* activity;\n\n    // The current configuration the app is running in.\n    AConfiguration* config;\n\n    // The last saved state that was given at creation time.\n    void* savedState;\n    size_t savedStateSize;\n\n    // The ALooper associated with the app's thread.\n    ALooper* looper;\n\n    // When non-NULL, this is the input queue from which the app will\n    // receive user input events.\n    AInputQueue* inputQueue;\n\n    // When non-NULL, this is the window surface that the app can draw in.\n    ANativeWindow* window;\n\n    // Current content rectangle of the window; this is the area where the\n    // window's content should be placed to be seen by the user.\n    ARect contentRect;\n\n    // Current state of the app's activity.  May be either APP_CMD_START,\n    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.\n    int activityState;\n\n    // This is non-zero when the application's NativeActivity is being\n    // destroyed and waiting for the app thread to complete.\n    int destroyRequested;\n\n    // -------------------------------------------------\n    // Below are \"private\" implementation of the glue code.\n\n    pthread_mutex_t mutex;\n    pthread_cond_t cond;\n\n    int msgread;\n    int msgwrite;\n\n    pthread_t thread;\n\n    struct android_poll_source cmdPollSource;\n    struct android_poll_source inputPollSource;\n\n    int running;\n    int stateSaved;\n    int destroyed;\n    int redrawNeeded;\n    AInputQueue* pendingInputQueue;\n    ANativeWindow* pendingWindow;\n    ARect pendingContentRect;\n};\n\nenum {\n    /**\n     * Looper data ID of commands coming from the app's main thread.\n     * These can be retrieved and processed with android_app_read_cmd()\n     * and android_app_exec_cmd().\n     */\n    LOOPER_ID_MAIN = 1,\n\n    /**\n     * Looper data ID of events coming from the AInputQueue of the\n     * application's window.  These can be read via the inputQueue\n     * object of android_app.\n     */\n    LOOPER_ID_EVENT = 2,\n\n    /**\n     * Looper data ID of events coming from the AInputQueue of the\n     * application's window.  These can be read via the inputQueue\n     * object of android_app.\n     */\n    LOOPER_ID_USER = 3,\n};\n\nenum {\n    APP_CMD_INPUT_CHANGED,\n    APP_CMD_INIT_WINDOW,\n    APP_CMD_TERM_WINDOW,\n    APP_CMD_WINDOW_RESIZED,\n    APP_CMD_WINDOW_REDRAW_NEEDED,\n    APP_CMD_CONTENT_RECT_CHANGED,\n    APP_CMD_GAINED_FOCUS,\n    APP_CMD_LOST_FOCUS,\n    APP_CMD_CONFIG_CHANGED,\n    APP_CMD_LOW_MEMORY,\n    APP_CMD_START,\n    APP_CMD_RESUME,\n    APP_CMD_SAVE_STATE,\n    APP_CMD_PAUSE,\n    APP_CMD_STOP,\n    APP_CMD_DESTROY,\n};\n\n/**\n * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next\n * app command message.\n */\nint8_t android_app_read_cmd(struct android_app* android_app);\n\n/**\n * Call with the command returned by android_app_read_cmd() to do the\n * initial pre-processing of the given command.  You can use this for\n * your own normal default behavior for the command, and then inspect\n * it yourself to do your own processing.  This function may block for\n * certain commands (e.g. to wait for the app's graphics context to be\n * initialized) and will returns true if it blocked.\n */\nvoid android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);\n\n/**\n * Call with the command returned by android_app_read_cmd() to do the\n * final post-processing of the given command.  You must have first called\n * android_app_pre_exec_cmd() before calling this function.\n */\nvoid android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);\n\n/**\n * Dummy function you can call to ensure glue code isn't stripped.\n */\nvoid app_dummy();\n\n/**\n * This is the function that application code must implement, representing\n * the main entry to the app.\n */\nextern void android_main(struct android_app* app);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _ANDROID_NATIVE_APP_GLUE_H */\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/src/main.cpp",
    "content": "#include <raylib.h>\n#include <android/log.h>\n\n#define LOG_TAG \"raydemo_custom_glue\"\n#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\n\nint main(int argc, char** argv) {\n    InitWindow(0, 0, \"Hello, xmake for raylib android!\");\n    SetTargetFPS(60);\n    LOGI(\"raylib application is running!\");\n\n    while (!WindowShouldClose()) {\n        BeginDrawing();\n        ClearBackground(BLACK);\n\n        // Draw FPS\n        const char* fpsText = TextFormat(\"%2i FPS\", GetFPS());\n        int fpsWidth = MeasureText(fpsText, 40);\n        DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN);\n\n        // Draw centered text\n        int fontSize = 50;\n        const char* text = \"Hello, xmake for raylib android!\";\n        int textWidth = MeasureText(text, fontSize);\n        DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 100, fontSize, BLUE);\n\n        EndDrawing();\n    }\n\n    CloseWindow();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_custom_glue/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"raylib 5.5.0\")\n\ntarget(\"raydemo_custom_glue\")\n    set_kind(\"binary\")\n    set_languages(\"c++17\")\n    add_files(\"src/main.cpp\", \"src/android_native_app_glue.c\")\n    add_syslinks(\"log\")\n    add_packages(\"raylib\")\n    add_rules(\"android.native_app\", {\n        android_sdk_version = \"35\",\n        android_manifest = \"android/AndroidManifest.xml\",\n        android_res = \"android/res\",\n        keystore = \"android/debug.jks\",\n        keystore_pass = \"123456\",\n        package_name = \"com.raylib.custom_glue\",\n        native_app_glue = false,\n        logcat_filters = {\"raydemo_custom_glue\", \"raylib\"}\n    })\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_particles/android/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.raylib.particles\"\n\t\t  \n\tandroid:versionCode=\"15\"\n    android:versionName=\"1.5\">\n\t\n\t<uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"30\" />\n\t\n\t<uses-permission android:name=\"android.permission.SET_RELEASE_APP\"/>\n\n    <application \n        android:label=\"RaylibParticles\" android:debuggable=\"true\" android:hasCode=\"false\"          \n        tools:replace=\"android:icon,android:theme,android:allowBackup,label\" \n        android:icon=\"@mipmap/icon\">\n\n        <activity android:name=\"android.app.NativeActivity\"\n                  android:label=\"RaylibParticles\"\n                  android:configChanges=\"orientation|keyboardHidden|screenSize|screenLayout\"\n                  android:screenOrientation=\"portrait\"\n                  android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\">\n            <meta-data android:name=\"android.app.lib_name\"\n                       android:value=\"main\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_particles/android/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Raylib Particles</string>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_particles/android/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"AppTheme\" parent=\"android:Theme.NoTitleBar.Fullscreen\">\n        <item name=\"android:windowBackground\">@android:color/black</item>\n        <item name=\"android:colorPrimary\">#FF6200EE</item>\n        <item name=\"android:colorPrimaryDark\">#FF3700B3</item>\n        <item name=\"android:colorAccent\">#FF03DAC5</item>\n    </style>\n</resources>"
  },
  {
    "path": "tests/projects/android/native_app/raylib_particles/src/main.cpp",
    "content": "#include <raylib.h>\n#include <android/log.h>\n#include <vector>\n#include <cmath>\n\n#define LOG_TAG \"raydemo_particles\"\n#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\n\nstruct Particle {\n    Vector2 position;\n    Vector2 velocity;\n    Color color;\n    float size;\n    float life;\n};\n\nint main(int argc, char** argv) {\n    InitWindow(0, 0, \"Raylib Particles\");\n    SetTargetFPS(60);\n    LOGD(\"raylib particles starting!\");\n\n    std::vector<Particle> particles;\n\n    while (!WindowShouldClose()) {\n        // Update\n        bool inputActive = IsMouseButtonDown(MOUSE_BUTTON_LEFT) || GetTouchPointCount() > 0;\n        Vector2 pos;\n\n        if (inputActive) {\n            pos = GetMousePosition();\n            if (GetTouchPointCount() > 0) pos = GetTouchPosition(0);\n        } else {\n            // Auto emit when idle\n            double time = GetTime();\n            pos.x = GetScreenWidth() / 2.0f + cos(time * 3.0f) * (GetScreenWidth() / 4.0f);\n            pos.y = GetScreenHeight() / 2.0f + sin(time * 2.0f) * (GetScreenHeight() / 4.0f);\n        }\n\n        if (inputActive || GetRandomValue(0, 100) < 50) {\n            int count = inputActive ? 5 : 2;\n            for (int i = 0; i < count; i++) {\n                Particle p;\n                p.position = pos;\n                p.velocity = {(float)GetRandomValue(-200, 200) / 100.0f, (float)GetRandomValue(-200, 200) / 100.0f};\n                p.color = (Color){(unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), 255};\n                p.size = (float)GetRandomValue(5, 20);\n                p.life = 1.0f;\n                particles.push_back(p);\n            }\n        }\n\n        for (auto it = particles.begin(); it != particles.end();) {\n            it->position.x += it->velocity.x * 5.0f;\n            it->position.y += it->velocity.y * 5.0f;\n            it->life -= 0.02f;\n            it->size *= 0.99f;\n\n            if (it->life <= 0) {\n                it = particles.erase(it);\n            } else {\n                ++it;\n            }\n        }\n\n        // Draw\n        BeginDrawing();\n        ClearBackground(BLACK);\n        \n        for (const auto& p : particles) {\n            DrawCircleV(p.position, p.size, Fade(p.color, p.life));\n        }\n        \n        // Draw FPS\n        const char* fpsText = TextFormat(\"%2i FPS\", GetFPS());\n        int fpsWidth = MeasureText(fpsText, 40);\n        DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN);\n\n        // Draw centered instructions\n        int fontSize = 40;\n        const char* text = \"Touch to create particles!\";\n        int textWidth = MeasureText(text, fontSize);\n        DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 80, fontSize, WHITE);\n\n        EndDrawing();\n    }\n\n    CloseWindow();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/android/native_app/raylib_particles/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"raylib 5.5.0\")\n\ntarget(\"raydemo_particles\")\n    set_kind(\"binary\")\n    set_languages(\"c++17\")\n    add_files(\"src/main.cpp\")\n    add_syslinks(\"log\")\n    add_packages(\"raylib\")\n    add_rules(\"android.native_app\", {\n        android_sdk_version = \"35\",\n        android_manifest = \"android/AndroidManifest.xml\",\n        android_res = \"android/res\",\n        keystore = \"android/debug.jks\",\n        keystore_pass = \"123456\",\n        package_name = \"com.raylib.particles\",\n        logcat_filters = {\"raydemo_particles\", \"raylib\"}\n    })\n"
  },
  {
    "path": "tests/projects/asm/fasm/src/main.S",
    "content": "format MZ\n\nentry main:start                        ; program entry point\nstack 100h                              ; stack size\n\nsegment main                            ; main program segment\n\n  start:\n        mov     ax,text\n        mov     ds,ax\n\n        mov     dx,hello\n        call    extra:write_text\n\n        mov     ax,4C00h\n        int     21h\n\nsegment text\n\n  hello db 'Hello world!',24h\n\nsegment extra\n\n  write_text:\n        mov     ah,9\n        int     21h\n        retf\n\n"
  },
  {
    "path": "tests/projects/asm/fasm/xmake.lua",
    "content": "target(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.S\")\n"
  },
  {
    "path": "tests/projects/asm/gas/src/main.S",
    "content": "        .global main\n\n        .text\nmain:                                   # This is called by C library's startup code\n        mov     $message, %rdi          # First integer (or pointer) parameter in %rdi\n        call    puts                    # puts(message)\n        ret                             # Return to C library code\nmessage:\n        .asciz \"Hola, mundo\"            # asciz puts a 0 byte at the end\n"
  },
  {
    "path": "tests/projects/asm/gas/xmake.lua",
    "content": "target(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.S\")\n"
  },
  {
    "path": "tests/projects/asm/masm32/src/generic.asm",
    "content": "; #########################################################################\r\n;\r\n;             GENERIC.ASM is a roadmap around a standard 32 bit\r\n;              windows application skeleton written in MASM32.\r\n;\r\n; #########################################################################\r\n\r\n;           Assembler specific instructions for 32 bit ASM code\r\n\r\n      .386                   ; minimum processor needed for 32 bit\r\n      .model flat, stdcall   ; FLAT memory model & STDCALL calling\r\n      option casemap :none   ; set code to case sensitive\r\n\r\n; #########################################################################\r\n\r\n      ; ---------------------------------------------\r\n      ; main include file with equates and structures\r\n      ; ---------------------------------------------\r\n      include windows.inc\r\n\r\n      ; -------------------------------------------------------------\r\n      ; In MASM32, each include file created by the L2INC.EXE utility\r\n      ; has a matching library file. If you need functions from a\r\n      ; specific library, you use BOTH the include file and library\r\n      ; file for that library.\r\n      ; -------------------------------------------------------------\r\n\r\n      include user32.inc\r\n      include kernel32.inc\r\n\r\n; #########################################################################\r\n\r\n; ------------------------------------------------------------------------\r\n; MACROS are a method of expanding text at assembly time. This allows the\r\n; programmer a tidy and convenient way of using COMMON blocks of code with\r\n; the capacity to use DIFFERENT parameters in each block.\r\n; ------------------------------------------------------------------------\r\n\r\n      ; 1. szText\r\n      ; A macro to insert TEXT into the code section for convenient and\r\n      ; more intuitive coding of functions that use byte data as text.\r\n\r\n      szText MACRO Name, Text:VARARG\r\n        LOCAL lbl\r\n          jmp lbl\r\n            Name db Text,0\r\n          lbl:\r\n        ENDM\r\n\r\n      ; 2. m2m\r\n      ; There is no mnemonic to copy from one memory location to another,\r\n      ; this macro saves repeated coding of this process and is easier to\r\n      ; read in complex code.\r\n\r\n      m2m MACRO M1, M2\r\n        push M2\r\n        pop  M1\r\n      ENDM\r\n\r\n      ; 3. return\r\n      ; Every procedure MUST have a \"ret\" to return the instruction\r\n      ; pointer EIP back to the next instruction after the call that\r\n      ; branched to it. This macro puts a return value in eax and\r\n      ; makes the \"ret\" instruction on one line. It is mainly used\r\n      ; for clear coding in complex conditionals in large branching\r\n      ; code such as the WndProc procedure.\r\n\r\n      return MACRO arg\r\n        mov eax, arg\r\n        ret\r\n      ENDM\r\n\r\n; #########################################################################\r\n\r\n; ----------------------------------------------------------------------\r\n; Prototypes are used in conjunction with the MASM \"invoke\" syntax for\r\n; checking the number and size of parameters passed to a procedure. This\r\n; improves the reliability of code that is written where errors in\r\n; parameters are caught and displayed at assembly time.\r\n; ----------------------------------------------------------------------\r\n\r\n        WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD\r\n        WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD\r\n        TopXY PROTO   :DWORD,:DWORD\r\n\r\n; #########################################################################\r\n\r\n; ------------------------------------------------------------------------\r\n; This is the INITIALISED data section meaning that data declared here has\r\n; an initial value. You can also use an UNINIALISED section if you need\r\n; data of that type [ .data? ]. Note that they are different and occur in\r\n; different sections.\r\n; ------------------------------------------------------------------------\r\n\r\n    .data\r\n        szDisplayName db \"Generic\",0\r\n        CommandLine   dd 0\r\n        hWnd          dd 0\r\n        hInstance     dd 0\r\n\r\n\r\n\r\n; #########################################################################\r\n\r\n; ------------------------------------------------------------------------\r\n; This is the start of the code section where executable code begins. This\r\n; section ending with the ExitProcess() API function call is the only\r\n; GLOBAL section of code and it provides access to the WinMain function\r\n; with the necessary parameters, the instance handle and the command line\r\n; address.\r\n; ------------------------------------------------------------------------\r\n\r\n    .code\r\n\r\n; -----------------------------------------------------------------------\r\n; The label \"start:\" is the address of the start of the code section and\r\n; it has a matching \"end start\" at the end of the file. All procedures in\r\n; this module must be written between these two.\r\n; -----------------------------------------------------------------------\r\n\r\nstart:\r\n    invoke GetModuleHandle, NULL ; provides the instance handle\r\n    mov hInstance, eax\r\n\r\n    invoke GetCommandLine        ; provides the command line address\r\n    mov CommandLine, eax\r\n\r\n    invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT\r\n\r\n    invoke ExitProcess,eax       ; cleanup & return to operating system\r\n\r\n; #########################################################################\r\n\r\nWinMain proc hInst     :DWORD,\r\n             hPrevInst :DWORD,\r\n             CmdLine   :DWORD,\r\n             CmdShow   :DWORD\r\n\r\n        ;====================\r\n        ; Put LOCALs on stack\r\n        ;====================\r\n\r\n        LOCAL wc   :WNDCLASSEX\r\n        LOCAL msg  :MSG\r\n\r\n        LOCAL Wwd  :DWORD\r\n        LOCAL Wht  :DWORD\r\n        LOCAL Wtx  :DWORD\r\n        LOCAL Wty  :DWORD\r\n\r\n        szText szClassName,\"Generic_Class\"\r\n\r\n        ;==================================================\r\n        ; Fill WNDCLASSEX structure with required variables\r\n        ;==================================================\r\n\r\n        mov wc.cbSize,         sizeof WNDCLASSEX\r\n        mov wc.style,          CS_HREDRAW or CS_VREDRAW \\\r\n                               or CS_BYTEALIGNWINDOW\r\n        mov wc.lpfnWndProc,    offset WndProc      ; address of WndProc\r\n        mov wc.cbClsExtra,     NULL\r\n        mov wc.cbWndExtra,     NULL\r\n        m2m wc.hInstance,      hInst               ; instance handle\r\n        mov wc.hbrBackground,  COLOR_BTNFACE+1     ; system color\r\n        mov wc.lpszMenuName,   NULL\r\n        mov wc.lpszClassName,  offset szClassName  ; window class name\r\n          invoke LoadIcon,hInst,500    ; icon ID   ; resource icon\r\n        mov wc.hIcon,          eax\r\n          invoke LoadCursor,NULL,IDC_ARROW         ; system cursor\r\n        mov wc.hCursor,        eax\r\n        mov wc.hIconSm,        0\r\n\r\n        invoke RegisterClassEx, ADDR wc     ; register the window class\r\n\r\n        ;================================\r\n        ; Centre window at following size\r\n        ;================================\r\n\r\n        mov Wwd, 500\r\n        mov Wht, 350\r\n\r\n        invoke GetSystemMetrics,SM_CXSCREEN ; get screen width in pixels\r\n        invoke TopXY,Wwd,eax\r\n        mov Wtx, eax\r\n\r\n        invoke GetSystemMetrics,SM_CYSCREEN ; get screen height in pixels\r\n        invoke TopXY,Wht,eax\r\n        mov Wty, eax\r\n\r\n        ; ==================================\r\n        ; Create the main application window\r\n        ; ==================================\r\n        invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,\r\n                              ADDR szClassName,\r\n                              ADDR szDisplayName,\r\n                              WS_OVERLAPPEDWINDOW,\r\n                              Wtx,Wty,Wwd,Wht,\r\n                              NULL,NULL,\r\n                              hInst,NULL\r\n\r\n        mov   hWnd,eax  ; copy return value into handle DWORD\r\n\r\n        invoke LoadMenu,hInst,600                 ; load resource menu\r\n        invoke SetMenu,hWnd,eax                   ; set it to main window\r\n\r\n        invoke ShowWindow,hWnd,SW_SHOWNORMAL      ; display the window\r\n        invoke UpdateWindow,hWnd                  ; update the display\r\n\r\n      ;===================================\r\n      ; Loop until PostQuitMessage is sent\r\n      ;===================================\r\n\r\n    StartLoop:\r\n      invoke GetMessage,ADDR msg,NULL,0,0         ; get each message\r\n      cmp eax, 0                                  ; exit if GetMessage()\r\n      je ExitLoop                                 ; returns zero\r\n      invoke TranslateMessage, ADDR msg           ; translate it\r\n      invoke DispatchMessage,  ADDR msg           ; send it to message proc\r\n      jmp StartLoop\r\n    ExitLoop:\r\n\r\n      return msg.wParam\r\n\r\nWinMain endp\r\n\r\n; #########################################################################\r\n\r\nWndProc proc hWin   :DWORD,\r\n             uMsg   :DWORD,\r\n             wParam :DWORD,\r\n             lParam :DWORD\r\n\r\n; -------------------------------------------------------------------------\r\n; Message are sent by the operating system to an application through the\r\n; WndProc proc. Each message can have additional values associated with it\r\n; in the two parameters, wParam & lParam. The range of additional data that\r\n; can be passed to an application is determined by the message.\r\n; -------------------------------------------------------------------------\r\n\r\n    .if uMsg == WM_COMMAND\r\n    ;----------------------------------------------------------------------\r\n    ; The WM_COMMAND message is sent by menus, buttons and toolbar buttons.\r\n    ; Processing the wParam parameter of it is the method of obtaining the\r\n    ; control's ID number so that the code for each operation can be\r\n    ; processed. NOTE that the ID number is in the LOWORD of the wParam\r\n    ; passed with the WM_COMMAND message. There may be some instances where\r\n    ; an application needs to seperate the high and low words of wParam.\r\n    ; ---------------------------------------------------------------------\r\n\r\n    ;======== menu commands ========\r\n\r\n        .if wParam == 1000\r\n            invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL\r\n        .elseif wParam == 1900\r\n            szText TheMsg,\"Assembler, Pure & Simple\"\r\n            invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK\r\n        .endif\r\n\r\n    ;====== end menu commands ======\r\n\r\n    .elseif uMsg == WM_CREATE\r\n    ; --------------------------------------------------------------------\r\n    ; This message is sent to WndProc during the CreateWindowEx function\r\n    ; call and is processed before it returns. This is used as a position\r\n    ; to start other items such as controls. IMPORTANT, the handle for the\r\n    ; CreateWindowEx call in the WinMain does not yet exist so the HANDLE\r\n    ; passed to the WndProc [ hWin ] must be used here for any controls\r\n    ; or child windows.\r\n    ; --------------------------------------------------------------------\r\n\r\n    .elseif uMsg == WM_CLOSE\r\n    ; -------------------------------------------------------------------\r\n    ; This is the place where various requirements are performed before\r\n    ; the application exits to the operating system such as deleting\r\n    ; resources and testing if files have been saved. You have the option\r\n    ; of returning ZERO if you don't wish the application to close which\r\n    ; exits the WndProc procedure without passing this message to the\r\n    ; default window processing done by the operating system.\r\n    ; -------------------------------------------------------------------\r\n        szText TheText,\"Please Confirm Exit\"\r\n        invoke MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNO\r\n          .if eax == IDNO\r\n            return 0\r\n          .endif\r\n\r\n    .elseif uMsg == WM_DESTROY\r\n    ; ----------------------------------------------------------------\r\n    ; This message MUST be processed to cleanly exit the application.\r\n    ; Calling the PostQuitMessage() function makes the GetMessage()\r\n    ; function in the WinMain() main loop return ZERO which exits the\r\n    ; application correctly. If this message is not processed properly\r\n    ; the window disappears but the code is left in memory.\r\n    ; ----------------------------------------------------------------\r\n        invoke PostQuitMessage,NULL\r\n        return 0\r\n    .endif\r\n\r\n    invoke DefWindowProc,hWin,uMsg,wParam,lParam\r\n    ; --------------------------------------------------------------------\r\n    ; Default window processing is done by the operating system for any\r\n    ; message that is not processed by the application in the WndProc\r\n    ; procedure. If the application requires other than default processing\r\n    ; it executes the code when the message is trapped and returns ZERO\r\n    ; to exit the WndProc procedure before the default window processing\r\n    ; occurs with the call to DefWindowProc().\r\n    ; --------------------------------------------------------------------\r\n\r\n    ret\r\n\r\nWndProc endp\r\n\r\n; ########################################################################\r\n\r\nTopXY proc wDim:DWORD, sDim:DWORD\r\n\r\n    ; ----------------------------------------------------\r\n    ; This procedure calculates the top X & Y co-ordinates\r\n    ; for the CreateWindowEx call in the WinMain procedure\r\n    ; ----------------------------------------------------\r\n\r\n    shr sDim, 1      ; divide screen dimension by 2\r\n    shr wDim, 1      ; divide window dimension by 2\r\n    mov eax, wDim    ; copy window dimension into eax\r\n    sub sDim, eax    ; sub half win dimension from half screen dimension\r\n\r\n    return sDim\r\n\r\nTopXY endp\r\n\r\n; ########################################################################\r\n\r\nend start\r\n"
  },
  {
    "path": "tests/projects/asm/masm32/src/rsrc.rc",
    "content": "500 ICON MOVEABLE PURE LOADONCALL DISCARDABLE \"MAINICON.ICO\"\r\n\r\n600 MENUEX MOVEABLE IMPURE LOADONCALL DISCARDABLE\r\nBEGIN\r\n    POPUP \"&File\", , , 0\r\n    BEGIN\r\n        MENUITEM \"&Exit\", 1000\r\n    END\r\n    POPUP \"&Help\", , , 0\r\n    BEGIN\r\n        MENUITEM \"&About\", 1900\r\n    END\r\nEND\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/asm/masm32/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_allowedplats(\"windows\")\nset_defaultarchs(\"x86\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.asm\")\n    add_files(\"src/*.rc\")\n    set_toolchains(\"masm32\")\n"
  },
  {
    "path": "tests/projects/asm/nasm/src/main.S",
    "content": "global _main\n\nsection .text\n\n_main:\n    mov     rax, 0x2000004 ; write\n    mov     rdi, 1 ; stdout\n    mov     rsi, msg\n    mov     rdx, msg.len\n    syscall\n\n    mov     rax, 0x2000001 ; exit\n    mov     rdi, 0\n    syscall\n\n\nsection .data\n\nmsg:    db      \"hello xmake!\", 10\n.len:   equ     $ - msg\n"
  },
  {
    "path": "tests/projects/asm/nasm/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.S\")\n"
  },
  {
    "path": "tests/projects/asm/yasm/src/main.S",
    "content": "bits 64\n\nextern _puts\n\nsection .data\n\nmessage:\n  db 'hello xmake!', 0\n\nsection .text\n\nglobal _main\n_main:\n  push rbp\n  mov rbp, rsp\n  lea rdi, [rel message]\n  call _puts\n  xor rax, rax\n  pop rbp\n  ret\n"
  },
  {
    "path": "tests/projects/asm/yasm/src/main_elf.S",
    "content": "bits 64\n\nextern puts\n\nsection .data\n\nmessage:\n  db 'hello xmake!', 0\n\nsection .text\n\nglobal main\nmain:\n  push rbp\n  mov rbp, rsp\n  lea rdi, [rel message]\n  call puts\n  xor rax, rax\n  pop rbp\n  ret\n"
  },
  {
    "path": "tests/projects/asm/yasm/src/stub.c",
    "content": ""
  },
  {
    "path": "tests/projects/asm/yasm/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    if is_plat(\"linux\") then\n        add_files(\"src/main_elf.S\")\n    else\n        add_files(\"src/main.S\")\n    end\n"
  },
  {
    "path": "tests/projects/c/Unicode 测试/test.lua",
    "content": "-- main entry\nfunction main(t)\n\n    -- build project, xmake does not support unicode for msys2/mingw\n    if not is_subhost(\"msys\", \"cygwin\") then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/c/Unicode 测试/xmake.lua",
    "content": "\n-- this file saved with utf-16 le for test purpose\n\nadd_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"程序\")\n    set_kind(\"binary\")\n    add_files(\"源文件🎆/*.c\")\n    add_includedirs(\"头文件✨\")\n\n    before_build(function()\n        print(\"开始编译😊\")\n    end)\n\n    after_build(function()\n        print(\"结束编译🎉\")\n    end)\n\n"
  },
  {
    "path": "tests/projects/c/Unicode 测试/头文件✨/标头🎟.h",
    "content": "﻿#pragma once\n\nvoid hello();"
  },
  {
    "path": "tests/projects/c/Unicode 测试/源文件🎆/中文.c",
    "content": "﻿#include <标头🎟.h>\n\nint main(int argc, char** argv)\n{\n    hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/Unicode 测试/源文件🎆/😘.c",
    "content": "﻿#include <stdio.h>\n#include <wchar.h>\n#include <标头🎟.h>\n\nvoid hello()\n{\n    printf(\"你好\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c/asn1c/src/main.c",
    "content": "#include <stdio.h>\n#include <sys/types.h>\n#include <Rectangle.h>   /* Rectangle ASN.1 type  */\n\n/*\n * This is a custom function which writes the\n * encoded output into some FILE stream.\n */\nstatic int\nwrite_out(const void *buffer, size_t size, void *app_key) {\n\tFILE *out_fp = app_key;\n\tsize_t wrote;\n\n\twrote = fwrite(buffer, 1, size, out_fp);\n\n\treturn (wrote == size) ? 0 : -1;\n}\n\nint main(int ac, char **av) {\n\tRectangle_t *rectangle; /* Type to encode        */\n\tasn_enc_rval_t ec;      /* Encoder return value  */\n\n\t/* Allocate the Rectangle_t */\n\trectangle = calloc(1, sizeof(Rectangle_t)); /* not malloc! */\n\tif(!rectangle) {\n\t\tperror(\"calloc() failed\");\n\t\texit(71); /* better, EX_OSERR */\n\t}\n\n\t/*\n\t * Initialize the Rectangle members\n\t */\n\n\t/* height */\n\trectangle->height = 42;\n\n\t/* width */\n\trectangle->width = 23;\n\n\t/* BER encode the data if filename is given */\n\tif(ac < 2) {\n\t\tfprintf(stderr, \"Specify filename for BER output\\n\");\n\t} else {\n\t\tconst char *filename = av[1];\n\t\tFILE *fp = fopen(filename, \"wb\");   /* for BER output */\n\n\t\tif(!fp) {\n\t\t\tperror(filename);\n\t\t\texit(71); /* better, EX_OSERR */\n\t\t}\n\n\t\t/* Encode the Rectangle type as BER (DER) */\n\t\tec = der_encode(&asn_DEF_Rectangle,\n\t\t\t\trectangle, write_out, fp);\n\t\tfclose(fp);\n\t\tif(ec.encoded == -1) {\n\t\t\tfprintf(stderr,\n\t\t\t\t\t\"Could not encode Rectangle (at %s)\\n\",\n\t\t\t\t\tec.failed_type ? ec.failed_type->name : \"unknown\");\n\t\t\texit(65); /* better, EX_DATAERR */\n\t\t} else {\n\t\t\tfprintf(stderr, \"Created %s with BER encoded Rectangle\\n\",\n\t\t\t\t\tfilename);\n\t\t}\n\t}\n\n\t/* Also print the constructed Rectangle XER encoded (XML) */\n\txer_fprint(stdout, &asn_DEF_Rectangle, rectangle);\n\n\treturn 0; /* Encoding finished successfully */\n}\n\n\n"
  },
  {
    "path": "tests/projects/c/asn1c/src/rectangle.asn1",
    "content": "RectangleModule1 DEFINITIONS ::=\nBEGIN\nRectangle ::= SEQUENCE {\n    height  INTEGER,\n    width   INTEGER\n}\nEND\n"
  },
  {
    "path": "tests/projects/c/asn1c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"asn1c\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_files(\"src/*.asn1\")\n    add_rules(\"asn1c\")\n    add_packages(\"asn1c\")\n"
  },
  {
    "path": "tests/projects/c/console/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/console/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n\n"
  },
  {
    "path": "tests/projects/c/cosmocc/console/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/cosmocc/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"cosmocc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@cosmocc\")\n\n"
  },
  {
    "path": "tests/projects/c/cosmocc/static_library/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/cosmocc/static_library/src/foo.h",
    "content": "int add(int a, int b);\n\n"
  },
  {
    "path": "tests/projects/c/cosmocc/static_library/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/cosmocc/static_library/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"cosmocc\")\nset_toolchains(\"@cosmocc\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.c\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n\n"
  },
  {
    "path": "tests/projects/c/embeddirs/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c/embeddirs/assets/message.txt",
    "content": "Hello from an embedded C23 file!\n"
  },
  {
    "path": "tests/projects/c/embeddirs/src/main.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nstatic const unsigned char message_data[] = {\n#embed \"message.txt\"\n    , '\\0'\n};\n\nint main(int argc, char** argv) {\n    printf(\"Embedded message: %s\\n\", (const char*)message_data);\n    printf(\"Size of embedded data (including null terminator): %zu bytes\\n\", sizeof(message_data));\n    printf(\"Length of embedded string: %zu characters\\n\", strlen((const char*)message_data));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/embeddirs/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_languages(\"c23\")\n\ntarget(\"embeddirs\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_embeddirs(\"assets\")\n\n"
  },
  {
    "path": "tests/projects/c/headeronly/src/foo.h",
    "content": "/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */ \nint             add(int a, int b);\n\n"
  },
  {
    "path": "tests/projects/c/headeronly/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/headeronly/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"foo\")\n    set_kind(\"headeronly\")\n    add_headerfiles(\"src/foo.h\")\n    add_rules(\"utils.install.cmake_importfiles\")\n    add_rules(\"utils.install.pkgconfig_importfiles\")\n\n\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/foo/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13.0)\nproject(foo LANGUAGES C CXX ASM)\n\nadd_library(foo STATIC \"\")\ntarget_sources(foo PRIVATE\n    src/foo.c\n)\nset_target_properties(foo PROPERTIES PUBLIC_HEADER src/foo.h)\ninclude(GNUInstallDirs)\ninstall(TARGETS foo\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}\n)\n\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/foo/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/foo/src/foo.h",
    "content": "int add(int a, int b);\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/test.lua",
    "content": "-- main entry\nfunction main(t)\n\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/c/library_with_cmakelists/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\npackage(\"foo\")\n    add_deps(\"cmake\")\n    set_sourcedir(path.join(os.scriptdir(), \"foo\"))\n    set_policy(\"package.install_always\", true)\n    on_install(function (package)\n        local configs = {}\n        table.insert(configs, \"-DCMAKE_BUILD_TYPE=\" .. (package:debug() and \"Debug\" or \"Release\"))\n        table.insert(configs, \"-DBUILD_SHARED_LIBS=\" .. (package:config(\"shared\") and \"ON\" or \"OFF\"))\n        import(\"package.tools.cmake\").install(package, configs)\n    end)\n    on_test(function (package)\n        assert(package:has_cfuncs(\"add\", {includes = \"foo.h\"}))\n    end)\npackage_end()\n\nadd_requires(\"foo\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    add_packages(\"foo\")\n\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/src/foo.c",
    "content": "#include <stdio.h>\n\nvoid foo() {\n    printf(\"hello world!\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/src/foo.def",
    "content": "EXPORTS\nfoo\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/src/main.c",
    "content": "#include <stdio.h>\n\nvoid foo();\n\nint main(int argc, char** argv) {\n    foo();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/src/main.lds",
    "content": "SECTIONS\n{\n  . = 0x10000;\n  .text : { *(.text) }\n  .init_array :\n  {\n      PROVIDE_HIDDEN (__init_array_start = .);\n      KEEP (*(SORT(.init_array.*)))\n      KEEP (*(.init_array*))\n      PROVIDE_HIDDEN (__init_array_end = .);\n  }\n  . = 0x8000000;\n  .data : { *(.data) }\n  .bss : { *(.bss) }\n}\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/linker_scripts/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_deps(\"foo\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    if is_plat(\"linux\") and is_arch(\"x86_64\") then\n        add_files(\"src/main.lds\")\n    end\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\")\n    if is_plat(\"windows\", \"mingw\") then\n        add_files(\"src/foo.def\")\n    else\n        add_files(\"src/foo.map\")\n    end\n\n"
  },
  {
    "path": "tests/projects/c/llvm_compiler_rt/src/main.c",
    "content": "int main(int argc, char **argv) {\n    __int128 a = 123;\n    __int128 b = 1;\n    return a / b;\n}\n"
  },
  {
    "path": "tests/projects/c/llvm_compiler_rt/test.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.tool.toolchain\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nfunction run_test(toolchain_name)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n\n    local plat = os.host()\n    local arch = os.arch()\n    if is_subhost(\"msys\") then\n        plat = \"mingw\"\n    end\n    local toolchain_inst = toolchain.load(toolchain_name, {plat = plat, arch = arch})\n    if not toolchain_inst or not toolchain_inst:check() then\n        wprint(toolchain_name .. \" not found, skipping tests\")\n        return\n    end\n    os.exec(\"xmake clean -a\")\n    os.exec(\"xmake f --toolchain=\" .. toolchain_name .. \" -c --yes \" .. flags)\n    os.run(\"xmake -r \" .. flags)\nend\n\nfunction main(t)\n    run_test(\"llvm\")\n    run_test(\"clang\")\nend\n"
  },
  {
    "path": "tests/projects/c/llvm_compiler_rt/xmake.lua",
    "content": "target(\"foo\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/header.h",
    "content": "// header.h\n#ifndef HEADER_H\n#define HEADER_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#endif\n\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/main.c",
    "content": "#include \"header.h\"\n\nint main(int argc, char** argv) \n{\n    printf(\"hello xmake!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test.cpp",
    "content": "int test_cpp()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test2.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test2()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test3.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test3()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test4.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test4()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test5.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test5()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test6.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test6()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test7.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test7()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/src/test8.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test8()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/precompiled_header/xmake.lua",
    "content": "target(\"main\")\n    set_kind(\"binary\")\n    set_pcheader(\"src/header.h\")\n    add_files(\"src/*.c\", \"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/c/protobuf/src/main.c",
    "content": "#include <stdio.h>\n#include \"test.pb-c.h\"\n#include \"subdir/test2.pb-c.h\"\n\nint main(int argc, char** argv)\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/protobuf/src/subdir/test2.proto",
    "content": "syntax = \"proto3\";\npackage test2;\nmessage TestCase2 {\n    string name = 4;\n}\nmessage Test2 {\n    repeated TestCase2 case = 1;\n}\n"
  },
  {
    "path": "tests/projects/c/protobuf/src/test.proto",
    "content": "syntax = \"proto3\";\nimport \"subdir/test2.proto\";\npackage test;\nmessage TestCase {\n    string name = 4;\n}\nmessage Test {\n    repeated TestCase case = 1;\n    repeated test2.TestCase2 case2 = 2;\n}\n"
  },
  {
    "path": "tests/projects/c/protobuf/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"protobuf-c\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_packages(\"protobuf-c\")\n    add_rules(\"protobuf.c\")\n    add_files(\"src/*.c\")\n    add_files(\"src/**.proto\", {proto_rootdir = \"src\"})\n\n"
  },
  {
    "path": "tests/projects/c/shared_library/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#   define __export         __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#   define __export         __attribute__((visibility(\"default\")))\n#else\n#   define __export\n#endif\n\n__export int    add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c/shared_library/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/shared_library/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/src/bar.cpp",
    "content": "#include <stdio.h>\n\nclass bar\n{\n    bar() {}\n    ~bar() {}\n    void test() {}\n};\n\nvoid test(bar& b)\n{\n    printf(\"test\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_all/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\", \"src/bar.cpp\")\n    add_rules(\"utils.symbols.export_all\", {export_classes = true})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/src/foo.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nvoid stub() {\n    printf(\"stub\\n\");\n}\n\nint sub(int a, int b) {\n    return a - b;\n}\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/src/foo.export.txt",
    "content": "add\nsub\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/shared_library_export_list/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\")\n    add_rules(\"utils.symbols.export_list\", {symbols = {\n        \"add\",\n        \"sub\"}})\n\ntarget(\"foo2\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\")\n    add_files(\"src/foo.export.txt\")\n    add_rules(\"utils.symbols.export_list\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n\n"
  },
  {
    "path": "tests/projects/c/static library with spaces/i n c/interface.h",
    "content": "/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\nint             add(int a, int b);\n"
  },
  {
    "path": "tests/projects/c/static library with spaces/i n c/stdafx.h",
    "content": ""
  },
  {
    "path": "tests/projects/c/static library with spaces/s r c/interface.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/static library with spaces/s r c/test.c",
    "content": "#include \"interface.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/static library with spaces/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/static library with spaces/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_files(\"s r c/interface.c\")\n    add_sysincludedirs(\"$(projectdir)/i n c\", {public = true})\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"s r c/test.c\")\n    set_pcheader(\"$(projectdir)/i n c/stdafx.h\")\n\n\n"
  },
  {
    "path": "tests/projects/c/static_library/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c/static_library/src/foo.h",
    "content": "int add(int a, int b);\n\n"
  },
  {
    "path": "tests/projects/c/static_library/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/static_library/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/static_library/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.c\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/bar/test4.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test4()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/bar/test5.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test5()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/foo/test1.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/foo/test2.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test3()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/header.h",
    "content": "// header.h\n#ifndef HEADER_H\n#define HEADER_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#endif\n\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/main.c",
    "content": "#include \"header.h\"\n\nint main(int argc, char** argv) \n{\n    printf(\"hello xmake!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/test.cpp",
    "content": "int test_cpp()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/test2.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test2()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/test6.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test6()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/test7.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test7()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/src/test8.c",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test8()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c/unity_build/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c/unity_build/xmake.lua",
    "content": "target(\"test\")\n    set_kind(\"binary\")\n    add_includedirs(\"src\")\n    add_rules(\"c.unity_build\", {batchsize = 2})\n    add_files(\"src/*.c\", \"src/*.cpp\")\n    add_files(\"src/foo/*.c\", {unity_group = \"foo\"})\n    add_files(\"src/bar/*.c\", {unity_group = \"bar\"})\n\n"
  },
  {
    "path": "tests/projects/c++/capnproto/proto/message.capnp",
    "content": "@0xd30600b3651feef7;\n\nusing Cxx = import \"/capnp/c++.capnp\";\n$Cxx.namespace(\"test::proto\");\n\nstruct Message {\n  text @0 :Text;\n}\n"
  },
  {
    "path": "tests/projects/c++/capnproto/src/main.cc",
    "content": "#include <capnp/message.h>\n#include \"message.capnp.h\"\n\nint main() {\n    capnp::MallocMessageBuilder builder;\n    // test::proto::Message msg;\n}\n"
  },
  {
    "path": "tests/projects/c++/capnproto/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"capnproto\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    set_languages(\"c++14\")\n    add_packages(\"capnproto\")\n    add_files(\"src/**.cc\")\n    add_files(\"proto/*.capnp\", {rules = \"capnproto.cpp\", capnp_rootdir = \"proto\"})\n"
  },
  {
    "path": "tests/projects/c++/console/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/console/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/console_zig_cxx/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/console_zig_cxx/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/console_zig_cxx/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"zig\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_toolchains(\"zig@zigcc\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/doctest/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/doctest/src/foo.cpp",
    "content": "void foo() {\n}\n"
  },
  {
    "path": "tests/projects/c++/doctest/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/doctest/tests/test_1.cpp",
    "content": "#include \"doctest/doctest.h\"\n\nstatic int factorial(int number) {\n    return number <= 1 ? number : factorial(number - 1) * number;\n}\n\nTEST_CASE(\"testing the factorial function\") {\n    CHECK(factorial(1) == 10);\n    CHECK(factorial(2) == 2);\n    CHECK(factorial(3) == 6);\n    CHECK(factorial(10) == 3628800);\n}\n"
  },
  {
    "path": "tests/projects/c++/doctest/tests/test_2.cpp",
    "content": "#include \"doctest/doctest.h\"\n\nstatic int factorial(int number) {\n    return number <= 1 ? number : factorial(number - 1) * number;\n}\n\nTEST_CASE(\"testing the factorial function\") {\n    CHECK(factorial(1) == 1);\n    CHECK(factorial(2) == 2);\n    CHECK(factorial(3) == 6);\n    CHECK(factorial(10) == 3628800);\n}\n"
  },
  {
    "path": "tests/projects/c++/doctest/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"doctest\")\n\ntarget(\"doctest\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    for _, testfile in ipairs(os.files(\"tests/*.cpp\")) do\n        add_tests(path.basename(testfile), {\n            files = testfile,\n            remove_files = \"src/main.cpp\",\n            languages = \"c++11\",\n            packages = \"doctest\",\n            defines = \"DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\"})\n    end\n\ntarget(\"doctest_shared\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n    for _, testfile in ipairs(os.files(\"tests/*.cpp\")) do\n        add_tests(path.basename(testfile), {\n            kind = \"binary\",\n            files = testfile,\n            languages = \"c++11\",\n            packages = \"doctest\",\n            defines = \"DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\"})\n    end\n\n"
  },
  {
    "path": "tests/projects/c++/linkorders/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/linkorders/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c++/linkorders/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/linkorders/test.lua",
    "content": "function main(t)\n\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/c++/linkorders/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"libpng\")\n\ntarget(\"bar\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n    add_linkgroups(\"m\", \"pthread\", {whole = true})\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n    add_packages(\"libpng\", {public = true})\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n    if is_plat(\"linux\", \"macosx\") then\n        add_syslinks(\"pthread\", \"m\", \"dl\")\n    end\n    if is_plat(\"macosx\") then\n        add_frameworks(\"Foundation\", \"CoreFoundation\")\n    end\n    add_linkorders(\"framework::Foundation\", \"png16\", \"foo\")\n    add_linkorders(\"dl\", \"linkgroup::syslib\")\n    add_linkgroups(\"m\", \"pthread\", {name = \"syslib\", group = true})\n\n\n"
  },
  {
    "path": "tests/projects/c++/manifest/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/manifest/src/main.manifest",
    "content": "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\r\n<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>\r\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\r\n    <security>\r\n      <requestedPrivileges>\r\n        <requestedExecutionLevel level='asInvoker' uiAccess='false' />\r\n      </requestedPrivileges>\r\n    </security>\r\n  </trustInfo>\r\n</assembly>\r\n"
  },
  {
    "path": "tests/projects/c++/manifest/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test1\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/*.manifest\")\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_policy(\"windows.manifest.uac\", \"admin\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/add_move_remove_module/src/foo.mpp",
    "content": "export module foo;\n\nexport {\n   inline int foo() { return 1; }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/add_move_remove_module/test.lua",
    "content": "inherit(\".test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction _build(_)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    os.run(\"xmake -r \" .. flags)\n    io.writefile(\"src/bar.mpp\", \"export module bar;\\n export {\\n inline int bar() { return 0; }\\n}\")\n    os.run(\"xmake \" .. flags)\n    os.rm(\"src/bar.mpp\")\n    os.run(\"xmake \" .. flags)\n    os.mv(\"src/foo.mpp\", \"src/bar.mpp\")\n    os.run(\"xmake \" .. flags)\n    os.mv(\"src/bar.mpp\", \"src/foo.mpp\")\nend\n\nfunction main(_)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, build = _build}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, build = _build}\n    local msvc_options = {version = MSVC_MIN_VER, build = _build}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/add_move_remove_module/xmake.lua",
    "content": "\nadd_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"mod\")\n    set_kind(\"static\")\n    add_files(\"src/*.mpp\", {public = true})\n\n"
  },
  {
    "path": "tests/projects/c++/modules/aliased_headerunit/src/foo/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nimport \"../header.hpp\";\n\nexport namespace hello {\n    void say(const char *arg) {\n        printf(\"%s: %s\\n\", FOO, arg);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/aliased_headerunit/src/header.hpp",
    "content": "#pragma once\n\nnamespace hello {\n    inline constexpr auto FOO = \"Hello\";\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/aliased_headerunit/src/main.cpp",
    "content": "import hello;\nimport \"header.hpp\";\n\nint main() {\n    hello::say(hello::FOO);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/aliased_headerunit/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/aliased_headerunit/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\n-- header.hpp should be built only one time\ntarget(\"aliased_headerunit\")\n    set_kind(\"binary\")\n    add_headerfiles(\"src/*.hpp\")\n    add_files(\"src/*.cpp\", \"src/foo/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/src/hello.mpp",
    "content": "export module hello;\n\nimport hello3;\n\nexport namespace hello {\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/src/hello2.mpp",
    "content": "export module hello2;\n\nimport hello;\n"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/src/hello3.mpp",
    "content": "export module hello3;\n\nimport hello2;\n"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say s(sizeof(hello::say));\n    s.hello();\n    return 0;\n}"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/test.lua",
    "content": "import(\".test_base\", {alias = \"test_build\"})\n\nfunction main(t)\n    if test_build.can_build() then\n        t:will_raise(test_build, \"circular modules dependency detected\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/circular_dependency/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"circular_dependency\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/modules/class/src/hello.mpp",
    "content": "export module hello;\n\nexport namespace hello {\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/class/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\n\nusing namespace std;\nnamespace hello {\nsay::say(int data) : data_(data) {\n}\nvoid say::hello() {\n    cout << \"hello, say class: \" << data_ << endl;\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/class/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say s(sizeof(hello::say));\n    s.hello();\n    return 0;\n}"
  },
  {
    "path": "tests/projects/c++/modules/class/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/class/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"class\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/modules/class_cmake/src/hello.mpp",
    "content": "export module hello;\n\nexport namespace hello {\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/class_cmake/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\n\nusing namespace std;\nnamespace hello {\nsay::say(int data) : data_(data) {\n}\nvoid say::hello() {\n    cout << \"hello, say class: \" << data_ << endl;\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/class_cmake/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say s(sizeof(hello::say));\n    s.hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/class_cmake/test.lua",
    "content": "inherit(\".test_cmake\")\n"
  },
  {
    "path": "tests/projects/c++/modules/class_cmake/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"class\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/modules/cpp_with_moduledeps/src/main.cpp",
    "content": "// main.cpp\nimport mod;\n\nint main()\n{\n    f();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/cpp_with_moduledeps/src/mod.cpp",
    "content": "module mod;\nvoid f()\n{\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/cpp_with_moduledeps/src/mod.mpp",
    "content": "export module mod;\nexport void f();\n"
  },
  {
    "path": "tests/projects/c++/modules/cpp_with_moduledeps/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/cpp_with_moduledeps/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"mod\")\n  set_kind(\"static\")\n  add_files(\"src/mod.mpp\", {public = true})\n  add_files(\"src/mod.cpp\")\n\ntarget(\"cpp_with_moduledeps\")\n  set_kind(\"binary\")\n  add_deps(\"mod\")\n  add_files(\"src/main.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/culling/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/culling/test.lua",
    "content": "inherit(\".test_culling\")\n"
  },
  {
    "path": "tests/projects/c++/modules/culling/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"culling\")\n    set_kind(\"static\")\n    add_files(\"src/*.mpp\")\n    set_policy(\"build.c++.modules.culling\", false)\n"
  },
  {
    "path": "tests/projects/c++/modules/culling2/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/culling2/test.lua",
    "content": "inherit(\".test_culling\")\n"
  },
  {
    "path": "tests/projects/c++/modules/culling2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"culling\")\n    set_kind(\"static\")\n    add_files(\"src/*.mpp\", {cull = false})\n"
  },
  {
    "path": "tests/projects/c++/modules/culling3/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/culling3/test.lua",
    "content": "inherit(\".test_culling\")\n"
  },
  {
    "path": "tests/projects/c++/modules/culling3/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"culling\")\n    set_kind(\"static\")\n    add_files(\"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/src/hello.mpp",
    "content": "export module hello;\n\nexport namespace hello {\n    extern int data__;\n    void say_hello();\n\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\nimport mod;\n\nvoid inner() {\n    std::cout << \"hello world! data: \" << mod::foo() << std::endl;\n}\n\nnamespace hello {\nint  data__;\nvoid say_hello() {\n    ::inner();\n}\n\nsay::say(int data) : data_{ data } {\n}\n\nvoid say::hello() {\n    hello::data__ = data_;\n    ::inner();\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::data__ = 123;\n    hello::say_hello();\n    hello::say(sizeof(hello::say)).hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/src/mod.mpp",
    "content": "export module mod;\n\nexport namespace mod {\n    int foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/src/mod_impl.cpp",
    "content": "module mod;\nimport hello;\n\nnamespace mod {\nint foo() {\n    return hello::data__;\n}\n} // namespace mod\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"dependence\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/src/bar.mpp",
    "content": "export module bar;\nimport zoo;\n\nexport namespace bar {\n    int add(int a, int b) {\n        return zoo::add(a, b);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/src/cat.mpp",
    "content": "export module cat;\n\nexport namespace cat {\n    int sub(int a, int b) {\n        return a - b;\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/src/foo.mpp",
    "content": "export module foo;\nimport bar;\nimport cat;\n\nexport namespace foo {\n    int add(int a, int b) {\n        return bar::add(a, b);\n    }\n    int sub(int a, int b) {\n        return cat::sub(a, b);\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/src/main.cpp",
    "content": "#include <stdio.h>\n\nimport foo;\n\nint main() {\n    printf(\"add(1, 2): %d\\n\", foo::add(1, 2));\n    printf(\"sub(1, 2): %d\\n\", foo::sub(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/src/zoo.mpp",
    "content": "export module zoo;\n\nexport namespace zoo {\n    int add(int a, int b) {\n        return a + b;\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependence2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"dependence2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update/src/bar.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module bar;\n\nnamespace bar {\nexport void hello() { std::cout << \"Hello world2\" << std::endl; }\n} // namespace bar\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update/src/foo.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module foo;\n\nnamespace foo {\nexport void hello() { std::cout << \"Hello world\" << std::endl; }\n} // namespace foo\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update/src/main.cpp",
    "content": "#if defined(FOO)\nimport foo;\nusing namespace foo;\n#else\nimport bar;\nusing namespace bar;\n#endif\n\nint main() {\n  hello();\n  return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update/test.lua",
    "content": "inherit(\".test_dependency_scanner\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\noption(\"foo\")\n    set_default(\"true\")\n    add_defines(\"FOO\")\n    \ntarget(\"dependency_flag_update\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n    add_options(\"foo\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/src/bar.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module bar;\n\nnamespace bar {\nexport void hello() { std::cout << \"Hello world2\" << std::endl; }\n} // namespace bar\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/src/foo.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module foo;\n\nnamespace foo {\nexport void hello() { std::cout << \"Hello world\" << std::endl; }\n} // namespace foo\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/src/foobar.mpp",
    "content": "export module foobar;\n\n#if defined(FOO)\nimport foo;\nnamespace impl = foo;\n#else\nimport bar;\nnamespace impl = bar;\n#endif\n\nexport void hello() { impl::hello(); }\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/src/main.cpp",
    "content": "import foobar;\n\nint main() {\n    hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/test.lua",
    "content": "inherit(\".test_dependency_scanner\")\n"
  },
  {
    "path": "tests/projects/c++/modules/dependency_flag_update2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\noption(\"foo\")\n    set_default(\"true\")\n    add_defines(\"FOO\")\n\ntarget(\"dependency_flag_update3\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n    add_options(\"foo\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/duplicate_name_detection/src/bar.mpp",
    "content": "export module foo;\n\nexport int value() {\n    return 1;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/duplicate_name_detection/src/foo.mpp",
    "content": "export module foo;\n\nexport int value() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/duplicate_name_detection/src/main.cpp",
    "content": "import foo;\n\nint main() {\n    return value();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/duplicate_name_detection/test.lua",
    "content": "inherit(\".test_duplicate_modules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/duplicate_name_detection/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"foo\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/foo.mpp\")\n\ntarget(\"bar\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/bar.mpp\")\n\ntarget(\"duplicate_name_detection_1\")\n    set_kind(\"binary\")\n    add_deps(\"foo\", \"bar\")\n    add_files(\"src/main.cpp\")\n\ntarget(\"duplicate_name_detection_2\")\n    set_kind(\"binary\")\n    add_deps(\"bar\", \"foo\")\n    add_files(\"src/main.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/headerunits_person/src/Person.mpp",
    "content": "module;\r\n\r\n#include <cstddef>\r\n\r\nexport module person;\r\n\r\nimport <string>;\r\n\r\nexport class Person {\r\npublic:\r\n  Person(std::string firstName, std::string lastName)\r\n      : m_firstName{std::move(firstName)}, m_lastName{std::move(lastName)} {}\r\n\r\n  const std::string &getFirstName() const { return m_firstName; }\r\n  const std::string &getLastName() const { return m_lastName; }\r\n\r\nprivate:\r\n  std::string m_firstName;\r\n  std::string m_lastName;\r\n};\r\n"
  },
  {
    "path": "tests/projects/c++/modules/headerunits_person/src/test.cpp",
    "content": "import person;\r\nimport <iostream>;\r\nimport <string>; // For operator<< for std::string\r\n\r\nusing namespace std;\r\n\r\nint main() {\r\n    Person person{ \"Kole\", \"Webb\" };\r\n    cout << person.getLastName() << \", \" << person.getFirstName() << endl;\r\n}\r\n"
  },
  {
    "path": "tests/projects/c++/modules/headerunits_person/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/headerunits_person/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\r\nset_languages(\"c++20\")\r\n\r\ntarget(\"headerunits_person\")\r\n    set_kind(\"binary\")\r\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\r\n\r\n"
  },
  {
    "path": "tests/projects/c++/modules/hello/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say(\"hello module!\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello with spaces/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello with spaces/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say(\"hello module!\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello with spaces/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello with spaces/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"hello with spaces\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_mpp/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_mpp/src/main.mpp",
    "content": "#include <cstdio>\n\nint main() {\n  std::printf(\"Hello world\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_mpp/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_mpp/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++23\")\n\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_files(\"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_with_pch/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nexport namespace hello {\n    void say(const char* str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_with_pch/src/main.cpp",
    "content": "#include \"test.h\"\n\nimport hello;\n\nint main() {\n    hello::say(\"hello module!\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_with_pch/src/test.h",
    "content": "#include <string>\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_with_pch/test.lua",
    "content": "inherit(\".test_base\")\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction main(_)\n    -- clang-cl doesn't support mixing pch and C++ module atm\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, disable_clang_cl = true}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER}\n    local msvc_options = {version = MSVC_MIN_VER}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/hello_with_pch/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"hello\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/test.h\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/src/bar.mpp",
    "content": "export module bar;\nimport zoo;\n\nexport namespace bar {\n    int add(int a, int b) {\n        return zoo::add(a, b);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/src/cat.mpp",
    "content": "export module cat;\n\nexport namespace cat {\n    int sub(int a, int b) {\n        return a - b;\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/src/foo.mpp",
    "content": "export module foo;\nimport bar;\nimport cat;\n\nexport namespace foo {\n    int add(int a, int b) {\n        return bar::add(a, b);\n    }\n    int sub(int a, int b) {\n        return cat::sub(a, b);\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/src/main.cpp",
    "content": "#include <stdio.h>\n\nimport foo;\n\nint main(int argc, char **argv) {\n    printf(\"add(1, 2): %d\\n\", foo::add(1, 2));\n    printf(\"sub(1, 2): %d\\n\", foo::sub(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/src/zoo.mpp",
    "content": "export module zoo;\n\nexport namespace zoo {\n    int add(int a, int b) {\n        return a + b;\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/hide_dependency_flags/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"dependence2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n    set_policy(\"build.c++.modules.hide_dependencies\", true)\n"
  },
  {
    "path": "tests/projects/c++/modules/ifdef_module/src/main.cpp",
    "content": "#ifdef FOO\nimport hello;\n#endif\n\nint main() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/ifdef_module/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/ifdef_module/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"ifdef_module\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_policy(\"build.c++.modules\", true)\n"
  },
  {
    "path": "tests/projects/c++/modules/impl_unit/src/hello.mpp",
    "content": "export module hello;\n\nnamespace hello {\n    void say_hi();\n}\n\nexport namespace hello {\n    void say_hello();\n    void say_xz();\n}"
  },
  {
    "path": "tests/projects/c++/modules/impl_unit/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\nusing namespace std;\n\nnamespace hello {\nvoid say_hi() {\n    cout << \"hello hi!\" << endl;\n}\n\nvoid say_hello() {\n    cout << \"hello world!\" << endl;\n}\n\nvoid say_xz() {\n    cout << \"hello xz!\" << endl;\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/impl_unit/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say_hello();\n    hello::say_xz();\n    // hello::say_hi();\n    return 0;\n}"
  },
  {
    "path": "tests/projects/c++/modules/impl_unit/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/impl_unit/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"impl_unit\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/include-dirs/include/foo.h",
    "content": "inline int foo() { return 0; }\n"
  },
  {
    "path": "tests/projects/c++/modules/include-dirs/src/hello.mpp",
    "content": "module;\n\n#include \"foo.h\"\n\nexport module bar;\n\nexport int bar() {\n  return foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/include-dirs/src/main.cpp",
    "content": "import bar;\n\nint main() {\n  return bar();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/include-dirs/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/include-dirs/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nrule(\"include\")\n    before_config(function (target)\n        target:add(\"includedirs\", \"$(projectdir)/include\")\n    end)\n\ntarget(\"src1\")\n    set_kind(\"static\")\n    add_rules(\"include\")\n    add_files(\"src/*.mpp\", {public = true})\n    add_defines(\"A\")\n\ntarget(\"src2\")\n    set_kind(\"binary\")\n    add_deps(\"src1\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/src/foo.mpp",
    "content": "export module foo;\n\nexport {\n    template <typename>\n    struct foo {\n        constexpr const char* hello(void) const {\n            return \"hello typename!\";\n        }\n    };\n\n    // template <>\n    // struct foo<int> {\n    //     constexpr const char* hello(void) const {\n    //         return \"hello typename int!\";\n    //     }\n    // };\n}"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/src/foo_impl.cpp",
    "content": "module foo;\n\ntemplate <>\nstruct foo<int> {\n    constexpr const char* hello(void) const {\n        return \"hello int!\";\n    }\n};"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\nexport namespace hello {\n    inline void say_hello() {\n        std::printf(\"hello world!\\n\");\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/src/main.cpp",
    "content": "#include <iostream>\n\nimport hello;\nimport say;\nimport foo;\n\nint main() {\n    hello::say_hello();\n    say{}.hello<sizeof(say)>();\n    std::cout << foo<int>{}.hello() << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/src/say.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module say;\nexport class say {\npublic:\n    template <int N>\n    void hello() {\n        std::printf(\"hello, say class: %d\\n\", N);\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/inline_and_template/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"inline_and_template\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/install_with_false_default/src/foo.mpp",
    "content": "export module foo;\n\nexport namespace foo {\n    void foo() {}\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/install_with_false_default/src/main.cpp",
    "content": "import foo;\n\nint main() {\n    foo::foo();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/install_with_false_default/test.lua",
    "content": "inherit(\".test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction _build(check_outdata)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    os.run(\"xmake -r \" .. flags)\n    os.run(\"xmake b -r \" .. flags .. \" module_test1\")\n    os.run(\"xmake install \" .. flags .. \" --installdir=out\")\nend\n\nfunction main(_)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, build = _build}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, build = _build}\n    local msvc_options = {version = MSVC_MIN_VER, build = _build}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/install_with_false_default/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"module_test\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.mpp\")\n\ntarget(\"module_test1\")\n    set_kind(\"binary\")\n    set_default(false)\n    add_deps(\"module_test\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/internal_partition/src/hello.mpp",
    "content": "export module hello;\n\nimport :part_internal;\n\nexport namespace hello {\n    void say(const char* str) {\n        say_internal(str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/internal_partition/src/hello_internal.mpp",
    "content": "module;\n\n#include <cstdio>\n\nmodule hello:part_internal;\n\nnamespace hello {\n    void say_internal(const char *str) {\n        printf(\"%s\\n\", str);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/internal_partition/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say(\"hello module!\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/internal_partition/test.lua",
    "content": "inherit(\".test_partitions\")\n"
  },
  {
    "path": "tests/projects/c++/modules/internal_partition/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"internal_partition\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/hello.mpp\")\n    add_files(\"src/hello_internal.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly/src/mod.mpp",
    "content": "export module hello;\nexport int foo() { return 0; }\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"mod\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/mod.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly_private_dep/src/main.cpp",
    "content": "import B;\n\nint main() {\n    return func();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly_private_dep/src/modA.mpp",
    "content": "export module A;\n\nexport inline constexpr auto foo = 1;\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly_private_dep/src/modB.cpp",
    "content": "module B;\n\nimport A;\n\nint func() {\n    return foo;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly_private_dep/src/modB.mpp",
    "content": "export module B;\n\nexport int func();\n"
  },
  {
    "path": "tests/projects/c++/modules/moduleonly_private_dep/xmake.lua",
    "content": "set_languages(\"c++20\")\n\ntarget(\"A\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/modA.mpp\")\n\ntarget(\"B\")\n    add_deps(\"A\")\n    set_kind(\"static\")\n    add_files(\"src/modB.mpp\", { public = true })\n    add_files(\"src/modB.cpp\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"B\")\n    add_files(\"src/main.cpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/multiple_runtimes/src/main.cpp",
    "content": "import std;\n\nint main() {\n    std::println(\"Hello world\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/multiple_runtimes/test.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"core.tool.toolchain\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = \"19\"\nGCC_MIN_VER = \"15\"\nMSVC_MIN_VER = \"14.35\"\n\nfunction _check_tool_version(name, min_ver)\n    local tool = find_tool(name, {version = true})\n    if not (tool and tool.version and semver.compare(tool.version, min_ver) >= 0) then\n        return false\n    end\n    return true\nend\n\n\nfunction _check_msvc_version(min_ver)\n    local msvc = toolchain.load(\"msvc\")\n    if not msvc or not msvc:check() then\n        return false\n    end\n    local vcvars = msvc:config(\"vcvars\")\n    if not vcvars or not vcvars.VCInstallDir or not vcvars.VCToolsVersion then\n        return false\n    end\n    local version = vcvars.VCToolsVersion\n    if not version or not (semver.compare(version, min_ver) >= 0) then\n        return false\n    end\n    return true\nend\n\nfunction main(_)\n    if is_subhost(\"windows\") then\n        if not _check_msvc_version(MSVC_MIN_VER) then\n            return\n        end\n        -- on windows, llvm libc++ std module is currently not supported, uncommend when supported\n        -- if not check_tool_version(\"clang\", CLANG_MIN_VER) then\n        --     return\n        -- end\n    elseif is_host(\"linux\") then\n        if not _check_tool_version(\"gcc\", GCC_MIN_VER) or not _check_tool_version(\"clang\", CLANG_MIN_VER) then\n            return\n        end\n    else\n        return\n    end\n\n    local cl_str = \"modules\\\\std.ixx\"\n    local clang_str = is_host(\"windows\") and \"v1\\\\std.cppm\" or \"v1/std.cppm\"\n    local gcc_str = \"v1/std.cppm\"\n\n    local flags = true and \"-vD\" or \"\"\n    local outdata\n    outdata = os.iorun(\"xmake b \" ..  flags)\n    if outdata then\n        local success = false\n        -- on windows, llvm libc++ std module is currently not supported, uncommend when supported\n        if is_subhost(\"windows\") then\n            success = outdata:find(cl_str, 1, true) -- and outdata:find(clang_str, 1, true)\n        else\n            success = outdata:find(gcc_str, 1, true) and outdata:find(clang_str, 1, true)\n        end\n        if not success then\n            raise(\"Multiple runtimes doesn't work\\n%s\", outdata)\n        end\n    end\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/multiple_runtimes/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++23\")\nset_encodings(\"utf-8\")\n\nif is_plat(\"windows\") then\n    -- on windows, llvm libc++ std module is currently not supported, uncommend when supported\n    -- target(\"llvm\")\n    --     set_kind(\"binary\")\n    --     set_toolchains(\"clang\")\n    --     set_runtimes(\"c++_shared\")\n    --     set_policy(\"build.c++.modules\", true)\n    --     add_files(\"src/main.cpp\")\n\n    target(\"llvm-msvc\")\n        set_kind(\"binary\")\n        set_toolchains(\"clang\")\n        set_policy(\"build.c++.modules\", true)\n        add_files(\"src/main.cpp\")\n\n    target(\"msvc\")\n        set_kind(\"binary\")\n        set_toolchains(\"msvc\")\n        set_policy(\"build.c++.modules\", true)\n        add_files(\"src/main.cpp\")\nelse\n    target(\"llvm\")\n        set_kind(\"binary\")\n        set_toolchains(\"clang\")\n        set_runtimes(\"c++_shared\")\n        set_policy(\"build.c++.modules\", true)\n        add_files(\"src/main.cpp\")\n\n    target(\"gnu\")\n        set_kind(\"binary\")\n        set_toolchains(\"gcc\")\n        set_runtimes(\"stdc++_shared\")\n        set_policy(\"build.c++.modules\", true)\n        set_policy(\"build.c++.modules.gcc.cxx11abi\", true)\n        add_files(\"src/main.cpp\")\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/src/hello.mpp",
    "content": "export module hello;\n\nexport namespace hello {\n    extern int data__;\n    void say_hello();\n\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\nimport mod;\n\nvoid inner() {\n    std::cout << \"hello world! data: \" << mod::foo() << std::endl;\n}\n\nnamespace hello {\nint  data__;\nvoid say_hello() {\n    ::inner();\n}\n\nsay::say(int data) : data_{ data } {\n}\n\nvoid say::hello() {\n    hello::data__ = data_;\n    ::inner();\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::data__ = 123;\n    hello::say_hello();\n    hello::say(sizeof(hello::say)).hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/src/mod.mpp",
    "content": "export module mod;\n\nexport namespace mod {\n    int foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/src/mod_impl.cpp",
    "content": "module mod;\nimport hello;\n\nnamespace mod {\nint foo() {\n    return hello::data__;\n}\n} // namespace mod\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\nnamespace(\"foo\", function()\n    target(\"dep\")\n        set_kind(\"static\")\n        add_files(\"src/hello.mpp\", \"src/mod.mpp\", {public = true})\n        add_files(\"src/hello_impl.cpp\", \"src/mod_impl.cpp\")\n\n    target(\"binary\")\n        set_kind(\"binary\")\n        add_files(\"src/main.cpp\")\n        add_deps(\"dep\")\nend)\n\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/src/hello.mpp",
    "content": "export module hello;\n\nexport namespace hello {\n    extern int data__;\n    void say_hello();\n\n    class say {\n    public:\n        say(int data);\n        void hello();\n    private:\n        int data_;\n    };\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/src/hello_impl.cpp",
    "content": "module;\n#include <iostream>\n\nmodule hello;\nimport mod;\n\nvoid inner() {\n    std::cout << \"hello world! data: \" << mod::foo() << std::endl;\n}\n\nnamespace hello {\nint  data__;\nvoid say_hello() {\n    ::inner();\n}\n\nsay::say(int data) : data_{ data } {\n}\n\nvoid say::hello() {\n    hello::data__ = data_;\n    ::inner();\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::data__ = 123;\n    hello::say_hello();\n    hello::say(sizeof(hello::say)).hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/src/mod.mpp",
    "content": "export module mod;\n\nexport namespace mod {\n    int foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/src/mod_impl.cpp",
    "content": "module mod;\nimport hello;\n\nnamespace mod {\nint foo() {\n    return hello::data__;\n}\n} // namespace mod\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/namespace2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\nnamespace(\"bar\", function()\n    target(\"dep\")\n        set_kind(\"static\")\n        add_files(\"src/hello.mpp\", \"src/mod.mpp\", {public = true})\n        add_files(\"src/hello_impl.cpp\", \"src/mod_impl.cpp\")\nend)\n\nnamespace(\"foo\", function()\n    target(\"binary\")\n        set_kind(\"binary\")\n        add_files(\"src/main.cpp\")\n        add_deps(\"bar::dep\")\nend)\n\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.cpp",
    "content": "#include <a.hpp>\n\nconst char *hello() {\n    return \"Hello world\";\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.mpp",
    "content": "module;\n\n#include <a.hpp>\n\nexport module bar;\n\nexport namespace bar {\nconst char *hello() {\n     return ::hello();\n}\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/include/a.hpp",
    "content": "#ifndef A_HPP\n#define A_HPP\n\n[[gnu::visibility(\"default\")]] const char *hello();\n\n#endif\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"bar\")\n    set_kind(\"static\")\n    add_headerfiles(\"include/(**.hpp)\")\n    add_includedirs(\"include\")\n    add_files(\"*.cpp\")\n    add_files(\"*.mpp\", { public = true })\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar/xmake.lua",
    "content": "package(\"bar\")\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/bar.mpp",
    "content": "export module bar2;\n\nexport namespace bar {\n    const char *hello2() {\n        return \"Hello world\";\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"bar2\")\n    set_kind(\"moduleonly\")\n    add_files(\"*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/b/bar2/xmake.lua",
    "content": "package(\"bar2\")\n    set_kind(\"library\", {moduleonly = true})\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.cpp",
    "content": "module foo;\n\nnamespace foo {\nvoid say(const char *msg) {\n}\n} // namespace foo\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.mpp",
    "content": "export module foo;\n\nexport namespace foo {\n  #ifdef FOO_EXPORT\n    void say(const char *);\n  #endif\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"*.cpp\")\n    add_files(\"*.mpp\", {defines = \"FOO_EXPORT\", public = true})\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/my-repo/packages/f/foo/xmake.lua",
    "content": "package(\"foo\")\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)"
  },
  {
    "path": "tests/projects/c++/modules/packages/src/main.cpp",
    "content": "import foo;\nimport bar;\nimport bar2;\n\nint main() {\n    foo::say(bar::hello());\n    foo::say(bar::hello2());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/packages/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\nadd_repositories(\"my-repo my-repo\")\nadd_requires(\"foo\", \"bar\", \"bar2\")\n\ntarget(\"packages\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"foo\", \"bar\", \"bar2\")\n    set_policy(\"build.c++.modules\", true)\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/bar.cpp",
    "content": "#include <a.hpp>\n\nconst char *hello() {\n    return \"Hello world\";\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/bar.mpp",
    "content": "module;\n\n#include <a.hpp>\n\nexport module bar;\n\nexport namespace bar {\nconst char *hello() {\n     return ::hello();\n}\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/include/a.hpp",
    "content": "#ifndef A_HPP\n#define A_HPP\n\n[[gnu::visibility(\"default\")]] const char *hello();\n\n#endif\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"bar\")\n    set_kind(\"static\")\n    add_headerfiles(\"include/(**.hpp)\")\n    add_includedirs(\"include\")\n    add_files(\"*.cpp\")\n    add_files(\"*.mpp\", { public = true })\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar/xmake.lua",
    "content": "package(\"bar\")\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/src/bar.mpp",
    "content": "export module bar2;\n\nexport namespace bar {\n    const char *hello2() {\n        return \"Hello world\";\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"bar2\")\n    set_kind(\"moduleonly\")\n    add_files(\"*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/b/bar2/xmake.lua",
    "content": "package(\"bar2\")\n    set_kind(\"library\", {moduleonly = true})\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/foo.cpp",
    "content": "module foo;\n\nnamespace foo {\nvoid say(const char *msg) {\n}\n} // namespace foo\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/foo.mpp",
    "content": "export module foo;\n\nexport namespace foo {\n  #ifdef FOO_EXPORT\n    void say(const char *);\n  #endif\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/src/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"*.cpp\")\n    add_files(\"*.mpp\", {defines = \"FOO_EXPORT\", public = true})\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/my-repo/packages/f/foo/xmake.lua",
    "content": "package(\"foo\")\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/src/main.cpp",
    "content": "import foobar;\nimport bar2;\n\nint main() {\n    foo::say(bar::hello());\n    foo::say(bar::hello2());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/src/mod.mpp",
    "content": "export module foobar;\n\nexport import foo;\nexport import bar;\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/packages-subtarget/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\nadd_repositories(\"my-repo my-repo\")\nadd_requires(\"foo\", \"bar\", \"bar2\")\n\ntarget(\"dep\")\n    set_kind(\"static\")\n    add_packages(\"foo\", \"bar\")\n    add_files(\"src/*.mpp\", {public = true})\n\ntarget(\"packages\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_deps(\"dep\")\n    add_packages(\"foo\", \"bar\", \"bar2\")\n    set_policy(\"build.c++.modules\", true)\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/src/main.cpp",
    "content": "#include <iostream>\n\nimport math;\n\nint main() {\n    std::cout << std::endl;\n\n    std::cout << \"add(3, 4): \" << add(3, 4) << std::endl;\n    std::cout << \"mul(3, 4): \" << mul(3, 4) << std::endl;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/src/math.math1.mpp",
    "content": "export module math:math1;\n\nexport int add(int fir, int sec) {\n    return fir + sec;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/src/math.math2.mpp",
    "content": "export module math:math2;\n\nexport {\n    int mul(int fir, int sec) {\n        return fir * sec;\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/src/math.mpp",
    "content": "export module math;\n\nexport import :math1;\nexport import :math2;\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/test.lua",
    "content": "inherit(\".test_partitions\")\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"partition\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/src/foo.cpp",
    "content": "// Foo.cpp\r\nmodule Foo;\r\n\r\n// Impl is implictly imported here\r\n\r\nvoid foo() {\r\n    bar();\r\n}\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/src/foo.mpp",
    "content": "// Foo.mpp\r\nexport module Foo;\r\n\r\nimport :Impl; // can't export import Impl because Impl is a implementation partition unit\r\n\r\nexport void foo();\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/src/foo_impl.mpp",
    "content": "module;\r\n#include <iostream>\r\n\r\n// Foo-Impl.mpp\r\n// can only be imported by module Foo, and visibility of bar is only public to module Foo\r\nmodule Foo:Impl;\r\n\r\nvoid bar() {\r\n    std::cout << \"Hello world\" << std::endl;\r\n}\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/src/main.cpp",
    "content": "import Foo;\r\n\r\nint main(int argc, char **argv) {\r\n    foo();\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/test.lua",
    "content": "inherit(\".test_partitions\")\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\r\nset_languages(\"c++20\")\r\n\r\ntarget(\"test\")\r\n    set_kind(\"binary\")\r\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit2/src/foo.mpp",
    "content": "// Foo.mpp\nexport module Foo;\n\nimport :Impl; // can't export import Impl because Impl is a implementation partition unit\n\nexport void foo() {\n    bar();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit2/src/foo_impl.mpp",
    "content": "module;\n#include <iostream>\n\n// Foo-Impl.mpp\n// can only be imported by module Foo, and visibility of bar is only public to module Foo\nmodule Foo:Impl;\n\nvoid bar() {\n    std::cout << \"Hello world\" << std::endl;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit2/src/main.cpp",
    "content": "import Foo;\r\n\r\nint main(int argc, char **argv) {\r\n    foo();\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit2/test.lua",
    "content": "inherit(\".test_partitions\")\n"
  },
  {
    "path": "tests/projects/c++/modules/partitions_implunit2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\r\nset_languages(\"c++20\")\r\n\r\ntarget(\"test\")\r\n    set_kind(\"binary\")\r\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\r\n"
  },
  {
    "path": "tests/projects/c++/modules/phony/src/hello.cpp",
    "content": "module;\n\n#include <iostream>\n\nmodule hello;\n\nusing namespace std;\n\nnamespace hello {\nsay::say(int data) : data_(data) {\n}\n\nvoid say::hello() {\n    cout << \"hello, say class: \" << data_ << endl;\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/phony/src/hello.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module hello;\n\nexport namespace hello {\n    class say {\n        public:\n            say(int data);\n            void hello();\n\n        private:\n            int data_;\n    };\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/phony/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say s(sizeof(hello::say));\n    s.hello();\n    return 0;\n}"
  },
  {
    "path": "tests/projects/c++/modules/phony/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/phony/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"test-phony\")\n    set_kind(\"phony\")\n    add_files(\"src/*.mpp\", {public = true})\n\ntarget(\"class\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_deps(\"test-phony\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/phony2/include/foo.h",
    "content": "inline int foo() {\n    return 5;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/phony2/src/hello.cpp",
    "content": "module;\n\n#include <iostream>\n\nmodule hello;\n\nusing namespace std;\n\nnamespace hello {\nsay::say(int data) : data_(data) {\n}\n\nvoid say::hello() {\n    cout << \"hello, say class: \" << data_ << endl;\n}\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/phony2/src/hello.mpp",
    "content": "module;\n\n#include <iostream>\n\nexport module hello;\n\nexport namespace hello {\n    class say {\n        public:\n            say(int data);\n            void hello();\n\n        private:\n            int data_;\n    };\n} // namespace hello\n"
  },
  {
    "path": "tests/projects/c++/modules/phony2/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say s(sizeof(hello::say));\n    s.hello();\n    return 0;\n}"
  },
  {
    "path": "tests/projects/c++/modules/phony2/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/phony2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_includedirs(\"include\")\n    add_files(\"src/*.mpp\", {public = true})\n\ntarget(\"test-phony\")\n    set_kind(\"phony\")\n    add_deps(\"test\")\n\ntarget(\"class\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_deps(\"test-phony\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/src/dep1.mpp",
    "content": "export module dep1;\n\nexport int m() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/src/dep2.mpp",
    "content": "export module dep2;\n\nimport dep1;\n\nexport int i() {\n    return m();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/src/use.cpp",
    "content": "module use;\n\nimport dep1;\nimport dep2;\n\nint lib() {\n    return m() + i();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/src/use.mpp",
    "content": "export module use;\n\nexport int lib();\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/private_module/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"private_module\")\n    add_rules(\"c++\")\n    set_kind(\"$(kind)\")\n    add_files(\"src/*.mpp\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib/src/main.cpp",
    "content": "#include <stdio.h>\nimport mod;\n\nint main() {\n    printf(\"%d\\n\", mod::foo());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib/src/mod.cpp",
    "content": "module mod;\n\nnamespace mod {\nint foo() {\n    return 2;\n}\n} // namespace mod\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib/src/mod.mpp",
    "content": "export module mod;\n\nexport namespace mod {\n    int foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"mod\")\n    set_kind(\"static\")\n    add_files(\"src/mod.mpp\", {public = true})\n    add_files(\"src/mod.cpp\")\n\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_deps(\"mod\")\n    add_files(\"src/main.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/src/bar.cpp",
    "content": "module bar;\n\nnamespace bar {\nint hello() {\n    return 2;\n}\n} // namespace bar\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/src/bar.mpp",
    "content": "export module bar;\n\nexport namespace bar {\n    int hello();\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/src/foo.cpp",
    "content": "module foo;\n\nimport bar;\n\nnamespace foo {\nint hello() {\n    return bar::hello();\n}\n} // namespace foo\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/src/foo.mpp",
    "content": "export module foo;\n\nexport namespace foo {\n    int hello();\n}\n\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/src/main.cpp",
    "content": "#include <stdio.h>\nimport foo;\n\nint main() {\n    printf(\"%d\\n\", foo::hello());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/staticlib2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"bar\")\n    set_kind(\"static\")\n    add_files(\"src/bar.mpp\", {public = true})\n    add_files(\"src/bar.cpp\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_deps(\"bar\")\n    add_files(\"src/foo.mpp\", {public = true})\n    add_files(\"src/foo.cpp\")\n\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules/src/my_module.cpp",
    "content": "module my_module;\n\nimport std;\n\nauto my_sum(std::size_t a, std::size_t b) -> std::size_t {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules/src/my_module.mpp",
    "content": "export module my_module;\n\nimport std;\n\nexport auto my_sum(std::size_t a, std::size_t b) -> std::size_t;\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules/test/test.cpp",
    "content": "import std;\n\nimport my_module;\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << my_sum(1, 1) << endl;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules/test.lua",
    "content": "inherit(\".test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++latest\")\n\ntarget(\"mod\")\n    set_kind(\"static\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/*.mpp\", {public = true})\n\ntarget(\"stdmodules\")\n    set_kind(\"binary\")\n    add_files(\"test/*.cpp\")\n    add_deps(\"mod\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_cpp_only/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_cpp_only/src/main.cpp",
    "content": "import std;\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_cpp_only/test.lua",
    "content": "inherit(\".test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_cpp_only/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_languages(\"c++latest\")\n\ntarget(\"stdmodules_cpp_only\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_policy(\"build.c++.modules\", true)\n\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/src/bar.mpp",
    "content": "export module bar;\n\nimport std;\n\nexport auto my_sum2(std::size_t a, std::size_t b) -> std::size_t;\n\n#if defined(__GNUC__) && !defined(__clang__)\ninline\n#else\nmodule :private;\n#endif\n    auto my_sum2(std::size_t a, std::size_t b) -> std::size_t {\n  return a + a + b + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/src/foo.cpp",
    "content": "module foo;\n\nauto my_sum(std::size_t a, std::size_t b) -> std::size_t {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/src/foo.mpp",
    "content": "export module foo;\n\nimport std;\n\nexport auto my_sum(std::size_t a, std::size_t b) -> std::size_t;\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/src/main.cpp",
    "content": "import foo;\nimport bar;\n\nimport std;\n\nint main() {\n    std::cout << my_sum(1, 2) << \":\" << my_sum2(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/test.lua",
    "content": "inherit(\".test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_deps/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++latest\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n    add_files(\"src/foo.mpp\", {public = true})\n\ntarget(\"bar\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/bar.mpp\")\n\ntarget(\"main\")\n    set_kind(\"binary\")\n    add_deps(\"foo\", \"bar\")\n    add_files(\"src/main.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_multiple_targets/src/my_module.cpp",
    "content": "module my_module;\n\nimport std;\n\nauto my_sum(std::size_t a, std::size_t b) -> std::size_t {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_multiple_targets/src/my_module.mpp",
    "content": "export module my_module;\n\nimport std;\n\nexport auto my_sum(std::size_t a, std::size_t b) -> std::size_t;\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_multiple_targets/test.lua",
    "content": "inherit(\".test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stdmodules_multiple_targets/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++latest\")\n\ntarget(\"mod\")\n    set_kind(\"static\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\ntarget(\"mod2\")\n    set_kind(\"static\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit/src/hello.mpp",
    "content": "module;\n\nexport module hello;\n\nimport <iostream>;\n\nexport namespace hello {\n    void say(const char* str) {\n        std::cout << str << std::endl;\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit/src/main.cpp",
    "content": "import hello;\n\nint main() {\n    hello::say(\"hello module!\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"stl_headerunit\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit_cpp_only/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit_cpp_only/src/main.cpp",
    "content": "import <iostream>;\nimport <algorithm>;\nimport <deque>;\nimport <iostream>;\nimport <map>;\nimport <memory>;\nimport <set>;\nimport <utility>;\nimport <vector>;\nimport <string>;\nimport <queue>;\nimport <cstdlib>;\nimport <utility>;\nimport <exception>;\nimport <list>;\nimport <stack>;\nimport <complex>;\nimport <fstream>;\nimport <cstdio>;\nimport <iomanip>;\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit_cpp_only/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/stl_headerunit_cpp_only/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"stl_headerunit_cpp_only\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_policy(\"build.c++.modules\", true)\n\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/src/main.cpp",
    "content": "#include <iostream>\nimport math;\n\nint main() {\n    std::cout << std::endl;\n\n    std::cout << \"add(3, 4): \" << add(3, 4) << std::endl;\n    std::cout << \"mul(3, 4): \" << mul(3, 4) << std::endl;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/src/math.math1.mpp",
    "content": "export module math.math1;\n\nexport int add(int fir, int sec) {\n    return fir + sec;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/src/math.math2.mpp",
    "content": "export module math.math2;\n\nexport {\n    int mul(int fir, int sec) {\n        return fir * sec;\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/src/math.mpp",
    "content": "export module math;\n\nexport import math.math1;\nexport import math.math2;\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"submodule\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/main.cpp",
    "content": "import main_module;\n\nint main(int argc, char **argv) {\n    hello();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/main_module.mpp",
    "content": "export module main_module;\n\nimport main_module.module1;\nimport main_module.module2;\n\nexport void hello() {\n    hello1();\n    hello2();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/module1.cpp",
    "content": "module;\n#include <stdio.h>\n\nmodule main_module.module1;\n\nvoid hello1(void) {\n    printf(\"hello1\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/module1.mpp",
    "content": "export module main_module.module1;\n\nexport void hello1(void);\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/module2.cpp",
    "content": "module;\n#include <stdio.h>\n\nmodule main_module.module2;\n\nvoid hello2(void) {\n    printf(\"hello2\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/src/module2.mpp",
    "content": "export module main_module.module2;\n\nexport void hello2(void);\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/test.lua",
    "content": "inherit(\".test_base\")\n"
  },
  {
    "path": "tests/projects/c++/modules/submodules2/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"submodules2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/test_base.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"core.tool.toolchain\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nCLANG_CL_MIN_VER = \"19\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction _build(check_outdata)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    if check_outdata then\n        local outdata\n        outdata = os.iorun(\"xmake -r \" ..  flags)\n        if outdata then\n            if outdata:find(check_outdata.str, 1, true) then\n                raise(check_outdata.format_string .. \"\\n%s\", outdata)\n            end\n        end\n    else\n        os.run(\"xmake -r \" .. flags)\n    end\n    local outdata = os.iorun(\"xmake \" .. flags)\n    if outdata then\n        if outdata:find(\"compiling\", 1, true) or outdata:find(\"linking\", 1, true) or outdata:find(\"generating\", 1, true) then\n            raise(\"Modules incremental compilation does not work\\n%s\", outdata)\n        end\n    end\nend\n\nfunction can_build()\n    if is_subhost(\"windows\") then\n        return true\n    elseif is_subhost(\"msys\") then\n        return true\n    elseif is_host(\"linux\") then\n        local gcc = find_tool(\"gcc\", {version = true})\n        if gcc and gcc.version and semver.compare(gcc.version, GCC_MIN_VER) >= 0 then\n            return true\n        end\n        local clang = find_tool(\"clang\", {version = true})\n        if clang and clang.version and semver.compare(clang.version, CLANG_MIN_VER) >= 0 then\n            return true\n        end\n    end\nend\n\nfunction build_tests(toolchain_name, opt)\n    assert(opt and opt.version)\n    local version\n    if is_subhost(\"windows\") then\n        local msvc = toolchain.load(\"msvc\")\n        if not msvc or not msvc:check() then\n            wprint(\"msvc not found, skipping tests\")\n            return\n        end\n        local vcvars = msvc:config(\"vcvars\")\n        if not vcvars or not vcvars.VCInstallDir or not vcvars.VCToolsVersion then\n            wprint(\"msvc not found, skipping tests\")\n            return\n        end\n        version = vcvars.VCToolsVersion\n    end\n    if opt.compiler then\n        local cc = find_tool(opt.compiler, {version = true})\n        if not cc then\n            wprint(opt.compiler .. \" not found, skipping tests\")\n            return\n        end\n        version = cc.version\n    end\n\n    local compiler = toolchain_name == \"msvc\" and \"cl\" or opt.compiler\n    if not version or not (semver.compare(version, opt.version) >= 0) then\n        local version_str = compiler ..  \" >= \" .. opt.version .. (version and \" (found \" .. version .. \")\" or \"\") .. \" \"\n        wprint(version_str .. \"not found, skipping tests\")\n        return\n    end\n\n    local two_phases = (opt.two_phases == nil or opt.two_phases == true)\n    local policies = \"--policies=build.c++.modules.std:\" .. (opt.stdmodule and \"y\" or \"n\")\n    policies = policies .. \",build.c++.modules.fallbackscanner:\" .. (opt.fallbackscanner and \"y\" or \"n\")\n    policies = policies .. \",build.c++.modules.two_phases:\" .. (two_phases and \"y\" or \"n\")\n\n    local platform = \" \"\n    if opt.platform then\n        platform = \" -p \"  .. opt.platform .. \" \"\n    end\n\n    local runtimes = \" \"\n    if opt.runtimes then\n        runtimes = \" --runtimes=\" .. opt.runtimes .. \" \"\n    end\n    print(\"running with config: (toolchain: %s, compiler: %s, version: %s, runtimes: %s, stdmodule: %s, fallback scanner: %s, two phases: %s)\",\n        toolchain_name, compiler, version, opt.runtimes or \"default\", opt.stdmodule or false, opt.fallbackscanner or false, two_phases)\n\n    local flags = \"\"\n    if opt.flags then\n        flags = \" \" .. table.concat(opt.flags, \" \")\n    end\n    if ci_is_running() then\n        flags = flags .. \" -vD\"\n    end\n\n    os.exec(\"xmake clean -a\")\n    os.exec(\"xmake f\" .. platform .. \"--toolchain=\" .. toolchain_name .. runtimes .. \"-c --yes \" .. policies .. flags)\n    if opt.build then\n        opt.build()\n    else\n        _build(opt.check_outdata)\n    end\n    if opt.after_build then\n        opt.after_build(platform, toolchain_name, runtimes, policies, flags)\n    end\nend\n\nfunction run_tests(clang_options, gcc_options, msvc_options)\n    local clang_libcpp_options\n    if clang_options then\n        clang_libcpp_options = table.clone(clang_options)\n        clang_libcpp_options.runtimes = \"c++_shared\"\n    end\n    if is_subhost(\"windows\") then\n        if clang_options then\n            build_tests(\"llvm\", clang_options)\n            build_tests(\"clang\", clang_options)\n            build_tests(\"clang\", table.join(clang_options, {two_phases = false}))\n            if not clang_options.disable_clang_cl then\n                local clang_cl_options = table.clone(clang_options)\n                clang_cl_options.compiler = \"clang-cl\"\n                clang_cl_options.version = CLANG_CL_MIN_VER\n                build_tests(\"clang-cl\", clang_cl_options)\n                build_tests(\"clang-cl\", table.join(clang_options, {two_phases = false}))\n            end\n            if clang_options.stdmodule then\n                wprint(\"std modules tests skipped for Windows clang libc++ as it's not currently supported officially\")\n            else\n                build_tests(\"llvm\", clang_libcpp_options)\n                build_tests(\"clang\", clang_libcpp_options)\n                build_tests(\"clang\", table.join(clang_libcpp_options, {two_phases = false}))\n            end\n        end\n        if msvc_options then\n            build_tests(\"msvc\", msvc_options)\n            build_tests(\"msvc\", table.join(msvc_options, {two_phases = false}))\n        end\n    elseif is_subhost(\"macosx\") then\n        if clang_options then\n            -- macOS doesn't ship clang-scan-deps currently\n            if is_subhost(\"macosx\") then\n                -- check if normal clang is avalaible\n                local regular_clang_available = false\n\n                local outdata = os.iorun(\"clang --version\")\n                if outdata then\n                    regular_clang_available = true\n                    if outdata:find(\"Apple\") then\n                        regular_clang_available = false\n                    end\n                end\n                if not regular_clang_available then\n                    wprint(\"Appleclang isn't shipped with clang-scan-deps, disabling modules tests\")\n                    return\n                end\n            end\n            build_tests(\"llvm\", clang_options)\n            build_tests(\"clang\", clang_options)\n            build_tests(\"clang\", table.join(clang_options, {two_phases = false}))\n        end\n    elseif is_subhost(\"msys\") then\n        if clang_options then\n            clang_options.platform = \"mingw\"\n            clang_libcpp_options.platform = \"mingw\"\n            build_tests(\"llvm\", clang_options)\n            build_tests(\"clang\", clang_options)\n            build_tests(\"clang\", table.join(clang_options, {two_phases = false}))\n            build_tests(\"llvm\", clang_libcpp_options)\n            build_tests(\"clang\", clang_libcpp_options)\n            build_tests(\"clang\", table.join(clang_libcpp_options, {two_phases = false}))\n        end\n        if gcc_options then\n            gcc_options.platform = \"mingw\"\n            build_tests(\"gcc\", gcc_options)\n            build_tests(\"gcc\", table.join(gcc_options, {two_phases = false}))\n        end\n    elseif is_host(\"linux\") then\n        if clang_options then\n            build_tests(\"llvm\", clang_options)\n            build_tests(\"clang\", clang_options)\n            build_tests(\"clang\", table.join(clang_options, {two_phases = false}))\n            build_tests(\"llvm\", clang_libcpp_options)\n            build_tests(\"clang\", clang_libcpp_options)\n            build_tests(\"clang\", table.join(clang_libcpp_options, {two_phases = false}))\n        end\n        if gcc_options then\n            build_tests(\"gcc\", gcc_options)\n            build_tests(\"gcc\", table.join(gcc_options, {two_phases = false}))\n        end\n    end\nend\n\nfunction main(_)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER}\n    local msvc_options = {version = MSVC_MIN_VER}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_cmake.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"core.tool.toolchain\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nfunction _gen_cmakelist()\n    if not os.isfile(\"CMakeLists.txt\") then\n        os.vrunv(\"xmake project -k cmake\")\n    end\nend\n\nfunction _build(name, opt)\n    opt = opt or {}\n    local build_args = {}\n    if ci_is_running() then\n        table.insert(build_args, \"-vD\")\n    end\n    os.rm(\".xmake\", \"build\")\n    os.mv(\"xmake.lua\", \"xmake.lua_\")\n    os.vrunv(\"xmake\", table.join({\"f\", \"--trybuild=cmake\", \"--toolchain=\" .. name}, build_args), {shell = true, envs = opt.envs})\n    os.vrunv(\"xmake\", table.join({\"b\"}, build_args), {shell = true, envs = opt.envs})\n    os.mv(\"xmake.lua_\", \"xmake.lua\")\nend\n\nfunction _build_with(name, minver)\n    if name == \"msvc\" then\n        local _toolchain = toolchain.load(name, {plat = os.host(), arch = os.arch()})\n        if _toolchain and _toolchain:check() then\n            local vcvars = _toolchain:config(\"vcvars\")\n            if vcvars and vcvars.VCToolsVersion and semver.compare(vcvars.VCToolsVersion, minver) >= 0 then\n                _build(name, {envs = vcvars})\n            end\n        end\n    else\n        local tool = find_tool(name, {version = true})\n        if tool and tool.version and semver.compare(tool.version, minver) >= 0 then\n            local _toolchain = toolchain.load(name, {plat = os.host(), arch = os.arch()})\n            if _toolchain and _toolchain:check() then\n                _build(name)\n            end\n        end\n    end\nend\n\nfunction main(t)\n    os.setenv(\"CMAKE_GENERATOR\", \"Ninja\")\n\n    local cmake = find_tool(\"cmake\", {version = true})\n    local ninja = find_tool(\"ninja\")\n    if ninja and cmake and cmake.version and semver.compare(cmake.version, \"3.28\") >= 0 then\n        _gen_cmakelist()\n        if is_subhost(\"windows\") then\n            _build_with(\"clang\", \"19\")\n            _build_with(\"msvc\", \"14.35\")\n        elseif is_subhost(\"linux\") then\n            _build_with(\"gcc\", \"14\")\n            _build_with(\"clang\", \"19\")\n        elseif is_subhost(\"macosx\") then\n            -- macOS doesn't ship clang-scan-deps currently\n            -- check if normal clang is avalaible\n            local regular_clang_available = false\n\n            local outdata = os.iorun(\"clang --version\")\n            if outdata then\n                regular_clang_available = true\n                if outdata:find(\"Apple\") then\n                    regular_clang_available = false\n                end\n            end\n            if not regular_clang_available then\n                wprint(\"Appleclang isn't shipped with clang-scan-deps, disabling modules tests\")\n                return\n            end\n            _build_with(\"clang\", \"19\")\n        end\n            \n    end\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_culling.lua",
    "content": "inherit(\"test_base\")\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction main(_)\n    local check_outdata = {str = \"culled\", format_string = \"Modules culling does not work\"}\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, check_outdata = check_outdata}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, check_outdata = check_outdata}\n    local msvc_options = {version = MSVC_MIN_VER, check_outdata = check_outdata}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_dependency_scanner.lua",
    "content": "inherit(\"test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction _build(platform, toolchain_name, runtimes, policies, flags)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    os.exec(\"xmake f\" .. platform .. \"--toolchain=\" .. toolchain_name .. runtimes .. \"-c --yes \" .. policies .. \" --foo=n\" .. \" \" .. flags)\n    local outdata\n    outdata = os.iorun(\"xmake -r \" .. flags)\n    if outdata then\n        if outdata:find(\"FOO\") then\n            raise(\"Modules dependency scanner update does not work\\n%s\", outdata)\n        end\n    end\nend\n\nfunction main(t)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, flags = {\"--foo=y\"}, after_build = _build}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, flags = {\"--foo=y\"}, after_build = _build}\n    local msvc_options = {version = MSVC_MIN_VER, flags = {\"--foo=y\"}, after_build = _build}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_duplicate_modules.lua",
    "content": "inherit(\"test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction _build()\n    local flags = \"\"\n    if ci_is_running() then\n     flags = \"-vD\"\n    end\n    try {\n        function ()\n            os.run(\"xmake -r \" .. flags)\n        end,\n        catch {\n            function (errors)\n                errors = tostring(errors)\n                if not errors:find(\"duplicate module name detected\", 1, true) then\n                    raise(\"Modules duplicate name detection does not work\\n%s\", errors)\n                end\n            end\n        }\n    }\nend\n\nfunction main(_)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, build = _build}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, build = _build}\n    local msvc_options = {version = MSVC_MIN_VER, build = _build}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_headerunits.lua",
    "content": "inherit(\"test_base\")\n\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.30\"\n\nfunction main(t)\n    local gcc_options = {fallbackscanner = true, compiler = \"gcc\", version = GCC_MIN_VER}\n    -- gcc/arm64: internal compiler error: in core_vals, at cp/module.cc:6108\n    -- on windows, mingw modulemapper doesn't handle headeunit path correctly, but it's working with mingw on macOS / Linux\n    if os.arch() == \"arm64\" or is_subhost(\"msys\") then\n        gcc_options = nil\n    end\n    local msvc_options = {version = MSVC_MIN_VER}\n    -- skip clang tests, headerunits with clang is not stable\n    run_tests(nil, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_partitions.lua",
    "content": "inherit(\"test_base\")\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"18\"\nGCC_MIN_VER = \"13\"\nMSVC_MIN_VER = \"14.30\"\n\nfunction main(_)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER}\n    local msvc_options = {version = MSVC_MIN_VER}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_stdmodules.lua",
    "content": "inherit(\"test_base\")\n\nCLANG_MIN_VER = \"19\"\nGCC_MIN_VER = \"15\"\nMSVC_MIN_VER = \"14.35\"\n\nfunction main(_)\n    local clang_options = {stdmodule = true, compiler = \"clang\", version = CLANG_MIN_VER}\n    local gcc_options = {stdmodule = true, compiler = \"gcc\", version = GCC_MIN_VER}\n    -- latest mingw gcc 15.1 is broken\n    --  error: F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:105:3: error: 'int std::__glibcxx_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)'\n    --   105 |   __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,\n    --       |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    -- In file included from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr-default.h:35,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr.h:157,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/ext/atomicity.h:37,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/bits/ios_base.h:41,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/streambuf:45,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/bits/streambuf_iterator.h:37,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/iterator:68,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/stdc++.h:56:\n    -- F:/msys64/mingw64/include/pthread.h:296:28: note: 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' declared with internal linkage\n    --   296 | WINPTHREAD_RWLOCK_DECL int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts)\n    --       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~\n    -- F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:115:3: error: 'int std::__glibcxx_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)'\n    --   115 |   __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,   local gcc_options = {stdmodule = true, compiler = \"gcc\", version = GCC_MIN_VER}\n    if is_subhost(\"msys\") then\n        gcc_options = nil\n    end\n    local msvc_options = {stdmodule = true, version = MSVC_MIN_VER}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_xmake_test.lua",
    "content": "inherit(\"test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = is_subhost(\"windows\") and \"19\" or \"17\"\nGCC_MIN_VER = \"11\"\nMSVC_MIN_VER = \"14.29\"\n\nfunction run_xmake_test(...)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    local outdata, errdata = os.iorun(\"xmake test \" .. flags)\n    assert(outdata, errdata)\nend\n\nfunction main(t)\n    local clang_options = {compiler = \"clang\", version = CLANG_MIN_VER, after_build = run_xmake_test}\n    local gcc_options = {compiler = \"gcc\", version = GCC_MIN_VER, after_build = run_xmake_test}\n    local msvc_options = {version = MSVC_MIN_VER, after_build = run_xmake_test}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/test_xmake_test_stdmodules.lua",
    "content": "inherit(\"test_base\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nCLANG_MIN_VER = \"19\"\nGCC_MIN_VER = \"15\"\nMSVC_MIN_VER = \"14.35\"\n\nfunction run_xmake_test(...)\n    local flags = \"\"\n    if ci_is_running() then\n        flags = \"-vD\"\n    end\n    local outdata, errdata = os.iorun(\"xmake test \" .. flags)\n    assert(outdata, errdata)\nend\n\nfunction main(_)\n    local clang_options = {stdmodule = true, compiler = \"clang\", version = CLANG_MIN_VER, after_build = run_xmake_test}\n    local gcc_options = {stdmodule = true, compiler = \"gcc\", version = GCC_MIN_VER, after_build = run_xmake_test}\n    -- latest mingw gcc 15.1 is broken\n    --  error: F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:105:3: error: 'int std::__glibcxx_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)'\n    --   105 |   __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,\n    --       |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    -- In file included from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr-default.h:35,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/gthr.h:157,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/ext/atomicity.h:37,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/bits/ios_base.h:41,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/streambuf:45,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/bits/streambuf_iterator.h:37,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/iterator:68,\n    --                  from F:/msys64/mingw64/include/c++/15.1.0/x86_64-w64-mingw32/bits/stdc++.h:56:\n    -- F:/msys64/mingw64/include/pthread.h:296:28: note: 'int pthread_rwlock_timedrdlock(pthread_rwlock_t*, const timespec*)' declared with internal linkage\n    --   296 | WINPTHREAD_RWLOCK_DECL int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts)\n    --       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~\n    -- F:/msys64/mingw64/include/c++/15.1.0/shared_mutex:115:3: error: 'int std::__glibcxx_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)' exposes TU-local entity 'int pthread_rwlock_timedwrlock(pthread_rwlock_t*, const timespec*)'\n    --   115 |   __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,   local gcc_options = {stdmodule = true, compiler = \"gcc\", version = GCC_MIN_VER}\n    if is_subhost(\"msys\") then\n        gcc_options = nil\n    end\n    local msvc_options = {stdmodule = true, version = MSVC_MIN_VER}\n    run_tests(clang_options, gcc_options, msvc_options)\nend\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit/src/header.hpp",
    "content": "#pragma once\n\nnamespace hello {\n    inline constexpr auto FOO = \"Hello\";\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit/src/hello.mpp",
    "content": "module;\n#include <cstdio>\n\nexport module hello;\n\nimport \"header.hpp\";\n\nexport namespace hello {\n    void say(const char *arg) {\n        printf(\"%s: %s\\n\", FOO, arg);\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit/src/main.cpp",
    "content": "import hello;\nimport \"header.hpp\";\n\nint main() {\n    hello::say(hello::FOO);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nset_languages(\"c++20\")\n\ntarget(\"user_headerunit\")\n    set_kind(\"binary\")\n    add_headerfiles(\"src/*.hpp\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/a/a.mpp",
    "content": "export module A;\r\nimport \"c.hpp\";\r\nimport \"d.hpp\";\r\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/a/c.hpp",
    "content": "﻿#pragma once"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/a/d.hpp",
    "content": "﻿#pragma once"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/a/xmake.lua",
    "content": "﻿target(\"a\")\r\n    set_kind(\"moduleonly\")\r\n    add_headerfiles(\"*.hpp\")\r\n    add_files(\"a.mpp\")\r\n    set_languages(\"cxxlatest\")\r\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/b/b.mpp",
    "content": "﻿export module B;\r\nimport A;\r\nimport \"../a/c.hpp\";"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/b/xmake.lua",
    "content": "﻿target(\"b\")\r\n    add_deps(\"a\")\r\n    set_kind(\"moduleonly\")\r\n    add_files(\"b.mpp\")\r\n    set_languages(\"cxxlatest\")\r\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/test.lua",
    "content": "inherit(\".test_headerunits\")\n"
  },
  {
    "path": "tests/projects/c++/modules/user_headerunit2/xmake.lua",
    "content": "﻿includes(\"a\", \"b\")\r\ntarget(\"test\")\r\n    add_deps(\"a\", \"b\")\r\n    set_kind(\"phony\")\r\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests1/src/foo.cppm",
    "content": "export module Foo;\n\nexport inline int foo() { return 0; }\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests1/src/main.cpp",
    "content": "import Foo;\n\nint main() {\n    return foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests1/test.lua",
    "content": "inherit(\".test_xmake_test\")\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests1/xmake.lua",
    "content": "add_rules('mode.debug', 'mode.release')\n\nset_languages('c++23')\nset_policy('build.c++.modules.std', false)\n\ntarget('module_dep')\n    set_kind('moduleonly')\n    add_files('src/*.cppm')\n\ntarget('module_target')\n    set_kind('moduleonly')\n    add_files('src/*.cppm')\n    add_deps('module_dep')\n    add_tests('test', { kind = 'binary', files = 'src/main.cpp', build_should_pass = true })\n    add_tests('test2', { kind = 'binary', files = 'src/main.cpp', build_should_pass = true })\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests2/src/foo.cppm",
    "content": "export module Foo;\n\nexport inline int foo() { return 0; }\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests2/src/main.cpp",
    "content": "import Foo;\n\nint main() {\n    return foo();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests2/test.lua",
    "content": "inherit(\".test_xmake_test\")\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests2/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++23\")\nset_policy(\"build.c++.modules.std\", false)\n\ntarget(\"module_dep\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.cppm\")\n\ntarget(\"module_target1\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.cppm\")\n    add_deps(\"module_dep\")\n    add_tests(\"tests\", {kind = \"binary\", files = \"src/main.cpp\", build_should_pass = true})\n\ntarget(\"module_target2\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.cppm\")\n    add_deps(\"module_dep\")\n    add_tests(\"tests\", {kind = \"binary\", files = \"src/main.cpp\", build_should_pass = true})\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests3/src/foo.cppm",
    "content": "export module Foo;\n\nimport std;\n\nexport void foo() {\n    std::printf(\"Hello from Foo\\n\");\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests3/src/main.cpp",
    "content": "import std;\nimport Foo;\n\nint main() {\n    foo();\n    std::printf(\"Hello from main\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests3/test.lua",
    "content": "inherit(\".test_xmake_test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests3/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++23\")\n\ntarget(\"module_dep\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.cppm\")\n\ntarget(\"module_target1\")\n    set_kind(\"moduleonly\")\n    add_files(\"src/*.cppm\")\n    add_deps(\"module_dep\")\n    add_tests(\"tests\", {kind = \"binary\", files = \"src/main.cpp\", build_should_pass = true, run_should_pass = true})\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/.gitignore",
    "content": ".xmake/\n.vscode/\nbuild/\nuselocalxmake.sh\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/src/main.cpp",
    "content": "import work;\n\nint main() {\n\tdo_work<int>();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/src/work.mpp",
    "content": "export module work;\nimport std;\n\nexport\ntemplate<typename T>\nvoid do_work() {\n    if constexpr (std::is_same_v<T, int>) {\n        std::println(\"Hello world!\");\n    } else if constexpr (std::is_same_v<T, double>) {\n        std::println(\"Hello test!\");\n    } else {\n        std::println(\"Hello unknown type!\");\n    }\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/test/test.cpp",
    "content": "import work;\n\nint main() {\n\tdo_work<double>();\n}\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/test.lua",
    "content": "inherit(\".test_xmake_test_stdmodules\")\n"
  },
  {
    "path": "tests/projects/c++/modules/xmake_tests4/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"c++23\")\n\ntarget(\"llvm\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.mpp\")\n    add_tests(\"test\", { files = \"test/test.cpp\", remove_files = \"src/main.cpp\" })\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/dpdk/src/add.cc",
    "content": "#include \"add.h\"\n\nint add(int x, int y) {\n    return x + y;\n}\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/dpdk/src/add.h",
    "content": "#pragma once\n\nint add(int x, int y);\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/dpdk/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"dpdk_add\")\n   set_kind(\"static\")\n   add_files(\"src/add.cc\")\n   add_headerfiles(\"src/*.h\")\n\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/spdk/src/mul.cc",
    "content": "#include \"mul.h\"\n#include \"add.h\"\n\nint mul(int x, int y) {\n    int result = 0;\n    for (int i = 0; i < y; i++) {\n        result = add(result, x);\n    }\n    return result;\n}\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/spdk/src/mul.h",
    "content": "#pragma once\n\nint mul(int x, int y);\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/3rd/spdk/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\npackage(\"dpdk\")\n    set_sourcedir(path.join(os.scriptdir(), \"../../3rd/dpdk\"))\n    on_install(\"linux\", function (package)\n        import(\"package.tools.xmake\").install(package)\n    end)\n    on_test(function (package)\n        assert(package:has_cxxincludes(\"add.h\"))\n    end)\npackage_end()\n\nadd_includedirs(\"src\")\n\nadd_requires(\"dpdk\")\n\ntarget(\"spdk_mul\")\n   set_kind(\"static\")\n   add_files(\"src/mul.cc\")\n   add_headerfiles(\"src/*.h\")\n   add_packages(\"dpdk\")\n\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/src/main.cc",
    "content": "#include <iostream>\n#include \"mul.h\"\n\n\nint main(int argc, char** argv) {\n    int s = mul(3, 4);\n    std::cout << \"hello world! \" << s << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/test.lua",
    "content": "function main(t)\n    if not is_host(\"linux\") then\n        return\n    end\n    t:build()\nend\n\n"
  },
  {
    "path": "tests/projects/c++/package_linkgroups/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\npackage(\"dpdk\")\n    set_sourcedir(path.join(os.scriptdir(), \"3rd/dpdk\"))\n    add_links(\"dpdk_add\")\n    add_linkgroups(\"dpdk_add\", {name = \"dpdk\", whole = true, group = true})\n    on_install(\"linux\", function (package)\n        import(\"package.tools.xmake\").install(package)\n    end)\n    on_test(function (package)\n        assert(package:has_cxxincludes(\"add.h\"))\n    end)\npackage_end()\n\npackage(\"spdk\")\n    set_sourcedir(path.join(os.scriptdir(), \"3rd/spdk\"))\n    add_deps(\"dpdk\")\n    add_links(\"spdk_mul\")\n    add_linkgroups(\"spdk_mul\", {name = \"dpdk\", whole = true, group = true})\n    on_install(\"linux\", function (package)\n        import(\"package.tools.xmake\").install(package)\n    end)\n    on_test(function (package)\n        assert(package:has_cxxincludes(\"mul.h\"))\n    end)\npackage_end()\n\nadd_requires(\"spdk\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.cc\")\n    add_packages(\"spdk\")\n    add_includedirs(\"src\")\n\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/header.h",
    "content": "// header.h\n#ifndef HEADER_H\n#define HEADER_H\n\n#include <algorithm>\n#include <deque>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <set>\n//#include <thread>\n#include <utility>\n#include <vector>\n#include <string>\n#include <queue>\n#include <cstdlib>\n#include <utility>\n#include <exception>\n#include <list>\n#include <stack>\n#include <complex>\n#include <fstream>\n#include <cstdio>\n#include <iomanip>\n\n#endif\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/header2.h",
    "content": ""
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/main.cpp",
    "content": "#include \"header.h\"\n\nint main(int argc, char **argv) {\n    std::string s(\"xmake\");\n    printf(\"hello %s!\\n\", s.c_str());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test.c",
    "content": "\nvoid test_c(void) {\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test2.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test2() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test4.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test4() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test5.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test5() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test6.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test6() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test7.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test7() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/src/test8.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test8() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/test3.cpp",
    "content": "\n#include \"src/header.h\"\n#include \"src/header2.h\"\n\nint test3() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"main\")\n    set_kind(\"binary\")\n    set_languages(\"cxx11\")\n    set_pcxxheader(\"src/header.h\")\n    add_files(\"src/*.cpp\", \"src/*.c\", \"*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/common.h",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/consumer.cpp",
    "content": "#include <iostream>\n\n// Declare the function from lib1\nint lib1_function();\n\nint main() {\n    std::cout << \"Consumer program without PCH\" << std::endl;\n    int result = lib1_function();\n    std::cout << \"lib1 result: \" << result << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/lib1.cpp",
    "content": "#include \"lib1_pch.h\"\n\nint lib1_function() {\n    std::vector<int> numbers = {1, 2, 3, 4, 5};\n    int sum = std::accumulate(numbers.begin(), numbers.end(), 0);\n    return sum;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/lib1_pch.h",
    "content": "#include <algorithm>\n#include <numeric>\n#include <vector>\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/lib2.cpp",
    "content": "#include \"lib2_pch.h\"\n\nint lib2_function() {\n    std::map<int, std::string> data = {{1, \"one\"}, {2, \"two\"}, {3, \"three\"}};\n    std::set<int> keys;\n    \n    for (const auto& pair : data) {\n        keys.insert(pair.first);\n    }\n    \n    return keys.size();\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/lib2_pch.h",
    "content": "#include <map>\n#include <set>\n#include <string>\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/main.cpp",
    "content": "#include \"common.h\"\n\nint lib1_function();\nint lib2_function();\n\nint main() {\n    std::cout << \"Main program started\" << std::endl;\n    \n    int result1 = lib1_function();\n    int result2 = lib2_function();\n    \n    std::cout << \"lib1 result: \" << result1 << std::endl;\n    std::cout << \"lib2 result: \" << result2 << std::endl;\n    \n    std::vector<int> vec = {result1, result2};\n    std::cout << \"Combined result: \" << vec[0] + vec[1] << std::endl;\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc",
    "content": "#pragma once\n\n#include <iostream>\n#include <string>\n#include <map>\n\n// PCH with .inc extension\n#define APP_NAME \"PCH Test\"\n#define VERSION \"1.0\"\n\ninline void hello_from_inc() {\n    std::cout << \"Hello from .inc PCH!\" << std::endl;\n}\n\ntemplate<typename K, typename V>\nclass INCMap {\nprivate:\n    std::map<K, V> data;\n    \npublic:\n    void insert(const K& key, const V& value) {\n        data[key] = value;\n    }\n    \n    V get(const K& key) const {\n        auto it = data.find(key);\n        return (it != data.end()) ? it->second : V();\n    }\n    \n    void print_info() const {\n        std::cout << APP_NAME << \" v\" << VERSION << std::endl;\n        std::cout << \"Map contains \" << data.size() << \" items\" << std::endl;\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl",
    "content": "#pragma once\n\n#include <iostream>\n#include <vector>\n#include <algorithm>\n\n// PCH with .inl extension\ninline void hello_from_inl() {\n    std::cout << \"Hello from .inl PCH!\" << std::endl;\n}\n\ntemplate<typename T>\nclass INLProcessor {\nprivate:\n    std::vector<T> items;\n    \npublic:\n    void add(const T& item) {\n        items.push_back(item);\n    }\n    \n    void sort() {\n        std::sort(items.begin(), items.end());\n    }\n    \n    T max() const {\n        if (items.empty()) return T();\n        return *std::max_element(items.begin(), items.end());\n    }\n    \n    T min() const {\n        if (items.empty()) return T();\n        return *std::min_element(items.begin(), items.end());\n    }\n    \n    void print() const {\n        for (const auto& item : items) {\n            std::cout << item << \" \";\n        }\n        std::cout << std::endl;\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp",
    "content": "#pragma once\n\n#include <iostream>\n#include <string>\n#include <vector>\n\n// PCH with .ipp extension\ninline void hello_from_ipp() {\n    std::cout << \"Hello from .ipp PCH!\" << std::endl;\n}\n\ntemplate<typename T>\nclass IPPContainer {\nprivate:\n    std::vector<T> data;\n    \npublic:\n    void add(const T& item) {\n        data.push_back(item);\n    }\n    \n    void print() const {\n        for (const auto& item : data) {\n            std::cout << item << \" \";\n        }\n        std::cout << std::endl;\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc",
    "content": "#pragma once\n\n#include <iostream>\n#include <list>\n#include <numeric>\n\n// PCH with .tcc extension\ninline void hello_from_tcc() {\n    std::cout << \"Hello from .tcc PCH!\" << std::endl;\n}\n\ntemplate<typename T>\nclass TCCCalculator {\nprivate:\n    std::list<T> values;\n    \npublic:\n    void add(const T& value) {\n        values.push_back(value);\n    }\n    \n    T sum() const {\n        return std::accumulate(values.begin(), values.end(), T(0));\n    }\n    \n    double average() const {\n        if (values.empty()) return 0.0;\n        return static_cast<double>(sum()) / values.size();\n    }\n    \n    void clear() {\n        values.clear();\n    }\n    \n    void print() const {\n        std::cout << \"Values: \";\n        for (const auto& value : values) {\n            std::cout << value << \" \";\n        }\n        std::cout << std::endl;\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl",
    "content": "#pragma once\n\n#include <iostream>\n#include <queue>\n#include <stack>\n\n// PCH with .tpl extension\ninline void hello_from_tpl() {\n    std::cout << \"Hello from .tpl PCH!\" << std::endl;\n}\n\ntemplate<typename T>\nclass TPLProcessor {\nprivate:\n    std::queue<T> input_queue;\n    std::stack<T> output_stack;\n    \npublic:\n    void enqueue(const T& item) {\n        input_queue.push(item);\n    }\n    \n    T dequeue() {\n        if (input_queue.empty()) return T();\n        T item = input_queue.front();\n        input_queue.pop();\n        return item;\n    }\n    \n    void push_to_stack(const T& item) {\n        output_stack.push(item);\n    }\n    \n    T pop_from_stack() {\n        if (output_stack.empty()) return T();\n        T item = output_stack.top();\n        output_stack.pop();\n        return item;\n    }\n    \n    void transfer_to_stack() {\n        while (!input_queue.empty()) {\n            push_to_stack(dequeue());\n        }\n    }\n    \n    void print_queue() const {\n        std::queue<T> temp = input_queue;\n        std::cout << \"Queue: \";\n        while (!temp.empty()) {\n            std::cout << temp.front() << \" \";\n            temp.pop();\n        }\n        std::cout << std::endl;\n    }\n    \n    void print_stack() const {\n        std::stack<T> temp = output_stack;\n        std::cout << \"Stack: \";\n        while (!temp.empty()) {\n            std::cout << temp.top() << \" \";\n            temp.pop();\n        }\n        std::cout << std::endl;\n    }\n};\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/simple.cpp",
    "content": "#include <iostream>\n#include <string>\n\nint main() {\n    std::string message = \"Simple program without PCH\";\n    std::cout << message << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp",
    "content": "#include \"pch_test.inc\"\n\nint main() {\n    hello_from_inc();\n    \n    INCMap<std::string, int> scores;\n    scores.insert(\"alice\", 95);\n    scores.insert(\"bob\", 87);\n    scores.insert(\"charlie\", 92);\n    \n    scores.print_info();\n    std::cout << \"Alice's score: \" << scores.get(\"alice\") << std::endl;\n    std::cout << \"Bob's score: \" << scores.get(\"bob\") << std::endl;\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp",
    "content": "#include \"pch_test.inl\"\n\nint main() {\n    hello_from_inl();\n    \n    INLProcessor<int> processor;\n    processor.add(42);\n    processor.add(17);\n    processor.add(89);\n    processor.add(3);\n    processor.add(56);\n    \n    std::cout << \"Original: \";\n    processor.print();\n    \n    processor.sort();\n    std::cout << \"Sorted:   \";\n    processor.print();\n    \n    std::cout << \"Min: \" << processor.min() << std::endl;\n    std::cout << \"Max: \" << processor.max() << std::endl;\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp",
    "content": "#include \"pch_test.ipp\"\n\nint main() {\n    hello_from_ipp();\n    \n    IPPContainer<int> container;\n    container.add(1);\n    container.add(2);\n    container.add(3);\n    \n    std::cout << \"Container contents: \";\n    container.print();\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp",
    "content": "#include \"pch_test.tcc\"\n\nint main() {\n    hello_from_tcc();\n    \n    TCCCalculator<double> calc;\n    calc.add(3.5);\n    calc.add(7.2);\n    calc.add(1.8);\n    calc.add(9.6);\n    calc.add(4.1);\n    \n    calc.print();\n    std::cout << \"Sum: \" << calc.sum() << std::endl;\n    std::cout << \"Average: \" << calc.average() << std::endl;\n    \n    // Test with integers\n    TCCCalculator<int> int_calc;\n    int_calc.add(10);\n    int_calc.add(20);\n    int_calc.add(30);\n    \n    int_calc.print();\n    std::cout << \"Sum: \" << int_calc.sum() << std::endl;\n    std::cout << \"Average: \" << int_calc.average() << std::endl;\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp",
    "content": "#include \"pch_test.tpl\"\n\nint main() {\n    hello_from_tpl();\n    \n    TPLProcessor<std::string> processor;\n    \n    // Add items to queue\n    processor.enqueue(\"first\");\n    processor.enqueue(\"second\");\n    processor.enqueue(\"third\");\n    \n    processor.print_queue();\n    \n    // Transfer to stack\n    processor.transfer_to_stack();\n    processor.print_queue();\n    processor.print_stack();\n    \n    // Pop from stack (LIFO order)\n    std::cout << \"Popping from stack:\" << std::endl;\n    while (true) {\n        std::string item = processor.pop_from_stack();\n        if (item.empty()) break;\n        std::cout << \"  \" << item << std::endl;\n    }\n    \n    // Test with integers\n    TPLProcessor<int> int_processor;\n    int_processor.enqueue(100);\n    int_processor.enqueue(200);\n    int_processor.enqueue(300);\n    \n    int_processor.transfer_to_stack();\n    std::cout << \"Integer stack pop:\" << std::endl;\n    while (true) {\n        int item = int_processor.pop_from_stack();\n        if (item == 0) break;\n        std::cout << \"  \" << item << std::endl;\n    }\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/tool.cpp",
    "content": "#include \"tool_pch.h\"\n\nint main() {\n    std::stringstream ss;\n    ss << \"Tool program output\";\n    \n    std::ofstream outfile(\"tool_output.txt\");\n    if (outfile.is_open()) {\n        outfile << ss.str() << std::endl;\n        outfile.close();\n    }\n    \n    std::cout << \"Tool completed successfully\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/src/tool_pch.h",
    "content": "#include <fstream>\n#include <sstream>\n#include <iostream>\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/precompiled_header_multiple_targets/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nset_languages(\"cxx11\")\n\n-- Target 1: main executable\ntarget(\"main\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/common.h\")\n    add_files(\"src/main.cpp\")\n    add_deps(\"lib1\", \"lib2\")\n\n-- Target 2: static library 1\ntarget(\"lib1\")\n    set_kind(\"static\")\n    set_pcxxheader(\"src/lib1_pch.h\")\n    add_files(\"src/lib1.cpp\")\n\n-- Target 3: static library 2\ntarget(\"lib2\")\n    set_kind(\"static\")\n    set_pcxxheader(\"src/lib2_pch.h\")\n    add_files(\"src/lib2.cpp\")\n\n-- Target 4: another executable with different PCH\ntarget(\"tool\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/tool_pch.h\")\n    add_files(\"src/tool.cpp\")\n\n-- Target 5: executable without PCH\ntarget(\"simple\")\n    set_kind(\"binary\")\n    add_files(\"src/simple.cpp\")\n\n-- Target 6: executable without PCH but depends on PCH library\ntarget(\"consumer\")\n    set_kind(\"binary\")\n    add_files(\"src/consumer.cpp\")\n    add_deps(\"lib1\")\n\n-- Target 7: PCH with .ipp extension\ntarget(\"test_ipp_pch\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/pch_test.ipp\")\n    add_files(\"src/test_ipp.cpp\")\n\n-- Target 8: PCH with .inc extension  \ntarget(\"test_inc_pch\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/pch_test.inc\")\n    add_files(\"src/test_inc.cpp\")\n\n-- Target 9: PCH with .inl extension\ntarget(\"test_inl_pch\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/pch_test.inl\")\n    add_files(\"src/test_inl.cpp\")\n\n-- Target 10: PCH with .tcc extension\ntarget(\"test_tcc_pch\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/pch_test.tcc\")\n    add_files(\"src/test_tcc.cpp\")\n\n-- Target 11: PCH with .tpl extension\ntarget(\"test_tpl_pch\")\n    set_kind(\"binary\")\n    set_pcxxheader(\"src/pch_test.tpl\")\n    add_files(\"src/test_tpl.cpp\")\n"
  },
  {
    "path": "tests/projects/c++/protobuf/src/main.cpp",
    "content": "#include <iostream>\n#include \"test.pb.h\"\n#include \"subdir/test2.pb.h\"\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf/src/subdir/test2.proto",
    "content": "syntax = \"proto3\";\npackage test2;\nmessage TestCase2 {\n    string name2 = 4;\n}\nmessage Test2 {\n    repeated TestCase2 case2 = 1;\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf/src/test.proto",
    "content": "syntax = \"proto3\";\nimport \"subdir/test2.proto\";\npackage test;\nmessage TestCase {\n    string name = 4;\n}\nmessage Test {\n    repeated TestCase case = 1;\n    repeated test2.TestCase2 case2 = 2;\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nlocal language = \"17\"\n\nadd_requires(\"protoc\", \"protobuf-cpp\")\n-- add_requireconfs(\"protoc.protobuf-cpp\", {override = true, version = \"1.0.0\"})\nadd_requireconfs(\"**.abseil\", {override = true, configs = {cxx_standard = language}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    set_languages(\"c++\" .. language)\n    add_rules(\"protobuf.cpp\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/**.proto\", {proto_rootdir = \"src\"})\n\n    add_packages(\"protoc\", \"protobuf-cpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/protobuf_grpc_cpp_plugin/src/main.cpp",
    "content": "#include <iostream>\n#include \"test.pb.h\"\n#include \"subdir/test2.pb.h\"\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf_grpc_cpp_plugin/src/subdir/test2.proto",
    "content": "syntax = \"proto3\";\npackage test2;\nmessage TestCase2 {\n    string name2 = 4;\n}\nmessage Test2 {\n    repeated TestCase2 case2 = 1;\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf_grpc_cpp_plugin/src/test.proto",
    "content": "syntax = \"proto3\";\nimport \"subdir/test2.proto\";\npackage test;\nmessage TestCase {\n    string name = 4;\n}\nmessage Test {\n    repeated TestCase case = 1;\n    repeated test2.TestCase2 case2 = 2;\n}\n\nmessage EchoRequest {\n    string data = 1;\n}\n\nmessage EchoResponse {\n    string data = 1;\n}\n\nservice EchoServer {\n  rpc Echo(EchoRequest) returns (EchoResponse);\n}\n"
  },
  {
    "path": "tests/projects/c++/protobuf_grpc_cpp_plugin/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"protobuf-cpp\")\nadd_requires(\"grpc\", {system = false})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    set_languages(\"c++17\")\n    add_packages(\"protobuf-cpp\")\n    add_packages(\"grpc\")\n    add_rules(\"protobuf.cpp\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/test.proto\", {proto_rootdir = \"src\", proto_grpc_cpp_plugin = true})\n    add_files(\"src/subdir/test2.proto\", {proto_rootdir = \"src\"})\n\n"
  },
  {
    "path": "tests/projects/c++/shared_library/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n__export int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c++/shared_library/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/src/bar.cpp",
    "content": "#include \"bar.h\"\n\nint bar::add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/src/bar.h",
    "content": "class bar {\n  public:\n    static int add(int a, int b);\n};\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint foo::add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/src/foo.h",
    "content": "class foo {\n  public:\n    static int add(int a, int b);\n};\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/src/main.cpp",
    "content": "#include \"foo.h\"\n#include \"bar.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"foo::add(1, 2) = \" << foo::add(1, 2) << std::endl;\n    std::cout << \"bar::add(1, 2) = \" << bar::add(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/shared_library_export_all/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n    add_rules(\"utils.symbols.export_all\", {export_classes = true})\n\ntarget(\"bar\")\n    set_kind(\"shared\")\n    add_files(\"src/bar.cpp\")\n    add_rules(\"utils.symbols.export_all\", {export_filter = function (symbol, opt)\n        local filepath = opt.sourcefile or opt.objectfile\n        if filepath and filepath:find(\"bar.cpp\", 1, true) and symbol:find(\"add\", 1, true) then\n            print(\"export: %s at %s\", symbol, filepath)\n            return true\n        end\n    end})\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\", \"bar\")\n    add_files(\"src/main.cpp\")\n\n\n\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n__export int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/shared_library_with_soname/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_version(\"1.0.1\", {soname = true})\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n    after_build(function (target)\n        print(target:soname())\n    end)\n\ntarget(\"tests\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/include/bar.hpp",
    "content": "#ifndef BAR_HPP\n#define BAR_HPP\n\n#include <string>\n\nstd::string foo();\n\n#endif\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/src/bar.cpp",
    "content": "#include <bar.hpp>\n\nstd::string foo() {\n    return \"bar\";\n}\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/src/xmake.lua",
    "content": "target(\"bar\")\n    set_kind(\"$(kind)\")\n    add_files(\"src/*.cpp\")\n    add_headerfiles(\"include/(**.hpp)\")\n    add_includedirs(\"include\")\n\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/my-repo/packages/b/bar/xmake.lua",
    "content": "package(\"bar\")\n    set_sourcedir(path.join(os.scriptdir(), \"src\"))\n\n    on_install(function(package)\n        import(\"package.tools.xmake\").install(package, {})\n    end)\n\n    on_test(function(package)\n         assert(package:check_cxxsnippets({test = [[\n             #include <iostream>\n             void test() {\n                 std::cout << _LIBCPP_VERSION << std::endl;\n             }\n         ]]}, {configs = {languages = \"c++17\"}}))\n    end)\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/src/main.cpp",
    "content": "#include <iostream>\n#include <bar.hpp>\n\nint main() {\n    std::cout << foo();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/test.lua",
    "content": "import(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\n\nfunction _build()\n    if ci_is_running() then\n        assert(os.iorun(\"xmake -rvD\"))\n    else\n        assert(os.iorun(\"xmake -r\"))\n    end\nend\n\nfunction main(t)\n    local clang = find_tool(\"clang\")\n    if clang and not is_subhost(\"windows\") and not is_subhost(\"bsd\", \"solaris\", \"haiku\") then\n        os.exec(\"xmake f --toolchain=clang --runtimes=c++_shared --yes\")\n        _build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/c++/snippet_runtimes/xmake.lua",
    "content": "add_repositories(\"my-repo my-repo\")\nadd_requires(\"bar\")\n\ntarget(\"foo\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"bar\")\n\n    on_config(function(target)\n         assert(target:check_cxxsnippets({test = [[\n             #include <iostream>\n             void test() {\n                 std::cout << _LIBCPP_VERSION << std::endl;\n             }\n         ]]}, {configs = {languages = \"c++17\"}}))\n    end)\n\n"
  },
  {
    "path": "tests/projects/c++/static_library/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/c++/static_library/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/c++/static_library/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << \"add(1, 2) = \" << add(1, 2) << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/static_library/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n\n"
  },
  {
    "path": "tests/projects/c++/test(brackets)/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/c++/test(brackets)/inc(brackets)/test.h",
    "content": "#define TEST \"hello\"\n"
  },
  {
    "path": "tests/projects/c++/test(brackets)/src/main.cpp",
    "content": "#include <iostream>\n#include \"test.h\"\n\nusing namespace std;\n\nint main(int argc, char **argv) {\n    cout << TEST \" \" WORD \"!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/test(brackets)/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/test(brackets)/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_includedirs(\"inc(brackets)\")\n    add_defines(\"WORD=\\\"(world)\\\"\")\n\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/bar/test4.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nnamespace MY_UNITY_ID {\nint i = 42;\n}\n\nint test4() {\n    return MY_UNITY_ID::i;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/bar/test5.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nnamespace MY_UNITY_ID {\nint i = 42;\n}\n\nint test5() {\n    return MY_UNITY_ID::i;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/bar/test6.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test6() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/foo/test.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/foo/test2.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test2() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/header.h",
    "content": "// header.h\n#ifndef HEADER_H\n#define HEADER_H\n\n#include <algorithm>\n#include <deque>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <set>\n//#include <thread>\n#include <utility>\n#include <vector>\n#include <string>\n#include <queue>\n#include <cstdlib>\n#include <utility>\n#include <exception>\n#include <list>\n#include <stack>\n#include <complex>\n#include <fstream>\n#include <cstdio>\n#include <iomanip>\n\n#endif\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/header2.h",
    "content": ""
  },
  {
    "path": "tests/projects/c++/unity_build/src/main.cpp",
    "content": "#include \"header.h\"\n\nint main(int argc, char **argv) {\n    std::string s(\"xmake\");\n    printf(\"hello %s!\\n\", s.c_str());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/test.c",
    "content": "\nvoid test_c(void) {\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/test7.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test7() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/src/test8.cpp",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test8() {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/c++/unity_build/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/c++/unity_build/xmake.lua",
    "content": "target(\"test\")\n    set_kind(\"binary\")\n    add_includedirs(\"src\")\n    add_rules(\"c++.unity_build\", {batchsize = 2, uniqueid = \"MY_UNITY_ID\"})\n    add_files(\"src/*.c\", \"src/*.cpp\")\n    add_files(\"src/foo/*.cpp\", {unity_group = \"foo\"})\n    add_files(\"src/bar/*.cpp\", {unity_group = \"bar\"})\n\n\n"
  },
  {
    "path": "tests/projects/cppfront/console/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/cppfront/console/src/main.cpp2",
    "content": "#include \"println.h2\"\nmain: () -> int =\n    println(\"Hello world!\\n\");\n\n\n"
  },
  {
    "path": "tests/projects/cppfront/console/src/println.h2",
    "content": "println: (msg: _) -> int = {\n    std::cout << msg;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/cppfront/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"cppfront\")\n\ntarget(\"test\")\n    add_rules(\"cppfront\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp2\")\n    add_files(\"src/*.h2\")\n    add_packages(\"cppfront\")\n\n"
  },
  {
    "path": "tests/projects/csharp/console/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n"
  },
  {
    "path": "tests/projects/csharp/console/src/Program.cs",
    "content": "Console.WriteLine(\"hello xmake!\");\n\n"
  },
  {
    "path": "tests/projects/csharp/console/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/Program.cs\")\n"
  },
  {
    "path": "tests/projects/csharp/console_with_runtime_json/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n\n"
  },
  {
    "path": "tests/projects/csharp/console_with_runtime_json/src/Program.cs",
    "content": "using System.Text.Json;\n\nvar runtimeFile = Path.Combine(Directory.GetCurrentDirectory(), \"runtime.json\");\nif (!File.Exists(runtimeFile)) {\n    Console.WriteLine(\"runtime.json missing\");\n    return;\n}\n\nvar json = File.ReadAllText(runtimeFile);\nusing var doc = JsonDocument.Parse(json);\nvar runtime = doc.RootElement.TryGetProperty(\"runtime\", out var value)\n    ? value.GetString()\n    : \"unknown\";\n\nConsole.WriteLine($\"runtime={runtime}\");\n"
  },
  {
    "path": "tests/projects/csharp/console_with_runtime_json/src/runtime.json",
    "content": "{\n  \"runtime\": \"xmake\",\n  \"featureFlags\": {\n    \"sample\": true\n  }\n}\n\n"
  },
  {
    "path": "tests/projects/csharp/console_with_runtime_json/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/console_with_runtime_json/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"app\")\n    set_kind(\"binary\")\n    add_files(\"src/Program.cs\")\n    set_rundir(\"src\")\n"
  },
  {
    "path": "tests/projects/csharp/multiple_library/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n"
  },
  {
    "path": "tests/projects/csharp/multiple_library/src/libalpha/Alpha.cs",
    "content": "namespace LibAlpha;\n\npublic static class Alpha {\n    public static string Message() {\n        return \"alpha\";\n    }\n}\n"
  },
  {
    "path": "tests/projects/csharp/multiple_library/src/libbeta/Beta.cs",
    "content": "using LibAlpha;\n\nnamespace LibBeta;\n\npublic static class Beta {\n    public static string Message() {\n        return Alpha.Message() + \"+beta\";\n    }\n}\n"
  },
  {
    "path": "tests/projects/csharp/multiple_library/src/sample/Program.cs",
    "content": "using LibBeta;\n\nConsole.WriteLine(Beta.Message());"
  },
  {
    "path": "tests/projects/csharp/multiple_library/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/multiple_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"libalpha\")\n    set_kind(\"shared\")\n    add_files(\"src/libalpha/*.cs\")\n\ntarget(\"libbeta\")\n    set_kind(\"shared\")\n    add_deps(\"libalpha\")\n    add_files(\"src/libbeta/*.cs\")\n\ntarget(\"sample\")\n    set_kind(\"binary\")\n    add_deps(\"libbeta\")\n    add_files(\"src/sample/*.cs\")\n"
  },
  {
    "path": "tests/projects/csharp/nuget_package/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n"
  },
  {
    "path": "tests/projects/csharp/nuget_package/src/Program.cs",
    "content": "using Humanizer;\n\nConsole.WriteLine(1234.ToWords());\n\n"
  },
  {
    "path": "tests/projects/csharp/nuget_package/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/nuget_package/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"nuget::Humanizer.Core 2.14.1\")\n\ntarget(\"app\")\n    set_kind(\"binary\")\n    add_files(\"src/Program.cs\")\n    add_packages(\"nuget::Humanizer.Core\")\n"
  },
  {
    "path": "tests/projects/csharp/pinvoke/src/app/Program.cs",
    "content": "using System.Runtime.InteropServices;\n\nint sum = NativeMethods.add(3, 4);\nint product = NativeMethods.multiply(5, 6);\nConsole.WriteLine($\"add(3,4)={sum}\");\nConsole.WriteLine($\"multiply(5,6)={product}\");\n\ninternal static class NativeMethods {\n    private const string NativeLib = \"mathlib\";\n\n    [DllImport(NativeLib)]\n    internal static extern int add(int a, int b);\n\n    [DllImport(NativeLib)]\n    internal static extern int multiply(int a, int b);\n}\n"
  },
  {
    "path": "tests/projects/csharp/pinvoke/src/native/mathlib.c",
    "content": "#ifdef _WIN32\n#define EXPORT __declspec(dllexport)\n#else\n#define EXPORT __attribute__((visibility(\"default\")))\n#endif\n\nEXPORT int add(int a, int b) {\n    return a + b;\n}\n\nEXPORT int multiply(int a, int b) {\n    return a * b;\n}\n"
  },
  {
    "path": "tests/projects/csharp/pinvoke/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/pinvoke/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"mathlib\")\n    set_kind(\"shared\")\n    add_files(\"src/native/*.c\")\n\ntarget(\"app\")\n    set_kind(\"binary\")\n    add_deps(\"mathlib\")\n    add_files(\"src/app/*.cs\")\n"
  },
  {
    "path": "tests/projects/csharp/shared_library/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n"
  },
  {
    "path": "tests/projects/csharp/shared_library/src/app/Program.cs",
    "content": "using MyLib;\n\nConsole.WriteLine(Greeter.Greet(\"xmake\"));\n\n"
  },
  {
    "path": "tests/projects/csharp/shared_library/src/lib/Greeter.cs",
    "content": "namespace MyLib;\n\npublic static class Greeter {\n    public static string Greet(string name) {\n        return $\"hello {name}!\";\n    }\n}\n"
  },
  {
    "path": "tests/projects/csharp/shared_library/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"mylib\")\n    set_kind(\"shared\")\n    add_files(\"src/lib/*.cs\")\n\ntarget(\"app\")\n    set_kind(\"binary\")\n    add_deps(\"mylib\")\n    add_files(\"src/app/*.cs\")\n"
  },
  {
    "path": "tests/projects/csharp/web_project/.gitignore",
    "content": ".xmake/\nbuild/\nbin/\nobj/\nvsxmake*/\n.vs/\n\n"
  },
  {
    "path": "tests/projects/csharp/web_project/src/Program.cs",
    "content": "var builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\napp.MapGet(\"/\", () => \"hello web xmake!\");\napp.MapGet(\"/health\", () => Results.Ok(new { status = \"ok\" }));\n\napp.Run();\n\n"
  },
  {
    "path": "tests/projects/csharp/web_project/test.lua",
    "content": "import(\"detect.sdks.find_dotnet\")\n\nfunction test_build(t)\n    if is_subhost(\"msys\") then\n        return t:skip(\"csharp not supported on msys\")\n    end\n    local dotnet = find_dotnet()\n    if dotnet and dotnet.sdkver then\n        t:build()\n    else\n        return t:skip(\"dotnet sdk not found\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/csharp/web_project/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"webapp\")\n    set_kind(\"binary\")\n    add_values(\"csharp.sdk\", \"Microsoft.NET.Sdk.Web\")\n    add_files(\"src/Program.cs\")\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/cuda_drvapi_dynlink.c",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// With these flags defined, this source file will dynamically\n// load the corresponding functions.  Disabled by default.\n//#define CUDA_INIT_D3D9\n//#define CUDA_INIT_D3D10\n//#define CUDA_INIT_D3D11\n//#define CUDA_INIT_OPENGL\n\n#include <stdio.h>\n#include \"cuda_drvapi_dynlink.h\"\n\ntcuInit                               *_cuInit;\ntcuDriverGetVersion                   *cuDriverGetVersion;\ntcuDeviceGet                          *cuDeviceGet;\ntcuDeviceGetCount                     *cuDeviceGetCount;\ntcuDeviceGetName                      *cuDeviceGetName;\ntcuDeviceComputeCapability            *cuDeviceComputeCapability;\ntcuDeviceTotalMem                     *cuDeviceTotalMem;\ntcuDeviceGetProperties                *cuDeviceGetProperties;\ntcuDeviceGetAttribute                 *cuDeviceGetAttribute;\ntcuCtxCreate                          *cuCtxCreate;\ntcuCtxDestroy                         *cuCtxDestroy;\ntcuCtxAttach                          *cuCtxAttach;\ntcuCtxDetach                          *cuCtxDetach;\ntcuCtxPushCurrent                     *cuCtxPushCurrent;\ntcuCtxPopCurrent                      *cuCtxPopCurrent;\ntcuCtxGetCurrent                      *cuCtxGetCurrent;\ntcuCtxSetCurrent                      *cuCtxSetCurrent;\ntcuCtxGetDevice                       *cuCtxGetDevice;\ntcuCtxSynchronize                     *cuCtxSynchronize;\ntcuModuleLoad                         *cuModuleLoad;\ntcuModuleLoadData                     *cuModuleLoadData;\ntcuModuleLoadDataEx                   *cuModuleLoadDataEx;\ntcuModuleLoadFatBinary                *cuModuleLoadFatBinary;\ntcuModuleUnload                       *cuModuleUnload;\ntcuModuleGetFunction                  *cuModuleGetFunction;\ntcuModuleGetGlobal                    *cuModuleGetGlobal;\ntcuModuleGetTexRef                    *cuModuleGetTexRef;\ntcuModuleGetSurfRef                   *cuModuleGetSurfRef;\ntcuMemGetInfo                         *cuMemGetInfo;\ntcuMemAlloc                           *cuMemAlloc;\ntcuMemAllocPitch                      *cuMemAllocPitch;\ntcuMemFree                            *cuMemFree;\ntcuMemGetAddressRange                 *cuMemGetAddressRange;\ntcuMemAllocHost                       *cuMemAllocHost;\ntcuMemFreeHost                        *cuMemFreeHost;\ntcuMemHostAlloc                       *cuMemHostAlloc;\ntcuMemHostGetDevicePointer            *cuMemHostGetDevicePointer;\ntcuMemHostRegister                    *cuMemHostRegister;\ntcuMemHostUnregister                  *cuMemHostUnregister;\ntcuMemcpyHtoD                         *cuMemcpyHtoD;\ntcuMemcpyDtoH                         *cuMemcpyDtoH;\ntcuMemcpyDtoD                         *cuMemcpyDtoD;\ntcuMemcpyDtoA                         *cuMemcpyDtoA;\ntcuMemcpyAtoD                         *cuMemcpyAtoD;\ntcuMemcpyHtoA                         *cuMemcpyHtoA;\ntcuMemcpyAtoH                         *cuMemcpyAtoH;\ntcuMemcpyAtoA                         *cuMemcpyAtoA;\ntcuMemcpy2D                           *cuMemcpy2D;\ntcuMemcpy2DUnaligned                  *cuMemcpy2DUnaligned;\ntcuMemcpy3D                           *cuMemcpy3D;\ntcuMemcpyHtoDAsync                    *cuMemcpyHtoDAsync;\ntcuMemcpyDtoHAsync                    *cuMemcpyDtoHAsync;\ntcuMemcpyDtoDAsync                    *cuMemcpyDtoDAsync;\ntcuMemcpyHtoAAsync                    *cuMemcpyHtoAAsync;\ntcuMemcpyAtoHAsync                    *cuMemcpyAtoHAsync;\ntcuMemcpy2DAsync                      *cuMemcpy2DAsync;\ntcuMemcpy3DAsync                      *cuMemcpy3DAsync;\ntcuMemcpy                             *cuMemcpy;\ntcuMemcpyPeer                         *cuMemcpyPeer;\ntcuMemsetD8                           *cuMemsetD8;\ntcuMemsetD16                          *cuMemsetD16;\ntcuMemsetD32                          *cuMemsetD32;\ntcuMemsetD2D8                         *cuMemsetD2D8;\ntcuMemsetD2D16                        *cuMemsetD2D16;\ntcuMemsetD2D32                        *cuMemsetD2D32;\ntcuFuncSetBlockShape                  *cuFuncSetBlockShape;\ntcuFuncSetSharedSize                  *cuFuncSetSharedSize;\ntcuFuncGetAttribute                   *cuFuncGetAttribute;\ntcuFuncSetCacheConfig                 *cuFuncSetCacheConfig;\ntcuLaunchKernel                       *cuLaunchKernel;\ntcuArrayCreate                        *cuArrayCreate;\ntcuArrayGetDescriptor                 *cuArrayGetDescriptor;\ntcuArrayDestroy                       *cuArrayDestroy;\ntcuArray3DCreate                      *cuArray3DCreate;\ntcuArray3DGetDescriptor               *cuArray3DGetDescriptor;\ntcuTexRefCreate                       *cuTexRefCreate;\ntcuTexRefDestroy                      *cuTexRefDestroy;\ntcuTexRefSetArray                     *cuTexRefSetArray;\ntcuTexRefSetAddress                   *cuTexRefSetAddress;\ntcuTexRefSetAddress2D                 *cuTexRefSetAddress2D;\ntcuTexRefSetFormat                    *cuTexRefSetFormat;\ntcuTexRefSetAddressMode               *cuTexRefSetAddressMode;\ntcuTexRefSetFilterMode                *cuTexRefSetFilterMode;\ntcuTexRefSetFlags                     *cuTexRefSetFlags;\ntcuTexRefGetAddress                   *cuTexRefGetAddress;\ntcuTexRefGetArray                     *cuTexRefGetArray;\ntcuTexRefGetAddressMode               *cuTexRefGetAddressMode;\ntcuTexRefGetFilterMode                *cuTexRefGetFilterMode;\ntcuTexRefGetFormat                    *cuTexRefGetFormat;\ntcuTexRefGetFlags                     *cuTexRefGetFlags;\ntcuSurfRefSetArray                    *cuSurfRefSetArray;\ntcuSurfRefGetArray                    *cuSurfRefGetArray;\ntcuParamSetSize                       *cuParamSetSize;\ntcuParamSeti                          *cuParamSeti;\ntcuParamSetf                          *cuParamSetf;\ntcuParamSetv                          *cuParamSetv;\ntcuParamSetTexRef                     *cuParamSetTexRef;\ntcuLaunch                             *cuLaunch;\ntcuLaunchGrid                         *cuLaunchGrid;\ntcuLaunchGridAsync                    *cuLaunchGridAsync;\ntcuEventCreate                        *cuEventCreate;\ntcuEventRecord                        *cuEventRecord;\ntcuEventQuery                         *cuEventQuery;\ntcuEventSynchronize                   *cuEventSynchronize;\ntcuEventDestroy                       *cuEventDestroy;\ntcuEventElapsedTime                   *cuEventElapsedTime;\ntcuStreamCreate                       *cuStreamCreate;\ntcuStreamQuery                        *cuStreamQuery;\ntcuStreamSynchronize                  *cuStreamSynchronize;\ntcuStreamDestroy                      *cuStreamDestroy;\ntcuGraphicsUnregisterResource         *cuGraphicsUnregisterResource;\ntcuGraphicsSubResourceGetMappedArray  *cuGraphicsSubResourceGetMappedArray;\ntcuGraphicsResourceGetMappedPointer   *cuGraphicsResourceGetMappedPointer;\ntcuGraphicsResourceSetMapFlags        *cuGraphicsResourceSetMapFlags;\ntcuGraphicsMapResources               *cuGraphicsMapResources;\ntcuGraphicsUnmapResources             *cuGraphicsUnmapResources;\ntcuGetExportTable                     *cuGetExportTable;\ntcuCtxSetLimit                        *cuCtxSetLimit;\ntcuCtxGetLimit                        *cuCtxGetLimit;\ntcuMemHostGetFlags                    *cuMemHostGetFlags;\n\n#ifdef CUDA_INIT_D3D9\n// D3D9/CUDA interop (CUDA 1.x compatible API). These functions\n// are deprecated; please use the ones below\ntcuD3D9Begin                          *cuD3D9Begin;\ntcuD3D9End                            *cuD3DEnd;\ntcuD3D9RegisterVertexBuffer           *cuD3D9RegisterVertexBuffer;\ntcuD3D9MapVertexBuffer                *cuD3D9MapVertexBuffer;\ntcuD3D9UnmapVertexBuffer              *cuD3D9UnmapVertexBuffer;\ntcuD3D9UnregisterVertexBuffer         *cuD3D9UnregisterVertexBuffer;\n\n// D3D9/CUDA interop (CUDA 2.x compatible)\ntcuD3D9GetDirect3DDevice              *cuD3D9GetDirect3DDevice;\ntcuD3D9RegisterResource               *cuD3D9RegisterResource;\ntcuD3D9UnregisterResource             *cuD3D9UnregisterResource;\ntcuD3D9MapResources                   *cuD3D9MapResources;\ntcuD3D9UnmapResources                 *cuD3D9UnmapResources;\ntcuD3D9ResourceSetMapFlags            *cuD3D9ResourceSetMapFlags;\ntcuD3D9ResourceGetSurfaceDimensions   *cuD3D9ResourceGetSurfaceDimensions;\ntcuD3D9ResourceGetMappedArray         *cuD3D9ResourceGetMappedArray;\ntcuD3D9ResourceGetMappedPointer       *cuD3D9ResourceGetMappedPointer;\ntcuD3D9ResourceGetMappedSize          *cuD3D9ResourceGetMappedSize;\ntcuD3D9ResourceGetMappedPitch         *cuD3D9ResourceGetMappedPitch;\n\n// D3D9/CUDA interop (CUDA 2.0+)\ntcuD3D9GetDevice                      *cuD3D9GetDevice;\ntcuD3D9CtxCreate                      *cuD3D9CtxCreate;\ntcuGraphicsD3D9RegisterResource       *cuGraphicsD3D9RegisterResource;\n#endif\n\n#ifdef CUDA_INIT_D3D10\n// D3D10/CUDA interop (CUDA 3.0+)\ntcuD3D10GetDevice                     *cuD3D10GetDevice;\ntcuD3D10CtxCreate                     *cuD3D10CtxCreate;\ntcuGraphicsD3D10RegisterResource      *cuGraphicsD3D10RegisterResource;\n#endif\n\n\n#ifdef CUDA_INIT_D3D11\n// D3D11/CUDA interop (CUDA 3.0+)\ntcuD3D11GetDevice                     *cuD3D11GetDevice;\ntcuD3D11CtxCreate                     *cuD3D11CtxCreate;\ntcuGraphicsD3D11RegisterResource      *cuGraphicsD3D11RegisterResource;\n#endif\n\n// GL/CUDA interop\n#ifdef CUDA_INIT_OPENGL\ntcuGLCtxCreate                        *cuGLCtxCreate;\ntcuGraphicsGLRegisterBuffer           *cuGraphicsGLRegisterBuffer;\ntcuGraphicsGLRegisterImage            *cuGraphicsGLRegisterImage;\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\ntcuWGLGetDevice                       *cuWGLGetDevice;\n#endif\n#endif\n\n#define STRINGIFY(X) #X\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#include <Windows.h>\n\n#ifdef UNICODE\nstatic LPCWSTR __CudaLibName = L\"nvcuda.dll\";\n#else\nstatic LPCSTR __CudaLibName = \"nvcuda.dll\";\n#endif\n\ntypedef HMODULE CUDADRIVER;\n\nstatic CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)\n{\n    *pInstance = LoadLibrary(__CudaLibName);\n\n    if (*pInstance == NULL)\n    {\n        printf(\"LoadLibrary \\\"%s\\\" failed!\\n\", __CudaLibName);\n        return CUDA_ERROR_UNKNOWN;\n    }\n\n    return CUDA_SUCCESS;\n}\n\n#define GET_PROC_EX(name, alias, required)                     \\\n    alias = (t##name *)GetProcAddress(CudaDrvLib, #name);               \\\n    if (alias == NULL && required) {                                    \\\n        printf(\"Failed to find required function \\\"%s\\\" in %s\\n\",       \\\n               #name, __CudaLibName);                                  \\\n        return CUDA_ERROR_UNKNOWN;                                      \\\n    }\n\n#define GET_PROC_EX_V2(name, alias, required)                           \\\n    alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v2));\\\n    if (alias == NULL && required) {                                    \\\n        printf(\"Failed to find required function \\\"%s\\\" in %s\\n\",       \\\n               STRINGIFY(name##_v2), __CudaLibName);                       \\\n        return CUDA_ERROR_UNKNOWN;                                      \\\n    }\n\n#elif defined(__unix__) || defined(__APPLE__) || defined(__MACOSX)\n\n#include <dlfcn.h>\n\n#if defined(__APPLE__) || defined(__MACOSX)\nstatic char __CudaLibName[] = \"/usr/local/cuda/lib/libcuda.dylib\";\n#else\nstatic char __CudaLibName[] = \"libcuda.so\";\n#endif\n\ntypedef void *CUDADRIVER;\n\nstatic CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)\n{\n    *pInstance = dlopen(__CudaLibName, RTLD_NOW);\n\n    if (*pInstance == NULL)\n    {\n        printf(\"dlopen \\\"%s\\\" failed!\\n\", __CudaLibName);\n        return CUDA_ERROR_UNKNOWN;\n    }\n\n    return CUDA_SUCCESS;\n}\n\n#define GET_PROC_EX(name, alias, required)                              \\\n    alias = (t##name *)dlsym(CudaDrvLib, #name);                        \\\n    if (alias == NULL && required) {                                    \\\n        printf(\"Failed to find required function \\\"%s\\\" in %s\\n\",       \\\n               #name, __CudaLibName);                                  \\\n        return CUDA_ERROR_UNKNOWN;                                      \\\n    }\n\n#define GET_PROC_EX_V2(name, alias, required)                           \\\n    alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v2));         \\\n    if (alias == NULL && required) {                                    \\\n        printf(\"Failed to find required function \\\"%s\\\" in %s\\n\",       \\\n               STRINGIFY(name##_v2), __CudaLibName);                    \\\n        return CUDA_ERROR_UNKNOWN;                                      \\\n    }\n\n#else\n#error unsupported platform\n#endif\n\n#define CHECKED_CALL(call)              \\\n    do {                                \\\n        CUresult result = (call);       \\\n        if (CUDA_SUCCESS != result) {   \\\n            return result;              \\\n        }                               \\\n    } while(0)\n\n#define GET_PROC_REQUIRED(name) GET_PROC_EX(name,name,1)\n#define GET_PROC_OPTIONAL(name) GET_PROC_EX(name,name,0)\n#define GET_PROC(name)          GET_PROC_REQUIRED(name)\n#define GET_PROC_V2(name)       GET_PROC_EX_V2(name,name,1)\n\nCUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)\n{\n    CUDADRIVER CudaDrvLib;\n    int driverVer = 1000;\n\n    CHECKED_CALL(LOAD_LIBRARY(&CudaDrvLib));\n\n    // cuInit is required; alias it to _cuInit\n    GET_PROC_EX(cuInit, _cuInit, 1);\n    CHECKED_CALL(_cuInit(Flags));\n\n    // available since 2.2. if not present, version 1.0 is assumed\n    GET_PROC_OPTIONAL(cuDriverGetVersion);\n\n    if (cuDriverGetVersion)\n    {\n        CHECKED_CALL(cuDriverGetVersion(&driverVer));\n    }\n\n    // fetch all function pointers\n    GET_PROC(cuDeviceGet);\n    GET_PROC(cuDeviceGetCount);\n    GET_PROC(cuDeviceGetName);\n    GET_PROC(cuDeviceComputeCapability);\n    GET_PROC(cuDeviceGetProperties);\n    GET_PROC(cuDeviceGetAttribute);\n    GET_PROC(cuCtxDestroy);\n    GET_PROC(cuCtxAttach);\n    GET_PROC(cuCtxDetach);\n    GET_PROC(cuCtxPushCurrent);\n    GET_PROC(cuCtxPopCurrent);\n    GET_PROC(cuCtxGetDevice);\n    GET_PROC(cuCtxSynchronize);\n    GET_PROC(cuModuleLoad);\n    GET_PROC(cuModuleLoadData);\n    GET_PROC(cuModuleUnload);\n    GET_PROC(cuModuleGetFunction);\n    GET_PROC(cuModuleGetTexRef);\n    GET_PROC(cuMemFreeHost);\n    GET_PROC(cuMemHostAlloc);\n    GET_PROC(cuFuncSetBlockShape);\n    GET_PROC(cuFuncSetSharedSize);\n    GET_PROC(cuFuncGetAttribute);\n    GET_PROC(cuArrayDestroy);\n    GET_PROC(cuTexRefCreate);\n    GET_PROC(cuTexRefDestroy);\n    GET_PROC(cuTexRefSetArray);\n    GET_PROC(cuTexRefSetFormat);\n    GET_PROC(cuTexRefSetAddressMode);\n    GET_PROC(cuTexRefSetFilterMode);\n    GET_PROC(cuTexRefSetFlags);\n    GET_PROC(cuTexRefGetArray);\n    GET_PROC(cuTexRefGetAddressMode);\n    GET_PROC(cuTexRefGetFilterMode);\n    GET_PROC(cuTexRefGetFormat);\n    GET_PROC(cuTexRefGetFlags);\n    GET_PROC(cuParamSetSize);\n    GET_PROC(cuParamSeti);\n    GET_PROC(cuParamSetf);\n    GET_PROC(cuParamSetv);\n    GET_PROC(cuParamSetTexRef);\n    GET_PROC(cuLaunch);\n    GET_PROC(cuLaunchGrid);\n    GET_PROC(cuLaunchGridAsync);\n    GET_PROC(cuEventCreate);\n    GET_PROC(cuEventRecord);\n    GET_PROC(cuEventQuery);\n    GET_PROC(cuEventSynchronize);\n    GET_PROC(cuEventDestroy);\n    GET_PROC(cuEventElapsedTime);\n    GET_PROC(cuStreamCreate);\n    GET_PROC(cuStreamQuery);\n    GET_PROC(cuStreamSynchronize);\n    GET_PROC(cuStreamDestroy);\n\n    // These could be _v2 interfaces\n    if (cudaVersion >= 4000 && __CUDA_API_VERSION >= 4000)\n    {\n        GET_PROC_V2(cuCtxDestroy);\n        GET_PROC_V2(cuCtxPopCurrent);\n        GET_PROC_V2(cuCtxPushCurrent);\n        GET_PROC_V2(cuStreamDestroy);\n        GET_PROC_V2(cuEventDestroy);\n    }\n\n    if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020)\n    {\n        GET_PROC_V2(cuDeviceTotalMem);\n        GET_PROC_V2(cuCtxCreate);\n        GET_PROC_V2(cuModuleGetGlobal);\n        GET_PROC_V2(cuMemGetInfo);\n        GET_PROC_V2(cuMemAlloc);\n        GET_PROC_V2(cuMemAllocPitch);\n        GET_PROC_V2(cuMemFree);\n        GET_PROC_V2(cuMemGetAddressRange);\n        GET_PROC_V2(cuMemAllocHost);\n        GET_PROC_V2(cuMemHostGetDevicePointer);\n        GET_PROC_V2(cuMemcpyHtoD);\n        GET_PROC_V2(cuMemcpyDtoH);\n        GET_PROC_V2(cuMemcpyDtoD);\n        GET_PROC_V2(cuMemcpyDtoA);\n        GET_PROC_V2(cuMemcpyAtoD);\n        GET_PROC_V2(cuMemcpyHtoA);\n        GET_PROC_V2(cuMemcpyAtoH);\n        GET_PROC_V2(cuMemcpyAtoA);\n        GET_PROC_V2(cuMemcpy2D);\n        GET_PROC_V2(cuMemcpy2DUnaligned);\n        GET_PROC_V2(cuMemcpy3D);\n        GET_PROC_V2(cuMemcpyHtoDAsync);\n        GET_PROC_V2(cuMemcpyDtoHAsync);\n        GET_PROC_V2(cuMemcpyHtoAAsync);\n        GET_PROC_V2(cuMemcpyAtoHAsync);\n        GET_PROC_V2(cuMemcpy2DAsync);\n        GET_PROC_V2(cuMemcpy3DAsync);\n        GET_PROC_V2(cuMemsetD8);\n        GET_PROC_V2(cuMemsetD16);\n        GET_PROC_V2(cuMemsetD32);\n        GET_PROC_V2(cuMemsetD2D8);\n        GET_PROC_V2(cuMemsetD2D16);\n        GET_PROC_V2(cuMemsetD2D32);\n        GET_PROC_V2(cuArrayCreate);\n        GET_PROC_V2(cuArrayGetDescriptor);\n        GET_PROC_V2(cuArray3DCreate);\n        GET_PROC_V2(cuArray3DGetDescriptor);\n        GET_PROC_V2(cuTexRefSetAddress);\n        GET_PROC_V2(cuTexRefSetAddress2D);\n        GET_PROC_V2(cuTexRefGetAddress);\n    }\n    else\n    {\n        GET_PROC(cuDeviceTotalMem);\n        GET_PROC(cuCtxCreate);\n        GET_PROC(cuModuleGetGlobal);\n        GET_PROC(cuMemGetInfo);\n        GET_PROC(cuMemAlloc);\n        GET_PROC(cuMemAllocPitch);\n        GET_PROC(cuMemFree);\n        GET_PROC(cuMemGetAddressRange);\n        GET_PROC(cuMemAllocHost);\n        GET_PROC(cuMemHostGetDevicePointer);\n        GET_PROC(cuMemcpyHtoD);\n        GET_PROC(cuMemcpyDtoH);\n        GET_PROC(cuMemcpyDtoD);\n        GET_PROC(cuMemcpyDtoA);\n        GET_PROC(cuMemcpyAtoD);\n        GET_PROC(cuMemcpyHtoA);\n        GET_PROC(cuMemcpyAtoH);\n        GET_PROC(cuMemcpyAtoA);\n        GET_PROC(cuMemcpy2D);\n        GET_PROC(cuMemcpy2DUnaligned);\n        GET_PROC(cuMemcpy3D);\n        GET_PROC(cuMemcpyHtoDAsync);\n        GET_PROC(cuMemcpyDtoHAsync);\n        GET_PROC(cuMemcpyHtoAAsync);\n        GET_PROC(cuMemcpyAtoHAsync);\n        GET_PROC(cuMemcpy2DAsync);\n        GET_PROC(cuMemcpy3DAsync);\n        GET_PROC(cuMemsetD8);\n        GET_PROC(cuMemsetD16);\n        GET_PROC(cuMemsetD32);\n        GET_PROC(cuMemsetD2D8);\n        GET_PROC(cuMemsetD2D16);\n        GET_PROC(cuMemsetD2D32);\n        GET_PROC(cuArrayCreate);\n        GET_PROC(cuArrayGetDescriptor);\n        GET_PROC(cuArray3DCreate);\n        GET_PROC(cuArray3DGetDescriptor);\n        GET_PROC(cuTexRefSetAddress);\n        GET_PROC(cuTexRefSetAddress2D);\n        GET_PROC(cuTexRefGetAddress);\n    }\n\n    // The following functions are specific to CUDA versions\n    if (driverVer >= 2010)\n    {\n        GET_PROC(cuModuleLoadDataEx);\n        GET_PROC(cuModuleLoadFatBinary);\n#ifdef CUDA_INIT_OPENGL\n        GET_PROC(cuGLCtxCreate);\n        GET_PROC(cuGraphicsGLRegisterBuffer);\n        GET_PROC(cuGraphicsGLRegisterImage);\n#  ifdef WIN32\n        GET_PROC(cuWGLGetDevice);\n#  endif\n#endif\n#ifdef CUDA_INIT_D3D9\n        GET_PROC(cuD3D9GetDevice);\n        GET_PROC(cuD3D9CtxCreate);\n        GET_PROC(cuGraphicsD3D9RegisterResource);\n#endif\n    }\n\n    if (driverVer >= 2030)\n    {\n        GET_PROC(cuMemHostGetFlags);\n#ifdef CUDA_INIT_D3D10\n        GET_PROC(cuD3D10GetDevice);\n        GET_PROC(cuD3D10CtxCreate);\n        GET_PROC(cuGraphicsD3D10RegisterResource);\n#endif\n#ifdef CUDA_INIT_OPENGL\n        GET_PROC(cuGraphicsGLRegisterBuffer);\n        GET_PROC(cuGraphicsGLRegisterImage);\n#endif\n    }\n\n    if (driverVer >= 3000)\n    {\n        GET_PROC(cuMemcpyDtoDAsync);\n        GET_PROC(cuFuncSetCacheConfig);\n#ifdef CUDA_INIT_D3D11\n        GET_PROC(cuD3D11GetDevice);\n        GET_PROC(cuD3D11CtxCreate);\n        GET_PROC(cuGraphicsD3D11RegisterResource);\n#endif\n        GET_PROC(cuGraphicsUnregisterResource);\n        GET_PROC(cuGraphicsSubResourceGetMappedArray);\n\n        if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020)\n        {\n            GET_PROC_V2(cuGraphicsResourceGetMappedPointer);\n        }\n        else\n        {\n            GET_PROC(cuGraphicsResourceGetMappedPointer);\n        }\n\n        GET_PROC(cuGraphicsResourceSetMapFlags);\n        GET_PROC(cuGraphicsMapResources);\n        GET_PROC(cuGraphicsUnmapResources);\n        GET_PROC(cuGetExportTable);\n    }\n\n    if (driverVer >= 3010)\n    {\n        GET_PROC(cuModuleGetSurfRef);\n        GET_PROC(cuSurfRefSetArray);\n        GET_PROC(cuSurfRefGetArray);\n        GET_PROC(cuCtxSetLimit);\n        GET_PROC(cuCtxGetLimit);\n    }\n\n    if (driverVer >= 4000)\n    {\n        GET_PROC(cuCtxSetCurrent);\n        GET_PROC(cuCtxGetCurrent);\n        GET_PROC(cuMemHostRegister);\n        GET_PROC(cuMemHostUnregister);\n        GET_PROC(cuMemcpy);\n        GET_PROC(cuMemcpyPeer);\n        GET_PROC(cuLaunchKernel);\n    }\n\n    return CUDA_SUCCESS;\n}\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/drvapi_error_string.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef _DRVAPI_ERROR_STRING_H_\n#define _DRVAPI_ERROR_STRING_H_\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n\n#ifdef  __cuda_cuda_h__ // check to see if CUDA_H is included above\n\n// Error Code string definitions here\ntypedef struct\n{\n    char const *error_string;\n    int  error_id;\n} s_CudaErrorStr;\n\n/**\n * Error codes\n */\nstatic s_CudaErrorStr sCudaDrvErrorString[] =\n{\n    /**\n     * The API call returned with no errors. In the case of query calls, this\n     * can also mean that the operation being queried is complete (see\n     * ::cuEventQuery() and ::cuStreamQuery()).\n     */\n    { \"CUDA_SUCCESS\", 0 },\n\n    /**\n     * This indicates that one or more of the parameters passed to the API call\n     * is not within an acceptable range of values.\n     */\n    { \"CUDA_ERROR_INVALID_VALUE\", 1 },\n\n    /**\n     * The API call failed because it was unable to allocate enough memory to\n     * perform the requested operation.\n     */\n    { \"CUDA_ERROR_OUT_OF_MEMORY\", 2 },\n\n    /**\n     * This indicates that the CUDA driver has not been initialized with\n     * ::cuInit() or that initialization has failed.\n     */\n    { \"CUDA_ERROR_NOT_INITIALIZED\", 3 },\n\n    /**\n     * This indicates that the CUDA driver is in the process of shutting down.\n     */\n    { \"CUDA_ERROR_DEINITIALIZED\", 4 },\n\n    /**\n     * This indicates profiling APIs are called while application is running\n     * in visual profiler mode.\n    */\n    { \"CUDA_ERROR_PROFILER_DISABLED\", 5 },\n    /**\n     * This indicates profiling has not been initialized for this context.\n     * Call cuProfilerInitialize() to resolve this.\n    */\n    { \"CUDA_ERROR_PROFILER_NOT_INITIALIZED\", 6 },\n    /**\n     * This indicates profiler has already been started and probably\n     * cuProfilerStart() is incorrectly called.\n    */\n    { \"CUDA_ERROR_PROFILER_ALREADY_STARTED\", 7 },\n    /**\n     * This indicates profiler has already been stopped and probably\n     * cuProfilerStop() is incorrectly called.\n    */\n    { \"CUDA_ERROR_PROFILER_ALREADY_STOPPED\", 8 },\n    /**\n     * This indicates that no CUDA-capable devices were detected by the installed\n     * CUDA driver.\n     */\n    { \"CUDA_ERROR_NO_DEVICE (no CUDA-capable devices were detected)\", 100 },\n\n    /**\n     * This indicates that the device ordinal supplied by the user does not\n     * correspond to a valid CUDA device.\n     */\n    { \"CUDA_ERROR_INVALID_DEVICE (device specified is not a valid CUDA device)\", 101 },\n\n\n    /**\n     * This indicates that the device kernel image is invalid. This can also\n     * indicate an invalid CUDA module.\n     */\n    { \"CUDA_ERROR_INVALID_IMAGE\", 200 },\n\n    /**\n     * This most frequently indicates that there is no context bound to the\n     * current thread. This can also be returned if the context passed to an\n     * API call is not a valid handle (such as a context that has had\n     * ::cuCtxDestroy() invoked on it). This can also be returned if a user\n     * mixes different API versions (i.e. 3010 context with 3020 API calls).\n     * See ::cuCtxGetApiVersion() for more details.\n     */\n    { \"CUDA_ERROR_INVALID_CONTEXT\", 201 },\n\n    /**\n     * This indicated that the context being supplied as a parameter to the\n     * API call was already the active context.\n     * \\deprecated\n     * This error return is deprecated as of CUDA 3.2. It is no longer an\n     * error to attempt to push the active context via ::cuCtxPushCurrent().\n     */\n    { \"CUDA_ERROR_CONTEXT_ALREADY_CURRENT\", 202 },\n\n    /**\n     * This indicates that a map or register operation has failed.\n     */\n    { \"CUDA_ERROR_MAP_FAILED\", 205 },\n\n    /**\n     * This indicates that an unmap or unregister operation has failed.\n     */\n    { \"CUDA_ERROR_UNMAP_FAILED\", 206 },\n\n    /**\n     * This indicates that the specified array is currently mapped and thus\n     * cannot be destroyed.\n     */\n    { \"CUDA_ERROR_ARRAY_IS_MAPPED\", 207 },\n\n    /**\n     * This indicates that the resource is already mapped.\n     */\n    { \"CUDA_ERROR_ALREADY_MAPPED\", 208 },\n\n    /**\n     * This indicates that there is no kernel image available that is suitable\n     * for the device. This can occur when a user specifies code generation\n     * options for a particular CUDA source file that do not include the\n     * corresponding device configuration.\n     */\n    { \"CUDA_ERROR_NO_BINARY_FOR_GPU\", 209 },\n\n    /**\n     * This indicates that a resource has already been acquired.\n     */\n    { \"CUDA_ERROR_ALREADY_ACQUIRED\", 210 },\n\n    /**\n     * This indicates that a resource is not mapped.\n     */\n    { \"CUDA_ERROR_NOT_MAPPED\", 211 },\n\n    /**\n     * This indicates that a mapped resource is not available for access as an\n     * array.\n     */\n    { \"CUDA_ERROR_NOT_MAPPED_AS_ARRAY\", 212 },\n\n    /**\n     * This indicates that a mapped resource is not available for access as a\n     * pointer.\n     */\n    { \"CUDA_ERROR_NOT_MAPPED_AS_POINTER\", 213 },\n\n    /**\n     * This indicates that an uncorrectable ECC error was detected during\n     * execution.\n     */\n    { \"CUDA_ERROR_ECC_UNCORRECTABLE\", 214 },\n\n    /**\n     * This indicates that the ::CUlimit passed to the API call is not\n     * supported by the active device.\n     */\n    { \"CUDA_ERROR_UNSUPPORTED_LIMIT\", 215 },\n\n    /**\n     * This indicates that the ::CUcontext passed to the API call can\n     * only be bound to a single CPU thread at a time but is already\n     * bound to a CPU thread.\n     */\n    { \"CUDA_ERROR_CONTEXT_ALREADY_IN_USE\", 216 },\n\n    /**\n     * This indicates that peer access is not supported across the given\n     * devices.\n     */\n    { \"CUDA_ERROR_PEER_ACCESS_UNSUPPORTED\", 217 },\n\n    /**\n     * This indicates that a PTX JIT compilation failed.\n     */\n    { \"CUDA_ERROR_INVALID_PTX\", 218 },\n\n    /**\n     * This indicates an error with OpenGL or DirectX context.\n     */\n    { \"CUDA_ERROR_INVALID_GRAPHICS_CONTEXT\", 219 },\n\n    /**\n    * This indicates that an uncorrectable NVLink error was detected during the\n    * execution.\n    */\n    { \"CUDA_ERROR_NVLINK_UNCORRECTABLE\", 220 },\n\n    /**\n     * This indicates that the PTX JIT compiler library was not found.\n     */\n    { \"CUDA_ERROR_JIT_COMPILER_NOT_FOUND\", 221 },\n\n    /**\n     * This indicates that the device kernel source is invalid.\n     */\n    { \"CUDA_ERROR_INVALID_SOURCE\", 300 },\n\n    /**\n     * This indicates that the file specified was not found.\n     */\n    { \"CUDA_ERROR_FILE_NOT_FOUND\", 301 },\n\n    /**\n     * This indicates that a link to a shared object failed to resolve.\n     */\n    { \"CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND\", 302 },\n\n    /**\n     * This indicates that initialization of a shared object failed.\n     */\n    { \"CUDA_ERROR_SHARED_OBJECT_INIT_FAILED\", 303 },\n\n    /**\n     * This indicates that an OS call failed.\n     */\n    { \"CUDA_ERROR_OPERATING_SYSTEM\", 304 },\n\n\n    /**\n     * This indicates that a resource handle passed to the API call was not\n     * valid. Resource handles are opaque types like ::CUstream and ::CUevent.\n     */\n    { \"CUDA_ERROR_INVALID_HANDLE\", 400 },\n\n\n    /**\n     * This indicates that a named symbol was not found. Examples of symbols\n     * are global/constant variable names, texture names }, and surface names.\n     */\n    { \"CUDA_ERROR_NOT_FOUND\", 500 },\n\n\n    /**\n     * This indicates that asynchronous operations issued previously have not\n     * completed yet. This result is not actually an error, but must be indicated\n     * differently than ::CUDA_SUCCESS (which indicates completion). Calls that\n     * may return this value include ::cuEventQuery() and ::cuStreamQuery().\n     */\n    { \"CUDA_ERROR_NOT_READY\", 600 },\n\n\n    /**\n     * While executing a kernel, the device encountered a\n     * load or store instruction on an invalid memory address.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_ILLEGAL_ADDRESS\", 700 },\n\n    /**\n     * This indicates that a launch did not occur because it did not have\n     * appropriate resources. This error usually indicates that the user has\n     * attempted to pass too many arguments to the device kernel, or the\n     * kernel launch specifies too many threads for the kernel's register\n     * count. Passing arguments of the wrong size (i.e. a 64-bit pointer\n     * when a 32-bit int is expected) is equivalent to passing too many\n     * arguments and can also result in this error.\n     */\n    { \"CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES\", 701 },\n\n    /**\n     * This indicates that the device kernel took too long to execute. This can\n     * only occur if timeouts are enabled - see the device attribute\n     * ::CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT for more information. The\n     * context cannot be used (and must be destroyed similar to\n     * ::CUDA_ERROR_LAUNCH_FAILED). All existing device memory allocations from\n     * this context are invalid and must be reconstructed if the program is to\n     * continue using CUDA.\n     */\n    { \"CUDA_ERROR_LAUNCH_TIMEOUT\", 702 },\n\n    /**\n     * This error indicates a kernel launch that uses an incompatible texturing\n     * mode.\n     */\n    { \"CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING\", 703 },\n\n    /**\n     * This error indicates that a call to ::cuCtxEnablePeerAccess() is\n     * trying to re-enable peer access to a context which has already\n     * had peer access to it enabled.\n     */\n    { \"CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED\", 704 },\n\n    /**\n     * This error indicates that ::cuCtxDisablePeerAccess() is\n     * trying to disable peer access which has not been enabled yet\n     * via ::cuCtxEnablePeerAccess().\n     */\n    { \"CUDA_ERROR_PEER_ACCESS_NOT_ENABLED\", 705 },\n\n    /**\n     * This error indicates that the primary context for the specified device\n     * has already been initialized.\n     */\n    { \"CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE\", 708 },\n\n    /**\n     * This error indicates that the context current to the calling thread\n     * has been destroyed using ::cuCtxDestroy }, or is a primary context which\n     * has not yet been initialized.\n     */\n    { \"CUDA_ERROR_CONTEXT_IS_DESTROYED\", 709 },\n\n    /**\n     * A device-side assert triggered during kernel execution. The context\n     * cannot be used anymore, and must be destroyed. All existing device\n     * memory allocations from this context are invalid and must be\n     * reconstructed if the program is to continue using CUDA.\n     */\n    { \"CUDA_ERROR_ASSERT\", 710 },\n\n    /**\n     * This error indicates that the hardware resources required to enable\n     * peer access have been exhausted for one or more of the devices\n     * passed to ::cuCtxEnablePeerAccess().\n     */\n    { \"CUDA_ERROR_TOO_MANY_PEERS\", 711 },\n\n    /**\n     * This error indicates that the memory range passed to ::cuMemHostRegister()\n     * has already been registered.\n     */\n    { \"CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED\", 712 },\n\n    /**\n     * This error indicates that the pointer passed to ::cuMemHostUnregister()\n     * does not correspond to any currently registered memory region.\n     */\n    { \"CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED\", 713 },\n\n    /**\n     * While executing a kernel, the device encountered a stack error.\n     * This can be due to stack corruption or exceeding the stack size limit.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_HARDWARE_STACK_ERROR\", 714 },\n\n    /**\n     * While executing a kernel, the device encountered an illegal instruction.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_ILLEGAL_INSTRUCTION\", 715 },\n\n    /**\n     * While executing a kernel, the device encountered a load or store instruction\n     * on a memory address which is not aligned.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_MISALIGNED_ADDRESS\", 716 },\n\n    /**\n     * While executing a kernel, the device encountered an instruction\n     * which can only operate on memory locations in certain address spaces\n     * (global, shared, or local), but was supplied a memory address not\n     * belonging to an allowed address space.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_INVALID_ADDRESS_SPACE\", 717 },\n\n    /**\n     * While executing a kernel, the device program counter wrapped its address space.\n     * This leaves the process in an inconsistent state and any further CUDA work\n     * will return the same error. To continue using CUDA, the process must be terminated\n     * and relaunched.\n     */\n    { \"CUDA_ERROR_INVALID_PC\", 718 },\n\n    /**\n     * An exception occurred on the device while executing a kernel. Common\n     * causes include dereferencing an invalid device pointer and accessing\n     * out of bounds shared memory. The context cannot be used }, so it must\n     * be destroyed (and a new one should be created). All existing device\n     * memory allocations from this context are invalid and must be\n     * reconstructed if the program is to continue using CUDA.\n     */\n    { \"CUDA_ERROR_LAUNCH_FAILED\", 719 },\n\n    /**\n     * This error indicates that the number of blocks launched per grid for a kernel that was\n     * launched via either ::cuLaunchCooperativeKernel or ::cuLaunchCooperativeKernelMultiDevice\n     * exceeds the maximum number of blocks as allowed by ::cuOccupancyMaxActiveBlocksPerMultiprocessor\n     * or ::cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags times the number of multiprocessors\n     * as specified by the device attribute ::CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT.\n     */\n    { \"CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE\", 720 },\n\n\n    /**\n     * This error indicates that the attempted operation is not permitted.\n     */\n    { \"CUDA_ERROR_NOT_PERMITTED\", 800 },\n\n    /**\n     * This error indicates that the attempted operation is not supported\n     * on the current system or device.\n     */\n    { \"CUDA_ERROR_NOT_SUPPORTED\", 801 },\n\n\n    /**\n     * This indicates that an unknown internal error has occurred.\n     */\n    { \"CUDA_ERROR_UNKNOWN\", 999 },\n    { NULL, -1 }\n};\n\n// This is just a linear search through the array, since the error_id's are not\n// always ocurring consecutively\ninline const char *getCudaDrvErrorString(CUresult error_id)\n{\n    int index = 0;\n\n    while (sCudaDrvErrorString[index].error_id != error_id &&\n           sCudaDrvErrorString[index].error_id != -1)\n    {\n        index++;\n    }\n\n    if (sCudaDrvErrorString[index].error_id == error_id)\n        return (const char *)sCudaDrvErrorString[index].error_string;\n    else\n        return (const char *)\"CUDA_ERROR not found!\";\n}\n\n#endif // __cuda_cuda_h__\n\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef __cuda_drvapi_dynlink_h__\n#define __cuda_drvapi_dynlink_h__\n\n#include \"cuda_drvapi_dynlink_cuda.h\"\n\n#if defined(CUDA_INIT_D3D9)||defined(CUDA_INIT_D3D10)||defined(CUDA_INIT_D3D11)\n#include \"cuda_drvapi_dynlink_d3d.h\"\n#endif\n\n#ifdef CUDA_INIT_OPENGL\n#include \"cuda_drvapi_dynlink_gl.h\"\n#endif\n\n#endif //__cuda_drvapi_dynlink_h__\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_cuda.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef __cuda_drvapi_dynlink_cuda_h__\n#define __cuda_drvapi_dynlink_cuda_h__\n\n#include <stdlib.h>\n\n/**\n * CUDA API versioning support\n */\n#define __CUDA_API_VERSION 4000\n\n/**\n * \\defgroup CUDA_DRIVER CUDA Driver API\n *\n * This section describes the low-level CUDA driver application programming\n * interface.\n *\n * @{\n */\n\n/**\n * \\defgroup CUDA_TYPES Data types used by CUDA driver\n * @{\n */\n\n/**\n * CUDA API version number\n */\n#define CUDA_VERSION 3020 /* 3.2 */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * CUDA device pointer\n */\n#if __CUDA_API_VERSION >= 3020\n\n#if defined(_WIN64) || defined(__LP64__)\ntypedef unsigned long long CUdeviceptr;\n#else\ntypedef unsigned int CUdeviceptr;\n#endif\n\n#endif /* __CUDA_API_VERSION >= 3020 */\n\ntypedef int CUdevice;                                     /**< CUDA device */\ntypedef struct CUctx_st *CUcontext;                       /**< CUDA context */\ntypedef struct CUmod_st *CUmodule;                        /**< CUDA module */\ntypedef struct CUfunc_st *CUfunction;                     /**< CUDA function */\ntypedef struct CUarray_st *CUarray;                       /**< CUDA array */\ntypedef struct CUtexref_st *CUtexref;                     /**< CUDA texture reference */\ntypedef struct CUsurfref_st *CUsurfref;                   /**< CUDA surface reference */\ntypedef struct CUevent_st *CUevent;                       /**< CUDA event */\ntypedef struct CUstream_st *CUstream;                     /**< CUDA stream */\ntypedef struct CUgraphicsResource_st *CUgraphicsResource; /**< CUDA graphics interop resource */\n\ntypedef struct CUuuid_st                                  /**< CUDA definition of UUID */\n{\n    char bytes[16];\n} CUuuid;\n\n/**\n * Context creation flags\n */\ntypedef enum CUctx_flags_enum\n{\n    CU_CTX_SCHED_AUTO          = 0x00, /**< Automatic scheduling */\n    CU_CTX_SCHED_SPIN          = 0x01, /**< Set spin as default scheduling */\n    CU_CTX_SCHED_YIELD         = 0x02, /**< Set yield as default scheduling */\n    CU_CTX_SCHED_BLOCKING_SYNC = 0x04, /**< Set blocking synchronization as default scheduling */\n    CU_CTX_BLOCKING_SYNC       = 0x04, /**< Set blocking synchronization as default scheduling \\deprecated */\n    CU_CTX_MAP_HOST            = 0x08, /**< Support mapped pinned allocations */\n    CU_CTX_LMEM_RESIZE_TO_MAX  = 0x10, /**< Keep local memory allocation after launch */\n#if __CUDA_API_VERSION < 4000\n    CU_CTX_SCHED_MASK          = 0x03,\n    CU_CTX_FLAGS_MASK          = 0x1f\n#else\n    CU_CTX_SCHED_MASK          = 0x07,\n    CU_CTX_PRIMARY             = 0x20, /**< Initialize and return the primary context */\n    CU_CTX_FLAGS_MASK          = 0x3f\n#endif\n} CUctx_flags;\n\n/**\n * Event creation flags\n */\ntypedef enum CUevent_flags_enum\n{\n    CU_EVENT_DEFAULT        = 0, /**< Default event flag */\n    CU_EVENT_BLOCKING_SYNC  = 1, /**< Event uses blocking synchronization */\n    CU_EVENT_DISABLE_TIMING = 2  /**< Event will not record timing data */\n} CUevent_flags;\n\n/**\n * Array formats\n */\ntypedef enum CUarray_format_enum\n{\n    CU_AD_FORMAT_UNSIGNED_INT8  = 0x01, /**< Unsigned 8-bit integers */\n    CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, /**< Unsigned 16-bit integers */\n    CU_AD_FORMAT_UNSIGNED_INT32 = 0x03, /**< Unsigned 32-bit integers */\n    CU_AD_FORMAT_SIGNED_INT8    = 0x08, /**< Signed 8-bit integers */\n    CU_AD_FORMAT_SIGNED_INT16   = 0x09, /**< Signed 16-bit integers */\n    CU_AD_FORMAT_SIGNED_INT32   = 0x0a, /**< Signed 32-bit integers */\n    CU_AD_FORMAT_HALF           = 0x10, /**< 16-bit floating point */\n    CU_AD_FORMAT_FLOAT          = 0x20  /**< 32-bit floating point */\n} CUarray_format;\n\n/**\n * Texture reference addressing modes\n */\ntypedef enum CUaddress_mode_enum\n{\n    CU_TR_ADDRESS_MODE_WRAP   = 0, /**< Wrapping address mode */\n    CU_TR_ADDRESS_MODE_CLAMP  = 1, /**< Clamp to edge address mode */\n    CU_TR_ADDRESS_MODE_MIRROR = 2, /**< Mirror address mode */\n    CU_TR_ADDRESS_MODE_BORDER = 3  /**< Border address mode */\n} CUaddress_mode;\n\n/**\n * Texture reference filtering modes\n */\ntypedef enum CUfilter_mode_enum\n{\n    CU_TR_FILTER_MODE_POINT  = 0, /**< Point filter mode */\n    CU_TR_FILTER_MODE_LINEAR = 1  /**< Linear filter mode */\n} CUfilter_mode;\n\n/**\n * Device properties\n */\ntypedef enum CUdevice_attribute_enum\n{\n    CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 1,              /**< Maximum number of threads per block */\n    CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X = 2,                    /**< Maximum block dimension X */\n    CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y = 3,                    /**< Maximum block dimension Y */\n    CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z = 4,                    /**< Maximum block dimension Z */\n    CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X = 5,                     /**< Maximum grid dimension X */\n    CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y = 6,                     /**< Maximum grid dimension Y */\n    CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z = 7,                     /**< Maximum grid dimension Z */\n    CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK = 8,        /**< Maximum shared memory available per block in bytes */\n    CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK = 8,            /**< Deprecated, use CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK */\n    CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY = 9,              /**< Memory available on device for __constant__ variables in a CUDA C kernel in bytes */\n    CU_DEVICE_ATTRIBUTE_WARP_SIZE = 10,                         /**< Warp size in threads */\n    CU_DEVICE_ATTRIBUTE_MAX_PITCH = 11,                         /**< Maximum pitch in bytes allowed by memory copies */\n    CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK = 12,           /**< Maximum number of 32-bit registers available per block */\n    CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK = 12,               /**< Deprecated, use CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK */\n    CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13,                        /**< Peak clock frequency in kilohertz */\n    CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT = 14,                 /**< Alignment requirement for textures */\n    CU_DEVICE_ATTRIBUTE_GPU_OVERLAP = 15,                       /**< Device can possibly copy memory and execute a kernel concurrently */\n    CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16,              /**< Number of multiprocessors on device */\n    CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT = 17,               /**< Specifies whether there is a run time limit on kernels */\n    CU_DEVICE_ATTRIBUTE_INTEGRATED = 18,                        /**< Device is integrated with host memory */\n    CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY = 19,               /**< Device can map host memory into CUDA address space */\n    CU_DEVICE_ATTRIBUTE_COMPUTE_MODE = 20,                      /**< Compute mode (See ::CUcomputemode for details) */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_WIDTH = 21,           /**< Maximum 1D texture width */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_WIDTH = 22,           /**< Maximum 2D texture width */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_HEIGHT = 23,          /**< Maximum 2D texture height */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_WIDTH = 24,           /**< Maximum 3D texture width */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_HEIGHT = 25,          /**< Maximum 3D texture height */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_DEPTH = 26,           /**< Maximum 3D texture depth */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_WIDTH = 27,     /**< Maximum texture array width */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_HEIGHT = 28,    /**< Maximum texture array height */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_NUMSLICES = 29, /**< Maximum slices in a texture array */\n    CU_DEVICE_ATTRIBUTE_SURFACE_ALIGNMENT = 30,                 /**< Alignment requirement for surfaces */\n    CU_DEVICE_ATTRIBUTE_CONCURRENT_KERNELS = 31,                /**< Device can possibly execute multiple kernels concurrently */\n    CU_DEVICE_ATTRIBUTE_ECC_ENABLED = 32,                       /**< Device has ECC support enabled */\n    CU_DEVICE_ATTRIBUTE_PCI_BUS_ID = 33,                        /**< PCI bus ID of the device */\n    CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID = 34,                     /**< PCI device ID of the device */\n    CU_DEVICE_ATTRIBUTE_TCC_DRIVER = 35                         /**< Device is using TCC driver model */\n\n#if __CUDA_API_VERSION >= 4000\n                                     ,\n    CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE = 36,                 /**< Peak memory clock frequency in kilohertz */\n    CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH = 37,           /**< Global memory bus width in bits */\n    CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE = 38,                     /**< Size of L2 cache in bytes */\n    CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR = 39,    /**< Maximum resident threads per multiprocessor */\n    CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT = 40,                /**< Number of asynchronous engines */\n    CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING = 41,                /**< Device uses shares a unified address space with the host */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_WIDTH = 42,   /**< Maximum 1D layered texture width */\n    CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_LAYERS = 43   /**< Maximum layers in a 1D layered texture */\n#endif\n} CUdevice_attribute;\n\n/**\n * Legacy device properties\n */\ntypedef struct CUdevprop_st\n{\n    int maxThreadsPerBlock;     /**< Maximum number of threads per block */\n    int maxThreadsDim[3];       /**< Maximum size of each dimension of a block */\n    int maxGridSize[3];         /**< Maximum size of each dimension of a grid */\n    int sharedMemPerBlock;      /**< Shared memory available per block in bytes */\n    int totalConstantMemory;    /**< Constant memory available on device in bytes */\n    int SIMDWidth;              /**< Warp size in threads */\n    int memPitch;               /**< Maximum pitch in bytes allowed by memory copies */\n    int regsPerBlock;           /**< 32-bit registers available per block */\n    int clockRate;              /**< Clock frequency in kilohertz */\n    int textureAlign;           /**< Alignment requirement for textures */\n} CUdevprop;\n\n/**\n * Function properties\n */\ntypedef enum CUfunction_attribute_enum\n{\n    /**\n     * The maximum number of threads per block, beyond which a launch of the\n     * function would fail. This number depends on both the function and the\n     * device on which the function is currently loaded.\n     */\n    CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 0,\n\n    /**\n     * The size in bytes of statically-allocated shared memory required by\n     * this function. This does not include dynamically-allocated shared\n     * memory requested by the user at runtime.\n     */\n    CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES = 1,\n\n    /**\n     * The size in bytes of user-allocated constant memory required by this\n     * function.\n     */\n    CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES = 2,\n\n    /**\n     * The size in bytes of local memory used by each thread of this function.\n     */\n    CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES = 3,\n\n    /**\n     * The number of registers used by each thread of this function.\n     */\n    CU_FUNC_ATTRIBUTE_NUM_REGS = 4,\n\n    /**\n     * The PTX virtual architecture version for which the function was\n     * compiled. This value is the major PTX version * 10 + the minor PTX\n     * version, so a PTX version 1.3 function would return the value 13.\n     * Note that this may return the undefined value of 0 for cubins\n     * compiled prior to CUDA 3.0.\n     */\n    CU_FUNC_ATTRIBUTE_PTX_VERSION = 5,\n\n    /**\n     * The binary architecture version for which the function was compiled.\n     * This value is the major binary version * 10 + the minor binary version,\n     * so a binary version 1.3 function would return the value 13. Note that\n     * this will return a value of 10 for legacy cubins that do not have a\n     * properly-encoded binary architecture version.\n     */\n    CU_FUNC_ATTRIBUTE_BINARY_VERSION = 6,\n\n    CU_FUNC_ATTRIBUTE_MAX\n} CUfunction_attribute;\n\n/**\n * Function cache configurations\n */\ntypedef enum CUfunc_cache_enum\n{\n    CU_FUNC_CACHE_PREFER_NONE    = 0x00, /**< no preference for shared memory or L1 (default) */\n    CU_FUNC_CACHE_PREFER_SHARED  = 0x01, /**< prefer larger shared memory and smaller L1 cache */\n    CU_FUNC_CACHE_PREFER_L1      = 0x02  /**< prefer larger L1 cache and smaller shared memory */\n} CUfunc_cache;\n\n/**\n * Memory types\n */\ntypedef enum CUmemorytype_enum\n{\n    CU_MEMORYTYPE_HOST    = 0x01,    /**< Host memory */\n    CU_MEMORYTYPE_DEVICE  = 0x02,    /**< Device memory */\n    CU_MEMORYTYPE_ARRAY   = 0x03     /**< Array memory */\n#if __CUDA_API_VERSION >= 4000\n                            ,\n    CU_MEMORYTYPE_UNIFIED = 0x04     /**< Unified device or host memory */\n#endif\n} CUmemorytype;\n\n/**\n * Compute Modes\n */\ntypedef enum CUcomputemode_enum\n{\n    CU_COMPUTEMODE_DEFAULT    = 0,  /**< Default compute mode (Multiple contexts allowed per device) */\n    CU_COMPUTEMODE_EXCLUSIVE         = 1, /**< Compute-exclusive-thread mode (Only one context used by a single thread can be present on this device at a time) */\n    CU_COMPUTEMODE_PROHIBITED        = 2  /**< Compute-prohibited mode (No contexts can be created on this device at this time) */\n#if __CUDA_API_VERSION >= 4000\n                                       ,\n    CU_COMPUTEMODE_EXCLUSIVE_PROCESS = 3  /**< Compute-exclusive-process mode (Only one context used by a single process can be present on this device at a time) */\n#endif\n} CUcomputemode;\n\n/**\n * Online compiler options\n */\ntypedef enum CUjit_option_enum\n{\n    /**\n     * Max number of registers that a thread may use.\\n\n     * Option type: unsigned int\n     */\n    CU_JIT_MAX_REGISTERS = 0,\n\n    /**\n     * IN: Specifies minimum number of threads per block to target compilation\n     * for\\n\n     * OUT: Returns the number of threads the compiler actually targeted.\n     * This restricts the resource utilization fo the compiler (e.g. max\n     * registers) such that a block with the given number of threads should be\n     * able to launch based on register limitations. Note, this option does not\n     * currently take into account any other resource limitations, such as\n     * shared memory utilization.\\n\n     * Option type: unsigned int\n     */\n    CU_JIT_THREADS_PER_BLOCK,\n\n    /**\n     * Returns a float value in the option of the wall clock time, in\n     * milliseconds, spent creating the cubin\\n\n     * Option type: float\n     */\n    CU_JIT_WALL_TIME,\n\n    /**\n     * Pointer to a buffer in which to print any log messsages from PTXAS\n     * that are informational in nature (the buffer size is specified via\n     * option ::CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES) \\n\n     * Option type: char*\n     */\n    CU_JIT_INFO_LOG_BUFFER,\n\n    /**\n     * IN: Log buffer size in bytes.  Log messages will be capped at this size\n     * (including null terminator)\\n\n     * OUT: Amount of log buffer filled with messages\\n\n     * Option type: unsigned int\n     */\n    CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES,\n\n    /**\n     * Pointer to a buffer in which to print any log messages from PTXAS that\n     * reflect errors (the buffer size is specified via option\n     * ::CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES)\\n\n     * Option type: char*\n     */\n    CU_JIT_ERROR_LOG_BUFFER,\n\n    /**\n     * IN: Log buffer size in bytes.  Log messages will be capped at this size\n     * (including null terminator)\\n\n     * OUT: Amount of log buffer filled with messages\\n\n     * Option type: unsigned int\n     */\n    CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES,\n\n    /**\n     * Level of optimizations to apply to generated code (0 - 4), with 4\n     * being the default and highest level of optimizations.\\n\n     * Option type: unsigned int\n     */\n    CU_JIT_OPTIMIZATION_LEVEL,\n\n    /**\n     * No option value required. Determines the target based on the current\n     * attached context (default)\\n\n     * Option type: No option value needed\n     */\n    CU_JIT_TARGET_FROM_CUCONTEXT,\n\n    /**\n     * Target is chosen based on supplied ::CUjit_target_enum.\\n\n     * Option type: unsigned int for enumerated type ::CUjit_target_enum\n     */\n    CU_JIT_TARGET,\n\n    /**\n     * Specifies choice of fallback strategy if matching cubin is not found.\n     * Choice is based on supplied ::CUjit_fallback_enum.\\n\n     * Option type: unsigned int for enumerated type ::CUjit_fallback_enum\n     */\n    CU_JIT_FALLBACK_STRATEGY\n\n} CUjit_option;\n\n/**\n * Online compilation targets\n */\ntypedef enum CUjit_target_enum\n{\n    CU_TARGET_COMPUTE_10 = 0,   /**< Compute device class 1.0 */\n    CU_TARGET_COMPUTE_11,       /**< Compute device class 1.1 */\n    CU_TARGET_COMPUTE_12,       /**< Compute device class 1.2 */\n    CU_TARGET_COMPUTE_13,       /**< Compute device class 1.3 */\n    CU_TARGET_COMPUTE_20,       /**< Compute device class 2.0 */\n    CU_TARGET_COMPUTE_21        /**< Compute device class 2.1 */\n} CUjit_target;\n\n/**\n * Cubin matching fallback strategies\n */\ntypedef enum CUjit_fallback_enum\n{\n    CU_PREFER_PTX = 0,  /**< Prefer to compile ptx */\n\n    CU_PREFER_BINARY    /**< Prefer to fall back to compatible binary code */\n\n} CUjit_fallback;\n\n/**\n * Flags to register a graphics resource\n */\ntypedef enum CUgraphicsRegisterFlags_enum\n{\n    CU_GRAPHICS_REGISTER_FLAGS_NONE          = 0x00,\n    CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY     = 0x01,\n    CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 0x02,\n    CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST  = 0x04\n} CUgraphicsRegisterFlags;\n\n/**\n * Flags for mapping and unmapping interop resources\n */\ntypedef enum CUgraphicsMapResourceFlags_enum\n{\n    CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE          = 0x00,\n    CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY     = 0x01,\n    CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD = 0x02\n} CUgraphicsMapResourceFlags;\n\n/**\n * Array indices for cube faces\n */\ntypedef enum CUarray_cubemap_face_enum\n{\n    CU_CUBEMAP_FACE_POSITIVE_X  = 0x00, /**< Positive X face of cubemap */\n    CU_CUBEMAP_FACE_NEGATIVE_X  = 0x01, /**< Negative X face of cubemap */\n    CU_CUBEMAP_FACE_POSITIVE_Y  = 0x02, /**< Positive Y face of cubemap */\n    CU_CUBEMAP_FACE_NEGATIVE_Y  = 0x03, /**< Negative Y face of cubemap */\n    CU_CUBEMAP_FACE_POSITIVE_Z  = 0x04, /**< Positive Z face of cubemap */\n    CU_CUBEMAP_FACE_NEGATIVE_Z  = 0x05  /**< Negative Z face of cubemap */\n} CUarray_cubemap_face;\n\n/**\n * Limits\n */\ntypedef enum CUlimit_enum\n{\n    CU_LIMIT_STACK_SIZE        = 0x00, /**< GPU thread stack size */\n    CU_LIMIT_PRINTF_FIFO_SIZE  = 0x01, /**< GPU printf FIFO size */\n    CU_LIMIT_MALLOC_HEAP_SIZE  = 0x02  /**< GPU malloc heap size */\n} CUlimit;\n\n/**\n * Error codes\n */\ntypedef enum cudaError_enum\n{\n    /**\n     * The API call returned with no errors. In the case of query calls, this\n     * can also mean that the operation being queried is complete (see\n     * ::cuEventQuery() and ::cuStreamQuery()).\n     */\n    CUDA_SUCCESS                              = 0,\n\n    /**\n     * This indicates that one or more of the parameters passed to the API call\n     * is not within an acceptable range of values.\n     */\n    CUDA_ERROR_INVALID_VALUE                  = 1,\n\n    /**\n     * The API call failed because it was unable to allocate enough memory to\n     * perform the requested operation.\n     */\n    CUDA_ERROR_OUT_OF_MEMORY                  = 2,\n\n    /**\n     * This indicates that the CUDA driver has not been initialized with\n     * ::cuInit() or that initialization has failed.\n     */\n    CUDA_ERROR_NOT_INITIALIZED                = 3,\n\n    /**\n     * This indicates that the CUDA driver is in the process of shutting down.\n     */\n    CUDA_ERROR_DEINITIALIZED                  = 4,\n\n    /**\n     * This indicates profiling APIs are called while application is running\n     * in visual profiler mode.\n    */\n    CUDA_ERROR_PROFILER_DISABLED           = 5,\n    /**\n     * This indicates profiling has not been initialized for this context.\n     * Call cuProfilerInitialize() to resolve this.\n    */\n    CUDA_ERROR_PROFILER_NOT_INITIALIZED       = 6,\n    /**\n     * This indicates profiler has already been started and probably\n     * cuProfilerStart() is incorrectly called.\n    */\n    CUDA_ERROR_PROFILER_ALREADY_STARTED       = 7,\n    /**\n     * This indicates profiler has already been stopped and probably\n     * cuProfilerStop() is incorrectly called.\n    */\n    CUDA_ERROR_PROFILER_ALREADY_STOPPED       = 8,\n    /**\n     * This indicates that no CUDA-capable devices were detected by the installed\n     * CUDA driver.\n     */\n    CUDA_ERROR_NO_DEVICE                      = 100,\n\n    /**\n     * This indicates that the device ordinal supplied by the user does not\n     * correspond to a valid CUDA device.\n     */\n    CUDA_ERROR_INVALID_DEVICE                 = 101,\n\n\n    /**\n     * This indicates that the device kernel image is invalid. This can also\n     * indicate an invalid CUDA module.\n     */\n    CUDA_ERROR_INVALID_IMAGE                  = 200,\n\n    /**\n     * This most frequently indicates that there is no context bound to the\n     * current thread. This can also be returned if the context passed to an\n     * API call is not a valid handle (such as a context that has had\n     * ::cuCtxDestroy() invoked on it). This can also be returned if a user\n     * mixes different API versions (i.e. 3010 context with 3020 API calls).\n     * See ::cuCtxGetApiVersion() for more details.\n     */\n    CUDA_ERROR_INVALID_CONTEXT                = 201,\n\n    /**\n     * This indicated that the context being supplied as a parameter to the\n     * API call was already the active context.\n     * \\deprecated\n     * This error return is deprecated as of CUDA 3.2. It is no longer an\n     * error to attempt to push the active context via ::cuCtxPushCurrent().\n     */\n    CUDA_ERROR_CONTEXT_ALREADY_CURRENT        = 202,\n\n    /**\n     * This indicates that a map or register operation has failed.\n     */\n    CUDA_ERROR_MAP_FAILED                     = 205,\n\n    /**\n     * This indicates that an unmap or unregister operation has failed.\n     */\n    CUDA_ERROR_UNMAP_FAILED                   = 206,\n\n    /**\n     * This indicates that the specified array is currently mapped and thus\n     * cannot be destroyed.\n     */\n    CUDA_ERROR_ARRAY_IS_MAPPED                = 207,\n\n    /**\n     * This indicates that the resource is already mapped.\n     */\n    CUDA_ERROR_ALREADY_MAPPED                 = 208,\n\n    /**\n     * This indicates that there is no kernel image available that is suitable\n     * for the device. This can occur when a user specifies code generation\n     * options for a particular CUDA source file that do not include the\n     * corresponding device configuration.\n     */\n    CUDA_ERROR_NO_BINARY_FOR_GPU              = 209,\n\n    /**\n     * This indicates that a resource has already been acquired.\n     */\n    CUDA_ERROR_ALREADY_ACQUIRED               = 210,\n\n    /**\n     * This indicates that a resource is not mapped.\n     */\n    CUDA_ERROR_NOT_MAPPED                     = 211,\n\n    /**\n     * This indicates that a mapped resource is not available for access as an\n     * array.\n     */\n    CUDA_ERROR_NOT_MAPPED_AS_ARRAY            = 212,\n\n    /**\n     * This indicates that a mapped resource is not available for access as a\n     * pointer.\n     */\n    CUDA_ERROR_NOT_MAPPED_AS_POINTER          = 213,\n\n    /**\n     * This indicates that an uncorrectable ECC error was detected during\n     * execution.\n     */\n    CUDA_ERROR_ECC_UNCORRECTABLE              = 214,\n\n    /**\n     * This indicates that the ::CUlimit passed to the API call is not\n     * supported by the active device.\n     */\n    CUDA_ERROR_UNSUPPORTED_LIMIT              = 215,\n\n    /**\n     * This indicates that the ::CUcontext passed to the API call can\n     * only be bound to a single CPU thread at a time but is already\n     * bound to a CPU thread.\n     */\n    CUDA_ERROR_CONTEXT_ALREADY_IN_USE         = 216,\n\n    /**\n     * This indicates that the device kernel source is invalid.\n     */\n    CUDA_ERROR_INVALID_SOURCE                 = 300,\n\n    /**\n     * This indicates that the file specified was not found.\n     */\n    CUDA_ERROR_FILE_NOT_FOUND                 = 301,\n\n    /**\n     * This indicates that a link to a shared object failed to resolve.\n     */\n    CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND = 302,\n\n    /**\n     * This indicates that initialization of a shared object failed.\n     */\n    CUDA_ERROR_SHARED_OBJECT_INIT_FAILED      = 303,\n\n    /**\n     * This indicates that an OS call failed.\n     */\n    CUDA_ERROR_OPERATING_SYSTEM               = 304,\n\n\n    /**\n     * This indicates that a resource handle passed to the API call was not\n     * valid. Resource handles are opaque types like ::CUstream and ::CUevent.\n     */\n    CUDA_ERROR_INVALID_HANDLE                 = 400,\n\n\n    /**\n     * This indicates that a named symbol was not found. Examples of symbols\n     * are global/constant variable names, texture names, and surface names.\n     */\n    CUDA_ERROR_NOT_FOUND                      = 500,\n\n\n    /**\n     * This indicates that asynchronous operations issued previously have not\n     * completed yet. This result is not actually an error, but must be indicated\n     * differently than ::CUDA_SUCCESS (which indicates completion). Calls that\n     * may return this value include ::cuEventQuery() and ::cuStreamQuery().\n     */\n    CUDA_ERROR_NOT_READY                      = 600,\n\n\n    /**\n     * An exception occurred on the device while executing a kernel. Common\n     * causes include dereferencing an invalid device pointer and accessing\n     * out of bounds shared memory. The context cannot be used, so it must\n     * be destroyed (and a new one should be created). All existing device\n     * memory allocations from this context are invalid and must be\n     * reconstructed if the program is to continue using CUDA.\n     */\n    CUDA_ERROR_LAUNCH_FAILED                  = 700,\n\n    /**\n     * This indicates that a launch did not occur because it did not have\n     * appropriate resources. This error usually indicates that the user has\n     * attempted to pass too many arguments to the device kernel, or the\n     * kernel launch specifies too many threads for the kernel's register\n     * count. Passing arguments of the wrong size (i.e. a 64-bit pointer\n     * when a 32-bit int is expected) is equivalent to passing too many\n     * arguments and can also result in this error.\n     */\n    CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES        = 701,\n\n    /**\n     * This indicates that the device kernel took too long to execute. This can\n     * only occur if timeouts are enabled - see the device attribute\n     * ::CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT for more information. The\n     * context cannot be used (and must be destroyed similar to\n     * ::CUDA_ERROR_LAUNCH_FAILED). All existing device memory allocations from\n     * this context are invalid and must be reconstructed if the program is to\n     * continue using CUDA.\n     */\n    CUDA_ERROR_LAUNCH_TIMEOUT                 = 702,\n\n    /**\n     * This error indicates a kernel launch that uses an incompatible texturing\n     * mode.\n     */\n    CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING  = 703,\n\n    /**\n     * This error indicates that a call to ::cuCtxEnablePeerAccess() is\n     * trying to re-enable peer access to a context which has already\n     * had peer access to it enabled.\n     */\n    CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED = 704,\n\n    /**\n     * This error indicates that a call to ::cuMemPeerRegister is trying to\n     * register memory from a context which has not had peer access\n     * enabled yet via ::cuCtxEnablePeerAccess(), or that\n     * ::cuCtxDisablePeerAccess() is trying to disable peer access\n     * which has not been enabled yet.\n     */\n    CUDA_ERROR_PEER_ACCESS_NOT_ENABLED    = 705,\n\n    /**\n     * This error indicates that a call to ::cuMemPeerRegister is trying to\n     * register already-registered memory.\n     */\n    CUDA_ERROR_PEER_MEMORY_ALREADY_REGISTERED = 706,\n\n    /**\n     * This error indicates that a call to ::cuMemPeerUnregister is trying to\n     * unregister memory that has not been registered.\n     */\n    CUDA_ERROR_PEER_MEMORY_NOT_REGISTERED     = 707,\n\n    /**\n     * This error indicates that ::cuCtxCreate was called with the flag\n     * ::CU_CTX_PRIMARY on a device which already has initialized its\n     * primary context.\n     */\n    CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE         = 708,\n\n    /**\n     * This error indicates that the context current to the calling thread\n     * has been destroyed using ::cuCtxDestroy, or is a primary context which\n     * has not yet been initialized.\n     */\n    CUDA_ERROR_CONTEXT_IS_DESTROYED           = 709,\n\n    /**\n     * This indicates that an unknown internal error has occurred.\n     */\n    CUDA_ERROR_UNKNOWN                        = 999\n} CUresult;\n\n#if __CUDA_API_VERSION >= 4000\n/**\n * If set, host memory is portable between CUDA contexts.\n * Flag for ::cuMemHostAlloc()\n */\n#define CU_MEMHOSTALLOC_PORTABLE        0x01\n\n/**\n * If set, host memory is mapped into CUDA address space and\n * ::cuMemHostGetDevicePointer() may be called on the host pointer.\n * Flag for ::cuMemHostAlloc()\n */\n#define CU_MEMHOSTALLOC_DEVICEMAP       0x02\n\n/**\n * If set, host memory is allocated as write-combined - fast to write,\n * faster to DMA, slow to read except via SSE4 streaming load instruction\n * (MOVNTDQA).\n * Flag for ::cuMemHostAlloc()\n */\n#define CU_MEMHOSTALLOC_WRITECOMBINED   0x04\n\n/**\n * If set, host memory is portable between CUDA contexts.\n * Flag for ::cuMemHostRegister()\n */\n#define CU_MEMHOSTREGISTER_PORTABLE     0x01\n\n/**\n * If set, host memory is mapped into CUDA address space and\n * ::cuMemHostGetDevicePointer() may be called on the host pointer.\n * Flag for ::cuMemHostRegister()\n */\n#define CU_MEMHOSTREGISTER_DEVICEMAP    0x02\n\n/**\n * If set, peer memory is mapped into CUDA address space and\n * ::cuMemPeerGetDevicePointer() may be called on the host pointer.\n * Flag for ::cuMemPeerRegister()\n */\n#define CU_MEMPEERREGISTER_DEVICEMAP    0x02\n#endif\n\n#if __CUDA_API_VERSION >= 3020\n\n/**\n * 2D memory copy parameters\n */\ntypedef struct CUDA_MEMCPY2D_st\n{\n    size_t srcXInBytes;         /**< Source X in bytes */\n    size_t srcY;                /**< Source Y */\n\n    CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */\n    const void *srcHost;        /**< Source host pointer */\n    CUdeviceptr srcDevice;      /**< Source device pointer */\n    CUarray srcArray;           /**< Source array reference */\n    size_t srcPitch;            /**< Source pitch (ignored when src is array) */\n\n    size_t dstXInBytes;         /**< Destination X in bytes */\n    size_t dstY;                /**< Destination Y */\n\n    CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */\n    void *dstHost;              /**< Destination host pointer */\n    CUdeviceptr dstDevice;      /**< Destination device pointer */\n    CUarray dstArray;           /**< Destination array reference */\n    size_t dstPitch;            /**< Destination pitch (ignored when dst is array) */\n\n    size_t WidthInBytes;        /**< Width of 2D memory copy in bytes */\n    size_t Height;              /**< Height of 2D memory copy */\n} CUDA_MEMCPY2D;\n\n/**\n * 3D memory copy parameters\n */\ntypedef struct CUDA_MEMCPY3D_st\n{\n    size_t srcXInBytes;         /**< Source X in bytes */\n    size_t srcY;                /**< Source Y */\n    size_t srcZ;                /**< Source Z */\n    size_t srcLOD;              /**< Source LOD */\n    CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */\n    const void *srcHost;        /**< Source host pointer */\n    CUdeviceptr srcDevice;      /**< Source device pointer */\n    CUarray srcArray;           /**< Source array reference */\n    void *reserved0;            /**< Must be NULL */\n    size_t srcPitch;            /**< Source pitch (ignored when src is array) */\n    size_t srcHeight;           /**< Source height (ignored when src is array; may be 0 if Depth==1) */\n\n    size_t dstXInBytes;         /**< Destination X in bytes */\n    size_t dstY;                /**< Destination Y */\n    size_t dstZ;                /**< Destination Z */\n    size_t dstLOD;              /**< Destination LOD */\n    CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */\n    void *dstHost;              /**< Destination host pointer */\n    CUdeviceptr dstDevice;      /**< Destination device pointer */\n    CUarray dstArray;           /**< Destination array reference */\n    void *reserved1;            /**< Must be NULL */\n    size_t dstPitch;            /**< Destination pitch (ignored when dst is array) */\n    size_t dstHeight;           /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */\n\n    size_t WidthInBytes;        /**< Width of 3D memory copy in bytes */\n    size_t Height;              /**< Height of 3D memory copy */\n    size_t Depth;               /**< Depth of 3D memory copy */\n} CUDA_MEMCPY3D;\n\n/**\n * 3D memory cross-context copy parameters\n */\ntypedef struct CUDA_MEMCPY3D_PEER_st\n{\n    size_t srcXInBytes;         /**< Source X in bytes */\n    size_t srcY;                /**< Source Y */\n    size_t srcZ;                /**< Source Z */\n    size_t srcLOD;              /**< Source LOD */\n    CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */\n    const void *srcHost;        /**< Source host pointer */\n    CUdeviceptr srcDevice;      /**< Source device pointer */\n    CUarray srcArray;           /**< Source array reference */\n    CUcontext srcContext;       /**< Source context (ignored with srcMemoryType is ::CU_MEMORYTYPE_ARRAY) */\n    size_t srcPitch;            /**< Source pitch (ignored when src is array) */\n    size_t srcHeight;           /**< Source height (ignored when src is array; may be 0 if Depth==1) */\n\n    size_t dstXInBytes;         /**< Destination X in bytes */\n    size_t dstY;                /**< Destination Y */\n    size_t dstZ;                /**< Destination Z */\n    size_t dstLOD;              /**< Destination LOD */\n    CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */\n    void *dstHost;              /**< Destination host pointer */\n    CUdeviceptr dstDevice;      /**< Destination device pointer */\n    CUarray dstArray;           /**< Destination array reference */\n    CUcontext dstContext;       /**< Destination context (ignored with dstMemoryType is ::CU_MEMORYTYPE_ARRAY) */\n    size_t dstPitch;            /**< Destination pitch (ignored when dst is array) */\n    size_t dstHeight;           /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */\n\n    size_t WidthInBytes;        /**< Width of 3D memory copy in bytes */\n    size_t Height;              /**< Height of 3D memory copy */\n    size_t Depth;               /**< Depth of 3D memory copy */\n} CUDA_MEMCPY3D_PEER;\n\n/**\n * Array descriptor\n */\ntypedef struct CUDA_ARRAY_DESCRIPTOR_st\n{\n    size_t Width;             /**< Width of array */\n    size_t Height;            /**< Height of array */\n\n    CUarray_format Format;    /**< Array format */\n    unsigned int NumChannels; /**< Channels per array element */\n} CUDA_ARRAY_DESCRIPTOR;\n\n/**\n * 3D array descriptor\n */\ntypedef struct CUDA_ARRAY3D_DESCRIPTOR_st\n{\n    size_t Width;             /**< Width of 3D array */\n    size_t Height;            /**< Height of 3D array */\n    size_t Depth;             /**< Depth of 3D array */\n\n    CUarray_format Format;    /**< Array format */\n    unsigned int NumChannels; /**< Channels per array element */\n    unsigned int Flags;       /**< Flags */\n} CUDA_ARRAY3D_DESCRIPTOR;\n\n#endif /* __CUDA_API_VERSION >= 3020 */\n\n/**\n * If set, the CUDA array is a collection of layers, where each layer is either a 1D\n * or a 2D array and the Depth member of CUDA_ARRAY3D_DESCRIPTOR specifies the number\n * of layers, not the depth of a 3D array.\n */\n#define CUDA_ARRAY3D_LAYERED        0x01\n\n/**\n * Deprecated, use CUDA_ARRAY3D_LAYERED\n */\n#define CUDA_ARRAY3D_2DARRAY        0x01\n\n/**\n * This flag must be set in order to bind a surface reference\n * to the CUDA array\n */\n#define CUDA_ARRAY3D_SURFACE_LDST   0x02\n\n/**\n * Override the texref format with a format inferred from the array.\n * Flag for ::cuTexRefSetArray()\n */\n#define CU_TRSA_OVERRIDE_FORMAT 0x01\n\n/**\n * Read the texture as integers rather than promoting the values to floats\n * in the range [0,1].\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_READ_AS_INTEGER         0x01\n\n/**\n * Use normalized texture coordinates in the range [0,1) instead of [0,dim).\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_NORMALIZED_COORDINATES  0x02\n\n/**\n * Perform sRGB->linear conversion during texture read.\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_SRGB  0x10\n\n/**\n * End of array terminator for the \\p extra parameter to\n * ::cuLaunchKernel\n */\n#define CU_LAUNCH_PARAM_END            ((void*)0x00)\n\n/**\n * Indicator that the next value in the \\p extra parameter to\n * ::cuLaunchKernel will be a pointer to a buffer containing all kernel\n * parameters used for launching kernel \\p f.  This buffer needs to\n * honor all alignment/padding requirements of the individual parameters.\n * If ::CU_LAUNCH_PARAM_BUFFER_SIZE is not also specified in the\n * \\p extra array, then ::CU_LAUNCH_PARAM_BUFFER_POINTER will have no\n * effect.\n */\n#define CU_LAUNCH_PARAM_BUFFER_POINTER ((void*)0x01)\n\n/**\n * Indicator that the next value in the \\p extra parameter to\n * ::cuLaunchKernel will be a pointer to a size_t which contains the\n * size of the buffer specified with ::CU_LAUNCH_PARAM_BUFFER_POINTER.\n * It is required that ::CU_LAUNCH_PARAM_BUFFER_POINTER also be specified\n * in the \\p extra array if the value associated with\n * ::CU_LAUNCH_PARAM_BUFFER_SIZE is not zero.\n */\n#define CU_LAUNCH_PARAM_BUFFER_SIZE    ((void*)0x02)\n\n/**\n * For texture references loaded into the module, use default texunit from\n * texture reference.\n */\n#define CU_PARAM_TR_DEFAULT -1\n\n/**\n * CUDA API made obselete at API version 3020\n */\n#if defined(__CUDA_API_VERSION_INTERNAL)\n#define CUdeviceptr                  CUdeviceptr_v1\n#define CUDA_MEMCPY2D_st             CUDA_MEMCPY2D_v1_st\n#define CUDA_MEMCPY2D                CUDA_MEMCPY2D_v1\n#define CUDA_MEMCPY3D_st             CUDA_MEMCPY3D_v1_st\n#define CUDA_MEMCPY3D                CUDA_MEMCPY3D_v1\n#define CUDA_ARRAY_DESCRIPTOR_st     CUDA_ARRAY_DESCRIPTOR_v1_st\n#define CUDA_ARRAY_DESCRIPTOR        CUDA_ARRAY_DESCRIPTOR_v1\n#define CUDA_ARRAY3D_DESCRIPTOR_st   CUDA_ARRAY3D_DESCRIPTOR_v1_st\n#define CUDA_ARRAY3D_DESCRIPTOR      CUDA_ARRAY3D_DESCRIPTOR_v1\n#endif /* CUDA_FORCE_LEGACY32_INTERNAL */\n\n#if defined(__CUDA_API_VERSION_INTERNAL) || __CUDA_API_VERSION < 3020\n\ntypedef unsigned int CUdeviceptr;\n\ntypedef struct CUDA_MEMCPY2D_st\n{\n    unsigned int srcXInBytes;   /**< Source X in bytes */\n    unsigned int srcY;          /**< Source Y */\n    CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */\n    const void *srcHost;        /**< Source host pointer */\n    CUdeviceptr srcDevice;      /**< Source device pointer */\n    CUarray srcArray;           /**< Source array reference */\n    unsigned int srcPitch;      /**< Source pitch (ignored when src is array) */\n\n    unsigned int dstXInBytes;   /**< Destination X in bytes */\n    unsigned int dstY;          /**< Destination Y */\n    CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */\n    void *dstHost;              /**< Destination host pointer */\n    CUdeviceptr dstDevice;      /**< Destination device pointer */\n    CUarray dstArray;           /**< Destination array reference */\n    unsigned int dstPitch;      /**< Destination pitch (ignored when dst is array) */\n\n    unsigned int WidthInBytes;  /**< Width of 2D memory copy in bytes */\n    unsigned int Height;        /**< Height of 2D memory copy */\n} CUDA_MEMCPY2D;\n\ntypedef struct CUDA_MEMCPY3D_st\n{\n    unsigned int srcXInBytes;   /**< Source X in bytes */\n    unsigned int srcY;          /**< Source Y */\n    unsigned int srcZ;          /**< Source Z */\n    unsigned int srcLOD;        /**< Source LOD */\n    CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */\n    const void *srcHost;        /**< Source host pointer */\n    CUdeviceptr srcDevice;      /**< Source device pointer */\n    CUarray srcArray;           /**< Source array reference */\n    void *reserved0;            /**< Must be NULL */\n    unsigned int srcPitch;      /**< Source pitch (ignored when src is array) */\n    unsigned int srcHeight;     /**< Source height (ignored when src is array; may be 0 if Depth==1) */\n\n    unsigned int dstXInBytes;   /**< Destination X in bytes */\n    unsigned int dstY;          /**< Destination Y */\n    unsigned int dstZ;          /**< Destination Z */\n    unsigned int dstLOD;        /**< Destination LOD */\n    CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */\n    void *dstHost;              /**< Destination host pointer */\n    CUdeviceptr dstDevice;      /**< Destination device pointer */\n    CUarray dstArray;           /**< Destination array reference */\n    void *reserved1;            /**< Must be NULL */\n    unsigned int dstPitch;      /**< Destination pitch (ignored when dst is array) */\n    unsigned int dstHeight;     /**< Destination height (ignored when dst is array; may be 0 if Depth==1) */\n\n    unsigned int WidthInBytes;  /**< Width of 3D memory copy in bytes */\n    unsigned int Height;        /**< Height of 3D memory copy */\n    unsigned int Depth;         /**< Depth of 3D memory copy */\n} CUDA_MEMCPY3D;\n\ntypedef struct CUDA_ARRAY_DESCRIPTOR_st\n{\n    unsigned int Width;         /**< Width of array */\n    unsigned int Height;        /**< Height of array */\n\n    CUarray_format Format;      /**< Array format */\n    unsigned int NumChannels;   /**< Channels per array element */\n} CUDA_ARRAY_DESCRIPTOR;\n\ntypedef struct CUDA_ARRAY3D_DESCRIPTOR_st\n{\n    unsigned int Width;         /**< Width of 3D array */\n    unsigned int Height;        /**< Height of 3D array */\n    unsigned int Depth;         /**< Depth of 3D array */\n\n    CUarray_format Format;      /**< Array format */\n    unsigned int NumChannels;   /**< Channels per array element */\n    unsigned int Flags;         /**< Flags */\n} CUDA_ARRAY3D_DESCRIPTOR;\n\n#endif /* (__CUDA_API_VERSION_INTERNAL) || __CUDA_API_VERSION < 3020 */\n\n/*\n * If set, the CUDA array contains an array of 2D slices\n * and the Depth member of CUDA_ARRAY3D_DESCRIPTOR specifies\n * the number of slices, not the depth of a 3D array.\n */\n#define CUDA_ARRAY3D_2DARRAY        0x01\n\n/**\n * This flag must be set in order to bind a surface reference\n * to the CUDA array\n */\n#define CUDA_ARRAY3D_SURFACE_LDST   0x02\n\n/**\n * Override the texref format with a format inferred from the array.\n * Flag for ::cuTexRefSetArray()\n */\n#define CU_TRSA_OVERRIDE_FORMAT 0x01\n\n/**\n * Read the texture as integers rather than promoting the values to floats\n * in the range [0,1].\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_READ_AS_INTEGER         0x01\n\n/**\n * Use normalized texture coordinates in the range [0,1) instead of [0,dim).\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_NORMALIZED_COORDINATES  0x02\n\n/**\n * Perform sRGB->linear conversion during texture read.\n * Flag for ::cuTexRefSetFlags()\n */\n#define CU_TRSF_SRGB  0x10\n\n/**\n * For texture references loaded into the module, use default texunit from\n * texture reference.\n */\n#define CU_PARAM_TR_DEFAULT -1\n\n/** @} */ /* END CUDA_TYPES */\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#define CUDAAPI __stdcall\n#else\n#define CUDAAPI\n#endif\n\n/**\n * \\defgroup CUDA_INITIALIZE Initialization\n *\n * This section describes the initialization functions of the low-level CUDA\n * driver application programming interface.\n *\n * @{\n */\n\n/*********************************\n ** Initialization\n *********************************/\ntypedef CUresult  CUDAAPI tcuInit(unsigned int Flags);\n\n/*********************************\n ** Driver Version Query\n *********************************/\ntypedef CUresult  CUDAAPI tcuDriverGetVersion(int *driverVersion);\n\n/************************************\n **\n **    Device management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuDeviceGet(CUdevice *device, int ordinal);\ntypedef CUresult  CUDAAPI tcuDeviceGetCount(int *count);\ntypedef CUresult  CUDAAPI tcuDeviceGetName(char *name, int len, CUdevice dev);\ntypedef CUresult  CUDAAPI tcuDeviceComputeCapability(int *major, int *minor, CUdevice dev);\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult  CUDAAPI tcuDeviceTotalMem(size_t *bytes, CUdevice dev);\n#else\ntypedef CUresult  CUDAAPI tcuDeviceTotalMem(unsigned int *bytes, CUdevice dev);\n#endif\n\ntypedef CUresult  CUDAAPI tcuDeviceGetProperties(CUdevprop *prop, CUdevice dev);\ntypedef CUresult  CUDAAPI tcuDeviceGetAttribute(int *pi, CUdevice_attribute attrib, CUdevice dev);\n\n/************************************\n **\n **    Context management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev);\ntypedef CUresult  CUDAAPI tcuCtxDestroy(CUcontext ctx);\ntypedef CUresult  CUDAAPI tcuCtxAttach(CUcontext *pctx, unsigned int flags);\ntypedef CUresult  CUDAAPI tcuCtxDetach(CUcontext ctx);\ntypedef CUresult  CUDAAPI tcuCtxPushCurrent(CUcontext ctx);\ntypedef CUresult  CUDAAPI tcuCtxPopCurrent(CUcontext *pctx);\n\ntypedef CUresult  CUDAAPI tcuCtxSetCurrent(CUcontext ctx);\ntypedef CUresult  CUDAAPI tcuCtxGetCurrent(CUcontext *pctx);\n\ntypedef CUresult  CUDAAPI tcuCtxGetDevice(CUdevice *device);\ntypedef CUresult  CUDAAPI tcuCtxSynchronize(void);\n\n\n/************************************\n **\n **    Module management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuModuleLoad(CUmodule *module, const char *fname);\ntypedef CUresult  CUDAAPI tcuModuleLoadData(CUmodule *module, const void *image);\ntypedef CUresult  CUDAAPI tcuModuleLoadDataEx(CUmodule *module, const void *image, unsigned int numOptions, CUjit_option *options, void **optionValues);\ntypedef CUresult  CUDAAPI tcuModuleLoadFatBinary(CUmodule *module, const void *fatCubin);\ntypedef CUresult  CUDAAPI tcuModuleUnload(CUmodule hmod);\ntypedef CUresult  CUDAAPI tcuModuleGetFunction(CUfunction *hfunc, CUmodule hmod, const char *name);\n\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult  CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, size_t *bytes, CUmodule hmod, const char *name);\n#else\ntypedef CUresult  CUDAAPI tcuModuleGetGlobal(CUdeviceptr *dptr, unsigned int *bytes, CUmodule hmod, const char *name);\n#endif\n\ntypedef CUresult  CUDAAPI tcuModuleGetTexRef(CUtexref *pTexRef, CUmodule hmod, const char *name);\ntypedef CUresult  CUDAAPI tcuModuleGetSurfRef(CUsurfref *pSurfRef, CUmodule hmod, const char *name);\n\n/************************************\n **\n **    Memory management\n **\n ***********************************/\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult CUDAAPI tcuMemGetInfo(size_t *free, size_t *total);\ntypedef CUresult CUDAAPI tcuMemAlloc(CUdeviceptr *dptr, size_t bytesize);\ntypedef CUresult CUDAAPI tcuMemGetAddressRange(CUdeviceptr *pbase, size_t *psize, CUdeviceptr dptr);\ntypedef CUresult CUDAAPI tcuMemAllocPitch(CUdeviceptr *dptr,\n                                          size_t *pPitch,\n                                          size_t WidthInBytes,\n                                          size_t Height,\n                                          // size of biggest r/w to be performed by kernels on this memory\n                                          // 4, 8 or 16 bytes\n                                          unsigned int ElementSizeBytes\n                                         );\n#else\ntypedef CUresult CUDAAPI tcuMemGetInfo(unsigned int *free, unsigned int *total);\ntypedef CUresult CUDAAPI tcuMemAlloc(CUdeviceptr *dptr, unsigned int bytesize);\ntypedef CUresult CUDAAPI tcuMemGetAddressRange(CUdeviceptr *pbase, unsigned int *psize, CUdeviceptr dptr);\ntypedef CUresult CUDAAPI tcuMemAllocPitch(CUdeviceptr *dptr,\n                                          unsigned int *pPitch,\n                                          unsigned int WidthInBytes,\n                                          unsigned int Height,\n                                          // size of biggest r/w to be performed by kernels on this memory\n                                          // 4, 8 or 16 bytes\n                                          unsigned int ElementSizeBytes\n                                         );\n#endif\n\ntypedef CUresult CUDAAPI tcuMemFree(CUdeviceptr dptr);\n\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult CUDAAPI tcuMemAllocHost(void **pp, size_t bytesize);\n#else\ntypedef CUresult CUDAAPI tcuMemAllocHost(void **pp, unsigned int bytesize);\n#endif\n\ntypedef CUresult CUDAAPI tcuMemFreeHost(void *p);\ntypedef CUresult CUDAAPI tcuMemHostAlloc(void **pp, size_t bytesize, unsigned int Flags);\n\ntypedef CUresult CUDAAPI tcuMemHostGetDevicePointer(CUdeviceptr *pdptr, void *p, unsigned int Flags);\ntypedef CUresult CUDAAPI tcuMemHostGetFlags(unsigned int *pFlags, void *p);\n\ntypedef CUresult CUDAAPI tcuMemHostRegister(void *p, size_t bytesize, unsigned int Flags);\ntypedef CUresult CUDAAPI tcuMemHostUnregister(void *p);;\ntypedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount);\ntypedef CUresult CUDAAPI tcuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount);\n\n/************************************\n **\n **    Synchronous Memcpy\n **\n ** Intra-device memcpy's done with these functions may execute in parallel with the CPU,\n ** but if host memory is involved, they wait until the copy is done before returning.\n **\n ***********************************/\n\n// 1D functions\n#if __CUDA_API_VERSION >= 3020\n// system <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoD(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyDtoH(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount);\n\n// device <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoD(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount);\n\n// device <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoA(CUarray dstArray, size_t dstOffset, CUdeviceptr srcDevice, size_t ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoD(CUdeviceptr dstDevice, CUarray srcArray, size_t srcOffset, size_t ByteCount);\n\n// system <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoA(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoH(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount);\n\n// array <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyAtoA(CUarray dstArray, size_t dstOffset, CUarray srcArray, size_t srcOffset, size_t ByteCount);\n#else\n// system <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoD(CUdeviceptr dstDevice, const void *srcHost, unsigned int ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyDtoH(void *dstHost, CUdeviceptr srcDevice, unsigned int ByteCount);\n\n// device <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoD(CUdeviceptr dstDevice, CUdeviceptr srcDevice, unsigned int ByteCount);\n\n// device <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoA(CUarray dstArray, unsigned int dstOffset, CUdeviceptr srcDevice, unsigned int ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoD(CUdeviceptr dstDevice, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount);\n\n// system <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoA(CUarray dstArray, unsigned int dstOffset, const void *srcHost, unsigned int ByteCount);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoH(void *dstHost, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount);\n\n// array <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyAtoA(CUarray dstArray, unsigned int dstOffset, CUarray srcArray, unsigned int srcOffset, unsigned int ByteCount);\n#endif\n\n// 2D memcpy\n\ntypedef CUresult  CUDAAPI tcuMemcpy2D(const CUDA_MEMCPY2D *pCopy);\ntypedef CUresult  CUDAAPI tcuMemcpy2DUnaligned(const CUDA_MEMCPY2D *pCopy);\n\n// 3D memcpy\n\ntypedef CUresult  CUDAAPI tcuMemcpy3D(const CUDA_MEMCPY3D *pCopy);\n\n/************************************\n **\n **    Asynchronous Memcpy\n **\n ** Any host memory involved must be DMA'able (e.g., allocated with cuMemAllocHost).\n ** memcpy's done with these functions execute in parallel with the CPU and, if\n ** the hardware is available, may execute in parallel with the GPU.\n ** Asynchronous memcpy must be accompanied by appropriate stream synchronization.\n **\n ***********************************/\n\n// 1D functions\n#if __CUDA_API_VERSION >= 3020\n// system <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoDAsync(CUdeviceptr dstDevice,\n                                             const void *srcHost, size_t ByteCount, CUstream hStream);\ntypedef CUresult  CUDAAPI tcuMemcpyDtoHAsync(void *dstHost,\n                                             CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream);\n\n// device <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoDAsync(CUdeviceptr dstDevice,\n                                             CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream);\n\n// system <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoAAsync(CUarray dstArray, size_t dstOffset,\n                                             const void *srcHost, size_t ByteCount, CUstream hStream);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoHAsync(void *dstHost, CUarray srcArray, size_t srcOffset,\n                                             size_t ByteCount, CUstream hStream);\n\n#else\n// system <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoDAsync(CUdeviceptr dstDevice,\n                                             const void *srcHost, unsigned int ByteCount, CUstream hStream);\ntypedef CUresult  CUDAAPI tcuMemcpyDtoHAsync(void *dstHost,\n                                             CUdeviceptr srcDevice, unsigned int ByteCount, CUstream hStream);\n\n// device <-> device memory\ntypedef CUresult  CUDAAPI tcuMemcpyDtoDAsync(CUdeviceptr dstDevice,\n                                             CUdeviceptr srcDevice, unsigned int ByteCount, CUstream hStream);\n\n// system <-> array memory\ntypedef CUresult  CUDAAPI tcuMemcpyHtoAAsync(CUarray dstArray, unsigned int dstOffset,\n                                             const void *srcHost, unsigned int ByteCount, CUstream hStream);\ntypedef CUresult  CUDAAPI tcuMemcpyAtoHAsync(void *dstHost, CUarray srcArray, unsigned int srcOffset,\n                                             unsigned int ByteCount, CUstream hStream);\n#endif\n\n// 2D memcpy\ntypedef CUresult  CUDAAPI tcuMemcpy2DAsync(const CUDA_MEMCPY2D *pCopy, CUstream hStream);\n\n// 3D memcpy\ntypedef CUresult  CUDAAPI tcuMemcpy3DAsync(const CUDA_MEMCPY3D *pCopy, CUstream hStream);\n\n/************************************\n **\n **    Memset\n **\n ***********************************/\ntypedef CUresult  CUDAAPI tcuMemsetD8(CUdeviceptr dstDevice, unsigned char uc, unsigned int N);\ntypedef CUresult  CUDAAPI tcuMemsetD16(CUdeviceptr dstDevice, unsigned short us, unsigned int N);\ntypedef CUresult  CUDAAPI tcuMemsetD32(CUdeviceptr dstDevice, unsigned int ui, unsigned int N);\n\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult  CUDAAPI tcuMemsetD2D8(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned char uc, size_t Width, size_t Height);\ntypedef CUresult  CUDAAPI tcuMemsetD2D16(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned short us, size_t Width, size_t Height);\ntypedef CUresult  CUDAAPI tcuMemsetD2D32(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned int ui, size_t Width, size_t Height);\n#else\ntypedef CUresult  CUDAAPI tcuMemsetD2D8(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned char uc, unsigned int Width, unsigned int Height);\ntypedef CUresult  CUDAAPI tcuMemsetD2D16(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned short us, unsigned int Width, unsigned int Height);\ntypedef CUresult  CUDAAPI tcuMemsetD2D32(CUdeviceptr dstDevice, unsigned int dstPitch, unsigned int ui, unsigned int Width, unsigned int Height);\n#endif\n\n/************************************\n **\n **    Function management\n **\n ***********************************/\n\n\ntypedef CUresult CUDAAPI tcuFuncSetBlockShape(CUfunction hfunc, int x, int y, int z);\ntypedef CUresult CUDAAPI tcuFuncSetSharedSize(CUfunction hfunc, unsigned int bytes);\ntypedef CUresult CUDAAPI tcuFuncGetAttribute(int *pi, CUfunction_attribute attrib, CUfunction hfunc);\ntypedef CUresult CUDAAPI tcuFuncSetCacheConfig(CUfunction hfunc, CUfunc_cache config);\ntypedef CUresult CUDAAPI tcuLaunchKernel(CUfunction f,\n                                         unsigned int gridDimX,  unsigned int gridDimY,  unsigned int gridDimZ,\n                                         unsigned int blockDimX, unsigned int blockDimY, unsigned int blockDimZ,\n                                         unsigned int sharedMemBytes,\n                                         CUstream hStream, void **kernelParams, void **extra);\n\n/************************************\n **\n **    Array management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuArrayCreate(CUarray *pHandle, const CUDA_ARRAY_DESCRIPTOR *pAllocateArray);\ntypedef CUresult  CUDAAPI tcuArrayGetDescriptor(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray);\ntypedef CUresult  CUDAAPI tcuArrayDestroy(CUarray hArray);\n\ntypedef CUresult  CUDAAPI tcuArray3DCreate(CUarray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pAllocateArray);\ntypedef CUresult  CUDAAPI tcuArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor, CUarray hArray);\n\n\n/************************************\n **\n **    Texture reference management\n **\n ***********************************/\ntypedef CUresult  CUDAAPI tcuTexRefCreate(CUtexref *pTexRef);\ntypedef CUresult  CUDAAPI tcuTexRefDestroy(CUtexref hTexRef);\n\ntypedef CUresult  CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned int Flags);\n\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult  CUDAAPI tcuTexRefSetAddress(size_t *ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, size_t bytes);\ntypedef CUresult  CUDAAPI tcuTexRefSetAddress2D(CUtexref hTexRef, const CUDA_ARRAY_DESCRIPTOR *desc, CUdeviceptr dptr, size_t Pitch);\n#else\ntypedef CUresult  CUDAAPI tcuTexRefSetAddress(unsigned int *ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, unsigned int bytes);\ntypedef CUresult  CUDAAPI tcuTexRefSetAddress2D(CUtexref hTexRef, const CUDA_ARRAY_DESCRIPTOR *desc, CUdeviceptr dptr, unsigned int Pitch);\n#endif\n\ntypedef CUresult  CUDAAPI tcuTexRefSetFormat(CUtexref hTexRef, CUarray_format fmt, int NumPackedComponents);\ntypedef CUresult  CUDAAPI tcuTexRefSetAddressMode(CUtexref hTexRef, int dim, CUaddress_mode am);\ntypedef CUresult  CUDAAPI tcuTexRefSetFilterMode(CUtexref hTexRef, CUfilter_mode fm);\ntypedef CUresult  CUDAAPI tcuTexRefSetFlags(CUtexref hTexRef, unsigned int Flags);\n\ntypedef CUresult  CUDAAPI tcuTexRefGetAddress(CUdeviceptr *pdptr, CUtexref hTexRef);\ntypedef CUresult  CUDAAPI tcuTexRefGetArray(CUarray *phArray, CUtexref hTexRef);\ntypedef CUresult  CUDAAPI tcuTexRefGetAddressMode(CUaddress_mode *pam, CUtexref hTexRef, int dim);\ntypedef CUresult  CUDAAPI tcuTexRefGetFilterMode(CUfilter_mode *pfm, CUtexref hTexRef);\ntypedef CUresult  CUDAAPI tcuTexRefGetFormat(CUarray_format *pFormat, int *pNumChannels, CUtexref hTexRef);\ntypedef CUresult  CUDAAPI tcuTexRefGetFlags(unsigned int *pFlags, CUtexref hTexRef);\n\n/************************************\n **\n **    Surface reference management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuSurfRefSetArray(CUsurfref hSurfRef, CUarray hArray, unsigned int Flags);\ntypedef CUresult  CUDAAPI tcuSurfRefGetArray(CUarray *phArray, CUsurfref hSurfRef);\n\n/************************************\n **\n **    Parameter management\n **\n ***********************************/\n\ntypedef CUresult  CUDAAPI tcuParamSetSize(CUfunction hfunc, unsigned int numbytes);\ntypedef CUresult  CUDAAPI tcuParamSeti(CUfunction hfunc, int offset, unsigned int value);\ntypedef CUresult  CUDAAPI tcuParamSetf(CUfunction hfunc, int offset, float value);\ntypedef CUresult  CUDAAPI tcuParamSetv(CUfunction hfunc, int offset, void *ptr, unsigned int numbytes);\ntypedef CUresult  CUDAAPI tcuParamSetTexRef(CUfunction hfunc, int texunit, CUtexref hTexRef);\n\n\n/************************************\n **\n **    Launch functions\n **\n ***********************************/\n\ntypedef CUresult CUDAAPI tcuLaunch(CUfunction f);\ntypedef CUresult CUDAAPI tcuLaunchGrid(CUfunction f, int grid_width, int grid_height);\ntypedef CUresult CUDAAPI tcuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream);\n\n/************************************\n **\n **    Events\n **\n ***********************************/\ntypedef CUresult CUDAAPI tcuEventCreate(CUevent *phEvent, unsigned int Flags);\ntypedef CUresult CUDAAPI tcuEventRecord(CUevent hEvent, CUstream hStream);\ntypedef CUresult CUDAAPI tcuEventQuery(CUevent hEvent);\ntypedef CUresult CUDAAPI tcuEventSynchronize(CUevent hEvent);\ntypedef CUresult CUDAAPI tcuEventDestroy(CUevent hEvent);\ntypedef CUresult CUDAAPI tcuEventElapsedTime(float *pMilliseconds, CUevent hStart, CUevent hEnd);\n\n/************************************\n **\n **    Streams\n **\n ***********************************/\ntypedef CUresult CUDAAPI  tcuStreamCreate(CUstream *phStream, unsigned int Flags);\ntypedef CUresult CUDAAPI  tcuStreamQuery(CUstream hStream);\ntypedef CUresult CUDAAPI  tcuStreamSynchronize(CUstream hStream);\ntypedef CUresult CUDAAPI  tcuStreamDestroy(CUstream hStream);\n\n/************************************\n **\n **    Graphics interop\n **\n ***********************************/\ntypedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource);\ntypedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);\n\n#if __CUDA_API_VERSION >= 3020\ntypedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer(CUdeviceptr *pDevPtr, size_t *pSize, CUgraphicsResource resource);\n#else\ntypedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer(CUdeviceptr *pDevPtr, unsigned int *pSize, CUgraphicsResource resource);\n#endif\n\ntypedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags(CUgraphicsResource resource, unsigned int flags);\ntypedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource *resources, CUstream hStream);\ntypedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource *resources, CUstream hStream);\n\n/************************************\n **\n **    Export tables\n **\n ***********************************/\ntypedef CUresult CUDAAPI tcuGetExportTable(const void **ppExportTable, const CUuuid *pExportTableId);\n\n/************************************\n **\n **    Limits\n **\n ***********************************/\n\ntypedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value);\ntypedef CUresult CUDAAPI tcuCtxGetLimit(size_t *pvalue, CUlimit limit);\n\n\n/************************************\n ************************************/\n\nextern CUresult CUDAAPI cuInit(unsigned int, int cudaVersion);\n\nextern tcuDriverGetVersion             *cuDriverGetVersion;\nextern tcuDeviceGet                    *cuDeviceGet;\nextern tcuDeviceGetCount               *cuDeviceGetCount;\nextern tcuDeviceGetName                *cuDeviceGetName;\nextern tcuDeviceComputeCapability      *cuDeviceComputeCapability;\nextern tcuDeviceGetProperties          *cuDeviceGetProperties;\nextern tcuDeviceGetAttribute           *cuDeviceGetAttribute;\nextern tcuCtxDestroy                   *cuCtxDestroy;\nextern tcuCtxAttach                    *cuCtxAttach;\nextern tcuCtxDetach                    *cuCtxDetach;\nextern tcuCtxPushCurrent               *cuCtxPushCurrent;\nextern tcuCtxPopCurrent                *cuCtxPopCurrent;\n\nextern tcuCtxSetCurrent                *cuCtxSetCurrent;\nextern tcuCtxGetCurrent                *cuCtxGetCurrent;\n\nextern tcuCtxGetDevice                 *cuCtxGetDevice;\nextern tcuCtxSynchronize               *cuCtxSynchronize;\nextern tcuModuleLoad                   *cuModuleLoad;\nextern tcuModuleLoadData               *cuModuleLoadData;\nextern tcuModuleLoadDataEx             *cuModuleLoadDataEx;\nextern tcuModuleLoadFatBinary          *cuModuleLoadFatBinary;\nextern tcuModuleUnload                 *cuModuleUnload;\nextern tcuModuleGetFunction            *cuModuleGetFunction;\nextern tcuModuleGetTexRef              *cuModuleGetTexRef;\nextern tcuModuleGetSurfRef             *cuModuleGetSurfRef;\nextern tcuMemFreeHost                  *cuMemFreeHost;\nextern tcuMemHostAlloc                 *cuMemHostAlloc;\nextern tcuMemHostGetFlags              *cuMemHostGetFlags;\n\nextern tcuMemHostRegister              *cuMemHostRegister;\nextern tcuMemHostUnregister            *cuMemHostUnregister;\nextern tcuMemcpy                       *cuMemcpy;\nextern tcuMemcpyPeer                   *cuMemcpyPeer;\n\nextern tcuDeviceTotalMem               *cuDeviceTotalMem;\nextern tcuCtxCreate                    *cuCtxCreate;\nextern tcuModuleGetGlobal              *cuModuleGetGlobal;\nextern tcuMemGetInfo                   *cuMemGetInfo;\nextern tcuMemAlloc                     *cuMemAlloc;\nextern tcuMemAllocPitch                *cuMemAllocPitch;\nextern tcuMemFree                      *cuMemFree;\nextern tcuMemGetAddressRange           *cuMemGetAddressRange;\nextern tcuMemAllocHost                 *cuMemAllocHost;\nextern tcuMemHostGetDevicePointer      *cuMemHostGetDevicePointer;\nextern tcuFuncSetBlockShape            *cuFuncSetBlockShape;\nextern tcuFuncSetSharedSize            *cuFuncSetSharedSize;\nextern tcuFuncGetAttribute             *cuFuncGetAttribute;\nextern tcuFuncSetCacheConfig           *cuFuncSetCacheConfig;\nextern tcuLaunchKernel                 *cuLaunchKernel;\nextern tcuArrayDestroy                 *cuArrayDestroy;\nextern tcuTexRefCreate                 *cuTexRefCreate;\nextern tcuTexRefDestroy                *cuTexRefDestroy;\nextern tcuTexRefSetArray               *cuTexRefSetArray;\nextern tcuTexRefSetFormat              *cuTexRefSetFormat;\nextern tcuTexRefSetAddressMode         *cuTexRefSetAddressMode;\nextern tcuTexRefSetFilterMode          *cuTexRefSetFilterMode;\nextern tcuTexRefSetFlags               *cuTexRefSetFlags;\nextern tcuTexRefGetArray               *cuTexRefGetArray;\nextern tcuTexRefGetAddressMode         *cuTexRefGetAddressMode;\nextern tcuTexRefGetFilterMode          *cuTexRefGetFilterMode;\nextern tcuTexRefGetFormat              *cuTexRefGetFormat;\nextern tcuTexRefGetFlags               *cuTexRefGetFlags;\nextern tcuSurfRefSetArray              *cuSurfRefSetArray;\nextern tcuSurfRefGetArray              *cuSurfRefGetArray;\nextern tcuParamSetSize                 *cuParamSetSize;\nextern tcuParamSeti                    *cuParamSeti;\nextern tcuParamSetf                    *cuParamSetf;\nextern tcuParamSetv                    *cuParamSetv;\nextern tcuParamSetTexRef               *cuParamSetTexRef;\nextern tcuLaunch                       *cuLaunch;\nextern tcuLaunchGrid                   *cuLaunchGrid;\nextern tcuLaunchGridAsync              *cuLaunchGridAsync;\nextern tcuEventCreate                  *cuEventCreate;\nextern tcuEventRecord                  *cuEventRecord;\nextern tcuEventQuery                   *cuEventQuery;\nextern tcuEventSynchronize             *cuEventSynchronize;\nextern tcuEventDestroy                 *cuEventDestroy;\nextern tcuEventElapsedTime             *cuEventElapsedTime;\nextern tcuStreamCreate                 *cuStreamCreate;\nextern tcuStreamQuery                  *cuStreamQuery;\nextern tcuStreamSynchronize            *cuStreamSynchronize;\nextern tcuStreamDestroy                *cuStreamDestroy;\nextern tcuGraphicsUnregisterResource         *cuGraphicsUnregisterResource;\nextern tcuGraphicsSubResourceGetMappedArray  *cuGraphicsSubResourceGetMappedArray;\nextern tcuGraphicsResourceSetMapFlags        *cuGraphicsResourceSetMapFlags;\nextern tcuGraphicsMapResources               *cuGraphicsMapResources;\nextern tcuGraphicsUnmapResources             *cuGraphicsUnmapResources;\nextern tcuGetExportTable                     *cuGetExportTable;\nextern tcuCtxSetLimit                        *cuCtxSetLimit;\nextern tcuCtxGetLimit                        *cuCtxGetLimit;\n\n// These functions could be using the CUDA 3.2 interface (_v2)\nextern tcuMemcpyHtoD                   *cuMemcpyHtoD;\nextern tcuMemcpyDtoH                   *cuMemcpyDtoH;\nextern tcuMemcpyDtoD                   *cuMemcpyDtoD;\nextern tcuMemcpyDtoA                   *cuMemcpyDtoA;\nextern tcuMemcpyAtoD                   *cuMemcpyAtoD;\nextern tcuMemcpyHtoA                   *cuMemcpyHtoA;\nextern tcuMemcpyAtoH                   *cuMemcpyAtoH;\nextern tcuMemcpyAtoA                   *cuMemcpyAtoA;\nextern tcuMemcpy2D                     *cuMemcpy2D;\nextern tcuMemcpy2DUnaligned            *cuMemcpy2DUnaligned;\nextern tcuMemcpy3D                     *cuMemcpy3D;\nextern tcuMemcpyHtoDAsync              *cuMemcpyHtoDAsync;\nextern tcuMemcpyDtoHAsync              *cuMemcpyDtoHAsync;\nextern tcuMemcpyDtoDAsync              *cuMemcpyDtoDAsync;\nextern tcuMemcpyHtoAAsync              *cuMemcpyHtoAAsync;\nextern tcuMemcpyAtoHAsync              *cuMemcpyAtoHAsync;\nextern tcuMemcpy2DAsync                *cuMemcpy2DAsync;\nextern tcuMemcpy3DAsync                *cuMemcpy3DAsync;\nextern tcuMemsetD8                     *cuMemsetD8;\nextern tcuMemsetD16                    *cuMemsetD16;\nextern tcuMemsetD32                    *cuMemsetD32;\nextern tcuMemsetD2D8                   *cuMemsetD2D8;\nextern tcuMemsetD2D16                  *cuMemsetD2D16;\nextern tcuMemsetD2D32                  *cuMemsetD2D32;\nextern tcuArrayCreate                  *cuArrayCreate;\nextern tcuArrayGetDescriptor           *cuArrayGetDescriptor;\nextern tcuArray3DCreate                *cuArray3DCreate;\nextern tcuArray3DGetDescriptor         *cuArray3DGetDescriptor;\nextern tcuTexRefSetAddress             *cuTexRefSetAddress;\nextern tcuTexRefSetAddress2D           *cuTexRefSetAddress2D;\nextern tcuTexRefGetAddress             *cuTexRefGetAddress;\nextern tcuGraphicsResourceGetMappedPointer   *cuGraphicsResourceGetMappedPointer;\n\n#ifdef __cplusplus\n}\n#endif\n\n//#undef __CUDA_API_VERSION\n\n#endif //__cuda_drvapi_dynlink_cuda_h__\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_d3d.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef __cuda_drvapi_dynlink_d3d_h__\n#define __cuda_drvapi_dynlink_d3d_h__\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#pragma warning(disable: 4312)\n\n#if defined (CUDA_INIT_D3D9) || defined(CUDA_INIT_D3D10) || defined(CUDA_INIT_D3D11)\n#include <Windows.h>\n#include <mmsystem.h>\n#endif\n\n#ifdef CUDA_INIT_D3D9\n#include <d3dx9.h>\n#pragma warning( disable : 4996 ) // disable deprecated warning \n#include <strsafe.h>\n#pragma warning( default : 4996 )\n\n/**\n * CUDA 2.x compatibility - Flags to register a D3D9 graphics resource\n */\ntypedef enum CUd3d9register_flags_enum\n{\n    CU_D3D9_REGISTER_FLAGS_NONE  = 0x00,\n    CU_D3D9_REGISTER_FLAGS_ARRAY = 0x01,\n} CUd3d9register_flags;\n\n/**\n * CUDA 2.x compatibility - Flags for D3D9 mapping and unmapping interop resources\n */\ntypedef enum CUd3d9map_flags_enum\n{\n    CU_D3D9_MAPRESOURCE_FLAGS_NONE         = 0x00,\n    CU_D3D9_MAPRESOURCE_FLAGS_READONLY     = 0x01,\n    CU_D3D9_MAPRESOURCE_FLAGS_WRITEDISCARD = 0x02,\n} CUd3d9map_flags;\n\n// D3D9/CUDA interop (CUDA 1.x compatible API). These functions are deprecated, please use the ones below\ntypedef CUresult CUDAAPI tcuD3D9Begin(IDirect3DDevice9 *pDevice);\ntypedef CUresult CUDAAPI tcuD3D9End(void);\ntypedef CUresult CUDAAPI tcuD3D9RegisterVertexBuffer(IDirect3DVertexBuffer9 *pVB);\ntypedef CUresult CUDAAPI tcuD3D9MapVertexBuffer(CUdeviceptr *pDevPtr, unsigned int *pSize, IDirect3DVertexBuffer9 *pVB);\ntypedef CUresult CUDAAPI tcuD3D9UnmapVertexBuffer(IDirect3DVertexBuffer9 *pVB);\ntypedef CUresult CUDAAPI tcuD3D9UnregisterVertexBuffer(IDirect3DVertexBuffer9 *pVB);\n\n// D3D9/CUDA interop (CUDA 2.x compatible)\ntypedef CUresult CUDAAPI tcuD3D9GetDirect3DDevice(IDirect3DDevice9 **ppD3DDevice);\ntypedef CUresult CUDAAPI tcuD3D9RegisterResource(IDirect3DResource9 *pResource, unsigned int Flags);\ntypedef CUresult CUDAAPI tcuD3D9UnregisterResource(IDirect3DResource9 *pResource);\n\ntypedef CUresult CUDAAPI tcuD3D9MapResources(unsigned int count, IDirect3DResource9 **ppResource);\ntypedef CUresult CUDAAPI tcuD3D9UnmapResources(unsigned int count, IDirect3DResource9 **ppResource);\ntypedef CUresult CUDAAPI tcuD3D9ResourceSetMapFlags(IDirect3DResource9 *pResource, unsigned int Flags);\n\ntypedef CUresult CUDAAPI tcuD3D9ResourceGetSurfaceDimensions(unsigned int *pWidth, unsigned int *pHeight, unsigned int *pDepth, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level);\ntypedef CUresult CUDAAPI tcuD3D9ResourceGetMappedArray(CUarray *pArray, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level);\ntypedef CUresult CUDAAPI tcuD3D9ResourceGetMappedPointer(CUdeviceptr *pDevPtr, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level);\ntypedef CUresult CUDAAPI tcuD3D9ResourceGetMappedSize(unsigned int *pSize, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level);\ntypedef CUresult CUDAAPI tcuD3D9ResourceGetMappedPitch(unsigned int *pPitch, unsigned int *pPitchSlice, IDirect3DResource9 *pResource, unsigned int Face, unsigned int Level);\n\n// D3D9/CUDA interop (CUDA 2.0+)\ntypedef CUresult CUDAAPI tcuD3D9GetDevice(CUdevice *pCudaDevice, const char *pszAdapterName);\ntypedef CUresult CUDAAPI tcuD3D9CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, IDirect3DDevice9 *pD3DDevice);\ntypedef CUresult CUDAAPI tcuGraphicsD3D9RegisterResource(CUgraphicsResource *pCudaResource, IDirect3DResource9 *pD3DResource, unsigned int Flags);\n#endif\n\n#ifdef CUDA_INIT_D3D10\n#include <dxgi.h>\n#include <d3d10_1.h>\n#include <d3d10.h>\n#include <d3dx10.h>\n\n#pragma warning( disable : 4996 ) // disable deprecated warning \n#include <strsafe.h>\n#pragma warning( default : 4996 )\n\n// D3D11/CUDA interop (CUDA 3.0)\ntypedef CUresult CUDAAPI tcuD3D10GetDevice(CUdevice *pCudaDevice, IDXGIAdapter *pAdapter);\ntypedef CUresult CUDAAPI tcuD3D10CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, ID3D10Device *pD3DDevice);\ntypedef CUresult CUDAAPI tcuGraphicsD3D10RegisterResource(CUgraphicsResource *pCudaResource, ID3D10Resource *pD3DResource, unsigned int Flags);\n#endif // CUDA_INIT_D3D10\n\n#ifdef CUDA_INIT_D3D11\n#include <dxgi.h>\n#include <d3d11.h>\n#include <d3dx11.h>\n\n#pragma warning( disable : 4996 ) // disable deprecated warning \n#include <strsafe.h>\n#pragma warning( default : 4996 )\n\n// D3D11/CUDA interop (CUDA 3.0)\ntypedef CUresult CUDAAPI tcuD3D11GetDevice(CUdevice *pCudaDevice, IDXGIAdapter *pAdapter);\ntypedef CUresult CUDAAPI tcuD3D11CtxCreate(CUcontext *pCtx, CUdevice *pCudaDevice, unsigned int Flags, ID3D11Device *pD3DDevice);\ntypedef CUresult CUDAAPI tcuGraphicsD3D11RegisterResource(CUgraphicsResource *pCudaResource, ID3D11Resource *pD3DResource, unsigned int Flags);\n#endif // CUDA_INIT_D3D11\n\n#endif // WIN32\n\n#endif // __cuda_drvapi_dynlink_cuda_d3d_h__\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink/cuda_drvapi_dynlink_gl.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef __cuda_drvapi_dynlink_cuda_gl_h__\n#define __cuda_drvapi_dynlink_cuda_gl_h__\n\n#ifdef CUDA_INIT_OPENGL\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#  define WINDOWS_LEAN_AND_MEAN\n#  define NOMINMAX\n#  include <windows.h>\n#endif\n\n// includes, system\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <math.h>\n\n// includes, GL\n#include <GL/glew.h>\n\n#if defined (__APPLE__) || defined(MACOSX)\n#include <GLUT/glut.h>\n#else\n#include <GL/freeglut.h>\n#endif\n\n/************************************\n **\n **    OpenGL Graphics/Interop\n **\n ***********************************/\n\n// OpenGL/CUDA interop (CUDA 2.0+)\ntypedef CUresult CUDAAPI tcuGLCtxCreate(CUcontext *pCtx, unsigned int Flags, CUdevice device);\ntypedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource *pCudaResource, GLuint buffer, unsigned int Flags);\ntypedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource *pCudaResource, GLuint image, GLenum target, unsigned int Flags);\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#include <GL/wglext.h>\n// WIN32\ntypedef CUresult CUDAAPI tcuWGLGetDevice(CUdevice *pDevice, HGPUNV hGpu);\n#endif\n\n#endif // CUDA_INIT_OPENGL\n\n#endif // __cuda_drvapi_dynlink_cuda_gl_h__\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink_d3d10.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//--------------------------------------------------------------------------------------\n// File: dynlink_d3d10.h\n//\n// Shortcut macros and functions for using DX objects\n//\n// Copyright (c) Microsoft Corporation. All rights reserved\n//--------------------------------------------------------------------------------------\n\n#ifndef _DYNLINK_D3D10_H_\n#define _DYNLINK_D3D10_H_\n\n// Standard Windows includes\n#include <windows.h>\n#include <initguid.h>\n#include <assert.h>\n#include <wchar.h>\n#include <mmsystem.h>\n#include <commctrl.h> // for InitCommonControls() \n#include <shellapi.h> // for ExtractIcon()\n#include <new.h>      // for placement new\n#include <shlobj.h>\n#include <math.h>\n#include <limits.h>\n#include <stdio.h>\n\n// CRT's memory leak detection\n#if defined(DEBUG) || defined(_DEBUG)\n#include <crtdbg.h>\n#endif\n\n// Direct3D9 includes\n#include <d3d9.h>\n#include <d3dx9.h>\n\n// Direct3D10 includes\n#include <dxgi.h>\n#include <d3d10_1.h>\n#include <d3d10.h>\n#include <d3dx10.h>\n\n// XInput includes\n#include <xinput.h>\n\n// HRESULT translation for Direct3D10 and other APIs\n#include <dxerr.h>\n\n// strsafe.h deprecates old unsecure string functions.  If you\n// really do not want to it to (not recommended), then uncomment the next line\n//#define STRSAFE_NO_DEPRECATE\n\n#ifndef STRSAFE_NO_DEPRECATE\n#pragma deprecated(\"strncpy\")\n#pragma deprecated(\"wcsncpy\")\n#pragma deprecated(\"_tcsncpy\")\n#pragma deprecated(\"wcsncat\")\n#pragma deprecated(\"strncat\")\n#pragma deprecated(\"_tcsncat\")\n#endif\n\n#pragma warning( disable : 4996 ) // disable deprecated warning \n#include <strsafe.h>\n#pragma warning( default : 4996 )\n\n//--------------------------------------------------------------------------------------\n// Structs\n//--------------------------------------------------------------------------------------\nstruct DXUTD3D9DeviceSettings\n{\n    UINT AdapterOrdinal;\n    D3DDEVTYPE DeviceType;\n    D3DFORMAT AdapterFormat;\n    DWORD BehaviorFlags;\n    D3DPRESENT_PARAMETERS pp;\n};\n\nstruct DXUTD3D10DeviceSettings\n{\n    UINT AdapterOrdinal;\n    D3D10_DRIVER_TYPE DriverType;\n    UINT Output;\n    DXGI_SWAP_CHAIN_DESC sd;\n    UINT32 CreateFlags;\n    UINT32 SyncInterval;\n    DWORD PresentFlags;\n    bool AutoCreateDepthStencil; // DXUT will create the a depth stencil resource and view if true\n    DXGI_FORMAT AutoDepthStencilFormat;\n};\n\nenum DXUTDeviceVersion { DXUT_D3D9_DEVICE, DXUT_D3D10_DEVICE };\nstruct DXUTDeviceSettings\n{\n    DXUTDeviceVersion ver;\n    union\n    {\n        DXUTD3D9DeviceSettings d3d9; // only valid if ver == DXUT_D3D9_DEVICE\n        DXUTD3D10DeviceSettings d3d10; // only valid if ver == DXUT_D3D10_DEVICE\n    };\n};\n\n\n//--------------------------------------------------------------------------------------\n// Error codes\n//--------------------------------------------------------------------------------------\n#define DXUTERR_NODIRECT3D              MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0901)\n#define DXUTERR_NOCOMPATIBLEDEVICES     MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0902)\n#define DXUTERR_MEDIANOTFOUND           MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0903)\n#define DXUTERR_NONZEROREFCOUNT         MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0904)\n#define DXUTERR_CREATINGDEVICE          MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0905)\n#define DXUTERR_RESETTINGDEVICE         MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0906)\n#define DXUTERR_CREATINGDEVICEOBJECTS   MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0907)\n#define DXUTERR_RESETTINGDEVICEOBJECTS  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0908)\n#define DXUTERR_DEVICEREMOVED           MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x090A)\n\n\ntypedef HRESULT(WINAPI *LPCREATEDXGIFACTORY)(REFIID, void **);\ntypedef HRESULT(WINAPI *LPD3D10CREATEDEVICE)(IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT, UINT32,\n                                             ID3D10Device **);\ntypedef HRESULT(WINAPI *LPD3D10CREATEDEVICE1)(IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT,\n                                              D3D10_FEATURE_LEVEL1, UINT, ID3D10Device1 **);\ntypedef HRESULT(WINAPI *LPD3D10CREATESTATEBLOCK)(ID3D10Device *pDevice, D3D10_STATE_BLOCK_MASK *pStateBlockMask,\n                                                 ID3D10StateBlock **ppStateBlock);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKUNION)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB,\n                                                    D3D10_STATE_BLOCK_MASK *pResult);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKINTERSECT)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB,\n                                                        D3D10_STATE_BLOCK_MASK *pResult);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDIFFERENCE)(D3D10_STATE_BLOCK_MASK *pA, D3D10_STATE_BLOCK_MASK *pB,\n                                                         D3D10_STATE_BLOCK_MASK *pResult);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKENABLECAPTURE)(D3D10_STATE_BLOCK_MASK *pMask,\n                                                            D3D10_DEVICE_STATE_TYPES StateType, UINT RangeStart,\n                                                            UINT RangeLength);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDISABLECAPTURE)(D3D10_STATE_BLOCK_MASK *pMask,\n        D3D10_DEVICE_STATE_TYPES StateType, UINT RangeStart,\n        UINT RangeLength);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKENABLEALL)(D3D10_STATE_BLOCK_MASK *pMask);\ntypedef HRESULT(WINAPI *LPD3D10STATEBLOCKMASKDISABLEALL)(D3D10_STATE_BLOCK_MASK *pMask);\ntypedef BOOL (WINAPI *LPD3D10STATEBLOCKMASKGETSETTING)(D3D10_STATE_BLOCK_MASK *pMask,\n                                                       D3D10_DEVICE_STATE_TYPES StateType, UINT Entry);\n\ntypedef HRESULT(WINAPI *LPD3D10COMPILEEFFECTFROMMEMORY)(void *pData, SIZE_T DataLength, LPCSTR pSrcFileName,\n                                                        CONST D3D10_SHADER_MACRO *pDefines,\n                                                        ID3D10Include *pInclude, UINT HLSLFlags, UINT FXFlags,\n                                                        ID3D10Blob **ppCompiledEffect, ID3D10Blob **ppErrors);\ntypedef HRESULT(WINAPI *LPD3D10CREATEEFFECTFROMMEMORY)(void *pData, SIZE_T DataLength, UINT FXFlags,\n                                                       ID3D10Device *pDevice,\n                                                       ID3D10EffectPool *pEffectPool,\n                                                       ID3D10Effect **ppEffect);\ntypedef HRESULT(WINAPI *LPD3D10CREATEEFFECTPOOLFROMMEMORY)(void *pData, SIZE_T DataLength, UINT FXFlags,\n                                                           ID3D10Device *pDevice, ID3D10EffectPool **ppEffectPool);\n\ntypedef HRESULT(WINAPI *LPD3D10CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter *pAdapter,\n                                                         D3D10_DRIVER_TYPE DriverType,\n                                                         HMODULE Software,\n                                                         UINT Flags,\n                                                         UINT SDKVersion,\n                                                         DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,\n                                                         IDXGISwapChain **ppSwapChain,\n                                                         ID3D10Device **ppDevice);\n\ntypedef HRESULT(WINAPI *LPD3D10CREATEDEVICEANDSWAPCHAIN1)(IDXGIAdapter *pAdapter,\n                                                          D3D10_DRIVER_TYPE DriverType,\n                                                          HMODULE Software,\n                                                          UINT Flags,\n                                                          D3D10_FEATURE_LEVEL1 HardwareLevel,\n                                                          UINT SDKVersion,\n                                                          DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,\n                                                          IDXGISwapChain **ppSwapChain,\n                                                          ID3D10Device1 **ppDevice);\n\n// Build a perspective projection matrix. (left-handed)\ntypedef D3DXMATRIX *(WINAPI *LPD3DXMATRIXPERSPECTIVEFOVLH)(D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf);\n\n// Build a lookat matrix. (left-handed)\ntypedef D3DXMATRIX *(WINAPI *LPD3DXMATRIXLOOKATLH)(D3DXMATRIX *pOut, CONST D3DXVECTOR3 *pEye, CONST D3DXVECTOR3 *pAt, CONST D3DXVECTOR3 *pUp);\n\n// Module and function pointers\nstatic HMODULE                              g_hModDXGI = NULL;\nstatic HMODULE                              g_hModD3DX10 = NULL;\nstatic HMODULE                              g_hModD3D10 = NULL;\nstatic HMODULE                              g_hModD3D101 = NULL;\nstatic LPCREATEDXGIFACTORY                  sFnPtr_CreateDXGIFactory = NULL;\nstatic LPD3D10CREATESTATEBLOCK              sFnPtr_D3D10CreateStateBlock = NULL;\nstatic LPD3D10CREATEDEVICE                  sFnPtr_D3D10CreateDevice = NULL;\nstatic LPD3D10CREATEDEVICE1                 sFnPtr_D3D10CreateDevice1 = NULL;\nstatic LPD3D10STATEBLOCKMASKUNION           sFnPtr_D3D10StateBlockMaskUnion = NULL;\nstatic LPD3D10STATEBLOCKMASKINTERSECT       sFnPtr_D3D10StateBlockMaskIntersect = NULL;\nstatic LPD3D10STATEBLOCKMASKDIFFERENCE      sFnPtr_D3D10StateBlockMaskDifference = NULL;\nstatic LPD3D10STATEBLOCKMASKENABLECAPTURE   sFnPtr_D3D10StateBlockMaskEnableCapture = NULL;\nstatic LPD3D10STATEBLOCKMASKDISABLECAPTURE  sFnPtr_D3D10StateBlockMaskDisableCapture = NULL;\nstatic LPD3D10STATEBLOCKMASKENABLEALL       sFnPtr_D3D10StateBlockMaskEnableAll = NULL;\nstatic LPD3D10STATEBLOCKMASKDISABLEALL      sFnPtr_D3D10StateBlockMaskDisableAll = NULL;\nstatic LPD3D10STATEBLOCKMASKGETSETTING      sFnPtr_D3D10StateBlockMaskGetSetting = NULL;\nstatic LPD3D10COMPILEEFFECTFROMMEMORY       sFnPtr_D3D10CompileEffectFromMemory = NULL;\nstatic LPD3D10CREATEEFFECTFROMMEMORY        sFnPtr_D3D10CreateEffectFromMemory = NULL;\nstatic LPD3D10CREATEEFFECTPOOLFROMMEMORY    sFnPtr_D3D10CreateEffectPoolFromMemory = NULL;\nstatic LPD3D10CREATEDEVICEANDSWAPCHAIN      sFnPtr_D3D10CreateDeviceAndSwapChain  = NULL;\nstatic LPD3D10CREATEDEVICEANDSWAPCHAIN1     sFnPtr_D3D10CreateDeviceAndSwapChain1 = NULL;\nstatic LPD3DXMATRIXPERSPECTIVEFOVLH         sFnPtr_D3DXMatrixPerspectiveFovLH = NULL;\nstatic LPD3DXMATRIXLOOKATLH                 sFnPtr_D3DXMatrixLookAtLH = NULL;\n\n// unload the D3D10 DLLs\nstatic bool dynlinkUnloadD3D10API(void)\n{\n    if (g_hModD3D10)\n    {\n        FreeLibrary(g_hModD3D10);\n        g_hModD3D10 = NULL;\n    }\n\n    if (g_hModD3DX10)\n    {\n        FreeLibrary(g_hModD3DX10);\n        g_hModD3DX10 = NULL;\n    }\n\n    if (g_hModDXGI)\n    {\n        FreeLibrary(g_hModDXGI);\n        g_hModDXGI = NULL;\n    }\n\n    if (g_hModD3D101)\n    {\n        FreeLibrary(g_hModD3D101);\n        g_hModD3D101 = NULL;\n    }\n\n    return true;\n}\n\n// Dynamically load the D3D10 DLLs loaded and map the function pointers\nstatic bool dynlinkLoadD3D10API(void)\n{\n    // First check to see if the D3D10 Library is present.\n    // if it succeeds, then we can call GetProcAddress to grab all of the DX10 functions\n    g_hModD3D10 = LoadLibrary(\"d3d10.dll\");\n\n    if (g_hModD3D10 != NULL)\n    {\n        sFnPtr_D3D10CreateStateBlock             = (LPD3D10CREATESTATEBLOCK)           GetProcAddress(g_hModD3D10, \"D3D10CreateStateBlock\");\n        sFnPtr_D3D10CreateDevice                 = (LPD3D10CREATEDEVICE)           GetProcAddress(g_hModD3D10, \"D3D10CreateDevice\");\n\n        sFnPtr_D3D10StateBlockMaskUnion          = (LPD3D10STATEBLOCKMASKUNION)        GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskUnion\");\n        sFnPtr_D3D10StateBlockMaskIntersect      = (LPD3D10STATEBLOCKMASKINTERSECT)    GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskIntersect\");\n        sFnPtr_D3D10StateBlockMaskDifference     = (LPD3D10STATEBLOCKMASKDIFFERENCE)   GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskDifference\");\n        sFnPtr_D3D10StateBlockMaskEnableCapture  = (LPD3D10STATEBLOCKMASKENABLECAPTURE) GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskEnableCapture\");\n        sFnPtr_D3D10StateBlockMaskDisableCapture = (LPD3D10STATEBLOCKMASKDISABLECAPTURE)GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskDisableCapture\");\n\n        sFnPtr_D3D10StateBlockMaskEnableAll      = (LPD3D10STATEBLOCKMASKENABLEALL)    GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskEnableAll\");\n        sFnPtr_D3D10StateBlockMaskDisableAll     = (LPD3D10STATEBLOCKMASKDISABLEALL)   GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskDisableAll\");\n        sFnPtr_D3D10StateBlockMaskGetSetting     = (LPD3D10STATEBLOCKMASKGETSETTING)   GetProcAddress(g_hModD3D10, \"D3D10StateBlockMaskGetSetting\");\n\n        sFnPtr_D3D10CompileEffectFromMemory      = (LPD3D10COMPILEEFFECTFROMMEMORY)    GetProcAddress(g_hModD3D10, \"D3D10CompileEffectFromMemory\");\n        sFnPtr_D3D10CreateEffectFromMemory       = (LPD3D10CREATEEFFECTFROMMEMORY)     GetProcAddress(g_hModD3D10, \"D3D10CreateEffectFromMemory\");\n        sFnPtr_D3D10CreateEffectPoolFromMemory   = (LPD3D10CREATEEFFECTPOOLFROMMEMORY) GetProcAddress(g_hModD3D10, \"D3D10CreateEffectPoolFromMemory\");\n\n        sFnPtr_D3D10CreateDeviceAndSwapChain     = (LPD3D10CREATEDEVICEANDSWAPCHAIN)    GetProcAddress(g_hModD3D10, \"D3D10CreateDeviceAndSwapChain\");\n    }\n\n    g_hModD3DX10 = LoadLibrary(\"d3dx10.dll\");\n\n    if (g_hModD3DX10)\n    {\n        sFnPtr_D3DXMatrixPerspectiveFovLH        = (LPD3DXMATRIXPERSPECTIVEFOVLH)  GetProcAddress(g_hModD3DX10, \"D3DXMatrixPerspectiveFovLH\");\n        sFnPtr_D3DXMatrixLookAtLH                = (LPD3DXMATRIXLOOKATLH)          GetProcAddress(g_hModD3DX10, \"D3DXMatrixLookAtLH\");\n    }\n\n    g_hModDXGI = LoadLibrary(\"dxgi.dll\");\n\n    if (g_hModDXGI)\n    {\n        sFnPtr_CreateDXGIFactory                 = (LPCREATEDXGIFACTORY)           GetProcAddress(g_hModDXGI , \"CreateDXGIFactory\");\n    }\n\n    // This may fail if this machine isn't Windows Vista SP1 or later\n    g_hModD3D101 = LoadLibrary(\"d3d10_1.dll\");\n\n    if (g_hModD3D101 != NULL)\n    {\n        sFnPtr_D3D10CreateDevice1                = (LPD3D10CREATEDEVICE1)              GetProcAddress(g_hModD3D101, \"D3D10CreateDevice1\");\n        sFnPtr_D3D10CreateDeviceAndSwapChain1    = (LPD3D10CREATEDEVICEANDSWAPCHAIN1)   GetProcAddress(g_hModD3D101, \"D3D10CreateDeviceAndSwapChain1\");\n    }\n\n    if (g_hModD3D10 == NULL || g_hModD3DX10 == NULL || g_hModDXGI == NULL || g_hModD3D101 == NULL)\n    {\n        dynlinkUnloadD3D10API();\n        return false;\n    }\n\n    return true;\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/dynlink_d3d11.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//--------------------------------------------------------------------------------------\n// File: dynlink_d3d11.h\n//\n// Shortcut macros and functions for using DX objects\n//\n// Copyright (c) Microsoft Corporation. All rights reserved\n//--------------------------------------------------------------------------------------\n\n#ifndef _DYNLINK_D3D11_H_\n#define _DYNLINK_D3D11_H_\n\n// Standard Windows includes\n#include <windows.h>\n#include <initguid.h>\n#include <assert.h>\n#include <wchar.h>\n#include <mmsystem.h>\n#include <commctrl.h> // for InitCommonControls() \n#include <shellapi.h> // for ExtractIcon()\n#include <new.h>      // for placement new\n#include <shlobj.h>\n#include <math.h>\n#include <limits.h>\n#include <stdio.h>\n\n// CRT's memory leak detection\n#if defined(DEBUG) || defined(_DEBUG)\n#include <crtdbg.h>\n#endif\n\n// Direct3D9 includes\n//#include <d3d9.h>\n//#include <d3dx9.h>\n\n// Direct3D10 includes\n#include <dxgi.h>\n#include <d3d11.h>\n#include <d3dx11.h>\n// #include <..\\Samples\\C++\\Effects11\\Inc\\d3dx11effect.h>\n\n// XInput includes\n#include <xinput.h>\n\n// HRESULT translation for Direct3D10 and other APIs\n#include <dxerr.h>\n\n// strsafe.h deprecates old unsecure string functions.  If you\n// really do not want to it to (not recommended), then uncomment the next line\n//#define STRSAFE_NO_DEPRECATE\n\n#ifndef STRSAFE_NO_DEPRECATE\n#pragma deprecated(\"strncpy\")\n#pragma deprecated(\"wcsncpy\")\n#pragma deprecated(\"_tcsncpy\")\n#pragma deprecated(\"wcsncat\")\n#pragma deprecated(\"strncat\")\n#pragma deprecated(\"_tcsncat\")\n#endif\n\n#pragma warning( disable : 4996 ) // disable deprecated warning \n#include <strsafe.h>\n#pragma warning( default : 4996 )\n\ntypedef HRESULT(WINAPI *LPCREATEDXGIFACTORY)(REFIID, void **);\ntypedef HRESULT(WINAPI *LPD3D11CREATEDEVICEANDSWAPCHAIN)(__in_opt IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, __in_ecount_opt(FeatureLevels) CONST D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, __in_opt CONST DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, __out_opt IDXGISwapChain **ppSwapChain, __out_opt ID3D11Device **ppDevice, __out_opt D3D_FEATURE_LEVEL *pFeatureLevel, __out_opt ID3D11DeviceContext **ppImmediateContext);\ntypedef HRESULT(WINAPI *LPD3D11CREATEDEVICE)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT32, D3D_FEATURE_LEVEL *, UINT, UINT32, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **);\ntypedef void (WINAPI *LPD3DX11COMPILEFROMMEMORY)(LPCSTR pSrcData, SIZE_T SrcDataLen, LPCSTR pFileName, CONST D3D10_SHADER_MACRO *pDefines, LPD3D10INCLUDE pInclude,\n                                                 LPCSTR pFunctionName, LPCSTR pProfile, UINT Flags1, UINT Flags2, ID3DX11ThreadPump *pPump, ID3D10Blob **ppShader, ID3D10Blob **ppErrorMsgs, HRESULT *pHResult);\n\nstatic HMODULE                              s_hModDXGI = NULL;\nstatic LPCREATEDXGIFACTORY                  sFnPtr_CreateDXGIFactory = NULL;\nstatic HMODULE                              s_hModD3D11 = NULL;\nstatic HMODULE                              s_hModD3DX11 = NULL;\nstatic LPD3D11CREATEDEVICE                  sFnPtr_D3D11CreateDevice = NULL;\nstatic LPD3D11CREATEDEVICEANDSWAPCHAIN      sFnPtr_D3D11CreateDeviceAndSwapChain = NULL;\nstatic LPD3DX11COMPILEFROMMEMORY            sFnPtr_D3DX11CompileFromMemory = NULL;\n\n// unload the D3D10 DLLs\nstatic bool dynlinkUnloadD3D11API(void)\n{\n    if (s_hModDXGI)\n    {\n        FreeLibrary(s_hModDXGI);\n        s_hModDXGI = NULL;\n    }\n\n    if (s_hModD3D11)\n    {\n        FreeLibrary(s_hModD3D11);\n        s_hModD3D11 = NULL;\n    }\n\n    if (s_hModD3DX11)\n    {\n        FreeLibrary(s_hModD3DX11);\n        s_hModD3DX11 = NULL;\n    }\n\n    return true;\n}\n\n// Dynamically load the D3D11 DLLs loaded and map the function pointers\nstatic bool dynlinkLoadD3D11API(void)\n{\n    // If both modules are non-NULL, this function has already been called.  Note\n    // that this doesn't guarantee that all ProcAddresses were found.\n    if (s_hModD3D11 != NULL && s_hModD3DX11 != NULL && s_hModDXGI != NULL)\n    {\n        return true;\n    }\n\n#if 1\n    // This may fail if Direct3D 11 isn't installed\n    s_hModD3D11 = LoadLibrary(\"d3d11.dll\");\n\n    if (s_hModD3D11 != NULL)\n    {\n        sFnPtr_D3D11CreateDevice = (LPD3D11CREATEDEVICE)GetProcAddress(s_hModD3D11, \"D3D11CreateDevice\");\n        sFnPtr_D3D11CreateDeviceAndSwapChain = (LPD3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(s_hModD3D11, \"D3D11CreateDeviceAndSwapChain\");\n    }\n\n    // first try to load D3DX11CompileFromMemory from DirectX 2010 June\n    s_hModD3DX11 = LoadLibrary(\"D3DX11d_43.dll\");\n\n    if (s_hModD3DX11 != NULL)\n    {\n        sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY)     GetProcAddress(s_hModD3DX11, \"D3DX11CompileFromMemory\");\n    }\n    else    // if absent try to take it from DirectX 2010 Feb\n    {\n        s_hModD3DX11 = LoadLibrary(\"D3DX11d_42.dll\");\n\n        if (s_hModD3DX11 != NULL)\n        {\n            sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY)     GetProcAddress(s_hModD3DX11, \"D3DX11CompileFromMemory\");\n        }\n    }\n\n    if (!sFnPtr_CreateDXGIFactory)\n    {\n        s_hModDXGI = LoadLibrary(\"dxgi.dll\");\n\n        if (s_hModDXGI)\n        {\n            sFnPtr_CreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress(s_hModDXGI, \"CreateDXGIFactory1\");\n        }\n\n        return (s_hModDXGI != NULL) && (s_hModD3D11 != NULL);\n    }\n\n    return (s_hModD3D11 != NULL);\n#else\n    sFnPtr_D3D11CreateDevice = (LPD3D11CREATEDEVICE)D3D11CreateDeviceAndSwapChain;\n    sFnPtr_D3D11CreateDeviceAndSwapChain = (LPD3D11CREATEDEVICEANDSWAPCHAIN)D3D11CreateDeviceAndSwapChain;\n    //sFnPtr_D3DX11CreateEffectFromMemory  = ( LPD3DX11CREATEEFFECTFROMMEMORY )D3DX11CreateEffectFromMemory;\n    sFnPtr_D3DX11CompileFromMemory = (LPD3DX11COMPILEFROMMEMORY)D3DX11CompileFromMemory;\n    sFnPtr_CreateDXGIFactory = (LPCREATEDXGIFACTORY)CreateDXGIFactory;\n    return true;\n#endif\n    return true;\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/exception.h",
    "content": "/*\n* Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n*\n* Please refer to the NVIDIA end user license agreement (EULA) associated\n* with this source code for terms and conditions that govern your use of\n* this software. Any use, reproduction, disclosure, or distribution of\n* this software and related documentation outside the terms of the EULA\n* is strictly prohibited.\n*\n*/\n\n/* CUda UTility Library */\n#ifndef _EXCEPTION_H_\n#define _EXCEPTION_H_\n\n// includes, system\n#include <exception>\n#include <stdexcept>\n#include <iostream>\n#include <stdlib.h>\n\n//! Exception wrapper.\n//! @param Std_Exception Exception out of namespace std for easy typing.\ntemplate<class Std_Exception>\nclass Exception : public Std_Exception\n{\n    public:\n\n        //! @brief Static construction interface\n        //! @return Alwayss throws ( Located_Exception<Exception>)\n        //! @param file file in which the Exception occurs\n        //! @param line line in which the Exception occurs\n        //! @param detailed details on the code fragment causing the Exception\n        static void throw_it(const char *file,\n                             const int line,\n                             const char *detailed = \"-\");\n\n        //! Static construction interface\n        //! @return Alwayss throws ( Located_Exception<Exception>)\n        //! @param file file in which the Exception occurs\n        //! @param line line in which the Exception occurs\n        //! @param detailed details on the code fragment causing the Exception\n        static void throw_it(const char *file,\n                             const int line,\n                             const std::string &detailed);\n\n        //! Destructor\n        virtual ~Exception() throw();\n\n    private:\n\n        //! Constructor, default (private)\n        Exception();\n\n        //! Constructor, standard\n        //! @param str string returned by what()\n        Exception(const std::string &str);\n\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//! Exception handler function for arbitrary exceptions\n//! @param ex exception to handle\n////////////////////////////////////////////////////////////////////////////////\ntemplate<class Exception_Typ>\ninline void\nhandleException(const Exception_Typ &ex)\n{\n    std::cerr << ex.what() << std::endl;\n\n    exit(EXIT_FAILURE);\n}\n\n//! Convenience macros\n\n//! Exception caused by dynamic program behavior, e.g. file does not exist\n#define RUNTIME_EXCEPTION( msg) \\\n    Exception<std::runtime_error>::throw_it( __FILE__, __LINE__, msg)\n\n//! Logic exception in program, e.g. an assert failed\n#define LOGIC_EXCEPTION( msg) \\\n    Exception<std::logic_error>::throw_it( __FILE__, __LINE__, msg)\n\n//! Out of range exception\n#define RANGE_EXCEPTION( msg) \\\n    Exception<std::range_error>::throw_it( __FILE__, __LINE__, msg)\n\n////////////////////////////////////////////////////////////////////////////////\n//! Implementation\n\n// includes, system\n#include <sstream>\n\n////////////////////////////////////////////////////////////////////////////////\n//! Static construction interface.\n//! @param  Exception causing code fragment (file and line) and detailed infos.\n////////////////////////////////////////////////////////////////////////////////\n/*static*/ template<class Std_Exception>\nvoid\nException<Std_Exception>::\nthrow_it(const char *file, const int line, const char *detailed)\n{\n    std::stringstream s;\n\n    // Quiet heavy-weight but exceptions are not for\n    // performance / release versions\n    s << \"Exception in file '\" << file << \"' in line \" << line << \"\\n\"\n      << \"Detailed description: \" << detailed << \"\\n\";\n\n    throw Exception(s.str());\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Static construction interface.\n//! @param  Exception causing code fragment (file and line) and detailed infos.\n////////////////////////////////////////////////////////////////////////////////\n/*static*/ template<class Std_Exception>\nvoid\nException<Std_Exception>::\nthrow_it(const char *file, const int line, const std::string &msg)\n{\n    throw_it(file, line, msg.c_str());\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Constructor, default (private).\n////////////////////////////////////////////////////////////////////////////////\ntemplate<class Std_Exception>\nException<Std_Exception>::Exception() :\n    Std_Exception(\"Unknown Exception.\\n\")\n{ }\n\n////////////////////////////////////////////////////////////////////////////////\n//! Constructor, standard (private).\n//! String returned by what().\n////////////////////////////////////////////////////////////////////////////////\ntemplate<class Std_Exception>\nException<Std_Exception>::Exception(const std::string &s) :\n    Std_Exception(s)\n{ }\n\n////////////////////////////////////////////////////////////////////////////////\n//! Destructor\n////////////////////////////////////////////////////////////////////////////////\ntemplate<class Std_Exception>\nException<Std_Exception>::~Exception() throw() { }\n\n// functions, exported\n\n#endif // #ifndef _EXCEPTION_H_\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_cuda.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n////////////////////////////////////////////////////////////////////////////////\n// These are CUDA Helper functions for initialization and error checking\n\n#ifndef HELPER_CUDA_H\n#define HELPER_CUDA_H\n\n#pragma once\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <helper_string.h>\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n// Note, it is required that your SDK sample to include the proper header files, please\n// refer the CUDA examples for examples of the needed CUDA headers, which may change depending\n// on which CUDA functions are used.\n\n// CUDA Runtime error messages\n#ifdef __DRIVER_TYPES_H__\nstatic const char *_cudaGetErrorEnum(cudaError_t error)\n{\n    switch (error)\n    {\n        case cudaSuccess:\n            return \"cudaSuccess\";\n\n        case cudaErrorMissingConfiguration:\n            return \"cudaErrorMissingConfiguration\";\n\n        case cudaErrorMemoryAllocation:\n            return \"cudaErrorMemoryAllocation\";\n\n        case cudaErrorInitializationError:\n            return \"cudaErrorInitializationError\";\n\n        case cudaErrorLaunchFailure:\n            return \"cudaErrorLaunchFailure\";\n\n        case cudaErrorPriorLaunchFailure:\n            return \"cudaErrorPriorLaunchFailure\";\n\n        case cudaErrorLaunchTimeout:\n            return \"cudaErrorLaunchTimeout\";\n\n        case cudaErrorLaunchOutOfResources:\n            return \"cudaErrorLaunchOutOfResources\";\n\n        case cudaErrorInvalidDeviceFunction:\n            return \"cudaErrorInvalidDeviceFunction\";\n\n        case cudaErrorInvalidConfiguration:\n            return \"cudaErrorInvalidConfiguration\";\n\n        case cudaErrorInvalidDevice:\n            return \"cudaErrorInvalidDevice\";\n\n        case cudaErrorInvalidValue:\n            return \"cudaErrorInvalidValue\";\n\n        case cudaErrorInvalidPitchValue:\n            return \"cudaErrorInvalidPitchValue\";\n\n        case cudaErrorInvalidSymbol:\n            return \"cudaErrorInvalidSymbol\";\n\n        case cudaErrorMapBufferObjectFailed:\n            return \"cudaErrorMapBufferObjectFailed\";\n\n        case cudaErrorUnmapBufferObjectFailed:\n            return \"cudaErrorUnmapBufferObjectFailed\";\n\n        case cudaErrorInvalidHostPointer:\n            return \"cudaErrorInvalidHostPointer\";\n\n        case cudaErrorInvalidDevicePointer:\n            return \"cudaErrorInvalidDevicePointer\";\n\n        case cudaErrorInvalidTexture:\n            return \"cudaErrorInvalidTexture\";\n\n        case cudaErrorInvalidTextureBinding:\n            return \"cudaErrorInvalidTextureBinding\";\n\n        case cudaErrorInvalidChannelDescriptor:\n            return \"cudaErrorInvalidChannelDescriptor\";\n\n        case cudaErrorInvalidMemcpyDirection:\n            return \"cudaErrorInvalidMemcpyDirection\";\n\n        case cudaErrorAddressOfConstant:\n            return \"cudaErrorAddressOfConstant\";\n\n        case cudaErrorTextureFetchFailed:\n            return \"cudaErrorTextureFetchFailed\";\n\n        case cudaErrorTextureNotBound:\n            return \"cudaErrorTextureNotBound\";\n\n        case cudaErrorSynchronizationError:\n            return \"cudaErrorSynchronizationError\";\n\n        case cudaErrorInvalidFilterSetting:\n            return \"cudaErrorInvalidFilterSetting\";\n\n        case cudaErrorInvalidNormSetting:\n            return \"cudaErrorInvalidNormSetting\";\n\n        case cudaErrorMixedDeviceExecution:\n            return \"cudaErrorMixedDeviceExecution\";\n\n        case cudaErrorCudartUnloading:\n            return \"cudaErrorCudartUnloading\";\n\n        case cudaErrorUnknown:\n            return \"cudaErrorUnknown\";\n\n        case cudaErrorNotYetImplemented:\n            return \"cudaErrorNotYetImplemented\";\n\n        case cudaErrorMemoryValueTooLarge:\n            return \"cudaErrorMemoryValueTooLarge\";\n\n        case cudaErrorInvalidResourceHandle:\n            return \"cudaErrorInvalidResourceHandle\";\n\n        case cudaErrorNotReady:\n            return \"cudaErrorNotReady\";\n\n        case cudaErrorInsufficientDriver:\n            return \"cudaErrorInsufficientDriver\";\n\n        case cudaErrorSetOnActiveProcess:\n            return \"cudaErrorSetOnActiveProcess\";\n\n        case cudaErrorInvalidSurface:\n            return \"cudaErrorInvalidSurface\";\n\n        case cudaErrorNoDevice:\n            return \"cudaErrorNoDevice\";\n\n        case cudaErrorECCUncorrectable:\n            return \"cudaErrorECCUncorrectable\";\n\n        case cudaErrorSharedObjectSymbolNotFound:\n            return \"cudaErrorSharedObjectSymbolNotFound\";\n\n        case cudaErrorSharedObjectInitFailed:\n            return \"cudaErrorSharedObjectInitFailed\";\n\n        case cudaErrorUnsupportedLimit:\n            return \"cudaErrorUnsupportedLimit\";\n\n        case cudaErrorDuplicateVariableName:\n            return \"cudaErrorDuplicateVariableName\";\n\n        case cudaErrorDuplicateTextureName:\n            return \"cudaErrorDuplicateTextureName\";\n\n        case cudaErrorDuplicateSurfaceName:\n            return \"cudaErrorDuplicateSurfaceName\";\n\n        case cudaErrorDevicesUnavailable:\n            return \"cudaErrorDevicesUnavailable\";\n\n        case cudaErrorInvalidKernelImage:\n            return \"cudaErrorInvalidKernelImage\";\n\n        case cudaErrorNoKernelImageForDevice:\n            return \"cudaErrorNoKernelImageForDevice\";\n\n        case cudaErrorIncompatibleDriverContext:\n            return \"cudaErrorIncompatibleDriverContext\";\n\n        case cudaErrorPeerAccessAlreadyEnabled:\n            return \"cudaErrorPeerAccessAlreadyEnabled\";\n\n        case cudaErrorPeerAccessNotEnabled:\n            return \"cudaErrorPeerAccessNotEnabled\";\n\n        case cudaErrorDeviceAlreadyInUse:\n            return \"cudaErrorDeviceAlreadyInUse\";\n\n        case cudaErrorProfilerDisabled:\n            return \"cudaErrorProfilerDisabled\";\n\n        case cudaErrorProfilerNotInitialized:\n            return \"cudaErrorProfilerNotInitialized\";\n\n        case cudaErrorProfilerAlreadyStarted:\n            return \"cudaErrorProfilerAlreadyStarted\";\n\n        case cudaErrorProfilerAlreadyStopped:\n            return \"cudaErrorProfilerAlreadyStopped\";\n\n        /* Since CUDA 4.0*/\n        case cudaErrorAssert:\n            return \"cudaErrorAssert\";\n\n        case cudaErrorTooManyPeers:\n            return \"cudaErrorTooManyPeers\";\n\n        case cudaErrorHostMemoryAlreadyRegistered:\n            return \"cudaErrorHostMemoryAlreadyRegistered\";\n\n        case cudaErrorHostMemoryNotRegistered:\n            return \"cudaErrorHostMemoryNotRegistered\";\n\n        /* Since CUDA 5.0 */\n        case cudaErrorOperatingSystem:\n            return \"cudaErrorOperatingSystem\";\n\n        case cudaErrorPeerAccessUnsupported:\n            return \"cudaErrorPeerAccessUnsupported\";\n\n        case cudaErrorLaunchMaxDepthExceeded:\n            return \"cudaErrorLaunchMaxDepthExceeded\";\n\n        case cudaErrorLaunchFileScopedTex:\n            return \"cudaErrorLaunchFileScopedTex\";\n\n        case cudaErrorLaunchFileScopedSurf:\n            return \"cudaErrorLaunchFileScopedSurf\";\n\n        case cudaErrorSyncDepthExceeded:\n            return \"cudaErrorSyncDepthExceeded\";\n\n        case cudaErrorLaunchPendingCountExceeded:\n            return \"cudaErrorLaunchPendingCountExceeded\";\n\n        case cudaErrorNotPermitted:\n            return \"cudaErrorNotPermitted\";\n\n        case cudaErrorNotSupported:\n            return \"cudaErrorNotSupported\";\n\n        /* Since CUDA 6.0 */\n        case cudaErrorHardwareStackError:\n            return \"cudaErrorHardwareStackError\";\n\n        case cudaErrorIllegalInstruction:\n            return \"cudaErrorIllegalInstruction\";\n\n        case cudaErrorMisalignedAddress:\n            return \"cudaErrorMisalignedAddress\";\n\n        case cudaErrorInvalidAddressSpace:\n            return \"cudaErrorInvalidAddressSpace\";\n\n        case cudaErrorInvalidPc:\n            return \"cudaErrorInvalidPc\";\n\n        case cudaErrorIllegalAddress:\n            return \"cudaErrorIllegalAddress\";\n\n        /* Since CUDA 6.5*/\n        case cudaErrorInvalidPtx:\n            return \"cudaErrorInvalidPtx\";\n\n        case cudaErrorInvalidGraphicsContext:\n            return \"cudaErrorInvalidGraphicsContext\";\n\n        case cudaErrorStartupFailure:\n            return \"cudaErrorStartupFailure\";\n\n        case cudaErrorApiFailureBase:\n            return \"cudaErrorApiFailureBase\";\n\n        /* Since CUDA 8.0*/        \n        case cudaErrorNvlinkUncorrectable :   \n            return \"cudaErrorNvlinkUncorrectable\";\n\n        /* Since CUDA 8.5*/        \n        case cudaErrorJitCompilerNotFound :   \n            return \"cudaErrorJitCompilerNotFound\";\n\n        /* Since CUDA 9.0*/\n        case cudaErrorCooperativeLaunchTooLarge :\n            return \"cudaErrorCooperativeLaunchTooLarge\";\n\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef __cuda_cuda_h__\n// CUDA Driver API errors\nstatic const char *_cudaGetErrorEnum(CUresult error)\n{\n    switch (error)\n    {\n        case CUDA_SUCCESS:\n            return \"CUDA_SUCCESS\";\n\n        case CUDA_ERROR_INVALID_VALUE:\n            return \"CUDA_ERROR_INVALID_VALUE\";\n\n        case CUDA_ERROR_OUT_OF_MEMORY:\n            return \"CUDA_ERROR_OUT_OF_MEMORY\";\n\n        case CUDA_ERROR_NOT_INITIALIZED:\n            return \"CUDA_ERROR_NOT_INITIALIZED\";\n\n        case CUDA_ERROR_DEINITIALIZED:\n            return \"CUDA_ERROR_DEINITIALIZED\";\n\n        case CUDA_ERROR_PROFILER_DISABLED:\n            return \"CUDA_ERROR_PROFILER_DISABLED\";\n\n        case CUDA_ERROR_PROFILER_NOT_INITIALIZED:\n            return \"CUDA_ERROR_PROFILER_NOT_INITIALIZED\";\n\n        case CUDA_ERROR_PROFILER_ALREADY_STARTED:\n            return \"CUDA_ERROR_PROFILER_ALREADY_STARTED\";\n\n        case CUDA_ERROR_PROFILER_ALREADY_STOPPED:\n            return \"CUDA_ERROR_PROFILER_ALREADY_STOPPED\";\n\n        case CUDA_ERROR_NO_DEVICE:\n            return \"CUDA_ERROR_NO_DEVICE\";\n\n        case CUDA_ERROR_INVALID_DEVICE:\n            return \"CUDA_ERROR_INVALID_DEVICE\";\n\n        case CUDA_ERROR_INVALID_IMAGE:\n            return \"CUDA_ERROR_INVALID_IMAGE\";\n\n        case CUDA_ERROR_INVALID_CONTEXT:\n            return \"CUDA_ERROR_INVALID_CONTEXT\";\n\n        case CUDA_ERROR_CONTEXT_ALREADY_CURRENT:\n            return \"CUDA_ERROR_CONTEXT_ALREADY_CURRENT\";\n\n        case CUDA_ERROR_MAP_FAILED:\n            return \"CUDA_ERROR_MAP_FAILED\";\n\n        case CUDA_ERROR_UNMAP_FAILED:\n            return \"CUDA_ERROR_UNMAP_FAILED\";\n\n        case CUDA_ERROR_ARRAY_IS_MAPPED:\n            return \"CUDA_ERROR_ARRAY_IS_MAPPED\";\n\n        case CUDA_ERROR_ALREADY_MAPPED:\n            return \"CUDA_ERROR_ALREADY_MAPPED\";\n\n        case CUDA_ERROR_NO_BINARY_FOR_GPU:\n            return \"CUDA_ERROR_NO_BINARY_FOR_GPU\";\n\n        case CUDA_ERROR_ALREADY_ACQUIRED:\n            return \"CUDA_ERROR_ALREADY_ACQUIRED\";\n\n        case CUDA_ERROR_NOT_MAPPED:\n            return \"CUDA_ERROR_NOT_MAPPED\";\n\n        case CUDA_ERROR_NOT_MAPPED_AS_ARRAY:\n            return \"CUDA_ERROR_NOT_MAPPED_AS_ARRAY\";\n\n        case CUDA_ERROR_NOT_MAPPED_AS_POINTER:\n            return \"CUDA_ERROR_NOT_MAPPED_AS_POINTER\";\n\n        case CUDA_ERROR_ECC_UNCORRECTABLE:\n            return \"CUDA_ERROR_ECC_UNCORRECTABLE\";\n\n        case CUDA_ERROR_UNSUPPORTED_LIMIT:\n            return \"CUDA_ERROR_UNSUPPORTED_LIMIT\";\n\n        case CUDA_ERROR_CONTEXT_ALREADY_IN_USE:\n            return \"CUDA_ERROR_CONTEXT_ALREADY_IN_USE\";\n\n        case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED:\n            return \"CUDA_ERROR_PEER_ACCESS_UNSUPPORTED\";\n\n        case CUDA_ERROR_INVALID_PTX:\n            return \"CUDA_ERROR_INVALID_PTX\";\n\n        case CUDA_ERROR_INVALID_GRAPHICS_CONTEXT:\n            return \"CUDA_ERROR_INVALID_GRAPHICS_CONTEXT\";\n\n        case CUDA_ERROR_NVLINK_UNCORRECTABLE:\n            return \"CUDA_ERROR_NVLINK_UNCORRECTABLE\";\n\n        case CUDA_ERROR_JIT_COMPILER_NOT_FOUND:\n            return \"CUDA_ERROR_JIT_COMPILER_NOT_FOUND\";\n\n        case CUDA_ERROR_INVALID_SOURCE:\n            return \"CUDA_ERROR_INVALID_SOURCE\";\n\n        case CUDA_ERROR_FILE_NOT_FOUND:\n            return \"CUDA_ERROR_FILE_NOT_FOUND\";\n\n        case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND:\n            return \"CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND\";\n\n        case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED:\n            return \"CUDA_ERROR_SHARED_OBJECT_INIT_FAILED\";\n\n        case CUDA_ERROR_OPERATING_SYSTEM:\n            return \"CUDA_ERROR_OPERATING_SYSTEM\";\n\n        case CUDA_ERROR_INVALID_HANDLE:\n            return \"CUDA_ERROR_INVALID_HANDLE\";\n\n        case CUDA_ERROR_NOT_FOUND:\n            return \"CUDA_ERROR_NOT_FOUND\";\n\n        case CUDA_ERROR_NOT_READY:\n            return \"CUDA_ERROR_NOT_READY\";\n\n        case CUDA_ERROR_ILLEGAL_ADDRESS:\n            return \"CUDA_ERROR_ILLEGAL_ADDRESS\";\n\n        case CUDA_ERROR_LAUNCH_FAILED:\n            return \"CUDA_ERROR_LAUNCH_FAILED\";\n\n        case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES:\n            return \"CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES\";\n\n        case CUDA_ERROR_LAUNCH_TIMEOUT:\n            return \"CUDA_ERROR_LAUNCH_TIMEOUT\";\n\n        case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING:\n            return \"CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING\";\n\n        case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED:\n            return \"CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED\";\n\n        case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED:\n            return \"CUDA_ERROR_PEER_ACCESS_NOT_ENABLED\";\n\n        case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE:\n            return \"CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE\";\n\n        case CUDA_ERROR_CONTEXT_IS_DESTROYED:\n            return \"CUDA_ERROR_CONTEXT_IS_DESTROYED\";\n\n        case CUDA_ERROR_ASSERT:\n            return \"CUDA_ERROR_ASSERT\";\n\n        case CUDA_ERROR_TOO_MANY_PEERS:\n            return \"CUDA_ERROR_TOO_MANY_PEERS\";\n\n        case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED:\n            return \"CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED\";\n\n        case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED:\n            return \"CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED\";\n\n        case CUDA_ERROR_HARDWARE_STACK_ERROR:\n            return \"CUDA_ERROR_HARDWARE_STACK_ERROR\";\n\n        case CUDA_ERROR_ILLEGAL_INSTRUCTION:\n            return \"CUDA_ERROR_ILLEGAL_INSTRUCTION\";\n\n        case CUDA_ERROR_MISALIGNED_ADDRESS:\n            return \"CUDA_ERROR_MISALIGNED_ADDRESS\";\n\n        case CUDA_ERROR_INVALID_ADDRESS_SPACE:\n            return \"CUDA_ERROR_INVALID_ADDRESS_SPACE\";\n\n        case CUDA_ERROR_INVALID_PC:\n            return \"CUDA_ERROR_INVALID_PC\";\n\n        case CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE:\n            return \"CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE\";\n\n        case CUDA_ERROR_NOT_PERMITTED:\n            return \"CUDA_ERROR_NOT_PERMITTED\";\n\n        case CUDA_ERROR_NOT_SUPPORTED:\n            return \"CUDA_ERROR_NOT_SUPPORTED\";\n\n        case CUDA_ERROR_UNKNOWN:\n            return \"CUDA_ERROR_UNKNOWN\";\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef CUBLAS_API_H_\n// cuBLAS API errors\nstatic const char *_cudaGetErrorEnum(cublasStatus_t error)\n{\n    switch (error)\n    {\n        case CUBLAS_STATUS_SUCCESS:\n            return \"CUBLAS_STATUS_SUCCESS\";\n\n        case CUBLAS_STATUS_NOT_INITIALIZED:\n            return \"CUBLAS_STATUS_NOT_INITIALIZED\";\n\n        case CUBLAS_STATUS_ALLOC_FAILED:\n            return \"CUBLAS_STATUS_ALLOC_FAILED\";\n\n        case CUBLAS_STATUS_INVALID_VALUE:\n            return \"CUBLAS_STATUS_INVALID_VALUE\";\n\n        case CUBLAS_STATUS_ARCH_MISMATCH:\n            return \"CUBLAS_STATUS_ARCH_MISMATCH\";\n\n        case CUBLAS_STATUS_MAPPING_ERROR:\n            return \"CUBLAS_STATUS_MAPPING_ERROR\";\n\n        case CUBLAS_STATUS_EXECUTION_FAILED:\n            return \"CUBLAS_STATUS_EXECUTION_FAILED\";\n\n        case CUBLAS_STATUS_INTERNAL_ERROR:\n            return \"CUBLAS_STATUS_INTERNAL_ERROR\";\n\n        case CUBLAS_STATUS_NOT_SUPPORTED:\n            return \"CUBLAS_STATUS_NOT_SUPPORTED\";\n\n        case CUBLAS_STATUS_LICENSE_ERROR:\n            return \"CUBLAS_STATUS_LICENSE_ERROR\";\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef _CUFFT_H_\n// cuFFT API errors\nstatic const char *_cudaGetErrorEnum(cufftResult error)\n{\n    switch (error)\n    {\n        case CUFFT_SUCCESS:\n            return \"CUFFT_SUCCESS\";\n\n        case CUFFT_INVALID_PLAN:\n            return \"CUFFT_INVALID_PLAN\";\n\n        case CUFFT_ALLOC_FAILED:\n            return \"CUFFT_ALLOC_FAILED\";\n\n        case CUFFT_INVALID_TYPE:\n            return \"CUFFT_INVALID_TYPE\";\n\n        case CUFFT_INVALID_VALUE:\n            return \"CUFFT_INVALID_VALUE\";\n\n        case CUFFT_INTERNAL_ERROR:\n            return \"CUFFT_INTERNAL_ERROR\";\n\n        case CUFFT_EXEC_FAILED:\n            return \"CUFFT_EXEC_FAILED\";\n\n        case CUFFT_SETUP_FAILED:\n            return \"CUFFT_SETUP_FAILED\";\n\n        case CUFFT_INVALID_SIZE:\n            return \"CUFFT_INVALID_SIZE\";\n\n        case CUFFT_UNALIGNED_DATA:\n            return \"CUFFT_UNALIGNED_DATA\";\n\n        case CUFFT_INCOMPLETE_PARAMETER_LIST:\n            return \"CUFFT_INCOMPLETE_PARAMETER_LIST\";\n\n        case CUFFT_INVALID_DEVICE:\n            return \"CUFFT_INVALID_DEVICE\";\n\n        case CUFFT_PARSE_ERROR:\n            return \"CUFFT_PARSE_ERROR\";\n\n        case CUFFT_NO_WORKSPACE:\n            return \"CUFFT_NO_WORKSPACE\";\n\n        case CUFFT_NOT_IMPLEMENTED:\n            return \"CUFFT_NOT_IMPLEMENTED\";\n\n        case CUFFT_LICENSE_ERROR:\n            return \"CUFFT_LICENSE_ERROR\";\n\n        case CUFFT_NOT_SUPPORTED:\n            return \"CUFFT_NOT_SUPPORTED\";\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n\n#ifdef CUSPARSEAPI\n// cuSPARSE API errors\nstatic const char *_cudaGetErrorEnum(cusparseStatus_t error)\n{\n    switch (error)\n    {\n        case CUSPARSE_STATUS_SUCCESS:\n            return \"CUSPARSE_STATUS_SUCCESS\";\n\n        case CUSPARSE_STATUS_NOT_INITIALIZED:\n            return \"CUSPARSE_STATUS_NOT_INITIALIZED\";\n\n        case CUSPARSE_STATUS_ALLOC_FAILED:\n            return \"CUSPARSE_STATUS_ALLOC_FAILED\";\n\n        case CUSPARSE_STATUS_INVALID_VALUE:\n            return \"CUSPARSE_STATUS_INVALID_VALUE\";\n\n        case CUSPARSE_STATUS_ARCH_MISMATCH:\n            return \"CUSPARSE_STATUS_ARCH_MISMATCH\";\n\n        case CUSPARSE_STATUS_MAPPING_ERROR:\n            return \"CUSPARSE_STATUS_MAPPING_ERROR\";\n\n        case CUSPARSE_STATUS_EXECUTION_FAILED:\n            return \"CUSPARSE_STATUS_EXECUTION_FAILED\";\n\n        case CUSPARSE_STATUS_INTERNAL_ERROR:\n            return \"CUSPARSE_STATUS_INTERNAL_ERROR\";\n\n        case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:\n            return \"CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED\";\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef CUSOLVER_COMMON_H_\n//cuSOLVER API errors\nstatic const char *_cudaGetErrorEnum(cusolverStatus_t error)\n{\n   switch(error)\n   {\n       case CUSOLVER_STATUS_SUCCESS:\n           return \"CUSOLVER_STATUS_SUCCESS\";\n       case CUSOLVER_STATUS_NOT_INITIALIZED:\n           return \"CUSOLVER_STATUS_NOT_INITIALIZED\";\n       case CUSOLVER_STATUS_ALLOC_FAILED:\n           return \"CUSOLVER_STATUS_ALLOC_FAILED\";\n       case CUSOLVER_STATUS_INVALID_VALUE:\n           return \"CUSOLVER_STATUS_INVALID_VALUE\";\n       case CUSOLVER_STATUS_ARCH_MISMATCH:\n           return \"CUSOLVER_STATUS_ARCH_MISMATCH\";\n       case CUSOLVER_STATUS_MAPPING_ERROR:\n           return \"CUSOLVER_STATUS_MAPPING_ERROR\";\n       case CUSOLVER_STATUS_EXECUTION_FAILED:\n           return \"CUSOLVER_STATUS_EXECUTION_FAILED\";\n       case CUSOLVER_STATUS_INTERNAL_ERROR:\n           return \"CUSOLVER_STATUS_INTERNAL_ERROR\";\n       case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:\n           return \"CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED\";\n       case CUSOLVER_STATUS_NOT_SUPPORTED :\n           return \"CUSOLVER_STATUS_NOT_SUPPORTED \";\n       case CUSOLVER_STATUS_ZERO_PIVOT:\n           return \"CUSOLVER_STATUS_ZERO_PIVOT\";\n       case CUSOLVER_STATUS_INVALID_LICENSE:\n           return \"CUSOLVER_STATUS_INVALID_LICENSE\";\n    }\n\n    return \"<unknown>\";\n\n}\n#endif\n\n#ifdef CURAND_H_\n// cuRAND API errors\nstatic const char *_cudaGetErrorEnum(curandStatus_t error)\n{\n    switch (error)\n    {\n        case CURAND_STATUS_SUCCESS:\n            return \"CURAND_STATUS_SUCCESS\";\n\n        case CURAND_STATUS_VERSION_MISMATCH:\n            return \"CURAND_STATUS_VERSION_MISMATCH\";\n\n        case CURAND_STATUS_NOT_INITIALIZED:\n            return \"CURAND_STATUS_NOT_INITIALIZED\";\n\n        case CURAND_STATUS_ALLOCATION_FAILED:\n            return \"CURAND_STATUS_ALLOCATION_FAILED\";\n\n        case CURAND_STATUS_TYPE_ERROR:\n            return \"CURAND_STATUS_TYPE_ERROR\";\n\n        case CURAND_STATUS_OUT_OF_RANGE:\n            return \"CURAND_STATUS_OUT_OF_RANGE\";\n\n        case CURAND_STATUS_LENGTH_NOT_MULTIPLE:\n            return \"CURAND_STATUS_LENGTH_NOT_MULTIPLE\";\n\n        case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED:\n            return \"CURAND_STATUS_DOUBLE_PRECISION_REQUIRED\";\n\n        case CURAND_STATUS_LAUNCH_FAILURE:\n            return \"CURAND_STATUS_LAUNCH_FAILURE\";\n\n        case CURAND_STATUS_PREEXISTING_FAILURE:\n            return \"CURAND_STATUS_PREEXISTING_FAILURE\";\n\n        case CURAND_STATUS_INITIALIZATION_FAILED:\n            return \"CURAND_STATUS_INITIALIZATION_FAILED\";\n\n        case CURAND_STATUS_ARCH_MISMATCH:\n            return \"CURAND_STATUS_ARCH_MISMATCH\";\n\n        case CURAND_STATUS_INTERNAL_ERROR:\n            return \"CURAND_STATUS_INTERNAL_ERROR\";\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef NV_NPPIDEFS_H\n// NPP API errors\nstatic const char *_cudaGetErrorEnum(NppStatus error)\n{\n    switch (error)\n    {\n        case NPP_NOT_SUPPORTED_MODE_ERROR:\n            return \"NPP_NOT_SUPPORTED_MODE_ERROR\";\n\n        case NPP_ROUND_MODE_NOT_SUPPORTED_ERROR:\n            return \"NPP_ROUND_MODE_NOT_SUPPORTED_ERROR\";\n\n        case NPP_RESIZE_NO_OPERATION_ERROR:\n            return \"NPP_RESIZE_NO_OPERATION_ERROR\";\n\n        case NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY:\n            return \"NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY\";\n\n#if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) <= 0x5000\n\n        case NPP_BAD_ARG_ERROR:\n            return \"NPP_BAD_ARGUMENT_ERROR\";\n\n        case NPP_COEFF_ERROR:\n            return \"NPP_COEFFICIENT_ERROR\";\n\n        case NPP_RECT_ERROR:\n            return \"NPP_RECTANGLE_ERROR\";\n\n        case NPP_QUAD_ERROR:\n            return \"NPP_QUADRANGLE_ERROR\";\n\n        case NPP_MEM_ALLOC_ERR:\n            return \"NPP_MEMORY_ALLOCATION_ERROR\";\n\n        case NPP_HISTO_NUMBER_OF_LEVELS_ERROR:\n            return \"NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR\";\n\n        case NPP_INVALID_INPUT:\n            return \"NPP_INVALID_INPUT\";\n\n        case NPP_POINTER_ERROR:\n            return \"NPP_POINTER_ERROR\";\n\n        case NPP_WARNING:\n            return \"NPP_WARNING\";\n\n        case NPP_ODD_ROI_WARNING:\n            return \"NPP_ODD_ROI_WARNING\";\n#else\n\n            // These are for CUDA 5.5 or higher\n        case NPP_BAD_ARGUMENT_ERROR:\n            return \"NPP_BAD_ARGUMENT_ERROR\";\n\n        case NPP_COEFFICIENT_ERROR:\n            return \"NPP_COEFFICIENT_ERROR\";\n\n        case NPP_RECTANGLE_ERROR:\n            return \"NPP_RECTANGLE_ERROR\";\n\n        case NPP_QUADRANGLE_ERROR:\n            return \"NPP_QUADRANGLE_ERROR\";\n\n        case NPP_MEMORY_ALLOCATION_ERR:\n            return \"NPP_MEMORY_ALLOCATION_ERROR\";\n\n        case NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR:\n            return \"NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR\";\n\n        case NPP_INVALID_HOST_POINTER_ERROR:\n            return \"NPP_INVALID_HOST_POINTER_ERROR\";\n\n        case NPP_INVALID_DEVICE_POINTER_ERROR:\n            return \"NPP_INVALID_DEVICE_POINTER_ERROR\";\n#endif\n\n        case NPP_LUT_NUMBER_OF_LEVELS_ERROR:\n            return \"NPP_LUT_NUMBER_OF_LEVELS_ERROR\";\n\n        case NPP_TEXTURE_BIND_ERROR:\n            return \"NPP_TEXTURE_BIND_ERROR\";\n\n        case NPP_WRONG_INTERSECTION_ROI_ERROR:\n            return \"NPP_WRONG_INTERSECTION_ROI_ERROR\";\n\n        case NPP_NOT_EVEN_STEP_ERROR:\n            return \"NPP_NOT_EVEN_STEP_ERROR\";\n\n        case NPP_INTERPOLATION_ERROR:\n            return \"NPP_INTERPOLATION_ERROR\";\n\n        case NPP_RESIZE_FACTOR_ERROR:\n            return \"NPP_RESIZE_FACTOR_ERROR\";\n\n        case NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR:\n            return \"NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR\";\n\n\n#if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) <= 0x5000\n\n        case NPP_MEMFREE_ERR:\n            return \"NPP_MEMFREE_ERR\";\n\n        case NPP_MEMSET_ERR:\n            return \"NPP_MEMSET_ERR\";\n\n        case NPP_MEMCPY_ERR:\n            return \"NPP_MEMCPY_ERROR\";\n\n        case NPP_MIRROR_FLIP_ERR:\n            return \"NPP_MIRROR_FLIP_ERR\";\n#else\n\n        case NPP_MEMFREE_ERROR:\n            return \"NPP_MEMFREE_ERROR\";\n\n        case NPP_MEMSET_ERROR:\n            return \"NPP_MEMSET_ERROR\";\n\n        case NPP_MEMCPY_ERROR:\n            return \"NPP_MEMCPY_ERROR\";\n\n        case NPP_MIRROR_FLIP_ERROR:\n            return \"NPP_MIRROR_FLIP_ERROR\";\n#endif\n\n        case NPP_ALIGNMENT_ERROR:\n            return \"NPP_ALIGNMENT_ERROR\";\n\n        case NPP_STEP_ERROR:\n            return \"NPP_STEP_ERROR\";\n\n        case NPP_SIZE_ERROR:\n            return \"NPP_SIZE_ERROR\";\n\n        case NPP_NULL_POINTER_ERROR:\n            return \"NPP_NULL_POINTER_ERROR\";\n\n        case NPP_CUDA_KERNEL_EXECUTION_ERROR:\n            return \"NPP_CUDA_KERNEL_EXECUTION_ERROR\";\n\n        case NPP_NOT_IMPLEMENTED_ERROR:\n            return \"NPP_NOT_IMPLEMENTED_ERROR\";\n\n        case NPP_ERROR:\n            return \"NPP_ERROR\";\n\n        case NPP_SUCCESS:\n            return \"NPP_SUCCESS\";\n\n        case NPP_WRONG_INTERSECTION_QUAD_WARNING:\n            return \"NPP_WRONG_INTERSECTION_QUAD_WARNING\";\n\n        case NPP_MISALIGNED_DST_ROI_WARNING:\n            return \"NPP_MISALIGNED_DST_ROI_WARNING\";\n\n        case NPP_AFFINE_QUAD_INCORRECT_WARNING:\n            return \"NPP_AFFINE_QUAD_INCORRECT_WARNING\";\n\n        case NPP_DOUBLE_SIZE_WARNING:\n            return \"NPP_DOUBLE_SIZE_WARNING\";\n\n        case NPP_WRONG_INTERSECTION_ROI_WARNING:\n            return \"NPP_WRONG_INTERSECTION_ROI_WARNING\";\n\n#if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) >= 0x6000\n        /* These are 6.0 or higher */\n        case NPP_LUT_PALETTE_BITSIZE_ERROR:\n            return \"NPP_LUT_PALETTE_BITSIZE_ERROR\";\n\n        case NPP_ZC_MODE_NOT_SUPPORTED_ERROR:\n            return \"NPP_ZC_MODE_NOT_SUPPORTED_ERROR\";\n\n        case NPP_QUALITY_INDEX_ERROR:\n            return \"NPP_QUALITY_INDEX_ERROR\";\n\n        case NPP_CHANNEL_ORDER_ERROR:\n            return \"NPP_CHANNEL_ORDER_ERROR\";\n\n        case NPP_ZERO_MASK_VALUE_ERROR:\n            return \"NPP_ZERO_MASK_VALUE_ERROR\";\n\n        case NPP_NUMBER_OF_CHANNELS_ERROR:\n            return \"NPP_NUMBER_OF_CHANNELS_ERROR\";\n\n        case NPP_COI_ERROR:\n            return \"NPP_COI_ERROR\";\n\n        case NPP_DIVISOR_ERROR:\n            return \"NPP_DIVISOR_ERROR\";\n\n        case NPP_CHANNEL_ERROR:\n            return \"NPP_CHANNEL_ERROR\";\n\n        case NPP_STRIDE_ERROR:\n            return \"NPP_STRIDE_ERROR\";\n\n        case NPP_ANCHOR_ERROR:\n            return \"NPP_ANCHOR_ERROR\";\n\n        case NPP_MASK_SIZE_ERROR:\n            return \"NPP_MASK_SIZE_ERROR\";\n\n        case NPP_MOMENT_00_ZERO_ERROR:\n            return \"NPP_MOMENT_00_ZERO_ERROR\";\n\n        case NPP_THRESHOLD_NEGATIVE_LEVEL_ERROR:\n            return \"NPP_THRESHOLD_NEGATIVE_LEVEL_ERROR\";\n\n        case NPP_THRESHOLD_ERROR:\n            return \"NPP_THRESHOLD_ERROR\";\n\n        case NPP_CONTEXT_MATCH_ERROR:\n            return \"NPP_CONTEXT_MATCH_ERROR\";\n\n        case NPP_FFT_FLAG_ERROR:\n            return \"NPP_FFT_FLAG_ERROR\";\n\n        case NPP_FFT_ORDER_ERROR:\n            return \"NPP_FFT_ORDER_ERROR\";\n\n        case NPP_SCALE_RANGE_ERROR:\n            return \"NPP_SCALE_RANGE_ERROR\";\n\n        case NPP_DATA_TYPE_ERROR:\n            return \"NPP_DATA_TYPE_ERROR\";\n\n        case NPP_OUT_OFF_RANGE_ERROR:\n            return \"NPP_OUT_OFF_RANGE_ERROR\";\n\n        case NPP_DIVIDE_BY_ZERO_ERROR:\n            return \"NPP_DIVIDE_BY_ZERO_ERROR\";\n\n        case NPP_RANGE_ERROR:\n            return \"NPP_RANGE_ERROR\";\n\n        case NPP_NO_MEMORY_ERROR:\n            return \"NPP_NO_MEMORY_ERROR\";\n\n        case NPP_ERROR_RESERVED:\n            return \"NPP_ERROR_RESERVED\";\n\n        case NPP_NO_OPERATION_WARNING:\n            return \"NPP_NO_OPERATION_WARNING\";\n\n        case NPP_DIVIDE_BY_ZERO_WARNING:\n            return \"NPP_DIVIDE_BY_ZERO_WARNING\";\n#endif\n\n#if ((NPP_VERSION_MAJOR << 12) + (NPP_VERSION_MINOR << 4)) >= 0x7000\n        /* These are 7.0 or higher */\n        case NPP_OVERFLOW_ERROR:\n            return \"NPP_OVERFLOW_ERROR\";\n\n        case NPP_CORRUPTED_DATA_ERROR:\n            return \"NPP_CORRUPTED_DATA_ERROR\";\n#endif\n    }\n\n    return \"<unknown>\";\n}\n#endif\n\n#ifdef __DRIVER_TYPES_H__\n#ifndef DEVICE_RESET\n#define DEVICE_RESET cudaDeviceReset();\n#endif\n#else\n#ifndef DEVICE_RESET\n#define DEVICE_RESET\n#endif\n#endif\n\ntemplate< typename T >\nvoid check(T result, char const *const func, const char *const file, int const line)\n{\n    if (result)\n    {\n        fprintf(stderr, \"CUDA error at %s:%d code=%d(%s) \\\"%s\\\" \\n\",\n                file, line, static_cast<unsigned int>(result), _cudaGetErrorEnum(result), func);\n        DEVICE_RESET\n        // Make sure we call CUDA Device Reset before exiting\n        exit(EXIT_FAILURE);\n    }\n}\n\n#ifdef __DRIVER_TYPES_H__\n// This will output the proper CUDA error strings in the event that a CUDA host call returns an error\n#define checkCudaErrors(val)           check ( (val), #val, __FILE__, __LINE__ )\n\n// This will output the proper error string when calling cudaGetLastError\n#define getLastCudaError(msg)      __getLastCudaError (msg, __FILE__, __LINE__)\n\ninline void __getLastCudaError(const char *errorMessage, const char *file, const int line)\n{\n    cudaError_t err = cudaGetLastError();\n\n    if (cudaSuccess != err)\n    {\n        fprintf(stderr, \"%s(%i) : getLastCudaError() CUDA error : %s : (%d) %s.\\n\",\n                file, line, errorMessage, (int)err, cudaGetErrorString(err));\n        DEVICE_RESET\n        exit(EXIT_FAILURE);\n    }\n}\n\n// This will only print the proper error string when calling cudaGetLastError but not exit program incase error detected.\n#define printLastCudaError(msg)      __printLastCudaError (msg, __FILE__, __LINE__)\n\ninline void __printLastCudaError(const char *errorMessage, const char *file, const int line)\n{\n    cudaError_t err = cudaGetLastError();\n\n    if (cudaSuccess != err)\n    {\n        fprintf(stderr, \"%s(%i) : getLastCudaError() CUDA error : %s : (%d) %s.\\n\",\n            file, line, errorMessage, (int)err, cudaGetErrorString(err));\n    }\n}\n#endif\n\n#ifndef MAX\n#define MAX(a,b) (a > b ? a : b)\n#endif\n\n// Float To Int conversion\ninline int ftoi(float value)\n{\n    return (value >= 0 ? (int)(value + 0.5) : (int)(value - 0.5));\n}\n\n// Beginning of GPU Architecture definitions\ninline int _ConvertSMVer2Cores(int major, int minor)\n{\n    // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM\n    typedef struct\n    {\n        int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version\n        int Cores;\n    } sSMtoCores;\n\n    sSMtoCores nGpuArchCoresPerSM[] =\n    {\n        { 0x30, 192}, // Kepler Generation (SM 3.0) GK10x class\n        { 0x32, 192}, // Kepler Generation (SM 3.2) GK10x class\n        { 0x35, 192}, // Kepler Generation (SM 3.5) GK11x class\n        { 0x37, 192}, // Kepler Generation (SM 3.7) GK21x class\n        { 0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class\n        { 0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class\n        { 0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class\n        { 0x60, 64 }, // Pascal Generation (SM 6.0) GP100 class\n        { 0x61, 128}, // Pascal Generation (SM 6.1) GP10x class\n        { 0x62, 128}, // Pascal Generation (SM 6.2) GP10x class\n        { 0x70, 64 }, // Volta Generation (SM 7.0) GV100 class\n        { 0x72, 64 }, // Volta Generation (SM 7.2) GV11b class\n        {   -1, -1 }\n    };\n\n    int index = 0;\n\n    while (nGpuArchCoresPerSM[index].SM != -1)\n    {\n        if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor))\n        {\n            return nGpuArchCoresPerSM[index].Cores;\n        }\n\n        index++;\n    }\n\n    // If we don't find the values, we default use the previous one to run properly\n    printf(\"MapSMtoCores for SM %d.%d is undefined.  Default to use %d Cores/SM\\n\", major, minor, nGpuArchCoresPerSM[index-1].Cores);\n    return nGpuArchCoresPerSM[index-1].Cores;\n}\n// end of GPU Architecture definitions\n\n#ifdef __CUDA_RUNTIME_H__\n// General GPU Device CUDA Initialization\ninline int gpuDeviceInit(int devID)\n{\n    int device_count;\n    checkCudaErrors(cudaGetDeviceCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"gpuDeviceInit() CUDA error: no devices supporting CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    if (devID < 0)\n    {\n        devID = 0;\n    }\n\n    if (devID > device_count-1)\n    {\n        fprintf(stderr, \"\\n\");\n        fprintf(stderr, \">> %d CUDA capable GPU device(s) detected. <<\\n\", device_count);\n        fprintf(stderr, \">> gpuDeviceInit (-device=%d) is not a valid GPU device. <<\\n\", devID);\n        fprintf(stderr, \"\\n\");\n        return -devID;\n    }\n\n    cudaDeviceProp deviceProp;\n    checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));\n\n    if (deviceProp.computeMode == cudaComputeModeProhibited)\n    {\n        fprintf(stderr, \"Error: device is running in <Compute Mode Prohibited>, no threads can use ::cudaSetDevice().\\n\");\n        return -1;\n    }\n\n    if (deviceProp.major < 1)\n    {\n        fprintf(stderr, \"gpuDeviceInit(): GPU device does not support CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    checkCudaErrors(cudaSetDevice(devID));\n    printf(\"gpuDeviceInit() CUDA Device [%d]: \\\"%s\\n\", devID, deviceProp.name);\n\n    return devID;\n}\n\n// This function returns the best GPU (with maximum GFLOPS)\ninline int gpuGetMaxGflopsDeviceId()\n{\n    int current_device     = 0, sm_per_multiproc  = 0;\n    int max_perf_device    = 0;\n    int device_count       = 0, best_SM_arch      = 0;\n    int devices_prohibited = 0;\n    \n    unsigned long long max_compute_perf = 0;\n    cudaDeviceProp deviceProp;\n    checkCudaErrors(cudaGetDeviceCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"gpuGetMaxGflopsDeviceId() CUDA error: no devices supporting CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the best major SM Architecture GPU device\n    while (current_device < device_count)\n    {\n        cudaGetDeviceProperties(&deviceProp, current_device);\n\n        // If this GPU is not running on Compute Mode prohibited, then we can add it to the list\n        if (deviceProp.computeMode != cudaComputeModeProhibited)\n        {\n            if (deviceProp.major > 0 && deviceProp.major < 9999)\n            {\n                best_SM_arch = MAX(best_SM_arch, deviceProp.major);\n            }\n        }\n        else\n        {\n            devices_prohibited++;\n        }\n\n        current_device++;\n    }\n\n    if (devices_prohibited == device_count)\n    {\n    \tfprintf(stderr, \"gpuGetMaxGflopsDeviceId() CUDA error: all devices have compute mode prohibited.\\n\");\n    \texit(EXIT_FAILURE);\n    }\n\n    // Find the best CUDA capable GPU device\n    current_device = 0;\n\n    while (current_device < device_count)\n    {\n        cudaGetDeviceProperties(&deviceProp, current_device);\n\n        // If this GPU is not running on Compute Mode prohibited, then we can add it to the list\n        if (deviceProp.computeMode != cudaComputeModeProhibited)\n        {\n            if (deviceProp.major == 9999 && deviceProp.minor == 9999)\n            {\n                sm_per_multiproc = 1;\n            }\n            else\n            {\n                sm_per_multiproc = _ConvertSMVer2Cores(deviceProp.major, deviceProp.minor);\n            }\n\n            unsigned long long compute_perf  = (unsigned long long) deviceProp.multiProcessorCount * sm_per_multiproc * deviceProp.clockRate;\n\n            if (compute_perf  > max_compute_perf)\n            {\n                // If we find GPU with SM major > 2, search only these\n                if (best_SM_arch > 2)\n                {\n                    // If our device==dest_SM_arch, choose this, or else pass\n                    if (deviceProp.major == best_SM_arch)\n                    {\n                        max_compute_perf  = compute_perf;\n                        max_perf_device   = current_device;\n                    }\n                }\n                else\n                {\n                    max_compute_perf  = compute_perf;\n                    max_perf_device   = current_device;\n                }\n            }\n        }\n\n        ++current_device;\n    }\n\n    return max_perf_device;\n}\n\n\n// Initialization code to find the best CUDA Device\ninline int findCudaDevice(int argc, const char **argv)\n{\n    cudaDeviceProp deviceProp;\n    int devID = 0;\n\n    // If the command-line has a device number specified, use it\n    if (checkCmdLineFlag(argc, argv, \"device\"))\n    {\n        devID = getCmdLineArgumentInt(argc, argv, \"device=\");\n\n        if (devID < 0)\n        {\n            printf(\"Invalid command line parameter\\n \");\n            exit(EXIT_FAILURE);\n        }\n        else\n        {\n            devID = gpuDeviceInit(devID);\n\n            if (devID < 0)\n            {\n                printf(\"exiting...\\n\");\n                exit(EXIT_FAILURE);\n            }\n        }\n    }\n    else\n    {\n        // Otherwise pick the device with highest Gflops/s\n        devID = gpuGetMaxGflopsDeviceId();\n        checkCudaErrors(cudaSetDevice(devID));\n        checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));\n        printf(\"GPU Device %d: \\\"%s\\\" with compute capability %d.%d\\n\\n\", devID, deviceProp.name, deviceProp.major, deviceProp.minor);\n    }\n\n    return devID;\n}\n\ninline int findIntegratedGPU()\n{\n    int current_device     = 0;\n    int device_count       = 0;\n    int devices_prohibited = 0;\n    \n    cudaDeviceProp deviceProp;\n    checkCudaErrors(cudaGetDeviceCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"CUDA error: no devices supporting CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the integrated GPU which is compute capable\n    while (current_device < device_count)\n    {\n        cudaGetDeviceProperties(&deviceProp, current_device);\n\n        // If GPU is integrated and is not running on Compute Mode prohibited, then cuda can map to GLES resource\n        if (deviceProp.integrated && (deviceProp.computeMode != cudaComputeModeProhibited))\n        {\n            checkCudaErrors(cudaSetDevice(current_device));\n            checkCudaErrors(cudaGetDeviceProperties(&deviceProp, current_device));\n            printf(\"GPU Device %d: \\\"%s\\\" with compute capability %d.%d\\n\\n\", current_device, deviceProp.name, deviceProp.major, deviceProp.minor);\n\n            return current_device;\n        }\n        else\n        {\n            devices_prohibited++;\n        }\n\n        current_device++;\n    }\n\n    if (devices_prohibited == device_count)\n    {\n        fprintf(stderr, \"CUDA error: No GLES-CUDA Interop capable GPU found.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    return -1;\n}\n\n// General check for CUDA GPU SM Capabilities\ninline bool checkCudaCapabilities(int major_version, int minor_version)\n{\n    cudaDeviceProp deviceProp;\n    deviceProp.major = 0;\n    deviceProp.minor = 0;\n    int dev;\n\n    checkCudaErrors(cudaGetDevice(&dev));\n    checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));\n\n    if ((deviceProp.major > major_version) ||\n        (deviceProp.major == major_version && deviceProp.minor >= minor_version))\n    {\n        printf(\"  Device %d: <%16s >, Compute SM %d.%d detected\\n\", dev, deviceProp.name, deviceProp.major, deviceProp.minor);\n        return true;\n    }\n    else\n    {\n        printf(\"  No GPU device was found that can support CUDA compute capability %d.%d.\\n\", major_version, minor_version);\n        return false;\n    }\n}\n#endif\n\n// end of CUDA Helper Functions\n\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_cuda_drvapi.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// Helper functions for CUDA Driver API error handling (make sure that CUDA_H is included in your projects)\n#ifndef HELPER_CUDA_DRVAPI_H\n#define HELPER_CUDA_DRVAPI_H\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <helper_string.h>\n#include <drvapi_error_string.h>\n\n#ifndef MAX\n#define MAX(a,b) (a > b ? a : b)\n#endif\n\n#ifndef HELPER_CUDA_H\ninline int ftoi(float value)\n{\n    return (value >= 0 ? (int)(value + 0.5) : (int)(value - 0.5));\n}\n#endif\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// These are CUDA Helper functions\n\n// add a level of protection to the CUDA SDK samples, let's force samples to explicitly include CUDA.H\n#ifdef  __cuda_cuda_h__\n// This will output the proper CUDA error strings in the event that a CUDA host call returns an error\n#ifndef checkCudaErrors\n#define checkCudaErrors(err)  __checkCudaErrors (err, __FILE__, __LINE__)\n\n// These are the inline versions for all of the SDK helper functions\ninline void __checkCudaErrors(CUresult err, const char *file, const int line)\n{\n    if (CUDA_SUCCESS != err)\n    {\n        fprintf(stderr, \"checkCudaErrors() Driver API error = %04d \\\"%s\\\" from file <%s>, line %i.\\n\",\n                err, getCudaDrvErrorString(err), file, line);\n        exit(EXIT_FAILURE);\n    }\n}\n#endif\n\n#ifdef getLastCudaDrvErrorMsg\n#undef getLastCudaDrvErrorMsg\n#endif\n\n#define getLastCudaDrvErrorMsg(msg)           __getLastCudaDrvErrorMsg  (msg, __FILE__, __LINE__)\n\ninline void __getLastCudaDrvErrorMsg(const char *msg, const char *file, const int line)\n{\n    CUresult err = cuCtxSynchronize();\n\n    if (CUDA_SUCCESS != err)\n    {\n        fprintf(stderr, \"getLastCudaDrvErrorMsg -> %s\", msg);\n        fprintf(stderr, \"getLastCudaDrvErrorMsg -> cuCtxSynchronize API error = %04d \\\"%s\\\" in file <%s>, line %i.\\n\",\n                err, getCudaDrvErrorString(err), file, line);\n        exit(EXIT_FAILURE);\n    }\n}\n\n// This function wraps the CUDA Driver API into a template function\ntemplate <class T>\ninline void getCudaAttribute(T *attribute, CUdevice_attribute device_attribute, int device)\n{\n    CUresult error_result = cuDeviceGetAttribute(attribute, device_attribute, device);\n\n    if (error_result != CUDA_SUCCESS)\n    {\n        printf(\"cuDeviceGetAttribute returned %d\\n-> %s\\n\", (int)error_result, getCudaDrvErrorString(error_result));\n        exit(EXIT_SUCCESS);\n    }\n}\n#endif\n\n// Beginning of GPU Architecture definitions\ninline int _ConvertSMVer2CoresDRV(int major, int minor)\n{\n    // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM\n    typedef struct\n    {\n        int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version\n        int Cores;\n    } sSMtoCores;\n\n    sSMtoCores nGpuArchCoresPerSM[] =\n    {\n        { 0x30, 192}, // Kepler Generation (SM 3.0) GK10x class\n        { 0x32, 192}, // Kepler Generation (SM 3.2) GK10x class\n        { 0x35, 192}, // Kepler Generation (SM 3.5) GK11x class\n        { 0x37, 192}, // Kepler Generation (SM 3.7) GK21x class\n        { 0x50, 128}, // Maxwell Generation (SM 5.0) GM10x class\n        { 0x52, 128}, // Maxwell Generation (SM 5.2) GM20x class\n        { 0x53, 128}, // Maxwell Generation (SM 5.3) GM20x class\n        { 0x60, 64 }, // Pascal Generation (SM 6.0) GP100 class\n        { 0x61, 128}, // Pascal Generation (SM 6.1) GP10x class\n        { 0x62, 128}, // Pascal Generation (SM 6.2) GP10x class\n        { 0x70, 64 }, // Volta Generation (SM 7.0) GV100 class\n        { 0x72, 64 }, // Volta Generation (SM 7.2) GV11b class\n        {   -1, -1 }\n    };\n\n    int index = 0;\n\n    while (nGpuArchCoresPerSM[index].SM != -1)\n    {\n        if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor))\n        {\n            return nGpuArchCoresPerSM[index].Cores;\n        }\n\n        index++;\n    }\n\n    // If we don't find the values, we default use the previous one to run properly\n    printf(\"MapSMtoCores for SM %d.%d is undefined.  Default to use %d Cores/SM\\n\", major, minor, nGpuArchCoresPerSM[index-1].Cores);\n    return nGpuArchCoresPerSM[index-1].Cores;\n}\n// end of GPU Architecture definitions\n\n#ifdef __cuda_cuda_h__\n// General GPU Device CUDA Initialization\ninline int gpuDeviceInitDRV(int ARGC, const char **ARGV)\n{\n    int cuDevice = 0;\n    int deviceCount = 0;\n    CUresult err = cuInit(0);\n\n    if (CUDA_SUCCESS == err)\n    {\n        checkCudaErrors(cuDeviceGetCount(&deviceCount));\n    }\n\n    if (deviceCount == 0)\n    {\n        fprintf(stderr, \"cudaDeviceInit error: no devices supporting CUDA\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    int dev = 0;\n    dev = getCmdLineArgumentInt(ARGC, (const char **) ARGV, \"device=\");\n\n    if (dev < 0)\n    {\n        dev = 0;\n    }\n\n    if (dev > deviceCount-1)\n    {\n        fprintf(stderr, \"\\n\");\n        fprintf(stderr, \">> %d CUDA capable GPU device(s) detected. <<\\n\", deviceCount);\n        fprintf(stderr, \">> cudaDeviceInit (-device=%d) is not a valid GPU device. <<\\n\", dev);\n        fprintf(stderr, \"\\n\");\n        return -dev;\n    }\n\n    checkCudaErrors(cuDeviceGet(&cuDevice, dev));\n    char name[100];\n    cuDeviceGetName(name, 100, cuDevice);\n\n    int computeMode;\n    getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, dev);\n\n    if (computeMode == CU_COMPUTEMODE_PROHIBITED)\n    {\n        fprintf(stderr, \"Error: device is running in <CU_COMPUTEMODE_PROHIBITED>, no threads can use this CUDA Device.\\n\");\n        return -1;\n    }\n\n    if (checkCmdLineFlag(ARGC, (const char **) ARGV, \"quiet\") == false)\n    {\n        printf(\"gpuDeviceInitDRV() Using CUDA Device [%d]: %s\\n\", dev, name);\n    }\n\n    return dev;\n}\n\n// This function returns the best GPU based on performance\ninline int gpuGetMaxGflopsDeviceIdDRV()\n{\n    CUdevice current_device  = 0;\n    CUdevice max_perf_device = 0;\n    int device_count     = 0;\n    int sm_per_multiproc = 0;\n    unsigned long long max_compute_perf = 0;\n    int best_SM_arch = 0;\n    int major = 0;\n    int minor = 0;\n    int multiProcessorCount;\n    int clockRate;\n    int devices_prohibited = 0;\n\n    cuInit(0);\n    checkCudaErrors(cuDeviceGetCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"gpuGetMaxGflopsDeviceIdDRV error: no devices supporting CUDA\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the best major SM Architecture GPU device\n    while (current_device < device_count)\n    {\n        checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));\n\n        if (major > 0 && major < 9999)\n        {\n            best_SM_arch = MAX(best_SM_arch, major);\n        }\n\n        current_device++;\n    }\n\n    // Find the best CUDA capable GPU device\n    current_device = 0;\n\n    while (current_device < device_count)\n    {\n        checkCudaErrors(cuDeviceGetAttribute(&multiProcessorCount,\n                                             CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,\n                                             current_device));\n        checkCudaErrors(cuDeviceGetAttribute(&clockRate,\n                                             CU_DEVICE_ATTRIBUTE_CLOCK_RATE,\n                                             current_device));\n        checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));\n\n        int computeMode;\n        getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device);\n\n        if (computeMode != CU_COMPUTEMODE_PROHIBITED)\n        {\n            if (major == 9999 && minor == 9999)\n            {\n                sm_per_multiproc = 1;\n            }\n            else\n            {\n                sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor);\n            }\n\n            unsigned long long compute_perf = (unsigned long long) (multiProcessorCount * sm_per_multiproc * clockRate);\n\n            if (compute_perf  > max_compute_perf)\n            {\n                // If we find GPU with SM major > 2, search only these\n                if (best_SM_arch > 2)\n                {\n                    // If our device==dest_SM_arch, choose this, or else pass\n                    if (major == best_SM_arch)\n                    {\n                        max_compute_perf  = compute_perf;\n                        max_perf_device   = current_device;\n                    }\n                }\n                else\n                {\n                    max_compute_perf  = compute_perf;\n                    max_perf_device   = current_device;\n                }\n            }\n        }\n        else\n        {\n            devices_prohibited++;\n        }\n\n        ++current_device;\n    }\n\n    if (devices_prohibited == device_count)\n    {    \n        fprintf(stderr, \"gpuGetMaxGflopsDeviceIdDRV error: all devices have compute mode prohibited.\\n\");\n        exit(EXIT_FAILURE);\n    }    \n\n    return max_perf_device;\n}\n\n// This function returns the best Graphics GPU based on performance\ninline int gpuGetMaxGflopsGLDeviceIdDRV()\n{\n    CUdevice current_device = 0, max_perf_device = 0;\n    int device_count     = 0, sm_per_multiproc = 0;\n    int max_compute_perf = 0, best_SM_arch     = 0;\n    int major = 0, minor = 0, multiProcessorCount, clockRate;\n    int bTCC = 0;\n    int devices_prohibited = 0;\n    char deviceName[256];\n\n    cuInit(0);\n    checkCudaErrors(cuDeviceGetCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"gpuGetMaxGflopsGLDeviceIdDRV error: no devices supporting CUDA\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the best major SM Architecture GPU device that are graphics devices\n    while (current_device < device_count)\n    {\n        checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device));\n        checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));\n\n#if CUDA_VERSION >= 3020\n        checkCudaErrors(cuDeviceGetAttribute(&bTCC,  CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device));\n#else\n\n        // Assume a Tesla GPU is running in TCC if we are running CUDA 3.1\n        if (deviceName[0] == 'T')\n        {\n            bTCC = 1;\n        }\n\n#endif\n\n        int computeMode;\n        getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device);\n\n        if (computeMode != CU_COMPUTEMODE_PROHIBITED)\n        {\n            if (!bTCC)\n            {\n                if (major > 0 && major < 9999)\n                {\n                    best_SM_arch = MAX(best_SM_arch, major);\n                }\n            }\n        }\n        else\n        {\n            devices_prohibited++;\n        }\n\n        current_device++;\n    }\n\n    if (devices_prohibited == device_count)\n    {\n        fprintf(stderr, \"gpuGetMaxGflopsGLDeviceIdDRV error: all devices have compute mode prohibited.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the best CUDA capable GPU device\n    current_device = 0;\n\n    while (current_device < device_count)\n    {\n        checkCudaErrors(cuDeviceGetAttribute(&multiProcessorCount,\n                                             CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,\n                                             current_device));\n        checkCudaErrors(cuDeviceGetAttribute(&clockRate,\n                                             CU_DEVICE_ATTRIBUTE_CLOCK_RATE,\n                                             current_device));\n        checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));\n\n#if CUDA_VERSION >= 3020\n        checkCudaErrors(cuDeviceGetAttribute(&bTCC,  CU_DEVICE_ATTRIBUTE_TCC_DRIVER, current_device));\n#else\n\n        // Assume a Tesla GPU is running in TCC if we are running CUDA 3.1\n        if (deviceName[0] == 'T')\n        {\n            bTCC = 1;\n        }\n\n#endif\n\n        int computeMode;\n        getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device);\n\n        if (computeMode != CU_COMPUTEMODE_PROHIBITED)\n        {\n            if (major == 9999 && minor == 9999)\n            {\n                sm_per_multiproc = 1;\n            }\n            else\n            {\n                sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor);\n            }\n\n            // If this is a Tesla based GPU and SM 2.0, and TCC is disabled, this is a contendor\n            if (!bTCC)   // Is this GPU running the TCC driver?  If so we pass on this\n            {\n                int compute_perf  = multiProcessorCount * sm_per_multiproc * clockRate;\n\n                if (compute_perf  > max_compute_perf)\n                {\n                    // If we find GPU with SM major > 2, search only these\n                    if (best_SM_arch > 2)\n                    {\n                        // If our device = dest_SM_arch, then we pick this one\n                        if (major == best_SM_arch)\n                        {\n                            max_compute_perf  = compute_perf;\n                            max_perf_device   = current_device;\n                        }\n                    }\n                    else\n                    {\n                        max_compute_perf  = compute_perf;\n                        max_perf_device   = current_device;\n                    }\n                }\n            }\n        }\n\n        ++current_device;\n    }\n\n    return max_perf_device;\n}\n\n// General initialization call to pick the best CUDA Device\ninline CUdevice findCudaDeviceDRV(int argc, const char **argv)\n{\n    CUdevice cuDevice;\n    int devID = 0;\n\n    // If the command-line has a device number specified, use it\n    if (checkCmdLineFlag(argc, (const char **)argv, \"device\"))\n    {\n        devID = gpuDeviceInitDRV(argc, argv);\n\n        if (devID < 0)\n        {\n            printf(\"exiting...\\n\");\n            exit(EXIT_SUCCESS);\n        }\n    }\n    else\n    {\n        // Otherwise pick the device with highest Gflops/s\n        char name[100];\n        devID = gpuGetMaxGflopsDeviceIdDRV();\n        checkCudaErrors(cuDeviceGet(&cuDevice, devID));\n        cuDeviceGetName(name, 100, cuDevice);\n        printf(\"> Using CUDA Device [%d]: %s\\n\", devID, name);\n    }\n\n    cuDeviceGet(&cuDevice, devID);\n\n    return cuDevice;\n}\n\ninline CUdevice findIntegratedGPUDrv()\n{\n    CUdevice current_device  = 0;\n    int device_count       = 0;\n    int devices_prohibited = 0;\n    int isIntegrated;\n\n    cuInit(0);\n    checkCudaErrors(cuDeviceGetCount(&device_count));\n\n    if (device_count == 0)\n    {\n        fprintf(stderr, \"CUDA error: no devices supporting CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    // Find the integrated GPU which is compute capable\n    while (current_device < device_count)\n    {\n        int computeMode = -1;\n        checkCudaErrors(cuDeviceGetAttribute(&isIntegrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, current_device));\n        checkCudaErrors(cuDeviceGetAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device));\n\n        // If GPU is integrated and is not running on Compute Mode prohibited use that\n        if (isIntegrated && (computeMode != CU_COMPUTEMODE_PROHIBITED))\n        {\n            int major = 0, minor = 0;\n            char deviceName[256];\n            checkCudaErrors(cuDeviceComputeCapability(&major, &minor, current_device));\n            checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device));\n            printf(\"GPU Device %d: \\\"%s\\\" with compute capability %d.%d\\n\\n\", current_device, deviceName, major, minor);\n\n            return  current_device;\n        }\n        else\n        {\n            devices_prohibited++;\n        }\n\n        current_device++;\n    }\n\n    if (devices_prohibited == device_count)\n    {\n        fprintf(stderr, \"CUDA error: No Integrated CUDA capable GPU found.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    return -1;\n}\n\n// This function will pick the best CUDA device available with OpenGL interop\ninline CUdevice findCudaGLDeviceDRV(int argc, const char **argv)\n{\n    CUdevice cuDevice;\n    int devID = 0;\n\n    // If the command-line has a device number specified, use it\n    if (checkCmdLineFlag(argc, (const char **)argv, \"device\"))\n    {\n        devID = gpuDeviceInitDRV(argc, (const char **)argv);\n\n        if (devID < 0)\n        {\n            printf(\"no CUDA capable devices found, exiting...\\n\");\n            exit(EXIT_SUCCESS);\n        }\n    }\n    else\n    {\n        char name[100];\n        // Otherwise pick the device with highest Gflops/s\n        devID = gpuGetMaxGflopsGLDeviceIdDRV();\n        checkCudaErrors(cuDeviceGet(&cuDevice, devID));\n        cuDeviceGetName(name, 100, cuDevice);\n        printf(\"> Using CUDA/GL Device [%d]: %s\\n\", devID, name);\n    }\n\n    return devID;\n}\n\n// General check for CUDA GPU SM Capabilities\ninline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, int devID)\n{\n    CUdevice cuDevice;\n    char name[256];\n    int major = 0, minor = 0;\n\n    checkCudaErrors(cuDeviceGet(&cuDevice, devID));\n    checkCudaErrors(cuDeviceGetName(name, 100, cuDevice));\n    checkCudaErrors(cuDeviceComputeCapability(&major, &minor, devID));\n\n    if ((major > major_version) ||\n        (major == major_version && minor >= minor_version))\n    {\n        printf(\"> Device %d: <%16s >, Compute SM %d.%d detected\\n\", devID, name, major, minor);\n        return true;\n    }\n    else\n    {\n        printf(\"No GPU device was found that can support CUDA compute capability %d.%d.\\n\", major_version, minor_version);\n        return false;\n    }\n}\n#endif\n\n// end of CUDA Helper Functions\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_cuda_gl.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef HELPER_CUDA_GL_H\n#define HELPER_CUDA_GL_H\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n\n// includes, graphics\n#if defined (__APPLE__) || defined(MACOSX)\n#include <OpenGL/gl.h>\n#else\n#include <GL/gl.h>\n#endif\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n#ifdef __DRIVER_TYPES_H__\n#ifndef DEVICE_RESET\n#define DEVICE_RESET cudaDeviceReset()\n#endif\n#else\n#ifndef DEVICE_RESET\n#define DEVICE_RESET\n#endif\n#endif\n\n#ifdef __CUDA_GL_INTEROP_H__\n////////////////////////////////////////////////////////////////////////////////\n// These are CUDA OpenGL Helper functions\n\ninline int gpuGLDeviceInit(int ARGC, const char **ARGV)\n{\n    int deviceCount;\n    checkCudaErrors(cudaGetDeviceCount(&deviceCount));\n\n    if (deviceCount == 0)\n    {\n        fprintf(stderr, \"CUDA error: no devices supporting CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    int dev = 0;\n    dev = getCmdLineArgumentInt(ARGC, ARGV, \"device=\");\n\n    if (dev < 0)\n    {\n        dev = 0;\n    }\n\n    if (dev > deviceCount-1)\n    {\n        fprintf(stderr, \"\\n\");\n        fprintf(stderr, \">> %d CUDA capable GPU device(s) detected. <<\\n\", deviceCount);\n        fprintf(stderr, \">> gpuGLDeviceInit (-device=%d) is not a valid GPU device. <<\\n\", dev);\n        fprintf(stderr, \"\\n\");\n        return -dev;\n    }\n\n    cudaDeviceProp deviceProp;\n    checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));\n\n    if (deviceProp.computeMode == cudaComputeModeProhibited)\n    {\n        fprintf(stderr, \"Error: device is running in <Compute Mode Prohibited>, no threads can use ::cudaSetDevice().\\n\");\n        return -1;\n    }\n\n    if (deviceProp.major < 1)\n    {\n        fprintf(stderr, \"Error: device does not support CUDA.\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    if (checkCmdLineFlag(ARGC, ARGV, \"quiet\") == false)\n    {\n        fprintf(stderr, \"Using device %d: %s\\n\", dev, deviceProp.name);\n    }\n\n    checkCudaErrors(cudaGLSetGLDevice(dev));\n    return dev;\n}\n\n// This function will pick the best CUDA device available with OpenGL interop\ninline int findCudaGLDevice(int argc, const char **argv)\n{\n    int devID = 0;\n\n    // If the command-line has a device number specified, use it\n    if (checkCmdLineFlag(argc, (const char **)argv, \"device\"))\n    {\n        devID = gpuGLDeviceInit(argc, (const char **)argv);\n\n        if (devID < 0)\n        {\n            printf(\"no CUDA capable devices found, exiting...\\n\");\n            DEVICE_RESET\n            exit(EXIT_SUCCESS);\n        }\n    }\n    else\n    {\n        // Otherwise pick the device with highest Gflops/s\n        devID = gpuGetMaxGflopsDeviceId();\n        cudaGLSetGLDevice(devID);\n    }\n\n    return devID;\n}\n\nstatic inline const char* glErrorToString(GLenum err)\n{\n#define CASE_RETURN_MACRO(arg) case arg: return #arg\n    switch(err)\n    {\n        CASE_RETURN_MACRO(GL_NO_ERROR);\n        CASE_RETURN_MACRO(GL_INVALID_ENUM);\n        CASE_RETURN_MACRO(GL_INVALID_VALUE);\n        CASE_RETURN_MACRO(GL_INVALID_OPERATION);\n        CASE_RETURN_MACRO(GL_OUT_OF_MEMORY);\n        CASE_RETURN_MACRO(GL_STACK_UNDERFLOW);\n        CASE_RETURN_MACRO(GL_STACK_OVERFLOW);\n#ifdef GL_INVALID_FRAMEBUFFER_OPERATION\n        CASE_RETURN_MACRO(GL_INVALID_FRAMEBUFFER_OPERATION);\n#endif\n        default: break;\n    }\n#undef CASE_RETURN_MACRO\n    return \"*UNKNOWN*\";\n}\n////////////////////////////////////////////////////////////////////////////\n//! Check for OpenGL error\n//! @return bool if no GL error has been encountered, otherwise 0\n//! @param file  __FILE__ macro\n//! @param line  __LINE__ macro\n//! @note The GL error is listed on stderr\n//! @note This function should be used via the CHECK_ERROR_GL() macro\n////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkCheckErrorGL(const char *file, const int line)\n{\n    bool ret_val = true;\n\n    // check for error\n    GLenum gl_error = glGetError();\n\n    if (gl_error != GL_NO_ERROR)\n    {\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n        char tmpStr[512];\n        // NOTE: \"%s(%i) : \" allows Visual Studio to directly jump to the file at the right line\n        // when the user double clicks on the error line in the Output pane. Like any compile error.\n        sprintf_s(tmpStr, 255, \"\\n%s(%i) : GL Error : %s\\n\\n\", file, line, glErrorToString(gl_error));\n        fprintf(stderr, \"%s\", tmpStr);\n#endif\n        fprintf(stderr, \"GL Error in file '%s' in line %d :\\n\", file, line);\n        fprintf(stderr, \"%s\\n\", glErrorToString(gl_error));\n        ret_val = false;\n    }\n\n    return ret_val;\n}\n\n#define SDK_CHECK_ERROR_GL()                                              \\\n    if( false == sdkCheckErrorGL( __FILE__, __LINE__)) {                  \\\n        DEVICE_RESET                                                      \\\n        exit(EXIT_FAILURE);                                               \\\n    }\n#endif\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_cusolver.h",
    "content": "/*\n * Copyright 2015 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef HELPER_CUSOLVER\n#define HELPER_CUSOLVER\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <math.h>\n#include <cuda_runtime.h>\n\n#include \"cusparse.h\"\n\n#define SWITCH_CHAR             '-'\n\nstruct  testOpts {\n    char *sparse_mat_filename;   // by switch -F<filename>\n    const char *testFunc; // by switch -R<name>\n    const char *reorder; // by switch -P<name>\n    int lda; // by switch -lda<int>\n};\n\ndouble vec_norminf(int n, const double *x)\n{\n    double norminf = 0;\n    for(int j = 0 ; j < n ; j++){\n        double x_abs = fabs(x[j]);\n        norminf = (norminf > x_abs)? norminf : x_abs;\n    }\n    return norminf;\n}\n\n/*\n * |A| = max { |A|*ones(m,1) }\n */\ndouble mat_norminf(\n    int m,\n    int n,\n    const double *A,\n    int lda)\n{\n    double norminf = 0;\n    for(int i = 0 ; i < m ; i++){\n        double sum = 0.0;\n        for(int j = 0 ; j < n ; j++){\n           double A_abs = fabs(A[i + j*lda]);\n           sum += A_abs;\n        }\n        norminf = (norminf > sum)? norminf : sum;\n    }\n    return norminf;\n}\n\n/*\n * |A| = max { |A|*ones(m,1) }\n */\ndouble csr_mat_norminf(\n    int m,\n    int n,\n    int nnzA,\n    const cusparseMatDescr_t descrA,\n    const double *csrValA,\n    const int *csrRowPtrA,\n    const int *csrColIndA)\n{\n    const int baseA = (CUSPARSE_INDEX_BASE_ONE == cusparseGetMatIndexBase(descrA))? 1:0;\n\n    double norminf = 0;\n    for(int i = 0 ; i < m ; i++){\n        double sum = 0.0;\n        const int start = csrRowPtrA[i  ] - baseA;\n        const int end   = csrRowPtrA[i+1] - baseA;\n        for(int colidx = start ; colidx < end ; colidx++){\n            // const int j = csrColIndA[colidx] - baseA; \n           double A_abs = fabs( csrValA[colidx] );\n           sum += A_abs;\n        }\n        norminf = (norminf > sum)? norminf : sum;\n    }\n    return norminf;\n}\n\n\nvoid display_matrix(\n    int m,\n    int n,\n    int nnzA,\n    const cusparseMatDescr_t descrA,\n    const double *csrValA,\n    const int *csrRowPtrA,\n    const int *csrColIndA)\n{\n    const int baseA = (CUSPARSE_INDEX_BASE_ONE == cusparseGetMatIndexBase(descrA))? 1:0;\n\n    printf(\"m = %d, n = %d, nnz = %d, matlab base-1\\n\", m, n, nnzA);\n\n    for(int row = 0 ; row < m ; row++){\n        const int start = csrRowPtrA[row  ] - baseA;\n        const int end   = csrRowPtrA[row+1] - baseA;\n        for(int colidx = start ; colidx < end ; colidx++){\n            const int col = csrColIndA[colidx] - baseA;\n            double Areg = csrValA[colidx];\n            printf(\"A(%d, %d) = %20.16E\\n\", row+1, col+1, Areg);\n        }\n    }\n}\n\n\n#if defined(_WIN32)\n#if !defined(WIN32_LEAN_AND_MEAN)\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <windows.h>\ndouble second (void)\n{\n    LARGE_INTEGER t;\n    static double oofreq;\n    static int checkedForHighResTimer;\n    static BOOL hasHighResTimer;\n\n    if (!checkedForHighResTimer) {\n        hasHighResTimer = QueryPerformanceFrequency (&t);\n        oofreq = 1.0 / (double)t.QuadPart;\n        checkedForHighResTimer = 1;\n    }\n    if (hasHighResTimer) {\n        QueryPerformanceCounter (&t);\n        return (double)t.QuadPart * oofreq;\n    } else {\n        return (double)GetTickCount() / 1000.0;\n    }\n}\n\n#elif defined(__linux) || defined(__QNX__)\n#include <stddef.h>\n#include <sys/time.h>\n#include <sys/resource.h>\ndouble second (void)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;\n}\n\n#elif defined(__APPLE__)\n#include <stddef.h>\n#include <sys/time.h>\n#include <sys/resource.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\ndouble second (void)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;\n}\n#else\n#error unsupported platform\n#endif\n\n#endif\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_functions.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// These are helper functions for the SDK samples (string parsing, timers, image helpers, etc)\n#ifndef HELPER_FUNCTIONS_H\n#define HELPER_FUNCTIONS_H\n\n#ifdef WIN32\n#pragma warning(disable:4996)\n#endif\n\n// includes, project\n#include <stdio.h>\n#include <stdlib.h>\n#include <string>\n#include <assert.h>\n#include <exception.h>\n#include <math.h>\n\n#include <fstream>\n#include <vector>\n#include <iostream>\n#include <algorithm>\n\n// includes, timer, string parsing, image helpers\n#include <helper_timer.h>   // helper functions for timers\n#include <helper_string.h>  // helper functions for string parsing\n#include <helper_image.h>   // helper functions for image compare, dump, data comparisons\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n#endif //  HELPER_FUNCTIONS_H\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_gl.h",
    "content": "/**\n * Copyright 2014 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// These are helper functions for the SDK samples (OpenGL)\n#ifndef HELPER_GL_H\n#define HELPER_GL_H\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n    #include <GL/glew.h>\n#endif\n\n#if defined(__APPLE__) || defined(MACOSX)\n    #include <OpenGL/gl.h>\n#else\n    #include <GL/gl.h>\n    #ifdef __linux__\n    #include <GL/glx.h>\n    #endif /* __linux__ */\n#endif\n\n#include <iostream>\n#include <string>\n#include <sstream>\n#include <algorithm>\n#include <iterator>\n#include <vector>\n#include <assert.h>\n\n\n/* Prototypes */\nnamespace __HelperGL {\n    static int isGLVersionSupported(unsigned reqMajor, unsigned reqMinor);\n    static int areGLExtensionsSupported(const std::string &);\n#ifdef __linux__\n\n    #ifndef HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION\n    #define USE_GL_FUNC(name, proto) proto name = (proto) glXGetProcAddress ((const GLubyte *)#name)\n    #else\n    #define USE_GL_FUNC(name, proto) extern proto name\n    #endif\n\n    USE_GL_FUNC(glBindBuffer, PFNGLBINDBUFFERPROC);\n    USE_GL_FUNC(glDeleteBuffers, PFNGLDELETEBUFFERSPROC);\n    USE_GL_FUNC(glBufferData, PFNGLBUFFERDATAPROC);\n    USE_GL_FUNC(glBufferSubData, PFNGLBUFFERSUBDATAPROC);\n    USE_GL_FUNC(glGenBuffers, PFNGLGENBUFFERSPROC);\n    USE_GL_FUNC(glCreateProgram, PFNGLCREATEPROGRAMPROC);\n    USE_GL_FUNC(glBindProgramARB, PFNGLBINDPROGRAMARBPROC);\n    USE_GL_FUNC(glGenProgramsARB, PFNGLGENPROGRAMSARBPROC);\n    USE_GL_FUNC(glDeleteProgramsARB, PFNGLDELETEPROGRAMSARBPROC);\n    USE_GL_FUNC(glDeleteProgram, PFNGLDELETEPROGRAMPROC);\n    USE_GL_FUNC(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC);\n    USE_GL_FUNC(glGetProgramiv, PFNGLGETPROGRAMIVPROC);\n    USE_GL_FUNC(glProgramParameteriEXT, PFNGLPROGRAMPARAMETERIEXTPROC);\n    USE_GL_FUNC(glProgramStringARB, PFNGLPROGRAMSTRINGARBPROC);\n    USE_GL_FUNC(glUnmapBuffer, PFNGLUNMAPBUFFERPROC);\n    USE_GL_FUNC(glMapBuffer, PFNGLMAPBUFFERPROC);\n    USE_GL_FUNC(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC);\n    USE_GL_FUNC(glLinkProgram, PFNGLLINKPROGRAMPROC);\n    USE_GL_FUNC(glUseProgram, PFNGLUSEPROGRAMPROC);\n    USE_GL_FUNC(glAttachShader, PFNGLATTACHSHADERPROC);\n    USE_GL_FUNC(glCreateShader, PFNGLCREATESHADERPROC);\n    USE_GL_FUNC(glShaderSource, PFNGLSHADERSOURCEPROC);\n    USE_GL_FUNC(glCompileShader, PFNGLCOMPILESHADERPROC);\n    USE_GL_FUNC(glDeleteShader, PFNGLDELETESHADERPROC);\n    USE_GL_FUNC(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC);\n    USE_GL_FUNC(glGetShaderiv, PFNGLGETSHADERIVPROC);\n    USE_GL_FUNC(glUniform1i, PFNGLUNIFORM1IPROC);\n    USE_GL_FUNC(glUniform1f, PFNGLUNIFORM1FPROC);\n    USE_GL_FUNC(glUniform2f, PFNGLUNIFORM2FPROC);\n    USE_GL_FUNC(glUniform3f, PFNGLUNIFORM3FPROC);\n    USE_GL_FUNC(glUniform4f, PFNGLUNIFORM4FPROC);\n    USE_GL_FUNC(glUniform1fv, PFNGLUNIFORM1FVPROC);\n    USE_GL_FUNC(glUniform2fv, PFNGLUNIFORM2FVPROC);\n    USE_GL_FUNC(glUniform3fv, PFNGLUNIFORM3FVPROC);\n    USE_GL_FUNC(glUniform4fv, PFNGLUNIFORM4FVPROC);\n    USE_GL_FUNC(glUniformMatrix4fv, PFNGLUNIFORMMATRIX4FVPROC);\n    USE_GL_FUNC(glSecondaryColor3fv, PFNGLSECONDARYCOLOR3FVPROC);\n    USE_GL_FUNC(glGetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC);\n    USE_GL_FUNC(glGenFramebuffersEXT, PFNGLGENFRAMEBUFFERSEXTPROC);\n    USE_GL_FUNC(glBindFramebufferEXT, PFNGLBINDFRAMEBUFFEREXTPROC);\n    USE_GL_FUNC(glDeleteFramebuffersEXT, PFNGLDELETEFRAMEBUFFERSEXTPROC);\n    USE_GL_FUNC(glCheckFramebufferStatusEXT, PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC);\n    USE_GL_FUNC(glGetFramebufferAttachmentParameterivEXT, PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC);\n    USE_GL_FUNC(glFramebufferTexture1DEXT, PFNGLFRAMEBUFFERTEXTURE1DEXTPROC);\n    USE_GL_FUNC(glFramebufferTexture2DEXT, PFNGLFRAMEBUFFERTEXTURE2DEXTPROC);\n    USE_GL_FUNC(glFramebufferTexture3DEXT, PFNGLFRAMEBUFFERTEXTURE3DEXTPROC);\n    USE_GL_FUNC(glGenerateMipmapEXT, PFNGLGENERATEMIPMAPEXTPROC);\n    USE_GL_FUNC(glGenRenderbuffersEXT, PFNGLGENRENDERBUFFERSEXTPROC);\n    USE_GL_FUNC(glDeleteRenderbuffersEXT, PFNGLDELETERENDERBUFFERSEXTPROC);\n    USE_GL_FUNC(glBindRenderbufferEXT, PFNGLBINDRENDERBUFFEREXTPROC);\n    USE_GL_FUNC(glRenderbufferStorageEXT, PFNGLRENDERBUFFERSTORAGEEXTPROC);\n    USE_GL_FUNC(glFramebufferRenderbufferEXT, PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC);\n    USE_GL_FUNC(glClampColorARB, PFNGLCLAMPCOLORARBPROC);\n    USE_GL_FUNC(glBindFragDataLocationEXT, PFNGLBINDFRAGDATALOCATIONEXTPROC);\n\n#if !defined(GLX_EXTENSION_NAME) || !defined(GL_VERSION_1_3)\n    USE_GL_FUNC(glActiveTexture, PFNGLACTIVETEXTUREPROC);\n    USE_GL_FUNC(glClientActiveTexture, PFNGLACTIVETEXTUREPROC);\n#endif\n\n    #undef USE_GL_FUNC\n#endif /*__linux__ */\n}\n\n\nnamespace __HelperGL {\n    namespace __Int {\n        static std::vector<std::string> split(const std::string &str)\n        {\n            std::istringstream ss(str);\n            std::istream_iterator<std::string> it(ss);\n            return std::vector<std::string> (it, std::istream_iterator<std::string>());\n        }\n\n        /* Sort the vector passed by reference */\n        template<typename T> static inline void sort(std::vector<T> &a)\n        {\n            std::sort(a.begin(), a.end());\n        }\n\n        /* Compare two vectors */\n        template<typename T> static int equals(std::vector<T> a, std::vector<T> b)\n        {\n            if (a.size() != b.size()) return 0;\n            sort(a);\n            sort(b);\n\n            return std::equal(a.begin(), a.end(), b.begin());\n        }\n\n        template<typename T> static std::vector<T> getIntersection(std::vector<T> a, std::vector<T> b)\n        {\n            sort(a);\n            sort(b);\n\n            std::vector<T> rc;\n            std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),\n                             std::back_inserter<std::vector<std::string> >(rc));\n            return rc;\n        }\n\n        static std::vector<std::string> getGLExtensions()\n        {\n            std::string extensionsStr( (const char *)glGetString(GL_EXTENSIONS));\n            return split (extensionsStr);\n        }\n    }\n\n    static int areGLExtensionsSupported(const std::string &extensions)\n    {\n        std::vector<std::string> all = __Int::getGLExtensions();\n\n        std::vector<std::string> requested = __Int::split(extensions);\n        std::vector<std::string> matched = __Int::getIntersection(all, requested);\n\n        return __Int::equals(matched, requested);\n    }\n\n    static int isGLVersionSupported(unsigned reqMajor, unsigned reqMinor)\n    {\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n        if (glewInit() != GLEW_OK)\n        {\n            std::cerr << \"glewInit() failed!\" << std::endl;\n            return 0;\n        }\n#endif\n        std::string version ((const char *) glGetString (GL_VERSION));\n        std::stringstream stream (version);\n        unsigned major, minor;\n        char dot;\n\n        stream >> major >> dot >> minor;\n\n        assert (dot == '.');\n        return major > reqMajor || (major == reqMajor && minor >= reqMinor);\n    }\n} /* of namespace __HelperGL*/\n\nusing namespace __HelperGL;\n\n#endif /*HELPER_GL_H*/\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_image.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// These are helper functions for the SDK samples (image,bitmap)\n#ifndef HELPER_IMAGE_H\n#define HELPER_IMAGE_H\n\n#include <string>\n#include <fstream>\n#include <vector>\n#include <iostream>\n#include <algorithm>\n\n#include <assert.h>\n#include <exception.h>\n#include <math.h>\n\n#ifndef MIN\n#define MIN(a,b) ((a < b) ? a : b)\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a > b) ? a : b)\n#endif\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n#include <helper_string.h>\n\n// namespace unnamed (internal)\nnamespace\n{\n    //! size of PGM file header\n    const unsigned int PGMHeaderSize = 0x40;\n\n    // types\n\n    //! Data converter from unsigned char / unsigned byte to type T\n    template<class T>\n    struct ConverterFromUByte;\n\n    //! Data converter from unsigned char / unsigned byte\n    template<>\n    struct ConverterFromUByte<unsigned char>\n    {\n        //! Conversion operator\n        //! @return converted value\n        //! @param  val  value to convert\n        float operator()(const unsigned char &val)\n        {\n            return static_cast<unsigned char>(val);\n        }\n    };\n\n    //! Data converter from unsigned char / unsigned byte to float\n    template<>\n    struct ConverterFromUByte<float>\n    {\n        //! Conversion operator\n        //! @return converted value\n        //! @param  val  value to convert\n        float operator()(const unsigned char &val)\n        {\n            return static_cast<float>(val) / 255.0f;\n        }\n    };\n\n    //! Data converter from unsigned char / unsigned byte to type T\n    template<class T>\n    struct ConverterToUByte;\n\n    //! Data converter from unsigned char / unsigned byte to unsigned int\n    template<>\n    struct ConverterToUByte<unsigned char>\n    {\n        //! Conversion operator (essentially a passthru\n        //! @return converted value\n        //! @param  val  value to convert\n        unsigned char operator()(const unsigned char &val)\n        {\n            return val;\n        }\n    };\n\n    //! Data converter from unsigned char / unsigned byte to unsigned int\n    template<>\n    struct ConverterToUByte<float>\n    {\n        //! Conversion operator\n        //! @return converted value\n        //! @param  val  value to convert\n        unsigned char operator()(const float &val)\n        {\n            return static_cast<unsigned char>(val * 255.0f);\n        }\n    };\n}\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#ifndef FOPEN\n#define FOPEN(fHandle,filename,mode) fopen_s(&fHandle, filename, mode)\n#endif\n#ifndef FOPEN_FAIL\n#define FOPEN_FAIL(result) (result != 0)\n#endif\n#ifndef SSCANF\n#define SSCANF sscanf_s\n#endif\n#else\n#ifndef FOPEN\n#define FOPEN(fHandle,filename,mode) (fHandle = fopen(filename, mode))\n#endif\n#ifndef FOPEN_FAIL\n#define FOPEN_FAIL(result) (result == NULL)\n#endif\n#ifndef SSCANF\n#define SSCANF sscanf\n#endif\n#endif\n\ninline bool\n__loadPPM(const char *file, unsigned char **data,\n          unsigned int *w, unsigned int *h, unsigned int *channels)\n{\n    FILE *fp = NULL;\n\n    if (FOPEN_FAIL(FOPEN(fp, file, \"rb\")))\n    {\n        std::cerr << \"__LoadPPM() : Failed to open file: \" << file << std::endl;\n        return false;\n    }\n\n    // check header\n    char header[PGMHeaderSize];\n\n    if (fgets(header, PGMHeaderSize, fp) == NULL)\n    {\n        std::cerr << \"__LoadPPM() : reading PGM header returned NULL\" << std::endl;\n        return false;\n    }\n\n    if (strncmp(header, \"P5\", 2) == 0)\n    {\n        *channels = 1;\n    }\n    else if (strncmp(header, \"P6\", 2) == 0)\n    {\n        *channels = 3;\n    }\n    else\n    {\n        std::cerr << \"__LoadPPM() : File is not a PPM or PGM image\" << std::endl;\n        *channels = 0;\n        return false;\n    }\n\n    // parse header, read maxval, width and height\n    unsigned int width = 0;\n    unsigned int height = 0;\n    unsigned int maxval = 0;\n    unsigned int i = 0;\n\n    while (i < 3)\n    {\n        if (fgets(header, PGMHeaderSize, fp) == NULL)\n        {\n            std::cerr << \"__LoadPPM() : reading PGM header returned NULL\" << std::endl;\n            return false;\n        }\n\n        if (header[0] == '#')\n        {\n            continue;\n        }\n\n        if (i == 0)\n        {\n            i += SSCANF(header, \"%u %u %u\", &width, &height, &maxval);\n        }\n        else if (i == 1)\n        {\n            i += SSCANF(header, \"%u %u\", &height, &maxval);\n        }\n        else if (i == 2)\n        {\n            i += SSCANF(header, \"%u\", &maxval);\n        }\n    }\n\n    // check if given handle for the data is initialized\n    if (NULL != *data)\n    {\n        if (*w != width || *h != height)\n        {\n            std::cerr << \"__LoadPPM() : Invalid image dimensions.\" << std::endl;\n        }\n    }\n    else\n    {\n        *data = (unsigned char *) malloc(sizeof(unsigned char) * width * height **channels);\n        *w = width;\n        *h = height;\n    }\n\n    // read and close file\n    if (fread(*data, sizeof(unsigned char), width * height **channels, fp) == 0)\n    {\n        std::cerr << \"__LoadPPM() read data returned error.\" << std::endl;\n    }\n\n    fclose(fp);\n\n    return true;\n}\n\ntemplate <class T>\ninline bool\nsdkLoadPGM(const char *file, T **data, unsigned int *w, unsigned int *h)\n{\n    unsigned char *idata = NULL;\n    unsigned int channels;\n\n    if (true != __loadPPM(file, &idata, w, h, &channels))\n    {\n        return false;\n    }\n\n    unsigned int size = *w **h * channels;\n\n    // initialize mem if necessary\n    // the correct size is checked / set in loadPGMc()\n    if (NULL == *data)\n    {\n        *data = (T *) malloc(sizeof(T) * size);\n    }\n\n    // copy and cast data\n    std::transform(idata, idata + size, *data, ConverterFromUByte<T>());\n\n    free(idata);\n\n    return true;\n}\n\ntemplate <class T>\ninline bool\nsdkLoadPPM4(const char *file, T **data,\n            unsigned int *w,unsigned int *h)\n{\n    unsigned char *idata = 0;\n    unsigned int channels;\n\n    if (__loadPPM(file, &idata, w, h, &channels))\n    {\n        // pad 4th component\n        int size = *w **h;\n        // keep the original pointer\n        unsigned char *idata_orig = idata;\n        *data = (T *) malloc(sizeof(T) * size * 4);\n        unsigned char *ptr = *data;\n\n        for (int i=0; i<size; i++)\n        {\n            *ptr++ = *idata++;\n            *ptr++ = *idata++;\n            *ptr++ = *idata++;\n            *ptr++ = 0;\n        }\n\n        free(idata_orig);\n        return true;\n    }\n    else\n    {\n        free(idata);\n        return false;\n    }\n}\n\ninline bool\n__savePPM(const char *file, unsigned char *data,\n          unsigned int w, unsigned int h, unsigned int channels)\n{\n    assert(NULL != data);\n    assert(w > 0);\n    assert(h > 0);\n\n    std::fstream fh(file, std::fstream::out | std::fstream::binary);\n\n    if (fh.bad())\n    {\n        std::cerr << \"__savePPM() : Opening file failed.\" << std::endl;\n        return false;\n    }\n\n    if (channels == 1)\n    {\n        fh << \"P5\\n\";\n    }\n    else if (channels == 3)\n    {\n        fh << \"P6\\n\";\n    }\n    else\n    {\n        std::cerr << \"__savePPM() : Invalid number of channels.\" << std::endl;\n        return false;\n    }\n\n    fh << w << \"\\n\" << h << \"\\n\" << 0xff << std::endl;\n\n    for (unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i)\n    {\n        fh << data[i];\n    }\n\n    fh.flush();\n\n    if (fh.bad())\n    {\n        std::cerr << \"__savePPM() : Writing data failed.\" << std::endl;\n        return false;\n    }\n\n    fh.close();\n\n    return true;\n}\n\ntemplate<class T>\ninline bool\nsdkSavePGM(const char *file, T *data, unsigned int w, unsigned int h)\n{\n    unsigned int size = w * h;\n    unsigned char *idata =\n        (unsigned char *) malloc(sizeof(unsigned char) * size);\n\n    std::transform(data, data + size, idata, ConverterToUByte<T>());\n\n    // write file\n    bool result = __savePPM(file, idata, w, h, 1);\n\n    // cleanup\n    free(idata);\n\n    return result;\n}\n\ninline bool\nsdkSavePPM4ub(const char *file, unsigned char *data,\n              unsigned int w, unsigned int h)\n{\n    // strip 4th component\n    int size = w * h;\n    unsigned char *ndata = (unsigned char *) malloc(sizeof(unsigned char) * size*3);\n    unsigned char *ptr = ndata;\n\n    for (int i=0; i<size; i++)\n    {\n        *ptr++ = *data++;\n        *ptr++ = *data++;\n        *ptr++ = *data++;\n        data++;\n    }\n\n    bool result = __savePPM(file, ndata, w, h, 3);\n    free(ndata);\n    return result;\n}\n\n\n//////////////////////////////////////////////////////////////////////////////\n//! Read file \\filename and return the data\n//! @return bool if reading the file succeeded, otherwise false\n//! @param filename name of the source file\n//! @param data  uninitialized pointer, returned initialized and pointing to\n//!        the data read\n//! @param len  number of data elements in data, -1 on error\n//////////////////////////////////////////////////////////////////////////////\ntemplate<class T>\ninline bool\nsdkReadFile(const char *filename, T **data, unsigned int *len, bool verbose)\n{\n    // check input arguments\n    assert(NULL != filename);\n    assert(NULL != len);\n\n    // intermediate storage for the data read\n    std::vector<T>  data_read;\n\n    // open file for reading\n    FILE *fh = NULL;\n\n    // check if filestream is valid\n    if (FOPEN_FAIL(FOPEN(fh, filename, \"r\")))\n    {\n        printf(\"Unable to open input file: %s\\n\", filename);\n        return false;\n    }\n\n    // read all data elements\n    T token;\n\n    while (!feof(fh))\n    {\n        fscanf(fh, \"%f\", &token);\n        data_read.push_back(token);\n    }\n\n    // the last element is read twice\n    data_read.pop_back();\n    fclose(fh);\n\n    // check if the given handle is already initialized\n    if (NULL != *data)\n    {\n        if (*len != data_read.size())\n        {\n            std::cerr << \"sdkReadFile() : Initialized memory given but \"\n                      << \"size  mismatch with signal read \"\n                      << \"(data read / data init = \" << (unsigned int)data_read.size()\n                      <<  \" / \" << *len << \")\" << std::endl;\n\n            return false;\n        }\n    }\n    else\n    {\n        // allocate storage for the data read\n        *data = (T *) malloc(sizeof(T) * data_read.size());\n        // store signal size\n        *len = static_cast<unsigned int>(data_read.size());\n    }\n\n    // copy data\n    memcpy(*data, &data_read.front(), sizeof(T) * data_read.size());\n\n    return true;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//! Read file \\filename and return the data\n//! @return bool if reading the file succeeded, otherwise false\n//! @param filename name of the source file\n//! @param data  uninitialized pointer, returned initialized and pointing to\n//!        the data read\n//! @param len  number of data elements in data, -1 on error\n//////////////////////////////////////////////////////////////////////////////\ntemplate<class T>\ninline bool\nsdkReadFileBlocks(const char *filename, T **data, unsigned int *len, unsigned int block_num, unsigned int block_size, bool verbose)\n{\n    // check input arguments\n    assert(NULL != filename);\n    assert(NULL != len);\n\n    // open file for reading\n    FILE *fh = fopen(filename, \"rb\");\n\n    if (fh == NULL && verbose)\n    {\n        std::cerr << \"sdkReadFile() : Opening file failed.\" << std::endl;\n        return false;\n    }\n\n    // check if the given handle is already initialized\n    // allocate storage for the data read\n    data[block_num] = (T *) malloc(block_size);\n\n    // read all data elements\n    fseek(fh, block_num * block_size, SEEK_SET);\n    *len = fread(data[block_num], sizeof(T), block_size/sizeof(T), fh);\n\n    fclose(fh);\n\n    return true;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//! Write a data file \\filename\n//! @return true if writing the file succeeded, otherwise false\n//! @param filename name of the source file\n//! @param data  data to write\n//! @param len  number of data elements in data, -1 on error\n//! @param epsilon  epsilon for comparison\n//////////////////////////////////////////////////////////////////////////////\ntemplate<class T, class S>\ninline bool\nsdkWriteFile(const char *filename, const T *data, unsigned int len,\n             const S epsilon, bool verbose, bool append = false)\n{\n    assert(NULL != filename);\n    assert(NULL != data);\n\n    // open file for writing\n    //    if (append) {\n    std::fstream fh(filename, std::fstream::out | std::fstream::ate);\n\n    if (verbose)\n    {\n        std::cerr << \"sdkWriteFile() : Open file \" << filename << \" for write/append.\" << std::endl;\n    }\n\n    /*    } else {\n            std::fstream fh(filename, std::fstream::out);\n            if (verbose) {\n                std::cerr << \"sdkWriteFile() : Open file \" << filename << \" for write.\" << std::endl;\n            }\n        }\n    */\n\n    // check if filestream is valid\n    if (! fh.good())\n    {\n        if (verbose)\n        {\n            std::cerr << \"sdkWriteFile() : Opening file failed.\" << std::endl;\n        }\n\n        return false;\n    }\n\n    // first write epsilon\n    fh << \"# \" << epsilon << \"\\n\";\n\n    // write data\n    for (unsigned int i = 0; (i < len) && (fh.good()); ++i)\n    {\n        fh << data[i] << ' ';\n    }\n\n    // Check if writing succeeded\n    if (! fh.good())\n    {\n        if (verbose)\n        {\n            std::cerr << \"sdkWriteFile() : Writing file failed.\" << std::endl;\n        }\n\n        return false;\n    }\n\n    // file ends with nl\n    fh << std::endl;\n\n    return true;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//! Compare two arrays of arbitrary type\n//! @return  true if \\a reference and \\a data are identical, otherwise false\n//! @param reference  timer_interface to the reference data / gold image\n//! @param data       handle to the computed data\n//! @param len        number of elements in reference and data\n//! @param epsilon    epsilon to use for the comparison\n//////////////////////////////////////////////////////////////////////////////\ntemplate<class T, class S>\ninline bool\ncompareData(const T *reference, const T *data, const unsigned int len,\n            const S epsilon, const float threshold)\n{\n    assert(epsilon >= 0);\n\n    bool result = true;\n    unsigned int error_count = 0;\n\n    for (unsigned int i = 0; i < len; ++i)\n    {\n        float diff = (float)reference[i] - (float)data[i];\n        bool comp = (diff <= epsilon) && (diff >= -epsilon);\n        result &= comp;\n\n        error_count += !comp;\n\n#if 0\n\n        if (! comp)\n        {\n            std::cerr << \"ERROR, i = \" << i << \",\\t \"\n                      << reference[i] << \" / \"\n                      << data[i]\n                      << \" (reference / data)\\n\";\n        }\n\n#endif\n    }\n\n    if (threshold == 0.0f)\n    {\n        return (result) ? true : false;\n    }\n    else\n    {\n        if (error_count)\n        {\n            printf(\"%4.2f(%%) of bytes mismatched (count=%d)\\n\", (float)error_count*100/(float)len, error_count);\n        }\n\n        return (len*threshold > error_count) ? true : false;\n    }\n}\n\n#ifndef __MIN_EPSILON_ERROR\n#define __MIN_EPSILON_ERROR 1e-3f\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//! Compare two arrays of arbitrary type\n//! @return  true if \\a reference and \\a data are identical, otherwise false\n//! @param reference  handle to the reference data / gold image\n//! @param data       handle to the computed data\n//! @param len        number of elements in reference and data\n//! @param epsilon    epsilon to use for the comparison\n//! @param epsilon    threshold % of (# of bytes) for pass/fail\n//////////////////////////////////////////////////////////////////////////////\ntemplate<class T, class S>\ninline bool\ncompareDataAsFloatThreshold(const T *reference, const T *data, const unsigned int len,\n                            const S epsilon, const float threshold)\n{\n    assert(epsilon >= 0);\n\n    // If we set epsilon to be 0, let's set a minimum threshold\n    float max_error = MAX((float)epsilon, __MIN_EPSILON_ERROR);\n    int error_count = 0;\n    bool result = true;\n\n    for (unsigned int i = 0; i < len; ++i)\n    {\n        float diff = fabs((float)reference[i] - (float)data[i]);\n        bool comp = (diff < max_error);\n        result &= comp;\n\n        if (! comp)\n        {\n            error_count++;\n#if 0\n\n            if (error_count < 50)\n            {\n                printf(\"\\n    ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\\n\",\n                       max_error, i,\n                       *(unsigned int *)&reference[i],\n                       *(unsigned int *)&data[i],\n                       (unsigned int)diff);\n            }\n\n#endif\n        }\n    }\n\n    if (threshold == 0.0f)\n    {\n        if (error_count)\n        {\n            printf(\"total # of errors = %d\\n\", error_count);\n        }\n\n        return (error_count == 0) ? true : false;\n    }\n    else\n    {\n        if (error_count)\n        {\n            printf(\"%4.2f(%%) of bytes mismatched (count=%d)\\n\", (float)error_count*100/(float)len, error_count);\n        }\n\n        return ((len*threshold > error_count) ? true : false);\n    }\n}\n\ninline\nvoid sdkDumpBin(void *data, unsigned int bytes, const char *filename)\n{\n    printf(\"sdkDumpBin: <%s>\\n\", filename);\n    FILE *fp;\n    FOPEN(fp, filename, \"wb\");\n    fwrite(data, bytes, 1, fp);\n    fflush(fp);\n    fclose(fp);\n}\n\ninline\nbool sdkCompareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold, char *exec_path)\n{\n    unsigned int *src_buffer, *ref_buffer;\n    FILE *src_fp = NULL, *ref_fp = NULL;\n\n    unsigned long error_count = 0;\n    size_t fsize = 0;\n\n    if (FOPEN_FAIL(FOPEN(src_fp, src_file, \"rb\")))\n    {\n        printf(\"compareBin2Bin <unsigned int> unable to open src_file: %s\\n\", src_file);\n        error_count++;\n    }\n\n    char *ref_file_path = sdkFindFilePath(ref_file, exec_path);\n\n    if (ref_file_path == NULL)\n    {\n        printf(\"compareBin2Bin <unsigned int>  unable to find <%s> in <%s>\\n\", ref_file, exec_path);\n        printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n        printf(\"Aborting comparison!\\n\");\n        printf(\"  FAILED\\n\");\n        error_count++;\n\n        if (src_fp)\n        {\n            fclose(src_fp);\n        }\n\n        if (ref_fp)\n        {\n            fclose(ref_fp);\n        }\n    }\n    else\n    {\n        if (FOPEN_FAIL(FOPEN(ref_fp, ref_file_path, \"rb\")))\n        {\n            printf(\"compareBin2Bin <unsigned int>  unable to open ref_file: %s\\n\", ref_file_path);\n            error_count++;\n        }\n\n        if (src_fp && ref_fp)\n        {\n            src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n            ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n\n            fsize = fread(src_buffer, nelements, sizeof(unsigned int), src_fp);\n            fsize = fread(ref_buffer, nelements, sizeof(unsigned int), ref_fp);\n\n            printf(\"> compareBin2Bin <unsigned int> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n            printf(\"   src_file <%s>, size=%d bytes\\n\", src_file, (int)fsize);\n            printf(\"   ref_file <%s>, size=%d bytes\\n\", ref_file_path, (int)fsize);\n\n            if (!compareData<unsigned int, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n            {\n                error_count++;\n            }\n\n            fclose(src_fp);\n            fclose(ref_fp);\n\n            free(src_buffer);\n            free(ref_buffer);\n        }\n        else\n        {\n            if (src_fp)\n            {\n                fclose(src_fp);\n            }\n\n            if (ref_fp)\n            {\n                fclose(ref_fp);\n            }\n        }\n    }\n\n    if (error_count == 0)\n    {\n        printf(\"  OK\\n\");\n    }\n    else\n    {\n        printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n    }\n\n    return (error_count == 0);  // returns true if all pixels pass\n}\n\ninline\nbool sdkCompareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold, char *exec_path)\n{\n    float *src_buffer, *ref_buffer;\n    FILE *src_fp = NULL, *ref_fp = NULL;\n    size_t fsize = 0;\n\n    unsigned long error_count = 0;\n\n    if (FOPEN_FAIL(FOPEN(src_fp, src_file, \"rb\")))\n    {\n        printf(\"compareBin2Bin <float> unable to open src_file: %s\\n\", src_file);\n        error_count = 1;\n    }\n\n    char *ref_file_path = sdkFindFilePath(ref_file, exec_path);\n\n    if (ref_file_path == NULL)\n    {\n        printf(\"compareBin2Bin <float> unable to find <%s> in <%s>\\n\", ref_file, exec_path);\n        printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", exec_path);\n        printf(\"Aborting comparison!\\n\");\n        printf(\"  FAILED\\n\");\n        error_count++;\n\n        if (src_fp)\n        {\n            fclose(src_fp);\n        }\n\n        if (ref_fp)\n        {\n            fclose(ref_fp);\n        }\n    }\n    else\n    {\n        if (FOPEN_FAIL(FOPEN(ref_fp, ref_file_path, \"rb\")))\n        {\n            printf(\"compareBin2Bin <float> unable to open ref_file: %s\\n\", ref_file_path);\n            error_count = 1;\n        }\n\n        if (src_fp && ref_fp)\n        {\n            src_buffer = (float *)malloc(nelements*sizeof(float));\n            ref_buffer = (float *)malloc(nelements*sizeof(float));\n\n            fsize = fread(src_buffer, nelements, sizeof(float), src_fp);\n            fsize = fread(ref_buffer, nelements, sizeof(float), ref_fp);\n\n            printf(\"> compareBin2Bin <float> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n            printf(\"   src_file <%s>, size=%d bytes\\n\", src_file, (int)fsize);\n            printf(\"   ref_file <%s>, size=%d bytes\\n\", ref_file_path, (int)fsize);\n\n            if (!compareDataAsFloatThreshold<float, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n            {\n                error_count++;\n            }\n\n            fclose(src_fp);\n            fclose(ref_fp);\n\n            free(src_buffer);\n            free(ref_buffer);\n        }\n        else\n        {\n            if (src_fp)\n            {\n                fclose(src_fp);\n            }\n\n            if (ref_fp)\n            {\n                fclose(ref_fp);\n            }\n        }\n    }\n\n    if (error_count == 0)\n    {\n        printf(\"  OK\\n\");\n    }\n    else\n    {\n        printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n    }\n\n    return (error_count == 0);  // returns true if all pixels pass\n}\n\ninline bool\nsdkCompareL2fe(const float *reference, const float *data,\n               const unsigned int len, const float epsilon)\n{\n    assert(epsilon >= 0);\n\n    float error = 0;\n    float ref = 0;\n\n    for (unsigned int i = 0; i < len; ++i)\n    {\n\n        float diff = reference[i] - data[i];\n        error += diff * diff;\n        ref += reference[i] * reference[i];\n    }\n\n    float normRef = sqrtf(ref);\n\n    if (fabs(ref) < 1e-7)\n    {\n#ifdef _DEBUG\n        std::cerr << \"ERROR, reference l2-norm is 0\\n\";\n#endif\n        return false;\n    }\n\n    float normError = sqrtf(error);\n    error = normError / normRef;\n    bool result = error < epsilon;\n#ifdef _DEBUG\n\n    if (! result)\n    {\n        std::cerr << \"ERROR, l2-norm error \"\n                  << error << \" is greater than epsilon \" << epsilon << \"\\n\";\n    }\n\n#endif\n\n    return result;\n}\n\ninline bool\nsdkLoadPPMub(const char *file, unsigned char **data,\n             unsigned int *w,unsigned int *h)\n{\n    unsigned int channels;\n    return __loadPPM(file, data, w, h, &channels);\n}\n\ninline bool\nsdkLoadPPM4ub(const char *file, unsigned char **data,\n              unsigned int *w, unsigned int *h)\n{\n    unsigned char *idata = 0;\n    unsigned int channels;\n\n    if (__loadPPM(file, &idata, w, h, &channels))\n    {\n        // pad 4th component\n        int size = *w **h;\n        // keep the original pointer\n        unsigned char *idata_orig = idata;\n        *data = (unsigned char *) malloc(sizeof(unsigned char) * size * 4);\n        unsigned char *ptr = *data;\n\n        for (int i=0; i<size; i++)\n        {\n            *ptr++ = *idata++;\n            *ptr++ = *idata++;\n            *ptr++ = *idata++;\n            *ptr++ = 0;\n        }\n\n        free(idata_orig);\n        return true;\n    }\n    else\n    {\n        free(idata);\n        return false;\n    }\n}\n\n\ninline bool\nsdkComparePPM(const char *src_file, const char *ref_file,\n              const float epsilon, const float threshold, bool verboseErrors)\n{\n    unsigned char *src_data, *ref_data;\n    unsigned long error_count = 0;\n    unsigned int ref_width, ref_height;\n    unsigned int src_width, src_height;\n\n    if (src_file == NULL || ref_file == NULL)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"PPMvsPPM: src_file or ref_file is NULL.  Aborting comparison\\n\";\n        }\n\n        return false;\n    }\n\n    if (verboseErrors)\n    {\n        std::cerr << \"> Compare (a)rendered:  <\" << src_file << \">\\n\";\n        std::cerr << \">         (b)reference: <\" << ref_file << \">\\n\";\n    }\n\n\n    if (sdkLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != true)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"PPMvsPPM: unable to load ref image file: \"<< ref_file << \"\\n\";\n        }\n\n        return false;\n    }\n\n    if (sdkLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != true)\n    {\n        std::cerr << \"PPMvsPPM: unable to load src image file: \" << src_file << \"\\n\";\n        return false;\n    }\n\n    if (src_height != ref_height || src_width != ref_width)\n    {\n        if (verboseErrors) std::cerr << \"PPMvsPPM: source and ref size mismatch (\" << src_width <<\n                                         \",\" << src_height << \")vs(\" << ref_width << \",\" << ref_height << \")\\n\";\n    }\n\n    if (verboseErrors) std::cerr << \"PPMvsPPM: comparing images size (\" << src_width <<\n                                     \",\" << src_height << \") epsilon(\" << epsilon << \"), threshold(\" << threshold*100 << \"%)\\n\";\n\n    if (compareData(ref_data, src_data, src_width*src_height*4, epsilon, threshold) == false)\n    {\n        error_count=1;\n    }\n\n    if (error_count == 0)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"    OK\\n\\n\";\n        }\n    }\n    else\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"    FAILURE!  \"<<error_count<<\" errors...\\n\\n\";\n        }\n    }\n\n    return (error_count == 0)? true : false;  // returns true if all pixels pass\n}\n\ninline bool\nsdkComparePGM(const char *src_file, const char *ref_file,\n              const float epsilon, const float threshold, bool verboseErrors)\n{\n    unsigned char *src_data = 0, *ref_data = 0;\n    unsigned long error_count = 0;\n    unsigned int ref_width, ref_height;\n    unsigned int src_width, src_height;\n\n    if (src_file == NULL || ref_file == NULL)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"PGMvsPGM: src_file or ref_file is NULL.  Aborting comparison\\n\";\n        }\n\n        return false;\n    }\n\n    if (verboseErrors)\n    {\n        std::cerr << \"> Compare (a)rendered:  <\" << src_file << \">\\n\";\n        std::cerr << \">         (b)reference: <\" << ref_file << \">\\n\";\n    }\n\n\n    if (sdkLoadPPMub(ref_file, &ref_data, &ref_width, &ref_height) != true)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"PGMvsPGM: unable to load ref image file: \"<< ref_file << \"\\n\";\n        }\n\n        return false;\n    }\n\n    if (sdkLoadPPMub(src_file, &src_data, &src_width, &src_height) != true)\n    {\n        std::cerr << \"PGMvsPGM: unable to load src image file: \" << src_file << \"\\n\";\n        return false;\n    }\n\n    if (src_height != ref_height || src_width != ref_width)\n    {\n        if (verboseErrors) std::cerr << \"PGMvsPGM: source and ref size mismatch (\" << src_width <<\n                                         \",\" << src_height << \")vs(\" << ref_width << \",\" << ref_height << \")\\n\";\n    }\n\n    if (verboseErrors) std::cerr << \"PGMvsPGM: comparing images size (\" << src_width <<\n                                     \",\" << src_height << \") epsilon(\" << epsilon << \"), threshold(\" << threshold*100 << \"%)\\n\";\n\n    if (compareData(ref_data, src_data, src_width*src_height, epsilon, threshold) == false)\n    {\n        error_count=1;\n    }\n\n    if (error_count == 0)\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"    OK\\n\\n\";\n        }\n    }\n    else\n    {\n        if (verboseErrors)\n        {\n            std::cerr << \"    FAILURE!  \"<<error_count<<\" errors...\\n\\n\";\n        }\n    }\n\n    return (error_count == 0)? true : false;  // returns true if all pixels pass\n}\n\n#endif // HELPER_IMAGE_H\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_math.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n/*\n *  This file implements common mathematical operations on vector types\n *  (float3, float4 etc.) since these are not provided as standard by CUDA.\n *\n *  The syntax is modeled on the Cg standard library.\n *\n *  This is part of the Helper library includes\n *\n *    Thanks to Linh Hah for additions and fixes.\n */\n\n#ifndef HELPER_MATH_H\n#define HELPER_MATH_H\n\n#include \"cuda_runtime.h\"\n\ntypedef unsigned int uint;\ntypedef unsigned short ushort;\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n#ifndef __CUDACC__\n#include <math.h>\n\n////////////////////////////////////////////////////////////////////////////////\n// host implementations of CUDA functions\n////////////////////////////////////////////////////////////////////////////////\n\ninline float fminf(float a, float b)\n{\n    return a < b ? a : b;\n}\n\ninline float fmaxf(float a, float b)\n{\n    return a > b ? a : b;\n}\n\ninline int max(int a, int b)\n{\n    return a > b ? a : b;\n}\n\ninline int min(int a, int b)\n{\n    return a < b ? a : b;\n}\n\ninline float rsqrtf(float x)\n{\n    return 1.0f / sqrtf(x);\n}\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// constructors\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 make_float2(float s)\n{\n    return make_float2(s, s);\n}\ninline __host__ __device__ float2 make_float2(float3 a)\n{\n    return make_float2(a.x, a.y);\n}\ninline __host__ __device__ float2 make_float2(int2 a)\n{\n    return make_float2(float(a.x), float(a.y));\n}\ninline __host__ __device__ float2 make_float2(uint2 a)\n{\n    return make_float2(float(a.x), float(a.y));\n}\n\ninline __host__ __device__ int2 make_int2(int s)\n{\n    return make_int2(s, s);\n}\ninline __host__ __device__ int2 make_int2(int3 a)\n{\n    return make_int2(a.x, a.y);\n}\ninline __host__ __device__ int2 make_int2(uint2 a)\n{\n    return make_int2(int(a.x), int(a.y));\n}\ninline __host__ __device__ int2 make_int2(float2 a)\n{\n    return make_int2(int(a.x), int(a.y));\n}\n\ninline __host__ __device__ uint2 make_uint2(uint s)\n{\n    return make_uint2(s, s);\n}\ninline __host__ __device__ uint2 make_uint2(uint3 a)\n{\n    return make_uint2(a.x, a.y);\n}\ninline __host__ __device__ uint2 make_uint2(int2 a)\n{\n    return make_uint2(uint(a.x), uint(a.y));\n}\n\ninline __host__ __device__ float3 make_float3(float s)\n{\n    return make_float3(s, s, s);\n}\ninline __host__ __device__ float3 make_float3(float2 a)\n{\n    return make_float3(a.x, a.y, 0.0f);\n}\ninline __host__ __device__ float3 make_float3(float2 a, float s)\n{\n    return make_float3(a.x, a.y, s);\n}\ninline __host__ __device__ float3 make_float3(float4 a)\n{\n    return make_float3(a.x, a.y, a.z);\n}\ninline __host__ __device__ float3 make_float3(int3 a)\n{\n    return make_float3(float(a.x), float(a.y), float(a.z));\n}\ninline __host__ __device__ float3 make_float3(uint3 a)\n{\n    return make_float3(float(a.x), float(a.y), float(a.z));\n}\n\ninline __host__ __device__ int3 make_int3(int s)\n{\n    return make_int3(s, s, s);\n}\ninline __host__ __device__ int3 make_int3(int2 a)\n{\n    return make_int3(a.x, a.y, 0);\n}\ninline __host__ __device__ int3 make_int3(int2 a, int s)\n{\n    return make_int3(a.x, a.y, s);\n}\ninline __host__ __device__ int3 make_int3(uint3 a)\n{\n    return make_int3(int(a.x), int(a.y), int(a.z));\n}\ninline __host__ __device__ int3 make_int3(float3 a)\n{\n    return make_int3(int(a.x), int(a.y), int(a.z));\n}\n\ninline __host__ __device__ uint3 make_uint3(uint s)\n{\n    return make_uint3(s, s, s);\n}\ninline __host__ __device__ uint3 make_uint3(uint2 a)\n{\n    return make_uint3(a.x, a.y, 0);\n}\ninline __host__ __device__ uint3 make_uint3(uint2 a, uint s)\n{\n    return make_uint3(a.x, a.y, s);\n}\ninline __host__ __device__ uint3 make_uint3(uint4 a)\n{\n    return make_uint3(a.x, a.y, a.z);\n}\ninline __host__ __device__ uint3 make_uint3(int3 a)\n{\n    return make_uint3(uint(a.x), uint(a.y), uint(a.z));\n}\n\ninline __host__ __device__ float4 make_float4(float s)\n{\n    return make_float4(s, s, s, s);\n}\ninline __host__ __device__ float4 make_float4(float3 a)\n{\n    return make_float4(a.x, a.y, a.z, 0.0f);\n}\ninline __host__ __device__ float4 make_float4(float3 a, float w)\n{\n    return make_float4(a.x, a.y, a.z, w);\n}\ninline __host__ __device__ float4 make_float4(int4 a)\n{\n    return make_float4(float(a.x), float(a.y), float(a.z), float(a.w));\n}\ninline __host__ __device__ float4 make_float4(uint4 a)\n{\n    return make_float4(float(a.x), float(a.y), float(a.z), float(a.w));\n}\n\ninline __host__ __device__ int4 make_int4(int s)\n{\n    return make_int4(s, s, s, s);\n}\ninline __host__ __device__ int4 make_int4(int3 a)\n{\n    return make_int4(a.x, a.y, a.z, 0);\n}\ninline __host__ __device__ int4 make_int4(int3 a, int w)\n{\n    return make_int4(a.x, a.y, a.z, w);\n}\ninline __host__ __device__ int4 make_int4(uint4 a)\n{\n    return make_int4(int(a.x), int(a.y), int(a.z), int(a.w));\n}\ninline __host__ __device__ int4 make_int4(float4 a)\n{\n    return make_int4(int(a.x), int(a.y), int(a.z), int(a.w));\n}\n\n\ninline __host__ __device__ uint4 make_uint4(uint s)\n{\n    return make_uint4(s, s, s, s);\n}\ninline __host__ __device__ uint4 make_uint4(uint3 a)\n{\n    return make_uint4(a.x, a.y, a.z, 0);\n}\ninline __host__ __device__ uint4 make_uint4(uint3 a, uint w)\n{\n    return make_uint4(a.x, a.y, a.z, w);\n}\ninline __host__ __device__ uint4 make_uint4(int4 a)\n{\n    return make_uint4(uint(a.x), uint(a.y), uint(a.z), uint(a.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// negate\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 operator-(float2 &a)\n{\n    return make_float2(-a.x, -a.y);\n}\ninline __host__ __device__ int2 operator-(int2 &a)\n{\n    return make_int2(-a.x, -a.y);\n}\ninline __host__ __device__ float3 operator-(float3 &a)\n{\n    return make_float3(-a.x, -a.y, -a.z);\n}\ninline __host__ __device__ int3 operator-(int3 &a)\n{\n    return make_int3(-a.x, -a.y, -a.z);\n}\ninline __host__ __device__ float4 operator-(float4 &a)\n{\n    return make_float4(-a.x, -a.y, -a.z, -a.w);\n}\ninline __host__ __device__ int4 operator-(int4 &a)\n{\n    return make_int4(-a.x, -a.y, -a.z, -a.w);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// addition\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 operator+(float2 a, float2 b)\n{\n    return make_float2(a.x + b.x, a.y + b.y);\n}\ninline __host__ __device__ void operator+=(float2 &a, float2 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n}\ninline __host__ __device__ float2 operator+(float2 a, float b)\n{\n    return make_float2(a.x + b, a.y + b);\n}\ninline __host__ __device__ float2 operator+(float b, float2 a)\n{\n    return make_float2(a.x + b, a.y + b);\n}\ninline __host__ __device__ void operator+=(float2 &a, float b)\n{\n    a.x += b;\n    a.y += b;\n}\n\ninline __host__ __device__ int2 operator+(int2 a, int2 b)\n{\n    return make_int2(a.x + b.x, a.y + b.y);\n}\ninline __host__ __device__ void operator+=(int2 &a, int2 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n}\ninline __host__ __device__ int2 operator+(int2 a, int b)\n{\n    return make_int2(a.x + b, a.y + b);\n}\ninline __host__ __device__ int2 operator+(int b, int2 a)\n{\n    return make_int2(a.x + b, a.y + b);\n}\ninline __host__ __device__ void operator+=(int2 &a, int b)\n{\n    a.x += b;\n    a.y += b;\n}\n\ninline __host__ __device__ uint2 operator+(uint2 a, uint2 b)\n{\n    return make_uint2(a.x + b.x, a.y + b.y);\n}\ninline __host__ __device__ void operator+=(uint2 &a, uint2 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n}\ninline __host__ __device__ uint2 operator+(uint2 a, uint b)\n{\n    return make_uint2(a.x + b, a.y + b);\n}\ninline __host__ __device__ uint2 operator+(uint b, uint2 a)\n{\n    return make_uint2(a.x + b, a.y + b);\n}\ninline __host__ __device__ void operator+=(uint2 &a, uint b)\n{\n    a.x += b;\n    a.y += b;\n}\n\n\ninline __host__ __device__ float3 operator+(float3 a, float3 b)\n{\n    return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);\n}\ninline __host__ __device__ void operator+=(float3 &a, float3 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n}\ninline __host__ __device__ float3 operator+(float3 a, float b)\n{\n    return make_float3(a.x + b, a.y + b, a.z + b);\n}\ninline __host__ __device__ void operator+=(float3 &a, float b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n}\n\ninline __host__ __device__ int3 operator+(int3 a, int3 b)\n{\n    return make_int3(a.x + b.x, a.y + b.y, a.z + b.z);\n}\ninline __host__ __device__ void operator+=(int3 &a, int3 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n}\ninline __host__ __device__ int3 operator+(int3 a, int b)\n{\n    return make_int3(a.x + b, a.y + b, a.z + b);\n}\ninline __host__ __device__ void operator+=(int3 &a, int b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n}\n\ninline __host__ __device__ uint3 operator+(uint3 a, uint3 b)\n{\n    return make_uint3(a.x + b.x, a.y + b.y, a.z + b.z);\n}\ninline __host__ __device__ void operator+=(uint3 &a, uint3 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n}\ninline __host__ __device__ uint3 operator+(uint3 a, uint b)\n{\n    return make_uint3(a.x + b, a.y + b, a.z + b);\n}\ninline __host__ __device__ void operator+=(uint3 &a, uint b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n}\n\ninline __host__ __device__ int3 operator+(int b, int3 a)\n{\n    return make_int3(a.x + b, a.y + b, a.z + b);\n}\ninline __host__ __device__ uint3 operator+(uint b, uint3 a)\n{\n    return make_uint3(a.x + b, a.y + b, a.z + b);\n}\ninline __host__ __device__ float3 operator+(float b, float3 a)\n{\n    return make_float3(a.x + b, a.y + b, a.z + b);\n}\n\ninline __host__ __device__ float4 operator+(float4 a, float4 b)\n{\n    return make_float4(a.x + b.x, a.y + b.y, a.z + b.z,  a.w + b.w);\n}\ninline __host__ __device__ void operator+=(float4 &a, float4 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n    a.w += b.w;\n}\ninline __host__ __device__ float4 operator+(float4 a, float b)\n{\n    return make_float4(a.x + b, a.y + b, a.z + b, a.w + b);\n}\ninline __host__ __device__ float4 operator+(float b, float4 a)\n{\n    return make_float4(a.x + b, a.y + b, a.z + b, a.w + b);\n}\ninline __host__ __device__ void operator+=(float4 &a, float b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n    a.w += b;\n}\n\ninline __host__ __device__ int4 operator+(int4 a, int4 b)\n{\n    return make_int4(a.x + b.x, a.y + b.y, a.z + b.z,  a.w + b.w);\n}\ninline __host__ __device__ void operator+=(int4 &a, int4 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n    a.w += b.w;\n}\ninline __host__ __device__ int4 operator+(int4 a, int b)\n{\n    return make_int4(a.x + b, a.y + b, a.z + b,  a.w + b);\n}\ninline __host__ __device__ int4 operator+(int b, int4 a)\n{\n    return make_int4(a.x + b, a.y + b, a.z + b,  a.w + b);\n}\ninline __host__ __device__ void operator+=(int4 &a, int b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n    a.w += b;\n}\n\ninline __host__ __device__ uint4 operator+(uint4 a, uint4 b)\n{\n    return make_uint4(a.x + b.x, a.y + b.y, a.z + b.z,  a.w + b.w);\n}\ninline __host__ __device__ void operator+=(uint4 &a, uint4 b)\n{\n    a.x += b.x;\n    a.y += b.y;\n    a.z += b.z;\n    a.w += b.w;\n}\ninline __host__ __device__ uint4 operator+(uint4 a, uint b)\n{\n    return make_uint4(a.x + b, a.y + b, a.z + b,  a.w + b);\n}\ninline __host__ __device__ uint4 operator+(uint b, uint4 a)\n{\n    return make_uint4(a.x + b, a.y + b, a.z + b,  a.w + b);\n}\ninline __host__ __device__ void operator+=(uint4 &a, uint b)\n{\n    a.x += b;\n    a.y += b;\n    a.z += b;\n    a.w += b;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// subtract\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 operator-(float2 a, float2 b)\n{\n    return make_float2(a.x - b.x, a.y - b.y);\n}\ninline __host__ __device__ void operator-=(float2 &a, float2 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n}\ninline __host__ __device__ float2 operator-(float2 a, float b)\n{\n    return make_float2(a.x - b, a.y - b);\n}\ninline __host__ __device__ float2 operator-(float b, float2 a)\n{\n    return make_float2(b - a.x, b - a.y);\n}\ninline __host__ __device__ void operator-=(float2 &a, float b)\n{\n    a.x -= b;\n    a.y -= b;\n}\n\ninline __host__ __device__ int2 operator-(int2 a, int2 b)\n{\n    return make_int2(a.x - b.x, a.y - b.y);\n}\ninline __host__ __device__ void operator-=(int2 &a, int2 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n}\ninline __host__ __device__ int2 operator-(int2 a, int b)\n{\n    return make_int2(a.x - b, a.y - b);\n}\ninline __host__ __device__ int2 operator-(int b, int2 a)\n{\n    return make_int2(b - a.x, b - a.y);\n}\ninline __host__ __device__ void operator-=(int2 &a, int b)\n{\n    a.x -= b;\n    a.y -= b;\n}\n\ninline __host__ __device__ uint2 operator-(uint2 a, uint2 b)\n{\n    return make_uint2(a.x - b.x, a.y - b.y);\n}\ninline __host__ __device__ void operator-=(uint2 &a, uint2 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n}\ninline __host__ __device__ uint2 operator-(uint2 a, uint b)\n{\n    return make_uint2(a.x - b, a.y - b);\n}\ninline __host__ __device__ uint2 operator-(uint b, uint2 a)\n{\n    return make_uint2(b - a.x, b - a.y);\n}\ninline __host__ __device__ void operator-=(uint2 &a, uint b)\n{\n    a.x -= b;\n    a.y -= b;\n}\n\ninline __host__ __device__ float3 operator-(float3 a, float3 b)\n{\n    return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);\n}\ninline __host__ __device__ void operator-=(float3 &a, float3 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n}\ninline __host__ __device__ float3 operator-(float3 a, float b)\n{\n    return make_float3(a.x - b, a.y - b, a.z - b);\n}\ninline __host__ __device__ float3 operator-(float b, float3 a)\n{\n    return make_float3(b - a.x, b - a.y, b - a.z);\n}\ninline __host__ __device__ void operator-=(float3 &a, float b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n}\n\ninline __host__ __device__ int3 operator-(int3 a, int3 b)\n{\n    return make_int3(a.x - b.x, a.y - b.y, a.z - b.z);\n}\ninline __host__ __device__ void operator-=(int3 &a, int3 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n}\ninline __host__ __device__ int3 operator-(int3 a, int b)\n{\n    return make_int3(a.x - b, a.y - b, a.z - b);\n}\ninline __host__ __device__ int3 operator-(int b, int3 a)\n{\n    return make_int3(b - a.x, b - a.y, b - a.z);\n}\ninline __host__ __device__ void operator-=(int3 &a, int b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n}\n\ninline __host__ __device__ uint3 operator-(uint3 a, uint3 b)\n{\n    return make_uint3(a.x - b.x, a.y - b.y, a.z - b.z);\n}\ninline __host__ __device__ void operator-=(uint3 &a, uint3 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n}\ninline __host__ __device__ uint3 operator-(uint3 a, uint b)\n{\n    return make_uint3(a.x - b, a.y - b, a.z - b);\n}\ninline __host__ __device__ uint3 operator-(uint b, uint3 a)\n{\n    return make_uint3(b - a.x, b - a.y, b - a.z);\n}\ninline __host__ __device__ void operator-=(uint3 &a, uint b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n}\n\ninline __host__ __device__ float4 operator-(float4 a, float4 b)\n{\n    return make_float4(a.x - b.x, a.y - b.y, a.z - b.z,  a.w - b.w);\n}\ninline __host__ __device__ void operator-=(float4 &a, float4 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n    a.w -= b.w;\n}\ninline __host__ __device__ float4 operator-(float4 a, float b)\n{\n    return make_float4(a.x - b, a.y - b, a.z - b,  a.w - b);\n}\ninline __host__ __device__ void operator-=(float4 &a, float b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n    a.w -= b;\n}\n\ninline __host__ __device__ int4 operator-(int4 a, int4 b)\n{\n    return make_int4(a.x - b.x, a.y - b.y, a.z - b.z,  a.w - b.w);\n}\ninline __host__ __device__ void operator-=(int4 &a, int4 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n    a.w -= b.w;\n}\ninline __host__ __device__ int4 operator-(int4 a, int b)\n{\n    return make_int4(a.x - b, a.y - b, a.z - b,  a.w - b);\n}\ninline __host__ __device__ int4 operator-(int b, int4 a)\n{\n    return make_int4(b - a.x, b - a.y, b - a.z, b - a.w);\n}\ninline __host__ __device__ void operator-=(int4 &a, int b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n    a.w -= b;\n}\n\ninline __host__ __device__ uint4 operator-(uint4 a, uint4 b)\n{\n    return make_uint4(a.x - b.x, a.y - b.y, a.z - b.z,  a.w - b.w);\n}\ninline __host__ __device__ void operator-=(uint4 &a, uint4 b)\n{\n    a.x -= b.x;\n    a.y -= b.y;\n    a.z -= b.z;\n    a.w -= b.w;\n}\ninline __host__ __device__ uint4 operator-(uint4 a, uint b)\n{\n    return make_uint4(a.x - b, a.y - b, a.z - b,  a.w - b);\n}\ninline __host__ __device__ uint4 operator-(uint b, uint4 a)\n{\n    return make_uint4(b - a.x, b - a.y, b - a.z, b - a.w);\n}\ninline __host__ __device__ void operator-=(uint4 &a, uint b)\n{\n    a.x -= b;\n    a.y -= b;\n    a.z -= b;\n    a.w -= b;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// multiply\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 operator*(float2 a, float2 b)\n{\n    return make_float2(a.x * b.x, a.y * b.y);\n}\ninline __host__ __device__ void operator*=(float2 &a, float2 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n}\ninline __host__ __device__ float2 operator*(float2 a, float b)\n{\n    return make_float2(a.x * b, a.y * b);\n}\ninline __host__ __device__ float2 operator*(float b, float2 a)\n{\n    return make_float2(b * a.x, b * a.y);\n}\ninline __host__ __device__ void operator*=(float2 &a, float b)\n{\n    a.x *= b;\n    a.y *= b;\n}\n\ninline __host__ __device__ int2 operator*(int2 a, int2 b)\n{\n    return make_int2(a.x * b.x, a.y * b.y);\n}\ninline __host__ __device__ void operator*=(int2 &a, int2 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n}\ninline __host__ __device__ int2 operator*(int2 a, int b)\n{\n    return make_int2(a.x * b, a.y * b);\n}\ninline __host__ __device__ int2 operator*(int b, int2 a)\n{\n    return make_int2(b * a.x, b * a.y);\n}\ninline __host__ __device__ void operator*=(int2 &a, int b)\n{\n    a.x *= b;\n    a.y *= b;\n}\n\ninline __host__ __device__ uint2 operator*(uint2 a, uint2 b)\n{\n    return make_uint2(a.x * b.x, a.y * b.y);\n}\ninline __host__ __device__ void operator*=(uint2 &a, uint2 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n}\ninline __host__ __device__ uint2 operator*(uint2 a, uint b)\n{\n    return make_uint2(a.x * b, a.y * b);\n}\ninline __host__ __device__ uint2 operator*(uint b, uint2 a)\n{\n    return make_uint2(b * a.x, b * a.y);\n}\ninline __host__ __device__ void operator*=(uint2 &a, uint b)\n{\n    a.x *= b;\n    a.y *= b;\n}\n\ninline __host__ __device__ float3 operator*(float3 a, float3 b)\n{\n    return make_float3(a.x * b.x, a.y * b.y, a.z * b.z);\n}\ninline __host__ __device__ void operator*=(float3 &a, float3 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n}\ninline __host__ __device__ float3 operator*(float3 a, float b)\n{\n    return make_float3(a.x * b, a.y * b, a.z * b);\n}\ninline __host__ __device__ float3 operator*(float b, float3 a)\n{\n    return make_float3(b * a.x, b * a.y, b * a.z);\n}\ninline __host__ __device__ void operator*=(float3 &a, float b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n}\n\ninline __host__ __device__ int3 operator*(int3 a, int3 b)\n{\n    return make_int3(a.x * b.x, a.y * b.y, a.z * b.z);\n}\ninline __host__ __device__ void operator*=(int3 &a, int3 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n}\ninline __host__ __device__ int3 operator*(int3 a, int b)\n{\n    return make_int3(a.x * b, a.y * b, a.z * b);\n}\ninline __host__ __device__ int3 operator*(int b, int3 a)\n{\n    return make_int3(b * a.x, b * a.y, b * a.z);\n}\ninline __host__ __device__ void operator*=(int3 &a, int b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n}\n\ninline __host__ __device__ uint3 operator*(uint3 a, uint3 b)\n{\n    return make_uint3(a.x * b.x, a.y * b.y, a.z * b.z);\n}\ninline __host__ __device__ void operator*=(uint3 &a, uint3 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n}\ninline __host__ __device__ uint3 operator*(uint3 a, uint b)\n{\n    return make_uint3(a.x * b, a.y * b, a.z * b);\n}\ninline __host__ __device__ uint3 operator*(uint b, uint3 a)\n{\n    return make_uint3(b * a.x, b * a.y, b * a.z);\n}\ninline __host__ __device__ void operator*=(uint3 &a, uint b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n}\n\ninline __host__ __device__ float4 operator*(float4 a, float4 b)\n{\n    return make_float4(a.x * b.x, a.y * b.y, a.z * b.z,  a.w * b.w);\n}\ninline __host__ __device__ void operator*=(float4 &a, float4 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n    a.w *= b.w;\n}\ninline __host__ __device__ float4 operator*(float4 a, float b)\n{\n    return make_float4(a.x * b, a.y * b, a.z * b,  a.w * b);\n}\ninline __host__ __device__ float4 operator*(float b, float4 a)\n{\n    return make_float4(b * a.x, b * a.y, b * a.z, b * a.w);\n}\ninline __host__ __device__ void operator*=(float4 &a, float b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n    a.w *= b;\n}\n\ninline __host__ __device__ int4 operator*(int4 a, int4 b)\n{\n    return make_int4(a.x * b.x, a.y * b.y, a.z * b.z,  a.w * b.w);\n}\ninline __host__ __device__ void operator*=(int4 &a, int4 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n    a.w *= b.w;\n}\ninline __host__ __device__ int4 operator*(int4 a, int b)\n{\n    return make_int4(a.x * b, a.y * b, a.z * b,  a.w * b);\n}\ninline __host__ __device__ int4 operator*(int b, int4 a)\n{\n    return make_int4(b * a.x, b * a.y, b * a.z, b * a.w);\n}\ninline __host__ __device__ void operator*=(int4 &a, int b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n    a.w *= b;\n}\n\ninline __host__ __device__ uint4 operator*(uint4 a, uint4 b)\n{\n    return make_uint4(a.x * b.x, a.y * b.y, a.z * b.z,  a.w * b.w);\n}\ninline __host__ __device__ void operator*=(uint4 &a, uint4 b)\n{\n    a.x *= b.x;\n    a.y *= b.y;\n    a.z *= b.z;\n    a.w *= b.w;\n}\ninline __host__ __device__ uint4 operator*(uint4 a, uint b)\n{\n    return make_uint4(a.x * b, a.y * b, a.z * b,  a.w * b);\n}\ninline __host__ __device__ uint4 operator*(uint b, uint4 a)\n{\n    return make_uint4(b * a.x, b * a.y, b * a.z, b * a.w);\n}\ninline __host__ __device__ void operator*=(uint4 &a, uint b)\n{\n    a.x *= b;\n    a.y *= b;\n    a.z *= b;\n    a.w *= b;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// divide\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 operator/(float2 a, float2 b)\n{\n    return make_float2(a.x / b.x, a.y / b.y);\n}\ninline __host__ __device__ void operator/=(float2 &a, float2 b)\n{\n    a.x /= b.x;\n    a.y /= b.y;\n}\ninline __host__ __device__ float2 operator/(float2 a, float b)\n{\n    return make_float2(a.x / b, a.y / b);\n}\ninline __host__ __device__ void operator/=(float2 &a, float b)\n{\n    a.x /= b;\n    a.y /= b;\n}\ninline __host__ __device__ float2 operator/(float b, float2 a)\n{\n    return make_float2(b / a.x, b / a.y);\n}\n\ninline __host__ __device__ float3 operator/(float3 a, float3 b)\n{\n    return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);\n}\ninline __host__ __device__ void operator/=(float3 &a, float3 b)\n{\n    a.x /= b.x;\n    a.y /= b.y;\n    a.z /= b.z;\n}\ninline __host__ __device__ float3 operator/(float3 a, float b)\n{\n    return make_float3(a.x / b, a.y / b, a.z / b);\n}\ninline __host__ __device__ void operator/=(float3 &a, float b)\n{\n    a.x /= b;\n    a.y /= b;\n    a.z /= b;\n}\ninline __host__ __device__ float3 operator/(float b, float3 a)\n{\n    return make_float3(b / a.x, b / a.y, b / a.z);\n}\n\ninline __host__ __device__ float4 operator/(float4 a, float4 b)\n{\n    return make_float4(a.x / b.x, a.y / b.y, a.z / b.z,  a.w / b.w);\n}\ninline __host__ __device__ void operator/=(float4 &a, float4 b)\n{\n    a.x /= b.x;\n    a.y /= b.y;\n    a.z /= b.z;\n    a.w /= b.w;\n}\ninline __host__ __device__ float4 operator/(float4 a, float b)\n{\n    return make_float4(a.x / b, a.y / b, a.z / b,  a.w / b);\n}\ninline __host__ __device__ void operator/=(float4 &a, float b)\n{\n    a.x /= b;\n    a.y /= b;\n    a.z /= b;\n    a.w /= b;\n}\ninline __host__ __device__ float4 operator/(float b, float4 a)\n{\n    return make_float4(b / a.x, b / a.y, b / a.z, b / a.w);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// min\n////////////////////////////////////////////////////////////////////////////////\n\ninline  __host__ __device__ float2 fminf(float2 a, float2 b)\n{\n    return make_float2(fminf(a.x,b.x), fminf(a.y,b.y));\n}\ninline __host__ __device__ float3 fminf(float3 a, float3 b)\n{\n    return make_float3(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z));\n}\ninline  __host__ __device__ float4 fminf(float4 a, float4 b)\n{\n    return make_float4(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z), fminf(a.w,b.w));\n}\n\ninline __host__ __device__ int2 min(int2 a, int2 b)\n{\n    return make_int2(min(a.x,b.x), min(a.y,b.y));\n}\ninline __host__ __device__ int3 min(int3 a, int3 b)\n{\n    return make_int3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z));\n}\ninline __host__ __device__ int4 min(int4 a, int4 b)\n{\n    return make_int4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w));\n}\n\ninline __host__ __device__ uint2 min(uint2 a, uint2 b)\n{\n    return make_uint2(min(a.x,b.x), min(a.y,b.y));\n}\ninline __host__ __device__ uint3 min(uint3 a, uint3 b)\n{\n    return make_uint3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z));\n}\ninline __host__ __device__ uint4 min(uint4 a, uint4 b)\n{\n    return make_uint4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// max\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 fmaxf(float2 a, float2 b)\n{\n    return make_float2(fmaxf(a.x,b.x), fmaxf(a.y,b.y));\n}\ninline __host__ __device__ float3 fmaxf(float3 a, float3 b)\n{\n    return make_float3(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z));\n}\ninline __host__ __device__ float4 fmaxf(float4 a, float4 b)\n{\n    return make_float4(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z), fmaxf(a.w,b.w));\n}\n\ninline __host__ __device__ int2 max(int2 a, int2 b)\n{\n    return make_int2(max(a.x,b.x), max(a.y,b.y));\n}\ninline __host__ __device__ int3 max(int3 a, int3 b)\n{\n    return make_int3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z));\n}\ninline __host__ __device__ int4 max(int4 a, int4 b)\n{\n    return make_int4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w));\n}\n\ninline __host__ __device__ uint2 max(uint2 a, uint2 b)\n{\n    return make_uint2(max(a.x,b.x), max(a.y,b.y));\n}\ninline __host__ __device__ uint3 max(uint3 a, uint3 b)\n{\n    return make_uint3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z));\n}\ninline __host__ __device__ uint4 max(uint4 a, uint4 b)\n{\n    return make_uint4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// lerp\n// - linear interpolation between a and b, based on value t in [0, 1] range\n////////////////////////////////////////////////////////////////////////////////\n\ninline __device__ __host__ float lerp(float a, float b, float t)\n{\n    return a + t*(b-a);\n}\ninline __device__ __host__ float2 lerp(float2 a, float2 b, float t)\n{\n    return a + t*(b-a);\n}\ninline __device__ __host__ float3 lerp(float3 a, float3 b, float t)\n{\n    return a + t*(b-a);\n}\ninline __device__ __host__ float4 lerp(float4 a, float4 b, float t)\n{\n    return a + t*(b-a);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// clamp\n// - clamp the value v to be in the range [a, b]\n////////////////////////////////////////////////////////////////////////////////\n\ninline __device__ __host__ float clamp(float f, float a, float b)\n{\n    return fmaxf(a, fminf(f, b));\n}\ninline __device__ __host__ int clamp(int f, int a, int b)\n{\n    return max(a, min(f, b));\n}\ninline __device__ __host__ uint clamp(uint f, uint a, uint b)\n{\n    return max(a, min(f, b));\n}\n\ninline __device__ __host__ float2 clamp(float2 v, float a, float b)\n{\n    return make_float2(clamp(v.x, a, b), clamp(v.y, a, b));\n}\ninline __device__ __host__ float2 clamp(float2 v, float2 a, float2 b)\n{\n    return make_float2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y));\n}\ninline __device__ __host__ float3 clamp(float3 v, float a, float b)\n{\n    return make_float3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b));\n}\ninline __device__ __host__ float3 clamp(float3 v, float3 a, float3 b)\n{\n    return make_float3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z));\n}\ninline __device__ __host__ float4 clamp(float4 v, float a, float b)\n{\n    return make_float4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b));\n}\ninline __device__ __host__ float4 clamp(float4 v, float4 a, float4 b)\n{\n    return make_float4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w));\n}\n\ninline __device__ __host__ int2 clamp(int2 v, int a, int b)\n{\n    return make_int2(clamp(v.x, a, b), clamp(v.y, a, b));\n}\ninline __device__ __host__ int2 clamp(int2 v, int2 a, int2 b)\n{\n    return make_int2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y));\n}\ninline __device__ __host__ int3 clamp(int3 v, int a, int b)\n{\n    return make_int3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b));\n}\ninline __device__ __host__ int3 clamp(int3 v, int3 a, int3 b)\n{\n    return make_int3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z));\n}\ninline __device__ __host__ int4 clamp(int4 v, int a, int b)\n{\n    return make_int4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b));\n}\ninline __device__ __host__ int4 clamp(int4 v, int4 a, int4 b)\n{\n    return make_int4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w));\n}\n\ninline __device__ __host__ uint2 clamp(uint2 v, uint a, uint b)\n{\n    return make_uint2(clamp(v.x, a, b), clamp(v.y, a, b));\n}\ninline __device__ __host__ uint2 clamp(uint2 v, uint2 a, uint2 b)\n{\n    return make_uint2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y));\n}\ninline __device__ __host__ uint3 clamp(uint3 v, uint a, uint b)\n{\n    return make_uint3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b));\n}\ninline __device__ __host__ uint3 clamp(uint3 v, uint3 a, uint3 b)\n{\n    return make_uint3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z));\n}\ninline __device__ __host__ uint4 clamp(uint4 v, uint a, uint b)\n{\n    return make_uint4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b));\n}\ninline __device__ __host__ uint4 clamp(uint4 v, uint4 a, uint4 b)\n{\n    return make_uint4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// dot product\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float dot(float2 a, float2 b)\n{\n    return a.x * b.x + a.y * b.y;\n}\ninline __host__ __device__ float dot(float3 a, float3 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z;\n}\ninline __host__ __device__ float dot(float4 a, float4 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;\n}\n\ninline __host__ __device__ int dot(int2 a, int2 b)\n{\n    return a.x * b.x + a.y * b.y;\n}\ninline __host__ __device__ int dot(int3 a, int3 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z;\n}\ninline __host__ __device__ int dot(int4 a, int4 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;\n}\n\ninline __host__ __device__ uint dot(uint2 a, uint2 b)\n{\n    return a.x * b.x + a.y * b.y;\n}\ninline __host__ __device__ uint dot(uint3 a, uint3 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z;\n}\ninline __host__ __device__ uint dot(uint4 a, uint4 b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// length\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float length(float2 v)\n{\n    return sqrtf(dot(v, v));\n}\ninline __host__ __device__ float length(float3 v)\n{\n    return sqrtf(dot(v, v));\n}\ninline __host__ __device__ float length(float4 v)\n{\n    return sqrtf(dot(v, v));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// normalize\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 normalize(float2 v)\n{\n    float invLen = rsqrtf(dot(v, v));\n    return v * invLen;\n}\ninline __host__ __device__ float3 normalize(float3 v)\n{\n    float invLen = rsqrtf(dot(v, v));\n    return v * invLen;\n}\ninline __host__ __device__ float4 normalize(float4 v)\n{\n    float invLen = rsqrtf(dot(v, v));\n    return v * invLen;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// floor\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 floorf(float2 v)\n{\n    return make_float2(floorf(v.x), floorf(v.y));\n}\ninline __host__ __device__ float3 floorf(float3 v)\n{\n    return make_float3(floorf(v.x), floorf(v.y), floorf(v.z));\n}\ninline __host__ __device__ float4 floorf(float4 v)\n{\n    return make_float4(floorf(v.x), floorf(v.y), floorf(v.z), floorf(v.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// frac - returns the fractional portion of a scalar or each vector component\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float fracf(float v)\n{\n    return v - floorf(v);\n}\ninline __host__ __device__ float2 fracf(float2 v)\n{\n    return make_float2(fracf(v.x), fracf(v.y));\n}\ninline __host__ __device__ float3 fracf(float3 v)\n{\n    return make_float3(fracf(v.x), fracf(v.y), fracf(v.z));\n}\ninline __host__ __device__ float4 fracf(float4 v)\n{\n    return make_float4(fracf(v.x), fracf(v.y), fracf(v.z), fracf(v.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// fmod\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 fmodf(float2 a, float2 b)\n{\n    return make_float2(fmodf(a.x, b.x), fmodf(a.y, b.y));\n}\ninline __host__ __device__ float3 fmodf(float3 a, float3 b)\n{\n    return make_float3(fmodf(a.x, b.x), fmodf(a.y, b.y), fmodf(a.z, b.z));\n}\ninline __host__ __device__ float4 fmodf(float4 a, float4 b)\n{\n    return make_float4(fmodf(a.x, b.x), fmodf(a.y, b.y), fmodf(a.z, b.z), fmodf(a.w, b.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// absolute value\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float2 fabs(float2 v)\n{\n    return make_float2(fabs(v.x), fabs(v.y));\n}\ninline __host__ __device__ float3 fabs(float3 v)\n{\n    return make_float3(fabs(v.x), fabs(v.y), fabs(v.z));\n}\ninline __host__ __device__ float4 fabs(float4 v)\n{\n    return make_float4(fabs(v.x), fabs(v.y), fabs(v.z), fabs(v.w));\n}\n\ninline __host__ __device__ int2 abs(int2 v)\n{\n    return make_int2(abs(v.x), abs(v.y));\n}\ninline __host__ __device__ int3 abs(int3 v)\n{\n    return make_int3(abs(v.x), abs(v.y), abs(v.z));\n}\ninline __host__ __device__ int4 abs(int4 v)\n{\n    return make_int4(abs(v.x), abs(v.y), abs(v.z), abs(v.w));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// reflect\n// - returns reflection of incident ray I around surface normal N\n// - N should be normalized, reflected vector's length is equal to length of I\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float3 reflect(float3 i, float3 n)\n{\n    return i - 2.0f * n * dot(n,i);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// cross product\n////////////////////////////////////////////////////////////////////////////////\n\ninline __host__ __device__ float3 cross(float3 a, float3 b)\n{\n    return make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// smoothstep\n// - returns 0 if x < a\n// - returns 1 if x > b\n// - otherwise returns smooth interpolation between 0 and 1 based on x\n////////////////////////////////////////////////////////////////////////////////\n\ninline __device__ __host__ float smoothstep(float a, float b, float x)\n{\n    float y = clamp((x - a) / (b - a), 0.0f, 1.0f);\n    return (y*y*(3.0f - (2.0f*y)));\n}\ninline __device__ __host__ float2 smoothstep(float2 a, float2 b, float2 x)\n{\n    float2 y = clamp((x - a) / (b - a), 0.0f, 1.0f);\n    return (y*y*(make_float2(3.0f) - (make_float2(2.0f)*y)));\n}\ninline __device__ __host__ float3 smoothstep(float3 a, float3 b, float3 x)\n{\n    float3 y = clamp((x - a) / (b - a), 0.0f, 1.0f);\n    return (y*y*(make_float3(3.0f) - (make_float3(2.0f)*y)));\n}\ninline __device__ __host__ float4 smoothstep(float4 a, float4 b, float4 x)\n{\n    float4 y = clamp((x - a) / (b - a), 0.0f, 1.0f);\n    return (y*y*(make_float4(3.0f) - (make_float4(2.0f)*y)));\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_string.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// These are helper functions for the SDK samples (string parsing, timers, etc)\n#ifndef STRING_HELPER_H\n#define STRING_HELPER_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <fstream>\n#include <string>\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#ifndef _CRT_SECURE_NO_DEPRECATE\n#define _CRT_SECURE_NO_DEPRECATE\n#endif\n#ifndef STRCASECMP\n#define STRCASECMP  _stricmp\n#endif\n#ifndef STRNCASECMP\n#define STRNCASECMP _strnicmp\n#endif\n#ifndef STRCPY\n#define STRCPY(sFilePath, nLength, sPath) strcpy_s(sFilePath, nLength, sPath)\n#endif\n\n#ifndef FOPEN\n#define FOPEN(fHandle,filename,mode) fopen_s(&fHandle, filename, mode)\n#endif\n#ifndef FOPEN_FAIL\n#define FOPEN_FAIL(result) (result != 0)\n#endif\n#ifndef SSCANF\n#define SSCANF sscanf_s\n#endif\n#ifndef SPRINTF\n#define SPRINTF sprintf_s\n#endif\n#else // Linux Includes\n#include <string.h>\n#include <strings.h>\n\n#ifndef STRCASECMP\n#define STRCASECMP  strcasecmp\n#endif\n#ifndef STRNCASECMP\n#define STRNCASECMP strncasecmp\n#endif\n#ifndef STRCPY\n#define STRCPY(sFilePath, nLength, sPath) strcpy(sFilePath, sPath)\n#endif\n\n#ifndef FOPEN\n#define FOPEN(fHandle,filename,mode) (fHandle = fopen(filename, mode))\n#endif\n#ifndef FOPEN_FAIL\n#define FOPEN_FAIL(result) (result == NULL)\n#endif\n#ifndef SSCANF\n#define SSCANF sscanf\n#endif\n#ifndef SPRINTF\n#define SPRINTF sprintf\n#endif\n#endif\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n// CUDA Utility Helper Functions\ninline int stringRemoveDelimiter(char delimiter, const char *string)\n{\n    int string_start = 0;\n\n    while (string[string_start] == delimiter)\n    {\n        string_start++;\n    }\n\n    if (string_start >= (int)strlen(string)-1)\n    {\n        return 0;\n    }\n\n    return string_start;\n}\n\ninline int getFileExtension(char *filename, char **extension)\n{\n    int string_length = (int)strlen(filename);\n\n    while (filename[string_length--] != '.')\n    {\n        if (string_length == 0)\n            break;\n    }\n\n    if (string_length > 0) string_length += 2;\n\n    if (string_length == 0)\n        *extension = NULL;\n    else\n        *extension = &filename[string_length];\n\n    return string_length;\n}\n\n\ninline bool checkCmdLineFlag(const int argc, const char **argv, const char *string_ref)\n{\n    bool bFound = false;\n\n    if (argc >= 1)\n    {\n        for (int i=1; i < argc; i++)\n        {\n            int string_start = stringRemoveDelimiter('-', argv[i]);\n            const char *string_argv = &argv[i][string_start];\n\n            const char *equal_pos = strchr(string_argv, '=');\n            int argv_length = (int)(equal_pos == 0 ? strlen(string_argv) : equal_pos - string_argv);\n\n            int length = (int)strlen(string_ref);\n\n            if (length == argv_length && !STRNCASECMP(string_argv, string_ref, length))\n            {\n                bFound = true;\n                continue;\n            }\n        }\n    }\n\n    return bFound;\n}\n\n// This function wraps the CUDA Driver API into a template function\ntemplate <class T>\ninline bool getCmdLineArgumentValue(const int argc, const char **argv, const char *string_ref, T *value)\n{\n    bool bFound = false;\n\n    if (argc >= 1)\n    {\n        for (int i=1; i < argc; i++)\n        {\n            int string_start = stringRemoveDelimiter('-', argv[i]);\n            const char *string_argv = &argv[i][string_start];\n            int length = (int)strlen(string_ref);\n\n            if (!STRNCASECMP(string_argv, string_ref, length))\n            {\n                if (length+1 <= (int)strlen(string_argv))\n                {\n                    int auto_inc = (string_argv[length] == '=') ? 1 : 0;\n                    *value = (T)atoi(&string_argv[length + auto_inc]);\n                }\n\n                bFound = true;\n                i=argc;\n            }\n        }\n    }\n\n    return bFound;\n}\n\ninline int getCmdLineArgumentInt(const int argc, const char **argv, const char *string_ref)\n{\n    bool bFound = false;\n    int value = -1;\n\n    if (argc >= 1)\n    {\n        for (int i=1; i < argc; i++)\n        {\n            int string_start = stringRemoveDelimiter('-', argv[i]);\n            const char *string_argv = &argv[i][string_start];\n            int length = (int)strlen(string_ref);\n\n            if (!STRNCASECMP(string_argv, string_ref, length))\n            {\n                if (length+1 <= (int)strlen(string_argv))\n                {\n                    int auto_inc = (string_argv[length] == '=') ? 1 : 0;\n                    value = atoi(&string_argv[length + auto_inc]);\n                }\n                else\n                {\n                    value = 0;\n                }\n\n                bFound = true;\n                continue;\n            }\n        }\n    }\n\n    if (bFound)\n    {\n        return value;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\ninline float getCmdLineArgumentFloat(const int argc, const char **argv, const char *string_ref)\n{\n    bool bFound = false;\n    float value = -1;\n\n    if (argc >= 1)\n    {\n        for (int i=1; i < argc; i++)\n        {\n            int string_start = stringRemoveDelimiter('-', argv[i]);\n            const char *string_argv = &argv[i][string_start];\n            int length = (int)strlen(string_ref);\n\n            if (!STRNCASECMP(string_argv, string_ref, length))\n            {\n                if (length+1 <= (int)strlen(string_argv))\n                {\n                    int auto_inc = (string_argv[length] == '=') ? 1 : 0;\n                    value = (float)atof(&string_argv[length + auto_inc]);\n                }\n                else\n                {\n                    value = 0.f;\n                }\n\n                bFound = true;\n                continue;\n            }\n        }\n    }\n\n    if (bFound)\n    {\n        return value;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\ninline bool getCmdLineArgumentString(const int argc, const char **argv,\n                                     const char *string_ref, char **string_retval)\n{\n    bool bFound = false;\n\n    if (argc >= 1)\n    {\n        for (int i=1; i < argc; i++)\n        {\n            int string_start = stringRemoveDelimiter('-', argv[i]);\n            char *string_argv = (char *)&argv[i][string_start];\n            int length = (int)strlen(string_ref);\n\n            if (!STRNCASECMP(string_argv, string_ref, length))\n            {\n                *string_retval = &string_argv[length+1];\n                bFound = true;\n                continue;\n            }\n        }\n    }\n\n    if (!bFound)\n    {\n        *string_retval = NULL;\n    }\n\n    return bFound;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//! Find the path for a file assuming that\n//! files are found in the searchPath.\n//!\n//! @return the path if succeeded, otherwise 0\n//! @param filename         name of the file\n//! @param executable_path  optional absolute path of the executable\n//////////////////////////////////////////////////////////////////////////////\ninline char *sdkFindFilePath(const char *filename, const char *executable_path)\n{\n    // <executable_name> defines a variable that is replaced with the name of the executable\n\n    // Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files)\n    // The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc\n    const char *searchPath[] =\n    {\n        \"./\",                                       // same dir\n        \"./<executable_name>_data_files/\",\n        \"./common/\",                                // \"/common/\" subdir\n        \"./common/data/\",                           // \"/common/data/\" subdir\n        \"./data/\",                                  // \"/data/\" subdir\n        \"./src/\",                                   // \"/src/\" subdir\n        \"./src/<executable_name>/data/\",            // \"/src/<executable_name>/data/\" subdir\n        \"./inc/\",                                   // \"/inc/\" subdir\n        \"./0_Simple/\",                              // \"/0_Simple/\" subdir\n        \"./1_Utilities/\",                           // \"/1_Utilities/\" subdir\n        \"./2_Graphics/\",                            // \"/2_Graphics/\" subdir\n        \"./3_Imaging/\",                             // \"/3_Imaging/\" subdir\n        \"./4_Finance/\",                             // \"/4_Finance/\" subdir\n        \"./5_Simulations/\",                         // \"/5_Simulations/\" subdir\n        \"./6_Advanced/\",                            // \"/6_Advanced/\" subdir\n        \"./7_CUDALibraries/\",                       // \"/7_CUDALibraries/\" subdir\n        \"./8_Android/\",                             // \"/8_Android/\" subdir\n        \"./samples/\",                               // \"/samples/\" subdir\n\n        \"./0_Simple/<executable_name>/data/\",        // \"/0_Simple/<executable_name>/data/\" subdir\n        \"./1_Utilities/<executable_name>/data/\",     // \"/1_Utilities/<executable_name>/data/\" subdir\n        \"./2_Graphics/<executable_name>/data/\",      // \"/2_Graphics/<executable_name>/data/\" subdir\n        \"./3_Imaging/<executable_name>/data/\",       // \"/3_Imaging/<executable_name>/data/\" subdir\n        \"./4_Finance/<executable_name>/data/\",       // \"/4_Finance/<executable_name>/data/\" subdir\n        \"./5_Simulations/<executable_name>/data/\",   // \"/5_Simulations/<executable_name>/data/\" subdir\n        \"./6_Advanced/<executable_name>/data/\",      // \"/6_Advanced/<executable_name>/data/\" subdir\n        \"./7_CUDALibraries/<executable_name>/\",      // \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"./7_CUDALibraries/<executable_name>/data/\", // \"/7_CUDALibraries/<executable_name>/data/\" subdir\n\n        \"../\",                                      // up 1 in tree\n        \"../common/\",                               // up 1 in tree, \"/common/\" subdir\n        \"../common/data/\",                          // up 1 in tree, \"/common/data/\" subdir\n        \"../data/\",                                 // up 1 in tree, \"/data/\" subdir\n        \"../src/\",                                  // up 1 in tree, \"/src/\" subdir\n        \"../inc/\",                                  // up 1 in tree, \"/inc/\" subdir\n\n        \"../0_Simple/<executable_name>/data/\",       // up 1 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../1_Utilities/<executable_name>/data/\",    // up 1 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../2_Graphics/<executable_name>/data/\",     // up 1 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../3_Imaging/<executable_name>/data/\",      // up 1 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../4_Finance/<executable_name>/data/\",      // up 1 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../5_Simulations/<executable_name>/data/\",  // up 1 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../6_Advanced/<executable_name>/data/\",     // up 1 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../7_CUDALibraries/<executable_name>/data/\",// up 1 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../8_Android/<executable_name>/data/\",      // up 1 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../samples/<executable_name>/data/\",        // up 1 in tree, \"/samples/<executable_name>/\" subdir\n        \"../../\",                                        // up 2 in tree\n        \"../../common/\",                                 // up 2 in tree, \"/common/\" subdir\n        \"../../common/data/\",                            // up 2 in tree, \"/common/data/\" subdir\n        \"../../data/\",                                   // up 2 in tree, \"/data/\" subdir\n        \"../../src/\",                                    // up 2 in tree, \"/src/\" subdir\n        \"../../inc/\",                                    // up 2 in tree, \"/inc/\" subdir\n        \"../../sandbox/<executable_name>/data/\",         // up 2 in tree, \"/sandbox/<executable_name>/\" subdir\n        \"../../0_Simple/<executable_name>/data/\",        // up 2 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../1_Utilities/<executable_name>/data/\",     // up 2 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../2_Graphics/<executable_name>/data/\",      // up 2 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../3_Imaging/<executable_name>/data/\",       // up 2 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../4_Finance/<executable_name>/data/\",       // up 2 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../5_Simulations/<executable_name>/data/\",   // up 2 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../6_Advanced/<executable_name>/data/\",      // up 2 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../7_CUDALibraries/<executable_name>/data/\", // up 2 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../8_Android/<executable_name>/data/\",       // up 2 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../samples/<executable_name>/data/\",         // up 2 in tree, \"/samples/<executable_name>/\" subdir\n        \"../../../\",                                        // up 3 in tree\n        \"../../../src/<executable_name>/\",                  // up 3 in tree, \"/src/<executable_name>/\" subdir\n        \"../../../src/<executable_name>/data/\",             // up 3 in tree, \"/src/<executable_name>/data/\" subdir\n        \"../../../src/<executable_name>/src/\",              // up 3 in tree, \"/src/<executable_name>/src/\" subdir\n        \"../../../src/<executable_name>/inc/\",              // up 3 in tree, \"/src/<executable_name>/inc/\" subdir\n        \"../../../sandbox/<executable_name>/\",              // up 3 in tree, \"/sandbox/<executable_name>/\" subdir\n        \"../../../sandbox/<executable_name>/data/\",         // up 3 in tree, \"/sandbox/<executable_name>/data/\" subdir\n        \"../../../sandbox/<executable_name>/src/\",          // up 3 in tree, \"/sandbox/<executable_name>/src/\" subdir\n        \"../../../sandbox/<executable_name>/inc/\",          // up 3 in tree, \"/sandbox/<executable_name>/inc/\" subdir\n        \"../../../0_Simple/<executable_name>/data/\",        // up 3 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../../1_Utilities/<executable_name>/data/\",     // up 3 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../../2_Graphics/<executable_name>/data/\",      // up 3 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../../3_Imaging/<executable_name>/data/\",       // up 3 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../../4_Finance/<executable_name>/data/\",       // up 3 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../../5_Simulations/<executable_name>/data/\",   // up 3 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../../6_Advanced/<executable_name>/data/\",      // up 3 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../../7_CUDALibraries/<executable_name>/data/\", // up 3 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../../8_Android/<executable_name>/data/\",       // up 3 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../../0_Simple/<executable_name>/\",        // up 3 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../../1_Utilities/<executable_name>/\",     // up 3 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../../2_Graphics/<executable_name>/\",      // up 3 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../../3_Imaging/<executable_name>/\",       // up 3 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../../4_Finance/<executable_name>/\",       // up 3 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../../5_Simulations/<executable_name>/\",   // up 3 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../../6_Advanced/<executable_name>/\",      // up 3 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../../7_CUDALibraries/<executable_name>/\", // up 3 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../../8_Android/<executable_name>/\",       // up 3 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../../samples/<executable_name>/data/\",         // up 3 in tree, \"/samples/<executable_name>/\" subdir\n        \"../../../common/\",                                 // up 3 in tree, \"../../../common/\" subdir\n        \"../../../common/data/\",                            // up 3 in tree, \"../../../common/data/\" subdir\n        \"../../../data/\",                                   // up 3 in tree, \"../../../data/\" subdir\n        \"../../../../\",                                // up 4 in tree\n        \"../../../../src/<executable_name>/\",          // up 4 in tree, \"/src/<executable_name>/\" subdir\n        \"../../../../src/<executable_name>/data/\",     // up 4 in tree, \"/src/<executable_name>/data/\" subdir\n        \"../../../../src/<executable_name>/src/\",      // up 4 in tree, \"/src/<executable_name>/src/\" subdir\n        \"../../../../src/<executable_name>/inc/\",      // up 4 in tree, \"/src/<executable_name>/inc/\" subdir\n        \"../../../../sandbox/<executable_name>/\",      // up 4 in tree, \"/sandbox/<executable_name>/\" subdir\n        \"../../../../sandbox/<executable_name>/data/\", // up 4 in tree, \"/sandbox/<executable_name>/data/\" subdir\n        \"../../../../sandbox/<executable_name>/src/\",  // up 4 in tree, \"/sandbox/<executable_name>/src/\" subdir\n        \"../../../../sandbox/<executable_name>/inc/\",   // up 4 in tree, \"/sandbox/<executable_name>/inc/\" subdir\n        \"../../../../0_Simple/<executable_name>/data/\",     // up 4 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../../../1_Utilities/<executable_name>/data/\",  // up 4 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../../../2_Graphics/<executable_name>/data/\",   // up 4 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../../../3_Imaging/<executable_name>/data/\",    // up 4 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../../../4_Finance/<executable_name>/data/\",    // up 4 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../../../5_Simulations/<executable_name>/data/\",// up 4 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../../../6_Advanced/<executable_name>/data/\",   // up 4 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../../../7_CUDALibraries/<executable_name>/data/\", // up 4 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../../../8_Android/<executable_name>/data/\",    // up 4 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../../../0_Simple/<executable_name>/\",     // up 4 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../../../1_Utilities/<executable_name>/\",  // up 4 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../../../2_Graphics/<executable_name>/\",   // up 4 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../../../3_Imaging/<executable_name>/\",    // up 4 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../../../4_Finance/<executable_name>/\",    // up 4 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../../../5_Simulations/<executable_name>/\",// up 4 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../../../6_Advanced/<executable_name>/\",   // up 4 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../../../7_CUDALibraries/<executable_name>/\", // up 4 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../../../8_Android/<executable_name>/\",    // up 4 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../../../samples/<executable_name>/data/\",      // up 4 in tree, \"/samples/<executable_name>/\" subdir\n        \"../../../../common/\",                              // up 4 in tree, \"../../../common/\" subdir\n        \"../../../../common/data/\",                         // up 4 in tree, \"../../../common/data/\" subdir\n        \"../../../../data/\",                                // up 4 in tree, \"../../../data/\" subdir\n        \"../../../../../\",                                // up 5 in tree\n        \"../../../../../src/<executable_name>/\",          // up 5 in tree, \"/src/<executable_name>/\" subdir\n        \"../../../../../src/<executable_name>/data/\",     // up 5 in tree, \"/src/<executable_name>/data/\" subdir\n        \"../../../../../src/<executable_name>/src/\",      // up 5 in tree, \"/src/<executable_name>/src/\" subdir\n        \"../../../../../src/<executable_name>/inc/\",      // up 5 in tree, \"/src/<executable_name>/inc/\" subdir\n        \"../../../../../sandbox/<executable_name>/\",      // up 5 in tree, \"/sandbox/<executable_name>/\" subdir\n        \"../../../../../sandbox/<executable_name>/data/\", // up 5 in tree, \"/sandbox/<executable_name>/data/\" subdir\n        \"../../../../../sandbox/<executable_name>/src/\",  // up 5 in tree, \"/sandbox/<executable_name>/src/\" subdir\n        \"../../../../../sandbox/<executable_name>/inc/\",   // up 5 in tree, \"/sandbox/<executable_name>/inc/\" subdir\n        \"../../../../../0_Simple/<executable_name>/data/\",     // up 5 in tree, \"/0_Simple/<executable_name>/\" subdir\n        \"../../../../../1_Utilities/<executable_name>/data/\",  // up 5 in tree, \"/1_Utilities/<executable_name>/\" subdir\n        \"../../../../../2_Graphics/<executable_name>/data/\",   // up 5 in tree, \"/2_Graphics/<executable_name>/\" subdir\n        \"../../../../../3_Imaging/<executable_name>/data/\",    // up 5 in tree, \"/3_Imaging/<executable_name>/\" subdir\n        \"../../../../../4_Finance/<executable_name>/data/\",    // up 5 in tree, \"/4_Finance/<executable_name>/\" subdir\n        \"../../../../../5_Simulations/<executable_name>/data/\",// up 5 in tree, \"/5_Simulations/<executable_name>/\" subdir\n        \"../../../../../6_Advanced/<executable_name>/data/\",   // up 5 in tree, \"/6_Advanced/<executable_name>/\" subdir\n        \"../../../../../7_CUDALibraries/<executable_name>/data/\", // up 5 in tree, \"/7_CUDALibraries/<executable_name>/\" subdir\n        \"../../../../../8_Android/<executable_name>/data/\",    // up 5 in tree, \"/8_Android/<executable_name>/\" subdir\n        \"../../../../../samples/<executable_name>/data/\",      // up 5 in tree, \"/samples/<executable_name>/\" subdir\n        \"../../../../../common/\",                         // up 5 in tree, \"../../../common/\" subdir\n        \"../../../../../common/data/\",                    // up 5 in tree, \"../../../common/data/\" subdir\n    };\n\n    // Extract the executable name\n    std::string executable_name;\n\n    if (executable_path != 0)\n    {\n        executable_name = std::string(executable_path);\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n        // Windows path delimiter\n        size_t delimiter_pos = executable_name.find_last_of('\\\\');\n        executable_name.erase(0, delimiter_pos + 1);\n\n        if (executable_name.rfind(\".exe\") != std::string::npos)\n        {\n            // we strip .exe, only if the .exe is found\n            executable_name.resize(executable_name.size() - 4);\n        }\n\n#else\n        // Linux & OSX path delimiter\n        size_t delimiter_pos = executable_name.find_last_of('/');\n        executable_name.erase(0,delimiter_pos+1);\n#endif\n    }\n\n    // Loop over all search paths and return the first hit\n    for (unsigned int i = 0; i < sizeof(searchPath)/sizeof(char *); ++i)\n    {\n        std::string path(searchPath[i]);\n        size_t executable_name_pos = path.find(\"<executable_name>\");\n\n        // If there is executable_name variable in the searchPath\n        // replace it with the value\n        if (executable_name_pos != std::string::npos)\n        {\n            if (executable_path != 0)\n            {\n                path.replace(executable_name_pos, strlen(\"<executable_name>\"), executable_name);\n            }\n            else\n            {\n                // Skip this path entry if no executable argument is given\n                continue;\n            }\n        }\n\n#ifdef _DEBUG\n        printf(\"sdkFindFilePath <%s> in %s\\n\", filename, path.c_str());\n#endif\n\n        // Test if the file exists\n        path.append(filename);\n        FILE *fp;\n        FOPEN(fp, path.c_str(), \"rb\");\n\n        if (fp != NULL)\n        {\n            fclose(fp);\n            // File found\n            // returning an allocated array here for backwards compatibility reasons\n            char *file_path = (char *) malloc(path.length() + 1);\n            STRCPY(file_path, path.length() + 1, path.c_str());\n            return file_path;\n        }\n\n        if (fp)\n        {\n            fclose(fp);\n        }\n    }\n\n    // File not found\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/helper_timer.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n// Helper Timing Functions\n#ifndef HELPER_TIMER_H\n#define HELPER_TIMER_H\n\n#ifndef EXIT_WAIVED\n#define EXIT_WAIVED 2\n#endif\n\n// includes, system\n#include <vector>\n\n// includes, project\n#include <exception.h>\n\n// Definition of the StopWatch Interface, this is used if we don't want to use the CUT functions\n// But rather in a self contained class interface\nclass StopWatchInterface\n{\n    public:\n        StopWatchInterface() {};\n        virtual ~StopWatchInterface() {};\n\n    public:\n        //! Start time measurement\n        virtual void start() = 0;\n\n        //! Stop time measurement\n        virtual void stop() = 0;\n\n        //! Reset time counters to zero\n        virtual void reset() = 0;\n\n        //! Time in msec. after start. If the stop watch is still running (i.e. there\n        //! was no call to stop()) then the elapsed time is returned, otherwise the\n        //! time between the last start() and stop call is returned\n        virtual float getTime() = 0;\n\n        //! Mean time to date based on the number of times the stopwatch has been\n        //! _stopped_ (ie finished sessions) and the current total time\n        virtual float getAverageTime() = 0;\n};\n\n\n//////////////////////////////////////////////////////////////////\n// Begin Stopwatch timer class definitions for all OS platforms //\n//////////////////////////////////////////////////////////////////\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n// includes, system\n#define WINDOWS_LEAN_AND_MEAN\n#include <windows.h>\n#undef min\n#undef max\n\n//! Windows specific implementation of StopWatch\nclass StopWatchWin : public StopWatchInterface\n{\n    public:\n        //! Constructor, default\n        StopWatchWin() :\n            start_time(),     end_time(),\n            diff_time(0.0f),  total_time(0.0f),\n            running(false), clock_sessions(0), freq(0), freq_set(false)\n        {\n            if (! freq_set)\n            {\n                // helper variable\n                LARGE_INTEGER temp;\n\n                // get the tick frequency from the OS\n                QueryPerformanceFrequency((LARGE_INTEGER *) &temp);\n\n                // convert to type in which it is needed\n                freq = ((double) temp.QuadPart) / 1000.0;\n\n                // rememeber query\n                freq_set = true;\n            }\n        };\n\n        // Destructor\n        ~StopWatchWin() { };\n\n    public:\n        //! Start time measurement\n        inline void start();\n\n        //! Stop time measurement\n        inline void stop();\n\n        //! Reset time counters to zero\n        inline void reset();\n\n        //! Time in msec. after start. If the stop watch is still running (i.e. there\n        //! was no call to stop()) then the elapsed time is returned, otherwise the\n        //! time between the last start() and stop call is returned\n        inline float getTime();\n\n        //! Mean time to date based on the number of times the stopwatch has been\n        //! _stopped_ (ie finished sessions) and the current total time\n        inline float getAverageTime();\n\n    private:\n        // member variables\n\n        //! Start of measurement\n        LARGE_INTEGER  start_time;\n        //! End of measurement\n        LARGE_INTEGER  end_time;\n\n        //! Time difference between the last start and stop\n        float  diff_time;\n\n        //! TOTAL time difference between starts and stops\n        float  total_time;\n\n        //! flag if the stop watch is running\n        bool running;\n\n        //! Number of times clock has been started\n        //! and stopped to allow averaging\n        int clock_sessions;\n\n        //! tick frequency\n        double  freq;\n\n        //! flag if the frequency has been set\n        bool  freq_set;\n};\n\n// functions, inlined\n\n////////////////////////////////////////////////////////////////////////////////\n//! Start time measurement\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchWin::start()\n{\n    QueryPerformanceCounter((LARGE_INTEGER *) &start_time);\n    running = true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Stop time measurement and increment add to the current diff_time summation\n//! variable. Also increment the number of times this clock has been run.\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchWin::stop()\n{\n    QueryPerformanceCounter((LARGE_INTEGER *) &end_time);\n    diff_time = (float)\n                (((double) end_time.QuadPart - (double) start_time.QuadPart) / freq);\n\n    total_time += diff_time;\n    clock_sessions++;\n    running = false;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Reset the timer to 0. Does not change the timer running state but does\n//! recapture this point in time as the current start time if it is running.\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchWin::reset()\n{\n    diff_time = 0;\n    total_time = 0;\n    clock_sessions = 0;\n\n    if (running)\n    {\n        QueryPerformanceCounter((LARGE_INTEGER *) &start_time);\n    }\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//! Time in msec. after start. If the stop watch is still running (i.e. there\n//! was no call to stop()) then the elapsed time is returned added to the\n//! current diff_time sum, otherwise the current summed time difference alone\n//! is returned.\n////////////////////////////////////////////////////////////////////////////////\ninline float\nStopWatchWin::getTime()\n{\n    // Return the TOTAL time to date\n    float retval = total_time;\n\n    if (running)\n    {\n        LARGE_INTEGER temp;\n        QueryPerformanceCounter((LARGE_INTEGER *) &temp);\n        retval += (float)\n                  (((double)(temp.QuadPart - start_time.QuadPart)) / freq);\n    }\n\n    return retval;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Time in msec. for a single run based on the total number of COMPLETED runs\n//! and the total time.\n////////////////////////////////////////////////////////////////////////////////\ninline float\nStopWatchWin::getAverageTime()\n{\n    return (clock_sessions > 0) ? (total_time/clock_sessions) : 0.0f;\n}\n#else\n// Declarations for Stopwatch on Linux and Mac OSX\n// includes, system\n#include <ctime>\n#include <sys/time.h>\n\n//! Windows specific implementation of StopWatch\nclass StopWatchLinux : public StopWatchInterface\n{\n    public:\n        //! Constructor, default\n        StopWatchLinux() :\n            start_time(), diff_time(0.0), total_time(0.0),\n            running(false), clock_sessions(0)\n        { };\n\n        // Destructor\n        virtual ~StopWatchLinux()\n        { };\n\n    public:\n        //! Start time measurement\n        inline void start();\n\n        //! Stop time measurement\n        inline void stop();\n\n        //! Reset time counters to zero\n        inline void reset();\n\n        //! Time in msec. after start. If the stop watch is still running (i.e. there\n        //! was no call to stop()) then the elapsed time is returned, otherwise the\n        //! time between the last start() and stop call is returned\n        inline float getTime();\n\n        //! Mean time to date based on the number of times the stopwatch has been\n        //! _stopped_ (ie finished sessions) and the current total time\n        inline float getAverageTime();\n\n    private:\n\n        // helper functions\n\n        //! Get difference between start time and current time\n        inline float getDiffTime();\n\n    private:\n\n        // member variables\n\n        //! Start of measurement\n        struct timeval  start_time;\n\n        //! Time difference between the last start and stop\n        float  diff_time;\n\n        //! TOTAL time difference between starts and stops\n        float  total_time;\n\n        //! flag if the stop watch is running\n        bool running;\n\n        //! Number of times clock has been started\n        //! and stopped to allow averaging\n        int clock_sessions;\n};\n\n// functions, inlined\n\n////////////////////////////////////////////////////////////////////////////////\n//! Start time measurement\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchLinux::start()\n{\n    gettimeofday(&start_time, 0);\n    running = true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Stop time measurement and increment add to the current diff_time summation\n//! variable. Also increment the number of times this clock has been run.\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchLinux::stop()\n{\n    diff_time = getDiffTime();\n    total_time += diff_time;\n    running = false;\n    clock_sessions++;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Reset the timer to 0. Does not change the timer running state but does\n//! recapture this point in time as the current start time if it is running.\n////////////////////////////////////////////////////////////////////////////////\ninline void\nStopWatchLinux::reset()\n{\n    diff_time = 0;\n    total_time = 0;\n    clock_sessions = 0;\n\n    if (running)\n    {\n        gettimeofday(&start_time, 0);\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Time in msec. after start. If the stop watch is still running (i.e. there\n//! was no call to stop()) then the elapsed time is returned added to the\n//! current diff_time sum, otherwise the current summed time difference alone\n//! is returned.\n////////////////////////////////////////////////////////////////////////////////\ninline float\nStopWatchLinux::getTime()\n{\n    // Return the TOTAL time to date\n    float retval = total_time;\n\n    if (running)\n    {\n        retval += getDiffTime();\n    }\n\n    return retval;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Time in msec. for a single run based on the total number of COMPLETED runs\n//! and the total time.\n////////////////////////////////////////////////////////////////////////////////\ninline float\nStopWatchLinux::getAverageTime()\n{\n    return (clock_sessions > 0) ? (total_time/clock_sessions) : 0.0f;\n}\n////////////////////////////////////////////////////////////////////////////////\n\n////////////////////////////////////////////////////////////////////////////////\ninline float\nStopWatchLinux::getDiffTime()\n{\n    struct timeval t_time;\n    gettimeofday(&t_time, 0);\n\n    // time difference in milli-seconds\n    return (float)(1000.0 * (t_time.tv_sec - start_time.tv_sec)\n                   + (0.001 * (t_time.tv_usec - start_time.tv_usec)));\n}\n#endif // WIN32\n\n////////////////////////////////////////////////////////////////////////////////\n//! Timer functionality exported\n\n////////////////////////////////////////////////////////////////////////////////\n//! Create a new timer\n//! @return true if a time has been created, otherwise false\n//! @param  name of the new timer, 0 if the creation failed\n////////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkCreateTimer(StopWatchInterface **timer_interface)\n{\n    //printf(\"sdkCreateTimer called object %08x\\n\", (void *)*timer_interface);\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n    *timer_interface = (StopWatchInterface *)new StopWatchWin();\n#else\n    *timer_interface = (StopWatchInterface *)new StopWatchLinux();\n#endif\n    return (*timer_interface != NULL) ? true : false;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//! Delete a timer\n//! @return true if a time has been deleted, otherwise false\n//! @param  name of the timer to delete\n////////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkDeleteTimer(StopWatchInterface **timer_interface)\n{\n    //printf(\"sdkDeleteTimer called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        delete *timer_interface;\n        *timer_interface = NULL;\n    }\n\n    return true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Start the time with name \\a name\n//! @param name  name of the timer to start\n////////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkStartTimer(StopWatchInterface **timer_interface)\n{\n    //printf(\"sdkStartTimer called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        (*timer_interface)->start();\n    }\n\n    return true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Stop the time with name \\a name. Does not reset.\n//! @param name  name of the timer to stop\n////////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkStopTimer(StopWatchInterface **timer_interface)\n{\n    // printf(\"sdkStopTimer called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        (*timer_interface)->stop();\n    }\n\n    return true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Resets the timer's counter.\n//! @param name  name of the timer to reset.\n////////////////////////////////////////////////////////////////////////////////\ninline bool\nsdkResetTimer(StopWatchInterface **timer_interface)\n{\n    // printf(\"sdkResetTimer called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        (*timer_interface)->reset();\n    }\n\n    return true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Return the average time for timer execution as the total time\n//! for the timer dividied by the number of completed (stopped) runs the timer\n//! has made.\n//! Excludes the current running time if the timer is currently running.\n//! @param name  name of the timer to return the time of\n////////////////////////////////////////////////////////////////////////////////\ninline float\nsdkGetAverageTimerValue(StopWatchInterface **timer_interface)\n{\n    //  printf(\"sdkGetAverageTimerValue called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        return (*timer_interface)->getAverageTime();\n    }\n    else\n    {\n        return 0.0f;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//! Total execution time for the timer over all runs since the last reset\n//! or timer creation.\n//! @param name  name of the timer to obtain the value of.\n////////////////////////////////////////////////////////////////////////////////\ninline float\nsdkGetTimerValue(StopWatchInterface **timer_interface)\n{\n    // printf(\"sdkGetTimerValue called object %08x\\n\", (void *)*timer_interface);\n    if (*timer_interface)\n    {\n        return (*timer_interface)->getTime();\n    }\n    else\n    {\n        return 0.0f;\n    }\n}\n\n#endif // HELPER_TIMER_H\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/multithreading.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef MULTITHREADING_H\n#define MULTITHREADING_H\n\n\n//Simple portable thread library.\n\n//Windows threads.\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#include <windows.h>\n\ntypedef HANDLE CUTThread;\ntypedef unsigned(WINAPI *CUT_THREADROUTINE)(void *);\n\n#define CUT_THREADPROC unsigned WINAPI\n#define  CUT_THREADEND return 0\n\n#else\n//POSIX threads.\n#include <pthread.h>\n\ntypedef pthread_t CUTThread;\ntypedef void *(*CUT_THREADROUTINE)(void *);\n\n#define CUT_THREADPROC void\n#define  CUT_THREADEND\n#endif\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//Create thread.\nCUTThread cutStartThread(CUT_THREADROUTINE, void *data);\n\n//Wait for thread to finish.\nvoid cutEndThread(CUTThread thread);\n\n//Destroy thread.\nvoid cutDestroyThread(CUTThread thread);\n\n//Wait for multiple threads.\nvoid cutWaitForThreads(const CUTThread *threads, int num);\n\n#ifdef __cplusplus\n} //extern \"C\"\n#endif\n\n#endif //MULTITHREADING_H\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvMath.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//\n// Template math library for common 3D functionality\n//\n// This code is in part deriver from glh, a cross platform glut helper library.\n// The copyright for glh follows this notice.\n//\n// Copyright (c) NVIDIA Corporation. All rights reserved.\n////////////////////////////////////////////////////////////////////////////////\n\n/*\n    Copyright (c) 2000 Cass Everitt\n    Copyright (c) 2000 NVIDIA Corporation\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or\n    without modification, are permitted provided that the following\n    conditions are met:\n\n     * Redistributions of source code must retain the above\n       copyright notice, this list of conditions and the following\n       disclaimer.\n\n     * Redistributions in binary form must reproduce the above\n       copyright notice, this list of conditions and the following\n       disclaimer in the documentation and/or other materials\n       provided with the distribution.\n\n     * The names of contributors to this software may not be used\n       to endorse or promote products derived from this software\n       without specific prior written permission.\n\n       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n       ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n       POSSIBILITY OF SUCH DAMAGE.\n\n\n    Cass Everitt - cass@r3.nu\n*/\n\n#ifndef NV_MATH_H\n#define NV_MATH_H\n\n#include <math.h>\n\n#include <nvVector.h>\n#include <nvMatrix.h>\n#include <nvQuaternion.h>\n\n#define NV_PI   float(3.1415926535897932384626433832795)\n\nnamespace nv\n{\n\n    typedef vec2<float> vec2f;\n    typedef vec3<float> vec3f;\n    typedef vec3<int> vec3i;\n    typedef vec3<unsigned int> vec3ui;\n    typedef vec4<float> vec4f;\n    typedef matrix4<float> matrix4f;\n    typedef quaternion<float> quaternionf;\n\n\n    inline void applyRotation(const quaternionf &r)\n    {\n        float angle;\n        vec3f axis;\n        r.get_value(axis, angle);\n        glRotatef(angle/3.1415926f * 180.0f, axis[0], axis[1], axis[2]);\n    }\n\n\n\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvMatrix.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//\n// Template math library for common 3D functionality\n//\n// nvMatrix.h - template matrix code\n//\n// This code is in part deriver from glh, a cross platform glut helper library.\n// The copyright for glh follows this notice.\n//\n// Copyright (c) NVIDIA Corporation. All rights reserved.\n////////////////////////////////////////////////////////////////////////////////\n\n/*\n    Copyright (c) 2000 Cass Everitt\n    Copyright (c) 2000 NVIDIA Corporation\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or\n    without modification, are permitted provided that the following\n    conditions are met:\n\n     * Redistributions of source code must retain the above\n       copyright notice, this list of conditions and the following\n       disclaimer.\n\n     * Redistributions in binary form must reproduce the above\n       copyright notice, this list of conditions and the following\n       disclaimer in the documentation and/or other materials\n       provided with the distribution.\n\n     * The names of contributors to this software may not be used\n       to endorse or promote products derived from this software\n       without specific prior written permission.\n\n       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n       ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n       POSSIBILITY OF SUCH DAMAGE.\n\n\n    Cass Everitt - cass@r3.nu\n*/\n\n#ifndef NV_MATRIX_H\n#define NV_MATRIX_H\n\nnamespace nv\n{\n\n    template <class T> class vec2;\n    template <class T> class vec3;\n    template <class T> class vec4;\n\n    ////////////////////////////////////////////////////////////////////////////////\n    //\n    //  Matrix\n    //\n    ////////////////////////////////////////////////////////////////////////////////\n    template<class T>\n    class matrix4\n    {\n\n        public:\n\n            matrix4()\n            {\n                make_identity();\n            }\n\n            matrix4(T t)\n            {\n                set_value(t);\n            }\n\n            matrix4(const T *m)\n            {\n                set_value(m);\n            }\n\n            matrix4(T a00, T a01, T a02, T a03,\n                    T a10, T a11, T a12, T a13,\n                    T a20, T a21, T a22, T a23,\n                    T a30, T a31, T a32, T a33) :\n                _11(a00), _12(a01), _13(a02), _14(a03),\n                _21(a10), _22(a11), _23(a12), _24(a13),\n                _31(a20), _32(a21), _33(a22), _34(a23),\n                _41(a30), _42(a31), _43(a32), _44(a33)\n            {}\n\n\n            void get_value(T *mp) const\n            {\n                int c = 0;\n\n                for (int j=0; j < 4; j++)\n                    for (int i=0; i < 4; i++)\n                    {\n                        mp[c++] = element(i,j);\n                    }\n            }\n\n            const T *get_value() const\n            {\n                return _array;\n            }\n\n            void set_value(T *mp)\n            {\n                int c = 0;\n\n                for (int j=0; j < 4; j++)\n                    for (int i=0; i < 4; i++)\n                    {\n                        element(i,j) = mp[c++];\n                    }\n            }\n\n            void set_value(T r)\n            {\n                for (int i=0; i < 4; i++)\n                    for (int j=0; j < 4; j++)\n                    {\n                        element(i,j) = r;\n                    }\n            }\n\n            void make_identity()\n            {\n                element(0,0) = 1.0;\n                element(0,1) = 0.0;\n                element(0,2) = 0.0;\n                element(0,3) = 0.0;\n\n                element(1,0) = 0.0;\n                element(1,1) = 1.0;\n                element(1,2) = 0.0;\n                element(1,3) = 0.0;\n\n                element(2,0) = 0.0;\n                element(2,1) = 0.0;\n                element(2,2) = 1.0;\n                element(2,3) = 0.0;\n\n                element(3,0) = 0.0;\n                element(3,1) = 0.0;\n                element(3,2) = 0.0;\n                element(3,3) = 1.0;\n            }\n\n            // set a uniform scale\n            void set_scale(T s)\n            {\n                element(0,0) = s;\n                element(1,1) = s;\n                element(2,2) = s;\n            }\n\n            void set_scale(const vec3<T> &s)\n            {\n                for (int i = 0; i < 3; i++)\n                {\n                    element(i,i) = s[i];\n                }\n            }\n\n\n            void set_translate(const vec3<T> &t)\n            {\n                for (int i = 0; i < 3; i++)\n                {\n                    element(i,3) = t[i];\n                }\n            }\n\n            void set_row(int r, const vec4<T> &t)\n            {\n                for (int i = 0; i < 4; i++)\n                {\n                    element(r,i) = t[i];\n                }\n            }\n\n            void set_column(int c, const vec4<T> &t)\n            {\n                for (int i = 0; i < 4; i++)\n                {\n                    element(i,c) = t[i];\n                }\n            }\n\n            vec4<T> get_row(int r) const\n            {\n                vec4<T> v;\n\n                for (int i = 0; i < 4; i++)\n                {\n                    v[i] = element(r,i);\n                }\n\n                return v;\n            }\n\n            vec4<T> get_column(int c) const\n            {\n                vec4<T> v;\n\n                for (int i = 0; i < 4; i++)\n                {\n                    v[i] = element(i,c);\n                }\n\n                return v;\n            }\n\n            friend matrix4 inverse(const matrix4 &m)\n            {\n                matrix4 minv;\n\n                T r1[8], r2[8], r3[8], r4[8];\n                T *s[4], *tmprow;\n\n                s[0] = &r1[0];\n                s[1] = &r2[0];\n                s[2] = &r3[0];\n                s[3] = &r4[0];\n\n                register int i,j,p,jj;\n\n                for (i=0; i<4; i++)\n                {\n                    for (j=0; j<4; j++)\n                    {\n                        s[i][j] = m.element(i,j);\n\n                        if (i==j)\n                        {\n                            s[i][j+4] = 1.0;\n                        }\n                        else\n                        {\n                            s[i][j+4] = 0.0;\n                        }\n                    }\n                }\n\n                T scp[4];\n\n                for (i=0; i<4; i++)\n                {\n                    scp[i] = T(fabs(s[i][0]));\n\n                    for (j=1; j<4; j++)\n                        if (T(fabs(s[i][j])) > scp[i])\n                        {\n                            scp[i] = T(fabs(s[i][j]));\n                        }\n\n                    if (scp[i] == 0.0)\n                    {\n                        return minv;    // singular matrix!\n                    }\n                }\n\n                int pivot_to;\n                T scp_max;\n\n                for (i=0; i<4; i++)\n                {\n                    // select pivot row\n                    pivot_to = i;\n                    scp_max = T(fabs(s[i][i]/scp[i]));\n\n                    // find out which row should be on top\n                    for (p=i+1; p<4; p++)\n                        if (T(fabs(s[p][i]/scp[p])) > scp_max)\n                        {\n                            scp_max = T(fabs(s[p][i]/scp[p]));\n                            pivot_to = p;\n                        }\n\n                    // Pivot if necessary\n                    if (pivot_to != i)\n                    {\n                        tmprow = s[i];\n                        s[i] = s[pivot_to];\n                        s[pivot_to] = tmprow;\n                        T tmpscp;\n                        tmpscp = scp[i];\n                        scp[i] = scp[pivot_to];\n                        scp[pivot_to] = tmpscp;\n                    }\n\n                    T mji;\n\n                    // perform gaussian elimination\n                    for (j=i+1; j<4; j++)\n                    {\n                        mji = s[j][i]/s[i][i];\n                        s[j][i] = 0.0;\n\n                        for (jj=i+1; jj<8; jj++)\n                        {\n                            s[j][jj] -= mji*s[i][jj];\n                        }\n                    }\n                }\n\n                if (s[3][3] == 0.0)\n                {\n                    return minv;    // singular matrix!\n                }\n\n                //\n                // Now we have an upper triangular matrix.\n                //\n                //  x x x x | y y y y\n                //  0 x x x | y y y y\n                //  0 0 x x | y y y y\n                //  0 0 0 x | y y y y\n                //\n                //  we'll back substitute to get the inverse\n                //\n                //  1 0 0 0 | z z z z\n                //  0 1 0 0 | z z z z\n                //  0 0 1 0 | z z z z\n                //  0 0 0 1 | z z z z\n                //\n\n                T mij;\n\n                for (i=3; i>0; i--)\n                {\n                    for (j=i-1; j > -1; j--)\n                    {\n                        mij = s[j][i]/s[i][i];\n\n                        for (jj=j+1; jj<8; jj++)\n                        {\n                            s[j][jj] -= mij*s[i][jj];\n                        }\n                    }\n                }\n\n                for (i=0; i<4; i++)\n                    for (j=0; j<4; j++)\n                    {\n                        minv(i,j) = s[i][j+4] / s[i][i];\n                    }\n\n                return minv;\n            }\n\n\n            friend matrix4 transpose(const matrix4 &m)\n            {\n                matrix4 mtrans;\n\n                for (int i=0; i<4; i++)\n                    for (int j=0; j<4; j++)\n                    {\n                        mtrans(i,j) = m.element(j,i);\n                    }\n\n                return mtrans;\n            }\n\n            matrix4 &operator *= (const matrix4 &rhs)\n            {\n                matrix4 mt(*this);\n                set_value(T(0));\n\n                for (int i=0; i < 4; i++)\n                    for (int j=0; j < 4; j++)\n                        for (int c=0; c < 4; c++)\n                        {\n                            element(i,j) += mt(i,c) * rhs(c,j);\n                        }\n\n                return *this;\n            }\n\n            friend matrix4 operator * (const matrix4 &lhs, const matrix4 &rhs)\n            {\n                matrix4 r(T(0));\n\n                for (int i=0; i < 4; i++)\n                    for (int j=0; j < 4; j++)\n                        for (int c=0; c < 4; c++)\n                        {\n                            r.element(i,j) += lhs(i,c) * rhs(c,j);\n                        }\n\n                return r;\n            }\n\n            // dst = M * src\n            vec4<T> operator *(const vec4<T> &src) const\n            {\n                vec4<T> r;\n\n                for (int i = 0; i < 4; i++)\n                    r[i]  = (src[0] * element(i,0) + src[1] * element(i,1) +\n                             src[2] * element(i,2) + src[3] * element(i,3));\n\n                return r;\n            }\n\n            // dst = src * M\n            friend vec4<T> operator *(const vec4<T> &lhs, const matrix4 &rhs)\n            {\n                vec4<T> r;\n\n                for (int i = 0; i < 4; i++)\n                    r[i]  = (lhs[0] * rhs.element(0,i) + lhs[1] * rhs.element(1,i) +\n                             lhs[2] * rhs.element(2,i) + lhs[3] * rhs.element(3,i));\n\n                return r;\n            }\n\n            T &operator()(int row, int col)\n            {\n                return element(row,col);\n            }\n\n            const T &operator()(int row, int col) const\n            {\n                return element(row,col);\n            }\n\n            T &element(int row, int col)\n            {\n                return _array[row | (col<<2)];\n            }\n\n            const T &element(int row, int col) const\n            {\n                return _array[row | (col<<2)];\n            }\n\n            matrix4 &operator *= (const T &r)\n            {\n                for (int i = 0; i < 4; ++i)\n                {\n                    element(0,i) *= r;\n                    element(1,i) *= r;\n                    element(2,i) *= r;\n                    element(3,i) *= r;\n                }\n\n                return *this;\n            }\n\n            matrix4 &operator += (const matrix4 &mat)\n            {\n                for (int i = 0; i < 4; ++i)\n                {\n                    element(0,i) += mat.element(0,i);\n                    element(1,i) += mat.element(1,i);\n                    element(2,i) += mat.element(2,i);\n                    element(3,i) += mat.element(3,i);\n                }\n\n                return *this;\n            }\n\n\n            friend bool operator == (const matrix4 &lhs, const matrix4 &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < 16; i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            friend bool operator != (const matrix4 &lhs, const matrix4 &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < 16; i++)\n                {\n                    r &= lhs._array[i] != rhs._array[i];\n                }\n\n                return r;\n            }\n\n            union\n            {\n                struct\n                {\n                    T _11, _12, _13, _14;   // standard names for components\n                    T _21, _22, _23, _24;   // standard names for components\n                    T _31, _32, _33, _34;   // standard names for components\n                    T _41, _42, _43, _44;   // standard names for components\n                };\n                T _array[16];     // array access\n            };\n    };\n\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvQuaternion.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//\n// Template math library for common 3D functionality\n//\n// nvQuaterion.h - quaternion template and utility functions\n//\n// This code is in part deriver from glh, a cross platform glut helper library.\n// The copyright for glh follows this notice.\n//\n// Copyright (c) NVIDIA Corporation. All rights reserved.\n////////////////////////////////////////////////////////////////////////////////\n\n/*\n    Copyright (c) 2000 Cass Everitt\n    Copyright (c) 2000 NVIDIA Corporation\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or\n    without modification, are permitted provided that the following\n    conditions are met:\n\n     * Redistributions of source code must retain the above\n       copyright notice, this list of conditions and the following\n       disclaimer.\n\n     * Redistributions in binary form must reproduce the above\n       copyright notice, this list of conditions and the following\n       disclaimer in the documentation and/or other materials\n       provided with the distribution.\n\n     * The names of contributors to this software may not be used\n       to endorse or promote products derived from this software\n       without specific prior written permission.\n\n       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n       ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n       POSSIBILITY OF SUCH DAMAGE.\n\n\n    Cass Everitt - cass@r3.nu\n*/\n#ifndef NV_QUATERNION_H\n#define NV_QUATERNION_H\n\nnamespace nv\n{\n\n    template <class T> class vec2;\n    template <class T> class vec3;\n    template <class T> class vec4;\n\n    ////////////////////////////////////////////////////////////////////////////////\n    //\n    //  Quaternion\n    //\n    ////////////////////////////////////////////////////////////////////////////////\n\n    template< class T>\n    class quaternion\n    {\n        public:\n\n            quaternion() : x(0.0), y(0.0), z(0.0), w(0.0)\n            {\n            }\n\n            quaternion(const T v[4])\n            {\n                set_value(v);\n            }\n\n\n            quaternion(T q0, T q1, T q2, T q3)\n            {\n                set_value(q0, q1, q2, q3);\n            }\n\n\n            quaternion(const matrix4<T> &m)\n            {\n                set_value(m);\n            }\n\n\n            quaternion(const vec3<T> &axis, T radians)\n            {\n                set_value(axis, radians);\n            }\n\n\n            quaternion(const vec3<T> &rotateFrom, const vec3<T> &rotateTo)\n            {\n                set_value(rotateFrom, rotateTo);\n            }\n\n            quaternion(const vec3<T> &from_look, const vec3<T> &from_up,\n                       const vec3<T> &to_look, const vec3<T> &to_up)\n            {\n                set_value(from_look, from_up, to_look, to_up);\n            }\n\n            const T *get_value() const\n            {\n                return  &_array[0];\n            }\n\n            void get_value(T &q0, T &q1, T &q2, T &q3) const\n            {\n                q0 = _array[0];\n                q1 = _array[1];\n                q2 = _array[2];\n                q3 = _array[3];\n            }\n\n            quaternion &set_value(T q0, T q1, T q2, T q3)\n            {\n                _array[0] = q0;\n                _array[1] = q1;\n                _array[2] = q2;\n                _array[3] = q3;\n                return *this;\n            }\n\n            void get_value(vec3<T> &axis, T &radians) const\n            {\n                radians = T(acos(_array[3]) * T(2.0));\n\n                if (radians == T(0.0))\n                {\n                    axis = vec3<T>(0.0, 0.0, 1.0);\n                }\n                else\n                {\n                    axis[0] = _array[0];\n                    axis[1] = _array[1];\n                    axis[2] = _array[2];\n                    axis = normalize(axis);\n                }\n            }\n\n            void get_value(matrix4<T> &m) const\n            {\n                T s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;\n\n                T norm = _array[0] * _array[0] + _array[1] * _array[1] + _array[2] * _array[2] + _array[3] * _array[3];\n\n                s = (norm == T(0.0)) ? T(0.0) : (T(2.0) / norm);\n\n                xs = _array[0] * s;\n                ys = _array[1] * s;\n                zs = _array[2] * s;\n\n                wx = _array[3] * xs;\n                wy = _array[3] * ys;\n                wz = _array[3] * zs;\n\n                xx = _array[0] * xs;\n                xy = _array[0] * ys;\n                xz = _array[0] * zs;\n\n                yy = _array[1] * ys;\n                yz = _array[1] * zs;\n                zz = _array[2] * zs;\n\n                m(0,0) = T(T(1.0) - (yy + zz));\n                m(1,0) = T(xy + wz);\n                m(2,0) = T(xz - wy);\n\n                m(0,1) = T(xy - wz);\n                m(1,1) = T(T(1.0) - (xx + zz));\n                m(2,1) = T(yz + wx);\n\n                m(0,2) = T(xz + wy);\n                m(1,2) = T(yz - wx);\n                m(2,2) = T(T(1.0) - (xx + yy));\n\n                m(3,0) = m(3,1) = m(3,2) = m(0,3) = m(1,3) = m(2,3) = T(0.0);\n                m(3,3) = T(1.0);\n            }\n\n            quaternion &set_value(const T *qp)\n            {\n                for (int i = 0; i < 4; i++)\n                {\n                    _array[i] = qp[i];\n                }\n\n                return *this;\n            }\n\n            quaternion &set_value(const matrix4<T> &m)\n            {\n                T tr, s;\n                int i, j, k;\n                const int nxt[3] = { 1, 2, 0 };\n\n                tr = m(0,0) + m(1,1) + m(2,2);\n\n                if (tr > T(0))\n                {\n                    s = T(sqrt(tr + m(3,3)));\n                    _array[3] = T(s * 0.5);\n                    s = T(0.5) / s;\n\n                    _array[0] = T((m(1,2) - m(2,1)) * s);\n                    _array[1] = T((m(2,0) - m(0,2)) * s);\n                    _array[2] = T((m(0,1) - m(1,0)) * s);\n                }\n                else\n                {\n                    i = 0;\n\n                    if (m(1,1) > m(0,0))\n                    {\n                        i = 1;\n                    }\n\n                    if (m(2,2) > m(i,i))\n                    {\n                        i = 2;\n                    }\n\n                    j = nxt[i];\n                    k = nxt[j];\n\n                    s = T(sqrt((m(i,j) - (m(j,j) + m(k,k))) + T(1.0)));\n\n                    _array[i] = T(s * 0.5);\n                    s = T(0.5 / s);\n\n                    _array[3] = T((m(j,k) - m(k,j)) * s);\n                    _array[j] = T((m(i,j) + m(j,i)) * s);\n                    _array[k] = T((m(i,k) + m(k,i)) * s);\n                }\n\n                return *this;\n            }\n\n            quaternion &set_value(const vec3<T> &axis, T theta)\n            {\n                T sqnorm = square_norm(axis);\n\n                if (sqnorm == T(0.0))\n                {\n                    // axis too small.\n                    x = y = z = T(0.0);\n                    w = T(1.0);\n                }\n                else\n                {\n                    theta *= T(0.5);\n                    T sin_theta = T(sin(theta));\n\n                    if (sqnorm != T(1))\n                    {\n                        sin_theta /= T(sqrt(sqnorm));\n                    }\n\n                    x = sin_theta * axis[0];\n                    y = sin_theta * axis[1];\n                    z = sin_theta * axis[2];\n                    w = T(cos(theta));\n                }\n\n                return *this;\n            }\n\n            quaternion &set_value(const vec3<T> &rotateFrom, const vec3<T> &rotateTo)\n            {\n                vec3<T> p1, p2;\n                T alpha;\n\n                p1 = normalize(rotateFrom);\n                p2 = normalize(rotateTo);\n\n                alpha = dot(p1, p2);\n\n                if (alpha == T(1.0))\n                {\n                    *this = quaternion();\n                    return *this;\n                }\n\n                // ensures that the anti-parallel case leads to a positive dot\n                if (alpha == T(-1.0))\n                {\n                    vec3<T> v;\n\n                    if (p1[0] != p1[1] || p1[0] != p1[2])\n                    {\n                        v = vec3<T>(p1[1], p1[2], p1[0]);\n                    }\n                    else\n                    {\n                        v = vec3<T>(-p1[0], p1[1], p1[2]);\n                    }\n\n                    v -= p1 * dot(p1, v);\n                    v = normalize(v);\n\n                    set_value(v, T(3.1415926));\n                    return *this;\n                }\n\n                p1 = normalize(cross(p1, p2));\n\n                set_value(p1,T(acos(alpha)));\n\n                return *this;\n            }\n\n            quaternion &set_value(const vec3<T> &from_look, const vec3<T> &from_up,\n                                  const vec3<T> &to_look, const vec3<T> &to_up)\n            {\n                quaternion r_look = quaternion(from_look, to_look);\n\n                vec3<T> rotated_from_up(from_up);\n                r_look.mult_vec(rotated_from_up);\n\n                quaternion r_twist = quaternion(rotated_from_up, to_up);\n\n                *this = r_twist;\n                *this *= r_look;\n                return *this;\n            }\n\n            quaternion &operator *= (const quaternion<T> &qr)\n            {\n                quaternion ql(*this);\n\n                w = ql.w * qr.w - ql.x * qr.x - ql.y * qr.y - ql.z * qr.z;\n                x = ql.w * qr.x + ql.x * qr.w + ql.y * qr.z - ql.z * qr.y;\n                y = ql.w * qr.y + ql.y * qr.w + ql.z * qr.x - ql.x * qr.z;\n                z = ql.w * qr.z + ql.z * qr.w + ql.x * qr.y - ql.y * qr.x;\n\n                return *this;\n            }\n\n            friend quaternion normalize(const quaternion<T> &q)\n            {\n                quaternion r(q);\n                T rnorm = T(1.0) / T(sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z));\n\n                r.x *= rnorm;\n                r.y *= rnorm;\n                r.z *= rnorm;\n                r.w *= rnorm;\n            }\n\n            friend quaternion<T> conjugate(const quaternion<T> &q)\n            {\n                quaternion<T> r(q);\n                r._array[0] *= T(-1.0);\n                r._array[1] *= T(-1.0);\n                r._array[2] *= T(-1.0);\n                return r;\n            }\n\n            friend quaternion<T> inverse(const quaternion<T> &q)\n            {\n                return conjugate(q);\n            }\n\n            //\n            // Quaternion multiplication with cartesian vector\n            // v' = q*v*q(star)\n            //\n            void mult_vec(const vec3<T> &src, vec3<T> &dst) const\n            {\n                T v_coef = w * w - x * x - y * y - z * z;\n                T u_coef = T(2.0) * (src[0] * x + src[1] * y + src[2] * z);\n                T c_coef = T(2.0) * w;\n\n                dst.v[0] = v_coef * src.v[0] + u_coef * x + c_coef * (y * src.v[2] - z * src.v[1]);\n                dst.v[1] = v_coef * src.v[1] + u_coef * y + c_coef * (z * src.v[0] - x * src.v[2]);\n                dst.v[2] = v_coef * src.v[2] + u_coef * z + c_coef * (x * src.v[1] - y * src.v[0]);\n            }\n\n            void mult_vec(vec3<T> &src_and_dst) const\n            {\n                mult_vec(vec3<T>(src_and_dst), src_and_dst);\n            }\n\n            void scale_angle(T scaleFactor)\n            {\n                vec3<T> axis;\n                T radians;\n\n                get_value(axis, radians);\n                radians *= scaleFactor;\n                set_value(axis, radians);\n            }\n\n            friend quaternion<T> slerp(const quaternion<T> &p, const quaternion<T> &q, T alpha)\n            {\n                quaternion r;\n\n                T cos_omega = p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w;\n                // if B is on opposite hemisphere from A, use -B instead\n\n                int bflip;\n\n                if ((bflip = (cos_omega < T(0))))\n                {\n                    cos_omega = -cos_omega;\n                }\n\n                // complementary interpolation parameter\n                T beta = T(1) - alpha;\n\n                if (cos_omega >= T(1))\n                {\n                    return p;\n                }\n\n                T omega = T(acos(cos_omega));\n                T one_over_sin_omega = T(1.0) / T(sin(omega));\n\n                beta    = T(sin(omega*beta)  * one_over_sin_omega);\n                alpha   = T(sin(omega*alpha) * one_over_sin_omega);\n\n                if (bflip)\n                {\n                    alpha = -alpha;\n                }\n\n                r.x = beta * p._array[0]+ alpha * q._array[0];\n                r.y = beta * p._array[1]+ alpha * q._array[1];\n                r.z = beta * p._array[2]+ alpha * q._array[2];\n                r.w = beta * p._array[3]+ alpha * q._array[3];\n                return r;\n            }\n\n            T &operator [](int i)\n            {\n                return _array[i];\n            }\n\n            const T &operator [](int i) const\n            {\n                return _array[i];\n            }\n\n\n            friend bool operator == (const quaternion<T> &lhs, const quaternion<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < 4; i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            friend bool operator != (const quaternion<T> &lhs, const quaternion<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < 4; i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            friend quaternion<T> operator * (const quaternion<T> &lhs, const quaternion<T> &rhs)\n            {\n                quaternion r(lhs);\n                r *= rhs;\n                return r;\n            }\n\n\n            union\n            {\n                struct\n                {\n                    T x;\n                    T y;\n                    T z;\n                    T w;\n                };\n                T _array[4];\n            };\n\n    };\n\n\n\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvShaderUtils.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n/*\n *\n * Utility functions for compiling shaders and programs\n *\n * Author: Evan Hart\n * Copyright (c) NVIDIA Corporation. All rights reserved.\n *\n */\n\n\n#ifndef NV_SHADER_UTILS_H\n#define NV_SHADER_UTILS_H\n\n#include <stdio.h>\n#include <string.h>\n\nnamespace nv\n{\n\n\n    //\n    //\n    ////////////////////////////////////////////////////////////\n    inline GLuint CompileGLSLShader(GLenum target, const char *shader)\n    {\n        GLuint object;\n\n        object = glCreateShader(target);\n\n        if (!object)\n        {\n            return object;\n        }\n\n        glShaderSource(object, 1, &shader, NULL);\n\n        glCompileShader(object);\n\n        // check if shader compiled\n        GLint compiled = 0;\n        glGetShaderiv(object, GL_COMPILE_STATUS, &compiled);\n\n        if (!compiled)\n        {\n#ifdef NV_REPORT_COMPILE_ERRORS\n            char temp[256] = \"\";\n            glGetShaderInfoLog(object, 256, NULL, temp);\n            fprintf(stderr, \"Compile failed:\\n%s\\n\", temp);\n#endif\n            glDeleteShader(object);\n            return 0;\n        }\n\n        return object;\n    }\n\n    //\n    //\n    ////////////////////////////////////////////////////////////\n    inline GLuint CompileGLSLShaderFromFile(GLenum target, const char *filename)\n    {\n        FILE *shaderFile;\n        char *text;\n        long size;\n        size_t fsize = 0;\n\n        // read files as binary to prevent problems from newline translation\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n\n        if (fopen_s(&shaderFile, filename, \"rb\") != 0)\n#else\n        if ((shaderFile = fopen(filename, \"rb\")) == 0)\n#endif\n        {\n            return 0;\n        }\n\n        // Get the length of the file\n        fseek(shaderFile, 0, SEEK_END);\n        size = ftell(shaderFile);\n\n        // Read the file contents from the start, then close file and add a null terminator\n        fseek(shaderFile, 0, SEEK_SET);\n        text = new char[size+1];\n        fsize = fread(text, size, 1, shaderFile);\n        fclose(shaderFile);\n\n        if (fsize == 0)\n        {\n            printf(\"CompileGLSLShaderFromFile(), error... fsize = 0\\n\");\n        }\n\n        text[size] = '\\0';\n\n        GLuint object = CompileGLSLShader(target, text);\n\n        delete []text;\n\n        return object;\n    }\n\n\n    // Create a program composed of vertex and fragment shaders.\n    inline GLuint LinkGLSLProgram(GLuint vertexShader, GLuint fragmentShader)\n    {\n        GLuint program = glCreateProgram();\n        glAttachShader(program, vertexShader);\n        glAttachShader(program, fragmentShader);\n        glLinkProgram(program);\n\n#ifdef NV_REPORT_COMPILE_ERRORS\n        // Get error log.\n        GLint charsWritten, infoLogLength;\n        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);\n\n        char *infoLog = new char[infoLogLength];\n        glGetProgramInfoLog(program, infoLogLength, &charsWritten, infoLog);\n        printf(infoLog);\n        delete [] infoLog;\n#endif\n\n        // Test linker result.\n        GLint linkSucceed = GL_FALSE;\n        glGetProgramiv(program, GL_LINK_STATUS, &linkSucceed);\n\n        if (linkSucceed == GL_FALSE)\n        {\n            glDeleteProgram(program);\n            return 0;\n        }\n\n        return program;\n    }\n\n\n    // Create a program composed of vertex, geometry and fragment shaders.\n    inline GLuint LinkGLSLProgram(GLuint vertexShader, GLuint geometryShader, GLint inputType, GLint vertexOut, GLint outputType, GLuint fragmentShader)\n    {\n        GLuint program = glCreateProgram();\n        glAttachShader(program, vertexShader);\n        glAttachShader(program, geometryShader);\n        glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, inputType);\n        glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertexOut);\n        glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, outputType);\n        glAttachShader(program, fragmentShader);\n        glLinkProgram(program);\n\n#ifdef NV_REPORT_COMPILE_ERRORS\n        // Get error log.\n        GLint charsWritten, infoLogLength;\n        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);\n\n        char *infoLog = new char[infoLogLength];\n        glGetProgramInfoLog(program, infoLogLength, &charsWritten, infoLog);\n        printf(infoLog);\n        delete [] infoLog;\n#endif\n\n        // Test linker result.\n        GLint linkSucceed = GL_FALSE;\n        glGetProgramiv(program, GL_LINK_STATUS, &linkSucceed);\n\n        if (linkSucceed == GL_FALSE)\n        {\n            glDeleteProgram(program);\n            return 0;\n        }\n\n        return program;\n    }\n\n    //\n    //\n    ////////////////////////////////////////////////////////////\n    inline GLuint CompileASMShader(GLenum program_type, const char *code)\n    {\n        GLuint program_id;\n        glGenProgramsARB(1, &program_id);\n        glBindProgramARB(program_type, program_id);\n        glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(code), (GLubyte *) code);\n\n        GLint error_pos;\n        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);\n\n        if (error_pos != -1)\n        {\n#ifdef NV_REPORT_COMPILE_ERRORS\n            const GLubyte *error_string;\n            error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);\n            fprintf(stderr, \"Program error at position: %d\\n%s\\n\", (int)error_pos, error_string);\n#endif\n            return 0;\n        }\n\n        return program_id;\n    }\n\n    //\n    //\n    ////////////////////////////////////////////////////////////\n    inline GLuint CompileASMShaderFromFile(GLenum target, const char *filename)\n    {\n        FILE *shaderFile;\n        char *text;\n        long size;\n        size_t fsize = 0;\n\n        // read files as binary to prevent problems from newline translation\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n\n        if (fopen_s(&shaderFile, filename, \"rb\") != 0)\n#else\n        if ((shaderFile = fopen(filename, \"rb\")) == 0)\n#endif\n        {\n            return 0;\n        }\n\n        // Get the length of the file\n        fseek(shaderFile, 0, SEEK_END);\n        size = ftell(shaderFile);\n\n        // Read the file contents from the start, then close file and add a null terminator\n        fseek(shaderFile, 0, SEEK_SET);\n        text = new char[size+1];\n        fsize = fread(text, size, 1, shaderFile);\n        fclose(shaderFile);\n\n        if (fsize == 0)\n        {\n            printf(\"CompileGLSLShaderFromFile(), error... fsize = 0\\n\");\n        }\n\n        text[size] = '\\0';\n\n        GLuint program_id = CompileASMShader(target, text);\n\n        delete []text;\n\n        return program_id;\n    }\n\n} // nv namespace\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvVector.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n//\n// Template math library for common 3D functionality\n//\n// nvVector.h - 2-vector, 3-vector, and 4-vector templates and utilities\n//\n// This code is in part deriver from glh, a cross platform glut helper library.\n// The copyright for glh follows this notice.\n//\n// Copyright (c) NVIDIA Corporation. All rights reserved.\n////////////////////////////////////////////////////////////////////////////////\n\n/*\n    Copyright (c) 2000 Cass Everitt\n    Copyright (c) 2000 NVIDIA Corporation\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or\n    without modification, are permitted provided that the following\n    conditions are met:\n\n     * Redistributions of source code must retain the above\n       copyright notice, this list of conditions and the following\n       disclaimer.\n\n     * Redistributions in binary form must reproduce the above\n       copyright notice, this list of conditions and the following\n       disclaimer in the documentation and/or other materials\n       provided with the distribution.\n\n     * The names of contributors to this software may not be used\n       to endorse or promote products derived from this software\n       without specific prior written permission.\n\n       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n       ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n       POSSIBILITY OF SUCH DAMAGE.\n\n\n    Cass Everitt - cass@r3.nu\n*/\n#ifndef NV_VECTOR_H\n#define NV_VECTOR_H\n\nnamespace nv\n{\n\n    template <class T> class vec2;\n    template <class T> class vec3;\n    template <class T> class vec4;\n\n    //////////////////////////////////////////////////////////////////////\n    //\n    // vec2 - template class for 2-tuple vector\n    //\n    //////////////////////////////////////////////////////////////////////\n    template <class T>\n    class vec2\n    {\n        public:\n\n            typedef T value_type;\n            int size() const\n            {\n                return 2;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Constructors\n            //\n            ////////////////////////////////////////////////////////\n\n            // Default/scalar constructor\n            vec2(const T &t = T())\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = t;\n                }\n            }\n\n            // Construct from array\n            vec2(const T *tp)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = tp[i];\n                }\n            }\n\n            // Construct from explicit values\n            vec2(const T v0, const T v1)\n            {\n                x = v0;\n                y = v1;\n            }\n\n            explicit vec2(const vec3<T> &u)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = u._array[i];\n                }\n            }\n\n            explicit vec2(const vec4<T> &u)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = u._array[i];\n                }\n            }\n\n            const T *get_value() const\n            {\n                return _array;\n            }\n\n            vec2<T> &set_value(const T *rhs)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = rhs[i];\n                }\n\n                return *this;\n            }\n\n            // indexing operators\n            T &operator [](int i)\n            {\n                return _array[i];\n            }\n\n            const T &operator [](int i) const\n            {\n                return _array[i];\n            }\n\n            // type-cast operators\n            operator T *()\n            {\n                return _array;\n            }\n\n            operator const T *() const\n            {\n                return _array;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Math operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // scalar multiply assign\n            friend vec2<T> &operator *= (vec2<T> &lhs, T d)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector multiply assign\n            friend vec2<T> &operator *= (vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= rhs[i];\n                }\n\n                return lhs;\n            }\n\n            // scalar divide assign\n            friend vec2<T> &operator /= (vec2<T> &lhs, T d)\n            {\n                if (d == 0)\n                {\n                    return lhs;\n                }\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector divide assign\n            friend vec2<T> &operator /= (vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector add assign\n            friend vec2<T> &operator += (vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] += rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector subtract assign\n            friend vec2<T> &operator -= (vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] -= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // unary negate\n            friend vec2<T> operator - (const vec2<T> &rhs)\n            {\n                vec2<T> rv;\n\n                for (int i = 0; i < rhs.size(); i++)\n                {\n                    rv._array[i] = -rhs._array[i];\n                }\n\n                return rv;\n            }\n\n            // vector add\n            friend vec2<T> operator + (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt += rhs;\n            }\n\n            // vector subtract\n            friend vec2<T> operator - (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt -= rhs;\n            }\n\n            // scalar multiply\n            friend vec2<T> operator * (const vec2<T> &lhs, T rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec2<T> operator * (T lhs, const vec2<T> &rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec2<T> operator * (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec2<T> operator / (const vec2<T> &lhs, T rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec2<T> operator / (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                vec2<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Comparison operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // equality\n            friend bool operator == (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            // inequality\n            friend bool operator != (const vec2<T> &lhs, const vec2<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] != rhs._array[i];\n                }\n\n                return r;\n            }\n\n            //data intentionally left public to allow vec2.x\n            union\n            {\n                struct\n                {\n                    T x,y;          // standard names for components\n                };\n                struct\n                {\n                    T s,t;          // standard names for components\n                };\n                T _array[2];     // array access\n            };\n    };\n\n    //////////////////////////////////////////////////////////////////////\n    //\n    // vec3 - template class for 3-tuple vector\n    //\n    //////////////////////////////////////////////////////////////////////\n    template <class T>\n    class vec3\n    {\n        public:\n\n            typedef T value_type;\n            int size() const\n            {\n                return 3;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Constructors\n            //\n            ////////////////////////////////////////////////////////\n\n            // Default/scalar constructor\n            vec3(const T &t = T())\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = t;\n                }\n            }\n\n            // Construct from array\n            vec3(const T *tp)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = tp[i];\n                }\n            }\n\n            // Construct from explicit values\n            vec3(const T v0, const T v1, const T v2)\n            {\n                x = v0;\n                y = v1;\n                z = v2;\n            }\n\n            explicit vec3(const vec4<T> &u)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = u._array[i];\n                }\n            }\n\n            explicit vec3(const vec2<T> &u, T v0)\n            {\n                x = u.x;\n                y = u.y;\n                z = v0;\n            }\n\n            const T *get_value() const\n            {\n                return _array;\n            }\n\n            vec3<T> &set_value(const T *rhs)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = rhs[i];\n                }\n\n                return *this;\n            }\n\n            // indexing operators\n            T &operator [](int i)\n            {\n                return _array[i];\n            }\n\n            const T &operator [](int i) const\n            {\n                return _array[i];\n            }\n\n            // type-cast operators\n            operator T *()\n            {\n                return _array;\n            }\n\n            operator const T *() const\n            {\n                return _array;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Math operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // scalar multiply assign\n            friend vec3<T> &operator *= (vec3<T> &lhs, T d)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector multiply assign\n            friend vec3<T> &operator *= (vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= rhs[i];\n                }\n\n                return lhs;\n            }\n\n            // scalar divide assign\n            friend vec3<T> &operator /= (vec3<T> &lhs, T d)\n            {\n                if (d == 0)\n                {\n                    return lhs;\n                }\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector divide assign\n            friend vec3<T> &operator /= (vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector add assign\n            friend vec3<T> &operator += (vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] += rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector subtract assign\n            friend vec3<T> &operator -= (vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] -= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // unary negate\n            friend vec3<T> operator - (const vec3<T> &rhs)\n            {\n                vec3<T> rv;\n\n                for (int i = 0; i < rhs.size(); i++)\n                {\n                    rv._array[i] = -rhs._array[i];\n                }\n\n                return rv;\n            }\n\n            // vector add\n            friend vec3<T> operator + (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt += rhs;\n            }\n\n            // vector subtract\n            friend vec3<T> operator - (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt -= rhs;\n            }\n\n            // scalar multiply\n            friend vec3<T> operator * (const vec3<T> &lhs, T rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec3<T> operator * (T lhs, const vec3<T> &rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec3<T> operator * (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec3<T> operator / (const vec3<T> &lhs, T rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec3<T> operator / (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                vec3<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Comparison operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // equality\n            friend bool operator == (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            // inequality\n            friend bool operator != (const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] != rhs._array[i];\n                }\n\n                return r;\n            }\n\n            ////////////////////////////////////////////////////////////////////////////////\n            //\n            // dimension specific operations\n            //\n            ////////////////////////////////////////////////////////////////////////////////\n\n            // cross product\n            friend vec3<T> cross(const vec3<T> &lhs, const vec3<T> &rhs)\n            {\n                vec3<T> r;\n\n                r.x = lhs.y * rhs.z - lhs.z * rhs.y;\n                r.y = lhs.z * rhs.x - lhs.x * rhs.z;\n                r.z = lhs.x * rhs.y - lhs.y * rhs.x;\n\n                return r;\n            }\n\n            //data intentionally left public to allow vec2.x\n            union\n            {\n                struct\n                {\n                    T x, y, z;          // standard names for components\n                };\n                struct\n                {\n                    T s, t, r;          // standard names for components\n                };\n                T _array[3];     // array access\n            };\n    };\n\n    //////////////////////////////////////////////////////////////////////\n    //\n    // vec4 - template class for 4-tuple vector\n    //\n    //////////////////////////////////////////////////////////////////////\n    template <class T>\n    class vec4\n    {\n        public:\n\n            typedef T value_type;\n            int size() const\n            {\n                return 4;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Constructors\n            //\n            ////////////////////////////////////////////////////////\n\n            // Default/scalar constructor\n            vec4(const T &t = T())\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = t;\n                }\n            }\n\n            // Construct from array\n            vec4(const T *tp)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = tp[i];\n                }\n            }\n\n            // Construct from explicit values\n            vec4(const T v0, const T v1, const T v2, const T v3)\n            {\n                x = v0;\n                y = v1;\n                z = v2;\n                w = v3;\n            }\n\n            explicit vec4(const vec3<T> &u, T v0)\n            {\n                x = u.x;\n                y = u.y;\n                z = u.z;\n                w = v0;\n            }\n\n            explicit vec4(const vec2<T> &u, T v0, T v1)\n            {\n                x = u.x;\n                y = u.y;\n                z = v0;\n                w = v1;\n            }\n\n            const T *get_value() const\n            {\n                return _array;\n            }\n\n            vec4<T> &set_value(const T *rhs)\n            {\n                for (int i = 0; i < size(); i++)\n                {\n                    _array[i] = rhs[i];\n                }\n\n                return *this;\n            }\n\n            // indexing operators\n            T &operator [](int i)\n            {\n                return _array[i];\n            }\n\n            const T &operator [](int i) const\n            {\n                return _array[i];\n            }\n\n            // type-cast operators\n            operator T *()\n            {\n                return _array;\n            }\n\n            operator const T *() const\n            {\n                return _array;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Math operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // scalar multiply assign\n            friend vec4<T> &operator *= (vec4<T> &lhs, T d)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector multiply assign\n            friend vec4<T> &operator *= (vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] *= rhs[i];\n                }\n\n                return lhs;\n            }\n\n            // scalar divide assign\n            friend vec4<T> &operator /= (vec4<T> &lhs, T d)\n            {\n                if (d == 0)\n                {\n                    return lhs;\n                }\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= d;\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector divide assign\n            friend vec4<T> &operator /= (vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] /= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector add assign\n            friend vec4<T> &operator += (vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] += rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // component-wise vector subtract assign\n            friend vec4<T> &operator -= (vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    lhs._array[i] -= rhs._array[i];\n                }\n\n                return lhs;\n            }\n\n            // unary negate\n            friend vec4<T> operator - (const vec4<T> &rhs)\n            {\n                vec4<T> rv;\n\n                for (int i = 0; i < rhs.size(); i++)\n                {\n                    rv._array[i] = -rhs._array[i];\n                }\n\n                return rv;\n            }\n\n            // vector add\n            friend vec4<T> operator + (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt += rhs;\n            }\n\n            // vector subtract\n            friend vec4<T> operator - (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt -= rhs;\n            }\n\n            // scalar multiply\n            friend vec4<T> operator * (const vec4<T> &lhs, T rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec4<T> operator * (T lhs, const vec4<T> &rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec4<T> operator * (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt *= rhs;\n            }\n\n            // scalar multiply\n            friend vec4<T> operator / (const vec4<T> &lhs, T rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            // vector component-wise multiply\n            friend vec4<T> operator / (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                vec4<T> rt(lhs);\n                return rt /= rhs;\n            }\n\n            ////////////////////////////////////////////////////////\n            //\n            //  Comparison operators\n            //\n            ////////////////////////////////////////////////////////\n\n            // equality\n            friend bool operator == (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] == rhs._array[i];\n                }\n\n                return r;\n            }\n\n            // inequality\n            friend bool operator != (const vec4<T> &lhs, const vec4<T> &rhs)\n            {\n                bool r = true;\n\n                for (int i = 0; i < lhs.size(); i++)\n                {\n                    r &= lhs._array[i] != rhs._array[i];\n                }\n\n                return r;\n            }\n\n            //data intentionally left public to allow vec2.x\n            union\n            {\n                struct\n                {\n                    T x, y, z, w;          // standard names for components\n                };\n                struct\n                {\n                    T s, t, r, q;          // standard names for components\n                };\n                T _array[4];     // array access\n            };\n    };\n\n    ////////////////////////////////////////////////////////////////////////////////\n    //\n    // Generic vector operations\n    //\n    ////////////////////////////////////////////////////////////////////////////////\n\n    // compute the dot product of two vectors\n    template<class T>\n    inline typename T::value_type dot(const T &lhs, const T &rhs)\n    {\n        typename T::value_type r = 0;\n\n        for (int i = 0; i < lhs.size(); i++)\n        {\n            r += lhs._array[i] * rhs._array[i];\n        }\n\n        return r;\n    }\n\n    // return the length of the provided vector\n    template< class T>\n    inline typename T::value_type length(const T &vec)\n    {\n        typename T::value_type r = 0;\n\n        for (int i = 0; i < vec.size(); i++)\n        {\n            r += vec._array[i]*vec._array[i];\n        }\n\n        return typename T::value_type(sqrt(r));\n    }\n\n    // return the squared norm\n    template< class T>\n    inline typename T::value_type square_norm(const T &vec)\n    {\n        typename T::value_type r = 0;\n\n        for (int i = 0; i < vec.size(); i++)\n        {\n            r += vec._array[i]*vec._array[i];\n        }\n\n        return r;\n    }\n\n    // return the normalized version of the vector\n    template< class T>\n    inline T normalize(const T &vec)\n    {\n        typename T::value_type sum(0);\n        T r;\n\n        for (int i = 0; i < vec.size(); i++)\n        {\n            sum += vec._array[i] * vec._array[i];\n        }\n\n        sum = typename T::value_type(sqrt(sum));\n\n        if (sum > 0)\n            for (int i = 0; i < vec.size(); i++)\n            {\n                r._array[i] = vec._array[i] / sum;\n            }\n\n        return r;\n    }\n\n    // In VC8 : min and max are already defined by a #define...\n#ifdef min\n#undef min\n#endif\n#ifdef max\n#undef max\n#endif\n    //componentwise min\n    template< class T>\n    inline T min(const T &lhs, const T &rhs)\n    {\n        T rt;\n\n        for (int i = 0; i < lhs.size(); i++)\n        {\n            rt._array[i] = std::min(lhs._array[i], rhs._array[i]);\n        }\n\n        return rt;\n    }\n\n    // componentwise max\n    template< class T>\n    inline T max(const T &lhs, const T &rhs)\n    {\n        T rt;\n\n        for (int i = 0; i < lhs.size(); i++)\n        {\n            rt._array[i] = std::max(lhs._array[i], rhs._array[i]);\n        }\n\n        return rt;\n    }\n\n\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/nvrtc_helper.h",
    "content": "#if !defined(__NVRTC_HELPER__)\n\n#define __NVRTC_HELPER__ 1\n\n#include <cuda.h>\n#include <nvrtc.h>\n#include <sstream>\n#include <iostream>\n#include <fstream>\n#include <helper_cuda_drvapi.h>\n\n#define NVRTC_SAFE_CALL(Name, x)                                             \\\n  do {                                                                       \\\n    nvrtcResult result = x;                                                  \\\n    if (result != NVRTC_SUCCESS) {                                           \\\n      std::cerr << \"\\nerror: \" << Name << \" failed with error \" <<           \\\n                                               nvrtcGetErrorString(result);  \\\n      exit(1);                                                               \\\n    }                                                                        \\\n  } while(0)\n\nvoid compileFileToPTX(char *filename, int argc, char **argv,\n                      char **ptxResult, size_t *ptxResultSize, int requiresCGheaders)\n{\n    std::ifstream inputFile(filename, std::ios::in | std::ios::binary |\n                                std::ios::ate);\n\n    if (!inputFile.is_open()) \n    {\n        std::cerr << \"\\nerror: unable to open \" << filename << \" for reading!\\n\";\n        exit(1);\n    }\n\n    std::streampos pos = inputFile.tellg();\n    size_t inputSize = (size_t)pos;\n    char * memBlock = new char [inputSize + 1];\n\n    inputFile.seekg (0, std::ios::beg);\n    inputFile.read (memBlock, inputSize);\n    inputFile.close();\n    memBlock[inputSize] = '\\x0';\n\n    int numCompileOptions = 0;\n\n    char *compileParams[1];\n\n    if (requiresCGheaders)\n    {\n        std::string compileOptions;\n        char *HeaderNames = \"cooperative_groups.h\";\n\n        compileOptions = \"--include-path=\";\n\n        std::string path = sdkFindFilePath(HeaderNames, argv[0]);\n        if (!path.empty())\n        {\n            std::size_t found = path.find(HeaderNames);\n            path.erase(found);\n        }\n        else\n        {\n            printf(\"\\nCooperativeGroups headers not found, please install it in %s sample directory..\\n Exiting..\\n\", argv[0]);\n        }\n        compileOptions += path.c_str();\n        compileParams[0] = (char *) malloc(sizeof(char)* (compileOptions.length() + 1));\n        strcpy(compileParams[0], compileOptions.c_str());\n        numCompileOptions++;\n    }\n\n    // compile\n    nvrtcProgram prog;\n    NVRTC_SAFE_CALL(\"nvrtcCreateProgram\", nvrtcCreateProgram(&prog, memBlock,\n                                                     filename, 0, NULL, NULL));\n\n    nvrtcResult res = nvrtcCompileProgram(prog, numCompileOptions, compileParams);\n\n    // dump log\n    size_t logSize;\n    NVRTC_SAFE_CALL(\"nvrtcGetProgramLogSize\", nvrtcGetProgramLogSize(prog, &logSize));\n    char *log = (char *) malloc(sizeof(char) * logSize + 1);\n    NVRTC_SAFE_CALL(\"nvrtcGetProgramLog\", nvrtcGetProgramLog(prog, log));\n    log[logSize] = '\\x0';\n\n    \n    if (strlen(log) >= 2)\n    { \n        std::cerr << \"\\n compilation log ---\\n\";\n        std::cerr << log;\n        std::cerr << \"\\n end log ---\\n\";\n    }\n    \n    free(log);\n\n    NVRTC_SAFE_CALL(\"nvrtcCompileProgram\", res);\n    // fetch PTX\n    size_t ptxSize;\n    NVRTC_SAFE_CALL(\"nvrtcGetPTXSize\", nvrtcGetPTXSize(prog, &ptxSize));\n    char *ptx = (char *) malloc(sizeof(char) * ptxSize);\n    NVRTC_SAFE_CALL(\"nvrtcGetPTX\", nvrtcGetPTX(prog, ptx));\n    NVRTC_SAFE_CALL(\"nvrtcDestroyProgram\", nvrtcDestroyProgram(&prog));\n    *ptxResult = ptx;\n    *ptxResultSize = ptxSize;\n\n    if (requiresCGheaders)\n        free(compileParams[0]);\n}\n\nCUmodule loadPTX(char *ptx, int argc, char **argv)\n{\n    CUmodule module;\n    CUcontext context;\n    int major = 0, minor = 0;\n    char deviceName[256];\n\n    // Picks the best CUDA device available\n    CUdevice cuDevice = findCudaDeviceDRV(argc, (const char **)argv);\n\n    // get compute capabilities and the devicename\n    checkCudaErrors(cuDeviceComputeCapability(&major, &minor, cuDevice));\n    checkCudaErrors(cuDeviceGetName(deviceName, 256, cuDevice));\n    printf(\"> GPU Device has SM %d.%d compute capability\\n\", major, minor);\n\n    checkCudaErrors(cuInit(0));\n    checkCudaErrors(cuDeviceGet(&cuDevice, 0));\n    checkCudaErrors(cuCtxCreate(&context, 0, cuDevice));\n\n    checkCudaErrors(cuModuleLoadDataEx(&module, ptx, 0, 0, 0));\n    free(ptx);\n\n    return module;\n}\n\n#endif\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/param.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n/*\n Simple parameter system\n sgreen@nvidia.com 4/2001\n*/\n\n#ifndef PARAM_H\n#define PARAM_H\n\n#include <string>\n#include <vector>\n#include <map>\n#include <iostream>\n#include <sstream>\n#include <iomanip>\n\n// base class for named parameter\nclass ParamBase\n{\n    public:\n        ParamBase(const char *name) : m_name(name) { }\n        virtual ~ParamBase() { }\n\n        std::string &GetName()\n        {\n            return m_name;\n        }\n\n        virtual float GetFloatValue() = 0;\n        virtual int GetIntValue() = 0;\n        virtual std::string GetValueString() = 0;\n\n        virtual void Reset() = 0;\n        virtual void Increment() = 0;\n        virtual void Decrement() = 0;\n\n        virtual float GetPercentage() = 0;\n        virtual void SetPercentage(float p) = 0;\n\n        virtual void Write(std::ostream &stream) = 0;\n        virtual void Read(std::istream &stream) = 0;\n\n        virtual bool IsList() = 0;\n\n    protected:\n        std::string m_name;\n};\n\n// derived class for single-valued parameter\ntemplate<class T> class Param : public ParamBase\n{\n    public:\n        Param(const char *name, T value = 0, T min = 0, T max = 10000, T step = 1, T *ptr = 0) :\n            ParamBase(name),\n            m_default(value),\n            m_min(min),\n            m_max(max),\n            m_step(step),\n            m_precision(3)\n        {\n            if (ptr)\n            {\n                m_ptr = ptr;\n            }\n            else\n            {\n                m_ptr = &m_value;\n            }\n\n            *m_ptr = value;\n        }\n        ~Param() { }\n\n        T GetValue() const\n        {\n            return *m_ptr;\n        }\n        T SetValue(const T value)\n        {\n            *m_ptr = value;\n        }\n\n        float GetFloatValue()\n        {\n            return (float) *m_ptr;\n        }\n        int GetIntValue()\n        {\n            return (int) *m_ptr;\n        }\n\n        std::string GetValueString()\n        {\n            std::ostringstream ost;\n            ost<<std::setprecision(m_precision)<<std::fixed;\n            ost<<*m_ptr;\n            return ost.str();\n        }\n\n        void SetPrecision(int x)\n        {\n            m_precision = x;\n        }\n\n        float GetPercentage()\n        {\n            return (*m_ptr - m_min) / (float)(m_max - m_min);\n        }\n\n        void SetPercentage(float p)\n        {\n            *m_ptr = (T)(m_min + p * (m_max - m_min));\n        }\n\n        void Reset()\n        {\n            *m_ptr = m_default;\n        }\n\n        void Increment()\n        {\n            *m_ptr += m_step;\n\n            if (*m_ptr > m_max)\n            {\n                *m_ptr = m_max;\n            }\n        }\n\n        void Decrement()\n        {\n            *m_ptr -= m_step;\n\n            if (*m_ptr < m_min)\n            {\n                *m_ptr = m_min;\n            }\n        }\n\n        void Write(std::ostream &stream)\n        {\n            stream << m_name << \" \" << *m_ptr << '\\n';\n        }\n        void Read(std::istream &stream)\n        {\n            stream >> m_name >> *m_ptr;\n        }\n\n        bool IsList()\n        {\n            return false;\n        }\n\n    private:\n        T m_value;\n        T *m_ptr;         // pointer to value declared elsewhere\n        T m_default, m_min, m_max, m_step;\n        int m_precision;  // number of digits after decimal point in string output\n};\n\nconst Param<int> dummy(\"error\");\n\n// list of parameters\nclass ParamList : public ParamBase\n{\n    public:\n        ParamList(const char *name = \"\") :\n            ParamBase(name)\n        {\n            active = true;\n        }\n        ~ParamList() { }\n\n        float GetFloatValue()\n        {\n            return 0.0f;\n        }\n        int GetIntValue()\n        {\n            return 0;\n        }\n\n        void AddParam(ParamBase *param)\n        {\n            m_params.push_back(param);\n            m_map[param->GetName()] = param;\n            m_current = m_params.begin();\n        }\n\n        // look-up parameter based on name\n        ParamBase *GetParam(char *name)\n        {\n            ParamBase *p = m_map[name];\n\n            if (p)\n            {\n                return p;\n            }\n            else\n            {\n                return (ParamBase *) &dummy;\n            }\n        }\n\n        ParamBase *GetParam(int i)\n        {\n            return m_params[i];\n        }\n\n        ParamBase *GetCurrent()\n        {\n            return *m_current;\n        }\n\n        int GetSize()\n        {\n            return (int)m_params.size();\n        }\n\n        std::string GetValueString()\n        {\n            return m_name;\n        }\n\n        // functions to traverse list\n        void Reset()\n        {\n            m_current = m_params.begin();\n        }\n\n        void Increment()\n        {\n            m_current++;\n\n            if (m_current == m_params.end())\n            {\n                m_current = m_params.begin();\n            }\n        }\n\n        void Decrement()\n        {\n            if (m_current == m_params.begin())\n            {\n                m_current = m_params.end()-1;\n            }\n            else\n            {\n                m_current--;\n            }\n\n        }\n\n        float GetPercentage()\n        {\n            return 0.0f;\n        }\n        void SetPercentage(float /*p*/) {}\n\n        void Write(std::ostream &stream)\n        {\n            stream << m_name << '\\n';\n\n            for (std::vector<ParamBase *>::const_iterator p = m_params.begin(); p != m_params.end(); ++p)\n            {\n                (*p)->Write(stream);\n            }\n        }\n\n        void Read(std::istream &stream)\n        {\n            stream >> m_name;\n\n            for (std::vector<ParamBase *>::const_iterator p = m_params.begin(); p != m_params.end(); ++p)\n            {\n                (*p)->Read(stream);\n            }\n        }\n\n        bool IsList()\n        {\n            return true;\n        }\n\n        void ResetAll()\n        {\n            for (std::vector<ParamBase *>::const_iterator p = m_params.begin(); p != m_params.end(); ++p)\n            {\n                (*p)->Reset();\n            }\n        }\n\n    protected:\n        bool active;\n        std::vector<ParamBase *> m_params;\n        std::map<std::string, ParamBase *> m_map;\n        std::vector<ParamBase *>::const_iterator m_current;\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/paramgl.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n/*\n   ParamListGL\n   - class derived from ParamList to do simple OpenGL rendering of a parameter list\n   sgg 8/2001\n*/\n\n#ifndef PARAMGL_H\n#define PARAMGL_H\n\n#if defined(__APPLE__) || defined(MACOSX)\n#include <GLUT/glut.h>\n#else\n#include <GL/freeglut.h>\n#endif\n\n#include <string.h>\n#include <param.h>\n\ninline void beginWinCoords(void)\n{\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n    glTranslatef(0.0, (GLfloat)(glutGet(GLUT_WINDOW_HEIGHT) - 1.0), 0.0);\n    glScalef(1.0, -1.0, 1.0);\n\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glOrtho(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT), -1, 1);\n\n    glMatrixMode(GL_MODELVIEW);\n}\n\ninline void endWinCoords(void)\n{\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n}\n\ninline void glPrint(int x, int y, const char *s, void *font)\n{\n    glRasterPos2f((GLfloat)x, (GLfloat)y);\n    int len = (int) strlen(s);\n\n    for (int i = 0; i < len; i++)\n    {\n        glutBitmapCharacter(font, s[i]);\n    }\n}\n\ninline void glPrintShadowed(int x, int y, const char *s, void *font, float *color)\n{\n    glColor3f(0.0, 0.0, 0.0);\n    glPrint(x-1, y-1, s, font);\n\n    glColor3fv((GLfloat *) color);\n    glPrint(x, y, s, font);\n}\n\nclass ParamListGL : public ParamList\n{\n    public:\n        ParamListGL(const char *name = \"\") :\n            ParamList(name),\n            m_active(true),\n            m_text_color_selected(1.0, 1.0, 1.0),\n            m_text_color_unselected(0.75, 0.75, 0.75),\n            m_text_color_shadow(0.0, 0.0, 0.0),\n            m_bar_color_outer(0.25, 0.25, 0.25),\n            m_bar_color_inner(1.0, 1.0, 1.0)\n        {\n            m_font = (void *) GLUT_BITMAP_9_BY_15; // GLUT_BITMAP_8_BY_13;\n            m_font_h = 15;\n            m_bar_x = 260;\n            m_bar_w = 250;\n            m_bar_h = 10;\n            m_bar_offset = 5;\n            m_text_x = 5;\n            m_separation = 15;\n            m_value_x = 200;\n            m_start_x = 0;\n            m_start_y = 0;\n        }\n\n        void Render(int x, int y, bool shadow = false)\n        {\n            beginWinCoords();\n\n            m_start_x = x;\n            m_start_y = y;\n\n            for (std::vector<ParamBase *>::const_iterator p = m_params.begin(); p != m_params.end(); ++p)\n            {\n                if ((*p)->IsList())\n                {\n                    ParamListGL *list = (ParamListGL *)(*p);\n                    list->Render(x+10, y);\n                    y += m_separation*list->GetSize();\n                }\n                else\n                {\n                    if (p == m_current)\n                    {\n                        glColor3fv(&m_text_color_selected.r);\n                    }\n                    else\n                    {\n                        glColor3fv(&m_text_color_unselected.r);\n                    }\n\n                    if (shadow)\n                    {\n                        glPrintShadowed(x + m_text_x, y + m_font_h, (*p)->GetName().c_str(), m_font, (p == m_current) ? &m_text_color_selected.r : &m_text_color_unselected.r);\n                        glPrintShadowed(x + m_value_x, y + m_font_h, (*p)->GetValueString().c_str(), m_font, (p == m_current) ? &m_text_color_selected.r : &m_text_color_unselected.r);\n                    }\n                    else\n                    {\n                        glPrint(x + m_text_x, y + m_font_h, (*p)->GetName().c_str(), m_font);\n                        glPrint(x + m_value_x, y + m_font_h, (*p)->GetValueString().c_str(), m_font);\n                    }\n\n                    glColor3fv((GLfloat *) &m_bar_color_outer.r);\n                    glBegin(GL_LINE_LOOP);\n                    glVertex2f((GLfloat)(x + m_bar_x)          , (GLfloat)(y + m_bar_offset));\n                    glVertex2f((GLfloat)(x + m_bar_x + m_bar_w), (GLfloat)(y + m_bar_offset));\n                    glVertex2f((GLfloat)(x + m_bar_x + m_bar_w), (GLfloat)(y + m_bar_offset + m_bar_h));\n                    glVertex2f((GLfloat)(x + m_bar_x)          , (GLfloat)(y + m_bar_offset + m_bar_h));\n                    glEnd();\n\n                    glColor3fv((GLfloat *) &m_bar_color_inner.r);\n                    glRectf((GLfloat)(x + m_bar_x), (GLfloat)(y + m_bar_offset + m_bar_h), (GLfloat)(x + m_bar_x + ((m_bar_w-1)*(*p)->GetPercentage())), (GLfloat)(y + m_bar_offset + 1));\n\n                    y += m_separation;\n                }\n            }\n\n            endWinCoords();\n        }\n\n        bool Mouse(int x, int y, int button=GLUT_LEFT_BUTTON, int state=GLUT_DOWN)\n        {\n            if ((y < m_start_y) || (y > (int)(m_start_y + (m_separation * m_params.size()) - 1)))\n            {\n                m_active = false;\n                return false;\n            }\n\n            m_active = true;\n\n            int i = (y - m_start_y) / m_separation;\n\n            if ((button==GLUT_LEFT_BUTTON) && (state==GLUT_DOWN))\n            {\n#if defined(__GNUC__) && (__GNUC__ < 3)\n                m_current = &m_params[i];\n#else\n\n                // MJH: workaround since the version of vector::at used here is non-standard\n                for (m_current = m_params.begin(); m_current != m_params.end() && i > 0; m_current++, i--) ;\n\n                //m_current = (std::vector<ParamBase *>::const_iterator)&m_params.at(i);\n#endif\n\n                if ((x > m_bar_x) && (x < m_bar_x + m_bar_w))\n                {\n                    Motion(x, y);\n                }\n            }\n\n            return true;\n        }\n\n        bool Motion(int x, int y)\n        {\n            if ((y < m_start_y) || (y > m_start_y + (m_separation * (int)m_params.size()) - 1))\n            {\n                return false;\n            }\n\n            if (x < m_bar_x)\n            {\n                (*m_current)->SetPercentage(0.0);\n                return true;\n            }\n\n            if (x > m_bar_x + m_bar_w)\n            {\n                (*m_current)->SetPercentage(1.0);\n                return true;\n            }\n\n            (*m_current)->SetPercentage((x-m_bar_x) / (float) m_bar_w);\n            return true;\n        }\n\n        void Special(int key, int x, int y)\n        {\n            if (!m_active)\n                return;\n\n            switch (key)\n            {\n                case GLUT_KEY_DOWN:\n                    Increment();\n                    break;\n\n                case GLUT_KEY_UP:\n                    Decrement();\n                    break;\n\n                case GLUT_KEY_RIGHT:\n                    GetCurrent()->Increment();\n                    break;\n\n                case GLUT_KEY_LEFT:\n                    GetCurrent()->Decrement();\n                    break;\n\n                case GLUT_KEY_HOME:\n                    GetCurrent()->Reset();\n                    break;\n\n                case GLUT_KEY_END:\n                    GetCurrent()->SetPercentage(1.0);\n                    break;\n            }\n\n            glutPostRedisplay();\n        }\n\n        void SetFont(void *font, int height)\n        {\n            m_font = font;\n            m_font_h = height;\n        }\n\n        void SetSelectedColor(float r, float g, float b)\n        {\n            m_text_color_selected = Color(r, g, b);\n        }\n        void SetUnSelectedColor(float r, float g, float b)\n        {\n            m_text_color_unselected = Color(r, g, b);\n        }\n        void SetBarColorInner(float r, float g, float b)\n        {\n            m_bar_color_inner = Color(r, g, b);\n        }\n        void SetBarColorOuter(float r, float g, float b)\n        {\n            m_bar_color_outer = Color(r, g, b);\n        }\n\n        void SetActive(bool b)\n        {\n            m_active = b;\n        }\n\n    private:\n        void *m_font;\n        int m_font_h;       // font height\n\n        int m_bar_x;        // bar start x position\n        int m_bar_w;        // bar width\n        int m_bar_h;        // bar height\n        int m_text_x;       // text start x position\n        int m_separation;   // bar separation in y\n        int m_value_x;      // value text x position\n        int m_bar_offset;   // bar offset in y\n\n        int m_start_x, m_start_y;\n\n        bool m_active;\n\n        struct Color\n        {\n            Color(float _r, float _g, float _b)\n            {\n                r = _r;\n                g = _g;\n                b = _b;\n            }\n            float r, g, b;\n        };\n\n        Color m_text_color_selected;\n        Color m_text_color_unselected;\n        Color m_text_color_shadow;\n        Color m_bar_color_outer;\n        Color m_bar_color_inner;\n};\n\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/rendercheck_d3d10.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#pragma once\n\n#ifndef _RENDERCHECK_D3D10_H_\n#define _RENDERCHECK_D3D10_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <d3d10.h>\n#include <d3dx10.h>\n\nclass CheckRenderD3D10\n{\n    public:\n\n        CheckRenderD3D10() {}\n\n        static HRESULT ActiveRenderTargetToPPM(ID3D10Device  *pDevice, const char *zFileName);\n        static HRESULT ResourceToPPM(ID3D10Device *pDevice, ID3D10Resource *pResource, const char *zFileName);\n\n        static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path,\n                             const float epsilon, const float threshold = 0.0f);\n};\n\n#endif"
  },
  {
    "path": "tests/projects/cuda/console/inc/rendercheck_d3d11.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#pragma once\n\n#ifndef _RENDERCHECK_D3D11_H_\n#define _RENDERCHECK_D3D11_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <d3d11.h>\n#include <d3dx11.h>\n\nclass CheckRenderD3D11\n{\n    public:\n\n        CheckRenderD3D11() {}\n\n        static HRESULT ActiveRenderTargetToPPM(ID3D11Device  *pDevice, const char *zFileName);\n        static HRESULT ResourceToPPM(ID3D11Device *pDevice, ID3D11Resource *pResource, const char *zFileName);\n\n        static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path,\n                             const float epsilon, const float threshold = 0.0f);\n};\n\n#endif"
  },
  {
    "path": "tests/projects/cuda/console/inc/rendercheck_d3d9.h",
    "content": "/*\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#pragma once\n\n#ifndef _RENDERCHECK_D3D9_H_\n#define _RENDERCHECK_D3D9_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <d3d9.h>\n\nclass CheckRenderD3D9\n{\n    public:\n\n        CheckRenderD3D9() {}\n\n        static HRESULT BackbufferToPPM(IDirect3DDevice9 *pDevice, const char *zFileName);\n        static HRESULT SurfaceToPPM(IDirect3DDevice9 *pDevice, IDirect3DSurface9 *pSurface, const char *zFileName);\n\n        static bool PPMvsPPM(const char *src_file, const char *ref_file, const char *exec_path,\n                             const float epsilon, const float threshold = 0.0f);\n};\n\n#endif"
  },
  {
    "path": "tests/projects/cuda/console/inc/rendercheck_gl.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n\n#ifndef _RENDERCHECK_GL_H_\n#define _RENDERCHECK_GL_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <vector>\n#include <map>\n#include <string>\n\n#if defined(__APPLE__) || defined(MACOSX)\n#include <GLUT/glut.h>\n#else\n#include <GL/freeglut.h>\n#endif\n\n#include <nvShaderUtils.h>\n\n#include <helper_image.h>\n\n\nusing std::vector;\nusing std::map;\nusing std::string;\n\n#define BUFFER_OFFSET(i) ((char *)NULL + (i))\n\n#if _DEBUG\n#define CHECK_FBO     checkStatus(__FILE__, __LINE__, true)\n#else\n#define CHECK_FBO     true\n#endif\n\n\n\nclass CheckRender\n{\n    public:\n        CheckRender(unsigned int width, unsigned int height, unsigned int Bpp,\n                    bool bQAReadback, bool bUseFBO, bool bUsePBO) :\n            m_Width(width), m_Height(height), m_Bpp(Bpp), m_bQAReadback(bQAReadback),\n            m_bUseFBO(bUseFBO), m_bUsePBO(bUsePBO), m_PixelFormat(GL_BGRA), m_fThresholdCompare(0.0f)\n        {\n            allocateMemory(width, height, Bpp, bUseFBO, bUsePBO);\n        }\n\n        virtual ~CheckRender()\n        {\n            // Release PBO resources\n            if (m_bUsePBO)\n            {\n                glDeleteBuffers(1, &m_pboReadback);\n                m_pboReadback = 0;\n            }\n\n            free(m_pImageData);\n        }\n\n        virtual void allocateMemory(unsigned int width, unsigned int height, unsigned int Bpp,\n                                    bool bUseFBO, bool bUsePBO)\n        {\n            // Create the PBO for readbacks\n            if (bUsePBO)\n            {\n                glGenBuffers(1, &m_pboReadback);\n                glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, m_pboReadback);\n                glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width*height*Bpp, NULL, GL_STREAM_READ);\n                glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\n            }\n\n            m_pImageData = (unsigned char *)malloc(width*height*Bpp);  // This is the image data stored in system memory\n        }\n\n\n        virtual void setExecPath(char *path)\n        {\n            m_ExecPath = path;\n        }\n        virtual void EnableQAReadback(bool bStatus)\n        {\n            m_bQAReadback = bStatus;\n        }\n        virtual bool IsQAReadback()\n        {\n            return m_bQAReadback;\n        }\n        virtual bool IsFBO()\n        {\n            return m_bUseFBO;\n        }\n        virtual bool IsPBO()\n        {\n            return m_bUsePBO;\n        }\n        virtual void *imageData()\n        {\n            return m_pImageData;\n        }\n\n        // Interface to this class functions\n        virtual void setPixelFormat(GLenum format)\n        {\n            m_PixelFormat = format;\n        }\n        virtual int  getPixelFormat()\n        {\n            return m_PixelFormat;\n        }\n        virtual bool checkStatus(const char *zfile, int line, bool silent) = 0;\n        virtual bool readback(GLuint width, GLuint height) = 0;\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject) = 0;\n        virtual bool readback(GLuint width, GLuint height, unsigned char *membuf) = 0;\n\n        virtual void bindReadback()\n        {\n            if (!m_bQAReadback)\n            {\n                printf(\"CheckRender::bindReadback() uninitialized!\\n\");\n                return;\n            }\n\n            if (m_bUsePBO)\n            {\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, m_pboReadback);   // Bind the PBO\n            }\n        }\n\n        virtual void unbindReadback()\n        {\n            if (!m_bQAReadback)\n            {\n                printf(\"CheckRender::unbindReadback() uninitialized!\\n\");\n                return;\n            }\n\n            if (m_bUsePBO)\n            {\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);   // Release the bind on the PBO\n            }\n        }\n\n        virtual void savePGM(const char *zfilename, bool bInvert, void **ppReadBuf)\n        {\n            if (zfilename != NULL)\n            {\n                if (bInvert)\n                {\n                    unsigned char *readBuf;\n                    unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height);\n\n                    for (unsigned int y=0; y < m_Height; y++)\n                    {\n                        if (ppReadBuf)\n                        {\n                            readBuf = *(unsigned char **)ppReadBuf;\n                        }\n                        else\n                        {\n                            readBuf = (unsigned char *)m_pImageData;\n                        }\n\n                        memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*(m_Height-1-y)), m_Width);\n                    }\n\n                    // we copy the results back to original system buffer\n                    if (ppReadBuf)\n                    {\n                        memcpy(*ppReadBuf, writeBuf, m_Width*m_Height);\n                    }\n                    else\n                    {\n                        memcpy(m_pImageData, writeBuf, m_Width*m_Height);\n                    }\n\n                    free(writeBuf);\n                }\n\n                printf(\"> Saving PGM: <%s>\\n\", zfilename);\n\n                if (ppReadBuf)\n                {\n                    sdkSavePGM<unsigned char>(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height);\n                }\n                else\n                {\n                    sdkSavePGM<unsigned char>(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height);\n                }\n            }\n        }\n\n        virtual void savePPM(const char *zfilename, bool bInvert, void **ppReadBuf)\n        {\n            if (zfilename != NULL)\n            {\n                if (bInvert)\n                {\n                    unsigned char *readBuf;\n                    unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height * m_Bpp);\n\n                    for (unsigned int y=0; y < m_Height; y++)\n                    {\n                        if (ppReadBuf)\n                        {\n                            readBuf = *(unsigned char **)ppReadBuf;\n                        }\n                        else\n                        {\n                            readBuf = (unsigned char *)m_pImageData;\n                        }\n\n                        memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*m_Bpp*(m_Height-1-y)), m_Width*m_Bpp);\n                    }\n\n                    // we copy the results back to original system buffer\n                    if (ppReadBuf)\n                    {\n                        memcpy(*ppReadBuf, writeBuf, m_Width*m_Height*m_Bpp);\n                    }\n                    else\n                    {\n                        memcpy(m_pImageData, writeBuf, m_Width*m_Height*m_Bpp);\n                    }\n\n                    free(writeBuf);\n                }\n\n                printf(\"> Saving PPM: <%s>\\n\", zfilename);\n\n                if (ppReadBuf)\n                {\n                    sdkSavePPM4ub(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height);\n                }\n                else\n                {\n                    sdkSavePPM4ub(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height);\n                }\n            }\n        }\n\n        virtual bool PGMvsPGM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f)\n        {\n            unsigned char *src_data = NULL, *ref_data = NULL;\n            unsigned long error_count = 0;\n            unsigned int width, height;\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"CheckRender::PGMvsPGM unable to find <%s> in <%s> Aborting comparison!\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n            }\n            else\n            {\n\n                if (src_file == NULL || ref_file_path == NULL)\n                {\n                    printf(\"PGMvsPGM: Aborting comparison\\n\");\n                    return false;\n                }\n\n                printf(\"   src_file <%s>\\n\", src_file);\n                printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                if (sdkLoadPPMub(ref_file_path, &ref_data, &width, &height) != true)\n                {\n                    printf(\"PGMvsPGM: unable to load ref image file: %s\\n\", ref_file_path);\n                    return false;\n                }\n\n                if (sdkLoadPPMub(src_file, &src_data, &width, &height) != true)\n                {\n                    printf(\"PGMvsPGM: unable to load src image file: %s\\n\", src_file);\n                    return false;\n                }\n\n                printf(\"PGMvsPGM: comparing images size (%d,%d) epsilon(%2.4f), threshold(%4.2f%%)\\n\", m_Height, m_Width, epsilon, threshold*100);\n\n                if (compareDataAsFloatThreshold<unsigned char, float>(ref_data, src_data, m_Height*m_Width, epsilon, threshold) == false)\n                {\n                    error_count = 1;\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n        virtual bool PPMvsPPM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f)\n        {\n            unsigned long error_count = 0;\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"CheckRender::PPMvsPPM unable to find <%s> in <%s> Aborting comparison!\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n            }\n\n            if (src_file == NULL || ref_file_path == NULL)\n            {\n                printf(\"PPMvsPPM: Aborting comparison\\n\");\n                return false;\n            }\n\n            printf(\"   src_file <%s>\\n\", src_file);\n            printf(\"   ref_file <%s>\\n\", ref_file_path);\n            return (sdkComparePPM(src_file, ref_file_path, epsilon, threshold, true) == true ? true : false);\n        }\n\n\n        void    setThresholdCompare(float value)\n        {\n            m_fThresholdCompare = value;\n        }\n\n        virtual void dumpBin(void *data, unsigned int bytes, const char *filename)\n        {\n            FILE *fp;\n            printf(\"CheckRender::dumpBin: <%s>\\n\", filename);\n            FOPEN(fp, filename, \"wb\");\n            fwrite(data, bytes, 1, fp);\n            fflush(fp);\n            fclose(fp);\n        }\n\n        virtual bool compareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold)\n        {\n            unsigned int *src_buffer, *ref_buffer;\n            FILE *src_fp = NULL, *ref_fp = NULL;\n\n            unsigned long error_count = 0;\n            size_t fsize = 0;\n\n            FOPEN(src_fp, src_file, \"rb\");\n\n            if (src_fp == NULL)\n            {\n                printf(\"compareBin2Bin <unsigned int> unable to open src_file: %s\\n\", src_file);\n                error_count++;\n            }\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"compareBin2Bin <unsigned int>  unable to find <%s> in <%s>\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n\n                if (src_fp)\n                {\n                    fclose(src_fp);\n                }\n\n                if (ref_fp)\n                {\n                    fclose(ref_fp);\n                }\n            }\n            else\n            {\n                FOPEN(ref_fp, ref_file_path, \"rb\");\n\n                if (ref_fp == NULL)\n                {\n                    printf(\"compareBin2Bin <unsigned int>  unable to open ref_file: %s\\n\", ref_file_path);\n                    error_count++;\n                }\n\n                if (src_fp && ref_fp)\n                {\n                    src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n                    ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n\n                    fsize = fread(src_buffer, sizeof(unsigned int), nelements, src_fp);\n\n                    if (fsize != nelements)\n                    {\n                        printf(\"compareBin2Bin <unsigned int>  failed to read %u elements from %s\\n\", nelements, src_file);\n                        error_count++;\n                    }\n\n                    fsize = fread(ref_buffer, sizeof(unsigned int), nelements, ref_fp);\n\n                    if (fsize == 0)\n                    {\n                        printf(\"compareBin2Bin <unsigned int>  failed to read %u elements from %s\\n\", nelements, ref_file_path);\n                        error_count++;\n                    }\n\n\n                    printf(\"> compareBin2Bin <unsigned int> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n                    printf(\"   src_file <%s>\\n\", src_file);\n                    printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                    if (!compareData<unsigned int, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n                    {\n                        error_count++;\n                    }\n\n                    fclose(src_fp);\n                    fclose(ref_fp);\n\n                    free(src_buffer);\n                    free(ref_buffer);\n                }\n                else\n                {\n                    if (src_fp)\n                    {\n                        fclose(src_fp);\n                    }\n\n                    if (ref_fp)\n                    {\n                        fclose(ref_fp);\n                    }\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n        virtual bool compareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold)\n        {\n            float *src_buffer, *ref_buffer;\n            FILE *src_fp = NULL, *ref_fp = NULL;\n            size_t fsize = 0;\n\n            unsigned long error_count = 0;\n\n            FOPEN(src_fp, src_file, \"rb\");\n\n            if (src_fp == NULL)\n            {\n                printf(\"compareBin2Bin <float> unable to open src_file: %s\\n\", src_file);\n                error_count = 1;\n            }\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"compareBin2Bin <float> unable to find <%s> in <%s>\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", m_ExecPath.c_str());\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n\n                if (src_fp)\n                {\n                    fclose(src_fp);\n                }\n\n                if (ref_fp)\n                {\n                    fclose(ref_fp);\n                }\n            }\n            else\n            {\n                FOPEN(ref_fp, ref_file_path, \"rb\");\n\n                if (ref_fp == NULL)\n                {\n                    printf(\"compareBin2Bin <float> unable to open ref_file: %s\\n\", ref_file_path);\n                    error_count = 1;\n                }\n\n                if (src_fp && ref_fp)\n                {\n                    src_buffer = (float *)malloc(nelements*sizeof(float));\n                    ref_buffer = (float *)malloc(nelements*sizeof(float));\n\n                    fsize = fread(src_buffer, sizeof(float), nelements, src_fp);\n\n                    if (fsize != nelements)\n                    {\n                        printf(\"compareBin2Bin <float>  failed to read %u elements from %s\\n\", nelements, src_file);\n                        error_count++;\n                    }\n\n                    fsize = fread(ref_buffer, sizeof(float), nelements, ref_fp);\n\n                    if (fsize == 0)\n                    {\n                        printf(\"compareBin2Bin <float>  failed to read %u elements from %s\\n\", nelements, ref_file_path);\n                        error_count++;\n                    }\n\n                    printf(\"> compareBin2Bin <float> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n                    printf(\"   src_file <%s>\\n\", src_file);\n                    printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                    if (!compareDataAsFloatThreshold<float, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n                    {\n                        error_count++;\n                    }\n\n                    fclose(src_fp);\n                    fclose(ref_fp);\n\n                    free(src_buffer);\n                    free(ref_buffer);\n                }\n                else\n                {\n                    if (src_fp)\n                    {\n                        fclose(src_fp);\n                    }\n\n                    if (ref_fp)\n                    {\n                        fclose(ref_fp);\n                    }\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n\n    protected:\n        unsigned int  m_Width, m_Height, m_Bpp;\n        unsigned char *m_pImageData;  // This is the image data stored in system memory\n        bool          m_bQAReadback, m_bUseFBO, m_bUsePBO;\n        GLuint        m_pboReadback;\n        GLenum        m_PixelFormat;\n        float         m_fThresholdCompare;\n        string        m_ExecPath;\n};\n\n\nclass CheckBackBuffer : public CheckRender\n{\n    public:\n        CheckBackBuffer(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseOpenGL = true) :\n            CheckRender(width, height, Bpp, false, false, bUseOpenGL)\n        {\n        }\n\n        virtual ~CheckBackBuffer()\n        {\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum nErrorCode = glGetError();\n\n            if (nErrorCode != GL_NO_ERROR)\n            {\n                if (!silent)\n                {\n                    printf(\"Assertion failed(%s,%d): %s\\n\", zfile, line, gluErrorString(nErrorCode));\n                }\n            }\n\n            return true;\n        }\n\n        virtual bool readback(GLuint width, GLuint height)\n        {\n            bool ret = false;\n\n            if (m_bUsePBO)\n            {\n                // binds the PBO for readback\n                bindReadback();\n\n                // Initiate the readback BLT from BackBuffer->PBO->membuf\n                glReadPixels(0, 0, width, height, getPixelFormat(),      GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                ret = checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckBackBuffer::glReadPixels() checkStatus = %d\\n\", ret);\n                }\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n                memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                // release the PBO\n                unbindReadback();\n            }\n            else\n            {\n                // reading direct from the backbuffer\n                glReadBuffer(GL_FRONT);\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n            }\n\n            return ret;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject)\n        {\n            bool ret = false;\n\n            if (m_bUseFBO)\n            {\n                if (m_bUsePBO)\n                {\n                    printf(\"CheckBackBuffer::readback() FBO->PBO->m_pImageData\\n\");\n                    // binds the PBO for readback\n                    bindReadback();\n\n                    // bind FBO buffer (we want to transfer FBO -> PBO)\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject);\n\n                    // Now initiate the readback to PBO\n                    glReadPixels(0, 0, width, height, getPixelFormat(),      GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                    }\n\n                    // map - unmap simulates readback without the copy\n                    void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n                    memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                    glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                    // release the FBO\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n\n                    // release the PBO\n                    unbindReadback();\n                }\n                else\n                {\n                    printf(\"CheckBackBuffer::readback() FBO->m_pImageData\\n\");\n                    // Reading direct to FBO using glReadPixels\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject);\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\\n\", bufObject, ret);\n                    }\n\n                    glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT));\n                    ret &= checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback::glReadBuffer() fbo=%d checkStatus = %d\\n\", bufObject, ret);\n                    }\n\n                    glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n                }\n            }\n            else\n            {\n\n                printf(\"CheckBackBuffer::readback() PBO->m_pImageData\\n\");\n                // read from bufObject (PBO) to system memorys image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject);   // Bind the PBO\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n\n                // allocate a buffer so we can flip the image\n                unsigned char *temp_buf = (unsigned char *)malloc(width*height*m_Bpp);\n                memcpy(temp_buf, ioMem, width*height*m_Bpp);\n\n                // let's flip the image as we copy\n                for (unsigned int y = 0; y < height; y++)\n                {\n                    memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(temp_buf[y*width*m_Bpp]), width*m_Bpp);\n                }\n\n                free(temp_buf);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                // read from bufObject (PBO) to system memory image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);   // unBind the PBO\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf)\n        {\n            // let's flip the image as we copy\n            for (unsigned int y = 0; y < height; y++)\n            {\n                memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp);\n            }\n\n            return true;\n        }\n\n    private:\n        virtual void bindFragmentProgram() {};\n        virtual void bindRenderPath() {};\n        virtual void unbindRenderPath() {};\n\n        // bind to the BackBuffer to Texture\n        virtual void bindTexture() {};\n\n        // release this bind\n        virtual void unbindTexture() {};\n};\n\n\n// structure defining the properties of a single buffer\nstruct bufferConfig\n{\n    string name;\n    GLenum format;\n    int bits;\n};\n\n// structures defining properties of an FBO\nstruct fboConfig\n{\n    string name;\n    GLenum colorFormat;\n    GLenum depthFormat;\n    int redbits;\n    int depthBits;\n    int depthSamples;\n    int coverageSamples;\n};\n\nstruct fboData\n{\n    GLuint colorTex; //color texture\n    GLuint depthTex; //depth texture\n    GLuint fb;      // render framebuffer\n    GLuint resolveFB; //multisample resolve target\n    GLuint colorRB; //color render buffer\n    GLuint depthRB; // depth render buffer\n};\n\n\nclass CFrameBufferObject\n{\n    public:\n        CFrameBufferObject(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFloat, GLenum eTarget) :\n            m_Width(width),\n            m_Height(height),\n            m_bUseFloat(bUseFloat),\n            m_eGLTarget(eTarget)\n        {\n            glGenFramebuffersEXT(1, &m_fboData.fb);\n\n            m_fboData.colorTex = createTexture(m_eGLTarget, width, height,\n                                               (bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8), GL_RGBA);\n\n            m_fboData.depthTex = createTexture(m_eGLTarget, width, height,\n                                               GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT);\n\n            attachTexture(m_eGLTarget, m_fboData.colorTex,   GL_COLOR_ATTACHMENT0_EXT);\n            attachTexture(m_eGLTarget, m_fboData.depthTex,   GL_DEPTH_ATTACHMENT_EXT);\n\n            //    bool ret = checkStatus(__FILE__, __LINE__, true);\n        }\n\n        virtual ~CFrameBufferObject()\n        {\n            //   freeResources();\n        }\n\n        GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format)\n        {\n            GLuint texid;\n            glGenTextures(1, &texid);\n            glBindTexture(target, texid);\n\n            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n            glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0);\n            return texid;\n        }\n\n        void    attachTexture(GLenum texTarget,\n                              GLuint texId,\n                              GLenum attachment   = GL_COLOR_ATTACHMENT0_EXT,\n                              int mipLevel        = 0,\n                              int zSlice          = 0)\n        {\n            bindRenderPath();\n\n            switch (texTarget)\n            {\n                case GL_TEXTURE_1D:\n                    glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment,\n                                              GL_TEXTURE_1D, texId, mipLevel);\n                    break;\n\n                case GL_TEXTURE_3D:\n                    glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment,\n                                              GL_TEXTURE_3D, texId, mipLevel, zSlice);\n                    break;\n\n                default:\n                    // Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces\n                    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,\n                                              texTarget, texId, mipLevel);\n                    break;\n            }\n\n            unbindRenderPath();\n        }\n\n        bool initialize(unsigned width, unsigned height, fboConfig &rConfigFBO, fboData &rActiveFBO)\n        {\n            //Framebuffer config options\n            vector<bufferConfig> colorConfigs;\n            vector<bufferConfig> depthConfigs;\n            bufferConfig temp;\n\n            //add default color configs\n            temp.name   = (m_bUseFloat ? \"RGBA32F\" : \"RGBA8\");\n            temp.bits   = (m_bUseFloat ? 32 : 8);\n            temp.format = (m_bUseFloat ? GL_RGBA32F_ARB : GL_RGBA8);\n            colorConfigs.push_back(temp);\n\n            //add default depth configs\n            temp.name = \"D24\";\n            temp.bits = 24;\n            temp.format = GL_DEPTH_COMPONENT24;\n            depthConfigs.push_back(temp);\n\n            // If the FBO can be created, add it to the list of available configs, and make a menu entry\n            string root = colorConfigs[0].name + \" \" + depthConfigs[0].name;\n\n            rConfigFBO.colorFormat  = colorConfigs[0].format;\n            rConfigFBO.depthFormat  = depthConfigs[0].format;\n            rConfigFBO.redbits      = colorConfigs[0].bits;\n            rConfigFBO.depthBits    = depthConfigs[0].bits;\n\n            //single sample\n            rConfigFBO.name             = root;\n            rConfigFBO.coverageSamples  = 0;\n            rConfigFBO.depthSamples     = 0;\n\n            create(width, height, rConfigFBO, rActiveFBO);\n\n            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n\n            if (m_bUseFloat)\n            {\n                // load fragment programs\n                const char *strTextureProgram2D =\n                    \"!!ARBfp1.0\\n\"\n                    \"TEX result.color, fragment.texcoord[0], texture[0], 2D;\\n\"\n                    \"END\\n\";\n\n                m_textureProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strTextureProgram2D);\n\n                const char *strOverlayProgram =\n                    \"!!ARBfp1.0\\n\"\n                    \"TEMP t;\\n\"\n                    \"TEX t, fragment.texcoord[0], texture[0], 2D;\\n\"\n                    \"MOV result.color, t;\\n\"\n                    \"END\\n\";\n\n                m_overlayProgram = nv::CompileASMShader(GL_FRAGMENT_PROGRAM_ARB, strOverlayProgram);\n            }\n\n            return CHECK_FBO;\n        }\n\n        bool create(GLuint width, GLuint height, fboConfig &config, fboData &data)\n        {\n            bool multisample = config.depthSamples > 0;\n            bool ret = true;\n            GLint query;\n\n            printf(\"\\nCreating FBO <%s> (%dx%d) Float:%s\\n\", config.name.c_str(), (int)width, (int)height, (m_bUseFloat ? \"Y\":\"N\"));\n\n            glGenFramebuffersEXT(1, &data.fb);\n            glGenTextures(1, &data.colorTex);\n\n            // init texture\n            glBindTexture(m_eGLTarget, data.colorTex);\n            glTexImage2D(m_eGLTarget, 0, config.colorFormat,\n                         width, height, 0, GL_RGBA,\n                         (m_bUseFloat ? GL_FLOAT : GL_UNSIGNED_BYTE),\n                         NULL);\n\n            glGenerateMipmapEXT(m_eGLTarget);\n\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // GL_LINEAR_MIPMAP_LINEAR);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // GL_LINEAR);\n\n            {\n                glGenTextures(1, &data.depthTex);\n                data.depthRB = 0;\n                data.colorRB = 0;\n                data.resolveFB = 0;\n\n                //non-multisample, so bind things directly to the FBO\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb);\n                glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_eGLTarget, data.colorTex, 0);\n\n                glBindTexture(m_eGLTarget, data.depthTex);\n                glTexImage2D(m_eGLTarget, 0, config.depthFormat,\n                             width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);\n\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // GL_LINEAR);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // GL_LINEAR);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n                glTexParameterf(m_eGLTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);\n\n                glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_eGLTarget, data.depthTex, 0);\n\n                ret &= checkStatus(__FILE__, __LINE__, true);\n            }\n\n            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.fb);\n            glGetIntegerv(GL_RED_BITS, &query);\n\n            if (query != config.redbits)\n            {\n                ret = false;\n            }\n\n            glGetIntegerv(GL_DEPTH_BITS, &query);\n\n            if (query != config.depthBits)\n            {\n                ret = false;\n            }\n\n            if (multisample)\n            {\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, data.resolveFB);\n                glGetIntegerv(GL_RED_BITS, &query);\n\n                if (query != config.redbits)\n                {\n                    ret = false;\n                }\n            }\n\n            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n\n            ret &= checkStatus(__FILE__, __LINE__, true);\n\n            return ret;\n        }\n\n        virtual void freeResources()\n        {\n            if (m_fboData.fb)\n            {\n                glDeleteFramebuffersEXT(1, &m_fboData.fb);\n            }\n\n            if (m_fboData.resolveFB)\n            {\n                glDeleteFramebuffersEXT(1, &m_fboData.resolveFB);\n            }\n\n            if (m_fboData.colorRB)\n            {\n                glDeleteRenderbuffersEXT(1, &m_fboData.colorRB);\n            }\n\n            if (m_fboData.depthRB)\n            {\n                glDeleteRenderbuffersEXT(1, &m_fboData.depthRB);\n            }\n\n            if (m_fboData.colorTex)\n            {\n                glDeleteTextures(1, &m_fboData.colorTex);\n            }\n\n            if (m_fboData.depthTex)\n            {\n                glDeleteTextures(1, &m_fboData.depthTex);\n            }\n\n            glDeleteProgramsARB(1, &m_textureProgram);\n            glDeleteProgramsARB(1, &m_overlayProgram);\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum status;\n            status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);\n\n            if (status != GL_FRAMEBUFFER_COMPLETE_EXT)\n            {\n                printf(\"<%s : %d> - \", zfile, line);\n            }\n\n            switch (status)\n            {\n                case GL_FRAMEBUFFER_COMPLETE_EXT:\n                    break;\n\n                case GL_FRAMEBUFFER_UNSUPPORTED_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Unsupported framebuffer format\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing attachment\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, duplicate attachment\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, attached images must have same dimensions\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, attached images must have same format\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing draw buffer\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing read buffer\\n\");\n                    }\n\n                    return false;\n\n                default:\n                    assert(0);\n                    return false;\n            }\n\n            return true;\n        }\n\n        virtual void renderQuad(int width, int height, GLenum eTarget)\n        {\n            float width_norm  = (float)width/(float)m_Width,\n                  height_norm = (float)height/(float)m_Height;\n\n            // Bind the FBO texture for the display path\n            glBindTexture(eTarget, m_fboData.colorTex);\n\n            glGenerateMipmapEXT(GL_TEXTURE_2D);\n            glBindTexture(eTarget, 0);\n\n            // now render to the full screen using this texture\n            glClearColor(0.2f, 0.2f, 0.2f, 0.0f);\n            glClear(GL_COLOR_BUFFER_BIT);\n\n            glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram);\n            glEnable(GL_FRAGMENT_PROGRAM_ARB);\n            glDisable(GL_DEPTH_TEST);\n\n            glBegin(GL_QUADS);\n            {\n                glVertex2f(0.0f      , 0.0f);\n                glTexCoord2f(0.0f      , 0.0f);\n                glVertex2f(0.0f      , height_norm);\n                glTexCoord2f(width_norm, 0.0f);\n                glVertex2f(width_norm, height_norm);\n                glTexCoord2f(width_norm, height_norm);\n                glVertex2f(width_norm, 0.0f);\n                glTexCoord2f(0.0f      , height_norm);\n            }\n            glEnd();\n\n            // Release the FBO texture (finished rendering)\n            glBindTexture(eTarget, 0);\n        }\n\n        // bind to the Fragment Program\n        void bindFragmentProgram()\n        {\n            glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_textureProgram);\n            glEnable(GL_FRAGMENT_PROGRAM_ARB);\n        }\n\n        // bind to the FrameBuffer Object\n        void bindRenderPath()\n        {\n            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboData.fb);\n        }\n\n        // release current FrameBuffer Object\n        void unbindRenderPath()\n        {\n            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n        }\n\n        // bind to the FBO to Texture\n        void bindTexture()\n        {\n            glBindTexture(m_eGLTarget, m_fboData.colorTex);\n        }\n\n        // release this bind\n        void unbindTexture()\n        {\n            glBindTexture(m_eGLTarget, 0);\n        }\n\n        GLuint getFbo()\n        {\n            return m_fboData.fb;\n        }\n        GLuint getTex()\n        {\n            return m_fboData.colorTex;\n        }\n        GLuint getDepthTex()\n        {\n            return m_fboData.depthTex;\n        }\n\n    private:\n        GLuint    m_Width, m_Height;\n        fboData   m_fboData;\n        fboConfig m_fboConfig;\n\n        GLuint    m_textureProgram;\n        GLuint    m_overlayProgram;\n\n        bool      m_bUseFloat;\n        GLenum    m_eGLTarget;\n};\n\n\n// CheckFBO - render and verify contents of the FBO\nclass CheckFBO: public CheckRender\n{\n    public:\n        CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp) :\n            CheckRender(width, height, Bpp, false, false, true),\n            m_pFrameBufferObject(NULL)\n        {\n        }\n\n        CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp, CFrameBufferObject *pFrameBufferObject) :\n            CheckRender(width, height, Bpp, false, true, true),\n            m_pFrameBufferObject(pFrameBufferObject)\n        {\n        }\n\n        virtual ~CheckFBO()\n        {\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum status;\n            status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);\n\n            if (status != GL_FRAMEBUFFER_COMPLETE_EXT)\n            {\n                printf(\"<%s : %d> - \", zfile, line);\n            }\n\n            switch (status)\n            {\n                case GL_FRAMEBUFFER_COMPLETE_EXT:\n                    break;\n\n                case GL_FRAMEBUFFER_UNSUPPORTED_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Unsupported framebuffer format\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing attachment\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, duplicate attachment\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, attached images must have same dimensions\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, attached images must have same format\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing draw buffer\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing read buffer\\n\");\n                    }\n\n                    return false;\n\n                default:\n                    assert(0);\n                    return false;\n            }\n\n            return true;\n        }\n\n        virtual bool readback(GLuint width, GLuint height)\n        {\n            bool ret = false;\n\n            if (m_bUsePBO)\n            {\n                // binds the PBO for readback\n                bindReadback();\n\n                // bind FBO buffer (we want to transfer FBO -> PBO)\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo());\n\n                // Now initiate the readback to PBO\n                glReadPixels(0, 0, width, height, getPixelFormat(),      GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                ret = checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                }\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n                memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                // release the FBO\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n\n                // release the PBO\n                unbindReadback();\n            }\n            else\n            {\n                // Reading back from FBO using glReadPixels\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_pFrameBufferObject->getFbo());\n                ret = checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback::glBindFramebufferEXT() checkStatus = %d\\n\", ret);\n                }\n\n                glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT));\n                ret &= checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback::glReadBuffer() checkStatus = %d\\n\", ret);\n                }\n\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject)\n        {\n            bool ret = false;\n\n            if (m_bUseFBO)\n            {\n                if (m_bUsePBO)\n                {\n                    printf(\"CheckFBO::readback() FBO->PBO->m_pImageData\\n\");\n                    // binds the PBO for readback\n                    bindReadback();\n\n                    // bind FBO buffer (we want to transfer FBO -> PBO)\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject);\n\n                    // Now initiate the readback to PBO\n                    glReadPixels(0, 0, width, height, getPixelFormat(),      GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                    }\n\n                    // map - unmap simulates readback without the copy\n                    void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n                    memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                    glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                    // release the FBO\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n\n                    // release the PBO\n                    unbindReadback();\n                }\n                else\n                {\n                    printf(\"CheckFBO::readback() FBO->m_pImageData\\n\");\n                    // Reading direct to FBO using glReadPixels\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bufObject);\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\\n\", (int)bufObject, (int)ret);\n                    }\n\n                    glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT));\n                    ret &= checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback::glReadBuffer() fbo=%d checkStatus = %d\\n\", (int)bufObject, (int)ret);\n                    }\n\n                    glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);\n                }\n            }\n            else\n            {\n                printf(\"CheckFBO::readback() PBO->m_pImageData\\n\");\n                // read from bufObject (PBO) to system memorys image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, bufObject);   // Bind the PBO\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);\n                memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);\n\n                // read from bufObject (PBO) to system memory image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);   // unBind the PBO\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf)\n        {\n            // let's flip the image as we copy\n            for (unsigned int y = 0; y < height; y++)\n            {\n                memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp);\n            }\n\n            return true;\n        }\n\n    private:\n        CFrameBufferObject *m_pFrameBufferObject;\n};\n\n#endif // _RENDERCHECK_GL_H_\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/rendercheck_gles.h",
    "content": "/**\n * Copyright 1993-2015 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n\n#ifndef _RENDERCHECK_GLES_H_\n#define _RENDERCHECK_GLES_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <vector>\n#include <map>\n#include <string>\n\n#include <GLES3/gl31.h>\n\n#include <helper_image.h>\n\nusing std::vector;\nusing std::map;\nusing std::string;\n\n#define BUFFER_OFFSET(i) ((char *)NULL + (i))\n\n#if _DEBUG\n#define CHECK_FBO     checkStatus(__FILE__, __LINE__, true)\n#else\n#define CHECK_FBO     true\n#endif\n\nclass CheckRender\n{\n    public:\n        CheckRender(unsigned int width, unsigned int height, unsigned int Bpp,\n                    bool bQAReadback, bool bUseFBO, bool bUsePBO) :\n            m_Width(width), m_Height(height), m_Bpp(Bpp), m_bQAReadback(bQAReadback),\n            m_bUseFBO(bUseFBO), m_bUsePBO(bUsePBO), m_PixelFormat(GL_RGBA), m_fThresholdCompare(0.0f)\n        {\n            allocateMemory(width, height, Bpp, bUseFBO, bUsePBO);\n        }\n\n        virtual ~CheckRender()\n        {\n            // Release PBO resources\n            if (m_bUsePBO)\n            {\n                glDeleteBuffers(1, &m_pboReadback);\n                m_pboReadback = 0;\n            }\n\n            free(m_pImageData);\n        }\n\n        virtual void allocateMemory(unsigned int width, unsigned int height, unsigned int Bpp,\n                                    bool bUseFBO, bool bUsePBO)\n        {\n            // Create the PBO for readbacks\n            if (bUsePBO)\n            {\n                glGenBuffers(1, &m_pboReadback);\n                glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboReadback);\n                glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*Bpp, NULL, GL_STREAM_READ);\n                glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);\n            }\n\n            m_pImageData = (unsigned char *)malloc(width*height*Bpp);  // This is the image data stored in system memory\n        }\n\n\n        virtual void setExecPath(char *path)\n        {\n            m_ExecPath = path;\n        }\n        virtual void EnableQAReadback(bool bStatus)\n        {\n            m_bQAReadback = bStatus;\n        }\n        virtual bool IsQAReadback()\n        {\n            return m_bQAReadback;\n        }\n        virtual bool IsFBO()\n        {\n            return m_bUseFBO;\n        }\n        virtual bool IsPBO()\n        {\n            return m_bUsePBO;\n        }\n        virtual void *imageData()\n        {\n            return m_pImageData;\n        }\n\n        // Interface to this class functions\n        virtual void setPixelFormat(GLenum format)\n        {\n            m_PixelFormat = format;\n        }\n        virtual int  getPixelFormat()\n        {\n            return m_PixelFormat;\n        }\n        virtual bool checkStatus(const char *zfile, int line, bool silent) = 0;\n        virtual bool readback(GLuint width, GLuint height) = 0;\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject) = 0;\n        virtual bool readback(GLuint width, GLuint height, unsigned char *membuf) = 0;\n\n        virtual void bindReadback()\n        {\n            if (!m_bQAReadback)\n            {\n                printf(\"CheckRender::bindReadback() uninitialized!\\n\");\n                return;\n            }\n\n            if (m_bUsePBO)\n            {\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pboReadback);   // Bind the PBO\n            }\n        }\n\n        virtual void unbindReadback()\n        {\n            if (!m_bQAReadback)\n            {\n                printf(\"CheckRender::unbindReadback() uninitialized!\\n\");\n                return;\n            }\n\n            if (m_bUsePBO)\n            {\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);   // Release the bind on the PBO\n            }\n        }\n\n        virtual void savePGM(const char *zfilename, bool bInvert, void **ppReadBuf)\n        {\n            if (zfilename != NULL)\n            {\n                if (bInvert)\n                {\n                    unsigned char *readBuf;\n                    unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height);\n\n                    for (unsigned int y=0; y < m_Height; y++)\n                    {\n                        if (ppReadBuf)\n                        {\n                            readBuf = *(unsigned char **)ppReadBuf;\n                        }\n                        else\n                        {\n                            readBuf = (unsigned char *)m_pImageData;\n                        }\n\n                        memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*(m_Height-1-y)), m_Width);\n                    }\n\n                    // we copy the results back to original system buffer\n                    if (ppReadBuf)\n                    {\n                        memcpy(*ppReadBuf, writeBuf, m_Width*m_Height);\n                    }\n                    else\n                    {\n                        memcpy(m_pImageData, writeBuf, m_Width*m_Height);\n                    }\n\n                    free(writeBuf);\n                }\n\n                printf(\"> Saving PGM: <%s>\\n\", zfilename);\n\n                if (ppReadBuf)\n                {\n                    sdkSavePGM<unsigned char>(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height);\n                }\n                else\n                {\n                    sdkSavePGM<unsigned char>(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height);\n                }\n            }\n        }\n\n        virtual void savePPM(const char *zfilename, bool bInvert, void **ppReadBuf)\n        {\n            if (zfilename != NULL)\n            {\n                if (bInvert)\n                {\n                    unsigned char *readBuf;\n                    unsigned char *writeBuf= (unsigned char *)malloc(m_Width * m_Height * m_Bpp);\n\n                    for (unsigned int y=0; y < m_Height; y++)\n                    {\n                        if (ppReadBuf)\n                        {\n                            readBuf = *(unsigned char **)ppReadBuf;\n                        }\n                        else\n                        {\n                            readBuf = (unsigned char *)m_pImageData;\n                        }\n                        memcpy(&writeBuf[m_Width*m_Bpp*y], (readBuf+ m_Width*m_Bpp*(m_Height-1-y)), m_Width*m_Bpp);\n                    }\n\n                    // we copy the results back to original system buffer\n                    if (ppReadBuf)\n                    {\n                        memcpy(*ppReadBuf, writeBuf, m_Width*m_Height*m_Bpp);\n                    }\n                    else\n                    {\n                        memcpy(m_pImageData, writeBuf, m_Width*m_Height*m_Bpp);\n                    }\n\n                    free(writeBuf);\n                }\n\n                printf(\"> Saving PPM: <%s>\\n\", zfilename);\n\n                if (ppReadBuf)\n                {\n                    sdkSavePPM4ub(zfilename, *(unsigned char **)ppReadBuf, m_Width, m_Height);\n                }\n                else\n                {\n                    sdkSavePPM4ub(zfilename, (unsigned char *)m_pImageData, m_Width, m_Height);\n                }\n            }\n        }\n\n        virtual bool PGMvsPGM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f)\n        {\n            unsigned char *src_data = NULL, *ref_data = NULL;\n            unsigned long error_count = 0;\n            unsigned int width, height;\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"CheckRender::PGMvsPGM unable to find <%s> in <%s> Aborting comparison!\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n            }\n            else\n            {\n\n                if (src_file == NULL || ref_file_path == NULL)\n                {\n                    printf(\"PGMvsPGM: Aborting comparison\\n\");\n                    return false;\n                }\n\n                printf(\"   src_file <%s>\\n\", src_file);\n                printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                if (sdkLoadPPMub(ref_file_path, &ref_data, &width, &height) != true)\n                {\n                    printf(\"PGMvsPGM: unable to load ref image file: %s\\n\", ref_file_path);\n                    return false;\n                }\n\n                if (sdkLoadPPMub(src_file, &src_data, &width, &height) != true)\n                {\n                    printf(\"PGMvsPGM: unable to load src image file: %s\\n\", src_file);\n                    return false;\n                }\n\n                printf(\"PGMvsPGM: comparing images size (%d,%d) epsilon(%2.4f), threshold(%4.2f%%)\\n\", m_Height, m_Width, epsilon, threshold*100);\n\n                if (compareDataAsFloatThreshold<unsigned char, float>(ref_data, src_data, m_Height*m_Width, epsilon, threshold) == false)\n                {\n                    error_count = 1;\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n        virtual bool PPMvsPPM(const char *src_file, const char *ref_file, const float epsilon, const float threshold = 0.0f)\n        {\n            unsigned long error_count = 0;\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"CheckRender::PPMvsPPM unable to find <%s> in <%s> Aborting comparison!\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n            }\n\n            if (src_file == NULL || ref_file_path == NULL)\n            {\n                printf(\"PPMvsPPM: Aborting comparison\\n\");\n                return false;\n            }\n\n            printf(\"   src_file <%s>\\n\", src_file);\n            printf(\"   ref_file <%s>\\n\", ref_file_path);\n            return (sdkComparePPM(src_file, ref_file_path, epsilon, threshold, true) == true ? true : false);\n        }\n\n\n        void    setThresholdCompare(float value)\n        {\n            m_fThresholdCompare = value;\n        }\n\n        virtual void dumpBin(void *data, unsigned int bytes, const char *filename)\n        {\n            FILE *fp;\n            printf(\"CheckRender::dumpBin: <%s>\\n\", filename);\n            FOPEN(fp, filename, \"wb\");\n            fwrite(data, bytes, 1, fp);\n            fflush(fp);\n            fclose(fp);\n        }\n\n        virtual bool compareBin2BinUint(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold)\n        {\n            unsigned int *src_buffer, *ref_buffer;\n            FILE *src_fp = NULL, *ref_fp = NULL;\n\n            unsigned long error_count = 0;\n            size_t fsize = 0;\n\n            FOPEN(src_fp, src_file, \"rb\");\n\n            if (src_fp == NULL)\n            {\n                printf(\"compareBin2Bin <unsigned int> unable to open src_file: %s\\n\", src_file);\n                error_count++;\n            }\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"compareBin2Bin <unsigned int>  unable to find <%s> in <%s>\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", ref_file);\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n\n                if (src_fp)\n                {\n                    fclose(src_fp);\n                }\n\n                if (ref_fp)\n                {\n                    fclose(ref_fp);\n                }\n            }\n            else\n            {\n                FOPEN(ref_fp, ref_file_path, \"rb\");\n\n                if (ref_fp == NULL)\n                {\n                    printf(\"compareBin2Bin <unsigned int>  unable to open ref_file: %s\\n\", ref_file_path);\n                    error_count++;\n                }\n\n                if (src_fp && ref_fp)\n                {\n                    src_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n                    ref_buffer = (unsigned int *)malloc(nelements*sizeof(unsigned int));\n\n                    fsize = fread(src_buffer, sizeof(unsigned int), nelements, src_fp);\n\n                    if (fsize != nelements)\n                    {\n                        printf(\"compareBin2Bin <unsigned int>  failed to read %u elements from %s\\n\", nelements, src_file);\n                        error_count++;\n                    }\n\n                    fsize = fread(ref_buffer, sizeof(unsigned int), nelements, ref_fp);\n\n                    if (fsize == 0)\n                    {\n                        printf(\"compareBin2Bin <unsigned int>  failed to read %u elements from %s\\n\", nelements, ref_file_path);\n                        error_count++;\n                    }\n\n\n                    printf(\"> compareBin2Bin <unsigned int> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n                    printf(\"   src_file <%s>\\n\", src_file);\n                    printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                    if (!compareData<unsigned int, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n                    {\n                        error_count++;\n                    }\n\n                    fclose(src_fp);\n                    fclose(ref_fp);\n\n                    free(src_buffer);\n                    free(ref_buffer);\n                }\n                else\n                {\n                    if (src_fp)\n                    {\n                        fclose(src_fp);\n                    }\n\n                    if (ref_fp)\n                    {\n                        fclose(ref_fp);\n                    }\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n        virtual bool compareBin2BinFloat(const char *src_file, const char *ref_file, unsigned int nelements, const float epsilon, const float threshold)\n        {\n            float *src_buffer, *ref_buffer;\n            FILE *src_fp = NULL, *ref_fp = NULL;\n            size_t fsize = 0;\n\n            unsigned long error_count = 0;\n\n            FOPEN(src_fp, src_file, \"rb\");\n\n            if (src_fp == NULL)\n            {\n                printf(\"compareBin2Bin <float> unable to open src_file: %s\\n\", src_file);\n                error_count = 1;\n            }\n\n            char *ref_file_path = sdkFindFilePath(ref_file, m_ExecPath.c_str());\n\n            if (ref_file_path == NULL)\n            {\n                printf(\"compareBin2Bin <float> unable to find <%s> in <%s>\\n\", ref_file, m_ExecPath.c_str());\n                printf(\">>> Check info.xml and [project//data] folder <%s> <<<\\n\", m_ExecPath.c_str());\n                printf(\"Aborting comparison!\\n\");\n                printf(\"  FAILED\\n\");\n                error_count++;\n\n                if (src_fp)\n                {\n                    fclose(src_fp);\n                }\n\n                if (ref_fp)\n                {\n                    fclose(ref_fp);\n                }\n            }\n            else\n            {\n                FOPEN(ref_fp, ref_file_path, \"rb\");\n\n                if (ref_fp == NULL)\n                {\n                    printf(\"compareBin2Bin <float> unable to open ref_file: %s\\n\", ref_file_path);\n                    error_count = 1;\n                }\n\n                if (src_fp && ref_fp)\n                {\n                    src_buffer = (float *)malloc(nelements*sizeof(float));\n                    ref_buffer = (float *)malloc(nelements*sizeof(float));\n\n                    fsize = fread(src_buffer, sizeof(float), nelements, src_fp);\n\n                    if (fsize != nelements)\n                    {\n                        printf(\"compareBin2Bin <float>  failed to read %u elements from %s\\n\", nelements, src_file);\n                        error_count++;\n                    }\n\n                    fsize = fread(ref_buffer, sizeof(float), nelements, ref_fp);\n\n                    if (fsize == 0)\n                    {\n                        printf(\"compareBin2Bin <float>  failed to read %u elements from %s\\n\", nelements, ref_file_path);\n                        error_count++;\n                    }\n\n                    printf(\"> compareBin2Bin <float> nelements=%d, epsilon=%4.2f, threshold=%4.2f\\n\", nelements, epsilon, threshold);\n                    printf(\"   src_file <%s>\\n\", src_file);\n                    printf(\"   ref_file <%s>\\n\", ref_file_path);\n\n                    if (!compareDataAsFloatThreshold<float, float>(ref_buffer, src_buffer, nelements, epsilon, threshold))\n                    {\n                        error_count++;\n                    }\n\n                    fclose(src_fp);\n                    fclose(ref_fp);\n\n                    free(src_buffer);\n                    free(ref_buffer);\n                }\n                else\n                {\n                    if (src_fp)\n                    {\n                        fclose(src_fp);\n                    }\n\n                    if (ref_fp)\n                    {\n                        fclose(ref_fp);\n                    }\n                }\n            }\n\n            if (error_count == 0)\n            {\n                printf(\"  OK\\n\");\n            }\n            else\n            {\n                printf(\"  FAILURE: %d errors...\\n\", (unsigned int)error_count);\n            }\n\n            return (error_count == 0);  // returns true if all pixels pass\n        }\n\n\n    protected:\n        unsigned int  m_Width, m_Height, m_Bpp;\n        unsigned char *m_pImageData;  // This is the image data stored in system memory\n        bool          m_bQAReadback, m_bUseFBO, m_bUsePBO;\n        GLuint        m_pboReadback;\n        GLenum        m_PixelFormat;\n        float         m_fThresholdCompare;\n        string        m_ExecPath;\n};\n\n\nclass CheckBackBuffer : public CheckRender\n{\n    public:\n        CheckBackBuffer(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseOpenGL = true) :\n            CheckRender(width, height, Bpp, false, false, bUseOpenGL)\n        {\n        }\n\n        virtual ~CheckBackBuffer()\n        {\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum nErrorCode = glGetError();\n\n            if (nErrorCode != GL_NO_ERROR)\n            {\n                if (!silent)\n                {\n                    //printf(\"Assertion failed(%s,%d): %s\\n\", zfile, line, gluErrorString(nErrorCode));\n                }\n            }\n\n            return true;\n        }\n\n        virtual bool readback(GLuint width, GLuint height)\n        {\n            bool ret = false;\n\n            if (m_bUsePBO)\n            {\n                // binds the PBO for readback\n                bindReadback();\n\n                // Initiate the readback BLT from BackBuffer->PBO->membuf\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n\n                ret = checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckBackBuffer::glReadPixels() checkStatus = %d\\n\", ret);\n                }\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_READ_ONLY);\n                memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                // release the PBO\n                unbindReadback();\n            }\n            else\n            {\n                // reading direct from the backbuffer\n                glReadBuffer(GL_FRONT);\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n            }\n\n            return ret;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject)\n        {\n            bool ret = false;\n\n            if (m_bUseFBO)\n            {\n                if (m_bUsePBO)\n                {\n                    printf(\"CheckBackBuffer::readback() FBO->PBO->m_pImageData\\n\");\n                    // binds the PBO for readback\n                    bindReadback();\n\n                    // bind FBO buffer (we want to transfer FBO -> PBO)\n                    glBindFramebuffer(GL_FRAMEBUFFER, bufObject);\n\n                    // Now initiate the readback to PBO\n                    glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                    }\n\n                    // map - unmap simulates readback without the copy\n                    void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT);\n                    memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                    // release the FBO\n                    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n                    // release the PBO\n                    unbindReadback();\n                }\n                else\n                {\n                    printf(\"CheckBackBuffer::readback() FBO->m_pImageData\\n\");\n                    // Reading direct to FBO using glReadPixels\n                    glBindFramebuffer(GL_FRAMEBUFFER, bufObject);\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\\n\", bufObject, ret);\n                    }\n\n                    glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0));\n                    ret &= checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckBackBuffer::readback::glReadBuffer() fbo=%d checkStatus = %d\\n\", bufObject, ret);\n                    }\n\n                    glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n                }\n            }\n            else\n            {\n\n                printf(\"CheckBackBuffer::readback() PBO->m_pImageData\\n\");\n                // read from bufObject (PBO) to system memorys image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject);   // Bind the PBO\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT);\n\n                // allocate a buffer so we can flip the image\n                unsigned char *temp_buf = (unsigned char *)malloc(width*height*m_Bpp);\n                memcpy(temp_buf, ioMem, width*height*m_Bpp);\n\n                // let's flip the image as we copy\n                for (unsigned int y = 0; y < height; y++)\n                {\n                    memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(temp_buf[y*width*m_Bpp]), width*m_Bpp);\n                }\n\n                free(temp_buf);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                // read from bufObject (PBO) to system memory image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);   // unBind the PBO\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf)\n        {\n            // let's flip the image as we copy\n            for (unsigned int y = 0; y < height; y++)\n            {\n                memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp);\n            }\n\n            return true;\n        }\n\n    private:\n        virtual void bindFragmentProgram() {};\n        virtual void bindRenderPath() {};\n        virtual void unbindRenderPath() {};\n\n        // bind to the BackBuffer to Texture\n        virtual void bindTexture() {};\n\n        // release this bind\n        virtual void unbindTexture() {};\n};\n\n// structure defining the properties of a single buffer\nstruct bufferConfig\n{\n    string name;\n    GLenum format;\n    int bits;\n};\n\n// structures defining properties of an FBO\nstruct fboConfig\n{\n    string name;\n    GLenum colorFormat;\n    GLenum depthFormat;\n    int redbits;\n    int depthBits;\n    int depthSamples;\n    int coverageSamples;\n};\n\nstruct fboData\n{\n    GLuint colorTex; //color texture\n    GLuint depthTex; //depth texture\n    GLuint fb;      // render framebuffer\n    GLuint resolveFB; //multisample resolve target\n    GLuint colorRB; //color render buffer\n    GLuint depthRB; // depth render buffer\n};\n\n\nclass CFrameBufferObject\n{\n    public:\n        CFrameBufferObject(unsigned int width, unsigned int height, unsigned int Bpp, bool bUseFloat, GLenum eTarget) :\n            m_Width(width),\n            m_Height(height),\n            m_bUseFloat(bUseFloat),\n            m_eGLTarget(eTarget)\n        {\n            glGenFramebuffers(1, &m_fboData.fb);\n\n            m_fboData.colorTex = createTexture(m_eGLTarget, width, height, GL_RGBA, GL_RGBA);\n            m_fboData.depthTex = createTexture(m_eGLTarget, width, height,  GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT);\n\n            attachTexture(m_eGLTarget, m_fboData.depthTex,   GL_DEPTH_ATTACHMENT);\n            attachTexture(m_eGLTarget, m_fboData.colorTex,   GL_COLOR_ATTACHMENT0);\n\n            bool ret = checkStatus(__FILE__, __LINE__, false);\n        }\n\n        void check_gl_error(const char *file, int line)\n        {\n            GLenum err (glGetError());\n \n            while(err!=GL_NO_ERROR) {\n                char error[64];\n \n                switch(err) {\n                        case GL_INVALID_OPERATION:      strcpy(error, \"INVALID_OPERATION\");      break;\n                        case GL_INVALID_ENUM:           strcpy(error, \"INVALID_ENUM\");           break;\n                        case GL_INVALID_VALUE:          strcpy(error, \"INVALID_VALUE\");          break;\n                        case GL_OUT_OF_MEMORY:          strcpy(error, \"OUT_OF_MEMORY\");          break;\n                        case GL_INVALID_FRAMEBUFFER_OPERATION:  strcpy(error, \"INVALID_FRAMEBUFFER_OPERATION\");  break;\n                }\n \n                printf ( \"GL_%s  - %s : %d\\n\", error, file, line);\n                err=glGetError();\n            }\n        }\n\n        virtual ~CFrameBufferObject()\n        {\n             freeResources();\n        }\n\n        GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format)\n        {\n            GLuint texid;\n            glGenTextures(1, &texid);\n\n            glBindTexture(target, texid);\n\n            if (format != GL_DEPTH_COMPONENT)\n            {\n                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n            }\n            else\n            {\n                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n            }\n\n            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n            if (internalformat == GL_DEPTH_COMPONENT24)\n            {\n                glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_INT, 0);\n            }\n            else\n            {\n                glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_UNSIGNED_BYTE, 0);\n            }\n\n            check_gl_error(__FILE__, __LINE__);\n            glBindTexture(target, 0);\n\n            return texid;\n        }\n\n        void    attachTexture(GLenum texTarget,\n                              GLuint texId,\n                              GLenum attachment   = GL_COLOR_ATTACHMENT0,\n                              int mipLevel        = 0,\n                              int zSlice          = 0)\n        {\n            bindRenderPath();\n            check_gl_error(__FILE__, __LINE__);\n\n            glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, texTarget, texId, mipLevel);\n\n            checkStatus(__FILE__, __LINE__, false);\n\n            unbindRenderPath();\n        }\n\n        bool initialize(unsigned width, unsigned height, fboConfig &rConfigFBO, fboData &rActiveFBO)\n        {\n            //Framebuffer config options\n            vector<bufferConfig> colorConfigs;\n            vector<bufferConfig> depthConfigs;\n            bufferConfig temp;\n\n            //add default color configs\n            temp.name   = (m_bUseFloat ? \"RGBA32F\" : \"RGBA8\");\n            temp.bits   = (m_bUseFloat ? 32 : 8);\n            temp.format = (m_bUseFloat ? GL_RGBA32F : GL_RGBA8);\n            colorConfigs.push_back(temp);\n\n            //add default depth configs\n            temp.name = \"D24\";\n            temp.bits = 24;\n            temp.format = GL_DEPTH_COMPONENT24;\n            depthConfigs.push_back(temp);\n\n            // If the FBO can be created, add it to the list of available configs, and make a menu entry\n            string root = colorConfigs[0].name + \" \" + depthConfigs[0].name;\n\n            rConfigFBO.colorFormat  = colorConfigs[0].format;\n            rConfigFBO.depthFormat  = depthConfigs[0].format;\n            rConfigFBO.redbits      = colorConfigs[0].bits;\n            rConfigFBO.depthBits    = depthConfigs[0].bits;\n\n            //single sample\n            rConfigFBO.name             = root;\n            rConfigFBO.coverageSamples  = 0;\n            rConfigFBO.depthSamples     = 0;\n\n            create(width, height, rConfigFBO, rActiveFBO);\n\n            glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n            return CHECK_FBO;\n        }\n\n        bool create(GLuint width, GLuint height, fboConfig &config, fboData &data)\n        {\n            bool multisample = config.depthSamples > 0;\n            bool ret = true;\n            GLint query;\n\n            printf(\"\\nCreating FBO <%s> (%dx%d) Float:%s\\n\", config.name.c_str(), (int)width, (int)height, (m_bUseFloat ? \"Y\":\"N\"));\n\n            glGenFramebuffers(1, &data.fb);\n            glGenTextures(1, &data.colorTex);\n\n            // init texture\n            glBindTexture(m_eGLTarget, data.colorTex);\n            glTexImage2D(m_eGLTarget, 0, config.colorFormat,\n                         width, height, 0, GL_RGBA,\n                         (m_bUseFloat ? GL_FLOAT : GL_UNSIGNED_BYTE),\n                         NULL);\n\n            glGenerateMipmap(m_eGLTarget);\n\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // GL_LINEAR_MIPMAP_LINEAR);\n            glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // GL_LINEAR);\n\n            {\n                glGenTextures(1, &data.depthTex);\n                data.depthRB = 0;\n                data.colorRB = 0;\n                data.resolveFB = 0;\n\n                //non-multisample, so bind things directly to the FBO\n                glBindFramebuffer(GL_FRAMEBUFFER, data.fb);\n                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_eGLTarget, data.colorTex, 0);\n\n                glBindTexture(m_eGLTarget, data.depthTex);\n                glTexImage2D(m_eGLTarget, 0, config.depthFormat,\n                             width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);\n\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // GL_LINEAR);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // GL_LINEAR);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n                glTexParameterf(m_eGLTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n//                glTexParameterf(m_eGLTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);\n\n                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_eGLTarget, data.depthTex, 0);\n\n                ret &= checkStatus(__FILE__, __LINE__, false);\n            }\n\n            glBindFramebuffer(GL_FRAMEBUFFER, data.fb);\n            glGetIntegerv(GL_RED_BITS, &query);\n\n            if (query != config.redbits)\n            {\n                ret = false;\n            }\n\n            glGetIntegerv(GL_DEPTH_BITS, &query);\n\n            if (query != config.depthBits)\n            {\n                ret = false;\n            }\n\n            if (multisample)\n            {\n                glBindFramebuffer(GL_FRAMEBUFFER, data.resolveFB);\n                glGetIntegerv(GL_RED_BITS, &query);\n\n                if (query != config.redbits)\n                {\n                    ret = false;\n                }\n            }\n\n            glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n            ret &= checkStatus(__FILE__, __LINE__, true);\n\n            return ret;\n        }\n\n        virtual void freeResources()\n        {\n            if (m_fboData.fb)\n            {\n                glDeleteFramebuffers(1, &m_fboData.fb);\n            }\n\n            if (m_fboData.resolveFB)\n            {\n                glDeleteFramebuffers(1, &m_fboData.resolveFB);\n            }\n\n            if (m_fboData.colorRB)\n            {\n                glDeleteRenderbuffers(1, &m_fboData.colorRB);\n            }\n\n            if (m_fboData.depthRB)\n            {\n                glDeleteRenderbuffers(1, &m_fboData.depthRB);\n            }\n\n            if (m_fboData.colorTex)\n            {\n                glDeleteTextures(1, &m_fboData.colorTex);\n            }\n\n            if (m_fboData.depthTex)\n            {\n                glDeleteTextures(1, &m_fboData.depthTex);\n            }\n\n            glDeleteProgram(m_textureProgram);\n            glDeleteProgram(m_overlayProgram);\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum status;\n            status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER);\n\n            if (status != GL_FRAMEBUFFER_COMPLETE)\n            {\n                printf(\"<%s : %d> - this one \", zfile, line);\n            }\n\n            switch (status)\n            {\n                case GL_FRAMEBUFFER_COMPLETE:\n                    break;\n\n                case GL_FRAMEBUFFER_UNSUPPORTED:\n                    if (!silent)\n                    {\n                        printf(\"Unsupported framebuffer format\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing attachment\\n\");\n                    }\n\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, duplicate attachment\\n\");\n                    }\n\n                    return false;\n\n                default:\n                    assert(0);\n                    return false;\n            }\n\n            return true;\n        }\n\n        // bind to the FrameBuffer Object\n        void bindRenderPath()\n        {\n            glBindFramebuffer(GL_FRAMEBUFFER, m_fboData.fb);\n        }\n\n        // release current FrameBuffer Object\n        void unbindRenderPath()\n        {\n            glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        }\n\n        // bind to the FBO to Texture\n        void bindTexture()\n        {\n            glBindTexture(m_eGLTarget, m_fboData.colorTex);\n        }\n\n        // release this bind\n        void unbindTexture()\n        {\n            glBindTexture(m_eGLTarget, 0);\n        }\n\n        GLuint getFbo()\n        {\n            return m_fboData.fb;\n        }\n        GLuint getTex()\n        {\n            return m_fboData.colorTex;\n        }\n        GLuint getDepthTex()\n        {\n            return m_fboData.depthTex;\n        }\n\n    private:\n        GLuint    m_Width, m_Height;\n        fboData   m_fboData;\n        fboConfig m_fboConfig;\n\n        GLuint    m_textureProgram;\n        GLuint    m_overlayProgram;\n\n        bool      m_bUseFloat;\n        GLenum    m_eGLTarget;\n};\n\n\n// CheckFBO - render and verify contents of the FBO\nclass CheckFBO: public CheckRender\n{\n    public:\n        CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp) :\n            CheckRender(width, height, Bpp, false, false, true),\n            m_pFrameBufferObject(NULL)\n        {\n        }\n\n        CheckFBO(unsigned int width, unsigned int height, unsigned int Bpp, CFrameBufferObject *pFrameBufferObject) :\n            CheckRender(width, height, Bpp, false, true, true),\n            m_pFrameBufferObject(pFrameBufferObject)\n        {\n        }\n\n        void check_gl_error(const char *file, int line) \n        {\n            GLenum err (glGetError());\n\n            while(err!=GL_NO_ERROR) \n            {\n                char error[64];\n \n                switch(err) \n                {\n                        case GL_INVALID_OPERATION:      strcpy(error, \"INVALID_OPERATION\");      break;\n                        case GL_INVALID_ENUM:           strcpy(error, \"INVALID_ENUM\");           break;\n                        case GL_INVALID_VALUE:          strcpy(error, \"INVALID_VALUE\");          break;\n                        case GL_OUT_OF_MEMORY:          strcpy(error, \"OUT_OF_MEMORY\");          break;\n                        case GL_INVALID_FRAMEBUFFER_OPERATION:  strcpy(error, \"INVALID_FRAMEBUFFER_OPERATION\");  break;\n                }\n \n                printf ( \"GL_%s  - %s : %d\\n\", error, file, line);\n                err=glGetError();\n            }\n        }\n\n        virtual ~CheckFBO()\n        {\n        }\n\n        virtual bool checkStatus(const char *zfile, int line, bool silent)\n        {\n            GLenum status;\n            status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER);\n\n            if (status != GL_FRAMEBUFFER_COMPLETE)\n            {\n                printf(\"<%s : %d> - here \", zfile, line);\n            }\n\n            switch (status)\n            {\n                case GL_FRAMEBUFFER_COMPLETE:\n                    break;\n\n                case GL_FRAMEBUFFER_UNSUPPORTED:\n                    if (!silent)\n                    {\n                        printf(\"Unsupported framebuffer format\\n\");\n                    }\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, missing attachment\\n\");\n                    }\n                    return false;\n\n                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, duplicate attachment\\n\");\n                    }\n                    return false;\n\n                case GL_FRAMEBUFFER_UNDEFINED:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer undefined\\n\");\n                    }\n                    return false;\n\n                default:\n                    if (!silent)\n                    {\n                        printf(\"Framebuffer incomplete, default state\\n\");\n                    }\n                    assert(0);\n                    return false;\n            }\n\n            return true;\n        }\n\n        virtual bool readback(GLuint width, GLuint height)\n        {\n            bool ret = false;\n\n            if (m_bUsePBO)\n            {\n                // binds the PBO for readback\n                bindReadback();\n\n                // bind FBO buffer (we want to transfer FBO -> PBO)\n                glBindFramebuffer(GL_FRAMEBUFFER, m_pFrameBufferObject->getFbo());\n\n                ret = checkStatus(__FILE__, __LINE__, false);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback() glBindFramebuffer checkStatus = %d\\n\", ret);\n                }\n\n                // Now initiate the readback to PBO\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n\n                ret = checkStatus(__FILE__, __LINE__, false);\n\n                check_gl_error(__FILE__, __LINE__);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                }\n\n                int nBufferSize = 0;\n                glGetBufferParameteriv(GL_PIXEL_PACK_BUFFER, GL_BUFFER_SIZE, &nBufferSize);\n\n                if (nBufferSize !=  width*height*m_Bpp)\n                {\n                    printf(\"Buffer size incorrect, exiting..\\n\");\n                    exit(EXIT_FAILURE);\n                }\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT);\n                check_gl_error(__FILE__, __LINE__);\n\n                if (ioMem != NULL)\n                {\n                    memcpy(m_pImageData, ioMem, width*height*m_Bpp);\n                }\n                else\n                {\n                    printf(\"\\nError: Unable to map the PBO\\n\");\n                    exit(EXIT_FAILURE);\n                }\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                // release the FBO\n                glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n                // release the PBO\n                unbindReadback();\n            }\n            else\n            {\n                // Reading back from FBO using glReadPixels\n                glBindFramebuffer(GL_FRAMEBUFFER, m_pFrameBufferObject->getFbo());\n                ret = checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback::glBindFramebufferEXT() checkStatus = %d\\n\", ret);\n                }\n\n                glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0));\n                ret &= checkStatus(__FILE__, __LINE__, true);\n\n                if (!ret)\n                {\n                    printf(\"CheckFBO::readback::glReadBuffer() checkStatus = %d\\n\", ret);\n                }\n\n                glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                glBindFramebuffer(GL_FRAMEBUFFER, 0);\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, GLuint bufObject)\n        {\n            bool ret = false;\n\n            if (m_bUseFBO)\n            {\n                if (m_bUsePBO)\n                {\n                    printf(\"CheckFBO::readback() FBO->PBO->m_pImageData\\n\");\n                    // binds the PBO for readback\n                    bindReadback();\n\n                    // bind FBO buffer (we want to transfer FBO -> PBO)\n                    glBindFramebuffer(GL_FRAMEBUFFER, bufObject);\n\n                    // Now initiate the readback to PBO\n                    glReadPixels(0, 0, width, height, getPixelFormat(),      GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback() FBO->PBO checkStatus = %d\\n\", ret);\n                    }\n\n                    // map - unmap simulates readback without the copy\n                    void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT);\n                    memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                    // release the FBO\n                    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n                    // release the PBO\n                    unbindReadback();\n                }\n                else\n                {\n                    printf(\"CheckFBO::readback() FBO->m_pImageData\\n\");\n                    // Reading direct to FBO using glReadPixels\n                    glBindFramebuffer(GL_FRAMEBUFFER, bufObject);\n                    ret = checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback::glBindFramebufferEXT() fbo=%d checkStatus = %d\\n\", (int)bufObject, (int)ret);\n                    }\n\n                    glReadBuffer(static_cast<GLenum>(GL_COLOR_ATTACHMENT0));\n                    ret &= checkStatus(__FILE__, __LINE__, true);\n\n                    if (!ret)\n                    {\n                        printf(\"CheckFBO::readback::glReadBuffer() fbo=%d checkStatus = %d\\n\", (int)bufObject, (int)ret);\n                    }\n\n                    glReadPixels(0, 0, width, height, getPixelFormat(), GL_UNSIGNED_BYTE, m_pImageData);\n\n                    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n                }\n            }\n            else\n            {\n                printf(\"CheckFBO::readback() PBO->m_pImageData\\n\");\n                // read from bufObject (PBO) to system memorys image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, bufObject);   // Bind the PBO\n\n                // map - unmap simulates readback without the copy\n                void *ioMem = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width*height*m_Bpp, GL_MAP_READ_BIT);\n                memcpy(m_pImageData,    ioMem, width*height*m_Bpp);\n\n                glUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n\n                // read from bufObject (PBO) to system memory image\n                glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);   // unBind the PBO\n            }\n\n            return CHECK_FBO;\n        }\n\n        virtual bool readback(GLuint width, GLuint height, unsigned char *memBuf)\n        {\n            // let's flip the image as we copy\n            for (unsigned int y = 0; y < height; y++)\n            {\n                memcpy((void *)&(m_pImageData[(height-y)*width*m_Bpp]), (void *)&(memBuf[y*width*m_Bpp]), width*m_Bpp);\n            }\n\n            return true;\n        }\n\n    private:\n        CFrameBufferObject *m_pFrameBufferObject;\n};\n\n#endif // _RENDERCHECK_GLES_H_\n\n"
  },
  {
    "path": "tests/projects/cuda/console/inc/timer.h",
    "content": "/**\n * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n#ifndef TIMER_H\n#define TIMER_H\n\n#include <stdlib.h>\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#else\n#include <sys/time.h>\n#endif\n\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\ndouble PCFreq = 0.0;\n__int64 timerStart = 0;\n#else\nstruct timeval timerStart;\n#endif\n\nvoid StartTimer()\n{\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n    LARGE_INTEGER li;\n\n    if (!QueryPerformanceFrequency(&li))\n    {\n        printf(\"QueryPerformanceFrequency failed!\\n\");\n    }\n\n    PCFreq = (double)li.QuadPart/1000.0;\n    QueryPerformanceCounter(&li);\n    timerStart = li.QuadPart;\n#else\n    gettimeofday(&timerStart, NULL);\n#endif\n}\n\n// time elapsed in ms\ndouble GetTimer()\n{\n#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)\n    LARGE_INTEGER li;\n    QueryPerformanceCounter(&li);\n    return (double)(li.QuadPart-timerStart)/PCFreq;\n#else\n    struct timeval timerStop, timerElapsed;\n    gettimeofday(&timerStop, NULL);\n    timersub(&timerStop, &timerStart, &timerElapsed);\n    return timerElapsed.tv_sec*1000.0+timerElapsed.tv_usec/1000.0;\n#endif\n}\n#endif // TIMER_H\n\n"
  },
  {
    "path": "tests/projects/cuda/console/src/main.cu",
    "content": "/*\n * Copyright 1993-2015 NVIDIA Corporation.  All rights reserved.\n *\n * Please refer to the NVIDIA end user license agreement (EULA) associated\n * with this source code for terms and conditions that govern your use of\n * this software. Any use, reproduction, disclosure, or distribution of\n * this software and related documentation outside the terms of the EULA\n * is strictly prohibited.\n *\n */\n\n\n// System includes\n#include <stdio.h>\n#include <assert.h>\n\n// CUDA runtime\n#include <cuda_runtime.h>\n\n// helper functions and utilities to work with CUDA\n#include <helper_functions.h>\n#include <helper_cuda.h>\n\n#ifndef MAX\n#define MAX(a,b) (a > b ? a : b)\n#endif\n\n__global__ void testKernel(int val)\n{\n    printf(\"[%d, %d]:\\t\\tValue is:%d\\n\",\\\n            blockIdx.y*gridDim.x+blockIdx.x,\\\n            threadIdx.z*blockDim.x*blockDim.y+threadIdx.y*blockDim.x+threadIdx.x,\\\n            val);\n}\n\nint main(int argc, char **argv)\n{\n    int devID;\n    cudaDeviceProp props;\n\n    // This will pick the best possible CUDA capable device\n    devID = findCudaDevice(argc, (const char **)argv);\n\n    //Get GPU information\n    checkCudaErrors(cudaGetDevice(&devID));\n    checkCudaErrors(cudaGetDeviceProperties(&props, devID));\n    printf(\"Device %d: \\\"%s\\\" with Compute %d.%d capability\\n\",\n           devID, props.name, props.major, props.minor);\n\n    printf(\"printf() is called. Output:\\n\\n\");\n\n    //Kernel configuration, where a two-dimensional grid and\n    //three-dimensional blocks are configured.\n    dim3 dimGrid(2, 2);\n    dim3 dimBlock(2, 2, 2);\n    testKernel<<<dimGrid, dimBlock>>>(10);\n    cudaDeviceSynchronize();\n\n    return EXIT_SUCCESS;\n}\n\n"
  },
  {
    "path": "tests/projects/cuda/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"cuda_console\")\n    set_kind(\"binary\")\n    add_includedirs(\"inc\")\n    add_files(\"src/*.cu\")\n\n    -- generate SASS code for each SM architecture\n    add_cugencodes(\"sm_75\", \"sm_80\", \"sm_89\", \"sm_90\", \"sm_100\")\n\n    -- generate PTX code from the highest SM architecture to guarantee forward-compatibility\n    add_cugencodes(\"compute_100\")\n\n"
  },
  {
    "path": "tests/projects/cuda/console_2/inc/lib.cuh",
    "content": "#pragma once\n\n__global__ void addKernel(int *c, const int *a, const int *b);"
  },
  {
    "path": "tests/projects/cuda/console_2/src/lib.cu",
    "content": "#include <lib.cuh>\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}"
  },
  {
    "path": "tests/projects/cuda/console_2/src/main.cu",
    "content": "\n#include \"cuda_runtime.h\"\n#include \"device_launch_parameters.h\"\n\n#include <stdio.h>\n#include <lib.cuh>\n\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);\n\nint main()\n{\n    const int arraySize = 5;\n    const int a[arraySize] = {1, 2, 3, 4, 5};\n    const int b[arraySize] = {10, 20, 30, 40, 50};\n    int c[arraySize] = {0};\n\n    // Add vectors in parallel.\n    cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addWithCuda failed!\");\n        return 1;\n    }\n\n    printf(\"{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\\n\",\n           c[0], c[1], c[2], c[3], c[4]);\n\n    // cudaDeviceReset must be called before exiting in order for profiling and\n    // tracing tools such as Nsight and Visual Profiler to show complete traces.\n    cudaStatus = cudaDeviceReset();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceReset failed!\");\n        return 1;\n    }\n\n    return 0;\n}\n\n// Helper function for using CUDA to add vectors in parallel.\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)\n{\n    int *dev_a = 0;\n    int *dev_b = 0;\n    int *dev_c = 0;\n    cudaError_t cudaStatus;\n\n    // Choose which GPU to run on, change this on a multi-GPU system.\n    cudaStatus = cudaSetDevice(0);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?\");\n        goto Error;\n    }\n\n    // Allocate GPU buffers for three vectors (two input, one output)    .\n    cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    // Copy input vectors from host memory to GPU buffers.\n    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    // Launch a kernel on the GPU with one thread for each element.\n    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);\n\n    // Check for any errors launching the kernel\n    cudaStatus = cudaGetLastError();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addKernel launch failed: %s\\n\", cudaGetErrorString(cudaStatus));\n        goto Error;\n    }\n\n    // cudaDeviceSynchronize waits for the kernel to finish, and returns\n    // any errors encountered during the launch.\n    cudaStatus = cudaDeviceSynchronize();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceSynchronize returned error code %d after launching addKernel!\\n\", cudaStatus);\n        goto Error;\n    }\n\n    // Copy output vector from GPU buffer to host memory.\n    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\nError:\n    cudaFree(dev_c);\n    cudaFree(dev_a);\n    cudaFree(dev_b);\n\n    return cudaStatus;\n}\n"
  },
  {
    "path": "tests/projects/cuda/console_2/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\n-- generate PTX code for the virtual architecture to guarantee compatibility\nadd_cugencodes(\"compute_75\")\n\ntarget(\"bin\")\n    set_kind(\"binary\")\n    add_includedirs(\"inc\")\n    add_files(\"src/*.cu\")\n"
  },
  {
    "path": "tests/projects/cuda/shared/inc/lib.cuh",
    "content": "#pragma once\n\n#include \"cuda_runtime.h\"\n#include \"device_launch_parameters.h\"\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n    __export cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/cuda/shared/src/lib.cu",
    "content": "#include <lib.cuh>\n#include <stdio.h>\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}\n\n// Helper function for using CUDA to add vectors in parallel.\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)\n{\n    int *dev_a = 0;\n    int *dev_b = 0;\n    int *dev_c = 0;\n    cudaError_t cudaStatus;\n\n    // Choose which GPU to run on, change this on a multi-GPU system.\n    cudaStatus = cudaSetDevice(0);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?\");\n        goto Error;\n    }\n\n    // Allocate GPU buffers for three vectors (two input, one output)    .\n    cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    // Copy input vectors from host memory to GPU buffers.\n    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    // Launch a kernel on the GPU with one thread for each element.\n    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);\n\n    // Check for any errors launching the kernel\n    cudaStatus = cudaGetLastError();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addKernel launch failed: %s\\n\", cudaGetErrorString(cudaStatus));\n        goto Error;\n    }\n\n    // cudaDeviceSynchronize waits for the kernel to finish, and returns\n    // any errors encountered during the launch.\n    cudaStatus = cudaDeviceSynchronize();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceSynchronize returned error code %d after launching addKernel!\\n\", cudaStatus);\n        goto Error;\n    }\n\n    // Copy output vector from GPU buffer to host memory.\n    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\nError:\n    cudaFree(dev_c);\n    cudaFree(dev_a);\n    cudaFree(dev_b);\n\n    return cudaStatus;\n}\n"
  },
  {
    "path": "tests/projects/cuda/shared/src/main.cu",
    "content": "\n#include \"cuda_runtime.h\"\n#include <stdio.h>\n#include <lib.cuh>\n\nint main()\n{\n    const int arraySize = 5;\n    const int a[arraySize] = {1, 2, 3, 4, 5};\n    const int b[arraySize] = {10, 20, 30, 40, 50};\n    int c[arraySize] = {0};\n\n    // Add vectors in parallel.\n    cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addWithCuda failed!\");\n        return 1;\n    }\n\n    printf(\"{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\\n\",\n           c[0], c[1], c[2], c[3], c[4]);\n\n    // cudaDeviceReset must be called before exiting in order for profiling and\n    // tracing tools such as Nsight and Visual Profiler to show complete traces.\n    cudaStatus = cudaDeviceReset();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceReset failed!\");\n        return 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/cuda/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\n-- generate PTX code for the virtual architecture to guarantee compatibility\nadd_cugencodes(\"compute_75\")\n\ntarget(\"lib\")\n    set_kind(\"shared\")\n    add_files(\"src/lib.cu\")\n    add_includedirs(\"inc\", {public = true})\n\ntarget(\"bin\")\n    add_deps(\"lib\")\n    set_kind(\"binary\")\n    add_files(\"src/main.cu\")\n"
  },
  {
    "path": "tests/projects/cuda/static/inc/lib.cuh",
    "content": "#pragma once\n\n__global__ void addKernel(int *c, const int *a, const int *b);"
  },
  {
    "path": "tests/projects/cuda/static/src/lib.cu",
    "content": "#include <lib.cuh>\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}"
  },
  {
    "path": "tests/projects/cuda/static/src/main.cu",
    "content": "\n#include \"cuda_runtime.h\"\n#include \"device_launch_parameters.h\"\n\n#include <stdio.h>\n#include <lib.cuh>\n\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);\n\nint main()\n{\n    const int arraySize = 5;\n    const int a[arraySize] = {1, 2, 3, 4, 5};\n    const int b[arraySize] = {10, 20, 30, 40, 50};\n    int c[arraySize] = {0};\n\n    // Add vectors in parallel.\n    cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addWithCuda failed!\");\n        return 1;\n    }\n\n    printf(\"{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\\n\",\n           c[0], c[1], c[2], c[3], c[4]);\n\n    // cudaDeviceReset must be called before exiting in order for profiling and\n    // tracing tools such as Nsight and Visual Profiler to show complete traces.\n    cudaStatus = cudaDeviceReset();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceReset failed!\");\n        return 1;\n    }\n\n    return 0;\n}\n\n// Helper function for using CUDA to add vectors in parallel.\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)\n{\n    int *dev_a = 0;\n    int *dev_b = 0;\n    int *dev_c = 0;\n    cudaError_t cudaStatus;\n\n    // Choose which GPU to run on, change this on a multi-GPU system.\n    cudaStatus = cudaSetDevice(0);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?\");\n        goto Error;\n    }\n\n    // Allocate GPU buffers for three vectors (two input, one output)    .\n    cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    // Copy input vectors from host memory to GPU buffers.\n    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    // Launch a kernel on the GPU with one thread for each element.\n    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);\n\n    // Check for any errors launching the kernel\n    cudaStatus = cudaGetLastError();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addKernel launch failed: %s\\n\", cudaGetErrorString(cudaStatus));\n        goto Error;\n    }\n\n    // cudaDeviceSynchronize waits for the kernel to finish, and returns\n    // any errors encountered during the launch.\n    cudaStatus = cudaDeviceSynchronize();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceSynchronize returned error code %d after launching addKernel!\\n\", cudaStatus);\n        goto Error;\n    }\n\n    // Copy output vector from GPU buffer to host memory.\n    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\nError:\n    cudaFree(dev_c);\n    cudaFree(dev_a);\n    cudaFree(dev_b);\n\n    return cudaStatus;\n}\n"
  },
  {
    "path": "tests/projects/cuda/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\n-- generate PTX code for the virtual architecture to guarantee compatibility\nadd_cugencodes(\"compute_75\")\n\ntarget(\"lib\")\n    set_kind(\"static\")\n    add_includedirs(\"inc\", {public = true})\n    add_files(\"src/lib.cu\")\n\ntarget(\"bin\")\n    add_deps(\"lib\")\n    set_kind(\"binary\")\n    add_files(\"src/main.cu\")\n"
  },
  {
    "path": "tests/projects/dlang/console/src/main.d",
    "content": "import std.stdio;\n\nvoid main()\n{\n    writeln(\"hello world!\");\n}\n"
  },
  {
    "path": "tests/projects/dlang/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.d\")\n\n"
  },
  {
    "path": "tests/projects/dlang/console_with_pkgs/src/main.d",
    "content": "import std.stdio;\nimport std.datetime;\nimport util.log;\nimport dateparser;\n\nvoid main()\n{\n    log = Log(stderrLogger, stdoutLogger(LogLevel.info), fileLogger(\"log\"));\n    log.info(\"hello xmake\");\n\n    assert(parse(\"2003-09-25\") == SysTime(DateTime(2003, 9, 25)));\n    assert(parse(\"09/25/2003\") == SysTime(DateTime(2003, 9, 25)));\n    assert(parse(\"Sep 2003\")   == SysTime(DateTime(2003, 9, 1)));\n}\n"
  },
  {
    "path": "tests/projects/dlang/console_with_pkgs/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"dub::log 0.4.3\", {alias = \"log\"})\nadd_requires(\"dub::dateparser\", {alias = \"dateparser\"})\nadd_requires(\"dub::emsi_containers\", {alias = \"emsi_containers\"})\nadd_requires(\"dub::stdx-allocator\", {alias = \"stdx-allocator\"})\nadd_requires(\"dub::mir-core\", {alias = \"mir-core\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.d\")\n    add_packages(\"log\", \"dateparser\", \"emsi_containers\", \"stdx-allocator\", \"mir-core\")\n\n"
  },
  {
    "path": "tests/projects/dlang/dub_package/src/main.d",
    "content": "import util.log;\n\nvoid main()\n{\n    log = Log(stderrLogger, stdoutLogger(LogLevel.info), fileLogger(\"log\"));\n    log.warn(\"test\");\n}"
  },
  {
    "path": "tests/projects/dlang/dub_package/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"dub::log 0.4.3\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.d\")\n    add_packages(\"dub::log\")"
  },
  {
    "path": "tests/projects/dlang/shared_library/src/interfaces.d",
    "content": "version(Windows) {\n    import core.sys.windows.windows;\n    import core.sys.windows.dll;\n    mixin SimpleDllMain;\n}\n\nextern(C) int add(int a, int b) {\n    return a + b;\n}\n\nextern(C) int sub(int a, int b) {\n    return a - b;\n}\n\n"
  },
  {
    "path": "tests/projects/dlang/shared_library/src/main.d",
    "content": "import std.stdio;\nimport interfaces;\n\nvoid main()\n{\n    printf(\"add: %d\\n\", interfaces.add(1, 1));\n    printf(\"sub: %d\\n\", interfaces.sub(2, 1));\n}\n"
  },
  {
    "path": "tests/projects/dlang/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"interfaces\")\n    set_kind(\"shared\")\n    add_files(\"src/interfaces.d\")\n    add_includedirs(\"src\", {public = true})\n    add_rules(\"utils.symbols.export_list\", {symbols = {\n      \"add\",\n      \"sub\"}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"interfaces\")\n    add_files(\"src/main.d\")\n\n"
  },
  {
    "path": "tests/projects/dlang/static_library/src/interfaces.d",
    "content": "extern(C) int add(int a, int b)\n{\n    return a + b;\n}\n\nextern(C) int sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "tests/projects/dlang/static_library/src/main.d",
    "content": "import std.stdio;\nimport interfaces;\n\nvoid main()\n{\n    printf(\"add: %d\\n\", interfaces.add(1, 1));\n    printf(\"sub: %d\\n\", interfaces.sub(2, 1));\n}\n"
  },
  {
    "path": "tests/projects/dlang/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"interfaces\")\n    set_kind(\"static\")\n    add_files(\"src/interfaces.d\")\n    add_includedirs(\"src\", {public = true})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"interfaces\")\n    add_files(\"src/main.d\")\n\n"
  },
  {
    "path": "tests/projects/embed/c51/hello/src/main.c",
    "content": "#include <reg52.h>\n\n#define REP(i, j) for(i = 0; i < j; ++i)\nsbit control = P3 ^ 2;\n\nvoid delay_ms(unsigned int n) {\n    unsigned int i, j;\n    for (j = n; j > 0; j--)\n        for (i = 112; i > 0; i--);\n}\n\n\nint i;\n\nvoid set(unsigned int x) {\n    P1 = x;\n    delay_ms(100);\n}\n\nvoid left_fill() {\n    REP(i, 8) set(0xFF >> i);\n}\n\nvoid right_fill() {\n    REP(i, 8) set((0xFF >> (7 - i)) ^ 0xFF);\n}\n\nvoid left_erase() {\n    REP(i, 8) set((0xFF >> (7 - i)));\n}\n\nvoid right_erase() {\n    REP(i, 8) set((0xFF >> i) ^ 0xFF);\n}\n\nint main() {\n    P1 = 0xFF;\n    P3 = 0xFF;\n    while (1) {\n        if (control == 0) {\n            left_fill();\n            left_erase();\n            right_fill();\n            right_erase();\n        } else {\n            set(0x55);\n            set(0xAA);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/projects/embed/c51/hello/xmake.lua",
    "content": "target(\"hello\")\n    add_rules(\"c51.binary\")\n    set_toolchains(\"c51\")\n    add_files(\"src/main.c\")\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/foo/foo.c",
    "content": "int foo(int x)\n{\n    return x;\n}\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/gcc_arm.ld",
    "content": "/******************************************************************************\n * @file     gcc_arm.ld\n * @brief    GNU Linker Script for Cortex-M based device\n * @version  V2.1.0\n * @date     04. August 2020\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2020 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n *-------- <<< Use Configuration Wizard in Context Menu >>> -------------------\n */\n\n/*---------------------- Flash Configuration ----------------------------------\n  <h> Flash Configuration\n    <o0> Flash Base Address <0x0-0xFFFFFFFF:8>\n    <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>\n  </h>\n  -----------------------------------------------------------------------------*/\n__ROM_BASE = 0x00000000;\n__ROM_SIZE = 0x00040000;\n\n/*--------------------- Embedded RAM Configuration ----------------------------\n  <h> RAM Configuration\n    <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>\n    <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>\n  </h>\n -----------------------------------------------------------------------------*/\n__RAM_BASE = 0x20000000;\n__RAM_SIZE = 0x00020000;\n\n/*--------------------- Stack / Heap Configuration ----------------------------\n  <h> Stack / Heap Configuration\n    <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>\n    <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>\n  </h>\n  -----------------------------------------------------------------------------*/\n__STACK_SIZE = 0x00000400;\n__HEAP_SIZE  = 0x00000C00;\n\n/*\n *-------------------- <<< end of configuration section >>> -------------------\n */\n\nMEMORY\n{\n  FLASH (rx)  : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE\n  RAM   (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE\n}\n\n/* Linker script to place sections and symbol values. Should be used together\n * with other linker script that defines memory regions FLASH and RAM.\n * It references following symbols, which must be defined in code:\n *   Reset_Handler : Entry of reset handler\n *\n * It defines following symbols, which code can use without definition:\n *   __exidx_start\n *   __exidx_end\n *   __copy_table_start__\n *   __copy_table_end__\n *   __zero_table_start__\n *   __zero_table_end__\n *   __etext\n *   __data_start__\n *   __preinit_array_start\n *   __preinit_array_end\n *   __init_array_start\n *   __init_array_end\n *   __fini_array_start\n *   __fini_array_end\n *   __data_end__\n *   __bss_start__\n *   __bss_end__\n *   __end__\n *   end\n *   __HeapLimit\n *   __StackLimit\n *   __StackTop\n *   __stack\n */\nENTRY(Reset_Handler)\n\nSECTIONS\n{\n  .text :\n  {\n    KEEP(*(.vectors))\n    *(.text*)\n\n    KEEP(*(.init))\n    KEEP(*(.fini))\n\n    /* .ctors */\n    *crtbegin.o(.ctors)\n    *crtbegin?.o(.ctors)\n    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)\n    *(SORT(.ctors.*))\n    *(.ctors)\n\n    /* .dtors */\n    *crtbegin.o(.dtors)\n    *crtbegin?.o(.dtors)\n    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)\n    *(SORT(.dtors.*))\n    *(.dtors)\n\n    *(.rodata*)\n\n    KEEP(*(.eh_frame*))\n  } > FLASH\n\n  /*\n   * SG veneers:\n   * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address\n   * must be set, either with the command line option --section-start or in a linker script,\n   * to indicate where to place these veneers in memory.\n   */\n/*\n  .gnu.sgstubs :\n  {\n    . = ALIGN(32);\n  } > FLASH\n*/\n  .ARM.extab :\n  {\n    *(.ARM.extab* .gnu.linkonce.armextab.*)\n  } > FLASH\n\n  __exidx_start = .;\n  .ARM.exidx :\n  {\n    *(.ARM.exidx* .gnu.linkonce.armexidx.*)\n  } > FLASH\n  __exidx_end = .;\n\n  .copy.table :\n  {\n    . = ALIGN(4);\n    __copy_table_start__ = .;\n\n    LONG (__etext)\n    LONG (__data_start__)\n    LONG ((__data_end__ - __data_start__) / 4)\n\n    /* Add each additional data section here */\n/*\n    LONG (__etext2)\n    LONG (__data2_start__)\n    LONG ((__data2_end__ - __data2_start__) / 4)\n*/\n    __copy_table_end__ = .;\n  } > FLASH\n\n  .zero.table :\n  {\n    . = ALIGN(4);\n    __zero_table_start__ = .;\n    /* Add each additional bss section here */\n/*\n    LONG (__bss2_start__)\n    LONG ((__bss2_end__ - __bss2_start__) / 4)\n*/\n    __zero_table_end__ = .;\n  } > FLASH\n\n  /**\n   * Location counter can end up 2byte aligned with narrow Thumb code but\n   * __etext is assumed by startup code to be the LMA of a section in RAM\n   * which must be 4byte aligned \n   */\n  __etext = ALIGN (4);\n\n  .data : AT (__etext)\n  {\n    __data_start__ = .;\n    *(vtable)\n    *(.data)\n    *(.data.*)\n\n    . = ALIGN(4);\n    /* preinit data */\n    PROVIDE_HIDDEN (__preinit_array_start = .);\n    KEEP(*(.preinit_array))\n    PROVIDE_HIDDEN (__preinit_array_end = .);\n\n    . = ALIGN(4);\n    /* init data */\n    PROVIDE_HIDDEN (__init_array_start = .);\n    KEEP(*(SORT(.init_array.*)))\n    KEEP(*(.init_array))\n    PROVIDE_HIDDEN (__init_array_end = .);\n\n    . = ALIGN(4);\n    /* finit data */\n    PROVIDE_HIDDEN (__fini_array_start = .);\n    KEEP(*(SORT(.fini_array.*)))\n    KEEP(*(.fini_array))\n    PROVIDE_HIDDEN (__fini_array_end = .);\n\n    KEEP(*(.jcr*))\n    . = ALIGN(4);\n    /* All data end */\n    __data_end__ = .;\n\n  } > RAM\n\n  /*\n   * Secondary data section, optional\n   *\n   * Remember to add each additional data section\n   * to the .copy.table above to asure proper\n   * initialization during startup.\n   */\n/*\n  __etext2 = ALIGN (4);\n\n  .data2 : AT (__etext2)\n  {\n    . = ALIGN(4);\n    __data2_start__ = .;\n    *(.data2)\n    *(.data2.*)\n    . = ALIGN(4);\n    __data2_end__ = .;\n\n  } > RAM2\n*/\n\n  .bss :\n  {\n    . = ALIGN(4);\n    __bss_start__ = .;\n    *(.bss)\n    *(.bss.*)\n    *(COMMON)\n    . = ALIGN(4);\n    __bss_end__ = .;\n  } > RAM AT > RAM\n\n  /*\n   * Secondary bss section, optional\n   *\n   * Remember to add each additional bss section\n   * to the .zero.table above to asure proper\n   * initialization during startup.\n   */\n/*\n  .bss2 :\n  {\n    . = ALIGN(4);\n    __bss2_start__ = .;\n    *(.bss2)\n    *(.bss2.*)\n    . = ALIGN(4);\n    __bss2_end__ = .;\n  } > RAM2 AT > RAM2\n*/\n\n  .heap (COPY) :\n  {\n    . = ALIGN(8);\n    __end__ = .;\n    PROVIDE(end = .);\n    . = . + __HEAP_SIZE;\n    . = ALIGN(8);\n    __HeapLimit = .;\n  } > RAM\n\n  .stack (ORIGIN(RAM) + LENGTH(RAM) - __STACK_SIZE) (COPY) :\n  {\n    . = ALIGN(8);\n    __StackLimit = .;\n    . = . + __STACK_SIZE;\n    . = ALIGN(8);\n    __StackTop = .;\n  } > RAM\n  PROVIDE(__stack = __StackTop);\n\n  /* Check if data + heap + stack exceeds RAM limit */\n  ASSERT(__StackLimit >= __HeapLimit, \"region RAM overflowed with stack\")\n}\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/ARMCM3.h",
    "content": "/**************************************************************************//**\n * @file     ARMCM3.h\n * @brief    CMSIS Core Peripheral Access Layer Header File for\n *           ARMCM3 Device\n * @version  V5.3.1\n * @date     09. July 2018\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2018 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ARMCM3_H\n#define ARMCM3_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/* -------------------------  Interrupt Number Definition  ------------------------ */\n\ntypedef enum IRQn\n{\n/* -------------------  Processor Exceptions Numbers  ----------------------------- */\n  NonMaskableInt_IRQn           = -14,     /*  2 Non Maskable Interrupt */\n  HardFault_IRQn                = -13,     /*  3 HardFault Interrupt */\n  MemoryManagement_IRQn         = -12,     /*  4 Memory Management Interrupt */\n  BusFault_IRQn                 = -11,     /*  5 Bus Fault Interrupt */\n  UsageFault_IRQn               = -10,     /*  6 Usage Fault Interrupt */\n  SVCall_IRQn                   =  -5,     /* 11 SV Call Interrupt */\n  DebugMonitor_IRQn             =  -4,     /* 12 Debug Monitor Interrupt */\n  PendSV_IRQn                   =  -2,     /* 14 Pend SV Interrupt */\n  SysTick_IRQn                  =  -1,     /* 15 System Tick Interrupt */\n\n/* -------------------  Processor Interrupt Numbers  ------------------------------ */\n  Interrupt0_IRQn               =   0,\n  Interrupt1_IRQn               =   1,\n  Interrupt2_IRQn               =   2,\n  Interrupt3_IRQn               =   3,\n  Interrupt4_IRQn               =   4,\n  Interrupt5_IRQn               =   5,\n  Interrupt6_IRQn               =   6,\n  Interrupt7_IRQn               =   7,\n  Interrupt8_IRQn               =   8,\n  Interrupt9_IRQn               =   9\n  /* Interrupts 10 .. 224 are left out */\n} IRQn_Type;\n\n\n/* ================================================================================ */\n/* ================      Processor and Core Peripheral Section     ================ */\n/* ================================================================================ */\n\n/* -------  Start of section using anonymous unions and disabling warnings  ------- */\n#if   defined (__CC_ARM)\n  #pragma push\n  #pragma anon_unions\n#elif defined (__ICCARM__)\n  #pragma language=extended\n#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wc11-extensions\"\n  #pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#elif defined (__GNUC__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TMS470__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TASKING__)\n  #pragma warning 586\n#elif defined (__CSMC__)\n  /* anonymous unions are enabled by default */\n#else\n  #warning Not supported compiler type\n#endif\n\n\n/* --------  Configuration of Core Peripherals  ----------------------------------- */\n#define __CM3_REV                 0x0201U   /* Core revision r2p1 */\n#define __MPU_PRESENT             1U        /* MPU present */\n#define __VTOR_PRESENT            1U        /* VTOR present */\n#define __NVIC_PRIO_BITS          3U        /* Number of Bits used for Priority Levels */\n#define __Vendor_SysTickConfig    0U        /* Set to 1 if different SysTick Config is used */\n\n#include \"core_cm3.h\"                       /* Processor and core peripherals */\n#include \"system_ARMCM3.h\"                  /* System Header */\n\n\n/* --------  End of section using anonymous unions and disabling warnings  -------- */\n#if   defined (__CC_ARM)\n  #pragma pop\n#elif defined (__ICCARM__)\n  /* leave anonymous unions enabled */\n#elif (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))\n  #pragma clang diagnostic pop\n#elif defined (__GNUC__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TMS470__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TASKING__)\n  #pragma warning restore\n#elif defined (__CSMC__)\n  /* anonymous unions are enabled by default */\n#else\n  #warning Not supported compiler type\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  /* ARMCM3_H */\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_compiler.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_compiler.h\n * @brief    CMSIS compiler generic header file\n * @version  V5.1.0\n * @date     09. October 2018\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2018 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __CMSIS_COMPILER_H\n#define __CMSIS_COMPILER_H\n\n#include <stdint.h>\n\n/*\n * Arm Compiler 4/5\n */\n#if   defined ( __CC_ARM )\n  #include \"cmsis_armcc.h\"\n\n\n/*\n * Arm Compiler 6.6 LTM (armclang)\n */\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100)\n  #include \"cmsis_armclang_ltm.h\"\n\n  /*\n * Arm Compiler above 6.10.1 (armclang)\n */\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)\n  #include \"cmsis_armclang.h\"\n\n\n/*\n * GNU Compiler\n */\n#elif defined ( __GNUC__ )\n  #include \"cmsis_gcc.h\"\n\n\n/*\n * IAR Compiler\n */\n#elif defined ( __ICCARM__ )\n  #include <cmsis_iccarm.h>\n\n\n/*\n * TI Arm Compiler\n */\n#elif defined ( __TI_ARM__ )\n  #include <cmsis_ccs.h>\n\n  #ifndef   __ASM\n    #define __ASM                                  __asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    #define __NO_RETURN                            __attribute__((noreturn))\n  #endif\n  #ifndef   __USED\n    #define __USED                                 __attribute__((used))\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __attribute__((weak))\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               __attribute__((packed))\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        struct __attribute__((packed))\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         union __attribute__((packed))\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    struct __attribute__((packed)) T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #define __ALIGNED(x)                           __attribute__((aligned(x)))\n  #endif\n  #ifndef   __RESTRICT\n    #define __RESTRICT                             __restrict\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n/*\n * TASKING Compiler\n */\n#elif defined ( __TASKING__ )\n  /*\n   * The CMSIS functions have been implemented as intrinsics in the compiler.\n   * Please use \"carm -?i\" to get an up to date list of all intrinsics,\n   * Including the CMSIS ones.\n   */\n\n  #ifndef   __ASM\n    #define __ASM                                  __asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    #define __NO_RETURN                            __attribute__((noreturn))\n  #endif\n  #ifndef   __USED\n    #define __USED                                 __attribute__((used))\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __attribute__((weak))\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               __packed__\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        struct __packed__\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         union __packed__\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    struct __packed__ T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #define __ALIGNED(x)              __align(x)\n  #endif\n  #ifndef   __RESTRICT\n    #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.\n    #define __RESTRICT\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n/*\n * COSMIC Compiler\n */\n#elif defined ( __CSMC__ )\n   #include <cmsis_csm.h>\n\n #ifndef   __ASM\n    #define __ASM                                  _asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    // NO RETURN is automatically detected hence no warning here\n    #define __NO_RETURN\n  #endif\n  #ifndef   __USED\n    #warning No compiler specific solution for __USED. __USED is ignored.\n    #define __USED\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __weak\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               @packed\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        @packed struct\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         @packed union\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    @packed struct T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.\n    #define __ALIGNED(x)\n  #endif\n  #ifndef   __RESTRICT\n    #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.\n    #define __RESTRICT\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n#else\n  #error Unknown compiler.\n#endif\n\n\n#endif /* __CMSIS_COMPILER_H */\n\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_gcc.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_gcc.h\n * @brief    CMSIS compiler GCC header file\n * @version  V5.4.1\n * @date     27. May 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __CMSIS_GCC_H\n#define __CMSIS_GCC_H\n\n/* ignore some GCC warnings */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wsign-conversion\"\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n\n/* Fallback for __has_builtin */\n#ifndef __has_builtin\n  #define __has_builtin(x) (0)\n#endif\n\n/* CMSIS compiler specific defines */\n#ifndef   __ASM\n  #define __ASM                                  __asm\n#endif\n#ifndef   __INLINE\n  #define __INLINE                               inline\n#endif\n#ifndef   __STATIC_INLINE\n  #define __STATIC_INLINE                        static inline\n#endif\n#ifndef   __STATIC_FORCEINLINE\n  #define __STATIC_FORCEINLINE                   __attribute__((always_inline)) static inline\n#endif\n#ifndef   __NO_RETURN\n  #define __NO_RETURN                            __attribute__((__noreturn__))\n#endif\n#ifndef   __USED\n  #define __USED                                 __attribute__((used))\n#endif\n#ifndef   __WEAK\n  #define __WEAK                                 __attribute__((weak))\n#endif\n#ifndef   __PACKED\n  #define __PACKED                               __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __PACKED_STRUCT\n  #define __PACKED_STRUCT                        struct __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __PACKED_UNION\n  #define __PACKED_UNION                         union __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __UNALIGNED_UINT32        /* deprecated */\n  #pragma GCC diagnostic push\n  #pragma GCC diagnostic ignored \"-Wpacked\"\n  #pragma GCC diagnostic ignored \"-Wattributes\"\n  struct __attribute__((packed)) T_UINT32 { uint32_t v; };\n  #pragma GCC diagnostic pop\n  #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n#endif\n#ifndef   __UNALIGNED_UINT16_WRITE\n  #pragma GCC diagnostic push\n  #pragma GCC diagnostic ignored \"-Wpacked\"\n  #pragma GCC diagnostic ignored \"-Wattributes\"\n  __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n  #pragma GCC diagnostic pop\n  #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT16_READ\n  #pragma GCC diagnostic push\n  #pragma GCC diagnostic ignored \"-Wpacked\"\n  #pragma GCC diagnostic ignored \"-Wattributes\"\n  __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n  #pragma GCC diagnostic pop\n  #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n#endif\n#ifndef   __UNALIGNED_UINT32_WRITE\n  #pragma GCC diagnostic push\n  #pragma GCC diagnostic ignored \"-Wpacked\"\n  #pragma GCC diagnostic ignored \"-Wattributes\"\n  __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n  #pragma GCC diagnostic pop\n  #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT32_READ\n  #pragma GCC diagnostic push\n  #pragma GCC diagnostic ignored \"-Wpacked\"\n  #pragma GCC diagnostic ignored \"-Wattributes\"\n  __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n  #pragma GCC diagnostic pop\n  #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n#endif\n#ifndef   __ALIGNED\n  #define __ALIGNED(x)                           __attribute__((aligned(x)))\n#endif\n#ifndef   __RESTRICT\n  #define __RESTRICT                             __restrict\n#endif\n#ifndef   __COMPILER_BARRIER\n  #define __COMPILER_BARRIER()                   __ASM volatile(\"\":::\"memory\")\n#endif\n\n/* #########################  Startup and Lowlevel Init  ######################## */\n\n#ifndef __PROGRAM_START\n\n/**\n  \\brief   Initializes data and bss sections\n  \\details This default implementations initialized all data and additional bss\n           sections relying on .copy.table and .zero.table specified properly\n           in the used linker script.\n\n */\n__STATIC_FORCEINLINE __NO_RETURN void __cmsis_start(void)\n{\n  extern void _start(void) __NO_RETURN;\n\n  typedef struct {\n    uint32_t const* src;\n    uint32_t* dest;\n    uint32_t  wlen;\n  } __copy_table_t;\n\n  typedef struct {\n    uint32_t* dest;\n    uint32_t  wlen;\n  } __zero_table_t;\n\n  extern const __copy_table_t __copy_table_start__;\n  extern const __copy_table_t __copy_table_end__;\n  extern const __zero_table_t __zero_table_start__;\n  extern const __zero_table_t __zero_table_end__;\n\n  for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {\n    for(uint32_t i=0u; i<pTable->wlen; ++i) {\n      pTable->dest[i] = pTable->src[i];\n    }\n  }\n\n  for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {\n    for(uint32_t i=0u; i<pTable->wlen; ++i) {\n      pTable->dest[i] = 0u;\n    }\n  }\n\n  _start();\n}\n\n#define __PROGRAM_START           __cmsis_start\n#endif\n\n#ifndef __INITIAL_SP\n#define __INITIAL_SP              __StackTop\n#endif\n\n#ifndef __STACK_LIMIT\n#define __STACK_LIMIT             __StackLimit\n#endif\n\n#ifndef __VECTOR_TABLE\n#define __VECTOR_TABLE            __Vectors\n#endif\n\n#ifndef __VECTOR_TABLE_ATTRIBUTE\n#define __VECTOR_TABLE_ATTRIBUTE  __attribute__((used, section(\".vectors\")))\n#endif\n\n#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)\n#ifndef __STACK_SEAL\n#define __STACK_SEAL              __StackSeal\n#endif\n\n#ifndef __TZ_STACK_SEAL_SIZE\n#define __TZ_STACK_SEAL_SIZE      8U\n#endif\n\n#ifndef __TZ_STACK_SEAL_VALUE\n#define __TZ_STACK_SEAL_VALUE     0xFEF5EDA5FEF5EDA5ULL\n#endif\n\n\n__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) {\n  *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE;\n}\n#endif\n\n\n/* ##########################  Core Instruction Access  ######################### */\n/** \\defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface\n  Access to dedicated instructions\n  @{\n*/\n\n/* Define macros for porting to both thumb1 and thumb2.\n * For thumb1, use low register (r0-r7), specified by constraint \"l\"\n * Otherwise, use general registers, specified by constraint \"r\" */\n#if defined (__thumb__) && !defined (__thumb2__)\n#define __CMSIS_GCC_OUT_REG(r) \"=l\" (r)\n#define __CMSIS_GCC_RW_REG(r) \"+l\" (r)\n#define __CMSIS_GCC_USE_REG(r) \"l\" (r)\n#else\n#define __CMSIS_GCC_OUT_REG(r) \"=r\" (r)\n#define __CMSIS_GCC_RW_REG(r) \"+r\" (r)\n#define __CMSIS_GCC_USE_REG(r) \"r\" (r)\n#endif\n\n/**\n  \\brief   No Operation\n  \\details No Operation does nothing. This instruction can be used for code alignment purposes.\n */\n#define __NOP()                             __ASM volatile (\"nop\")\n\n/**\n  \\brief   Wait For Interrupt\n  \\details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.\n */\n#define __WFI()                             __ASM volatile (\"wfi\":::\"memory\")\n\n\n/**\n  \\brief   Wait For Event\n  \\details Wait For Event is a hint instruction that permits the processor to enter\n           a low-power state until one of a number of events occurs.\n */\n#define __WFE()                             __ASM volatile (\"wfe\":::\"memory\")\n\n\n/**\n  \\brief   Send Event\n  \\details Send Event is a hint instruction. It causes an event to be signaled to the CPU.\n */\n#define __SEV()                             __ASM volatile (\"sev\")\n\n\n/**\n  \\brief   Instruction Synchronization Barrier\n  \\details Instruction Synchronization Barrier flushes the pipeline in the processor,\n           so that all instructions following the ISB are fetched from cache or memory,\n           after the instruction has been completed.\n */\n__STATIC_FORCEINLINE void __ISB(void)\n{\n  __ASM volatile (\"isb 0xF\":::\"memory\");\n}\n\n\n/**\n  \\brief   Data Synchronization Barrier\n  \\details Acts as a special kind of Data Memory Barrier.\n           It completes when all explicit memory accesses before this instruction complete.\n */\n__STATIC_FORCEINLINE void __DSB(void)\n{\n  __ASM volatile (\"dsb 0xF\":::\"memory\");\n}\n\n\n/**\n  \\brief   Data Memory Barrier\n  \\details Ensures the apparent order of the explicit memory operations before\n           and after the instruction, without ensuring their completion.\n */\n__STATIC_FORCEINLINE void __DMB(void)\n{\n  __ASM volatile (\"dmb 0xF\":::\"memory\");\n}\n\n\n/**\n  \\brief   Reverse byte order (32 bit)\n  \\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n__STATIC_FORCEINLINE uint32_t __REV(uint32_t value)\n{\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)\n  return __builtin_bswap32(value);\n#else\n  uint32_t result;\n\n  __ASM (\"rev %0, %1\" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );\n  return result;\n#endif\n}\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value)\n{\n  uint32_t result;\n\n  __ASM (\"rev16 %0, %1\" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );\n  return result;\n}\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n__STATIC_FORCEINLINE int16_t __REVSH(int16_t value)\n{\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n  return (int16_t)__builtin_bswap16(value);\n#else\n  int16_t result;\n\n  __ASM (\"revsh %0, %1\" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );\n  return result;\n#endif\n}\n\n\n/**\n  \\brief   Rotate Right in unsigned value (32 bit)\n  \\details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.\n  \\param [in]    op1  Value to rotate\n  \\param [in]    op2  Number of Bits to rotate\n  \\return               Rotated value\n */\n__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)\n{\n  op2 %= 32U;\n  if (op2 == 0U)\n  {\n    return op1;\n  }\n  return (op1 >> op2) | (op1 << (32U - op2));\n}\n\n\n/**\n  \\brief   Breakpoint\n  \\details Causes the processor to enter Debug state.\n           Debug tools can use this to investigate system state when the instruction at a particular address is reached.\n  \\param [in]    value  is ignored by the processor.\n                 If required, a debugger can use it to store additional information about the breakpoint.\n */\n#define __BKPT(value)                       __ASM volatile (\"bkpt \"#value)\n\n\n/**\n  \\brief   Reverse bit order of value\n  \\details Reverses the bit order of the given value.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n__STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value)\n{\n  uint32_t result;\n\n#if ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n     (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    )\n   __ASM (\"rbit %0, %1\" : \"=r\" (result) : \"r\" (value) );\n#else\n  uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */\n\n  result = value;                      /* r will be reversed bits of v; first get LSB of v */\n  for (value >>= 1U; value != 0U; value >>= 1U)\n  {\n    result <<= 1U;\n    result |= value & 1U;\n    s--;\n  }\n  result <<= s;                        /* shift when v's highest bits are zero */\n#endif\n  return result;\n}\n\n\n/**\n  \\brief   Count leading zeros\n  \\details Counts the number of leading zeros of a data value.\n  \\param [in]  value  Value to count the leading zeros\n  \\return             number of leading zeros in value\n */\n__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value)\n{\n  /* Even though __builtin_clz produces a CLZ instruction on ARM, formally\n     __builtin_clz(0) is undefined behaviour, so handle this case specially.\n     This guarantees ARM-compatible results if happening to compile on a non-ARM\n     target, and ensures the compiler doesn't decide to activate any\n     optimisations using the logic \"value was passed to __builtin_clz, so it\n     is non-zero\".\n     ARM GCC 7.3 and possibly earlier will optimise this test away, leaving a\n     single CLZ instruction.\n   */\n  if (value == 0U)\n  {\n    return 32U;\n  }\n  return __builtin_clz(value);\n}\n\n\n#if ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n     (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    )\n/**\n  \\brief   LDR Exclusive (8 bit)\n  \\details Executes a exclusive LDR instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr)\n{\n    uint32_t result;\n\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n   __ASM volatile (\"ldrexb %0, %1\" : \"=r\" (result) : \"Q\" (*addr) );\n#else\n    /* Prior to GCC 4.8, \"Q\" will be expanded to [rx, #0] which is not\n       accepted by assembler. So has to use following less efficient pattern.\n    */\n   __ASM volatile (\"ldrexb %0, [%1]\" : \"=r\" (result) : \"r\" (addr) : \"memory\" );\n#endif\n   return ((uint8_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDR Exclusive (16 bit)\n  \\details Executes a exclusive LDR instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr)\n{\n    uint32_t result;\n\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n   __ASM volatile (\"ldrexh %0, %1\" : \"=r\" (result) : \"Q\" (*addr) );\n#else\n    /* Prior to GCC 4.8, \"Q\" will be expanded to [rx, #0] which is not\n       accepted by assembler. So has to use following less efficient pattern.\n    */\n   __ASM volatile (\"ldrexh %0, [%1]\" : \"=r\" (result) : \"r\" (addr) : \"memory\" );\n#endif\n   return ((uint16_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDR Exclusive (32 bit)\n  \\details Executes a exclusive LDR instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldrex %0, %1\" : \"=r\" (result) : \"Q\" (*addr) );\n   return(result);\n}\n\n\n/**\n  \\brief   STR Exclusive (8 bit)\n  \\details Executes a exclusive STR instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"strexb %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*addr) : \"r\" ((uint32_t)value) );\n   return(result);\n}\n\n\n/**\n  \\brief   STR Exclusive (16 bit)\n  \\details Executes a exclusive STR instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"strexh %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*addr) : \"r\" ((uint32_t)value) );\n   return(result);\n}\n\n\n/**\n  \\brief   STR Exclusive (32 bit)\n  \\details Executes a exclusive STR instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"strex %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*addr) : \"r\" (value) );\n   return(result);\n}\n\n\n/**\n  \\brief   Remove the exclusive lock\n  \\details Removes the exclusive lock which is created by LDREX.\n */\n__STATIC_FORCEINLINE void __CLREX(void)\n{\n  __ASM volatile (\"clrex\" ::: \"memory\");\n}\n\n#endif /* ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n           (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    ) */\n\n\n#if ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n     (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    )\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  ARG1  Value to be saturated\n  \\param [in]  ARG2  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n#define __SSAT(ARG1, ARG2) \\\n__extension__ \\\n({                          \\\n  int32_t __RES, __ARG1 = (ARG1); \\\n  __ASM volatile (\"ssat %0, %1, %2\" : \"=r\" (__RES) :  \"I\" (ARG2), \"r\" (__ARG1) : \"cc\" ); \\\n  __RES; \\\n })\n\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  ARG1  Value to be saturated\n  \\param [in]  ARG2  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n#define __USAT(ARG1, ARG2) \\\n__extension__ \\\n({                          \\\n  uint32_t __RES, __ARG1 = (ARG1); \\\n  __ASM volatile (\"usat %0, %1, %2\" : \"=r\" (__RES) :  \"I\" (ARG2), \"r\" (__ARG1) : \"cc\" ); \\\n  __RES; \\\n })\n\n\n/**\n  \\brief   Rotate Right with Extend (32 bit)\n  \\details Moves each bit of a bitstring right by one bit.\n           The carry input is shifted in at the left end of the bitstring.\n  \\param [in]    value  Value to rotate\n  \\return               Rotated value\n */\n__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value)\n{\n  uint32_t result;\n\n  __ASM volatile (\"rrx %0, %1\" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );\n  return(result);\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged LDRT instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr)\n{\n    uint32_t result;\n\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n   __ASM volatile (\"ldrbt %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n#else\n    /* Prior to GCC 4.8, \"Q\" will be expanded to [rx, #0] which is not\n       accepted by assembler. So has to use following less efficient pattern.\n    */\n   __ASM volatile (\"ldrbt %0, [%1]\" : \"=r\" (result) : \"r\" (ptr) : \"memory\" );\n#endif\n   return ((uint8_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged LDRT instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr)\n{\n    uint32_t result;\n\n#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n   __ASM volatile (\"ldrht %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n#else\n    /* Prior to GCC 4.8, \"Q\" will be expanded to [rx, #0] which is not\n       accepted by assembler. So has to use following less efficient pattern.\n    */\n   __ASM volatile (\"ldrht %0, [%1]\" : \"=r\" (result) : \"r\" (ptr) : \"memory\" );\n#endif\n   return ((uint16_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged LDRT instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldrt %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n   return(result);\n}\n\n\n/**\n  \\brief   STRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged STRT instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr)\n{\n   __ASM volatile (\"strbt %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) );\n}\n\n\n/**\n  \\brief   STRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged STRT instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr)\n{\n   __ASM volatile (\"strht %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) );\n}\n\n\n/**\n  \\brief   STRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged STRT instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr)\n{\n   __ASM volatile (\"strt %1, %0\" : \"=Q\" (*ptr) : \"r\" (value) );\n}\n\n#else  /* ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n           (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    ) */\n\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat)\n{\n  if ((sat >= 1U) && (sat <= 32U))\n  {\n    const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U);\n    const int32_t min = -1 - max ;\n    if (val > max)\n    {\n      return max;\n    }\n    else if (val < min)\n    {\n      return min;\n    }\n  }\n  return val;\n}\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat)\n{\n  if (sat <= 31U)\n  {\n    const uint32_t max = ((1U << sat) - 1U);\n    if (val > (int32_t)max)\n    {\n      return max;\n    }\n    else if (val < 0)\n    {\n      return 0U;\n    }\n  }\n  return (uint32_t)val;\n}\n\n#endif /* ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n           (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    ) */\n\n\n#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    )\n/**\n  \\brief   Load-Acquire (8 bit)\n  \\details Executes a LDAB instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldab %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return ((uint8_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire (16 bit)\n  \\details Executes a LDAH instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldah %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return ((uint16_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire (32 bit)\n  \\details Executes a LDA instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"lda %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return(result);\n}\n\n\n/**\n  \\brief   Store-Release (8 bit)\n  \\details Executes a STLB instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr)\n{\n   __ASM volatile (\"stlb %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Store-Release (16 bit)\n  \\details Executes a STLH instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr)\n{\n   __ASM volatile (\"stlh %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Store-Release (32 bit)\n  \\details Executes a STL instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr)\n{\n   __ASM volatile (\"stl %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Load-Acquire Exclusive (8 bit)\n  \\details Executes a LDAB exclusive instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldaexb %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return ((uint8_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire Exclusive (16 bit)\n  \\details Executes a LDAH exclusive instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldaexh %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return ((uint16_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire Exclusive (32 bit)\n  \\details Executes a LDA exclusive instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr)\n{\n    uint32_t result;\n\n   __ASM volatile (\"ldaex %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n   return(result);\n}\n\n\n/**\n  \\brief   Store-Release Exclusive (8 bit)\n  \\details Executes a STLB exclusive instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"stlexb %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n   return(result);\n}\n\n\n/**\n  \\brief   Store-Release Exclusive (16 bit)\n  \\details Executes a STLH exclusive instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"stlexh %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n   return(result);\n}\n\n\n/**\n  \\brief   Store-Release Exclusive (32 bit)\n  \\details Executes a STL exclusive instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n__STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr)\n{\n   uint32_t result;\n\n   __ASM volatile (\"stlex %0, %2, %1\" : \"=&r\" (result), \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n   return(result);\n}\n\n#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    ) */\n\n/*@}*/ /* end of group CMSIS_Core_InstructionInterface */\n\n\n/* ###########################  Core Function Access  ########################### */\n/** \\ingroup  CMSIS_Core_FunctionInterface\n    \\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions\n  @{\n */\n\n/**\n  \\brief   Enable IRQ Interrupts\n  \\details Enables IRQ interrupts by clearing special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __enable_irq(void)\n{\n  __ASM volatile (\"cpsie i\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Disable IRQ Interrupts\n  \\details Disables IRQ interrupts by setting special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __disable_irq(void)\n{\n  __ASM volatile (\"cpsid i\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Get Control Register\n  \\details Returns the content of the Control Register.\n  \\return               Control Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_CONTROL(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, control\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Control Register (non-secure)\n  \\details Returns the content of the non-secure Control Register when in secure mode.\n  \\return               non-secure Control Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, control_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Control Register\n  \\details Writes the given value to the Control Register.\n  \\param [in]    control  Control Register value to set\n */\n__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control)\n{\n  __ASM volatile (\"MSR control, %0\" : : \"r\" (control) : \"memory\");\n  __ISB();\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Control Register (non-secure)\n  \\details Writes the given value to the non-secure Control Register when in secure state.\n  \\param [in]    control  Control Register value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control)\n{\n  __ASM volatile (\"MSR control_ns, %0\" : : \"r\" (control) : \"memory\");\n  __ISB();\n}\n#endif\n\n\n/**\n  \\brief   Get IPSR Register\n  \\details Returns the content of the IPSR Register.\n  \\return               IPSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_IPSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, ipsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get APSR Register\n  \\details Returns the content of the APSR Register.\n  \\return               APSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_APSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, apsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get xPSR Register\n  \\details Returns the content of the xPSR Register.\n  \\return               xPSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_xPSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, xpsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get Process Stack Pointer\n  \\details Returns the current value of the Process Stack Pointer (PSP).\n  \\return               PSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_PSP(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, psp\"  : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Process Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state.\n  \\return               PSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, psp_ns\"  : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Process Stack Pointer\n  \\details Assigns the given value to the Process Stack Pointer (PSP).\n  \\param [in]    topOfProcStack  Process Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack)\n{\n  __ASM volatile (\"MSR psp, %0\" : : \"r\" (topOfProcStack) : );\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Process Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state.\n  \\param [in]    topOfProcStack  Process Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack)\n{\n  __ASM volatile (\"MSR psp_ns, %0\" : : \"r\" (topOfProcStack) : );\n}\n#endif\n\n\n/**\n  \\brief   Get Main Stack Pointer\n  \\details Returns the current value of the Main Stack Pointer (MSP).\n  \\return               MSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_MSP(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, msp\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Main Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state.\n  \\return               MSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, msp_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Main Stack Pointer\n  \\details Assigns the given value to the Main Stack Pointer (MSP).\n  \\param [in]    topOfMainStack  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack)\n{\n  __ASM volatile (\"MSR msp, %0\" : : \"r\" (topOfMainStack) : );\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Main Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state.\n  \\param [in]    topOfMainStack  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack)\n{\n  __ASM volatile (\"MSR msp_ns, %0\" : : \"r\" (topOfMainStack) : );\n}\n#endif\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Stack Pointer (SP) when in secure state.\n  \\return               SP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, sp_ns\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Set Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state.\n  \\param [in]    topOfStack  Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack)\n{\n  __ASM volatile (\"MSR sp_ns, %0\" : : \"r\" (topOfStack) : );\n}\n#endif\n\n\n/**\n  \\brief   Get Priority Mask\n  \\details Returns the current state of the priority mask bit from the Priority Mask Register.\n  \\return               Priority Mask value\n */\n__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, primask\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Priority Mask (non-secure)\n  \\details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state.\n  \\return               Priority Mask value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, primask_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Priority Mask\n  \\details Assigns the given value to the Priority Mask Register.\n  \\param [in]    priMask  Priority Mask\n */\n__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask)\n{\n  __ASM volatile (\"MSR primask, %0\" : : \"r\" (priMask) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Priority Mask (non-secure)\n  \\details Assigns the given value to the non-secure Priority Mask Register when in secure state.\n  \\param [in]    priMask  Priority Mask\n */\n__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask)\n{\n  __ASM volatile (\"MSR primask_ns, %0\" : : \"r\" (priMask) : \"memory\");\n}\n#endif\n\n\n#if ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n     (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    )\n/**\n  \\brief   Enable FIQ\n  \\details Enables FIQ interrupts by clearing special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __enable_fault_irq(void)\n{\n  __ASM volatile (\"cpsie f\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Disable FIQ\n  \\details Disables FIQ interrupts by setting special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __disable_fault_irq(void)\n{\n  __ASM volatile (\"cpsid f\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Get Base Priority\n  \\details Returns the current value of the Base Priority register.\n  \\return               Base Priority register value\n */\n__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, basepri\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Base Priority (non-secure)\n  \\details Returns the current value of the non-secure Base Priority register when in secure state.\n  \\return               Base Priority register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, basepri_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Base Priority\n  \\details Assigns the given value to the Base Priority register.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri, %0\" : : \"r\" (basePri) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Base Priority (non-secure)\n  \\details Assigns the given value to the non-secure Base Priority register when in secure state.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri_ns, %0\" : : \"r\" (basePri) : \"memory\");\n}\n#endif\n\n\n/**\n  \\brief   Set Base Priority with condition\n  \\details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled,\n           or the new value increases the BASEPRI priority level.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri_max, %0\" : : \"r\" (basePri) : \"memory\");\n}\n\n\n/**\n  \\brief   Get Fault Mask\n  \\details Returns the current value of the Fault Mask register.\n  \\return               Fault Mask register value\n */\n__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, faultmask\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Fault Mask (non-secure)\n  \\details Returns the current value of the non-secure Fault Mask register when in secure state.\n  \\return               Fault Mask register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, faultmask_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Fault Mask\n  \\details Assigns the given value to the Fault Mask register.\n  \\param [in]    faultMask  Fault Mask value to set\n */\n__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask)\n{\n  __ASM volatile (\"MSR faultmask, %0\" : : \"r\" (faultMask) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Fault Mask (non-secure)\n  \\details Assigns the given value to the non-secure Fault Mask register when in secure state.\n  \\param [in]    faultMask  Fault Mask value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask)\n{\n  __ASM volatile (\"MSR faultmask_ns, %0\" : : \"r\" (faultMask) : \"memory\");\n}\n#endif\n\n#endif /* ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \\\n           (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    ) */\n\n\n#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    )\n\n/**\n  \\brief   Get Process Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always in non-secure\n  mode.\n\n  \\details Returns the current value of the Process Stack Pointer Limit (PSPLIM).\n  \\return               PSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n    // without main extensions, the non-secure PSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, psplim\"  : \"=r\" (result) );\n  return result;\n#endif\n}\n\n#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Process Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always.\n\n  \\details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state.\n  \\return               PSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, psplim_ns\"  : \"=r\" (result) );\n  return result;\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Set Process Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored in non-secure\n  mode.\n\n  \\details Assigns the given value to the Process Stack Pointer Limit (PSPLIM).\n  \\param [in]    ProcStackPtrLimit  Process Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  (void)ProcStackPtrLimit;\n#else\n  __ASM volatile (\"MSR psplim, %0\" : : \"r\" (ProcStackPtrLimit));\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Set Process Stack Pointer (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored.\n\n  \\details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state.\n  \\param [in]    ProcStackPtrLimit  Process Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  (void)ProcStackPtrLimit;\n#else\n  __ASM volatile (\"MSR psplim_ns, %0\\n\" : : \"r\" (ProcStackPtrLimit));\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Get Main Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always in non-secure\n  mode.\n\n  \\details Returns the current value of the Main Stack Pointer Limit (MSPLIM).\n  \\return               MSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, msplim\" : \"=r\" (result) );\n  return result;\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Get Main Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always.\n\n  \\details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state.\n  \\return               MSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, msplim_ns\" : \"=r\" (result) );\n  return result;\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Set Main Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored in non-secure\n  mode.\n\n  \\details Assigns the given value to the Main Stack Pointer Limit (MSPLIM).\n  \\param [in]    MainStackPtrLimit  Main Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  (void)MainStackPtrLimit;\n#else\n  __ASM volatile (\"MSR msplim, %0\" : : \"r\" (MainStackPtrLimit));\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Set Main Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored.\n\n  \\details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state.\n  \\param [in]    MainStackPtrLimit  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit)\n{\n#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  (void)MainStackPtrLimit;\n#else\n  __ASM volatile (\"MSR msplim_ns, %0\" : : \"r\" (MainStackPtrLimit));\n#endif\n}\n#endif\n\n#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    ) */\n\n\n/**\n  \\brief   Get FPSCR\n  \\details Returns the current value of the Floating Point Status/Control register.\n  \\return               Floating Point Status/Control register value\n */\n__STATIC_FORCEINLINE uint32_t __get_FPSCR(void)\n{\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n#if __has_builtin(__builtin_arm_get_fpscr)\n// Re-enable using built-in when GCC has been fixed\n// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2)\n  /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */\n  return __builtin_arm_get_fpscr();\n#else\n  uint32_t result;\n\n  __ASM volatile (\"VMRS %0, fpscr\" : \"=r\" (result) );\n  return(result);\n#endif\n#else\n  return(0U);\n#endif\n}\n\n\n/**\n  \\brief   Set FPSCR\n  \\details Assigns the given value to the Floating Point Status/Control register.\n  \\param [in]    fpscr  Floating Point Status/Control value to set\n */\n__STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr)\n{\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n#if __has_builtin(__builtin_arm_set_fpscr)\n// Re-enable using built-in when GCC has been fixed\n// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2)\n  /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */\n  __builtin_arm_set_fpscr(fpscr);\n#else\n  __ASM volatile (\"VMSR fpscr, %0\" : : \"r\" (fpscr) : \"vfpcc\", \"memory\");\n#endif\n#else\n  (void)fpscr;\n#endif\n}\n\n\n/*@} end of CMSIS_Core_RegAccFunctions */\n\n\n/* ###################  Compiler specific Intrinsics  ########################### */\n/** \\defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics\n  Access to dedicated SIMD instructions\n  @{\n*/\n\n#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1))\n\n__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"sadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"uadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhadd8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n\n__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ssub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qsub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shsub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"usub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqsub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhsub8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n\n__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"sadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"uadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhadd16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ssub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qsub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shsub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"usub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqsub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhsub16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"sasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"uasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhasx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ssax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"qsax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"shsax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"usax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uqsax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uhsax %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"usad8 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3)\n{\n  uint32_t result;\n\n  __ASM (\"usada8 %0, %1, %2, %3\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n#define __SSAT16(ARG1, ARG2) \\\n__extension__ \\\n({                          \\\n  int32_t __RES, __ARG1 = (ARG1); \\\n  __ASM volatile (\"ssat16 %0, %1, %2\" : \"=r\" (__RES) :  \"I\" (ARG2), \"r\" (__ARG1) : \"cc\" ); \\\n  __RES; \\\n })\n\n#define __USAT16(ARG1, ARG2) \\\n__extension__ \\\n({                          \\\n  uint32_t __RES, __ARG1 = (ARG1); \\\n  __ASM volatile (\"usat16 %0, %1, %2\" : \"=r\" (__RES) :  \"I\" (ARG2), \"r\" (__ARG1) : \"cc\" ); \\\n  __RES; \\\n })\n\n__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1)\n{\n  uint32_t result;\n\n  __ASM (\"uxtb16 %0, %1\" : \"=r\" (result) : \"r\" (op1));\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"uxtab16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1)\n{\n  uint32_t result;\n\n  __ASM (\"sxtb16 %0, %1\" : \"=r\" (result) : \"r\" (op1));\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SXTB16_RORn(uint32_t op1, uint32_t rotate)\n{\n  uint32_t result;\n  if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) {\n    __ASM volatile (\"sxtb16 %0, %1, ROR %2\" : \"=r\" (result) : \"r\" (op1), \"i\" (rotate) );\n  } else {\n    result = __SXTB16(__ROR(op1, rotate)) ;\n  }\n  return result;\n}\n\n__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM (\"sxtab16 %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SXTAB16_RORn(uint32_t op1, uint32_t op2, uint32_t rotate)\n{\n  uint32_t result;\n  if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) {\n    __ASM volatile (\"sxtab16 %0, %1, %2, ROR %3\" : \"=r\" (result) : \"r\" (op1) , \"r\" (op2) , \"i\" (rotate));\n  } else {\n    result = __SXTAB16(op1, __ROR(op2, rotate));\n  }\n  return result;\n}\n\n\n__STATIC_FORCEINLINE uint32_t __SMUAD  (uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smuad %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smuadx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smlad %0, %1, %2, %3\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smladx %0, %1, %2, %3\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc)\n{\n  union llreg_u{\n    uint32_t w32[2];\n    uint64_t w64;\n  } llr;\n  llr.w64 = acc;\n\n#ifndef __ARMEB__   /* Little endian */\n  __ASM volatile (\"smlald %0, %1, %2, %3\" : \"=r\" (llr.w32[0]), \"=r\" (llr.w32[1]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[0]), \"1\" (llr.w32[1]) );\n#else               /* Big endian */\n  __ASM volatile (\"smlald %0, %1, %2, %3\" : \"=r\" (llr.w32[1]), \"=r\" (llr.w32[0]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[1]), \"1\" (llr.w32[0]) );\n#endif\n\n  return(llr.w64);\n}\n\n__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc)\n{\n  union llreg_u{\n    uint32_t w32[2];\n    uint64_t w64;\n  } llr;\n  llr.w64 = acc;\n\n#ifndef __ARMEB__   /* Little endian */\n  __ASM volatile (\"smlaldx %0, %1, %2, %3\" : \"=r\" (llr.w32[0]), \"=r\" (llr.w32[1]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[0]), \"1\" (llr.w32[1]) );\n#else               /* Big endian */\n  __ASM volatile (\"smlaldx %0, %1, %2, %3\" : \"=r\" (llr.w32[1]), \"=r\" (llr.w32[0]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[1]), \"1\" (llr.w32[0]) );\n#endif\n\n  return(llr.w64);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMUSD  (uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smusd %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smusdx %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smlsd %0, %1, %2, %3\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3)\n{\n  uint32_t result;\n\n  __ASM volatile (\"smlsdx %0, %1, %2, %3\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc)\n{\n  union llreg_u{\n    uint32_t w32[2];\n    uint64_t w64;\n  } llr;\n  llr.w64 = acc;\n\n#ifndef __ARMEB__   /* Little endian */\n  __ASM volatile (\"smlsld %0, %1, %2, %3\" : \"=r\" (llr.w32[0]), \"=r\" (llr.w32[1]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[0]), \"1\" (llr.w32[1]) );\n#else               /* Big endian */\n  __ASM volatile (\"smlsld %0, %1, %2, %3\" : \"=r\" (llr.w32[1]), \"=r\" (llr.w32[0]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[1]), \"1\" (llr.w32[0]) );\n#endif\n\n  return(llr.w64);\n}\n\n__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc)\n{\n  union llreg_u{\n    uint32_t w32[2];\n    uint64_t w64;\n  } llr;\n  llr.w64 = acc;\n\n#ifndef __ARMEB__   /* Little endian */\n  __ASM volatile (\"smlsldx %0, %1, %2, %3\" : \"=r\" (llr.w32[0]), \"=r\" (llr.w32[1]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[0]), \"1\" (llr.w32[1]) );\n#else               /* Big endian */\n  __ASM volatile (\"smlsldx %0, %1, %2, %3\" : \"=r\" (llr.w32[1]), \"=r\" (llr.w32[0]): \"r\" (op1), \"r\" (op2) , \"0\" (llr.w32[1]), \"1\" (llr.w32[0]) );\n#endif\n\n  return(llr.w64);\n}\n\n__STATIC_FORCEINLINE uint32_t __SEL  (uint32_t op1, uint32_t op2)\n{\n  uint32_t result;\n\n  __ASM volatile (\"sel %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE  int32_t __QADD( int32_t op1,  int32_t op2)\n{\n  int32_t result;\n\n  __ASM volatile (\"qadd %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n__STATIC_FORCEINLINE  int32_t __QSUB( int32_t op1,  int32_t op2)\n{\n  int32_t result;\n\n  __ASM volatile (\"qsub %0, %1, %2\" : \"=r\" (result) : \"r\" (op1), \"r\" (op2) );\n  return(result);\n}\n\n\n#define __PKHBT(ARG1,ARG2,ARG3) \\\n__extension__ \\\n({                          \\\n  uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \\\n  __ASM (\"pkhbt %0, %1, %2, lsl %3\" : \"=r\" (__RES) :  \"r\" (__ARG1), \"r\" (__ARG2), \"I\" (ARG3)  ); \\\n  __RES; \\\n })\n\n#define __PKHTB(ARG1,ARG2,ARG3) \\\n__extension__ \\\n({                          \\\n  uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \\\n  if (ARG3 == 0) \\\n    __ASM (\"pkhtb %0, %1, %2\" : \"=r\" (__RES) :  \"r\" (__ARG1), \"r\" (__ARG2)  ); \\\n  else \\\n    __ASM (\"pkhtb %0, %1, %2, asr %3\" : \"=r\" (__RES) :  \"r\" (__ARG1), \"r\" (__ARG2), \"I\" (ARG3)  ); \\\n  __RES; \\\n })\n\n\n__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3)\n{\n int32_t result;\n\n __ASM (\"smmla %0, %1, %2, %3\" : \"=r\" (result): \"r\"  (op1), \"r\" (op2), \"r\" (op3) );\n return(result);\n}\n\n#endif /* (__ARM_FEATURE_DSP == 1) */\n/*@} end of group CMSIS_SIMD_intrinsics */\n\n\n#pragma GCC diagnostic pop\n\n#endif /* __CMSIS_GCC_H */\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/cmsis_version.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_version.h\n * @brief    CMSIS Core(M) Version definitions\n * @version  V5.0.4\n * @date     23. July 2019\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2019 ARM Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header   /* treat file as system include file */\n#endif\n\n#ifndef __CMSIS_VERSION_H\n#define __CMSIS_VERSION_H\n\n/*  CMSIS Version definitions */\n#define __CM_CMSIS_VERSION_MAIN  ( 5U)                                      /*!< [31:16] CMSIS Core(M) main version */\n#define __CM_CMSIS_VERSION_SUB   ( 4U)                                      /*!< [15:0]  CMSIS Core(M) sub version */\n#define __CM_CMSIS_VERSION       ((__CM_CMSIS_VERSION_MAIN << 16U) | \\\n                                   __CM_CMSIS_VERSION_SUB           )       /*!< CMSIS Core(M) version number */\n#endif\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/core_cm3.h",
    "content": "/**************************************************************************//**\n * @file     core_cm3.h\n * @brief    CMSIS Cortex-M3 Core Peripheral Access Layer Header File\n * @version  V5.1.2\n * @date     04. June 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header   /* treat file as system include file */\n#endif\n\n#ifndef __CORE_CM3_H_GENERIC\n#define __CORE_CM3_H_GENERIC\n\n#include <stdint.h>\n\n#ifdef __cplusplus\n extern \"C\" {\n#endif\n\n/**\n  \\page CMSIS_MISRA_Exceptions  MISRA-C:2004 Compliance Exceptions\n  CMSIS violates the following MISRA-C:2004 rules:\n\n   \\li Required Rule 8.5, object/function definition in header file.<br>\n     Function definitions in header files are used to allow 'inlining'.\n\n   \\li Required Rule 18.4, declaration of union type or object of union type: '{...}'.<br>\n     Unions are used for effective representation of core registers.\n\n   \\li Advisory Rule 19.7, Function-like macro defined.<br>\n     Function-like macros are used to allow more efficient code.\n */\n\n\n/*******************************************************************************\n *                 CMSIS definitions\n ******************************************************************************/\n/**\n  \\ingroup Cortex_M3\n  @{\n */\n\n#include \"cmsis_version.h\"\n\n/* CMSIS CM3 definitions */\n#define __CM3_CMSIS_VERSION_MAIN  (__CM_CMSIS_VERSION_MAIN)              /*!< \\deprecated [31:16] CMSIS HAL main version */\n#define __CM3_CMSIS_VERSION_SUB   (__CM_CMSIS_VERSION_SUB)               /*!< \\deprecated [15:0]  CMSIS HAL sub version */\n#define __CM3_CMSIS_VERSION       ((__CM3_CMSIS_VERSION_MAIN << 16U) | \\\n                                    __CM3_CMSIS_VERSION_SUB           )  /*!< \\deprecated CMSIS HAL version number */\n\n#define __CORTEX_M                (3U)                                   /*!< Cortex-M Core */\n\n/** __FPU_USED indicates whether an FPU is used or not.\n    This core does not support an FPU at all\n*/\n#define __FPU_USED       0U\n\n#if defined ( __CC_ARM )\n  #if defined __TARGET_FPU_VFP\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)\n  #if defined __ARM_FP\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __GNUC__ )\n  #if defined (__VFP_FP__) && !defined(__SOFTFP__)\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __ICCARM__ )\n  #if defined __ARMVFP__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __TI_ARM__ )\n  #if defined __TI_VFP_SUPPORT__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __TASKING__ )\n  #if defined __FPU_VFP__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __CSMC__ )\n  #if ( __CSMC__ & 0x400U)\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#endif\n\n#include \"cmsis_compiler.h\"               /* CMSIS compiler specific defines */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __CORE_CM3_H_GENERIC */\n\n#ifndef __CMSIS_GENERIC\n\n#ifndef __CORE_CM3_H_DEPENDANT\n#define __CORE_CM3_H_DEPENDANT\n\n#ifdef __cplusplus\n extern \"C\" {\n#endif\n\n/* check device defines and use defaults */\n#if defined __CHECK_DEVICE_DEFINES\n  #ifndef __CM3_REV\n    #define __CM3_REV               0x0200U\n    #warning \"__CM3_REV not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __MPU_PRESENT\n    #define __MPU_PRESENT             0U\n    #warning \"__MPU_PRESENT not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __VTOR_PRESENT\n    #define __VTOR_PRESENT             1U\n    #warning \"__VTOR_PRESENT not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __NVIC_PRIO_BITS\n    #define __NVIC_PRIO_BITS          3U\n    #warning \"__NVIC_PRIO_BITS not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __Vendor_SysTickConfig\n    #define __Vendor_SysTickConfig    0U\n    #warning \"__Vendor_SysTickConfig not defined in device header file; using default!\"\n  #endif\n#endif\n\n/* IO definitions (access restrictions to peripheral registers) */\n/**\n    \\defgroup CMSIS_glob_defs CMSIS Global Defines\n\n    <strong>IO Type Qualifiers</strong> are used\n    \\li to specify the access to peripheral variables.\n    \\li for automatic generation of peripheral register debug information.\n*/\n#ifdef __cplusplus\n  #define   __I     volatile             /*!< Defines 'read only' permissions */\n#else\n  #define   __I     volatile const       /*!< Defines 'read only' permissions */\n#endif\n#define     __O     volatile             /*!< Defines 'write only' permissions */\n#define     __IO    volatile             /*!< Defines 'read / write' permissions */\n\n/* following defines should be used for structure members */\n#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */\n#define     __OM     volatile            /*! Defines 'write only' structure member permissions */\n#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */\n\n/*@} end of group Cortex_M3 */\n\n\n\n/*******************************************************************************\n *                 Register Abstraction\n  Core Register contain:\n  - Core Register\n  - Core NVIC Register\n  - Core SCB Register\n  - Core SysTick Register\n  - Core Debug Register\n  - Core MPU Register\n ******************************************************************************/\n/**\n  \\defgroup CMSIS_core_register Defines and Type Definitions\n  \\brief Type definitions and defines for Cortex-M processor based devices.\n*/\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_CORE  Status and Control Registers\n  \\brief      Core Register type definitions.\n  @{\n */\n\n/**\n  \\brief  Union type to access the Application Program Status Register (APSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t _reserved0:27;              /*!< bit:  0..26  Reserved */\n    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */\n    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */\n    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */\n    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */\n    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} APSR_Type;\n\n/* APSR Register Definitions */\n#define APSR_N_Pos                         31U                                            /*!< APSR: N Position */\n#define APSR_N_Msk                         (1UL << APSR_N_Pos)                            /*!< APSR: N Mask */\n\n#define APSR_Z_Pos                         30U                                            /*!< APSR: Z Position */\n#define APSR_Z_Msk                         (1UL << APSR_Z_Pos)                            /*!< APSR: Z Mask */\n\n#define APSR_C_Pos                         29U                                            /*!< APSR: C Position */\n#define APSR_C_Msk                         (1UL << APSR_C_Pos)                            /*!< APSR: C Mask */\n\n#define APSR_V_Pos                         28U                                            /*!< APSR: V Position */\n#define APSR_V_Msk                         (1UL << APSR_V_Pos)                            /*!< APSR: V Mask */\n\n#define APSR_Q_Pos                         27U                                            /*!< APSR: Q Position */\n#define APSR_Q_Msk                         (1UL << APSR_Q_Pos)                            /*!< APSR: Q Mask */\n\n\n/**\n  \\brief  Union type to access the Interrupt Program Status Register (IPSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t ISR:9;                      /*!< bit:  0.. 8  Exception number */\n    uint32_t _reserved0:23;              /*!< bit:  9..31  Reserved */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} IPSR_Type;\n\n/* IPSR Register Definitions */\n#define IPSR_ISR_Pos                        0U                                            /*!< IPSR: ISR Position */\n#define IPSR_ISR_Msk                       (0x1FFUL /*<< IPSR_ISR_Pos*/)                  /*!< IPSR: ISR Mask */\n\n\n/**\n  \\brief  Union type to access the Special-Purpose Program Status Registers (xPSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t ISR:9;                      /*!< bit:  0.. 8  Exception number */\n    uint32_t _reserved0:1;               /*!< bit:      9  Reserved */\n    uint32_t ICI_IT_1:6;                 /*!< bit: 10..15  ICI/IT part 1 */\n    uint32_t _reserved1:8;               /*!< bit: 16..23  Reserved */\n    uint32_t T:1;                        /*!< bit:     24  Thumb bit */\n    uint32_t ICI_IT_2:2;                 /*!< bit: 25..26  ICI/IT part 2 */\n    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */\n    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */\n    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */\n    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */\n    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} xPSR_Type;\n\n/* xPSR Register Definitions */\n#define xPSR_N_Pos                         31U                                            /*!< xPSR: N Position */\n#define xPSR_N_Msk                         (1UL << xPSR_N_Pos)                            /*!< xPSR: N Mask */\n\n#define xPSR_Z_Pos                         30U                                            /*!< xPSR: Z Position */\n#define xPSR_Z_Msk                         (1UL << xPSR_Z_Pos)                            /*!< xPSR: Z Mask */\n\n#define xPSR_C_Pos                         29U                                            /*!< xPSR: C Position */\n#define xPSR_C_Msk                         (1UL << xPSR_C_Pos)                            /*!< xPSR: C Mask */\n\n#define xPSR_V_Pos                         28U                                            /*!< xPSR: V Position */\n#define xPSR_V_Msk                         (1UL << xPSR_V_Pos)                            /*!< xPSR: V Mask */\n\n#define xPSR_Q_Pos                         27U                                            /*!< xPSR: Q Position */\n#define xPSR_Q_Msk                         (1UL << xPSR_Q_Pos)                            /*!< xPSR: Q Mask */\n\n#define xPSR_ICI_IT_2_Pos                  25U                                            /*!< xPSR: ICI/IT part 2 Position */\n#define xPSR_ICI_IT_2_Msk                  (3UL << xPSR_ICI_IT_2_Pos)                     /*!< xPSR: ICI/IT part 2 Mask */\n\n#define xPSR_T_Pos                         24U                                            /*!< xPSR: T Position */\n#define xPSR_T_Msk                         (1UL << xPSR_T_Pos)                            /*!< xPSR: T Mask */\n\n#define xPSR_ICI_IT_1_Pos                  10U                                            /*!< xPSR: ICI/IT part 1 Position */\n#define xPSR_ICI_IT_1_Msk                  (0x3FUL << xPSR_ICI_IT_1_Pos)                  /*!< xPSR: ICI/IT part 1 Mask */\n\n#define xPSR_ISR_Pos                        0U                                            /*!< xPSR: ISR Position */\n#define xPSR_ISR_Msk                       (0x1FFUL /*<< xPSR_ISR_Pos*/)                  /*!< xPSR: ISR Mask */\n\n\n/**\n  \\brief  Union type to access the Control Registers (CONTROL).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t nPRIV:1;                    /*!< bit:      0  Execution privilege in Thread mode */\n    uint32_t SPSEL:1;                    /*!< bit:      1  Stack to be used */\n    uint32_t _reserved1:30;              /*!< bit:  2..31  Reserved */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} CONTROL_Type;\n\n/* CONTROL Register Definitions */\n#define CONTROL_SPSEL_Pos                   1U                                            /*!< CONTROL: SPSEL Position */\n#define CONTROL_SPSEL_Msk                  (1UL << CONTROL_SPSEL_Pos)                     /*!< CONTROL: SPSEL Mask */\n\n#define CONTROL_nPRIV_Pos                   0U                                            /*!< CONTROL: nPRIV Position */\n#define CONTROL_nPRIV_Msk                  (1UL /*<< CONTROL_nPRIV_Pos*/)                 /*!< CONTROL: nPRIV Mask */\n\n/*@} end of group CMSIS_CORE */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_NVIC  Nested Vectored Interrupt Controller (NVIC)\n  \\brief      Type definitions for the NVIC Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Nested Vectored Interrupt Controller (NVIC).\n */\ntypedef struct\n{\n  __IOM uint32_t ISER[8U];               /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register */\n        uint32_t RESERVED0[24U];\n  __IOM uint32_t ICER[8U];               /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register */\n        uint32_t RESERVED1[24U];\n  __IOM uint32_t ISPR[8U];               /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register */\n        uint32_t RESERVED2[24U];\n  __IOM uint32_t ICPR[8U];               /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register */\n        uint32_t RESERVED3[24U];\n  __IOM uint32_t IABR[8U];               /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register */\n        uint32_t RESERVED4[56U];\n  __IOM uint8_t  IP[240U];               /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */\n        uint32_t RESERVED5[644U];\n  __OM  uint32_t STIR;                   /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register */\n}  NVIC_Type;\n\n/* Software Triggered Interrupt Register Definitions */\n#define NVIC_STIR_INTID_Pos                 0U                                         /*!< STIR: INTLINESNUM Position */\n#define NVIC_STIR_INTID_Msk                (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/)        /*!< STIR: INTLINESNUM Mask */\n\n/*@} end of group CMSIS_NVIC */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SCB     System Control Block (SCB)\n  \\brief    Type definitions for the System Control Block Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Control Block (SCB).\n */\ntypedef struct\n{\n  __IM  uint32_t CPUID;                  /*!< Offset: 0x000 (R/ )  CPUID Base Register */\n  __IOM uint32_t ICSR;                   /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register */\n  __IOM uint32_t VTOR;                   /*!< Offset: 0x008 (R/W)  Vector Table Offset Register */\n  __IOM uint32_t AIRCR;                  /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register */\n  __IOM uint32_t SCR;                    /*!< Offset: 0x010 (R/W)  System Control Register */\n  __IOM uint32_t CCR;                    /*!< Offset: 0x014 (R/W)  Configuration Control Register */\n  __IOM uint8_t  SHP[12U];               /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */\n  __IOM uint32_t SHCSR;                  /*!< Offset: 0x024 (R/W)  System Handler Control and State Register */\n  __IOM uint32_t CFSR;                   /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register */\n  __IOM uint32_t HFSR;                   /*!< Offset: 0x02C (R/W)  HardFault Status Register */\n  __IOM uint32_t DFSR;                   /*!< Offset: 0x030 (R/W)  Debug Fault Status Register */\n  __IOM uint32_t MMFAR;                  /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register */\n  __IOM uint32_t BFAR;                   /*!< Offset: 0x038 (R/W)  BusFault Address Register */\n  __IOM uint32_t AFSR;                   /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register */\n  __IM  uint32_t PFR[2U];                /*!< Offset: 0x040 (R/ )  Processor Feature Register */\n  __IM  uint32_t DFR;                    /*!< Offset: 0x048 (R/ )  Debug Feature Register */\n  __IM  uint32_t ADR;                    /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register */\n  __IM  uint32_t MMFR[4U];               /*!< Offset: 0x050 (R/ )  Memory Model Feature Register */\n  __IM  uint32_t ISAR[5U];               /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register */\n        uint32_t RESERVED0[5U];\n  __IOM uint32_t CPACR;                  /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register */\n} SCB_Type;\n\n/* SCB CPUID Register Definitions */\n#define SCB_CPUID_IMPLEMENTER_Pos          24U                                            /*!< SCB CPUID: IMPLEMENTER Position */\n#define SCB_CPUID_IMPLEMENTER_Msk          (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos)          /*!< SCB CPUID: IMPLEMENTER Mask */\n\n#define SCB_CPUID_VARIANT_Pos              20U                                            /*!< SCB CPUID: VARIANT Position */\n#define SCB_CPUID_VARIANT_Msk              (0xFUL << SCB_CPUID_VARIANT_Pos)               /*!< SCB CPUID: VARIANT Mask */\n\n#define SCB_CPUID_ARCHITECTURE_Pos         16U                                            /*!< SCB CPUID: ARCHITECTURE Position */\n#define SCB_CPUID_ARCHITECTURE_Msk         (0xFUL << SCB_CPUID_ARCHITECTURE_Pos)          /*!< SCB CPUID: ARCHITECTURE Mask */\n\n#define SCB_CPUID_PARTNO_Pos                4U                                            /*!< SCB CPUID: PARTNO Position */\n#define SCB_CPUID_PARTNO_Msk               (0xFFFUL << SCB_CPUID_PARTNO_Pos)              /*!< SCB CPUID: PARTNO Mask */\n\n#define SCB_CPUID_REVISION_Pos              0U                                            /*!< SCB CPUID: REVISION Position */\n#define SCB_CPUID_REVISION_Msk             (0xFUL /*<< SCB_CPUID_REVISION_Pos*/)          /*!< SCB CPUID: REVISION Mask */\n\n/* SCB Interrupt Control State Register Definitions */\n#define SCB_ICSR_NMIPENDSET_Pos            31U                                            /*!< SCB ICSR: NMIPENDSET Position */\n#define SCB_ICSR_NMIPENDSET_Msk            (1UL << SCB_ICSR_NMIPENDSET_Pos)               /*!< SCB ICSR: NMIPENDSET Mask */\n\n#define SCB_ICSR_PENDSVSET_Pos             28U                                            /*!< SCB ICSR: PENDSVSET Position */\n#define SCB_ICSR_PENDSVSET_Msk             (1UL << SCB_ICSR_PENDSVSET_Pos)                /*!< SCB ICSR: PENDSVSET Mask */\n\n#define SCB_ICSR_PENDSVCLR_Pos             27U                                            /*!< SCB ICSR: PENDSVCLR Position */\n#define SCB_ICSR_PENDSVCLR_Msk             (1UL << SCB_ICSR_PENDSVCLR_Pos)                /*!< SCB ICSR: PENDSVCLR Mask */\n\n#define SCB_ICSR_PENDSTSET_Pos             26U                                            /*!< SCB ICSR: PENDSTSET Position */\n#define SCB_ICSR_PENDSTSET_Msk             (1UL << SCB_ICSR_PENDSTSET_Pos)                /*!< SCB ICSR: PENDSTSET Mask */\n\n#define SCB_ICSR_PENDSTCLR_Pos             25U                                            /*!< SCB ICSR: PENDSTCLR Position */\n#define SCB_ICSR_PENDSTCLR_Msk             (1UL << SCB_ICSR_PENDSTCLR_Pos)                /*!< SCB ICSR: PENDSTCLR Mask */\n\n#define SCB_ICSR_ISRPREEMPT_Pos            23U                                            /*!< SCB ICSR: ISRPREEMPT Position */\n#define SCB_ICSR_ISRPREEMPT_Msk            (1UL << SCB_ICSR_ISRPREEMPT_Pos)               /*!< SCB ICSR: ISRPREEMPT Mask */\n\n#define SCB_ICSR_ISRPENDING_Pos            22U                                            /*!< SCB ICSR: ISRPENDING Position */\n#define SCB_ICSR_ISRPENDING_Msk            (1UL << SCB_ICSR_ISRPENDING_Pos)               /*!< SCB ICSR: ISRPENDING Mask */\n\n#define SCB_ICSR_VECTPENDING_Pos           12U                                            /*!< SCB ICSR: VECTPENDING Position */\n#define SCB_ICSR_VECTPENDING_Msk           (0x1FFUL << SCB_ICSR_VECTPENDING_Pos)          /*!< SCB ICSR: VECTPENDING Mask */\n\n#define SCB_ICSR_RETTOBASE_Pos             11U                                            /*!< SCB ICSR: RETTOBASE Position */\n#define SCB_ICSR_RETTOBASE_Msk             (1UL << SCB_ICSR_RETTOBASE_Pos)                /*!< SCB ICSR: RETTOBASE Mask */\n\n#define SCB_ICSR_VECTACTIVE_Pos             0U                                            /*!< SCB ICSR: VECTACTIVE Position */\n#define SCB_ICSR_VECTACTIVE_Msk            (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/)       /*!< SCB ICSR: VECTACTIVE Mask */\n\n/* SCB Vector Table Offset Register Definitions */\n#if defined (__CM3_REV) && (__CM3_REV < 0x0201U)                   /* core r2p1 */\n#define SCB_VTOR_TBLBASE_Pos               29U                                            /*!< SCB VTOR: TBLBASE Position */\n#define SCB_VTOR_TBLBASE_Msk               (1UL << SCB_VTOR_TBLBASE_Pos)                  /*!< SCB VTOR: TBLBASE Mask */\n\n#define SCB_VTOR_TBLOFF_Pos                 7U                                            /*!< SCB VTOR: TBLOFF Position */\n#define SCB_VTOR_TBLOFF_Msk                (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos)            /*!< SCB VTOR: TBLOFF Mask */\n#else\n#define SCB_VTOR_TBLOFF_Pos                 7U                                            /*!< SCB VTOR: TBLOFF Position */\n#define SCB_VTOR_TBLOFF_Msk                (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos)           /*!< SCB VTOR: TBLOFF Mask */\n#endif\n\n/* SCB Application Interrupt and Reset Control Register Definitions */\n#define SCB_AIRCR_VECTKEY_Pos              16U                                            /*!< SCB AIRCR: VECTKEY Position */\n#define SCB_AIRCR_VECTKEY_Msk              (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos)            /*!< SCB AIRCR: VECTKEY Mask */\n\n#define SCB_AIRCR_VECTKEYSTAT_Pos          16U                                            /*!< SCB AIRCR: VECTKEYSTAT Position */\n#define SCB_AIRCR_VECTKEYSTAT_Msk          (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos)        /*!< SCB AIRCR: VECTKEYSTAT Mask */\n\n#define SCB_AIRCR_ENDIANESS_Pos            15U                                            /*!< SCB AIRCR: ENDIANESS Position */\n#define SCB_AIRCR_ENDIANESS_Msk            (1UL << SCB_AIRCR_ENDIANESS_Pos)               /*!< SCB AIRCR: ENDIANESS Mask */\n\n#define SCB_AIRCR_PRIGROUP_Pos              8U                                            /*!< SCB AIRCR: PRIGROUP Position */\n#define SCB_AIRCR_PRIGROUP_Msk             (7UL << SCB_AIRCR_PRIGROUP_Pos)                /*!< SCB AIRCR: PRIGROUP Mask */\n\n#define SCB_AIRCR_SYSRESETREQ_Pos           2U                                            /*!< SCB AIRCR: SYSRESETREQ Position */\n#define SCB_AIRCR_SYSRESETREQ_Msk          (1UL << SCB_AIRCR_SYSRESETREQ_Pos)             /*!< SCB AIRCR: SYSRESETREQ Mask */\n\n#define SCB_AIRCR_VECTCLRACTIVE_Pos         1U                                            /*!< SCB AIRCR: VECTCLRACTIVE Position */\n#define SCB_AIRCR_VECTCLRACTIVE_Msk        (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos)           /*!< SCB AIRCR: VECTCLRACTIVE Mask */\n\n#define SCB_AIRCR_VECTRESET_Pos             0U                                            /*!< SCB AIRCR: VECTRESET Position */\n#define SCB_AIRCR_VECTRESET_Msk            (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/)           /*!< SCB AIRCR: VECTRESET Mask */\n\n/* SCB System Control Register Definitions */\n#define SCB_SCR_SEVONPEND_Pos               4U                                            /*!< SCB SCR: SEVONPEND Position */\n#define SCB_SCR_SEVONPEND_Msk              (1UL << SCB_SCR_SEVONPEND_Pos)                 /*!< SCB SCR: SEVONPEND Mask */\n\n#define SCB_SCR_SLEEPDEEP_Pos               2U                                            /*!< SCB SCR: SLEEPDEEP Position */\n#define SCB_SCR_SLEEPDEEP_Msk              (1UL << SCB_SCR_SLEEPDEEP_Pos)                 /*!< SCB SCR: SLEEPDEEP Mask */\n\n#define SCB_SCR_SLEEPONEXIT_Pos             1U                                            /*!< SCB SCR: SLEEPONEXIT Position */\n#define SCB_SCR_SLEEPONEXIT_Msk            (1UL << SCB_SCR_SLEEPONEXIT_Pos)               /*!< SCB SCR: SLEEPONEXIT Mask */\n\n/* SCB Configuration Control Register Definitions */\n#define SCB_CCR_STKALIGN_Pos                9U                                            /*!< SCB CCR: STKALIGN Position */\n#define SCB_CCR_STKALIGN_Msk               (1UL << SCB_CCR_STKALIGN_Pos)                  /*!< SCB CCR: STKALIGN Mask */\n\n#define SCB_CCR_BFHFNMIGN_Pos               8U                                            /*!< SCB CCR: BFHFNMIGN Position */\n#define SCB_CCR_BFHFNMIGN_Msk              (1UL << SCB_CCR_BFHFNMIGN_Pos)                 /*!< SCB CCR: BFHFNMIGN Mask */\n\n#define SCB_CCR_DIV_0_TRP_Pos               4U                                            /*!< SCB CCR: DIV_0_TRP Position */\n#define SCB_CCR_DIV_0_TRP_Msk              (1UL << SCB_CCR_DIV_0_TRP_Pos)                 /*!< SCB CCR: DIV_0_TRP Mask */\n\n#define SCB_CCR_UNALIGN_TRP_Pos             3U                                            /*!< SCB CCR: UNALIGN_TRP Position */\n#define SCB_CCR_UNALIGN_TRP_Msk            (1UL << SCB_CCR_UNALIGN_TRP_Pos)               /*!< SCB CCR: UNALIGN_TRP Mask */\n\n#define SCB_CCR_USERSETMPEND_Pos            1U                                            /*!< SCB CCR: USERSETMPEND Position */\n#define SCB_CCR_USERSETMPEND_Msk           (1UL << SCB_CCR_USERSETMPEND_Pos)              /*!< SCB CCR: USERSETMPEND Mask */\n\n#define SCB_CCR_NONBASETHRDENA_Pos          0U                                            /*!< SCB CCR: NONBASETHRDENA Position */\n#define SCB_CCR_NONBASETHRDENA_Msk         (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/)        /*!< SCB CCR: NONBASETHRDENA Mask */\n\n/* SCB System Handler Control and State Register Definitions */\n#define SCB_SHCSR_USGFAULTENA_Pos          18U                                            /*!< SCB SHCSR: USGFAULTENA Position */\n#define SCB_SHCSR_USGFAULTENA_Msk          (1UL << SCB_SHCSR_USGFAULTENA_Pos)             /*!< SCB SHCSR: USGFAULTENA Mask */\n\n#define SCB_SHCSR_BUSFAULTENA_Pos          17U                                            /*!< SCB SHCSR: BUSFAULTENA Position */\n#define SCB_SHCSR_BUSFAULTENA_Msk          (1UL << SCB_SHCSR_BUSFAULTENA_Pos)             /*!< SCB SHCSR: BUSFAULTENA Mask */\n\n#define SCB_SHCSR_MEMFAULTENA_Pos          16U                                            /*!< SCB SHCSR: MEMFAULTENA Position */\n#define SCB_SHCSR_MEMFAULTENA_Msk          (1UL << SCB_SHCSR_MEMFAULTENA_Pos)             /*!< SCB SHCSR: MEMFAULTENA Mask */\n\n#define SCB_SHCSR_SVCALLPENDED_Pos         15U                                            /*!< SCB SHCSR: SVCALLPENDED Position */\n#define SCB_SHCSR_SVCALLPENDED_Msk         (1UL << SCB_SHCSR_SVCALLPENDED_Pos)            /*!< SCB SHCSR: SVCALLPENDED Mask */\n\n#define SCB_SHCSR_BUSFAULTPENDED_Pos       14U                                            /*!< SCB SHCSR: BUSFAULTPENDED Position */\n#define SCB_SHCSR_BUSFAULTPENDED_Msk       (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos)          /*!< SCB SHCSR: BUSFAULTPENDED Mask */\n\n#define SCB_SHCSR_MEMFAULTPENDED_Pos       13U                                            /*!< SCB SHCSR: MEMFAULTPENDED Position */\n#define SCB_SHCSR_MEMFAULTPENDED_Msk       (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos)          /*!< SCB SHCSR: MEMFAULTPENDED Mask */\n\n#define SCB_SHCSR_USGFAULTPENDED_Pos       12U                                            /*!< SCB SHCSR: USGFAULTPENDED Position */\n#define SCB_SHCSR_USGFAULTPENDED_Msk       (1UL << SCB_SHCSR_USGFAULTPENDED_Pos)          /*!< SCB SHCSR: USGFAULTPENDED Mask */\n\n#define SCB_SHCSR_SYSTICKACT_Pos           11U                                            /*!< SCB SHCSR: SYSTICKACT Position */\n#define SCB_SHCSR_SYSTICKACT_Msk           (1UL << SCB_SHCSR_SYSTICKACT_Pos)              /*!< SCB SHCSR: SYSTICKACT Mask */\n\n#define SCB_SHCSR_PENDSVACT_Pos            10U                                            /*!< SCB SHCSR: PENDSVACT Position */\n#define SCB_SHCSR_PENDSVACT_Msk            (1UL << SCB_SHCSR_PENDSVACT_Pos)               /*!< SCB SHCSR: PENDSVACT Mask */\n\n#define SCB_SHCSR_MONITORACT_Pos            8U                                            /*!< SCB SHCSR: MONITORACT Position */\n#define SCB_SHCSR_MONITORACT_Msk           (1UL << SCB_SHCSR_MONITORACT_Pos)              /*!< SCB SHCSR: MONITORACT Mask */\n\n#define SCB_SHCSR_SVCALLACT_Pos             7U                                            /*!< SCB SHCSR: SVCALLACT Position */\n#define SCB_SHCSR_SVCALLACT_Msk            (1UL << SCB_SHCSR_SVCALLACT_Pos)               /*!< SCB SHCSR: SVCALLACT Mask */\n\n#define SCB_SHCSR_USGFAULTACT_Pos           3U                                            /*!< SCB SHCSR: USGFAULTACT Position */\n#define SCB_SHCSR_USGFAULTACT_Msk          (1UL << SCB_SHCSR_USGFAULTACT_Pos)             /*!< SCB SHCSR: USGFAULTACT Mask */\n\n#define SCB_SHCSR_BUSFAULTACT_Pos           1U                                            /*!< SCB SHCSR: BUSFAULTACT Position */\n#define SCB_SHCSR_BUSFAULTACT_Msk          (1UL << SCB_SHCSR_BUSFAULTACT_Pos)             /*!< SCB SHCSR: BUSFAULTACT Mask */\n\n#define SCB_SHCSR_MEMFAULTACT_Pos           0U                                            /*!< SCB SHCSR: MEMFAULTACT Position */\n#define SCB_SHCSR_MEMFAULTACT_Msk          (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/)         /*!< SCB SHCSR: MEMFAULTACT Mask */\n\n/* SCB Configurable Fault Status Register Definitions */\n#define SCB_CFSR_USGFAULTSR_Pos            16U                                            /*!< SCB CFSR: Usage Fault Status Register Position */\n#define SCB_CFSR_USGFAULTSR_Msk            (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos)          /*!< SCB CFSR: Usage Fault Status Register Mask */\n\n#define SCB_CFSR_BUSFAULTSR_Pos             8U                                            /*!< SCB CFSR: Bus Fault Status Register Position */\n#define SCB_CFSR_BUSFAULTSR_Msk            (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos)            /*!< SCB CFSR: Bus Fault Status Register Mask */\n\n#define SCB_CFSR_MEMFAULTSR_Pos             0U                                            /*!< SCB CFSR: Memory Manage Fault Status Register Position */\n#define SCB_CFSR_MEMFAULTSR_Msk            (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/)        /*!< SCB CFSR: Memory Manage Fault Status Register Mask */\n\n/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_MMARVALID_Pos             (SCB_CFSR_MEMFAULTSR_Pos + 7U)                 /*!< SCB CFSR (MMFSR): MMARVALID Position */\n#define SCB_CFSR_MMARVALID_Msk             (1UL << SCB_CFSR_MMARVALID_Pos)                /*!< SCB CFSR (MMFSR): MMARVALID Mask */\n\n#define SCB_CFSR_MSTKERR_Pos               (SCB_CFSR_MEMFAULTSR_Pos + 4U)                 /*!< SCB CFSR (MMFSR): MSTKERR Position */\n#define SCB_CFSR_MSTKERR_Msk               (1UL << SCB_CFSR_MSTKERR_Pos)                  /*!< SCB CFSR (MMFSR): MSTKERR Mask */\n\n#define SCB_CFSR_MUNSTKERR_Pos             (SCB_CFSR_MEMFAULTSR_Pos + 3U)                 /*!< SCB CFSR (MMFSR): MUNSTKERR Position */\n#define SCB_CFSR_MUNSTKERR_Msk             (1UL << SCB_CFSR_MUNSTKERR_Pos)                /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */\n\n#define SCB_CFSR_DACCVIOL_Pos              (SCB_CFSR_MEMFAULTSR_Pos + 1U)                 /*!< SCB CFSR (MMFSR): DACCVIOL Position */\n#define SCB_CFSR_DACCVIOL_Msk              (1UL << SCB_CFSR_DACCVIOL_Pos)                 /*!< SCB CFSR (MMFSR): DACCVIOL Mask */\n\n#define SCB_CFSR_IACCVIOL_Pos              (SCB_CFSR_MEMFAULTSR_Pos + 0U)                 /*!< SCB CFSR (MMFSR): IACCVIOL Position */\n#define SCB_CFSR_IACCVIOL_Msk              (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/)             /*!< SCB CFSR (MMFSR): IACCVIOL Mask */\n\n/* BusFault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_BFARVALID_Pos            (SCB_CFSR_BUSFAULTSR_Pos + 7U)                  /*!< SCB CFSR (BFSR): BFARVALID Position */\n#define SCB_CFSR_BFARVALID_Msk            (1UL << SCB_CFSR_BFARVALID_Pos)                 /*!< SCB CFSR (BFSR): BFARVALID Mask */\n\n#define SCB_CFSR_STKERR_Pos               (SCB_CFSR_BUSFAULTSR_Pos + 4U)                  /*!< SCB CFSR (BFSR): STKERR Position */\n#define SCB_CFSR_STKERR_Msk               (1UL << SCB_CFSR_STKERR_Pos)                    /*!< SCB CFSR (BFSR): STKERR Mask */\n\n#define SCB_CFSR_UNSTKERR_Pos             (SCB_CFSR_BUSFAULTSR_Pos + 3U)                  /*!< SCB CFSR (BFSR): UNSTKERR Position */\n#define SCB_CFSR_UNSTKERR_Msk             (1UL << SCB_CFSR_UNSTKERR_Pos)                  /*!< SCB CFSR (BFSR): UNSTKERR Mask */\n\n#define SCB_CFSR_IMPRECISERR_Pos          (SCB_CFSR_BUSFAULTSR_Pos + 2U)                  /*!< SCB CFSR (BFSR): IMPRECISERR Position */\n#define SCB_CFSR_IMPRECISERR_Msk          (1UL << SCB_CFSR_IMPRECISERR_Pos)               /*!< SCB CFSR (BFSR): IMPRECISERR Mask */\n\n#define SCB_CFSR_PRECISERR_Pos            (SCB_CFSR_BUSFAULTSR_Pos + 1U)                  /*!< SCB CFSR (BFSR): PRECISERR Position */\n#define SCB_CFSR_PRECISERR_Msk            (1UL << SCB_CFSR_PRECISERR_Pos)                 /*!< SCB CFSR (BFSR): PRECISERR Mask */\n\n#define SCB_CFSR_IBUSERR_Pos              (SCB_CFSR_BUSFAULTSR_Pos + 0U)                  /*!< SCB CFSR (BFSR): IBUSERR Position */\n#define SCB_CFSR_IBUSERR_Msk              (1UL << SCB_CFSR_IBUSERR_Pos)                   /*!< SCB CFSR (BFSR): IBUSERR Mask */\n\n/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_DIVBYZERO_Pos            (SCB_CFSR_USGFAULTSR_Pos + 9U)                  /*!< SCB CFSR (UFSR): DIVBYZERO Position */\n#define SCB_CFSR_DIVBYZERO_Msk            (1UL << SCB_CFSR_DIVBYZERO_Pos)                 /*!< SCB CFSR (UFSR): DIVBYZERO Mask */\n\n#define SCB_CFSR_UNALIGNED_Pos            (SCB_CFSR_USGFAULTSR_Pos + 8U)                  /*!< SCB CFSR (UFSR): UNALIGNED Position */\n#define SCB_CFSR_UNALIGNED_Msk            (1UL << SCB_CFSR_UNALIGNED_Pos)                 /*!< SCB CFSR (UFSR): UNALIGNED Mask */\n\n#define SCB_CFSR_NOCP_Pos                 (SCB_CFSR_USGFAULTSR_Pos + 3U)                  /*!< SCB CFSR (UFSR): NOCP Position */\n#define SCB_CFSR_NOCP_Msk                 (1UL << SCB_CFSR_NOCP_Pos)                      /*!< SCB CFSR (UFSR): NOCP Mask */\n\n#define SCB_CFSR_INVPC_Pos                (SCB_CFSR_USGFAULTSR_Pos + 2U)                  /*!< SCB CFSR (UFSR): INVPC Position */\n#define SCB_CFSR_INVPC_Msk                (1UL << SCB_CFSR_INVPC_Pos)                     /*!< SCB CFSR (UFSR): INVPC Mask */\n\n#define SCB_CFSR_INVSTATE_Pos             (SCB_CFSR_USGFAULTSR_Pos + 1U)                  /*!< SCB CFSR (UFSR): INVSTATE Position */\n#define SCB_CFSR_INVSTATE_Msk             (1UL << SCB_CFSR_INVSTATE_Pos)                  /*!< SCB CFSR (UFSR): INVSTATE Mask */\n\n#define SCB_CFSR_UNDEFINSTR_Pos           (SCB_CFSR_USGFAULTSR_Pos + 0U)                  /*!< SCB CFSR (UFSR): UNDEFINSTR Position */\n#define SCB_CFSR_UNDEFINSTR_Msk           (1UL << SCB_CFSR_UNDEFINSTR_Pos)                /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */\n\n/* SCB Hard Fault Status Register Definitions */\n#define SCB_HFSR_DEBUGEVT_Pos              31U                                            /*!< SCB HFSR: DEBUGEVT Position */\n#define SCB_HFSR_DEBUGEVT_Msk              (1UL << SCB_HFSR_DEBUGEVT_Pos)                 /*!< SCB HFSR: DEBUGEVT Mask */\n\n#define SCB_HFSR_FORCED_Pos                30U                                            /*!< SCB HFSR: FORCED Position */\n#define SCB_HFSR_FORCED_Msk                (1UL << SCB_HFSR_FORCED_Pos)                   /*!< SCB HFSR: FORCED Mask */\n\n#define SCB_HFSR_VECTTBL_Pos                1U                                            /*!< SCB HFSR: VECTTBL Position */\n#define SCB_HFSR_VECTTBL_Msk               (1UL << SCB_HFSR_VECTTBL_Pos)                  /*!< SCB HFSR: VECTTBL Mask */\n\n/* SCB Debug Fault Status Register Definitions */\n#define SCB_DFSR_EXTERNAL_Pos               4U                                            /*!< SCB DFSR: EXTERNAL Position */\n#define SCB_DFSR_EXTERNAL_Msk              (1UL << SCB_DFSR_EXTERNAL_Pos)                 /*!< SCB DFSR: EXTERNAL Mask */\n\n#define SCB_DFSR_VCATCH_Pos                 3U                                            /*!< SCB DFSR: VCATCH Position */\n#define SCB_DFSR_VCATCH_Msk                (1UL << SCB_DFSR_VCATCH_Pos)                   /*!< SCB DFSR: VCATCH Mask */\n\n#define SCB_DFSR_DWTTRAP_Pos                2U                                            /*!< SCB DFSR: DWTTRAP Position */\n#define SCB_DFSR_DWTTRAP_Msk               (1UL << SCB_DFSR_DWTTRAP_Pos)                  /*!< SCB DFSR: DWTTRAP Mask */\n\n#define SCB_DFSR_BKPT_Pos                   1U                                            /*!< SCB DFSR: BKPT Position */\n#define SCB_DFSR_BKPT_Msk                  (1UL << SCB_DFSR_BKPT_Pos)                     /*!< SCB DFSR: BKPT Mask */\n\n#define SCB_DFSR_HALTED_Pos                 0U                                            /*!< SCB DFSR: HALTED Position */\n#define SCB_DFSR_HALTED_Msk                (1UL /*<< SCB_DFSR_HALTED_Pos*/)               /*!< SCB DFSR: HALTED Mask */\n\n/*@} end of group CMSIS_SCB */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB)\n  \\brief    Type definitions for the System Control and ID Register not in the SCB\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Control and ID Register not in the SCB.\n */\ntypedef struct\n{\n        uint32_t RESERVED0[1U];\n  __IM  uint32_t ICTR;                   /*!< Offset: 0x004 (R/ )  Interrupt Controller Type Register */\n#if defined (__CM3_REV) && (__CM3_REV >= 0x200U)\n  __IOM uint32_t ACTLR;                  /*!< Offset: 0x008 (R/W)  Auxiliary Control Register */\n#else\n        uint32_t RESERVED1[1U];\n#endif\n} SCnSCB_Type;\n\n/* Interrupt Controller Type Register Definitions */\n#define SCnSCB_ICTR_INTLINESNUM_Pos         0U                                         /*!< ICTR: INTLINESNUM Position */\n#define SCnSCB_ICTR_INTLINESNUM_Msk        (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/)  /*!< ICTR: INTLINESNUM Mask */\n\n/* Auxiliary Control Register Definitions */\n#if defined (__CM3_REV) && (__CM3_REV >= 0x200U)\n#define SCnSCB_ACTLR_DISOOFP_Pos            9U                                         /*!< ACTLR: DISOOFP Position */\n#define SCnSCB_ACTLR_DISOOFP_Msk           (1UL << SCnSCB_ACTLR_DISOOFP_Pos)           /*!< ACTLR: DISOOFP Mask */\n\n#define SCnSCB_ACTLR_DISFPCA_Pos            8U                                         /*!< ACTLR: DISFPCA Position */\n#define SCnSCB_ACTLR_DISFPCA_Msk           (1UL << SCnSCB_ACTLR_DISFPCA_Pos)           /*!< ACTLR: DISFPCA Mask */\n\n#define SCnSCB_ACTLR_DISFOLD_Pos            2U                                         /*!< ACTLR: DISFOLD Position */\n#define SCnSCB_ACTLR_DISFOLD_Msk           (1UL << SCnSCB_ACTLR_DISFOLD_Pos)           /*!< ACTLR: DISFOLD Mask */\n\n#define SCnSCB_ACTLR_DISDEFWBUF_Pos         1U                                         /*!< ACTLR: DISDEFWBUF Position */\n#define SCnSCB_ACTLR_DISDEFWBUF_Msk        (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos)        /*!< ACTLR: DISDEFWBUF Mask */\n\n#define SCnSCB_ACTLR_DISMCYCINT_Pos         0U                                         /*!< ACTLR: DISMCYCINT Position */\n#define SCnSCB_ACTLR_DISMCYCINT_Msk        (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/)    /*!< ACTLR: DISMCYCINT Mask */\n#endif\n\n/*@} end of group CMSIS_SCnotSCB */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SysTick     System Tick Timer (SysTick)\n  \\brief    Type definitions for the System Timer Registers.\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Timer (SysTick).\n */\ntypedef struct\n{\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */\n  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */\n  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */\n  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */\n} SysTick_Type;\n\n/* SysTick Control / Status Register Definitions */\n#define SysTick_CTRL_COUNTFLAG_Pos         16U                                            /*!< SysTick CTRL: COUNTFLAG Position */\n#define SysTick_CTRL_COUNTFLAG_Msk         (1UL << SysTick_CTRL_COUNTFLAG_Pos)            /*!< SysTick CTRL: COUNTFLAG Mask */\n\n#define SysTick_CTRL_CLKSOURCE_Pos          2U                                            /*!< SysTick CTRL: CLKSOURCE Position */\n#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)            /*!< SysTick CTRL: CLKSOURCE Mask */\n\n#define SysTick_CTRL_TICKINT_Pos            1U                                            /*!< SysTick CTRL: TICKINT Position */\n#define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos)              /*!< SysTick CTRL: TICKINT Mask */\n\n#define SysTick_CTRL_ENABLE_Pos             0U                                            /*!< SysTick CTRL: ENABLE Position */\n#define SysTick_CTRL_ENABLE_Msk            (1UL /*<< SysTick_CTRL_ENABLE_Pos*/)           /*!< SysTick CTRL: ENABLE Mask */\n\n/* SysTick Reload Register Definitions */\n#define SysTick_LOAD_RELOAD_Pos             0U                                            /*!< SysTick LOAD: RELOAD Position */\n#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/)    /*!< SysTick LOAD: RELOAD Mask */\n\n/* SysTick Current Register Definitions */\n#define SysTick_VAL_CURRENT_Pos             0U                                            /*!< SysTick VAL: CURRENT Position */\n#define SysTick_VAL_CURRENT_Msk            (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/)    /*!< SysTick VAL: CURRENT Mask */\n\n/* SysTick Calibration Register Definitions */\n#define SysTick_CALIB_NOREF_Pos            31U                                            /*!< SysTick CALIB: NOREF Position */\n#define SysTick_CALIB_NOREF_Msk            (1UL << SysTick_CALIB_NOREF_Pos)               /*!< SysTick CALIB: NOREF Mask */\n\n#define SysTick_CALIB_SKEW_Pos             30U                                            /*!< SysTick CALIB: SKEW Position */\n#define SysTick_CALIB_SKEW_Msk             (1UL << SysTick_CALIB_SKEW_Pos)                /*!< SysTick CALIB: SKEW Mask */\n\n#define SysTick_CALIB_TENMS_Pos             0U                                            /*!< SysTick CALIB: TENMS Position */\n#define SysTick_CALIB_TENMS_Msk            (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/)    /*!< SysTick CALIB: TENMS Mask */\n\n/*@} end of group CMSIS_SysTick */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_ITM     Instrumentation Trace Macrocell (ITM)\n  \\brief    Type definitions for the Instrumentation Trace Macrocell (ITM)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Instrumentation Trace Macrocell Register (ITM).\n */\ntypedef struct\n{\n  __OM  union\n  {\n    __OM  uint8_t    u8;                 /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 8-bit */\n    __OM  uint16_t   u16;                /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 16-bit */\n    __OM  uint32_t   u32;                /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 32-bit */\n  }  PORT [32U];                         /*!< Offset: 0x000 ( /W)  ITM Stimulus Port Registers */\n        uint32_t RESERVED0[864U];\n  __IOM uint32_t TER;                    /*!< Offset: 0xE00 (R/W)  ITM Trace Enable Register */\n        uint32_t RESERVED1[15U];\n  __IOM uint32_t TPR;                    /*!< Offset: 0xE40 (R/W)  ITM Trace Privilege Register */\n        uint32_t RESERVED2[15U];\n  __IOM uint32_t TCR;                    /*!< Offset: 0xE80 (R/W)  ITM Trace Control Register */\n        uint32_t RESERVED3[32U];\n        uint32_t RESERVED4[43U];\n  __OM  uint32_t LAR;                    /*!< Offset: 0xFB0 ( /W)  ITM Lock Access Register */\n  __IM  uint32_t LSR;                    /*!< Offset: 0xFB4 (R/ )  ITM Lock Status Register */\n        uint32_t RESERVED5[6U];\n  __IM  uint32_t PID4;                   /*!< Offset: 0xFD0 (R/ )  ITM Peripheral Identification Register #4 */\n  __IM  uint32_t PID5;                   /*!< Offset: 0xFD4 (R/ )  ITM Peripheral Identification Register #5 */\n  __IM  uint32_t PID6;                   /*!< Offset: 0xFD8 (R/ )  ITM Peripheral Identification Register #6 */\n  __IM  uint32_t PID7;                   /*!< Offset: 0xFDC (R/ )  ITM Peripheral Identification Register #7 */\n  __IM  uint32_t PID0;                   /*!< Offset: 0xFE0 (R/ )  ITM Peripheral Identification Register #0 */\n  __IM  uint32_t PID1;                   /*!< Offset: 0xFE4 (R/ )  ITM Peripheral Identification Register #1 */\n  __IM  uint32_t PID2;                   /*!< Offset: 0xFE8 (R/ )  ITM Peripheral Identification Register #2 */\n  __IM  uint32_t PID3;                   /*!< Offset: 0xFEC (R/ )  ITM Peripheral Identification Register #3 */\n  __IM  uint32_t CID0;                   /*!< Offset: 0xFF0 (R/ )  ITM Component  Identification Register #0 */\n  __IM  uint32_t CID1;                   /*!< Offset: 0xFF4 (R/ )  ITM Component  Identification Register #1 */\n  __IM  uint32_t CID2;                   /*!< Offset: 0xFF8 (R/ )  ITM Component  Identification Register #2 */\n  __IM  uint32_t CID3;                   /*!< Offset: 0xFFC (R/ )  ITM Component  Identification Register #3 */\n} ITM_Type;\n\n/* ITM Trace Privilege Register Definitions */\n#define ITM_TPR_PRIVMASK_Pos                0U                                            /*!< ITM TPR: PRIVMASK Position */\n#define ITM_TPR_PRIVMASK_Msk               (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/)     /*!< ITM TPR: PRIVMASK Mask */\n\n/* ITM Trace Control Register Definitions */\n#define ITM_TCR_BUSY_Pos                   23U                                            /*!< ITM TCR: BUSY Position */\n#define ITM_TCR_BUSY_Msk                   (1UL << ITM_TCR_BUSY_Pos)                      /*!< ITM TCR: BUSY Mask */\n\n#define ITM_TCR_TraceBusID_Pos             16U                                            /*!< ITM TCR: ATBID Position */\n#define ITM_TCR_TraceBusID_Msk             (0x7FUL << ITM_TCR_TraceBusID_Pos)             /*!< ITM TCR: ATBID Mask */\n\n#define ITM_TCR_GTSFREQ_Pos                10U                                            /*!< ITM TCR: Global timestamp frequency Position */\n#define ITM_TCR_GTSFREQ_Msk                (3UL << ITM_TCR_GTSFREQ_Pos)                   /*!< ITM TCR: Global timestamp frequency Mask */\n\n#define ITM_TCR_TSPrescale_Pos              8U                                            /*!< ITM TCR: TSPrescale Position */\n#define ITM_TCR_TSPrescale_Msk             (3UL << ITM_TCR_TSPrescale_Pos)                /*!< ITM TCR: TSPrescale Mask */\n\n#define ITM_TCR_SWOENA_Pos                  4U                                            /*!< ITM TCR: SWOENA Position */\n#define ITM_TCR_SWOENA_Msk                 (1UL << ITM_TCR_SWOENA_Pos)                    /*!< ITM TCR: SWOENA Mask */\n\n#define ITM_TCR_DWTENA_Pos                  3U                                            /*!< ITM TCR: DWTENA Position */\n#define ITM_TCR_DWTENA_Msk                 (1UL << ITM_TCR_DWTENA_Pos)                    /*!< ITM TCR: DWTENA Mask */\n\n#define ITM_TCR_SYNCENA_Pos                 2U                                            /*!< ITM TCR: SYNCENA Position */\n#define ITM_TCR_SYNCENA_Msk                (1UL << ITM_TCR_SYNCENA_Pos)                   /*!< ITM TCR: SYNCENA Mask */\n\n#define ITM_TCR_TSENA_Pos                   1U                                            /*!< ITM TCR: TSENA Position */\n#define ITM_TCR_TSENA_Msk                  (1UL << ITM_TCR_TSENA_Pos)                     /*!< ITM TCR: TSENA Mask */\n\n#define ITM_TCR_ITMENA_Pos                  0U                                            /*!< ITM TCR: ITM Enable bit Position */\n#define ITM_TCR_ITMENA_Msk                 (1UL /*<< ITM_TCR_ITMENA_Pos*/)                /*!< ITM TCR: ITM Enable bit Mask */\n\n/* ITM Lock Status Register Definitions */\n#define ITM_LSR_ByteAcc_Pos                 2U                                            /*!< ITM LSR: ByteAcc Position */\n#define ITM_LSR_ByteAcc_Msk                (1UL << ITM_LSR_ByteAcc_Pos)                   /*!< ITM LSR: ByteAcc Mask */\n\n#define ITM_LSR_Access_Pos                  1U                                            /*!< ITM LSR: Access Position */\n#define ITM_LSR_Access_Msk                 (1UL << ITM_LSR_Access_Pos)                    /*!< ITM LSR: Access Mask */\n\n#define ITM_LSR_Present_Pos                 0U                                            /*!< ITM LSR: Present Position */\n#define ITM_LSR_Present_Msk                (1UL /*<< ITM_LSR_Present_Pos*/)               /*!< ITM LSR: Present Mask */\n\n/*@}*/ /* end of group CMSIS_ITM */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_DWT     Data Watchpoint and Trace (DWT)\n  \\brief    Type definitions for the Data Watchpoint and Trace (DWT)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Data Watchpoint and Trace Register (DWT).\n */\ntypedef struct\n{\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  Control Register */\n  __IOM uint32_t CYCCNT;                 /*!< Offset: 0x004 (R/W)  Cycle Count Register */\n  __IOM uint32_t CPICNT;                 /*!< Offset: 0x008 (R/W)  CPI Count Register */\n  __IOM uint32_t EXCCNT;                 /*!< Offset: 0x00C (R/W)  Exception Overhead Count Register */\n  __IOM uint32_t SLEEPCNT;               /*!< Offset: 0x010 (R/W)  Sleep Count Register */\n  __IOM uint32_t LSUCNT;                 /*!< Offset: 0x014 (R/W)  LSU Count Register */\n  __IOM uint32_t FOLDCNT;                /*!< Offset: 0x018 (R/W)  Folded-instruction Count Register */\n  __IM  uint32_t PCSR;                   /*!< Offset: 0x01C (R/ )  Program Counter Sample Register */\n  __IOM uint32_t COMP0;                  /*!< Offset: 0x020 (R/W)  Comparator Register 0 */\n  __IOM uint32_t MASK0;                  /*!< Offset: 0x024 (R/W)  Mask Register 0 */\n  __IOM uint32_t FUNCTION0;              /*!< Offset: 0x028 (R/W)  Function Register 0 */\n        uint32_t RESERVED0[1U];\n  __IOM uint32_t COMP1;                  /*!< Offset: 0x030 (R/W)  Comparator Register 1 */\n  __IOM uint32_t MASK1;                  /*!< Offset: 0x034 (R/W)  Mask Register 1 */\n  __IOM uint32_t FUNCTION1;              /*!< Offset: 0x038 (R/W)  Function Register 1 */\n        uint32_t RESERVED1[1U];\n  __IOM uint32_t COMP2;                  /*!< Offset: 0x040 (R/W)  Comparator Register 2 */\n  __IOM uint32_t MASK2;                  /*!< Offset: 0x044 (R/W)  Mask Register 2 */\n  __IOM uint32_t FUNCTION2;              /*!< Offset: 0x048 (R/W)  Function Register 2 */\n        uint32_t RESERVED2[1U];\n  __IOM uint32_t COMP3;                  /*!< Offset: 0x050 (R/W)  Comparator Register 3 */\n  __IOM uint32_t MASK3;                  /*!< Offset: 0x054 (R/W)  Mask Register 3 */\n  __IOM uint32_t FUNCTION3;              /*!< Offset: 0x058 (R/W)  Function Register 3 */\n} DWT_Type;\n\n/* DWT Control Register Definitions */\n#define DWT_CTRL_NUMCOMP_Pos               28U                                         /*!< DWT CTRL: NUMCOMP Position */\n#define DWT_CTRL_NUMCOMP_Msk               (0xFUL << DWT_CTRL_NUMCOMP_Pos)             /*!< DWT CTRL: NUMCOMP Mask */\n\n#define DWT_CTRL_NOTRCPKT_Pos              27U                                         /*!< DWT CTRL: NOTRCPKT Position */\n#define DWT_CTRL_NOTRCPKT_Msk              (0x1UL << DWT_CTRL_NOTRCPKT_Pos)            /*!< DWT CTRL: NOTRCPKT Mask */\n\n#define DWT_CTRL_NOEXTTRIG_Pos             26U                                         /*!< DWT CTRL: NOEXTTRIG Position */\n#define DWT_CTRL_NOEXTTRIG_Msk             (0x1UL << DWT_CTRL_NOEXTTRIG_Pos)           /*!< DWT CTRL: NOEXTTRIG Mask */\n\n#define DWT_CTRL_NOCYCCNT_Pos              25U                                         /*!< DWT CTRL: NOCYCCNT Position */\n#define DWT_CTRL_NOCYCCNT_Msk              (0x1UL << DWT_CTRL_NOCYCCNT_Pos)            /*!< DWT CTRL: NOCYCCNT Mask */\n\n#define DWT_CTRL_NOPRFCNT_Pos              24U                                         /*!< DWT CTRL: NOPRFCNT Position */\n#define DWT_CTRL_NOPRFCNT_Msk              (0x1UL << DWT_CTRL_NOPRFCNT_Pos)            /*!< DWT CTRL: NOPRFCNT Mask */\n\n#define DWT_CTRL_CYCEVTENA_Pos             22U                                         /*!< DWT CTRL: CYCEVTENA Position */\n#define DWT_CTRL_CYCEVTENA_Msk             (0x1UL << DWT_CTRL_CYCEVTENA_Pos)           /*!< DWT CTRL: CYCEVTENA Mask */\n\n#define DWT_CTRL_FOLDEVTENA_Pos            21U                                         /*!< DWT CTRL: FOLDEVTENA Position */\n#define DWT_CTRL_FOLDEVTENA_Msk            (0x1UL << DWT_CTRL_FOLDEVTENA_Pos)          /*!< DWT CTRL: FOLDEVTENA Mask */\n\n#define DWT_CTRL_LSUEVTENA_Pos             20U                                         /*!< DWT CTRL: LSUEVTENA Position */\n#define DWT_CTRL_LSUEVTENA_Msk             (0x1UL << DWT_CTRL_LSUEVTENA_Pos)           /*!< DWT CTRL: LSUEVTENA Mask */\n\n#define DWT_CTRL_SLEEPEVTENA_Pos           19U                                         /*!< DWT CTRL: SLEEPEVTENA Position */\n#define DWT_CTRL_SLEEPEVTENA_Msk           (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos)         /*!< DWT CTRL: SLEEPEVTENA Mask */\n\n#define DWT_CTRL_EXCEVTENA_Pos             18U                                         /*!< DWT CTRL: EXCEVTENA Position */\n#define DWT_CTRL_EXCEVTENA_Msk             (0x1UL << DWT_CTRL_EXCEVTENA_Pos)           /*!< DWT CTRL: EXCEVTENA Mask */\n\n#define DWT_CTRL_CPIEVTENA_Pos             17U                                         /*!< DWT CTRL: CPIEVTENA Position */\n#define DWT_CTRL_CPIEVTENA_Msk             (0x1UL << DWT_CTRL_CPIEVTENA_Pos)           /*!< DWT CTRL: CPIEVTENA Mask */\n\n#define DWT_CTRL_EXCTRCENA_Pos             16U                                         /*!< DWT CTRL: EXCTRCENA Position */\n#define DWT_CTRL_EXCTRCENA_Msk             (0x1UL << DWT_CTRL_EXCTRCENA_Pos)           /*!< DWT CTRL: EXCTRCENA Mask */\n\n#define DWT_CTRL_PCSAMPLENA_Pos            12U                                         /*!< DWT CTRL: PCSAMPLENA Position */\n#define DWT_CTRL_PCSAMPLENA_Msk            (0x1UL << DWT_CTRL_PCSAMPLENA_Pos)          /*!< DWT CTRL: PCSAMPLENA Mask */\n\n#define DWT_CTRL_SYNCTAP_Pos               10U                                         /*!< DWT CTRL: SYNCTAP Position */\n#define DWT_CTRL_SYNCTAP_Msk               (0x3UL << DWT_CTRL_SYNCTAP_Pos)             /*!< DWT CTRL: SYNCTAP Mask */\n\n#define DWT_CTRL_CYCTAP_Pos                 9U                                         /*!< DWT CTRL: CYCTAP Position */\n#define DWT_CTRL_CYCTAP_Msk                (0x1UL << DWT_CTRL_CYCTAP_Pos)              /*!< DWT CTRL: CYCTAP Mask */\n\n#define DWT_CTRL_POSTINIT_Pos               5U                                         /*!< DWT CTRL: POSTINIT Position */\n#define DWT_CTRL_POSTINIT_Msk              (0xFUL << DWT_CTRL_POSTINIT_Pos)            /*!< DWT CTRL: POSTINIT Mask */\n\n#define DWT_CTRL_POSTPRESET_Pos             1U                                         /*!< DWT CTRL: POSTPRESET Position */\n#define DWT_CTRL_POSTPRESET_Msk            (0xFUL << DWT_CTRL_POSTPRESET_Pos)          /*!< DWT CTRL: POSTPRESET Mask */\n\n#define DWT_CTRL_CYCCNTENA_Pos              0U                                         /*!< DWT CTRL: CYCCNTENA Position */\n#define DWT_CTRL_CYCCNTENA_Msk             (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/)       /*!< DWT CTRL: CYCCNTENA Mask */\n\n/* DWT CPI Count Register Definitions */\n#define DWT_CPICNT_CPICNT_Pos               0U                                         /*!< DWT CPICNT: CPICNT Position */\n#define DWT_CPICNT_CPICNT_Msk              (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/)       /*!< DWT CPICNT: CPICNT Mask */\n\n/* DWT Exception Overhead Count Register Definitions */\n#define DWT_EXCCNT_EXCCNT_Pos               0U                                         /*!< DWT EXCCNT: EXCCNT Position */\n#define DWT_EXCCNT_EXCCNT_Msk              (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/)       /*!< DWT EXCCNT: EXCCNT Mask */\n\n/* DWT Sleep Count Register Definitions */\n#define DWT_SLEEPCNT_SLEEPCNT_Pos           0U                                         /*!< DWT SLEEPCNT: SLEEPCNT Position */\n#define DWT_SLEEPCNT_SLEEPCNT_Msk          (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/)   /*!< DWT SLEEPCNT: SLEEPCNT Mask */\n\n/* DWT LSU Count Register Definitions */\n#define DWT_LSUCNT_LSUCNT_Pos               0U                                         /*!< DWT LSUCNT: LSUCNT Position */\n#define DWT_LSUCNT_LSUCNT_Msk              (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/)       /*!< DWT LSUCNT: LSUCNT Mask */\n\n/* DWT Folded-instruction Count Register Definitions */\n#define DWT_FOLDCNT_FOLDCNT_Pos             0U                                         /*!< DWT FOLDCNT: FOLDCNT Position */\n#define DWT_FOLDCNT_FOLDCNT_Msk            (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/)     /*!< DWT FOLDCNT: FOLDCNT Mask */\n\n/* DWT Comparator Mask Register Definitions */\n#define DWT_MASK_MASK_Pos                   0U                                         /*!< DWT MASK: MASK Position */\n#define DWT_MASK_MASK_Msk                  (0x1FUL /*<< DWT_MASK_MASK_Pos*/)           /*!< DWT MASK: MASK Mask */\n\n/* DWT Comparator Function Register Definitions */\n#define DWT_FUNCTION_MATCHED_Pos           24U                                         /*!< DWT FUNCTION: MATCHED Position */\n#define DWT_FUNCTION_MATCHED_Msk           (0x1UL << DWT_FUNCTION_MATCHED_Pos)         /*!< DWT FUNCTION: MATCHED Mask */\n\n#define DWT_FUNCTION_DATAVADDR1_Pos        16U                                         /*!< DWT FUNCTION: DATAVADDR1 Position */\n#define DWT_FUNCTION_DATAVADDR1_Msk        (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos)      /*!< DWT FUNCTION: DATAVADDR1 Mask */\n\n#define DWT_FUNCTION_DATAVADDR0_Pos        12U                                         /*!< DWT FUNCTION: DATAVADDR0 Position */\n#define DWT_FUNCTION_DATAVADDR0_Msk        (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos)      /*!< DWT FUNCTION: DATAVADDR0 Mask */\n\n#define DWT_FUNCTION_DATAVSIZE_Pos         10U                                         /*!< DWT FUNCTION: DATAVSIZE Position */\n#define DWT_FUNCTION_DATAVSIZE_Msk         (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos)       /*!< DWT FUNCTION: DATAVSIZE Mask */\n\n#define DWT_FUNCTION_LNK1ENA_Pos            9U                                         /*!< DWT FUNCTION: LNK1ENA Position */\n#define DWT_FUNCTION_LNK1ENA_Msk           (0x1UL << DWT_FUNCTION_LNK1ENA_Pos)         /*!< DWT FUNCTION: LNK1ENA Mask */\n\n#define DWT_FUNCTION_DATAVMATCH_Pos         8U                                         /*!< DWT FUNCTION: DATAVMATCH Position */\n#define DWT_FUNCTION_DATAVMATCH_Msk        (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos)      /*!< DWT FUNCTION: DATAVMATCH Mask */\n\n#define DWT_FUNCTION_CYCMATCH_Pos           7U                                         /*!< DWT FUNCTION: CYCMATCH Position */\n#define DWT_FUNCTION_CYCMATCH_Msk          (0x1UL << DWT_FUNCTION_CYCMATCH_Pos)        /*!< DWT FUNCTION: CYCMATCH Mask */\n\n#define DWT_FUNCTION_EMITRANGE_Pos          5U                                         /*!< DWT FUNCTION: EMITRANGE Position */\n#define DWT_FUNCTION_EMITRANGE_Msk         (0x1UL << DWT_FUNCTION_EMITRANGE_Pos)       /*!< DWT FUNCTION: EMITRANGE Mask */\n\n#define DWT_FUNCTION_FUNCTION_Pos           0U                                         /*!< DWT FUNCTION: FUNCTION Position */\n#define DWT_FUNCTION_FUNCTION_Msk          (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/)    /*!< DWT FUNCTION: FUNCTION Mask */\n\n/*@}*/ /* end of group CMSIS_DWT */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_TPI     Trace Port Interface (TPI)\n  \\brief    Type definitions for the Trace Port Interface (TPI)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Trace Port Interface Register (TPI).\n */\ntypedef struct\n{\n  __IM  uint32_t SSPSR;                  /*!< Offset: 0x000 (R/ )  Supported Parallel Port Size Register */\n  __IOM uint32_t CSPSR;                  /*!< Offset: 0x004 (R/W)  Current Parallel Port Size Register */\n        uint32_t RESERVED0[2U];\n  __IOM uint32_t ACPR;                   /*!< Offset: 0x010 (R/W)  Asynchronous Clock Prescaler Register */\n        uint32_t RESERVED1[55U];\n  __IOM uint32_t SPPR;                   /*!< Offset: 0x0F0 (R/W)  Selected Pin Protocol Register */\n        uint32_t RESERVED2[131U];\n  __IM  uint32_t FFSR;                   /*!< Offset: 0x300 (R/ )  Formatter and Flush Status Register */\n  __IOM uint32_t FFCR;                   /*!< Offset: 0x304 (R/W)  Formatter and Flush Control Register */\n  __IM  uint32_t FSCR;                   /*!< Offset: 0x308 (R/ )  Formatter Synchronization Counter Register */\n        uint32_t RESERVED3[759U];\n  __IM  uint32_t TRIGGER;                /*!< Offset: 0xEE8 (R/ )  TRIGGER Register */\n  __IM  uint32_t FIFO0;                  /*!< Offset: 0xEEC (R/ )  Integration ETM Data */\n  __IM  uint32_t ITATBCTR2;              /*!< Offset: 0xEF0 (R/ )  ITATBCTR2 */\n        uint32_t RESERVED4[1U];\n  __IM  uint32_t ITATBCTR0;              /*!< Offset: 0xEF8 (R/ )  ITATBCTR0 */\n  __IM  uint32_t FIFO1;                  /*!< Offset: 0xEFC (R/ )  Integration ITM Data */\n  __IOM uint32_t ITCTRL;                 /*!< Offset: 0xF00 (R/W)  Integration Mode Control */\n        uint32_t RESERVED5[39U];\n  __IOM uint32_t CLAIMSET;               /*!< Offset: 0xFA0 (R/W)  Claim tag set */\n  __IOM uint32_t CLAIMCLR;               /*!< Offset: 0xFA4 (R/W)  Claim tag clear */\n        uint32_t RESERVED7[8U];\n  __IM  uint32_t DEVID;                  /*!< Offset: 0xFC8 (R/ )  TPIU_DEVID */\n  __IM  uint32_t DEVTYPE;                /*!< Offset: 0xFCC (R/ )  TPIU_DEVTYPE */\n} TPI_Type;\n\n/* TPI Asynchronous Clock Prescaler Register Definitions */\n#define TPI_ACPR_PRESCALER_Pos              0U                                         /*!< TPI ACPR: PRESCALER Position */\n#define TPI_ACPR_PRESCALER_Msk             (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/)    /*!< TPI ACPR: PRESCALER Mask */\n\n/* TPI Selected Pin Protocol Register Definitions */\n#define TPI_SPPR_TXMODE_Pos                 0U                                         /*!< TPI SPPR: TXMODE Position */\n#define TPI_SPPR_TXMODE_Msk                (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/)          /*!< TPI SPPR: TXMODE Mask */\n\n/* TPI Formatter and Flush Status Register Definitions */\n#define TPI_FFSR_FtNonStop_Pos              3U                                         /*!< TPI FFSR: FtNonStop Position */\n#define TPI_FFSR_FtNonStop_Msk             (0x1UL << TPI_FFSR_FtNonStop_Pos)           /*!< TPI FFSR: FtNonStop Mask */\n\n#define TPI_FFSR_TCPresent_Pos              2U                                         /*!< TPI FFSR: TCPresent Position */\n#define TPI_FFSR_TCPresent_Msk             (0x1UL << TPI_FFSR_TCPresent_Pos)           /*!< TPI FFSR: TCPresent Mask */\n\n#define TPI_FFSR_FtStopped_Pos              1U                                         /*!< TPI FFSR: FtStopped Position */\n#define TPI_FFSR_FtStopped_Msk             (0x1UL << TPI_FFSR_FtStopped_Pos)           /*!< TPI FFSR: FtStopped Mask */\n\n#define TPI_FFSR_FlInProg_Pos               0U                                         /*!< TPI FFSR: FlInProg Position */\n#define TPI_FFSR_FlInProg_Msk              (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/)        /*!< TPI FFSR: FlInProg Mask */\n\n/* TPI Formatter and Flush Control Register Definitions */\n#define TPI_FFCR_TrigIn_Pos                 8U                                         /*!< TPI FFCR: TrigIn Position */\n#define TPI_FFCR_TrigIn_Msk                (0x1UL << TPI_FFCR_TrigIn_Pos)              /*!< TPI FFCR: TrigIn Mask */\n\n#define TPI_FFCR_EnFCont_Pos                1U                                         /*!< TPI FFCR: EnFCont Position */\n#define TPI_FFCR_EnFCont_Msk               (0x1UL << TPI_FFCR_EnFCont_Pos)             /*!< TPI FFCR: EnFCont Mask */\n\n/* TPI TRIGGER Register Definitions */\n#define TPI_TRIGGER_TRIGGER_Pos             0U                                         /*!< TPI TRIGGER: TRIGGER Position */\n#define TPI_TRIGGER_TRIGGER_Msk            (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/)      /*!< TPI TRIGGER: TRIGGER Mask */\n\n/* TPI Integration ETM Data Register Definitions (FIFO0) */\n#define TPI_FIFO0_ITM_ATVALID_Pos          29U                                         /*!< TPI FIFO0: ITM_ATVALID Position */\n#define TPI_FIFO0_ITM_ATVALID_Msk          (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos)        /*!< TPI FIFO0: ITM_ATVALID Mask */\n\n#define TPI_FIFO0_ITM_bytecount_Pos        27U                                         /*!< TPI FIFO0: ITM_bytecount Position */\n#define TPI_FIFO0_ITM_bytecount_Msk        (0x3UL << TPI_FIFO0_ITM_bytecount_Pos)      /*!< TPI FIFO0: ITM_bytecount Mask */\n\n#define TPI_FIFO0_ETM_ATVALID_Pos          26U                                         /*!< TPI FIFO0: ETM_ATVALID Position */\n#define TPI_FIFO0_ETM_ATVALID_Msk          (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos)        /*!< TPI FIFO0: ETM_ATVALID Mask */\n\n#define TPI_FIFO0_ETM_bytecount_Pos        24U                                         /*!< TPI FIFO0: ETM_bytecount Position */\n#define TPI_FIFO0_ETM_bytecount_Msk        (0x3UL << TPI_FIFO0_ETM_bytecount_Pos)      /*!< TPI FIFO0: ETM_bytecount Mask */\n\n#define TPI_FIFO0_ETM2_Pos                 16U                                         /*!< TPI FIFO0: ETM2 Position */\n#define TPI_FIFO0_ETM2_Msk                 (0xFFUL << TPI_FIFO0_ETM2_Pos)              /*!< TPI FIFO0: ETM2 Mask */\n\n#define TPI_FIFO0_ETM1_Pos                  8U                                         /*!< TPI FIFO0: ETM1 Position */\n#define TPI_FIFO0_ETM1_Msk                 (0xFFUL << TPI_FIFO0_ETM1_Pos)              /*!< TPI FIFO0: ETM1 Mask */\n\n#define TPI_FIFO0_ETM0_Pos                  0U                                         /*!< TPI FIFO0: ETM0 Position */\n#define TPI_FIFO0_ETM0_Msk                 (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/)          /*!< TPI FIFO0: ETM0 Mask */\n\n/* TPI ITATBCTR2 Register Definitions */\n#define TPI_ITATBCTR2_ATREADY2_Pos          0U                                         /*!< TPI ITATBCTR2: ATREADY2 Position */\n#define TPI_ITATBCTR2_ATREADY2_Msk         (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/)   /*!< TPI ITATBCTR2: ATREADY2 Mask */\n\n#define TPI_ITATBCTR2_ATREADY1_Pos          0U                                         /*!< TPI ITATBCTR2: ATREADY1 Position */\n#define TPI_ITATBCTR2_ATREADY1_Msk         (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/)   /*!< TPI ITATBCTR2: ATREADY1 Mask */\n\n/* TPI Integration ITM Data Register Definitions (FIFO1) */\n#define TPI_FIFO1_ITM_ATVALID_Pos          29U                                         /*!< TPI FIFO1: ITM_ATVALID Position */\n#define TPI_FIFO1_ITM_ATVALID_Msk          (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos)        /*!< TPI FIFO1: ITM_ATVALID Mask */\n\n#define TPI_FIFO1_ITM_bytecount_Pos        27U                                         /*!< TPI FIFO1: ITM_bytecount Position */\n#define TPI_FIFO1_ITM_bytecount_Msk        (0x3UL << TPI_FIFO1_ITM_bytecount_Pos)      /*!< TPI FIFO1: ITM_bytecount Mask */\n\n#define TPI_FIFO1_ETM_ATVALID_Pos          26U                                         /*!< TPI FIFO1: ETM_ATVALID Position */\n#define TPI_FIFO1_ETM_ATVALID_Msk          (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos)        /*!< TPI FIFO1: ETM_ATVALID Mask */\n\n#define TPI_FIFO1_ETM_bytecount_Pos        24U                                         /*!< TPI FIFO1: ETM_bytecount Position */\n#define TPI_FIFO1_ETM_bytecount_Msk        (0x3UL << TPI_FIFO1_ETM_bytecount_Pos)      /*!< TPI FIFO1: ETM_bytecount Mask */\n\n#define TPI_FIFO1_ITM2_Pos                 16U                                         /*!< TPI FIFO1: ITM2 Position */\n#define TPI_FIFO1_ITM2_Msk                 (0xFFUL << TPI_FIFO1_ITM2_Pos)              /*!< TPI FIFO1: ITM2 Mask */\n\n#define TPI_FIFO1_ITM1_Pos                  8U                                         /*!< TPI FIFO1: ITM1 Position */\n#define TPI_FIFO1_ITM1_Msk                 (0xFFUL << TPI_FIFO1_ITM1_Pos)              /*!< TPI FIFO1: ITM1 Mask */\n\n#define TPI_FIFO1_ITM0_Pos                  0U                                         /*!< TPI FIFO1: ITM0 Position */\n#define TPI_FIFO1_ITM0_Msk                 (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/)          /*!< TPI FIFO1: ITM0 Mask */\n\n/* TPI ITATBCTR0 Register Definitions */\n#define TPI_ITATBCTR0_ATREADY2_Pos          0U                                         /*!< TPI ITATBCTR0: ATREADY2 Position */\n#define TPI_ITATBCTR0_ATREADY2_Msk         (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/)   /*!< TPI ITATBCTR0: ATREADY2 Mask */\n\n#define TPI_ITATBCTR0_ATREADY1_Pos          0U                                         /*!< TPI ITATBCTR0: ATREADY1 Position */\n#define TPI_ITATBCTR0_ATREADY1_Msk         (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/)   /*!< TPI ITATBCTR0: ATREADY1 Mask */\n\n/* TPI Integration Mode Control Register Definitions */\n#define TPI_ITCTRL_Mode_Pos                 0U                                         /*!< TPI ITCTRL: Mode Position */\n#define TPI_ITCTRL_Mode_Msk                (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/)          /*!< TPI ITCTRL: Mode Mask */\n\n/* TPI DEVID Register Definitions */\n#define TPI_DEVID_NRZVALID_Pos             11U                                         /*!< TPI DEVID: NRZVALID Position */\n#define TPI_DEVID_NRZVALID_Msk             (0x1UL << TPI_DEVID_NRZVALID_Pos)           /*!< TPI DEVID: NRZVALID Mask */\n\n#define TPI_DEVID_MANCVALID_Pos            10U                                         /*!< TPI DEVID: MANCVALID Position */\n#define TPI_DEVID_MANCVALID_Msk            (0x1UL << TPI_DEVID_MANCVALID_Pos)          /*!< TPI DEVID: MANCVALID Mask */\n\n#define TPI_DEVID_PTINVALID_Pos             9U                                         /*!< TPI DEVID: PTINVALID Position */\n#define TPI_DEVID_PTINVALID_Msk            (0x1UL << TPI_DEVID_PTINVALID_Pos)          /*!< TPI DEVID: PTINVALID Mask */\n\n#define TPI_DEVID_MinBufSz_Pos              6U                                         /*!< TPI DEVID: MinBufSz Position */\n#define TPI_DEVID_MinBufSz_Msk             (0x7UL << TPI_DEVID_MinBufSz_Pos)           /*!< TPI DEVID: MinBufSz Mask */\n\n#define TPI_DEVID_AsynClkIn_Pos             5U                                         /*!< TPI DEVID: AsynClkIn Position */\n#define TPI_DEVID_AsynClkIn_Msk            (0x1UL << TPI_DEVID_AsynClkIn_Pos)          /*!< TPI DEVID: AsynClkIn Mask */\n\n#define TPI_DEVID_NrTraceInput_Pos          0U                                         /*!< TPI DEVID: NrTraceInput Position */\n#define TPI_DEVID_NrTraceInput_Msk         (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/)  /*!< TPI DEVID: NrTraceInput Mask */\n\n/* TPI DEVTYPE Register Definitions */\n#define TPI_DEVTYPE_SubType_Pos             4U                                         /*!< TPI DEVTYPE: SubType Position */\n#define TPI_DEVTYPE_SubType_Msk            (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/)      /*!< TPI DEVTYPE: SubType Mask */\n\n#define TPI_DEVTYPE_MajorType_Pos           0U                                         /*!< TPI DEVTYPE: MajorType Position */\n#define TPI_DEVTYPE_MajorType_Msk          (0xFUL << TPI_DEVTYPE_MajorType_Pos)        /*!< TPI DEVTYPE: MajorType Mask */\n\n/*@}*/ /* end of group CMSIS_TPI */\n\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_MPU     Memory Protection Unit (MPU)\n  \\brief    Type definitions for the Memory Protection Unit (MPU)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Memory Protection Unit (MPU).\n */\ntypedef struct\n{\n  __IM  uint32_t TYPE;                   /*!< Offset: 0x000 (R/ )  MPU Type Register */\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x004 (R/W)  MPU Control Register */\n  __IOM uint32_t RNR;                    /*!< Offset: 0x008 (R/W)  MPU Region RNRber Register */\n  __IOM uint32_t RBAR;                   /*!< Offset: 0x00C (R/W)  MPU Region Base Address Register */\n  __IOM uint32_t RASR;                   /*!< Offset: 0x010 (R/W)  MPU Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A1;                /*!< Offset: 0x014 (R/W)  MPU Alias 1 Region Base Address Register */\n  __IOM uint32_t RASR_A1;                /*!< Offset: 0x018 (R/W)  MPU Alias 1 Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A2;                /*!< Offset: 0x01C (R/W)  MPU Alias 2 Region Base Address Register */\n  __IOM uint32_t RASR_A2;                /*!< Offset: 0x020 (R/W)  MPU Alias 2 Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A3;                /*!< Offset: 0x024 (R/W)  MPU Alias 3 Region Base Address Register */\n  __IOM uint32_t RASR_A3;                /*!< Offset: 0x028 (R/W)  MPU Alias 3 Region Attribute and Size Register */\n} MPU_Type;\n\n#define MPU_TYPE_RALIASES                  4U\n\n/* MPU Type Register Definitions */\n#define MPU_TYPE_IREGION_Pos               16U                                            /*!< MPU TYPE: IREGION Position */\n#define MPU_TYPE_IREGION_Msk               (0xFFUL << MPU_TYPE_IREGION_Pos)               /*!< MPU TYPE: IREGION Mask */\n\n#define MPU_TYPE_DREGION_Pos                8U                                            /*!< MPU TYPE: DREGION Position */\n#define MPU_TYPE_DREGION_Msk               (0xFFUL << MPU_TYPE_DREGION_Pos)               /*!< MPU TYPE: DREGION Mask */\n\n#define MPU_TYPE_SEPARATE_Pos               0U                                            /*!< MPU TYPE: SEPARATE Position */\n#define MPU_TYPE_SEPARATE_Msk              (1UL /*<< MPU_TYPE_SEPARATE_Pos*/)             /*!< MPU TYPE: SEPARATE Mask */\n\n/* MPU Control Register Definitions */\n#define MPU_CTRL_PRIVDEFENA_Pos             2U                                            /*!< MPU CTRL: PRIVDEFENA Position */\n#define MPU_CTRL_PRIVDEFENA_Msk            (1UL << MPU_CTRL_PRIVDEFENA_Pos)               /*!< MPU CTRL: PRIVDEFENA Mask */\n\n#define MPU_CTRL_HFNMIENA_Pos               1U                                            /*!< MPU CTRL: HFNMIENA Position */\n#define MPU_CTRL_HFNMIENA_Msk              (1UL << MPU_CTRL_HFNMIENA_Pos)                 /*!< MPU CTRL: HFNMIENA Mask */\n\n#define MPU_CTRL_ENABLE_Pos                 0U                                            /*!< MPU CTRL: ENABLE Position */\n#define MPU_CTRL_ENABLE_Msk                (1UL /*<< MPU_CTRL_ENABLE_Pos*/)               /*!< MPU CTRL: ENABLE Mask */\n\n/* MPU Region Number Register Definitions */\n#define MPU_RNR_REGION_Pos                  0U                                            /*!< MPU RNR: REGION Position */\n#define MPU_RNR_REGION_Msk                 (0xFFUL /*<< MPU_RNR_REGION_Pos*/)             /*!< MPU RNR: REGION Mask */\n\n/* MPU Region Base Address Register Definitions */\n#define MPU_RBAR_ADDR_Pos                   5U                                            /*!< MPU RBAR: ADDR Position */\n#define MPU_RBAR_ADDR_Msk                  (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos)             /*!< MPU RBAR: ADDR Mask */\n\n#define MPU_RBAR_VALID_Pos                  4U                                            /*!< MPU RBAR: VALID Position */\n#define MPU_RBAR_VALID_Msk                 (1UL << MPU_RBAR_VALID_Pos)                    /*!< MPU RBAR: VALID Mask */\n\n#define MPU_RBAR_REGION_Pos                 0U                                            /*!< MPU RBAR: REGION Position */\n#define MPU_RBAR_REGION_Msk                (0xFUL /*<< MPU_RBAR_REGION_Pos*/)             /*!< MPU RBAR: REGION Mask */\n\n/* MPU Region Attribute and Size Register Definitions */\n#define MPU_RASR_ATTRS_Pos                 16U                                            /*!< MPU RASR: MPU Region Attribute field Position */\n#define MPU_RASR_ATTRS_Msk                 (0xFFFFUL << MPU_RASR_ATTRS_Pos)               /*!< MPU RASR: MPU Region Attribute field Mask */\n\n#define MPU_RASR_XN_Pos                    28U                                            /*!< MPU RASR: ATTRS.XN Position */\n#define MPU_RASR_XN_Msk                    (1UL << MPU_RASR_XN_Pos)                       /*!< MPU RASR: ATTRS.XN Mask */\n\n#define MPU_RASR_AP_Pos                    24U                                            /*!< MPU RASR: ATTRS.AP Position */\n#define MPU_RASR_AP_Msk                    (0x7UL << MPU_RASR_AP_Pos)                     /*!< MPU RASR: ATTRS.AP Mask */\n\n#define MPU_RASR_TEX_Pos                   19U                                            /*!< MPU RASR: ATTRS.TEX Position */\n#define MPU_RASR_TEX_Msk                   (0x7UL << MPU_RASR_TEX_Pos)                    /*!< MPU RASR: ATTRS.TEX Mask */\n\n#define MPU_RASR_S_Pos                     18U                                            /*!< MPU RASR: ATTRS.S Position */\n#define MPU_RASR_S_Msk                     (1UL << MPU_RASR_S_Pos)                        /*!< MPU RASR: ATTRS.S Mask */\n\n#define MPU_RASR_C_Pos                     17U                                            /*!< MPU RASR: ATTRS.C Position */\n#define MPU_RASR_C_Msk                     (1UL << MPU_RASR_C_Pos)                        /*!< MPU RASR: ATTRS.C Mask */\n\n#define MPU_RASR_B_Pos                     16U                                            /*!< MPU RASR: ATTRS.B Position */\n#define MPU_RASR_B_Msk                     (1UL << MPU_RASR_B_Pos)                        /*!< MPU RASR: ATTRS.B Mask */\n\n#define MPU_RASR_SRD_Pos                    8U                                            /*!< MPU RASR: Sub-Region Disable Position */\n#define MPU_RASR_SRD_Msk                   (0xFFUL << MPU_RASR_SRD_Pos)                   /*!< MPU RASR: Sub-Region Disable Mask */\n\n#define MPU_RASR_SIZE_Pos                   1U                                            /*!< MPU RASR: Region Size Field Position */\n#define MPU_RASR_SIZE_Msk                  (0x1FUL << MPU_RASR_SIZE_Pos)                  /*!< MPU RASR: Region Size Field Mask */\n\n#define MPU_RASR_ENABLE_Pos                 0U                                            /*!< MPU RASR: Region enable bit Position */\n#define MPU_RASR_ENABLE_Msk                (1UL /*<< MPU_RASR_ENABLE_Pos*/)               /*!< MPU RASR: Region enable bit Disable Mask */\n\n/*@} end of group CMSIS_MPU */\n#endif\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_CoreDebug       Core Debug Registers (CoreDebug)\n  \\brief    Type definitions for the Core Debug Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Core Debug Register (CoreDebug).\n */\ntypedef struct\n{\n  __IOM uint32_t DHCSR;                  /*!< Offset: 0x000 (R/W)  Debug Halting Control and Status Register */\n  __OM  uint32_t DCRSR;                  /*!< Offset: 0x004 ( /W)  Debug Core Register Selector Register */\n  __IOM uint32_t DCRDR;                  /*!< Offset: 0x008 (R/W)  Debug Core Register Data Register */\n  __IOM uint32_t DEMCR;                  /*!< Offset: 0x00C (R/W)  Debug Exception and Monitor Control Register */\n} CoreDebug_Type;\n\n/* Debug Halting Control and Status Register Definitions */\n#define CoreDebug_DHCSR_DBGKEY_Pos         16U                                            /*!< CoreDebug DHCSR: DBGKEY Position */\n#define CoreDebug_DHCSR_DBGKEY_Msk         (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos)       /*!< CoreDebug DHCSR: DBGKEY Mask */\n\n#define CoreDebug_DHCSR_S_RESET_ST_Pos     25U                                            /*!< CoreDebug DHCSR: S_RESET_ST Position */\n#define CoreDebug_DHCSR_S_RESET_ST_Msk     (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos)        /*!< CoreDebug DHCSR: S_RESET_ST Mask */\n\n#define CoreDebug_DHCSR_S_RETIRE_ST_Pos    24U                                            /*!< CoreDebug DHCSR: S_RETIRE_ST Position */\n#define CoreDebug_DHCSR_S_RETIRE_ST_Msk    (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos)       /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */\n\n#define CoreDebug_DHCSR_S_LOCKUP_Pos       19U                                            /*!< CoreDebug DHCSR: S_LOCKUP Position */\n#define CoreDebug_DHCSR_S_LOCKUP_Msk       (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos)          /*!< CoreDebug DHCSR: S_LOCKUP Mask */\n\n#define CoreDebug_DHCSR_S_SLEEP_Pos        18U                                            /*!< CoreDebug DHCSR: S_SLEEP Position */\n#define CoreDebug_DHCSR_S_SLEEP_Msk        (1UL << CoreDebug_DHCSR_S_SLEEP_Pos)           /*!< CoreDebug DHCSR: S_SLEEP Mask */\n\n#define CoreDebug_DHCSR_S_HALT_Pos         17U                                            /*!< CoreDebug DHCSR: S_HALT Position */\n#define CoreDebug_DHCSR_S_HALT_Msk         (1UL << CoreDebug_DHCSR_S_HALT_Pos)            /*!< CoreDebug DHCSR: S_HALT Mask */\n\n#define CoreDebug_DHCSR_S_REGRDY_Pos       16U                                            /*!< CoreDebug DHCSR: S_REGRDY Position */\n#define CoreDebug_DHCSR_S_REGRDY_Msk       (1UL << CoreDebug_DHCSR_S_REGRDY_Pos)          /*!< CoreDebug DHCSR: S_REGRDY Mask */\n\n#define CoreDebug_DHCSR_C_SNAPSTALL_Pos     5U                                            /*!< CoreDebug DHCSR: C_SNAPSTALL Position */\n#define CoreDebug_DHCSR_C_SNAPSTALL_Msk    (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos)       /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */\n\n#define CoreDebug_DHCSR_C_MASKINTS_Pos      3U                                            /*!< CoreDebug DHCSR: C_MASKINTS Position */\n#define CoreDebug_DHCSR_C_MASKINTS_Msk     (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos)        /*!< CoreDebug DHCSR: C_MASKINTS Mask */\n\n#define CoreDebug_DHCSR_C_STEP_Pos          2U                                            /*!< CoreDebug DHCSR: C_STEP Position */\n#define CoreDebug_DHCSR_C_STEP_Msk         (1UL << CoreDebug_DHCSR_C_STEP_Pos)            /*!< CoreDebug DHCSR: C_STEP Mask */\n\n#define CoreDebug_DHCSR_C_HALT_Pos          1U                                            /*!< CoreDebug DHCSR: C_HALT Position */\n#define CoreDebug_DHCSR_C_HALT_Msk         (1UL << CoreDebug_DHCSR_C_HALT_Pos)            /*!< CoreDebug DHCSR: C_HALT Mask */\n\n#define CoreDebug_DHCSR_C_DEBUGEN_Pos       0U                                            /*!< CoreDebug DHCSR: C_DEBUGEN Position */\n#define CoreDebug_DHCSR_C_DEBUGEN_Msk      (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/)     /*!< CoreDebug DHCSR: C_DEBUGEN Mask */\n\n/* Debug Core Register Selector Register Definitions */\n#define CoreDebug_DCRSR_REGWnR_Pos         16U                                            /*!< CoreDebug DCRSR: REGWnR Position */\n#define CoreDebug_DCRSR_REGWnR_Msk         (1UL << CoreDebug_DCRSR_REGWnR_Pos)            /*!< CoreDebug DCRSR: REGWnR Mask */\n\n#define CoreDebug_DCRSR_REGSEL_Pos          0U                                            /*!< CoreDebug DCRSR: REGSEL Position */\n#define CoreDebug_DCRSR_REGSEL_Msk         (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/)     /*!< CoreDebug DCRSR: REGSEL Mask */\n\n/* Debug Exception and Monitor Control Register Definitions */\n#define CoreDebug_DEMCR_TRCENA_Pos         24U                                            /*!< CoreDebug DEMCR: TRCENA Position */\n#define CoreDebug_DEMCR_TRCENA_Msk         (1UL << CoreDebug_DEMCR_TRCENA_Pos)            /*!< CoreDebug DEMCR: TRCENA Mask */\n\n#define CoreDebug_DEMCR_MON_REQ_Pos        19U                                            /*!< CoreDebug DEMCR: MON_REQ Position */\n#define CoreDebug_DEMCR_MON_REQ_Msk        (1UL << CoreDebug_DEMCR_MON_REQ_Pos)           /*!< CoreDebug DEMCR: MON_REQ Mask */\n\n#define CoreDebug_DEMCR_MON_STEP_Pos       18U                                            /*!< CoreDebug DEMCR: MON_STEP Position */\n#define CoreDebug_DEMCR_MON_STEP_Msk       (1UL << CoreDebug_DEMCR_MON_STEP_Pos)          /*!< CoreDebug DEMCR: MON_STEP Mask */\n\n#define CoreDebug_DEMCR_MON_PEND_Pos       17U                                            /*!< CoreDebug DEMCR: MON_PEND Position */\n#define CoreDebug_DEMCR_MON_PEND_Msk       (1UL << CoreDebug_DEMCR_MON_PEND_Pos)          /*!< CoreDebug DEMCR: MON_PEND Mask */\n\n#define CoreDebug_DEMCR_MON_EN_Pos         16U                                            /*!< CoreDebug DEMCR: MON_EN Position */\n#define CoreDebug_DEMCR_MON_EN_Msk         (1UL << CoreDebug_DEMCR_MON_EN_Pos)            /*!< CoreDebug DEMCR: MON_EN Mask */\n\n#define CoreDebug_DEMCR_VC_HARDERR_Pos     10U                                            /*!< CoreDebug DEMCR: VC_HARDERR Position */\n#define CoreDebug_DEMCR_VC_HARDERR_Msk     (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos)        /*!< CoreDebug DEMCR: VC_HARDERR Mask */\n\n#define CoreDebug_DEMCR_VC_INTERR_Pos       9U                                            /*!< CoreDebug DEMCR: VC_INTERR Position */\n#define CoreDebug_DEMCR_VC_INTERR_Msk      (1UL << CoreDebug_DEMCR_VC_INTERR_Pos)         /*!< CoreDebug DEMCR: VC_INTERR Mask */\n\n#define CoreDebug_DEMCR_VC_BUSERR_Pos       8U                                            /*!< CoreDebug DEMCR: VC_BUSERR Position */\n#define CoreDebug_DEMCR_VC_BUSERR_Msk      (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos)         /*!< CoreDebug DEMCR: VC_BUSERR Mask */\n\n#define CoreDebug_DEMCR_VC_STATERR_Pos      7U                                            /*!< CoreDebug DEMCR: VC_STATERR Position */\n#define CoreDebug_DEMCR_VC_STATERR_Msk     (1UL << CoreDebug_DEMCR_VC_STATERR_Pos)        /*!< CoreDebug DEMCR: VC_STATERR Mask */\n\n#define CoreDebug_DEMCR_VC_CHKERR_Pos       6U                                            /*!< CoreDebug DEMCR: VC_CHKERR Position */\n#define CoreDebug_DEMCR_VC_CHKERR_Msk      (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos)         /*!< CoreDebug DEMCR: VC_CHKERR Mask */\n\n#define CoreDebug_DEMCR_VC_NOCPERR_Pos      5U                                            /*!< CoreDebug DEMCR: VC_NOCPERR Position */\n#define CoreDebug_DEMCR_VC_NOCPERR_Msk     (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos)        /*!< CoreDebug DEMCR: VC_NOCPERR Mask */\n\n#define CoreDebug_DEMCR_VC_MMERR_Pos        4U                                            /*!< CoreDebug DEMCR: VC_MMERR Position */\n#define CoreDebug_DEMCR_VC_MMERR_Msk       (1UL << CoreDebug_DEMCR_VC_MMERR_Pos)          /*!< CoreDebug DEMCR: VC_MMERR Mask */\n\n#define CoreDebug_DEMCR_VC_CORERESET_Pos    0U                                            /*!< CoreDebug DEMCR: VC_CORERESET Position */\n#define CoreDebug_DEMCR_VC_CORERESET_Msk   (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/)  /*!< CoreDebug DEMCR: VC_CORERESET Mask */\n\n/*@} end of group CMSIS_CoreDebug */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_core_bitfield     Core register bit field macros\n  \\brief      Macros for use with bit field definitions (xxx_Pos, xxx_Msk).\n  @{\n */\n\n/**\n  \\brief   Mask and shift a bit field value for use in a register bit range.\n  \\param[in] field  Name of the register bit field.\n  \\param[in] value  Value of the bit field. This parameter is interpreted as an uint32_t type.\n  \\return           Masked and shifted value.\n*/\n#define _VAL2FLD(field, value)    (((uint32_t)(value) << field ## _Pos) & field ## _Msk)\n\n/**\n  \\brief     Mask and shift a register value to extract a bit filed value.\n  \\param[in] field  Name of the register bit field.\n  \\param[in] value  Value of register. This parameter is interpreted as an uint32_t type.\n  \\return           Masked and shifted bit field value.\n*/\n#define _FLD2VAL(field, value)    (((uint32_t)(value) & field ## _Msk) >> field ## _Pos)\n\n/*@} end of group CMSIS_core_bitfield */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_core_base     Core Definitions\n  \\brief      Definitions for base addresses, unions, and structures.\n  @{\n */\n\n/* Memory mapping of Core Hardware */\n#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */\n#define ITM_BASE            (0xE0000000UL)                            /*!< ITM Base Address */\n#define DWT_BASE            (0xE0001000UL)                            /*!< DWT Base Address */\n#define TPI_BASE            (0xE0040000UL)                            /*!< TPI Base Address */\n#define CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address */\n#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address */\n#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address */\n#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!< System Control Block Base Address */\n\n#define SCnSCB              ((SCnSCB_Type    *)     SCS_BASE      )   /*!< System control Register not in SCB */\n#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct */\n#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct */\n#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct */\n#define ITM                 ((ITM_Type       *)     ITM_BASE      )   /*!< ITM configuration struct */\n#define DWT                 ((DWT_Type       *)     DWT_BASE      )   /*!< DWT configuration struct */\n#define TPI                 ((TPI_Type       *)     TPI_BASE      )   /*!< TPI configuration struct */\n#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct */\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n  #define MPU_BASE          (SCS_BASE +  0x0D90UL)                    /*!< Memory Protection Unit */\n  #define MPU               ((MPU_Type       *)     MPU_BASE      )   /*!< Memory Protection Unit */\n#endif\n\n/*@} */\n\n\n\n/*******************************************************************************\n *                Hardware Abstraction Layer\n  Core Function Interface contains:\n  - Core NVIC Functions\n  - Core SysTick Functions\n  - Core Debug Functions\n  - Core Register Access Functions\n ******************************************************************************/\n/**\n  \\defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference\n*/\n\n\n\n/* ##########################   NVIC functions  #################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_NVICFunctions NVIC Functions\n  \\brief    Functions that manage interrupts and exceptions via the NVIC.\n  @{\n */\n\n#ifdef CMSIS_NVIC_VIRTUAL\n  #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE\n    #define CMSIS_NVIC_VIRTUAL_HEADER_FILE \"cmsis_nvic_virtual.h\"\n  #endif\n  #include CMSIS_NVIC_VIRTUAL_HEADER_FILE\n#else\n  #define NVIC_SetPriorityGrouping    __NVIC_SetPriorityGrouping\n  #define NVIC_GetPriorityGrouping    __NVIC_GetPriorityGrouping\n  #define NVIC_EnableIRQ              __NVIC_EnableIRQ\n  #define NVIC_GetEnableIRQ           __NVIC_GetEnableIRQ\n  #define NVIC_DisableIRQ             __NVIC_DisableIRQ\n  #define NVIC_GetPendingIRQ          __NVIC_GetPendingIRQ\n  #define NVIC_SetPendingIRQ          __NVIC_SetPendingIRQ\n  #define NVIC_ClearPendingIRQ        __NVIC_ClearPendingIRQ\n  #define NVIC_GetActive              __NVIC_GetActive\n  #define NVIC_SetPriority            __NVIC_SetPriority\n  #define NVIC_GetPriority            __NVIC_GetPriority\n  #define NVIC_SystemReset            __NVIC_SystemReset\n#endif /* CMSIS_NVIC_VIRTUAL */\n\n#ifdef CMSIS_VECTAB_VIRTUAL\n  #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE\n    #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE \"cmsis_vectab_virtual.h\"\n  #endif\n  #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE\n#else\n  #define NVIC_SetVector              __NVIC_SetVector\n  #define NVIC_GetVector              __NVIC_GetVector\n#endif  /* (CMSIS_VECTAB_VIRTUAL) */\n\n#define NVIC_USER_IRQ_OFFSET          16\n\n\n/* The following EXC_RETURN values are saved the LR on exception entry */\n#define EXC_RETURN_HANDLER         (0xFFFFFFF1UL)     /* return to Handler mode, uses MSP after return                               */\n#define EXC_RETURN_THREAD_MSP      (0xFFFFFFF9UL)     /* return to Thread mode, uses MSP after return                                */\n#define EXC_RETURN_THREAD_PSP      (0xFFFFFFFDUL)     /* return to Thread mode, uses PSP after return                                */\n\n\n/**\n  \\brief   Set Priority Grouping\n  \\details Sets the priority grouping field using the required unlock sequence.\n           The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field.\n           Only values from 0..7 are used.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.\n  \\param [in]      PriorityGroup  Priority grouping field.\n */\n__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup)\n{\n  uint32_t reg_value;\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);             /* only values 0..7 are used          */\n\n  reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */\n  reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change               */\n  reg_value  =  (reg_value                                   |\n                ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |\n                (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos)  );              /* Insert write key and priority group */\n  SCB->AIRCR =  reg_value;\n}\n\n\n/**\n  \\brief   Get Priority Grouping\n  \\details Reads the priority grouping field from the NVIC Interrupt Controller.\n  \\return                Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field).\n */\n__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void)\n{\n  return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos));\n}\n\n\n/**\n  \\brief   Enable Interrupt\n  \\details Enables a device specific interrupt in the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    __COMPILER_BARRIER();\n    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n    __COMPILER_BARRIER();\n  }\n}\n\n\n/**\n  \\brief   Get Interrupt Enable status\n  \\details Returns a device specific interrupt enable status from the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt is not enabled.\n  \\return             1  Interrupt is enabled.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Disable Interrupt\n  \\details Disables a device specific interrupt in the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n    __DSB();\n    __ISB();\n  }\n}\n\n\n/**\n  \\brief   Get Pending Interrupt\n  \\details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt status is not pending.\n  \\return             1  Interrupt status is pending.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Set Pending Interrupt\n  \\details Sets the pending bit of a device specific interrupt in the NVIC pending register.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n  }\n}\n\n\n/**\n  \\brief   Clear Pending Interrupt\n  \\details Clears the pending bit of a device specific interrupt in the NVIC pending register.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n  }\n}\n\n\n/**\n  \\brief   Get Active Interrupt\n  \\details Reads the active register in the NVIC and returns the active bit for the device specific interrupt.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt status is not active.\n  \\return             1  Interrupt status is active.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Set Interrupt Priority\n  \\details Sets the priority of a device specific interrupt or a processor exception.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]      IRQn  Interrupt number.\n  \\param [in]  priority  Priority to set.\n  \\note    The priority cannot be set for every processor exception.\n */\n__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->IP[((uint32_t)IRQn)]               = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);\n  }\n  else\n  {\n    SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);\n  }\n}\n\n\n/**\n  \\brief   Get Interrupt Priority\n  \\details Reads the priority of a device specific interrupt or a processor exception.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]   IRQn  Interrupt number.\n  \\return             Interrupt Priority.\n                      Value is aligned automatically to the implemented priority bits of the microcontroller.\n */\n__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn)\n{\n\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return(((uint32_t)NVIC->IP[((uint32_t)IRQn)]               >> (8U - __NVIC_PRIO_BITS)));\n  }\n  else\n  {\n    return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS)));\n  }\n}\n\n\n/**\n  \\brief   Encode Priority\n  \\details Encodes the priority for an interrupt with the given priority group,\n           preemptive priority value, and subpriority value.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.\n  \\param [in]     PriorityGroup  Used priority group.\n  \\param [in]   PreemptPriority  Preemptive priority value (starting from 0).\n  \\param [in]       SubPriority  Subpriority value (starting from 0).\n  \\return                        Encoded priority. Value can be used in the function \\ref NVIC_SetPriority().\n */\n__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)\n{\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);   /* only values 0..7 are used          */\n  uint32_t PreemptPriorityBits;\n  uint32_t SubPriorityBits;\n\n  PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);\n  SubPriorityBits     = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));\n\n  return (\n           ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) |\n           ((SubPriority     & (uint32_t)((1UL << (SubPriorityBits    )) - 1UL)))\n         );\n}\n\n\n/**\n  \\brief   Decode Priority\n  \\details Decodes an interrupt priority value with a given priority group to\n           preemptive priority value and subpriority value.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set.\n  \\param [in]         Priority   Priority value, which can be retrieved with the function \\ref NVIC_GetPriority().\n  \\param [in]     PriorityGroup  Used priority group.\n  \\param [out] pPreemptPriority  Preemptive priority value (starting from 0).\n  \\param [out]     pSubPriority  Subpriority value (starting from 0).\n */\n__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority)\n{\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);   /* only values 0..7 are used          */\n  uint32_t PreemptPriorityBits;\n  uint32_t SubPriorityBits;\n\n  PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);\n  SubPriorityBits     = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));\n\n  *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL);\n  *pSubPriority     = (Priority                   ) & (uint32_t)((1UL << (SubPriorityBits    )) - 1UL);\n}\n\n\n/**\n  \\brief   Set Interrupt Vector\n  \\details Sets an interrupt vector in SRAM based interrupt vector table.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n           VTOR must been relocated to SRAM before.\n  \\param [in]   IRQn      Interrupt number\n  \\param [in]   vector    Address of interrupt handler function\n */\n__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)\n{\n  uint32_t *vectors = (uint32_t *)SCB->VTOR;\n  vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector;\n  /* ARM Application Note 321 states that the M3 does not require the architectural barrier */\n}\n\n\n/**\n  \\brief   Get Interrupt Vector\n  \\details Reads an interrupt vector from interrupt vector table.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]   IRQn      Interrupt number.\n  \\return                 Address of interrupt handler function\n */\n__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn)\n{\n  uint32_t *vectors = (uint32_t *)SCB->VTOR;\n  return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET];\n}\n\n\n/**\n  \\brief   System Reset\n  \\details Initiates a system reset request to reset the MCU.\n */\n__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void)\n{\n  __DSB();                                                          /* Ensure all outstanding memory accesses included\n                                                                       buffered write are completed before reset */\n  SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |\n                           (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |\n                            SCB_AIRCR_SYSRESETREQ_Msk    );         /* Keep priority group unchanged */\n  __DSB();                                                          /* Ensure completion of memory access */\n\n  for(;;)                                                           /* wait until reset */\n  {\n    __NOP();\n  }\n}\n\n/*@} end of CMSIS_Core_NVICFunctions */\n\n\n/* ##########################  MPU functions  #################################### */\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n\n#include \"mpu_armv7.h\"\n\n#endif\n\n\n/* ##########################  FPU functions  #################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_FpuFunctions FPU Functions\n  \\brief    Function that provides FPU type.\n  @{\n */\n\n/**\n  \\brief   get FPU type\n  \\details returns the FPU type\n  \\returns\n   - \\b  0: No FPU\n   - \\b  1: Single precision FPU\n   - \\b  2: Double + Single precision FPU\n */\n__STATIC_INLINE uint32_t SCB_GetFPUType(void)\n{\n    return 0U;           /* No FPU */\n}\n\n\n/*@} end of CMSIS_Core_FpuFunctions */\n\n\n\n/* ##################################    SysTick function  ############################################ */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_SysTickFunctions SysTick Functions\n  \\brief    Functions that configure the System.\n  @{\n */\n\n#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)\n\n/**\n  \\brief   System Tick Configuration\n  \\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.\n           Counter is in free running mode to generate periodic interrupts.\n  \\param [in]  ticks  Number of ticks between two interrupts.\n  \\return          0  Function succeeded.\n  \\return          1  Function failed.\n  \\note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the\n           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>\n           must contain a vendor-specific implementation of this function.\n */\n__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)\n{\n  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)\n  {\n    return (1UL);                                                   /* Reload value impossible */\n  }\n\n  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */\n  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */\n  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */\n  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |\n                   SysTick_CTRL_TICKINT_Msk   |\n                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */\n  return (0UL);                                                     /* Function successful */\n}\n\n#endif\n\n/*@} end of CMSIS_Core_SysTickFunctions */\n\n\n\n/* ##################################### Debug In/Output function ########################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_core_DebugFunctions ITM Functions\n  \\brief    Functions that access the ITM debug interface.\n  @{\n */\n\nextern volatile int32_t ITM_RxBuffer;                              /*!< External variable to receive characters. */\n#define                 ITM_RXBUFFER_EMPTY  ((int32_t)0x5AA55AA5U) /*!< Value identifying \\ref ITM_RxBuffer is ready for next character. */\n\n\n/**\n  \\brief   ITM Send Character\n  \\details Transmits a character via the ITM channel 0, and\n           \\li Just returns when no debugger is connected that has booked the output.\n           \\li Is blocking when a debugger is connected, but the previous character sent has not been transmitted.\n  \\param [in]     ch  Character to transmit.\n  \\returns            Character to transmit.\n */\n__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)\n{\n  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */\n      ((ITM->TER & 1UL               ) != 0UL)   )     /* ITM Port #0 enabled */\n  {\n    while (ITM->PORT[0U].u32 == 0UL)\n    {\n      __NOP();\n    }\n    ITM->PORT[0U].u8 = (uint8_t)ch;\n  }\n  return (ch);\n}\n\n\n/**\n  \\brief   ITM Receive Character\n  \\details Inputs a character via the external variable \\ref ITM_RxBuffer.\n  \\return             Received character.\n  \\return         -1  No character pending.\n */\n__STATIC_INLINE int32_t ITM_ReceiveChar (void)\n{\n  int32_t ch = -1;                           /* no character available */\n\n  if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY)\n  {\n    ch = ITM_RxBuffer;\n    ITM_RxBuffer = ITM_RXBUFFER_EMPTY;       /* ready for next character */\n  }\n\n  return (ch);\n}\n\n\n/**\n  \\brief   ITM Check Character\n  \\details Checks whether a character is pending for reading in the variable \\ref ITM_RxBuffer.\n  \\return          0  No character available.\n  \\return          1  Character available.\n */\n__STATIC_INLINE int32_t ITM_CheckChar (void)\n{\n\n  if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY)\n  {\n    return (0);                              /* no character available */\n  }\n  else\n  {\n    return (1);                              /*    character available */\n  }\n}\n\n/*@} end of CMSIS_core_DebugFunctions */\n\n\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __CORE_CM3_H_DEPENDANT */\n\n#endif /* __CMSIS_GENERIC */\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/mpu_armv7.h",
    "content": "/******************************************************************************\n * @file     mpu_armv7.h\n * @brief    CMSIS MPU API for Armv7-M MPU\n * @version  V5.1.2\n * @date     25. May 2020\n ******************************************************************************/\n/*\n * Copyright (c) 2017-2020 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n \n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header    /* treat file as system include file */\n#endif\n \n#ifndef ARM_MPU_ARMV7_H\n#define ARM_MPU_ARMV7_H\n\n#define ARM_MPU_REGION_SIZE_32B      ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes\n#define ARM_MPU_REGION_SIZE_64B      ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes\n#define ARM_MPU_REGION_SIZE_128B     ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes\n#define ARM_MPU_REGION_SIZE_256B     ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes\n#define ARM_MPU_REGION_SIZE_512B     ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes\n#define ARM_MPU_REGION_SIZE_1KB      ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte\n#define ARM_MPU_REGION_SIZE_2KB      ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes\n#define ARM_MPU_REGION_SIZE_4KB      ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes\n#define ARM_MPU_REGION_SIZE_8KB      ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes\n#define ARM_MPU_REGION_SIZE_16KB     ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes\n#define ARM_MPU_REGION_SIZE_32KB     ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes\n#define ARM_MPU_REGION_SIZE_64KB     ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes\n#define ARM_MPU_REGION_SIZE_128KB    ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes\n#define ARM_MPU_REGION_SIZE_256KB    ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes\n#define ARM_MPU_REGION_SIZE_512KB    ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes\n#define ARM_MPU_REGION_SIZE_1MB      ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte\n#define ARM_MPU_REGION_SIZE_2MB      ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes\n#define ARM_MPU_REGION_SIZE_4MB      ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes\n#define ARM_MPU_REGION_SIZE_8MB      ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes\n#define ARM_MPU_REGION_SIZE_16MB     ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes\n#define ARM_MPU_REGION_SIZE_32MB     ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes\n#define ARM_MPU_REGION_SIZE_64MB     ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes\n#define ARM_MPU_REGION_SIZE_128MB    ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes\n#define ARM_MPU_REGION_SIZE_256MB    ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes\n#define ARM_MPU_REGION_SIZE_512MB    ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes\n#define ARM_MPU_REGION_SIZE_1GB      ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte\n#define ARM_MPU_REGION_SIZE_2GB      ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes\n#define ARM_MPU_REGION_SIZE_4GB      ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes\n\n#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access\n#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only\n#define ARM_MPU_AP_URO  2U ///!< MPU Access Permission unprivileged access read-only\n#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access\n#define ARM_MPU_AP_PRO  5U ///!< MPU Access Permission privileged access read-only\n#define ARM_MPU_AP_RO   6U ///!< MPU Access Permission read-only access\n\n/** MPU Region Base Address Register Value\n*\n* \\param Region The region to be configured, number 0 to 15.\n* \\param BaseAddress The base address for the region.\n*/\n#define ARM_MPU_RBAR(Region, BaseAddress) \\\n  (((BaseAddress) & MPU_RBAR_ADDR_Msk) |  \\\n   ((Region) & MPU_RBAR_REGION_Msk)    |  \\\n   (MPU_RBAR_VALID_Msk))\n\n/**\n* MPU Memory Access Attributes\n* \n* \\param TypeExtField      Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.\n* \\param IsShareable       Region is shareable between multiple bus masters.\n* \\param IsCacheable       Region is cacheable, i.e. its value may be kept in cache.\n* \\param IsBufferable      Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.\n*/  \n#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable)   \\\n  ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk)                  | \\\n   (((IsShareable)  << MPU_RASR_S_Pos)   & MPU_RASR_S_Msk)                    | \\\n   (((IsCacheable)  << MPU_RASR_C_Pos)   & MPU_RASR_C_Msk)                    | \\\n   (((IsBufferable) << MPU_RASR_B_Pos)   & MPU_RASR_B_Msk))\n\n/**\n* MPU Region Attribute and Size Register Value\n* \n* \\param DisableExec       Instruction access disable bit, 1= disable instruction fetches.\n* \\param AccessPermission  Data access permissions, allows you to configure read/write access for User and Privileged mode.\n* \\param AccessAttributes  Memory access attribution, see \\ref ARM_MPU_ACCESS_.\n* \\param SubRegionDisable  Sub-region disable field.\n* \\param Size              Region size of the region to be configured, for example 4K, 8K.\n*/\n#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size)    \\\n  ((((DisableExec)      << MPU_RASR_XN_Pos)   & MPU_RASR_XN_Msk)                                  | \\\n   (((AccessPermission) << MPU_RASR_AP_Pos)   & MPU_RASR_AP_Msk)                                  | \\\n   (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \\\n   (((SubRegionDisable) << MPU_RASR_SRD_Pos)  & MPU_RASR_SRD_Msk)                                 | \\\n   (((Size)             << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk)                                | \\\n   (((MPU_RASR_ENABLE_Msk))))\n\n/**\n* MPU Region Attribute and Size Register Value\n* \n* \\param DisableExec       Instruction access disable bit, 1= disable instruction fetches.\n* \\param AccessPermission  Data access permissions, allows you to configure read/write access for User and Privileged mode.\n* \\param TypeExtField      Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.\n* \\param IsShareable       Region is shareable between multiple bus masters.\n* \\param IsCacheable       Region is cacheable, i.e. its value may be kept in cache.\n* \\param IsBufferable      Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.\n* \\param SubRegionDisable  Sub-region disable field.\n* \\param Size              Region size of the region to be configured, for example 4K, 8K.\n*/                         \n#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \\\n  ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)\n\n/**\n* MPU Memory Access Attribute for strongly ordered memory.\n*  - TEX: 000b\n*  - Shareable\n*  - Non-cacheable\n*  - Non-bufferable\n*/ \n#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)\n\n/**\n* MPU Memory Access Attribute for device memory.\n*  - TEX: 000b (if shareable) or 010b (if non-shareable)\n*  - Shareable or non-shareable\n*  - Non-cacheable\n*  - Bufferable (if shareable) or non-bufferable (if non-shareable)\n*\n* \\param IsShareable Configures the device memory as shareable or non-shareable.\n*/ \n#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))\n\n/**\n* MPU Memory Access Attribute for normal memory.\n*  - TEX: 1BBb (reflecting outer cacheability rules)\n*  - Shareable or non-shareable\n*  - Cacheable or non-cacheable (reflecting inner cacheability rules)\n*  - Bufferable or non-bufferable (reflecting inner cacheability rules)\n*\n* \\param OuterCp Configures the outer cache policy.\n* \\param InnerCp Configures the inner cache policy.\n* \\param IsShareable Configures the memory as shareable or non-shareable.\n*/ \n#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U))\n\n/**\n* MPU Memory Access Attribute non-cacheable policy.\n*/\n#define ARM_MPU_CACHEP_NOCACHE 0U\n\n/**\n* MPU Memory Access Attribute write-back, write and read allocate policy.\n*/\n#define ARM_MPU_CACHEP_WB_WRA 1U\n\n/**\n* MPU Memory Access Attribute write-through, no write allocate policy.\n*/\n#define ARM_MPU_CACHEP_WT_NWA 2U\n\n/**\n* MPU Memory Access Attribute write-back, no write allocate policy.\n*/\n#define ARM_MPU_CACHEP_WB_NWA 3U\n\n\n/**\n* Struct for a single MPU Region\n*/\ntypedef struct {\n  uint32_t RBAR; //!< The region base address register value (RBAR)\n  uint32_t RASR; //!< The region attribute and size register value (RASR) \\ref MPU_RASR\n} ARM_MPU_Region_t;\n    \n/** Enable the MPU.\n* \\param MPU_Control Default access permissions for unconfigured regions.\n*/\n__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)\n{\n  __DMB();\n  MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;\n#ifdef SCB_SHCSR_MEMFAULTENA_Msk\n  SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;\n#endif\n  __DSB();\n  __ISB();\n}\n\n/** Disable the MPU.\n*/\n__STATIC_INLINE void ARM_MPU_Disable(void)\n{\n  __DMB();\n#ifdef SCB_SHCSR_MEMFAULTENA_Msk\n  SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;\n#endif\n  MPU->CTRL  &= ~MPU_CTRL_ENABLE_Msk;\n  __DSB();\n  __ISB();\n}\n\n/** Clear and disable the given MPU region.\n* \\param rnr Region number to be cleared.\n*/\n__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)\n{\n  MPU->RNR = rnr;\n  MPU->RASR = 0U;\n}\n\n/** Configure an MPU region.\n* \\param rbar Value for RBAR register.\n* \\param rasr Value for RASR register.\n*/   \n__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)\n{\n  MPU->RBAR = rbar;\n  MPU->RASR = rasr;\n}\n\n/** Configure the given MPU region.\n* \\param rnr Region number to be configured.\n* \\param rbar Value for RBAR register.\n* \\param rasr Value for RASR register.\n*/   \n__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)\n{\n  MPU->RNR = rnr;\n  MPU->RBAR = rbar;\n  MPU->RASR = rasr;\n}\n\n/** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load().\n* \\param dst Destination data is copied to.\n* \\param src Source data is copied from.\n* \\param len Amount of data words to be copied.\n*/\n__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)\n{\n  uint32_t i;\n  for (i = 0U; i < len; ++i) \n  {\n    dst[i] = src[i];\n  }\n}\n\n/** Load the given number of MPU regions from a table.\n* \\param table Pointer to the MPU configuration table.\n* \\param cnt Amount of regions to be configured.\n*/\n__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) \n{\n  const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;\n  while (cnt > MPU_TYPE_RALIASES) {\n    ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);\n    table += MPU_TYPE_RALIASES;\n    cnt -= MPU_TYPE_RALIASES;\n  }\n  ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/lib/cmsis/system_ARMCM3.h",
    "content": "/**************************************************************************//**\n * @file     system_ARMCM3.h\n * @brief    CMSIS Device System Header File for\n *           ARMCM3 Device\n * @version  V5.3.2\n * @date     15. November 2019\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2019 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SYSTEM_ARMCM3_H\n#define SYSTEM_ARMCM3_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n  \\brief Exception / Interrupt Handler Function Prototype\n*/\ntypedef void(*VECTOR_TABLE_Type)(void);\n\n/**\n  \\brief System Clock Frequency (Core Clock)\n*/\nextern uint32_t SystemCoreClock;\n\n/**\n  \\brief Setup the microcontroller system.\n\n   Initialize the System and update the SystemCoreClock variable.\n */\nextern void SystemInit (void);\n\n\n/**\n  \\brief  Update SystemCoreClock variable.\n\n   Updates the SystemCoreClock with current core Clock retrieved from cpu registers.\n */\nextern void SystemCoreClockUpdate (void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* SYSTEM_ARMCM3_H */\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/main.c",
    "content": "int foo(int x);\n\nint main()\n{\n    return foo(1);\n}\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/startup_ARMCM3.S",
    "content": "/**************************************************************************//**\n * @file     startup_ARMCM3.S\n * @brief    CMSIS-Core(M) Device Startup File for Cortex-M3 Device\n * @version  V2.2.0\n * @date     26. May 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n                .syntax  unified\n                .arch    armv7-m\n\n                .section .vectors\n                .align   2\n                .globl   __Vectors\n                .globl   __Vectors_End\n                .globl   __Vectors_Size\n__Vectors:\n                .long    __StackTop                         /*     Top of Stack */\n                .long    Reset_Handler                      /*     Reset Handler */\n                .long    NMI_Handler                        /* -14 NMI Handler */\n                .long    HardFault_Handler                  /* -13 Hard Fault Handler */\n                .long    MemManage_Handler                  /* -12 MPU Fault Handler */\n                .long    BusFault_Handler                   /* -11 Bus Fault Handler */\n                .long    UsageFault_Handler                 /* -10 Usage Fault Handler */\n                .long    0                                  /*     Reserved */\n                .long    0                                  /*     Reserved */\n                .long    0                                  /*     Reserved */\n                .long    0                                  /*     Reserved */\n                .long    SVC_Handler                        /*  -5 SVC Handler */\n                .long    DebugMon_Handler                   /*  -4 Debug Monitor Handler */\n                .long    0                                  /*     Reserved */\n                .long    PendSV_Handler                     /*  -2 PendSV Handler */\n                .long    SysTick_Handler                    /*  -1 SysTick Handler */\n\n                /* Interrupts */\n                .long    Interrupt0_Handler                 /*   0 Interrupt 0 */\n                .long    Interrupt1_Handler                 /*   1 Interrupt 1 */\n                .long    Interrupt2_Handler                 /*   2 Interrupt 2 */\n                .long    Interrupt3_Handler                 /*   3 Interrupt 3 */\n                .long    Interrupt4_Handler                 /*   4 Interrupt 4 */\n                .long    Interrupt5_Handler                 /*   5 Interrupt 5 */\n                .long    Interrupt6_Handler                 /*   6 Interrupt 6 */\n                .long    Interrupt7_Handler                 /*   7 Interrupt 7 */\n                .long    Interrupt8_Handler                 /*   8 Interrupt 8 */\n                .long    Interrupt9_Handler                 /*   9 Interrupt 9 */\n\n                .space   (214 * 4)                          /* Interrupts 10 .. 224 are left out */\n__Vectors_End:\n                .equ     __Vectors_Size, __Vectors_End - __Vectors\n                .size    __Vectors, . - __Vectors\n\n\n                .thumb\n                .section .text\n                .align   2\n\n                .thumb_func\n                .type    Reset_Handler, %function\n                .globl   Reset_Handler\n                .fnstart\nReset_Handler:\n                bl       SystemInit\n\n                ldr      r4, =__copy_table_start__\n                ldr      r5, =__copy_table_end__\n\n.L_loop0:\n                cmp      r4, r5\n                bge      .L_loop0_done\n                ldr      r1, [r4]                /* source address */\n                ldr      r2, [r4, #4]            /* destination address */\n                ldr      r3, [r4, #8]            /* word count */\n                lsls     r3, r3, #2              /* byte count */\n\n.L_loop0_0:\n                subs     r3, #4                  /* decrement byte count */\n                ittt     ge\n                ldrge    r0, [r1, r3]\n                strge    r0, [r2, r3]\n                bge      .L_loop0_0\n\n                adds     r4, #12\n                b        .L_loop0\n.L_loop0_done:\n\n                ldr      r3, =__zero_table_start__\n                ldr      r4, =__zero_table_end__\n\n.L_loop2:\n                cmp      r3, r4\n                bge      .L_loop2_done\n                ldr      r1, [r3]                /* destination address */\n                ldr      r2, [r3, #4]            /* word count */\n                lsls     r2, r2, #2              /* byte count */\n                movs     r0, 0\n\n.L_loop2_0:\n                subs     r2, #4                  /* decrement byte count */\n                itt      ge\n                strge    r0, [r1, r2]\n                bge      .L_loop2_0\n\n                adds     r3, #8\n                b        .L_loop2\n.L_loop2_done:\n\n                bl       _start\n\n                .fnend\n                .size    Reset_Handler, . - Reset_Handler\n\n/* The default macro is not used for HardFault_Handler\n * because this results in a poor debug illusion.\n */\n                .thumb_func\n                .type    HardFault_Handler, %function\n                .weak    HardFault_Handler\n                .fnstart\nHardFault_Handler:\n                b        .\n                .fnend\n                .size    HardFault_Handler, . - HardFault_Handler\n\n                .thumb_func\n                .type    Default_Handler, %function\n                .weak    Default_Handler\n                .fnstart\nDefault_Handler:\n                b        .\n                .fnend\n                .size    Default_Handler, . - Default_Handler\n\n/* Macro to define default exception/interrupt handlers.\n * Default handler are weak symbols with an endless loop.\n * They can be overwritten by real handlers.\n */\n                .macro   Set_Default_Handler  Handler_Name\n                .weak    \\Handler_Name\n                .set     \\Handler_Name, Default_Handler\n                .endm\n\n\n/* Default exception/interrupt handler */\n\n                Set_Default_Handler  NMI_Handler\n                Set_Default_Handler  MemManage_Handler\n                Set_Default_Handler  BusFault_Handler\n                Set_Default_Handler  UsageFault_Handler\n                Set_Default_Handler  SVC_Handler\n                Set_Default_Handler  DebugMon_Handler\n                Set_Default_Handler  PendSV_Handler\n                Set_Default_Handler  SysTick_Handler\n\n                Set_Default_Handler  Interrupt0_Handler\n                Set_Default_Handler  Interrupt1_Handler\n                Set_Default_Handler  Interrupt2_Handler\n                Set_Default_Handler  Interrupt3_Handler\n                Set_Default_Handler  Interrupt4_Handler\n                Set_Default_Handler  Interrupt5_Handler\n                Set_Default_Handler  Interrupt6_Handler\n                Set_Default_Handler  Interrupt7_Handler\n                Set_Default_Handler  Interrupt8_Handler\n                Set_Default_Handler  Interrupt9_Handler\n\n\n                .end\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/src/system_ARMCM3.c",
    "content": "/**************************************************************************//**\n * @file     system_ARMCM3.c\n * @brief    CMSIS Device System Source File for\n *           ARMCM3 Device\n * @version  V1.0.1\n * @date     15. November 2019\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2019 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ARMCM3.h\"\n\n/*----------------------------------------------------------------------------\n  Define clocks\n *----------------------------------------------------------------------------*/\n#define  XTAL            (50000000UL)     /* Oscillator frequency */\n\n#define  SYSTEM_CLOCK    (XTAL / 2U)\n\n/*----------------------------------------------------------------------------\n  Exception / Interrupt Vector table\n *----------------------------------------------------------------------------*/\nextern const VECTOR_TABLE_Type __VECTOR_TABLE[240];\n\n/*----------------------------------------------------------------------------\n  System Core Clock Variable\n *----------------------------------------------------------------------------*/\nuint32_t SystemCoreClock = SYSTEM_CLOCK;  /* System Core Clock Frequency */\n\n\n/*----------------------------------------------------------------------------\n  System Core Clock update function\n *----------------------------------------------------------------------------*/\nvoid SystemCoreClockUpdate (void)\n{\n  SystemCoreClock = SYSTEM_CLOCK;\n}\n\n/*----------------------------------------------------------------------------\n  System initialization function\n *----------------------------------------------------------------------------*/\nvoid SystemInit (void)\n{\n\n#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)\n  SCB->VTOR = (uint32_t) &(__VECTOR_TABLE[0]);\n#endif\n\n  SystemCoreClock = SYSTEM_CLOCK;\n}\n"
  },
  {
    "path": "tests/projects/embed/gnu-rm/hello/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"gnu-rm\")\nset_toolchains(\"@gnu-rm\")\nset_plat(\"cross\")\nset_arch(\"armv7\")\n\ntarget(\"foo\")\n    add_rules(\"gnu-rm.static\")\n    add_files(\"src/foo/*.c\")\n\ntarget(\"hello\")\n    add_deps(\"foo\")\n    add_rules(\"gnu-rm.binary\")\n    add_files(\"src/*.c\", \"src/*.S\")\n    add_files(\"src/*.ld\")\n    add_includedirs(\"src/lib/cmsis\")\n"
  },
  {
    "path": "tests/projects/embed/iverilog/hello/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/iverilog/hello/xmake.lua",
    "content": "add_requires(\"iverilog\")\ntarget(\"hello\")\n    add_rules(\"iverilog.binary\")\n    set_toolchains(\"@iverilog\")\n    add_files(\"src/*.v\")\n"
  },
  {
    "path": "tests/projects/embed/iverilog/hello_vcd/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $dumpfile(\"hello.vcd\");\n    $dumpvars(0, hello);\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/iverilog/hello_vcd/xmake.lua",
    "content": "add_requires(\"iverilog\")\ntarget(\"hello\")\n    add_rules(\"iverilog.binary\")\n    set_toolchains(\"@iverilog\")\n    add_files(\"src/*.v\")\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/foo/foo.c",
    "content": "int foo(int x)\r\n{\r\n\treturn x;\r\n}\r\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/ARMCM3.h",
    "content": "/**************************************************************************//**\n * @file     ARMCM3.h\n * @brief    CMSIS Core Peripheral Access Layer Header File for\n *           ARMCM3 Device\n * @version  V5.3.1\n * @date     09. July 2018\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2018 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef ARMCM3_H\n#define ARMCM3_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/* -------------------------  Interrupt Number Definition  ------------------------ */\n\ntypedef enum IRQn\n{\n/* -------------------  Processor Exceptions Numbers  ----------------------------- */\n  NonMaskableInt_IRQn           = -14,     /*  2 Non Maskable Interrupt */\n  HardFault_IRQn                = -13,     /*  3 HardFault Interrupt */\n  MemoryManagement_IRQn         = -12,     /*  4 Memory Management Interrupt */\n  BusFault_IRQn                 = -11,     /*  5 Bus Fault Interrupt */\n  UsageFault_IRQn               = -10,     /*  6 Usage Fault Interrupt */\n  SVCall_IRQn                   =  -5,     /* 11 SV Call Interrupt */\n  DebugMonitor_IRQn             =  -4,     /* 12 Debug Monitor Interrupt */\n  PendSV_IRQn                   =  -2,     /* 14 Pend SV Interrupt */\n  SysTick_IRQn                  =  -1,     /* 15 System Tick Interrupt */\n\n/* -------------------  Processor Interrupt Numbers  ------------------------------ */\n  Interrupt0_IRQn               =   0,\n  Interrupt1_IRQn               =   1,\n  Interrupt2_IRQn               =   2,\n  Interrupt3_IRQn               =   3,\n  Interrupt4_IRQn               =   4,\n  Interrupt5_IRQn               =   5,\n  Interrupt6_IRQn               =   6,\n  Interrupt7_IRQn               =   7,\n  Interrupt8_IRQn               =   8,\n  Interrupt9_IRQn               =   9\n  /* Interrupts 10 .. 224 are left out */\n} IRQn_Type;\n\n\n/* ================================================================================ */\n/* ================      Processor and Core Peripheral Section     ================ */\n/* ================================================================================ */\n\n/* -------  Start of section using anonymous unions and disabling warnings  ------- */\n#if   defined (__CC_ARM)\n  #pragma push\n  #pragma anon_unions\n#elif defined (__ICCARM__)\n  #pragma language=extended\n#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wc11-extensions\"\n  #pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#elif defined (__GNUC__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TMS470__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TASKING__)\n  #pragma warning 586\n#elif defined (__CSMC__)\n  /* anonymous unions are enabled by default */\n#else\n  #warning Not supported compiler type\n#endif\n\n\n/* --------  Configuration of Core Peripherals  ----------------------------------- */\n#define __CM3_REV                 0x0201U   /* Core revision r2p1 */\n#define __MPU_PRESENT             1U        /* MPU present */\n#define __VTOR_PRESENT            1U        /* VTOR present */\n#define __NVIC_PRIO_BITS          3U        /* Number of Bits used for Priority Levels */\n#define __Vendor_SysTickConfig    0U        /* Set to 1 if different SysTick Config is used */\n\n#include \"core_cm3.h\"                       /* Processor and core peripherals */\n#include \"system_ARMCM3.h\"                  /* System Header */\n\n\n/* --------  End of section using anonymous unions and disabling warnings  -------- */\n#if   defined (__CC_ARM)\n  #pragma pop\n#elif defined (__ICCARM__)\n  /* leave anonymous unions enabled */\n#elif (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))\n  #pragma clang diagnostic pop\n#elif defined (__GNUC__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TMS470__)\n  /* anonymous unions are enabled by default */\n#elif defined (__TASKING__)\n  #pragma warning restore\n#elif defined (__CSMC__)\n  /* anonymous unions are enabled by default */\n#else\n  #warning Not supported compiler type\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  /* ARMCM3_H */\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_armcc.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_armcc.h\n * @brief    CMSIS compiler ARMCC (Arm Compiler 5) header file\n * @version  V5.3.2\n * @date     27. May 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __CMSIS_ARMCC_H\n#define __CMSIS_ARMCC_H\n\n\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 400677)\n  #error \"Please use Arm Compiler Toolchain V4.0.677 or later!\"\n#endif\n\n/* CMSIS compiler control architecture macros */\n#if ((defined (__TARGET_ARCH_6_M  ) && (__TARGET_ARCH_6_M   == 1)) || \\\n     (defined (__TARGET_ARCH_6S_M ) && (__TARGET_ARCH_6S_M  == 1))   )\n  #define __ARM_ARCH_6M__           1\n#endif\n\n#if (defined (__TARGET_ARCH_7_M ) && (__TARGET_ARCH_7_M  == 1))\n  #define __ARM_ARCH_7M__           1\n#endif\n\n#if (defined (__TARGET_ARCH_7E_M) && (__TARGET_ARCH_7E_M == 1))\n  #define __ARM_ARCH_7EM__          1\n#endif\n\n  /* __ARM_ARCH_8M_BASE__  not applicable */\n  /* __ARM_ARCH_8M_MAIN__  not applicable */\n  /* __ARM_ARCH_8_1M_MAIN__  not applicable */\n\n/* CMSIS compiler control DSP macros */\n#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     )\n  #define __ARM_FEATURE_DSP         1\n#endif\n\n/* CMSIS compiler specific defines */\n#ifndef   __ASM\n  #define __ASM                                  __asm\n#endif\n#ifndef   __INLINE\n  #define __INLINE                               __inline\n#endif\n#ifndef   __STATIC_INLINE\n  #define __STATIC_INLINE                        static __inline\n#endif\n#ifndef   __STATIC_FORCEINLINE\n  #define __STATIC_FORCEINLINE                   static __forceinline\n#endif\n#ifndef   __NO_RETURN\n  #define __NO_RETURN                            __declspec(noreturn)\n#endif\n#ifndef   __USED\n  #define __USED                                 __attribute__((used))\n#endif\n#ifndef   __WEAK\n  #define __WEAK                                 __attribute__((weak))\n#endif\n#ifndef   __PACKED\n  #define __PACKED                               __attribute__((packed))\n#endif\n#ifndef   __PACKED_STRUCT\n  #define __PACKED_STRUCT                        __packed struct\n#endif\n#ifndef   __PACKED_UNION\n  #define __PACKED_UNION                         __packed union\n#endif\n#ifndef   __UNALIGNED_UINT32        /* deprecated */\n  #define __UNALIGNED_UINT32(x)                  (*((__packed uint32_t *)(x)))\n#endif\n#ifndef   __UNALIGNED_UINT16_WRITE\n  #define __UNALIGNED_UINT16_WRITE(addr, val)    ((*((__packed uint16_t *)(addr))) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT16_READ\n  #define __UNALIGNED_UINT16_READ(addr)          (*((const __packed uint16_t *)(addr)))\n#endif\n#ifndef   __UNALIGNED_UINT32_WRITE\n  #define __UNALIGNED_UINT32_WRITE(addr, val)    ((*((__packed uint32_t *)(addr))) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT32_READ\n  #define __UNALIGNED_UINT32_READ(addr)          (*((const __packed uint32_t *)(addr)))\n#endif\n#ifndef   __ALIGNED\n  #define __ALIGNED(x)                           __attribute__((aligned(x)))\n#endif\n#ifndef   __RESTRICT\n  #define __RESTRICT                             __restrict\n#endif\n#ifndef   __COMPILER_BARRIER\n  #define __COMPILER_BARRIER()                   __memory_changed()\n#endif\n\n/* #########################  Startup and Lowlevel Init  ######################## */\n\n#ifndef __PROGRAM_START\n#define __PROGRAM_START           __main\n#endif\n\n#ifndef __INITIAL_SP\n#define __INITIAL_SP              Image$$ARM_LIB_STACK$$ZI$$Limit\n#endif\n\n#ifndef __STACK_LIMIT\n#define __STACK_LIMIT             Image$$ARM_LIB_STACK$$ZI$$Base\n#endif\n\n#ifndef __VECTOR_TABLE\n#define __VECTOR_TABLE            __Vectors\n#endif\n\n#ifndef __VECTOR_TABLE_ATTRIBUTE\n#define __VECTOR_TABLE_ATTRIBUTE  __attribute__((used, section(\"RESET\")))\n#endif\n\n/* ##########################  Core Instruction Access  ######################### */\n/** \\defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface\n  Access to dedicated instructions\n  @{\n*/\n\n/**\n  \\brief   No Operation\n  \\details No Operation does nothing. This instruction can be used for code alignment purposes.\n */\n#define __NOP                             __nop\n\n\n/**\n  \\brief   Wait For Interrupt\n  \\details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.\n */\n#define __WFI                             __wfi\n\n\n/**\n  \\brief   Wait For Event\n  \\details Wait For Event is a hint instruction that permits the processor to enter\n           a low-power state until one of a number of events occurs.\n */\n#define __WFE                             __wfe\n\n\n/**\n  \\brief   Send Event\n  \\details Send Event is a hint instruction. It causes an event to be signaled to the CPU.\n */\n#define __SEV                             __sev\n\n\n/**\n  \\brief   Instruction Synchronization Barrier\n  \\details Instruction Synchronization Barrier flushes the pipeline in the processor,\n           so that all instructions following the ISB are fetched from cache or memory,\n           after the instruction has been completed.\n */\n#define __ISB()                           __isb(0xF)\n\n/**\n  \\brief   Data Synchronization Barrier\n  \\details Acts as a special kind of Data Memory Barrier.\n           It completes when all explicit memory accesses before this instruction complete.\n */\n#define __DSB()                           __dsb(0xF)\n\n/**\n  \\brief   Data Memory Barrier\n  \\details Ensures the apparent order of the explicit memory operations before\n           and after the instruction, without ensuring their completion.\n */\n#define __DMB()                           __dmb(0xF)\n\n\n/**\n  \\brief   Reverse byte order (32 bit)\n  \\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#define __REV                             __rev\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#ifndef __NO_EMBEDDED_ASM\n__attribute__((section(\".rev16_text\"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value)\n{\n  rev16 r0, r0\n  bx lr\n}\n#endif\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#ifndef __NO_EMBEDDED_ASM\n__attribute__((section(\".revsh_text\"))) __STATIC_INLINE __ASM int16_t __REVSH(int16_t value)\n{\n  revsh r0, r0\n  bx lr\n}\n#endif\n\n\n/**\n  \\brief   Rotate Right in unsigned value (32 bit)\n  \\details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.\n  \\param [in]    op1  Value to rotate\n  \\param [in]    op2  Number of Bits to rotate\n  \\return               Rotated value\n */\n#define __ROR                             __ror\n\n\n/**\n  \\brief   Breakpoint\n  \\details Causes the processor to enter Debug state.\n           Debug tools can use this to investigate system state when the instruction at a particular address is reached.\n  \\param [in]    value  is ignored by the processor.\n                 If required, a debugger can use it to store additional information about the breakpoint.\n */\n#define __BKPT(value)                       __breakpoint(value)\n\n\n/**\n  \\brief   Reverse bit order of value\n  \\details Reverses the bit order of the given value.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n     (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     )\n  #define __RBIT                          __rbit\n#else\n__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value)\n{\n  uint32_t result;\n  uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */\n\n  result = value;                      /* r will be reversed bits of v; first get LSB of v */\n  for (value >>= 1U; value != 0U; value >>= 1U)\n  {\n    result <<= 1U;\n    result |= value & 1U;\n    s--;\n  }\n  result <<= s;                        /* shift when v's highest bits are zero */\n  return result;\n}\n#endif\n\n\n/**\n  \\brief   Count leading zeros\n  \\details Counts the number of leading zeros of a data value.\n  \\param [in]  value  Value to count the leading zeros\n  \\return             number of leading zeros in value\n */\n#define __CLZ                             __clz\n\n\n#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n     (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     )\n\n/**\n  \\brief   LDR Exclusive (8 bit)\n  \\details Executes a exclusive LDR instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __LDREXB(ptr)                                                        ((uint8_t ) __ldrex(ptr))\n#else\n  #define __LDREXB(ptr)          _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") ((uint8_t ) __ldrex(ptr))  _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   LDR Exclusive (16 bit)\n  \\details Executes a exclusive LDR instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __LDREXH(ptr)                                                        ((uint16_t) __ldrex(ptr))\n#else\n  #define __LDREXH(ptr)          _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") ((uint16_t) __ldrex(ptr))  _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   LDR Exclusive (32 bit)\n  \\details Executes a exclusive LDR instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __LDREXW(ptr)                                                        ((uint32_t ) __ldrex(ptr))\n#else\n  #define __LDREXW(ptr)          _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") ((uint32_t ) __ldrex(ptr))  _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   STR Exclusive (8 bit)\n  \\details Executes a exclusive STR instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __STREXB(value, ptr)                                                 __strex(value, ptr)\n#else\n  #define __STREXB(value, ptr)   _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") __strex(value, ptr)        _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   STR Exclusive (16 bit)\n  \\details Executes a exclusive STR instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __STREXH(value, ptr)                                                 __strex(value, ptr)\n#else\n  #define __STREXH(value, ptr)   _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") __strex(value, ptr)        _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   STR Exclusive (32 bit)\n  \\details Executes a exclusive STR instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020)\n  #define __STREXW(value, ptr)                                                 __strex(value, ptr)\n#else\n  #define __STREXW(value, ptr)   _Pragma(\"push\") _Pragma(\"diag_suppress 3731\") __strex(value, ptr)        _Pragma(\"pop\")\n#endif\n\n\n/**\n  \\brief   Remove the exclusive lock\n  \\details Removes the exclusive lock which is created by LDREX.\n */\n#define __CLREX                           __clrex\n\n\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n#define __SSAT                            __ssat\n\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n#define __USAT                            __usat\n\n\n/**\n  \\brief   Rotate Right with Extend (32 bit)\n  \\details Moves each bit of a bitstring right by one bit.\n           The carry input is shifted in at the left end of the bitstring.\n  \\param [in]    value  Value to rotate\n  \\return               Rotated value\n */\n#ifndef __NO_EMBEDDED_ASM\n__attribute__((section(\".rrx_text\"))) __STATIC_INLINE __ASM uint32_t __RRX(uint32_t value)\n{\n  rrx r0, r0\n  bx lr\n}\n#endif\n\n\n/**\n  \\brief   LDRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged LDRT instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n#define __LDRBT(ptr)                      ((uint8_t )  __ldrt(ptr))\n\n\n/**\n  \\brief   LDRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged LDRT instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n#define __LDRHT(ptr)                      ((uint16_t)  __ldrt(ptr))\n\n\n/**\n  \\brief   LDRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged LDRT instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n#define __LDRT(ptr)                       ((uint32_t ) __ldrt(ptr))\n\n\n/**\n  \\brief   STRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged STRT instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n#define __STRBT(value, ptr)               __strt(value, ptr)\n\n\n/**\n  \\brief   STRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged STRT instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n#define __STRHT(value, ptr)               __strt(value, ptr)\n\n\n/**\n  \\brief   STRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged STRT instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n#define __STRT(value, ptr)                __strt(value, ptr)\n\n#else  /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n           (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     ) */\n\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n__attribute__((always_inline)) __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat)\n{\n  if ((sat >= 1U) && (sat <= 32U))\n  {\n    const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U);\n    const int32_t min = -1 - max ;\n    if (val > max)\n    {\n      return max;\n    }\n    else if (val < min)\n    {\n      return min;\n    }\n  }\n  return val;\n}\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat)\n{\n  if (sat <= 31U)\n  {\n    const uint32_t max = ((1U << sat) - 1U);\n    if (val > (int32_t)max)\n    {\n      return max;\n    }\n    else if (val < 0)\n    {\n      return 0U;\n    }\n  }\n  return (uint32_t)val;\n}\n\n#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n           (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     ) */\n\n/*@}*/ /* end of group CMSIS_Core_InstructionInterface */\n\n\n/* ###########################  Core Function Access  ########################### */\n/** \\ingroup  CMSIS_Core_FunctionInterface\n    \\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions\n  @{\n */\n\n/**\n  \\brief   Enable IRQ Interrupts\n  \\details Enables IRQ interrupts by clearing special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n/* intrinsic void __enable_irq();     */\n\n\n/**\n  \\brief   Disable IRQ Interrupts\n  \\details Disables IRQ interrupts by setting special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n/* intrinsic void __disable_irq();    */\n\n/**\n  \\brief   Get Control Register\n  \\details Returns the content of the Control Register.\n  \\return               Control Register value\n */\n__STATIC_INLINE uint32_t __get_CONTROL(void)\n{\n  register uint32_t __regControl         __ASM(\"control\");\n  return(__regControl);\n}\n\n\n/**\n  \\brief   Set Control Register\n  \\details Writes the given value to the Control Register.\n  \\param [in]    control  Control Register value to set\n */\n__STATIC_INLINE void __set_CONTROL(uint32_t control)\n{\n  register uint32_t __regControl         __ASM(\"control\");\n  __regControl = control;\n  __ISB();\n}\n\n\n/**\n  \\brief   Get IPSR Register\n  \\details Returns the content of the IPSR Register.\n  \\return               IPSR Register value\n */\n__STATIC_INLINE uint32_t __get_IPSR(void)\n{\n  register uint32_t __regIPSR          __ASM(\"ipsr\");\n  return(__regIPSR);\n}\n\n\n/**\n  \\brief   Get APSR Register\n  \\details Returns the content of the APSR Register.\n  \\return               APSR Register value\n */\n__STATIC_INLINE uint32_t __get_APSR(void)\n{\n  register uint32_t __regAPSR          __ASM(\"apsr\");\n  return(__regAPSR);\n}\n\n\n/**\n  \\brief   Get xPSR Register\n  \\details Returns the content of the xPSR Register.\n  \\return               xPSR Register value\n */\n__STATIC_INLINE uint32_t __get_xPSR(void)\n{\n  register uint32_t __regXPSR          __ASM(\"xpsr\");\n  return(__regXPSR);\n}\n\n\n/**\n  \\brief   Get Process Stack Pointer\n  \\details Returns the current value of the Process Stack Pointer (PSP).\n  \\return               PSP Register value\n */\n__STATIC_INLINE uint32_t __get_PSP(void)\n{\n  register uint32_t __regProcessStackPointer  __ASM(\"psp\");\n  return(__regProcessStackPointer);\n}\n\n\n/**\n  \\brief   Set Process Stack Pointer\n  \\details Assigns the given value to the Process Stack Pointer (PSP).\n  \\param [in]    topOfProcStack  Process Stack Pointer value to set\n */\n__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)\n{\n  register uint32_t __regProcessStackPointer  __ASM(\"psp\");\n  __regProcessStackPointer = topOfProcStack;\n}\n\n\n/**\n  \\brief   Get Main Stack Pointer\n  \\details Returns the current value of the Main Stack Pointer (MSP).\n  \\return               MSP Register value\n */\n__STATIC_INLINE uint32_t __get_MSP(void)\n{\n  register uint32_t __regMainStackPointer     __ASM(\"msp\");\n  return(__regMainStackPointer);\n}\n\n\n/**\n  \\brief   Set Main Stack Pointer\n  \\details Assigns the given value to the Main Stack Pointer (MSP).\n  \\param [in]    topOfMainStack  Main Stack Pointer value to set\n */\n__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)\n{\n  register uint32_t __regMainStackPointer     __ASM(\"msp\");\n  __regMainStackPointer = topOfMainStack;\n}\n\n\n/**\n  \\brief   Get Priority Mask\n  \\details Returns the current state of the priority mask bit from the Priority Mask Register.\n  \\return               Priority Mask value\n */\n__STATIC_INLINE uint32_t __get_PRIMASK(void)\n{\n  register uint32_t __regPriMask         __ASM(\"primask\");\n  return(__regPriMask);\n}\n\n\n/**\n  \\brief   Set Priority Mask\n  \\details Assigns the given value to the Priority Mask Register.\n  \\param [in]    priMask  Priority Mask\n */\n__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)\n{\n  register uint32_t __regPriMask         __ASM(\"primask\");\n  __regPriMask = (priMask);\n}\n\n\n#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n     (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     )\n\n/**\n  \\brief   Enable FIQ\n  \\details Enables FIQ interrupts by clearing special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n#define __enable_fault_irq                __enable_fiq\n\n\n/**\n  \\brief   Disable FIQ\n  \\details Disables FIQ interrupts by setting special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n#define __disable_fault_irq               __disable_fiq\n\n\n/**\n  \\brief   Get Base Priority\n  \\details Returns the current value of the Base Priority register.\n  \\return               Base Priority register value\n */\n__STATIC_INLINE uint32_t  __get_BASEPRI(void)\n{\n  register uint32_t __regBasePri         __ASM(\"basepri\");\n  return(__regBasePri);\n}\n\n\n/**\n  \\brief   Set Base Priority\n  \\details Assigns the given value to the Base Priority register.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_INLINE void __set_BASEPRI(uint32_t basePri)\n{\n  register uint32_t __regBasePri         __ASM(\"basepri\");\n  __regBasePri = (basePri & 0xFFU);\n}\n\n\n/**\n  \\brief   Set Base Priority with condition\n  \\details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled,\n           or the new value increases the BASEPRI priority level.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_INLINE void __set_BASEPRI_MAX(uint32_t basePri)\n{\n  register uint32_t __regBasePriMax      __ASM(\"basepri_max\");\n  __regBasePriMax = (basePri & 0xFFU);\n}\n\n\n/**\n  \\brief   Get Fault Mask\n  \\details Returns the current value of the Fault Mask register.\n  \\return               Fault Mask register value\n */\n__STATIC_INLINE uint32_t __get_FAULTMASK(void)\n{\n  register uint32_t __regFaultMask       __ASM(\"faultmask\");\n  return(__regFaultMask);\n}\n\n\n/**\n  \\brief   Set Fault Mask\n  \\details Assigns the given value to the Fault Mask register.\n  \\param [in]    faultMask  Fault Mask value to set\n */\n__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)\n{\n  register uint32_t __regFaultMask       __ASM(\"faultmask\");\n  __regFaultMask = (faultMask & (uint32_t)1U);\n}\n\n#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__  == 1)) || \\\n           (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     ) */\n\n\n/**\n  \\brief   Get FPSCR\n  \\details Returns the current value of the Floating Point Status/Control register.\n  \\return               Floating Point Status/Control register value\n */\n__STATIC_INLINE uint32_t __get_FPSCR(void)\n{\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n  register uint32_t __regfpscr         __ASM(\"fpscr\");\n  return(__regfpscr);\n#else\n   return(0U);\n#endif\n}\n\n\n/**\n  \\brief   Set FPSCR\n  \\details Assigns the given value to the Floating Point Status/Control register.\n  \\param [in]    fpscr  Floating Point Status/Control value to set\n */\n__STATIC_INLINE void __set_FPSCR(uint32_t fpscr)\n{\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n  register uint32_t __regfpscr         __ASM(\"fpscr\");\n  __regfpscr = (fpscr);\n#else\n  (void)fpscr;\n#endif\n}\n\n\n/*@} end of CMSIS_Core_RegAccFunctions */\n\n\n/* ###################  Compiler specific Intrinsics  ########################### */\n/** \\defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics\n  Access to dedicated SIMD instructions\n  @{\n*/\n\n#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     )\n\n#define __SADD8                           __sadd8\n#define __QADD8                           __qadd8\n#define __SHADD8                          __shadd8\n#define __UADD8                           __uadd8\n#define __UQADD8                          __uqadd8\n#define __UHADD8                          __uhadd8\n#define __SSUB8                           __ssub8\n#define __QSUB8                           __qsub8\n#define __SHSUB8                          __shsub8\n#define __USUB8                           __usub8\n#define __UQSUB8                          __uqsub8\n#define __UHSUB8                          __uhsub8\n#define __SADD16                          __sadd16\n#define __QADD16                          __qadd16\n#define __SHADD16                         __shadd16\n#define __UADD16                          __uadd16\n#define __UQADD16                         __uqadd16\n#define __UHADD16                         __uhadd16\n#define __SSUB16                          __ssub16\n#define __QSUB16                          __qsub16\n#define __SHSUB16                         __shsub16\n#define __USUB16                          __usub16\n#define __UQSUB16                         __uqsub16\n#define __UHSUB16                         __uhsub16\n#define __SASX                            __sasx\n#define __QASX                            __qasx\n#define __SHASX                           __shasx\n#define __UASX                            __uasx\n#define __UQASX                           __uqasx\n#define __UHASX                           __uhasx\n#define __SSAX                            __ssax\n#define __QSAX                            __qsax\n#define __SHSAX                           __shsax\n#define __USAX                            __usax\n#define __UQSAX                           __uqsax\n#define __UHSAX                           __uhsax\n#define __USAD8                           __usad8\n#define __USADA8                          __usada8\n#define __SSAT16                          __ssat16\n#define __USAT16                          __usat16\n#define __UXTB16                          __uxtb16\n#define __UXTAB16                         __uxtab16\n#define __SXTB16                          __sxtb16\n#define __SXTAB16                         __sxtab16\n#define __SMUAD                           __smuad\n#define __SMUADX                          __smuadx\n#define __SMLAD                           __smlad\n#define __SMLADX                          __smladx\n#define __SMLALD                          __smlald\n#define __SMLALDX                         __smlaldx\n#define __SMUSD                           __smusd\n#define __SMUSDX                          __smusdx\n#define __SMLSD                           __smlsd\n#define __SMLSDX                          __smlsdx\n#define __SMLSLD                          __smlsld\n#define __SMLSLDX                         __smlsldx\n#define __SEL                             __sel\n#define __QADD                            __qadd\n#define __QSUB                            __qsub\n\n#define __PKHBT(ARG1,ARG2,ARG3)          ( ((((uint32_t)(ARG1))          ) & 0x0000FFFFUL) |  \\\n                                           ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL)  )\n\n#define __PKHTB(ARG1,ARG2,ARG3)          ( ((((uint32_t)(ARG1))          ) & 0xFFFF0000UL) |  \\\n                                           ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL)  )\n\n#define __SMMLA(ARG1,ARG2,ARG3)          ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \\\n                                                      ((int64_t)(ARG3) << 32U)     ) >> 32U))\n\n#define __SXTB16_RORn(ARG1, ARG2)        __SXTB16(__ROR(ARG1, ARG2))\n\n#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3))\n\n#endif /* ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))     ) */\n/*@} end of group CMSIS_SIMD_intrinsics */\n\n\n#endif /* __CMSIS_ARMCC_H */\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_armclang.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_armclang.h\n * @brief    CMSIS compiler armclang (Arm Compiler 6) header file\n * @version  V5.4.3\n * @date     27. May 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */\n\n#ifndef __CMSIS_ARMCLANG_H\n#define __CMSIS_ARMCLANG_H\n\n#pragma clang system_header   /* treat file as system include file */\n\n/* CMSIS compiler specific defines */\n#ifndef   __ASM\n  #define __ASM                                  __asm\n#endif\n#ifndef   __INLINE\n  #define __INLINE                               __inline\n#endif\n#ifndef   __STATIC_INLINE\n  #define __STATIC_INLINE                        static __inline\n#endif\n#ifndef   __STATIC_FORCEINLINE\n  #define __STATIC_FORCEINLINE                   __attribute__((always_inline)) static __inline\n#endif\n#ifndef   __NO_RETURN\n  #define __NO_RETURN                            __attribute__((__noreturn__))\n#endif\n#ifndef   __USED\n  #define __USED                                 __attribute__((used))\n#endif\n#ifndef   __WEAK\n  #define __WEAK                                 __attribute__((weak))\n#endif\n#ifndef   __PACKED\n  #define __PACKED                               __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __PACKED_STRUCT\n  #define __PACKED_STRUCT                        struct __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __PACKED_UNION\n  #define __PACKED_UNION                         union __attribute__((packed, aligned(1)))\n#endif\n#ifndef   __UNALIGNED_UINT32        /* deprecated */\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wpacked\"\n/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */\n  struct __attribute__((packed)) T_UINT32 { uint32_t v; };\n  #pragma clang diagnostic pop\n  #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n#endif\n#ifndef   __UNALIGNED_UINT16_WRITE\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wpacked\"\n/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */\n  __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n  #pragma clang diagnostic pop\n  #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT16_READ\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wpacked\"\n/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */\n  __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n  #pragma clang diagnostic pop\n  #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n#endif\n#ifndef   __UNALIGNED_UINT32_WRITE\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wpacked\"\n/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */\n  __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n  #pragma clang diagnostic pop\n  #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n#endif\n#ifndef   __UNALIGNED_UINT32_READ\n  #pragma clang diagnostic push\n  #pragma clang diagnostic ignored \"-Wpacked\"\n/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */\n  __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n  #pragma clang diagnostic pop\n  #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n#endif\n#ifndef   __ALIGNED\n  #define __ALIGNED(x)                           __attribute__((aligned(x)))\n#endif\n#ifndef   __RESTRICT\n  #define __RESTRICT                             __restrict\n#endif\n#ifndef   __COMPILER_BARRIER\n  #define __COMPILER_BARRIER()                   __ASM volatile(\"\":::\"memory\")\n#endif\n\n/* #########################  Startup and Lowlevel Init  ######################## */\n\n#ifndef __PROGRAM_START\n#define __PROGRAM_START           __main\n#endif\n\n#ifndef __INITIAL_SP\n#define __INITIAL_SP              Image$$ARM_LIB_STACK$$ZI$$Limit\n#endif\n\n#ifndef __STACK_LIMIT\n#define __STACK_LIMIT             Image$$ARM_LIB_STACK$$ZI$$Base\n#endif\n\n#ifndef __VECTOR_TABLE\n#define __VECTOR_TABLE            __Vectors\n#endif\n\n#ifndef __VECTOR_TABLE_ATTRIBUTE\n#define __VECTOR_TABLE_ATTRIBUTE  __attribute__((used, section(\"RESET\")))\n#endif\n\n#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)\n#ifndef __STACK_SEAL\n#define __STACK_SEAL              Image$$STACKSEAL$$ZI$$Base\n#endif\n\n#ifndef __TZ_STACK_SEAL_SIZE\n#define __TZ_STACK_SEAL_SIZE      8U\n#endif\n\n#ifndef __TZ_STACK_SEAL_VALUE\n#define __TZ_STACK_SEAL_VALUE     0xFEF5EDA5FEF5EDA5ULL\n#endif\n\n\n__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) {\n  *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE;\n}\n#endif\n\n\n/* ##########################  Core Instruction Access  ######################### */\n/** \\defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface\n  Access to dedicated instructions\n  @{\n*/\n\n/* Define macros for porting to both thumb1 and thumb2.\n * For thumb1, use low register (r0-r7), specified by constraint \"l\"\n * Otherwise, use general registers, specified by constraint \"r\" */\n#if defined (__thumb__) && !defined (__thumb2__)\n#define __CMSIS_GCC_OUT_REG(r) \"=l\" (r)\n#define __CMSIS_GCC_RW_REG(r) \"+l\" (r)\n#define __CMSIS_GCC_USE_REG(r) \"l\" (r)\n#else\n#define __CMSIS_GCC_OUT_REG(r) \"=r\" (r)\n#define __CMSIS_GCC_RW_REG(r) \"+r\" (r)\n#define __CMSIS_GCC_USE_REG(r) \"r\" (r)\n#endif\n\n/**\n  \\brief   No Operation\n  \\details No Operation does nothing. This instruction can be used for code alignment purposes.\n */\n#define __NOP          __builtin_arm_nop\n\n/**\n  \\brief   Wait For Interrupt\n  \\details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.\n */\n#define __WFI          __builtin_arm_wfi\n\n\n/**\n  \\brief   Wait For Event\n  \\details Wait For Event is a hint instruction that permits the processor to enter\n           a low-power state until one of a number of events occurs.\n */\n#define __WFE          __builtin_arm_wfe\n\n\n/**\n  \\brief   Send Event\n  \\details Send Event is a hint instruction. It causes an event to be signaled to the CPU.\n */\n#define __SEV          __builtin_arm_sev\n\n\n/**\n  \\brief   Instruction Synchronization Barrier\n  \\details Instruction Synchronization Barrier flushes the pipeline in the processor,\n           so that all instructions following the ISB are fetched from cache or memory,\n           after the instruction has been completed.\n */\n#define __ISB()        __builtin_arm_isb(0xF)\n\n/**\n  \\brief   Data Synchronization Barrier\n  \\details Acts as a special kind of Data Memory Barrier.\n           It completes when all explicit memory accesses before this instruction complete.\n */\n#define __DSB()        __builtin_arm_dsb(0xF)\n\n\n/**\n  \\brief   Data Memory Barrier\n  \\details Ensures the apparent order of the explicit memory operations before\n           and after the instruction, without ensuring their completion.\n */\n#define __DMB()        __builtin_arm_dmb(0xF)\n\n\n/**\n  \\brief   Reverse byte order (32 bit)\n  \\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#define __REV(value)   __builtin_bswap32(value)\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#define __REV16(value) __ROR(__REV(value), 16)\n\n\n/**\n  \\brief   Reverse byte order (16 bit)\n  \\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#define __REVSH(value) (int16_t)__builtin_bswap16(value)\n\n\n/**\n  \\brief   Rotate Right in unsigned value (32 bit)\n  \\details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.\n  \\param [in]    op1  Value to rotate\n  \\param [in]    op2  Number of Bits to rotate\n  \\return               Rotated value\n */\n__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)\n{\n  op2 %= 32U;\n  if (op2 == 0U)\n  {\n    return op1;\n  }\n  return (op1 >> op2) | (op1 << (32U - op2));\n}\n\n\n/**\n  \\brief   Breakpoint\n  \\details Causes the processor to enter Debug state.\n           Debug tools can use this to investigate system state when the instruction at a particular address is reached.\n  \\param [in]    value  is ignored by the processor.\n                 If required, a debugger can use it to store additional information about the breakpoint.\n */\n#define __BKPT(value)     __ASM volatile (\"bkpt \"#value)\n\n\n/**\n  \\brief   Reverse bit order of value\n  \\details Reverses the bit order of the given value.\n  \\param [in]    value  Value to reverse\n  \\return               Reversed value\n */\n#define __RBIT            __builtin_arm_rbit\n\n/**\n  \\brief   Count leading zeros\n  \\details Counts the number of leading zeros of a data value.\n  \\param [in]  value  Value to count the leading zeros\n  \\return             number of leading zeros in value\n */\n__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value)\n{\n  /* Even though __builtin_clz produces a CLZ instruction on ARM, formally\n     __builtin_clz(0) is undefined behaviour, so handle this case specially.\n     This guarantees ARM-compatible results if happening to compile on a non-ARM\n     target, and ensures the compiler doesn't decide to activate any\n     optimisations using the logic \"value was passed to __builtin_clz, so it\n     is non-zero\".\n     ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a\n     single CLZ instruction.\n   */\n  if (value == 0U)\n  {\n    return 32U;\n  }\n  return __builtin_clz(value);\n}\n\n\n#if ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n     (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n     (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     )\n\n/**\n  \\brief   LDR Exclusive (8 bit)\n  \\details Executes a exclusive LDR instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n#define __LDREXB        (uint8_t)__builtin_arm_ldrex\n\n\n/**\n  \\brief   LDR Exclusive (16 bit)\n  \\details Executes a exclusive LDR instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n#define __LDREXH        (uint16_t)__builtin_arm_ldrex\n\n\n/**\n  \\brief   LDR Exclusive (32 bit)\n  \\details Executes a exclusive LDR instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n#define __LDREXW        (uint32_t)__builtin_arm_ldrex\n\n\n/**\n  \\brief   STR Exclusive (8 bit)\n  \\details Executes a exclusive STR instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define __STREXB        (uint32_t)__builtin_arm_strex\n\n\n/**\n  \\brief   STR Exclusive (16 bit)\n  \\details Executes a exclusive STR instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define __STREXH        (uint32_t)__builtin_arm_strex\n\n\n/**\n  \\brief   STR Exclusive (32 bit)\n  \\details Executes a exclusive STR instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define __STREXW        (uint32_t)__builtin_arm_strex\n\n\n/**\n  \\brief   Remove the exclusive lock\n  \\details Removes the exclusive lock which is created by LDREX.\n */\n#define __CLREX             __builtin_arm_clrex\n\n#endif /* ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n           (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n           (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n\n#if ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n     (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n     (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     )\n\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n#define __SSAT             __builtin_arm_ssat\n\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n#define __USAT             __builtin_arm_usat\n\n\n/**\n  \\brief   Rotate Right with Extend (32 bit)\n  \\details Moves each bit of a bitstring right by one bit.\n           The carry input is shifted in at the left end of the bitstring.\n  \\param [in]    value  Value to rotate\n  \\return               Rotated value\n */\n__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value)\n{\n  uint32_t result;\n\n  __ASM volatile (\"rrx %0, %1\" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );\n  return(result);\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged LDRT instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ldrbt %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n  return ((uint8_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged LDRT instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ldrht %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n  return ((uint16_t) result);    /* Add explicit type cast here */\n}\n\n\n/**\n  \\brief   LDRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged LDRT instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ldrt %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) );\n  return(result);\n}\n\n\n/**\n  \\brief   STRT Unprivileged (8 bit)\n  \\details Executes a Unprivileged STRT instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr)\n{\n  __ASM volatile (\"strbt %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) );\n}\n\n\n/**\n  \\brief   STRT Unprivileged (16 bit)\n  \\details Executes a Unprivileged STRT instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr)\n{\n  __ASM volatile (\"strht %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) );\n}\n\n\n/**\n  \\brief   STRT Unprivileged (32 bit)\n  \\details Executes a Unprivileged STRT instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr)\n{\n  __ASM volatile (\"strt %1, %0\" : \"=Q\" (*ptr) : \"r\" (value) );\n}\n\n#else /* ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n          (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n          (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n          (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n/**\n  \\brief   Signed Saturate\n  \\details Saturates a signed value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (1..32)\n  \\return             Saturated value\n */\n__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat)\n{\n  if ((sat >= 1U) && (sat <= 32U))\n  {\n    const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U);\n    const int32_t min = -1 - max ;\n    if (val > max)\n    {\n      return max;\n    }\n    else if (val < min)\n    {\n      return min;\n    }\n  }\n  return val;\n}\n\n/**\n  \\brief   Unsigned Saturate\n  \\details Saturates an unsigned value.\n  \\param [in]  value  Value to be saturated\n  \\param [in]    sat  Bit position to saturate to (0..31)\n  \\return             Saturated value\n */\n__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat)\n{\n  if (sat <= 31U)\n  {\n    const uint32_t max = ((1U << sat) - 1U);\n    if (val > (int32_t)max)\n    {\n      return max;\n    }\n    else if (val < 0)\n    {\n      return 0U;\n    }\n  }\n  return (uint32_t)val;\n}\n\n#endif /* ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n           (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n           (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n\n#if ((defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n     (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     )\n\n/**\n  \\brief   Load-Acquire (8 bit)\n  \\details Executes a LDAB instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ldab %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n  return ((uint8_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire (16 bit)\n  \\details Executes a LDAH instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"ldah %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n  return ((uint16_t) result);\n}\n\n\n/**\n  \\brief   Load-Acquire (32 bit)\n  \\details Executes a LDA instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr)\n{\n  uint32_t result;\n\n  __ASM volatile (\"lda %0, %1\" : \"=r\" (result) : \"Q\" (*ptr) : \"memory\" );\n  return(result);\n}\n\n\n/**\n  \\brief   Store-Release (8 bit)\n  \\details Executes a STLB instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr)\n{\n  __ASM volatile (\"stlb %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Store-Release (16 bit)\n  \\details Executes a STLH instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr)\n{\n  __ASM volatile (\"stlh %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Store-Release (32 bit)\n  \\details Executes a STL instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n */\n__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr)\n{\n  __ASM volatile (\"stl %1, %0\" : \"=Q\" (*ptr) : \"r\" ((uint32_t)value) : \"memory\" );\n}\n\n\n/**\n  \\brief   Load-Acquire Exclusive (8 bit)\n  \\details Executes a LDAB exclusive instruction for 8 bit value.\n  \\param [in]    ptr  Pointer to data\n  \\return             value of type uint8_t at (*ptr)\n */\n#define     __LDAEXB                 (uint8_t)__builtin_arm_ldaex\n\n\n/**\n  \\brief   Load-Acquire Exclusive (16 bit)\n  \\details Executes a LDAH exclusive instruction for 16 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint16_t at (*ptr)\n */\n#define     __LDAEXH                 (uint16_t)__builtin_arm_ldaex\n\n\n/**\n  \\brief   Load-Acquire Exclusive (32 bit)\n  \\details Executes a LDA exclusive instruction for 32 bit values.\n  \\param [in]    ptr  Pointer to data\n  \\return        value of type uint32_t at (*ptr)\n */\n#define     __LDAEX                  (uint32_t)__builtin_arm_ldaex\n\n\n/**\n  \\brief   Store-Release Exclusive (8 bit)\n  \\details Executes a STLB exclusive instruction for 8 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define     __STLEXB                 (uint32_t)__builtin_arm_stlex\n\n\n/**\n  \\brief   Store-Release Exclusive (16 bit)\n  \\details Executes a STLH exclusive instruction for 16 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define     __STLEXH                 (uint32_t)__builtin_arm_stlex\n\n\n/**\n  \\brief   Store-Release Exclusive (32 bit)\n  \\details Executes a STL exclusive instruction for 32 bit values.\n  \\param [in]  value  Value to store\n  \\param [in]    ptr  Pointer to location\n  \\return          0  Function succeeded\n  \\return          1  Function failed\n */\n#define     __STLEX                  (uint32_t)__builtin_arm_stlex\n\n#endif /* ((defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n           (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n/*@}*/ /* end of group CMSIS_Core_InstructionInterface */\n\n\n/* ###########################  Core Function Access  ########################### */\n/** \\ingroup  CMSIS_Core_FunctionInterface\n    \\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions\n  @{\n */\n\n/**\n  \\brief   Enable IRQ Interrupts\n  \\details Enables IRQ interrupts by clearing special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n#ifndef __ARM_COMPAT_H\n__STATIC_FORCEINLINE void __enable_irq(void)\n{\n  __ASM volatile (\"cpsie i\" : : : \"memory\");\n}\n#endif\n\n\n/**\n  \\brief   Disable IRQ Interrupts\n  \\details Disables IRQ interrupts by setting special-purpose register PRIMASK.\n           Can only be executed in Privileged modes.\n */\n#ifndef __ARM_COMPAT_H\n__STATIC_FORCEINLINE void __disable_irq(void)\n{\n  __ASM volatile (\"cpsid i\" : : : \"memory\");\n}\n#endif\n\n\n/**\n  \\brief   Get Control Register\n  \\details Returns the content of the Control Register.\n  \\return               Control Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_CONTROL(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, control\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Control Register (non-secure)\n  \\details Returns the content of the non-secure Control Register when in secure mode.\n  \\return               non-secure Control Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, control_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Control Register\n  \\details Writes the given value to the Control Register.\n  \\param [in]    control  Control Register value to set\n */\n__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control)\n{\n  __ASM volatile (\"MSR control, %0\" : : \"r\" (control) : \"memory\");\n  __ISB();\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Control Register (non-secure)\n  \\details Writes the given value to the non-secure Control Register when in secure state.\n  \\param [in]    control  Control Register value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control)\n{\n  __ASM volatile (\"MSR control_ns, %0\" : : \"r\" (control) : \"memory\");\n  __ISB();\n}\n#endif\n\n\n/**\n  \\brief   Get IPSR Register\n  \\details Returns the content of the IPSR Register.\n  \\return               IPSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_IPSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, ipsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get APSR Register\n  \\details Returns the content of the APSR Register.\n  \\return               APSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_APSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, apsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get xPSR Register\n  \\details Returns the content of the xPSR Register.\n  \\return               xPSR Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_xPSR(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, xpsr\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Get Process Stack Pointer\n  \\details Returns the current value of the Process Stack Pointer (PSP).\n  \\return               PSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_PSP(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, psp\"  : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Process Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state.\n  \\return               PSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, psp_ns\"  : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Process Stack Pointer\n  \\details Assigns the given value to the Process Stack Pointer (PSP).\n  \\param [in]    topOfProcStack  Process Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack)\n{\n  __ASM volatile (\"MSR psp, %0\" : : \"r\" (topOfProcStack) : );\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Process Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state.\n  \\param [in]    topOfProcStack  Process Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack)\n{\n  __ASM volatile (\"MSR psp_ns, %0\" : : \"r\" (topOfProcStack) : );\n}\n#endif\n\n\n/**\n  \\brief   Get Main Stack Pointer\n  \\details Returns the current value of the Main Stack Pointer (MSP).\n  \\return               MSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_MSP(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, msp\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Main Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state.\n  \\return               MSP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, msp_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Main Stack Pointer\n  \\details Assigns the given value to the Main Stack Pointer (MSP).\n  \\param [in]    topOfMainStack  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack)\n{\n  __ASM volatile (\"MSR msp, %0\" : : \"r\" (topOfMainStack) : );\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Main Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state.\n  \\param [in]    topOfMainStack  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack)\n{\n  __ASM volatile (\"MSR msp_ns, %0\" : : \"r\" (topOfMainStack) : );\n}\n#endif\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Stack Pointer (non-secure)\n  \\details Returns the current value of the non-secure Stack Pointer (SP) when in secure state.\n  \\return               SP Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, sp_ns\" : \"=r\" (result) );\n  return(result);\n}\n\n\n/**\n  \\brief   Set Stack Pointer (non-secure)\n  \\details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state.\n  \\param [in]    topOfStack  Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack)\n{\n  __ASM volatile (\"MSR sp_ns, %0\" : : \"r\" (topOfStack) : );\n}\n#endif\n\n\n/**\n  \\brief   Get Priority Mask\n  \\details Returns the current state of the priority mask bit from the Priority Mask Register.\n  \\return               Priority Mask value\n */\n__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, primask\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Priority Mask (non-secure)\n  \\details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state.\n  \\return               Priority Mask value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, primask_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Priority Mask\n  \\details Assigns the given value to the Priority Mask Register.\n  \\param [in]    priMask  Priority Mask\n */\n__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask)\n{\n  __ASM volatile (\"MSR primask, %0\" : : \"r\" (priMask) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Priority Mask (non-secure)\n  \\details Assigns the given value to the non-secure Priority Mask Register when in secure state.\n  \\param [in]    priMask  Priority Mask\n */\n__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask)\n{\n  __ASM volatile (\"MSR primask_ns, %0\" : : \"r\" (priMask) : \"memory\");\n}\n#endif\n\n\n#if ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n     (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n     (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n     (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     )\n/**\n  \\brief   Enable FIQ\n  \\details Enables FIQ interrupts by clearing special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __enable_fault_irq(void)\n{\n  __ASM volatile (\"cpsie f\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Disable FIQ\n  \\details Disables FIQ interrupts by setting special-purpose register FAULTMASK.\n           Can only be executed in Privileged modes.\n */\n__STATIC_FORCEINLINE void __disable_fault_irq(void)\n{\n  __ASM volatile (\"cpsid f\" : : : \"memory\");\n}\n\n\n/**\n  \\brief   Get Base Priority\n  \\details Returns the current value of the Base Priority register.\n  \\return               Base Priority register value\n */\n__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, basepri\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Base Priority (non-secure)\n  \\details Returns the current value of the non-secure Base Priority register when in secure state.\n  \\return               Base Priority register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, basepri_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Base Priority\n  \\details Assigns the given value to the Base Priority register.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri, %0\" : : \"r\" (basePri) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Base Priority (non-secure)\n  \\details Assigns the given value to the non-secure Base Priority register when in secure state.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri_ns, %0\" : : \"r\" (basePri) : \"memory\");\n}\n#endif\n\n\n/**\n  \\brief   Set Base Priority with condition\n  \\details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled,\n           or the new value increases the BASEPRI priority level.\n  \\param [in]    basePri  Base Priority value to set\n */\n__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri)\n{\n  __ASM volatile (\"MSR basepri_max, %0\" : : \"r\" (basePri) : \"memory\");\n}\n\n\n/**\n  \\brief   Get Fault Mask\n  \\details Returns the current value of the Fault Mask register.\n  \\return               Fault Mask register value\n */\n__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, faultmask\" : \"=r\" (result) );\n  return(result);\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Fault Mask (non-secure)\n  \\details Returns the current value of the non-secure Fault Mask register when in secure state.\n  \\return               Fault Mask register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void)\n{\n  uint32_t result;\n\n  __ASM volatile (\"MRS %0, faultmask_ns\" : \"=r\" (result) );\n  return(result);\n}\n#endif\n\n\n/**\n  \\brief   Set Fault Mask\n  \\details Assigns the given value to the Fault Mask register.\n  \\param [in]    faultMask  Fault Mask value to set\n */\n__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask)\n{\n  __ASM volatile (\"MSR faultmask, %0\" : : \"r\" (faultMask) : \"memory\");\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Set Fault Mask (non-secure)\n  \\details Assigns the given value to the non-secure Fault Mask register when in secure state.\n  \\param [in]    faultMask  Fault Mask value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask)\n{\n  __ASM volatile (\"MSR faultmask_ns, %0\" : : \"r\" (faultMask) : \"memory\");\n}\n#endif\n\n#endif /* ((defined (__ARM_ARCH_7M__       ) && (__ARM_ARCH_7M__        == 1)) || \\\n           (defined (__ARM_ARCH_7EM__      ) && (__ARM_ARCH_7EM__       == 1)) || \\\n           (defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n           (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n\n#if ((defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n     (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n     (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     )\n\n/**\n  \\brief   Get Process Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always in non-secure\n  mode.\n\n  \\details Returns the current value of the Process Stack Pointer Limit (PSPLIM).\n  \\return               PSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n    // without main extensions, the non-secure PSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, psplim\"  : \"=r\" (result) );\n  return result;\n#endif\n}\n\n#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3))\n/**\n  \\brief   Get Process Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always in non-secure\n  mode.\n\n  \\details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state.\n  \\return               PSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) )\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, psplim_ns\"  : \"=r\" (result) );\n  return result;\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Set Process Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored in non-secure\n  mode.\n\n  \\details Assigns the given value to the Process Stack Pointer Limit (PSPLIM).\n  \\param [in]    ProcStackPtrLimit  Process Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  (void)ProcStackPtrLimit;\n#else\n  __ASM volatile (\"MSR psplim, %0\" : : \"r\" (ProcStackPtrLimit));\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Set Process Stack Pointer (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored in non-secure\n  mode.\n\n  \\details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state.\n  \\param [in]    ProcStackPtrLimit  Process Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) )\n  // without main extensions, the non-secure PSPLIM is RAZ/WI\n  (void)ProcStackPtrLimit;\n#else\n  __ASM volatile (\"MSR psplim_ns, %0\\n\" : : \"r\" (ProcStackPtrLimit));\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Get Main Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always.\n\n  \\details Returns the current value of the Main Stack Pointer Limit (MSPLIM).\n  \\return               MSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, msplim\" : \"=r\" (result) );\n  return result;\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Get Main Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence zero is returned always.\n\n  \\details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state.\n  \\return               MSPLIM Register value\n */\n__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) )\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  return 0U;\n#else\n  uint32_t result;\n  __ASM volatile (\"MRS %0, msplim_ns\" : \"=r\" (result) );\n  return result;\n#endif\n}\n#endif\n\n\n/**\n  \\brief   Set Main Stack Pointer Limit\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored.\n\n  \\details Assigns the given value to the Main Stack Pointer Limit (MSPLIM).\n  \\param [in]    MainStackPtrLimit  Main Stack Pointer Limit value to set\n */\n__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) && \\\n    (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3)))\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  (void)MainStackPtrLimit;\n#else\n  __ASM volatile (\"MSR msplim, %0\" : : \"r\" (MainStackPtrLimit));\n#endif\n}\n\n\n#if (defined (__ARM_FEATURE_CMSE  ) && (__ARM_FEATURE_CMSE   == 3))\n/**\n  \\brief   Set Main Stack Pointer Limit (non-secure)\n  Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure\n  Stack Pointer Limit register hence the write is silently ignored.\n\n  \\details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state.\n  \\param [in]    MainStackPtrLimit  Main Stack Pointer value to set\n */\n__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit)\n{\n#if (!((defined (__ARM_ARCH_8M_MAIN__   ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n       (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1))   ) )\n  // without main extensions, the non-secure MSPLIM is RAZ/WI\n  (void)MainStackPtrLimit;\n#else\n  __ASM volatile (\"MSR msplim_ns, %0\" : : \"r\" (MainStackPtrLimit));\n#endif\n}\n#endif\n\n#endif /* ((defined (__ARM_ARCH_8M_MAIN__  ) && (__ARM_ARCH_8M_MAIN__   == 1)) || \\\n           (defined (__ARM_ARCH_8M_BASE__  ) && (__ARM_ARCH_8M_BASE__   == 1)) || \\\n           (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1))     ) */\n\n/**\n  \\brief   Get FPSCR\n  \\details Returns the current value of the Floating Point Status/Control register.\n  \\return               Floating Point Status/Control register value\n */\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n#define __get_FPSCR      (uint32_t)__builtin_arm_get_fpscr\n#else\n#define __get_FPSCR()      ((uint32_t)0U)\n#endif\n\n/**\n  \\brief   Set FPSCR\n  \\details Assigns the given value to the Floating Point Status/Control register.\n  \\param [in]    fpscr  Floating Point Status/Control value to set\n */\n#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \\\n     (defined (__FPU_USED   ) && (__FPU_USED    == 1U))     )\n#define __set_FPSCR      __builtin_arm_set_fpscr\n#else\n#define __set_FPSCR(x)      ((void)(x))\n#endif\n\n\n/*@} end of CMSIS_Core_RegAccFunctions */\n\n\n/* ###################  Compiler specific Intrinsics  ########################### */\n/** \\defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics\n  Access to dedicated SIMD instructions\n  @{\n*/\n\n#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1))\n\n#define     __SADD8                 __builtin_arm_sadd8\n#define     __QADD8                 __builtin_arm_qadd8\n#define     __SHADD8                __builtin_arm_shadd8\n#define     __UADD8                 __builtin_arm_uadd8\n#define     __UQADD8                __builtin_arm_uqadd8\n#define     __UHADD8                __builtin_arm_uhadd8\n#define     __SSUB8                 __builtin_arm_ssub8\n#define     __QSUB8                 __builtin_arm_qsub8\n#define     __SHSUB8                __builtin_arm_shsub8\n#define     __USUB8                 __builtin_arm_usub8\n#define     __UQSUB8                __builtin_arm_uqsub8\n#define     __UHSUB8                __builtin_arm_uhsub8\n#define     __SADD16                __builtin_arm_sadd16\n#define     __QADD16                __builtin_arm_qadd16\n#define     __SHADD16               __builtin_arm_shadd16\n#define     __UADD16                __builtin_arm_uadd16\n#define     __UQADD16               __builtin_arm_uqadd16\n#define     __UHADD16               __builtin_arm_uhadd16\n#define     __SSUB16                __builtin_arm_ssub16\n#define     __QSUB16                __builtin_arm_qsub16\n#define     __SHSUB16               __builtin_arm_shsub16\n#define     __USUB16                __builtin_arm_usub16\n#define     __UQSUB16               __builtin_arm_uqsub16\n#define     __UHSUB16               __builtin_arm_uhsub16\n#define     __SASX                  __builtin_arm_sasx\n#define     __QASX                  __builtin_arm_qasx\n#define     __SHASX                 __builtin_arm_shasx\n#define     __UASX                  __builtin_arm_uasx\n#define     __UQASX                 __builtin_arm_uqasx\n#define     __UHASX                 __builtin_arm_uhasx\n#define     __SSAX                  __builtin_arm_ssax\n#define     __QSAX                  __builtin_arm_qsax\n#define     __SHSAX                 __builtin_arm_shsax\n#define     __USAX                  __builtin_arm_usax\n#define     __UQSAX                 __builtin_arm_uqsax\n#define     __UHSAX                 __builtin_arm_uhsax\n#define     __USAD8                 __builtin_arm_usad8\n#define     __USADA8                __builtin_arm_usada8\n#define     __SSAT16                __builtin_arm_ssat16\n#define     __USAT16                __builtin_arm_usat16\n#define     __UXTB16                __builtin_arm_uxtb16\n#define     __UXTAB16               __builtin_arm_uxtab16\n#define     __SXTB16                __builtin_arm_sxtb16\n#define     __SXTAB16               __builtin_arm_sxtab16\n#define     __SMUAD                 __builtin_arm_smuad\n#define     __SMUADX                __builtin_arm_smuadx\n#define     __SMLAD                 __builtin_arm_smlad\n#define     __SMLADX                __builtin_arm_smladx\n#define     __SMLALD                __builtin_arm_smlald\n#define     __SMLALDX               __builtin_arm_smlaldx\n#define     __SMUSD                 __builtin_arm_smusd\n#define     __SMUSDX                __builtin_arm_smusdx\n#define     __SMLSD                 __builtin_arm_smlsd\n#define     __SMLSDX                __builtin_arm_smlsdx\n#define     __SMLSLD                __builtin_arm_smlsld\n#define     __SMLSLDX               __builtin_arm_smlsldx\n#define     __SEL                   __builtin_arm_sel\n#define     __QADD                  __builtin_arm_qadd\n#define     __QSUB                  __builtin_arm_qsub\n\n#define __PKHBT(ARG1,ARG2,ARG3)          ( ((((uint32_t)(ARG1))          ) & 0x0000FFFFUL) |  \\\n                                           ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL)  )\n\n#define __PKHTB(ARG1,ARG2,ARG3)          ( ((((uint32_t)(ARG1))          ) & 0xFFFF0000UL) |  \\\n                                           ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL)  )\n\n#define __SXTB16_RORn(ARG1, ARG2)        __SXTB16(__ROR(ARG1, ARG2))\n\n#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3))\n\n__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3)\n{\n  int32_t result;\n\n  __ASM volatile (\"smmla %0, %1, %2, %3\" : \"=r\" (result): \"r\"  (op1), \"r\" (op2), \"r\" (op3) );\n  return(result);\n}\n\n#endif /* (__ARM_FEATURE_DSP == 1) */\n/*@} end of group CMSIS_SIMD_intrinsics */\n\n\n#endif /* __CMSIS_ARMCLANG_H */\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_compiler.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_compiler.h\n * @brief    CMSIS compiler generic header file\n * @version  V5.1.0\n * @date     09. October 2018\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2018 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef __CMSIS_COMPILER_H\n#define __CMSIS_COMPILER_H\n\n#include <stdint.h>\n\n/*\n * Arm Compiler 4/5\n */\n#if   defined ( __CC_ARM )\n  #include \"cmsis_armcc.h\"\n\n\n/*\n * Arm Compiler 6.6 LTM (armclang)\n */\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100)\n  #include \"cmsis_armclang_ltm.h\"\n\n  /*\n * Arm Compiler above 6.10.1 (armclang)\n */\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)\n  #include \"cmsis_armclang.h\"\n\n\n/*\n * GNU Compiler\n */\n#elif defined ( __GNUC__ )\n  #include \"cmsis_gcc.h\"\n\n\n/*\n * IAR Compiler\n */\n#elif defined ( __ICCARM__ )\n  #include <cmsis_iccarm.h>\n\n\n/*\n * TI Arm Compiler\n */\n#elif defined ( __TI_ARM__ )\n  #include <cmsis_ccs.h>\n\n  #ifndef   __ASM\n    #define __ASM                                  __asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    #define __NO_RETURN                            __attribute__((noreturn))\n  #endif\n  #ifndef   __USED\n    #define __USED                                 __attribute__((used))\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __attribute__((weak))\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               __attribute__((packed))\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        struct __attribute__((packed))\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         union __attribute__((packed))\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    struct __attribute__((packed)) T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #define __ALIGNED(x)                           __attribute__((aligned(x)))\n  #endif\n  #ifndef   __RESTRICT\n    #define __RESTRICT                             __restrict\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n/*\n * TASKING Compiler\n */\n#elif defined ( __TASKING__ )\n  /*\n   * The CMSIS functions have been implemented as intrinsics in the compiler.\n   * Please use \"carm -?i\" to get an up to date list of all intrinsics,\n   * Including the CMSIS ones.\n   */\n\n  #ifndef   __ASM\n    #define __ASM                                  __asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    #define __NO_RETURN                            __attribute__((noreturn))\n  #endif\n  #ifndef   __USED\n    #define __USED                                 __attribute__((used))\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __attribute__((weak))\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               __packed__\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        struct __packed__\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         union __packed__\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    struct __packed__ T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #define __ALIGNED(x)              __align(x)\n  #endif\n  #ifndef   __RESTRICT\n    #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.\n    #define __RESTRICT\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n/*\n * COSMIC Compiler\n */\n#elif defined ( __CSMC__ )\n   #include <cmsis_csm.h>\n\n #ifndef   __ASM\n    #define __ASM                                  _asm\n  #endif\n  #ifndef   __INLINE\n    #define __INLINE                               inline\n  #endif\n  #ifndef   __STATIC_INLINE\n    #define __STATIC_INLINE                        static inline\n  #endif\n  #ifndef   __STATIC_FORCEINLINE\n    #define __STATIC_FORCEINLINE                   __STATIC_INLINE\n  #endif\n  #ifndef   __NO_RETURN\n    // NO RETURN is automatically detected hence no warning here\n    #define __NO_RETURN\n  #endif\n  #ifndef   __USED\n    #warning No compiler specific solution for __USED. __USED is ignored.\n    #define __USED\n  #endif\n  #ifndef   __WEAK\n    #define __WEAK                                 __weak\n  #endif\n  #ifndef   __PACKED\n    #define __PACKED                               @packed\n  #endif\n  #ifndef   __PACKED_STRUCT\n    #define __PACKED_STRUCT                        @packed struct\n  #endif\n  #ifndef   __PACKED_UNION\n    #define __PACKED_UNION                         @packed union\n  #endif\n  #ifndef   __UNALIGNED_UINT32        /* deprecated */\n    @packed struct T_UINT32 { uint32_t v; };\n    #define __UNALIGNED_UINT32(x)                  (((struct T_UINT32 *)(x))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT16_WRITE\n    __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };\n    #define __UNALIGNED_UINT16_WRITE(addr, val)    (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT16_READ\n    __PACKED_STRUCT T_UINT16_READ { uint16_t v; };\n    #define __UNALIGNED_UINT16_READ(addr)          (((const struct T_UINT16_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __UNALIGNED_UINT32_WRITE\n    __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };\n    #define __UNALIGNED_UINT32_WRITE(addr, val)    (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))\n  #endif\n  #ifndef   __UNALIGNED_UINT32_READ\n    __PACKED_STRUCT T_UINT32_READ { uint32_t v; };\n    #define __UNALIGNED_UINT32_READ(addr)          (((const struct T_UINT32_READ *)(const void *)(addr))->v)\n  #endif\n  #ifndef   __ALIGNED\n    #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.\n    #define __ALIGNED(x)\n  #endif\n  #ifndef   __RESTRICT\n    #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.\n    #define __RESTRICT\n  #endif\n  #ifndef   __COMPILER_BARRIER\n    #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.\n    #define __COMPILER_BARRIER()                   (void)0\n  #endif\n\n\n#else\n  #error Unknown compiler.\n#endif\n\n\n#endif /* __CMSIS_COMPILER_H */\n\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/cmsis_version.h",
    "content": "/**************************************************************************//**\n * @file     cmsis_version.h\n * @brief    CMSIS Core(M) Version definitions\n * @version  V5.0.4\n * @date     23. July 2019\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2019 ARM Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header   /* treat file as system include file */\n#endif\n\n#ifndef __CMSIS_VERSION_H\n#define __CMSIS_VERSION_H\n\n/*  CMSIS Version definitions */\n#define __CM_CMSIS_VERSION_MAIN  ( 5U)                                      /*!< [31:16] CMSIS Core(M) main version */\n#define __CM_CMSIS_VERSION_SUB   ( 4U)                                      /*!< [15:0]  CMSIS Core(M) sub version */\n#define __CM_CMSIS_VERSION       ((__CM_CMSIS_VERSION_MAIN << 16U) | \\\n                                   __CM_CMSIS_VERSION_SUB           )       /*!< CMSIS Core(M) version number */\n#endif\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/core_cm3.h",
    "content": "/**************************************************************************//**\n * @file     core_cm3.h\n * @brief    CMSIS Cortex-M3 Core Peripheral Access Layer Header File\n * @version  V5.1.2\n * @date     04. June 2021\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2021 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header   /* treat file as system include file */\n#endif\n\n#ifndef __CORE_CM3_H_GENERIC\n#define __CORE_CM3_H_GENERIC\n\n#include <stdint.h>\n\n#ifdef __cplusplus\n extern \"C\" {\n#endif\n\n/**\n  \\page CMSIS_MISRA_Exceptions  MISRA-C:2004 Compliance Exceptions\n  CMSIS violates the following MISRA-C:2004 rules:\n\n   \\li Required Rule 8.5, object/function definition in header file.<br>\n     Function definitions in header files are used to allow 'inlining'.\n\n   \\li Required Rule 18.4, declaration of union type or object of union type: '{...}'.<br>\n     Unions are used for effective representation of core registers.\n\n   \\li Advisory Rule 19.7, Function-like macro defined.<br>\n     Function-like macros are used to allow more efficient code.\n */\n\n\n/*******************************************************************************\n *                 CMSIS definitions\n ******************************************************************************/\n/**\n  \\ingroup Cortex_M3\n  @{\n */\n\n#include \"cmsis_version.h\"\n\n/* CMSIS CM3 definitions */\n#define __CM3_CMSIS_VERSION_MAIN  (__CM_CMSIS_VERSION_MAIN)              /*!< \\deprecated [31:16] CMSIS HAL main version */\n#define __CM3_CMSIS_VERSION_SUB   (__CM_CMSIS_VERSION_SUB)               /*!< \\deprecated [15:0]  CMSIS HAL sub version */\n#define __CM3_CMSIS_VERSION       ((__CM3_CMSIS_VERSION_MAIN << 16U) | \\\n                                    __CM3_CMSIS_VERSION_SUB           )  /*!< \\deprecated CMSIS HAL version number */\n\n#define __CORTEX_M                (3U)                                   /*!< Cortex-M Core */\n\n/** __FPU_USED indicates whether an FPU is used or not.\n    This core does not support an FPU at all\n*/\n#define __FPU_USED       0U\n\n#if defined ( __CC_ARM )\n  #if defined __TARGET_FPU_VFP\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)\n  #if defined __ARM_FP\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __GNUC__ )\n  #if defined (__VFP_FP__) && !defined(__SOFTFP__)\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __ICCARM__ )\n  #if defined __ARMVFP__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __TI_ARM__ )\n  #if defined __TI_VFP_SUPPORT__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __TASKING__ )\n  #if defined __FPU_VFP__\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#elif defined ( __CSMC__ )\n  #if ( __CSMC__ & 0x400U)\n    #error \"Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)\"\n  #endif\n\n#endif\n\n#include \"cmsis_compiler.h\"               /* CMSIS compiler specific defines */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __CORE_CM3_H_GENERIC */\n\n#ifndef __CMSIS_GENERIC\n\n#ifndef __CORE_CM3_H_DEPENDANT\n#define __CORE_CM3_H_DEPENDANT\n\n#ifdef __cplusplus\n extern \"C\" {\n#endif\n\n/* check device defines and use defaults */\n#if defined __CHECK_DEVICE_DEFINES\n  #ifndef __CM3_REV\n    #define __CM3_REV               0x0200U\n    #warning \"__CM3_REV not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __MPU_PRESENT\n    #define __MPU_PRESENT             0U\n    #warning \"__MPU_PRESENT not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __VTOR_PRESENT\n    #define __VTOR_PRESENT             1U\n    #warning \"__VTOR_PRESENT not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __NVIC_PRIO_BITS\n    #define __NVIC_PRIO_BITS          3U\n    #warning \"__NVIC_PRIO_BITS not defined in device header file; using default!\"\n  #endif\n\n  #ifndef __Vendor_SysTickConfig\n    #define __Vendor_SysTickConfig    0U\n    #warning \"__Vendor_SysTickConfig not defined in device header file; using default!\"\n  #endif\n#endif\n\n/* IO definitions (access restrictions to peripheral registers) */\n/**\n    \\defgroup CMSIS_glob_defs CMSIS Global Defines\n\n    <strong>IO Type Qualifiers</strong> are used\n    \\li to specify the access to peripheral variables.\n    \\li for automatic generation of peripheral register debug information.\n*/\n#ifdef __cplusplus\n  #define   __I     volatile             /*!< Defines 'read only' permissions */\n#else\n  #define   __I     volatile const       /*!< Defines 'read only' permissions */\n#endif\n#define     __O     volatile             /*!< Defines 'write only' permissions */\n#define     __IO    volatile             /*!< Defines 'read / write' permissions */\n\n/* following defines should be used for structure members */\n#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */\n#define     __OM     volatile            /*! Defines 'write only' structure member permissions */\n#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */\n\n/*@} end of group Cortex_M3 */\n\n\n\n/*******************************************************************************\n *                 Register Abstraction\n  Core Register contain:\n  - Core Register\n  - Core NVIC Register\n  - Core SCB Register\n  - Core SysTick Register\n  - Core Debug Register\n  - Core MPU Register\n ******************************************************************************/\n/**\n  \\defgroup CMSIS_core_register Defines and Type Definitions\n  \\brief Type definitions and defines for Cortex-M processor based devices.\n*/\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_CORE  Status and Control Registers\n  \\brief      Core Register type definitions.\n  @{\n */\n\n/**\n  \\brief  Union type to access the Application Program Status Register (APSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t _reserved0:27;              /*!< bit:  0..26  Reserved */\n    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */\n    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */\n    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */\n    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */\n    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} APSR_Type;\n\n/* APSR Register Definitions */\n#define APSR_N_Pos                         31U                                            /*!< APSR: N Position */\n#define APSR_N_Msk                         (1UL << APSR_N_Pos)                            /*!< APSR: N Mask */\n\n#define APSR_Z_Pos                         30U                                            /*!< APSR: Z Position */\n#define APSR_Z_Msk                         (1UL << APSR_Z_Pos)                            /*!< APSR: Z Mask */\n\n#define APSR_C_Pos                         29U                                            /*!< APSR: C Position */\n#define APSR_C_Msk                         (1UL << APSR_C_Pos)                            /*!< APSR: C Mask */\n\n#define APSR_V_Pos                         28U                                            /*!< APSR: V Position */\n#define APSR_V_Msk                         (1UL << APSR_V_Pos)                            /*!< APSR: V Mask */\n\n#define APSR_Q_Pos                         27U                                            /*!< APSR: Q Position */\n#define APSR_Q_Msk                         (1UL << APSR_Q_Pos)                            /*!< APSR: Q Mask */\n\n\n/**\n  \\brief  Union type to access the Interrupt Program Status Register (IPSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t ISR:9;                      /*!< bit:  0.. 8  Exception number */\n    uint32_t _reserved0:23;              /*!< bit:  9..31  Reserved */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} IPSR_Type;\n\n/* IPSR Register Definitions */\n#define IPSR_ISR_Pos                        0U                                            /*!< IPSR: ISR Position */\n#define IPSR_ISR_Msk                       (0x1FFUL /*<< IPSR_ISR_Pos*/)                  /*!< IPSR: ISR Mask */\n\n\n/**\n  \\brief  Union type to access the Special-Purpose Program Status Registers (xPSR).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t ISR:9;                      /*!< bit:  0.. 8  Exception number */\n    uint32_t _reserved0:1;               /*!< bit:      9  Reserved */\n    uint32_t ICI_IT_1:6;                 /*!< bit: 10..15  ICI/IT part 1 */\n    uint32_t _reserved1:8;               /*!< bit: 16..23  Reserved */\n    uint32_t T:1;                        /*!< bit:     24  Thumb bit */\n    uint32_t ICI_IT_2:2;                 /*!< bit: 25..26  ICI/IT part 2 */\n    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */\n    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */\n    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */\n    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */\n    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} xPSR_Type;\n\n/* xPSR Register Definitions */\n#define xPSR_N_Pos                         31U                                            /*!< xPSR: N Position */\n#define xPSR_N_Msk                         (1UL << xPSR_N_Pos)                            /*!< xPSR: N Mask */\n\n#define xPSR_Z_Pos                         30U                                            /*!< xPSR: Z Position */\n#define xPSR_Z_Msk                         (1UL << xPSR_Z_Pos)                            /*!< xPSR: Z Mask */\n\n#define xPSR_C_Pos                         29U                                            /*!< xPSR: C Position */\n#define xPSR_C_Msk                         (1UL << xPSR_C_Pos)                            /*!< xPSR: C Mask */\n\n#define xPSR_V_Pos                         28U                                            /*!< xPSR: V Position */\n#define xPSR_V_Msk                         (1UL << xPSR_V_Pos)                            /*!< xPSR: V Mask */\n\n#define xPSR_Q_Pos                         27U                                            /*!< xPSR: Q Position */\n#define xPSR_Q_Msk                         (1UL << xPSR_Q_Pos)                            /*!< xPSR: Q Mask */\n\n#define xPSR_ICI_IT_2_Pos                  25U                                            /*!< xPSR: ICI/IT part 2 Position */\n#define xPSR_ICI_IT_2_Msk                  (3UL << xPSR_ICI_IT_2_Pos)                     /*!< xPSR: ICI/IT part 2 Mask */\n\n#define xPSR_T_Pos                         24U                                            /*!< xPSR: T Position */\n#define xPSR_T_Msk                         (1UL << xPSR_T_Pos)                            /*!< xPSR: T Mask */\n\n#define xPSR_ICI_IT_1_Pos                  10U                                            /*!< xPSR: ICI/IT part 1 Position */\n#define xPSR_ICI_IT_1_Msk                  (0x3FUL << xPSR_ICI_IT_1_Pos)                  /*!< xPSR: ICI/IT part 1 Mask */\n\n#define xPSR_ISR_Pos                        0U                                            /*!< xPSR: ISR Position */\n#define xPSR_ISR_Msk                       (0x1FFUL /*<< xPSR_ISR_Pos*/)                  /*!< xPSR: ISR Mask */\n\n\n/**\n  \\brief  Union type to access the Control Registers (CONTROL).\n */\ntypedef union\n{\n  struct\n  {\n    uint32_t nPRIV:1;                    /*!< bit:      0  Execution privilege in Thread mode */\n    uint32_t SPSEL:1;                    /*!< bit:      1  Stack to be used */\n    uint32_t _reserved1:30;              /*!< bit:  2..31  Reserved */\n  } b;                                   /*!< Structure used for bit  access */\n  uint32_t w;                            /*!< Type      used for word access */\n} CONTROL_Type;\n\n/* CONTROL Register Definitions */\n#define CONTROL_SPSEL_Pos                   1U                                            /*!< CONTROL: SPSEL Position */\n#define CONTROL_SPSEL_Msk                  (1UL << CONTROL_SPSEL_Pos)                     /*!< CONTROL: SPSEL Mask */\n\n#define CONTROL_nPRIV_Pos                   0U                                            /*!< CONTROL: nPRIV Position */\n#define CONTROL_nPRIV_Msk                  (1UL /*<< CONTROL_nPRIV_Pos*/)                 /*!< CONTROL: nPRIV Mask */\n\n/*@} end of group CMSIS_CORE */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_NVIC  Nested Vectored Interrupt Controller (NVIC)\n  \\brief      Type definitions for the NVIC Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Nested Vectored Interrupt Controller (NVIC).\n */\ntypedef struct\n{\n  __IOM uint32_t ISER[8U];               /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register */\n        uint32_t RESERVED0[24U];\n  __IOM uint32_t ICER[8U];               /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register */\n        uint32_t RESERVED1[24U];\n  __IOM uint32_t ISPR[8U];               /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register */\n        uint32_t RESERVED2[24U];\n  __IOM uint32_t ICPR[8U];               /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register */\n        uint32_t RESERVED3[24U];\n  __IOM uint32_t IABR[8U];               /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register */\n        uint32_t RESERVED4[56U];\n  __IOM uint8_t  IP[240U];               /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */\n        uint32_t RESERVED5[644U];\n  __OM  uint32_t STIR;                   /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register */\n}  NVIC_Type;\n\n/* Software Triggered Interrupt Register Definitions */\n#define NVIC_STIR_INTID_Pos                 0U                                         /*!< STIR: INTLINESNUM Position */\n#define NVIC_STIR_INTID_Msk                (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/)        /*!< STIR: INTLINESNUM Mask */\n\n/*@} end of group CMSIS_NVIC */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SCB     System Control Block (SCB)\n  \\brief    Type definitions for the System Control Block Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Control Block (SCB).\n */\ntypedef struct\n{\n  __IM  uint32_t CPUID;                  /*!< Offset: 0x000 (R/ )  CPUID Base Register */\n  __IOM uint32_t ICSR;                   /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register */\n  __IOM uint32_t VTOR;                   /*!< Offset: 0x008 (R/W)  Vector Table Offset Register */\n  __IOM uint32_t AIRCR;                  /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register */\n  __IOM uint32_t SCR;                    /*!< Offset: 0x010 (R/W)  System Control Register */\n  __IOM uint32_t CCR;                    /*!< Offset: 0x014 (R/W)  Configuration Control Register */\n  __IOM uint8_t  SHP[12U];               /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */\n  __IOM uint32_t SHCSR;                  /*!< Offset: 0x024 (R/W)  System Handler Control and State Register */\n  __IOM uint32_t CFSR;                   /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register */\n  __IOM uint32_t HFSR;                   /*!< Offset: 0x02C (R/W)  HardFault Status Register */\n  __IOM uint32_t DFSR;                   /*!< Offset: 0x030 (R/W)  Debug Fault Status Register */\n  __IOM uint32_t MMFAR;                  /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register */\n  __IOM uint32_t BFAR;                   /*!< Offset: 0x038 (R/W)  BusFault Address Register */\n  __IOM uint32_t AFSR;                   /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register */\n  __IM  uint32_t PFR[2U];                /*!< Offset: 0x040 (R/ )  Processor Feature Register */\n  __IM  uint32_t DFR;                    /*!< Offset: 0x048 (R/ )  Debug Feature Register */\n  __IM  uint32_t ADR;                    /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register */\n  __IM  uint32_t MMFR[4U];               /*!< Offset: 0x050 (R/ )  Memory Model Feature Register */\n  __IM  uint32_t ISAR[5U];               /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register */\n        uint32_t RESERVED0[5U];\n  __IOM uint32_t CPACR;                  /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register */\n} SCB_Type;\n\n/* SCB CPUID Register Definitions */\n#define SCB_CPUID_IMPLEMENTER_Pos          24U                                            /*!< SCB CPUID: IMPLEMENTER Position */\n#define SCB_CPUID_IMPLEMENTER_Msk          (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos)          /*!< SCB CPUID: IMPLEMENTER Mask */\n\n#define SCB_CPUID_VARIANT_Pos              20U                                            /*!< SCB CPUID: VARIANT Position */\n#define SCB_CPUID_VARIANT_Msk              (0xFUL << SCB_CPUID_VARIANT_Pos)               /*!< SCB CPUID: VARIANT Mask */\n\n#define SCB_CPUID_ARCHITECTURE_Pos         16U                                            /*!< SCB CPUID: ARCHITECTURE Position */\n#define SCB_CPUID_ARCHITECTURE_Msk         (0xFUL << SCB_CPUID_ARCHITECTURE_Pos)          /*!< SCB CPUID: ARCHITECTURE Mask */\n\n#define SCB_CPUID_PARTNO_Pos                4U                                            /*!< SCB CPUID: PARTNO Position */\n#define SCB_CPUID_PARTNO_Msk               (0xFFFUL << SCB_CPUID_PARTNO_Pos)              /*!< SCB CPUID: PARTNO Mask */\n\n#define SCB_CPUID_REVISION_Pos              0U                                            /*!< SCB CPUID: REVISION Position */\n#define SCB_CPUID_REVISION_Msk             (0xFUL /*<< SCB_CPUID_REVISION_Pos*/)          /*!< SCB CPUID: REVISION Mask */\n\n/* SCB Interrupt Control State Register Definitions */\n#define SCB_ICSR_NMIPENDSET_Pos            31U                                            /*!< SCB ICSR: NMIPENDSET Position */\n#define SCB_ICSR_NMIPENDSET_Msk            (1UL << SCB_ICSR_NMIPENDSET_Pos)               /*!< SCB ICSR: NMIPENDSET Mask */\n\n#define SCB_ICSR_PENDSVSET_Pos             28U                                            /*!< SCB ICSR: PENDSVSET Position */\n#define SCB_ICSR_PENDSVSET_Msk             (1UL << SCB_ICSR_PENDSVSET_Pos)                /*!< SCB ICSR: PENDSVSET Mask */\n\n#define SCB_ICSR_PENDSVCLR_Pos             27U                                            /*!< SCB ICSR: PENDSVCLR Position */\n#define SCB_ICSR_PENDSVCLR_Msk             (1UL << SCB_ICSR_PENDSVCLR_Pos)                /*!< SCB ICSR: PENDSVCLR Mask */\n\n#define SCB_ICSR_PENDSTSET_Pos             26U                                            /*!< SCB ICSR: PENDSTSET Position */\n#define SCB_ICSR_PENDSTSET_Msk             (1UL << SCB_ICSR_PENDSTSET_Pos)                /*!< SCB ICSR: PENDSTSET Mask */\n\n#define SCB_ICSR_PENDSTCLR_Pos             25U                                            /*!< SCB ICSR: PENDSTCLR Position */\n#define SCB_ICSR_PENDSTCLR_Msk             (1UL << SCB_ICSR_PENDSTCLR_Pos)                /*!< SCB ICSR: PENDSTCLR Mask */\n\n#define SCB_ICSR_ISRPREEMPT_Pos            23U                                            /*!< SCB ICSR: ISRPREEMPT Position */\n#define SCB_ICSR_ISRPREEMPT_Msk            (1UL << SCB_ICSR_ISRPREEMPT_Pos)               /*!< SCB ICSR: ISRPREEMPT Mask */\n\n#define SCB_ICSR_ISRPENDING_Pos            22U                                            /*!< SCB ICSR: ISRPENDING Position */\n#define SCB_ICSR_ISRPENDING_Msk            (1UL << SCB_ICSR_ISRPENDING_Pos)               /*!< SCB ICSR: ISRPENDING Mask */\n\n#define SCB_ICSR_VECTPENDING_Pos           12U                                            /*!< SCB ICSR: VECTPENDING Position */\n#define SCB_ICSR_VECTPENDING_Msk           (0x1FFUL << SCB_ICSR_VECTPENDING_Pos)          /*!< SCB ICSR: VECTPENDING Mask */\n\n#define SCB_ICSR_RETTOBASE_Pos             11U                                            /*!< SCB ICSR: RETTOBASE Position */\n#define SCB_ICSR_RETTOBASE_Msk             (1UL << SCB_ICSR_RETTOBASE_Pos)                /*!< SCB ICSR: RETTOBASE Mask */\n\n#define SCB_ICSR_VECTACTIVE_Pos             0U                                            /*!< SCB ICSR: VECTACTIVE Position */\n#define SCB_ICSR_VECTACTIVE_Msk            (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/)       /*!< SCB ICSR: VECTACTIVE Mask */\n\n/* SCB Vector Table Offset Register Definitions */\n#if defined (__CM3_REV) && (__CM3_REV < 0x0201U)                   /* core r2p1 */\n#define SCB_VTOR_TBLBASE_Pos               29U                                            /*!< SCB VTOR: TBLBASE Position */\n#define SCB_VTOR_TBLBASE_Msk               (1UL << SCB_VTOR_TBLBASE_Pos)                  /*!< SCB VTOR: TBLBASE Mask */\n\n#define SCB_VTOR_TBLOFF_Pos                 7U                                            /*!< SCB VTOR: TBLOFF Position */\n#define SCB_VTOR_TBLOFF_Msk                (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos)            /*!< SCB VTOR: TBLOFF Mask */\n#else\n#define SCB_VTOR_TBLOFF_Pos                 7U                                            /*!< SCB VTOR: TBLOFF Position */\n#define SCB_VTOR_TBLOFF_Msk                (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos)           /*!< SCB VTOR: TBLOFF Mask */\n#endif\n\n/* SCB Application Interrupt and Reset Control Register Definitions */\n#define SCB_AIRCR_VECTKEY_Pos              16U                                            /*!< SCB AIRCR: VECTKEY Position */\n#define SCB_AIRCR_VECTKEY_Msk              (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos)            /*!< SCB AIRCR: VECTKEY Mask */\n\n#define SCB_AIRCR_VECTKEYSTAT_Pos          16U                                            /*!< SCB AIRCR: VECTKEYSTAT Position */\n#define SCB_AIRCR_VECTKEYSTAT_Msk          (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos)        /*!< SCB AIRCR: VECTKEYSTAT Mask */\n\n#define SCB_AIRCR_ENDIANESS_Pos            15U                                            /*!< SCB AIRCR: ENDIANESS Position */\n#define SCB_AIRCR_ENDIANESS_Msk            (1UL << SCB_AIRCR_ENDIANESS_Pos)               /*!< SCB AIRCR: ENDIANESS Mask */\n\n#define SCB_AIRCR_PRIGROUP_Pos              8U                                            /*!< SCB AIRCR: PRIGROUP Position */\n#define SCB_AIRCR_PRIGROUP_Msk             (7UL << SCB_AIRCR_PRIGROUP_Pos)                /*!< SCB AIRCR: PRIGROUP Mask */\n\n#define SCB_AIRCR_SYSRESETREQ_Pos           2U                                            /*!< SCB AIRCR: SYSRESETREQ Position */\n#define SCB_AIRCR_SYSRESETREQ_Msk          (1UL << SCB_AIRCR_SYSRESETREQ_Pos)             /*!< SCB AIRCR: SYSRESETREQ Mask */\n\n#define SCB_AIRCR_VECTCLRACTIVE_Pos         1U                                            /*!< SCB AIRCR: VECTCLRACTIVE Position */\n#define SCB_AIRCR_VECTCLRACTIVE_Msk        (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos)           /*!< SCB AIRCR: VECTCLRACTIVE Mask */\n\n#define SCB_AIRCR_VECTRESET_Pos             0U                                            /*!< SCB AIRCR: VECTRESET Position */\n#define SCB_AIRCR_VECTRESET_Msk            (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/)           /*!< SCB AIRCR: VECTRESET Mask */\n\n/* SCB System Control Register Definitions */\n#define SCB_SCR_SEVONPEND_Pos               4U                                            /*!< SCB SCR: SEVONPEND Position */\n#define SCB_SCR_SEVONPEND_Msk              (1UL << SCB_SCR_SEVONPEND_Pos)                 /*!< SCB SCR: SEVONPEND Mask */\n\n#define SCB_SCR_SLEEPDEEP_Pos               2U                                            /*!< SCB SCR: SLEEPDEEP Position */\n#define SCB_SCR_SLEEPDEEP_Msk              (1UL << SCB_SCR_SLEEPDEEP_Pos)                 /*!< SCB SCR: SLEEPDEEP Mask */\n\n#define SCB_SCR_SLEEPONEXIT_Pos             1U                                            /*!< SCB SCR: SLEEPONEXIT Position */\n#define SCB_SCR_SLEEPONEXIT_Msk            (1UL << SCB_SCR_SLEEPONEXIT_Pos)               /*!< SCB SCR: SLEEPONEXIT Mask */\n\n/* SCB Configuration Control Register Definitions */\n#define SCB_CCR_STKALIGN_Pos                9U                                            /*!< SCB CCR: STKALIGN Position */\n#define SCB_CCR_STKALIGN_Msk               (1UL << SCB_CCR_STKALIGN_Pos)                  /*!< SCB CCR: STKALIGN Mask */\n\n#define SCB_CCR_BFHFNMIGN_Pos               8U                                            /*!< SCB CCR: BFHFNMIGN Position */\n#define SCB_CCR_BFHFNMIGN_Msk              (1UL << SCB_CCR_BFHFNMIGN_Pos)                 /*!< SCB CCR: BFHFNMIGN Mask */\n\n#define SCB_CCR_DIV_0_TRP_Pos               4U                                            /*!< SCB CCR: DIV_0_TRP Position */\n#define SCB_CCR_DIV_0_TRP_Msk              (1UL << SCB_CCR_DIV_0_TRP_Pos)                 /*!< SCB CCR: DIV_0_TRP Mask */\n\n#define SCB_CCR_UNALIGN_TRP_Pos             3U                                            /*!< SCB CCR: UNALIGN_TRP Position */\n#define SCB_CCR_UNALIGN_TRP_Msk            (1UL << SCB_CCR_UNALIGN_TRP_Pos)               /*!< SCB CCR: UNALIGN_TRP Mask */\n\n#define SCB_CCR_USERSETMPEND_Pos            1U                                            /*!< SCB CCR: USERSETMPEND Position */\n#define SCB_CCR_USERSETMPEND_Msk           (1UL << SCB_CCR_USERSETMPEND_Pos)              /*!< SCB CCR: USERSETMPEND Mask */\n\n#define SCB_CCR_NONBASETHRDENA_Pos          0U                                            /*!< SCB CCR: NONBASETHRDENA Position */\n#define SCB_CCR_NONBASETHRDENA_Msk         (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/)        /*!< SCB CCR: NONBASETHRDENA Mask */\n\n/* SCB System Handler Control and State Register Definitions */\n#define SCB_SHCSR_USGFAULTENA_Pos          18U                                            /*!< SCB SHCSR: USGFAULTENA Position */\n#define SCB_SHCSR_USGFAULTENA_Msk          (1UL << SCB_SHCSR_USGFAULTENA_Pos)             /*!< SCB SHCSR: USGFAULTENA Mask */\n\n#define SCB_SHCSR_BUSFAULTENA_Pos          17U                                            /*!< SCB SHCSR: BUSFAULTENA Position */\n#define SCB_SHCSR_BUSFAULTENA_Msk          (1UL << SCB_SHCSR_BUSFAULTENA_Pos)             /*!< SCB SHCSR: BUSFAULTENA Mask */\n\n#define SCB_SHCSR_MEMFAULTENA_Pos          16U                                            /*!< SCB SHCSR: MEMFAULTENA Position */\n#define SCB_SHCSR_MEMFAULTENA_Msk          (1UL << SCB_SHCSR_MEMFAULTENA_Pos)             /*!< SCB SHCSR: MEMFAULTENA Mask */\n\n#define SCB_SHCSR_SVCALLPENDED_Pos         15U                                            /*!< SCB SHCSR: SVCALLPENDED Position */\n#define SCB_SHCSR_SVCALLPENDED_Msk         (1UL << SCB_SHCSR_SVCALLPENDED_Pos)            /*!< SCB SHCSR: SVCALLPENDED Mask */\n\n#define SCB_SHCSR_BUSFAULTPENDED_Pos       14U                                            /*!< SCB SHCSR: BUSFAULTPENDED Position */\n#define SCB_SHCSR_BUSFAULTPENDED_Msk       (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos)          /*!< SCB SHCSR: BUSFAULTPENDED Mask */\n\n#define SCB_SHCSR_MEMFAULTPENDED_Pos       13U                                            /*!< SCB SHCSR: MEMFAULTPENDED Position */\n#define SCB_SHCSR_MEMFAULTPENDED_Msk       (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos)          /*!< SCB SHCSR: MEMFAULTPENDED Mask */\n\n#define SCB_SHCSR_USGFAULTPENDED_Pos       12U                                            /*!< SCB SHCSR: USGFAULTPENDED Position */\n#define SCB_SHCSR_USGFAULTPENDED_Msk       (1UL << SCB_SHCSR_USGFAULTPENDED_Pos)          /*!< SCB SHCSR: USGFAULTPENDED Mask */\n\n#define SCB_SHCSR_SYSTICKACT_Pos           11U                                            /*!< SCB SHCSR: SYSTICKACT Position */\n#define SCB_SHCSR_SYSTICKACT_Msk           (1UL << SCB_SHCSR_SYSTICKACT_Pos)              /*!< SCB SHCSR: SYSTICKACT Mask */\n\n#define SCB_SHCSR_PENDSVACT_Pos            10U                                            /*!< SCB SHCSR: PENDSVACT Position */\n#define SCB_SHCSR_PENDSVACT_Msk            (1UL << SCB_SHCSR_PENDSVACT_Pos)               /*!< SCB SHCSR: PENDSVACT Mask */\n\n#define SCB_SHCSR_MONITORACT_Pos            8U                                            /*!< SCB SHCSR: MONITORACT Position */\n#define SCB_SHCSR_MONITORACT_Msk           (1UL << SCB_SHCSR_MONITORACT_Pos)              /*!< SCB SHCSR: MONITORACT Mask */\n\n#define SCB_SHCSR_SVCALLACT_Pos             7U                                            /*!< SCB SHCSR: SVCALLACT Position */\n#define SCB_SHCSR_SVCALLACT_Msk            (1UL << SCB_SHCSR_SVCALLACT_Pos)               /*!< SCB SHCSR: SVCALLACT Mask */\n\n#define SCB_SHCSR_USGFAULTACT_Pos           3U                                            /*!< SCB SHCSR: USGFAULTACT Position */\n#define SCB_SHCSR_USGFAULTACT_Msk          (1UL << SCB_SHCSR_USGFAULTACT_Pos)             /*!< SCB SHCSR: USGFAULTACT Mask */\n\n#define SCB_SHCSR_BUSFAULTACT_Pos           1U                                            /*!< SCB SHCSR: BUSFAULTACT Position */\n#define SCB_SHCSR_BUSFAULTACT_Msk          (1UL << SCB_SHCSR_BUSFAULTACT_Pos)             /*!< SCB SHCSR: BUSFAULTACT Mask */\n\n#define SCB_SHCSR_MEMFAULTACT_Pos           0U                                            /*!< SCB SHCSR: MEMFAULTACT Position */\n#define SCB_SHCSR_MEMFAULTACT_Msk          (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/)         /*!< SCB SHCSR: MEMFAULTACT Mask */\n\n/* SCB Configurable Fault Status Register Definitions */\n#define SCB_CFSR_USGFAULTSR_Pos            16U                                            /*!< SCB CFSR: Usage Fault Status Register Position */\n#define SCB_CFSR_USGFAULTSR_Msk            (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos)          /*!< SCB CFSR: Usage Fault Status Register Mask */\n\n#define SCB_CFSR_BUSFAULTSR_Pos             8U                                            /*!< SCB CFSR: Bus Fault Status Register Position */\n#define SCB_CFSR_BUSFAULTSR_Msk            (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos)            /*!< SCB CFSR: Bus Fault Status Register Mask */\n\n#define SCB_CFSR_MEMFAULTSR_Pos             0U                                            /*!< SCB CFSR: Memory Manage Fault Status Register Position */\n#define SCB_CFSR_MEMFAULTSR_Msk            (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/)        /*!< SCB CFSR: Memory Manage Fault Status Register Mask */\n\n/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_MMARVALID_Pos             (SCB_CFSR_MEMFAULTSR_Pos + 7U)                 /*!< SCB CFSR (MMFSR): MMARVALID Position */\n#define SCB_CFSR_MMARVALID_Msk             (1UL << SCB_CFSR_MMARVALID_Pos)                /*!< SCB CFSR (MMFSR): MMARVALID Mask */\n\n#define SCB_CFSR_MSTKERR_Pos               (SCB_CFSR_MEMFAULTSR_Pos + 4U)                 /*!< SCB CFSR (MMFSR): MSTKERR Position */\n#define SCB_CFSR_MSTKERR_Msk               (1UL << SCB_CFSR_MSTKERR_Pos)                  /*!< SCB CFSR (MMFSR): MSTKERR Mask */\n\n#define SCB_CFSR_MUNSTKERR_Pos             (SCB_CFSR_MEMFAULTSR_Pos + 3U)                 /*!< SCB CFSR (MMFSR): MUNSTKERR Position */\n#define SCB_CFSR_MUNSTKERR_Msk             (1UL << SCB_CFSR_MUNSTKERR_Pos)                /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */\n\n#define SCB_CFSR_DACCVIOL_Pos              (SCB_CFSR_MEMFAULTSR_Pos + 1U)                 /*!< SCB CFSR (MMFSR): DACCVIOL Position */\n#define SCB_CFSR_DACCVIOL_Msk              (1UL << SCB_CFSR_DACCVIOL_Pos)                 /*!< SCB CFSR (MMFSR): DACCVIOL Mask */\n\n#define SCB_CFSR_IACCVIOL_Pos              (SCB_CFSR_MEMFAULTSR_Pos + 0U)                 /*!< SCB CFSR (MMFSR): IACCVIOL Position */\n#define SCB_CFSR_IACCVIOL_Msk              (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/)             /*!< SCB CFSR (MMFSR): IACCVIOL Mask */\n\n/* BusFault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_BFARVALID_Pos            (SCB_CFSR_BUSFAULTSR_Pos + 7U)                  /*!< SCB CFSR (BFSR): BFARVALID Position */\n#define SCB_CFSR_BFARVALID_Msk            (1UL << SCB_CFSR_BFARVALID_Pos)                 /*!< SCB CFSR (BFSR): BFARVALID Mask */\n\n#define SCB_CFSR_STKERR_Pos               (SCB_CFSR_BUSFAULTSR_Pos + 4U)                  /*!< SCB CFSR (BFSR): STKERR Position */\n#define SCB_CFSR_STKERR_Msk               (1UL << SCB_CFSR_STKERR_Pos)                    /*!< SCB CFSR (BFSR): STKERR Mask */\n\n#define SCB_CFSR_UNSTKERR_Pos             (SCB_CFSR_BUSFAULTSR_Pos + 3U)                  /*!< SCB CFSR (BFSR): UNSTKERR Position */\n#define SCB_CFSR_UNSTKERR_Msk             (1UL << SCB_CFSR_UNSTKERR_Pos)                  /*!< SCB CFSR (BFSR): UNSTKERR Mask */\n\n#define SCB_CFSR_IMPRECISERR_Pos          (SCB_CFSR_BUSFAULTSR_Pos + 2U)                  /*!< SCB CFSR (BFSR): IMPRECISERR Position */\n#define SCB_CFSR_IMPRECISERR_Msk          (1UL << SCB_CFSR_IMPRECISERR_Pos)               /*!< SCB CFSR (BFSR): IMPRECISERR Mask */\n\n#define SCB_CFSR_PRECISERR_Pos            (SCB_CFSR_BUSFAULTSR_Pos + 1U)                  /*!< SCB CFSR (BFSR): PRECISERR Position */\n#define SCB_CFSR_PRECISERR_Msk            (1UL << SCB_CFSR_PRECISERR_Pos)                 /*!< SCB CFSR (BFSR): PRECISERR Mask */\n\n#define SCB_CFSR_IBUSERR_Pos              (SCB_CFSR_BUSFAULTSR_Pos + 0U)                  /*!< SCB CFSR (BFSR): IBUSERR Position */\n#define SCB_CFSR_IBUSERR_Msk              (1UL << SCB_CFSR_IBUSERR_Pos)                   /*!< SCB CFSR (BFSR): IBUSERR Mask */\n\n/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */\n#define SCB_CFSR_DIVBYZERO_Pos            (SCB_CFSR_USGFAULTSR_Pos + 9U)                  /*!< SCB CFSR (UFSR): DIVBYZERO Position */\n#define SCB_CFSR_DIVBYZERO_Msk            (1UL << SCB_CFSR_DIVBYZERO_Pos)                 /*!< SCB CFSR (UFSR): DIVBYZERO Mask */\n\n#define SCB_CFSR_UNALIGNED_Pos            (SCB_CFSR_USGFAULTSR_Pos + 8U)                  /*!< SCB CFSR (UFSR): UNALIGNED Position */\n#define SCB_CFSR_UNALIGNED_Msk            (1UL << SCB_CFSR_UNALIGNED_Pos)                 /*!< SCB CFSR (UFSR): UNALIGNED Mask */\n\n#define SCB_CFSR_NOCP_Pos                 (SCB_CFSR_USGFAULTSR_Pos + 3U)                  /*!< SCB CFSR (UFSR): NOCP Position */\n#define SCB_CFSR_NOCP_Msk                 (1UL << SCB_CFSR_NOCP_Pos)                      /*!< SCB CFSR (UFSR): NOCP Mask */\n\n#define SCB_CFSR_INVPC_Pos                (SCB_CFSR_USGFAULTSR_Pos + 2U)                  /*!< SCB CFSR (UFSR): INVPC Position */\n#define SCB_CFSR_INVPC_Msk                (1UL << SCB_CFSR_INVPC_Pos)                     /*!< SCB CFSR (UFSR): INVPC Mask */\n\n#define SCB_CFSR_INVSTATE_Pos             (SCB_CFSR_USGFAULTSR_Pos + 1U)                  /*!< SCB CFSR (UFSR): INVSTATE Position */\n#define SCB_CFSR_INVSTATE_Msk             (1UL << SCB_CFSR_INVSTATE_Pos)                  /*!< SCB CFSR (UFSR): INVSTATE Mask */\n\n#define SCB_CFSR_UNDEFINSTR_Pos           (SCB_CFSR_USGFAULTSR_Pos + 0U)                  /*!< SCB CFSR (UFSR): UNDEFINSTR Position */\n#define SCB_CFSR_UNDEFINSTR_Msk           (1UL << SCB_CFSR_UNDEFINSTR_Pos)                /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */\n\n/* SCB Hard Fault Status Register Definitions */\n#define SCB_HFSR_DEBUGEVT_Pos              31U                                            /*!< SCB HFSR: DEBUGEVT Position */\n#define SCB_HFSR_DEBUGEVT_Msk              (1UL << SCB_HFSR_DEBUGEVT_Pos)                 /*!< SCB HFSR: DEBUGEVT Mask */\n\n#define SCB_HFSR_FORCED_Pos                30U                                            /*!< SCB HFSR: FORCED Position */\n#define SCB_HFSR_FORCED_Msk                (1UL << SCB_HFSR_FORCED_Pos)                   /*!< SCB HFSR: FORCED Mask */\n\n#define SCB_HFSR_VECTTBL_Pos                1U                                            /*!< SCB HFSR: VECTTBL Position */\n#define SCB_HFSR_VECTTBL_Msk               (1UL << SCB_HFSR_VECTTBL_Pos)                  /*!< SCB HFSR: VECTTBL Mask */\n\n/* SCB Debug Fault Status Register Definitions */\n#define SCB_DFSR_EXTERNAL_Pos               4U                                            /*!< SCB DFSR: EXTERNAL Position */\n#define SCB_DFSR_EXTERNAL_Msk              (1UL << SCB_DFSR_EXTERNAL_Pos)                 /*!< SCB DFSR: EXTERNAL Mask */\n\n#define SCB_DFSR_VCATCH_Pos                 3U                                            /*!< SCB DFSR: VCATCH Position */\n#define SCB_DFSR_VCATCH_Msk                (1UL << SCB_DFSR_VCATCH_Pos)                   /*!< SCB DFSR: VCATCH Mask */\n\n#define SCB_DFSR_DWTTRAP_Pos                2U                                            /*!< SCB DFSR: DWTTRAP Position */\n#define SCB_DFSR_DWTTRAP_Msk               (1UL << SCB_DFSR_DWTTRAP_Pos)                  /*!< SCB DFSR: DWTTRAP Mask */\n\n#define SCB_DFSR_BKPT_Pos                   1U                                            /*!< SCB DFSR: BKPT Position */\n#define SCB_DFSR_BKPT_Msk                  (1UL << SCB_DFSR_BKPT_Pos)                     /*!< SCB DFSR: BKPT Mask */\n\n#define SCB_DFSR_HALTED_Pos                 0U                                            /*!< SCB DFSR: HALTED Position */\n#define SCB_DFSR_HALTED_Msk                (1UL /*<< SCB_DFSR_HALTED_Pos*/)               /*!< SCB DFSR: HALTED Mask */\n\n/*@} end of group CMSIS_SCB */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB)\n  \\brief    Type definitions for the System Control and ID Register not in the SCB\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Control and ID Register not in the SCB.\n */\ntypedef struct\n{\n        uint32_t RESERVED0[1U];\n  __IM  uint32_t ICTR;                   /*!< Offset: 0x004 (R/ )  Interrupt Controller Type Register */\n#if defined (__CM3_REV) && (__CM3_REV >= 0x200U)\n  __IOM uint32_t ACTLR;                  /*!< Offset: 0x008 (R/W)  Auxiliary Control Register */\n#else\n        uint32_t RESERVED1[1U];\n#endif\n} SCnSCB_Type;\n\n/* Interrupt Controller Type Register Definitions */\n#define SCnSCB_ICTR_INTLINESNUM_Pos         0U                                         /*!< ICTR: INTLINESNUM Position */\n#define SCnSCB_ICTR_INTLINESNUM_Msk        (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/)  /*!< ICTR: INTLINESNUM Mask */\n\n/* Auxiliary Control Register Definitions */\n#if defined (__CM3_REV) && (__CM3_REV >= 0x200U)\n#define SCnSCB_ACTLR_DISOOFP_Pos            9U                                         /*!< ACTLR: DISOOFP Position */\n#define SCnSCB_ACTLR_DISOOFP_Msk           (1UL << SCnSCB_ACTLR_DISOOFP_Pos)           /*!< ACTLR: DISOOFP Mask */\n\n#define SCnSCB_ACTLR_DISFPCA_Pos            8U                                         /*!< ACTLR: DISFPCA Position */\n#define SCnSCB_ACTLR_DISFPCA_Msk           (1UL << SCnSCB_ACTLR_DISFPCA_Pos)           /*!< ACTLR: DISFPCA Mask */\n\n#define SCnSCB_ACTLR_DISFOLD_Pos            2U                                         /*!< ACTLR: DISFOLD Position */\n#define SCnSCB_ACTLR_DISFOLD_Msk           (1UL << SCnSCB_ACTLR_DISFOLD_Pos)           /*!< ACTLR: DISFOLD Mask */\n\n#define SCnSCB_ACTLR_DISDEFWBUF_Pos         1U                                         /*!< ACTLR: DISDEFWBUF Position */\n#define SCnSCB_ACTLR_DISDEFWBUF_Msk        (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos)        /*!< ACTLR: DISDEFWBUF Mask */\n\n#define SCnSCB_ACTLR_DISMCYCINT_Pos         0U                                         /*!< ACTLR: DISMCYCINT Position */\n#define SCnSCB_ACTLR_DISMCYCINT_Msk        (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/)    /*!< ACTLR: DISMCYCINT Mask */\n#endif\n\n/*@} end of group CMSIS_SCnotSCB */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_SysTick     System Tick Timer (SysTick)\n  \\brief    Type definitions for the System Timer Registers.\n  @{\n */\n\n/**\n  \\brief  Structure type to access the System Timer (SysTick).\n */\ntypedef struct\n{\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */\n  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */\n  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */\n  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */\n} SysTick_Type;\n\n/* SysTick Control / Status Register Definitions */\n#define SysTick_CTRL_COUNTFLAG_Pos         16U                                            /*!< SysTick CTRL: COUNTFLAG Position */\n#define SysTick_CTRL_COUNTFLAG_Msk         (1UL << SysTick_CTRL_COUNTFLAG_Pos)            /*!< SysTick CTRL: COUNTFLAG Mask */\n\n#define SysTick_CTRL_CLKSOURCE_Pos          2U                                            /*!< SysTick CTRL: CLKSOURCE Position */\n#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)            /*!< SysTick CTRL: CLKSOURCE Mask */\n\n#define SysTick_CTRL_TICKINT_Pos            1U                                            /*!< SysTick CTRL: TICKINT Position */\n#define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos)              /*!< SysTick CTRL: TICKINT Mask */\n\n#define SysTick_CTRL_ENABLE_Pos             0U                                            /*!< SysTick CTRL: ENABLE Position */\n#define SysTick_CTRL_ENABLE_Msk            (1UL /*<< SysTick_CTRL_ENABLE_Pos*/)           /*!< SysTick CTRL: ENABLE Mask */\n\n/* SysTick Reload Register Definitions */\n#define SysTick_LOAD_RELOAD_Pos             0U                                            /*!< SysTick LOAD: RELOAD Position */\n#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/)    /*!< SysTick LOAD: RELOAD Mask */\n\n/* SysTick Current Register Definitions */\n#define SysTick_VAL_CURRENT_Pos             0U                                            /*!< SysTick VAL: CURRENT Position */\n#define SysTick_VAL_CURRENT_Msk            (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/)    /*!< SysTick VAL: CURRENT Mask */\n\n/* SysTick Calibration Register Definitions */\n#define SysTick_CALIB_NOREF_Pos            31U                                            /*!< SysTick CALIB: NOREF Position */\n#define SysTick_CALIB_NOREF_Msk            (1UL << SysTick_CALIB_NOREF_Pos)               /*!< SysTick CALIB: NOREF Mask */\n\n#define SysTick_CALIB_SKEW_Pos             30U                                            /*!< SysTick CALIB: SKEW Position */\n#define SysTick_CALIB_SKEW_Msk             (1UL << SysTick_CALIB_SKEW_Pos)                /*!< SysTick CALIB: SKEW Mask */\n\n#define SysTick_CALIB_TENMS_Pos             0U                                            /*!< SysTick CALIB: TENMS Position */\n#define SysTick_CALIB_TENMS_Msk            (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/)    /*!< SysTick CALIB: TENMS Mask */\n\n/*@} end of group CMSIS_SysTick */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_ITM     Instrumentation Trace Macrocell (ITM)\n  \\brief    Type definitions for the Instrumentation Trace Macrocell (ITM)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Instrumentation Trace Macrocell Register (ITM).\n */\ntypedef struct\n{\n  __OM  union\n  {\n    __OM  uint8_t    u8;                 /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 8-bit */\n    __OM  uint16_t   u16;                /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 16-bit */\n    __OM  uint32_t   u32;                /*!< Offset: 0x000 ( /W)  ITM Stimulus Port 32-bit */\n  }  PORT [32U];                         /*!< Offset: 0x000 ( /W)  ITM Stimulus Port Registers */\n        uint32_t RESERVED0[864U];\n  __IOM uint32_t TER;                    /*!< Offset: 0xE00 (R/W)  ITM Trace Enable Register */\n        uint32_t RESERVED1[15U];\n  __IOM uint32_t TPR;                    /*!< Offset: 0xE40 (R/W)  ITM Trace Privilege Register */\n        uint32_t RESERVED2[15U];\n  __IOM uint32_t TCR;                    /*!< Offset: 0xE80 (R/W)  ITM Trace Control Register */\n        uint32_t RESERVED3[32U];\n        uint32_t RESERVED4[43U];\n  __OM  uint32_t LAR;                    /*!< Offset: 0xFB0 ( /W)  ITM Lock Access Register */\n  __IM  uint32_t LSR;                    /*!< Offset: 0xFB4 (R/ )  ITM Lock Status Register */\n        uint32_t RESERVED5[6U];\n  __IM  uint32_t PID4;                   /*!< Offset: 0xFD0 (R/ )  ITM Peripheral Identification Register #4 */\n  __IM  uint32_t PID5;                   /*!< Offset: 0xFD4 (R/ )  ITM Peripheral Identification Register #5 */\n  __IM  uint32_t PID6;                   /*!< Offset: 0xFD8 (R/ )  ITM Peripheral Identification Register #6 */\n  __IM  uint32_t PID7;                   /*!< Offset: 0xFDC (R/ )  ITM Peripheral Identification Register #7 */\n  __IM  uint32_t PID0;                   /*!< Offset: 0xFE0 (R/ )  ITM Peripheral Identification Register #0 */\n  __IM  uint32_t PID1;                   /*!< Offset: 0xFE4 (R/ )  ITM Peripheral Identification Register #1 */\n  __IM  uint32_t PID2;                   /*!< Offset: 0xFE8 (R/ )  ITM Peripheral Identification Register #2 */\n  __IM  uint32_t PID3;                   /*!< Offset: 0xFEC (R/ )  ITM Peripheral Identification Register #3 */\n  __IM  uint32_t CID0;                   /*!< Offset: 0xFF0 (R/ )  ITM Component  Identification Register #0 */\n  __IM  uint32_t CID1;                   /*!< Offset: 0xFF4 (R/ )  ITM Component  Identification Register #1 */\n  __IM  uint32_t CID2;                   /*!< Offset: 0xFF8 (R/ )  ITM Component  Identification Register #2 */\n  __IM  uint32_t CID3;                   /*!< Offset: 0xFFC (R/ )  ITM Component  Identification Register #3 */\n} ITM_Type;\n\n/* ITM Trace Privilege Register Definitions */\n#define ITM_TPR_PRIVMASK_Pos                0U                                            /*!< ITM TPR: PRIVMASK Position */\n#define ITM_TPR_PRIVMASK_Msk               (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/)     /*!< ITM TPR: PRIVMASK Mask */\n\n/* ITM Trace Control Register Definitions */\n#define ITM_TCR_BUSY_Pos                   23U                                            /*!< ITM TCR: BUSY Position */\n#define ITM_TCR_BUSY_Msk                   (1UL << ITM_TCR_BUSY_Pos)                      /*!< ITM TCR: BUSY Mask */\n\n#define ITM_TCR_TraceBusID_Pos             16U                                            /*!< ITM TCR: ATBID Position */\n#define ITM_TCR_TraceBusID_Msk             (0x7FUL << ITM_TCR_TraceBusID_Pos)             /*!< ITM TCR: ATBID Mask */\n\n#define ITM_TCR_GTSFREQ_Pos                10U                                            /*!< ITM TCR: Global timestamp frequency Position */\n#define ITM_TCR_GTSFREQ_Msk                (3UL << ITM_TCR_GTSFREQ_Pos)                   /*!< ITM TCR: Global timestamp frequency Mask */\n\n#define ITM_TCR_TSPrescale_Pos              8U                                            /*!< ITM TCR: TSPrescale Position */\n#define ITM_TCR_TSPrescale_Msk             (3UL << ITM_TCR_TSPrescale_Pos)                /*!< ITM TCR: TSPrescale Mask */\n\n#define ITM_TCR_SWOENA_Pos                  4U                                            /*!< ITM TCR: SWOENA Position */\n#define ITM_TCR_SWOENA_Msk                 (1UL << ITM_TCR_SWOENA_Pos)                    /*!< ITM TCR: SWOENA Mask */\n\n#define ITM_TCR_DWTENA_Pos                  3U                                            /*!< ITM TCR: DWTENA Position */\n#define ITM_TCR_DWTENA_Msk                 (1UL << ITM_TCR_DWTENA_Pos)                    /*!< ITM TCR: DWTENA Mask */\n\n#define ITM_TCR_SYNCENA_Pos                 2U                                            /*!< ITM TCR: SYNCENA Position */\n#define ITM_TCR_SYNCENA_Msk                (1UL << ITM_TCR_SYNCENA_Pos)                   /*!< ITM TCR: SYNCENA Mask */\n\n#define ITM_TCR_TSENA_Pos                   1U                                            /*!< ITM TCR: TSENA Position */\n#define ITM_TCR_TSENA_Msk                  (1UL << ITM_TCR_TSENA_Pos)                     /*!< ITM TCR: TSENA Mask */\n\n#define ITM_TCR_ITMENA_Pos                  0U                                            /*!< ITM TCR: ITM Enable bit Position */\n#define ITM_TCR_ITMENA_Msk                 (1UL /*<< ITM_TCR_ITMENA_Pos*/)                /*!< ITM TCR: ITM Enable bit Mask */\n\n/* ITM Lock Status Register Definitions */\n#define ITM_LSR_ByteAcc_Pos                 2U                                            /*!< ITM LSR: ByteAcc Position */\n#define ITM_LSR_ByteAcc_Msk                (1UL << ITM_LSR_ByteAcc_Pos)                   /*!< ITM LSR: ByteAcc Mask */\n\n#define ITM_LSR_Access_Pos                  1U                                            /*!< ITM LSR: Access Position */\n#define ITM_LSR_Access_Msk                 (1UL << ITM_LSR_Access_Pos)                    /*!< ITM LSR: Access Mask */\n\n#define ITM_LSR_Present_Pos                 0U                                            /*!< ITM LSR: Present Position */\n#define ITM_LSR_Present_Msk                (1UL /*<< ITM_LSR_Present_Pos*/)               /*!< ITM LSR: Present Mask */\n\n/*@}*/ /* end of group CMSIS_ITM */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_DWT     Data Watchpoint and Trace (DWT)\n  \\brief    Type definitions for the Data Watchpoint and Trace (DWT)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Data Watchpoint and Trace Register (DWT).\n */\ntypedef struct\n{\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  Control Register */\n  __IOM uint32_t CYCCNT;                 /*!< Offset: 0x004 (R/W)  Cycle Count Register */\n  __IOM uint32_t CPICNT;                 /*!< Offset: 0x008 (R/W)  CPI Count Register */\n  __IOM uint32_t EXCCNT;                 /*!< Offset: 0x00C (R/W)  Exception Overhead Count Register */\n  __IOM uint32_t SLEEPCNT;               /*!< Offset: 0x010 (R/W)  Sleep Count Register */\n  __IOM uint32_t LSUCNT;                 /*!< Offset: 0x014 (R/W)  LSU Count Register */\n  __IOM uint32_t FOLDCNT;                /*!< Offset: 0x018 (R/W)  Folded-instruction Count Register */\n  __IM  uint32_t PCSR;                   /*!< Offset: 0x01C (R/ )  Program Counter Sample Register */\n  __IOM uint32_t COMP0;                  /*!< Offset: 0x020 (R/W)  Comparator Register 0 */\n  __IOM uint32_t MASK0;                  /*!< Offset: 0x024 (R/W)  Mask Register 0 */\n  __IOM uint32_t FUNCTION0;              /*!< Offset: 0x028 (R/W)  Function Register 0 */\n        uint32_t RESERVED0[1U];\n  __IOM uint32_t COMP1;                  /*!< Offset: 0x030 (R/W)  Comparator Register 1 */\n  __IOM uint32_t MASK1;                  /*!< Offset: 0x034 (R/W)  Mask Register 1 */\n  __IOM uint32_t FUNCTION1;              /*!< Offset: 0x038 (R/W)  Function Register 1 */\n        uint32_t RESERVED1[1U];\n  __IOM uint32_t COMP2;                  /*!< Offset: 0x040 (R/W)  Comparator Register 2 */\n  __IOM uint32_t MASK2;                  /*!< Offset: 0x044 (R/W)  Mask Register 2 */\n  __IOM uint32_t FUNCTION2;              /*!< Offset: 0x048 (R/W)  Function Register 2 */\n        uint32_t RESERVED2[1U];\n  __IOM uint32_t COMP3;                  /*!< Offset: 0x050 (R/W)  Comparator Register 3 */\n  __IOM uint32_t MASK3;                  /*!< Offset: 0x054 (R/W)  Mask Register 3 */\n  __IOM uint32_t FUNCTION3;              /*!< Offset: 0x058 (R/W)  Function Register 3 */\n} DWT_Type;\n\n/* DWT Control Register Definitions */\n#define DWT_CTRL_NUMCOMP_Pos               28U                                         /*!< DWT CTRL: NUMCOMP Position */\n#define DWT_CTRL_NUMCOMP_Msk               (0xFUL << DWT_CTRL_NUMCOMP_Pos)             /*!< DWT CTRL: NUMCOMP Mask */\n\n#define DWT_CTRL_NOTRCPKT_Pos              27U                                         /*!< DWT CTRL: NOTRCPKT Position */\n#define DWT_CTRL_NOTRCPKT_Msk              (0x1UL << DWT_CTRL_NOTRCPKT_Pos)            /*!< DWT CTRL: NOTRCPKT Mask */\n\n#define DWT_CTRL_NOEXTTRIG_Pos             26U                                         /*!< DWT CTRL: NOEXTTRIG Position */\n#define DWT_CTRL_NOEXTTRIG_Msk             (0x1UL << DWT_CTRL_NOEXTTRIG_Pos)           /*!< DWT CTRL: NOEXTTRIG Mask */\n\n#define DWT_CTRL_NOCYCCNT_Pos              25U                                         /*!< DWT CTRL: NOCYCCNT Position */\n#define DWT_CTRL_NOCYCCNT_Msk              (0x1UL << DWT_CTRL_NOCYCCNT_Pos)            /*!< DWT CTRL: NOCYCCNT Mask */\n\n#define DWT_CTRL_NOPRFCNT_Pos              24U                                         /*!< DWT CTRL: NOPRFCNT Position */\n#define DWT_CTRL_NOPRFCNT_Msk              (0x1UL << DWT_CTRL_NOPRFCNT_Pos)            /*!< DWT CTRL: NOPRFCNT Mask */\n\n#define DWT_CTRL_CYCEVTENA_Pos             22U                                         /*!< DWT CTRL: CYCEVTENA Position */\n#define DWT_CTRL_CYCEVTENA_Msk             (0x1UL << DWT_CTRL_CYCEVTENA_Pos)           /*!< DWT CTRL: CYCEVTENA Mask */\n\n#define DWT_CTRL_FOLDEVTENA_Pos            21U                                         /*!< DWT CTRL: FOLDEVTENA Position */\n#define DWT_CTRL_FOLDEVTENA_Msk            (0x1UL << DWT_CTRL_FOLDEVTENA_Pos)          /*!< DWT CTRL: FOLDEVTENA Mask */\n\n#define DWT_CTRL_LSUEVTENA_Pos             20U                                         /*!< DWT CTRL: LSUEVTENA Position */\n#define DWT_CTRL_LSUEVTENA_Msk             (0x1UL << DWT_CTRL_LSUEVTENA_Pos)           /*!< DWT CTRL: LSUEVTENA Mask */\n\n#define DWT_CTRL_SLEEPEVTENA_Pos           19U                                         /*!< DWT CTRL: SLEEPEVTENA Position */\n#define DWT_CTRL_SLEEPEVTENA_Msk           (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos)         /*!< DWT CTRL: SLEEPEVTENA Mask */\n\n#define DWT_CTRL_EXCEVTENA_Pos             18U                                         /*!< DWT CTRL: EXCEVTENA Position */\n#define DWT_CTRL_EXCEVTENA_Msk             (0x1UL << DWT_CTRL_EXCEVTENA_Pos)           /*!< DWT CTRL: EXCEVTENA Mask */\n\n#define DWT_CTRL_CPIEVTENA_Pos             17U                                         /*!< DWT CTRL: CPIEVTENA Position */\n#define DWT_CTRL_CPIEVTENA_Msk             (0x1UL << DWT_CTRL_CPIEVTENA_Pos)           /*!< DWT CTRL: CPIEVTENA Mask */\n\n#define DWT_CTRL_EXCTRCENA_Pos             16U                                         /*!< DWT CTRL: EXCTRCENA Position */\n#define DWT_CTRL_EXCTRCENA_Msk             (0x1UL << DWT_CTRL_EXCTRCENA_Pos)           /*!< DWT CTRL: EXCTRCENA Mask */\n\n#define DWT_CTRL_PCSAMPLENA_Pos            12U                                         /*!< DWT CTRL: PCSAMPLENA Position */\n#define DWT_CTRL_PCSAMPLENA_Msk            (0x1UL << DWT_CTRL_PCSAMPLENA_Pos)          /*!< DWT CTRL: PCSAMPLENA Mask */\n\n#define DWT_CTRL_SYNCTAP_Pos               10U                                         /*!< DWT CTRL: SYNCTAP Position */\n#define DWT_CTRL_SYNCTAP_Msk               (0x3UL << DWT_CTRL_SYNCTAP_Pos)             /*!< DWT CTRL: SYNCTAP Mask */\n\n#define DWT_CTRL_CYCTAP_Pos                 9U                                         /*!< DWT CTRL: CYCTAP Position */\n#define DWT_CTRL_CYCTAP_Msk                (0x1UL << DWT_CTRL_CYCTAP_Pos)              /*!< DWT CTRL: CYCTAP Mask */\n\n#define DWT_CTRL_POSTINIT_Pos               5U                                         /*!< DWT CTRL: POSTINIT Position */\n#define DWT_CTRL_POSTINIT_Msk              (0xFUL << DWT_CTRL_POSTINIT_Pos)            /*!< DWT CTRL: POSTINIT Mask */\n\n#define DWT_CTRL_POSTPRESET_Pos             1U                                         /*!< DWT CTRL: POSTPRESET Position */\n#define DWT_CTRL_POSTPRESET_Msk            (0xFUL << DWT_CTRL_POSTPRESET_Pos)          /*!< DWT CTRL: POSTPRESET Mask */\n\n#define DWT_CTRL_CYCCNTENA_Pos              0U                                         /*!< DWT CTRL: CYCCNTENA Position */\n#define DWT_CTRL_CYCCNTENA_Msk             (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/)       /*!< DWT CTRL: CYCCNTENA Mask */\n\n/* DWT CPI Count Register Definitions */\n#define DWT_CPICNT_CPICNT_Pos               0U                                         /*!< DWT CPICNT: CPICNT Position */\n#define DWT_CPICNT_CPICNT_Msk              (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/)       /*!< DWT CPICNT: CPICNT Mask */\n\n/* DWT Exception Overhead Count Register Definitions */\n#define DWT_EXCCNT_EXCCNT_Pos               0U                                         /*!< DWT EXCCNT: EXCCNT Position */\n#define DWT_EXCCNT_EXCCNT_Msk              (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/)       /*!< DWT EXCCNT: EXCCNT Mask */\n\n/* DWT Sleep Count Register Definitions */\n#define DWT_SLEEPCNT_SLEEPCNT_Pos           0U                                         /*!< DWT SLEEPCNT: SLEEPCNT Position */\n#define DWT_SLEEPCNT_SLEEPCNT_Msk          (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/)   /*!< DWT SLEEPCNT: SLEEPCNT Mask */\n\n/* DWT LSU Count Register Definitions */\n#define DWT_LSUCNT_LSUCNT_Pos               0U                                         /*!< DWT LSUCNT: LSUCNT Position */\n#define DWT_LSUCNT_LSUCNT_Msk              (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/)       /*!< DWT LSUCNT: LSUCNT Mask */\n\n/* DWT Folded-instruction Count Register Definitions */\n#define DWT_FOLDCNT_FOLDCNT_Pos             0U                                         /*!< DWT FOLDCNT: FOLDCNT Position */\n#define DWT_FOLDCNT_FOLDCNT_Msk            (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/)     /*!< DWT FOLDCNT: FOLDCNT Mask */\n\n/* DWT Comparator Mask Register Definitions */\n#define DWT_MASK_MASK_Pos                   0U                                         /*!< DWT MASK: MASK Position */\n#define DWT_MASK_MASK_Msk                  (0x1FUL /*<< DWT_MASK_MASK_Pos*/)           /*!< DWT MASK: MASK Mask */\n\n/* DWT Comparator Function Register Definitions */\n#define DWT_FUNCTION_MATCHED_Pos           24U                                         /*!< DWT FUNCTION: MATCHED Position */\n#define DWT_FUNCTION_MATCHED_Msk           (0x1UL << DWT_FUNCTION_MATCHED_Pos)         /*!< DWT FUNCTION: MATCHED Mask */\n\n#define DWT_FUNCTION_DATAVADDR1_Pos        16U                                         /*!< DWT FUNCTION: DATAVADDR1 Position */\n#define DWT_FUNCTION_DATAVADDR1_Msk        (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos)      /*!< DWT FUNCTION: DATAVADDR1 Mask */\n\n#define DWT_FUNCTION_DATAVADDR0_Pos        12U                                         /*!< DWT FUNCTION: DATAVADDR0 Position */\n#define DWT_FUNCTION_DATAVADDR0_Msk        (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos)      /*!< DWT FUNCTION: DATAVADDR0 Mask */\n\n#define DWT_FUNCTION_DATAVSIZE_Pos         10U                                         /*!< DWT FUNCTION: DATAVSIZE Position */\n#define DWT_FUNCTION_DATAVSIZE_Msk         (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos)       /*!< DWT FUNCTION: DATAVSIZE Mask */\n\n#define DWT_FUNCTION_LNK1ENA_Pos            9U                                         /*!< DWT FUNCTION: LNK1ENA Position */\n#define DWT_FUNCTION_LNK1ENA_Msk           (0x1UL << DWT_FUNCTION_LNK1ENA_Pos)         /*!< DWT FUNCTION: LNK1ENA Mask */\n\n#define DWT_FUNCTION_DATAVMATCH_Pos         8U                                         /*!< DWT FUNCTION: DATAVMATCH Position */\n#define DWT_FUNCTION_DATAVMATCH_Msk        (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos)      /*!< DWT FUNCTION: DATAVMATCH Mask */\n\n#define DWT_FUNCTION_CYCMATCH_Pos           7U                                         /*!< DWT FUNCTION: CYCMATCH Position */\n#define DWT_FUNCTION_CYCMATCH_Msk          (0x1UL << DWT_FUNCTION_CYCMATCH_Pos)        /*!< DWT FUNCTION: CYCMATCH Mask */\n\n#define DWT_FUNCTION_EMITRANGE_Pos          5U                                         /*!< DWT FUNCTION: EMITRANGE Position */\n#define DWT_FUNCTION_EMITRANGE_Msk         (0x1UL << DWT_FUNCTION_EMITRANGE_Pos)       /*!< DWT FUNCTION: EMITRANGE Mask */\n\n#define DWT_FUNCTION_FUNCTION_Pos           0U                                         /*!< DWT FUNCTION: FUNCTION Position */\n#define DWT_FUNCTION_FUNCTION_Msk          (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/)    /*!< DWT FUNCTION: FUNCTION Mask */\n\n/*@}*/ /* end of group CMSIS_DWT */\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_TPI     Trace Port Interface (TPI)\n  \\brief    Type definitions for the Trace Port Interface (TPI)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Trace Port Interface Register (TPI).\n */\ntypedef struct\n{\n  __IM  uint32_t SSPSR;                  /*!< Offset: 0x000 (R/ )  Supported Parallel Port Size Register */\n  __IOM uint32_t CSPSR;                  /*!< Offset: 0x004 (R/W)  Current Parallel Port Size Register */\n        uint32_t RESERVED0[2U];\n  __IOM uint32_t ACPR;                   /*!< Offset: 0x010 (R/W)  Asynchronous Clock Prescaler Register */\n        uint32_t RESERVED1[55U];\n  __IOM uint32_t SPPR;                   /*!< Offset: 0x0F0 (R/W)  Selected Pin Protocol Register */\n        uint32_t RESERVED2[131U];\n  __IM  uint32_t FFSR;                   /*!< Offset: 0x300 (R/ )  Formatter and Flush Status Register */\n  __IOM uint32_t FFCR;                   /*!< Offset: 0x304 (R/W)  Formatter and Flush Control Register */\n  __IM  uint32_t FSCR;                   /*!< Offset: 0x308 (R/ )  Formatter Synchronization Counter Register */\n        uint32_t RESERVED3[759U];\n  __IM  uint32_t TRIGGER;                /*!< Offset: 0xEE8 (R/ )  TRIGGER Register */\n  __IM  uint32_t FIFO0;                  /*!< Offset: 0xEEC (R/ )  Integration ETM Data */\n  __IM  uint32_t ITATBCTR2;              /*!< Offset: 0xEF0 (R/ )  ITATBCTR2 */\n        uint32_t RESERVED4[1U];\n  __IM  uint32_t ITATBCTR0;              /*!< Offset: 0xEF8 (R/ )  ITATBCTR0 */\n  __IM  uint32_t FIFO1;                  /*!< Offset: 0xEFC (R/ )  Integration ITM Data */\n  __IOM uint32_t ITCTRL;                 /*!< Offset: 0xF00 (R/W)  Integration Mode Control */\n        uint32_t RESERVED5[39U];\n  __IOM uint32_t CLAIMSET;               /*!< Offset: 0xFA0 (R/W)  Claim tag set */\n  __IOM uint32_t CLAIMCLR;               /*!< Offset: 0xFA4 (R/W)  Claim tag clear */\n        uint32_t RESERVED7[8U];\n  __IM  uint32_t DEVID;                  /*!< Offset: 0xFC8 (R/ )  TPIU_DEVID */\n  __IM  uint32_t DEVTYPE;                /*!< Offset: 0xFCC (R/ )  TPIU_DEVTYPE */\n} TPI_Type;\n\n/* TPI Asynchronous Clock Prescaler Register Definitions */\n#define TPI_ACPR_PRESCALER_Pos              0U                                         /*!< TPI ACPR: PRESCALER Position */\n#define TPI_ACPR_PRESCALER_Msk             (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/)    /*!< TPI ACPR: PRESCALER Mask */\n\n/* TPI Selected Pin Protocol Register Definitions */\n#define TPI_SPPR_TXMODE_Pos                 0U                                         /*!< TPI SPPR: TXMODE Position */\n#define TPI_SPPR_TXMODE_Msk                (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/)          /*!< TPI SPPR: TXMODE Mask */\n\n/* TPI Formatter and Flush Status Register Definitions */\n#define TPI_FFSR_FtNonStop_Pos              3U                                         /*!< TPI FFSR: FtNonStop Position */\n#define TPI_FFSR_FtNonStop_Msk             (0x1UL << TPI_FFSR_FtNonStop_Pos)           /*!< TPI FFSR: FtNonStop Mask */\n\n#define TPI_FFSR_TCPresent_Pos              2U                                         /*!< TPI FFSR: TCPresent Position */\n#define TPI_FFSR_TCPresent_Msk             (0x1UL << TPI_FFSR_TCPresent_Pos)           /*!< TPI FFSR: TCPresent Mask */\n\n#define TPI_FFSR_FtStopped_Pos              1U                                         /*!< TPI FFSR: FtStopped Position */\n#define TPI_FFSR_FtStopped_Msk             (0x1UL << TPI_FFSR_FtStopped_Pos)           /*!< TPI FFSR: FtStopped Mask */\n\n#define TPI_FFSR_FlInProg_Pos               0U                                         /*!< TPI FFSR: FlInProg Position */\n#define TPI_FFSR_FlInProg_Msk              (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/)        /*!< TPI FFSR: FlInProg Mask */\n\n/* TPI Formatter and Flush Control Register Definitions */\n#define TPI_FFCR_TrigIn_Pos                 8U                                         /*!< TPI FFCR: TrigIn Position */\n#define TPI_FFCR_TrigIn_Msk                (0x1UL << TPI_FFCR_TrigIn_Pos)              /*!< TPI FFCR: TrigIn Mask */\n\n#define TPI_FFCR_EnFCont_Pos                1U                                         /*!< TPI FFCR: EnFCont Position */\n#define TPI_FFCR_EnFCont_Msk               (0x1UL << TPI_FFCR_EnFCont_Pos)             /*!< TPI FFCR: EnFCont Mask */\n\n/* TPI TRIGGER Register Definitions */\n#define TPI_TRIGGER_TRIGGER_Pos             0U                                         /*!< TPI TRIGGER: TRIGGER Position */\n#define TPI_TRIGGER_TRIGGER_Msk            (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/)      /*!< TPI TRIGGER: TRIGGER Mask */\n\n/* TPI Integration ETM Data Register Definitions (FIFO0) */\n#define TPI_FIFO0_ITM_ATVALID_Pos          29U                                         /*!< TPI FIFO0: ITM_ATVALID Position */\n#define TPI_FIFO0_ITM_ATVALID_Msk          (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos)        /*!< TPI FIFO0: ITM_ATVALID Mask */\n\n#define TPI_FIFO0_ITM_bytecount_Pos        27U                                         /*!< TPI FIFO0: ITM_bytecount Position */\n#define TPI_FIFO0_ITM_bytecount_Msk        (0x3UL << TPI_FIFO0_ITM_bytecount_Pos)      /*!< TPI FIFO0: ITM_bytecount Mask */\n\n#define TPI_FIFO0_ETM_ATVALID_Pos          26U                                         /*!< TPI FIFO0: ETM_ATVALID Position */\n#define TPI_FIFO0_ETM_ATVALID_Msk          (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos)        /*!< TPI FIFO0: ETM_ATVALID Mask */\n\n#define TPI_FIFO0_ETM_bytecount_Pos        24U                                         /*!< TPI FIFO0: ETM_bytecount Position */\n#define TPI_FIFO0_ETM_bytecount_Msk        (0x3UL << TPI_FIFO0_ETM_bytecount_Pos)      /*!< TPI FIFO0: ETM_bytecount Mask */\n\n#define TPI_FIFO0_ETM2_Pos                 16U                                         /*!< TPI FIFO0: ETM2 Position */\n#define TPI_FIFO0_ETM2_Msk                 (0xFFUL << TPI_FIFO0_ETM2_Pos)              /*!< TPI FIFO0: ETM2 Mask */\n\n#define TPI_FIFO0_ETM1_Pos                  8U                                         /*!< TPI FIFO0: ETM1 Position */\n#define TPI_FIFO0_ETM1_Msk                 (0xFFUL << TPI_FIFO0_ETM1_Pos)              /*!< TPI FIFO0: ETM1 Mask */\n\n#define TPI_FIFO0_ETM0_Pos                  0U                                         /*!< TPI FIFO0: ETM0 Position */\n#define TPI_FIFO0_ETM0_Msk                 (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/)          /*!< TPI FIFO0: ETM0 Mask */\n\n/* TPI ITATBCTR2 Register Definitions */\n#define TPI_ITATBCTR2_ATREADY2_Pos          0U                                         /*!< TPI ITATBCTR2: ATREADY2 Position */\n#define TPI_ITATBCTR2_ATREADY2_Msk         (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/)   /*!< TPI ITATBCTR2: ATREADY2 Mask */\n\n#define TPI_ITATBCTR2_ATREADY1_Pos          0U                                         /*!< TPI ITATBCTR2: ATREADY1 Position */\n#define TPI_ITATBCTR2_ATREADY1_Msk         (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/)   /*!< TPI ITATBCTR2: ATREADY1 Mask */\n\n/* TPI Integration ITM Data Register Definitions (FIFO1) */\n#define TPI_FIFO1_ITM_ATVALID_Pos          29U                                         /*!< TPI FIFO1: ITM_ATVALID Position */\n#define TPI_FIFO1_ITM_ATVALID_Msk          (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos)        /*!< TPI FIFO1: ITM_ATVALID Mask */\n\n#define TPI_FIFO1_ITM_bytecount_Pos        27U                                         /*!< TPI FIFO1: ITM_bytecount Position */\n#define TPI_FIFO1_ITM_bytecount_Msk        (0x3UL << TPI_FIFO1_ITM_bytecount_Pos)      /*!< TPI FIFO1: ITM_bytecount Mask */\n\n#define TPI_FIFO1_ETM_ATVALID_Pos          26U                                         /*!< TPI FIFO1: ETM_ATVALID Position */\n#define TPI_FIFO1_ETM_ATVALID_Msk          (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos)        /*!< TPI FIFO1: ETM_ATVALID Mask */\n\n#define TPI_FIFO1_ETM_bytecount_Pos        24U                                         /*!< TPI FIFO1: ETM_bytecount Position */\n#define TPI_FIFO1_ETM_bytecount_Msk        (0x3UL << TPI_FIFO1_ETM_bytecount_Pos)      /*!< TPI FIFO1: ETM_bytecount Mask */\n\n#define TPI_FIFO1_ITM2_Pos                 16U                                         /*!< TPI FIFO1: ITM2 Position */\n#define TPI_FIFO1_ITM2_Msk                 (0xFFUL << TPI_FIFO1_ITM2_Pos)              /*!< TPI FIFO1: ITM2 Mask */\n\n#define TPI_FIFO1_ITM1_Pos                  8U                                         /*!< TPI FIFO1: ITM1 Position */\n#define TPI_FIFO1_ITM1_Msk                 (0xFFUL << TPI_FIFO1_ITM1_Pos)              /*!< TPI FIFO1: ITM1 Mask */\n\n#define TPI_FIFO1_ITM0_Pos                  0U                                         /*!< TPI FIFO1: ITM0 Position */\n#define TPI_FIFO1_ITM0_Msk                 (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/)          /*!< TPI FIFO1: ITM0 Mask */\n\n/* TPI ITATBCTR0 Register Definitions */\n#define TPI_ITATBCTR0_ATREADY2_Pos          0U                                         /*!< TPI ITATBCTR0: ATREADY2 Position */\n#define TPI_ITATBCTR0_ATREADY2_Msk         (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/)   /*!< TPI ITATBCTR0: ATREADY2 Mask */\n\n#define TPI_ITATBCTR0_ATREADY1_Pos          0U                                         /*!< TPI ITATBCTR0: ATREADY1 Position */\n#define TPI_ITATBCTR0_ATREADY1_Msk         (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/)   /*!< TPI ITATBCTR0: ATREADY1 Mask */\n\n/* TPI Integration Mode Control Register Definitions */\n#define TPI_ITCTRL_Mode_Pos                 0U                                         /*!< TPI ITCTRL: Mode Position */\n#define TPI_ITCTRL_Mode_Msk                (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/)          /*!< TPI ITCTRL: Mode Mask */\n\n/* TPI DEVID Register Definitions */\n#define TPI_DEVID_NRZVALID_Pos             11U                                         /*!< TPI DEVID: NRZVALID Position */\n#define TPI_DEVID_NRZVALID_Msk             (0x1UL << TPI_DEVID_NRZVALID_Pos)           /*!< TPI DEVID: NRZVALID Mask */\n\n#define TPI_DEVID_MANCVALID_Pos            10U                                         /*!< TPI DEVID: MANCVALID Position */\n#define TPI_DEVID_MANCVALID_Msk            (0x1UL << TPI_DEVID_MANCVALID_Pos)          /*!< TPI DEVID: MANCVALID Mask */\n\n#define TPI_DEVID_PTINVALID_Pos             9U                                         /*!< TPI DEVID: PTINVALID Position */\n#define TPI_DEVID_PTINVALID_Msk            (0x1UL << TPI_DEVID_PTINVALID_Pos)          /*!< TPI DEVID: PTINVALID Mask */\n\n#define TPI_DEVID_MinBufSz_Pos              6U                                         /*!< TPI DEVID: MinBufSz Position */\n#define TPI_DEVID_MinBufSz_Msk             (0x7UL << TPI_DEVID_MinBufSz_Pos)           /*!< TPI DEVID: MinBufSz Mask */\n\n#define TPI_DEVID_AsynClkIn_Pos             5U                                         /*!< TPI DEVID: AsynClkIn Position */\n#define TPI_DEVID_AsynClkIn_Msk            (0x1UL << TPI_DEVID_AsynClkIn_Pos)          /*!< TPI DEVID: AsynClkIn Mask */\n\n#define TPI_DEVID_NrTraceInput_Pos          0U                                         /*!< TPI DEVID: NrTraceInput Position */\n#define TPI_DEVID_NrTraceInput_Msk         (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/)  /*!< TPI DEVID: NrTraceInput Mask */\n\n/* TPI DEVTYPE Register Definitions */\n#define TPI_DEVTYPE_SubType_Pos             4U                                         /*!< TPI DEVTYPE: SubType Position */\n#define TPI_DEVTYPE_SubType_Msk            (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/)      /*!< TPI DEVTYPE: SubType Mask */\n\n#define TPI_DEVTYPE_MajorType_Pos           0U                                         /*!< TPI DEVTYPE: MajorType Position */\n#define TPI_DEVTYPE_MajorType_Msk          (0xFUL << TPI_DEVTYPE_MajorType_Pos)        /*!< TPI DEVTYPE: MajorType Mask */\n\n/*@}*/ /* end of group CMSIS_TPI */\n\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_MPU     Memory Protection Unit (MPU)\n  \\brief    Type definitions for the Memory Protection Unit (MPU)\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Memory Protection Unit (MPU).\n */\ntypedef struct\n{\n  __IM  uint32_t TYPE;                   /*!< Offset: 0x000 (R/ )  MPU Type Register */\n  __IOM uint32_t CTRL;                   /*!< Offset: 0x004 (R/W)  MPU Control Register */\n  __IOM uint32_t RNR;                    /*!< Offset: 0x008 (R/W)  MPU Region RNRber Register */\n  __IOM uint32_t RBAR;                   /*!< Offset: 0x00C (R/W)  MPU Region Base Address Register */\n  __IOM uint32_t RASR;                   /*!< Offset: 0x010 (R/W)  MPU Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A1;                /*!< Offset: 0x014 (R/W)  MPU Alias 1 Region Base Address Register */\n  __IOM uint32_t RASR_A1;                /*!< Offset: 0x018 (R/W)  MPU Alias 1 Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A2;                /*!< Offset: 0x01C (R/W)  MPU Alias 2 Region Base Address Register */\n  __IOM uint32_t RASR_A2;                /*!< Offset: 0x020 (R/W)  MPU Alias 2 Region Attribute and Size Register */\n  __IOM uint32_t RBAR_A3;                /*!< Offset: 0x024 (R/W)  MPU Alias 3 Region Base Address Register */\n  __IOM uint32_t RASR_A3;                /*!< Offset: 0x028 (R/W)  MPU Alias 3 Region Attribute and Size Register */\n} MPU_Type;\n\n#define MPU_TYPE_RALIASES                  4U\n\n/* MPU Type Register Definitions */\n#define MPU_TYPE_IREGION_Pos               16U                                            /*!< MPU TYPE: IREGION Position */\n#define MPU_TYPE_IREGION_Msk               (0xFFUL << MPU_TYPE_IREGION_Pos)               /*!< MPU TYPE: IREGION Mask */\n\n#define MPU_TYPE_DREGION_Pos                8U                                            /*!< MPU TYPE: DREGION Position */\n#define MPU_TYPE_DREGION_Msk               (0xFFUL << MPU_TYPE_DREGION_Pos)               /*!< MPU TYPE: DREGION Mask */\n\n#define MPU_TYPE_SEPARATE_Pos               0U                                            /*!< MPU TYPE: SEPARATE Position */\n#define MPU_TYPE_SEPARATE_Msk              (1UL /*<< MPU_TYPE_SEPARATE_Pos*/)             /*!< MPU TYPE: SEPARATE Mask */\n\n/* MPU Control Register Definitions */\n#define MPU_CTRL_PRIVDEFENA_Pos             2U                                            /*!< MPU CTRL: PRIVDEFENA Position */\n#define MPU_CTRL_PRIVDEFENA_Msk            (1UL << MPU_CTRL_PRIVDEFENA_Pos)               /*!< MPU CTRL: PRIVDEFENA Mask */\n\n#define MPU_CTRL_HFNMIENA_Pos               1U                                            /*!< MPU CTRL: HFNMIENA Position */\n#define MPU_CTRL_HFNMIENA_Msk              (1UL << MPU_CTRL_HFNMIENA_Pos)                 /*!< MPU CTRL: HFNMIENA Mask */\n\n#define MPU_CTRL_ENABLE_Pos                 0U                                            /*!< MPU CTRL: ENABLE Position */\n#define MPU_CTRL_ENABLE_Msk                (1UL /*<< MPU_CTRL_ENABLE_Pos*/)               /*!< MPU CTRL: ENABLE Mask */\n\n/* MPU Region Number Register Definitions */\n#define MPU_RNR_REGION_Pos                  0U                                            /*!< MPU RNR: REGION Position */\n#define MPU_RNR_REGION_Msk                 (0xFFUL /*<< MPU_RNR_REGION_Pos*/)             /*!< MPU RNR: REGION Mask */\n\n/* MPU Region Base Address Register Definitions */\n#define MPU_RBAR_ADDR_Pos                   5U                                            /*!< MPU RBAR: ADDR Position */\n#define MPU_RBAR_ADDR_Msk                  (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos)             /*!< MPU RBAR: ADDR Mask */\n\n#define MPU_RBAR_VALID_Pos                  4U                                            /*!< MPU RBAR: VALID Position */\n#define MPU_RBAR_VALID_Msk                 (1UL << MPU_RBAR_VALID_Pos)                    /*!< MPU RBAR: VALID Mask */\n\n#define MPU_RBAR_REGION_Pos                 0U                                            /*!< MPU RBAR: REGION Position */\n#define MPU_RBAR_REGION_Msk                (0xFUL /*<< MPU_RBAR_REGION_Pos*/)             /*!< MPU RBAR: REGION Mask */\n\n/* MPU Region Attribute and Size Register Definitions */\n#define MPU_RASR_ATTRS_Pos                 16U                                            /*!< MPU RASR: MPU Region Attribute field Position */\n#define MPU_RASR_ATTRS_Msk                 (0xFFFFUL << MPU_RASR_ATTRS_Pos)               /*!< MPU RASR: MPU Region Attribute field Mask */\n\n#define MPU_RASR_XN_Pos                    28U                                            /*!< MPU RASR: ATTRS.XN Position */\n#define MPU_RASR_XN_Msk                    (1UL << MPU_RASR_XN_Pos)                       /*!< MPU RASR: ATTRS.XN Mask */\n\n#define MPU_RASR_AP_Pos                    24U                                            /*!< MPU RASR: ATTRS.AP Position */\n#define MPU_RASR_AP_Msk                    (0x7UL << MPU_RASR_AP_Pos)                     /*!< MPU RASR: ATTRS.AP Mask */\n\n#define MPU_RASR_TEX_Pos                   19U                                            /*!< MPU RASR: ATTRS.TEX Position */\n#define MPU_RASR_TEX_Msk                   (0x7UL << MPU_RASR_TEX_Pos)                    /*!< MPU RASR: ATTRS.TEX Mask */\n\n#define MPU_RASR_S_Pos                     18U                                            /*!< MPU RASR: ATTRS.S Position */\n#define MPU_RASR_S_Msk                     (1UL << MPU_RASR_S_Pos)                        /*!< MPU RASR: ATTRS.S Mask */\n\n#define MPU_RASR_C_Pos                     17U                                            /*!< MPU RASR: ATTRS.C Position */\n#define MPU_RASR_C_Msk                     (1UL << MPU_RASR_C_Pos)                        /*!< MPU RASR: ATTRS.C Mask */\n\n#define MPU_RASR_B_Pos                     16U                                            /*!< MPU RASR: ATTRS.B Position */\n#define MPU_RASR_B_Msk                     (1UL << MPU_RASR_B_Pos)                        /*!< MPU RASR: ATTRS.B Mask */\n\n#define MPU_RASR_SRD_Pos                    8U                                            /*!< MPU RASR: Sub-Region Disable Position */\n#define MPU_RASR_SRD_Msk                   (0xFFUL << MPU_RASR_SRD_Pos)                   /*!< MPU RASR: Sub-Region Disable Mask */\n\n#define MPU_RASR_SIZE_Pos                   1U                                            /*!< MPU RASR: Region Size Field Position */\n#define MPU_RASR_SIZE_Msk                  (0x1FUL << MPU_RASR_SIZE_Pos)                  /*!< MPU RASR: Region Size Field Mask */\n\n#define MPU_RASR_ENABLE_Pos                 0U                                            /*!< MPU RASR: Region enable bit Position */\n#define MPU_RASR_ENABLE_Msk                (1UL /*<< MPU_RASR_ENABLE_Pos*/)               /*!< MPU RASR: Region enable bit Disable Mask */\n\n/*@} end of group CMSIS_MPU */\n#endif\n\n\n/**\n  \\ingroup  CMSIS_core_register\n  \\defgroup CMSIS_CoreDebug       Core Debug Registers (CoreDebug)\n  \\brief    Type definitions for the Core Debug Registers\n  @{\n */\n\n/**\n  \\brief  Structure type to access the Core Debug Register (CoreDebug).\n */\ntypedef struct\n{\n  __IOM uint32_t DHCSR;                  /*!< Offset: 0x000 (R/W)  Debug Halting Control and Status Register */\n  __OM  uint32_t DCRSR;                  /*!< Offset: 0x004 ( /W)  Debug Core Register Selector Register */\n  __IOM uint32_t DCRDR;                  /*!< Offset: 0x008 (R/W)  Debug Core Register Data Register */\n  __IOM uint32_t DEMCR;                  /*!< Offset: 0x00C (R/W)  Debug Exception and Monitor Control Register */\n} CoreDebug_Type;\n\n/* Debug Halting Control and Status Register Definitions */\n#define CoreDebug_DHCSR_DBGKEY_Pos         16U                                            /*!< CoreDebug DHCSR: DBGKEY Position */\n#define CoreDebug_DHCSR_DBGKEY_Msk         (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos)       /*!< CoreDebug DHCSR: DBGKEY Mask */\n\n#define CoreDebug_DHCSR_S_RESET_ST_Pos     25U                                            /*!< CoreDebug DHCSR: S_RESET_ST Position */\n#define CoreDebug_DHCSR_S_RESET_ST_Msk     (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos)        /*!< CoreDebug DHCSR: S_RESET_ST Mask */\n\n#define CoreDebug_DHCSR_S_RETIRE_ST_Pos    24U                                            /*!< CoreDebug DHCSR: S_RETIRE_ST Position */\n#define CoreDebug_DHCSR_S_RETIRE_ST_Msk    (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos)       /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */\n\n#define CoreDebug_DHCSR_S_LOCKUP_Pos       19U                                            /*!< CoreDebug DHCSR: S_LOCKUP Position */\n#define CoreDebug_DHCSR_S_LOCKUP_Msk       (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos)          /*!< CoreDebug DHCSR: S_LOCKUP Mask */\n\n#define CoreDebug_DHCSR_S_SLEEP_Pos        18U                                            /*!< CoreDebug DHCSR: S_SLEEP Position */\n#define CoreDebug_DHCSR_S_SLEEP_Msk        (1UL << CoreDebug_DHCSR_S_SLEEP_Pos)           /*!< CoreDebug DHCSR: S_SLEEP Mask */\n\n#define CoreDebug_DHCSR_S_HALT_Pos         17U                                            /*!< CoreDebug DHCSR: S_HALT Position */\n#define CoreDebug_DHCSR_S_HALT_Msk         (1UL << CoreDebug_DHCSR_S_HALT_Pos)            /*!< CoreDebug DHCSR: S_HALT Mask */\n\n#define CoreDebug_DHCSR_S_REGRDY_Pos       16U                                            /*!< CoreDebug DHCSR: S_REGRDY Position */\n#define CoreDebug_DHCSR_S_REGRDY_Msk       (1UL << CoreDebug_DHCSR_S_REGRDY_Pos)          /*!< CoreDebug DHCSR: S_REGRDY Mask */\n\n#define CoreDebug_DHCSR_C_SNAPSTALL_Pos     5U                                            /*!< CoreDebug DHCSR: C_SNAPSTALL Position */\n#define CoreDebug_DHCSR_C_SNAPSTALL_Msk    (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos)       /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */\n\n#define CoreDebug_DHCSR_C_MASKINTS_Pos      3U                                            /*!< CoreDebug DHCSR: C_MASKINTS Position */\n#define CoreDebug_DHCSR_C_MASKINTS_Msk     (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos)        /*!< CoreDebug DHCSR: C_MASKINTS Mask */\n\n#define CoreDebug_DHCSR_C_STEP_Pos          2U                                            /*!< CoreDebug DHCSR: C_STEP Position */\n#define CoreDebug_DHCSR_C_STEP_Msk         (1UL << CoreDebug_DHCSR_C_STEP_Pos)            /*!< CoreDebug DHCSR: C_STEP Mask */\n\n#define CoreDebug_DHCSR_C_HALT_Pos          1U                                            /*!< CoreDebug DHCSR: C_HALT Position */\n#define CoreDebug_DHCSR_C_HALT_Msk         (1UL << CoreDebug_DHCSR_C_HALT_Pos)            /*!< CoreDebug DHCSR: C_HALT Mask */\n\n#define CoreDebug_DHCSR_C_DEBUGEN_Pos       0U                                            /*!< CoreDebug DHCSR: C_DEBUGEN Position */\n#define CoreDebug_DHCSR_C_DEBUGEN_Msk      (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/)     /*!< CoreDebug DHCSR: C_DEBUGEN Mask */\n\n/* Debug Core Register Selector Register Definitions */\n#define CoreDebug_DCRSR_REGWnR_Pos         16U                                            /*!< CoreDebug DCRSR: REGWnR Position */\n#define CoreDebug_DCRSR_REGWnR_Msk         (1UL << CoreDebug_DCRSR_REGWnR_Pos)            /*!< CoreDebug DCRSR: REGWnR Mask */\n\n#define CoreDebug_DCRSR_REGSEL_Pos          0U                                            /*!< CoreDebug DCRSR: REGSEL Position */\n#define CoreDebug_DCRSR_REGSEL_Msk         (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/)     /*!< CoreDebug DCRSR: REGSEL Mask */\n\n/* Debug Exception and Monitor Control Register Definitions */\n#define CoreDebug_DEMCR_TRCENA_Pos         24U                                            /*!< CoreDebug DEMCR: TRCENA Position */\n#define CoreDebug_DEMCR_TRCENA_Msk         (1UL << CoreDebug_DEMCR_TRCENA_Pos)            /*!< CoreDebug DEMCR: TRCENA Mask */\n\n#define CoreDebug_DEMCR_MON_REQ_Pos        19U                                            /*!< CoreDebug DEMCR: MON_REQ Position */\n#define CoreDebug_DEMCR_MON_REQ_Msk        (1UL << CoreDebug_DEMCR_MON_REQ_Pos)           /*!< CoreDebug DEMCR: MON_REQ Mask */\n\n#define CoreDebug_DEMCR_MON_STEP_Pos       18U                                            /*!< CoreDebug DEMCR: MON_STEP Position */\n#define CoreDebug_DEMCR_MON_STEP_Msk       (1UL << CoreDebug_DEMCR_MON_STEP_Pos)          /*!< CoreDebug DEMCR: MON_STEP Mask */\n\n#define CoreDebug_DEMCR_MON_PEND_Pos       17U                                            /*!< CoreDebug DEMCR: MON_PEND Position */\n#define CoreDebug_DEMCR_MON_PEND_Msk       (1UL << CoreDebug_DEMCR_MON_PEND_Pos)          /*!< CoreDebug DEMCR: MON_PEND Mask */\n\n#define CoreDebug_DEMCR_MON_EN_Pos         16U                                            /*!< CoreDebug DEMCR: MON_EN Position */\n#define CoreDebug_DEMCR_MON_EN_Msk         (1UL << CoreDebug_DEMCR_MON_EN_Pos)            /*!< CoreDebug DEMCR: MON_EN Mask */\n\n#define CoreDebug_DEMCR_VC_HARDERR_Pos     10U                                            /*!< CoreDebug DEMCR: VC_HARDERR Position */\n#define CoreDebug_DEMCR_VC_HARDERR_Msk     (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos)        /*!< CoreDebug DEMCR: VC_HARDERR Mask */\n\n#define CoreDebug_DEMCR_VC_INTERR_Pos       9U                                            /*!< CoreDebug DEMCR: VC_INTERR Position */\n#define CoreDebug_DEMCR_VC_INTERR_Msk      (1UL << CoreDebug_DEMCR_VC_INTERR_Pos)         /*!< CoreDebug DEMCR: VC_INTERR Mask */\n\n#define CoreDebug_DEMCR_VC_BUSERR_Pos       8U                                            /*!< CoreDebug DEMCR: VC_BUSERR Position */\n#define CoreDebug_DEMCR_VC_BUSERR_Msk      (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos)         /*!< CoreDebug DEMCR: VC_BUSERR Mask */\n\n#define CoreDebug_DEMCR_VC_STATERR_Pos      7U                                            /*!< CoreDebug DEMCR: VC_STATERR Position */\n#define CoreDebug_DEMCR_VC_STATERR_Msk     (1UL << CoreDebug_DEMCR_VC_STATERR_Pos)        /*!< CoreDebug DEMCR: VC_STATERR Mask */\n\n#define CoreDebug_DEMCR_VC_CHKERR_Pos       6U                                            /*!< CoreDebug DEMCR: VC_CHKERR Position */\n#define CoreDebug_DEMCR_VC_CHKERR_Msk      (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos)         /*!< CoreDebug DEMCR: VC_CHKERR Mask */\n\n#define CoreDebug_DEMCR_VC_NOCPERR_Pos      5U                                            /*!< CoreDebug DEMCR: VC_NOCPERR Position */\n#define CoreDebug_DEMCR_VC_NOCPERR_Msk     (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos)        /*!< CoreDebug DEMCR: VC_NOCPERR Mask */\n\n#define CoreDebug_DEMCR_VC_MMERR_Pos        4U                                            /*!< CoreDebug DEMCR: VC_MMERR Position */\n#define CoreDebug_DEMCR_VC_MMERR_Msk       (1UL << CoreDebug_DEMCR_VC_MMERR_Pos)          /*!< CoreDebug DEMCR: VC_MMERR Mask */\n\n#define CoreDebug_DEMCR_VC_CORERESET_Pos    0U                                            /*!< CoreDebug DEMCR: VC_CORERESET Position */\n#define CoreDebug_DEMCR_VC_CORERESET_Msk   (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/)  /*!< CoreDebug DEMCR: VC_CORERESET Mask */\n\n/*@} end of group CMSIS_CoreDebug */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_core_bitfield     Core register bit field macros\n  \\brief      Macros for use with bit field definitions (xxx_Pos, xxx_Msk).\n  @{\n */\n\n/**\n  \\brief   Mask and shift a bit field value for use in a register bit range.\n  \\param[in] field  Name of the register bit field.\n  \\param[in] value  Value of the bit field. This parameter is interpreted as an uint32_t type.\n  \\return           Masked and shifted value.\n*/\n#define _VAL2FLD(field, value)    (((uint32_t)(value) << field ## _Pos) & field ## _Msk)\n\n/**\n  \\brief     Mask and shift a register value to extract a bit filed value.\n  \\param[in] field  Name of the register bit field.\n  \\param[in] value  Value of register. This parameter is interpreted as an uint32_t type.\n  \\return           Masked and shifted bit field value.\n*/\n#define _FLD2VAL(field, value)    (((uint32_t)(value) & field ## _Msk) >> field ## _Pos)\n\n/*@} end of group CMSIS_core_bitfield */\n\n\n/**\n  \\ingroup    CMSIS_core_register\n  \\defgroup   CMSIS_core_base     Core Definitions\n  \\brief      Definitions for base addresses, unions, and structures.\n  @{\n */\n\n/* Memory mapping of Core Hardware */\n#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */\n#define ITM_BASE            (0xE0000000UL)                            /*!< ITM Base Address */\n#define DWT_BASE            (0xE0001000UL)                            /*!< DWT Base Address */\n#define TPI_BASE            (0xE0040000UL)                            /*!< TPI Base Address */\n#define CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address */\n#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address */\n#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address */\n#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!< System Control Block Base Address */\n\n#define SCnSCB              ((SCnSCB_Type    *)     SCS_BASE      )   /*!< System control Register not in SCB */\n#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct */\n#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct */\n#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct */\n#define ITM                 ((ITM_Type       *)     ITM_BASE      )   /*!< ITM configuration struct */\n#define DWT                 ((DWT_Type       *)     DWT_BASE      )   /*!< DWT configuration struct */\n#define TPI                 ((TPI_Type       *)     TPI_BASE      )   /*!< TPI configuration struct */\n#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct */\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n  #define MPU_BASE          (SCS_BASE +  0x0D90UL)                    /*!< Memory Protection Unit */\n  #define MPU               ((MPU_Type       *)     MPU_BASE      )   /*!< Memory Protection Unit */\n#endif\n\n/*@} */\n\n\n\n/*******************************************************************************\n *                Hardware Abstraction Layer\n  Core Function Interface contains:\n  - Core NVIC Functions\n  - Core SysTick Functions\n  - Core Debug Functions\n  - Core Register Access Functions\n ******************************************************************************/\n/**\n  \\defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference\n*/\n\n\n\n/* ##########################   NVIC functions  #################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_NVICFunctions NVIC Functions\n  \\brief    Functions that manage interrupts and exceptions via the NVIC.\n  @{\n */\n\n#ifdef CMSIS_NVIC_VIRTUAL\n  #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE\n    #define CMSIS_NVIC_VIRTUAL_HEADER_FILE \"cmsis_nvic_virtual.h\"\n  #endif\n  #include CMSIS_NVIC_VIRTUAL_HEADER_FILE\n#else\n  #define NVIC_SetPriorityGrouping    __NVIC_SetPriorityGrouping\n  #define NVIC_GetPriorityGrouping    __NVIC_GetPriorityGrouping\n  #define NVIC_EnableIRQ              __NVIC_EnableIRQ\n  #define NVIC_GetEnableIRQ           __NVIC_GetEnableIRQ\n  #define NVIC_DisableIRQ             __NVIC_DisableIRQ\n  #define NVIC_GetPendingIRQ          __NVIC_GetPendingIRQ\n  #define NVIC_SetPendingIRQ          __NVIC_SetPendingIRQ\n  #define NVIC_ClearPendingIRQ        __NVIC_ClearPendingIRQ\n  #define NVIC_GetActive              __NVIC_GetActive\n  #define NVIC_SetPriority            __NVIC_SetPriority\n  #define NVIC_GetPriority            __NVIC_GetPriority\n  #define NVIC_SystemReset            __NVIC_SystemReset\n#endif /* CMSIS_NVIC_VIRTUAL */\n\n#ifdef CMSIS_VECTAB_VIRTUAL\n  #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE\n    #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE \"cmsis_vectab_virtual.h\"\n  #endif\n  #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE\n#else\n  #define NVIC_SetVector              __NVIC_SetVector\n  #define NVIC_GetVector              __NVIC_GetVector\n#endif  /* (CMSIS_VECTAB_VIRTUAL) */\n\n#define NVIC_USER_IRQ_OFFSET          16\n\n\n/* The following EXC_RETURN values are saved the LR on exception entry */\n#define EXC_RETURN_HANDLER         (0xFFFFFFF1UL)     /* return to Handler mode, uses MSP after return                               */\n#define EXC_RETURN_THREAD_MSP      (0xFFFFFFF9UL)     /* return to Thread mode, uses MSP after return                                */\n#define EXC_RETURN_THREAD_PSP      (0xFFFFFFFDUL)     /* return to Thread mode, uses PSP after return                                */\n\n\n/**\n  \\brief   Set Priority Grouping\n  \\details Sets the priority grouping field using the required unlock sequence.\n           The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field.\n           Only values from 0..7 are used.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.\n  \\param [in]      PriorityGroup  Priority grouping field.\n */\n__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup)\n{\n  uint32_t reg_value;\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);             /* only values 0..7 are used          */\n\n  reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */\n  reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change               */\n  reg_value  =  (reg_value                                   |\n                ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |\n                (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos)  );              /* Insert write key and priority group */\n  SCB->AIRCR =  reg_value;\n}\n\n\n/**\n  \\brief   Get Priority Grouping\n  \\details Reads the priority grouping field from the NVIC Interrupt Controller.\n  \\return                Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field).\n */\n__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void)\n{\n  return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos));\n}\n\n\n/**\n  \\brief   Enable Interrupt\n  \\details Enables a device specific interrupt in the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    __COMPILER_BARRIER();\n    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n    __COMPILER_BARRIER();\n  }\n}\n\n\n/**\n  \\brief   Get Interrupt Enable status\n  \\details Returns a device specific interrupt enable status from the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt is not enabled.\n  \\return             1  Interrupt is enabled.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Disable Interrupt\n  \\details Disables a device specific interrupt in the NVIC interrupt controller.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n    __DSB();\n    __ISB();\n  }\n}\n\n\n/**\n  \\brief   Get Pending Interrupt\n  \\details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt status is not pending.\n  \\return             1  Interrupt status is pending.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Set Pending Interrupt\n  \\details Sets the pending bit of a device specific interrupt in the NVIC pending register.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n  }\n}\n\n\n/**\n  \\brief   Clear Pending Interrupt\n  \\details Clears the pending bit of a device specific interrupt in the NVIC pending register.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));\n  }\n}\n\n\n/**\n  \\brief   Get Active Interrupt\n  \\details Reads the active register in the NVIC and returns the active bit for the device specific interrupt.\n  \\param [in]      IRQn  Device specific interrupt number.\n  \\return             0  Interrupt status is not active.\n  \\return             1  Interrupt status is active.\n  \\note    IRQn must not be negative.\n */\n__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));\n  }\n  else\n  {\n    return(0U);\n  }\n}\n\n\n/**\n  \\brief   Set Interrupt Priority\n  \\details Sets the priority of a device specific interrupt or a processor exception.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]      IRQn  Interrupt number.\n  \\param [in]  priority  Priority to set.\n  \\note    The priority cannot be set for every processor exception.\n */\n__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)\n{\n  if ((int32_t)(IRQn) >= 0)\n  {\n    NVIC->IP[((uint32_t)IRQn)]               = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);\n  }\n  else\n  {\n    SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);\n  }\n}\n\n\n/**\n  \\brief   Get Interrupt Priority\n  \\details Reads the priority of a device specific interrupt or a processor exception.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]   IRQn  Interrupt number.\n  \\return             Interrupt Priority.\n                      Value is aligned automatically to the implemented priority bits of the microcontroller.\n */\n__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn)\n{\n\n  if ((int32_t)(IRQn) >= 0)\n  {\n    return(((uint32_t)NVIC->IP[((uint32_t)IRQn)]               >> (8U - __NVIC_PRIO_BITS)));\n  }\n  else\n  {\n    return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS)));\n  }\n}\n\n\n/**\n  \\brief   Encode Priority\n  \\details Encodes the priority for an interrupt with the given priority group,\n           preemptive priority value, and subpriority value.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.\n  \\param [in]     PriorityGroup  Used priority group.\n  \\param [in]   PreemptPriority  Preemptive priority value (starting from 0).\n  \\param [in]       SubPriority  Subpriority value (starting from 0).\n  \\return                        Encoded priority. Value can be used in the function \\ref NVIC_SetPriority().\n */\n__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)\n{\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);   /* only values 0..7 are used          */\n  uint32_t PreemptPriorityBits;\n  uint32_t SubPriorityBits;\n\n  PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);\n  SubPriorityBits     = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));\n\n  return (\n           ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) |\n           ((SubPriority     & (uint32_t)((1UL << (SubPriorityBits    )) - 1UL)))\n         );\n}\n\n\n/**\n  \\brief   Decode Priority\n  \\details Decodes an interrupt priority value with a given priority group to\n           preemptive priority value and subpriority value.\n           In case of a conflict between priority grouping and available\n           priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set.\n  \\param [in]         Priority   Priority value, which can be retrieved with the function \\ref NVIC_GetPriority().\n  \\param [in]     PriorityGroup  Used priority group.\n  \\param [out] pPreemptPriority  Preemptive priority value (starting from 0).\n  \\param [out]     pSubPriority  Subpriority value (starting from 0).\n */\n__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority)\n{\n  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);   /* only values 0..7 are used          */\n  uint32_t PreemptPriorityBits;\n  uint32_t SubPriorityBits;\n\n  PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);\n  SubPriorityBits     = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));\n\n  *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL);\n  *pSubPriority     = (Priority                   ) & (uint32_t)((1UL << (SubPriorityBits    )) - 1UL);\n}\n\n\n/**\n  \\brief   Set Interrupt Vector\n  \\details Sets an interrupt vector in SRAM based interrupt vector table.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n           VTOR must been relocated to SRAM before.\n  \\param [in]   IRQn      Interrupt number\n  \\param [in]   vector    Address of interrupt handler function\n */\n__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)\n{\n  uint32_t *vectors = (uint32_t *)SCB->VTOR;\n  vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector;\n  /* ARM Application Note 321 states that the M3 does not require the architectural barrier */\n}\n\n\n/**\n  \\brief   Get Interrupt Vector\n  \\details Reads an interrupt vector from interrupt vector table.\n           The interrupt number can be positive to specify a device specific interrupt,\n           or negative to specify a processor exception.\n  \\param [in]   IRQn      Interrupt number.\n  \\return                 Address of interrupt handler function\n */\n__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn)\n{\n  uint32_t *vectors = (uint32_t *)SCB->VTOR;\n  return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET];\n}\n\n\n/**\n  \\brief   System Reset\n  \\details Initiates a system reset request to reset the MCU.\n */\n__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void)\n{\n  __DSB();                                                          /* Ensure all outstanding memory accesses included\n                                                                       buffered write are completed before reset */\n  SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |\n                           (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |\n                            SCB_AIRCR_SYSRESETREQ_Msk    );         /* Keep priority group unchanged */\n  __DSB();                                                          /* Ensure completion of memory access */\n\n  for(;;)                                                           /* wait until reset */\n  {\n    __NOP();\n  }\n}\n\n/*@} end of CMSIS_Core_NVICFunctions */\n\n\n/* ##########################  MPU functions  #################################### */\n\n#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)\n\n#include \"mpu_armv7.h\"\n\n#endif\n\n\n/* ##########################  FPU functions  #################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_FpuFunctions FPU Functions\n  \\brief    Function that provides FPU type.\n  @{\n */\n\n/**\n  \\brief   get FPU type\n  \\details returns the FPU type\n  \\returns\n   - \\b  0: No FPU\n   - \\b  1: Single precision FPU\n   - \\b  2: Double + Single precision FPU\n */\n__STATIC_INLINE uint32_t SCB_GetFPUType(void)\n{\n    return 0U;           /* No FPU */\n}\n\n\n/*@} end of CMSIS_Core_FpuFunctions */\n\n\n\n/* ##################################    SysTick function  ############################################ */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_Core_SysTickFunctions SysTick Functions\n  \\brief    Functions that configure the System.\n  @{\n */\n\n#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)\n\n/**\n  \\brief   System Tick Configuration\n  \\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.\n           Counter is in free running mode to generate periodic interrupts.\n  \\param [in]  ticks  Number of ticks between two interrupts.\n  \\return          0  Function succeeded.\n  \\return          1  Function failed.\n  \\note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the\n           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>\n           must contain a vendor-specific implementation of this function.\n */\n__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)\n{\n  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)\n  {\n    return (1UL);                                                   /* Reload value impossible */\n  }\n\n  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */\n  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */\n  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */\n  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |\n                   SysTick_CTRL_TICKINT_Msk   |\n                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */\n  return (0UL);                                                     /* Function successful */\n}\n\n#endif\n\n/*@} end of CMSIS_Core_SysTickFunctions */\n\n\n\n/* ##################################### Debug In/Output function ########################################### */\n/**\n  \\ingroup  CMSIS_Core_FunctionInterface\n  \\defgroup CMSIS_core_DebugFunctions ITM Functions\n  \\brief    Functions that access the ITM debug interface.\n  @{\n */\n\nextern volatile int32_t ITM_RxBuffer;                              /*!< External variable to receive characters. */\n#define                 ITM_RXBUFFER_EMPTY  ((int32_t)0x5AA55AA5U) /*!< Value identifying \\ref ITM_RxBuffer is ready for next character. */\n\n\n/**\n  \\brief   ITM Send Character\n  \\details Transmits a character via the ITM channel 0, and\n           \\li Just returns when no debugger is connected that has booked the output.\n           \\li Is blocking when a debugger is connected, but the previous character sent has not been transmitted.\n  \\param [in]     ch  Character to transmit.\n  \\returns            Character to transmit.\n */\n__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)\n{\n  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */\n      ((ITM->TER & 1UL               ) != 0UL)   )     /* ITM Port #0 enabled */\n  {\n    while (ITM->PORT[0U].u32 == 0UL)\n    {\n      __NOP();\n    }\n    ITM->PORT[0U].u8 = (uint8_t)ch;\n  }\n  return (ch);\n}\n\n\n/**\n  \\brief   ITM Receive Character\n  \\details Inputs a character via the external variable \\ref ITM_RxBuffer.\n  \\return             Received character.\n  \\return         -1  No character pending.\n */\n__STATIC_INLINE int32_t ITM_ReceiveChar (void)\n{\n  int32_t ch = -1;                           /* no character available */\n\n  if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY)\n  {\n    ch = ITM_RxBuffer;\n    ITM_RxBuffer = ITM_RXBUFFER_EMPTY;       /* ready for next character */\n  }\n\n  return (ch);\n}\n\n\n/**\n  \\brief   ITM Check Character\n  \\details Checks whether a character is pending for reading in the variable \\ref ITM_RxBuffer.\n  \\return          0  No character available.\n  \\return          1  Character available.\n */\n__STATIC_INLINE int32_t ITM_CheckChar (void)\n{\n\n  if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY)\n  {\n    return (0);                              /* no character available */\n  }\n  else\n  {\n    return (1);                              /*    character available */\n  }\n}\n\n/*@} end of CMSIS_core_DebugFunctions */\n\n\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __CORE_CM3_H_DEPENDANT */\n\n#endif /* __CMSIS_GENERIC */\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/mpu_armv7.h",
    "content": "/******************************************************************************\n * @file     mpu_armv7.h\n * @brief    CMSIS MPU API for Armv7-M MPU\n * @version  V5.1.2\n * @date     25. May 2020\n ******************************************************************************/\n/*\n * Copyright (c) 2017-2020 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n \n#if   defined ( __ICCARM__ )\n  #pragma system_include         /* treat file as system include file for MISRA check */\n#elif defined (__clang__)\n  #pragma clang system_header    /* treat file as system include file */\n#endif\n \n#ifndef ARM_MPU_ARMV7_H\n#define ARM_MPU_ARMV7_H\n\n#define ARM_MPU_REGION_SIZE_32B      ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes\n#define ARM_MPU_REGION_SIZE_64B      ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes\n#define ARM_MPU_REGION_SIZE_128B     ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes\n#define ARM_MPU_REGION_SIZE_256B     ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes\n#define ARM_MPU_REGION_SIZE_512B     ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes\n#define ARM_MPU_REGION_SIZE_1KB      ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte\n#define ARM_MPU_REGION_SIZE_2KB      ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes\n#define ARM_MPU_REGION_SIZE_4KB      ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes\n#define ARM_MPU_REGION_SIZE_8KB      ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes\n#define ARM_MPU_REGION_SIZE_16KB     ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes\n#define ARM_MPU_REGION_SIZE_32KB     ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes\n#define ARM_MPU_REGION_SIZE_64KB     ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes\n#define ARM_MPU_REGION_SIZE_128KB    ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes\n#define ARM_MPU_REGION_SIZE_256KB    ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes\n#define ARM_MPU_REGION_SIZE_512KB    ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes\n#define ARM_MPU_REGION_SIZE_1MB      ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte\n#define ARM_MPU_REGION_SIZE_2MB      ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes\n#define ARM_MPU_REGION_SIZE_4MB      ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes\n#define ARM_MPU_REGION_SIZE_8MB      ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes\n#define ARM_MPU_REGION_SIZE_16MB     ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes\n#define ARM_MPU_REGION_SIZE_32MB     ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes\n#define ARM_MPU_REGION_SIZE_64MB     ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes\n#define ARM_MPU_REGION_SIZE_128MB    ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes\n#define ARM_MPU_REGION_SIZE_256MB    ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes\n#define ARM_MPU_REGION_SIZE_512MB    ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes\n#define ARM_MPU_REGION_SIZE_1GB      ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte\n#define ARM_MPU_REGION_SIZE_2GB      ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes\n#define ARM_MPU_REGION_SIZE_4GB      ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes\n\n#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access\n#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only\n#define ARM_MPU_AP_URO  2U ///!< MPU Access Permission unprivileged access read-only\n#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access\n#define ARM_MPU_AP_PRO  5U ///!< MPU Access Permission privileged access read-only\n#define ARM_MPU_AP_RO   6U ///!< MPU Access Permission read-only access\n\n/** MPU Region Base Address Register Value\n*\n* \\param Region The region to be configured, number 0 to 15.\n* \\param BaseAddress The base address for the region.\n*/\n#define ARM_MPU_RBAR(Region, BaseAddress) \\\n  (((BaseAddress) & MPU_RBAR_ADDR_Msk) |  \\\n   ((Region) & MPU_RBAR_REGION_Msk)    |  \\\n   (MPU_RBAR_VALID_Msk))\n\n/**\n* MPU Memory Access Attributes\n* \n* \\param TypeExtField      Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.\n* \\param IsShareable       Region is shareable between multiple bus masters.\n* \\param IsCacheable       Region is cacheable, i.e. its value may be kept in cache.\n* \\param IsBufferable      Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.\n*/  \n#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable)   \\\n  ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk)                  | \\\n   (((IsShareable)  << MPU_RASR_S_Pos)   & MPU_RASR_S_Msk)                    | \\\n   (((IsCacheable)  << MPU_RASR_C_Pos)   & MPU_RASR_C_Msk)                    | \\\n   (((IsBufferable) << MPU_RASR_B_Pos)   & MPU_RASR_B_Msk))\n\n/**\n* MPU Region Attribute and Size Register Value\n* \n* \\param DisableExec       Instruction access disable bit, 1= disable instruction fetches.\n* \\param AccessPermission  Data access permissions, allows you to configure read/write access for User and Privileged mode.\n* \\param AccessAttributes  Memory access attribution, see \\ref ARM_MPU_ACCESS_.\n* \\param SubRegionDisable  Sub-region disable field.\n* \\param Size              Region size of the region to be configured, for example 4K, 8K.\n*/\n#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size)    \\\n  ((((DisableExec)      << MPU_RASR_XN_Pos)   & MPU_RASR_XN_Msk)                                  | \\\n   (((AccessPermission) << MPU_RASR_AP_Pos)   & MPU_RASR_AP_Msk)                                  | \\\n   (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \\\n   (((SubRegionDisable) << MPU_RASR_SRD_Pos)  & MPU_RASR_SRD_Msk)                                 | \\\n   (((Size)             << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk)                                | \\\n   (((MPU_RASR_ENABLE_Msk))))\n\n/**\n* MPU Region Attribute and Size Register Value\n* \n* \\param DisableExec       Instruction access disable bit, 1= disable instruction fetches.\n* \\param AccessPermission  Data access permissions, allows you to configure read/write access for User and Privileged mode.\n* \\param TypeExtField      Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.\n* \\param IsShareable       Region is shareable between multiple bus masters.\n* \\param IsCacheable       Region is cacheable, i.e. its value may be kept in cache.\n* \\param IsBufferable      Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.\n* \\param SubRegionDisable  Sub-region disable field.\n* \\param Size              Region size of the region to be configured, for example 4K, 8K.\n*/                         \n#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \\\n  ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)\n\n/**\n* MPU Memory Access Attribute for strongly ordered memory.\n*  - TEX: 000b\n*  - Shareable\n*  - Non-cacheable\n*  - Non-bufferable\n*/ \n#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)\n\n/**\n* MPU Memory Access Attribute for device memory.\n*  - TEX: 000b (if shareable) or 010b (if non-shareable)\n*  - Shareable or non-shareable\n*  - Non-cacheable\n*  - Bufferable (if shareable) or non-bufferable (if non-shareable)\n*\n* \\param IsShareable Configures the device memory as shareable or non-shareable.\n*/ \n#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))\n\n/**\n* MPU Memory Access Attribute for normal memory.\n*  - TEX: 1BBb (reflecting outer cacheability rules)\n*  - Shareable or non-shareable\n*  - Cacheable or non-cacheable (reflecting inner cacheability rules)\n*  - Bufferable or non-bufferable (reflecting inner cacheability rules)\n*\n* \\param OuterCp Configures the outer cache policy.\n* \\param InnerCp Configures the inner cache policy.\n* \\param IsShareable Configures the memory as shareable or non-shareable.\n*/ \n#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U))\n\n/**\n* MPU Memory Access Attribute non-cacheable policy.\n*/\n#define ARM_MPU_CACHEP_NOCACHE 0U\n\n/**\n* MPU Memory Access Attribute write-back, write and read allocate policy.\n*/\n#define ARM_MPU_CACHEP_WB_WRA 1U\n\n/**\n* MPU Memory Access Attribute write-through, no write allocate policy.\n*/\n#define ARM_MPU_CACHEP_WT_NWA 2U\n\n/**\n* MPU Memory Access Attribute write-back, no write allocate policy.\n*/\n#define ARM_MPU_CACHEP_WB_NWA 3U\n\n\n/**\n* Struct for a single MPU Region\n*/\ntypedef struct {\n  uint32_t RBAR; //!< The region base address register value (RBAR)\n  uint32_t RASR; //!< The region attribute and size register value (RASR) \\ref MPU_RASR\n} ARM_MPU_Region_t;\n    \n/** Enable the MPU.\n* \\param MPU_Control Default access permissions for unconfigured regions.\n*/\n__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)\n{\n  __DMB();\n  MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;\n#ifdef SCB_SHCSR_MEMFAULTENA_Msk\n  SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;\n#endif\n  __DSB();\n  __ISB();\n}\n\n/** Disable the MPU.\n*/\n__STATIC_INLINE void ARM_MPU_Disable(void)\n{\n  __DMB();\n#ifdef SCB_SHCSR_MEMFAULTENA_Msk\n  SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;\n#endif\n  MPU->CTRL  &= ~MPU_CTRL_ENABLE_Msk;\n  __DSB();\n  __ISB();\n}\n\n/** Clear and disable the given MPU region.\n* \\param rnr Region number to be cleared.\n*/\n__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)\n{\n  MPU->RNR = rnr;\n  MPU->RASR = 0U;\n}\n\n/** Configure an MPU region.\n* \\param rbar Value for RBAR register.\n* \\param rasr Value for RASR register.\n*/   \n__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)\n{\n  MPU->RBAR = rbar;\n  MPU->RASR = rasr;\n}\n\n/** Configure the given MPU region.\n* \\param rnr Region number to be configured.\n* \\param rbar Value for RBAR register.\n* \\param rasr Value for RASR register.\n*/   \n__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)\n{\n  MPU->RNR = rnr;\n  MPU->RBAR = rbar;\n  MPU->RASR = rasr;\n}\n\n/** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load().\n* \\param dst Destination data is copied to.\n* \\param src Source data is copied from.\n* \\param len Amount of data words to be copied.\n*/\n__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)\n{\n  uint32_t i;\n  for (i = 0U; i < len; ++i) \n  {\n    dst[i] = src[i];\n  }\n}\n\n/** Load the given number of MPU regions from a table.\n* \\param table Pointer to the MPU configuration table.\n* \\param cnt Amount of regions to be configured.\n*/\n__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) \n{\n  const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;\n  while (cnt > MPU_TYPE_RALIASES) {\n    ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);\n    table += MPU_TYPE_RALIASES;\n    cnt -= MPU_TYPE_RALIASES;\n  }\n  ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/lib/cmsis/system_ARMCM3.h",
    "content": "/**************************************************************************//**\n * @file     system_ARMCM3.h\n * @brief    CMSIS Device System Header File for\n *           ARMCM3 Device\n * @version  V5.3.2\n * @date     15. November 2019\n ******************************************************************************/\n/*\n * Copyright (c) 2009-2019 Arm Limited. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the License); you may\n * not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SYSTEM_ARMCM3_H\n#define SYSTEM_ARMCM3_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n  \\brief Exception / Interrupt Handler Function Prototype\n*/\ntypedef void(*VECTOR_TABLE_Type)(void);\n\n/**\n  \\brief System Clock Frequency (Core Clock)\n*/\nextern uint32_t SystemCoreClock;\n\n/**\n  \\brief Setup the microcontroller system.\n\n   Initialize the System and update the SystemCoreClock variable.\n */\nextern void SystemInit (void);\n\n\n/**\n  \\brief  Update SystemCoreClock variable.\n\n   Updates the SystemCoreClock with current core Clock retrieved from cpu registers.\n */\nextern void SystemCoreClockUpdate (void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* SYSTEM_ARMCM3_H */\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/main.c",
    "content": "int foo(int x);\r\n\r\nint main()\r\n{\r\n\treturn foo(1);\r\n}\r\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/startup_ARMCM3.s",
    "content": ";/**************************************************************************//**\r\n; * @file     startup_ARMCM3.s\r\n; * @brief    CMSIS Core Device Startup File for\r\n; *           ARMCM3 Device\r\n; * @version  V1.0.1\r\n; * @date     23. July 2019\r\n; ******************************************************************************/\r\n;/*\r\n; * Copyright (c) 2009-2019 Arm Limited. All rights reserved.\r\n; *\r\n; * SPDX-License-Identifier: Apache-2.0\r\n; *\r\n; * Licensed under the Apache License, Version 2.0 (the License); you may\r\n; * not use this file except in compliance with the License.\r\n; * You may obtain a copy of the License at\r\n; *\r\n; * www.apache.org/licenses/LICENSE-2.0\r\n; *\r\n; * Unless required by applicable law or agreed to in writing, software\r\n; * distributed under the License is distributed on an AS IS BASIS, WITHOUT\r\n; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n; * See the License for the specific language governing permissions and\r\n; * limitations under the License.\r\n; */\r\n\r\n;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------\r\n\r\n\r\n;<h> Stack Configuration\r\n;  <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>\r\n;</h>\r\n\r\nStack_Size      EQU      0x00000400\r\n\r\n                AREA     STACK, NOINIT, READWRITE, ALIGN=3\r\n__stack_limit\r\nStack_Mem       SPACE    Stack_Size\r\n__initial_sp\r\n\r\n\r\n;<h> Heap Configuration\r\n;  <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>\r\n;</h>\r\n\r\nHeap_Size       EQU      0x00000C00\r\n\r\n                IF       Heap_Size != 0                      ; Heap is provided\r\n                AREA     HEAP, NOINIT, READWRITE, ALIGN=3\r\n__heap_base\r\nHeap_Mem        SPACE    Heap_Size\r\n__heap_limit\r\n                ENDIF\r\n\r\n\r\n                PRESERVE8\r\n                THUMB\r\n\r\n\r\n; Vector Table Mapped to Address 0 at Reset\r\n\r\n                AREA     RESET, DATA, READONLY\r\n                EXPORT   __Vectors\r\n                EXPORT   __Vectors_End\r\n                EXPORT   __Vectors_Size\r\n\r\n__Vectors       DCD      __initial_sp                        ;     Top of Stack\r\n                DCD      Reset_Handler                       ;     Reset Handler\r\n                DCD      NMI_Handler                         ; -14 NMI Handler\r\n                DCD      HardFault_Handler                   ; -13 Hard Fault Handler\r\n                DCD      MemManage_Handler                   ; -12 MPU Fault Handler\r\n                DCD      BusFault_Handler                    ; -11 Bus Fault Handler\r\n                DCD      UsageFault_Handler                  ; -10 Usage Fault Handler\r\n                DCD      0                                   ;     Reserved\r\n                DCD      0                                   ;     Reserved\r\n                DCD      0                                   ;     Reserved\r\n                DCD      0                                   ;     Reserved\r\n                DCD      SVC_Handler                         ;  -5 SVCall Handler\r\n                DCD      DebugMon_Handler                    ;  -4 Debug Monitor Handler\r\n                DCD      0                                   ;     Reserved\r\n                DCD      PendSV_Handler                      ;  -2 PendSV Handler\r\n                DCD      SysTick_Handler                     ;  -1 SysTick Handler\r\n\r\n                ; Interrupts\r\n                DCD      Interrupt0_Handler                  ;   0 Interrupt 0\r\n                DCD      Interrupt1_Handler                  ;   1 Interrupt 1\r\n                DCD      Interrupt2_Handler                  ;   2 Interrupt 2\r\n                DCD      Interrupt3_Handler                  ;   3 Interrupt 3\r\n                DCD      Interrupt4_Handler                  ;   4 Interrupt 4\r\n                DCD      Interrupt5_Handler                  ;   5 Interrupt 5\r\n                DCD      Interrupt6_Handler                  ;   6 Interrupt 6\r\n                DCD      Interrupt7_Handler                  ;   7 Interrupt 7\r\n                DCD      Interrupt8_Handler                  ;   8 Interrupt 8\r\n                DCD      Interrupt9_Handler                  ;   9 Interrupt 9\r\n\r\n                SPACE    (214 * 4)                           ; Interrupts 10 .. 224 are left out\r\n__Vectors_End\r\n__Vectors_Size  EQU      __Vectors_End - __Vectors\r\n\r\n\r\n                AREA     |.text|, CODE, READONLY\r\n\r\n; Reset Handler\r\n\r\nReset_Handler   PROC\r\n                EXPORT   Reset_Handler             [WEAK]\r\n                IMPORT   SystemInit\r\n                IMPORT   __main\r\n\r\n                LDR      R0, =SystemInit\r\n                BLX      R0\r\n                LDR      R0, =__main\r\n                BX       R0\r\n                ENDP\r\n\r\n; The default macro is not used for HardFault_Handler\r\n; because this results in a poor debug illusion.\r\nHardFault_Handler PROC\r\n                EXPORT   HardFault_Handler         [WEAK]\r\n                B        .\r\n                ENDP\r\n\r\n; Macro to define default exception/interrupt handlers.\r\n; Default handler are weak symbols with an endless loop.\r\n; They can be overwritten by real handlers.\r\n                MACRO\r\n                Set_Default_Handler  $Handler_Name\r\n$Handler_Name   PROC\r\n                EXPORT   $Handler_Name             [WEAK]\r\n                B        .\r\n                ENDP\r\n                MEND\r\n\r\n\r\n; Default exception/interrupt handler\r\n\r\n                Set_Default_Handler  NMI_Handler\r\n                Set_Default_Handler  MemManage_Handler\r\n                Set_Default_Handler  BusFault_Handler\r\n                Set_Default_Handler  UsageFault_Handler\r\n                Set_Default_Handler  SVC_Handler\r\n                Set_Default_Handler  DebugMon_Handler\r\n                Set_Default_Handler  PendSV_Handler\r\n                Set_Default_Handler  SysTick_Handler\r\n\r\n                Set_Default_Handler  Interrupt0_Handler\r\n                Set_Default_Handler  Interrupt1_Handler\r\n                Set_Default_Handler  Interrupt2_Handler\r\n                Set_Default_Handler  Interrupt3_Handler\r\n                Set_Default_Handler  Interrupt4_Handler\r\n                Set_Default_Handler  Interrupt5_Handler\r\n                Set_Default_Handler  Interrupt6_Handler\r\n                Set_Default_Handler  Interrupt7_Handler\r\n                Set_Default_Handler  Interrupt8_Handler\r\n                Set_Default_Handler  Interrupt9_Handler\r\n\r\n                ALIGN\r\n\r\n\r\n; User setup Stack & Heap\r\n\r\n                IF       :LNOT::DEF:__MICROLIB\r\n                IMPORT   __use_two_region_memory\r\n                ENDIF\r\n\r\n                EXPORT   __stack_limit\r\n                EXPORT   __initial_sp\r\n                IF       Heap_Size != 0                      ; Heap is provided\r\n                EXPORT   __heap_base\r\n                EXPORT   __heap_limit\r\n                ENDIF\r\n\r\n                END\r\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/src/system_ARMCM3.c",
    "content": "/**************************************************************************//**\r\n * @file     system_ARMCM3.c\r\n * @brief    CMSIS Device System Source File for\r\n *           ARMCM3 Device\r\n * @version  V1.0.1\r\n * @date     15. November 2019\r\n ******************************************************************************/\r\n/*\r\n * Copyright (c) 2009-2019 Arm Limited. All rights reserved.\r\n *\r\n * SPDX-License-Identifier: Apache-2.0\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the License); you may\r\n * not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n * www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an AS IS BASIS, WITHOUT\r\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\n#include \"ARMCM3.h\"\r\n\r\n/*----------------------------------------------------------------------------\r\n  Define clocks\r\n *----------------------------------------------------------------------------*/\r\n#define  XTAL            (50000000UL)     /* Oscillator frequency */\r\n\r\n#define  SYSTEM_CLOCK    (XTAL / 2U)\r\n\r\n/*----------------------------------------------------------------------------\r\n  Exception / Interrupt Vector table\r\n *----------------------------------------------------------------------------*/\r\nextern const VECTOR_TABLE_Type __VECTOR_TABLE[240];\r\n\r\n/*----------------------------------------------------------------------------\r\n  System Core Clock Variable\r\n *----------------------------------------------------------------------------*/\r\nuint32_t SystemCoreClock = SYSTEM_CLOCK;  /* System Core Clock Frequency */\r\n\r\n\r\n/*----------------------------------------------------------------------------\r\n  System Core Clock update function\r\n *----------------------------------------------------------------------------*/\r\nvoid SystemCoreClockUpdate (void)\r\n{\r\n  SystemCoreClock = SYSTEM_CLOCK;\r\n}\r\n\r\n/*----------------------------------------------------------------------------\r\n  System initialization function\r\n *----------------------------------------------------------------------------*/\r\nvoid SystemInit (void)\r\n{\r\n\r\n#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)\r\n  SCB->VTOR = (uint32_t) &(__VECTOR_TABLE[0]);\r\n#endif\r\n\r\n  SystemCoreClock = SYSTEM_CLOCK;\r\n}\r\n"
  },
  {
    "path": "tests/projects/embed/mdk/hello/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_runtimes(\"microlib\")\n\ntarget(\"foo\")\n    add_rules(\"mdk.static\")\n    add_files(\"src/foo/*.c\")\n\ntarget(\"hello\")\n    add_deps(\"foo\")\n    add_rules(\"mdk.binary\")\n    add_files(\"src/*.c\", \"src/*.s\")\n    add_includedirs(\"src/lib/cmsis\")\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello/src/sim_main.cpp",
    "content": "#include \"hello.h\"\n#include \"verilated.h\"\n\ndouble sc_time_stamp() { return 0; }\n\nint main(int argc, char** argv) {\n    VerilatedContext* contextp = new VerilatedContext;\n    contextp->commandArgs(argc, argv);\n    hello* top = new hello{contextp};\n    while (!contextp->gotFinish()) { top->eval(); }\n    delete top;\n    delete contextp;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello/xmake.lua",
    "content": "add_requires(\"verilator\")\n\ntarget(\"hello\")\n    add_rules(\"verilator.binary\")\n    set_toolchains(\"@verilator\")\n    add_files(\"src/*.v\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello_vcd/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $dumpvars(0, hello);\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello_vcd/src/sim_main.cpp",
    "content": "#include \"hello.h\"\n#include \"verilated.h\"\n#include \"verilated_vcd_c.h\"\n\ndouble sc_time_stamp() {\n    return 0;\n}\n\nint main(int argc, char** argv) {\n    char const* vcdfile = NULL;\n    if (argc == 2) {\n        vcdfile = argv[1];\n    }\n    if (!vcdfile) {\n        vcdfile = \"hello.vcd\";\n    }\n    VerilatedContext* contextp = new VerilatedContext;\n    contextp->commandArgs(argc, argv);\n    hello* top = new hello{contextp};\n    VerilatedVcdC* tfp = new VerilatedVcdC;\n    top->trace(tfp, 99);\n    Verilated::traceEverOn(true);\n    tfp->open(vcdfile);\n    while (!contextp->gotFinish()) { top->eval(); }\n    tfp->close();\n    delete top;\n    delete contextp;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/embed/verilator/hello_vcd/xmake.lua",
    "content": "add_requires(\"verilator\")\n\ntarget(\"hello\")\n    add_rules(\"verilator.binary\")\n    set_toolchains(\"@verilator\")\n    add_files(\"src/*.v\")\n    add_files(\"src/*.cpp\")\n    add_values(\"verilator.flags\", \"--trace\", \"--timing\")\n"
  },
  {
    "path": "tests/projects/embed/verilator/shared/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/verilator/shared/src/sim_main.cpp",
    "content": "#include \"hello.h\"\n#include \"verilated.h\"\n\ndouble sc_time_stamp() { return 0; }\n\nint main(int argc, char** argv) {\n    VerilatedContext* contextp = new VerilatedContext;\n    contextp->commandArgs(argc, argv);\n    hello* top = new hello{contextp};\n    while (!contextp->gotFinish()) { top->eval(); }\n    delete top;\n    delete contextp;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/embed/verilator/shared/xmake.lua",
    "content": "add_requires(\"verilator\")\n\ntarget(\"hello\")\n    add_rules(\"verilator.shared\")\n    set_toolchains(\"@verilator\")\n    add_files(\"src/*.v\")\n\ntarget(\"test\")\n    add_deps(\"hello\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/embed/verilator/static/src/main.v",
    "content": "module hello;\n  initial begin\n    $display(\"hello world!\");\n    $finish ;\n  end\nendmodule\n"
  },
  {
    "path": "tests/projects/embed/verilator/static/src/sim_main.cpp",
    "content": "#include \"hello.h\"\n#include \"verilated.h\"\n\ndouble sc_time_stamp() { return 0; }\n\nint main(int argc, char** argv) {\n    VerilatedContext* contextp = new VerilatedContext;\n    contextp->commandArgs(argc, argv);\n    hello* top = new hello{contextp};\n    while (!contextp->gotFinish()) { top->eval(); }\n    delete top;\n    delete contextp;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/embed/verilator/static/xmake.lua",
    "content": "add_requires(\"verilator\")\n\ntarget(\"hello\")\n    add_rules(\"verilator.static\")\n    set_toolchains(\"@verilator\")\n    add_files(\"src/*.v\")\n\ntarget(\"test\")\n    add_deps(\"hello\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/fortran/console/src/main.f90",
    "content": "program hello\n  print *, \"Hello World!\"\nend program hello\n"
  },
  {
    "path": "tests/projects/fortran/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.f90\")\n\n"
  },
  {
    "path": "tests/projects/fortran/shared_library/src/main.f90",
    "content": "program hello\n    use test, only: print_hello\n    implicit none (type, external)\n    call print_hello()\nend program hello\n"
  },
  {
    "path": "tests/projects/fortran/shared_library/src/test.f90",
    "content": "module test\n    implicit none (type, external)\n    \ncontains\n    subroutine print_hello()\n        print *, \"Hello World!\"\n    end subroutine print_hello\nend module test\n"
  },
  {
    "path": "tests/projects/fortran/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"testlib\")\n    set_kind(\"shared\")\n    add_files(\"src/test.f90\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"testlib\")\n    add_files(\"src/main.f90\")\n\n"
  },
  {
    "path": "tests/projects/fortran/static_library/src/main.f90",
    "content": "program hello\n    use test, only: print_hello\n    implicit none (type, external)\n    call print_hello()\nend program hello\n"
  },
  {
    "path": "tests/projects/fortran/static_library/src/test.f90",
    "content": "module test\n    implicit none (type, external)\n    \ncontains\n    subroutine print_hello()\n        print *, \"Hello World!\"\n    end subroutine print_hello\nend module test\n"
  },
  {
    "path": "tests/projects/fortran/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"testlib\")\n    set_kind(\"static\")\n    add_files(\"src/test.f90\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"testlib\")\n    add_files(\"src/main.f90\")\n\n"
  },
  {
    "path": "tests/projects/go/console/src/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"hello xmake!\")\n}\n"
  },
  {
    "path": "tests/projects/go/console/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() ~= \"arm64\" then\n--        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/go/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.go\")\n\n"
  },
  {
    "path": "tests/projects/go/static_library/src/main.go",
    "content": "package main\n\nfunc main() {\n\n    Run()\n}\n\n"
  },
  {
    "path": "tests/projects/go/static_library/src/module/add.go",
    "content": "package module\n\nfunc Add(a int, b int) int {\n    return a + b;\n}\n\n"
  },
  {
    "path": "tests/projects/go/static_library/src/module/sub.go",
    "content": "package module\n\nfunc Sub(a int, b int) int {\n    return a - b;\n}\n\n"
  },
  {
    "path": "tests/projects/go/static_library/src/test.go",
    "content": "package main\n\nimport (\n    \"fmt\"\n    \"module\"\n)\n\nfunc Run() {\n    fmt.Printf(\"add: %d\\n\", module.Add(1, 2));\n    fmt.Printf(\"sub: %d\\n\", module.Sub(1, 2));\n}\n"
  },
  {
    "path": "tests/projects/go/static_library/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() ~= \"arm64\" then\n--        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/go/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"module\")\n    set_kind(\"static\")\n    add_files(\"src/module/*.go\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"module\")\n    add_files(\"src/*.go\")\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/main.cpp",
    "content": "#include \"test.h\"\n\nint main(int argc, char** argv) {\n    test1();\n#ifdef MACOSX\n    test2();\n    test3();\n#endif\n    test4();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/main2.cpp",
    "content": "#include \"test.h\"\n\nint main(int argc, char** argv) {\n    test5();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid test1(void);\nvoid test2(void);\nvoid test3(void);\nvoid test4(void);\nint  test5(void);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test1.c",
    "content": "#include \"test.h\"\n\nvoid test1() {\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test2.m",
    "content": "#include \"test.h\"\n\nvoid test2() {\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test3.mm",
    "content": "#include \"test.h\"\n\nvoid test3() {\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test4.cpp",
    "content": "#include \"test.h\"\n\nvoid test4() {\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/src/test5.d",
    "content": "\nextern(C) int test5() {\n    return 5;\n}\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() == \"arm64\" then\n        return\n    end\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/hybrid/static_library/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_files(\"src/*.c\", \"src/*.cpp\")\n    if is_plat(\"macosx\") then\n        add_files(\"src/*.m\", \"src/*.mm\")\n    end\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"src/main.cpp\")\n    if is_plat(\"macosx\") then\n        add_defines(\"MACOSX\")\n    end\n\n--[[\ntarget(\"demo2\")\n    set_kind(\"binary\")\n    add_files(\"src/main2.cpp\", \"src/*.d\")\n    if not is_plat(\"macosx\") then\n        set_enabled(false)\n    end\n]]\n"
  },
  {
    "path": "tests/projects/kotlin-native/console/src/main.kt",
    "content": "fun main() {\n    println(\"hello xmake!\")\n}\n"
  },
  {
    "path": "tests/projects/kotlin-native/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"kotlin-native\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.kt\")\n    set_toolchains(\"@kotlin-native\")\n\n"
  },
  {
    "path": "tests/projects/kotlin-native/package/cli-parser/src/main.kt",
    "content": "import kotlinx.cli.ArgParser\nimport kotlinx.cli.ArgType\nimport kotlinx.cli.default\n\nfun main(args: Array<String>) {\n    val parser = ArgParser(\"example\")\n    val name by parser.option(ArgType.String, shortName = \"n\", description = \"Your name\").default(\"World\")\n    parser.parse(args)\n    println(\"Hello, $name!\")\n}\n"
  },
  {
    "path": "tests/projects/kotlin-native/package/cli-parser/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"kotlin-native\")\nadd_requires(\"kotlin-native::org.jetbrains.kotlinx:kotlinx-cli 0.3.6\", {alias = \"kotlinx-cli\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.kt\")\n    add_packages(\"kotlinx-cli\")\n    set_toolchains(\"@kotlin-native\")\n"
  },
  {
    "path": "tests/projects/kotlin-native/package/json/src/main.kt",
    "content": "import kotlinx.serialization.Serializable\nimport kotlinx.serialization.encodeToString\nimport kotlinx.serialization.json.Json\n\n@Serializable\nprivate data class Message(\n    val topic: String,\n    val content: String,\n)\n\nprivate val PrettyPrintJson = Json {\n    prettyPrint = true\n}\n\nfun main() {\n    val message = Message(\n        topic = \"Kotlin/Native\",\n        content = \"Hello!\"\n    )\n    println(PrettyPrintJson.encodeToString(message))\n}\n\n\n"
  },
  {
    "path": "tests/projects/kotlin-native/package/json/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"kotlin-native\")\nadd_requires(\"kotlin-native::org.jetbrains.kotlinx:kotlinx-serialization-json 1.8.0\", {alias = \"json\"})\nadd_requires(\"kotlin-native::org.jetbrains.kotlinx:kotlinx-serialization-core 1.8.0\", {alias = \"core\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.kt\")\n    add_packages(\"json\", \"core\")\n    set_toolchains(\"@kotlin-native\")\n"
  },
  {
    "path": "tests/projects/kotlin-native/shared_library/src/foo.kt",
    "content": "@CName(\"kotlin_add\")\nfun add(a: Int, b: Int): Int = a + b\n"
  },
  {
    "path": "tests/projects/kotlin-native/shared_library/src/main.c",
    "content": "#include \"libfoo_api.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"add(1, 2) = %d\\n\", kotlin_add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/kotlin-native/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"kotlin-native\")\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.kt\")\n    set_toolchains(\"@kotlin-native\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    add_deps(\"foo\")\n\n"
  },
  {
    "path": "tests/projects/kotlin-native/static_library/src/foo.kt",
    "content": "@CName(\"kotlin_add\")\nfun add(a: Int, b: Int): Int = a + b\n"
  },
  {
    "path": "tests/projects/kotlin-native/static_library/src/main.c",
    "content": "#include \"libfoo_api.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"add(1, 2) = %d\\n\", kotlin_add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/kotlin-native/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"kotlin-native\")\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.kt\")\n    set_toolchains(\"@kotlin-native\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    add_deps(\"foo\")\n\n"
  },
  {
    "path": "tests/projects/lex_yacc/src/calc.l",
    "content": "%option noyywrap\n\n%{\n#include <stdio.h>\n\n#define YY_DECL int yylex()\n\n#include \"calc.tab.h\"\n\n%}\n\n%%\n\n[ \\t]\t; // ignore all whitespace\n[0-9]+\\.[0-9]+ \t{yylval.fval = atof(yytext); return T_FLOAT;}\n[0-9]+\t\t{yylval.ival = atoi(yytext); return T_INT;}\n\\n\t\t{return T_NEWLINE;}\n\"+\"\t\t{return T_PLUS;}\n\"-\"\t\t{return T_MINUS;}\n\"*\"\t\t{return T_MULTIPLY;}\n\"/\"\t\t{return T_DIVIDE;}\n\"(\"\t\t{return T_LEFT;}\n\")\"\t\t{return T_RIGHT;}\n\"exit\"\t\t{return T_QUIT;}\n\"quit\"\t\t{return T_QUIT;}\n\n%%\n"
  },
  {
    "path": "tests/projects/lex_yacc/src/calc.y",
    "content": "%{\n\n#include <stdio.h>\n#include <stdlib.h>\n\nextern int yylex();\nextern int yyparse();\nextern FILE* yyin;\n\nvoid yyerror(const char* s);\n%}\n\n%union {\n\tint ival;\n\tfloat fval;\n}\n\n%token<ival> T_INT\n%token<fval> T_FLOAT\n%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT\n%token T_NEWLINE T_QUIT\n%left T_PLUS T_MINUS\n%left T_MULTIPLY T_DIVIDE\n\n%type<ival> expression\n%type<fval> mixed_expression\n\n%start calculation\n\n%%\n\ncalculation:\n\t   | calculation line\n;\n\nline: T_NEWLINE\n    | mixed_expression T_NEWLINE { printf(\"\\tResult: %f\\n\", $1);}\n    | expression T_NEWLINE { printf(\"\\tResult: %i\\n\", $1); }\n    | T_QUIT T_NEWLINE { printf(\"bye!\\n\"); exit(0); }\n;\n\nmixed_expression: T_FLOAT                 \t\t { $$ = $1; }\n\t  | mixed_expression T_PLUS mixed_expression\t { $$ = $1 + $3; }\n\t  | mixed_expression T_MINUS mixed_expression\t { $$ = $1 - $3; }\n\t  | mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }\n\t  | mixed_expression T_DIVIDE mixed_expression\t { $$ = $1 / $3; }\n\t  | T_LEFT mixed_expression T_RIGHT\t\t { $$ = $2; }\n\t  | expression T_PLUS mixed_expression\t \t { $$ = $1 + $3; }\n\t  | expression T_MINUS mixed_expression\t \t { $$ = $1 - $3; }\n\t  | expression T_MULTIPLY mixed_expression \t { $$ = $1 * $3; }\n\t  | expression T_DIVIDE mixed_expression\t { $$ = $1 / $3; }\n\t  | mixed_expression T_PLUS expression\t \t { $$ = $1 + $3; }\n\t  | mixed_expression T_MINUS expression\t \t { $$ = $1 - $3; }\n\t  | mixed_expression T_MULTIPLY expression \t { $$ = $1 * $3; }\n\t  | mixed_expression T_DIVIDE expression\t { $$ = $1 / $3; }\n\t  | expression T_DIVIDE expression\t\t { $$ = $1 / (float)$3; }\n;\n\nexpression: T_INT\t\t\t\t{ $$ = $1; }\n\t  | expression T_PLUS expression\t{ $$ = $1 + $3; }\n\t  | expression T_MINUS expression\t{ $$ = $1 - $3; }\n\t  | expression T_MULTIPLY expression\t{ $$ = $1 * $3; }\n\t  | T_LEFT expression T_RIGHT\t\t{ $$ = $2; }\n;\n\n%%\n\nint main() {\n\tyyin = stdin;\n\n\tdo {\n\t\tyyparse();\n\t} while(!feof(yyin));\n\n\treturn 0;\n}\n\nvoid yyerror(const char* s) {\n\tfprintf(stderr, \"Parse error: %s\\n\", s);\n\texit(1);\n}\n"
  },
  {
    "path": "tests/projects/lex_yacc/src/test.c",
    "content": "#include \"calc.tab.h\"\nvoid test()\n{\n}\n"
  },
  {
    "path": "tests/projects/lex_yacc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"calc\")\n    set_kind(\"binary\")\n    add_rules(\"lex\", \"yacc\")\n    add_files(\"src/*.c\", \"src/*.l\", \"src/*.y\")\n"
  },
  {
    "path": "tests/projects/linux/bpf/minimal/src/minimal.bpf.c",
    "content": "// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause\n/* Copyright (c) 2020 Facebook */\n#include <linux/bpf.h>\n#include <bpf/bpf_helpers.h>\n\nchar LICENSE[] SEC(\"license\") = \"Dual BSD/GPL\";\n\nint my_pid = 0;\n\nSEC(\"tp/syscalls/sys_enter_write\")\nint handle_tp(void *ctx)\n{\n\tint pid = bpf_get_current_pid_tgid() >> 32;\n\n\tif (pid != my_pid)\n\t\treturn 0;\n\n\tbpf_printk(\"BPF triggered from PID %d.\\n\", pid);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/projects/linux/bpf/minimal/src/minimal.c",
    "content": "// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)\n/* Copyright (c) 2020 Facebook */\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/resource.h>\n#include <bpf/libbpf.h>\n#include \"minimal.skel.h\"\n\nstatic int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)\n{\n\treturn vfprintf(stderr, format, args);\n}\n\nstatic void bump_memlock_rlimit(void)\n{\n\tstruct rlimit rlim_new = {\n\t\t.rlim_cur\t= RLIM_INFINITY,\n\t\t.rlim_max\t= RLIM_INFINITY,\n\t};\n\n\tif (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {\n\t\tfprintf(stderr, \"Failed to increase RLIMIT_MEMLOCK limit!\\n\");\n\t\texit(1);\n\t}\n}\n\nint main(int argc, char **argv)\n{\n\tstruct minimal_bpf *skel;\n\tint err;\n\n\t/* Set up libbpf errors and debug info callback */\n\tlibbpf_set_print(libbpf_print_fn);\n\n\t/* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */\n\tbump_memlock_rlimit();\n\n\t/* Open BPF application */\n\tskel = minimal_bpf__open();\n\tif (!skel) {\n\t\tfprintf(stderr, \"Failed to open BPF skeleton\\n\");\n\t\treturn 1;\n\t}\n\n\t/* ensure BPF program only handles write() syscalls from our process */\n\tskel->bss->my_pid = getpid();\n\n\t/* Load & verify BPF programs */\n\terr = minimal_bpf__load(skel);\n\tif (err) {\n\t\tfprintf(stderr, \"Failed to load and verify BPF skeleton\\n\");\n\t\tgoto cleanup;\n\t}\n\n\t/* Attach tracepoint handler */\n\terr = minimal_bpf__attach(skel);\n\tif (err) {\n\t\tfprintf(stderr, \"Failed to attach BPF skeleton\\n\");\n\t\tgoto cleanup;\n\t}\n\n\tprintf(\"Successfully started!\\n\");\n\n\tfor (;;) {\n\t\t/* trigger our BPF program */\n\t\tfprintf(stderr, \".\");\n\t\tsleep(1);\n\t}\n\ncleanup:\n\tminimal_bpf__destroy(skel);\n\treturn -err;\n}\n"
  },
  {
    "path": "tests/projects/linux/bpf/minimal/test.lua",
    "content": "function main(t)\n    if is_host(\"linux\") and os.arch() == \"x86_64\" and linuxos.name() ~= \"alpine\" then\n        os.vrun(\"xmake f -y -p android -vD\")\n        os.vrun(\"xmake -y -vD\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/linux/bpf/minimal/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_rules(\"platform.linux.bpf\")\n\nadd_requires(\"linux-tools\", {configs = {bpftool = true}})\nadd_requires(\"libbpf\")\nif is_plat(\"android\") then\n    add_requires(\"ndk >=22.0 <26.0\")\n    set_toolchains(\"@ndk\", {sdkver = \"23\"})\nelse\n    add_requires(\"llvm >=10.x\")\n    set_toolchains(\"@llvm\")\n    add_requires(\"linux-headers\")\nend\n\n-- fix error: libbpf: map 'my_pid_map': unsupported map linkage static. for bpftool >= 7.2.0\n-- we cannot add `\"-fvisibility=hidden\"` when compiling *.bpf.c\n-- @see https://github.com/libbpf/bpftool/issues/120\nset_symbols(\"none\")\n\ntarget(\"minimal\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"linux-tools\", \"linux-headers\", \"libbpf\")\n    set_license(\"GPL-2.0\")\n"
  },
  {
    "path": "tests/projects/linux/driver/hello/src/add.c",
    "content": "#include \"add.h\"\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/linux/driver/hello/src/add.h",
    "content": "#pragma once\nint add(int a, int b);\n"
  },
  {
    "path": "tests/projects/linux/driver/hello/src/hello.c",
    "content": "#include <linux/init.h>\n#include <linux/module.h>\n#include \"add.h\"\n\nMODULE_LICENSE(\"Dual BSD/GPL\");\nMODULE_AUTHOR(\"Ruki\");\nMODULE_DESCRIPTION(\"A simple Hello World Module\");\nMODULE_ALIAS(\"a simplest module\");\n\nstatic int hello_init(void)\n{\n    printk(KERN_INFO \"Hello World: %d\\n\", add(1, 2));\n    return 0;\n}\n\nstatic void hello_exit(void)\n{\n    printk(KERN_INFO \"Goodbye World\\n\");\n}\n\nmodule_init(hello_init);\nmodule_exit(hello_exit);\n"
  },
  {
    "path": "tests/projects/linux/driver/hello/xmake.lua",
    "content": "add_requires(\"linux-headers\", {configs = {driver_modules = true}})\n\ntarget(\"hello\")\n    add_rules(\"platform.linux.module\")\n    add_files(\"src/*.c\")\n    add_packages(\"linux-headers\")\n    set_license(\"GPL-2.0\")\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_custom/src/add.c",
    "content": "#include \"add.h\"\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_custom/src/add.h",
    "content": "#pragma once\nint add(int a, int b);\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_custom/src/hello.c",
    "content": "#include <linux/init.h>\n#include <linux/module.h>\n#include \"add.h\"\nMODULE_LICENSE(\"Dual BSD/GPL\");\nMODULE_AUTHOR(\"Ruki\");\nMODULE_DESCRIPTION(\"A simple Hello World Module\");\nMODULE_ALIAS(\"a simplest module\");\n\nstatic int hello_init(void)\n{\n    printk(KERN_INFO \"Hello World: %d\\n\", add(1, 2));\n    return 0;\n}\n\nstatic void hello_exit(void)\n{\n    printk(KERN_INFO \"Goodbye World\\n\");\n}\n\nmodule_init(hello_init);\nmodule_exit(hello_exit);\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_custom/xmake.lua",
    "content": "option(\"linux-headers\", {showmenu = true, description = \"Set linux-headers path.\"})\ntarget(\"hello\")\n    add_rules(\"platform.linux.module\")\n    add_files(\"src/*.c\")\n    set_values(\"linux.driver.linux-headers\", \"$(linux-headers)\")\n\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_makefile/src/add.c",
    "content": "#include \"add.h\"\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_makefile/src/add.h",
    "content": "#pragma once\nint add(int a, int b);\n"
  },
  {
    "path": "tests/projects/linux/driver/hello_makefile/src/hello.c",
    "content": "#include <linux/init.h>\n#include <linux/module.h>\n#include \"add.h\"\n\nMODULE_LICENSE(\"Dual BSD/GPL\");\nMODULE_AUTHOR(\"Ruki\");\nMODULE_DESCRIPTION(\"A simple Hello World Module\");\nMODULE_ALIAS(\"a simplest module\");\n\nstatic int hello_init(void)\n{\n    printk(KERN_INFO \"Hello World: %d\\n\", add(1, 2));\n    return 0;\n}\n\nstatic void hello_exit(void)\n{\n    printk(KERN_INFO \"Goodbye World\\n\");\n}\n\nmodule_init(hello_init);\nmodule_exit(hello_exit);\n"
  },
  {
    "path": "tests/projects/nim/console/src/main.nim",
    "content": "echo \"hello xmake!\"\n"
  },
  {
    "path": "tests/projects/nim/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.nim\")\n"
  },
  {
    "path": "tests/projects/nim/console_with_c/src/foo.c",
    "content": "int foo(int n) {\n    return n;\n}\n"
  },
  {
    "path": "tests/projects/nim/console_with_c/src/main.nim",
    "content": "proc foo(n: int): int {.cdecl, importc}\n\necho foo(2)\n"
  },
  {
    "path": "tests/projects/nim/console_with_c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/*.c\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.nim\")\n"
  },
  {
    "path": "tests/projects/nim/link_library/headers/test_header.h",
    "content": "#ifndef TEST_HEADER_H\n#define TEST_HEADER_H\n\n#define TEST_HEADER_VAL 123\n\nstatic int test_add_five(int x) {\n    return x + 5;\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/nim/link_library/inc/test.h",
    "content": "\n#ifndef TEST_H\n#define TEST_H\n\n#ifdef TEST_STATIC\n    #define TEST_MSG \"Hello from Static Lib!\"\n#else\n    #define TEST_MSG \"Hello from Shared Lib!\"\n#endif\n\n#endif\n"
  },
  {
    "path": "tests/projects/nim/link_library/maindll.nim",
    "content": "import shared\n\necho \"Calling shared lib mulTwo(10): \", mulTwo(10)\necho \"Calling shared lib countWords('hello, world, hello'): \", countWords(\"hello, world, hello\")\necho \"Calling shared lib getMsg('test'): \", getMsg()\n\n{.emit: \"\"\"\n#include <test_header.h>\n\"\"\".}\n\nvar testHeaderVal {.importc: \"TEST_HEADER_VAL\", nodecl.}: cint\necho \"TEST_HEADER_VAL: \", testHeaderVal\n\nproc test_add_five(x: cint): cint {.importc: \"test_add_five\", nodecl.}\necho \"test_add_five(80): \", test_add_five(80)\n\n"
  },
  {
    "path": "tests/projects/nim/link_library/mainlib.nim",
    "content": "import static\n\n{.emit: \"\"\"\n#include <zlib.h>\n#define STB_IMAGE_IMPLEMENTATION\n#include <stb_image.h>\n\"\"\".}\n\nproc zlibVersion(): cstring {.importc: \"zlibVersion\", nodecl.}\nproc stbi_set_flip_vertically_on_load(flag_true_if_should_flip: cint) {.importc: \"stbi_set_flip_vertically_on_load\", nodecl.}\n\necho \"Zlib Version: \", zlibVersion()\n\nstbi_set_flip_vertically_on_load(1)\necho \"STB Image: Flip vertically on load set to 1\"\n\necho \"Calling static lib addTwo(10): \", addTwo(10)\necho \"Calling static lib getAlphabet(): \", getAlphabet()\necho \"Calling static lib getMsg('test'): \", getMsg()\n\n{.emit: \"\"\"\n#include <test_header.h>\n\"\"\".}\n\nvar testHeaderVal {.importc: \"TEST_HEADER_VAL\", nodecl.}: cint\necho \"TEST_HEADER_VAL: \", testHeaderVal\n\nproc test_add_five(x: cint): cint {.importc: \"test_add_five\", nodecl.}\necho \"test_add_five(55): \", test_add_five(55)\n\n"
  },
  {
    "path": "tests/projects/nim/link_library/shared.nim",
    "content": "proc mulTwo*(x: int): int =\n  return x * 2\n\nimport tables, strutils\n\nproc countWords*(input: string): string =\n  var wordFrequencies = initCountTable[string]()\n  for word in input.split(\", \"):\n    wordFrequencies.inc(word)\n  return \"The most frequent word is '\" & $wordFrequencies.largest & \"'\"\n\n{.emit: \"\"\"\n#include \"test.h\"\n\"\"\".}\n\nproc getMsg*(): cstring {.exportc, dynlib.} =\n    var msg: cstring\n    {.emit: \"`msg` = TEST_MSG;\".}\n    return msg\n\n{.emit: \"\"\"\n#include <test_header.h>\n\"\"\".}\n\nvar testHeaderVal {.importc: \"TEST_HEADER_VAL\", nodecl.}: cint\necho \"TEST_HEADER_VAL: \", testHeaderVal\n\nproc test_add_five(x: cint): cint {.importc: \"test_add_five\", nodecl.}\necho \"test_add_five(10): \", test_add_five(10)\n"
  },
  {
    "path": "tests/projects/nim/link_library/static.nim",
    "content": "proc addTwo*(x: int): int =\n  return x + 2\n\nproc getAlphabet*(): string =\n  for letter in 'a'..'z':\n    result.add(letter)\n\n{.emit: \"\"\"\n#define TEST_STATIC\n#include \"test.h\"\n\"\"\".}\n\nproc getMsg*(): cstring {.exportc, dynlib.} =\n    var msg: cstring\n    {.emit: \"`msg` = TEST_MSG;\".}\n    return msg\n\n{.emit: \"\"\"\n#include <test_header.h>\n\"\"\".}\n\nvar testHeaderVal {.importc: \"TEST_HEADER_VAL\", nodecl.}: cint\necho \"TEST_HEADER_VAL: \", testHeaderVal\n\nproc test_add_five(x: cint): cint {.importc: \"test_add_five\", nodecl.}\necho \"test_add_five(60): \", test_add_five(60)\n"
  },
  {
    "path": "tests/projects/nim/link_library/xmake.lua",
    "content": "set_project(\"link_libs\")\nadd_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"zlib\", {system = false, configs = {shared = true}})\nadd_requires(\"stb\", {system = false})\n\ntarget(\"headers\")\n    set_kind(\"headeronly\")\n    add_headerfiles(\"headers/*.h\")\n    add_includedirs(\"headers\", {public = true})\n\ntarget(\"executablestatic\")\n    set_kind(\"binary\")\n    add_files(\"mainlib.nim\")\n    add_deps(\"staticlib\")\n    add_packages(\"zlib\", \"stb\", {public = true})\n    if is_plat(\"linux\") then\n        add_syslinks(\"pthread\", \"m\")\n    end\n\ntarget(\"executableshared\")\n    set_kind(\"binary\")\n    add_files(\"maindll.nim\")\n    add_deps(\"sharedlib\")\n    if is_plat(\"linux\") then\n        add_syslinks(\"pthread\", \"m\")\n    end\n\ntarget(\"staticlib\")\n    set_kind(\"static\")\n    add_files(\"static.nim\")\n    add_includedirs(\"inc\", {public = true})\n    add_headerfiles(\"inc/*.h\")\n    if is_plat(\"linux\") then\n        add_syslinks(\"pthread\", \"m\")\n    end\n    add_deps(\"headers\")\n\ntarget(\"sharedlib\")\n    set_kind(\"shared\")\n    add_files(\"shared.nim\")\n    add_includedirs(\"inc\", {public = true})\n    add_headerfiles(\"inc/*.h\")\n    if is_plat(\"linux\") then\n        add_syslinks(\"pthread\", \"m\")\n    end\n    add_deps(\"headers\")\n"
  },
  {
    "path": "tests/projects/nim/native_package/src/main.nim",
    "content": "proc zlibVersion(): cstring {.cdecl, importc}\n\necho zlibVersion()\n"
  },
  {
    "path": "tests/projects/nim/native_package/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"zlib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.nim\")\n    add_packages(\"zlib\")\n"
  },
  {
    "path": "tests/projects/nim/nimble_package/src/main.nim",
    "content": "import zip/zlib\n\necho zlibVersion()\n"
  },
  {
    "path": "tests/projects/nim/nimble_package/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"nimble::zip >0.3\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.nim\")\n    add_packages(\"nimble::zip\")\n"
  },
  {
    "path": "tests/projects/nim/shared_library/src/foo.nim",
    "content": "proc foo(n: int): int {.cdecl, exportc, dynlib.} =\n  if n < 2:\n    result = n\n  else:\n    result = foo(n - 1) + (n - 2).foo\n"
  },
  {
    "path": "tests/projects/nim/shared_library/src/main.nim",
    "content": "proc foo(n: int): int {.cdecl, importc}\n\necho foo(2)\n\n"
  },
  {
    "path": "tests/projects/nim/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.nim\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.nim\")\n\n\n"
  },
  {
    "path": "tests/projects/nim/static_library/src/foo.nim",
    "content": "proc foo(n: int): int {.cdecl, exportc} =\n  if n < 2:\n    result = n\n  else:\n    result = foo(n - 1) + (n - 2).foo\n\n"
  },
  {
    "path": "tests/projects/nim/static_library/src/main.nim",
    "content": "proc foo(n: int): int {.cdecl, importc}\n\necho foo(2)\n"
  },
  {
    "path": "tests/projects/nim/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.nim\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.nim\")\n\n\n"
  },
  {
    "path": "tests/projects/objc/bundle/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/bundle/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "tests/projects/objc/bundle/src/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/objc/bundle/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/objc/bundle/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.bundle\")\n    add_files(\"src/test.m\")\n    add_files(\"src/Info.plist\")\n\n"
  },
  {
    "path": "tests/projects/objc/console/src/main.m",
    "content": "#import <Foundation/Foundation.h>\n\nint main(int argc, char** argv)\n{\n    @autoreleasepool\n    {\n        NSLog(@\"hello world!\");\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc/console/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/objc/console/xmake.lua",
    "content": "-- add rules\nadd_rules(\"mode.debug\", \"mode.release\")\n\n-- add target\ntarget(\"console_objc\")\n\n    -- set kind\n    set_kind(\"binary\")\n\n    -- add files\n    add_files(\"src/*.m\")\n\n"
  },
  {
    "path": "tests/projects/objc/framework/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/framework/src/main.m",
    "content": "#import <Foundation/Foundation.h>\n#import <test/test.h>\n\nint main(int argc, char** argv)\n{\n    @autoreleasepool\n    {\n        NSLog(@\"add(1, 2): %d\", add(1, 2));\n        Test* t = [[Test alloc] init];\n        [t hello];\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc/framework/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n\n@interface Test : NSObject\n- (void)hello;\n@end\n"
  },
  {
    "path": "tests/projects/objc/framework/src/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n\n@implementation Test\n\n- (void)hello {\n    NSLog(@\"hello xmake!\");\n}\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/framework/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/objc/framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/test.m\")\n    add_files(\"src/Info.plist\")\n    add_headerfiles(\"src/*.h\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"src/main.m\")\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    return YES;\n}\n\n\n#pragma mark - UISceneSession lifecycle\n\n\n- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {\n    // Called when a new scene session is being created.\n    // Use this method to select a configuration to create the new scene with.\n    return [[UISceneConfiguration alloc] initWithName:@\"Default Configuration\" sessionRole:connectingSceneSession.role];\n}\n\n\n- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {\n    // Called when the user discards a scene session.\n    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/iosapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/iosapp/src/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/SceneDelegate.h",
    "content": "//\n//  SceneDelegate.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>\n\n@property (strong, nonatomic) UIWindow * window;\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/SceneDelegate.m",
    "content": "#import \"SceneDelegate.h\"\n\n@interface SceneDelegate ()\n\n@end\n\n@implementation SceneDelegate\n\n\n- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n}\n\n\n- (void)sceneDidDisconnect:(UIScene *)scene {\n    // Called as the scene is being released by the system.\n    // This occurs shortly after the scene enters the background, or when its session is discarded.\n    // Release any resources associated with this scene that can be re-created the next time the scene connects.\n    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n}\n\n\n- (void)sceneDidBecomeActive:(UIScene *)scene {\n    // Called when the scene has moved from an inactive state to an active state.\n    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n}\n\n\n- (void)sceneWillResignActive:(UIScene *)scene {\n    // Called when the scene will move from an active state to an inactive state.\n    // This may occur due to temporary interruptions (ex. an incoming phone call).\n}\n\n\n- (void)sceneWillEnterForeground:(UIScene *)scene {\n    // Called as the scene transitions from the background to the foreground.\n    // Use this method to undo the changes made on entering the background.\n}\n\n\n- (void)sceneDidEnterBackground:(UIScene *)scene {\n    // Called as the scene transitions from the foreground to the background.\n    // Use this method to save data, release shared resources, and store enough scene-specific state information\n    // to restore the scene back to its current state.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp/src/main.m",
    "content": "//\n//  main.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    NSString * appDelegateClassName;\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n        appDelegateClassName = NSStringFromClass([AppDelegate class]);\n    }\n    return UIApplicationMain(argc, argv, nil, appDelegateClassName);\n}\n"
  },
  {
    "path": "tests/projects/objc/iosapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n    set_plat(\"iphoneos\")\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import <test/test.h>\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    NSLog(@\"add(1, 2): %d\", add(1, 2));\n    Test* t = [[Test alloc] init];\n    [t hello];\n    return YES;\n}\n\n\n#pragma mark - UISceneSession lifecycle\n\n\n- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {\n    // Called when a new scene session is being created.\n    // Use this method to select a configuration to create the new scene with.\n    return [[UISceneConfiguration alloc] initWithName:@\"Default Configuration\" sessionRole:connectingSceneSession.role];\n}\n\n\n- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {\n    // Called when the user discards a scene session.\n    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/SceneDelegate.h",
    "content": "//\n//  SceneDelegate.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>\n\n@property (strong, nonatomic) UIWindow * window;\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/SceneDelegate.m",
    "content": "#import \"SceneDelegate.h\"\n\n@interface SceneDelegate ()\n\n@end\n\n@implementation SceneDelegate\n\n\n- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n}\n\n\n- (void)sceneDidDisconnect:(UIScene *)scene {\n    // Called as the scene is being released by the system.\n    // This occurs shortly after the scene enters the background, or when its session is discarded.\n    // Release any resources associated with this scene that can be re-created the next time the scene connects.\n    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n}\n\n\n- (void)sceneDidBecomeActive:(UIScene *)scene {\n    // Called when the scene has moved from an inactive state to an active state.\n    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n}\n\n\n- (void)sceneWillResignActive:(UIScene *)scene {\n    // Called when the scene will move from an active state to an inactive state.\n    // This may occur due to temporary interruptions (ex. an incoming phone call).\n}\n\n\n- (void)sceneWillEnterForeground:(UIScene *)scene {\n    // Called as the scene transitions from the background to the foreground.\n    // Use this method to undo the changes made on entering the background.\n}\n\n\n- (void)sceneDidEnterBackground:(UIScene *)scene {\n    // Called as the scene transitions from the foreground to the background.\n    // Use this method to save data, release shared resources, and store enough scene-specific state information\n    // to restore the scene back to its current state.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/app/main.m",
    "content": "//\n//  main.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    NSString * appDelegateClassName;\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n        appDelegateClassName = NSStringFromClass([AppDelegate class]);\n    }\n    return UIApplicationMain(argc, argv, nil, appDelegateClassName);\n}\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/framework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 xmake.io. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/framework/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n\n@interface Test : NSObject\n- (void)hello;\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/src/framework/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n\n@implementation Test\n\n- (void)hello {\n    NSLog(@\"hello xmake!\");\n}\n\n@end\n\n\n"
  },
  {
    "path": "tests/projects/objc/iosapp_with_framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/framework/test.m\")\n    add_files(\"src/framework/Info.plist\")\n    add_headerfiles(\"src/framework/test.h\")\n\ntarget(\"demo\")\n    add_rules(\"xcode.application\")\n    add_deps(\"test\")\n    add_files(\"src/app/*.m\", \"src/app/**.storyboard\", \"src/app/*.xcassets\")\n    add_files(\"src/app/Info.plist\")\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test3\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test3\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test3\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test3\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test3\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test3 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/main.m",
    "content": "//\n//  main.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "tests/projects/objc/macapp/src/test.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.files.user-selected.read-only</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nrule(\"test\")\n    add_deps(\"xcode.application\")\n\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n    add_rules(\"test\")\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import <test/test.h>\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n    add(1, 2);\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test3\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test3\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test3\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test3\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test3\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test3 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/app/main.m",
    "content": "//\n//  main.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/framework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/framework/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/src/framework/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/framework/test.m\")\n    add_files(\"src/framework/Info.plist\")\n    add_headerfiles(\"src/framework/test.h\")\n\ntarget(\"demo\")\n    add_rules(\"xcode.application\")\n    add_deps(\"test\")\n    add_files(\"src/app/*.m\", \"src/app/**.storyboard\", \"src/app/*.xcassets\")\n    add_files(\"src/app/Info.plist\")\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#include \"test.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n    add(1, 2);\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test3\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test3\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test3\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test3\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test3\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test3 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/main.m",
    "content": "//\n//  main.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/test.c",
    "content": "#include \"test.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/test.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.files.user-selected.read-only</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/src/test.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\n__attribute__((visibility(\"default\"))) int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/objc/macapp_with_shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"shared\")\n    add_files(\"src/test.c\")\n\ntarget(\"demo\")\n    add_rules(\"xcode.application\")\n    add_deps(\"test\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n"
  },
  {
    "path": "tests/projects/objc/metal_app/.gitignore",
    "content": "# See LICENSE folder for this sample’s licensing information.\n#\n# Apple sample code gitignore configuration.\n\n# Finder\n.DS_Store\n\n# Xcode - User files\nxcuserdata/\n\n**/*.xcodeproj/project.xcworkspace/*\n!**/*.xcodeproj/project.xcworkspace/xcshareddata\n\n**/*.xcodeproj/project.xcworkspace/xcshareddata/*\n!**/*.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings\n\n**/*.playground/playground.xcworkspace/*\n!**/*.playground/playground.xcworkspace/xcshareddata\n\n**/*.playground/playground.xcworkspace/xcshareddata/*\n!**/*.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/AAPLAppDelegate.h",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nHeader for our iOS & tvOS application delegate\n*/\n\n#import <UIKit/UIKit.h>\n\n@interface AAPLAppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/AAPLAppDelegate.m",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nImplementation of our iOS & tvOS application delegate\n*/\n\n#import \"AAPLAppDelegate.h\"\n\n@implementation AAPLAppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    return YES;\n}\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/AAPLViewController.h",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nHeader for our our cross-platform view controller\n*/\n\n#if defined(TARGET_IOS) || defined(TARGET_TVOS)\n@import UIKit;\n#define PlatformViewController UIViewController\n#else\n@import AppKit;\n#define PlatformViewController NSViewController\n#endif\n\n@import MetalKit;\n\n#import \"AAPLRenderer.h\"\n\n// Our view controller\n@interface AAPLViewController : PlatformViewController\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/AAPLViewController.m",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nImplementation of our cross-platform view controller\n*/\n\n#import \"AAPLViewController.h\"\n#import \"AAPLRenderer.h\"\n\n@implementation AAPLViewController\n{\n    MTKView *_view;\n\n    AAPLRenderer *_renderer;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n\n    // Set the view to use the default device\n    _view = (MTKView *)self.view;\n\n    _view.device = MTLCreateSystemDefaultDevice();\n\n    NSAssert(_view.device, @\"Metal is not supported on this device\");\n\n    _renderer = [[AAPLRenderer alloc] initWithMetalKitView:_view];\n\n    NSAssert(_renderer, @\"Renderer failed initialization\");\n\n    // Initialize our renderer with the view size\n    [_renderer mtkView:_view drawableSizeWillChange:_view.drawableSize];\n\n    _view.delegate = _renderer;\n}\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/iOS/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/iOS/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11762\" systemVersion=\"16E138\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BV1-FR-VrT\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11757\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tXr-a1-R10\">\n            <objects>\n                <viewController id=\"BV1-FR-VrT\" customClass=\"AAPLViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"8aa-yV-Osq\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"qHh-Mt-9TT\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"3se-qz-xqx\" customClass=\"MTKView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"SZV-WD-TEh\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/iOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UIStatusBarHidden</key>\n\t<true/>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/macOS/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14724.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"14724.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"Hello Triangle\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Hello Triangle\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About Hello Triangle\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide Hello Triangle\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit Hello Triangle\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\"/>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\"/>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\"/>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\"/>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\"/>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"Hello Triangle Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </application>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Hello Triangle\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"c2Y-5V-HmV\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"AAPLViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" wantsLayer=\"YES\" id=\"m2S-Jp-Qdl\" customClass=\"MTKView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"817\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/macOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/main.m",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nApplication entry point for all platforms\n*/\n\n#if defined(TARGET_IOS) || defined(TARGET_TVOS)\n#import <UIKit/UIKit.h>\n#import <TargetConditionals.h>\n#import <Availability.h>\n#import \"AAPLAppDelegate.h\"\n#else\n#import <Cocoa/Cocoa.h>\n#endif\n\n#if defined(TARGET_IOS) || defined(TARGET_TVOS)\n\nint main(int argc, char * argv[]) {\n\n#if TARGET_OS_SIMULATOR && (!defined(__IPHONE_13_0) ||  !defined(__TVOS_13_0))\n#error No simulator support for Metal API for this SDK version.  Must build for a device\n#endif\n\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AAPLAppDelegate class]));\n    }\n}\n\n#elif defined(TARGET_MACOS)\n\nint main(int argc, const char * argv[]) {\n    return NSApplicationMain(argc, argv);\n}\n\n#endif\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/tvOS/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.Storyboard\" version=\"3.0\" toolsVersion=\"11762\" systemVersion=\"16E138\" targetRuntime=\"AppleTV\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BV1-FR-VrT\">\n    <device id=\"appleTV\" orientation=\"landscape\">\n        <adaptation id=\"light\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"tvOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11757\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tXr-a1-R10\">\n            <objects>\n                <viewController id=\"BV1-FR-VrT\" customClass=\"AAPLViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"8aa-yV-Osq\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"qHh-Mt-9TT\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"3se-qz-xqx\" customClass=\"MTKView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1080\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"SZV-WD-TEh\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Application/tvOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UIUserInterfaceStyle</key>\n\t<string>Automatic</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Configuration/SampleCode.xcconfig",
    "content": "//\n// See LICENSE folder for this sample’s licensing information.\n//\n// SampleCode.xcconfig\n//\n\n// The `SAMPLE_CODE_DISAMBIGUATOR` configuration is to make it easier to build\n// and run a sample code project. Once you set your project's development team,\n// you'll have a unique bundle identifier. This is because the bundle identifier\n// is derived based on the 'SAMPLE_CODE_DISAMBIGUATOR' value. Do not use this\n// approach in your own projects—it's only useful for sample code projects because\n// they are frequently downloaded and don't have a development team set.\nSAMPLE_CODE_DISAMBIGUATOR=${DEVELOPMENT_TEAM}\n"
  },
  {
    "path": "tests/projects/objc/metal_app/HelloTriangle.xcodeproj/.xcodesamplecode.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<array/>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/HelloTriangle.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t3A05CBE01F731ABB00CA21B1 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A1F1B411F0338CF001622B3 /* MetalKit.framework */; };\n\t\t3A05CBE11F731AC000CA21B1 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */; };\n\t\t3A1F1B391F033765001622B3 /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; };\n\t\t3A1F1B3D1F033827001622B3 /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; };\n\t\t3A1F1B3E1F033846001622B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; };\n\t\t3A1F1B3F1F033846001622B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; };\n\t\t3A1F1B441F033EF3001622B3 /* AAPLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */; };\n\t\t3A3532941E99974500C194AD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532931E99974500C194AD /* main.m */; };\n\t\t3A35329D1E99974500C194AD /* AAPLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A35329C1E99974500C194AD /* AAPLViewController.m */; };\n\t\t3A3532A01E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A35329E1E99974500C194AD /* Main.storyboard */; };\n\t\t3A3532A31E99974500C194AD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532A11E99974500C194AD /* LaunchScreen.storyboard */; };\n\t\t3A3532B91E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532B71E99974500C194AD /* Main.storyboard */; };\n\t\t3A3532CC1E99974500C194AD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A3532CA1E99974500C194AD /* Main.storyboard */; };\n\t\t3A3532CE1E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; };\n\t\t3A3532CF1E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; };\n\t\t3A3532D01E99974500C194AD /* AAPLRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532851E99974500C194AD /* AAPLRenderer.m */; };\n\t\t3ACD21351EAE60D2000D1DED /* AAPLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */; };\n\t\t63E77A181ED2059A00E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; };\n\t\t63E77A191ED2059E00E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; };\n\t\t63E77A1A1ED205A200E1E542 /* AAPLShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A3532871E99974500C194AD /* AAPLShaders.metal */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t328A8E964EC41C65EC8AF01A /* LICENSE.txt */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE.txt; sourceTree = \"<group>\"; };\n\t\t3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = ../../../../iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };\n\t\t3A1F1B411F0338CF001622B3 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = ../../../../AppleTVOS.platform/Developer/SDKs/AppleTVOS11.0.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };\n\t\t3A3532841E99974500C194AD /* AAPLRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLRenderer.h; sourceTree = \"<group>\"; };\n\t\t3A3532851E99974500C194AD /* AAPLRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AAPLRenderer.m; sourceTree = \"<group>\"; };\n\t\t3A3532861E99974500C194AD /* AAPLShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLShaderTypes.h; sourceTree = \"<group>\"; };\n\t\t3A3532871E99974500C194AD /* AAPLShaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = AAPLShaders.metal; sourceTree = \"<group>\"; };\n\t\t3A35328F1E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3A3532931E99974500C194AD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t3A35329B1E99974500C194AD /* AAPLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AAPLViewController.h; sourceTree = \"<group>\"; };\n\t\t3A35329C1E99974500C194AD /* AAPLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AAPLViewController.m; sourceTree = \"<group>\"; };\n\t\t3A35329F1E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t3A3532A21E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t3A3532A41E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t3A3532A91E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3A3532B81E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t3A3532BA1E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t3A3532BF1E99974500C194AD /* HelloTriangle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloTriangle.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3A3532CB1E99974500C194AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t3A3532CD1E99974500C194AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t3ACD21331EAE60D2000D1DED /* AAPLAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AAPLAppDelegate.h; sourceTree = \"<group>\"; };\n\t\t3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AAPLAppDelegate.m; sourceTree = \"<group>\"; };\n\t\t3ED283CC1EC2C6D200A23F58 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t907FE32A28789CDAFD777257 /* SampleCode.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = SampleCode.xcconfig; path = Configuration/SampleCode.xcconfig; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t3A35328C1E99974500C194AD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A05CBE11F731AC000CA21B1 /* MetalKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532A61E99974500C194AD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A05CBE01F731ABB00CA21B1 /* MetalKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532BC1E99974500C194AD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t3A1F1B351F0336A8001622B3 /* iOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A35329E1E99974500C194AD /* Main.storyboard */,\n\t\t\t\t3A3532A11E99974500C194AD /* LaunchScreen.storyboard */,\n\t\t\t\t3A3532A41E99974500C194AD /* Info.plist */,\n\t\t\t);\n\t\t\tpath = iOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A1F1B361F0336DB001622B3 /* macOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532CA1E99974500C194AD /* Main.storyboard */,\n\t\t\t\t3A3532CD1E99974500C194AD /* Info.plist */,\n\t\t\t);\n\t\t\tpath = macOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A1F1B371F0336F4001622B3 /* tvOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532B71E99974500C194AD /* Main.storyboard */,\n\t\t\t\t3A3532BA1E99974500C194AD /* Info.plist */,\n\t\t\t);\n\t\t\tpath = tvOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A35327E1E99974500C194AD = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3ED283CC1EC2C6D200A23F58 /* README.md */,\n\t\t\t\t3A3532831E99974500C194AD /* Renderer */,\n\t\t\t\t3A3532911E99974500C194AD /* Application */,\n\t\t\t\t3AE289861EEA0A9100DF4C9A /* Frameworks */,\n\t\t\t\t3A3532901E99974500C194AD /* Products */,\n\t\t\t\tF4F7FAFBBA6575359FC81F34 /* Configuration */,\n\t\t\t\t9772A968083C4C14D4BE84E1 /* LICENSE */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532831E99974500C194AD /* Renderer */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532841E99974500C194AD /* AAPLRenderer.h */,\n\t\t\t\t3A3532851E99974500C194AD /* AAPLRenderer.m */,\n\t\t\t\t3A3532861E99974500C194AD /* AAPLShaderTypes.h */,\n\t\t\t\t3A3532871E99974500C194AD /* AAPLShaders.metal */,\n\t\t\t);\n\t\t\tpath = Renderer;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532901E99974500C194AD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A35328F1E99974500C194AD /* HelloTriangle.app */,\n\t\t\t\t3A3532A91E99974500C194AD /* HelloTriangle.app */,\n\t\t\t\t3A3532BF1E99974500C194AD /* HelloTriangle.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532911E99974500C194AD /* Application */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3ACD21331EAE60D2000D1DED /* AAPLAppDelegate.h */,\n\t\t\t\t3ACD21341EAE60D2000D1DED /* AAPLAppDelegate.m */,\n\t\t\t\t3A35329B1E99974500C194AD /* AAPLViewController.h */,\n\t\t\t\t3A35329C1E99974500C194AD /* AAPLViewController.m */,\n\t\t\t\t3A3532931E99974500C194AD /* main.m */,\n\t\t\t\t3A1F1B361F0336DB001622B3 /* macOS */,\n\t\t\t\t3A1F1B371F0336F4001622B3 /* tvOS */,\n\t\t\t\t3A1F1B351F0336A8001622B3 /* iOS */,\n\t\t\t);\n\t\t\tpath = Application;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3AE289861EEA0A9100DF4C9A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A05CBDE1F731AB800CA21B1 /* MetalKit.framework */,\n\t\t\t\t3A1F1B411F0338CF001622B3 /* MetalKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9772A968083C4C14D4BE84E1 /* LICENSE */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t328A8E964EC41C65EC8AF01A /* LICENSE.txt */,\n\t\t\t);\n\t\t\tpath = LICENSE;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF4F7FAFBBA6575359FC81F34 /* Configuration */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t907FE32A28789CDAFD777257 /* SampleCode.xcconfig */,\n\t\t\t);\n\t\t\tname = Configuration;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t3A35328E1E99974500C194AD /* HelloTriangle-iOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3A3532E21E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-iOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3A35328B1E99974500C194AD /* Sources */,\n\t\t\t\t3A35328C1E99974500C194AD /* Frameworks */,\n\t\t\t\t3A35328D1E99974500C194AD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"HelloTriangle-iOS\";\n\t\t\tproductName = iOS;\n\t\t\tproductReference = 3A35328F1E99974500C194AD /* HelloTriangle.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t3A3532A81E99974500C194AD /* HelloTriangle-tvOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3A3532E51E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-tvOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3A3532A51E99974500C194AD /* Sources */,\n\t\t\t\t3A3532A61E99974500C194AD /* Frameworks */,\n\t\t\t\t3A3532A71E99974500C194AD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"HelloTriangle-tvOS\";\n\t\t\tproductName = tvOS;\n\t\t\tproductReference = 3A3532A91E99974500C194AD /* HelloTriangle.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t3A3532BE1E99974500C194AD /* HelloTriangle-macOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3A3532E81E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-macOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3A3532BB1E99974500C194AD /* Sources */,\n\t\t\t\t3A3532BC1E99974500C194AD /* Frameworks */,\n\t\t\t\t3A3532BD1E99974500C194AD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"HelloTriangle-macOS\";\n\t\t\tproductName = macOS;\n\t\t\tproductReference = 3A3532BF1E99974500C194AD /* HelloTriangle.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t3A35327F1E99974500C194AD /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = Apple;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t3A35328E1E99974500C194AD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t3A3532A81E99974500C194AD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t3A3532BE1E99974500C194AD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3;\n\t\t\t\t\t\tDevelopmentTeam = 43AAQM58X3;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 3A3532821E99974500C194AD /* Build configuration list for PBXProject \"HelloTriangle\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 3A35327E1E99974500C194AD;\n\t\t\tproductRefGroup = 3A3532901E99974500C194AD /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t3A3532BE1E99974500C194AD /* HelloTriangle-macOS */,\n\t\t\t\t3A35328E1E99974500C194AD /* HelloTriangle-iOS */,\n\t\t\t\t3A3532A81E99974500C194AD /* HelloTriangle-tvOS */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t3A35328D1E99974500C194AD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A3532A01E99974500C194AD /* Main.storyboard in Resources */,\n\t\t\t\t3A3532A31E99974500C194AD /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532A71E99974500C194AD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A3532B91E99974500C194AD /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532BD1E99974500C194AD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A3532CC1E99974500C194AD /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t3A35328B1E99974500C194AD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t63E77A181ED2059A00E1E542 /* AAPLShaders.metal in Sources */,\n\t\t\t\t3A35329D1E99974500C194AD /* AAPLViewController.m in Sources */,\n\t\t\t\t3A3532941E99974500C194AD /* main.m in Sources */,\n\t\t\t\t3A3532CE1E99974500C194AD /* AAPLRenderer.m in Sources */,\n\t\t\t\t3ACD21351EAE60D2000D1DED /* AAPLAppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532A51E99974500C194AD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t63E77A191ED2059E00E1E542 /* AAPLShaders.metal in Sources */,\n\t\t\t\t3A3532CF1E99974500C194AD /* AAPLRenderer.m in Sources */,\n\t\t\t\t3A1F1B391F033765001622B3 /* AAPLViewController.m in Sources */,\n\t\t\t\t3A1F1B3F1F033846001622B3 /* main.m in Sources */,\n\t\t\t\t3A1F1B441F033EF3001622B3 /* AAPLAppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3A3532BB1E99974500C194AD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3A1F1B3D1F033827001622B3 /* AAPLViewController.m in Sources */,\n\t\t\t\t63E77A1A1ED205A200E1E542 /* AAPLShaders.metal in Sources */,\n\t\t\t\t3A1F1B3E1F033846001622B3 /* main.m in Sources */,\n\t\t\t\t3A3532D01E99974500C194AD /* AAPLRenderer.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t3A35329E1E99974500C194AD /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t3A35329F1E99974500C194AD /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532A11E99974500C194AD /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532A21E99974500C194AD /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532B71E99974500C194AD /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532B81E99974500C194AD /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3A3532CA1E99974500C194AD /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t3A3532CB1E99974500C194AD /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t3A3532E01E99974500C194AD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3A3532E11E99974500C194AD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3A3532E31E99974500C194AD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(SDKROOT)/System/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\tTARGET_IOS,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Application/iOS/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3A3532E41E99974500C194AD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(SDKROOT)/System/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = TARGET_IOS;\n\t\t\t\tINFOPLIST_FILE = Application/iOS/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3A3532E61E99974500C194AD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(SDKROOT)/System/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\tTARGET_TVOS,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Application/tvOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3A3532E71E99974500C194AD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(SDKROOT)/System/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = TARGET_TVOS;\n\t\t\t\tINFOPLIST_FILE = Application/tvOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.HelloTriangle${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3A3532E91E99974500C194AD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Mac Developer\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 43AAQM58X3;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\tTARGET_MACOS,\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Application/macOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.12;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.$(PRODUCT_NAME)${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3A3532EA1E99974500C194AD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 907FE32A28789CDAFD777257 /* SampleCode.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Mac Developer\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 43AAQM58X3;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = TARGET_MACOS;\n\t\t\t\tINFOPLIST_FILE = Application/macOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.12;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.apple-samplecode.$(PRODUCT_NAME)${SAMPLE_CODE_DISAMBIGUATOR}\";\n\t\t\t\tPRODUCT_NAME = HelloTriangle;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t3A3532821E99974500C194AD /* Build configuration list for PBXProject \"HelloTriangle\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3A3532E01E99974500C194AD /* Debug */,\n\t\t\t\t3A3532E11E99974500C194AD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3A3532E21E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-iOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3A3532E31E99974500C194AD /* Debug */,\n\t\t\t\t3A3532E41E99974500C194AD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3A3532E51E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-tvOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3A3532E61E99974500C194AD /* Debug */,\n\t\t\t\t3A3532E71E99974500C194AD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3A3532E81E99974500C194AD /* Build configuration list for PBXNativeTarget \"HelloTriangle-macOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3A3532E91E99974500C194AD /* Debug */,\n\t\t\t\t3A3532EA1E99974500C194AD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 3A35327F1E99974500C194AD /* Project object */;\n}\n"
  },
  {
    "path": "tests/projects/objc/metal_app/HelloTriangle.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>BuildSystemType</key>\n\t<string>Latest</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/objc/metal_app/LICENSE/LICENSE.txt",
    "content": "Copyright © 2020 Apple Inc. \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "tests/projects/objc/metal_app/README.md",
    "content": "# Using a Render Pipeline to Render Primitives\n\nRender a simple 2D triangle.\n\n## Overview\n\nIn [Using Metal to Draw a View’s Contents](https://developer.apple.com/documentation/metal/basic_tasks_and_concepts/using_metal_to_draw_a_view_s_contents), you learned how to set up an `MTKView` object and to change the view's contents using a render pass.\nThat sample simply erased the view's contents to a background color.\nThis sample shows you how to configure a render pipeline and use it as part of the render pass to draw a simple 2D colored triangle into the view.\nThe sample supplies a position and color for each vertex, and the render pipeline uses that data to render the triangle, interpolating color values between the colors specified for the triangle's vertices.\n\n![Simple 2D Triangle Vertices](Documentation/2DTriangleVertices.png)\n\nThe Xcode project contains schemes for running the sample on macOS, iOS, and tvOS.\n\n## Understand the Metal Render Pipeline\n\nA *render pipeline* processes drawing commands and writes data into a render pass’s targets.\n A render pipeline has many stages, some programmed using shaders and others with fixed or configurable behavior.\nThis sample focuses on the three main stages of the pipeline: the vertex stage, the rasterization stage, and the fragment stage.\nThe vertex stage and fragment stage are programmable, so you write functions for them in Metal Shading Language (MSL).\nThe rasterization stage has fixed behavior.\n\n**Figure 1** Main stages of the Metal graphics render pipeline\n![Main Stages of the Metal Graphics Render Pipeline](Documentation/SimplePipeline.png)\n\nRendering starts with a drawing command, which includes a vertex count and what kind of primitive to render. For example, here's the drawing command from this sample:\n\n``` objective-c\n// Draw the triangle.\n[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle\n                  vertexStart:0\n                  vertexCount:3];\n```\n\nThe vertex stage provides data for each vertex. When enough vertices have been processed, the render pipeline rasterizes the primitive, determining which pixels in the render targets lie within the boundaries of the primitive. The fragment stage determines the values to write into the render targets for those pixels.\n\nIn the rest of this sample, you will see how to write the vertex and fragment functions, how to create the render pipeline state object, and finally, how to encode a draw command that uses this pipeline.\n\n## Decide How Data is Processed by Your Custom Render Pipeline\n\nA vertex function generates data for a single vertex and a fragment function generates data for a single fragment, but you decide how they work.\nYou configure the stages of the pipeline with a goal in mind, meaning that you know what you want the pipeline to generate and how it generates those results.\n\nDecide what data to pass into your render pipeline and what data is passed to later stages of the pipeline. There are typically three places where you do this:\n\n- The inputs to the pipeline, which are provided by your app and passed to the vertex stage.\n- The outputs of the vertex stage, which is passed to the rasterization stage.\n- The inputs to the fragment stage, which are provided by your app or generated by the rasterization stage.\n\nIn this sample, the input data for the pipeline is the position of a vertex and its color. To demonstrate the kind of transformation you typically perform in a vertex function, input coordinates are defined in a custom coordinate space, measured in pixels from the center of the view. These coordinates need to be translated into Metal's coordinate system.\n\nDeclare an `AAPLVertex` structure, using SIMD vector types to hold the position and color data.\nTo share a single definition for how the structure is laid out in memory, declare the structure in a common header and import it in both the Metal shader and the app.\n\n``` objective-c\ntypedef struct\n{\n    vector_float2 position;\n    vector_float4 color;\n} AAPLVertex;\n```\n\nSIMD types are commonplace in Metal Shading Language, and you should also use them in your app using the simd library.\nSIMD types contain multiple channels of a particular data type, so declaring the position as a `vector_float2` means it contains two 32-bit float values (which will hold the x and y coordinates.)\nColors are stored using a `vector_float4`, so they have four channels – red, green, blue, and alpha.\n\nIn the app, the input data is specified using a constant array:\n\n``` objective-c\nstatic const AAPLVertex triangleVertices[] =\n{\n    // 2D positions,    RGBA colors\n    { {  250,  -250 }, { 1, 0, 0, 1 } },\n    { { -250,  -250 }, { 0, 1, 0, 1 } },\n    { {    0,   250 }, { 0, 0, 1, 1 } },\n};\n```\n\nThe vertex stage generates data for a vertex, so it needs to provide a color and a transformed position.\nDeclare a `RasterizerData` structure containing a position and a color value, again using SIMD types. \n\n``` metal\nstruct RasterizerData\n{\n    // The [[position]] attribute of this member indicates that this value\n    // is the clip space position of the vertex when this structure is\n    // returned from the vertex function.\n    float4 position [[position]];\n\n    // Since this member does not have a special attribute, the rasterizer\n    // interpolates its value with the values of the other triangle vertices\n    // and then passes the interpolated value to the fragment shader for each\n    // fragment in the triangle.\n    float4 color;\n};\n```\n\nThe output position (described in detail below) must be defined as a `vector_float4`. The color is declared as it was in the input data structure.\n\nYou need to tell Metal which field in the rasterization data provides position data, because Metal doesn't enforce any particular naming convention for fields in your struct.\nAnnotate the `position` field with the `[[position]]` attribute qualifier to declare that this field holds the output position.\n\nThe fragment function simply passes the rasterization stage's data to later stages so it doesn't need any additional arguments.\n\n## Declare the Vertex Function\n\nDeclare the vertex function, including its input arguments and the data it outputs.\nMuch like compute functions were declared using the `kernel` keyword, you declare a vertex function using the `vertex` keyword.\n\n``` metal\nvertex RasterizerData\nvertexShader(uint vertexID [[vertex_id]],\n             constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],\n             constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])\n```\n\nThe first argument, `vertexID`, uses the `[[vertex_id]]` attribute qualifier, which is another Metal keyword.\nWhen you execute a render command, the GPU calls your vertex function multiple times, generating a unique value for each vertex.\n\nThe second argument, `vertices`, is an array that contains the vertex data, using the `AAPLVertex` struct previously defined.\n\nTo transform the position into Metal's coordinates, the function needs the size of the viewport (in pixels) that the triangle is being drawn into, so this is stored in the `viewportSizePointer` argument.\n\nThe second and third arguments have the `[[buffer(n)]]` attribute qualifier.\nBy default, Metal assigns slots in the argument table for each parameter automatically.\nWhen you add the `[[buffer(n)]]` qualifier to a buffer argument, you tell Metal explicitly which slot to use.\nDeclaring slots explicitly can make it easier to revise your shaders without also needing to change your app code.\nDeclare the constants for the two indicies in the shared header file.\n\nThe function's output is a `RasterizerData` struct.\n\n## Write the Vertex Function\n\nYour vertex function must generate both fields of the output struct. \nUse the `vertexID` argument to index into the `vertices` array and read the input data for the vertex.\nAlso, retrieve the viewport dimensions.\n\n``` metal\nfloat2 pixelSpacePosition = vertices[vertexID].position.xy;\n\n// Get the viewport size and cast to float.\nvector_float2 viewportSize = vector_float2(*viewportSizePointer);\n\n```\n\nVertex functions must provide position data in *clip-space coordinates*, which are 3D points specified using a four-dimensional homogenous vector (`x,y,z,w`). The rasterization stage takes the output position and divides the `x`,`y`, and `z` coordinates by `w` to generate a 3D point in *normalized device coordinates*. Normalized device coordinates are independent of viewport size.\n\n**Figure 2** Normalized device coordinate system\n![Normalized device coordinate system](Documentation/normalizeddevicecoords.png)\n\nNormalized device coordinates use a *left-handed coordinate system* and map to positions in the viewport.\nPrimitives are clipped to a box in this coordinate system and then rasterized.\nThe lower-left corner of the clipping box is at an `(x,y)` coordinate of `(-1.0,-1.0)` and the upper-right corner is at `(1.0,1.0)`.\nPositive-z values point away from the camera (into the screen.)\nThe visible portion of the `z` coordinate is between `0.0` (the near clipping plane) and `1.0` (the far clipping plane).\n\nTransform the input coordinate system to the normalized device coordinate system.\n\n![Vertex function coordinate transformation](Documentation/metal-coordinate-transformation.png)\n\nBecause this is a 2D application and does not need homogenous coordinates, first write a default value to the output coordinate, with the the `w` value is set to `1.0` and the other coordinates set to `0.0`.\nThis means that the coordinates are already in the normalized device coordinate space and the vertex function should generate (x,y) coordinates in that coordinate space.\nDivide the input position by half the viewport size to generate normalized device coordinates.\nSince this calculation is performed using SIMD types, both channels can be divided at the same time using a single line of code.\nPerform the divide and put the results in the x and y channels of the output position. \n\n``` metal\nout.position = vector_float4(0.0, 0.0, 0.0, 1.0);\nout.position.xy = pixelSpacePosition / (viewportSize / 2.0);\n```\n\nFinally, copy the color value into the `out.color` return value.\n\n``` metal\nout.color = vertices[vertexID].color;\n```\n\n## Write a Fragment Function\n\nA *fragment* is a possible change to the render targets. The rasterizer determines which pixels of the render target are covered by the primitive.\nOnly fragments whose pixel centers are inside the triangle are rendered.\n\n**Figure 3** Fragments generated by the rasterization stage\n![Fragments generated by the rasterization stage](Documentation/Rasterization.png)\n\nA fragment function processes incoming information from the rasterizer for a single position and calculates output values for each of the render targets. These fragment values are processed by later stages in the pipeline, eventually being written to the render targets.\n\n- Note: The reason a fragment is called a possible change is because the pipeline stages after the fragment stage can be configured to reject some fragments or change what gets written to the render targets. In this sample, all values calculated by the fragment stage are written as-is to the render target.\n\nThe fragment shader in this sample receives the same parameters that were declared in the vertex shader's output. Declare the fragment function using the `fragment` keyword. It takes a single argument, the same `RasterizerData` structure that was provided by the vertex stage. Add the `[[stage_in]]` attribute qualifier to indicate that this argument is generated by the rasterizer.\n\n``` metal\nfragment float4 fragmentShader(RasterizerData in [[stage_in]])\n```\n\nIf your fragment function writes to multiple render targets, it must declare a struct with fields for each render target.\nBecause this sample only has a single render target, you specify a floating-point vector directly as the function's output. This output is the color to be written to the render target.\n\nThe rasterization stage calculates values for each fragment's arguments and calls the fragment function with them.\nThe rasterization stage calculates its color argument as a blend of the colors at the triangle's vertices.\nThe closer a fragment is to a vertex, the more that vertex contributes to the final color.\n\n**Figure 4** Interpolated fragment colors\n![Interpolated Fragment Colors](Documentation/Interpolation.png)\n\nReturn the interpolated color as the function's output. \n\n``` metal\nreturn in.color;\n```\n\n## Create a Render Pipeline State Object\n\nNow that the functions are complete, you can create a render pipeline that uses them.\nFirst, get the default library and obtain a [`MTLFunction`][MTLFunction] object for each function.\n\n``` objective-c\nid<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];\n\nid<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@\"vertexShader\"];\nid<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@\"fragmentShader\"];\n```\n\nNext, create a [`MTLRenderPipelineState`][MTLRenderPipelineState] object.\nRender pipelines have more stages to configure, so you use a [`MTLRenderPipelineDescriptor`][MTLRenderPipelineDescriptor] to configure the pipeline.\n\n``` objective-c\nMTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];\npipelineStateDescriptor.label = @\"Simple Pipeline\";\npipelineStateDescriptor.vertexFunction = vertexFunction;\npipelineStateDescriptor.fragmentFunction = fragmentFunction;\npipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;\n\n_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor\n                                                         error:&error];\n```\n\nIn addition to specifying the vertex and fragment functions, you also declare the *pixel format* of all render targets that the pipeline will draw into.\nA pixel format ([`MTLPixelFormat`][MTLPixelFormat]) defines the memory layout of pixel data.\nFor simple formats, this definition includes the number of bytes per pixel, the number of channels of data stored in a pixel, and the bit layout of those channels.\nSince this sample only has one render target and it is provided by the view, copy the view's pixel format into the render pipeline descriptor.\nYour render pipeline state must use a pixel format that is compatible with the one specified by the render pass.\nIn this sample, the render pass and the pipeline state object both use the view's pixel format, so they are always the same.\n\nWhen Metal creates the render pipeline state object, the pipeline is configured to convert the fragment function's output into the render target's pixel format.\nIf you want to target a different pixel format, you need to create a different pipeline state object.\nYou can reuse the same shaders in multiple pipelines targeting different pixel formats.\n\n \n## Set a Viewport\n\nNow that you have the render pipeline state object for the pipeline, you'll render the triangle. You do this using a render command encoder. First, set the viewport, so that Metal knows which part of the render target you want to draw into.\n\n``` objective-c\n// Set the region of the drawable to draw into.\n[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }];\n```\n\n## Set the Render Pipeline State\n\nSet the render pipeline state for the pipeline you want to use.\n\n``` objective-c\n[renderEncoder setRenderPipelineState:_pipelineState];\n```\n\n## Send Argument Data to the Vertex Function\n\nOften, you use buffers ([`MTLBuffer`][MTLBuffer]) to pass data to shaders.\nHowever, when you need to pass only a small amount of data to the vertex function, as is the case here, copy the data directly into the command buffer.\n\nThe sample copies data for both parameters into the command buffer.\nThe vertex data is copied from an array defined in the sample.\nThe viewport data is copied from the same variable that you used to set the viewport. \n\nIn this sample, the fragment function uses only the data it receives from the rasterizer, so there are no arguments to set.\n\n``` objective-c\n[renderEncoder setVertexBytes:triangleVertices\n                       length:sizeof(triangleVertices)\n                      atIndex:AAPLVertexInputIndexVertices];\n\n[renderEncoder setVertexBytes:&_viewportSize\n                       length:sizeof(_viewportSize)\n                      atIndex:AAPLVertexInputIndexViewportSize];\n```\n\n\n## Encode the Drawing Command\n\nSpecify the kind of primitive, the starting index, and the number of vertices.\nWhen the triangle is rendered, the vertex function is called with values of 0, 1, and 2 for the `vertexID` argument.\n\n``` objective-c\n// Draw the triangle.\n[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle\n                  vertexStart:0\n                  vertexCount:3];\n```\n\nAs with Drawing to the Screen Using Metal, you end the encoding process and commit the command buffer.\nHowever, you could encode more render commands using the same set of steps.\nThe final image is rendered as if the commands were processed in the order they were specified.\n(For performance, the GPU is allowed to process commands or even parts of commands in parallel, so long as the final result appears to have been rendered in order. )\n\n## Experiment with the Color Interpolation\n\nIn this sample, color values were interpolated across the triangle.\nThat's often what you want, but sometimes you want a value to be generated by one vertex and remain constant across the whole primitive.\nSpecify the `flat` attribute qualifier on an output of the vertex function to do this.\nTry this now.\nFind the definition of `RasterizerData` in the sample project and add the `[[flat]]` qualifier to its `color` field.\n\n`float4 color [[flat]];`\n\nRun the sample again.\nThe render pipeline uses the color value from the first vertex (called the *provoking vertex*) uniformly across the triangle, and it ignores the colors from the other two vertices.\nYou can use a mix of flat shaded and interpolated values, simply by adding or omitting the `flat` qualifier on your vertex function's outputs.\nThe [Metal Shading Language specification][ShadingLanguageSpec] defines other attribute qualifiers you can also use to modify the rasterization behavior.\n\n[ScreenDrawing]: https://developer.apple.com/documentation/metal\n[MTLDevice]: https://developer.apple.com/documentation/metal/mtldevice\n[MTLResource]: https://developer.apple.com/documentation/metal/mtlresource\n[MTLBuffer]: https://developer.apple.com/documentation/metal/mtlbuffer\n[MTLRenderPipelineState]: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate\n[MTLRenderPipelineDescriptor]: https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor\n[MTLRenderCommandEncoder]: https://developer.apple.com/documentation/metal/mtlrendercommandencoder\n[MTLPixelFormat]: https://developer.apple.com/documentation/metal/mtlpixelformat\n[MTKView]: https://developer.apple.com/documentation/metalkit/mtkview\n[ShadingLanguageSpec]: https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf\n[MTLFunction]: https://developer.apple.com/documentation/metal/mtlfunction\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Renderer/AAPLRenderer.h",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nHeader for a platform independent renderer class, which performs Metal setup and per frame rendering.\n*/\n\n@import MetalKit;\n\n@interface AAPLRenderer : NSObject<MTKViewDelegate>\n\n- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView;\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Renderer/AAPLRenderer.m",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nImplementation of a platform independent renderer class, which performs Metal setup and per frame rendering\n*/\n\n@import simd;\n@import MetalKit;\n\n#import \"AAPLRenderer.h\"\n\n// Header shared between C code here, which executes Metal API commands, and .metal files, which\n// uses these types as inputs to the shaders.\n#import \"AAPLShaderTypes.h\"\n\n// Main class performing the rendering\n@implementation AAPLRenderer\n{\n    id<MTLDevice> _device;\n\n    // The render pipeline generated from the vertex and fragment shaders in the .metal shader file.\n    id<MTLRenderPipelineState> _pipelineState;\n\n    // The command queue used to pass commands to the device.\n    id<MTLCommandQueue> _commandQueue;\n\n    // The current size of the view, used as an input to the vertex shader.\n    vector_uint2 _viewportSize;\n}\n\n- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView\n{\n    self = [super init];\n    if(self)\n    {\n        NSError *error;\n\n        _device = mtkView.device;\n\n        // Load all the shader files with a .metal file extension in the project.\n        id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];\n\n        id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@\"vertexShader\"];\n        id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@\"fragmentShader\"];\n\n        // Configure a pipeline descriptor that is used to create a pipeline state.\n        MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];\n        pipelineStateDescriptor.label = @\"Simple Pipeline\";\n        pipelineStateDescriptor.vertexFunction = vertexFunction;\n        pipelineStateDescriptor.fragmentFunction = fragmentFunction;\n        pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;\n\n        _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor\n                                                                 error:&error];\n\n        // Pipeline State creation could fail if the pipeline descriptor isn't set up properly.\n        //  If the Metal API validation is enabled, you can find out more information about what\n        //  went wrong.  (Metal API validation is enabled by default when a debug build is run\n        //  from Xcode.)\n        NSAssert(_pipelineState, @\"Failed to create pipeline state: %@\", error);\n\n        // Create the command queue\n        _commandQueue = [_device newCommandQueue];\n    }\n\n    return self;\n}\n\n/// Called whenever view changes orientation or is resized\n- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size\n{\n    // Save the size of the drawable to pass to the vertex shader.\n    _viewportSize.x = size.width;\n    _viewportSize.y = size.height;\n}\n\n/// Called whenever the view needs to render a frame.\n- (void)drawInMTKView:(nonnull MTKView *)view\n{\n    static const AAPLVertex triangleVertices[] =\n    {\n        // 2D positions,    RGBA colors\n        { {  250,  -250 }, { 1, 0, 0, 1 } },\n        { { -250,  -250 }, { 0, 1, 0, 1 } },\n        { {    0,   250 }, { 0, 0, 1, 1 } },\n    };\n\n    // Create a new command buffer for each render pass to the current drawable.\n    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];\n    commandBuffer.label = @\"MyCommand\";\n\n    // Obtain a renderPassDescriptor generated from the view's drawable textures.\n    MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;\n\n    if(renderPassDescriptor != nil)\n    {\n        // Create a render command encoder.\n        id<MTLRenderCommandEncoder> renderEncoder =\n        [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];\n        renderEncoder.label = @\"MyRenderEncoder\";\n\n        // Set the region of the drawable to draw into.\n        [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }];\n\n        [renderEncoder setRenderPipelineState:_pipelineState];\n\n        // Pass in the parameter data.\n        [renderEncoder setVertexBytes:triangleVertices\n                               length:sizeof(triangleVertices)\n                              atIndex:AAPLVertexInputIndexVertices];\n\n        [renderEncoder setVertexBytes:&_viewportSize\n                               length:sizeof(_viewportSize)\n                              atIndex:AAPLVertexInputIndexViewportSize];\n\n        // Draw the triangle.\n        [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle\n                          vertexStart:0\n                          vertexCount:3];\n\n        [renderEncoder endEncoding];\n\n        // Schedule a present once the framebuffer is complete using the current drawable.\n        [commandBuffer presentDrawable:view.currentDrawable];\n    }\n\n    // Finalize rendering here & push the command buffer to the GPU.\n    [commandBuffer commit];\n}\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Renderer/AAPLShaderTypes.h",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nHeader containing types and enum constants shared between Metal shaders and C/ObjC source\n*/\n\n#ifndef AAPLShaderTypes_h\n#define AAPLShaderTypes_h\n\n#include <simd/simd.h>\n\n// Buffer index values shared between shader and C code to ensure Metal shader buffer inputs\n// match Metal API buffer set calls.\ntypedef enum AAPLVertexInputIndex\n{\n    AAPLVertexInputIndexVertices     = 0,\n    AAPLVertexInputIndexViewportSize = 1,\n} AAPLVertexInputIndex;\n\n//  This structure defines the layout of vertices sent to the vertex\n//  shader. This header is shared between the .metal shader and C code, to guarantee that\n//  the layout of the vertex array in the C code matches the layout that the .metal\n//  vertex shader expects.\ntypedef struct\n{\n    vector_float2 position;\n    vector_float4 color;\n} AAPLVertex;\n\n#endif /* AAPLShaderTypes_h */\n"
  },
  {
    "path": "tests/projects/objc/metal_app/Renderer/AAPLShaders.metal",
    "content": "/*\nSee LICENSE folder for this sample’s licensing information.\n\nAbstract:\nMetal shaders used for this sample\n*/\n\n#include <metal_stdlib>\n\nusing namespace metal;\n\n// Include header shared between this Metal shader code and C code executing Metal API commands.\n#include \"AAPLShaderTypes.h\"\n\n// Vertex shader outputs and fragment shader inputs\nstruct RasterizerData\n{\n    // The [[position]] attribute of this member indicates that this value\n    // is the clip space position of the vertex when this structure is\n    // returned from the vertex function.\n    float4 position [[position]];\n\n    // Since this member does not have a special attribute, the rasterizer\n    // interpolates its value with the values of the other triangle vertices\n    // and then passes the interpolated value to the fragment shader for each\n    // fragment in the triangle.\n    float4 color;\n};\n\nvertex RasterizerData\nvertexShader(uint vertexID [[vertex_id]],\n             constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],\n             constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])\n{\n    RasterizerData out;\n\n    // Index into the array of positions to get the current vertex.\n    // The positions are specified in pixel dimensions (i.e. a value of 100\n    // is 100 pixels from the origin).\n    float2 pixelSpacePosition = vertices[vertexID].position.xy;\n\n    // Get the viewport size and cast to float.\n    vector_float2 viewportSize = vector_float2(*viewportSizePointer);\n    \n\n    // To convert from positions in pixel space to positions in clip-space,\n    //  divide the pixel coordinates by half the size of the viewport.\n    out.position = vector_float4(0.0, 0.0, 0.0, 1.0);\n    out.position.xy = pixelSpacePosition / (viewportSize / 2.0);\n\n    // Pass the input color directly to the rasterizer.\n    out.color = vertices[vertexID].color;\n\n    return out;\n}\n\nfragment float4 fragmentShader(RasterizerData in [[stage_in]])\n{\n    // Return the interpolated color.\n    return in.color;\n}\n\n"
  },
  {
    "path": "tests/projects/objc/metal_app/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"HelloTriangle\")\n    add_rules(\"xcode.application\")\n    add_includedirs(\"Renderer\")\n    add_frameworks(\"MetalKit\")\n    add_mflags(\"-fmodules\")\n    add_files(\"Renderer/*.m\", \"Renderer/*.metal\")\n    if is_plat(\"macosx\") then\n        add_files(\"Application/main.m\")\n        add_files(\"Application/AAPLViewController.m\")\n        add_files(\"Application/macOS/Info.plist\")\n        add_files(\"Application/macOS/Base.lproj/*.storyboard\")\n        add_defines(\"TARGET_MACOS\")\n        add_frameworks(\"AppKit\")\n    elseif is_plat(\"iphoneos\") then\n        add_files(\"Application/*.m\")\n        add_files(\"Application/iOS/Info.plist\")\n        add_files(\"Application/iOS/Base.lproj/*.storyboard\")\n        add_frameworks(\"UIKit\")\n        add_defines(\"TARGET_IOS\")\n    end\n"
  },
  {
    "path": "tests/projects/objc/modulemap/src/hello.h",
    "content": "#import <Foundation/Foundation.h>\n\n@interface Hello : NSObject\n\n+ (void)say:(NSString*)s;\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/modulemap/src/hello.m",
    "content": "#import \"hello.h\"\n\n@implementation Hello\n\n+ (void)say:(NSString*)s\n{\n    NSLog(@\"%@\\n\", s);\n}\n\n@end\n"
  },
  {
    "path": "tests/projects/objc/modulemap/src/main.m",
    "content": "#import <Foundation/Foundation.h>\n@import Hello;\n\nint main(int argc, char** argv)\n{\n    [Hello say:@\"hello\"];\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc/modulemap/src/module.modulemap",
    "content": "module Hello {\n    header \"hello.h\"\n    export *\n}\n"
  },
  {
    "path": "tests/projects/objc/modulemap/xmake.lua",
    "content": "target(\"modulemap\")\n    set_kind(\"binary\")\n    add_files(\"src/*.m\")\n    add_mflags(\"-fmodules\", \"-fmodule-map-file=src/module.modulemap\")\n\n\n"
  },
  {
    "path": "tests/projects/objc++/console/src/main.mm",
    "content": "#import <Foundation/Foundation.h>\n\nint main(int argc, char** argv)\n{\n    @autoreleasepool\n    {\n        NSLog(@\"hello world!\");\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/console/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/objc++/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"console_objc++\")\n    set_kind(\"binary\")\n    add_files(\"src/*.mm\")\n\n"
  },
  {
    "path": "tests/projects/objc++/modulemap/src/hello.h",
    "content": "#import <Foundation/Foundation.h>\n\n@interface Hello : NSObject\n\n+ (void)say:(NSString*)s;\n\n@end\n"
  },
  {
    "path": "tests/projects/objc++/modulemap/src/hello.m",
    "content": "#import \"hello.h\"\n\n@implementation Hello\n\n+ (void)say:(NSString*)s\n{\n    NSLog(@\"%@\\n\", s);\n}\n\n@end\n"
  },
  {
    "path": "tests/projects/objc++/modulemap/src/main.mm",
    "content": "#import <Foundation/Foundation.h>\n@import Hello;\n\nint main(int argc, char** argv)\n{\n    [Hello say:@\"hello\"];\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/modulemap/src/module.modulemap",
    "content": "module Hello {\n    header \"hello.h\"\n    export *\n}\n"
  },
  {
    "path": "tests/projects/objc++/modulemap/xmake.lua",
    "content": "target(\"modulemap\")\n    set_kind(\"binary\")\n    add_files(\"src/*.mm\", \"src/*.m\")\n    add_mxxflags(\"-fmodules\", \"-fcxx-modules\", \"-fmodule-map-file=src/module.modulemap\")\n\n\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/header.h",
    "content": "// header.h\n#ifndef HEADER_H\n#define HEADER_H\n   \n#include <algorithm>\n#include <deque>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <set>\n//#include <thread>\n#include <utility>\n#include <vector>\n#include <string>\n#include <queue>\n#include <cstdlib>\n#include <utility>\n#include <exception>\n#include <list>\n#include <stack>\n#include <complex>\n#include <fstream>\n#include <cstdio>\n#include <iomanip>\n\n#endif\n\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/header2.h",
    "content": ""
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/main.mm",
    "content": "#include \"header.h\"\n\nint main(int argc, char** argv) \n{\n    std::string s(\"xmake\");\n    printf(\"hello %s!\\n\", s.c_str());\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test.c",
    "content": "\nvoid test_c(void)\n{\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test2.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test2()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test4.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test4()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test5.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test5()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test6.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test6()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test7.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test7()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/src/test8.mm",
    "content": "\n// main.cpp\n#include \"header.h\"\n\nint test8()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/test3.mm",
    "content": "\n#include \"src/header.h\"\n#include \"src/header2.h\"\n\nint test3()\n{\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/objc++/precompiled_header/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"main\")\n    set_kind(\"binary\")\n    set_languages(\"cxx11\")\n    set_pmxxheader(\"src/header.h\")\n    add_files(\"src/*.mm\", \"src/*.c\", \"*.mm\")\n\n"
  },
  {
    "path": "tests/projects/openmp/hello/src/main.c",
    "content": "#include <stdio.h>\n#include <omp.h>\n\nint main(int argc, char** argv)\n{\n    #pragma omp parallel\n    {\n        printf(\"hello %d\\n\", omp_get_thread_num());\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/openmp/hello/xmake.lua",
    "content": "add_requires(\"openmp\")\ntarget(\"hello\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"openmp\")\n"
  },
  {
    "path": "tests/projects/openmp/loop/src/main.cpp",
    "content": "#include <stdio.h>\n#include <omp.h>\n\nint main(int argc, char** argv)\n{\n    #pragma omp parallel for\n    for (int i = 0; i < 10; ++i)\n    {\n        printf(\"hello(%d): i = %d\\n\", omp_get_thread_num(), i);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/openmp/loop/xmake.lua",
    "content": "add_requires(\"openmp\")\ntarget(\"loop\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"openmp\")\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/src/main.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <vector>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    ifstream src_file(argv[1], ios::in | ios::binary);\n    if (!src_file) {\n        return 1;\n    }\n    vector<char> buffer(istreambuf_iterator<char>(src_file), {});\n    src_file.close();\n\n    ofstream dst_file(argv[2], ios::out);\n    if (!dst_file) {\n        return 1;\n    }\n\n    dst_file << \"unsigned char g_codegen_data[] = {\";\n    for (auto byte : buffer) {\n        dst_file << \"0x\" << hex << (int)(unsigned char)byte << \",\";\n    }\n    dst_file << \"0};\" << endl;\n    dst_file.close();\n    return 0;\n}\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/modules/autogen/foo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"generate\")\n    add_rules(\"module.binary\")\n    add_files(\"src/*.cpp\")\n    set_languages(\"c++11\")\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/src/data.in",
    "content": "hello world!\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nextern unsigned char g_codegen_data[];\n\nint main(int argc, char** argv) {\n    cout << (const char*)g_codegen_data << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_binary_module/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\nrule(\"autogen\")\n    set_extensions(\".in\")\n    before_build_file(function (target, sourcefile, opt)\n        import(\"utils.progress\")\n        import(\"core.project.depend\")\n        import(\"core.tool.compiler\")\n        import(\"autogen.foo\", {always_build = true})\n\n        local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"autogen\", path.basename(sourcefile) .. \".cpp\")\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n\n        depend.on_changed(function ()\n            progress.show(opt.progress, \"${color.build.object}compiling.autogen %s\", sourcefile)\n            os.mkdir(path.directory(sourcefile_cx))\n            foo.generate(sourcefile, sourcefile_cx)\n            compiler.compile(sourcefile_cx, objectfile, {target = target})\n        end, {dependfile = target:dependfile(objectfile),\n              files = sourcefile,\n              changed = target:is_rebuilt()})\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"autogen\")\n    add_files(\"src/main.cpp\")\n    add_files(\"src/*.in\")\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_code/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_code/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_code/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"$(builddir)/autogen.cpp\", {always_added = true})\n    before_build(function (target)\n        io.writefile(\"$(builddir)/autogen.cpp\", [[\n#include <iostream>\nusing namespace std;\nint main(int argc, char** argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n        ]])\n    end)\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/src/autogen.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <vector>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    ifstream src_file(argv[1], ios::in | ios::binary);\n    if (!src_file) {\n        return 1;\n    }\n    vector<char> buffer(istreambuf_iterator<char>(src_file), {});\n    src_file.close();\n\n    ofstream dst_file(argv[2], ios::out);\n    if (!dst_file) {\n        return 1;\n    }\n\n    dst_file << \"unsigned char g_codegen_data[] = {\";\n    for (auto byte : buffer) {\n        dst_file << \"0x\" << hex << (int)(unsigned char)byte << \",\";\n    }\n    dst_file << \"0};\" << endl;\n    dst_file.close();\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/src/data.in",
    "content": "hello world!\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nextern unsigned char g_codegen_data[];\n\nint main(int argc, char** argv) {\n    cout << (const char*)g_codegen_data << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_codedep/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nrule(\"autogen\")\n    set_extensions(\".in\")\n    before_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"autogen\", path.basename(sourcefile) .. \".cpp\")\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.autogen %s\", sourcefile)\n        batchcmds:mkdir(path.directory(sourcefile_cx))\n        batchcmds:vrunv(target:dep(\"autogen\"):targetfile(), {sourcefile, sourcefile_cx})\n        batchcmds:compile(sourcefile_cx, objectfile)\n\n        batchcmds:add_depfiles(sourcefile, target:dep(\"autogen\"):targetfile())\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\ntarget(\"autogen\")\n    set_default(false)\n    set_kind(\"binary\")\n    set_plat(os.host())\n    set_arch(os.arch())\n    add_files(\"src/autogen.cpp\")\n    set_languages(\"c++11\")\n    set_policy(\"build.fence\", true)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"autogen\")\n    add_rules(\"autogen\")\n    add_files(\"src/main.cpp\")\n    add_files(\"src/*.in\")\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/src/main.cpp",
    "content": "#include <xmi.h>\n#include <iostream>\n#include <fstream>\n#include <vector>\n\nusing namespace std;\n\nstatic int generate(lua_State* lua) {\n    const char* inputfile = lua_tostring(lua, 1);\n    const char* outputfile = lua_tostring(lua, 2);\n\n    ifstream src_file(inputfile, ios::in | ios::binary);\n    if (!src_file) {\n        return 1;\n    }\n    vector<char> buffer(istreambuf_iterator<char>(src_file), {});\n    src_file.close();\n\n    ofstream dst_file(outputfile, ios::out);\n    if (!dst_file) {\n        return 1;\n    }\n\n    dst_file << \"unsigned char g_codegen_data[] = {\";\n    for (auto byte : buffer) {\n        dst_file << \"0x\" << hex << (int)(unsigned char)byte << \",\";\n    }\n    dst_file << \"0};\" << endl;\n    dst_file.close();\n    return 0;\n}\n\nint luaopen(foo, lua_State* lua) {\n    static const luaL_Reg funcs[] = {\n        {\"generate\", generate},\n        {NULL, NULL}\n    };\n    lua_newtable(lua);\n    luaL_setfuncs(lua, funcs, 0);\n    return 1;\n}\n\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/modules/autogen/foo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    add_rules(\"module.shared\")\n    add_files(\"src/*.cpp\")\n    set_languages(\"c++11\")\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/src/data.in",
    "content": "hello world!\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nextern unsigned char g_codegen_data[];\n\nint main(int argc, char** argv) {\n    cout << (const char*)g_codegen_data << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/autogen/autogen_shared_module/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\nrule(\"autogen\")\n    set_extensions(\".in\")\n    before_build_file(function (target, sourcefile, opt)\n        import(\"utils.progress\")\n        import(\"core.project.depend\")\n        import(\"core.tool.compiler\")\n        import(\"autogen.foo\", {always_build = true})\n\n        local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"autogen\", path.basename(sourcefile) .. \".cpp\")\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n\n        depend.on_changed(function ()\n            progress.show(opt.progress, \"${color.build.object}compiling.autogen %s\", sourcefile)\n            os.mkdir(path.directory(sourcefile_cx))\n            foo.generate(sourcefile, sourcefile_cx)\n            compiler.compile(sourcefile_cx, objectfile, {target = target})\n        end, {dependfile = target:dependfile(objectfile),\n              files = sourcefile,\n              changed = target:is_rebuilt()})\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"autogen\")\n    add_files(\"src/main.cpp\")\n    add_files(\"src/*.in\")\n\n"
  },
  {
    "path": "tests/projects/other/bin2c/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/bin2c/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nstatic unsigned char g_bin_data[] = {\n    #include \"data.bin.h\"\n};\n\nstatic unsigned char g_ico_data[] = {\n    #include \"xmake.ico.h\"\n};\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv)\n{\n    hexdump(\"data.bin\", g_bin_data, (uint32_t)sizeof(g_bin_data));\n    printf(\"\\n\");\n    hexdump(\"xmake.ico\", g_ico_data, (uint32_t)sizeof(g_ico_data));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/bin2c/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/bin2c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.bin2c\", {linewidth = 16, extensions = {\".bin\", \".ico\"}})\n    add_files(\"src/*.c\")\n    add_files(\"src/*.bin\")\n    add_files(\"src/xmake.ico\", {nozeroend = true})\n\n\n"
  },
  {
    "path": "tests/projects/other/bin2obj/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nextern const uint8_t _binary_data_bin_start[];\nextern const uint8_t _binary_data_bin_end[];\n\nextern const uint8_t _binary_xmake_ico_start[];\nextern const uint8_t _binary_xmake_ico_end[];\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv) {\n    const uint32_t _binary_data_bin_size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start);\n    const uint32_t _binary_xmake_ico_size = (uint32_t)(_binary_xmake_ico_end - _binary_xmake_ico_start);\n\n    hexdump(\"data.bin\", _binary_data_bin_start, _binary_data_bin_size);\n    printf(\"\\n\");\n    hexdump(\"xmake.ico\", _binary_xmake_ico_start, _binary_xmake_ico_size);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/bin2obj/test.lua",
    "content": "function main(t)\n    t:build()\nend\n\n"
  },
  {
    "path": "tests/projects/other/bin2obj/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.bin2obj\", {extensions = {\".bin\", \".ico\"}})\n    add_files(\"src/*.c\")\n    add_files(\"src/data.bin\", {zeroend = true})\n    add_files(\"src/xmake.ico\", {zeroend = false})\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/dep1.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/dep2.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/dep3.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/dep4.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/dep5.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/interface.h",
    "content": "/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */ \nint             add(int a, int b);\n\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/test1.c",
    "content": "#include \"interface.h\"\n#include <stdio.h>\n  \nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/test2.c",
    "content": "#include \"interface.h\"\n#include <stdio.h>\n  \nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/src/test3.c",
    "content": "#include \"interface.h\"\n#include <stdio.h>\n  \nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/build_deps/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/build_deps/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\ntarget(\"dep1\")\n    set_kind(\"static\")\n    add_deps(\"dep3\")\n    add_files(\"src/dep1.c\")\n    set_policy(\"build.fence\", true)\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep3\"):targetfile())\n    end)\n    before_link(function (target)\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"dep1: before_link failed!\")\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"dep1: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"dep2\")\n    set_kind(\"static\")\n    add_deps(\"dep3\")\n    add_files(\"src/dep2.c\")\n    set_policy(\"build.fence\", true)\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep3\"):targetfile())\n    end)\n    before_link(function (target)\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"dep2: before_link failed!\")\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"dep2: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"dep3\")\n    set_kind(\"static\")\n    add_files(\"src/dep3.c\")\n    add_deps(\"dep4\", \"dep5\")\n    set_policy(\"build.fence\", true)\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep4\"):targetfile())\n        os.rm(target:dep(\"dep5\"):targetfile())\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"dep3: after_link failed!\")\n        assert(os.isfile(target:dep(\"dep4\"):targetfile()), \"dep3: after_link failed!\")\n        assert(os.isfile(target:dep(\"dep5\"):targetfile()), \"dep3: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"dep4\")\n    set_kind(\"static\")\n    add_files(\"src/dep4.c\")\n    after_load(function (target)\n        os.rm(target:targetfile())\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"dep4: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"dep5\")\n    set_kind(\"static\")\n    add_files(\"src/dep5.c\")\n    after_load(function (target)\n        os.rm(target:targetfile())\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"dep5: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"test1\")\n    set_kind(\"binary\")\n    add_deps(\"dep1\", \"dep2\")\n    add_files(\"src/test1.c\")\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep1\"):targetfile())\n        os.rm(target:dep(\"dep2\"):targetfile())\n        os.rm(target:dep(\"dep3\"):targetfile())\n    end)\n    before_link(function (target)\n        assert(os.isfile(target:dep(\"dep1\"):targetfile()), \"test1: before_link failed!\")\n        assert(os.isfile(target:dep(\"dep2\"):targetfile()), \"test1: before_link failed!\")\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"test1: before_link failed!\")\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"test1: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_deps(\"dep1\")\n    add_files(\"src/test2.c\")\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep1\"):targetfile())\n        os.rm(target:dep(\"dep3\"):targetfile())\n    end)\n    before_link(function (target)\n        assert(os.isfile(target:dep(\"dep1\"):targetfile()), \"test2: before_link failed!\")\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"test2: before_link failed!\")\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"test2: after_link failed!\")\n    end)\n    on_install(function (target) end)\n\nrule(\"test3\")\n    before_build(function (target)\n        assert(os.isfile(target:dep(\"dep1\"):targetfile()), \"test2: before_build/rule failed!\")\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"test2: before_build/rule failed!\")\n    end)\n\ntarget(\"test3\")\n    set_kind(\"binary\")\n    add_deps(\"dep1\")\n    add_rules(\"test3\")\n    add_files(\"src/test3.c\")\n    after_load(function (target)\n        os.rm(target:targetfile())\n        os.rm(target:dep(\"dep1\"):targetfile())\n        os.rm(target:dep(\"dep3\"):targetfile())\n    end)\n    before_build(function (target)\n        assert(os.isfile(target:dep(\"dep1\"):targetfile()), \"test2: before_build failed!\")\n        assert(os.isfile(target:dep(\"dep3\"):targetfile()), \"test2: before_build failed!\")\n    end)\n    after_link(function (target)\n        assert(os.isfile(target:targetfile()), \"test2: after_link failed!\")\n    end)\n    on_install(function (target) end)\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2c/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nstatic unsigned char g_test_vert_spv_data[] = {\n    #include \"test.vert.spv.h\"\n};\n\nstatic unsigned char g_test_frag_spv_data[] = {\n    #include \"test.frag.spv.h\"\n};\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv)\n{\n    hexdump(\"test.vert.spv\", g_test_vert_spv_data, (uint32_t)sizeof(g_test_vert_spv_data));\n    printf(\"\\n\");\n    hexdump(\"test.frag.spv\", g_test_frag_spv_data, (uint32_t)sizeof(g_test_frag_spv_data));\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2c/src/test.frag",
    "content": "#version 330\nprecision mediump float;\n\nvoid main() {\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2c/src/test.vert",
    "content": "#version 330\nprecision mediump float;\n\nvoid main() {\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"glslang\", {configs = {binaryonly = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.glsl2spv\", {bin2c = true})\n    add_files(\"src/*.c\")\n    add_files(\"src/*.vert\", \"src/*.frag\")\n    add_packages(\"glslang\")\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2obj/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nextern const uint8_t _binary_test_vert_spv_start[];\nextern const uint8_t _binary_test_vert_spv_end[];\n\nextern const uint8_t _binary_test_frag_spv_start[];\nextern const uint8_t _binary_test_frag_spv_end[];\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv) {\n    const uint32_t vert_size = (uint32_t)(_binary_test_vert_spv_end - _binary_test_vert_spv_start);\n    const uint32_t frag_size = (uint32_t)(_binary_test_frag_spv_end - _binary_test_frag_spv_start);\n    \n    hexdump(\"test.vert.spv\", _binary_test_vert_spv_start, vert_size);\n    printf(\"\\n\");\n    hexdump(\"test.frag.spv\", _binary_test_frag_spv_start, frag_size);\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2obj/src/test.frag",
    "content": "#version 330\nprecision mediump float;\n\nvoid main() {\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2obj/src/test.vert",
    "content": "#version 330\nprecision mediump float;\n\nvoid main() {\n}\n\n"
  },
  {
    "path": "tests/projects/other/glsl2spv_bin2obj/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"glslang\", {configs = {binaryonly = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.glsl2spv\", {bin2obj = true})\n    add_files(\"src/*.c\")\n    add_files(\"src/*.vert\", \"src/*.frag\")\n    add_packages(\"glslang\")\n\n"
  },
  {
    "path": "tests/projects/other/group/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/group/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/group/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test1\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_group(\"group1\")\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_group(\"group1\")\n\ntarget(\"test3\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_group(\"group1/group2\")\n\ntarget(\"test4\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_group(\"group3/group4\")\n\ntarget(\"test5\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\ntarget(\"test6\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2c/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nstatic unsigned char g_test_vs_spv_data[] = {\n    #include \"test.vs.spv.h\"\n};\n\nstatic unsigned char g_test_ps_spv_data[] = {\n    #include \"test.ps.spv.h\"\n};\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv)\n{\n    hexdump(\"test.vs.spv\", g_test_vs_spv_data, (uint32_t)sizeof(g_test_vs_spv_data));\n    printf(\"\\n\");\n    hexdump(\"test.ps.spv\", g_test_ps_spv_data, (uint32_t)sizeof(g_test_ps_spv_data));\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2c/src/test.ps.hlsl",
    "content": "struct PSInput {\n    float4 position : SV_POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nfloat4 main(PSInput input) : SV_TARGET {\n    return float4(input.texcoord, 0.0, 1.0);\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2c/src/test.vs.hlsl",
    "content": "struct VSInput {\n    float3 position : POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nstruct VSOutput {\n    float4 position : SV_POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nVSOutput main(VSInput input) {\n    VSOutput output;\n    output.position = float4(input.position, 1.0);\n    output.texcoord = input.texcoord;\n    return output;\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"directxshadercompiler\", {configs = {binaryonly = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.hlsl2spv\", {bin2c = true})\n    add_files(\"src/*.c\")\n    add_files(\"src/*.vs.hlsl\", \"src/*.ps.hlsl\")\n    add_packages(\"directxshadercompiler\")\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2obj/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <ctype.h>\n\nextern const uint8_t _binary_test_vs_spv_start[];\nextern const uint8_t _binary_test_vs_spv_end[];\n\nextern const uint8_t _binary_test_ps_spv_start[];\nextern const uint8_t _binary_test_ps_spv_end[];\n\nstatic void hexdump(const char* name, const uint8_t* data, uint32_t size) {\n    printf(\"%s: size: %u bytes\\n\", name, (unsigned int)size);\n    if (size == 0) {\n        return;\n    }\n    \n    // if file is larger than 128 bytes, only dump first 64 and last 64 bytes\n    uint32_t dump_size = size;\n    uint32_t start_offset = 0;\n    uint32_t end_offset = 0;\n    uint32_t skip_size = 0;\n    \n    if (size > 128) {\n        dump_size = 64;\n        start_offset = 0;\n        end_offset = size - 64;\n        skip_size = end_offset - start_offset - dump_size;\n    }\n    \n    // dump start\n    for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) {\n        // print offset\n        printf(\"%08x  \", (unsigned int)offset);\n        \n        // print hex bytes (8 bytes, space, 8 bytes)\n        for (uint32_t i = 0; i < 16; i++) {\n            if (offset + i < size) {\n                printf(\"%02x \", data[offset + i]);\n            } else {\n                printf(\"   \");\n            }\n            if (i == 7) {\n                printf(\" \");\n            }\n        }\n        \n        // print ASCII representation\n        printf(\" |\");\n        for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n            uint8_t c = data[offset + i];\n            printf(\"%c\", isprint(c) ? c : '.');\n        }\n        printf(\"|\\n\");\n    }\n    \n    // print skip indicator if needed\n    if (skip_size > 0) {\n        printf(\"        ... (skipped %u bytes) ...\\n\", (unsigned int)skip_size);\n    }\n    \n    // dump end if needed\n    if (size > 128) {\n        for (uint32_t offset = end_offset; offset < size; offset += 16) {\n            // print offset\n            printf(\"%08x  \", (unsigned int)offset);\n            \n            // print hex bytes (8 bytes, space, 8 bytes)\n            for (uint32_t i = 0; i < 16; i++) {\n                if (offset + i < size) {\n                    printf(\"%02x \", data[offset + i]);\n                } else {\n                    printf(\"   \");\n                }\n                if (i == 7) {\n                    printf(\" \");\n                }\n            }\n            \n            // print ASCII representation\n            printf(\" |\");\n            for (uint32_t i = 0; i < 16 && offset + i < size; i++) {\n                uint8_t c = data[offset + i];\n                printf(\"%c\", isprint(c) ? c : '.');\n            }\n            printf(\"|\\n\");\n        }\n    }\n}\n\nint main(int argc, char** argv) {\n    const uint32_t vs_size = (uint32_t)(_binary_test_vs_spv_end - _binary_test_vs_spv_start);\n    const uint32_t ps_size = (uint32_t)(_binary_test_ps_spv_end - _binary_test_ps_spv_start);\n    \n    hexdump(\"test.vs.spv\", _binary_test_vs_spv_start, vs_size);\n    printf(\"\\n\");\n    hexdump(\"test.ps.spv\", _binary_test_ps_spv_start, ps_size);\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2obj/src/test.ps.hlsl",
    "content": "struct PSInput {\n    float4 position : SV_POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nfloat4 main(PSInput input) : SV_TARGET {\n    return float4(input.texcoord, 0.0, 1.0);\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2obj/src/test.vs.hlsl",
    "content": "struct VSInput {\n    float3 position : POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nstruct VSOutput {\n    float4 position : SV_POSITION;\n    float2 texcoord : TEXCOORD0;\n};\n\nVSOutput main(VSInput input) {\n    VSOutput output;\n    output.position = float4(input.position, 1.0);\n    output.texcoord = input.texcoord;\n    return output;\n}\n\n"
  },
  {
    "path": "tests/projects/other/hlsl2spv_bin2obj/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"glslang\", {configs = {binaryonly = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.hlsl2spv\", {bin2obj = true})\n    add_files(\"src/*.c\")\n    add_files(\"src/*.hlsl\")\n    add_packages(\"directxshadercompiler\")\n\n"
  },
  {
    "path": "tests/projects/other/ispc/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/ispc/src/main.cpp",
    "content": "#include \"test_ispc.h\"\n\nusing namespace ispc;\n\nint main(int argc, char *argv[])\n{\n    test_ispc();\n}\n"
  },
  {
    "path": "tests/projects/other/ispc/src/test.ispc",
    "content": "export void test_ispc() {}"
  },
  {
    "path": "tests/projects/other/ispc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"utils.ispc\", {header_extension = \"_ispc.h\"})\n    set_values(\"ispc.flags\", \"--target=host\")\n    add_files(\"src/*.ispc\")\n    add_files(\"src/*.cpp\")\n"
  },
  {
    "path": "tests/projects/other/merge_archive/src/add.c",
    "content": "int add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive/src/mul.c",
    "content": "int mul(int a, int b)\n{\n    return a * b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive/src/sub.c",
    "content": "int sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive/test.lua",
    "content": "function main(t)\n    -- Solaris ar does not support merging archives with duplicate object file names\n    if is_host(\"solaris\") then\n        return\n    end\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/merge_archive/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"add\")\n    set_kind(\"static\")\n    add_files(\"src/add.c\")\n    set_policy(\"build.fence\", true)\n    set_targetdir(\"$(builddir)/merge_archive\")\n\ntarget(\"sub\")\n    set_kind(\"static\")\n    add_files(\"src/sub.c\")\n    set_policy(\"build.fence\", true)\n    set_targetdir(\"$(builddir)/merge_archive\")\n\ntarget(\"mul\")\n    set_kind(\"static\")\n    add_deps(\"add\", \"sub\")\n    add_files(\"src/mul.c\")\n    if is_plat(\"windows\") then\n        add_files(\"$(builddir)/merge_archive/*.lib\")\n    else\n        add_files(\"$(builddir)/merge_archive/*.a\")\n    end\n\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/add.c",
    "content": "int add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/main.c",
    "content": "#include <stdio.h>\n\nint add(int a, int b);\nint sub(int a, int b);\nint mul(int a, int b);\nint subdir_add(int a, int b);\nint subdir_sub(int a, int b);\n\nint main(int argc, char** argv)\n{\n    printf(\"%d\\n\", add(1, 1));\n    printf(\"%d\\n\", sub(1, 1));\n    printf(\"%d\\n\", mul(1, 1));\n    printf(\"%d\\n\", subdir_add(1, 1));\n    printf(\"%d\\n\", subdir_sub(1, 1));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/mul.c",
    "content": "int mul(int a, int b)\n{\n    return a * b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/sub.c",
    "content": "int sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/subdir/add.c",
    "content": "int subdir_add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/src/subdir/sub.c",
    "content": "int subdir_sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/test.lua",
    "content": "function main(t)\n    -- Solaris ar does not support merging archives with duplicate object file names\n    if is_host(\"solaris\") then\n        return\n    end\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/merge_archive2/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"add\")\n    set_kind(\"static\")\n    add_files(\"src/add.c\")\n    add_files(\"src/subdir/add.c\")\n\ntarget(\"sub\")\n    set_kind(\"static\")\n    add_files(\"src/sub.c\")\n    add_files(\"src/subdir/sub.c\")\n\ntarget(\"mul\")\n    set_kind(\"static\")\n    add_deps(\"add\", \"sub\")\n    add_files(\"src/mul.c\")\n    set_policy(\"build.merge_archive\", true)\n\ntarget(\"test\")\n    add_deps(\"mul\")\n    add_files(\"src/main.c\")\n"
  },
  {
    "path": "tests/projects/other/merge_object/src/interface.c",
    "content": "#include \"interface.h\"\n\nint add(int a, int b)\n{\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_object/src/interface.h",
    "content": "/*! calculate add(a, b) \n *\n * @param a     the first argument\n * @param b     the second argument\n *\n * @return      the result\n */\nint             add(int a, int b);\n"
  },
  {
    "path": "tests/projects/other/merge_object/src/test.c",
    "content": "#include \"interface.h\"\n#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/merge_object/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/merge_object/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"merge_object\")\n    set_kind(\"static\")\n    add_files(\"src/interface.c\")\n    set_policy(\"build.fence\", true)\n    after_build_file(function (target, sourcefile)\n        os.cp(target:objectfile(sourcefile), \"$(builddir)/merge_object/\")\n    end)\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"merge_object\")\n    add_files(\"src/test.c\")\n    if is_plat(\"windows\") then\n        add_files(\"$(builddir)/merge_object/interface.c.obj\")\n    else\n        add_files(\"$(builddir)/merge_object/interface.c.o\")\n    end\n\n"
  },
  {
    "path": "tests/projects/other/multiplats_vs/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/multiplats_vs/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/multiplats_vs/src/test.asm",
    "content": "\n"
  },
  {
    "path": "tests/projects/other/multiplats_vs/src/test.rc",
    "content": ""
  },
  {
    "path": "tests/projects/other/multiplats_vs/test.lua",
    "content": "function test_multivs(t)\n    if is_subhost(\"windows\") then\n        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/other/multiplats_vs/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nrule(\"vs2015_x86\")\n    on_load(function (target)\n        target:set(\"arch\", \"x86\")\n        target:set(\"toolchains\", \"msvc\", {vs = \"2015\"})\n    end)\n\ntarget(\"testvs_vs2015_x86\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.rc\")\n    add_rules(\"vs2015_x86\")\n\ntarget(\"testvs\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\", \"src/*.rc\")\n\n\n"
  },
  {
    "path": "tests/projects/other/multiplats_xcode/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/multiplats_xcode/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") then\n        os.exec(\"xmake f -c -vD\")\n        os.exec(\"xmake -rvD\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/other/multiplats_xcode/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"test_host\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n\ntarget(\"test_iphoneos\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_plat(\"iphoneos\")\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/modules/lua/cjson/src/cjson.c",
    "content": "#include <xmi.h>\n\nint luaopen_cjson(lua_State* lua);\n\nint luaopen(cjson, lua_State* lua) {\n    return luaopen_cjson(lua);\n}\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/modules/lua/cjson/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"cjson\")\n    add_rules(\"module.shared\")\n    set_warnings(\"all\")\n    if is_plat(\"windows\") then\n        set_languages(\"c89\")\n    end\n    add_files(\"src/*.c\")\n    add_files(\"../../../../../../../../core/src/lua-cjson/lua-cjson/*.c|fpconv.c\")\n    -- Use internal strtod() / g_fmt() code for performance and disable multi-thread\n    add_defines(\"NDEBUG\", \"USE_INTERNAL_FPCONV\")\n    add_defines(\"XM_CONFIG_API_HAVE_LUA_CJSON\")\n    if is_plat(\"windows\") then\n        -- Windows sprintf()/strtod() handle NaN/inf differently. Not supported.\n        add_defines(\"DISABLE_INVALID_NUMBERS\")\n        add_defines(\"inline=__inline\")\n    end\n\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/native_module/cjson/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    on_config(function (target)\n        import(\"lua.cjson\", {always_build = true})\n        print(cjson.decode('{\"foo\": 1, \"bar\": [1, 2, 3]}'))\n    end)\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/binary/bar/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/binary/bar/src/add.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char** argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a + b);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/binary/bar/src/sub.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char** argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a - b);\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/binary/bar/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"add\")\n    add_rules(\"module.binary\")\n    add_files(\"src/add.cpp\")\n\ntarget(\"sub\")\n    add_rules(\"module.binary\")\n    add_files(\"src/sub.cpp\")\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/shared/foo/src/foo.c",
    "content": "#include <xmi.h>\n\nstatic int add(lua_State* lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a + b);\n    return 1;\n}\n\nstatic int sub(lua_State* lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a - b);\n    return 1;\n}\n\nint luaopen(foo, lua_State* lua) {\n    static const luaL_Reg funcs[] = {\n        {\"add\", add},\n        {\"sub\", sub},\n        {NULL, NULL}\n    };\n    lua_newtable(lua);\n    luaL_setfuncs(lua, funcs, 0);\n    return 1;\n}\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/modules/shared/foo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    add_rules(\"module.shared\")\n    add_files(\"src/foo.c\")\n\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/native_module/hello/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    on_config(function (target)\n        import(\"shared.foo\", {always_build = true})\n        import(\"binary.bar\")\n        print(\"foo: 1 + 1 = %d\", foo.add(1, 1))\n        print(\"foo: 1 - 1 = %d\", foo.sub(1, 1))\n        print(\"bar: 1 + 1 = %s\", bar.add(1, 1))\n        print(\"bar: 1 - 1 = %s\", bar.sub(1, 1))\n    end)\n\n"
  },
  {
    "path": "tests/projects/other/object_only/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/object_only/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/other/object_only/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tests/projects/other/object_only/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/object_only/test.lua",
    "content": "function main(t)\n    t:build()\nend\n"
  },
  {
    "path": "tests/projects/other/object_only/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"bar\")\n    set_kind(\"object\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_deps(\"bar\")\n    add_rules(\"c++\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n"
  },
  {
    "path": "tests/projects/other/parallel_build/1.cpp",
    "content": "int main(int argv, char** argv) {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/parallel_build/2.cpp",
    "content": "// Make this object complex and cost longer compile time...\n#include <algorithm>\n#include <any>\n#include <bitset>\n#include <filesystem>\n#include <fstream>\n#include <iostream>\n#include <list>\n#include <map>\n#include <optional>\n#include <queue>\n#include <string>\n#include <unordered_map>\n#include <variant>\n#include <vector>\n\nint main(int argc, char** argv) {\n    using Type = std::variant<int8_t, uint8_t, int16_t, uint16_t, int32_t,\n          uint32_t, int64_t, uint64_t, double, float>;\n    Type a, b, c;\n    a = 5;\n    b = 3.0;\n    c = 4.0f;\n    double r;\n    std::visit([&](auto a, auto b, auto c) { r = a + b + c; }, a, b, c);\n    std::visit([&](auto a, auto b, auto c) { r = a + b - c; }, a, b, c);\n    std::visit([&](auto a, auto b, auto c) { r = a - b - c; }, a, b, c);\n    std::visit([&](auto a, auto b, auto c) { r = (a + b + c) * 2; }, a, b, c);\n    std::visit([&](auto a, auto b, auto c) { r = (a + b - c) * 3; }, a, b, c);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/parallel_build/xmake.lua",
    "content": "-- These targets should compiled and linked concurrently.\nadd_rules(\"mode.release\", \"mode.debug\", \"mode.releasedbg\")\nset_policy(\"build.ccache\", false)\n\ntarget(\"first\")\n    set_kind(\"binary\")\n    add_files(\"1.cpp\")\n    set_languages(\"clatest\", \"cxx20\")\n\ntarget(\"second\")\n    set_kind(\"binary\")\n    add_files(\"2.cpp\")\n    set_languages(\"clatest\", \"cxx20\")\n"
  },
  {
    "path": "tests/projects/other/parse_headerdeps/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/other/parse_headerdeps/common/test1.hpp",
    "content": "// ../common/test1.hpp \n#include <iostream>\n \nvoid f()\n{\n  std::cout << \"f()\" << std::endl;\n}\n   \n\n"
  },
  {
    "path": "tests/projects/other/parse_headerdeps/src/test1.cpp",
    "content": "// test1.cpp \n#include \"common/test1.hpp\"\n\nint main(int argc, char** argv)\n{\n  f();\n  return 0;\n}\n"
  },
  {
    "path": "tests/projects/other/parse_headerdeps/src/xmake.lua",
    "content": "-- xmake.lua\n-- global\nadd_rules('mode.debug', 'mode.release')\n\nset_version('0.1.0')\n\nset_kind('binary')\nadd_includedirs('..')\nset_warnings('all')\n--set_languages('cxx20')\ntarget('test1')\n    add_files('test1.cpp')\n"
  },
  {
    "path": "tests/projects/package/basic/src/main.c",
    "content": "#include <stdio.h>\n#include <pcre2.h>\n\nint test();\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    pcre2_compile(0, 0, 0, 0, 0, 0);\n    test();\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/basic/src/test.c",
    "content": "#include <stdio.h>\n#include <pcre2.h>\n\nint test()\n{\n    printf(\"hello world!\\n\");\n    pcre2_compile(0, 0, 0, 0, 0, 0);\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/package/basic/test.lua",
    "content": "function main(t)\n\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/basic/xmake.lua",
    "content": "add_requires(\"tbox master\", {debug = true})\nadd_requires(\"zlib >=1.2.11\")\nadd_requires(\"pcre2\", {system = false, optional = true})\n\nadd_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"static\")\n    add_files(\"src/test.c\")\n    add_packages(\"pcre2\", {public = true})\n\ntarget(\"console\")\n    set_kind(\"binary\")\n    add_deps(\"test\")\n    add_files(\"src/main.c\")\n    add_packages(\"tbox\", \"zlib\")\n\n"
  },
  {
    "path": "tests/projects/package/brew/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/brew/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/brew/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"brew::pcre2/libpcre2-8\", {alias = \"pcre2\"})\n\ntarget(\"brew\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"pcre2\")\n\n"
  },
  {
    "path": "tests/projects/package/cmake/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/cmake/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/cmake/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"cmake::ZLIB\", {system = true})\nadd_requires(\"cmake::LibXml2\", {system = true})\nadd_requires(\"cmake::Boost\", {system = true,\n    configs = {components = {\"regex\", \"system\"}, presets = {Boost_USE_STATIC_LIB = true}}})\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"cmake::ZLIB\", \"cmake::Boost\", \"cmake::LibXml2\")\n\n\n"
  },
  {
    "path": "tests/projects/package/compatibility/deps_with_version/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/compatibility/deps_with_version/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/compatibility/deps_with_version/xmake.lua",
    "content": "package(\"foo\")\n    add_deps(\"zlib >=1.2.13\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"bar\")\n    add_deps(\"zlib 1.2.x\")\n--    add_deps(\"libpng dev\")\n--    add_deps(\"boost\", {system = false, configs = {zlib = false}})\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"zoo\")\n--    add_deps(\"libpng master\")\n--    add_deps(\"boost\", {system = false, configs = {zlib = true}})\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"test\")\n    add_deps(\"foo\", \"bar\", \"zoo\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\nadd_requires(\"test\")\n--add_requireconfs(\"**.boost\", {override = true, configs = {zlib = false}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"test\")\n"
  },
  {
    "path": "tests/projects/package/compatibility/sync_requires_to_deps/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/compatibility/sync_requires_to_deps/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/compatibility/sync_requires_to_deps/xmake.lua",
    "content": "\npackage(\"foo\")\n    add_deps(\"zlib >=1.2.13\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"bar\")\n    add_deps(\"zlib 1.2.x\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"zoo\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\npackage(\"test\")\n    add_deps(\"foo\", \"bar\", \"zoo\")\n    set_policy(\"package.install_locally\", true)\n    on_install(function () end)\npackage_end()\n\nset_policy(\"package.sync_requires_to_deps\", true)\n\nadd_requires(\"test\")\nadd_requires(\"zlib >=1.2.13\", {system = false, configs = {shared = true}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"test\")\n"
  },
  {
    "path": "tests/projects/package/components/src/graphics.cpp",
    "content": "#include <SFML/Graphics.hpp>\n\nextern \"C\" {\nvoid graphics() {\n    sf::Text text;\n    text.setString(\"Hello world\");\n}\n}\n"
  },
  {
    "path": "tests/projects/package/components/src/main.cpp",
    "content": "#include <SFML/Graphics.hpp>\n#include <SFML/Network.hpp>\n\nextern \"C\" {\nvoid network();\nvoid graphics();\n}\n\nint main(int argc, char** argv) {\n    network();\n    graphics();\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/package/components/src/network.cpp",
    "content": "#include <SFML/Network.hpp>\n\nextern \"C\" {\nvoid network() {\n    sf::UdpSocket socket;\n    socket.bind(54000);\n\n    char data[100];\n    std::size_t received;\n    sf::IpAddress sender;\n    unsigned short port;\n    socket.receive(data, 100, received, sender, port);\n}\n}\n"
  },
  {
    "path": "tests/projects/package/components/test.lua",
    "content": "function main(t)\n    if is_host(\"bsd\", \"solaris\", \"haiku\") or is_subhost(\"msys\") then\n        return\n    end\n    if is_host(\"linux\") and linuxos.name() == \"alpine\" then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/components/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"sfml\")\n\ntarget(\"graphics\")\n    set_kind(\"static\")\n    add_files(\"src/graphics.cpp\")\n    add_packages(\"sfml\", {components = \"graphics\", public = true})\n\ntarget(\"network\")\n    set_kind(\"static\")\n    add_files(\"src/network.cpp\")\n    add_packages(\"sfml\", {components = \"network\", public = true})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.cpp\")\n    add_deps(\"graphics\", \"network\")\n\npackage(\"sfml\")\n\n    set_homepage(\"https://www.sfml-dev.org\")\n    set_description(\"Simple and Fast Multimedia Library\")\n\n    if is_plat(\"windows\", \"linux\") then\n        set_urls(\"https://www.sfml-dev.org/files/SFML-$(version)-sources.zip\")\n        add_urls(\"https://github.com/SFML/SFML/releases/download/$(version)/SFML-$(version)-sources.zip\")\n        add_versions(\"2.5.1\", \"bf1e0643acb92369b24572b703473af60bac82caf5af61e77c063b779471bb7f\")\n    elseif is_plat(\"macosx\") then\n        if is_arch(\"x64\", \"x86_64\") then\n            set_urls(\"https://www.sfml-dev.org/files/SFML-$(version)-macOS-clang.tar.gz\")\n            add_versions(\"2.5.1\", \"6af0f14fbd41dc038a00d7709f26fb66bb7ccdfe6187657ef0ef8cba578dcf14\")\n\n            add_configs(\"debug\", {builtin = true, description = \"Enable debug symbols.\", default = false, type = \"boolean\", readonly = true})\n            add_configs(\"shared\", {description = \"Build shared library.\", default = true, type = \"boolean\", readonly = true})\n        end\n    end\n\n    if is_plat(\"linux\") then\n        add_syslinks(\"pthread\")\n    end\n\n    add_configs(\"graphics\",   {description = \"Use the graphics module\", default = true, type = \"boolean\"})\n    add_configs(\"window\",     {description = \"Use the window module\", default = true, type = \"boolean\"})\n    add_configs(\"audio\",      {description = \"Use the audio module\", default = true, type = \"boolean\"})\n    add_configs(\"network\",    {description = \"Use the network module\", default = true, type = \"boolean\"})\n    if is_plat(\"windows\") then\n        add_configs(\"main\",       {description = \"Link to the sfml-main library\", default = true, type = \"boolean\"})\n    end\n\n    if is_plat(\"macosx\") then\n        add_extsources(\"brew::sfml/sfml-all\")\n    end\n\n    on_component(\"graphics\", function (package, component)\n        local e = package:config(\"shared\") and \"\" or \"-s\"\n        if package:debug() then\n            e = e .. \"-d\"\n        end\n        component:add(\"links\", \"sfml-graphics\" .. e)\n        if package:is_plat(\"windows\") and not package:config(\"shared\") then\n            component:add(\"links\", \"freetype\")\n            component:add(\"syslinks\", \"opengl32\", \"gdi32\", \"user32\", \"advapi32\")\n        end\n        component:add(\"deps\", \"window\", \"system\")\n        component:add(\"extsources\", \"brew::sfml/sfml-graphics\")\n    end)\n\n    on_component(\"window\", function (package, component)\n        local e = package:config(\"shared\") and \"\" or \"-s\"\n        if package:debug() then\n            e = e .. \"-d\"\n        end\n        component:add(\"links\", \"sfml-window\" .. e)\n        if package:is_plat(\"windows\") and not package:config(\"shared\") then\n            component:add(\"syslinks\", \"opengl32\", \"gdi32\", \"user32\", \"advapi32\")\n        end\n        component:add(\"deps\", \"system\")\n        component:add(\"extsources\", \"brew::sfml/sfml-window\")\n    end)\n\n    on_component(\"audio\", function (package, component)\n        local e = package:config(\"shared\") and \"\" or \"-s\"\n        if package:debug() then\n            e = e .. \"-d\"\n        end\n        component:add(\"links\", \"sfml-audio\" .. e)\n        if package:is_plat(\"windows\") and not package:config(\"shared\") then\n            component:add(\"links\", \"openal32\", \"flac\", \"vorbisenc\", \"vorbisfile\", \"vorbis\", \"ogg\")\n        end\n        component:add(\"deps\", \"system\")\n        component:add(\"extsources\", \"brew::sfml/sfml-audio\")\n    end)\n\n    on_component(\"network\", function (package, component)\n        local e = package:config(\"shared\") and \"\" or \"-s\"\n        if package:debug() then\n            e = e .. \"-d\"\n        end\n        component:add(\"links\", \"sfml-network\" .. e)\n        if package:is_plat(\"windows\") and not package:config(\"shared\") then\n            component:add(\"syslinks\", \"ws2_32\")\n        end\n        component:add(\"deps\", \"system\")\n        component:add(\"extsources\", \"brew::sfml/sfml-network\")\n        component:add(\"extsources\", \"apt::sfml-network\")\n    end)\n\n    on_component(\"system\", function (package, component)\n        local e = package:config(\"shared\") and \"\" or \"-s\"\n        if package:debug() then\n            e = e .. \"-d\"\n        end\n        component:add(\"links\", \"sfml-system\" .. e)\n        if package:is_plat(\"windows\") then\n            component:add(\"syslinks\", \"winmm\")\n        end\n        if package:is_plat(\"windows\") and package:config(\"main\") then\n            component:add(\"deps\", \"main\")\n        end\n        component:add(\"extsources\", \"brew::sfml/sfml-system\")\n    end)\n\n    on_component(\"main\", function (package, component)\n        if package:is_plat(\"windows\") then\n            local main_module = \"sfml-main\"\n            if package:debug() then\n                main_module = main_module .. \"-d\"\n            end\n            component:add(\"links\", main_module)\n        end\n    end)\n\n    on_load(\"windows\", \"linux\", \"macosx\", function (package)\n        if package:is_plat(\"windows\", \"linux\") then\n            package:add(\"deps\", \"cmake\")\n        end\n\n        if not package:config(\"shared\") then\n            package:add(\"defines\", \"SFML_STATIC\")\n        end\n\n        if package:is_plat(\"linux\") then\n            if package:config(\"window\") or package:config(\"graphics\") then\n                package:add(\"deps\", \"libx11\", \"libxext\", \"libxrandr\", \"libxrender\", \"freetype\", \"eudev\")\n                package:add(\"deps\", \"opengl\", \"glx\", {optional = true})\n            end\n            if package:config(\"audio\") then\n                package:add(\"deps\", \"libogg\", \"libflac\", \"libvorbis\", \"openal-soft\")\n            end\n        end\n        package:add(\"components\", \"system\")\n        for _, component in ipairs({\"graphics\", \"window\", \"audio\", \"network\"}) do\n            if package:config(component) then\n                package:add(\"components\", component)\n            end\n        end\n        if package:is_plat(\"windows\") and package:config(\"main\") then\n            package:add(\"components\", \"main\")\n        end\n    end)\n\n    on_install(\"windows\", \"linux\", function (package)\n        local configs = {\"-DSFML_BUILD_DOC=OFF\", \"-DSFML_BUILD_EXAMPLES=OFF\"}\n        table.insert(configs, \"-DCMAKE_BUILD_TYPE=\" .. (package:debug() and \"Debug\" or \"Release\"))\n        if package:config(\"shared\") then\n            table.insert(configs, \"-DBUILD_SHARED_LIBS=ON\")\n        else\n            table.insert(configs, \"-DBUILD_SHARED_LIBS=OFF\")\n            if package:is_plat(\"windows\") and package:runtimes():startswith(\"MT\") then\n                table.insert(configs, \"-DSFML_USE_STATIC_STD_LIBS=ON\")\n            end\n        end\n        local packagedeps\n        if package:is_plat(\"linux\") and package:config(\"shared\") then\n            io.replace(\"src/SFML/Graphics/CMakeLists.txt\", \"target_link_libraries(sfml-graphics PRIVATE X11)\",\n                \"target_link_libraries(sfml-graphics PRIVATE X11 Xext Xrender)\", {plain = true})\n            packagedeps = {\"libxext\", \"libxrender\"}\n        end\n        table.insert(configs, \"-DSFML_BUILD_AUDIO=\" .. (package:config(\"audio\") and \"ON\" or \"OFF\"))\n        table.insert(configs, \"-DSFML_BUILD_GRAPHICS=\" .. (package:config(\"graphics\") and \"ON\" or \"OFF\"))\n        table.insert(configs, \"-DSFML_BUILD_WINDOW=\" .. (package:config(\"window\") and \"ON\" or \"OFF\"))\n        table.insert(configs, \"-DSFML_BUILD_NETWORK=\" .. (package:config(\"network\") and \"ON\" or \"OFF\"))\n        import(\"package.tools.cmake\").install(package, configs, {packagedeps = packagedeps})\n    end)\n\n    on_install(\"macosx\", function (package)\n        os.cp(\"lib\", package:installdir())\n        os.cp(\"include\", package:installdir())\n    end)\n\n    on_test(function (package)\n        assert(package:check_cxxsnippets({test = [[\n            void test(int args, char** argv) {\n                sf::Clock c;\n                c.restart();\n            }\n        ]]}, {includes = \"SFML/System.hpp\"}))\n        if package:config(\"graphics\") then\n            assert(package:check_cxxsnippets({test = [[\n                void test(int args, char** argv) {\n                    sf::Text text;\n                    text.setString(\"Hello world\");\n                }\n            ]]}, {includes = \"SFML/Graphics.hpp\"}))\n        end\n        if package:config(\"window\") or package:config(\"graphics\") then\n            assert(package:check_cxxsnippets({test = [[\n                void test(int args, char** argv) {\n                    sf::Window window(sf::VideoMode(1280, 720), \"Title\");\n\n                    sf::Event event;\n                    window.pollEvent(event);\n                }\n            ]]}, {includes = \"SFML/Window.hpp\"}))\n        end\n        if package:config(\"audio\") then\n            assert(package:check_cxxsnippets({test = [[\n                void test(int args, char** argv) {\n                    sf::Music music;\n                    music.openFromFile(\"music.ogg\");\n                    music.play();\n                }\n            ]]}, {includes = \"SFML/Audio.hpp\"}))\n        end\n        if package:config(\"network\") then\n            assert(package:check_cxxsnippets({test = [[\n                void test(int args, char** argv) {\n                    sf::UdpSocket socket;\n                    socket.bind(54000);\n\n                    char data[100];\n                    std::size_t received;\n                    sf::IpAddress sender;\n                    unsigned short port;\n                    socket.receive(data, 100, received, sender, port);\n                }\n            ]]}, {includes = \"SFML/Network.hpp\"}))\n        end\n    end)\npackage_end()\n"
  },
  {
    "path": "tests/projects/package/conan/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/conan/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/conan/xmake.lua",
    "content": "add_requires(\"conan::zlib 1.2.11\", {alias = \"zlib\", debug = true,\n    configs = {settings = \"compiler.cppstd=14\"}})\nadd_requires(\"conan::openssl 1.1.1t\", {alias = \"openssl\",\n    configs = {options = \"shared=True\"}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"openssl\", \"zlib\")\n\n"
  },
  {
    "path": "tests/projects/package/depconfigs/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/depconfigs/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/depconfigs/xmake.lua",
    "content": "add_requires(\"libpng\", {system = false, configs = {runtimes = \"MD\"}})\nadd_requires(\"libtiff\", {system = false, configs = {runtimes = \"MD\", zlib = true}})\n\nadd_requireconfs(\"libpng.zlib\",        {system = false, override = true, configs = {cxflags = \"-DTEST1\"}, version = \"1.2.10\"})\nadd_requireconfs(\"libtiff.*|cmake\",    {system = false, configs = {cxflags = \"-DTEST2\"}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"libpng\")\n    before_build(function (target)\n        if target:pkg(\"libpng\") then\n            local found\n            for _, linkdir in ipairs(target:pkg(\"libpng\"):get(\"linkdirs\")) do\n                if linkdir:find(\"zlib[/\\\\]v1%.2%.10\") then\n                    found = true\n                end\n            end\n            assert(found, \"package(zlib 1.2.10) not found!\")\n        end\n    end)\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"libtiff\")\n    before_build(function (target)\n        if target:pkg(\"libtiff\") then\n            local found\n            for _, linkdir in ipairs(target:pkg(\"libtiff\"):get(\"linkdirs\")) do\n                if linkdir:find(\"zlib\", 1, true) then\n                    found = true\n                end\n            end\n            assert(found, \"package(zlib) not found!\")\n        end\n    end)\n\n"
  },
  {
    "path": "tests/projects/package/inherit_base/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/inherit_base/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/inherit_base/xmake.lua",
    "content": "package(\"myzlib\")\n    set_base(\"zlib\")\n    set_urls(\"https://github.com/madler/zlib.git\")\npackage_end()\n\nadd_requires(\"myzlib\", {system = false, alias = \"zlib\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\")\n"
  },
  {
    "path": "tests/projects/package/llvm_dev/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/llvm_dev/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/llvm_dev/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"llvm\", {kind = \"library\", configs = {mlir = true}})\n\ntarget(\"testllvm\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"llvm\", {components = \"mlir\"})\n\n"
  },
  {
    "path": "tests/projects/package/multiconfig/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/multiconfig/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/multiconfig/xmake.lua",
    "content": "add_requires(\"zlib\", {system = false})\nadd_requires(\"zlib\", {system = false}) -- test repeat requires\nadd_requires(\"zlib~debug\", {system = false, debug = true})\nadd_requires(\"zlib~shared\", {system = false, configs = {shared = true}, alias = \"zlib_shared\"})\nset_policy(\"package.requires_lock\", true)\n\ntarget(\"test1\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\")\n\ntarget(\"test2\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib~debug\")\n\ntarget(\"test3\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib_shared\")\n"
  },
  {
    "path": "tests/projects/package/multiplat/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/multiplat/src/main.cpp",
    "content": "/*******************************************************************************************\n*\n*   raylib [core] example - Basic window\n*\n*   Welcome to raylib!\n*\n*   To test examples, just press F6 and execute raylib_compile_execute script\n*   Note that compiled executable is placed in the same folder as .c file\n*\n*   You can find all basic examples on C:\\raylib\\raylib\\examples folder or\n*   raylib official webpage: www.raylib.com\n*\n*   Enjoy using raylib. :)\n*\n*   This example has been created using raylib 1.0 (www.raylib.com)\n*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)\n*\n*   Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)\n*\n********************************************************************************************/\n\n#include \"raylib.h\"\n\nint main(void)\n{\n    // Initialization\n    //--------------------------------------------------------------------------------------\n    const int screenWidth = 800;\n    const int screenHeight = 450;\n\n    InitWindow(screenWidth, screenHeight, \"raylib [core] example - basic window\");\n\n    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second\n    //--------------------------------------------------------------------------------------\n\n    // Main game loop\n    while (!WindowShouldClose())    // Detect window close button or ESC key\n    {\n        // Update\n        //----------------------------------------------------------------------------------\n        // TODO: Update your variables here\n        //----------------------------------------------------------------------------------\n\n        // Draw\n        //----------------------------------------------------------------------------------\n        BeginDrawing();\n\n        ClearBackground(RAYWHITE);\n\n        DrawText(\"Congrats! You created your first window!\", 190, 200, 20, LIGHTGRAY);\n\n        EndDrawing();\n        //----------------------------------------------------------------------------------\n    }\n\n    // De-Initialization\n    //--------------------------------------------------------------------------------------\n    CloseWindow();        // Close window and OpenGL context\n    //--------------------------------------------------------------------------------------\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/multiplat/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"raylib\")\nadd_requires(\"raylib~mingw\", {plat = \"mingw\", arch = \"x86_64\"})\n\ntarget(\"hello\")\n    add_packages(\"raylib\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_languages(\"c++11\")\n\ntarget(\"hello_mingw\")\n    set_plat(\"mingw\")\n    set_arch(\"x86_64\")\n    add_packages(\"raylib~mingw\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/package/nuget/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "tests/projects/package/nuget/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/nuget/xmake.lua",
    "content": "add_requires(\"nuget::zlib_static\", {alias = \"zlib\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"zlib\")\n\n"
  },
  {
    "path": "tests/projects/package/package_rule/repo/packages/f/foo/rules/markdown.lua",
    "content": "rule(\"markdown\")\n    set_extensions(\".md\")\n    on_config(function (target)\n        print(\"test: config %s\", target:name())\n    end)\n    on_build_file(function(target, sourcefile)\n        print(\"test: build %s\", sourcefile)\n    end)\n    after_clean(function (target)\n        print(\"test: clean\")\n    end)\n"
  },
  {
    "path": "tests/projects/package/package_rule/repo/packages/f/foo/xmake.lua",
    "content": "package(\"foo\")\n    on_install(function()\n    end)\n"
  },
  {
    "path": "tests/projects/package/package_rule/src/main.cpp",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/package_rule/src/test.md",
    "content": ""
  },
  {
    "path": "tests/projects/package/package_rule/test.lua",
    "content": "function main(t)\n\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/package_rule/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"foo\")\nadd_repositories(\"myrepo ./repo\")\n\ntarget(\"console\")\n    set_kind(\"binary\")\n    add_files(\"src/main.cpp\", \"src/*.md\")\n    add_packages(\"foo\")\n    add_rules(\"@foo/markdown\")\n\n"
  },
  {
    "path": "tests/projects/package/requires_lock/src/main.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n\nint main(int argc, char** argv) {\n    printf(\"zlib version: %s\\n\", zlibVersion());\n    \n    // simple compression test\n    const char* source = \"Hello, zlib requires lock test!\";\n    uLong sourceLen = strlen(source) + 1;\n    uLong destLen = compressBound(sourceLen);\n    Bytef* dest = (Bytef*)malloc(destLen);\n    \n    if (compress(dest, &destLen, (const Bytef*)source, sourceLen) == Z_OK) {\n        printf(\"Compression successful, compressed size: %lu\\n\", destLen);\n        \n        // decompression test\n        uLong decompLen = sourceLen;\n        Bytef* decomp = (Bytef*)malloc(decompLen);\n        if (uncompress(decomp, &decompLen, dest, destLen) == Z_OK) {\n            printf(\"Decompression successful: %s\\n\", (char*)decomp);\n        }\n        free(decomp);\n    }\n    free(dest);\n    \n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/requires_lock/test.lua",
    "content": "import(\"core.project.config\")\n\n-- helper function to count table entries\nfunction count_table(t)\n    local count = 0\n    for _ in pairs(t) do\n        count = count + 1\n    end\n    return count\nend\n\n-- helper function to get all package keys from lock data\nfunction get_package_keys(lockdata)\n    local keys = {}\n    for key, _ in pairs(lockdata) do\n        if key ~= \"__meta__\" then\n            table.insert(keys, key)\n        end\n    end\n    return keys\nend\n\n-- helper function to verify lock file basic structure\nfunction verify_lock_file_structure(lockdata)\n    assert(lockdata, \"lock file should be loadable\")\n    assert(lockdata.__meta__, \"lock file should have metadata\")\n    assert(lockdata.__meta__.version == \"1.0\", \"lock file version should be 1.0\")\n\n    -- find any platform entry\n    local found_platform = nil\n    for key, value in pairs(lockdata) do\n        if key ~= \"__meta__\" then\n            found_platform = key\n            break\n        end\n    end\n\n    assert(found_platform, \"no platform entries found in lock file\")\n    return lockdata[found_platform]\nend\n\n-- helper function to count zlib entries\nfunction count_zlib_entries(plat_entries)\n    local zlib_count = 0\n    for key, _ in pairs(plat_entries) do\n        if key:find(\"zlib\") then\n            zlib_count = zlib_count + 1\n        end\n    end\n    return zlib_count\nend\n\n-- helper function to remove installed packages to trigger reinstallation\nfunction remove_zlib_packages()\n    os.execv(\"xmake\", {\"lua\", \"private.xrepo\", \"remove\", \"--all\", \"-y\", \"zlib\"})\nend\n\n-- helper function to remove existing lock file\nfunction remove_lock_file(scriptdir)\n    local lockfile = path.join(scriptdir, \"xmake-requires.lock\")\n    os.tryrm(lockfile)\nend\n\n-- test lock file generation and basic content validation\nfunction test_lock_file_generation(scriptdir)\n    local lockfile = path.join(scriptdir, \"xmake-requires.lock\")\n    assert(os.isfile(lockfile), \"xmake-requires.lock should be generated\")\n\n    -- load and verify lock file content\n    local lockdata = io.load(lockfile)\n    local plat_entries = verify_lock_file_structure(lockdata)\n\n    -- check zlib entries and repo info\n    local found_zlib = false\n    for key, package_data in pairs(plat_entries) do\n        if key:find(\"zlib#\") then\n            found_zlib = true\n            assert(package_data.version, \"zlib should have version\")\n            assert(package_data.repo, \"zlib should have repo info\")\n            assert(package_data.repo.url, \"zlib repo should have url\")\n            assert(package_data.repo.commit, \"zlib repo should have commit\")\n        end\n    end\n\n    -- we should have three zlib entries (version constraint, specific version, shared config)\n    local zlib_count = count_zlib_entries(plat_entries)\n    assert(zlib_count == 3, \"should find 3 zlib entries in lock file, found: \" .. zlib_count)\n    assert(found_zlib, \"should find zlib entry in lock file\")\n\n    -- verify specific versions are locked correctly\n    local found_old_version = false\n    for key, package_data in pairs(plat_entries) do\n        if key:find(\"zlib 1.2.13#\") then\n            found_old_version = true\n            assert(package_data.version == \"v1.2.13\", \"zlib 1.2.13 should be locked to v1.2.13\")\n        end\n    end\n    assert(found_old_version, \"should find zlib 1.2.13 entry with v1.2.13\")\n\n    print(\"✓ lock file generation test passed\")\nend\n\n-- test lock file stability across rebuilds\nfunction test_lock_file_stability(scriptdir, t)\n    local lockfile = path.join(scriptdir, \"xmake-requires.lock\")\n\n    -- get the lock file content and mtime after first build\n    local lockdata_after_first = io.load(lockfile)\n    local mtime_after_first = os.mtime(lockfile)\n    local keys_after_first = get_package_keys(lockdata_after_first)\n\n    -- remove installed packages using xmake lua private.xrepo to trigger reinstallation\n    remove_zlib_packages()\n\n    -- rebuild and verify lock file content doesn't change\n    t:build()\n\n    local lockdata_after_second = io.load(lockfile)\n    local mtime_after_second = os.mtime(lockfile)\n    local keys_after_second = get_package_keys(lockdata_after_second)\n\n    -- compare lock file content\n    assert(lockdata_after_first.__meta__.version == lockdata_after_second.__meta__.version, \"lock metadata version should not change\")\n    assert(count_table(lockdata_after_first) == count_table(lockdata_after_second), \"lock file structure should not change\")\n\n    -- compare platform-specific entries using the same platform for consistency\n    local plat_entries_after_first = verify_lock_file_structure(lockdata_after_first)\n    local plat_entries_after_second = verify_lock_file_structure(lockdata_after_second)\n\n    -- ensure we're comparing the same platform entries by finding the common platform\n    local first_platform_key = nil\n    for key, value in pairs(lockdata_after_first) do\n        if key ~= \"__meta__\" then\n            first_platform_key = key\n            break\n        end\n    end\n\n    assert(first_platform_key, \"no platform found in first lock file\")\n    assert(lockdata_after_second[first_platform_key], \"platform \" .. first_platform_key .. \" not found in second lock file\")\n\n    plat_entries_after_first = lockdata_after_first[first_platform_key]\n    plat_entries_after_second = lockdata_after_second[first_platform_key]\n\n    assert(count_table(plat_entries_after_first) == count_table(plat_entries_after_second), \"platform entries count should not change\")\n\n    -- verify package key order stability (keys should be in same order)\n    assert(#keys_after_first == #keys_after_second, \"package keys count should be the same\")\n    for i, key in ipairs(keys_after_first) do\n        assert(keys_after_second[i] == key, \"package key order should be stable at index \" .. i .. \": \" .. key)\n    end\n\n    -- verify each package entry is identical\n    for key, first_data in pairs(plat_entries_after_first) do\n        local second_data = plat_entries_after_second[key]\n        assert(second_data, \"package entry should exist: \" .. key)\n        assert(first_data.version == second_data.version, \"version should not change for: \" .. key .. \", first: \" .. (first_data.version or \"nil\") .. \", second: \" .. (second_data.version or \"nil\"))\n        assert(first_data.repo.url == second_data.repo.url, \"repo url should not change for: \" .. key .. \", first: \" .. (first_data.repo.url or \"nil\") .. \", second: \" .. (second_data.repo.url or \"nil\"))\n        assert(first_data.repo.commit == second_data.repo.commit, \"repo commit should not change for: \" .. key .. \", first: \" .. (first_data.repo.commit or \"nil\") .. \", second: \" .. (second_data.repo.commit or \"nil\"))\n        assert(first_data.repo.branch == second_data.repo.branch, \"repo branch should not change for: \" .. key .. \", first: \" .. (first_data.repo.branch or \"nil\") .. \", second: \" .. (second_data.repo.branch or \"nil\"))\n    end\n\n    -- verify mtime doesn't change (lock file should only be written when content actually changes)\n    -- With copy_if_different, the file should not be rewritten if content is identical\n    local time_diff = math.abs(mtime_after_second - mtime_after_first)\n    print(\"lock file mtime difference: \" .. time_diff .. \"s\")\n    -- mtime should be exactly the same when content is identical\n    assert(time_diff == 0, \"lock file mtime should not change when content is identical, diff: \" .. time_diff .. \"s\")\n\n    print(\"✓ lock file stability test passed\")\nend\n\nfunction main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n\n        -- get script directory from context filename\n        local scriptdir = path.directory(t.filename)\n\n        -- remove existing lock file before test\n        remove_lock_file(scriptdir)\n\n        -- remove installed packages using xmake lua private.xrepo to trigger reinstallation\n        remove_zlib_packages()\n\n        -- build project and generate requires lock\n        t:build()\n\n        -- test requires lock file generation and content\n        test_lock_file_generation(scriptdir)\n\n        -- test building with existing lock file\n        t:build()\n\n        -- test lock file stability across rebuilds\n        test_lock_file_stability(scriptdir, t)\n\n        print(\"requires lock test passed!\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/requires_lock/xmake.lua",
    "content": "-- test requires lock functionality with zlib package\nset_policy(\"package.requires_lock\", true)\n\nadd_requires(\"zlib >=1.2.11\", {system = false})\nadd_requires(\"zlib 1.2.13\", {system = false, alias = \"zlib_old\"})  -- test lower version\nadd_requires(\"zlib\", {system = false, configs = {shared = true}, alias = \"zlib_shared\"})\n\ntarget(\"test_static\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\")\n\ntarget(\"test_shared\")\n    set_kind(\"binary\") \n    add_files(\"src/*.c\")\n    add_packages(\"zlib_shared\")\n\ntarget(\"test_old\")\n    set_kind(\"binary\") \n    add_files(\"src/*.c\")\n    add_packages(\"zlib_old\")\n"
  },
  {
    "path": "tests/projects/package/rootconfigs/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/rootconfigs/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\n\n    -- test packagekey\n    os.execv(\"xmake\", {\"lua\", \"-vD\", \"utils.ci.packageskey\"})\nend\n"
  },
  {
    "path": "tests/projects/package/rootconfigs/xmake.lua",
    "content": "add_requireconfs(\"*\", {system = false, configs = {debug = false}})\nadd_requires(\"zlib\", {system = false, debug = true})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\")\n"
  },
  {
    "path": "tests/projects/package/schemes/port/xmake.lua",
    "content": "includes(\"@builtin/check\")\n\nadd_rules(\"mode.release\", \"mode.debug\")\n\noption(\"version\", {description = \"The ninja version.\"})\nset_version(\"$(version)\")\n\nset_languages(\"c++14\")\ncheck_cfuncs(\"USE_PPOLL=1\", \"ppoll\", {includes = \"poll.h\"})\n\ntarget(\"libninja\")\n    set_kind(\"$(kind)\")\n    set_basename(\"ninja\")\n\n    add_files(\"src/build_log.cc\")\n    add_files(\"src/build.cc\")\n    add_files(\"src/clean.cc\")\n    add_files(\"src/clparser.cc\")\n    add_files(\"src/debug_flags.cc\")\n    add_files(\"src/deps_log.cc\")\n    add_files(\"src/disk_interface.cc\")\n    add_files(\"src/edit_distance.cc\")\n    add_files(\"src/eval_env.cc\")\n    add_files(\"src/graph.cc\")\n    add_files(\"src/graphviz.cc\")\n    add_files(\"src/line_printer.cc\")\n    add_files(\"src/manifest_parser.cc\")\n    add_files(\"src/metrics.cc\")\n    add_files(\"src/state.cc\")\n    add_files(\"src/string_piece_util.cc\")\n    add_files(\"src/util.cc\")\n    add_files(\"src/version.cc\")\n    add_files(\"src/depfile_parser.cc\", \"src/lexer.cc\")\n\n    if is_plat(\"windows\", \"mingw\", \"msys\") then\n        add_files(\"src/subprocess-win32.cc\")\n        add_files(\"src/includes_normalize-win32.cc\")\n        add_files(\"src/msvc_helper-win32.cc\")\n        add_files(\"src/msvc_helper_main-win32.cc\")\n        add_files(\"src/getopt.c\", {sourcekind = \"cxx\"})\n        add_files(\"src/minidump-win32.cc\")\n\n        add_defines(\"NOMINMAX\")\n    else\n        add_files(\"src/subprocess-posix.cc\")\n    end\n\n    if is_plat(\"mingw\") then\n        add_defines(\"_WIN32_WINNT=0x0601\", \"__USE_MINGW_ANSI_STDIO=1\")\n    end\n\n    on_load(function (target)\n        import(\"core.base.semver\")\n        local version = semver.new(target:version())\n        if version:ge(\"1.13.1\") then\n            target:add(\"files\", \"src/elide_middle.cc\")\n            target:add(\"files\", \"src/jobserver.cc\")\n            target:add(\"files\", \"src/real_command_runner.cc\")\n            target:add(\"files\", \"src/status_printer.cc\")\n            if target:is_plat(\"windows\", \"mingw\", \"msys\") then\n                target:add(\"files\", \"src/jobserver-win32.cc\")\n            else\n                target:add(\"files\", \"src/jobserver-posix.cc\")\n            end\n        end\n        if version:ge(\"1.11.0\") then\n            if version:lt(\"1.13.1\") then\n                target:add(\"files\", \"src/status.cc\")\n            end\n            target:add(\"files\", \"src/json.cc\")\n            target:add(\"files\", \"src/missing_deps.cc\")\n        end\n        if version:ge(\"1.10.0\") then\n            target:add(\"files\", \"src/dyndep.cc\")\n            target:add(\"files\", \"src/dyndep_parser.cc\")\n            target:add(\"files\", \"src/parser.cc\")\n        end\n    end)\n\ntarget(\"ninja\")\n    set_kind(\"binary\")\n    add_deps(\"libninja\")\n\n    add_files(\"src/ninja.cc\")\n    if is_plat(\"windows\") then\n        add_files(\"windows/ninja.manifest\")\n    end\n"
  },
  {
    "path": "tests/projects/package/schemes/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char** argv) {\n    std::cout << \"Hello, schemes test!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/schemes/test.lua",
    "content": "function main(t)\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/schemes/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\npackage(\"ninja\")\n    set_kind(\"binary\")\n    set_homepage(\"https://ninja-build.org/\")\n    set_description(\"Small build system for use with gyp or CMake.\")\n\n    local function add_binary_urls(package, scheme_name)\n        local scheme = package\n        if scheme_name then\n            scheme = package:scheme(scheme_name)\n        end\n\n        if is_host(\"macosx\") then\n            scheme:add(\"urls\", \"https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-mac.zip\")\n            scheme:add(\"versions\", \"1.13.1\", \"da7797794153629aca5570ef7c813342d0be214ba84632af886856e8f0063dd9\")\n            return true\n        elseif is_host(\"linux\") then\n            scheme:add(\"urls\", \"https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-linux.zip\")\n            scheme:add(\"versions\", \"1.13.1\", \"0830252db77884957a1a4b87b05a1e2d9b5f658b8367f82999a941884cbe0238\")\n            return true\n        elseif is_host(\"windows\") then\n            scheme:add(\"urls\", \"https://github.com/ninja-build/ninja/releases/download/v$(version)/ninja-win.zip\")\n            scheme:add(\"versions\", \"1.13.1\", \"26a40fa8595694dec2fad4911e62d29e10525d2133c9a4230b66397774ae25bf\")\n            return true\n        end\n    end\n\n    local function add_source_urls(package, scheme_name)\n        local scheme = package\n        if scheme_name then\n            scheme = package:scheme(scheme_name)\n        end\n        scheme:add(\"urls\", \"https://github.com/ninja-build/ninja/archive/refs/tags/v$(version).tar.gz\")\n        scheme:add(\"versions\", \"1.13.1\",  \"f0055ad0369bf2e372955ba55128d000cfcc21777057806015b45e4accbebf23\")\n    end\n\n    if add_schemes then\n        add_schemes(\"binary\", \"source\")\n        on_source(function (package)\n            add_binary_urls(package, \"binary\")\n            add_source_urls(package, \"source\")\n        end)\n    else\n        -- for compatibility with older xmake versions\n        on_source(function (package)\n            if add_binary_urls(package) then\n                package:data_set(\"scheme\", \"binary\")\n            else\n                add_source_urls(package)\n                package:data_set(\"scheme\", \"source\")\n            end\n        end)\n    end\n\n    on_install(\"@linux\", \"@windows\", \"@msys\", \"@cygwin\", \"@macosx\", function (package)\n        local scheme_name = package.current_scheme and package:current_scheme():name() or package:data(\"scheme\")\n        if scheme_name and scheme_name == \"binary\" then\n            raise(\"trigger failure when installing binaries, then we will fallback to install it from source tarball.\")\n        else\n            local configs = {}\n            configs.version = package:version_str()\n            os.cp(path.join(package:scriptdir(), \"port\", \"xmake.lua\"), \"xmake.lua\")\n            import(\"package.tools.xmake\").install(package, configs)\n        end\n    end)\n\n    on_test(function (package)\n        os.vrun(\"ninja --version\")\n    end)\npackage_end()\n\nadd_requires(\"ninja\", {system = false})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"ninja\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_gnu_rm/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_gnu_rm/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"gnu-rm\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@gnu-rm\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_llvm/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_llvm/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"llvm 14.0.0\", {alias = \"llvm-14\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"llvm@llvm-14\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_llvm_mingw/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_llvm_mingw/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"llvm-mingw\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"mingw[clang]@llvm-mingw\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_msvc/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_msvc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"msvc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@msvc\")\n    --set_toolchains(\"clang-cl@msvc\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_muslcc/src/main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <zlib.h>\n#include <ogg/ogg.h>\n#ifdef HAVE_LIBPLIST\n#   include <plist/plist.h>\n#endif\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    inflate(0, 0);\n    ogg_sync_init(0);\n#ifdef HAVE_LIBPLIST\n    plist_new_dict();\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_muslcc/test.lua",
    "content": "function main(t)\n\n    -- freebsd ci is slower\n    if is_host(\"bsd\", \"solaris\", \"haiku\") then\n        return\n    end\n\n    -- only for x86/x64, because it will take too long time on ci with arm/mips\n    if os.subarch():startswith(\"x\") or os.subarch() == \"i386\" then\n        t:build()\n    end\nend\n"
  },
  {
    "path": "tests/projects/package/toolchain_muslcc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\n-- set cross-compliation platform\nset_plat(\"cross\")\nset_arch(\"arm\")\n\n-- lock requires\nset_policy(\"package.requires_lock\", true)\n\n-- custom toolchain\ntoolchain(\"my_muslcc\")\n    set_homepage(\"https://musl.cc/\")\n    set_description(\"The musl-based cross-compilation toolchains\")\n    set_kind(\"cross\")\n    on_load(function (toolchain)\n        toolchain:load_cross_toolchain()\n        if toolchain:is_arch(\"arm\") then\n            toolchain:add(\"cxflags\", \"-march=armv7-a\", \"-msoft-float\", {force = true})\n            toolchain:add(\"ldflags\", \"-march=armv7-a\", \"-msoft-float\", {force = true})\n        end\n        toolchain:add(\"syslinks\", \"gcc\", \"c\")\n    end)\ntoolchain_end()\n\n-- add library packages\n-- for testing zlib/xmake, libplist/autoconf, libogg/cmake\nadd_requires(\"zlib\", \"libogg\",  {system = false})\nif is_host(\"macosx\", \"linux\", \"bsd\", \"solaris\", \"haiku\") then\n    add_requires(\"libplist\", {system = false})\nend\n\n-- add toolchains package\nadd_requires(\"muslcc\")\n\n-- set global toolchains for target and packages\nset_toolchains(\"my_muslcc@muslcc\")\n\n-- use the builltin toolchain(\"muslcc\") instead of \"my_muslcc\"\n--set_toolchains(\"@muslcc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_packages(\"zlib\", \"libplist\", \"libogg\")\n    if has_package(\"libplist\") then\n        add_defines(\"HAVE_LIBPLIST\")\n    end\n"
  },
  {
    "path": "tests/projects/package/toolchain_tinycc/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char** argv)\n{\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_tinycc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"tinycc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    set_toolchains(\"@tinycc\")\n"
  },
  {
    "path": "tests/projects/package/toolchain_zig/src/main.zig",
    "content": "const std = @import(\"std\");\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s}!\\n\", .{\"world\"});\n}\n"
  },
  {
    "path": "tests/projects/package/toolchain_zig/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"zig\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.zig\")\n    set_toolchains(\"@zig\")\n\n"
  },
  {
    "path": "tests/projects/package/vcpkg/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n"
  },
  {
    "path": "tests/projects/package/vcpkg/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/vcpkg/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"vcpkg::zlib\", \"vcpkg::pcre2\")\nadd_requires(\"vcpkg::boost[core]\", {alias = \"boost\"})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"vcpkg::zlib\", \"vcpkg::pcre2\", \"boost\")\n\n"
  },
  {
    "path": "tests/projects/package/vcpkg_dependency/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n"
  },
  {
    "path": "tests/projects/package/vcpkg_dependency/src/main.cpp",
    "content": "#include <OpenColorIO/OpenColorIO.h>\n#include <OpenImageIO/imageio.h>\n#include <boost/system/error_code.hpp>\n#include <boost/filesystem.hpp>\n\nint main(int argc, char **argv) {\n    // test for opencolorio, opencolorio is one of the dependencies of openimageio.\n    auto transform = OCIO_NAMESPACE::ColorSpaceTransform::Create();\n\n    // test for openimageio.\n    auto write_image = OIIO::ImageInput::open(\"test.png\");\n\n    // test for boost-system, boost-system is one of the dependencies of boost-filesystem.\n    boost::system::error_code ec;\n\n    // test for boost-filesystem.\n    boost::filesystem::exists(\"test.png\", ec);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/vcpkg_dependency/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"vcpkg::openimageio[jpegxl,libraw,webp]\", { configs = { shared = true } })\nadd_requires(\"vcpkg::boost-filesystem\", { alias = \"filesystem\" })\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_languages(\"c++17\")\n    set_encodings(\"utf-8\")\n    add_packages(\"vcpkg::openimageio[jpegxl,libraw,webp]\", \"filesystem\")\n"
  },
  {
    "path": "tests/projects/package/vcpkg_manifest/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n"
  },
  {
    "path": "tests/projects/package/vcpkg_manifest/src/main.cpp",
    "content": "#include <iostream>\n\nusing namespace std;\n\nint main(int argc, char** argv) {\n    cout << \"hello world!\" << endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/package/vcpkg_manifest/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"vcpkg::zlib 1.2.11+10\")\nadd_requires(\"vcpkg::fmt >=8.0.1\", {configs = {baseline = \"50fd3d9957195575849a49fa591e645f1d8e7156\"}})\nadd_requires(\"vcpkg::libpng\", {configs = {features = {\"apng\"}}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"vcpkg::zlib\", \"vcpkg::fmt\", \"vcpkg::libpng\")\n\n"
  },
  {
    "path": "tests/projects/pascal/console/src/main.pas",
    "content": "program Hello;\nbegin\n  writeln ('Hello, world.');\nend.\n"
  },
  {
    "path": "tests/projects/pascal/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.pas\")\n\n"
  },
  {
    "path": "tests/projects/pascal/console_with_c/src/foo.c",
    "content": "#include <stdint.h>\n\nextern int64_t fib(int64_t n) {\n    return n > 1 ? fib(n - 1) + fib(n - 2) : 1;\n}\n"
  },
  {
    "path": "tests/projects/pascal/console_with_c/src/main.pas",
    "content": "program hello;\n\nfunction fib(n: Int64): Int64;\n  cdecl; external 'foo';\n\nvar\n  Value: Integer;\nbegin\n  Value := 5;\n  WriteLn(fib(Value));\nend.\n\n"
  },
  {
    "path": "tests/projects/pascal/console_with_c/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.c\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.pas\")\n"
  },
  {
    "path": "tests/projects/pascal/shared/src/foo.pas",
    "content": "library foo;\n\n{$mode objfpc}{$H+}\n\nfunction fib(n : Int64) : Int64; cdecl;\nbegin\n  if n > 1 then\n  begin\n      Result := fib(n - 1) + fib(n - 2);\n  end\n  else\n        Result := 1;\nend;\n\nexports\n fib;\nend.\n\n\n"
  },
  {
    "path": "tests/projects/pascal/shared/src/main.pas",
    "content": "program hello;\n\nfunction fib(n: Int64): Int64;\n  cdecl; external 'foo';\n\nvar\n  Value: Integer;\nbegin\n  Value := 5;\n  WriteLn(fib(Value));\nend.\n\n\n"
  },
  {
    "path": "tests/projects/pascal/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.pas\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.pas\")\n"
  },
  {
    "path": "tests/projects/policy/compile_commands/src/main.c",
    "content": "int main(int argc, char** argv) {\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/policy/compile_commands/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"enabled\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n\ntarget(\"disabled\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    set_policy(\"generator.compile_commands\", false)\n"
  },
  {
    "path": "tests/projects/python/cython/example/src/example.py",
    "content": "print(\"Hello, world!\")\n"
  },
  {
    "path": "tests/projects/python/cython/example/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"python 3.x\")\n\ntarget(\"example\")\n    add_rules(\"python.cython\")\n    add_files(\"src/*.py\")\n    add_packages(\"python\")\n"
  },
  {
    "path": "tests/projects/python/pybind/example/src/example.cpp",
    "content": "#include <pybind11/pybind11.h>\n\n#define STRINGIFY(x) #x\n#define MACRO_STRINGIFY(x) STRINGIFY(x)\n\nint add(int i, int j) {\n    return i + j;\n}\n\nnamespace py = pybind11;\n\nPYBIND11_MODULE(example, m) {\n    m.doc() = R\"pbdoc(\n        Pybind11 example plugin\n        -----------------------\n        .. currentmodule:: example\n        .. autosummary::\n           :toctree: _generate\n           add\n           subtract\n    )pbdoc\";\n\n    m.def(\"add\", &add, R\"pbdoc(\n        Add two numbers\n        Some other explanation about the add function.\n    )pbdoc\");\n\n    m.def(\"subtract\", [](int i, int j) { return i - j; }, R\"pbdoc(\n        Subtract two numbers\n        Some other explanation about the subtract function.\n    )pbdoc\");\n\n#ifdef VERSION_INFO\n    m.attr(\"__version__\") = MACRO_STRINGIFY(VERSION_INFO);\n#else\n    m.attr(\"__version__\") = \"dev\";\n#endif\n}\n"
  },
  {
    "path": "tests/projects/python/pybind/example/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"pybind11\")\n\ntarget(\"example\")\n    add_rules(\"python.module\", {soabi = false})\n    add_files(\"src/*.cpp\")\n    add_packages(\"pybind11\")\n    set_languages(\"c++11\")\n"
  },
  {
    "path": "tests/projects/python/pybind/example_with_soabi/src/example.cpp",
    "content": "#include <pybind11/pybind11.h>\n\n#define STRINGIFY(x) #x\n#define MACRO_STRINGIFY(x) STRINGIFY(x)\n\nint add(int i, int j) {\n    return i + j;\n}\n\nnamespace py = pybind11;\n\nPYBIND11_MODULE(example, m) {\n    m.doc() = R\"pbdoc(\n        Pybind11 example plugin\n        -----------------------\n        .. currentmodule:: example\n        .. autosummary::\n           :toctree: _generate\n           add\n           subtract\n    )pbdoc\";\n\n    m.def(\"add\", &add, R\"pbdoc(\n        Add two numbers\n        Some other explanation about the add function.\n    )pbdoc\");\n\n    m.def(\"subtract\", [](int i, int j) { return i - j; }, R\"pbdoc(\n        Subtract two numbers\n        Some other explanation about the subtract function.\n    )pbdoc\");\n\n#ifdef VERSION_INFO\n    m.attr(\"__version__\") = MACRO_STRINGIFY(VERSION_INFO);\n#else\n    m.attr(\"__version__\") = \"dev\";\n#endif\n}\n"
  },
  {
    "path": "tests/projects/python/pybind/example_with_soabi/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"pybind11\")\n\ntarget(\"example\")\n    add_rules(\"python.module\")\n    add_files(\"src/*.cpp\")\n    add_packages(\"pybind11\")\n    set_languages(\"c++11\")\n"
  },
  {
    "path": "tests/projects/qt/console/src/main.cpp",
    "content": "#include <QCoreApplication>\n\nint main(int argc, char *argv[])\n{\n    QCoreApplication a(argc, argv);\n\n    printf(\"hello xmake\\n\");\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.console\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/qt/console_static/src/main.cpp",
    "content": "#include <QCoreApplication>\n\nint main(int argc, char *argv[])\n{\n    QCoreApplication a(argc, argv);\n\n    printf(\"hello xmake\\n\");\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/console_static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.console\")\n    add_files(\"src/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/qt/quickapp/src/main.cpp",
    "content": "#include <QGuiApplication>\n#include <QQmlApplicationEngine>\n\nint main(int argc, char *argv[]) {\n#if QT_VERSION >= 0x50601\n    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\n#endif\n\n    QGuiApplication app(argc, argv);\n\n    QQmlApplicationEngine engine;\n    engine.load(QUrl(QStringLiteral(\"qrc:/main.qml\")));\n    if (engine.rootObjects().isEmpty())\n        return -1;\n\n    return app.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/quickapp/src/main.qml",
    "content": "import QtQuick 2.6\nimport QtQuick.Window 2.2\nimport QtQuick.Controls 2.2\n\nWindow {\n    id: root\n    visible: true\n    width: 640\n    height: 480\n    title: qsTr(\"Hello World\")\n    Button {\n        text: \"Ok\"\n        onClicked: {\n            root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);\n        }\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/qt/quickapp/src/qml.qrc",
    "content": "<RCC> \n    <qresource prefix=\"/\">\n        <file>main.qml</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "tests/projects/qt/quickapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.quickapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n\n\n"
  },
  {
    "path": "tests/projects/qt/quickapp_static/src/main.cpp",
    "content": "#include <QGuiApplication>\n#include <QQmlApplicationEngine>\n\nint main(int argc, char *argv[])\n{\n#if QT_VERSION >= 0x50601\n    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\n#endif\n\n    QGuiApplication app(argc, argv);\n\n    QQmlApplicationEngine engine;\n    engine.load(QUrl(QStringLiteral(\"qrc:/main.qml\")));\n    if (engine.rootObjects().isEmpty())\n        return -1;\n\n    return app.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/quickapp_static/src/main.qml",
    "content": "import QtQuick 2.6\nimport QtQuick.Window 2.2\nimport QtQuick.Controls 2.2\n\nWindow {\n    id: root\n    visible: true\n    width: 640\n    height: 480\n    title: qsTr(\"Hello World\")\n    Button {\n        text: \"Ok\"\n        onClicked: {\n            root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/projects/qt/quickapp_static/src/qml.qrc",
    "content": "<RCC> \n    <qresource prefix=\"/\">\n        <file>main.qml</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "tests/projects/qt/quickapp_static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/qt\")\n\ntarget(\"demo\")\n    add_rules(\"qt.quickapp_static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n    add_frameworks(\"QtQuickControls2\", \"QtQuickTemplates2\")\n    qt_add_static_plugins(\"QtQuick2Plugin\", {linkdirs = \"qml/QtQuick.2\", links = \"qtquick2plugin\"})\n    qt_add_static_plugins(\"QtQuick2WindowPlugin\", {linkdirs = \"qml/QtQuick/Window.2\", links = \"windowplugin\"})\n    qt_add_static_plugins(\"QtQuickControls2Plugin\", {linkdirs = \"qml/QtQuick/Controls.2\", links = \"qtquickcontrols2plugin\"})\n    qt_add_static_plugins(\"QtQuickTemplates2Plugin\", {linkdirs = \"qml/QtQuick/Templates.2\", links = \"qtquicktemplates2plugin\"})\n\n"
  },
  {
    "path": "tests/projects/qt/quickplugin/src/Foo.cpp",
    "content": "#include \"Foo.h\"\n\nFoo::Foo(QObject *parent) : QObject { parent }, m_bar{ 0 } {\n}\n\nint Foo::bar() const noexcept {\n    return m_bar;\n}\n\nvoid Foo::setBar(int bar) noexcept {\n    if (bar == m_bar) return;\n\n    m_bar = bar;\n\n    Q_EMIT barChanged(m_bar);\n}"
  },
  {
    "path": "tests/projects/qt/quickplugin/src/Foo.h",
    "content": "#include <QtCore/QObject>\n#include <QtQml/qqml.h>\n\nclass Foo: public QObject {\n    Q_OBJECT\n    Q_PROPERTY(int bar READ bar WRITE setBar NOTIFY barChanged)\n    QML_NAMED_ELEMENT(Foo)\n\n    public:\n        explicit Foo(QObject *parent = nullptr);\n\n        int bar() const noexcept;\n        void setBar(int bar) noexcept;\n\n    Q_SIGNALS:\n        void barChanged(int bar);\n\n    private:\n        int m_bar;\n};\n\nQML_DECLARE_TYPE(Foo)\n"
  },
  {
    "path": "tests/projects/qt/quickplugin/src/Plugin.cpp",
    "content": "#include \"Plugin.h\"\n\nvoid qml_register_types_My_Plugin();\n\n/////////////////////////////////////\n/////////////////////////////////////\nPlugin::Plugin(QObject *parent) : QQmlEngineExtensionPlugin { parent } {\n    volatile auto registration = &qml_register_types_My_Plugin;\n    Q_UNUSED(registration);\n}\n"
  },
  {
    "path": "tests/projects/qt/quickplugin/src/Plugin.h",
    "content": "#include <QtCore/QObject>\n#include <QtQml/QQmlEngineExtensionPlugin>\n\nclass Plugin: public QQmlEngineExtensionPlugin {\n    Q_OBJECT\n    Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)\n\n  public:\n    explicit Plugin(QObject *parent = nullptr);\n};\n"
  },
  {
    "path": "tests/projects/qt/quickplugin/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.qmlplugin\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    -- add files with Q_OBJECT meta (only for qt.moc)\n    add_files(\"src/*.h\")\n\n    set_values(\"qt.qmlplugin.import_name\", \"My.Plugin\")"
  },
  {
    "path": "tests/projects/qt/shared_library/src/demo.cpp",
    "content": "#include \"demo.h\"\n\n\nQtDemo::QtDemo()\n{\n}\n"
  },
  {
    "path": "tests/projects/qt/shared_library/src/demo.h",
    "content": "#ifndef QT_DEMO_H\n#define QT_DEMO_H\n\n#include \"demo_global.h\"\n\nclass QT_DEMOSHARED_EXPORT QtDemo\n{\n\npublic:\n    QtDemo();\n};\n\n#endif // QT_TEST5_H\n"
  },
  {
    "path": "tests/projects/qt/shared_library/src/demo_global.h",
    "content": "#ifndef QT_DEMO_GLOBAL_H\n#define QT_DEMO_GLOBAL_H\n\n#include <QtCore/qglobal.h>\n\n#if defined(QT_DEMO_LIBRARY)\n#  define QT_DEMOSHARED_EXPORT Q_DECL_EXPORT\n#else\n#  define QT_DEMOSHARED_EXPORT Q_DECL_IMPORT\n#endif\n\n#endif // QT_TEST5_GLOBAL_H\n"
  },
  {
    "path": "tests/projects/qt/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.shared\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_defines(\"QT_DEMO_LIBRARY\")\n    add_frameworks(\"QtGui\")\n"
  },
  {
    "path": "tests/projects/qt/static_library/src/demo.cpp",
    "content": "#include \"demo.h\"\n\nQtDemo::QtDemo()\n{\n}\n"
  },
  {
    "path": "tests/projects/qt/static_library/src/demo.h",
    "content": "#ifndef QT_DEMO_H\n#define QT_DEMO_H\n\nclass QtDemo\n{\n\npublic:\n    QtDemo();\n};\n\n#endif // QT_DEMO_H\n"
  },
  {
    "path": "tests/projects/qt/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"qt_demo\")\n    add_rules(\"qt.static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_frameworks(\"QtGui\")\n"
  },
  {
    "path": "tests/projects/qt/widgetapp/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\nint main(int argc, char *argv[]) {\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.show();\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/widgetapp/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nMainWindow::MainWindow(QWidget *parent) :\n    QMainWindow(parent),\n    ui(new Ui::MainWindow)\n{\n    ui->setupUi(this);\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n"
  },
  {
    "path": "tests/projects/qt/widgetapp/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n \n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "tests/projects/qt/widgetapp/src/mainwindow.ui",
    "content": "<ui version=\"4.0\"> \n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\n  <property name=\"geometry\" >\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\" >\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\n  <widget class=\"QWidget\" name=\"centralWidget\" />\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\n </widget>\n <layoutDefault spacing=\"6\" margin=\"11\" />\n <pixmapfunction></pixmapfunction>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "tests/projects/qt/widgetapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.widgetapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    add_files(\"src/mainwindow.h\")\n\n\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot/main.cpp",
    "content": "#include \"mainwindow.h\"\r\n#include <QApplication>\r\n\r\nint main(int argc, char *argv[])\r\n{\r\n    QApplication a(argc, argv);\r\n    MainWindow w;\r\n    w.show();\r\n\r\n    return a.exec();\r\n}\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\r\n#include <QDebug>\r\n\r\nclass MainWindowPrivate\r\n{\r\n    MainWindow *q_ptr;\r\n    Q_DECLARE_PUBLIC(MainWindow)\r\npublic:\r\n    MainWindowPrivate(){}\r\n    void mainWindow_slot(){qDebug()<<\"mainWindow_slot\";}\r\n};\r\n\r\nMainWindow::MainWindow(QWidget *parent) :\r\n    QMainWindow(parent)\r\n{\r\n    d_ptr = new MainWindowPrivate;\r\n    d_ptr->q_ptr = this;\r\n}\r\n\r\nMainWindow::~MainWindow()\r\n{\r\n\r\n}\r\n\r\n#include \"moc_mainwindow.cpp\"\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\r\n#define MAINWINDOW_H\r\n\r\n#include <QMainWindow>\r\n\r\n#if QT_VERSION >= 0x040400\r\nQT_BEGIN_NAMESPACE\r\n#endif\r\n\r\nclass MainWindowPrivate;\r\n\r\nclass MainWindow : public QMainWindow\r\n{\r\n    Q_OBJECT\r\n\r\npublic:\r\n    explicit MainWindow(QWidget *parent = nullptr);\r\n    ~MainWindow();\r\n\r\nprivate:\r\n    MainWindowPrivate *d_ptr;\r\n    Q_DECLARE_PRIVATE(MainWindow)\r\n    Q_DISABLE_COPY(MainWindow)\r\n\r\n    Q_PRIVATE_SLOT(d_func(), void mainWindow_slot())\r\n};\r\n#if QT_VERSION >= 0x040400\r\nQT_END_NAMESPACE\r\n#endif\r\n#endif // MAINWINDOW_H\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot/mainwindow.ui",
    "content": "<ui version=\"4.0\">\r\n <class>MainWindow</class>\r\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\r\n  <property name=\"geometry\" >\r\n   <rect>\r\n    <x>0</x>\r\n    <y>0</y>\r\n    <width>400</width>\r\n    <height>300</height>\r\n   </rect>\r\n  </property>\r\n  <property name=\"windowTitle\" >\r\n   <string>MainWindow</string>\r\n  </property>\r\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\r\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\r\n  <widget class=\"QWidget\" name=\"centralWidget\" />\r\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\r\n </widget>\r\n <layoutDefault spacing=\"6\" margin=\"11\" />\r\n <pixmapfunction></pixmapfunction>\r\n <resources/>\r\n <connections/>\r\n</ui>\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot/xmake.lua",
    "content": "target(\"test\")\n    add_rules(\"qt.widgetapp\")\n    add_files(\"mainwindow.h\")\n    add_files(\"*.cpp\")\n    add_frameworks(\"QtCore\", \"QtGui\")\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot2/main.cpp",
    "content": "#include \"mainwindow.h\"\r\n#include <QApplication>\r\n\r\nint main(int argc, char *argv[])\r\n{\r\n    QApplication a(argc, argv);\r\n    MainWindow w;\r\n    w.show();\r\n\r\n    return a.exec();\r\n}\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot2/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\r\n#include <QDebug>\r\n\r\nclass MainWindowPrivate:public QObject\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    MainWindow *q_ptr;\r\n    Q_DECLARE_PUBLIC(MainWindow)\r\npublic:\r\n    MainWindowPrivate(){}\r\n    void mainWindow_slot(){qDebug()<<\"mainWindow_slot\";}\r\nprivate:\r\n     Q_PRIVATE_SLOT(q_ptr, void test())\r\n};\r\n\r\nMainWindow::MainWindow(QWidget *parent) :\r\n    QMainWindow(parent)\r\n{\r\n    d_ptr = new MainWindowPrivate;\r\n    d_ptr->q_ptr = this;\r\n}\r\n\r\nMainWindow::~MainWindow()\r\n{\r\n\r\n}\r\n\r\nvoid MainWindow::test()\r\n{\r\n\r\n}\r\n\r\n#include \"moc_mainwindow.cpp\"\r\n#include \"mainwindow.moc\"\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot2/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\r\n#define MAINWINDOW_H\r\n\r\n#include <QMainWindow>\r\n\r\n#if QT_VERSION >= 0x040400\r\nQT_BEGIN_NAMESPACE\r\n#endif\r\n\r\nclass MainWindowPrivate;\r\n\r\nclass MainWindow : public QMainWindow\r\n{\r\n    Q_OBJECT\r\n\r\npublic:\r\n    explicit MainWindow(QWidget *parent = nullptr);\r\n    ~MainWindow();\r\n\r\npublic Q_SLOTS:\r\n    void test();\r\nprivate:\r\n    MainWindowPrivate *d_ptr;\r\n    Q_DECLARE_PRIVATE(MainWindow)\r\n    Q_DISABLE_COPY(MainWindow)\r\n\r\n    Q_PRIVATE_SLOT(d_func(), void mainWindow_slot())\r\n};\r\n#if QT_VERSION >= 0x040400\r\nQT_END_NAMESPACE\r\n#endif\r\n#endif // MAINWINDOW_H\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot2/mainwindow.ui",
    "content": "<ui version=\"4.0\">\r\n <class>MainWindow</class>\r\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\r\n  <property name=\"geometry\" >\r\n   <rect>\r\n    <x>0</x>\r\n    <y>0</y>\r\n    <width>400</width>\r\n    <height>300</height>\r\n   </rect>\r\n  </property>\r\n  <property name=\"windowTitle\" >\r\n   <string>MainWindow</string>\r\n  </property>\r\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\r\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\r\n  <widget class=\"QWidget\" name=\"centralWidget\" />\r\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\r\n </widget>\r\n <layoutDefault spacing=\"6\" margin=\"11\" />\r\n <pixmapfunction></pixmapfunction>\r\n <resources/>\r\n <connections/>\r\n</ui>\r\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_private_slot2/xmake.lua",
    "content": "target(\"test\")\n    add_rules(\"qt.widgetapp\")\n    add_files(\"main.cpp\")\n    add_files(\"mainwindow.cpp\", {rules = \"qt.moc\"})\n    add_files(\"*.h\")\n    add_files(\"*.ui\")\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_static/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\nint main(int argc, char *argv[]) {\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.show();\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_static/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nMainWindow::MainWindow(QWidget *parent) :\n    QMainWindow(parent),\n    ui(new Ui::MainWindow)\n{\n    ui->setupUi(this);\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_static/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n \n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_static/src/mainwindow.ui",
    "content": "<ui version=\"4.0\"> \n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\n  <property name=\"geometry\" >\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\" >\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\n  <widget class=\"QWidget\" name=\"centralWidget\" />\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\n </widget>\n <layoutDefault spacing=\"6\" margin=\"11\" />\n <pixmapfunction></pixmapfunction>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "tests/projects/qt/widgetapp_static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/qt\")\n\ntarget(\"demo\")\n    add_rules(\"qt.widgetapp_static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    add_files(\"src/mainwindow.h\")\n    add_frameworks(\"QtSvg\")\n    qt_add_static_plugins(\"QSvgPlugin\", {linkdirs = \"plugins/imageformats\", links = {\"qsvg\"}})\n"
  },
  {
    "path": "tests/projects/qt/with_private/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\nint main(int argc, char *argv[])\n{\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.show();\n\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/with_private/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n#include <private/qquicktext_p.h>\nMainWindow::MainWindow(QWidget *parent) :\n    QMainWindow(parent),\n    ui(new Ui::MainWindow)\n{\n    ui->setupUi(this);\n    QQuickText *text = new QQuickText();\n    delete text;\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n"
  },
  {
    "path": "tests/projects/qt/with_private/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n \n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "tests/projects/qt/with_private/src/mainwindow.ui",
    "content": "<ui version=\"4.0\"> \n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\n  <property name=\"geometry\" >\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\" >\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\n  <widget class=\"QWidget\" name=\"centralWidget\" />\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\n </widget>\n <layoutDefault spacing=\"6\" margin=\"11\" />\n <pixmapfunction></pixmapfunction>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "tests/projects/qt/with_private/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.widgetapp\")\n    add_frameworks(\"QtCore\", \"QtGui\", \"QtWidgets\", \"QtQuick\", \"QtQuickPrivate\", \"QtQml\", \"QtQmlPrivate\", \"QtCorePrivate\", \"QtGuiPrivate\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    add_files(\"src/mainwindow.h\")\n\n\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/demo_zh_CN.ts",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE TS>\n<TS version=\"2.1\" language=\"zh_CN\">\n<context>\n    <name>MainWindow</name>\n    <message>\n        <location filename=\"mainwindow.ui\" line=\"14\"/>\n        <source>MainWindow</source>\n        <translation>主窗口</translation>\n    </message>\n    <message>\n        <location filename=\"mainwindow.ui\" line=\"27\"/>\n        <source>PushButton</source>\n        <translation>按钮</translation>\n    </message>\n</context>\n</TS>\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/demo_zh_TW.ts",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE TS>\n<TS version=\"2.1\" language=\"zh_TW\">\n<context>\n    <name>MainWindow</name>\n    <message>\n        <location filename=\"mainwindow.ui\" line=\"14\"/>\n        <source>MainWindow</source>\n        <translation>主視窗</translation>\n    </message>\n    <message>\n        <location filename=\"mainwindow.ui\" line=\"27\"/>\n        <source>PushButton</source>\n        <translation>按鈕</translation>\n    </message>\n</context>\n</TS>\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n#include <QLocale>\n#include <QTranslator>\n\nint main(int argc, char *argv[])\n{\n    QApplication a(argc, argv);\n\n    QTranslator translator;\n    const QStringList uiLanguages = QLocale::system().uiLanguages();\n    for (const QString& locale : uiLanguages) {\n        const QString baseName = \"demo_\" + QLocale(locale).name();\n        if (translator.load(baseName + \".qm\")) {\n            a.installTranslator(&translator);\n            break;\n        }\n    }\n    MainWindow w;\n    w.show();\n\n    return a.exec();\n}\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\nMainWindow::MainWindow(QWidget *parent) :\n    QMainWindow(parent),\n    ui(new Ui::MainWindow)\n{\n    ui->setupUi(this);\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n \n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "tests/projects/qt/with_ts/src/mainwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <widget class=\"QPushButton\" name=\"pushButton\">\n    <property name=\"geometry\">\n     <rect>\n      <x>110</x>\n      <y>90</y>\n      <width>75</width>\n      <height>23</height>\n     </rect>\n    </property>\n    <property name=\"text\">\n     <string>PushButton</string>\n    </property>\n   </widget>\n  </widget>\n </widget>\n <layoutdefault spacing=\"6\" margin=\"11\"/>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "tests/projects/qt/with_ts/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"demo\")\n    add_rules(\"qt.widgetapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    add_files(\"src/mainwindow.h\")\n    add_files(\"src/demo_zh_CN.ts\")\n    add_files(\"src/demo_zh_TW.ts\", {\n        prefixdir = \"translations\"\n    })"
  },
  {
    "path": "tests/projects/rust/cargo_deps/src/main.rs",
    "content": "extern crate base64;\n\nuse base64::{encode, decode};\n\nfn main() {\n    let a = b\"hello world\";\n    let b = \"aGVsbG8gd29ybGQ=\";\n\n    assert_eq!(encode(a), b);\n    assert_eq!(a, &decode(b).unwrap()[..]);\n    println!(\"{}\", encode(a));\n}\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"cargo::base64 0.13.0\")\nadd_requires(\"cargo::flate2 1.0.17\", {configs = {features = \"zlib\"}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.rs\")\n    add_packages(\"cargo::base64\", \"cargo::flate2\")\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_cross_build/Cargo.toml",
    "content": "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nspin = \"^0.9\"\n\n[target.'cfg(target_arch = \"aarch64\")'.dependencies]\naarch64-cpu = \"^9.3\"\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_cross_build/src/main.rs",
    "content": "// src/main.rs\n#![no_main]\n#![no_std]\n\nuse core::panic::PanicInfo;\n\n#[panic_handler]\nfn panic(_panic: &PanicInfo<'_>) -> ! {\n    loop {}\n}\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_cross_build/xmake.lua",
    "content": "-- rustup target add aarch64-unknown-none\n-- xmake f -a aarch64-unknown-none\n\nset_arch(\"aarch64-unknown-none\")\nadd_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"cargo::test\", {configs = {\n    std = false,\n    main = false,\n    cargo_toml = path.join(os.projectdir(), \"Cargo.toml\")}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.rs\")\n    add_packages(\"cargo::test\")\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_with_toml/Cargo.toml",
    "content": "[package]\nname = \"test\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nbase64 = \"0.13.0\"\nflate2 = {version = \"1.0.17\", features = [\"zlib\"]}\n\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_with_toml/src/main.rs",
    "content": "extern crate base64;\n\nuse base64::{encode, decode};\n\nfn main() {\n    let a = b\"hello world\";\n    let b = \"aGVsbG8gd29ybGQ=\";\n\n    assert_eq!(encode(a), b);\n    assert_eq!(a, &decode(b).unwrap()[..]);\n    println!(\"{}\", encode(a));\n}\n"
  },
  {
    "path": "tests/projects/rust/cargo_deps_with_toml/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"cargo::test\", {configs = {cargo_toml = path.join(os.projectdir(), \"Cargo.toml\")}})\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.rs\")\n    add_packages(\"cargo::test\")\n"
  },
  {
    "path": "tests/projects/rust/console/src/main.rs",
    "content": "fn main() {\n    println!(\"hello xmake!\");\n}\n"
  },
  {
    "path": "tests/projects/rust/console/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() ~= \"arm64\" then\n        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/rust/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/main.rs\")\n\n"
  },
  {
    "path": "tests/projects/rust/cxx_call_rust_library/src/bridge.rsx",
    "content": "#[cxx::bridge]\nmod foo {\n    extern \"Rust\" {\n        fn add(a: i32, b: i32) -> i32;\n    }\n}\n"
  },
  {
    "path": "tests/projects/rust/cxx_call_rust_library/src/foo.rs",
    "content": "#[cxx::bridge]\nmod foo {\n    extern \"Rust\" {\n        fn add(a: i32, b: i32) -> i32;\n    }\n}\n\npub fn add(a: i32, b: i32) -> i32 {\n    return a + b;\n}\n\n\n"
  },
  {
    "path": "tests/projects/rust/cxx_call_rust_library/src/main.cc",
    "content": "#include <stdio.h>\n#include \"bridge.rs.h\"\n\nint main(int argc, char** argv) {\n    printf(\"add(1, 2) == %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/rust/cxx_call_rust_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"cargo::cxx 1.0\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.rs\")\n    set_values(\"rust.cratetype\", \"staticlib\")\n    add_packages(\"cargo::cxx\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"rust.cxxbridge\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cc\")\n    add_files(\"src/bridge.rsx\")\n"
  },
  {
    "path": "tests/projects/rust/rust_call_cxx_library/src/foo.cc",
    "content": "extern \"C\" int add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/rust/rust_call_cxx_library/src/main.rs",
    "content": "extern \"C\" {\n\tfn add(a: i32, b: i32) -> i32;\n}\n\nfn main() {\n    unsafe {\n\t    println!(\"add(1, 2) = {}\", add(1, 2));\n    }\n}\n"
  },
  {
    "path": "tests/projects/rust/rust_call_cxx_library/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() ~= \"arm64\" then\n        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/rust/rust_call_cxx_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cc\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.rs\")\n\n\n"
  },
  {
    "path": "tests/projects/rust/shared_library/src/foo.rs",
    "content": "pub fn add(a: i32, b: i32) -> i32 {\n    return a + b;\n}\n\n"
  },
  {
    "path": "tests/projects/rust/shared_library/src/main.rs",
    "content": "extern crate foo;\n\nfn main() {\n    println!(\"hello xmake!\");\n    println!(\"add: {}\", foo::add(1, 1));\n}\n"
  },
  {
    "path": "tests/projects/rust/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.rs\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.rs\")\n\n\n"
  },
  {
    "path": "tests/projects/rust/static_library/src/foo.rs",
    "content": "pub fn add(a: i32, b: i32) -> i32 {\n    return a + b;\n}\n\n"
  },
  {
    "path": "tests/projects/rust/static_library/src/main.rs",
    "content": "extern crate foo;\nfn main() {\n    println!(\"hello xmake!\");\n    println!(\"add: {}\", foo::add(1, 1));\n}\n"
  },
  {
    "path": "tests/projects/rust/static_library/test.lua",
    "content": "function main(t)\n    if is_host(\"macosx\") and os.arch() ~= \"arm64\" then\n        t:build()\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/rust/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.rs\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.rs\")\n\n\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/include/fibonacci/fibonacci.h",
    "content": "#ifndef FIBONACCI_FIBONACCI_H\n#define FIBONACCI_FIBONACCI_H\n\nextern \"C\" int fibonacci_cpp(int x);\n\n#endif // FIBONACCI_FIBONACCI_H\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/include/fibonacci/module.modulemap",
    "content": "module Fibonacci {\n  header \"fibonacci.h\"\n}\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/lib/fibonacci.cpp",
    "content": "#include <fibonacci/fibonacci.h>\n#include <fibonacci-Swift.h>\n#include <iostream>\n\nextern \"C\" int fibonacci_cpp(int x) {\n    std::cout << \"x [cpp]: \" << x << std::endl;\n    if (x <= 1) return 1;\n    return SwiftFibonacci::fibonacciSwift(x - 1) + SwiftFibonacci::fibonacciSwift(x - 2);\n}\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/lib/fibonacci.swift",
    "content": "public func fibonacciSwift(_ x: CInt) -> CInt {\n    print(\"x [swift]: \\(x)\")\n    if x <= 1 {\n        return 1\n    }\n    return fibonacciSwift(x - 1) + fibonacciSwift(x - 2)\n}\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/src/fibonacci.cpp",
    "content": "#include <fibonacci-Swift.h>\n#include <iostream>\n\nint main(int argc, char ** argv) {\n    std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/src/fibonacci.swift",
    "content": "import Fibonacci\n\nprint(fibonacci_cpp(5))\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/swift/bidirectional_cxx_interop_lib/xmake.lua",
    "content": "target(\"fibonacci\")\n    set_kind(\"$(kind)\")\n    set_languages(\"cxx20\")\n    add_files(\"lib/**.swift\", {public = true})\n    add_files(\"lib/**.cpp\")\n    set_values(\"swift.modulename\", \"SwiftFibonacci\")\n    set_values(\"swift.interop\", \"cxx\")\n    -- for automatic clang modulemap\n    add_includedirs(\"include/fibonacci\", {public = true})\n    add_includedirs(\"include\")\n    add_headerfiles(\"include/**.h\")\n\ntarget(\"cxx_interop_lib\")\n    set_kind(\"binary\")\n    set_languages(\"cxx20\")\n    add_files(\"src/**.cpp\")\n    add_deps(\"fibonacci\")\n\ntarget(\"swift_interop_lib\")\n    set_kind(\"binary\")\n    add_files(\"src/**.swift\")\n    add_deps(\"fibonacci\")\n    set_values(\"swift.interop\", \"cxx\")\n"
  },
  {
    "path": "tests/projects/swift/console/src/main.swift",
    "content": "import Foundation\n\nprint(\"hello world!\")\n"
  },
  {
    "path": "tests/projects/swift/console/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/swift/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.swift\")\n\n"
  },
  {
    "path": "tests/projects/swift/cross_modules/src/A.swift",
    "content": "\nfunc test() {\n    print(\"xxxxx\")\n}\n"
  },
  {
    "path": "tests/projects/swift/cross_modules/src/main.swift",
    "content": "\ntest()\n"
  },
  {
    "path": "tests/projects/swift/cross_modules/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.swift\")\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop/lib/fibonacci/fibonacci.swift",
    "content": "public func fibonacciSwift(_ x: CInt) -> CInt {\n    print(\"x [swift]: \\(x)\")\n    if x <= 1 {\n        return 1\n    }\n    return fibonacciSwift(x - 1) + fibonacciSwift(x - 2)\n}\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop/src/fibonacci.cpp",
    "content": "#include <fibonacci-Swift.h>\n#include <iostream>\n\nint main(int argc, char ** argv) {\n    std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop/xmake.lua",
    "content": "target(\"cxx_interop\")\n    set_kind(\"binary\")\n    set_languages(\"cxx20\")\n    add_files(\"lib/**.swift\", {public = true})\n    add_files(\"src/**.cpp\")\n    set_values(\"swift.modulename\", \"SwiftFibonacci\")\n    set_values(\"swift.interop\", \"cxx\")\n    set_values(\"swift.interop.headername\", \"fibonacci-Swift.h\")\n    set_values(\"swift.interop.cxxmain\", true)\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop_lib/lib/fibonacci/fibonacci.swift",
    "content": "public func fibonacciSwift(_ x: CInt) -> CInt {\n    print(\"x [swift]: \\(x)\")\n    if x <= 1 {\n        return 1\n    }\n    return fibonacciSwift(x - 1) + fibonacciSwift(x - 2)\n}\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop_lib/src/fibonacci.cpp",
    "content": "#include <fibonacci-Swift.h>\n#include <iostream>\n\nint main(int argc, char ** argv) {\n    std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop_lib/test.lua",
    "content": "function main(t)\n    if os.host() == \"macosx\" then\n        t:build({iphoneos = true})\n    else\n        return t:skip(\"wrong host platform\")\n    end\nend\n"
  },
  {
    "path": "tests/projects/swift/cxx_interop_lib/xmake.lua",
    "content": "target(\"fibonacci\")\n    set_kind(\"$(kind)\")\n    set_languages(\"cxx20\")\n    add_files(\"lib/**.swift\", {public = true})\n    set_values(\"swift.modulename\", \"SwiftFibonacci\")\n    set_values(\"swift.interop\", \"cxx\")\n\ntarget(\"cxx_interop_lib\")\n    set_kind(\"binary\")\n    set_languages(\"cxx20\")\n    add_files(\"src/**.cpp\")\n    add_deps(\"fibonacci\")\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  test8\n//\n//  Created by ruki on 2020/4/10.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    // MARK: UISceneSession Lifecycle\n\n    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {\n        // Called when a new scene session is being created.\n        // Use this method to select a configuration to create the new scene with.\n        return UISceneConfiguration(name: \"Default Configuration\", sessionRole: connectingSceneSession.role)\n    }\n\n    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {\n        // Called when the user discards a scene session.\n        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n    }\n\n\n}\n\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/swift/iosapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/swift/iosapp/src/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/SceneDelegate.swift",
    "content": "//\n//  SceneDelegate.swift\n//  test8\n//\n//  Created by ruki on 2020/4/10.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\nimport UIKit\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n        guard let _ = (scene as? UIWindowScene) else { return }\n    }\n\n    func sceneDidDisconnect(_ scene: UIScene) {\n        // Called as the scene is being released by the system.\n        // This occurs shortly after the scene enters the background, or when its session is discarded.\n        // Release any resources associated with this scene that can be re-created the next time the scene connects.\n        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n    }\n\n    func sceneDidBecomeActive(_ scene: UIScene) {\n        // Called when the scene has moved from an inactive state to an active state.\n        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n    }\n\n    func sceneWillResignActive(_ scene: UIScene) {\n        // Called when the scene will move from an active state to an inactive state.\n        // This may occur due to temporary interruptions (ex. an incoming phone call).\n    }\n\n    func sceneWillEnterForeground(_ scene: UIScene) {\n        // Called as the scene transitions from the background to the foreground.\n        // Use this method to undo the changes made on entering the background.\n    }\n\n    func sceneDidEnterBackground(_ scene: UIScene) {\n        // Called as the scene transitions from the foreground to the background.\n        // Use this method to save data, release shared resources, and store enough scene-specific state information\n        // to restore the scene back to its current state.\n    }\n\n\n}\n\n"
  },
  {
    "path": "tests/projects/swift/iosapp/src/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  test8\n//\n//  Created by ruki on 2020/4/10.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\nimport UIKit\n\nclass ViewController: UIViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Do any additional setup after loading the view.\n    }\n\n\n}\n\n"
  },
  {
    "path": "tests/projects/swift/iosapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nset_plat(\"iphoneos\")\nset_arch(\"arm64\")\n\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.swift\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n"
  },
  {
    "path": "tests/projects/swift/macapp/src/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  test9\n//\n//  Created by ruki on 2020/4/10.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\nimport Cocoa\n\n@NSApplicationMain\nclass AppDelegate: NSObject, NSApplicationDelegate {\n\n\n\n    func applicationDidFinishLaunching(_ aNotification: Notification) {\n        // Insert code here to initialize your application\n    }\n\n    func applicationWillTerminate(_ aNotification: Notification) {\n        // Insert code here to tear down your application\n    }\n\n\n}\n\n"
  },
  {
    "path": "tests/projects/swift/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/swift/macapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "tests/projects/swift/macapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test9\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test9\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test9\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test9\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test9\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test9 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"target\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "tests/projects/swift/macapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/swift/macapp/src/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  test9\n//\n//  Created by ruki on 2020/4/10.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\nimport Cocoa\n\nclass ViewController: NSViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        // Do any additional setup after loading the view.\n    }\n\n    override var representedObject: Any? {\n        didSet {\n        // Update the view, if already loaded.\n        }\n    }\n\n\n}\n\n"
  },
  {
    "path": "tests/projects/swift/macapp/src/test.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.files.user-selected.read-only</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "tests/projects/swift/macapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.swift\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n"
  },
  {
    "path": "tests/projects/swift/modulemap/src/hello.cpp",
    "content": "#include <stdio.h>\n#include \"hello.h\"\n\nvoid say1(char const* s) {\n    printf(\"%s\\n\", s);\n}\n\n\n"
  },
  {
    "path": "tests/projects/swift/modulemap/src/hello.h",
    "content": "#include <stdio.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n    void say1(char const* s);\n#ifdef __cplusplus\n}\n#endif\nstatic inline void say2(char const* s) {\n    printf(\"%s\\n\", s);\n}\n\n\n"
  },
  {
    "path": "tests/projects/swift/modulemap/src/main.swift",
    "content": "import Foundation\nimport hello\n\nhello.say1(\"hello1\")\nhello.say2(\"hello2\")\n"
  },
  {
    "path": "tests/projects/swift/modulemap/src/module.modulemap",
    "content": "module hello {\n    header \"hello.h\"\n    export *\n}\n"
  },
  {
    "path": "tests/projects/swift/modulemap/xmake.lua",
    "content": "target(\"modulemap\")\n    set_kind(\"binary\")\n    add_files(\"src/*.swift\", \"src/*.cpp\")\n    add_scflags(\"-Xcc -fmodules\", \"-Xcc -fmodule-map-file=src/module.modulemap\", {force = true})\n"
  },
  {
    "path": "tests/projects/swig/auto_include/src/example.cpp",
    "content": "double My_variable = 3.0;\n\n/* Compute factorial of n */\nint fact(int n) {\n    if (n <= 1)\n        return 1;\n    else\n        return n*fact(n-1);\n}\n\n/* Compute n mod m */\nint my_mod(int n, int m) {\n    return(n % m);\n}\n"
  },
  {
    "path": "tests/projects/swig/auto_include/src/example.i",
    "content": "%module example\n\n%{\n/* Put headers and other declarations here */\n#include \"nlohmann/json.hpp\"\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n%}\n\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n"
  },
  {
    "path": "tests/projects/swig/auto_include/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"python 3.x\")\nadd_requires(\"nlohmann_json\")\n\ntarget(\"example\")\n    add_rules(\"swig.cpp\", {moduletype = \"python\"})\n    add_files(\"src/example.i\", {scriptdir = \"share\"})\n    add_files(\"src/example.cpp\")\n    add_packages(\"python\")\n    add_packages(\"nlohmann_json\")"
  },
  {
    "path": "tests/projects/swig/java_c/src/example.c",
    "content": "int fact(int n) {\n    return n;\n}\n\nint fact2(int n) {\n    return n;\n}\n\n"
  },
  {
    "path": "tests/projects/swig/java_c/src/example.i",
    "content": "%module example\n%{\nextern int fact(int n);\n%}\nextern int fact(int n);\n\n%include \"example2.i\"\n"
  },
  {
    "path": "tests/projects/swig/java_c/src/example2.i",
    "content": "%inline %{\n#include \"test.h\"\n%}\n%include \"test.h\"\n"
  },
  {
    "path": "tests/projects/swig/java_c/src/test.h",
    "content": "#pragma once\n\nint fact2(int n);\n"
  },
  {
    "path": "tests/projects/swig/java_c/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\n-- make sure you config to an enviroment with jni.h\n-- for example: xmake f -c -p android\n\ntarget(\"example\")\n    set_kind('shared')\n    -- set moduletype to java\n    add_rules(\"swig.c\", {moduletype = \"java\"})\n    -- test jar build\n    -- add_rules(\"swig.c\", {moduletype = \"java\" , buildjar = true})\n    -- use swigflags to provider package name and output path of java files\n    add_files(\"src/example.i\", {swigflags = {\n        \"-package\",\n        \"com.example\",\n        \"-outdir\",\n        \"build/java/com/example/\"\n    }})\n    add_files(\"src/example.c\")\n    add_includedirs(\"src\")\n    before_build(function()\n        -- ensure output path exists before running swig\n        os.mkdir(\"build/java/com/example/\")\n    end)\n"
  },
  {
    "path": "tests/projects/swig/lua_c/src/example.c",
    "content": "int fact(int n) {\n    return n;\n}\n\n"
  },
  {
    "path": "tests/projects/swig/lua_c/src/example.i",
    "content": "%module example\n%{\nextern int fact(int n);\n%}\nextern int fact(int n);\n"
  },
  {
    "path": "tests/projects/swig/lua_c/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"lua\")\n\ntarget(\"example\")\n    add_rules(\"swig.c\", {moduletype = \"lua\"})\n    add_files(\"src/example.i\", {swigflags = \"-no-old-metatable-bindings\"})\n    add_files(\"src/example.c\")\n    add_packages(\"lua\")\n"
  },
  {
    "path": "tests/projects/swig/python_c/src/example.c",
    "content": "double My_variable = 3.0;\n\n/* Compute factorial of n */\nint fact(int n) {\n    if (n <= 1)\n        return 1;\n    else\n        return n*fact(n-1);\n}\n\n/* Compute n mod m */\nint my_mod(int n, int m) {\n    return(n % m);\n}\n"
  },
  {
    "path": "tests/projects/swig/python_c/src/example.i",
    "content": "%module example\n%{\n/* Put headers and other declarations here */\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n%}\n\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n"
  },
  {
    "path": "tests/projects/swig/python_c/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"python 3.x\")\n\ntarget(\"example\")\n    add_rules(\"swig.c\", {moduletype = \"python\"})\n    add_files(\"src/example.i\", {scriptdir = \"share\"})\n    add_files(\"src/example.c\")\n    add_packages(\"python\")\n"
  },
  {
    "path": "tests/projects/swig/python_c_with_soabi/src/example.c",
    "content": "double My_variable = 3.0;\n\n/* Compute factorial of n */\nint fact(int n) {\n    if (n <= 1)\n        return 1;\n    else\n        return n*fact(n-1);\n}\n\n/* Compute n mod m */\nint my_mod(int n, int m) {\n    return(n % m);\n}\n"
  },
  {
    "path": "tests/projects/swig/python_c_with_soabi/src/example.i",
    "content": "%module example\n%{\n/* Put headers and other declarations here */\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n%}\n\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n"
  },
  {
    "path": "tests/projects/swig/python_c_with_soabi/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"python 3.x\")\n\ntarget(\"example\")\n    add_rules(\"swig.c\", {moduletype = \"python\", soabi = true})\n    add_files(\"src/example.i\", {scriptdir = \"share\"})\n    add_files(\"src/example.c\")\n    add_packages(\"python\")\n"
  },
  {
    "path": "tests/projects/swig/python_cpp/src/example.cpp",
    "content": "double My_variable = 3.0;\n\n/* Compute factorial of n */\nint fact(int n) {\n    if (n <= 1)\n        return 1;\n    else\n        return n*fact(n-1);\n}\n\n/* Compute n mod m */\nint my_mod(int n, int m) {\n    return(n % m);\n}\n"
  },
  {
    "path": "tests/projects/swig/python_cpp/src/example.i",
    "content": "%module example\n%{\n/* Put headers and other declarations here */\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n%}\n\nextern double My_variable;\nextern int    fact(int);\nextern int    my_mod(int n, int m);\n"
  },
  {
    "path": "tests/projects/swig/python_cpp/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\nadd_requires(\"python 3.x\")\n\ntarget(\"example\")\n    add_rules(\"swig.cpp\", {moduletype = \"python\"})\n    add_files(\"src/example.i\", {scriptdir = \"share\"})\n    add_files(\"src/example.cpp\")\n    add_packages(\"python\")\n"
  },
  {
    "path": "tests/projects/vala/gtk+3/src/main.vala",
    "content": "using Gtk;\n\nint main (string[] args) {\n    Gtk.init (ref args);\n\n    var window = new Window ();\n    window.title = \"First GTK+ Program\";\n    window.border_width = 10;\n    window.window_position = WindowPosition.CENTER;\n    window.set_default_size (350, 70);\n    window.destroy.connect (Gtk.main_quit);\n\n    var button = new Button.with_label (\"Click me!\");\n    button.clicked.connect (() => {\n        button.label = \"Thank you\";\n    });\n\n    window.add (button);\n    window.show_all ();\n\n    Gtk.main ();\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/vala/gtk+3/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"gtk+3\", \"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"vala\")\n    add_files(\"src/*.vala\")\n    add_packages(\"gtk+3\", \"glib\")\n    add_values(\"vala.packages\", \"gtk+-3.0\")\n"
  },
  {
    "path": "tests/projects/vala/includec/src/main.vala",
    "content": "extern void printer_from_c();\n\nint main (string[] args) {\n    printer_from_c();\n    printer_from_other_file();\n\n    return 0;\n}\n\n"
  },
  {
    "path": "tests/projects/vala/includec/src/printer.c",
    "content": "#include <stdio.h>\n\nvoid printer_from_c() {\n    printf(\"Calling from C\");\n}\n\n"
  },
  {
    "path": "tests/projects/vala/includec/src/printer.vala",
    "content": "void printer_from_other_file() {\n    stdout.printf(\"Calling from other file\");\n}\n"
  },
  {
    "path": "tests/projects/vala/includec/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"vala\")\n    add_files(\"src/*.vala\")\n    add_files(\"src/*.c\")\n    add_packages(\"glib\")\n"
  },
  {
    "path": "tests/projects/vala/lua/src/main.vala",
    "content": "using Lua;\n\nstatic int my_func (LuaVM vm) {\n    stdout.printf (\"Vala Code From Lua Code! (%f)\\n\", vm.to_number (1));\n    return 1;\n}\n\nstatic int main (string[] args) {\n\n    string code = \"\"\"\n            print \"Lua Code From Vala Code!\"\n            my_func(33)\n        \"\"\";\n\n    var vm = new LuaVM ();\n    vm.open_libs ();\n    vm.register (\"my_func\", my_func);\n    vm.do_string (code);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/vala/lua/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"lua\", \"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"vala\")\n    add_files(\"src/*.vala\")\n    add_packages(\"lua\", \"glib\")\n    add_values(\"vala.packages\", \"lua\")\n"
  },
  {
    "path": "tests/projects/vala/sharedlib/src/main.vala",
    "content": "using MyMath;\n\npublic void main() {\n    stdout.printf(\"\\n\\t2 + 3 is %d\", sum(2, 3));\n    stdout.printf(\"\\n\\t8 squared is %d\\n\", square(8));\n}\n"
  },
  {
    "path": "tests/projects/vala/sharedlib/src/mymath.vala",
    "content": "namespace MyMath {\n    public int sum(int a, int b) {\n        return(a + b);\n    }\n\n    public int square(int a) {\n        return(a * a);\n    }\n}\n"
  },
  {
    "path": "tests/projects/vala/sharedlib/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"glib\")\n\ntarget(\"mymath\")\n    set_kind(\"shared\")\n    add_rules(\"vala\")\n    add_files(\"src/mymath.vala\")\n    add_values(\"vala.header\", \"mymath.h\")\n    add_values(\"vala.vapi\", \"mymath-1.0.vapi\")\n    add_packages(\"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"mymath\")\n    add_rules(\"vala\")\n    add_files(\"src/main.vala\")\n    add_packages(\"glib\")\n"
  },
  {
    "path": "tests/projects/vala/sqlite3/src/main.vala",
    "content": "/**\n * Using SQLite in Vala Sample Code\n * Port of an example found on the SQLite site.\n * http://www.sqlite.org/quickstart.html\n */\n\nusing GLib;\nusing Sqlite;\n\npublic class SqliteSample : GLib.Object {\n\n    public static int callback (int n_columns, string[] values,\n                                string[] column_names)\n    {\n        for (int i = 0; i < n_columns; i++) {\n            stdout.printf (\"%s = %s\\n\", column_names[i], values[i]);\n        }\n        stdout.printf (\"\\n\");\n\n        return 0;\n    }\n\n    public static int main (string[] args) {\n        Database db;\n        int rc;\n\n        if (args.length != 3) {\n            stderr.printf (\"Usage: %s DATABASE SQL-STATEMENT\\n\", args[0]);\n            return 1;\n        }\n\n        if (!FileUtils.test (args[1], FileTest.IS_REGULAR)) {\n            stderr.printf (\"Database %s does not exist or is directory\\n\", args[1]);\n            return 1;\n        }\n\n        rc = Database.open (args[1], out db);\n\n        if (rc != Sqlite.OK) {\n            stderr.printf (\"Can't open database: %d, %s\\n\", rc, db.errmsg ());\n            return 1;\n        }\n\n        rc = db.exec (args[2], callback, null);\n        /* maybe it is better to use closures, so you can access local variables, eg: */\n        /*rc = db.exec(args[2], (n_columns, values, column_names) => {\n            for (int i = 0; i < n_columns; i++) {\n                stdout.printf (\"%s = %s\\n\", column_names[i], values[i]);\n            }\n            stdout.printf (\"\\n\");\n\n            return 0;\n            }, null);\n        */\n\n        if (rc != Sqlite.OK) { \n            stderr.printf (\"SQL error: %d, %s\\n\", rc, db.errmsg ());\n            return 1;\n        }\n\n        return 0;\n    }\n}\n"
  },
  {
    "path": "tests/projects/vala/sqlite3/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"sqlite3\", \"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_rules(\"vala\")\n    add_files(\"src/*.vala\")\n    add_packages(\"sqlite3\", \"glib\")\n    add_values(\"vala.packages\", \"sqlite3\")\n"
  },
  {
    "path": "tests/projects/vala/staticlib/src/main.vala",
    "content": "using MyMath;\n\npublic void main() {\n    stdout.printf(\"\\n\\t2 + 3 is %d\", sum(2, 3));\n    stdout.printf(\"\\n\\t8 squared is %d\\n\", square(8));\n}\n"
  },
  {
    "path": "tests/projects/vala/staticlib/src/mymath.vala",
    "content": "namespace MyMath {\n    public int sum(int a, int b) {\n        return(a + b);\n    }\n\n    public int square(int a) {\n        return(a * a);\n    }\n}\n"
  },
  {
    "path": "tests/projects/vala/staticlib/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"glib\")\n\ntarget(\"mymath\")\n    set_kind(\"static\")\n    add_rules(\"vala\")\n    add_files(\"src/mymath.vala\")\n    add_values(\"vala.header\", \"mymath.h\")\n    add_values(\"vala.vapi\", \"mymath-1.0.vapi\")\n    add_packages(\"glib\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"mymath\")\n    add_rules(\"vala\")\n    add_files(\"src/main.vala\")\n    add_packages(\"glib\")\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    nonpnp.c\r\n\r\nAbstract:\r\n\r\n    Purpose of this driver is to demonstrate how to write a legacy (NON WDM)\r\n    driver using framework, show how to handle 4 different ioctls -\r\n    METHOD_NEITHER - in particular and also show how to read & write to file\r\n    from KernelMode using Zw functions.\r\n\r\n    For a non-framework version of sample on how to handle IOCTLs in driver,\r\n    study src\\general\\IOCTL in the DDK.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode only.\r\n\r\n--*/\r\n\r\n#include \"nonpnp.h\"\r\n\r\n//\r\n// The trace message header file must be included in a source file\r\n// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS\r\n// macro. During the compilation, WPP scans the source files for\r\n// TraceEvents() calls and builds a .tmh file which stores a unique\r\n// data GUID for each message, the text resource string for each message,\r\n// and the data types of the variables passed in for each message.\r\n// This file is automatically generated and used during post-processing.\r\n//\r\n#include \"nonpnp.tmh\"\r\n\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text( INIT, DriverEntry )\r\n#pragma alloc_text( PAGE, NonPnpDeviceAdd)\r\n#pragma alloc_text( PAGE, NonPnpEvtDriverContextCleanup)\r\n#pragma alloc_text( PAGE, NonPnpEvtDriverUnload)\r\n#pragma alloc_text( PAGE, NonPnpEvtDeviceIoInCallerContext)\r\n#pragma alloc_text( PAGE, NonPnpEvtDeviceFileCreate)\r\n#pragma alloc_text( PAGE, NonPnpEvtFileClose)\r\n#pragma alloc_text( PAGE, FileEvtIoRead)\r\n#pragma alloc_text( PAGE, FileEvtIoWrite)\r\n#pragma alloc_text( PAGE, FileEvtIoDeviceControl)\r\n#endif // ALLOC_PRAGMA\r\n\r\n\r\nNTSTATUS\r\nDriverEntry(\r\n    IN OUT PDRIVER_OBJECT   DriverObject,\r\n    IN PUNICODE_STRING      RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n    This routine is called by the Operating System to initialize the driver.\r\n\r\n    It creates the device object, fills in the dispatch entry points and\r\n    completes the initialization.\r\n\r\nArguments:\r\n    DriverObject - a pointer to the object that represents this device\r\n    driver.\r\n\r\n    RegistryPath - a pointer to our Services key in the registry.\r\n\r\nReturn Value:\r\n    STATUS_SUCCESS if initialized; an error otherwise.\r\n\r\n--*/\r\n{\r\n    NTSTATUS                       status;\r\n    WDF_DRIVER_CONFIG              config;\r\n    WDFDRIVER                      hDriver;\r\n    PWDFDEVICE_INIT                pInit = NULL;\r\n    WDF_OBJECT_ATTRIBUTES          attributes;\r\n\r\n    KdPrint((\"Driver Frameworks NONPNP Legacy Driver Example\\n\"));\r\n\r\n\r\n    WDF_DRIVER_CONFIG_INIT(\r\n        &config,\r\n        WDF_NO_EVENT_CALLBACK // This is a non-pnp driver.\r\n        );\r\n\r\n    //\r\n    // Tell the framework that this is non-pnp driver so that it doesn't\r\n    // set the default AddDevice routine.\r\n    //\r\n    config.DriverInitFlags |= WdfDriverInitNonPnpDriver;\r\n\r\n    //\r\n    // NonPnp driver must explicitly register an unload routine for\r\n    // the driver to be unloaded.\r\n    //\r\n    config.EvtDriverUnload = NonPnpEvtDriverUnload;\r\n\r\n    //\r\n    // Register a cleanup callback so that we can call WPP_CLEANUP when\r\n    // the framework driver object is deleted during driver unload.\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n    attributes.EvtCleanupCallback = NonPnpEvtDriverContextCleanup;\r\n\r\n    //\r\n    // Create a framework driver object to represent our driver.\r\n    //\r\n    status = WdfDriverCreate(DriverObject,\r\n                            RegistryPath,\r\n                            &attributes,\r\n                            &config,\r\n                            &hDriver);\r\n    if (!NT_SUCCESS(status)) {\r\n        KdPrint ((\"NonPnp: WdfDriverCreate failed with status 0x%x\\n\", status));\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Since we are calling WPP_CLEANUP in the DriverContextCleanup\r\n    // callback we should initialize WPP Tracing after WDFDRIVER\r\n    // object is created to ensure that we cleanup WPP properly\r\n    // if we return failure status from DriverEntry. This\r\n    // eliminates the need to call WPP_CLEANUP in every path\r\n    // of DriverEntry.\r\n    //\r\n    WPP_INIT_TRACING( DriverObject, RegistryPath );\r\n\r\n    //\r\n    // On Win2K system,  you will experience some delay in getting trace events\r\n    // due to the way the ETW is activated to accept trace messages.\r\n    //\r\n    KdPrint((\"NonPnp: DriverEntry: tracing enabled\\n\"));\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,\r\n                   \"Driver Frameworks NONPNP Legacy Driver Example\");\r\n\r\n    //\r\n    //\r\n    // In order to create a control device, we first need to allocate a\r\n    // WDFDEVICE_INIT structure and set all properties.\r\n    //\r\n    pInit = WdfControlDeviceInitAllocate(\r\n                            hDriver,\r\n                            &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R\r\n                            );\r\n\r\n    if (pInit == NULL) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Call NonPnpDeviceAdd to create a deviceobject to represent our\r\n    // software device.\r\n    //\r\n    status = NonPnpDeviceAdd(hDriver, pInit);\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nNonPnpDeviceAdd(\r\n    IN WDFDRIVER Driver,\r\n    IN PWDFDEVICE_INIT DeviceInit\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Called by the DriverEntry to create a control-device. This call is\r\n    responsible for freeing the memory for DeviceInit.\r\n\r\nArguments:\r\n\r\n    DriverObject - a pointer to the object that represents this device\r\n    driver.\r\n\r\n    DeviceInit - Pointer to a driver-allocated WDFDEVICE_INIT structure.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if initialized; an error otherwise.\r\n\r\n--*/\r\n{\r\n    NTSTATUS                       status;\r\n    WDF_OBJECT_ATTRIBUTES           attributes;\r\n    WDF_IO_QUEUE_CONFIG      ioQueueConfig;\r\n    WDF_FILEOBJECT_CONFIG fileConfig;\r\n    WDFQUEUE                            queue;\r\n    WDFDEVICE   controlDevice;\r\n    DECLARE_CONST_UNICODE_STRING(ntDeviceName, NTDEVICE_NAME_STRING) ;\r\n    DECLARE_CONST_UNICODE_STRING(symbolicLinkName, SYMBOLIC_NAME_STRING) ;\r\n\r\n    UNREFERENCED_PARAMETER( Driver );\r\n\r\n    PAGED_CODE();\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,\r\n                   \"NonPnpDeviceAdd DeviceInit %p\\n\", DeviceInit);\r\n    //\r\n    // Set exclusive to TRUE so that no more than one app can talk to the\r\n    // control device at any time.\r\n    //\r\n    WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r\n\r\n    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);\r\n\r\n\r\n    status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, \"WdfDeviceInitAssignName failed %!STATUS!\", status);\r\n        goto End;\r\n    }\r\n\r\n    WdfControlDeviceInitSetShutdownNotification(DeviceInit,\r\n                                                NonPnpShutdown,\r\n                                                WdfDeviceShutdown);\r\n\r\n    //\r\n    // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the\r\n    // framework whether you are interested in handling Create, Close and\r\n    // Cleanup requests that gets generated when an application or another\r\n    // kernel component opens an handle to the device. If you don't register\r\n    // the framework default behaviour would be to complete these requests\r\n    // with STATUS_SUCCESS. A driver might be interested in registering these\r\n    // events if it wants to do security validation and also wants to maintain\r\n    // per handle (fileobject) context.\r\n    //\r\n\r\n    WDF_FILEOBJECT_CONFIG_INIT(\r\n                        &fileConfig,\r\n                        NonPnpEvtDeviceFileCreate,\r\n                        NonPnpEvtFileClose,\r\n                        WDF_NO_EVENT_CALLBACK // not interested in Cleanup\r\n                        );\r\n\r\n    WdfDeviceInitSetFileObjectConfig(DeviceInit,\r\n                                       &fileConfig,\r\n                                       WDF_NO_OBJECT_ATTRIBUTES);\r\n\r\n    //\r\n    // In order to support METHOD_NEITHER Device controls, or\r\n    // NEITHER device I/O type, we need to register for the\r\n    // EvtDeviceIoInProcessContext callback so that we can handle the request\r\n    // in the calling threads context.\r\n    //\r\n    WdfDeviceInitSetIoInCallerContextCallback(DeviceInit,\r\n                                    NonPnpEvtDeviceIoInCallerContext);\r\n\r\n    //\r\n    // Specify the size of device context\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,\r\n                                    CONTROL_DEVICE_EXTENSION);\r\n\r\n    status = WdfDeviceCreate(&DeviceInit,\r\n                             &attributes,\r\n                             &controlDevice);\r\n    if (!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, \"WdfDeviceCreate failed %!STATUS!\", status);\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // Create a symbolic link for the control object so that usermode can open\r\n    // the device.\r\n    //\r\n\r\n\r\n    status = WdfDeviceCreateSymbolicLink(controlDevice,\r\n                                &symbolicLinkName);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        //\r\n        // Control device will be deleted automatically by the framework.\r\n        //\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, \"WdfDeviceCreateSymbolicLink failed %!STATUS!\", status);\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // Configure a default queue so that requests that are not\r\n    // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto\r\n    // other queues get dispatched here.\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,\r\n                                    WdfIoQueueDispatchSequential);\r\n\r\n    ioQueueConfig.EvtIoRead = FileEvtIoRead;\r\n    ioQueueConfig.EvtIoWrite = FileEvtIoWrite;\r\n    ioQueueConfig.EvtIoDeviceControl = FileEvtIoDeviceControl;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n    //\r\n    // Since we are using Zw function set execution level to passive so that\r\n    // framework ensures that our Io callbacks called at only passive-level\r\n    // even if the request came in at DISPATCH_LEVEL from another driver.\r\n    //\r\n    //attributes.ExecutionLevel = WdfExecutionLevelPassive;\r\n\r\n    //\r\n    // By default, Static Driver Verifier (SDV) displays a warning if it\r\n    // doesn't find the EvtIoStop callback on a power-managed queue.\r\n    // The 'assume' below causes SDV to suppress this warning. If the driver\r\n    // has not explicitly set PowerManaged to WdfFalse, the framework creates\r\n    // power-managed queues when the device is not a filter driver.  Normally\r\n    // the EvtIoStop is required for power-managed queues, but for this driver\r\n    // it is not needed b/c the driver doesn't hold on to the requests or\r\n    // forward them to other drivers. This driver completes the requests\r\n    // directly in the queue's handlers. If the EvtIoStop callback is not\r\n    // implemented, the framework waits for all driver-owned requests to be\r\n    // done before moving in the Dx/sleep states or before removing the\r\n    // device, which is the correct behavior for this type of driver.\r\n    // If the requests were taking an indeterminate amount of time to complete,\r\n    // or if the driver forwarded the requests to a lower driver/another stack,\r\n    // the queue should have an EvtIoStop/EvtIoResume.\r\n    //\r\n    __analysis_assume(ioQueueConfig.EvtIoStop != 0);\r\n    status = WdfIoQueueCreate(controlDevice,\r\n                              &ioQueueConfig,\r\n                              &attributes,\r\n                              &queue // pointer to default queue\r\n                              );\r\n    __analysis_assume(ioQueueConfig.EvtIoStop == 0);\r\n    if (!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, \"WdfIoQueueCreate failed %!STATUS!\", status);\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // Control devices must notify WDF when they are done initializing.   I/O is\r\n    // rejected until this call is made.\r\n    //\r\n    WdfControlFinishInitializing(controlDevice);\r\n\r\nEnd:\r\n    //\r\n    // If the device is created successfully, framework would clear the\r\n    // DeviceInit value. Otherwise device create must have failed so we\r\n    // should free the memory ourself.\r\n    //\r\n    if (DeviceInit != NULL) {\r\n        WdfDeviceInitFree(DeviceInit);\r\n    }\r\n\r\n    return status;\r\n\r\n}\r\n\r\nVOID\r\nNonPnpEvtDriverContextCleanup(\r\n    IN WDFOBJECT Driver\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n   Called when the driver object is deleted during driver unload.\r\n   You can free all the resources created in DriverEntry that are\r\n   not automatically freed by the framework.\r\n\r\nArguments:\r\n\r\n    Driver - Handle to a framework driver object created in DriverEntry\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,\r\n                        \"Entered NonPnpEvtDriverContextCleanup\\n\");\r\n\r\n    PAGED_CODE();\r\n\r\n    //\r\n    // No need to free the controldevice object explicitly because it will\r\n    // be deleted when the Driver object is deleted due to the default parent\r\n    // child relationship between Driver and ControlDevice.\r\n    //\r\n    WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver ) );\r\n\r\n}\r\n\r\n\r\n\r\nVOID\r\nNonPnpEvtDeviceFileCreate (\r\n    IN WDFDEVICE            Device,\r\n    IN WDFREQUEST Request,\r\n    IN WDFFILEOBJECT        FileObject\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    The framework calls a driver's EvtDeviceFileCreate callback\r\n    when it receives an IRP_MJ_CREATE request.\r\n    The system sends this request when a user application opens the\r\n    device to perform an I/O operation, such as reading or writing a file.\r\n    This callback is called synchronously, in the context of the thread\r\n    that created the IRP_MJ_CREATE request.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n    FileObject - Pointer to fileobject that represents the open handle.\r\n    CreateParams - Parameters of IO_STACK_LOCATION for create\r\n\r\nReturn Value:\r\n\r\n   NT status code\r\n\r\n--*/\r\n{\r\n    PUNICODE_STRING             fileName;\r\n    UNICODE_STRING              absFileName, directory;\r\n    OBJECT_ATTRIBUTES           fileAttributes;\r\n    IO_STATUS_BLOCK             ioStatus;\r\n    PCONTROL_DEVICE_EXTENSION   devExt;\r\n    NTSTATUS                    status;\r\n    USHORT                      length = 0;\r\n\r\n\r\n    UNREFERENCED_PARAMETER( FileObject );\r\n\r\n    PAGED_CODE ();\r\n\r\n    devExt = ControlGetData(Device);\r\n\r\n    //\r\n    // Assume the directory is a temp directory under %windir%\r\n    //\r\n    RtlInitUnicodeString(&directory, L\"\\\\SystemRoot\\\\temp\");\r\n\r\n    //\r\n    // Parsed filename has \"\\\" in the begining. The object manager strips\r\n    // of all \"\\\", except one, after the device name.\r\n    //\r\n    fileName = WdfFileObjectGetFileName(FileObject);\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, \"NonPnpEvtDeviceFileCreate %wZ%wZ\",\r\n                   &directory, fileName);\r\n\r\n    //\r\n    // Find the total length of the directory + filename\r\n    //\r\n    length = directory.Length + fileName->Length;\r\n\r\n    absFileName.Buffer = ExAllocatePoolWithTag(PagedPool, length, POOL_TAG);\r\n    if(absFileName.Buffer == NULL) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, \"ExAllocatePoolWithTag failed\");\r\n        goto End;\r\n    }\r\n    absFileName.Length = 0;\r\n    absFileName.MaximumLength =  length;\r\n\r\n    status = RtlAppendUnicodeStringToString(&absFileName, &directory);\r\n    if (!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,\r\n                   \"RtlAppendUnicodeStringToString failed with status %!STATUS!\",\r\n                   status);\r\n        goto End;\r\n    }\r\n\r\n    status = RtlAppendUnicodeStringToString(&absFileName, fileName);\r\n    if (!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,\r\n                   \"RtlAppendUnicodeStringToString failed with status %!STATUS!\",\r\n                   status);\r\n        goto End;\r\n    }\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, \"Absolute Filename %wZ\", &absFileName);\r\n\r\n    InitializeObjectAttributes( &fileAttributes,\r\n                                &absFileName,\r\n                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r\n                                NULL, // RootDirectory\r\n                                NULL // SecurityDescriptor\r\n                                );\r\n\r\n    status = ZwCreateFile (\r\n                    &devExt->FileHandle,\r\n                    SYNCHRONIZE | GENERIC_WRITE | GENERIC_READ,\r\n                    &fileAttributes,\r\n                    &ioStatus,\r\n                    NULL,// alloc size = none\r\n                    FILE_ATTRIBUTE_NORMAL,\r\n                    FILE_SHARE_READ,\r\n                    FILE_OPEN_IF,\r\n                    FILE_SYNCHRONOUS_IO_NONALERT |FILE_NON_DIRECTORY_FILE,\r\n                    NULL,// eabuffer\r\n                    0// ealength\r\n                    );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,\r\n                       \"ZwCreateFile failed with status %!STATUS!\", status);\r\n        devExt->FileHandle = NULL;\r\n    }\r\n\r\nEnd:\r\n    if(absFileName.Buffer != NULL) {\r\n        ExFreePool(absFileName.Buffer);\r\n    }\r\n\r\n    WdfRequestComplete(Request, status);\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nNonPnpEvtFileClose (\r\n    IN WDFFILEOBJECT    FileObject\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   EvtFileClose is called when all the handles represented by the FileObject\r\n   is closed and all the references to FileObject is removed. This callback\r\n   may get called in an arbitrary thread context instead of the thread that\r\n   called CloseHandle. If you want to delete any per FileObject context that\r\n   must be done in the context of the user thread that made the Create call,\r\n   you should do that in the EvtDeviceCleanp callback.\r\n\r\nArguments:\r\n\r\n    FileObject - Pointer to fileobject that represents the open handle.\r\n\r\nReturn Value:\r\n\r\n   VOID\r\n\r\n--*/\r\n{\r\n    PCONTROL_DEVICE_EXTENSION devExt;\r\n\r\n    PAGED_CODE ();\r\n\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, \"NonPnpEvtFileClose\\n\");\r\n\r\n    devExt = ControlGetData(WdfFileObjectGetDevice(FileObject));\r\n\r\n    if(devExt->FileHandle) {\r\n        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,\r\n                       \"Closing File Handle %p\", devExt->FileHandle);\r\n        ZwClose(devExt->FileHandle);\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nFileEvtIoRead(\r\n    IN WDFQUEUE         Queue,\r\n    IN WDFREQUEST       Request,\r\n    IN size_t            Length\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called when the framework receives IRP_MJ_READ requests.\r\n    We will just read the file.\r\n\r\nArguments:\r\n\r\n    Queue -  Handle to the framework queue object that is associated with the\r\n            I/O request.\r\n    Request - Handle to a framework request object.\r\n\r\n    Length  - number of bytes to be read.\r\n                   Queue is by default configured to fail zero length read & write requests.\r\n\r\nReturn Value:\r\n\r\n  None.\r\n\r\n--*/\r\n{\r\n    NTSTATUS                   status = STATUS_SUCCESS;\r\n    PVOID                       outBuf;\r\n    IO_STATUS_BLOCK             ioStatus;\r\n    PCONTROL_DEVICE_EXTENSION   devExt;\r\n    FILE_POSITION_INFORMATION   position;\r\n    ULONG_PTR                   bytesRead = 0;\r\n    size_t  bufLength;\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_RW, \"FileEvtIoRead: Request: 0x%p, Queue: 0x%p\\n\",\r\n                     Request, Queue);\r\n\r\n    PAGED_CODE ();\r\n\r\n    //\r\n    // Get the request buffer. Since the device is set to do buffered\r\n    // I/O, this function will retrieve Irp->AssociatedIrp.SystemBuffer.\r\n    //\r\n    status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufLength);\r\n    if(!NT_SUCCESS(status)) {\r\n        WdfRequestComplete(Request, status);\r\n        return;\r\n\r\n    }\r\n\r\n    devExt = ControlGetData(WdfIoQueueGetDevice(Queue));\r\n\r\n    if(devExt->FileHandle) {\r\n\r\n        //\r\n        // Set the file position to the beginning of the file.\r\n        //\r\n        position.CurrentByteOffset.QuadPart = 0;\r\n        status = ZwSetInformationFile(devExt->FileHandle,\r\n                             &ioStatus,\r\n                             &position,\r\n                             sizeof(FILE_POSITION_INFORMATION),\r\n                             FilePositionInformation);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            status = ZwReadFile (devExt->FileHandle,\r\n                                NULL,//   Event,\r\n                                NULL,// PIO_APC_ROUTINE  ApcRoutine\r\n                                NULL,// PVOID  ApcContext\r\n                                &ioStatus,\r\n                                outBuf,\r\n                                (ULONG)Length,\r\n                                0, // ByteOffset\r\n                                NULL // Key\r\n                                );\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TraceEvents(TRACE_LEVEL_ERROR, DBG_RW,\r\n                               \"ZwReadFile failed with status 0x%x\",\r\n                               status);\r\n            }\r\n\r\n            status = ioStatus.Status;\r\n            bytesRead = ioStatus.Information;\r\n        }\r\n    }\r\n\r\n    WdfRequestCompleteWithInformation(Request, status, bytesRead);\r\n\r\n}\r\n\r\n\r\n\r\nVOID\r\nFileEvtIoWrite(\r\n    IN WDFQUEUE         Queue,\r\n    IN WDFREQUEST       Request,\r\n    IN size_t            Length\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called when the framework receives IRP_MJ_WRITE requests.\r\n\r\nArguments:\r\n\r\n    Queue -  Handle to the framework queue object that is associated with the\r\n            I/O request.\r\n    Request - Handle to a framework request object.\r\n\r\n    Length  - number of bytes to be written.\r\n                   Queue is by default configured to fail zero length read & write requests.\r\n\r\n\r\nReturn Value:\r\n\r\n   None\r\n--*/\r\n{\r\n    NTSTATUS                   status = STATUS_SUCCESS;\r\n    PVOID                       inBuf;\r\n    IO_STATUS_BLOCK             ioStatus;\r\n    PCONTROL_DEVICE_EXTENSION   devExt;\r\n    FILE_POSITION_INFORMATION   position;\r\n    ULONG_PTR                   bytesWritten = 0;\r\n    size_t      bufLength;\r\n\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_RW, \"FileEvtIoWrite: Request: 0x%p, Queue: 0x%p\\n\",\r\n                     Request, Queue);\r\n    PAGED_CODE ();\r\n\r\n    //\r\n    // Get the request buffer. Since the device is set to do buffered\r\n    // I/O, this function will retrieve Irp->AssociatedIrp.SystemBuffer.\r\n    //\r\n    status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufLength);\r\n    if(!NT_SUCCESS(status)) {\r\n        WdfRequestComplete(Request, status);\r\n        return;\r\n\r\n    }\r\n\r\n    devExt = ControlGetData(WdfIoQueueGetDevice(Queue));\r\n\r\n    if(devExt->FileHandle) {\r\n\r\n        //\r\n        // Set the file position to the beginning of the file.\r\n        //\r\n        position.CurrentByteOffset.QuadPart = 0;\r\n\r\n        status = ZwSetInformationFile(devExt->FileHandle,\r\n                             &ioStatus,\r\n                             &position,\r\n                             sizeof(FILE_POSITION_INFORMATION),\r\n                             FilePositionInformation);\r\n        if (NT_SUCCESS(status))\r\n        {\r\n\r\n            status = ZwWriteFile(devExt->FileHandle,\r\n                                NULL,//   Event,\r\n                                NULL,// PIO_APC_ROUTINE  ApcRoutine\r\n                                NULL,// PVOID  ApcContext\r\n                                &ioStatus,\r\n                                inBuf,\r\n                                (ULONG)Length,\r\n                                0, // ByteOffset\r\n                                NULL // Key\r\n                                );\r\n            if (!NT_SUCCESS(status))\r\n            {\r\n                TraceEvents(TRACE_LEVEL_ERROR, DBG_RW,\r\n                               \"ZwWriteFile failed with status 0x%x\",\r\n                               status);\r\n            }\r\n\r\n            status = ioStatus.Status;\r\n            bytesWritten =  ioStatus.Information;\r\n        }\r\n    }\r\n\r\n    WdfRequestCompleteWithInformation(Request, status, bytesWritten);\r\n\r\n}\r\n\r\nVOID\r\nFileEvtIoDeviceControl(\r\n    IN WDFQUEUE         Queue,\r\n    IN WDFREQUEST       Request,\r\n    IN size_t            OutputBufferLength,\r\n    IN size_t            InputBufferLength,\r\n    IN ULONG            IoControlCode\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL\r\n    requests from the system.\r\n\r\nArguments:\r\n\r\n    Queue - Handle to the framework queue object that is associated\r\n            with the I/O request.\r\n    Request - Handle to a framework request object.\r\n\r\n    OutputBufferLength - length of the request's output buffer,\r\n                        if an output buffer is available.\r\n    InputBufferLength - length of the request's input buffer,\r\n                        if an input buffer is available.\r\n\r\n    IoControlCode - the driver-defined or system-defined I/O control code\r\n                    (IOCTL) that is associated with the request.\r\n\r\nReturn Value:\r\n\r\n   VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS            status = STATUS_SUCCESS;// Assume success\r\n    PCHAR               inBuf = NULL, outBuf = NULL; // pointer to Input and output buffer\r\n    PCHAR               data = \"this String is from Device Driver !!!\";\r\n    ULONG               datalen = (ULONG) strlen(data)+1;//Length of data including null\r\n    PCHAR               buffer = NULL;\r\n    PREQUEST_CONTEXT    reqContext = NULL;\r\n    size_t               bufSize;\r\n\r\n    UNREFERENCED_PARAMETER( Queue );\r\n\r\n    PAGED_CODE();\r\n\r\n    if(!OutputBufferLength || !InputBufferLength)\r\n    {\r\n        WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);\r\n        return;\r\n    }\r\n\r\n    //\r\n    // Determine which I/O control code was specified.\r\n    //\r\n\r\n    switch (IoControlCode)\r\n    {\r\n    case IOCTL_NONPNP_METHOD_BUFFERED:\r\n\r\n\r\n        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Called IOCTL_NONPNP_METHOD_BUFFERED\\n\");\r\n\r\n        //\r\n        // For bufffered ioctls WdfRequestRetrieveInputBuffer &\r\n        // WdfRequestRetrieveOutputBuffer return the same buffer\r\n        // pointer (Irp->AssociatedIrp.SystemBuffer), so read the\r\n        // content of the buffer before writing to it.\r\n        //\r\n        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == InputBufferLength);\r\n\r\n        //\r\n        // Read the input buffer content.\r\n        // We are using the following function to print characters instead\r\n        // TraceEvents with %s format because the string we get may or\r\n        // may not be null terminated. The buffer may contain non-printable\r\n        // characters also.\r\n        //\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data from User : %!HEXDUMP!\\n\",\r\n                        log_xstr(inBuf, (USHORT)InputBufferLength)));\r\n        PrintChars(inBuf, InputBufferLength  );\r\n\r\n\r\n        status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == OutputBufferLength);\r\n\r\n        //\r\n        // Writing to the buffer over-writes the input buffer content\r\n        //\r\n\r\n        RtlCopyMemory(outBuf, data, OutputBufferLength);\r\n\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data to User : %!HEXDUMP!\\n\",\r\n                        log_xstr(outBuf, (USHORT)datalen)));\r\n        PrintChars(outBuf, datalen  );\r\n\r\n        //\r\n        // Assign the length of the data copied to IoStatus.Information\r\n        // of the request and complete the request.\r\n        //\r\n        WdfRequestSetInformation(Request,\r\n                OutputBufferLength < datalen? OutputBufferLength:datalen);\r\n\r\n        //\r\n        // When the request is completed the content of the SystemBuffer\r\n        // is copied to the User output buffer and the SystemBuffer is\r\n        // is freed.\r\n        //\r\n\r\n       break;\r\n\r\n\r\n    case IOCTL_NONPNP_METHOD_IN_DIRECT:\r\n\r\n\r\n        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Called IOCTL_NONPNP_METHOD_IN_DIRECT\\n\");\r\n\r\n        //\r\n        // Get the Input buffer. WdfRequestRetrieveInputBuffer returns\r\n        // Irp->AssociatedIrp.SystemBuffer.\r\n        //\r\n        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == InputBufferLength);\r\n\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data from User : %!HEXDUMP!\\n\",\r\n                        log_xstr(inBuf, (USHORT)InputBufferLength)));\r\n        PrintChars(inBuf, InputBufferLength);\r\n\r\n        //\r\n        // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe\r\n        // on the Irp->MdlAddress and returns the system address.\r\n        // Oddity: For this method, this buffer is intended for transfering data\r\n        // from the application to the driver.\r\n        //\r\n\r\n        status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == OutputBufferLength);\r\n\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data from User in OutputBuffer: %!HEXDUMP!\\n\",\r\n                        log_xstr(buffer, (USHORT)OutputBufferLength)));\r\n        PrintChars(buffer, OutputBufferLength);\r\n\r\n        //\r\n        // Return total bytes read from the output buffer.\r\n        // Note OutputBufferLength = MmGetMdlByteCount(Irp->MdlAddress)\r\n        //\r\n\r\n        WdfRequestSetInformation(Request, OutputBufferLength);\r\n\r\n        //\r\n        // NOTE: Changes made to the  SystemBuffer are not copied\r\n        // to the user input buffer by the I/O manager\r\n        //\r\n\r\n      break;\r\n\r\n    case IOCTL_NONPNP_METHOD_OUT_DIRECT:\r\n\r\n\r\n        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Called IOCTL_NONPNP_METHOD_OUT_DIRECT\\n\");\r\n\r\n        //\r\n        // Get the Input buffer. WdfRequestRetrieveInputBuffer returns\r\n        // Irp->AssociatedIrp.SystemBuffer.\r\n        //\r\n        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == InputBufferLength);\r\n\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data from User : %!HEXDUMP!\\n\",\r\n                        log_xstr(inBuf, (USHORT)InputBufferLength)));\r\n        PrintChars(inBuf, InputBufferLength);\r\n\r\n        //\r\n        // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe\r\n        // on the Irp->MdlAddress and returns the system address.\r\n        // For this method, this buffer is intended for transfering data from the\r\n        // driver to the application.\r\n        //\r\n        status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize);\r\n        if(!NT_SUCCESS(status)) {\r\n            break;\r\n        }\r\n\r\n        ASSERT(bufSize == OutputBufferLength);\r\n\r\n        //\r\n        // Write data to be sent to the user in this buffer\r\n        //\r\n        RtlCopyMemory(buffer, data, OutputBufferLength);\r\n\r\n        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data to User : %!HEXDUMP!\\n\",\r\n                        log_xstr(buffer, (USHORT)datalen)));\r\n        PrintChars(buffer, datalen);\r\n\r\n        WdfRequestSetInformation(Request,\r\n                    OutputBufferLength < datalen? OutputBufferLength: datalen);\r\n\r\n        //\r\n        // NOTE: Changes made to the  SystemBuffer are not copied\r\n        // to the user input buffer by the I/O manager\r\n        //\r\n\r\n        break;\r\n\r\n    case IOCTL_NONPNP_METHOD_NEITHER:\r\n        {\r\n            size_t inBufLength, outBufLength;\r\n\r\n            //\r\n            // The NonPnpEvtDeviceIoInCallerContext has already probe and locked the\r\n            // pages and mapped the user buffer into system address space and\r\n            // stored memory buffer pointers in the request context. We can get the\r\n            // buffer pointer by calling WdfMemoryGetBuffer.\r\n            //\r\n            TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Called IOCTL_NONPNP_METHOD_NEITHER\\n\");\r\n\r\n            reqContext = GetRequestContext(Request);\r\n\r\n            inBuf = WdfMemoryGetBuffer(reqContext->InputMemoryBuffer, &inBufLength);\r\n            outBuf = WdfMemoryGetBuffer(reqContext->OutputMemoryBuffer, &outBufLength);\r\n\r\n            if(inBuf == NULL || outBuf == NULL) {\r\n                status = STATUS_INVALID_PARAMETER;\r\n            }\r\n\r\n            ASSERT(inBufLength == InputBufferLength);\r\n            ASSERT(outBufLength == OutputBufferLength);\r\n\r\n            //\r\n            // Now you can safely read the data from the buffer in any arbitrary\r\n            // context.\r\n            //\r\n            Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data from User : %!HEXDUMP!\\n\",\r\n                            log_xstr(inBuf, (USHORT)inBufLength)));\r\n            PrintChars(inBuf, inBufLength);\r\n\r\n            //\r\n            // Write to the buffer in any arbitrary context.\r\n            //\r\n            RtlCopyMemory(outBuf, data, outBufLength);\r\n\r\n            Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, \"Data to User : %!HEXDUMP!\\n\",\r\n                            log_xstr(outBuf, (USHORT)datalen)));\r\n            PrintChars(outBuf, datalen);\r\n\r\n            //\r\n            // Assign the length of the data copied to IoStatus.Information\r\n            // of the Irp and complete the Irp.\r\n            //\r\n            WdfRequestSetInformation(Request,\r\n                    outBufLength < datalen? outBufLength:datalen);\r\n\r\n            break;\r\n        }\r\n    default:\r\n\r\n        //\r\n        // The specified I/O control code is unrecognized by this driver.\r\n        //\r\n        status = STATUS_INVALID_DEVICE_REQUEST;\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, \"ERROR: unrecognized IOCTL %x\\n\", IoControlCode);\r\n        break;\r\n    }\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Completing Request %p with status %X\",\r\n                   Request, status );\r\n\r\n    WdfRequestComplete( Request, status);\r\n\r\n}\r\n\r\nVOID\r\nNonPnpEvtDeviceIoInCallerContext(\r\n    IN WDFDEVICE  Device,\r\n    IN WDFREQUEST Request\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    This I/O in-process callback is called in the calling threads context/address\r\n    space before the request is subjected to any framework locking or queueing\r\n    scheme based on the device pnp/power or locking attributes set by the\r\n    driver. The process context of the calling app is guaranteed as long as\r\n    this driver is a top-level driver and no other filter driver is attached\r\n    to it.\r\n\r\n    This callback is only required if you are handling method-neither IOCTLs,\r\n    or want to process requests in the context of the calling process.\r\n\r\n    Driver developers should avoid defining neither IOCTLs and access user\r\n    buffers, and use much safer I/O tranfer methods such as buffered I/O\r\n    or direct I/O.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    Request - Handle to a framework request object. Framework calls\r\n              PreProcess callback only for Read/Write/ioctls and internal\r\n              ioctl requests.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS                   status = STATUS_SUCCESS;\r\n    PREQUEST_CONTEXT            reqContext = NULL;\r\n    WDF_OBJECT_ATTRIBUTES           attributes;\r\n    WDF_REQUEST_PARAMETERS  params;\r\n    size_t              inBufLen, outBufLen;\r\n    PVOID              inBuf, outBuf;\r\n\r\n    PAGED_CODE();\r\n\r\n    WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n    WdfRequestGetParameters(Request,  &params );\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"Entered NonPnpEvtDeviceIoInCallerContext %p \\n\",\r\n                            Request);\r\n\r\n    //\r\n    // Check to see whether we have recevied a METHOD_NEITHER IOCTL. if not\r\n    // just send the request back to framework because we aren't doing\r\n    // any pre-processing in the context of the calling thread process.\r\n    //\r\n    if(!(params.Type == WdfRequestTypeDeviceControl &&\r\n            params.Parameters.DeviceIoControl.IoControlCode ==\r\n                                    IOCTL_NONPNP_METHOD_NEITHER)) {\r\n        //\r\n        // Forward it for processing by the I/O package\r\n        //\r\n        status = WdfDeviceEnqueueRequest(Device, Request);\r\n        if( !NT_SUCCESS(status) ) {\r\n            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                        \"Error forwarding Request 0x%x\",  status);\r\n            goto End;\r\n        }\r\n\r\n        return;\r\n    }\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"EvtIoPreProcess: received METHOD_NEITHER ioctl \\n\");\r\n\r\n    //\r\n    // In this type of transfer, the I/O manager assigns the user input\r\n    // to Type3InputBuffer and the output buffer to UserBuffer of the Irp.\r\n    // The I/O manager doesn't copy or map the buffers to the kernel\r\n    // buffers.\r\n    //\r\n    status = WdfRequestRetrieveUnsafeUserInputBuffer(Request, 0, &inBuf, &inBufLen);\r\n    if(!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfRequestRetrieveUnsafeUserInputBuffer failed 0x%x\",  status);\r\n        goto End;\r\n    }\r\n\r\n    status = WdfRequestRetrieveUnsafeUserOutputBuffer(Request, 0, &outBuf, &outBufLen);\r\n    if(!NT_SUCCESS(status)) {\r\n       TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfRequestRetrieveUnsafeUserOutputBuffer failed 0x%x\",  status);\r\n       goto End;\r\n    }\r\n\r\n    //\r\n    // Allocate a context for this request so that we can store the memory\r\n    // objects created for input and output buffer.\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);\r\n\r\n    status = WdfObjectAllocateContext(Request, &attributes, &reqContext);\r\n    if(!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfObjectAllocateContext failed 0x%x\",  status);\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // WdfRequestProbleAndLockForRead/Write function checks to see\r\n    // whether the caller in the right thread context, creates an MDL,\r\n    // probe and locks the pages, and map the MDL to system address\r\n    // space and finally creates a WDFMEMORY object representing this\r\n    // system buffer address. This memory object is associated with the\r\n    // request. So it will be freed when the request is completed. If we\r\n    // are accessing this memory buffer else where, we should store these\r\n    // pointers in the request context.\r\n    //\r\n\r\n    #pragma prefast(suppress:6387, \"If inBuf==NULL at this point, then inBufLen==0\")\r\n    status = WdfRequestProbeAndLockUserBufferForRead(Request,\r\n                            inBuf,\r\n                            inBufLen,\r\n                            &reqContext->InputMemoryBuffer);\r\n\r\n    if(!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfRequestProbeAndLockUserBufferForRead failed 0x%x\",  status);\r\n        goto End;\r\n    }\r\n\r\n    #pragma prefast(suppress:6387, \"If outBuf==NULL at this point, then outBufLen==0\")\r\n    status = WdfRequestProbeAndLockUserBufferForWrite(Request,\r\n                            outBuf,\r\n                            outBufLen,\r\n                            &reqContext->OutputMemoryBuffer);\r\n    if(!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfRequestProbeAndLockUserBufferForWrite failed 0x%x\",  status);\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // Finally forward it for processing by the I/O package\r\n    //\r\n    status = WdfDeviceEnqueueRequest(Device, Request);\r\n    if(!NT_SUCCESS(status)) {\r\n        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,\r\n                                    \"Error WdfDeviceEnqueueRequest failed 0x%x\",  status);\r\n        goto End;\r\n    }\r\n\r\n    return;\r\n\r\nEnd:\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, \"EvtIoPreProcess failed %x \\n\", status);\r\n    WdfRequestComplete(Request, status);\r\n    return;\r\n}\r\n\r\nVOID\r\nNonPnpShutdown(\r\n    WDFDEVICE Device\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n    Callback invoked when the machine is shutting down.  If you register for\r\n    a last chance shutdown notification you cannot do the following:\r\n    o Call any pageable routines\r\n    o Access pageable memory\r\n    o Perform any file I/O operations\r\n\r\n    If you register for a normal shutdown notification, all of these are\r\n    available to you.\r\n\r\n    This function implementation does nothing, but if you had any outstanding\r\n    file handles open, this is where you would close them.\r\n\r\nArguments:\r\n    Device - The device which registered the notification during init\r\n\r\nReturn Value:\r\n    None\r\n\r\n  --*/\r\n\r\n{\r\n    UNREFERENCED_PARAMETER(Device);\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nNonPnpEvtDriverUnload(\r\n    IN WDFDRIVER Driver\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n   Called by the I/O subsystem just before unloading the driver.\r\n   You can free the resources created in the DriverEntry either\r\n   in this routine or in the EvtDriverContextCleanup callback.\r\n\r\nArguments:\r\n\r\n    Driver - Handle to a framework driver object created in DriverEntry\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(Driver);\r\n\r\n    PAGED_CODE();\r\n\r\n    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, \"Entered NonPnpDriverUnload\\n\");\r\n\r\n    return;\r\n}\r\n\r\nVOID\r\nPrintChars(\r\n    _In_reads_(CountChars) PCHAR BufferAddress,\r\n    _In_ size_t CountChars\r\n    )\r\n{\r\n    if (CountChars) {\r\n\r\n        while (CountChars--) {\r\n\r\n            if (*BufferAddress > 31\r\n                 && *BufferAddress != 127) {\r\n\r\n                KdPrint (( \"%c\", *BufferAddress) );\r\n\r\n            } else {\r\n\r\n                KdPrint(( \".\") );\r\n\r\n            }\r\n            BufferAddress++;\r\n        }\r\n        KdPrint ((\"\\n\"));\r\n    }\r\n    return;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    nonpnp.h\r\n\r\nAbstract:\r\n\r\n    Contains function prototypes and includes other neccessary header files.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode only.\r\n\r\n--*/\r\n\r\n#include <ntddk.h>\r\n#include <wdf.h>\r\n\r\n#define NTSTRSAFE_LIB\r\n#include <ntstrsafe.h>\r\n#include <wdmsec.h> // for SDDLs\r\n#include \"public.h\" // contains IOCTL definitions\r\n#include \"Trace.h\" // contains macros for WPP tracing\r\n\r\n#define NTDEVICE_NAME_STRING      L\"\\\\Device\\\\NONPNP\"\r\n#define SYMBOLIC_NAME_STRING     L\"\\\\DosDevices\\\\NONPNP\"\r\n#define POOL_TAG                   'ELIF'\r\n\r\ntypedef struct _CONTROL_DEVICE_EXTENSION {\r\n\r\n    HANDLE   FileHandle; // Store your control data here\r\n\r\n} CONTROL_DEVICE_EXTENSION, *PCONTROL_DEVICE_EXTENSION;\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROL_DEVICE_EXTENSION,\r\n                                        ControlGetData)\r\n\r\n//\r\n// Following request context is used only for the method-neither ioctl case.\r\n//\r\ntypedef struct _REQUEST_CONTEXT {\r\n\r\n    WDFMEMORY InputMemoryBuffer;\r\n    WDFMEMORY OutputMemoryBuffer;\r\n\r\n} REQUEST_CONTEXT, *PREQUEST_CONTEXT;\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext)\r\n\r\n//\r\n// Device driver routine declarations.\r\n//\r\n\r\nDRIVER_INITIALIZE DriverEntry;\r\n\r\n//\r\n// Don't use EVT_WDF_DRIVER_DEVICE_ADD for NonPnpDeviceAdd even though\r\n// the signature is same because this is not an event called by the\r\n// framework.\r\n//\r\nNTSTATUS\r\nNonPnpDeviceAdd(\r\n    IN WDFDRIVER Driver,\r\n    IN PWDFDEVICE_INIT DeviceInit\r\n    );\r\n\r\nEVT_WDF_DRIVER_UNLOAD NonPnpEvtDriverUnload;\r\n\r\nEVT_WDF_DEVICE_CONTEXT_CLEANUP NonPnpEvtDriverContextCleanup;\r\nEVT_WDF_DEVICE_SHUTDOWN_NOTIFICATION NonPnpShutdown;\r\n\r\nEVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FileEvtIoDeviceControl;\r\nEVT_WDF_IO_QUEUE_IO_READ FileEvtIoRead;\r\nEVT_WDF_IO_QUEUE_IO_WRITE FileEvtIoWrite;\r\n\r\nEVT_WDF_IO_IN_CALLER_CONTEXT NonPnpEvtDeviceIoInCallerContext;\r\nEVT_WDF_DEVICE_FILE_CREATE NonPnpEvtDeviceFileCreate;\r\nEVT_WDF_FILE_CLOSE NonPnpEvtFileClose;\r\n\r\nVOID\r\nPrintChars(\r\n    _In_reads_(CountChars) PCHAR BufferAddress,\r\n    _In_ size_t CountChars\r\n    );\r\n\r\n#pragma warning(disable:4127)\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/driver/nonpnp.rc",
    "content": "#include <windows.h>\r\n\r\n#include <ntverp.h>\r\n\r\n#define VER_FILETYPE             VFT_DRV\r\n#define VER_FILESUBTYPE          VFT2_DRV_SYSTEM\r\n#define VER_FILEDESCRIPTION_STR  \"Sample Non-PNP Driver using WDF\"\r\n#define VER_INTERNALNAME_STR     \"NONPNP.sys\"\r\n\r\n#include \"common.ver\"\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/driver/trace.h",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    TRACE.h\r\n\r\nAbstract:\r\n\r\n    Header file for the debug tracing related function defintions and macros.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n//\r\n// If software tracing is defined in the sources file..\r\n// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver.\r\n// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID ***\r\n// WPP_DEFINE_BIT allows setting debug bit masks to selectively print.\r\n// The names defined in the WPP_DEFINE_BIT call define the actual names\r\n// that are used to control the level of tracing for the control guid\r\n// specified.\r\n//\r\n//   {71ae54db-0862-41bf-a24f-5330cec3c7f6}\r\n//\r\n#define WPP_CHECK_FOR_NULL_STRING  //to prevent exceptions due to NULL strings\r\n\r\n#define WPP_CONTROL_GUIDS                                            \\\r\n    WPP_DEFINE_CONTROL_GUID( FileIoTraceGuid,                        \\\r\n                             (71ae54db,0862,41bf,a24f,5330cec3c7f6), \\\r\n                             WPP_DEFINE_BIT(DBG_INIT)     \\\r\n                             WPP_DEFINE_BIT(DBG_RW)       \\\r\n                             WPP_DEFINE_BIT(DBG_IOCTL)    \\\r\n                             )\r\n\r\n#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)\r\n#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level  >= lvl)\r\n\r\n#pragma warning(disable:4204) // C4204 nonstandard extension used : non-constant aggregate initializer\r\n\r\n//\r\n// Define the 'xstr' structure for logging buffer and length pairs\r\n// and the 'log_xstr' function which returns it to create one in-place.\r\n// this enables logging of complex data types.\r\n//\r\ntypedef struct xstr { char * _buf; short  _len; } xstr_t;\r\n__inline xstr_t log_xstr(void * p, short l) { xstr_t xs = {(char*)p,l}; return xs; }\r\n\r\n#pragma warning(default:4204)\r\n\r\n//\r\n// Define the macro required for a hexdump use as:\r\n//\r\n//   Hexdump((FLAG,\"%!HEXDUMP!\\n\", log_xstr(buffersize,(char *)buffer) ));\r\n//\r\n//\r\n#define WPP_LOGHEXDUMP(x) WPP_LOGPAIR(2, &((x)._len)) WPP_LOGPAIR((x)._len, (x)._buf)\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/exe/install.c",
    "content": "/*++\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    install.c\r\n\r\nAbstract:\r\n\r\n    Win32 routines to dynamically load and unload a Windows NT kernel-mode\r\n    driver using the Service Control Manager APIs.\r\n\r\nEnvironment:\r\n\r\n    User mode only\r\n\r\n--*/\r\n\r\n\r\n#include <DriverSpecs.h>\r\n_Analysis_mode_(_Analysis_code_type_user_code_)\r\n\r\n#include <windows.h>\r\n#include <strsafe.h>\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <string.h>\r\n#include \"public.h\"\r\n\r\n#include <wdfinstaller.h>\r\n\r\n#define ARRAY_SIZE(x)        (sizeof(x) /sizeof(x[0]))\r\n\r\nextern\r\nPCHAR\r\nGetCoinstallerVersion(\r\n    VOID\r\n    ) ;\r\n\r\nBOOLEAN\r\nInstallDriver(\r\n    IN SC_HANDLE  SchSCManager,\r\n    IN LPCTSTR    DriverName,\r\n    IN LPCTSTR    ServiceExe\r\n    );\r\n\r\n\r\nBOOLEAN\r\nRemoveDriver(\r\n    IN SC_HANDLE  SchSCManager,\r\n    IN LPCTSTR    DriverName\r\n    );\r\n\r\nBOOLEAN\r\nStartDriver(\r\n    IN SC_HANDLE  SchSCManager,\r\n    IN LPCTSTR    DriverName\r\n    );\r\n\r\nBOOLEAN\r\nStopDriver(\r\n    IN SC_HANDLE  SchSCManager,\r\n    IN LPCTSTR    DriverName\r\n    );\r\n\r\n#define SYSTEM32_DRIVERS \"\\\\System32\\\\Drivers\\\\\"\r\n#define NONPNP_INF_FILENAME  L\"\\\\nonpnp.inf\"\r\n#define WDF_SECTION_NAME L\"nonpnp.NT.Wdf\"\r\n\r\n//----------------------------------------------------------------------------\r\n//\r\n//----------------------------------------------------------------------------\r\nPFN_WDFPREDEVICEINSTALLEX pfnWdfPreDeviceInstallEx;\r\nPFN_WDFPOSTDEVICEINSTALL   pfnWdfPostDeviceInstall;\r\nPFN_WDFPREDEVICEREMOVE     pfnWdfPreDeviceRemove;\r\nPFN_WDFPOSTDEVICEREMOVE   pfnWdfPostDeviceRemove;\r\n\r\n//-----------------------------------------------------------------------------\r\n// 4127 -- Conditional Expression is Constant warning\r\n//-----------------------------------------------------------------------------\r\n#define WHILE(a) \\\r\n__pragma(warning(suppress:4127)) while(a)\r\n\r\nLONG\r\nGetPathToInf(\r\n    _Out_writes_(InfFilePathSize) PWCHAR InfFilePath,\r\n    IN ULONG InfFilePathSize\r\n    )\r\n{\r\n    LONG    error = ERROR_SUCCESS;\r\n\r\n    if (GetCurrentDirectoryW(InfFilePathSize, InfFilePath) == 0) {\r\n        error =  GetLastError();\r\n        printf(\"InstallDriver failed!  Error = %d \\n\", error);\r\n        return error;\r\n    }\r\n    if (FAILED( StringCchCatW(InfFilePath,\r\n                              InfFilePathSize,\r\n                              NONPNP_INF_FILENAME) )) {\r\n        error = ERROR_BUFFER_OVERFLOW;\r\n        return error;\r\n    }\r\n    return error;\r\n\r\n}\r\n\r\n//----------------------------------------------------------------------------\r\n//\r\n//----------------------------------------------------------------------------\r\nBOOLEAN\r\nInstallDriver(\r\n    IN SC_HANDLE  SchSCManager,\r\n    IN LPCTSTR    DriverName,\r\n    IN LPCTSTR    ServiceExe\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\nArguments:\r\n\r\nReturn Value:\r\n\r\n--*/\r\n{\r\n    SC_HANDLE   schService;\r\n    DWORD       err;\r\n    WCHAR      infPath[MAX_PATH];\r\n    WDF_COINSTALLER_INSTALL_OPTIONS clientOptions;\r\n\r\n    WDF_COINSTALLER_INSTALL_OPTIONS_INIT(&clientOptions);\r\n\r\n    //\r\n    // NOTE: This creates an entry for a standalone driver. If this\r\n    //       is modified for use with a driver that requires a Tag,\r\n    //       Group, and/or Dependencies, it may be necessary to\r\n    //       query the registry for existing driver information\r\n    //       (in order to determine a unique Tag, etc.).\r\n    //\r\n    //\r\n    // PRE-INSTALL for WDF support\r\n    //\r\n    err = GetPathToInf(infPath, ARRAY_SIZE(infPath) );\r\n    if (err != ERROR_SUCCESS) {\r\n        return  FALSE;\r\n    }\r\n    err = pfnWdfPreDeviceInstallEx(infPath, WDF_SECTION_NAME, &clientOptions);\r\n\r\n    if (err != ERROR_SUCCESS) {\r\n        if (err == ERROR_SUCCESS_REBOOT_REQUIRED) {\r\n            printf(\"System needs to be rebooted, before the driver installation can proceed.\\n\");\r\n        }\r\n\r\n        return  FALSE;\r\n    }\r\n\r\n    //\r\n    // Create a new a service object.\r\n    //\r\n\r\n    schService = CreateService(SchSCManager,           // handle of service control manager database\r\n                               DriverName,             // address of name of service to start\r\n                               DriverName,             // address of display name\r\n                               SERVICE_ALL_ACCESS,     // type of access to service\r\n                               SERVICE_KERNEL_DRIVER,  // type of service\r\n                               SERVICE_DEMAND_START,   // when to start service\r\n                               SERVICE_ERROR_NORMAL,   // severity if service fails to start\r\n                               ServiceExe,             // address of name of binary file\r\n                               NULL,                   // service does not belong to a group\r\n                               NULL,                   // no tag requested\r\n                               NULL,                   // no dependency names\r\n                               NULL,                   // use LocalSystem account\r\n                               NULL                    // no password for service account\r\n                               );\r\n\r\n    if (schService == NULL) {\r\n\r\n        err = GetLastError();\r\n\r\n        if (err == ERROR_SERVICE_EXISTS) {\r\n\r\n            //\r\n            // Ignore this error.\r\n            //\r\n\r\n            return TRUE;\r\n\r\n        } else {\r\n\r\n            printf(\"CreateService failed!  Error = %d \\n\", err );\r\n\r\n            //\r\n            // Indicate an error.\r\n            //\r\n\r\n            return  FALSE;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Close the service object.\r\n    //\r\n    CloseServiceHandle(schService);\r\n\r\n    //\r\n    // POST-INSTALL for WDF support\r\n    //\r\n    err = pfnWdfPostDeviceInstall( infPath, WDF_SECTION_NAME );\r\n\r\n    if (err != ERROR_SUCCESS) {\r\n        return  FALSE;\r\n    }\r\n\r\n    //\r\n    // Indicate success.\r\n    //\r\n\r\n    return TRUE;\r\n\r\n}   // InstallDriver\r\n\r\nBOOLEAN\r\nManageDriver(\r\n    IN LPCTSTR  DriverName,\r\n    IN LPCTSTR  ServiceName,\r\n    IN USHORT   Function\r\n    )\r\n{\r\n\r\n    SC_HANDLE   schSCManager;\r\n\r\n    BOOLEAN rCode = TRUE;\r\n\r\n    //\r\n    // Insure (somewhat) that the driver and service names are valid.\r\n    //\r\n\r\n    if (!DriverName || !ServiceName) {\r\n\r\n        printf(\"Invalid Driver or Service provided to ManageDriver() \\n\");\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Connect to the Service Control Manager and open the Services database.\r\n    //\r\n\r\n    schSCManager = OpenSCManager(NULL,                   // local machine\r\n                                 NULL,                   // local database\r\n                                 SC_MANAGER_ALL_ACCESS   // access required\r\n                                 );\r\n\r\n    if (!schSCManager) {\r\n\r\n        printf(\"Open SC Manager failed! Error = %d \\n\", GetLastError());\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Do the requested function.\r\n    //\r\n\r\n    switch( Function ) {\r\n\r\n        case DRIVER_FUNC_INSTALL:\r\n\r\n            //\r\n            // Install the driver service.\r\n            //\r\n\r\n            if (InstallDriver(schSCManager,\r\n                              DriverName,\r\n                              ServiceName\r\n                              )) {\r\n\r\n                //\r\n                // Start the driver service (i.e. start the driver).\r\n                //\r\n\r\n                rCode = StartDriver(schSCManager,\r\n                                    DriverName\r\n                                    );\r\n\r\n            } else {\r\n\r\n                //\r\n                // Indicate an error.\r\n                //\r\n\r\n                rCode = FALSE;\r\n            }\r\n\r\n            break;\r\n\r\n        case DRIVER_FUNC_REMOVE:\r\n\r\n            //\r\n            // Stop the driver.\r\n            //\r\n\r\n            StopDriver(schSCManager,\r\n                       DriverName\r\n                       );\r\n\r\n            //\r\n            // Remove the driver service.\r\n            //\r\n\r\n            RemoveDriver(schSCManager,\r\n                         DriverName\r\n                         );\r\n\r\n            //\r\n            // Ignore all errors.\r\n            //\r\n\r\n            rCode = TRUE;\r\n\r\n            break;\r\n\r\n        default:\r\n\r\n            printf(\"Unknown ManageDriver() function. \\n\");\r\n\r\n            rCode = FALSE;\r\n\r\n            break;\r\n    }\r\n\r\n    //\r\n    // Close handle to service control manager.\r\n    //\r\n    CloseServiceHandle(schSCManager);\r\n\r\n    return rCode;\r\n\r\n}   // ManageDriver\r\n\r\n\r\nBOOLEAN\r\nRemoveDriver(\r\n    IN SC_HANDLE    SchSCManager,\r\n    IN LPCTSTR      DriverName\r\n    )\r\n{\r\n    SC_HANDLE   schService;\r\n    BOOLEAN     rCode;\r\n    DWORD       err;\r\n    WCHAR      infPath[MAX_PATH];\r\n\r\n    err = GetPathToInf(infPath, ARRAY_SIZE(infPath) );\r\n    if (err != ERROR_SUCCESS) {\r\n        return  FALSE;\r\n    }\r\n\r\n    //\r\n    // PRE-REMOVE of WDF support\r\n    //\r\n    err = pfnWdfPreDeviceRemove( infPath, WDF_SECTION_NAME );\r\n\r\n    if (err != ERROR_SUCCESS) {\r\n        return  FALSE;\r\n    }\r\n\r\n    //\r\n    // Open the handle to the existing service.\r\n    //\r\n\r\n    schService = OpenService(SchSCManager,\r\n                             DriverName,\r\n                             SERVICE_ALL_ACCESS\r\n                             );\r\n\r\n    if (schService == NULL) {\r\n\r\n        printf(\"OpenService failed!  Error = %d \\n\", GetLastError());\r\n\r\n        //\r\n        // Indicate error.\r\n        //\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Mark the service for deletion from the service control manager database.\r\n    //\r\n\r\n    if (DeleteService(schService)) {\r\n\r\n        //\r\n        // Indicate success.\r\n        //\r\n\r\n        rCode = TRUE;\r\n\r\n    } else {\r\n\r\n        printf(\"DeleteService failed!  Error = %d \\n\", GetLastError());\r\n\r\n        //\r\n        // Indicate failure.  Fall through to properly close the service handle.\r\n        //\r\n\r\n        rCode = FALSE;\r\n    }\r\n\r\n    //\r\n    // Close the service object.\r\n    //\r\n    CloseServiceHandle(schService);\r\n\r\n    //\r\n    // POST-REMOVE of WDF support\r\n    //\r\n    err = pfnWdfPostDeviceRemove(infPath, WDF_SECTION_NAME );\r\n\r\n    if (err != ERROR_SUCCESS) {\r\n        rCode = FALSE;\r\n    }\r\n\r\n    return rCode;\r\n\r\n}   // RemoveDriver\r\n\r\n\r\n\r\nBOOLEAN\r\nStartDriver(\r\n    IN SC_HANDLE    SchSCManager,\r\n    IN LPCTSTR      DriverName\r\n    )\r\n{\r\n    SC_HANDLE   schService;\r\n    DWORD       err;\r\n    BOOL        ok;\r\n\r\n    //\r\n    // Open the handle to the existing service.\r\n    //\r\n    schService = OpenService(SchSCManager,\r\n                             DriverName,\r\n                             SERVICE_ALL_ACCESS\r\n                             );\r\n\r\n    if (schService == NULL) {\r\n        //\r\n        // Indicate failure.\r\n        //\r\n        printf(\"OpenService failed!  Error = %d\\n\", GetLastError());\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Start the execution of the service (i.e. start the driver).\r\n    //\r\n    ok = StartService( schService, 0, NULL );\r\n\r\n    if (!ok) {\r\n\r\n        err = GetLastError();\r\n\r\n        if (err == ERROR_SERVICE_ALREADY_RUNNING) {\r\n            //\r\n            // Ignore this error.\r\n            //\r\n            return TRUE;\r\n\r\n        } else {\r\n            //\r\n            // Indicate failure.\r\n            // Fall through to properly close the service handle.\r\n            //\r\n            printf(\"StartService failure! Error = %d\\n\", err );\r\n            return FALSE;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Close the service object.\r\n    //\r\n    CloseServiceHandle(schService);\r\n\r\n    return TRUE;\r\n\r\n}   // StartDriver\r\n\r\n\r\n\r\nBOOLEAN\r\nStopDriver(\r\n    IN SC_HANDLE    SchSCManager,\r\n    IN LPCTSTR      DriverName\r\n    )\r\n{\r\n    BOOLEAN         rCode = TRUE;\r\n    SC_HANDLE       schService;\r\n    SERVICE_STATUS  serviceStatus;\r\n\r\n    //\r\n    // Open the handle to the existing service.\r\n    //\r\n\r\n    schService = OpenService(SchSCManager,\r\n                             DriverName,\r\n                             SERVICE_ALL_ACCESS\r\n                             );\r\n\r\n    if (schService == NULL) {\r\n\r\n        printf(\"OpenService failed!  Error = %d \\n\", GetLastError());\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Request that the service stop.\r\n    //\r\n\r\n    if (ControlService(schService,\r\n                       SERVICE_CONTROL_STOP,\r\n                       &serviceStatus\r\n                       )) {\r\n\r\n        //\r\n        // Indicate success.\r\n        //\r\n\r\n        rCode = TRUE;\r\n\r\n    } else {\r\n\r\n        printf(\"ControlService failed!  Error = %d \\n\", GetLastError() );\r\n\r\n        //\r\n        // Indicate failure.  Fall through to properly close the service handle.\r\n        //\r\n\r\n        rCode = FALSE;\r\n    }\r\n\r\n    //\r\n    // Close the service object.\r\n    //\r\n    CloseServiceHandle (schService);\r\n\r\n    return rCode;\r\n\r\n}   //  StopDriver\r\n\r\n\r\n//\r\n// Caller must free returned pathname string.\r\n//\r\nPCHAR\r\nBuildDriversDirPath(\r\n    _In_ PSTR DriverName\r\n    )\r\n{\r\n    size_t  remain;\r\n    size_t  len;\r\n    PCHAR   dir;\r\n\r\n    if (!DriverName || strlen(DriverName) == 0) {\r\n        return NULL;\r\n    }\r\n\r\n    remain = MAX_PATH;\r\n\r\n    //\r\n    // Allocate string space\r\n    //\r\n    dir = (PCHAR) malloc( remain + 1 );\r\n\r\n    if (!dir) {\r\n        return NULL;\r\n    }\r\n\r\n    //\r\n    // Get the base windows directory path.\r\n    //\r\n    len = GetWindowsDirectory( dir, (UINT) remain );\r\n\r\n    if (len == 0 ||\r\n        (remain - len) < sizeof(SYSTEM32_DRIVERS)) {\r\n        free(dir);\r\n        return NULL;\r\n    }\r\n    remain -= len;\r\n\r\n    //\r\n    // Build dir to have \"%windir%\\System32\\Drivers\\<DriverName>\".\r\n    //\r\n    if (FAILED( StringCchCat(dir, remain, SYSTEM32_DRIVERS) )) {\r\n        free(dir);\r\n        return NULL;\r\n    }\r\n\r\n    remain -= sizeof(SYSTEM32_DRIVERS);\r\n    len    += sizeof(SYSTEM32_DRIVERS);\r\n    len    += strlen(DriverName);\r\n\r\n    if (remain < len) {\r\n        free(dir);\r\n        return NULL;\r\n    }\r\n\r\n    if (FAILED( StringCchCat(dir, remain, DriverName) )) {\r\n        free(dir);\r\n        return NULL;\r\n    }\r\n\r\n    dir[len] = '\\0';  // keeps prefast happy\r\n\r\n    return dir;\r\n}\r\n\r\n\r\nBOOLEAN\r\nSetupDriverName(\r\n    _Inout_updates_all_(BufferLength) PCHAR DriverLocation,\r\n    _In_ ULONG BufferLength\r\n    )\r\n{\r\n    HANDLE fileHandle;\r\n    DWORD  driverLocLen = 0;\r\n    BOOL   ok;\r\n    PCHAR  driversDir;\r\n\r\n    //\r\n    // Setup path name to driver file.\r\n    //\r\n    driverLocLen =\r\n        GetCurrentDirectory(BufferLength, DriverLocation);\r\n\r\n    if (!driverLocLen) {\r\n\r\n        printf(\"GetCurrentDirectory failed!  Error = %d \\n\",\r\n               GetLastError());\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    if (FAILED( StringCchCat(DriverLocation, BufferLength, \"\\\\\" DRIVER_NAME \".sys\") )) {\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Insure driver file is in the specified directory.\r\n    //\r\n    fileHandle = CreateFile( DriverLocation,\r\n                             GENERIC_READ,\r\n                             FILE_SHARE_READ,\r\n                             NULL,\r\n                             OPEN_EXISTING,\r\n                             FILE_ATTRIBUTE_NORMAL,\r\n                             NULL );\r\n\r\n    if (fileHandle == INVALID_HANDLE_VALUE) {\r\n        //\r\n        // Indicate failure.\r\n        //\r\n        printf(\"Driver: %s.SYS is not in the %s directory. \\n\",\r\n               DRIVER_NAME, DriverLocation );\r\n        return FALSE;\r\n    }\r\n\r\n    //\r\n    // Build %windir%\\System32\\Drivers\\<DRIVER_NAME> path.\r\n    // Copy the driver to %windir%\\system32\\drivers\r\n    //\r\n    driversDir = BuildDriversDirPath( DRIVER_NAME \".sys\" );\r\n\r\n    if (!driversDir) {\r\n        printf(\"BuildDriversDirPath failed!\\n\");\r\n        return FALSE;\r\n    }\r\n\r\n    ok = CopyFile( DriverLocation, driversDir, FALSE );\r\n\r\n    if(!ok) {\r\n        printf(\"CopyFile failed: error(%d) - \\\"%s\\\"\\n\",\r\n               GetLastError(), driversDir );\r\n        free(driversDir);\r\n        return FALSE;\r\n    }\r\n\r\n    if (FAILED( StringCchCopy(DriverLocation, BufferLength, driversDir) )) {\r\n        free(driversDir);\r\n        return FALSE;\r\n    }\r\n\r\n    free(driversDir);\r\n\r\n    //\r\n    // Close open file handle.\r\n    //\r\n    if (fileHandle) {\r\n        CloseHandle(fileHandle);\r\n    }\r\n\r\n    //\r\n    // Indicate success.\r\n    //\r\n    return TRUE;\r\n\r\n}   // SetupDriverName\r\n\r\n\r\nHMODULE\r\nLoadWdfCoInstaller(\r\n    VOID\r\n    )\r\n{\r\n    HMODULE library = NULL;\r\n    DWORD   error = ERROR_SUCCESS;\r\n    CHAR   szCurDir[MAX_PATH];\r\n    CHAR   tempCoinstallerName[MAX_PATH];\r\n    PCHAR  coinstallerVersion;\r\n\r\n    do {\r\n\r\n        if (GetCurrentDirectory(MAX_PATH, szCurDir) == 0) {\r\n\r\n            printf(\"GetCurrentDirectory failed!  Error = %d \\n\", GetLastError());\r\n            break;\r\n        }\r\n        coinstallerVersion = GetCoinstallerVersion();\r\n        if (FAILED( StringCchPrintf(tempCoinstallerName,\r\n                                  MAX_PATH,\r\n                                  \"\\\\WdfCoInstaller%s.dll\",\r\n                                  coinstallerVersion) )) {\r\n            break;\r\n        }\r\n        if (FAILED( StringCchCat(szCurDir, MAX_PATH, tempCoinstallerName) )) {\r\n            break;\r\n        }\r\n\r\n        library = LoadLibrary(szCurDir);\r\n\r\n        if (library == NULL) {\r\n            error = GetLastError();\r\n            printf(\"LoadLibrary(%s) failed: %d\\n\", szCurDir, error);\r\n            break;\r\n        }\r\n\r\n        pfnWdfPreDeviceInstallEx =\r\n            (PFN_WDFPREDEVICEINSTALLEX) GetProcAddress( library, \"WdfPreDeviceInstallEx\" );\r\n\r\n        if (pfnWdfPreDeviceInstallEx == NULL) {\r\n            error = GetLastError();\r\n            printf(\"GetProcAddress(\\\"WdfPreDeviceInstallEx\\\") failed: %d\\n\", error);\r\n            return NULL;\r\n        }\r\n\r\n        pfnWdfPostDeviceInstall =\r\n            (PFN_WDFPOSTDEVICEINSTALL) GetProcAddress( library, \"WdfPostDeviceInstall\" );\r\n\r\n        if (pfnWdfPostDeviceInstall == NULL) {\r\n            error = GetLastError();\r\n            printf(\"GetProcAddress(\\\"WdfPostDeviceInstall\\\") failed: %d\\n\", error);\r\n            return NULL;\r\n        }\r\n\r\n        pfnWdfPreDeviceRemove =\r\n            (PFN_WDFPREDEVICEREMOVE) GetProcAddress( library, \"WdfPreDeviceRemove\" );\r\n\r\n        if (pfnWdfPreDeviceRemove == NULL) {\r\n            error = GetLastError();\r\n            printf(\"GetProcAddress(\\\"WdfPreDeviceRemove\\\") failed: %d\\n\", error);\r\n            return NULL;\r\n        }\r\n\r\n        pfnWdfPostDeviceRemove =\r\n            (PFN_WDFPREDEVICEREMOVE) GetProcAddress( library, \"WdfPostDeviceRemove\" );\r\n\r\n        if (pfnWdfPostDeviceRemove == NULL) {\r\n            error = GetLastError();\r\n            printf(\"GetProcAddress(\\\"WdfPostDeviceRemove\\\") failed: %d\\n\", error);\r\n            return NULL;\r\n        }\r\n\r\n    } WHILE (0);\r\n\r\n    if (error != ERROR_SUCCESS) {\r\n        if (library) {\r\n            FreeLibrary( library );\r\n        }\r\n        library = NULL;\r\n    }\r\n\r\n    return library;\r\n}\r\n\r\n\r\nVOID\r\nUnloadWdfCoInstaller(\r\n    HMODULE Library\r\n    )\r\n{\r\n    if (Library) {\r\n        FreeLibrary( Library );\r\n    }\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/exe/nonpnp.inf",
    "content": "[Version]\nSignature=\"$WINDOWS NT$\"\n\n[nonpnp.NT.Wdf]\nKmdfService = nonpnp, nonpnp_Service_kmdfInst\n\n[nonpnp_Service_kmdfInst]\nKmdfLibraryVersion = 1.11\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/exe/testapp.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\n\r\nModule Name:\r\n\r\n    testapp.c\r\n\r\nAbstract:\r\n\r\n    Purpose of this app to test the NONPNP sample driver. The app\r\n    makes four different ioctl calls to test all the buffer types, write\r\n    some random buffer content to a file created by the driver in \\SystemRoot\\Temp\r\n    directory, and reads the same file and matches the content.\r\n    If -l option is specified, it does the write and read operation in a loop\r\n    until the app is terminated by pressing ^C.\r\n\r\n    Make sure you have the \\SystemRoot\\Temp directory exists before you run the test.\r\n\r\nEnvironment:\r\n\r\n    Win32 console application.\r\n\r\n--*/\r\n\r\n\r\n#include <DriverSpecs.h>\r\n_Analysis_mode_(_Analysis_code_type_user_code_)\r\n\r\n#include <windows.h>\r\n\r\n#pragma warning(disable:4201)  // nameless struct/union\r\n#include <winioctl.h>\r\n#pragma warning(default:4201)\r\n\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <time.h>\r\n#include <limits.h>\r\n#include <strsafe.h>\r\n#include \"public.h\"\r\n\r\n\r\nBOOLEAN\r\nManageDriver(\r\n    IN LPCTSTR  DriverName,\r\n    IN LPCTSTR  ServiceName,\r\n    IN USHORT   Function\r\n    );\r\n\r\nHMODULE\r\nLoadWdfCoInstaller(\r\n    VOID\r\n    );\r\n\r\nVOID\r\nUnloadWdfCoInstaller(\r\n    HMODULE Library\r\n    );\r\n\r\nBOOLEAN\r\nSetupDriverName(\r\n    _Inout_updates_all_(BufferLength) PCHAR DriverLocation,\r\n    _In_ ULONG BufferLength\r\n    );\r\n\r\nBOOLEAN\r\nDoFileReadWrite(\r\n    HANDLE HDevice\r\n    );\r\n\r\nVOID\r\nDoIoctls(\r\n    HANDLE hDevice\r\n    );\r\n\r\n// for example, WDF 1.9 is \"01009\". the size 6 includes the ending NULL marker\r\n//\r\n#define MAX_VERSION_SIZE 6\r\n\r\nCHAR G_coInstallerVersion[MAX_VERSION_SIZE] = {0};\r\nBOOLEAN  G_fLoop = FALSE;\r\nBOOL G_versionSpecified = FALSE;\r\n\r\n\r\n\r\n//-----------------------------------------------------------------------------\r\n// 4127 -- Conditional Expression is Constant warning\r\n//-----------------------------------------------------------------------------\r\n#define WHILE(constant) \\\r\n__pragma(warning(disable: 4127)) while(constant); __pragma(warning(default: 4127))\r\n\r\n\r\n#define USAGE  \\\r\n\"Usage: nonpnpapp <-V version> <-l> \\n\" \\\r\n       \" -V version  {if no version is specified the version specified in the build environment will be used.}\\n\" \\\r\n       \"    The version is the version of the KMDF coinstaller to use \\n\"  \\\r\n       \"    The format of version  is MMmmm where MM -- major #, mmm - serial# \\n\" \\\r\n       \" -l  { option to continuously read & write to the file} \\n\"\r\n\r\nBOOL\r\nValidateCoinstallerVersion(\r\n    _In_ PSTR Version\r\n    )\r\n{   BOOL ok = FALSE;\r\n    INT i;\r\n\r\n    for(i= 0; i<MAX_VERSION_SIZE ;i++){\r\n        if( ! IsCharAlphaNumericA(Version[i])) {\r\n            break;\r\n        }\r\n    }\r\n    if (i == (MAX_VERSION_SIZE -sizeof(CHAR))) {\r\n        ok = TRUE;\r\n    }\r\n    return ok;\r\n}\r\n\r\nLONG\r\nParse(\r\n    _In_ int argc,\r\n    _In_reads_(argc) char *argv[]\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    Called by main() to parse command line parms\r\n\r\nArguments:\r\n\r\n    argc and argv that was passed to main()\r\n\r\nReturn Value:\r\n\r\n    Sets global flags as per user function request\r\n\r\n--*/\r\n{\r\n    int i;\r\n    BOOL ok;\r\n    LONG error = ERROR_SUCCESS;\r\n\r\n    for (i=0; i<argc; i++) {\r\n        if (argv[i][0] == '-' ||\r\n            argv[i][0] == '/') {\r\n            switch(argv[i][1]) {\r\n            case 'V':\r\n            case 'v':\r\n                if (( (i+1 < argc ) &&\r\n                      ( argv[i+1][0] != '-' && argv[i+1][0] != '/'))) {\r\n                    //\r\n                    // use version in commandline\r\n                    //\r\n                    i++;\r\n                    ok = ValidateCoinstallerVersion(argv[i]);\r\n                    if (!ok) {\r\n                        printf(\"Not a valid format for coinstaller version\\n\"\r\n                               \"It should be characters between A-Z, a-z , 0-9\\n\"\r\n                               \"The version format is MMmmm where MM -- major #, mmm - serial#\");\r\n                        error = ERROR_INVALID_PARAMETER;\r\n                        break;\r\n                    }\r\n                    if (FAILED( StringCchCopy(G_coInstallerVersion,\r\n                                              MAX_VERSION_SIZE,\r\n                                              argv[i]) )) {\r\n                        break;\r\n                    }\r\n                    G_versionSpecified = TRUE;\r\n\r\n                }\r\n                else{\r\n                    printf(USAGE);\r\n                    error = ERROR_INVALID_PARAMETER;\r\n                }\r\n                break;\r\n            case 'l':\r\n            case 'L':\r\n                G_fLoop = TRUE;\r\n                break;\r\n            default:\r\n                printf(USAGE);\r\n                error = ERROR_INVALID_PARAMETER;\r\n\r\n            }\r\n        }\r\n    }\r\n    return error;\r\n}\r\n\r\nPCHAR\r\nGetCoinstallerVersion(\r\n    VOID\r\n    )\r\n{\r\n    if (!G_versionSpecified &&\r\n        FAILED( StringCchPrintf(G_coInstallerVersion,\r\n                                MAX_VERSION_SIZE,\r\n                                \"%02d%03d\",    // for example, \"01009\"\r\n                                KMDF_VERSION_MAJOR,\r\n                                KMDF_VERSION_MINOR)))\r\n    {\r\n        printf(\"StringCchCopy failed with error \\n\");\r\n    }\r\n\r\n    return (PCHAR)&G_coInstallerVersion;\r\n}\r\n\r\nVOID __cdecl\r\nmain(\r\n    _In_ INT argc,\r\n    _In_reads_(argc) PCHAR argv[]\r\n    )\r\n{\r\n    HANDLE   hDevice;\r\n    DWORD    errNum = 0;\r\n    CHAR     driverLocation [MAX_PATH];\r\n    BOOL     ok;\r\n    HMODULE  library = NULL;\r\n    LONG     error;\r\n    PCHAR    coinstallerVersion;\r\n\r\n    //\r\n    // Parse command line args\r\n    //   -l     -- loop option\r\n    //\r\n    if ( argc > 1 ) {// give usage if invoked with no parms\r\n        error = Parse(argc, argv);\r\n        if (error != ERROR_SUCCESS) {\r\n            return;\r\n        }\r\n    }\r\n\r\n    if (!G_versionSpecified ) {\r\n        coinstallerVersion = GetCoinstallerVersion();\r\n\r\n        //\r\n        // if no version is specified or an invalid one is specified use default version\r\n        //\r\n        printf(\"No version specified. Using default version:%s\\n\",\r\n               coinstallerVersion);\r\n\r\n    } else {\r\n        coinstallerVersion = (PCHAR)&G_coInstallerVersion;\r\n    }\r\n\r\n    //\r\n    // open the device\r\n    //\r\n    hDevice = CreateFile(DEVICE_NAME,\r\n                         GENERIC_READ | GENERIC_WRITE,\r\n                         0,\r\n                         NULL,\r\n                         CREATE_ALWAYS,\r\n                         FILE_ATTRIBUTE_NORMAL,\r\n                         NULL);\r\n\r\n    if(hDevice == INVALID_HANDLE_VALUE) {\r\n\r\n        errNum = GetLastError();\r\n\r\n        if (!(errNum == ERROR_FILE_NOT_FOUND ||\r\n                errNum == ERROR_PATH_NOT_FOUND)) {\r\n\r\n            printf(\"CreateFile failed!  ERROR_FILE_NOT_FOUND = %d\\n\",\r\n                   errNum);\r\n            return ;\r\n        }\r\n\r\n        //\r\n        // Load WdfCoInstaller.dll.\r\n        //\r\n        library = LoadWdfCoInstaller();\r\n\r\n        if (library == NULL) {\r\n            printf(\"The WdfCoInstaller%s.dll library needs to be \"\r\n                   \"in same directory as nonpnpapp.exe\\n\", coinstallerVersion);\r\n            return;\r\n        }\r\n\r\n        //\r\n        // The driver is not started yet so let us the install the driver.\r\n        // First setup full path to driver name.\r\n        //\r\n        ok = SetupDriverName( driverLocation, MAX_PATH );\r\n\r\n        if (!ok) {\r\n            return ;\r\n        }\r\n\r\n        ok = ManageDriver( DRIVER_NAME,\r\n                           driverLocation,\r\n                           DRIVER_FUNC_INSTALL );\r\n\r\n        if (!ok) {\r\n\r\n            printf(\"Unable to install driver. \\n\");\r\n\r\n            //\r\n            // Error - remove driver.\r\n            //\r\n            ManageDriver( DRIVER_NAME,\r\n                          driverLocation,\r\n                          DRIVER_FUNC_REMOVE );\r\n            return;\r\n        }\r\n\r\n        hDevice = CreateFile( DEVICE_NAME,\r\n                              GENERIC_READ | GENERIC_WRITE,\r\n                              0,\r\n                              NULL,\r\n                              CREATE_ALWAYS,\r\n                              FILE_ATTRIBUTE_NORMAL,\r\n                              NULL );\r\n\r\n        if (hDevice == INVALID_HANDLE_VALUE) {\r\n            printf ( \"Error: CreatFile Failed : %d\\n\", GetLastError());\r\n            return;\r\n        }\r\n    }\r\n\r\n    DoIoctls(hDevice);\r\n\r\n    do {\r\n\r\n        if(!DoFileReadWrite(hDevice)) {\r\n            break;\r\n        }\r\n\r\n        if(!G_fLoop) {\r\n            break;\r\n        }\r\n        Sleep(1000); // sleep for 1 sec.\r\n\r\n    } WHILE (TRUE);\r\n\r\n    //\r\n    // Close the handle to the device before unloading the driver.\r\n    //\r\n    CloseHandle ( hDevice );\r\n\r\n    //\r\n    // Unload the driver.  Ignore any errors.\r\n    //\r\n    ManageDriver( DRIVER_NAME,\r\n                  driverLocation,\r\n                  DRIVER_FUNC_REMOVE );\r\n\r\n    //\r\n    // Unload WdfCoInstaller.dll\r\n    //\r\n    if ( library ) {\r\n        UnloadWdfCoInstaller( library );\r\n    }\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nDoIoctls(\r\n    HANDLE hDevice\r\n    )\r\n{\r\n    char OutputBuffer[100];\r\n    char InputBuffer[200];\r\n    BOOL bRc;\r\n    ULONG bytesReturned;\r\n\r\n    //\r\n    // Printing Input & Output buffer pointers and size\r\n    //\r\n\r\n    printf(\"InputBuffer Pointer = %p, BufLength = %Id\\n\", InputBuffer,\r\n                        sizeof(InputBuffer));\r\n    printf(\"OutputBuffer Pointer = %p BufLength = %Id\\n\", OutputBuffer,\r\n                                sizeof(OutputBuffer));\r\n    //\r\n    // Performing METHOD_BUFFERED\r\n    //\r\n\r\n    if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),\r\n        \"this String is from User Application; using METHOD_BUFFERED\"))){\r\n        return;\r\n    }\r\n\r\n    printf(\"\\nCalling DeviceIoControl METHOD_BUFFERED:\\n\");\r\n\r\n    memset(OutputBuffer, 0, sizeof(OutputBuffer));\r\n\r\n    bRc = DeviceIoControl ( hDevice,\r\n                            (DWORD) IOCTL_NONPNP_METHOD_BUFFERED,\r\n                            InputBuffer,\r\n                            (DWORD) strlen( InputBuffer )+1,\r\n                            OutputBuffer,\r\n                            sizeof( OutputBuffer),\r\n                            &bytesReturned,\r\n                            NULL\r\n                            );\r\n\r\n    if ( !bRc )\r\n    {\r\n        printf ( \"Error in DeviceIoControl : %d\", GetLastError());\r\n        return;\r\n\r\n    }\r\n    printf(\"    OutBuffer (%d): %s\\n\", bytesReturned, OutputBuffer);\r\n\r\n\r\n    //\r\n    // Performing METHOD_NIETHER\r\n    //\r\n\r\n    printf(\"\\nCalling DeviceIoControl METHOD_NEITHER\\n\");\r\n\r\n    if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),\r\n               \"this String is from User Application; using METHOD_NEITHER\"))) {\r\n        return;\r\n    }\r\n\r\n    memset(OutputBuffer, 0, sizeof(OutputBuffer));\r\n\r\n    bRc = DeviceIoControl ( hDevice,\r\n                            (DWORD) IOCTL_NONPNP_METHOD_NEITHER,\r\n                            InputBuffer,\r\n                            (DWORD) strlen( InputBuffer )+1,\r\n                            OutputBuffer,\r\n                            sizeof( OutputBuffer),\r\n                            &bytesReturned,\r\n                            NULL\r\n                            );\r\n\r\n    if ( !bRc )\r\n    {\r\n        printf ( \"Error in DeviceIoControl : %d\\n\", GetLastError());\r\n        return;\r\n\r\n    }\r\n\r\n    printf(\"    OutBuffer (%d): %s\\n\", bytesReturned, OutputBuffer);\r\n\r\n    //\r\n    // Performing METHOD_IN_DIRECT\r\n    //\r\n\r\n    printf(\"\\nCalling DeviceIoControl METHOD_IN_DIRECT\\n\");\r\n\r\n    if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),\r\n               \"this String is from User Application; using METHOD_IN_DIRECT\"))) {\r\n        return;\r\n    }\r\n\r\n    if(FAILED(StringCchCopy(OutputBuffer, sizeof(OutputBuffer),\r\n               \"This String is from User Application in OutBuffer; using METHOD_IN_DIRECT\"))) {\r\n        return;\r\n    }\r\n\r\n    bRc = DeviceIoControl ( hDevice,\r\n                            (DWORD) IOCTL_NONPNP_METHOD_IN_DIRECT,\r\n                            InputBuffer,\r\n                            (DWORD) strlen( InputBuffer )+1,\r\n                            OutputBuffer,\r\n                            sizeof( OutputBuffer),\r\n                            &bytesReturned,\r\n                            NULL\r\n                            );\r\n\r\n    if ( !bRc )\r\n    {\r\n        printf ( \"Error in DeviceIoControl : : %d\", GetLastError());\r\n        return;\r\n    }\r\n\r\n    printf(\"    Number of bytes transfered from OutBuffer: %d\\n\",\r\n                                    bytesReturned);\r\n\r\n    //\r\n    // Performing METHOD_OUT_DIRECT\r\n    //\r\n\r\n    printf(\"\\nCalling DeviceIoControl METHOD_OUT_DIRECT\\n\");\r\n    if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),\r\n               \"this String is from User Application; using METHOD_OUT_DIRECT\"))){\r\n        return;\r\n    }\r\n\r\n    memset(OutputBuffer, 0, sizeof(OutputBuffer));\r\n\r\n    bRc = DeviceIoControl ( hDevice,\r\n                            (DWORD) IOCTL_NONPNP_METHOD_OUT_DIRECT,\r\n                            InputBuffer,\r\n                            (DWORD) strlen( InputBuffer )+1,\r\n                            OutputBuffer,\r\n                            sizeof( OutputBuffer),\r\n                            &bytesReturned,\r\n                            NULL\r\n                            );\r\n\r\n    if ( !bRc )\r\n    {\r\n        printf ( \"Error in DeviceIoControl : : %d\", GetLastError());\r\n        return;\r\n    }\r\n\r\n    printf(\"    OutBuffer (%d): %s\\n\", bytesReturned, OutputBuffer);\r\n\r\n    return;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nDoFileReadWrite(\r\n    HANDLE HDevice\r\n    )\r\n{\r\n    ULONG bufLength, index;\r\n    PUCHAR readBuf = NULL;\r\n    PUCHAR writeBuf = NULL;\r\n    BOOLEAN ret;\r\n    ULONG   bytesWritten, bytesRead;\r\n\r\n    //\r\n    // Seed the random-number generator with current time so that\r\n    // the numbers will be different every time we run.\r\n    //\r\n    srand( (unsigned)time( NULL ) );\r\n\r\n    //\r\n    // rand function returns a pseudorandom integer in the range 0 to RAND_MAX\r\n    // (0x7fff)\r\n    //\r\n    bufLength = rand();\r\n    //\r\n    // Try until the bufLength is not zero.\r\n    //\r\n    while(bufLength == 0) {\r\n        bufLength = rand();\r\n    }\r\n\r\n    //\r\n    // Allocate a buffer of that size to use for write operation.\r\n    //\r\n    writeBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufLength);\r\n    if(!writeBuf) {\r\n        ret = FALSE;\r\n        goto End;\r\n    }\r\n    //\r\n    // Fill the buffer with randon number less than UCHAR_MAX.\r\n    //\r\n    index = bufLength;\r\n    while(index){\r\n        writeBuf[index-1] = (UCHAR) rand() % UCHAR_MAX;\r\n        index--;\r\n    }\r\n\r\n    printf(\"Write %d bytes to file\\n\", bufLength);\r\n\r\n    //\r\n    // Tell the driver to write the buffer content to the file from the\r\n    // begining of the file.\r\n    //\r\n\r\n    if (!WriteFile(HDevice,\r\n                  writeBuf,\r\n                  bufLength,\r\n                  &bytesWritten,\r\n                  NULL)) {\r\n\r\n        printf(\"ReadFile failed with error 0x%x\\n\", GetLastError());\r\n\r\n        ret = FALSE;\r\n        goto End;\r\n\r\n    }\r\n\r\n    //\r\n    // Allocate another buffer of same size.\r\n    //\r\n    readBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufLength);\r\n    if(!readBuf) {\r\n\r\n        ret = FALSE;\r\n        goto End;\r\n    }\r\n\r\n    printf(\"Read %d bytes from the same file\\n\", bufLength);\r\n\r\n    //\r\n    // Tell the driver to read the file from the begining.\r\n    //\r\n    if (!ReadFile(HDevice,\r\n                  readBuf,\r\n                  bufLength,\r\n                  &bytesRead,\r\n                  NULL)) {\r\n\r\n        printf(\"Error: ReadFile failed with error 0x%x\\n\", GetLastError());\r\n\r\n        ret = FALSE;\r\n        goto End;\r\n\r\n    }\r\n\r\n    //\r\n    // Now compare the readBuf and writeBuf content. They should be the same.\r\n    //\r\n\r\n    if(bytesRead != bytesWritten) {\r\n        printf(\"bytesRead(%d) != bytesWritten(%d)\\n\", bytesRead, bytesWritten);\r\n        ret = FALSE;\r\n        goto End;\r\n    }\r\n\r\n    if(memcmp(readBuf, writeBuf, bufLength) != 0){\r\n        printf(\"Error: ReadBuf and WriteBuf contents are not the same\\n\");\r\n        ret = FALSE;\r\n        goto End;\r\n    }\r\n\r\n    ret = TRUE;\r\n\r\nEnd:\r\n\r\n    if(readBuf){\r\n        HeapFree (GetProcessHeap(), 0, readBuf);\r\n    }\r\n\r\n    if(writeBuf){\r\n        HeapFree (GetProcessHeap(), 0, writeBuf);\r\n    }\r\n\r\n    return ret;\r\n\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/localwpp.ini",
    "content": "//\n// This defines how to log a len/buffer pair.\n// This function should be in trace.h\n//\n\nDEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, xstr_t, ItemHEXDump,\"s\", _HEX_, 0,2);\n\n// DEFINE_CPLX_TYPE(\n// name,             // i.e. HEXDUMP         // %!HEXDUMP!\n// macro,            // i.e. WPP_LOGHEXDUMP  // Marshalling macro, defined in trace.h\n// structure,        // i.e. xstr_t          // Argument type (structure to be created by above macro)\n// item type,        // i.e. ItemHEXDump     // MOF type that TracePrt can understand\n// format specifier, // i.e. \"s\"             // a format specifier that TracePrt can understand\n// ????              // i.e. _HEX_           // Type signature (becomes a part of function name)\n// ????              // i.e. 0               // Weight (0 is variable data length)\n// ????              // i.e. 2               // Slots used by this entry (optional, 1 default)\n// )\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/public.h",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\n\r\nModule Name:\r\n\r\n    PUBLIC.H\r\n\r\nAbstract:\r\n\r\n\r\n    Defines the IOCTL codes that will be used by this driver.  The IOCTL code\r\n    contains a command identifier, plus other information about the device,\r\n    the type of access with which the file must have been opened,\r\n    and the type of buffering.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode only.\r\n\r\n--*/\r\n\r\n//\r\n// Device type           -- in the \"User Defined\" range.\"\r\n//\r\n#define FILEIO_TYPE 40001\r\n//\r\n// The IOCTL function codes from 0x800 to 0xFFF are for customer use.\r\n//\r\n#define IOCTL_NONPNP_METHOD_IN_DIRECT \\\r\n    CTL_CODE( FILEIO_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS  )\r\n\r\n#define IOCTL_NONPNP_METHOD_OUT_DIRECT \\\r\n    CTL_CODE( FILEIO_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS  )\r\n\r\n#define IOCTL_NONPNP_METHOD_BUFFERED \\\r\n    CTL_CODE( FILEIO_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS  )\r\n\r\n#define IOCTL_NONPNP_METHOD_NEITHER \\\r\n    CTL_CODE( FILEIO_TYPE, 0x903, METHOD_NEITHER , FILE_ANY_ACCESS  )\r\n\r\n\r\n#define DRIVER_FUNC_INSTALL     0x01\r\n#define DRIVER_FUNC_REMOVE      0x02\r\n\r\n#define DRIVER_NAME       \"NONPNP\"\r\n#define DEVICE_NAME       \"\\\\\\\\.\\\\NONPNP\\\\nonpnpsamp.log\"\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/ioctl/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_includedirs(\".\")\n\ntarget(\"nonpnp\")\n    add_rules(\"wdk.env.kmdf\", \"wdk.driver\")\n    add_values(\"wdk.tracewpp.flags\", \"-func:TraceEvents(LEVEL,FLAGS,MSG,...)\", \"-func:Hexdump((LEVEL,FLAGS,MSG,...))\")\n    add_files(\"driver/*.c\", {rules = \"wdk.tracewpp\"})\n    add_files(\"driver/*.rc\")\n\ntarget(\"app\")\n    add_rules(\"wdk.env.kmdf\", \"wdk.binary\")\n    add_files(\"exe/*.c\")\n    add_files(\"exe/*.inf\")\n\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/error.c",
    "content": "/*++\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    error.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to error\r\n    operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"error.tmh\"\r\n#endif\r\n\r\n\r\nVOID\r\nSerialCommError(\r\n    IN WDFDPC Dpc\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is invoked at dpc level to in response to\r\n    a comm error.  All comm errors complete all read and writes\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT,\r\n                     \">SerialCommError(%p)\\n\", Extension);\r\n\r\n    SerialFlushRequests(\r\n        Extension->WriteQueue,\r\n        &Extension->CurrentWriteRequest\r\n        );\r\n\r\n    SerialFlushRequests(\r\n        Extension->ReadQueue,\r\n        &Extension->CurrentReadRequest\r\n        );\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT,\r\n                     \"<SerialCommError\\n\");\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/flush.c",
    "content": "/*++\r\n\r\nCopyright (c) 1991, 1992, 1993 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    flush.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to flush\r\n    operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"flush.tmh\"\r\n#endif\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGE, SerialFlush)\r\n#endif\r\n\r\n#pragma warning(push)\r\n#pragma warning(disable:28118) // this callback will run at IRQL=PASSIVE_LEVEL\r\n_Use_decl_annotations_\r\nNTSTATUS\r\nSerialFlush(\r\n    WDFDEVICE Device,\r\n    PIRP Irp\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the dispatch routine for flush.  Flushing works by placing\r\n    this request in the write queue.  When this request reaches the\r\n    front of the write queue we simply complete it since this implies\r\n    that all previous writes have completed.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Pointer to the device object for this device\r\n\r\n    Irp - Pointer to the IRP for the current request\r\n\r\nReturn Value:\r\n\r\n    Could return status success, cancelled, or pending.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension;\r\n\r\n    extension = SerialGetDeviceExtension(Device);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialFlush(%p, %p)\\n\", Device, Irp);\r\n\r\n    PAGED_CODE();\r\n\r\n    WdfIoQueueStopSynchronously(extension->WriteQueue);\r\n    //\r\n    // Flush is done - restart the queue\r\n    //\r\n    WdfIoQueueStart(extension->WriteQueue);\r\n\r\n    Irp->IoStatus.Information = 0L;\r\n    Irp->IoStatus.Status = STATUS_SUCCESS;\r\n    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialFlush\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n }\r\n#pragma warning(pop) // enable 28118 again\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/immediat.c",
    "content": "/*++\r\n\r\nCopyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    immediat.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to transmit\r\n    immediate character operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"immediat.tmh\"\r\n#endif\r\n\r\n\r\nVOID\r\nSerialGetNextImmediate(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    IN WDFREQUEST *NewRequest,\r\n    IN BOOLEAN CompleteCurrent,\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nEVT_WDF_REQUEST_CANCEL SerialCancelImmediate;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveImmediateToIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabImmediateFromIsr;\r\n\r\n\r\nVOID\r\nSerialStartImmediate(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will calculate the timeouts needed for the\r\n    write.  It will then hand the request off to the isr.  It\r\n    will need to be careful incase the request has been canceled.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the serial device extension.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    LARGE_INTEGER TotalTime = {0};\r\n    BOOLEAN UseATimer;\r\n    SERIAL_TIMEOUTS Timeouts;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \">SerialStartImmediate(%p)\\n\",\r\n                     Extension);\r\n\r\n    UseATimer = FALSE;\r\n    reqContext->Status = STATUS_PENDING;\r\n\r\n    //\r\n    // Calculate the timeout value needed for the\r\n    // request.  Note that the values stored in the\r\n    // timeout record are in milliseconds.  Note that\r\n    // if the timeout values are zero then we won't start\r\n    // the timer.\r\n    //\r\n\r\n    Timeouts = Extension->Timeouts;\r\n\r\n    if (Timeouts.WriteTotalTimeoutConstant ||\r\n        Timeouts.WriteTotalTimeoutMultiplier) {\r\n\r\n        UseATimer = TRUE;\r\n\r\n        //\r\n        // We have some timer values to calculate.\r\n        //\r\n\r\n        TotalTime.QuadPart\r\n           = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);\r\n\r\n        TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;\r\n\r\n        TotalTime.QuadPart *= -10000;\r\n\r\n    }\r\n\r\n    //\r\n    // As the request might be going to the isr, this is a good time\r\n    // to initialize the reference count.\r\n    //\r\n\r\n    SERIAL_INIT_REFERENCE(reqContext);\r\n\r\n     //\r\n     // We give the request to to the isr to write out.\r\n     // We set a cancel routine that knows how to\r\n     // grab the current write away from the isr.\r\n     //\r\n    SerialSetCancelRoutine(Extension->CurrentImmediateRequest,\r\n                                    SerialCancelImmediate);\r\n\r\n    if (UseATimer) {\r\n        BOOLEAN result;\r\n\r\n        result = SerialSetTimer(\r\n            Extension->ImmediateTotalTimer,\r\n            TotalTime\r\n            );\r\n\r\n        if(result == FALSE) {\r\n            //\r\n            // Since the timer knows about the request we increment\r\n            // the reference count.\r\n            //\r\n\r\n            SERIAL_SET_REFERENCE(\r\n                reqContext,\r\n                SERIAL_REF_TOTAL_TIMER\r\n                );\r\n        }\r\n    }\r\n\r\n    WdfInterruptSynchronize(\r\n        Extension->WdfInterrupt,\r\n        SerialGiveImmediateToIsr,\r\n        Extension\r\n        );\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"<SerialStartImmediate\\n\");\r\n\r\n}\r\n\r\nVOID\r\nSerialCompleteImmediate(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \">SerialCompleteImmediate(%p)\\n\",\r\n                     Extension);\r\n\r\n    SerialTryToCompleteCurrent(\r\n        Extension,\r\n        NULL,\r\n        STATUS_SUCCESS,\r\n        &Extension->CurrentImmediateRequest,\r\n        NULL,\r\n        NULL,\r\n        Extension->ImmediateTotalTimer,\r\n        NULL,\r\n        SerialGetNextImmediate,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \"<SerialCompleteImmediate\\n\");\r\n\r\n}\r\n\r\nVOID\r\nSerialTimeoutImmediate(\r\n    IN WDFTIMER Timer\r\n    )\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \">SerialTimeoutImmediate(%p)\\n\",\r\n                     Extension);\r\n\r\n    SerialTryToCompleteCurrent(\r\n        Extension,\r\n        SerialGrabImmediateFromIsr,\r\n        STATUS_TIMEOUT,\r\n        &Extension->CurrentImmediateRequest,\r\n        NULL,\r\n        NULL,\r\n        Extension->ImmediateTotalTimer,\r\n        NULL,\r\n        SerialGetNextImmediate,\r\n        SERIAL_REF_TOTAL_TIMER\r\n        );\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \"<SerialTimeoutImmediate\\n\");\r\n}\r\n\r\nVOID\r\nSerialGetNextImmediate(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    IN WDFREQUEST *NewRequest,\r\n    IN BOOLEAN CompleteCurrent,\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to complete the current immediate\r\n    request.  Even though the current immediate will always\r\n    be completed and there is no queue associated with it,\r\n    we use this routine so that we can try to satisfy\r\n    a wait for transmit queue empty event.\r\n\r\nArguments:\r\n\r\n    CurrentOpRequest - Pointer to the pointer that points to the\r\n                   current write request.  This should point\r\n                   to CurrentImmediateRequest.\r\n\r\n    QueueToProcess - Always NULL.\r\n\r\n    NewRequest - Always NULL on exit to this routine.\r\n\r\n    CompleteCurrent - Should always be true for this routine.\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    WDFREQUEST oldRequest = *CurrentOpRequest;\r\n    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(oldRequest);\r\n\r\n    UNREFERENCED_PARAMETER(QueueToProcess);\r\n    UNREFERENCED_PARAMETER(CompleteCurrent);\r\n\r\n\r\n    ASSERT(Extension->TotalCharsQueued >= 1);\r\n    Extension->TotalCharsQueued--;\r\n\r\n    *CurrentOpRequest = NULL;\r\n    *NewRequest = NULL;\r\n     WdfInterruptSynchronize(\r\n        Extension->WdfInterrupt,\r\n        SerialProcessEmptyTransmit,\r\n        Extension\r\n        );\r\n\r\n    SerialCompleteRequest(oldRequest, reqContext->Status, reqContext->Information);\r\n}\r\n\r\nVOID\r\nSerialCancelImmediate(\r\n    IN WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to cancel a request that is waiting on\r\n    a comm event.\r\n\r\nArguments:\r\n\r\n    Request - Pointer to the WDFREQUEST for the current request\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));\r\n\r\n    UNREFERENCED_PARAMETER(Request);\r\n\r\n    Extension = SerialGetDeviceExtension(device);\r\n\r\n    SerialTryToCompleteCurrent(\r\n        Extension,\r\n        SerialGrabImmediateFromIsr,\r\n        STATUS_CANCELLED,\r\n        &Extension->CurrentImmediateRequest,\r\n        NULL,\r\n        NULL,\r\n        Extension->ImmediateTotalTimer,\r\n        NULL,\r\n        SerialGetNextImmediate,\r\n        SERIAL_REF_CANCEL\r\n        );\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialGiveImmediateToIsr(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Try to start off the write by slipping it in behind\r\n    a transmit immediate char, or if that isn't available\r\n    and the transmit holding register is empty, \"tickle\"\r\n    the UART into interrupting with a transmit buffer\r\n    empty.\r\n\r\n    NOTE: This routine is called by WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the\r\n          cancel spin lock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    PREQUEST_CONTEXT         reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);\r\n\r\n    Extension->TransmitImmediate = TRUE;\r\n    Extension->ImmediateChar =  *((UCHAR *) (reqContext->SystemBuffer));\r\n\r\n    //\r\n    // The isr now has a reference to the request.\r\n    //\r\n\r\n    SERIAL_SET_REFERENCE(\r\n        reqContext,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n    //\r\n    // Check first to see if a write is going on.  If\r\n    // there is then we'll just slip in during the write.\r\n    //\r\n\r\n    if (!Extension->WriteLength) {\r\n\r\n        //\r\n        // If there is no normal write transmitting then we\r\n        // will \"re-enable\" the transmit holding register empty\r\n        // interrupt.  The 8250 family of devices will always\r\n        // signal a transmit holding register empty interrupt\r\n        // *ANY* time this bit is set to one.  By doing things\r\n        // this way we can simply use the normal interrupt code\r\n        // to start off this write.\r\n        //\r\n        // We've been keeping track of whether the transmit holding\r\n        // register is empty so it we only need to do this\r\n        // if the register is empty.\r\n        //\r\n\r\n        if (Extension->HoldingEmpty) {\r\n            DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n            ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialGrabImmediateFromIsr(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n\r\n    This routine is used to grab the current request, which could be timing\r\n    out or canceling, from the ISR\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that the cancel spin lock is held\r\n          when this routine is called.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    PREQUEST_CONTEXT         reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentImmediateRequest);\r\n\r\n    if (Extension->TransmitImmediate) {\r\n\r\n        Extension->TransmitImmediate = FALSE;\r\n\r\n        //\r\n        // Since the isr no longer references this request, we can\r\n        // decrement it's reference count.\r\n        //\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/initunlo.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    initunlo.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to initialization\r\n    and unload operations in the serial driver\r\n\r\n    WDF Version of serial sample doesn't support:\r\n    1) Multiport Serial devices.\r\n    2) Enumeration of Non PNP serial devices that are not detected by BIOS\r\n                    (IO address range 0x2F0-0x2F7 using IRQ 9)\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"initunlo.tmh\"\r\n#endif\r\n\r\nstatic const PHYSICAL_ADDRESS SerialPhysicalZero = {0};\r\n\r\n//\r\n// We use this to query into the registry as to whether we\r\n// should break at driver entry.\r\n//\r\n\r\nSERIAL_FIRMWARE_DATA    driverDefaults;\r\n\r\n//\r\n// This is exported from the kernel.  It is used to point\r\n// to the address that the kernel debugger is using.\r\n//\r\nextern PUCHAR *KdComPortInUse;\r\n//\r\n// INIT - only needed during init and then can be disposed\r\n// PAGESRP0 - always paged / never locked\r\n// PAGESER - must be locked when a device is open, else paged\r\n//\r\n//\r\n// INIT is used for DriverEntry() specific code\r\n//\r\n// PAGESRP0 is used for code that is not often called and has nothing\r\n// to do with I/O performance.  An example, passive-level PNP\r\n// support functions\r\n//\r\n// PAGESER is used for code that needs to be locked after an open for both\r\n// performance and IRQL reasons.\r\n//\r\n\r\nULONG DebugLevel = TRACE_LEVEL_INFORMATION;\r\nULONG DebugFlag = 0xf;//0x46;//0x4FF; //0x00000006;\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(INIT, DriverEntry)\r\n#pragma alloc_text(PAGE, SerialEvtDriverContextCleanup)\r\n#endif\r\n\r\n\r\n\r\nNTSTATUS\r\nDriverEntry(\r\n    IN PDRIVER_OBJECT DriverObject,\r\n    IN PUNICODE_STRING RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    The entry point that the system point calls to initialize\r\n    any driver.\r\n\r\nArguments:\r\n\r\n    DriverObject - Just what it says,  really of little use\r\n    to the driver itself, it is something that the IO system\r\n    cares more about.\r\n\r\n    PathToRegistry - points to the entry for this driver\r\n    in the current control set of the registry.\r\n\r\nReturn Value:\r\n\r\n    Always STATUS_SUCCESS\r\n\r\n--*/\r\n\r\n{\r\n    WDF_DRIVER_CONFIG config;\r\n    WDFDRIVER hDriver;\r\n    NTSTATUS status;\r\n    WDF_OBJECT_ATTRIBUTES attributes;\r\n\r\n    //\r\n    // Initialize WPP Tracing\r\n    //\r\n    WPP_INIT_TRACING( DriverObject, RegistryPath );\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT,\r\n                    \"Serial Sample (WDF Version)\\n\");\r\n    //\r\n    // Register a cleanup callback so that we can call WPP_CLEANUP when\r\n    // the framework driver object is deleted during driver unload.\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n    attributes.EvtCleanupCallback = SerialEvtDriverContextCleanup;\r\n\r\n    WDF_DRIVER_CONFIG_INIT(&config, SerialEvtDeviceAdd);\r\n\r\n    status = WdfDriverCreate(DriverObject,\r\n                           RegistryPath,\r\n                           &attributes,\r\n                           &config,\r\n                           &hDriver);\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_INIT,\r\n                         \"WdfDriverCreate failed with status 0x%x\\n\",\r\n                         status);\r\n        //\r\n        // Cleanup tracing here because DriverContextCleanup will not be called\r\n        // as we have failed to create WDFDRIVER object itself.\r\n        // Please note that if your return failure from DriverEntry after the\r\n        // WDFDRIVER object is created successfully, you don't have to\r\n        // call WPP cleanup because in those cases DriverContextCleanup\r\n        // will be executed when the framework deletes the DriverObject.\r\n        //\r\n        WPP_CLEANUP(DriverObject);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Call to find out default values to use for all the devices that the\r\n    // driver controls, including whether or not to break on entry.\r\n    //\r\n\r\n    SerialGetConfigDefaults(&driverDefaults, hDriver);\r\n\r\n    //\r\n    // Break on entry if requested via registry\r\n    //\r\n    if (driverDefaults.ShouldBreakOnEntry) {\r\n        DbgBreakPoint();\r\n    }\r\n\r\n\r\n    return status;\r\n}\r\n\r\n\r\n_Use_decl_annotations_\r\nVOID\r\nSerialEvtDriverContextCleanup(\r\n    WDFOBJECT Driver\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    Free all the resources allocated in DriverEntry.\r\n\r\nArguments:\r\n\r\n    Driver - handle to a WDF Driver object.\r\n\r\nReturn Value:\r\n\r\n    VOID.\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(Driver);\r\n\r\n    PAGED_CODE ();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT,\r\n                     \"--> SerialEvtDriverContextCleanup\\n\");\r\n\r\n    //\r\n    // Stop WPP Tracing\r\n    //\r\n    WPP_CLEANUP( WdfDriverWdmGetDriverObject(Driver) );\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT,\r\n                     \"<-- SerialEvtDriverContextCleanup\\n\");\r\n\r\n}\r\n\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/ioctl.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    ioctl.c\r\n\r\nAbstract:\r\n\r\n    This module contains the ioctl dispatcher as well as a couple\r\n    of routines that are generally just called in response to\r\n    ioctl calls.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"ioctl.tmh\"\r\n#endif\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetModemUpdate;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetCommStatus;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetEscapeChar;\r\n\r\nPCHAR\r\nSerialGetIoctlName(\r\n    IN ULONG      IoControlCode\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n    SerialGetIoctlName returns the name of the ioctl\r\n\r\n--*/\r\n{\r\n    switch (IoControlCode)\r\n    {\r\n    case IOCTL_SERIAL_SET_BAUD_RATE : return \"IOCTL_SERIAL_SET_BAUD_RATE\";\r\n    case IOCTL_SERIAL_GET_BAUD_RATE: return \"IOCTL_SERIAL_GET_BAUD_RATE\";\r\n    case IOCTL_SERIAL_GET_MODEM_CONTROL: return \"IOCTL_SERIAL_GET_MODEM_CONTROL\";\r\n    case IOCTL_SERIAL_SET_MODEM_CONTROL: return \"IOCTL_SERIAL_SET_MODEM_CONTROL\";\r\n    case IOCTL_SERIAL_SET_FIFO_CONTROL: return \"IOCTL_SERIAL_SET_FIFO_CONTROL\";\r\n    case IOCTL_SERIAL_SET_LINE_CONTROL: return \"IOCTL_SERIAL_SET_LINE_CONTROL\";\r\n    case IOCTL_SERIAL_GET_LINE_CONTROL: return \"IOCTL_SERIAL_GET_LINE_CONTROL\";\r\n    case IOCTL_SERIAL_SET_TIMEOUTS: return \"IOCTL_SERIAL_SET_TIMEOUTS\";\r\n    case IOCTL_SERIAL_GET_TIMEOUTS: return \"IOCTL_SERIAL_GET_TIMEOUTS\";\r\n    case IOCTL_SERIAL_SET_CHARS: return \"IOCTL_SERIAL_SET_CHARS\";\r\n    case IOCTL_SERIAL_GET_CHARS: return \"IOCTL_SERIAL_GET_CHARS\";\r\n    case IOCTL_SERIAL_SET_DTR: return \"IOCTL_SERIAL_SET_DTR\";\r\n    case IOCTL_SERIAL_CLR_DTR: return \"IOCTL_SERIAL_SET_DTR\";\r\n    case IOCTL_SERIAL_RESET_DEVICE: return \"IOCTL_SERIAL_RESET_DEVICE\";\r\n    case IOCTL_SERIAL_SET_RTS: return \"IOCTL_SERIAL_SET_RTS\";\r\n    case IOCTL_SERIAL_CLR_RTS: return \"IOCTL_SERIAL_CLR_RTS\";\r\n    case IOCTL_SERIAL_SET_XOFF: return \"IOCTL_SERIAL_SET_XOFF\";\r\n    case IOCTL_SERIAL_SET_XON: return \"IOCTL_SERIAL_SET_XON\";\r\n    case IOCTL_SERIAL_SET_BREAK_ON: return \"IOCTL_SERIAL_SET_BREAK_ON\";\r\n    case IOCTL_SERIAL_SET_BREAK_OFF: return \"IOCTL_SERIAL_SET_BREAK_OFF\";\r\n    case IOCTL_SERIAL_SET_QUEUE_SIZE: return \"IOCTL_SERIAL_SET_QUEUE_SIZE\";\r\n    case IOCTL_SERIAL_GET_WAIT_MASK: return \"IOCTL_SERIAL_GET_WAIT_MASK\";\r\n    case IOCTL_SERIAL_SET_WAIT_MASK: return \"IOCTL_SERIAL_SET_WAIT_MASK\";\r\n    case IOCTL_SERIAL_WAIT_ON_MASK: return \"IOCTL_SERIAL_WAIT_ON_MASK\";\r\n    case IOCTL_SERIAL_IMMEDIATE_CHAR: return \"IOCTL_SERIAL_IMMEDIATE_CHAR\";\r\n    case IOCTL_SERIAL_PURGE: return \"IOCTL_SERIAL_PURGE\";\r\n    case IOCTL_SERIAL_GET_HANDFLOW: return \"IOCTL_SERIAL_GET_HANDFLOW\";\r\n    case IOCTL_SERIAL_SET_HANDFLOW: return \"IOCTL_SERIAL_SET_HANDFLOW\";\r\n    case IOCTL_SERIAL_GET_MODEMSTATUS: return \"IOCTL_SERIAL_GET_MODEMSTATUS\";\r\n    case IOCTL_SERIAL_GET_DTRRTS: return \"IOCTL_SERIAL_GET_DTRRTS\";\r\n    case IOCTL_SERIAL_GET_COMMSTATUS: return \"IOCTL_SERIAL_GET_COMMSTATUS\";\r\n    case IOCTL_SERIAL_GET_PROPERTIES: return \"IOCTL_SERIAL_GET_PROPERTIES\";\r\n    case IOCTL_SERIAL_XOFF_COUNTER: return \"IOCTL_SERIAL_XOFF_COUNTER\";\r\n    case IOCTL_SERIAL_LSRMST_INSERT: return \"IOCTL_SERIAL_LSRMST_INSERT\";\r\n    case IOCTL_SERIAL_CONFIG_SIZE: return \"IOCTL_SERIAL_CONFIG_SIZE\";\r\n    case IOCTL_SERIAL_GET_STATS: return \"IOCTL_SERIAL_GET_STATS\";\r\n    case IOCTL_SERIAL_CLEAR_STATS: return \"IOCTL_SERIAL_CLEAR_STATS\";\r\n    default: return \"UnKnown ioctl\";\r\n    }\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialGetStats(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    In sync with the interrpt service routine (which sets the perf stats)\r\n    return the perf stats to the caller.\r\n\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a the request.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PREQUEST_CONTEXT reqContext = (PREQUEST_CONTEXT)Context;\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt));\r\n    PSERIALPERF_STATS sp = reqContext->SystemBuffer;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    *sp = extension->PerfStats;\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialClearStats(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    In sync with the interrpt service routine (which sets the perf stats)\r\n    clear the perf stats.\r\n\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a the extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    RtlZeroMemory(\r\n        &((PSERIAL_DEVICE_EXTENSION)Context)->PerfStats,\r\n        sizeof(SERIALPERF_STATS)\r\n        );\r\n\r\n    RtlZeroMemory(&((PSERIAL_DEVICE_EXTENSION)Context)->WmiPerfData,\r\n                 sizeof(SERIAL_WMI_PERF_DATA));\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialSetChars(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the special characters for the\r\n    driver.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a special characters\r\n              structure.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ((PSERIAL_IOCTL_SYNC)Context)->Extension->SpecialChars =\r\n        *((PSERIAL_CHARS)(((PSERIAL_IOCTL_SYNC)Context)->Data));\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialSetBaud(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the baud rate of the device.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and what should be the current\r\n              baud rate.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n    USHORT Appropriate = PtrToUshort(((PSERIAL_IOCTL_SYNC)Context)->Data);\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    WRITE_DIVISOR_LATCH(\r\n        Extension,\r\n        Extension->Controller,\r\n        Appropriate\r\n        );\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialSetLineControl(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the buad rate of the device.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    WRITE_LINE_CONTROL(Extension,\r\n        Extension->Controller,\r\n        Extension->LineControl\r\n        );\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGetModemUpdate(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is simply used to call the interrupt level routine\r\n    that handles modem status update.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a ulong.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n    ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    *Result = SerialHandleModemUpdate(\r\n                  Extension,\r\n                  FALSE\r\n                  );\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialSetMCRContents(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is simply used to set the contents of the MCR\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a ulong.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n{\r\n   PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n   ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);\r\n\r\n   UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n   //\r\n   // This is severe casting abuse!!!\r\n   //\r\n   WRITE_MODEM_CONTROL(Extension, Extension->Controller, (UCHAR)PtrToUlong(Result));\r\n\r\n   return FALSE;\r\n}\r\n\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialGetMCRContents(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is simply used to get the contents of the MCR\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a ulong.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n    ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    *Result = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialSetFCRContents(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is simply used to set the contents of the FCR\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a ulong.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n{\r\n   PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n   ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);\r\n\r\n   UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n   //\r\n   // This is severe casting abuse!!!\r\n   //\r\n   WRITE_FIFO_CONTROL(Extension, Extension->Controller, (UCHAR)*Result);\r\n\r\n   return FALSE;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialGetCommStatus(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is used to get the current state of the serial driver.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a serial status\r\n              record.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;\r\n    PSERIAL_STATUS Stat = ((PSERIAL_IOCTL_SYNC)Context)->Data;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    Stat->Errors = Extension->ErrorWord;\r\n    Extension->ErrorWord = 0;\r\n\r\n    //\r\n    // Eof isn't supported in binary mode\r\n    //\r\n    Stat->EofReceived = FALSE;\r\n\r\n    Stat->AmountInInQueue = Extension->CharsInInterruptBuffer;\r\n\r\n    Stat->AmountInOutQueue = Extension->TotalCharsQueued;\r\n\r\n    if (Extension->WriteLength) {\r\n\r\n        //\r\n        // By definition if we have a writelength the we have\r\n        // a current write request.\r\n        //\r\n     PREQUEST_CONTEXT reqContext = NULL;\r\n\r\n        ASSERT(Extension->CurrentWriteRequest);\r\n        ASSERT(Stat->AmountInOutQueue >= Extension->WriteLength);\r\n\r\n     reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);\r\n        Stat->AmountInOutQueue -= reqContext->Length - (Extension->WriteLength);\r\n\r\n    }\r\n\r\n    Stat->WaitForImmediate = Extension->TransmitImmediate;\r\n\r\n    Stat->HoldReasons = 0;\r\n    if (Extension->TXHolding) {\r\n\r\n        if (Extension->TXHolding & SERIAL_TX_CTS) {\r\n\r\n            Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;\r\n\r\n        }\r\n\r\n        if (Extension->TXHolding & SERIAL_TX_DSR) {\r\n\r\n            Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR;\r\n\r\n        }\r\n\r\n        if (Extension->TXHolding & SERIAL_TX_DCD) {\r\n\r\n            Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD;\r\n\r\n        }\r\n\r\n        if (Extension->TXHolding & SERIAL_TX_XOFF) {\r\n\r\n            Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;\r\n\r\n        }\r\n\r\n        if (Extension->TXHolding & SERIAL_TX_BREAK) {\r\n\r\n            Stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    if (Extension->RXHolding & SERIAL_RX_DSR) {\r\n\r\n        Stat->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR;\r\n\r\n    }\r\n\r\n    if (Extension->RXHolding & SERIAL_RX_XOFF) {\r\n\r\n        Stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;\r\n\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialSetEscapeChar(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID         Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is used to set the character that will be used to escape\r\n    line status and modem status information when the application\r\n    has set up that line status and modem status should be passed\r\n    back in the data stream.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to the request that is specify the escape character.\r\n              Implicitly - An escape character of 0 means no escaping\r\n              will occur.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PREQUEST_CONTEXT reqContext = (PREQUEST_CONTEXT)Context;\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt));\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    extension->EscapeChar = *(PUCHAR)reqContext->SystemBuffer;\r\n\r\n    return FALSE;\r\n}\r\n\r\nVOID\r\nSerialEvtIoDeviceControl(\r\n    IN WDFQUEUE     Queue,\r\n    IN WDFREQUEST   Request,\r\n    IN size_t       OutputBufferLength,\r\n    IN size_t       InputBufferLength,\r\n    IN ULONG        IoControlCode\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine provides the initial processing for all of the\r\n    Ioctrls for the serial device.\r\n\r\nArguments:\r\n\r\n    Request - Pointer to the WDFREQUEST for the current request\r\n\r\nReturn Value:\r\n\r\n    The function value is the final status of the call\r\n\r\n--*/\r\n\r\n{\r\n    //\r\n    // The status that gets returned to the caller and\r\n    // set in the Request.\r\n    //\r\n    NTSTATUS Status;\r\n\r\n    //\r\n    // Just what it says.  This is the serial specific device\r\n    // extension of the device object create for the serial driver.\r\n    //\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    PVOID buffer;\r\n    PREQUEST_CONTEXT reqContext;\r\n    size_t  bufSize;\r\n\r\n    UNREFERENCED_PARAMETER(OutputBufferLength);\r\n    UNREFERENCED_PARAMETER(InputBufferLength);\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \"%s for: %p\\n\",\r\n                                    SerialGetIoctlName(IoControlCode), Request);\r\n\r\n    Extension = SerialGetDeviceExtension(WdfIoQueueGetDevice(Queue));\r\n\r\n    //\r\n    // We expect to be open so all our pages are locked down.  This is, after\r\n    // all, an IO operation, so the device should be open first.\r\n    //\r\n\r\n    if (Extension->DeviceIsOpened != TRUE) {\r\n       SerialCompleteRequest(Request, STATUS_INVALID_DEVICE_REQUEST, 0);\r\n       return;\r\n    }\r\n\r\n\r\n    if (SerialCompleteIfError(Extension, Request) != STATUS_SUCCESS) {\r\n\r\n       SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS,\r\n                    \"<SerialEvtIoDeviceControl (2) %d\\n\", STATUS_CANCELLED);\r\n       return;\r\n\r\n    }\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n    reqContext->Information = 0;\r\n    reqContext->Status = STATUS_SUCCESS;\r\n    reqContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;\r\n\r\n\r\n    Status = STATUS_SUCCESS;\r\n\r\n    switch (IoControlCode) {\r\n\r\n        case IOCTL_SERIAL_SET_BAUD_RATE : {\r\n\r\n            ULONG BaudRate;\r\n            //\r\n            // Will hold the value of the appropriate divisor for\r\n            // the requested baud rate.  If the baudrate is invalid\r\n            // (because the device won't support that baud rate) then\r\n            // this value is undefined.\r\n            //\r\n            // Note: in one sense the concept of a valid baud rate\r\n            // is cloudy.  We could allow the user to request any\r\n            // baud rate.  We could then calculate the divisor needed\r\n            // for that baud rate.  As long as the divisor wasn't less\r\n            // than one we would be \"ok\".  (The percentage difference\r\n            // between the \"true\" divisor and the \"rounded\" value given\r\n            // to the hardware might make it unusable, but... )  It would\r\n            // really be up to the user to \"Know\" whether the baud rate\r\n            // is suitable.  So much for theory, *We* only support a given\r\n            // set of baud rates.\r\n            //\r\n            SHORT AppropriateDivisor;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer (Request, sizeof(SERIAL_BAUD_RATE), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            BaudRate = ((PSERIAL_BAUD_RATE)(buffer))->BaudRate;\r\n\r\n\r\n            //\r\n            // Get the baud rate from the request.  We pass it\r\n            // to a routine which will set the correct divisor.\r\n            //\r\n\r\n            Status = SerialGetDivisorFromBaud(\r\n                         Extension->ClockRate,\r\n                         BaudRate,\r\n                         &AppropriateDivisor\r\n                         );\r\n\r\n\r\n            if (NT_SUCCESS(Status)) {\r\n\r\n                SERIAL_IOCTL_SYNC S;\r\n\r\n\r\n                Extension->CurrentBaud = BaudRate;\r\n                Extension->WmiCommData.BaudRate = BaudRate;\r\n\r\n                S.Extension = Extension;\r\n                S.Data = (PVOID) (ULONG_PTR) AppropriateDivisor;\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    SerialSetBaud,\r\n                    &S\r\n                    );\r\n\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case IOCTL_SERIAL_GET_BAUD_RATE: {\r\n\r\n            PSERIAL_BAUD_RATE Br;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_BAUD_RATE), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            Br = (PSERIAL_BAUD_RATE)buffer;\r\n\r\n            Br->BaudRate = Extension->CurrentBaud;\r\n\r\n            reqContext->Information = sizeof(SERIAL_BAUD_RATE);\r\n\r\n            break;\r\n\r\n        }\r\n\r\n        case IOCTL_SERIAL_GET_MODEM_CONTROL: {\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(ULONG);\r\n\r\n            S.Extension = Extension;\r\n            S.Data = buffer;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialGetMCRContents,\r\n                &S\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_MODEM_CONTROL: {\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer (Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            S.Extension = Extension;\r\n            S.Data = buffer;\r\n\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetMCRContents,\r\n                &S\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_FIFO_CONTROL: {\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer (Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            S.Extension = Extension;\r\n            S.Data = buffer;\r\n\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetFCRContents,\r\n                &S\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_LINE_CONTROL: {\r\n\r\n            PSERIAL_LINE_CONTROL Lc;\r\n            UCHAR LData;\r\n            UCHAR LStop;\r\n            UCHAR LParity;\r\n            UCHAR Mask = 0xff;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer (Request, sizeof(SERIAL_LINE_CONTROL), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            //\r\n            // Points to the line control record in the Request.\r\n            //\r\n            Lc =  (PSERIAL_LINE_CONTROL)buffer;\r\n\r\n            switch (Lc->WordLength) {\r\n                case 5: {\r\n\r\n                    LData = SERIAL_5_DATA;\r\n                    Mask = 0x1f;\r\n                    break;\r\n\r\n                }\r\n                case 6: {\r\n\r\n                    LData = SERIAL_6_DATA;\r\n                    Mask = 0x3f;\r\n                    break;\r\n\r\n                }\r\n                case 7: {\r\n\r\n                    LData = SERIAL_7_DATA;\r\n                    Mask = 0x7f;\r\n                    break;\r\n\r\n                }\r\n                case 8: {\r\n\r\n                    LData = SERIAL_8_DATA;\r\n                    break;\r\n\r\n                }\r\n                default: {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n                    goto DoneWithIoctl;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            Extension->WmiCommData.BitsPerByte = Lc->WordLength;\r\n\r\n            switch (Lc->Parity) {\r\n\r\n                case NO_PARITY: {\r\n                    Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;\r\n                    LParity = SERIAL_NONE_PARITY;\r\n                    break;\r\n\r\n                }\r\n                case EVEN_PARITY: {\r\n                    Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;\r\n                    LParity = SERIAL_EVEN_PARITY;\r\n                    break;\r\n\r\n                }\r\n                case ODD_PARITY: {\r\n                    Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;\r\n                    LParity = SERIAL_ODD_PARITY;\r\n                    break;\r\n\r\n                }\r\n                case SPACE_PARITY: {\r\n                    Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;\r\n                    LParity = SERIAL_SPACE_PARITY;\r\n                    break;\r\n\r\n                }\r\n                case MARK_PARITY: {\r\n                    Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;\r\n                    LParity = SERIAL_MARK_PARITY;\r\n                    break;\r\n\r\n                }\r\n                default: {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n                    goto DoneWithIoctl;\r\n                    break;\r\n                }\r\n\r\n            }\r\n\r\n            switch (Lc->StopBits) {\r\n\r\n                case STOP_BIT_1: {\r\n                    Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1;\r\n                    LStop = SERIAL_1_STOP;\r\n                    break;\r\n                }\r\n                case STOP_BITS_1_5: {\r\n\r\n                    if (LData != SERIAL_5_DATA) {\r\n\r\n                        Status = STATUS_INVALID_PARAMETER;\r\n                        goto DoneWithIoctl;\r\n                    }\r\n                    Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5;\r\n                    LStop = SERIAL_1_5_STOP;\r\n                    break;\r\n\r\n                }\r\n                case STOP_BITS_2: {\r\n\r\n                    if (LData == SERIAL_5_DATA) {\r\n\r\n                        Status = STATUS_INVALID_PARAMETER;\r\n                        goto DoneWithIoctl;\r\n                    }\r\n                    Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_2;\r\n                    LStop = SERIAL_2_STOP;\r\n                    break;\r\n\r\n                }\r\n                default: {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n                    goto DoneWithIoctl;\r\n                }\r\n\r\n            }\r\n\r\n            Extension->LineControl =\r\n                (UCHAR)((Extension->LineControl & SERIAL_LCR_BREAK) |\r\n                        (LData | LParity | LStop));\r\n            Extension->ValidDataMask = Mask;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetLineControl,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_GET_LINE_CONTROL: {\r\n\r\n            PSERIAL_LINE_CONTROL Lc;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_LINE_CONTROL), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            Lc = (PSERIAL_LINE_CONTROL)buffer;\r\n\r\n            RtlZeroMemory(buffer, OutputBufferLength);\r\n\r\n            if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {\r\n                Lc->WordLength = 5;\r\n            } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                        == SERIAL_6_DATA) {\r\n                Lc->WordLength = 6;\r\n            } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                        == SERIAL_7_DATA) {\r\n                Lc->WordLength = 7;\r\n            } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                        == SERIAL_8_DATA) {\r\n                Lc->WordLength = 8;\r\n            }\r\n\r\n            if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n                    == SERIAL_NONE_PARITY) {\r\n                Lc->Parity = NO_PARITY;\r\n            } else if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n                    == SERIAL_ODD_PARITY) {\r\n                Lc->Parity = ODD_PARITY;\r\n            } else if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n                    == SERIAL_EVEN_PARITY) {\r\n                Lc->Parity = EVEN_PARITY;\r\n            } else if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n                    == SERIAL_MARK_PARITY) {\r\n                Lc->Parity = MARK_PARITY;\r\n            } else if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n                    == SERIAL_SPACE_PARITY) {\r\n                Lc->Parity = SPACE_PARITY;\r\n            }\r\n\r\n            if (Extension->LineControl & SERIAL_2_STOP) {\r\n                if (Lc->WordLength == 5) {\r\n                    Lc->StopBits = STOP_BITS_1_5;\r\n                } else {\r\n                    Lc->StopBits = STOP_BITS_2;\r\n                }\r\n            } else {\r\n                Lc->StopBits = STOP_BIT_1;\r\n            }\r\n\r\n            reqContext->Information = sizeof(SERIAL_LINE_CONTROL);\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_TIMEOUTS: {\r\n\r\n            PSERIAL_TIMEOUTS NewTimeouts;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_TIMEOUTS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            NewTimeouts =(PSERIAL_TIMEOUTS)buffer;\r\n\r\n            if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) &&\r\n                (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&\r\n                (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n\r\n            Extension->Timeouts.ReadIntervalTimeout =\r\n                NewTimeouts->ReadIntervalTimeout;\r\n\r\n            Extension->Timeouts.ReadTotalTimeoutMultiplier =\r\n                NewTimeouts->ReadTotalTimeoutMultiplier;\r\n\r\n            Extension->Timeouts.ReadTotalTimeoutConstant =\r\n                NewTimeouts->ReadTotalTimeoutConstant;\r\n\r\n            Extension->Timeouts.WriteTotalTimeoutMultiplier =\r\n                NewTimeouts->WriteTotalTimeoutMultiplier;\r\n\r\n            Extension->Timeouts.WriteTotalTimeoutConstant =\r\n                NewTimeouts->WriteTotalTimeoutConstant;\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_GET_TIMEOUTS: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_TIMEOUTS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            *((PSERIAL_TIMEOUTS)buffer) = Extension->Timeouts;\r\n            reqContext->Information = sizeof(SERIAL_TIMEOUTS);\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_CHARS: {\r\n\r\n            SERIAL_IOCTL_SYNC S;\r\n            PSERIAL_CHARS NewChars;\r\n\r\n           Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_CHARS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            NewChars = (PSERIAL_CHARS)buffer;\r\n\r\n            //\r\n            // The only thing that can be wrong with the chars\r\n            // is that the xon and xoff characters are the\r\n            // same.\r\n            //\r\n#if 0\r\n            if (NewChars->XonChar == NewChars->XoffChar) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n#endif\r\n\r\n            //\r\n            // We acquire the control lock so that only\r\n            // one request can GET or SET the characters\r\n            // at a time.  The sets could be synchronized\r\n            // by the interrupt spinlock, but that wouldn't\r\n            // prevent multiple gets at the same time.\r\n            //\r\n\r\n            S.Extension = Extension;\r\n            S.Data = NewChars;\r\n\r\n            //\r\n            // Under the protection of the lock, make sure that\r\n            // the xon and xoff characters aren't the same as\r\n            // the escape character.\r\n            //\r\n\r\n            if (Extension->EscapeChar) {\r\n\r\n                if ((Extension->EscapeChar == NewChars->XonChar) ||\r\n                    (Extension->EscapeChar == NewChars->XoffChar)) {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n                    break;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            Extension->WmiCommData.XonCharacter = NewChars->XonChar;\r\n            Extension->WmiCommData.XoffCharacter = NewChars->XoffChar;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetChars,\r\n                &S\r\n                );\r\n\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_GET_CHARS: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_CHARS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            *((PSERIAL_CHARS)buffer) = Extension->SpecialChars;\r\n            reqContext->Information = sizeof(SERIAL_CHARS);\r\n\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_DTR:\r\n        case IOCTL_SERIAL_CLR_DTR: {\r\n\r\n\r\n            //\r\n            // We acquire the lock so that we can check whether\r\n            // automatic dtr flow control is enabled.  If it is\r\n            // then we return an error since the app is not allowed\r\n            // to touch this if it is automatic.\r\n            //\r\n\r\n            if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK)\r\n                == SERIAL_DTR_HANDSHAKE) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n\r\n            } else {\r\n\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    ((IoControlCode ==\r\n                     IOCTL_SERIAL_SET_DTR)?\r\n                     (SerialSetDTR):(SerialClrDTR)),\r\n                    Extension\r\n                    );\r\n\r\n            }\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_RESET_DEVICE: {\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_RTS:\r\n        case IOCTL_SERIAL_CLR_RTS: {\r\n\r\n            //\r\n            // We acquire the lock so that we can check whether\r\n            // automatic rts flow control or transmit toggleing\r\n            // is enabled.  If it is then we return an error since\r\n            // the app is not allowed to touch this if it is automatic\r\n            // or toggling.\r\n            //\r\n\r\n            if (((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)\r\n                 == SERIAL_RTS_HANDSHAKE) ||\r\n                ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)\r\n                 == SERIAL_TRANSMIT_TOGGLE)) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n\r\n            } else {\r\n\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    ((IoControlCode ==\r\n                     IOCTL_SERIAL_SET_RTS)?\r\n                     (SerialSetRTS):(SerialClrRTS)),\r\n                    Extension\r\n                    );\r\n\r\n            }\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_SET_XOFF: {\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialPretendXoff,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_SET_XON: {\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialPretendXon,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_SET_BREAK_ON: {\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialTurnOnBreak,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_BREAK_OFF: {\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialTurnOffBreak,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_SET_QUEUE_SIZE: {\r\n\r\n            //\r\n            // Type ahead buffer is fixed, so we just validate\r\n            // the the users request is not bigger that our\r\n            // own internal buffer size.\r\n            //\r\n\r\n            PSERIAL_QUEUE_SIZE Rs;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_QUEUE_SIZE), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            ASSERT(Extension->InterruptReadBuffer);\r\n\r\n            Rs =   (PSERIAL_QUEUE_SIZE)buffer;\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            //\r\n            // We have to allocate the memory for the new\r\n            // buffer while we're still in the context of the\r\n            // caller.  We don't even try to protect this\r\n            // with a lock because the value could be stale\r\n            // as soon as we release the lock - The only time\r\n            // we will know for sure is when we actually try\r\n            // to do the resize.\r\n            //\r\n\r\n            if (Rs->InSize <= Extension->BufferSize) {\r\n\r\n                Status = STATUS_SUCCESS;\r\n                break;\r\n\r\n            }\r\n\r\n            reqContext->Type3InputBuffer =\r\n                    ExAllocatePoolWithQuotaTag(\r\n                        NonPagedPoolNx | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,\r\n                        Rs->InSize,\r\n                        POOL_TAG\r\n                        );\r\n\r\n            if (!reqContext->Type3InputBuffer) {\r\n\r\n                Status = STATUS_INSUFFICIENT_RESOURCES;\r\n                break;\r\n\r\n            }\r\n\r\n            //\r\n            // Well the data passed was big enough.  Do the request.\r\n            //\r\n            // There are two reason we place it in the read queue:\r\n            //\r\n            // 1) We want to serialize these resize requests so that\r\n            //    they don't contend with each other.\r\n            //\r\n            // 2) We want to serialize these requests with reads since\r\n            //    we don't want reads and resizes contending over the\r\n            //    read buffer.\r\n            //\r\n\r\n\r\n            SerialStartOrQueue(\r\n                       Extension,\r\n                       Request,\r\n                       Extension->ReadQueue,\r\n                       &Extension->CurrentReadRequest,\r\n                       SerialStartRead\r\n                       );\r\n\r\n            return;\r\n        }\r\n        case IOCTL_SERIAL_GET_WAIT_MASK: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            //\r\n            // Simple scalar read.  No reason to acquire a lock.\r\n            //\r\n\r\n            reqContext->Information = sizeof(ULONG);\r\n\r\n            *((ULONG *)buffer) = Extension->IsrWaitMask;\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_SET_WAIT_MASK: {\r\n\r\n            ULONG NewMask;\r\n\r\n            SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"In Ioctl processing for set mask\\n\");\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            NewMask = *((ULONG *)buffer);\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            //\r\n            // Make sure that the mask only contains valid\r\n            // waitable events.\r\n            //\r\n\r\n            if (NewMask & ~(SERIAL_EV_RXCHAR   |\r\n                            SERIAL_EV_RXFLAG   |\r\n                            SERIAL_EV_TXEMPTY  |\r\n                            SERIAL_EV_CTS      |\r\n                            SERIAL_EV_DSR      |\r\n                            SERIAL_EV_RLSD     |\r\n                            SERIAL_EV_BREAK    |\r\n                            SERIAL_EV_ERR      |\r\n                            SERIAL_EV_RING     |\r\n                            SERIAL_EV_PERR     |\r\n                            SERIAL_EV_RX80FULL |\r\n                            SERIAL_EV_EVENT1   |\r\n                            SERIAL_EV_EVENT2)) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Unknown mask %x\\n\", NewMask);\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            //\r\n            // Either start this request or put it on the\r\n            // queue.\r\n            //\r\n\r\n            SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Starting or queuing set mask request %p\"\r\n                             \"\\n\", Request);\r\n\r\n            SerialStartOrQueue(Extension, Request, Extension->MaskQueue,\r\n                                      &Extension->CurrentMaskRequest,\r\n                                      SerialStartMask);\r\n            return;\r\n\r\n        }\r\n        case IOCTL_SERIAL_WAIT_ON_MASK: {\r\n\r\n            SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"In Ioctl processing for wait mask\\n\");\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            //\r\n            // Either start this request or put it on the\r\n            // queue.\r\n            //\r\n\r\n            SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Starting or queuing wait mask request\"\r\n                             \"%p\\n\", Request);\r\n\r\n            SerialStartOrQueue(\r\n                       Extension,\r\n                       Request,\r\n                       Extension->MaskQueue,\r\n                       &Extension->CurrentMaskRequest,\r\n                       SerialStartMask\r\n                       );\r\n            return;\r\n        }\r\n        case IOCTL_SERIAL_IMMEDIATE_CHAR: {\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(UCHAR), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            if (Extension->CurrentImmediateRequest) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n\r\n            } else {\r\n\r\n                //\r\n                // We can queue the char.  We need to set\r\n                // a cancel routine because flow control could\r\n                // keep the char from transmitting.  Make sure\r\n                // that the request hasn't already been canceled.\r\n                //\r\n\r\n                Extension->CurrentImmediateRequest = Request;\r\n                Extension->TotalCharsQueued++;\r\n                SerialStartImmediate(Extension);\r\n                return;\r\n\r\n            }\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_PURGE: {\r\n\r\n            ULONG Mask;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            //\r\n            // Check to make sure that the mask only has\r\n            // 0 or the other appropriate values.\r\n            //\r\n\r\n            Mask = *((ULONG *)(buffer));\r\n\r\n            if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT |\r\n                                      SERIAL_PURGE_RXABORT |\r\n                                      SERIAL_PURGE_TXCLEAR |\r\n                                      SERIAL_PURGE_RXCLEAR\r\n                                     )\r\n                                   )\r\n                           )) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            //\r\n            // Either start this request or put it on the\r\n            // queue.\r\n            //\r\n\r\n            SerialStartOrQueue(\r\n                       Extension,\r\n                       Request,\r\n                       Extension->PurgeQueue,\r\n                       &Extension->CurrentPurgeRequest,\r\n                       SerialStartPurge\r\n                       );\r\n            return;\r\n        }\r\n        case IOCTL_SERIAL_GET_HANDFLOW: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_HANDFLOW), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(SERIAL_HANDFLOW);\r\n\r\n            *((PSERIAL_HANDFLOW)buffer) = Extension->HandFlow;\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_SET_HANDFLOW: {\r\n\r\n            SERIAL_IOCTL_SYNC S;\r\n            PSERIAL_HANDFLOW HandFlow;\r\n\r\n            //\r\n            // Make sure that the hand shake and control is the\r\n            // right size.\r\n            //\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_HANDFLOW), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            HandFlow = (PSERIAL_HANDFLOW)buffer;\r\n\r\n            //\r\n            // Make sure that there are no invalid bits set in\r\n            // the control and handshake.\r\n            //\r\n\r\n            if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            //\r\n            // Make sure that the app hasn't set an invlid DTR mode.\r\n            //\r\n\r\n            if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) ==\r\n                SERIAL_DTR_MASK) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            //\r\n            // Make sure that haven't set totally invalid xon/xoff\r\n            // limits.\r\n            //\r\n\r\n            if ((HandFlow->XonLimit < 0) ||\r\n                ((ULONG)HandFlow->XonLimit > Extension->BufferSize)) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            if ((HandFlow->XoffLimit < 0) ||\r\n                ((ULONG)HandFlow->XoffLimit > Extension->BufferSize)) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n\r\n            S.Extension = Extension;\r\n            S.Data = HandFlow;\r\n\r\n            //\r\n            // Under the protection of the lock, make sure that\r\n            // we aren't turning on error replacement when we\r\n            // are doing line status/modem status insertion.\r\n            //\r\n\r\n            if (Extension->EscapeChar) {\r\n\r\n                if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n                    break;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetHandFlow,\r\n                &S\r\n                );\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_GET_MODEMSTATUS: {\r\n\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(ULONG);\r\n\r\n            S.Extension = Extension;\r\n            S.Data = buffer;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialGetModemUpdate,\r\n                &S\r\n                );\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_GET_DTRRTS: {\r\n\r\n            ULONG ModemControl;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(ULONG);\r\n            reqContext->Status = STATUS_SUCCESS;\r\n\r\n            //\r\n            // Reading this hardware has no effect on the device.\r\n            //\r\n\r\n            ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n            ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE;\r\n\r\n            *(PULONG)buffer = ModemControl;\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_GET_COMMSTATUS: {\r\n\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_STATUS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(SERIAL_STATUS);\r\n\r\n            S.Extension = Extension;\r\n            S.Data =  buffer;\r\n\r\n            //\r\n            // Acquire the cancel spin lock so nothing much\r\n            // changes while were getting the state.\r\n            //\r\n\r\n            //IoAcquireCancelSpinLock(&OldIrql);\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialGetCommStatus,\r\n                &S\r\n                );\r\n\r\n            //IoReleaseCancelSpinLock(OldIrql);\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_GET_PROPERTIES: {\r\n\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_COMMPROP), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            //\r\n            // No synchronization is required since this information\r\n            // is \"static\".\r\n            //\r\n\r\n            SerialGetProperties(\r\n                Extension,\r\n                buffer\r\n                );\r\n\r\n            reqContext->Information = sizeof(SERIAL_COMMPROP);\r\n            reqContext->Status = STATUS_SUCCESS;\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_XOFF_COUNTER: {\r\n\r\n            PSERIAL_XOFF_COUNTER Xc;\r\n\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_XOFF_COUNTER), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            Xc = (PSERIAL_XOFF_COUNTER)buffer;\r\n\r\n            if (Xc->Counter <= 0) {\r\n\r\n                Status = STATUS_INVALID_PARAMETER;\r\n                break;\r\n\r\n            }\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            //\r\n            // There is no output, so make that clear now\r\n            //\r\n\r\n            reqContext->Information = 0;\r\n\r\n            //\r\n            // So far so good.  Put the request onto the write queue.\r\n            //\r\n\r\n            SerialStartOrQueue(\r\n                       Extension,\r\n                       Request,\r\n                       Extension->WriteQueue,\r\n                       &Extension->CurrentWriteRequest,\r\n                       SerialStartWrite\r\n                       );\r\n            return;\r\n\r\n        }\r\n        case IOCTL_SERIAL_LSRMST_INSERT: {\r\n\r\n            PUCHAR escapeChar;\r\n            SERIAL_IOCTL_SYNC S;\r\n\r\n            //\r\n            // Make sure we get a byte.\r\n            //\r\n            Status = WdfRequestRetrieveInputBuffer ( Request, sizeof(UCHAR), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            escapeChar = (PUCHAR)buffer;\r\n\r\n            if (*escapeChar) {\r\n\r\n                //\r\n                // We've got some escape work to do.  We will make sure that\r\n                // the character is not the same as the Xon or Xoff character,\r\n                // or that we are already doing error replacement.\r\n                //\r\n\r\n                if ((*escapeChar == Extension->SpecialChars.XoffChar) ||\r\n                    (*escapeChar == Extension->SpecialChars.XonChar) ||\r\n                    (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) {\r\n\r\n                    Status = STATUS_INVALID_PARAMETER;\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            S.Extension = Extension;\r\n            S.Data = buffer;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialSetEscapeChar,\r\n                reqContext\r\n                );\r\n\r\n            break;\r\n\r\n        }\r\n        case IOCTL_SERIAL_CONFIG_SIZE: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(ULONG), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->Information = sizeof(ULONG);\r\n            reqContext->Status = STATUS_SUCCESS;\r\n\r\n            *(PULONG)buffer = 0;\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_GET_STATS: {\r\n\r\n            Status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIALPERF_STATS), &buffer, &bufSize );\r\n            if( !NT_SUCCESS(Status) ) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", Status);\r\n                break;\r\n            }\r\n\r\n            reqContext->SystemBuffer = buffer;\r\n\r\n            reqContext->Information = sizeof(SERIALPERF_STATS);\r\n            reqContext->Status = STATUS_SUCCESS;\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialGetStats,\r\n                reqContext\r\n                );\r\n\r\n            break;\r\n        }\r\n        case IOCTL_SERIAL_CLEAR_STATS: {\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialClearStats,\r\n                Extension\r\n                );\r\n            break;\r\n        }\r\n        default: {\r\n\r\n            Status = STATUS_INVALID_PARAMETER;\r\n            break;\r\n        }\r\n    }\r\n\r\nDoneWithIoctl:;\r\n\r\n    reqContext->Status = Status;\r\n\r\n    SerialCompleteRequest(Request, Status, reqContext->Information);\r\n\r\n    return;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialGetProperties(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PSERIAL_COMMPROP Properties\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function returns the capabilities of this particular\r\n    serial device.\r\n\r\nArguments:\r\n\r\n    Extension - The serial device extension.\r\n\r\n    Properties - The structure used to return the properties\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n\r\n    RtlZeroMemory(\r\n        Properties,\r\n        sizeof(SERIAL_COMMPROP)\r\n        );\r\n\r\n    Properties->PacketLength = sizeof(SERIAL_COMMPROP);\r\n    Properties->PacketVersion = 2;\r\n    Properties->ServiceMask = SERIAL_SP_SERIALCOMM;\r\n    Properties->MaxTxQueue = 0;\r\n    Properties->MaxRxQueue = 0;\r\n\r\n    Properties->MaxBaud = SERIAL_BAUD_USER;\r\n    Properties->SettableBaud = Extension->SupportedBauds;\r\n\r\n    Properties->ProvSubType = SERIAL_SP_RS232;\r\n    Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |\r\n                                   SERIAL_PCF_RTSCTS |\r\n                                   SERIAL_PCF_CD     |\r\n                                   SERIAL_PCF_PARITY_CHECK |\r\n                                   SERIAL_PCF_XONXOFF |\r\n                                   SERIAL_PCF_SETXCHAR |\r\n                                   SERIAL_PCF_TOTALTIMEOUTS |\r\n                                   SERIAL_PCF_INTTIMEOUTS;\r\n    Properties->SettableParams = SERIAL_SP_PARITY |\r\n                                 SERIAL_SP_BAUD |\r\n                                 SERIAL_SP_DATABITS |\r\n                                 SERIAL_SP_STOPBITS |\r\n                                 SERIAL_SP_HANDSHAKING |\r\n                                 SERIAL_SP_PARITY_CHECK |\r\n                                 SERIAL_SP_CARRIER_DETECT;\r\n\r\n\r\n    Properties->SettableData = SERIAL_DATABITS_5 |\r\n                               SERIAL_DATABITS_6 |\r\n                               SERIAL_DATABITS_7 |\r\n                               SERIAL_DATABITS_8;\r\n    Properties->SettableStopParity = SERIAL_STOPBITS_10 |\r\n                                     SERIAL_STOPBITS_15 |\r\n                                     SERIAL_STOPBITS_20 |\r\n                                     SERIAL_PARITY_NONE |\r\n                                     SERIAL_PARITY_ODD  |\r\n                                     SERIAL_PARITY_EVEN |\r\n                                     SERIAL_PARITY_MARK |\r\n                                     SERIAL_PARITY_SPACE;\r\n    Properties->CurrentTxQueue = 0;\r\n    Properties->CurrentRxQueue = Extension->BufferSize;\r\n\r\n}\r\n\r\nVOID\r\nSerialEvtIoInternalDeviceControl(\r\n    IN WDFQUEUE     Queue,\r\n    IN WDFREQUEST Request,\r\n    IN size_t      OutputBufferLength,\r\n    IN size_t      InputBufferLength,\r\n    IN ULONG      IoControlCode\r\n)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine provides the initial processing for all of the\r\n    internal Ioctrls for the serial device.\r\n\r\nArguments:\r\n\r\n    PDevObj - Pointer to the device object for this device\r\n\r\n    PIrp - Pointer to the WDFREQUEST for the current request\r\n\r\nReturn Value:\r\n\r\n    The function value is the final status of the call\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status;\r\n    PSERIAL_DEVICE_EXTENSION pDevExt = NULL;\r\n    PVOID buffer;\r\n    PREQUEST_CONTEXT reqContext;\r\n    WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;\r\n    size_t  bufSize;\r\n\r\n    UNREFERENCED_PARAMETER(OutputBufferLength);\r\n    UNREFERENCED_PARAMETER(InputBufferLength);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"SerialEvtIoInternalDeviceControl for: %p\\n\", Request);\r\n\r\n    pDevExt = SerialGetDeviceExtension(WdfIoQueueGetDevice(Queue));\r\n\r\n    if (SerialCompleteIfError(pDevExt, Request) != STATUS_SUCCESS) {\r\n\r\n       SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                    \"<SerialEvtIoDeviceControl (2) %d\\n\", STATUS_CANCELLED);\r\n       return;\r\n\r\n    }\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n    reqContext->Information = 0;\r\n    reqContext->Status = STATUS_SUCCESS;\r\n    reqContext->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;\r\n\r\n    switch (IoControlCode) {\r\n\r\n    case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE:\r\n        //\r\n        // Init wait-wake policy structure.\r\n        //\r\n        WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);\r\n        //\r\n        // Override the default settings from allow user control to do not allow.\r\n        //\r\n        wakeSettings.UserControlOfWakeSettings = IdleDoNotAllowUserControl;\r\n        status = WdfDeviceAssignSxWakeSettings(pDevExt->WdfDevice, &wakeSettings);\r\n        if (!NT_SUCCESS(status)) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"WdfDeviceAssignSxWakeSettings failed %x \\n\", status);\r\n            break;\r\n        }\r\n\r\n       pDevExt->IsWakeEnabled = TRUE;\r\n       status = STATUS_SUCCESS;\r\n       break;\r\n\r\n    case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE:\r\n\r\n       WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);\r\n       //\r\n       // Override the default settings.\r\n       //\r\n       wakeSettings.Enabled = WdfFalse; // Disables wait-wake\r\n       wakeSettings.UserControlOfWakeSettings = IdleDoNotAllowUserControl;\r\n       status = WdfDeviceAssignSxWakeSettings(pDevExt->WdfDevice, &wakeSettings);\r\n       if (!NT_SUCCESS(status)) {\r\n           SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"WdfDeviceAssignSxWakeSettings failed %x \\n\", status);\r\n           break;\r\n       }\r\n\r\n       pDevExt->IsWakeEnabled = FALSE;\r\n       status = STATUS_SUCCESS;\r\n       break;\r\n\r\n\r\n    //\r\n    // Put the serial port in a \"filter-driver\" appropriate state\r\n    //\r\n    // WARNING: This code assumes it is being called by a trusted kernel\r\n    // entity and no checking is done on the validity of the settings\r\n    // passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS\r\n    //\r\n    // If validity checking is desired, the regular ioctl's should be used\r\n    //\r\n\r\n    case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS:\r\n    case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: {\r\n\r\n       SERIAL_BASIC_SETTINGS   basic;\r\n       PSERIAL_BASIC_SETTINGS  pBasic;\r\n       SERIAL_IOCTL_SYNC       S;\r\n\r\n       if (IoControlCode == IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) {\r\n\r\n\r\n         //\r\n         // Check the buffer size\r\n         //\r\n         status = WdfRequestRetrieveOutputBuffer ( Request, sizeof(SERIAL_BASIC_SETTINGS), &buffer, &bufSize );\r\n         if( !NT_SUCCESS(status) ) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", status);\r\n            break;\r\n         }\r\n\r\n         reqContext->SystemBuffer = buffer;\r\n\r\n          //\r\n          // Everything is 0 -- timeouts and flow control and fifos.  If\r\n          // We add additional features, this zero memory method\r\n          // may not work.\r\n          //\r\n\r\n          RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS));\r\n\r\n          basic.TxFifo = 1;\r\n          basic.RxFifo = SERIAL_1_BYTE_HIGH_WATER;\r\n\r\n          reqContext->Information = sizeof(SERIAL_BASIC_SETTINGS);\r\n          pBasic = (PSERIAL_BASIC_SETTINGS)buffer;\r\n\r\n          //\r\n          // Save off the old settings\r\n          //\r\n\r\n          RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts,\r\n                        sizeof(SERIAL_TIMEOUTS));\r\n\r\n          RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow,\r\n                        sizeof(SERIAL_HANDFLOW));\r\n\r\n          pBasic->RxFifo = pDevExt->RxFifoTrigger;\r\n          pBasic->TxFifo = pDevExt->TxFifoAmount;\r\n\r\n          //\r\n          // Point to our new settings\r\n          //\r\n\r\n          pBasic = &basic;\r\n       } else { // restoring settings\r\n\r\n          status = WdfRequestRetrieveInputBuffer ( Request, sizeof(SERIAL_BASIC_SETTINGS), &buffer, &bufSize );\r\n          if( !NT_SUCCESS(status) ) {\r\n              SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_IOCTLS, \"Could not get request memory buffer %X\\n\", status);\r\n              break;\r\n          }\r\n\r\n          pBasic = (PSERIAL_BASIC_SETTINGS)buffer;\r\n       }\r\n\r\n       //\r\n       // Set the timeouts\r\n       //\r\n\r\n       RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts,\r\n                     sizeof(SERIAL_TIMEOUTS));\r\n\r\n       //\r\n       // Set flowcontrol\r\n       //\r\n\r\n       S.Extension = pDevExt;\r\n       S.Data = &pBasic->HandFlow;\r\n       WdfInterruptSynchronize(pDevExt->WdfInterrupt, SerialSetHandFlow, &S);\r\n\r\n       if (pDevExt->FifoPresent) {\r\n          pDevExt->TxFifoAmount = pBasic->TxFifo;\r\n          pDevExt->RxFifoTrigger = (UCHAR)pBasic->RxFifo;\r\n\r\n          WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0);\r\n          READ_RECEIVE_BUFFER(pDevExt, pDevExt->Controller);\r\n          WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller,\r\n                             (UCHAR)(SERIAL_FCR_ENABLE | pDevExt->RxFifoTrigger\r\n                                     | SERIAL_FCR_RCVR_RESET\r\n                                     | SERIAL_FCR_TXMT_RESET));\r\n       } else {\r\n          pDevExt->TxFifoAmount = pDevExt->RxFifoTrigger = 0;\r\n          WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0);\r\n       }\r\n\r\n\r\n       break;\r\n    }\r\n\r\n    default:\r\n       status = STATUS_INVALID_PARAMETER;\r\n       break;\r\n\r\n    }\r\n\r\n    reqContext->Status = status;\r\n\r\n    SerialCompleteRequest(Request, reqContext->Status, reqContext->Information);\r\n\r\n    return;\r\n}\r\n\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/isr.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    isr.c\r\n\r\nAbstract:\r\n\r\n    This module contains the interrupt service routine for the\r\n    serial driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"isr.tmh\"\r\n#endif\r\n\r\n\r\nNTSTATUS\r\nSerialEvtInterruptEnable(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN WDFDEVICE     AssociatedDevice\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called when the Framework moves the device to D0, and after\r\n    EvtDeviceD0Entry.  The driver should enable its interrupt here.\r\n\r\n    This function will be called at the device's assigned interrupt\r\n    IRQL (DIRQL.)\r\n\r\nArguments:\r\n\r\n    Interrupt - Handle to a Framework interrupt object.\r\n\r\n    AssociatedDevice - Handle to a Framework device object.\r\n\r\nReturn Value:\r\n\r\n    BOOLEAN - TRUE indicates that the interrupt was successfully enabled.\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n    UNREFERENCED_PARAMETER(AssociatedDevice);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \"--> SerialEvtInterruptEnable\\n\");\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \"<-- SerialEvtInterruptEnable\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nSerialEvtInterruptDisable(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN WDFDEVICE     AssociatedDevice\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called before the Framework moves the device to D1, D2 or D3\r\n    and before EvtDeviceD0Exit.  The driver should disable its interrupt here.\r\n\r\n    This function will be called at the device's assigned interrupt\r\n    IRQL (DIRQL.)\r\n\r\nArguments:\r\n\r\n    Interrupt - Handle to a Framework interrupt object.\r\n\r\n    AssociatedDevice - Handle to a Framework device object.\r\n\r\nReturn Value:\r\n\r\n    BOOLEAN - TRUE indicates that the interrupt was successfully disabled.\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n    UNREFERENCED_PARAMETER(AssociatedDevice);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \"--> SerialEvtInterruptDisable\\n\");\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \"<-- SerialEvtInterruptDisable\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nBOOLEAN\r\nSerialISR(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN ULONG        MessageID\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the interrupt service routine for the serial port driver.\r\n    It will determine whether the serial port is the source of this\r\n    interrupt.  If it is, then this routine will do the minimum of\r\n    processing to quiet the interrupt.  It will store any information\r\n    necessary for later processing.\r\n\r\nArguments:\r\n\r\n    InterruptObject - Points to the interrupt object declared for this\r\n    device.  We *do not* use this parameter.\r\n\r\n\r\nReturn Value:\r\n\r\n    This function will return TRUE if the serial port is the source\r\n    of this interrupt, FALSE otherwise.\r\n\r\n--*/\r\n\r\n{\r\n    //\r\n    // Holds the information specific to handling this device.\r\n    //\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    //\r\n    // Holds the contents of the interrupt identification record.\r\n    // A low bit of zero in this register indicates that there is\r\n    // an interrupt pending on this device.\r\n    //\r\n    UCHAR InterruptIdReg;\r\n\r\n    //\r\n    // Will hold whether we've serviced any interrupt causes in this\r\n    // routine.\r\n    //\r\n    BOOLEAN ServicedAnInterrupt;\r\n\r\n    UCHAR tempLSR;\r\n    PREQUEST_CONTEXT reqContext = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(MessageID);\r\n\r\n    Extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt));\r\n\r\n    //\r\n    // Make sure we have an interrupt pending.  If we do then\r\n    // we need to make sure that the device is open.  If the\r\n    // device isn't open or powered down then quiet the device.  Note that\r\n    // if the device isn't opened when we enter this routine\r\n    // it can't open while we're in it.\r\n    //\r\n\r\n    InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);\r\n\r\n    if ((InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING)) {\r\n\r\n        ServicedAnInterrupt = FALSE;\r\n\r\n    } else if (!Extension->DeviceIsOpened/*\r\n               || (Extension->PowerState != PowerDeviceD0)*/) {\r\n\r\n\r\n        //\r\n        // We got an interrupt with the device being closed or when the\r\n        // device is supposed to be powered down.  This\r\n        // is not unlikely with a serial device.  We just quietly\r\n        // keep servicing the causes until it calms down.\r\n        //\r\n\r\n        ServicedAnInterrupt = TRUE;\r\n        do {\r\n\r\n            InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);\r\n            switch (InterruptIdReg) {\r\n\r\n                case SERIAL_IIR_RLS: {\r\n\r\n                    READ_LINE_STATUS(Extension, Extension->Controller);\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_RDA:\r\n                case SERIAL_IIR_CTI: {\r\n\r\n                    READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_THR: {\r\n\r\n                    //\r\n                    // Alread clear from reading the iir.\r\n                    //\r\n                    // We want to keep close track of whether\r\n                    // the holding register is empty.\r\n                    //\r\n\r\n                    Extension->HoldingEmpty = TRUE;\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_MS: {\r\n\r\n                    READ_MODEM_STATUS(Extension, Extension->Controller);\r\n                    break;\r\n\r\n                }\r\n\r\n                default: {\r\n\r\n                    ASSERT(FALSE);\r\n                    break;\r\n\r\n                }\r\n\r\n            }\r\n\r\n        } while (!((InterruptIdReg =\r\n                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))\r\n                    & SERIAL_IIR_NO_INTERRUPT_PENDING));\r\n\r\n    } else {\r\n\r\n        ServicedAnInterrupt = TRUE;\r\n        do {\r\n\r\n            //\r\n            // We only care about bits that can denote an interrupt.\r\n            //\r\n\r\n            InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA |\r\n                              SERIAL_IIR_CTI | SERIAL_IIR_THR |\r\n                              SERIAL_IIR_MS;\r\n\r\n            //\r\n            // We have an interrupt.  We look for interrupt causes\r\n            // in priority order.  The presence of a higher interrupt\r\n            // will mask out causes of a lower priority.  When we service\r\n            // and quiet a higher priority interrupt we then need to check\r\n            // the interrupt causes to see if a new interrupt cause is\r\n            // present.\r\n            //\r\n\r\n            switch (InterruptIdReg) {\r\n\r\n                case SERIAL_IIR_RLS: {\r\n\r\n                    SerialProcessLSR(Extension);\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_RDA:\r\n                case SERIAL_IIR_CTI:\r\n\r\n                {\r\n\r\n                    //\r\n                    // Reading the receive buffer will quiet this interrupt.\r\n                    //\r\n                    // It may also reveal a new interrupt cause.\r\n                    //\r\n                    UCHAR ReceivedChar;\r\n\r\n                    do {\r\n\r\n                        ReceivedChar =\r\n                            READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n                        Extension->PerfStats.ReceivedCount++;\r\n                        Extension->WmiPerfData.ReceivedCount++;\r\n\r\n                        ReceivedChar &= Extension->ValidDataMask;\r\n\r\n                        if (!ReceivedChar &&\r\n                            (Extension->HandFlow.FlowReplace &\r\n                             SERIAL_NULL_STRIPPING)) {\r\n\r\n                            //\r\n                            // If what we got is a null character\r\n                            // and we're doing null stripping, then\r\n                            // we simply act as if we didn't see it.\r\n                            //\r\n\r\n                            goto ReceiveDoLineStatus;\r\n\r\n                        }\r\n\r\n                        if ((Extension->HandFlow.FlowReplace &\r\n                             SERIAL_AUTO_TRANSMIT) &&\r\n                            ((ReceivedChar ==\r\n                              Extension->SpecialChars.XonChar) ||\r\n                             (ReceivedChar ==\r\n                              Extension->SpecialChars.XoffChar))) {\r\n\r\n                            //\r\n                            // No matter what happens this character\r\n                            // will never get seen by the app.\r\n                            //\r\n\r\n                            if (ReceivedChar ==\r\n                                Extension->SpecialChars.XoffChar) {\r\n\r\n                                Extension->TXHolding |= SERIAL_TX_XOFF;\r\n\r\n                                if ((Extension->HandFlow.FlowReplace &\r\n                                     SERIAL_RTS_MASK) ==\r\n                                     SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                    SerialInsertQueueDpc(\r\n                                        Extension->StartTimerLowerRTSDpc\r\n                                        )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n                                }\r\n\r\n\r\n                            } else {\r\n\r\n                                if (Extension->TXHolding & SERIAL_TX_XOFF) {\r\n\r\n                                    //\r\n                                    // We got the xon char **AND*** we\r\n                                    // were being held up on transmission\r\n                                    // by xoff.  Clear that we are holding\r\n                                    // due to xoff.  Transmission will\r\n                                    // automatically restart because of\r\n                                    // the code outside the main loop that\r\n                                    // catches problems chips like the\r\n                                    // SMC and the Winbond.\r\n                                    //\r\n\r\n                                    Extension->TXHolding &= ~SERIAL_TX_XOFF;\r\n\r\n                                }\r\n\r\n                            }\r\n\r\n                            goto ReceiveDoLineStatus;\r\n\r\n                        }\r\n\r\n                        //\r\n                        // Check to see if we should note\r\n                        // the receive character or special\r\n                        // character event.\r\n                        //\r\n\r\n                        if (Extension->IsrWaitMask) {\r\n\r\n                            if (Extension->IsrWaitMask &\r\n                                SERIAL_EV_RXCHAR) {\r\n\r\n                                Extension->HistoryMask |= SERIAL_EV_RXCHAR;\r\n\r\n                            }\r\n\r\n                            if ((Extension->IsrWaitMask &\r\n                                 SERIAL_EV_RXFLAG) &&\r\n                                (Extension->SpecialChars.EventChar ==\r\n                                 ReceivedChar)) {\r\n\r\n                                Extension->HistoryMask |= SERIAL_EV_RXFLAG;\r\n\r\n                            }\r\n\r\n                            if (Extension->IrpMaskLocation &&\r\n                                Extension->HistoryMask) {\r\n\r\n                                *Extension->IrpMaskLocation =\r\n                                 Extension->HistoryMask;\r\n                                Extension->IrpMaskLocation = NULL;\r\n                                Extension->HistoryMask = 0;\r\n                                reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n                                reqContext->Information = sizeof(ULONG);\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->CommWaitDpc\r\n                                    );\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                        SerialPutChar(\r\n                            Extension,\r\n                            ReceivedChar\r\n                            );\r\n\r\n                        //\r\n                        // If we're doing line status and modem\r\n                        // status insertion then we need to insert\r\n                        // a zero following the character we just\r\n                        // placed into the buffer to mark that this\r\n                        // was reception of what we are using to\r\n                        // escape.\r\n                        //\r\n\r\n                        if (Extension->EscapeChar &&\r\n                            (Extension->EscapeChar ==\r\n                             ReceivedChar)) {\r\n\r\n                            SerialPutChar(\r\n                                Extension,\r\n                                SERIAL_LSRMST_ESCAPE\r\n                                );\r\n\r\n                        }\r\n\r\n\r\nReceiveDoLineStatus:    ;\r\n                        //\r\n                        // This reads the interrupt ID register and detemines if bits are 0\r\n                        // If either of the reserved bits are 1, we stop servicing interrupts\r\n                        // Since this detection method is not guarenteed this is enabled via\r\n                        // a registry entry \"UartDetectRemoval\" and intialized on DriverEntry.\r\n                        // This is disabled by default and will only be enabled on Stratus systems\r\n                        // that allow hot replacement of serial cards\r\n                        //\r\n                        if(Extension->UartRemovalDetect)\r\n                        {\r\n                           UCHAR DetectRemoval;\r\n\r\n                           DetectRemoval = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);\r\n\r\n                           if(DetectRemoval & SERIAL_IIR_MUST_BE_ZERO)\r\n                           {\r\n                               // break out of this loop and stop processing interrupts\r\n                               break;\r\n                           }\r\n                        }\r\n\r\n                        if (!((tempLSR = SerialProcessLSR(Extension)) &\r\n                              SERIAL_LSR_DR)) {\r\n\r\n                            //\r\n                            // No more characters, get out of the\r\n                            // loop.\r\n                            //\r\n\r\n                            break;\r\n\r\n                        }\r\n\r\n                        if ((tempLSR & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT |\r\n                                         SERIAL_LSR_DR)) &&\r\n                            Extension->EscapeChar) {\r\n\r\n                           //\r\n                           // An error was indicated and inserted into the\r\n                           // stream, get out of the loop.\r\n                           //\r\n\r\n                           break;\r\n                        }\r\n\r\n                    } WHILE (TRUE);\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_THR: {\r\n\r\ndoTrasmitStuff:;\r\n                    Extension->HoldingEmpty = TRUE;\r\n\r\n                    if (Extension->WriteLength ||\r\n                        Extension->TransmitImmediate ||\r\n                        Extension->SendXoffChar ||\r\n                        Extension->SendXonChar) {\r\n\r\n                        //\r\n                        // Even though all of the characters being\r\n                        // sent haven't all been sent, this variable\r\n                        // will be checked when the transmit queue is\r\n                        // empty.  If it is still true and there is a\r\n                        // wait on the transmit queue being empty then\r\n                        // we know we finished transmitting all characters\r\n                        // following the initiation of the wait since\r\n                        // the code that initiates the wait will set\r\n                        // this variable to false.\r\n                        //\r\n                        // One reason it could be false is that\r\n                        // the writes were cancelled before they\r\n                        // actually started, or that the writes\r\n                        // failed due to timeouts.  This variable\r\n                        // basically says a character was written\r\n                        // by the isr at some point following the\r\n                        // initiation of the wait.\r\n                        //\r\n\r\n                        Extension->EmptiedTransmit = TRUE;\r\n\r\n                        //\r\n                        // If we have output flow control based on\r\n                        // the modem status lines, then we have to do\r\n                        // all the modem work before we output each\r\n                        // character. (Otherwise we might miss a\r\n                        // status line change.)\r\n                        //\r\n\r\n                        if (Extension->HandFlow.ControlHandShake &\r\n                            SERIAL_OUT_HANDSHAKEMASK) {\r\n\r\n                            SerialHandleModemUpdate(\r\n                                Extension,\r\n                                TRUE\r\n                                );\r\n\r\n                        }\r\n\r\n                        //\r\n                        // We can only send the xon character if\r\n                        // the only reason we are holding is because\r\n                        // of the xoff.  (Hardware flow control or\r\n                        // sending break preclude putting a new character\r\n                        // on the wire.)\r\n                        //\r\n\r\n                        if (Extension->SendXonChar &&\r\n                            !(Extension->TXHolding & ~SERIAL_TX_XOFF)) {\r\n\r\n                            if ((Extension->HandFlow.FlowReplace &\r\n                                 SERIAL_RTS_MASK) ==\r\n                                 SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                //\r\n                                // We have to raise if we're sending\r\n                                // this character.\r\n                                //\r\n\r\n                                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n\r\n                                WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller,\r\n                                                                Extension->SpecialChars.XonChar);\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->StartTimerLowerRTSDpc\r\n                                    )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n\r\n                            } else {\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n\r\n                                WRITE_TRANSMIT_HOLDING(Extension,\r\n                                    Extension->Controller,\r\n                                    Extension->SpecialChars.XonChar);\r\n                            }\r\n\r\n\r\n                            Extension->SendXonChar = FALSE;\r\n                            Extension->HoldingEmpty = FALSE;\r\n\r\n                            //\r\n                            // If we send an xon, by definition we\r\n                            // can't be holding by Xoff.\r\n                            //\r\n\r\n                            Extension->TXHolding &= ~SERIAL_TX_XOFF;\r\n\r\n                            //\r\n                            // If we are sending an xon char then\r\n                            // by definition we can't be \"holding\"\r\n                            // up reception by Xoff.\r\n                            //\r\n\r\n                            Extension->RXHolding &= ~SERIAL_RX_XOFF;\r\n\r\n                        } else if (Extension->SendXoffChar &&\r\n                              !Extension->TXHolding) {\r\n\r\n                            if ((Extension->HandFlow.FlowReplace &\r\n                                 SERIAL_RTS_MASK) ==\r\n                                 SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                //\r\n                                // We have to raise if we're sending\r\n                                // this character.\r\n                                //\r\n\r\n                                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n                                WRITE_TRANSMIT_HOLDING(Extension,\r\n                                    Extension->Controller,\r\n                                    Extension->SpecialChars.XoffChar);\r\n\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->StartTimerLowerRTSDpc\r\n                                    )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n                            } else {\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n                                WRITE_TRANSMIT_HOLDING(Extension,\r\n                                    Extension->Controller,\r\n                                    Extension->SpecialChars.XoffChar);\r\n\r\n                            }\r\n\r\n                            //\r\n                            // We can't be sending an Xoff character\r\n                            // if the transmission is already held\r\n                            // up because of Xoff.  Therefore, if we\r\n                            // are holding then we can't send the char.\r\n                            //\r\n\r\n                            //\r\n                            // If the application has set xoff continue\r\n                            // mode then we don't actually stop sending\r\n                            // characters if we send an xoff to the other\r\n                            // side.\r\n                            //\r\n\r\n                            if (!(Extension->HandFlow.FlowReplace &\r\n                                  SERIAL_XOFF_CONTINUE)) {\r\n\r\n                                Extension->TXHolding |= SERIAL_TX_XOFF;\r\n\r\n                                if ((Extension->HandFlow.FlowReplace &\r\n                                     SERIAL_RTS_MASK) ==\r\n                                     SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                    SerialInsertQueueDpc(\r\n                                        Extension->StartTimerLowerRTSDpc\r\n                                        )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n                                }\r\n\r\n                            }\r\n\r\n                            Extension->SendXoffChar = FALSE;\r\n                            Extension->HoldingEmpty = FALSE;\r\n\r\n                        //\r\n                        // Even if transmission is being held\r\n                        // up, we should still transmit an immediate\r\n                        // character if all that is holding us\r\n                        // up is xon/xoff (OS/2 rules).\r\n                        //\r\n\r\n                        } else if (Extension->TransmitImmediate &&\r\n                            (!Extension->TXHolding ||\r\n                             (Extension->TXHolding == SERIAL_TX_XOFF)\r\n                            )) {\r\n\r\n                            Extension->TransmitImmediate = FALSE;\r\n\r\n                            if ((Extension->HandFlow.FlowReplace &\r\n                                 SERIAL_RTS_MASK) ==\r\n                                 SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                //\r\n                                // We have to raise if we're sending\r\n                                // this character.\r\n                                //\r\n\r\n                                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n                                WRITE_TRANSMIT_HOLDING(Extension,\r\n                                    Extension->Controller,\r\n                                    Extension->ImmediateChar);\r\n\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->StartTimerLowerRTSDpc\r\n                                    )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n                            } else {\r\n\r\n                                Extension->PerfStats.TransmittedCount++;\r\n                                Extension->WmiPerfData.TransmittedCount++;\r\n                                WRITE_TRANSMIT_HOLDING(Extension,\r\n                                    Extension->Controller,\r\n                                    Extension->ImmediateChar);\r\n\r\n                            }\r\n\r\n                            Extension->HoldingEmpty = FALSE;\r\n\r\n                            SerialInsertQueueDpc(\r\n                                Extension->CompleteImmediateDpc\r\n                                );\r\n\r\n                        } else if (!Extension->TXHolding) {\r\n\r\n                            ULONG amountToWrite;\r\n\r\n                            if (Extension->FifoPresent) {\r\n\r\n                                amountToWrite = (Extension->TxFifoAmount <\r\n                                                 Extension->WriteLength)?\r\n                                                Extension->TxFifoAmount:\r\n                                                Extension->WriteLength;\r\n\r\n                            } else {\r\n\r\n                                amountToWrite = 1;\r\n\r\n                            }\r\n                            if ((Extension->HandFlow.FlowReplace &\r\n                                 SERIAL_RTS_MASK) ==\r\n                                 SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n                                //\r\n                                // We have to raise if we're sending\r\n                                // this character.\r\n                                //\r\n\r\n                                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                                if (amountToWrite == 1) {\r\n\r\n                                    Extension->PerfStats.TransmittedCount++;\r\n                                    Extension->WmiPerfData.TransmittedCount++;\r\n                                    WRITE_TRANSMIT_HOLDING(Extension,\r\n                                        Extension->Controller,\r\n                                        *(Extension->WriteCurrentChar));\r\n\r\n                                } else {\r\n\r\n                                    Extension->PerfStats.TransmittedCount +=\r\n                                        amountToWrite;\r\n                                    Extension->WmiPerfData.TransmittedCount +=\r\n                                       amountToWrite;\r\n                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,\r\n                                        Extension->Controller,\r\n                                        Extension->WriteCurrentChar,\r\n                                        amountToWrite);\r\n                                }\r\n\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->StartTimerLowerRTSDpc\r\n                                    )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n                            } else {\r\n\r\n                                if (amountToWrite == 1) {\r\n\r\n                                    Extension->PerfStats.TransmittedCount++;\r\n                                    Extension->WmiPerfData.TransmittedCount++;\r\n                                    WRITE_TRANSMIT_HOLDING(Extension,\r\n                                        Extension->Controller,\r\n                                        *(Extension->WriteCurrentChar));\r\n\r\n                                } else {\r\n\r\n                                    Extension->PerfStats.TransmittedCount +=\r\n                                        amountToWrite;\r\n                                    Extension->WmiPerfData.TransmittedCount +=\r\n                                        amountToWrite;\r\n                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,\r\n                                        Extension->Controller,\r\n                                        Extension->WriteCurrentChar,\r\n                                        amountToWrite);\r\n\r\n                                }\r\n\r\n                            }\r\n\r\n                            Extension->HoldingEmpty = FALSE;\r\n                            Extension->WriteCurrentChar += amountToWrite;\r\n                            Extension->WriteLength -= amountToWrite;\r\n\r\n                            if (!Extension->WriteLength) {\r\n\r\n                                //\r\n                                // No More characters left.  This\r\n                                // write is complete.  Take care\r\n                                // when updating the information field,\r\n                                // we could have an xoff counter masquerading\r\n                                // as a write request.\r\n                                //\r\n                                reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);\r\n\r\n                                reqContext->Information =\r\n                                    (reqContext->MajorFunction == IRP_MJ_WRITE)?\r\n                                        (reqContext->Length): (1);\r\n\r\n                                SerialInsertQueueDpc(\r\n                                    Extension->CompleteWriteDpc\r\n                                    );\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                    }\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n                case SERIAL_IIR_MS: {\r\n\r\n                    SerialHandleModemUpdate(\r\n                        Extension,\r\n                        FALSE\r\n                        );\r\n\r\n                    break;\r\n\r\n                }\r\n\r\n            }\r\n\r\n        } while (!((InterruptIdReg =\r\n                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))\r\n                    & SERIAL_IIR_NO_INTERRUPT_PENDING));\r\n\r\n        //\r\n        // Besides catching the WINBOND and SMC chip problems this\r\n        // will also cause transmission to restart incase of an xon\r\n        // char being received.  Don't remove.\r\n        //\r\n\r\n        if (SerialProcessLSR(Extension) & SERIAL_LSR_THRE) {\r\n\r\n            if (!Extension->TXHolding &&\r\n                (Extension->WriteLength ||\r\n                 Extension->TransmitImmediate)) {\r\n\r\n                goto doTrasmitStuff;\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return ServicedAnInterrupt;\r\n\r\n}\r\n\r\nVOID\r\nSerialPutChar(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN UCHAR CharToPut\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine, which only runs at device level, takes care of\r\n    placing a character into the typeahead (receive) buffer.\r\n\r\nArguments:\r\n\r\n    Extension - The serial device extension.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PREQUEST_CONTEXT reqContext = NULL;\r\n\r\n    //\r\n    // If we have dsr sensitivity enabled then\r\n    // we need to check the modem status register\r\n    // to see if it has changed.\r\n    //\r\n\r\n    if (Extension->HandFlow.ControlHandShake &\r\n        SERIAL_DSR_SENSITIVITY) {\r\n\r\n        SerialHandleModemUpdate(\r\n            Extension,\r\n            FALSE\r\n            );\r\n\r\n        if (Extension->RXHolding & SERIAL_RX_DSR) {\r\n\r\n            //\r\n            // We simply act as if we haven't\r\n            // seen the character if we have dsr\r\n            // sensitivity and the dsr line is low.\r\n            //\r\n\r\n            return;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // If the xoff counter is non-zero then decrement it.\r\n    // If the counter then goes to zero, complete that request.\r\n    //\r\n\r\n    if (Extension->CountSinceXoff) {\r\n\r\n        Extension->CountSinceXoff--;\r\n\r\n        if (!Extension->CountSinceXoff) {\r\n            reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest);\r\n            reqContext->Status = STATUS_SUCCESS;\r\n            reqContext->Information = 0;\r\n            SerialInsertQueueDpc(\r\n                Extension->XoffCountCompleteDpc\r\n                );\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // Check to see if we are copying into the\r\n    // users buffer or into the interrupt buffer.\r\n    //\r\n    // If we are copying into the user buffer\r\n    // then we know there is always room for one more.\r\n    // (We know this because if there wasn't room\r\n    // then that read would have completed and we\r\n    // would be using the interrupt buffer.)\r\n    //\r\n    // If we are copying into the interrupt buffer\r\n    // then we will need to check if we have enough\r\n    // room.\r\n    //\r\n\r\n    if (Extension->ReadBufferBase !=\r\n        Extension->InterruptReadBuffer) {\r\n\r\n        //\r\n        // Increment the following value so\r\n        // that the interval timer (if one exists\r\n        // for this read) can know that a character\r\n        // has been read.\r\n        //\r\n\r\n        Extension->ReadByIsr++;\r\n\r\n        //\r\n        // We are in the user buffer.  Place the\r\n        // character into the buffer.  See if the\r\n        // read is complete.\r\n        //\r\n\r\n        *Extension->CurrentCharSlot = CharToPut;\r\n\r\n        if (Extension->CurrentCharSlot ==\r\n            Extension->LastCharSlot) {\r\n\r\n            //\r\n            // We've filled up the users buffer.\r\n            // Switch back to the interrupt buffer\r\n            // and send off a DPC to Complete the read.\r\n            //\r\n            // It is inherent that when we were using\r\n            // a user buffer that the interrupt buffer\r\n            // was empty.\r\n            //\r\n\r\n            Extension->ReadBufferBase =\r\n                Extension->InterruptReadBuffer;\r\n            Extension->CurrentCharSlot =\r\n                Extension->InterruptReadBuffer;\r\n            Extension->FirstReadableChar =\r\n                Extension->InterruptReadBuffer;\r\n            Extension->LastCharSlot =\r\n                Extension->InterruptReadBuffer +\r\n                (Extension->BufferSize - 1);\r\n            Extension->CharsInInterruptBuffer = 0;\r\n            reqContext = SerialGetRequestContext(Extension->CurrentReadRequest);\r\n            reqContext->Information = reqContext->Length;\r\n\r\n            SerialInsertQueueDpc(\r\n                Extension->CompleteReadDpc\r\n                );\r\n\r\n        } else {\r\n\r\n            //\r\n            // Not done with the users read.\r\n            //\r\n\r\n            Extension->CurrentCharSlot++;\r\n\r\n        }\r\n\r\n    } else {\r\n\r\n        //\r\n        // We need to see if we reached our flow\r\n        // control threshold.  If we have then\r\n        // we turn on whatever flow control the\r\n        // owner has specified.  If no flow\r\n        // control was specified, well..., we keep\r\n        // trying to receive characters and hope that\r\n        // we have enough room.  Note that no matter\r\n        // what flow control protocol we are using, it\r\n        // will not prevent us from reading whatever\r\n        // characters are available.\r\n        //\r\n\r\n        if ((Extension->HandFlow.ControlHandShake\r\n             & SERIAL_DTR_MASK) ==\r\n            SERIAL_DTR_HANDSHAKE) {\r\n\r\n            //\r\n            // If we are already doing a\r\n            // dtr hold then we don't have\r\n            // to do anything else.\r\n            //\r\n\r\n            if (!(Extension->RXHolding &\r\n                  SERIAL_RX_DTR)) {\r\n\r\n                if ((Extension->BufferSize -\r\n                     Extension->HandFlow.XoffLimit)\r\n                    <= (Extension->CharsInInterruptBuffer+1)) {\r\n\r\n                    Extension->RXHolding |= SERIAL_RX_DTR;\r\n\r\n                    SerialClrDTR(Extension->WdfInterrupt, Extension);\r\n\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if ((Extension->HandFlow.FlowReplace\r\n             & SERIAL_RTS_MASK) ==\r\n            SERIAL_RTS_HANDSHAKE) {\r\n\r\n            //\r\n            // If we are already doing a\r\n            // rts hold then we don't have\r\n            // to do anything else.\r\n            //\r\n\r\n            if (!(Extension->RXHolding &\r\n                  SERIAL_RX_RTS)) {\r\n\r\n                if ((Extension->BufferSize -\r\n                     Extension->HandFlow.XoffLimit)\r\n                    <= (Extension->CharsInInterruptBuffer+1)) {\r\n\r\n                    Extension->RXHolding |= SERIAL_RX_RTS;\r\n\r\n                    SerialClrRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if (Extension->HandFlow.FlowReplace &\r\n            SERIAL_AUTO_RECEIVE) {\r\n\r\n            //\r\n            // If we are already doing a\r\n            // xoff hold then we don't have\r\n            // to do anything else.\r\n            //\r\n\r\n            if (!(Extension->RXHolding &\r\n                  SERIAL_RX_XOFF)) {\r\n\r\n                if ((Extension->BufferSize -\r\n                     Extension->HandFlow.XoffLimit)\r\n                    <= (Extension->CharsInInterruptBuffer+1)) {\r\n\r\n                    Extension->RXHolding |= SERIAL_RX_XOFF;\r\n\r\n                    //\r\n                    // If necessary cause an\r\n                    // off to be sent.\r\n                    //\r\n\r\n                    SerialProdXonXoff(\r\n                        Extension,\r\n                        FALSE\r\n                        );\r\n\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if (Extension->CharsInInterruptBuffer <\r\n            Extension->BufferSize) {\r\n\r\n            *Extension->CurrentCharSlot = CharToPut;\r\n            Extension->CharsInInterruptBuffer++;\r\n\r\n            //\r\n            // If we've become 80% full on this character\r\n            // and this is an interesting event, note it.\r\n            //\r\n\r\n            if (Extension->CharsInInterruptBuffer ==\r\n                Extension->BufferSizePt8) {\r\n\r\n                if (Extension->IsrWaitMask &\r\n                    SERIAL_EV_RX80FULL) {\r\n\r\n                    Extension->HistoryMask |= SERIAL_EV_RX80FULL;\r\n\r\n                    if (Extension->IrpMaskLocation) {\r\n\r\n                        *Extension->IrpMaskLocation =\r\n                         Extension->HistoryMask;\r\n                        Extension->IrpMaskLocation = NULL;\r\n                        Extension->HistoryMask = 0;\r\n\r\n                        reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n                        reqContext->Information =  sizeof(ULONG);\r\n                        SerialInsertQueueDpc(\r\n                            Extension->CommWaitDpc\r\n                            );\r\n\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            //\r\n            // Point to the next available space\r\n            // for a received character.  Make sure\r\n            // that we wrap around to the beginning\r\n            // of the buffer if this last character\r\n            // received was placed at the last slot\r\n            // in the buffer.\r\n            //\r\n\r\n            if (Extension->CurrentCharSlot ==\r\n                Extension->LastCharSlot) {\r\n\r\n                Extension->CurrentCharSlot =\r\n                    Extension->InterruptReadBuffer;\r\n\r\n            } else {\r\n\r\n                Extension->CurrentCharSlot++;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // We have a new character but no room for it.\r\n            //\r\n\r\n            Extension->PerfStats.BufferOverrunErrorCount++;\r\n            Extension->WmiPerfData.BufferOverrunErrorCount++;\r\n            Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;\r\n\r\n            if (Extension->HandFlow.FlowReplace &\r\n                SERIAL_ERROR_CHAR) {\r\n\r\n                //\r\n                // Place the error character into the last\r\n                // valid place for a character.  Be careful!,\r\n                // that place might not be the previous location!\r\n                //\r\n\r\n                if (Extension->CurrentCharSlot ==\r\n                    Extension->InterruptReadBuffer) {\r\n\r\n                    *(Extension->InterruptReadBuffer+\r\n                      (Extension->BufferSize-1)) =\r\n                      Extension->SpecialChars.ErrorChar;\r\n\r\n                } else {\r\n\r\n                    *(Extension->CurrentCharSlot-1) =\r\n                     Extension->SpecialChars.ErrorChar;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            //\r\n            // If the application has requested it, abort all reads\r\n            // and writes on an error.\r\n            //\r\n\r\n            if (Extension->HandFlow.ControlHandShake &\r\n                SERIAL_ERROR_ABORT) {\r\n\r\n                SerialInsertQueueDpc(\r\n                    Extension->CommErrorDpc\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n}\r\n\r\nUCHAR\r\nSerialProcessLSR(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine, which only runs at device level, reads the\r\n    ISR and totally processes everything that might have\r\n    changed.\r\n\r\nArguments:\r\n\r\n    Extension - The serial device extension.\r\n\r\nReturn Value:\r\n\r\n    The value of the line status register.\r\n\r\n--*/\r\n\r\n{\r\n    PREQUEST_CONTEXT reqContext = NULL;\r\n\r\n    UCHAR LineStatus = READ_LINE_STATUS(Extension, Extension->Controller);\r\n\r\n\r\n    Extension->HoldingEmpty = (LineStatus & SERIAL_LSR_THRE) ? TRUE : FALSE;\r\n\r\n    //\r\n    // If the line status register is just the fact that\r\n    // the trasmit registers are empty or a character is\r\n    // received then we want to reread the interrupt\r\n    // identification register so that we just pick up that.\r\n    //\r\n\r\n    if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT\r\n                       | SERIAL_LSR_DR)) {\r\n\r\n        //\r\n        // We have some sort of data problem in the receive.\r\n        // For any of these errors we may abort all current\r\n        // reads and writes.\r\n        //\r\n        //\r\n        // If we are inserting the value of the line status\r\n        // into the data stream then we should put the escape\r\n        // character in now.\r\n        //\r\n\r\n        if (Extension->EscapeChar) {\r\n\r\n            SerialPutChar(\r\n                Extension,\r\n                Extension->EscapeChar\r\n                );\r\n\r\n            SerialPutChar(\r\n                Extension,\r\n                (UCHAR)((LineStatus & SERIAL_LSR_DR)?\r\n                    (SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA))\r\n                );\r\n\r\n            SerialPutChar(\r\n                Extension,\r\n                LineStatus\r\n                );\r\n\r\n            if (LineStatus & SERIAL_LSR_DR) {\r\n\r\n                Extension->PerfStats.ReceivedCount++;\r\n                Extension->WmiPerfData.ReceivedCount++;\r\n                SerialPutChar(\r\n                    Extension,\r\n                    READ_RECEIVE_BUFFER(Extension, Extension->Controller)\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if (LineStatus & SERIAL_LSR_OE) {\r\n\r\n            Extension->PerfStats.SerialOverrunErrorCount++;\r\n            Extension->WmiPerfData.SerialOverrunErrorCount++;\r\n            Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;\r\n\r\n            if (Extension->HandFlow.FlowReplace &\r\n                SERIAL_ERROR_CHAR) {\r\n\r\n                SerialPutChar(\r\n                    Extension,\r\n                    Extension->SpecialChars.ErrorChar\r\n                    );\r\n\r\n                if (LineStatus & SERIAL_LSR_DR) {\r\n\r\n                    Extension->PerfStats.ReceivedCount++;\r\n                    Extension->WmiPerfData.ReceivedCount++;\r\n                    READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n                }\r\n\r\n            } else {\r\n\r\n                if (LineStatus & SERIAL_LSR_DR) {\r\n\r\n                    Extension->PerfStats.ReceivedCount++;\r\n                    Extension->WmiPerfData.ReceivedCount++;\r\n                    SerialPutChar(\r\n                        Extension,\r\n                        READ_RECEIVE_BUFFER(Extension,\r\n                            Extension->Controller\r\n                            )\r\n                        );\r\n\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if (LineStatus & SERIAL_LSR_BI) {\r\n\r\n            Extension->ErrorWord |= SERIAL_ERROR_BREAK;\r\n\r\n            if (Extension->HandFlow.FlowReplace &\r\n                SERIAL_BREAK_CHAR) {\r\n\r\n                SerialPutChar(\r\n                    Extension,\r\n                    Extension->SpecialChars.BreakChar\r\n                    );\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // Framing errors only count if they\r\n            // occur exclusive of a break being\r\n            // received.\r\n            //\r\n\r\n            if (LineStatus & SERIAL_LSR_PE) {\r\n\r\n                Extension->PerfStats.ParityErrorCount++;\r\n                Extension->WmiPerfData.ParityErrorCount++;\r\n                Extension->ErrorWord |= SERIAL_ERROR_PARITY;\r\n\r\n                if (Extension->HandFlow.FlowReplace &\r\n                    SERIAL_ERROR_CHAR) {\r\n\r\n                    SerialPutChar(\r\n                        Extension,\r\n                        Extension->SpecialChars.ErrorChar\r\n                        );\r\n\r\n                    if (LineStatus & SERIAL_LSR_DR) {\r\n\r\n                        Extension->PerfStats.ReceivedCount++;\r\n                        Extension->WmiPerfData.ReceivedCount++;\r\n                        READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            if (LineStatus & SERIAL_LSR_FE) {\r\n\r\n                Extension->PerfStats.FrameErrorCount++;\r\n                Extension->WmiPerfData.FrameErrorCount++;\r\n                Extension->ErrorWord |= SERIAL_ERROR_FRAMING;\r\n\r\n                if (Extension->HandFlow.FlowReplace &\r\n                    SERIAL_ERROR_CHAR) {\r\n\r\n                    SerialPutChar(\r\n                        Extension,\r\n                        Extension->SpecialChars.ErrorChar\r\n                        );\r\n                    if (LineStatus & SERIAL_LSR_DR) {\r\n\r\n                        Extension->PerfStats.ReceivedCount++;\r\n                        Extension->WmiPerfData.ReceivedCount++;\r\n                        READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        //\r\n        // If the application has requested it,\r\n        // abort all the reads and writes\r\n        // on an error.\r\n        //\r\n\r\n        if (Extension->HandFlow.ControlHandShake &\r\n            SERIAL_ERROR_ABORT) {\r\n\r\n            SerialInsertQueueDpc(\r\n                Extension->CommErrorDpc\r\n                );\r\n\r\n        }\r\n\r\n        //\r\n        // Check to see if we have a wait\r\n        // pending on the comm error events.  If we\r\n        // do then we schedule a dpc to satisfy\r\n        // that wait.\r\n        //\r\n\r\n        if (Extension->IsrWaitMask) {\r\n\r\n            if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&\r\n                (LineStatus & (SERIAL_LSR_OE |\r\n                               SERIAL_LSR_PE |\r\n                               SERIAL_LSR_FE))) {\r\n\r\n                Extension->HistoryMask |= SERIAL_EV_ERR;\r\n\r\n            }\r\n\r\n            if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&\r\n                (LineStatus & SERIAL_LSR_BI)) {\r\n\r\n                Extension->HistoryMask |= SERIAL_EV_BREAK;\r\n\r\n            }\r\n\r\n            if (Extension->IrpMaskLocation &&\r\n                Extension->HistoryMask) {\r\n\r\n                *Extension->IrpMaskLocation =\r\n                 Extension->HistoryMask;\r\n                Extension->IrpMaskLocation = NULL;\r\n                Extension->HistoryMask = 0;\r\n                reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n                reqContext->Information =  sizeof(ULONG);\r\n                SerialInsertQueueDpc(\r\n                    Extension->CommWaitDpc\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n        if (LineStatus & SERIAL_LSR_THRE) {\r\n\r\n            //\r\n            // There is a hardware bug in some versions\r\n            // of the 16450 and 550.  If THRE interrupt\r\n            // is pending, but a higher interrupt comes\r\n            // in it will only return the higher and\r\n            // *forget* about the THRE.\r\n            //\r\n            // A suitable workaround - whenever we\r\n            // are *all* done reading line status\r\n            // of the device we check to see if the\r\n            // transmit holding register is empty.  If it is\r\n            // AND we are currently transmitting data\r\n            // enable the interrupts which should cause\r\n            // an interrupt indication which we quiet\r\n            // when we read the interrupt id register.\r\n            //\r\n\r\n            if (Extension->WriteLength |\r\n                Extension->TransmitImmediate) {\r\n\r\n                DISABLE_ALL_INTERRUPTS(Extension,\r\n                    Extension->Controller\r\n                    );\r\n                ENABLE_ALL_INTERRUPTS(Extension,\r\n                    Extension->Controller\r\n                    );\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return LineStatus;\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/log.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    log.c\r\n\r\nAbstract:\r\n\r\n    Debug log Code for serial.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\nextern ULONG DebugLevel;\r\nextern ULONG DebugFlag;\r\n\r\n#if !defined(EVENT_TRACING)\r\n\r\nVOID\r\nSerialDbgPrintEx    (\r\n    IN ULONG   TraceEventsLevel,\r\n    IN ULONG   TraceEventsFlag,\r\n    IN PCCHAR  DebugMessage,\r\n    ...\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Debug print for the sample driver.\r\n\r\nArguments:\r\n\r\n    TraceEventsLevel - print level between 0 and 3, with 3 the most verbose\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n --*/\r\n {\r\n#if DBG\r\n\r\n#define     TEMP_BUFFER_SIZE        1024\r\n\r\n    va_list    list;\r\n    CHAR      debugMessageBuffer [TEMP_BUFFER_SIZE];\r\n    NTSTATUS   status;\r\n\r\n    va_start(list, DebugMessage);\r\n\r\n    if (DebugMessage) {\r\n\r\n        //\r\n        // Using new safe string functions instead of _vsnprintf.\r\n        // This function takes care of NULL terminating if the message\r\n        // is longer than the buffer.\r\n        //\r\n        status = RtlStringCbVPrintfA( debugMessageBuffer,\r\n                                      sizeof(debugMessageBuffer),\r\n                                      DebugMessage,\r\n                                      list );\r\n        if(!NT_SUCCESS(status)) {\r\n\r\n            KdPrint((_DRIVER_NAME_\": RtlStringCbVPrintfA failed %x\\n\", status));\r\n            return;\r\n        }\r\n        if (TraceEventsLevel < TRACE_LEVEL_INFORMATION ||\r\n            (TraceEventsLevel <= DebugLevel &&\r\n             ((TraceEventsFlag & DebugFlag) == TraceEventsFlag))) {\r\n\r\n            KdPrint((debugMessageBuffer));\r\n        }\r\n    }\r\n    va_end(list);\r\n\r\n    return;\r\n\r\n#else\r\n\r\n    UNREFERENCED_PARAMETER(TraceEventsLevel);\r\n    UNREFERENCED_PARAMETER(TraceEventsFlag);\r\n    UNREFERENCED_PARAMETER(DebugMessage);\r\n\r\n#endif\r\n}\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/log.h",
    "content": "/*++\r\n\r\nCopyright (c) 1993  Microsoft Corporation\r\n:ts=4\r\n\r\nModule Name:\r\n\r\n    log.h\r\n\r\nAbstract:\r\n\r\n    debug macros\r\n\r\nEnvironment:\r\n\r\n    Kernel & user mode\r\n\r\n--*/\r\n\r\n#ifndef   __LOG_H__\r\n#define   __LOG_H__\r\n\r\n#if !defined(EVENT_TRACING)\r\n\r\nVOID\r\nSerialDbgPrintEx    (\r\n    IN ULONG   DebugPrintLevel,\r\n    IN ULONG   DebugPrintFlag,\r\n    IN PCCHAR  DebugMessage,\r\n    ...\r\n    );\r\n\r\n#endif\r\n\r\n#endif // __LOG_H__\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/modmflow.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    modmflow.c\r\n\r\nAbstract:\r\n\r\n    This module contains *MOST* of the code used to manipulate\r\n    the modem control and status registers.  The vast majority\r\n    of the remainder of flow control is concentrated in the\r\n    Interrupt service routine.  A very small amount resides\r\n    in the read code that pull characters out of the interrupt\r\n    buffer.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"modmflow.tmh\"\r\n#endif\r\n\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialDecrementRTSCounter;\r\n\r\nBOOLEAN\r\nSerialSetDTR(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine which is only called at interrupt level is used\r\n    to set the DTR in the modem control register.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    UCHAR ModemControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n    ModemControl |= SERIAL_MCR_DTR;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,\r\n                     \"Setting DTR for %p\\n\", Extension->Controller);\r\n\r\n    WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl);\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialClrDTR(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine which is only called at interrupt level is used\r\n    to clear the DTR in the modem control register.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    UCHAR ModemControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n    ModemControl &= ~SERIAL_MCR_DTR;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Clearing DTR for %p\\n\", Extension->Controller);\r\n\r\n    WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl);\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialSetRTS(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine which is only called at interrupt level is used\r\n    to set the RTS in the modem control register.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    UCHAR ModemControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n    ModemControl |= SERIAL_MCR_RTS;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Setting Rts for %p\\n\", Extension->Controller);\r\n\r\n    WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl);\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialClrRTS(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine which is only called at interrupt level is used\r\n    to clear the RTS in the modem control register.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    UCHAR ModemControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ModemControl = READ_MODEM_CONTROL(Extension, Extension->Controller);\r\n\r\n    ModemControl &= ~SERIAL_MCR_RTS;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Clearing Rts for %p\\n\", Extension->Controller);\r\n\r\n    WRITE_MODEM_CONTROL(Extension, Extension->Controller, ModemControl);\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialSetupNewHandFlow(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PSERIAL_HANDFLOW NewHandFlow\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine adjusts the flow control based on new\r\n    control flow.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the serial device extension.\r\n\r\n    NewHandFlow - A pointer to a serial handflow structure\r\n                  that is to become the new setup for flow\r\n                  control.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    SERIAL_HANDFLOW New = *NewHandFlow;\r\n\r\n    //\r\n    // If the Extension->DeviceIsOpened is FALSE that means\r\n    // we are entering this routine in response to an open request.\r\n    // If that is so, then we always proceed with the work regardless\r\n    // of whether things have changed.\r\n    //\r\n\r\n    //\r\n    // First we take care of the DTR flow control.  We only\r\n    // do work if something has changed.\r\n    //\r\n\r\n    if ((!Extension->DeviceIsOpened) ||\r\n        ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=\r\n         (New.ControlHandShake & SERIAL_DTR_MASK))) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Processing DTR flow for %p\\n\",\r\n                         Extension->Controller);\r\n\r\n        if (New.ControlHandShake & SERIAL_DTR_MASK) {\r\n\r\n            //\r\n            // Well we might want to set DTR.\r\n            //\r\n            // Before we do, we need to check whether we are doing\r\n            // dtr flow control.  If we are then we need to check\r\n            // if then number of characters in the interrupt buffer\r\n            // exceeds the XoffLimit.  If it does then we don't\r\n            // enable DTR AND we set the RXHolding to record that\r\n            // we are holding because of the dtr.\r\n            //\r\n\r\n            if ((New.ControlHandShake & SERIAL_DTR_MASK)\r\n                == SERIAL_DTR_HANDSHAKE) {\r\n\r\n                if ((Extension->BufferSize - New.XoffLimit) >\r\n                    Extension->CharsInInterruptBuffer) {\r\n\r\n                    //\r\n                    // However if we are already holding we don't want\r\n                    // to turn it back on unless we exceed the Xon\r\n                    // limit.\r\n                    //\r\n\r\n                    if (Extension->RXHolding & SERIAL_RX_DTR) {\r\n\r\n                        //\r\n                        // We can assume that its DTR line is already low.\r\n                        //\r\n\r\n                        if (Extension->CharsInInterruptBuffer >\r\n                            (ULONG)New.XonLimit) {\r\n\r\n                            SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Removing DTR block on \"\r\n                                             \"reception for %p\\n\",\r\n                                             Extension->Controller);\r\n\r\n                            Extension->RXHolding &= ~SERIAL_RX_DTR;\r\n                            SerialSetDTR(Extension->WdfInterrupt, Extension);\r\n\r\n                        }\r\n\r\n                    } else {\r\n\r\n                        SerialSetDTR(Extension->WdfInterrupt, Extension);\r\n\r\n                    }\r\n\r\n                } else {\r\n\r\n                    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Setting DTR block on reception \"\r\n                                     \"for %p\\n\", Extension->Controller);\r\n                    Extension->RXHolding |= SERIAL_RX_DTR;\r\n                    SerialClrDTR(Extension->WdfInterrupt, Extension);\r\n\r\n                }\r\n\r\n            } else {\r\n\r\n                //\r\n                // Note that if we aren't currently doing dtr flow control then\r\n                // we MIGHT have been.  So even if we aren't currently doing\r\n                // DTR flow control, we should still check if RX is holding\r\n                // because of DTR.  If it is, then we should clear the holding\r\n                // of this bit.\r\n                //\r\n\r\n                if (Extension->RXHolding & SERIAL_RX_DTR) {\r\n                    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Removing dtr block of reception \"\r\n                                     \"for %p\\n\", Extension->Controller);\r\n                    Extension->RXHolding &= ~SERIAL_RX_DTR;\r\n                }\r\n\r\n                SerialSetDTR(Extension->WdfInterrupt, Extension);\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // The end result here will be that DTR is cleared.\r\n            //\r\n            // We first need to check whether reception is being held\r\n            // up because of previous DTR flow control.  If it is then\r\n            // we should clear that reason in the RXHolding mask.\r\n            //\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_DTR) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"removing dtr block of reception for\"\r\n                                 \" %p\\n\", Extension->Controller);\r\n                Extension->RXHolding &= ~SERIAL_RX_DTR;\r\n\r\n            }\r\n\r\n            SerialClrDTR(Extension->WdfInterrupt, Extension);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // Time to take care of the RTS Flow control.\r\n    //\r\n    // First we only do work if something has changed.\r\n    //\r\n\r\n    if ((!Extension->DeviceIsOpened) ||\r\n        ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) !=\r\n         (New.FlowReplace & SERIAL_RTS_MASK))) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Processing RTS flow %p\\n\",\r\n                         Extension->Controller);\r\n\r\n        if ((New.FlowReplace & SERIAL_RTS_MASK) ==\r\n            SERIAL_RTS_HANDSHAKE) {\r\n\r\n            //\r\n            // Well we might want to set RTS.\r\n            //\r\n            // Before we do, we need to check whether we are doing\r\n            // rts flow control.  If we are then we need to check\r\n            // if then number of characters in the interrupt buffer\r\n            // exceeds the XoffLimit.  If it does then we don't\r\n            // enable RTS AND we set the RXHolding to record that\r\n            // we are holding because of the rts.\r\n            //\r\n\r\n            if ((Extension->BufferSize - New.XoffLimit) >\r\n                Extension->CharsInInterruptBuffer) {\r\n\r\n                //\r\n                // However if we are already holding we don't want\r\n                // to turn it back on unless we exceed the Xon\r\n                // limit.\r\n                //\r\n\r\n                if (Extension->RXHolding & SERIAL_RX_RTS) {\r\n\r\n                    //\r\n                    // We can assume that its RTS line is already low.\r\n                    //\r\n\r\n                    if (Extension->CharsInInterruptBuffer >\r\n                        (ULONG)New.XonLimit) {\r\n\r\n                       SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Removing rts block of \"\r\n                                        \"reception for %p\\n\",\r\n                                        Extension->Controller);\r\n                        Extension->RXHolding &= ~SERIAL_RX_RTS;\r\n                        SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                    }\r\n\r\n                } else {\r\n\r\n                    SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n                }\r\n\r\n            } else {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Setting rts block of reception for \"\r\n                                 \"%p\\n\", Extension->Controller);\r\n                Extension->RXHolding |= SERIAL_RX_RTS;\r\n                SerialClrRTS(Extension->WdfInterrupt, Extension);\r\n\r\n            }\r\n\r\n        } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==\r\n                   SERIAL_RTS_CONTROL) {\r\n\r\n            //\r\n            // Note that if we aren't currently doing rts flow control then\r\n            // we MIGHT have been.  So even if we aren't currently doing\r\n            // RTS flow control, we should still check if RX is holding\r\n            // because of RTS.  If it is, then we should clear the holding\r\n            // of this bit.\r\n            //\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_RTS) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Clearing rts block of reception for \"\r\n                                 \"%p\\n\", Extension->Controller);\r\n                Extension->RXHolding &= ~SERIAL_RX_RTS;\r\n\r\n            }\r\n\r\n            SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n        } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==\r\n                   SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n            //\r\n            // We first need to check whether reception is being held\r\n            // up because of previous RTS flow control.  If it is then\r\n            // we should clear that reason in the RXHolding mask.\r\n            //\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_RTS) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"TOGGLE Clearing rts block of \"\r\n                                 \"reception for %p\\n\", Extension->Controller);\r\n                Extension->RXHolding &= ~SERIAL_RX_RTS;\r\n\r\n            }\r\n\r\n            //\r\n            // We have to place the rts value into the Extension\r\n            // now so that the code that tests whether the\r\n            // rts line should be lowered will find that we\r\n            // are \"still\" doing transmit toggling.  The code\r\n            // for lowering can be invoked later by a timer so\r\n            // it has to test whether it still needs to do its\r\n            // work.\r\n            //\r\n\r\n            Extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;\r\n            Extension->HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;\r\n\r\n            //\r\n            // The order of the tests is very important below.\r\n            //\r\n            // If there is a break then we should turn on the RTS.\r\n            //\r\n            // If there isn't a break but there are characters in\r\n            // the hardware, then turn on the RTS.\r\n            //\r\n            // If there are writes pending that aren't being held\r\n            // up, then turn on the RTS.\r\n            //\r\n\r\n            if ((Extension->TXHolding & SERIAL_TX_BREAK) ||\r\n                ((SerialProcessLSR(Extension) & (SERIAL_LSR_THRE |\r\n                                                 SERIAL_LSR_TEMT)) !=\r\n                                                (SERIAL_LSR_THRE |\r\n                                                 SERIAL_LSR_TEMT)) ||\r\n                (Extension->CurrentWriteRequest || Extension->TransmitImmediate ||\r\n                 (!IsQueueEmpty(Extension->WriteQueue)) &&\r\n                 (!Extension->TXHolding))) {\r\n\r\n                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n            } else {\r\n\r\n                //\r\n                // This routine will check to see if it is time\r\n                // to lower the RTS because of transmit toggle\r\n                // being on.  If it is ok to lower it, it will,\r\n                // if it isn't ok, it will schedule things so\r\n                // that it will get lowered later.\r\n                //\r\n\r\n                Extension->CountOfTryingToLowerRTS++;\r\n                SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension);\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // The end result here will be that RTS is cleared.\r\n            //\r\n            // We first need to check whether reception is being held\r\n            // up because of previous RTS flow control.  If it is then\r\n            // we should clear that reason in the RXHolding mask.\r\n            //\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_RTS) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, \"Clearing rts block of reception for\"\r\n                                 \" %p\\n\", Extension->Controller);\r\n                Extension->RXHolding &= ~SERIAL_RX_RTS;\r\n\r\n            }\r\n\r\n            SerialClrRTS(Extension->WdfInterrupt, Extension);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // We now take care of automatic receive flow control.\r\n    // We only do work if things have changed.\r\n    //\r\n\r\n    if ((!Extension->DeviceIsOpened) ||\r\n        ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=\r\n         (New.FlowReplace & SERIAL_AUTO_RECEIVE))) {\r\n\r\n        if (New.FlowReplace & SERIAL_AUTO_RECEIVE) {\r\n\r\n            //\r\n            // We wouldn't be here if it had been on before.\r\n            //\r\n            // We should check to see whether we exceed the turn\r\n            // off limits.\r\n            //\r\n            // Note that since we are following the OS/2 flow\r\n            // control rules we will never send an xon if\r\n            // when enabling xon/xoff flow control we discover that\r\n            // we could receive characters but we are held up do\r\n            // to a previous Xoff.\r\n            //\r\n\r\n            if ((Extension->BufferSize - New.XoffLimit) <=\r\n                Extension->CharsInInterruptBuffer) {\r\n\r\n                //\r\n                // Cause the Xoff to be sent.\r\n                //\r\n\r\n                Extension->RXHolding |= SERIAL_RX_XOFF;\r\n\r\n                SerialProdXonXoff(\r\n                    Extension,\r\n                    FALSE\r\n                    );\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // The app has disabled automatic receive flow control.\r\n            //\r\n            // If transmission was being held up because of\r\n            // an automatic receive Xoff, then we should\r\n            // cause an Xon to be sent.\r\n            //\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_XOFF) {\r\n\r\n                Extension->RXHolding &= ~SERIAL_RX_XOFF;\r\n\r\n                //\r\n                // Cause the Xon to be sent.\r\n                //\r\n\r\n                SerialProdXonXoff(\r\n                    Extension,\r\n                    TRUE\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // We now take care of automatic transmit flow control.\r\n    // We only do work if things have changed.\r\n    //\r\n\r\n    if ((!Extension->DeviceIsOpened) ||\r\n        ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) !=\r\n         (New.FlowReplace & SERIAL_AUTO_TRANSMIT))) {\r\n\r\n        if (New.FlowReplace & SERIAL_AUTO_TRANSMIT) {\r\n\r\n            //\r\n            // We wouldn't be here if it had been on before.\r\n            //\r\n            // There is some belief that if autotransmit\r\n            // was just enabled, I should go look in what we\r\n            // already received, and if we find the xoff character\r\n            // then we should stop transmitting.  I think this\r\n            // is an application bug.  For now we just care about\r\n            // what we see in the future.\r\n            //\r\n\r\n            ;\r\n\r\n        } else {\r\n\r\n            //\r\n            // The app has disabled automatic transmit flow control.\r\n            //\r\n            // If transmission was being held up because of\r\n            // an automatic transmit Xoff, then we should\r\n            // cause an Xon to be sent.\r\n            //\r\n\r\n            if (Extension->TXHolding & SERIAL_TX_XOFF) {\r\n\r\n                Extension->TXHolding &= ~SERIAL_TX_XOFF;\r\n\r\n                //\r\n                // Cause the Xon to be sent.\r\n                //\r\n\r\n                SerialProdXonXoff(\r\n                    Extension,\r\n                    TRUE\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // At this point we can simply make sure that entire\r\n    // handflow structure in the extension is updated.\r\n    //\r\n\r\n    Extension->HandFlow = New;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialSetHandFlow(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the handshake and control\r\n    flow in the device extension.\r\n\r\nArguments:\r\n\r\n    Context - Pointer to a structure that contains a pointer to\r\n              the device extension and a pointer to a handflow\r\n              structure..\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_IOCTL_SYNC S = Context;\r\n    PSERIAL_DEVICE_EXTENSION Extension = S->Extension;\r\n    PSERIAL_HANDFLOW HandFlow = S->Data;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    SerialSetupNewHandFlow(\r\n        Extension,\r\n        HandFlow\r\n        );\r\n\r\n    SerialHandleModemUpdate(\r\n        Extension,\r\n        FALSE\r\n        );\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialTurnOnBreak(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will turn on break in the hardware and\r\n    record the fact the break is on, in the extension variable\r\n    that holds reasons that transmission is stopped.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UCHAR OldLineControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==\r\n        SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n        SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n    }\r\n\r\n    OldLineControl = READ_LINE_CONTROL(Extension, Extension->Controller);\r\n\r\n    OldLineControl |= SERIAL_LCR_BREAK;\r\n\r\n    WRITE_LINE_CONTROL(Extension,\r\n        Extension->Controller,\r\n        OldLineControl\r\n        );\r\n\r\n    Extension->TXHolding |= SERIAL_TX_BREAK;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialTurnOffBreak(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will turn off break in the hardware and\r\n    record the fact the break is off, in the extension variable\r\n    that holds reasons that transmission is stopped.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UCHAR OldLineControl;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    if (Extension->TXHolding & SERIAL_TX_BREAK) {\r\n\r\n        //\r\n        // We actually have a good reason for testing if transmission\r\n        // is holding instead of blindly clearing the bit.\r\n        //\r\n        // If transmission actually was holding and the result of\r\n        // clearing the bit is that we should restart transmission\r\n        // then we will poke the interrupt enable bit, which will\r\n        // cause an actual interrupt and transmission will then\r\n        // restart on its own.\r\n        //\r\n        // If transmission wasn't holding and we poked the bit\r\n        // then we would interrupt before a character actually made\r\n        // it out and we could end up over writing a character in\r\n        // the transmission hardware.\r\n\r\n        OldLineControl = READ_LINE_CONTROL(Extension, Extension->Controller);\r\n\r\n        OldLineControl &= ~SERIAL_LCR_BREAK;\r\n\r\n        WRITE_LINE_CONTROL(Extension,\r\n            Extension->Controller,\r\n            OldLineControl\r\n            );\r\n\r\n        Extension->TXHolding &= ~SERIAL_TX_BREAK;\r\n\r\n        if (!Extension->TXHolding &&\r\n            (Extension->TransmitImmediate ||\r\n             Extension->WriteLength) &&\r\n             Extension->HoldingEmpty) {\r\n\r\n            DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n            ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n        } else {\r\n\r\n            //\r\n            // The following routine will lower the rts if we\r\n            // are doing transmit toggleing and there is no\r\n            // reason to keep it up.\r\n            //\r\n\r\n            Extension->CountOfTryingToLowerRTS++;\r\n            SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialPretendXoff(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to process the Ioctl that request the\r\n    driver to act as if an Xoff was received.  Even if the\r\n    driver does not have automatic Xoff/Xon flowcontrol - This\r\n    still will stop the transmission.  This is the OS/2 behavior\r\n    and is not well specified for Windows.  Therefore we adopt\r\n    the OS/2 behavior.\r\n\r\n    Note: If the driver does not have automatic Xoff/Xon enabled\r\n    then the only way to restart transmission is for the\r\n    application to request we \"act\" as if we saw the xon.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    Extension->TXHolding |= SERIAL_TX_XOFF;\r\n\r\n    if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==\r\n        SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n        SerialInsertQueueDpc(\r\n            Extension->StartTimerLowerRTSDpc\r\n            )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialPretendXon(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to process the Ioctl that request the\r\n    driver to act as if an Xon was received.\r\n\r\n    Note: If the driver does not have automatic Xoff/Xon enabled\r\n    then the only way to restart transmission is for the\r\n    application to request we \"act\" as if we saw the xon.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    if (Extension->TXHolding) {\r\n\r\n        //\r\n        // We actually have a good reason for testing if transmission\r\n        // is holding instead of blindly clearing the bit.\r\n        //\r\n        // If transmission actually was holding and the result of\r\n        // clearing the bit is that we should restart transmission\r\n        // then we will poke the interrupt enable bit, which will\r\n        // cause an actual interrupt and transmission will then\r\n        // restart on its own.\r\n        //\r\n        // If transmission wasn't holding and we poked the bit\r\n        // then we would interrupt before a character actually made\r\n        // it out and we could end up over writing a character in\r\n        // the transmission hardware.\r\n\r\n        Extension->TXHolding &= ~SERIAL_TX_XOFF;\r\n\r\n        if (!Extension->TXHolding &&\r\n            (Extension->TransmitImmediate ||\r\n             Extension->WriteLength) &&\r\n             Extension->HoldingEmpty) {\r\n\r\n            DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n            ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nVOID\r\nSerialHandleReducedIntBuffer(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called to handle a reduction in the number\r\n    of characters in the interrupt (typeahead) buffer.  It\r\n    will check the current output flow control and re-enable transmission\r\n    as needed.\r\n\r\n    NOTE: This routine assumes that it is working at interrupt level.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n\r\n    //\r\n    // If we are doing receive side flow control and we are\r\n    // currently \"holding\" then because we've emptied out\r\n    // some characters from the interrupt buffer we need to\r\n    // see if we can \"re-enable\" reception.\r\n    //\r\n\r\n    if (Extension->RXHolding) {\r\n\r\n        if (Extension->CharsInInterruptBuffer <=\r\n            (ULONG)Extension->HandFlow.XonLimit) {\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_DTR) {\r\n\r\n                Extension->RXHolding &= ~SERIAL_RX_DTR;\r\n                SerialSetDTR(Extension->WdfInterrupt, Extension);\r\n\r\n            }\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_RTS) {\r\n\r\n                Extension->RXHolding &= ~SERIAL_RX_RTS;\r\n                SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n            }\r\n\r\n            if (Extension->RXHolding & SERIAL_RX_XOFF) {\r\n\r\n                //\r\n                // Prod the transmit code to send xon.\r\n                //\r\n\r\n                SerialProdXonXoff(\r\n                    Extension,\r\n                    TRUE\r\n                    );\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n}\r\n\r\nVOID\r\nSerialProdXonXoff(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN BOOLEAN SendXon\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will set up the SendXxxxChar variables if\r\n    necessary and determine if we are going to be interrupting\r\n    because of current transmission state.  It will cause an\r\n    interrupt to occur if neccessary, to send the xon/xoff char.\r\n\r\n    NOTE: This routine assumes that it is called at interrupt\r\n          level.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the serial device extension.\r\n\r\n    SendXon - If a character is to be send, this indicates whether\r\n              it should be an Xon or an Xoff.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    //\r\n    // We assume that if the prodding is called more than\r\n    // once that the last prod has set things up appropriately.\r\n    //\r\n    // We could get called before the character is sent out\r\n    // because the send of the character was blocked because\r\n    // of hardware flow control (or break).\r\n    //\r\n\r\n    if (!Extension->SendXonChar && !Extension->SendXoffChar\r\n        && Extension->HoldingEmpty) {\r\n\r\n        DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n        ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n    }\r\n\r\n    if (SendXon) {\r\n\r\n        Extension->SendXonChar = TRUE;\r\n        Extension->SendXoffChar = FALSE;\r\n\r\n    } else {\r\n\r\n        Extension->SendXonChar = FALSE;\r\n        Extension->SendXoffChar = TRUE;\r\n\r\n    }\r\n\r\n}\r\n\r\nULONG\r\nSerialHandleModemUpdate(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN BOOLEAN DoingTX\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will be to check on the modem status, and\r\n    handle any appropriate event notification as well as\r\n    any flow control appropriate to modem status lines.\r\n\r\n    NOTE: This routine assumes that it is called at interrupt\r\n          level.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the serial device extension.\r\n\r\n    DoingTX - This boolean is used to indicate that this call\r\n              came from the transmit processing code.  If this\r\n              is true then there is no need to cause a new interrupt\r\n              since the code will be trying to send the next\r\n              character as soon as this call finishes.\r\n\r\nReturn Value:\r\n\r\n    This returns the old value of the modem status register\r\n    (extended into a ULONG).\r\n\r\n--*/\r\n\r\n{\r\n\r\n    //\r\n    // We keep this local so that after we are done\r\n    // examining the modem status and we've updated\r\n    // the transmission holding value, we know whether\r\n    // we've changed from needing to hold up transmission\r\n    // to transmission being able to proceed.\r\n    //\r\n    ULONG OldTXHolding = Extension->TXHolding;\r\n\r\n    //\r\n    // Holds the value in the mode status register.\r\n    //\r\n    UCHAR ModemStatus;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    ModemStatus =\r\n    READ_MODEM_STATUS(Extension, Extension->Controller);\r\n\r\n\r\n    //\r\n    // If we are placeing the modem status into the data stream\r\n    // on every change, we should do it now.\r\n    //\r\n\r\n    if (Extension->EscapeChar) {\r\n\r\n        if (ModemStatus & (SERIAL_MSR_DCTS |\r\n                           SERIAL_MSR_DDSR |\r\n                           SERIAL_MSR_TERI |\r\n                           SERIAL_MSR_DDCD)) {\r\n\r\n            SerialPutChar(\r\n                Extension,\r\n                Extension->EscapeChar\r\n                );\r\n            SerialPutChar(\r\n                Extension,\r\n                SERIAL_LSRMST_MST\r\n                );\r\n            SerialPutChar(\r\n                Extension,\r\n                ModemStatus\r\n                );\r\n\r\n        }\r\n\r\n    }\r\n\r\n\r\n    //\r\n    // Take care of input flow control based on sensitivity\r\n    // to the DSR.  This is done so that the application won't\r\n    // see spurious data generated by odd devices.\r\n    //\r\n    // Basically, if we are doing dsr sensitivity then the\r\n    // driver should only accept data when the dsr bit is\r\n    // set.\r\n    //\r\n\r\n    if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) {\r\n\r\n        if (ModemStatus & SERIAL_MSR_DSR) {\r\n\r\n            //\r\n            // The line is high.  Simply make sure that\r\n            // RXHolding does't have the DSR bit.\r\n            //\r\n\r\n            Extension->RXHolding &= ~SERIAL_RX_DSR;\r\n\r\n        } else {\r\n\r\n            Extension->RXHolding |= SERIAL_RX_DSR;\r\n\r\n        }\r\n\r\n    } else {\r\n\r\n        //\r\n        // We don't have sensitivity due to DSR.  Make sure we\r\n        // arn't holding. (We might have been, but the app just\r\n        // asked that we don't hold for this reason any more.)\r\n        //\r\n\r\n        Extension->RXHolding &= ~SERIAL_RX_DSR;\r\n\r\n    }\r\n\r\n    //\r\n    // Check to see if we have a wait\r\n    // pending on the modem status events.  If we\r\n    // do then we schedule a dpc to satisfy\r\n    // that wait.\r\n    //\r\n\r\n    if (Extension->IsrWaitMask) {\r\n\r\n        if ((Extension->IsrWaitMask & SERIAL_EV_CTS) &&\r\n            (ModemStatus & SERIAL_MSR_DCTS)) {\r\n\r\n            Extension->HistoryMask |= SERIAL_EV_CTS;\r\n\r\n        }\r\n\r\n        if ((Extension->IsrWaitMask & SERIAL_EV_DSR) &&\r\n            (ModemStatus & SERIAL_MSR_DDSR)) {\r\n\r\n            Extension->HistoryMask |= SERIAL_EV_DSR;\r\n\r\n        }\r\n\r\n        if ((Extension->IsrWaitMask & SERIAL_EV_RING) &&\r\n            (ModemStatus & SERIAL_MSR_TERI)) {\r\n\r\n            Extension->HistoryMask |= SERIAL_EV_RING;\r\n\r\n        }\r\n\r\n        if ((Extension->IsrWaitMask & SERIAL_EV_RLSD) &&\r\n            (ModemStatus & SERIAL_MSR_DDCD)) {\r\n\r\n            Extension->HistoryMask |= SERIAL_EV_RLSD;\r\n\r\n        }\r\n\r\n        if (Extension->IrpMaskLocation &&\r\n            Extension->HistoryMask) {\r\n\r\n            *Extension->IrpMaskLocation =\r\n             Extension->HistoryMask;\r\n            Extension->IrpMaskLocation = NULL;\r\n            Extension->HistoryMask = 0;\r\n\r\n            reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n            reqContext->Information = sizeof(ULONG);\r\n            SerialInsertQueueDpc(\r\n                Extension->CommWaitDpc\r\n                );\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // If the app has modem line flow control then\r\n    // we check to see if we have to hold up transmission.\r\n    //\r\n\r\n    if (Extension->HandFlow.ControlHandShake &\r\n        SERIAL_OUT_HANDSHAKEMASK) {\r\n\r\n        if (Extension->HandFlow.ControlHandShake &\r\n            SERIAL_CTS_HANDSHAKE) {\r\n\r\n            if (ModemStatus & SERIAL_MSR_CTS) {\r\n\r\n                Extension->TXHolding &= ~SERIAL_TX_CTS;\r\n\r\n            } else {\r\n\r\n                Extension->TXHolding |= SERIAL_TX_CTS;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            Extension->TXHolding &= ~SERIAL_TX_CTS;\r\n\r\n        }\r\n\r\n        if (Extension->HandFlow.ControlHandShake &\r\n            SERIAL_DSR_HANDSHAKE) {\r\n\r\n            if (ModemStatus & SERIAL_MSR_DSR) {\r\n\r\n                Extension->TXHolding &= ~SERIAL_TX_DSR;\r\n\r\n            } else {\r\n\r\n                Extension->TXHolding |= SERIAL_TX_DSR;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            Extension->TXHolding &= ~SERIAL_TX_DSR;\r\n\r\n        }\r\n\r\n        if (Extension->HandFlow.ControlHandShake &\r\n            SERIAL_DCD_HANDSHAKE) {\r\n\r\n            if (ModemStatus & SERIAL_MSR_DCD) {\r\n\r\n                Extension->TXHolding &= ~SERIAL_TX_DCD;\r\n\r\n            } else {\r\n\r\n                Extension->TXHolding |= SERIAL_TX_DCD;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            Extension->TXHolding &= ~SERIAL_TX_DCD;\r\n\r\n        }\r\n\r\n        //\r\n        // If we hadn't been holding, and now we are then\r\n        // queue off a dpc that will lower the RTS line\r\n        // if we are doing transmit toggling.\r\n        //\r\n\r\n        if (!OldTXHolding && Extension->TXHolding  &&\r\n            ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==\r\n              SERIAL_TRANSMIT_TOGGLE)) {\r\n\r\n            SerialInsertQueueDpc(\r\n                Extension->StartTimerLowerRTSDpc\r\n                )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n        }\r\n\r\n        //\r\n        // We've done any adjusting that needed to be\r\n        // done to the holding mask given updates\r\n        // to the modem status.  If the Holding mask\r\n        // is clear (and it wasn't clear to start)\r\n        // and we have \"write\" work to do set things\r\n        // up so that the transmission code gets invoked.\r\n        //\r\n\r\n        if (!DoingTX && OldTXHolding && !Extension->TXHolding) {\r\n\r\n            if (!Extension->TXHolding &&\r\n                (Extension->TransmitImmediate ||\r\n                 Extension->WriteLength) &&\r\n                 Extension->HoldingEmpty) {\r\n\r\n                DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n                ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n            }\r\n\r\n        }\r\n\r\n    } else {\r\n\r\n        //\r\n        // We need to check if transmission is holding\r\n        // up because of modem status lines.  What\r\n        // could have occured is that for some strange\r\n        // reason, the app has asked that we no longer\r\n        // stop doing output flow control based on\r\n        // the modem status lines.  If however, we\r\n        // *had* been held up because of the status lines\r\n        // then we need to clear up those reasons.\r\n        //\r\n\r\n        if (Extension->TXHolding & (SERIAL_TX_DCD |\r\n                                    SERIAL_TX_DSR |\r\n                                    SERIAL_TX_CTS)) {\r\n\r\n            Extension->TXHolding &= ~(SERIAL_TX_DCD |\r\n                                      SERIAL_TX_DSR |\r\n                                      SERIAL_TX_CTS);\r\n\r\n\r\n            if (!DoingTX && OldTXHolding && !Extension->TXHolding) {\r\n\r\n                if (!Extension->TXHolding &&\r\n                    (Extension->TransmitImmediate ||\r\n                     Extension->WriteLength) &&\r\n                     Extension->HoldingEmpty) {\r\n\r\n                    DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n                    ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return ((ULONG)ModemStatus);\r\n}\r\n\r\nBOOLEAN\r\nSerialPerhapsLowerRTS(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine checks that the software reasons for lowering\r\n    the RTS lines are present.  If so, it will then cause the\r\n    line status register to be read (and any needed processing\r\n    implied by the status register to be done), and if the\r\n    shift register is empty it will lower the line.  If the\r\n    shift register isn't empty, this routine will queue off\r\n    a dpc that will start a timer, that will basically call\r\n    us back to try again.\r\n\r\n    NOTE: This routine assumes that it is called at interrupt\r\n          level.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    //\r\n    // We first need to test if we are actually still doing\r\n    // transmit toggle flow control.  If we aren't then\r\n    // we have no reason to try be here.\r\n    //\r\n\r\n    if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==\r\n        SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n        //\r\n        // The order of the tests is very important below.\r\n        //\r\n        // If there is a break then we should leave on the RTS,\r\n        // because when the break is turned off, it will submit\r\n        // the code to shut down the RTS.\r\n        //\r\n        // If there are writes pending that aren't being held\r\n        // up, then leave on the RTS, because the end of the write\r\n        // code will cause this code to be reinvoked.  If the writes\r\n        // are being held up, its ok to lower the RTS because the\r\n        // upon trying to write the first character after transmission\r\n        // is restarted, we will raise the RTS line.\r\n        //\r\n\r\n        if ((Extension->TXHolding & SERIAL_TX_BREAK) ||\r\n            (Extension->CurrentWriteRequest || Extension->TransmitImmediate ||\r\n             (!IsQueueEmpty(Extension->WriteQueue)) &&\r\n             (!Extension->TXHolding))) {\r\n\r\n            NOTHING;\r\n\r\n        } else {\r\n\r\n            //\r\n            // Looks good so far.  Call the line status check and processing\r\n            // code, it will return the \"current\" line status value.  If\r\n            // the holding and shift register are clear, lower the RTS line,\r\n            // if they aren't clear, queue of a dpc that will cause a timer\r\n            // to reinvoke us later.  We do this code here because no one\r\n            // but this routine cares about the characters in the hardware,\r\n            // so no routine by this routine will bother invoking to test\r\n            // if the hardware is empty.\r\n            //\r\n\r\n            if ((SerialProcessLSR(Extension) &\r\n                 (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=\r\n                 (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {\r\n\r\n                //\r\n                // Well it's not empty, try again later.\r\n                //\r\n\r\n                SerialInsertQueueDpc(\r\n                    Extension->StartTimerLowerRTSDpc\r\n                    )?Extension->CountOfTryingToLowerRTS++:0;\r\n\r\n\r\n            } else {\r\n\r\n                //\r\n                // Nothing in the hardware, Lower the RTS.\r\n                //\r\n\r\n                SerialClrRTS(Extension->WdfInterrupt, Extension);\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // We decement the counter to indicate that we've reached\r\n    // the end of the execution path that is trying to push\r\n    // down the RTS line.\r\n    //\r\n\r\n    Extension->CountOfTryingToLowerRTS--;\r\n\r\n    return FALSE;\r\n}\r\n\r\nVOID\r\nSerialStartTimerLowerRTS(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine starts a timer that when it expires will start\r\n    a dpc that will check if it can lower the rts line because\r\n    there are no characters in the hardware.\r\n\r\nArguments:\r\n\r\n    Dpc - Not Used.\r\n\r\n    DeferredContext - Really points to the device extension.\r\n\r\n    SystemContext1 - Not Used.\r\n\r\n    SystemContext2 - Not Used.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    LARGE_INTEGER CharTime;\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \">SerialStartTimerLowerRTS(%p)\\n\",\r\n                     Extension);\r\n\r\n\r\n    //\r\n    // Since all the callbacks into the driver are serialized, we don't have\r\n    // synchronize the access to any of the Extension variables.\r\n    //\r\n\r\n    CharTime = SerialGetCharTime(Extension);\r\n\r\n    CharTime.QuadPart = -CharTime.QuadPart;\r\n\r\n    if (SerialSetTimer(\r\n            Extension->LowerRTSTimer,\r\n            CharTime\r\n            )) {\r\n\r\n        //\r\n        // The timer was already in the timer queue.  This implies\r\n        // that one path of execution that was trying to lower\r\n        // the RTS has \"died\".  Synchronize with the ISR so that\r\n        // we can lower the count.\r\n        //\r\n\r\n        WdfInterruptSynchronize(\r\n            Extension->WdfInterrupt,\r\n            SerialDecrementRTSCounter,\r\n            Extension\r\n            );\r\n\r\n    }\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, \"<SerialStartTimerLowerRTS\\n\");\r\n\r\n}\r\n\r\nVOID\r\nSerialInvokePerhapsLowerRTS(\r\n    IN WDFTIMER Timer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This dpc routine exists solely to call the code that\r\n    tests if the rts line should be lowered when TRANSMIT\r\n    TOGGLE flow control is being used.\r\n\r\nArguments:\r\n\r\n     WDFTIMER\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n    WdfInterruptSynchronize(\r\n        Extension->WdfInterrupt,\r\n        SerialPerhapsLowerRTS,\r\n        Extension\r\n        );\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialDecrementRTSCounter(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine checks that the software reasons for lowering\r\n    the RTS lines are present.  If so, it will then cause the\r\n    line status register to be read (and any needed processing\r\n    implied by the status register to be done), and if the\r\n    shift register is empty it will lower the line.  If the\r\n    shift register isn't empty, this routine will queue off\r\n    a dpc that will start a timer, that will basically call\r\n    us back to try again.\r\n\r\n    NOTE: This routine assumes that it is called at interrupt\r\n          level.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    Extension->CountOfTryingToLowerRTS--;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/openclos.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    openclos.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to\r\n    opening, closing, and cleaning up in the serial driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"openclos.tmh\"\r\n#endif\r\n\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESER,SerialGetCharTime)\r\n#pragma alloc_text(PAGESER,SerialEvtFileClose)\r\n#pragma alloc_text(PAGESER,SerialDrainUART)\r\n#pragma alloc_text(PAGESRP0,SerialEvtDeviceFileCreate)\r\n#pragma alloc_text(PAGESRP0,SerialCreateTimersAndDpcs)\r\n#endif // ALLOC_PRAGMA\r\n\r\n\r\n\r\nVOID\r\nSerialEvtDeviceFileCreate (\r\n    IN WDFDEVICE     Device,\r\n    IN WDFREQUEST    Request,\r\n    IN WDFFILEOBJECT FileObject\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    The framework calls a driver's EvtDeviceFileCreate callback\r\n    when the framework receives an IRP_MJ_CREATE request.\r\n    The system sends this request when a user application opens the\r\n    device to perform an I/O operation, such as reading or writing a file.\r\n    This callback is called synchronously, in the context of the thread\r\n    that created the IRP_MJ_CREATE request.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n    FileObject - Pointer to fileobject that represents the open handle.\r\n    CreateParams - Copy of the Create IO_STACK_LOCATION\r\n\r\nReturn Value:\r\n\r\n   VOID.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);\r\n\r\n    UNREFERENCED_PARAMETER(FileObject);\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE,\r\n                     \"SerialEvtDeviceFileCreate %wZ\\n\", &extension->DeviceName);\r\n\r\n    status = SerialDeviceFileCreateWorker(Device);\r\n\r\n    //\r\n    // Complete the WDF request.\r\n    //\r\n    WdfRequestComplete(Request, status);\r\n\r\n    return;\r\n\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialWdmDeviceFileCreate (\r\n    IN WDFDEVICE Device,\r\n    IN PIRP Irp\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the dispatch routine for IRP_MJ_CREATE. The system sends this\r\n    request when a user application opens the device to perform an I/O\r\n    operation, such as reading or writing a file.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Pointer to the device object for this device\r\n    Irp - Pointer to the IRP for the current request\r\n\r\nReturn Value:\r\n\r\n   NT status code\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE,\r\n                     \"SerialWdmDeviceFileCreate %wZ\\n\", &extension->DeviceName);\r\n\r\n    status = SerialDeviceFileCreateWorker(Device);\r\n\r\n    //\r\n    // Complete the WDM request.\r\n    //\r\n    Irp->IoStatus.Information = 0L;\r\n    Irp->IoStatus.Status = status;\r\n    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialDeviceFileCreateWorker (\r\n    IN WDFDEVICE Device\r\n    )\r\n{\r\n    NTSTATUS status;\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension (Device);\r\n\r\n    //\r\n    // Create a buffer for the RX data when no reads are outstanding.\r\n    //\r\n\r\n    extension->InterruptReadBuffer = NULL;\r\n    extension->BufferSize = 0;\r\n\r\n    switch (MmQuerySystemSize()) {\r\n\r\n        case MmLargeSystem: {\r\n\r\n            extension->BufferSize = 4096;\r\n            extension->InterruptReadBuffer = ExAllocatePoolWithTag(\r\n                                                 NonPagedPoolNx,\r\n                                                 extension->BufferSize,\r\n                                                 POOL_TAG\r\n                                                 );\r\n\r\n            if (extension->InterruptReadBuffer) {\r\n                break;\r\n            }\r\n\r\n        }\r\n\r\n        case MmMediumSystem: {\r\n\r\n            extension->BufferSize = 1024;\r\n            extension->InterruptReadBuffer = ExAllocatePoolWithTag(\r\n                                                 NonPagedPoolNx,\r\n                                                 extension->BufferSize,\r\n                                                 POOL_TAG\r\n                                                 );\r\n\r\n            if (extension->InterruptReadBuffer) {\r\n                break;\r\n            }\r\n\r\n        }\r\n\r\n        case MmSmallSystem: {\r\n\r\n            extension->BufferSize = 128;\r\n            extension->InterruptReadBuffer = ExAllocatePoolWithTag(\r\n                                                 NonPagedPoolNx,\r\n                                                 extension->BufferSize,\r\n                                                 POOL_TAG\r\n                                                 );\r\n\r\n        }\r\n\r\n    }\r\n\r\n    if (!extension->InterruptReadBuffer) {\r\n        return STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    //\r\n    // By taking a power reference by calling WdfDeviceStopIdle, we prevent the\r\n    // framework from powering down our device due to idle timeout when there\r\n    // is an open handle.  Power reference also moves the device to D0 if we are\r\n    // idled out. If you fail create anywhere later in this routine, do make sure\r\n    // drop the reference.\r\n    //\r\n    status = WdfDeviceStopIdle(Device, TRUE);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // wakeup is not currently enabled\r\n    //\r\n\r\n    extension->IsWakeEnabled = FALSE;\r\n\r\n    //\r\n    // On a new open we \"flush\" the read queue by initializing the\r\n    // count of characters.\r\n    //\r\n\r\n    extension->CharsInInterruptBuffer = 0;\r\n    extension->LastCharSlot = extension->InterruptReadBuffer +\r\n                              (extension->BufferSize - 1);\r\n\r\n    extension->ReadBufferBase = extension->InterruptReadBuffer;\r\n    extension->CurrentCharSlot = extension->InterruptReadBuffer;\r\n    extension->FirstReadableChar = extension->InterruptReadBuffer;\r\n\r\n    extension->TotalCharsQueued = 0;\r\n\r\n    //\r\n    // We set up the default xon/xoff limits.\r\n    //\r\n\r\n    extension->HandFlow.XoffLimit = extension->BufferSize >> 3;\r\n    extension->HandFlow.XonLimit = extension->BufferSize >> 1;\r\n\r\n    extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;\r\n    extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;\r\n\r\n    extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+\r\n                                   (extension->BufferSize>>4));\r\n\r\n    //\r\n    // Mark the device as busy for WMI\r\n    //\r\n\r\n    extension->WmiCommData.IsBusy = TRUE;\r\n\r\n    extension->IrpMaskLocation = NULL;\r\n    extension->HistoryMask = 0;\r\n    extension->IsrWaitMask = 0;\r\n\r\n    extension->SendXonChar = FALSE;\r\n    extension->SendXoffChar = FALSE;\r\n\r\n#if !DBG\r\n    //\r\n    // Clear out the statistics.\r\n    //\r\n\r\n    WdfInterruptSynchronize(\r\n        extension->WdfInterrupt,\r\n        SerialClearStats,\r\n        extension\r\n        );\r\n#endif\r\n\r\n    //\r\n    // The escape char replacement must be reset upon every open.\r\n    //\r\n\r\n    extension->EscapeChar = 0;\r\n\r\n    //\r\n    // We don't want the device to be removed or stopped when there is an handle\r\n    //\r\n    // Note to anyone copying this sample as a starting point:\r\n    //\r\n    // This works in this driver simply because this driver supports exactly\r\n    // one open handle at a time.  If it supported more, then it would need\r\n    // counting logic to determine when all the reasons for failing Stop/Remove\r\n    // were gone.\r\n    //\r\n    WdfDeviceSetStaticStopRemove(Device, FALSE);\r\n\r\n    //\r\n    // Synchronize with the ISR and let it know that the device\r\n    // has been successfully opened.\r\n    //\r\n\r\n    WdfInterruptSynchronize(\r\n        extension->WdfInterrupt,\r\n        SerialMarkOpen,\r\n        extension\r\n        );\r\n\r\n    return STATUS_SUCCESS;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialEvtFileClose(\r\n    IN WDFFILEOBJECT FileObject\r\n    )\r\n\r\n/*++\r\n\r\n   EvtFileClose is called when all the handles represented by the FileObject\r\n   is closed and all the references to FileObject is removed. This callback\r\n   may get called in an arbitrary thread context instead of the thread that\r\n   called CloseHandle. If you want to delete any per FileObject context that\r\n   must be done in the context of the user thread that made the Create call,\r\n   you should do that in the EvtDeviceCleanp callback.\r\n\r\nArguments:\r\n\r\n    FileObject - Pointer to fileobject that represents the open handle.\r\n\r\nReturn Value:\r\n\r\n   VOID\r\n\r\n--*/\r\n\r\n{\r\n    PAGED_CODE();\r\n\r\n    SerialFileCloseWorker(WdfFileObjectGetDevice(FileObject));\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialWdmFileClose (\r\n    IN WDFDEVICE Device,\r\n    IN PIRP Irp\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the dispatch routine for IRP_MJ_CLOSE. This is called when all the\r\n    handles represented by the FileObject is closed and all the references to\r\n    the FileObject is removed.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Pointer to the device object for this device\r\n    Irp - Pointer to the IRP for the current request\r\n\r\nReturn Value:\r\n\r\n   NT status code\r\n\r\n--*/\r\n{\r\n    SerialFileCloseWorker(Device);\r\n\r\n    Irp->IoStatus.Information = 0L;\r\n    Irp->IoStatus.Status = STATUS_SUCCESS;\r\n    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nVOID\r\nSerialFileCloseWorker(\r\n    IN WDFDEVICE Device\r\n    )\r\n{\r\n    ULONG flushCount;\r\n\r\n    //\r\n    // This \"timer value\" is used to wait 10 character times\r\n    // after the hardware is empty before we actually \"run down\"\r\n    // all of the flow control/break junk.\r\n    //\r\n    LARGE_INTEGER tenCharDelay;\r\n\r\n    //\r\n    // Holds a character time.\r\n    //\r\n    LARGE_INTEGER charTime;\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device);\r\n    PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_CREATE_CLOSE, \"In SerialEvtFileClose %wZ\\n\",\r\n                                                &extension->DeviceName);\r\n\r\n    //\r\n    // Acquire the interrupt state lock.\r\n    //\r\n    WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL);\r\n\r\n    //\r\n    // If the Interrupts are connected, then the hardware state has to be\r\n    // cleaned up now. Note that the EvtFileClose callback gets called for\r\n    // an open file object even though the interrupts have been disabled\r\n    // possibly  due to a Surprise Remove PNP event. In such a case, the\r\n    // Interrupt  object should not be used.\r\n    //\r\n    if (interruptContext->IsInterruptConnected) {\r\n\r\n        charTime.QuadPart = -SerialGetCharTime(extension).QuadPart;\r\n\r\n        //\r\n        // Do this now so that if the isr gets called it won't do anything\r\n        // to cause more chars to get sent.  We want to run down the hardware.\r\n        //\r\n\r\n        SetDeviceIsOpened(extension, FALSE, FALSE);\r\n\r\n        //\r\n        // Synchronize with the isr to turn off break if it\r\n        // is already on.\r\n        //\r\n\r\n        WdfInterruptSynchronize(\r\n            extension->WdfInterrupt,\r\n            SerialTurnOffBreak,\r\n            extension\r\n            );\r\n\r\n        //\r\n        // Wait a reasonable amount of time (20 * fifodepth) until all characters\r\n        // have been emptied out of the hardware.\r\n        //\r\n\r\n        for (flushCount = (20 * 16); flushCount != 0; flushCount--) {\r\n           if ((READ_LINE_STATUS(extension, extension->Controller) &\r\n                (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=\r\n               (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {\r\n\r\n              KeDelayExecutionThread(KernelMode, FALSE, &charTime);\r\n          } else {\r\n             break;\r\n          }\r\n        }\r\n\r\n        if (flushCount == 0) {\r\n           SerialMarkHardwareBroken(extension);\r\n        }\r\n\r\n        //\r\n        // Synchronize with the ISR to let it know that interrupts are\r\n        // no longer important.\r\n        //\r\n\r\n        WdfInterruptSynchronize(\r\n            extension->WdfInterrupt,\r\n            SerialMarkClose,\r\n            extension\r\n            );\r\n\r\n\r\n        //\r\n        // If the driver has automatically transmitted an Xoff in\r\n        // the context of automatic receive flow control then we\r\n        // should transmit an Xon.\r\n        //\r\n\r\n        if (extension->RXHolding & SERIAL_RX_XOFF) {\r\n\r\n            //\r\n            // Loop until the holding register is empty.\r\n            //\r\n            while (!(READ_LINE_STATUS(extension, extension->Controller) &\r\n                     SERIAL_LSR_THRE)) {\r\n                KeDelayExecutionThread(\r\n                    KernelMode,\r\n                    FALSE,\r\n                    &charTime\r\n                    );\r\n\r\n            }\r\n\r\n            WRITE_TRANSMIT_HOLDING(extension,\r\n                extension->Controller,\r\n                extension->SpecialChars.XonChar\r\n                );\r\n\r\n            //\r\n            // Wait a reasonable amount of time for the characters\r\n            // to be emptied out of the hardware.\r\n            //\r\n\r\n             for (flushCount = (20 * 16); flushCount != 0; flushCount--) {\r\n                if ((READ_LINE_STATUS(extension, extension->Controller) &\r\n                     (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=\r\n                    (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {\r\n                   KeDelayExecutionThread(KernelMode, FALSE, &charTime);\r\n                } else {\r\n                   break;\r\n                }\r\n             }\r\n\r\n             if (flushCount == 0) {\r\n                SerialMarkHardwareBroken(extension);\r\n             }\r\n        }\r\n\r\n\r\n        //\r\n        // The hardware is empty.  Delay 10 character times before\r\n        // shut down all the flow control.\r\n        //\r\n\r\n        tenCharDelay.QuadPart = charTime.QuadPart * 10;\r\n\r\n        KeDelayExecutionThread(\r\n            KernelMode,\r\n            TRUE,\r\n            &tenCharDelay\r\n            );\r\n\r\n#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, \"This warning is because we are calling interrupt synchronize routine directly.\")\r\n        SerialClrDTR(extension->WdfInterrupt, extension);\r\n\r\n        //\r\n        // We have to be very careful how we clear the RTS line.\r\n        // Transmit toggling might have been on at some point.\r\n        //\r\n        // We know that there is nothing left that could start\r\n        // out the \"polling\"  execution path.  We need to\r\n        // check the counter that indicates that the execution\r\n        // path is active.  If it is then we loop delaying one\r\n        // character time.  After each delay we check to see if\r\n        // the counter has gone to zero.  When it has we know that\r\n        // the execution path should be just about finished.  We\r\n        // make sure that we still aren't in the routine that\r\n        // synchronized execution with the ISR by synchronizing\r\n        // ourselve with the ISR.\r\n        //\r\n\r\n        if (extension->CountOfTryingToLowerRTS) {\r\n\r\n            do {\r\n#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_HIGH, \"This warning is due to suppressing the previous one.\")\r\n                KeDelayExecutionThread(\r\n                    KernelMode,\r\n                    FALSE,\r\n                    &charTime\r\n                    );\r\n\r\n            } while (extension->CountOfTryingToLowerRTS);\r\n\r\n            //\r\n            // The execution path should no longer exist that\r\n            // is trying to push down the RTS.  Well just\r\n            // make sure it's down by falling through to\r\n            // code that forces it down.\r\n            //\r\n\r\n        }\r\n\r\n#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, \"This warning is because we are calling interrupt synchronize routine directly.\")\r\n        SerialClrRTS(extension->WdfInterrupt, extension);\r\n\r\n        //\r\n        // Clean out the holding reasons (since we are closed).\r\n        //\r\n\r\n        extension->RXHolding = 0;\r\n        extension->TXHolding = 0;\r\n\r\n        //\r\n        // Mark device as not busy for WMI\r\n        //\r\n\r\n        extension->WmiCommData.IsBusy = FALSE;\r\n\r\n    }\r\n\r\n    //\r\n    // Release the Interrupt state lock.\r\n    //\r\n    WdfWaitLockRelease(interruptContext->InterruptStateLock);\r\n\r\n    //\r\n    // All is done.  The port has been disabled from interrupting\r\n    // so there is no point in keeping the memory around.\r\n    //\r\n\r\n    extension->BufferSize = 0;\r\n    if (extension->InterruptReadBuffer != NULL) {\r\n       ExFreePool(extension->InterruptReadBuffer);\r\n    }\r\n    extension->InterruptReadBuffer = NULL;\r\n\r\n    //\r\n    // Make sure the wake is disabled.\r\n    //\r\n    ASSERT(!extension->IsWakeEnabled);\r\n\r\n    SerialDrainTimersAndDpcs(extension);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_CREATE_CLOSE, \"DPC's drained:\\n\");\r\n\r\n    //\r\n    // It's fine for the device to be powered off if there are no open handles.\r\n    //\r\n    WdfDeviceResumeIdle(Device);\r\n\r\n    //\r\n    // It's okay to allow the device to be stopped or removed.\r\n    //\r\n    // Note to anyone copying this sample as a starting point:\r\n    //\r\n    // This works in this driver simply because this driver supports exactly\r\n    // one open handle at a time.  If it supported more, then it would need\r\n    // counting logic to determine when all the reasons for failing Stop/Remove\r\n    // were gone.\r\n    //\r\n    WdfDeviceSetStaticStopRemove(Device, TRUE);\r\n\r\n    return;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialMarkOpen(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine merely sets a boolean to true to mark the fact that\r\n    somebody opened the device and its worthwhile to pay attention\r\n    to interrupts.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    SerialReset(extension->WdfInterrupt, extension);\r\n\r\n    //\r\n    // Prepare for the opening by re-enabling interrupts.\r\n    //\r\n    // We do this my modifying the OUT2 line in the modem control.\r\n    // In PC's this bit is \"anded\" with the interrupt line.\r\n    //\r\n\r\n    WRITE_MODEM_CONTROL(extension,\r\n        extension->Controller,\r\n        (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller) | SERIAL_MCR_OUT2)\r\n        );\r\n\r\n    extension->DeviceIsOpened = TRUE;\r\n    extension->ErrorWord = 0;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nVOID\r\nSerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n                IN PLARGE_INTEGER PDrainTime)\r\n{\r\n   PAGED_CODE();\r\n\r\n   //\r\n   // Wait until all characters have been emptied out of the hardware.\r\n   //\r\n\r\n   while ((READ_LINE_STATUS(PDevExt, PDevExt->Controller) &\r\n           (SERIAL_LSR_THRE | SERIAL_LSR_TEMT))\r\n           != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {\r\n        KeDelayExecutionThread(KernelMode, FALSE, PDrainTime);\r\n    }\r\n}\r\n\r\nVOID\r\nSerialDisableUART(IN PVOID Context)\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine disables the UART and puts it in a \"safe\" state when\r\n    not in use (like a close or powerdown).\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n   PSERIAL_DEVICE_EXTENSION extension = Context;\r\n\r\n   //\r\n   // Prepare for the closing by stopping interrupts.\r\n   //\r\n   // We do this by adjusting the OUT2 line in the modem control.\r\n   // In PC's this bit is \"anded\" with the interrupt line.\r\n   //\r\n\r\n   WRITE_MODEM_CONTROL(extension, extension->Controller,\r\n                       (UCHAR)(READ_MODEM_CONTROL(extension, extension->Controller)\r\n                               & ~SERIAL_MCR_OUT2));\r\n\r\n   if (extension->FifoPresent) {\r\n      WRITE_FIFO_CONTROL(extension, extension->Controller, (UCHAR)0);\r\n    }\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialMarkClose(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine merely sets a boolean to false to mark the fact that\r\n    somebody closed the device and it's no longer worthwhile to pay attention\r\n    to interrupts.  It also disables the UART.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    SerialDisableUART(Context);\r\n    extension->DeviceIsOpened = FALSE;\r\n    extension->DeviceState.Reopen   = FALSE;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nLARGE_INTEGER\r\nSerialGetCharTime(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function will return the number of 100 nanosecond intervals\r\n    there are in one character time (based on the present form\r\n    of flow control.\r\n\r\nArguments:\r\n\r\n    Extension - Just what it says.\r\n\r\nReturn Value:\r\n\r\n    100 nanosecond intervals in a character time.\r\n\r\n--*/\r\n\r\n{\r\n    ULONG dataSize = 0;\r\n    ULONG paritySize;\r\n    ULONG stopSize;\r\n    ULONG charTime;\r\n    ULONG bitTime;\r\n    LARGE_INTEGER tmp;\r\n\r\n    PAGED_CODE();\r\n\r\n    if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {\r\n        dataSize = 5;\r\n    } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                == SERIAL_6_DATA) {\r\n        dataSize = 6;\r\n    } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                == SERIAL_7_DATA) {\r\n        dataSize = 7;\r\n    } else if ((Extension->LineControl & SERIAL_DATA_MASK)\r\n                == SERIAL_8_DATA) {\r\n        dataSize = 8;\r\n    }\r\n\r\n    paritySize = 1;\r\n    if ((Extension->LineControl & SERIAL_PARITY_MASK)\r\n            == SERIAL_NONE_PARITY) {\r\n\r\n        paritySize = 0;\r\n\r\n    }\r\n\r\n    if (Extension->LineControl & SERIAL_2_STOP) {\r\n\r\n        //\r\n        // Even if it is 1.5, for sanities sake were going\r\n        // to say 2.\r\n        //\r\n\r\n        stopSize = 2;\r\n\r\n    } else {\r\n\r\n        stopSize = 1;\r\n\r\n    }\r\n\r\n    //\r\n    // First we calculate the number of 100 nanosecond intervals\r\n    // are in a single bit time (Approximately).\r\n    //\r\n\r\n    bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;\r\n    charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);\r\n\r\n    tmp.QuadPart = charTime;\r\n    return tmp;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/pnp.c",
    "content": "/*++\r\n\r\nCopyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    pnp.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that handles the plug and play\r\n    IRPs for the serial driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n#include <initguid.h>\r\n#include <ntddser.h>\r\n#include <stdlib.h>\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"pnp.tmh\"\r\n#endif\r\n\r\nstatic const PHYSICAL_ADDRESS SerialPhysicalZero = {0};\r\nstatic const SUPPORTED_BAUD_RATES SupportedBaudRates[] = {\r\n        {75, SERIAL_BAUD_075},\r\n        {110, SERIAL_BAUD_110},\r\n        {135, SERIAL_BAUD_134_5},\r\n        {150, SERIAL_BAUD_150},\r\n        {300, SERIAL_BAUD_300},\r\n        {600, SERIAL_BAUD_600},\r\n        {1200, SERIAL_BAUD_1200},\r\n        {1800, SERIAL_BAUD_1800},\r\n        {2400, SERIAL_BAUD_2400},\r\n        {4800, SERIAL_BAUD_4800},\r\n        {7200, SERIAL_BAUD_7200},\r\n        {9600, SERIAL_BAUD_9600},\r\n        {14400, SERIAL_BAUD_14400},\r\n        {19200, SERIAL_BAUD_19200},\r\n        {38400, SERIAL_BAUD_38400},\r\n        {56000, SERIAL_BAUD_56K},\r\n        {57600, SERIAL_BAUD_57600},\r\n        {115200, SERIAL_BAUD_115200},\r\n        {128000, SERIAL_BAUD_128K},\r\n        {SERIAL_BAUD_INVALID, SERIAL_BAUD_USER}\r\n    };\r\n\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESRP0, SerialEvtDeviceAdd)\r\n#pragma alloc_text(PAGESRP0, SerialEvtPrepareHardware)\r\n#pragma alloc_text(PAGESRP0, SerialEvtReleaseHardware)\r\n#pragma alloc_text(PAGESRP0, SerialEvtDeviceD0ExitPreInterruptsDisabled)\r\n#pragma alloc_text(PAGESRP0, SerialMapHWResources)\r\n#pragma alloc_text(PAGESRP0, SerialUnmapHWResources)\r\n#pragma alloc_text(PAGESRP0, SerialEvtDeviceContextCleanup)\r\n#pragma alloc_text(PAGESRP0, SerialDoExternalNaming)\r\n#pragma alloc_text(PAGESRP0, SerialReportMaxBaudRate)\r\n#pragma alloc_text(PAGESRP0, SerialUndoExternalNaming)\r\n#pragma alloc_text(PAGESRP0, SerialInitController)\r\n#pragma alloc_text(PAGESRP0, SerialGetMappedAddress)\r\n#pragma alloc_text(PAGESRP0, SerialSetPowerPolicy)\r\n#pragma alloc_text(PAGESRP0, SerialReadSymName)\r\n\r\n#endif // ALLOC_PRAGMA\r\n\r\nPVOID LocalMmMapIoSpace(\r\n    _In_ PHYSICAL_ADDRESS PhysicalAddress,\r\n    _In_ SIZE_T NumberOfBytes\r\n    )\r\n{\r\n    typedef\r\n    PVOID\r\n    (*PFN_MM_MAP_IO_SPACE_EX) (\r\n        _In_ PHYSICAL_ADDRESS PhysicalAddress,\r\n        _In_ SIZE_T NumberOfBytes,\r\n        _In_ ULONG Protect\r\n        );\r\n\r\n    UNICODE_STRING         name;\r\n    PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx;\r\n\r\n    RtlInitUnicodeString(&name, L\"MmMapIoSpaceEx\");\r\n    pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name);\r\n\r\n    if (pMmMapIoSpaceEx != NULL){\r\n        //\r\n        // Call WIN10 API if available\r\n        //\r\n        return pMmMapIoSpaceEx(PhysicalAddress,\r\n                               NumberOfBytes,\r\n                               PAGE_READWRITE | PAGE_NOCACHE);\r\n    }\r\n\r\n    //\r\n    // Supress warning that MmMapIoSpace allocates executable memory.\r\n    // This function is only used if the preferred API, MmMapIoSpaceEx\r\n    // is not present. MmMapIoSpaceEx is available starting in WIN10.\r\n    //\r\n    #pragma warning(suppress: 30029)\r\n    return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached);\r\n}\r\n\r\nNTSTATUS\r\nSerialEvtDeviceAdd(\r\n    IN WDFDRIVER Driver,\r\n    IN PWDFDEVICE_INIT DeviceInit\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    EvtDeviceAdd is called by the framework in response to AddDevice\r\n    call from the PnP manager.\r\n\r\n\r\nArguments:\r\n\r\n    Driver - Handle to a framework driver object created in DriverEntry\r\n\r\n    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS                      status;\r\n    PSERIAL_DEVICE_EXTENSION      pDevExt;\r\n    static ULONG                  currentInstance = 0;\r\n    WDF_FILEOBJECT_CONFIG         fileobjectConfig;\r\n    WDFDEVICE                     device;\r\n    WDF_PNPPOWER_EVENT_CALLBACKS  pnpPowerCallbacks;\r\n    WDF_OBJECT_ATTRIBUTES         attributes;\r\n    WDF_IO_QUEUE_CONFIG           queueConfig;\r\n    WDFQUEUE                      defaultqueue;\r\n    ULONG                         isMulti;\r\n    PULONG                        countSoFar;\r\n    WDF_INTERRUPT_CONFIG          interruptConfig;\r\n    PSERIAL_INTERRUPT_CONTEXT     interruptContext;\r\n    ULONG                         relinquishPowerPolicy;\r\n\r\n    DECLARE_UNICODE_STRING_SIZE(deviceName, DEVICE_OBJECT_NAME_LENGTH);\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"-->SerialEvtDeviceAdd\\n\");\r\n\r\n    status = RtlUnicodeStringPrintf(&deviceName, L\"%ws%u\",\r\n                                L\"\\\\Device\\\\Serial\",\r\n                                currentInstance++);\r\n\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    status = WdfDeviceInitAssignName(DeviceInit,& deviceName);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    WdfDeviceInitSetExclusive(DeviceInit, TRUE);\r\n    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT);\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);\r\n\r\n    WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes);\r\n\r\n    //\r\n    // Zero out the PnpPowerCallbacks structure.\r\n    //\r\n    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);\r\n\r\n    //\r\n    // Set Callbacks for any of the functions we are interested in.\r\n    // If no callback is set, Framework will take the default action\r\n    // by itself.  These next two callbacks set up and tear down hardware state,\r\n    // specifically that which only has to be done once.\r\n    //\r\n\r\n    pnpPowerCallbacks.EvtDevicePrepareHardware = SerialEvtPrepareHardware;\r\n    pnpPowerCallbacks.EvtDeviceReleaseHardware = SerialEvtReleaseHardware;\r\n\r\n    //\r\n    // These two callbacks set up and tear down hardware state that must be\r\n    // done every time the device moves in and out of the D0-working state.\r\n    //\r\n\r\n    pnpPowerCallbacks.EvtDeviceD0Entry         = SerialEvtDeviceD0Entry;\r\n    pnpPowerCallbacks.EvtDeviceD0Exit          = SerialEvtDeviceD0Exit;\r\n\r\n    //\r\n    // Specify the callback for monitoring when the device's interrupt are\r\n    // enabled or about to be disabled.\r\n    //\r\n\r\n    pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = SerialEvtDeviceD0EntryPostInterruptsEnabled;\r\n    pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled  = SerialEvtDeviceD0ExitPreInterruptsDisabled;\r\n\r\n    //\r\n    // Register the PnP and power callbacks.\r\n    //\r\n    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);\r\n\r\n    if ( !NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                         \"WdfDeviceInitSetPnpPowerEventCallbacks failed %!STATUS!\\n\",\r\n                         status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Find out if we own power policy\r\n    //\r\n    SerialGetFdoRegistryKeyValue( DeviceInit,\r\n                                  L\"SerialRelinquishPowerPolicy\",\r\n                                  &relinquishPowerPolicy );\r\n\r\n    if(relinquishPowerPolicy) {\r\n        //\r\n        // FDO's are assumed to be power policy owner by default. So tell\r\n        // the framework explicitly to relinquish the power policy ownership.\r\n        //\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                         \"RelinquishPowerPolicy due to registry settings\\n\");\r\n\r\n        WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE);\r\n    }\r\n\r\n    //\r\n    // For Windows XP and below, we will register for the WDM Preprocess callback\r\n    // for IRP_MJ_CREATE. This is done because, the Serenum filter doesn't handle\r\n    // creates that are marked pending. Since framework always marks the IRP pending,\r\n    // we are registering this WDM preprocess handler so that we can bypass the\r\n    // framework and handle the create and close ourself. This workaround is need\r\n    // only if you intend to install the Serenum as an upper filter.\r\n    //\r\n    if (RtlIsNtDdiVersionAvailable(NTDDI_VISTA) == FALSE) {\r\n\r\n        status = WdfDeviceInitAssignWdmIrpPreprocessCallback(\r\n                                                DeviceInit,\r\n                                                SerialWdmDeviceFileCreate,\r\n                                                IRP_MJ_CREATE,\r\n                                                NULL, // pointer minor function table\r\n                                                0); // number of entries in the table\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                             \"WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\\n\",\r\n                             status);\r\n            return status;\r\n        }\r\n\r\n        status = WdfDeviceInitAssignWdmIrpPreprocessCallback(\r\n                                                DeviceInit,\r\n                                                SerialWdmFileClose,\r\n                                                IRP_MJ_CLOSE,\r\n                                                NULL, // pointer minor function table\r\n                                                0); // number of entries in the table\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                             \"WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\\n\",\r\n                             status);\r\n            return status;\r\n        }\r\n\r\n    } else {\r\n\r\n        //\r\n        // FileEvents can opt for Device level synchronization only if the ExecutionLevel\r\n        // of the Device is passive. Since we can't choose passive execution-level for\r\n        // device because we have chose to synchronize timers & dpcs with the device,\r\n        // we will opt out of synchonization with the device for fileobjects.\r\n        // Note: If the driver has to synchronize Create with the other I/O events,\r\n        // it can create a queue and configure-dispatch create requests to the queue.\r\n        //\r\n        WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n        attributes.SynchronizationScope = WdfSynchronizationScopeNone;\r\n\r\n        //\r\n        // Set Entry points for Create and Close..\r\n        //\r\n        WDF_FILEOBJECT_CONFIG_INIT(\r\n                            &fileobjectConfig,\r\n                            SerialEvtDeviceFileCreate,\r\n                            SerialEvtFileClose,\r\n                            WDF_NO_EVENT_CALLBACK // Cleanup\r\n                            );\r\n\r\n        WdfDeviceInitSetFileObjectConfig(\r\n                        DeviceInit,\r\n                        &fileobjectConfig,\r\n                        &attributes\r\n                        );\r\n    }\r\n\r\n\r\n    //\r\n    // Since framework queues doesn't handle IRP_MJ_FLUSH_BUFFERS,\r\n    // IRP_MJ_QUERY_INFORMATION and IRP_MJ_SET_INFORMATION requests,\r\n    // we will register a preprocess callback to handle them.\r\n    //\r\n    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(\r\n                                            DeviceInit,\r\n                                            SerialFlush,\r\n                                            IRP_MJ_FLUSH_BUFFERS,\r\n                                            NULL, // pointer minor function table\r\n                                            0); // number of entries in the table\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                         \"WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\\n\",\r\n                         status);\r\n        return status;\r\n    }\r\n\r\n    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(\r\n                                        DeviceInit,\r\n                                        SerialQueryInformationFile,\r\n                                        IRP_MJ_QUERY_INFORMATION,\r\n                                        NULL, // pointer minor function table\r\n                                        0); // number of entries in the table\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                         \"WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\\n\",\r\n                         status);\r\n        return status;\r\n    }\r\n    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(\r\n                                        DeviceInit,\r\n                                        SerialSetInformationFile,\r\n                                        IRP_MJ_SET_INFORMATION,\r\n                                        NULL, // pointer minor function table\r\n                                        0); // number of entries in the table\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                         \"WdfDeviceInitAssignWdmIrpPreprocessCallback failed %!STATUS!\\n\",\r\n                         status);\r\n        return status;\r\n    }\r\n\r\n\r\n    //\r\n    // Create a device\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE (&attributes,\r\n                                            SERIAL_DEVICE_EXTENSION);\r\n    //\r\n    // Provide a callback to cleanup the context. This will be called\r\n    // when the device is removed.\r\n    //\r\n    attributes.EvtCleanupCallback = SerialEvtDeviceContextCleanup;\r\n    //\r\n    // By opting for SynchronizationScopeDevice, we tell the framework to\r\n    // synchronize callbacks events of all the objects directly associated\r\n    // with the device. In this driver, we will associate queues, dpcs,\r\n    // and timers. By doing that we don't have to worrry about synchronizing\r\n    // access to device-context by Io Events, cancel-routine, timer and dpc\r\n    // callbacks.\r\n    //\r\n    attributes.SynchronizationScope = WdfSynchronizationScopeDevice;\r\n\r\n    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                       \"SerialAddDevice - WdfDeviceCreate failed %!STATUS!\\n\",\r\n                         status);\r\n        return status;\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"Created device (%p) %wZ\\n\", device, &deviceName);\r\n\r\n    pDevExt = SerialGetDeviceExtension (device);\r\n\r\n    pDevExt->DriverObject = WdfDriverWdmGetDriverObject(Driver);\r\n\r\n    //\r\n    // This sample doesn't support multiport serial devices.\r\n    // Multiport devices allow other pseudo-serial devices with extra\r\n    // resources to specify another range of I/O ports.\r\n    //\r\n    if(!SerialGetRegistryKeyValue(device, L\"MultiportDevice\",  &isMulti)) {\r\n        isMulti = 0;\r\n    }\r\n\r\n    if(isMulti) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                         \"This sample doesn't support multiport devices\\n\");\r\n        return STATUS_DEVICE_CONFIGURATION_ERROR;\r\n    }\r\n\r\n    //\r\n    // Set up the device extension.\r\n    //\r\n\r\n    pDevExt = SerialGetDeviceExtension (device);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"AddDevice PDO(0x%p) FDO(0x%p), Lower(0x%p) DevExt (0x%p)\\n\",\r\n                    WdfDeviceWdmGetPhysicalDevice (device),\r\n                    WdfDeviceWdmGetDeviceObject (device),\r\n                    WdfDeviceWdmGetAttachedDevice(device),\r\n                    pDevExt);\r\n\r\n    pDevExt->DeviceIsOpened = FALSE;\r\n    pDevExt->DeviceObject   = WdfDeviceWdmGetDeviceObject(device);\r\n    pDevExt->WdfDevice = device;\r\n\r\n    pDevExt->TxFifoAmount           = driverDefaults.TxFIFODefault;\r\n    pDevExt->UartRemovalDetect      = driverDefaults.UartRemovalDetect;\r\n    pDevExt->CreatedSymbolicLink    = FALSE;\r\n    pDevExt->OwnsPowerPolicy = relinquishPowerPolicy ? FALSE : TRUE;\r\n\r\n    status = SerialSetPowerPolicy(pDevExt);\r\n    if(!NT_SUCCESS(status)){\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // We create four manual queues below.\r\n    // Read Queue..(how about using serial queue for read). Since requests\r\n    // jump from queue to queue, we cannot configure the queues to receive a\r\n    // particular type of request. For example, some of the IOCTLs end up\r\n    // in read and write queue.\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,\r\n                             WdfIoQueueDispatchManual);\r\n\r\n    queueConfig.EvtIoStop = SerialEvtIoStop;\r\n    queueConfig.EvtIoResume = SerialEvtIoResume;\r\n    queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue;\r\n\r\n    status = WdfIoQueueCreate (device,\r\n                               &queueConfig,\r\n                               WDF_NO_OBJECT_ATTRIBUTES,\r\n                               &pDevExt->ReadQueue\r\n                               );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \" WdfIoQueueCreate for Read failed %!STATUS!\\n\", status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Write Queue..\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,\r\n                             WdfIoQueueDispatchManual);\r\n\r\n    queueConfig.EvtIoStop = SerialEvtIoStop;\r\n    queueConfig.EvtIoResume = SerialEvtIoResume;\r\n    queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue;\r\n\r\n    status = WdfIoQueueCreate (device,\r\n                               &queueConfig,\r\n                               WDF_NO_OBJECT_ATTRIBUTES,\r\n                               &pDevExt->WriteQueue\r\n                               );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \" WdfIoQueueCreate for Write failed %!STATUS!\\n\", status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Mask Queue...\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,\r\n                             WdfIoQueueDispatchManual\r\n                             );\r\n\r\n    queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue;\r\n\r\n    queueConfig.EvtIoStop = SerialEvtIoStop;\r\n    queueConfig.EvtIoResume = SerialEvtIoResume;\r\n\r\n    status = WdfIoQueueCreate (device,\r\n                               &queueConfig,\r\n                               WDF_NO_OBJECT_ATTRIBUTES,\r\n                               &pDevExt->MaskQueue\r\n                               );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \" WdfIoQueueCreate for Mask failed %!STATUS!\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Purge Queue..\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,\r\n                             WdfIoQueueDispatchManual\r\n                             );\r\n\r\n    queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue;\r\n\r\n    queueConfig.EvtIoStop = SerialEvtIoStop;\r\n    queueConfig.EvtIoResume = SerialEvtIoResume;\r\n\r\n    status = WdfIoQueueCreate (device,\r\n                               &queueConfig,\r\n                               WDF_NO_OBJECT_ATTRIBUTES,\r\n                               &pDevExt->PurgeQueue\r\n                               );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \" WdfIoQueueCreate for Purge failed %!STATUS!\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // All the incoming I/O requests are routed to the default queue and dispatch to the\r\n    // appropriate callback events. These callback event will check to see if another\r\n    // request is currently active. If so then it will forward it to other manual queues.\r\n    // All the queues are auto managed by the framework in response to the PNP\r\n    // and Power events.\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(\r\n                &queueConfig,\r\n                WdfIoQueueDispatchParallel\r\n                );\r\n    queueConfig.EvtIoRead   = SerialEvtIoRead;\r\n    queueConfig.EvtIoWrite  = SerialEvtIoWrite;\r\n    queueConfig.EvtIoDeviceControl = SerialEvtIoDeviceControl;\r\n    queueConfig.EvtIoInternalDeviceControl = SerialEvtIoInternalDeviceControl;\r\n    queueConfig.EvtIoCanceledOnQueue = SerialEvtCanceledOnQueue;\r\n\r\n    queueConfig.EvtIoStop = SerialEvtIoStop;\r\n    queueConfig.EvtIoResume = SerialEvtIoResume;\r\n\r\n    status = WdfIoQueueCreate(device,\r\n                                         &queueConfig,\r\n                                         WDF_NO_OBJECT_ATTRIBUTES,\r\n                                         &defaultqueue\r\n                                         );\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"WdfIoQueueCreate failed %!STATUS!\\n\", status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Create WDFINTERRUPT object. Let us leave the ShareVector to  default value and\r\n    // let the framework decide whether to share the interrupt or not based on the\r\n    // ShareDisposition provided by the bus driver in the resource descriptor.\r\n    //\r\n\r\n    WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,\r\n                              SerialISR,\r\n                              NULL);\r\n\r\n    interruptConfig.EvtInterruptDisable = SerialEvtInterruptDisable;\r\n    interruptConfig.EvtInterruptEnable = SerialEvtInterruptEnable;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, SERIAL_INTERRUPT_CONTEXT);\r\n\r\n    status = WdfInterruptCreate(device,\r\n                                &interruptConfig,\r\n                                &attributes,\r\n                                &pDevExt->WdfInterrupt);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Couldn't create interrupt for %wZ\\n\",\r\n                  &pDevExt->DeviceName);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Interrupt state wait lock...\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n    attributes.ParentObject = pDevExt->WdfInterrupt;\r\n\r\n    interruptContext = SerialGetInterruptContext(pDevExt->WdfInterrupt);\r\n\r\n    status = WdfWaitLockCreate(&attributes,\r\n                               &interruptContext->InterruptStateLock\r\n                               );\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \" WdfWaitLockCreate for InterruptStateLock failed %!STATUS!\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Set interrupt policy\r\n    //\r\n    SerialSetInterruptPolicy(pDevExt->WdfInterrupt);\r\n\r\n    //\r\n    // Timers and DPCs...\r\n    //\r\n    status = SerialCreateTimersAndDpcs(pDevExt);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"SerialCreateTimersAndDpcs failed %x\\n\", status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Register with WMI.\r\n    //\r\n    status = SerialWmiRegistration(device);\r\n    if(!NT_SUCCESS (status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"SerialWmiRegistration failed %!STATUS!\\n\", status);\r\n        return status;\r\n\r\n    }\r\n\r\n    //\r\n    // Upto this point, if we fail, we don't have to worry about freeing any resource because\r\n    // framework will free all the objects.\r\n    //\r\n    //\r\n    // Do the external naming.\r\n    //\r\n\r\n    status = SerialDoExternalNaming(pDevExt);\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"External Naming Failed - Status %!STATUS!\\n\",\r\n                      status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Finally increment the global system configuration that keeps track of number of serial ports.\r\n    //\r\n    countSoFar = &IoGetConfigurationInformation()->SerialCount;\r\n    (*countSoFar)++;\r\n    pDevExt->IsSystemConfigInfoUpdated = TRUE;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<--SerialEvtDeviceAdd\\n\");\r\n\r\n    return status;\r\n\r\n}\r\n#pragma warning(push)\r\n#pragma warning(disable:28118) // this callback will run at IRQL=PASSIVE_LEVEL\r\n_Use_decl_annotations_\r\nVOID\r\nSerialEvtDeviceContextCleanup (\r\n    WDFOBJECT       Device\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   EvtDeviceContextCleanup event callback cleans up anything done in\r\n   EvtDeviceAdd, except those things that are automatically cleaned\r\n   up by the Framework.\r\n\r\n   In a driver derived from this sample, it's quite likely that this function could\r\n   be deleted.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION deviceExtension;\r\n    PULONG countSoFar;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"--> SerialDeviceContextCleanup\\n\");\r\n\r\n    PAGED_CODE();\r\n\r\n    deviceExtension = SerialGetDeviceExtension (Device);\r\n\r\n    if (deviceExtension->InterruptReadBuffer != NULL) {\r\n       ExFreePool(deviceExtension->InterruptReadBuffer);\r\n       deviceExtension->InterruptReadBuffer = NULL;\r\n    }\r\n\r\n    //\r\n    // Update the global configuration count for serial device.\r\n    //\r\n    if(deviceExtension->IsSystemConfigInfoUpdated) {\r\n        countSoFar = &IoGetConfigurationInformation()->SerialCount;\r\n        (*countSoFar)--;\r\n    }\r\n\r\n    SerialUndoExternalNaming(deviceExtension);\r\n\r\n    return;\r\n}\r\n#pragma warning(pop) // enable 28118 again\r\n\r\nNTSTATUS\r\nSerialEvtPrepareHardware(\r\n    WDFDEVICE Device,\r\n    WDFCMRESLIST Resources,\r\n    WDFCMRESLIST ResourcesTranslated\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    SerialEvtPrepareHardware event callback performs operations that are necessary\r\n    to make the device operational. The framework calls the driver's\r\n    SerialEvtPrepareHardware callback when the PnP manager sends an IRP_MN_START_DEVICE\r\n    request to the driver stack.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    Resources - Handle to a collection of framework resource objects.\r\n                This collection identifies the raw (bus-relative) hardware\r\n                resources that have been assigned to the device.\r\n\r\n    ResourcesTranslated - Handle to a collection of framework resource objects.\r\n                This collection identifies the translated (system-physical)\r\n                hardware resources that have been assigned to the device.\r\n                The resources appear from the CPU's point of view.\r\n                Use this list of resources to map I/O space and\r\n                device-accessible memory into virtual address space\r\n\r\nReturn Value:\r\n\r\n    WDF status code\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n    NTSTATUS status;\r\n    CONFIG_DATA config;\r\n    PCONFIG_DATA pConfig = &config;\r\n    ULONG defaultClockRate = 1843200;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx (TRACE_LEVEL_INFORMATION, DBG_PNP, \"--> SerialEvtPrepareHardware\\n\");\r\n    //\r\n    // Get the Device Extension..\r\n    //\r\n    pDevExt = SerialGetDeviceExtension (Device);\r\n\r\n    RtlZeroMemory(pConfig, sizeof(CONFIG_DATA));\r\n\r\n    //\r\n    // Initialize a config data structure with default values for those that\r\n    // may not already be initialized.\r\n    //\r\n\r\n    pConfig->LogFifo = driverDefaults.LogFifoDefault;\r\n\r\n\r\n    //\r\n    // Get the hw resources for the device.\r\n    //\r\n\r\n    status = SerialMapHWResources(Device, Resources, ResourcesTranslated, pConfig);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        goto End;\r\n    }\r\n\r\n    //\r\n    // Open the \"Device Parameters\" section of registry for this device and get parameters.\r\n    //\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                  L\"DisablePort\",\r\n                                  &pConfig->DisablePort)){\r\n        pConfig->DisablePort = 0;\r\n    }\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                   L\"ForceFifoEnable\",\r\n                                   &pConfig->ForceFifoEnable)){\r\n        pConfig->ForceFifoEnable = driverDefaults.ForceFifoEnableDefault;\r\n    }\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                   L\"RxFIFO\",\r\n                                   &pConfig->RxFIFO)){\r\n        pConfig->RxFIFO = driverDefaults.RxFIFODefault;\r\n    }\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                   L\"TxFIFO\",\r\n                                   &pConfig->TxFIFO)){\r\n        pConfig->TxFIFO = driverDefaults.TxFIFODefault;\r\n    }\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                   L\"Share System Interrupt\",\r\n                                   &pConfig->PermitShare)){\r\n        pConfig->PermitShare = driverDefaults.PermitShareDefault;\r\n    }\r\n\r\n    if(!SerialGetRegistryKeyValue (Device,\r\n                                   L\"ClockRate\",\r\n                                   &pConfig->ClockRate)) {\r\n        pConfig->ClockRate = defaultClockRate;\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"Com Port ClockRate: %x\\n\",\r\n                    pConfig->ClockRate);\r\n\r\n    if(!SerialGetRegistryKeyValue(Device,\r\n                                 L\"TL16C550C Auto Flow Control\",\r\n                                 &pConfig->TL16C550CAFC)){\r\n        pConfig->TL16C550CAFC = 0;\r\n    }\r\n\r\n    status = SerialInitController(pDevExt, pConfig);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n    }\r\nEnd:\r\n\r\n   SerialDbgPrintEx (TRACE_LEVEL_INFORMATION, DBG_PNP, \"<-- SerialEvtPrepareHardware 0x%x\\n\", status);\r\n\r\n   return status;\r\n}\r\n\r\nNTSTATUS\r\nSerialEvtReleaseHardware(\r\n    IN  WDFDEVICE Device,\r\n    IN  WDFCMRESLIST ResourcesTranslated\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    EvtDeviceReleaseHardware is called by the framework whenever the PnP manager\r\n    is revoking ownership of our resources.  This may be in response to either\r\n    IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE.  The callback is made before\r\n    passing down the IRP to the lower driver.\r\n\r\n    In this callback, do anything necessary to free those resources.\r\n    In this driver, we will not receive this callback when there is open handle to\r\n    the device. We explicitly tell the framework (WdfDeviceSetStaticStopRemove) to\r\n    fail stop and query-remove when handle is open.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    ResourcesTranslated - Handle to a collection of framework resource objects.\r\n                This collection identifies the translated (system-physical)\r\n                hardware resources that have been assigned to the device.\r\n                The resources appear from the CPU's point of view.\r\n                Use this list of resources to map I/O space and\r\n                device-accessible memory into virtual address space\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - Failures will be logged, but not acted on.\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    UNREFERENCED_PARAMETER(ResourcesTranslated);\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"--> SerialEvtReleaseHardware\\n\");\r\n\r\n    pDevExt = SerialGetDeviceExtension (Device);\r\n\r\n    //\r\n    // Reset and put the device into a known initial state before releasing the hw resources.\r\n    // In this driver we can recieve this callback only when there is no handle open because\r\n    // we tell the framework to disable stop by calling WdfDeviceSetStaticStopRemove.\r\n    // Since we have already reset the device in our close handler, we don't have to\r\n    // do anything other than unmapping the I/O resources.\r\n    //\r\n\r\n    //\r\n    // Unmap any Memory-Mapped registers. Disconnecting from the interrupt will\r\n    // be done automatically by the framework.\r\n    //\r\n    SerialUnmapHWResources(pDevExt);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"<-- SerialEvtReleaseHardware\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialEvtDeviceD0EntryPostInterruptsEnabled(\r\n    IN WDFDEVICE Device,\r\n    IN WDF_POWER_DEVICE_STATE PreviousState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    EvtDeviceD0EntryPostInterruptsEnabled is called by the framework after the\r\n    driver has enabled the device's hardware interrupts.\r\n\r\n    This function is not marked pageable because this function is in the\r\n    device power up path. When a function is marked pagable and the code\r\n    section is paged out, it will generate a page fault which could impact\r\n    the fast resume behavior because the client driver will have to wait\r\n    until the system drivers can service this page fault.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    PreviousState - A WDF_POWER_DEVICE_STATE-typed enumerator that identifies\r\n                    the previous device power state.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - Failures will be logged, but not acted on.\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device);\r\n    PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt);\r\n    WDF_INTERRUPT_INFO info;\r\n\r\n    UNREFERENCED_PARAMETER(PreviousState);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"--> SerialEvtDeviceD0EntryPostInterruptsEnabled\\n\");\r\n    //\r\n    // The following lines of code show how to call WdfInterruptGetInfo.\r\n    //\r\n    WDF_INTERRUPT_INFO_INIT(&info);\r\n    WdfInterruptGetInfo(extension->WdfInterrupt, &info);\r\n\r\n    WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL);\r\n    interruptContext->IsInterruptConnected = TRUE;\r\n    WdfWaitLockRelease(interruptContext->InterruptStateLock);\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialEvtDeviceD0ExitPreInterruptsDisabled(\r\n    IN WDFDEVICE Device,\r\n    IN WDF_POWER_DEVICE_STATE TargetState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    EvtDeviceD0ExitPreInterruptsDisabled is called by the framework before the\r\n    driver disables the device's hardware interrupts.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    TargetState - A WDF_POWER_DEVICE_STATE-typed enumerator that identifies the\r\n                  device power state that the device is about to enter.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - Failures will be logged, but not acted on.\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION extension = SerialGetDeviceExtension(Device);\r\n    PSERIAL_INTERRUPT_CONTEXT interruptContext = SerialGetInterruptContext(extension->WdfInterrupt);\r\n\r\n    UNREFERENCED_PARAMETER(TargetState);\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"--> SerialEvtDeviceD0ExitPreInterruptsDisabled\\n\");\r\n\r\n    WdfWaitLockAcquire(interruptContext->InterruptStateLock, NULL);\r\n    interruptContext->IsInterruptConnected = FALSE;\r\n    WdfWaitLockRelease(interruptContext->InterruptStateLock);\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialSetPowerPolicy(\r\n    IN PSERIAL_DEVICE_EXTENSION DeviceExtension\r\n    )\r\n{\r\n    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;\r\n    //WDF_POWER_POLICY_EVENT_CALLBACKS    powerPolicyCallbacks;\r\n    NTSTATUS    status = STATUS_SUCCESS;\r\n    WDFDEVICE hDevice = DeviceExtension->WdfDevice;\r\n    ULONG powerOnClose;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \"--> SerialSetPowerPolicy\\n\");\r\n\r\n    PAGED_CODE();\r\n\r\n    //\r\n    // Find out whether we want to power down the device when there no handles open.\r\n    //\r\n    SerialGetRegistryKeyValue(hDevice, L\"EnablePowerManagement\",  &powerOnClose);\r\n    DeviceExtension->RetainPowerOnClose = powerOnClose ? TRUE : FALSE;\r\n\r\n    //\r\n    // In some drivers, the device must be specifically programmed to enable\r\n    // wake signals.  UARTs were designed long, long before such a concept.  So\r\n    // this driver, which just drives UARTs, doesn't register wake arm/disarm\r\n    // callbacks.  Arming or disarming for UARTs has to be handled by side-band\r\n    // code that controls hardware designed more recently.  In this case, ACPI\r\n    // is handling it.  If one were to write a driver which implemented a more\r\n    // modern serial device, one might need to use these callbacks.\r\n    //\r\n\r\n    //\r\n    // Init the power policy callbacks\r\n    //\r\n    //WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks);\r\n\r\n    //\r\n    // This group of three callbacks allows this sample driver to manage\r\n    // arming the device for wake from the S0 state.\r\n    //\r\n\r\n    //powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = SerialEvtDeviceWakeArmS0;\r\n    //powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = SerialEvtDeviceWakeDisarmS0;\r\n    //powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = SerialEvtDeviceWakeTriggeredS0;\r\n\r\n    //\r\n    // This group of three callbacks allows the device to be armed for wake\r\n    // from Sx (S1, S2, S3 or S4.)  Networking devices can optionally be put\r\n    // into a state where a packet sent to them will cause the device's wake\r\n    // signal to be triggered, which causes the machine to wake, moving back\r\n    // into the S0 state.\r\n    //\r\n\r\n    //powerPolicyCallbacks.EvtDeviceArmWakeFromSx = SerialEvtDeviceWakeArmSx;\r\n    //powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = SerialEvtDeviceWakeDisarmSx;\r\n    //powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = SerialEvtDeviceWakeTriggeredSx;\r\n\r\n    //\r\n    // Register the power policy callbacks.\r\n    //\r\n    //WdfDeviceSetPowerPolicyEventCallbacks(hDevice, &powerPolicyCallbacks);\r\n\r\n    //\r\n    // Init the idle policy structure. By setting IdleCannotWakeFromS0 we tell the framework\r\n    // to power down the device without arming for wake. The only way the device can come\r\n    // back to D0 is when we call WdfDeviceStopIdle in SerialEvtDeviceFileCreate.\r\n    // We can't choose IdleCanWakeFromS0 by default is because onboard serial ports typically\r\n    // don't have wake capability. If the driver is used for plugin boards that does support\r\n    // wait-wake, you can update the settings to match that. If MS provided modem driver\r\n    // is used on ports that does support wake on ring, then it will update the settings\r\n    // by sending an internal ioctl to us.\r\n    //\r\n    WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0);\r\n    if(DeviceExtension->OwnsPowerPolicy && !DeviceExtension->RetainPowerOnClose) {\r\n        //\r\n        // Since we don't have to retain power when there are no open handles, we\r\n        // register for idle power management to save power. Check the use of\r\n        // WdfDeviceStopIdle in SerialEvtDeviceFileCreate.\r\n        //\r\n        idleSettings.UserControlOfIdleSettings = IdleAllowUserControl;\r\n\r\n        status = WdfDeviceAssignS0IdleSettings(hDevice, &idleSettings);\r\n        if ( !NT_SUCCESS(status)) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                                \"WdfDeviceSetPowerPolicyS0IdlePolicy failed %x \\n\", status);\r\n            return status;\r\n        }\r\n    }\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<-- SerialSetPowerPolicy\\n\");\r\n\r\n    return status;\r\n}\r\n\r\nUINT32\r\nSerialReportMaxBaudRate(ULONG Bauds)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine returns the max baud rate given a selection of rates\r\n\r\nArguments:\r\n\r\n   Bauds  -  Bit-encoded list of supported bauds\r\n\r\n\r\n  Return Value:\r\n\r\n   The max baud rate listed in Bauds\r\n\r\n--*/\r\n{\r\n    int i;\r\n\r\n    PAGED_CODE();\r\n\r\n    for(i=0; SupportedBaudRates[i].BaudRate != SERIAL_BAUD_INVALID; i++) {\r\n\r\n        if(Bauds & SupportedBaudRates[i].Mask) {\r\n            return SupportedBaudRates[i].BaudRate;\r\n        }\r\n    }\r\n\r\n    //\r\n    // We're in bad shape\r\n    //\r\n\r\n    return 0;\r\n}\r\n\r\nNTSTATUS\r\nSerialInitController(\r\n    IN PSERIAL_DEVICE_EXTENSION pDevExt,\r\n    IN PCONFIG_DATA PConfigData\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Really too many things to mention here.  In general initializes\r\n    kernel synchronization structures, allocates the typeahead buffer,\r\n    sets up defaults, etc.\r\n\r\nArguments:\r\n\r\n    PDevObj       - Device object for the device to be started\r\n\r\n    PConfigData   - Pointer to a record for a single port.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCCESS if everything went ok.  A !NT_SUCCESS status\r\n    otherwise.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    SHORT junk;\r\n    int i;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"--> SerialInitController for %wZ\\n\",\r\n                                                    &pDevExt->DeviceName);\r\n\r\n    //\r\n    // Save the value of clock input to the part.  We use this to calculate\r\n    // the divisor latch value.  The value is in Hertz.\r\n    //\r\n\r\n    pDevExt->ClockRate = PConfigData->ClockRate;\r\n\r\n\r\n    //\r\n    // Save if we have to enable TI's auto flow control\r\n    //\r\n\r\n\r\n    pDevExt->TL16C550CAFC = PConfigData->TL16C550CAFC;\r\n\r\n\r\n    //\r\n    // Map the memory for the control registers for the serial device\r\n    // into virtual memory.\r\n    //\r\n    pDevExt->Controller =\r\n      SerialGetMappedAddress(PConfigData->TrController,\r\n                             PConfigData->SpanOfController,\r\n                             (BOOLEAN)PConfigData->AddressSpace,\r\n                             &pDevExt->UnMapRegisters);\r\n\r\n\r\n    if (!pDevExt->Controller) {\r\n\r\n      SerialLogError(\r\n                    pDevExt->DriverObject,\r\n                    pDevExt->DeviceObject,\r\n                    PConfigData->TrController,\r\n                    SerialPhysicalZero,\r\n                    0,\r\n                    0,\r\n                    0,\r\n                    7,\r\n                    STATUS_SUCCESS,\r\n                    SERIAL_REGISTERS_NOT_MAPPED,\r\n                    pDevExt->DeviceName.Length+sizeof(WCHAR),\r\n                    pDevExt->DeviceName.Buffer,\r\n                    0,\r\n                    NULL\r\n                    );\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_WARNING, DBG_PNP, \"Could not map memory for device \"\r\n                       \"registers for %wZ\\n\", &pDevExt->DeviceName);\r\n\r\n      pDevExt->UnMapRegisters = FALSE;\r\n      status = STATUS_NONE_MAPPED;\r\n      goto ExtensionCleanup;\r\n\r\n    }\r\n\r\n    pDevExt->AddressSpace          = PConfigData->AddressSpace;\r\n    pDevExt->SpanOfController      = PConfigData->SpanOfController;\r\n\r\n    //\r\n    // Save off the interface type and the bus number.\r\n    //\r\n\r\n    pDevExt->Vector = PConfigData->TrVector;\r\n    pDevExt->Irql = (UCHAR)PConfigData->TrIrql;\r\n    pDevExt->InterruptMode = PConfigData->InterruptMode;\r\n    pDevExt->Affinity = PConfigData->Affinity;\r\n\r\n    //\r\n    // If the user said to permit sharing within the device, propagate this\r\n    // through.\r\n    //\r\n\r\n    pDevExt->PermitShare = PConfigData->PermitShare;\r\n\r\n\r\n    //\r\n    // Before we test whether the port exists (which will enable the FIFO)\r\n    // convert the rx trigger value to what should be used in the register.\r\n    //\r\n    // If a bogus value was given - crank them down to 1.\r\n    //\r\n    // If this is a \"souped up\" UART with like a 64 byte FIFO, they\r\n    // should use the appropriate \"spoofing\" value to get the desired\r\n    // results.  I.e., if on their chip 0xC0 in the FCR is for 64 bytes,\r\n    // they should specify 14 in the registry.\r\n    //\r\n\r\n    switch (PConfigData->RxFIFO) {\r\n\r\n    case 1:\r\n\r\n      pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;\r\n      break;\r\n\r\n    case 4:\r\n\r\n      pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;\r\n      break;\r\n\r\n    case 8:\r\n\r\n      pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;\r\n      break;\r\n\r\n    case 14:\r\n\r\n      pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;\r\n      break;\r\n\r\n    default:\r\n\r\n      pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;\r\n      break;\r\n\r\n    }\r\n\r\n\r\n    if (PConfigData->TxFIFO < 1) {\r\n\r\n      pDevExt->TxFifoAmount = 1;\r\n\r\n    } else {\r\n\r\n      pDevExt->TxFifoAmount = PConfigData->TxFIFO;\r\n\r\n    }\r\n\r\n    if (!SerialDoesPortExist(\r\n                           pDevExt,\r\n                           &pDevExt->DeviceName,\r\n                           PConfigData->ForceFifoEnable,\r\n                           PConfigData->LogFifo\r\n                           )) {\r\n\r\n      //\r\n      // We couldn't verify that there was actually a\r\n      // port. No need to log an error as the port exist\r\n      // code will log exactly why.\r\n      //\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_WARNING, DBG_PNP, \"DoesPortExist test failed for \"\r\n                       \"%wZ\\n\", &pDevExt->DeviceName);\r\n\r\n      status = STATUS_NO_SUCH_DEVICE;\r\n      goto ExtensionCleanup;\r\n\r\n    }\r\n\r\n\r\n    //\r\n    // If the user requested that we disable the port, then\r\n    // do it now.  Log the fact that the port has been disabled.\r\n    //\r\n\r\n    if (PConfigData->DisablePort) {\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"disabled port %wZ as requested in \"\r\n                       \"configuration\\n\", &pDevExt->DeviceName);\r\n\r\n      status = STATUS_NO_SUCH_DEVICE;\r\n\r\n      SerialLogError(\r\n                    pDevExt->DriverObject,\r\n                    pDevExt->DeviceObject,\r\n                    PConfigData->TrController,\r\n                    SerialPhysicalZero,\r\n                    0,\r\n                    0,\r\n                    0,\r\n                    57,\r\n                    STATUS_SUCCESS,\r\n                    SERIAL_DISABLED_PORT,\r\n                    pDevExt->DeviceName.Length+sizeof(WCHAR),\r\n                    pDevExt->DeviceName.Buffer,\r\n                    0,\r\n                    NULL\r\n                    );\r\n\r\n      goto ExtensionCleanup;\r\n\r\n    }\r\n\r\n\r\n\r\n    //\r\n    // Set up the default device control fields.\r\n    // Note that if the values are changed after\r\n    // the file is open, they do NOT revert back\r\n    // to the old value at file close.\r\n    //\r\n\r\n    pDevExt->SpecialChars.XonChar      = SERIAL_DEF_XON;\r\n    pDevExt->SpecialChars.XoffChar     = SERIAL_DEF_XOFF;\r\n    pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;\r\n    pDevExt->HandFlow.FlowReplace      = SERIAL_RTS_CONTROL;\r\n\r\n\r\n    //\r\n    // Default Line control protocol. 7E1\r\n    //\r\n    // Seven data bits.\r\n    // Even parity.\r\n    // 1 Stop bits.\r\n    //\r\n\r\n    pDevExt->LineControl = SERIAL_7_DATA |\r\n                           SERIAL_EVEN_PARITY |\r\n                           SERIAL_NONE_PARITY;\r\n\r\n    pDevExt->ValidDataMask = 0x7f;\r\n    pDevExt->CurrentBaud   = 1200;\r\n\r\n\r\n    //\r\n    // We set up the default xon/xoff limits.\r\n    //\r\n    // This may be a bogus value.  It looks like the BufferSize\r\n    // is not set up until the device is actually opened.\r\n    //\r\n\r\n    pDevExt->HandFlow.XoffLimit    = pDevExt->BufferSize >> 3;\r\n    pDevExt->HandFlow.XonLimit     = pDevExt->BufferSize >> 1;\r\n\r\n    pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+\r\n                                  (pDevExt->BufferSize>>4));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \" The default interrupt read buffer size is: %d\\n\"\r\n                    \"------  The XoffLimit is                         : %d\\n\"\r\n                    \"------  The XonLimit is                          : %d\\n\"\r\n                    \"------  The pt 8 size is                         : %d\\n\",\r\n                    pDevExt->BufferSize, pDevExt->HandFlow.XoffLimit,\r\n                    pDevExt->HandFlow.XonLimit, pDevExt->BufferSizePt8);\r\n\r\n\r\n    //\r\n    // Go through all the \"named\" baud rates to find out which ones\r\n    // can be supported with this port.\r\n    //\r\n    //\r\n\r\n    pDevExt->SupportedBauds = SERIAL_BAUD_USER;\r\n\r\n\r\n    for(i=0; SupportedBaudRates[i].BaudRate != SERIAL_BAUD_INVALID; i++) {\r\n\r\n        if (!NT_ERROR(SerialGetDivisorFromBaud(\r\n                                            pDevExt->ClockRate,\r\n                                            (LONG)SupportedBaudRates[i].BaudRate,\r\n                                            &junk\r\n                                            ))) {\r\n\r\n            pDevExt->SupportedBauds |= SupportedBaudRates[i].Mask;\r\n         }\r\n    }\r\n\r\n\r\n\r\n\r\n    //\r\n    // Mark this device as not being opened by anyone.  We keep a\r\n    // variable around so that spurious interrupts are easily\r\n    // dismissed by the ISR.\r\n    //\r\n\r\n    SetDeviceIsOpened(pDevExt, FALSE, FALSE);\r\n\r\n    //\r\n    // Store values into the extension for interval timing.\r\n    //\r\n\r\n    //\r\n    // If the interval timer is less than a second then come\r\n    // in with a short \"polling\" loop.\r\n    //\r\n    // For large (> then 2 seconds) use a 1 second poller.\r\n    //\r\n\r\n    pDevExt->ShortIntervalAmount.QuadPart  = -1;\r\n    pDevExt->LongIntervalAmount.QuadPart   = -10000000;\r\n    pDevExt->CutOverAmount.QuadPart        = 200000000;\r\n\r\n    DISABLE_ALL_INTERRUPTS (pDevExt, pDevExt->Controller);\r\n\r\n    WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, (UCHAR)0);\r\n\r\n    // make sure there is no escape character currently set\r\n    pDevExt->EscapeChar = 0;\r\n    //\r\n    // This should set up everything as it should be when\r\n    // a device is to be opened.  We do need to lower the\r\n    // modem lines, and disable the recalcitrant fifo\r\n    // so that it will show up if the user boots to dos.\r\n    //\r\n\r\n    // __WARNING_IRQ_SET_TOO_HIGH:  we are calling interrupt synchronize routine directly. Suppress it because interrupt is not connected yet.\r\n    // __WARNING_INVALID_PARAM_VALUE_1: Interrupt is UNREFERENCED_PARAMETER, so it can be NULL\r\n#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1)\r\n    SerialReset(NULL, pDevExt);\r\n\r\n#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1)\r\n    SerialMarkClose(NULL, pDevExt);\r\n\r\n#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1)\r\n    SerialClrRTS(NULL, pDevExt);\r\n\r\n#pragma warning(suppress: __WARNING_IRQ_SET_TOO_HIGH; suppress: __WARNING_INVALID_PARAM_VALUE_1)\r\n    SerialClrDTR(NULL, pDevExt);\r\n\r\n    //\r\n    // Fill in WMI hardware data\r\n    //\r\n    pDevExt->WmiHwData.IrqNumber = pDevExt->Irql;\r\n    pDevExt->WmiHwData.IrqLevel = pDevExt->Irql;\r\n    pDevExt->WmiHwData.IrqVector = pDevExt->Vector;\r\n    pDevExt->WmiHwData.IrqAffinityMask = pDevExt->Affinity;\r\n    pDevExt->WmiHwData.InterruptType = pDevExt->InterruptMode == Latched\r\n       ? SERIAL_WMI_INTTYPE_LATCHED : SERIAL_WMI_INTTYPE_LEVEL;\r\n    pDevExt->WmiHwData.BaseIOAddress = (ULONG_PTR)pDevExt->Controller;\r\n\r\n    //\r\n    // Fill in WMI device state data (as defaults)\r\n    //\r\n\r\n    pDevExt->WmiCommData.BaudRate = pDevExt->CurrentBaud;\r\n    pDevExt->WmiCommData.BitsPerByte = (pDevExt->LineControl & 0x03) + 5;\r\n    pDevExt->WmiCommData.ParityCheckEnable = (pDevExt->LineControl & 0x08)\r\n       ? TRUE : FALSE;\r\n\r\n    switch (pDevExt->LineControl & SERIAL_PARITY_MASK) {\r\n    case SERIAL_NONE_PARITY:\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;\r\n       break;\r\n\r\n    case SERIAL_ODD_PARITY:\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;\r\n       break;\r\n\r\n    case SERIAL_EVEN_PARITY:\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;\r\n       break;\r\n\r\n    case SERIAL_MARK_PARITY:\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;\r\n       break;\r\n\r\n    case SERIAL_SPACE_PARITY:\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;\r\n       break;\r\n\r\n    default:\r\n       ASSERTMSG(0, \"Illegal Parity setting for WMI\");\r\n       pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;\r\n       break;\r\n    }\r\n\r\n    pDevExt->WmiCommData.StopBits = pDevExt->LineControl & SERIAL_STOP_MASK\r\n       ? (pDevExt->WmiCommData.BitsPerByte == 5 ? SERIAL_WMI_STOP_1_5\r\n          : SERIAL_WMI_STOP_2) : SERIAL_WMI_STOP_1;\r\n    pDevExt->WmiCommData.XoffCharacter = pDevExt->SpecialChars.XoffChar;\r\n    pDevExt->WmiCommData.XoffXmitThreshold = pDevExt->HandFlow.XoffLimit;\r\n    pDevExt->WmiCommData.XonCharacter = pDevExt->SpecialChars.XonChar;\r\n    pDevExt->WmiCommData.XonXmitThreshold = pDevExt->HandFlow.XonLimit;\r\n    pDevExt->WmiCommData.MaximumBaudRate\r\n       = SerialReportMaxBaudRate(pDevExt->SupportedBauds);\r\n    pDevExt->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1);\r\n    pDevExt->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1);\r\n    pDevExt->WmiCommData.Support16BitMode = FALSE;\r\n    pDevExt->WmiCommData.SupportDTRDSR = TRUE;\r\n    pDevExt->WmiCommData.SupportIntervalTimeouts = TRUE;\r\n    pDevExt->WmiCommData.SupportParityCheck = TRUE;\r\n    pDevExt->WmiCommData.SupportRTSCTS = TRUE;\r\n    pDevExt->WmiCommData.SupportXonXoff = TRUE;\r\n    pDevExt->WmiCommData.SettableBaudRate = TRUE;\r\n    pDevExt->WmiCommData.SettableDataBits = TRUE;\r\n    pDevExt->WmiCommData.SettableFlowControl = TRUE;\r\n    pDevExt->WmiCommData.SettableParity = TRUE;\r\n    pDevExt->WmiCommData.SettableParityCheck = TRUE;\r\n    pDevExt->WmiCommData.SettableStopBits = TRUE;\r\n    pDevExt->WmiCommData.IsBusy = FALSE;\r\n\r\n    //\r\n    // Common error path cleanup.  If the status is\r\n    // bad, get rid of the device extension, device object\r\n    // and any memory associated with it.\r\n    //\r\n\r\nExtensionCleanup: ;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<-- SerialInitController %x\\n\", status);\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialMapHWResources(\r\n        IN WDFDEVICE Device,\r\n        IN WDFCMRESLIST PResList,\r\n        IN WDFCMRESLIST PTrResList,\r\n        OUT PCONFIG_DATA PConfig\r\n        )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will get the configuration information and put\r\n    it and the translated values into CONFIG_DATA structures.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    Resources - Handle to a collection of framework resource objects.\r\n                This collection identifies the raw (bus-relative) hardware\r\n                resources that have been assigned to the device.\r\n\r\n    ResourcesTranslated - Handle to a collection of framework resource objects.\r\n                This collection identifies the translated (system-physical)\r\n                hardware resources that have been assigned to the device.\r\n                The resources appear from the CPU's point of view.\r\n                Use this list of resources to map I/O space and\r\n                device-accessible memory into virtual address space\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if consistant configuration was found - otherwise.\r\n    returns STATUS_SERIAL_NO_DEVICE_INITED.\r\n\r\n--*/\r\n\r\n{\r\n   PSERIAL_DEVICE_EXTENSION pDevExt;\r\n   NTSTATUS status = STATUS_SUCCESS;\r\n   ULONG i;\r\n   PCM_PARTIAL_RESOURCE_DESCRIPTOR  pPartialTrResourceDesc, pPartialRawResourceDesc;\r\n   ULONG gotInt = 0;\r\n   ULONG gotIO = 0;\r\n   ULONG ioResIndex = 0;\r\n   ULONG curIoIndex = 0;\r\n   ULONG gotMem = 0;\r\n   BOOLEAN DebugPortInUse = FALSE;\r\n\r\n   PAGED_CODE();\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"--> SerialMapHWResources\\n\");\r\n\r\n   //\r\n   // Get the DeviceExtension..\r\n   //\r\n   pDevExt = SerialGetDeviceExtension (Device);\r\n\r\n   if ((PResList == NULL) || (PTrResList == NULL)) {\r\n        ASSERT(PResList != NULL);\r\n        ASSERT(PTrResList != NULL);\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto End;\r\n   }\r\n\r\n    for (i = 0; i < WdfCmResourceListGetCount(PTrResList); i++) {\r\n\r\n        pPartialTrResourceDesc = WdfCmResourceListGetDescriptor(PTrResList, i);\r\n        pPartialRawResourceDesc = WdfCmResourceListGetDescriptor(PResList, i);\r\n\r\n        switch (pPartialTrResourceDesc->Type) {\r\n        case CmResourceTypePort:\r\n\r\n            ASSERT(!(pPartialTrResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH));\r\n\r\n            if (gotIO == 0) {\r\n\r\n                if (curIoIndex == ioResIndex) {\r\n\r\n                    gotIO = 1;\r\n                    PConfig->TrController  = pPartialTrResourceDesc->u.Port.Start;\r\n\r\n                    if (!PConfig->TrController.LowPart) {\r\n                        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Bogus port address %x\\n\",\r\n                                            PConfig->TrController.LowPart);\r\n                        status = STATUS_DEVICE_CONFIGURATION_ERROR;\r\n                        goto End;\r\n                    }\r\n                    //\r\n                    // We need the raw address to check if the debugger is using the com port\r\n                    //\r\n                    PConfig->Controller  = pPartialRawResourceDesc->u.Port.Start;\r\n                    PConfig->AddressSpace  = pPartialTrResourceDesc->Flags;\r\n                    pDevExt->SerialReadUChar = SerialReadPortUChar;\r\n                    pDevExt->SerialWriteUChar = SerialWritePortUChar;\r\n\r\n                } else {\r\n                    curIoIndex++;\r\n                }\r\n        }\r\n\r\n        break;\r\n\r\n        //\r\n        // If this is 8 bytes long and we haven't found any I/O range,\r\n        // then this is probably a fancy-pants machine with memory replacing\r\n        // IO space\r\n        //\r\n        case CmResourceTypeMemory:\r\n\r\n        ASSERT(!(pPartialTrResourceDesc->u.Port.Length == SERIAL_STATUS_LENGTH));\r\n\r\n        if ((gotMem == 0) && (gotIO == 0)\r\n                         && (pPartialTrResourceDesc->u.Memory.Length\r\n                         == (SERIAL_REGISTER_SPAN + SERIAL_STATUS_LENGTH))) {\r\n            gotMem = 1;\r\n            PConfig->TrController = pPartialTrResourceDesc->u.Memory.Start;\r\n\r\n            if (!PConfig->TrController.LowPart) {\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Bogus I/O memory address %x\\n\",\r\n                                    PConfig->TrController.LowPart);\r\n                status = STATUS_DEVICE_CONFIGURATION_ERROR;\r\n                goto End;\r\n            }\r\n\r\n            PConfig->Controller = pPartialRawResourceDesc->u.Memory.Start;\r\n            PConfig->AddressSpace = CM_RESOURCE_PORT_MEMORY;\r\n            PConfig->SpanOfController = SERIAL_REGISTER_SPAN;\r\n            pDevExt->SerialReadUChar = SerialReadRegisterUChar;\r\n            pDevExt->SerialWriteUChar = SerialWriteRegisterUChar;\r\n        }\r\n        break;\r\n\r\n        case CmResourceTypeInterrupt:\r\n            if (gotInt == 0) {\r\n                gotInt = 1;\r\n                PConfig->TrVector = pPartialTrResourceDesc->u.Interrupt.Vector;\r\n\r\n                if (!PConfig->TrVector) {\r\n                    SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Bogus vector 0\\n\");\r\n                    status = STATUS_DEVICE_CONFIGURATION_ERROR;\r\n                    goto End;\r\n                }\r\n\r\n               if (pPartialTrResourceDesc->ShareDisposition == CmResourceShareShared) {\r\n                    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"Sharing interrupt with other devices \\n\");\r\n                } else {\r\n                    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"Interrupt is not shared with other devices\\n\");\r\n                }\r\n\r\n                PConfig->TrIrql = pPartialTrResourceDesc->u.Interrupt.Level;\r\n                PConfig->Affinity = pPartialTrResourceDesc->u.Interrupt.Affinity;\r\n            }\r\n        break;\r\n\r\n        default:   break;\r\n        }   // switch (pPartialTrResourceDesc->Type)\r\n\r\n    }       // for (i = 0;     i < WdfCollectionGetCount\r\n\r\n   if(!((gotMem  || gotIO) && gotInt) )\r\n   {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto End;\r\n   }\r\n\r\n   //\r\n   // First check what type of AddressSpace this port is in. Then check\r\n   // if the debugger is using this port. If it is, set DebugPortInUse to TRUE.\r\n   //\r\n   if(PConfig->AddressSpace == CM_RESOURCE_PORT_MEMORY) {\r\n\r\n        PHYSICAL_ADDRESS  KdComPhysical;\r\n\r\n        KdComPhysical = MmGetPhysicalAddress(*KdComPortInUse);\r\n\r\n        if(KdComPhysical.LowPart == PConfig->Controller.LowPart) {\r\n            DebugPortInUse = TRUE;\r\n        }\r\n\r\n   } else {\r\n              //\r\n              // This compare is done using **untranslated** values since that is what\r\n              // the kernel shoves in regardless of the architecture.\r\n              //\r\n\r\n        if ((*KdComPortInUse) == (ULongToPtr(PConfig->Controller.LowPart)))    {\r\n            DebugPortInUse = TRUE;\r\n        }\r\n   }\r\n\r\n   if (DebugPortInUse) {\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Kernel debugger is using port at \"\r\n                       \"address %p\\n\", *KdComPortInUse);\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Serial driver will not load port\\n\");\r\n\r\n      SerialLogError(\r\n                    pDevExt->DriverObject,\r\n                    NULL,\r\n                    PConfig->TrController,\r\n                    SerialPhysicalZero,\r\n                    0,\r\n                    0,\r\n                    0,\r\n                    3,\r\n                    STATUS_SUCCESS,\r\n                    SERIAL_KERNEL_DEBUGGER_ACTIVE,\r\n                    pDevExt->DeviceName.Length+sizeof(WCHAR),\r\n                    pDevExt->DeviceName.Buffer,\r\n                    0,\r\n                    NULL\r\n                    );\r\n\r\n      status = STATUS_INSUFFICIENT_RESOURCES;\r\n      goto End;\r\n   }\r\n\r\nEnd:\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<-- SerialMapHWResources %x\\n\", status);\r\n\r\n   return status;\r\n}\r\n\r\nVOID\r\nSerialUnmapHWResources(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Releases resources (not pool) stored in the device extension.\r\n\r\nArguments:\r\n\r\n    PDevExt - Pointer to the device extension to release resources from.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"-->SerialUnMapResources(%p)\\n\",\r\n                    PDevExt);\r\n   PAGED_CODE();\r\n\r\n   //\r\n   // If necessary, unmap the device registers.\r\n   //\r\n\r\n   if (PDevExt->UnMapRegisters) {\r\n      MmUnmapIoSpace(PDevExt->Controller, PDevExt->SpanOfController);\r\n      PDevExt->UnMapRegisters = FALSE;\r\n   }\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<--SerialUnMapResources\\n\");\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialReadSymName(\r\n    IN                           WDFDEVICE Device,\r\n    _Out_writes_bytes_(*SizeOfRegName) PWSTR RegName,\r\n    _Inout_                      PUSHORT SizeOfRegName\r\n    )\r\n{\r\n    NTSTATUS status;\r\n    WDFKEY hKey;\r\n    UNICODE_STRING value;\r\n    UNICODE_STRING valueName;\r\n    USHORT requiredLength;\r\n\r\n    PAGED_CODE();\r\n\r\n    value.Buffer = RegName;\r\n    value.MaximumLength = *SizeOfRegName;\r\n    value.Length = 0;\r\n\r\n    status = WdfDeviceOpenRegistryKey(Device,\r\n                      PLUGPLAY_REGKEY_DEVICE,\r\n                      STANDARD_RIGHTS_ALL,\r\n                      WDF_NO_OBJECT_ATTRIBUTES,\r\n                      &hKey);\r\n\r\n    if (NT_SUCCESS (status)) {\r\n        //\r\n        // Fetch PortName which contains the suggested REG_SZ symbolic name.\r\n        //\r\n\r\n\r\n        RtlInitUnicodeString(&valueName, L\"PortName\");\r\n\r\n        status = WdfRegistryQueryUnicodeString (hKey,\r\n                          &valueName,\r\n                          &requiredLength,\r\n                          &value);\r\n\r\n        if (!NT_SUCCESS (status)) {\r\n            //\r\n            // This is for PCMCIA which currently puts the name under Identifier.\r\n            //\r\n\r\n            RtlInitUnicodeString(&valueName, L\"Identifier\");\r\n            status = WdfRegistryQueryUnicodeString (hKey,\r\n                                  &valueName,\r\n                                  &requiredLength,\r\n                                  &value);\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n                //\r\n                // Hmm.  Either we have to pick a name or bail...\r\n                //\r\n                SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Getting PortName/Identifier failed - %x\\n\", status);\r\n            }\r\n        }\r\n\r\n        WdfRegistryClose(hKey);\r\n    }\r\n\r\n    if(NT_SUCCESS(status)) {\r\n        //\r\n        // NULL terminate the string and return number of characters in the string.\r\n        //\r\n        if(value.Length > *SizeOfRegName - sizeof(WCHAR)) {\r\n            return STATUS_UNSUCCESSFUL;\r\n        }\r\n\r\n        *SizeOfRegName = value.Length;\r\n        RegName[*SizeOfRegName/sizeof(WCHAR)] = UNICODE_NULL;\r\n    }\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialDoExternalNaming(IN PSERIAL_DEVICE_EXTENSION PDevExt)\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will be used to create a symbolic link\r\n    to the driver name in the given object directory.\r\n\r\n    It will also create an entry in the device map for\r\n    this device - IF we could create the symbolic link.\r\n\r\nArguments:\r\n\r\n    Extension - Pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    WCHAR pRegName[SYMBOLIC_NAME_LENGTH];\r\n    USHORT nameSize = sizeof(pRegName);\r\n    WDFSTRING stringHandle = NULL;\r\n    WDF_OBJECT_ATTRIBUTES attributes;\r\n    DECLARE_UNICODE_STRING_SIZE(symbolicLinkName,SYMBOLIC_NAME_LENGTH ) ;\r\n\r\n    PAGED_CODE();\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);\r\n    attributes.ParentObject = PDevExt->WdfDevice;\r\n    status = WdfStringCreate(NULL, &attributes, &stringHandle);\r\n    if(!NT_SUCCESS(status)){\r\n        goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    status = WdfDeviceRetrieveDeviceName(PDevExt->WdfDevice, stringHandle);\r\n    if(!NT_SUCCESS(status)){\r\n        goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    //\r\n    // Since we are storing the buffer pointer of the string handle in our\r\n    // extension, we will hold onto string handle until the device is deleted.\r\n    //\r\n    WdfStringGetUnicodeString(stringHandle, &PDevExt->DeviceName);\r\n\r\n    SerialGetRegistryKeyValue(PDevExt->WdfDevice, L\"SerialSkipExternalNaming\",  &PDevExt->SkipNaming);\r\n\r\n    if (PDevExt->SkipNaming) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Skipping external naming due to registry settings\\n\");\r\n        return STATUS_SUCCESS;\r\n    }\r\n\r\n    status = SerialReadSymName(PDevExt->WdfDevice, pRegName, &nameSize);\r\n    if (!NT_SUCCESS(status)) {\r\n        goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"DosName is %ws\\n\", pRegName);\r\n\r\n    status = RtlUnicodeStringPrintf(&symbolicLinkName,\r\n                                    L\"%ws%ws\",\r\n                                    L\"\\\\DosDevices\\\\\",\r\n                                    pRegName);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n      goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    status = WdfDeviceCreateSymbolicLink(PDevExt->WdfDevice, &symbolicLinkName);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Couldn't create the symbolic link for port %wZ\\n\", &symbolicLinkName);\r\n\r\n      goto SerialDoExternalNamingError;\r\n\r\n    }\r\n\r\n\r\n    PDevExt->CreatedSymbolicLink = TRUE;\r\n\r\n    status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,\r\n                                   PDevExt->DeviceName.Buffer,\r\n                                   REG_SZ,\r\n                                   pRegName,\r\n                                   nameSize + sizeof(WCHAR));\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Couldn't create the device map entry\\n\"\r\n                       \"------- for port %ws\\n\", PDevExt->DeviceName.Buffer);\r\n\r\n      goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    PDevExt->CreatedSerialCommEntry = TRUE;\r\n\r\n    //\r\n    // Make the device visible via a device association as well.\r\n    // The reference string is the eight digit device index\r\n    //\r\n    status = WdfDeviceCreateDeviceInterface(PDevExt->WdfDevice,\r\n                                            (LPGUID) &GUID_DEVINTERFACE_COMPORT,\r\n                                            NULL);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP, \"Couldn't register class association\\n\"\r\n                       \"for port %wZ\\n\", &PDevExt->DeviceName);\r\n\r\n        goto SerialDoExternalNamingError;\r\n    }\r\n\r\n    return status;\r\n\r\n    SerialDoExternalNamingError:;\r\n\r\n    //\r\n    // Clean up error conditions\r\n    //\r\n\r\n    PDevExt->DeviceName.Buffer = NULL;\r\n\r\n    if (PDevExt->CreatedSerialCommEntry) {\r\n        _Analysis_assume_(NULL != PDevExt->DeviceName.Buffer);\r\n        RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,\r\n                               PDevExt->DeviceName.Buffer);\r\n    }\r\n\r\n    if(stringHandle) {\r\n        WdfObjectDelete(stringHandle);\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nSerialUndoExternalNaming(IN PSERIAL_DEVICE_EXTENSION Extension)\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will be used to delete a symbolic link\r\n    to the driver name in the given object directory.\r\n\r\n    It will also delete an entry in the device map for\r\n    this device if the symbolic link had been created.\r\n\r\nArguments:\r\n\r\n    Extension - Pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n   NTSTATUS status;\r\n   PWCHAR   deviceName = Extension->DeviceName.Buffer;\r\n\r\n   PAGED_CODE();\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                    \"In SerialUndoExternalNaming for extension: \"\r\n                    \"%p of port %ws\\n\", Extension, deviceName);\r\n\r\n   //\r\n   // Maybe there is nothing for us to do\r\n   //\r\n\r\n   if (Extension->SkipNaming) {\r\n      return;\r\n   }\r\n\r\n   //\r\n   // We're cleaning up here.  One reason we're cleaning up\r\n   // is that we couldn't allocate space for the NtNameOfPort.\r\n   //\r\n\r\n   if ((deviceName !=  NULL)  && Extension->CreatedSerialCommEntry) {\r\n\r\n      status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP,\r\n                                      SERIAL_DEVICE_MAP,\r\n                                      deviceName);\r\n      if (!NT_SUCCESS(status)) {\r\n\r\n         SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,\r\n                          \"Couldn't delete value entry %ws\\n\",\r\n                          deviceName);\r\n\r\n      }\r\n   }\r\n}\r\n\r\nVOID\r\nSerialPurgePendingRequests(PSERIAL_DEVICE_EXTENSION pDevExt)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This routine completes any irps pending for the passed device object.\r\n\r\nArguments:\r\n\r\n    PDevObj - Pointer to the device object whose irps must die.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                     \">SerialPurgePendingRequests(%p)\\n\", pDevExt);\r\n\r\n    //\r\n    // Then cancel all the reads and writes.\r\n    //\r\n\r\n    SerialPurgeRequests(pDevExt->WriteQueue,  &pDevExt->CurrentWriteRequest);\r\n\r\n    SerialPurgeRequests(pDevExt->ReadQueue,  &pDevExt->CurrentReadRequest);\r\n\r\n    //\r\n    // Next get rid of purges.\r\n    //\r\n\r\n    SerialPurgeRequests(pDevExt->PurgeQueue,  &pDevExt->CurrentPurgeRequest);\r\n\r\n    //\r\n    // Get rid of any mask operations.\r\n    //\r\n\r\n    SerialPurgeRequests( pDevExt->MaskQueue,   &pDevExt->CurrentMaskRequest);\r\n\r\n    //\r\n    // Now get rid of pending wait mask request.\r\n    //\r\n\r\n    if (pDevExt->CurrentWaitRequest) {\r\n\r\n        status = SerialClearCancelRoutine(pDevExt->CurrentWaitRequest, TRUE );\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            SerialCompleteRequest(pDevExt->CurrentWaitRequest, STATUS_CANCELLED, 0);\r\n            pDevExt->CurrentWaitRequest = NULL;\r\n\r\n        }\r\n\r\n    }\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \"<SerialPurgePendingRequests\\n\");\r\n}\r\n\r\nBOOLEAN\r\nSerialDoesPortExist(\r\n                   IN PSERIAL_DEVICE_EXTENSION Extension,\r\n                   IN PUNICODE_STRING InsertString,\r\n                   IN ULONG ForceFifo,\r\n                   IN ULONG LogFifo\r\n                   )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine examines several of what might be the serial device\r\n    registers.  It ensures that the bits that should be zero are zero.\r\n\r\n    In addition, this routine will determine if the device supports\r\n    fifo's.  If it does it will enable the fifo's and turn on a boolean\r\n    in the extension that indicates the fifo's presence.\r\n\r\n    NOTE: If there is indeed a serial port at the address specified\r\n          it will absolutely have interrupts inhibited upon return\r\n          from this routine.\r\n\r\n    NOTE: Since this routine should be called fairly early in\r\n          the device driver initialization, the only element\r\n          that needs to be filled in is the base register address.\r\n\r\n    NOTE: These tests all assume that this code is the only\r\n          code that is looking at these ports or this memory.\r\n\r\n          This is a not to unreasonable assumption even on\r\n          multiprocessor systems.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to a serial device extension.\r\n    InsertString - String to place in an error log entry.\r\n    ForceFifo - !0 forces the fifo to be left on if found.\r\n    LogFifo - !0 forces a log message if fifo found.\r\n\r\nReturn Value:\r\n\r\n    Will return true if the port really exists, otherwise it\r\n    will return false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n\r\n   UCHAR regContents;\r\n   BOOLEAN returnValue = TRUE;\r\n   UCHAR oldIERContents;\r\n   UCHAR oldLCRContents;\r\n   USHORT value1;\r\n   USHORT value2;\r\n   KIRQL oldIrql;\r\n\r\n   //\r\n   // Save of the line control.\r\n   //\r\n\r\n   oldLCRContents = READ_LINE_CONTROL(Extension, Extension->Controller);\r\n\r\n   //\r\n   // Make sure that we are *aren't* accessing the divsior latch.\r\n   //\r\n\r\n   WRITE_LINE_CONTROL(Extension,\r\n                     Extension->Controller,\r\n                     (UCHAR)(oldLCRContents & ~SERIAL_LCR_DLAB)\r\n                     );\r\n\r\n   oldIERContents = READ_INTERRUPT_ENABLE(Extension, Extension->Controller);\r\n\r\n   //\r\n   // Go up to power level for a very short time to prevent\r\n   // any interrupts from this device from coming in.\r\n   //\r\n\r\n   KeRaiseIrql(\r\n              POWER_LEVEL,\r\n              &oldIrql\r\n              );\r\n\r\n   WRITE_INTERRUPT_ENABLE(Extension,\r\n                         Extension->Controller,\r\n                         0x0f\r\n                         );\r\n\r\n   value1 = READ_INTERRUPT_ENABLE(Extension, Extension->Controller);\r\n   value1 = value1 << 8;\r\n   value1 |= READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n   READ_DIVISOR_LATCH(Extension,\r\n                      Extension->Controller,\r\n                      (PSHORT) &value2\r\n                      );\r\n\r\n   WRITE_LINE_CONTROL(Extension,\r\n                     Extension->Controller,\r\n                     oldLCRContents\r\n                     );\r\n\r\n   //\r\n   // Put the ier back to where it was before.  If we are on a\r\n   // level sensitive port this should prevent the interrupts\r\n   // from coming in.  If we are on a latched, we don't care\r\n   // cause the interrupts generated will just get dropped.\r\n   //\r\n\r\n   WRITE_INTERRUPT_ENABLE(Extension,\r\n                         Extension->Controller,\r\n                         oldIERContents\r\n                         );\r\n\r\n   KeLowerIrql(oldIrql);\r\n\r\n   if (value1 == value2) {\r\n\r\n      SerialLogError(\r\n                    Extension->DeviceObject->DriverObject,\r\n                    Extension->DeviceObject,\r\n                    SerialPhysicalZero,\r\n                    SerialPhysicalZero,\r\n                    0,\r\n                    0,\r\n                    0,\r\n                    62,\r\n                    STATUS_SUCCESS,\r\n                    SERIAL_DLAB_INVALID,\r\n                    InsertString->Length+sizeof(WCHAR),\r\n                    InsertString->Buffer,\r\n                    0,\r\n                    NULL\r\n                    );\r\n      returnValue = FALSE;\r\n      goto AllDone;\r\n\r\n   }\r\n\r\n   AllDone: ;\r\n\r\n\r\n   //\r\n   // If we think that there is a serial device then we determine\r\n   // if a fifo is present.\r\n   //\r\n\r\n   if (returnValue) {\r\n\r\n      //\r\n      // Well, we think it's a serial device.  Absolutely\r\n      // positively, prevent interrupts from occuring.\r\n      //\r\n      // We disable all the interrupt enable bits, and\r\n      // push down all the lines in the modem control\r\n      // We only needed to push down OUT2 which in\r\n      // PC's must also be enabled to get an interrupt.\r\n      //\r\n\r\n      DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n      WRITE_MODEM_CONTROL(Extension, Extension->Controller, (UCHAR)0);\r\n\r\n      //\r\n      // See if this is a 16550.  We do this by writing to\r\n      // what would be the fifo control register with a bit\r\n      // pattern that tells the device to enable fifo's.\r\n      // We then read the iterrupt Id register to see if the\r\n      // bit pattern is present that identifies the 16550.\r\n      //\r\n\r\n      WRITE_FIFO_CONTROL(Extension,\r\n                        Extension->Controller,\r\n                        SERIAL_FCR_ENABLE\r\n                        );\r\n\r\n      regContents = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);\r\n\r\n      if (regContents & SERIAL_IIR_FIFOS_ENABLED) {\r\n\r\n         //\r\n         // Save off that the device supports fifos.\r\n         //\r\n\r\n         Extension->FifoPresent = TRUE;\r\n\r\n         //\r\n         // There is a fine new \"super\" IO chip out there that\r\n         // will get stuck with a line status interrupt if you\r\n         // attempt to clear the fifo and enable it at the same\r\n         // time if data is present.  The best workaround seems\r\n         // to be that you should turn off the fifo read a single\r\n         // byte, and then re-enable the fifo.\r\n         //\r\n\r\n         WRITE_FIFO_CONTROL(Extension,\r\n                           Extension->Controller,\r\n                           (UCHAR)0\r\n                           );\r\n\r\n         READ_RECEIVE_BUFFER(Extension, Extension->Controller);\r\n\r\n         //\r\n         // There are fifos on this card.  Set the value of the\r\n         // receive fifo to interrupt when 4 characters are present.\r\n         //\r\n\r\n         WRITE_FIFO_CONTROL(Extension, Extension->Controller,\r\n                            (UCHAR)(SERIAL_FCR_ENABLE\r\n                                    | Extension->RxFifoTrigger\r\n                                    | SERIAL_FCR_RCVR_RESET\r\n                                    | SERIAL_FCR_TXMT_RESET));\r\n\r\n      }\r\n\r\n      //\r\n      // The !Extension->FifoPresent is included in the test so that\r\n      // broken chips like the WinBond will still work after we test\r\n      // for the fifo.\r\n      //\r\n\r\n      if (!ForceFifo || !Extension->FifoPresent) {\r\n\r\n         Extension->FifoPresent = FALSE;\r\n         WRITE_FIFO_CONTROL(Extension,\r\n                           Extension->Controller,\r\n                           (UCHAR)0\r\n                           );\r\n\r\n      }\r\n\r\n      if (Extension->FifoPresent) {\r\n\r\n         if (LogFifo) {\r\n\r\n            SerialLogError(\r\n                          Extension->DeviceObject->DriverObject,\r\n                          Extension->DeviceObject,\r\n                          SerialPhysicalZero,\r\n                          SerialPhysicalZero,\r\n                          0,\r\n                          0,\r\n                          0,\r\n                          15,\r\n                          STATUS_SUCCESS,\r\n                          SERIAL_FIFO_PRESENT,\r\n                          InsertString->Length+sizeof(WCHAR),\r\n                          InsertString->Buffer,\r\n                          0,\r\n                          NULL\r\n                          );\r\n\r\n         }\r\n\r\n         SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP,\r\n                          \"Fifo's detected at port address: %p\\n\",\r\n                          Extension->Controller);\r\n      }\r\n   }\r\n\r\n   return returnValue;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialReset(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This places the hardware in a standard configuration.\r\n\r\n    NOTE: This assumes that it is called at interrupt level.\r\n\r\n\r\nArguments:\r\n\r\n    Context - The device extension for serial device\r\n    being managed.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n   PSERIAL_DEVICE_EXTENSION extension = Context;\r\n   UCHAR regContents;\r\n   UCHAR oldModemControl;\r\n   ULONG i;\r\n\r\n   UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n   //\r\n   // Adjust the out2 bit.\r\n   // This will also prevent any interrupts from occuring.\r\n   //\r\n\r\n   oldModemControl = READ_MODEM_CONTROL(extension, extension->Controller);\r\n\r\n   WRITE_MODEM_CONTROL(extension, extension->Controller,\r\n                       (UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2));\r\n\r\n   //\r\n   // Reset the fifo's if there are any.\r\n   //\r\n\r\n   if (extension->FifoPresent) {\r\n\r\n      //\r\n      // There is a fine new \"super\" IO chip out there that\r\n      // will get stuck with a line status interrupt if you\r\n      // attempt to clear the fifo and enable it at the same\r\n      // time if data is present.  The best workaround seems\r\n      // to be that you should turn off the fifo read a single\r\n      // byte, and then re-enable the fifo.\r\n      //\r\n\r\n      WRITE_FIFO_CONTROL(extension,\r\n                        extension->Controller,\r\n                        (UCHAR)0\r\n                        );\r\n\r\n      READ_RECEIVE_BUFFER(extension, extension->Controller);\r\n\r\n      WRITE_FIFO_CONTROL(extension,\r\n                        extension->Controller,\r\n                        (UCHAR)(SERIAL_FCR_ENABLE | extension->RxFifoTrigger |\r\n                                SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)\r\n                        );\r\n\r\n   }\r\n\r\n   //\r\n   // Make sure that the line control set up correct.\r\n   //\r\n   // 1) Make sure that the Divisor latch select is set\r\n   //    up to select the transmit and receive register.\r\n   //\r\n   // 2) Make sure that we aren't in a break state.\r\n   //\r\n\r\n   regContents = READ_LINE_CONTROL(extension, extension->Controller);\r\n   regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK);\r\n\r\n   WRITE_LINE_CONTROL(extension,\r\n                     extension->Controller,\r\n                     regContents\r\n                     );\r\n\r\n   //\r\n   // Read the receive buffer until the line status is\r\n   // clear.  (Actually give up after a 5 reads.)\r\n   //\r\n\r\n   for (i = 0;\r\n       i < 5;\r\n       i++\r\n       ) {\r\n                                              #pragma warning(disable: 4127)\r\n      if (IsNotNEC_98) {\r\n                                              #pragma warning(default: 4127)\r\n         READ_RECEIVE_BUFFER(extension, extension->Controller);\r\n         if (!(READ_LINE_STATUS(extension, extension->Controller) & 1)) {\r\n\r\n            break;\r\n\r\n         }\r\n      } else {\r\n          //\r\n          // I get incorrect data when read enpty buffer.\r\n          // But do not read no data! for PC98!\r\n          //\r\n          if (!(READ_LINE_STATUS(extension, extension->Controller) & 1)) {\r\n\r\n             break;\r\n\r\n          }\r\n          READ_RECEIVE_BUFFER(extension, extension->Controller);\r\n      }\r\n\r\n   }\r\n\r\n   //\r\n   // Read the modem status until the low 4 bits are\r\n   // clear.  (Actually give up after a 5 reads.)\r\n   //\r\n\r\n   for (i = 0;\r\n       i < 1000;\r\n       i++\r\n       ) {\r\n\r\n      if (!(READ_MODEM_STATUS(extension, extension->Controller) & 0x0f)) {\r\n\r\n         break;\r\n\r\n      }\r\n\r\n   }\r\n\r\n   //\r\n   // Now we set the line control, modem control, and the\r\n   // baud to what they should be.\r\n   //\r\n\r\n   //\r\n   // See if we have to enable special Auto Flow Control\r\n   //\r\n\r\n   if (extension->TL16C550CAFC) {\r\n      oldModemControl = READ_MODEM_CONTROL(extension, extension->Controller);\r\n\r\n      WRITE_MODEM_CONTROL(extension, extension->Controller,\r\n                          (UCHAR)(oldModemControl | SERIAL_MCR_TL16C550CAFE));\r\n   }\r\n\r\n\r\n\r\n   SerialSetLineControl(extension->WdfInterrupt, extension);\r\n\r\n   SerialSetupNewHandFlow(\r\n                         extension,\r\n                         &extension->HandFlow\r\n                         );\r\n\r\n   SerialHandleModemUpdate(\r\n                          extension,\r\n                          FALSE\r\n                          );\r\n\r\n   {\r\n      SHORT  appropriateDivisor;\r\n      SERIAL_IOCTL_SYNC s;\r\n\r\n      SerialGetDivisorFromBaud( extension->ClockRate,\r\n                                extension->CurrentBaud,\r\n                                &appropriateDivisor );\r\n\r\n      s.Extension = extension;\r\n      s.Data = (PVOID) (ULONG_PTR) appropriateDivisor;\r\n      SerialSetBaud(extension->WdfInterrupt, &s);\r\n   }\r\n\r\n   //\r\n   // Enable which interrupts we want to receive.\r\n   //\r\n   // NOTE NOTE: This does not actually let interrupts\r\n   // occur.  We must still raise the OUT2 bit in the\r\n   // modem control register.  We will do that on open.\r\n   //\r\n\r\n   ENABLE_ALL_INTERRUPTS(extension, extension->Controller);\r\n\r\n   //\r\n   // Read the interrupt id register until the low bit is\r\n   // set.  (Actually give up after a 5 reads.)\r\n   //\r\n\r\n   for (i = 0;\r\n       i < 5;\r\n       i++\r\n       ) {\r\n\r\n      if (READ_INTERRUPT_ID_REG(extension, extension->Controller) & 0x01) {\r\n\r\n         break;\r\n\r\n      }\r\n\r\n   }\r\n\r\n   //\r\n   // Now we know that nothing could be transmitting at this point\r\n   // so we set the HoldingEmpty indicator.\r\n   //\r\n\r\n   extension->HoldingEmpty = TRUE;\r\n\r\n   return FALSE;\r\n}\r\n\r\n\r\n\r\nPVOID\r\nSerialGetMappedAddress(\r\n    PHYSICAL_ADDRESS IoAddress,\r\n    ULONG NumberOfBytes,\r\n    ULONG AddressSpace,\r\n    PBOOLEAN MappedAddress\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine maps an IO address to system address space.\r\n\r\nArguments:\r\n\r\n    IoAddress - base device address to be mapped.\r\n    NumberOfBytes - number of bytes for which address is valid.\r\n    AddressSpace - Denotes whether the address is in io space or memory.\r\n    MappedAddress - indicates whether the address was mapped.\r\n                    This only has meaning if the address returned\r\n                    is non-null.\r\n\r\nReturn Value:\r\n\r\n    Mapped address\r\n\r\n--*/\r\n\r\n{\r\n   PVOID address;\r\n\r\n   PAGED_CODE();\r\n\r\n   //\r\n   // Map the device base address into the virtual address space\r\n   // if the address is in memory space.\r\n   //\r\n\r\n   if (!AddressSpace) {\r\n\r\n      address = LocalMmMapIoSpace(IoAddress,\r\n                                  NumberOfBytes);\r\n\r\n      *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));\r\n\r\n\r\n   } else {\r\n\r\n      address = ULongToPtr(IoAddress.LowPart);\r\n      *MappedAddress = FALSE;\r\n\r\n   }\r\n\r\n   return address;\r\n}\r\n\r\nVOID\r\nSerialSetInterruptPolicy(\r\n   _In_ WDFINTERRUPT WdfInterrupt\r\n   )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine shows how to set the interrupt policy preferences.\r\n\r\nArguments:\r\n\r\n    WdfInterrupt - Interrupt object handle.\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    WDF_INTERRUPT_EXTENDED_POLICY   policyAndGroup;\r\n#ifdef SERIAL_SELECT_INTERRUPT_GROUP\r\n    USHORT                          groupCount      = 1;\r\n    USHORT                          group           = 0;\r\n    UNICODE_STRING                  funcName;\r\n    PFN_KE_GET_ACTIVE_GROUP_COUNT   fnKeQueryActiveGroupCount;\r\n    PFN_KE_QUERY_GROUP_AFFINITY     fnKeQueryGroupAffinity;\r\n    KAFFINITY                       groupAffinity   = (KAFFINITY)1;\r\n#endif\r\n\r\n    WDF_INTERRUPT_EXTENDED_POLICY_INIT(&policyAndGroup);\r\n    policyAndGroup.Priority = WdfIrqPriorityNormal;\r\n\r\n#ifdef SERIAL_SELECT_INTERRUPT_GROUP\r\n    //\r\n    // If OS supports groups, find how many they are.\r\n    //\r\n    RtlInitUnicodeString(&funcName, L\"KeQueryActiveGroupCount\");\r\n    fnKeQueryActiveGroupCount = (PFN_KE_GET_ACTIVE_GROUP_COUNT)\r\n        MmGetSystemRoutineAddress(&funcName);\r\n\r\n    if (fnKeQueryActiveGroupCount != NULL) {\r\n        groupCount = fnKeQueryActiveGroupCount();\r\n\r\n        //\r\n        // Make sure there is at least one group for the boot processor.\r\n        //\r\n        if (0 == groupCount) {\r\n            groupCount = 1;\r\n        }\r\n    }\r\n\r\n    if (groupCount <= SERIAL_PREFERRED_INTERRUPT_GROUP) {\r\n        group = groupCount - 1;\r\n    }\r\n    else {\r\n        group = SERIAL_PREFERRED_INTERRUPT_GROUP;\r\n    }\r\n\r\n    //\r\n    // Get the group affinity.\r\n    //\r\n    RtlInitUnicodeString(&funcName, L\"KeQueryGroupAffinity\");\r\n    fnKeQueryGroupAffinity = (PFN_KE_QUERY_GROUP_AFFINITY)\r\n        MmGetSystemRoutineAddress(&funcName);\r\n\r\n    if (fnKeQueryGroupAffinity != NULL) {\r\n        groupAffinity = fnKeQueryGroupAffinity(group);\r\n\r\n        //\r\n        // Active groups have at least one processor.\r\n        //\r\n        if ((KAFFINITY)0 == groupAffinity) {\r\n            groupAffinity = (KAFFINITY)1;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Initialize group.\r\n    //\r\n    policyAndGroup.Policy = WdfIrqPolicySpecifiedProcessors;\r\n    policyAndGroup.TargetProcessorSetAndGroup.Group = group;\r\n    policyAndGroup.TargetProcessorSetAndGroup.Mask  = groupAffinity;\r\n#endif\r\n\r\n    //\r\n    // Set interrupt policy and group preference.\r\n    //\r\n    WdfInterruptSetExtendedPolicy(WdfInterrupt, &policyAndGroup);\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/power.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    power.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that handles the power IRPs for the serial\r\n    driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"power.tmh\"\r\n#endif\r\n\r\n\r\nPCHAR\r\nDbgDevicePowerString(\r\n    IN WDF_POWER_DEVICE_STATE Type\r\n    );\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESER,SerialEvtDeviceD0Exit)\r\n#pragma alloc_text(PAGESER,SerialSaveDeviceState)\r\n#endif // ALLOC_PRAGMA\r\n\r\nPCHAR\r\nDbgDevicePowerString(\r\n    IN WDF_POWER_DEVICE_STATE Type\r\n    )\r\n/*++\r\n\r\nUpdated Routine Description:\r\n    DbgDevicePowerString does not change in this stage of the function driver.\r\n\r\n--*/\r\n{\r\n\r\n    switch (Type)\r\n    {\r\n    case WdfPowerDeviceInvalid:\r\n        return \"WdfPowerDeviceInvalid\";\r\n    case WdfPowerDeviceD0:\r\n        return \"WdfPowerDeviceD0\";\r\n    case WdfPowerDeviceD1:\r\n        return \"WdfPowerDeviceD1\";\r\n    case WdfPowerDeviceD2:\r\n        return \"WdfPowerDeviceD2\";\r\n    case WdfPowerDeviceD3:\r\n        return \"WdfPowerDeviceD3\";\r\n    case WdfPowerDeviceD3Final:\r\n        return \"WdfPowerDeviceD3Final\";\r\n    case WdfPowerDevicePrepareForHibernation:\r\n        return \"WdfPowerDevicePrepareForHibernation\";\r\n    case WdfPowerDeviceMaximum:\r\n        return \"WdfPowerDeviceMaximum\";\r\n    default:\r\n        return \"UnKnown Device Power State\";\r\n    }\r\n}\r\n\r\nNTSTATUS\r\nSerialEvtDeviceD0Entry(\r\n    IN  WDFDEVICE Device,\r\n    IN  WDF_POWER_DEVICE_STATE PreviousState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    EvtDeviceD0Entry event callback must perform any operations that are\r\n    necessary before the specified device is used.  It will be called every\r\n    time the hardware needs to be (re-)initialized.  This includes after\r\n    IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE,\r\n    IRP_MN_SET_POWER-D0.\r\n\r\n    This function is not marked pageable because this function is in the\r\n    device power up path. When a function is marked pagable and the code\r\n    section is paged out, it will generate a page fault which could impact\r\n    the fast resume behavior because the client driver will have to wait\r\n    until the system drivers can service this page fault.\r\n\r\n    This function runs at PASSIVE_LEVEL, even though it is not paged.  A\r\n    driver can optionally make this function pageable if DO_POWER_PAGABLE\r\n    is set.  Even if DO_POWER_PAGABLE isn't set, this function still runs\r\n    at PASSIVE_LEVEL.  In this case, though, the function absolutely must\r\n    not do anything that will cause a page fault.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    PreviousState - Device power state which the device was in most recently.\r\n        If the device is being newly started, this will be\r\n        PowerDeviceUnspecified.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION deviceExtension;\r\n    PSERIAL_DEVICE_STATE pDevState;\r\n    SHORT divisor;\r\n    SERIAL_IOCTL_SYNC S;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER,\r\n                \"-->SerialEvtDeviceD0Entry - coming from %s\\n\", DbgDevicePowerString(PreviousState));\r\n\r\n    deviceExtension = SerialGetDeviceExtension (Device);\r\n    pDevState = &deviceExtension->DeviceState;\r\n\r\n    //\r\n    // Restore the state of the UART.  First, that involves disabling\r\n    // interrupts both via OUT2 and IER.\r\n    //\r\n\r\n    WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, 0);\r\n    DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);\r\n\r\n    //\r\n    // Set the baud rate\r\n    //\r\n\r\n    SerialGetDivisorFromBaud(deviceExtension->ClockRate, deviceExtension->CurrentBaud, &divisor);\r\n    S.Extension = deviceExtension;\r\n    S.Data = (PVOID) (ULONG_PTR) divisor;\r\n\r\n#pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, \"PFD warning that we are calling interrupt synchronize routine directly. Suppress it because interrupt is disabled above.\")\r\n    SerialSetBaud(deviceExtension->WdfInterrupt, &S);\r\n\r\n    //\r\n    // Reset / Re-enable the FIFO's\r\n    //\r\n\r\n    if (deviceExtension->FifoPresent) {\r\n       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0);\r\n       READ_RECEIVE_BUFFER(deviceExtension, deviceExtension->Controller);\r\n       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller,\r\n                          (UCHAR)(SERIAL_FCR_ENABLE | deviceExtension->RxFifoTrigger\r\n                                  | SERIAL_FCR_RCVR_RESET\r\n                                  | SERIAL_FCR_TXMT_RESET));\r\n    } else {\r\n       WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0);\r\n    }\r\n\r\n    //\r\n    // Restore a couple more registers\r\n    //\r\n\r\n    WRITE_INTERRUPT_ENABLE(deviceExtension, deviceExtension->Controller, pDevState->IER);\r\n    WRITE_LINE_CONTROL(deviceExtension, deviceExtension->Controller, pDevState->LCR);\r\n\r\n    //\r\n    // Clear out any stale interrupts\r\n    //\r\n\r\n    READ_INTERRUPT_ID_REG(deviceExtension, deviceExtension->Controller);\r\n    READ_LINE_STATUS(deviceExtension, deviceExtension->Controller);\r\n    READ_MODEM_STATUS(deviceExtension, deviceExtension->Controller);\r\n\r\n    //\r\n    // TODO:  move this code to EvtInterruptEnable.\r\n    //\r\n\r\n    if (deviceExtension->DeviceState.Reopen == TRUE) {\r\n       SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, \"Reopening device\\n\");\r\n\r\n       SetDeviceIsOpened(deviceExtension, TRUE, FALSE);\r\n\r\n       //\r\n       // This enables interrupts on the device!\r\n       //\r\n\r\n       WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller,\r\n                           (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2));\r\n\r\n       //\r\n       // Refire the state machine\r\n       //\r\n\r\n       DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);\r\n       ENABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller);\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, \"<--SerialEvtDeviceD0Entry\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialEvtDeviceD0Exit(\r\n    IN  WDFDEVICE Device,\r\n    IN  WDF_POWER_DEVICE_STATE TargetState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   EvtDeviceD0Exit event callback must perform any operations that are\r\n   necessary before the specified device is moved out of the D0 state.  If the\r\n   driver needs to save hardware state before the device is powered down, then\r\n   that should be done here.\r\n\r\n   This function runs at PASSIVE_LEVEL, though it is generally not paged.  A\r\n   driver can optionally make this function pageable if DO_POWER_PAGABLE is set.\r\n\r\n   Even if DO_POWER_PAGABLE isn't set, this function still runs at\r\n   PASSIVE_LEVEL.  In this case, though, the function absolutely must not do\r\n   anything that will cause a page fault.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\n    TargetState - Device power state which the device will be put in once this\r\n        callback is complete.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    PSERIAL_DEVICE_EXTENSION deviceExtension;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER,\r\n                \"-->SerialEvtDeviceD0Exit - moving to %s\\n\", DbgDevicePowerString(TargetState));\r\n\r\n    PAGED_CODE();\r\n\r\n    deviceExtension = SerialGetDeviceExtension (Device);\r\n\r\n    if (deviceExtension->DeviceIsOpened == TRUE) {\r\n        LARGE_INTEGER charTime;\r\n\r\n        SetDeviceIsOpened(deviceExtension, FALSE, TRUE);\r\n\r\n        charTime.QuadPart = -SerialGetCharTime(deviceExtension).QuadPart;\r\n\r\n        //\r\n        // Shut down the chip\r\n        //\r\n\r\n        SerialDisableUART(deviceExtension);\r\n\r\n        //\r\n        // Drain the device\r\n        //\r\n\r\n        SerialDrainUART(deviceExtension, &charTime);\r\n\r\n        //\r\n        // Save the device state\r\n        //\r\n\r\n        SerialSaveDeviceState(deviceExtension);\r\n    }\r\n    else\r\n    {\r\n        SetDeviceIsOpened(deviceExtension, FALSE, FALSE);\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, \"<--SerialEvtDeviceD0Exit\\n\");\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nVOID\r\nSerialSaveDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine saves the device state of the UART\r\n\r\nArguments:\r\n\r\n    PDevExt - Pointer to the device extension for the devobj to save the state\r\n              for.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n\r\n--*/\r\n{\r\n   PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState;\r\n\r\n   PAGED_CODE();\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, \"Entering SerialSaveDeviceState\\n\");\r\n\r\n   //\r\n   // Read necessary registers direct\r\n   //\r\n\r\n   pDevState->IER = READ_INTERRUPT_ENABLE(PDevExt, PDevExt->Controller);\r\n   pDevState->MCR = READ_MODEM_CONTROL(PDevExt, PDevExt->Controller);\r\n   pDevState->LCR = READ_LINE_CONTROL(PDevExt, PDevExt->Controller);\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, \"Leaving SerialSaveDeviceState\\n\");\r\n}\r\n\r\n\r\nVOID\r\nSetDeviceIsOpened(IN PSERIAL_DEVICE_EXTENSION PDevExt, IN BOOLEAN DeviceIsOpened, IN BOOLEAN Reopen)\r\n{\r\n\r\n    PDevExt->DeviceIsOpened     = DeviceIsOpened;\r\n    PDevExt->DeviceState.Reopen = Reopen;\r\n\r\n}\r\n\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/precomp.h",
    "content": "\r\n#include <stddef.h>\r\n#include <stdarg.h>\r\n#define WIN9X_COMPAT_SPINLOCK\r\n#include \"ntddk.h\"\r\n#include <wdf.h>\r\n#define NTSTRSAFE_LIB\r\n#include <ntstrsafe.h>\r\n#include \"ntddser.h\"\r\n#include <wmilib.h>\r\n#include <initguid.h> // required for GUID definitions\r\n#include <wmidata.h>\r\n#include \"serial.h\"\r\n#include \"serialp.h\"\r\n#include \"serlog.h\"\r\n#include \"log.h\"\r\n#include \"trace.h\"\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/precompsrc.c",
    "content": "#include \"precomp.h\""
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/purge.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    purge.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to purge\r\n    operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"purge.tmh\"\r\n#endif\r\n\r\n\r\nVOID\r\nSerialStartPurge(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Depending on the mask in the current request, purge the interrupt\r\n    buffer, the read queue, or the write queue, or all of the above.\r\n\r\nArguments:\r\n\r\n    Extension - Pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Will return STATUS_SUCCESS always.  This is reasonable\r\n    since the DPC completion code that calls this routine doesn't\r\n    care and the purge request always goes through to completion\r\n    once it's started.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    WDFREQUEST NewRequest;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    do {\r\n\r\n        ULONG Mask;\r\n        reqContext = SerialGetRequestContext(Extension->CurrentPurgeRequest);\r\n        Mask = *((ULONG *) (reqContext->SystemBuffer));\r\n\r\n        if (Mask & SERIAL_PURGE_TXABORT) {\r\n\r\n            SerialFlushRequests(\r\n                Extension->WriteQueue,\r\n                &Extension->CurrentWriteRequest\r\n                );\r\n\r\n            SerialFlushRequests(\r\n                Extension->WriteQueue,\r\n                &Extension->CurrentXoffRequest\r\n                );\r\n\r\n        }\r\n\r\n        if (Mask & SERIAL_PURGE_RXABORT) {\r\n\r\n            SerialFlushRequests(\r\n                Extension->ReadQueue,\r\n                &Extension->CurrentReadRequest\r\n                );\r\n\r\n        }\r\n\r\n        if (Mask & SERIAL_PURGE_RXCLEAR) {\r\n\r\n            //\r\n            // Clean out the interrupt buffer.\r\n            //\r\n            // Note that we do this under protection of the\r\n            // the drivers control lock so that we don't hose\r\n            // the pointers if there is currently a read that\r\n            // is reading out of the buffer.\r\n            //\r\n\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialPurgeInterruptBuff,\r\n                Extension\r\n                );\r\n\r\n        }\r\n\r\n        reqContext->Status = STATUS_SUCCESS;\r\n        reqContext->Information = 0;\r\n\r\n        SerialGetNextRequest(\r\n            &Extension->CurrentPurgeRequest,\r\n            Extension->PurgeQueue,\r\n            &NewRequest,\r\n            TRUE,\r\n            Extension\r\n            );\r\n\r\n    } while (NewRequest);\r\n\r\n    return;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialPurgeInterruptBuff(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine simply resets the interrupt (typeahead) buffer.\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    //\r\n    // The typeahead buffer is by definition empty if there\r\n    // currently is a read owned by the isr.\r\n    //\r\n\r\n\r\n    if (Extension->ReadBufferBase == Extension->InterruptReadBuffer) {\r\n\r\n        Extension->CurrentCharSlot = Extension->InterruptReadBuffer;\r\n        Extension->FirstReadableChar = Extension->InterruptReadBuffer;\r\n        Extension->LastCharSlot = Extension->InterruptReadBuffer +\r\n                                      (Extension->BufferSize - 1);\r\n        Extension->CharsInInterruptBuffer = 0;\r\n\r\n        SerialHandleReducedIntBuffer(Extension);\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/qsfile.c",
    "content": "/*++\r\n\r\nCopyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    qsfile.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to query/set file\r\n    operations in the serial driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"qsfile.tmh\"\r\n#endif\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESRP0,SerialQueryInformationFile)\r\n#pragma alloc_text(PAGESRP0,SerialSetInformationFile)\r\n#endif\r\n\r\n\r\nNTSTATUS\r\nSerialQueryInformationFile(\r\n    IN WDFDEVICE Device,\r\n    IN PIRP Irp\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to query the end of file information on\r\n    the opened serial port.  Any other file information request\r\n    is retured with an invalid parameter.\r\n\r\n    This routine always returns an end of file of 0.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Pointer to the device object for this device\r\n\r\n    Irp - Pointer to the IRP for the current request\r\n\r\nReturn Value:\r\n\r\n    The function value is the final status of the call\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS Status;\r\n    PIO_STACK_LOCATION IrpSp;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \">SerialQueryInformationFile(%p, %p)\\n\", Device, Irp);\r\n\r\n    PAGED_CODE();\r\n\r\n\r\n    IrpSp = IoGetCurrentIrpStackLocation(Irp);\r\n    Irp->IoStatus.Information = 0L;\r\n    Status = STATUS_SUCCESS;\r\n\r\n    if (IrpSp->Parameters.QueryFile.FileInformationClass ==\r\n        FileStandardInformation) {\r\n\r\n        if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <\r\n                sizeof(FILE_STANDARD_INFORMATION))\r\n        {\r\n                Status = STATUS_BUFFER_TOO_SMALL;\r\n        }\r\n        else\r\n        {\r\n            PFILE_STANDARD_INFORMATION Buf = Irp->AssociatedIrp.SystemBuffer;\r\n\r\n            Buf->AllocationSize.QuadPart = 0;\r\n            Buf->EndOfFile = Buf->AllocationSize;\r\n            Buf->NumberOfLinks = 0;\r\n            Buf->DeletePending = FALSE;\r\n            Buf->Directory = FALSE;\r\n            Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);\r\n        }\r\n\r\n    } else if (IrpSp->Parameters.QueryFile.FileInformationClass ==\r\n               FilePositionInformation) {\r\n\r\n        if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <\r\n                sizeof(FILE_POSITION_INFORMATION))\r\n        {\r\n                Status = STATUS_BUFFER_TOO_SMALL;\r\n        }\r\n        else\r\n        {\r\n\r\n            ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->\r\n                CurrentByteOffset.QuadPart = 0;\r\n            Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);\r\n        }\r\n\r\n    } else {\r\n        Status = STATUS_INVALID_PARAMETER;\r\n    }\r\n\r\n    Irp->IoStatus.Status = Status;\r\n\r\n    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r\n\r\n    return Status;\r\n\r\n}\r\n\r\nNTSTATUS\r\nSerialSetInformationFile(\r\n    IN WDFDEVICE Device,\r\n    IN PIRP Irp\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the end of file information on\r\n    the opened parallel port.  Any other file information request\r\n    is retured with an invalid parameter.\r\n\r\n    This routine always ignores the actual end of file since\r\n    the query information code always returns an end of file of 0.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Pointer to the device object for this device\r\n\r\n    Irp - Pointer to the IRP for the current request\r\n\r\nReturn Value:\r\n\r\nThe function value is the final status of the call\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS Status;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_PNP, \">SerialSetInformationFile(%p, %p)\\n\", Device, Irp);\r\n\r\n    Irp->IoStatus.Information = 0L;\r\n    if ((IoGetCurrentIrpStackLocation(Irp)->\r\n            Parameters.SetFile.FileInformationClass ==\r\n         FileEndOfFileInformation) ||\r\n        (IoGetCurrentIrpStackLocation(Irp)->\r\n            Parameters.SetFile.FileInformationClass ==\r\n         FileAllocationInformation)) {\r\n\r\n        Status = STATUS_SUCCESS;\r\n\r\n    } else {\r\n\r\n        Status = STATUS_INVALID_PARAMETER;\r\n\r\n    }\r\n\r\n    Irp->IoStatus.Status = Status;\r\n\r\n    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r\n\r\n    return Status;\r\n\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/read.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    read.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to read\r\n    operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"read.tmh\"\r\n#endif\r\n\r\nEVT_WDF_REQUEST_CANCEL SerialCancelCurrentRead;\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabReadFromIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateReadByIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateInterruptBuffer;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateAndSwitchToUser;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialUpdateAndSwitchToNew;\r\n\r\nULONG\r\nSerialGetCharsFromIntBuffer(\r\n    PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\n\r\nNTSTATUS\r\nSerialResizeBuffer(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nULONG\r\nSerialMoveToNewIntBuffer(\r\n    PSERIAL_DEVICE_EXTENSION Extension,\r\n    PUCHAR NewBuffer\r\n    );\r\n\r\nVOID\r\nSerialEvtIoRead(\r\n    IN WDFQUEUE         Queue,\r\n    IN WDFREQUEST       Request,\r\n    IN size_t            Length\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the dispatch routine for reading.  It validates the parameters\r\n    for the read request and if all is ok then it places the request\r\n    on the work queue.\r\n\r\nArguments:\r\n\r\n    Queue - Queue handle\r\n    Request - Handle to the read request\r\n    Lenght - Length of the data buffer associated with the request.\r\n                 The default property of the queue is to not dispatch\r\n                 zero lenght read & write requests to the driver and\r\n                 complete is with status success. So we will never get\r\n                 a zero length request.\r\n\r\nReturn Value:\r\n\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension;\r\n    NTSTATUS status;\r\n    WDFDEVICE hDevice;\r\n    WDF_REQUEST_PARAMETERS params;\r\n    PREQUEST_CONTEXT reqContext;\r\n    size_t bufLen;\r\n\r\n    hDevice = WdfIoQueueGetDevice(Queue);\r\n    extension = SerialGetDeviceExtension(hDevice);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ,\r\n                    \">SerialEvtIoRead(%p, 0x%I64x)\\n\", Request, Length);\r\n\r\n    if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) {\r\n\r\n       SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \"<SerialEvtIoRead (2) %d\\n\", STATUS_CANCELLED);\r\n       return;\r\n\r\n    }\r\n\r\n    WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n    WdfRequestGetParameters(\r\n             Request,\r\n             &params\r\n             );\r\n\r\n    //\r\n    // Initialize the scratch area of the request.\r\n    //\r\n    reqContext = SerialGetRequestContext(Request);\r\n    reqContext->MajorFunction = params.Type;\r\n    reqContext->Length  = (ULONG) Length;\r\n\r\n    status = WdfRequestRetrieveOutputBuffer (Request, Length, &reqContext->SystemBuffer, &bufLen);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        SerialCompleteRequest(Request , status, 0);\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_READ, \"<SerialEvtIoRead (5) %X\\n\", status);\r\n        return;\r\n    }\r\n\r\n    ASSERT(bufLen == reqContext->Length);\r\n\r\n    //\r\n    // Well it looks like we actually have to do some\r\n    // work.  Put the read on the queue so that we can\r\n    // process it when our previous reads are done.\r\n    //\r\n    SerialStartOrQueue(extension, Request, extension->ReadQueue,\r\n                                   &extension->CurrentReadRequest, SerialStartRead);\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \"<SerialEvtIoRead (3) %X\\n\", status);\r\n\r\n    return;\r\n\r\n}\r\n\r\nVOID\r\nSerialStartRead(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to start off any read.  It initializes\r\n    the Iostatus fields of the request.  It will set up any timers\r\n    that are used to control the read.  It will attempt to complete\r\n    the read from data already in the interrupt buffer.  If the\r\n    read can be completed quickly it will start off another if\r\n    necessary.\r\n\r\nArguments:\r\n\r\n    Extension - Simply a pointer to the serial device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine will return the status of the first read\r\n    request.  This is useful in that if we have a read that can\r\n    complete right away (AND there had been nothing in the\r\n    queue before it) the read could return SUCCESS and the\r\n    application won't have to do a wait.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    SERIAL_UPDATE_CHAR updateChar;\r\n\r\n    WDFREQUEST newRequest;\r\n\r\n    BOOLEAN returnWithWhatsPresent;\r\n    BOOLEAN os2ssreturn;\r\n    BOOLEAN crunchDownToOne;\r\n    BOOLEAN useTotalTimer;\r\n    BOOLEAN useIntervalTimer;\r\n\r\n    ULONG multiplierVal = 0;\r\n    ULONG constantVal   = 0;\r\n\r\n    LARGE_INTEGER totalTime = {0};\r\n\r\n    SERIAL_TIMEOUTS timeoutsForIrp;\r\n\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ,\r\n                     \">SerialStartRead(%p)\\n\", Extension);\r\n\r\n    updateChar.Extension = Extension;\r\n\r\n\r\n    do {\r\n\r\n        reqContext = SerialGetRequestContext(Extension->CurrentReadRequest);\r\n\r\n        //\r\n        // Check to see if this is a resize request.  If it is\r\n        // then go to a routine that specializes in that.\r\n        //\r\n\r\n        if (reqContext->MajorFunction != IRP_MJ_READ) {\r\n\r\n            NTSTATUS localStatus = SerialResizeBuffer(Extension);\r\n            UNREFERENCED_PARAMETER(localStatus);\r\n            ASSERT(NT_SUCCESS(localStatus));\r\n\r\n        } else {\r\n\r\n            Extension->NumberNeededForRead = reqContext->Length;\r\n\r\n            //\r\n            // Calculate the timeout value needed for the\r\n            // request.  Note that the values stored in the\r\n            // timeout record are in milliseconds.\r\n            //\r\n\r\n            useTotalTimer = FALSE;\r\n            returnWithWhatsPresent = FALSE;\r\n            os2ssreturn = FALSE;\r\n            crunchDownToOne = FALSE;\r\n            useIntervalTimer = FALSE;\r\n\r\n            //\r\n            //\r\n            // CIMEXCIMEX -- this is a lie\r\n            //\r\n            // Always initialize the timer objects so that the\r\n            // completion code can tell when it attempts to\r\n            // cancel the timers whether the timers had ever\r\n            // been Set.\r\n            //\r\n            // CIMEXCIMEX -- this is the truth\r\n            //\r\n            // What we want to do is just make sure the timers are\r\n            // cancelled to the best of our ability and move on with\r\n            // life.\r\n            //\r\n\r\n            SerialCancelTimer(Extension->ReadRequestTotalTimer, Extension);\r\n            SerialCancelTimer(Extension->ReadRequestIntervalTimer, Extension);\r\n\r\n            //\r\n            // We get the *current* timeout values to use for timing\r\n            // this read.\r\n            //\r\n\r\n\r\n            timeoutsForIrp = Extension->Timeouts;\r\n\r\n            //\r\n            // Calculate the interval timeout for the read.\r\n            //\r\n\r\n            if (timeoutsForIrp.ReadIntervalTimeout &&\r\n                (timeoutsForIrp.ReadIntervalTimeout !=\r\n                 MAXULONG)) {\r\n\r\n                useIntervalTimer = TRUE;\r\n\r\n                Extension->IntervalTime.QuadPart =\r\n                    UInt32x32To64(\r\n                        timeoutsForIrp.ReadIntervalTimeout,\r\n                        10000\r\n                        );\r\n\r\n\r\n                if (Extension->IntervalTime.QuadPart >=\r\n                    Extension->CutOverAmount.QuadPart) {\r\n\r\n                    Extension->IntervalTimeToUse =\r\n                        &Extension->LongIntervalAmount;\r\n\r\n                } else {\r\n\r\n                    Extension->IntervalTimeToUse =\r\n                        &Extension->ShortIntervalAmount;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {\r\n\r\n                //\r\n                // We need to do special return quickly stuff here.\r\n                //\r\n                // 1) If both constant and multiplier are\r\n                //    0 then we return immediately with whatever\r\n                //    we've got, even if it was zero.\r\n                //\r\n                // 2) If constant and multiplier are not MAXULONG\r\n                //    then return immediately if any characters\r\n                //    are present, but if nothing is there, then\r\n                //    use the timeouts as specified.\r\n                //\r\n                // 3) If multiplier is MAXULONG then do as in\r\n                //    \"2\" but return when the first character\r\n                //    arrives.\r\n                //\r\n\r\n                if (!timeoutsForIrp.ReadTotalTimeoutConstant &&\r\n                    !timeoutsForIrp.ReadTotalTimeoutMultiplier) {\r\n\r\n                    returnWithWhatsPresent = TRUE;\r\n\r\n                } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)\r\n                            &&\r\n                           (timeoutsForIrp.ReadTotalTimeoutMultiplier\r\n                            != MAXULONG)) {\r\n\r\n                    useTotalTimer = TRUE;\r\n                    os2ssreturn = TRUE;\r\n                    multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;\r\n                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;\r\n\r\n                } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)\r\n                            &&\r\n                           (timeoutsForIrp.ReadTotalTimeoutMultiplier\r\n                            == MAXULONG)) {\r\n\r\n                    useTotalTimer = TRUE;\r\n                    os2ssreturn = TRUE;\r\n                    crunchDownToOne = TRUE;\r\n                    multiplierVal = 0;\r\n                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;\r\n\r\n                }\r\n\r\n            } else {\r\n\r\n                //\r\n                // If both the multiplier and the constant are\r\n                // zero then don't do any total timeout processing.\r\n                //\r\n\r\n                if (timeoutsForIrp.ReadTotalTimeoutMultiplier ||\r\n                    timeoutsForIrp.ReadTotalTimeoutConstant) {\r\n\r\n                    //\r\n                    // We have some timer values to calculate.\r\n                    //\r\n\r\n                    useTotalTimer = TRUE;\r\n                    multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;\r\n                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;\r\n\r\n                }\r\n\r\n            }\r\n\r\n            if (useTotalTimer) {\r\n\r\n                totalTime.QuadPart = ((LONGLONG)(UInt32x32To64(\r\n                                          Extension->NumberNeededForRead,\r\n                                          multiplierVal\r\n                                          )\r\n                                          + constantVal))\r\n                                      * -10000;\r\n\r\n            }\r\n\r\n\r\n            //\r\n            // We do this copy in the hope of getting most (if not\r\n            // all) of the characters out of the interrupt buffer.\r\n            //\r\n            // Note that we need to protect this operation with a\r\n            // spinlock since we don't want a purge to hose us.\r\n            //\r\n\r\n            updateChar.CharsCopied = SerialGetCharsFromIntBuffer(Extension);\r\n\r\n            //\r\n            // See if we have any cause to return immediately.\r\n            //\r\n\r\n            if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) ||\r\n                (os2ssreturn &&\r\n                 reqContext->Information)) {\r\n\r\n                //\r\n                // We got all we needed for this read.\r\n                // Update the number of characters in the\r\n                // interrupt read buffer.\r\n                //\r\n\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    SerialUpdateInterruptBuffer,\r\n                    &updateChar\r\n                    );\r\n\r\n                reqContext->Status =  STATUS_SUCCESS;\r\n\r\n            } else {\r\n\r\n                //\r\n                // The request might go under control of the isr.  It\r\n                // won't hurt to initialize the reference count\r\n                // right now.\r\n                //\r\n\r\n                SERIAL_INIT_REFERENCE(reqContext);\r\n\r\n                //\r\n                // If we are supposed to crunch the read down to\r\n                // one character, then update the read length\r\n                // in the request and truncate the number needed for\r\n                // read down to one. Note that if we are doing\r\n                // this crunching, then the information must be\r\n                // zero (or we would have completed above) and\r\n                // the number needed for the read must still be\r\n                // equal to the read length.\r\n                //\r\n\r\n                if (crunchDownToOne) {\r\n\r\n                    ASSERT(\r\n                        (!reqContext->Information)\r\n                        &&\r\n                        (Extension->NumberNeededForRead == reqContext->Length)\r\n                        );\r\n\r\n                    Extension->NumberNeededForRead = 1;\r\n                    reqContext->Length = 1;\r\n\r\n                }\r\n\r\n                //\r\n                // We still need to get more characters for this read.\r\n                // synchronize with the isr so that we can update the\r\n                // number of characters and if necessary it will have the\r\n                // isr switch to copying into the users buffer.\r\n                //\r\n\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    SerialUpdateAndSwitchToUser,\r\n                    &updateChar\r\n                    );\r\n\r\n                if (!updateChar.Completed) {\r\n\r\n                     SerialSetCancelRoutine(Extension->CurrentReadRequest,\r\n                                                     SerialCancelCurrentRead);\r\n\r\n                    //\r\n                    // The request still isn't complete.  The\r\n                    // completion routines will end up reinvoking\r\n                    // this routine.  So we simply leave.\r\n                    //\r\n                    // First thought we should start off the total\r\n                    // timer for the read and increment the reference\r\n                    // count that the total timer has on the current\r\n                    // request.  Note that this is safe, because even if\r\n                    // the io has been satisfied by the isr it can't\r\n                    // complete yet because we still own the cancel\r\n                    // spinlock.\r\n                    //\r\n\r\n                    if (useTotalTimer) {\r\n                        BOOLEAN result;\r\n\r\n                        result = SerialSetTimer(\r\n                            Extension->ReadRequestTotalTimer,\r\n                            totalTime\r\n                            );\r\n\r\n                        if(result == FALSE) {\r\n                            SERIAL_SET_REFERENCE(\r\n                                reqContext,\r\n                                SERIAL_REF_TOTAL_TIMER\r\n                                );\r\n                        }\r\n\r\n                    }\r\n\r\n                    if (useIntervalTimer) {\r\n\r\n                        BOOLEAN result;\r\n\r\n                        KeQuerySystemTime(\r\n                            &Extension->LastReadTime\r\n\r\n                            );\r\n                        result = SerialSetTimer(\r\n                            Extension->ReadRequestIntervalTimer,\r\n                            *Extension->IntervalTimeToUse\r\n                            );\r\n\r\n                        if(result == FALSE) {\r\n                            SERIAL_SET_REFERENCE(\r\n                                reqContext,\r\n                                SERIAL_REF_INT_TIMER\r\n                                );\r\n                        }\r\n\r\n                    }\r\n\r\n                    break;\r\n\r\n                } else {\r\n\r\n                    reqContext->Status = STATUS_SUCCESS;\r\n                }\r\n\r\n            }\r\n\r\n        }\r\n\r\n        //\r\n        // Well the operation is complete.\r\n        //\r\n\r\n        SerialGetNextRequest(&Extension->CurrentReadRequest,\r\n                             Extension->ReadQueue,\r\n                             &newRequest, TRUE, Extension);\r\n\r\n    } while (newRequest);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ,  \"<SerialStartRead \\n\");\r\n\r\n    return;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialCompleteRead(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is merely used to complete any read that\r\n    ended up being used by the Isr.  It assumes that the\r\n    status and the information fields of the request are already\r\n    correctly filled in.\r\n\r\nArguments:\r\n\r\n    Dpc - Not Used.\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = NULL;\r\n\r\n    extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \">SerialCompleteRead(%p)\\n\",\r\n                     extension);\r\n\r\n    //\r\n    // We set this to indicate to the interval timer\r\n    // that the read has completed.\r\n    //\r\n    // Recall that the interval timer dpc can be lurking in some\r\n    // DPC queue.\r\n    //\r\n\r\n    extension->CountOnLastRead = SERIAL_COMPLETE_READ_COMPLETE;\r\n\r\n    SerialTryToCompleteCurrent(\r\n        extension,\r\n        NULL,\r\n        STATUS_SUCCESS,\r\n        &extension->CurrentReadRequest,\r\n        extension->ReadQueue,\r\n        extension->ReadRequestIntervalTimer,\r\n        extension->ReadRequestTotalTimer,\r\n        SerialStartRead,\r\n        SerialGetNextRequest,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \"<SerialCompleteRead\\n\");\r\n}\r\n\r\n\r\nVOID\r\nSerialCancelCurrentRead(\r\n    WDFREQUEST  Request\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to cancel the current read.\r\n\r\nArguments:\r\n\r\n    Device - Wdf device handle\r\n\r\n    Request - Pointer to the WDFREQUEST to be canceled.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = NULL;\r\n    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));\r\n\r\n    UNREFERENCED_PARAMETER(Request);\r\n\r\n    extension = SerialGetDeviceExtension(device);\r\n\r\n    //\r\n    // We set this to indicate to the interval timer\r\n    // that the read has encountered a cancel.\r\n    //\r\n    // Recall that the interval timer dpc can be lurking in some\r\n    // DPC queue.\r\n    //\r\n\r\n    extension->CountOnLastRead = SERIAL_COMPLETE_READ_CANCEL;\r\n\r\n    SerialTryToCompleteCurrent(\r\n        extension,\r\n        SerialGrabReadFromIsr,\r\n        STATUS_CANCELLED,\r\n        &extension->CurrentReadRequest,\r\n        extension->ReadQueue,\r\n        extension->ReadRequestIntervalTimer,\r\n        extension->ReadRequestTotalTimer,\r\n        SerialStartRead,\r\n        SerialGetNextRequest,\r\n        SERIAL_REF_CANCEL\r\n        );\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGrabReadFromIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to grab (if possible) the request from the\r\n    isr.  If it finds that the isr still owns the request it grabs\r\n    the ipr away (updating the number of characters copied into the\r\n    users buffer).  If it grabs it away it also decrements the\r\n    reference count on the request since it no longer belongs to the\r\n    isr (and the dpc that would complete it).\r\n\r\n    NOTE: This routine assumes that if the current buffer that the\r\n          ISR is copying characters into is the interrupt buffer then\r\n          the dpc has already been queued.\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the cancel spin\r\n          lock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = Context;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(extension->CurrentReadRequest);\r\n\r\n    if (extension->ReadBufferBase !=\r\n        extension->InterruptReadBuffer) {\r\n\r\n        //\r\n        // We need to set the information to the number of characters\r\n        // that the read wanted minus the number of characters that\r\n        // didn't get read into the interrupt buffer.\r\n        //\r\n\r\n        reqContext->Information = reqContext->Length -\r\n            ((extension->LastCharSlot - extension->CurrentCharSlot) + 1);\r\n\r\n        //\r\n        // Switch back to the interrupt buffer.\r\n        //\r\n\r\n        extension->ReadBufferBase = extension->InterruptReadBuffer;\r\n        extension->CurrentCharSlot = extension->InterruptReadBuffer;\r\n        extension->FirstReadableChar = extension->InterruptReadBuffer;\r\n        extension->LastCharSlot = extension->InterruptReadBuffer +\r\n                                      (extension->BufferSize - 1);\r\n        extension->CharsInInterruptBuffer = 0;\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\nVOID\r\nSerialReadTimeout(\r\n    IN WDFTIMER Timer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to complete a read because its total\r\n    timer has expired.\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = NULL;\r\n\r\n    extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \">SerialReadTimeout(%p)\\n\",\r\n                     extension);\r\n\r\n    //\r\n    // We set this to indicate to the interval timer\r\n    // that the read has completed due to total timeout.\r\n    //\r\n    // Recall that the interval timer dpc can be lurking in some\r\n    // DPC queue.\r\n    //\r\n\r\n    extension->CountOnLastRead = SERIAL_COMPLETE_READ_TOTAL;\r\n\r\n    SerialTryToCompleteCurrent(\r\n        extension,\r\n        SerialGrabReadFromIsr,\r\n        STATUS_TIMEOUT,\r\n        &extension->CurrentReadRequest,\r\n        extension->ReadQueue,\r\n        extension->ReadRequestIntervalTimer,\r\n        extension->ReadRequestTotalTimer,\r\n        SerialStartRead,\r\n        SerialGetNextRequest,\r\n        SERIAL_REF_TOTAL_TIMER\r\n        );\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \"<SerialReadTimeout\\n\");\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialUpdateReadByIsr(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to update the count of characters read\r\n    by the isr since the last interval timer experation.\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the cancel spin\r\n          lock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    extension->CountOnLastRead = extension->ReadByIsr;\r\n    extension->ReadByIsr = 0;\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialIntervalReadTimeout(\r\n    IN WDFTIMER Timer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used timeout the request if the time between\r\n    characters exceed the interval time.  A global is kept in\r\n    the device extension that records the count of characters read\r\n    the last the last time this routine was invoked (This dpc\r\n    will resubmit the timer if the count has changed).  If the\r\n    count has not changed then this routine will attempt to complete\r\n    the request.  Note the special case of the last count being zero.\r\n    The timer isn't really in effect until the first character is\r\n    read.\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION extension = NULL;\r\n\r\n    extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n\r\n    //SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \">SerialIntervalReadTimeout(%p)\\n\",\r\n    //                 extension);\r\n\r\n    if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) {\r\n\r\n        //\r\n        // This value is only set by the total\r\n        // timer to indicate that it has fired.\r\n        // If so, then we should simply try to complete.\r\n        //\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, \"in SERIAL_COMPLETE_READ_TOTAL\\n\");\r\n\r\n        SerialTryToCompleteCurrent(\r\n            extension,\r\n            SerialGrabReadFromIsr,\r\n            STATUS_TIMEOUT,\r\n            &extension->CurrentReadRequest,\r\n            extension->ReadQueue,\r\n            extension->ReadRequestIntervalTimer,\r\n            extension->ReadRequestTotalTimer,\r\n            SerialStartRead,\r\n            SerialGetNextRequest,\r\n            SERIAL_REF_INT_TIMER\r\n            );\r\n\r\n    } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) {\r\n\r\n        //\r\n        // This value is only set by the regular\r\n        // completion routine.\r\n        //\r\n        // If so, then we should simply try to complete.\r\n        //\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, \"in SERIAL_COMPLETE_READ_COMPLETE\\n\");\r\n\r\n        SerialTryToCompleteCurrent(\r\n            extension,\r\n            SerialGrabReadFromIsr,\r\n            STATUS_SUCCESS,\r\n            &extension->CurrentReadRequest,\r\n            extension->ReadQueue,\r\n            extension->ReadRequestIntervalTimer,\r\n            extension->ReadRequestTotalTimer,\r\n            SerialStartRead,\r\n            SerialGetNextRequest,\r\n            SERIAL_REF_INT_TIMER\r\n            );\r\n\r\n    } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) {\r\n\r\n        //\r\n        // This value is only set by the cancel\r\n        // read routine.\r\n        //\r\n        // If so, then we should simply try to complete.\r\n        //\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_INIT, \"in SERIAL_COMPLETE_READ_CANCEL\\n\");\r\n\r\n        SerialTryToCompleteCurrent(\r\n            extension,\r\n            SerialGrabReadFromIsr,\r\n            STATUS_CANCELLED,\r\n            &extension->CurrentReadRequest,\r\n            extension->ReadQueue,\r\n            extension->ReadRequestIntervalTimer,\r\n            extension->ReadRequestTotalTimer,\r\n            SerialStartRead,\r\n            SerialGetNextRequest,\r\n            SERIAL_REF_INT_TIMER\r\n            );\r\n\r\n    } else if (extension->CountOnLastRead || extension->ReadByIsr) {\r\n\r\n        //\r\n        // Something has happened since we last came here.  We\r\n        // check to see if the ISR has read in any more characters.\r\n        // If it did then we should update the isr's read count\r\n        // and resubmit the timer.\r\n        //\r\n\r\n        if (extension->ReadByIsr) {\r\n\r\n            WdfInterruptSynchronize(\r\n                extension->WdfInterrupt,\r\n                SerialUpdateReadByIsr,\r\n                extension\r\n                );\r\n\r\n            //\r\n            // Save off the \"last\" time something was read.\r\n            // As we come back to this routine we will compare\r\n            // the current time to the \"last\" time.  If the\r\n            // difference is ever larger then the interval\r\n            // requested by the user, then time out the request.\r\n            //\r\n\r\n            KeQuerySystemTime(\r\n                &extension->LastReadTime\r\n                );\r\n\r\n            SerialSetTimer(\r\n                extension->ReadRequestIntervalTimer,\r\n                *extension->IntervalTimeToUse\r\n                );\r\n\r\n        } else {\r\n\r\n            //\r\n            // Take the difference between the current time\r\n            // and the last time we had characters and\r\n            // see if it is greater then the interval time.\r\n            // if it is, then time out the request.  Otherwise\r\n            // go away again for a while.\r\n            //\r\n\r\n            //\r\n            // No characters read in the interval time.  Kill\r\n            // this read.\r\n            //\r\n\r\n            LARGE_INTEGER currentTime;\r\n\r\n            KeQuerySystemTime(\r\n                &currentTime\r\n                );\r\n\r\n            if ((currentTime.QuadPart - extension->LastReadTime.QuadPart) >=\r\n                extension->IntervalTime.QuadPart) {\r\n\r\n                SerialTryToCompleteCurrent(\r\n                    extension,\r\n                    SerialGrabReadFromIsr,\r\n                    STATUS_TIMEOUT,\r\n                    &extension->CurrentReadRequest,\r\n                    extension->ReadQueue,\r\n                    extension->ReadRequestIntervalTimer,\r\n                    extension->ReadRequestTotalTimer,\r\n                    SerialStartRead,\r\n                    SerialGetNextRequest,\r\n                    SERIAL_REF_INT_TIMER\r\n                    );\r\n\r\n            } else {\r\n\r\n                SerialSetTimer(\r\n                    extension->ReadRequestIntervalTimer,\r\n                    *extension->IntervalTimeToUse\r\n                    );\r\n\r\n            }\r\n\r\n\r\n        }\r\n\r\n    } else {\r\n\r\n        //\r\n        // Timer doesn't really start until the first character.\r\n        // So we should simply resubmit ourselves.\r\n        //\r\n\r\n        SerialSetTimer(\r\n            extension->ReadRequestIntervalTimer,\r\n            *extension->IntervalTimeToUse\r\n            );\r\n\r\n    }\r\n\r\n\r\n    //SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_READ, \"<SerialIntervalReadTimeout\\n\");\r\n}\r\n\r\n\r\nULONG\r\nSerialGetCharsFromIntBuffer(\r\n    PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to copy any characters out of the interrupt\r\n    buffer into the users buffer.  It will be reading values that\r\n    are updated with the ISR but this is safe since this value is\r\n    only decremented by synchronization routines.  This routine will\r\n    return the number of characters copied so some other routine\r\n    can call a synchronization routine to update what is seen at\r\n    interrupt level.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    The number of characters that were copied into the user\r\n    buffer.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    //\r\n    // This value will be the number of characters that this\r\n    // routine returns.  It will be the minimum of the number\r\n    // of characters currently in the buffer or the number of\r\n    // characters required for the read.\r\n    //\r\n    ULONG numberOfCharsToGet;\r\n\r\n    //\r\n    // This holds the number of characters between the first\r\n    // readable character and - the last character we will read or\r\n    // the real physical end of the buffer (not the last readable\r\n    // character).\r\n    //\r\n    ULONG firstTryNumberToGet;\r\n\r\n    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Extension->CurrentReadRequest);\r\n\r\n    //\r\n    // The minimum of the number of characters we need and\r\n    // the number of characters available\r\n    //\r\n\r\n    numberOfCharsToGet = Extension->CharsInInterruptBuffer;\r\n\r\n    if (numberOfCharsToGet > Extension->NumberNeededForRead) {\r\n\r\n        numberOfCharsToGet = Extension->NumberNeededForRead;\r\n\r\n    }\r\n\r\n    if (numberOfCharsToGet) {\r\n\r\n        //\r\n        // This will hold the number of characters between the\r\n        // first available character and the end of the buffer.\r\n        // Note that the buffer could wrap around but for the\r\n        // purposes of the first copy we don't care about that.\r\n        //\r\n\r\n        firstTryNumberToGet = (ULONG)(Extension->LastCharSlot -\r\n                               Extension->FirstReadableChar) + 1;\r\n\r\n        if (firstTryNumberToGet > numberOfCharsToGet) {\r\n\r\n            //\r\n            // The characters don't wrap. Actually they may wrap but\r\n            // we don't care for the purposes of this read since the\r\n            // characters we need are available before the wrap.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                ((PUCHAR)(reqContext->SystemBuffer))\r\n                    + (reqContext->Length - Extension->NumberNeededForRead),\r\n                Extension->FirstReadableChar,\r\n                numberOfCharsToGet\r\n                );\r\n\r\n            Extension->NumberNeededForRead -= numberOfCharsToGet;\r\n\r\n            //\r\n            // We now will move the pointer to the first character after\r\n            // what we just copied into the users buffer.\r\n            //\r\n            // We need to check if the stream of readable characters\r\n            // is wrapping around to the beginning of the buffer.\r\n            //\r\n            // Note that we may have just taken the last characters\r\n            // at the end of the buffer.\r\n            //\r\n\r\n            if ((Extension->FirstReadableChar + (numberOfCharsToGet - 1)) ==\r\n                Extension->LastCharSlot) {\r\n\r\n                Extension->FirstReadableChar = Extension->InterruptReadBuffer;\r\n\r\n            } else {\r\n\r\n                Extension->FirstReadableChar += numberOfCharsToGet;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // The characters do wrap.  Get up until the end of the buffer.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                ((PUCHAR)(reqContext->SystemBuffer))\r\n                    + (reqContext->Length - Extension->NumberNeededForRead),\r\n                Extension->FirstReadableChar,\r\n                firstTryNumberToGet\r\n                );\r\n\r\n            Extension->NumberNeededForRead -= firstTryNumberToGet;\r\n\r\n            //\r\n            // Now get the rest of the characters from the beginning of the\r\n            // buffer.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                ((PUCHAR)(reqContext->SystemBuffer))\r\n                    + (reqContext->Length  - Extension->NumberNeededForRead),\r\n                Extension->InterruptReadBuffer,\r\n                numberOfCharsToGet - firstTryNumberToGet\r\n                );\r\n\r\n            Extension->FirstReadableChar = Extension->InterruptReadBuffer +\r\n                                           (numberOfCharsToGet -\r\n                                            firstTryNumberToGet);\r\n\r\n            Extension->NumberNeededForRead -= (numberOfCharsToGet -\r\n                                               firstTryNumberToGet);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    reqContext->Information += numberOfCharsToGet;\r\n    return numberOfCharsToGet;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialUpdateInterruptBuffer(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to update the number of characters that\r\n    remain in the interrupt buffer.  We need to use this routine\r\n    since the count could be updated during the update by execution\r\n    of the ISR.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - Points to a structure that contains a pointer to the\r\n              device extension and count of the number of characters\r\n              that we previously copied into the users buffer.  The\r\n              structure actually has a third field that we don't\r\n              use in this routine.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_UPDATE_CHAR update = Context;\r\n    PSERIAL_DEVICE_EXTENSION extension = update->Extension;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ASSERT(extension->CharsInInterruptBuffer >= update->CharsCopied);\r\n    extension->CharsInInterruptBuffer -= update->CharsCopied;\r\n\r\n    //\r\n    // Deal with flow control if necessary.\r\n    //\r\n\r\n    SerialHandleReducedIntBuffer(extension);\r\n\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialUpdateAndSwitchToUser(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine gets the (hopefully) few characters that\r\n    remain in the interrupt buffer after the first time we tried\r\n    to get them out.  If we still don't have enough characters\r\n    to satisfy the read it will then we set things up so that the\r\n    ISR uses the user buffer copy into.\r\n\r\n    This routine is also used to update a count that is maintained\r\n    by the ISR to keep track of the number of characters in its buffer.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - Points to a structure that contains a pointer to the\r\n              device extension, a count of the number of characters\r\n              that we previously copied into the users buffer, and\r\n              a boolean that we will set that defines whether we\r\n              switched the ISR to copy into the users buffer.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_UPDATE_CHAR      updateChar = Context;\r\n    PSERIAL_DEVICE_EXTENSION extension = updateChar->Extension;\r\n    PREQUEST_CONTEXT         reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(extension->CurrentReadRequest);\r\n\r\n    SerialUpdateInterruptBuffer(extension->WdfInterrupt, Context);\r\n\r\n    //\r\n    // There are more characters to get to satisfy this read.\r\n    // Copy any characters that have arrived since we got\r\n    // the last batch.\r\n    //\r\n\r\n    updateChar->CharsCopied = SerialGetCharsFromIntBuffer(extension);\r\n\r\n    SerialUpdateInterruptBuffer(extension->WdfInterrupt, Context);\r\n\r\n    //\r\n    // No more new characters will be \"received\" until we exit\r\n    // this routine.  We again check to make sure that we\r\n    // haven't satisfied this read, and if we haven't we set things\r\n    // up so that the ISR copies into the user buffer.\r\n    //\r\n\r\n    if (extension->NumberNeededForRead) {\r\n\r\n        //\r\n        // We shouldn't be switching unless there are no\r\n        // characters left.\r\n        //\r\n\r\n        ASSERT(!extension->CharsInInterruptBuffer);\r\n\r\n        //\r\n        // We use the following to values to do inteval timing.\r\n        //\r\n        // CountOnLastRead is mostly used to simply prevent\r\n        // the interval timer from timing out before any characters\r\n        // are read. (Interval timing should only be effective\r\n        // after the first character is read.)\r\n        //\r\n        // After the first time the interval timer fires and\r\n        // characters have be read we will simply update with\r\n        // the value of ReadByIsr and then set ReadByIsr to zero.\r\n        // (We do that in a synchronization routine.\r\n        //\r\n        // If the interval timer dpc routine ever encounters\r\n        // ReadByIsr == 0 when CountOnLastRead is non-zero it\r\n        // will timeout the read.\r\n        //\r\n        // (Note that we have a special case of CountOnLastRead\r\n        // < 0.  This is done by the read completion routines other\r\n        // than the total timeout dpc to indicate that the total\r\n        // timeout has expired.)\r\n        //\r\n\r\n        extension->CountOnLastRead = (LONG)reqContext->Information;\r\n\r\n        extension->ReadByIsr = 0;\r\n\r\n        //\r\n        // By compareing the read buffer base address to the\r\n        // the base address of the interrupt buffer the ISR\r\n        // can determine whether we are using the interrupt\r\n        // buffer or the user buffer.\r\n        //\r\n\r\n        extension->ReadBufferBase = reqContext->SystemBuffer;\r\n\r\n        //\r\n        // The current char slot is after the last copied in\r\n        // character.  We know there is always room since we\r\n        // we wouldn't have gotten here if there wasn't.\r\n        //\r\n\r\n        extension->CurrentCharSlot = extension->ReadBufferBase +\r\n                                    reqContext->Information;\r\n\r\n        //\r\n        // The last position that a character can go is on the\r\n        // last byte of user buffer.  While the actual allocated\r\n        // buffer space may be bigger, we know that there is at\r\n        // least as much as the read length.\r\n        //\r\n\r\n        extension->LastCharSlot = extension->ReadBufferBase +\r\n                                      (reqContext->Length - 1);\r\n#if 0 // We set the cancel before calling this routine in StartRead\r\n        //\r\n        // Mark the request as being in a cancelable state.\r\n        //\r\n        IoSetCancelRoutine(\r\n            extension->CurrentReadIrp,\r\n            SerialCancelCurrentRead\r\n            );\r\n\r\n       SERIAL_SET_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_CANCEL\r\n            );\r\n#endif\r\n        //\r\n        // Increment the reference count twice.\r\n        //\r\n        // Once for the Isr owning the request and once\r\n        // because the cancel routine has a reference\r\n        // to it.\r\n        //\r\n\r\n        SERIAL_SET_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n        updateChar->Completed = FALSE;\r\n\r\n    } else {\r\n\r\n        updateChar->Completed = TRUE;\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n//\r\n// We use this structure only to communicate to the synchronization\r\n// routine when we are switching to the resized buffer.\r\n//\r\ntypedef struct _SERIAL_RESIZE_PARAMS {\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    PUCHAR OldBuffer;\r\n    PUCHAR NewBuffer;\r\n    ULONG NewBufferSize;\r\n    ULONG NumberMoved;\r\n    } SERIAL_RESIZE_PARAMS,*PSERIAL_RESIZE_PARAMS;\r\n\r\n\r\nNTSTATUS\r\nSerialResizeBuffer(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will process the resize buffer request.\r\n    If size requested for the RX buffer is smaller than\r\n    the current buffer then we will simply return\r\n    STATUS_SUCCESS.  (We don't want to make buffers smaller.\r\n    If we did that then we all of a sudden have \"overrun\"\r\n    problems to deal with as well as flow control to deal\r\n    with - very painful.)  We ignore the TX buffer size\r\n    request since we don't use a TX buffer.\r\n\r\nArguments:\r\n\r\n    Extension - Pointer to the device extension for the port.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if everything worked out ok.\r\n    STATUS_INSUFFICIENT_RESOURCES if we couldn't allocate the\r\n    memory for the buffer.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Extension->CurrentReadRequest);\r\n    PSERIAL_QUEUE_SIZE rs = reqContext->SystemBuffer;\r\n\r\n    PVOID newBuffer = reqContext->Type3InputBuffer;\r\n\r\n\r\n    reqContext->Type3InputBuffer = NULL;\r\n    reqContext->Information = 0L;\r\n    reqContext->Status = STATUS_SUCCESS;\r\n\r\n    if (rs->InSize <= Extension->BufferSize) {\r\n\r\n        //\r\n        // Nothing to do.  We don't make buffers smaller.  Just\r\n        // agree with the user.  We must deallocate the memory\r\n        // that was already allocated in the ioctl dispatch routine.\r\n        //\r\n\r\n        ExFreePool(newBuffer);\r\n\r\n    } else {\r\n\r\n        SERIAL_RESIZE_PARAMS rp;\r\n\r\n        //\r\n        // Hmmm, looks like we actually have to go\r\n        // through with this.  We need to move all the\r\n        // data that is in the current buffer into this\r\n        // new buffer.  We'll do this in two steps.\r\n        //\r\n        // First we go up to dispatch level and try to\r\n        // move as much as we can without stopping the\r\n        // ISR from running.  We go up to dispatch level\r\n        // by acquiring the control lock.  We do it at\r\n        // dispatch using the control lock so that:\r\n        //\r\n        //    1) We can't be context switched in the middle\r\n        //       of the move.  Our pointers into the buffer\r\n        //       could be *VERY* stale by the time we got back.\r\n        //\r\n        //    2) We use the control lock since we don't want\r\n        //       some pesky purge request to come along while\r\n        //       we are trying to move.\r\n        //\r\n        // After the move, but while we still hold the control\r\n        // lock, we synch with the ISR and get those last\r\n        // (hopefully) few characters that have come in since\r\n        // we started the copy.  We switch all of our pointers,\r\n        // counters, and such to point to this new buffer.  NOTE:\r\n        // we need to be careful.  If the buffer we were using\r\n        // was not the default one created when we initialized\r\n        // the device (i.e. it was created via a previous WDFREQUEST of\r\n        // this type), we should deallocate it.\r\n        //\r\n\r\n        rp.Extension = Extension;\r\n        rp.OldBuffer = Extension->InterruptReadBuffer;\r\n        rp.NewBuffer = newBuffer;\r\n        rp.NewBufferSize = rs->InSize;\r\n\r\n        rp.NumberMoved = SerialMoveToNewIntBuffer(\r\n                             Extension,\r\n                             newBuffer\r\n                             );\r\n\r\n        WdfInterruptSynchronize(\r\n            Extension->WdfInterrupt,\r\n            SerialUpdateAndSwitchToNew,\r\n            &rp\r\n            );\r\n\r\n        //\r\n        // Free up the memory that the old buffer consumed.\r\n        //\r\n\r\n        ExFreePool(rp.OldBuffer);\r\n\r\n    }\r\n\r\n    return STATUS_SUCCESS;\r\n\r\n}\r\n\r\n\r\nULONG\r\nSerialMoveToNewIntBuffer(\r\n    PSERIAL_DEVICE_EXTENSION Extension,\r\n    PUCHAR NewBuffer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to copy any characters out of the interrupt\r\n    buffer into the \"new\" buffer.  It will be reading values that\r\n    are updated with the ISR but this is safe since this value is\r\n    only decremented by synchronization routines.  This routine will\r\n    return the number of characters copied so some other routine\r\n    can call a synchronization routine to update what is seen at\r\n    interrupt level.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the device extension.\r\n    NewBuffer - Where the characters are to be move to.\r\n\r\nReturn Value:\r\n\r\n    The number of characters that were copied into the user\r\n    buffer.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    ULONG numberOfCharsMoved = Extension->CharsInInterruptBuffer;\r\n\r\n\r\n    if (numberOfCharsMoved) {\r\n\r\n        //\r\n        // This holds the number of characters between the first\r\n        // readable character and the last character we will read or\r\n        // the real physical end of the buffer (not the last readable\r\n        // character).\r\n        //\r\n        ULONG firstTryNumberToGet = (ULONG)(Extension->LastCharSlot -\r\n                                     Extension->FirstReadableChar) + 1;\r\n\r\n        if (firstTryNumberToGet >= numberOfCharsMoved) {\r\n\r\n            //\r\n            // The characters don't wrap.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                NewBuffer,\r\n                Extension->FirstReadableChar,\r\n                numberOfCharsMoved\r\n                );\r\n\r\n            if ((Extension->FirstReadableChar+(numberOfCharsMoved-1)) ==\r\n                Extension->LastCharSlot) {\r\n\r\n                Extension->FirstReadableChar = Extension->InterruptReadBuffer;\r\n\r\n            } else {\r\n\r\n                Extension->FirstReadableChar += numberOfCharsMoved;\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            //\r\n            // The characters do wrap.  Get up until the end of the buffer.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                NewBuffer,\r\n                Extension->FirstReadableChar,\r\n                firstTryNumberToGet\r\n                );\r\n\r\n            //\r\n            // Now get the rest of the characters from the beginning of the\r\n            // buffer.\r\n            //\r\n\r\n            RtlMoveMemory(\r\n                NewBuffer+firstTryNumberToGet,\r\n                Extension->InterruptReadBuffer,\r\n                numberOfCharsMoved - firstTryNumberToGet\r\n                );\r\n\r\n            Extension->FirstReadableChar = Extension->InterruptReadBuffer +\r\n                                   numberOfCharsMoved - firstTryNumberToGet;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    return numberOfCharsMoved;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialUpdateAndSwitchToNew(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine gets the (hopefully) few characters that\r\n    remain in the interrupt buffer after the first time we tried\r\n    to get them out.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - Points to a structure that contains a pointer to the\r\n              device extension, a pointer to the buffer we are moving\r\n              to, and a count of the number of characters\r\n              that we previously copied into the new buffer, and the\r\n              actual size of the new buffer.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_RESIZE_PARAMS params = Context;\r\n    PSERIAL_DEVICE_EXTENSION extension = params->Extension;\r\n    ULONG tempCharsInInterruptBuffer = extension->CharsInInterruptBuffer;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    ASSERT(extension->CharsInInterruptBuffer >= params->NumberMoved);\r\n\r\n    //\r\n    // We temporarily reduce the chars in interrupt buffer to\r\n    // \"fool\" the move routine.  We will restore it after the\r\n    // move.\r\n    //\r\n\r\n    extension->CharsInInterruptBuffer -= params->NumberMoved;\r\n\r\n    if (extension->CharsInInterruptBuffer) {\r\n\r\n        SerialMoveToNewIntBuffer(\r\n            extension,\r\n            params->NewBuffer + params->NumberMoved\r\n            );\r\n\r\n    }\r\n\r\n    extension->CharsInInterruptBuffer = tempCharsInInterruptBuffer;\r\n\r\n\r\n    extension->LastCharSlot = params->NewBuffer + (params->NewBufferSize - 1);\r\n    extension->FirstReadableChar = params->NewBuffer;\r\n    extension->ReadBufferBase = params->NewBuffer;\r\n    extension->InterruptReadBuffer = params->NewBuffer;\r\n    extension->BufferSize = params->NewBufferSize;\r\n\r\n    //\r\n    // We *KNOW* that the new interrupt buffer is larger than the\r\n    // old buffer.  We don't need to worry about it being full.\r\n    //\r\n\r\n    extension->CurrentCharSlot = extension->InterruptReadBuffer +\r\n                                 extension->CharsInInterruptBuffer;\r\n\r\n    //\r\n    // We set up the default xon/xoff limits.\r\n    //\r\n\r\n    extension->HandFlow.XoffLimit = extension->BufferSize >> 3;\r\n    extension->HandFlow.XonLimit = extension->BufferSize >> 1;\r\n\r\n    extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;\r\n    extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;\r\n\r\n    extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+\r\n                                   (extension->BufferSize>>4));\r\n\r\n    //\r\n    // Since we (essentially) reduced the percentage of the interrupt\r\n    // buffer being full, we need to handle any flow of control.\r\n    //\r\n\r\n    SerialHandleReducedIntBuffer(extension);\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/registry.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    registry.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is used to get values from the\r\n    registry and to manipulate entries in the registry.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"registry.tmh\"\r\n#endif\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(INIT,SerialGetConfigDefaults)\r\n#pragma alloc_text(PAGESRP0,SerialGetRegistryKeyValue)\r\n#pragma alloc_text(PAGESRP0,SerialPutRegistryKeyValue)\r\n#pragma alloc_text(PAGESRP0,SerialGetFdoRegistryKeyValue)\r\n#endif // ALLOC_PRAGMA\r\n\r\n\r\n#define PARAMATER_NAME_LEN 80\r\n\r\n\r\nNTSTATUS\r\nSerialGetConfigDefaults(\r\n    IN PSERIAL_FIRMWARE_DATA    DriverDefaultsPtr,\r\n    IN WDFDRIVER          Driver\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine reads the default configuration data from the\r\n    registry for the serial driver.\r\n\r\n    It also builds fields in the registry for several configuration\r\n    options if they don't exist.\r\n\r\nArguments:\r\n\r\n    DriverDefaultsPtr - Pointer to a structure that will contain\r\n                        the default configuration values.\r\n\r\n    RegistryPath - points to the entry for this driver in the\r\n                   current control set of the registry.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if we got the defaults, otherwise we failed.\r\n    The only way to fail this call is if the  STATUS_INSUFFICIENT_RESOURCES.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    NTSTATUS status = STATUS_SUCCESS;    // return value\r\n    WDFKEY hKey;\r\n    DECLARE_UNICODE_STRING_SIZE(valueName,PARAMATER_NAME_LEN);\r\n\r\n    status = WdfDriverOpenParametersRegistryKey(Driver,\r\n                                  STANDARD_RIGHTS_ALL,\r\n                                  WDF_NO_OBJECT_ATTRIBUTES,\r\n                                  &hKey);\r\n    if (!NT_SUCCESS (status)) {\r\n        return status;\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"BreakOnEntry\");\r\n    if (!NT_SUCCESS (status)) {\r\n             goto End;\r\n\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n                              &valueName,\r\n                              &DriverDefaultsPtr->ShouldBreakOnEntry);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n        DriverDefaultsPtr->ShouldBreakOnEntry = 0;\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"DebugLevel\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n                              &valueName,\r\n                              &DriverDefaultsPtr->DebugLevel);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n        DriverDefaultsPtr->DebugLevel = 0;\r\n    }\r\n\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"ForceFifoEnable\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->ForceFifoEnableDefault);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        //\r\n        // If it isn't then write out values so that it could\r\n        // be adjusted later.\r\n        //\r\n        DriverDefaultsPtr->ForceFifoEnableDefault = SERIAL_FORCE_FIFO_DEFAULT;\r\n\r\n        status = WdfRegistryAssignULong(hKey,\r\n                            &valueName,\r\n                            DriverDefaultsPtr->ForceFifoEnableDefault\r\n                            );\r\n        if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n        }\r\n\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"RxFIFO\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->RxFIFODefault);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        DriverDefaultsPtr->RxFIFODefault = SERIAL_RX_FIFO_DEFAULT;\r\n\r\n        status = WdfRegistryAssignULong(hKey,\r\n                            &valueName,\r\n                            DriverDefaultsPtr->RxFIFODefault\r\n                            );\r\n        if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n        }\r\n\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"TxFIFO\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->TxFIFODefault);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        DriverDefaultsPtr->TxFIFODefault = SERIAL_TX_FIFO_DEFAULT;\r\n\r\n        status = WdfRegistryAssignULong(hKey,\r\n                            &valueName,\r\n                            DriverDefaultsPtr->TxFIFODefault\r\n                            );\r\n        if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n        }\r\n\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"PermitShare\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->PermitShareDefault);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        DriverDefaultsPtr->PermitShareDefault = SERIAL_PERMIT_SHARE_DEFAULT;\r\n\r\n        status = WdfRegistryAssignULong(hKey,\r\n                            &valueName,\r\n                            DriverDefaultsPtr->PermitShareDefault\r\n                            );\r\n        if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n        }\r\n\r\n    }\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"LogFifo\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->LogFifoDefault);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        DriverDefaultsPtr->LogFifoDefault = SERIAL_LOG_FIFO_DEFAULT;\r\n\r\n        status = WdfRegistryAssignULong(hKey,\r\n                            &valueName,\r\n                            DriverDefaultsPtr->LogFifoDefault\r\n                            );\r\n        if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n        }\r\n\r\n            DriverDefaultsPtr->LogFifoDefault = 1;\r\n    }\r\n\r\n\r\n    status = RtlUnicodeStringPrintf(&valueName,L\"UartRemovalDetect\");\r\n    if (!NT_SUCCESS (status)) {\r\n            goto End;\r\n    }\r\n\r\n    status = WdfRegistryQueryULong (hKey,\r\n              &valueName,\r\n              &DriverDefaultsPtr->UartRemovalDetect);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n        DriverDefaultsPtr->UartRemovalDetect = 0;\r\n    }\r\n\r\n\r\nEnd:\r\n       WdfRegistryClose(hKey);\r\n    return (status);\r\n}\r\n\r\nBOOLEAN\r\nSerialGetRegistryKeyValue(\r\n    IN WDFDEVICE  WdfDevice,\r\n    _In_ PCWSTR   Name,\r\n    OUT PULONG    Value\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Can be used to read any REG_DWORD registry value stored\r\n    under Device Parameter.\r\n\r\nArguments:\r\n\r\n    FdoData - pointer to the device extension\r\n    Name - Name of the registry value\r\n    Value -\r\n\r\n\r\nReturn Value:\r\n\r\n   TRUE if successful\r\n   FALSE if not present/error in reading registry\r\n\r\n--*/\r\n{\r\n    WDFKEY      hKey = NULL;\r\n    NTSTATUS    status;\r\n    BOOLEAN     retValue = FALSE;\r\n    UNICODE_STRING valueName;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \">SerialGetRegistryKeyValue(XXX)\\n\");\r\n\r\n    *Value = 0;\r\n\r\n    status = WdfDeviceOpenRegistryKey(WdfDevice,\r\n                                  PLUGPLAY_REGKEY_DEVICE,\r\n                                  STANDARD_RIGHTS_ALL,\r\n                                  WDF_NO_OBJECT_ATTRIBUTES,\r\n                                  &hKey);\r\n\r\n    if (NT_SUCCESS (status)) {\r\n\r\n        RtlInitUnicodeString(&valueName,Name);\r\n\r\n        status = WdfRegistryQueryULong (hKey,\r\n                                  &valueName,\r\n                                  Value);\r\n\r\n        if (NT_SUCCESS (status)) {\r\n            retValue = TRUE;\r\n        }\r\n\r\n        WdfRegistryClose(hKey);\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP, \"<--SerialGetRegistryKeyValue %ws %d \\n\",\r\n                            Name, *Value);\r\n\r\n    return retValue;\r\n}\r\n\r\n#define PARAMATER_NAME_LEN 80\r\n\r\nBOOLEAN\r\nSerialPutRegistryKeyValue(\r\n    IN WDFDEVICE  WdfDevice,\r\n    _In_ PCWSTR   Name,\r\n    IN ULONG      Value\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Can be used to write any REG_DWORD registry value stored\r\n    under Device Parameter.\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n   TRUE - if write is successful\r\n   FALSE - otherwise\r\n\r\n--*/\r\n{\r\n    WDFKEY          hKey = NULL;\r\n    NTSTATUS        status;\r\n    BOOLEAN         retValue = FALSE;\r\n    UNICODE_STRING valueName;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP,  \"Entered PciDrvWriteRegistryValue\\n\");\r\n\r\n    //\r\n    // write the value out to the registry\r\n    //\r\n    status = WdfDeviceOpenRegistryKey(WdfDevice,\r\n                                      PLUGPLAY_REGKEY_DEVICE,\r\n                                      STANDARD_RIGHTS_ALL,\r\n                                      WDF_NO_OBJECT_ATTRIBUTES,\r\n                                      &hKey);\r\n\r\n    if (NT_SUCCESS (status)) {\r\n\r\n        RtlInitUnicodeString(&valueName,Name);\r\n\r\n        status = WdfRegistryAssignULong (hKey,\r\n                                  &valueName,\r\n                                  Value\r\n                                );\r\n\r\n        if (NT_SUCCESS (status)) {\r\n            retValue = TRUE;\r\n        }\r\n\r\n        WdfRegistryClose(hKey);\r\n    }\r\n\r\n    return retValue;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialGetFdoRegistryKeyValue(\r\n    IN PWDFDEVICE_INIT  DeviceInit,\r\n    _In_ PCWSTR         Name,\r\n    OUT PULONG          Value\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Can be used to read any REG_DWORD registry value stored\r\n    under Device Parameter.\r\n\r\nArguments:\r\n\r\n    FdoData - pointer to the device extension\r\n    Name - Name of the registry value\r\n    Value -\r\n\r\n\r\nReturn Value:\r\n\r\n   TRUE if successful\r\n   FALSE if not present/error in reading registry\r\n\r\n--*/\r\n{\r\n    WDFKEY      hKey = NULL;\r\n    NTSTATUS    status;\r\n    BOOLEAN     retValue = FALSE;\r\n    UNICODE_STRING valueName;\r\n\r\n    PAGED_CODE();\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP,\r\n                     \"-->SerialGetFdoRegistryKeyValue\\n\");\r\n\r\n    *Value = 0;\r\n\r\n    status = WdfFdoInitOpenRegistryKey(DeviceInit,\r\n                                  PLUGPLAY_REGKEY_DEVICE,\r\n                                  STANDARD_RIGHTS_ALL,\r\n                                  WDF_NO_OBJECT_ATTRIBUTES,\r\n                                  &hKey);\r\n\r\n    if (NT_SUCCESS (status)) {\r\n\r\n        RtlInitUnicodeString(&valueName,Name);\r\n\r\n        status = WdfRegistryQueryULong (hKey, &valueName, Value);\r\n\r\n        if (NT_SUCCESS (status)) {\r\n            retValue = TRUE;\r\n        }\r\n\r\n        WdfRegistryClose(hKey);\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP,\r\n                     \"<--SerialGetFdoRegistryKeyValue %ws %d \\n\",\r\n                            Name, *Value);\r\n\r\n    return retValue;\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/serial.h",
    "content": "/*++\r\n\r\nCopyright (c) 1990, 1991, 1992, 1993 - 1997 Microsoft Corporation\r\n\r\nModule Name :\r\n\r\n    serial.h\r\n\r\nAbstract:\r\n\r\n    Type definitions and data for the serial port driver\r\n\r\n--*/\r\n\r\n#define POOL_TAG 'XMOC'\r\n\r\n\r\n//\r\n// Some default driver values.  We will check the registry for\r\n// them first.\r\n//\r\n#define SERIAL_UNINITIALIZED_DEFAULT    1234567\r\n#define SERIAL_FORCE_FIFO_DEFAULT       1\r\n#define SERIAL_RX_FIFO_DEFAULT          8\r\n#define SERIAL_TX_FIFO_DEFAULT          14\r\n#define SERIAL_PERMIT_SHARE_DEFAULT     0\r\n#define SERIAL_LOG_FIFO_DEFAULT         0\r\n\r\n\r\n//\r\n// This define gives the default Object directory\r\n// that we should use to insert the symbolic links\r\n// between the NT device name and namespace used by\r\n// that object directory.\r\n#define DEFAULT_DIRECTORY L\"DosDevices\"\r\n\r\n//\r\n// For the above directory, the serial port will\r\n// use the following name as the suffix of the serial\r\n// ports for that directory.  It will also append\r\n// a number onto the end of the name.  That number\r\n// will start at 1.\r\n#define DEFAULT_SERIAL_NAME L\"COM\"\r\n//\r\n//\r\n// This define gives the default NT name for\r\n// for serial ports detected by the firmware.\r\n// This name will be appended to Device prefix\r\n// with a number following it.  The number is\r\n// incremented each time encounter a serial\r\n// port detected by the firmware.  Note that\r\n// on a system with multiple busses, this means\r\n// that the first port on a bus is not necessarily\r\n// \\Device\\Serial0.\r\n//\r\n#define DEFAULT_NT_SUFFIX L\"Serial\"\r\n#define _DRIVER_NAME_  \"Serial.sys\"\r\n\r\n#define DEVICE_OBJECT_NAME_LENGTH       128\r\n#define SYMBOLIC_NAME_LENGTH            128\r\n#define SERIAL_DEVICE_MAP               L\"SERIALCOMM\"\r\n\r\n//\r\n// GUID_DEVINTERFACE_COMPORT is not defined in the Win2K\r\n// headers, so we will need this definition to avoid compilation\r\n// errors.\r\n//\r\n#define GUID_DEVINTERFACE_COMPORT GUID_CLASS_COMPORT\r\n\r\n//\r\n// This value - which could be redefined at compile\r\n// time, define the stride between registers\r\n//\r\n#if !defined(SERIAL_REGISTER_STRIDE)\r\n#define SERIAL_REGISTER_STRIDE 1\r\n#endif\r\n\r\n//\r\n// Offsets from the base register address of the\r\n// various registers for the 8250 family of UARTS.\r\n//\r\n#define RECEIVE_BUFFER_REGISTER    ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))\r\n#define TRANSMIT_HOLDING_REGISTER  ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))\r\n#define INTERRUPT_ENABLE_REGISTER  ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE))\r\n#define INTERRUPT_IDENT_REGISTER   ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE))\r\n#define FIFO_CONTROL_REGISTER      ((ULONG)((0x02)*SERIAL_REGISTER_STRIDE))\r\n#define LINE_CONTROL_REGISTER      ((ULONG)((0x03)*SERIAL_REGISTER_STRIDE))\r\n#define MODEM_CONTROL_REGISTER     ((ULONG)((0x04)*SERIAL_REGISTER_STRIDE))\r\n#define LINE_STATUS_REGISTER       ((ULONG)((0x05)*SERIAL_REGISTER_STRIDE))\r\n#define MODEM_STATUS_REGISTER      ((ULONG)((0x06)*SERIAL_REGISTER_STRIDE))\r\n#define DIVISOR_LATCH_LSB          ((ULONG)((0x00)*SERIAL_REGISTER_STRIDE))\r\n#define DIVISOR_LATCH_MSB          ((ULONG)((0x01)*SERIAL_REGISTER_STRIDE))\r\n#define SERIAL_REGISTER_SPAN       ((ULONG)(7*SERIAL_REGISTER_STRIDE))\r\n\r\n//\r\n// If we have an interrupt status register this is its assumed\r\n// length.\r\n//\r\n#define SERIAL_STATUS_LENGTH       ((ULONG)(1*SERIAL_REGISTER_STRIDE))\r\n\r\n//\r\n// Bitmask definitions for accessing the 8250 device registers.\r\n//\r\n\r\n//\r\n// These bits define the number of data bits trasmitted in\r\n// the Serial Data Unit (SDU - Start,data, parity, and stop bits)\r\n//\r\n#define SERIAL_DATA_LENGTH_5 0x00\r\n#define SERIAL_DATA_LENGTH_6 0x01\r\n#define SERIAL_DATA_LENGTH_7 0x02\r\n#define SERIAL_DATA_LENGTH_8 0x03\r\n\r\n\r\n//\r\n// These masks define the interrupts that can be enabled or disabled.\r\n//\r\n//\r\n// This interrupt is used to notify that there is new incomming\r\n// data available.  The SERIAL_RDA interrupt is enabled by this bit.\r\n//\r\n#define SERIAL_IER_RDA   0x01\r\n\r\n//\r\n// This interrupt is used to notify that there is space available\r\n// in the transmitter for another character.  The SERIAL_THR\r\n// interrupt is enabled by this bit.\r\n//\r\n#define SERIAL_IER_THR   0x02\r\n\r\n//\r\n// This interrupt is used to notify that some sort of error occured\r\n// with the incomming data.  The SERIAL_RLS interrupt is enabled by\r\n// this bit.\r\n#define SERIAL_IER_RLS   0x04\r\n\r\n//\r\n// This interrupt is used to notify that some sort of change has\r\n// taken place in the modem control line.  The SERIAL_MS interrupt is\r\n// enabled by this bit.\r\n//\r\n#define SERIAL_IER_MS    0x08\r\n\r\n\r\n//\r\n// These masks define the values of the interrupt identification\r\n// register.  The low bit must be clear in the interrupt identification\r\n// register for any of these interrupts to be valid.  The interrupts\r\n// are defined in priority order, with the highest value being most\r\n// important.  See above for a description of what each interrupt\r\n// implies.\r\n//\r\n#define SERIAL_IIR_RLS      0x06\r\n#define SERIAL_IIR_RDA      0x04\r\n#define SERIAL_IIR_CTI      0x0c\r\n#define SERIAL_IIR_THR      0x02\r\n#define SERIAL_IIR_MS       0x00\r\n\r\n//\r\n// This bit mask get the value of the high two bits of the\r\n// interrupt id register.  If this is a 16550 class chip\r\n// these bits will be a one if the fifo's are enbled, otherwise\r\n// they will always be zero.\r\n//\r\n#define SERIAL_IIR_FIFOS_ENABLED 0xc0\r\n\r\n//\r\n// If the low bit is logic one in the interrupt identification register\r\n// this implies that *NO* interrupts are pending on the device.\r\n//\r\n#define SERIAL_IIR_NO_INTERRUPT_PENDING 0x01\r\n\r\n\r\n//\r\n// Use these bits to detect removal of serial card for Stratus implementation\r\n//\r\n#define SERIAL_IIR_MUST_BE_ZERO 0x30\r\n\r\n\r\n//\r\n// These masks define access to the fifo control register.\r\n//\r\n\r\n//\r\n// Enabling this bit in the fifo control register will turn\r\n// on the fifos.  If the fifos are enabled then the high two\r\n// bits of the interrupt id register will be set to one.  Note\r\n// that this only occurs on a 16550 class chip.  If the high\r\n// two bits in the interrupt id register are not one then\r\n// we know we have a lower model chip.\r\n//\r\n//\r\n#define SERIAL_FCR_ENABLE     ((UCHAR)0x01)\r\n#define SERIAL_FCR_RCVR_RESET ((UCHAR)0x02)\r\n#define SERIAL_FCR_TXMT_RESET ((UCHAR)0x04)\r\n\r\n//\r\n// This set of values define the high water marks (when the\r\n// interrupts trip) for the receive fifo.\r\n//\r\n#define SERIAL_1_BYTE_HIGH_WATER   ((UCHAR)0x00)\r\n#define SERIAL_4_BYTE_HIGH_WATER   ((UCHAR)0x40)\r\n#define SERIAL_8_BYTE_HIGH_WATER   ((UCHAR)0x80)\r\n#define SERIAL_14_BYTE_HIGH_WATER  ((UCHAR)0xc0)\r\n\r\n//\r\n// These masks define access to the line control register.\r\n//\r\n\r\n//\r\n// This defines the bit used to control the definition of the \"first\"\r\n// two registers for the 8250.  These registers are the input/output\r\n// register and the interrupt enable register.  When the DLAB bit is\r\n// enabled these registers become the least significant and most\r\n// significant bytes of the divisor value.\r\n//\r\n#define SERIAL_LCR_DLAB     0x80\r\n\r\n//\r\n// This defines the bit used to control whether the device is sending\r\n// a break.  When this bit is set the device is sending a space (logic 0).\r\n//\r\n// Most protocols will assume that this is a hangup.\r\n//\r\n#define SERIAL_LCR_BREAK    0x40\r\n\r\n//\r\n// These defines are used to set the line control register.\r\n//\r\n#define SERIAL_5_DATA       ((UCHAR)0x00)\r\n#define SERIAL_6_DATA       ((UCHAR)0x01)\r\n#define SERIAL_7_DATA       ((UCHAR)0x02)\r\n#define SERIAL_8_DATA       ((UCHAR)0x03)\r\n#define SERIAL_DATA_MASK    ((UCHAR)0x03)\r\n\r\n#define SERIAL_1_STOP       ((UCHAR)0x00)\r\n#define SERIAL_1_5_STOP     ((UCHAR)0x04) // Only valid for 5 data bits\r\n#define SERIAL_2_STOP       ((UCHAR)0x04) // Not valid for 5 data bits\r\n#define SERIAL_STOP_MASK    ((UCHAR)0x04)\r\n\r\n#define SERIAL_NONE_PARITY  ((UCHAR)0x00)\r\n#define SERIAL_ODD_PARITY   ((UCHAR)0x08)\r\n#define SERIAL_EVEN_PARITY  ((UCHAR)0x18)\r\n#define SERIAL_MARK_PARITY  ((UCHAR)0x28)\r\n#define SERIAL_SPACE_PARITY ((UCHAR)0x38)\r\n#define SERIAL_PARITY_MASK  ((UCHAR)0x38)\r\n\r\n//\r\n// These masks define access the modem control register.\r\n//\r\n\r\n//\r\n// This bit controls the data terminal ready (DTR) line.  When\r\n// this bit is set the line goes to logic 0 (which is then inverted\r\n// by normal hardware).  This is normally used to indicate that\r\n// the device is available to be used.  Some odd hardware\r\n// protocols (like the kernel debugger) use this for handshaking\r\n// purposes.\r\n//\r\n#define SERIAL_MCR_DTR            0x01\r\n\r\n//\r\n// This bit controls the ready to send (RTS) line.  When this bit\r\n// is set the line goes to logic 0 (which is then inverted by the normal\r\n// hardware).  This is used for hardware handshaking.  It indicates that\r\n// the hardware is ready to send data and it is waiting for the\r\n// receiving end to set clear to send (CTS).\r\n//\r\n#define SERIAL_MCR_RTS            0x02\r\n\r\n//\r\n// This bit is used for general purpose output.\r\n//\r\n#define SERIAL_MCR_OUT1           0x04\r\n\r\n//\r\n// This bit is used for general purpose output.\r\n//\r\n#define SERIAL_MCR_OUT2           0x08\r\n\r\n//\r\n// This bit controls the loopback testing mode of the device.  Basically\r\n// the outputs are connected to the inputs (and vice versa).\r\n//\r\n#define SERIAL_MCR_LOOP           0x10\r\n\r\n//\r\n// This bit enables auto flow control on a TI TL16C550C/TL16C550CI\r\n//\r\n\r\n#define SERIAL_MCR_TL16C550CAFE   0x20\r\n\r\n\r\n//\r\n// These masks define access to the line status register.  The line\r\n// status register contains information about the status of data\r\n// transfer.  The first five bits deal with receive data and the\r\n// last two bits deal with transmission.  An interrupt is generated\r\n// whenever bits 1 through 4 in this register are set.\r\n//\r\n\r\n//\r\n// This bit is the data ready indicator.  It is set to indicate that\r\n// a complete character has been received.  This bit is cleared whenever\r\n// the receive buffer register has been read.\r\n//\r\n#define SERIAL_LSR_DR       0x01\r\n\r\n//\r\n// This is the overrun indicator.  It is set to indicate that the receive\r\n// buffer register was not read befor a new character was transferred\r\n// into the buffer.  This bit is cleared when this register is read.\r\n//\r\n#define SERIAL_LSR_OE       0x02\r\n\r\n//\r\n// This is the parity error indicator.  It is set whenever the hardware\r\n// detects that the incoming serial data unit does not have the correct\r\n// parity as defined by the parity select in the line control register.\r\n// This bit is cleared by reading this register.\r\n//\r\n#define SERIAL_LSR_PE       0x04\r\n\r\n//\r\n// This is the framing error indicator.  It is set whenever the hardware\r\n// detects that the incoming serial data unit does not have a valid\r\n// stop bit.  This bit is cleared by reading this register.\r\n//\r\n#define SERIAL_LSR_FE       0x08\r\n\r\n//\r\n// This is the break interrupt indicator.  It is set whenever the data\r\n// line is held to logic 0 for more than the amount of time it takes\r\n// to send one serial data unit.  This bit is cleared whenever the\r\n// this register is read.\r\n//\r\n#define SERIAL_LSR_BI       0x10\r\n\r\n//\r\n// This is the transmit holding register empty indicator.  It is set\r\n// to indicate that the hardware is ready to accept another character\r\n// for transmission.  This bit is cleared whenever a character is\r\n// written to the transmit holding register.\r\n//\r\n#define SERIAL_LSR_THRE     0x20\r\n\r\n//\r\n// This bit is the transmitter empty indicator.  It is set whenever the\r\n// transmit holding buffer is empty and the transmit shift register\r\n// (a non-software accessable register that is used to actually put\r\n// the data out on the wire) is empty.  Basically this means that all\r\n// data has been sent.  It is cleared whenever the transmit holding or\r\n// the shift registers contain data.\r\n//\r\n#define SERIAL_LSR_TEMT     0x40\r\n\r\n//\r\n// This bit indicates that there is at least one error in the fifo.\r\n// The bit will not be turned off until there are no more errors\r\n// in the fifo.\r\n//\r\n#define SERIAL_LSR_FIFOERR  0x80\r\n\r\n\r\n//\r\n// These masks are used to access the modem status register.\r\n// Whenever one of the first four bits in the modem status\r\n// register changes state a modem status interrupt is generated.\r\n//\r\n\r\n//\r\n// This bit is the delta clear to send.  It is used to indicate\r\n// that the clear to send bit (in this register) has *changed*\r\n// since this register was last read by the CPU.\r\n//\r\n#define SERIAL_MSR_DCTS     0x01\r\n\r\n//\r\n// This bit is the delta data set ready.  It is used to indicate\r\n// that the data set ready bit (in this register) has *changed*\r\n// since this register was last read by the CPU.\r\n//\r\n#define SERIAL_MSR_DDSR     0x02\r\n\r\n//\r\n// This is the trailing edge ring indicator.  It is used to indicate\r\n// that the ring indicator input has changed from a low to high state.\r\n//\r\n#define SERIAL_MSR_TERI     0x04\r\n\r\n//\r\n// This bit is the delta data carrier detect.  It is used to indicate\r\n// that the data carrier bit (in this register) has *changed*\r\n// since this register was last read by the CPU.\r\n//\r\n#define SERIAL_MSR_DDCD     0x08\r\n\r\n//\r\n// This bit contains the (complemented) state of the clear to send\r\n// (CTS) line.\r\n//\r\n#define SERIAL_MSR_CTS      0x10\r\n\r\n//\r\n// This bit contains the (complemented) state of the data set ready\r\n// (DSR) line.\r\n//\r\n#define SERIAL_MSR_DSR      0x20\r\n\r\n//\r\n// This bit contains the (complemented) state of the ring indicator\r\n// (RI) line.\r\n//\r\n#define SERIAL_MSR_RI       0x40\r\n\r\n//\r\n// This bit contains the (complemented) state of the data carrier detect\r\n// (DCD) line.\r\n//\r\n#define SERIAL_MSR_DCD      0x80\r\n\r\n//\r\n// This should be more than enough space to hold then\r\n// numeric suffix of the device name.\r\n//\r\n#define DEVICE_NAME_DELTA 20\r\n\r\n\r\n//\r\n// Up to 16 Ports Per card.  However for sixteen\r\n// port cards the interrupt status register must me\r\n// the indexing kind rather then the bitmask kind.\r\n//\r\n//\r\n#define SERIAL_MAX_PORTS_INDEXED (16)\r\n#define SERIAL_MAX_PORTS_NONINDEXED (8)\r\n\r\ntypedef struct _CONFIG_DATA {\r\n    PHYSICAL_ADDRESS    Controller;\r\n    PHYSICAL_ADDRESS    TrController;\r\n    ULONG               SpanOfController;\r\n    ULONG               ClockRate;\r\n    ULONG               AddressSpace;\r\n    ULONG               DisablePort;\r\n    ULONG               ForceFifoEnable;\r\n    ULONG               RxFIFO;\r\n    ULONG               TxFIFO;\r\n    ULONG               PermitShare;\r\n    ULONG               PermitSystemWideShare;\r\n    ULONG               LogFifo;\r\n    KINTERRUPT_MODE     InterruptMode;\r\n    ULONG               TrVector;\r\n    ULONG               TrIrql;\r\n    KAFFINITY           Affinity;\r\n    ULONG               TL16C550CAFC;\r\n    } CONFIG_DATA,*PCONFIG_DATA;\r\n\r\n\r\n//\r\n// This structure contains configuration data, much of which\r\n// is read from the registry.\r\n//\r\ntypedef struct _SERIAL_FIRMWARE_DATA {\r\n    PDRIVER_OBJECT  DriverObject;\r\n    ULONG           ControllersFound;\r\n    ULONG           ForceFifoEnableDefault;\r\n    ULONG           DebugLevel;\r\n    ULONG           ShouldBreakOnEntry;\r\n    ULONG           RxFIFODefault;\r\n    ULONG           TxFIFODefault;\r\n    ULONG           PermitShareDefault;\r\n    ULONG           PermitSystemWideShare;\r\n    ULONG           LogFifoDefault;\r\n    ULONG           UartRemovalDetect;\r\n    UNICODE_STRING  Directory;\r\n    UNICODE_STRING  NtNameSuffix;\r\n    UNICODE_STRING  DirectorySymbolicName;\r\n    LIST_ENTRY      ConfigList;\r\n} SERIAL_FIRMWARE_DATA,*PSERIAL_FIRMWARE_DATA;\r\n\r\n//\r\n// Default xon/xoff characters.\r\n//\r\n#define SERIAL_DEF_XON 0x11\r\n#define SERIAL_DEF_XOFF 0x13\r\n\r\n//\r\n// Reasons that recption may be held up.\r\n//\r\n#define SERIAL_RX_DTR       ((ULONG)0x01)\r\n#define SERIAL_RX_XOFF      ((ULONG)0x02)\r\n#define SERIAL_RX_RTS       ((ULONG)0x04)\r\n#define SERIAL_RX_DSR       ((ULONG)0x08)\r\n\r\n//\r\n// Reasons that transmission may be held up.\r\n//\r\n#define SERIAL_TX_CTS       ((ULONG)0x01)\r\n#define SERIAL_TX_DSR       ((ULONG)0x02)\r\n#define SERIAL_TX_DCD       ((ULONG)0x04)\r\n#define SERIAL_TX_XOFF      ((ULONG)0x08)\r\n#define SERIAL_TX_BREAK     ((ULONG)0x10)\r\n\r\n//\r\n// These values are used by the routines that can be used\r\n// to complete a read (other than interval timeout) to indicate\r\n// to the interval timeout that it should complete.\r\n//\r\n#define SERIAL_COMPLETE_READ_CANCEL ((LONG)-1)\r\n#define SERIAL_COMPLETE_READ_TOTAL ((LONG)-2)\r\n#define SERIAL_COMPLETE_READ_COMPLETE ((LONG)-3)\r\n\r\n//\r\n// These are default values that shouldn't appear in the registry\r\n//\r\n#define SERIAL_BAD_VALUE ((ULONG)-1)\r\n\r\n\r\ntypedef struct _SERIAL_DEVICE_STATE {\r\n   //\r\n   // TRUE if we need to set the state to open\r\n   // on a powerup\r\n   //\r\n\r\n   BOOLEAN Reopen;\r\n\r\n   //\r\n   // Hardware registers\r\n   //\r\n\r\n   UCHAR IER;\r\n   // FCR is known by other values\r\n   UCHAR LCR;\r\n   UCHAR MCR;\r\n   // LSR is never written\r\n   // MSR is never written\r\n   // SCR is either scratch or interrupt status\r\n\r\n\r\n} SERIAL_DEVICE_STATE, *PSERIAL_DEVICE_STATE;\r\n\r\n\r\ntypedef\r\nUCHAR\r\n(*PREAD_PORT_UCHAR)(\r\n    IN UCHAR *Register\r\n    );\r\n\r\ntypedef\r\nVOID\r\n(*PWRITE_PORT_UCHAR)(\r\n    IN UCHAR *Register,\r\n    IN UCHAR  Value\r\n    );\r\n\r\ntypedef struct _SERIAL_DEVICE_EXTENSION {\r\n    //\r\n    // WDF device handle\r\n    //\r\n    WDFDEVICE WdfDevice;\r\n    //\r\n    // Points to the device object that contains\r\n    // this device extension.\r\n    //\r\n    PDEVICE_OBJECT DeviceObject;\r\n    //\r\n    // We keep a pointer around to our device name for dumps\r\n    // and for creating \"external\" symbolic links to this\r\n    // device.\r\n    //\r\n    UNICODE_STRING DeviceName;\r\n    //\r\n    // Pointer to the driver object\r\n    //\r\n\r\n    PDRIVER_OBJECT DriverObject;\r\n\r\n    //\r\n    // Records whether we actually created the symbolic link name\r\n    // at driver load time.  If we didn't create it, we won't try\r\n    // to destroy it when we unload.\r\n    //\r\n    BOOLEAN CreatedSymbolicLink;\r\n\r\n    //\r\n    // Records whether we actually created an entry in SERIALCOMM\r\n    // at driver load time.  If we didn't create it, we won't try\r\n    // to destroy it when the device is removed.\r\n    //\r\n    BOOLEAN CreatedSerialCommEntry;\r\n\r\n    //\r\n    // Did we update system count for serial ports\r\n    //\r\n    BOOLEAN    IsSystemConfigInfoUpdated;\r\n\r\n    //\r\n    // Should we expose external interfaces?\r\n    //\r\n    ULONG SkipNaming;\r\n\r\n    //\r\n    // Support the TI TL16C550C and TL16C550CI auto flow control\r\n    //\r\n\r\n    ULONG TL16C550CAFC;\r\n\r\n    //\r\n    // Detect removed hardware in intterrupt routine flag\r\n    //\r\n    ULONG UartRemovalDetect;\r\n\r\n    //\r\n    // We keep track of whether the somebody has the device currently\r\n    // opened with a simple boolean.  We need to know this so that\r\n    // spurious interrupts from the device (especially during initialization)\r\n    // will be ignored.  This value is only accessed in the ISR and\r\n    // is only set via synchronization routines.  We may be able\r\n    // to get rid of this boolean when the code is more fleshed out.\r\n    //\r\n    BOOLEAN DeviceIsOpened;\r\n\r\n    //\r\n    // Current state during powerdown\r\n    //\r\n\r\n    SERIAL_DEVICE_STATE DeviceState;\r\n\r\n    //\r\n    // TRUE if we own power policy\r\n    //\r\n\r\n    BOOLEAN OwnsPowerPolicy;\r\n\r\n    //\r\n    // TRUE if we should retain power on close and not aggressively\r\n    // reduce power consumption\r\n    //\r\n\r\n    BOOLEAN RetainPowerOnClose;\r\n\r\n    //\r\n    // Should we enable wakeup\r\n    //\r\n\r\n    BOOLEAN IsWakeEnabled;\r\n\r\n    //\r\n    // This list head is used to contain the time ordered list\r\n    // of read requests.  Access to this list is protected by\r\n    // the global cancel spinlock.\r\n    //\r\n    WDFQUEUE ReadQueue;\r\n\r\n    //\r\n    // This list head is used to contain the time ordered list\r\n    // of write requests.  Access to this list is protected by\r\n    // the global cancel spinlock.\r\n    //\r\n    WDFQUEUE WriteQueue;\r\n\r\n    //\r\n    // This list head is used to contain the time ordered list\r\n    // of set and wait mask requests.  Access to this list is protected by\r\n    // the global cancel spinlock.\r\n    //\r\n    WDFQUEUE MaskQueue;\r\n\r\n    //\r\n    // Holds the serialized list of purge requests.\r\n    //\r\n    WDFQUEUE PurgeQueue;\r\n\r\n    //\r\n    // This points to the request that is currently being processed\r\n    // for the read queue.  This field is initialized by the open to\r\n    // NULL.\r\n    //\r\n    // This value is only set at dispatch level.  It may be\r\n    // read at interrupt level.\r\n    //\r\n    WDFREQUEST CurrentReadRequest;\r\n\r\n    //\r\n    // This points to the request that is currently being processed\r\n    // for the write queue.\r\n    //\r\n    // This value is only set at dispatch level.  It may be\r\n    // read at interrupt level.\r\n    //\r\n    WDFREQUEST CurrentWriteRequest;\r\n\r\n    //\r\n    // Points to the request that is currently being processed to\r\n    // affect the wait mask operations.\r\n    //\r\n    WDFREQUEST CurrentMaskRequest;\r\n\r\n    //\r\n    // Points to the request that is currently being processed to\r\n    // purge the read/write queues and buffers.\r\n    //\r\n    WDFREQUEST CurrentPurgeRequest;\r\n\r\n    //\r\n    // Points to the current request that is waiting on a comm event.\r\n    //\r\n    WDFREQUEST CurrentWaitRequest;\r\n\r\n    //\r\n    // Points to the request that is being used to send an immediate\r\n    // character.\r\n    //\r\n    WDFREQUEST CurrentImmediateRequest;\r\n\r\n    //\r\n    // Points to the request that is being used to count the number\r\n    // of characters received after an xoff (as currently defined\r\n    // by the IOCTL_SERIAL_XOFF_COUNTER ioctl) is sent.\r\n    //\r\n    WDFREQUEST CurrentXoffRequest;\r\n\r\n    //\r\n    // The base address for the set of device registers\r\n    // of the serial port.\r\n    //\r\n    PUCHAR Controller;\r\n    //\r\n    // This value holds the span (in units of bytes) of the register\r\n    // set controlling this port.  This is constant over the life\r\n    // of the port.\r\n    //\r\n    ULONG SpanOfController;\r\n\r\n    //\r\n    // Address space\r\n    //\r\n\r\n    ULONG AddressSpace;\r\n\r\n    PREAD_PORT_UCHAR SerialReadUChar;\r\n    PWRITE_PORT_UCHAR SerialWriteUChar;\r\n\r\n    //\r\n    // Hold the clock rate input to the serial part.\r\n    //\r\n    ULONG ClockRate;\r\n\r\n    //\r\n    // The number of characters to push out if a fifo is present.\r\n    //\r\n    ULONG TxFifoAmount;\r\n\r\n    //\r\n    // Set to indicate that it is ok to share interrupts within the device.\r\n    //\r\n    ULONG PermitShare;\r\n\r\n\r\n    //\r\n    // Points to the interrupt object for used by this device.\r\n    //\r\n    WDFINTERRUPT WdfInterrupt;\r\n\r\n    //\r\n    // Translated vector\r\n    //\r\n    ULONG Vector;\r\n    //\r\n    // Translated Irql\r\n    //\r\n    KIRQL Irql;\r\n\r\n    KINTERRUPT_MODE     InterruptMode;\r\n\r\n    KAFFINITY           Affinity;\r\n\r\n    //\r\n    // This value is set by the read code to hold the time value\r\n    // used for read interval timing.  We keep it in the extension\r\n    // so that the interval timer dpc routine determine if the\r\n    // interval time has passed for the IO.\r\n    //\r\n    LARGE_INTEGER IntervalTime;\r\n\r\n    //\r\n    // These two values hold the \"constant\" time that we should use\r\n    // to delay for the read interval time.\r\n    //\r\n    LARGE_INTEGER ShortIntervalAmount;\r\n    LARGE_INTEGER LongIntervalAmount;\r\n\r\n    //\r\n    // This holds the value that we use to determine if we should use\r\n    // the long interval delay or the short interval delay.\r\n    //\r\n    LARGE_INTEGER CutOverAmount;\r\n\r\n    //\r\n    // This holds the system time when we last time we had\r\n    // checked that we had actually read characters.  Used\r\n    // for interval timing.\r\n    //\r\n    LARGE_INTEGER LastReadTime;\r\n\r\n\r\n    //\r\n    // This points the the delta time that we should use to\r\n    // delay for interval timing.\r\n    //\r\n    PLARGE_INTEGER IntervalTimeToUse;\r\n\r\n\r\n    //\r\n    // Set at intialization to indicate that on the current\r\n    // architecture we need to unmap the base register address\r\n    // when we unload the driver.\r\n    //\r\n    BOOLEAN UnMapRegisters;\r\n\r\n    //\r\n    // Holds the number of bytes remaining in the current write\r\n    // request.\r\n    //\r\n    // This location is only accessed while at interrupt level.\r\n    //\r\n    ULONG WriteLength;\r\n\r\n    //\r\n    // Holds a pointer to the current character to be sent in\r\n    // the current write.\r\n    //\r\n    // This location is only accessed while at interrupt level.\r\n    //\r\n    PUCHAR WriteCurrentChar;\r\n\r\n    //\r\n    // This is a buffer for the read processing.\r\n    //\r\n    // The buffer works as a ring.  When the character is read from\r\n    // the device it will be place at the end of the ring.\r\n    //\r\n    // Characters are only placed in this buffer at interrupt level\r\n    // although character may be read at any level. The pointers\r\n    // that manage this buffer may not be updated except at interrupt\r\n    // level.\r\n    //\r\n    PUCHAR InterruptReadBuffer;\r\n\r\n    //\r\n    // This is a pointer to the first character of the buffer into\r\n    // which the interrupt service routine is copying characters.\r\n    //\r\n    PUCHAR ReadBufferBase;\r\n\r\n    //\r\n    // This is a count of the number of characters in the interrupt\r\n    // buffer.  This value is set and read at interrupt level.  Note\r\n    // that this value is only *incremented* at interrupt level so\r\n    // it is safe to read it at any level.  When characters are\r\n    // copied out of the read buffer, this count is decremented by\r\n    // a routine that synchronizes with the ISR.\r\n    //\r\n    ULONG CharsInInterruptBuffer;\r\n\r\n    //\r\n    // Points to the first available position for a newly received\r\n    // character.  This variable is only accessed at interrupt level and\r\n    // buffer initialization code.\r\n    //\r\n    PUCHAR CurrentCharSlot;\r\n\r\n    //\r\n    // This variable is used to contain the last available position\r\n    // in the read buffer.  It is updated at open and at interrupt\r\n    // level when switching between the users buffer and the interrupt\r\n    // buffer.\r\n    //\r\n    PUCHAR LastCharSlot;\r\n\r\n    //\r\n    // This marks the first character that is available to satisfy\r\n    // a read request.  Note that while this always points to valid\r\n    // memory, it may not point to a character that can be sent to\r\n    // the user.  This can occur when the buffer is empty.\r\n    //\r\n    PUCHAR FirstReadableChar;\r\n\r\n    //\r\n    // Pointer to the lock variable returned for this extension when\r\n    // locking down the driver\r\n    //\r\n    PVOID LockPtr;\r\n\r\n\r\n    //\r\n    // This variable holds the size of whatever buffer we are currently\r\n    // using.\r\n    //\r\n    ULONG BufferSize;\r\n\r\n    //\r\n    // This variable holds .8 of BufferSize. We don't want to recalculate\r\n    // this real often - It's needed when so that an application can be\r\n    // \"notified\" that the buffer is getting full.\r\n    //\r\n    ULONG BufferSizePt8;\r\n\r\n    //\r\n    // This value holds the number of characters desired for a\r\n    // particular read.  It is initially set by read length in the\r\n    // WDFREQUEST.  It is decremented each time more characters are placed\r\n    // into the \"users\" buffer buy the code that reads characters\r\n    // out of the typeahead buffer into the users buffer.  If the\r\n    // typeahead buffer is exhausted by the read, and the reads buffer\r\n    // is given to the isr to fill, this value is becomes meaningless.\r\n    //\r\n    ULONG NumberNeededForRead;\r\n\r\n    //\r\n    // This mask will hold the bitmask sent down via the set mask\r\n    // ioctl.  It is used by the interrupt service routine to determine\r\n    // if the occurence of \"events\" (in the serial drivers understanding\r\n    // of the concept of an event) should be noted.\r\n    //\r\n    ULONG IsrWaitMask;\r\n\r\n    //\r\n    // This mask will always be a subset of the IsrWaitMask.  While\r\n    // at device level, if an event occurs that is \"marked\" as interesting\r\n    // in the IsrWaitMask, the driver will turn on that bit in this\r\n    // history mask.  The driver will then look to see if there is a\r\n    // request waiting for an event to occur.  If there is one, it\r\n    // will copy the value of the history mask into the wait request, zero\r\n    // the history mask, and complete the wait request.  If there is no\r\n    // waiting request, the driver will be satisfied with just recording\r\n    // that the event occured.  If a wait request should be queued,\r\n    // the driver will look to see if the history mask is non-zero.  If\r\n    // it is non-zero, the driver will copy the history mask into the\r\n    // request, zero the history mask, and then complete the request.\r\n    //\r\n    ULONG HistoryMask;\r\n\r\n    //\r\n    // This is a pointer to the where the history mask should be\r\n    // placed when completing a wait.  It is only accessed at\r\n    // device level.\r\n    //\r\n    // We have a pointer here to assist us to synchronize completing a wait.\r\n    // If this is non-zero, then we have wait outstanding, and the isr still\r\n    // knows about it.  We make this pointer null so that the isr won't\r\n    // attempt to complete the wait.\r\n    //\r\n    // We still keep a pointer around to the wait request, since the actual\r\n    // pointer to the wait request will be used for the \"common\" request completion\r\n    // path.\r\n    //\r\n    ULONG *IrpMaskLocation;\r\n\r\n    //\r\n    // This mask holds all of the reason that transmission\r\n    // is not proceeding.  Normal transmission can not occur\r\n    // if this is non-zero.\r\n    //\r\n    // This is only written from interrupt level.\r\n    // This could be (but is not) read at any level.\r\n    //\r\n    ULONG TXHolding;\r\n\r\n    //\r\n    // This mask holds all of the reason that reception\r\n    // is not proceeding.  Normal reception can not occur\r\n    // if this is non-zero.\r\n    //\r\n    // This is only written from interrupt level.\r\n    // This could be (but is not) read at any level.\r\n    //\r\n    ULONG RXHolding;\r\n\r\n    //\r\n    // This holds the reasons that the driver thinks it is in\r\n    // an error state.\r\n    //\r\n    // This is only written from interrupt level.\r\n    // This could be (but is not) read at any level.\r\n    //\r\n    ULONG ErrorWord;\r\n\r\n    //\r\n    // This keeps a total of the number of characters that\r\n    // are in all of the \"write\" irps that the driver knows\r\n    // about.  It is only accessed with the cancel spinlock\r\n    // held.\r\n    //\r\n    ULONG TotalCharsQueued;\r\n\r\n    //\r\n    // This holds a count of the number of characters read\r\n    // the last time the interval timer dpc fired.  It\r\n    // is a long (rather than a ulong) since the other read\r\n    // completion routines use negative values to indicate\r\n    // to the interval timer that it should complete the read\r\n    // if the interval timer DPC was lurking in some DPC queue when\r\n    // some other way to complete occurs.\r\n    //\r\n    LONG CountOnLastRead;\r\n\r\n    //\r\n    // This is a count of the number of characters read by the\r\n    // isr routine.  It is *ONLY* written at isr level.  We can\r\n    // read it at dispatch level.\r\n    //\r\n    ULONG ReadByIsr;\r\n\r\n    //\r\n    // This holds the current baud rate for the device.\r\n    //\r\n    ULONG CurrentBaud;\r\n\r\n    //\r\n    // This is the number of characters read since the XoffCounter\r\n    // was started.  This variable is only accessed at device level.\r\n    // If it is greater than zero, it implies that there is an\r\n    // XoffCounter ioctl in the queue.\r\n    //\r\n    LONG CountSinceXoff;\r\n\r\n    //\r\n    // This ulong is incremented each time something trys to start\r\n    // the execution path that tries to lower the RTS line when\r\n    // doing transmit toggling.  If it \"bumps\" into another path\r\n    // (indicated by a false return value from queueing a dpc\r\n    // and a TRUE return value tring to start a timer) it will\r\n    // decrement the count.  These increments and decrements\r\n    // are all done at device level.  Note that in the case\r\n    // of a bump while trying to start the timer, we have to\r\n    // go up to device level to do the decrement.\r\n    //\r\n    ULONG CountOfTryingToLowerRTS;\r\n\r\n    //\r\n    // This ULONG is used to keep track of the \"named\" (in ntddser.h)\r\n    // baud rates that this particular device supports.\r\n    //\r\n    ULONG SupportedBauds;\r\n\r\n    //\r\n    // Holds the timeout controls for the device.  This value\r\n    // is set by the Ioctl processing.\r\n    //\r\n    // It should only be accessed under protection of the control\r\n    // lock since more than one request can be in the control dispatch\r\n    // routine at one time.\r\n    //\r\n    SERIAL_TIMEOUTS Timeouts;\r\n\r\n    //\r\n    // This holds the various characters that are used\r\n    // for replacement on errors and also for flow control.\r\n    //\r\n    // They are only set at interrupt level.\r\n    //\r\n    SERIAL_CHARS SpecialChars;\r\n\r\n    //\r\n    // This structure holds the handshake and control flow\r\n    // settings for the serial driver.\r\n    //\r\n    // It is only set at interrupt level.  It can be\r\n    // be read at any level with the control lock held.\r\n    //\r\n    SERIAL_HANDFLOW HandFlow;\r\n\r\n\r\n    //\r\n    // Holds performance statistics that applications can query.\r\n    // Reset on each open.  Only set at device level.\r\n    //\r\n    SERIALPERF_STATS PerfStats;\r\n\r\n    //\r\n    // This holds what we beleive to be the current value of\r\n    // the line control register.\r\n    //\r\n    // It should only be accessed under protection of the control\r\n    // lock since more than one request can be in the control dispatch\r\n    // routine at one time.\r\n    //\r\n    UCHAR LineControl;\r\n\r\n\r\n    //\r\n    // This is only accessed at interrupt level.  It keeps track\r\n    // of whether the holding register is empty.\r\n    //\r\n    BOOLEAN HoldingEmpty;\r\n\r\n    //\r\n    // This variable is only accessed at interrupt level.  It\r\n    // indicates that we want to transmit a character immediately.\r\n    // That is - in front of any characters that could be transmitting\r\n    // from a normal write.\r\n    //\r\n    BOOLEAN TransmitImmediate;\r\n\r\n    //\r\n    // This variable is only accessed at interrupt level.  Whenever\r\n    // a wait is initiated this variable is set to false.\r\n    // Whenever any kind of character is written it is set to true.\r\n    // Whenever the write queue is found to be empty the code that\r\n    // is processing that completing request will synchonize with the interrupt.\r\n    // If this synchronization code finds that the variable is true and that\r\n    // there is a wait on the transmit queue being empty then it is\r\n    // certain that the queue was emptied and that it has happened since\r\n    // the wait was initiated.\r\n    //\r\n    BOOLEAN EmptiedTransmit;\r\n\r\n    //\r\n    // We keep the following values around so that we can connect\r\n    // to the interrupt and report resources after the configuration\r\n    // record is gone.\r\n    //\r\n\r\n    //\r\n    // We hold the character that should be transmitted immediately.\r\n    //\r\n    // Note that we can't use this to determine whether there is\r\n    // a character to send because the character to send could be\r\n    // zero.\r\n    //\r\n    UCHAR ImmediateChar;\r\n\r\n    //\r\n    // This holds the mask that will be used to mask off unwanted\r\n    // data bits of the received data (valid data bits can be 5,6,7,8)\r\n    // The mask will normally be 0xff.  This is set while the control\r\n    // lock is held since it wouldn't have adverse effects on the\r\n    // isr if it is changed in the middle of reading characters.\r\n    // (What it would do to the app is another question - but then\r\n    // the app asked the driver to do it.)\r\n    //\r\n    UCHAR ValidDataMask;\r\n\r\n    //\r\n    // The application can turn on a mode,via the\r\n    // IOCTL_SERIAL_LSRMST_INSERT ioctl, that will cause the\r\n    // serial driver to insert the line status or the modem\r\n    // status into the RX stream.  The parameter with the ioctl\r\n    // is a pointer to a UCHAR.  If the value of the UCHAR is\r\n    // zero, then no insertion will ever take place.  If the\r\n    // value of the UCHAR is non-zero (and not equal to the\r\n    // xon/xoff characters), then the serial driver will insert.\r\n    //\r\n    UCHAR EscapeChar;\r\n\r\n    //\r\n    // These two booleans are used to indicate to the isr transmit\r\n    // code that it should send the xon or xoff character.  They are\r\n    // only accessed at open and at interrupt level.\r\n    //\r\n    BOOLEAN SendXonChar;\r\n    BOOLEAN SendXoffChar;\r\n\r\n    //\r\n    // This boolean will be true if a 16550 is present *and* enabled.\r\n    //\r\n    BOOLEAN FifoPresent;\r\n\r\n    //\r\n    // This is the water mark that the rxfifo should be\r\n    // set to when the fifo is turned on.  This is not the actual\r\n    // value, but the encoded value that goes into the register.\r\n    //\r\n    UCHAR RxFifoTrigger;\r\n\r\n    //\r\n    // This points to a DPC used to complete write requests.\r\n    //\r\n    WDFDPC CompleteWriteDpc;\r\n\r\n    //\r\n    // This points to a DPC used to complete read requests.\r\n    //\r\n    WDFDPC CompleteReadDpc;\r\n\r\n\r\n    //\r\n    // This dpc is fired off if a comm error occurs.  It will\r\n    // execute a dpc routine that will cancel all pending reads\r\n    // and writes.\r\n    //\r\n    WDFDPC CommErrorDpc;\r\n\r\n    //\r\n    // This dpc is fired off if an event occurs and there was\r\n    // a request waiting on that event.  A dpc routine will execute\r\n    // that completes the request.\r\n    //\r\n    WDFDPC CommWaitDpc;\r\n\r\n    //\r\n    // This dpc is fired off when the transmit immediate char\r\n    // character is given to the hardware.  It will simply complete\r\n    // the request.\r\n    //\r\n    WDFDPC CompleteImmediateDpc;\r\n\r\n    //\r\n    // This dpc is fired off if the xoff counter actually runs down\r\n    // to zero.\r\n    //\r\n    WDFDPC XoffCountCompleteDpc;\r\n\r\n    //\r\n    // This dpc is fired off only from device level to start off\r\n    // a timer that will queue a dpc to check if the RTS line\r\n    // should be lowered when we are doing transmit toggling.\r\n    //\r\n    WDFDPC StartTimerLowerRTSDpc;\r\n\r\n    //\r\n    // This timer used to handle total read request timing.\r\n    //\r\n    WDFTIMER ReadRequestTotalTimer;\r\n\r\n    //\r\n    // This timer used to handle interval read request timing.\r\n    //\r\n    WDFTIMER ReadRequestIntervalTimer;\r\n\r\n    //\r\n    // This timer used to handle total write request timing.\r\n    //\r\n    WDFTIMER WriteRequestTotalTimer;\r\n\r\n    //\r\n    // This is timer structure used to handle total time request timing.\r\n    //\r\n    WDFTIMER ImmediateTotalTimer;\r\n\r\n    //\r\n    // This timer is used to timeout the xoff counter io.\r\n    //\r\n    WDFTIMER XoffCountTimer;\r\n\r\n    //\r\n    // This timer is used to invoke a dpc one character time\r\n    // after the timer is set.  That dpc will be used to check\r\n    // whether we should lower the RTS line if we are doing\r\n    // transmit toggling.\r\n    //\r\n    WDFTIMER LowerRTSTimer;\r\n\r\n    //\r\n    // WMI Information\r\n    //\r\n\r\n    //\r\n    // WMI Comm Data\r\n    //\r\n\r\n    SERIAL_WMI_COMM_DATA WmiCommData;\r\n\r\n    //\r\n    // WMI HW Data\r\n    //\r\n\r\n    SERIAL_WMI_HW_DATA WmiHwData;\r\n\r\n    //\r\n    // WMI Performance Data\r\n    //\r\n\r\n    SERIAL_WMI_PERF_DATA WmiPerfData;\r\n\r\n} SERIAL_DEVICE_EXTENSION,*PSERIAL_DEVICE_EXTENSION;\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SERIAL_DEVICE_EXTENSION,\r\n                                        SerialGetDeviceExtension)\r\n\r\n//\r\n// This is the scratch area for every request.\r\n// We will copy some of the frequently used information of the request\r\n// into our context area so that way we don't have to call WdfRequestGetParams\r\n// function everytime.\r\n//\r\ntypedef struct _REQUEST_CONTEXT {\r\n    ULONG_PTR Information;\r\n    NTSTATUS Status;\r\n    ULONG Length;\r\n    PVOID RefCount;\r\n    PVOID SystemBuffer;\r\n    UCHAR MajorFunction;\r\n    PFN_WDF_REQUEST_CANCEL CancelRoutine;\r\n    BOOLEAN Cancelled;\r\n    PVOID Type3InputBuffer;\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    ULONG IoctlCode;\r\n    BOOLEAN MarkCancelableOnResume;\r\n} REQUEST_CONTEXT, *PREQUEST_CONTEXT;\r\n\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT,\r\n                                        SerialGetRequestContext)\r\n\r\n\r\n//\r\n// This is the Interrupt context for the Serial device. This structure is used\r\n// for keeping track of whether the Interrupt is connected or not.\r\n//\r\ntypedef struct _SERIAL_INTERRUPT_CONTEXT {\r\n\r\n    //\r\n    // This boolean value indicates whether Interrupt is connected.\r\n    //\r\n    BOOLEAN IsInterruptConnected;\r\n\r\n    //\r\n    // This lock is used to synchronize the file close logic and\r\n    // the Surprise Removal logic. When a surprise remove happens,\r\n    // the device interrupts are disabled. When this occurs, the\r\n    // file close logic should not attempt to use the interrupt\r\n    // object.\r\n    //\r\n    WDFWAITLOCK InterruptStateLock;\r\n\r\n} SERIAL_INTERRUPT_CONTEXT, *PSERIAL_INTERRUPT_CONTEXT;\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SERIAL_INTERRUPT_CONTEXT,\r\n                                        SerialGetInterruptContext)\r\n\r\n\r\n#define SERIAL_FLAGS_CLEAR                  0x0L\r\n#define SERIAL_FLAGS_STARTED                0x1L\r\n#define SERIAL_FLAGS_STOPPED                0x2L\r\n#define SERIAL_FLAGS_BROKENHW               0x4L\r\n#define SERIAL_FLAGS_LEGACY_ENUMED          0x8L\r\n\r\n\r\n__inline\r\nUCHAR\r\nSerialReadPortUChar (\r\n    IN  UCHAR * x\r\n    )\r\n{\r\n    return READ_PORT_UCHAR (x);\r\n}\r\n__inline\r\nVOID\r\nSerialWritePortUChar (\r\n    IN  UCHAR * x,\r\n    IN  UCHAR   y\r\n    )\r\n{\r\n    WRITE_PORT_UCHAR (x,y);\r\n}\r\n\r\n__inline\r\nUCHAR\r\nSerialReadRegisterUChar (\r\n    IN  UCHAR * x\r\n    )\r\n{\r\n    return READ_REGISTER_UCHAR (x);\r\n}\r\n\r\n__inline\r\nVOID\r\nSerialWriteRegisterUChar (\r\n    IN  UCHAR * x,\r\n    IN  UCHAR   y\r\n    )\r\n{\r\n    WRITE_REGISTER_UCHAR (x,y);\r\n}\r\n\r\n\r\n\r\n//\r\n// Sets the divisor latch register.  The divisor latch register\r\n// is used to control the baud rate of the 8250.\r\n//\r\n// As with all of these routines it is assumed that it is called\r\n// at a safe point to access the hardware registers.  In addition\r\n// it also assumes that the data is correct.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// DesiredDivisor - The value to which the divisor latch register should\r\n//                  be set.\r\n//\r\n#define WRITE_DIVISOR_LATCH(Extension, BaseAddress,DesiredDivisor)           \\\r\ndo                                                                \\\r\n{                                                                 \\\r\n    PUCHAR Address = BaseAddress;                                 \\\r\n    SHORT Divisor = DesiredDivisor;                               \\\r\n    UCHAR LineControl;                                            \\\r\n    LineControl = Extension->SerialReadUChar(Address+LINE_CONTROL_REGISTER); \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+LINE_CONTROL_REGISTER,                            \\\r\n        (UCHAR)(LineControl | SERIAL_LCR_DLAB)                    \\\r\n        );                                                        \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+DIVISOR_LATCH_LSB,                                \\\r\n        (UCHAR)(Divisor & 0xff)                                   \\\r\n        );                                                        \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+DIVISOR_LATCH_MSB,                                \\\r\n        (UCHAR)((Divisor & 0xff00) >> 8)                          \\\r\n        );                                                        \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+LINE_CONTROL_REGISTER,                            \\\r\n        LineControl                                               \\\r\n        );                                                        \\\r\n} WHILE (0)\r\n\r\n//\r\n// Reads the divisor latch register.  The divisor latch register\r\n// is used to control the baud rate of the 8250.\r\n//\r\n// As with all of these routines it is assumed that it is called\r\n// at a safe point to access the hardware registers.  In addition\r\n// it also assumes that the data is correct.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// DesiredDivisor - A pointer to the 2 byte word which will contain\r\n//                  the value of the divisor.\r\n//\r\n#define READ_DIVISOR_LATCH(Extension, BaseAddress,PDesiredDivisor)           \\\r\ndo                                                                \\\r\n{                                                                 \\\r\n    PUCHAR Address = BaseAddress;                                 \\\r\n    PSHORT PDivisor = PDesiredDivisor;                            \\\r\n    UCHAR LineControl;                                            \\\r\n    UCHAR Lsb;                                                    \\\r\n    UCHAR Msb;                                                    \\\r\n    LineControl = Extension->SerialReadUChar(Address+LINE_CONTROL_REGISTER); \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+LINE_CONTROL_REGISTER,                            \\\r\n        (UCHAR)(LineControl | SERIAL_LCR_DLAB)                    \\\r\n        );                                                        \\\r\n    Lsb = Extension->SerialReadUChar(Address+DIVISOR_LATCH_LSB);             \\\r\n    Msb = Extension->SerialReadUChar(Address+DIVISOR_LATCH_MSB);             \\\r\n    *PDivisor = Lsb;                                              \\\r\n    *PDivisor = *PDivisor | (((USHORT)Msb) << 8);                 \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        Address+LINE_CONTROL_REGISTER,                            \\\r\n        LineControl                                               \\\r\n        );                                                        \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro reads the interrupt enable register.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n#define READ_INTERRUPT_ENABLE(Extension, BaseAddress)                     \\\r\n    (Extension->SerialReadUChar((BaseAddress)+INTERRUPT_ENABLE_REGISTER))\r\n\r\n//\r\n// This macro writes the interrupt enable register.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// Values - The values to write to the interrupt enable register.\r\n//\r\n#define WRITE_INTERRUPT_ENABLE(Extension, BaseAddress,Values)                \\\r\ndo                                                                \\\r\n{                                                                 \\\r\n    Extension->SerialWriteUChar(                                             \\\r\n        BaseAddress+INTERRUPT_ENABLE_REGISTER,                    \\\r\n        Values                                                    \\\r\n        );                                                        \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro disables all interrupts on the hardware.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define DISABLE_ALL_INTERRUPTS(Extension, BaseAddress)       \\\r\ndo                                                \\\r\n{                                                 \\\r\n    WRITE_INTERRUPT_ENABLE(Extension, BaseAddress,0);        \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro enables all interrupts on the hardware.\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define ENABLE_ALL_INTERRUPTS(Extension, BaseAddress)        \\\r\ndo                                                \\\r\n{                                                 \\\r\n                                                  \\\r\n    WRITE_INTERRUPT_ENABLE(                       \\\r\n        (Extension), (BaseAddress),                            \\\r\n        (UCHAR)(SERIAL_IER_RDA | SERIAL_IER_THR | \\\r\n                SERIAL_IER_RLS | SERIAL_IER_MS)   \\\r\n        );                                        \\\r\n                                                  \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro reads the interrupt identification register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// Note that this routine potententially quites a transmitter\r\n// empty interrupt.  This is because one way that the transmitter\r\n// empty interrupt is cleared is to simply read the interrupt id\r\n// register.\r\n//\r\n//\r\n#define READ_INTERRUPT_ID_REG(Extension, BaseAddress)                          \\\r\n    (Extension->SerialReadUChar((BaseAddress)+INTERRUPT_IDENT_REGISTER))\r\n\r\n//\r\n// This macro reads the modem control register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define READ_MODEM_CONTROL(Extension, BaseAddress)                          \\\r\n    (Extension->SerialReadUChar((BaseAddress)+MODEM_CONTROL_REGISTER))\r\n\r\n//\r\n// This macro reads the modem status register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define READ_MODEM_STATUS(Extension, BaseAddress)                          \\\r\n    (Extension->SerialReadUChar((BaseAddress)+MODEM_STATUS_REGISTER))\r\n\r\n//\r\n// This macro reads a value out of the receive buffer\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define READ_RECEIVE_BUFFER(Extension, BaseAddress)                          \\\r\n    (Extension->SerialReadUChar((BaseAddress)+RECEIVE_BUFFER_REGISTER))\r\n\r\n//\r\n// This macro reads the line status register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define READ_LINE_STATUS(Extension, BaseAddress)                          \\\r\n    (Extension->SerialReadUChar((BaseAddress)+LINE_STATUS_REGISTER))\r\n\r\n//\r\n// This macro writes the line control register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define WRITE_LINE_CONTROL(Extension, BaseAddress,NewLineControl)           \\\r\ndo                                                               \\\r\n{                                                                \\\r\n    Extension->SerialWriteUChar(                                            \\\r\n        (BaseAddress)+LINE_CONTROL_REGISTER,                     \\\r\n        (NewLineControl)                                         \\\r\n        );                                                       \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro reads the line control register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n//\r\n#define READ_LINE_CONTROL(Extension, BaseAddress)           \\\r\n    (Extension->SerialReadUChar((BaseAddress)+LINE_CONTROL_REGISTER))\r\n\r\n\r\n//\r\n// This macro writes to the transmit register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// TransmitChar - The character to send down the wire.\r\n//\r\n//\r\n#define WRITE_TRANSMIT_HOLDING(Extension, BaseAddress,TransmitChar)       \\\r\ndo                                                             \\\r\n{                                                              \\\r\n    Extension->SerialWriteUChar(                                          \\\r\n        (BaseAddress)+TRANSMIT_HOLDING_REGISTER,               \\\r\n        (TransmitChar)                                         \\\r\n        );                                                     \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro writes to the transmit FIFO register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// TransmitChars - Pointer to the characters to send down the wire.\r\n//\r\n// TxN - number of charactes to send.\r\n//\r\n//\r\n#define WRITE_TRANSMIT_FIFO_HOLDING(Extension, BaseAddress,TransmitChars,TxN)  \\\r\ndo                                                             \\\r\n{                                                              \\\r\n    WRITE_PORT_BUFFER_UCHAR(                                   \\\r\n        (BaseAddress)+TRANSMIT_HOLDING_REGISTER,               \\\r\n        (TransmitChars),                                       \\\r\n        (TxN)                                                  \\\r\n        );                                                     \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro writes to the control register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// ControlValue - The value to set the fifo control register too.\r\n//\r\n//\r\n#define WRITE_FIFO_CONTROL(Extension, BaseAddress,ControlValue)           \\\r\ndo                                                             \\\r\n{                                                              \\\r\n    Extension->SerialWriteUChar(                                          \\\r\n        (BaseAddress)+FIFO_CONTROL_REGISTER,                   \\\r\n        (ControlValue)                                         \\\r\n        );                                                     \\\r\n} WHILE (0)\r\n\r\n//\r\n// This macro writes to the modem control register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located.\r\n//\r\n// ModemControl - The control bits to send to the modem control.\r\n//\r\n//\r\n#define WRITE_MODEM_CONTROL(Extension, BaseAddress,ModemControl)          \\\r\ndo                                                             \\\r\n{                                                              \\\r\n    Extension->SerialWriteUChar(                                          \\\r\n        (BaseAddress)+MODEM_CONTROL_REGISTER,                  \\\r\n        (ModemControl)                                         \\\r\n        );                                                     \\\r\n} WHILE (0)\r\n\r\n#define WRITE_INTERRUPT_STATUS(Extension, BaseAddress,Status)  \\\r\ndo                                                               \\\r\n{                                                                \\\r\n       Extension->SerialWriteUChar(BaseAddress, Status);                    \\\r\n} WHILE (0)\r\n\r\n\r\n//\r\n// This macro reads the interrupt status register\r\n//\r\n// Arguments:\r\n//\r\n// BaseAddress - A pointer to the address from which the hardware\r\n//               device registers are located. BaseAddress is gotten\r\n//               from PSERIAL_MULTIPORT_DISPATCH->InterruptStatus which\r\n//               already has the complete address\r\n//\r\n// AddressSpace - Flag indicating where port is located, MMIO or IO\r\n//                space\r\n//\r\n//\r\n#define READ_INTERRUPT_STATUS(Extension, BaseAddress)  \\\r\n                      Extension->SerialReadUChar(BaseAddress))\r\n\r\n//\r\n// We use this to query into the registry as to whether we\r\n// should break at driver entry.\r\n//\r\n\r\nextern SERIAL_FIRMWARE_DATA    driverDefaults;\r\n\r\n\r\n//\r\n// This is exported from the kernel.  It is used to point\r\n// to the address that the kernel debugger is using.\r\n//\r\n\r\nextern PUCHAR *KdComPortInUse;\r\n\r\n\r\ntypedef enum _SERIAL_MEM_COMPARES {\r\n    AddressesAreEqual,\r\n    AddressesOverlap,\r\n    AddressesAreDisjoint\r\n    } SERIAL_MEM_COMPARES,*PSERIAL_MEM_COMPARES;\r\n\r\n#define SERIAL_BAUD_INVALID 0xFFFFFFFF\r\n\r\ntypedef struct   _SUPPORTED_BAUD_RATES {\r\n    UINT32 BaudRate;\r\n    ULONG Mask;\r\n}SUPPORTED_BAUD_RATES;\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/serial.rc",
    "content": "#include <windows.h>\r\n\r\n#include <ntverp.h>\r\n\r\n#define    VER_FILETYPE    VFT_DRV\r\n#define    VER_FILESUBTYPE    VFT2_DRV_SYSTEM\r\n#define VER_FILEDESCRIPTION_STR     \"Serial Device Driver\"\r\n#define VER_INTERNALNAME_STR        \"serial.sys\"\r\n#define VER_ORIGINALFILENAME_STR    \"serial.sys\"\r\n\r\n#include \"common.ver\"\r\n\r\n#include \"serlog.rc\"\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/serialp.h",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name :\r\n\r\n    serialp.h\r\n\r\nAbstract:\r\n\r\n    Prototypes and macros that are used throughout the driver.\r\n\r\n--*/\r\n\r\n//-----------------------------------------------------------------------------\r\n// 4127 -- Conditional Expression is Constant warning\r\n//-----------------------------------------------------------------------------\r\n#define WHILE(constant) \\\r\n__pragma(warning(suppress: 4127)) while(constant)\r\n\r\ntypedef\r\nVOID\r\n(*PSERIAL_START_ROUTINE) (\r\n    IN PSERIAL_DEVICE_EXTENSION\r\n    );\r\n\r\ntypedef\r\nVOID\r\n(*PSERIAL_GET_NEXT_ROUTINE) (\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    OUT WDFREQUEST *NewRequest,\r\n    IN BOOLEAN CompleteCurrent,\r\n    PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nDRIVER_INITIALIZE DriverEntry;\r\n\r\nEVT_WDF_DRIVER_DEVICE_ADD SerialEvtDeviceAdd;\r\nEVT_WDF_OBJECT_CONTEXT_CLEANUP SerialEvtDriverContextCleanup;\r\nEVT_WDF_DEVICE_CONTEXT_CLEANUP SerialEvtDeviceContextCleanup;\r\n\r\nEVT_WDF_DEVICE_D0_ENTRY SerialEvtDeviceD0Entry;\r\nEVT_WDF_DEVICE_D0_EXIT SerialEvtDeviceD0Exit;\r\nEVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED SerialEvtDeviceD0EntryPostInterruptsEnabled;\r\nEVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED SerialEvtDeviceD0ExitPreInterruptsDisabled;\r\nEVT_WDF_DEVICE_PREPARE_HARDWARE SerialEvtPrepareHardware;\r\nEVT_WDF_DEVICE_RELEASE_HARDWARE SerialEvtReleaseHardware;\r\n\r\nEVT_WDF_DEVICE_FILE_CREATE SerialEvtDeviceFileCreate;\r\nEVT_WDF_FILE_CLOSE SerialEvtFileClose;\r\n\r\nEVT_WDF_IO_QUEUE_IO_READ SerialEvtIoRead;\r\nEVT_WDF_IO_QUEUE_IO_WRITE SerialEvtIoWrite;\r\nEVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL SerialEvtIoDeviceControl;\r\nEVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL SerialEvtIoInternalDeviceControl;\r\nEVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE SerialEvtCanceledOnQueue;\r\nEVT_WDF_IO_QUEUE_IO_STOP SerialEvtIoStop;\r\nEVT_WDF_IO_QUEUE_IO_RESUME SerialEvtIoResume;\r\n\r\nEVT_WDF_INTERRUPT_ENABLE SerialEvtInterruptEnable;\r\nEVT_WDF_INTERRUPT_DISABLE SerialEvtInterruptDisable;\r\n\r\nEVT_WDF_DPC SerialCompleteRead;\r\nEVT_WDF_DPC SerialCompleteWrite;\r\nEVT_WDF_DPC SerialCommError;\r\nEVT_WDF_DPC SerialCompleteImmediate;\r\nEVT_WDF_DPC SerialCompleteXoff;\r\nEVT_WDF_DPC SerialCompleteWait;\r\nEVT_WDF_DPC SerialStartTimerLowerRTS;\r\n\r\nEVT_WDF_TIMER SerialReadTimeout;\r\nEVT_WDF_TIMER SerialIntervalReadTimeout;\r\nEVT_WDF_TIMER SerialWriteTimeout;\r\nEVT_WDF_TIMER SerialTimeoutImmediate;\r\nEVT_WDF_TIMER SerialTimeoutXoff;\r\nEVT_WDF_TIMER SerialInvokePerhapsLowerRTS;\r\n\r\nVOID\r\nSerialStartRead(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialStartWrite(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialStartMask(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialStartImmediate(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialStartPurge(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialGetNextWrite(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    IN WDFREQUEST *NewRequest,\r\n    IN BOOLEAN CompleteCurrent,\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nEVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialWdmDeviceFileCreate;\r\nEVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialWdmFileClose;\r\nEVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialFlush;\r\n\r\nEVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialQueryInformationFile;\r\nEVT_WDFDEVICE_WDM_IRP_PREPROCESS SerialSetInformationFile;\r\n\r\nNTSTATUS\r\nSerialDeviceFileCreateWorker (\r\n    IN WDFDEVICE Device\r\n    );\r\n\r\n\r\nVOID\r\nSerialFileCloseWorker(\r\n    IN WDFDEVICE Device\r\n    );\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialProcessEmptyTransmit;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetDTR;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialClrDTR;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetRTS;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialClrRTS;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetBaud;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetLineControl;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetHandFlow;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialTurnOnBreak;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialTurnOffBreak;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialPretendXoff;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialPretendXon;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialReset;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialPerhapsLowerRTS;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialMarkOpen;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialMarkClose;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetStats;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialClearStats;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetChars;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetMCRContents;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGetMCRContents;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialSetFCRContents;\r\n\r\nBOOLEAN\r\nSerialSetupNewHandFlow(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PSERIAL_HANDFLOW NewHandFlow\r\n    );\r\n\r\n\r\nVOID\r\nSerialHandleReducedIntBuffer(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialProdXonXoff(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN BOOLEAN SendXon\r\n    );\r\n\r\nEVT_WDF_REQUEST_CANCEL SerialCancelWait;\r\n\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialPurgeInterruptBuff;\r\n\r\nVOID\r\nSerialPurgeRequests(\r\n    IN WDFQUEUE QueueToClean,\r\n    IN WDFREQUEST *CurrentOpRequest\r\n    );\r\n\r\nVOID\r\nSerialFlushRequests(\r\n    IN WDFQUEUE QueueToClean,\r\n    IN WDFREQUEST *CurrentOpRequest\r\n    );\r\n\r\nVOID\r\nSerialGetNextRequest(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    OUT WDFREQUEST *NextIrp,\r\n    IN BOOLEAN CompleteCurrent,\r\n    IN PSERIAL_DEVICE_EXTENSION extension\r\n    );\r\n\r\n\r\nVOID\r\nSerialTryToCompleteCurrent(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PFN_WDF_INTERRUPT_SYNCHRONIZE  SynchRoutine OPTIONAL,\r\n    IN NTSTATUS StatusToUse,\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    IN WDFTIMER IntervalTimer,\r\n    IN WDFTIMER TotalTimer,\r\n    IN PSERIAL_START_ROUTINE Starter,\r\n    IN PSERIAL_GET_NEXT_ROUTINE GetNextIrp,\r\n    IN LONG RefType\r\n    );\r\n\r\nVOID\r\nSerialStartOrQueue(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN WDFREQUEST Request,\r\n    IN WDFQUEUE QueueToExamine,\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN PSERIAL_START_ROUTINE Starter\r\n    );\r\n\r\nNTSTATUS\r\nSerialCompleteIfError(\r\n    PSERIAL_DEVICE_EXTENSION extension,\r\n    WDFREQUEST Request\r\n    );\r\n\r\nULONG\r\nSerialHandleModemUpdate(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN BOOLEAN DoingTX\r\n    );\r\n\r\n\r\nEVT_WDF_INTERRUPT_ISR SerialISR;\r\n\r\nNTSTATUS\r\nSerialGetDivisorFromBaud(\r\n    IN ULONG ClockRate,\r\n    IN LONG DesiredBaud,\r\n    OUT PSHORT AppropriateDivisor\r\n    );\r\n\r\nVOID\r\nSerialCleanupDevice(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nUCHAR\r\nSerialProcessLSR(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nLARGE_INTEGER\r\nSerialGetCharTime(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\n\r\nVOID\r\nSerialPutChar(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN UCHAR CharToPut\r\n    );\r\n\r\nNTSTATUS\r\nSerialGetConfigDefaults(\r\n    IN PSERIAL_FIRMWARE_DATA DriverDefaultsPtr,\r\n    IN WDFDRIVER          Driver\r\n    );\r\n\r\nVOID\r\nSerialGetProperties(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PSERIAL_COMMPROP Properties\r\n    );\r\n\r\nVOID\r\nSerialLogError(\r\n    _In_                             PDRIVER_OBJECT DriverObject,\r\n    _In_opt_                         PDEVICE_OBJECT DeviceObject,\r\n    _In_                             PHYSICAL_ADDRESS P1,\r\n    _In_                             PHYSICAL_ADDRESS P2,\r\n    _In_                             ULONG SequenceNumber,\r\n    _In_                             UCHAR MajorFunctionCode,\r\n    _In_                             UCHAR RetryCount,\r\n    _In_                             ULONG UniqueErrorValue,\r\n    _In_                             NTSTATUS FinalStatus,\r\n    _In_                             NTSTATUS SpecificIOStatus,\r\n    _In_                             ULONG LengthOfInsert1,\r\n    _In_reads_bytes_opt_(LengthOfInsert1) PWCHAR Insert1,\r\n    _In_                             ULONG LengthOfInsert2,\r\n    _In_reads_bytes_opt_(LengthOfInsert2) PWCHAR Insert2\r\n    );\r\n\r\nNTSTATUS\r\nSerialMapHWResources(\r\n    IN WDFDEVICE Device,\r\n    IN WDFCMRESLIST PResList,\r\n    IN WDFCMRESLIST PTrResList,\r\n    OUT PCONFIG_DATA PConfig\r\n    );\r\n\r\nVOID\r\nSerialUnmapHWResources(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nBOOLEAN\r\nSerialGetRegistryKeyValue (\r\n    IN  WDFDEVICE  WdfDevice,\r\n    _In_  PCWSTR   Name,\r\n    OUT PULONG     Value\r\n    );\r\n\r\n\r\nBOOLEAN\r\nSerialPutRegistryKeyValue (\r\n    IN WDFDEVICE  WdfDevice,\r\n    _In_ PCWSTR   Name,\r\n    IN ULONG      Value\r\n    );\r\n\r\nNTSTATUS\r\nSerialInitController(\r\n    IN PSERIAL_DEVICE_EXTENSION pDevExt,\r\n    IN PCONFIG_DATA PConfigData\r\n    );\r\n\r\nBOOLEAN\r\nSerialCIsrSw(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN ULONG        MessageID\r\n    );\r\n\r\nNTSTATUS\r\nSerialDoExternalNaming(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nPVOID\r\nSerialGetMappedAddress(\r\n    PHYSICAL_ADDRESS IoAddress,\r\n    ULONG NumberOfBytes,\r\n    ULONG AddressSpace,\r\n    PBOOLEAN MappedAddress\r\n    );\r\n\r\nBOOLEAN\r\nSerialDoesPortExist(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    PUNICODE_STRING InsertString,\r\n    IN ULONG ForceFifo,\r\n    IN ULONG LogFifo\r\n    );\r\n\r\nSERIAL_MEM_COMPARES\r\nSerialMemCompare(\r\n    IN PHYSICAL_ADDRESS A,\r\n    IN ULONG SpanOfA,\r\n    IN PHYSICAL_ADDRESS B,\r\n    IN ULONG SpanOfB\r\n    );\r\n\r\nVOID\r\nSerialUndoExternalNaming(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    );\r\n\r\nVOID\r\nSerialReleaseResources(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nVOID\r\nSerialPurgePendingRequests(\r\n    PSERIAL_DEVICE_EXTENSION pDevExt\r\n    );\r\n\r\nVOID\r\nSerialDisableUART(\r\n    IN PVOID Context\r\n    );\r\n\r\nVOID\r\nSerialDrainUART(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    IN PLARGE_INTEGER PDrainTime\r\n    );\r\n\r\nVOID\r\nSerialSaveDeviceState(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nNTSTATUS\r\nSerialSetPowerPolicy(\r\n    IN PSERIAL_DEVICE_EXTENSION DeviceExtension\r\n    );\r\n\r\nUINT32\r\nSerialReportMaxBaudRate(\r\n    ULONG Bauds\r\n    );\r\n\r\nBOOLEAN\r\nSerialInsertQueueDpc(\r\n    IN WDFDPC Dpc\r\n    );\r\n\r\nBOOLEAN\r\nSerialSetTimer(\r\n    IN WDFTIMER Timer,\r\n    IN LARGE_INTEGER DueTime\r\n    );\r\n\r\nBOOLEAN\r\nSerialCancelTimer(\r\n    IN WDFTIMER Timer,\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nVOID\r\nSerialUnlockPages(\r\n    IN WDFDPC PDpc,\r\n    IN PVOID PDeferredContext,\r\n    IN PVOID PSysContext1,\r\n    IN PVOID PSysContext2)\r\n    ;\r\n\r\nVOID\r\nSerialMarkHardwareBroken(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nVOID\r\nSerialDisableInterfacesResources(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    IN BOOLEAN DisableUART\r\n    );\r\n\r\nVOID\r\nSerialSetDeviceFlags(\r\n    IN  PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    OUT PULONG PFlags,\r\n    IN  ULONG Value,\r\n    IN  BOOLEAN Set\r\n    );\r\n\r\n\r\nVOID\r\nSetDeviceIsOpened(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    IN BOOLEAN DeviceIsOpened,\r\n    IN BOOLEAN Reopen\r\n    );\r\n\r\nBOOLEAN\r\nIsQueueEmpty(\r\n    IN WDFQUEUE Queue\r\n    );\r\n\r\nNTSTATUS\r\nSerialCreateTimersAndDpcs(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nVOID\r\nSerialDrainTimersAndDpcs(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    );\r\n\r\nVOID\r\nSerialSetCancelRoutine(\r\n    IN WDFREQUEST Request,\r\n    IN PFN_WDF_REQUEST_CANCEL CancelRoutine\r\n    );\r\n\r\nNTSTATUS\r\nSerialClearCancelRoutine(\r\n    IN WDFREQUEST Request,\r\n    IN BOOLEAN ClearReference\r\n    );\r\n\r\nNTSTATUS\r\nSerialWmiRegistration(\r\n    WDFDEVICE      Device\r\n    );\r\n\r\nNTSTATUS\r\nSerialReadSymName(\r\n    IN                           WDFDEVICE Device,\r\n    _Out_writes_bytes_(*SizeOfRegName) PWSTR RegName,\r\n    _Inout_                      PUSHORT SizeOfRegName\r\n    );\r\n\r\nVOID\r\nSerialCompleteRequest(\r\n    IN WDFREQUEST    Request,\r\n    IN NTSTATUS      Status,\r\n    IN ULONG_PTR     Info\r\n    );\r\n\r\nBOOLEAN\r\nSerialGetFdoRegistryKeyValue(\r\n    IN PWDFDEVICE_INIT  DeviceInit,\r\n    _In_ PCWSTR         Name,\r\n    OUT PULONG          Value\r\n    );\r\n\r\nVOID\r\nSerialSetInterruptPolicy(\r\n   _In_ WDFINTERRUPT WdfInterrupt\r\n   );\r\n\r\ntypedef struct _SERIAL_UPDATE_CHAR {\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    ULONG CharsCopied;\r\n    BOOLEAN Completed;\r\n    } SERIAL_UPDATE_CHAR,*PSERIAL_UPDATE_CHAR;\r\n\r\n//\r\n// The following simple structure is used to send a pointer\r\n// the device extension and an ioctl specific pointer\r\n// to data.\r\n//\r\ntypedef struct _SERIAL_IOCTL_SYNC {\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    PVOID Data;\r\n    } SERIAL_IOCTL_SYNC,*PSERIAL_IOCTL_SYNC;\r\n\r\n\r\n//\r\n// The following three macros are used to initialize, set\r\n// and clear references in IRPs that are used by\r\n// this driver.  The reference is stored in the fourth\r\n// argument of the request, which is never used by any operation\r\n// accepted by this driver.\r\n//\r\n\r\n#define SERIAL_REF_ISR         (0x00000001)\r\n#define SERIAL_REF_CANCEL      (0x00000002)\r\n#define SERIAL_REF_TOTAL_TIMER (0x00000004)\r\n#define SERIAL_REF_INT_TIMER   (0x00000008)\r\n#define SERIAL_REF_XOFF_REF    (0x00000010)\r\n\r\n\r\n#define SERIAL_INIT_REFERENCE(ReqContext) { \\\r\n    (ReqContext)->RefCount = NULL; \\\r\n    }\r\n\r\n#define SERIAL_SET_REFERENCE(ReqContext, RefType) \\\r\n   do { \\\r\n       LONG _refType = (RefType); \\\r\n       PULONG_PTR _arg4 = (PVOID)&(ReqContext)->RefCount; \\\r\n       ASSERT(!(*_arg4 & _refType)); \\\r\n       *_arg4 |= _refType; \\\r\n   } WHILE (0)\r\n\r\n#define SERIAL_CLEAR_REFERENCE(ReqContext, RefType) \\\r\n   do { \\\r\n       LONG _refType = (RefType); \\\r\n       PULONG_PTR _arg4 = (PVOID)&(ReqContext)->RefCount; \\\r\n       ASSERT(*_arg4 & _refType); \\\r\n       *_arg4 &= ~_refType; \\\r\n   } WHILE (0)\r\n\r\n#define SERIAL_REFERENCE_COUNT(ReqContext) \\\r\n    ((ULONG_PTR)(((ReqContext)->RefCount)))\r\n\r\n#define SERIAL_TEST_REFERENCE(ReqContext, RefType) ((ULONG_PTR)ReqContext ->RefCount & RefType)\r\n\r\n//\r\n// Prototypes and defines to handle processor groups.\r\n//\r\ntypedef\r\nUSHORT\r\n(*PFN_KE_GET_ACTIVE_GROUP_COUNT)(\r\n    VOID\r\n    );\r\n\r\ntypedef\r\nKAFFINITY\r\n(*PFN_KE_QUERY_GROUP_AFFINITY) (\r\n    _In_ USHORT GroupNumber\r\n    );\r\n\r\n//\r\n// Force the serial interrupt to run on the last interrupt group.\r\n//\r\n//#define SERIAL_SELECT_INTERRUPT_GROUP       1\r\n#define SERIAL_LAST_INTERRUPT_GROUP         0xFFFF\r\n#define SERIAL_PREFERRED_INTERRUPT_GROUP    SERIAL_LAST_INTERRUPT_GROUP\r\n\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/serlog.mc",
    "content": ";/*++ BUILD Version: 0001    // Increment this if a change has global effects\n;\n;Copyright (c) 1992, 1993  Microsoft Corporation\n;\n;Module Name:\n;\n;    ntiologc.h\n;\n;Abstract:\n;\n;    Constant definitions for the I/O error code log values.\n;\n;--*/\n;\n;#ifndef _SERLOG_\n;#define _SERLOG_\n;\n;//\n;//  Status values are 32 bit values layed out as follows:\n;//\n;//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n;//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\n;//  +---+-+-------------------------+-------------------------------+\n;//  |Sev|C|       Facility          |               Code            |\n;//  +---+-+-------------------------+-------------------------------+\n;//\n;//  where\n;//\n;//      Sev - is the severity code\n;//\n;//          00 - Success\n;//          01 - Informational\n;//          10 - Warning\n;//          11 - Error\n;//\n;//      C - is the Customer code flag\n;//\n;//      Facility - is the facility code\n;//\n;//      Code - is the facility's status code\n;//\n;\nMessageIdTypedef=NTSTATUS\n\nSeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS\n               Informational=0x1:STATUS_SEVERITY_INFORMATIONAL\n               Warning=0x2:STATUS_SEVERITY_WARNING\n               Error=0x3:STATUS_SEVERITY_ERROR\n              )\n\nFacilityNames=(System=0x0\n               RpcRuntime=0x2:FACILITY_RPC_RUNTIME\n               RpcStubs=0x3:FACILITY_RPC_STUBS\n               Io=0x4:FACILITY_IO_ERROR_CODE\n               Serial=0x6:FACILITY_SERIAL_ERROR_CODE\n              )\n\n\nMessageId=0x0001 Facility=Serial Severity=Informational SymbolicName=SERIAL_KERNEL_DEBUGGER_ACTIVE\nLanguage=English\nThe kernel debugger is already using %2.\n.\n\nMessageId=0x0002 Facility=Serial Severity=Informational SymbolicName=SERIAL_FIFO_PRESENT\nLanguage=English\nWhile validating that %2 was really a serial port, a fifo was detected. The fifo will be used.\n.\n\nMessageId=0x0003 Facility=Serial Severity=Informational SymbolicName=SERIAL_USER_OVERRIDE\nLanguage=English\nUser configuration data for parameter %2 overriding firmware configuration data.\n.\n\nMessageId=0x0004 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_SYMLINK_CREATED\nLanguage=English\nUnable to create the symbolic link for %2.\n.\n\nMessageId=0x0005 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_DEVICE_MAP_CREATED\nLanguage=English\nUnable to create the device map entry for %2.\n.\n\nMessageId=0x0006 Facility=Serial Severity=Warning SymbolicName=SERIAL_NO_DEVICE_MAP_DELETED\nLanguage=English\nUnable to delete the device map entry for %2.\n.\n\nMessageId=0x0007 Facility=Serial Severity=Error SymbolicName=SERIAL_UNREPORTED_IRQL_CONFLICT\nLanguage=English\nAnother driver on the system, which did not report its resources, has already claimed the interrupt used by %2.\n.\n\nMessageId=0x0008 Facility=Serial Severity=Error SymbolicName=SERIAL_INSUFFICIENT_RESOURCES\nLanguage=English\nNot enough resources were available for the driver.\n.\n\nMessageId=0x0009 Facility=Serial Severity=Error SymbolicName=SERIAL_UNSUPPORTED_CLOCK_RATE\nLanguage=English\nThe baud clock rate configuration is not supported on device %2.\n.\n\nMessageId=0x000A Facility=Serial Severity=Error SymbolicName=SERIAL_REGISTERS_NOT_MAPPED\nLanguage=English\nThe hardware locations for %2 could not be translated to something the memory management system could understand.\n.\n\nMessageId=0x000B Facility=Serial Severity=Error SymbolicName=SERIAL_RESOURCE_CONFLICT\nLanguage=English\nThe hardware resources for %2 are already in use by another device.\n.\n\nMessageId=0x000C Facility=Serial Severity=Error SymbolicName=SERIAL_NO_BUFFER_ALLOCATED\nLanguage=English\nNo memory could be allocated in which to place new data for %2.\n.\n\nMessageId=0x000D Facility=Serial Severity=Error SymbolicName=SERIAL_IER_INVALID\nLanguage=English\nWhile validating that %2 was really a serial port, the interrupt enable register contained enabled bits in a must be zero bitfield.\nThe device is assumed not to be a serial port and will be deleted.\n.\n\nMessageId=0x000E Facility=Serial Severity=Error SymbolicName=SERIAL_MCR_INVALID\nLanguage=English\nWhile validating that %2 was really a serial port, the modem control register contained enabled bits in a must be zero bitfield.\nThe device is assumed not to be a serial port and will be deleted.\n.\n\nMessageId=0x000F Facility=Serial Severity=Error SymbolicName=SERIAL_IIR_INVALID\nLanguage=English\nWhile validating that %2 was really a serial port, the interrupt id register contained enabled bits in a must be zero bitfield.\nThe device is assumed not to be a serial port and will be deleted.\n.\n\nMessageId=0x0010 Facility=Serial Severity=Error SymbolicName=SERIAL_DL_INVALID\nLanguage=English\nWhile validating that %2 was really a serial port, the baud rate register could not be set consistantly.\nThe device is assumed not to be a serial port and will be deleted.\n.\n\nMessageId=0x0011 Facility=Serial Severity=Error SymbolicName=SERIAL_NOT_ENOUGH_CONFIG_INFO\nLanguage=English\nSome firmware configuration information was incomplete.\n.\n\nMessageId=0x0012 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_PARAMETERS_INFO\nLanguage=English\nNo Parameters subkey was found for user defined data.  This is odd, and it also means no user configuration can be found.\n.\n\nMessageId=0x0013 Facility=Serial Severity=Error SymbolicName=SERIAL_UNABLE_TO_ACCESS_CONFIG\nLanguage=English\nSpecific user configuration data is unretrievable.\n.\n\nMessageId=0x0014 Facility=Serial Severity=Error SymbolicName=SERIAL_INVALID_PORT_INDEX\nLanguage=English\nOn parameter %2 which indicates a multiport card, must have a port index specified greater than 0.\n.\n\nMessageId=0x0015 Facility=Serial Severity=Error SymbolicName=SERIAL_PORT_INDEX_TOO_HIGH\nLanguage=English\nOn parameter %2 which indicates a multiport card, the port index for the multiport card is too large.\n.\n\nMessageId=0x0016 Facility=Serial Severity=Error SymbolicName=SERIAL_UNKNOWN_BUS\nLanguage=English\nThe bus type for %2 is not recognizable.\n.\n\nMessageId=0x0017 Facility=Serial Severity=Error SymbolicName=SERIAL_BUS_NOT_PRESENT\nLanguage=English\nThe bus type for %2 is not available on this computer.\n.\n\nMessageId=0x0018 Facility=Serial Severity=Error SymbolicName=SERIAL_BUS_INTERRUPT_CONFLICT\nLanguage=English\nThe bus specified for %2 does not support the specified method of interrupt.\n.\n\nMessageId=0x0019 Facility=Serial Severity=Error SymbolicName=SERIAL_INVALID_USER_CONFIG\nLanguage=English\nUser configuration for parameter %2 must have %3.\n.\n\nMessageId=0x001A Facility=Serial Severity=Error SymbolicName=SERIAL_DEVICE_TOO_HIGH\nLanguage=English\nThe user specified port for %2 is way too high in physical memory.\n.\n\nMessageId=0x001B Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_TOO_HIGH\nLanguage=English\nThe status port for %2 is way too high in physical memory.\n.\n\nMessageId=0x001C Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_CONTROL_CONFLICT\nLanguage=English\nThe status port for %2 overlaps the control registers for the device.\n.\n\nMessageId=0x001D Facility=Serial Severity=Error SymbolicName=SERIAL_CONTROL_OVERLAP\nLanguage=English\nThe control registers for %2 overlaps with the %3 control registers.\n.\n\nMessageId=0x001E Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_OVERLAP\nLanguage=English\nThe status register for %2 overlaps the %3 control registers.\n.\n\nMessageId=0x001F Facility=Serial Severity=Error SymbolicName=SERIAL_STATUS_STATUS_OVERLAP\nLanguage=English\nThe status register for %2 overlaps with the %3 status register.\n.\n\nMessageId=0x0020 Facility=Serial Severity=Error SymbolicName=SERIAL_CONTROL_STATUS_OVERLAP\nLanguage=English\nThe control registers for %2 overlaps the %3 status register.\n.\n\nMessageId=0x0021 Facility=Serial Severity=Error SymbolicName=SERIAL_MULTI_INTERRUPT_CONFLICT\nLanguage=English\nTwo ports, %2 and %3, on a single multiport card can't have two different interrupts.\n.\n\nMessageId=0x0022 Facility=Serial Severity=Informational SymbolicName=SERIAL_DISABLED_PORT\nLanguage=English\nDisabling %2 as requested by the configuration data.\n.\n\nMessageId=0x0023 Facility=Serial Severity=Error SymbolicName=SERIAL_GARBLED_PARAMETER\nLanguage=English\nParameter %2 data is unretrievable from the registry.\n.\n\nMessageId=0x0024 Facility=Serial Severity=Error SymbolicName=SERIAL_DLAB_INVALID\nLanguage=English\nWhile validating that %2 was really a serial port, the contents of the divisor latch register was identical to the interrupt enable and the receive registers.\nThe device is assumed not to be a serial port and will be deleted.\n.\n\nMessageId=0x0025 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_TRANSLATE_PORT\nLanguage=English\nCould not translate the user reported I/O port for %2.\n.\n\nMessageId=0x0026 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_GET_INTERRUPT\nLanguage=English\nCould not get the user reported interrupt for %2 from the HAL.\n.\n\nMessageId=0x0027 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_TRANSLATE_ISR\nLanguage=English\nCould not translate the user reported Interrupt Status Register for %2.\n.\n\nMessageId=0x0028 Facility=Serial Severity=Error SymbolicName=SERIAL_NO_DEVICE_REPORT\nLanguage=English\nCould not report the discovered legacy device %2 to the IO subsystem.\n.\n\nMessageId=0x0029 Facility=Serial Severity=Error SymbolicName=SERIAL_REGISTRY_WRITE_FAILED\nLanguage=English\nError writing to the registry.\n.\n\nMessageId=0x002A Facility=Serial Severity=Warning SymbolicName=SERIAL_MOUSE_CONFLICT_IRQ\nLanguage=English\nThere is a serial mouse using the same interrupt as %2.  Therefore, %2 will not be started.\n.\n\nMessageId=0x002B Facility=Serial Severity=Warning SymbolicName=SERIAL_MOUSE_ON_PORT\nLanguage=English\nThere was a serial mouse found on %2.  Therefore, %2 will be assigned to the mouse.\n.\n\nMessageId=0x002C Facility=Serial Severity=Error SymbolicName=SERIAL_NO_DEVICE_REPORT_RES\nLanguage=English\nCould not report device %2 to IO subsystem due to a resource conflict.\n.\n\nMessageId=0x002D Facility=Serial Severity=Error SymbolicName=SERIAL_HARDWARE_FAILURE\nLanguage=English\nThe serial driver detected a hardware failure on device %2 and will disable this device.\n.\n\n;#endif /* _NTIOLOGC_ */\n\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/trace.h",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    TRACE.h\r\n\r\nAbstract:\r\n\r\n    Header file for the debug tracing related function defintions and macros.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include <evntrace.h> // For TRACE_LEVEL definitions\r\n\r\n#if !defined(EVENT_TRACING)\r\n\r\n//\r\n// TODO: These defines are missing in evntrace.h\r\n// in some DDK build environments (XP).\r\n//\r\n#if !defined(TRACE_LEVEL_NONE)\r\n  #define TRACE_LEVEL_NONE        0\r\n  #define TRACE_LEVEL_CRITICAL    1\r\n  #define TRACE_LEVEL_FATAL       1\r\n  #define TRACE_LEVEL_ERROR       2\r\n  #define TRACE_LEVEL_WARNING     3\r\n  #define TRACE_LEVEL_INFORMATION 4\r\n  #define TRACE_LEVEL_VERBOSE     5\r\n  #define TRACE_LEVEL_RESERVED6   6\r\n  #define TRACE_LEVEL_RESERVED7   7\r\n  #define TRACE_LEVEL_RESERVED8   8\r\n  #define TRACE_LEVEL_RESERVED9   9\r\n#endif\r\n\r\n\r\n//\r\n// Define Debug Flags\r\n//\r\n#define DBG_INIT                0x00000001\r\n#define DBG_PNP                 0x00000002\r\n#define DBG_POWER               0x00000004\r\n#define DBG_WMI                 0x00000008\r\n#define DBG_CREATE_CLOSE        0x00000010\r\n#define DBG_IOCTLS              0x00000020\r\n#define DBG_WRITE               0x00000040\r\n#define DBG_READ                0x00000080\r\n#define DBG_DPC                 0x00000100\r\n#define DBG_INTERRUPT           0x00000200\r\n#define DBG_LOCKS               0x00000400\r\n#define DBG_QUEUEING            0x00000800\r\n#define DBG_HW_ACCESS           0x00001000\r\n\r\nVOID\r\nTraceEvents    (\r\n    IN ULONG   DebugPrintLevel,\r\n    IN ULONG   DebugPrintFlag,\r\n    IN PCCHAR  DebugMessage,\r\n    ...\r\n    );\r\n\r\n#define WPP_INIT_TRACING(DriverObject, RegistryPath)\r\n#define WPP_CLEANUP(DriverObject)\r\n\r\n#else\r\n//\r\n// If software tracing is defined in the sources file..\r\n// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver.\r\n// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID ***\r\n// WPP_DEFINE_BIT allows setting debug bit masks to selectively print.\r\n// The names defined in the WPP_DEFINE_BIT call define the actual names\r\n// that are used to control the level of tracing for the control guid\r\n// specified.\r\n//\r\n// Name of the logger is Serial and the guid is\r\n//   {F3A79AB6-9827-4419-9465-45CF949EF659}\r\n//   (0xf3a79ab6, 0x9827, 0x4419, 0x94, 0x65, 0x45, 0xcf, 0x94, 0x9e, 0xf6, 0x59);\r\n//\r\n\r\n#define WPP_CHECK_FOR_NULL_STRING  //to prevent exceptions due to NULL strings\r\n\r\n#define WPP_CONTROL_GUIDS \\\r\n    WPP_DEFINE_CONTROL_GUID(SerialTraceGuid,(bc6c9364,fc67,42c5,acf7,abed3b12ecc6), \\\r\n        WPP_DEFINE_BIT(DBG_INIT)             /* bit  0 = 0x00000001 */ \\\r\n        WPP_DEFINE_BIT(DBG_PNP)              /* bit  1 = 0x00000002 */ \\\r\n        WPP_DEFINE_BIT(DBG_POWER)            /* bit  2 = 0x00000004 */ \\\r\n        WPP_DEFINE_BIT(DBG_WMI)              /* bit  3 = 0x00000008 */ \\\r\n        WPP_DEFINE_BIT(DBG_CREATE_CLOSE)     /* bit  4 = 0x00000010 */ \\\r\n        WPP_DEFINE_BIT(DBG_IOCTLS)           /* bit  5 = 0x00000020 */ \\\r\n        WPP_DEFINE_BIT(DBG_WRITE)            /* bit  6 = 0x00000040 */ \\\r\n        WPP_DEFINE_BIT(DBG_READ)             /* bit  7 = 0x00000080 */ \\\r\n        WPP_DEFINE_BIT(DBG_DPC)              /* bit  8 = 0x00000100 */ \\\r\n        WPP_DEFINE_BIT(DBG_INTERRUPT)        /* bit  9 = 0x00000200 */ \\\r\n        WPP_DEFINE_BIT(DBG_LOCKS)            /* bit 10 = 0x00000400 */ \\\r\n        WPP_DEFINE_BIT(DBG_QUEUEING)         /* bit 11 = 0x00000800 */ \\\r\n        WPP_DEFINE_BIT(DBG_HW_ACCESS)        /* bit 12 = 0x00001000 */ \\\r\n        /* You can have up to 32 defines. If you want more than that,\\\r\n           you have to provide another trace control GUID */\\\r\n        )\r\n\r\n\r\n#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)\r\n#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level  >= lvl)\r\n\r\n\r\n#endif\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/utils.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    utils.c\r\n\r\nAbstract:\r\n\r\n    This module contains code that perform queueing and completion\r\n    manipulation on requests.  Also module generic functions such\r\n    as error logging.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"utils.tmh\"\r\n#endif\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESRP0,SerialMemCompare)\r\n#pragma alloc_text(PAGESRP0,SerialLogError)\r\n#pragma alloc_text(PAGESRP0,SerialMarkHardwareBroken)\r\n#endif // ALLOC_PRAGMA\r\n\r\n\r\nVOID\r\nSerialRundownIrpRefs(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFTIMER IntervalTimer,\r\n    IN WDFTIMER TotalTimer,\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    IN LONG RefType\r\n    );\r\n\r\nstatic const PHYSICAL_ADDRESS SerialPhysicalZero = {0};\r\n\r\nVOID\r\nSerialPurgeRequests(\r\n    IN WDFQUEUE QueueToClean,\r\n    IN WDFREQUEST *CurrentOpRequest\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function is used to cancel all queued and the current irps\r\n    for reads or for writes. Called at DPC level.\r\n\r\nArguments:\r\n\r\n    QueueToClean - A pointer to the queue which we're going to clean out.\r\n\r\n    CurrentOpRequest - Pointer to a pointer to the current request.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    WdfIoQueuePurge(QueueToClean, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT);\r\n\r\n    //\r\n    // The queue is clean.  Now go after the current if\r\n    // it's there.\r\n    //\r\n\r\n    if (*CurrentOpRequest) {\r\n\r\n        PFN_WDF_REQUEST_CANCEL CancelRoutine;\r\n\r\n        reqContext = SerialGetRequestContext(*CurrentOpRequest);\r\n        CancelRoutine = reqContext->CancelRoutine;\r\n        //\r\n        // Clear the common cancel routine but don't clear the reference because the\r\n        // request specific cancel routine called below will clear the reference.\r\n        //\r\n        status = SerialClearCancelRoutine(*CurrentOpRequest, FALSE);\r\n        if (NT_SUCCESS(status)) {\r\n            //\r\n            // Let us just call the CancelRoutine to start the next request.\r\n            //\r\n            if(CancelRoutine) {\r\n                CancelRoutine(*CurrentOpRequest);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nVOID\r\nSerialFlushRequests(\r\n    IN WDFQUEUE QueueToClean,\r\n    IN WDFREQUEST *CurrentOpRequest\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function is used to cancel all queued and the current irps\r\n    for reads or for writes. Called at DPC level.\r\n\r\nArguments:\r\n\r\n    QueueToClean - A pointer to the queue which we're going to clean out.\r\n\r\n    CurrentOpRequest - Pointer to a pointer to the current request.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    SerialPurgeRequests(QueueToClean,  CurrentOpRequest);\r\n\r\n    //\r\n    // Since purge puts the queue state to fail requests, we have to explicitly\r\n    // change the queue state to accept requests.\r\n    //\r\n    WdfIoQueueStart(QueueToClean);\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialGetNextRequest(\r\n    IN WDFREQUEST               * CurrentOpRequest,\r\n    IN WDFQUEUE                   QueueToProcess,\r\n    OUT WDFREQUEST              * NextRequest,\r\n    IN BOOLEAN                    CompleteCurrent,\r\n    IN PSERIAL_DEVICE_EXTENSION   Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function is used to make the head of the particular\r\n    queue the current request.  It also completes the what\r\n    was the old current request if desired.\r\n\r\nArguments:\r\n\r\n    CurrentOpRequest - Pointer to a pointer to the currently active\r\n                   request for the particular work list.  Note that\r\n                   this item is not actually part of the list.\r\n\r\n    QueueToProcess - The list to pull the new item off of.\r\n\r\n    NextIrp - The next Request to process.  Note that CurrentOpRequest\r\n              will be set to this value under protection of the\r\n              cancel spin lock.  However, if *NextIrp is NULL when\r\n              this routine returns, it is not necessaryly true the\r\n              what is pointed to by CurrentOpRequest will also be NULL.\r\n              The reason for this is that if the queue is empty\r\n              when we hold the cancel spin lock, a new request may come\r\n              in immediately after we release the lock.\r\n\r\n    CompleteCurrent - If TRUE then this routine will complete the\r\n                      request pointed to by the pointer argument\r\n                      CurrentOpRequest.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    WDFREQUEST       oldRequest = NULL;\r\n    PREQUEST_CONTEXT reqContext;\r\n    NTSTATUS         status;\r\n\r\n    UNREFERENCED_PARAMETER(Extension);\r\n\r\n    oldRequest = *CurrentOpRequest;\r\n    *CurrentOpRequest = NULL;\r\n\r\n    //\r\n    // Check to see if there is a new request to start up.\r\n    //\r\n\r\n    status = WdfIoQueueRetrieveNextRequest(\r\n                 QueueToProcess,\r\n                 CurrentOpRequest\r\n                 );\r\n\r\n    if(!NT_SUCCESS(status)) {\r\n        ASSERTMSG(\"WdfIoQueueRetrieveNextRequest failed\",\r\n                  status == STATUS_NO_MORE_ENTRIES);\r\n    }\r\n\r\n    *NextRequest = *CurrentOpRequest;\r\n\r\n    if (CompleteCurrent) {\r\n\r\n        if (oldRequest) {\r\n\r\n            reqContext = SerialGetRequestContext(oldRequest);\r\n\r\n            SerialCompleteRequest(oldRequest,\r\n                                  reqContext->Status,\r\n                                  reqContext->Information);\r\n        }\r\n    }\r\n}\r\n\r\nVOID\r\nSerialTryToCompleteCurrent(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN PFN_WDF_INTERRUPT_SYNCHRONIZE  SynchRoutine OPTIONAL,\r\n    IN NTSTATUS StatusToUse,\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess OPTIONAL,\r\n    IN WDFTIMER IntervalTimer OPTIONAL,\r\n    IN WDFTIMER TotalTimer OPTIONAL,\r\n    IN PSERIAL_START_ROUTINE Starter OPTIONAL,\r\n    IN PSERIAL_GET_NEXT_ROUTINE GetNextRequest OPTIONAL,\r\n    IN LONG RefType\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine attempts to remove all of the reasons there are\r\n    references on the current read/write.  If everything can be completed\r\n    it will complete this read/write and try to start another.\r\n\r\n    NOTE: This routine assumes that it is called with the cancel\r\n          spinlock held.\r\n\r\nArguments:\r\n\r\n    Extension - Simply a pointer to the device extension.\r\n\r\n    SynchRoutine - A routine that will synchronize with the isr\r\n                   and attempt to remove the knowledge of the\r\n                   current request from the isr.  NOTE: This pointer\r\n                   can be null.\r\n\r\n    IrqlForRelease - This routine is called with the cancel spinlock held.\r\n                     This is the irql that was current when the cancel\r\n                     spinlock was acquired.\r\n\r\n    StatusToUse - The request's status field will be set to this value, if\r\n                  this routine can complete the request.\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    ASSERTMSG(\"SerialTryToCompleteCurrent: CurrentOpRequest is NULL\", *CurrentOpRequest);\r\n\r\n     reqContext = SerialGetRequestContext(*CurrentOpRequest);\r\n\r\n    if(RefType == SERIAL_REF_ISR || RefType == SERIAL_REF_XOFF_REF) {\r\n        //\r\n        // We can decrement the reference to \"remove\" the fact\r\n        // that the caller no longer will be accessing this request.\r\n        //\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            RefType\r\n            );\r\n    }\r\n\r\n    if (SynchRoutine) {\r\n\r\n        WdfInterruptSynchronize(\r\n            Extension->WdfInterrupt,\r\n            SynchRoutine,\r\n            Extension\r\n            );\r\n\r\n    }\r\n\r\n    //\r\n    // Try to run down all other references to this request.\r\n    //\r\n\r\n    SerialRundownIrpRefs(\r\n        CurrentOpRequest,\r\n        IntervalTimer,\r\n        TotalTimer,\r\n        Extension,\r\n        RefType\r\n        );\r\n\r\n    if(StatusToUse == STATUS_CANCELLED) {\r\n        //\r\n        // This function is called from a cancelroutine. So mark\r\n        // the request as cancelled. We need to do this because\r\n        // we may not complete the request below if somebody\r\n        // else has a reference to it.\r\n        // This state variable was added to avoid calling\r\n        // WdfRequestMarkCancelable second time on a request that\r\n        // has cancelled but wasn't completed in the cancel routine.\r\n        //\r\n        reqContext->Cancelled = TRUE;\r\n    }\r\n\r\n    //\r\n    // See if the ref count is zero after trying to complete everybody else.\r\n    //\r\n\r\n    if (!SERIAL_REFERENCE_COUNT(reqContext)) {\r\n\r\n        WDFREQUEST newRequest;\r\n\r\n\r\n        //\r\n        // The ref count was zero so we should complete this\r\n        // request.\r\n        //\r\n        // The following call will also cause the current request to be\r\n        // completed.\r\n        //\r\n\r\n        reqContext->Status = StatusToUse;\r\n\r\n        if (StatusToUse == STATUS_CANCELLED) {\r\n\r\n            reqContext->Information = 0;\r\n\r\n        }\r\n\r\n        if (GetNextRequest) {\r\n\r\n            GetNextRequest(\r\n                CurrentOpRequest,\r\n                QueueToProcess,\r\n                &newRequest,\r\n                TRUE,\r\n                Extension\r\n                );\r\n\r\n            if (newRequest) {\r\n\r\n                Starter(Extension);\r\n\r\n            }\r\n\r\n        } else {\r\n\r\n            WDFREQUEST oldRequest = *CurrentOpRequest;\r\n\r\n            //\r\n            // There was no get next routine.  We will simply complete\r\n            // the request.  We should make sure that we null out the\r\n            // pointer to the pointer to this request.\r\n            //\r\n\r\n            *CurrentOpRequest = NULL;\r\n\r\n            SerialCompleteRequest(oldRequest,\r\n                                  reqContext->Status,\r\n                                  reqContext->Information);\r\n        }\r\n\r\n    } else {\r\n\r\n\r\n    }\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialEvtIoStop(\r\n    IN WDFQUEUE                 Queue,\r\n    IN WDFREQUEST               Request,\r\n    IN ULONG                    ActionFlags\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n     This callback is invoked for every request pending in the driver (not queue) -\r\n     in-flight request. The Action parameter tells us why the callback is invoked -\r\n     because the device is being stopped, removed or suspended. In this\r\n     driver, we have told the framework not to stop or remove when there\r\n     are pending requests, so only reason for this callback is when the system is\r\n     suspending.\r\n\r\nArguments:\r\n\r\n    Queue - Queue the request currently belongs to\r\n    Request - Request that is currently out of queue and being processed by the driver\r\n    Action - Reason for this callback\r\n\r\nReturn Value:\r\n\r\n    None. Acknowledge the request so that framework can contiue suspending the\r\n    device.\r\n\r\n--*/\r\n{\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Queue);\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n                    \"--> SerialEvtIoStop %x %p\\n\", ActionFlags, Request);\r\n\r\n    //\r\n    // System suspends all the timers before asking the driver to goto\r\n    // sleep. So let us not worry about cancelling the timers. Also the\r\n    // framework will disconnect the interrupt before calling our\r\n    // D0Exit handler so we can be sure that nobody will touch the hardware.\r\n    // So just acknowledge callback to say that we are okay to stop due to\r\n    // system suspend. Please note that since we have taken a power reference\r\n    // we will never idle out when there is an open handle. Also we have told\r\n    // the framework to not stop for resource rebalancing or remove when there are\r\n    // open handles, so let us not worry about that either.\r\n    //\r\n    if (ActionFlags & WdfRequestStopRequestCancelable) {\r\n        PFN_WDF_REQUEST_CANCEL cancelRoutine;\r\n\r\n        //\r\n        // Request is in a cancelable state. So unmark cancelable before you\r\n        // acknowledge. We will mark the request cancelable when we resume.\r\n        //\r\n        cancelRoutine = reqContext->CancelRoutine;\r\n\r\n        SerialClearCancelRoutine(Request, TRUE);\r\n\r\n        //\r\n        // SerialClearCancelRoutine clears the cancel-routine. So set it back\r\n        // in the context. We will need that when we resume.\r\n        //\r\n        reqContext->CancelRoutine = cancelRoutine;\r\n\r\n        reqContext->MarkCancelableOnResume = TRUE;\r\n\r\n        ActionFlags &= ~WdfRequestStopRequestCancelable;\r\n    }\r\n\r\n    ASSERT(ActionFlags == WdfRequestStopActionSuspend);\r\n\r\n    WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue the request\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n                        \"<-- SerialEvtIoStop \\n\");\r\n}\r\n\r\nVOID\r\nSerialEvtIoResume(\r\n    IN WDFQUEUE   Queue,\r\n    IN WDFREQUEST Request\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n     This callback is invoked for every request pending in the driver - in-flight\r\n     request - to notify that the hardware is ready for contiuing the processing\r\n     of the request.\r\n\r\nArguments:\r\n\r\n    Queue - Queue the request currently belongs to\r\n    Request - Request that is currently out of queue and being processed by the driver\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n{\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Queue);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n            \"--> SerialEvtIoResume %p \\n\", Request);\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    //\r\n    // If we unmarked cancelable on suspend, let us mark it cancelable again.\r\n    //\r\n    if (reqContext->MarkCancelableOnResume) {\r\n        SerialSetCancelRoutine(Request, reqContext->CancelRoutine);\r\n        reqContext->MarkCancelableOnResume = FALSE;\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n        \"<-- SerialEvtIoResume \\n\");\r\n}\r\n\r\nVOID\r\nSerialRundownIrpRefs(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFTIMER IntervalTimer OPTIONAL,\r\n    IN WDFTIMER TotalTimer OPTIONAL,\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt,\r\n    IN LONG RefType\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine runs through the various items that *could*\r\n    have a reference to the current read/write.  It try's to remove\r\n    the reason.  If it does succeed in removing the reason it\r\n    will decrement the reference count on the request.\r\n\r\n    NOTE: This routine assumes that it is called with the cancel\r\n          spin lock held.\r\n\r\nArguments:\r\n\r\n    CurrentOpRequest - Pointer to a pointer to current request for the\r\n                   particular operation.\r\n\r\n    IntervalTimer - Pointer to the interval timer for the operation.\r\n                    NOTE: This could be null.\r\n\r\n    TotalTimer - Pointer to the total timer for the operation.\r\n                 NOTE: This could be null.\r\n\r\n    PDevExt - Pointer to device extension\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n\r\n{\r\n    PREQUEST_CONTEXT  reqContext;\r\n    WDFREQUEST        request = *CurrentOpRequest;\r\n\r\n    reqContext = SerialGetRequestContext(request);\r\n\r\n    if(RefType == SERIAL_REF_CANCEL) {\r\n        //\r\n        // Caller is a cancel routine. So just clear the reference.\r\n        //\r\n        SERIAL_CLEAR_REFERENCE( reqContext,  SERIAL_REF_CANCEL );\r\n        reqContext->CancelRoutine = NULL;\r\n\r\n    } else {\r\n        //\r\n        // Try to clear the cancelable state.\r\n        //\r\n        SerialClearCancelRoutine(request, TRUE);\r\n    }\r\n    if (IntervalTimer) {\r\n\r\n        //\r\n        // Try to cancel the operations interval timer.  If the operation\r\n        // returns true then the timer did have a reference to the\r\n        // request.  Since we've canceled this timer that reference is\r\n        // no longer valid and we can decrement the reference count.\r\n        //\r\n        // If the cancel returns false then this means either of two things:\r\n        //\r\n        // a) The timer has already fired.\r\n        //\r\n        // b) There never was an interval timer.\r\n        //\r\n        // In the case of \"b\" there is no need to decrement the reference\r\n        // count since the \"timer\" never had a reference to it.\r\n        //\r\n        // In the case of \"a\", then the timer itself will be coming\r\n        // along and decrement it's reference.  Note that the caller\r\n        // of this routine might actually be the this timer, so\r\n        // decrement the reference.\r\n        //\r\n\r\n        if (SerialCancelTimer(IntervalTimer, PDevExt)) {\r\n\r\n            SERIAL_CLEAR_REFERENCE(\r\n                reqContext,\r\n                SERIAL_REF_INT_TIMER\r\n                );\r\n\r\n        } else if(RefType == SERIAL_REF_INT_TIMER) { // caller is the timer\r\n\r\n            SERIAL_CLEAR_REFERENCE(\r\n                reqContext,\r\n                SERIAL_REF_INT_TIMER\r\n                );\r\n        }\r\n\r\n    }\r\n\r\n    if (TotalTimer) {\r\n\r\n        //\r\n        // Try to cancel the operations total timer.  If the operation\r\n        // returns true then the timer did have a reference to the\r\n        // request.  Since we've canceled this timer that reference is\r\n        // no longer valid and we can decrement the reference count.\r\n        //\r\n        // If the cancel returns false then this means either of two things:\r\n        //\r\n        // a) The timer has already fired.\r\n        //\r\n        // b) There never was an total timer.\r\n        //\r\n        // In the case of \"b\" there is no need to decrement the reference\r\n        // count since the \"timer\" never had a reference to it.\r\n        //\r\n        // In the case of \"a\", then the timer itself will be coming\r\n        // along and decrement it's reference.  Note that the caller\r\n        // of this routine might actually be the this timer, so\r\n        // decrement the reference.\r\n        //\r\n\r\n        if (SerialCancelTimer(TotalTimer, PDevExt)) {\r\n\r\n            SERIAL_CLEAR_REFERENCE(\r\n                reqContext,\r\n                SERIAL_REF_TOTAL_TIMER\r\n                );\r\n\r\n        } else if(RefType == SERIAL_REF_TOTAL_TIMER) { // caller is the timer\r\n\r\n            SERIAL_CLEAR_REFERENCE(\r\n                reqContext,\r\n                SERIAL_REF_TOTAL_TIMER\r\n                );\r\n        }\r\n    }\r\n}\r\n\r\n\r\nVOID\r\nSerialStartOrQueue(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension,\r\n    IN WDFREQUEST Request,\r\n    IN WDFQUEUE QueueToExamine,\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN PSERIAL_START_ROUTINE Starter\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to either start or queue any requst\r\n    that can be queued in the driver.\r\n\r\nArguments:\r\n\r\n    Extension - Points to the serial device extension.\r\n\r\n    Request - The request to either queue or start.  In either\r\n          case the request will be marked pending.\r\n\r\n    QueueToExamine - The queue the request will be place on if there\r\n                     is already an operation in progress.\r\n\r\n    CurrentOpRequest - Pointer to a pointer to the request the is current\r\n                   for the queue.  The pointer pointed to will be\r\n                   set with to Request if what CurrentOpRequest points to\r\n                   is NULL.\r\n\r\n    Starter - The routine to call if the queue is empty.\r\n\r\nReturn Value:\r\n\r\n\r\n--*/\r\n\r\n{\r\n\r\n    NTSTATUS status;\r\n    PREQUEST_CONTEXT reqContext;\r\n    WDF_REQUEST_PARAMETERS  params;\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n    WdfRequestGetParameters(\r\n             Request,\r\n             &params);\r\n\r\n    //\r\n    // If this is a write request then take the amount of characters\r\n    // to write and add it to the count of characters to write.\r\n    //\r\n\r\n    if (params.Type == WdfRequestTypeWrite) {\r\n\r\n        Extension->TotalCharsQueued += reqContext->Length;\r\n\r\n    } else if ((params.Type == WdfRequestTypeDeviceControl) &&\r\n               ((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) ||\r\n                (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) {\r\n\r\n        reqContext->IoctlCode = params.Parameters.DeviceIoControl.IoControlCode; // We need this in the destroy callback\r\n\r\n        Extension->TotalCharsQueued++;\r\n\r\n    }\r\n\r\n    if (IsQueueEmpty(QueueToExamine) &&  !(*CurrentOpRequest)) {\r\n\r\n        //\r\n        // There were no current operation.  Mark this one as\r\n        // current and start it up.\r\n        //\r\n\r\n        *CurrentOpRequest = Request;\r\n\r\n        Starter(Extension);\r\n\r\n        return;\r\n\r\n    } else {\r\n\r\n        //\r\n        // We don't know how long the request will be in the\r\n        // queue.  If it gets cancelled while waiting in the queue, we will\r\n        // be notified by EvtCanceledOnQueue callback so that we can readjust\r\n        // the lenght or free the buffer.\r\n        //\r\n        reqContext->Extension = Extension; // We need this in the destroy callback\r\n\r\n        status = WdfRequestForwardToIoQueue(Request,  QueueToExamine);\r\n        if(!NT_SUCCESS(status)) {\r\n            SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_READ, \"WdfRequestForwardToIoQueue failed%X\\n\", status);\r\n            ASSERTMSG(\"WdfRequestForwardToIoQueue failed \", FALSE);\r\n            SerialCompleteRequest(Request, status, 0);\r\n        }\r\n\r\n        return;\r\n    }\r\n}\r\n\r\nVOID\r\nSerialEvtCanceledOnQueue(\r\n    IN WDFQUEUE   Queue,\r\n    IN WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Called when the request is cancelled while it's waiting\r\n    on the queue. This callback is used instead of EvtCleanupCallback\r\n    on the request because this one will be called with the\r\n    presentation lock held.\r\n\r\n\r\nArguments:\r\n\r\n    Queue - Queue in which the request currently waiting\r\n    Request - Request being cancelled\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION extension = NULL;\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Queue);\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    extension = reqContext->Extension;\r\n\r\n    //\r\n    // If this is a write request then take the amount of characters\r\n    // to write and subtract it from the count of characters to write.\r\n    //\r\n\r\n    if (reqContext->MajorFunction == IRP_MJ_WRITE) {\r\n\r\n        extension->TotalCharsQueued -= reqContext->Length;\r\n\r\n    } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {\r\n\r\n        //\r\n        // If it's an immediate then we need to decrement the\r\n        // count of chars queued.  If it's a resize then we\r\n        // need to deallocate the pool that we're passing on\r\n        // to the \"resizing\" routine.\r\n        //\r\n\r\n        if (( reqContext->IoctlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) ||\r\n            (reqContext->IoctlCode ==  IOCTL_SERIAL_XOFF_COUNTER)) {\r\n\r\n            extension->TotalCharsQueued--;\r\n\r\n        } else if (reqContext->IoctlCode ==  IOCTL_SERIAL_SET_QUEUE_SIZE) {\r\n\r\n            //\r\n            // We shoved the pointer to the memory into the\r\n            // the type 3 buffer pointer which we KNOW we\r\n            // never use.\r\n            //\r\n\r\n            ASSERT(reqContext->Type3InputBuffer);\r\n\r\n            ExFreePool(reqContext->Type3InputBuffer);\r\n\r\n            reqContext->Type3InputBuffer = NULL;\r\n\r\n        }\r\n\r\n    }\r\n\r\n    SerialCompleteRequest(Request, WdfRequestGetStatus(Request), 0);\r\n}\r\n\r\n\r\nNTSTATUS\r\nSerialCompleteIfError(\r\n    PSERIAL_DEVICE_EXTENSION extension,\r\n    WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    If the current request is not an IOCTL_SERIAL_GET_COMMSTATUS request and\r\n    there is an error and the application requested abort on errors,\r\n    then cancel the request.\r\n\r\nArguments:\r\n\r\n    extension - Pointer to the device context\r\n\r\n    Request - Pointer to the WDFREQUEST to test.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or STATUS_CANCELLED.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    WDF_REQUEST_PARAMETERS  params;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    if ((extension->HandFlow.ControlHandShake &\r\n         SERIAL_ERROR_ABORT) && extension->ErrorWord) {\r\n\r\n        WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n        WdfRequestGetParameters(\r\n            Request,\r\n            &params\r\n            );\r\n\r\n\r\n        //\r\n        // There is a current error in the driver.  No requests should\r\n        // come through except for the GET_COMMSTATUS.\r\n        //\r\n\r\n        if ((params.Type != WdfRequestTypeDeviceControl) ||\r\n                    (params.Parameters.DeviceIoControl.IoControlCode !=  IOCTL_SERIAL_GET_COMMSTATUS)) {\r\n            status = STATUS_CANCELLED;\r\n            SerialCompleteRequest(Request, status, 0);\r\n        }\r\n\r\n    }\r\n\r\n    return status;\r\n\r\n}\r\n\r\nNTSTATUS\r\nSerialCreateTimersAndDpcs(\r\n    IN PSERIAL_DEVICE_EXTENSION pDevExt\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This function creates all the timers and DPC objects. All the objects\r\n   are associated with the WDFDEVICE and the callbacks are serialized\r\n   with the device callbacks. Also these objects will be deleted automatically\r\n   when the device is deleted, so there is no need for the driver to explicitly\r\n   delete the objects.\r\n\r\nArguments:\r\n\r\n   PDevExt - Pointer to the device extension for the device\r\n\r\nReturn Value:\r\n\r\n    return NTSTATUS\r\n\r\n--*/\r\n{\r\n   WDF_DPC_CONFIG dpcConfig;\r\n   WDF_TIMER_CONFIG timerConfig;\r\n   NTSTATUS status;\r\n   WDF_OBJECT_ATTRIBUTES dpcAttributes;\r\n   WDF_OBJECT_ATTRIBUTES timerAttributes;\r\n\r\n   //\r\n   // Initialize all the timers used to timeout operations.\r\n   //\r\n   //\r\n   // This timer dpc is fired off if the timer for the total timeout\r\n   // for the read expires.  It will cause the current read to complete.\r\n   //\r\n\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig, SerialReadTimeout);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                           &timerAttributes,\r\n                                    &pDevExt->ReadRequestTotalTimer);\r\n\r\n   if (!NT_SUCCESS(status)) {\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(ReadRequestTotalTimer) failed  [%#08lx]\\n\",   status);\r\n      return status;\r\n   }\r\n\r\n   //\r\n   // This dpc is fired off if the timer for the interval timeout\r\n   // expires.  If no more characters have been read then the\r\n   // dpc routine will cause the read to complete.  However, if\r\n   // more characters have been read then the dpc routine will\r\n   // resubmit the timer.\r\n   //\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig,   SerialIntervalReadTimeout);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                           &timerAttributes,\r\n                                        &pDevExt->ReadRequestIntervalTimer);\r\n\r\n   if (!NT_SUCCESS(status)) {\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(ReadRequestIntervalTimer) failed  [%#08lx]\\n\",   status);\r\n      return status;\r\n   }\r\n\r\n   //\r\n   // This dpc is fired off if the timer for the total timeout\r\n   // for the write expires.  It will queue a dpc routine that\r\n   // will cause the current write to complete.\r\n   //\r\n   //\r\n\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig,    SerialWriteTimeout);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                                &timerAttributes,\r\n                                &pDevExt->WriteRequestTotalTimer);\r\n\r\n   if (!NT_SUCCESS(status)) {\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(WriteRequestTotalTimer) failed  [%#08lx]\\n\",   status);\r\n      return status;\r\n   }\r\n\r\n   //\r\n   // This dpc is fired off if the transmit immediate char\r\n   // character times out.  The dpc routine will \"grab\" the\r\n   // request from the isr and time it out.\r\n   //\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig,   SerialTimeoutImmediate);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                           &timerAttributes,\r\n                                        &pDevExt->ImmediateTotalTimer);\r\n\r\n   if (!NT_SUCCESS(status)) {\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(ImmediateTotalTimer) failed  [%#08lx]\\n\",   status);\r\n      return status;\r\n   }\r\n\r\n   //\r\n   // This dpc is fired off if the timer used to \"timeout\" counting\r\n   // the number of characters received after the Xoff ioctl is started\r\n   // expired.\r\n   //\r\n\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig,   SerialTimeoutXoff);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                                    &timerAttributes,\r\n                                    &pDevExt->XoffCountTimer);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n      SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(XoffCountTimer) failed  [%#08lx]\\n\",   status);\r\n      return status;\r\n   }\r\n\r\n   //\r\n   // This dpc is fired off when a timer expires (after one\r\n   // character time), so that code can be invoked that will\r\n   // check to see if we should lower the RTS line when\r\n   // doing transmit toggling.\r\n   //\r\n   WDF_TIMER_CONFIG_INIT(&timerConfig,  SerialInvokePerhapsLowerRTS);\r\n\r\n   timerConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n   timerAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfTimerCreate(&timerConfig,\r\n                           &timerAttributes,\r\n                                    &pDevExt->LowerRTSTimer);\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfTimerCreate(LowerRTSTimer) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // Create a DPC to complete read requests.\r\n    //\r\n\r\n   WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteWrite);\r\n\r\n   dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n   dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfDpcCreate(&dpcConfig,\r\n                                    &dpcAttributes,\r\n                                    &pDevExt->CompleteWriteDpc);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(CompleteWriteDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n\r\n    //\r\n    // Create a DPC to complete read requests.\r\n    //\r\n\r\n    WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteRead);\r\n\r\n    dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n    dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n    status = WdfDpcCreate(&dpcConfig,\r\n                                &dpcAttributes,\r\n                                &pDevExt->CompleteReadDpc);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(CompleteReadDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // This dpc is fired off if a comm error occurs.  It will\r\n    // cancel all pending reads and writes.\r\n    //\r\n    WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCommError);\r\n\r\n    dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n    dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n    status = WdfDpcCreate(&dpcConfig,\r\n                                &dpcAttributes,\r\n                                &pDevExt->CommErrorDpc);\r\n\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(CommErrorDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // This dpc is fired off when the transmit immediate char\r\n    // character is given to the hardware.  It will simply complete\r\n    // the request.\r\n    //\r\n\r\n   WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteImmediate);\r\n\r\n   dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n   WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n   dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n   status = WdfDpcCreate(&dpcConfig,\r\n                                    &dpcAttributes,\r\n                                    &pDevExt->CompleteImmediateDpc);\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(CompleteImmediateDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // This dpc is fired off if an event occurs and there was\r\n    // a request waiting on that event.  A dpc routine will execute\r\n    // that completes the request.\r\n    //\r\n    WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteWait);\r\n\r\n    dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n    dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n    status = WdfDpcCreate(&dpcConfig,\r\n                                &dpcAttributes,\r\n                                &pDevExt->CommWaitDpc);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(CommWaitDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    //\r\n    // This dpc is fired off if the xoff counter actually runs down\r\n    // to zero.\r\n    //\r\n    WDF_DPC_CONFIG_INIT(&dpcConfig, SerialCompleteXoff);\r\n\r\n    dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n    dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n    status = WdfDpcCreate(&dpcConfig,\r\n                                &dpcAttributes,\r\n                                &pDevExt->XoffCountCompleteDpc);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(XoffCountCompleteDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n\r\n    //\r\n    // This dpc is fired off only from device level to start off\r\n    // a timer that will queue a dpc to check if the RTS line\r\n    // should be lowered when we are doing transmit toggling.\r\n    //\r\n    WDF_DPC_CONFIG_INIT(&dpcConfig, SerialStartTimerLowerRTS);\r\n\r\n    dpcConfig.AutomaticSerialization = TRUE;\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&dpcAttributes);\r\n    dpcAttributes.ParentObject = pDevExt->WdfDevice;\r\n\r\n    status = WdfDpcCreate(&dpcConfig,\r\n                                &dpcAttributes,\r\n                                &pDevExt->StartTimerLowerRTSDpc);\r\n    if (!NT_SUCCESS(status)) {\r\n        SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_PNP,  \"WdfDpcCreate(StartTimerLowerRTSDpc) failed  [%#08lx]\\n\",   status);\r\n        return status;\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialInsertQueueDpc(IN WDFDPC PDpc)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This function must be called to queue DPC's for the serial driver.\r\n\r\nArguments:\r\n\r\n   PDpc - Pointer to the Dpc object\r\n\r\nReturn Value:\r\n\r\n   Kicks up return value from KeInsertQueueDpc()\r\n\r\n--*/\r\n{\r\n    //\r\n    // If the specified DPC object is not currently in the queue, WdfDpcEnqueue\r\n    // queues the DPC and returns TRUE.\r\n    //\r\n\r\n    return WdfDpcEnqueue(PDpc);\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialSetTimer(IN WDFTIMER Timer, IN LARGE_INTEGER DueTime)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This function must be called to set timers for the serial driver.\r\n\r\nArguments:\r\n\r\n   Timer - pointer to timer dispatcher object\r\n\r\n   DueTime - time at which the timer should expire\r\n\r\n\r\nReturn Value:\r\n\r\n   Kicks up return value from KeSetTimerEx()\r\n\r\n--*/\r\n{\r\n    BOOLEAN result;\r\n    //\r\n    // If the timer object was already in the system timer queue, WdfTimerStart returns TRUE\r\n    //\r\n    result = WdfTimerStart(Timer, DueTime.QuadPart);\r\n\r\n    return result;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialDrainTimersAndDpcs(\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This function cancels all the timers and Dpcs and waits for them\r\n   to run to completion if they are already fired.\r\n\r\nArguments:\r\n\r\n   PDevExt - Pointer to the device extension for the device that needs to\r\n             set a timer\r\n\r\nReturn Value:\r\n\r\n--*/\r\n{\r\n    WdfTimerStop(PDevExt->ReadRequestTotalTimer, TRUE);\r\n\r\n    WdfTimerStop(PDevExt->ReadRequestIntervalTimer, TRUE);\r\n\r\n    WdfTimerStop(PDevExt->WriteRequestTotalTimer, TRUE);\r\n\r\n    WdfTimerStop(PDevExt->ImmediateTotalTimer, TRUE);\r\n\r\n    WdfTimerStop(PDevExt->XoffCountTimer, TRUE);\r\n\r\n    WdfTimerStop(PDevExt->LowerRTSTimer, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->CompleteWriteDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->CompleteReadDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->CommErrorDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->CompleteImmediateDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->CommWaitDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->XoffCountCompleteDpc, TRUE);\r\n\r\n    WdfDpcCancel(PDevExt->StartTimerLowerRTSDpc, TRUE);\r\n\r\n    return;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nSerialCancelTimer(\r\n    IN WDFTIMER                 Timer,\r\n    IN PSERIAL_DEVICE_EXTENSION PDevExt\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   This function must be called to cancel timers for the serial driver.\r\n\r\nArguments:\r\n\r\n   Timer - pointer to timer dispatcher object\r\n\r\n   PDevExt - Pointer to the device extension for the device that needs to\r\n             set a timer\r\n\r\nReturn Value:\r\n\r\n   True if timer was cancelled\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(PDevExt);\r\n\r\n    return WdfTimerStop(Timer, FALSE);\r\n}\r\n\r\nSERIAL_MEM_COMPARES\r\nSerialMemCompare(\r\n                IN PHYSICAL_ADDRESS A,\r\n                IN ULONG SpanOfA,\r\n                IN PHYSICAL_ADDRESS B,\r\n                IN ULONG SpanOfB\r\n                )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Compare two phsical address.\r\n\r\nArguments:\r\n\r\n    A - One half of the comparison.\r\n\r\n    SpanOfA - In units of bytes, the span of A.\r\n\r\n    B - One half of the comparison.\r\n\r\n    SpanOfB - In units of bytes, the span of B.\r\n\r\n\r\nReturn Value:\r\n\r\n    The result of the comparison.\r\n\r\n--*/\r\n{\r\n   LARGE_INTEGER a;\r\n   LARGE_INTEGER b;\r\n\r\n   LARGE_INTEGER lower;\r\n   ULONG lowerSpan;\r\n   LARGE_INTEGER higher;\r\n\r\n   PAGED_CODE();\r\n\r\n   a = A;\r\n   b = B;\r\n\r\n   if (a.QuadPart == b.QuadPart) {\r\n\r\n      return AddressesAreEqual;\r\n\r\n   }\r\n\r\n   if (a.QuadPart > b.QuadPart) {\r\n\r\n      higher = a;\r\n      lower = b;\r\n      lowerSpan = SpanOfB;\r\n\r\n   } else {\r\n\r\n      higher = b;\r\n      lower = a;\r\n      lowerSpan = SpanOfA;\r\n\r\n   }\r\n\r\n   if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {\r\n\r\n      return AddressesAreDisjoint;\r\n\r\n   }\r\n\r\n   return AddressesOverlap;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialLogError(\r\n    _In_                             PDRIVER_OBJECT DriverObject,\r\n    _In_opt_                         PDEVICE_OBJECT DeviceObject,\r\n    _In_                             PHYSICAL_ADDRESS P1,\r\n    _In_                             PHYSICAL_ADDRESS P2,\r\n    _In_                             ULONG SequenceNumber,\r\n    _In_                             UCHAR MajorFunctionCode,\r\n    _In_                             UCHAR RetryCount,\r\n    _In_                             ULONG UniqueErrorValue,\r\n    _In_                             NTSTATUS FinalStatus,\r\n    _In_                             NTSTATUS SpecificIOStatus,\r\n    _In_                             ULONG LengthOfInsert1,\r\n    _In_reads_bytes_opt_(LengthOfInsert1) PWCHAR Insert1,\r\n    _In_                             ULONG LengthOfInsert2,\r\n    _In_reads_bytes_opt_(LengthOfInsert2) PWCHAR Insert2\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine allocates an error log entry, copies the supplied data\r\n    to it, and requests that it be written to the error log file.\r\n\r\nArguments:\r\n\r\n    DriverObject - A pointer to the driver object for the device.\r\n\r\n    DeviceObject - A pointer to the device object associated with the\r\n    device that had the error, early in initialization, one may not\r\n    yet exist.\r\n\r\n    P1,P2 - If phyical addresses for the controller ports involved\r\n    with the error are available, put them through as dump data.\r\n\r\n    SequenceNumber - A ulong value that is unique to an WDFREQUEST over the\r\n    life of the request in this driver - 0 generally means an error not\r\n    associated with an request.\r\n\r\n    MajorFunctionCode - If there is an error associated with the request,\r\n    this is the major function code of that request.\r\n\r\n    RetryCount - The number of times a particular operation has been\r\n    retried.\r\n\r\n    UniqueErrorValue - A unique long word that identifies the particular\r\n    call to this function.\r\n\r\n    FinalStatus - The final status given to the request that was associated\r\n    with this error.  If this log entry is being made during one of\r\n    the retries this value will be STATUS_SUCCESS.\r\n\r\n    SpecificIOStatus - The IO status for a particular error.\r\n\r\n    LengthOfInsert1 - The length in bytes (including the terminating NULL)\r\n                      of the first insertion string.\r\n\r\n    Insert1 - The first insertion string.\r\n\r\n    LengthOfInsert2 - The length in bytes (including the terminating NULL)\r\n                      of the second insertion string.  NOTE, there must\r\n                      be a first insertion string for their to be\r\n                      a second insertion string.\r\n\r\n    Insert2 - The second insertion string.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n   PIO_ERROR_LOG_PACKET errorLogEntry;\r\n\r\n   PVOID objectToUse;\r\n   SHORT dumpToAllocate = 0;\r\n   PUCHAR ptrToFirstInsert;\r\n   PUCHAR ptrToSecondInsert;\r\n\r\n   PAGED_CODE();\r\n\r\n   if (Insert1 == NULL) {\r\n      LengthOfInsert1 = 0;\r\n   }\r\n\r\n   if (Insert2 == NULL) {\r\n      LengthOfInsert2 = 0;\r\n   }\r\n\r\n\r\n   if (ARGUMENT_PRESENT(DeviceObject)) {\r\n\r\n      objectToUse = DeviceObject;\r\n\r\n   } else {\r\n\r\n      objectToUse = DriverObject;\r\n\r\n   }\r\n\r\n   if (SerialMemCompare(\r\n                       P1,\r\n                       (ULONG)1,\r\n                       SerialPhysicalZero,\r\n                       (ULONG)1\r\n                       ) != AddressesAreEqual) {\r\n\r\n      dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);\r\n\r\n   }\r\n\r\n   if (SerialMemCompare(\r\n                       P2,\r\n                       (ULONG)1,\r\n                       SerialPhysicalZero,\r\n                       (ULONG)1\r\n                       ) != AddressesAreEqual) {\r\n\r\n      dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);\r\n\r\n   }\r\n\r\n   errorLogEntry = IoAllocateErrorLogEntry(\r\n                                          objectToUse,\r\n                                          (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +\r\n                                                  dumpToAllocate\r\n                                                  + LengthOfInsert1 +\r\n                                                  LengthOfInsert2)\r\n                                          );\r\n\r\n   if ( errorLogEntry != NULL ) {\r\n\r\n      errorLogEntry->ErrorCode = SpecificIOStatus;\r\n      errorLogEntry->SequenceNumber = SequenceNumber;\r\n      errorLogEntry->MajorFunctionCode = MajorFunctionCode;\r\n      errorLogEntry->RetryCount = RetryCount;\r\n      errorLogEntry->UniqueErrorValue = UniqueErrorValue;\r\n      errorLogEntry->FinalStatus = FinalStatus;\r\n      errorLogEntry->DumpDataSize = dumpToAllocate;\r\n\r\n      if (dumpToAllocate) {\r\n\r\n         RtlCopyMemory(\r\n                      &errorLogEntry->DumpData[0],\r\n                      &P1,\r\n                      sizeof(PHYSICAL_ADDRESS)\r\n                      );\r\n\r\n         if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {\r\n\r\n            RtlCopyMemory(\r\n                         ((PUCHAR)&errorLogEntry->DumpData[0])\r\n                         +sizeof(PHYSICAL_ADDRESS),\r\n                         &P2,\r\n                         sizeof(PHYSICAL_ADDRESS)\r\n                         );\r\n\r\n            ptrToFirstInsert =\r\n            ((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS));\r\n\r\n         } else {\r\n\r\n            ptrToFirstInsert =\r\n            ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS);\r\n\r\n\r\n         }\r\n\r\n      } else {\r\n\r\n         ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];\r\n\r\n      }\r\n\r\n      ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;\r\n\r\n      if (LengthOfInsert1) {\r\n\r\n         errorLogEntry->NumberOfStrings = 1;\r\n         errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -\r\n                                                (PUCHAR)errorLogEntry);\r\n         RtlCopyMemory(\r\n                      ptrToFirstInsert,\r\n                      Insert1,\r\n                      LengthOfInsert1\r\n                      );\r\n\r\n         if (LengthOfInsert2) {\r\n\r\n            errorLogEntry->NumberOfStrings = 2;\r\n            RtlCopyMemory(\r\n                         ptrToSecondInsert,\r\n                         Insert2,\r\n                         LengthOfInsert2\r\n                         );\r\n\r\n         }\r\n\r\n      }\r\n\r\n      IoWriteErrorLogEntry(errorLogEntry);\r\n\r\n   }\r\n\r\n}\r\n\r\nVOID\r\nSerialMarkHardwareBroken(IN PSERIAL_DEVICE_EXTENSION PDevExt)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n   Marks a UART as broken.  This causes the driver stack to stop accepting\r\n   requests and eventually be removed.\r\n\r\nArguments:\r\n   PDevExt - Device extension attached to PDevObj\r\n\r\nReturn Value:\r\n\r\n   None.\r\n\r\n--*/\r\n{\r\n   PAGED_CODE();\r\n\r\n   //\r\n   // Write a log entry\r\n   //\r\n\r\n   SerialLogError(PDevExt->DriverObject, NULL, SerialPhysicalZero,\r\n                  SerialPhysicalZero, 0, 0, 0, 88, STATUS_SUCCESS,\r\n                  SERIAL_HARDWARE_FAILURE, PDevExt->DeviceName.Length\r\n                  + sizeof(WCHAR), PDevExt->DeviceName.Buffer, 0, NULL);\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_ERROR, DBG_INIT, \"Device is broken. Request a restart...\\n\");\r\n   WdfDeviceSetFailed(PDevExt->WdfDevice, WdfDeviceFailedAttemptRestart);\r\n}\r\n\r\nNTSTATUS\r\nSerialGetDivisorFromBaud(\r\n                        IN ULONG ClockRate,\r\n                        IN LONG DesiredBaud,\r\n                        OUT PSHORT AppropriateDivisor\r\n                        )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will determine a divisor based on an unvalidated\r\n    baud rate.\r\n\r\nArguments:\r\n\r\n    ClockRate - The clock input to the controller.\r\n\r\n    DesiredBaud - The baud rate for whose divisor we seek.\r\n\r\n    AppropriateDivisor - Given that the DesiredBaud is valid, the\r\n    LONG pointed to by this parameter will be set to the appropriate\r\n    value.  NOTE: The long is undefined if the DesiredBaud is not\r\n    supported.\r\n\r\nReturn Value:\r\n\r\n    This function will return STATUS_SUCCESS if the baud is supported.\r\n    If the value is not supported it will return a status such that\r\n    NT_ERROR(Status) == FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n   NTSTATUS status = STATUS_SUCCESS;\r\n   SHORT calculatedDivisor;\r\n   ULONG denominator;\r\n   ULONG remainder;\r\n\r\n   //\r\n   // Allow up to a 1 percent error\r\n   //\r\n\r\n   ULONG maxRemain18 = 18432;\r\n   ULONG maxRemain30 = 30720;\r\n   ULONG maxRemain42 = 42336;\r\n   ULONG maxRemain80 = 80000;\r\n   ULONG maxRemain;\r\n\r\n\r\n\r\n   //\r\n   // Reject any non-positive bauds.\r\n   //\r\n\r\n   denominator = DesiredBaud*(ULONG)16;\r\n\r\n   if (DesiredBaud <= 0) {\r\n\r\n      *AppropriateDivisor = -1;\r\n\r\n   } else if ((LONG)denominator < DesiredBaud) {\r\n\r\n      //\r\n      // If the desired baud was so huge that it cause the denominator\r\n      // calculation to wrap, don't support it.\r\n      //\r\n\r\n      *AppropriateDivisor = -1;\r\n\r\n   } else {\r\n\r\n      if (ClockRate == 1843200) {\r\n         maxRemain = maxRemain18;\r\n      } else if (ClockRate == 3072000) {\r\n         maxRemain = maxRemain30;\r\n      } else if (ClockRate == 4233600) {\r\n         maxRemain = maxRemain42;\r\n      } else {\r\n         maxRemain = maxRemain80;\r\n      }\r\n\r\n      calculatedDivisor = (SHORT)(ClockRate / denominator);\r\n      remainder = ClockRate % denominator;\r\n\r\n      //\r\n      // Round up.\r\n      //\r\n\r\n      if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) {\r\n\r\n         calculatedDivisor++;\r\n      }\r\n\r\n\r\n      //\r\n      // Only let the remainder calculations effect us if\r\n      // the baud rate is > 9600.\r\n      //\r\n\r\n      if (DesiredBaud >= 9600) {\r\n\r\n         //\r\n         // If the remainder is less than the maximum remainder (wrt\r\n         // the ClockRate) or the remainder + the maximum remainder is\r\n         // greater than or equal to the ClockRate then assume that the\r\n         // baud is ok.\r\n         //\r\n\r\n         if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) {\r\n            calculatedDivisor = -1;\r\n         }\r\n\r\n      }\r\n\r\n      //\r\n      // Don't support a baud that causes the denominator to\r\n      // be larger than the clock.\r\n      //\r\n\r\n      if (denominator > ClockRate) {\r\n\r\n         calculatedDivisor = -1;\r\n\r\n      }\r\n\r\n      //\r\n      // Ok, Now do some special casing so that things can actually continue\r\n      // working on all platforms.\r\n      //\r\n\r\n      if (ClockRate == 1843200) {\r\n\r\n         if (DesiredBaud == 56000) {\r\n            calculatedDivisor = 2;\r\n         }\r\n\r\n      } else if (ClockRate == 3072000) {\r\n\r\n         if (DesiredBaud == 14400) {\r\n            calculatedDivisor = 13;\r\n         }\r\n\r\n      } else if (ClockRate == 4233600) {\r\n\r\n         if (DesiredBaud == 9600) {\r\n            calculatedDivisor = 28;\r\n         } else if (DesiredBaud == 14400) {\r\n            calculatedDivisor = 18;\r\n         } else if (DesiredBaud == 19200) {\r\n            calculatedDivisor = 14;\r\n         } else if (DesiredBaud == 38400) {\r\n            calculatedDivisor = 7;\r\n         } else if (DesiredBaud == 56000) {\r\n            calculatedDivisor = 5;\r\n         }\r\n\r\n      } else if (ClockRate == 8000000) {\r\n\r\n         if (DesiredBaud == 14400) {\r\n            calculatedDivisor = 35;\r\n         } else if (DesiredBaud == 56000) {\r\n            calculatedDivisor = 9;\r\n         }\r\n\r\n      }\r\n\r\n      *AppropriateDivisor = calculatedDivisor;\r\n\r\n   }\r\n\r\n\r\n   if (*AppropriateDivisor == -1) {\r\n\r\n      status = STATUS_INVALID_PARAMETER;\r\n\r\n   }\r\n\r\n   return status;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nIsQueueEmpty(\r\n    IN WDFQUEUE Queue\r\n    )\r\n{\r\n    WDF_IO_QUEUE_STATE queueStatus;\r\n\r\n    queueStatus = WdfIoQueueGetState( Queue, NULL, NULL );\r\n\r\n    return (WDF_IO_QUEUE_IDLE(queueStatus)) ? TRUE : FALSE;\r\n}\r\n\r\nVOID\r\nSerialSetCancelRoutine(\r\n    IN WDFREQUEST Request,\r\n    IN PFN_WDF_REQUEST_CANCEL CancelRoutine)\r\n{\r\n    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Request);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                        \"-->SerialSetCancelRoutine %p \\n\",  Request);\r\n\r\n    WdfRequestMarkCancelable(Request, CancelRoutine);\r\n    SERIAL_SET_REFERENCE(reqContext, SERIAL_REF_CANCEL);\r\n    reqContext->CancelRoutine = CancelRoutine;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                        \"<-- SerialSetCancelRoutine \\n\");\r\n\r\n    return;\r\n}\r\n\r\nNTSTATUS\r\nSerialClearCancelRoutine(\r\n    IN WDFREQUEST Request,\r\n    IN BOOLEAN    ClearReference\r\n    )\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PREQUEST_CONTEXT reqContext = SerialGetRequestContext(Request);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"-->SerialClearCancelRoutine %p %x\\n\",\r\n                     Request, ClearReference);\r\n\r\n    if(SERIAL_TEST_REFERENCE(reqContext,  SERIAL_REF_CANCEL))\r\n    {\r\n        status = WdfRequestUnmarkCancelable(Request);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            reqContext->CancelRoutine = NULL;\r\n            if(ClearReference) {\r\n\r\n               SERIAL_CLEAR_REFERENCE( reqContext,  SERIAL_REF_CANCEL );\r\n\r\n              }\r\n        } else {\r\n             ASSERT(status == STATUS_CANCELLED);\r\n        }\r\n    }\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                        \"-->SerialClearCancelRoutine %p\\n\",  Request);\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nSerialCompleteRequest(\r\n    IN WDFREQUEST   Request,\r\n    IN NTSTATUS     Status,\r\n    IN ULONG_PTR    Info\r\n    )\r\n{\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    reqContext = SerialGetRequestContext(Request);\r\n\r\n    ASSERT(reqContext->RefCount == 0);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_VERBOSE, DBG_PNP,\r\n                     \"Complete Request: %p %X 0x%I64x\\n\",\r\n                     (Request), (Status), (Info));\r\n\r\n    WdfRequestCompleteWithInformation((Request), (Status), (Info));\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/waitmask.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    waitmask.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to get/set/wait\r\n    on event mask operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"waitmask.tmh\"\r\n#endif\r\n\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabWaitFromIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveWaitToIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialFinishOldWait;\r\n\r\n\r\nVOID\r\nSerialStartMask(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to process the set mask and wait\r\n    mask ioctls.  Calls to this routine are serialized by\r\n    placing irps in the list under the protection of the\r\n    cancel spin lock.\r\n\r\nArguments:\r\n\r\n    Extension - A pointer to the serial device extension.\r\n\r\nReturn Value:\r\n\r\n    Will return pending for everything put the first\r\n    request that we actually process.  Even in that\r\n    case it will return pending unless it can complete\r\n    it right away.\r\n\r\n\r\n--*/\r\n\r\n{\r\n\r\n\r\n    WDFREQUEST NewRequest;\r\n    PREQUEST_CONTEXT reqContext;\r\n    WDF_REQUEST_PARAMETERS  params;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"In SerialStartMask\\n\");\r\n\r\n    ASSERT(Extension->CurrentMaskRequest);\r\n\r\n\r\n    do {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                         \"STARTMASK - CurrentMaskRequest: %p\\n\",\r\n                         Extension->CurrentMaskRequest);\r\n\r\n        WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n        WdfRequestGetParameters(\r\n                 Extension->CurrentMaskRequest,\r\n                 &params\r\n                 );\r\n\r\n\r\n         reqContext = SerialGetRequestContext(Extension->CurrentMaskRequest);\r\n\r\n        ASSERT((params.Parameters.DeviceIoControl.IoControlCode ==\r\n                IOCTL_SERIAL_WAIT_ON_MASK) ||\r\n               (params.Parameters.DeviceIoControl.IoControlCode ==\r\n                IOCTL_SERIAL_SET_WAIT_MASK));\r\n\r\n        if (params.Parameters.DeviceIoControl.IoControlCode ==\r\n                                    IOCTL_SERIAL_SET_WAIT_MASK) {\r\n\r\n            SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                             \"SERIAL - %p is a SETMASK request\\n\",\r\n                             Extension->CurrentMaskRequest);\r\n\r\n            //\r\n            // Complete the old wait if there is one.\r\n            //\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialFinishOldWait,\r\n                Extension\r\n                );\r\n\r\n            //\r\n            // Any current waits should be on its way to completion\r\n            // at this point.  There certainly shouldn't be any\r\n            // request mask location.\r\n            //\r\n\r\n            ASSERT(!Extension->IrpMaskLocation);\r\n\r\n            reqContext->Status = STATUS_SUCCESS;\r\n\r\n            //\r\n            // The following call will also cause the current\r\n            // call to be completed.\r\n            //\r\n\r\n            SerialGetNextRequest(\r\n                &Extension->CurrentMaskRequest,\r\n                Extension->MaskQueue,\r\n                &NewRequest,\r\n                TRUE,\r\n                Extension\r\n                );\r\n            SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                             \"Perhaps another mask request was found in \"\r\n                             \"the queue\\n\"\r\n                             \"------- %p/%p <- values should be the same\\n\",\r\n                             Extension->CurrentMaskRequest, NewRequest);\r\n\r\n\r\n        } else {\r\n\r\n            //\r\n            // First make sure that we have a non-zero mask.\r\n            // If the app queues a wait on a zero mask it can't\r\n            // be statisfied so it makes no sense to start it.\r\n            //\r\n\r\n            if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitRequest)) {\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                                 \"WaitIrp is invalid\\n\"\r\n                                 \"------- IsrWaitMask: %x\\n\"\r\n                                 \"------- CurrentWaitRequest: %p\\n\",\r\n                                 Extension->IsrWaitMask,\r\n                                 Extension->CurrentWaitRequest);\r\n\r\n                reqContext->Status = STATUS_INVALID_PARAMETER;\r\n\r\n                SerialGetNextRequest(&Extension->CurrentMaskRequest,\r\n                                 Extension->MaskQueue, &NewRequest, TRUE,\r\n                                 Extension);\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                                 \"Perhaps another mask request was found \"\r\n                                 \"in the queue\\n\"\r\n                                 \"------- %p/%p <- values should be the same\\n\",\r\n                                 Extension->CurrentMaskRequest,NewRequest);\r\n\r\n            } else {\r\n\r\n                //\r\n                // Make the current mask request the current wait request and\r\n                // get a new current mask request.  Note that when we get\r\n                // the new current mask request we DO NOT complete the\r\n                // old current mask request (which is now the current wait\r\n                // request.\r\n                //\r\n                // Then under the protection of the cancel spin lock\r\n                // we check to see if the current wait request needs to\r\n                // be canceled\r\n                //\r\n\r\n                SERIAL_INIT_REFERENCE(reqContext);\r\n\r\n                SerialSetCancelRoutine(Extension->CurrentMaskRequest,\r\n                                                SerialCancelWait);\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                                 \"%p will become the current \"\r\n                                 \"wait request\\n\",\r\n                                 Extension->CurrentMaskRequest);\r\n                //\r\n                // There should never be a mask location when\r\n                // there isn't a current wait request.  At this point\r\n                // there shouldn't be a current wait request also.\r\n                //\r\n\r\n                ASSERT(!Extension->IrpMaskLocation);\r\n                ASSERT(!Extension->CurrentWaitRequest);\r\n\r\n                Extension->CurrentWaitRequest = Extension->CurrentMaskRequest;\r\n\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    SerialGiveWaitToIsr,\r\n                    Extension\r\n                    );\r\n\r\n                //\r\n                // Since it isn't really the mask request anymore,\r\n                // null out that pointer.\r\n                //\r\n                Extension->CurrentMaskRequest = NULL;\r\n\r\n                //\r\n                // This will release the cancel spinlock for us\r\n                //\r\n\r\n                SerialGetNextRequest(&Extension->CurrentMaskRequest,\r\n                                       Extension->MaskQueue, &NewRequest,\r\n                                       FALSE, Extension);\r\n\r\n                SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                                 \"Perhaps another mask request was \"\r\n                                 \"found in the queue\\n\"\r\n                                 \"------- %p/%p <- values should be the \"\r\n                                 \"same\\n\", Extension->CurrentMaskRequest,\r\n                                 NewRequest);\r\n            }\r\n\r\n        }\r\n\r\n    } while (NewRequest);\r\n\r\n    return;\r\n\r\n}\r\n\r\nBOOLEAN\r\nSerialGrabWaitFromIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will check to see if the ISR still knows about\r\n    a wait request by checking to see if the IrpMaskLocation is non-null.\r\n    If it is then it will zero the Irpmasklocation (which in effect\r\n    grabs the request away from the isr).  This routine is only called\r\n    buy the cancel code for the wait.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - A pointer to the device extension\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"In SerialGrabWaitFromIsr\\n\");\r\n\r\n    if (Extension->IrpMaskLocation) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                         \"The isr still owns the request %p, mask \"\r\n                         \"location is %p\\n\"\r\n                         \"------- and system buffer is %p\\n\",\r\n                         Extension->CurrentWaitRequest,Extension->IrpMaskLocation,\r\n                         reqContext->SystemBuffer);\r\n\r\n        //\r\n        // The isr still \"owns\" the request.\r\n        //\r\n\r\n        *Extension->IrpMaskLocation = 0;\r\n        Extension->IrpMaskLocation = NULL;\r\n\r\n        reqContext->Information = sizeof(ULONG);\r\n\r\n        //\r\n        // Since the isr no longer references the request we need to\r\n        // decrement the reference count.\r\n        //\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\nBOOLEAN\r\nSerialGiveWaitToIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine simply sets a variable in the device extension\r\n    so that the isr knows that we have a wait request.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the\r\n          cancel spinlock held.\r\n\r\nArguments:\r\n\r\n    Context - Simply a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"In SerialGiveWaitToIsr\\n\");\r\n    //\r\n    // There certainly shouldn't be a current mask location at\r\n    // this point since we have a new current wait request.\r\n    //\r\n\r\n    ASSERT(!Extension->IrpMaskLocation);\r\n\r\n    //\r\n    // The isr may or may not actually reference this request.  It\r\n    // won't if the wait can be satisfied immediately.  However,\r\n    // since it will then go through the normal completion sequence,\r\n    // we need to have an incremented reference count anyway.\r\n    //\r\n\r\n    SERIAL_SET_REFERENCE(\r\n        reqContext,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n    if (!Extension->HistoryMask) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                         \"No events occured prior to the wait call\"\r\n                         \"\\n\");\r\n\r\n        //\r\n        // Although this wait might not be for empty transmit\r\n        // queue, it doesn't hurt anything to set it to false.\r\n        //\r\n\r\n        Extension->EmptiedTransmit = FALSE;\r\n\r\n        //\r\n        // Record where the \"completion mask\" should be set.\r\n        //\r\n\r\n        Extension->IrpMaskLocation = reqContext->SystemBuffer;\r\n        SerialDbgPrintEx( TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                          \"The isr owns the request %p, mask location is \"\r\n                          \"%p\\n\"\r\n                          \"------- and system buffer is %p\\n\",\r\n                          Extension->CurrentWaitRequest,Extension->IrpMaskLocation,\r\n                          reqContext->SystemBuffer);\r\n\r\n    } else {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                         \"%x occurred prior to the wait - starting \"\r\n                         \"the\\n\"\r\n                         \"------- completion code for %p\\n\",\r\n                         Extension->HistoryMask,Extension->CurrentWaitRequest);\r\n\r\n        *((ULONG *)reqContext->SystemBuffer) =\r\n            Extension->HistoryMask;\r\n        Extension->HistoryMask = 0;\r\n        reqContext->Information = sizeof(ULONG);\r\n        reqContext->Status = STATUS_SUCCESS;\r\n\r\n        SerialInsertQueueDpc(Extension->CommWaitDpc);\r\n\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\nBOOLEAN\r\nSerialFinishOldWait(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will check to see if the ISR still knows about\r\n    a wait request by checking to see if the Irpmasklocation is non-null.\r\n    If it is then it will zero the Irpmasklocation (which in effect\r\n    grabs the request away from the isr).  This routine is only called\r\n    buy the cancel code for the wait.\r\n\r\n    NOTE: This is called by WdfInterruptSynchronize.\r\n\r\nArguments:\r\n\r\n    Context - A pointer to the device extension\r\n\r\nReturn Value:\r\n\r\n    Always FALSE.\r\n\r\n--*/\r\n\r\n{\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    PREQUEST_CONTEXT reqContext = NULL;\r\n    PREQUEST_CONTEXT reqContextMask;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContextMask = SerialGetRequestContext(Extension->CurrentMaskRequest);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"In SerialFinishOldWait\\n\");\r\n\r\n    if (Extension->IrpMaskLocation) {\r\n\r\n        reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                         \"The isr still owns the request %p, mask \"\r\n                         \"location is %p\\n\"\r\n                         \"------- and system buffer is %p\\n\",\r\n                         Extension->CurrentWaitRequest,Extension->IrpMaskLocation,\r\n                         reqContext->SystemBuffer);\r\n        //\r\n        // The isr still \"owns\" the request.\r\n        //\r\n\r\n        *Extension->IrpMaskLocation = 0;\r\n        Extension->IrpMaskLocation = NULL;\r\n\r\n        reqContext->Information = sizeof(ULONG);\r\n\r\n        //\r\n        // We don't decrement the reference since the completion routine\r\n        // will do that.\r\n        //\r\n\r\n        SerialInsertQueueDpc(Extension->CommWaitDpc);\r\n\r\n    }\r\n\r\n    //\r\n    // Don't wipe out any historical data we are still interested in.\r\n    //\r\n\r\n    Extension->HistoryMask &= *((ULONG *)reqContextMask->SystemBuffer);\r\n\r\n    Extension->IsrWaitMask = *((ULONG *)reqContextMask->SystemBuffer);\r\n    SerialDbgPrintEx( TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                      \"Set mask location of %p, in request %p, with \"\r\n                      \"system buffer of %p\\n\",\r\n                      Extension->IrpMaskLocation, Extension->CurrentMaskRequest,\r\n                      reqContextMask->SystemBuffer);\r\n    return FALSE;\r\n}\r\n\r\nVOID\r\nSerialCancelWait(\r\n     IN WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to cancel a request that is waiting on\r\n    a comm event.\r\n\r\nArguments:\r\n\r\n    Device - Wdf handle for the device\r\n\r\n    Request - Pointer to the WDFREQUEST for the current request\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));\r\n\r\n    UNREFERENCED_PARAMETER(Request);\r\n\r\n    Extension = SerialGetDeviceExtension(device);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"Canceling wait for request %p\\n\",\r\n                     Extension->CurrentWaitRequest);\r\n\r\n    SerialTryToCompleteCurrent(Extension,\r\n                               SerialGrabWaitFromIsr,\r\n                               STATUS_CANCELLED,\r\n                               &Extension->CurrentWaitRequest,\r\n                               NULL, NULL, NULL,\r\n                               NULL, NULL, SERIAL_REF_CANCEL);\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialCompleteWait(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \">SerialCompleteWait(%p)\\n\",\r\n                     Extension);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"Completing wait for request %p\\n\",\r\n                     Extension->CurrentWaitRequest);\r\n\r\n    SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS,\r\n                               &Extension->CurrentWaitRequest, NULL, NULL, NULL,\r\n                               NULL, NULL, SERIAL_REF_ISR);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,\r\n                     \"<SerialCompleteWait\\n\");\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/wmi.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    wmi.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that handles the wmi IRPs for the\r\n    serial driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n#include <wmistr.h>\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"wmi.tmh\"\r\n#endif\r\n\r\nEVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortName;\r\nEVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortCommData;\r\nEVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortHWData;\r\nEVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortPerfData;\r\nEVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiQueryPortPropData;\r\n\r\nNTSTATUS\r\nSerialWmiRegisterInstance(\r\n    WDFDEVICE Device,\r\n    const GUID* Guid,\r\n    ULONG MinInstanceBufferSize,\r\n    PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance\r\n    );\r\n\r\n#ifdef ALLOC_PRAGMA\r\n#pragma alloc_text(PAGESRP0, SerialWmiRegistration)\r\n#pragma alloc_text(PAGESRP0, SerialWmiRegisterInstance)\r\n#pragma alloc_text(PAGESRP0, EvtWmiQueryPortName)\r\n#pragma alloc_text(PAGESRP0, EvtWmiQueryPortCommData)\r\n#pragma alloc_text(PAGESRP0, EvtWmiQueryPortHWData)\r\n#pragma alloc_text(PAGESRP0, EvtWmiQueryPortPerfData)\r\n#pragma alloc_text(PAGESRP0, EvtWmiQueryPortPropData)\r\n#endif\r\n\r\nNTSTATUS\r\nSerialWmiRegisterInstance(\r\n    WDFDEVICE Device,\r\n    const GUID* Guid,\r\n    ULONG MinInstanceBufferSize,\r\n    PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance\r\n    )\r\n{\r\n    WDF_WMI_PROVIDER_CONFIG providerConfig;\r\n    WDF_WMI_INSTANCE_CONFIG instanceConfig;\r\n\r\n    PAGED_CODE();\r\n\r\n    //\r\n    // Create and register WMI providers and instances  blocks\r\n    //\r\n    WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, Guid);\r\n    providerConfig.MinInstanceBufferSize = MinInstanceBufferSize;\r\n\r\n    WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig);\r\n    instanceConfig.Register = TRUE;\r\n    instanceConfig.EvtWmiInstanceQueryInstance = EvtWmiInstanceQueryInstance;\r\n\r\n    return WdfWmiInstanceCreate(Device,\r\n                                &instanceConfig,\r\n                                WDF_NO_OBJECT_ATTRIBUTES,\r\n                                WDF_NO_HANDLE);\r\n}\r\n\r\nNTSTATUS\r\nSerialWmiRegistration(\r\n    WDFDEVICE      Device\r\n)\r\n/*++\r\nRoutine Description\r\n\r\n    Registers with WMI as a data provider for this\r\n    instance of the device\r\n\r\n--*/\r\n{\r\n    NTSTATUS        status = STATUS_SUCCESS;\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    PAGED_CODE();\r\n\r\n    pDevExt = SerialGetDeviceExtension (Device);\r\n\r\n    //\r\n    // Fill in wmi perf data (all zero's)\r\n    //\r\n    RtlZeroMemory(&pDevExt->WmiPerfData, sizeof(pDevExt->WmiPerfData));\r\n\r\n    status = SerialWmiRegisterInstance(Device,\r\n                                       &MSSerial_PortName_GUID,\r\n                                       0,\r\n                                       EvtWmiQueryPortName);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    status = SerialWmiRegisterInstance(Device,\r\n                                       &MSSerial_CommInfo_GUID,\r\n                                       sizeof(SERIAL_WMI_COMM_DATA),\r\n                                       EvtWmiQueryPortCommData);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    status = SerialWmiRegisterInstance(Device,\r\n                                       &MSSerial_HardwareConfiguration_GUID,\r\n                                       sizeof(SERIAL_WMI_HW_DATA),\r\n                                       EvtWmiQueryPortHWData);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    status = SerialWmiRegisterInstance(Device,\r\n                                       &MSSerial_PerformanceInformation_GUID,\r\n                                       sizeof(SERIAL_WMI_PERF_DATA),\r\n                                       EvtWmiQueryPortPerfData);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    status = SerialWmiRegisterInstance(Device,\r\n                                       &MSSerial_CommProperties_GUID,\r\n                                       sizeof(SERIAL_COMMPROP) + sizeof(ULONG),\r\n                                       EvtWmiQueryPortPropData);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n//\r\n// WMI Call back functions\r\n//\r\n\r\nNTSTATUS\r\nEvtWmiQueryPortName(\r\n    IN  WDFWMIINSTANCE WmiInstance,\r\n    IN  ULONG OutBufferSize,\r\n    IN  PVOID OutBuffer,\r\n    OUT PULONG BufferUsed\r\n    )\r\n{\r\n    WDFDEVICE device;\r\n    WCHAR pRegName[SYMBOLIC_NAME_LENGTH];\r\n    UNICODE_STRING string;\r\n    USHORT nameSize = sizeof(pRegName);\r\n    NTSTATUS status;\r\n\r\n    PAGED_CODE();\r\n\r\n    device = WdfWmiInstanceGetDevice(WmiInstance);\r\n\r\n    status = SerialReadSymName(device, pRegName, &nameSize);\r\n    if (!NT_SUCCESS(status)) {\r\n        return status;\r\n    }\r\n\r\n    RtlInitUnicodeString(&string, pRegName);\r\n\r\n    return WDF_WMI_BUFFER_APPEND_STRING(OutBuffer,\r\n                                        OutBufferSize,\r\n                                        &string,\r\n                                        BufferUsed);\r\n}\r\n\r\nNTSTATUS\r\nEvtWmiQueryPortCommData(\r\n    IN  WDFWMIINSTANCE WmiInstance,\r\n    IN  ULONG  OutBufferSize,\r\n    IN  PVOID  OutBuffer,\r\n    OUT PULONG BufferUsed\r\n    )\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    UNREFERENCED_PARAMETER(OutBufferSize);\r\n\r\n    PAGED_CODE();\r\n\r\n    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));\r\n\r\n    *BufferUsed = sizeof(SERIAL_WMI_COMM_DATA);\r\n\r\n    if (OutBufferSize < *BufferUsed) {\r\n        return STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    *(PSERIAL_WMI_COMM_DATA)OutBuffer = pDevExt->WmiCommData;\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nEvtWmiQueryPortHWData(\r\n    IN  WDFWMIINSTANCE WmiInstance,\r\n    IN  ULONG  OutBufferSize,\r\n    IN  PVOID  OutBuffer,\r\n    OUT PULONG BufferUsed\r\n    )\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    UNREFERENCED_PARAMETER(OutBufferSize);\r\n\r\n    PAGED_CODE();\r\n\r\n    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));\r\n\r\n    *BufferUsed = sizeof(SERIAL_WMI_HW_DATA);\r\n\r\n    if (OutBufferSize < *BufferUsed) {\r\n        return STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    *(PSERIAL_WMI_HW_DATA)OutBuffer = pDevExt->WmiHwData;\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nEvtWmiQueryPortPerfData(\r\n    IN  WDFWMIINSTANCE WmiInstance,\r\n    IN  ULONG OutBufferSize,\r\n    IN  PVOID OutBuffer,\r\n    OUT PULONG BufferUsed\r\n    )\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    UNREFERENCED_PARAMETER(OutBufferSize);\r\n\r\n    PAGED_CODE();\r\n\r\n    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));\r\n\r\n    *BufferUsed = sizeof(SERIAL_WMI_PERF_DATA);\r\n\r\n    if (OutBufferSize < *BufferUsed) {\r\n        return STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    *(PSERIAL_WMI_PERF_DATA)OutBuffer = pDevExt->WmiPerfData;\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nEvtWmiQueryPortPropData(\r\n    IN  WDFWMIINSTANCE WmiInstance,\r\n    IN  ULONG OutBufferSize,\r\n    IN  PVOID OutBuffer,\r\n    OUT PULONG BufferUsed\r\n    )\r\n{\r\n    PSERIAL_DEVICE_EXTENSION pDevExt;\r\n\r\n    UNREFERENCED_PARAMETER(OutBufferSize);\r\n\r\n    PAGED_CODE();\r\n\r\n    pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance));\r\n\r\n    *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG);\r\n\r\n    if (OutBufferSize < *BufferUsed) {\r\n        return STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    SerialGetProperties(\r\n            pDevExt,\r\n            (PSERIAL_COMMPROP)OutBuffer\r\n            );\r\n\r\n    *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0;\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/write.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    write.c\r\n\r\nAbstract:\r\n\r\n    This module contains the code that is very specific to write\r\n    operations in the serial driver\r\n\r\nEnvironment:\r\n\r\n    Kernel mode\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#if defined(EVENT_TRACING)\r\n#include \"write.tmh\"\r\n#endif\r\n\r\nEVT_WDF_REQUEST_CANCEL SerialCancelCurrentWrite;\r\nEVT_WDF_REQUEST_CANCEL SerialCancelCurrentXoff;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveWriteToIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGiveXoffToIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabWriteFromIsr;\r\nEVT_WDF_INTERRUPT_SYNCHRONIZE SerialGrabXoffFromIsr;\r\n\r\n\r\nVOID\r\nSerialEvtIoWrite(\r\n    IN WDFQUEUE         Queue,\r\n    IN WDFREQUEST       Request,\r\n    IN size_t            Length\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the dispatch routine for write.  It validates the parameters\r\n    for the write request and if all is ok then it places the request\r\n    on the work queue.\r\n\r\nArguments:\r\n\r\n    Queue - Handle to the framework queue object that is associated\r\n            with the I/O request.\r\n    Request - Pointer to the WDFREQUEST for the current request\r\n\r\n    Length - Length of the IO operation\r\n                 The default property of the queue is to not dispatch\r\n                 zero lenght read & write requests to the driver and\r\n                 complete is with status success. So we will never get\r\n                 a zero length request.\r\n\r\nReturn Value:\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION extension;\r\n    NTSTATUS status;\r\n    WDFDEVICE hDevice;\r\n    WDF_REQUEST_PARAMETERS params;\r\n    PREQUEST_CONTEXT reqContext;\r\n    size_t bufLen;\r\n\r\n    hDevice = WdfIoQueueGetDevice(Queue);\r\n    extension = SerialGetDeviceExtension(hDevice);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n                    \">SerialEvtIoWrite(%p, 0x%I64x)\\n\", Request,  Length);\r\n\r\n    if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) {\r\n\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialEvtIoWrite (2) %d\\n\", STATUS_CANCELLED);\r\n        return;\r\n\r\n    }\r\n\r\n\r\n    WDF_REQUEST_PARAMETERS_INIT(&params);\r\n\r\n    WdfRequestGetParameters(\r\n          Request,\r\n          &params\r\n          );\r\n\r\n    //\r\n    // Initialize the scratch area of the request.\r\n    //\r\n    reqContext = SerialGetRequestContext(Request);\r\n    reqContext->MajorFunction = params.Type;\r\n    reqContext->Length = (ULONG) Length;\r\n\r\n    status = WdfRequestRetrieveInputBuffer (Request, Length, &reqContext->SystemBuffer, &bufLen);\r\n\r\n    if (!NT_SUCCESS (status)) {\r\n\r\n        SerialCompleteRequest(Request , status, 0);\r\n        SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialEvtIoWrite (4) %X\\n\", status);\r\n        return;\r\n    }\r\n\r\n   SerialStartOrQueue(extension, Request, extension->WriteQueue,\r\n                               &extension->CurrentWriteRequest,\r\n                               SerialStartWrite);\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialEvtIoWrite (5) %X\\n\", status);\r\n\r\n   return ;\r\n\r\n}\r\n\r\nVOID\r\nSerialStartWrite(\r\n    IN PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to start off any write.  It initializes\r\n    the Iostatus fields of the request.  It will set up any timers\r\n    that are used to control the write.\r\n\r\nArguments:\r\n\r\n    Extension - Points to the serial device extension\r\n\r\nReturn Value:\r\n\r\n--*/\r\n\r\n{\r\n\r\n    LARGE_INTEGER    TotalTime;\r\n    BOOLEAN          UseATimer;\r\n    SERIAL_TIMEOUTS  Timeouts;\r\n    PREQUEST_CONTEXT reqContext;\r\n    PREQUEST_CONTEXT reqContextXoff;\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE,\r\n                     \">SerialStartWrite(%p)\\n\", Extension);\r\n\r\n    TotalTime.QuadPart = 0;\r\n\r\n    do {\r\n\r\n        reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);\r\n\r\n        //\r\n        // If there is an xoff counter then complete it.\r\n        //\r\n\r\n        //\r\n        // We see if there is a actually an Xoff counter request.\r\n        //\r\n        // If there is, we put the write request back on the head\r\n        // of the write list.  We then complete the xoff counter.\r\n        // The xoff counter completing code will actually make the\r\n        // xoff counter back into the current write request, and\r\n        // in the course of completing the xoff (which is now\r\n        // the current write) we will restart this request.\r\n        //\r\n\r\n        if (Extension->CurrentXoffRequest) {\r\n\r\n            reqContextXoff =\r\n                SerialGetRequestContext(Extension->CurrentXoffRequest);\r\n\r\n            if (SERIAL_REFERENCE_COUNT(reqContextXoff)) {\r\n\r\n                //\r\n                // The reference count is non-zero.  This implies that\r\n                // the xoff request has not made it through the completion\r\n                // path yet.  We will increment the reference count\r\n                // and attempt to complete it ourseleves.\r\n                //\r\n\r\n                SERIAL_SET_REFERENCE(\r\n                    reqContextXoff,\r\n                    SERIAL_REF_XOFF_REF\r\n                    );\r\n\r\n                reqContextXoff->Information = 0;\r\n\r\n                //\r\n                // The following call will actually release the\r\n                // cancel spin lock.\r\n                //\r\n\r\n                SerialTryToCompleteCurrent(\r\n                    Extension,\r\n                    SerialGrabXoffFromIsr,\r\n                    STATUS_SERIAL_MORE_WRITES,\r\n                    &Extension->CurrentXoffRequest,\r\n                    NULL,\r\n                    NULL,\r\n                    Extension->XoffCountTimer,\r\n                    NULL,\r\n                    NULL,\r\n                    SERIAL_REF_XOFF_REF\r\n                    );\r\n\r\n            } else {\r\n\r\n                //\r\n                // The request is well on its way to being finished.\r\n                // We can let the regular completion code do the\r\n                // work.  Just release the spin lock.\r\n                //\r\n\r\n            }\r\n\r\n        }\r\n\r\n        UseATimer = FALSE;\r\n\r\n        //\r\n        // Calculate the timeout value needed for the\r\n        // request.  Note that the values stored in the\r\n        // timeout record are in milliseconds.  Note that\r\n        // if the timeout values are zero then we won't start\r\n        // the timer.\r\n        //\r\n\r\n        Timeouts = Extension->Timeouts;\r\n\r\n        if (Timeouts.WriteTotalTimeoutConstant ||\r\n            Timeouts.WriteTotalTimeoutMultiplier) {\r\n\r\n            UseATimer = TRUE;\r\n\r\n            //\r\n            // We have some timer values to calculate.\r\n            //\r\n            // Take care, we might have an xoff counter masquerading\r\n            // as a write.\r\n            //\r\n\r\n            TotalTime.QuadPart =\r\n                ((LONGLONG)((UInt32x32To64(\r\n                                 (reqContext->MajorFunction == IRP_MJ_WRITE)?\r\n                                     (reqContext->Length) : (1),\r\n                                 Timeouts.WriteTotalTimeoutMultiplier\r\n                                 )\r\n                                 + Timeouts.WriteTotalTimeoutConstant)))\r\n                * -10000;\r\n\r\n        }\r\n\r\n        //\r\n        // The request may be going to the isr shortly.  Now\r\n        // is a good time to initialize its reference counts.\r\n        //\r\n\r\n        SERIAL_INIT_REFERENCE(reqContext);\r\n\r\n         //\r\n         // We give the request to to the isr to write out.\r\n         // We set a cancel routine that knows how to\r\n         // grab the current write away from the isr.\r\n         //\r\n         SerialSetCancelRoutine(Extension->CurrentWriteRequest,\r\n                                         SerialCancelCurrentWrite);\r\n\r\n        if (UseATimer) {\r\n            BOOLEAN result;\r\n\r\n            result = SerialSetTimer(\r\n                Extension->WriteRequestTotalTimer,\r\n                TotalTime\r\n                );\r\n            if(result == FALSE) {\r\n                //\r\n                // This timer now has a reference to the request.\r\n                //\r\n\r\n                SERIAL_SET_REFERENCE( reqContext, SERIAL_REF_TOTAL_TIMER );\r\n            }\r\n        }\r\n\r\n        WdfInterruptSynchronize(\r\n            Extension->WdfInterrupt,\r\n            SerialGiveWriteToIsr,\r\n            Extension\r\n            );\r\n\r\n    } WHILE (FALSE);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialStartWrite \\n\");\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nSerialGetNextWrite(\r\n    IN WDFREQUEST *CurrentOpRequest,\r\n    IN WDFQUEUE QueueToProcess,\r\n    IN WDFREQUEST *NewRequest,\r\n    IN BOOLEAN CompleteCurrent,\r\n    PSERIAL_DEVICE_EXTENSION Extension\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine completes the old write as well as getting\r\n    a pointer to the next write.\r\n\r\n    The reason that we have have pointers to the current write\r\n    queue as well as the current write request is so that this\r\n    routine may be used in the common completion code for\r\n    read and write.\r\n\r\nArguments:\r\n\r\n    CurrentOpRequest - Pointer to the pointer that points to the\r\n                   current write request.\r\n\r\n    QueueToProcess - Pointer to the write queue.\r\n\r\n    NewRequest - A pointer to a pointer to the request that will be the\r\n             current request.  Note that this could end up pointing\r\n             to a null pointer.  This does NOT necessaryly mean\r\n             that there is no current write.  What could occur\r\n             is that while the cancel lock is held the write\r\n             queue ended up being empty, but as soon as we release\r\n             the cancel spin lock a new request came in from\r\n             SerialStartWrite.\r\n\r\n    CompleteCurrent - Flag indicates whether the CurrentOpRequest should\r\n                      be completed.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n   SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialGetNextWrite\\n\");\r\n\r\n\r\n    do {\r\n\r\n        reqContext = SerialGetRequestContext(*CurrentOpRequest);\r\n\r\n        //\r\n        // We could be completing a flush.\r\n        //\r\n\r\n        if (reqContext->MajorFunction == IRP_MJ_WRITE) {\r\n\r\n            ASSERT(Extension->TotalCharsQueued >= reqContext->Length);\r\n\r\n            Extension->TotalCharsQueued -= reqContext->Length;\r\n\r\n        } else if (reqContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {\r\n\r\n            WDFREQUEST request = *CurrentOpRequest;\r\n            PSERIAL_XOFF_COUNTER Xc;\r\n\r\n            Xc = reqContext->SystemBuffer;\r\n\r\n            //\r\n            // We should never have a xoff counter when we\r\n            // get to this point.\r\n            //\r\n\r\n            ASSERT(!Extension->CurrentXoffRequest);\r\n\r\n            //\r\n            // This could only be a xoff counter masquerading as\r\n            // a write request.\r\n            //\r\n\r\n            Extension->TotalCharsQueued--;\r\n\r\n            //\r\n            // Check to see of the xoff request has been set with success.\r\n            // This means that the write completed normally.  If that\r\n            // is the case, and it hasn't been set to cancel in the\r\n            // meanwhile, then go on and make it the CurrentXoffRequest.\r\n            //\r\n\r\n            if (reqContext->Status != STATUS_SUCCESS || reqContext->Cancelled) {\r\n\r\n                // TODO: I see Xoff request getting abandoned due to loss of\r\n                // Total timer - SERIAL_REF_TOTAL_TIMER\r\n                //\r\n                // Oh well, we can just finish it off.\r\n                //\r\n                NOTHING;\r\n\r\n            } else {\r\n\r\n                SerialSetCancelRoutine(request, SerialCancelCurrentXoff);\r\n\r\n                //\r\n                // We don't want to complete the current request now.  This\r\n                // will now get completed by the Xoff counter code.\r\n                //\r\n\r\n                CompleteCurrent = FALSE;\r\n\r\n                //\r\n                // Give the counter to the isr.\r\n                //\r\n\r\n                Extension->CurrentXoffRequest = request;\r\n                WdfInterruptSynchronize(\r\n                    Extension->WdfInterrupt,\r\n                    SerialGiveXoffToIsr,\r\n                    Extension\r\n                    );\r\n\r\n                //\r\n                // Start the timer for the counter and increment\r\n                // the reference count since the timer has a\r\n                // reference to the request.\r\n                //\r\n\r\n                if (Xc->Timeout) {\r\n\r\n                    LARGE_INTEGER delta;\r\n                    BOOLEAN result;\r\n\r\n                    delta.QuadPart = -((LONGLONG)UInt32x32To64(\r\n                                                     1000,\r\n                                                     Xc->Timeout\r\n                                                     ));\r\n\r\n                    result = SerialSetTimer(\r\n                        Extension->XoffCountTimer,\r\n                        delta\r\n\r\n                        );\r\n                    if(result == FALSE) {\r\n                        SERIAL_SET_REFERENCE(\r\n                            reqContext,\r\n                            SERIAL_REF_TOTAL_TIMER\r\n                            );\r\n                    }\r\n                }\r\n\r\n            }\r\n\r\n\r\n        }\r\n\r\n        //\r\n        // Note that the following call will (probably) also cause\r\n        // the current request to be completed.\r\n        //\r\n\r\n        SerialGetNextRequest(\r\n            CurrentOpRequest,\r\n            QueueToProcess,\r\n            NewRequest,\r\n            CompleteCurrent,\r\n            Extension\r\n            );\r\n\r\n        if (!*NewRequest) {\r\n\r\n\r\n            WdfInterruptSynchronize(\r\n                Extension->WdfInterrupt,\r\n                SerialProcessEmptyTransmit,\r\n                Extension\r\n                );\r\n\r\n            break;\r\n\r\n        } else if (SerialGetRequestContext(*NewRequest)->MajorFunction\r\n                   == IRP_MJ_FLUSH_BUFFERS) {\r\n\r\n            //\r\n            // If we encounter a flush request we just want to get\r\n            // the next request and complete the flush.\r\n            //\r\n            // Note that if NewRequest is non-null then it is also\r\n            // equal to CurrentWriteRequest.\r\n            //\r\n\r\n\r\n            ASSERT((*NewRequest) == (*CurrentOpRequest));\r\n            SerialGetRequestContext(*NewRequest)->Status = STATUS_SUCCESS;\r\n\r\n        } else {\r\n\r\n            break;\r\n\r\n        }\r\n\r\n    } WHILE (TRUE);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialGetNextWrite\\n\");\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialCompleteWrite(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is merely used to complete any write.  It\r\n    assumes that the status and the information fields of\r\n    the request are already correctly filled in.\r\n\r\nArguments:\r\n\r\n    Dpc - Not Used.\r\n\r\n    DeferredContext - Really points to the device extension.\r\n\r\n    SystemContext1 - Not Used.\r\n\r\n    SystemContext2 - Not Used.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialCompleteWrite(%p)\\n\",\r\n                     Extension);\r\n\r\n\r\n    SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS,\r\n                               &Extension->CurrentWriteRequest,\r\n                               Extension->WriteQueue, NULL,\r\n                               Extension->WriteRequestTotalTimer,\r\n                               SerialStartWrite, SerialGetNextWrite,\r\n                               SERIAL_REF_ISR);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialCompleteWrite\\n\");\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialProcessEmptyTransmit(\r\n    IN WDFINTERRUPT  Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to determine if conditions are appropriate\r\n    to satisfy a wait for transmit empty event, and if so to complete\r\n    the request that is waiting for that event.  It also call the code\r\n    that checks to see if we should lower the RTS line if we are\r\n    doing transmit toggling.\r\n\r\n    NOTE: This routine is called by WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the cancel\r\n          spinlock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    if (Extension->IsrWaitMask && (Extension->IsrWaitMask & SERIAL_EV_TXEMPTY) &&\r\n        Extension->EmptiedTransmit && (!Extension->TransmitImmediate) &&\r\n        (!Extension->CurrentWriteRequest) && IsQueueEmpty(Extension->WriteQueue)) {\r\n\r\n        Extension->HistoryMask |= SERIAL_EV_TXEMPTY;\r\n        if (Extension->IrpMaskLocation) {\r\n\r\n            *Extension->IrpMaskLocation = Extension->HistoryMask;\r\n            Extension->IrpMaskLocation = NULL;\r\n            Extension->HistoryMask = 0;\r\n\r\n            SerialGetRequestContext(Extension->CurrentWaitRequest)->Information = sizeof(ULONG);\r\n            SerialInsertQueueDpc(\r\n                Extension->CommWaitDpc\r\n                );\r\n\r\n        }\r\n\r\n        Extension->CountOfTryingToLowerRTS++;\r\n        SerialPerhapsLowerRTS(Extension->WdfInterrupt, Extension);\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGiveWriteToIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Try to start off the write by slipping it in behind\r\n    a transmit immediate char, or if that isn't available\r\n    and the transmit holding register is empty, \"tickle\"\r\n    the UART into interrupting with a transmit buffer\r\n    empty.\r\n\r\n    NOTE: This routine is called by WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the\r\n          cancel spin lock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    //\r\n    // The current stack location.  This contains all of the\r\n    // information we need to process this particular request.\r\n    //\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);\r\n\r\n    //\r\n    // We might have a xoff counter request masquerading as a\r\n    // write.  The length of these requests will always be one\r\n    // and we can get a pointer to the actual character from\r\n    // the data supplied by the user.\r\n    //\r\n\r\n    if (reqContext->MajorFunction == IRP_MJ_WRITE) {\r\n\r\n        Extension->WriteLength = reqContext->Length;\r\n        Extension->WriteCurrentChar = reqContext->SystemBuffer;\r\n\r\n    } else {\r\n\r\n        Extension->WriteLength = 1;\r\n        Extension->WriteCurrentChar =\r\n            ((PUCHAR)reqContext->SystemBuffer) +\r\n            FIELD_OFFSET(\r\n                SERIAL_XOFF_COUNTER,\r\n                XoffChar\r\n                );\r\n\r\n    }\r\n\r\n    //\r\n    // The isr now has a reference to the request.\r\n    //\r\n\r\n    SERIAL_SET_REFERENCE(\r\n        reqContext,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n    //\r\n    // Check first to see if an immediate char is transmitting.\r\n    // If it is then we'll just slip in behind it when its\r\n    // done.\r\n    //\r\n\r\n    if (!Extension->TransmitImmediate) {\r\n\r\n        //\r\n        // If there is no immediate char transmitting then we\r\n        // will \"re-enable\" the transmit holding register empty\r\n        // interrupt.  The 8250 family of devices will always\r\n        // signal a transmit holding register empty interrupt\r\n        // *ANY* time this bit is set to one.  By doing things\r\n        // this way we can simply use the normal interrupt code\r\n        // to start off this write.\r\n        //\r\n        // We've been keeping track of whether the transmit holding\r\n        // register is empty so it we only need to do this\r\n        // if the register is empty.\r\n        //\r\n\r\n        if (Extension->HoldingEmpty) {\r\n\r\n            DISABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n            ENABLE_ALL_INTERRUPTS(Extension, Extension->Controller);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    //\r\n    // The rts line may already be up from previous writes,\r\n    // however, it won't take much additional time to turn\r\n    // on the RTS line if we are doing transmit toggling.\r\n    //\r\n\r\n    if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==\r\n        SERIAL_TRANSMIT_TOGGLE) {\r\n\r\n        SerialSetRTS(Extension->WdfInterrupt, Extension);\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialCancelCurrentWrite(\r\n    IN WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to cancel the current write.\r\n\r\nArguments:\r\n\r\n    Device - Wdf handle for the device\r\n\r\n    Request - Pointer to the WDFREQUEST to be canceled.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));\r\n\r\n    UNREFERENCED_PARAMETER(Request);\r\n\r\n    Extension = SerialGetDeviceExtension(device);\r\n\r\n    SerialTryToCompleteCurrent(\r\n        Extension,\r\n        SerialGrabWriteFromIsr,\r\n        STATUS_CANCELLED,\r\n        &Extension->CurrentWriteRequest,\r\n        Extension->WriteQueue,\r\n        NULL,\r\n        Extension->WriteRequestTotalTimer,\r\n        SerialStartWrite,\r\n        SerialGetNextWrite,\r\n        SERIAL_REF_CANCEL\r\n        );\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialWriteTimeout(\r\n    IN WDFTIMER Timer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will try to timeout the current write.\r\n\r\nArguments:\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialWriteTimeout(%p)\\n\",\r\n                     Extension);\r\n\r\n    SerialTryToCompleteCurrent(Extension, SerialGrabWriteFromIsr,\r\n                               STATUS_TIMEOUT, &Extension->CurrentWriteRequest,\r\n                               Extension->WriteQueue, NULL,\r\n                               Extension->WriteRequestTotalTimer,\r\n                               SerialStartWrite, SerialGetNextWrite,\r\n                               SERIAL_REF_TOTAL_TIMER);\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialWriteTimeout\\n\");\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGrabWriteFromIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n\r\n    This routine is used to grab the current request, which could be timing\r\n    out or canceling, from the ISR\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that the cancel spin lock is held\r\n          when this routine is called.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);\r\n\r\n    //\r\n    // Check if the write length is non-zero.  If it is non-zero\r\n    // then the ISR still owns the request. We calculate the the number\r\n    // of characters written and update the information field of the\r\n    // request with the characters written.  We then clear the write length\r\n    // the isr sees.\r\n    //\r\n\r\n    if (Extension->WriteLength) {\r\n\r\n        //\r\n        // We could have an xoff counter masquerading as a\r\n        // write request.  If so, don't update the write length.\r\n        //\r\n\r\n        if (reqContext->MajorFunction == IRP_MJ_WRITE) {\r\n\r\n            reqContext->Information = reqContext->Length -Extension->WriteLength;\r\n\r\n        } else {\r\n\r\n            reqContext->Information = 0;\r\n\r\n        }\r\n\r\n        //\r\n        // Since the isr no longer references this request, we can\r\n        // decrement it's reference count.\r\n        //\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n        Extension->WriteLength = 0;\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGrabXoffFromIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to grab an xoff counter request from the\r\n    isr when it is no longer masquerading as a write request.  This\r\n    routine is called by the cancel and timeout code for the\r\n    xoff counter ioctl.\r\n\r\n\r\n    NOTE: This routine is being called from WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that the cancel spin lock is held\r\n          when this routine is called.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    Always false.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n\r\n    PREQUEST_CONTEXT reqContext;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest);\r\n\r\n    if (Extension->CountSinceXoff) {\r\n\r\n        //\r\n        // This is only non-zero when there actually is a Xoff ioctl\r\n        // counting down.\r\n        //\r\n\r\n        Extension->CountSinceXoff = 0;\r\n\r\n        //\r\n        // We decrement the count since the isr no longer owns\r\n        // the request.\r\n        //\r\n\r\n        SERIAL_CLEAR_REFERENCE(\r\n            reqContext,\r\n            SERIAL_REF_ISR\r\n            );\r\n\r\n    }\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialCompleteXoff(\r\n    IN WDFDPC Dpc\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is merely used to truely complete an xoff counter request.  It\r\n    assumes that the status and the information fields of the request are\r\n    already correctly filled in.\r\n\r\nArguments:\r\n\r\n    Dpc - Not Used.\r\n\r\n    DeferredContext - Really points to the device extension.\r\n\r\n    SystemContext1 - Not Used.\r\n\r\n    SystemContext2 - Not Used.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfDpcGetParentObject(Dpc));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialCompleteXoff(%p)\\n\",\r\n                     Extension);\r\n\r\n\r\n    SerialTryToCompleteCurrent(Extension, NULL, STATUS_SUCCESS,\r\n                               &Extension->CurrentXoffRequest, NULL, NULL,\r\n                               Extension->XoffCountTimer, NULL, NULL,\r\n                               SERIAL_REF_ISR);\r\n\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialCompleteXoff\\n\");\r\n\r\n}\r\n\r\n\r\nVOID\r\nSerialTimeoutXoff(\r\n    IN WDFTIMER Timer\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is merely used to truely complete an xoff counter request,\r\n    if its timer has run out.\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = NULL;\r\n\r\n    Extension = SerialGetDeviceExtension(WdfTimerGetParentObject(Timer));\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \">SerialTimeoutXoff(%p)\\n\", Extension);\r\n\r\n    SerialTryToCompleteCurrent(Extension, SerialGrabXoffFromIsr,\r\n                               STATUS_SERIAL_COUNTER_TIMEOUT,\r\n                               &Extension->CurrentXoffRequest, NULL, NULL, NULL,\r\n                               NULL, NULL, SERIAL_REF_TOTAL_TIMER);\r\n\r\n    SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_WRITE, \"<SerialTimeoutXoff\\n\");\r\n}\r\n\r\n\r\nVOID\r\nSerialCancelCurrentXoff(\r\n    IN WDFREQUEST Request\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to cancel the current write.\r\n\r\nArguments:\r\n\r\n    Device - Wdf handle for the device\r\n\r\n    Request - Pointer to the WDFREQUEST to be canceled.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension;\r\n    WDFDEVICE  device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));\r\n\r\n    UNREFERENCED_PARAMETER(Request);\r\n\r\n    Extension = SerialGetDeviceExtension(device);\r\n\r\n    SerialTryToCompleteCurrent(\r\n        Extension,\r\n        SerialGrabXoffFromIsr,\r\n        STATUS_CANCELLED,\r\n        &Extension->CurrentXoffRequest,\r\n        NULL,\r\n        NULL,\r\n        Extension->XoffCountTimer,\r\n        NULL,\r\n        NULL,\r\n        SERIAL_REF_CANCEL\r\n        );\r\n\r\n}\r\n\r\n\r\nBOOLEAN\r\nSerialGiveXoffToIsr(\r\n    IN WDFINTERRUPT Interrupt,\r\n    IN PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n\r\n    This routine starts off the xoff counter.  It merely\r\n    has to set the xoff count and increment the reference\r\n    count to denote that the isr has a reference to the request.\r\n\r\n    NOTE: This routine is called by WdfInterruptSynchronize.\r\n\r\n    NOTE: This routine assumes that it is called with the\r\n          cancel spin lock held.\r\n\r\nArguments:\r\n\r\n    Context - Really a pointer to the device extension.\r\n\r\nReturn Value:\r\n\r\n    This routine always returns FALSE.\r\n\r\n--*/\r\n\r\n{\r\n\r\n    PSERIAL_DEVICE_EXTENSION Extension = Context;\r\n    PREQUEST_CONTEXT reqContext;\r\n    PSERIAL_XOFF_COUNTER Xc = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(Interrupt);\r\n\r\n    reqContext = SerialGetRequestContext(Extension->CurrentXoffRequest);\r\n    Xc = reqContext->SystemBuffer;\r\n\r\n    //\r\n    // The current stack location.  This contains all of the\r\n    // information we need to process this particular request.\r\n    //\r\n\r\n    ASSERT(Extension->CurrentXoffRequest);\r\n    Extension->CountSinceXoff = Xc->Counter;\r\n\r\n    //\r\n    // The isr now has a reference to the request.\r\n    //\r\n\r\n    SERIAL_SET_REFERENCE(\r\n        reqContext,\r\n        SERIAL_REF_ISR\r\n        );\r\n\r\n    return FALSE;\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/kmdf/serial/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"wdfserial\")\n    add_rules(\"wdk.env.kmdf\", \"wdk.driver\")\n    add_values(\"wdk.tracewpp.flags\", \"-func:SerialDbgPrintEx(LEVEL,FLAGS,MSG,...)\")\n    add_values(\"wdk.mc.header\", \"serlog.h\")\n    add_files(\"*.c\", {rules = \"wdk.tracewpp\"})\n    add_files(\"*.mc\", \"*.rc\", \"*.inx\")\n\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/device.c",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    device.c - Device handling events for example driver.\r\n\r\nAbstract:\r\n\r\n    This is a C version of a very simple sample driver that illustrates\r\n    how to use the driver framework and demonstrates best practices.\r\n\r\n--*/\r\n\r\n#include \"driver.h\"\r\n\r\nNTSTATUS\r\nEchoDeviceCreate(\r\n    PWDFDEVICE_INIT DeviceInit\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Worker routine called to create a device and its software resources.\r\n\r\nArguments:\r\n\r\n    DeviceInit - Pointer to an opaque init structure. Memory for this\r\n                    structure will be freed by the framework when the WdfDeviceCreate\r\n                    succeeds. So don't access the structure after that point.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    WDF_OBJECT_ATTRIBUTES   deviceAttributes;\r\n    PDEVICE_CONTEXT deviceContext;\r\n    WDF_PNPPOWER_EVENT_CALLBACKS    pnpPowerCallbacks;\r\n    WDFDEVICE device;\r\n    NTSTATUS status;\r\n\r\n    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);\r\n\r\n    //\r\n    // Register pnp/power callbacks so that we can start and stop the timer as the device\r\n    // gets started and stopped.\r\n    //\r\n    pnpPowerCallbacks.EvtDeviceSelfManagedIoInit    = EchoEvtDeviceSelfManagedIoStart;\r\n    pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend;\r\n\r\n    #pragma prefast(suppress: 28024, \"Function used for both Init and Restart Callbacks\")\r\n    pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart;\r\n\r\n    //\r\n    // Register the PnP and power callbacks. Power policy related callbacks will be registered\r\n    // later in SotwareInit.\r\n    //\r\n    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);\r\n\r\n    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n        //\r\n        // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an\r\n        // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the\r\n        // device.h header file. This function will do the type checking and return\r\n        // the device context. If you pass a wrong object  handle\r\n        // it will return NULL and assert if run under framework verifier mode.\r\n        //\r\n        deviceContext = WdfObjectGet_DEVICE_CONTEXT(device);\r\n        deviceContext->PrivateDeviceData = 0;\r\n\r\n        //\r\n        // Create a device interface so that application can find and talk\r\n        // to us.\r\n        //\r\n        status = WdfDeviceCreateDeviceInterface(\r\n            device,\r\n            &GUID_DEVINTERFACE_ECHO,\r\n            NULL // ReferenceString\r\n            );\r\n\r\n        if (NT_SUCCESS(status)) {\r\n            //\r\n            // Initialize the I/O Package and any Queues\r\n            //\r\n            status = EchoQueueInitialize(device);\r\n        }\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nEchoEvtDeviceSelfManagedIoStart(\r\n    IN  WDFDEVICE Device\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called by the Framework when the device is started\r\n    or restarted after a suspend operation.\r\n\r\n    This function is not marked pageable because this function is in the\r\n    device power up path. When a function is marked pagable and the code\r\n    section is paged out, it will generate a page fault which could impact\r\n    the fast resume behavior because the client driver will have to wait\r\n    until the system drivers can service this page fault.\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - Failures will result in the device stack being torn down.\r\n\r\n--*/\r\n{\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));\r\n    LARGE_INTEGER DueTime;\r\n\r\n    KdPrint((\"--> EchoEvtDeviceSelfManagedIoInit\\n\"));\r\n\r\n    //\r\n    // Restart the queue and the periodic timer. We stopped them before going\r\n    // into low power state.\r\n    //\r\n    WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device));\r\n\r\n    DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100);\r\n\r\n    WdfTimerStart(queueContext->Timer,  DueTime.QuadPart);\r\n\r\n    KdPrint(( \"<-- EchoEvtDeviceSelfManagedIoInit\\n\"));\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nEchoEvtDeviceSelfManagedIoSuspend(\r\n    IN  WDFDEVICE Device\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called by the Framework when the device is stopped\r\n    for resource rebalance or suspended when the system is entering\r\n    Sx state.\r\n\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - The driver is not allowed to fail this function.  If it does, the\r\n    device stack will be torn down.\r\n\r\n--*/\r\n{\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device));\r\n\r\n    PAGED_CODE();\r\n\r\n    KdPrint((\"--> EchoEvtDeviceSelfManagedIoSuspend\\n\"));\r\n\r\n    //\r\n    // Before we stop the timer we should make sure there are no outstanding\r\n    // i/o. We need to do that because framework cannot suspend the device\r\n    // if there are requests owned by the driver. There are two ways to solve\r\n    // this issue: 1) We can wait for the outstanding I/O to be complete by the\r\n    // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge\r\n    // the request to inform the framework that it's okay to suspend the device\r\n    // with outstanding I/O. In this sample we will use the 1st approach\r\n    // because it's pretty easy to do. We will restart the queue when the\r\n    // device is restarted.\r\n    //\r\n    WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device));\r\n\r\n    //\r\n    // Stop the watchdog timer and wait for DPC to run to completion if it's already fired.\r\n    //\r\n    WdfTimerStop(queueContext->Timer, TRUE);\r\n\r\n    KdPrint(( \"<-- EchoEvtDeviceSelfManagedIoSuspend\\n\"));\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/device.h",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    device.h\r\n\r\nAbstract:\r\n\r\n    This is a C version of a very simple sample driver that illustrates\r\n    how to use the driver framework and demonstrates best practices.\r\n\r\n--*/\r\n\r\n#include \"public.h\"\r\n\r\n//\r\n// The device context performs the same job as\r\n// a WDM device extension in the driver frameworks\r\n//\r\ntypedef struct _DEVICE_CONTEXT\r\n{\r\n    ULONG PrivateDeviceData;  // just a placeholder\r\n\r\n} DEVICE_CONTEXT, *PDEVICE_CONTEXT;\r\n\r\n//\r\n// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT\r\n// which will be used to get a pointer to the device context memory\r\n// in a type safe manner.\r\n//\r\nWDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT)\r\n\r\n//\r\n// Function to initialize the device and its callbacks\r\n//\r\nNTSTATUS\r\nEchoDeviceCreate(\r\n    PWDFDEVICE_INIT DeviceInit\r\n    );\r\n\r\n//\r\n// Device events\r\n//\r\nEVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart;\r\nEVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend;\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/driver.c",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    driver.c\r\n\r\nAbstract:\r\n\r\n    This driver demonstrates use of a default I/O Queue, its\r\n    request start events, cancellation event, and a synchronized DPC.\r\n\r\n    To demonstrate asynchronous operation, the I/O requests are not completed\r\n    immediately, but stored in the drivers private data structure, and a timer\r\n    will complete it next time the Timer callback runs.\r\n\r\n    During the time the request is waiting for the timer callback to run, it is\r\n    made cancellable by the call WdfRequestMarkCancelable. This\r\n    allows the test program to cancel the request and exit instantly.\r\n\r\n    This rather complicated set of events is designed to demonstrate\r\n    the driver frameworks synchronization of access to a device driver\r\n    data structure, and a pointer which can be a proxy for device hardware\r\n    registers or resources.\r\n\r\n    This common data structure, or resource is accessed by new request\r\n    events arriving, the Timer callback that completes it, and cancel processing.\r\n\r\n    Notice the lack of specific lock/unlock operations.\r\n\r\n    Even though this example utilizes a serial queue, a parallel queue\r\n    would not need any additional explicit synchronization, just a\r\n    strategy for managing multiple requests outstanding.\r\n\r\n--*/\r\n\r\n#include \"driver.h\"\r\n\r\nNTSTATUS\r\nDriverEntry(\r\n    IN PDRIVER_OBJECT  DriverObject,\r\n    IN PUNICODE_STRING RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n    DriverEntry initializes the driver and is the first routine called by the\r\n    system after the driver is loaded. DriverEntry specifies the other entry\r\n    points in the function driver, such as EvtDevice and DriverUnload.\r\n\r\nParameters Description:\r\n\r\n    DriverObject - represents the instance of the function driver that is loaded\r\n    into memory. DriverEntry must initialize members of DriverObject before it\r\n    returns to the caller. DriverObject is allocated by the system before the\r\n    driver is loaded, and it is released by the system after the system unloads\r\n    the function driver from memory.\r\n\r\n    RegistryPath - represents the driver specific path in the Registry.\r\n    The function driver can use the path to store driver related data between\r\n    reboots. The path does not store hardware instance specific data.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if successful,\r\n    STATUS_UNSUCCESSFUL otherwise.\r\n\r\n--*/\r\n{\r\n    WDF_DRIVER_CONFIG config;\r\n    NTSTATUS status;\r\n\r\n    WDF_DRIVER_CONFIG_INIT(&config,\r\n                        EchoEvtDeviceAdd\r\n                        );\r\n\r\n    status = WdfDriverCreate(DriverObject,\r\n                            RegistryPath,\r\n                            WDF_NO_OBJECT_ATTRIBUTES,\r\n                            &config,\r\n                            WDF_NO_HANDLE);\r\n    if (!NT_SUCCESS(status)) {\r\n        KdPrint((\"Error: WdfDriverCreate failed 0x%x\\n\", status));\r\n        return status;\r\n    }\r\n\r\n#if DBG\r\n    EchoPrintDriverVersion();\r\n#endif\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nEchoEvtDeviceAdd(\r\n    IN WDFDRIVER       Driver,\r\n    IN PWDFDEVICE_INIT DeviceInit\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    EvtDeviceAdd is called by the framework in response to AddDevice\r\n    call from the PnP manager. We create and initialize a device object to\r\n    represent a new instance of the device.\r\n\r\nArguments:\r\n\r\n    Driver - Handle to a framework driver object created in DriverEntry\r\n\r\n    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n\r\n    UNREFERENCED_PARAMETER(Driver);\r\n\r\n    KdPrint((\"Enter  EchoEvtDeviceAdd\\n\"));\r\n\r\n    status = EchoDeviceCreate(DeviceInit);\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nEchoPrintDriverVersion(\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n   This routine shows how to retrieve framework version string and\r\n   also how to find out to which version of framework library the\r\n   client driver is bound to.\r\n\r\nArguments:\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n    WDFSTRING string;\r\n    UNICODE_STRING us;\r\n    WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver;\r\n\r\n    //\r\n    // 1) Retreive version string and print that in the debugger.\r\n    //\r\n    status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string);\r\n    if (!NT_SUCCESS(status)) {\r\n        KdPrint((\"Error: WdfStringCreate failed 0x%x\\n\", status));\r\n        return status;\r\n    }\r\n\r\n    status = WdfDriverRetrieveVersionString(WdfGetDriver(), string);\r\n    if (!NT_SUCCESS(status)) {\r\n        //\r\n        // No need to worry about delete the string object because\r\n        // by default it's parented to the driver and it will be\r\n        // deleted when the driverobject is deleted when the DriverEntry\r\n        // returns a failure status.\r\n        //\r\n        KdPrint((\"Error: WdfDriverRetrieveVersionString failed 0x%x\\n\", status));\r\n        return status;\r\n    }\r\n\r\n    WdfStringGetUnicodeString(string, &us);\r\n    KdPrint((\"Echo Sample %wZ\\n\", &us));\r\n\r\n    WdfObjectDelete(string);\r\n    string = NULL; // To avoid referencing a deleted object.\r\n\r\n    //\r\n    // 2) Find out to which version of framework this driver is bound to.\r\n    //\r\n    WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0);\r\n    if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) {\r\n        KdPrint((\"Yes, framework version is 1.0\\n\"));\r\n    }else {\r\n        KdPrint((\"No, framework verison is not 1.0\\n\"));\r\n    }\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/driver.h",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    driver.h\r\n\r\nAbstract:\r\n\r\n    This is a C version of a very simple sample driver that illustrates\r\n    how to use the driver framework and demonstrates best practices.\r\n\r\n--*/\r\n\r\n#define INITGUID\r\n\r\n#include <windows.h>\r\n#include <wdf.h>\r\n#include \"device.h\"\r\n#include \"queue.h\"\r\n\r\n#ifndef ASSERT\r\n#if DBG\r\n#define ASSERT( exp ) \\\r\n    ((!(exp)) ? \\\r\n        (KdPrint(( \"\\n*** Assertion failed: \" #exp \"\\n\\n\")), \\\r\n         DebugBreak(), \\\r\n         FALSE) : \\\r\n        TRUE)\r\n#else\r\n#define ASSERT( exp )\r\n#endif // DBG\r\n#endif // ASSERT\r\n\r\n//\r\n// WDFDRIVER Events\r\n//\r\n\r\nDRIVER_INITIALIZE DriverEntry;\r\nEVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd;\r\n\r\nNTSTATUS\r\nEchoPrintDriverVersion(\r\n    );\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/queue.c",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    queue.c\r\n\r\nAbstract:\r\n\r\n    This is a C version of a very simple sample driver that illustrates\r\n    how to use the driver framework and demonstrates best practices.\r\n\r\n--*/\r\n\r\n#include \"driver.h\"\r\n\r\nNTSTATUS\r\nEchoQueueInitialize(\r\n    WDFDEVICE Device\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n\r\n     The I/O dispatch callbacks for the frameworks device object\r\n     are configured in this function.\r\n\r\n     A single default I/O Queue is configured for serial request\r\n     processing, and a driver context memory allocation is created\r\n     to hold our structure QUEUE_CONTEXT.\r\n\r\n     This memory may be used by the driver automatically synchronized\r\n     by the Queue's presentation lock.\r\n\r\n     The lifetime of this memory is tied to the lifetime of the I/O\r\n     Queue object, and we register an optional destructor callback\r\n     to release any private allocations, and/or resources.\r\n\r\n\r\nArguments:\r\n\r\n    Device - Handle to a framework device object.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    WDFQUEUE queue;\r\n    NTSTATUS status;\r\n    PQUEUE_CONTEXT queueContext;\r\n    WDF_IO_QUEUE_CONFIG    queueConfig;\r\n    WDF_OBJECT_ATTRIBUTES  queueAttributes;\r\n\r\n    //\r\n    // Configure a default queue so that requests that are not\r\n    // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto\r\n    // other queues get dispatched here.\r\n    //\r\n    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(\r\n         &queueConfig,\r\n        WdfIoQueueDispatchSequential\r\n        );\r\n\r\n    queueConfig.EvtIoRead   = EchoEvtIoRead;\r\n    queueConfig.EvtIoWrite  = EchoEvtIoWrite;\r\n\r\n    //\r\n    // Fill in a callback for destroy, and our QUEUE_CONTEXT size\r\n    //\r\n    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT);\r\n\r\n    //\r\n    // Set synchronization scope on queue and have the timer to use queue as\r\n    // the parent object so that queue and timer callbacks are synchronized\r\n    // with the same lock.\r\n    //\r\n    queueAttributes.SynchronizationScope = WdfSynchronizationScopeQueue;\r\n\r\n    queueAttributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy;\r\n\r\n    status = WdfIoQueueCreate(\r\n                 Device,\r\n                 &queueConfig,\r\n                 &queueAttributes,\r\n                 &queue\r\n                 );\r\n\r\n    if( !NT_SUCCESS(status) ) {\r\n        KdPrint((\"WdfIoQueueCreate failed 0x%x\\n\",status));\r\n        return status;\r\n    }\r\n\r\n    // Get our Driver Context memory from the returned Queue handle\r\n    queueContext = QueueGetContext(queue);\r\n\r\n    queueContext->WriteMemory = NULL;\r\n    queueContext->Timer = NULL;\r\n\r\n    queueContext->CurrentRequest = NULL;\r\n    queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST;\r\n\r\n    //\r\n    // Create the Queue timer\r\n    //\r\n    status = EchoTimerCreate(&queueContext->Timer, queue);\r\n    if (!NT_SUCCESS(status)) {\r\n        KdPrint((\"Error creating timer 0x%x\\n\",status));\r\n        return status;\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nEchoTimerCreate(\r\n    IN WDFTIMER*       Timer,\r\n    IN WDFQUEUE        Queue\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Subroutine to create timer. By associating the timerobject with\r\n    the queue, we are basically telling the framework to serialize the queue\r\n    callbacks with the timer callback. By doing so, we don't have to worry\r\n    about protecting queue-context structure from multiple threads accessing\r\n    it simultaneously.\r\n\r\nArguments:\r\n\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    NTSTATUS Status;\r\n    WDF_TIMER_CONFIG       timerConfig;\r\n    WDF_OBJECT_ATTRIBUTES  timerAttributes;\r\n\r\n    //\r\n    // Create a non-periodic timer since WDF does not allow periodic timer\r\n    // at passive level, which is the level UMDF callbacks are invoked at.\r\n    // The workaround is to always restart the timer in the timer callback.\r\n    //\r\n    // WDF_TIMER_CONFIG_INIT sets AutomaticSerialization to TRUE by default.\r\n    //\r\n    WDF_TIMER_CONFIG_INIT(&timerConfig, EchoEvtTimerFunc);\r\n\r\n    WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);\r\n    timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue\r\n    timerAttributes.ExecutionLevel = WdfExecutionLevelPassive;\r\n\r\n    Status = WdfTimerCreate(&timerConfig,\r\n                             &timerAttributes,\r\n                             Timer     // Output handle\r\n                             );\r\n\r\n    return Status;\r\n}\r\n\r\n\r\n\r\nVOID\r\nEchoEvtIoQueueContextDestroy(\r\n    WDFOBJECT Object\r\n)\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is called when the Queue that our driver context memory\r\n    is associated with is destroyed.\r\n\r\nArguments:\r\n\r\n    Context - Context that's being freed.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(Object);\r\n\r\n    //\r\n    // Release any resources pointed to in the queue context.\r\n    //\r\n    // The body of the queue context will be released after\r\n    // this callback handler returns\r\n    //\r\n\r\n    //\r\n    // If Queue context has an I/O buffer, release it\r\n    //\r\n    if( queueContext->WriteMemory != NULL ) {\r\n        WdfObjectDelete(queueContext->WriteMemory);\r\n        queueContext->WriteMemory = NULL;\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nEchoEvtRequestCancel(\r\n    IN WDFREQUEST Request\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n\r\n    Called when an I/O request is cancelled after the driver has marked\r\n    the request cancellable. This callback is automatically synchronized\r\n    with the I/O callbacks since we have chosen to use frameworks Device\r\n    level locking.\r\n\r\nArguments:\r\n\r\n    Request - Request being cancelled.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(WdfRequestGetIoQueue(Request));\r\n\r\n    KdPrint((\"EchoEvtRequestCancel called on Request 0x%p\\n\",  Request));\r\n\r\n    //\r\n    // The following is race free by the callside or DPC side\r\n    // synchronizing completion by calling\r\n    // WdfRequestMarkCancelable(Queue, Request, FALSE) before\r\n    // completion and not calling WdfRequestComplete if the\r\n    // return status == STATUS_CANCELLED.\r\n    //\r\n    WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L);\r\n\r\n    //\r\n    // This book keeping is synchronized by the common\r\n    // Queue presentation lock\r\n    //\r\n    ASSERT(queueContext->CurrentRequest == Request);\r\n    queueContext->CurrentRequest = NULL;\r\n\r\n    return;\r\n}\r\n\r\nVOID\r\nEchoEvtIoRead(\r\n    IN WDFQUEUE   Queue,\r\n    IN WDFREQUEST Request,\r\n    IN size_t      Length\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is called when the framework receives IRP_MJ_READ request.\r\n    It will copy the content from the queue-context buffer to the request buffer.\r\n    If the driver hasn't received any write request earlier, the read returns zero.\r\n\r\nArguments:\r\n\r\n    Queue -  Handle to the framework queue object that is associated with the\r\n             I/O request.\r\n\r\n    Request - Handle to a framework request object.\r\n\r\n    Length  - number of bytes to be read.\r\n              The default property of the queue is to not dispatch\r\n              zero lenght read & write requests to the driver and\r\n              complete is with status success. So we will never get\r\n              a zero length request.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS Status;\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);\r\n    WDFMEMORY memory;\r\n    size_t writeMemoryLength;\r\n\r\n    _Analysis_assume_(Length > 0);\r\n\r\n    KdPrint((\"EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\\n\",\r\n             Queue,Request,Length));\r\n    //\r\n    // No data to read\r\n    //\r\n    if( (queueContext->WriteMemory == NULL)  ) {\r\n        WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);\r\n        return;\r\n    }\r\n\r\n    //\r\n    // Read what we have\r\n    //\r\n    WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength);\r\n    _Analysis_assume_(writeMemoryLength > 0);\r\n\r\n    if( writeMemoryLength < Length ) {\r\n        Length = writeMemoryLength;\r\n    }\r\n\r\n    //\r\n    // Get the request memory\r\n    //\r\n    Status = WdfRequestRetrieveOutputMemory(Request, &memory);\r\n    if( !NT_SUCCESS(Status) ) {\r\n        KdPrint((\"EchoEvtIoRead Could not get request memory buffer 0x%x\\n\", Status));\r\n        WdfVerifierDbgBreakPoint();\r\n        WdfRequestCompleteWithInformation(Request, Status, 0L);\r\n        return;\r\n    }\r\n\r\n    // Copy the memory out\r\n    Status = WdfMemoryCopyFromBuffer( memory, // destination\r\n                             0,      // offset into the destination memory\r\n                             WdfMemoryGetBuffer(queueContext->WriteMemory, NULL),\r\n                             Length );\r\n    if( !NT_SUCCESS(Status) ) {\r\n        KdPrint((\"EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\\n\", Status));\r\n        WdfRequestComplete(Request, Status);\r\n        return;\r\n    }\r\n\r\n    // Set transfer information\r\n    WdfRequestSetInformation(Request, (ULONG_PTR)Length);\r\n\r\n    // Mark the request is cancelable\r\n    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);\r\n\r\n\r\n    // Defer the completion to another thread from the timer dpc\r\n    queueContext->CurrentRequest = Request;\r\n    queueContext->CurrentStatus  = Status;\r\n\r\n    return;\r\n}\r\n\r\nVOID\r\nEchoEvtIoWrite(\r\n    IN WDFQUEUE   Queue,\r\n    IN WDFREQUEST Request,\r\n    IN size_t     Length\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This event is invoked when the framework receives IRP_MJ_WRITE request.\r\n    This routine allocates memory buffer, copies the data from the request to it,\r\n    and stores the buffer pointer in the queue-context with the length variable\r\n    representing the buffers length. The actual completion of the request\r\n    is defered to the periodic timer dpc.\r\n\r\nArguments:\r\n\r\n    Queue -  Handle to the framework queue object that is associated with the\r\n             I/O request.\r\n\r\n    Request - Handle to a framework request object.\r\n\r\n    Length  - number of bytes to be read.\r\n              The default property of the queue is to not dispatch\r\n              zero lenght read & write requests to the driver and\r\n              complete is with status success. So we will never get\r\n              a zero length request.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS Status;\r\n    WDFMEMORY memory;\r\n    PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);\r\n    PVOID writeBuffer = NULL;\r\n\r\n    _Analysis_assume_(Length > 0);\r\n\r\n    KdPrint((\"EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\\n\",\r\n             Queue,Request,Length));\r\n\r\n    if( Length > MAX_WRITE_LENGTH ) {\r\n        KdPrint((\"EchoEvtIoWrite Buffer Length to big %d, Max is %d\\n\",\r\n                 Length,MAX_WRITE_LENGTH));\r\n        WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L);\r\n        return;\r\n    }\r\n\r\n    // Get the memory buffer\r\n    Status = WdfRequestRetrieveInputMemory(Request, &memory);\r\n    if( !NT_SUCCESS(Status) ) {\r\n        KdPrint((\"EchoEvtIoWrite Could not get request memory buffer 0x%x\\n\",\r\n                 Status));\r\n        WdfVerifierDbgBreakPoint();\r\n        WdfRequestComplete(Request, Status);\r\n        return;\r\n    }\r\n\r\n    // Release previous buffer if set\r\n    if( queueContext->WriteMemory != NULL ) {\r\n        WdfObjectDelete(queueContext->WriteMemory);\r\n        queueContext->WriteMemory = NULL;\r\n    }\r\n\r\n    Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES,\r\n                             NonPagedPoolNx,\r\n                             'sam1',\r\n                             Length,\r\n                             &queueContext->WriteMemory,\r\n                             &writeBuffer\r\n                             );\r\n\r\n    if(!NT_SUCCESS(Status)) {\r\n        KdPrint((\"EchoEvtIoWrite: Could not allocate %d byte buffer\\n\", Length));\r\n        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);\r\n        return;\r\n    }\r\n\r\n\r\n    // Copy the memory in\r\n    Status = WdfMemoryCopyToBuffer( memory,\r\n                                    0,  // offset into the source memory\r\n                                    writeBuffer,\r\n                                    Length );\r\n    if( !NT_SUCCESS(Status) ) {\r\n        KdPrint((\"EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\\n\", Status));\r\n        WdfVerifierDbgBreakPoint();\r\n\r\n        WdfObjectDelete(queueContext->WriteMemory);\r\n        queueContext->WriteMemory = NULL;\r\n\r\n        WdfRequestComplete(Request, Status);\r\n        return;\r\n    }\r\n\r\n    // Set transfer information\r\n    WdfRequestSetInformation(Request, (ULONG_PTR)Length);\r\n\r\n    // Specify the request is cancelable\r\n    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);\r\n\r\n    // Defer the completion to another thread from the timer dpc\r\n    queueContext->CurrentRequest = Request;\r\n    queueContext->CurrentStatus  = Status;\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nEchoEvtTimerFunc(\r\n    IN WDFTIMER     Timer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the TimerDPC the driver sets up to complete requests.\r\n    This function is registered when the WDFTIMER object is created, and\r\n    will automatically synchronize with the I/O Queue callbacks\r\n    and cancel routine.\r\n\r\nArguments:\r\n\r\n    Timer - Handle to a framework Timer object.\r\n\r\nReturn Value:\r\n\r\n    VOID\r\n\r\n--*/\r\n{\r\n    NTSTATUS      Status;\r\n    WDFREQUEST     Request;\r\n    WDFQUEUE queue;\r\n    PQUEUE_CONTEXT queueContext ;\r\n\r\n    queue = WdfTimerGetParentObject(Timer);\r\n    queueContext = QueueGetContext(queue);\r\n\r\n    //\r\n    // DPC is automatically synchronized to the Queue lock,\r\n    // so this is race free without explicit driver managed locking.\r\n    //\r\n    Request = queueContext->CurrentRequest;\r\n    if( Request != NULL ) {\r\n\r\n        //\r\n        // Attempt to remove cancel status from the request.\r\n        //\r\n        // The request is not completed if it is already cancelled\r\n        // since the EchoEvtIoCancel function has run, or is about to run\r\n        // and we are racing with it.\r\n        //\r\n        Status = WdfRequestUnmarkCancelable(Request);\r\n        if( Status != STATUS_CANCELLED ) {\r\n\r\n            queueContext->CurrentRequest = NULL;\r\n            Status = queueContext->CurrentStatus;\r\n\r\n            KdPrint((\"CustomTimerDPC Completing request 0x%p, Status 0x%x \\n\", Request,Status));\r\n\r\n            WdfRequestComplete(Request, Status);\r\n        }\r\n        else {\r\n            KdPrint((\"CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\\n\",\r\n                                Request));\r\n        }\r\n    }\r\n\r\n    //\r\n    // Restart the Timer since WDF does not allow periodic timer\r\n    // with autosynchronization at passive level\r\n    //\r\n    WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(TIMER_PERIOD));\r\n\r\n    return;\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/driver/queue.h",
    "content": "/*++\r\n\r\nCopyright (c) 1990-2000  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    queue.h\r\n\r\nAbstract:\r\n\r\n    This is a C version of a very simple sample driver that illustrates\r\n    how to use the driver framework and demonstrates best practices.\r\n\r\n--*/\r\n\r\n// Set max write length for testing\r\n#define MAX_WRITE_LENGTH 1024*40\r\n\r\n// Set timer period in ms\r\n#define TIMER_PERIOD     1000*2\r\n\r\n//\r\n// This is the context that can be placed per queue\r\n// and would contain per queue information.\r\n//\r\ntypedef struct _QUEUE_CONTEXT {\r\n\r\n    // Here we allocate a buffer from a test write so it can be read back\r\n    WDFMEMORY WriteMemory;\r\n\r\n    // Timer DPC for this queue\r\n    WDFTIMER   Timer;\r\n\r\n    // Virtual I/O\r\n    WDFREQUEST  CurrentRequest;\r\n    NTSTATUS   CurrentStatus;\r\n\r\n} QUEUE_CONTEXT, *PQUEUE_CONTEXT;\r\n\r\nWDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)\r\n\r\nNTSTATUS\r\nEchoQueueInitialize(\r\n    WDFDEVICE hDevice\r\n    );\r\n\r\nEVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy;\r\n\r\n//\r\n// Events from the IoQueue object\r\n//\r\nEVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel;\r\nEVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead;\r\nEVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite;\r\n\r\nNTSTATUS\r\nEchoTimerCreate(\r\n    IN WDFTIMER*       pTimer,\r\n    IN WDFQUEUE        Queue\r\n    );\r\n\r\nEVT_WDF_TIMER EchoEvtTimerFunc;\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/exe/echoapp.cpp",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    EchoApp.cpp\r\n\r\nAbstract:\r\n\r\n    An application to exercise the WDF \"echo\" sample driver.\r\n\r\n\r\nEnvironment:\r\n\r\n    user mode only\r\n\r\n--*/\r\n\r\n\r\n#include <DriverSpecs.h>\r\n_Analysis_mode_(_Analysis_code_type_user_code_)\r\n\r\n#define INITGUID\r\n\r\n#include <windows.h>\r\n#include <strsafe.h>\r\n#include <cfgmgr32.h>\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include \"public.h\"\r\n\r\n#define NUM_ASYNCH_IO   100\r\n#define BUFFER_SIZE     (40*1024)\r\n\r\n#define READER_TYPE   1\r\n#define WRITER_TYPE   2\r\n\r\n#define MAX_DEVPATH_LENGTH                       256\r\n\r\nBOOLEAN G_PerformAsyncIo;\r\nBOOLEAN G_LimitedLoops;\r\nULONG G_AsyncIoLoopsNum;\r\nWCHAR G_DevicePath[MAX_DEVPATH_LENGTH];\r\n\r\n\r\nULONG\r\nAsyncIo(\r\n    PVOID   ThreadParameter\r\n    );\r\n\r\nBOOLEAN\r\nPerformWriteReadTest(\r\n    IN HANDLE hDevice,\r\n    IN ULONG TestLength\r\n    );\r\n\r\nBOOL\r\nGetDevicePath(\r\n    IN  LPGUID InterfaceGuid,\r\n    _Out_writes_(BufLen) PWCHAR DevicePath,\r\n    _In_ size_t BufLen\r\n    );\r\n\r\n\r\nint __cdecl\r\nmain(\r\n    _In_ int argc,\r\n    _In_reads_(argc) char* argv[]\r\n    )\r\n{\r\n    HANDLE hDevice = INVALID_HANDLE_VALUE;\r\n    HANDLE  th1 = NULL;\r\n    BOOLEAN result = TRUE;\r\n\r\n\r\n    if (argc > 1)  {\r\n        if(!_strnicmp (argv[1], \"-Async\", 6) ) {\r\n            G_PerformAsyncIo = TRUE;\r\n            if (argc > 2) {\r\n                G_AsyncIoLoopsNum = atoi(argv[2]);\r\n                G_LimitedLoops = TRUE;\r\n            }\r\n            else {\r\n                G_LimitedLoops = FALSE;\r\n            }\r\n\r\n        } else {\r\n            printf(\"Usage:\\n\");\r\n            printf(\"    Echoapp.exe         --- Send single write and read request synchronously\\n\");\r\n            printf(\"    Echoapp.exe -Async  --- Send reads and writes asynchronously without terminating\\n\");\r\n            printf(\"    Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\\n\");\r\n            printf(\"Exit the app anytime by pressing Ctrl-C\\n\");\r\n            result = FALSE;\r\n            goto exit;\r\n        }\r\n    }\r\n\r\n    if ( !GetDevicePath(\r\n            (LPGUID) &GUID_DEVINTERFACE_ECHO,\r\n            G_DevicePath,\r\n            sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) )\r\n    {\r\n        result = FALSE;\r\n        goto exit;\r\n    }\r\n\r\n    printf(\"DevicePath: %ws\\n\", G_DevicePath);\r\n\r\n    hDevice = CreateFile(G_DevicePath,\r\n                         GENERIC_READ|GENERIC_WRITE,\r\n                         FILE_SHARE_READ | FILE_SHARE_WRITE,\r\n                         NULL,\r\n                         OPEN_EXISTING,\r\n                         0,\r\n                         NULL );\r\n\r\n    if (hDevice == INVALID_HANDLE_VALUE) {\r\n        printf(\"Failed to open device. Error %d\\n\",GetLastError());\r\n        result = FALSE;\r\n        goto exit;\r\n    }\r\n\r\n    printf(\"Opened device successfully\\n\");\r\n\r\n    if(G_PerformAsyncIo) {\r\n\r\n        printf(\"Starting AsyncIo\\n\");\r\n\r\n        //\r\n        // Create a reader thread\r\n        //\r\n        th1 = CreateThread( NULL,                   // Default Security Attrib.\r\n                            0,                      // Initial Stack Size,\r\n                            (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func\r\n                            (LPVOID)READER_TYPE,\r\n                            0,                      // Creation Flags\r\n                            NULL );                 // Don't need the Thread Id.\r\n\r\n        if (th1 == NULL) {\r\n            printf(\"Couldn't create reader thread - error %d\\n\", GetLastError());\r\n            result = FALSE;\r\n            goto exit;\r\n        }\r\n\r\n        //\r\n        // Use this thread for peforming write.\r\n        //\r\n        result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE);\r\n\r\n    }else {\r\n        //\r\n        // Write pattern buffers and read them back, then verify them\r\n        //\r\n        result = PerformWriteReadTest(hDevice, 512);\r\n        if(!result) {\r\n            goto exit;\r\n        }\r\n\r\n        result = PerformWriteReadTest(hDevice, 30*1024);\r\n        if(!result) {\r\n            goto exit;\r\n        }\r\n\r\n    }\r\n\r\nexit:\r\n\r\n    if (th1 != NULL) {\r\n        WaitForSingleObject(th1, INFINITE);\r\n        CloseHandle(th1);\r\n    }\r\n\r\n    if (hDevice != INVALID_HANDLE_VALUE) {\r\n        CloseHandle(hDevice);\r\n    }\r\n\r\n    return ((result == TRUE) ? 0 : 1);\r\n\r\n}\r\n\r\nPUCHAR\r\nCreatePatternBuffer(\r\n    IN ULONG Length\r\n    )\r\n{\r\n    unsigned int i;\r\n    PUCHAR p, pBuf;\r\n\r\n    pBuf = (PUCHAR)malloc(Length);\r\n    if( pBuf == NULL ) {\r\n        printf(\"Could not allocate %d byte buffer\\n\",Length);\r\n        return NULL;\r\n    }\r\n\r\n    p = pBuf;\r\n\r\n    for(i=0; i < Length; i++ ) {\r\n        *p = (UCHAR)i;\r\n        p++;\r\n    }\r\n\r\n    return pBuf;\r\n}\r\n\r\nBOOLEAN\r\nVerifyPatternBuffer(\r\n    _In_reads_bytes_(Length) PUCHAR pBuffer,\r\n    _In_ ULONG Length\r\n    )\r\n{\r\n    unsigned int i;\r\n    PUCHAR p = pBuffer;\r\n\r\n    for( i=0; i < Length; i++ ) {\r\n\r\n        if( *p != (UCHAR)(i & 0xFF) ) {\r\n            printf(\"Pattern changed. SB 0x%x, Is 0x%x\\n\",\r\n                   (UCHAR)(i & 0xFF), *p);\r\n            return FALSE;\r\n        }\r\n\r\n        p++;\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\nBOOLEAN\r\nPerformWriteReadTest(\r\n    IN HANDLE hDevice,\r\n    IN ULONG TestLength\r\n    )\r\n/*\r\n*/\r\n{\r\n    ULONG  bytesReturned =0;\r\n    PUCHAR WriteBuffer = NULL,\r\n                   ReadBuffer = NULL;\r\n    BOOLEAN result = TRUE;\r\n\r\n    WriteBuffer = CreatePatternBuffer(TestLength);\r\n    if( WriteBuffer == NULL ) {\r\n\r\n        result = FALSE;\r\n        goto Cleanup;\r\n    }\r\n\r\n    ReadBuffer = (PUCHAR)malloc(TestLength);\r\n    if( ReadBuffer == NULL ) {\r\n\r\n        printf(\"PerformWriteReadTest: Could not allocate %d \"\r\n               \"bytes ReadBuffer\\n\",TestLength);\r\n\r\n         result = FALSE;\r\n         goto Cleanup;\r\n\r\n    }\r\n\r\n    //\r\n    // Write the pattern to the device\r\n    //\r\n    bytesReturned = 0;\r\n\r\n    if (!WriteFile ( hDevice,\r\n            WriteBuffer,\r\n            TestLength,\r\n            &bytesReturned,\r\n            NULL)) {\r\n\r\n        printf (\"PerformWriteReadTest: WriteFile failed: \"\r\n                \"Error %d\\n\", GetLastError());\r\n\r\n        result = FALSE;\r\n        goto Cleanup;\r\n\r\n    } else {\r\n\r\n        if( bytesReturned != TestLength ) {\r\n\r\n            printf(\"bytes written is not test length! Written %d, \"\r\n                   \"SB %d\\n\",bytesReturned, TestLength);\r\n\r\n            result = FALSE;\r\n            goto Cleanup;\r\n        }\r\n\r\n        printf (\"%d Pattern Bytes Written successfully\\n\",\r\n                bytesReturned);\r\n    }\r\n\r\n    bytesReturned = 0;\r\n\r\n    if ( !ReadFile (hDevice,\r\n            ReadBuffer,\r\n            TestLength,\r\n            &bytesReturned,\r\n            NULL)) {\r\n\r\n        printf (\"PerformWriteReadTest: ReadFile failed: \"\r\n                \"Error %d\\n\", GetLastError());\r\n\r\n        result = FALSE;\r\n        goto Cleanup;\r\n\r\n    } else {\r\n\r\n        if( bytesReturned != TestLength ) {\r\n\r\n            printf(\"bytes Read is not test length! Read %d, \"\r\n                   \"SB %d\\n\",bytesReturned, TestLength);\r\n\r\n             //\r\n             // Note: Is this a Failure Case??\r\n             //\r\n            result = FALSE;\r\n            goto Cleanup;\r\n        }\r\n\r\n        printf (\"%d Pattern Bytes Read successfully\\n\",bytesReturned);\r\n    }\r\n\r\n    //\r\n    // Now compare\r\n    //\r\n    if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) {\r\n\r\n        printf(\"Verify failed\\n\");\r\n\r\n        result = FALSE;\r\n        goto Cleanup;\r\n    }\r\n\r\n    printf(\"Pattern Verified successfully\\n\");\r\n\r\nCleanup:\r\n\r\n    //\r\n    // Free WriteBuffer if non NULL.\r\n    //\r\n    if (WriteBuffer) {\r\n        free (WriteBuffer);\r\n    }\r\n\r\n    //\r\n    // Free ReadBuffer if non NULL\r\n    //\r\n    if (ReadBuffer) {\r\n        free (ReadBuffer);\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nULONG\r\nAsyncIo(\r\n    PVOID  ThreadParameter\r\n    )\r\n{\r\n    HANDLE hDevice = INVALID_HANDLE_VALUE;\r\n    HANDLE hCompletionPort = NULL;\r\n    OVERLAPPED *pOvList = NULL;\r\n    PUCHAR      buf = NULL;\r\n    ULONG     numberOfBytesTransferred;\r\n    OVERLAPPED *completedOv;\r\n    ULONG_PTR    i;\r\n    ULONG   ioType = (ULONG)(ULONG_PTR)ThreadParameter;\r\n    ULONG_PTR   key;\r\n    ULONG   error;\r\n    BOOLEAN result = TRUE;\r\n    ULONG maxPendingRequests = NUM_ASYNCH_IO;\r\n    ULONG remainingRequestsToSend = 0;\r\n    ULONG remainingRequestsToReceive = 0;\r\n\r\n    hDevice = CreateFile(G_DevicePath,\r\n                     GENERIC_WRITE|GENERIC_READ,\r\n                     FILE_SHARE_READ | FILE_SHARE_WRITE,\r\n                     NULL,\r\n                     OPEN_EXISTING,\r\n                     FILE_FLAG_OVERLAPPED,\r\n                     NULL );\r\n\r\n\r\n    if (hDevice == INVALID_HANDLE_VALUE) {\r\n        printf(\"Cannot open %ws error %d\\n\", G_DevicePath, GetLastError());\r\n        result = FALSE;\r\n        goto Error;\r\n    }\r\n\r\n    hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0);\r\n    if (hCompletionPort == NULL) {\r\n        printf(\"Cannot open completion port %d \\n\",GetLastError());\r\n        result = FALSE;\r\n        goto Error;\r\n    }\r\n\r\n    //\r\n    // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any\r\n    // time (whichever is less)\r\n    //\r\n    if (G_LimitedLoops == TRUE) {\r\n        remainingRequestsToReceive = G_AsyncIoLoopsNum;\r\n        if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) {\r\n            //\r\n            // After we send the initial NUM_ASYNCH_IO, we will have additional\r\n            // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send\r\n            //\r\n            maxPendingRequests = NUM_ASYNCH_IO;\r\n            remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO;\r\n        }\r\n        else {\r\n            maxPendingRequests = G_AsyncIoLoopsNum;\r\n            remainingRequestsToSend = 0;\r\n\r\n        }\r\n    }\r\n\r\n    pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED));\r\n    if (pOvList == NULL) {\r\n        printf(\"Cannot allocate overlapped array \\n\");\r\n        result = FALSE;\r\n        goto Error;\r\n    }\r\n\r\n    buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE);\r\n    if (buf == NULL) {\r\n        printf(\"Cannot allocate buffer \\n\");\r\n        result = FALSE;\r\n        goto Error;\r\n    }\r\n\r\n    ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED));\r\n    ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE);\r\n\r\n    //\r\n    // Issue asynch I/O\r\n    //\r\n\r\n    for (i = 0; i < maxPendingRequests; i++) {\r\n        if (ioType == READER_TYPE) {\r\n            if ( ReadFile( hDevice,\r\n                      buf + (i* BUFFER_SIZE),\r\n                      BUFFER_SIZE,\r\n                      NULL,\r\n                      &pOvList[i]) == 0) {\r\n\r\n                error = GetLastError();\r\n                if (error != ERROR_IO_PENDING) {\r\n                    printf(\" %dth Read failed %d \\n\", (ULONG) i, GetLastError());\r\n                    result = FALSE;\r\n                    goto Error;\r\n                }\r\n            }\r\n\r\n        } else {\r\n            if ( WriteFile( hDevice,\r\n                      buf + (i* BUFFER_SIZE),\r\n                      BUFFER_SIZE,\r\n                      NULL,\r\n                      &pOvList[i]) == 0) {\r\n                error = GetLastError();\r\n                if (error != ERROR_IO_PENDING) {\r\n                    printf(\" %dth Write failed %d \\n\", (ULONG) i, GetLastError());\r\n                    result = FALSE;\r\n                    goto Error;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // Wait for the I/Os to complete. If one completes then reissue the I/O\r\n    //\r\n\r\n    WHILE (1) {\r\n\r\n        if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) {\r\n            printf(\"GetQueuedCompletionStatus failed %d\\n\", GetLastError());\r\n            result = FALSE;\r\n            goto Error;\r\n        }\r\n\r\n        //\r\n        // Read successfully completed. If we're doing unlimited I/Os then Issue another one.\r\n        //\r\n\r\n        if (ioType == READER_TYPE) {\r\n\r\n            i = completedOv - pOvList;\r\n            printf(\"Number of bytes read by request number %Id is %d\\n\", i, numberOfBytesTransferred);\r\n\r\n            //\r\n            // If we're done with the I/Os, then exit\r\n            //\r\n            if (G_LimitedLoops == TRUE) {\r\n                if ((--remainingRequestsToReceive) == 0) {\r\n                    break;\r\n                }\r\n\r\n                if (remainingRequestsToSend == 0) {\r\n                    continue;\r\n                }\r\n                else {\r\n                    remainingRequestsToSend--;\r\n                }\r\n            }\r\n\r\n\r\n            if ( ReadFile( hDevice,\r\n                      buf + (i * BUFFER_SIZE),\r\n                      BUFFER_SIZE,\r\n                      NULL,\r\n                      completedOv) == 0) {\r\n                error = GetLastError();\r\n                if (error != ERROR_IO_PENDING) {\r\n                    printf(\"%Idth Read failed %d \\n\", i, GetLastError());\r\n                    result = FALSE;\r\n                    goto Error;\r\n                }\r\n            }\r\n        } else {\r\n\r\n            i = completedOv - pOvList;\r\n\r\n            printf(\"Number of bytes written by request number %Id is %d\\n\", i, numberOfBytesTransferred);\r\n\r\n            //\r\n            // If we're done with the I/Os, then exit\r\n            //\r\n            if (G_LimitedLoops == TRUE) {\r\n                if ((--remainingRequestsToReceive) == 0) {\r\n                    break;\r\n                }\r\n\r\n                if (remainingRequestsToSend == 0) {\r\n                    continue;\r\n                }\r\n                else {\r\n                    remainingRequestsToSend--;\r\n                }\r\n            }\r\n\r\n\r\n            if ( WriteFile( hDevice,\r\n                      buf + (i * BUFFER_SIZE),\r\n                      BUFFER_SIZE,\r\n                      NULL,\r\n                      completedOv) == 0) {\r\n                error = GetLastError();\r\n                if (error != ERROR_IO_PENDING) {\r\n\r\n                    printf(\"%Idth write failed %d \\n\", i, GetLastError());\r\n                    result = FALSE;\r\n                    goto Error;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\nError:\r\n    if(hDevice != INVALID_HANDLE_VALUE) {\r\n        CloseHandle(hDevice);\r\n    }\r\n\r\n    if(hCompletionPort) {\r\n        CloseHandle(hCompletionPort);\r\n    }\r\n\r\n    if(buf) {\r\n        free(buf);\r\n    }\r\n    if(pOvList) {\r\n        free(pOvList);\r\n    }\r\n\r\n    return (ULONG)result;\r\n\r\n}\r\n\r\nBOOL\r\nGetDevicePath(\r\n    _In_ LPGUID InterfaceGuid,\r\n    _Out_writes_(BufLen) PWCHAR DevicePath,\r\n    _In_ size_t BufLen\r\n    )\r\n{\r\n    CONFIGRET cr = CR_SUCCESS;\r\n    PWSTR deviceInterfaceList = NULL;\r\n    ULONG deviceInterfaceListLength = 0;\r\n    PWSTR nextInterface;\r\n    HRESULT hr = E_FAIL;\r\n    BOOL bRet = TRUE;\r\n\r\n    cr = CM_Get_Device_Interface_List_Size(\r\n                &deviceInterfaceListLength,\r\n                InterfaceGuid,\r\n                NULL,\r\n                CM_GET_DEVICE_INTERFACE_LIST_PRESENT);\r\n    if (cr != CR_SUCCESS) {\r\n        printf(\"Error 0x%x retrieving device interface list size.\\n\", cr);\r\n        goto clean0;\r\n    }\r\n\r\n    if (deviceInterfaceListLength <= 1) {\r\n        bRet = FALSE;\r\n        printf(\"Error: No active device interfaces found.\\n\"\r\n            \" Is the sample driver loaded?\");\r\n        goto clean0;\r\n    }\r\n\r\n    deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR));\r\n    if (deviceInterfaceList == NULL) {\r\n        printf(\"Error allocating memory for device interface list.\\n\");\r\n        goto clean0;\r\n    }\r\n    ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR));\r\n\r\n    cr = CM_Get_Device_Interface_List(\r\n                InterfaceGuid,\r\n                NULL,\r\n                deviceInterfaceList,\r\n                deviceInterfaceListLength,\r\n                CM_GET_DEVICE_INTERFACE_LIST_PRESENT);\r\n    if (cr != CR_SUCCESS) {\r\n        printf(\"Error 0x%x retrieving device interface list.\\n\", cr);\r\n        goto clean0;\r\n    }\r\n\r\n    nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1;\r\n    if (*nextInterface != UNICODE_NULL) {\r\n        printf(\"Warning: More than one device interface instance found. \\n\"\r\n            \"Selecting first matching device.\\n\\n\");\r\n    }\r\n\r\n    hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList);\r\n    if (FAILED(hr)) {\r\n        bRet = FALSE;\r\n        printf(\"Error: StringCchCopy failed with HRESULT 0x%x\", hr);\r\n        goto clean0;\r\n    }\r\n\r\nclean0:\r\n    if (deviceInterfaceList != NULL) {\r\n        free(deviceInterfaceList);\r\n    }\r\n    if (CR_SUCCESS != cr) {\r\n        bRet = FALSE;\r\n    }\r\n\r\n    return bRet;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/exe/public.h",
    "content": "/*++\r\nCopyright (c) 1990-2000    Microsoft Corporation All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    public.h\r\n\r\nAbstract:\r\n\r\n    This module contains the common declarations shared by driver\r\n    and user applications.\r\n\r\n\r\nEnvironment:\r\n\r\n    user and kernel\r\n\r\n--*/\r\n\r\n#define WHILE(a) \\\r\n__pragma(warning(suppress:4127)) while(a)\r\n\r\n//\r\n// Define an Interface Guid so that app can find the device and talk to it.\r\n//\r\n\r\nDEFINE_GUID (GUID_DEVINTERFACE_ECHO,\r\n    0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a);\r\n// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/echo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_defines(\"_UNICODE\", \"UNICODE\")\n\ntarget(\"echo\")\n    add_rules(\"wdk.env.umdf\", \"wdk.driver\")\n\n    -- set test sign\n--    set_values(\"wdk.sign.mode\", \"test\")\n\n    -- set release sign\n--    set_values(\"wdk.sign.mode\", \"release\")\n--    set_values(\"wdk.sign.certfile\", path.join(os.projectdir(), \"xxx.cer\"))\n\n    add_files(\"driver/*.c\")\n    add_files(\"driver/*.inx\")\n    add_includedirs(\"exe\")\n\ntarget(\"app\")\n    add_rules(\"wdk.env.umdf\", \"wdk.binary\")\n    add_files(\"exe/*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/Skeleton.rc",
    "content": "//---------------------------------------------------------------------------\r\n// Skeleton.rc\r\n//\r\n// Copyright (c) Microsoft Corporation, All Rights Reserved\r\n//---------------------------------------------------------------------------\r\n\r\n\r\n#include <windows.h>\r\n#include <ntverp.h>\r\n\r\n//\r\n// TODO: Change the file description and file names to match your binary.\r\n//\r\n\r\n#define VER_FILETYPE                VFT_DLL\r\n#define VER_FILESUBTYPE             VFT_UNKNOWN\r\n#define VER_FILEDESCRIPTION_STR     \"WDF:UMDF Skeleton User-Mode Driver Sample\"\r\n#define VER_INTERNALNAME_STR        \"UMDFSkeleton\"\r\n#define VER_ORIGINALFILENAME_STR    \"UMDFSkeleton.dll\"\r\n\r\n#include \"common.ver\"\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/comsup.cpp",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    ComSup.cpp\r\n\r\nAbstract:\r\n\r\n    This module contains implementations for the functions and methods\r\n    used for providing COM support.\r\n\r\nEnvironment:\r\n\r\n    Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#include \"internal.h\"\r\n\r\n#include \"comsup.tmh\"\r\n\r\n//\r\n// Implementation of CUnknown methods.\r\n//\r\n\r\nCUnknown::CUnknown(\r\n    VOID\r\n    ) : m_ReferenceCount(1)\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    Constructor for an instance of the CUnknown class.  This simply initializes\r\n    the reference count of the object to 1.  The caller is expected to\r\n    call Release() if it wants to delete the object once it has been allocated.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    // do nothing.\r\n}\r\n\r\nHRESULT\r\nSTDMETHODCALLTYPE\r\nCUnknown::QueryInterface(\r\n    _In_ REFIID InterfaceId,\r\n    _Out_ PVOID *Object\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method provides the basic support for query interface on CUnknown.\r\n    If the interface requested is IUnknown it references the object and\r\n    returns an interface pointer.  Otherwise it returns an error.\r\n\r\n  Arguments:\r\n\r\n    InterfaceId - the IID being requested\r\n\r\n    Object - a location to store the interface pointer to return.\r\n\r\n  Return Value:\r\n\r\n    S_OK or E_NOINTERFACE\r\n\r\n--*/\r\n{\r\n    if (IsEqualIID(InterfaceId, __uuidof(IUnknown)))\r\n    {\r\n        *Object = QueryIUnknown();\r\n        return S_OK;\r\n    }\r\n    else\r\n    {\r\n        *Object = NULL;\r\n        return E_NOINTERFACE;\r\n    }\r\n}\r\n\r\nIUnknown *\r\nCUnknown::QueryIUnknown(\r\n    VOID\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This helper method references the object and returns a pointer to the\r\n    object's IUnknown interface.\r\n\r\n    This allows other methods to convert a CUnknown pointer into an IUnknown\r\n    pointer without a typecast and without calling QueryInterface and dealing\r\n    with the return value.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    A pointer to the object's IUnknown interface.\r\n\r\n--*/\r\n{\r\n    AddRef();\r\n    return static_cast<IUnknown *>(this);\r\n}\r\n\r\nULONG\r\nSTDMETHODCALLTYPE\r\nCUnknown::AddRef(\r\n    VOID\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method adds one to the object's reference count.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    The new reference count.   The caller should only use this for debugging\r\n    as the object's actual reference count can change while the caller\r\n    examines the return value.\r\n\r\n--*/\r\n{\r\n    return InterlockedIncrement(&m_ReferenceCount);\r\n}\r\n\r\nULONG\r\nSTDMETHODCALLTYPE\r\nCUnknown::Release(\r\n    VOID\r\n   )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method subtracts one to the object's reference count.  If the count\r\n    goes to zero, this method deletes the object.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    The new reference count.   If the caller uses this value it should only be\r\n    to check for zero (i.e. this call caused or will cause deletion) or\r\n    non-zero (i.e. some other call may have caused deletion, but this one\r\n    didn't).\r\n\r\n--*/\r\n{\r\n    ULONG count = InterlockedDecrement(&m_ReferenceCount);\r\n\r\n    if (count == 0)\r\n    {\r\n        delete this;\r\n    }\r\n    return count;\r\n}\r\n\r\n//\r\n// Implementation of CClassFactory methods.\r\n//\r\n\r\n//\r\n// Define storage for the factory's static lock count variable.\r\n//\r\n\r\nLONG CClassFactory::s_LockCount = 0;\r\n\r\nIClassFactory *\r\nCClassFactory::QueryIClassFactory(\r\n    VOID\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This helper method references the object and returns a pointer to the\r\n    object's IClassFactory interface.\r\n\r\n    This allows other methods to convert a CClassFactory pointer into an\r\n    IClassFactory pointer without a typecast and without dealing with the\r\n    return value QueryInterface.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    A referenced pointer to the object's IClassFactory interface.\r\n\r\n--*/\r\n{\r\n    AddRef();\r\n    return static_cast<IClassFactory *>(this);\r\n}\r\n\r\nHRESULT\r\nCClassFactory::QueryInterface(\r\n    _In_ REFIID InterfaceId,\r\n    _Out_ PVOID *Object\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method attempts to retrieve the requested interface from the object.\r\n\r\n    If the interface is found then the reference count on that interface (and\r\n    thus the object itself) is incremented.\r\n\r\n  Arguments:\r\n\r\n    InterfaceId - the interface the caller is requesting.\r\n\r\n    Object - a location to store the interface pointer.\r\n\r\n  Return Value:\r\n\r\n    S_OK or E_NOINTERFACE\r\n\r\n--*/\r\n{\r\n    //\r\n    // This class only supports IClassFactory so check for that.\r\n    //\r\n\r\n    if (IsEqualIID(InterfaceId, __uuidof(IClassFactory)))\r\n    {\r\n        *Object = QueryIClassFactory();\r\n        return S_OK;\r\n    }\r\n    else\r\n    {\r\n        //\r\n        // See if the base class supports the interface.\r\n        //\r\n\r\n        return CUnknown::QueryInterface(InterfaceId, Object);\r\n    }\r\n}\r\n\r\nHRESULT\r\nSTDMETHODCALLTYPE\r\nCClassFactory::CreateInstance(\r\n    _In_opt_ IUnknown * /* OuterObject */,\r\n    _In_ REFIID InterfaceId,\r\n    _Out_ PVOID *Object\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This COM method is the factory routine - it creates instances of the driver\r\n    callback class and returns the specified interface on them.\r\n\r\n  Arguments:\r\n\r\n    OuterObject - only used for aggregation, which our driver callback class\r\n                  does not support.\r\n\r\n    InterfaceId - the interface ID the caller would like to get from our\r\n                  new object.\r\n\r\n    Object - a location to store the referenced interface pointer to the new\r\n             object.\r\n\r\n  Return Value:\r\n\r\n    Status.\r\n\r\n--*/\r\n{\r\n    HRESULT hr;\r\n\r\n    PCMyDriver driver;\r\n\r\n    *Object = NULL;\r\n\r\n    hr = CMyDriver::CreateInstance(&driver);\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        hr = driver->QueryInterface(InterfaceId, Object);\r\n        driver->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\nHRESULT\r\nSTDMETHODCALLTYPE\r\nCClassFactory::LockServer(\r\n    _In_ BOOL Lock\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This COM method can be used to keep the DLL in memory.  However since the\r\n    driver's DllCanUnloadNow function always returns false, this has little\r\n    effect.  Still it tracks the number of lock and unlock operations.\r\n\r\n  Arguments:\r\n\r\n    Lock - Whether the caller wants to lock or unlock the \"server\"\r\n\r\n  Return Value:\r\n\r\n    S_OK\r\n\r\n--*/\r\n{\r\n    if (Lock)\r\n    {\r\n        InterlockedIncrement(&s_LockCount);\r\n    }\r\n    else\r\n    {\r\n        InterlockedDecrement(&s_LockCount);\r\n    }\r\n    return S_OK;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/comsup.h",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    ComSup.h\r\n\r\nAbstract:\r\n\r\n    This module contains classes and functions use for providing COM support\r\n    code.\r\n\r\nEnvironment:\r\n\r\n    Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n//\r\n// Forward type declarations.  They are here rather than in internal.h as\r\n// you only need them if you choose to use these support classes.\r\n//\r\n\r\ntypedef class CUnknown *PCUnknown;\r\ntypedef class CClassFactory *PCClassFactory;\r\n\r\n//\r\n// Base class to implement IUnknown.  You can choose to derive your COM\r\n// classes from this class, or simply implement IUnknown in each of your\r\n// classes.\r\n//\r\n\r\nclass CUnknown : public IUnknown\r\n{\r\n\r\n//\r\n// Private data members and methods.  These are only accessible by the methods\r\n// of this class.\r\n//\r\nprivate:\r\n\r\n    //\r\n    // The reference count for this object.  Initialized to 1 in the\r\n    // constructor.\r\n    //\r\n\r\n    LONG m_ReferenceCount;\r\n\r\n//\r\n// Protected data members and methods.  These are accessible by the subclasses\r\n// but not by other classes.\r\n//\r\nprotected:\r\n\r\n    //\r\n    // The constructor and destructor are protected to ensure that only the\r\n    // subclasses of CUnknown can create and destroy instances.\r\n    //\r\n\r\n    CUnknown(\r\n        VOID\r\n        );\r\n\r\n    //\r\n    // The destructor MUST be virtual.  Since any instance of a CUnknown\r\n    // derived class should only be deleted from within CUnknown::Release,\r\n    // the destructor MUST be virtual or only CUnknown::~CUnknown will get\r\n    // invoked on deletion.\r\n    //\r\n    // If you see that your CMyDevice specific destructor is never being\r\n    // called, make sure you haven't deleted the virtual destructor here.\r\n    //\r\n\r\n    virtual\r\n    ~CUnknown(\r\n        VOID\r\n        )\r\n    {\r\n        // Do nothing\r\n    }\r\n\r\n//\r\n// Public Methods.  These are accessible by any class.\r\n//\r\npublic:\r\n\r\n    IUnknown *\r\n    QueryIUnknown(\r\n        VOID\r\n        );\r\n\r\n//\r\n// COM Methods.\r\n//\r\npublic:\r\n\r\n    //\r\n    // IUnknown methods\r\n    //\r\n\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    AddRef(\r\n        VOID\r\n        );\r\n\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    Release(\r\n        VOID\r\n       );\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    QueryInterface(\r\n        _In_ REFIID InterfaceId,\r\n        _Out_ PVOID *Object\r\n        );\r\n};\r\n\r\n//\r\n// Class factory support class.  Create an instance of this from your\r\n// DllGetClassObject method and modify the implementation to create\r\n// an instance of your driver event handler class.\r\n//\r\n\r\nclass CClassFactory : public CUnknown, public IClassFactory\r\n{\r\n//\r\n// Private data members and methods.  These are only accessible by the methods\r\n// of this class.\r\n//\r\nprivate:\r\n\r\n    //\r\n    // The lock count.  This is shared across all instances of IClassFactory\r\n    // and can be queried through the public IsLocked method.\r\n    //\r\n\r\n    static LONG s_LockCount;\r\n\r\n//\r\n// Public Methods.  These are accessible by any class.\r\n//\r\npublic:\r\n\r\n    IClassFactory *\r\n    QueryIClassFactory(\r\n        VOID\r\n        );\r\n\r\n//\r\n// COM Methods.\r\n//\r\npublic:\r\n\r\n    //\r\n    // IUnknown methods\r\n    //\r\n\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    AddRef(\r\n        VOID\r\n        )\r\n    {\r\n        return __super::AddRef();\r\n    }\r\n\r\n    _At_(this, __drv_freesMem(object))\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    Release(\r\n        VOID\r\n       )\r\n    {\r\n        return __super::Release();\r\n    }\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    QueryInterface(\r\n        _In_ REFIID InterfaceId,\r\n        _Out_ PVOID *Object\r\n        );\r\n\r\n    //\r\n    // IClassFactory methods.\r\n    //\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    CreateInstance(\r\n        _In_opt_ IUnknown *OuterObject,\r\n        _In_ REFIID InterfaceId,\r\n        _Out_ PVOID *Object\r\n        );\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    LockServer(\r\n        _In_ BOOL Lock\r\n        );\r\n};\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/device.cpp",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved.\r\n\r\nModule Name:\r\n\r\n    Device.cpp\r\n\r\nAbstract:\r\n\r\n    This module contains the implementation of the UMDF Skeleton sample driver's\r\n    device callback object.\r\n\r\n    The skeleton sample device does very little.  It does not implement either\r\n    of the PNP interfaces so once the device is setup, it won't ever get any\r\n    callbacks until the device is removed.\r\n\r\nEnvironment:\r\n\r\n   Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#include \"internal.h\"\r\n#include \"device.tmh\"\r\n\r\nHRESULT\r\nCMyDevice::CreateInstance(\r\n    _In_ IWDFDriver *FxDriver,\r\n    _In_ IWDFDeviceInitialize * FxDeviceInit,\r\n    _Out_ PCMyDevice *Device\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method creates and initializs an instance of the skeleton driver's\r\n    device callback object.\r\n\r\n  Arguments:\r\n\r\n    FxDeviceInit - the settings for the device.\r\n\r\n    Device - a location to store the referenced pointer to the device object.\r\n\r\n  Return Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PCMyDevice device;\r\n    HRESULT hr;\r\n\r\n    //\r\n    // Allocate a new instance of the device class.\r\n    //\r\n\r\n    device = new CMyDevice();\r\n\r\n    if (NULL == device)\r\n    {\r\n        return E_OUTOFMEMORY;\r\n    }\r\n\r\n    //\r\n    // Initialize the instance.\r\n    //\r\n\r\n    hr = device->Initialize(FxDriver, FxDeviceInit);\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        *Device = device;\r\n    }\r\n    else\r\n    {\r\n        device->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\nHRESULT\r\nCMyDevice::Initialize(\r\n    _In_ IWDFDriver           * FxDriver,\r\n    _In_ IWDFDeviceInitialize * FxDeviceInit\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method initializes the device callback object and creates the\r\n    partner device object.\r\n\r\n    The method should perform any device-specific configuration that:\r\n        *  could fail (these can't be done in the constructor)\r\n        *  must be done before the partner object is created -or-\r\n        *  can be done after the partner object is created and which aren't\r\n           influenced by any device-level parameters the parent (the driver\r\n           in this case) might set.\r\n\r\n  Arguments:\r\n\r\n    FxDeviceInit - the settings for this device.\r\n\r\n  Return Value:\r\n\r\n    status.\r\n\r\n--*/\r\n{\r\n    IWDFDevice *fxDevice;\r\n    HRESULT hr;\r\n\r\n    //\r\n    // Configure things like the locking model before we go to create our\r\n    // partner device.\r\n    //\r\n\r\n    //\r\n    // Set no locking unless you need an automatic callbacks synchronization\r\n    //\r\n\r\n    FxDeviceInit->SetLockingConstraint(None);\r\n\r\n    //\r\n    // TODO: If you're writing a filter driver then indicate that here.\r\n    //\r\n    // FxDeviceInit->SetFilter();\r\n    //\r\n\r\n    //\r\n    // TODO: Any per-device initialization which must be done before\r\n    //       creating the partner object.\r\n    //\r\n\r\n    //\r\n    // Create a new FX device object and assign the new callback object to\r\n    // handle any device level events that occur.\r\n    //\r\n\r\n    //\r\n    // QueryIUnknown references the IUnknown interface that it returns\r\n    // (which is the same as referencing the device).  We pass that to\r\n    // CreateDevice, which takes its own reference if everything works.\r\n    //\r\n\r\n    {\r\n        IUnknown *unknown = this->QueryIUnknown();\r\n\r\n        hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice);\r\n\r\n        unknown->Release();\r\n    }\r\n\r\n    //\r\n    // If that succeeded then set our FxDevice member variable.\r\n    //\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        m_FxDevice = fxDevice;\r\n\r\n        //\r\n        // Drop the reference we got from CreateDevice.  Since this object\r\n        // is partnered with the framework object they have the same\r\n        // lifespan - there is no need for an additional reference.\r\n        //\r\n\r\n        fxDevice->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\nHRESULT\r\nCMyDevice::Configure(\r\n    VOID\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method is called after the device callback object has been initialized\r\n    and returned to the driver.  It would setup the device's queues and their\r\n    corresponding callback objects.\r\n\r\n  Arguments:\r\n\r\n    FxDevice - the framework device object for which we're handling events.\r\n\r\n  Return Value:\r\n\r\n    status\r\n\r\n--*/\r\n{\r\n    //\r\n    // TODO: Setup your device queues and I/O forwarding.\r\n    //\r\n\r\n    return S_OK;\r\n}\r\n\r\nHRESULT\r\nCMyDevice::QueryInterface(\r\n    _In_ REFIID InterfaceId,\r\n    _Out_ PVOID *Object\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method is called to get a pointer to one of the object's callback\r\n    interfaces.\r\n\r\n    Since the skeleton driver doesn't support any of the device events, this\r\n    method simply calls the base class's BaseQueryInterface.\r\n\r\n    If the skeleton is extended to include device event interfaces then this\r\n    method must be changed to check the IID and return pointers to them as\r\n    appropriate.\r\n\r\n  Arguments:\r\n\r\n    InterfaceId - the interface being requested\r\n\r\n    Object - a location to store the interface pointer if successful\r\n\r\n  Return Value:\r\n\r\n    S_OK or E_NOINTERFACE\r\n\r\n--*/\r\n{\r\n    return CUnknown::QueryInterface(InterfaceId, Object);\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/device.h",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    Device.h\r\n\r\nAbstract:\r\n\r\n    This module contains the type definitions for the UMDF Skeleton sample\r\n    driver's device callback class.\r\n\r\nEnvironment:\r\n\r\n    Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n//\r\n// Class for the iotrace driver.\r\n//\r\n\r\nclass CMyDevice : public CUnknown\r\n{\r\n\r\n//\r\n// Private data members.\r\n//\r\nprivate:\r\n\r\n    IWDFDevice *m_FxDevice;\r\n\r\n//\r\n// Private methods.\r\n//\r\n\r\nprivate:\r\n\r\n    CMyDevice(\r\n        VOID\r\n        )\r\n    {\r\n        m_FxDevice = NULL;\r\n    }\r\n\r\n    HRESULT\r\n    Initialize(\r\n        _In_ IWDFDriver *FxDriver,\r\n        _In_ IWDFDeviceInitialize *FxDeviceInit\r\n        );\r\n\r\n//\r\n// Public methods\r\n//\r\npublic:\r\n\r\n    //\r\n    // The factory method used to create an instance of this driver.\r\n    //\r\n\r\n    static\r\n    HRESULT\r\n    CreateInstance(\r\n        _In_ IWDFDriver *FxDriver,\r\n        _In_ IWDFDeviceInitialize *FxDeviceInit,\r\n        _Out_ PCMyDevice *Device\r\n        );\r\n\r\n    HRESULT\r\n    Configure(\r\n        VOID\r\n        );\r\n\r\n//\r\n// COM methods\r\n//\r\npublic:\r\n\r\n    //\r\n    // IUnknown methods.\r\n    //\r\n\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    AddRef(\r\n        VOID\r\n        )\r\n    {\r\n        return __super::AddRef();\r\n    }\r\n\r\n    _At_(this, __drv_freesMem(object))\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    Release(\r\n        VOID\r\n       )\r\n    {\r\n        return __super::Release();\r\n    }\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    QueryInterface(\r\n        _In_ REFIID InterfaceId,\r\n        _Out_ PVOID *Object\r\n        );\r\n\r\n};\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/dllsup.cpp",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved.\r\n\r\nModule Name:\r\n\r\n    dllsup.cpp\r\n\r\nAbstract:\r\n\r\n    This module contains the implementation of the UMDF Skeleton Sample\r\n    Driver's entry point and its exported functions for providing COM support.\r\n\r\n    This module can be copied without modification to a new UMDF driver.  It\r\n    depends on some of the code in comsup.cpp & comsup.h to handle DLL\r\n    registration and creating the first class factory.\r\n\r\n    This module is dependent on the following defines:\r\n\r\n        MYDRIVER_TRACING_ID -      A wide string passed to WPP when initializing\r\n                                   tracing.  For example the skeleton uses\r\n                                   L\"Microsoft\\\\UMDF\\\\Skeleton\"\r\n\r\n        MYDRIVER_CLASS_ID -   A GUID encoded in struct format used to\r\n                              initialize the driver's ClassID.\r\n\r\n    These are defined in internal.h for the sample.  If you choose\r\n    to use a different primary include file, you should ensure they are\r\n    defined there as well.\r\n\r\nEnvironment:\r\n\r\n    WDF User-Mode Driver Framework (WDF:UMDF)\r\n\r\n--*/\r\n\r\n#include \"internal.h\"\r\n#include \"dllsup.tmh\"\r\n\r\nconst GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID;\r\n\r\nBOOL\r\nWINAPI\r\nDllMain(\r\n    HINSTANCE ModuleHandle,\r\n    DWORD Reason,\r\n    PVOID /* Reserved */\r\n   )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This is the entry point and exit point for the I/O trace driver.  This\r\n    does very little as the I/O trace driver has minimal global data.\r\n\r\n    This method initializes tracing.\r\n\r\n  Arguments:\r\n\r\n    ModuleHandle - the DLL handle for this module.\r\n\r\n    Reason - the reason this entry point was called.\r\n\r\n    Reserved - unused\r\n\r\n  Return Value:\r\n\r\n    TRUE\r\n\r\n--*/\r\n{\r\n\r\n    UNREFERENCED_PARAMETER( ModuleHandle );\r\n\r\n    if (DLL_PROCESS_ATTACH == Reason)\r\n    {\r\n        //\r\n        // Initialize tracing.\r\n        //\r\n\r\n        WPP_INIT_TRACING(MYDRIVER_TRACING_ID);\r\n\r\n    }\r\n    else if (DLL_PROCESS_DETACH == Reason)\r\n    {\r\n        //\r\n        // Cleanup tracing.\r\n        //\r\n\r\n        WPP_CLEANUP();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\nHRESULT\r\nSTDAPICALLTYPE\r\nDllGetClassObject(\r\n    _In_ REFCLSID ClassId,\r\n    _In_ REFIID InterfaceId,\r\n    _Outptr_ LPVOID *Interface\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This routine is called by COM in order to instantiate the\r\n    driver callback object and do an initial query interface on it.\r\n\r\n    This method only creates an instance of the driver's class factory, as this\r\n    is the minimum required to support UMDF.\r\n\r\n  Arguments:\r\n\r\n    ClassId - the CLSID of the object being \"gotten\"\r\n\r\n    InterfaceId - the interface the caller wants from that object.\r\n\r\n    Interface - a location to store the referenced interface pointer\r\n\r\n  Return Value:\r\n\r\n    S_OK if the function succeeds or error indicating the cause of the\r\n    failure.\r\n\r\n--*/\r\n{\r\n    PCClassFactory factory;\r\n\r\n    HRESULT hr = S_OK;\r\n\r\n    *Interface = NULL;\r\n\r\n    //\r\n    // If the CLSID doesn't match that of our \"coclass\" (defined in the IDL\r\n    // file) then we can't create the object the caller wants.  This may\r\n    // indicate that the COM registration is incorrect, and another CLSID\r\n    // is referencing this drvier.\r\n    //\r\n\r\n    if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false)\r\n    {\r\n        Trace(\r\n            TRACE_LEVEL_ERROR,\r\n            L\"ERROR: Called to create instance of unrecognized class (%!GUID!)\",\r\n            &ClassId\r\n            );\r\n\r\n        return CLASS_E_CLASSNOTAVAILABLE;\r\n    }\r\n\r\n    //\r\n    // Create an instance of the class factory for the caller.\r\n    //\r\n\r\n    factory = new CClassFactory();\r\n\r\n    if (NULL == factory)\r\n    {\r\n        hr = E_OUTOFMEMORY;\r\n    }\r\n\r\n    //\r\n    // Query the object we created for the interface the caller wants.  After\r\n    // that we release the object.  This will drive the reference count to\r\n    // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed).\r\n    // In the later case the object is automatically deleted.\r\n    //\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        hr = factory->QueryInterface(InterfaceId, Interface);\r\n        factory->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/driver.cpp",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved.\r\n\r\nModule Name:\r\n\r\n    Driver.cpp\r\n\r\nAbstract:\r\n\r\n    This module contains the implementation of the UMDF Skeleton Sample's\r\n    core driver callback object.\r\n\r\nEnvironment:\r\n\r\n   Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#include \"internal.h\"\r\n#include \"driver.tmh\"\r\n\r\nHRESULT\r\nCMyDriver::CreateInstance(\r\n    _Out_ PCMyDriver *Driver\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This static method is invoked in order to create and initialize a new\r\n    instance of the driver class.  The caller should arrange for the object\r\n    to be released when it is no longer in use.\r\n\r\n  Arguments:\r\n\r\n    Driver - a location to store a referenced pointer to the new instance\r\n\r\n  Return Value:\r\n\r\n    S_OK if successful, or error otherwise.\r\n\r\n--*/\r\n{\r\n    PCMyDriver driver;\r\n    HRESULT hr;\r\n\r\n    //\r\n    // Allocate the callback object.\r\n    //\r\n\r\n    driver = new CMyDriver();\r\n\r\n    if (NULL == driver)\r\n    {\r\n        return E_OUTOFMEMORY;\r\n    }\r\n\r\n    //\r\n    // Initialize the callback object.\r\n    //\r\n\r\n    hr = driver->Initialize();\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        //\r\n        // Store a pointer to the new, initialized object in the output\r\n        // parameter.\r\n        //\r\n\r\n        *Driver = driver;\r\n    }\r\n    else\r\n    {\r\n\r\n        //\r\n        // Release the reference on the driver object to get it to delete\r\n        // itself.\r\n        //\r\n\r\n        driver->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\nHRESULT\r\nCMyDriver::Initialize(\r\n    VOID\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method is called to initialize a newly created driver callback object\r\n    before it is returned to the creator.  Unlike the constructor, the\r\n    Initialize method contains operations which could potentially fail.\r\n\r\n  Arguments:\r\n\r\n    None\r\n\r\n  Return Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    return S_OK;\r\n}\r\n\r\nHRESULT\r\nCMyDriver::QueryInterface(\r\n    _In_ REFIID InterfaceId,\r\n    _Out_ PVOID *Interface\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    This method returns a pointer to the requested interface on the callback\r\n    object..\r\n\r\n  Arguments:\r\n\r\n    InterfaceId - the IID of the interface to query/reference\r\n\r\n    Interface - a location to store the interface pointer.\r\n\r\n  Return Value:\r\n\r\n    S_OK if the interface is supported.\r\n    E_NOINTERFACE if it is not supported.\r\n\r\n--*/\r\n{\r\n    if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry)))\r\n    {\r\n        *Interface = QueryIDriverEntry();\r\n        return S_OK;\r\n    }\r\n    else\r\n    {\r\n        return CUnknown::QueryInterface(InterfaceId, Interface);\r\n    }\r\n}\r\n\r\nHRESULT\r\nCMyDriver::OnDeviceAdd(\r\n    _In_ IWDFDriver *FxWdfDriver,\r\n    _In_ IWDFDeviceInitialize *FxDeviceInit\r\n    )\r\n/*++\r\n\r\n  Routine Description:\r\n\r\n    The FX invokes this method when it wants to install our driver on a device\r\n    stack.  This method creates a device callback object, then calls the Fx\r\n    to create an Fx device object and associate the new callback object with\r\n    it.\r\n\r\n  Arguments:\r\n\r\n    FxWdfDriver - the Fx driver object.\r\n\r\n    FxDeviceInit - the initialization information for the device.\r\n\r\n  Return Value:\r\n\r\n    status\r\n\r\n--*/\r\n{\r\n    HRESULT hr;\r\n\r\n    PCMyDevice device = NULL;\r\n\r\n    //\r\n    // TODO: Do any per-device initialization (reading settings from the\r\n    //       registry for example) that's necessary before creating your\r\n    //       device callback object here.  Otherwise you can leave such\r\n    //       initialization to the initialization of the device event\r\n    //       handler.\r\n    //\r\n\r\n    //\r\n    // Create a new instance of our device callback object\r\n    //\r\n\r\n    hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device);\r\n\r\n    //\r\n    // TODO: Change any per-device settings that the object exposes before\r\n    //       calling Configure to let it complete its initialization.\r\n    //\r\n\r\n    //\r\n    // If that succeeded then call the device's construct method.  This\r\n    // allows the device to create any queues or other structures that it\r\n    // needs now that the corresponding fx device object has been created.\r\n    //\r\n\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        hr = device->Configure();\r\n    }\r\n\r\n    //\r\n    // Release the reference on the device callback object now that it's been\r\n    // associated with an fx device object.\r\n    //\r\n\r\n    if (NULL != device)\r\n    {\r\n        device->Release();\r\n    }\r\n\r\n    return hr;\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/driver.h",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    Driver.h\r\n\r\nAbstract:\r\n\r\n    This module contains the type definitions for the UMDF Skeleton sample's\r\n    driver callback class.\r\n\r\nEnvironment:\r\n\r\n    Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n//\r\n// This class handles driver events for the skeleton sample.  In particular\r\n// it supports the OnDeviceAdd event, which occurs when the driver is called\r\n// to setup per-device handlers for a new device stack.\r\n//\r\n\r\nclass CMyDriver : public CUnknown, public IDriverEntry\r\n{\r\n//\r\n// Private data members.\r\n//\r\nprivate:\r\n\r\n//\r\n// Private methods.\r\n//\r\nprivate:\r\n\r\n    //\r\n    // Returns a refernced pointer to the IDriverEntry interface.\r\n    //\r\n\r\n    IDriverEntry *\r\n    QueryIDriverEntry(\r\n        VOID\r\n        )\r\n    {\r\n        AddRef();\r\n        return static_cast<IDriverEntry*>(this);\r\n    }\r\n\r\n    HRESULT\r\n    Initialize(\r\n        VOID\r\n        );\r\n\r\n//\r\n// Public methods\r\n//\r\npublic:\r\n\r\n    //\r\n    // The factory method used to create an instance of this driver.\r\n    //\r\n\r\n    static\r\n    HRESULT\r\n    CreateInstance(\r\n        _Out_ PCMyDriver *Driver\r\n        );\r\n\r\n//\r\n// COM methods\r\n//\r\npublic:\r\n\r\n    //\r\n    // IDriverEntry methods\r\n    //\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    OnInitialize(\r\n        _In_ IWDFDriver *FxWdfDriver\r\n        )\r\n    {\r\n        UNREFERENCED_PARAMETER( FxWdfDriver );\r\n\r\n        return S_OK;\r\n    }\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    OnDeviceAdd(\r\n        _In_ IWDFDriver *FxWdfDriver,\r\n        _In_ IWDFDeviceInitialize *FxDeviceInit\r\n        );\r\n\r\n    virtual\r\n    VOID\r\n    STDMETHODCALLTYPE\r\n    OnDeinitialize(\r\n        _In_ IWDFDriver *FxWdfDriver\r\n        )\r\n    {\r\n        UNREFERENCED_PARAMETER( FxWdfDriver );\r\n\r\n        return;\r\n    }\r\n\r\n    //\r\n    // IUnknown methods.\r\n    //\r\n    // We have to implement basic ones here that redirect to the\r\n    // base class becuase of the multiple inheritance.\r\n    //\r\n\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    AddRef(\r\n        VOID\r\n        )\r\n    {\r\n        return __super::AddRef();\r\n    }\r\n\r\n    _At_(this, __drv_freesMem(object))\r\n    virtual\r\n    ULONG\r\n    STDMETHODCALLTYPE\r\n    Release(\r\n        VOID\r\n       )\r\n    {\r\n        return __super::Release();\r\n    }\r\n\r\n    virtual\r\n    HRESULT\r\n    STDMETHODCALLTYPE\r\n    QueryInterface(\r\n        _In_ REFIID InterfaceId,\r\n        _Out_ PVOID *Object\r\n        );\r\n};\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/exports.def",
    "content": "; Skeleton.def : Declares the module parameters.\r\n\r\n;\r\n; TODO: Change the library name here to match your binary name.\r\n;\r\n\r\nLIBRARY      \"UMDFSkeleton.DLL\"\r\n\r\nEXPORTS\r\n    DllGetClassObject   PRIVATE\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/internal.h",
    "content": "/*++\r\n\r\nCopyright (C) Microsoft Corporation, All Rights Reserved\r\n\r\nModule Name:\r\n\r\n    Internal.h\r\n\r\nAbstract:\r\n\r\n    This module contains the local type definitions for the UMDF Skeleton\r\n    driver sample.\r\n\r\nEnvironment:\r\n\r\n    Windows User-Mode Driver Framework (WUDF)\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n#ifndef ARRAY_SIZE\r\n#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))\r\n#endif\r\n\r\n//\r\n// Include the WUDF DDI\r\n//\r\n\r\n#include \"wudfddi.h\"\r\n\r\n//\r\n// Use specstrings for in/out annotation of function parameters.\r\n//\r\n\r\n#include \"specstrings.h\"\r\n\r\n//\r\n// Forward definitions of classes in the other header files.\r\n//\r\n\r\ntypedef class CMyDriver *PCMyDriver;\r\ntypedef class CMyDevice *PCMyDevice;\r\n\r\n//\r\n// Define the tracing flags.\r\n//\r\n// TODO: Choose a different trace control GUID\r\n//\r\n\r\n#define WPP_CONTROL_GUIDS                                                   \\\r\n    WPP_DEFINE_CONTROL_GUID(                                                \\\r\n        MyDriverTraceControl, (e7541cdd,30e8,4b50,aeb0,51927330ae64),       \\\r\n                                                                            \\\r\n        WPP_DEFINE_BIT(MYDRIVER_ALL_INFO)                                   \\\r\n        )\r\n\r\n#define WPP_FLAG_LEVEL_LOGGER(flag, level)                                  \\\r\n    WPP_LEVEL_LOGGER(flag)\r\n\r\n#define WPP_FLAG_LEVEL_ENABLED(flag, level)                                 \\\r\n    (WPP_LEVEL_ENABLED(flag) &&                                             \\\r\n     WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)\r\n\r\n//\r\n// This comment block is scanned by the trace preprocessor to define our\r\n// Trace function.\r\n//\r\n// begin_wpp config\r\n// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);\r\n// end_wpp\r\n//\r\n\r\n//\r\n// Driver specific #defines\r\n//\r\n// TODO: Change these values to be appropriate for your driver.\r\n//\r\n\r\n#define MYDRIVER_TRACING_ID L\"Microsoft\\\\UMDF\\\\Skeleton\"\r\n#define MYDRIVER_CLASS_ID   { 0xd4112073, 0xd09b, 0x458f, { 0xa5, 0xaa, 0x35, 0xef, 0x21, 0xee, 0xf5, 0xde } }\r\n\r\n\r\n//\r\n// Include the type specific headers.\r\n//\r\n\r\n#include \"comsup.h\"\r\n#include \"driver.h\"\r\n#include \"device.h\"\r\n"
  },
  {
    "path": "tests/projects/windows/driver/umdf/skeleton/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_defines(\"_UNICODE\", \"UNICODE\")\n\ntarget(\"UMDFSkeleton\")\n    add_rules(\"wdk.env.umdf\", \"wdk.driver\")\n    add_values(\"wdk.tracewpp.flags\", \"-scan:internal.h\")\n    add_files(\"*.cpp\", {rules = \"wdk.tracewpp\"})\n    add_files(\"*.rc\", \"*.inx\")\n    set_values(\"wdk.umdf.sdkver\", \"1.9\")\n    add_files(\"exports.def\")\n    on_config(function(target)\n        if target:has_tool(\"sh\", \"clang\", \"clangxx\") then\n            target:add(\"shflags\", \"-Wl,/ENTRY:_DllMainCRTStartup\" .. (is_arch(\"x86\") and \"@12\" or \"\"), {force = true})\n        else\n            target:add(\"shflags\", \"/ENTRY:_DllMainCRTStartup\" .. (is_arch(\"x86\") and \"@12\" or \"\"), {force = true})\n        end\n    end)\n\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/dsmmain.c",
    "content": "/*++\r\n\r\nCopyright (C) 2004-2010  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    dsmmain.c\r\n\r\nAbstract:\r\n\r\n    This driver is the Microsoft Device Specific Module (DSM).\r\n    It exports behaviours that mpio.sys will use to determine how to\r\n    multipath SPC-3 conforming devices.\r\n\r\n    This file contains routines that are internal to MSDSM.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#ifdef DEBUG_USE_WPP\r\n#include \"dsmmain.tmh\"\r\n#endif\r\n\r\n#pragma warning (disable:4305)\r\n\r\nextern BOOLEAN DoAssert;\r\n\r\n#ifdef ALLOC_PRAGMA\r\n    #pragma alloc_text(PAGE, DsmpRegisterPersistentReservationKeys)\r\n#endif\r\n\r\nVOID\r\nDsmpFreeDSMResources(\r\n    _In_ IN PDSM_CONTEXT DsmContext\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will free the resources allocated by the DSM. This routine\r\n    should be called when the DSM is being unloaded.\r\n\r\nArguements:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n\r\nReturn Value:\r\n\r\n    None\r\n--*/\r\n{\r\n    PDSM_WMILIB_CONTEXT wmiInfo;\r\n    PVOID tempAddress = (PVOID)DsmContext;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpFreeDSMResources (DsmCtxt %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    //\r\n    // First free the buffer allocated for storing the registry path.\r\n    //\r\n    wmiInfo = &gDsmInitData.DsmWmiInfo;\r\n\r\n    if (wmiInfo->RegistryPath.Buffer) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DsmpFreeDSMResources (DsmCtxt %p): Freeing wmiInfo's registry buffer.\\n\",\r\n                    DsmContext));\r\n\r\n        DsmpFreePool(wmiInfo->RegistryPath.Buffer);\r\n    }\r\n\r\n    if (DsmContext) {\r\n        PLIST_ENTRY entry;\r\n        PDSM_DEVICE_INFO deviceInfo;\r\n        PDSM_GROUP_ENTRY groupEntry;\r\n        PDSM_FAILOVER_GROUP failGroup;\r\n        PDSM_CONTROLLER_LIST_ENTRY controllerEntry;\r\n\r\n        ExDeleteNPagedLookasideList(&(DsmContext->CompletionContextList));\r\n\r\n        //\r\n        // Free up the devices (DeviceInfo) list.\r\n        //\r\n        while (!IsListEmpty(&DsmContext->DeviceList)) {\r\n\r\n             entry = DsmContext->DeviceList.Flink;\r\n\r\n             NT_ASSERT(entry);\r\n\r\n             deviceInfo = CONTAINING_RECORD(entry, DSM_DEVICE_INFO, ListEntry);\r\n\r\n             if (deviceInfo) {\r\n\r\n                 DsmpRemoveDeviceFailGroup(DsmContext, deviceInfo->FailGroup, deviceInfo, TRUE);\r\n                 DsmpRemoveDeviceEntry(DsmContext, deviceInfo->Group, deviceInfo);\r\n             }\r\n        }\r\n\r\n        NT_ASSERT(!DsmContext->NumberDevices &&\r\n                  !DsmContext->NumberFOGroups &&\r\n                  !DsmContext->NumberGroups);\r\n\r\n        //\r\n        // By now, there should be no group entries left but play it safe and\r\n        // free up the GROUP list.\r\n        //\r\n        while (!IsListEmpty(&DsmContext->GroupList)) {\r\n\r\n             entry = DsmContext->GroupList.Flink;\r\n\r\n             NT_ASSERT(entry);\r\n\r\n             groupEntry = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry);\r\n\r\n             if (groupEntry) {\r\n\r\n                 DsmpRemoveGroupEntry(DsmContext, groupEntry, TRUE);\r\n\r\n                 DsmpFreePool(groupEntry);\r\n             }\r\n        }\r\n\r\n        //\r\n        // By now there should be no FOG entries left but we play it safe and\r\n        // free up the FOG list.\r\n        //\r\n        while (!IsListEmpty(&DsmContext->FailGroupList)) {\r\n\r\n             entry = RemoveHeadList(&DsmContext->FailGroupList);\r\n\r\n             if (entry) {\r\n\r\n                 failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry);\r\n\r\n                 if (failGroup) {\r\n\r\n                     PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL;\r\n                     PLIST_ENTRY deviceEntry = NULL;\r\n\r\n                     while (!IsListEmpty(&failGroup->FOG_DeviceList)) {\r\n\r\n                         deviceEntry = RemoveHeadList(&failGroup->FOG_DeviceList);\r\n\r\n                         if (deviceEntry) {\r\n\r\n                             fogDeviceListEntry = CONTAINING_RECORD(deviceEntry, DSM_FOG_DEVICELIST_ENTRY, ListEntry);\r\n\r\n                             if (!fogDeviceListEntry) {\r\n                                 continue;\r\n                             }\r\n\r\n                             (fogDeviceListEntry->DeviceInfo)->FailGroup = NULL;\r\n\r\n                             DsmpFreePool(fogDeviceListEntry);\r\n                             InterlockedDecrement((LONG volatile*)&failGroup->Count);\r\n                         }\r\n                     }\r\n\r\n                     DsmpFreeZombieGroupList(failGroup);\r\n                     DsmpFreePool(failGroup);\r\n                     InterlockedDecrement((LONG volatile*)&DsmContext->NumberFOGroups);\r\n                 }\r\n             }\r\n        }\r\n\r\n        //\r\n        // Free up the controller list.\r\n        //\r\n        while (!IsListEmpty(&DsmContext->ControllerList)) {\r\n\r\n             entry = RemoveHeadList(&DsmContext->ControllerList);\r\n\r\n             if (entry) {\r\n\r\n                 controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry);\r\n\r\n                 if (controllerEntry) {\r\n\r\n                     DsmpFreeControllerEntry(DsmContext, controllerEntry);\r\n\r\n                     InterlockedDecrement((LONG volatile*)&DsmContext->NumberControllers);\r\n                 }\r\n             }\r\n        }\r\n\r\n        NT_ASSERT(!DsmContext->NumberControllers);\r\n\r\n        //\r\n        // Free up the stale FOG list.\r\n        //\r\n        while (!IsListEmpty(&DsmContext->StaleFailGroupList)) {\r\n\r\n             entry = RemoveHeadList(&DsmContext->StaleFailGroupList);\r\n\r\n             if (entry) {\r\n\r\n                 failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry);\r\n\r\n                 if (failGroup) {\r\n\r\n                     InterlockedDecrement((LONG volatile*)&DsmContext->NumberStaleFOGroups);\r\n                     NT_ASSERT(IsListEmpty(&failGroup->FOG_DeviceList));\r\n                     DsmpFreeZombieGroupList(failGroup);\r\n                     DsmpFreePool(failGroup);\r\n                 }\r\n             }\r\n        }\r\n\r\n        //\r\n        // Free up the supported devices list buffer.\r\n        //\r\n        DsmpFreePool(DsmContext->SupportedDevices.Buffer);\r\n\r\n        //\r\n        // It's the responsibility of the mpio bus driver to have already\r\n        // destroyed all devices and paths. As those functions free allocations\r\n        // for the objects, the only thing needed here is to free the DsmContext.\r\n        //\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DsmpFreeDSMResources (DsmCtxt %p): Freeing the DsmContext.\\n\",\r\n                    DsmContext));\r\n\r\n        DsmpFreePool(DsmContext);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpFreeDSMResources (DsmCtxt %p): Exiting function.\\n\",\r\n                tempAddress));\r\n\r\n    return;\r\n}\r\n\r\n\r\nPDSM_GROUP_ENTRY\r\nDsmpFindDevice(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine searches for a serial number match between DeviceInfo and\r\n    the rest of the devices currently being driven by this DSM.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DeviceInfo - The deviceInfo containing serial number for which to search.\r\n    AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively\r\n\r\nReturn Value:\r\n\r\n    The multi-path group entry in which the device resides.\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PLIST_ENTRY entry;\r\n    PDSM_GROUP_ENTRY groupEntry = NULL;\r\n    ULONG i;\r\n    KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindDevice (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    if (AcquireDSMLockExclusive) {\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    }\r\n\r\n    //\r\n    // Run through the DeviceInfo List\r\n    //\r\n    entry = DsmContext->DeviceList.Flink;\r\n    for (i = 0; i < DsmContext->NumberDevices; i++, entry = entry->Flink) {\r\n\r\n        //\r\n        // Extract the deviceInfo structure.\r\n        //\r\n        deviceInfo = CONTAINING_RECORD(entry, DSM_DEVICE_INFO, ListEntry);\r\n        DSM_ASSERT(deviceInfo);\r\n\r\n        if (deviceInfo) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpFindDevice (DevInfo %p): Comparing with %p.\\n\",\r\n                        DeviceInfo,\r\n                        deviceInfo));\r\n\r\n            //\r\n            // Call the Serial Number compare routine.\r\n            //\r\n            if (DsmCompareDevices(DsmContext,\r\n                                  DeviceInfo,\r\n                                  deviceInfo)) {\r\n\r\n                groupEntry = deviceInfo->Group;\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpFindDevice (DevInfo %p): Found matching multi-path group %p.\\n\",\r\n                            DeviceInfo,\r\n                            groupEntry));\r\n\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (AcquireDSMLockExclusive) {\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindDevice (DevInfo %p): Exiting function with groupEntry %p.\\n\",\r\n                DeviceInfo,\r\n                groupEntry));\r\n\r\n    return groupEntry;\r\n}\r\n\r\n\r\nPDSM_GROUP_ENTRY\r\nDsmpBuildGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will allocate and partially initialise a multi-path group entry.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DeviceInfo - The first device to be added to the group.\r\n\r\nReturn Value:\r\n\r\n    The new group entry.\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildGroupEntry (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    //\r\n    // Allocate the memory for the multi-path group.\r\n    //\r\n    group = DsmpAllocatePool(NonPagedPoolNx,\r\n                             sizeof(DSM_GROUP_ENTRY),\r\n                             DSM_TAG_GROUP_ENTRY);\r\n\r\n    if (group) {\r\n\r\n        InitializeListHead(&group->FailingDevInfoList);\r\n        group->GroupNumber = InterlockedIncrement((LONG volatile*)&DsmContext->NumberGroups);\r\n        group->GroupSig = DSM_GROUP_SIG;\r\n        group->State = DSM_GP_NORMAL;\r\n\r\n        //\r\n        // Add it to the list of multi-path groups.\r\n        //\r\n        InsertTailList(&DsmContext->GroupList, &group->ListEntry);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildGroupEntry (DevInfo %p): Failed to allocate memory for the group.\\n\",\r\n                    DeviceInfo));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildGroupEntry (DevInfo %p): Exiting function with group %p.\\n\",\r\n                DeviceInfo,\r\n                group));\r\n\r\n    return group;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpParseTargetPortGroupsInformation(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will parse the information returned back from a previously\r\n    made call to ReportTargetPortGroups and build new TPG entries or\r\n    update old ones.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    Group - group entry\r\n    TargetPortGroupsInfo - Pointer to the ReportTPG returned buffer.\r\n    TargetPortGroupsInfoLength - length of the buffer.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate error code.\r\n\r\n--*/\r\n{\r\n    PUCHAR targetPortGroupsInfoIndex;\r\n    ULONG bytes = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL;\r\n    ULONG descriptorSize = 0;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ULONG index;\r\n    DSM_DEVICE_STATE tpgState = DSM_DEV_NOT_USED_STATE;\r\n    ULONG bytesLeft;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpParseTargetPortGroupsInformation (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    targetPortGroupsInfoIndex = TargetPortGroupsInfo + bytes;\r\n    bytesLeft = TargetPortGroupsInfoLength - bytes;\r\n\r\n    while (bytes < TargetPortGroupsInfoLength && NT_SUCCESS(status)) {\r\n\r\n        targetPortGroupEntry = DsmpFindTargetPortGroupEntry(DsmContext,\r\n                                                            Group,\r\n                                                            targetPortGroupsInfoIndex,\r\n                                                            bytesLeft);\r\n\r\n        if (targetPortGroupEntry) {\r\n\r\n            targetPortGroupEntry = DsmpUpdateTargetPortGroupEntry(DsmContext,\r\n                                                                  targetPortGroupEntry,\r\n                                                                  targetPortGroupsInfoIndex,\r\n                                                                  bytesLeft,\r\n                                                                  &descriptorSize);\r\n        } else {\r\n\r\n            targetPortGroupEntry = DsmpBuildTargetPortGroupEntry(DsmContext,\r\n                                                                 Group,\r\n                                                                 targetPortGroupsInfoIndex,\r\n                                                                 bytesLeft,\r\n                                                                 &descriptorSize);\r\n\r\n            if (targetPortGroupEntry) {\r\n\r\n                //\r\n                // Insert this TPG entry into array\r\n                //\r\n                for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n                    if (!Group->TargetPortGroupList[index]) {\r\n\r\n                        Group->TargetPortGroupList[index] = targetPortGroupEntry;\r\n                        InterlockedIncrement((LONG volatile*)&Group->NumberTargetPortGroups);\r\n                        targetPortGroupEntry->Group = Group;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                if (index == DSM_MAX_PATHS) {\r\n\r\n                    NT_ASSERT(index < DSM_MAX_PATHS);\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_GENERAL,\r\n                                \"DsmpParseTargetPortGroupsInformation (Group %p): Number of paths exceeded max supported.\\n\",\r\n                                Group));\r\n\r\n                    status = STATUS_UNSUCCESSFUL;\r\n                    goto __Exit_DsmpParseTargetPortGroupsInformation;\r\n                }\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpParseTargetPortGroupsInformation (Group %p): Insufficient resources to build TPG.\\n\",\r\n                            Group));\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // If this is the first TPG being parsed, save off its AA state.\r\n            //\r\n            if (tpgState == DSM_DEV_NOT_USED_STATE) {\r\n\r\n                tpgState = targetPortGroupEntry->AsymmetricAccessState;\r\n\r\n            } else {\r\n\r\n                //\r\n                // Check if this TPG's AA state differs from the previous one's.\r\n                // Symmetric LU access means that TPG access states must be the\r\n                // same for TPGs. If this one is different, we know that the\r\n                // device supports Asymmetric LU access.\r\n                //\r\n                if (tpgState != targetPortGroupEntry->AsymmetricAccessState) {\r\n\r\n                    Group->Symmetric = FALSE;\r\n                }\r\n            }\r\n        }\r\n\r\n        if (targetPortGroupEntry) {\r\n\r\n            //\r\n            // Set the flag to indicate that we've encountered this TPG in the RTPG information.\r\n            //\r\n            targetPortGroupEntry->Traversed = TRUE;\r\n        }\r\n\r\n        bytes += descriptorSize;\r\n        targetPortGroupsInfoIndex += descriptorSize;\r\n        bytesLeft -= descriptorSize;\r\n    }\r\n\r\n    //\r\n    // Since we've gone through the entire information reported by back RTPG, it\r\n    // is now time to delete the stale entries.\r\n    //\r\n    for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n        targetPortGroupEntry = Group->TargetPortGroupList[index];\r\n\r\n        if (targetPortGroupEntry) {\r\n\r\n            if (targetPortGroupEntry->Traversed) {\r\n\r\n                //\r\n                // Entry needs to continue to exist. Reset the flag and continue.\r\n                //\r\n                targetPortGroupEntry->Traversed = FALSE;\r\n                continue;\r\n\r\n            } else {\r\n\r\n                PLIST_ENTRY entry;\r\n                PLIST_ENTRY tempEntry;\r\n                PDSM_TARGET_PORT_LIST_ENTRY targetPort;\r\n\r\n                //\r\n                // For this target port group, clean up all its target ports if\r\n                // the port doesn't expose any instance of this device.\r\n                //\r\n                for (entry = targetPortGroupEntry->TargetPortList.Flink;\r\n                     entry != NULL && entry != &targetPortGroupEntry->TargetPortList;\r\n                     entry = entry->Flink) {\r\n\r\n                        targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n\r\n                        if (targetPort) {\r\n\r\n                            //\r\n                            // If the TP doesn't expose this device, it is safe\r\n                            // to delete it.\r\n                            //\r\n                            if (IsListEmpty(&targetPort->TP_DeviceList)) {\r\n\r\n                                tempEntry = entry;\r\n                                entry = entry->Blink;\r\n\r\n                                RemoveEntryList(tempEntry);\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_PNP,\r\n                                            \"DsmpParseTargetPortGroupsInformation (Group %p): Deleting empty target port %p from TPG %p list.\\n\",\r\n                                            Group,\r\n                                            targetPort,\r\n                                            targetPortGroupEntry));\r\n\r\n                                DsmpFreePool(targetPort);\r\n\r\n                                InterlockedDecrement((LONG volatile*)&targetPortGroupEntry->NumberTargetPorts);\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                //\r\n                // If the TPG doesn't have any TPs, it is safe to delete it.\r\n                //\r\n                if (!targetPortGroupEntry->NumberTargetPorts) {\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpParseTargetPortGroupsInformation (Group %p): Deleting target port group %p.\\n\",\r\n                                Group,\r\n                                targetPortGroupEntry));\r\n\r\n                    DsmpFreePool(targetPortGroupEntry);\r\n\r\n                    InterlockedDecrement((LONG volatile*)&Group->NumberTargetPortGroups);\r\n\r\n                    Group->TargetPortGroupList[index] = NULL;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmpParseTargetPortGroupsInformation:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpParseTargetPortGroupsInformation (Group %p): Exiting function with status %x\\n\",\r\n                Group,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpFindTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will search the group's TPG array to look for an identifier match.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in either Shared\r\n    or Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    Group - group entry\r\n    TargetPortGroupsDescriptor - Pointer to the TPG descriptor.\r\n    TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer.\r\n\r\nReturn Value:\r\n\r\n    Pointer to the array element that matches, else NULL.\r\n\r\n--*/\r\n{\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL;\r\n    PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor;\r\n    ULONG index;\r\n    BOOLEAN found = FALSE;\r\n    USHORT identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8);\r\n\r\n    UNREFERENCED_PARAMETER(TPGs_BufferLength);\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortGroupEntry (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    for (index = 0; index < DSM_MAX_PATHS && !found; index++) {\r\n\r\n        targetPortGroup = Group->TargetPortGroupList[index];\r\n\r\n        if (targetPortGroup) {\r\n\r\n            if (targetPortGroup->Identifier == identifier) {\r\n\r\n                found = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!found) {\r\n        targetPortGroup = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortGroupEntry (Group %p): Exiting function with targetPortGroup %p.\\n\",\r\n                Group,\r\n                targetPortGroup));\r\n\r\n    return targetPortGroup;\r\n}\r\n\r\n_Success_(return!=0)\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpUpdateTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength,\r\n    _Out_ OUT PULONG DescriptorSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will update the target port group with information contained\r\n    in the passed in descriptor.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    TargetPortGroup - Pointer to the TPG entry to update.\r\n    TargetPortGroupsDescriptor - Pointer to the TPG descriptor.\r\n    TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer.\r\n    DescriptorSize - return value of the size of the descriptor.\r\n\r\nReturn Value:\r\n\r\n    The updated target port group entry on success, NULL in case of failure.\r\n\r\n--*/\r\n{\r\n    PLIST_ENTRY entry;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = TargetPortGroup;\r\n    PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor;\r\n    ULONG numberTargetPorts = 0;\r\n    PULONG descriptorIndex;\r\n    ULONG index;\r\n    PDSM_TARGET_PORT_LIST_ENTRY listEntry;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ULONG identifier;\r\n    PLIST_ENTRY tempEntry = NULL;\r\n    ULONG delCount;\r\n    PUCHAR endOfBuffer = TargetPortGroupsDescriptor + TPGs_BufferLength - 1;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpUpdateTargetPortGroupEntry (TPG %p): Entering function.\\n\",\r\n                TargetPortGroup));\r\n\r\n    if (DescriptorSize == NULL) {\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to null passed in DescriptorSize pointer\\n\",\r\n                    TargetPortGroup,\r\n                    status));\r\n\r\n        goto __Exit_DsmpUpdateTargetPortGroupEntry;\r\n    }\r\n\r\n    *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                      (targetPortGroup->NumberTargetPorts * sizeof(ULONG));\r\n\r\n    if (((PUCHAR)descriptor + sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) - 1) > endOfBuffer) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to incorrect passed in TPG buffer size (%u).\\n\",\r\n                    TargetPortGroup,\r\n                    status,\r\n                    TPGs_BufferLength));\r\n\r\n        goto __Exit_DsmpUpdateTargetPortGroupEntry;\r\n    }\r\n\r\n    identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8);\r\n    NT_ASSERT(targetPortGroup->Identifier == (USHORT)identifier);\r\n    NT_ASSERT(targetPortGroup->ActiveOptimizedSupported == (descriptor->ActiveOptimizedSupported) ? TRUE : FALSE);\r\n    NT_ASSERT(targetPortGroup->ActiveUnoptimizedSupported == (descriptor->ActiveUnoptimizedSupported) ? TRUE : FALSE);\r\n    NT_ASSERT(targetPortGroup->StandBySupported == (descriptor->StandbySupported) ? TRUE : FALSE);\r\n    NT_ASSERT(targetPortGroup->UnavailableSupported == (descriptor->UnavailableSupported) ? TRUE : FALSE);\r\n    NT_ASSERT(targetPortGroup->TransitioningSupported == (descriptor->TransitioningSupported) ? TRUE : FALSE);\r\n    DSM_ASSERT(targetPortGroup->VendorUnique == descriptor->VendorUnique);\r\n\r\n    //\r\n    // It is possible that the asymmetric access state, status code and number of port\r\n    // may have changed\r\n    //\r\n    if ((targetPortGroup->AsymmetricAccessState) != (descriptor->AsymmetricAccessState & 0xF))\r\n    {\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpUpdateTargetPortGroupEntry (TPG %p): Asymmetric access state has changed.\\n\",\r\n                        TargetPortGroup));\r\n\r\n\r\n        targetPortGroup->AsymmetricAccessState = descriptor->AsymmetricAccessState & 0xF;\r\n    }\r\n\r\n    targetPortGroup->Preferred = (descriptor->Preferred) ? TRUE : FALSE;\r\n\r\n    targetPortGroup->StatusCode = descriptor->StatusCode;\r\n\r\n    numberTargetPorts = descriptor->NumberTargetPorts;\r\n\r\n    NT_ASSERT(numberTargetPorts > 0);\r\n\r\n    //\r\n    // Point to first target port identifier\r\n    //\r\n    descriptorIndex = descriptor->TargetPortIds;\r\n\r\n    for (index = 0; index < numberTargetPorts && NT_SUCCESS(status); index++) {\r\n\r\n        if (((PUCHAR)descriptorIndex + ((index + 1) * sizeof(ULONG)) - 1) > endOfBuffer) {\r\n\r\n            status = STATUS_INVALID_PARAMETER;\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpUpdateTargetPortGroupEntry (TPG %p): Status %x due to incorrect TPG buffer size (%u) passed in.\\n\",\r\n                        TargetPortGroup,\r\n                        status,\r\n                        TPGs_BufferLength));\r\n\r\n            goto __Exit_DsmpUpdateTargetPortGroupEntry;\r\n        }\r\n\r\n        GetUlongFrom4ByteArray((PUCHAR)(&descriptorIndex[index]), identifier);\r\n\r\n        listEntry = DsmpFindTargetPortListEntry(DsmContext,\r\n                                                targetPortGroup,\r\n                                                identifier);\r\n\r\n        if (listEntry) {\r\n\r\n            RemoveEntryList(&listEntry->ListEntry);\r\n            InsertHeadList(&targetPortGroup->TargetPortList, &listEntry->ListEntry);\r\n\r\n        } else {\r\n\r\n            listEntry = DsmpBuildTargetPortListEntry(DsmContext,\r\n                                                     targetPortGroup,\r\n                                                     identifier);\r\n\r\n            if (listEntry) {\r\n\r\n                InsertHeadList(&targetPortGroup->TargetPortList, &listEntry->ListEntry);\r\n                InterlockedIncrement((LONG volatile*)&targetPortGroup->NumberTargetPorts);\r\n\r\n            } else {\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpUpdateTargetPortGroupEntry (TPG %p): Failed to allocate TargetPort (identifier %x).\\n\",\r\n                            TargetPortGroup,\r\n                            identifier));\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // Ignore the status & carry on. Even if we weren't able to build TP entries\r\n    // for the new target ports, we are no worse off than before.\r\n    //\r\n    DSM_ASSERT(NT_SUCCESS(status));\r\n\r\n    *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                      (numberTargetPorts * sizeof(ULONG));\r\n\r\n    for (index = 0, entry = targetPortGroup->TargetPortList.Flink;\r\n         index < numberTargetPorts;\r\n         index++, entry = entry->Flink);\r\n\r\n    delCount = targetPortGroup->NumberTargetPorts - numberTargetPorts;\r\n\r\n    for (index = 0; index < delCount; index++) {\r\n\r\n        tempEntry = entry;\r\n        entry = entry->Flink;\r\n\r\n        RemoveEntryList(tempEntry);\r\n        InterlockedDecrement((LONG volatile*)&targetPortGroup->NumberTargetPorts);\r\n\r\n        listEntry = CONTAINING_RECORD(tempEntry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n        NT_ASSERT(listEntry);\r\n\r\n        if (listEntry) {\r\n\r\n            PLIST_ENTRY deviceEntry;\r\n            PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device;\r\n\r\n            while (!IsListEmpty(&listEntry->TP_DeviceList)) {\r\n\r\n                deviceEntry = RemoveHeadList(&listEntry->TP_DeviceList);\r\n                InterlockedDecrement((LONG volatile*)&listEntry->Count);\r\n\r\n                if (deviceEntry) {\r\n\r\n                    tp_device = CONTAINING_RECORD(deviceEntry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry);\r\n\r\n                    if (tp_device) {\r\n\r\n                        if (tp_device->DeviceInfo) {\r\n\r\n                            tp_device->DeviceInfo->TargetPort = NULL;\r\n                        }\r\n\r\n                        DsmpFreePool(tp_device);\r\n                    }\r\n                }\r\n            }\r\n\r\n            DsmpFreePool(listEntry);\r\n        }\r\n    }\r\n\r\n__Exit_DsmpUpdateTargetPortGroupEntry:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpUpdateTargetPortGroupEntry (TPG %p): Exiting function.\\n\",\r\n                targetPortGroup));\r\n\r\n    return targetPortGroup;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpBuildTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength,\r\n    _Out_ OUT PULONG DescriptorSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will allocate and partially initialise a target port group entry.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    Group - The group that this newly going to be built TPG belongs to.\r\n    TargetPortGroupsDescriptor - Pointer to the TPG descriptor.\r\n    TPGs_BufferLength - Length of the passed in TargetPortGroupsDescriptor buffer.\r\n    DescriptorSize - return value of the size of the descriptor.\r\n\r\nReturn Value:\r\n\r\n    The new target port group entry.\r\n\r\n--*/\r\n{\r\n    PDSM_TARGET_PORT_GROUP_ENTRY entry = NULL;\r\n    PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR descriptor = (PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR)TargetPortGroupsDescriptor;\r\n    ULONG numberTargetPorts = 0;\r\n    PULONG descriptorIndex;\r\n    ULONG index = 0;\r\n    PDSM_TARGET_PORT_LIST_ENTRY listEntry;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ULONG identifier;\r\n    PUCHAR endOfBuffer = TargetPortGroupsDescriptor + TPGs_BufferLength - 1;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpBuildTargetPortGroupEntry (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    if (DescriptorSize == NULL) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to null passed in DescriptorSize pointer\\n\",\r\n                    Group,\r\n                    status));\r\n\r\n        goto __Exit_DsmpBuildTargetPortGroupEntry;\r\n    }\r\n\r\n    *DescriptorSize = 0;\r\n\r\n    if (((PUCHAR)descriptor + sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) - 1) > endOfBuffer) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to incorrect passed in TPG buffer size (%u).\\n\",\r\n                    Group,\r\n                    status,\r\n                    TPGs_BufferLength));\r\n\r\n        goto __Exit_DsmpBuildTargetPortGroupEntry;\r\n    }\r\n\r\n    //\r\n    // Allocate the memory for the multi-path group.\r\n    //\r\n    entry = DsmpAllocatePool(NonPagedPoolNx,\r\n                             sizeof(DSM_TARGET_PORT_GROUP_ENTRY),\r\n                             DSM_TAG_TARGET_PORT_GROUP_ENTRY);\r\n\r\n    if (entry) {\r\n\r\n        entry->TargetPortGroupSig = DSM_TARGET_PORT_GROUP_SIG;\r\n\r\n        //\r\n        // Target Port Group's access state\r\n        //\r\n        entry->AsymmetricAccessState = descriptor->AsymmetricAccessState & 0xF;\r\n\r\n        //\r\n        // Target Port Group's supported states\r\n        //\r\n        entry->ActiveOptimizedSupported = (descriptor->ActiveOptimizedSupported) ? TRUE : FALSE;\r\n        entry->ActiveUnoptimizedSupported = (descriptor->ActiveUnoptimizedSupported) ? TRUE : FALSE;\r\n        entry->StandBySupported = (descriptor->StandbySupported) ? TRUE : FALSE;\r\n        entry->UnavailableSupported = (descriptor->UnavailableSupported) ? TRUE : FALSE;\r\n\r\n        //\r\n        // Target Port Group's Preference and support for reporting transitioning\r\n        //\r\n        entry->Preferred = (descriptor->Preferred) ? TRUE : FALSE;\r\n        entry->TransitioningSupported = (descriptor->TransitioningSupported) ? TRUE : FALSE;\r\n\r\n        //\r\n        // Target Port Group's identifier\r\n        //\r\n        entry->Identifier = ((descriptor->TPG_Identifier & 0x00FF) << 8) | ((descriptor->TPG_Identifier & 0xFF00) >> 8);\r\n\r\n        //\r\n        // Target Port Group's status code\r\n        //\r\n        entry->StatusCode = descriptor->StatusCode;\r\n\r\n        //\r\n        // Vendor unique\r\n        //\r\n        entry->VendorUnique = descriptor->VendorUnique;\r\n\r\n        //\r\n        // Number of target ports\r\n        //\r\n        numberTargetPorts = descriptor->NumberTargetPorts;\r\n\r\n        NT_ASSERT(numberTargetPorts > 0);\r\n\r\n        //\r\n        // Point to first target port identifier\r\n        //\r\n        descriptorIndex = descriptor->TargetPortIds;\r\n\r\n        InitializeListHead(&entry->TargetPortList);\r\n\r\n        for (index = 0; index < numberTargetPorts && NT_SUCCESS(status); index++) {\r\n\r\n            if (((PUCHAR)descriptorIndex + ((index + 1) * sizeof(ULONG)) - 1) > endOfBuffer) {\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpBuildTargetPortGroupEntry (Group %p): Status %x due to incorrect TPG buffer size (%u) passed in.\\n\",\r\n                            Group,\r\n                            status,\r\n                            TPGs_BufferLength));\r\n\r\n                break;\r\n            }\r\n\r\n            GetUlongFrom4ByteArray((PUCHAR)(&descriptorIndex[index]), identifier);\r\n\r\n            listEntry = DsmpBuildTargetPortListEntry(DsmContext,\r\n                                                     entry,\r\n                                                     identifier);\r\n\r\n            if (listEntry) {\r\n\r\n                InsertTailList(&entry->TargetPortList, &listEntry->ListEntry);\r\n                InterlockedIncrement((LONG volatile*)&entry->NumberTargetPorts);\r\n\r\n            } else {\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpBuildTargetPortGroupEntry (Group %p): Failed to allocate memory for TP (identifier %x) of TPG %p.\\n\",\r\n                            Group,\r\n                            identifier,\r\n                            entry));\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n            *DescriptorSize = sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                              (numberTargetPorts * sizeof(ULONG));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpBuildTargetPortGroupEntry (Group %p): Failed to allocate memory for the TPG.\\n\",\r\n                    Group));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Delete the target port list and the target port group entry\r\n        //\r\n        numberTargetPorts = index - 1;\r\n\r\n        if (entry) {\r\n\r\n            PLIST_ENTRY delEntry;\r\n\r\n            for (index = 0; index < numberTargetPorts; index++) {\r\n\r\n                delEntry = RemoveHeadList(&entry->TargetPortList);\r\n                listEntry = CONTAINING_RECORD(delEntry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpBuildTargetPortGroupEntry (Group %p): Cleaning up TPG %p's TP %x.\\n\",\r\n                            Group,\r\n                            entry,\r\n                            listEntry->Identifier));\r\n\r\n                DsmpFreePool(listEntry);\r\n            }\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpBuildTargetPortGroupEntry (Group %p): Cleaning up TPG %p.\\n\",\r\n                        Group,\r\n                        entry));\r\n\r\n            DsmpFreePool(entry);\r\n            entry = NULL;\r\n        }\r\n    }\r\n\r\n__Exit_DsmpBuildTargetPortGroupEntry:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpBuildTargetPortGroupEntry (Group %p): Exiting function with entry %p.\\n\",\r\n                Group,\r\n                entry));\r\n\r\n    return entry;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpFindTargetPortListEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN ULONG RelativeTargetPortId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will search the passed in TPG's target port list for an identifier match.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    TargetPortGroup - The Target Port Group whose target ports need to be searched.\r\n    RelativeTargetPortId - Identifier of the target port entry being matched.\r\n\r\nReturn Value:\r\n\r\n    The target port list entry if match found, else NULL.\r\n\r\n--*/\r\n{\r\n    PLIST_ENTRY entry = NULL;\r\n    PDSM_TARGET_PORT_LIST_ENTRY targetPort = NULL;\r\n    BOOLEAN found = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortListEntry (TPG %p): Entering function.\\n\",\r\n                TargetPortGroup));\r\n\r\n    for (entry = TargetPortGroup->TargetPortList.Flink;\r\n         entry != &TargetPortGroup->TargetPortList && !found;\r\n         entry = entry->Flink) {\r\n\r\n        targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n        NT_ASSERT(targetPort);\r\n\r\n        if (targetPort) {\r\n\r\n            if (targetPort->Identifier == RelativeTargetPortId) {\r\n\r\n                NT_ASSERT(targetPort->TargetPortGroup == TargetPortGroup);\r\n\r\n                found = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!found) {\r\n        targetPort = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortListEntry (TPG %p): Exiting function with target port %p.\\n\",\r\n                TargetPortGroup,\r\n                targetPort));\r\n\r\n    return targetPort;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpBuildTargetPortListEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN ULONG RelativeTargetPortId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will allocate and partially initialize a target port list entry.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DsmContext\r\n    TargetPortGroup - The Target Port Group that this target port belongs to.\r\n    RelativeTargetPortId - Identifier of the target port entry being added.\r\n\r\nReturn Value:\r\n\r\n    The new target port list entry.\r\n\r\n--*/\r\n{\r\n    PDSM_TARGET_PORT_LIST_ENTRY entry;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpBuildTargetPortListEntry (TPG %p): Entering function.\\n\",\r\n                TargetPortGroup));\r\n\r\n    entry = DsmpAllocatePool(NonPagedPoolNx,\r\n                             sizeof(DSM_TARGET_PORT_LIST_ENTRY),\r\n                             DSM_TAG_TARGET_PORT_LIST_ENTRY);\r\n\r\n    if (entry) {\r\n\r\n        InitializeListHead(&entry->TP_DeviceList);\r\n\r\n        entry->Identifier = RelativeTargetPortId;\r\n        entry->TargetPortGroup = TargetPortGroup;\r\n        entry->TargetPortSig = DSM_TARGET_PORT_SIG;\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpBuildTargetPortListEntry (TPG %p): Failed to allocate memory for target port (identifier %x).\\n\",\r\n                    TargetPortGroup,\r\n                    RelativeTargetPortId));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpBuildTargetPortListEntry (TPG %p): Exiting function with entry %p.\\n\",\r\n                TargetPortGroup,\r\n                entry));\r\n\r\n    return entry;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpFindTargetPortGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PUSHORT TargetPortGroupId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine searches the list of TargetPortGroups of a Group to\r\n    find a match for the passed in TargetPortGroupId.\r\n\r\n    N.B: This routine must be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context.\r\n    Group - The group whose target port groups to search for a match.\r\n    TargetPortGroupId - Identifier of the target port group entry being searched.\r\n\r\nReturn Value:\r\n\r\n    The target port group entry which matches the passed in identifier.\r\n\r\n--*/\r\n{\r\n    ULONG index;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL;\r\n    BOOLEAN found = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortGroup (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    //\r\n    // Run through the target port group array\r\n    //\r\n    for (index = 0; index < DSM_MAX_PATHS && !found; index++) {\r\n\r\n        targetPortGroupEntry = Group->TargetPortGroupList[index];\r\n\r\n        if (targetPortGroupEntry) {\r\n\r\n            if (targetPortGroupEntry->Identifier == *TargetPortGroupId) {\r\n\r\n                found = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!found) {\r\n\r\n        targetPortGroupEntry = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPortGroup (Group %p): Exiting function with targetPortGroupEntry %p.\\n\",\r\n                Group,\r\n                targetPortGroupEntry));\r\n\r\n    return targetPortGroupEntry;\r\n}\r\n\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpFindTargetPort(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN PULONG TargetPortGroupId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine searches the list of TargetPorts to\r\n    find a match for the passed in TargetPortGroup and RelativeTargetPortId.\r\n\r\n    N.B. Spin lock must be held by caller.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context.\r\n    TargetPortGroup - the Target Port Group of which this target port is a member.\r\n    RelativeTargetPortId - Identifier of the target port entry being searched.\r\n\r\nReturn Value:\r\n\r\n    The target port entry which matches the passed in identifier.\r\n\r\n--*/\r\n{\r\n    PLIST_ENTRY entry;\r\n    PDSM_TARGET_PORT_LIST_ENTRY targetPortListEntry = NULL;\r\n    BOOLEAN found = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPort (TPG %p): Entering function.\\n\",\r\n                TargetPortGroup));\r\n\r\n    //\r\n    // Run through the Target Port List\r\n    //\r\n    for (entry = TargetPortGroup->TargetPortList.Flink;\r\n         entry != &TargetPortGroup->TargetPortList && !found;\r\n         entry = entry->Flink) {\r\n\r\n        //\r\n        // Extract the target port group structure.\r\n        //\r\n        targetPortListEntry = CONTAINING_RECORD(entry,\r\n                                                DSM_TARGET_PORT_LIST_ENTRY,\r\n                                                ListEntry);\r\n        NT_ASSERT(targetPortListEntry);\r\n\r\n        if (targetPortListEntry) {\r\n\r\n            NT_ASSERT(TargetPortGroup == targetPortListEntry->TargetPortGroup);\r\n\r\n            //\r\n            // Compare with passed in identifier.\r\n            //\r\n            if (targetPortListEntry->Identifier == *TargetPortGroupId) {\r\n\r\n                found = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!found) {\r\n\r\n        targetPortListEntry = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindTargetPort (TPG %p): Exiting function with targetPortListEntry %p.\\n\",\r\n                TargetPortGroup,\r\n                targetPortListEntry));\r\n\r\n    return targetPortListEntry;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpAddDeviceEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine adds DeviceInfo to an existing multi-path group.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    Group - The multi-path group to which DeviceInfo should be added.\r\n    DeviceInfo - The new device.\r\n    DeviceState - The initial device state (active, passive,...)\r\n\r\nReturn Value:\r\n\r\n    UNSUCCESSFUL - If there are too many paths already.\r\n    SUCCESS\r\n\r\n--*/\r\n{\r\n    ULONG numberDevices;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpAddDeviceEntry (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    //\r\n    // Ensure that this is a valid config - namely, it hasn't\r\n    // exceeded the number of paths supported.\r\n    //\r\n    numberDevices = * (volatile ULONG *) &Group->NumberDevices;\r\n    if (numberDevices < DSM_MAX_PATHS) {\r\n\r\n#if DBG\r\n        ULONG i;\r\n\r\n        //\r\n        // Ensure that this isn't a second copy of the same pdo.\r\n        //\r\n        for (i = 0; i < numberDevices; i++) {\r\n            if (Group->DeviceList[i]->PortPdo == DeviceInfo->PortPdo) {\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpAddDeviceEntry (DevInfo %p): Received same PDO %p twice.\\n\",\r\n                            DeviceInfo,\r\n                            DeviceInfo->PortPdo));\r\n            }\r\n        }\r\n#endif\r\n\r\n        //\r\n        // Indicate one more device is present in this group.\r\n        //\r\n        Group->DeviceList[numberDevices] = DeviceInfo;\r\n\r\n        //\r\n        // Indicate one more in the list.\r\n        //\r\n        InterlockedIncrement((LONG volatile*)&Group->NumberDevices);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpAddDeviceEntry (DevInfo %p): Adding Device to Group %p\\n\",\r\n                    DeviceInfo,\r\n                    Group));\r\n\r\n        //\r\n        // Set-up this device's group id.\r\n        //\r\n        DeviceInfo->Group = Group;\r\n\r\n        //\r\n        // One more deviceInfo entry.\r\n        //\r\n        InterlockedIncrement((LONG volatile*)&DsmContext->NumberDevices);\r\n\r\n        //\r\n        // Finally, add it to the global list of devices.\r\n        //\r\n        InsertTailList(&DsmContext->DeviceList,\r\n                       &DeviceInfo->ListEntry);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpAddDeviceEntry (DevInfo %p): Max Paths already added for Group %p.\\n\",\r\n                    DeviceInfo,\r\n                    Group));\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpAddDeviceEntry (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPDSM_CONTROLLER_LIST_ENTRY\r\nDsmpFindControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSCSI_ADDRESS ScsiAddress,\r\n    _In_reads_(ControllerSerialNumberLength) IN PSTR ControllerSerialNumber,\r\n    _In_ IN SIZE_T ControllerSerialNumberLength,\r\n    _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN AcquireLock\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine compares the passed in serial number and SCSI address with the\r\n    entries in the list of controller objects.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization.\r\n    PortObject - Port FDO exposing the controller.\r\n    ScsiAddress - The scsi address to match.\r\n    ControllerSerialNumber - The serial number for which to find a match.\r\n    ControllerSerialNumberLength - Length of the passed in serial number, in bytes.\r\n    CodeSet - Code set used when building the passed in serial number.\r\n    AcquireLock - FALSE indicates that the caller has already acquired the spin lock.\r\n\r\nReturn Value:\r\n\r\n    Controller list entry if a match is found, else NULL\r\n\r\n--*/\r\n{\r\n    KIRQL oldIrql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error\r\n    PLIST_ENTRY entry;\r\n    PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL;\r\n    BOOLEAN found = FALSE;\r\n    PDSM_CONTROLLER_LIST_ENTRY candidate = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(CodeSet);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindControllerEntry (SN %s): Entering function.\\n\",\r\n                ControllerSerialNumber));\r\n\r\n    if (AcquireLock) {\r\n\r\n        oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    }\r\n\r\n    for (entry = DsmContext->ControllerList.Flink;\r\n         entry != &DsmContext->ControllerList && !found;\r\n         entry = entry->Flink) {\r\n\r\n        controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry);\r\n        NT_ASSERT(controllerEntry);\r\n\r\n        if (!controllerEntry) {\r\n\r\n            continue;\r\n        }\r\n\r\n        //\r\n        // Serial numbers and Portal, Bus, and Target of the SCSI address must match.\r\n        //\r\n        if (!strncmp((const char*)controllerEntry->Identifier,\r\n                    ControllerSerialNumber,\r\n                    ControllerSerialNumberLength) &&\r\n            (controllerEntry->ScsiAddress->PortNumber == ScsiAddress->PortNumber &&\r\n             controllerEntry->ScsiAddress->PathId == ScsiAddress->PathId &&\r\n             controllerEntry->ScsiAddress->TargetId == ScsiAddress->TargetId)) {\r\n\r\n            if (controllerEntry->IdLength == ControllerSerialNumberLength) {\r\n\r\n                found = TRUE;\r\n\r\n            } else {\r\n\r\n                if ((!candidate) ||\r\n                    (controllerEntry->IdLength > ControllerSerialNumberLength && ControllerSerialNumberLength == 32)) {\r\n\r\n                    candidate = controllerEntry;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!found) {\r\n\r\n        if (candidate) {\r\n\r\n            controllerEntry = candidate;\r\n\r\n        } else {\r\n\r\n            controllerEntry = NULL;\r\n        }\r\n    }\r\n\r\n    //\r\n    // If we found a matching controller entry, we need to make sure the Port\r\n    // Object (FDO) is updated.  We also don't care about the LUN part of the\r\n    // SCSI address so we just set it to zero.\r\n    //\r\n    if (controllerEntry) {\r\n        controllerEntry->PortObject = PortObject;\r\n        controllerEntry->ScsiAddress->Lun = 0;\r\n    }\r\n\r\n    if (AcquireLock) {\r\n\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindControllerEntry (SN %s): Exiting function with controllerEntry %p\\n\",\r\n                ControllerSerialNumber,\r\n                controllerEntry));\r\n\r\n    return controllerEntry;\r\n}\r\n\r\n\r\n_Ret_maybenull_\r\n_Must_inspect_result_\r\n_When_(return != NULL, __drv_allocatesMem(Mem))\r\nPDSM_CONTROLLER_LIST_ENTRY\r\nDsmpBuildControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_opt_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSCSI_ADDRESS ScsiAddress,\r\n    _In_ IN PSTR ControllerSerialNumber,\r\n    _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN AcquireLock\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine builds a new controller list entry with the passed in serial number info.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization.\r\n    DeviceObject - Controller's PDO.\r\n    PortObject - Port FDO exposing the controller.\r\n    ScsiAddress - scsi address of the controller.\r\n    ControllerSerialNumber - The serial number to associate with new entry.\r\n    CodeSet - Code set of the identifier that was used to build the serial number.\r\n    AcquireLock - TRUE indicates that the function must grab the spinlock. FALSE indicates\r\n                  that caller has the spin lock held.\r\n\r\nReturn Value:\r\n\r\n    New controller list entry if we successfully built one, else NULL\r\n\r\n--*/\r\n{\r\n    KIRQL oldIrql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error\r\n    PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildControllerEntry (SN %s): Entering function - Controller %p seen through PortFDO %p.\\n\",\r\n                ControllerSerialNumber,\r\n                DeviceObject,\r\n                PortObject));\r\n\r\n    if (AcquireLock) {\r\n\r\n        oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    }\r\n\r\n    controllerEntry = DsmpAllocatePool(NonPagedPoolNx,\r\n                                       sizeof(DSM_CONTROLLER_LIST_ENTRY),\r\n                                       DSM_TAG_CONTROLLER_LIST_ENTRY);\r\n\r\n    if (controllerEntry) {\r\n\r\n        //\r\n        // Note:\r\n        // ControllerSerialNumber's length fits in a 32-bit value.\r\n        // See implementation in DsmpParseDeviceID()\r\n        //\r\n        ULONG length = (ULONG)strlen(ControllerSerialNumber);\r\n\r\n        controllerEntry->Identifier = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                       length + 1,\r\n                                                       DSM_TAG_SERIAL_NUM);\r\n\r\n        if (controllerEntry->Identifier) {\r\n\r\n            controllerEntry->ScsiAddress = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                            sizeof(SCSI_ADDRESS),\r\n                                                            DSM_TAG_SCSI_ADDRESS);\r\n            if (controllerEntry->ScsiAddress) {\r\n\r\n                RtlCopyMemory(controllerEntry->ScsiAddress, ScsiAddress, sizeof(SCSI_ADDRESS));\r\n\r\n                controllerEntry->DeviceObject = DeviceObject;\r\n                controllerEntry->PortObject = PortObject;\r\n                controllerEntry->ControllerSig = DSM_CONTROLLER_SIG;\r\n                controllerEntry->IdLength = length;\r\n                controllerEntry->IdCodeSet = CodeSet;\r\n\r\n                RtlCopyMemory(controllerEntry->Identifier,\r\n                              ControllerSerialNumber,\r\n                              length);\r\n\r\n                controllerEntry->RefCount = 0;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpBuildControllerEntry (SN %s): Failed to allocate resources for scsiaddress (controllerEntry %p).\\n\",\r\n                            ControllerSerialNumber,\r\n                            controllerEntry));\r\n\r\n                DsmpFreePool(controllerEntry->Identifier);\r\n                controllerEntry->Identifier = NULL;\r\n                DsmpFreePool(controllerEntry);\r\n                controllerEntry = NULL;\r\n            }\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildControllerEntry (SN %s): Failed to allocate resources for identifier (controllerEntry %p).\\n\",\r\n                        ControllerSerialNumber,\r\n                        controllerEntry));\r\n\r\n            DsmpFreePool(controllerEntry);\r\n            controllerEntry = NULL;\r\n        }\r\n\r\n    } else {\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildControllerEntry (SN %s): Failed to allocate memory for ControllerEntry.\\n\",\r\n                    ControllerSerialNumber));\r\n    }\r\n\r\n    if (AcquireLock) {\r\n\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildControllerEntry (SN %s): Exiting function with controllerEntry %p\\n\",\r\n                ControllerSerialNumber,\r\n                controllerEntry));\r\n\r\n    return controllerEntry;\r\n}\r\n\r\n\r\nVOID\r\nDsmpFreeControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ __drv_freesMem(Mem) IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine frees the allocations of the passed in controller list entry.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization.\r\n    ControllerEntry - Controller list entry.\r\n\r\nReturn Value:\r\n\r\n    Nothing\r\n\r\n--*/\r\n{\r\n    PVOID tempAddress = (PVOID)ControllerEntry;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFreeControllerEntry (Entry %p): Entering function.\\n\",\r\n                ControllerEntry));\r\n\r\n    if (ControllerEntry->Identifier) {\r\n        DsmpFreePool(ControllerEntry->Identifier);\r\n    }\r\n\r\n    if (ControllerEntry->ScsiAddress) {\r\n        DsmpFreePool(ControllerEntry->ScsiAddress);\r\n    }\r\n\r\n    DsmpFreePool(ControllerEntry);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFreeControllerEntry (Entry %p): Exiting function.\\n\",\r\n                tempAddress));\r\n\r\n    return;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpIsDeviceBelongsToController(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine determines if the device passed in was exposed via the passed\r\n    in controller.\r\n    The match is to be based on VID and SCSI Address (using the Port, Bus\r\n    and Target comparison).\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization.\r\n    DeviceInfo - The device instance to match.\r\n    ControllerEntry - The controller object which we need to determine whether\r\n                      DeviceInfo is exposed from.\r\n\r\nReturn Value:\r\n\r\n    TRUE - if the controller's VID and scsi address match\r\n    FALSE - not matched\r\n\r\n--*/\r\n{\r\n    BOOLEAN saMatch = FALSE;\r\n    BOOLEAN vMatch = FALSE;\r\n    BOOLEAN match = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpIsDeviceBelongsToController (DevInfo %p): Entering function - ControllerEntry is %p.\\n\",\r\n                DeviceInfo,\r\n                ControllerEntry));\r\n\r\n    if (DeviceInfo->ScsiAddress && ControllerEntry->ScsiAddress) {\r\n\r\n        saMatch = (DeviceInfo->ScsiAddress->PathId == ControllerEntry->ScsiAddress->PathId &&\r\n                   DeviceInfo->ScsiAddress->PortNumber == ControllerEntry->ScsiAddress->PortNumber &&\r\n                   DeviceInfo->ScsiAddress->TargetId == ControllerEntry->ScsiAddress->TargetId);\r\n    }\r\n\r\n    if (saMatch) {\r\n\r\n        INQUIRYDATA inquiryData = {0};\r\n        UCHAR controllerVID[9] = {0};\r\n        UCHAR deviceVID[9] = {0};\r\n\r\n        if (NT_SUCCESS(DsmpGetStandardInquiryData(ControllerEntry->DeviceObject, &inquiryData))) {\r\n\r\n            RtlStringCchCopyA((PSTR)controllerVID,\r\n                              ARRAYSIZE(controllerVID),\r\n                              (PCSTR)(&inquiryData.VendorId));\r\n\r\n            RtlStringCchCopyA((PSTR)deviceVID,\r\n                              ARRAYSIZE(deviceVID),\r\n                              (PCSTR)(&DeviceInfo->Descriptor) + DeviceInfo->Descriptor.VendorIdOffset);\r\n\r\n\r\n            if (!strcmp((const char*)controllerVID, (const char*)deviceVID)) {\r\n\r\n                vMatch = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    match = saMatch & vMatch;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpIsDeviceBelongsToController (DevInfo %p): ControllerEntry %p. Exiting function with match = %x.\\n\",\r\n                DeviceInfo,\r\n                ControllerEntry,\r\n                match));\r\n\r\n    return match;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindDevInfoFromGroupAndFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_FAILOVER_GROUP FOGroup\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will find the deviceInfo that is part of both the passed in Group\r\n    as well as passed in Fail-Over group.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    Group - The group that represents the device.\r\n    FOGroup - The FOG that the device is part of.\r\n\r\nReturn Value:\r\n\r\n    The deviceInfo that is part of both.\r\n    NULL - if not found.\r\n\r\n--*/\r\n{\r\n    ULONG i;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpFindDevInfoFromGroupAndFOGroup (Group %p FOG %p): Entering function.\\n\",\r\n                Group,\r\n                FOGroup));\r\n\r\n    if (Group && FOGroup) {\r\n\r\n        //\r\n        // Run through the list of devInfos in passed in Group\r\n        //\r\n        for (i = 0; i < DSM_MAX_PATHS; i++) {\r\n\r\n            deviceInfo = Group->DeviceList[i];\r\n\r\n            if (deviceInfo) {\r\n\r\n                if (deviceInfo->FailGroup == FOGroup) {\r\n\r\n                    break;\r\n\r\n                } else {\r\n\r\n                    deviceInfo = NULL;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpFindFOGroup (Group %p FOG %p): Exiting function with deviceInfo %p.\\n\",\r\n                Group,\r\n                FOGroup,\r\n                deviceInfo));\r\n\r\n    return deviceInfo;\r\n}\r\n\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpFindFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PVOID PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will find the Fail-Over group that corresponds to PathId.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    PathId - The Path Identifier that corresponds to\r\n             an adapter/adapter-controller\r\n\r\nReturn Value:\r\n\r\n    The fail-over group.\r\n    NULL - if not found.\r\n\r\n--*/\r\n{\r\n    PDSM_FAILOVER_GROUP failOverGroup = NULL;\r\n    PDSM_FAILOVER_GROUP retFOGroup = NULL;\r\n    PLIST_ENTRY entry;\r\n    ULONG i;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindFOGroup (PathId %p): Entering function.\\n\",\r\n                PathId));\r\n\r\n    //\r\n    // Run through the list of Fail-Over Groups\r\n    //\r\n    entry = DsmContext->FailGroupList.Flink;\r\n    for (i = 0; i < DsmContext->NumberFOGroups; i++, entry = entry->Flink) {\r\n\r\n        //\r\n        // Extract the fail-over group structure.\r\n        //\r\n        failOverGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry);\r\n        NT_ASSERT(failOverGroup);\r\n\r\n        if (!failOverGroup) {\r\n            continue;\r\n        }\r\n\r\n        //\r\n        // Check for a match of the PathId.\r\n        //\r\n        if (failOverGroup->PathId == PathId) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpFindFOGroup (PathId %p): Found a FO group %p.\\n\",\r\n                        PathId,\r\n                        failOverGroup));\r\n\r\n            retFOGroup = failOverGroup;\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindFOGroup (PathId %p): Exiting function with retFOGroup %p.\\n\",\r\n                PathId,\r\n                retFOGroup));\r\n\r\n    return retFOGroup;\r\n}\r\n\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpBuildFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PVOID *PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will build and partially initialise a fail-over group entry.\r\n    The FOG corresponds to the device list which will fail as a group.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DeviceInfo - The first device to add to the group.\r\n    PathId - An identifier that is returned to mpio that id's the path.\r\n\r\nReturn Value:\r\n\r\n    The fail-over group entry.\r\n    NULL - on failed allocation.\r\n\r\n--*/\r\n{\r\n    PDSM_FAILOVER_GROUP failOverGroup;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildFOGroup (PathId %p): Entering function.\\n\", PathId));\r\n\r\n    //\r\n    // Allocate a new Fail Over Group\r\n    //\r\n    failOverGroup = DsmpAllocatePool(NonPagedPoolNx,\r\n                                     sizeof(DSM_FAILOVER_GROUP),\r\n                                     DSM_TAG_FO_GROUP);\r\n    if (failOverGroup) {\r\n\r\n        InitializeListHead(&failOverGroup->FOG_DeviceList);\r\n        InitializeListHead(&failOverGroup->ZombieGroupList);\r\n\r\n        //\r\n        // Get the current number of groups, and add the one that's being created.\r\n        //\r\n        InterlockedIncrement((LONG volatile*)&DsmContext->NumberFOGroups);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildFOGroup (PathId %p): Path that will be used for %p is %p.\\n\",\r\n                    PathId,\r\n                    DeviceInfo,\r\n                    *PathId));\r\n\r\n        failOverGroup->PathId = *PathId;\r\n\r\n        //\r\n        // Set the initial state to NORMAL.\r\n        //\r\n        failOverGroup->State = DSM_FG_NORMAL;\r\n\r\n        failOverGroup->FailOverSig = DSM_FOG_SIG;\r\n\r\n        //\r\n        // Add it to the global list.\r\n        //\r\n        InsertTailList(&DsmContext->FailGroupList,\r\n                       &failOverGroup->ListEntry);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildFOGroup (PathId %p): Added new FOGroup %p with path %p. Count of FO Group %d.\\n\",\r\n                    PathId,\r\n                    failOverGroup,\r\n                    *PathId,\r\n                    DsmContext->NumberFOGroups));\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildFOGroup (PathId %p): Failed to allocate memory for FailOverGroup.\\n\",\r\n                    PathId));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildFOGroup (PathId %p): Exiting function with failOverGroup %p.\\n\",\r\n                PathId,\r\n                failOverGroup));\r\n\r\n    return failOverGroup;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpUpdateFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will add DeviceInfo to an existing FOG.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    FailGroup - The fail-over group entry.\r\n    DeviceInfo - The new device.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate error code.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpUpdateFOGroup (FOG %p): Entering function. DeviceInfo %p.\\n\",\r\n                FailGroup,\r\n                DeviceInfo));\r\n\r\n    if (DeviceInfo && FailGroup) {\r\n\r\n        fogDeviceListEntry = DsmpAllocatePool(NonPagedPoolNx,\r\n                                              sizeof(DSM_FOG_DEVICELIST_ENTRY),\r\n                                              DSM_TAG_FOG_DEV_ENTRY);\r\n\r\n        if (fogDeviceListEntry) {\r\n\r\n            //\r\n            // Add the device to the list of devices that are on this path.\r\n            //\r\n            fogDeviceListEntry->DeviceInfo = DeviceInfo;\r\n            InterlockedIncrement((LONG volatile*)&FailGroup->Count);\r\n            InsertTailList(&FailGroup->FOG_DeviceList, &fogDeviceListEntry->ListEntry);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpUpdateFOGroup (FOG %p): DevInfo %p added (current count: %d)\\n\",\r\n                        FailGroup,\r\n                        DeviceInfo,\r\n                        FailGroup->Count));\r\n\r\n            //\r\n            // Set the device's F.O. Group.\r\n            //\r\n            DeviceInfo->FailGroup = FailGroup;\r\n\r\n        } else {\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpUpdateFOGroup (FOG %p): Failed to allocate memory for FOG devlist entry.\\n\",\r\n                        FailGroup));\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpUpdateFOGroup (FOG %p): Exiting function with status %x.\\n\",\r\n                FailGroup,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmpRemoveDeviceFailGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will remove DeviceInfo from the FOG.\r\n    This routine is called in response to a removal of the device.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    FailGroup - The FOG from which DeviceInfo should be removed.\r\n    DeviceInfo - The now missing device.\r\n    AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively\r\n\r\nReturn Value:\r\n\r\n    NOTHING\r\n\r\n--*/\r\n{\r\n    KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings\r\n    PLIST_ENTRY entry;\r\n    PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry;\r\n    PLIST_ENTRY zombieEntry;\r\n    PDSM_ZOMBIEGROUP_ENTRY zombieGroup;\r\n    PDSM_ZOMBIEGROUP_ENTRY newZombieGroup;\r\n    BOOLEAN groupInZombieList = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveDeviceFailGroup (FOG %p): Entering function. DeviceInfo %p.\\n\",\r\n                FailGroup,\r\n                DeviceInfo));\r\n\r\n    if (FailGroup && DeviceInfo) {\r\n\r\n        if (AcquireDSMLockExclusive) {\r\n            irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n        }\r\n\r\n        for (entry = FailGroup->FOG_DeviceList.Flink;\r\n             entry != &FailGroup->FOG_DeviceList;\r\n             entry = entry->Flink) {\r\n\r\n            fogDeviceListEntry = CONTAINING_RECORD(entry,\r\n                                                   DSM_FOG_DEVICELIST_ENTRY,\r\n                                                   ListEntry);\r\n            DSM_ASSERT(fogDeviceListEntry);\r\n\r\n            if (!fogDeviceListEntry) {\r\n                continue;\r\n            }\r\n\r\n            if (fogDeviceListEntry->DeviceInfo == DeviceInfo) {\r\n\r\n                DeviceInfo->FailGroup = NULL;\r\n                RemoveEntryList(entry);\r\n                DsmpFreePool(fogDeviceListEntry);\r\n\r\n                InterlockedDecrement((LONG volatile*)&FailGroup->Count);\r\n\r\n                //\r\n                // If a DeviceInfo is removed, we need to keep its group in a\r\n                // \"zombie\" list so that we can still access a fail-over group's\r\n                // associated groups even when all its devices are gone.\r\n                //\r\n                for (zombieEntry = FailGroup->ZombieGroupList.Flink;\r\n                     zombieEntry != &(FailGroup->ZombieGroupList);\r\n                     zombieEntry = zombieEntry->Flink) {\r\n\r\n                    zombieGroup = CONTAINING_RECORD(zombieEntry, DSM_ZOMBIEGROUP_ENTRY, ListEntry);\r\n                    if (zombieGroup != NULL &&\r\n                        zombieGroup->Group != NULL &&\r\n                        zombieGroup->Group == DeviceInfo->Group) {\r\n\r\n                        groupInZombieList = TRUE;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                //\r\n                // Create a new entry if the group does not exist in the zombie group list.\r\n                //\r\n                if (groupInZombieList == FALSE) {\r\n                    newZombieGroup = (PDSM_ZOMBIEGROUP_ENTRY)DsmpAllocatePool(NonPagedPoolNx,\r\n                                                                              sizeof(DSM_ZOMBIEGROUP_ENTRY),\r\n                                                                              DSM_TAG_ZOMBIEGROUP_ENTRY);\r\n                    if (newZombieGroup != NULL) {\r\n                        newZombieGroup->Group = DeviceInfo->Group;\r\n                        InsertTailList(&FailGroup->ZombieGroupList, &newZombieGroup->ListEntry);\r\n                    } else {\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmpRemoveDeviceFailGroup (DevInfo %p): Failed to allocate memory for the zombie group.\\n\",\r\n                                    DeviceInfo));\r\n                    }\r\n                }\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpRemoveDeviceFailGroup (FOG %p): DevInfo %p removed from FOG (current count: %d)\\n\",\r\n                            FailGroup,\r\n                            DeviceInfo,\r\n                            FailGroup->Count));\r\n\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (AcquireDSMLockExclusive) {\r\n            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveDeviceFailGroup (FOG %p): Exiting function.\\n\",\r\n                FailGroup));\r\n\r\n    return;\r\n}\r\n\r\n\r\nULONG\r\nDsmpRemoveDeviceEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will remove DeviceInfo from Group. If it is the last DeviceInfo\r\n    in the Group, it has the added side-effect of cleaning up the Group entry\r\n    also.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    Group - The multi-path group from which DeviceInfo should be removed.\r\n    DeviceInfo - The device to remove.\r\n\r\nReturn Value:\r\n\r\n    Number of devices left in group.\r\n\r\n--*/\r\n{\r\n    KIRQL irql;\r\n    ULONG i;\r\n    ULONG j;\r\n    ULONG numberDevices;\r\n    BOOLEAN freeGroup = FALSE;\r\n    PVOID tempAddress = (PVOID)Group;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveDeviceEntry (Group %p): Entering function. DeviceInfo %p.\\n\",\r\n                Group,\r\n                DeviceInfo));\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    //\r\n    // Find it's offset in the array of devices.\r\n    //\r\n    for (i = 0; i < Group->NumberDevices; i++) {\r\n\r\n        if (Group->DeviceList[i] == DeviceInfo) {\r\n\r\n            //\r\n            // Zero out it's entry.\r\n            //\r\n            Group->DeviceList[i] = NULL;\r\n\r\n            //\r\n            // Reduce the number in the group.\r\n            //\r\n            InterlockedDecrement((LONG volatile*)&Group->NumberDevices);\r\n\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRemoveDeviceEntry (Group %p): Removing Device %p (desiredState %u) from Group\\n\",\r\n                        Group,\r\n                        DeviceInfo,\r\n                        DeviceInfo->DesiredState));\r\n\r\n            //\r\n            // Collapse the array.\r\n            // Holding the spinlock, so that the state is consistent in other\r\n            // routines.\r\n            //\r\n            for (j = i; j < Group->NumberDevices; j++) {\r\n\r\n                //\r\n                // Shuffle all entries down to fill the hole.\r\n                //\r\n                Group->DeviceList[j] = Group->DeviceList[j + 1];\r\n            }\r\n\r\n            //\r\n            // Zero out the last one.\r\n            //\r\n            Group->DeviceList[j] = NULL;\r\n            break;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Remove this devInfo from the TargetPort deviceList\r\n    //\r\n    DsmpRemoveDeviceFromTargetPortList(DeviceInfo);\r\n\r\n    numberDevices = Group->NumberDevices;\r\n\r\n    //\r\n    // See if anything is left in the Group.\r\n    //\r\n    if (Group->NumberDevices == 0) {\r\n\r\n        Group->State = DSM_GP_FAILED;\r\n\r\n        //\r\n        // Yank it from the Group list.\r\n        //\r\n        DsmpRemoveGroupEntry(DsmContext, Group, FALSE);\r\n\r\n        freeGroup = TRUE;\r\n    }\r\n\r\n    //\r\n    // Yank the device out of the Global list.\r\n    //\r\n    RemoveEntryList(&DeviceInfo->ListEntry);\r\n    InterlockedDecrement((LONG volatile*)&DsmContext->NumberDevices);\r\n\r\n    //\r\n    // If the serial number buffer was allocated, need to free it.\r\n    //\r\n    if (DeviceInfo->SerialNumberAllocated) {\r\n        DsmpFreePool(DeviceInfo->SerialNumber);\r\n    }\r\n\r\n    if (DeviceInfo->ScsiAddress) {\r\n        DsmpFreePool(DeviceInfo->ScsiAddress);\r\n    }\r\n\r\n    //\r\n    // Fix up the Reservation List, if needed.\r\n    //\r\n    if (!freeGroup && Group->ReservationList) {\r\n        ULONG oldList;\r\n\r\n        //\r\n        // Capture the list for debugging.\r\n        //\r\n        oldList = Group->ReservationList;\r\n        Group->ReservationList = 0;\r\n\r\n        //\r\n        // Go through all devices in this group and find the one(s) registered.\r\n        //\r\n        for (i = 0; i < Group->NumberDevices; i++) {\r\n\r\n            if (Group->DeviceList[i]->RegisterServiced) {\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmRemoveDeviceEntry (Group %p): Device %p at %d registered.\\n\",\r\n                            Group,\r\n                            Group->DeviceList[i],\r\n                            i));\r\n\r\n                //\r\n                // Indicate its place.\r\n                //\r\n                Group->ReservationList |= (1 << i);\r\n            }\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmRemoveDeviceEntry (Group %p): Reservations Old (%x) New (%x).\\n\",\r\n                    Group,\r\n                    oldList,\r\n                    Group->ReservationList));\r\n    }\r\n\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    //\r\n    // Free the allocation.\r\n    //\r\n    DsmpFreePool(DeviceInfo);\r\n\r\n    if (freeGroup) {\r\n\r\n        //\r\n        // Free the allocations.\r\n        //\r\n        if (Group->RegistryKeyName) {\r\n            DsmpFreePool(Group->RegistryKeyName);\r\n        }\r\n\r\n        if (Group->HardwareId) {\r\n            DsmpFreePool(Group->HardwareId);\r\n        }\r\n\r\n        DsmpFreePool(Group);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveDeviceEntry (Group %p): Exiting function - numberDevices = %x.\\n\",\r\n                tempAddress,\r\n                numberDevices));\r\n\r\n    return numberDevices;\r\n}\r\n\r\n\r\nVOID\r\nDsmpRemoveDeviceFromTargetPortList(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will remove a DeviceInfo from its target port device list.\r\n\r\n    The caller should ensure that the DsmContext->SpinLock is held before\r\n    calling this function.\r\n\r\nArguments:\r\n\r\n    DeviceInfo - The DeviceInfo to be removed.\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    if (DeviceInfo->TargetPort) {\r\n\r\n        PLIST_ENTRY entry;\r\n        PDSM_TARGET_PORT_DEVICELIST_ENTRY listEntry;\r\n\r\n        for (entry = DeviceInfo->TargetPort->TP_DeviceList.Flink;\r\n             entry != NULL && entry != &DeviceInfo->TargetPort->TP_DeviceList;\r\n             entry = entry->Flink) {\r\n\r\n                listEntry = CONTAINING_RECORD(entry, DSM_TARGET_PORT_DEVICELIST_ENTRY, ListEntry);\r\n\r\n                if (listEntry) {\r\n\r\n                    if (listEntry->DeviceInfo == DeviceInfo) {\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmpRemoveDeviceFromTargetPortList: Removing device %p from target port entry %p.\\n\",\r\n                                    DeviceInfo,\r\n                                    listEntry));\r\n\r\n                        RemoveEntryList(entry);\r\n                        InterlockedDecrement((LONG volatile*)&DeviceInfo->TargetPort->Count);\r\n                        DsmpFreePool(listEntry);\r\n\r\n                        DeviceInfo->TargetPort = NULL;\r\n                        DeviceInfo->TargetPortGroup = NULL;\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n}\r\n\r\n\r\nVOID\r\nDsmpRemoveZombieGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY ZombieGroup\r\n    )\r\n/* ++\r\n\r\nRoutine Description:\r\n\r\n    This will scan through all the Failover Groups and remove the given Group\r\n    from each Failover Group's zombie group list.\r\n\r\n    The DSM lock should be aquired by the caller.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    ZombieGroup - Group entry that should be removed from FOGs' ZombieGroupList\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n-- */\r\n{\r\n    //\r\n    // Run through the list of Fail-Over Groups\r\n    //\r\n    ULONG i;\r\n    PDSM_FAILOVER_GROUP failOverGroup = NULL;\r\n    PLIST_ENTRY fogEntry;\r\n    PLIST_ENTRY groupEntry;\r\n    PDSM_ZOMBIEGROUP_ENTRY zombieGroupEntry;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n            TRACE_FLAG_PNP,\r\n            \"DsmpRemoveZombieGroupEntry (Group %p): Entering function.\\n\",\r\n            ZombieGroup));\r\n\r\n    fogEntry = DsmContext->FailGroupList.Flink;\r\n    for (i = 0; fogEntry != NULL && i < DsmContext->NumberFOGroups; i++, fogEntry = fogEntry->Flink) {\r\n\r\n            failOverGroup = CONTAINING_RECORD(fogEntry, DSM_FAILOVER_GROUP, ListEntry);\r\n            if (failOverGroup != NULL) {\r\n\r\n                for (groupEntry = failOverGroup->ZombieGroupList.Flink;\r\n                     groupEntry != &(failOverGroup->ZombieGroupList);\r\n                     groupEntry = groupEntry->Flink) {\r\n\r\n                    zombieGroupEntry = CONTAINING_RECORD(groupEntry, DSM_ZOMBIEGROUP_ENTRY, ListEntry);\r\n                    if (zombieGroupEntry != NULL &&\r\n                        zombieGroupEntry->Group != NULL &&\r\n                        zombieGroupEntry->Group == ZombieGroup) {\r\n\r\n                        RemoveEntryList(groupEntry);\r\n                        DsmpFreePool(zombieGroupEntry);\r\n\r\n                        TracePrint((TRACE_LEVEL_VERBOSE,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpRemoveZombieGroupEntry (Group %p): Found and removed a zombie group in (FOG %p)\\n\",\r\n                            ZombieGroup,\r\n                            failOverGroup));\r\n\r\n                        //\r\n                        // We removed the zombie group entry from this fail-over\r\n                        // group, so we can move on to the next fail-over group.\r\n                        //\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n            TRACE_FLAG_PNP,\r\n            \"DsmpRemoveZombieGroupEntry (Group %p): Exiting function.\\n\",\r\n            ZombieGroup));\r\n}\r\n\r\n\r\nVOID\r\nDsmpRemoveGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY GroupEntry,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This will remove a group entry from the DSM's list.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    GroupEntry - Group entry that should be removed from DSM's list\r\n    AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings\r\n    ULONG index;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup;\r\n    PLIST_ENTRY entry;\r\n    PDSM_TARGET_PORT_LIST_ENTRY targetPort;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveGroupEntry (Group %p): Entering function.\\n\",\r\n                GroupEntry));\r\n\r\n    if (AcquireDSMLockExclusive) {\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    }\r\n\r\n    NT_ASSERT(GroupEntry && GroupEntry->ListEntry.Flink && GroupEntry->ListEntry.Blink);\r\n\r\n    //\r\n    // Since this group is being removed, we need to make sure it is also\r\n    // removed from all fail-over groups' zombie group lists.\r\n    //\r\n    DsmpRemoveZombieGroupEntry(DsmContext, GroupEntry);\r\n\r\n    //\r\n    // Add it to the list of multi-path groups.\r\n    //\r\n    RemoveEntryList(&GroupEntry->ListEntry);\r\n\r\n    GroupEntry->ListEntry.Flink = GroupEntry->ListEntry.Blink = NULL;\r\n\r\n    InterlockedDecrement((LONG volatile*)&DsmContext->NumberGroups);\r\n\r\n    for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n        //\r\n        // Clean up all its Target Port Groups\r\n        //\r\n        targetPortGroup = GroupEntry->TargetPortGroupList[index];\r\n\r\n        if (targetPortGroup) {\r\n\r\n            GroupEntry->TargetPortGroupList[index] = NULL;\r\n\r\n            //\r\n            // For each target port group, clean up all its target ports\r\n            //\r\n            while (!IsListEmpty(&targetPortGroup->TargetPortList)) {\r\n\r\n                entry = RemoveHeadList(&targetPortGroup->TargetPortList);\r\n\r\n                if (entry) {\r\n\r\n                    targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n\r\n                    if (targetPort) {\r\n\r\n                        PLIST_ENTRY deviceEntry;\r\n                        PDSM_TARGET_PORT_DEVICELIST_ENTRY listEntry;\r\n\r\n                        while (!IsListEmpty(&targetPort->TP_DeviceList)) {\r\n\r\n                            deviceEntry = RemoveHeadList(&targetPort->TP_DeviceList);\r\n\r\n                            if (deviceEntry) {\r\n\r\n                                listEntry = CONTAINING_RECORD(deviceEntry,\r\n                                                              DSM_TARGET_PORT_DEVICELIST_ENTRY,\r\n                                                              ListEntry);\r\n\r\n                                if (listEntry) {\r\n\r\n                                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                TRACE_FLAG_PNP,\r\n                                                \"DsmpRemoveGroupEntry (Group %p): Deleting device %p from TP %p list (TPG %p).\\n\",\r\n                                                GroupEntry,\r\n                                                listEntry->DeviceInfo,\r\n                                                targetPort,\r\n                                                targetPortGroup));\r\n\r\n                                    DsmpFreePool(listEntry);\r\n\r\n                                    InterlockedDecrement((LONG volatile*)&targetPort->Count);\r\n                                }\r\n                            }\r\n                        }\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmpRemoveGroupEntry (Group %p): Deleting target port %p from TPG %p list.\\n\",\r\n                                    GroupEntry,\r\n                                    targetPort,\r\n                                    targetPortGroup));\r\n\r\n                        DsmpFreePool(targetPort);\r\n\r\n                        InterlockedDecrement((LONG volatile*)&targetPortGroup->NumberTargetPorts);\r\n                    }\r\n                }\r\n            }\r\n\r\n            NT_ASSERT(targetPortGroup->NumberTargetPorts == 0);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRemoveGroupEntry (Group %p): Deleting target port group %p.\\n\",\r\n                        GroupEntry,\r\n                        targetPortGroup));\r\n\r\n            DsmpFreePool(targetPortGroup);\r\n\r\n            InterlockedDecrement((LONG volatile*)&GroupEntry->NumberTargetPortGroups);\r\n        }\r\n    }\r\n\r\n    NT_ASSERT(GroupEntry->NumberTargetPortGroups == 0);\r\n\r\n    if (AcquireDSMLockExclusive) {\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRemoveGroupEntry (Group %p): Exiting function.\\n\",\r\n                GroupEntry));\r\n\r\n    return;\r\n}\r\n\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpSetNewPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevice\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will assign a new path to the multi-path group in\r\n    which FailingDevice resides.\r\n\r\n    Caller must NOT hold spin lock.\r\n\r\nArguments:\r\n\r\n    DsmContext    - DSM context given to MPIO during initialization\r\n\r\n    FailingDevice - The device-path that is being moved\r\n                    (due to failure, or admin. request)\r\n\r\nReturn Value:\r\n\r\n    The FOG containing the new path.\r\n\r\n--*/\r\n{\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetNewPath (DevInfo %p): Entering function.\\n\",\r\n                FailingDevice));\r\n\r\n    if (DsmpIsSymmetricAccess(FailingDevice)) {\r\n\r\n        DsmpSetLBForPathRemoval(DsmContext, FailingDevice, NULL, SpecialHandlingFlag);\r\n\r\n    } else {\r\n\r\n        DsmpSetLBForPathRemovalALUA(DsmContext, FailingDevice, NULL, SpecialHandlingFlag);\r\n    }\r\n\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetNewPath (DevInfo %p): Exiting function with path (failGroup) %p.\\n\",\r\n                FailingDevice,\r\n                FailingDevice->Group->PathToBeUsed));\r\n\r\n    return FailingDevice->Group->PathToBeUsed;\r\n}\r\n\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpSetNewPathUsingGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n       This routine will try to assign a new path using the given multi-path group.\r\n       This function should only be called during failover in the event that there\r\n       is no DeviceInfo with which to call DsmpSetNewPath().\r\n\r\n       Typically this will be called with one of a fail-over group's zombie groups.\r\n\r\n       Caller must NOT hold spin lock.\r\n\r\nArguments:\r\n\r\n       DsmContext - DSM context given to MPIO during initialization.\r\n\r\n       Group - The multi-path group which to assign a new path.\r\n\r\nReturn Value:\r\n\r\n       The FOG containing the new path or NULL if no path was found.\r\n\r\n--*/\r\n\r\n{\r\n    ULONG               i;\r\n    PDSM_DEVICE_INFO    pDevInfo = NULL;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetNewPathUsingGroup (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    //\r\n    // Get the first available DeviceInfo.\r\n    //\r\n    for (i = 0; i < DSM_MAX_PATHS; i ++) {\r\n        if (Group->DeviceList[i] != NULL) {\r\n            pDevInfo = Group->DeviceList[i];\r\n            break;\r\n        }\r\n    }\r\n\r\n    if (pDevInfo == NULL) {\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpSetNewPathForZombieGroup (ZombieGroup %p): No failover group can be found.\\n\",\r\n                    Group));\r\n        return NULL;\r\n    }\r\n\r\n\r\n    if (DsmpIsSymmetricAccess(pDevInfo)) {\r\n\r\n        DsmpSetLBForPathRemoval(DsmContext, pDevInfo, Group, SpecialHandlingFlag);\r\n\r\n    } else {\r\n\r\n        DsmpSetLBForPathRemovalALUA(DsmContext, pDevInfo, Group, SpecialHandlingFlag);\r\n    }\r\n\r\n\r\n    TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetNewPathForZombieGroup (ZombieGroup %p): Exiting function with path (failGroup) %p.\\n\",\r\n                Group,\r\n                Group->PathToBeUsed));\r\n\r\n    return Group->PathToBeUsed;\r\n\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpUpdateTargetPortGroupDevicesStates(\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN DSM_DEVICE_STATE NewState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will update the target port group and all its appropriate\r\n    devInfos (ones not in remove pending, removed, or invalidated) with the\r\n    new state. The ALUAState will only be updated, NOT the real State.\r\n    Caller needs to update the real State based on the current LB policy.\r\n\r\n    Note: This should be called with DsmContext Lock held and should only be\r\n    called after a SetTargetPortGroups request was sent down.\r\n\r\nArguments:\r\n\r\n    TargetPortGroup - TargetPortGroup whose state and deviceInfos need to be\r\n                      updated\r\n\r\n    NewState        - The new state\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PLIST_ENTRY entry = NULL;\r\n    PDSM_TARGET_PORT_LIST_ENTRY targetPort = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Entering function.\\n\",\r\n                TargetPortGroup));\r\n\r\n    if (!TargetPortGroup) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Invalid TPG passed in.\\n\",\r\n                    TargetPortGroup));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpUpdateTargetPortGroupDevicesStates;\r\n    }\r\n\r\n    //\r\n    // First update TPG's asymmetric access state.\r\n    //\r\n    TargetPortGroup->AsymmetricAccessState = NewState;\r\n\r\n    //\r\n    // Now update state of each of the devices belonging to this TPG.\r\n    //\r\n    for (entry = TargetPortGroup->TargetPortList.Flink;\r\n         entry != &TargetPortGroup->TargetPortList;\r\n         entry = entry->Flink) {\r\n\r\n        targetPort = CONTAINING_RECORD(entry, DSM_TARGET_PORT_LIST_ENTRY, ListEntry);\r\n        NT_ASSERT(targetPort);\r\n\r\n        if (targetPort) {\r\n\r\n            PLIST_ENTRY deviceEntry;\r\n            PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device;\r\n\r\n            for (deviceEntry = targetPort->TP_DeviceList.Flink;\r\n                 deviceEntry != &targetPort->TP_DeviceList;\r\n                 deviceEntry = deviceEntry->Flink) {\r\n\r\n                tp_device = CONTAINING_RECORD(deviceEntry,\r\n                                              DSM_TARGET_PORT_DEVICELIST_ENTRY,\r\n                                              ListEntry);\r\n\r\n                if (tp_device) {\r\n\r\n                    tp_device->DeviceInfo->ALUAState = NewState;\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_GENERAL,\r\n                                \"DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Updated device %p alua state to %x.\\n\",\r\n                                TargetPortGroup,\r\n                                tp_device->DeviceInfo,\r\n                                tp_device->DeviceInfo->ALUAState));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmpUpdateTargetPortGroupDevicesStates:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpUpdateTargetPortGroupDevicesStates (TPG %p): Exiting function with status %x.\\n\",\r\n                TargetPortGroup,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmpIncrementCounters(\r\n    _In_ PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ PSCSI_REQUEST_BLOCK Srb\r\n    )\r\n{\r\n    ULONG bytes = 0;\r\n    PCDB cdb = NULL;\r\n    ULONG cdbLength = 0;\r\n    BOOLEAN isReadWrite = FALSE;\r\n    ULONGLONG lastLba = 0;\r\n    ULONG numBlocks = 0;\r\n    ULONGLONG startLba = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpIncrementCounters (FOG %p): Entering function.\\n\",\r\n                FailGroup));\r\n\r\n    if (Srb) {\r\n\r\n        cdb = SrbGetCdb(Srb);\r\n\r\n        if (cdb && DsmIsReadWrite(cdb->AsByte[0])) {\r\n\r\n            isReadWrite = TRUE;\r\n        }\r\n    }\r\n\r\n    InterlockedIncrement(&FailGroup->NumberOfRequestsInFlight);\r\n\r\n    //\r\n    // Update counters that apply to read/write requests\r\n    //\r\n    if (isReadWrite) {\r\n\r\n        bytes = SrbGetDataTransferLength(Srb);\r\n\r\n        InterlockedExchangeAdd64((LONGLONG volatile*)&FailGroup->OutstandingBytesOfIO, bytes);\r\n\r\n        cdbLength = SrbGetCdbLength(Srb);\r\n\r\n        if (cdbLength == 16) {\r\n\r\n            REVERSE_BYTES_QUAD(&startLba, &cdb->CDB16.LogicalBlock);\r\n            REVERSE_BYTES(&numBlocks, &cdb->CDB16.TransferLength);\r\n\r\n        } else {\r\n\r\n            REVERSE_BYTES(&startLba, &cdb->CDB10.LogicalBlockByte0);\r\n            REVERSE_BYTES_SHORT(&numBlocks, &cdb->CDB10.TransferBlocksMsb);\r\n        }\r\n\r\n        lastLba = startLba + numBlocks - 1;\r\n\r\n        InterlockedExchange64((LONGLONG volatile*)&FailGroup->LastLba, lastLba);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpIncrementCounters (FOG %p): Exiting function.\\n\",\r\n                FailGroup));\r\n\r\n    return;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpDecrementCounters(\r\n    _In_ PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ PSCSI_REQUEST_BLOCK Srb\r\n    )\r\n{\r\n    ULONG bytes = 0;\r\n    PCDB cdb = NULL;\r\n    BOOLEAN isReadWrite = FALSE;\r\n    BOOLEAN isDeletionEligible = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpDecrementCounters (FOG %p): Entering function.\\n\",\r\n                FailGroup));\r\n\r\n    if (Srb) {\r\n\r\n        cdb = SrbGetCdb(Srb);\r\n\r\n        if (cdb && DsmIsReadWrite(cdb->AsByte[0])) {\r\n\r\n            isReadWrite = TRUE;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Update counters that apply to read/write requests\r\n    //\r\n    if (isReadWrite) {\r\n\r\n        bytes = SrbGetDataTransferLength(Srb);\r\n\r\n        InterlockedExchangeAdd64((LONGLONG volatile*)&FailGroup->OutstandingBytesOfIO, -(LONGLONG)bytes);\r\n    }\r\n\r\n    NT_ASSERT(FailGroup->NumberOfRequestsInFlight > 0);\r\n    if (InterlockedCompareExchange(&FailGroup->NumberOfRequestsInFlight, 0, 0) > 0) {\r\n\r\n        if(InterlockedDecrement(&FailGroup->NumberOfRequestsInFlight) == 0){\r\n\r\n            //\r\n            // If the inflight requests on the path is zero, if needed path can be removed.\r\n            //\r\n            isDeletionEligible = TRUE;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpDecrementCounters (FOG %p): Exiting function.\\n\",\r\n                FailGroup));\r\n\r\n    return isDeletionEligible;\r\n}\r\n\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpGetPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will pick a path, for processing a request, based\r\n    on the current LoadBalance policy that is set.\r\n\r\n    N.B: This routine must be called with DSM Context Lock held in Shared mode.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DsmList    - List of DSM Ids sent by MPIO\r\n    Srb        - The read/write/verify request\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    FailOver Group that should be used for processing the request\r\n--*/\r\n{\r\n    //\r\n    // Algorithm:\r\n    // ==========\r\n    // Failover-only:\r\n    // --------------\r\n    //      If symmetric LUA (ie. ALUA not supported, or symmetric LUA using ALUA semantics (viz. storage reports\r\n    //                                                              implicit-only transitions and all TPGs in A/O):\r\n    //          One path AO,            <- this will be the only path used for I/O\r\n    //          M paths in SB,          <- one of these will be made active on failure of the above active path\r\n    //          Rest of the paths Failed (Invalidated/PendingRemove/Removed)\r\n    //\r\n    //      If ALUA:\r\n    //          One path AO,            <- this will be the only path used for I/O\r\n    //          M paths in AU, SB or UA <- one of these made active on failover. Pref: AU > SB > UA. Also, controller affinity.\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      Automatic failback will happen only if Preferred path has been set.\r\n    //      This is the only policy that will support failback.\r\n    //\r\n    // Round-Robin:\r\n    // ------------\r\n    //      If symmetric LUA:\r\n    //          N paths AO,             <- round robin among these\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      If ALUA:\r\n    //          Round Robin policy not supported since all paths can't be in A/O state.\r\n    //\r\n    // Round-Robin With Subset:\r\n    // ------------------------\r\n    //      If symmetric LUA:\r\n    //          N paths AO,             <- round robin among these\r\n    //          M paths SB,             <- if no active paths left, make one of these active\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      If ALUA:\r\n    //          N paths AO,             <- round robin among these (NOTE: paths in AU not considered)\r\n    //          M paths AU, SB or UA    <- if no active paths, make subset of these active (based on TPG states after transition)\r\n    //          Rest of the paths Failed\r\n    //\r\n    // Least-Queue Depth:\r\n    // ------------------\r\n    //      If symmetric LUA:\r\n    //          N paths AO,             <- one with least outstanding I/O is chosen\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      If ALUA:\r\n    //          N paths AO,             <- one with least outstanding I/O is chosen\r\n    //          M paths AU, SB or UA    <- if no AO paths available, subset of these become active (based on TPG\r\n    //                                        states after transition) - one with least outstanding I/O is chosen.\r\n    //          Rest of the paths Failed\r\n    //\r\n    // Least-Weighted:\r\n    // ---------------\r\n    //      If symmetric LUA:\r\n    //          N paths AO,             <- every path has an associated weight, path with least weight is used.\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      If ALUA:\r\n    //          N paths AO,\r\n    //          M paths AU, SB or UA    <- if no AO paths available, subset of these become active (based on TPG\r\n    //                                        states after transition) - path with least weight used.\r\n    //          Rest of the paths Failed\r\n    //\r\n    // Least-Blocks:\r\n    // -------------\r\n    //      If symmetric LUA:\r\n    //          N paths AO,             <- one with least cumulative outstanding IO is chosen\r\n    //          Rest of the paths Failed\r\n    //\r\n    //      If ALUA:\r\n    //          N paths AO,             <- one with least cumulative outstanding IO is chosen\r\n    //          M paths AU, SB or UA    <- if no AO paths available, subset of these become active (based on TPG\r\n    //                                        states after transition) - one with least cumulative outstanding is chosen.\r\n    //\r\n    // Actual implementation of algorithm happens in the following routines: DsmpGetAnyActivePath,\r\n    //          DsmpGetActivePathToBeUsed, flavors of DsmpSetLBForPathXXX.\r\n    //\r\n\r\n    PDSM_FAILOVER_GROUP failGroup = NULL;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmList->IdList[0];\r\n    PDSM_GROUP_ENTRY groupEntry;\r\n    ULONG inx = 0;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n    UNREFERENCED_PARAMETER(SpecialHandlingFlag);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpGetPath (DsmIds %p): Entering function.\\n\",\r\n                DsmList));\r\n\r\n    if (!(DsmList->Count && deviceInfo)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpGetPath (DsmIds %p): Called with no available paths.\\n\",\r\n                    DsmList));\r\n\r\n        goto __Exit_DsmpGetPath;\r\n    }\r\n\r\n    groupEntry = deviceInfo->Group;\r\n    DSM_ASSERT(groupEntry->GroupSig == DSM_GROUP_SIG);\r\n\r\n    switch (groupEntry->LoadBalanceType) {\r\n\r\n        case DSM_LB_FAILOVER:\r\n        case DSM_LB_WEIGHTED_PATHS: {\r\n\r\n            //\r\n            // For FailOverOnly there is only one active path so we can\r\n            // just grab it from the cached location and go with it.\r\n            // For LeastWeightPath we always choose the lowest weighted\r\n            // one so we grab that and go\r\n            //\r\n            failGroup = groupEntry->PathToBeUsed;\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_ROUND_ROBIN:\r\n        case DSM_LB_ROUND_ROBIN_WITH_SUBSET: {\r\n\r\n            PDSM_DEVICE_INFO candidateDevice = NULL;\r\n            PDSM_GROUP_ENTRY newGroup = NULL;\r\n            ULONG newPath;\r\n            BOOLEAN foundPath = FALSE;\r\n            ULONG jnx = 0;\r\n            ULONG counter = 0;\r\n            BOOLEAN reset = FALSE;\r\n\r\n            for (inx = 0; inx < DsmList->Count; inx++) {\r\n\r\n                deviceInfo = DsmList->IdList[inx];\r\n\r\n                if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) {\r\n\r\n                    continue;\r\n                }\r\n\r\n\r\n                if (deviceInfo->FailGroup == groupEntry->PathToBeUsed) {\r\n\r\n                    //\r\n                    // We've reached the devInfo that corresponds to the path\r\n                    // that we should be using. If this devInfo is not in the\r\n                    // right state to be used, we need to find the first candidate\r\n                    // starting from this one to satisfy the request.\r\n                    // To play it safe, we may have already considered a previous\r\n                    // devInfo to be a candidate, that now needs to be reset to\r\n                    // the one that we now find.\r\n                    //\r\n                    reset = TRUE;\r\n                }\r\n\r\n#if DBG\r\n                if (deviceInfo->TargetPortGroup && !DsmpIsDeviceFailedState(deviceInfo->State)) {\r\n\r\n                    if (deviceInfo->State != deviceInfo->ALUAState) {\r\n\r\n                        DSM_ASSERT(groupEntry->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET &&\r\n                                   deviceInfo->State == DSM_DEV_ACTIVE_UNOPTIMIZED &&\r\n                                   deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED);\r\n                    }\r\n                }\r\n#endif\r\n\r\n                if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                    if (!candidateDevice || reset) {\r\n\r\n                        candidateDevice = deviceInfo;\r\n                        TracePrint((TRACE_LEVEL_WARNING,\r\n                                    TRACE_FLAG_RW,\r\n                                    \"DsmpGetPath (DsmIds %p): Candidate device %p.\\n\",\r\n                                    DsmList,\r\n                                    candidateDevice));\r\n\r\n                        jnx = inx;\r\n                    }\r\n\r\n                    if (!groupEntry->PathToBeUsed || deviceInfo->FailGroup == groupEntry->PathToBeUsed) {\r\n\r\n                        //\r\n                        // The devInfo that corresponds to the path that we were\r\n                        // supposed to use, is in a state that makes it usable.\r\n                        // So we've found our devInfo.\r\n                        //\r\n                        InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)deviceInfo->FailGroup);\r\n                        foundPath = TRUE;\r\n                        candidateDevice = NULL;\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (!foundPath) {\r\n\r\n                if (candidateDevice) {\r\n\r\n                    InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)candidateDevice->FailGroup);\r\n                    inx = jnx;\r\n                    candidateDevice = NULL;\r\n\r\n                } else {\r\n\r\n                    inx = 0;\r\n                }\r\n            }\r\n\r\n            failGroup = groupEntry->PathToBeUsed;\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpGetPath (DsmIds %p): Path to be used is %p.\\n\",\r\n                        DsmList,\r\n                        groupEntry->PathToBeUsed));\r\n\r\n            //\r\n            // The current chosen path is given by failGroup. Find the next path\r\n            // that should be chosen in the RoundRobin policy. Start with the\r\n            // device at index inx + 1, and look for the one with Active state.\r\n            //\r\n            for (counter = 0, jnx = inx + 1;\r\n                 counter < DsmList->Count && !newGroup;\r\n                 counter++, jnx++) {\r\n\r\n                newPath = jnx % DsmList->Count;\r\n\r\n                deviceInfo = DsmList->IdList[newPath];\r\n\r\n                if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) {\r\n\r\n                    continue;\r\n                }\r\n\r\n\r\n                if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                    newGroup = deviceInfo->Group;\r\n                    DSM_ASSERT(newGroup == groupEntry);\r\n\r\n                    InterlockedExchangePointer(&(newGroup->PathToBeUsed), (PVOID)deviceInfo->FailGroup);\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpGetPath (DsmIds %p): New Path is %p.\\n\",\r\n                                DsmList,\r\n                                newGroup->PathToBeUsed));\r\n\r\n                     break;\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_DYN_LEAST_QUEUE_DEPTH: {\r\n\r\n            LONG leastQueueDepth = 0x7FFFFFFF;\r\n\r\n            for (inx = 0; inx < DsmList->Count; inx++) {\r\n\r\n                deviceInfo = DsmList->IdList[inx];\r\n\r\n                if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) {\r\n\r\n                    continue;\r\n                }\r\n\r\n\r\n                if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                    deviceInfo->FailGroup->NumberOfRequestsInFlight < leastQueueDepth) {\r\n\r\n                    leastQueueDepth = deviceInfo->FailGroup->NumberOfRequestsInFlight;\r\n                    failGroup = deviceInfo->FailGroup;\r\n                }\r\n            }\r\n\r\n            if (failGroup) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmpGetPath (DsmIds %p): Path to be used for LQD is %p.\\n\",\r\n                            DsmList,\r\n                            failGroup));\r\n\r\n            } else {\r\n\r\n                //\r\n                // For ALUA storage there are two cases where we are left with no\r\n                // TPG in the A/O state:\r\n                // 1) On storage that supports implicit transitions, a transition\r\n                //    was initiated that left no TPG in the A/O state.\r\n                // 2) On storage that has explicit only transitions enabled, we tried\r\n                //    making at least one path as A/O and failed. This can happen,\r\n                //    for example, when STPG fails because this initiator is not\r\n                //    registered or does not hold exclusive reservation over the\r\n                //    target.\r\n                //\r\n                // For such storages, we should return some path instead of just\r\n                // failing the I/O. The path will likely be an A/U path until the\r\n                // storage does a transition to make a TPG A/O.\r\n                //\r\n                if (!DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmList->IdList[0])) {\r\n\r\n                    //\r\n                    // Use the same path as the one used for the previous request.\r\n                    //\r\n                    failGroup = groupEntry->PathToBeUsed;\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpGetPath (DsmIds %p): Using same path (FOG %p) as previous request for LQD.\\n\",\r\n                                DsmList,\r\n                                failGroup));\r\n                } else {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpGetPath (DsmIds %p): Failed to find a path for LQD.\\n\",\r\n                                DsmList));\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_LEAST_BLOCKS: {\r\n\r\n            ULONG bytes = 0;\r\n            PCDB cdb = NULL;\r\n            ULONG cdbLength = 0;\r\n            BOOLEAN isRead = FALSE;\r\n            BOOLEAN isWrite = FALSE;\r\n            PDSM_FAILOVER_GROUP lastPathUsed = groupEntry->PathToBeUsed;\r\n            ULONGLONG leastOutstandingIO = MAXULONGLONG;\r\n            ULONGLONG startLba = 0;\r\n\r\n            //\r\n            // Use the last path under the following conditions:\r\n            //\r\n            // 1. This is not a read/write request or\r\n            // 2. This is a read/write request and\r\n            //   a. The request is sequential and\r\n            //   b. The cache is not exhausted\r\n            //\r\n\r\n            if (Srb) {\r\n\r\n                cdb = SrbGetCdb(Srb);\r\n\r\n                if (cdb && DsmIsReadRequest(cdb->AsByte[0])) {\r\n\r\n                    isRead = TRUE;\r\n                }\r\n\r\n                if (cdb && DsmIsWriteRequest(cdb->AsByte[0])) {\r\n\r\n                    isWrite = TRUE;\r\n                }\r\n            }\r\n\r\n            if (isRead || isWrite) {\r\n\r\n                if (groupEntry->UseCacheForLeastBlocks) {\r\n\r\n                    bytes = SrbGetDataTransferLength(Srb);\r\n\r\n                    cdbLength = SrbGetCdbLength(Srb);\r\n\r\n                    if (cdbLength == 16) {\r\n\r\n                        REVERSE_BYTES_QUAD(&startLba, &cdb->CDB16.LogicalBlock);\r\n\r\n                    } else {\r\n\r\n                        REVERSE_BYTES(&startLba, &cdb->CDB10.LogicalBlockByte0);\r\n                    }\r\n\r\n                    //\r\n                    // Check if:\r\n                    // 1. The IO is sequential, AND\r\n                    // 2. It is either:\r\n                    //    a. read request, OR\r\n                    //    b. write request and outstanding bytes will be within the cache limit\r\n                    //\r\n                    if ((lastPathUsed != NULL) &&\r\n                        (startLba >= lastPathUsed->LastLba) &&\r\n                        ((isRead) ||\r\n                         (isWrite && lastPathUsed->OutstandingBytesOfIO + bytes <= groupEntry->CacheSizeForLeastBlocks))) {\r\n\r\n                        failGroup = groupEntry->PathToBeUsed;\r\n\r\n                        TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmpGetPath (DsmIds %p): Sequential IO, so using same path %p for LeastBlocks.\\n\",\r\n                            DsmList,\r\n                            failGroup));\r\n                    }\r\n                }\r\n\r\n            } else {\r\n                //\r\n                // The request is neither a read nor a write so use the same path.\r\n                //\r\n                failGroup = groupEntry->PathToBeUsed;\r\n            }\r\n\r\n            if (!failGroup) {\r\n\r\n                //\r\n                // Choose whichever Active/Optimized path has the least outstanding bytes.\r\n                //\r\n                for (inx = 0; inx < DsmList->Count; inx++) {\r\n\r\n                    deviceInfo = DsmList->IdList[inx];\r\n\r\n                    if (!(deviceInfo && DsmpIsDeviceInitialized(deviceInfo) && DsmpIsDeviceUsable(deviceInfo) && DsmpIsDeviceUsablePR(deviceInfo))) {\r\n\r\n                        continue;\r\n                    }\r\n\r\n\r\n                    if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                        deviceInfo->FailGroup->OutstandingBytesOfIO < leastOutstandingIO) {\r\n\r\n                        leastOutstandingIO = deviceInfo->FailGroup->OutstandingBytesOfIO;\r\n                        failGroup = deviceInfo->FailGroup;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (failGroup) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmpGetPath (DsmIds %p): Path to be used for LeastBlocks is %p.\\n\",\r\n                            DsmList,\r\n                            failGroup));\r\n\r\n            } else {\r\n\r\n                //\r\n                // For ALUA storage there are two cases where we are left with no\r\n                // TPG in the A/O state:\r\n                // 1) On storage that supports implicit transitions, a transition\r\n                //    was initiated that left no TPG in the A/O state.\r\n                // 2) On storage that has explicit only transitions enabled, we tried\r\n                //    making at least one path as A/O and failed. This can happen,\r\n                //    for example, when STPG fails because this initiator is not\r\n                //    registered or does not hold exclusive reservation over the\r\n                //    target.\r\n                //\r\n                // For such storages, we should return some path instead of just\r\n                // failing the I/O. The path will likely be an A/U path until the\r\n                // storage does a transition to make a TPG A/O.\r\n                //\r\n                if (!DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmList->IdList[0])) {\r\n\r\n                    //\r\n                    // Use the same path as the one used for the previous request.\r\n                    //\r\n                    failGroup = groupEntry->PathToBeUsed;\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpGetPath (DsmIds %p): Using same path (FOG %p) as previous request for LeastBlocks.\\n\",\r\n                                DsmList,\r\n                                failGroup));\r\n                } else {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpGetPath (DsmIds %p): Failed to find a path for LeastBlocks.\\n\",\r\n                                DsmList));\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpGetPath (DsmIds %p): Invalid LB Type %d set for group %p.\\n\",\r\n                        DsmList,\r\n                        groupEntry->LoadBalanceType,\r\n                        groupEntry));\r\n\r\n            DSM_ASSERT(FALSE);\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n__Exit_DsmpGetPath:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpGetPath (DsmIds %p): Exiting function with failGroup %p.\\n\",\r\n                DsmList,\r\n                failGroup));\r\n\r\n    return failGroup;\r\n}\r\n\r\n\r\nPVOID\r\nDsmpGetPathIdFromPassThroughPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ PIRP Irp,\r\n    _Inout_ IN OUT NTSTATUS *Status\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will pick the path that corresponds to the PathId\r\n    in the mpio pass through structure.\r\n\r\n    NOTE: Caller must ensure that the IRP is either MPTP or MPTPD.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DsmList    - List of DSM Ids sent by MPIO\r\n    Irp        - The MPTP or MPTPD request\r\n    Status     - Returned status\r\n\r\nReturn Value:\r\n\r\n    The PathId to which the request should be sent\r\n--*/\r\n{\r\n    PDSM_FAILOVER_GROUP failGroup = NULL;\r\n    PDSM_GROUP_ENTRY groupEntry;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    ULONG inx = 0;\r\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\r\n    KIRQL irql;\r\n    PVOID newPath = NULL;\r\n    BOOLEAN found = FALSE;\r\n    BOOLEAN useScsiAddress = FALSE;\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;\r\n    UCHAR pathId = 0;\r\n    UCHAR targetId = 0;\r\n    UCHAR portNumber = 0;\r\n    ULONGLONG mpioPathId = 0;\r\n\r\n#if DBG\r\n    BOOLEAN useMpioPathId = FALSE;\r\n#endif\r\n\r\n    //\r\n    // Extract the parameters from the passthrough based on the bitness of the\r\n    // process (32 or 64) and the type of passthrough (legacy or extended).\r\n    //\r\n#if defined (_WIN64)\r\n    if (IoIs32bitProcess(Irp)) {\r\n\r\n        if (DsmpIsMPIOPassThroughEx(controlCode)) {\r\n            PMPIO_PASS_THROUGH_PATH32_EX mpioPassThroughPath32 = (PMPIO_PASS_THROUGH_PATH32_EX)(Irp->AssociatedIrp.SystemBuffer);\r\n            PSCSI_PASS_THROUGH32_EX passThrough32 = (PSCSI_PASS_THROUGH32_EX)((PUCHAR)mpioPassThroughPath32 + mpioPassThroughPath32->PassThroughOffset);\r\n\r\n            useScsiAddress = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS;\r\n            #if DBG\r\n            useMpioPathId = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_PATHID;\r\n            #endif\r\n\r\n            if (useScsiAddress) {\r\n                PSTOR_ADDRESS address;\r\n                if (passThrough32->StorAddressOffset < sizeof(SCSI_PASS_THROUGH_EX) ||\r\n                    passThrough32->StorAddressLength < sizeof(STOR_ADDRESS)) {\r\n                    *Status = STATUS_INVALID_PARAMETER;\r\n                    return NULL;\r\n                }\r\n                address = (PSTOR_ADDRESS)((PUCHAR)passThrough32 + passThrough32->StorAddressOffset);\r\n                if (address->Type != STOR_ADDRESS_TYPE_BTL8 ||\r\n                    address->AddressLength < STOR_ADDR_BTL8_ADDRESS_LENGTH) {\r\n                    *Status = STATUS_INVALID_PARAMETER;\r\n                    return NULL;\r\n                }\r\n                pathId = ((PSTOR_ADDR_BTL8)address)->Path;\r\n                targetId = ((PSTOR_ADDR_BTL8)address)->Target;\r\n                portNumber = mpioPassThroughPath32->PortNumber;\r\n            } else {\r\n                mpioPathId = mpioPassThroughPath32->MpioPathId;\r\n            }\r\n\r\n        } else {\r\n            PMPIO_PASS_THROUGH_PATH32 mpioPassThroughPath32 = (PMPIO_PASS_THROUGH_PATH32)(Irp->AssociatedIrp.SystemBuffer);\r\n\r\n            useScsiAddress = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS;\r\n            #if DBG\r\n            useMpioPathId = mpioPassThroughPath32->Flags & MPIO_IOCTL_FLAG_USE_PATHID;\r\n            #endif\r\n\r\n            if (useScsiAddress) {\r\n                pathId = mpioPassThroughPath32->PassThrough.PathId;\r\n                targetId = mpioPassThroughPath32->PassThrough.TargetId;\r\n                portNumber = mpioPassThroughPath32->PortNumber;\r\n            } else {\r\n                mpioPathId = mpioPassThroughPath32->MpioPathId;\r\n            }\r\n        }\r\n    } else\r\n#endif\r\n    if (DsmpIsMPIOPassThroughEx(controlCode)) {\r\n        PMPIO_PASS_THROUGH_PATH_EX mpioPassThroughPath = (PMPIO_PASS_THROUGH_PATH_EX)(Irp->AssociatedIrp.SystemBuffer);\r\n        PSCSI_PASS_THROUGH_EX passThrough = (PSCSI_PASS_THROUGH_EX)((PUCHAR)mpioPassThroughPath + mpioPassThroughPath->PassThroughOffset);\r\n\r\n        useScsiAddress = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS;\r\n        #if DBG\r\n        useMpioPathId = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_PATHID;\r\n        #endif\r\n\r\n        if (useScsiAddress) {\r\n            PSTOR_ADDRESS address;\r\n            if (passThrough->StorAddressOffset < sizeof(SCSI_PASS_THROUGH_EX) ||\r\n                passThrough->StorAddressLength < sizeof(STOR_ADDRESS)) {\r\n                *Status = STATUS_INVALID_PARAMETER;\r\n                return NULL;\r\n            }\r\n            address = (PSTOR_ADDRESS)((PUCHAR)passThrough + passThrough->StorAddressOffset);\r\n            if (address->Type != STOR_ADDRESS_TYPE_BTL8 ||\r\n                address->AddressLength < STOR_ADDR_BTL8_ADDRESS_LENGTH) {\r\n                *Status = STATUS_INVALID_PARAMETER;\r\n                return NULL;\r\n            }\r\n            pathId = ((PSTOR_ADDR_BTL8)address)->Path;\r\n            targetId = ((PSTOR_ADDR_BTL8)address)->Target;\r\n            portNumber = mpioPassThroughPath->PortNumber;\r\n        } else {\r\n            mpioPathId = mpioPassThroughPath->MpioPathId;\r\n        }\r\n    } else {\r\n        PMPIO_PASS_THROUGH_PATH mpioPassThroughPath = (PMPIO_PASS_THROUGH_PATH)(Irp->AssociatedIrp.SystemBuffer);\r\n\r\n        useScsiAddress = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_SCSIADDRESS;\r\n        #if DBG\r\n        useMpioPathId = mpioPassThroughPath->Flags & MPIO_IOCTL_FLAG_USE_PATHID;\r\n        #endif\r\n\r\n        if (useScsiAddress) {\r\n            pathId = mpioPassThroughPath->PassThrough.PathId;\r\n            targetId = mpioPassThroughPath->PassThrough.TargetId;\r\n            portNumber = mpioPassThroughPath->PortNumber;\r\n        } else {\r\n            mpioPathId = mpioPassThroughPath->MpioPathId;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpGetPathIdFromPassThroughPath (DsmIds %p): Entering function.\\n\",\r\n                DsmList));\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    deviceInfo = DsmList->IdList[0];\r\n    groupEntry = deviceInfo->Group;\r\n    DSM_ASSERT(groupEntry->GroupSig == DSM_GROUP_SIG);\r\n    //\r\n    // useMpioPathId is BOOLEAN (0 or 1) since MPIO_IOCTL_FLAG_USE_PATHID = 1\r\n    // But since MPIO_IOCTL_FLAG_USE_SCSIADDRESS = 0x2,\r\n    // useScsiAddress could have a value of 2 if set. Use logical NOT to make boolean before comparing below\r\n    //\r\n    DSM_ASSERT(useMpioPathId == !useScsiAddress);\r\n\r\n    for (inx = 0; inx < DSM_MAX_PATHS; inx++) {\r\n\r\n        deviceInfo = groupEntry->DeviceList[inx];\r\n\r\n        if (deviceInfo) {\r\n\r\n            failGroup = deviceInfo->FailGroup;\r\n\r\n            if (failGroup) {\r\n\r\n                if (useScsiAddress) {\r\n\r\n                    if (portNumber == deviceInfo->ScsiAddress->PortNumber &&\r\n                        pathId == deviceInfo->ScsiAddress->PathId &&\r\n                        targetId == deviceInfo->ScsiAddress->TargetId) {\r\n\r\n                        found = TRUE;\r\n                        break;\r\n                    }\r\n                } else {\r\n\r\n                    NT_ASSERT(useMpioPathId);\r\n\r\n                    if ((ULONGLONG)((ULONG_PTR)(failGroup->PathId)) == mpioPathId) {\r\n\r\n                        found = TRUE;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    if (found) {\r\n\r\n        newPath = failGroup->PathId;\r\n        status = STATUS_SUCCESS;\r\n\r\n        //\r\n        // This should not affect the next path chosen based on the\r\n        // current LB policy, so do NOT update groupEntry->PathToBeUsed\r\n        //\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpGetPathIdFromPassThroughPath (DsmIds %p): Failed to get corresponding path.\\n\",\r\n                    DsmList));\r\n    }\r\n\r\n    if (Status) {\r\n\r\n        *Status = status;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpGetPathIdFromPassThroughPath (DsmIds %p): Exiting function with path %p and status %x.\\n\",\r\n                DsmList,\r\n                newPath,\r\n                status));\r\n\r\n    return newPath;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpShouldRetryTPGRequest(\r\n    _In_ IN PVOID SenseData,\r\n    _In_ IN UCHAR SenseDataSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine determines if a Report/Set TargetPortGroup request (sent either\r\n    as a passThrough or as an IRP_MJ_SCSI) needs to be retried.\r\n\r\nArguments:\r\n\r\n    SenseData - Pointer to Sense Data information buffer.\r\n    SenseDataSize - Size of the passed in sense data buffer.\r\n\r\nReturn Value:\r\n\r\n    TRUE if sense information indicates a retry-able error, else FALSE.\r\n\r\n--*/\r\n{\r\n    BOOLEAN retry = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryTPGRequest (SenseData %p): Entering function.\\n\",\r\n                SenseData));\r\n\r\n    //\r\n    // Two types of conditions need to be retried:\r\n    // 1. Asymmetric Access State Changed\r\n    // 2. Asymmetric Access State Transition\r\n    //\r\n\r\n    //\r\n    // Check if asymmetric access state changed\r\n    //\r\n    retry = DsmpShouldRetryPassThroughRequest(SenseData, SenseDataSize);\r\n    if (!retry) {\r\n\r\n        BOOLEAN validSense = FALSE;\r\n        UCHAR senseKey = 0;\r\n        UCHAR addSenseCode = 0;\r\n        UCHAR addSenseCodeQualifier = 0;\r\n\r\n        validSense = ScsiGetSenseKeyAndCodes(SenseData,\r\n                                             SenseDataSize,\r\n                                             SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,\r\n                                             &senseKey,\r\n                                             &addSenseCode,\r\n                                             &addSenseCodeQualifier);\r\n        if (validSense) {\r\n\r\n            if (senseKey == SCSI_SENSE_NOT_READY) {\r\n\r\n                switch (addSenseCode) {\r\n                    case SCSI_ADSENSE_LUN_NOT_READY: {\r\n\r\n                        //\r\n                        // Check if asymmetric access state transitioning\r\n                        //\r\n                        if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION) {\r\n\r\n                            retry = TRUE;\r\n                        }\r\n                        break;\r\n                    }\r\n\r\n                    case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: {\r\n\r\n                        if (addSenseCodeQualifier == SCSI_SENSEQ_REPORTED_LUNS_DATA_CHANGED) {\r\n\r\n                            retry = TRUE;\r\n                        }\r\n                        break;\r\n                    }\r\n\r\n                    default: {\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_GENERAL,\r\n                                    \"DsmpShouldRetryTPGRequest (SenseData %p): AddSenseCode %x. Not retrying.\\n\",\r\n                                    SenseData,\r\n                                    addSenseCode));\r\n\r\n                        retry = FALSE;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        } else {\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpShouldRetryTPGRequest (SenseData %p): Sense data size %d not big enough.\\n\",\r\n                        SenseData,\r\n                        SenseDataSize));\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryTPGRequest (SenseData %p): Exiting function with retry %x.\\n\",\r\n                SenseData,\r\n                retry));\r\n\r\n    return retry;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpIsDeviceRemoved(\r\n    _In_ IN PVOID   SenseData,\r\n    _In_ IN UCHAR   SenseDataSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine evaluate Sense Data and determine if LUN is available or not.\r\n\r\nArguments:\r\n\r\n    SenseData - Pointer to Sense Data information buffer.\r\n    SenseDataSize - Size of the passed in sense data buffer.\r\n\r\nReturn Value:\r\n\r\n    TRUE if device is no longer available, else FALSE.\r\n\r\n--*/\r\n{\r\n    BOOLEAN validSense = FALSE;\r\n    UCHAR senseKey = 0;\r\n    UCHAR addSenseCode = 0;\r\n    UCHAR addSenseCodeQualifier = 0;\r\n    BOOLEAN bRemoved = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpIsDeviceRemoved (SenseData %p): Entering function.\\n\",\r\n                SenseData));\r\n\r\n    validSense = ScsiGetSenseKeyAndCodes(SenseData,\r\n                                         SenseDataSize,\r\n                                         SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,\r\n                                         &senseKey,\r\n                                         &addSenseCode,\r\n                                         &addSenseCodeQualifier);\r\n\r\n    if (validSense) {\r\n        //\r\n        // SPC 3 6.25 suggests response should follow Test Unit Ready responses\r\n        // For now, we accept Ileegal Request as an indication of device not in available\r\n        // state.\r\n        //\r\n        if (senseKey == SCSI_SENSE_ILLEGAL_REQUEST) {\r\n\r\n            ASSERT(addSenseCodeQualifier == 0); //LOGICAL UNIT NOT SUPPORTED\r\n\r\n            bRemoved = TRUE;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpIsDeviceRemoved (SenseData %p): SenseKey %x AddSenseCode %x. Remove %x\\n\",\r\n                    SenseData,\r\n                    senseKey,\r\n                    addSenseCode,\r\n                    bRemoved));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpIsDeviceRemoved (SenseData %p): Exiting function. Removed %x.\\n\",\r\n                SenseData,\r\n                bRemoved));\r\n\r\n    return bRemoved;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpReservationCommand(\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine examines the DeviceIoControlCode and Srb OpCode to determine\r\n    if this is PR request.\r\n\r\nArguments:\r\n\r\n    Irp - The Irp containing Srb.\r\n    Srb - The current non-read/write Srb.\r\n\r\nReturn Value:\r\n\r\n    TRUE - If it's a special-case command (some reservation-handling request).\r\n\r\n--*/\r\n{\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    UCHAR opCode = 0;\r\n    BOOLEAN isReservationCommand = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpReservationCommand (Irp %p): Entering function.\\n\",\r\n                Irp));\r\n\r\n    //\r\n    // Ensure it's a scsi request before checking the opcode.\r\n    //\r\n    if (irpStack->MajorFunction == IRP_MJ_SCSI) {\r\n\r\n        PCDB cdb = SrbGetCdb(Srb);\r\n        if (cdb != NULL) {\r\n            opCode = cdb->AsByte[0];\r\n\r\n            if (opCode == SCSIOP_PERSISTENT_RESERVE_IN || opCode == SCSIOP_PERSISTENT_RESERVE_OUT) {\r\n\r\n                //\r\n                // Set or release a reservation.\r\n                //\r\n                isReservationCommand = TRUE;\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpReservationCommand (Irp %p): Exiting function - IsReservationCmd %x.\\n\",\r\n                Irp,\r\n                isReservationCommand));\r\n\r\n    return isReservationCommand;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpMpioPassThroughPathCommand(\r\n    _In_ IN PIRP Irp\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine examines the DeviceIoControlCode to determine whether this is\r\n    either a mpio pass through or a mpio pass through direct. If so, it needs\r\n    to be handled via a specific path indicated by the caller.\r\n\r\nArguments:\r\n\r\n    Irp - The Irp.\r\n\r\nReturn Value:\r\n\r\n    TRUE  - If it is either MPTP or MPTPD.\r\n    FALSE - Otherwise.\r\n\r\n--*/\r\n{\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    ULONG ioctlCode;\r\n    BOOLEAN isMPTPCommand = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpMpioPassThroughPathCommand (Irp %p): Entering function.\\n\",\r\n                Irp));\r\n\r\n    if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {\r\n\r\n        //\r\n        // Check whether this is a MPTP, MPTPD, or an extended flavor.\r\n        //\r\n        ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;\r\n\r\n        if (ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH ||\r\n            ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT ||\r\n            ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_EX ||\r\n            ioctlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT_EX) {\r\n\r\n            isMPTPCommand = TRUE;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpMpioPassThroughPathCommand (Irp %p): Exiting function - IsMpioPassThruPathCmd %!bool!.\\n\",\r\n                Irp,\r\n                isMPTPCommand));\r\n\r\n    return isMPTPCommand;\r\n}\r\n\r\n\r\nVOID\r\nDsmpRequestComplete(\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PVOID DsmContext\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called from mpio's completion routine when the Irp\r\n    has been completed by the port driver. Currently, it updates some counters\r\n    and free's the context back to the look-aside list.\r\n\r\nArguments:\r\n\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDISK.\r\n    Irp - Irp containing SRB.\r\n    Srb - Scsi request block\r\n    DsmContext - DSM context given to MPIO during initialization\r\n\r\nReturn Value:\r\n\r\n    NONE\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PDSM_CONTEXT dsmContext = (PDSM_CONTEXT)DsmContext;\r\n    UCHAR opCode = 0xFF;\r\n    ULONG dataTransferLength = 0;\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    PDSM_FAILOVER_GROUP failGroup = irpStack->Parameters.Others.Argument3;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpRequestComplete (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    DSM_ASSERT(DsmContext);\r\n\r\n    if (Srb) {\r\n        PCDB cdb = SrbGetCdb(Srb);\r\n        if (cdb) {\r\n            opCode = cdb->AsByte[0];\r\n        }\r\n        dataTransferLength = SrbGetDataTransferLength(Srb);\r\n    }\r\n\r\n    //\r\n    // Extract the interesting bits from the context struct.\r\n    //\r\n\r\n    if (failGroup) {\r\n\r\n        if (DsmpDecrementCounters(failGroup, Srb)) {\r\n\r\n            //\r\n            // If there are no requests on a path that is supposed to be removed, remove it now.\r\n            //\r\n            if (failGroup->State == DSM_FG_PENDING_REMOVE) {\r\n\r\n                KIRQL oldIrql;\r\n\r\n                NT_ASSERT(failGroup->Count == 0);\r\n\r\n                oldIrql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n                RemoveEntryList(&failGroup->ListEntry);\r\n                InterlockedDecrement((LONG volatile*)&dsmContext->NumberStaleFOGroups);\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpRequestComplete (DevInfo %p): Removing FOGroup %p with path %p.\\n\",\r\n                            DsmId,\r\n                            failGroup,\r\n                            failGroup->PathId));\r\n\r\n                DsmpFreePool(failGroup);\r\n                ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), oldIrql);\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // Note: We use the deviceInfo passed in since the one saved off in the\r\n    // context may be stale in the case of a retried I/O\r\n    //\r\n    if (deviceInfo) {\r\n\r\n        //\r\n        // If statistics gathering is enabled update the inflight request count\r\n        // for this device-path pairing.\r\n        //\r\n        if (!dsmContext->DisableStatsGathering) {\r\n\r\n            //\r\n            // Indicate one less request on this device.\r\n            // Update the path that on which the increment was done.\r\n            //\r\n            if (InterlockedCompareExchange((LONG volatile*)&deviceInfo->NumberOfRequestsInProgress, 0, 0) > 0) {\r\n                InterlockedDecrement(&(deviceInfo->NumberOfRequestsInProgress));\r\n            }\r\n        }\r\n\r\n        //\r\n        // If statistics gathering is enabled, we are interested in read/write requests\r\n        //\r\n        if (!dsmContext->DisableStatsGathering) {\r\n\r\n            //\r\n            // If it's a read or a write, update the stats.\r\n            // Use the path that was cached during dispatch.\r\n            //\r\n            if (DsmIsReadRequest(opCode)) {\r\n\r\n                if (deviceInfo->DeviceStats.NumberReads <= MAXULONG) {\r\n\r\n                    InterlockedIncrement((LONG volatile*)&deviceInfo->DeviceStats.NumberReads);\r\n                }\r\n\r\n                if ((MAXULONGLONG - dataTransferLength) > deviceInfo->DeviceStats.BytesRead) {\r\n\r\n                    deviceInfo->DeviceStats.BytesRead += dataTransferLength;\r\n\r\n                } else {\r\n\r\n                    deviceInfo->DeviceStats.BytesRead = MAXULONGLONG;\r\n                }\r\n\r\n            } else if (DsmIsWriteRequest(opCode)) {\r\n\r\n                if (deviceInfo->DeviceStats.NumberWrites <= MAXULONG) {\r\n\r\n                    InterlockedIncrement((LONG volatile*)&deviceInfo->DeviceStats.NumberWrites);\r\n                }\r\n\r\n                if ((MAXULONGLONG - dataTransferLength) > deviceInfo->DeviceStats.BytesWritten) {\r\n\r\n                    deviceInfo->DeviceStats.BytesWritten += dataTransferLength;\r\n\r\n                } else {\r\n\r\n                    deviceInfo->DeviceStats.BytesWritten = MAXULONGLONG;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpRequestComplete (DevInfo %p): Exiting function.\\n\",\r\n                DsmId));\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpRegisterPersistentReservationKeys(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN      Register\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to build and send down the request to register\r\n    or unregister the persistent reservation keys to the device down\r\n    the path given by DeviceInfo.\r\n\r\nArguments:\r\n\r\n    DeviceInfo - Device-path pair to use for sending down the request\r\n    Register - Flag to indicate whether to register or unregister the keys.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS on success, else appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL;\r\n    PCDB cdb;\r\n    PPRO_PARAMETER_LIST parameters;\r\n    IO_STATUS_BLOCK ioStatus;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ULONG length;\r\n    PDSM_DEVICE_INFO deviceInfo = DeviceInfo;\r\n    PDSM_GROUP_ENTRY group;\r\n    ULONGLONG saKey;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Entering function - Register = %x.\\n\",\r\n                deviceInfo,\r\n                Register));\r\n\r\n    group = DeviceInfo->Group;\r\n\r\n    NT_ASSERT(group && group->PRKeyValid);\r\n\r\n    if (DeviceInfo->State >= DSM_DEV_FAILED) {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Unusable - state %d.\\n\",\r\n                    deviceInfo,\r\n                    deviceInfo->State));\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n        goto __Exit_DsmpRegisterPersistentReservationKeys;\r\n    }\r\n\r\n    //\r\n    // Build a pass through command to process Persistent Reserve Out\r\n    // for registering the device.\r\n    //\r\n    length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n    passThrough = DsmpAllocatePool(NonPagedPoolNx,\r\n                                   length,\r\n                                   DSM_TAG_PASS_THRU);\r\n    if (!passThrough) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Failed to allocate memory for persistent reserve.\\n\",\r\n                    deviceInfo));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpRegisterPersistentReservationKeys;\r\n    }\r\n\r\n    REVERSE_BYTES_QUAD(&saKey, &group->PersistentReservationRegisteredKey);\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Attempting PR-Out SA %u, Type %u, Scope %u, PR-Key %I64x.\\n\",\r\n                deviceInfo,\r\n                group->PRServiceAction,\r\n                group->PRType,\r\n                group->PRScope,\r\n                saKey));\r\n\r\n__RetryRequest:\r\n\r\n    //\r\n    // Build the cdb to reserve the device (Logical Unit). The type of reservation\r\n    // scope and service action is whatever cluster service provided at the time of\r\n    // sending down registration to this device before this particular path was available.\r\n    //\r\n    cdb = (PCDB) passThrough->ScsiPassThrough.Cdb;\r\n    cdb->PERSISTENT_RESERVE_OUT.OperationCode = SCSIOP_PERSISTENT_RESERVE_OUT;\r\n    cdb->PERSISTENT_RESERVE_OUT.ServiceAction = group->PRServiceAction;\r\n    cdb->PERSISTENT_RESERVE_OUT.Scope = group->PRScope;\r\n    cdb->PERSISTENT_RESERVE_OUT.Type = group->PRType;\r\n    cdb->PERSISTENT_RESERVE_OUT.ParameterListLength[1] = sizeof(PRO_PARAMETER_LIST);\r\n\r\n    passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH);\r\n    passThrough->ScsiPassThrough.CdbLength = 10;\r\n    passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH;\r\n    passThrough->ScsiPassThrough.DataIn = 0;\r\n    passThrough->ScsiPassThrough.DataTransferLength = sizeof(PRO_PARAMETER_LIST);\r\n    passThrough->ScsiPassThrough.TimeOutValue = 20;\r\n    passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer);\r\n    passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer);\r\n\r\n    parameters = (PPRO_PARAMETER_LIST)(passThrough->DataBuffer);\r\n\r\n    //\r\n    // Copy the persistent reservation key given by cluster service to\r\n    // Service Action Reservation Key. This key will be registered\r\n    // with the device.\r\n    //\r\n    // Set ServiceActionReservationKey to the well-known key if we are registering.\r\n    // Note that to unregister ServiceActionReservationKey needs to be set to 0.\r\n    //\r\n    if (Register) {\r\n\r\n        RtlCopyMemory(parameters->ServiceActionReservationKey, group->PersistentReservationRegisteredKey, 8);\r\n\r\n    } else {\r\n\r\n        RtlCopyMemory(parameters->ReservationKey, group->PersistentReservationRegisteredKey, 8);\r\n        RtlZeroMemory(parameters->ServiceActionReservationKey, 8);\r\n    }\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH,\r\n                                      DeviceInfo->TargetObject,\r\n                                      passThrough,\r\n                                      passThrough,\r\n                                      length,\r\n                                      length,\r\n                                      FALSE,\r\n                                      &ioStatus);\r\n\r\n    status = ioStatus.Status;\r\n\r\n    if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(ioStatus.Status))) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Persistent Reserve (Register Key) succeeded using %p.\\n\",\r\n                    deviceInfo,\r\n                    DeviceInfo));\r\n\r\n    } else {\r\n\r\n        PUCHAR senseData;\r\n        UCHAR senseInfoLength;\r\n\r\n        senseData = (PUCHAR)(passThrough->SenseInfoBuffer);\r\n        senseInfoLength = passThrough->ScsiPassThrough.SenseInfoLength;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpRegisterPersistentReservationKeys (DevInfo %p): DevInfo %p, Register keys (%d): NTStatus %x, ScsiStatus %x.\\n\",\r\n                    deviceInfo,\r\n                    DeviceInfo,\r\n                    Register,\r\n                    ioStatus.Status,\r\n                    passThrough->ScsiPassThrough.ScsiStatus));\r\n\r\n        if (DsmpShouldRetryPassThroughRequest((PVOID)senseData, senseInfoLength)) {\r\n\r\n            length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n            RtlZeroMemory(passThrough, length);\r\n\r\n            goto __RetryRequest;\r\n\r\n        } else if (NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Will change success to error status for register\\n\",\r\n                        deviceInfo));\r\n\r\n            status = STATUS_INVALID_DEVICE_REQUEST;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Free the passthrough + data buffer.\r\n    //\r\n    DsmpFreePool(passThrough);\r\n\r\n__Exit_DsmpRegisterPersistentReservationKeys:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpRegisterPersistentReservationKeys (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\n\r\nBOOLEAN\r\nDsmpShouldRetryPassThroughRequest(\r\n    _In_ IN PVOID SenseData,\r\n    _In_ IN UCHAR SenseDataSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine determines if a passthrough request needs to be retried based on the\r\n    information in the passed in sense data.\r\n\r\nArguments:\r\n\r\n    SenseData - Pointer to Sense Data information buffer.\r\n    SenseDataSize - Size of the passed in sense data buffer.\r\n\r\nReturn Value:\r\n\r\n    TRUE if sense information indicates a retry-able error, else FALSE.\r\n\r\n--*/\r\n{\r\n    BOOLEAN validSense = FALSE;\r\n    UCHAR senseKey = 0;\r\n    UCHAR addSenseCode = 0;\r\n    BOOLEAN retry = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryPassThroughRequest (SenseData %p): Entering function.\\n\",\r\n                SenseData));\r\n\r\n#if DBG\r\n    if (SenseDataSize > 0) {\r\n\r\n        ULONG inx;\r\n        PUCHAR senseInfo;\r\n\r\n\r\n        senseInfo = (PUCHAR) SenseData;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpShouldRetryPassThroughRequest (SenseData %p): Sense info length %d. Sense Info : \",\r\n                    SenseData,\r\n                    SenseDataSize));\r\n\r\n        for (inx = 0; inx < SenseDataSize; inx++) {\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"%x \",\r\n                        senseInfo[inx]));\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"\\n\"));\r\n    }\r\n#endif\r\n\r\n    validSense = ScsiGetSenseKeyAndCodes(SenseData,\r\n                                         SenseDataSize,\r\n                                         SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,\r\n                                         &senseKey,\r\n                                         &addSenseCode,\r\n                                         NULL);\r\n    if (validSense) {\r\n        if (senseKey == SCSI_SENSE_UNIT_ATTENTION) {\r\n\r\n            switch (addSenseCode) {\r\n                case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED:\r\n                case SCSI_ADSENSE_BUS_RESET:\r\n                case SCSI_ADSENSE_PARAMETERS_CHANGED: {\r\n                    retry = TRUE;\r\n                    break;\r\n                }\r\n\r\n                default: {\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_GENERAL,\r\n                                \"DsmpShouldRetryPassThroughRequest (SenseData %p): AddSenseCode %x. Not retrying.\\n\",\r\n                                SenseData,\r\n                                addSenseCode));\r\n\r\n                    retry = FALSE;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n    } else {\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpShouldRetryPassThroughRequest (SenseData %p): Sense data size %d not big enough.\\n\",\r\n                    SenseData,\r\n                    SenseDataSize));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryPassThroughRequest (SenseData %p): Exiting function with retry %x.\\n\",\r\n                SenseData,\r\n                retry));\r\n\r\n    return retry;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpShouldRetryPersistentReserveCommand(\r\n    _In_ IN PVOID SenseData,\r\n    _In_ IN UCHAR SenseDataSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine determines if a a PR request needs to be retried based on the\r\n    information in the passed in sense data.\r\n\r\nArguments:\r\n\r\n    SenseData - Pointer to Sense Data information buffer.\r\n    SenseDataSize - Size of the passed in sense data buffer.\r\n\r\nReturn Value:\r\n\r\n    TRUE if sense information indicates a retry-able error, else FALSE.\r\n\r\n--*/\r\n{\r\n    BOOLEAN retry = FALSE;\r\n    BOOLEAN validSense = FALSE;\r\n    UCHAR senseKey = 0;\r\n    UCHAR addSenseCode = 0;\r\n    UCHAR addSenseCodeQualifier = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryPersistentReserveCommand (SenseData %p): Entering function.\\n\",\r\n                SenseData));\r\n\r\n    retry = DsmpShouldRetryPassThroughRequest(SenseData, SenseDataSize);\r\n\r\n    if (!retry) {\r\n        validSense = ScsiGetSenseKeyAndCodes(SenseData,\r\n                                             SenseDataSize,\r\n                                             SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,\r\n                                             &senseKey,\r\n                                             &addSenseCode,\r\n                                             &addSenseCodeQualifier);\r\n        if (validSense) {\r\n\r\n            //\r\n            // If the TPG is in transitioning state, retry the request\r\n            //\r\n            if ((senseKey == SCSI_SENSE_UNIT_ATTENTION || senseKey == SCSI_SENSE_NOT_READY) &&\r\n                (addSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&\r\n                 addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION)) {\r\n\r\n                retry = TRUE;\r\n            }\r\n        } else {\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpShouldRetryPersistentReserveCommand (SenseData %p): Sense data size %d not big enough.\\n\",\r\n                        SenseData,\r\n                        SenseDataSize));\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpShouldRetryPersistentReserveCommand (SenseData %p): Exiting function with retry %x.\\n\",\r\n                SenseData,\r\n                retry));\r\n\r\n    return retry;\r\n}\r\n\r\n\r\nVOID\r\nDsmpAllowStandbyPathsToRest(\r\n    _In_ PDSM_GROUP_ENTRY Group\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a new path is available for a device\r\n    and has a desired state of ACTIVE_O. Since this will be an ACTIVE_O\r\n    path we see if there are any paths with a desired state of Standby\r\n    but that are currently active. These paths can be safely moved by\r\n    to standby.\r\n\r\n    This routine assumes that the lock is held\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n\r\nReturn Value:\r\n\r\n    None\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO existingDeviceInfo;\r\n    ULONG inx;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpAllowStandbyPathsToRest (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    for (inx = 0; inx < Group->NumberDevices; inx++) {\r\n\r\n        existingDeviceInfo = Group->DeviceList[inx];\r\n\r\n        if ((existingDeviceInfo->DesiredState == DSM_DEV_STANDBY) &&\r\n            (existingDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED)) {\r\n\r\n            existingDeviceInfo->State = DSM_DEV_STANDBY;\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpAllowStandbyPathsToRest (Group %p): DevInfo %p changed to state %d at %d\\n\",\r\n                        Group,\r\n                        existingDeviceInfo,\r\n                        existingDeviceInfo->State,\r\n                        __LINE__));\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpAllowStandbyPathsToRest (Group %p): Exiting function.\\n\",\r\n                Group));\r\n    return;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpGetAnyActivePath(\r\n    _In_ PDSM_GROUP_ENTRY Group,\r\n    _In_ BOOLEAN Exception,\r\n    _In_opt_ PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will return an active path from the list\r\n\r\n    This routine assumes that the DSM lock is held\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n    Exception - if TRUE, indicates that the returned devInfo must not be the same\r\n                as the one passed in.\r\n    DeviceInfo - the must-not-match devInfo. Valid parameter only if Exception is\r\n                 TRUE.\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    active path or NULL\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO existingDeviceInfo;\r\n    PDSM_DEVICE_INFO candidateDevInfo = NULL;\r\n    ULONG inx;\r\n\r\n    UNREFERENCED_PARAMETER(SpecialHandlingFlag);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetAnyActivePath (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    for (inx = 0; inx < DSM_MAX_PATHS; inx++) {\r\n\r\n        existingDeviceInfo = Group->DeviceList[inx];\r\n\r\n        if (existingDeviceInfo &&\r\n            existingDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED &&\r\n            DsmpIsDeviceInitialized(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsable(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsablePR(existingDeviceInfo)) {\r\n\r\n\r\n            if (Exception && existingDeviceInfo == DeviceInfo) {\r\n                continue;\r\n            }\r\n\r\n            candidateDevInfo = existingDeviceInfo;\r\n            break;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetAnyActivePath (Group %p): Exiting function with DevInfo %p\\n\",\r\n                Group,\r\n                candidateDevInfo));\r\n\r\n    return candidateDevInfo;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpGetActivePathToBeUsed(\r\n    _In_ PDSM_GROUP_ENTRY Group,\r\n    _In_ BOOLEAN Symmetric,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will return an active path from the list that should\r\n    be the next one used by the DSM\r\n\r\n    This routine assumes that the DSM lock is held\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    active path or NULL\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetActivePathToBeUsed (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    deviceInfo = NULL;\r\n\r\n    switch (Group->LoadBalanceType) {\r\n\r\n        case DSM_LB_LEAST_BLOCKS:\r\n        case DSM_LB_DYN_LEAST_QUEUE_DEPTH: {\r\n\r\n            //\r\n            // Since we choose the path with the smallest queue or cumulative size in\r\n            // DsmpGetPath, we just pick any path now\r\n            //\r\n\r\n            // fall through\r\n        }\r\n\r\n        case DSM_LB_ROUND_ROBIN_WITH_SUBSET:\r\n        case DSM_LB_ROUND_ROBIN: {\r\n\r\n            //\r\n            // For RR and RRS we just pick any active path to start with\r\n            // and the DsmpGetPath will do the round robining\r\n            //\r\n        }\r\n\r\n        case DSM_LB_FAILOVER: {\r\n\r\n            deviceInfo = DsmpGetAnyActivePath(Group, FALSE, NULL, SpecialHandlingFlag);\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_WEIGHTED_PATHS: {\r\n\r\n            PDSM_DEVICE_INFO workDeviceInfo;\r\n            ULONG weight = (ULONG) -1;\r\n            ULONG inx;\r\n\r\n            for (inx = 0; inx < Group->NumberDevices; inx++) {\r\n\r\n                workDeviceInfo = Group->DeviceList[inx];\r\n\r\n                if ((workDeviceInfo) &&\r\n                    (DsmpIsDeviceInitialized(workDeviceInfo)) &&\r\n                    (DsmpIsDeviceUsable(workDeviceInfo)) &&\r\n                    (DsmpIsDeviceUsablePR(workDeviceInfo)) &&\r\n                    (workDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) &&\r\n                    (workDeviceInfo->PathWeight < weight)) {\r\n\r\n                    //\r\n                    // We found a path that is active and is at\r\n                    // the lowest weight. Remember it.\r\n                    //\r\n                    weight = workDeviceInfo->PathWeight;\r\n\r\n                    deviceInfo = workDeviceInfo;\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    if (!deviceInfo && !Symmetric) {\r\n\r\n        //\r\n        // In the case of implicit transitions, it is possible that a TPG hasn't yet\r\n        // been made A/O. So instead of not setting any path, fall back to using some\r\n        // other path. IO sent down this path may fail, but will be retried in\r\n        // InterpretError(). Hopefully by then, at least one TPG will have transitioned\r\n        // to A/O state.\r\n        //\r\n        // The same argument holds true if the storage supports both implicit and\r\n        // explicit transitions, since it is possible that after we explicitly changed\r\n        // the TPG states, an implicit transition left us with no path in A/O state.\r\n        //\r\n        // In the case of explicit only transitions, we tried making at least one path\r\n        // as A/O and failed. This can happen, for example, when STPG fails because\r\n        // this initiator is not registered or does not hold exclusive reservation over\r\n        // the target. Instead of not using any path, we can consider a path in A/U state,\r\n        // A/U being just a functional path state.\r\n        //\r\n        BOOLEAN sendTPG = FALSE;\r\n\r\n        deviceInfo = DsmpFindStandbyPathToActivateALUA(Group, &sendTPG, SpecialHandlingFlag);\r\n\r\n        if ((deviceInfo != NULL) &&\r\n            ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_EXPLICIT) ||\r\n             ((deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT) &&\r\n              (deviceInfo->State <= DSM_DEV_ACTIVE_UNOPTIMIZED)))) {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpGetActivePathToBeUsed (Group %p): Using best alternative candidate device %p\\n\",\r\n                        Group,\r\n                        deviceInfo));\r\n        } else {\r\n\r\n            deviceInfo = NULL;\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpGetActivePathToBeUsed (Group %p): No active/alternative path available for group\\n\",\r\n                        Group));\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetActivePathToBeUsed (Group %p): Exiting function with devInfo %p.\\n\",\r\n                Group,\r\n                deviceInfo));\r\n\r\n    return deviceInfo;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathToActivate(\r\n    _In_ PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will find another path in the group that is active\r\n\r\n    This routine assumes that the DSM lock is held\r\n\r\n    This is used by devices that support symmetric LUA.\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Standby path or NULL if no standby path is available\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO existingDeviceInfo;\r\n    ULONG inx;\r\n    PDSM_DEVICE_INFO candidateDevInfo = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(SpecialHandlingFlag);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathToActivate(Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    for (inx = 0; inx < Group->NumberDevices; inx++) {\r\n\r\n        existingDeviceInfo = Group->DeviceList[inx];\r\n\r\n        if (existingDeviceInfo &&\r\n            existingDeviceInfo->State == DSM_DEV_STANDBY &&\r\n            DsmpIsDeviceInitialized(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsable(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsablePR(existingDeviceInfo)) {\r\n\r\n            //\r\n            // If we don't as yet have a candidate, pick the first available one.\r\n            // However, our preference is one that is through the preferred TPG.\r\n            //\r\n            if (!candidateDevInfo ||\r\n                existingDeviceInfo->TargetPortGroup && existingDeviceInfo->TargetPortGroup->Preferred) {\r\n\r\n                candidateDevInfo = existingDeviceInfo;\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathToActivate (Group %p): Exiting function with devInfo %p.\\n\",\r\n                Group,\r\n                candidateDevInfo));\r\n\r\n    return candidateDevInfo;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathToActivateALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PBOOLEAN SendTPG,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will find another path in the group that is active\r\n\r\n    This is used by devices that don't support symmetric LUA.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n    SendTPG - output parameter that indicates if TPG command need to be sent down.\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Standby path or NULL if no standby path is available\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO existingDeviceInfo;\r\n    ULONG inx;\r\n    PDSM_DEVICE_INFO candidateDevInfo = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(SpecialHandlingFlag);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathToActivateALUA (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    for (inx = 0; inx < Group->NumberDevices; inx++) {\r\n\r\n        existingDeviceInfo = Group->DeviceList[inx];\r\n\r\n        //\r\n        // The candidate for making A/O obviously mustn't be in a failed state\r\n        // and should have a path assigned.\r\n        //\r\n        if (existingDeviceInfo &&\r\n            !DsmpIsDeviceFailedState(existingDeviceInfo->State) &&\r\n            DsmpIsDeviceInitialized(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsable(existingDeviceInfo) &&\r\n            DsmpIsDeviceUsablePR(existingDeviceInfo)) {\r\n\r\n            //\r\n            // If we don't have any candidate currently, choose the very first\r\n            // one that is in a non-failure state, regardless of what state it\r\n            // may be in.\r\n            //\r\n            if (!candidateDevInfo) {\r\n\r\n                candidateDevInfo = existingDeviceInfo;\r\n                *SendTPG = TRUE;\r\n            }\r\n\r\n            //\r\n            // Might as well use one that the Admin desires for to be in A/O\r\n            //\r\n            if (existingDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                //\r\n                // However, such a devInfo is not a better candidate if our candidate\r\n                // devInfo is also one that the Admin desires be in A/O, and it is\r\n                // through a preferred TPG.\r\n                //\r\n                if (!(existingDeviceInfo->DesiredState == candidateDevInfo->DesiredState &&\r\n                      candidateDevInfo->TargetPortGroup->Preferred)) {\r\n\r\n                    candidateDevInfo = existingDeviceInfo;\r\n                    *SendTPG = TRUE;\r\n                }\r\n            }\r\n\r\n            //\r\n            // Check if the current one is at least better than the candidate.\r\n            //\r\n            if (DsmpIsBetterDeviceState(candidateDevInfo->State, existingDeviceInfo->State)) {\r\n\r\n                candidateDevInfo = existingDeviceInfo;\r\n                *SendTPG = TRUE;\r\n            }\r\n\r\n            //\r\n            // We found one that we may have just masked as non-A/O. This is the\r\n            // best option as we don't have to send down an STPG.\r\n            //\r\n            if (existingDeviceInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                candidateDevInfo = existingDeviceInfo;\r\n                *SendTPG = FALSE;\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathToActivateALUA (Group %p): Exiting function with devInfo %p.\\n\",\r\n                Group,\r\n                candidateDevInfo));\r\n\r\n    return candidateDevInfo;\r\n}\r\n\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathInAlternateTpgALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will find another path in the group that is not in the same\r\n    TPG as the passed in DeviceInfo.\r\n\r\n    This routine assumes that the DSM lock is held\r\n\r\n    This is used by devices that support ALUA.\r\n\r\nArguements:\r\n\r\n    Group is the multipath group\r\n    DeviceInfo is the devInfo whose TPG must not be matched\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Standby path not in same TPG as passed in DeviceInfo\r\n    or NULL if no standby path is available\r\n\r\n--*/\r\n{\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = DeviceInfo->TargetPortGroup;\r\n    PDSM_DEVICE_INFO existingDeviceInfo;\r\n    ULONG inx;\r\n    PDSM_DEVICE_INFO candidateDevInfo = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(SpecialHandlingFlag);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathInAlternateTpgALUA (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    for (inx = 0; inx < Group->NumberDevices; inx++) {\r\n\r\n        existingDeviceInfo = Group->DeviceList[inx];\r\n\r\n        //\r\n        // We only care about deviceInfo if TPG is different\r\n        //\r\n        if (existingDeviceInfo && existingDeviceInfo->TargetPortGroup != targetPortGroup) {\r\n\r\n            //\r\n            // The candidate for making A/O obviously mustn't be in a failed state\r\n            // and must be initialized\r\n            //\r\n            if (!DsmpIsDeviceFailedState(existingDeviceInfo->State) &&\r\n                DsmpIsDeviceInitialized(existingDeviceInfo) &&\r\n                DsmpIsDeviceUsable(existingDeviceInfo) &&\r\n                DsmpIsDeviceUsablePR(existingDeviceInfo)) {\r\n\r\n                //\r\n                // If we don't have any candidate currently, choose the very first\r\n                // one that is in a non-failure state, regardless of what state it\r\n                // may be in.\r\n                //\r\n                if (!candidateDevInfo) {\r\n\r\n                    candidateDevInfo = existingDeviceInfo;\r\n                    continue;\r\n                }\r\n\r\n                //\r\n                // Check if the current one is at least better than the candidate.\r\n                //\r\n                if (DsmpIsBetterDeviceState(candidateDevInfo->State, existingDeviceInfo->State)) {\r\n\r\n                    candidateDevInfo = existingDeviceInfo;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFindStandbyPathInAlternateTpgALUA (DevInfo %p): Exiting function with devInfo %p.\\n\",\r\n                DeviceInfo,\r\n                candidateDevInfo));\r\n\r\n    return candidateDevInfo;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForDsmPolicyAdjustment(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a change is made to the DSM-wide default\r\n    load balance policy. It goes through each LUN representation (ie. Group\r\n    entry) and updates the appropriate ones (ie. ones for which the policy\r\n    was not chosen based on VID/PID or because of an explicit settings on\r\n    the LUN). It also then updates the path states in accordance with the\r\n    new LB policy.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n    LoadBalanceType is the new load balance policy to be applied\r\n    PreferredPath is the preferred failback path to be used (applicable only\r\n                  if LB policy is Failover)\r\n\r\nReturn Value:\r\n\r\n    Success\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL oldIrql;\r\n    PLIST_ENTRY entry;\r\n    ULONG groupIndex = 0;\r\n    ULONG devInfoIndex;\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    DSM_LOAD_BALANCE_TYPE newLoadBalancePolicy;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLBForDsmPolicyAdjustment (DsmContext %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    for (entry = DsmContext->GroupList.Flink; entry != &(DsmContext->GroupList); entry = entry->Flink, groupIndex++) {\r\n\r\n        group = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry);\r\n\r\n        newLoadBalancePolicy = LoadBalanceType;\r\n\r\n        //\r\n        // Only LUNs that don't have their policy explicitly set\r\n        // and ones that don't have it set based on VID/PID are\r\n        // of interest to us here.\r\n        //\r\n        if (group->LBPolicySelection == DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY ||\r\n            group->LBPolicySelection == DSM_DEFAULT_LB_POLICY_DSM_WIDE) {\r\n\r\n            //\r\n            // Also, if the caller is trying to clear the DSM-wide\r\n            // default policy, then we don't even care about those\r\n            // LUNs whose policies were not set using this value.\r\n            //\r\n            if (newLoadBalancePolicy < DSM_LB_FAILOVER &&\r\n                group->LBPolicySelection != DSM_DEFAULT_LB_POLICY_DSM_WIDE) {\r\n\r\n                continue;\r\n            }\r\n\r\n            //\r\n            // If the DSM-wide setting is being cleared, we need to fall back\r\n            // to using the default based on the array's ALUA capabilities.\r\n            //\r\n            if (newLoadBalancePolicy < DSM_LB_FAILOVER) {\r\n\r\n                newLoadBalancePolicy = DSM_LB_ROUND_ROBIN;\r\n                group->PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n                group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY;\r\n\r\n\r\n            } else {\r\n\r\n                //\r\n                // Since a new policy has been selected for the DSM-wide\r\n                // one, it needs to be applied to this LUN.\r\n                //\r\n                group->PreferredPath = (ULONGLONG)((ULONG_PTR)PreferredPath);\r\n                group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE;\r\n            }\r\n\r\n            //\r\n            // If Round Robin is set and ALUA is enabled, we need to change the\r\n            // policy to Round Robin with Subset.\r\n            //\r\n            if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && newLoadBalancePolicy == DSM_LB_ROUND_ROBIN) {\r\n\r\n                newLoadBalancePolicy = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n            }\r\n\r\n            //\r\n            // Finally set the new load balance policy.\r\n            //\r\n            group->LoadBalanceType = newLoadBalancePolicy;\r\n\r\n            //\r\n            // Path states need to be updated in accordance with the new policy.\r\n            //\r\n            for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) {\r\n\r\n                devInfo = group->DeviceList[devInfoIndex];\r\n                DsmpSetNewDefaultLBPolicy(DsmContext, devInfo, group->LoadBalanceType, SpecialHandlingFlag);\r\n            }\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLBForDsmPolicyAdjustment (DsmContext %p): Exiting function with status %x\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForVidPidPolicyAdjustment(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PWSTR TargetHardwareId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a change is made to the default load balance\r\n    policy for a VID/PID. It goes through each LUN representation (ie. Group\r\n    entry) and updates the appropriate ones (ie. ones for which the policy\r\n    was not because of an explicit settings on the LUN). It also then updates\r\n    the path states in accordance with the new LB policy.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n    TargetHardwareId is the VID/PID whose matching LUNs policy need to be updated\r\n    LoadBalanceType is the new load balance policy to be applied\r\n    PreferredPath is the preferred failback path to be used (applicable only\r\n                  if LB policy is Failover)\r\n\r\nReturn Value:\r\n\r\n    Success\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL oldIrql;\r\n    PLIST_ENTRY entry;\r\n    ULONG groupIndex = 0;\r\n    ULONG devInfoIndex;\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    DSM_LOAD_BALANCE_TYPE dsmLoadBalanceType;\r\n    ULONGLONG dsmPreferredPath;\r\n    BOOLEAN useDsmLBSettings = FALSE;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLBForVidPidPolicyAdjustment (%ws): Entering function.\\n\",\r\n                TargetHardwareId));\r\n\r\n    status = DsmpQueryDsmLBPolicyFromRegistry(&dsmLoadBalanceType, &dsmPreferredPath);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        useDsmLBSettings = TRUE;\r\n\r\n    } else {\r\n\r\n        if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n            status = STATUS_SUCCESS;\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpSetLBForVidPidPolicyAdjustment (%ws): MSDSM-wide default LB policy not set.\\n\",\r\n                        TargetHardwareId));\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpSetLBForVidPidPolicyAdjustment (%ws): Failed to query MSDMS-wide default LB setting. Status %x.\\n\",\r\n                        TargetHardwareId,\r\n                        status));\r\n        }\r\n    }\r\n\r\n    oldIrql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    for (entry = DsmContext->GroupList.Flink; entry != &(DsmContext->GroupList); entry = entry->Flink, groupIndex++) {\r\n\r\n        group = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry);\r\n\r\n        //\r\n        // Only LUNs that don't have their policy explicitly set\r\n        // are of interest to us here.\r\n        //\r\n        if (group->LBPolicySelection < DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT) {\r\n\r\n            //\r\n            // Figure out if this LUN matches the VID/PID of interest\r\n            // Device not of interest if it doesn't match the passed in target ID\r\n            //\r\n            if (wcscmp(group->HardwareId, TargetHardwareId) != 0) {\r\n\r\n                continue;\r\n            }\r\n\r\n            //\r\n            // Also, if the caller is trying to clear the VID/PID\r\n            // default policy, then we don't even care about those\r\n            // LUNs whose policies were not set using this value.\r\n            //\r\n            if (LoadBalanceType < DSM_LB_FAILOVER &&\r\n                group->LBPolicySelection != DSM_DEFAULT_LB_POLICY_VID_PID) {\r\n\r\n                continue;\r\n            }\r\n\r\n            //\r\n            // If the VID/PID setting is being cleared, we need to fall back\r\n            // to using the DSM-wide default policy if it has been set, else\r\n            // we need to use the default based on the array's ALUA capabilities.\r\n            //\r\n            if (LoadBalanceType < DSM_LB_FAILOVER) {\r\n\r\n                if (useDsmLBSettings) {\r\n\r\n                    //\r\n                    // Even if the MSDSM-wide policy is specified as RR, if the storage\r\n                    // is ALUA, we can't have the policy as RR, so we'll change it to\r\n                    // RRWS instead.\r\n                    //\r\n                    if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && dsmLoadBalanceType == DSM_LB_ROUND_ROBIN) {\r\n\r\n                        group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n\r\n                    } else {\r\n\r\n                        group->LoadBalanceType = dsmLoadBalanceType;\r\n                    }\r\n\r\n                    group->PreferredPath = (ULONGLONG)((ULONG_PTR)dsmPreferredPath);\r\n                    group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE;\r\n\r\n                } else {\r\n\r\n                    //\r\n                    // Default LB type:\r\n                    // is Round Robin if ALUA is not supported, or if ALUA support is implicit but access is symmetric,\r\n                    // else Round Robin With Subset (since in ALUA, all paths aren't in A/O).\r\n                    //\r\n                    if (DsmpIsSymmetricAccess(group->DeviceList[0])) {\r\n\r\n                        group->LoadBalanceType = DSM_LB_ROUND_ROBIN;\r\n\r\n                    } else {\r\n\r\n                        group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n                    }\r\n\r\n\r\n                    group->PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n                    group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY;\r\n                }\r\n\r\n            } else {\r\n\r\n                //\r\n                // Since a new policy has been selected for the DSM-wide\r\n                // one, it needs to be applied to this LUN.\r\n                //\r\n                // However, if the VID/PID policy is specified as RR but the storage\r\n                // is ALUA, we can't have the policy as RR, so we'll change it to\r\n                // RRWS instead.\r\n                //\r\n                if (!DsmpIsSymmetricAccess(group->DeviceList[0]) && LoadBalanceType == DSM_LB_ROUND_ROBIN) {\r\n\r\n                    group->LoadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n\r\n                } else {\r\n\r\n                    group->LoadBalanceType = LoadBalanceType;\r\n                }\r\n\r\n                group->PreferredPath = (ULONGLONG)((ULONG_PTR)PreferredPath);\r\n                group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID;\r\n            }\r\n\r\n            //\r\n            // Path states need to be updated in accordance with the new policy.\r\n            //\r\n            for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) {\r\n\r\n                devInfo = group->DeviceList[devInfoIndex];\r\n                DsmpSetNewDefaultLBPolicy(DsmContext, devInfo, group->LoadBalanceType, SpecialHandlingFlag);\r\n            }\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), oldIrql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLBForVidPidPolicyAdjustment (%ws): Exiting function with status %x\\n\",\r\n                TargetHardwareId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetNewDefaultLBPolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_opt_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called to adjust the path state of an instance of a\r\n    LUN for which a new default load balance policy was applied\r\n    following an admin request for such a change.\r\n\r\n    This routine must be called with spinlock held.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n    DeviceInfo is the device info on which the new path state needs to be set\r\n    LoadBalanceType is the load balance policy in accordance with which the path state needs to be adjusted\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetNewDefaultLBPolicy (DevInfo %p): Entering function\\n\",\r\n                DeviceInfo));\r\n\r\n    if (!DeviceInfo) {\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpSetNewDefaultLBPolicy;\r\n    }\r\n\r\n    if (!(DsmpIsDeviceInitialized(DeviceInfo) && DsmpIsDeviceUsable(DeviceInfo) && DsmpIsDeviceUsablePR(DeviceInfo)) ||\r\n        DsmpIsDeviceFailedState(DeviceInfo->State)) {\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n        goto __Exit_DsmpSetNewDefaultLBPolicy;\r\n    }\r\n\r\n\r\n    group = DeviceInfo->Group;\r\n\r\n    if (!DsmpIsSymmetricAccess(DeviceInfo)) {\r\n\r\n        DsmpAdjustDeviceStatesALUA(group, NULL, SpecialHandlingFlag);\r\n\r\n    } else {\r\n\r\n        switch (LoadBalanceType) {\r\n\r\n            //\r\n            // For failover, it is important the right path is\r\n            // chosen, ie. preferred path needs to be taken into\r\n            // consideration.\r\n            //\r\n            case DSM_LB_FAILOVER: {\r\n\r\n                DsmpSetLBForPathArrival(DsmContext, DeviceInfo, SpecialHandlingFlag);\r\n\r\n                break;\r\n            }\r\n\r\n            //\r\n            // For all other policies, the state must be A/O.\r\n            //\r\n            default: {\r\n\r\n                DeviceInfo->PreviousState = DeviceInfo->State;\r\n                DeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmpSetNewDefaultLBPolicy:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetNewDefaultLBPolicy (DevInfo %p): Exiting function with status %x\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathArrival(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO NewDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a new path arrives for a multipath\r\n    group that doesn't support ALUA. The routine will set the path\r\n    to the appropriate state and fix up the other paths state if\r\n    they need to change.\r\n\r\n    This is used by devices NOT supporting ALUA.\r\n\r\n    This routine must be called with spinlock held.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n    NewDeviceInfo is the device info for the newly arrived path\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathArrival (DevInfo %p): Entering function.\\n\",\r\n                NewDeviceInfo));\r\n\r\n    group = NewDeviceInfo->Group;\r\n\r\n    if (!(DsmpIsDeviceInitialized(NewDeviceInfo) && DsmpIsDeviceUsable(NewDeviceInfo) && DsmpIsDeviceUsablePR(NewDeviceInfo))) {\r\n\r\n        //\r\n        // Bad device instance. Nothing can be done about it.\r\n        //\r\n        NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n        NewDeviceInfo->State = DSM_DEV_UNDETERMINED;\r\n\r\n        NT_ASSERT(NewDeviceInfo->FailGroup == NULL);\r\n\r\n        goto __Exit_DsmpSetLBForPathArrival;\r\n    }\r\n\r\n\r\n    if (group->NumberDevices == 1) {\r\n\r\n        //\r\n        // if this is the only device for the group then we will always\r\n        // be active as every group must have at least one active path\r\n        //\r\n        if (NewDeviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n            //\r\n            // All's good\r\n            //\r\n            goto __Exit_DsmpSetLBForPathArrival;\r\n\r\n        } else {\r\n\r\n            NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n            NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrival (DevInfo %p): State changed to %d at %d\\n\",\r\n                    NewDeviceInfo,\r\n                    NewDeviceInfo->State,\r\n                    __LINE__));\r\n\r\n        goto __Exit_DsmpSetLBForPathArrival;\r\n    }\r\n\r\n    switch(group->LoadBalanceType) {\r\n        case DSM_LB_FAILOVER: {\r\n\r\n            //\r\n            // Get the current active path.\r\n            //\r\n            deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag);\r\n\r\n            //\r\n            // If the newly arriving path is the preferred path, this now should\r\n            // become our active path.\r\n            //\r\n            if (group->PreferredPath == ((ULONGLONG)((ULONG_PTR)(NewDeviceInfo->FailGroup->PathId)))) {\r\n\r\n                //\r\n                // If current active path is not the preferred path, change its\r\n                // path state to standby.\r\n                //\r\n                if (deviceInfo && deviceInfo != NewDeviceInfo) {\r\n\r\n                    deviceInfo->PreviousState = deviceInfo->State;\r\n                    deviceInfo->State = DSM_DEV_STANDBY;\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpSetLBForPathArrival (Group %p): Preferred path back online. DevInfo %p changed to state %d\\n\",\r\n                                group,\r\n                                deviceInfo,\r\n                                deviceInfo->State));\r\n                }\r\n\r\n                NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n            } else {\r\n\r\n                //\r\n                // In the case of failover, we must have only a single\r\n                // active path. If this newly added path is configured as\r\n                // the one that is desired to be active then we make this\r\n                // active and set the standby path that was active back to\r\n                // standby unless the preferred path is the currently active\r\n                // path. If the newly added path is supposed to be\r\n                // standby then we leave it as standby.\r\n                //\r\n                if (NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                    if (deviceInfo) {\r\n\r\n                        //\r\n                        // If the preferred path is currently active, don't change\r\n                        // it regardless of this path wanting to be in active state.\r\n                        //\r\n                        if (group->PreferredPath == ((ULONGLONG)((ULONG_PTR)(deviceInfo->FailGroup->PathId)))) {\r\n\r\n                            if (NewDeviceInfo != deviceInfo) {\r\n\r\n                                NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                                NewDeviceInfo->State = DSM_DEV_STANDBY;\r\n                            }\r\n\r\n                        } else {\r\n\r\n                            //\r\n                            // Since the preferred path is not active, make this\r\n                            // path active since it wants to be so. This means\r\n                            // changing the current active path to standby.\r\n                            //\r\n                            deviceInfo->PreviousState = deviceInfo->State;\r\n                            deviceInfo->State = DSM_DEV_STANDBY;\r\n\r\n                            NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                            NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                        }\r\n                    } else {\r\n\r\n                        NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                        NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                    }\r\n\r\n                } else {\r\n\r\n                    if (deviceInfo) {\r\n\r\n                        if (deviceInfo != NewDeviceInfo) {\r\n\r\n                            //\r\n                            // This newly arrived device doesn't want to be in\r\n                            // A/O, and we already have an active path, so make\r\n                            // it standby.\r\n                            //\r\n                            NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                            NewDeviceInfo->State = DSM_DEV_STANDBY;\r\n                        }\r\n                    } else {\r\n\r\n                        //\r\n                        // Since we currently don't have an active path, this one\r\n                        // needs to be made active, regardless of its path it wishes\r\n                        // to be in.\r\n                        //\r\n                        NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                        NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                    }\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_ROUND_ROBIN_WITH_SUBSET: {\r\n\r\n            //\r\n            // In RRWS, a set of paths can be active and another set of\r\n            // paths can be standby. We set the new path to the desired\r\n            // state unless the desired state is standby, but there are\r\n            // no active paths. Also if the desired state is Active we\r\n            // need to check if there are any existing paths that are\r\n            // also active but have a desired state of standby. For\r\n            // those we can move them back to standby.\r\n            //\r\n            if (NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                //\r\n                // We are the active path coming back. Find out who has\r\n                // been the active one and place him back to standby\r\n                //\r\n                DsmpAllowStandbyPathsToRest(group);\r\n                NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpSetLBForPathArrival (DevInfo %p): Changed to state %d at %d\\n\",\r\n                            NewDeviceInfo,\r\n                            NewDeviceInfo->State,\r\n                            __LINE__));\r\n\r\n            } else {\r\n\r\n                //\r\n                // if there are no paths already active then we've got\r\n                // to make this one AO, otherwise we can be non-AO\r\n                //\r\n                deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag);\r\n\r\n                if (!deviceInfo || deviceInfo == NewDeviceInfo) {\r\n\r\n                    NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                    NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                } else {\r\n\r\n                    NewDeviceInfo->State = DSM_DEV_STANDBY;\r\n                }\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpSetLBForPathArrival (%p): Changed to state %d at %d. Status %x\\n\",\r\n                            NewDeviceInfo,\r\n                            NewDeviceInfo->State,\r\n                            __LINE__,\r\n                            status));\r\n            }\r\n\r\n            status = STATUS_SUCCESS;\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_LEAST_BLOCKS:\r\n        case DSM_LB_ROUND_ROBIN:\r\n        case DSM_LB_DYN_LEAST_QUEUE_DEPTH:\r\n        case DSM_LB_WEIGHTED_PATHS: {\r\n\r\n            //\r\n            // In RR, LWP, LB and LQD all paths are active so the new device\r\n            // becomes AO or AU.\r\n            //\r\n            if (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n                NewDeviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n            }\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetLBForPathArrival (DevInfo %p): Changed to state %d at %d. Status %x\\n\",\r\n                        NewDeviceInfo,\r\n                        NewDeviceInfo->State,\r\n                        __LINE__,\r\n                        status));\r\n\r\n            status = STATUS_SUCCESS;\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n            status = STATUS_INVALID_PARAMETER;\r\n            break;\r\n        }\r\n    }\r\n\r\n__Exit_DsmpSetLBForPathArrival:\r\n\r\n    //\r\n    // Update the next path to be used for the group\r\n    //\r\n    deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                           DsmpIsSymmetricAccess(NewDeviceInfo),\r\n                                           SpecialHandlingFlag);\r\n    if (deviceInfo != NULL) {\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)deviceInfo->FailGroup);\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrival (DevInfo %p): Updating PathToBeUsed in %p to %p\\n\",\r\n                    NewDeviceInfo,\r\n                    group,\r\n                    group->PathToBeUsed));\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrival (DevInfo %p): No FOG available for group %p\\n\",\r\n                    NewDeviceInfo,\r\n                    group));\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathArrival (DevInfo %p): Exiting function with status %x\\n\",\r\n                NewDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathArrivalALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO NewDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a new path arrives for a multipath\r\n    group. The routine will set the path to the appropriate state and\r\n    fix up the other paths state if they need to change.\r\n\r\n    Spin lock must NOT be held by caller\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n    NewDeviceInfo is the device info for the newly arrived path\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 warnings;\r\n    BOOLEAN lockHeld = FALSE;\r\n    PDSM_DEVICE_INFO preferredActiveDeviceInfo = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathArrivalALUA (DevInfo %p): Entering function.\\n\",\r\n                NewDeviceInfo));\r\n\r\n    group = NewDeviceInfo->Group;\r\n\r\n    if (!(DsmpIsDeviceInitialized(NewDeviceInfo) && DsmpIsDeviceUsable(NewDeviceInfo) && DsmpIsDeviceUsablePR(NewDeviceInfo))) {\r\n\r\n        //\r\n        // Bad device instance. Nothing can be done about it.\r\n        //\r\n        NewDeviceInfo->PreviousState = NewDeviceInfo->State;\r\n        NewDeviceInfo->State = DSM_DEV_UNDETERMINED;\r\n\r\n        NT_ASSERT(NewDeviceInfo->FailGroup == NULL);\r\n\r\n        goto __Exit_DsmpSetLBForPathArrivalALUA;\r\n    }\r\n\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    lockHeld = TRUE;\r\n\r\n    if (group->NumberDevices == 1) {\r\n\r\n        //\r\n        // If this is the only device for the group then it should be the\r\n        // active instance as every group must have at least one active path.\r\n        //\r\n        if (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n            lockHeld = FALSE;\r\n\r\n            if (NewDeviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n                //\r\n                // If the device supports explicit transitions, set its state to A/O\r\n                //\r\n                status = DsmpSetDeviceALUAState(DsmContext, NewDeviceInfo, DSM_DEV_ACTIVE_OPTIMIZED);\r\n\r\n            } else {\r\n\r\n                //\r\n                // Since the device supports only implicit transitions, send down\r\n                // RTPG and hope that the controller has made this one the A/O path.\r\n                //\r\n                status = DsmpGetDeviceALUAState(DsmContext, NewDeviceInfo, NULL);\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    //\r\n                    // Remember that at this point it is possible that this path\r\n                    // is still non-A/O. We'll need to handle this in DsmGetPath\r\n                    // as a special case where we don't find an A/O path but the\r\n                    // storage supports implicit-only transitions. At that time,\r\n                    // we mustn't blindly return a NULL path back.\r\n                    //\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpSetLBForPathArrivalALUA (DevInfo %p): RTPG returned state = %x, ALUA state = %x.\\n\",\r\n                                NewDeviceInfo,\r\n                                NewDeviceInfo->State,\r\n                                NewDeviceInfo->ALUAState));\r\n                }\r\n            }\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrivalALUA (DevInfo %p): State changed to %d at %d\\n\",\r\n                    NewDeviceInfo,\r\n                    NewDeviceInfo->State,\r\n                    __LINE__));\r\n\r\n    } else {\r\n\r\n        deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag);\r\n\r\n        //\r\n        // Irrespecitve of the policy, we must have at least one A/O path.\r\n        //\r\n        // For RRWS and FOO, this path is of interest if it is desired to be in A/O.\r\n        //\r\n        // Also, for failover-only, this new path is of interest if it is\r\n        // the preferred path.\r\n        //\r\n        // This path is also of interest if it is not A/O and desired state has not\r\n        // explicitly been set to non-A/O and it has been exposed through the\r\n        // preferred TPG.\r\n        //\r\n        if ((!deviceInfo) ||\r\n            ((NewDeviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) &&\r\n             (group->LoadBalanceType == DSM_LB_FAILOVER ||\r\n              group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET)) ||\r\n            (group->PreferredPath == (ULONGLONG)((ULONG_PTR)(NewDeviceInfo->FailGroup->PathId)) &&\r\n             group->LoadBalanceType == DSM_LB_FAILOVER) ||\r\n            (NewDeviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n             NewDeviceInfo->DesiredState == DSM_DEV_UNDETERMINED &&\r\n             NewDeviceInfo->TargetPortGroup->Preferred)) {\r\n\r\n            //\r\n            // Since this path is supposed to be active, we make it\r\n            // active and then allow any paths that are supposed to\r\n            // be standby go back to being standby\r\n            //\r\n            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n            lockHeld = FALSE;\r\n\r\n            //\r\n            // If explicit ALUA is supported, we need to send down STPG to make the change.\r\n            //\r\n            if (NewDeviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n                status = DsmpSetDeviceALUAState(DsmContext, NewDeviceInfo, DSM_DEV_ACTIVE_OPTIMIZED);\r\n\r\n            } else {\r\n\r\n                //\r\n                // If implicit ALUA, the controller may have made some\r\n                // changes to the TPG states. We just need to query it.\r\n                // We'll try and honor the Admin's request but can't\r\n                // guarantee it.\r\n                //\r\n                status = DsmpGetDeviceALUAState(DsmContext, NewDeviceInfo, NULL);\r\n            }\r\n\r\n            //\r\n            // We prefer this newly arrived devInfo to be A/O\r\n            //\r\n            preferredActiveDeviceInfo = NewDeviceInfo;\r\n        }\r\n    }\r\n\r\n    if (!lockHeld) {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n        lockHeld = TRUE;\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        DsmpAdjustDeviceStatesALUA(group, preferredActiveDeviceInfo, SpecialHandlingFlag);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrivalALUA (DevInfo %p): Trying to query ALUA state failed with %x\\n\",\r\n                    NewDeviceInfo,\r\n                    status));\r\n    }\r\n\r\n    status = STATUS_SUCCESS;\r\n\r\n__Exit_DsmpSetLBForPathArrivalALUA:\r\n\r\n    //\r\n    // Update the next path to be used for the group\r\n    //\r\n    deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                           DsmpIsSymmetricAccess(NewDeviceInfo),\r\n                                           SpecialHandlingFlag);\r\n    if (deviceInfo != NULL) {\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)deviceInfo->FailGroup);\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrivalALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\\n\",\r\n                    NewDeviceInfo,\r\n                    group,\r\n                    group->PathToBeUsed));\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathArrivalALUA (DevInfo %p): No active/alternative path available for group %p\\n\",\r\n                    NewDeviceInfo,\r\n                    group));\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n    }\r\n\r\n    if (lockHeld) {\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathArrivalALUA (DevInfo %p): Exiting function with status %x\\n\",\r\n                NewDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathRemoval(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo,\r\n    _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a path is removed from a multipath\r\n    group. The routine will set the path to the appropriate state and\r\n    fix up the other paths state if they need to change.\r\n\r\n    Note: This is used by devices NOT supporting ALUA.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n\r\n    RemovedDeviceInfo is the device info for failing/going-away path\r\n\r\n    Group is an optional group override.  That is, if Group is not NULL, this\r\n        function will run the load balance policy on the given Group and not\r\n        the Group from the RemovedDeviceInfo.  This should only be used when\r\n        it's impossible to get a pointer to the RemovedDeviceInfo.\r\n\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathRemoval (DevInfo %p, Group %p): Entering function.\\n\",\r\n                RemovedDeviceInfo,\r\n                Group));\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    if (Group == NULL) {\r\n\r\n        if (!(DsmpIsDeviceFailedState(RemovedDeviceInfo->State))) {\r\n\r\n            RemovedDeviceInfo->LastKnownGoodState = RemovedDeviceInfo->State;\r\n        }\r\n\r\n        RemovedDeviceInfo->PreviousState = RemovedDeviceInfo->State;\r\n        RemovedDeviceInfo->State = DSM_DEV_FAILED;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemoval (DevInfo %p): changed to state %d at %d\\n\",\r\n                    RemovedDeviceInfo,\r\n                    RemovedDeviceInfo->State,\r\n                    __LINE__));\r\n\r\n        group = RemovedDeviceInfo->Group;\r\n\r\n    } else {\r\n        //\r\n        // The caller has chosen to override the RemovedDeviceInfo->Group.\r\n        //\r\n        group = Group;\r\n    }\r\n\r\n    switch(group->LoadBalanceType) {\r\n        case DSM_LB_FAILOVER:\r\n        case DSM_LB_ROUND_ROBIN_WITH_SUBSET: {\r\n\r\n            //\r\n            // In the case of failover, we must have only a single\r\n            // active path. If the removed path was the active path we\r\n            // need to find another path to become active\r\n            //\r\n            // In RRWS, a set of paths can be active and another set of\r\n            // paths can be standby. If the removed path is an active\r\n            // path then we need to make sure there is another active\r\n            // path. If there is already another active path then there\r\n            // is nothing to do. If not then a path needs to be made\r\n            // active.\r\n            //\r\n            if (!DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag)) {\r\n\r\n                deviceInfo = DsmpFindStandbyPathToActivate(group, SpecialHandlingFlag);\r\n                if (deviceInfo) {\r\n\r\n                    deviceInfo->PreviousState = deviceInfo->State;\r\n                    deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpSetLBForPathRemoval (DevInfo %p): DevInfo %p changed to state %d at %d\\n\",\r\n                                RemovedDeviceInfo,\r\n                                deviceInfo,\r\n                                deviceInfo->State,\r\n                                __LINE__));\r\n                }\r\n            } else {\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpSetLBForPathRemoval (DevInfo %p): LB Policy FO/RRWS and other paths active, no path made active at %d\\n\",\r\n                            RemovedDeviceInfo,\r\n                            __LINE__));\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_LB_LEAST_BLOCKS:\r\n        case DSM_LB_ROUND_ROBIN:\r\n        case DSM_LB_WEIGHTED_PATHS:\r\n        case DSM_LB_DYN_LEAST_QUEUE_DEPTH: {\r\n\r\n            //\r\n            // In RR, LQD, LB and LWP, all paths are active so we don't\r\n            // need to worry about activating a new path\r\n            //\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetLBForPathRemoval (DevInfo %p): LB Policy RR, LWP or LQD, no path made active at %d\\n\",\r\n                        RemovedDeviceInfo,\r\n                        __LINE__));\r\n            break;\r\n        }\r\n\r\n        default: {\r\n            status = STATUS_INVALID_PARAMETER;\r\n            break;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Update the next path to be used for the group\r\n    //\r\n    deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                           DsmpIsSymmetricAccess(RemovedDeviceInfo),\r\n                                           SpecialHandlingFlag);\r\n    if (deviceInfo != NULL) {\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemoval (DevInfo %p): Removal: Updating PathToBeUsed in %p to %p\\n\",\r\n                    RemovedDeviceInfo,\r\n                    group,\r\n                    group->PathToBeUsed));\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemoval (DevInfo %p): After remove No FOG available for group %p\\n\",\r\n                    RemovedDeviceInfo,\r\n                    group));\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathRemoval (DevInfo %p): Exiting function with status %x\\n\",\r\n                RemovedDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathRemovalALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo,\r\n    _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a path is removed from a multipath\r\n    group. The routine will set the path to the appropriate state and\r\n    fix up the other paths state if they need to change.\r\n\r\n    Note: This should NOT be called with DsmContext Lock held\r\n          This is used for devices supporting ALUA.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n\r\n    RemovedDeviceInfo is the device info for the failing/going-away path\r\n\r\n    Group is an optional group override.  That is, if Group is not NULL, this\r\n        function will run the load balance policy on the given Group and not\r\n        the Group from the RemovedDeviceInfo.  This should only be used when\r\n        it's impossible to get a pointer to the RemovedDeviceInfo.\r\n\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n    BOOLEAN lockHeld = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathRemovalALUA (DevInfo %p, Group %p): Entering function.\\n\",\r\n                RemovedDeviceInfo,\r\n                Group));\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n    lockHeld = TRUE;\r\n\r\n    if (Group == NULL) {\r\n\r\n        if (!(DsmpIsDeviceFailedState(RemovedDeviceInfo->State))) {\r\n\r\n            RemovedDeviceInfo->LastKnownGoodState = RemovedDeviceInfo->State;\r\n        }\r\n\r\n        RemovedDeviceInfo->PreviousState = RemovedDeviceInfo->State;\r\n        RemovedDeviceInfo->State = DSM_DEV_FAILED;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemovalALUA (DevInfo %p): changed to state %d at %d\\n\",\r\n                    RemovedDeviceInfo,\r\n                    RemovedDeviceInfo->State,\r\n                    __LINE__));\r\n\r\n        group = RemovedDeviceInfo->Group;\r\n\r\n    } else {\r\n        //\r\n        // The caller has chosen to override the RemovedDeviceInfo->Group.\r\n        //\r\n        group = Group;\r\n    }\r\n\r\n    if (group->LoadBalanceType < DSM_LB_FAILOVER ||\r\n        group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n    } else {\r\n\r\n        //\r\n        // In the case of failover, we must have only a single\r\n        // active path. If the removed path was the active path we\r\n        // need to find another path to become active\r\n        //\r\n        // In rest of policies, set of paths can be active and another set of\r\n        // paths can be standby. If the removed path is an active\r\n        // path then we need to make sure there is another active\r\n        // path. If there is already another active path then there\r\n        // is nothing to do. If not then a path needs to be made\r\n        // active.\r\n        //\r\n        if (!DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag)) {\r\n\r\n            BOOLEAN sendTPG = TRUE;\r\n\r\n            deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag);\r\n\r\n            if (deviceInfo) {\r\n\r\n                if (sendTPG) {\r\n\r\n                    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n                    lockHeld = FALSE;\r\n\r\n                    //\r\n                    // If explicit transition supported, we need to send down STPG to make the change.\r\n                    //\r\n                    if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n                        status = DsmpSetDeviceALUAState(DsmContext, deviceInfo, DSM_DEV_ACTIVE_OPTIMIZED);\r\n\r\n                    } else {\r\n\r\n                        //\r\n                        // If implicit ALUA, the controller may have made necessary\r\n                        // changes to the TPG states. We just need to query it.\r\n                        //\r\n                        status = DsmpGetDeviceALUAState(DsmContext, deviceInfo, NULL);\r\n                    }\r\n\r\n                    if (!lockHeld) {\r\n                        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n                        lockHeld = TRUE;\r\n                    }\r\n\r\n                    if (NT_SUCCESS(status)) {\r\n\r\n                        DsmpAdjustDeviceStatesALUA(group, deviceInfo, SpecialHandlingFlag);\r\n\r\n                    } else {\r\n\r\n                        TracePrint((TRACE_LEVEL_WARNING,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmpSetLBForPathRemovalALUA (DevInfo %p): Trying to query for ALUA state failed with status %x\\n\",\r\n                                    RemovedDeviceInfo,\r\n                                    status));\r\n                    }\r\n                } else {\r\n\r\n                    deviceInfo->PreviousState = deviceInfo->State;\r\n                    deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                }\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpSetLBForPathRemovalALUA (DevInfo %p): Device %p changed to state %d at %d\\n\",\r\n                                RemovedDeviceInfo,\r\n                                deviceInfo,\r\n                                deviceInfo->State,\r\n                                __LINE__));\r\n                }\r\n            }\r\n        } else {\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetLBForPathRemovalALUA (DevInfo %p): Other paths active, no path made active at %d\\n\",\r\n                        RemovedDeviceInfo,\r\n                        __LINE__));\r\n        }\r\n\r\n        status = STATUS_SUCCESS;\r\n    }\r\n\r\n    //\r\n    // Update the next path to be used for the group\r\n    //\r\n    deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                           DsmpIsSymmetricAccess(RemovedDeviceInfo),\r\n                                           SpecialHandlingFlag);\r\n    if (deviceInfo != NULL) {\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemovalALUA (DevInfo %p): Removal: Updating PathToBeUsed in %p to %p\\n\",\r\n                    RemovedDeviceInfo,\r\n                    group,\r\n                    group->PathToBeUsed));\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetLBForPathRemovalALUA (DevInfo %p): No active/alternative path available for group %p\\n\",\r\n                    RemovedDeviceInfo,\r\n                    group));\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n    }\r\n\r\n    if (lockHeld) {\r\n\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetLBForPathRemovalALUA (DevInfo %p): Exiting function with status %x.\\n\",\r\n                RemovedDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathFailing(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN MarkDevInfoFailed,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when an IO that was sent using this path fails with\r\n    a fatal error. The routine will set the path to the appropriate state and\r\n    fix up the other paths state if they need to change.\r\n\r\n    Note: This is used by devices NOT supporting ALUA.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n\r\n    FailingDeviceInfo is the device info for the path on which IO failed\r\n\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetLBForPathFailing (DevInfo %p): Entering function.\\n\",\r\n                FailingDeviceInfo));\r\n\r\n    //\r\n    // We need to do exactly what DsmpSetLBForPathRemoval() does, except\r\n    // that the devInfo may not really go away (may come back before a\r\n    // Pnp remove comes down for the real LUN)\r\n    //\r\n    if (MarkDevInfoFailed) {\r\n        status = DsmpSetLBForPathRemoval(DsmContext, FailingDeviceInfo, NULL, SpecialHandlingFlag);\r\n    } else {\r\n        status = DsmpSetLBForPathRemoval(DsmContext, FailingDeviceInfo, FailingDeviceInfo->Group, SpecialHandlingFlag);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetLBForPathFailing (DevInfo %p): Exiting function with status %x\\n\",\r\n                FailingDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathFailingALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN MarkDevInfoFailed,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when an IO that was sent using this path fails with\r\n    a fatal error. The routine will set the path to the appropriate state and\r\n    send down a Set Target Port Groups command asynchronously to fix up the\r\n    other paths state if they need to change (actual work done in the completion\r\n    routine).\r\n\r\n    Note: This should NOT be called with DsmContext Lock held\r\n          This is used for devices supporting ALUA.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n\r\n    FailingDeviceInfo is the device info for the failing/going-away path\r\n\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength;\r\n    PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL;\r\n    PDSM_COMPLETION_CONTEXT completionContext = NULL;\r\n    PVOID senseInfo = NULL;\r\n    PSCSI_REQUEST_BLOCK srb = NULL;\r\n    PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetLBForPathFailingALUA (DevInfo %p): Entering function.\\n\",\r\n                FailingDeviceInfo));\r\n\r\n    if (MarkDevInfoFailed) {\r\n        if (!(DsmpIsDeviceFailedState(FailingDeviceInfo->State))) {\r\n\r\n            FailingDeviceInfo->LastKnownGoodState = FailingDeviceInfo->State;\r\n        }\r\n\r\n        FailingDeviceInfo->PreviousState = FailingDeviceInfo->State;\r\n        FailingDeviceInfo->State = DSM_DEV_FAILED;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpSetLBForPathFailingALUA (DevInfo %p): changed to state %d at %d\\n\",\r\n                    FailingDeviceInfo,\r\n                    FailingDeviceInfo->State,\r\n                    __LINE__));\r\n    }\r\n\r\n    group = FailingDeviceInfo->Group;\r\n\r\n    if (group->LoadBalanceType < DSM_LB_FAILOVER ||\r\n        group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n    } else {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n        //\r\n        // Check if there are any active paths that can be used.\r\n        //\r\n        deviceInfo = DsmpGetAnyActivePath(group, FALSE, NULL, SpecialHandlingFlag);\r\n        if (!deviceInfo) {\r\n\r\n            //\r\n            // Check if an Set/Report TPG has already been sent for this failing devInfo\r\n            //\r\n            failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(DsmContext, group, FailingDeviceInfo);\r\n\r\n            if (!failDevInfoListEntry) {\r\n\r\n                BOOLEAN sendTPG = TRUE;\r\n\r\n                deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag);\r\n\r\n                if (deviceInfo) {\r\n\r\n                    if (sendTPG) {\r\n\r\n                        tpgCompletionContext = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                                sizeof(DSM_TPG_COMPLETION_CONTEXT),\r\n                                                                DSM_TAG_TPG_COMPLETION_CONTEXT);\r\n\r\n                        if (tpgCompletionContext) {\r\n                            UCHAR senseInfoLength = SENSE_BUFFER_SIZE_EX;\r\n\r\n                            senseInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                         senseInfoLength,\r\n                                                         DSM_TAG_SCSI_SENSE_INFO);\r\n\r\n                            if (senseInfo) {\r\n\r\n                                srb = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                       sizeof(SCSI_REQUEST_BLOCK),\r\n                                                       DSM_TAG_SCSI_REQUEST_BLOCK);\r\n\r\n                                if (srb) {\r\n\r\n                                    srb->Length = SCSI_REQUEST_BLOCK_SIZE;\r\n                                    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;\r\n\r\n                                    completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList);\r\n                                    if (completionContext) {\r\n\r\n                                        //\r\n                                        // Update the target port group that needs to be made\r\n                                        // active/optimized. We will send down an STPG for\r\n                                        // storages that support both implicit and explicit.\r\n                                        // If the storage does NOT like our choice of A/O TPG,\r\n                                        // it will make an implicit transition. This is still\r\n                                        // a better option than solely relying on the storage's\r\n                                        // implicit transitions at this stage and ending up with\r\n                                        // no path in A/O state.\r\n                                        //\r\n                                        if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n                                            targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                                                         sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR);\r\n\r\n                                        } else {\r\n\r\n                                            //\r\n                                            // Find an active/optimized target port group that should\r\n                                            // have been set by the controller\r\n                                            //\r\n                                            // Take care of worst case scenario, which is:\r\n                                            // 1. 4-byte header (for allocation length)\r\n                                            // 2. 32 8-byte descriptors (for TPGs)\r\n                                            // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG)\r\n                                            //\r\n                                            targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                                                         (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                                                                                           DSM_MAX_PATHS * sizeof(ULONG)));\r\n                                        }\r\n\r\n                                        targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                                                targetPortGroupsInfoLength,\r\n                                                                                DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n                                        if (targetPortGroupsInfo) {\r\n\r\n                                            failDevInfoListEntry = DsmpBuildFailPathDevInfoEntry(DsmContext,\r\n                                                                                                 group,\r\n                                                                                                 FailingDeviceInfo,\r\n                                                                                                 deviceInfo);\r\n\r\n                                            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                                            if (failDevInfoListEntry) {\r\n\r\n                                                tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE);\r\n                                                tpgDescriptor->AsymmetricAccessState = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                                                REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &deviceInfo->TargetPortGroup->Identifier);\r\n\r\n                                                //\r\n                                                // Prevent the device info from being removed when a TPG is in-flight.\r\n                                                //\r\n                                                InterlockedIncrement(&FailingDeviceInfo->BlockRemove);\r\n\r\n                                                completionContext->DeviceInfo = FailingDeviceInfo;\r\n                                                completionContext->DsmContext = DsmContext;\r\n                                                completionContext->RequestUnique1 = deviceInfo;\r\n                                                completionContext->RequestUnique2 = FALSE;\r\n\r\n                                                tpgCompletionContext->CompletionContext = completionContext;\r\n                                                tpgCompletionContext->Srb = srb;\r\n                                                tpgCompletionContext->SenseInfoBuffer = senseInfo;\r\n                                                tpgCompletionContext->SenseInfoBufferLength = senseInfoLength;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_RW,\r\n                                                            \"DsmpSetLBForPathFailingALUA (DevInfo %p): Sending down TPG asynchronously for %p using devInfo %p (path %p).\\n\",\r\n                                                            FailingDeviceInfo,\r\n                                                            FailingDeviceInfo->FailGroup->PathId,\r\n                                                            deviceInfo,\r\n                                                            deviceInfo->FailGroup->PathId));\r\n\r\n                                                if (deviceInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n                                                    status = DsmpSetTargetPortGroupsAsync(deviceInfo,\r\n                                                                                          DsmpPhase1ProcessPathFailingALUA,\r\n                                                                                          tpgCompletionContext,\r\n                                                                                          targetPortGroupsInfoLength,\r\n                                                                                          targetPortGroupsInfo);\r\n                                                } else {\r\n\r\n                                                    status = DsmpReportTargetPortGroupsAsync(deviceInfo,\r\n                                                                                             DsmpPhase2ProcessPathFailingALUA,\r\n                                                                                             tpgCompletionContext,\r\n                                                                                             targetPortGroupsInfoLength,\r\n                                                                                             targetPortGroupsInfo);\r\n                                                }\r\n\r\n                                                if (status != STATUS_PENDING) {\r\n\r\n                                                    //\r\n                                                    // Request not sent down successfully. Free the allocations.\r\n                                                    //\r\n                                                    DsmpFreePool(targetPortGroupsInfo);\r\n                                                    ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                                    DsmpFreePool(srb);\r\n                                                    DsmpFreePool(senseInfo);\r\n                                                    DsmpFreePool(tpgCompletionContext);\r\n\r\n                                                    //\r\n                                                    // Allow the failing device to be removed.\r\n                                                    //\r\n                                                    InterlockedDecrement(&FailingDeviceInfo->BlockRemove);\r\n                                                }\r\n                                            } else {\r\n\r\n                                                //\r\n                                                // Fail to build DevInfo entry. Free the allocations.\r\n                                                //\r\n                                                DsmpFreePool(targetPortGroupsInfo);\r\n                                                ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                                DsmpFreePool(srb);\r\n                                                DsmpFreePool(senseInfo);\r\n                                                DsmpFreePool(tpgCompletionContext);\r\n\r\n                                            }\r\n                                        } else {\r\n                                            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                                            ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                            DsmpFreePool(srb);\r\n                                            DsmpFreePool(senseInfo);\r\n                                            DsmpFreePool(tpgCompletionContext);\r\n                                        }\r\n                                    } else {\r\n                                        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                                        NT_ASSERT(completionContext != NULL);\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate completion context. Failing path %p.\\n\",\r\n                                                    FailingDeviceInfo,\r\n                                                    FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                        DsmpFreePool(srb);\r\n                                        DsmpFreePool(senseInfo);\r\n                                        DsmpFreePool(tpgCompletionContext);\r\n                                    }\r\n                                } else {\r\n                                    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                                    NT_ASSERT(srb != NULL);\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate SRB. Failing path %p.\\n\",\r\n                                                FailingDeviceInfo,\r\n                                                FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                    DsmpFreePool(senseInfo);\r\n                                    DsmpFreePool(tpgCompletionContext);\r\n                                }\r\n                            } else {\r\n                                ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                                NT_ASSERT(senseInfo != NULL);\r\n\r\n                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                            TRACE_FLAG_RW,\r\n                                            \"DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate senseInfo. Failing path %p.\\n\",\r\n                                            FailingDeviceInfo,\r\n                                            FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                DsmpFreePool(tpgCompletionContext);\r\n                            }\r\n                        } else {\r\n                            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                            NT_ASSERT(tpgCompletionContext != NULL);\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_RW,\r\n                                        \"DsmpSetLBForPathFailingALUA (DevInfo %p): Failed to allocate TPG completion context. Failing path %p.\\n\",\r\n                                        FailingDeviceInfo,\r\n                                        FailingDeviceInfo->FailGroup->PathId));\r\n                        }\r\n                    } else {\r\n                        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                        deviceInfo->PreviousState = deviceInfo->State;\r\n                        deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_RW,\r\n                                    \"DsmpSetLBForPathFailingALUA (DevInfo %p): Found alternative devInfo %p for failing path %p without need for TPG\\n\",\r\n                                    FailingDeviceInfo,\r\n                                    deviceInfo,\r\n                                    FailingDeviceInfo->FailGroup->PathId));\r\n                    }\r\n                } else {\r\n                    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpSetLBForPathFailingALUA (DevInfo %p): Couldn't find a standby path to activate for failing path %p.\\n\",\r\n                                FailingDeviceInfo,\r\n                                FailingDeviceInfo->FailGroup->PathId));\r\n                }\r\n            } else {\r\n                ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                deviceInfo = failDevInfoListEntry->TempDeviceInfo;\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmpSetLBForPathFailingALUA (DevInfo %p): There is an RTPG/STPG already in progress for this path %p. Returning alternative %p.\\n\",\r\n                            FailingDeviceInfo,\r\n                            FailingDeviceInfo->FailGroup->PathId,\r\n                            deviceInfo));\r\n            }\r\n        } else {\r\n            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetLBForPathFailingALUA (DevInfo %p): Other paths active, no path made active at %d\\n\",\r\n                        FailingDeviceInfo,\r\n                        __LINE__));\r\n        }\r\n\r\n        status = STATUS_SUCCESS;\r\n    }\r\n\r\n    if (deviceInfo) {\r\n\r\n        //\r\n        // Update temporarily the next path to be used for the group as this devInfo\r\n        //\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup);\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpSetLBForPathFailingALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\\n\",\r\n                    FailingDeviceInfo,\r\n                    group,\r\n                    group->PathToBeUsed));\r\n\r\n    } else {\r\n\r\n        InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpSetLBForPathRemovalALUA (DevInfo %p): No FOG available for group %p\\n\",\r\n                    FailingDeviceInfo,\r\n                    group));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetLBForPathFailingALUA (DevInfo %p): Exiting function with status %x.\\n\",\r\n                FailingDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetPathForIoRetryALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN TPGException,\r\n    _In_ IN BOOLEAN DeviceInfoException\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when an IO that was sent using this path fails with\r\n    a retry-able \"ALUA\" error. What this basically means is that most likely an\r\n    implicit transition has taken place and we need an RTPG to get the updated\r\n    path states. The routine will send down a Report Target Port Groups command\r\n    asynchronously to get the paths states (actual work done in the completion\r\n    routine).\r\n\r\n    Note: This should NOT be called with DsmContext Lock held\r\n          This is used for devices supporting ALUA.\r\n\r\nArguements:\r\n\r\n    DsmContext is the DSM context\r\n\r\n    FailingDeviceInfo is the device info for the failing/going-away path\r\n\r\n    TPGException is a flag used to indicate if the selected path must be from a\r\n                      TPG that is different from FailingDeviceInfo's. This is\r\n                      special handling for UA with sense \"TPG in SB/UA state\"\r\n\r\n    DeviceInfoException is a flag used to indicate that the current FailindDeviceInfo\r\n                      itself needs to be used again. This is special handling for\r\n                      UA with sense \"Asymmetric Access State Changed\"\r\n\r\n    (NOTE: TPGException and DeviceInfoException are mutually exclusive, although\r\n           it is okay for both to be FALSE)\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength;\r\n    PDSM_COMPLETION_CONTEXT completionContext = NULL;\r\n    PVOID senseInfo = NULL;\r\n    PSCSI_REQUEST_BLOCK srb = NULL;\r\n    PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = NULL;\r\n    NTSTATUS throttleStatus = STATUS_UNSUCCESSFUL;\r\n    ULONG inflightRTPG;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetPathForIoRetryALUA (DevInfo %p): Entering function.\\n\",\r\n                FailingDeviceInfo));\r\n\r\n    group = FailingDeviceInfo->Group;\r\n\r\n\r\n    if (group->LoadBalanceType < DSM_LB_FAILOVER ||\r\n        group->LoadBalanceType > DSM_LB_LEAST_BLOCKS) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n    } else {\r\n\r\n        //\r\n        // First check to see if we need to find a candidate from a different TPG.\r\n        //\r\n        if (TPGException) {\r\n\r\n            irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n            //\r\n            // Find a candidate in a TPG that is different from this one\r\n            //\r\n            deviceInfo = DsmpFindStandbyPathInAlternateTpgALUA(group, FailingDeviceInfo, SpecialHandlingFlag);\r\n\r\n            ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): Need to try a different TPG deviceInfo %p.\\n\",\r\n                        FailingDeviceInfo,\r\n                        deviceInfo));\r\n\r\n        } else if (DeviceInfoException) {\r\n\r\n            //\r\n            // Retry on the same path\r\n            //\r\n            deviceInfo = FailingDeviceInfo;\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): Will retry using same deviceInfo %p.\\n\",\r\n                        FailingDeviceInfo,\r\n                        deviceInfo));\r\n        }\r\n\r\n        //\r\n        // Check if an Report TPG has already been sent for this group\r\n        //\r\n        inflightRTPG = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 0);\r\n\r\n        //\r\n        // If there is no RTPG currently in flight, use the best candidate found\r\n        // above to send down the RTPG. If there is already an RTPG inflight,\r\n        // we're done. The result of the RTPG should fix the path states.\r\n        //\r\n        if (!inflightRTPG) {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): No RTPG in flight. Try sending one down.\\n\",\r\n                        FailingDeviceInfo));\r\n\r\n            //\r\n            // If we need a candidate device, first get the currently active one.\r\n            // If we can't find one that way, resort to finding the best alternative.\r\n            // Basic idea is find SOME path instead of failing IOs back to the application.\r\n            //\r\n            if (!deviceInfo) {\r\n\r\n                irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n                //\r\n                // Find the best candidate - ie. either a currently A/O path or\r\n                // the best alternative path to be made A/O.\r\n                //\r\n                deviceInfo = DsmpGetAnyActivePath(group, TRUE, deviceInfo, SpecialHandlingFlag);\r\n                if (!deviceInfo) {\r\n\r\n                    BOOLEAN sendTPG = TRUE;\r\n\r\n                    deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag);\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpSetPathForIoRetryALUA (DevInfo %p): No active path. Best alternative %p.\\n\",\r\n                                FailingDeviceInfo,\r\n                                deviceInfo));\r\n                }\r\n                ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n            }\r\n\r\n            if (deviceInfo) {\r\n\r\n                tpgCompletionContext = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                        sizeof(DSM_TPG_COMPLETION_CONTEXT),\r\n                                                        DSM_TAG_TPG_COMPLETION_CONTEXT);\r\n\r\n                if (tpgCompletionContext) {\r\n                    UCHAR senseInfoLength = SENSE_BUFFER_SIZE_EX;\r\n\r\n                    senseInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                 senseInfoLength,\r\n                                                 DSM_TAG_SCSI_SENSE_INFO);\r\n\r\n                    if (senseInfo) {\r\n\r\n                        srb = DsmpAllocatePool(NonPagedPoolNx,\r\n                                               sizeof(SCSI_REQUEST_BLOCK),\r\n                                               DSM_TAG_SCSI_REQUEST_BLOCK);\r\n\r\n                        if (srb) {\r\n\r\n                            srb->Length = SCSI_REQUEST_BLOCK_SIZE;\r\n                            srb->Function = SRB_FUNCTION_EXECUTE_SCSI;\r\n\r\n                            completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList);\r\n\r\n                            if (completionContext) {\r\n\r\n                                //\r\n                                // Find an active/optimized target port group that should\r\n                                // have been set by the controller\r\n                                //\r\n                                // Take care of worst case scenario, which is:\r\n                                // 1. 4-byte header (for allocation length)\r\n                                // 2. 32 8-byte descriptors (for TPGs)\r\n                                // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG)\r\n                                //\r\n                                targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                                             (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                                                                               DSM_MAX_PATHS * sizeof(ULONG)));\r\n\r\n                                targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                                        targetPortGroupsInfoLength,\r\n                                                                        DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n                                if (targetPortGroupsInfo) {\r\n\r\n                                    completionContext->DeviceInfo = FailingDeviceInfo;\r\n                                    completionContext->DsmContext = DsmContext;\r\n                                    completionContext->RequestUnique1 = deviceInfo;\r\n                                    completionContext->RequestUnique2 = TRUE;\r\n\r\n                                    tpgCompletionContext->CompletionContext = completionContext;\r\n                                    tpgCompletionContext->Srb = srb;\r\n                                    tpgCompletionContext->SenseInfoBuffer = senseInfo;\r\n                                    tpgCompletionContext->SenseInfoBufferLength = senseInfoLength;\r\n\r\n                                    //\r\n                                    // Now we are all set to send the RTPG request.\r\n                                    // check and set InFlightRTPG to make sure this thread is the only one with\r\n                                    // the RTPG active for this group, since it is possible to have more than one\r\n                                    // threads reaching up to this point in parallel\r\n                                    //\r\n                                    inflightRTPG = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 1, 0);\r\n                                    if (inflightRTPG) {\r\n\r\n                                        DsmpFreePool(targetPortGroupsInfo);\r\n                                        ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                        DsmpFreePool(srb);\r\n                                        DsmpFreePool(senseInfo);\r\n                                        DsmpFreePool(tpgCompletionContext);\r\n                                    } else {\r\n\r\n                                        //\r\n                                        // Prevent the device info from being removed when a TPG is in-flight.\r\n                                        //\r\n                                        InterlockedIncrement(&FailingDeviceInfo->BlockRemove);\r\n\r\n                                        //\r\n                                        // First try and throttle the IO. The completion routine will\r\n                                        // take care of resuming the IO.\r\n                                        //\r\n                                        if (!InterlockedCompareExchange((LONG volatile*)&group->Throttled, 1, 0)) {\r\n\r\n                                            DsmNotification(((PDSM_CONTEXT)DsmContext)->MPIOContext,\r\n                                                            ThrottleIO_V2,\r\n                                                            deviceInfo,\r\n                                                            FALSE,\r\n                                                            &throttleStatus,\r\n                                                            0);\r\n\r\n                                            if (NT_SUCCESS(throttleStatus)) {\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_RW,\r\n                                                            \"DsmpSetPathForIoRetryALUA (DevInfo %p): Successfully throttled IO. About to send RTPG. Failing path %p.\\n\",\r\n                                                            FailingDeviceInfo,\r\n                                                            FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                            } else {\r\n\r\n                                                //\r\n                                                // Throttle can fail when the MPDisk is\r\n                                                // 1. Being removed. (or)\r\n                                                // 2. In any other state other than Normal or Degraded.\r\n                                                //\r\n\r\n                                                TracePrint((TRACE_LEVEL_WARNING,\r\n                                                            TRACE_FLAG_RW,\r\n                                                            \"DsmpSetPathForIoRetryALUA (DevInfo %p): Throttle before RTPG failed. Failing path %p.\\n\",\r\n                                                            FailingDeviceInfo,\r\n                                                            FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                                InterlockedDecrement((LONG volatile*)&FailingDeviceInfo->Group->Throttled);\r\n                                            }\r\n                                        } else {\r\n\r\n                                            //\r\n                                            // Currently we don't expect this to happen\r\n                                            //\r\n                                            NT_ASSERT(FALSE);\r\n                                        }\r\n\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmpSetPathForIoRetryALUA (DevInfo %p): Sending RTPG asynchronously. Failing path %p.\\n\",\r\n                                                    FailingDeviceInfo,\r\n                                                    FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                        if (STATUS_PENDING != DsmpReportTargetPortGroupsAsync(deviceInfo,\r\n                                                                                              DsmpPhase2ProcessPathFailingALUA,\r\n                                                                                              tpgCompletionContext,\r\n                                                                                              targetPortGroupsInfoLength,\r\n                                                                                              targetPortGroupsInfo)) {\r\n\r\n\r\n\r\n                                            //\r\n                                            // Request not sent down successfully. Free the allocations.\r\n                                            //\r\n                                            DsmpFreePool(targetPortGroupsInfo);\r\n                                            ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                            DsmpFreePool(srb);\r\n                                            DsmpFreePool(senseInfo);\r\n                                            DsmpFreePool(tpgCompletionContext);\r\n\r\n                                            //\r\n                                            // Allow the failing device to be removed.\r\n                                            //\r\n                                            InterlockedDecrement(&FailingDeviceInfo->BlockRemove);\r\n\r\n                                            //\r\n                                            // Resume IO if we throttled requests before calling DsmpReportTargetPortGroupsAsync\r\n                                            //\r\n                                            if (InterlockedCompareExchange((LONG volatile*)&group->Throttled, 0, 1)) {\r\n\r\n                                                NTSTATUS resumeStatus = STATUS_UNSUCCESSFUL;\r\n\r\n                                                DsmNotification(((PDSM_CONTEXT)deviceInfo->DsmContext)->MPIOContext,\r\n                                                                ResumeIO_V2,\r\n                                                                deviceInfo,\r\n                                                                TRUE,\r\n                                                                &resumeStatus,\r\n                                                                0);\r\n\r\n                                                if (!NT_SUCCESS(resumeStatus)) {\r\n\r\n                                                    //\r\n                                                    // Resume can fail when\r\n                                                    // 1. The MPDisk is being removed (or)\r\n                                                    // 2. The MPDisk is any other state other than throttled (or)\r\n                                                    // 3. There is a problem dispatching throttled requests.\r\n                                                    //\r\n\r\n                                                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                                                TRACE_FLAG_RW,\r\n                                                                \"DsmpSetPathForIoRetryALUA (DevInfo %p): Resume IO failed.\\n\",\r\n                                                                deviceInfo));\r\n                                                }\r\n\r\n                                            }\r\n\r\n                                            InterlockedDecrement((LONG volatile*)&group->InFlightRTPG);\r\n                                        }\r\n                                    }\r\n                                } else {\r\n\r\n                                    NT_ASSERT(targetPortGroupsInfo != NULL);\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate TPG info buffer. Failing path %p.\\n\",\r\n                                                FailingDeviceInfo,\r\n                                                FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                    ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n                                    ExFreePool(srb);\r\n                                    ExFreePool(senseInfo);\r\n                                    ExFreePool(tpgCompletionContext);\r\n                                }\r\n                            } else {\r\n\r\n                                NT_ASSERT(completionContext != NULL);\r\n\r\n                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                            TRACE_FLAG_RW,\r\n                                            \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate completion context. Failing path %p.\\n\",\r\n                                            FailingDeviceInfo,\r\n                                            FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                                ExFreePool(srb);\r\n                                ExFreePool(senseInfo);\r\n                                ExFreePool(tpgCompletionContext);\r\n                            }\r\n                        } else {\r\n\r\n                            NT_ASSERT(srb != NULL);\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_RW,\r\n                                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate SRB. Failing path %p.\\n\",\r\n                                        FailingDeviceInfo,\r\n                                        FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                            ExFreePool(senseInfo);\r\n                            ExFreePool(tpgCompletionContext);\r\n                        }\r\n                    } else {\r\n\r\n                        NT_ASSERT(senseInfo != NULL);\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_RW,\r\n                                    \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate senseInfo. Failing path %p.\\n\",\r\n                                    FailingDeviceInfo,\r\n                                    FailingDeviceInfo->FailGroup->PathId));\r\n\r\n                        ExFreePool(tpgCompletionContext);\r\n                    }\r\n                } else {\r\n\r\n                    NT_ASSERT(tpgCompletionContext != NULL);\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't allocate TPG completion context. Failing path %p.\\n\",\r\n                                FailingDeviceInfo,\r\n                                FailingDeviceInfo->FailGroup->PathId));\r\n                }\r\n            } else {\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmpSetPathForIoRetryALUA (DevInfo %p): Couldn't find a path for RTPG. Failing path %p.\\n\",\r\n                            FailingDeviceInfo,\r\n                            FailingDeviceInfo->FailGroup->PathId));\r\n            }\r\n        } else {\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): Other paths active, no path made active at %d\\n\",\r\n                        FailingDeviceInfo,\r\n                        __LINE__));\r\n        }\r\n\r\n        if(!deviceInfo) {\r\n\r\n            //\r\n            // It is possible that there are only two TPGs with one of them in U/A\r\n            // state and the other in transitioning state. In such a case, we would\r\n            // not find an alternative TPG deviceInfo. In addition, if there is an\r\n            // RTPG in flight, we won't go down the path of forcibly picking any\r\n            // deviceInfo. This is to cover that scenario, else we're left with no\r\n            // deviceInfo to do the retry and we'll end up setting the group's PTBU\r\n            // to NULL thus failing the retried request (if for eg. the LB is RRWS).\r\n            // Need to ensure that we handle this exception case.\r\n            //\r\n            if (inflightRTPG) {\r\n\r\n                irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n                //\r\n                // Find the best candidate - ie. either a currently A/O path or\r\n                // the best alternative path to be made A/O.\r\n                //\r\n                deviceInfo = DsmpGetAnyActivePath(group, TRUE, deviceInfo, SpecialHandlingFlag);\r\n                if (!deviceInfo) {\r\n\r\n                    BOOLEAN sendTPG = TRUE;\r\n\r\n                    deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag);\r\n                }\r\n\r\n                ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n            }\r\n        }\r\n\r\n        if(deviceInfo) {\r\n\r\n            //\r\n            // Update temporarily the next path to be used for the group as this devInfo\r\n            //\r\n            InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup);\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): Updating PathToBeUsed in %p to %p\\n\",\r\n                        FailingDeviceInfo,\r\n                        group,\r\n                        group->PathToBeUsed));\r\n\r\n        } else {\r\n            InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpSetPathForIoRetryALUA (DevInfo %p): No FOG available for group %p\\n\",\r\n                        FailingDeviceInfo,\r\n                        group));\r\n        }\r\n\r\n        status = STATUS_SUCCESS;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetPathForIoRetryALUA (DevInfo %p): Exiting function with status %x.\\n\",\r\n                FailingDeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPDSM_FAIL_PATH_PROCESSING_LIST_ENTRY\r\nDsmpFindFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine finds the entry that contains the alternate devInfo to use for\r\n    a failing one for the passed in devInfo.\r\n\r\n    N.B: This routine MUST be called with DsmContextLock held in either Shared or\r\n    Exclusive mode.\r\n\r\nArguments:\r\n\r\n    Context is the DSM's context info.\r\n\r\n    Group is the group entry representing the device.\r\n\r\n    FailingDevInfo is the device info whose entry needs to be found.\r\n\r\nReturn Value:\r\n\r\n    Pointer to the entry. NULL if it doesn't exist.\r\n\r\n--*/\r\n{\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL;\r\n    PLIST_ENTRY entry = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpFindFailPathDevInfoEntry (DevInfo %p): Entering function.\\n\",\r\n                FailingDevInfo));\r\n\r\n    for (entry = Group->FailingDevInfoList.Flink;\r\n         entry != &Group->FailingDevInfoList;\r\n         entry = entry->Flink) {\r\n\r\n        failDevInfoListEntry = CONTAINING_RECORD(entry, DSM_FAIL_PATH_PROCESSING_LIST_ENTRY, ListEntry);\r\n        NT_ASSERT(failDevInfoListEntry);\r\n\r\n        if (failDevInfoListEntry) {\r\n\r\n            if (failDevInfoListEntry->FailingDeviceInfo == FailingDevInfo) {\r\n\r\n                break;\r\n\r\n            } else {\r\n\r\n                failDevInfoListEntry = NULL;\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpFindFailPathDevInfoEntry (DevInfo %p): Exiting function returning entry %p.\\n\",\r\n                FailingDevInfo,\r\n                failDevInfoListEntry));\r\n\r\n    return failDevInfoListEntry;\r\n}\r\n\r\n\r\nPDSM_FAIL_PATH_PROCESSING_LIST_ENTRY\r\nDsmpBuildFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevInfo,\r\n    _In_ IN PDSM_DEVICE_INFO AlternateDevInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    When InterpretError() is called with an IRP that has failed with a fatal error,\r\n    if the device is ALUA it is possible that STPG needs to be sent to update a new\r\n    devInfo as being Active/Optimized. However, for in-flight IOs that weren't\r\n    queued by MPIO, we still need to return a path that can be used.\r\n\r\n    This routine is builds an entry that contains the alternate devInfo to use for\r\n    a failing one.\r\n\r\n    NOTE: Calling function should be holding the spin lock.\r\n\r\nArguments:\r\n\r\n    Context is the DSM's context info.\r\n\r\n    Group is the group entry representing the device.\r\n\r\n    FailingDevInfo is the device info that was used when the IRP failed.\r\n\r\n    AlternateDevInfo is the new one to temporarily use until its state can be properly set.\r\n\r\nReturn Value:\r\n\r\n    Pointer to the newly built entry.\r\n    NULL if there were any errors building it.\r\n\r\n--*/\r\n{\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpBuildFailPathDevInfoEntry (DevInfo %p): Entering function.\\n\",\r\n                FailingDevInfo));\r\n\r\n    failDevInfoListEntry = DsmpAllocatePool(NonPagedPoolNx,\r\n                                            sizeof(DSM_FAIL_PATH_PROCESSING_LIST_ENTRY),\r\n                                            DSM_TAG_FAIL_DEVINFO_LIST_ENTRY);\r\n\r\n    if (failDevInfoListEntry) {\r\n\r\n        failDevInfoListEntry->FailingDeviceInfo = FailingDevInfo;\r\n        failDevInfoListEntry->TempDeviceInfo = AlternateDevInfo;\r\n        InsertTailList(&Group->FailingDevInfoList, &failDevInfoListEntry->ListEntry);\r\n        InterlockedIncrement((LONG volatile*)&Group->NumberFailingDevInfos);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpBuildFailPathDevInfoEntry (DevInfo %p): Failed to allocate memory for entry.\\n\",\r\n                    FailingDevInfo));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpBuildFailPathDevInfoEntry (DevInfo %p): Exiting function returning entry %p.\\n\",\r\n                FailingDevInfo,\r\n                failDevInfoListEntry));\r\n\r\n    return failDevInfoListEntry;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPhase1ProcessPathFailingALUA(\r\n    IN PDEVICE_OBJECT DeviceObject,\r\n    IN PIRP Irp,\r\n    IN PVOID Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the completion routine that is called when the STPG is sent down by\r\n    DsmpSetLBForPathFailingALUA.\r\n\r\n    The caller SHOULD NOT acquire the DSM Context lock before calling this routine.\r\n\r\nArguements:\r\n\r\n    DeviceObject is the target device object to which Irp was sent\r\n\r\n    Irp is the scsi pass through request for STPG\r\n\r\n    Context is the completion context.\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);\r\n    PDSM_TPG_COMPLETION_CONTEXT context = (PDSM_TPG_COMPLETION_CONTEXT)Context;\r\n    PSCSI_REQUEST_BLOCK srb = context->Srb;\r\n    PVOID senseData = context->SenseInfoBuffer;\r\n    UCHAR senseDataLength = context->SenseInfoBufferLength;\r\n    NTSTATUS status = Irp->IoStatus.Status;\r\n    ULONG targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR);\r\n    PUCHAR targetPortGroupsInfo;\r\n    PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)(context->CompletionContext->RequestUnique1);\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL;\r\n    BOOLEAN releaseCompletionContextResources = TRUE;\r\n    KIRQL irql;\r\n    UCHAR scsiStatus = SrbGetScsiStatus(srb);\r\n\r\n    UNREFERENCED_PARAMETER(DeviceObject);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpPhase1ProcessPathFailingALUA (DevInfo %p): Entering function.\\n\",\r\n                deviceInfo));\r\n\r\n#if DBG\r\n    KeQuerySystemTime(&context->CompletionContext->TickCount);\r\n#endif\r\n\r\n    if ((scsiStatus == SCSISTAT_GOOD) &&\r\n        (NT_SUCCESS(status))) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpPhase1ProcessPathFailingALUA (DevInfo %p): STPG succeeded.\\n\",\r\n                    deviceInfo));\r\n\r\n    } else if (NT_SUCCESS(status) &&\r\n               scsiStatus == SCSISTAT_CHECK_CONDITION &&\r\n               DsmpShouldRetryTPGRequest(senseData, senseDataLength)) {\r\n\r\n        if ((context->NumberRetries)--) {\r\n\r\n            //\r\n            // Retry the request\r\n            //\r\n\r\n            NT_ASSERT(SrbGetDataBuffer(srb) == MmGetMdlVirtualAddress(Irp->MdlAddress));\r\n\r\n            //\r\n            // Reset byte count of transfer in SRB Extension.\r\n            //\r\n            SrbSetDataTransferLength(srb, Irp->MdlAddress->ByteCount);\r\n\r\n            //\r\n            // Zero SRB statuses.\r\n            //\r\n            srb->SrbStatus = 0;\r\n            SrbSetScsiStatus(srb, 0);\r\n\r\n            nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;\r\n            nextIrpStack->MinorFunction = IRP_MN_SCSI_CLASS;\r\n\r\n            //\r\n            // Save SRB address in next stack for port driver.\r\n            //\r\n            nextIrpStack->Parameters.Scsi.Srb = srb;\r\n            IoSetCompletionRoutine(Irp, DsmpPhase1ProcessPathFailingALUA, Context, TRUE, TRUE, TRUE);\r\n\r\n            IoMarkIrpPending(Irp);\r\n\r\n            //\r\n            // Send the IRP asynchronously\r\n            //\r\n            DsmSendRequestEx(context->CompletionContext->DsmContext->MPIOContext,\r\n                             deviceInfo->TargetObject,\r\n                             Irp,\r\n                             deviceInfo,\r\n                             DSM_CALL_COMPLETION_ON_MPIO_ERROR);\r\n\r\n            //\r\n            // We know that the completion routine will always be called.\r\n            //\r\n            status = STATUS_PENDING;\r\n            goto __Exit_DsmpPhase1ProcessPathFailingALUA;\r\n        }\r\n    } else {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock));\r\n\r\n        failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                                            context->CompletionContext->DeviceInfo->Group,\r\n                                                            context->CompletionContext->DeviceInfo);\r\n\r\n        if (failDevInfoListEntry) {\r\n\r\n            DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                           context->CompletionContext->DeviceInfo->Group,\r\n                                           failDevInfoListEntry);\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql);\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpPhase1ProcessPathFailingALUA (DevInfo %p): NTStatus 0%x, ScsiStatus 0x%x.\\n\",\r\n                    deviceInfo,\r\n                    status,\r\n                    scsiStatus));\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // An explicit transition may cause changes to some other TPGs.\r\n        // So we need to query for the states of all the TPGs and update\r\n        // our internal list and its elements.\r\n        //\r\n\r\n        //\r\n        // Take care of worst case scenario, which is:\r\n        // 1. 4-byte header (for allocation length)\r\n        // 2. 32 8-byte descriptors (for TPGs)\r\n        // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG)\r\n        //\r\n        targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                     (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                                                       DSM_MAX_PATHS * sizeof(ULONG)));\r\n\r\n        targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                targetPortGroupsInfoLength,\r\n                                                DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n        if (targetPortGroupsInfo) {\r\n\r\n            if (STATUS_PENDING == DsmpReportTargetPortGroupsAsync(deviceInfo,\r\n                                                                  DsmpPhase2ProcessPathFailingALUA,\r\n                                                                  Context,\r\n                                                                  targetPortGroupsInfoLength,\r\n                                                                  targetPortGroupsInfo)) {\r\n\r\n                releaseCompletionContextResources = FALSE;\r\n\r\n            } else {\r\n\r\n                DsmpFreePool(targetPortGroupsInfo);\r\n            }\r\n        } else {\r\n\r\n            irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock));\r\n\r\n            failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                                                context->CompletionContext->DeviceInfo->Group,\r\n                                                                context->CompletionContext->DeviceInfo);\r\n\r\n            if (failDevInfoListEntry) {\r\n\r\n                DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                               context->CompletionContext->DeviceInfo->Group,\r\n                                               failDevInfoListEntry);\r\n            }\r\n\r\n            ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql);\r\n        }\r\n    }\r\n\r\n    //\r\n    // Free the allocations.\r\n    //\r\n    IoFreeMdl(Irp->MdlAddress);\r\n    Irp->MdlAddress = NULL;\r\n\r\n    DsmpFreePool(Irp->UserBuffer);\r\n\r\n    IoFreeIrp(Irp);\r\n    Irp = (PIRP) NULL;\r\n\r\n    if (releaseCompletionContextResources) {\r\n\r\n        //\r\n        // Release our hold on the device info so that it can be removed.\r\n        //\r\n        InterlockedDecrement(&context->CompletionContext->DeviceInfo->BlockRemove);\r\n\r\n        ExFreeToNPagedLookasideList(&(context->CompletionContext->DsmContext)->CompletionContextList, context->CompletionContext);\r\n        DsmpFreePool(context->Srb);\r\n        DsmpFreePool(context->SenseInfoBuffer);\r\n#pragma warning(suppress:6001) // DevDiv 818965\r\n        DsmpFreePool(context);\r\n    }\r\n\r\n__Exit_DsmpPhase1ProcessPathFailingALUA:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpPhase1ProcessPathFailingALUA (DevInfo %p): Exiting function.\\n\",\r\n                deviceInfo));\r\n\r\n    return STATUS_MORE_PROCESSING_REQUIRED;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpRemoveFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY FailPathDevInfoEntry\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine removes the entry pointed to from the passed in Group's list.\r\n\r\n    NOTE: Calling function should be holding the spin lock.\r\n\r\nArguments:\r\n\r\n    Context is the DSM's context info.\r\n\r\n    Group is the group entry representing the device.\r\n\r\n    FailingPathDevInfoEntry is the entry that needs to be removed.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if successful, else appropriate NT error code.\r\n\r\n--*/\r\n{\r\n    PLIST_ENTRY entry = &FailPathDevInfoEntry->ListEntry;\r\n    PDSM_DEVICE_INFO deviceInfo = FailPathDevInfoEntry->FailingDeviceInfo;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpRemoveFailPathDevInfoEntry (DevInfo %p): Entering function.\\n\",\r\n                deviceInfo));\r\n\r\n    RemoveEntryList(entry);\r\n    DsmpFreePool(FailPathDevInfoEntry);\r\n    InterlockedDecrement((LONG volatile*)&Group->NumberFailingDevInfos);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpRemoveFailPathDevInfoEntry (DevInfo %p): Exiting function with status %x.\\n\",\r\n                deviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPhase2ProcessPathFailingALUA(\r\n    IN PDEVICE_OBJECT DeviceObject,\r\n    IN PIRP Irp,\r\n    IN PVOID Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the completion routine that is called when the RTPG is sent down by\r\n    DsmpPhase1ProcessPathFailingALUA.\r\n\r\n    The caller SHOULD NOT acquire the DSM Context lock before calling this routine.\r\n\r\nArguements:\r\n\r\n    DeviceObject is the target device object to which Irp was sent\r\n\r\n    Irp is the scsi pass through request for RTPG\r\n\r\n    Context is the completion context.\r\n\r\nReturn Value:\r\n\r\n    Status\r\n\r\n--*/\r\n{\r\n    PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);\r\n    PDSM_TPG_COMPLETION_CONTEXT context = (PDSM_TPG_COMPLETION_CONTEXT)Context;\r\n    PSCSI_REQUEST_BLOCK srb = context->Srb;\r\n    PVOID senseData = context->SenseInfoBuffer;\r\n    UCHAR senseDataLength = context->SenseInfoBufferLength;\r\n    NTSTATUS status = Irp->IoStatus.Status;\r\n    PUCHAR header;\r\n    ULONG returnedDataLength = 0;\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength = 0;\r\n    PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)(context->CompletionContext->RequestUnique1);\r\n    BOOLEAN decrementRTPGcount = (BOOLEAN)(context->CompletionContext->RequestUnique2);\r\n    KIRQL irql;\r\n    ULONG index;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL;\r\n    PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failDevInfoListEntry = NULL;\r\n    UCHAR scsiStatus = SrbGetScsiStatus(srb);\r\n\r\n    UNREFERENCED_PARAMETER(DeviceObject);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Entering function.\\n\",\r\n                deviceInfo));\r\n\r\n#if DBG\r\n    KeQuerySystemTime(&(context->CompletionContext)->TickCount);\r\n#endif\r\n\r\n    if ((status == STATUS_BUFFER_OVERFLOW) ||\r\n        (NT_SUCCESS(status) &&\r\n        (scsiStatus == SCSISTAT_GOOD))) {\r\n\r\n        header = (PUCHAR)((PUCHAR)SrbGetDataBuffer(srb));\r\n        GetUlongFrom4ByteArray(header, returnedDataLength);\r\n\r\n        status = STATUS_SUCCESS;\r\n        if (returnedDataLength > SrbGetDataTransferLength(srb)) {\r\n\r\n            status = STATUS_BUFFER_OVERFLOW;\r\n        }\r\n    }\r\n\r\n    if ((scsiStatus == SCSISTAT_GOOD) &&\r\n        (NT_SUCCESS(status))) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): RTPG using path %p succeeded.\\n\",\r\n                    deviceInfo,\r\n                    deviceInfo->FailGroup->PathId));\r\n\r\n        header = (PUCHAR)((PUCHAR)SrbGetDataBuffer(srb));\r\n        GetUlongFrom4ByteArray(header, returnedDataLength);\r\n\r\n        //\r\n        // Allocate a buffer to hold the TPG info.\r\n        //\r\n        targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength,\r\n                                                DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n        if (targetPortGroupsInfo) {\r\n\r\n            targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength;\r\n\r\n            //\r\n            // Copy it over.\r\n            //\r\n            RtlCopyMemory(targetPortGroupsInfo,\r\n                          header,\r\n                          targetPortGroupsInfoLength);\r\n\r\n        } else {\r\n\r\n            irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock));\r\n\r\n            failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                                                context->CompletionContext->DeviceInfo->Group,\r\n                                                                context->CompletionContext->DeviceInfo);\r\n\r\n            if (failDevInfoListEntry) {\r\n\r\n                DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                               context->CompletionContext->DeviceInfo->Group,\r\n                                               failDevInfoListEntry);\r\n            }\r\n\r\n            ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql);\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Failed to allocate mem for TPG.\\n\",\r\n                        deviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n\r\n    } else if (NT_SUCCESS(status) &&\r\n               scsiStatus == SCSISTAT_CHECK_CONDITION &&\r\n               DsmpShouldRetryTPGRequest(senseData, senseDataLength)) {\r\n\r\n        if ((context->NumberRetries)--) {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Retrying check condition using path %p. Retries remaining %u.\\n\",\r\n                        deviceInfo,\r\n                        deviceInfo->FailGroup->PathId,\r\n                        context->NumberRetries));\r\n\r\n            //\r\n            // Retry the request\r\n            //\r\n\r\n            NT_ASSERT(SrbGetDataBuffer(srb) == MmGetMdlVirtualAddress(Irp->MdlAddress));\r\n\r\n            //\r\n            // Reset byte count of transfer in SRB Extension to true length.\r\n            //\r\n            SrbSetDataTransferLength(srb, targetPortGroupsInfoLength);\r\n\r\n            //\r\n            // Zero SRB statuses.\r\n            //\r\n            srb->SrbStatus = 0;\r\n            SrbSetScsiStatus(srb, 0);\r\n\r\n            nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;\r\n            nextIrpStack->MinorFunction = IRP_MN_SCSI_CLASS;\r\n\r\n            //\r\n            // Save SRB address in next stack for port driver.\r\n            //\r\n            nextIrpStack->Parameters.Scsi.Srb = srb;\r\n            IoSetCompletionRoutine(Irp, DsmpPhase2ProcessPathFailingALUA, Context, TRUE, TRUE, TRUE);\r\n\r\n            IoMarkIrpPending(Irp);\r\n\r\n            //\r\n            // Send the IRP asynchronously\r\n            //\r\n            DsmSendRequestEx(context->CompletionContext->DsmContext->MPIOContext,\r\n                             deviceInfo->TargetObject,\r\n                             Irp,\r\n                             deviceInfo,\r\n                             DSM_CALL_COMPLETION_ON_MPIO_ERROR);\r\n\r\n            //\r\n            // We know that the completion routine will always be called.\r\n            //\r\n            status = STATUS_PENDING;\r\n            goto __Exit_DsmpPhase2ProcessPathFailingALUA;\r\n        }\r\n    } else {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock));\r\n\r\n        failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                                            context->CompletionContext->DeviceInfo->Group,\r\n                                                            context->CompletionContext->DeviceInfo);\r\n\r\n        if (failDevInfoListEntry) {\r\n\r\n            DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                           context->CompletionContext->DeviceInfo->Group,\r\n                                           failDevInfoListEntry);\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql);\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): NTStatus 0%x, ScsiStatus 0x%x.\\n\",\r\n                    deviceInfo,\r\n                    status,\r\n                    SrbGetScsiStatus(srb)));\r\n\r\n        // Failed to get TPG Info.\r\n        // Here it is possible status is success, but scsiStatus is not.\r\n        // If so, set status to unsuccessful.\r\n\r\n        if (NT_SUCCESS(status)) {\r\n            status = STATUS_UNSUCCESSFUL;\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock));\r\n\r\n        //\r\n        // Parse the TPG information and update the device path states\r\n        //\r\n        status = DsmpParseTargetPortGroupsInformation(context->CompletionContext->DsmContext,\r\n                                                      deviceInfo->Group,\r\n                                                      targetPortGroupsInfo,\r\n                                                      targetPortGroupsInfoLength);\r\n\r\n        for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n            targetPortGroup = deviceInfo->Group->TargetPortGroupList[index];\r\n\r\n            if (targetPortGroup) {\r\n\r\n                DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState);\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            PDSM_DEVICE_INFO tempDevice = NULL;\r\n\r\n            //\r\n            // Update all the devInfo states. If the device is AO but\r\n            // not this device, make it fake AU.\r\n            // If device not in AO, make sure that it matches the TPG\r\n            // state.\r\n            // Ensure that:\r\n            // 1. All devices match their ALUA state.\r\n            // 2. For RRWS, if a device's desired state is non-A/O, but ALUA state is A/O, mask it.\r\n            // 3. For FOO there must be only one A/O device. Preferably the preferred path.\r\n            //\r\n            for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n                devInfo = group->DeviceList[index];\r\n\r\n                if (devInfo) {\r\n\r\n                    if (devInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                        //\r\n                        // In implicit transitions, there is no guarantee that\r\n                        // the TPG of chosen \"deviceInfo\" is in A/O state. So\r\n                        // to play it safe, we hang on to the very first devInfo\r\n                        // whose TPG is in A/O state.\r\n                        //\r\n                        if (!tempDevice &&\r\n                            !DsmpIsDeviceFailedState(devInfo->State)) {\r\n\r\n                            devInfo->PreviousState = devInfo->State;\r\n                            devInfo->State = devInfo->ALUAState;\r\n\r\n                            tempDevice = devInfo;\r\n                        }\r\n\r\n                        if (devInfo != deviceInfo) {\r\n\r\n                            if (!DsmpIsDeviceFailedState(devInfo->State)) {\r\n\r\n                                //\r\n                                // For FOO, only one path can be in A/O.\r\n                                // For RRWS, mask an A/O path if that isn't the desired state.\r\n                                //\r\n                                if ((group->LoadBalanceType == DSM_LB_FAILOVER) ||\r\n                                    (group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET &&\r\n                                     devInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                     devInfo->DesiredState != DSM_DEV_UNDETERMINED)) {\r\n\r\n                                    //\r\n                                    // For implicit transitions, we may have saved off an A/O path.\r\n                                    // Don't undo that.\r\n                                    //\r\n                                    if (tempDevice != devInfo) {\r\n\r\n                                        devInfo->PreviousState = devInfo->State;\r\n                                        devInfo->State = DSM_DEV_ACTIVE_UNOPTIMIZED;\r\n                                    }\r\n\r\n                                } else {\r\n\r\n                                    devInfo->PreviousState = devInfo->State;\r\n                                    devInfo->State = devInfo->ALUAState;\r\n                                }\r\n                            }\r\n                        } else {\r\n\r\n                            devInfo->PreviousState = devInfo->State;\r\n\r\n                            //\r\n                            // For FOO, only one path can be in A/O state.\r\n                            // The TPG of the selected \"deviceInfo\" is in A/O, so this\r\n                            // can now very well be made the candidate. However, since\r\n                            // it is possible that we saved off another candidate, we\r\n                            // now need to replace that with this.\r\n                            //\r\n                            if (!DsmpIsDeviceFailedState(devInfo->State) &&\r\n                                devInfo->Group->LoadBalanceType == DSM_LB_FAILOVER &&\r\n                                tempDevice) {\r\n\r\n                                tempDevice->State = DSM_DEV_ACTIVE_UNOPTIMIZED;\r\n                            }\r\n\r\n                            devInfo->State = devInfo->ALUAState;\r\n\r\n                            tempDevice = devInfo;\r\n                        }\r\n                    } else {\r\n\r\n                        if (!DsmpIsDeviceFailedState(devInfo->State)) {\r\n\r\n                            devInfo->PreviousState = devInfo->State;\r\n                            devInfo->State = devInfo->ALUAState;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        failDevInfoListEntry = DsmpFindFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                                            context->CompletionContext->DeviceInfo->Group,\r\n                                                            context->CompletionContext->DeviceInfo);\r\n\r\n        if (failDevInfoListEntry) {\r\n\r\n            DsmpRemoveFailPathDevInfoEntry(context->CompletionContext->DsmContext,\r\n                                           context->CompletionContext->DeviceInfo->Group,\r\n                                           failDevInfoListEntry);\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(context->CompletionContext->DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n\r\n    //\r\n    // Resume IO if we throttled requests.\r\n    //\r\n    if (InterlockedCompareExchange((LONG volatile*)&group->Throttled, 0, 1)) {\r\n\r\n        NTSTATUS resumeStatus = STATUS_UNSUCCESSFUL;\r\n\r\n        DsmNotification(((PDSM_CONTEXT)deviceInfo->DsmContext)->MPIOContext,\r\n                        ResumeIO_V2,\r\n                        deviceInfo,\r\n                        TRUE,\r\n                        &resumeStatus,\r\n                        0);\r\n\r\n        if (!NT_SUCCESS(resumeStatus)) {\r\n\r\n            //\r\n            // Resume can fail when\r\n            // 1. The MPDisk is being removed (or)\r\n            // 2. The MPDisk is any other state other than throttled (or)\r\n            // 3. There is a problem dispatching throttled requests.\r\n            //\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmpPhase2ProcessPathFailingALUA (DevObj %p): Resume IO failed.\\n\",\r\n                        DeviceObject));\r\n        }\r\n\r\n    }\r\n\r\n    if (decrementRTPGcount) {\r\n\r\n        //\r\n        // Resetting InFlightRTPG after resume so that we don't get into situation where\r\n        // new DsmpSetPathForIoRetryALUA caller thread finds that InFlightRTPG is not set but Throttled is set\r\n        //\r\n        ULONG count = InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 1);\r\n\r\n        //\r\n        // If decrementRTPGCount flag is set, there must be atleast one RTPG in flight.\r\n        //\r\n        NT_ASSERT(count);\r\n\r\n        UNREFERENCED_PARAMETER(count);\r\n\r\n    }\r\n\r\n    //\r\n    // Free the allocations.\r\n    //\r\n    if (targetPortGroupsInfo) {\r\n\r\n        DsmpFreePool(targetPortGroupsInfo);\r\n    }\r\n\r\n    //\r\n    // Release our hold on the device info so that it can be removed.\r\n    //\r\n    InterlockedDecrement(&context->CompletionContext->DeviceInfo->BlockRemove);\r\n\r\n    IoFreeMdl(Irp->MdlAddress);\r\n    Irp->MdlAddress = NULL;\r\n\r\n    DsmpFreePool(Irp->UserBuffer);\r\n\r\n    IoFreeIrp(Irp);\r\n    Irp = (PIRP) NULL;\r\n\r\n    ExFreeToNPagedLookasideList(&(context->CompletionContext->DsmContext)->CompletionContextList, context->CompletionContext);\r\n    DsmpFreePool(srb);\r\n    DsmpFreePool(senseData);\r\n#pragma warning(suppress:6001) // DevDiv 818965\r\n    DsmpFreePool(context);\r\n\r\n__Exit_DsmpPhase2ProcessPathFailingALUA:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpPhase2ProcessPathFailingALUA (DevInfo %p): Exiting function.\\n\",\r\n                deviceInfo));\r\n\r\n    return STATUS_MORE_PROCESSING_REQUIRED;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPersistentReserveOut(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will handle determine which devices to send the request to based\r\n    on the service action of the PR-out command.\r\n    On REGISTER/REGISTER_AND_IGNORE_EXISTING, it will send the command down all\r\n    paths. If any path succeeds, the PR key will be stored. If failure down any\r\n    path, return failure.\r\n    On REGISTER/REGISTER_AND_IGNORE_EXISTING with key == 0 (ie. UNREGISTER),\r\n    the request is sent down every path. Failure is returned if request fails down\r\n    any path (but error is ignored if path happens to be one where prior\r\n    REGISTER/REGISTER_AND_IGNORE_EXISTING had failed in the first place). The\r\n    stored PR key is cleared irrespective of success/failure being returned.\r\n    On RESERVE/RELEASE, the command is sent down one path. If it fails, another\r\n    path is tried. Failure is returned only if none succeed.\r\n    On CLEAR, command is sent down one path. If it fails, another path is tried.\r\n    Failure is returned only if none succeed. The stored PR key is cleared\r\n    irrespective of success/failure being returned.\r\n    On PREEMPT, command is sent down one path. If it fails, another path is\r\n    tried. Failure is returned only if none succeed.\r\n    On PREEMPT_AND_ABORT, command is sent down one path. Failed request is not\r\n    retried.\r\n\r\n    NOTE: If a path shows up later, REGISTER_AND_IGNORE_EXISTING request is\r\n    built by the IsPathActive routine using the saved PR key and sent down new path.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDISK.\r\n    Irp - Irp containing SRB.\r\n    Srb - Scsi request block\r\n    Event - The event to\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PDSM_DEVICE_INFO servicingDeviceInfo = NULL;\r\n    PDSM_GROUP_ENTRY group;\r\n    LONG i;\r\n    ULONG count;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n    PDSM_COMPLETION_CONTEXT completionContext;\r\n    PCDB cdb = SrbGetCdb(Srb);\r\n    UCHAR serviceAction;\r\n    NTSTATUS returnStatus = STATUS_SUCCESS;\r\n    BOOLEAN sendDownAll = FALSE;\r\n    BOOLEAN savePRKeyIfAnySucceed = FALSE;\r\n    BOOLEAN retryOnAnother = FALSE;\r\n    BOOLEAN passOnlyIfAllSucceed = FALSE;\r\n    BOOLEAN ignoreIfPreviousFailed = FALSE;\r\n    BOOLEAN clearPRKey = FALSE;\r\n    KEVENT event;\r\n    PPRO_PARAMETER_LIST prOutParam = Irp->AssociatedIrp.SystemBuffer;\r\n    PUCHAR index = NULL;\r\n    UCHAR prKey[8] = {0};\r\n    PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL;\r\n    PIO_STACK_LOCATION irpStack;\r\n    PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    BOOLEAN statusUpdated = FALSE;\r\n    ULONGLONG currentTickCount;\r\n    ULONGLONG finalTickCount;\r\n    ULONG tickLength = KeQueryTimeIncrement();\r\n    PVOID senseInfoBuffer = NULL;\r\n    UCHAR senseInfoBufferLength = 0;\r\n    BOOLEAN srbCopySucceeded = FALSE;\r\n    UCHAR prType;\r\n    UCHAR prScope;\r\n    ULONGLONG saKey;\r\n    ULONGLONG resKey;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    UNREFERENCED_PARAMETER(Event);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveOut (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // Cache away a copy of the SRB\r\n    //\r\n    srbCopy = SrbAllocateCopy(Srb, NonPagedPoolNx, DSM_TAG_SCSI_REQUEST_BLOCK);\r\n    if (srbCopy == NULL) {\r\n        returnStatus = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpPersistentReserveOut;\r\n    }\r\n\r\n    deviceInfo = DsmIds->IdList[0];\r\n    group = deviceInfo->Group;\r\n\r\n    prType = cdb->PERSISTENT_RESERVE_OUT.Type;\r\n    prScope = cdb->PERSISTENT_RESERVE_OUT.Scope;\r\n    serviceAction = cdb->PERSISTENT_RESERVE_OUT.ServiceAction;\r\n\r\n    NT_ASSERT(serviceAction >= RESERVATION_ACTION_REGISTER && serviceAction <= RESERVATION_ACTION_REGISTER_IGNORE_EXISTING);\r\n\r\n    index = prOutParam->ServiceActionReservationKey;\r\n    RtlCopyMemory(&prKey, index, 8);\r\n    REVERSE_BYTES_QUAD(&saKey, &prOutParam->ServiceActionReservationKey);\r\n\r\n    REVERSE_BYTES_QUAD(&resKey, &prOutParam->ReservationKey);\r\n\r\n    switch (serviceAction) {\r\n        case RESERVATION_ACTION_REGISTER:\r\n        case RESERVATION_ACTION_REGISTER_IGNORE_EXISTING: {\r\n\r\n            //\r\n            // The command must be sent down all paths.\r\n            //\r\n            sendDownAll = TRUE;\r\n\r\n            //\r\n            // Return failure if it fails down even one of the paths.\r\n            //\r\n            passOnlyIfAllSucceed = TRUE;\r\n\r\n            if (DsmpIsPersistentReservationKeyZeroKey(ARRAY_SIZE(prKey), prKey)) {\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): NULL PR key, service action %u\\n\",\r\n                            DsmIds,\r\n                            serviceAction));\r\n\r\n                //\r\n                // If unregister fails, don't report it back as error if the\r\n                // previous register/register_and_ignore_existing down that\r\n                // path had failed too.\r\n                //\r\n                ignoreIfPreviousFailed = TRUE;\r\n\r\n                //\r\n                // Clear the group PR key irrespective of the status that is\r\n                // going to be returned to clusdisk.\r\n                //\r\n                clearPRKey = TRUE;\r\n\r\n            } else {\r\n\r\n                //\r\n                // If register/register_and_ignore_existing succeed down any of\r\n                // the paths, save off the PR key for the group entry.\r\n                //\r\n                savePRKeyIfAnySucceed = TRUE;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case RESERVATION_ACTION_RESERVE:\r\n        case RESERVATION_ACTION_RELEASE:\r\n        case RESERVATION_ACTION_PREEMPT:\r\n        case RESERVATION_ACTION_PREEMPT_ABORT:\r\n        case RESERVATION_ACTION_CLEAR: {\r\n\r\n            if (serviceAction != RESERVATION_ACTION_PREEMPT_ABORT) {\r\n\r\n                //\r\n                // Apart from preempt_abort, all the others must be retried\r\n                // (down another path) if they fail down the chosen path.\r\n                //\r\n                retryOnAnother = TRUE;\r\n            }\r\n\r\n            if (serviceAction == RESERVATION_ACTION_CLEAR) {\r\n\r\n                //\r\n                // Clear the stored PR key for the group entry irrespective of\r\n                // the status that is going to be returned back.\r\n                //\r\n                clearPRKey = TRUE;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            returnStatus = STATUS_INVALID_PARAMETER;\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpPersistentReserveOut (DsmIds %p): Invalid service action %u.\\n\",\r\n                        DsmIds,\r\n                        serviceAction));\r\n\r\n            goto __Exit_DsmpPersistentReserveOut;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveOut (DsmIds %p): Srb %p, Service Action %u, Type %u, Scope %u, \\\r\n                \\n\\t\\t\\t\\tservice action reservation key %I64x, reservation key %I64x.\\n\",\r\n                DsmIds,\r\n                Srb,\r\n                serviceAction,\r\n                prType,\r\n                prScope,\r\n                saKey,\r\n                resKey));\r\n\r\n    //\r\n    // Allocate a context for the completion routine.\r\n    //\r\n    completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList);\r\n    if (!completionContext) {\r\n\r\n        returnStatus = STATUS_INSUFFICIENT_RESOURCES;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Failed to allocate completion context.\\n\",\r\n                    DsmIds,\r\n                    serviceAction));\r\n\r\n        goto __Exit_DsmpPersistentReserveOut;\r\n    }\r\n\r\n    KeInitializeEvent(&event, NotificationEvent, FALSE);\r\n\r\n    //\r\n    // Indicate the target for this request.\r\n    //\r\n    completionContext->DsmContext = DsmContext;\r\n    completionContext->RequestUnique1 = (PVOID)&event;\r\n    completionContext->RequestUnique2 = cdb->PERSISTENT_RESERVE_OUT.OperationCode;\r\n\r\n    count = group->NumberDevices;\r\n\r\n    for (i = count - 1; i >= 0; i--) {\r\n\r\n        //\r\n        // A PR command may fail with a \"retry-able\" UA when reservation is\r\n        // released or preempted (on every I_T_L nexus except the one on which\r\n        // it was released/preempted). In such a case we should retry the PR\r\n        // command on the same path.\r\n        //\r\n        KeQueryTickCount((PLARGE_INTEGER)&currentTickCount);\r\n        finalTickCount = currentTickCount + (DSM_SECONDS_TO_TICKS(group->MaxPRRetryTimeDuringStateTransition) / tickLength);\r\n\r\n        if (!sendDownAll && !retryOnAnother) {\r\n\r\n            //\r\n            // If the request doesn't need to be retried (down another path) on\r\n            // failure, better choose the path that has maximum chances of\r\n            // success.\r\n            //\r\n            deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                                   DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]),\r\n                                                   SpecialHandlingFlag);\r\n\r\n            if (!deviceInfo) {\r\n\r\n                returnStatus = STATUS_UNSUCCESSFUL;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - No active/alternative path for device %p.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            group));\r\n\r\n                break;\r\n            }\r\n\r\n        } else {\r\n\r\n            deviceInfo = group->DeviceList[i];\r\n\r\n            //\r\n            // Ignore \"bad\" paths for now. If the path becomes \"good\" again,\r\n            // IsPathActive() will send down the register.\r\n            // Also, don't consider newly arrived paths for which the group has\r\n            // a reservation but register has not yet been sent down. This rule\r\n            // applies only to requests that are not Register.\r\n            //\r\n            if ((DsmpIsDeviceFailedState(deviceInfo->State) || !DsmpIsDeviceInitialized(deviceInfo)) ||\r\n                (!DsmpIsDeviceUsablePR(deviceInfo) && !sendDownAll)) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): Ignoring bad instance - state %x, init %x, key reg %x (key valid %x).\\n\",\r\n                            DsmIds,\r\n                            deviceInfo->State,\r\n                            deviceInfo->Initialized,\r\n                            deviceInfo->PRKeyRegistered,\r\n                            deviceInfo->Group->PRKeyValid));\r\n\r\n                deviceInfo = NULL;\r\n            }\r\n\r\n        }\r\n\r\n        if (!deviceInfo) {\r\n\r\n            //\r\n            // Maybe a remove came through and caused a collapse of the device\r\n            // list, thus making this entry empty.\r\n            //\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Couldn't find path for device %p.\\n\",\r\n                        DsmIds,\r\n                        serviceAction,\r\n                        group));\r\n\r\n            continue;\r\n        }\r\n\r\n__DsmpPersistentReserveOut_RetryRequest:\r\n\r\n        IoMarkIrpPending(Irp);\r\n\r\n        completionContext->DeviceInfo = deviceInfo;\r\n\r\n        //\r\n        // Set-up a completion routine.\r\n        //\r\n        IoSetCompletionRoutine(Irp,\r\n                               DsmpPersistentReserveCompletion,\r\n                               completionContext,\r\n                               TRUE,\r\n                               TRUE,\r\n                               TRUE);\r\n\r\n        //\r\n        // Always send the original request down a new path\r\n        //\r\n        irpStack = IoGetNextIrpStackLocation(Irp);\r\n        srbCopySucceeded = SrbCopySrb(Srb, SrbGetSrbLength(Srb), srbCopy);\r\n        NT_ASSERT(srbCopySucceeded == TRUE);\r\n        irpStack->Parameters.Scsi.Srb = Srb;\r\n\r\n        //\r\n        // Clear the sense buffer if it exists\r\n        //\r\n        senseInfoBuffer = SrbGetSenseInfoBuffer(Srb);\r\n        senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);\r\n        if (senseInfoBuffer) {\r\n            RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength);\r\n        }\r\n\r\n        servicingDeviceInfo = deviceInfo;\r\n\r\n        //\r\n        // Issue the request and wait.\r\n        //\r\n        status = DsmSendRequest(DsmContext->MPIOContext,\r\n                                deviceInfo->TargetObject,\r\n                                Irp,\r\n                                deviceInfo);\r\n\r\n        if (status == STATUS_PENDING) {\r\n\r\n            KeWaitForSingleObject(&event,\r\n                                  Executive,\r\n                                  KernelMode,\r\n                                  FALSE,\r\n                                  NULL);\r\n\r\n            status = Irp->IoStatus.Status;\r\n        }\r\n\r\n        if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down successfully on %p.\\n\",\r\n                        DsmIds,\r\n                        serviceAction,\r\n                        deviceInfo->FailGroup->PathId));\r\n\r\n            if (!passOnlyIfAllSucceed) {\r\n\r\n                //\r\n                // Success down any one path means success\r\n                //\r\n                returnStatus = status;\r\n            }\r\n\r\n            if (savePRKeyIfAnySucceed) {\r\n\r\n                RtlCopyMemory(&group->PersistentReservationRegisteredKey, &prKey, 8);\r\n\r\n                group->PRServiceAction = serviceAction;\r\n                group->PRType = prType;\r\n                group->PRScope = prScope;\r\n                group->PRKeyValid = TRUE;\r\n                deviceInfo->PRKeyRegistered = TRUE;\r\n            }\r\n\r\n            if (!sendDownAll) {\r\n\r\n                //\r\n                // Need for retrying on another path only necessary in the case\r\n                // of request failing down the chosen path. Since the request\r\n                // succeeded down this path, we are done.\r\n                //\r\n                break;\r\n            }\r\n        } else {\r\n\r\n            BOOLEAN recordFailure;\r\n\r\n            //\r\n            // Check to see if the request failed because of a \"transient error\",\r\n            // like reservations released for example. If so, this is NOT an actual\r\n            // error and the request must be retried. Multiple retries may be required\r\n            // if for example the UA indicates that the TPGs are in transitioning state.\r\n            //\r\n            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&\r\n                Srb->SrbStatus & SRB_STATUS_ERROR &&\r\n                SrbGetScsiStatus(Srb) == SCSISTAT_CHECK_CONDITION) {\r\n\r\n                KeQueryTickCount((PLARGE_INTEGER)&currentTickCount);\r\n\r\n                senseInfoBuffer = SrbGetSenseInfoBuffer(Srb);\r\n                senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);\r\n\r\n                if (DsmpShouldRetryPersistentReserveCommand(senseInfoBuffer, senseInfoBufferLength) &&\r\n                    currentTickCount < finalTickCount) {\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_IOCTL,\r\n                                \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u returned UA with error %x. Retrying same path %p.\\n\",\r\n                                DsmIds,\r\n                                serviceAction,\r\n                                status,\r\n                                deviceInfo->FailGroup->PathId));\r\n\r\n                    KeResetEvent(&event);\r\n                    Irp->IoStatus.Status = 0;\r\n\r\n                    goto __DsmpPersistentReserveOut_RetryRequest;\r\n                }\r\n            }\r\n\r\n            //\r\n            // The return status is STATUS_SUCCESS by default. This means that if the\r\n            // request failed on the first path and was retried down every other path\r\n            // but fails down all of them, the return status is never updated.\r\n            // So cache the first failure status to cover the above scenario.\r\n            //\r\n            if (!statusUpdated) {\r\n\r\n                returnStatus = status;\r\n                statusUpdated = TRUE;\r\n            }\r\n\r\n            recordFailure = TRUE;\r\n            if (ignoreIfPreviousFailed && !deviceInfo->PRKeyRegistered) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Ignoring status %x for path %p.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            status,\r\n                            deviceInfo->FailGroup->PathId));\r\n\r\n                //\r\n                // Okay to ignore this failure if the previous failed.\r\n                //\r\n                recordFailure = FALSE;\r\n            }\r\n\r\n            if (passOnlyIfAllSucceed && recordFailure) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u - Saving status %x for return.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            status));\r\n\r\n                //\r\n                // Save the failure status to return back.\r\n                //\r\n                returnStatus = status;\r\n            }\r\n\r\n            //\r\n            // If the request is not to be sent down all paths, and also\r\n            // a retry (along a different path) on failure is not required,\r\n            // we're done - just return this failure.\r\n            //\r\n            if (!(sendDownAll || retryOnAnother)) {\r\n\r\n                returnStatus = status;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down %p failed with %x. Breaking out.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            deviceInfo->FailGroup->PathId,\r\n                            status));\r\n\r\n                break;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT %u sent down %p failed with %x. Sending down another path.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            deviceInfo->FailGroup->PathId,\r\n                            status));\r\n            }\r\n        }\r\n\r\n        //\r\n        // If we are here, it is either because the request needs to be sent down\r\n        // all paths, or because the request failed down the chosen path and needs\r\n        // to be retried down a new path.\r\n        //\r\n        KeResetEvent(&event);\r\n        Irp->IoStatus.Status = 0;\r\n    }\r\n\r\n    if (clearPRKey) {\r\n\r\n        for (i = 0; (ULONG)i < group->NumberDevices; i++) {\r\n\r\n            deviceInfo = group->DeviceList[i];\r\n\r\n            if (deviceInfo) {\r\n\r\n                deviceInfo->RegisterServiced = FALSE;\r\n                deviceInfo->PRKeyRegistered = FALSE;\r\n            }\r\n        }\r\n        group->PersistentReservationRegisteredKey[0] = group->PersistentReservationRegisteredKey[1] =\r\n        group->PersistentReservationRegisteredKey[2] = group->PersistentReservationRegisteredKey[3] =\r\n        group->PersistentReservationRegisteredKey[4] = group->PersistentReservationRegisteredKey[5] =\r\n        group->PersistentReservationRegisteredKey[6] = group->PersistentReservationRegisteredKey[7] = 0;\r\n\r\n        group->PRKeyValid = FALSE;\r\n        group->ReservationList = 0;\r\n    }\r\n\r\n    if (savePRKeyIfAnySucceed && group->PRKeyValid) {\r\n\r\n        ULONG ordinal;\r\n\r\n        for (i = 0; (ULONG)i < group->NumberDevices; i++) {\r\n\r\n            deviceInfo = group->DeviceList[i];\r\n\r\n            if (deviceInfo) {\r\n\r\n                deviceInfo->RegisterServiced = TRUE;\r\n                ordinal = (1 << i);\r\n                group->ReservationList |= ordinal;\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveOut (DsmIds %p): PR_OUT for %u completed with status %x.\\n\",\r\n                DsmIds,\r\n                serviceAction,\r\n                returnStatus));\r\n\r\n    ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n\r\n__Exit_DsmpPersistentReserveOut:\r\n\r\n    if (srbCopy != NULL) {\r\n        DsmpFreePool(srbCopy);\r\n    }\r\n\r\n    currentIrpStack->Parameters.Others.Argument3 = servicingDeviceInfo;\r\n    Irp->IoStatus.Status = returnStatus;\r\n    if ((!NT_SUCCESS(returnStatus)) &&\r\n        (SrbGetSrbStatus(Srb) == SRB_STATUS_SUCCESS)) {\r\n        SrbSetSrbStatus(Srb, DsmpNtStatusToSrbStatus(returnStatus));\r\n    }\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveOut (DsmIds %p): Exiting function returning IRP status %x.\\n\",\r\n                DsmIds,\r\n                returnStatus));\r\n\r\n    return returnStatus;\r\n}\r\n\r\n\r\n\r\nNTSTATUS\r\nDsmpPersistentReserveIn(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will handle determine which devices to send the request to based\r\n    on the service action of the PR-in command.\r\n    On READ KEYS, it will send down one path. In case of failure, other paths will\r\n    be tried until one succeeds. Failure is returned only if it fails down all paths.\r\n    On READ_RESERVATION/REPORT_CAPABILITIES, command is sent down one path. Failed\r\n    request is not retried.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context given to MPIO during initialization\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDISK.\r\n    Irp - Irp containing SRB.\r\n    Srb - Scsi request block\r\n    Event - The event to\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PDSM_DEVICE_INFO servicingDeviceInfo = NULL;\r\n    PDSM_GROUP_ENTRY group;\r\n    LONG i;\r\n    ULONG count;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n    PDSM_COMPLETION_CONTEXT completionContext;\r\n    PCDB cdb = SrbGetCdb(Srb);\r\n    UCHAR serviceAction;\r\n    BOOLEAN retryOnAnother = FALSE;\r\n    KEVENT event;\r\n    PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL;\r\n    PIO_STACK_LOCATION irpStack;\r\n    PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    ULONGLONG currentTickCount;\r\n    ULONGLONG finalTickCount;\r\n    ULONG tickLength = KeQueryTimeIncrement();\r\n    PVOID senseInfoBuffer = NULL;\r\n    UCHAR senseInfoBufferLength = 0;\r\n    BOOLEAN srbCopySucceeded = FALSE;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    UNREFERENCED_PARAMETER(Event);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveIn (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // Cache away a copy of the SRB\r\n    //\r\n    srbCopy = SrbAllocateCopy(Srb, NonPagedPoolNx, DSM_TAG_SCSI_REQUEST_BLOCK);\r\n    if (srbCopy == NULL) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpPersistentReserveIn;\r\n    }\r\n\r\n    deviceInfo = DsmIds->IdList[0];\r\n    group = deviceInfo->Group;\r\n\r\n    serviceAction = cdb->PERSISTENT_RESERVE_IN.ServiceAction;\r\n\r\n    switch (serviceAction) {\r\n        case RESERVATION_ACTION_READ_RESERVATIONS:\r\n        case RESERVATION_ACTION_READ_KEYS: {\r\n\r\n            //\r\n            // If there is a failure on the chosen path, retry on another path.\r\n            //\r\n            retryOnAnother = TRUE;\r\n            break;\r\n        }\r\n\r\n        case SPC3_RESERVATION_ACTION_REPORT_CAPABILITIES: {\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            NT_ASSERT(FALSE);\r\n            status = STATUS_INVALID_PARAMETER;\r\n            goto __Exit_DsmpPersistentReserveIn;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveIn (DsmIds %p): Srb %p. Service Action %u.\\n\",\r\n                DsmIds,\r\n                Srb,\r\n                serviceAction));\r\n\r\n    //\r\n    // Allocate a context for the completion routine.\r\n    //\r\n    completionContext = ExAllocateFromNPagedLookasideList(&DsmContext->CompletionContextList);\r\n    if (!completionContext) {\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - Failed to allocate completion context.\\n\",\r\n                    DsmIds,\r\n                    serviceAction));\r\n\r\n        goto __Exit_DsmpPersistentReserveIn;\r\n    }\r\n\r\n    KeInitializeEvent(&event, NotificationEvent, FALSE);\r\n\r\n    //\r\n    // Indicate the target for this request.\r\n    //\r\n    completionContext->DsmContext = DsmContext;\r\n    completionContext->RequestUnique1 = (PVOID)&event;\r\n    completionContext->RequestUnique2 = cdb->PERSISTENT_RESERVE_IN.OperationCode;\r\n\r\n    count = group->NumberDevices;\r\n\r\n    for (i = count - 1; i >= 0; i--) {\r\n\r\n        //\r\n        // A PR command may fail with a \"retry-able\" UA when reservation is\r\n        // released or preempted (on every I_T_L nexus except the one on which\r\n        // it was released/preempted). In such a case we should retry the PR\r\n        // command on the same path.\r\n        //\r\n        KeQueryTickCount((PLARGE_INTEGER)&currentTickCount);\r\n        finalTickCount = currentTickCount + (DSM_SECONDS_TO_TICKS(group->MaxPRRetryTimeDuringStateTransition) / tickLength);\r\n\r\n        if (!retryOnAnother) {\r\n\r\n            //\r\n            // If the request doesn't need to be retried (down another path) on\r\n            // failure, better choose the path that has maximum chances of\r\n            // success.\r\n            //\r\n            deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                                   DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]),\r\n                                                   SpecialHandlingFlag);\r\n\r\n            if (!deviceInfo) {\r\n\r\n                status = STATUS_UNSUCCESSFUL;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - No active/alternative path for device %p.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            group));\r\n\r\n                break;\r\n            }\r\n\r\n        } else {\r\n\r\n            deviceInfo = group->DeviceList[i];\r\n\r\n            if (DsmpIsDeviceFailedState(deviceInfo->State) || !DsmpIsDeviceInitialized(deviceInfo)) {\r\n\r\n                //\r\n                // Ignore \"bad\" paths for now.\r\n                //\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveIn (DsmIds %p): Ignoring bad instance - state %x, init %x.\\n\",\r\n                            DsmIds,\r\n                            deviceInfo->State,\r\n                            deviceInfo->Initialized));\r\n\r\n                deviceInfo = NULL;\r\n            }\r\n        }\r\n\r\n        if (!deviceInfo) {\r\n\r\n            //\r\n            // Maybe a remove came through and caused a collapse of the device\r\n            // list, thus making this entry empty.\r\n            //\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpPersistentReserveIn (DsmIds %p): PR_IN %u - Couldn't find path for device %p.\\n\",\r\n                        DsmIds,\r\n                        serviceAction,\r\n                        group));\r\n\r\n            continue;\r\n        }\r\n\r\n__DsmpPersistentReserveIn_RetryRequest:\r\n\r\n        IoMarkIrpPending(Irp);\r\n\r\n        completionContext->DeviceInfo = deviceInfo;\r\n\r\n        //\r\n        // Set-up a completion routine.\r\n        //\r\n        IoSetCompletionRoutine(Irp,\r\n                               DsmpPersistentReserveCompletion,\r\n                               completionContext,\r\n                               TRUE,\r\n                               TRUE,\r\n                               TRUE);\r\n\r\n        //\r\n        // Always send the original request down a new path\r\n        //\r\n        irpStack = IoGetNextIrpStackLocation(Irp);\r\n        srbCopySucceeded = SrbCopySrb(Srb, SrbGetSrbLength(Srb), srbCopy);\r\n        NT_ASSERT(srbCopySucceeded == TRUE);\r\n        irpStack->Parameters.Scsi.Srb = Srb;\r\n\r\n        //\r\n        // Clear the sense buffer if it exists\r\n        //\r\n        senseInfoBuffer = SrbGetSenseInfoBuffer(Srb);\r\n        senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);\r\n        if (senseInfoBuffer) {\r\n            RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength);\r\n        }\r\n\r\n        servicingDeviceInfo = deviceInfo;\r\n\r\n        //\r\n        // Issue the request and wait.\r\n        //\r\n        status = DsmSendRequest(DsmContext->MPIOContext,\r\n                                deviceInfo->TargetObject,\r\n                                Irp,\r\n                                deviceInfo);\r\n\r\n        if (status == STATUS_PENDING) {\r\n\r\n            KeWaitForSingleObject(&event,\r\n                                  Executive,\r\n                                  KernelMode,\r\n                                  FALSE,\r\n                                  NULL);\r\n\r\n            status = Irp->IoStatus.Status;\r\n        }\r\n\r\n        if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u sent down successfully on %p.\\n\",\r\n                        DsmIds,\r\n                        serviceAction,\r\n                        deviceInfo->FailGroup->PathId));\r\n#if DBG\r\n            if (serviceAction == RESERVATION_ACTION_READ_KEYS) {\r\n\r\n                PPRI_REGISTRATION_LIST prInRegistrationList = Irp->AssociatedIrp.SystemBuffer;\r\n                ULONG numberOfKeys;\r\n                ULONG keyIndex;\r\n                ULONGLONG prKey;\r\n\r\n                REVERSE_BYTES(&numberOfKeys, &prInRegistrationList->AdditionalLength);\r\n                numberOfKeys /= 8;\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveIn (DsmIds %p): %u registrations keys present:\\n\",\r\n                            DsmIds,\r\n                            numberOfKeys));\r\n\r\n                for (keyIndex = 0; keyIndex < numberOfKeys; keyIndex++) {\r\n\r\n                    REVERSE_BYTES_QUAD(&prKey, &(prInRegistrationList->ReservationKeyList[keyIndex]));\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_IOCTL,\r\n                                \"DsmpPersistentReserveIn (DsmIds %p): Registration Key %u: %I64x\\n\",\r\n                                DsmIds,\r\n                                keyIndex,\r\n                                prKey));\r\n                }\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"\\n\"));\r\n\r\n            } else if (serviceAction == RESERVATION_ACTION_READ_RESERVATIONS) {\r\n\r\n                PPRI_RESERVATION_LIST prInReservationList = Irp->AssociatedIrp.SystemBuffer;\r\n                ULONG numberOfDescriptors;\r\n                PPRI_RESERVATION_DESCRIPTOR prInReservationDescriptor = prInReservationList->Reservations;\r\n                ULONGLONG prKey = 0;\r\n\r\n                REVERSE_BYTES(&numberOfDescriptors, &prInReservationList->AdditionalLength);\r\n                numberOfDescriptors /= sizeof(PRI_RESERVATION_DESCRIPTOR);\r\n                NT_ASSERT(numberOfDescriptors <= 1);\r\n\r\n                if (numberOfDescriptors == 1) {\r\n                    REVERSE_BYTES_QUAD(&prKey, &prInReservationDescriptor->ReservationKey);\r\n                }\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveIn (DsmIds %p): %u Reservation Key: %I64x\\n\",\r\n                            DsmIds,\r\n                            numberOfDescriptors,\r\n                            prKey));\r\n            }\r\n#endif\r\n            //\r\n            // Done.\r\n            //\r\n            break;\r\n\r\n        } else {\r\n\r\n            //\r\n            // Check to see if the request failed because of a \"transient error\",\r\n            // like reservations released for example. If so, this is NOT an actual\r\n            // error and the request must be retried. Multiple retries may be required\r\n            // if for example the UA indicates that the TPGs are in transitioning state.\r\n            //\r\n            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&\r\n                Srb->SrbStatus & SRB_STATUS_ERROR &&\r\n                SrbGetScsiStatus(Srb) == SCSISTAT_CHECK_CONDITION) {\r\n\r\n                KeQueryTickCount((PLARGE_INTEGER)&currentTickCount);\r\n\r\n                senseInfoBuffer = SrbGetSenseInfoBuffer(Srb);\r\n                senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);\r\n\r\n                if (group->PRKeyValid &&\r\n                    DsmpShouldRetryPersistentReserveCommand(senseInfoBuffer, senseInfoBufferLength) &&\r\n                    currentTickCount < finalTickCount) {\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_IOCTL,\r\n                                \"DsmpPersistentReserveIn (DsmIds %p): PR_IN %u returned UA with error %x. Retrying same path %p.\\n\",\r\n                                DsmIds,\r\n                                serviceAction,\r\n                                status,\r\n                                deviceInfo->FailGroup->PathId));\r\n\r\n                    KeResetEvent(&event);\r\n                    Irp->IoStatus.Status = 0;\r\n\r\n                    goto __DsmpPersistentReserveIn_RetryRequest;\r\n                }\r\n            }\r\n\r\n            //\r\n            // If a retry (along a different path) on failure is not required,\r\n            // we're done - just return this failure.\r\n            //\r\n            if (!retryOnAnother) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_IOCTL,\r\n                            \"DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u down %p failed with %x. Breaking out.\\n\",\r\n                            DsmIds,\r\n                            serviceAction,\r\n                            deviceInfo->FailGroup->PathId,\r\n                            status));\r\n\r\n                break;\r\n            }\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u down %p failed with %x. Sending down another path.\\n\",\r\n                    DsmIds,\r\n                    serviceAction,\r\n                    deviceInfo->FailGroup->PathId,\r\n                    status));\r\n\r\n        //\r\n        // If we are here, it is because the request failed down the chosen path\r\n        // and needs to be retried down a new path.\r\n        //\r\n        KeResetEvent(&event);\r\n        Irp->IoStatus.Status = 0;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveIn (DsmIds %p): PR_IN for %u completed with status %x.\\n\",\r\n                DsmIds,\r\n                serviceAction,\r\n                status));\r\n\r\n    ExFreeToNPagedLookasideList(&DsmContext->CompletionContextList, completionContext);\r\n\r\n__Exit_DsmpPersistentReserveIn:\r\n\r\n    if (srbCopy != NULL) {\r\n        DsmpFreePool(srbCopy);\r\n    }\r\n\r\n    currentIrpStack->Parameters.Others.Argument3 = servicingDeviceInfo;\r\n    Irp->IoStatus.Status = status;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveIn (DsmIds %p): Exiting function returning IRP status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPersistentReserveCompletion(\r\n    IN PDEVICE_OBJECT DeviceObject,\r\n    IN PIRP Irp,\r\n    IN PVOID Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    General-purpose completion routine for PR in and out commands sent synchronously.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Target of the request.\r\n    Irp - Command being sent.\r\n    Context - The event on which the caller is waiting.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_COMPLETION_CONTEXT context = Context;\r\n    PKEVENT event;\r\n\r\n    // It is required to specify a DSM completion context\r\n    // when setting DsmpPersistentReserveCompletion as completion routine.\r\n    _Analysis_assume_(context != NULL);\r\n\r\n    event = (PKEVENT)(context->RequestUnique1);\r\n\r\n    UNREFERENCED_PARAMETER(DeviceObject);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpPersistentReserveCompletion: DevInfo %p, IRP %p, Context %p\\n\",\r\n                context->DeviceInfo,\r\n                Irp,\r\n                Context));\r\n\r\n    if (Irp->PendingReturned) {\r\n\r\n        IoMarkIrpPending(Irp);\r\n    }\r\n\r\n    KeSetEvent(event, 0, FALSE);\r\n\r\n    return STATUS_MORE_PROCESSING_REQUIRED;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/dsmtrace.mof",
    "content": "#pragma classflags(\"forceupdate\")\n#pragma namespace(\"\\\\\\\\.\\\\root\\\\WMI\")\n//\n// Copyright (C) 2004  Microsoft Corporation\n//\n// WPP Generated File\n//\n\n//ModuleName = wppCtlGuid        (Init called in Function DriverEntry)\n[Dynamic,\n Description(\"MSDSM Driver Tracing Provider\"),\n guid(\"{DEDADFF5-F99F-4600-B8C9-2D4D9B806B5B}\"),\n locale(\"MS\\\\0x409\")]\nclass MSDSMGuid : EventTrace\n{\n    [Description (\"Enable Flags\"),\n        ValueDescriptions{\n             \"TRACE_FLAG_GENERAL Flag\",\n             \"TRACE_FLAG_PNP Flag\",\n             \"TRACE_FLAG_POWER Flag\",\n             \"TRACE_FLAG_RW Flag\",\n             \"TRACE_FLAG_IOCTL Flag\",\n             \"TRACE_FLAG_QUEUE Flag\",\n             \"TRACE_FLAG_WMI Flag\",\n             \"TRACE_FLAG_TIMER Flag\",\n             \"TRACE_FLAG_INIT Flag\",\n             \"TRACE_FLAG_LOCK Flag\",\n             \"TRACE_FLAG_DEBUG1 Flag\",\n             \"TRACE_FLAG_DEBUG2 Flag\",\n             \"TRACE_FLAG_MCN Flag\",\n             \"TRACE_FLAG_ISR Flag\",\n             \"TRACE_FLAG_ENUM Flag\"},\n        DefineValues{\n             \"TRACE_FLAG_GENERAL\",\n             \"TRACE_FLAG_PNP\",\n             \"TRACE_FLAG_POWER\",\n             \"TRACE_FLAG_RW\",\n             \"TRACE_FLAG_IOCTL\",\n             \"TRACE_FLAG_QUEUE\",\n             \"TRACE_FLAG_WMI\",\n             \"TRACE_FLAG_TIMER\",\n             \"TRACE_FLAG_INIT\",\n             \"TRACE_FLAG_LOCK\",\n             \"TRACE_FLAG_DEBUG1\",\n             \"TRACE_FLAG_DEBUG2\",\n             \"TRACE_FLAG_MCN\",\n             \"TRACE_FLAG_ISR\",\n             \"TRACE_FLAG_ENUM\"},\n        Values{\n             \"TRACE_FLAG_GENERAL\",\n             \"TRACE_FLAG_PNP\",\n             \"TRACE_FLAG_POWER\",\n             \"TRACE_FLAG_RW\",\n             \"TRACE_FLAG_IOCTL\",\n             \"TRACE_FLAG_QUEUE\",\n             \"TRACE_FLAG_WMI\",\n             \"TRACE_FLAG_TIMER\",\n             \"TRACE_FLAG_INIT\",\n             \"TRACE_FLAG_LOCK\",\n             \"TRACE_FLAG_DEBUG1\",\n             \"TRACE_FLAG_DEBUG2\",\n             \"TRACE_FLAG_MCN\",\n             \"TRACE_FLAG_ISR\",\n             \"TRACE_FLAG_ENUM\"},\n        ValueMap{\n             \"0x00000001\",\n             \"0x00000002\",\n             \"0x00000004\",\n             \"0x00000008\",\n             \"0x00000010\",\n             \"0x00000020\",\n             \"0x00000040\",\n             \"0x00000080\",\n             \"0x00000100\",\n             \"0x00000200\",\n             \"0x00000400\",\n             \"0x00000800\",\n             \"0x00001000\",\n             \"0x00002000\",\n             \"0x00004000\"}\n    ]\n    uint32 Flags;\n    [Description (\"Levels\"),\n        ValueDescriptions{\n            \"Abnormal exit or termination\",\n            \"Severe errors that need logging\",\n            \"Warnings such as allocation failure\",\n            \"Includes non-error cases\",\n            \"Detailed traces from intermediate steps\" },\n         DefineValues{\n            \"TRACE_LEVEL_FATAL\",\n            \"TRACE_LEVEL_ERROR\",\n            \"TRACE_LEVEL_WARNING\"\n            \"TRACE_LEVEL_INFORMATION\",\n            \"TRACE_LEVEL_VERBOSE\" },\n        Values{\n            \"Fatal\",\n            \"Error\",\n            \"Warning\",\n            \"Information\",\n            \"Verbose\" },\n        ValueMap{\n            \"0x1\",\n            \"0x2\",\n            \"0x3\",\n            \"0x4\",\n            \"0x5\" },\n        ValueType(\"index\")\n    ]\n    uint32 Level;\n};\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/intrface.c",
    "content": "/*++\r\n\r\nCopyright (C) 2004-2010  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    intrface.c\r\n\r\nAbstract:\r\n\r\n    This driver is the Microsoft Device Specific Module (DSM)\r\n    devices that conform with SPC-3 specs.\r\n    It exports behaviors that mpio.sys will use to determine how to\r\n    multipath these devices.\r\n\r\n    This file contains DriverEntry and all the functions that are\r\n    exported to MPIO.\r\n\r\n    This DSM is targetted towards Windows 2008 and above.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#ifdef DEBUG_USE_WPP\r\n#include \"intrface.tmh\"\r\n#endif\r\n\r\n#pragma warning (disable:4305)\r\n\r\nDSM_INIT_DATA gDsmInitData;\r\n\r\n//\r\n// Flag to indicate whether to NT_ASSERT or ignore a particular condition.\r\n//\r\nBOOLEAN DoAssert = TRUE;\r\n\r\n//\r\n// OS Version Info\r\n// MSDSM is targetted towards Windows Server 2008 and above.\r\n//\r\nBOOLEAN gServer2008AndAbove = FALSE;\r\n\r\n//\r\n// Global to cache MPIO's Control Object.\r\n//\r\nPDEVICE_OBJECT gMPIOControlObject = NULL;\r\n\r\n//\r\n// Flag to indicate if the MPIO control object was referenced.\r\n//\r\nBOOLEAN gMPIOControlObjectRefd = FALSE;\r\n\r\n//\r\n// Global to cache the Driver Object.\r\n//\r\nPDRIVER_OBJECT gDsmDriverObject = NULL;\r\n\r\n\r\n#ifdef ALLOC_PRAGMA\r\n    #pragma alloc_text(INIT, DriverEntry)\r\n#endif\r\n\r\n//\r\n// The code.\r\n//\r\nNTSTATUS\r\nDriverEntry(\r\n    IN PDRIVER_OBJECT DriverObject,\r\n    IN PUNICODE_STRING RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when the driver is loaded.\r\n\r\nArguments:\r\n\r\n    DriverObject  - Supplies the driver object.\r\n    RegistryPath  - Supplies the registry path.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n\r\n--*/\r\n{\r\n    PDSM_CONTEXT dsmContext = NULL;\r\n    PFILE_OBJECT fileObject;\r\n    WCHAR dosDeviceName[64] = DSM_MPIO_CONTROL_OBJECT_SYMLINK;\r\n    UNICODE_STRING mpUnicodeName;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    MPIO_VERSION_INFO versionInfo = {0};\r\n    DSM_TYPE dsmMode = DsmType3;\r\n    DSM_MPIO_CONTEXT mpctlContext;\r\n    IO_STATUS_BLOCK ioStatus;\r\n\r\n\r\n    //\r\n    // Initialize the tracing subsystem.\r\n    // Any failure is handled by ETW itself.\r\n    //\r\n    WPP_INIT_TRACING(DriverObject, RegistryPath);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DriverEntry (DrvObj %p): Entering function.\\n\",\r\n                DriverObject));\r\n\r\n    gDsmDriverObject = DriverObject;\r\n\r\n    //\r\n    // Determine the OS version.\r\n    //\r\n    gServer2008AndAbove = RtlIsNtDdiVersionAvailable(NTDDI_VISTA);\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_INIT,\r\n                \"DriverEntry (DrvObj %p): Server2008AndAbove is %!bool!.\\n\",\r\n                DriverObject,\r\n                gServer2008AndAbove));\r\n\r\n    //\r\n    // MSDSM is supported only on Server 2008 and above.\r\n    //\r\n    if (!gServer2008AndAbove) {\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DriverEntry;\r\n    }\r\n\r\n    //\r\n    // Build the mpio symbolic link name.\r\n    //\r\n    RtlInitUnicodeString(&mpUnicodeName, dosDeviceName);\r\n\r\n    //\r\n    // Get a pointer to mpio's deviceObject.\r\n    //\r\n    status = IoGetDeviceObjectPointer(&mpUnicodeName,\r\n                                      FILE_READ_ATTRIBUTES,\r\n                                      &fileObject,\r\n                                      &gMPIOControlObject);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_FATAL,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): Failed to communicate with MPIO control object. Status %x.\\n\",\r\n                    DriverObject,\r\n                    status));\r\n\r\n        goto __Exit_DriverEntry;\r\n    }\r\n\r\n    ObReferenceObject(gMPIOControlObject);\r\n    gMPIOControlObjectRefd = TRUE;\r\n    ObDereferenceObject(fileObject);\r\n\r\n    status = DsmGetVersion(&versionInfo, sizeof(MPIO_VERSION_INFO));\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // If we can't get the version, that means we aren't using a compatible\r\n        // version of MPIO drivers and so should not continue.\r\n        //\r\n        TracePrint((TRACE_LEVEL_FATAL,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): MPIO version unknown - DSM exiting.\\n\",\r\n                    DriverObject));\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n        goto __Exit_DriverEntry;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_INIT,\r\n                \"DriverEntry (DrvObj %p): MPIO version %d.%d.%d.%d.\\n\",\r\n                DriverObject,\r\n                versionInfo.MajorVersion,\r\n                versionInfo.MinorVersion,\r\n                versionInfo.ProductBuild,\r\n                versionInfo.QfeNumber));\r\n\r\n    RtlZeroMemory(&gDsmInitData, sizeof(DSM_INIT_DATA));\r\n\r\n    //\r\n    // Must be newer than 1.0.7.0 to support DSM type 2 upwards.\r\n    //\r\n    if ((versionInfo.MajorVersion > 1)  ||\r\n        (versionInfo.MinorVersion >= 1) ||\r\n        (versionInfo.ProductBuild > 7)  ||\r\n        (versionInfo.QfeNumber    >= 1)) {\r\n\r\n        //\r\n        // Must be newer than 1.18 to support DSM's versioning\r\n        //\r\n        if (versionInfo.MajorVersion > 1 ||\r\n            versionInfo.MinorVersion > 17) {\r\n\r\n            dsmMode = DsmType6;\r\n\r\n            {\r\n                RTL_OSVERSIONINFOW osVersion = {0};\r\n\r\n                osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);\r\n                RtlGetVersion(&osVersion);\r\n\r\n                gDsmInitData.DsmVersion.MajorVersion = osVersion.dwMajorVersion;\r\n                gDsmInitData.DsmVersion.MinorVersion = osVersion.dwMinorVersion;\r\n                gDsmInitData.DsmVersion.ProductBuild = osVersion.dwBuildNumber;\r\n                gDsmInitData.DsmVersion.QfeNumber = 0;\r\n            }\r\n        }\r\n    } else {\r\n\r\n        //\r\n        // We cannot use this DSM with older versions of the MPIO drivers.\r\n        //\r\n        TracePrint((TRACE_LEVEL_FATAL,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): MPIO version not supported - DSM exiting.\\n\",\r\n                    DriverObject));\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n        goto __Exit_DriverEntry;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_INIT,\r\n                \"DriverEntry (DrvObj %p): Setting DSM type to %d.\\n\",\r\n                DriverObject,\r\n                dsmMode));\r\n\r\n    //\r\n    // Build the init data structure.\r\n    //\r\n    dsmContext = DsmpAllocatePool(NonPagedPoolNx,\r\n                                  sizeof(DSM_CONTEXT),\r\n                                  DSM_TAG_DSM_CONTEXT);\r\n    if (!dsmContext) {\r\n\r\n        TracePrint((TRACE_LEVEL_FATAL,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): Failed to allocate memory for DSM Context.\\n\",\r\n                    DriverObject));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DriverEntry;\r\n    }\r\n\r\n    //\r\n    // Set-up the init data\r\n    //\r\n    gDsmInitData.DsmContext = (PVOID) dsmContext;\r\n    gDsmInitData.InitDataSize = sizeof(DSM_INIT_DATA);\r\n\r\n    gDsmInitData.DsmInquireDriver = DsmInquire;\r\n    gDsmInitData.DsmCompareDevices = DsmCompareDevices;\r\n    gDsmInitData.DsmGetControllerInfo = DsmGetControllerInfo;\r\n    gDsmInitData.DsmSetDeviceInfo = DsmSetDeviceInfo;\r\n    gDsmInitData.DsmIsPathActive = DsmIsPathActive;\r\n    gDsmInitData.DsmPathVerify = DsmPathVerify;\r\n    gDsmInitData.DsmInvalidatePath = DsmInvalidatePath;\r\n    gDsmInitData.DsmMoveDevice = DsmMoveDevice;\r\n    gDsmInitData.DsmRemovePending = DsmRemovePending;\r\n    gDsmInitData.DsmRemoveDevice = DsmRemoveDevice;\r\n    gDsmInitData.DsmRemovePath = DsmRemovePath;\r\n    gDsmInitData.DsmSrbDeviceControl = DsmSrbDeviceControl;\r\n    gDsmInitData.DsmLBGetPath = DsmLBGetPath;\r\n    gDsmInitData.DsmInterpretErrorEx = DsmInterpretError;\r\n    gDsmInitData.DsmUnload = DsmUnload;\r\n    gDsmInitData.DsmSetCompletion = DsmSetCompletion;\r\n    gDsmInitData.DsmCategorizeRequest = DsmCategorizeRequest;\r\n    gDsmInitData.DsmBroadcastSrb = DsmBroadcastRequest;\r\n    gDsmInitData.DsmIsAddressTypeSupported = DsmIsAddressTypeSupported;\r\n    gDsmInitData.DsmDeviceNotUsed = DsmDeviceNotUsed;\r\n\r\n    //\r\n    // Since MSDSM is for SPC-3 compliant devices, MPIO should be able to build\r\n    // a serial number for the device.\r\n    //\r\n    gDsmInitData.DsmDeviceSerialNumber = NULL;\r\n\r\n    //\r\n    // Notifies MPIO of the appropriate Type support\r\n    //\r\n    gDsmInitData.DsmType = dsmMode;\r\n\r\n    gDsmInitData.DriverObject = DriverObject;\r\n\r\n\r\n    //\r\n    // Set-up the WMI Info.\r\n    //\r\n    DsmpWmiInitialize(&gDsmInitData.DsmWmiInfo, RegistryPath);\r\n    DsmpDsmWmiInitialize(&gDsmInitData.DsmWmiGlobalInfo, RegistryPath);\r\n\r\n    RtlInitUnicodeString(&gDsmInitData.DisplayName, DSM_FRIENDLY_NAME);\r\n\r\n    //\r\n    // Initialize some of the fields in DSM Context structure.\r\n    //\r\n    KeInitializeSpinLock(&dsmContext->SupportedDevicesListLock);\r\n    InitializeListHead(&dsmContext->GroupList);\r\n    InitializeListHead(&dsmContext->DeviceList);\r\n    InitializeListHead(&dsmContext->FailGroupList);\r\n    InitializeListHead(&dsmContext->ControllerList);\r\n    InitializeListHead(&dsmContext->StaleFailGroupList);\r\n\r\n    //\r\n    // Build the list context structures used for completion processing.\r\n    //\r\n    ExInitializeNPagedLookasideList(&dsmContext->CompletionContextList,\r\n                                    NULL,\r\n                                    NULL,\r\n                                    POOL_NX_ALLOCATION,\r\n                                    sizeof(DSM_COMPLETION_CONTEXT),\r\n                                    DSM_TAG_GENERIC,\r\n                                    0);\r\n\r\n    RtlZeroMemory(&mpctlContext, sizeof(DSM_MPIO_CONTEXT));\r\n\r\n    //\r\n    // Send the IOCTL to mpio.sys to register ourselves.\r\n    //\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_MPDSM_REGISTER,\r\n                                      gMPIOControlObject,\r\n                                      &gDsmInitData,\r\n                                      &mpctlContext,\r\n                                      sizeof(DSM_INIT_DATA),\r\n                                      sizeof(DSM_MPIO_CONTEXT),\r\n                                      TRUE,\r\n                                      &ioStatus);\r\n\r\n    status = ioStatus.Status;\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        dsmContext->MPIOContext = mpctlContext.MPIOContext;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): Registered with MPIO.\\n\",\r\n                    DriverObject));\r\n\r\n        DriverObject->DriverUnload = DsmDriverUnload;\r\n\r\n        //\r\n        // Query the registry for disabling/enabling statistics gathering\r\n        //\r\n        if (STATUS_OBJECT_NAME_NOT_FOUND == DsmpGetStatsGatheringChoice(dsmContext, (PULONG)&dsmContext->DisableStatsGathering)) {\r\n\r\n            //\r\n            // If the value does not exist, write the default to registry.\r\n            //\r\n            DsmpSetStatsGatheringChoice(dsmContext, (ULONG)dsmContext->DisableStatsGathering);\r\n        }\r\n    }\r\n\r\n__Exit_DriverEntry:\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_VERBOSE,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): Exiting function successfully.\\n\",\r\n                    DriverObject));\r\n    } else {\r\n\r\n        //\r\n        // Since the DSM is going to be unloaded but without DriverUnload being\r\n        // called, we need to perform cleanup here.\r\n        //\r\n        if (dsmContext != NULL) {\r\n            DsmpFreeDSMResources(dsmContext);\r\n            dsmContext = NULL;\r\n        }\r\n\r\n        if (gMPIOControlObjectRefd) {\r\n\r\n            //\r\n            // Drop the reference on MPIO's control object.\r\n            //\r\n            ObDereferenceObject(gMPIOControlObject);\r\n            gMPIOControlObjectRefd = FALSE;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_VERBOSE,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DriverEntry (DrvObj %p): Exiting function with status %x.\\n\",\r\n                    DriverObject,\r\n                    status));\r\n\r\n        //\r\n        // Stop the tracing subsystem.\r\n        // NOTE: once we unregister ETW, no more TracePrint can be done, so we\r\n        // must ensure that ETW unregister is the last thing that happens.\r\n        //\r\n        WPP_CLEANUP(gDsmDriverObject);\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmDriverUnload(\r\n    _In_ IN PDRIVER_OBJECT DriverObject\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when the driver is unloaded.\r\n\r\nArguments:\r\n\r\n    DriverObject  - Supplies the driver object.\r\n\r\nReturn Value:\r\n\r\n    Nothing\r\n\r\n--*/\r\n{\r\n    DSM_DEREGISTER_DATA deregisterData;\r\n    IO_STATUS_BLOCK ioStatus;\r\n\r\n    deregisterData.DeregisterDataSize = sizeof(DSM_DEREGISTER_DATA);\r\n    deregisterData.DriverObject = DriverObject;\r\n    deregisterData.DsmContext = gDsmInitData.DsmContext;\r\n    deregisterData.MpioContext = ((PDSM_CONTEXT)(gDsmInitData.DsmContext))->MPIOContext;\r\n    //\r\n    // Send the IOCTL to mpio.sys to de-register ourselves.\r\n    //\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_MPDSM_DEREGISTER,\r\n                                      gMPIOControlObject,\r\n                                      &deregisterData,\r\n                                      NULL,\r\n                                      sizeof(DSM_DEREGISTER_DATA),\r\n                                      0,\r\n                                      TRUE,\r\n                                      &ioStatus);\r\n\r\n    NT_ASSERT(NT_SUCCESS(ioStatus.Status));\r\n\r\n\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmInquire(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDEVICE_OBJECT TargetDevice,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList,\r\n    _Out_ OUT PVOID *DsmIdentifier\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to determine if TargetDevice belongs to\r\n    the DSM. If this is a supported device DsmIdentifier will be\r\n    updated with 'deviceInfo'.\r\n\r\nArguments:\r\n\r\n    DsmContext   - Context value given to the multipath driver during\r\n                   registration.\r\n    TargetDevice - DeviceObject for the child device.\r\n    PortObject   - The Port driver FDO on which TargetDevice resides.\r\n    Descriptor   - Pointer to the device descriptor corresponding to TargetDevice.\r\n                   Rehash of inquiry data, plus serial number information\r\n                   (if applicable).\r\n    DeviceIdList - VPD Page 0x83 information.\r\n    DsmIdentifier - Pointer to be filled in by the DSM on success.\r\n\r\nReturn Value:\r\n\r\n    STATUS_NOT_SUPPORTED - if not on the SupportList.\r\n    STATUS_INSUFFICIENT_RESOURCES - No mem.\r\n    STATUS_SUCCESS\r\n--*/\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    PDSM_GROUP_ENTRY group;\r\n    BOOLEAN newGroup;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroupEntry = NULL;\r\n    PDSM_TARGET_PORT_LIST_ENTRY targetPortEntry = NULL;\r\n    PSTR serialNumber = NULL;\r\n    SIZE_T serialNumberLength = 0;\r\n    NTSTATUS status;\r\n    ULONG allocationLength;\r\n    BOOLEAN serialNumberAllocated = FALSE;\r\n    KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error\r\n    BOOLEAN supported = FALSE;\r\n    BOOLEAN spinlockHeld = FALSE;\r\n    UCHAR vendorId[9] = {0};\r\n    UCHAR productId[17] = {0};\r\n    INQUIRYDATA inquiryData;\r\n    UCHAR alua = DSM_DEVINFO_ALUA_NOT_SUPPORTED;\r\n    ULONG index;\r\n    PDSM_IDS controllerObjects = NULL;\r\n    PDEVICE_OBJECT controllerDeviceObject;\r\n    PLIST_ENTRY entry = NULL;\r\n    PSTORAGE_DESCRIPTOR_HEADER controllerIdHeader = NULL;\r\n    PULONG relativeTargetPortId = NULL;\r\n    PUSHORT targetPortGroupId = NULL;\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength = 0;\r\n    PSTR controllerSerialNumber;\r\n    BOOLEAN match = FALSE;\r\n    BOOLEAN doneUpdating = FALSE;\r\n    PDSM_CONTROLLER_LIST_ENTRY controllerEntry = NULL;\r\n    PDSM_TARGET_PORT_DEVICELIST_ENTRY tp_device = NULL;\r\n    PWSTR hardwareId = NULL;\r\n    PWCHAR deviceName = NULL;\r\n    ULONG tempResult = 0;\r\n    ULONG maxPRRetryTimeDuringStateTransition = DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME;\r\n    BOOLEAN useCacheForLeastBlocks = FALSE;\r\n    ULONGLONG cacheSizeForLeastBlocks = 0;\r\n    BOOLEAN fakeControllerEntryExists = FALSE;\r\n    STORAGE_IDENTIFIER_CODE_SET serialNumberCodeSet = StorageIdCodeSetReserved;\r\n\r\n#if DBG\r\n    BOOLEAN multiport;\r\n#endif\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmInquire (DevObj %p): Entering function.\\n\",\r\n                TargetDevice));\r\n\r\n    //\r\n    //  1. Get standard inquiry for the device. Check if SPC-3 compliant.\r\n    //        If not compliant, check SupportedDeviceList.\r\n    //  2. Create device serial number.\r\n    //  3. Create a partially populated deviceInfo.\r\n    //        DeviceDescriptor.\r\n    //        SCSI address.\r\n    //        Save off serial number.\r\n    //        ALUA, port FDO, etc.\r\n    //  4. Create device name.\r\n    //  5. If ALUA support, send down Report Target Port Groups.\r\n    //  6. Find the group. If none, build one.\r\n    //  7. If new group, build target port groups and target ports info.\r\n    //        Else, update target port groups and target ports info.\r\n    //  8. If both implicit as well as explicit transitions allowed, disable implicit.\r\n    //  9. Get list of controllers objects and get VPD 0x83 for each (only if no\r\n    //     match for existing ones).\r\n    //        Match returned ids of type 0x5 with what was returned in Report Target Port Groups.\r\n    //        If no type 0x5 identifier, use SCSI address.\r\n    //        Create controller list (delete stale entries).\r\n    //\r\n\r\n\r\n    //\r\n    // Query the registry to find out what devices are being supported\r\n    // on this machine.\r\n    //\r\n    DsmpGetDeviceList(dsmContext);\r\n\r\n    status = DsmpGetStandardInquiryData(TargetDevice, &inquiryData);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        supported = DsmpCheckScsiCompliance(TargetDevice,\r\n                                            &inquiryData,\r\n                                            Descriptor,\r\n                                            DeviceIdList);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Failed to get inquiry data with status %x.\\n\",\r\n                    TargetDevice,\r\n                    status));\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DsmInquire;\r\n    }\r\n\r\n    //\r\n    // Since the device isn't SPC-3 compliant, check if the device is on the\r\n    // SupportedDeviceList.\r\n    //\r\n    if (!supported) {\r\n\r\n\r\n        if (!supported) {\r\n\r\n            //\r\n            // Get the inquiry data embedded in the device descriptor.\r\n            //\r\n            RtlStringCchCopyA((LPSTR)vendorId,\r\n                              sizeof(vendorId) / sizeof(vendorId[0]),\r\n                              (LPCSTR)(&inquiryData.VendorId));\r\n\r\n            RtlStringCchCopyA((LPSTR)productId,\r\n                              sizeof(productId) / sizeof(productId[0]),\r\n                              (LPCSTR)(&inquiryData.ProductId));\r\n\r\n            supported = DsmpDeviceSupported(dsmContext,\r\n                                            (PCSZ)vendorId,\r\n                                            (PCSZ)productId);\r\n        }\r\n\r\n        if (!supported) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): Unsupported Device.\\n\",\r\n                        TargetDevice));\r\n\r\n            status = STATUS_NOT_SUPPORTED;\r\n            goto __Exit_DsmInquire;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Find out if device can be accessed via mulitple ports. This info is\r\n    // important since it will determine whether or not to send down a\r\n    // ReportTargetPortGroups command.\r\n    //\r\n#if DBG\r\n    multiport = (inquiryData.MultiPort & 0x10) ? TRUE : FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmInquire (DevObj %p): Is %ws multiported.\\n\",\r\n                TargetDevice,\r\n                multiport ? L\"\" : L\"not\"));\r\n#endif\r\n\r\n    //\r\n    // Query the assymmetric states transition method\r\n    //\r\n    switch ((inquiryData.Reserved >> 0x4) & 0x3) {\r\n        case 1: alua = DSM_DEVINFO_ALUA_IMPLICIT;\r\n                break;\r\n\r\n        case 2: alua = DSM_DEVINFO_ALUA_EXPLICIT;\r\n                break;\r\n\r\n        case 3: alua = DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT;\r\n                break;\r\n\r\n        default: alua = DSM_DEVINFO_ALUA_NOT_SUPPORTED;\r\n                break;\r\n    }\r\n\r\n    //\r\n    // Get some information about this device. The preferred info is\r\n    // from the Device ID Page.\r\n    //\r\n    if (DeviceIdList) {\r\n\r\n        //\r\n        // This will parse out the 'best' identifier and return\r\n        // a NULL-terminated ascii string.\r\n        //\r\n        serialNumber = (PSTR)DsmpParseDeviceID(DeviceIdList,\r\n                                               DSM_DEVID_SERIAL_NUMBER,\r\n                                               NULL,\r\n                                               &serialNumberCodeSet,\r\n                                               FALSE);\r\n\r\n        if (!serialNumber) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): NULL serial number.\\n\",\r\n                        TargetDevice));\r\n\r\n            //\r\n            // Either an allocation failed, or the DeviceIdList is malformed.\r\n            //\r\n            status = STATUS_NOT_SUPPORTED;\r\n            goto __Exit_DsmInquire;\r\n        }\r\n\r\n        //\r\n        // Indicate that the serialnumber buffer is allocated.\r\n        //\r\n        serialNumberAllocated = TRUE;\r\n        serialNumberLength = strlen((const char*)serialNumber);\r\n\r\n    } else {\r\n\r\n        //\r\n        // Get the serial number of this device. Use the serial number\r\n        // page (0x80). Ensure that the device's serial number is\r\n        // present. If not, can't claim support for  this drive.\r\n        //\r\n\r\n        if (!Descriptor ||\r\n            (Descriptor->SerialNumberOffset == MAXULONG) ||\r\n            (Descriptor->SerialNumberOffset == 0)) {\r\n\r\n            //\r\n            // The port driver currently doesn't get the VPD page 0x80,\r\n            // if the device doesn't support GET_SUPPORTED_PAGES. Check to\r\n            // see whether there actually is a serial number.\r\n            //\r\n            serialNumber = DsmpGetSerialNumber(TargetDevice);\r\n\r\n            if (!serialNumber) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): serialNumber = NULL.\\n\",\r\n                            TargetDevice));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n\r\n            } else {\r\n                serialNumberAllocated = TRUE;\r\n                serialNumberLength = strlen((const char*)serialNumber);\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // Allocate for the device. This is also used as DsmId.\r\n    //\r\n    allocationLength = sizeof(DSM_DEVICE_INFO);\r\n\r\n    //\r\n    // As DSM_DEVICE_INFO has storage for the descriptor, add only\r\n    // the additional stuff that's at the end.\r\n    //\r\n    if (Descriptor) {\r\n        status = RtlULongSub(Descriptor->Size, sizeof(STORAGE_DEVICE_DESCRIPTOR), &tempResult);\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): Arithmetic underflow - status %x.\\n\",\r\n                        TargetDevice,\r\n                        status));\r\n\r\n            status = STATUS_NOT_SUPPORTED;\r\n            goto __Exit_DsmInquire;\r\n        }\r\n    }\r\n\r\n    status = RtlULongAdd(allocationLength, tempResult, &allocationLength);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Arithmetic overflow - status %x.\\n\",\r\n                    TargetDevice,\r\n                    status));\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DsmInquire;\r\n    }\r\n\r\n    deviceInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                  allocationLength,\r\n                                  DSM_TAG_DEV_INFO);\r\n    if (!deviceInfo) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Failed to allocate Device Info.\\n\",\r\n                    TargetDevice));\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DsmInquire;\r\n    }\r\n\r\n    deviceInfo->State = deviceInfo->PreviousState = deviceInfo->TempPreviousStateForLB = deviceInfo->ALUAState = deviceInfo->LastKnownGoodState = DSM_DEV_NOT_USED_STATE;\r\n    deviceInfo->DesiredState = DSM_DEV_UNDETERMINED;\r\n    //\r\n    // Copy over the StorageDescriptor.\r\n    //\r\n    if (Descriptor) {\r\n        RtlCopyMemory(&deviceInfo->Descriptor,\r\n                      Descriptor,\r\n                      Descriptor->Size);\r\n    }\r\n\r\n    //\r\n    // Get the scsi address for this device.  Note that on success, DsmGetScsiAddress()\r\n    // will allocate memory which we are responsible for freeing.\r\n    //\r\n    status = DsmGetScsiAddress(TargetDevice,\r\n                               &deviceInfo->ScsiAddress);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Error %x while getting scsi address.\\n\",\r\n                    TargetDevice,\r\n                    status));\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DsmInquire;\r\n    }\r\n\r\n    //\r\n    // Capture the serial number allocated flag.\r\n    //\r\n    deviceInfo->SerialNumberAllocated = serialNumberAllocated;\r\n\r\n    //\r\n    // Set the serial number.\r\n    //\r\n    if (!serialNumberAllocated) {\r\n\r\n        PSTORAGE_DEVICE_DESCRIPTOR descriptor;\r\n\r\n        //\r\n        // serialNumber is not pointing to the buffer passed by MPIO. Update\r\n        // it to point to the Device Descriptor allocated by the DSM.\r\n        //\r\n        descriptor = &(deviceInfo->Descriptor);\r\n\r\n        NT_ASSERT(descriptor->SerialNumberOffset != 0 && descriptor->SerialNumberOffset != MAXULONG);\r\n\r\n        serialNumber = (PCHAR)descriptor + descriptor->SerialNumberOffset;\r\n        serialNumberLength = strlen((const char*)serialNumber);\r\n    }\r\n\r\n    if (alua == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT)) {\r\n\r\n        BOOLEAN disableImplicit = FALSE;\r\n\r\n        status = DsmpDisableImplicitStateTransition(TargetDevice, &disableImplicit);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            if (disableImplicit) {\r\n\r\n                alua &= ~DSM_DEVINFO_ALUA_IMPLICIT;\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Disabled implicit ALUA state transition.\\n\",\r\n                            TargetDevice));\r\n\r\n                //\r\n                // Record that the storage actually supported implicit also, but we\r\n                // turned it OFF.\r\n                //\r\n                deviceInfo->ImplicitDisabled = TRUE;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Storage support both transitions but does NOT allow disabling Implicit.\\n\",\r\n                            TargetDevice));\r\n            }\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): Failed to disable implicit ALUA state transitions - status %x.\\n\",\r\n                        TargetDevice,\r\n                        status));\r\n        }\r\n    }\r\n\r\n    deviceInfo->SerialNumber = serialNumber;\r\n\r\n    //\r\n    // Save the Physical Device Object (PDO) of the device.\r\n    // Used to verify that no two devices have the same PDO.\r\n    //\r\n    deviceInfo->PortPdo = TargetDevice;\r\n\r\n    //\r\n    // Save the FDO of the adapter. Used for handling reserve\\release\r\n    //\r\n    deviceInfo->PortFdo = PortObject;\r\n\r\n    //\r\n    // Set the signature.\r\n    //\r\n    deviceInfo->DeviceSig = DSM_DEVICE_SIG;\r\n\r\n    deviceInfo->DsmContext = DsmContext;\r\n\r\n    deviceInfo->ALUASupport = alua;\r\n\r\n    //\r\n    // Build the name (using serialnumber) that will be used as registry key\r\n    // to store Load Balance settings for this device.\r\n    //\r\n    deviceName = DsmpBuildDeviceName(deviceInfo, serialNumber, serialNumberLength);\r\n\r\n    if (!deviceName) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Failed to allocate device name for %p.\\n\",\r\n                    TargetDevice,\r\n                    deviceInfo));\r\n\r\n        status = STATUS_NOT_SUPPORTED;\r\n        goto __Exit_DsmInquire;\r\n    }\r\n\r\n\r\n    //\r\n    // Send down ReportTargetPortGroups command and keep the info handy.\r\n    //\r\n    if (alua != DSM_DEVINFO_ALUA_NOT_SUPPORTED) {\r\n\r\n        status = DsmpReportTargetPortGroups(TargetDevice,\r\n                                            &targetPortGroupsInfo,\r\n                                            &targetPortGroupsInfoLength);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): Failed to report target port groups for %p. Status %x.\\n\",\r\n                        TargetDevice,\r\n                        deviceInfo,\r\n                        status));\r\n\r\n            status = STATUS_NOT_SUPPORTED;\r\n            goto __Exit_DsmInquire;\r\n        }\r\n\r\n        //\r\n        // We've just sent down an RTPG (relatively expensive operation), and it\r\n        // succeeded, so sending down one more as part part of the initialization\r\n        // in PathVerify() since it is going to be called almost immediately.\r\n        //\r\n        deviceInfo->IgnorePathVerify = TRUE;\r\n    }\r\n\r\n    //\r\n    // Query the registry for max time to retry failed PR requests\r\n    //\r\n    DsmpGetMaxPRRetryTime(DsmContext, &maxPRRetryTimeDuringStateTransition);\r\n\r\n    //\r\n    // Query the registry to see if the user has overridden the default\r\n    // Least Blocks settings.\r\n    //\r\n    status = DsmpQueryCacheInformationFromRegistry(DsmContext,\r\n                                                  &useCacheForLeastBlocks,\r\n                                                  &cacheSizeForLeastBlocks);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        //\r\n        // Couldn't get the settings from the registry so fall back on the\r\n        // default for Least Blocks.\r\n        //\r\n        useCacheForLeastBlocks = TRUE;\r\n        cacheSizeForLeastBlocks = DSM_LEAST_BLOCKS_DEFAULT_THRESHOLD;\r\n    }\r\n\r\n    //\r\n    // Build LUN's hardware id.  Needs to be called at PASSIVE_LEVEL, so\r\n    // do it before grabbing the lock.  The hardware id of the group is\r\n    // later set under the protection of the lock.\r\n    //\r\n    hardwareId = DsmpBuildHardwareId(deviceInfo);\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(((PDSM_CONTEXT)DsmContext)->DsmContextLock));\r\n    spinlockHeld = TRUE;\r\n\r\n    status = STATUS_SUCCESS;\r\n\r\n    //\r\n    // See if there is an existing Multi-path group to which this belongs.\r\n    // (same serial number).\r\n    //\r\n    group = DsmpFindDevice(DsmContext, deviceInfo, FALSE);\r\n    if (!group) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): First device %p in the group.\\n\",\r\n                    TargetDevice,\r\n                    deviceInfo));\r\n\r\n        newGroup = TRUE;\r\n\r\n        //\r\n        // This device doesn't belong to any group yet. So Build a multi-path\r\n        // group entry. This'll represents all paths to a particular device.\r\n        //\r\n        group = DsmpBuildGroupEntry(DsmContext, deviceInfo);\r\n        if (group) {\r\n\r\n            //\r\n            // Set the registry key name for the new group\r\n            //\r\n            group->RegistryKeyName = deviceName;\r\n            deviceName = NULL;\r\n\r\n            //\r\n            // Cache the LUN's hardware id\r\n            //\r\n            if (!hardwareId) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to build a hardwareId for %p.\\n\",\r\n                            TargetDevice,\r\n                            deviceInfo));\r\n            }\r\n\r\n            group->HardwareId = hardwareId;\r\n            hardwareId = NULL;\r\n\r\n            group->UseCacheForLeastBlocks = useCacheForLeastBlocks;\r\n            group->CacheSizeForLeastBlocks = cacheSizeForLeastBlocks;\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmInquire (DevObj %p): Failed to allocate Group Entry for %p.\\n\",\r\n                        TargetDevice,\r\n                        deviceInfo));\r\n\r\n            status = STATUS_NOT_SUPPORTED;\r\n            goto __Exit_DsmInquire;\r\n        }\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmInquire (DevObj %p): Found group %p for device %p.\\n\",\r\n                    TargetDevice,\r\n                    group,\r\n                    deviceInfo));\r\n\r\n        newGroup = FALSE;\r\n\r\n        if (!group->HardwareId) {\r\n\r\n            //\r\n            // If we weren't successful in previously building the hardware id for this LUN,\r\n            // retry doing it again now.\r\n            //\r\n            hardwareId = DsmpBuildHardwareId(deviceInfo);\r\n            if (!hardwareId) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to build a hardwareId for %p.\\n\",\r\n                            TargetDevice,\r\n                            deviceInfo));\r\n            }\r\n\r\n            group->HardwareId = hardwareId;\r\n            hardwareId = NULL;\r\n        }\r\n\r\n        //\r\n        // Sanity check that we haven't been presented with device instances\r\n        // with different ALUA support. So compare with the first device instance.\r\n        //\r\n        for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n            if (group->DeviceList[index]) {\r\n\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (index < DSM_MAX_PATHS) {\r\n\r\n            //\r\n            // Only acceptable conditions are:\r\n            // 1. both have same support,\r\n            // 2. one has explicit, while other has both explicit-and-implicit (this\r\n            //    is a potential valid case because DsmpDisableImplicitStateTransition\r\n            //    may have failed).\r\n            //\r\n            if (!((deviceInfo->ALUASupport == group->DeviceList[index]->ALUASupport) ||\r\n                  ((deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT && deviceInfo->ImplicitDisabled) &&\r\n                   (group->DeviceList[index]->ALUASupport == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT))) ||\r\n                  ((group->DeviceList[index]->ALUASupport == DSM_DEVINFO_ALUA_EXPLICIT && group->DeviceList[index]->ImplicitDisabled) &&\r\n                   (deviceInfo->ALUASupport == (DSM_DEVINFO_ALUA_IMPLICIT | DSM_DEVINFO_ALUA_EXPLICIT))))) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Mismatch in device instances' ALUA support %d vs %d.\\n\",\r\n                            TargetDevice,\r\n                            deviceInfo->ALUASupport,\r\n                            group->DeviceList[index]->ALUASupport));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        NT_ASSERT(group);\r\n\r\n        group->MaxPRRetryTimeDuringStateTransition = maxPRRetryTimeDuringStateTransition;\r\n\r\n        if (alua == DSM_DEVINFO_ALUA_NOT_SUPPORTED) {\r\n\r\n            //\r\n            // Since the device doesn't support ALUA, it is automatically\r\n            // symmetric LU access.\r\n            //\r\n            group->Symmetric = TRUE;\r\n\r\n            if (newGroup) {\r\n\r\n                //\r\n                // This is the first in the group, so make it the active device.\r\n                // The actual active/passive devices will be set-up when\r\n                // LB policies are set by the user.\r\n                //\r\n                deviceInfo->PreviousState = deviceInfo->State;\r\n                deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n            } else {\r\n\r\n                //\r\n                // Already something active, this will be the fail-over device\r\n                // until the load-balance groups are set-up.\r\n                //\r\n                deviceInfo->PreviousState = deviceInfo->State;\r\n                deviceInfo->State = DSM_DEV_STANDBY;\r\n            }\r\n\r\n        } else {\r\n\r\n            if (DeviceIdList == NULL) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): No Device ID List.\\n\",\r\n                            TargetDevice));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n\r\n            if (alua == DSM_DEVINFO_ALUA_IMPLICIT) {\r\n\r\n                //\r\n                // Assume that the LU access is symmetric. When parsing the TPG\r\n                // info, if we find that not all TPGs are in the same LU access\r\n                // state, then we know that this the access is asymmetric.\r\n                //\r\n                group->Symmetric = TRUE;\r\n            }\r\n\r\n            //\r\n            // Build TPG and TP info\r\n            //\r\n            status = DsmpParseTargetPortGroupsInformation(DsmContext,\r\n                                                          group,\r\n                                                          targetPortGroupsInfo,\r\n                                                          targetPortGroupsInfoLength);\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to build TPG information - status %x.\\n\",\r\n                            TargetDevice,\r\n                            status));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n\r\n            for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n                PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup;\r\n\r\n                targetPortGroup = group->TargetPortGroupList[index];\r\n\r\n                if (targetPortGroup) {\r\n\r\n                    DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState);\r\n                }\r\n            }\r\n\r\n            //\r\n            // Find the target port through which this devInfo was exposed.\r\n            //\r\n            relativeTargetPortId = (PULONG)DsmpParseDeviceID(DeviceIdList,\r\n                                                             DSM_DEVID_RELATIVE_TARGET_PORT,\r\n                                                             NULL,\r\n                                                             NULL,\r\n                                                             FALSE);\r\n            NT_ASSERT(relativeTargetPortId);\r\n\r\n            if (!relativeTargetPortId) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Couldn't retrieve relative TP id.\\n\",\r\n                            TargetDevice));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n\r\n            //\r\n            // Find the target port group\r\n            //\r\n            targetPortGroupId = (PUSHORT)DsmpParseDeviceID(DeviceIdList,\r\n                                                           DSM_DEVID_TARGET_PORT_GROUP,\r\n                                                           NULL,\r\n                                                           NULL,\r\n                                                           FALSE);\r\n            NT_ASSERT(targetPortGroupId);\r\n\r\n            if (targetPortGroupId) {\r\n\r\n                //\r\n                // Find the target port group entry\r\n                //\r\n                targetPortGroupEntry = DsmpFindTargetPortGroup(DsmContext,\r\n                                                               group,\r\n                                                               targetPortGroupId);\r\n\r\n                NT_ASSERT(targetPortGroupEntry);\r\n\r\n                if (targetPortGroupEntry) {\r\n\r\n                    //\r\n                    // Look through the target port group to find the target port\r\n                    //\r\n                    targetPortEntry = DsmpFindTargetPort(DsmContext,\r\n                                                         targetPortGroupEntry,\r\n                                                         relativeTargetPortId);\r\n                } else {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmInquire (DevObj %p): Couldn't find TPG Id %x's entry.\\n\",\r\n                                TargetDevice,\r\n                                *targetPortGroupId));\r\n\r\n                    status = STATUS_NOT_SUPPORTED;\r\n                    goto __Exit_DsmInquire;\r\n                }\r\n\r\n                NT_ASSERT(targetPortEntry);\r\n\r\n                if (!targetPortEntry) {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmInquire (DevObj %p): Couldn't find relative TP %x's entry.\\n\",\r\n                                TargetDevice,\r\n                                *relativeTargetPortId));\r\n\r\n                    status = STATUS_NOT_SUPPORTED;\r\n                    goto __Exit_DsmInquire;\r\n                }\r\n\r\n                //\r\n                // Update the devInfo with the target port and target port group\r\n                // info\r\n                //\r\n                deviceInfo->TargetPortGroup = targetPortGroupEntry;\r\n                deviceInfo->TargetPort = targetPortEntry;\r\n                deviceInfo->PreviousState = deviceInfo->State;\r\n                deviceInfo->State = deviceInfo->ALUAState = deviceInfo->TargetPortGroup->AsymmetricAccessState;\r\n\r\n                tp_device = DsmpAllocatePool(NonPagedPoolNx,\r\n                                             sizeof(DSM_TARGET_PORT_DEVICELIST_ENTRY),\r\n                                             DSM_TAG_TP_DEVICE_LIST_ENTRY);\r\n\r\n                if (!tp_device) {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmInquire (DevObj %p): Insufficient resources allocating TP device list entry.\\n\",\r\n                                TargetDevice));\r\n\r\n                    status = STATUS_NOT_SUPPORTED;\r\n                    goto __Exit_DsmInquire;\r\n                }\r\n\r\n                //\r\n                // Add the device to the list of devices that are exposed via this target port.\r\n                //\r\n                tp_device->DeviceInfo = deviceInfo;\r\n                InterlockedIncrement((LONG volatile*)&targetPortEntry->Count);\r\n                InsertTailList(&targetPortEntry->TP_DeviceList, &tp_device->ListEntry);\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to retrieve TPG Id.\\n\",\r\n                            TargetDevice));\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // Add the deviceInfo to the list.  DO NOT modify the status\r\n            // variable if this function returns SUCCESS.\r\n            //\r\n            status = DsmpAddDeviceEntry(DsmContext,\r\n                                        group,\r\n                                        deviceInfo);\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                *DsmIdentifier = deviceInfo;\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Added device %p to group %p.\\n\",\r\n                            TargetDevice,\r\n                            *DsmIdentifier,\r\n                            group));\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to add device %p to group %p - status %x.\\n\",\r\n                            TargetDevice,\r\n                            deviceInfo,\r\n                            group,\r\n                            status));\r\n\r\n                //\r\n                // We weren't able to add this deviceInfo to the list so we must\r\n                // remove its entry on the target port list before the deviceInfo\r\n                // is freed.\r\n                //\r\n                DsmpRemoveDeviceFromTargetPortList(deviceInfo);\r\n\r\n                if (newGroup) {\r\n\r\n                    DsmpRemoveGroupEntry(DsmContext, group, FALSE);\r\n\r\n                    DsmpFreePool(group);\r\n                    group = NULL;\r\n                }\r\n\r\n                status = STATUS_NOT_SUPPORTED;\r\n                goto __Exit_DsmInquire;\r\n            }\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n    spinlockHeld = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmInquire (DevObj %p): Device %p added. State %d, Desired State %d\\n\",\r\n                TargetDevice,\r\n                deviceInfo,\r\n                deviceInfo->State,\r\n                deviceInfo->DesiredState));\r\n\r\n    //\r\n    // Update the global list of controller objects\r\n    //\r\n    controllerObjects = DsmGetAssociatedDevice(dsmContext->MPIOContext,\r\n                                               PortObject,\r\n                                               0x0C);\r\n    if (controllerObjects) {\r\n\r\n        //\r\n        // This loop needs its own status variable so that it does not\r\n        // inadvertently overwrite a STATUS_SUCCESS from the code above.\r\n        //\r\n        NTSTATUS matchStatus = STATUS_SUCCESS;\r\n        PSCSI_ADDRESS controllerScsiAddress = NULL;\r\n\r\n        //\r\n        // Walk through the list and get VPD 0x83 data and associate the devInfo\r\n        // with the controller object.\r\n        //\r\n        for (index = 0; index < controllerObjects->Count; index++) {\r\n\r\n            STORAGE_IDENTIFIER_CODE_SET codeSet = StorageIdCodeSetReserved;\r\n\r\n            //\r\n            // Free the previously allocated SCSI address, if any.\r\n            //\r\n            if (controllerScsiAddress) {\r\n                DsmpFreePool(controllerScsiAddress);\r\n                controllerScsiAddress = NULL;\r\n            }\r\n\r\n            controllerDeviceObject = (PDEVICE_OBJECT)controllerObjects->IdList[index];\r\n            NT_ASSERT(controllerDeviceObject);\r\n\r\n            if (!controllerDeviceObject) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Controller list %p's index %x is NULL.\\n\",\r\n                            TargetDevice,\r\n                            controllerObjects,\r\n                            index));\r\n\r\n                continue;\r\n            }\r\n\r\n            matchStatus = DsmpGetDeviceIdList(controllerDeviceObject, &controllerIdHeader);\r\n            NT_ASSERT(NT_SUCCESS(matchStatus));\r\n\r\n            if (!NT_SUCCESS(matchStatus)) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to get DeviceId list for controller %p - status %x.\\n\",\r\n                            TargetDevice,\r\n                            controllerDeviceObject,\r\n                            matchStatus));\r\n\r\n                continue;\r\n            }\r\n\r\n            controllerSerialNumber = DsmpParseDeviceID((PSTORAGE_DEVICE_ID_DESCRIPTOR)controllerIdHeader,\r\n                                                       DSM_DEVID_SERIAL_NUMBER,\r\n                                                       NULL,\r\n                                                       &codeSet,\r\n                                                       FALSE);\r\n            NT_ASSERT(controllerSerialNumber);\r\n            DsmpFreePool(controllerIdHeader);\r\n\r\n            if (!controllerSerialNumber) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to parse serial number for controller %p.\\n\",\r\n                            TargetDevice,\r\n                            controllerDeviceObject));\r\n\r\n                continue;\r\n            }\r\n\r\n            //\r\n            // Note that on success, DsmGetScsiAddress() will allocate memory\r\n            // which we are responsible for freeing.\r\n            //\r\n            matchStatus = DsmGetScsiAddress(controllerDeviceObject, &controllerScsiAddress);\r\n            NT_ASSERT(NT_SUCCESS(matchStatus));\r\n\r\n            if (!NT_SUCCESS(matchStatus)) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to get controller %p's scsi address - status %x.\\n\",\r\n                            TargetDevice,\r\n                            controllerDeviceObject,\r\n                            matchStatus));\r\n\r\n                continue;\r\n            }\r\n\r\n            controllerEntry = DsmpFindControllerEntry(DsmContext,\r\n                                                      PortObject,\r\n                                                      controllerScsiAddress,\r\n                                                      controllerSerialNumber,\r\n                                                      strlen(controllerSerialNumber),\r\n                                                      codeSet,\r\n                                                      TRUE);\r\n\r\n            if (!controllerEntry) {\r\n\r\n                controllerEntry = DsmpBuildControllerEntry(DsmContext,\r\n                                                           controllerDeviceObject,\r\n                                                           PortObject,\r\n                                                           controllerScsiAddress,\r\n                                                           controllerSerialNumber,\r\n                                                           codeSet,\r\n                                                           TRUE);\r\n\r\n                if (!controllerEntry) {\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmInquire (DevObj %p): Failed to build an entry for controller %p.\\n\",\r\n                                TargetDevice,\r\n                                controllerDeviceObject));\r\n\r\n                    continue;\r\n                }\r\n\r\n                InsertHeadList(&dsmContext->ControllerList, &controllerEntry->ListEntry);\r\n                InterlockedIncrement((LONG volatile*)&dsmContext->NumberControllers);\r\n            }\r\n\r\n            controllerEntry->DeviceObject = controllerDeviceObject;\r\n\r\n            //\r\n            // Parse the DeviceIdList for all the 0x5 type identifiers\r\n            // and for each, compare the target port groups and target ports to match\r\n            // the device to its controller.\r\n            //\r\n            if (!match) {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmInquire (DevObj %p): Failed to match devInfo %p with controller %p's Ids.\\n\",\r\n                            TargetDevice,\r\n                            deviceInfo,\r\n                            controllerDeviceObject));\r\n\r\n                match = DsmpIsDeviceBelongsToController(DsmContext,\r\n                                                        deviceInfo,\r\n                                                        controllerEntry);\r\n            }\r\n\r\n            if (match && !doneUpdating) {\r\n\r\n                InterlockedIncrement((LONG volatile*)&(controllerEntry->RefCount));\r\n                deviceInfo->Controller = controllerEntry;\r\n                doneUpdating = TRUE;\r\n            }\r\n        }\r\n\r\n        //\r\n        // Free the last SCSI address allocated in the loop, if any.\r\n        //\r\n        if (controllerScsiAddress) {\r\n            DsmpFreePool(controllerScsiAddress);\r\n            controllerScsiAddress = NULL;\r\n        }\r\n    }\r\n\r\n    //\r\n    // If there was no controller to associate this device with, use a fake one.\r\n    // Note that we only really care about matching on the Port and Target\r\n    // portions of the SCSI address.\r\n    //\r\n    if (!deviceInfo->Controller) {\r\n\r\n        for (entry = dsmContext->ControllerList.Flink;\r\n             entry != &dsmContext->ControllerList;\r\n             entry = entry->Flink) {\r\n\r\n            controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry);\r\n\r\n            if ((controllerEntry->IsFakeController) &&\r\n                (controllerEntry->ScsiAddress->PortNumber == deviceInfo->ScsiAddress->PortNumber) &&\r\n                (controllerEntry->ScsiAddress->TargetId == deviceInfo->ScsiAddress->TargetId)) {\r\n\r\n                fakeControllerEntryExists = TRUE;\r\n                break;\r\n            }\r\n        }\r\n\r\n        //\r\n        // If no fake one exists as yet for this port FDO, create one now.\r\n        //\r\n        if (!fakeControllerEntryExists) {\r\n\r\n            CHAR fakeControllerSerialNumber[] = \"FakeController\";\r\n            SCSI_ADDRESS fakeControllerScsiAddress = {0};\r\n            fakeControllerScsiAddress.PortNumber = deviceInfo->ScsiAddress->PortNumber;\r\n            fakeControllerScsiAddress.TargetId = deviceInfo->ScsiAddress->TargetId;\r\n\r\n            controllerEntry = DsmpBuildControllerEntry(DsmContext,\r\n                                                       NULL,\r\n                                                       PortObject,\r\n                                                       &fakeControllerScsiAddress,\r\n                                                       fakeControllerSerialNumber,\r\n                                                       StorageIdCodeSetBinary,\r\n                                                       TRUE);\r\n\r\n            if (controllerEntry) {\r\n\r\n                InsertHeadList(&dsmContext->ControllerList, &controllerEntry->ListEntry);\r\n                InterlockedIncrement((LONG volatile*)&dsmContext->NumberControllers);\r\n                controllerEntry->IsFakeController = TRUE;\r\n            }\r\n        }\r\n\r\n        if (controllerEntry) {\r\n            InterlockedIncrement((LONG volatile*)&(controllerEntry->RefCount));\r\n        }\r\n\r\n        deviceInfo->Controller = controllerEntry;\r\n    }\r\n\r\n__Exit_DsmInquire:\r\n\r\n    if (spinlockHeld) {\r\n        ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        NT_ASSERT(*DsmIdentifier);\r\n\r\n    } else {\r\n\r\n        //\r\n        // If there was any sort of ERROR, the deviceInfo will NOT be put on\r\n        // MSDSM's internal list that is accessible to other threads.  Thus,\r\n        // we are safe to free the memory below and we do not require any\r\n        // synchronization mechanism to do so.\r\n        //\r\n\r\n        //\r\n        // Check to see whether the serial number buffer was allocated, or just\r\n        // an offset into the Descriptor.\r\n        //\r\n        if (serialNumberAllocated) {\r\n\r\n            //\r\n            // Need to free this before returning.\r\n            //\r\n            DsmpFreePool(serialNumber);\r\n        }\r\n\r\n        if (deviceInfo) {\r\n\r\n            if (deviceInfo->ScsiAddress) {\r\n                DsmpFreePool(deviceInfo->ScsiAddress);\r\n            }\r\n\r\n            DsmpFreePool(deviceInfo);\r\n        }\r\n    }\r\n\r\n    //\r\n    // If deviceName is not NULL then it hasn't been assigned to any GROUP.\r\n    // Free the allocated memory.\r\n    //\r\n    if (deviceName) {\r\n        DsmpFreePool(deviceName);\r\n    }\r\n\r\n    //\r\n    // If hardwareId is not NULL then it hasn't been assigned to any GROUP.\r\n    // Free the allocated memory.\r\n    //\r\n    if (hardwareId) {\r\n        DsmpFreePool(hardwareId);\r\n    }\r\n\r\n    if (targetPortGroupsInfo) {\r\n        DsmpFreePool(targetPortGroupsInfo);\r\n    }\r\n\r\n    if (relativeTargetPortId) {\r\n        DsmpFreePool(relativeTargetPortId);\r\n    }\r\n\r\n    if (targetPortGroupId) {\r\n        DsmpFreePool(targetPortGroupId);\r\n    }\r\n\r\n    if (controllerObjects) {\r\n        DsmpFreePool(controllerObjects);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmInquire (DevObj %p): Exiting function with status %x.\\n\",\r\n                TargetDevice,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmCompareDevices(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId1,\r\n    _In_ IN PVOID DsmId2\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called to determine if the device ids represent\r\n    the same underlying physical device.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    DsmId1/2 - Identifers returned from DMS_INQUIRE_DRIVER.\r\n\r\nReturn Value:\r\n\r\n    TRUE if DsmIds correspond to the same underlying device.\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo0 = DsmId1;\r\n    PDSM_DEVICE_INFO deviceInfo1 = DsmId2;\r\n    PSTR serialNumber0;\r\n    PSTR serialNumber1;\r\n    SIZE_T length;\r\n    BOOLEAN match = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmCompareDevices (DevInfo %p): Entering function - comparing with %p.\\n\",\r\n                deviceInfo0,\r\n                deviceInfo1));\r\n\r\n    //\r\n    // Get the two serial numbers. They were either embedded in\r\n    // the STORAGE_DEVICE_DESCRIPTOR or built by directly issuing\r\n    // the VPD request.\r\n    //\r\n    serialNumber0 = deviceInfo0->SerialNumber;\r\n    serialNumber1 = deviceInfo1->SerialNumber;\r\n\r\n    if (serialNumber0 && serialNumber1) {\r\n\r\n        //\r\n        // Get the length of the base-device Serial Number.\r\n        //\r\n        length = strlen((const char*)serialNumber0);\r\n\r\n        //\r\n        // If the lengths match, compare the contents.\r\n        //\r\n        if (length == strlen((const char*)serialNumber1)) {\r\n\r\n            if (RtlEqualMemory(serialNumber0, serialNumber1, length)) {\r\n                match = TRUE;\r\n            }\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmCompareDevices (DevInfo %p): Serialnumber not assigned for %p and\\\\or %p.\\n\",\r\n                    DsmId1,\r\n                    deviceInfo0,\r\n                    deviceInfo1));\r\n    }\r\n\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmCompareDevices (DevInfo %p): Exiting function with match = %!bool!.\\n\",\r\n                DsmId1,\r\n                match));\r\n\r\n    return match;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmGetControllerInfo(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN ULONG Flags,\r\n    _Inout_ IN OUT PCONTROLLER_INFO *ControllerInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to get information about the controller that\r\n    the device corresponding to DsmId in on. Currently this DSM controls\r\n    hardware that doesn't expose controllers directly. Therefore State\r\n    is always NO_CNTRL. This information is used mainly by whatever\r\n    WMI admin utilities want it.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n\r\n    DsmId - Value returned from DMSInquireDriver.\r\n\r\n    Flags - Bitfield of modifiers. If ALLOCATE is not set, ControllerInfo\r\n            will have a valid buffer for the DSM to operate on.\r\n\r\n    ControllerInfo - Pointer  for  the DSM to place the allocated controller\r\n                     info pertaining to DsmId\r\n\r\nReturn Value:\r\n\r\n    STATUS_INSUFFICIENT_RESOURCES if memory allocation fails.\r\n\r\n    STATUS_SUCCESS on success\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PDSM_CONTROLLER_LIST_ENTRY controllerEntry = deviceInfo->Controller;\r\n    PCONTROLLER_INFO controllerInfo = NULL;\r\n    LARGE_INTEGER time;\r\n    ULONG controllerId = 0;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmGetControllerInfo (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    //\r\n    // Check to see whether a controller id has already been made-up.\r\n    //\r\n    if (!controllerEntry) {\r\n\r\n        //\r\n        // Since this device is in an enclosure that doesn't have controllers,\r\n        // e.g. JBOD, make one up.\r\n        //\r\n        KeQuerySystemTime(&time);\r\n\r\n        //\r\n        // Use only the lower 32-bits.\r\n        //\r\n        controllerId = time.LowPart;\r\n    }\r\n\r\n    //\r\n    // Check the Flags\r\n    //\r\n    if (Flags & DSM_CNTRL_FLAGS_ALLOCATE) {\r\n\r\n        //\r\n        // This is the first call. Need to allocate the controller structure.\r\n        //\r\n        controllerInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                          sizeof(CONTROLLER_INFO),\r\n                                          DSM_TAG_CTRL_INFO);\r\n        if (!controllerInfo) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmGetControllerInfo (DevInfo %p): Failed to allocate memory for Controller Info\\n\",\r\n                        DsmId));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            goto __Exit_DsmGetControllerInfo;\r\n        }\r\n\r\n        if (!controllerEntry) {\r\n\r\n            //\r\n            // Indicate that there are no specific controllers.\r\n            //\r\n            controllerInfo->State = DSM_CONTROLLER_NO_CNTRL;\r\n\r\n            //\r\n            // Set the identifier to the value generated earlier.\r\n            // Indicate that it's Binary, not ASCII.\r\n            //\r\n            controllerInfo->Identifier.Type = StorageIdCodeSetBinary;\r\n            controllerInfo->Identifier.Length = 8;\r\n\r\n            RtlCopyMemory(controllerInfo->Identifier.SerialNumber,\r\n                          &controllerId,\r\n                          sizeof(controllerId));\r\n\r\n        } else {\r\n\r\n            //\r\n            // If either implicit or explicit ALUA state transition is supported,\r\n            // every controller is active. Else, if the devInfo's is in Active\r\n            // state, the controller is obviously in the active state.\r\n            //\r\n            if ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED) ||\r\n                (DsmpIsDeviceStateActive(deviceInfo->State))) {\r\n\r\n                controllerInfo->State = DSM_CONTROLLER_ACTIVE;\r\n\r\n            } else {\r\n\r\n                controllerInfo->State = DSM_CONTROLLER_STANDBY;\r\n            }\r\n\r\n            controllerInfo->Identifier.Type = controllerEntry->IdCodeSet;\r\n            controllerInfo->Identifier.Length = controllerEntry->IdLength;\r\n\r\n            if (controllerInfo->Identifier.Length > 32) {\r\n\r\n                controllerInfo->Identifier.Length = 32;\r\n            }\r\n\r\n            RtlCopyMemory(controllerInfo->Identifier.SerialNumber,\r\n                          controllerEntry->Identifier,\r\n                          controllerInfo->Identifier.Length);\r\n\r\n            controllerInfo->DeviceObject = controllerEntry->DeviceObject;\r\n        }\r\n\r\n        *ControllerInfo = controllerInfo;\r\n\r\n    } else if (Flags & DSM_CNTRL_FLAGS_CHECK_STATE) {\r\n\r\n        //\r\n        // Get the passed in struct.\r\n        //\r\n        controllerInfo = *ControllerInfo;\r\n\r\n        //\r\n        // If the enclosures supported by this DSM actually had controllers,\r\n        // there would be a list of them and a search based on\r\n        // ControllerIdentifier would be made.\r\n        //\r\n        controllerEntry = deviceInfo->Controller;\r\n\r\n        if (!controllerEntry) {\r\n\r\n            controllerInfo->State = DSM_CONTROLLER_NO_CNTRL;\r\n\r\n        } else {\r\n\r\n            //\r\n            // If either implicit or explicit ALUA state transition is supported,\r\n            // every controller is active. Else, if the devInfo's is in Active\r\n            // state, the controller is obviously in the active state.\r\n            //\r\n            if ((deviceInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED) ||\r\n                (DsmpIsDeviceStateActive(deviceInfo->State))) {\r\n\r\n                controllerInfo->State = DSM_CONTROLLER_ACTIVE;\r\n\r\n            } else {\r\n\r\n                controllerInfo->State = DSM_CONTROLLER_STANDBY;\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmGetControllerInfo:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmGetControllerInfo (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DsmId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmSetDeviceInfo(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDEVICE_OBJECT TargetObject,\r\n    _In_ IN PVOID DsmId,\r\n    _Inout_ IN OUT PVOID *PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine associates the DsmId to the controlling MPDisk PDO,\r\n    the targetObject for DSM-initiated requests, and to a Path\r\n    (given by PathId).\r\n    This routine will update the PathId in a way that better explains\r\n    the topology to MPIO.\r\n    Additionally, if we are in failover LB policy, failback if this\r\n    path is preferred path.\r\n    Also, if PR is being used, send registration down this path.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    TargetObject - The D.O. to which DSM-initiated requests should be sent.\r\n    DsmId - Value returned from DMSInquireDriver.\r\n    PathId - Id that represents the path. The value passed in may be used\r\n             as is, or the DSM optionally can update it if it requires\r\n             additional state info to be kept.\r\n\r\nReturn Value:\r\n\r\n    INSUFFICENT_RESOURCES for no-mem conditions.\r\n    STATUS_SUCCESS\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n    PDSM_FAILOVER_GROUP failGroup;\r\n    PDSM_CONTEXT dsmContext;\r\n    PSCSI_ADDRESS scsiAddress;\r\n    ULONG primaryPath = 0;\r\n    ULONG optimizedPath = 0;\r\n    ULONG pathWeight = 0;\r\n    ULONG pathId;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    WCHAR registryKeyName[256] = {0};\r\n    BOOLEAN newFOGroup = FALSE;\r\n    BOOLEAN registryKeyExists = FALSE;\r\n    KIRQL irql;\r\n    PVOID tempPathId = *PathId;\r\n    DSM_LOAD_BALANCE_TYPE loadBalanceType;\r\n    ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n    UCHAR explicitlySet = FALSE;\r\n    BOOLEAN vidpidPolicySet = FALSE;\r\n    BOOLEAN overallPolicySet = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmSetDeviceInfo (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    //\r\n    //  1. Set default LB policy.\r\n    //  2. Query LB policy from registry and update if necessary.\r\n    //  3. Set default value for primaryPath and optimizedPath based on device's\r\n    //     access state\r\n    //  4. Map deviceInfo to real LUN by saving off the target for I/O\r\n    //  5. Build pathId from SCSI address\r\n    //  6. Find FOG for device. If none found, build one.\r\n    //       Add deviceInfo to FOG.\r\n    //  7. Query registry for pathWeight, primaryPath and optimizedPath\r\n    //       Update deviceInfo with results of query.\r\n    //  8. Compare deviceInfo access state with persistent value (based on\r\n    //     primaryPath and optimizedPath) and update its DesiredState.\r\n    //\r\n\r\n    if (!TargetObject) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmSetDeviceInfo (DevInfo %p): No target object.\\n\",\r\n                    deviceInfo));\r\n\r\n        //\r\n        // This deviceInfo will have no path or targetObject associated with it.\r\n        // Mark it in a failed state so it won't be used to handle any requests.\r\n        //\r\n        deviceInfo->PreviousState = deviceInfo->State;\r\n        deviceInfo->State = DSM_DEV_UNDETERMINED;\r\n\r\n        goto __Exit_DsmSetDeviceInfo;\r\n    }\r\n\r\n    //\r\n    // Default LB type is Round Robin.\r\n    //\r\n    loadBalanceType = DSM_LB_ROUND_ROBIN;\r\n\r\n    //\r\n    // Override the default with whatever is the overall policy that needs to be\r\n    // applied for all LUNs controlled by MSDSM.\r\n    //\r\n    // Override that policy if one has been set for this device's VID/PID.\r\n    //\r\n    // Override that policy with whatever has been explicitly set for this particular\r\n    // device.\r\n    //\r\n    // In order to perform the above, first query the policy for this particular device.\r\n    // If it has not been explicity set, use MSDSM's overall policy or VID/PID policy.\r\n    //\r\n    status = DsmpQueryDeviceLBPolicyFromRegistry(deviceInfo,\r\n                                                 group->RegistryKeyName,\r\n                                                 &loadBalanceType,\r\n                                                 &preferredPath,\r\n                                                 &explicitlySet);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmSetDeviceInfo (DevInfo %p): Failed to query LB policy from registry. Status %x.\\n\",\r\n                    deviceInfo,\r\n                    status));\r\n\r\n        NT_ASSERT(NT_SUCCESS(status));\r\n\r\n        //\r\n        // This deviceInfo will have no path or targetObject associated with it.\r\n        // Mark it in a failed state so it won't be used to handle any requests.\r\n        //\r\n        deviceInfo->PreviousState = deviceInfo->State;\r\n        deviceInfo->State = DSM_DEV_UNDETERMINED;\r\n\r\n        goto __Exit_DsmSetDeviceInfo;\r\n    }\r\n\r\n    //\r\n    // If this device's policy was not explicitly set, check to see if a policy\r\n    // was set for this device's VID/PID and use that.\r\n    // If VID/PID policy is not set, query the overall default policy\r\n    // that needs to be applied to all devices controlled by this DSM.\r\n    // If this setting hasn't been set, we'll fall back to using the default that was\r\n    // determined based on the storage's ALUA capabilities.\r\n    //\r\n    if (!explicitlySet) {\r\n\r\n        status = DsmpQueryTargetLBPolicyFromRegistry(deviceInfo,\r\n                                                     &loadBalanceType,\r\n                                                     &preferredPath);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID;\r\n            vidpidPolicySet = TRUE;\r\n\r\n        } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n            //\r\n            // Since the policy hasn't been set for this VID/PID, check if\r\n            // overall MSDSM-wide policy has been set.\r\n            //\r\n            status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType,\r\n                                                      &preferredPath);\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE;\r\n                overallPolicySet = TRUE;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmSetDeviceInfo (DevInfo %p): Failed to query Dsm overall LB policy from registry. Status %x.\\n\",\r\n                            deviceInfo,\r\n                            status));\r\n\r\n                NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND);\r\n                status = STATUS_SUCCESS;\r\n            }\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmSetDeviceInfo (DevInfo %p): Failed to query VID/PID LB policy from registry. Status %x.\\n\",\r\n                        deviceInfo,\r\n                        status));\r\n\r\n            NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND);\r\n            status = STATUS_SUCCESS;\r\n        }\r\n    } else {\r\n\r\n        group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT;\r\n    }\r\n\r\n    if (!explicitlySet && !vidpidPolicySet && !overallPolicySet) {\r\n\r\n        group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY;\r\n\r\n    }\r\n\r\n    //\r\n    // If ALUA is enabled and the load balance policy is set to Round Robin,\r\n    // we need to set it to Round Robin with Subset instead.\r\n    //\r\n    if (!DsmpIsSymmetricAccess(deviceInfo) && loadBalanceType == DSM_LB_ROUND_ROBIN) {\r\n        loadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n    }\r\n\r\n    group->LoadBalanceType = loadBalanceType;\r\n    group->PreferredPath = preferredPath;\r\n    dsmContext = (PDSM_CONTEXT) DsmContext;\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n\r\n    //\r\n    // Save the registry key name under which Load balance policies\r\n    // are stored. This will be used to query the LB policy later.\r\n    //\r\n    if (group->RegistryKeyName) {\r\n\r\n        registryKeyExists = TRUE;\r\n\r\n        if (!NT_SUCCESS(RtlStringCchCopyNW(registryKeyName,\r\n                                           sizeof(registryKeyName) / sizeof(registryKeyName[0]),\r\n                                           group->RegistryKeyName,\r\n                                           ((sizeof(registryKeyName) / sizeof(registryKeyName[0])) - sizeof(WCHAR))))) {\r\n\r\n            registryKeyName[(sizeof(registryKeyName) / sizeof(registryKeyName[0])) - 1] = L'\\0';\r\n        }\r\n    }\r\n\r\n    //\r\n    // TargetObject is the destination for any requests created by this driver.\r\n    // Save this for future reference.\r\n    //\r\n    deviceInfo->TargetObject = TargetObject;\r\n\r\n    //\r\n    // Set the PathId - All devices on the same PathId will\r\n    // failover together. Currently the pathId is constructed\r\n    // from Port Number, Bus Number, and Target Id of the device.\r\n    //\r\n    scsiAddress = deviceInfo->ScsiAddress;\r\n    NT_ASSERT(scsiAddress);\r\n\r\n    pathId = 0x77;\r\n    pathId <<= 8;\r\n    pathId |= scsiAddress->PortNumber;\r\n    pathId <<= 8;\r\n    pathId |= scsiAddress->PathId;\r\n    pathId <<= 8;\r\n    pathId |= scsiAddress->TargetId;\r\n\r\n    *PathId = ((PVOID)((ULONG_PTR)(pathId)));\r\n\r\n    //\r\n    // PathId indicates the path on which this device resides. Meaning\r\n    // that when a Fail-Over occurs all device's on the same path fail\r\n    // together. Search for a matching F.O. Group\r\n    //\r\n    failGroup = DsmpFindFOGroup(DsmContext, *PathId);\r\n\r\n    //\r\n    // If not found, create a new failover group\r\n    //\r\n    if (!failGroup) {\r\n\r\n        failGroup = DsmpBuildFOGroup(DsmContext, deviceInfo, PathId);\r\n\r\n        if (failGroup) {\r\n\r\n            newFOGroup = TRUE;\r\n            failGroup->MPIOPath = tempPathId;\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmSetDeviceInfo (DevInfo %p): Failed to build FO Group.\\n\",\r\n                        DsmId));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // If this path is in the midst of failover processing, mark it as \"good\"\r\n        // again.\r\n        //\r\n        failGroup->State = DSM_FG_NORMAL;\r\n\r\n        //\r\n        // add this deviceInfo to the f.o. group.\r\n        //\r\n        status = DsmpUpdateFOGroup(DsmContext, failGroup, deviceInfo);\r\n        NT_ASSERT(NT_SUCCESS(status));\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        if (registryKeyExists) {\r\n\r\n            NTSTATUS queryStatus = STATUS_INVALID_PARAMETER;\r\n            ULONGLONG pathId64;\r\n\r\n            //\r\n            // If the overall default policy or a target-level policy has been set and\r\n            // this device's policy has not been explicitly set, there's no use querying\r\n            // its individual path (desired) states.\r\n            //\r\n            if ((!overallPolicySet && !vidpidPolicySet) || (explicitlySet)) {\r\n\r\n                //\r\n                // Created a new failover group. Query the LB policy\r\n                // for this device from registry.\r\n                //\r\n                pathId64 = (ULONGLONG)((ULONG_PTR)*PathId);\r\n\r\n                queryStatus = DsmpQueryLBPolicyForDevice(registryKeyName,\r\n                                                         pathId64,\r\n                                                         loadBalanceType,\r\n                                                         &primaryPath,\r\n                                                         &optimizedPath,\r\n                                                         &pathWeight);\r\n            }\r\n\r\n            irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n\r\n            if (NT_SUCCESS(queryStatus)) {\r\n\r\n                deviceInfo->PathWeight = pathWeight;\r\n\r\n                //\r\n                // If device doesn't support ALUA, update the device state\r\n                // based on the primary path info in the registry.\r\n                //\r\n                if (DsmpIsSymmetricAccess(deviceInfo)) {\r\n\r\n                    if (primaryPath) {\r\n\r\n                        deviceInfo->DesiredState = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                    } else {\r\n\r\n                        deviceInfo->DesiredState = DSM_DEV_STANDBY;\r\n                    }\r\n\r\n                } else {\r\n\r\n                    DSM_DEVICE_STATE devState;\r\n\r\n                    if (primaryPath) {\r\n\r\n                        devState = optimizedPath ? DSM_DEV_ACTIVE_OPTIMIZED : DSM_DEV_ACTIVE_UNOPTIMIZED;\r\n\r\n                    } else {\r\n\r\n                        devState = optimizedPath ? DSM_DEV_STANDBY : DSM_DEV_UNAVAILABLE;\r\n                    }\r\n\r\n                    //\r\n                    // For ALUA, desired state makes sense for FOO.\r\n                    // For RRWS, we assume desired state was explicitly selected\r\n                    // by Admin if the ALUA state is different from the path\r\n                    // state. Only under such cases would the path state have\r\n                    // been saved in registry.\r\n                    // In all other policies, state must just match the TPG state.\r\n                    //\r\n                    if (group->LoadBalanceType == DSM_LB_FAILOVER ||\r\n                        group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET) {\r\n\r\n                        deviceInfo->DesiredState = devState;\r\n\r\n                    } else {\r\n\r\n                        deviceInfo->DesiredState = DSM_DEV_UNDETERMINED;\r\n                    }\r\n                }\r\n            } else if (queryStatus == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n                deviceInfo->PathWeight = pathWeight;\r\n                deviceInfo->DesiredState = DSM_DEV_UNDETERMINED;\r\n\r\n            } else {\r\n\r\n                deviceInfo->PathWeight = 0;\r\n                deviceInfo->DesiredState = DSM_DEV_UNDETERMINED;\r\n            }\r\n\r\n            ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmSetDeviceInfo (DevInfo %p): PathWeight %x, DesiredState %x, State %x, PrevState %x.\\n\",\r\n                deviceInfo,\r\n                deviceInfo->PathWeight,\r\n                deviceInfo->DesiredState,\r\n                deviceInfo->State,\r\n                deviceInfo->PreviousState));\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        deviceInfo->Initialized = TRUE;\r\n\r\n    } else if (!NT_SUCCESS(status) && newFOGroup) {\r\n\r\n        //\r\n        // This deviceInfo will have no path associated with it.\r\n        // Mark it in a failed state so it won't be used to handle any requests.\r\n        //\r\n        deviceInfo->PreviousState = deviceInfo->State;\r\n        deviceInfo->State = DSM_DEV_UNDETERMINED;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmSetDeviceInfo (DevInfo %p): No path associated with instance. Changing state from %u to %u.\\n\",\r\n                    deviceInfo,\r\n                    deviceInfo->PreviousState,\r\n                    deviceInfo->State));\r\n\r\n        DsmpRemoveDeviceFailGroup(DsmContext, failGroup, deviceInfo, TRUE);\r\n\r\n        if (failGroup->Count == 0) {\r\n\r\n            //\r\n            // Yank it from the list.\r\n            //\r\n            RemoveEntryList(&failGroup->ListEntry);\r\n            InterlockedDecrement((LONG volatile*)&dsmContext->NumberFOGroups);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmSetDeviceInfo (DevInfo %p): Removing FOGroup %p with path %p. Count of FOGroups %d.\\n\",\r\n                        DsmId,\r\n                        failGroup,\r\n                        failGroup->PathId,\r\n                        dsmContext->NumberFOGroups));\r\n\r\n            //\r\n            // Free the zombie group list and then the failover group.\r\n            //\r\n            DsmpFreeZombieGroupList(failGroup);\r\n            DsmpFreePool(failGroup);\r\n        }\r\n    }\r\n\r\n__Exit_DsmSetDeviceInfo:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmSetDeviceInfo (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DsmId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmIsPathActive(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID PathId,\r\n    _In_ IN PVOID DsmId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to determine whether the path to DsmId is usable\r\n    (ie. able to handle requests without a failover).\r\n\r\n    Also, after a failover, the path validity will be queried.\r\n    If the path error was transitory and the DSM feels that the path is good,\r\n    then this request will be re-issued to determine whether it is usable.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    PathId - Value set in SetPathId.\r\n    DsmId - DSM Id returned during DsmInquire.\r\n\r\nReturn Value:\r\n\r\n    TRUE if the path is active. FALSE otherwise.\r\n--*/\r\n{\r\n    PDSM_FAILOVER_GROUP foGroup;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n    PDSM_CONTEXT dsmContext = (PDSM_CONTEXT) DsmContext;\r\n    KIRQL irql;\r\n    BOOLEAN retVal;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    //\r\n    //  1. If PR and reserved by this node, register the PR keys.\r\n    //  2. Find the FOG for the passed in PathId\r\n    //  3. Depending on the LB policy, set the appropriate devInfo states\r\n    //        If FailOver, and DesiredState is AO, change the active\r\n    //        devInfos to non-active state and make this one AO.\r\n    //           If ALUA supported, send down SetTPG to make this change,\r\n    //               else directly make the change.\r\n    //        If RR/LWP/LQD, make this DevInfo ActiveOptimized.\r\n    //        If RRS, and DesiredState is AO, change the active devInfos to\r\n    //        their desired states and then make this one AO.\r\n    //           If DesiredState is not AO, find a devInfo in AO state. If\r\n    //           one is found, make this devInfo's state its desired state,\r\n    //           else if one isn't found, make this one AO.\r\n    //  3. If this is preferredPath, and LB policy is failover-only, change the\r\n    //     access state of deviceInfo to AO.\r\n    //       If there is another devInfo currently in AO, change its state too.\r\n    //       If ALUA supported, send down SetTPG to make these changes.\r\n    //  4. Get the appropriate AO DeviceInfo and mark the group's PTBU to its\r\n    //     pathId.\r\n    //\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmIsPathActive (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    //\r\n    // Initialize this instance to be usable so that during the possible processing\r\n    // of PR register, this device can be a candidate for certain kind of requests.\r\n    //\r\n    deviceInfo->Usable = TRUE;\r\n\r\n    //\r\n    // New path arriving. If this Node owns the reservation register this path.\r\n    //\r\n    if (group->PRKeyValid) {\r\n\r\n        NTSTATUS prRegStatus;\r\n        ULONG i;\r\n        PDSM_DEVICE_INFO devInfo;\r\n        ULONG ordinal;\r\n\r\n            prRegStatus = DsmpRegisterPersistentReservationKeys(deviceInfo, TRUE);\r\n\r\n        deviceInfo->RegisterServiced = TRUE;\r\n\r\n        if (NT_SUCCESS(prRegStatus)) {\r\n\r\n            deviceInfo->PRKeyRegistered = TRUE;\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmIsPathActive (DevInfo %p): Failed (status %x) to register PR key\\n\",\r\n                        deviceInfo,\r\n                        prRegStatus));\r\n        }\r\n\r\n        for (i = 0; i < group->NumberDevices; i++) {\r\n\r\n            devInfo = group->DeviceList[i];\r\n            if (devInfo && devInfo == deviceInfo) {\r\n\r\n                ordinal = (1 << i);\r\n                group->ReservationList |= ordinal;\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n\r\n    //\r\n    // Get the F.O. Group information.\r\n    //\r\n    foGroup = DsmpFindFOGroup(DsmContext, PathId);\r\n\r\n    //\r\n    // If there are any devices on this path, and it's not in a failed state\r\n    // it's capable of handling requests. So it's active.\r\n    //\r\n    if ((foGroup) &&\r\n        (foGroup->Count) &&\r\n        (foGroup->State == DSM_FG_NORMAL)) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmIsPathActive (DevInfo %p): Path %p is usable.\\n\",\r\n                    DsmId,\r\n                    PathId));\r\n\r\n        retVal = TRUE;\r\n\r\n        //\r\n        // Update the next path to be used for the group if it not set already.\r\n        //\r\n        deviceInfo = (PDSM_DEVICE_INFO)DsmId;\r\n\r\n        group = deviceInfo->Group;\r\n        DSM_ASSERT(group != NULL);\r\n        DSM_ASSERT(group->GroupSig == DSM_GROUP_SIG);\r\n\r\n        //\r\n        // If an invalidated path came back online before PnP removes came in,\r\n        // then MPIO's path recovery thread would have sent down a PathVerify\r\n        // just moments before by which we changed the state of the FOG to\r\n        // normal. Now it is time to change the deviceInfo's state to a \"good\"\r\n        // state.\r\n        //\r\n        if (deviceInfo->State >= DSM_DEV_FAILED) {\r\n\r\n            DSM_ASSERT(deviceInfo->State == DSM_DEV_INVALIDATED);\r\n\r\n            if (DsmpIsSymmetricAccess(deviceInfo)) {\r\n\r\n                //\r\n                // Mark it as AO. The SetLBForPathArrival will update the state\r\n                // appropriately.\r\n                //\r\n                deviceInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n            } else {\r\n\r\n                //\r\n                // Set it to the state that was reported during the last RTPG\r\n                // call that was made.\r\n                //\r\n                deviceInfo->State = deviceInfo->ALUAState;\r\n            }\r\n        }\r\n\r\n        if (DsmpIsSymmetricAccess(deviceInfo)) {\r\n\r\n            DsmpSetLBForPathArrival(DsmContext, deviceInfo, SpecialHandlingFlag);\r\n\r\n        } else {\r\n\r\n            ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n            DsmpSetLBForPathArrivalALUA(DsmContext, deviceInfo, SpecialHandlingFlag);\r\n            irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmIsPathActive (DevInfo %p): State set to %d\\n\",\r\n                    deviceInfo,\r\n                    deviceInfo->State));\r\n\r\n        if (group->PathToBeUsed == NULL) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmIsPathActive (DevInfo %p): Will set PathToBeUsed for %p\\n\",\r\n                        deviceInfo,\r\n                        group));\r\n\r\n            deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                                   DsmpIsSymmetricAccess(deviceInfo),\r\n                                                   SpecialHandlingFlag);\r\n            if (deviceInfo != NULL) {\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmIsPathActive (DevInfo %p): FOG %p set for PathToBeUsed for %p\\n\",\r\n                            deviceInfo,\r\n                            deviceInfo->FailGroup,\r\n                            group));\r\n\r\n                InterlockedExchangePointer(&(group->PathToBeUsed), deviceInfo->FailGroup);\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmIsPathActive (DevInfo %p): No active/alternative path available for group %p\\n\",\r\n                            DsmId,\r\n                            group));\r\n\r\n                InterlockedExchangePointer(&(group->PathToBeUsed), NULL);\r\n            }\r\n        }\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmIsPathActive (DevInfo %p): Path %p is NOT usable.\\n\",\r\n                    DsmId,\r\n                    PathId));\r\n\r\n        retVal = FALSE;\r\n    }\r\n\r\n    ((PDSM_DEVICE_INFO)DsmId)->Usable = retVal;\r\n\r\n    ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmIsPathActive (DevInfo %p): Exiting function with retVal = %!bool!.\\n\",\r\n                DsmId,\r\n                retVal));\r\n\r\n    return retVal;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmPathVerify(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PVOID PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine ensures that the path to the device indicated by DsmId\r\n    is healthy. It's called periodically by the bus driver, and also\r\n    after a fail-over condition has been dealt with to ensure that\r\n    the path is able to handle requests.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    DsmId - Value returned from DMSInquire.\r\n    PathId - Value set in SetPathId.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS\r\n--*/\r\n\r\n{\r\n    PDSM_CONTEXT dsmCtxt = (PDSM_CONTEXT) DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PDSM_FAILOVER_GROUP foGroup;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n    BOOLEAN found = FALSE;\r\n    KIRQL irql;\r\n    PLIST_ENTRY entry;\r\n    PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL;\r\n    PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmPathVerify (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    if (DsmpIsDeviceInitialized(deviceInfo)) {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(dsmCtxt->DsmContextLock));\r\n\r\n        //\r\n        // Get the failover group\r\n        //\r\n        foGroup = DsmpFindFOGroup(DsmContext, PathId);\r\n\r\n        if (foGroup) {\r\n\r\n            //\r\n            // Find the device.\r\n            //\r\n            for (entry = foGroup->FOG_DeviceList.Flink;\r\n                 entry != &foGroup->FOG_DeviceList;\r\n                 entry = entry->Flink) {\r\n\r\n                fogDeviceListEntry = CONTAINING_RECORD(entry, DSM_FOG_DEVICELIST_ENTRY, ListEntry);\r\n\r\n                if (fogDeviceListEntry && fogDeviceListEntry->DeviceInfo == deviceInfo) {\r\n\r\n                    status = STATUS_SUCCESS;\r\n                    found = TRUE;\r\n\r\n                    break;\r\n                }\r\n            }\r\n        } else {\r\n\r\n            //\r\n            // This is not a good thing. It indicates that either we\r\n            // returned a bogus path to the bus-driver on a fail-over,\r\n            // or that the path evaporated between polls and PnP hasn't\r\n            // torn stuff down.\r\n            //\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmPathVerify (DevInfo %p): Failed to find failover group for path %p.\\n\",\r\n                        DsmId,\r\n                        PathId));\r\n\r\n            status = STATUS_DEVICE_NOT_CONNECTED;\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(dsmCtxt->DsmContextLock), irql);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            if (found) {\r\n\r\n                //\r\n                // Send down TUR if ALUA is not supported.\r\n                // Else, send down ReportTargetPortGroups (sending TUR down non-A/O path will\r\n                // always result in a check condition).\r\n                //\r\n                if (deviceInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) {\r\n\r\n                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmPathVerify (DevInfo %p): Sending TUR using %p to verify path %p.\\n\",\r\n                                DsmId,\r\n                                deviceInfo,\r\n                                deviceInfo->FailGroup->PathId));\r\n\r\n                    status = DsmSendTUR(deviceInfo->TargetObject);\r\n\r\n                } else {\r\n\r\n                    //\r\n                    // Check for whether we should ignore sending down an RTPG:\r\n                    // Flag set indicates that this PathVerify() is happening in response to device\r\n                    // arrival and can be skipped since Inquire() has just already sent down an RTPG.\r\n                    // All that needs to be done is to clear the flag so that subsequent PathVerify()\r\n                    // sent in response to InitiateFO will send RTPG as a ping.\r\n                    // This is an optimization with the idea of helping speed up boot time, which is\r\n                    // is adversely impacted, especially if there are many LUNs, each with many paths.\r\n                    //\r\n                    if (deviceInfo->IgnorePathVerify) {\r\n\r\n                        deviceInfo->IgnorePathVerify = FALSE;\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmPathVerify (DevInfo %p): Returning success immediately since RTPG was already just sent.\\n\",\r\n                                    DsmId));\r\n\r\n                        status = STATUS_SUCCESS;\r\n\r\n                    } else {\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmPathVerify (DevInfo %p): Sending RTPG using %p to verify path %p.\\n\",\r\n                                    DsmId,\r\n                                    deviceInfo,\r\n                                    deviceInfo->FailGroup->PathId));\r\n\r\n                        status = DsmpGetDeviceALUAState(dsmCtxt, deviceInfo, NULL);\r\n\r\n                        //\r\n                        // Since this RTPG may have resulted in us losing a UA, adjust\r\n                        // the states if needed.\r\n                        //\r\n                        if (NT_SUCCESS(status)) {\r\n\r\n                            DsmpAdjustDeviceStatesALUA(group, NULL, SpecialHandlingFlag);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                if (deviceInfo->State >= DSM_DEV_FAILED) {\r\n\r\n                    foGroup->State = DSM_FG_NORMAL;\r\n                    deviceInfo->State = deviceInfo->LastKnownGoodState;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmPathVerify (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DsmId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmInvalidatePath(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN ULONG ErrorMask,\r\n    _In_ IN PVOID PathId,\r\n    _Inout_ IN OUT PVOID *NewPathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will mark up devices as failed on PathId, and find\r\n    an appropriate path to return to MPIO.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    ErrorMask - Value returned from InterpretError.\r\n    PathId - The failing path.\r\n    NewPathId - Pointer to the new path.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n{\r\n    PDSM_CONTEXT context = DsmContext;\r\n    PDSM_FAILOVER_GROUP failGroup;\r\n    PDSM_FAILOVER_GROUP newPath = NULL;\r\n    PDSM_FAILOVER_GROUP pathId;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    LIST_ENTRY reservedDeviceList;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n    PLIST_ENTRY entry;\r\n    PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL;\r\n    BOOLEAN lockHeld = FALSE;\r\n\r\n    UNREFERENCED_PARAMETER(ErrorMask);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmInvalidatePath (PathId %p): Entering function.\\n\",\r\n                PathId));\r\n\r\n    DSM_ASSERT(ErrorMask & DSM_FATAL_ERROR);\r\n\r\n    *NewPathId = NULL;\r\n\r\n    InitializeListHead(&reservedDeviceList);\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n    lockHeld = TRUE;\r\n\r\n    //\r\n    // Get the fail-over group corresponding to the PathId.\r\n    //\r\n    failGroup = DsmpFindFOGroup(DsmContext, PathId);\r\n\r\n    if (!failGroup || failGroup->State == DSM_FG_FAILED) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmInvalidatePath (PathId %p): Failed to find FailOver group.\\n\",\r\n                    PathId));\r\n\r\n        status = STATUS_NO_SUCH_DEVICE;\r\n        goto __Exit_DsmInvalidatePath;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_RW,\r\n                \"DsmInvalidatePath (PathId %p): Context %p, FOG %p failing.\\n\",\r\n                PathId,\r\n                DsmContext,\r\n                failGroup));\r\n\r\n    //\r\n    // Mark the path as failed.\r\n    //\r\n    failGroup->State = DSM_FG_FAILED;\r\n\r\n    //\r\n    // Check to see whether the port driver and PnP removed the devices\r\n    // BEFORE the fail-over indication actually occurred. Work-around\r\n    // of several Fibre miniports.\r\n    //\r\n    if (failGroup->Count == 0) {\r\n\r\n        //\r\n        // There are no longer any devices in this fail-over group, which means\r\n        // in order to get a back-pointer to the groups using this fail-over\r\n        // group, we need to go through the \"zombie\" group list.  This should\r\n        // allow us to find a new path ID to return.\r\n        //Then go through failGroup->ZombieGroupList to do failover for each group.\r\n        //\r\n        PDSM_ZOMBIEGROUP_ENTRY group;\r\n        PDSM_GROUP_ENTRY groupEntry;\r\n\r\n        //\r\n        // Initialize all the entries to indicate that they haven't been processed.\r\n        //\r\n        for (entry = failGroup->ZombieGroupList.Flink; entry != &(failGroup->ZombieGroupList); entry = entry->Flink) {\r\n\r\n            group = CONTAINING_RECORD(entry, DSM_ZOMBIEGROUP_ENTRY, ListEntry);\r\n            group->Processed = FALSE;\r\n        }\r\n\r\n        //\r\n        // Since we need to drop the spin lock while processing an entry, it is possible\r\n        // that a removal in parallel frees up this entry during that time, thus making it\r\n        // impossible for us to move to the next entry in the list.\r\n        // In order to safely access each of the entries, we mark an entry as being processed\r\n        // just before dropping the spinlock, and always start processing from the beginning\r\n        // of the list, skipping over the already processed ones.\r\n        //\r\n        entry = failGroup->ZombieGroupList.Flink;\r\n\r\n        while (entry != &(failGroup->ZombieGroupList)) {\r\n\r\n            group = CONTAINING_RECORD(entry, DSM_ZOMBIEGROUP_ENTRY, ListEntry);\r\n            entry = entry->Flink;\r\n\r\n            if (!group || !group->Group || group->Processed) {\r\n                continue;\r\n            }\r\n\r\n            group->Processed = TRUE;\r\n            groupEntry = group->Group;\r\n\r\n            ExReleaseSpinLockExclusive(&context->DsmContextLock, irql);\r\n            lockHeld = FALSE;\r\n\r\n            pathId = DsmpSetNewPathUsingGroup((PDSM_CONTEXT)DsmContext, groupEntry);\r\n\r\n            if (!newPath) {\r\n                newPath = pathId; // Save off first good alternative path that we find\r\n            }\r\n\r\n            if (!lockHeld) {\r\n                irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n                lockHeld = TRUE;\r\n                entry = failGroup->ZombieGroupList.Flink;\r\n            }\r\n        }\r\n\r\n        if (!newPath) {\r\n            //\r\n            // This indicates that all of the devices have already been removed.\r\n            // If there were reservations outstanding, the RemoveDevice code\r\n            // should have updated them.\r\n            //\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInvalidatePath (PathId %p): Failed to find new path using zombie group list.\\n\",\r\n                        PathId));\r\n        }\r\n\r\n    } else {\r\n\r\n\r\n        //\r\n        // Process each device in the fail-over group\r\n        //\r\n        for (entry = failGroup->FOG_DeviceList.Flink;\r\n             entry != &failGroup->FOG_DeviceList;\r\n             entry = entry->Flink) {\r\n\r\n            fogDeviceListEntry = CONTAINING_RECORD(entry, DSM_FOG_DEVICELIST_ENTRY, ListEntry);\r\n\r\n            if (!fogDeviceListEntry) {\r\n                continue;\r\n            }\r\n\r\n            //\r\n            // Get the deviceInfo.\r\n            //\r\n            deviceInfo = fogDeviceListEntry->DeviceInfo;\r\n\r\n            if (!(DsmpIsDeviceFailedState(deviceInfo->State))) {\r\n\r\n                deviceInfo->LastKnownGoodState = deviceInfo->State;\r\n            }\r\n\r\n            //\r\n            // Set the state of the Failing Device\r\n            //\r\n            deviceInfo->PreviousState = deviceInfo->State;\r\n            deviceInfo->State = DSM_DEV_INVALIDATED;\r\n\r\n            InterlockedIncrement(&deviceInfo->BlockRemove);\r\n\r\n            ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql);\r\n            lockHeld = FALSE;\r\n\r\n            pathId = DsmpSetNewPath(DsmContext, deviceInfo);\r\n\r\n            if (!newPath) {\r\n                newPath = pathId; // Save off first good alternative path that we find\r\n            }\r\n\r\n            if (!lockHeld) {\r\n                irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n                lockHeld = TRUE;\r\n            }\r\n\r\n            InterlockedDecrement(&deviceInfo->BlockRemove);\r\n        }\r\n    }\r\n\r\n    if (!newPath) {\r\n\r\n        //\r\n        // This indicates that no acceptable paths\r\n        // were found. Return the error to mpctl.\r\n        //\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmInvalidatePath (PathId %p): No valid path found.\\n\",\r\n                    PathId));\r\n\r\n        status = STATUS_NO_SUCH_DEVICE;\r\n\r\n    } else {\r\n\r\n        //\r\n        // return the new path.\r\n        //\r\n        *NewPathId = newPath->PathId;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmInvalidatePath (PathId %p): Returning %p as newPath.\\n\",\r\n                    PathId,\r\n                    newPath->PathId));\r\n    }\r\n\r\n__Exit_DsmInvalidatePath:\r\n\r\n    if (lockHeld) {\r\n        ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmInvalidatePath (PathId %p): Exiting function with status %x.\\n\",\r\n                PathId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmMoveDevice(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PVOID MPIOPath,\r\n    _In_ IN PVOID SuggestedPath,\r\n    _In_ IN ULONG Flags\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is invoked in response to an administrative request.\r\n    The device that's associated with SuggestedPath will be made active, and the\r\n    current active device, moved to stand-by.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during registration.\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDisk.\r\n    MPIOPath - The original path value passed to SetDeviceInfo.\r\n    SuggestedPath - The path which should become the active path.\r\n    Flags - Bitmask indicating the intent of the move.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS - STATUS_SUCCESS, unless SuggestedPath is somehow invalid.\r\n               STATUS_INVALID_PARAMETER is ADMIN is set and the path is invalid.\r\n\r\n--*/\r\n{\r\n    PDSM_CONTEXT context = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PDSM_FAILOVER_GROUP failGroup;\r\n    ULONG i;\r\n    NTSTATUS status;\r\n    KIRQL irql;\r\n    BOOLEAN adminRequest = FALSE;\r\n    PDSM_GROUP_ENTRY group = NULL;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmMoveDevice (DsmIds %p): Entering function - DsmContext %p MPIOPath (%p) SuggestedPath %p.\\n\",\r\n                DsmIds,\r\n                DsmContext,\r\n                MPIOPath,\r\n                SuggestedPath));\r\n\r\n    //\r\n    // Capture the value of the ADMIN flag bit.\r\n    // Currently, permanent assignment of the device to \"preferred path\" isn't supported.\r\n    // This driver doesn't care about the pending remove flag (currently).\r\n    //\r\n    adminRequest = (BOOLEAN)(Flags & DSM_MOVE_ADMIN_REQUEST);\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n\r\n    group = ((PDSM_DEVICE_INFO)(DsmIds->IdList[0]))->Group;\r\n\r\n    //\r\n    // Find the first active device.\r\n    //\r\n    deviceInfo = DsmpGetActivePathToBeUsed(group,\r\n                                           DsmpIsSymmetricAccess((PDSM_DEVICE_INFO)DsmIds->IdList[0]),\r\n                                           SpecialHandlingFlag);\r\n\r\n    if (!deviceInfo) {\r\n\r\n        //\r\n        // Didn't find an active device. Should LOG.\r\n        // Use the first one to piggy-back the request.\r\n        //\r\n        deviceInfo = DsmIds->IdList[0];\r\n    }\r\n\r\n    //\r\n    // Get the fail-over group associated with the Path.\r\n    //\r\n    failGroup = DsmpFindFOGroup(DsmContext,\r\n                                SuggestedPath);\r\n\r\n    if (!failGroup) {\r\n\r\n        //\r\n        // The caller has made a terrible mistake.\r\n        // If it's an ADMIN request, blow it off.\r\n        //\r\n        if (adminRequest) {\r\n            status = STATUS_INVALID_PARAMETER;\r\n        } else {\r\n\r\n            //\r\n            // Try to set another path.\r\n            //\r\n            // Note that failGroup will be NULL going into\r\n            // SetNewPath. This is OK.\r\n            //\r\n            status = STATUS_SUCCESS;\r\n        }\r\n    } else {\r\n        status = STATUS_SUCCESS;\r\n    }\r\n\r\n    if (status == STATUS_SUCCESS) {\r\n\r\n        //\r\n        // Set the new path, using SuggestedPath.\r\n        //\r\n        InterlockedIncrement(&deviceInfo->BlockRemove);\r\n        ExReleaseSpinLockExclusive(&context->DsmContextLock, irql);\r\n        failGroup = DsmpSetNewPath(context,\r\n                                   deviceInfo);\r\n        irql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n        InterlockedDecrement(&deviceInfo->BlockRemove);\r\n\r\n        //\r\n        // If we were able to make the suggested path active, that should be used.\r\n        //\r\n        for (i = 0, status = STATUS_UNSUCCESSFUL; i < DsmIds->Count && !NT_SUCCESS(status); i++) {\r\n\r\n            deviceInfo = DsmIds->IdList[i];\r\n\r\n            if (deviceInfo->FailGroup == failGroup) {\r\n\r\n                if (deviceInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                    InterlockedExchangePointer(&(group->PathToBeUsed), (PVOID)failGroup);\r\n                    status = STATUS_SUCCESS;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(context->DsmContextLock), irql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmMoveDevice (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmRemovePending(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine indicates that the device represented by DsmId will be\r\n    removed, so the deviceInfo is marked up to indicate the pending removal,\r\n    so that it won't be used.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver\r\n                 during registration.\r\n    DsmId - Value referring to the failed device.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    KIRQL irql;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemovePending (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    //\r\n    // DsmpSetNewPath then finds the next available device. This is basically a\r\n    // fail-over for just this device.\r\n    //\r\n    InterlockedIncrement(&deviceInfo->BlockRemove);\r\n    DsmpSetNewPath(DsmContext, deviceInfo);\r\n    irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n    InterlockedDecrement(&deviceInfo->BlockRemove);\r\n\r\n    if (!(DsmpIsDeviceFailedState(deviceInfo->State))) {\r\n\r\n        deviceInfo->LastKnownGoodState = deviceInfo->State;\r\n    }\r\n\r\n    //\r\n    // Mark the device as being unavailable since remove will be sent shortly.\r\n    //\r\n    deviceInfo->PreviousState = deviceInfo->State;\r\n    deviceInfo->State = DSM_DEV_REMOVE_PENDING;\r\n\r\n    ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemovePending (DevInfo %p): Exiting function.\\n\",\r\n                DsmId));\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nDsmRemoveDevice(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PVOID PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    The device is gone and the port pdo has been removed. This routine will\r\n    update the internal structures and free any allocations.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    DsmId - Value referring to the failed device.\r\n    PathId - The path on which the Device lives.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    KIRQL irql;\r\n    PDSM_FAILOVER_GROUP failGroup = deviceInfo->FailGroup;\r\n    PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n    LONG block;\r\n\r\n    UNREFERENCED_PARAMETER(PathId);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemoveDevice (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    do {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n        block = deviceInfo->BlockRemove;\r\n        NT_ASSERT(block >= 0);\r\n\r\n        if (block) {\r\n\r\n            ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n            KeStallExecutionProcessor(10000);\r\n        }\r\n\r\n    } while (block);\r\n\r\n    if (!(DsmpIsDeviceFailedState(deviceInfo->State))) {\r\n\r\n        deviceInfo->LastKnownGoodState = deviceInfo->State;\r\n    }\r\n\r\n    deviceInfo->PreviousState = deviceInfo->State;\r\n    deviceInfo->State = DSM_DEV_REMOVED;\r\n\r\n    //\r\n    // Decrement the reference count for this device's controller entry and\r\n    // delete the entry if its reference count is now zero.\r\n    //\r\n    if (deviceInfo->Controller) {\r\n\r\n        if (InterlockedDecrement((LONG volatile*)&(deviceInfo->Controller->RefCount)) == 0) {\r\n\r\n            RemoveEntryList(&(deviceInfo->Controller->ListEntry));\r\n            DsmpFreeControllerEntry(dsmContext, deviceInfo->Controller);\r\n            deviceInfo->Controller = NULL;\r\n            InterlockedDecrement((LONG volatile*)&(dsmContext->NumberControllers));\r\n        }\r\n    }\r\n\r\n    //\r\n    // Ensure that the device has been fully initialized before trying to\r\n    // remove it from the FOG. If SetDeviceInfo has yet to be invoked, there\r\n    // will yet to be an association set.\r\n    //\r\n    if (failGroup) {\r\n\r\n        //\r\n        // Remove its entry from the Fail-Over Group.\r\n        //\r\n        DsmpRemoveDeviceFailGroup(DsmContext, failGroup, deviceInfo, FALSE);\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n\r\n    //\r\n    // Remove it from it's multi-path group. This has the side-effect\r\n    // of cleaning up the Group if the number of devices goes to zero.\r\n    //\r\n    DsmpRemoveDeviceEntry(DsmContext, group, deviceInfo);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemoveDevice (DevInfo %p): Exiting function.\\n\",\r\n                DsmId));\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmRemovePath(\r\n    _In_ IN PVOID _DsmContext,\r\n    _In_ IN PVOID PathId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine indicates that the path is no longer valid, and that it should\r\n    be removed. Internal counts will be updated and any allocations associated\r\n    with this path freed.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during registration.\r\n    PathId - The path to remove.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_FAILOVER_GROUP failGroup;\r\n    KIRQL irql;\r\n\r\n    PDSM_CONTEXT DsmContext = (PDSM_CONTEXT)_DsmContext;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemovePath (PathId %p): Entering function.\\n\",\r\n                PathId));\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    failGroup = DsmpFindFOGroup(DsmContext, PathId);\r\n\r\n    if (failGroup) {\r\n\r\n        //\r\n        // The claim is that a path won't be removed, until all\r\n        // the devices on it are.\r\n        //\r\n        if (failGroup->Count == 0) {\r\n\r\n            //\r\n            // Yank it from the list.\r\n            //\r\n            RemoveEntryList(&failGroup->ListEntry);\r\n            InterlockedDecrement((LONG volatile*)&DsmContext->NumberFOGroups);\r\n\r\n            //\r\n            // Move this over to the stale FOG list if there are inflight requests.\r\n            // Otherwise free the allocation.\r\n            //\r\n            if (InterlockedCompareExchange(&failGroup->NumberOfRequestsInFlight, 0, 0) > 0) {\r\n\r\n                failGroup->State = DSM_FG_PENDING_REMOVE;\r\n                InsertTailList(&DsmContext->StaleFailGroupList, &failGroup->ListEntry);\r\n                InterlockedIncrement((LONG volatile*)&DsmContext->NumberStaleFOGroups);\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmRemovePath (PathId %p): Outstanding requests %d. Moving FOGroup %p with path %p to stale path list.\\n\",\r\n                            PathId,\r\n                            failGroup->NumberOfRequestsInFlight,\r\n                            failGroup,\r\n                            failGroup->PathId));\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmRemovePath (PathId %p): Removing FOGroup %p with path %p. Count of FOGroups %d.\\n\",\r\n                            PathId,\r\n                            failGroup,\r\n                            failGroup->PathId,\r\n                            DsmContext->NumberFOGroups));\r\n\r\n                //\r\n                // Free the zombie group list and then the failover group.\r\n                //\r\n                DsmpFreeZombieGroupList(failGroup);\r\n                DsmpFreePool(failGroup);\r\n            }\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmRemovePath (PathId %p): Count %d. Not removing FOGroup %p.\\n\",\r\n                        PathId,\r\n                        failGroup->Count,\r\n                        failGroup));\r\n\r\n            //\r\n            // Should never be here.\r\n            //\r\n            NT_ASSERT(failGroup->Count == 0);\r\n        }\r\n    } else {\r\n\r\n        //\r\n        // It's already been removed.\r\n        //\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmRemovePath (PathId %p): Did not find the FO group.\\n\",\r\n                    PathId));\r\n\r\n        NT_ASSERT(failGroup);\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmRemovePath (PathId %p): Exiting function.\\n\",\r\n                PathId));\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n\r\nPVOID\r\nDsmLBGetPath(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ IN PVOID CurrentPath,\r\n    _Out_ OUT NTSTATUS *Status\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used by mpio to handle load-balancing.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    Srb - The current read/write Srb.\r\n    DsmList - List of our DSM IDs.\r\n    CurrentPath - The last path that was returned for this multi-path group.\r\n    Status - Storage to place NTSTATUS of the call.\r\n\r\nReturn Value:\r\n\r\n    The path ID to which the request should be sent.\r\n\r\n--*/\r\n\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PDSM_GROUP_ENTRY group;\r\n    PDSM_FAILOVER_GROUP failGroup = NULL;\r\n    PVOID newPath = NULL;\r\n    PDSM_FAILOVER_GROUP oldFailGroup = NULL;\r\n    PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY failPathDevInfoEntry = NULL;\r\n    PCDB cdb = NULL;\r\n    UCHAR opCode = 0xFF;\r\n    BOOLEAN lockInExclusiveMode = FALSE;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n\r\n    if (Srb) {\r\n        cdb = SrbGetCdb(Srb);\r\n        if (cdb) {\r\n            opCode = cdb->AsByte[0];\r\n\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmLBGetPath (DsmIds %p): Entering function.\\n\",\r\n                DsmList));\r\n\r\n    //\r\n    // Up-front checking to minimally validate the list of\r\n    // DsmId's being passed in.\r\n    //\r\n    NT_ASSERT(DsmList->Count && DsmList->IdList[0]);\r\n    if (!(DsmList->Count && DsmList->IdList[0])) {\r\n\r\n        *Status = STATUS_NO_SUCH_DEVICE;\r\n        goto __Exit_DsmLBGetPath;\r\n    }\r\n\r\n    deviceInfo = DsmList->IdList[0];\r\n    group = deviceInfo->Group;\r\n\r\n\r\n    failGroup = DsmpGetPath(dsmContext, DsmList, Srb, SpecialHandlingFlag);\r\n\r\n    //\r\n    // If there wasn't a single active/optimized path found, check to see if\r\n    // there is an STPG in progress that may be making a path A/O.\r\n    //\r\n    if (!failGroup) {\r\n\r\n        //\r\n        // Take the last path used.\r\n        //\r\n        oldFailGroup = DsmpFindFOGroup(dsmContext, CurrentPath);\r\n\r\n        //\r\n        // Find the devInfo corresponding to this path.\r\n        //\r\n        deviceInfo = DsmpFindDevInfoFromGroupAndFOGroup(dsmContext,\r\n                                                        group,\r\n                                                        oldFailGroup);\r\n\r\n        if (deviceInfo) {\r\n\r\n            //\r\n            // Check if there is an alternate devInfo to be used temporarily\r\n            // for this deviceInfo\r\n            //\r\n            failPathDevInfoEntry = DsmpFindFailPathDevInfoEntry(dsmContext,\r\n                                                                group,\r\n                                                                deviceInfo);\r\n\r\n            if (failPathDevInfoEntry) {\r\n\r\n                //\r\n                // Use the alternate devInfo for now temporarily while the STPG\r\n                // that was previously sent (asynchronously) works on making the\r\n                // appropriate path active/optimized.\r\n                //\r\n                failGroup = (failPathDevInfoEntry->TempDeviceInfo)->FailGroup;\r\n            }\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmLBGetPath (DsmIds %p): Couldn't find FOG but FO in progress, so returning devInfo %p (FOG %p path %p).\\n\",\r\n                        DsmList,\r\n                        deviceInfo,\r\n                        deviceInfo->FailGroup,\r\n                        deviceInfo->FailGroup->PathId));\r\n        } else {\r\n\r\n            //\r\n            // Check if there is an RTPG in progress, if yes, return some path\r\n            // for the IO to be sent down.\r\n            //\r\n            if (InterlockedCompareExchange((LONG volatile*)&group->InFlightRTPG, 0, 0)) {\r\n\r\n                BOOLEAN sendTPG = FALSE;\r\n                deviceInfo = DsmpFindStandbyPathToActivateALUA(group, &sendTPG, SpecialHandlingFlag);\r\n\r\n                if (deviceInfo) {\r\n\r\n                    failGroup = deviceInfo->FailGroup;\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmLBGetPath (DsmIds %p): Couldn't find FOG but RTPG inflight, so returning devInfo %p (FOG %p path %p).\\n\",\r\n                                DsmList,\r\n                                deviceInfo,\r\n                                deviceInfo->FailGroup,\r\n                                deviceInfo->FailGroup->PathId));\r\n                } else {\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmLBGetPath (DsmIds %p): Couldn't find FOG but RTPG inflight, even then couldn't find alternative devInfo.\\n\",\r\n                                DsmList));\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    if (failGroup) {\r\n\r\n        newPath = failGroup->PathId;\r\n        *Status = STATUS_SUCCESS;\r\n\r\n        //\r\n        // If this is a retried request, our SetCompletion would have been bypassed,\r\n        // and our completion routine won't yet get called, so update the old and\r\n        // the new paths' stats.\r\n        //\r\n        if (Srb && DsmIsReadWrite(opCode)) {\r\n\r\n            PDSM_FAILOVER_GROUP oldPath;\r\n            PIRP irp = (PIRP)SrbGetOriginalRequest(Srb);\r\n            PIO_STACK_LOCATION irpStack;\r\n\r\n            //\r\n            // This indicates that the request is being retried. So we need to:\r\n            // 1. Update old path's and new path's request count\r\n            // 2. If the old path was supposed to be removed, check if there is\r\n            //    no more outstanding request, and if so, remove the path\r\n            //\r\n\r\n            irpStack = IoGetCurrentIrpStackLocation(irp);\r\n            oldPath = irpStack->Parameters.Others.Argument3;\r\n\r\n            if (oldPath) {\r\n\r\n                NT_ASSERT(oldPath->FailOverSig == DSM_FOG_SIG);\r\n\r\n                if (DsmpDecrementCounters(oldPath, Srb)) {\r\n\r\n                    //\r\n                    // If there are no requests on a path that is supposed to be removed,\r\n                    // remove it now.\r\n                    //\r\n                    if (oldPath->State == DSM_FG_PENDING_REMOVE) {\r\n                        KIRQL irql;\r\n\r\n                        NT_ASSERT(oldPath->Count == 0);\r\n\r\n                        //\r\n                        // We need to acquire the DsmContextLock in Exclusive mode since\r\n                        // we are removing a path from the Failover Group list.\r\n                        //\r\n                        irql = ExAcquireSpinLockExclusive(&(dsmContext->DsmContextLock));\r\n                        lockInExclusiveMode = TRUE;\r\n\r\n                        RemoveEntryList(&oldPath->ListEntry);\r\n                        InterlockedDecrement((LONG volatile*)&dsmContext->NumberStaleFOGroups);\r\n\r\n                        ExReleaseSpinLockExclusive(&(dsmContext->DsmContextLock), irql);\r\n\r\n                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmLBGetPath (DsmIds %p): Removing FOGroup %p with path %p.\\n\",\r\n                                    DsmList,\r\n                                    oldPath,\r\n                                    oldPath->PathId));\r\n\r\n                        DsmpFreePool(oldPath);\r\n                    }\r\n                }\r\n\r\n                irpStack->Parameters.Others.Argument3 = failGroup;\r\n\r\n                DsmpIncrementCounters(failGroup, Srb);\r\n            }\r\n        }\r\n\r\n    } else {\r\n\r\n        *Status = STATUS_NO_SUCH_DEVICE;\r\n\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmLBGetPath (DsmIds %p): Failed to get FO group in LBGetPath.\\n\",\r\n                    DsmList));\r\n\r\n\r\n    }\r\n\r\n__Exit_DsmLBGetPath:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmLBGetPath (DsmIds %p): Exiting function returning path %p for request %p.\\n\",\r\n                DsmList,\r\n                newPath,\r\n                Srb));\r\n\r\n    return newPath;\r\n}\r\n\r\n_Success_(return == DSM_PATH_SET)\r\nULONG\r\nDsmCategorizeRequest(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PVOID CurrentPath,\r\n    _Outptr_result_maybenull_ OUT PVOID *PathId,\r\n    _Out_ OUT NTSTATUS *Status\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when a request is received other than a read/write.\r\n    It will determine the best path to which the request is to be sent.\r\n\r\n    In order to support clusters, reserve and release need to be handled\r\n    via SrbControl.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during\r\n                 registration.\r\n    DsmIds - List of our DSM IDs.\r\n    Irp - The Irp containing Srb.\r\n    Srb - The current non-read/write Srb.\r\n    CurrentPath - The last path that was returned for this multi-path group.\r\n    PathId - Placeholder for the PathID\r\n    Status - Storage to place NTSTATUS of the call.\r\n\r\nReturn Value:\r\n\r\n    DSM_PATH_SET - Indicates PathID is valid.\r\n    DSM_ERROR - Couldn't get a path.\r\n\r\n--*/\r\n{\r\n    ULONG dsmStatus;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmCategorizeRequest (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // Determine whether this is a special-case request.\r\n    //\r\n    if (DsmpReservationCommand(Irp, Srb)) {\r\n\r\n        dsmStatus = DSM_WILL_HANDLE;\r\n        goto __Exit_DsmCategorizeRequest;\r\n    }\r\n\r\n\r\n    //\r\n    // If this is a mpio pass through or a mpio pass through direct request,\r\n    // pick the path that corresponds to the pathId specified.\r\n    //\r\n    if (DsmpMpioPassThroughPathCommand(Irp)) {\r\n\r\n        *PathId = DsmpGetPathIdFromPassThroughPath(DsmContext,\r\n                                                   DsmIds,\r\n                                                   Irp,\r\n                                                   &status);\r\n    } else {\r\n\r\n        //\r\n        // For requests other than reservation-handling and pass through, punt\r\n        // it back to the bus-driver. Need to get a path for the request first,\r\n        // so call the Load-Balance function.\r\n        //\r\n        *PathId = DsmLBGetPath(DsmContext,\r\n                               Srb,\r\n                               DsmIds,\r\n                               CurrentPath,\r\n                               &status);\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        if (!*PathId) {\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_IOCTL,\r\n                        \"DsmCategorizeRequest (DsmIds %p): DSM_PATH_SET didn't return a path.\\n\",\r\n                        DsmIds));\r\n        }\r\n\r\n        //\r\n        // Indicate that the path is updated, and mpctl should handle the request.\r\n        //\r\n        dsmStatus = DSM_PATH_SET;\r\n\r\n    } else {\r\n\r\n        //\r\n        // Indicate the error back to mpctl.\r\n        //\r\n        dsmStatus = DSM_ERROR;\r\n\r\n        //\r\n        // Mark-up the Srb to show that a failure has occurred.\r\n        // This value is really only for this DSM to know what to do\r\n        // in the InterpretError routine - Fatal Error.\r\n        // It could be something more meaningful.\r\n        //\r\n        if (Srb) {\r\n            Srb->SrbStatus = SRB_STATUS_NO_DEVICE;\r\n        }\r\n\r\n        *PathId = NULL;\r\n    }\r\n\r\n    //\r\n    // Pass back status info to mpctl.\r\n    //\r\n    *Status = status;\r\n\r\n__Exit_DsmCategorizeRequest:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmCategorizeRequest (DsmIds %p): Exiting function with categorization %x.\\n\",\r\n                DsmIds,\r\n                dsmStatus));\r\n\r\n    return dsmStatus;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmBroadcastRequest(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when the DSM has indicated that Srb should be\r\n    sent to the device down all paths. The DSM will update IoStatus\r\n    information and status, but not complete the request.\r\n\r\n    Currently MSDSM doesn't have a need for this.\r\n\r\nArguments:\r\n\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDisk.\r\n    Irp - Irp containing SRB.\r\n    Srb - Scsi request block\r\n    Event - DSM sets this once all sub-requests have completed and\r\n            the original request's IoStatus has been setup.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n    UNREFERENCED_PARAMETER(Srb);\r\n    UNREFERENCED_PARAMETER(Irp);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmBroadcastRequest (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // Currently nothing is handled via Broadcast. Just set the event to\r\n    // free up the request handling in the bus-driver.\r\n    //\r\n    NT_ASSERT(NT_SUCCESS(status));\r\n    KeSetEvent(Event, 0, FALSE);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmBroadcastReqeust (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmSrbDeviceControl(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when the DSM has indicated that it wants to handle\r\n    it internally (via returning DSM_WILL_HANDLE in CategorizeRequest).\r\n\r\n    It should set IoStatus (Status and Information) and the Event, but not\r\n    complete the request.\r\n\r\nArguments:\r\n\r\n    DsmContext - The DSM's context\r\n    DsmIds - The collection of DSM IDs that pertain to the MPDISK.\r\n    Irp - Irp containing SRB.\r\n    Srb - Scsi request block\r\n    Event - Event to be set when the DSM is finished if DsmHandled is TRUE\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the request.\r\n\r\n--*/\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    NTSTATUS status;\r\n    UCHAR opCode = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmSrbDeviceControl (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    if (!DsmIds || !DsmIds->Count) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_IOCTL,\r\n                    \"DsmSrbDeviceControl (DsmIds %p): No DsmIds passed in.\\n\",\r\n                    DsmIds));\r\n\r\n        status = STATUS_NO_SUCH_DEVICE;\r\n        goto __Exit_DsmSrbDeviceControl;\r\n    }\r\n\r\n    if (irpStack->MajorFunction == IRP_MJ_SCSI) {\r\n\r\n        //\r\n        // Determine the operation.\r\n        //\r\n        PCDB cdb = SrbGetCdb(Srb);\r\n        if (cdb) {\r\n            opCode = cdb->AsByte[0];\r\n        }\r\n\r\n        if (opCode == SCSIOP_PERSISTENT_RESERVE_OUT) {\r\n\r\n                status = DsmpPersistentReserveOut(dsmContext,\r\n                                                  DsmIds,\r\n                                                  Irp,\r\n                                                  Srb,\r\n                                                  Event);\r\n\r\n        } else if (opCode == SCSIOP_PERSISTENT_RESERVE_IN) {\r\n\r\n            status = DsmpPersistentReserveIn(dsmContext,\r\n                                             DsmIds,\r\n                                             Irp,\r\n                                             Srb,\r\n                                             Event);\r\n\r\n        } else {\r\n\r\n            //\r\n            // Should never be here.\r\n            //\r\n            DSM_ASSERT(FALSE);\r\n            status = STATUS_INVALID_DEVICE_REQUEST;\r\n        }\r\n    } else {\r\n        //\r\n        // Should never be here.\r\n        //\r\n        DSM_ASSERT(irpStack->MajorFunction == IRP_MJ_SCSI);\r\n        status = STATUS_INVALID_DEVICE_REQUEST;\r\n    }\r\n\r\n__Exit_DsmSrbDeviceControl:\r\n    if (status != STATUS_PENDING) {\r\n\r\n        //\r\n        // Set-up the Irp status for mpio's completion of the request.\r\n        // If it was IRP_MJ_SCSI, one of the helper routines set Srb->SrbStatus\r\n        // already.\r\n        //\r\n        if ((irpStack->MajorFunction == IRP_MJ_SCSI) &&\r\n            (Srb != NULL) &&\r\n            (Srb->SrbStatus == SRB_STATUS_PENDING)) {\r\n\r\n            Srb->SrbStatus = SRB_STATUS_ERROR;\r\n        }\r\n\r\n        Irp->IoStatus.Status = status;\r\n\r\n        //\r\n        // Set the event to free up the request handling in the bus-driver.\r\n        //\r\n        KeSetEvent(Event, 0, FALSE);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmSrbDeviceControl (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmSetCompletion(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _Inout_ IN OUT PDSM_COMPLETION_INFO DsmCompletion\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called before the actual submission of a request,\r\n    but after the categorisation of the I/O. This will be called only\r\n    for those requests not handled by the DSM directly:\r\n         Read/Write\r\n         Other requests not handled by SrbControl or Broadcast\r\n\r\nArguments:\r\n\r\n    DsmContext - The DSM's context.\r\n    DsmId - Identifer that was indicated when the request was\r\n            categorized (or be LBGetPath)\r\n    Irp - Irp containing Srb.\r\n    Srb - The request\r\n    DsmCompletion - Completion info structure to be filled out by DSM.\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    PDSM_CONTEXT dsmContext = DsmContext;\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);\r\n    PDSM_FAILOVER_GROUP failGroup = deviceInfo->FailGroup;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmSetCompletion (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    //\r\n    // Save off the path that was selected to service this request in Argument3.\r\n    //\r\n    irpStack->Parameters.Others.Argument3 = failGroup;\r\n\r\n    DsmpIncrementCounters(failGroup, Srb);\r\n\r\n    if (!dsmContext->DisableStatsGathering) {\r\n\r\n        //\r\n        // Indicate one more request on this device down this path.\r\n        //\r\n        InterlockedIncrement(&deviceInfo->NumberOfRequestsInProgress);\r\n    }\r\n\r\n    //\r\n    // Update the passed-in struct with our routine and context values.\r\n    //\r\n    DsmCompletion->DsmCompletionRoutine = DsmpRequestComplete;\r\n    DsmCompletion->DsmContext = DsmContext;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmSetCompletion (DevInfo %p): Exiting function.\\n\",\r\n                DsmId));\r\n\r\n    return;\r\n}\r\n\r\n\r\nULONG\r\nDsmInterpretError(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _Inout_ IN OUT NTSTATUS *Status,\r\n    _Out_ OUT PBOOLEAN Retry,\r\n    _Out_ OUT PLONG RetryInterval,\r\n    ...\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is invoked by MPIO if Status is other than SUCCESS.\r\n    A few NTSTATUS and SRB_STATUS values indicate a fatal error.\r\n    Also checked are unit attentions, for which a retry is requested.\r\n\r\nArguments:\r\n\r\n    DsmContext - The DSM's context.\r\n    DsmId - Identifers returned from DMS_INQUIRE_DRIVER.\r\n    Srb - The Srb with an error.\r\n    Status - NTSTATUS of the operation. Can be updated.\r\n    Retry - Allows the DSM to indicate whether to retry the IO.\r\n    RetryInterval - Lets DSM specify (in seconds) when this specific I/O\r\n                    should be retried. Use MAXLONG to use the default\r\n                    retry interval. Use zero to retry immediately.\r\n\r\nReturn Value:\r\n\r\n    DSM_FATAL_ERROR indicates a fatal error.\r\n\r\n--*/\r\n{\r\n    //\r\n    // The requests that will be encountered can be divided into four categories:\r\n    // 1. The request that has failed.\r\n    // 2. Subsequent requests that were sent down the failing path that will\r\n    //    complete with failure.\r\n    // 3. Requests that were already submitted to LBGetPath() just before InterpretError()\r\n    //    was called for the failed request (but have yet to have the LB policy\r\n    //    algo run).\r\n    // 4. Requests that come into the Dispatch() routine after the failed request\r\n    //    has been processed by InterpretError().\r\n    //\r\n    // For the failed request:\r\n    // =======================\r\n    // 1. Find a standby path to make active/optimized.\r\n    // 2. Send STPG asynchronously as a scsi pass through via IRP_MJ_SCSI (this\r\n    //    way it can be sent at DISPATCH_IRQL) after setting a completion routine.\r\n    // 3. Save the devInfo corresponding to the standby path for the failing devInfo.\r\n    // 4. Return FATAL to MPIO so that new IO are queued.\r\n    // 5. In the completion routine, update the new states for the devInfos. Then\r\n    //    clear the saved (previously) standby devInfo for the failing devInfo.\r\n    //\r\n    // For the subsequent request that will fail (since it was sent on the failing path):\r\n    // ==================================================================================\r\n    // 1. If a standby devInfo has been saved off, it indicates that an STPG was\r\n    //    already sent, so no need to send another one.\r\n    // 2. Return FATAL to MPIO so that this request gets queued.\r\n    //\r\n    // For the requests that were already submitted to LBGetPath() during this time:\r\n    // =============================================================================\r\n    // 1. If there is no active path, check if a standby devInfo has been saved\r\n    //    away. If it has, return this path. Such requests will fail with check\r\n    //    condition saying path used is in standby.\r\n    // 2. In InterpretError() retry (since the error indicates that request\r\n    //    completed before STPG completed) without decrementing the remaining\r\n    //    retries count.\r\n    //\r\n    // For new requests that come into Dispatch() after above processing:\r\n    // ==================================================================\r\n    // We don't need to worry about such requests, since MPIO will queue them\r\n    // automatically.\r\n    //\r\n\r\n    PDSM_DEVICE_INFO deviceInfo = DsmId;\r\n    ULONG errorMask = 0;\r\n    PVOID senseData = SrbGetSenseInfoBuffer(Srb);\r\n    UCHAR senseDataLength = SrbGetSenseInfoBufferLength(Srb);\r\n    BOOLEAN failover = FALSE;\r\n    BOOLEAN retry = FALSE;\r\n    BOOLEAN handled = FALSE;\r\n    BOOLEAN sendTPG = FALSE;\r\n    BOOLEAN tpgException = FALSE;\r\n    BOOLEAN devInfoException = FALSE;\r\n    PCDB cdb = SrbGetCdb(Srb);\r\n    UCHAR opCode = 0;\r\n    UCHAR scsiStatus = SrbGetScsiStatus(Srb);\r\n    BOOLEAN validSense = FALSE;\r\n    UCHAR senseKey = 0;\r\n    UCHAR addSenseCode = 0;\r\n    UCHAR addSenseCodeQualifier = 0;\r\n\r\n    if (cdb) {\r\n        opCode = cdb->AsByte[0];\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmInterpretError (DevInfo %p): Entering function.\\n\",\r\n                DsmId));\r\n\r\n    *RetryInterval = MAXLONG;\r\n\r\n    if ((scsiStatus == SCSISTAT_RESERVATION_CONFLICT) ||\r\n        (*Status == STATUS_DEVICE_BUSY)) {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmInterpretError (DevInfo %p): Srb %p. Either busy or res. conflict (%x %x).\\n\",\r\n                    DsmId,\r\n                    Srb,\r\n                    scsiStatus,\r\n                    *Status));\r\n    }\r\n\r\n    //\r\n    // Go ahead and get the sense data if it's valid.\r\n    //\r\n    if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {\r\n\r\n        NT_ASSERT(senseData != NULL);\r\n\r\n        validSense = ScsiGetSenseKeyAndCodes(senseData,\r\n                                                senseDataLength,\r\n                                                SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,\r\n                                                &senseKey,\r\n                                                &addSenseCode,\r\n                                                &addSenseCodeQualifier);\r\n    }\r\n\r\n    //\r\n    // Sense data relating to logical block provisioning should be failed\r\n    // immediately back to the class layer for handling.\r\n    //\r\n    if (validSense) {\r\n        if (senseKey == SCSI_SENSE_NOT_READY &&\r\n            addSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&\r\n            addSenseCodeQualifier == SCSI_SENSEQ_SPACE_ALLOC_IN_PROGRESS) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Temporary resource exhaustion. Fail Srb %p.\\n\",\r\n                        DsmId,\r\n                        Srb));\r\n\r\n            handled = TRUE;\r\n\r\n        } else if (senseKey == SCSI_SENSE_DATA_PROTECT &&\r\n                   addSenseCode == SCSI_ADSENSE_WRITE_PROTECT &&\r\n                   addSenseCodeQualifier == SCSI_SENSEQ_SPACE_ALLOC_FAILED_WRITE_PROTECT) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Permanent resource exhaustion. Fail Srb %p.\\n\",\r\n                        DsmId,\r\n                        Srb));\r\n\r\n            handled = TRUE;\r\n\r\n        } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION &&\r\n                   addSenseCode == SCSI_ADSENSE_LB_PROVISIONING &&\r\n                   addSenseCodeQualifier == SCSI_SENSEQ_SOFT_THRESHOLD_REACHED) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Soft threshold reached. Fail Srb %p.\\n\",\r\n                        DsmId,\r\n                        Srb));\r\n\r\n            handled = TRUE;\r\n\r\n        } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION &&\r\n                   addSenseCode == SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED &&\r\n                   addSenseCodeQualifier == SCSI_SENSEQ_INQUIRY_DATA_CHANGED) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Inquiry data changed. Fail Srb %p.\\n\",\r\n                        DsmId,\r\n                        Srb));\r\n\r\n            handled = TRUE;\r\n        } else if (senseKey == SCSI_SENSE_UNIT_ATTENTION &&\r\n                   addSenseCode == SCSI_ADSENSE_PARAMETERS_CHANGED &&\r\n                   addSenseCodeQualifier == SCSI_SENSEQ_CAPACITY_DATA_CHANGED) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Capacity data changed. Fail Srb %p.\\n\",\r\n                        DsmId,\r\n                        Srb));\r\n\r\n            handled = TRUE;\r\n        }\r\n    }\r\n\r\n    if (handled) {\r\n        return errorMask;\r\n    }\r\n\r\n    //\r\n    // Check the NT Status first.\r\n    // Several are clearly failover conditions.\r\n    //\r\n    switch (*Status) {\r\n        case STATUS_DEVICE_NOT_CONNECTED:\r\n        case STATUS_DEVICE_DOES_NOT_EXIST:\r\n        case STATUS_NO_SUCH_DEVICE:\r\n        case STATUS_DELETE_PENDING: {\r\n\r\n            //\r\n            // The port pdo has either been removed or is\r\n            // very broken. A fail-over is necessary.\r\n            //\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Will initiate fail over. Status %x. Opcode %x.\\n\",\r\n                        DsmId,\r\n                        *Status,\r\n                        opCode));\r\n\r\n            handled = TRUE;\r\n            failover = TRUE;\r\n            break;\r\n        }\r\n\r\n        case STATUS_IO_DEVICE_ERROR: {\r\n\r\n            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {\r\n\r\n                if (validSense) {\r\n\r\n                    //\r\n                    // See if it's a unit attention.\r\n                    //\r\n                    if (senseKey == SCSI_SENSE_UNIT_ATTENTION) {\r\n\r\n                        switch (addSenseCode) {\r\n\r\n                            case SCSI_ADSENSE_PARAMETERS_CHANGED: {\r\n\r\n                                switch (addSenseCodeQualifier) {\r\n\r\n                                    case SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED:\r\n                                    case SPC3_SCSI_SENSEQ_IMPLICIT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED: {\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): TPG states have changed. Requesting retry on Srb %p. Will send asyn RTPG.\\n\",\r\n                                                    DsmId,\r\n                                                    Srb));\r\n\r\n                                        //\r\n                                        // Retry but after sending RTPG, which will update the path states.\r\n                                        //\r\n                                        sendTPG = TRUE;\r\n                                        retry = TRUE;\r\n                                        handled = TRUE;\r\n                                        errorMask = DSM_RETRY_DONT_DECREMENT;\r\n\r\n                                        if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED) {\r\n\r\n                                            //\r\n                                            // Worth retrying on the same path.\r\n                                            //\r\n                                            devInfoException = TRUE;\r\n                                            NT_ASSERT(!tpgException);\r\n                                        }\r\n\r\n                                        break;\r\n                                    }\r\n\r\n\r\n                                    case SPC3_SCSI_SENSEQ_RESERVATIONS_RELEASED: {\r\n\r\n                                        //\r\n                                        // This request needs to be immediately retried down the same path.\r\n                                        //\r\n                                        retry = TRUE;\r\n                                        *RetryInterval = 0;\r\n                                        handled = TRUE;\r\n                                        InterlockedExchangePointer(&(deviceInfo->Group->PathToBeUsed), deviceInfo->FailGroup);\r\n                                        break;\r\n                                    }\r\n\r\n                                    case SPC3_SCSI_SENSEQ_MODE_PARAMETERS_CHANGED:\r\n                                    case SPC3_SCSI_SENSEQ_RESERVATIONS_PREEMPTED:\r\n                                    case SPC3_SCSI_SENSEQ_REGISTRATIONS_PREEMPTED:\r\n                                    case SPC3_SCSI_SENSEQ_CAPACITY_DATA_HAS_CHANGED: {\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): Failing request. STATUS_IO_DEVICE_ERROR (params changed). SrbStatus (%x) Scsi (%x) AddQual (%u).\\n\",\r\n                                                    DsmId,\r\n                                                    Srb->SrbStatus,\r\n                                                    scsiStatus,\r\n                                                    addSenseCodeQualifier));\r\n\r\n                                        //\r\n                                        // Just fail these back.\r\n                                        //\r\n                                        handled = TRUE;\r\n                                        break;\r\n                                    }\r\n\r\n                                    default: {\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): UNIT_ATTENTION for params changed. ASCQ %x. Asking for retry on Srb %p.\\n\",\r\n                                                    DsmId,\r\n                                                    addSenseCodeQualifier,\r\n                                                    Srb));\r\n\r\n                                        //\r\n                                        // Indicate that a retry is necessary.\r\n                                        //\r\n                                        retry = TRUE;\r\n                                        handled = TRUE;\r\n\r\n                                        break;\r\n                                    }\r\n                                }\r\n\r\n                                break;\r\n                            }\r\n\r\n\r\n                            case SPC3_SCSI_ADSENSE_COMMANDS_CLEARED_BY_ANOTHER_INITIATOR: {\r\n\r\n                                if (addSenseCodeQualifier == 0x00) {\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmInterpretError (DevInfo %p): UNIT_ATTENTION (commands cleared by another initiator). Fail back to upper level. Srb %p.\\n\",\r\n                                                DsmId,\r\n                                                Srb));\r\n\r\n                                    //\r\n                                    // Commands cleared by another Initiator\r\n                                    //\r\n                                    handled = TRUE;\r\n\r\n                                } else {\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmInterpretError (DevInfo %p): UNIT_ATTENTION (commands cleared by another initiator). ASCQ %x. Asking for retry on Srb %p.\\n\",\r\n                                                DsmId,\r\n                                                addSenseCodeQualifier,\r\n                                                Srb));\r\n\r\n                                    //\r\n                                    // Indicate that a retry is necessary.\r\n                                    //\r\n                                    retry = TRUE;\r\n                                    handled = TRUE;\r\n                                }\r\n\r\n\r\n                                break;\r\n                            }\r\n\r\n                            case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: {\r\n\r\n                                if (addSenseCodeQualifier == SCSI_SENSEQ_VOLUME_SET_MODIFIED ||\r\n                                    addSenseCodeQualifier == SCSI_SENSEQ_REPORTED_LUNS_DATA_CHANGED) {\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmInterpretError (DevInfo %p): VolumeSet/LunsData changed. Fail Srb %p.\\n\",\r\n                                                DsmId,\r\n                                                Srb));\r\n\r\n                                    //\r\n                                    // Fail back to upper layers.\r\n                                    //\r\n                                    handled = TRUE;\r\n\r\n                                    break;\r\n\r\n                                } else {\r\n\r\n                                    //\r\n                                    // Fall through to default case (ie. retry the request)\r\n                                    //\r\n                                }\r\n                            }\r\n\r\n                            default: {\r\n\r\n                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                            TRACE_FLAG_RW,\r\n                                            \"DsmInterpretError (DevInfo %p): UNIT_ATTENTION. ASC %x, ASCQ %x. Asking for retry on Srb %p.\\n\",\r\n                                            DsmId,\r\n                                            addSenseCode,\r\n                                            addSenseCodeQualifier,\r\n                                            Srb));\r\n\r\n                                //\r\n                                // Indicate that a retry is necessary.\r\n                                //\r\n                                retry = TRUE;\r\n                                handled = TRUE;\r\n\r\n                                break;\r\n                            }\r\n                        }\r\n                    } else if (senseKey == SCSI_SENSE_NOT_READY) {\r\n\r\n                        if (addSenseCode == SCSI_ADSENSE_LUN_NOT_READY) {\r\n\r\n                            if (scsiStatus == SCSISTAT_CHECK_CONDITION) {\r\n\r\n                                switch (addSenseCodeQualifier) {\r\n\r\n                                    //\r\n                                    // See if failure is due to device's current TPG state.\r\n                                    //\r\n                                    // If the failure is PORT_IN_STANDBY_STATE, we leave DSM_RETRY_DONT_DECREMENT unset if no active path exists,\r\n                                    // because otherwise MPIO will not be able to find a better path, and it will get into an infinite loop\r\n                                    // of trying and failing the command on a Standby path.  See WCxeTfs:89150\r\n                                    //\r\n                                    case SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION:\r\n                                    case SPC3_SCSI_SENSEQ_TARGET_PORT_IN_UNAVAILABLE_STATE:\r\n\r\n                                        errorMask = DSM_RETRY_DONT_DECREMENT;\r\n\r\n                                    case SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE:\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): TPG-transition/TPG-SB/TPG-UA. ASCQ %x. Will send down async RTPG. Asking for retry on Srb %p.\\n\",\r\n                                                    DsmId,\r\n                                                    addSenseCodeQualifier,\r\n                                                    Srb));\r\n\r\n                                        //\r\n                                        // Indicate that a retry is necessary but without decrementing the remaining\r\n                                        // retries count. However, we may need to send down an STPG/RTPG also.\r\n                                        // And we must set PTBU to a path that is in a different TPG.\r\n                                        //\r\n                                        sendTPG = TRUE;\r\n                                        tpgException = TRUE;\r\n                                        NT_ASSERT(!devInfoException);\r\n                                        retry = TRUE;\r\n                                        handled = TRUE;\r\n\r\n                                        if ((addSenseCodeQualifier == SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE) &&\r\n                                            DsmIsReadWrite(opCode)) {\r\n\r\n                                            PDSM_CONTEXT context = (PDSM_CONTEXT) deviceInfo->DsmContext;\r\n                                            KIRQL oldIrql = ExAcquireSpinLockExclusive(&(context->DsmContextLock));\r\n                                            BOOLEAN activePathExists = ( NULL != DsmpGetAnyActivePath(deviceInfo->Group, FALSE, NULL, 0) );\r\n                                            ExReleaseSpinLockExclusive(&(context->DsmContextLock), oldIrql);\r\n\r\n                                            if (activePathExists) {\r\n                                                errorMask = DSM_RETRY_DONT_DECREMENT;\r\n\r\n                                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                                        TRACE_FLAG_RW,\r\n                                                        \"DsmInterpretError (DevInfo %p): Not decrementing error counter, as an active path exists in group %p and opcode %x is r/w\\n\",\r\n                                                        DsmId,\r\n                                                        deviceInfo->Group,\r\n                                                        opCode));\r\n                                            }\r\n                                        }\r\n\r\n                                        break;\r\n\r\n                                    case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): Manual intervention required. Asking for retry on Srb %p.\\n\",\r\n                                                    DsmId,\r\n                                                    Srb));\r\n\r\n                                        //\r\n                                        // This may be caused by NDU of controller firmware. It does not\r\n                                        // necessarily indicate that the device won't be ready via other path(s).\r\n                                        // Worth retrying instead of immediately failing back.\r\n                                        //\r\n                                        retry = TRUE;\r\n                                        handled = TRUE;\r\n\r\n                                        break;\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n\r\n            } else if (Srb->SrbStatus == SRB_STATUS_BUS_RESET) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError (DevInfo %p): BUS_RESET. Failing back Srb %p.\\n\",\r\n                            DsmId,\r\n                            Srb));\r\n\r\n                //\r\n                // Upper layers will retry in this case.  If we retry here it will\r\n                // have a multiplicative effect which may result in a very long\r\n                // IO completion time if the device persistently times out.\r\n                //\r\n                retry = FALSE;\r\n                handled = TRUE;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError (DevInfo %p): Failing request. STATUS_IO_DEVICE_ERROR. SrbStatus (%x) ScsiStatus (%x).\\n\",\r\n                            DsmId,\r\n                            Srb->SrbStatus,\r\n                            scsiStatus));\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case STATUS_BUFFER_OVERFLOW: {\r\n\r\n            if (DsmIsReadWrite(opCode)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError (DevInfo %p): BUFFER_OVERFLOW: Retry.\\n\",\r\n                            DsmId));\r\n\r\n                //\r\n                // Retry these, as this condition might indicate a torn write.\r\n                //\r\n                retry = TRUE;\r\n                handled = TRUE;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case STATUS_DEVICE_BUSY: {\r\n\r\n            //\r\n            // See if it's a check condition for TPG states in transition.\r\n            //\r\n            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&\r\n                scsiStatus == SCSISTAT_CHECK_CONDITION) {\r\n\r\n                if (validSense) {\r\n\r\n                    if (senseKey == SCSI_SENSE_NOT_READY &&\r\n                        addSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&\r\n                        addSenseCodeQualifier == SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION) {\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_RW,\r\n                                    \"DsmInterpretError (DevInfo %p): TPG transition. Will send down async RTPG. Asking for retry on Srb %p.\\n\",\r\n                                    DsmId,\r\n                                    Srb));\r\n\r\n                        //\r\n                        // Indicate that a retry is necessary but without decrementing the remaining\r\n                        // retries count. However, we may need to send down an STPG/RTPG also.\r\n                        // And we must set PTBU to a path that is in a different TPG.\r\n                        //\r\n                        sendTPG = TRUE;\r\n                        tpgException = TRUE;\r\n                        NT_ASSERT(!devInfoException);\r\n                        retry = TRUE;\r\n                        handled = TRUE;\r\n                        errorMask = DSM_RETRY_DONT_DECREMENT;\r\n                    }\r\n\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case STATUS_DEVICE_NOT_READY: {\r\n\r\n            if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&\r\n                scsiStatus == SCSISTAT_CHECK_CONDITION) {\r\n\r\n                if (validSense) {\r\n                    if (senseKey == SCSI_SENSE_NOT_READY &&\r\n                        addSenseCode == SCSI_ADSENSE_LUN_NOT_READY) {\r\n\r\n                        switch (addSenseCodeQualifier) {\r\n\r\n                            case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {\r\n\r\n                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                            TRACE_FLAG_RW,\r\n                                            \"DsmInterpretError (DevInfo %p): Manual intervention required. Asking for retry on Srb %p.\\n\",\r\n                                            DsmId,\r\n                                            Srb));\r\n\r\n                                //\r\n                                // This may be caused by NDU of controller firmware. It does not\r\n                                // necessarily indicate that the device won't be ready via other path(s).\r\n                                // Worth retrying instead of immediately failing back.\r\n                                //\r\n                                retry = TRUE;\r\n                                handled = TRUE;\r\n\r\n                                break;\r\n                            }\r\n\r\n                            case SCSI_SENSEQ_SPACE_ALLOC_IN_PROGRESS: {\r\n                                //\r\n                                // This indicates a logical block provisioning temporary resource exhaustion\r\n                                // condition and therefore we must allow the class layer to handle it.\r\n                                //\r\n                                retry = FALSE;\r\n                                handled = TRUE;\r\n\r\n                                break;\r\n                            }\r\n\r\n                            default: {\r\n\r\n                                TracePrint((TRACE_LEVEL_ERROR,\r\n                                            TRACE_FLAG_RW,\r\n                                            \"DsmInterpretError (DevInfo %p): Unhandled AddQual %x.\\n\",\r\n                                            DsmId,\r\n                                            addSenseCodeQualifier));\r\n\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n\r\n        default: {\r\n\r\n            TracePrint((TRACE_LEVEL_WARNING,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Unhandled status code %x.\\n\",\r\n                        DsmId,\r\n                        *Status));\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    if (!handled) {\r\n\r\n        //\r\n        // The NTSTATUS didn't indicate a fail-over condition, but\r\n        // check various srb status for failover-class error.\r\n        //\r\n        switch (Srb->SrbStatus) {\r\n            case SRB_STATUS_SELECTION_TIMEOUT:\r\n            case SRB_STATUS_INVALID_LUN:\r\n            case SRB_STATUS_INVALID_TARGET_ID:\r\n            case SRB_STATUS_NO_DEVICE:\r\n            case SRB_STATUS_NO_HBA:\r\n            case SRB_STATUS_INVALID_PATH_ID: {\r\n\r\n                //\r\n                // All of these are fatal.\r\n                //\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError (DevInfo %p): SrbStatus 0x%x. Will initiate fail over.\\n\",\r\n                            DsmId,\r\n                            Srb->SrbStatus));\r\n\r\n                failover = TRUE;\r\n                break;\r\n            }\r\n\r\n\r\n            default: {\r\n\r\n                if ((scsiStatus == SCSISTAT_CHECK_CONDITION) &&\r\n                    (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {\r\n\r\n                    if (validSense) {\r\n\r\n                        switch (senseKey) {\r\n\r\n                            case SCSI_SENSE_NO_SENSE: {\r\n\r\n                                if (addSenseCode == SCSI_ADSENSE_NO_SENSE &&\r\n                                    addSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE) {\r\n\r\n                                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                                TRACE_FLAG_RW,\r\n                                                \"DsmInterpretError (DevInfo %p): CheckCondition with no sense info. Will initiate fail over.\\n\",\r\n                                                DsmId));\r\n\r\n                                    //\r\n                                    // This could be a transient error generated\r\n                                    // in response to potentially a hardware fault.\r\n                                    // Worth trying another path.\r\n                                    //\r\n                                    failover = TRUE;\r\n                                    handled = TRUE;\r\n                                }\r\n\r\n                                break;\r\n                            }\r\n\r\n                            case SCSI_SENSE_ILLEGAL_REQUEST: {\r\n\r\n                                if (addSenseCode == SCSI_ADSENSE_INVALID_LUN) {\r\n\r\n                                    if (addSenseCodeQualifier == 0x00) {\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): Invalid LUN. Will initiate fail over.\\n\",\r\n                                                    DsmId));\r\n\r\n                                        //\r\n                                        // LUN may still exist on other path(s).\r\n                                        // Worth a failover.\r\n                                        //\r\n                                        failover = TRUE;\r\n                                        handled = TRUE;\r\n                                    }\r\n                                }\r\n\r\n                                break;\r\n                            }\r\n\r\n                            case SCSI_SENSE_HARDWARE_ERROR: {\r\n\r\n                                if (addSenseCode == SPC3_SCSI_ADSENSE_LOGICAL_UNIT_COMMAND_FAILED) {\r\n\r\n                                    if (addSenseCodeQualifier == SPC3_SCSI_SENSEQ_SET_TARGET_PORT_GROUPS_FAILED) {\r\n\r\n                                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                                    TRACE_FLAG_RW,\r\n                                                    \"DsmInterpretError (DevInfo %p): STPG failed. Will initiate fail over.\\n\",\r\n                                                    DsmId));\r\n\r\n                                        //\r\n                                        // If an STPG failed, treat as FATAL and get another\r\n                                        // path set to A/O via another STPG.\r\n                                        //\r\n                                        failover = TRUE;\r\n                                        handled = TRUE;\r\n                                    }\r\n                                } else if ((addSenseCode == SCSI_ADSENSE_LOGICAL_UNIT_ERROR && addSenseCodeQualifier == SCSI_SENSEQ_TIMEOUT_ON_LOGICAL_UNIT) ||\r\n                                           (addSenseCode == SCSI_ADSENSE_DATA_TRANSFER_ERROR && addSenseCodeQualifier == SCSI_SENSEQ_INITIATOR_RESPONSE_TIMEOUT)) {\r\n\r\n                                    //\r\n                                    // Could potentially indicate a dropped FC packet. Retry (along another\r\n                                    // path, based on the LB policy).\r\n                                    //\r\n                                    retry = TRUE;\r\n                                    handled = TRUE;\r\n                                }\r\n\r\n                                break;\r\n                            }\r\n\r\n                            default: {\r\n\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (!handled) {\r\n\r\n                    TracePrint((TRACE_LEVEL_WARNING,\r\n                                TRACE_FLAG_RW,\r\n                                \"DsmInterpretError (DevInfo %p): Unhandled SRB Status 0x%x. Sense data %x|%x|%x.\\n\",\r\n                                DsmId,\r\n                                Srb->SrbStatus,\r\n                                validSense ? senseKey : 0xFF,\r\n                                validSense ? addSenseCode : 0xFF,\r\n                                validSense ? addSenseCodeQualifier : 0xFF));\r\n                }\r\n\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (failover) {\r\n        ULONG SpecialHandlingFlag = 0;\r\n\r\n        //\r\n        // If ALUA is supported, then it is possible that we may need to send\r\n        // down an STPG so build an IRP and fill in the SRB for STPG and send it down.\r\n        //\r\n        if (!DsmpIsSymmetricAccess(deviceInfo)) {\r\n\r\n            DsmpSetLBForPathFailingALUA(DsmContext, deviceInfo, TRUE, SpecialHandlingFlag);\r\n\r\n        } else {\r\n\r\n            //\r\n            // If device doesn't support ALUA, we just need to update\r\n            // states without sending down any commands (STPG)\r\n            //\r\n            DsmpSetLBForPathFailing(DsmContext, deviceInfo, TRUE, SpecialHandlingFlag);\r\n        }\r\n\r\n        errorMask = DSM_FATAL_ERROR;\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmInterpretError(DevInfo %p): Device changed to state %d\\n\",\r\n                    deviceInfo,\r\n                    deviceInfo->State));\r\n\r\n#if DBG\r\n        {\r\n            ULONG inx;\r\n            PDSM_GROUP_ENTRY group = deviceInfo->Group;\r\n            PDSM_DEVICE_INFO tempDevInfo;\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_RW,\r\n                        \"DsmInterpretError (DevInfo %p): Device %p in group %p being marked as failed. NTStatus 0x%x.\\n\",\r\n                        DsmId,\r\n                        deviceInfo,\r\n                        group,\r\n                        *Status));\r\n\r\n            for (inx = 0; inx < group->NumberDevices; inx++) {\r\n\r\n                tempDevInfo = group->DeviceList[inx];\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError (DevInfo %p): Device %p at %d. State %d.\\n\",\r\n                            DsmId,\r\n                            tempDevInfo,\r\n                            inx,\r\n                            tempDevInfo->State));\r\n            }\r\n        }\r\n#endif // DBG\r\n    }\r\n\r\n    if (retry) {\r\n\r\n        if (sendTPG) {\r\n\r\n            //\r\n            // If ALUA is supported, send down STPG/RTPG as appropriate.\r\n            //\r\n            if (!DsmpIsSymmetricAccess(deviceInfo)) {\r\n\r\n                DsmpSetPathForIoRetryALUA(DsmContext, deviceInfo, tpgException, devInfoException);\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_RW,\r\n                            \"DsmInterpretError(DevInfo %p): SRB request %p will be retried. PTBU set to %p.\\n\",\r\n                            deviceInfo,\r\n                            Srb,\r\n                            deviceInfo->Group->PathToBeUsed));\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    *Retry = retry;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmInterpretError (DevInfo %p): Exiting function returning errorMask %x.\\n\",\r\n                DsmId,\r\n                errorMask));\r\n\r\n    return errorMask;\r\n}\r\n\r\nBOOLEAN\r\nDsmIsAddressTypeSupported(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN ULONG AddressType\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when MPIO wants to know if the DSM supports a\r\n    particular storage address type.\r\n\r\n    This routine must be provided for DSMs of DsmType6 or higher.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value passed to DsmInitialize()\r\n    AddressType - The storage address type being queried.\r\n\r\nReturn Value:\r\n\r\n    TRUE - If the DSM supports the given storage address type.\r\n    FALSE - If the DSM does not support the given storage address type.\r\n\r\n--*/\r\n{\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    if (AddressType == STORAGE_ADDRESS_TYPE_BTL8)\r\n    {\r\n        return TRUE;\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\nNTSTATUS\r\nDsmDeviceNotUsed(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine indicates that the device represented by DsmId will not be\r\n    initialized completely by MPIO.\r\n    The DSM_ID list passed to other functions will no longer contain DsmId,\r\n    so internal structures should be updated accordingly.\r\n\r\n    This routine must be provided for DSMs of DsmType6 or higher.\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value given to the multipath driver during registration.\r\n    DsmId - Value referring to the uninitialized device.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS of the operation.\r\n\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO deviceInfo = (PDSM_DEVICE_INFO)DsmId;\r\n\r\n    DSM_ASSERT(deviceInfo->Group != NULL);\r\n    DSM_ASSERT(deviceInfo->Group->GroupSig == DSM_GROUP_SIG);\r\n\r\n    //\r\n    // Undo anything we did to build up the device in DsmInquire().\r\n    //\r\n    DsmRemoveDevice((PDSM_CONTEXT)DsmContext, DsmId, deviceInfo->FailGroup);\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nDsmUnload(\r\n    _In_ IN PVOID DsmContext\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called when the main module requires the DSM to be unloaded\r\n    (ie. prior to the main module unload).\r\n\r\nArguments:\r\n\r\n    DsmContext - Context value passed to DsmInitialize()\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS;\r\n\r\n--*/\r\n\r\n{\r\n    PVOID tempAddress = DsmContext;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmUnload (DsmCtxt %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    DsmpFreeDSMResources((PDSM_CONTEXT) DsmContext);\r\n\r\n    if (gMPIOControlObjectRefd) {\r\n\r\n        ObDereferenceObject(gMPIOControlObject);\r\n        gMPIOControlObjectRefd = FALSE;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmUnload (DsmCtxt %p): Exiting function.\\n\",\r\n                tempAddress));\r\n\r\n    //\r\n    // Stop the tracing subsystem.\r\n    //\r\n    WPP_CLEANUP(gDsmDriverObject);\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/msdsm.h",
    "content": "/*++\r\n\r\nCopyright (C) 2004-2010  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    msdsm.h\r\n\r\nAbstract:\r\n\r\n    Header for the Microsoft Device Specific Module (DSM).\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n#ifndef _MSDSM_H_\r\n#define _MSDSM_H_\r\n\r\n//\r\n// Maximum number of paths per device supported by the DSM.\r\n// This is a limit currently set by MPIO itself and needs to be updated if MPIO\r\n// supports more paths-per-device in the future.\r\n//\r\n#define DSM_MAX_PATHS 32\r\n\r\n//\r\n// MPIO control object's well known symbolic name\r\n//\r\n#define DSM_MPIO_CONTROL_OBJECT_SYMLINK         L\"\\\\DosDevices\\\\MPIOControl\"\r\n\r\n//\r\n// Location of System class node in the registry\r\n//\r\n#define DSM_SYSTEM_CLASS_GUID_KEY               L\"\\\\Registry\\\\Machine\\\\System\\\\CurrentControlSet\\\\Control\\\\Class\\\\{4D36E97D-E325-11CE-BFC1-08002BE10318}\"\r\n\r\n//\r\n// Values used for matching and figuring out the DriverVersion\r\n//\r\n#define DSM_INF_PATH                            L\"InfPath\"\r\n#define DSM_MSDSM_INF_PATH                      L\"msdsm.inf\"\r\n#define DSM_DRIVER_VERSION                      L\"DriverVersion\"\r\n#define DSM_DRIVER_VERSION_FIELD_DELIMITER      L'.'\r\n#define DSM_BUFFER_MAXCOUNT                     64\r\n\r\n//\r\n// MSDSM's display name.\r\n//\r\n#define DSM_FRIENDLY_NAME                       L\"Microsoft DSM\"\r\n\r\n//\r\n// Name of the value for the supported devices in the registry, found in the\r\n// DSM's Services' Parameters key\r\n//\r\n#define DSM_SUPPORTED_DEVICELIST_VALUE_NAME     L\"DsmSupportedDeviceList\"\r\n\r\n//\r\n// Value used to determine if per-IO statistics gathering needs to be turned OFF\r\n//\r\n#define DSM_DISABLE_STATISTICS                  L\"DsmDisableStatistics\"\r\n\r\n//\r\n// Names of the values in the registry for whether to use the same path for\r\n// sequential IOs when employing Least Blocks load balance policy, as well\r\n// as its size.\r\n//\r\n#define DSM_USE_CACHE_FOR_LEAST_BLOCKS          L\"DsmUseCacheForLeastBlocks\"\r\n#define DSM_CACHE_SIZE_FOR_LEAST_BLOCKS         L\"DsmCacheSizeForLeastBlocks\"\r\n\r\n//\r\n// Name of the value in the registry for the maximum request retry time during ALUA\r\n// state transitions. This value is found in the DSM's Services' Parameters key, and\r\n// applies only to Persistent Reservation commands.\r\n//\r\n#define DSM_MAX_STATE_TRANSITION_TIME_VALUE_NAME  L\"DsmMaximumStateTransitionTime\"\r\n\r\n\r\n//\r\n// Default max amount of time (in seconds) that a PR failing with retry-able UA will be retried\r\n//\r\n#define DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME    3\r\n\r\n//\r\n// Macro to translate seconds to ticks. Each system tick is 10^(-7) seconds.\r\n//\r\n#define DSM_SECONDS_TO_TICKS(_Seconds)              ((_Seconds) * 10000000)\r\n\r\n//\r\n// Size of the buffer allocated to retrieve device serial number.\r\n// This is as defined by SPC-3 spec. The identifier with the biggest size is\r\n// SCSI name type (0x8).\r\n//\r\n#define DSM_SERIAL_NUMBER_BUFFER_SIZE 255\r\n\r\n//\r\n// Number of LB Policies that are supported by this driver.\r\n//\r\n#define DSM_NUMBER_OF_LB_POLICIES 6\r\n\r\n//\r\n// Size of the buffer passed to read in Persistent Reserve keys.\r\n//\r\n#define DSM_READ_PERSISTENT_KEYS_BUFFER_SIZE  4096\r\n\r\n//\r\n// The default threshold for sequential IO for the Least Blocks load balance\r\n// policy is 1MB.\r\n//\r\n#define DSM_LEAST_BLOCKS_DEFAULT_THRESHOLD 0x00100000\r\n\r\n//\r\n// Initialization data structure that needs to be filled in for MPIO\r\n//\r\nextern DSM_INIT_DATA gDsmInitData;\r\n\r\n//\r\n// Macro used to round of a number to the nearest 8 byte aligned one.\r\n//\r\n#ifdef AlignOn8Bytes\r\n#undef AlignOn8Bytes\r\n#endif\r\n#define AlignOn8Bytes(x)    (((x) + 7) & ~7)\r\n\r\n//\r\n// Macro for determining minimum of two numbers\r\n//\r\n#ifdef MIN\r\n#undef MIN\r\n#endif\r\n#define MIN(a, b)           ((ULONGLONG)(a) < (ULONGLONG)(b) ? (a) : (b))\r\n\r\n//\r\n// Macro used to convert a 4 byte array to a ULONG (where byte 0 MSB, byte 3 LSB)\r\n//\r\n#define GetUlongFrom4ByteArray(UCharArray, ULongValue)                                 \\\r\n         ((UNALIGNED UCHAR *)&(ULongValue))[3] = ((UNALIGNED UCHAR *)(UCharArray))[0]; \\\r\n         ((UNALIGNED UCHAR *)&(ULongValue))[2] = ((UNALIGNED UCHAR *)(UCharArray))[1]; \\\r\n         ((UNALIGNED UCHAR *)&(ULongValue))[1] = ((UNALIGNED UCHAR *)(UCharArray))[2]; \\\r\n         ((UNALIGNED UCHAR *)&(ULongValue))[0] = ((UNALIGNED UCHAR *)(UCharArray))[3];\r\n\r\n//\r\n// Macro used to convert a ULONG into a 4 byte array (as big-endian)\r\n//\r\n#define Get4ByteArrayFromUlong(ULongValue, UCharArray)                                 \\\r\n         ((UNALIGNED UCHAR *)(UCharArray))[3] = ((UNALIGNED UCHAR *)&(ULongValue))[0]; \\\r\n         ((UNALIGNED UCHAR *)(UCharArray))[2] = ((UNALIGNED UCHAR *)&(ULongValue))[1]; \\\r\n         ((UNALIGNED UCHAR *)(UCharArray))[1] = ((UNALIGNED UCHAR *)&(ULongValue))[2]; \\\r\n         ((UNALIGNED UCHAR *)(UCharArray))[0] = ((UNALIGNED UCHAR *)&(ULongValue))[3];\r\n\r\n//\r\n// Macro to check if passed in opcode is a read, write\r\n//\r\n#define DsmIsReadRequest(_Opcode)       (_Opcode == SCSIOP_READ || _Opcode == SCSIOP_READ16)\r\n#define DsmIsWriteRequest(_Opcode)      (_Opcode == SCSIOP_WRITE || _Opcode == SCSIOP_WRITE16)\r\n#define DsmIsReadWrite(_Opcode)         (_Opcode == SCSIOP_READ || _Opcode == SCSIOP_READ16 || \\\r\n                                         _Opcode == SCSIOP_WRITE || _Opcode == SCSIOP_WRITE16)\r\n\r\n#define DsmIsReadCapacity( _Opcode )    (_Opcode == SCSIOP_READ_CAPACITY || _Opcode == SCSIOP_READ_CAPACITY16)\r\n\r\n\r\n//\r\n// Macro to find the number of bytes consumed by the array\r\n//\r\n#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))\r\n\r\n\r\n//\r\n// Signature used to identify various structures.\r\n// Used solely for debugging purposes.\r\n//\r\n#define DSM_DEVICE_SIG              0xAAAAAAAA\r\n#define DSM_GROUP_SIG               0x55555555\r\n#define DSM_FOG_SIG                 0x88888888\r\n#define DSM_TARGET_PORT_GROUP_SIG   0x33333333\r\n#define DSM_TARGET_PORT_SIG         0xCCCCCCCC\r\n#define DSM_CONTROLLER_SIG          0xEEEEEEEE\r\n\r\n#define WNULL             (L'\\0')\r\n#define WNULL_SIZE        (sizeof(WNULL))\r\n\r\n#if DBG\r\n\r\n//\r\n// NT_ASSERT wrapper.\r\n//\r\n#define DSM_ASSERT(exp)    if (DoAssert) {    \\\r\n                               NT_ASSERT(exp);   \\\r\n                           }\r\n\r\n#else // DBG\r\n\r\n#define DSM_ASSERT(exp)\r\n\r\n#endif // DBG\r\n\r\n#define DSM_PARAMETER_PATH_W                L\"MSDSM\\\\Parameters\"\r\n\r\n//\r\n// Pool Tags used in memory allocation\r\n//\r\n#define DSM_TAG_GENERIC                     '00ZZ'\r\n#define DSM_TAG_PASS_THRU                   '10ZZ'\r\n#define DSM_TAG_GROUP_ENTRY                 '20ZZ'\r\n#define DSM_TAG_FO_GROUP                    '30ZZ'\r\n#define DSM_TAG_DSM_CONTEXT                 '40ZZ'\r\n#define DSM_TAG_DEV_INFO                    '50ZZ'\r\n#define DSM_TAG_SERIAL_NUM                  '60ZZ'\r\n#define DSM_TAG_CTRL_INFO                   '70ZZ'\r\n#define DSM_TAG_SUPPORTED_DEV               '80ZZ'\r\n#define DSM_TAG_REG_PATH                    '90ZZ'\r\n#define DSM_TAG_FOG_DEV_ENTRY               'A0ZZ'\r\n#define DSM_TAG_DEV_ID                      'B0ZZ'\r\n#define DSM_TAG_DEV_NAME                    'C0ZZ'\r\n#define DSM_TAG_LB_POLICY                   'D0ZZ'\r\n#define DSM_TAG_PR_KEYS                     'E0ZZ'\r\n#define DSM_TAG_RESERVED_DEVICE             'F0ZZ'\r\n#define DSM_TAG_BIN_TO_ASCII                '01ZZ'\r\n#define DSM_TAG_TARGET_PORT_LIST_ENTRY      '11ZZ'\r\n#define DSM_TAG_TARGET_PORT_GROUP_ENTRY     '21ZZ'\r\n#define DSM_TAG_RELATIVE_TARGET_PORT_ID     '31ZZ'\r\n#define DSM_TAG_TARGET_PORT_GROUPS          '41ZZ'\r\n#define DSM_TAG_CONTROLLER_LIST_ENTRY       '51ZZ'\r\n#define DSM_TAG_CONTROLLER_INFO             '61ZZ'\r\n#define DSM_TAG_IO_STATUS_BLOCK             '71ZZ'\r\n#define DSM_TAG_DEVICE_ID_LIST              '81ZZ'\r\n#define DSM_TAG_TP_DEVICE_LIST_ENTRY        '91ZZ'\r\n#define DSM_TAG_RETRY_RESERVE               'A1ZZ'\r\n#define DSM_TAG_WORKITEM                    'B1ZZ'\r\n#define DSM_TAG_SCSI_ADDRESS                'C1ZZ'\r\n#define DSM_TAG_FAIL_DEVINFO_LIST_ENTRY     'D1ZZ'\r\n#define DSM_TAG_TPG_COMPLETION_CONTEXT      'E1ZZ'\r\n#define DSM_TAG_SCSI_REQUEST_BLOCK          'F1ZZ'\r\n#define DSM_TAG_SCSI_SENSE_INFO             '02ZZ'\r\n#define DSM_TAG_SPT_DATA_BUFFER             '12ZZ'\r\n#define DSM_TAG_REG_KEY_RELATED             '22ZZ'\r\n#define DSM_TAG_DEV_HARDWARE_ID             '32ZZ'\r\n#define DSM_TAG_REG_VALUE_RELATED           '42ZZ'\r\n#define DSM_TAG_ZOMBIEGROUP_ENTRY           '52ZZ'\r\n#define DSM_TAG_PERSISTENT_RESERVATION      '62ZZ'\r\n\r\n//\r\n// Parameters subkey name under HKLM\\System\\CCS\\Services\\MSDSM\r\n//\r\n#define DSM_SERVICE_PARAMETERS              L\"Parameters\"\r\n\r\n//\r\n// Load Balance settings are persisted in the registry under this key\r\n//\r\n#define DSM_LOAD_BALANCE_SETTINGS           L\"DsmLoadBalanceSettings\"\r\n\r\n//\r\n// Load Balance settings on a VID/PID basis are persistented in the registry\r\n// under this key\r\n//\r\n#define DSM_TARGETS_LOAD_BALANCE_SETTING    L\"DsmTargetsLoadBalanceSetting\"\r\n\r\n//\r\n// Values persisted per device:\r\n// 1. Load Balance Policy\r\n// 2. Preferred Path\r\n// 3. Whether LB policy has been explicitly set\r\n//\r\n#define DSM_LOAD_BALANCE_POLICY             L\"DsmLoadBalancePolicy\"\r\n#define DSM_PREFERRED_PATH                  L\"DsmPreferredPath\"\r\n#define DSM_POLICY_EXPLICITLY_SET           L\"DsmLoadBalancePolicyExplicitlySet\"\r\n\r\n//\r\n// Prefix for subkey created for each path\r\n//\r\n#define DSM_PATH                            L\"DSMPath\"\r\n\r\n//\r\n// Values persisted per path:\r\n// 1. Whether primary\r\n// 2. Whether optimized\r\n// 3. Path weight.\r\n//\r\n// Primary      Optimized       State\r\n//====================================\r\n// True         True            Active-Optimized\r\n// True         False           Active-Unoptimized\r\n// False        True            StandBy\r\n// False        False           Unavailable\r\n//\r\n#define DSM_PRIMARY_PATH            L\"DsmPrimaryPath\"\r\n#define DSM_OPTIMIZED_PATH          L\"DsmOptimizedPath\"\r\n#define DSM_PATH_WEIGHT             L\"DsmPathWeight\"\r\n\r\n//\r\n// Indicates that device doesn't support ALUA.\r\n//\r\n#define DSM_DEVINFO_ALUA_NOT_SUPPORTED  0\r\n\r\n//\r\n// Implies that device supports implicit ALUA transistions.\r\n//\r\n#define DSM_DEVINFO_ALUA_IMPLICIT       1\r\n\r\n//\r\n// Implies that device supports explicit ALUA state transitions.\r\n//\r\n#define DSM_DEVINFO_ALUA_EXPLICIT       2\r\n\r\n//\r\n// Type of device identifier (VPD 0x83)\r\n//\r\ntypedef enum _DSM_DEVID_TYPE {\r\n    DSM_DEVID_SERIAL_NUMBER = 1,\r\n    DSM_DEVID_RELATIVE_TARGET_PORT,\r\n    DSM_DEVID_TARGET_PORT_GROUP\r\n} DSM_DEVID_TYPE, *PDSM_DEVID_TYPE;\r\n\r\n#define _DSM_TERNARY_BOOLEAN UCHAR\r\ntypedef _DSM_TERNARY_BOOLEAN DSM_TERNARY_BOOLEAN, *PDSM_TERNARY_BOOLEAN;\r\n#define DSM_TERNARY_UNKNOWN 0\r\n#define DSM_TERNARY_TRUE 1\r\n#define DSM_TERNARY_FALSE 2\r\n\r\n//\r\n// Macro to determine if _Id2 is more preferred than _Id1 to build a device's\r\n// serial number.\r\n//\r\n#define DsmpIsPreferredDeviceId(_Id1, _Id2)     (((_Id2) == StorageIdTypeScsiNameString) || \\\r\n                                                 ((_Id2) == StorageIdTypeFCPHName && (_Id1) != StorageIdTypeScsiNameString) || \\\r\n                                                 ((_Id2) == StorageIdTypeEUI64 && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName) || \\\r\n                                                 ((_Id2) == StorageIdTypeVendorId && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName && (_Id1) != StorageIdTypeEUI64) || \\\r\n                                                 ((_Id2) == StorageIdTypeVendorSpecific && (_Id1) != StorageIdTypeScsiNameString && (_Id1) != StorageIdTypeFCPHName && (_Id1) != StorageIdTypeEUI64 && (_Id1) != StorageIdTypeVendorId))\r\n\r\n//\r\n// Device State\r\n//\r\ntypedef enum _DSM_DEVICE_STATE {\r\n\r\n    //\r\n    // If ALUA is not supported, this state indicates that the device is active\r\n    // and a request can be sent to the device.\r\n    // If ALUA is supported, then this state indicates optimizied device-path\r\n    // pair for the device.\r\n    //\r\n    DSM_DEV_ACTIVE_OPTIMIZED = 0,\r\n\r\n    //\r\n    // If ALUA is not supported, this state is not used.\r\n    // If ALUA is supported, then this state indicates active but unoptimized\r\n    // device-path pairing for the device. Can be used in in case no\r\n    // active/optimized path is available to service the IO.\r\n    //\r\n    DSM_DEV_ACTIVE_UNOPTIMIZED,\r\n\r\n    //\r\n    // If ALUA is not supported, this state indicates that the device is in\r\n    // standby state. A request can be sent to the device in this state.\r\n    // If ALUA is supported, then this state indicates standby device-path\r\n    // pairing and only certain requests can be handled in this state.\r\n    //\r\n    DSM_DEV_STANDBY,\r\n\r\n    //\r\n    // If ALUA is not supported, this state is not used.\r\n    // If ALUA is supported, then this state indicates that the device-path pairing\r\n    // is not active and incapable of handling any requests.\r\n    //\r\n    DSM_DEV_UNAVAILABLE,\r\n\r\n    //\r\n    // If ALUA is not supported, this state is not used.\r\n    // If ALUA is supported, then this state indicates that the device-path pairing\r\n    // (actually its TPG) is in a transitioning state.\r\n    //\r\n    DSM_DEV_TRANSITIONING = 15,\r\n\r\n    //\r\n    // Initial state when devInfo is created.\r\n    //\r\n    DSM_DEV_NOT_USED_STATE = 16,\r\n\r\n    //\r\n    // Indicates that the state was undetermined (this is applicable only for\r\n    // a deviceInfo's DesiredState or if the device instance's path was not\r\n    // determined).\r\n    //\r\n    DSM_DEV_UNDETERMINED,\r\n\r\n    //\r\n    // Indicates that a request sent down previously failed with a fatal error\r\n    //\r\n    DSM_DEV_FAILED,\r\n\r\n    //\r\n    // Indicates that InvalidatePath has been called\r\n    //\r\n    DSM_DEV_INVALIDATED,\r\n\r\n    //\r\n    // This indicates the device is about to be removed. No new request\r\n    // should be sent to the device.\r\n    //\r\n    DSM_DEV_REMOVE_PENDING,\r\n\r\n    //\r\n    // This indicates the device has been removed.\r\n    //\r\n    DSM_DEV_REMOVED\r\n\r\n} DSM_DEVICE_STATE, *PDSM_DEVICE_STATE;\r\n\r\n//\r\n// Device states supported\r\n//\r\n#define DSM_STATE_ACTIVE_OPTIMIZED_SUPPORTED        0\r\n#define DSM_STATE_STANDBY_SUPPORTED                 1\r\n#define DSM_STATE_ACTIVE_UNOPTIMIZED_SUPPORTED      2\r\n#define DSM_STATE_UNAVAILABLE_SUPPORTED             4\r\n\r\n\r\n//\r\n// Macro to determine if devInfo is in a failure state.\r\n//\r\n#define DsmpIsDeviceFailedState(_State)             ((_State) > DSM_DEV_NOT_USED_STATE)\r\n\r\n//\r\n// Macro to determine if devInfo was initialized.\r\n//\r\n#define DsmpIsDeviceInitialized(_DeviceInfo)        ((_DeviceInfo)->Initialized)\r\n\r\n//\r\n// Macro to determine if device is \"usable\" (ie. IsPathActive was successfully called).\r\n//\r\n#define DsmpIsDeviceUsable(_DeviceInfo)             ((_DeviceInfo)->Usable)\r\n\r\n//\r\n// Macro to determine if devInfo was used to send down registration.\r\n// It the devInfo's group is not reserved, then the devInfo doesn't need to have\r\n// had a register go down it.\r\n// It the group is reserved, then the devInfo MUST have had a register go down it\r\n// for it to be used.\r\n//\r\n#define DsmpIsDeviceUsablePR(_DeviceInfo)           (!(_DeviceInfo)->Group->PRKeyValid || (_DeviceInfo)->PRKeyRegistered)\r\n\r\n\r\n//\r\n// Macro to determine if _State2 is a more preferred state than _State1.\r\n//\r\n#define DsmpIsBetterDeviceState(_State1, _State2)   (((_State1) == DSM_DEV_STANDBY && (_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED) || \\\r\n                                                     ((_State1) == DSM_DEV_UNAVAILABLE && \\\r\n                                                      ((_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED || (_State2) == DSM_DEV_STANDBY)) || \\\r\n                                                     ((_State1) == DSM_DEV_TRANSITIONING && \\\r\n                                                      ((_State2) == DSM_DEV_ACTIVE_UNOPTIMIZED || (_State2) == DSM_DEV_STANDBY) || (_State2) == DSM_DEV_UNAVAILABLE))\r\n\r\n//\r\n// Macro to determine if passed in _State is active.\r\n//\r\n#define DsmpIsDeviceStateActive(_State)             ((_State) == DSM_DEV_ACTIVE_OPTIMIZED || (_State) == DSM_DEV_ACTIVE_UNOPTIMIZED)\r\n\r\n//\r\n// Macro to determine if symmetric access to the storage\r\n//\r\n#define DsmpIsSymmetricAccess(_DeviceInfo)          ((_DeviceInfo)->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED || \\\r\n                                                     ((_DeviceInfo)->ALUASupport == DSM_DEVINFO_ALUA_IMPLICIT && \\\r\n                                                      (_DeviceInfo)->Group->Symmetric))\r\n\r\n//\r\n// Multi-path Group State\r\n//\r\ntypedef enum _DSM_GROUP_STATE {\r\n\r\n    //\r\n    // This indicates that the device is in working state.\r\n    //\r\n    DSM_GP_NORMAL = 1,\r\n\r\n    //\r\n    // This indicates that there is a pending reservation failover\r\n    //\r\n    DSM_GP_PENDING,\r\n\r\n    //\r\n    // This indicates that the device has lost all its paths\r\n    //\r\n    DSM_GP_FAILED\r\n\r\n} DSM_GROUP_STATE, *PDSM_GROUP_STATE;\r\n\r\n//\r\n// Fail-Over Group State\r\n//\r\ntypedef enum _DSM_FAILOVER_GROUP_STATE {\r\n\r\n    //\r\n    // This indicates that the path is in working state.\r\n    //\r\n    DSM_FG_NORMAL = 1,\r\n\r\n    //\r\n    // This indicates the path which had failed earlier\r\n    // is back to working state now.\r\n    //\r\n    DSM_FG_FAILBACK,\r\n\r\n    //\r\n    // This indicates the path is about to be removed\r\n    //\r\n    DSM_FG_PENDING_REMOVE,\r\n\r\n    //\r\n    // This indicates the path has failed.\r\n    //\r\n    DSM_FG_FAILED\r\n\r\n} DSM_FAILOVER_GROUP_STATE, *PDSM_FAILOVER_GROUP_STATE;\r\n\r\n#define DsmpIsPathFailedState(_State)   ((_State) >= DSM_FG_PENDING_REMOVE)\r\n\r\n//\r\n// DSM Context is the global driver context that gets passed to each of the DSM\r\n// entry points.\r\n//\r\n// The DSM Context will maintain a list of all DeviceInfos (device-path pairing).\r\n// It will maintain a list of Group entries. Each entry in the Group list will\r\n//         represent a LUN's different instances down different paths (i.e. DeviceInfos).\r\n//         Each entry in the Group will maintain a list of target port groups.\r\n//         Each entry in the target port group list will maintain a list of target\r\n//         ports that make up the target port group. Every deviceInfo that isn't\r\n//         in a failure state will be in the same state as the Asymmetric Access\r\n//         State of the target port group.\r\n// There will be a list of Fail Over Group entries, where each entry represents\r\n//         the list of devices that fail over as a group (i.e. devices on the same path).\r\n// There will also be a list of controller entries, representing the controllers\r\n//         on all storages connected to the system.\r\n//\r\ntypedef struct _DSM_CONTEXT {\r\n\r\n    //\r\n    // Used to synchronize access to the SupportedDevices list.\r\n    //\r\n    KSPIN_LOCK SupportedDevicesListLock;\r\n\r\n    //\r\n    // List of supported devices - added into the INF.\r\n    //\r\n    UNICODE_STRING SupportedDevices;\r\n\r\n    //\r\n    // Used to synchronize access to the elements in this structure.\r\n    //\r\n    EX_SPIN_LOCK DsmContextLock;\r\n\r\n    //\r\n    // Flag cached that indicates if statistics don't need to be gathered\r\n    //\r\n    BOOLEAN DisableStatsGathering;\r\n\r\n    UCHAR Reserved[3];\r\n\r\n    //\r\n    // Number of devices currently found.\r\n    //\r\n    ULONG NumberDevices;\r\n\r\n    //\r\n    // List of devices.\r\n    //\r\n    LIST_ENTRY DeviceList;\r\n\r\n    //\r\n    // Number of multi-path groups.\r\n    //\r\n    ULONG NumberGroups;\r\n\r\n    //\r\n    // List of multi-path groups.\r\n    //\r\n    LIST_ENTRY GroupList;\r\n\r\n    //\r\n    // Number of fail-over groups.\r\n    //\r\n    ULONG NumberFOGroups;\r\n\r\n    //\r\n    // List of fail-over groups.\r\n    //\r\n    LIST_ENTRY FailGroupList;\r\n\r\n    //\r\n    // Number of controllers.\r\n    //\r\n    ULONG NumberControllers;\r\n\r\n    //\r\n    // List of controllers\r\n    //\r\n    LIST_ENTRY ControllerList;\r\n\r\n    //\r\n    // Number of stale fail-over groups\r\n    //\r\n    ULONG NumberStaleFOGroups;\r\n\r\n    //\r\n    // List of stale fail-over groups maintained for paths for which all devices\r\n    // have gotten removed but for which there is still outstanding IO-statistics\r\n    //\r\n    LIST_ENTRY StaleFailGroupList;\r\n\r\n    //\r\n    // Context value passed to the DSM from MPIO.\r\n    //\r\n    PVOID MPIOContext;\r\n\r\n\r\n    //\r\n    // Look-aside list of completion routine context structures.\r\n    //\r\n    NPAGED_LOOKASIDE_LIST CompletionContextList;\r\n\r\n} DSM_CONTEXT, *PDSM_CONTEXT;\r\n\r\n//\r\n// Statistics structure. Used by the device and path routines.\r\n//\r\ntypedef struct _DSM_STATS {\r\n\r\n    ULONG      NumberReads;\r\n    ULONG      NumberWrites;\r\n    ULONGLONG  BytesRead;\r\n    ULONGLONG  BytesWritten;\r\n\r\n} DSM_STATS, *PDSM_STATS;\r\n\r\n\r\n//\r\n// Information about each device that is supported by the DSM.\r\n//\r\ntypedef struct _DSM_DEVICE_INFO {\r\n\r\n    //\r\n    // To link to the next device info structure in the list\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // The device SIG. Used for debug.\r\n    //\r\n    ULONG DeviceSig;\r\n\r\n    //\r\n    // Back-pointer to the DSM_CONTEXT.\r\n    //\r\n    PVOID DsmContext;\r\n\r\n    //\r\n    // The underlying port driver PDO.\r\n    //\r\n    PDEVICE_OBJECT PortPdo;\r\n\r\n    //\r\n    // The port FDO to which PortPdo is attached.\r\n    //\r\n    PDEVICE_OBJECT PortFdo;\r\n\r\n    //\r\n    // The DeviceObject to which I/Os generated by the DSM should\r\n    // be sent. This is given to us by MPIO.\r\n    //\r\n    PDEVICE_OBJECT TargetObject;\r\n\r\n    //\r\n    // The multi-path group to which this device belongs.\r\n    //\r\n    struct _DSM_GROUP_ENTRY *Group;\r\n\r\n    //\r\n    // The fail-over group to which this device belongs.\r\n    //\r\n    struct _DSM_FAILOVER_GROUP *FailGroup;\r\n\r\n    //\r\n    // The controller through which this device showed up.\r\n    //\r\n    struct _DSM_CONTROLLER_LIST_ENTRY *Controller;\r\n\r\n    //\r\n    // The Target Port Group that this device belongs to.\r\n    //\r\n    struct _DSM_TARGET_PORT_GROUP_ENTRY *TargetPortGroup;\r\n\r\n    //\r\n    // The Target Port that this device was exposed via.\r\n    //\r\n    struct _DSM_TARGET_PORT_LIST_ENTRY *TargetPort;\r\n\r\n    //\r\n    // The current state of this device: ACTIVE_O, ACTIVE_U, STANDBY, UNAVAILABLE, etc.\r\n    //\r\n    DSM_DEVICE_STATE State;\r\n\r\n    //\r\n    // Previous state of this device. Updated whenever this deviceInfo makes a\r\n    // state transition.\r\n    //\r\n    DSM_DEVICE_STATE PreviousState;\r\n\r\n    //\r\n    // The desired state of this device: based on PrimaryPath and OptimizedPath\r\n    // specified in the registry.\r\n    //\r\n    DSM_DEVICE_STATE DesiredState;\r\n\r\n    //\r\n    // The ALUA state of the TPG immediately after a ReportTPG is issued.\r\n    //\r\n    DSM_DEVICE_STATE ALUAState;\r\n\r\n    //\r\n    // Holds state information temporarily while applying LB policy. Used in case\r\n    // changes need to be reverted in case of failure to apply the policy.\r\n    //\r\n    DSM_DEVICE_STATE TempPreviousStateForLB;\r\n\r\n    //\r\n    // This is to save off the last known non-failed state.\r\n    // In case of an error down this deviceInfo, it is marked to be in Failed state.\r\n    // However, if no remove comes down for this device and a PathVerify down this\r\n    // deviceInfo succeeds, we need to put the deviceInfo back into a usable state.\r\n    //\r\n    DSM_DEVICE_STATE LastKnownGoodState;\r\n\r\n    //\r\n    // This counter indicates that this deviceInfo is being used and a remove\r\n    // must thus wait until the counter falls to 0.\r\n    //\r\n    LONG BlockRemove;\r\n\r\n\r\n    //\r\n    // This indicates whether this device has handled a register/register_ignore_existing request,\r\n    // irrespective of the actual status of the operation.\r\n    //\r\n    BOOLEAN RegisterServiced;\r\n\r\n    //\r\n    // This flag is set when a register/register_ignore_existing succeeds down this device-path pair.\r\n    //\r\n    BOOLEAN PRKeyRegistered;\r\n\r\n    //\r\n    // Indicates whether the serial number was embedded in the device\r\n    // descriptor, or it was allocated.\r\n    //\r\n    BOOLEAN SerialNumberAllocated;\r\n\r\n    //\r\n    // Flag to indicate that SetDeviceInfo has been called (and succeeded) on this device\r\n    //\r\n    BOOLEAN Initialized;\r\n\r\n    //\r\n    // Flag to indicate that IsPathActive has been called (and succeeded) on this device.\r\n    //\r\n    BOOLEAN Usable;\r\n\r\n    //\r\n    // Flag to indicate if IALUAE was disabled (via mode select)\r\n    //\r\n    BOOLEAN ImplicitDisabled;\r\n\r\n    //\r\n    // Flag to indicate that RTPG has already been sent down in Inquire, so\r\n    // PathVerify can ignore sending down one more if it is called during\r\n    // device initialization.\r\n    //\r\n    BOOLEAN IgnorePathVerify;\r\n\r\n    //\r\n    // Bit map indicating whether (and what kind) of ALUA support.\r\n    //\r\n    UCHAR ALUASupport;\r\n\r\n    //\r\n    // Weight assigned to this path by management application. This is used\r\n    // when doing Load Balancing based on weighted paths.\r\n    //\r\n    ULONG PathWeight;\r\n\r\n    //\r\n    // Number of requests outstanding on this device.\r\n    //\r\n    LONG NumberOfRequestsInProgress;\r\n\r\n    //\r\n    // I/O, Fail-Over statistics.\r\n    //\r\n    DSM_STATS DeviceStats;\r\n\r\n    //\r\n    // The device's serial number.\r\n    //\r\n    PSTR SerialNumber;\r\n\r\n    //\r\n    // The scsi address of the port pdo.\r\n    //\r\n    PSCSI_ADDRESS ScsiAddress;\r\n\r\n\r\n    //\r\n    // Kernel structure that describes this device. Passed in to Inquire.\r\n    //\r\n    // NOTE: Descriptor should be the LAST field in this structure\r\n    //\r\n    STORAGE_DEVICE_DESCRIPTOR Descriptor;\r\n\r\n} DSM_DEVICE_INFO, *PDSM_DEVICE_INFO;\r\n\r\ntypedef enum _DSM_DEFAULT_LB_POLICY_TYPE {\r\n    DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY = 0,  // DSM assigned based on LUN access capability\r\n    DSM_DEFAULT_LB_POLICY_DSM_WIDE,             // Admin has set a DSM-wide default policy\r\n    DSM_DEFAULT_LB_POLICY_VID_PID,              // Admin has set a default policy for LUN's VID/PID\r\n    DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT          // Admin has explicitly set the policy on the LUN\r\n} DSM_DEFAULT_LB_POLICY_TYPE, *PDSM_DEFAULT_LB_POLICY_TYPE;\r\n\r\ntypedef ULONG   DSM_LOAD_BALANCE_TYPE, *PDSM_LOAD_BALANCE_TYPE;\r\n\r\n\r\n//\r\n// Information about multi-path groups: The same device found via multiple paths\r\n// are put under one group. Each group will have it's own Load Balance policy\r\n// settings. In other words, Load Balance policy settings are on per-device basis.\r\n//\r\ntypedef struct _DSM_GROUP_ENTRY {\r\n\r\n    //\r\n    // To link to the next entry in the multi-path group.\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Group signature. Used for debug.\r\n    //\r\n    ULONG GroupSig;\r\n\r\n    //\r\n    // Ordinal of creation. Never decremented.\r\n    //\r\n    ULONG GroupNumber;\r\n\r\n    //\r\n    // State of the group.\r\n    //\r\n    DSM_GROUP_STATE State;\r\n\r\n    //\r\n    // Number of devices in the multi-path group.\r\n    //\r\n    ULONG NumberDevices;\r\n\r\n    //\r\n    // Array of devices belonging to this group.\r\n    //\r\n    PDSM_DEVICE_INFO DeviceList[DSM_MAX_PATHS];\r\n\r\n    //\r\n    // Max time to retry failed PR requests\r\n    //\r\n    ULONG MaxPRRetryTimeDuringStateTransition;\r\n\r\n    //\r\n    // Number of target port groups that this device is accessible via.\r\n    //\r\n    ULONG NumberTargetPortGroups;\r\n\r\n    //\r\n    // Array of the target port groups that this LUN belongs in.\r\n    //\r\n    struct _DSM_TARGET_PORT_GROUP_ENTRY *TargetPortGroupList[DSM_MAX_PATHS];\r\n\r\n    //\r\n    // Key used in Persistent Reserve\\Release. This key is provided to the DSM\r\n    // by Cluster service. If cluster service has provided the key PRKeyValid\r\n    // is set to TRUE. PRKeyValid is set to FALSE otherwise.\r\n    // PRServiceAction, PRType and PRScope are the service action, type and\r\n    // scope associated with the PR registration.\r\n    //\r\n    UCHAR PersistentReservationRegisteredKey[8];\r\n    UCHAR PRServiceAction;\r\n    UCHAR PRType;\r\n    UCHAR PRScope;\r\n    UCHAR PRKeyValid;\r\n\r\n\r\n    //\r\n    // Flag used to denote that LU access is symmetric down all paths\r\n    //\r\n    BOOLEAN Symmetric;\r\n\r\n    //\r\n    // Flag to indicate whether or not to use same path for sequential IO\r\n    // when employing Least Blocks load balance policy.\r\n    //\r\n    BOOLEAN UseCacheForLeastBlocks;\r\n\r\n    //\r\n    // Flag used to indicate if a throttle request succeeded.\r\n    //\r\n    ULONG Throttled;\r\n\r\n    //\r\n    // Counter to track the number of RTPG in flight.\r\n    //\r\n    ULONG InFlightRTPG;\r\n\r\n    //\r\n    // A bitmask of which devices are currently reserved.\r\n    //\r\n    ULONG ReservationList;\r\n\r\n    //\r\n    // Which type of Load Balancing is being performed.\r\n    //\r\n    DSM_LOAD_BALANCE_TYPE LoadBalanceType;\r\n\r\n    //\r\n    // Indicates how the Load Balancing policy was selected.\r\n    //\r\n    DSM_DEFAULT_LB_POLICY_TYPE LBPolicySelection;\r\n\r\n    //\r\n    // The path to use when possible - if in F.O. Only, if failover had taken\r\n    // place and this path comes back online, failback to this path will take\r\n    // place.\r\n    //\r\n    ULONGLONG PreferredPath;\r\n\r\n    //\r\n    // The path to choose when Round Robin Load Balance policy is in use\r\n    //\r\n    PVOID PathToBeUsed;\r\n\r\n    //\r\n    // Size of cache set by Admin. Used in case of handling sequential\r\n    // IO in Least Blocks policy.\r\n    //\r\n    ULONGLONG CacheSizeForLeastBlocks;\r\n\r\n    //\r\n    // The HardwareId (VID/PID) of the LUN\r\n    //\r\n    PWSTR HardwareId;\r\n\r\n    //\r\n    // The registry key under which Load Balance Policy settings\r\n    // are stored in the registry for this Device Group.\r\n    //\r\n    PWSTR RegistryKeyName;\r\n\r\n    //\r\n    // Number of failing deviceInfos\r\n    //\r\n    ULONG NumberFailingDevInfos;\r\n\r\n    //\r\n    // To link the list of failed A/O devInfos and the corresponding non-A/O\r\n    // devInfos that are temporarily being used to service IO until STPG can\r\n    // properly update the device states. This is applicable only for ALUA\r\n    // devices.\r\n    //\r\n    LIST_ENTRY FailingDevInfoList;\r\n\r\n    //\r\n    // General Purpose Event.\r\n    //\r\n    KEVENT Event;\r\n\r\n} DSM_GROUP_ENTRY, *PDSM_GROUP_ENTRY;\r\n\r\n//\r\n// The collection of devices on one path. These fail-over as a unit.\r\n// A path is considered an I_T nexus, i.e. Initiator port to Target (controller) port.\r\n//\r\ntypedef struct _DSM_FAILOVER_GROUP {\r\n\r\n    //\r\n    // To link to the next entry in the failover group\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Signature. Used for debug.\r\n    //\r\n    ULONG FailOverSig;\r\n\r\n    //\r\n    // State of the Path.\r\n    //\r\n    DSM_FAILOVER_GROUP_STATE State;\r\n\r\n    //\r\n    // The pathId corresponding to this FOG. It may or may not be\r\n    // the same as what MPIO gave us as the default value.\r\n    //\r\n    PVOID PathId;\r\n\r\n    //\r\n    // The default pathId (port FDO).\r\n    //\r\n    PDEVICE_OBJECT MPIOPath;\r\n\r\n    //\r\n    // Last LBA\r\n    //\r\n    ULONGLONG LastLba;\r\n\r\n    //\r\n    // Cumulative outstanding IO (in terms of size)\r\n    //\r\n    ULONGLONG OutstandingBytesOfIO;\r\n\r\n    //\r\n    // Count of inflight IOs. This will be used in LQD load balance policy.\r\n    //\r\n    volatile LONG NumberOfRequestsInFlight;\r\n\r\n    //\r\n    // Number of devices in this FOG.\r\n    //\r\n    ULONG Count;\r\n\r\n    //\r\n    // List of devices that will over together.\r\n    //\r\n    LIST_ENTRY FOG_DeviceList;\r\n\r\n    //\r\n    // List of zombie groups (in case a device is removed before the failover\r\n    // processing begins).\r\n    //\r\n    LIST_ENTRY ZombieGroupList;\r\n\r\n} DSM_FAILOVER_GROUP, *PDSM_FAILOVER_GROUP;\r\n\r\n\r\n//\r\n// Information about a target port group entry for a given LUN.\r\n// Note: This is not a global list of all TPGs that are built. It is local to a Group entry.\r\n//\r\ntypedef struct _DSM_TARGET_PORT_GROUP_ENTRY {\r\n\r\n    //\r\n    // Signature. Used for debug.\r\n    //\r\n    ULONG TargetPortGroupSig;\r\n\r\n    //\r\n    // The asymmetric access state for this target port group:\r\n    // ACTIVE_O, ACTIVE_U, STANDBY or UNAVAILABLE\r\n    //\r\n    DSM_DEVICE_STATE AsymmetricAccessState;\r\n\r\n    //\r\n    // Flag to indicate if this is the preferred target port group.\r\n    //\r\n    BOOLEAN Preferred;\r\n\r\n    //\r\n    // Supported access states\r\n    //\r\n    BOOLEAN ActiveOptimizedSupported;\r\n    BOOLEAN ActiveUnoptimizedSupported;\r\n    BOOLEAN StandBySupported;\r\n    BOOLEAN UnavailableSupported;\r\n\r\n    //\r\n    // Indicates if the device reports asymmetric state as being under transition.\r\n    //\r\n    BOOLEAN TransitioningSupported;\r\n\r\n    //\r\n    // Flag to indicate if this has been returned in any subsequent RTPG after\r\n    // it is initially built. (If this flag is not set after parsing the RTPG\r\n    // information, it indicates that this TPG entry is stale and should be\r\n    // deleted).\r\n    //\r\n    BOOLEAN Traversed;\r\n\r\n    UCHAR Reserved;\r\n\r\n    //\r\n    // The target group identifier\r\n    //\r\n    USHORT Identifier;\r\n\r\n    //\r\n    // Status code\r\n    //\r\n    UCHAR StatusCode;\r\n\r\n    //\r\n    // Vendor unique\r\n    //\r\n    UCHAR VendorUnique;\r\n\r\n    //\r\n    // Backpointer to owning group\r\n    //\r\n    PDSM_GROUP_ENTRY Group;\r\n\r\n    //\r\n    // Number of target ports that make up this group\r\n    //\r\n    ULONG NumberTargetPorts;\r\n\r\n    //\r\n    // Linked list of target ports that make up this target port group.\r\n    //\r\n    LIST_ENTRY TargetPortList;\r\n\r\n} DSM_TARGET_PORT_GROUP_ENTRY, *PDSM_TARGET_PORT_GROUP_ENTRY;\r\n\r\n\r\n//\r\n// Information about each target port list entry for a given target port group.\r\n// Note: this is not a global list of all TPs. It is local to a given TPG entry.\r\n//\r\ntypedef struct _DSM_TARGET_PORT_LIST_ENTRY {\r\n\r\n    //\r\n    // Link\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Signature. Used for debug.\r\n    //\r\n    ULONG TargetPortSig;\r\n\r\n    //\r\n    // Relative target port identifier\r\n    //\r\n    ULONG Identifier;\r\n\r\n    //\r\n    // Backpointer to owning target port group\r\n    //\r\n    PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup;\r\n\r\n    //\r\n    // Number of device instances exposed via this target port\r\n    //\r\n    ULONG Count;\r\n\r\n    //\r\n    // List of device instances exposed via this target port\r\n    //\r\n    LIST_ENTRY TP_DeviceList;\r\n\r\n} DSM_TARGET_PORT_LIST_ENTRY, *PDSM_TARGET_PORT_LIST_ENTRY;\r\n\r\n//\r\n// Information about each controller entry\r\n//\r\ntypedef struct _DSM_CONTROLLER_LIST_ENTRY {\r\n\r\n    //\r\n    // To link to the next contoller entry.\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // It's signature. Used for debug.\r\n    //\r\n    ULONG ControllerSig;\r\n\r\n    //\r\n    // Device object (this controller's PDO).\r\n    //\r\n    PDEVICE_OBJECT DeviceObject;\r\n\r\n    //\r\n    // Port FDO through which this controller object was exposed.\r\n    //\r\n    PDEVICE_OBJECT PortObject;\r\n\r\n    //\r\n    // Identifier.\r\n    //\r\n    _Field_size_(IdLength) PUCHAR Identifier;\r\n\r\n    //\r\n    // Identifier length.\r\n    //\r\n    ULONG IdLength;\r\n\r\n    //\r\n    // Identifier code set.\r\n    //\r\n    STORAGE_IDENTIFIER_CODE_SET IdCodeSet;\r\n\r\n    //\r\n    // Controller's SCSI address.\r\n    //\r\n    PSCSI_ADDRESS ScsiAddress;\r\n\r\n    //\r\n    // Number of references to this entry.\r\n    //\r\n    UCHAR RefCount;\r\n\r\n    //\r\n    // Flag to indicate whether this is a fake entry built for storage that do\r\n    // NOT have controllers\r\n    //\r\n    BOOLEAN IsFakeController;\r\n\r\n    UCHAR Reserved[2];\r\n\r\n} DSM_CONTROLLER_LIST_ENTRY, *PDSM_CONTROLLER_LIST_ENTRY;\r\n\r\n//\r\n// Generic linked list of devices\r\n//\r\ntypedef struct _DSM_DEVICELIST_ENTRY {\r\n\r\n    //\r\n    // To link to the next device info structure in the list\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Representation of device-path pair\r\n    //\r\n    PDSM_DEVICE_INFO DeviceInfo;\r\n\r\n} DSM_DEVICELIST_ENTRY, *PDSM_DEVICELIST_ENTRY;\r\n\r\n//\r\n// Zombie Group List Entry\r\n//\r\ntypedef struct _DSM_ZOMBIEGROUP_ENTRY {\r\n\r\n    //\r\n    // To link to the next zombie group structure in the list\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Pointer to actual group entry\r\n    //\r\n    PDSM_GROUP_ENTRY Group;\r\n\r\n    //\r\n    // Flag to indicate that the failover thread has processed this entry.\r\n    //\r\n    BOOLEAN Processed;\r\n\r\n} DSM_ZOMBIEGROUP_ENTRY, *PDSM_ZOMBIEGROUP_ENTRY;\r\n\r\n//\r\n// Linked list of devices that will failover as a group\r\n//\r\ntypedef DSM_DEVICELIST_ENTRY DSM_FOG_DEVICELIST_ENTRY, *PDSM_FOG_DEVICELIST_ENTRY;\r\n\r\n//\r\n// Linked list of the same device being exposed off of a particular target port\r\n// (possibly because the controller is connected to multiple HBAs).\r\n//\r\ntypedef DSM_DEVICELIST_ENTRY DSM_TARGET_PORT_DEVICELIST_ENTRY, *PDSM_TARGET_PORT_DEVICELIST_ENTRY;\r\n\r\n//\r\n// Information about each failing devInfo and its corresponding devInfo\r\n// being used temporarily to service requests until STPG can update new\r\n// device states.\r\n//\r\ntypedef struct _DSM_FAIL_PATH_PROCESSING_LIST_ENTRY {\r\n\r\n    //\r\n    // To link to the next device info structure in the list\r\n    //\r\n    LIST_ENTRY ListEntry;\r\n\r\n    //\r\n    // Representation of the failing device-path pair\r\n    //\r\n    PDSM_DEVICE_INFO FailingDeviceInfo;\r\n\r\n    //\r\n    // Representation of the new candidate device-path pair that will take over\r\n    // processing of requests\r\n    //\r\n    PDSM_DEVICE_INFO TempDeviceInfo;\r\n\r\n} DSM_FAIL_PATH_PROCESSING_LIST_ENTRY, *PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY;\r\n\r\n//\r\n// Completion context structure.\r\n//\r\ntypedef struct _DSM_COMPLETION_CONTEXT {\r\n\r\n    //\r\n    // The device that handled the request.\r\n    //\r\n    PDSM_DEVICE_INFO DeviceInfo;\r\n\r\n    //\r\n    // The global context.\r\n    //\r\n    PDSM_CONTEXT DsmContext;\r\n\r\n    //\r\n    // These are used to store control code, pointer to KEVENT, etc.\r\n    //\r\n    PVOID RequestUnique1;\r\n\r\n    ULONG_PTR RequestUnique2;\r\n\r\n#if DBG\r\n    //\r\n    // Request time-stamp.\r\n    //\r\n    LARGE_INTEGER TickCount;\r\n#endif\r\n\r\n} DSM_COMPLETION_CONTEXT, *PDSM_COMPLETION_CONTEXT;\r\n\r\n//\r\n// Completion context structure for report/set target port groups.\r\n//\r\ntypedef struct _DSM_TPG_COMPLETION_CONTEXT {\r\n\r\n    PDSM_COMPLETION_CONTEXT CompletionContext;\r\n\r\n    PSCSI_REQUEST_BLOCK Srb;\r\n\r\n    PVOID SenseInfoBuffer;\r\n\r\n    ULONG NumberRetries;\r\n\r\n    UCHAR SenseInfoBufferLength;\r\n\r\n} DSM_TPG_COMPLETION_CONTEXT, *PDSM_TPG_COMPLETION_CONTEXT;\r\n\r\n//\r\n// Version number used to determine whice version of MPIO_DSM_Path to use.\r\n//\r\n#define DSM_WMI_VERSION_1   1\r\n#define DSM_WMI_VERSION_2   2\r\n\r\n//\r\n// Version of MPIO_DSM_Path that is currently supported by this DSM.\r\n//\r\n#define DSM_WMI_VERSION   DSM_WMI_VERSION_2\r\n\r\n//\r\n// This struct is used to save Load Balance Policy Settings in the registry\r\n//\r\ntypedef struct _DSM_LOAD_BALANCE_POLICY_SETTINGS {\r\n\r\n    WCHAR RegistryKeyName[256];\r\n    ULONG LoadBalancePolicy;\r\n    ULONG PathCount;\r\n    MPIO_DSM_Path_V2 DsmPath[1];\r\n\r\n} DSM_LOAD_BALANCE_POLICY_SETTINGS, *PDSM_LOAD_BALANCE_POLICY_SETTINGS;\r\n\r\n//\r\n// This structure is used to pass in information used by the workitem\r\n// to failover reservations down another path.\r\n//\r\ntypedef struct _DSM_RETRY_RESERVE {\r\n\r\n    PDSM_COMPLETION_CONTEXT CompletionContext;\r\n\r\n    PIRP Irp;\r\n\r\n    PKEVENT Event;\r\n\r\n} DSM_RETRY_RESERVE, *PDSM_RETRY_RESERVE;\r\n\r\n//\r\n// This structure defines the workitem that will be used to handle reservation\r\n// failover.\r\n//\r\ntypedef struct _DSM_WORKITEM {\r\n\r\n    //\r\n    // Work item that should be freed by the worker routine\r\n    //\r\n    PIO_WORKITEM WorkItem;\r\n\r\n    //\r\n    // Context to be passed to worker routine\r\n    //\r\n    PVOID Context;\r\n\r\n} DSM_WORKITEM, *PDSM_WORKITEM;\r\n\r\n#endif // _MSDSM_H\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/msdsm.mof",
    "content": "//\n// Copyright (C) 2004  Microsoft Corporation\n//\n//\n// Microsoft DSM's internal classes\n//\n\n//\n// Perf class.\n//\n[WMI,\n guid(\"{a34d03ec-6b0b-46a1-9178-82525f41133f}\")]\nclass MSDSM_DEVICEPATH_PERF\n{\n    [WmiDataId(1),\n     Description(\"Path Identifier.\") : amended\n    ] uint64 PathId;\n\n    [WmiDataId(2),\n     Description(\"Number of Read Requests.\") : amended\n    ] uint32 NumberReads;\n\n    [WmiDataId(3),\n     Description(\"Number of Write Requests.\") : amended\n    ] uint32 NumberWrites;\n\n    [WmiDataId(4),\n     Description(\"Total Bytes Read.\") : amended\n    ] uint64 BytesRead;\n\n    [WmiDataId(5),\n     Description(\"Total Bytes Written.\") : amended\n    ] uint64 BytesWritten;\n};\n\n[WMI,\n Dynamic,\n Provider(\"WmiProv\"),\n Description(\"Retrieve MSDSM Performance Information.\") : amended,\n Locale(\"MS\\\\0x409\"),\n guid(\"{875b8871-4889-4114-93f6-cd064c001cea}\")]\nclass MSDSM_DEVICE_PERF\n{\n    [key, read]\n     string InstanceName;\n    [read] boolean Active;\n\n    [WmiDataId(1),\n     read,\n     Description(\"Number of paths.\") : amended\n    ] uint32 NumberPaths;\n\n    [WmiDataId(2),\n     read,\n     Description(\"Array of Performance Information per path for the device.\") : amended,\n     WmiSizeIs(\"NumberPaths\")\n    ] MSDSM_DEVICEPATH_PERF PerfInfo[];\n};\n\n//\n// Methods\n//     Clear perf counters.\n//\n[Dynamic,\n Provider(\"WMIProv\"),\n WMI,\n Description(\"MSDSM WMI Methods\") : amended,\n guid(\"{04517f7e-92bb-4ebe-aed0-54339fa5f544}\"),\n locale(\"MS\\\\0x409\")\n]\nclass MSDSM_WMI_METHODS\n{\n\n    [key, read]\n    string InstanceName;\n    [read] boolean Active;\n\n    [WmiMethodId(1),\n     Implemented,\n     Description(\"Clear path performance counters for the device.\") : amended\n    ] void MSDsmClearCounters();\n};\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/msdsm.rc",
    "content": "//+-------------------------------------------------------------------------\r\n//\r\n//  Microsoft Windows\r\n//\r\n//  Copyright (C) Microsoft Corporation, 2004\r\n//\r\n//  File:       msdsm.rc\r\n//\r\n//--------------------------------------------------------------------------\r\n\r\n#include <windows.h>\r\n\r\n#include <ntverp.h>\r\n\r\n#define VER_FILETYPE    VFT_DRV\r\n#define VER_FILESUBTYPE VFT2_DRV_SYSTEM\r\n#define VER_FILEDESCRIPTION_STR     \"Microsoft Device Specific Module\"\r\n#define VER_INTERNALNAME_STR        \"msdsm.sys\"\r\n#define VER_ORIGINALFILENAME_STR    \"msdsm.sys\"\r\n\r\n#include \"common.ver\"\r\n\r\nMofResourceName MOFDATA msdsm.bmf\r\nDsmMofResourceName MOFDATA msdsmdsm.bmf\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/msdsmdsm.mof",
    "content": "//\n// Copyright (C) 2004  Microsoft Corporation\n//\n// Microsoft DSM's DSM-specific classes\n//\n\n//\n// Class used for retrieving and setting MSDSM-wide default load balance policy.\n//\n[WMI,\n Dynamic,\n Provider(\"WmiProv\"),\n Description(\"MSDSM-wide default load balance policies.\") : amended,\n Locale(\"MS\\\\0x409\"),\n guid(\"{c81b5681-f3ca-4c98-9325-707d0d62ffc4}\")]\nclass MSDSM_DEFAULT_LOAD_BALANCE_POLICY\n{\n    [key, read]\n     string InstanceName;\n    [read] boolean Active;\n\n    [WmiDataId(1),\n     read, write,\n     Description(\"Load Balance Policy to be applied to devices controlled by MSDSM.\") : amended\n    ] uint32 LoadBalancePolicy;\n\n    [WmiDataId(2),\n     read,\n     Description(\"Reserved.\") : amended\n    ] uint32 Reserved;\n\n    //\n    // Preferred path.\n    //\n    [WmiDataId(3),\n     read, write,\n     Description(\"Preferred Path.\") : amended\n    ] uint64 PreferredPath;\n};\n\n//\n// Embedded class that describes a target and the default load balance policy\n// of its LUNs.\n//\n[WMI,\n guid(\"{ddb00a72-0fab-418b-a89e-97370ae293a4}\")]\nclass MSDSM_TARGET_DEFAULT_POLICY_INFO\n{\n    //\n    // VID-PID string as an 8 + 16 character concatenated string.\n    // Spaces should be used to make the VID 8 chars and the PID 16 chars.\n    //\n    [WmiDataId(1),\n     MaxLen(31),\n     Description(\"Concatenated VendorID (8 characters) and ProductID (16 characters).\") : amended\n    ] string HardwareId;\n\n    //\n    // The default load balance policy to be applied to LUNs from the target\n    // whose hardware id matches the VID/PID above.\n    // NOTE: Setting this to 0 will act as removal of default setting for this\n    // target.\n    //\n    [WmiDataId(2)] uint32 LoadBalancePolicy;\n\n    //\n    // Used for alignment reasons.\n    //\n    [WmiDataId(3)] uint32 Reserved;\n\n    //\n    // Preferred path.\n    //\n    [WmiDataId(4)] uint64 PreferredPath;\n};\n\n//\n// Class used for retrieving and setting target-level default load balance policy.\n//\n[WMI,\n Dynamic,\n Provider(\"WmiProv\"),\n Description(\"Target-level default load balance policies.\") : amended,\n Locale(\"MS\\\\0x409\"),\n guid(\"{5ccbcd91-1b56-4327-a2f3-0960335f8846}\")]\nclass MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY\n{\n    [key, read]\n     string InstanceName;\n    [read] boolean Active;\n\n    [WmiDataId(1),\n     read, write,\n     Description(\"Number of targets specified.\") : amended\n    ] uint32 NumberDevices;\n\n    [WmiDataId(2),\n     read,\n     Description(\"Reserved.\") : amended\n    ] uint32 Reserved;\n\n    [WmiDataId(3),\n     read, write,\n     MaxLen(31),\n     Description(\"Array of target hardware identifiers with policy and preferred path information.\") : amended,\n     WmiSizeIs(\"NumberDevices\")\n    ] MSDSM_TARGET_DEFAULT_POLICY_INFO TargetDefaultPolicyInfo[];\n};\n\n//\n// Supported devices list class.\n//\n[WMI,\n Dynamic,\n Provider(\"WmiProv\"),\n Description(\"Retrieve MSDSM's supported devices list.\") : amended,\n Locale(\"MS\\\\0x409\"),\n guid(\"{c362d67c-371e-44d8-8bba-044619e4f245}\")]\nclass MSDSM_SUPPORTED_DEVICES_LIST\n{\n    [key, read]\n     string InstanceName;\n    [read] boolean Active;\n\n    [WmiDataId(1),\n     read,\n     Description(\"Number of supported devices.\") : amended\n    ] uint32 NumberDevices;\n\n    [WmiDataId(2),\n     read,\n     Description(\"Reserved.\") : amended\n    ] uint32 Reserved;\n\n    [WmiDataId(3),\n     read,\n     MaxLen(31),\n     Description(\"Array of device hardware identifiers.\") : amended,\n     WmiSizeIs(\"NumberDevices\")\n    ] string DeviceId[];\n};\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/precomp.h",
    "content": "\r\n/*++\r\n\r\nCopyright (c) 2004  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    precomp.h\r\n\r\nAbstract:\r\n\r\n    Precompiled header file for Microsoft Device Specific Module (DSM).\r\n\r\nRevision History:\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n#define DEBUG_MAIN_SOURCE 1\r\n\r\n#include <stdio.h>\r\n#include <stdarg.h>\r\n\r\n#include \"dsm.h\"\r\n#include \"mpiodisk.h\"\r\n#include \"msdsm.h\"\r\n#include \"prototypes.h\"\r\n#include \"trace.h\"\r\n#include \"srbhelper.h\"\r\n\r\n#include <ntstrsafe.h>\r\n#include <ntintsafe.h>\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/precompsrc.c",
    "content": "#include \"precomp.h\""
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/prototypes.h",
    "content": "\r\n/*++\r\n\r\nCopyright (C) 2004  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    prototypes.h\r\n\r\nAbstract:\r\n\r\n    Contains function prototypes for all the functions defined\r\n    by Microsoft Device Specific Module (DSM).\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n#pragma warning (disable:4214) // bit field usage\r\n#pragma warning (disable:4200) // zero-sized array\r\n\r\n#ifndef _PROTOTYPES_H_\r\n#define _PROTOTYPES_H_\r\n\r\n#define DSM_VENDOR_ID_LEN       8\r\n#define DSM_PRODUCT_ID_LEN      16\r\n#define DSM_VENDPROD_ID_LEN     24\r\n\r\n//\r\n// In accordance with SPC-3 specs\r\n//\r\n#define SPC3_TARGET_PORT_GROUPS_HEADER_SIZE         4\r\n\r\ntypedef struct _SPC3_CDB_REPORT_TARGET_PORT_GROUPS {\r\n    UCHAR OperationCode;\r\n    UCHAR ServiceAction : 5;\r\n    UCHAR Reserved1 : 3;\r\n    UCHAR Reserved2[4];\r\n    UCHAR AllocationLength[4];\r\n    UCHAR Reserved3;\r\n    UCHAR Control;\r\n} SPC3_CDB_REPORT_TARGET_PORT_GROUPS, *PSPC3_CDB_REPORT_TARGET_PORT_GROUPS;\r\n\r\ntypedef struct _SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR {\r\n    UCHAR AsymmetricAccessState : 4;\r\n    UCHAR Reserved : 3;\r\n    UCHAR Preferred : 1;\r\n    UCHAR ActiveOptimizedSupported : 1;\r\n    UCHAR ActiveUnoptimizedSupported : 1;\r\n    UCHAR StandbySupported : 1;\r\n    UCHAR UnavailableSupported : 1;\r\n    UCHAR Reserved2 : 3;\r\n    UCHAR TransitioningSupported : 1;\r\n    USHORT TPG_Identifier;\r\n    UCHAR Reserved3;\r\n    UCHAR StatusCode;\r\n    UCHAR VendorUnique;\r\n    UCHAR NumberTargetPorts;\r\n    ULONG TargetPortIds[0];\r\n} SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR, *PSPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR;\r\n\r\ntypedef struct _SPC3_CDB_SET_TARGET_PORT_GROUPS {\r\n    UCHAR OperationCode;\r\n    UCHAR ServiceAction : 5;\r\n    UCHAR Reserved1 : 3;\r\n    UCHAR Reserved2[4];\r\n    UCHAR ParameterListLength[4];\r\n    UCHAR Reserved3;\r\n    UCHAR Control;\r\n} SPC3_CDB_SET_TARGET_PORT_GROUPS, *PSPC3_CDB_SET_TARGET_PORT_GROUPS;\r\n\r\ntypedef struct _SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR {\r\n    UCHAR AsymmetricAccessState : 4;\r\n    UCHAR Reserved1 : 4;\r\n    UCHAR Reserved2;\r\n    USHORT TPG_Identifier;\r\n} SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR, *PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR;\r\n\r\ntypedef struct _SPC3_CONTROL_EXTENSION_MODE_PAGE {\r\n    UCHAR PageCode : 6;\r\n    UCHAR SubpageFormat : 1;\r\n    UCHAR ParametersSavable : 1;\r\n    UCHAR SubpageCode;\r\n    UCHAR PageLength[2];\r\n    UCHAR ImplicitALUAEnable : 1;\r\n    UCHAR ScsiPrecendence : 1;\r\n    UCHAR TimestampChangeable : 1;\r\n    UCHAR Reserved1 : 5;\r\n    UCHAR InitialPriority : 4;\r\n    UCHAR Reserved2 : 4;\r\n    UCHAR Reserved3[26];\r\n} SPC3_CONTROL_EXTENSION_MODE_PAGE, *PSPC3_CONTROL_EXTENSION_MODE_PAGE;\r\n\r\n#define SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS       0xA3\r\n#define SPC3_SCSIOP_SET_TARGET_PORT_GROUPS          0xA4\r\n#define SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS      0xA\r\n#define SPC3_RESERVATION_ACTION_REPORT_CAPABILITIES 0x2\r\n\r\n#define SPC3_SCSI_ADSENSE_COMMANDS_CLEARED_BY_ANOTHER_INITIATOR 0x2F\r\n#define SPC3_SCSI_ADSENSE_LOGICAL_UNIT_COMMAND_FAILED       0x67\r\n\r\n#define SPC3_SCSI_SENSEQ_MODE_PARAMETERS_CHANGED            0x1\r\n#define SPC3_SCSI_SENSEQ_RESERVATIONS_PREEMPTED             0x3\r\n#define SPC3_SCSI_SENSEQ_RESERVATIONS_RELEASED              0x4\r\n#define SPC3_SCSI_SENSEQ_REGISTRATIONS_PREEMPTED            0x5\r\n#define SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_CHANGED    0x6\r\n#define SPC3_SCSI_SENSEQ_IMPLICIT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED 0x7\r\n#define SPC3_SCSI_SENSEQ_CAPACITY_DATA_HAS_CHANGED          0x9\r\n#define SPC3_SCSI_SENSEQ_ASYMMETRIC_ACCESS_STATE_TRANSITION 0xA\r\n#define SPC3_SCSI_SENSEQ_TARGET_PORT_IN_STANDBY_STATE       0xB\r\n#define SPC3_SCSI_SENSEQ_TARGET_PORT_IN_UNAVAILABLE_STATE   0xC\r\n\r\n#define SPC3_SCSI_SENSEQ_SET_TARGET_PORT_GROUPS_FAILED      0xA\r\n\r\n#define SPC3_SET_TARGET_PORT_GROUPS_TIMEOUT     10\r\n#define SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT  10\r\n\r\n\r\n//\r\n// Function prototypes for functions intrface.c\r\n//\r\n\r\nDRIVER_INITIALIZE DriverEntry;\r\nDRIVER_UNLOAD DsmDriverUnload;\r\n\r\nNTSTATUS\r\nDsmInquire (\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDEVICE_OBJECT TargetDevice,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList,\r\n    _Out_ OUT PVOID *DsmIdentifier\r\n    );\r\n\r\nBOOLEAN\r\nDsmCompareDevices(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId1,\r\n    _In_ IN PVOID DsmId2\r\n    );\r\n\r\nNTSTATUS\r\nDsmGetControllerInfo(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN ULONG Flags,\r\n    _Inout_ IN OUT PCONTROLLER_INFO *ControllerInfo\r\n    );\r\n\r\nNTSTATUS\r\nDsmSetDeviceInfo(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDEVICE_OBJECT TargetObject,\r\n    _In_ IN PVOID DsmId,\r\n    _Inout_ IN OUT PVOID *PathId\r\n    );\r\n\r\nBOOLEAN\r\nDsmIsPathActive(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID PathId,\r\n    _In_ IN PVOID DsmId\r\n    );\r\n\r\nNTSTATUS\r\nDsmPathVerify(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PVOID PathId\r\n    );\r\n\r\nNTSTATUS\r\nDsmInvalidatePath(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN ULONG ErrorMask,\r\n    _In_ IN PVOID PathId,\r\n    _Inout_ IN OUT PVOID *NewPathId\r\n    );\r\n\r\nNTSTATUS\r\nDsmMoveDevice(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PVOID MPIOPath,\r\n    _In_ IN PVOID SuggestedPath,\r\n    _In_ IN ULONG Flags\r\n    );\r\n\r\nNTSTATUS\r\nDsmRemovePending(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId\r\n    );\r\n\r\nNTSTATUS\r\nDsmRemoveDevice(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PVOID PathId\r\n    );\r\n\r\nNTSTATUS\r\nDsmRemovePath(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID PathId\r\n    );\r\n\r\nNTSTATUS\r\nDsmSrbDeviceControl(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    );\r\n\r\nPVOID\r\nDsmLBGetPath(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ IN PVOID CurrentPath,\r\n    _Out_ OUT NTSTATUS *Status\r\n    );\r\n\r\nULONG\r\nDsmInterpretError(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _Inout_ IN OUT NTSTATUS *Status,\r\n    _Out_ OUT PBOOLEAN Retry,\r\n    _Out_ OUT PLONG RetryInterval,\r\n    ...\r\n    );\r\n\r\nNTSTATUS\r\nDsmUnload(\r\n    _In_ IN PVOID DsmContext\r\n    );\r\n\r\nVOID\r\nDsmSetCompletion(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _Inout_ IN OUT PDSM_COMPLETION_INFO DsmCompletion\r\n    );\r\n\r\n_Success_(return == DSM_PATH_SET)\r\nULONG\r\nDsmCategorizeRequest(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PVOID CurrentPath,\r\n    _Outptr_result_maybenull_ OUT PVOID *PathId,\r\n    _Out_ OUT NTSTATUS *Status\r\n    );\r\n\r\nNTSTATUS\r\nDsmBroadcastRequest(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    );\r\n\r\nBOOLEAN\r\nDsmIsAddressTypeSupported(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN ULONG AddressType\r\n    );\r\n\r\nNTSTATUS\r\nDsmDeviceNotUsed(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PVOID DsmId\r\n    );\r\n\r\n\r\n//\r\n// Function prototypes for functions in dsmmain.c\r\n//\r\n\r\nVOID\r\nDsmpFreeDSMResources(\r\n    _In_ IN PDSM_CONTEXT DsmContext\r\n    );\r\n\r\nPDSM_GROUP_ENTRY\r\nDsmpFindDevice(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    );\r\n\r\nPDSM_GROUP_ENTRY\r\nDsmpBuildGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nNTSTATUS\r\nDsmpParseTargetPortGroupsInformation(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength\r\n    );\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpFindTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength\r\n    );\r\n\r\n_Success_(return!=0)\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpUpdateTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength,\r\n    _Out_ OUT PULONG DescriptorSize\r\n    );\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpBuildTargetPortGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_reads_bytes_(TPGs_BufferLength) IN PUCHAR TargetPortGroupsDescriptor,\r\n    _In_ IN ULONG TPGs_BufferLength,\r\n    _Out_ OUT PULONG DescriptorSize\r\n    );\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpFindTargetPortListEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN ULONG RelativeTargetPortId\r\n    );\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpBuildTargetPortListEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN ULONG RelativeTargetPortId\r\n    );\r\n\r\nPDSM_TARGET_PORT_GROUP_ENTRY\r\nDsmpFindTargetPortGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PUSHORT TargetPortGroupId\r\n    );\r\n\r\nPDSM_TARGET_PORT_LIST_ENTRY\r\nDsmpFindTargetPort(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN PULONG TargetPortGroupId\r\n    );\r\n\r\nNTSTATUS\r\nDsmpAddDeviceEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nPDSM_CONTROLLER_LIST_ENTRY\r\nDsmpFindControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSCSI_ADDRESS ScsiAddress,\r\n    _In_reads_(ControllerSerialNumberLength) IN PSTR ControllerSerialNumber,\r\n    _In_ IN SIZE_T ControllerSerialNumberLength,\r\n    _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN AcquireLock\r\n    );\r\n\r\n_Ret_maybenull_\r\n_Must_inspect_result_\r\n_When_(return != NULL, __drv_allocatesMem(Mem))\r\nPDSM_CONTROLLER_LIST_ENTRY\r\nDsmpBuildControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_opt_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_ IN PDEVICE_OBJECT PortObject,\r\n    _In_ IN PSCSI_ADDRESS ScsiAddress,\r\n    _In_ IN PSTR ControllerSerialNumber,\r\n    _In_ IN STORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN AcquireLock\r\n    );\r\n\r\nVOID\r\nDsmpFreeControllerEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ __drv_freesMem(Mem) IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry\r\n    );\r\n\r\nBOOLEAN\r\nDsmpIsDeviceBelongsToController(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PDSM_CONTROLLER_LIST_ENTRY ControllerEntry\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindDevInfoFromGroupAndFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_FAILOVER_GROUP FOGroup\r\n    );\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpFindFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PVOID PathId\r\n    );\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpBuildFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PVOID        *PathId\r\n    );\r\n\r\nNTSTATUS\r\nDsmpUpdateFOGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nVOID\r\nDsmpRemoveDeviceFailGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    );\r\n\r\nULONG\r\nDsmpRemoveDeviceEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nVOID\r\nDsmpRemoveDeviceFromTargetPortList(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpSetNewPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevice\r\n    );\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpSetNewPathUsingGroup(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY Group\r\n    );\r\n\r\nVOID\r\nDsmpRemoveZombieGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY ZombieGroup\r\n    );\r\n\r\nNTSTATUS\r\nDsmpUpdateTargetPortGroupDevicesStates(\r\n    _In_ IN PDSM_TARGET_PORT_GROUP_ENTRY TargetPortGroup,\r\n    _In_ IN DSM_DEVICE_STATE NewState\r\n    );\r\n\r\nVOID\r\nDsmpIncrementCounters(\r\n    _In_ PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ PSCSI_REQUEST_BLOCK Srb\r\n    );\r\n\r\nBOOLEAN\r\nDsmpDecrementCounters(\r\n    _In_ PDSM_FAILOVER_GROUP FailGroup,\r\n    _In_ PSCSI_REQUEST_BLOCK Srb\r\n    );\r\n\r\nPDSM_FAILOVER_GROUP\r\nDsmpGetPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPVOID\r\nDsmpGetPathIdFromPassThroughPath(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmList,\r\n    _In_ IN PIRP Irp,\r\n    _Inout_ IN OUT NTSTATUS *Status\r\n    );\r\n\r\nVOID\r\nDsmpRemoveGroupEntry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_GROUP_ENTRY GroupEntry,\r\n    _In_ IN BOOLEAN AcquireDSMLockExclusive\r\n    );\r\n\r\nBOOLEAN\r\nDsmpMpioPassThroughPathCommand(\r\n    _In_ IN PIRP Irp\r\n    );\r\n\r\nBOOLEAN\r\nDsmpReservationCommand(\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb\r\n    );\r\n\r\nVOID\r\nDsmpRequestComplete(\r\n    _In_ IN PVOID DsmId,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PVOID DsmContext\r\n    );\r\n\r\nNTSTATUS\r\nDsmpRegisterPersistentReservationKeys(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN BOOLEAN      Register\r\n    );\r\n\r\n\r\nBOOLEAN\r\nDsmpShouldRetryPassThroughRequest(\r\n    _In_ IN PVOID   SenseData,\r\n    _In_ IN UCHAR   SenseDataSize\r\n    );\r\n\r\nBOOLEAN\r\nDsmpShouldRetryPersistentReserveCommand(\r\n    _In_ IN PVOID   SenseData,\r\n    _In_ IN UCHAR   SenseDataSize\r\n    );\r\n\r\nBOOLEAN\r\nDsmpShouldRetryTPGRequest(\r\n    _In_ IN PVOID   SenseData,\r\n    _In_ IN UCHAR   SenseDataSize\r\n    );\r\n\r\nBOOLEAN\r\nDsmpIsDeviceRemoved(\r\n    _In_ IN PVOID   SenseData,\r\n    _In_ IN UCHAR   SenseDataSize\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpGetActivePathToBeUsed(\r\n    _In_ PDSM_GROUP_ENTRY Group,\r\n    _In_ BOOLEAN Symmetric,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpGetAnyActivePath(\r\n    _In_ PDSM_GROUP_ENTRY Group,\r\n    _In_ BOOLEAN Exception,\r\n    _In_opt_ PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathToActivate(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathToActivateALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PBOOLEAN SendTPG,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPDSM_DEVICE_INFO\r\nDsmpFindStandbyPathInAlternateTpgALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForDsmPolicyAdjustment(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForVidPidPolicyAdjustment(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PWSTR TargetHardwareId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetNewDefaultLBPolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_opt_ IN PDSM_DEVICE_INFO NewDeviceInfo,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathArrival(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO NewDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathArrivalALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO NewDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathRemoval(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo,\r\n    _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathRemovalALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO RemovedDeviceInfo,\r\n    _In_opt_ IN OPTIONAL PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathFailing(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN MarkDevInfoFailed,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLBForPathFailingALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN MarkDevInfoFailed,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetPathForIoRetryALUA(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDeviceInfo,\r\n    _In_ IN BOOLEAN TPGException,\r\n    _In_ IN BOOLEAN DeviceInfoException\r\n    );\r\n\r\nPDSM_FAIL_PATH_PROCESSING_LIST_ENTRY\r\nDsmpFindFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevInfo\r\n    );\r\n\r\nPDSM_FAIL_PATH_PROCESSING_LIST_ENTRY\r\nDsmpBuildFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_DEVICE_INFO FailingDevInfo,\r\n    _In_ IN PDSM_DEVICE_INFO AlternateDevInfo\r\n    );\r\n\r\nIO_COMPLETION_ROUTINE DsmpPhase1ProcessPathFailingALUA;\r\n\r\nNTSTATUS\r\nDsmpRemoveFailPathDevInfoEntry(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN PDSM_FAIL_PATH_PROCESSING_LIST_ENTRY FailPathDevInfoEntry\r\n    );\r\n\r\nIO_COMPLETION_ROUTINE DsmpPhase2ProcessPathFailingALUA;\r\n\r\nNTSTATUS\r\nDsmpPersistentReserveOut(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    );\r\n\r\n__inline\r\nBOOLEAN\r\nDsmpIsPersistentReservationKeyZeroKey(\r\n    _In_ ULONG KeyLength,\r\n    _In_reads_bytes_(KeyLength) PUCHAR Key\r\n    )\r\n{\r\n    BOOLEAN zeroKey = FALSE;\r\n\r\n    NT_ASSERT(KeyLength == 8);\r\n\r\n    if ((KeyLength) == 8 &&\r\n        (Key[0] == 0 && Key[1] == 0 && Key[2] == 0 && Key[3] == 0 &&\r\n         Key[4] == 0 && Key[5] == 0 && Key[6] == 0 && Key[7] == 0)) {\r\n\r\n        zeroKey = TRUE;\r\n    }\r\n\r\n    return zeroKey;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPersistentReserveIn(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN PSCSI_REQUEST_BLOCK Srb,\r\n    _In_ IN PKEVENT Event\r\n    );\r\n\r\nIO_COMPLETION_ROUTINE DsmpPersistentReserveCompletion;\r\n\r\n\r\n//\r\n// Function prototypes for functions in utils.c\r\n//\r\n\r\n_Success_(return != NULL)\r\n__drv_allocatesMem(Mem)\r\n_When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL))\r\n_When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL))\r\n_When_(((PoolType&0x2))!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n    \"Allocation failures cause a system crash\"))\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0,\r\n    _Post_maybenull_ _Must_inspect_result_)\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0,\r\n   _Post_notnull_)\r\n_When_((PoolType&NonPagedPoolMustSucceed)!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n                      \"Allocation failures cause a system crash\"))\r\n_Post_writable_byte_size_(NumberOfBytes)\r\nPVOID\r\nDsmpAllocatePool(\r\n    _In_ _Strict_type_match_ IN POOL_TYPE PoolType,\r\n    _In_ IN SIZE_T NumberOfBytes,\r\n    _In_ IN ULONG Tag\r\n    );\r\n\r\n_Success_(return != NULL)\r\n_Post_maybenull_\r\n_Must_inspect_result_\r\n__drv_allocatesMem(Mem)\r\n_Post_writable_byte_size_(*BytesAllocated)\r\n_When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL))\r\n_When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL))\r\n_When_((PoolType&NonPagedPoolMustSucceed)!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n                      \"Allocation failures cause a system crash\"))\r\nPVOID\r\nDsmpAllocateAlignedPool(\r\n    _In_ IN POOL_TYPE PoolType,\r\n    _In_ IN SIZE_T NumberOfBytes,\r\n    _In_ IN ULONG AlignmentMask,\r\n    _In_ IN ULONG Tag,\r\n    _Out_ OUT SIZE_T *BytesAllocated\r\n    );\r\n\r\n_IRQL_requires_max_(DISPATCH_LEVEL)\r\nVOID\r\nDsmpFreePool(\r\n    _In_opt_ __drv_freesMem(Mem) IN PVOID Block\r\n    );\r\n\r\nNTSTATUS\r\nDsmpGetStatsGatheringChoice(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _Out_ OUT PULONG StatsGatherChoice\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetStatsGatheringChoice(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN ULONG StatsGatherChoice\r\n    );\r\n\r\n\r\nNTSTATUS\r\nDsmpGetDeviceList(\r\n    _In_ IN PDSM_CONTEXT Context\r\n    );\r\n\r\n_Success_(return==0)\r\nNTSTATUS\r\nDsmpGetStandardInquiryData(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _Out_ OUT PINQUIRYDATA InquiryData\r\n    );\r\n\r\nBOOLEAN\r\nDsmpCheckScsiCompliance(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_ IN PINQUIRYDATA InquiryData,\r\n    _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList\r\n    );\r\n\r\nBOOLEAN\r\nDsmpDeviceSupported(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PCSTR VendorId,\r\n    _In_ IN PCSTR ProductId\r\n    );\r\n\r\nBOOLEAN\r\nDsmpFindSupportedDevice(\r\n    _In_ IN PUNICODE_STRING DeviceName,\r\n    _In_ IN PUNICODE_STRING SupportedDevices\r\n    );\r\n\r\n_Success_(return!=0)\r\nPVOID\r\nDsmpParseDeviceID (\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceID,\r\n    _In_ IN DSM_DEVID_TYPE DeviceIdType,\r\n    _In_opt_ IN PULONG IdNumber,\r\n    _Out_opt_ PSTORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN Legacy\r\n    );\r\n\r\nPUCHAR\r\nDsmpBinaryToAscii(\r\n    _In_reads_(Length) IN PUCHAR HexBuffer,\r\n    _In_ IN ULONG Length,\r\n    _Inout_ IN OUT PULONG UpdateLength,\r\n    _In_ IN BOOLEAN Legacy\r\n    );\r\n\r\nPSTR\r\nDsmpGetSerialNumber(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject\r\n    );\r\n\r\n\r\nNTSTATUS\r\nDsmpDisableImplicitStateTransition(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _Out_ OUT PBOOLEAN DisableImplicit\r\n    );\r\n\r\nPWSTR\r\nDsmpBuildHardwareId(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\nPWSTR\r\nDsmpBuildDeviceNameLegacyPage0x80(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    );\r\n\r\n\r\nPWSTR\r\nDsmpBuildDeviceName(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_reads_(SerialNumberLength) IN PSTR SerialNumber,\r\n    _In_ IN SIZE_T SerialNumberLength\r\n    );\r\n\r\nNTSTATUS\r\nDsmpApplyDeviceNameCorrection(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_reads_(DeviceNameLegacyLen) PWSTR DeviceNameLegacy,\r\n    _In_ IN SIZE_T DeviceNameLegacyLen,\r\n    _In_reads_(DeviceNameLen) PWSTR DeviceName,\r\n    _In_ IN SIZE_T DeviceNameLen\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryDeviceLBPolicyFromRegistry(\r\n    _In_ PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ PWSTR RegistryKeyName,\r\n    _Inout_ PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Inout_ PULONGLONG PreferredPath,\r\n    _Inout_ PUCHAR ExplicitlySet\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryTargetLBPolicyFromRegistry(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryDsmLBPolicyFromRegistry(\r\n    _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetDsmLBPolicyInRegistry(\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetVidPidLBPolicyInRegistry(\r\n    _In_ IN PWSTR TargetHardwareId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmpOpenLoadBalanceSettingsKey(\r\n    _In_ IN ACCESS_MASK AccessMask,\r\n    _Out_ OUT PHANDLE LoadBalanceSettingsKey\r\n    );\r\n\r\nNTSTATUS\r\nDsmpOpenTargetsLoadBalanceSettingKey(\r\n    _In_ IN ACCESS_MASK AccessMask,\r\n    _Out_ OUT PHANDLE TargetsLoadBalanceSettingKey\r\n    );\r\n\r\nNTSTATUS\r\nDsmpOpenDsmServicesParametersKey(\r\n    _In_ IN ACCESS_MASK AccessMask,\r\n    _Out_ OUT PHANDLE ParametersSettingsKey\r\n    );\r\n\r\nIO_COMPLETION_ROUTINE DsmpReportTargetPortGroupsSyncCompletion;\r\n\r\n_Success_(return==0)\r\nNTSTATUS\r\nDsmpReportTargetPortGroups(\r\n    _In_ PDEVICE_OBJECT DeviceObject,\r\n    _Outptr_result_buffer_maybenull_(*TargetPortGroupsInfoLength) PUCHAR *TargetPortGroupsInfo,\r\n    _Out_ PULONG TargetPortGroupsInfoLength\r\n    );\r\n\r\nNTSTATUS\r\nDsmpReportTargetPortGroupsAsync(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine,\r\n    _Inout_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength,\r\n    _Inout_ __drv_aliasesMem IN OUT PUCHAR TargetPortGroupsInfo\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryLBPolicyForDevice(\r\n    _In_ IN PWSTR RegistryKeyName,\r\n    _In_ IN  ULONGLONG PathId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONG PrimaryPath,\r\n    _Out_ OUT PULONG OptimizedPath,\r\n    _Out_ OUT PULONG PathWeight\r\n    );\r\n\r\nVOID\r\nDsmpGetDSMPathKeyName(\r\n    _In_ ULONGLONG DSMPathId,\r\n    _Out_writes_(DsmPathKeyNameSize) PWCHAR DsmPathKeyName,\r\n    _In_ ULONG  DsmPathKeyNameSize\r\n    );\r\n\r\nUCHAR\r\nDsmpGetAsciiForBinary(\r\n    _In_ UCHAR BinaryChar\r\n    );\r\n\r\nNTSTATUS\r\nDsmpGetDeviceIdList (\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _Out_ OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetTargetPortGroups(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetTargetPortGroupsAsync(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine,\r\n    _In_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength,\r\n    _In_ __drv_aliasesMem IN PUCHAR TargetPortGroupsInfo\r\n    );\r\n\r\nPDSM_LOAD_BALANCE_POLICY_SETTINGS\r\nDsmpCopyLoadBalancePolicies(\r\n    _In_ IN PDSM_GROUP_ENTRY GroupEntry,\r\n    _In_ IN ULONG DsmWmiVersion,\r\n    _In_ IN PVOID SupportedLBPolicies\r\n    );\r\n\r\nNTSTATUS\r\nDsmpPersistLBSettings(\r\n    _In_ IN PDSM_LOAD_BALANCE_POLICY_SETTINGS LoadBalanceSettings\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetDeviceALUAState(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN DSM_DEVICE_STATE DevState\r\n    );\r\n\r\nNTSTATUS\r\nDsmpGetDeviceALUAState(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_opt_ IN PDSM_DEVICE_STATE DevState\r\n    );\r\n\r\nNTSTATUS\r\nDsmpAdjustDeviceStatesALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_opt_ IN PDSM_DEVICE_INFO PreferredActiveDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    );\r\n\r\nPDSM_WORKITEM\r\nDsmpAllocateWorkItem(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_ IN PVOID Context\r\n    );\r\n\r\nVOID\r\nDsmpFreeWorkItem(\r\n    _In_ IN PDSM_WORKITEM DsmWorkItem\r\n    );\r\n\r\nVOID\r\nDsmpFreeZombieGroupList(\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup\r\n    );\r\n\r\nNTSTATUS\r\nDsmpRegCopyTree(\r\n    _In_ IN HANDLE SourceKey,\r\n    _In_ IN HANDLE DestKey\r\n    );\r\n\r\nNTSTATUS\r\nDsmpRegDeleteTree(\r\n    _In_ IN HANDLE KeyRoot\r\n    );\r\n\r\n#if defined (_WIN64)\r\nVOID\r\nDsmpPassThroughPathTranslate32To64(\r\n    _In_ IN PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32,\r\n    _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64\r\n    );\r\n\r\nVOID\r\nDsmpPassThroughPathTranslate64To32(\r\n    _In_ IN PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64,\r\n    _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32\r\n    );\r\n#endif\r\n\r\nNTSTATUS\r\nDsmpGetMaxPRRetryTime(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _Out_ OUT PULONG RetryTime\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryCacheInformationFromRegistry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _Out_ OUT PBOOLEAN UseCacheForLeastBlocks,\r\n    _Out_ OUT PULONGLONG CacheSizeForLeastBlocks\r\n    );\r\n\r\nBOOLEAN\r\nDsmpConvertSharedSpinLockToExclusive(\r\n    _Inout_ _Requires_lock_held_(*_Curr_) PEX_SPIN_LOCK SpinLock\r\n    );\r\n\r\n\r\n//\r\n// Function prototypes for functions in wmi.c\r\n//\r\n\r\nVOID\r\nDsmpDsmWmiInitialize(\r\n    _In_ IN PDSM_WMILIB_CONTEXT WmiGlobalInfo,\r\n    _In_ IN PUNICODE_STRING RegistryPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmGlobalQueryData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG InstanceCount,\r\n    _Inout_ IN OUT PULONG InstanceLengthArray,\r\n    _In_ IN ULONG BufferAvail,\r\n    _Out_writes_to_(BufferAvail, *DataLength) OUT PUCHAR Buffer,\r\n    _Out_ OUT PULONG DataLength,\r\n    ...\r\n    );\r\n\r\nNTSTATUS\r\nDsmGlobalSetData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG BufferAvail,\r\n    _In_reads_bytes_(BufferAvail) IN PUCHAR Buffer,\r\n    ...\r\n    );\r\n\r\nVOID\r\nDsmpWmiInitialize(\r\n    _In_ IN PDSM_WMILIB_CONTEXT WmiInfo,\r\n    _In_ IN PUNICODE_STRING RegistryPath\r\n    );\r\n\r\nNTSTATUS\r\nDsmQueryData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG InstanceCount,\r\n    _Inout_ IN OUT PULONG InstanceLengthArray,\r\n    _In_ IN ULONG BufferAvail,\r\n    _When_(GuidIndex == 0 || GuidIndex == 7, _Pre_notnull_ _Const_)\r\n    _When_(!(GuidIndex == 0 || GuidIndex == 7), _Out_writes_to_(BufferAvail, *DataLength))\r\n          OUT PUCHAR Buffer,\r\n    _Out_ OUT PULONG DataLength,\r\n    ...\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN ULONG        InBufferSize,\r\n    _In_ IN PULONG       OutBufferSize,\r\n    _Out_writes_bytes_(*OutBufferSize) OUT PVOID Buffer\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQuerySupportedLBPolicies(\r\n    _In_ IN   PDSM_CONTEXT DsmContext,\r\n    _In_ IN   PDSM_IDS DsmIds,\r\n    _In_ IN   ULONG BufferAvail,\r\n    _In_ IN   ULONG DsmWmiVersion,\r\n    _Out_ OUT PULONG OutBufferSize,\r\n    _Out_writes_to_(BufferAvail, *OutBufferSize) OUT PUCHAR Buffer\r\n   );\r\n\r\nNTSTATUS\r\nDsmExecuteMethod(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP  Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG MethodId,\r\n    _In_ IN ULONG InBufferSize,\r\n    _In_ IN PULONG OutBufferSize,\r\n    _Inout_ IN OUT PUCHAR Buffer,\r\n    ...\r\n    );\r\n\r\nNTSTATUS\r\nDsmpClearLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds\r\n    );\r\n\r\nNTSTATUS\r\nDsmpSetLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN ULONG        InBufferSize,\r\n    _In_ IN PULONG       OutBufferSize,\r\n    _In_ IN PVOID        Buffer\r\n    );\r\n\r\nNTSTATUS\r\nDsmpValidateSetLBPolicyInput(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN PVOID        SetLoadBalancePolicyIN,\r\n    _In_ IN ULONG        InBufferSize\r\n    );\r\n\r\nVOID\r\nDsmpSaveDeviceState(\r\n    _In_ IN PVOID SupportedLBPolicies,\r\n    _In_ IN ULONG DsmWmiVersion\r\n    );\r\n\r\nVOID\r\nDsmpRestorePreviousDeviceState(\r\n    _In_ IN PVOID SupportedLBPolicies,\r\n    _In_ IN ULONG DsmWmiVersion\r\n    );\r\n\r\nVOID\r\nDsmpUpdateDesiredStateAndWeight(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG DsmWmiVersion,\r\n    _In_ IN PVOID SupportedLBPolicies\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryDevicePerf(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ PDSM_IDS DsmIds,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    );\r\n\r\nNTSTATUS\r\nDsmpClearPerfCounters(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQuerySupportedDevicesList(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryTargetsDefaultPolicy(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    );\r\n\r\nNTSTATUS\r\nDsmpQueryDsmDefaultPolicy(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    );\r\n\r\n\r\n//\r\n// Function prototypes for functions in debug.c\r\n//\r\n\r\nVOID\r\nDsmpDebugPrint(\r\n    _In_ ULONG DebugPrintLevel,\r\n    _In_ PCCHAR DebugMessage,\r\n    ...\r\n    );\r\n\r\n//\r\n// SRB Helpers not found in srbhelper.h\r\n//\r\n_Success_(return != 0)\r\n__drv_allocatesMem(mem)\r\n_When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL))\r\n_When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL))\r\n_When_(((PoolType&0x2))!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n    \"Allocation failures cause a system crash\"))\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0,\r\n    _Post_maybenull_ _Must_inspect_result_)\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0,\r\n    _Post_notnull_ )\r\n__inline PSTORAGE_REQUEST_BLOCK_HEADER\r\nSrbAllocateCopy(\r\n    _Inout_ PVOID Srb,\r\n    _In_ _Strict_type_match_ POOL_TYPE PoolType,\r\n    _In_ ULONG Tag\r\n    )\r\n/*\r\n\r\nDescription:\r\n    This function returns an allocated copy of the given SRB. The memory is\r\n    allocated using DsmpAllocatePool().\r\n\r\n    ***It is up to the caller to free the memory returned by this function.***\r\n\r\nArguments:\r\n    Srb - A pointer to either a STORAGE_REQUEST_BLOCK or a SCSI_REQUEST_BLOCK.\r\n    PoolType - The pool type to use. See documentation for ExAllocatePoolWithTag().\r\n    Tag - The allocation tag to use. See documentation for ExAllocatePoolWithTag().\r\n\r\nReturns:\r\n    NULL, if the copy could not be allocated; or\r\n    A pointer to either a STORAGE_REQUEST_BLOCK or a SCSI_REQUEST_BLOCK that is\r\n    direct copy of the given SRB.\r\n\r\n*/\r\n{\r\n    PSTORAGE_REQUEST_BLOCK srb = (PSTORAGE_REQUEST_BLOCK)Srb;\r\n    PSTORAGE_REQUEST_BLOCK_HEADER srbCopy = NULL;\r\n    ULONG allocationSize = 0;\r\n\r\n    if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK)\r\n    {\r\n        allocationSize = srb->SrbLength;\r\n        NT_ASSERT(allocationSize >= (sizeof(STORAGE_REQUEST_BLOCK) + sizeof(STOR_ADDR_BTL8)));\r\n    }\r\n    else\r\n    {\r\n        allocationSize = SCSI_REQUEST_BLOCK_SIZE;\r\n        NT_ASSERT(allocationSize >= sizeof(SCSI_REQUEST_BLOCK));\r\n    }\r\n\r\n    #pragma warning(suppress: 28160 28118) // False-positive; PoolType is simply passed through\r\n    srbCopy = (PSTORAGE_REQUEST_BLOCK_HEADER)DsmpAllocatePool(PoolType, allocationSize, Tag);\r\n    if (srbCopy != NULL)\r\n    {\r\n        RtlCopyMemory(srbCopy, Srb, allocationSize);\r\n    }\r\n\r\n    return srbCopy;\r\n}\r\n\r\n__inline\r\nBOOLEAN DsmpIsMPIOPassThroughEx(\r\n    ULONG ControlCode\r\n    )\r\n//\r\n// Returns TRUE if the given passthrough IOCTL's control code indicates it is\r\n// an \"extended\" passthrough.  Returns FALSE otherwise.\r\n//\r\n{\r\n    if (ControlCode == IOCTL_MPIO_PASS_THROUGH_PATH_EX ||\r\n        ControlCode == IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT_EX) {\r\n        return TRUE;\r\n    } else {\r\n        return FALSE;\r\n    }\r\n}\r\n\r\n__inline\r\nUCHAR DsmpNtStatusToSrbStatus(\r\n    _In_ NTSTATUS Status\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Translate an NT status value into a SCSI Srb status code.\r\n\r\nArguments:\r\n\r\n    Status - Supplies the NT status code to translate.\r\n\r\nReturn Value:\r\n\r\n    SRB status code.\r\n\r\n--*/\r\n{\r\n    switch (Status) {\r\n\r\n        case STATUS_DEVICE_BUSY:\r\n            return SRB_STATUS_BUSY;\r\n\r\n        case STATUS_INVALID_DEVICE_REQUEST:\r\n            return SRB_STATUS_BAD_FUNCTION;\r\n\r\n        case STATUS_INSUFFICIENT_RESOURCES:\r\n            return SRB_STATUS_INTERNAL_ERROR;\r\n\r\n        case STATUS_INVALID_PARAMETER:\r\n            return SRB_STATUS_INVALID_REQUEST;\r\n\r\n        default:\r\n            if (NT_SUCCESS (Status)) {\r\n                return SRB_STATUS_SUCCESS;\r\n            } else {\r\n                return SRB_STATUS_ERROR;\r\n            }\r\n    }\r\n}\r\n\r\n\r\n#endif // _PROTOTYPES_H_\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/trace.h",
    "content": "\r\n/*++\r\n\r\nCopyright (C) 2004  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    trace.h\r\n\r\nAbstract:\r\n\r\n    Header file included by the Microsoft Device Specific Module (DSM).\r\n\r\n    This file contains Windows tracing related defines.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n//\r\n// Set component ID for DbgPrintEx calls\r\n//\r\n#define DEBUG_COMP_ID   DPFLTR_MSDSM_ID\r\n\r\n//\r\n// Include header file and setup GUID for tracing\r\n//\r\n#include <storswtr.h>\r\n#define WPP_GUID_MSDSM      (DEDADFF5, F99F, 4600, B8C9, 2D4D9B806B5B)\r\n#define WPP_CONTROL_GUIDS   WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_MSDSM)\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/utils.c",
    "content": "\r\n/*++\r\n\r\nCopyright (C) 2004-2010  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    utils.c\r\n\r\nAbstract:\r\n\r\n    This driver is the Microsoft Device Specific Module (DSM).\r\n    It exports behaviours that mpio.sys will use to determine how to\r\n    multipath SPC-3 compliant devices.\r\n\r\n    This file contains utility routines.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n#include \"precomp.h\"\r\n\r\n#ifdef DEBUG_USE_WPP\r\n#include \"utils.tmh\"\r\n#endif\r\n\r\n#pragma warning (disable:4305)\r\n\r\nextern BOOLEAN DoAssert;\r\n\r\n#ifdef ALLOC_PRAGMA\r\n    #pragma alloc_text(PAGE, DsmpBuildDeviceNameLegacyPage0x80)\r\n    #pragma alloc_text(PAGE, DsmpBuildDeviceName)\r\n    #pragma alloc_text(PAGE, DsmpApplyDeviceNameCorrection)\r\n    #pragma alloc_text(PAGE, DsmpOpenLoadBalanceSettingsKey)\r\n    #pragma alloc_text(PAGE, DsmpQueryLBPolicyForDevice)\r\n    #pragma alloc_text(PAGE, DsmpOpenTargetsLoadBalanceSettingKey)\r\n    #pragma alloc_text(PAGE, DsmpOpenDsmServicesParametersKey)\r\n#endif\r\n\r\n_Success_(return != NULL)\r\n__drv_allocatesMem(Mem)\r\n_When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL))\r\n_When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL))\r\n_When_(((PoolType&0x2))!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n    \"Allocation failures cause a system crash\"))\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))==0,\r\n    _Post_maybenull_ _Must_inspect_result_)\r\n_When_(((PoolType&(0x2|POOL_RAISE_IF_ALLOCATION_FAILURE)))!=0,\r\n    _Post_notnull_ )\r\n_When_((PoolType&NonPagedPoolMustSucceed)!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n                      \"Allocation failures cause a system crash\"))\r\n_Post_writable_byte_size_(NumberOfBytes)\r\nPVOID\r\nDsmpAllocatePool(\r\n    _In_ _Strict_type_match_ IN POOL_TYPE PoolType,\r\n    _In_ IN SIZE_T NumberOfBytes,\r\n    _In_ IN ULONG Tag\r\n    )\r\n/*+++\r\n\r\nRoutine Description :\r\n\r\n    Allocates memory from the specified pool using the given tag.\r\n    If the allocation is successful, the entire buffer will be zeroed.\r\n\r\nArguements:\r\n\r\n    PoolType - Pool to allocate from (NonPaged, Paged, etc)\r\n    NumberOfBytes - Size of the buffer to allocate\r\n    Tag - Tag (DSM_TAG_XXX) to be used for this allocation.\r\n          These tags are defined in msdsm.h\r\n\r\nReturn Value:\r\n\r\n    Pointer to the buffer if allocation is successful\r\n    NULL otherwise\r\n\r\n--*/\r\n{\r\n    PVOID Block = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAllocatePool (Tag %u): Entering function.\\n\",\r\n                Tag));\r\n\r\n    #pragma warning(suppress: 28118) // False-positive; PoolType is simply passed through\r\n    Block = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);\r\n    if (Block) {\r\n        RtlZeroMemory(Block, NumberOfBytes);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAllocatePool (Tag %u): Exiting function with allocated block %p.\\n\",\r\n                Tag,\r\n                Block));\r\n\r\n    return Block;\r\n}\r\n\r\n\r\n_Success_(return != NULL)\r\n_Post_maybenull_\r\n_Must_inspect_result_\r\n__drv_allocatesMem(Mem)\r\n_Post_writable_byte_size_(*BytesAllocated)\r\n_When_(((PoolType&0x1))!=0, _IRQL_requires_max_(APC_LEVEL))\r\n_When_(((PoolType&0x1))==0, _IRQL_requires_max_(DISPATCH_LEVEL))\r\n_When_((PoolType&NonPagedPoolMustSucceed)!=0,\r\n    __drv_reportError(\"Must succeed pool allocations are forbidden. \"\r\n                      \"Allocation failures cause a system crash\"))\r\nPVOID\r\n#pragma warning(suppress:28195) // Allocation is not guaranteed, caller needs to check return value\r\nDsmpAllocateAlignedPool(\r\n    _In_ IN POOL_TYPE PoolType,\r\n    _In_ IN SIZE_T NumberOfBytes,\r\n    _In_ IN ULONG AlignmentMask,\r\n    _In_ IN ULONG Tag,\r\n    _Out_ OUT SIZE_T *BytesAllocated\r\n    )\r\n/*+++\r\n\r\nRoutine Description :\r\n\r\n    Allocates memory from the specified pool using the given tag and alignment requirement.\r\n    If the allocation is successful, the entire buffer will be zeroed.\r\n\r\nArguements:\r\n\r\n    PoolType - Pool to allocate from (NonPaged, Paged, etc)\r\n    NumberOfBytes - Size of the buffer to allocate\r\n    AlignmentMask - Alignment requirement specified by the device\r\n    Tag - Tag (DSM_TAG_XXX) to be used for this allocation.\r\n          These tags are defined in msdsm.h\r\n    BytesAllocated - Returns the number of bytes allocated, if the routine was successful\r\n\r\nReturn Value:\r\n\r\n    Pointer to the buffer if allocation is successful\r\n    NULL otherwise\r\n\r\n--*/\r\n{\r\n    PVOID Block = NULL;\r\n    UINT_PTR align64 = (UINT_PTR)AlignmentMask;\r\n    ULONG totalSize = (ULONG)NumberOfBytes;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAllocateAlignedPool (Tag %u): Entering function.\\n\",\r\n                Tag));\r\n\r\n    if (BytesAllocated == NULL) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit;\r\n    }\r\n\r\n    *BytesAllocated = 0;\r\n\r\n    if (AlignmentMask) {\r\n\r\n        status = RtlULongAdd((ULONG)NumberOfBytes, AlignmentMask, &totalSize);\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n\t#pragma warning(suppress: 6014 28118) // Block isn't leaked, this function is marked as an allocator; PoolType is simply passed through\r\n        Block = ExAllocatePoolWithTag(PoolType, totalSize, Tag);\r\n\r\n        if (Block != NULL) {\r\n\r\n            if (AlignmentMask) {\r\n\r\n                Block = (PVOID)(((UINT_PTR)Block + align64) & ~align64);\r\n            }\r\n        } else {\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n__Exit:\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        RtlZeroMemory(Block, totalSize);\r\n        *BytesAllocated = totalSize;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAllocateAlignedPool (Tag %u): Exiting function with allocated block %p.\\n\",\r\n                Tag,\r\n                Block));\r\n\r\n    return Block;\r\n}\r\n\r\n\r\n_IRQL_requires_max_(DISPATCH_LEVEL)\r\nVOID\r\nDsmpFreePool(\r\n    _In_opt_ __drv_freesMem(Mem) IN PVOID Block\r\n    )\r\n/*+++\r\n\r\nRoutine Description :\r\n\r\n    Frees the block passed in.\r\n\r\nArguements:\r\n\r\n    Block - pointer to the memory to free.\r\n\r\nReturn Value:\r\n\r\n    Nothing\r\n\r\n--*/\r\n{\r\n    PVOID tempAddress = Block;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFreePool (Block %p): Entering function.\\n\",\r\n                Block));\r\n\r\n    if (Block) {\r\n\r\n        ExFreePool(Block);\r\n        Block = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFreePool (Block %p): Exiting function.\\n\",\r\n                tempAddress));\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpGetStatsGatheringChoice(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _Out_ OUT PULONG StatsGatherChoice\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to determine if the Admin wants statitics to be collected\r\n    on every IO. It queries the the services key for the value under\r\n    \"msdsm\\Parameters\\DsmDisableStatistics\"\r\n\r\nArguments:\r\n\r\n    Context - The DSM Context value.\r\n    StatsGatherChoice - Returns the choice of whether or not to gather statistics\r\n\r\nReturn Value:\r\n\r\n    Status of the RtlQueryRegistryValues call.\r\n\r\n--*/\r\n{\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n    WCHAR registryKeyName[56] = {0};\r\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetStatsGatherChoice (DsmCtxt %p): Entering function.\\n\",\r\n                Context));\r\n\r\n    if (!StatsGatherChoice) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DsmpGetStatsGatherChoice (DsmCtxt %p): Invalid parameter - StatsGatherChoice is NULL.\\n\",\r\n                    Context));\r\n\r\n        goto __Exit_DsmpGetStatsGatherChoice;\r\n    }\r\n\r\n    RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n    //\r\n    // Build the key value name that we want as the base of the query.\r\n    //\r\n    RtlStringCbPrintfW(registryKeyName,\r\n                       sizeof(registryKeyName),\r\n                       DSM_PARAMETER_PATH_W);\r\n\r\n    //\r\n    // The query table has two entries. One for the supporteddeviceList and\r\n    // the second which is the 'NULL' terminator.\r\n    //\r\n    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;\r\n    queryTable[0].Name = DSM_DISABLE_STATISTICS;\r\n    queryTable[0].EntryContext = StatsGatherChoice;\r\n    queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n    status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,\r\n                                    registryKeyName,\r\n                                    queryTable,\r\n                                    registryKeyName,\r\n                                    NULL);\r\n\r\n__Exit_DsmpGetStatsGatherChoice:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetStatsGatherChoice (DsmCtxt %p): Exiting function with status %x.\\n\",\r\n                Context,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetStatsGatheringChoice(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN ULONG StatsGatherChoice\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to set the value that indicates whether statistics will\r\n    be gathered on every IO. It updates the services key for the value under\r\n    \"msdsm\\Parameters\\DsmDisableStatistics\"\r\n\r\nArguments:\r\n\r\n    Context - The DSM Context value.\r\n    StatsGatherChoice - Value indicating whether to gather statistics (TRUE) or not (FALSE)\r\n\r\nReturn Value:\r\n\r\n    Status of the RtlWriteRegistryValue call.\r\n\r\n--*/\r\n{\r\n    WCHAR registryKeyName[56] = {0};\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetStatsGatherChoice (DsmCtxt %p): Entering function.\\n\",\r\n                Context));\r\n\r\n    //\r\n    // Build the key value name that we want as the base of the query.\r\n    //\r\n    RtlStringCbPrintfW(registryKeyName,\r\n                       sizeof(registryKeyName),\r\n                       DSM_PARAMETER_PATH_W);\r\n\r\n\r\n    status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,\r\n                                   registryKeyName,\r\n                                   DSM_DISABLE_STATISTICS,\r\n                                   REG_DWORD,\r\n                                   &StatsGatherChoice,\r\n                                   sizeof(ULONG));\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetStatsGatherChoice (DsmCtxt %p): Exiting function with status %x.\\n\",\r\n                Context,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\n\r\nNTSTATUS\r\nDsmpGetDeviceList(\r\n    _In_ IN PDSM_CONTEXT Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to build the supported device list by querying the services\r\n    key for the values under \"msdsm\\Parameters\\DsmSupportedDeviceList\"\r\n\r\nArguments:\r\n\r\n    Context - The DSM Context value. It contains storage for the multi_sz string that may\r\n              be built.\r\n\r\nReturn Value:\r\n\r\n    Status of the RtlQueryRegistryValues call.\r\n\r\n--*/\r\n{\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n    WCHAR registryKeyName[56] = {0};\r\n    UNICODE_STRING inquiryStrings;\r\n    WCHAR defaultIDs[] = { L\"\\0\" };\r\n    NTSTATUS status;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDeviceList (DsmCtxt %p): Entering function.\\n\",\r\n                Context));\r\n\r\n    RtlZeroMemory(queryTable, sizeof(queryTable));\r\n    RtlInitUnicodeString(&inquiryStrings, NULL);\r\n\r\n    //\r\n    // Build the key value name that we want as the base of the query.\r\n    //\r\n    RtlStringCbPrintfW(registryKeyName,\r\n                       sizeof(registryKeyName),\r\n                       DSM_PARAMETER_PATH_W);\r\n\r\n    //\r\n    // The query table has two entries. One for the supporteddeviceList and\r\n    // the second which is the 'NULL' terminator.\r\n    //\r\n    // Indicate that there is NO call-back routine, and to give back the MULTI_SZ as\r\n    // one blob, as opposed to individual unicode strings.\r\n    //\r\n    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_TYPECHECK;\r\n\r\n    //\r\n    // The value to query.\r\n    //\r\n    queryTable[0].Name = DSM_SUPPORTED_DEVICELIST_VALUE_NAME;\r\n\r\n    //\r\n    // Where to put the strings. Note that we need to use an empty unicode_string\r\n    // for the query or else RtlQueryRegistryValues will only fill in enough\r\n    // entries as specified by the size of the unicode string's buffer, which\r\n    // is why we can't use Context->SupportedDevices directly in the call.\r\n    //\r\n    queryTable[0].EntryContext = &inquiryStrings;\r\n    queryTable[0].DefaultType  = (REG_MULTI_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_MULTI_SZ;\r\n    queryTable[0].DefaultData = defaultIDs;\r\n    queryTable[0].DefaultLength = sizeof(defaultIDs);\r\n\r\n    status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,\r\n                                    registryKeyName,\r\n                                    queryTable,\r\n                                    registryKeyName,\r\n                                    NULL);\r\n\r\n    //\r\n    // If we successfully queried for the supported device list, we need to delete\r\n    // our cached list and update it with this new one.\r\n    //\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        KIRQL oldIrql;\r\n        PWCHAR tempBuffer = NULL;\r\n\r\n        tempBuffer = DsmpAllocatePool(NonPagedPoolNx, inquiryStrings.MaximumLength, DSM_TAG_REG_VALUE_RELATED);\r\n\r\n        //\r\n        // This is a \"best effort\" operation. If we are unable to allocate a\r\n        // buffer for the strings, we just continue using our old cached list.\r\n        // We do NOT fall back to using inquiryStrings's buffer as we want to\r\n        // be able to work with the supported devices list at raised IRQL.\r\n        //\r\n        if (tempBuffer) {\r\n\r\n            RtlCopyMemory(tempBuffer, inquiryStrings.Buffer, inquiryStrings.Length);\r\n\r\n            KeAcquireSpinLock(&Context->SupportedDevicesListLock, &oldIrql);\r\n            DsmpFreePool(Context->SupportedDevices.Buffer);\r\n            Context->SupportedDevices.Buffer = tempBuffer;\r\n            Context->SupportedDevices.Length = inquiryStrings.Length;\r\n            Context->SupportedDevices.MaximumLength = inquiryStrings.MaximumLength;\r\n            KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql);\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpGetDeviceList (DsmCtxt %p): Failed to allocate supported device list's buffer.\\n\",\r\n                        Context));\r\n\r\n            status =  STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n\r\n        ExFreePool(inquiryStrings.Buffer);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDeviceList (DsmCtxt %p): Exiting function with status %x.\\n\",\r\n                Context,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\n_Success_(return==0)\r\nNTSTATUS\r\nDsmpGetStandardInquiryData(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _Out_ OUT PINQUIRYDATA InquiryData\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send an inquiry with EVPD cleared to get the standard inquiry data.\r\n\r\nArguments:\r\n\r\n    DeviceObject - The port PDO to which the command should be sent.\r\n    InquiryData - Pointer to inquiry data that will be returned to caller.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or failure NTSTATUS code.\r\n\r\n--*/\r\n{\r\n    PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL;\r\n    PCDB cdb;\r\n    IO_STATUS_BLOCK ioStatus;\r\n    ULONG length;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PINQUIRYDATA inquiryData;\r\n    PSENSE_DATA senseData;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetStandardInquiryData (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    if (InquiryData == NULL) {\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpGetStandardInquiryData;\r\n    }\r\n\r\n    //\r\n    // Build a standard inquiry command.\r\n    //\r\n    length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n    passThrough = DsmpAllocatePool(NonPagedPoolNx,\r\n                                   length,\r\n                                   DSM_TAG_PASS_THRU);\r\n    if (!passThrough) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetStandardInquiryData (DevObj %p): Failed to allocate mem for passthrough.\\n\",\r\n                    DeviceObject));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpGetStandardInquiryData;\r\n    }\r\n\r\n__Retry_Request:\r\n\r\n    //\r\n    // Build the cdb for SCSI-3 standard inquiry.\r\n    //\r\n    cdb = (PCDB)passThrough->ScsiPassThrough.Cdb;\r\n    cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;\r\n    cdb->CDB6INQUIRY3.EnableVitalProductData = 0;\r\n    cdb->CDB6INQUIRY3.AllocationLength = sizeof(INQUIRYDATA);\r\n\r\n    passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH);\r\n    passThrough->ScsiPassThrough.CdbLength = 6;\r\n    passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH;\r\n    passThrough->ScsiPassThrough.DataIn = 1;\r\n    passThrough->ScsiPassThrough.DataTransferLength = sizeof(INQUIRYDATA);\r\n    passThrough->ScsiPassThrough.TimeOutValue = 20;\r\n    passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer);\r\n    passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer);\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH,\r\n                                      DeviceObject,\r\n                                      passThrough,\r\n                                      passThrough,\r\n                                      length,\r\n                                      length,\r\n                                      FALSE,\r\n                                      &ioStatus);\r\n\r\n    status = ioStatus.Status;\r\n    senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer);\r\n\r\n    if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) {\r\n\r\n        //\r\n        // Get the returned data.\r\n        //\r\n        inquiryData = (PINQUIRYDATA)(passThrough->DataBuffer);\r\n\r\n        RtlCopyMemory(InquiryData, inquiryData, sizeof(INQUIRYDATA));\r\n\r\n    } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) &&\r\n               (NT_SUCCESS(ioStatus.Status)) &&\r\n               (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) {\r\n\r\n        length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n        //\r\n        // Retry the request\r\n        //\r\n        RtlZeroMemory(passThrough, length);\r\n        goto __Retry_Request;\r\n\r\n    } else {\r\n\r\n        // Failed to get inquiry data\r\n        // Here it is possible that status is success, but scsi status is not.\r\n        // If so, set status to unsuccessful.\r\n        if (NT_SUCCESS(status)){\r\n            status = STATUS_UNSUCCESSFUL;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetStandardInquiryData (DevObj %p): NTStatus 0x%x, ScsiStatus 0x%x.\\n\",\r\n                    DeviceObject,\r\n                    status,\r\n                    passThrough->ScsiPassThrough.ScsiStatus));\r\n    }\r\n\r\n__Exit_DsmpGetStandardInquiryData:\r\n\r\n    //\r\n    // Free the passthrough + data buffer.\r\n    //\r\n    if (passThrough) {\r\n        DsmpFreePool(passThrough);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetStandardInquiryData (DevObj %p): Exiting function with status %x.\\n\",\r\n                DeviceObject,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpCheckScsiCompliance(\r\n    _In_ IN PDEVICE_OBJECT TargetObject,\r\n    _In_ IN PINQUIRYDATA InquiryData,\r\n    _In_ IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceIdList\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to determine if the device is SPC-3 compliant.\r\n\r\nArguments:\r\n\r\n    DeviceObject - The port PDO that we're determining compliance for.\r\n    InquiryData - Pointer to its inquiry data.\r\n    Descriptor - Pointer to its VPD page 0x80 data\r\n    DeviceIdList - Pointer to its VPD page 0x83 data\r\n\r\nReturn Value:\r\n\r\n    TRUE if compliant, else FALSE.\r\n\r\n--*/\r\n{\r\n    BOOLEAN supported = FALSE /* TRUE */;\r\n    UCHAR deviceType;\r\n    UCHAR qualifier;\r\n\r\n    UNREFERENCED_PARAMETER(DeviceIdList);\r\n    UNREFERENCED_PARAMETER(Descriptor);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpCheckScsiCompliance (DevObj %p): Entering function.\\n\",\r\n                TargetObject));\r\n\r\n    deviceType = InquiryData->DeviceType & 0x1F;\r\n    qualifier = (InquiryData->DeviceTypeQualifier >> 0x5) & 0x7;\r\n\r\n    if ((deviceType | qualifier) == 0x7F) {\r\n\r\n        supported = FALSE;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpCheckScsiCompliance (DevObj %p): Exiting function with Supported = %u.\\n\",\r\n                TargetObject,\r\n                supported));\r\n\r\n    return supported;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpDeviceSupported(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _In_ IN PCSTR VendorId,\r\n    _In_ IN PCSTR ProductId\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine determines whether the device is supported by traversing the SupportedDevice\r\n    list and comparing to the VendorId/ProductId values passed in.\r\n\r\nArguments:\r\n\r\n    Context   - Context value given to the multipath driver during registration.\r\n    VendorId - Pointer to the inquiry data VendorId.\r\n    ProductId - Pointer to the inquiry data ProductId.\r\n\r\nReturn Value:\r\n\r\n    TRUE - If VendorId/ProductId is found.\r\n\r\n--*/\r\n{\r\n    UNICODE_STRING deviceName;\r\n    UNICODE_STRING productName;\r\n    ANSI_STRING ansiVendor;\r\n    ANSI_STRING ansiProduct;\r\n    NTSTATUS status;\r\n    BOOLEAN supported = FALSE;\r\n    KIRQL oldIrql;\r\n    UNICODE_STRING tempStrings;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpDeviceSupported (DsmCtxt %p): Entering function.\\n\",\r\n                Context));\r\n\r\n    KeAcquireSpinLock(&Context->SupportedDevicesListLock, &oldIrql);\r\n\r\n    RtlInitUnicodeString(&tempStrings, NULL);\r\n    tempStrings.Buffer = DsmpAllocatePool(NonPagedPoolNx, Context->SupportedDevices.MaximumLength, DSM_TAG_REG_VALUE_RELATED);\r\n\r\n    if (tempStrings.Buffer) {\r\n\r\n        RtlCopyMemory(tempStrings.Buffer, Context->SupportedDevices.Buffer, Context->SupportedDevices.Length);\r\n        tempStrings.Length = Context->SupportedDevices.Length;\r\n        tempStrings.MaximumLength = Context->SupportedDevices.MaximumLength;\r\n\r\n    } else {\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpDeviceSupported (DsmCtxt %p): Failed to allocate temporary list (error %x).\\n\",\r\n                    Context,\r\n                    status));\r\n\r\n        KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql);\r\n\r\n        goto __Exit_DsmpDeviceSupported;\r\n    }\r\n\r\n    KeReleaseSpinLock(&Context->SupportedDevicesListLock, oldIrql);\r\n\r\n    //\r\n    // The SupportedDevice list was built in DriverEntry from the services key.\r\n    //\r\n    if (tempStrings.MaximumLength == 0) {\r\n\r\n        //\r\n        // List is empty.\r\n        //\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpDeviceSupported (DsmCtxt %p): No supported Device in the list.\\n\",\r\n                    Context));\r\n\r\n        goto __Exit_DsmpDeviceSupported;\r\n    }\r\n\r\n    RtlInitUnicodeString(&productName, NULL);\r\n\r\n    //\r\n    // Convert the inquiry fields into ansi strings.\r\n    //\r\n    RtlInitAnsiString(&ansiVendor, VendorId);\r\n    RtlInitAnsiString(&ansiProduct, ProductId);\r\n\r\n    //\r\n    // Allocate the deviceName buffer. Needs to be 8+16 plus NULL.\r\n    // (productId length + vendorId length + NULL).\r\n    //\r\n    deviceName.MaximumLength = 25 * sizeof(WCHAR);\r\n    deviceName.Buffer = DsmpAllocatePool(PagedPool, deviceName.MaximumLength, DSM_TAG_SUPPORTED_DEV);\r\n\r\n    if (deviceName.Buffer) {\r\n\r\n        //\r\n        // Convert the vendorId to unicode.\r\n        //\r\n        status = RtlAnsiStringToUnicodeString(&deviceName, &ansiVendor, FALSE);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // Convert the productId to unicode.\r\n            //\r\n            status = RtlAnsiStringToUnicodeString(&productName, &ansiProduct, TRUE);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                //\r\n                // 'cat' them.\r\n                //\r\n                status = RtlAppendUnicodeStringToString(&deviceName, &productName);\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    //\r\n                    // Run the list of supported devices that was captured from the registry\r\n                    // and see if this one is in the list.\r\n                    //\r\n                    supported = DsmpFindSupportedDevice(&deviceName,\r\n                                                        &tempStrings);\r\n                }\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpDeviceSupported (DsmCtxt %p): Failed to append product name. Status %x.\\n\",\r\n                            Context,\r\n                            status));\r\n            }\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpDeviceSupported (DsmCtxt %p): Failed to convert ansi vendor string to unicode. Status %x\\n\",\r\n                        Context,\r\n                        status));\r\n        }\r\n\r\n        DsmpFreePool(deviceName.Buffer);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpDeviceSupported (DsmCtxt %p): Failed to allocate device name buffer.\\n\",\r\n                    Context));\r\n    }\r\n\r\n__Exit_DsmpDeviceSupported:\r\n\r\n    if (tempStrings.Buffer) {\r\n        DsmpFreePool(tempStrings.Buffer);\r\n    }\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpDeviceSupported (DsmCtxt %p): Exiting function with supported = %u.\\n\",\r\n                Context,\r\n                supported));\r\n\r\n    return supported;\r\n}\r\n\r\n\r\nBOOLEAN\r\nDsmpFindSupportedDevice(\r\n    _In_ IN PUNICODE_STRING DeviceName,\r\n    _In_ IN PUNICODE_STRING SupportedDevices\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine compares the two unicode strings for a match.\r\n\r\nArguments:\r\n\r\n    DeviceName - String built from the current device's inquiry data.\r\n    SupportedDevices - MULTI_SZ of devices that are supported.\r\n\r\nReturn Value:\r\n\r\n    TRUE - If VendorId/ProductId is found.\r\n\r\n--*/\r\n{\r\n    PWSTR devices = SupportedDevices->Buffer;\r\n    ULONG bufferLengthLeft = SupportedDevices->MaximumLength / sizeof(WCHAR);\r\n    UNICODE_STRING unicodeString;\r\n    USHORT originalLength = DeviceName->Length;\r\n    LONG compare;\r\n    BOOLEAN supported = FALSE;\r\n    WCHAR tempString[32];\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindSupportedDevice (DevName %ws): Entering function.\\n\",\r\n                DeviceName->Buffer));\r\n\r\n    //\r\n    // 'devices' is the current buffer in the MULTI_SZ built from\r\n    // the registry.\r\n    //\r\n    while (devices[0]) {\r\n\r\n        RtlZeroMemory(tempString, sizeof(tempString));\r\n\r\n        if (!NT_SUCCESS(RtlStringCchCopyNW(tempString, sizeof(tempString) / sizeof(tempString[0]), devices, bufferLengthLeft))) {\r\n\r\n            tempString[(sizeof(tempString) / sizeof(tempString)) - 1] = L'\\0';\r\n        }\r\n\r\n        //\r\n        // Make the current entry into a unicode string.\r\n        //\r\n        RtlInitUnicodeString(&unicodeString, tempString);\r\n\r\n        //\r\n        // Compare this one with the current device.\r\n        // However, for storages that make up the product id on-the-fly, MPIO\r\n        // allows for matching based just on substring (product-id-prefix so to\r\n        // speak).\r\n        //\r\n        if (unicodeString.Length < DeviceName->Length) {\r\n            DeviceName->Length = unicodeString.Length;\r\n        }\r\n\r\n        compare = RtlCompareUnicodeStrings(unicodeString.Buffer,\r\n                                           unicodeString.Length / sizeof(WCHAR),\r\n                                           DeviceName->Buffer,\r\n                                           DeviceName->Length / sizeof(WCHAR),\r\n                                           TRUE);\r\n\r\n        DeviceName->Length = originalLength;\r\n\r\n        if (compare == 0) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpFindSupportedDevice (DevName %ws): Device support found in the registry.\\n\",\r\n                        DeviceName->Buffer));\r\n\r\n            supported = TRUE;\r\n            break;\r\n        }\r\n\r\n        //\r\n        // Advance to next entry in the MULTI_SZ.\r\n        //\r\n        devices += (unicodeString.MaximumLength / sizeof(WCHAR));\r\n\r\n        bufferLengthLeft -= (unicodeString.MaximumLength / sizeof(WCHAR));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpFindSupportedDevice (DevName %ws): Exiting function with Supported = %u.\\n\",\r\n                DeviceName->Buffer,\r\n                supported));\r\n\r\n    return supported;\r\n}\r\n\r\n_Success_(return!=0)\r\nPVOID\r\nDsmpParseDeviceID(\r\n    _In_ IN PSTORAGE_DEVICE_ID_DESCRIPTOR DeviceID,\r\n    _In_ IN DSM_DEVID_TYPE DeviceIdType,\r\n    _In_opt_ IN PULONG IdNumber,\r\n    _Out_opt_ OUT PSTORAGE_IDENTIFIER_CODE_SET CodeSet,\r\n    _In_ IN BOOLEAN Legacy\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine builds a serial number string based on the information\r\n    in the VPD page 0x83 data if serial number is requested, else it\r\n    returns the appropriate identifier requested.\r\n\r\n    Caller must free the buffer.\r\n\r\nArguments:\r\n\r\n    DeviceIdList - VPD Page 0x83 information.\r\n    DeviceIdType - Type of identifier that the DeviceID is being parsed for\r\n    IdNumber - If there are multiple identifiers of type DeviceIdType, this parameter\r\n                   determines which among them to actually return.\r\n                   IMPORTANT: This number is one-based (not zero-based).\r\n    CodeSet - Of relevance only if the DeviceIdType is DSM_DEVID_SERIAL_NUMBER. This\r\n                   returns the code set that was used when building the serial number.\r\n    Legacy - Of relevance only if the DeviceIdType is DSM_DEVID_SERIAL_NUMBER. If the\r\n                   code set of the identifier is StorageIdCodeSetBinary, this determines\r\n                   whether to use the legacy method of binary to ascii conversion.\r\n\r\nReturn Value:\r\n\r\n    Requested Device identifier.\r\n\r\n--*/\r\n{\r\n    PSTORAGE_IDENTIFIER identifier;\r\n    STORAGE_IDENTIFIER_CODE_SET codeSet = StorageIdCodeSetReserved; // Preload with a bogus value.\r\n    STORAGE_IDENTIFIER_TYPE type = 0xF;\r\n    STORAGE_ASSOCIATION_TYPE association = 0xF;\r\n    ULONG numberIds;\r\n    ULONG i;\r\n    ULONG identifierSize = 0;\r\n    PUCHAR bytes = NULL;\r\n    PVOID buffer = NULL;\r\n    BOOLEAN done = FALSE;\r\n    ULONG idNumber = MAXULONG;\r\n    ULONG matches = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpParseDeviceID (DevIdDesc %p): Entering function - IdType %x.\\n\",\r\n                DeviceID,\r\n                DeviceIdType));\r\n\r\n    if (IdNumber) {\r\n        idNumber = *IdNumber;\r\n    }\r\n\r\n    //\r\n    // Get the number of encapsulated identifiers.\r\n    //\r\n    numberIds = DeviceID->NumberOfIdentifiers;\r\n\r\n    if (idNumber != MAXULONG && idNumber > numberIds) {\r\n        goto __Exit_DsmpParseDeviceID;\r\n    }\r\n\r\n    //\r\n    // Get a pointer to the first one.\r\n    //\r\n    identifier = (PSTORAGE_IDENTIFIER)(DeviceID->Identifiers);\r\n\r\n    for (i = 0; i < numberIds && !done; i++) {\r\n\r\n        switch (DeviceIdType) {\r\n\r\n            case DSM_DEVID_SERIAL_NUMBER: {\r\n\r\n                //\r\n                // The way this works is that we will go through all the identifiers\r\n                // Order of preference will be LUN-associated over Target-associated.\r\n                // Further, upon same association, preference will be based on type as\r\n                // follows: 0x8, 0x3, 0x2, 0x1, 0x0.\r\n                // So an existing identifier will be discarded if a better one is found.\r\n                // If two identifiers have the same type, we will prefer the one will\r\n                // the larger length.\r\n                //\r\n\r\n                //\r\n                // 1. Ensure that the association is for either the LUN or target. (If neither, ignore id).\r\n                // 2. If association is with target, don't it consider if current candidate has assocation with LUN.\r\n                // 3. If considering this identifier, order of preference is 8 > 3 > 2 > 1 > 0.\r\n                // 4. If this id type is same as current candidate, consider it only if it is of greater length.\r\n                //\r\n                if (((identifier->Association == StorageIdAssocDevice) ||\r\n                     (identifier->Association == 0x2 && association != StorageIdAssocDevice)) &&\r\n                    ((type == identifier->Type && identifierSize < identifier->IdentifierSize) ||\r\n                     (type != identifier->Type && DsmpIsPreferredDeviceId(type, identifier->Type)))) {\r\n\r\n                    //\r\n                    // Get a pointer to the id itself.\r\n                    //\r\n                    bytes = identifier->Identifier;\r\n\r\n                    //\r\n                    // The id's size.\r\n                    //\r\n                    identifierSize = identifier->IdentifierSize;\r\n\r\n                    //\r\n                    // Get the type, code set, and association.\r\n                    //\r\n                    type = identifier->Type;\r\n                    codeSet = identifier->CodeSet;\r\n                    association = identifier->Association;\r\n\r\n                    matches++;\r\n                }\r\n\r\n                break;\r\n            }\r\n\r\n            case DSM_DEVID_RELATIVE_TARGET_PORT: {\r\n\r\n                //\r\n                // Ensure that the association is for the target port.\r\n                //\r\n                if (identifier->Association != StorageIdAssocPort) {\r\n\r\n                    if ((i + 1) < numberIds) {\r\n                        identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset);\r\n                    }\r\n\r\n                    continue;\r\n                }\r\n\r\n                if (identifier->Type == StorageIdTypePortRelative) {\r\n\r\n                    //\r\n                    // Get a pointer to the id itself.\r\n                    //\r\n                    bytes = identifier->Identifier;\r\n\r\n                    //\r\n                    // The id's size.\r\n                    //\r\n                    identifierSize = identifier->IdentifierSize;\r\n\r\n                    type = identifier->Type;\r\n                    codeSet = identifier->CodeSet;\r\n                    association = identifier->Association;\r\n\r\n                    matches++;\r\n                }\r\n\r\n                break;\r\n            }\r\n\r\n            case DSM_DEVID_TARGET_PORT_GROUP: {\r\n\r\n                //\r\n                // Ensure that the association is for the target port.\r\n                //\r\n                if (identifier->Association != StorageIdAssocPort) {\r\n\r\n                    if ((i + 1) < numberIds) {\r\n                        identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset);\r\n                    }\r\n\r\n                    continue;\r\n                }\r\n\r\n                if (identifier->Type == 0x5) {\r\n\r\n                    //\r\n                    // Get a pointer to the id itself.\r\n                    //\r\n                    bytes = identifier->Identifier;\r\n\r\n                    //\r\n                    // Move this by two bytes because first two bytes are reservered\r\n                    //\r\n                    bytes += sizeof(USHORT);\r\n\r\n                    //\r\n                    // The id's size. Reduce the size by 2 bytes (to account\r\n                    // for the reservered bytes)\r\n                    //\r\n                    identifierSize = identifier->IdentifierSize - sizeof(USHORT);\r\n\r\n                    type = identifier->Type;\r\n                    codeSet = identifier->CodeSet;\r\n                    association = identifier->Association;\r\n\r\n                    matches++;\r\n                }\r\n\r\n                break;\r\n            }\r\n\r\n            default: break;\r\n        }\r\n\r\n\r\n        if (idNumber != MAXULONG && idNumber == matches) {\r\n            done = TRUE;\r\n        }\r\n\r\n        //\r\n        // Advance to the next identifier in the buffer.\r\n        //\r\n        if ((i + 1) < numberIds) {\r\n            identifier = (PSTORAGE_IDENTIFIER)((PUCHAR)identifier + identifier->NextOffset);\r\n        }\r\n    }\r\n\r\n    if (idNumber != MAXULONG && idNumber > matches) {\r\n        goto __Exit_DsmpParseDeviceID;\r\n    }\r\n\r\n    if (DeviceIdType == DSM_DEVID_SERIAL_NUMBER) {\r\n\r\n        if (type != StorageIdTypeScsiNameString &&\r\n            type != StorageIdTypeFCPHName &&\r\n            type != StorageIdTypeEUI64 &&\r\n            type != StorageIdTypeVendorId &&\r\n            type != StorageIdTypeVendorSpecific) {\r\n\r\n            DSM_ASSERT(FALSE);\r\n            bytes = NULL;\r\n            identifierSize = 0;\r\n            type = association = 0xF;\r\n            codeSet = StorageIdCodeSetReserved;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpParseDeviceID (DevIdDesc %p): IdentifierSize = %u, Type = %u, Association = %u, CodeSet = %u.\\n\",\r\n                    DeviceID,\r\n                    identifierSize,\r\n                    type,\r\n                    association,\r\n                    codeSet));\r\n\r\n        if (!bytes) {\r\n            goto __Exit_DsmpParseDeviceID;\r\n        }\r\n\r\n        if (codeSet == StorageIdCodeSetBinary) {\r\n\r\n            //\r\n            // Need to convert to ascii.\r\n            //\r\n            buffer = DsmpBinaryToAscii(bytes,\r\n                                       identifierSize,\r\n                                       &identifierSize,\r\n                                       Legacy);\r\n\r\n        } else {\r\n\r\n            if (identifierSize) {\r\n                //\r\n                // Allocate a buffer that is the size of the data, plus one for NULL.\r\n                //\r\n                buffer = DsmpAllocatePool(NonPagedPoolNx, identifierSize + 1, DSM_TAG_DEV_ID);\r\n                DSM_ASSERT(buffer);\r\n\r\n                if (buffer) {\r\n\r\n                    //\r\n                    // Copy over the id.\r\n                    //\r\n                    RtlCopyMemory(buffer, bytes, identifierSize);\r\n                }\r\n            }\r\n        }\r\n\r\n        if (CodeSet) {\r\n            *CodeSet = codeSet;\r\n        }\r\n\r\n    } else {\r\n\r\n        if (identifierSize) {\r\n\r\n            DSM_ASSERT((DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT && identifierSize == sizeof(ULONG)) ||\r\n                       (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP && identifierSize == sizeof(USHORT)));\r\n\r\n            _Analysis_assume_((DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT && identifierSize == sizeof(ULONG)) ||\r\n                              (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP && identifierSize == sizeof(USHORT)));\r\n\r\n            buffer = DsmpAllocatePool(NonPagedPoolNx, identifierSize, DSM_TAG_DEV_ID);\r\n\r\n            if (buffer) {\r\n\r\n                if (DeviceIdType == DSM_DEVID_RELATIVE_TARGET_PORT) {\r\n\r\n                    GetUlongFrom4ByteArray(bytes, *((PULONG)buffer));\r\n\r\n                } else if (DeviceIdType == DSM_DEVID_TARGET_PORT_GROUP) {\r\n\r\n                    *((PUSHORT)buffer) = (bytes[0] << 8) | (bytes[1]);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmpParseDeviceID:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpParseDeviceID (DevIdDesc %p): Exiting function with buffer %p.\\n\",\r\n                DeviceID,\r\n                buffer));\r\n\r\n    return buffer;\r\n}\r\n\r\n\r\nPUCHAR\r\nDsmpBinaryToAscii(\r\n    _In_reads_(Length) IN PUCHAR HexBuffer,\r\n    _In_ IN ULONG Length,\r\n    _Inout_ IN OUT PULONG UpdateLength,\r\n    _In_ IN BOOLEAN Legacy\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will convert HexBuffer into an ascii NULL-terminated string.\r\n\r\n    Note: This routine will allocate memory for storing the ascii string. It is\r\n          the responsibility of the caller to free this buffer.\r\n\r\nArguments:\r\n\r\n    HexBuffer - Pointer to the binary data.\r\n    Length - Length, in bytes, of HexBuffer.\r\n    UpdateLength - Storage to place the actual length of the returned string.\r\n    Legacy - Use the legacy method for the conversion.\r\n\r\nReturn Value:\r\n\r\n    Serial Number string, or NULL if an error occurred.\r\n\r\n--*/\r\n{\r\n    static UCHAR IntegerTable[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r\n    ULONG i;\r\n    ULONG j;\r\n    ULONG actualLength;\r\n    PUCHAR buffer = NULL;\r\n    UCHAR highWord;\r\n    UCHAR lowWord;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBinaryToAscii (HexBuff %p): Entering function.\\n\",\r\n                HexBuffer));\r\n\r\n    if (Length == 0) {\r\n        *UpdateLength = 0;\r\n        goto __Exit_DsmpBinaryToAscii;\r\n    }\r\n\r\n    if (Legacy) {\r\n        //\r\n        // Do a pre-test on the buffer to determine the length actually needed.\r\n        //\r\n        for (i = 0, actualLength = 0; i < Length; i++) {\r\n\r\n            if (HexBuffer[i] < 0x10) {\r\n                actualLength++;\r\n            } else {\r\n                actualLength += 2;\r\n            }\r\n        }\r\n\r\n        //\r\n        // Add room for a terminating NULL.\r\n        //\r\n        actualLength++;\r\n    } else {\r\n        //\r\n        // We need one character for each nibble, plus one for the terminating NULL.\r\n        //\r\n        actualLength = (Length * 2) + 1;\r\n    }\r\n\r\n    //\r\n    // Allocate the buffer.\r\n    //\r\n    buffer = DsmpAllocatePool(NonPagedPoolNx,\r\n                              actualLength,\r\n                              DSM_TAG_BIN_TO_ASCII);\r\n    if (!buffer) {\r\n        *UpdateLength = 0;\r\n        goto __Exit_DsmpBinaryToAscii;\r\n    }\r\n\r\n    for (i = 0, j = 0; i < Length && j < actualLength; i++) {\r\n\r\n        if (Legacy && (HexBuffer[i] < 0x10)) {\r\n\r\n            //\r\n            // If legacy is mentioned and it's 0x0F or less,\r\n            // just convert the entire byte.\r\n            //\r\n            buffer[j++] = IntegerTable[HexBuffer[i]];\r\n        } else {\r\n\r\n            //\r\n            // Split out each nibble from the binary byte.\r\n            //\r\n            highWord = HexBuffer[i] >> 4;\r\n            lowWord = HexBuffer[i] & 0x0F;\r\n\r\n            //\r\n            // Using the lookup table, convert and stuff into\r\n            // the ascii buffer.\r\n            //\r\n            buffer[j++] = IntegerTable[highWord];\r\n            buffer[j++] = IntegerTable[lowWord];\r\n        }\r\n    }\r\n\r\n    //\r\n    // Update the caller's length field.\r\n    //\r\n    *UpdateLength = actualLength;\r\n\r\n__Exit_DsmpBinaryToAscii:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBinaryToAscii (HexBuff %p): Exiting function with buffer %s.\\n\",\r\n                HexBuffer,\r\n                (const char*) buffer));\r\n\r\n    return buffer;\r\n}\r\n\r\n\r\nPSTR\r\nDsmpGetSerialNumber(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send an inquiry with EVPD set to get the serial number page.\r\n    Used if the serial number is not embedded in the device descriptor (this device probably\r\n    doesn't support VPD page 0x00).\r\n\r\n    Note: This routine will allocate memory for storing the serial number. It is\r\n          the responsibility of the caller to free this buffer.\r\n\r\nArguments:\r\n\r\n    DeviceObject - The port PDO to which the command should be sent.\r\n\r\nReturn Value:\r\n\r\n    The serial number (null-terminated string) or NULL if the call fails.\r\n\r\n--*/\r\n{\r\n    PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL;\r\n    PVPD_SERIAL_NUMBER_PAGE serialPage;\r\n    PCDB cdb;\r\n    PSTR serialNumber = NULL;\r\n    IO_STATUS_BLOCK ioStatus;\r\n    ULONG length;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetSerialNumber (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    //\r\n    // Build an inquiry command with EVPD and pagecode of 0x80 (serial number).\r\n    //\r\n    length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n    passThrough = DsmpAllocatePool(NonPagedPoolNx,\r\n                                   length,\r\n                                   DSM_TAG_PASS_THRU);\r\n    if (!passThrough) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetSerialNumber (DevObj %p): Failed to allocate mem for passthrough.\\n\",\r\n                    DeviceObject));\r\n\r\n        goto __Exit_DsmpGetSerialNumber;\r\n    }\r\n\r\n    //\r\n    // Build the cdb.\r\n    //\r\n    cdb = (PCDB)passThrough->ScsiPassThrough.Cdb;\r\n    cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;\r\n    cdb->CDB6INQUIRY.Reserved1 = 1;\r\n    cdb->CDB6INQUIRY.PageCode = VPD_SERIAL_NUMBER;\r\n    cdb->CDB6INQUIRY.AllocationLength = DSM_SERIAL_NUMBER_BUFFER_SIZE;\r\n\r\n    passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH);\r\n    passThrough->ScsiPassThrough.CdbLength = 6;\r\n    passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH;\r\n    passThrough->ScsiPassThrough.DataIn = 1;\r\n    passThrough->ScsiPassThrough.DataTransferLength = DSM_SERIAL_NUMBER_BUFFER_SIZE;\r\n    passThrough->ScsiPassThrough.TimeOutValue = 20;\r\n    passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer);\r\n    passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer);\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH,\r\n                                      DeviceObject,\r\n                                      passThrough,\r\n                                      passThrough,\r\n                                      length,\r\n                                      length,\r\n                                      FALSE,\r\n                                      &ioStatus);\r\n    if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) &&\r\n        (NT_SUCCESS(ioStatus.Status))) {\r\n\r\n        ULONG inx;\r\n\r\n        //\r\n        // Get the returned data.\r\n        //\r\n        serialPage = (PVPD_SERIAL_NUMBER_PAGE)(passThrough->DataBuffer);\r\n\r\n        //\r\n        // Allocate a buffer to hold just the serial number plus a null terminator\r\n        //\r\n        serialNumber = DsmpAllocatePool(NonPagedPoolNx,\r\n                                        serialPage->PageLength + 1,\r\n                                        DSM_TAG_SERIAL_NUM);\r\n        if (serialNumber) {\r\n\r\n            //\r\n            // Copy it over.\r\n            //\r\n            RtlCopyMemory(serialNumber, serialPage->SerialNumber, serialPage->PageLength);\r\n\r\n            //\r\n            // Some devices return binary data for the serial number.\r\n            // Convert to a more ascii-ish format so that other routines don't have a problem.\r\n            //\r\n            for (inx = 0; inx < serialPage->PageLength; inx++) {\r\n                if (serialNumber[inx] == '\\0') {\r\n                    serialNumber[inx] = ' ';\r\n                }\r\n            }\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpGetSerialNumber (DevObj %p): Failed to allocate mem for serialnumber.\\n\",\r\n                        DeviceObject));\r\n        }\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetSerialNumber (DevObj %p): NTStatus 0%x, ScsiStatus 0x%x.\\n\",\r\n                    DeviceObject,\r\n                    ioStatus.Status,\r\n                    passThrough->ScsiPassThrough.ScsiStatus));\r\n    }\r\n\r\n__Exit_DsmpGetSerialNumber:\r\n\r\n    //\r\n    // Free the passthrough + data buffer.\r\n    //\r\n    if (passThrough) {\r\n\r\n        DsmpFreePool(passThrough);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetSerialNumber (DevObj %p): Exiting function with serial number %s.\\n\",\r\n                DeviceObject,\r\n                (const char*)serialNumber));\r\n\r\n    //\r\n    // Return the sn.\r\n    //\r\n    return serialNumber;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpDisableImplicitStateTransition(\r\n    _In_ IN PDEVICE_OBJECT TargetDevice,\r\n    _Out_ OUT PBOOLEAN DisableImplicit\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Send down request to disable implicit ALUA state transition.\r\n    The function first sends down a mode sense to get the control extension mode\r\n    sense data. It then clears the IALUAE bit and sends down a mode select.\r\n\r\nArguements:\r\n\r\n    TargetDevice - Device object that will be target of this command.\r\n    DisableImplicit - Flag returned to the caller to indicate whether or not\r\n                      implicit transitions are disabled.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if the command succeeds.\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PSCSI_PASS_THROUGH_WITH_BUFFERS passThrough = NULL;\r\n    PCDB cdb;\r\n    IO_STATUS_BLOCK ioStatus;\r\n    ULONG length;\r\n    PSPC3_CONTROL_EXTENSION_MODE_PAGE controlExtensionPage = NULL;\r\n    PSENSE_DATA senseData = NULL;\r\n    BOOLEAN implicitDisabled = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpDisableImplicitStateTransition (DevObj %p): Entering function.\\n\",\r\n                TargetDevice));\r\n\r\n    //\r\n    // First build the mode sense command to get the control extension parameters.\r\n    //\r\n    length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n    passThrough = DsmpAllocatePool(NonPagedPoolNx,\r\n                                   length,\r\n                                   DSM_TAG_PASS_THRU);\r\n    if (!passThrough) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpDisableImplicitStateTransition (DevObj %p): Failed to allocate mem for passthrough.\\n\",\r\n                    TargetDevice));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpDisableImplicitStateTransition;\r\n    }\r\n\r\n__Retry_ModeSense:\r\n\r\n    passThrough->ScsiPassThrough.Length = sizeof(SCSI_PASS_THROUGH);\r\n    passThrough->ScsiPassThrough.CdbLength = 6;\r\n    passThrough->ScsiPassThrough.SenseInfoLength = SPTWB_SENSE_LENGTH;\r\n    passThrough->ScsiPassThrough.DataIn = 1;\r\n    passThrough->ScsiPassThrough.DataTransferLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE);\r\n    passThrough->ScsiPassThrough.TimeOutValue = 20;\r\n    passThrough->ScsiPassThrough.SenseInfoOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseInfoBuffer);\r\n    passThrough->ScsiPassThrough.DataBufferOffset = FIELD_OFFSET(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuffer);\r\n\r\n    //\r\n    // Build the cdb for mode sense.\r\n    //\r\n    cdb = (PCDB)passThrough->ScsiPassThrough.Cdb;\r\n    cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;\r\n    cdb->MODE_SENSE.Dbd = 1;\r\n    cdb->MODE_SENSE.PageCode = 0xA;\r\n    cdb->MODE_SENSE.SubPageCode = 0x01;\r\n    cdb->MODE_SENSE.AllocationLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE);\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH,\r\n                                      TargetDevice,\r\n                                      passThrough,\r\n                                      passThrough,\r\n                                      length,\r\n                                      length,\r\n                                      FALSE,\r\n                                      &ioStatus);\r\n\r\n    status = ioStatus.Status;\r\n    senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer);\r\n\r\n    if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) {\r\n\r\n        controlExtensionPage = (PSPC3_CONTROL_EXTENSION_MODE_PAGE)(passThrough->DataBuffer);\r\n\r\n        if (controlExtensionPage->ImplicitALUAEnable) {\r\n\r\n            controlExtensionPage->ImplicitALUAEnable = 0;\r\n\r\n__Retry_ModeSelect:\r\n\r\n            RtlZeroMemory(passThrough->SenseInfoBuffer, passThrough->ScsiPassThrough.SenseInfoLength);\r\n\r\n            passThrough->ScsiPassThrough.DataIn = 0;\r\n\r\n            //\r\n            // Build the cdb for mode select.\r\n            //\r\n            RtlZeroMemory(cdb, 6);\r\n            cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;\r\n            cdb->MODE_SELECT.SPBit = 0;\r\n            cdb->MODE_SELECT.PFBit = 1;\r\n            cdb->MODE_SELECT.ParameterListLength = sizeof(SPC3_CONTROL_EXTENSION_MODE_PAGE);\r\n\r\n            length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n            DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH,\r\n                                              TargetDevice,\r\n                                              passThrough,\r\n                                              passThrough,\r\n                                              length,\r\n                                              length,\r\n                                              FALSE,\r\n                                              &ioStatus);\r\n\r\n            status = ioStatus.Status;\r\n            senseData = (PSENSE_DATA)(passThrough->SenseInfoBuffer);\r\n\r\n            if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_GOOD) && (NT_SUCCESS(status))) {\r\n\r\n                implicitDisabled = TRUE;\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpDisableImplicitStateTransition (DevObj %p): Implicit transitions turned off successfully.\\n\",\r\n                            TargetDevice));\r\n\r\n            } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) &&\r\n                       (NT_SUCCESS(status)) &&\r\n                       (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) {\r\n\r\n                //\r\n                // Retry the request\r\n                //\r\n                goto __Retry_ModeSelect;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpDisableImplicitStateTransition (DevObj %p): ModeSelect failed - NTStatus 0x%x, ScsiStatus 0x%x.\\n\",\r\n                            TargetDevice,\r\n                            status,\r\n                            passThrough->ScsiPassThrough.ScsiStatus));\r\n            }\r\n        } else {\r\n\r\n            implicitDisabled = TRUE;\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpDisableImplicitStateTransition (DevObj %p): Implicit transitions already turned OFF.\\n\",\r\n                        TargetDevice));\r\n        }\r\n    } else if ((passThrough->ScsiPassThrough.ScsiStatus == SCSISTAT_CHECK_CONDITION) &&\r\n               (NT_SUCCESS(status)) &&\r\n               (DsmpShouldRetryPassThroughRequest(senseData, passThrough->ScsiPassThrough.SenseInfoLength))) {\r\n\r\n        length = sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS);\r\n\r\n        //\r\n        // Retry the request\r\n        //\r\n        RtlZeroMemory(passThrough, length);\r\n        goto __Retry_ModeSense;\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpDisableImplicitStateTransition (DevObj %p): ModeSense failed - NTStatus 0x%x, ScsiStatus 0x%x.\\n\",\r\n                    TargetDevice,\r\n                    status,\r\n                    passThrough->ScsiPassThrough.ScsiStatus));\r\n    }\r\n\r\n__Exit_DsmpDisableImplicitStateTransition:\r\n\r\n    //\r\n    // Free the passthrough + data buffer.\r\n    //\r\n    if (passThrough) {\r\n        DsmpFreePool(passThrough);\r\n    }\r\n\r\n    //\r\n    // Return whether IALUAE is set to 0.\r\n    //\r\n    if (DisableImplicit) {\r\n\r\n        *DisableImplicit = implicitDisabled;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpDisableImplicitStateTransition (DevObj %p): Exiting function with status %x.\\n\",\r\n                TargetDevice,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPWSTR\r\nDsmpBuildHardwareId(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Construct a string concatinating VendorId with ProductId.\r\n\r\nArguements:\r\n\r\n    DeviceInfo   - Device Extension\r\n\r\nReturn Value :\r\n\r\n    NULL terminated hardware id if it was built successfully.\r\n    NULL in case of failure.\r\n\r\n--*/\r\n{\r\n    PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;\r\n    PWSTR hardwareId = NULL;\r\n    SIZE_T vendorIDLength = 0;\r\n    SIZE_T productIDLength = 0;\r\n    PCSZ vendorIdOffset;\r\n    PCSZ productIdOffset;\r\n    SIZE_T sizeNeeded;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ANSI_STRING ansiString;\r\n    UNICODE_STRING unicodeString;\r\n    ULONG offset;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildHardwareId (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    deviceDescriptor = &(DeviceInfo->Descriptor);\r\n\r\n    //\r\n    // Save the vendorid and productid offset in Device Descriptor\r\n    //\r\n    offset = deviceDescriptor->ProductIdOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    offset = deviceDescriptor->VendorIdOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    if (!vendorIDLength || !productIDLength) {\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildHardwareId (DevInfo %p): Invalid vendor and/or product id.\\n\",\r\n                    DeviceInfo));\r\n\r\n        goto __Exit_DsmpBuildHardwareId;\r\n    }\r\n\r\n    sizeNeeded = vendorIDLength + productIDLength;\r\n    hardwareId = DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_HARDWARE_ID);\r\n    if (!hardwareId) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildHardwareId (DevInfo %p): Failed to allocate memory for device name.\\n\",\r\n                    DeviceInfo));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpBuildHardwareId;\r\n    }\r\n\r\n    //\r\n    // Build the NULL terminated hardwareId whose format is :\r\n    //\r\n    //        VendorIdProductId\r\n    //\r\n    vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->VendorIdOffset);\r\n    RtlInitAnsiString(&ansiString, vendorIdOffset);\r\n    unicodeString.Length = 0;\r\n    unicodeString.MaximumLength = (USHORT)vendorIDLength;\r\n    unicodeString.Buffer = hardwareId;\r\n\r\n    status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                          &ansiString,\r\n                                          FALSE);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildHardwareId (DevInfo %p): Failed to convert vendor id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n        goto __Exit_DsmpBuildHardwareId;\r\n    }\r\n\r\n    productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor + deviceDescriptor->ProductIdOffset);\r\n    RtlInitAnsiString(&ansiString, productIdOffset);\r\n    unicodeString.Length = 0;\r\n    unicodeString.MaximumLength = (USHORT)productIDLength;\r\n    unicodeString.Buffer = hardwareId + strlen(((PCHAR)deviceDescriptor) + offset);\r\n\r\n    status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                          &ansiString,\r\n                                          FALSE);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildHardwareId (DevInfo %p): Failed to convert product id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n        goto __Exit_DsmpBuildHardwareId;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildHardwareId (DevInfo %p): HardwareId is %ws.\\n\",\r\n                DeviceInfo,\r\n                hardwareId));\r\n\r\n__Exit_DsmpBuildHardwareId:\r\n\r\n    if (hardwareId && !NT_SUCCESS(status)) {\r\n        DsmpFreePool(hardwareId);\r\n        hardwareId = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildHardwareId (DevInfo %p): Exiting function with deviceName %ws.\\n\",\r\n                DeviceInfo,\r\n                hardwareId));\r\n\r\n    return hardwareId;\r\n}\r\n\r\n\r\nPWSTR\r\nDsmpBuildDeviceNameLegacyPage0x80(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Construct a string from VendorId, ProductId, and SerialNumber (page 0x80\r\n    info) of the device.\r\n\r\nArguements:\r\n\r\n    DeviceInfo - Device Extension\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if the device name was built successfully.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;\r\n    PWCHAR deviceName = NULL;\r\n    PWCHAR tmpPtr;\r\n    PWCHAR vendorID = NULL;\r\n    PWCHAR productID = NULL;\r\n    PWCHAR serialID = NULL;\r\n    ANSI_STRING ansiString;\r\n    UNICODE_STRING unicodeString;\r\n    UNICODE_STRING unicodeDeviceName;\r\n    SIZE_T vendorIDLength = 0;\r\n    SIZE_T productIDLength = 0;\r\n    SIZE_T serialIDLength = 0;\r\n    ULONG offset;\r\n    SIZE_T sizeNeeded;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    deviceDescriptor = &(DeviceInfo->Descriptor);\r\n\r\n    //\r\n    // Save the vendorid, productid, and serialnumber offset\r\n    // in Device Descriptor\r\n    //\r\n    offset = deviceDescriptor->VendorIdOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    offset = deviceDescriptor->ProductIdOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    offset = deviceDescriptor->SerialNumberOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        serialIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    //\r\n    // Allocate buffers to use to convert the IDs from ANSI to Unicode and\r\n    // eventually build the device name.\r\n    //\r\n    if (vendorIDLength > 0) {\r\n        vendorID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, vendorIDLength, DSM_TAG_DEV_NAME);\r\n        if (!vendorID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for vendor ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    if (productIDLength > 0) {\r\n        productID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, productIDLength, DSM_TAG_DEV_NAME);\r\n        if (!productID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for product ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    if (serialIDLength > 0) {\r\n        serialID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, serialIDLength, DSM_TAG_DEV_NAME);\r\n        if (!serialID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for serial ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    sizeNeeded = vendorIDLength + productIDLength + serialIDLength;\r\n    if (sizeNeeded > 0) {\r\n\r\n        //\r\n        // Account for the terminating NULL if serial id is empty.\r\n        //\r\n\r\n        sizeNeeded += (serialIDLength ? 0 : WNULL_SIZE);\r\n\r\n        deviceName = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_NAME);\r\n        if (!deviceName) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to allocate memory for device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    } else {\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n    }\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n    }\r\n\r\n    //\r\n    // Build the NULL terminated device name whose format is :\r\n    //\r\n    //        VendorId_ProductId_SerialNumber\r\n    //\r\n\r\n    unicodeDeviceName.Length = 0;\r\n    unicodeDeviceName.MaximumLength = (USHORT)sizeNeeded;\r\n    unicodeDeviceName.Buffer = deviceName;\r\n\r\n    if (vendorIDLength) {\r\n\r\n        PCSZ vendorIdOffset;\r\n\r\n        vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor +\r\n                         deviceDescriptor->VendorIdOffset);\r\n\r\n        RtlInitAnsiString(&ansiString, vendorIdOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) vendorIDLength;\r\n        unicodeString.Buffer = vendorID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert vendor id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(vendorID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, vendorID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate vendor ID to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n\r\n        RtlUnicodeStringCatString(&unicodeDeviceName, L\"_\");\r\n    }\r\n\r\n    if (productIDLength) {\r\n\r\n        PCSZ productIdOffset;\r\n\r\n        productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor +\r\n                          deviceDescriptor->ProductIdOffset);\r\n\r\n        RtlInitAnsiString(&ansiString, productIdOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) productIDLength;\r\n        unicodeString.Buffer = productID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert product id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(productID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, productID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate product ID to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n\r\n        RtlUnicodeStringCatString(&unicodeDeviceName, L\"_\");\r\n    }\r\n\r\n    //\r\n    // Serial number\r\n    //\r\n    if (serialIDLength) {\r\n\r\n        PCSZ serialNumberOffset;\r\n\r\n        serialNumberOffset = (PCSZ)((PUCHAR)deviceDescriptor +\r\n                              deviceDescriptor->SerialNumberOffset);\r\n\r\n        RtlInitAnsiString(&ansiString, serialNumberOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) serialIDLength;\r\n        unicodeString.Buffer = serialID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to convert serial number to unicode string.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(serialID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, serialID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Failed to concatenate serial number to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceNameLegacyPage0x80;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Device Name is %ws.\\n\",\r\n                DeviceInfo,\r\n                deviceName));\r\n\r\n__Exit_DsmpBuildDeviceNameLegacyPage0x80:\r\n\r\n    if (vendorID) {\r\n        DsmpFreePool(vendorID);\r\n    }\r\n\r\n    if (productID) {\r\n        DsmpFreePool(productID);\r\n    }\r\n\r\n    if (serialID) {\r\n        DsmpFreePool(serialID);\r\n    }\r\n\r\n    if (deviceName && !NT_SUCCESS(status)) {\r\n        DsmpFreePool(deviceName);\r\n        deviceName = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceNameLegacyPage0x80 (DevInfo %p): Exiting function with deviceName %ws.\\n\",\r\n                DeviceInfo,\r\n                deviceName));\r\n\r\n    return deviceName;\r\n}\r\n\r\n\r\n\r\nPWSTR\r\nDsmpBuildDeviceName(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_reads_(SerialNumberLength) IN PSTR SerialNumber,\r\n    _In_ IN SIZE_T SerialNumberLength\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Construct a string from VendorId, ProductId, and SerialNumber (page 0x83\r\n    identifiers) of the device.\r\n\r\nArguements:\r\n\r\n    DeviceInfo   - Device Extension\r\n    SerialNumber - Device serial number built from appropriate page 0x83 identifier\r\n    SerialNumberLength - Length (in chars) of the passed in serial number buffer\r\n\r\nReturn Value :\r\n\r\n    Device name if it was built successfully.\r\n    NULL in case of failure.\r\n\r\n--*/\r\n{\r\n    PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;\r\n    PWCHAR deviceName = NULL;\r\n    PWCHAR tmpPtr;\r\n    PWCHAR vendorID = NULL;\r\n    PWCHAR productID = NULL;\r\n    PWCHAR serialID = NULL;\r\n    ANSI_STRING ansiString;\r\n    UNICODE_STRING unicodeString;\r\n    UNICODE_STRING unicodeDeviceName;\r\n    SIZE_T vendorIDLength = 0;\r\n    SIZE_T productIDLength = 0;\r\n    SIZE_T serialIDLength = 0;\r\n    ULONG offset;\r\n    SIZE_T sizeNeeded;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceName (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    deviceDescriptor = &(DeviceInfo->Descriptor);\r\n\r\n    //\r\n    // Save the vendorid, productid, and serialnumber offset\r\n    // in Device Descriptor\r\n    //\r\n    offset = deviceDescriptor->VendorIdOffset;\r\n    if ((offset != 0) && (offset != MAXULONG)) {\r\n\r\n        vendorIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    offset = deviceDescriptor->ProductIdOffset;\r\n    if ((offset != 0) && (offset != -1)) {\r\n\r\n        productIDLength = (strlen(((PCHAR)deviceDescriptor) + offset) * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    if (SerialNumber) {\r\n\r\n        serialIDLength = (SerialNumberLength * sizeof(WCHAR)) + WNULL_SIZE;\r\n    }\r\n\r\n    //\r\n    // Allocate buffers to use to convert the IDs from ANSI to Unicode and\r\n    // eventually build the device name.\r\n    //\r\n    if (vendorIDLength > 0) {\r\n        vendorID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, vendorIDLength, DSM_TAG_DEV_NAME);\r\n        if (!vendorID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for vendor ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    if (productIDLength > 0) {\r\n        productID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, productIDLength, DSM_TAG_DEV_NAME);\r\n        if (!productID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for product ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    if (serialIDLength > 0) {\r\n        serialID = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, serialIDLength, DSM_TAG_DEV_NAME);\r\n        if (!serialID) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for serial ID.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    }\r\n\r\n    sizeNeeded = vendorIDLength + productIDLength + serialIDLength;\r\n    if (sizeNeeded > 0) {\r\n\r\n        //\r\n        // Account for the terminating NULL if serial id is empty.\r\n        //\r\n\r\n        sizeNeeded += (serialIDLength ? 0 : WNULL_SIZE);\r\n\r\n        deviceName = (PWCHAR)DsmpAllocatePool(NonPagedPoolNx, sizeNeeded, DSM_TAG_DEV_NAME);\r\n        if (!deviceName) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to allocate memory for device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n        }\r\n    } else {\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n    }\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n        goto __Exit_DsmpBuildDeviceName;\r\n    }\r\n\r\n    //\r\n    // Build the NULL terminated device name whose format is :\r\n    //\r\n    //        VendorId_ProductId_SerialNumber\r\n    //\r\n\r\n    unicodeDeviceName.Length = 0;\r\n    unicodeDeviceName.MaximumLength = (USHORT)sizeNeeded;\r\n    unicodeDeviceName.Buffer = deviceName;\r\n\r\n    if (vendorIDLength) {\r\n\r\n        PCSZ vendorIdOffset;\r\n\r\n        vendorIdOffset = (PCSZ)((PUCHAR)deviceDescriptor +\r\n                         deviceDescriptor->VendorIdOffset);\r\n\r\n        RtlInitAnsiString(&ansiString, vendorIdOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) vendorIDLength;\r\n        unicodeString.Buffer = vendorID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildDeviceName (DevInfo %p): Failed to convert vendor id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(vendorID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, vendorID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to concatenate vendor ID to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n\r\n        RtlUnicodeStringCatString(&unicodeDeviceName, L\"_\");\r\n    }\r\n\r\n    if (productIDLength) {\r\n\r\n        PCSZ productIdOffset;\r\n\r\n        productIdOffset = (PCSZ)((PUCHAR)deviceDescriptor +\r\n                          deviceDescriptor->ProductIdOffset);\r\n\r\n        RtlInitAnsiString(&ansiString, productIdOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) productIDLength;\r\n        unicodeString.Buffer = productID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpBuildDeviceName (DevInfo %p): Failed to convert product id to unicode string.\\n\",\r\n                    DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(productID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, productID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to concatenate product ID to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n\r\n        RtlUnicodeStringCatString(&unicodeDeviceName, L\"_\");\r\n    }\r\n\r\n    //\r\n    // Serial number\r\n    //\r\n    if (serialIDLength) {\r\n\r\n        PSTR serialNumberOffset;\r\n\r\n        serialNumberOffset = SerialNumber;\r\n\r\n        RtlInitAnsiString(&ansiString, serialNumberOffset);\r\n\r\n        unicodeString.Length = 0;\r\n        unicodeString.MaximumLength = (USHORT) serialIDLength;\r\n        unicodeString.Buffer = serialID;\r\n\r\n        status = RtlAnsiStringToUnicodeString(&unicodeString,\r\n                                              &ansiString,\r\n                                              FALSE);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to convert serial number to unicode string.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n\r\n        //\r\n        // If there are spaces in the id, set NULL at the first space.\r\n        //\r\n        tmpPtr = wcschr(serialID, L' ');\r\n        if (tmpPtr != NULL) {\r\n            *tmpPtr = WNULL;\r\n        }\r\n\r\n        status = RtlUnicodeStringCatString(&unicodeDeviceName, serialID);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpBuildDeviceName (DevInfo %p): Failed to concatenate serial number to device name.\\n\",\r\n                        DeviceInfo));\r\n\r\n            goto __Exit_DsmpBuildDeviceName;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceName (DevInfo %p): Device Name is %ws.\\n\",\r\n                DeviceInfo,\r\n                deviceName));\r\n\r\n__Exit_DsmpBuildDeviceName:\r\n\r\n    if (vendorID) {\r\n        DsmpFreePool(vendorID);\r\n    }\r\n\r\n    if (productID) {\r\n        DsmpFreePool(productID);\r\n    }\r\n\r\n    if (serialID) {\r\n        DsmpFreePool(serialID);\r\n    }\r\n\r\n    if (deviceName && !NT_SUCCESS(status)) {\r\n        DsmpFreePool(deviceName);\r\n        deviceName = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpBuildDeviceName (DevInfo %p): Exiting function with deviceName %ws.\\n\",\r\n                DeviceInfo,\r\n                deviceName));\r\n\r\n    return deviceName;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpApplyDeviceNameCorrection(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_reads_(DeviceNameLegacyLen) PWSTR DeviceNameLegacy,\r\n    _In_ IN SIZE_T DeviceNameLegacyLen,\r\n    _In_reads_(DeviceNameLen) PWSTR DeviceName,\r\n    _In_ IN SIZE_T DeviceNameLen\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    If the registry has a key name built with a legacy device name, this\r\n    function updates the key name with the current device name.\r\n\r\nArguements:\r\n\r\n    DeviceInfo          - Device instance\r\n    DeviceNameLegacy    - Device name built using legacy methods.\r\n    DeviceNameLegacyLen - Number of chars (including NULL) of the DeviceNameLegacy buffer.\r\n    DeviceName          - Device name built using current methods.\r\n    DeviceNameLen       - Number of chars (including NULL) of the DeviceName buffer.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if the device's key was updated successfully.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE lbSettingsKey = NULL;\r\n    HANDLE deviceKeyLegacy = NULL;\r\n    HANDLE deviceKey = NULL;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    NTSTATUS status;\r\n    UNICODE_STRING deviceNameLegacy;\r\n    UNICODE_STRING deviceName;\r\n\r\n    PAGED_CODE();\r\n\r\n    UNREFERENCED_PARAMETER(DeviceNameLen);\r\n    UNREFERENCED_PARAMETER(DeviceNameLegacyLen);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpApplyDeviceNameCorrection (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    //\r\n    // First open LoadBalanceSettings key under the service key.\r\n    //\r\n    status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to open LB Settings key. Status %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n\r\n        goto __Exit_DsmpApplyDeviceNameCorrection;\r\n    }\r\n\r\n    RtlInitUnicodeString(&deviceNameLegacy, DeviceNameLegacy);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &deviceNameLegacy,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               lbSettingsKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    //\r\n    // Open the old device key under DsmLoadBalanceSettings key.\r\n    // The name of this key is the one built using legacy methods - either a\r\n    // serial number from VPD page 0x80 or an aliased serial number from VPD\r\n    // page 0x83.\r\n    //\r\n    status = ZwOpenKey(&deviceKeyLegacy,\r\n                       KEY_ALL_ACCESS,\r\n                       &objectAttributes);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        ULONG disposition;\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpApplyDeviceNameCorrection (DevInfo %p): Key with old device name exists.\\n\",\r\n                    DeviceInfo));\r\n\r\n        RtlInitUnicodeString(&deviceName, DeviceName);\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &deviceName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   lbSettingsKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        //\r\n        // Since the old name key exists, create one with the new name.\r\n        //\r\n        status = ZwCreateKey(&deviceKey,\r\n                             KEY_ALL_ACCESS,\r\n                             &objectAttributes,\r\n                             0,\r\n                             NULL,\r\n                             REG_OPTION_NON_VOLATILE,\r\n                             &disposition);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // The new key shouldn't exist if the old one does.\r\n            // If it does, it indicates a error occured the previous time\r\n            // this was tried, so just copy over the old subtree anyways now.\r\n            //\r\n            DSM_ASSERT(disposition == REG_CREATED_NEW_KEY);\r\n\r\n            //\r\n            // Copy over the entire subtree of the old key over to the new key.\r\n            //\r\n            status = DsmpRegCopyTree(deviceKeyLegacy, deviceKey);\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to copy over the old device key's subtree. Status %x.\\n\",\r\n                            DeviceInfo,\r\n                            status));\r\n\r\n                goto __Exit_DsmpApplyDeviceNameCorrection;\r\n            }\r\n\r\n            //\r\n            // Delete the old key name.\r\n            //\r\n            status = DsmpRegDeleteTree(deviceKeyLegacy);\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to delete the old device key's subtree. Status %x.\\n\",\r\n                            DeviceInfo,\r\n                            status));\r\n\r\n                goto __Exit_DsmpApplyDeviceNameCorrection;\r\n            }\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to create the new device key. Status %x.\\n\",\r\n                        DeviceInfo,\r\n                        status));\r\n\r\n            goto __Exit_DsmpApplyDeviceNameCorrection;\r\n        }\r\n\r\n    } else if (status == STATUS_INVALID_HANDLE ||\r\n               status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpApplyDeviceNameCorrection (DevInfo %p): Key with old device name does not exist.\\n\",\r\n                    DeviceInfo));\r\n\r\n        status = STATUS_SUCCESS;\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpApplyDeviceNameCorrection (DevInfo %p): Failed to query key with old device name. Status %x\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n    }\r\n\r\n__Exit_DsmpApplyDeviceNameCorrection:\r\n\r\n    if (deviceKey) {\r\n        ZwClose(deviceKey);\r\n    }\r\n\r\n    if (deviceKeyLegacy) {\r\n        ZwClose(deviceKeyLegacy);\r\n    }\r\n\r\n    if (lbSettingsKey) {\r\n        ZwClose(lbSettingsKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpApplyDeviceNameCorrection (DevInfo %p): Exiting function with status %x\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryDeviceLBPolicyFromRegistry(\r\n    _In_ PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ PWSTR RegistryKeyName,\r\n    _Inout_ PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Inout_ PULONGLONG PreferredPath,\r\n    _Inout_ PUCHAR ExplicitlySet\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Query the saved load balance policy and preferred path for this device from\r\n    the registry.\r\n    Also returns whether this setting was explicitly set via WMI call to SetLBPolicy,\r\n    (as opposed to the settings being made based on defaults determined through the\r\n    storage's ALUA capabilities).\r\n\r\nArguements:\r\n\r\n    DeviceInfo - The instance of the LUN through a paricular path\r\n    RegistryKeyName - DeviceName representing this LUN\r\n    LoadBalanceType - Type of LB policy.\r\n    PreferredPath - The preferred path for the device.\r\n    ExplicitlySet - Flag reflecting if LB policy was explicitly set.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully query the registry for the info.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE lbSettingsKey = NULL;\r\n    HANDLE deviceKey = NULL;\r\n    UNICODE_STRING subKeyName;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    NTSTATUS status;\r\n    UNICODE_STRING keyValueName;\r\n    ULONG length;\r\n    struct _explicitSet {\r\n        KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;\r\n        UCHAR Data;\r\n    } explicitSet;\r\n    struct _preferredPath {\r\n        KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;\r\n        ULONGLONG Data;\r\n    } preferredPath;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    //\r\n    // Query the Load Balance settings for the given device from the registry.\r\n    // First open LoadBalanceSettings key under the service key.\r\n    //\r\n    status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to open LB Settings key. Status %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryDeviceLBPolicyFromRegistry;\r\n    }\r\n\r\n    RtlInitUnicodeString(&subKeyName, RegistryKeyName);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &subKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               lbSettingsKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    //\r\n    // Create or Open the device key under DsmLoadBalanceSettings key.\r\n    // The name of this key is the one built in DsmpBuildDeviceName\r\n    //\r\n    status = ZwCreateKey(&deviceKey,\r\n                         KEY_ALL_ACCESS,\r\n                         &objectAttributes,\r\n                         0,\r\n                         NULL,\r\n                         REG_OPTION_NON_VOLATILE,\r\n                         NULL);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n\r\n        RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n        queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                              RTL_QUERY_REGISTRY_REQUIRED |\r\n                              RTL_QUERY_REGISTRY_TYPECHECK;\r\n        queryTable[0].Name = DSM_LOAD_BALANCE_POLICY;\r\n        queryTable[0].EntryContext = LoadBalanceType;\r\n        queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n        status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                        deviceKey,\r\n                                        queryTable,\r\n                                        deviceKey,\r\n                                        NULL);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): LB Policy is %d.\\n\",\r\n                        DeviceInfo,\r\n                        *LoadBalanceType));\r\n\r\n        } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n            //\r\n            // The device key must have been newly created.\r\n            // Set the default load balance policy for this device\r\n            //\r\n\r\n            status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                           deviceKey,\r\n                                           DSM_LOAD_BALANCE_POLICY,\r\n                                           REG_DWORD,\r\n                                           LoadBalanceType,\r\n                                           sizeof(ULONG));\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write LB policy. Status %x.\\n\",\r\n                            DeviceInfo,\r\n                            status));\r\n\r\n                goto __Exit_DsmpQueryDeviceLBPolicyFromRegistry;\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            RtlInitUnicodeString(&keyValueName, DSM_POLICY_EXPLICITLY_SET);\r\n            status = ZwQueryValueKey(deviceKey,\r\n                                     &keyValueName,\r\n                                     KeyValuePartialInformation,\r\n                                     &explicitSet,\r\n                                     sizeof(explicitSet),\r\n                                     &length);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                NT_ASSERT(explicitSet.KeyValueInfo.DataLength == sizeof(UCHAR));\r\n\r\n                *ExplicitlySet = *((UCHAR UNALIGNED *)&(explicitSet.KeyValueInfo.Data));\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): ExplicitlySet is %!bool!.\\n\",\r\n                            DeviceInfo,\r\n                            *ExplicitlySet));\r\n\r\n            } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n                *ExplicitlySet = FALSE;\r\n\r\n                //\r\n                // The device key must have been newly created.\r\n                // Set ExplicitlySet to 0 to indicate that the default was used.\r\n                //\r\n                status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                               deviceKey,\r\n                                               DSM_POLICY_EXPLICITLY_SET,\r\n                                               REG_BINARY,\r\n                                               ExplicitlySet,\r\n                                               sizeof(UCHAR));\r\n                if (!NT_SUCCESS(status)) {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write ExplicitlySet. Status %x.\\n\",\r\n                                DeviceInfo,\r\n                                status));\r\n                }\r\n            }\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH);\r\n                status = ZwQueryValueKey(deviceKey,\r\n                                         &keyValueName,\r\n                                         KeyValuePartialInformation,\r\n                                         &preferredPath,\r\n                                         sizeof(preferredPath),\r\n                                         &length);\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG));\r\n\r\n                    *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data));\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): PreferredPath is %I64x.\\n\",\r\n                                DeviceInfo,\r\n                                *PreferredPath));\r\n\r\n                } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n                    *PreferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n\r\n                    //\r\n                    // The device key must have been newly created.\r\n                    // Set a bogus preferred path as default.\r\n                    //\r\n                    status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                                   deviceKey,\r\n                                                   DSM_PREFERRED_PATH,\r\n                                                   REG_BINARY,\r\n                                                   PreferredPath,\r\n                                                   sizeof(ULONGLONG));\r\n                    if (!NT_SUCCESS(status)) {\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_PNP,\r\n                                    \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to write PreferredPath. Status %x.\\n\",\r\n                                    DeviceInfo,\r\n                                    status));\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Failed to create LB policy registry key. Status %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n\r\n        deviceKey = NULL;\r\n    }\r\n\r\n__Exit_DsmpQueryDeviceLBPolicyFromRegistry:\r\n\r\n    if (deviceKey) {\r\n        ZwClose(deviceKey);\r\n    }\r\n\r\n    if (lbSettingsKey) {\r\n        ZwClose(lbSettingsKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryDeviceLBPolicyFromRegistry (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryTargetLBPolicyFromRegistry(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONGLONG PreferredPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Query the load balance policy for the VID/PID of the passed in device from\r\n    the registry if it has been set.\r\n\r\nArguements:\r\n\r\n    DeviceInfo - Device's whose VID/PID we need to compare against.\r\n    LoadBalanceType - Type of LB policy.\r\n    PreferredPath - The preferred path for the device.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully query the registry for the info.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE targetsLBSettingKey = NULL;\r\n    HANDLE targetKey = NULL;\r\n    UNICODE_STRING subKeyName;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\r\n    UNICODE_STRING keyValueName;\r\n    ULONG length;\r\n    struct _preferredPath {\r\n        KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;\r\n        ULONGLONG Data;\r\n    } preferredPath;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    if (!LoadBalanceType || !PreferredPath) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Invalid parameter.\\n\",\r\n                    DeviceInfo));\r\n\r\n        goto __Exit_DsmpQueryTargetLBPolicyFromRegistry;\r\n    }\r\n\r\n    if (!DeviceInfo->Group->HardwareId) {\r\n\r\n        status = STATUS_UNSUCCESSFUL;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Couldn't build hardware id for passed in device.\\n\",\r\n                    DeviceInfo));\r\n\r\n        goto __Exit_DsmpQueryTargetLBPolicyFromRegistry;\r\n    }\r\n\r\n    //\r\n    // Query the Load Balance settings for the given target from the registry.\r\n    // First open TargetsLoadBalanceSetting key under the service key.\r\n    //\r\n    status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to open Targets LB Setting key. Status %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryTargetLBPolicyFromRegistry;\r\n    }\r\n\r\n    RtlInitUnicodeString(&subKeyName, DeviceInfo->Group->HardwareId);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &subKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               targetsLBSettingKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    //\r\n    // Open the VID/PID key under DsmTargetsLoadBalanceSetting key.\r\n    //\r\n    status = ZwOpenKey(&targetKey, KEY_ALL_ACCESS, &objectAttributes);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n\r\n        RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n        queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                              RTL_QUERY_REGISTRY_REQUIRED |\r\n                              RTL_QUERY_REGISTRY_TYPECHECK;\r\n        queryTable[0].Name = DSM_LOAD_BALANCE_POLICY;\r\n        queryTable[0].EntryContext = LoadBalanceType;\r\n        queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n        status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                        targetKey,\r\n                                        queryTable,\r\n                                        targetKey,\r\n                                        NULL);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): LB Policy is %d.\\n\",\r\n                        DeviceInfo,\r\n                        *LoadBalanceType));\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to query LB Policy - error %x.\\n\",\r\n                        DeviceInfo,\r\n                        status));\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH);\r\n            status = ZwQueryValueKey(targetKey,\r\n                                     &keyValueName,\r\n                                     KeyValuePartialInformation,\r\n                                     &preferredPath,\r\n                                     sizeof(preferredPath),\r\n                                     &length);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG));\r\n\r\n                *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data));\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): PreferredPath is %I64x.\\n\",\r\n                            DeviceInfo,\r\n                            *PreferredPath));\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to query PreferredPath. Status %x.\\n\",\r\n                            DeviceInfo,\r\n                            status));\r\n            }\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Failed to open LB policy registry key. Status %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n\r\n        targetKey = NULL;\r\n    }\r\n\r\n__Exit_DsmpQueryTargetLBPolicyFromRegistry:\r\n\r\n    if (targetKey) {\r\n        ZwClose(targetKey);\r\n    }\r\n\r\n    if (targetsLBSettingKey) {\r\n        ZwClose(targetsLBSettingKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryTargetLBPolicyFromRegistry (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryDsmLBPolicyFromRegistry(\r\n    _Out_ OUT PDSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONGLONG PreferredPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Query the overall load balance policy for MSDSM controlled devices from\r\n    the registry if it has been set.\r\n\r\nArguements:\r\n\r\n    LoadBalanceType - Type of LB policy.\r\n    PreferredPath - The preferred path for the device.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully query the registry for the info.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE parametersKey = NULL;\r\n    NTSTATUS status = STATUS_INVALID_PARAMETER;\r\n    UNICODE_STRING keyValueName;\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n    ULONG length;\r\n    struct _preferredPath {\r\n        KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;\r\n        ULONGLONG Data;\r\n    } preferredPath;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryDsmLBPolicyFromRegistry: Entering function.\\n\"));\r\n\r\n    if (!LoadBalanceType || !PreferredPath) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDsmLBPolicyFromRegistry: Invalid parameter.\\n\"));\r\n\r\n        goto __Exit_DsmpQueryDsmLBPolicyFromRegistry;\r\n    }\r\n\r\n    //\r\n    // Query the overall default Load Balance settings for MSDSM from the registry.\r\n    // First open the Parameters key under the service key.\r\n    //\r\n    status = DsmpOpenDsmServicesParametersKey(KEY_ALL_ACCESS, &parametersKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDsmLBPolicyFromRegistry: Failed to open Parameters key. Status %x.\\n\",\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryDsmLBPolicyFromRegistry;\r\n    }\r\n\r\n    RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                          RTL_QUERY_REGISTRY_REQUIRED |\r\n                          RTL_QUERY_REGISTRY_TYPECHECK;\r\n    queryTable[0].Name = DSM_LOAD_BALANCE_POLICY;\r\n    queryTable[0].EntryContext = LoadBalanceType;\r\n    queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n    status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                    parametersKey,\r\n                                    queryTable,\r\n                                    parametersKey,\r\n                                    NULL);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDsmLBPolicyFromRegistry: LB Policy is %d.\\n\",\r\n                    *LoadBalanceType));\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryDsmLBPolicyFromRegistry: Failed to query LB policy. Status %x.\\n\",\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryDsmLBPolicyFromRegistry;\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH);\r\n        status = ZwQueryValueKey(parametersKey,\r\n                                 &keyValueName,\r\n                                 KeyValuePartialInformation,\r\n                                 &preferredPath,\r\n                                 sizeof(preferredPath),\r\n                                 &length);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            NT_ASSERT(preferredPath.KeyValueInfo.DataLength == sizeof(ULONGLONG));\r\n\r\n            *PreferredPath = *((ULONGLONG UNALIGNED *)&(preferredPath.KeyValueInfo.Data));\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryDsmLBPolicyFromRegistry: PreferredPath is %I64x.\\n\",\r\n                        *PreferredPath));\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryDsmLBPolicyFromRegistry: Failed to query PreferredPath. Status %x.\\n\",\r\n                        status));\r\n        }\r\n    }\r\n\r\n__Exit_DsmpQueryDsmLBPolicyFromRegistry:\r\n\r\n    if (parametersKey) {\r\n        ZwClose(parametersKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryDsmLBPolicyFromRegistry: Exiting function with status %x.\\n\",\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetDsmLBPolicyInRegistry(\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Set the overall load balance policy for MSDSM controlled devices in\r\n    the registry.\r\n    Note: If the policy specified is 0, remove the currently set values\r\n          for policy and preferred path.\r\n\r\nArguements:\r\n\r\n    LoadBalanceType - Type of LB policy.\r\n    PreferredPath - The preferred path for devices controlled by DSM.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully set the info in the registry.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE parametersKey = NULL;\r\n    NTSTATUS status;\r\n    UNICODE_STRING lbPolicyValueName;\r\n    UNICODE_STRING preferredPathValueName;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetDsmLBPolicyInRegistry: Entering function.\\n\"));\r\n\r\n    //\r\n    // First open the Parameters key under the service key.\r\n    //\r\n    status = DsmpOpenDsmServicesParametersKey(KEY_ALL_ACCESS, &parametersKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetDsmLBPolicyInRegistry: Failed to open Parameters key. Status %x.\\n\",\r\n                    status));\r\n\r\n        goto __Exit_DsmpSetDsmLBPolicyInRegistry;\r\n    }\r\n\r\n    RtlInitUnicodeString(&lbPolicyValueName, DSM_LOAD_BALANCE_POLICY);\r\n    RtlInitUnicodeString(&preferredPathValueName, DSM_PREFERRED_PATH);\r\n\r\n    //\r\n    // If the LB policy is specified as 0, we need to delete the values.\r\n    //\r\n    if (LoadBalanceType < DSM_LB_FAILOVER) {\r\n\r\n        status = ZwDeleteValueKey(parametersKey, &preferredPathValueName);\r\n\r\n        if (NT_SUCCESS(status) || status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n            status = ZwDeleteValueKey(parametersKey, &lbPolicyValueName);\r\n        }\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetDsmLBPolicyInRegistry: Failed to delete either preferredPath or lbPolicy. Status %x.\\n\",\r\n                        status));\r\n        }\r\n    } else {\r\n\r\n        status = ZwSetValueKey(parametersKey,\r\n                               &lbPolicyValueName,\r\n                               0,\r\n                               REG_DWORD,\r\n                               &LoadBalanceType,\r\n                               sizeof(ULONG));\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetDsmLBPolicyInRegistry: Failed to set LB policy in registry. Status %x.\\n\",\r\n                        status));\r\n\r\n            goto __Exit_DsmpSetDsmLBPolicyInRegistry;\r\n        }\r\n\r\n        status = ZwSetValueKey(parametersKey,\r\n                               &preferredPathValueName,\r\n                               0,\r\n                               REG_BINARY,\r\n                               &PreferredPath,\r\n                               sizeof(ULONGLONG));\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetDsmLBPolicyInRegistry: Failed to set preferred path in registry. Status %x.\\n\",\r\n                        status));\r\n        }\r\n    }\r\n\r\n__Exit_DsmpSetDsmLBPolicyInRegistry:\r\n\r\n    if (parametersKey) {\r\n        ZwClose(parametersKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetDsmLBPolicyInRegistry: Exiting function with status %x.\\n\",\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetVidPidLBPolicyInRegistry(\r\n    _In_ IN PWSTR TargetHardwareId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _In_ IN ULONGLONG PreferredPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Set the default load balance policy for MSDSM controlled devices for\r\n    a particular target VID/PID in the registry.\r\n    Note: If the policy specified is 0, remove the subkey that matches\r\n          the passed in TargetHardwareId.\r\n\r\nArguements:\r\n\r\n    TargetHardwareId - The VID/PID for which a default LB policy is being set.\r\n    LoadBalanceType - Type of LB policy.\r\n    PreferredPath - The preferred path for devices controlled by DSM.\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully set the info in the registry.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE targetsLBSettingKey = NULL;\r\n    HANDLE targetSubKey = NULL;\r\n    NTSTATUS status;\r\n    UNICODE_STRING vidPidKeyName;\r\n    UNICODE_STRING lbPolicyValueName;\r\n    UNICODE_STRING preferredPathValueName;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetVidPidLBPolicyInRegistry (%ws): Entering function.\\n\",\r\n                TargetHardwareId));\r\n\r\n    //\r\n    // First open the DsmTargetsLoadBalanceSetting key under the service's parameters key.\r\n    //\r\n    status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to open Targets Policy settings key. Status %x.\\n\",\r\n                    TargetHardwareId,\r\n                    status));\r\n\r\n        goto __Exit_DsmpSetVidPidLBPolicyInRegistry;\r\n    }\r\n\r\n    RtlInitUnicodeString(&vidPidKeyName, TargetHardwareId);\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &vidPidKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               targetsLBSettingKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    //\r\n    // If the LB policy is specified as 0, we need to delete the values.\r\n    //\r\n    if (LoadBalanceType < DSM_LB_FAILOVER) {\r\n\r\n        //\r\n        // Open the VID/PID key under DsmTargetsLoadBalanceSetting key.\r\n        //\r\n        status = ZwOpenKey(&targetSubKey, KEY_ALL_ACCESS, &objectAttributes);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            status = ZwDeleteKey(targetSubKey);\r\n        }\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to either open or delete. Status %x.\\n\",\r\n                        TargetHardwareId,\r\n                        status));\r\n        }\r\n    } else {\r\n\r\n        RtlInitUnicodeString(&lbPolicyValueName, DSM_LOAD_BALANCE_POLICY);\r\n        RtlInitUnicodeString(&preferredPathValueName, DSM_PREFERRED_PATH);\r\n\r\n        status = ZwCreateKey(&targetSubKey,\r\n                             KEY_ALL_ACCESS,\r\n                             &objectAttributes,\r\n                             0,\r\n                             NULL,\r\n                             REG_OPTION_NON_VOLATILE,\r\n                             NULL);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to open/create key in registry. Status %x.\\n\",\r\n                        TargetHardwareId,\r\n                        status));\r\n\r\n            goto __Exit_DsmpSetVidPidLBPolicyInRegistry;\r\n        }\r\n\r\n        status = ZwSetValueKey(targetSubKey,\r\n                               &lbPolicyValueName,\r\n                               0,\r\n                               REG_DWORD,\r\n                               &LoadBalanceType,\r\n                               sizeof(ULONG));\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to set LB policy in registry. Status %x.\\n\",\r\n                        TargetHardwareId,\r\n                        status));\r\n\r\n            goto __Exit_DsmpSetVidPidLBPolicyInRegistry;\r\n        }\r\n\r\n        status = ZwSetValueKey(targetSubKey,\r\n                               &preferredPathValueName,\r\n                               0,\r\n                               REG_BINARY,\r\n                               &PreferredPath,\r\n                               sizeof(ULONGLONG));\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpSetVidPidLBPolicyInRegistry (%ws): Failed to set preferred path in registry. Status %x.\\n\",\r\n                        TargetHardwareId,\r\n                        status));\r\n        }\r\n    }\r\n\r\n__Exit_DsmpSetVidPidLBPolicyInRegistry:\r\n\r\n    if (targetSubKey) {\r\n        ZwClose(targetSubKey);\r\n    }\r\n\r\n    if (targetsLBSettingKey) {\r\n        ZwClose(targetsLBSettingKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpSetVidPidLBPolicyInRegistry (%ws): Exiting function with status %x.\\n\",\r\n                TargetHardwareId,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpOpenLoadBalanceSettingsKey(\r\n    _In_ IN  ACCESS_MASK    AccessMask,\r\n    _Out_ OUT PHANDLE LoadBalanceSettingsKey\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Open the device key in the registry.\r\n\r\n    NOTE: It is the responsibility of the caller to close the returned handle.\r\n\r\nArguements:\r\n\r\n    AccessMask - Requested access with which to open key\r\n    LoadBalanceSettingsKey - handle of the key that is returned to the caller\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully open the registry key.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE serviceKey = NULL;\r\n    HANDLE parametersKey = NULL;\r\n    PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath);\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    UNICODE_STRING parametersKeyName;\r\n    UNICODE_STRING subKeyName;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Entering function.\\n\",\r\n                registryPath));\r\n\r\n    *LoadBalanceSettingsKey = NULL;\r\n\r\n    //\r\n    // First check if registry path is available for msdsm.\r\n    //\r\n    if (!registryPath->Buffer) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Registry Path not set.\\n\",\r\n                    registryPath));\r\n\r\n        goto __Exit_DsmpOpenLoadBalanceSettingsKey;\r\n    }\r\n\r\n    //\r\n    // Open the service key first\r\n    //\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               registryPath,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               NULL,\r\n                               NULL);\r\n\r\n    status = ZwOpenKey(&serviceKey,\r\n                       AccessMask,\r\n                       &objectAttributes);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Open Parameters key under the Service key\r\n        //\r\n        RtlInitUnicodeString(&parametersKeyName, DSM_SERVICE_PARAMETERS);\r\n\r\n        RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &parametersKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   serviceKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        status = ZwOpenKey(&parametersKey,\r\n                           AccessMask,\r\n                           &objectAttributes);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // Open LoadBalanceSettings key under the Parameters key\r\n            //\r\n            RtlInitUnicodeString(&subKeyName, DSM_LOAD_BALANCE_SETTINGS);\r\n\r\n            RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n            InitializeObjectAttributes(&objectAttributes,\r\n                                       &subKeyName,\r\n                                       (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                       parametersKey,\r\n                                       (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n            status = ZwCreateKey(LoadBalanceSettingsKey,\r\n                                 AccessMask,\r\n                                 &objectAttributes,\r\n                                 0,\r\n                                 NULL,\r\n                                 REG_OPTION_NON_VOLATILE,\r\n                                 NULL);\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open/create LBSettings key. Status %x.\\n\",\r\n                            registryPath,\r\n                            status));\r\n\r\n                *LoadBalanceSettingsKey = NULL;\r\n            }\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open parameters key. Status %x.\\n\",\r\n                        registryPath,\r\n                        status));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Failed to open service key %ws. Status %x.\\n\",\r\n                    registryPath,\r\n                    registryPath->Buffer,\r\n                    status));\r\n    }\r\n\r\n__Exit_DsmpOpenLoadBalanceSettingsKey:\r\n\r\n    if (parametersKey) {\r\n        ZwClose(parametersKey);\r\n    }\r\n\r\n    if (serviceKey) {\r\n        ZwClose(serviceKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenLoadBalanceSettingsKey (RegPath %p): Exiting function with status %x.\\n\",\r\n                registryPath,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpOpenTargetsLoadBalanceSettingKey(\r\n    _In_ IN  ACCESS_MASK    AccessMask,\r\n    _Out_ OUT PHANDLE TargetsLoadBalanceSettingKey\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Open the target key in the registry.\r\n\r\n    NOTE: It is the responsibility of the caller to close the returned handle.\r\n\r\nArguements:\r\n\r\n    AccessMask - Requested access with which to open key\r\n    LoadBalanceSettingsKey - handle of the key that is returned to the caller\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully open the registry key.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE serviceKey = NULL;\r\n    HANDLE parametersKey = NULL;\r\n    PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath);\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    UNICODE_STRING parametersKeyName;\r\n    UNICODE_STRING subKeyName;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Entering function.\\n\",\r\n                registryPath));\r\n\r\n    if (!TargetsLoadBalanceSettingKey) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Invalid parameter.\\n\",\r\n                    registryPath));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpOpenTargetsLoadBalanceSettingKey;\r\n    }\r\n\r\n    *TargetsLoadBalanceSettingKey = NULL;\r\n\r\n    //\r\n    // First check if registry path is available for msdsm.\r\n    //\r\n    if (!registryPath->Buffer) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Registry Path not set.\\n\",\r\n                    registryPath));\r\n\r\n        goto __Exit_DsmpOpenTargetsLoadBalanceSettingKey;\r\n    }\r\n\r\n    //\r\n    // Open the service key first\r\n    //\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               registryPath,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               NULL,\r\n                               NULL);\r\n\r\n    status = ZwOpenKey(&serviceKey,\r\n                       AccessMask,\r\n                       &objectAttributes);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Open Parameters key under the Service key\r\n        //\r\n        RtlInitUnicodeString(&parametersKeyName, DSM_SERVICE_PARAMETERS);\r\n\r\n        RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &parametersKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   serviceKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        status = ZwOpenKey(&parametersKey,\r\n                           AccessMask,\r\n                           &objectAttributes);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // Open LoadBalanceSettings key under the Parameters key\r\n            //\r\n            RtlInitUnicodeString(&subKeyName, DSM_TARGETS_LOAD_BALANCE_SETTING);\r\n\r\n            RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n            InitializeObjectAttributes(&objectAttributes,\r\n                                       &subKeyName,\r\n                                       (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                       parametersKey,\r\n                                       (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n            status = ZwCreateKey(TargetsLoadBalanceSettingKey,\r\n                                 AccessMask,\r\n                                 &objectAttributes,\r\n                                 0,\r\n                                 NULL,\r\n                                 REG_OPTION_NON_VOLATILE,\r\n                                 NULL);\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open/create TargetsLBSetting key. Status %x.\\n\",\r\n                            registryPath,\r\n                            status));\r\n\r\n                *TargetsLoadBalanceSettingKey = NULL;\r\n            }\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open parameters key. Status %x.\\n\",\r\n                        registryPath,\r\n                        status));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Failed to open service key %ws. Status %x.\\n\",\r\n                    registryPath,\r\n                    registryPath->Buffer,\r\n                    status));\r\n    }\r\n\r\n__Exit_DsmpOpenTargetsLoadBalanceSettingKey:\r\n\r\n    if (parametersKey) {\r\n        ZwClose(parametersKey);\r\n    }\r\n\r\n    if (serviceKey) {\r\n        ZwClose(serviceKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenTargetsLoadBalanceSettingKey (RegPath %p): Exiting function with status %x.\\n\",\r\n                registryPath,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpOpenDsmServicesParametersKey(\r\n    _In_ IN  ACCESS_MASK AccessMask,\r\n    _Out_ OUT PHANDLE ParametersKey\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Open the DSM's Parameters key in the registry.\r\n\r\n    NOTE: It is the responsibility of the caller to close the returned handle.\r\n\r\nArguements:\r\n\r\n    AccessMask - Requested access with which to open key\r\n    ParametersKey - handle of the key that is returned to the caller\r\n\r\nReturn Value :\r\n\r\n    STATUS_SUCCESS if we were able to successfully open the registry key.\r\n\r\n    Appropriate NTSTATUS code on failure\r\n\r\n--*/\r\n{\r\n    HANDLE serviceKey = NULL;\r\n    PUNICODE_STRING registryPath = &(gDsmInitData.DsmWmiInfo.RegistryPath);\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    UNICODE_STRING parametersKeyName;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenDsmServicesParametersKey (RegPath %p): Entering function.\\n\",\r\n                registryPath));\r\n\r\n    if (!ParametersKey) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenDsmServicesParametersKey (RegPath %p): Invalid parameter.\\n\",\r\n                    registryPath));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpOpenDsmServicesParametersKey;\r\n    }\r\n\r\n    *ParametersKey = NULL;\r\n\r\n    //\r\n    // First check if registry path is available for msdsm.\r\n    //\r\n    if (!registryPath->Buffer) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenDsmServicesParametersKey (RegPath %p): Registry Path not set.\\n\",\r\n                    registryPath));\r\n\r\n        goto __Exit_DsmpOpenDsmServicesParametersKey;\r\n    }\r\n\r\n    //\r\n    // Open the service key first\r\n    //\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               registryPath,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               NULL,\r\n                               NULL);\r\n\r\n    status = ZwOpenKey(&serviceKey,\r\n                       AccessMask,\r\n                       &objectAttributes);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Open Parameters key under the Service key\r\n        //\r\n        RtlInitUnicodeString(&parametersKeyName, DSM_SERVICE_PARAMETERS);\r\n\r\n        RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &parametersKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   serviceKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        status = ZwOpenKey(ParametersKey,\r\n                           AccessMask,\r\n                           &objectAttributes);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpOpenDsmServicesParametersKey (RegPath %p): Failed to open parameters key. Status %x.\\n\",\r\n                        registryPath,\r\n                        status));\r\n\r\n            *ParametersKey = NULL;\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpOpenDsmServicesParametersKey (RegPath %p): Failed to open service key %ws. Status %x.\\n\",\r\n                    registryPath,\r\n                    registryPath->Buffer,\r\n                    status));\r\n    }\r\n\r\n__Exit_DsmpOpenDsmServicesParametersKey:\r\n\r\n    if (serviceKey) {\r\n        ZwClose(serviceKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpOpenDsmServicesParametersKey (RegPath %p): Exiting function with status %x.\\n\",\r\n                registryPath,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nDsmpReportTargetPortGroupsSyncCompletion(\r\n    IN PDEVICE_OBJECT DeviceObject,\r\n    IN PIRP Irp,\r\n    IN PVOID Context\r\n    )\r\n{\r\n    UNREFERENCED_PARAMETER(DeviceObject);\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpReportTargetPortGroupsSyncCompletion: IRP %p, Context %p\\n\",\r\n                Irp, Context));\r\n\r\n    KeSetEvent(Irp->UserEvent, 0, FALSE);\r\n\r\n    return STATUS_MORE_PROCESSING_REQUIRED;\r\n}\r\n\r\n_Success_(return==0)\r\nNTSTATUS\r\nDsmpReportTargetPortGroups(\r\n    _In_ PDEVICE_OBJECT DeviceObject,\r\n    _Outptr_result_buffer_maybenull_(*TargetPortGroupsInfoLength) PUCHAR *TargetPortGroupsInfo,\r\n    _Out_ PULONG TargetPortGroupsInfoLength\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send down ReportTargetPortGroups request synchronously.\r\n    Used if device supports ALUA.\r\n\r\n    Note: This routine will allocate memory for the TPG info. It is the\r\n    responsibility of the caller to free this buffer, but only if the function\r\n    returns STATUS_SUCCESS.\r\n\r\nArguments:\r\n\r\n    DeviceObject - The port PDO to which the command should be sent.\r\n    TargetPortGroupsInfo - buffer containing the returned data.\r\n    TargetPortGroupsInfoLength - size of the returned buffer.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PSPC3_CDB_REPORT_TARGET_PORT_GROUPS cdb;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PIRP irp = NULL;\r\n    PMDL mdl = NULL;\r\n    PSCSI_REQUEST_BLOCK srb = NULL;\r\n    PSENSE_DATA_EX senseInfoBuffer = NULL;\r\n    UCHAR senseInfoBufferLength = 0;\r\n    KEVENT completionEvent;\r\n    ULONG targetPortGroupsInfoLength = 0;\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    PIO_STACK_LOCATION irpStack = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpReportTargetPortGroups (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    if (TargetPortGroupsInfoLength == NULL ||\r\n        TargetPortGroupsInfo == NULL) {\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpReportTargetPortGroups;\r\n    }\r\n\r\n    *TargetPortGroupsInfoLength = 0;\r\n    *TargetPortGroupsInfo = NULL;\r\n\r\n    senseInfoBuffer = (PSENSE_DATA_EX)DsmpAllocatePool(NonPagedPoolNx,\r\n                                                       SENSE_BUFFER_SIZE_EX,\r\n                                                       DSM_TAG_SCSI_SENSE_INFO);\r\n    if (senseInfoBuffer != NULL) {\r\n\r\n        senseInfoBufferLength = SENSE_BUFFER_SIZE_EX;\r\n\r\n        srb = (PSCSI_REQUEST_BLOCK)DsmpAllocatePool(NonPagedPoolNx,\r\n                                                    sizeof(SCSI_REQUEST_BLOCK),\r\n                                                    DSM_TAG_SCSI_REQUEST_BLOCK);\r\n        if (srb != NULL) {\r\n\r\n            SrbSetSenseInfoBufferLength(srb, senseInfoBufferLength);\r\n            SrbSetSenseInfoBuffer(srb, senseInfoBuffer);\r\n\r\n            //\r\n            // Take care of worst case scenario, which is:\r\n            // 1. 4-byte header (for allocation length)\r\n            // 2. 32 8-byte descriptors (for TPGs)\r\n            // 3. Each descriptor containing 32 4-byte identifiers (for TPs in each TPG)\r\n            //\r\n            targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                         (DSM_MAX_PATHS * (sizeof(SPC3_REPORT_TARGET_PORT_GROUP_DESCRIPTOR) +\r\n                                                           DSM_MAX_PATHS * sizeof(ULONG)));\r\n\r\n            targetPortGroupsInfo = (PUCHAR)DsmpAllocatePool(NonPagedPoolNx,\r\n                                                            targetPortGroupsInfoLength,\r\n                                                            DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n            if (targetPortGroupsInfo == NULL) {\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpReportTargetPortGroups (DevObj %p): Failed to allocate TPG info.\\n\",\r\n                            DeviceObject));\r\n                goto __Exit_DsmpReportTargetPortGroups;\r\n            }\r\n\r\n        } else {\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpReportTargetPortGroups (DevObj %p): Failed to allocate SRB.\\n\",\r\n                    DeviceObject));\r\n            goto __Exit_DsmpReportTargetPortGroups;\r\n        }\r\n\r\n    } else {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpReportTargetPortGroups (DevObj %p): Failed to allocate Sense Info Buffer.\\n\",\r\n                    DeviceObject));\r\n        goto __Exit_DsmpReportTargetPortGroups;\r\n    }\r\n\r\n    irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE);\r\n    if (irp == NULL) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpReportTargetPortGroups (DevObj %p): Failed to allocate IRP.\\n\",\r\n                    DeviceObject));\r\n        goto __Exit_DsmpReportTargetPortGroups;\r\n    }\r\n\r\n    mdl = IoAllocateMdl(targetPortGroupsInfo,\r\n                        targetPortGroupsInfoLength,\r\n                        FALSE,\r\n                        FALSE,\r\n                        irp);\r\n\r\n    if (mdl == NULL) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpReportTargetPortGroups (DevObj %p): Failed to allocate MDL.\\n\",\r\n                DeviceObject));\r\n        goto __Exit_DsmpReportTargetPortGroups;\r\n    }\r\n\r\n    MmBuildMdlForNonPagedPool(mdl);\r\n\r\n__Retry_DsmpReportTargetPortGroups:\r\n\r\n    irp->MdlAddress = mdl;\r\n\r\n    //\r\n    // Set up SRB for execute scsi request. Save SRB address in next stack\r\n    // for the port driver.\r\n    //\r\n    irpStack = IoGetNextIrpStackLocation(irp);\r\n    irpStack->MajorFunction = IRP_MJ_SCSI;\r\n    irpStack->MinorFunction = IRP_MN_SCSI_CLASS;\r\n    irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srb;\r\n    irpStack->DeviceObject = DeviceObject;\r\n\r\n    //\r\n    // Set the completion event and the completion routine.\r\n    //\r\n    KeInitializeEvent(&completionEvent, NotificationEvent, FALSE);\r\n    irp->UserEvent = &completionEvent;\r\n    IoSetCompletionRoutine(irp,\r\n                           DsmpReportTargetPortGroupsSyncCompletion,\r\n                           srb,\r\n                           TRUE,\r\n                           TRUE,\r\n                           TRUE);\r\n\r\n    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;\r\n    srb->Length = sizeof(SCSI_REQUEST_BLOCK);\r\n\r\n    SrbSetCdbLength(srb, sizeof(SPC3_CDB_REPORT_TARGET_PORT_GROUPS));\r\n    cdb = (PSPC3_CDB_REPORT_TARGET_PORT_GROUPS)SrbGetCdb(srb);\r\n    cdb->OperationCode = SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS;\r\n    cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS;\r\n    REVERSE_BYTES(&(cdb->AllocationLength), &targetPortGroupsInfoLength);\r\n\r\n    SrbSetTimeOutValue(srb, SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT);\r\n    SrbSetDataTransferLength(srb, targetPortGroupsInfoLength);\r\n    SrbSetDataBuffer(srb, targetPortGroupsInfo);\r\n    srb->SrbStatus = 0;\r\n    SrbSetScsiStatus(srb, 0);\r\n    SrbSetNextSrb(srb, NULL);\r\n    SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE |\r\n                        SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER |\r\n                        SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE);\r\n    SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST);\r\n    SrbSetOriginalRequest(srb, irp);\r\n\r\n    ObReferenceObject(DeviceObject);\r\n\r\n    //\r\n    // Finally, send the IRP down and wait for its completion.\r\n    //\r\n    status = IoCallDriver(DeviceObject, irp);\r\n\r\n    if (status == STATUS_PENDING) {\r\n        KeWaitForSingleObject(&completionEvent,\r\n                              Executive,\r\n                              KernelMode,\r\n                              FALSE,\r\n                              NULL);\r\n        status = irp->IoStatus.Status;\r\n    }\r\n\r\n    ObDereferenceObject(DeviceObject);\r\n\r\n    if ((status == STATUS_BUFFER_OVERFLOW) ||\r\n        (NT_SUCCESS(status) && (SrbGetScsiStatus(srb) == SCSISTAT_GOOD))) {\r\n\r\n        //\r\n        // The first 4 bytes of the returned data are the Returned Data Length\r\n        // field of the RTPG header.\r\n        //\r\n        ULONG returnedDataLength = 0;\r\n        REVERSE_BYTES(&returnedDataLength, targetPortGroupsInfo);\r\n\r\n        status = STATUS_SUCCESS;\r\n        if (returnedDataLength > SrbGetDataTransferLength(srb)) {\r\n\r\n            status = STATUS_BUFFER_OVERFLOW;\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status) && SrbGetScsiStatus(srb) == SCSISTAT_GOOD) {\r\n\r\n        //\r\n        // RTPG was successful so return the TPG info to the caller.\r\n        //\r\n\r\n        //\r\n        // The first 4 bytes of the returned data are the Returned Data Length\r\n        // field of the RTPG header.  We need to return this value plus the header size.\r\n        //\r\n        ULONG returnedDataLength = 0;\r\n        REVERSE_BYTES(&returnedDataLength, targetPortGroupsInfo);\r\n        *TargetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE + returnedDataLength;\r\n\r\n        *TargetPortGroupsInfo = targetPortGroupsInfo;\r\n\r\n    } else if (SrbGetScsiStatus(srb) == SCSISTAT_CHECK_CONDITION) {\r\n\r\n        if (DsmpShouldRetryTPGRequest(senseInfoBuffer, senseInfoBufferLength)) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpReportTargetPortGroups (DevObj %p): Retrying request.\\n\",\r\n                        DeviceObject));\r\n\r\n            IoReuseIrp(irp, STATUS_SUCCESS);\r\n\r\n            RtlZeroMemory(senseInfoBuffer, senseInfoBufferLength);\r\n\r\n            goto __Retry_DsmpReportTargetPortGroups;\r\n        }\r\n\r\n        if (DsmpIsDeviceRemoved(senseInfoBuffer, senseInfoBufferLength)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpReportTargetPortGroups (DevObj %p): Device not available.\\n\",\r\n                        DeviceObject));\r\n\r\n            //\r\n            // Sense key was illegal request. SPC 6.25 says response to TPG should follow Test Unit Ready responses\r\n            //\r\n            status = STATUS_NO_SUCH_DEVICE;\r\n\r\n        }\r\n\r\n        // RTPG was unsuccessful\r\n        // Here it is possible that status is success, but scsi status is not.\r\n        // and there was no RTPG retry. If so, set status to unsuccessful.\r\n        if (NT_SUCCESS(status)) {\r\n            status = STATUS_UNSUCCESSFUL;\r\n        }\r\n\r\n        //\r\n        // TPG resulted HW to respond with Check Condition but Sense Key indicates it is not for retry or illegal request\r\n        //\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpReportTargetPortGroups (DevObj %p): TPG returned Check Condition, NTStatus 0x%x, ScsiStatus 0x%x.\\n\",\r\n                    DeviceObject,\r\n                    status,\r\n                    SrbGetScsiStatus(srb)));\r\n    } else {\r\n\r\n        // RTPG was unsuccessful\r\n        // Here it is possible that status is success, but scsi status is not.\r\n        // If so, set status to unsuccessful.\r\n        if (NT_SUCCESS(status)) {\r\n            status = STATUS_UNSUCCESSFUL;\r\n        }\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpReportTargetPortGroups (DevObj %p): NTStatus 0x%x, ScsiStatus 0x%x.\\n\",\r\n                    DeviceObject,\r\n                    status,\r\n                    SrbGetScsiStatus(srb)));\r\n    }\r\n\r\n__Exit_DsmpReportTargetPortGroups:\r\n\r\n    //\r\n    // The port driver may have allocated its own sense buffer so we need to\r\n    // make sure we free that here.\r\n    //\r\n    if (srb != NULL &&\r\n        SrbGetSrbFlags(srb) & SRB_FLAGS_PORT_DRIVER_ALLOCSENSE &&\r\n        SrbGetSrbFlags(srb) & SRB_FLAGS_FREE_SENSE_BUFFER &&\r\n        SrbGetSenseInfoBuffer(srb) != NULL) {\r\n        DsmpFreePool(SrbGetSenseInfoBuffer(srb));\r\n    }\r\n\r\n    if (senseInfoBuffer) {\r\n        DsmpFreePool(senseInfoBuffer);\r\n    }\r\n\r\n    if (srb) {\r\n        DsmpFreePool(srb);\r\n    }\r\n\r\n    if (irp) {\r\n        if (irp->MdlAddress) {\r\n            IoFreeMdl(irp->MdlAddress);\r\n        }\r\n        IoFreeIrp(irp);\r\n    }\r\n\r\n    if (!NT_SUCCESS(status) && targetPortGroupsInfo) {\r\n        DsmpFreePool(targetPortGroupsInfo);\r\n        *TargetPortGroupsInfoLength = 0;\r\n        *TargetPortGroupsInfo = NULL;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpReportTargetPortGroups (DevObj %p): Exiting function with status %x.\\n\",\r\n                DeviceObject,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nDsmpReportTargetPortGroupsAsync(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine,\r\n    _Inout_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength,\r\n    _Inout_ __drv_aliasesMem IN OUT PUCHAR TargetPortGroupsInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send down ReportTargetPortGroups request asynchronously.\r\n    Used if device supports ALUA.\r\n\r\n    NOTE: Caller needs to free Irp, system buffer, and passThrough buffer.\r\n\r\nArguments:\r\n\r\n    DeviceInfo - The deviceInfo whose corresponding port PDO the command should be sent to.\r\n    CompletionRoutine - completion routine passed in by the caller.\r\n    CompletionContext - context to be passed to be completion routine.\r\n    TargetPortGroupsInfoLength - size of the returned buffer.\r\n    TargetPortGroupsInfo - preallocated (by caller) buffer that'll contain the returned data.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = CompletionContext;\r\n    PSCSI_REQUEST_BLOCK srb = NULL;\r\n    PSPC3_CDB_REPORT_TARGET_PORT_GROUPS cdb;\r\n    NTSTATUS status;\r\n    PIRP irp = NULL;\r\n    PIO_STACK_LOCATION irpStack;\r\n    PMDL mdl = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpReportTargetPortGroupsAsync (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    srb = tpgCompletionContext->Srb;\r\n\r\n    SrbZeroSrb(srb);\r\n\r\n    //\r\n    // Allocate an irp.\r\n    //\r\n    irp = IoAllocateIrp(DeviceInfo->TargetObject->StackSize + 1, FALSE);\r\n    if (!irp) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpReportTargetPortGroupsAsync (DevInfo %p): Failed to allocate IRP.\\n\",\r\n                    DeviceInfo));\r\n        goto __Exit_DsmpReportTargetPortGroupsAsync;\r\n    }\r\n\r\n    mdl = IoAllocateMdl(TargetPortGroupsInfo,\r\n                        TargetPortGroupsInfoLength,\r\n                        FALSE,\r\n                        FALSE,\r\n                        irp);\r\n    if (!mdl) {\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpReportTargetPortGroupsAsync (DevInfo %p): Failed to allocate MDL.\\n\",\r\n                    DeviceInfo));\r\n        goto __Exit_DsmpReportTargetPortGroupsAsync;\r\n    }\r\n\r\n    MmBuildMdlForNonPagedPool(irp->MdlAddress);\r\n\r\n    //\r\n    // It is possible that if an implicit access state transition took place,\r\n    // each I_T nexus will return UA for asymmetric access state changed. So\r\n    // set the number of retries to be one more than the total number of paths.\r\n    // Worst case scenario is the it is sent down each path once (assuming every\r\n    // is a different I_T nexus) and then one more for a retry one one of the\r\n    // paths.\r\n    //\r\n    tpgCompletionContext->NumberRetries = DeviceInfo->Group->NumberDevices + 1;\r\n\r\n    //\r\n    // Set-up the completion routine.\r\n    //\r\n    IoSetCompletionRoutine(irp,\r\n                           CompletionRoutine,\r\n                           (PVOID)CompletionContext,\r\n                           TRUE,\r\n                           TRUE,\r\n                           TRUE);\r\n\r\n    //\r\n    // Get the recipient's irpstack location.\r\n    //\r\n    irpStack = IoGetNextIrpStackLocation(irp);\r\n\r\n    irpStack->Parameters.Scsi.Srb = srb;\r\n    irpStack->DeviceObject = DeviceInfo->TargetObject;\r\n\r\n    //\r\n    // Set the major function code to IRP_MJ_SCSI.\r\n    //\r\n    irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;\r\n\r\n    //\r\n    // Set the minor function, or many requests will get kicked by by port.\r\n    //\r\n    irpStack->MinorFunction = IRP_MN_SCSI_CLASS;\r\n\r\n    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;\r\n    srb->Length = sizeof(SCSI_REQUEST_BLOCK);\r\n\r\n    SrbSetCdbLength(srb, sizeof(SPC3_CDB_REPORT_TARGET_PORT_GROUPS));\r\n    cdb = (PSPC3_CDB_REPORT_TARGET_PORT_GROUPS)SrbGetCdb(srb);\r\n    cdb->OperationCode = SPC3_SCSIOP_REPORT_TARGET_PORT_GROUPS;\r\n    cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS;\r\n    Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->AllocationLength);\r\n\r\n    SrbSetTimeOutValue(srb, SPC3_REPORT_TARGET_PORT_GROUPS_TIMEOUT);\r\n    SrbSetSenseInfoBuffer(srb, tpgCompletionContext->SenseInfoBuffer);\r\n    SrbSetSenseInfoBufferLength(srb, tpgCompletionContext->SenseInfoBufferLength);\r\n    SrbSetDataTransferLength(srb, TargetPortGroupsInfoLength);\r\n    SrbSetDataBuffer(srb, TargetPortGroupsInfo);\r\n    srb->SrbStatus = 0;\r\n    SrbSetScsiStatus(srb, 0);\r\n    SrbSetNextSrb(srb, NULL);\r\n    SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE |\r\n                        SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER |\r\n                        SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE);\r\n    SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST);\r\n    SrbSetOriginalRequest(srb, irp);\r\n\r\n    irp->UserBuffer = TargetPortGroupsInfo;\r\n    irp->Tail.Overlay.Thread = PsGetCurrentThread();\r\n\r\n    //\r\n    // Send the IRP asynchronously\r\n    //\r\n    DsmSendRequestEx(((PDSM_CONTEXT)(DeviceInfo->DsmContext))->MPIOContext,\r\n                     DeviceInfo->TargetObject,\r\n                     irp,\r\n                     (PVOID)DeviceInfo,\r\n                     DSM_CALL_COMPLETION_ON_MPIO_ERROR);\r\n\r\n    //\r\n    // We know that the completion routine will always be called.\r\n    //\r\n    status = STATUS_PENDING;\r\n\r\n__Exit_DsmpReportTargetPortGroupsAsync:\r\n\r\n    if (status != STATUS_PENDING) {\r\n\r\n        //\r\n        // This indicates Irp was never sent down to stack (completion routine was never called).\r\n        // We need to clean up.\r\n        //\r\n        if (irp) {\r\n\r\n            if (irp->MdlAddress) {\r\n                IoFreeMdl(irp->MdlAddress);\r\n            }\r\n\r\n            IoFreeIrp(irp);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpReportTargetPortGroupsAsync (DevInfo %p): Exiting function with status %x\\n.\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryLBPolicyForDevice(\r\n    _In_ IN PWSTR RegistryKeyName,\r\n    _In_ IN  ULONGLONG PathId,\r\n    _In_ IN DSM_LOAD_BALANCE_TYPE LoadBalanceType,\r\n    _Out_ OUT PULONG PrimaryPath,\r\n    _Out_ OUT PULONG OptimizedPath,\r\n    _Out_ OUT PULONG PathWeight\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine opens the device's registry subkey, builds the path subkey from\r\n    the passed in PathId, then queries that subkey for the value of PrimaryPath,\r\n    OptimizedPath and PathWeight.\r\n\r\nArguments:\r\n\r\n    RegistryKeyName - The device's registry subkey name.\r\n    PathId - The pathId for this instance of the device.\r\n    LoadBalanceType - The current load balance policy.\r\n    PrimaryPath - Output of the queried PrimaryPath value.\r\n    OptimizedPath - Output of the queried OptimizedPath value.\r\n    PathWeight - Output of the queried PathWeight value.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    HANDLE lbSettingsKey = NULL;\r\n    HANDLE deviceKey = NULL;\r\n    HANDLE dsmPathKey = NULL;\r\n    UNICODE_STRING subKeyName;\r\n    WCHAR dsmPathName[128] = {0};\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    NTSTATUS status;\r\n    NTSTATUS pathWeightQueryStatus = STATUS_SUCCESS;\r\n\r\n    PAGED_CODE();\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryLBPolicyForDevice (DevName %ws): Entering function.\\n\",\r\n                RegistryKeyName));\r\n\r\n    //\r\n    // Query PrimaryPath and PathWeight for the given path.\r\n    // These values are stored under DsmPath#Suffix key for\r\n    // this path. If this key doesn't exist create it and\r\n    // create PrimaryPath and PathWeight values - use the\r\n    // values passed in PrimaryPath and PathWeight in this case.\r\n    //\r\n    status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to open LB Settings key. Status %x.\\n\",\r\n                    RegistryKeyName,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryLBPolicyForDevice;\r\n    }\r\n\r\n    RtlInitUnicodeString(&subKeyName, RegistryKeyName);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &subKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               lbSettingsKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Create or open DsmPath#Suffix key for this path\r\n        //\r\n        DsmpGetDSMPathKeyName(PathId, dsmPathName, 128);\r\n\r\n        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryLBPolicyForDevice (DevName %ws): Will query %ws for PrimaryPath, OptimizedPath and PathWeight.\\n\",\r\n                    RegistryKeyName,\r\n                    dsmPathName));\r\n\r\n        RtlInitUnicodeString(&subKeyName, dsmPathName);\r\n\r\n        RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &subKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   deviceKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        status = ZwCreateKey(&dsmPathKey,\r\n                             KEY_ALL_ACCESS,\r\n                             &objectAttributes,\r\n                             0,\r\n                             NULL,\r\n                             REG_OPTION_NON_VOLATILE,\r\n                             NULL);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n\r\n            //\r\n            // Query the Path Weight value.\r\n            //\r\n\r\n            RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n            queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                                  RTL_QUERY_REGISTRY_REQUIRED |\r\n                                  RTL_QUERY_REGISTRY_TYPECHECK;\r\n            queryTable[0].Name = DSM_PATH_WEIGHT;\r\n            queryTable[0].EntryContext = PathWeight;\r\n            queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n            pathWeightQueryStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                                           dsmPathKey,\r\n                                                           queryTable,\r\n                                                           dsmPathKey,\r\n                                                           NULL);\r\n\r\n            if (!NT_SUCCESS(pathWeightQueryStatus)) {\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query PathWeight. Status %x.\\n\",\r\n                            RegistryKeyName,\r\n                            pathWeightQueryStatus));\r\n            }\r\n\r\n            //\r\n            // Query the Primary Path value.\r\n            //\r\n\r\n            RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n            queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                                    RTL_QUERY_REGISTRY_REQUIRED |\r\n                                    RTL_QUERY_REGISTRY_TYPECHECK;\r\n            queryTable[0].Name = DSM_PRIMARY_PATH;\r\n            queryTable[0].EntryContext = PrimaryPath;\r\n            queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n            status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                            dsmPathKey,\r\n                                            queryTable,\r\n                                            dsmPathKey,\r\n                                            NULL);\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                //\r\n                // Query the Optimized Path value.\r\n                //\r\n\r\n                RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n                queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |\r\n                                        RTL_QUERY_REGISTRY_REQUIRED |\r\n                                        RTL_QUERY_REGISTRY_TYPECHECK;\r\n                queryTable[0].Name = DSM_OPTIMIZED_PATH;\r\n                queryTable[0].EntryContext = OptimizedPath;\r\n                queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n                status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                                dsmPathKey,\r\n                                                queryTable,\r\n                                                dsmPathKey,\r\n                                                NULL);\r\n                if (!NT_SUCCESS(status)) {\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query OptimizedPath. Status %x.\\n\",\r\n                                RegistryKeyName,\r\n                                status));\r\n                }\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to query PrimaryPath. Status %x.\\n\",\r\n                            RegistryKeyName,\r\n                            status));\r\n            }\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to create DSM Path key %ws. Status %x.\\n\",\r\n                        RegistryKeyName,\r\n                        dsmPathName,\r\n                        status));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryLBPolicyForDevice (DevName %ws): Failed to open key. Status %x.\\n\",\r\n                    RegistryKeyName,\r\n                    status));\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpQueryLBPolicyForDevice (DevName %ws): PrimaryPath %d, OptmizedPath %d, PathWeight %d.\\n\",\r\n                    RegistryKeyName,\r\n                    *PrimaryPath,\r\n                    *OptimizedPath,\r\n                    *PathWeight));\r\n    }\r\n\r\n__Exit_DsmpQueryLBPolicyForDevice:\r\n\r\n    if (dsmPathKey) {\r\n        ZwClose(dsmPathKey);\r\n    }\r\n\r\n    if (deviceKey) {\r\n        ZwClose(deviceKey);\r\n    }\r\n\r\n    if (lbSettingsKey) {\r\n        ZwClose(lbSettingsKey);\r\n    }\r\n\r\n    //\r\n    // If the load balance policy is Weighted Paths and we failed to read in\r\n    // the path weight value, we need to return the failure status from the\r\n    // path weight value query.\r\n    //\r\n    if (LoadBalanceType == DSM_LB_WEIGHTED_PATHS && !NT_SUCCESS(pathWeightQueryStatus)) {\r\n        status = pathWeightQueryStatus;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryLBPolicyForDevice (DevName %ws): Exiting function with status %x.\\n\",\r\n                RegistryKeyName,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmpGetDSMPathKeyName(\r\n    _In_ ULONGLONG DSMPathId,\r\n    _Out_writes_(DsmPathKeyNameSize) PWCHAR DsmPathKeyName,\r\n    _In_ ULONG  DsmPathKeyNameSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine builds the string that corresponds to the device's Path subkey\r\n    name in the registry.\r\n\r\nArguments:\r\n\r\n    DSMPathId - The pathId of this instance of the device.\r\n    DsmPathKeyName - Output buffer in which the subkey name for path is returned.\r\n    DsmPathKeyNameSize - size  of the output buffer in WCHARs.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PWCHAR pathPtr;\r\n    SIZE_T wcharsLeft;\r\n    SIZE_T size;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDSMPathKeyName (PathId %I64x): Entering function.\\n\",\r\n                DSMPathId));\r\n\r\n    //\r\n    // This routine will build a name for a given DSM Path.\r\n    // The name is of the format DsmPath#Suffix, where Suffix\r\n    // is derived from the PathId\r\n    //\r\n    pathPtr = DsmPathKeyName;\r\n\r\n    wcharsLeft = DsmPathKeyNameSize;\r\n\r\n    size = wcslen(DSM_PATH);\r\n\r\n    if (size < wcharsLeft) {\r\n\r\n        //\r\n        // First copy the string DsmPath#\r\n        //\r\n        if (NT_SUCCESS(RtlStringCchCopyNW(pathPtr, wcharsLeft, DSM_PATH, wcslen(DSM_PATH)))) {\r\n\r\n            wcharsLeft -= size;\r\n            pathPtr += size;\r\n\r\n            if (wcharsLeft > 2) {\r\n\r\n                RtlStringCchCatW(pathPtr, wcharsLeft, L\"#\");\r\n                wcharsLeft--;\r\n                pathPtr++;\r\n\r\n                //\r\n                // Each nibble in the path id would need 1 WCHAR\r\n                // upon conversion to WCHAR string. So we'll need\r\n                // 2 WCHARs for each byte. Include the NULL char also\r\n                //\r\n                size = (sizeof(PVOID) + 1) * 2;\r\n                if (size <= wcharsLeft) {\r\n\r\n                    PVOID pathId;\r\n                    PUCHAR pathIdPtr;\r\n                    ULONG inx;\r\n                    UCHAR tmpChar;\r\n\r\n                    //\r\n                    // Convert the ULONGLONG path id to a string and\r\n                    // append that to DsmPath#\r\n                    //\r\n                    pathId = (PVOID) DSMPathId;\r\n\r\n                    pathIdPtr = (PUCHAR) &pathId;\r\n\r\n                    for (inx = 0; inx < sizeof(PVOID); inx++) {\r\n\r\n                        tmpChar = (*pathIdPtr & 0xF0) >> 4;\r\n                        *pathPtr++ = DsmpGetAsciiForBinary(tmpChar);\r\n\r\n                        tmpChar = (*pathIdPtr & 0x0F);\r\n                        *pathPtr++ = DsmpGetAsciiForBinary(tmpChar);\r\n\r\n                        pathIdPtr++;\r\n                    }\r\n\r\n                    *pathPtr = WNULL;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDSMPathKeyName (PathId %I64x): Exiting function.\\n\",\r\n                DSMPathId));\r\n\r\n    return;\r\n}\r\n\r\n\r\nUCHAR\r\nDsmpGetAsciiForBinary(\r\n    _In_ UCHAR BinaryChar\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine converts the passed in binary value into ASCII equivalent.\r\n\r\nArguments:\r\n\r\n    BinaryChar - The binary value that needs to be converted.\r\n\r\nReturn Value:\r\n\r\n    Corresponding ASCII value.\r\n\r\n--*/\r\n{\r\n    UCHAR outChar = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetAsciiForBinary (BinaryChar %d): Entering function.\\n\",\r\n                BinaryChar));\r\n\r\n    //\r\n    // Convert a binary nibble into an ASCII character.\r\n    //\r\n    if ((BinaryChar >= 0) && (BinaryChar <= 9)) {\r\n        outChar = BinaryChar + '0';\r\n    } else {\r\n        outChar = BinaryChar + 'A' - 10;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetAsciiForBinary (BinaryChar %d): Exiting function with outChar %c.\\n\",\r\n                BinaryChar,\r\n                outChar));\r\n\r\n    return outChar;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpGetDeviceIdList(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _Out_ OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine will perform a query for the StorageDeviceIdProperty and will\r\n    allocate a non-paged buffer to store the data in.\r\n    IMPORTANT: It is the responsibility of the caller to ensure that this buffer is freed.\r\n\r\nArguments:\r\n\r\n    DeviceObject - the device to query\r\n    Descriptor - a location to store a pointer to the buffer we allocate\r\n\r\nReturn Value:\r\n\r\n    status.\r\n\r\n--*/\r\n{\r\n    STORAGE_PROPERTY_QUERY query;\r\n    PIO_STATUS_BLOCK ioStatus = NULL;\r\n    PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL;\r\n    ULONG length;\r\n    NTSTATUS status = STATUS_UNSUCCESSFUL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDeviceIdList (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    if (!DeviceObject) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n    //\r\n    // Poison the passed in descriptor.\r\n    //\r\n    *Descriptor = NULL;\r\n\r\n    //\r\n    // Setup the query buffer.\r\n    //\r\n    query.PropertyId = StorageDeviceIdProperty;\r\n    query.QueryType = PropertyStandardQuery;\r\n    query.AdditionalParameters[0] = 0;\r\n\r\n    ioStatus = DsmpAllocatePool(NonPagedPoolNx, sizeof(IO_STATUS_BLOCK), DSM_TAG_IO_STATUS_BLOCK);\r\n\r\n    if (!ioStatus) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetDeviceIdList (DevObj %p): Failed to allocate an IO_STATUS_BLOCK.\\n\",\r\n                    DeviceObject));\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n    ioStatus->Status = 0;\r\n    ioStatus->Information = 0;\r\n\r\n    //\r\n    // On the first call, just need to get the length of the descriptor.\r\n    //\r\n    descriptor = (PVOID)&query;\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY,\r\n                                      DeviceObject,\r\n                                      &query,\r\n                                      &query,\r\n                                      sizeof(STORAGE_PROPERTY_QUERY),\r\n                                      sizeof(STORAGE_DESCRIPTOR_HEADER),\r\n                                      FALSE,\r\n                                      ioStatus);\r\n\r\n    status = ioStatus->Status;\r\n\r\n    if(!NT_SUCCESS(status)) {\r\n\r\n        descriptor = NULL;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetDeviceIdList (DevObj %p): Query failed (%x) on attempt 1.\\n\",\r\n                    DeviceObject,\r\n                    ioStatus->Status));\r\n\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n    NT_ASSERT(descriptor->Size);\r\n    if (descriptor->Size == 0) {\r\n        status = STATUS_UNSUCCESSFUL;\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n    //\r\n    // This time we know how much data there is so we can\r\n    // allocate a buffer of the correct size\r\n    //\r\n    length = descriptor->Size;\r\n\r\n    descriptor = DsmpAllocatePool(NonPagedPoolNx, length, DSM_TAG_DEVICE_ID_LIST);\r\n\r\n    if(!descriptor) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetDeviceIdList (DevObj %p): Couldn't allocate descriptor of %ld.\\n\",\r\n                    DeviceObject,\r\n                    length));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n    //\r\n    // setup the query again.\r\n    //\r\n    query.PropertyId = StorageDeviceIdProperty;\r\n    query.QueryType = PropertyStandardQuery;\r\n    query.AdditionalParameters[0] = 0;\r\n\r\n    //\r\n    // copy the input to the new outputbuffer\r\n    //\r\n    RtlCopyMemory(descriptor,\r\n                  &query,\r\n                  sizeof(STORAGE_PROPERTY_QUERY));\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY,\r\n                                      DeviceObject,\r\n                                      descriptor,\r\n                                      descriptor,\r\n                                      sizeof(STORAGE_PROPERTY_QUERY),\r\n                                      length,\r\n                                      0,\r\n                                      ioStatus);\r\n\r\n    status = ioStatus->Status;\r\n\r\n    if(!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpGetDeviceIdList (DevObj %p): Query Failed (%x) on attempt 2.\\n\",\r\n                    DeviceObject,\r\n                    ioStatus->Status));\r\n\r\n        goto __Exit_DsmpGetDeviceIdList;\r\n    }\r\n\r\n__Exit_DsmpGetDeviceIdList:\r\n\r\n    if (ioStatus) {\r\n        DsmpFreePool(ioStatus);\r\n    }\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        if (descriptor) {\r\n            DsmpFreePool(descriptor);\r\n        }\r\n\r\n    } else {\r\n        *Descriptor = descriptor;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetDeviceIdList (DevObj %p): Exiting function with status %x.\\n\",\r\n                DeviceObject,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetTargetPortGroups(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_reads_bytes_(TargetPortGroupsInfoLength) IN PUCHAR TargetPortGroupsInfo,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send down SetTargetPortGroups request.\r\n\r\nArguments:\r\n\r\n    DeviceObject - The port PDO to which the command should be sent.\r\n    TargetPortGroupsInfo - buffer containing the TPG data.\r\n    TargetPortGroupsInfoLength - size of the TPG buffer.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER passThrough;\r\n    PSPC3_CDB_SET_TARGET_PORT_GROUPS cdb;\r\n    IO_STATUS_BLOCK ioStatus;\r\n    ULONG alignmentMask = DeviceObject->AlignmentRequirement;\r\n    PUCHAR dataBuffer = NULL;\r\n    SIZE_T allocatedLength = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetTargetPortGroups (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    NT_ASSERT(TargetPortGroupsInfoLength && TargetPortGroupsInfo);\r\n\r\n    //\r\n    // Build request.\r\n    //\r\n    RtlZeroMemory(&passThrough, sizeof(passThrough));\r\n\r\n    dataBuffer = DsmpAllocateAlignedPool(NonPagedPoolNx,\r\n                                         TargetPortGroupsInfoLength,\r\n                                         alignmentMask,\r\n                                         DSM_TAG_PASS_THRU,\r\n                                         &allocatedLength);\r\n    if (!dataBuffer) {\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpSetTargetPortGroups (DevObj %p): Failed to allocate mem for passthrough's databuffer.\\n\",\r\n                    DeviceObject));\r\n        goto __Exit_DsmpSetTargetPortGroups;\r\n    }\r\n\r\n__Retry_Request:\r\n\r\n    //\r\n    // Build the cdb.\r\n    //\r\n    cdb = (PSPC3_CDB_SET_TARGET_PORT_GROUPS)passThrough.ScsiPassThroughDirect.Cdb;\r\n\r\n    cdb->OperationCode = SPC3_SCSIOP_SET_TARGET_PORT_GROUPS;\r\n    cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS;\r\n    Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->ParameterListLength);\r\n\r\n    passThrough.ScsiPassThroughDirect.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);\r\n    passThrough.ScsiPassThroughDirect.CdbLength = 12;\r\n    passThrough.ScsiPassThroughDirect.SenseInfoLength = SPTWB_SENSE_LENGTH;\r\n    passThrough.ScsiPassThroughDirect.DataIn = 0;\r\n    passThrough.ScsiPassThroughDirect.DataTransferLength = TargetPortGroupsInfoLength;\r\n    passThrough.ScsiPassThroughDirect.TimeOutValue = 20;\r\n    passThrough.ScsiPassThroughDirect.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseInfoBuffer);\r\n    passThrough.ScsiPassThroughDirect.DataBuffer = dataBuffer;\r\n    RtlCopyMemory(dataBuffer,\r\n                  TargetPortGroupsInfo,\r\n                  TargetPortGroupsInfoLength);\r\n\r\n    DsmSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH_DIRECT,\r\n                                      DeviceObject,\r\n                                      &passThrough,\r\n                                      &passThrough,\r\n                                      sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),\r\n                                      sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),\r\n                                      FALSE,\r\n                                      &ioStatus);\r\n\r\n    if ((passThrough.ScsiPassThroughDirect.ScsiStatus == SCSISTAT_GOOD) &&\r\n        (NT_SUCCESS(ioStatus.Status))) {\r\n\r\n        status = STATUS_SUCCESS;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpSetTargetPortGroups (DevObj %p): STPG succeeded.\\n\",\r\n                    DeviceObject));\r\n\r\n    } else if (NT_SUCCESS(ioStatus.Status) &&\r\n               passThrough.ScsiPassThroughDirect.ScsiStatus == SCSISTAT_CHECK_CONDITION &&\r\n               DsmpShouldRetryTPGRequest((PSENSE_DATA)&passThrough.SenseInfoBuffer, passThrough.ScsiPassThroughDirect.SenseInfoLength)) {\r\n\r\n        //\r\n        // Retry the request\r\n        //\r\n        RtlZeroMemory(dataBuffer, TargetPortGroupsInfoLength);\r\n        goto __Retry_Request;\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpSetTargetPortGroups (DevObj %p): NTStatus 0%x, ScsiStatus 0x%x.\\n\",\r\n                    DeviceObject,\r\n                    ioStatus.Status,\r\n                    passThrough.ScsiPassThroughDirect.ScsiStatus));\r\n\r\n        status = ioStatus.Status;\r\n    }\r\n\r\n__Exit_DsmpSetTargetPortGroups:\r\n\r\n    //\r\n    // Free the passthrough + data buffer.\r\n    //\r\n    if (dataBuffer) {\r\n        DsmpFreePool(dataBuffer);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetTargetPortGroups (DevObj %p): Exiting function with status %x.\\n\",\r\n                DeviceObject,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetTargetPortGroupsAsync(\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN PIO_COMPLETION_ROUTINE CompletionRoutine,\r\n    _In_ __drv_aliasesMem IN PDSM_TPG_COMPLETION_CONTEXT CompletionContext,\r\n    _In_ IN ULONG TargetPortGroupsInfoLength,\r\n    _In_ __drv_aliasesMem IN PUCHAR TargetPortGroupsInfo\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to send down SetTargetPortGroups request asynchronously.\r\n\r\n    IMPORTANT: Caller needs to free the IRP and allocated system buffer.\r\n\r\nArguments:\r\n\r\n    DeviceInfo - The deviceInfo whose corresponding port PDO the command should be sent to.\r\n    CompletionRoutine - completion routine provided by the caller.\r\n    CompletionContext - context passed into the completion routine.\r\n    TargetPortGroupsInfoLength - size of the TPG buffer.\r\n    TargetPortGroupsInfo - buffer containing the TPG data.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PDSM_TPG_COMPLETION_CONTEXT tpgCompletionContext = CompletionContext;\r\n    PSCSI_REQUEST_BLOCK srb;\r\n    PSPC3_CDB_SET_TARGET_PORT_GROUPS cdb;\r\n    NTSTATUS status;\r\n    PIRP irp = NULL;\r\n    PIO_STACK_LOCATION irpStack;\r\n    PMDL mdl = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetTargetPortGroupsAsync (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    srb = tpgCompletionContext->Srb;\r\n\r\n    SrbZeroSrb(srb);\r\n\r\n    //\r\n    // Allocate an irp.\r\n    //\r\n    irp = IoAllocateIrp(DeviceInfo->TargetObject->StackSize + 1, FALSE);\r\n    if (!irp) {\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpSetTargetPortGroupsAsync (DevInfo %p): Failed to allocate IRP.\\n\",\r\n                    DeviceInfo));\r\n        goto __Exit_DsmpSetTargetPortGroupsAsync;\r\n    }\r\n\r\n    mdl = IoAllocateMdl(TargetPortGroupsInfo,\r\n                        TargetPortGroupsInfoLength,\r\n                        FALSE,\r\n                        FALSE,\r\n                        irp);\r\n    if (!mdl) {\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_RW,\r\n                    \"DsmpSetTargetPortGroupsAsync (DevInfo %p): Failed to allocate MDL.\\n\",\r\n                    DeviceInfo));\r\n        goto __Exit_DsmpSetTargetPortGroupsAsync;\r\n    }\r\n\r\n    MmBuildMdlForNonPagedPool(irp->MdlAddress);\r\n\r\n    //\r\n    // It is possible that an implicit state transition may have occurred which\r\n    // will cause every I_T nexus to return an UA (for asymmetric access state\r\n    // changed). So set the number of retries to number of paths (worst case of\r\n    // every path being a separate I_T nexus) plus one for a retry down one of\r\n    // paths.\r\n    //\r\n    tpgCompletionContext->NumberRetries = DeviceInfo->Group->NumberDevices + 1;\r\n\r\n    //\r\n    // Set-up the completion routine.\r\n    //\r\n    IoSetCompletionRoutine(irp,\r\n                           CompletionRoutine,\r\n                           (PVOID)CompletionContext,\r\n                           TRUE,\r\n                           TRUE,\r\n                           TRUE);\r\n\r\n    //\r\n    // Get the recipient's irpstack location.\r\n    //\r\n    irpStack = IoGetNextIrpStackLocation(irp);\r\n\r\n    irpStack->Parameters.Scsi.Srb = srb;\r\n    irpStack->DeviceObject = DeviceInfo->TargetObject;\r\n\r\n    //\r\n    // Set the major function code to IRP_MJ_SCSI.\r\n    //\r\n    irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;\r\n\r\n    //\r\n    // Set the minor function, or many requests will get kicked by by port.\r\n    //\r\n    irpStack->MinorFunction = IRP_MN_SCSI_CLASS;\r\n\r\n    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;\r\n    srb->Length = sizeof(SCSI_REQUEST_BLOCK);\r\n\r\n    SrbSetCdbLength(srb, sizeof(SPC3_CDB_SET_TARGET_PORT_GROUPS));\r\n    cdb = (PSPC3_CDB_SET_TARGET_PORT_GROUPS)SrbGetCdb(srb);\r\n    cdb->OperationCode = SPC3_SCSIOP_SET_TARGET_PORT_GROUPS;\r\n    cdb->ServiceAction = SPC3_SERVICE_ACTION_TARGET_PORT_GROUPS;\r\n    Get4ByteArrayFromUlong(TargetPortGroupsInfoLength, cdb->ParameterListLength);\r\n\r\n    SrbSetTimeOutValue(srb, SPC3_SET_TARGET_PORT_GROUPS_TIMEOUT);\r\n    SrbSetSenseInfoBuffer(srb, tpgCompletionContext->SenseInfoBuffer);\r\n    SrbSetSenseInfoBufferLength(srb, tpgCompletionContext->SenseInfoBufferLength);\r\n    SrbSetDataTransferLength(srb, TargetPortGroupsInfoLength);\r\n    SrbSetDataBuffer(srb, TargetPortGroupsInfo);\r\n    srb->SrbStatus = 0;\r\n    SrbSetScsiStatus(srb, 0);\r\n    SrbSetNextSrb(srb, NULL);\r\n    SrbSetSrbFlags(srb, SRB_FLAGS_DONT_START_NEXT_PACKET | SRB_FLAGS_QUEUE_ACTION_ENABLE |\r\n                     SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER |\r\n                     SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE);\r\n    SrbSetQueueAction(srb, SRB_HEAD_OF_QUEUE_TAG_REQUEST);\r\n    SrbSetOriginalRequest(srb, irp);\r\n\r\n    irp->UserBuffer = TargetPortGroupsInfo;\r\n    irp->Tail.Overlay.Thread = PsGetCurrentThread();\r\n\r\n    //\r\n    // Send the IRP asynchronously\r\n    //\r\n    DsmSendRequestEx(((PDSM_CONTEXT)(DeviceInfo->DsmContext))->MPIOContext,\r\n                     DeviceInfo->TargetObject,\r\n                     irp,\r\n                     DeviceInfo,\r\n                     DSM_CALL_COMPLETION_ON_MPIO_ERROR);\r\n\r\n    //\r\n    // We know that the completion routine will always be called.\r\n    //\r\n    status = STATUS_PENDING;\r\n\r\n\r\n__Exit_DsmpSetTargetPortGroupsAsync:\r\n\r\n    if (status != STATUS_PENDING) {\r\n\r\n        //\r\n        // This indicates Irp was never sent down to stack (completion routine was never called).\r\n        // We need to clean up.\r\n        //\r\n        if (irp) {\r\n\r\n            if (irp->MdlAddress) {\r\n                IoFreeMdl(irp->MdlAddress);\r\n            }\r\n\r\n            IoFreeIrp(irp);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_RW,\r\n                \"DsmpSetTargetPortGroupsAsync (DevInfo %p): Exiting function with status %x.\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPDSM_LOAD_BALANCE_POLICY_SETTINGS\r\nDsmpCopyLoadBalancePolicies(\r\n    _In_ IN PDSM_GROUP_ENTRY GroupEntry,\r\n    _In_ IN ULONG DsmWmiVersion,\r\n    _In_ IN PVOID SupportedLBPolicies\r\n    )\r\n/*+++\r\n\r\nRoutine Description:\r\n\r\n    This routine copies the LB Policies that needs to be persisted in registry.\r\n    This is done because registry routines can be called at PASSIVE IRQL only.\r\n    So a spinlock cannot be held while accessing registry. So hold a spinlock,\r\n    save the values in a temp buffer, release spinlock, and save data to registry\r\n    from the temp buffer.\r\n\r\n    NOTE: This routine MUST be called with DSM_CONTEXT lock held.\r\n\r\nArguements:\r\n\r\n    GroupEntry - Group entry\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n    SupportedLBPolicies - LB policy for the group\r\n\r\n Return Value:\r\n\r\n    Pointer to  LOAD_BALANCE_POLICY_SETTINGS if successful. Else, NULL\r\n--*/\r\n{\r\n    PDSM_LOAD_BALANCE_POLICY_SETTINGS lbSettings = NULL;\r\n    ULONG sizeNeeded;\r\n    ULONG inx;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpCopyLoadBalancePolicies (Group %p): Entering function.\\n\",\r\n                GroupEntry));\r\n\r\n    if (((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpCopyLoadBalancePolicies (Group %p): No paths specified in Set LB policies.\\n\",\r\n                    GroupEntry));\r\n\r\n        goto __Exit_DsmpCopyLoadBalancePolicies;\r\n    }\r\n\r\n    sizeNeeded = sizeof(DSM_LOAD_BALANCE_POLICY_SETTINGS) +\r\n                 ((((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount - 1) * sizeof(MPIO_DSM_Path_V2));;\r\n\r\n    lbSettings = DsmpAllocatePool(NonPagedPoolNx,\r\n                                  sizeNeeded,\r\n                                  DSM_TAG_LB_POLICY);\r\n\r\n    if (!lbSettings) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpCopyLoadBalancePolicies (Group %p): Failed to allocate memory for LBSettings.\\n\",\r\n                    GroupEntry));\r\n        goto __Exit_DsmpCopyLoadBalancePolicies;\r\n    }\r\n\r\n    //\r\n    // Copy the registry key name used to store the LB policies.\r\n    //\r\n    RtlStringCchCopyNW(lbSettings->RegistryKeyName,\r\n                       sizeof(lbSettings->RegistryKeyName) / sizeof(lbSettings->RegistryKeyName[0]),\r\n                       GroupEntry->RegistryKeyName,\r\n                       ((sizeof(lbSettings->RegistryKeyName) - sizeof(WCHAR))/sizeof(WCHAR)));\r\n\r\n    //\r\n    // Copy the Load Balance settings for this group\r\n    //\r\n    lbSettings->LoadBalancePolicy = ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->LoadBalancePolicy;\r\n\r\n    lbSettings->PathCount = ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount;\r\n\r\n    for (inx = 0; inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount; inx++) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            RtlCopyMemory(&(lbSettings->DsmPath[inx]),\r\n                          &(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]),\r\n                          sizeof(MPIO_DSM_Path));\r\n\r\n            //\r\n            // DSM_WMI_VERSION_1 supports only active and standby states\r\n            //\r\n            (lbSettings->DsmPath[inx]).OptimizedPath = TRUE;\r\n\r\n        } else {\r\n\r\n            RtlCopyMemory(&(lbSettings->DsmPath[inx]),\r\n                          &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]),\r\n                          sizeof(MPIO_DSM_Path_V2));\r\n        }\r\n    }\r\n\r\n__Exit_DsmpCopyLoadBalancePolicies:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpCopyLoadBalancePolicies (Group %p): Exiting function with lbSettings %p.\\n\",\r\n                GroupEntry,\r\n                lbSettings));\r\n\r\n    return lbSettings;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpPersistLBSettings(\r\n    _In_ IN PDSM_LOAD_BALANCE_POLICY_SETTINGS LoadBalanceSettings\r\n    )\r\n/*+++\r\n\r\nRoutine Description:\r\n\r\n    This routine will save the Load Balance settings from LoadBalanceSettings\r\n    to registry.\r\n\r\n    NOTE: This routine MUST be called at PASSIVE IRQL\r\n\r\n    The format of the registry tree is :\r\n\r\n      Services\\MSDSM\\LoadBalanceSettings ->\r\n\r\n               DeviceName -> LoadBalancePolicy REG_DWORD  <LB Value>\r\n\r\n                  DsmPath#Suffix -> PrimaryPath     REG_DWORD <Value>\r\n                                    OptimizedPath   REG_DWORD <Value>\r\n                                    PathWeight      REG_DWORD <Value>\r\n\r\n      The device name is the one built in DsmpBuildDeviceName\r\n\r\n      The Suffix in DsmPath#Suffix is built from the PathId. It is built in\r\n      the routine DsmpGetDSMPathKeyName.\r\n\r\nArguements:\r\n\r\n     LoadBalanceSettings - Load Balance settings to be persisted in registry\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS if the data could be successfully stored in the registry\r\n    Appropriate NT Status code on failure.\r\n--*/\r\n{\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    HANDLE lbSettingsKey = NULL;\r\n    HANDLE deviceKey = NULL;\r\n    HANDLE dsmPathKey = NULL;\r\n    UNICODE_STRING subKeyName;\r\n    WCHAR dsmPathName[128];\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    NTSTATUS status;\r\n    ULONG inx;\r\n    PMPIO_DSM_Path_V2 preferredPath = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpPersistLBSettings (DevName %ws): Entering function.\\n\",\r\n                LoadBalanceSettings->RegistryKeyName));\r\n\r\n    //\r\n    // First open LoadBalanceSettings key under the Service key\r\n    //\r\n    status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpPersistLBSettings (DevName %ws): Failed to open LB Settings key. Status %x.\\n\",\r\n                    LoadBalanceSettings->RegistryKeyName,\r\n                    status));\r\n\r\n        goto __Exit_DsmpPersistLBSettings;\r\n    }\r\n\r\n    //\r\n    // Now open the key under which the LB settings for the given device is stored\r\n    //\r\n    RtlInitUnicodeString(&subKeyName, LoadBalanceSettings->RegistryKeyName);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &subKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               lbSettingsKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // Remove all LB policy information as we are going to rewrite it.\r\n        // We do this in case there is stale information about a path that\r\n        // no longer exists\r\n        //\r\n        status = DsmpRegDeleteTree(deviceKey);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpPersistLBSettings (DevName %ws): Deleted key along with its subkeys.\\n\",\r\n                        LoadBalanceSettings->RegistryKeyName));\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpPersistLBSettings (DevName %ws): Failed to delete key. Status %x\\n\",\r\n                        LoadBalanceSettings->RegistryKeyName,\r\n                        status));\r\n\r\n        }\r\n\r\n        ZwClose(deviceKey);\r\n        deviceKey = NULL;\r\n\r\n    }\r\n\r\n    status = ZwCreateKey(&deviceKey,\r\n                         KEY_ALL_ACCESS,\r\n                         &objectAttributes,\r\n                         0,\r\n                         NULL,\r\n                         REG_OPTION_NON_VOLATILE,\r\n                         NULL);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        PDSM_DEVICE_INFO devInfo;\r\n\r\n        for (inx = 0; inx < LoadBalanceSettings->PathCount; inx++) {\r\n\r\n            dsmPath = &(LoadBalanceSettings->DsmPath[inx]);\r\n\r\n            if (dsmPath->DsmPathId == 0) {\r\n\r\n                continue;\r\n            }\r\n\r\n            RtlZeroMemory(dsmPathName, sizeof(dsmPathName));\r\n\r\n            //\r\n            // Get the sub key name under which the LB settings for\r\n            // the given path is stored.\r\n            //\r\n            DsmpGetDSMPathKeyName(dsmPath->DsmPathId, dsmPathName, 128);\r\n\r\n            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpPersistLBSettings (DevName %ws): Will open subkey %ws.\\n\",\r\n                        LoadBalanceSettings->RegistryKeyName,\r\n                        dsmPathName));\r\n\r\n            RtlInitUnicodeString(&subKeyName, dsmPathName);\r\n\r\n            RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));\r\n\r\n            InitializeObjectAttributes(&objectAttributes,\r\n                                       &subKeyName,\r\n                                       (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                       deviceKey,\r\n                                       (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n            status = ZwCreateKey(&dsmPathKey,\r\n                                 KEY_ALL_ACCESS,\r\n                                 &objectAttributes,\r\n                                 0,\r\n                                 NULL,\r\n                                 REG_OPTION_NON_VOLATILE,\r\n                                 NULL);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                if (dsmPath->PreferredPath) {\r\n\r\n                    preferredPath = dsmPath;\r\n                }\r\n\r\n                devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n                //\r\n                // Save PrimaryPath, PathWeight and OptimizedPath values for this path\r\n                //\r\n                if (devInfo->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                    status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                                   dsmPathKey,\r\n                                                   DSM_PRIMARY_PATH,\r\n                                                   REG_DWORD,\r\n                                                   &(dsmPath->PrimaryPath),\r\n                                                   sizeof(ULONG));\r\n\r\n                    if (NT_SUCCESS(status)) {\r\n\r\n                        status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                                       dsmPathKey,\r\n                                                       DSM_OPTIMIZED_PATH,\r\n                                                       REG_DWORD,\r\n                                                       &(dsmPath->OptimizedPath),\r\n                                                       sizeof(ULONG));\r\n\r\n                        if (!NT_SUCCESS(status)) {\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_WMI,\r\n                                        \"DsmpPersistLBSettings (DevName %ws): Failed to save OptimizedPath. Status %x.\\n\",\r\n                                        LoadBalanceSettings->RegistryKeyName,\r\n                                        status));\r\n                        }\r\n                    } else {\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_WMI,\r\n                                    \"DsmpPersistLBSettings (DevName %ws): Failed to save Primary Path. Status %x.\\n\",\r\n                                    LoadBalanceSettings->RegistryKeyName,\r\n                                    status));\r\n                    }\r\n                }\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    if (LoadBalanceSettings->LoadBalancePolicy == DSM_LB_WEIGHTED_PATHS) {\r\n\r\n                        status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                                       dsmPathKey,\r\n                                                       DSM_PATH_WEIGHT,\r\n                                                       REG_DWORD,\r\n                                                       &(dsmPath->PathWeight),\r\n                                                       sizeof(ULONG));\r\n\r\n                        if (!NT_SUCCESS(status)) {\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_WMI,\r\n                                        \"DsmpPersistLBSettings (DevName %ws): Failed to save PathWeight. Status %x.\\n\",\r\n                                        LoadBalanceSettings->RegistryKeyName,\r\n                                        status));\r\n                        }\r\n                    }\r\n                }\r\n\r\n                ZwClose(dsmPathKey);\r\n                dsmPathKey = NULL;\r\n            } else {\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpPersistLBSettings (DevName %ws): Failed to open DSM Path key. Status %x.\\n\",\r\n                            LoadBalanceSettings->RegistryKeyName,\r\n                            status));\r\n            }\r\n\r\n            if (!NT_SUCCESS(status)) {\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // Save the new Load Balance Policy value,\r\n            //\r\n            status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                           deviceKey,\r\n                                           DSM_LOAD_BALANCE_POLICY,\r\n                                           REG_DWORD,\r\n                                           &(LoadBalanceSettings->LoadBalancePolicy),\r\n                                           sizeof(ULONG));\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                UCHAR explicitlySet = TRUE;\r\n\r\n                //\r\n                // Write out that the policy has been explicitly set\r\n                //\r\n                status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                               deviceKey,\r\n                                               DSM_POLICY_EXPLICITLY_SET,\r\n                                               REG_BINARY,\r\n                                               &explicitlySet,\r\n                                               sizeof(UCHAR));\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    //\r\n                    // If FailOver-Only policy, set the PreferredPath, if specified\r\n                    //\r\n                    if (preferredPath) {\r\n\r\n                        status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                                       deviceKey,\r\n                                                       DSM_PREFERRED_PATH,\r\n                                                       REG_BINARY,\r\n                                                       &(preferredPath->DsmPathId),\r\n                                                       sizeof(ULONGLONG));\r\n                    }\r\n                } else {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_WMI,\r\n                                \"DsmpPersistLBSettings (DevName %ws): Failed to save LB Settings (ES).\\n\",\r\n                                LoadBalanceSettings->RegistryKeyName));\r\n                }\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpPersistLBSettings (DevName %ws): Failed to save LB Settings (LBP).\\n\",\r\n                            LoadBalanceSettings->RegistryKeyName));\r\n            }\r\n        }\r\n    }\r\n\r\n__Exit_DsmpPersistLBSettings:\r\n\r\n    if (dsmPathKey) {\r\n        ZwClose(dsmPathKey);\r\n    }\r\n\r\n    if (deviceKey) {\r\n        ZwClose(deviceKey);\r\n    }\r\n\r\n    if (lbSettingsKey) {\r\n        ZwClose(lbSettingsKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpPersistLBSettings (DevName %ws): Exiting function with status %x.\\n\",\r\n                LoadBalanceSettings->RegistryKeyName,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetDeviceALUAState(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_ IN DSM_DEVICE_STATE DevState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to build the STPG info and send it down to modify the passed in\r\n    devInfo's state.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context.\r\n    DeviceInfo - DevInfo whose state needs to be changed.\r\n    DevState - New state to be set.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength;\r\n    PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL;\r\n    NTSTATUS status;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetDeviceALUAState (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    //\r\n    // Send down SetTPG to set the appropriate access state\r\n    // (The TPG block will contain the header and a SetTPG descriptor).\r\n    //\r\n    targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                 sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR);\r\n\r\n    targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                            targetPortGroupsInfoLength,\r\n                                            DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n    if (targetPortGroupsInfo) {\r\n\r\n        tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE);\r\n        tpgDescriptor->AsymmetricAccessState = DevState;\r\n        REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &DeviceInfo->TargetPortGroup->Identifier);\r\n\r\n        status = DsmpSetTargetPortGroups(DeviceInfo->TargetObject,\r\n                                         targetPortGroupsInfo,\r\n                                         targetPortGroupsInfoLength);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            //\r\n            // An explicit transition may cause changes to some other TPGs.\r\n            // So we need to query for the states of all the TPGs and update\r\n            // our internal list and its elements.\r\n            //\r\n            status = DsmpGetDeviceALUAState(DsmContext,\r\n                                            DeviceInfo,\r\n                                            NULL);\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_GENERAL,\r\n                        \"DsmpSetDeviceALUAState (DevInfo %p): Failed to SetTPG with %x.\\n\",\r\n                        DeviceInfo,\r\n                        status));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpSetDeviceALUAState (DevInfo %p): Failed to allocate TPG.\\n\",\r\n                    DeviceInfo));\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n    }\r\n\r\n    if (targetPortGroupsInfo) {\r\n        DsmpFreePool(targetPortGroupsInfo);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpSetDeviceALUAState (DevInfo %p): Exiting function with status %x\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpAdjustDeviceStatesALUA(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_opt_ IN PDSM_DEVICE_INFO PreferredActiveDeviceInfo,\r\n    _In_ IN ULONG SpecialHandlingFlag\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to build the adjust every device state in the group taking\r\n    the following into consideration:\r\n    1. PreferredActiveDeviceInfo\r\n    2. DeviceInfo's TPG state\r\n    3. Preferred Path\r\n    4. LB Policy\r\n\r\nArguments:\r\n\r\n    Group - Pseudo-LUN whose path states need to be adjusted.\r\n    PreferredActiveDeviceInfo - DevInfo whose state needs to preferrably made\r\n                                A/O, if possible. This parameter is optional.\r\n\r\n    SpecialHandlingFlag - Flags to indicate any special handling requirement\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    ULONG index;\r\n    PDSM_DEVICE_INFO deviceInfo;\r\n    PDSM_DEVICE_INFO activeDevice = NULL;\r\n    DSM_DEVICE_STATE devState;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAdjustDeviceStatesALUA (Group %p): Entering function with preferred active devInfo %p.\\n\",\r\n                Group,\r\n                PreferredActiveDeviceInfo));\r\n\r\n    //\r\n    // Ensure that:\r\n    // 1. All devices match their ALUA state.\r\n    // 2. For RRWS, if a device's desired state is non-A/O, but ALUA state is A/O, mask it.\r\n    // 3. For FOO there must be only one A/O device. Preferably the preferred path.\r\n    //\r\n    for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n        deviceInfo = Group->DeviceList[index];\r\n\r\n        if (deviceInfo) {\r\n\r\n            devState = deviceInfo->State;\r\n\r\n            if (!DsmpIsDeviceFailedState(deviceInfo->State) &&\r\n                DsmpIsDeviceInitialized(deviceInfo) &&\r\n                DsmpIsDeviceUsable(deviceInfo) &&\r\n                DsmpIsDeviceUsablePR(deviceInfo)) {\r\n\r\n\r\n                deviceInfo->PreviousState = deviceInfo->State;\r\n                deviceInfo->State = deviceInfo->ALUAState;\r\n\r\n                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                            TRACE_FLAG_GENERAL,\r\n                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (its ALUA state).\\n\",\r\n                            Group,\r\n                            deviceInfo,\r\n                            deviceInfo->PreviousState,\r\n                            deviceInfo->State));\r\n\r\n                if (deviceInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                    //\r\n                    // In FOO and RRWS, we need to mask states.\r\n                    //\r\n                    switch (Group->LoadBalanceType) {\r\n                        case DSM_LB_FAILOVER: {\r\n\r\n                            //\r\n                            // Cache the first available devInfo that is in A/O\r\n                            //\r\n                            if (!activeDevice) {\r\n\r\n                                activeDevice = deviceInfo;\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_GENERAL,\r\n                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p choosen as the active device.\\n\",\r\n                                            Group,\r\n                                            activeDevice));\r\n\r\n                                break;\r\n                            }\r\n\r\n                            //\r\n                            // Check if this deviceInfo is the preferred path. If yes,\r\n                            // mask the active device's state and make this the new\r\n                            // active device.\r\n                            //\r\n                            if (Group->PreferredPath == (ULONGLONG)((ULONG_PTR)deviceInfo->FailGroup->PathId)) {\r\n\r\n                                activeDevice->PreviousState = activeDevice->State;\r\n                                activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                       activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState;\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_GENERAL,\r\n                                            \"DsmpAdjustDeviceStatesALUA (Group %p): Previous active devInfo %p transitioning from %u to %u.\\n\",\r\n                                            Group,\r\n                                            activeDevice,\r\n                                            activeDevice->PreviousState,\r\n                                            activeDevice->State));\r\n\r\n                                activeDevice = deviceInfo;\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_GENERAL,\r\n                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (preferred path).\\n\",\r\n                                            Group,\r\n                                            activeDevice));\r\n\r\n                                break;\r\n                            }\r\n\r\n                            //\r\n                            // If active device's desired state is not A/O but this\r\n                            // deviceInfo's is, then mask the active device's state\r\n                            // and make this one the new active device.\r\n                            //\r\n                            if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                activeDevice->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                //\r\n                                // The exception though is if the current active device\r\n                                // is the preferred path\r\n                                //\r\n                                if (Group->PreferredPath == (ULONGLONG)((ULONG_PTR)activeDevice->FailGroup->PathId)) {\r\n\r\n                                    deviceInfo->PreviousState = deviceInfo->State;\r\n                                    deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                         deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState;\r\n\r\n                                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                TRACE_FLAG_GENERAL,\r\n                                                \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (active DI is PrefPath).\\n\",\r\n                                                Group,\r\n                                                deviceInfo,\r\n                                                deviceInfo->PreviousState,\r\n                                                deviceInfo->State));\r\n                                } else {\r\n\r\n                                    //\r\n                                    // If this is the devInfo that is preferred to be A/O, make it such\r\n                                    //\r\n                                    if (PreferredActiveDeviceInfo &&\r\n                                        PreferredActiveDeviceInfo == deviceInfo) {\r\n\r\n                                        activeDevice->PreviousState = activeDevice->State;\r\n                                        activeDevice->State = activeDevice->DesiredState;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (found a preferred active DI).\\n\",\r\n                                                    Group,\r\n                                                    activeDevice,\r\n                                                    activeDevice->PreviousState,\r\n                                                    activeDevice->State));\r\n\r\n                                        activeDevice = deviceInfo;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active DI (preferred).\\n\",\r\n                                                    Group,\r\n                                                    activeDevice));\r\n                                    } else {\r\n\r\n                                        //\r\n                                        // Check if this devInfo desires to be in A/O, since the currently\r\n                                        // active one doesn't want to be.\r\n                                        //\r\n                                        if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                            deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                            //\r\n                                            // This deviceInfo's desire is also not to be in A/O,\r\n                                            // so just leave the current one active.\r\n                                            //\r\n                                            if (devState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                                                //\r\n                                                // Exception is if we're processing the device whose state before\r\n                                                // RTPG was sent was already A/O, it is best to leave this device\r\n                                                // in A/O state.\r\n                                                //\r\n\r\n                                                activeDevice->PreviousState = activeDevice->State;\r\n                                                activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                                       activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. Found a DI that was previously active.\\n\",\r\n                                                            Group,\r\n                                                            activeDevice,\r\n                                                            activeDevice->PreviousState,\r\n                                                            activeDevice->State));\r\n\r\n                                                activeDevice = deviceInfo;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active device (previously A/O).\\n\",\r\n                                                            Group,\r\n                                                            activeDevice));\r\n                                            } else {\r\n\r\n                                                //\r\n                                                // This device wasn't in A/O state before, so just leave\r\n                                                // the currently selected active device as is.\r\n                                                //\r\n                                                deviceInfo->PreviousState = deviceInfo->State;\r\n                                                deviceInfo->State = deviceInfo->DesiredState;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (active device already exists).\\n\",\r\n                                                            Group,\r\n                                                            deviceInfo,\r\n                                                            deviceInfo->PreviousState,\r\n                                                            deviceInfo->State));\r\n                                            }\r\n                                        } else {\r\n\r\n                                            //\r\n                                            // Current devInfo wants (or doesn't) mind being in\r\n                                            // A/O, whereas the current active device doesn't, so\r\n                                            // mask the active device and make this devInfo the\r\n                                            // active device.\r\n                                            //\r\n                                            activeDevice->PreviousState = activeDevice->State;\r\n                                            activeDevice->State = activeDevice->DesiredState;\r\n\r\n                                            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                        TRACE_FLAG_GENERAL,\r\n                                                        \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. Current DI prefers being A/O.\\n\",\r\n                                                        Group,\r\n                                                        activeDevice,\r\n                                                        activeDevice->PreviousState,\r\n                                                        activeDevice->State));\r\n\r\n                                            activeDevice = deviceInfo;\r\n\r\n                                            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                        TRACE_FLAG_GENERAL,\r\n                                                        \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (desired state).\\n\",\r\n                                                        Group,\r\n                                                        activeDevice));\r\n                                        }\r\n                                    }\r\n                                }\r\n                            } else {\r\n\r\n                                //\r\n                                // The single overriding factor is always the preferred path.\r\n                                // Everything else is secondary, so first check if the currently\r\n                                // active device can even be overridden by another one.\r\n                                //\r\n                                if (Group->PreferredPath != (ULONGLONG)((ULONG_PTR)activeDevice->FailGroup->PathId)) {\r\n\r\n                                    //\r\n                                    // It can't be overridden, so we're done.\r\n                                    //\r\n                                    deviceInfo->PreviousState = deviceInfo->State;\r\n                                    deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                         deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState;\r\n\r\n                                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                TRACE_FLAG_GENERAL,\r\n                                                \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (current active DI is PrefPath).\\n\",\r\n                                                Group,\r\n                                                deviceInfo,\r\n                                                deviceInfo->PreviousState,\r\n                                                deviceInfo->State));\r\n                                } else {\r\n\r\n                                    //\r\n                                    // Active device's desired state is A/O but it isn't the preferred\r\n                                    // path. Check if this devInfo is preferred as A/O.\r\n                                    //\r\n                                    if (PreferredActiveDeviceInfo &&\r\n                                        PreferredActiveDeviceInfo == deviceInfo) {\r\n\r\n                                        activeDevice->PreviousState = activeDevice->State;\r\n                                        activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                               activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u. New DI is preferred active.\\n\",\r\n                                                    Group,\r\n                                                    activeDevice,\r\n                                                    activeDevice->PreviousState,\r\n                                                    activeDevice->State));\r\n\r\n                                        activeDevice = deviceInfo;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is now the new active device (this DI is preferred active).\\n\",\r\n                                                    Group,\r\n                                                    activeDevice));\r\n                                    } else {\r\n\r\n                                        //\r\n                                        // Active device's desired state is A/O but it isn't the\r\n                                        // preferred path. Check if this devInfo's desired state\r\n                                        // is also A/O. If yes, we'll need to make certain decisions.\r\n                                        //\r\n                                        if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                            deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                            //\r\n                                            // Since this device doesn't desire to be in\r\n                                            // A/O and we already have an active device, just\r\n                                            // mask its state.\r\n                                            //\r\n                                            deviceInfo->PreviousState = deviceInfo->State;\r\n                                            deviceInfo->State = deviceInfo->DesiredState;\r\n\r\n                                            TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                        TRACE_FLAG_GENERAL,\r\n                                                        \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (prefers being in non-A/O).\\n\",\r\n                                                        Group,\r\n                                                        deviceInfo,\r\n                                                        deviceInfo->PreviousState,\r\n                                                        deviceInfo->State));\r\n                                        } else {\r\n\r\n                                            //\r\n                                            // Active device is in A/O and this device desires to be in\r\n                                            // A/O too. Make this the new active device only if its state\r\n                                            // before the RTPG was already A/O.\r\n                                            //\r\n                                            if (devState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                                                activeDevice->PreviousState = activeDevice->State;\r\n                                                activeDevice->State = (activeDevice->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                                       activeDevice->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : activeDevice->DesiredState;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (new DI was already in A/O previously).\\n\",\r\n                                                            Group,\r\n                                                            activeDevice,\r\n                                                            activeDevice->PreviousState,\r\n                                                            activeDevice->State));\r\n\r\n                                                activeDevice = deviceInfo;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p is new active device (since it was in A/O previously too).\\n\",\r\n                                                            Group,\r\n                                                            activeDevice));\r\n                                            } else {\r\n\r\n                                                //\r\n                                                // Just leave the currently active one alone.\r\n                                                //\r\n                                                deviceInfo->PreviousState = deviceInfo->State;\r\n                                                deviceInfo->State = (deviceInfo->DesiredState == DSM_DEV_UNDETERMINED ||\r\n                                                                     deviceInfo->DesiredState == DSM_DEV_ACTIVE_OPTIMIZED) ? DSM_DEV_ACTIVE_UNOPTIMIZED : deviceInfo->DesiredState;\r\n\r\n                                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                            TRACE_FLAG_GENERAL,\r\n                                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (leave current active DI alone).\\n\",\r\n                                                            Group,\r\n                                                            deviceInfo,\r\n                                                            deviceInfo->PreviousState,\r\n                                                            deviceInfo->State));\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                            break;\r\n                        }\r\n\r\n                        case DSM_LB_ROUND_ROBIN_WITH_SUBSET: {\r\n\r\n                            //\r\n                            // At least one path needs to be in A/O state, so\r\n                            // cache the first available devInfo that is in A/O\r\n                            //\r\n                            if (!activeDevice) {\r\n\r\n                                activeDevice = deviceInfo;\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_GENERAL,\r\n                                            \"DsmpAdjustDeviceStatesALUA (Group %p): We have atleast one A/O DevInfo %p.\\n\",\r\n                                            Group,\r\n                                            activeDevice));\r\n\r\n                                break;\r\n                            }\r\n\r\n                            //\r\n                            // Check if this device is preferred to be in A/O\r\n                            //\r\n                            if (PreferredActiveDeviceInfo &&\r\n                                PreferredActiveDeviceInfo == deviceInfo) {\r\n\r\n                                //\r\n                                // If the currently active device, doesn't desire to be in\r\n                                // A/O state, mask its state.\r\n                                //\r\n                                if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                    activeDevice->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                    activeDevice->PreviousState = activeDevice->State;\r\n                                    activeDevice->State = activeDevice->DesiredState;\r\n\r\n                                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                TRACE_FLAG_GENERAL,\r\n                                                \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (desired state non-A/O).\\n\",\r\n                                                Group,\r\n                                                activeDevice,\r\n                                                activeDevice->PreviousState,\r\n                                                activeDevice->State));\r\n                                }\r\n\r\n                                activeDevice = deviceInfo;\r\n\r\n                                TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                            TRACE_FLAG_GENERAL,\r\n                                            \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active device (preferred active DI).\\n\",\r\n                                            Group,\r\n                                            activeDevice));\r\n                            } else {\r\n\r\n                                //\r\n                                // If this device's desired state is specified and not A/O,\r\n                                // mask its path state.\r\n                                //\r\n                                if (deviceInfo->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                    deviceInfo->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                    deviceInfo->PreviousState = deviceInfo->State;\r\n                                    deviceInfo->State = deviceInfo->DesiredState;\r\n\r\n                                    TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                TRACE_FLAG_GENERAL,\r\n                                                \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (desires to be in non-A/O).\\n\",\r\n                                                Group,\r\n                                                deviceInfo,\r\n                                                deviceInfo->PreviousState,\r\n                                                deviceInfo->State));\r\n                                } else {\r\n\r\n                                    //\r\n                                    // Since this devInfo desires to be in A/O, we are assured\r\n                                    // of at least one path in A/O. So check to see if the\r\n                                    // currently active device doesn't desire to be in A/O.\r\n                                    //\r\n                                    if (activeDevice->DesiredState != DSM_DEV_ACTIVE_OPTIMIZED &&\r\n                                        activeDevice->DesiredState != DSM_DEV_UNDETERMINED) {\r\n\r\n                                        activeDevice->PreviousState = activeDevice->State;\r\n                                        activeDevice->State = activeDevice->DesiredState;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p transitioning from %u to %u (new DI desires to be in A/O).\\n\",\r\n                                                    Group,\r\n                                                    activeDevice,\r\n                                                    activeDevice->PreviousState,\r\n                                                    activeDevice->State));\r\n\r\n                                        activeDevice = deviceInfo;\r\n\r\n                                        TracePrint((TRACE_LEVEL_INFORMATION,\r\n                                                    TRACE_FLAG_GENERAL,\r\n                                                    \"DsmpAdjustDeviceStatesALUA (Group %p): DevInfo %p now the new active DI (desires to be in A/O).\\n\",\r\n                                                    Group,\r\n                                                    activeDevice));\r\n                                    }\r\n                                }\r\n                            }\r\n\r\n                            break;\r\n                        }\r\n\r\n                        default: {\r\n\r\n                            //\r\n                            // For RR, LQD and WP, paths must be in the same\r\n                            // state as their corresponding TPG. Preferably\r\n                            // all should be A/O.\r\n                            //\r\n                            if (deviceInfo->State != DSM_DEV_ACTIVE_OPTIMIZED) {\r\n                                DSM_ASSERT(deviceInfo->State == deviceInfo->ALUAState);\r\n                            }\r\n\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // There may have been a change to the device states.\r\n    // DsmpGetPath() will pick these changes for RR, RRWS and LQD.\r\n    // However, it won't for FOO and WP, so update PTBU if needed.\r\n    //\r\n    if (Group->LoadBalanceType == DSM_LB_FAILOVER ||\r\n        Group->LoadBalanceType == DSM_LB_WEIGHTED_PATHS) {\r\n\r\n        deviceInfo = DsmpGetActivePathToBeUsed(Group, FALSE, SpecialHandlingFlag);\r\n\r\n        if (deviceInfo) {\r\n\r\n            InterlockedExchangePointer(&(Group->PathToBeUsed), deviceInfo->FailGroup);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpAdjustDeviceStatesALUA (Group %p): Exiting function with status %x\\n\",\r\n                Group,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nPDSM_WORKITEM\r\nDsmpAllocateWorkItem(\r\n    _In_ IN PDEVICE_OBJECT DeviceObject,\r\n    _In_ IN PVOID Context\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Allocates a work item to handle reservation failover.\r\n\r\nArguments:\r\n\r\n    DeviceObject - Target device.\r\n    Context - Workitem context\r\n\r\nReturn Value:\r\n\r\n    Allocated workitem or NULL (if low memory).\r\n\r\n--*/\r\n{\r\n    PDSM_WORKITEM dsmWorkItem = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpAllocateWorkItem (DevObj %p): Entering function.\\n\",\r\n                DeviceObject));\r\n\r\n    dsmWorkItem = DsmpAllocatePool(NonPagedPoolNx,\r\n                                   sizeof(DSM_WORKITEM),\r\n                                   DSM_TAG_WORKITEM);\r\n    if (dsmWorkItem != NULL) {\r\n\r\n        dsmWorkItem->WorkItem = IoAllocateWorkItem(DeviceObject);\r\n        if (dsmWorkItem->WorkItem != NULL) {\r\n\r\n            dsmWorkItem->Context = Context;\r\n        } else {\r\n\r\n            DsmpFreePool(dsmWorkItem);\r\n            dsmWorkItem = NULL;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpAllocateWorkItem (DevObj %p): Exiting function. dsmWorkItem %p.\\n\",\r\n                DeviceObject,\r\n                dsmWorkItem));\r\n\r\n    return dsmWorkItem;\r\n}\r\n\r\n\r\nVOID\r\nDsmpFreeWorkItem(\r\n    _In_ IN PDSM_WORKITEM DsmWorkItem\r\n    )\r\n{\r\n    PVOID temp = DsmWorkItem;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpFreeWorkItem (WorkItem %p): Entering function.\\n\",\r\n                DsmWorkItem));\r\n\r\n    if (DsmWorkItem != NULL) {\r\n\r\n        if (DsmWorkItem->WorkItem != NULL) {\r\n            IoFreeWorkItem(DsmWorkItem->WorkItem);\r\n        }\r\n\r\n        DsmpFreePool(DsmWorkItem);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_IOCTL,\r\n                \"DsmpFreeWorkItem (WorkItem %p): Exiting function.\\n\",\r\n                temp));\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nDsmpFreeZombieGroupList(\r\n    _In_ IN PDSM_FAILOVER_GROUP FailGroup\r\n    )\r\n{\r\n     PLIST_ENTRY zombieEntry = NULL;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFreeZombieGroupList (FailGroup %p): Entering function.\\n\",\r\n                FailGroup));\r\n\r\n     while (!IsListEmpty(&FailGroup->ZombieGroupList)) {\r\n\r\n         zombieEntry = RemoveHeadList(&FailGroup->ZombieGroupList);\r\n\r\n         if (zombieEntry) {\r\n\r\n             DsmpFreePool(zombieEntry);\r\n         }\r\n     }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpFreeZombieGroupList (FailGroup %p): Exiting function.\\n\",\r\n                FailGroup));\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpGetDeviceALUAState(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_DEVICE_INFO DeviceInfo,\r\n    _In_opt_ IN PDSM_DEVICE_STATE DevState\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Helper routine to build the RTPG info and send it down to retrieve the\r\n    devInfo's current state.\r\n\r\nArguments:\r\n\r\n    DsmContext - DSM context.\r\n    DeviceInfo - DevInfo whose state needs to be changed.\r\n    DevState   - Current state of passed in DeviceInfo.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS or appropriate failure code.\r\n\r\n--*/\r\n{\r\n    PUCHAR targetPortGroupsInfo = NULL;\r\n    ULONG targetPortGroupsInfoLength = 0;\r\n    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup = NULL;\r\n    KIRQL irql;\r\n    NTSTATUS status;\r\n    ULONG index;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetDeviceALUAState (DevInfo %p): Entering function.\\n\",\r\n                DeviceInfo));\r\n\r\n    status = DsmpReportTargetPortGroups(DeviceInfo->TargetObject,\r\n                                        &targetPortGroupsInfo,\r\n                                        &targetPortGroupsInfoLength);\r\n\r\n\r\n    if (NT_SUCCESS(status) && targetPortGroupsInfo != NULL) {\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n        status = DsmpParseTargetPortGroupsInformation(DsmContext,\r\n                                                      DeviceInfo->Group,\r\n                                                      targetPortGroupsInfo,\r\n                                                      targetPortGroupsInfoLength);\r\n\r\n        for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n            targetPortGroup = DeviceInfo->Group->TargetPortGroupList[index];\r\n\r\n            if (targetPortGroup) {\r\n\r\n                DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState);\r\n            }\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n        if (DevState) {\r\n\r\n            *DevState = DeviceInfo->State;\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_GENERAL,\r\n                    \"DsmpGetDeviceALUAState (DevInfo %p): ReportTPG failed with %x.\\n\",\r\n                    DeviceInfo,\r\n                    status));\r\n    }\r\n\r\n    if (targetPortGroupsInfo) {\r\n\r\n        DsmpFreePool(targetPortGroupsInfo);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_GENERAL,\r\n                \"DsmpGetDeviceALUAState (DevInfo %p): Exiting function with status %x\\n\",\r\n                DeviceInfo,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpRegCopyTree(\r\n    _In_ IN HANDLE SourceKey,\r\n    _In_ IN HANDLE DestKey\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    Copies a reg subtree from source key to destination key.\r\n    This routine will first copy over all the key's values, and then\r\n    copy the subkeys, each time recursively handling the subkey's\r\n    values and its subtree.\r\n\r\nArguments:\r\n\r\n    SourceKey - Handle to the root of the subtree to copy over.\r\n    DestKey   - Handle to the root of the new tree.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS upon successfully coping over the tree.\r\n    Appropriate NT error code in case of failure.\r\n\r\n--*/\r\n{\r\n    ULONG numValues = 0;\r\n    ULONG numSubKeys = 0;\r\n    ULONG lengthOfValueName = 0;\r\n    ULONG lengthOfValueData = 0;\r\n    ULONG lengthOfKeyName = 0;\r\n    LPWSTR valueBuf = NULL;\r\n    BYTE *valueDataBuf = NULL;\r\n    ULONG valueDataType;\r\n    ULONG titleIndex;\r\n    HANDLE srcSubKey = NULL;\r\n    HANDLE destSubKey = NULL;\r\n    LPWSTR subKey = NULL;\r\n    NTSTATUS status;\r\n    PKEY_FULL_INFORMATION keyFullInfo = NULL;\r\n    ULONG length = sizeof(KEY_FULL_INFORMATION);\r\n    ULONG index = 0;\r\n    PKEY_VALUE_FULL_INFORMATION keyValueFullInfo = NULL;\r\n    PKEY_BASIC_INFORMATION keyBasicInfo = NULL;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRegCopyTree (SrcKey %p): Entering function.\\n\",\r\n                SourceKey));\r\n\r\n    if (!SourceKey || !DestKey) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    //\r\n    // Query the source key for information about number of subkeys, number of values, etc.\r\n    //\r\n    do {\r\n        if (keyFullInfo) {\r\n\r\n            DsmpFreePool(keyFullInfo);\r\n        }\r\n\r\n        keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED);\r\n\r\n        if (!keyFullInfo) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for key full info.\\n\",\r\n                        SourceKey));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            goto __Exit_DsmpRegCopyTree;\r\n        }\r\n\r\n        status = ZwQueryKey(SourceKey,\r\n                            KeyFullInformation,\r\n                            keyFullInfo,\r\n                            length,\r\n                            &length);\r\n\r\n    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegCopyTree (SrcKey %p): Failed to query key. Status %x.\\n\",\r\n                    SourceKey,\r\n                    status));\r\n\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    numSubKeys = keyFullInfo->SubKeys;\r\n    numValues = keyFullInfo->Values;\r\n    lengthOfKeyName = keyFullInfo->MaxNameLen + sizeof(WCHAR);\r\n    lengthOfValueName = keyFullInfo->MaxValueNameLen + sizeof(WCHAR);\r\n    lengthOfValueData = keyFullInfo->MaxValueDataLen + sizeof(WCHAR);\r\n\r\n    //\r\n    // Allocate a buffer for the name of the value\r\n    //\r\n    valueBuf = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                lengthOfValueName,\r\n                                DSM_TAG_REG_KEY_RELATED);\r\n    if (!valueBuf) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value name.\\n\",\r\n                    SourceKey));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    //\r\n    // Allocate a buffer for the value data\r\n    //\r\n    valueDataBuf = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                    lengthOfValueData,\r\n                                    DSM_TAG_REG_KEY_RELATED);\r\n\r\n    if (!valueDataBuf) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value's data.\\n\",\r\n                    SourceKey));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    //\r\n    // First enumerate all of the values\r\n    //\r\n    status = STATUS_SUCCESS;\r\n    for (index = 0; index < numValues && NT_SUCCESS(status); index++) {\r\n\r\n        UNICODE_STRING valueName;\r\n\r\n        length = sizeof(KEY_VALUE_FULL_INFORMATION);\r\n\r\n        do {\r\n\r\n            if (keyValueFullInfo) {\r\n\r\n                DsmpFreePool(keyValueFullInfo);\r\n            }\r\n\r\n            keyValueFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED);\r\n\r\n            if (!keyValueFullInfo) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for value full info.\\n\",\r\n                            SourceKey));\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n                goto __Exit_DsmpRegCopyTree;\r\n            }\r\n\r\n            //\r\n            // Get the information of the index'th value\r\n            //\r\n            status = ZwEnumerateValueKey(SourceKey,\r\n                                         index,\r\n                                         KeyValueFullInformation,\r\n                                         keyValueFullInfo,\r\n                                         length,\r\n                                         &length);\r\n\r\n        } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegCopyTree (SrcKey %p): Failed to enumerate key's value information. Status %x.\\n\",\r\n                        SourceKey,\r\n                        status));\r\n\r\n            goto __Exit_DsmpRegCopyTree;\r\n        }\r\n\r\n        //\r\n        // Capture the data type, data value, and value name.\r\n        //\r\n        titleIndex = keyValueFullInfo->TitleIndex;\r\n        valueDataType = keyValueFullInfo->Type;\r\n\r\n        RtlZeroMemory(valueDataBuf, lengthOfValueData);\r\n        RtlCopyMemory(valueDataBuf,\r\n                      (PUCHAR)keyValueFullInfo + keyValueFullInfo->DataOffset,\r\n                      keyValueFullInfo->DataLength);\r\n\r\n        RtlZeroMemory(valueBuf, lengthOfValueName);\r\n        RtlStringCbCopyNW(valueBuf, lengthOfValueName, keyValueFullInfo->Name, keyValueFullInfo->NameLength);\r\n        RtlInitUnicodeString(&valueName, valueBuf);\r\n\r\n        //\r\n        // Copy the value over to the new key\r\n        //\r\n        status = ZwSetValueKey(DestKey,\r\n                               &valueName,\r\n                               titleIndex,\r\n                               valueDataType,\r\n                               valueDataBuf,\r\n                               keyValueFullInfo->DataLength);\r\n    }\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegCopyTree (SrcKey %p): Failed to allocate set new key's value information. Status %x.\\n\",\r\n                    SourceKey,\r\n                    status));\r\n\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    //\r\n    // Allocate buffer for subkey name\r\n    //\r\n    subKey = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                              lengthOfKeyName,\r\n                              DSM_TAG_REG_KEY_RELATED);\r\n\r\n    if(!subKey) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for sub key name.\\n\",\r\n                    SourceKey));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        goto __Exit_DsmpRegCopyTree;\r\n    }\r\n\r\n    //\r\n    // Now Enumerate all of the subkeys\r\n    //\r\n    length = sizeof(KEY_BASIC_INFORMATION);\r\n    for(index = 0; index < numSubKeys && NT_SUCCESS(status); index++) {\r\n\r\n        UNICODE_STRING subKeyName;\r\n\r\n        do {\r\n            if (keyBasicInfo) {\r\n\r\n                DsmpFreePool(keyBasicInfo);\r\n            }\r\n\r\n            keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                            length,\r\n                                            DSM_TAG_REG_KEY_RELATED);\r\n\r\n            if (!keyBasicInfo) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_PNP,\r\n                            \"DsmpRegCopyTree (SrcKey %p): Failed to allocate resources for key basic info.\\n\",\r\n                            SourceKey));\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n                goto __Exit_DsmpRegCopyTree;\r\n            }\r\n\r\n            //\r\n            // Enumerate the index'th subkey\r\n            //\r\n            status = ZwEnumerateKey(SourceKey,\r\n                                    index,\r\n                                    KeyBasicInformation,\r\n                                    keyBasicInfo,\r\n                                    length,\r\n                                    &length);\r\n\r\n        } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegCopyTree (SrcKey %p): Failed to enumerate sub key's info. Status %x.\\n\",\r\n                        SourceKey,\r\n                        status));\r\n\r\n            goto __Exit_DsmpRegCopyTree;\r\n        }\r\n\r\n        RtlZeroMemory(subKey, lengthOfKeyName);\r\n        RtlStringCbCopyNW(subKey, lengthOfKeyName, keyBasicInfo->Name, keyBasicInfo->NameLength);\r\n        RtlInitUnicodeString(&subKeyName, subKey);\r\n\r\n        //\r\n        // Open a handle to the the subkey on the old device.\r\n        //\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &subKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   SourceKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        if (srcSubKey) {\r\n            ZwClose(srcSubKey);\r\n            srcSubKey = NULL;\r\n        }\r\n\r\n        status = ZwOpenKey(&srcSubKey,\r\n                           KEY_ALL_ACCESS,\r\n                           &objectAttributes);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegCopyTree (SrcKey %p): Failed to open reg key %ws. Status %x.\\n\",\r\n                        SourceKey,\r\n                        subKey,\r\n                        status));\r\n\r\n            goto __Exit_DsmpRegCopyTree;\r\n        }\r\n\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &subKeyName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   DestKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        if (destSubKey) {\r\n            ZwClose(destSubKey);\r\n            destSubKey = NULL;\r\n        }\r\n\r\n        //\r\n        // Create the subkey on the new device.\r\n        //\r\n        status = ZwCreateKey(&destSubKey,\r\n                             KEY_ALL_ACCESS,\r\n                             &objectAttributes,\r\n                             0,\r\n                             NULL,\r\n                             REG_OPTION_NON_VOLATILE,\r\n                             NULL);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegCopyTree (SrcKey %p): Failed to create reg key %ws. Status %x.\\n\",\r\n                        SourceKey,\r\n                        subKey,\r\n                        status));\r\n\r\n            goto __Exit_DsmpRegCopyTree;\r\n        }\r\n\r\n        //\r\n        // That's it. We've got everything we need (ie. handles to the two new\r\n        // subtrees' roots. Call recursively.\r\n        //\r\n        status = DsmpRegCopyTree(srcSubKey, destSubKey);\r\n    }\r\n\r\n__Exit_DsmpRegCopyTree:\r\n\r\n    if (keyFullInfo) {\r\n        DsmpFreePool(keyFullInfo);\r\n    }\r\n\r\n    if (valueBuf) {\r\n        DsmpFreePool(valueBuf);\r\n    }\r\n\r\n    if (valueDataBuf) {\r\n        DsmpFreePool(valueDataBuf);\r\n    }\r\n\r\n    if (keyValueFullInfo) {\r\n        DsmpFreePool(keyValueFullInfo);\r\n    }\r\n\r\n    if (subKey) {\r\n        DsmpFreePool(subKey);\r\n    }\r\n\r\n    if (keyBasicInfo) {\r\n        DsmpFreePool(keyBasicInfo);\r\n    }\r\n\r\n    if (srcSubKey) {\r\n        ZwClose(srcSubKey);\r\n    }\r\n\r\n    if (destSubKey) {\r\n        ZwClose(destSubKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRegCopyTree (SrcKey %p): Exiting function with status %x.\\n\",\r\n                SourceKey,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpRegDeleteTree(\r\n    _In_ IN HANDLE KeyRoot\r\n    )\r\n/*++\r\nRoutine Description:\r\n\r\n    This routine is a recursive worker that enumerates the subkeys\r\n    of a given key, applies itself to each one, then deletes itself.\r\n\r\nArguments:\r\n\r\n    KeyRoot - Supplies a handle to the root of subtree to be deleted.\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS - upon successful deletion of subtree.\r\n    Appropriate NT error code upon failure.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n    PKEY_FULL_INFORMATION keyFullInfo = NULL;\r\n    ULONG length = sizeof(KEY_FULL_INFORMATION);\r\n    ULONG numSubKeys;\r\n    ULONG lengthOfKeyName;\r\n    LPWSTR subKey = NULL;\r\n    PKEY_BASIC_INFORMATION keyBasicInfo = NULL;\r\n    ULONG index = 0;\r\n    HANDLE srcSubKey = NULL;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRegDeleteTree (SrcKey %p): Entering function.\\n\",\r\n                KeyRoot));\r\n\r\n    if (!KeyRoot) {\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpRegDeleteTree;\r\n    }\r\n\r\n    //\r\n    // Query the source key for information about number of subkeys and max\r\n    // length needed for subkey name.\r\n    //\r\n    do {\r\n        if (keyFullInfo) {\r\n\r\n            DsmpFreePool(keyFullInfo);\r\n        }\r\n\r\n        keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED);\r\n\r\n        if (!keyFullInfo) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for key full info.\\n\",\r\n                        KeyRoot));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            goto __Exit_DsmpRegDeleteTree;\r\n        }\r\n\r\n        status = ZwQueryKey(KeyRoot,\r\n                            KeyFullInformation,\r\n                            keyFullInfo,\r\n                            length,\r\n                            &length);\r\n\r\n    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpRegDeleteTree (SrcKey %p): Failed to query key. Status %x.\\n\",\r\n                    KeyRoot,\r\n                    status));\r\n\r\n        goto __Exit_DsmpRegDeleteTree;\r\n    }\r\n\r\n    numSubKeys = keyFullInfo->SubKeys;\r\n    lengthOfKeyName = keyFullInfo->MaxNameLen + sizeof(WCHAR);\r\n\r\n    if (numSubKeys) {\r\n\r\n        //\r\n        // Allocate buffer for subkey name\r\n        //\r\n        subKey = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                  lengthOfKeyName,\r\n                                  DSM_TAG_REG_KEY_RELATED);\r\n\r\n        if(!subKey) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for sub key.\\n\",\r\n                        KeyRoot));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            goto __Exit_DsmpRegDeleteTree;\r\n        }\r\n\r\n        //\r\n        // Now Enumerate all of the subkeys\r\n        //\r\n        index = numSubKeys - 1;\r\n        length = sizeof(KEY_BASIC_INFORMATION);\r\n        do {\r\n\r\n            UNICODE_STRING subKeyName;\r\n\r\n            do {\r\n                if (keyBasicInfo) {\r\n\r\n                    DsmpFreePool(keyBasicInfo);\r\n                }\r\n\r\n                keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                                length,\r\n                                                DSM_TAG_REG_KEY_RELATED);\r\n\r\n                if (!keyBasicInfo) {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpRegDeleteTree (SrcKey %p): Failed to allocate resources for key basic info.\\n\",\r\n                                KeyRoot));\r\n\r\n                    status = STATUS_INSUFFICIENT_RESOURCES;\r\n                    goto __Exit_DsmpRegDeleteTree;\r\n                }\r\n\r\n                //\r\n                // Enumerate the index'th subkey\r\n                //\r\n                status = ZwEnumerateKey(KeyRoot,\r\n                                        index,\r\n                                        KeyBasicInformation,\r\n                                        keyBasicInfo,\r\n                                        length,\r\n                                        &length);\r\n\r\n            } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                RtlZeroMemory(subKey, lengthOfKeyName);\r\n                RtlStringCbCopyNW(subKey, lengthOfKeyName, keyBasicInfo->Name, keyBasicInfo->NameLength);\r\n                RtlInitUnicodeString(&subKeyName, subKey);\r\n\r\n                //\r\n                // Open a handle to the the current root's subkey.\r\n                //\r\n                InitializeObjectAttributes(&objectAttributes,\r\n                                           &subKeyName,\r\n                                           (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                           KeyRoot,\r\n                                           (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n                status = ZwOpenKey(&srcSubKey,\r\n                                   KEY_ALL_ACCESS,\r\n                                   &objectAttributes);\r\n\r\n                if (!NT_SUCCESS(status)) {\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_PNP,\r\n                                \"DsmpRegDeleteTree (SrcKey %p): Failed to open key %ws. Status %x.\\n\",\r\n                                KeyRoot,\r\n                                subKey,\r\n                                status));\r\n\r\n                    goto __Exit_DsmpRegDeleteTree;\r\n                }\r\n\r\n                //\r\n                // Delete this key's subtree (recursively).\r\n                //\r\n                status = DsmpRegDeleteTree(srcSubKey);\r\n\r\n                ZwClose(srcSubKey);\r\n                srcSubKey = NULL;\r\n            }\r\n\r\n            index--;\r\n\r\n        } while (status != STATUS_NO_MORE_ENTRIES && (LONG)index >= 0);\r\n\r\n        if (status == STATUS_NO_MORE_ENTRIES) {\r\n\r\n            status = STATUS_SUCCESS;\r\n        }\r\n    }\r\n\r\n    ZwDeleteKey(KeyRoot);\r\n\r\n__Exit_DsmpRegDeleteTree:\r\n\r\n    if (srcSubKey) {\r\n        ZwClose(srcSubKey);\r\n    }\r\n\r\n    if (keyFullInfo) {\r\n        DsmpFreePool(keyFullInfo);\r\n    }\r\n\r\n    if (subKey) {\r\n        DsmpFreePool(subKey);\r\n    }\r\n\r\n    if (keyBasicInfo) {\r\n        DsmpFreePool(keyBasicInfo);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpRegDeleteTree (SrcKey %p): Exiting function with status %x.\\n\",\r\n                KeyRoot,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\n#if defined (_WIN64)\r\nVOID\r\nDsmpPassThroughPathTranslate32To64(\r\n    _In_ IN PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32,\r\n    _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    On WIN64, the SCSI_PASS_THROUGH field of the MPIO_PASS_THROUGH_PATH structure\r\n    sent down by a 32-bit application must be marshaled into a 64-bit version\r\n    of the structure.  This function performs that marshaling.\r\n\r\nArguments:\r\n\r\n    MpioPassThroughPath32 - Supplies a pointer to a 32-bit MPIO_PASS_THROUGH_PATH\r\n                            struct.\r\n\r\n    MpioPassThroughPath64 - Supplies a pointer to a 64-bit MPIO_PASS_THROUGH_PATH\r\n                            structure, into which we'll copy the marshaled\r\n                            32-bit data.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n{\r\n    //\r\n    // Copy the first set of fields out of the 32-bit structure.  These\r\n    // fields all line up between the 32 & 64 bit versions.\r\n    //\r\n    // Note that we do NOT adjust the length in the SrbControl.  This is to\r\n    // allow the calling routine to compare the length of the actual\r\n    // control area against the offsets embedded within.  If we adjusted the\r\n    // length then requests with the sense area backed against the control\r\n    // area would be rejected because the 64-bit control area is 4 bytes\r\n    // longer.\r\n    //\r\n    RtlCopyMemory(MpioPassThroughPath64,\r\n                  MpioPassThroughPath32,\r\n                  FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset));\r\n\r\n    //\r\n    // Copy over the CDB.\r\n    //\r\n    RtlCopyMemory(MpioPassThroughPath64->PassThrough.Cdb,\r\n                  MpioPassThroughPath32->PassThrough.Cdb,\r\n                  16 * sizeof(UCHAR)\r\n                  );\r\n\r\n    //\r\n    // Copy over the rest of the fields of the structure.\r\n    //\r\n    MpioPassThroughPath64->Version = MpioPassThroughPath32->Version;\r\n    MpioPassThroughPath64->Length = MpioPassThroughPath32->Length;\r\n    MpioPassThroughPath64->Flags = MpioPassThroughPath32->Flags;\r\n    MpioPassThroughPath64->PortNumber = MpioPassThroughPath32->PortNumber;\r\n    MpioPassThroughPath64->MpioPathId = MpioPassThroughPath32->MpioPathId;\r\n\r\n    //\r\n    // Copy the fields that follow the ULONG_PTR.\r\n    //\r\n    MpioPassThroughPath64->PassThrough.DataBufferOffset = (ULONG_PTR)MpioPassThroughPath32->PassThrough.DataBufferOffset;\r\n    MpioPassThroughPath64->PassThrough.SenseInfoOffset = MpioPassThroughPath32->PassThrough.SenseInfoOffset;\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nDsmpPassThroughPathTranslate64To32(\r\n    _In_ IN PMPIO_PASS_THROUGH_PATH MpioPassThroughPath64,\r\n    _Inout_ IN OUT PMPIO_PASS_THROUGH_PATH32 MpioPassThroughPath32\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    On WIN64, the SCSI_PASS_THROUGH field of MPIO_PASS_THROUGH_PATH structure\r\n    sent down by a 32-bit application must be marshaled into a 64-bit version\r\n    of the structure.  This function marshals a 64-bit version of the structure\r\n    back into a 32-bit version.\r\n\r\nArguments:\r\n\r\n    MpioPassThroughPath64 - Supplies a pointer to a 64-bit MPIO_PASS_THROUGH_PATH\r\n                            struct.\r\n\r\n    MpioPassThroughPath32 - Supplies the address of a pointer to a 32-bit\r\n                            MPIO_PASS_THROUGH_PATH structure, into which we'll\r\n                            copy the marshaled 64-bit data.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n{\r\n    //\r\n    // Copy back the fields through the data offsets.\r\n    //\r\n    RtlCopyMemory(MpioPassThroughPath32,\r\n                  MpioPassThroughPath64,\r\n                  FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset));\r\n\r\n\r\n    //\r\n    // Copy over the CDB.\r\n    //\r\n    RtlCopyMemory(MpioPassThroughPath32->PassThrough.Cdb,\r\n                  MpioPassThroughPath64->PassThrough.Cdb,\r\n                  16 * sizeof(UCHAR)\r\n                  );\r\n\r\n    //\r\n    // Copy over the rest of the fields of the structure.\r\n    //\r\n    MpioPassThroughPath32->Version = MpioPassThroughPath64->Version;\r\n    MpioPassThroughPath32->Length = MpioPassThroughPath64->Length;\r\n    MpioPassThroughPath32->Flags = MpioPassThroughPath64->Flags;\r\n    MpioPassThroughPath32->PortNumber = MpioPassThroughPath64->PortNumber;\r\n    MpioPassThroughPath32->MpioPathId = MpioPassThroughPath64->MpioPathId;\r\n\r\n    return;\r\n}\r\n#endif\r\n\r\n\r\nNTSTATUS\r\nDsmpGetMaxPRRetryTime(\r\n    _In_ IN PDSM_CONTEXT Context,\r\n    _Out_ OUT PULONG RetryTime\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to get the max time period for which a PR request failing\r\n    with a retry-able unit attention should be retried before failing back to MSCS.\r\n    The value is determined by querying the value found at\r\n    \"msdsm\\Parameters\\DsmMaximumStateTransitionTime\"\r\n\r\nArguments:\r\n\r\n    Context - The DSM Context value.\r\n    RetryTime - The output parameter that will receive the value to be used.\r\n\r\nReturn Value:\r\n\r\n    Status of the RtlQueryRegistryValues call.\r\n\r\n--*/\r\n{\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n    WCHAR registryKeyName[56] = {0};\r\n    NTSTATUS status;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetMaxPRRetryTime (DsmCtxt %p): Entering function.\\n\",\r\n                Context));\r\n\r\n    NT_ASSERT(RetryTime);\r\n    *RetryTime = DSM_MAX_PR_UNIT_ATTENTION_RETRY_TIME;\r\n\r\n    RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n    //\r\n    // Build the key value name that we want as the base of the query.\r\n    //\r\n    RtlStringCbPrintfW(registryKeyName,\r\n                       sizeof(registryKeyName),\r\n                       DSM_PARAMETER_PATH_W);\r\n\r\n    //\r\n    // The query table has two entries. One for the state transition time and\r\n    // the second which is the 'NULL' terminator.\r\n    //\r\n    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;\r\n    queryTable[0].Name = DSM_MAX_STATE_TRANSITION_TIME_VALUE_NAME;\r\n    queryTable[0].EntryContext = RetryTime;\r\n    queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n    status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,\r\n                                    registryKeyName,\r\n                                    queryTable,\r\n                                    registryKeyName,\r\n                                    NULL);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpGetMaxPRRetryTime (DsmCtxt %p): Exiting function with status %x.\\n\",\r\n                Context,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryCacheInformationFromRegistry(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _Out_ OUT PBOOLEAN UseCacheForLeastBlocks,\r\n    _Out_ OUT PULONGLONG CacheSizeForLeastBlocks\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to get the information about whether sequential IO\r\n    should use the same path when employing Least Blocks policy.\r\n    It also queries the size of cache set by the administrator.\r\n    The value is determined by querying the value found at\r\n    \"msdsm\\Parameters\\DsmUseCacheForLeastBlocks\" and\r\n    \"msdsm\\Parameters\\DsmCacheSizeForLeastBlocks\"\r\n\r\nArguments:\r\n\r\n    Context - The DSM Context value.\r\n    UseCacheForLeastBlocks - Returns the flag that indicates whether or not to\r\n                                use same path for sequential IO when LB policy\r\n                                is Least Blocks.\r\n    CacheSizeForLeastBlocks - Returns the size of the cache (in bytes) set by\r\n                                the Admin to indicate the amount of sequential\r\n                                data that should be use the same path when LB\r\n                                policy is Least Blocks.\r\n\r\nReturn Value:\r\n\r\n    Status of the RtlQueryRegistryValues call.\r\n\r\n--*/\r\n{\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0};\r\n    WCHAR registryKeyName[56] = {0};\r\n    HANDLE parametersKey = NULL;\r\n    UNICODE_STRING keyValueName;\r\n    NTSTATUS status;\r\n    struct _cacheSizeForLeastBlocks {\r\n        KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;\r\n        ULONGLONG Data;\r\n    } cacheSizeForLeastBlocks;\r\n    ULONG length = 0;\r\n    BOOLEAN useCacheForLeastBlocksDefault = FALSE;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryCacheInformationFromRegistry (DsmCtxt %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    NT_ASSERT(UseCacheForLeastBlocks);\r\n    NT_ASSERT(CacheSizeForLeastBlocks);\r\n\r\n    RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n    //\r\n    // Build the key value name that we want as the base of the query.\r\n    //\r\n    RtlStringCbPrintfW(registryKeyName,\r\n                       sizeof(registryKeyName),\r\n                       DSM_PARAMETER_PATH_W);\r\n\r\n    //\r\n    // The query table has two entries. One for whether to use cache, and\r\n    // and the second which is the 'NULL' terminator.\r\n    //\r\n    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;\r\n    queryTable[0].Name = DSM_USE_CACHE_FOR_LEAST_BLOCKS;\r\n    queryTable[0].EntryContext = UseCacheForLeastBlocks;\r\n    queryTable[0].DefaultType  = (REG_BINARY << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_BINARY;\r\n    queryTable[0].DefaultLength = sizeof(BOOLEAN);\r\n    queryTable[0].DefaultData = &useCacheForLeastBlocksDefault;\r\n\r\n    status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,\r\n                                    registryKeyName,\r\n                                    queryTable,\r\n                                    registryKeyName,\r\n                                    NULL);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        status = DsmpOpenDsmServicesParametersKey(KEY_QUERY_VALUE, &parametersKey);\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            RtlInitUnicodeString(&keyValueName, DSM_CACHE_SIZE_FOR_LEAST_BLOCKS);\r\n\r\n            status = ZwQueryValueKey(parametersKey,\r\n                                     &keyValueName,\r\n                                     KeyValuePartialInformation,\r\n                                     &cacheSizeForLeastBlocks,\r\n                                     sizeof(cacheSizeForLeastBlocks),\r\n                                     &length);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                NT_ASSERT(cacheSizeForLeastBlocks.KeyValueInfo.DataLength == sizeof(ULONGLONG));\r\n                *CacheSizeForLeastBlocks = *((ULONGLONG UNALIGNED *)&(cacheSizeForLeastBlocks.KeyValueInfo.Data));\r\n            }\r\n        }\r\n\r\n        if (parametersKey) {\r\n            ZwClose(parametersKey);\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_PNP,\r\n                \"DsmpQueryCacheInformationFromRegistry (DsmCtxt %p): Exiting function with status %x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\nBOOLEAN\r\nDsmpConvertSharedSpinLockToExclusive(\r\n    _Inout_ _Requires_lock_held_(*_Curr_) PEX_SPIN_LOCK SpinLock\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is a wrapper around ExTryConvertSharedSpinLockExclusive() that\r\n    guarantees the given EX_SPIN_LOCK will be acquired in Exclusive mode once\r\n    this function returns.\r\n\r\n    It's possible the lock may be released and re-acquired within this function\r\n    so the caller should be very careful about the use of this function.\r\n\r\n    N.B. The caller MUST have acquired the given lock in Shared mode before\r\n    calling this function.\r\n\r\nArguments:\r\n\r\n    SpinLock - The EX_SPIN_LOCK to convert from Shared to Exclusive mode.\r\n\r\nReturn Value:\r\n\r\n    Status of the ExTryConvertSharedSpinLockExclusive() call.  This function\r\n    will always return with the lock acquired in Exclusive mode.  The FALSE is\r\n    returned, then the lock had to be released and re-acquired.\r\n\r\n--*/\r\n{\r\n    BOOLEAN converted = FALSE;\r\n\r\n    converted = (BOOLEAN)ExTryConvertSharedSpinLockExclusive(SpinLock);\r\n\r\n    //\r\n    // If the conversion attempt failed, then we should release the lock from\r\n    // Shared mode and try to pick it back up in Exclusive mode to guarantee\r\n    // this function will always return with the lock in Exclusive mode.\r\n    //\r\n    if (converted == FALSE) {\r\n        ExReleaseSpinLockSharedFromDpcLevel(SpinLock);\r\n        ExAcquireSpinLockExclusiveAtDpcLevel(SpinLock);\r\n    }\r\n\r\n    return converted;\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/wmi.c",
    "content": "\r\n/*++\r\n\r\nCopyright (C) 2004-2010  Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    wmi.c\r\n\r\nAbstract:\r\n\r\n    This driver is the Microsoft Device Specific Module (DSM).\r\n    It exports behaviours that mpio.sys will use to determine how to\r\n    multipath SPC-3 compliant devices.\r\n\r\n    This file contains WMI related functions.\r\n\r\nEnvironment:\r\n\r\n    kernel mode only\r\n\r\nNotes:\r\n\r\n--*/\r\n\r\n\r\n\r\n#include \"precomp.h\"\r\n#include \"msdsmwmi.h\"\r\n#include \"msdsmdsm.h\"\r\n\r\n#ifdef DEBUG_USE_WPP\r\n#include \"wmi.tmh\"\r\n#endif\r\n\r\n#pragma warning (disable:4305)\r\n\r\nextern BOOLEAN DoAssert;\r\n\r\n#define USE_BINARY_MOF_RESOURCE\r\n\r\n#define DSM_INVALID_LOAD_BALANCE_POLICY STATUS_INVALID_PARAMETER\r\n#define DSM_UNSUPPORTED_VERSION         STATUS_NOT_SUPPORTED\r\n\r\n//\r\n// Max length for each of the DeviceId strings (supported device list)\r\n// NOTE: This must be kept in sync with msdsmdsm.mof\r\n//\r\n#define MSDSM_MAX_DEVICE_ID_LENGTH          31\r\n#define MSDSM_MAX_DEVICE_ID_SIZE            (MSDSM_MAX_DEVICE_ID_LENGTH * sizeof(WCHAR))\r\n\r\n//\r\n// List of supported DSM-centric guids\r\n//\r\nGUID MSDSM_SUPPORTED_DEVICES_LISTGUID = MSDSM_SUPPORTED_DEVICES_LISTGuid;\r\nGUID MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID = MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGuid;\r\nGUID MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID = MSDSM_DEFAULT_LOAD_BALANCE_POLICYGuid;\r\n\r\n//\r\n// Symbolic names for the DSM-centric guid indexes\r\n//\r\n#define MSDSM_SUPPORTED_DEVICES_LISTGUID_Index              0\r\n#define MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index 1\r\n#define MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index         2\r\n\r\nWMIGUIDREGINFO MSDsmGuidList[] = {\r\n    {\r\n        &MSDSM_SUPPORTED_DEVICES_LISTGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID,\r\n        1,\r\n        0\r\n    }\r\n};\r\n\r\n#define MSDsmGuidCount (sizeof(MSDsmGuidList) / sizeof(WMIGUIDREGINFO))\r\n\r\n//\r\n// List of supported Device-centric guids\r\n//\r\nGUID DSM_LBOperationsGUID = DSM_LB_OperationsGuid;\r\nGUID DSM_QueryLBPolicyGUID  = DSM_QueryLBPolicyGuid;\r\nGUID DSM_QuerySupportedLBPoliciesGUID = DSM_QuerySupportedLBPoliciesGuid;\r\nGUID DSM_QueryDsmUniqueIdGUID = DSM_QueryUniqueIdGuid;\r\nGUID DSM_QueryLBPolicyV2GUID = DSM_QueryLBPolicy_V2Guid;\r\nGUID DSM_QuerySupportedLBPoliciesV2GUID = DSM_QuerySupportedLBPolicies_V2Guid;\r\nGUID MSDSM_DEVICE_PERFGUID = MSDSM_DEVICE_PERFGuid;\r\nGUID MSDSM_WMI_METHODSGUID = MSDSM_WMI_METHODSGuid;\r\n\r\n//\r\n// Symbolic names for the Device-centric guid indexes\r\n//\r\n#define DSM_LBOperationsGUID_Index                  0\r\n#define DSM_QueryLBPolicyGUID_Index                 1\r\n#define DSM_QuerySupportedLBPoliciesGUID_Index      2\r\n#define DSM_QueryDsmUniqueIdGUID_Index              3\r\n#define DSM_QueryLBPolicyV2GUID_Index               4\r\n#define DSM_QuerySupportedLBPoliciesV2GUID_Index    5\r\n#define MSDSM_DEVICE_PERFGuidIndex                  6\r\n#define MSDSM_WMI_METHODSGuidIndex                  7\r\n\r\nWMIGUIDREGINFO DsmGuidList[] = {\r\n    {\r\n        &DSM_LBOperationsGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &DSM_QueryLBPolicyGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &DSM_QuerySupportedLBPoliciesGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &DSM_QueryDsmUniqueIdGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &DSM_QueryLBPolicyV2GUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &DSM_QuerySupportedLBPoliciesV2GUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &MSDSM_DEVICE_PERFGUID,\r\n        1,\r\n        0\r\n    },\r\n\r\n    {\r\n        &MSDSM_WMI_METHODSGUID,\r\n        1,\r\n        0\r\n    }\r\n};\r\n\r\n#define DsmGuidCount (sizeof(DsmGuidList) / sizeof(WMIGUIDREGINFO))\r\n\r\nVOID\r\nDsmpDsmWmiInitialize(\r\n    _In_ IN PDSM_WMILIB_CONTEXT WmiGlobalInfo,\r\n    _In_ IN PUNICODE_STRING RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine intializes the DSM-specific WmiGlobalInfo structure that is passed\r\n    back to MPIO during DriverEntry.\r\n\r\nArguments:\r\n\r\n    WmiGlobalInfo - WMI information structure to initialize.\r\n    RegistryPath  - Registry path to the service key for this driver.\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpDsmWmiInitialize (RegPath %ws): Entering function.\\n\",\r\n                RegistryPath->Buffer));\r\n\r\n    RtlZeroMemory(WmiGlobalInfo, sizeof(DSM_WMILIB_CONTEXT));\r\n\r\n    //\r\n    // Build the mof resource name. This tells wmi via the busdriver,\r\n    // where to find the mof data. This is found in the .rc.\r\n    //\r\n    RtlInitUnicodeString(&WmiGlobalInfo->MofResourceName, L\"DsmMofResourceName\");\r\n\r\n    //\r\n    // This will jam in the entry points and guids for supported WMI\r\n    // operations. SetDataBlock, SetDataItem, ExecuteMethod and FunctionControl are\r\n    // currently not needed, so leave them set to zero.\r\n    //\r\n    WmiGlobalInfo->GuidCount = MSDsmGuidCount;\r\n    WmiGlobalInfo->GuidList = MSDsmGuidList;\r\n\r\n    WmiGlobalInfo->QueryWmiDataBlockEx = DsmGlobalQueryData;\r\n    WmiGlobalInfo->SetWmiDataBlockEx = DsmGlobalSetData;\r\n\r\n    //\r\n    // Allocate a buffer for the reg. path.\r\n    //\r\n    WmiGlobalInfo->RegistryPath.Buffer = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                          RegistryPath->MaximumLength,\r\n                                                          DSM_TAG_REG_PATH);\r\n    if (WmiGlobalInfo->RegistryPath.Buffer) {\r\n\r\n        //\r\n        // Set maximum length of the new string and copy it.\r\n        //\r\n        WmiGlobalInfo->RegistryPath.MaximumLength = RegistryPath->MaximumLength;\r\n\r\n        RtlCopyUnicodeString(&WmiGlobalInfo->RegistryPath, RegistryPath);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DsmpDsmWmiInitialize (RegPath %ws): Failed to allocate memory for Registry path in WmiGlobalInfo.\\n\",\r\n                    RegistryPath->Buffer));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpDsmWmiInitialize (RegPath %ws): Exiting function.\\n\",\r\n                RegistryPath->Buffer));\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmGlobalQueryData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG InstanceCount,\r\n    _Inout_ IN OUT PULONG InstanceLengthArray,\r\n    _In_ IN ULONG BufferAvail,\r\n    _Out_writes_to_(BufferAvail, *DataLength) OUT PUCHAR Buffer,\r\n    _Out_ OUT PULONG DataLength,\r\n    ...\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the WMI query entry point for DSM-specific GUIDs. The index into the\r\n    GUID array is found and assuming the buffer is large enough, the data will be\r\n    copied over.\r\n\r\nArguments:\r\n\r\n    DsmContext - Global DSM Context\r\n    DsmIds - Dsm Ids\r\n    Irp - The WMI Irp\r\n    GuidIndex - Index into the WMIGUIDINFO array\r\n    InstanceIndex - Index of the data instance\r\n    InstanceCount - Number of instances\r\n    InstanceLengthArray - Array of ULONGs that indicate per-instance data lengths.\r\n    BufferAvail - Size of the buffer in which data is returned.\r\n    Buffer - Buffer in which the data is returned.\r\n    DataLength - Storage for the actual data length written.\r\n\r\nReturn Value:\r\n\r\n    STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to\r\n                              to return all the available data.\r\n    STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry\r\n                                in the reginfo array.\r\n    STATUS_SUCCESS - On success.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND;\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n    UNREFERENCED_PARAMETER(InstanceLengthArray);\r\n    UNREFERENCED_PARAMETER(InstanceCount);\r\n    UNREFERENCED_PARAMETER(InstanceIndex);\r\n    UNREFERENCED_PARAMETER(Irp);\r\n    UNREFERENCED_PARAMETER(DsmIds);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmGlobalQueryData (DsmContext %p): Entering function - GuidIndex %u.\\n\",\r\n                DsmContext,\r\n                GuidIndex));\r\n\r\n    //\r\n    // Check the GuidIndex - the index into the DsmGuildList array - to see\r\n    // whether this is a supported GUID or not.\r\n    //\r\n    switch(GuidIndex) {\r\n\r\n        case MSDSM_SUPPORTED_DEVICES_LISTGUID_Index: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQuerySupportedDevicesList(DsmContext,\r\n                                                   BufferAvail,\r\n                                                   DataLength,\r\n                                                   Buffer);\r\n\r\n            break;\r\n        }\r\n\r\n        case MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQueryTargetsDefaultPolicy(DsmContext,\r\n                                                   BufferAvail,\r\n                                                   DataLength,\r\n                                                   Buffer);\r\n\r\n            break;\r\n        }\r\n\r\n        case MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQueryDsmDefaultPolicy(DsmContext,\r\n                                               BufferAvail,\r\n                                               DataLength,\r\n                                               Buffer);\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmGlobalQueryData (DsmContext %p): Unknown GuidIndex %d.\\n\",\r\n                        DsmContext,\r\n                        GuidIndex));\r\n\r\n            *DataLength = 0;\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmGlobalQueryData (DsmContext %p): Exiting function with status 0x%x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmGlobalSetData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG BufferAvail,\r\n    _In_reads_bytes_(BufferAvail) IN PUCHAR Buffer,\r\n    ...\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the WMI set entry point for DSM-specific GUIDs. The index into the\r\n    GUID array is found and the contents of the buffer are set to the passed in\r\n    instance index.\r\n\r\nArguments:\r\n\r\n    DsmContext - Global DSM Context\r\n    DsmIds - Dsm Ids\r\n    Irp - The WMI Irp\r\n    GuidIndex - Index into the WMIGUIDINFO array\r\n    InstanceIndex - Index of the data instance\r\n    BufferAvail - Size of the buffer in which data is returned.\r\n    Buffer - Buffer in which the data is returned.\r\n\r\nReturn Value:\r\n\r\n    STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to\r\n                              to return all the available data.\r\n    STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry\r\n                                in the reginfo array.\r\n    STATUS_SUCCESS - On success.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND;\r\n    ULONG dataLength;\r\n    PDSM_CONTEXT dsmContext = (PDSM_CONTEXT)DsmContext;\r\n\r\n    UNREFERENCED_PARAMETER(DsmIds);\r\n    UNREFERENCED_PARAMETER(Irp);\r\n    UNREFERENCED_PARAMETER(InstanceIndex);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmGlobalSetData (DsmContext %p): Entering function - GuidIndex %u.\\n\",\r\n                DsmContext,\r\n                GuidIndex));\r\n\r\n    switch (GuidIndex) {\r\n\r\n        case MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: {\r\n\r\n            PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY targetsPolicyInfo = (PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY)Buffer;\r\n            PMSDSM_TARGET_DEFAULT_POLICY_INFO targetPolicyInfo;\r\n            PWSTR vidpidIndex;\r\n            DSM_LOAD_BALANCE_TYPE loadBalancePolicy;\r\n            ULONGLONG preferredPath;\r\n            DWORD index;\r\n            NTSTATUS errorStatus = STATUS_SUCCESS;\r\n\r\n            //\r\n            // Determine the correct buffer size.\r\n            //\r\n            dataLength = AlignOn8Bytes(FIELD_OFFSET(MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY, TargetDefaultPolicyInfo));\r\n\r\n            if (BufferAvail < dataLength) {\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size. Status %x\\n\",\r\n                            DsmContext,\r\n                            GuidIndex,\r\n                            status));\r\n                break;\r\n            }\r\n\r\n            dataLength += targetsPolicyInfo->NumberDevices * sizeof(MSDSM_TARGET_DEFAULT_POLICY_INFO);\r\n\r\n            if (BufferAvail < dataLength) {\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size for %u targets. Status %x\\n\",\r\n                            DsmContext,\r\n                            GuidIndex,\r\n                            targetsPolicyInfo->NumberDevices,\r\n                            status));\r\n                break;\r\n            }\r\n\r\n            targetPolicyInfo = targetsPolicyInfo->TargetDefaultPolicyInfo;\r\n\r\n            for (index = 0; index < targetsPolicyInfo->NumberDevices; index++, targetPolicyInfo++) {\r\n\r\n                size_t stringLength = 0;\r\n\r\n                //\r\n                // First ensure that these values make sense. The VID/PID should be\r\n                // a string of 8+16 chars and the LB policy must be one that MSDSM\r\n                // supports.\r\n                //\r\n                // The WMI string is like a unicode string with the first USHORT\r\n                // containing the size.\r\n                //\r\n                vidpidIndex = targetPolicyInfo->HardwareId;\r\n                vidpidIndex++;\r\n\r\n                if (!NT_SUCCESS(RtlStringCchLengthW(vidpidIndex, DSM_VENDPROD_ID_LEN + 1, &stringLength)) || (stringLength != DSM_VENDPROD_ID_LEN)) {\r\n\r\n                    errorStatus = STATUS_INVALID_PARAMETER;\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_WMI,\r\n                                \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Ignoring incorrect VID/PID %ws. Status %x\\n\",\r\n                                DsmContext,\r\n                                GuidIndex,\r\n                                vidpidIndex,\r\n                                errorStatus));\r\n                    continue;\r\n                }\r\n\r\n                if (targetPolicyInfo->LoadBalancePolicy >= DSM_LB_VENDOR_SPECIFIC) {\r\n\r\n                    errorStatus = STATUS_INVALID_PARAMETER;\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_WMI,\r\n                                \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Ignoring policy %u for %ws. Status %x\\n\",\r\n                                DsmContext,\r\n                                GuidIndex,\r\n                                targetPolicyInfo->LoadBalancePolicy,\r\n                                vidpidIndex,\r\n                                errorStatus));\r\n                    continue;\r\n                }\r\n\r\n                loadBalancePolicy = targetPolicyInfo->LoadBalancePolicy;\r\n                preferredPath = (ULONGLONG)((ULONG_PTR)targetPolicyInfo->PreferredPath);\r\n\r\n                //\r\n                // Now update/create the key in the registry with the LB policy info.\r\n                // If the LB policy is specified as 0, delete the key.\r\n                //\r\n                status = DsmpSetVidPidLBPolicyInRegistry(vidpidIndex, loadBalancePolicy, preferredPath);\r\n\r\n                //\r\n                // If above was successful, find the group that corresponds to this\r\n                // targetId and update its LB policy as well as the states of the paths\r\n                //\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    DsmpSetLBForVidPidPolicyAdjustment(dsmContext, vidpidIndex, loadBalancePolicy, preferredPath);\r\n                } else {\r\n                    errorStatus = status;\r\n                }\r\n            }\r\n\r\n            //\r\n            // If any error occurred, return the last error.\r\n            //\r\n            if (!NT_SUCCESS(errorStatus)) {\r\n                status = errorStatus;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case MSDSM_DEFAULT_LOAD_BALANCE_POLICYGUID_Index: {\r\n\r\n            PMSDSM_DEFAULT_LOAD_BALANCE_POLICY dsmPolicyInfo = (PMSDSM_DEFAULT_LOAD_BALANCE_POLICY)Buffer;\r\n            DSM_LOAD_BALANCE_TYPE loadBalancePolicy;\r\n            ULONGLONG preferredPath;\r\n\r\n            //\r\n            // Determine the correct buffer size.\r\n            //\r\n            dataLength = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY);\r\n\r\n            if (BufferAvail < dataLength) {\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Incorrect buffer size. Status %x\\n\",\r\n                            DsmContext,\r\n                            GuidIndex,\r\n                            status));\r\n                break;\r\n            }\r\n\r\n            loadBalancePolicy = dsmPolicyInfo->LoadBalancePolicy;\r\n            preferredPath = (ULONGLONG)((ULONG_PTR)dsmPolicyInfo->PreferredPath);\r\n\r\n            //\r\n            // First ensure that the values make sense.\r\n            //\r\n            if (loadBalancePolicy >= DSM_LB_VENDOR_SPECIFIC) {\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmGlobalSetData (DsmContext %p): GuidIndex %u. Invalid policy %u specified. Status %x\\n\",\r\n                            DsmContext,\r\n                            GuidIndex,\r\n                            loadBalancePolicy,\r\n                            status));\r\n\r\n            } else {\r\n\r\n                //\r\n                // Update/create the values in the registry with the LB policy info.\r\n                // If the LB policy is specified as 0, delete the values.\r\n                //\r\n                status = DsmpSetDsmLBPolicyInRegistry(loadBalancePolicy, preferredPath);\r\n\r\n                //\r\n                // If above is successful, find the groups that haven't had their LB policy\r\n                // explicitly set or haven't had their policy set in accordance with target\r\n                // hardware id. For each of these, adjust the states of the paths as well.\r\n                //\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    DsmpSetLBForDsmPolicyAdjustment(dsmContext, loadBalancePolicy, preferredPath);\r\n                }\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmGlobalSetData (DsmContext %p): Unknown GuidIndex %d.\\n\",\r\n                        DsmContext,\r\n                        GuidIndex));\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmGlobalSetData (DsmContext %p): Exiting function with status 0x%x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmpWmiInitialize(\r\n    _In_ IN PDSM_WMILIB_CONTEXT WmiInfo,\r\n    _In_ IN PUNICODE_STRING RegistryPath\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine intializes the Device-specific WmiInfo structure that is passed\r\n    back to MPIO during DriverEntry.\r\n\r\nArguments:\r\n\r\n    WmiInfo - WMI information structure to initialize.\r\n    RegistryPath - Registry path to the service key for this driver.\r\n\r\nReturn Value:\r\n\r\n    None\r\n\r\n--*/\r\n{\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpWmiInitialize (RegPath %ws): Entering function.\\n\",\r\n                RegistryPath->Buffer));\r\n\r\n    RtlZeroMemory(WmiInfo, sizeof(DSM_WMILIB_CONTEXT));\r\n\r\n    //\r\n    // Build the mof resource name. This tells wmi via the busdriver,\r\n    // where to find the mof data. This is found in the .rc.\r\n    //\r\n    RtlInitUnicodeString(&WmiInfo->MofResourceName, L\"MofResourceName\");\r\n\r\n    //\r\n    // This will jam in the entry points and guids for supported WMI\r\n    // operations. SetDataBlock, SetDataItem, and FunctionControl are\r\n    // currently not needed, so leave them set to zero.\r\n    //\r\n    WmiInfo->GuidCount = DsmGuidCount;\r\n    WmiInfo->GuidList = DsmGuidList;\r\n\r\n    WmiInfo->QueryWmiDataBlockEx = DsmQueryData;\r\n    WmiInfo->ExecuteWmiMethodEx = DsmExecuteMethod;\r\n\r\n    //\r\n    // Allocate a buffer for the reg. path.\r\n    //\r\n    WmiInfo->RegistryPath.Buffer = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                    RegistryPath->MaximumLength,\r\n                                                    DSM_TAG_REG_PATH);\r\n    if (WmiInfo->RegistryPath.Buffer) {\r\n\r\n        //\r\n        // Set maximum length of the new string and copy it.\r\n        //\r\n        WmiInfo->RegistryPath.MaximumLength = RegistryPath->MaximumLength;\r\n\r\n        RtlCopyUnicodeString(&WmiInfo->RegistryPath, RegistryPath);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_INIT,\r\n                    \"DsmpWmiInitialize (RegPath %ws): Failed to allocate memory for Registry path in WMIInfo.\\n\",\r\n                    RegistryPath->Buffer));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_INIT,\r\n                \"DsmpWmiInitialize (RegPath %ws): Exiting function.\\n\",\r\n                RegistryPath->Buffer));\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmQueryData(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG InstanceCount,\r\n    _Inout_ IN OUT PULONG InstanceLengthArray,\r\n    _In_ IN ULONG BufferAvail,\r\n    _When_(GuidIndex == DSM_LBOperationsGUID_Index || GuidIndex == MSDSM_WMI_METHODSGuidIndex, _Pre_notnull_ _Const_)\r\n    _When_(!(GuidIndex == DSM_LBOperationsGUID_Index || GuidIndex == MSDSM_WMI_METHODSGuidIndex), _Out_writes_to_(BufferAvail, *DataLength))\r\n          OUT PUCHAR Buffer,\r\n    _Out_ OUT PULONG DataLength,\r\n    ...\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This is the main WMI query entry point. The index into the GUID array is found\r\n    and assuming the buffer is large enough, the data will be copied over.\r\n\r\nArguments:\r\n\r\n    DsmContext - Global DSM Context\r\n    DsmIds - Dsm Ids\r\n    Irp - The WMI Irp\r\n    GuidIndex - Index into the WMIGUIDINFO array\r\n    InstanceIndex - Index of the data instance\r\n    InstanceCount - Number of instances\r\n    InstanceLengthArray - Array of ULONGs that indicate per-instance data lengths.\r\n    BufferAvail - Size of the buffer in which data is returned.\r\n    Buffer - Buffer in which the data is returned.\r\n    DataLength - Storage for the actual data length written.\r\n\r\nReturn Value:\r\n\r\n    STATUS_BUFFER_TOO_SMALL - If output buffer is not big enough to\r\n                              to return all the available data.\r\n    STATUS_WMI_GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry\r\n                                in the reginfo array.\r\n    STATUS_SUCCESS - On success.\r\n\r\n--*/\r\n{\r\n    ULONG sizeNeeded;\r\n    NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n    UNREFERENCED_PARAMETER(InstanceCount);\r\n    UNREFERENCED_PARAMETER(InstanceIndex);\r\n    UNREFERENCED_PARAMETER(Irp);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmQueryData (DsmIds %p): Entering function - GuidIndex %u.\\n\",\r\n                DsmIds,\r\n                GuidIndex));\r\n\r\n    //\r\n    // Check the GuidIndex - the index into the DsmGuildList array - to see\r\n    // whether this is a supported GUID or not.\r\n    //\r\n    switch(GuidIndex) {\r\n\r\n        case DSM_LBOperationsGUID_Index: {\r\n\r\n            //\r\n            // Even though this class only has methods, we need to respond\r\n            // to any queries for it since WMI expects that there is an actual\r\n            // instance of the class on which to execute the method\r\n            //\r\n\r\n            sizeNeeded = sizeof(ULONG);\r\n\r\n            *DataLength = sizeNeeded;\r\n\r\n            if (BufferAvail >= sizeNeeded) {\r\n\r\n                *InstanceLengthArray = sizeNeeded;\r\n                status = STATUS_SUCCESS;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmQueryData (DsmIds %p): Buffer too small in query data. Needed %d, Given %d.\\n\",\r\n                            DsmIds,\r\n                            sizeNeeded,\r\n                            BufferAvail));\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case DSM_QueryLBPolicyGUID_Index:\r\n        case DSM_QueryLBPolicyV2GUID_Index: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQueryLoadBalancePolicy(DsmContext,\r\n                                                DsmIds,\r\n                                                ((GuidIndex == DSM_QueryLBPolicyGUID_Index) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2),\r\n                                                BufferAvail,\r\n                                                DataLength,\r\n                                                Buffer);\r\n            break;\r\n        }\r\n\r\n        case DSM_QuerySupportedLBPoliciesGUID_Index:\r\n        case DSM_QuerySupportedLBPoliciesV2GUID_Index: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQuerySupportedLBPolicies(DsmContext,\r\n                                                  DsmIds,\r\n                                                  BufferAvail,\r\n                                                  ((GuidIndex == DSM_QuerySupportedLBPoliciesGUID_Index) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2),\r\n                                                  DataLength,\r\n                                                  Buffer);\r\n            break;\r\n        }\r\n\r\n        case DSM_QueryDsmUniqueIdGUID_Index: {\r\n\r\n            PDSM_QueryUniqueId dsmQueryUniqueId;\r\n\r\n            *DataLength = sizeof(DSM_QueryUniqueId);\r\n\r\n            if (BufferAvail >= sizeof(DSM_QueryUniqueId)) {\r\n\r\n                dsmQueryUniqueId = (PDSM_QueryUniqueId) Buffer;\r\n                dsmQueryUniqueId->DsmUniqueId = (ULONGLONG)((ULONG_PTR)DsmContext);\r\n                status = STATUS_SUCCESS;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmQueryData (DsmIds %p): Buffersize %d too small for Query Unique Id.\\n\",\r\n                            DsmIds,\r\n                            BufferAvail));\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        case MSDSM_DEVICE_PERFGuidIndex: {\r\n\r\n            *DataLength = BufferAvail;\r\n\r\n            status = DsmpQueryDevicePerf(DsmContext,\r\n                                         DsmIds,\r\n                                         BufferAvail,\r\n                                         DataLength,\r\n                                         Buffer);\r\n\r\n            break;\r\n        }\r\n\r\n        case MSDSM_WMI_METHODSGuidIndex: {\r\n\r\n            //\r\n            // Even though this class only has methods, we need to respond\r\n            // to any queries for it since WMI expects that there is an actual\r\n            // instance of the class on which to execute the method\r\n            //\r\n\r\n            sizeNeeded = sizeof(ULONG);\r\n\r\n            *DataLength = sizeNeeded;\r\n\r\n            if (BufferAvail >= sizeNeeded) {\r\n\r\n                *InstanceLengthArray = sizeNeeded;\r\n                status = STATUS_SUCCESS;\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_WARNING,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmQueryData (DsmIds %p): Buffer too small in query data. Needed %d, Given %d.\\n\",\r\n                            DsmIds,\r\n                            sizeNeeded,\r\n                            BufferAvail));\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n        default: {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmQueryData (DsmIds %p): Unknown GuidIndex %d in DsmQueryData.\\n\",\r\n                        DsmIds,\r\n                        GuidIndex));\r\n\r\n            *DataLength = 0;\r\n\r\n            break;\r\n        }\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmQueryData (DsmIds %p): Exiting function with status 0x%x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN ULONG        InBufferSize,\r\n    _In_ IN PULONG       OutBufferSize,\r\n    _Out_writes_bytes_(*OutBufferSize) OUT PVOID Buffer\r\n    )\r\n/*+++\r\n\r\nRoutine Description:\r\n\r\n    This routine returns the current Load Balance policy settings\r\n    for the given device.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer in which the current Load Balance policy settings\r\n             is returned, if the buffer is big enough\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    PDSM_GROUP_ENTRY groupEntry;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    PDSM_DEVICE_INFO rtpgDeviceInfo = NULL;\r\n    ULONG inx;\r\n    ULONG sizeNeeded;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    KIRQL irql;\r\n    PDSM_Load_Balance_Policy_V2 supportedLBPolicies;\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    PDSM_FAILOVER_GROUP foGroup;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    UNREFERENCED_PARAMETER(InBufferSize);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryLoadBalancePolicy (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // At least one device should be given\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryLoadBalancePolicy (DsmIds %p): No DSM Ids given in DsmpQueryLoadBalancePolicy.\\n\",\r\n                    DsmIds));\r\n\r\n        *OutBufferSize = 0;\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        goto __Exit_DsmpQueryLoadBalancePolicy;\r\n    }\r\n\r\n    //\r\n    // Compute the size needed for returning LoadBalance policy information\r\n    //\r\n    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n        sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths));\r\n        sizeNeeded += (DsmIds->Count) * sizeof(MPIO_DSM_Path);\r\n\r\n    } else {\r\n\r\n        sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths));\r\n        sizeNeeded += (DsmIds->Count * sizeof(MPIO_DSM_Path_V2));\r\n    }\r\n\r\n    if (*OutBufferSize < sizeNeeded) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryLoadBalancePolicy (DsmIds %p): Output buffer too small for QueryLBPolicy.\\n\",\r\n                    DsmIds));\r\n\r\n        *OutBufferSize = sizeNeeded;\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        goto __Exit_DsmpQueryLoadBalancePolicy;\r\n    }\r\n\r\n    //\r\n    // Set the size of the data returned to user\r\n    //\r\n    *OutBufferSize = sizeNeeded;\r\n\r\n    //\r\n    // Zero out the output buffer first\r\n    //\r\n    RtlZeroMemory(Buffer, sizeNeeded);\r\n\r\n    devInfo = DsmIds->IdList[0];\r\n    DSM_ASSERT(devInfo && devInfo->DeviceSig == DSM_DEVICE_SIG);\r\n    groupEntry = devInfo->Group;\r\n\r\n    //\r\n    // Send down an RTPG to get the current state info if implicit transitions\r\n    // are supported, since the states may have changed from under us.\r\n    // Storages that support both implicit and explicit transitions that haven't\r\n    // allowed us to turn OFF their implicit transitions, may have also changed\r\n    // TPG states from under us. So do this for such storages also.\r\n    //\r\n    if (!DsmpIsSymmetricAccess(devInfo) &&\r\n        devInfo->ALUASupport != DSM_DEVINFO_ALUA_EXPLICIT) {\r\n\r\n        rtpgDeviceInfo = DsmpGetActivePathToBeUsed(groupEntry, FALSE, SpecialHandlingFlag);\r\n\r\n        if (!rtpgDeviceInfo) {\r\n\r\n            BOOLEAN sendTPG = FALSE;\r\n\r\n            rtpgDeviceInfo = DsmpFindStandbyPathToActivateALUA(groupEntry, &sendTPG, SpecialHandlingFlag);\r\n        }\r\n\r\n        if (rtpgDeviceInfo) {\r\n\r\n            status = DsmpGetDeviceALUAState(DsmContext, rtpgDeviceInfo, NULL);\r\n        }\r\n    }\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    //\r\n    // If an RTPG was sent down, update all the devInfo states.\r\n    //\r\n    if (NT_SUCCESS(status) && rtpgDeviceInfo) {\r\n\r\n        DsmpAdjustDeviceStatesALUA(groupEntry, NULL, SpecialHandlingFlag);\r\n    }\r\n\r\n    supportedLBPolicies = &(((PDSM_QueryLBPolicy_V2)Buffer)->LoadBalancePolicy);\r\n    supportedLBPolicies->Version = DSM_WMI_VERSION;\r\n    supportedLBPolicies->LoadBalancePolicy = groupEntry->LoadBalanceType;\r\n    supportedLBPolicies->DSMPathCount = DsmIds->Count;\r\n    dsmPath = supportedLBPolicies->DSM_Paths;\r\n\r\n    //\r\n    // Indicate which path is active and which path(s) are standby paths\r\n    //\r\n    inx = 0;\r\n    while (inx < DsmIds->Count) {\r\n\r\n        devInfo = (PDSM_DEVICE_INFO)DsmIds->IdList[inx];\r\n\r\n        dsmPath->PathWeight = devInfo->PathWeight;\r\n        dsmPath->Reserved = DSM_STATE_ACTIVE_OPTIMIZED_SUPPORTED;\r\n\r\n        if (devInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) {\r\n\r\n            if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                dsmPath->TargetPortGroup_State = DSM_DEV_NOT_USED_STATE;\r\n            }\r\n\r\n            dsmPath->Reserved |= DSM_STATE_STANDBY_SUPPORTED;\r\n\r\n        } else {\r\n\r\n            if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                dsmPath->TargetPortGroup_State = devInfo->TargetPortGroup->AsymmetricAccessState;\r\n                dsmPath->TargetPortGroup_Preferred = devInfo->TargetPortGroup->Preferred;\r\n                dsmPath->TargetPortGroup_Identifier = devInfo->TargetPortGroup->Identifier;\r\n\r\n                if (devInfo->TargetPort) {\r\n\r\n                    dsmPath->TargetPort_Identifier = devInfo->TargetPort->Identifier;\r\n                }\r\n\r\n                if (groupEntry->Symmetric) {\r\n\r\n                    //\r\n                    // For certain policies like FOO and RRWS, we need to be able to put\r\n                    // path in standby.\r\n                    //\r\n                    dsmPath->Reserved |= DSM_STATE_STANDBY_SUPPORTED;\r\n                }\r\n            }\r\n\r\n            dsmPath->Reserved |= devInfo->TargetPortGroup->ActiveUnoptimizedSupported ? DSM_STATE_ACTIVE_UNOPTIMIZED_SUPPORTED : 0;\r\n            dsmPath->Reserved |= devInfo->TargetPortGroup->StandBySupported ? DSM_STATE_STANDBY_SUPPORTED : 0;\r\n            dsmPath->Reserved |= devInfo->TargetPortGroup->UnavailableSupported ? DSM_STATE_UNAVAILABLE_SUPPORTED : 0;\r\n        }\r\n\r\n        groupEntry = devInfo->Group;\r\n\r\n        if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath->SymmetricLUA = groupEntry->Symmetric;\r\n            dsmPath->ALUASupport = devInfo->ALUASupport;\r\n\r\n        }\r\n\r\n        if (DsmpIsDeviceFailedState(devInfo->State) || !DsmpIsDeviceInitialized(devInfo)) {\r\n\r\n            dsmPath->PrimaryPath = FALSE;\r\n            dsmPath->DsmPathId = 0;\r\n\r\n            if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                dsmPath->OptimizedPath = dsmPath->PreferredPath = FALSE;\r\n                dsmPath->FailedPath = TRUE;\r\n            }\r\n\r\n        } else {\r\n\r\n            foGroup = devInfo->FailGroup;\r\n            dsmPath->DsmPathId = (ULONGLONG)((ULONG_PTR)foGroup->PathId);\r\n\r\n            if (DsmpIsDeviceStateActive(devInfo->State)) {\r\n\r\n                dsmPath->PrimaryPath = TRUE;\r\n            }\r\n\r\n            if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED ||\r\n                    devInfo->State == DSM_DEV_STANDBY) {\r\n\r\n                    dsmPath->OptimizedPath = TRUE;\r\n                }\r\n\r\n                if (((ULONGLONG)((ULONG_PTR)(foGroup->PathId))) == (devInfo->Group->PreferredPath)) {\r\n\r\n                    dsmPath->PreferredPath = TRUE;\r\n                }\r\n            }\r\n        }\r\n\r\n#if DBG\r\n        if (!dsmPath->PrimaryPath &&\r\n            !dsmPath->FailedPath) {\r\n            NT_ASSERT(groupEntry->LoadBalanceType != DSM_LB_ROUND_ROBIN &&\r\n                   groupEntry->LoadBalanceType != DSM_LB_WEIGHTED_PATHS &&\r\n                   groupEntry->LoadBalanceType != DSM_LB_DYN_LEAST_QUEUE_DEPTH &&\r\n                   groupEntry->LoadBalanceType != DSM_LB_LEAST_BLOCKS);\r\n        }\r\n#endif\r\n\r\n        dsmPath = DsmWmiVersion == DSM_WMI_VERSION_1 ?\r\n                                   (PVOID)((PUCHAR)dsmPath + sizeof(MPIO_DSM_Path)) :\r\n                                   (PVOID)((PUCHAR)dsmPath + sizeof(MPIO_DSM_Path_V2));\r\n\r\n        inx++;\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n__Exit_DsmpQueryLoadBalancePolicy:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryLoadBalancePolicy (DsmIds %p): Exiting with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQuerySupportedLBPolicies(\r\n    _In_ IN  PDSM_CONTEXT DsmContext,\r\n    _In_ IN  PDSM_IDS DsmIds,\r\n    _In_ IN  ULONG BufferAvail,\r\n    _In_ IN  ULONG DsmWmiVersion,\r\n    _Out_ OUT PULONG OutBufferSize,\r\n    _Out_writes_to_(BufferAvail, *OutBufferSize) OUT PUCHAR Buffer\r\n    )\r\n/*+++\r\n\r\nRoutine Description:\r\n\r\n    This routine returns the load balance policies supported by this DSM for the\r\n    given LUN (specified by the DsmIds).\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n    BufferAvail - Size of buffer available.\r\n    DsmWmiVersion - Indicates which version of MPIO_DSMPath to use.\r\n    OutBufferSize - Size of the output buffer.\r\n    Buffer - Buffer in which the supported Load Balance policies are\r\n             returned, if the buffer is big enough.\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    PDSM_QuerySupportedLBPolicies_V2 supportedLBPolicies;\r\n    PDSM_Load_Balance_Policy_V2 dsmLBPolicy;\r\n    ULONG sizeNeeded;\r\n    ULONG policyCount;\r\n    ULONG inx;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    BOOLEAN skipRR = FALSE;\r\n    PDSM_DEVICE_INFO devInfo = NULL;\r\n    PUCHAR endOfBuffer;\r\n\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\"DsmpQuerySupportedLBPolicies (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // At least one device should be given\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQuerySupportedLBPolicies (DsmIds %p): No DSM Ids given in DsmpQuerySupportedLBPolicies.\\n\",\r\n                    DsmIds));\r\n\r\n        *OutBufferSize = 0;\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        goto __Exit_DsmpQuerySupportedLBPolicies;\r\n    }\r\n\r\n    devInfo = DsmIds->IdList[0];\r\n    DSM_ASSERT(devInfo && devInfo->DeviceSig == DSM_DEVICE_SIG);\r\n\r\n    policyCount = DSM_NUMBER_OF_LB_POLICIES;\r\n\r\n    //\r\n    // Round Robin policy is not supported for arrays that are AAA.\r\n    //\r\n    if (!DsmpIsSymmetricAccess(devInfo)) {\r\n\r\n        skipRR = TRUE;\r\n        policyCount--;\r\n    }\r\n\r\n    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n        sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_QuerySupportedLBPolicies, Supported_LB_Policies));\r\n        sizeNeeded += policyCount * AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths));\r\n\r\n    } else {\r\n\r\n        sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(DSM_QuerySupportedLBPolicies_V2, Supported_LB_Policies));\r\n        sizeNeeded += policyCount * AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths));\r\n    }\r\n\r\n    //\r\n    // Set the size of the data returned to user or needed but not provided.\r\n    //\r\n    *OutBufferSize = sizeNeeded;\r\n\r\n    if (sizeNeeded > BufferAvail) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQuerySupportedLBPolicies (Buffer %p): Output buffer too small. Size needed = %u.\\n\",\r\n                    Buffer,\r\n                    sizeNeeded));\r\n\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        goto __Exit_DsmpQuerySupportedLBPolicies;\r\n    }\r\n\r\n    endOfBuffer = Buffer + sizeNeeded - 1;\r\n\r\n    //\r\n    // Zero out the output buffer first\r\n    //\r\n    supportedLBPolicies = (PDSM_QuerySupportedLBPolicies_V2)Buffer;\r\n    RtlZeroMemory(Buffer, sizeNeeded);\r\n\r\n    supportedLBPolicies->SupportedLBPoliciesCount = policyCount;\r\n\r\n    if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n        dsmLBPolicy = &(supportedLBPolicies->Supported_LB_Policies[0]);\r\n\r\n    } else {\r\n\r\n        dsmLBPolicy = (PVOID)&(((PDSM_QuerySupportedLBPolicies)supportedLBPolicies)->Supported_LB_Policies[0]);\r\n    }\r\n\r\n    //\r\n    // All Load Balance policies are supported in Windows Server 2003\r\n    // and above.\r\n    //\r\n    for (inx = 0; inx < DSM_NUMBER_OF_LB_POLICIES; inx++) {\r\n\r\n        //\r\n        // Skip reporting Round Robin for AAA arrays.\r\n        //\r\n        if (((inx + 1) == DSM_LB_ROUND_ROBIN) && skipRR) {\r\n\r\n            continue;\r\n        }\r\n\r\n        if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n            if ((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths)) - 1 > endOfBuffer) {\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n                break;\r\n            }\r\n        } else {\r\n\r\n            if ((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths)) - 1 > endOfBuffer) {\r\n\r\n                status = STATUS_BUFFER_TOO_SMALL;\r\n                break;\r\n            }\r\n        }\r\n\r\n        dsmLBPolicy->Version = DSM_WMI_VERSION;\r\n\r\n        //\r\n        // The value set for LoadBalancePolicy is based on\r\n        // the #define for LB policies in LBPolicy.h\r\n        //\r\n        dsmLBPolicy->LoadBalancePolicy = inx + 1;\r\n\r\n        //\r\n        // Point to the next DSM_Load_Balance_Policy area\r\n        //\r\n        if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n            dsmLBPolicy = (PDSM_Load_Balance_Policy_V2)((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths)));\r\n\r\n        } else {\r\n\r\n            dsmLBPolicy = (PVOID)((PUCHAR)dsmLBPolicy + AlignOn8Bytes(FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths)));\r\n        }\r\n    }\r\n\r\n__Exit_DsmpQuerySupportedLBPolicies:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQuerySupportedLBPolicies (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmExecuteMethod(\r\n    _In_ IN PVOID DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds,\r\n    _In_ IN PIRP  Irp,\r\n    _In_ IN ULONG GuidIndex,\r\n    _In_ IN ULONG InstanceIndex,\r\n    _In_ IN ULONG MethodId,\r\n    _In_ IN ULONG InBufferSize,\r\n    _In_ IN PULONG OutBufferSize,\r\n    _Inout_ IN OUT PUCHAR Buffer,\r\n    ...\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine handles the invocation of WMI methods defined in the DSM mof.\r\n\r\nArguments:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids\r\n    Irp - The WMI Irp\r\n    GuidIndex - Index into the WMIGUIDINFO array\r\n    InstanceIndex - Index value indicating for which instance data should be returned.\r\n    MethodId - Specifies which method to invoke.\r\n    InBufferSize - Buffer size, in bytes, of input parameter data.\r\n    OutBufferSize - Buffer size, in bytes, of output data.\r\n    Buffer - Buffer to which the data is read/written.\r\n\r\nReturn Value:\r\n\r\n    Status of the method, or STATUS_WMI_ITEMID_NOT_FOUND\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND;\r\n    UNREFERENCED_PARAMETER(DsmContext);\r\n    UNREFERENCED_PARAMETER(InstanceIndex);\r\n    UNREFERENCED_PARAMETER(Irp);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmExecuteMethod (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // This should be the index for ExecMethod Index\r\n    //\r\n    if (GuidIndex == DSM_LBOperationsGUID_Index) {\r\n\r\n        switch (MethodId) {\r\n\r\n            case DsmSetLoadBalancePolicy:\r\n            case DsmSetLoadBalancePolicyALUA: {\r\n\r\n                status = DsmpSetLoadBalancePolicy(DsmContext,\r\n                                                  DsmIds,\r\n                                                  (MethodId == DsmSetLoadBalancePolicy) ? DSM_WMI_VERSION_1 : DSM_WMI_VERSION_2,\r\n                                                  InBufferSize,\r\n                                                  OutBufferSize,\r\n                                                  Buffer);\r\n                break;\r\n            }\r\n\r\n            default: {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmExecuteMethod (DsmIds %p): Unknown MethodId %d in DsmExecuteMethod.\\n\",\r\n                            DsmIds,\r\n                            MethodId));\r\n\r\n                status = STATUS_WMI_ITEMID_NOT_FOUND;\r\n\r\n                break;\r\n            }\r\n        }\r\n    } else if (GuidIndex == MSDSM_WMI_METHODSGuidIndex) {\r\n\r\n        if (MethodId == MSDsmClearCounters) {\r\n\r\n            status = DsmpClearPerfCounters(DsmContext, DsmIds);\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmExecuteMethod (DsmIds %p): Unknown MethodId %d for GuidIndex %d in DsmExecuteMethod.\\n\",\r\n                        DsmIds,\r\n                        MethodId,\r\n                        GuidIndex));\r\n        }\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmExecuteMethod (DsmIds %p): Unknown GuidIndex %d in DsmExecuteMethod.\\n\",\r\n                    DsmIds,\r\n                    GuidIndex));\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmExecuteMethod (DsmIds %p): Exiting function with status 0x%x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\nNTSTATUS\r\nDsmpClearLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called to clear the LUN-specific load balance policy for the given device.\r\n\r\n    First, the routine will try to clear the \"explicitly set\" registry key for the device.  If\r\n    this fails, the whole routine is aborted.\r\n\r\n    If the registry key is successfully cleared, the following happens:\r\n    1. Check to see if there is a target-wide load balance policy set for this device's VID/PID.\r\n       If yes, we set the device's load balance policy accordingly and return.\r\n    2. Check to see if there is an MSDSM-wide load balance policy set.\r\n       If yes, we set the device's load balance policy accordingly and return.\r\n    3. If steps 1 and 2 fall through, we set the device's load balance policy to RR, or RRWS if\r\n       ALUA is enabled.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n\r\nReturn Value:\r\n\r\n    Appropriate status indicating the error if the input is malformed or\r\n    if the function was unable to clear the load balance policy.\r\n    STATUS_SUCCESS on success\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PDSM_DEVICE_INFO deviceInfo = NULL;\r\n    PDSM_GROUP_ENTRY group = NULL;\r\n    HANDLE lbSettingsKey = NULL;\r\n    HANDLE deviceKey = NULL;\r\n    UNICODE_STRING subKeyName;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    DSM_LOAD_BALANCE_TYPE loadBalanceType;\r\n    ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n    ULONG devInfoIndex;\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpClearLoadBalancePolicy (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // There should be at least one device\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpClearLoadBalancePolicy (DsmIds %p): No DSM Ids given.\\n\",\r\n                    DsmIds));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpClearLoadBalancePolicy;\r\n    }\r\n\r\n    deviceInfo = (PDSM_DEVICE_INFO)DsmIds->IdList[0];\r\n    group = deviceInfo->Group;\r\n\r\n    //\r\n    // First open LoadBalanceSettings key under the Services key\r\n    //\r\n    status = DsmpOpenLoadBalanceSettingsKey(KEY_ALL_ACCESS, &lbSettingsKey);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpClearLoadBalancePolicy (DevName %ws): Failed to open LB Settings key. Status %x.\\n\",\r\n                    group->RegistryKeyName,\r\n                    status));\r\n\r\n        goto __Exit_DsmpClearLoadBalancePolicy;\r\n    }\r\n\r\n    //\r\n    // Now open the key under which the LB settings for the given device is stored\r\n    // and clear the DsmLoadBalancePolicyExplicitlySet key.\r\n    //\r\n    RtlInitUnicodeString(&subKeyName, group->RegistryKeyName);\r\n\r\n    InitializeObjectAttributes(&objectAttributes,\r\n                               &subKeyName,\r\n                               (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                               lbSettingsKey,\r\n                               (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n    status = ZwOpenKey(&deviceKey, KEY_ALL_ACCESS, &objectAttributes);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        UCHAR explicitlySet = FALSE;\r\n\r\n        status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,\r\n                                       deviceKey,\r\n                                       DSM_POLICY_EXPLICITLY_SET,\r\n                                       REG_BINARY,\r\n                                       &explicitlySet,\r\n                                       sizeof(UCHAR));\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpClearLoadBalancePolicy (DevName %ws): Failed to clear DsmLoadBalancePolicyExplicitlySet key.\\n\",\r\n                        group->RegistryKeyName));\r\n\r\n            goto __Exit_DsmpClearLoadBalancePolicy;\r\n        }\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpClearLoadBalancePolicy (DevName %ws): Failed to open device subkey.\\n\",\r\n                    group->RegistryKeyName));\r\n\r\n        goto __Exit_DsmpClearLoadBalancePolicy;\r\n    }\r\n\r\n\r\n\r\n    //\r\n    // Set the defaults.  These will be used if no target-wide or MSDSM-wide\r\n    // load balance policies are set.\r\n    //\r\n    group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_ALUA_CAPABILITY;\r\n    loadBalanceType = DSM_LB_ROUND_ROBIN;\r\n    preferredPath = 0;\r\n\r\n    //\r\n    // Check to see if target-wide (VID/PID) LB policy is set for this device.\r\n    //\r\n    status = DsmpQueryTargetLBPolicyFromRegistry(deviceInfo,\r\n                                                 &loadBalanceType,\r\n                                                 &preferredPath);\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_VID_PID;\r\n\r\n    } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {\r\n\r\n        //\r\n        // Since the policy hasn't been set for this VID/PID, check if\r\n        // overall MSDSM-wide policy has been set.\r\n        //\r\n        status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType,\r\n                                                  &preferredPath);\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            group->LBPolicySelection = DSM_DEFAULT_LB_POLICY_DSM_WIDE;\r\n\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_PNP,\r\n                        \"DsmpClearLoadBalancePolicy (DevInfo %p): Failed to query Dsm overall LB policy from registry. Status %x.\\n\",\r\n                        deviceInfo,\r\n                        status));\r\n\r\n            NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND);\r\n            status = STATUS_SUCCESS;\r\n        }\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_PNP,\r\n                    \"DsmpClearLoadBalancePolicy (DevInfo %p): Failed to query VID/PID LB policy from registry. Status %x.\\n\",\r\n                    deviceInfo,\r\n                    status));\r\n\r\n        NT_ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND);\r\n        status = STATUS_SUCCESS;\r\n    }\r\n\r\n\r\n    //\r\n    // If the storage is ALUA enabled and we specified Round Robin, change\r\n    // it to Round Robin with Subset instead.\r\n    //\r\n    if (!DsmpIsSymmetricAccess(deviceInfo) && loadBalanceType == DSM_LB_ROUND_ROBIN) {\r\n\r\n        loadBalanceType = DSM_LB_ROUND_ROBIN_WITH_SUBSET;\r\n    }\r\n\r\n    //\r\n    // Finally set the load balance policy and the preferred path.\r\n    //\r\n    group->LoadBalanceType = loadBalanceType;\r\n    group->PreferredPath = preferredPath;\r\n\r\n    //\r\n    // Update the path states in accordance with the new policy.\r\n    //\r\n    for (devInfoIndex = 0; devInfoIndex < DSM_MAX_PATHS; devInfoIndex++) {\r\n\r\n        DsmpSetNewDefaultLBPolicy(DsmContext,\r\n                                  group->DeviceList[devInfoIndex],\r\n                                  group->LoadBalanceType,\r\n                                  SpecialHandlingFlag);\r\n    }\r\n\r\n__Exit_DsmpClearLoadBalancePolicy:\r\n\r\n    if (deviceKey) {\r\n        ZwClose(deviceKey);\r\n    }\r\n\r\n    if (lbSettingsKey) {\r\n        ZwClose(lbSettingsKey);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpClearLoadBalancePolicy (DsmIds %p): Exiting function with status 0x%x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpSetLoadBalancePolicy(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN ULONG        InBufferSize,\r\n    _In_ IN PULONG       OutBufferSize,\r\n    _In_ IN PVOID        Buffer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is called to set the load balance policy for the given device.\r\n\r\n    If zero is passed in as the load balance policy, the LUN-specific load balance\r\n    policy will attempt to be cleared.  See DsmpClearLoadBalancePolicy for more details.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer for input\\output data\r\n\r\nReturn Value:\r\n\r\n    STATUS_BUFFER_TOO_SMALL - If the input buffer is too small\r\n    Appropriate status indicating the error if the input is malformed.\r\n    STATUS_SUCCESS on success\r\n\r\n--*/\r\n\r\n{\r\n    PDsmSetLoadBalancePolicyALUA_IN setLoadBalancePolicyIN = (PDsmSetLoadBalancePolicyALUA_IN) Buffer;\r\n    PDsmSetLoadBalancePolicyALUA_OUT setLoadBalancePolicyOUT = (PDsmSetLoadBalancePolicyALUA_OUT) Buffer;\r\n    PVOID supportedLBPolicies;\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    ULONG inx = 0;\r\n    ULONG jnx;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    BOOLEAN lengthOkay = TRUE;\r\n    PDSM_DEVICE_INFO devInfo = NULL;\r\n    PDSM_DEVICE_INFO tempDevInfo = NULL;\r\n    PDSM_GROUP_ENTRY groupEntry;\r\n    PDSM_LOAD_BALANCE_POLICY_SETTINGS savedLBSettings = NULL;\r\n    KIRQL irql;\r\n    BOOLEAN optimized = TRUE;\r\n    BOOLEAN preferred = FALSE;\r\n    ULONG activePaths = 0;\r\n    ULONG activeTPGs = 0;\r\n    ULONG numberDevInfoChanged = 0;\r\n    ULONG numberPreferredPaths = 0;\r\n    DSM_LOAD_BALANCE_TYPE loadBalancePolicy;\r\n    BOOLEAN sendSTPG = FALSE;\r\n    ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n    ULONG SpecialHandlingFlag = 0;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLoadBalancePolicy (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // There should be at least one device\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpSetLoadBalancePolicy (DsmIds %p): No DSM Ids given.\\n\",\r\n                    DsmIds));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpSetLoadBalancePolicy;\r\n    }\r\n\r\n    groupEntry = ((PDSM_DEVICE_INFO)DsmIds->IdList[0])->Group;\r\n\r\n    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n        if (*OutBufferSize < sizeof(DsmSetLoadBalancePolicy_OUT)) {\r\n\r\n            *OutBufferSize = sizeof(DsmSetLoadBalancePolicy_OUT);\r\n            lengthOkay = FALSE;\r\n        }\r\n    } else {\r\n\r\n        if (*OutBufferSize < sizeof(DsmSetLoadBalancePolicyALUA_OUT)) {\r\n\r\n            *OutBufferSize = sizeof(DsmSetLoadBalancePolicyALUA_OUT);\r\n            lengthOkay = FALSE;\r\n        }\r\n    }\r\n\r\n    if (!lengthOkay) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpSetLoadBalancePolicy (DsmIds %p): Buffer too small for SetLBPolicy.\\n\",\r\n                    DsmIds));\r\n\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n        goto __Exit_DsmpSetLoadBalancePolicy;\r\n    }\r\n\r\n    *OutBufferSize = (DsmWmiVersion == DSM_WMI_VERSION_1) ? sizeof(DsmSetLoadBalancePolicy_OUT) : sizeof(DsmSetLoadBalancePolicyALUA_OUT);\r\n\r\n    //\r\n    // If the user specified zero as the load balance policy, we need to clear the\r\n    // LUN-specific load balance policy.\r\n    //\r\n    if (setLoadBalancePolicyIN->LoadBalancePolicy.LoadBalancePolicy == 0) {\r\n        status = DsmpClearLoadBalancePolicy(DsmContext, DsmIds);\r\n        goto __Exit_DsmpSetLoadBalancePolicy;\r\n    }\r\n\r\n    status = DsmpValidateSetLBPolicyInput(DsmContext,\r\n                                          DsmIds,\r\n                                          DsmWmiVersion,\r\n                                          Buffer,\r\n                                          InBufferSize);\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpSetLoadBalancePolicy (DsmIds %p): Failed to validate input. Status %x.\\n\",\r\n                    DsmIds,\r\n                    status));\r\n\r\n        goto __Exit_DsmpSetLoadBalancePolicy;\r\n    }\r\n\r\n    //\r\n    // At this point the Reserved field in each MPIO_DSM_Path should\r\n    // contain the respective Device Info\r\n    //\r\n    supportedLBPolicies = &(setLoadBalancePolicyIN->LoadBalancePolicy);\r\n    loadBalancePolicy = ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->LoadBalancePolicy;\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    //\r\n    // Cache each DeviceInfo's current state.\r\n    // This will be used to rollback in case of errors.\r\n    //\r\n    DsmpSaveDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n\r\n    while (inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n            optimized = TRUE;\r\n            preferred = FALSE;\r\n\r\n        } else {\r\n\r\n            dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n            optimized = dsmPath->OptimizedPath ? TRUE : FALSE;\r\n            preferred = dsmPath->PreferredPath ? TRUE : FALSE;\r\n\r\n            if (preferred && loadBalancePolicy == DSM_LB_FAILOVER) {\r\n\r\n                preferredPath = dsmPath->DsmPathId;\r\n\r\n                if (preferredPath != 0) {\r\n\r\n                    numberPreferredPaths++;\r\n                }\r\n\r\n                if (numberPreferredPaths > 1) {\r\n\r\n                    DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                    status = STATUS_INVALID_PARAMETER;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        //\r\n        // Reserved field in MPIO_DSM_Path is set to DeviceInfo in\r\n        // DsmpValidateSetLBPolicyInput routine.\r\n        //\r\n        devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n        if (!devInfo) {\r\n\r\n            inx++;\r\n            continue;\r\n\r\n        } else {\r\n\r\n            if (!tempDevInfo) {\r\n\r\n                tempDevInfo = devInfo;\r\n\r\n                if (loadBalancePolicy == DSM_LB_ROUND_ROBIN ||\r\n                    loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) {\r\n\r\n                    InterlockedExchangePointer(&(groupEntry->PathToBeUsed), NULL);\r\n                }\r\n            }\r\n        }\r\n\r\n        if (!DsmpIsDeviceFailedState(devInfo->State)) {\r\n\r\n            if (devInfo->ALUAState == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                activeTPGs++;\r\n            }\r\n\r\n            if (dsmPath->PrimaryPath) {\r\n\r\n                //\r\n                // Optimized flag decides between AO and AU\r\n                //\r\n                if (optimized) {\r\n\r\n                    //\r\n                    // For implicit-only ALUA, state cannot be explicitly changed to A/O\r\n                    //\r\n                    if (!DsmpIsSymmetricAccess(devInfo) && devInfo->ALUASupport == DSM_DEVINFO_ALUA_IMPLICIT) {\r\n\r\n                        //\r\n                        // While we can mask off acutal A/O to be A/U, there is no\r\n                        // way to explicitly make non-A/O state A/O\r\n                        //\r\n                        if (devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_WMI,\r\n                                        \"DsmpSetLoadBalancePolicy (DsmIds %p): Can't make non-AO path A/O for Implicit-only transitions.\\n\",\r\n                                        DsmIds));\r\n\r\n                            DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                            status = STATUS_INVALID_PARAMETER;\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    numberDevInfoChanged++;\r\n\r\n                    devInfo->State = DSM_DEV_ACTIVE_OPTIMIZED;\r\n                    activePaths++;\r\n\r\n                    //\r\n                    // Check to see if the actual making of this path state A/O\r\n                    // will require an STPG to be sent down.\r\n                    //\r\n                    if (devInfo->TargetPortGroup &&\r\n                        devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                        sendSTPG = TRUE;\r\n                    }\r\n\r\n                    if (loadBalancePolicy == DSM_LB_FAILOVER) {\r\n\r\n                        //\r\n                        // Only ONE path can be specified as AO for FailOverOnly policy.\r\n                        //\r\n                        if (activePaths > 1) {\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_WMI,\r\n                                        \"DsmpSetLoadBalancePolicy (DsmIds %p): More than one AO node given for FO Only.\\n\",\r\n                                        DsmIds));\r\n\r\n                            DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                            status = STATUS_INVALID_PARAMETER;\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    if (loadBalancePolicy == DSM_LB_ROUND_ROBIN ||\r\n                        loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) {\r\n\r\n                        if (!groupEntry->PathToBeUsed) {\r\n                            InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)devInfo->FailGroup);\r\n                        }\r\n                    }\r\n                } else {\r\n\r\n                    //\r\n                    // This is an ActiveUnoptimized path\r\n                    //\r\n                    devInfo->State = DSM_DEV_ACTIVE_UNOPTIMIZED;\r\n\r\n                    //\r\n                    // For LB policy RR, WP, LB and LQD, all paths must be in A/O\r\n                    // state. However, this is not possible for ALUA storages.\r\n                    // For these storages, A/U is allowable only if that is the\r\n                    // access state that the TPG is in.\r\n                    //\r\n                    if (loadBalancePolicy == DSM_LB_ROUND_ROBIN ||\r\n                        loadBalancePolicy == DSM_LB_WEIGHTED_PATHS ||\r\n                        loadBalancePolicy == DSM_LB_DYN_LEAST_QUEUE_DEPTH ||\r\n                        loadBalancePolicy == DSM_LB_LEAST_BLOCKS) {\r\n\r\n                        if (devInfo->TargetPortGroup && devInfo->ALUAState != DSM_DEV_ACTIVE_UNOPTIMIZED) {\r\n\r\n                            TracePrint((TRACE_LEVEL_ERROR,\r\n                                        TRACE_FLAG_WMI,\r\n                                        \"DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) specified in A/U state when TPG is in %u state (for LB %u).\\n\",\r\n                                        DsmIds,\r\n                                        inx,\r\n                                        devInfo->ALUAState,\r\n                                        loadBalancePolicy));\r\n\r\n                            DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                            status = STATUS_INVALID_PARAMETER;\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n            } else {\r\n\r\n                if (optimized) {\r\n\r\n                    //\r\n                    // This is a standby path\r\n                    //\r\n                    devInfo->State = DSM_DEV_STANDBY;\r\n\r\n                } else {\r\n\r\n                    //\r\n                    // This is unavailable path\r\n                    //\r\n                    devInfo->State = DSM_DEV_UNAVAILABLE;\r\n                }\r\n\r\n                //\r\n                // For RR, LQD, LB and WP, all paths must be in A/O state for non-ALUA\r\n                // storage. For ALUA storage, the only time path states can be in\r\n                // S/B or U/A is if the TPG itself is in that state.\r\n                //\r\n                if (loadBalancePolicy == DSM_LB_ROUND_ROBIN ||\r\n                    loadBalancePolicy == DSM_LB_WEIGHTED_PATHS ||\r\n                    loadBalancePolicy == DSM_LB_DYN_LEAST_QUEUE_DEPTH ||\r\n                    loadBalancePolicy == DSM_LB_LEAST_BLOCKS) {\r\n\r\n                    if ((!devInfo->TargetPortGroup) ||\r\n                        (devInfo->TargetPortGroup && devInfo->State != devInfo->ALUAState)) {\r\n\r\n                        //\r\n                        // No paths can be in SB or UA unless its TPG is in that state.\r\n                        //\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_WMI,\r\n                                    \"DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) specified in non-active state for LB %u.\\n\",\r\n                                    DsmIds,\r\n                                    inx,\r\n                                    loadBalancePolicy));\r\n\r\n                        DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                        status = STATUS_INVALID_PARAMETER;\r\n                        break;\r\n                    }\r\n                } else if (loadBalancePolicy == DSM_LB_ROUND_ROBIN_WITH_SUBSET) {\r\n\r\n                    //\r\n                    // It is okay to set a path to be in S/B or U/A state in RRWS\r\n                    // if either the storage is non-ALUA, or if the storage is\r\n                    // ALUA but the TPG is in A/O (where it can be masked) or the\r\n                    // TPG is in the state that the path is being set to.\r\n                    //\r\n                    if ((devInfo->TargetPortGroup) &&\r\n                        (devInfo->ALUAState != DSM_DEV_ACTIVE_OPTIMIZED && devInfo->State != devInfo->ALUAState)) {\r\n\r\n                        //\r\n                        // No paths can be in SB or UA unless its TPG is in that state.\r\n                        //\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_WMI,\r\n                                    \"DsmpSetLoadBalancePolicy (DsmIds %p): Path (%u) (in TPG state %u) can't be specified in non-active state for LB %u.\\n\",\r\n                                    DsmIds,\r\n                                    inx,\r\n                                    devInfo->ALUAState,\r\n                                    loadBalancePolicy));\r\n\r\n                        DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                        status = STATUS_INVALID_PARAMETER;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        inx++;\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n\r\n        //\r\n        // If we arrive here, that means DsmpValidateSetLBPolicyInput already returned success.\r\n        // The device info is found.\r\n        //\r\n        _Analysis_assume_(tempDevInfo != NULL);\r\n\r\n        //\r\n        // There must be at least one AO path. Unless there are no A/O TPGs.\r\n        // eg. During a controller failover, it is possible that the TPG through\r\n        // the TPG through other controller is still in non-A/O state and the\r\n        // storage supports implicit transitions and is still in the midst of\r\n        // making the transition of the non-A/O TPG to A/O. During such windows\r\n        // the states for all paths will be non-A/O and there's nothing that can\r\n        // be done about it. This is not an error condition.\r\n        //\r\n        if (!activePaths) {\r\n\r\n            if ((tempDevInfo->ALUASupport == DSM_DEVINFO_ALUA_NOT_SUPPORTED) ||\r\n                (tempDevInfo->ALUASupport != DSM_DEVINFO_ALUA_NOT_SUPPORTED && activeTPGs)) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpSetLoadBalancePolicy (DsmIds %p): No active node given for LB %u.\\n\",\r\n                            DsmIds,\r\n                            loadBalancePolicy));\r\n\r\n                //\r\n                // Roll back to DeviceState to the state it was before\r\n                // processing this SetLB policy request\r\n                //\r\n                DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // If we arrive here, that means DsmpValidateSetLBPolicyInput already returned success.\r\n        // The device info is found.\r\n        //\r\n        _Analysis_assume_(tempDevInfo != NULL);\r\n\r\n        //\r\n        // If device supports explicit transitions, we need to send down an\r\n        // STPG to enforce A/O path selection if we need to make a path in a\r\n        // non-A/O TPG active/optimized.\r\n        //\r\n        if (tempDevInfo->ALUASupport >= DSM_DEVINFO_ALUA_EXPLICIT && sendSTPG) {\r\n\r\n            PUCHAR targetPortGroupsInfo = NULL;\r\n            ULONG targetPortGroupsInfoLength = 0;\r\n            PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR tpgDescriptor = NULL;\r\n\r\n            //\r\n            // Build the target port groups info to set the new states.\r\n            // Send down an STPG for TPG descriptors for those devInfos' TPGs\r\n            // that need to be in AO state. If this causes side-effects in\r\n            // state transitions (these can't be considered implicit according\r\n            // to the spec), fake the devInfo states to what was selected.\r\n            //\r\n            targetPortGroupsInfoLength = SPC3_TARGET_PORT_GROUPS_HEADER_SIZE +\r\n                                         activePaths * sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR);\r\n\r\n            targetPortGroupsInfo = DsmpAllocatePool(NonPagedPoolNx,\r\n                                                    targetPortGroupsInfoLength,\r\n                                                    DSM_TAG_TARGET_PORT_GROUPS);\r\n\r\n            if (targetPortGroupsInfo) {\r\n\r\n                PDSM_DEVICE_INFO devInfoToUse = NULL;\r\n\r\n                //\r\n                // Set the new asymmetric access states for the the devices' target port groups\r\n                //\r\n                tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)(targetPortGroupsInfo + SPC3_TARGET_PORT_GROUPS_HEADER_SIZE);\r\n\r\n                for (inx = 0, jnx = 0;\r\n                     inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount;\r\n                     inx++) {\r\n\r\n                    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n                        dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n                    } else {\r\n\r\n                        dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]);\r\n                    }\r\n\r\n                    devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n                    if (!devInfo) {\r\n\r\n                        continue;\r\n                    }\r\n\r\n                    if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                        tpgDescriptor->AsymmetricAccessState = devInfo->State;\r\n                        REVERSE_BYTES_SHORT(&tpgDescriptor->TPG_Identifier, &devInfo->TargetPortGroup->Identifier);\r\n\r\n                        tpgDescriptor = (PSPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR)((PUCHAR)tpgDescriptor + sizeof(SPC3_SET_TARGET_PORT_GROUP_DESCRIPTOR));\r\n\r\n                        jnx++;\r\n                    }\r\n\r\n                    if (devInfo->TempPreviousStateForLB == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                        devInfoToUse = devInfo;\r\n                    }\r\n                }\r\n\r\n                NT_ASSERT(jnx == numberDevInfoChanged);\r\n                NT_ASSERT(devInfoToUse);\r\n\r\n                if (devInfoToUse) {\r\n\r\n                    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n                    status = DsmpSetTargetPortGroups(devInfoToUse->TargetObject,\r\n                                                     targetPortGroupsInfo,\r\n                                                     targetPortGroupsInfoLength);\r\n\r\n                    if (NT_SUCCESS(status)) {\r\n\r\n                        DsmpFreePool(targetPortGroupsInfo);\r\n                        targetPortGroupsInfo = NULL;\r\n                        targetPortGroupsInfoLength = 0;\r\n                        status = DsmpReportTargetPortGroups(devInfoToUse->TargetObject,\r\n                                                            &targetPortGroupsInfo,\r\n                                                            &targetPortGroupsInfoLength);\r\n                    } else {\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_WMI,\r\n                                    \"DsmpSetLoadBalancePolicy (DsmIds %p): STPG failed with status %x.\\n\",\r\n                                    DsmIds,\r\n                                    status));\r\n\r\n                        DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n                    }\r\n\r\n                    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n                }\r\n\r\n                if (NT_SUCCESS(status)) {\r\n\r\n                    ULONG index;\r\n                    PDSM_TARGET_PORT_GROUP_ENTRY targetPortGroup;\r\n\r\n                    status = DsmpParseTargetPortGroupsInformation(DsmContext,\r\n                                                                  groupEntry,\r\n                                                                  targetPortGroupsInfo,\r\n                                                                  targetPortGroupsInfoLength);\r\n\r\n                    NT_ASSERT(NT_SUCCESS(status));\r\n\r\n                    for (index = 0; index < DSM_MAX_PATHS; index++) {\r\n\r\n                        targetPortGroup = groupEntry->TargetPortGroupList[index];\r\n\r\n                        if (targetPortGroup) {\r\n\r\n                            DsmpUpdateTargetPortGroupDevicesStates(targetPortGroup, targetPortGroup->AsymmetricAccessState);\r\n                        }\r\n                    }\r\n\r\n                    //\r\n                    // Update TPGs with new state\r\n                    //\r\n                    for (inx = 0;\r\n                         inx < ((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSMPathCount;\r\n                         inx++) {\r\n\r\n                        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n                            dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n                        } else {\r\n\r\n                            dsmPath = &(((PDSM_Load_Balance_Policy_V2)supportedLBPolicies)->DSM_Paths[inx]);\r\n                        }\r\n\r\n                        devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n                        if (devInfo) {\r\n\r\n                            //\r\n                            // An explicit state transition can cause TPGs that were not specified\r\n                            // in the parameter list to also change (this is not considered to be\r\n                            // an implicit transition. It is SPC3 behavior and we must take\r\n                            // this into consideration and update the devInfo states.\r\n                            // This is an unfortunate side-effect in that the Admin may not get\r\n                            // the paths to be in the exact states that he has set.\r\n                            //\r\n                            if (devInfo->State == DSM_DEV_ACTIVE_OPTIMIZED) {\r\n\r\n                                if (devInfo->ALUAState == DSM_DEV_ACTIVE_UNOPTIMIZED ||\r\n                                    devInfo->ALUAState == DSM_DEV_STANDBY ||\r\n                                    devInfo->ALUAState == DSM_DEV_UNAVAILABLE) {\r\n\r\n                                    //\r\n                                    // An A/O TPG's devInfos can be masked as A/U.\r\n                                    // However, the reverse the is not true (ie. we can't\r\n                                    // mark a non-A/O TPG's devInfo(s) to be in A/O state.\r\n                                    //\r\n                                    devInfo->State = devInfo->ALUAState;\r\n                                }\r\n                            }\r\n\r\n                            //\r\n                            // The devInfo->State has already been set. Update its previous state.\r\n                            //\r\n                            devInfo->PreviousState = devInfo->TempPreviousStateForLB;\r\n                        }\r\n                    }\r\n\r\n                    NT_ASSERT(jnx == numberDevInfoChanged);\r\n                }\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpSetLoadBalancePolicy (DsmIds %p): Failed to allocate targetPortGroupsInfo.\\n\",\r\n                            DsmIds));\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n            }\r\n        }\r\n\r\n        if (NT_SUCCESS(status)) {\r\n\r\n            groupEntry->LoadBalanceType = loadBalancePolicy;\r\n\r\n            if (loadBalancePolicy == DSM_LB_FAILOVER) {\r\n\r\n                groupEntry->PreferredPath = preferredPath;\r\n            }\r\n\r\n            savedLBSettings = DsmpCopyLoadBalancePolicies(groupEntry,\r\n                                                          DsmWmiVersion,\r\n                                                          supportedLBPolicies);\r\n\r\n        } else {\r\n\r\n            //\r\n            // Roll back to DeviceState to the state it was before\r\n            // processing this SetLB policy request\r\n            //\r\n            DsmpRestorePreviousDeviceState(supportedLBPolicies, DsmWmiVersion);\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        //\r\n        // LUN's LB policy has been explicitly set by Admin\r\n        //\r\n        groupEntry->LBPolicySelection = DSM_DEFAULT_LB_POLICY_LUN_EXPLICIT;\r\n\r\n        //\r\n        // Update the states and if appropriate, the path weight\r\n        //\r\n        DsmpUpdateDesiredStateAndWeight(groupEntry,\r\n                                        DsmWmiVersion,\r\n                                        supportedLBPolicies);\r\n\r\n        //\r\n        // Update the next path to be used for the group\r\n        //\r\n        devInfo = DsmpGetActivePathToBeUsed(groupEntry,\r\n                                            DsmpIsSymmetricAccess(tempDevInfo),\r\n                                            SpecialHandlingFlag);\r\n        if (devInfo != NULL) {\r\n\r\n            InterlockedExchangePointer(&(groupEntry->PathToBeUsed), (PVOID)devInfo->FailGroup);\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpSetLoadBalancePolicy (DsmIds %p): After setting LB policy No FOG available for group %p\\n\",\r\n                        DsmIds,\r\n                        groupEntry));\r\n\r\n            InterlockedExchangePointer(&(groupEntry->PathToBeUsed), NULL);\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    if (NT_SUCCESS(status) && savedLBSettings) {\r\n\r\n        DsmpPersistLBSettings(savedLBSettings);\r\n\r\n        DsmpFreePool(savedLBSettings);\r\n    }\r\n\r\n__Exit_DsmpSetLoadBalancePolicy:\r\n\r\n    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n        ((PDsmSetLoadBalancePolicy_OUT)setLoadBalancePolicyOUT)->Status = status;\r\n\r\n    } else {\r\n\r\n        setLoadBalancePolicyOUT->Status = status;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSetLoadBalancePolicy (DsmIds %p): Exiting function with status 0x%x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpValidateSetLBPolicyInput(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS     DsmIds,\r\n    _In_ IN ULONG        DsmWmiVersion,\r\n    _In_ IN PVOID        SetLoadBalancePolicyIN,\r\n    _In_ IN ULONG        InBufferSize\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine validates the input buffer given for setting\r\n    Load Balance policy\r\n\r\nArguements:\r\n\r\n    DsmContext - DSM Global Context\r\n    DsmIds - DSM Ids for the given device\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n    SetLoadBalancePolicyIN - Describes the load balance policy to be set\r\n    InBufferSize - Number of bytes in SetLoadBalancePolicyIN\r\n\r\nReturn Value:\r\n\r\n    STATUS_SUCCESS - if the input buffer is well formed\r\n    Appropriate error status if the input buffer is malformed.\r\n\r\n--*/\r\n{\r\n    PDSM_Load_Balance_Policy_V2 supportedLBPolicies;\r\n    PMPIO_DSM_Path_V2 dsmPath0;\r\n    PMPIO_DSM_Path_V2 dsmPath1;\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    ULONG inx;\r\n    ULONG jnx;\r\n    ULONG sizeNeeded;\r\n    KIRQL irql;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpValidateSetLBPolicyInput (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // Validate the input buffer for setting Load Balance policy\r\n    //\r\n    if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n        sizeNeeded = FIELD_OFFSET(DSM_Load_Balance_Policy_V2, DSM_Paths);\r\n\r\n    } else {\r\n\r\n        sizeNeeded = FIELD_OFFSET(DSM_Load_Balance_Policy, DSM_Paths);\r\n    }\r\n\r\n    if (InBufferSize < sizeNeeded) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Insufficient buffer in SetLB. Expected %d, Given %d.\\n\",\r\n                    DsmIds,\r\n                    sizeNeeded,\r\n                    InBufferSize));\r\n\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n        goto __Exit_DsmpValidateSetLBPolicyInput;\r\n    }\r\n\r\n    if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n        supportedLBPolicies = (PVOID)&(((PDsmSetLoadBalancePolicy_IN)SetLoadBalancePolicyIN)->LoadBalancePolicy);\r\n\r\n        sizeNeeded += supportedLBPolicies->DSMPathCount * sizeof(MPIO_DSM_Path);\r\n\r\n    } else {\r\n\r\n        supportedLBPolicies = &(((PDsmSetLoadBalancePolicyALUA_IN)SetLoadBalancePolicyIN)->LoadBalancePolicy);\r\n\r\n        sizeNeeded += supportedLBPolicies->DSMPathCount * sizeof(MPIO_DSM_Path_V2);\r\n    }\r\n\r\n    if (InBufferSize < sizeNeeded) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Insufficient buffer in SetLB. Expected %d, Given %d.\\n\",\r\n                    DsmIds,\r\n                    sizeNeeded,\r\n                    InBufferSize));\r\n\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n        goto __Exit_DsmpValidateSetLBPolicyInput;\r\n    }\r\n\r\n    if (supportedLBPolicies->Version > DSM_WMI_VERSION) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): WMI Version mismatch. Expected %d, Given %d.\\n\",\r\n                    DsmIds,\r\n                    DSM_WMI_VERSION,\r\n                    supportedLBPolicies->Version));\r\n\r\n        status = DSM_UNSUPPORTED_VERSION;\r\n        goto __Exit_DsmpValidateSetLBPolicyInput;\r\n\r\n    } else if (supportedLBPolicies->Version < DSM_WMI_VERSION) {\r\n\r\n        ULONG dsmWmiVersion = DSM_WMI_VERSION;\r\n        TracePrint((TRACE_LEVEL_WARNING,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Use of older management app (WMI-Version %x) with newer DSM (WMI-Version %x).\\n\",\r\n                    DsmIds,\r\n                    supportedLBPolicies->Version,\r\n                    dsmWmiVersion));\r\n\r\n        NT_ASSERT(supportedLBPolicies->Version == DSM_WMI_VERSION);\r\n    }\r\n\r\n    if ((supportedLBPolicies->LoadBalancePolicy < DSM_LB_FAILOVER) ||\r\n        (supportedLBPolicies->LoadBalancePolicy > DSM_LB_LEAST_BLOCKS)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Invalid LB Policy %d.\\n\",\r\n                    DsmIds,\r\n                    supportedLBPolicies->LoadBalancePolicy));\r\n\r\n        status = DSM_INVALID_LOAD_BALANCE_POLICY;\r\n        goto __Exit_DsmpValidateSetLBPolicyInput;\r\n    }\r\n\r\n    //\r\n    // It is expected that the user provide LB policy settings\r\n    // for all the paths and not just a subset of the paths.\r\n    //\r\n    if (supportedLBPolicies->DSMPathCount != DsmIds->Count) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Path Count %d not equal to DSM IDs count %d.\\n\",\r\n                    DsmIds,\r\n                    supportedLBPolicies->DSMPathCount,\r\n                    DsmIds->Count));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n        goto __Exit_DsmpValidateSetLBPolicyInput;\r\n    }\r\n\r\n    //\r\n    // Make sure user did not provide duplicate path ids\r\n    //\r\n    for (inx = 0; inx < supportedLBPolicies->DSMPathCount && NT_SUCCESS(status); inx++) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath0 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n        } else {\r\n\r\n            dsmPath0 = &(supportedLBPolicies->DSM_Paths[inx]);\r\n        }\r\n\r\n        dsmPath0->Reserved = 0;\r\n\r\n        for (jnx = 0; jnx < supportedLBPolicies->DSMPathCount; jnx++) {\r\n\r\n            if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n                dsmPath1 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[jnx]);\r\n\r\n            } else {\r\n\r\n                dsmPath1 = &(supportedLBPolicies->DSM_Paths[jnx]);\r\n            }\r\n\r\n            if ((inx != jnx) &&\r\n                ((dsmPath0->DsmPathId == dsmPath1->DsmPathId) && (dsmPath1->DsmPathId != 0))) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpValidateSetLBPolicyInput (DsmIds %p): Duplicate path id %I64x at %d and %d.\\n\",\r\n                            DsmIds,\r\n                            dsmPath0->DsmPathId,\r\n                            inx,\r\n                            jnx));\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n\r\n                break;\r\n            }\r\n        }\r\n    }\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        PDSM_DEVICE_INFO devInfo;\r\n        PDSM_FAILOVER_GROUP foGroup;\r\n        PVOID pathId;\r\n        BOOLEAN foundPath;\r\n\r\n        irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n        //\r\n        // Make sure the user has provided path id corresponding\r\n        // to all the DSM IDs given to us.\r\n        //\r\n        for (inx = 0; inx < DsmIds->Count; inx++) {\r\n\r\n            devInfo = DsmIds->IdList[inx];\r\n\r\n            if (!DsmpIsDeviceInitialized(devInfo)) {\r\n\r\n                continue;\r\n            }\r\n\r\n            foGroup = devInfo->FailGroup;\r\n            if (!foGroup) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpValidateSetLBPolicyInput (DsmIds %p): FO Group NULL for %p at index %d.\\n\",\r\n                            DsmIds,\r\n                            devInfo,\r\n                            inx));\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n\r\n                break;\r\n            }\r\n\r\n            foundPath = FALSE;\r\n\r\n            for (jnx = 0; jnx < supportedLBPolicies->DSMPathCount; jnx++) {\r\n\r\n                if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n                    dsmPath0 = (PVOID)&(((PDSM_Load_Balance_Policy)supportedLBPolicies)->DSM_Paths[jnx]);\r\n\r\n                } else {\r\n\r\n                    dsmPath0 = &(supportedLBPolicies->DSM_Paths[jnx]);\r\n                }\r\n\r\n                pathId = (PVOID) dsmPath0->DsmPathId;\r\n                if (foGroup->PathId == pathId) {\r\n\r\n                    //\r\n                    // Found the device info corresponding to the given path.\r\n                    // Use the reserved field in MPIO_DSM_Path to store\r\n                    // the pointer to the device info. Device Info is used\r\n                    // later on to set the load balance policy for the device.\r\n                    //\r\n                    foundPath = TRUE;\r\n\r\n                    dsmPath0->Reserved = (ULONG_PTR) devInfo;\r\n\r\n                    //\r\n                    // If ALUA, RoundRobin is not an allowed LB policy since not all paths can\r\n                    // be in A/O state. RRWS must be used instead.\r\n                    //\r\n                    if (supportedLBPolicies->LoadBalancePolicy == DSM_LB_ROUND_ROBIN && !DsmpIsSymmetricAccess(devInfo)) {\r\n\r\n                        status = DSM_INVALID_LOAD_BALANCE_POLICY;\r\n\r\n                        TracePrint((TRACE_LEVEL_ERROR,\r\n                                    TRACE_FLAG_WMI,\r\n                                    \"DsmpValidateSetLBPolicyInput (DsmIds %p): Invalid LB policy for ALUA. Status %x.\\n\",\r\n                                    DsmIds,\r\n                                    status));\r\n                    }\r\n\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (!foundPath) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpValidateSetLBPolicyInput (DsmIds %p): Failed to find path %p for %p at index %d.\\n\",\r\n                            DsmIds,\r\n                            foGroup->PathId,\r\n                            devInfo,\r\n                            inx));\r\n\r\n                status = STATUS_INVALID_PARAMETER;\r\n\r\n                break;\r\n            }\r\n        }\r\n\r\n        ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n    }\r\n\r\n__Exit_DsmpValidateSetLBPolicyInput:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpValidateSetLBPolicyInput (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nVOID\r\nDsmpSaveDeviceState(\r\n    _In_ IN PVOID SupportedLBPolicies,\r\n    _In_ IN ULONG DsmWmiVersion\r\n    )\r\n/*+++\r\n\r\nRoutine Description:\r\n\r\n    This routine saves the current Load Balance policy settings.\r\n    If there is any error while setting the new policy given\r\n    by the user, the saved values will be used to restore\r\n    the old state.\r\n\r\n    Note: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguements:\r\n\r\n    SupportedLBPolicies - New Load Balance policy values\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n\r\nReturn Value:\r\n\r\n    None\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO devInfo;\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    ULONG inx;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSaveDeviceState (LBP %p): Entering function.\\n\",\r\n                SupportedLBPolicies));\r\n\r\n    inx = 0;\r\n\r\n    while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n        } else {\r\n\r\n            dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]);\r\n        }\r\n\r\n        devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n        if (devInfo) {\r\n\r\n            devInfo->TempPreviousStateForLB = devInfo->State;\r\n        }\r\n\r\n        inx++;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpSaveDeviceState (LBP %p): Exiting function.\\n\",\r\n                SupportedLBPolicies));\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nDsmpRestorePreviousDeviceState(\r\n    _In_ IN PVOID SupportedLBPolicies,\r\n    _In_ IN ULONG DsmWmiVersion\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine restores the old Load Balance policy settings.\r\n    If there is any error while setting the new policy given\r\n    by the user, the old state is restored from the saved state.\r\n\r\n    Note: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguements:\r\n\r\n    SupportedLBPolicies - New Load Balance policy values\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n\r\nReturn Value:\r\n\r\n    None\r\n--*/\r\n{\r\n    PDSM_DEVICE_INFO devInfo;\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    ULONG inx;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpRestorePreviousDeviceState (LBP %p): Entering function.\\n\",\r\n                SupportedLBPolicies));\r\n\r\n    inx = 0;\r\n\r\n    while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n        } else {\r\n\r\n            dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]);\r\n        }\r\n\r\n        devInfo = (PDSM_DEVICE_INFO)dsmPath->Reserved;\r\n\r\n        if (devInfo) {\r\n\r\n            devInfo->State = devInfo->TempPreviousStateForLB;\r\n        }\r\n\r\n        inx++;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpRestorePreviousDeviceState (LBP %p): Exiting function.\\n\",\r\n                SupportedLBPolicies));\r\n\r\n    return;\r\n}\r\n\r\n\r\nVOID\r\nDsmpUpdateDesiredStateAndWeight(\r\n    _In_ IN PDSM_GROUP_ENTRY Group,\r\n    _In_ IN ULONG DsmWmiVersion,\r\n    _In_ IN PVOID SupportedLBPolicies\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine updates the desired state and path weights\r\n    based on admin's LB selection.\r\n\r\n    Note: This routine MUST be called with DsmContextLock held in Exclusive mode.\r\n\r\nArguements:\r\n\r\n    Group - The group entry correponding to the pseudo-LUN.\r\n    SupportedLBPolicies - New Load Balance policy values\r\n    DsmWmiVersion - version of the MPIO_DSM_Path class to use\r\n\r\nReturn Value:\r\n\r\n    None\r\n--*/\r\n{\r\n    PMPIO_DSM_Path_V2 dsmPath;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    ULONG inx;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpUpdatedDesiredState (Group %p): Entering function.\\n\",\r\n                Group));\r\n\r\n    inx = 0;\r\n    while (inx < ((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSMPathCount) {\r\n\r\n        if (DsmWmiVersion == DSM_WMI_VERSION_1) {\r\n\r\n            dsmPath = (PVOID)&(((PDSM_Load_Balance_Policy)SupportedLBPolicies)->DSM_Paths[inx]);\r\n\r\n        } else {\r\n\r\n            dsmPath = &(((PDSM_Load_Balance_Policy_V2)SupportedLBPolicies)->DSM_Paths[inx]);\r\n        }\r\n\r\n        devInfo = (PDSM_DEVICE_INFO) dsmPath->Reserved;\r\n\r\n        if (!devInfo) {\r\n\r\n            inx++;\r\n            continue;\r\n        }\r\n\r\n        DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG);\r\n        NT_ASSERT(devInfo->Group == Group);\r\n\r\n        //\r\n        // We'll honor the chosen path for FOO for ALUA storage\r\n        // since we know for a fact that the Admin has chosen the path.\r\n        // We'll also honor path state in RRWS if it is different from TPG state\r\n        // as that too is an indication that it was explicitly selected.\r\n        //\r\n        if ((DsmpIsSymmetricAccess(devInfo)) ||\r\n            (Group->LoadBalanceType == DSM_LB_FAILOVER) ||\r\n            (!DsmpIsSymmetricAccess(devInfo) && Group->LoadBalanceType == DSM_LB_ROUND_ROBIN_WITH_SUBSET && devInfo->State != devInfo->ALUAState)) {\r\n\r\n            //\r\n            // Check if this is the primary path or a standby path\r\n            //\r\n            if (dsmPath->PrimaryPath) {\r\n\r\n                devInfo->DesiredState = DSM_DEV_ACTIVE_OPTIMIZED;\r\n\r\n                if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                    if (!dsmPath->OptimizedPath) {\r\n\r\n                        devInfo->DesiredState = DSM_DEV_ACTIVE_UNOPTIMIZED;\r\n                    }\r\n                }\r\n\r\n            } else {\r\n\r\n                devInfo->DesiredState = DSM_DEV_STANDBY;\r\n\r\n                if (DsmWmiVersion > DSM_WMI_VERSION_1) {\r\n\r\n                    if (!dsmPath->OptimizedPath) {\r\n\r\n                        devInfo->DesiredState = DSM_DEV_UNAVAILABLE;\r\n                    }\r\n                }\r\n            }\r\n        } else {\r\n\r\n            devInfo->DesiredState = DSM_DEV_UNDETERMINED;\r\n        }\r\n\r\n        if (Group->LoadBalanceType == DSM_LB_WEIGHTED_PATHS) {\r\n\r\n            devInfo->PathWeight = dsmPath->PathWeight;\r\n        }\r\n\r\n        inx++;\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpUpdatedDesiredState (Group %p): Exiting function.\\n\",\r\n                Group));\r\n\r\n    return;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryDevicePerf(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ PDSM_IDS DsmIds,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine returns the perf counters for each path for the\r\n    device that corresponds to the passed in DsmIds.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer in which the current Load Balance policy settings\r\n             is returned, if the buffer is big enough\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    ULONG sizeNeeded;\r\n    PMSDSM_DEVICE_PERF devicePerf;\r\n    ULONG i;\r\n    PMSDSM_DEVICEPATH_PERF pathPerf;\r\n    KIRQL irql;\r\n\r\n    UNREFERENCED_PARAMETER(InBufferSize);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryDevicePerf (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // At least one device should be given\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryDevicePerf (DsmIds %p): No DSM Ids given.\\n\",\r\n                    DsmIds));\r\n\r\n        *OutBufferSize = 0;\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        goto __Exit_DsmpQueryDevicePerf;\r\n    }\r\n\r\n    sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_DEVICE_PERF, PerfInfo));\r\n    sizeNeeded += (DsmIds->Count * sizeof(MSDSM_DEVICEPATH_PERF));\r\n\r\n    if (*OutBufferSize < sizeNeeded) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryDevicePerf (DsmIds %p): Output buffer too small for QueryLBPolicy.\\n\",\r\n                    DsmIds));\r\n\r\n        *OutBufferSize = sizeNeeded;\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        goto __Exit_DsmpQueryDevicePerf;\r\n    }\r\n\r\n    //\r\n    // Zero out the output buffer first\r\n    //\r\n    RtlZeroMemory(Buffer, sizeNeeded);\r\n\r\n#if DBG\r\n    devInfo = DsmIds->IdList[0];\r\n    DSM_ASSERT(devInfo);\r\n    DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG);\r\n#endif\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    devicePerf = (PMSDSM_DEVICE_PERF)Buffer;\r\n    devicePerf->NumberPaths = DsmIds->Count;\r\n\r\n    //\r\n    // For each path, get the stats info\r\n    //\r\n    for (i = 0; i < DsmIds->Count; i++) {\r\n\r\n        pathPerf = &devicePerf->PerfInfo[i];\r\n        devInfo = DsmIds->IdList[i];\r\n\r\n        if (DsmpIsDeviceInitialized(devInfo)) {\r\n\r\n            pathPerf->PathId = (ULONGLONG)((ULONG_PTR)((devInfo->FailGroup)->PathId));\r\n            pathPerf->NumberReads = (devInfo->DeviceStats).NumberReads;\r\n            pathPerf->NumberWrites = (devInfo->DeviceStats).NumberWrites;\r\n            pathPerf->BytesRead = (devInfo->DeviceStats).BytesRead;\r\n            pathPerf->BytesWritten = (devInfo->DeviceStats).BytesWritten;\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n    *OutBufferSize = sizeNeeded;\r\n\r\n__Exit_DsmpQueryDevicePerf:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryDevicePerf (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpClearPerfCounters(\r\n    _In_ IN PDSM_CONTEXT DsmContext,\r\n    _In_ IN PDSM_IDS DsmIds\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine clears the perf counters for each path for the\r\n    device that corresponds to the passed in DsmIds.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    DsmIds - DSM Ids for the given device\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status = STATUS_SUCCESS;\r\n    PDSM_DEVICE_INFO devInfo;\r\n    KIRQL irql;\r\n    ULONG i;\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpClearPerfCounters (DsmIds %p): Entering function.\\n\",\r\n                DsmIds));\r\n\r\n    //\r\n    // At least one device should be given\r\n    //\r\n    if (DsmIds->Count == 0) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpClearPerfCounters (DsmIds %p): No DSM Ids given.\\n\",\r\n                    DsmIds));\r\n\r\n        status = STATUS_INVALID_PARAMETER;\r\n\r\n        goto __Exit_DsmpClearPerfCounters;\r\n    }\r\n\r\n    irql = ExAcquireSpinLockExclusive(&(DsmContext->DsmContextLock));\r\n\r\n    for (i = 0; i < DsmIds->Count; i++) {\r\n\r\n        devInfo = DsmIds->IdList[i];\r\n        DSM_ASSERT(devInfo);\r\n        DSM_ASSERT(devInfo->DeviceSig == DSM_DEVICE_SIG);\r\n\r\n        if (devInfo) {\r\n            (devInfo->DeviceStats).BytesRead = 0;\r\n            (devInfo->DeviceStats).BytesWritten = 0;\r\n            (devInfo->DeviceStats).NumberReads = 0;\r\n            (devInfo->DeviceStats).NumberWrites = 0;\r\n        }\r\n    }\r\n\r\n    ExReleaseSpinLockExclusive(&(DsmContext->DsmContextLock), irql);\r\n\r\n__Exit_DsmpClearPerfCounters:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpClearPerfCounters (DsmIds %p): Exiting function with status %x.\\n\",\r\n                DsmIds,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQuerySupportedDevicesList(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine returns the list of devices that are supported by MSDSM.\r\n\r\nArguements:\r\n\r\n    DsmContext - Global DSM context\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer in which the current Load Balance policy settings\r\n             is returned, if the buffer is big enough\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    NTSTATUS status;\r\n    ULONG sizeNeeded;\r\n    PMSDSM_SUPPORTED_DEVICES_LIST supportedDeviceIds;\r\n    PWSTR szIndex;\r\n    PWSTR deviceIdIndex;\r\n    ULONG numberDeviceIds = 0;\r\n    ULONG index = 0;\r\n    KIRQL oldIrql;\r\n    PWSTR tempBuffer = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(InBufferSize);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQuerySupportedDevicesList (DsmContext %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    //\r\n    // It is possible that manually changes to the registry weren't yet picked up,\r\n    // so query for the list in its current state. Failure to get this list is not\r\n    // fatal, so ignore errors.\r\n    //\r\n#if DBG\r\n    status = DsmpGetDeviceList(DsmContext);\r\n    NT_ASSERT(NT_SUCCESS(status));\r\n#else\r\n    DsmpGetDeviceList(DsmContext);\r\n#endif\r\n\r\n    //\r\n    // Since it is possible that this list may change if a new device arrival\r\n    // gets processed at the same time as this query being processed, we need\r\n    // to protect it.\r\n    //\r\n    KeAcquireSpinLock(&DsmContext->SupportedDevicesListLock, &oldIrql);\r\n\r\n    tempBuffer = DsmpAllocatePool(NonPagedPoolNx, DsmContext->SupportedDevices.MaximumLength, DSM_TAG_REG_VALUE_RELATED);\r\n\r\n    if (tempBuffer) {\r\n\r\n        RtlCopyMemory(tempBuffer, DsmContext->SupportedDevices.Buffer, DsmContext->SupportedDevices.Length);\r\n\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQuerySupportedDevicesList (DsmContext %p): Failed to allocate temporary list.\\n\",\r\n                    DsmContext));\r\n\r\n        status = STATUS_INSUFFICIENT_RESOURCES;\r\n        KeReleaseSpinLock(&DsmContext->SupportedDevicesListLock, oldIrql);\r\n\r\n        goto __Exit_DsmpQuerySupportedDevicesList;\r\n    }\r\n\r\n    KeReleaseSpinLock(&DsmContext->SupportedDevicesListLock, oldIrql);\r\n\r\n    status = STATUS_SUCCESS;\r\n    szIndex = tempBuffer;\r\n\r\n    sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_SUPPORTED_DEVICES_LIST, DeviceId));\r\n\r\n    if (szIndex) {\r\n\r\n        while (*szIndex) {\r\n\r\n            szIndex += wcslen(szIndex) + 1;\r\n            numberDeviceIds++;\r\n        }\r\n\r\n        sizeNeeded += numberDeviceIds * (MSDSM_MAX_DEVICE_ID_SIZE + sizeof(WNULL));\r\n    }\r\n\r\n    if (*OutBufferSize < sizeNeeded) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQuerySupportedDevicesList (DsmContext %p): Output buffer too small for QuerySupportedDevicesList.\\n\",\r\n                    DsmContext));\r\n\r\n        *OutBufferSize = sizeNeeded;\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        goto __Exit_DsmpQuerySupportedDevicesList;\r\n    }\r\n\r\n    //\r\n    // Zero out the output buffer first\r\n    //\r\n    RtlZeroMemory(Buffer, sizeNeeded);\r\n\r\n    *OutBufferSize = sizeNeeded;\r\n\r\n    supportedDeviceIds = (PMSDSM_SUPPORTED_DEVICES_LIST)Buffer;\r\n    supportedDeviceIds->NumberDevices = numberDeviceIds;\r\n\r\n    for (index = 0, szIndex = tempBuffer, deviceIdIndex = supportedDeviceIds->DeviceId;\r\n         index < numberDeviceIds;\r\n         index++, szIndex += wcslen(szIndex) + 1, deviceIdIndex += MSDSM_MAX_DEVICE_ID_LENGTH) {\r\n\r\n        *((PUSHORT)deviceIdIndex) = MSDSM_MAX_DEVICE_ID_SIZE;\r\n        deviceIdIndex++;\r\n\r\n        RtlStringCchCopyW(deviceIdIndex,\r\n                          MSDSM_MAX_DEVICE_ID_LENGTH - 1,\r\n                          szIndex);\r\n    }\r\n\r\n__Exit_DsmpQuerySupportedDevicesList:\r\n\r\n    if (tempBuffer) {\r\n        DsmpFreePool(tempBuffer);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQuerySupportedDevicesList (DsmContext %p): Exiting function with status %x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryTargetsDefaultPolicy(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to build the target list (for which the override default LB policy\r\n    was explicitly set), by querying the services key for the subkeys under\r\n    \"msdsm\\Parameters\\DsmTargetsLoadBalanceSetting\"\r\n\r\nArguements:\r\n\r\n    Context - The DSM Context value. It contains storage for the target hardware ids and their\r\n              default policy info.\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer in which the current targets whose default policy settings is returned, if the buffer is big enough\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    ULONG sizeNeeded;\r\n    PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY targetsPolicyInfo = (PMSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY)Buffer;\r\n    PMSDSM_TARGET_DEFAULT_POLICY_INFO targetPolicyInfo;\r\n    HANDLE targetsLBSettingKey = NULL;\r\n    NTSTATUS status;\r\n    PKEY_FULL_INFORMATION keyFullInfo = NULL;\r\n    ULONG length = sizeof(KEY_FULL_INFORMATION);\r\n    ULONG numSubKeys = 0;\r\n    WCHAR vidPid[25] = {0};\r\n    PKEY_BASIC_INFORMATION keyBasicInfo = NULL;\r\n    OBJECT_ATTRIBUTES objectAttributes;\r\n    HANDLE targetKey = NULL;\r\n    ULONG index = 0;\r\n    RTL_QUERY_REGISTRY_TABLE queryTable[2];\r\n    DSM_LOAD_BALANCE_TYPE loadBalanceType;\r\n    ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n    PWCHAR policyInfoIndex;\r\n    UNICODE_STRING keyValueName;\r\n    PKEY_VALUE_PARTIAL_INFORMATION keyValueInfo = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(InBufferSize);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryTargetsDefaultPolicy (Context %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    status = DsmpOpenTargetsLoadBalanceSettingKey(KEY_ALL_ACCESS, &targetsLBSettingKey);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to open Targets LB Setting key. Status %x.\\n\",\r\n                    DsmContext,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n    }\r\n\r\n    //\r\n    // Query for number of subkeys\r\n    //\r\n    do {\r\n        if (keyFullInfo) {\r\n\r\n            DsmpFreePool(keyFullInfo);\r\n        }\r\n\r\n        keyFullInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED);\r\n\r\n        if (!keyFullInfo) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for key full info.\\n\",\r\n                        DsmContext));\r\n\r\n            status = STATUS_INSUFFICIENT_RESOURCES;\r\n            goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n        }\r\n\r\n        status = ZwQueryKey(targetsLBSettingKey,\r\n                            KeyFullInformation,\r\n                            keyFullInfo,\r\n                            length,\r\n                            &length);\r\n\r\n    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n    if (!NT_SUCCESS(status)) {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query key. Status %x.\\n\",\r\n                    DsmContext,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n    }\r\n\r\n    //\r\n    // Calculate total buffer size required\r\n    //\r\n    numSubKeys = keyFullInfo->SubKeys;\r\n\r\n    sizeNeeded = AlignOn8Bytes(FIELD_OFFSET(MSDSM_TARGETS_DEFAULT_LOAD_BALANCE_POLICY, TargetDefaultPolicyInfo));\r\n    sizeNeeded += numSubKeys * sizeof(MSDSM_TARGET_DEFAULT_POLICY_INFO);\r\n\r\n    if (*OutBufferSize < sizeNeeded) {\r\n\r\n        *OutBufferSize = sizeNeeded;\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryTargetsDefaultPolicy (Context %p): Buffer insufficient. Status %x.\\n\",\r\n                    DsmContext,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n    }\r\n\r\n    *OutBufferSize = sizeNeeded;\r\n    RtlZeroMemory(Buffer, *OutBufferSize);\r\n\r\n    targetsPolicyInfo->NumberDevices = numSubKeys;\r\n    targetPolicyInfo = targetsPolicyInfo->TargetDefaultPolicyInfo;\r\n\r\n    //\r\n    // Now Enumerate all of the subkeys\r\n    //\r\n    for(index = 0; index < numSubKeys && NT_SUCCESS(status); index++) {\r\n\r\n        UNICODE_STRING targetName;\r\n\r\n        if (targetKey) {\r\n            ZwClose(targetKey);\r\n            targetKey = NULL;\r\n        }\r\n\r\n        length = sizeof(KEY_BASIC_INFORMATION);\r\n\r\n        do {\r\n            if (keyBasicInfo) {\r\n\r\n                DsmpFreePool(keyBasicInfo);\r\n            }\r\n\r\n            keyBasicInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned,\r\n                                            length,\r\n                                            DSM_TAG_REG_KEY_RELATED);\r\n\r\n            if (!keyBasicInfo) {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for key basic info.\\n\",\r\n                            DsmContext));\r\n\r\n                status = STATUS_INSUFFICIENT_RESOURCES;\r\n                goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n            }\r\n\r\n            //\r\n            // Enumerate the index'th subkey\r\n            //\r\n            status = ZwEnumerateKey(targetsLBSettingKey,\r\n                                    index,\r\n                                    KeyBasicInformation,\r\n                                    keyBasicInfo,\r\n                                    length,\r\n                                    &length);\r\n\r\n        } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n        //\r\n        // Ignore errors - this is a best case effort.\r\n        //\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to enumerate sub key's info. Status %x.\\n\",\r\n                        DsmContext,\r\n                        status));\r\n\r\n            status = STATUS_SUCCESS;\r\n            continue;\r\n        }\r\n\r\n        RtlZeroMemory(vidPid, sizeof(vidPid));\r\n        RtlStringCbCopyNW(vidPid, sizeof(vidPid), keyBasicInfo->Name, keyBasicInfo->NameLength);\r\n        RtlInitUnicodeString(&targetName, vidPid);\r\n\r\n        //\r\n        // Open a handle to the the target subkey.\r\n        //\r\n        InitializeObjectAttributes(&objectAttributes,\r\n                                   &targetName,\r\n                                   (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE),\r\n                                   targetsLBSettingKey,\r\n                                   (PSECURITY_DESCRIPTOR) NULL);\r\n\r\n        status = ZwOpenKey(&targetKey,\r\n                           KEY_ALL_ACCESS,\r\n                           &objectAttributes);\r\n\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to open reg key %ws. Status %x.\\n\",\r\n                        DsmContext,\r\n                        vidPid,\r\n                        status));\r\n\r\n            goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n        }\r\n\r\n        RtlZeroMemory(queryTable, sizeof(queryTable));\r\n\r\n        queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;\r\n        queryTable[0].Name = DSM_LOAD_BALANCE_POLICY;\r\n        queryTable[0].EntryContext = &loadBalanceType;\r\n        queryTable[0].DefaultType  = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;\r\n\r\n        status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,\r\n                                        targetKey,\r\n                                        queryTable,\r\n                                        targetKey,\r\n                                        NULL);\r\n        if (!NT_SUCCESS(status)) {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query LB Policy for %ws - error %x.\\n\",\r\n                        DsmContext,\r\n                        vidPid,\r\n                        status));\r\n        } else {\r\n\r\n            TracePrint((TRACE_LEVEL_ERROR,\r\n                        TRACE_FLAG_WMI,\r\n                        \"DsmpQueryTargetsDefaultPolicy (Context %p): LB Policy for %ws is %d.\\n\",\r\n                        DsmContext,\r\n                        vidPid,\r\n                        loadBalanceType));\r\n\r\n            RtlInitUnicodeString(&keyValueName, DSM_PREFERRED_PATH);\r\n\r\n            length = sizeof(KEY_VALUE_PARTIAL_INFORMATION);\r\n\r\n            do {\r\n                DsmpFreePool(keyValueInfo);\r\n                keyValueInfo = DsmpAllocatePool(NonPagedPoolNxCacheAligned, length, DSM_TAG_REG_KEY_RELATED);\r\n                if (!keyValueInfo) {\r\n\r\n                    status = STATUS_INSUFFICIENT_RESOURCES;\r\n\r\n                    TracePrint((TRACE_LEVEL_ERROR,\r\n                                TRACE_FLAG_WMI,\r\n                                \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to allocate resources for keyValueInfo (PP). Status %x.\\n\",\r\n                                DsmContext,\r\n                                status));\r\n\r\n                    goto __Exit_DsmpQueryTargetsDefaultPolicy;\r\n                }\r\n\r\n                status = ZwQueryValueKey(targetKey,\r\n                                         &keyValueName,\r\n                                         KeyValuePartialInformation,\r\n                                         keyValueInfo,\r\n                                         length,\r\n                                         &length);\r\n\r\n            } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW);\r\n\r\n            if (NT_SUCCESS(status)) {\r\n\r\n                NT_ASSERT(keyValueInfo->DataLength == sizeof(ULONGLONG));\r\n\r\n                preferredPath = *((ULONGLONG UNALIGNED *)keyValueInfo->Data);\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpQueryTargetsDefaultPolicy (Context %p): PreferredPath for %ws is %I64x.\\n\",\r\n                            DsmContext,\r\n                            vidPid,\r\n                            preferredPath));\r\n\r\n            } else {\r\n\r\n                TracePrint((TRACE_LEVEL_ERROR,\r\n                            TRACE_FLAG_WMI,\r\n                            \"DsmpQueryTargetsDefaultPolicy (Context %p): Failed to query PreferredPath for %ws. Status %x.\\n\",\r\n                            DsmContext,\r\n                            vidPid,\r\n                            status));\r\n            }\r\n\r\n            //\r\n            // Copy over this target's policy info.\r\n            //\r\n            policyInfoIndex = targetPolicyInfo->HardwareId;\r\n            *((PUSHORT)policyInfoIndex) = MSDSM_MAX_DEVICE_ID_SIZE;\r\n            policyInfoIndex++;\r\n            RtlStringCchCopyW((PWSTR)policyInfoIndex, MSDSM_MAX_DEVICE_ID_LENGTH - 1, vidPid);\r\n            targetPolicyInfo->LoadBalancePolicy = loadBalanceType;\r\n            targetPolicyInfo->PreferredPath = preferredPath;\r\n\r\n            targetPolicyInfo++;\r\n        }\r\n    }\r\n\r\n__Exit_DsmpQueryTargetsDefaultPolicy:\r\n\r\n    if (targetKey) {\r\n        ZwClose(targetKey);\r\n    }\r\n\r\n    if (targetsLBSettingKey) {\r\n        ZwClose(targetsLBSettingKey);\r\n    }\r\n\r\n    if (keyBasicInfo) {\r\n        DsmpFreePool(keyBasicInfo);\r\n    }\r\n\r\n    if (keyValueInfo) {\r\n        DsmpFreePool(keyValueInfo);\r\n    }\r\n\r\n    if (keyFullInfo) {\r\n        DsmpFreePool(keyFullInfo);\r\n    }\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryTargetsDefaultPolicy (Context %p): Exiting function with status %x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n\r\nNTSTATUS\r\nDsmpQueryDsmDefaultPolicy(\r\n    _In_ PDSM_CONTEXT DsmContext,\r\n    _In_ ULONG InBufferSize,\r\n    _Inout_ PULONG OutBufferSize,\r\n    _Out_writes_to_(*OutBufferSize, *OutBufferSize) PUCHAR Buffer\r\n    )\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This routine is used to return the override MSDSM-wide default LB policy\r\n    if it was explicitly set, by querying the services key at \"msdsm\\Parameters\"\r\n\r\nArguements:\r\n\r\n    Context - The DSM Context value. It contains storage for the target hardware ids and their\r\n              default policy info.\r\n    InBufferSize - Size of the input buffer\r\n    OutBufferSize - Size of the output buffer\r\n    Buffer - Buffer in which the current MSDSM-wide default policy is returned, if the buffer\r\n             is big enough\r\n\r\nReturn Value:\r\n\r\n   STATUS_SUCCESS on success\r\n   Appropriate error code on error.\r\n\r\n--*/\r\n{\r\n    PMSDSM_DEFAULT_LOAD_BALANCE_POLICY dsmPolicyInfo = (PMSDSM_DEFAULT_LOAD_BALANCE_POLICY)Buffer;\r\n    NTSTATUS status;\r\n    DSM_LOAD_BALANCE_TYPE loadBalanceType;\r\n    ULONGLONG preferredPath = (ULONGLONG)((ULONG_PTR)MAXULONG);\r\n\r\n    UNREFERENCED_PARAMETER(InBufferSize);\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryDsmDefaultPolicy (Context %p): Entering function.\\n\",\r\n                DsmContext));\r\n\r\n    if (*OutBufferSize < sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY)) {\r\n\r\n        *OutBufferSize = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY);\r\n        status = STATUS_BUFFER_TOO_SMALL;\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryDsmDefaultPolicy (Context %p): Buffer insufficient. Status %x.\\n\",\r\n                    DsmContext,\r\n                    status));\r\n\r\n        goto __Exit_DsmpQueryDsmDefaultPolicy;\r\n    }\r\n\r\n    *OutBufferSize = sizeof(MSDSM_DEFAULT_LOAD_BALANCE_POLICY);\r\n    RtlZeroMemory(Buffer, *OutBufferSize);\r\n\r\n    status = DsmpQueryDsmLBPolicyFromRegistry(&loadBalanceType, &preferredPath);\r\n\r\n    if (NT_SUCCESS(status)) {\r\n\r\n        dsmPolicyInfo->LoadBalancePolicy = loadBalanceType;\r\n        dsmPolicyInfo->PreferredPath = (ULONGLONG)((ULONG_PTR)preferredPath);\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryDsmDefaultPolicy (Context %p): LB policy = %u, Preferred path = %I64x.\\n\",\r\n                    DsmContext,\r\n                    dsmPolicyInfo->LoadBalancePolicy,\r\n                    dsmPolicyInfo->PreferredPath));\r\n    } else {\r\n\r\n        TracePrint((TRACE_LEVEL_ERROR,\r\n                    TRACE_FLAG_WMI,\r\n                    \"DsmpQueryDsmDefaultPolicy (Context %p): Query for MSDSM-wide policy, status %x.\\n\",\r\n                    DsmContext,\r\n                    status));\r\n    }\r\n\r\n__Exit_DsmpQueryDsmDefaultPolicy:\r\n\r\n    TracePrint((TRACE_LEVEL_VERBOSE,\r\n                TRACE_FLAG_WMI,\r\n                \"DsmpQueryDsmDefaultPolicy (Context %p): Exiting function with status %x.\\n\",\r\n                DsmContext,\r\n                status));\r\n\r\n    return status;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/msdsm/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"sampledsm\")\n    add_rules(\"wdk.env.wdm\", \"wdk.driver\")\n    add_values(\"wdk.tracewpp.flags\", \"-func:TracePrint((LEVEL,FLAGS,MSG,...))\")\n    add_files(\"*.c\", {rules = \"wdk.tracewpp\"})\n    add_files(\"*.rc\", \"*.inf\")\n    add_files(\"*.mof|msdsm.mof\")\n\n    -- add file msdsm.mof and modify default wdk.mof.header for this file\n    add_files(\"msdsm.mof\", {values = {wdk_mof_header = \"msdsmwmi.h\"}})\n\n    set_pcheader(\"precomp.h\")\n    add_links(\"mpio\")\n\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/perfcounters/kcs.c",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    kcs.c\r\n\r\nAbstract:\r\n\r\n    This module contains sample code to demonstrate how to provide\r\n    counter data from a kernel driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode only.\r\n\r\n--*/\r\n\r\n\r\n#include <wdm.h>\r\n#include \"kcs.h\"\r\n#include \"kcsCounters.h\"\r\n\r\n#include <stdlib.h>\r\n#include <math.h>\r\n\r\n#pragma code_seg(\"PAGE\")\r\n\r\nDRIVER_INITIALIZE DriverEntry;\r\nDRIVER_UNLOAD KcsUnload;\r\n\r\nNTSTATUS\r\nKcsAddGeometricInstance (\r\n    _In_ PPCW_BUFFER Buffer,\r\n    _In_ PCWSTR Name,\r\n    _In_ ULONG MinimalValue,\r\n    _In_ ULONG Amplitude\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This utility function adds instance to the callback buffer.\r\n\r\nArguments:\r\n\r\n    Buffer - Data will be returned in this buffer.\r\n\r\n    Name - Name of instances to be added.\r\n\r\n    MinimalValue - Minimum value of the wave.\r\n\r\n    Amplitude - Amplitude of the wave.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS indicating if the function succeeded.\r\n\r\n--*/\r\n\r\n{\r\n    ULONG Index;\r\n    LARGE_INTEGER Timestamp;\r\n    UNICODE_STRING UnicodeName;\r\n    GEOMETRIC_WAVE_VALUES Values;\r\n\r\n    PAGED_CODE();\r\n\r\n    KeQuerySystemTime(&Timestamp);\r\n\r\n    Index = (Timestamp.QuadPart / 10000000) % 10;\r\n\r\n    Values.Triangle = MinimalValue + Amplitude * abs(5 - Index) / 5;\r\n    Values.Square = MinimalValue + Amplitude * (Index < 5);\r\n\r\n    RtlInitUnicodeString(&UnicodeName, Name);\r\n\r\n    return KcsAddGeometricWave(Buffer, &UnicodeName, 0, &Values);\r\n}\r\n\r\nNTSTATUS NTAPI\r\nKcsGeometricWaveCallback (\r\n    _In_ PCW_CALLBACK_TYPE Type,\r\n    _In_ PPCW_CALLBACK_INFORMATION Info,\r\n    _In_opt_ PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function returns the list of counter instances and counter data.\r\n\r\nArguments:\r\n\r\n    Type - Request type.\r\n\r\n    Info - Buffer for returned data.\r\n\r\n    Context - Not used.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS indicating if the function succeeded.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS Status;\r\n    UNICODE_STRING UnicodeName;\r\n\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    PAGED_CODE();\r\n\r\n    switch (Type) {\r\n    case PcwCallbackEnumerateInstances:\r\n\r\n        //\r\n        // Instances are being enumerated, so we add them without values.\r\n        //\r\n\r\n        RtlInitUnicodeString(&UnicodeName, L\"Small Wave\");\r\n        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,\r\n                                     &UnicodeName,\r\n                                     0,\r\n                                     NULL);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        RtlInitUnicodeString(&UnicodeName, L\"Medium Wave\");\r\n        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,\r\n                                     &UnicodeName,\r\n                                     0,\r\n                                     NULL);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        RtlInitUnicodeString(&UnicodeName, L\"Large Wave\");\r\n        Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer,\r\n                                     &UnicodeName,\r\n                                     0,\r\n                                     NULL);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        break;\r\n\r\n    case PcwCallbackCollectData:\r\n\r\n        //\r\n        // Add values for 3 instances of Geometric Wave Counter Set.\r\n        //\r\n\r\n        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,\r\n                                         L\"Small Wave\",\r\n                                         40,\r\n                                         20);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,\r\n                                         L\"Medium Wave\",\r\n                                         30,\r\n                                         40);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        Status = KcsAddGeometricInstance(Info->CollectData.Buffer,\r\n                                         L\"Large Wave\",\r\n                                         20,\r\n                                         60);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        break;\r\n    }\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nNTSTATUS\r\nKcsAddTrignometricInstance (\r\n    _In_ PPCW_BUFFER Buffer,\r\n    _In_ PCWSTR Name,\r\n    _In_ ULONG MinimalValue,\r\n    _In_ ULONG Amplitude\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This utility function adds instance to the callback buffer.\r\n\r\nArguments:\r\n\r\n    Buffer - Data will be returned in this buffer.\r\n\r\n    Name - Name of instances to be added.\r\n\r\n    MinimalValue - Minimum value of the wave.\r\n\r\n    Amplitude - Amplitude of the wave.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS indicating if the function succeeded.\r\n\r\n--*/\r\n\r\n{\r\n    double Angle;\r\n    KFLOATING_SAVE FloatSave;\r\n    NTSTATUS Status;\r\n    LARGE_INTEGER Timestamp;\r\n    UNICODE_STRING UnicodeName;\r\n    TRIGNOMETRIC_WAVE_VALUES Values;\r\n\r\n    PAGED_CODE();\r\n\r\n    Status = KeSaveFloatingPointState(&FloatSave);\r\n    if (!NT_SUCCESS(Status)) {\r\n        return Status;\r\n    }\r\n\r\n    KeQuerySystemTime(&Timestamp);\r\n\r\n    Angle = (double)(Timestamp.QuadPart / 400000) * (22/7) / 180;\r\n\r\n    Values.Constant = MinimalValue;\r\n    Values.Cosine = (ULONG)(MinimalValue + Amplitude * cos(Angle));\r\n    Values.Sine = (ULONG)(MinimalValue + Amplitude * sin(Angle));\r\n\r\n    KeRestoreFloatingPointState(&FloatSave);\r\n\r\n    //\r\n    // Add instance name & values to the caller's buffer.\r\n    //\r\n\r\n    RtlInitUnicodeString(&UnicodeName, Name);\r\n\r\n    return KcsAddTrignometricWave(Buffer, &UnicodeName, 0, &Values);\r\n}\r\n\r\nNTSTATUS NTAPI\r\nKcsTrignometricWaveCallback (\r\n    _In_ PCW_CALLBACK_TYPE Type,\r\n    _In_ PPCW_CALLBACK_INFORMATION Info,\r\n    _In_opt_ PVOID Context\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function returns the list of counter instances and counter data.\r\n\r\nArguments:\r\n\r\n    Type - Request type.\r\n\r\n    Info - Buffer for returned data.\r\n\r\n    Context - Not used.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS indicating if the function succeeded.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS Status;\r\n    UNICODE_STRING UnicodeName;\r\n\r\n    UNREFERENCED_PARAMETER(Context);\r\n\r\n    PAGED_CODE();\r\n\r\n    switch (Type) {\r\n    case PcwCallbackEnumerateInstances:\r\n        RtlInitUnicodeString(&UnicodeName, L\"default\");\r\n        Status = KcsAddTrignometricWave(Info->EnumerateInstances.Buffer,\r\n                                        &UnicodeName,\r\n                                        0,\r\n                                        NULL);\r\n        if (!NT_SUCCESS(Status)) {\r\n            return Status;\r\n        }\r\n\r\n        break;\r\n\r\n    case PcwCallbackCollectData:\r\n\r\n        //\r\n        // Add values for Single Instance of Trignometirc Wave Counter Set.\r\n        //\r\n\r\n        return KcsAddTrignometricInstance(Info->CollectData.Buffer,\r\n                                          L\"default\",\r\n                                          50,\r\n                                          30);\r\n    }\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nVOID\r\nKcsUnload (\r\n    _In_ PDRIVER_OBJECT DriverObject\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function unregisters countersets\r\n\r\nArguments:\r\n\r\n    DriverObject - Not used.\r\n\r\nReturn Value:\r\n\r\n    None.\r\n\r\n--*/\r\n\r\n{\r\n    UNREFERENCED_PARAMETER(DriverObject);\r\n\r\n    PAGED_CODE();\r\n\r\n    //\r\n    // Unregister Countersets.\r\n    //\r\n\r\n    KcsUnregisterGeometricWave();\r\n    KcsUnregisterTrignometricWave();\r\n}\r\n\r\nNTSTATUS\r\nDriverEntry (\r\n    _In_ PDRIVER_OBJECT DriverObject,\r\n    _In_ PUNICODE_STRING RegistryPath\r\n    )\r\n\r\n/*++\r\n\r\nRoutine Description:\r\n\r\n    This function registers countersets on initial loading of the driver.\r\n\r\nArguments:\r\n\r\n    DriverObject - Supplies the driver object of the driver being loaded.\r\n\r\n    RegistryPath - Not used.\r\n\r\nReturn Value:\r\n\r\n    NTSTATUS indicating if driver was properly loaded.\r\n\r\n--*/\r\n\r\n{\r\n    NTSTATUS Status;\r\n\r\n    UNREFERENCED_PARAMETER(RegistryPath);\r\n\r\n    PAGED_CODE();\r\n\r\n    //\r\n    // Register Countersets.\r\n    //\r\n\r\n    Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL);\r\n    if (!NT_SUCCESS(Status)) {\r\n        return Status;\r\n    }\r\n\r\n    Status = KcsRegisterTrignometricWave(KcsTrignometricWaveCallback, NULL);\r\n    if (!NT_SUCCESS(Status)) {\r\n        KcsUnregisterTrignometricWave();\r\n        return Status;\r\n    }\r\n\r\n    //\r\n    // Success path - set up unload routine and return success.\r\n    //\r\n\r\n    DriverObject->DriverUnload = KcsUnload;\r\n\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/perfcounters/kcs.h",
    "content": "/*++\r\n\r\nCopyright (c) Microsoft Corporation.  All rights reserved.\r\n\r\n    THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\r\n    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r\n    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\r\n    PURPOSE.\r\n\r\nModule Name:\r\n\r\n    kcs.h\r\n\r\nAbstract:\r\n\r\n    This module contains sample code to demonstrate how to provide\r\n    counter data from a kernel driver.\r\n\r\nEnvironment:\r\n\r\n    Kernel mode only.\r\n\r\n--*/\r\n\r\ntypedef struct _GEOMETRIC_WAVE_VALUES {\r\n    ULONG Square;\r\n    ULONG Triangle;\r\n} GEOMETRIC_WAVE_VALUES, *PGEOMETRIC_WAVE_VALUES;\r\n\r\ntypedef struct _TRIGNOMETRIC_WAVE_VALUES {\r\n    ULONG Constant;\r\n    ULONG Cosine;\r\n    ULONG Sine;\r\n} TRIGNOMETRIC_WAVE_VALUES, *PTRIGNOMETRIC_WAVE_VALUES;"
  },
  {
    "path": "tests/projects/windows/driver/wdm/perfcounters/kcs.man",
    "content": "<instrumentationManifest\n    xmlns=\"http://schemas.microsoft.com/win/2004/08/events\"\n    xmlns:trace=\"http://schemas.microsoft.com/win/2004/08/events/trace\"\n    xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\"\n    xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://schemas.microsoft.com/win/2004/08/events eventman.xsd\"\n    >\n    <instrumentation>\n        <counters\n            xmlns=\"http://schemas.microsoft.com/win/2005/12/counters\"\n            xmlns:auto-ns1=\"http://schemas.microsoft.com/win/2004/08/events\"\n            schemaVersion=\"1.1\"\n            >\n            <provider callback = \"custom\"\n                      applicationIdentity = \"Kcs.sys\"\n                      providerType = \"kernelMode\"\n                      providerName = \"KernelCountersSample\"\n                      providerGuid = \"{d2ffffff-965a-4cf9-9c07-fe25378c2a23}\">\n                <counterSet guid        = \"{d2ffffff-c923-4794-b696-70577630b5cf}\"\n                            uri         = \"Microsoft.Wdk.Samples.Kcs.GeometricWave\"\n                            name        = \"Geometric Waves\"\n                            description = \"This counter set displays a Triangle and a Square wave\"\n  \t\t            symbol       = \"GeometricWave\"\n                            instances   = \"multipleAggregate\"\n\t\t\t    >\t\n \t          <structs>\t\n        \t    <struct name=\"GeometricWaveValues\" type=\"GEOMETRIC_WAVE_VALUES\"/>\n        \t  </structs>\n                    <counter id           = \"1\"\n                             uri          = \"Microsoft.Wdk.Samples.Kcs.GeometricWave.Triangle\"\n                             name         = \"Triangle\"\n\t                     struct       = \"GeometricWaveValues\"\t\n\t\t             field        = \"Triangle\"\n                             description  = \"This counter displays triangle wave\"\n                             aggregate    = \"avg\"  \n                             type         = \"perf_counter_rawcount\"\n                             detailLevel  = \"standard\">\n                    </counter>\n\n                    <counter id           = \"2\"\n                             uri          = \"Microsoft.Wdk.Samples.Kcs.GeometricWave.Square\"\n                             name         = \"Square Wave\"\n\t                     struct       = \"GeometricWaveValues\"\t\n\t\t             field        = \"Square\"\n                             description  = \"This counter displays Square Wave\"\n                             aggregate    = \"avg\"  \n                             type         = \"perf_counter_rawcount\"\n                             detailLevel  = \"standard\">\n                    </counter>\n                </counterSet>\n                <counterSet guid        = \"{ffffffff-eaa6-45ba-bf6d-4c7cb0d6ef73}\"\n                            uri         = \"Microsoft.Wdk.Samples.Kcs.TrignometricWave\"\n                            name        = \"Trignometric Waves\"\n                            description = \"This counter set displays a sine, cosine and a constant wave\"\n\t\t\t    symbol       = \"TrignometricWave\"\n                            instances   = \"single\">\n \t          <structs>\t\n        \t    <struct name=\"TrignometricWaveValues\" type=\"TRIGNOMETRIC_WAVE_VALUES\"/>\n        \t  </structs>\n                    <counter id           = \"1\"\n                             uri          = \"Microsoft.Wdk.Samples.Kcs.TrignometricWave.Sine\"\n                             name         = \"Sine Wave\"\n                             description  = \"This counter displays Sine Wave\"\n\t                     struct       = \"TrignometricWaveValues\"\n\t\t             field        = \"Sine\"\t\n                             type         = \"perf_counter_rawcount\"\n                             detailLevel  = \"standard\">\n                        <counterAttributes>\n                            <counterAttribute name = \"reference\" />\n                        </counterAttributes>\n                    </counter>\n                    <counter id           = \"2\"\n                             uri          = \"Microsoft.Wdk.Samples.Kcs.TrignometricWave.Cosine\"\n                             name         = \"Cosine Wave\"\n                             description  = \"This counter displays Cosine Wave\"\n\t                     struct       = \"TrignometricWaveValues\"\n\t\t             field        = \"Cosine\"\t\t\n                             type         = \"perf_counter_rawcount\"\n\t\t\t     detailLevel  = \"standard\">\n                        <counterAttributes>\n                            <counterAttribute name = \"reference\" />\n                        </counterAttributes>\n                    </counter>\n                    <counter id           = \"3\"\n                             uri          = \"Microsoft.Wdk.Samples.Kcs.TrignometricWave.Constant\"\n                             name         = \"Constant Value\"\n                             description  = \"This counter displays Constant Value\"\n\t                     struct       = \"TrignometricWaveValues\"\t\n\t\t             field        = \"Constant\"\t\t\n                             type         = \"perf_counter_rawcount\"\n                             detailLevel  = \"standard\">\n                        <counterAttributes>\n                            <counterAttribute name = \"reference\" />\n                        </counterAttributes>\n                    </counter>\n                </counterSet>            \n\t    </provider>\n        </counters>\n    </instrumentation>\n</instrumentationManifest>"
  },
  {
    "path": "tests/projects/windows/driver/wdm/perfcounters/kcs.rc",
    "content": "#include \"kcsCounters.rc\"\r\n"
  },
  {
    "path": "tests/projects/windows/driver/wdm/perfcounters/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"kcs\")\n    add_rules(\"wdk.env.wdm\", \"wdk.driver\")\n    add_values(\"wdk.man.prefix\", \"Kcs\")\n    add_values(\"wdk.man.resource\", \"kcsCounters.rc\")\n    add_values(\"wdk.man.header\", \"kcsCounters.h\")\n    add_values(\"wdk.man.counter_header\", \"kcsCounters_counters.h\")\n    add_files(\"*.c\", \"*.rc\", \"*.man\")\n\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc/src/lockowner.idl",
    "content": "/*\n * PROJECT:     SupernovaX SDK\n * LICENSE:     MIT (https://spdx.org/licenses/MIT)\n * PURPOSE:     Lock owner COM interfaces\n * COPYRIGHT:   Copyright 2023 Christian Rendina <pizzaiolo100@proton.me>\n */\nimport \"oaidl.idl\";\nimport \"ocidl.idl\";\n\n[\n    object,\n    local,\n    uuid(9b7e4a00-342c-4106-a19f-4f2704f689f0)\n]\ninterface ILockOwner : IUnknown\n{\n    void LOEnter(\n        void\n    );\n\n    void LOLeave(\n        void\n    );\n\n    BOOL LOTryEnter(\n        void\n    );\n};\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc/src/test_iid.c",
    "content": "#include <lockowner.h>\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    IID g = IID_ILockOwner;\n    printf(\"GUID: %x-%x-%x-%llx\", g.Data1, g.Data2, g.Data3, *(unsigned long long*)g.Data4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"idltest_norpc\")\n    set_kind(\"binary\")\n    add_files(\"src/*.idl\", { proxy = false })\n    add_files(\"src/*.c\")\n    add_syslinks(\"Rpcrt4\")\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc_proxy/src/lockowner.idl",
    "content": "/*\n * PROJECT:     SupernovaX SDK\n * LICENSE:     MIT (https://spdx.org/licenses/MIT)\n * PURPOSE:     Lock owner COM interfaces\n * COPYRIGHT:   Copyright 2023 Christian Rendina <pizzaiolo100@proton.me>\n */\nimport \"oaidl.idl\";\nimport \"ocidl.idl\";\n\n[\n    object,\n    local,\n    uuid(9b7e4a00-342c-4106-a19f-4f2704f689f0)\n]\ninterface ILockOwner : IUnknown\n{\n    void LOEnter(\n        void\n    );\n\n    void LOLeave(\n        void\n    );\n\n    BOOL LOTryEnter(\n        void\n    );\n};\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc_proxy/src/test_iid.c",
    "content": "#include <lockowner.h>\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    IID g = IID_ILockOwner;\n    printf(\"GUID: %x-%x-%x-%llx\", g.Data1, g.Data2, g.Data3, *(unsigned long long*)g.Data4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_norpc_proxy/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"idltest_norpc\")\n    set_kind(\"binary\")\n    add_files(\"src/*.idl\")\n    add_files(\"src/*.c\")\n    add_syslinks(\"Rpcrt4\")\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc/src/example.idl",
    "content": "[\n    uuid(ba209999-0c6c-11d2-97cf-00c04f8eea45),\n    version(1.0)\n]\ninterface MyInterface\n{\n    const unsigned short INT_ARRAY_LEN = 100;\n\n    void MyRemoteProc( \n        [in] int param1,\n        [out] int outArray[INT_ARRAY_LEN]\n    );\n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc/src/test_iid.c",
    "content": "#include <Windows.h>\n#include <example.h>\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    MyInterface_v1_0_c_ifspec = (void*)1;\n    MyInterface_v1_0_s_ifspec = (void*)1;\n    printf(\"set ok\\n\");\n    return 0;\n}\n\nvoid __RPC_FAR * __RPC_API midl_user_allocate(size_t cBytes) { \n    return(malloc(cBytes)); \n}\n\nvoid __RPC_API midl_user_free(void __RPC_FAR * p) { \n    free(p); \n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"idltest_rpc\")\n    set_kind(\"binary\")\n    add_files(\"src/*.idl\", {client = true, server = true})\n    add_files(\"src/*.c\")\n    add_syslinks(\"Rpcrt4\")\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc_noserver/src/example.idl",
    "content": "[\n    uuid(ba209999-0c6c-11d2-97cf-00c04f8eea45),\n    version(1.0)\n]\ninterface MyInterface\n{\n    const unsigned short INT_ARRAY_LEN = 100;\n\n    void MyRemoteProc( \n        [in] int param1,\n        [out] int outArray[INT_ARRAY_LEN]\n    );\n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc_noserver/src/test_iid.c",
    "content": "#include <Windows.h>\n#include <example.h>\n#include <stdio.h>\n\nint main(int argc, char** argv) {\n    MyInterface_v1_0_c_ifspec = (void*)1;\n    printf(\"call ok\\n\");\n    return 0;\n}\n\nvoid __RPC_FAR * __RPC_API midl_user_allocate(size_t cBytes) {\n    return(malloc(cBytes)); \n}\n\nvoid __RPC_API midl_user_free(void __RPC_FAR * p) {\n    free(p); \n}\n"
  },
  {
    "path": "tests/projects/windows/idl/test_rpc_noserver/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"idltest_rpc_noserver\")\n    set_kind(\"binary\")\n    add_files(\"src/*.idl\", {client = true, server = false})\n    add_files(\"src/*.c\")\n    add_syslinks(\"Rpcrt4\")\n"
  },
  {
    "path": "tests/projects/windows/windows_links/src/foo.c",
    "content": "#include <stdio.h>\r\n\r\n#ifdef _WIN32\r\n__declspec(dllexport) \r\n#endif\r\nvoid foo() {\r\n    printf(\"foo called\\n\");\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/windows_links/src/main.c",
    "content": "#include <windows.h>\r\n#include <psapi.h>\r\n#include <stdio.h>\r\n\r\n__declspec(dllimport) void foo();\r\n\r\nint main() {\r\n    PROCESS_MEMORY_COUNTERS pmc;\r\n    printf(\"Calling GetProcessMemoryInfo...\\n\");\r\n    if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {\r\n        printf(\"PageFaultCount: %lu\\n\", pmc.PageFaultCount);\r\n        printf(\"WorkingSetSize: %lu\\n\", pmc.WorkingSetSize);\r\n    } else {\r\n        printf(\"GetProcessMemoryInfo failed (%lu)\\n\", GetLastError());\r\n    }\r\n    printf(\"Calling foo...\\n\");\r\n    foo();\r\n    printf(\"Done.\\n\");\r\n    return 0;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/windows_links/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\r\n\r\nset_policy(\"run.windows_error_dialog\", true)\r\n\r\ntarget(\"foo\")\r\n    set_kind(\"shared\")\r\n    add_files(\"src/foo.c\")\r\n\r\ntarget(\"test_foo_dll_presence\")\r\n    set_kind(\"binary\")\r\n    add_files(\"src/main.c\")\r\n    add_deps(\"foo\")\r\n    add_syslinks(\"psapi\")\r\n    after_build(function (target)\r\n        local foo = target:dep(\"foo\")\r\n        if foo then\r\n            os.tryrm(foo:targetfile())\r\n        end\r\n    end)\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/app.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!-- This config file is needed for Usbview to run on machines without .net3.5 installed -->\n<configuration>\n<startup useLegacyV2RuntimeActivationPolicy=\"true\">   \n\t<supportedRuntime version=\"v4.0.30319\" sku=\".NETFramework,Version=v4.0,Profile=Full\"/>\n\t<supportedRuntime version=\"v4.0.30319\"/>\n\t<supportedRuntime version=\"v4.0\"/>\n\t<supportedRuntime version=\"v3.5\"/>\n\t<supportedRuntime version=\"v3.0\"/>\n\t<supportedRuntime version=\"v2.0.50727\"/>\n</startup>\n</configuration>\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/codeanalysis.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2011 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    CODEANALYSIS.H\r\n\r\nAbstract:\r\n\r\n    This header file is used for supressing fxcop errors which are not applicable\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    08-11-11 : created\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n#if CODE_ANALYSIS\r\n\r\n/*****************************************************************************\r\n  C O D E  A N A L Y S I S  S U P P R E S S I O N S\r\n *****************************************************************************/\r\n\r\nusing namespace System::Diagnostics::CodeAnalysis;\r\n\r\nnamespace Microsoft\r\n{\r\n    namespace Kits\r\n    {\r\n        namespace Samples\r\n        {\r\n            namespace Usb\r\n            {\r\n                // Justification : C++ Compiler cannot enforce ClsCompliant\r\n                [module: SuppressMessage(\"Microsoft.Design\", \"CA1014:MarkAssembliesWithClsCompliant\")]\r\n\r\n                // Justification : The naming of the following types are based on native USB types\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType\", MessageId=\"Bos\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.Hub30DescriptorType.#HubHdrDecLat\", MessageId=\"Hdr\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMajorSpecVersion\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMinorSpecVersion\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMinorVersion\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.MachineInfoType.#UvcMajorVersion\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceClassDetailsType.#UvcVersion\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#BNumDeviceCaps\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbDispContIdCapExtDescriptor\", MessageId=\"Disp\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#BosDescriptor\", MessageId=\"Bos\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.NodeConnectionInfoExType.#IProductStringDescEn\", MessageId=\"Desc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#OtgDescriptor\", MessageId=\"Otg\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#OtgError\", MessageId=\"Otg\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#IadError\", MessageId=\"Iad\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#IadDescriptor\", MessageId=\"Iad\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceIADDescriptorType.#StringDesc\", MessageId=\"Desc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#BNumEndpoints\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#StringDesc\", MessageId=\"Desc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceInterfaceDescriptorType.#WNumClasses\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#NumOfOpenPipes\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#SpeedStr\", MessageId=\"Str\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#ConfStringDesc\", MessageId=\"Desc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#AttributesStr\", MessageId=\"Str\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#ConfigDescError\", MessageId=\"Desc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#BNumInterfaces\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UvcViewAll\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UvcViewAll.#UvcView\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UsbDispContIdCapExtDescriptorType\", MessageId=\"Disp\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDispContIdCapExtDescriptorType.#ContainerIdStr\", MessageId=\"Str\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConnectionStatusType.#DeviceCausedOvercurrent\", MessageId=\"Overcurrent\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#NumConfigurations\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#DeviceNumConfigError\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#NumConfigurations\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceType.#BosDescriptor\", MessageId=\"Bos\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UvcViewType\", MessageId=\"Uvc\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#BNumDescriptors\", MessageId=\"Num\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1711:IdentifiersShouldNotHaveIncorrectSuffix\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#HubInformationEx\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1711:IdentifiersShouldNotHaveIncorrectSuffix\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#HubInformationEx\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1702:CompoundWordsShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceConfigurationType.#PreReleaseError\", MessageId=\"PreRelease\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1702:CompoundWordsShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbHCPowerStateType.#CanWakeUp\", MessageId=\"WakeUp\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbSuperSpeedExtensionDescriptorType.#BmAttributes\", MessageId=\"Bm\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbUsb20ExtensionDescriptorType.#BmAttributes\", MessageId=\"Bm\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.HubNodeType.#UsbMiParent\", MessageId=\"Mi\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#HwId\", MessageId=\"Hw\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.HostControllerType.#HwId\", MessageId=\"Hw\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceOTGDescriptorType\", MessageId=\"OTG\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceOTGDescriptorType.#BmAttributes\", MessageId=\"Bm\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.HubNodeInformationType.#MiParentNumberOfInterfaces\", MessageId=\"Mi\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.NodeConnectionInfoExType.#IProductStringDescEn\", MessageId=\"En\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"type\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceIADDescriptorType\", MessageId=\"IAD\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbConfigurationDescriptorType.#BmAttributes\", MessageId=\"Bm\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#HwId\", MessageId=\"Hw\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceQualifierDescriptorType.#BcdUSB\", MessageId=\"USB\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdDevice\", MessageId=\"Cd\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdUSB\", MessageId=\"USB\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceDescriptorType.#CdUSB\", MessageId=\"Cd\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceType.#HwId\", MessageId=\"Hw\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#BcdHID\", MessageId=\"HID\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1711:IdentifiersShouldNotHaveIncorrectSuffix\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#HubCapabilityEx\")]\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1711:IdentifiersShouldNotHaveIncorrectSuffix\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#HubCapabilityEx\")]\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.HubCapabilitiesExType.#HubIsMultiTt\", MessageId=\"Multi\")]\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.HubCapabilitiesExType.#HubIsMultiTtCapable\", MessageId=\"Multi\")]\r\n\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1709:IdentifiersShouldBeCasedCorrectly\", MessageId=\"usbview\")];\r\n                [module: SuppressMessage(\"Microsoft.Naming\", \"CA1704:IdentifiersShouldBeSpelledCorrectly\", MessageId=\"usbview\")];\r\n\r\n                // Justification: The version of XSD which is used to generate the objects does not support Collections.\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbSuperSpeedExtensionDescriptor\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbUsb20ExtensionDescriptor\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UnknownDescriptor\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbBosDescriptorType.#UsbDispContIdCapExtDescriptor\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#UsbDevice\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#DeviceConfiguration\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#NoDevice\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.ExternalHubType.#ExternalHub\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.NodeConnectionInfoExStructType.#Pipe\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbHCPowerStateMappingType.#PowerMap\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#NoDevice\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#ExternalHub\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.RootHubType.#UsbDevice\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceType.#DeviceConfiguration\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UvcViewType.#UsbTree\")];\r\n                [module: SuppressMessage(\"Microsoft.Performance\", \"CA1819:PropertiesShouldNotReturnArrays\", Scope=\"member\", Target=\"Microsoft.Kits.Samples.Usb.UsbDeviceHidDescriptorType.#OptionalDescriptor\")];\r\n                };\r\n        };\r\n    };\r\n};\r\n\r\n#endif\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/debug.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    DEBUG.C\r\n\r\nAbstract:\r\n\r\n    This source file contains debug routines.\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    07-08-97 : created\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\n I N C L U D E S\r\n*****************************************************************************/\r\n\r\n#include \"uvcview.h\"\r\n\r\n#if DBG\r\n\r\n/*****************************************************************************\r\n T Y P E D E F S\r\n*****************************************************************************/\r\n\r\ntypedef struct _ALLOCHEADER\r\n{\r\n    LIST_ENTRY  ListEntry;\r\n\r\n    PCHAR       File;\r\n\r\n    ULONG       Line;\r\n\r\n} ALLOCHEADER, *PALLOCHEADER;\r\n\r\n\r\n/*****************************************************************************\r\n G L O B A L S\r\n*****************************************************************************/\r\n\r\nLIST_ENTRY AllocListHead =\r\n{\r\n    &AllocListHead,\r\n    &AllocListHead\r\n};\r\n\r\n\r\n/*****************************************************************************\r\n\r\n MyAlloc()\r\n\r\n*****************************************************************************/\r\n_Success_(return != NULL)\r\n_Post_writable_byte_size_(dwBytes)\r\nHGLOBAL\r\nMyAlloc (\r\n    _In_    PCHAR   File,\r\n    ULONG   Line,\r\n    DWORD   dwBytes\r\n)\r\n{\r\n    PALLOCHEADER header;\r\n    DWORD dwRequest = dwBytes;\r\n\r\n    if (0 == dwBytes)\r\n    {\r\n        return NULL;\r\n    }\r\n\r\n    dwBytes += sizeof(ALLOCHEADER);\r\n    // check for integer overflow\r\n    if (dwBytes > dwRequest)\r\n    {\r\n        header = (PALLOCHEADER)GlobalAlloc(GPTR, dwBytes);\r\n\r\n        if (header != NULL)\r\n        {\r\n            InsertTailList(&AllocListHead, &header->ListEntry);\r\n\r\n            header->File = File;\r\n            header->Line = Line;\r\n\r\n            return (HGLOBAL)(header + 1);\r\n        }\r\n    }\r\n    return NULL;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n MyReAlloc()\r\n\r\n*****************************************************************************/\r\n\r\n_Success_(return != NULL)\r\n_Post_writable_byte_size_(dwBytes)\r\nHGLOBAL\r\nMyReAlloc (\r\n    HGLOBAL hMem,\r\n    DWORD   dwBytes\r\n)\r\n{\r\n    PALLOCHEADER header;\r\n    PALLOCHEADER headerNew;\r\n\r\n    if ((NULL == hMem) || (0 == dwBytes))\r\n    {\r\n        return NULL;\r\n    }\r\n\r\n    header = (PALLOCHEADER)hMem;\r\n    header--;\r\n\r\n    // Remove the old address from the allocation list\r\n    //\r\n    RemoveEntryList(&header->ListEntry);\r\n\r\n    if (dwBytes < (dwBytes + (DWORD) sizeof(ALLOCHEADER)))\r\n        {\r\n        dwBytes += sizeof(ALLOCHEADER);\r\n        headerNew = GlobalReAlloc((HGLOBAL)header, dwBytes, GMEM_MOVEABLE|GMEM_ZEROINIT);\r\n\r\n        if (NULL == headerNew)\r\n        {\r\n            // If GlobalReAlloc fails, the original memory is not freed,\r\n            // and the original handle and pointer are still valid.\r\n            // Add the old address back to the allocation list.\r\n            //\r\n            #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR, \"SAL noise\")\r\n            InsertTailList(&AllocListHead, &header->ListEntry);\r\n        }\r\n        else\r\n        {\r\n            // Add the new address to the allocation list\r\n            //\r\n            InsertTailList(&AllocListHead, &headerNew->ListEntry);\r\n\r\n            return (HGLOBAL)(headerNew + 1);\r\n        }\r\n    }\r\n    return NULL;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n MyFree()\r\n\r\n*****************************************************************************/\r\n\r\nHGLOBAL\r\nMyFree (\r\n    HGLOBAL hMem\r\n)\r\n{\r\n    PALLOCHEADER header;\r\n\r\n    if (hMem)\r\n    {\r\n        header = (PALLOCHEADER)hMem;\r\n\r\n        header--;\r\n\r\n        RemoveEntryList(&header->ListEntry);\r\n\r\n        return GlobalFree((HGLOBAL)header);\r\n    }\r\n\r\n    return GlobalFree(hMem);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n MyCheckForLeaks()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nMyCheckForLeaks (\r\n    VOID\r\n)\r\n{\r\n    PALLOCHEADER header;\r\n    CHAR         buf[128];\r\n\r\n    memset(buf, 0, sizeof(buf));\r\n\r\n    while (!IsListEmpty(&AllocListHead))\r\n    {\r\n        header = (PALLOCHEADER)RemoveHeadList(&AllocListHead);\r\n\r\n        StringCbPrintf(buf, sizeof(buf),\r\n                 \"File: %s, Line: %d\\r\\n\",\r\n                 header->File,\r\n                 header->Line);\r\n\r\n        OutputDebugString(buf);\r\n    }\r\n}\r\n\r\n#endif\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/devnode.c",
    "content": "/*++\r\n\r\n  Copyright (c) 1998-2011 Microsoft Corporation\r\n\r\n  Module Name:\r\n\r\n  DEVNODE.C\r\n\r\n  --*/\r\n\r\n/*****************************************************************************\r\n  I N C L U D E S\r\n *****************************************************************************/\r\n\r\n#include \"uvcview.h\"\r\n\r\n/*****************************************************************************\r\n\r\n  DriverNameToDeviceInst()\r\n\r\n  Finds the Device instance of the DevNode with the matching DriverName.\r\n  Returns FALSE if the matching DevNode is not found and TRUE if found\r\n\r\n *****************************************************************************/\r\nBOOL\r\nDriverNameToDeviceInst(\r\n    _In_reads_bytes_(cbDriverName) PCHAR DriverName,\r\n    _In_ size_t cbDriverName,\r\n    _Out_ HDEVINFO *pDevInfo,\r\n    _Out_writes_bytes_(sizeof(SP_DEVINFO_DATA)) PSP_DEVINFO_DATA pDevInfoData\r\n    )\r\n{\r\n    HDEVINFO         deviceInfo = INVALID_HANDLE_VALUE;\r\n    BOOL             status = TRUE;\r\n    ULONG            deviceIndex;\r\n    SP_DEVINFO_DATA  deviceInfoData;\r\n    BOOL             bResult = FALSE;\r\n    PCHAR            pDriverName = NULL;\r\n    PSTR             buf = NULL;\r\n    BOOL             done = FALSE;\r\n\r\n    if (pDevInfo == NULL)\r\n    {\r\n        return FALSE;\r\n    }\r\n\r\n    if (pDevInfoData == NULL)\r\n    {\r\n        return FALSE;\r\n    }\r\n\r\n    memset(pDevInfoData, 0, sizeof(SP_DEVINFO_DATA));\r\n\r\n    *pDevInfo = INVALID_HANDLE_VALUE;\r\n\r\n    // Use local string to guarantee zero termination\r\n    pDriverName = (PCHAR) ALLOC((DWORD) cbDriverName + 1);\r\n    if (NULL == pDriverName)\r\n    {\r\n        status = FALSE;\r\n        goto Done;\r\n    }\r\n    StringCbCopyN(pDriverName, cbDriverName + 1, DriverName, cbDriverName);\r\n\r\n    //\r\n    // We cannot walk the device tree with CM_Get_Sibling etc. unless we assume\r\n    // the device tree will stabilize. Any devnode removal (even outside of USB)\r\n    // would force us to retry. Instead we use Setup API to snapshot all\r\n    // devices.\r\n    //\r\n\r\n    // Examine all present devices to see if any match the given DriverName\r\n    //\r\n    deviceInfo = SetupDiGetClassDevs(NULL,\r\n            NULL,\r\n            NULL,\r\n            DIGCF_ALLCLASSES | DIGCF_PRESENT);\r\n\r\n    if (deviceInfo == INVALID_HANDLE_VALUE)\r\n    {\r\n        status = FALSE;\r\n        goto Done;\r\n    }\r\n\r\n    deviceIndex = 0;\r\n    deviceInfoData.cbSize = sizeof(deviceInfoData);\r\n\r\n    while (done == FALSE)\r\n    {\r\n        //\r\n        // Get devinst of the next device\r\n        //\r\n\r\n        status = SetupDiEnumDeviceInfo(deviceInfo,\r\n                                       deviceIndex,\r\n                                       &deviceInfoData);\r\n\r\n        deviceIndex++;\r\n\r\n        if (!status)\r\n        {\r\n            //\r\n            // This could be an error, or indication that all devices have been\r\n            // processed. Either way the desired device was not found.\r\n            //\r\n\r\n            done = TRUE;\r\n            break;\r\n        }\r\n\r\n        //\r\n        // Get the DriverName value\r\n        //\r\n\r\n        bResult = GetDeviceProperty(deviceInfo,\r\n                                    &deviceInfoData,\r\n                                    SPDRP_DRIVER,\r\n                                    &buf);\r\n\r\n        // If the DriverName value matches, return the DeviceInstance\r\n        //\r\n        if (bResult == TRUE && buf != NULL && _stricmp(pDriverName, buf) == 0)\r\n        {\r\n            done = TRUE;\r\n            *pDevInfo = deviceInfo;\r\n            CopyMemory(pDevInfoData, &deviceInfoData, sizeof(deviceInfoData));\r\n            FREE(buf);\r\n            break;\r\n        }\r\n\r\n        if(buf != NULL)\r\n        {\r\n            FREE(buf);\r\n            buf = NULL;\r\n        }\r\n    }\r\n\r\nDone:\r\n\r\n    if (bResult == FALSE)\r\n    {\r\n        if (deviceInfo != INVALID_HANDLE_VALUE)\r\n        {\r\n            SetupDiDestroyDeviceInfoList(deviceInfo);\r\n        }\r\n    }\r\n\r\n    if (pDriverName != NULL)\r\n    {\r\n        FREE(pDriverName);\r\n    }\r\n\r\n    return status;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  DriverNameToDeviceProperties()\r\n\r\n  Returns the Device properties of the DevNode with the matching DriverName.\r\n  Returns NULL if the matching DevNode is not found.\r\n\r\n  The caller should free the returned structure using FREE() macro\r\n\r\n *****************************************************************************/\r\nPUSB_DEVICE_PNP_STRINGS\r\nDriverNameToDeviceProperties(\r\n        _In_reads_bytes_(cbDriverName) PCHAR  DriverName,\r\n        _In_ size_t cbDriverName\r\n        )\r\n{\r\n    HDEVINFO        deviceInfo = INVALID_HANDLE_VALUE;\r\n    SP_DEVINFO_DATA deviceInfoData = {0};\r\n    ULONG           len;\r\n    BOOL            status;\r\n    PUSB_DEVICE_PNP_STRINGS DevProps = NULL;\r\n    DWORD           lastError;\r\n\r\n    // Allocate device propeties structure\r\n    DevProps = (PUSB_DEVICE_PNP_STRINGS) ALLOC(sizeof(USB_DEVICE_PNP_STRINGS));\r\n\r\n    if(NULL == DevProps)\r\n    {\r\n        status = FALSE;\r\n        goto Done;\r\n    }\r\n\r\n    // Get device instance\r\n    status = DriverNameToDeviceInst(DriverName, cbDriverName, &deviceInfo, &deviceInfoData);\r\n    if (status == FALSE)\r\n    {\r\n        goto Done;\r\n    }\r\n\r\n    len = 0;\r\n    status = SetupDiGetDeviceInstanceId(deviceInfo,\r\n                                        &deviceInfoData,\r\n                                        NULL,\r\n                                        0,\r\n                                        &len);\r\n    lastError = GetLastError();\r\n\r\n\r\n    if (status != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER)\r\n    {\r\n        status = FALSE;\r\n        goto Done;\r\n    }\r\n\r\n    //\r\n    // An extra byte is required for the terminating character\r\n    //\r\n\r\n    len++;\r\n    DevProps->DeviceId = ALLOC(len);\r\n\r\n    if (DevProps->DeviceId == NULL)\r\n    {\r\n        status = FALSE;\r\n        goto Done;\r\n    }\r\n\r\n    status = SetupDiGetDeviceInstanceId(deviceInfo,\r\n                                        &deviceInfoData,\r\n                                        DevProps->DeviceId,\r\n                                        len,\r\n                                        &len);\r\n    if (status == FALSE)\r\n    {\r\n        goto Done;\r\n    }\r\n\r\n    status = GetDeviceProperty(deviceInfo,\r\n                               &deviceInfoData,\r\n                               SPDRP_DEVICEDESC,\r\n                               &DevProps->DeviceDesc);\r\n\r\n    if (status == FALSE)\r\n    {\r\n        goto Done;\r\n    }\r\n\r\n\r\n    //\r\n    // We don't fail if the following registry query fails as these fields are additional information only\r\n    //\r\n\r\n    GetDeviceProperty(deviceInfo,\r\n                      &deviceInfoData,\r\n                      SPDRP_HARDWAREID,\r\n                      &DevProps->HwId);\r\n\r\n    GetDeviceProperty(deviceInfo,\r\n                      &deviceInfoData,\r\n                      SPDRP_SERVICE,\r\n                      &DevProps->Service);\r\n\r\n    GetDeviceProperty(deviceInfo,\r\n                       &deviceInfoData,\r\n                       SPDRP_CLASS,\r\n                       &DevProps->DeviceClass);\r\nDone:\r\n\r\n    if (deviceInfo != INVALID_HANDLE_VALUE)\r\n    {\r\n        SetupDiDestroyDeviceInfoList(deviceInfo);\r\n    }\r\n\r\n    if (status == FALSE)\r\n    {\r\n        if (DevProps != NULL)\r\n        {\r\n            FreeDeviceProperties(&DevProps);\r\n        }\r\n    }\r\n    return DevProps;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  FreeDeviceProperties()\r\n\r\n  Free the device properties structure\r\n\r\n *****************************************************************************/\r\nVOID FreeDeviceProperties(_In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps)\r\n{\r\n    if(ppDevProps == NULL)\r\n    {\r\n        return;\r\n    }\r\n\r\n    if(*ppDevProps == NULL)\r\n    {\r\n        return;\r\n    }\r\n\r\n    if ((*ppDevProps)->DeviceId != NULL)\r\n    {\r\n        FREE((*ppDevProps)->DeviceId);\r\n    }\r\n\r\n    if ((*ppDevProps)->DeviceDesc != NULL)\r\n    {\r\n        FREE((*ppDevProps)->DeviceDesc);\r\n    }\r\n\r\n    //\r\n    // The following are not necessary, but left in case\r\n    // in the future there is a later failure where these\r\n    // pointer fields would be allocated.\r\n    //\r\n\r\n    if ((*ppDevProps)->HwId != NULL)\r\n    {\r\n        FREE((*ppDevProps)->HwId);\r\n    }\r\n\r\n    if ((*ppDevProps)->Service != NULL)\r\n    {\r\n        FREE((*ppDevProps)->Service);\r\n    }\r\n\r\n    if ((*ppDevProps)->DeviceClass != NULL)\r\n    {\r\n        FREE((*ppDevProps)->DeviceClass);\r\n    }\r\n\r\n    if ((*ppDevProps)->PowerState != NULL)\r\n    {\r\n        FREE((*ppDevProps)->PowerState);\r\n    }\r\n\r\n    FREE(*ppDevProps);\r\n    *ppDevProps = NULL;\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/dispaud.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\nDISPAUD.C\r\n\r\nAbstract:\r\n\r\nThis source file contains routines which update the edit control\r\nto display information about USB Audio descriptors.\r\n\r\nEnvironment:\r\n\r\nuser mode\r\n\r\nRevision History:\r\n\r\n03-07-1998 : created\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\n I N C L U D E S\r\n*****************************************************************************/\r\n\r\n#include \"uvcview.h\"\r\n\r\n/*****************************************************************************\r\n G L O B A L S    P R I V A T E    T O    T H I S    F I L E\r\n*****************************************************************************/\r\n\r\n//\r\n// USB Device Class Definition for Terminal Types  0.9 Draft Revision\r\n//\r\nSTRINGLIST slAudioTerminalTypes [] =\r\n{\r\n    //\r\n    // 2.1 USB Terminal Types\r\n    //\r\n    {0x0100, \"USB Undefined\",       \"\"},\r\n    {0x0101, \"USB streaming\",       \"\"},\r\n    {0x01FF, \"USB vendor specific\", \"\"},\r\n    //\r\n    // 2.2 Input Terminal Types\r\n    //\r\n    {0x0200, \"Input Undefined\",             \"\"},\r\n    {0x0201, \"Microphone\",                  \"\"},\r\n    {0x0202, \"Desktop microphone\",          \"\"},\r\n    {0x0203, \"Personal microphone\",         \"\"},\r\n    {0x0204, \"Omni-directional microphone\", \"\"},\r\n    {0x0205, \"Microphone array\",            \"\"},\r\n    {0x0206, \"Processing microphone array\", \"\"},\r\n    //\r\n    // 2.3 Output Terminal Types\r\n    //\r\n    {0x0300, \"Output Undefined\",              \"\"},\r\n    {0x0301, \"Speaker\",                       \"\"},\r\n    {0x0302, \"Headphones\",                    \"\"},\r\n    {0x0303, \"Head Mounted Display Audio\",    \"\"},\r\n    {0x0304, \"Desktop speaker\",               \"\"},\r\n    {0x0305, \"Room speaker\",                  \"\"},\r\n    {0x0306, \"Communication speaker\",         \"\"},\r\n    {0x0307, \"Low frequency effects speaker\", \"\"},\r\n    //\r\n    // 2.4 Bi-directional Terminal Types\r\n    //\r\n    {0x0400, \"Bi-directional Undefined\",        \"\"},\r\n    {0x0401, \"Handset\",                         \"\"},\r\n    {0x0402, \"Headset\",                         \"\"},\r\n    {0x0403, \"Speakerphone, no echo reduction\", \"\"},\r\n    {0x0404, \"Echo-suppressing speakerphone\",   \"\"},\r\n    {0x0405, \"Echo-canceling speakerphone\",     \"\"},\r\n    //\r\n    // 2.5 Telephony Terminal Types\r\n    //\r\n    {0x0500, \"Telephony Undefined\", \"\"},\r\n    {0x0501, \"Phone line\",          \"\"},\r\n    {0x0502, \"Telephone\",           \"\"},\r\n    {0x0503, \"Down Line Phone\",     \"\"},\r\n    //\r\n    // 2.6 External Terminal Types\r\n    //\r\n    {0x0600, \"External Undefined\",        \"\"},\r\n    {0x0601, \"Analog connector\",          \"\"},\r\n    {0x0602, \"Digital audio interface\",   \"\"},\r\n    {0x0603, \"Line connector\",            \"\"},\r\n    {0x0604, \"Legacy audio connector\",    \"\"},\r\n    {0x0605, \"S/PDIF interface\",          \"\"},\r\n    {0x0606, \"1394 DA stream\",            \"\"},\r\n    {0x0607, \"1394 DV stream soundtrack\", \"\"},\r\n    //\r\n    // Embedded Function Terminal Types\r\n    //\r\n    {0x0700, \"Embedded Undefined\",             \"\"},\r\n    {0x0701, \"Level Calibration Noise Source\", \"\"},\r\n    {0x0702, \"Equalization Noise\",             \"\"},\r\n    {0x0703, \"CD player\",                      \"\"},\r\n    {0x0704, \"DAT\",                            \"\"},\r\n    {0x0705, \"DCC\",                            \"\"},\r\n    {0x0706, \"MiniDisk\",                       \"\"},\r\n    {0x0707, \"Analog Tape\",                    \"\"},\r\n    {0x0708, \"Phonograph\",                     \"\"},\r\n    {0x0709, \"VCR Audio\",                      \"\"},\r\n    {0x070A, \"Video Disc Audio\",               \"\"},\r\n    {0x070B, \"DVD Audio\",                      \"\"},\r\n    {0x070C, \"TV Tuner Audio\",                 \"\"},\r\n    {0x070D, \"Satellite Receiver Audio\",       \"\"},\r\n    {0x070E, \"Cable Tuner Audio\",              \"\"},\r\n    {0x070F, \"DSS Audio\",                      \"\"},\r\n    {0x0710, \"Radio Receiver\",                 \"\"},\r\n    {0x0711, \"Radio Transmitter\",              \"\"},\r\n    {0x0712, \"Multi-track Recorder\",           \"\"},\r\n    {0x0713, \"Synthesizer\",                    \"\"},\r\n};\r\nSTRINGLIST slAudioFormatTypes [] =\r\n{\r\n    //\r\n    // A.1.1 Audio Data Format Type I Codes\r\n    //\r\n    {0x0000, \"TYPE_I_UNDEFINED\", \"\"},\r\n    {0x0001, \"PCM\",              \"\"},\r\n    {0x0002, \"PCM8\",             \"\"},\r\n    {0x0003, \"IEEE_FLOAT\",       \"\"},\r\n    {0x0004, \"ALAW\",             \"\"},\r\n    {0x0005, \"MULAW\",            \"\"},\r\n    //\r\n    // A.1.2 Audio Data Format Type II Codes\r\n    //\r\n    {0x1000, \"TYPE_II_UNDEFINED\", \"\"},\r\n    {0x1001, \"MPEG\",              \"\"},\r\n    {0x1002, \"AC-3\",              \"\"},\r\n    //\r\n    // A.1.3 Audio Data Format Type III Codes\r\n    //\r\n    {0x2000, \"TYPE_III_UNDEFINED\",                              \"\"},\r\n    {0x2001, \"IEC1937_AC-3\",                                    \"\"},\r\n    {0x2002, \"IEC1937_MPEG-1_Layer1\",                           \"\"},\r\n    {0x2003, \"IEC1937_MPEG-1_Layer2/3 or IEC1937_MPEG-2_NOEXT\", \"\"},\r\n    {0x2004, \"IEC1937_MPEG-2_EXT\",                              \"\"},\r\n    {0x2005, \"IEC1937_MPEG-2_Layer1_LS\",                        \"\"},\r\n    {0x2006, \"IEC1937_MPEG-2_Layer2/3_LS\",                      \"\"},\r\n};\r\n\r\n\r\n\r\n/*****************************************************************************\r\n L O C A L    F U N C T I O N    P R O T O T Y P E S\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACHeader (\r\n    PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc\r\n);\r\n\r\nBOOL\r\nDisplayACInputTerminal (\r\n    PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc\r\n);\r\n\r\nBOOL\r\nDisplayACOutputTerminal (\r\n    PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc\r\n);\r\n\r\nBOOL\r\nDisplayACMixerUnit (\r\n    PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc\r\n);\r\n\r\nBOOL\r\nDisplayACSelectorUnit (\r\n    PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc\r\n);\r\n\r\nBOOL\r\nDisplayACFeatureUnit (\r\n    PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc\r\n);\r\n\r\nBOOL\r\nDisplayACProcessingUnit (\r\n    PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc\r\n);\r\n\r\nBOOL\r\nDisplayACExtensionUnit (\r\n    PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc\r\n);\r\n\r\nBOOL\r\nDisplayASGeneral (\r\n    PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc\r\n);\r\n\r\nBOOL\r\nDisplayCSEndpoint (\r\n    PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc\r\n);\r\n\r\nBOOL\r\nDisplayASFormatType (\r\n    PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc\r\n);\r\n\r\nBOOL\r\nDisplayASFormatSpecific (\r\n    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc\r\n);\r\n\r\nVOID\r\nDisplayBytes (\r\n    PUCHAR Data,\r\n    USHORT Len\r\n);\r\n\r\n/*****************************************************************************\r\n L O C A L    F U N C T I O N S\r\n*****************************************************************************/\r\n\r\n/*****************************************************************************\r\n\r\n DisplayAudioDescriptor()\r\n\r\n CommonDesc - An Audio Class Descriptor\r\n\r\n bInterfaceSubClass - The SubClass of the Interface containing the descriptor\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayAudioDescriptor (\r\n    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc,\r\n    UCHAR                        bInterfaceSubClass\r\n)\r\n{\r\n    switch (CommonDesc->bDescriptorType)\r\n    {\r\n        case USB_AUDIO_CS_INTERFACE:\r\n            switch (bInterfaceSubClass)\r\n            {\r\n                case USB_AUDIO_SUBCLASS_AUDIOCONTROL:\r\n                    switch (CommonDesc->bDescriptorSubtype)\r\n                    {\r\n                        case USB_AUDIO_AC_HEADER:\r\n                            return DisplayACHeader((PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_INPUT_TERMINAL:\r\n                            return DisplayACInputTerminal((PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_OUTPUT_TERMINAL:\r\n                            return DisplayACOutputTerminal((PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_MIXER_UNIT:\r\n                            return DisplayACMixerUnit((PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_SELECTOR_UNIT:\r\n                            return DisplayACSelectorUnit((PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_FEATURE_UNIT:\r\n                            return DisplayACFeatureUnit((PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_PROCESSING_UNIT:\r\n                            return DisplayACProcessingUnit((PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AC_EXTENSION_UNIT:\r\n                            return DisplayACExtensionUnit((PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR)CommonDesc);\r\n\r\n                        default:\r\n                            break;\r\n                    }\r\n                    break;\r\n\r\n                case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:\r\n                    switch (CommonDesc->bDescriptorSubtype)\r\n                    {\r\n                        case USB_AUDIO_AS_GENERAL:\r\n                            return DisplayASGeneral((PUSB_AUDIO_GENERAL_DESCRIPTOR)CommonDesc);\r\n\r\n                        case USB_AUDIO_AS_FORMAT_TYPE:\r\n                            return DisplayASFormatType((PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR)CommonDesc);\r\n                            break;\r\n\r\n                        case USB_AUDIO_AS_FORMAT_SPECIFIC:\r\n                            return DisplayASFormatSpecific(CommonDesc);\r\n\r\n                        default:\r\n                            break;\r\n                    }\r\n                    break;\r\n\r\n                default:\r\n                    break;\r\n            }\r\n            break;\r\n\r\n        case USB_AUDIO_CS_ENDPOINT:\r\n            return DisplayCSEndpoint((PUSB_AUDIO_ENDPOINT_DESCRIPTOR)CommonDesc);\r\n\r\n        default:\r\n            break;\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACHeader()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACHeader (\r\n    PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc\r\n)\r\n{\r\n    UINT i = 0;\r\n\r\n    if (HeaderDesc->bLength < sizeof(USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Interface Header Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     HeaderDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     HeaderDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     HeaderDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bcdADC:                          0x%04X\\r\\n\",\r\n                     HeaderDesc->bcdADC);\r\n\r\n    AppendTextBuffer(\"wTotalLength:                    0x%04X\\r\\n\",\r\n                     HeaderDesc->wTotalLength);\r\n\r\n    AppendTextBuffer(\"bInCollection:                     0x%02X\\r\\n\",\r\n                     HeaderDesc->bInCollection);\r\n\r\n    for (i=0; i<HeaderDesc->bInCollection; i++)\r\n    {\r\n        AppendTextBuffer(\"baInterfaceNr[%d]:                  0x%02X\\r\\n\",\r\n                         i+1,\r\n                         HeaderDesc->baInterfaceNr[i]);\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACInputTerminal()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACInputTerminal (\r\n    PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc\r\n)\r\n{\r\n    PCHAR pStr = NULL;\r\n\r\n    if (ITDesc->bLength != sizeof(USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Input Terminal Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     ITDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     ITDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     ITDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bTerminalID:                       0x%02X\\r\\n\",\r\n                     ITDesc->bTerminalID);\r\n\r\n    AppendTextBuffer(\"wTerminalType:                   0x%04X\",\r\n                     ITDesc->wTerminalType);\r\n    pStr = GetStringFromList(slAudioTerminalTypes,\r\n            sizeof(slAudioTerminalTypes) / sizeof(STRINGLIST),\r\n            ITDesc->wTerminalType,\r\n            \"Invalid AC Input Terminal Type\");\r\n    AppendTextBuffer(\" (%s)\\r\\n\", pStr);\r\n\r\n    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\",\r\n                     ITDesc->bAssocTerminal);\r\n\r\n    AppendTextBuffer(\"bNrChannels:                       0x%02X\\r\\n\",\r\n                     ITDesc->bNrChannels);\r\n\r\n    AppendTextBuffer(\"wChannelConfig:                  0x%04X\\r\\n\",\r\n                     ITDesc->wChannelConfig);\r\n\r\n    AppendTextBuffer(\"iChannelNames:                     0x%02X\\r\\n\",\r\n                     ITDesc->iChannelNames);\r\n\r\n    AppendTextBuffer(\"iTerminal:                         0x%02X\\r\\n\",\r\n                     ITDesc->iTerminal);\r\n\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACOutputTerminal()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACOutputTerminal (\r\n    PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc\r\n)\r\n{\r\n    PCHAR pStr = NULL;\r\n\r\n    if (OTDesc->bLength != sizeof(USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Output Terminal Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     OTDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     OTDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     OTDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bTerminalID:                       0x%02X\\r\\n\",\r\n                     OTDesc->bTerminalID);\r\n\r\n    AppendTextBuffer(\"wTerminalType:                   0x%04X\",\r\n                     OTDesc->wTerminalType);\r\n\r\n    pStr = GetStringFromList(slAudioTerminalTypes,\r\n            sizeof(slAudioTerminalTypes) / sizeof(STRINGLIST),\r\n            OTDesc->wTerminalType,\r\n            \"Invalid AC Output Terminal Type\");\r\n    AppendTextBuffer(\" (%s)\\r\\n\", pStr);\r\n\r\n    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\",\r\n                     OTDesc->bAssocTerminal);\r\n\r\n    AppendTextBuffer(\"bSourceID:                         0x%02X\\r\\n\",\r\n                     OTDesc->bSourceID);\r\n\r\n    AppendTextBuffer(\"iTerminal:                         0x%02X\\r\\n\",\r\n                     OTDesc->iTerminal);\r\n\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACMixerUnit()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACMixerUnit (\r\n    PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    if (MixerDesc->bLength < 10)\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Mixer Unit Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     MixerDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     MixerDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     MixerDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\",\r\n                     MixerDesc->bUnitID);\r\n\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\",\r\n                     MixerDesc->bNrInPins);\r\n\r\n    for (i=0; i<MixerDesc->bNrInPins; i++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n                        i+1,\r\n                        MixerDesc->baSourceID[i]);\r\n    }\r\n\r\n    data = &MixerDesc->baSourceID[MixerDesc->bNrInPins];\r\n\r\n    AppendTextBuffer(\"bNrChannels:                       0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    AppendTextBuffer(\"wChannelConfig:                  0x%04X\\r\\n\",\r\n                     *(PUSHORT)data);\r\n\r\n    data = (PUCHAR) ((PUSHORT) data + 1);\r\n\r\n    AppendTextBuffer(\"iChannelNames:                     0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    AppendTextBuffer(\"bmControls:\\r\\n\");\r\n\r\n    i = MixerDesc->bLength - 10 - MixerDesc->bNrInPins;\r\n\r\n    DisplayBytes(data, i);\r\n\r\n    data += i;\r\n\r\n    AppendTextBuffer(\"iMixer:                            0x%02X\\r\\n\",\r\n                     *data);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACSelectorUnit()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACSelectorUnit (\r\n    PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    if (SelectorDesc->bLength < 6)\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Selector Unit Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     SelectorDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     SelectorDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     SelectorDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\",\r\n                     SelectorDesc->bUnitID);\r\n\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\",\r\n                     SelectorDesc->bNrInPins);\r\n\r\n    for (i=0; i<SelectorDesc->bNrInPins; i++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n                        i+1,\r\n                        SelectorDesc->baSourceID[i]);\r\n    }\r\n\r\n    data = &SelectorDesc->baSourceID[SelectorDesc->bNrInPins];\r\n\r\n    AppendTextBuffer(\"iSelector:                         0x%02X\\r\\n\",\r\n                     *data);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACFeatureUnit()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACFeatureUnit (\r\n    PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    UCHAR  n = 0;\r\n    UCHAR  ch = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Feature Unit Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     FeatureDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     FeatureDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     FeatureDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\",\r\n                     FeatureDesc->bUnitID);\r\n\r\n    AppendTextBuffer(\"bSourceID:                         0x%02X\\r\\n\",\r\n                     FeatureDesc->bSourceID);\r\n\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\",\r\n                     FeatureDesc->bControlSize);\r\n\r\n\r\n    if (FeatureDesc->bLength < 7)\r\n    {\r\n        AppendTextBuffer(\"*!*WARNING:    bLength is invalid (< 7)\\r\\n\");\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n    else if(FeatureDesc->bLength == 7)\r\n    {\r\n        AppendTextBuffer(\"Audio controls are not available (bLength = 7)\\r\\n\");\r\n        return TRUE;\r\n    }\r\n\r\n    n = FeatureDesc->bControlSize;\r\n\r\n    if(n == 0)\r\n    {\r\n        AppendTextBuffer(\"Audio controls are not available (bControlSize = 0)\\r\\n\");\r\n        return TRUE;\r\n    }\r\n\r\n    ch = ((FeatureDesc->bLength - 7) / n) - 1;\r\n\r\n    // Check if there are extra bytes in descriptor based on formula in Spec\r\n    if (FeatureDesc->bLength != (7 + (ch + 1) * n))\r\n    {\r\n        // The descriptor length is greater than number of bmaControls\r\n        AppendTextBuffer(\"*!*WARNING:    bLength is greater than number of bmaControls (bLength > ( 7 + (ch + 1) * n)\\r\\n\");\r\n    }\r\n\r\n    data = &FeatureDesc->bmaControls[0];\r\n\r\n    if (ch == (UCHAR) -1)\r\n    {\r\n        // This should not happen, but this check is put in place so we don't loop for a long time below\r\n        AppendTextBuffer(\"*!*WARNING:    Either bLength or bControlSize are invalid. The calculated logical channel count is -1. ((bLength - 7)/ n) - 1\\r\\n\");\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    for (i=0; i<=ch; i++)\r\n    {\r\n        AppendTextBuffer(\"bmaControls[%d]:                    \", i);\r\n        DisplayBytes(data, n);\r\n\r\n        data += n;\r\n    }\r\n\r\n\r\n    AppendTextBuffer(\"iFeature:                          0x%02X\\r\\n\",\r\n                     *data);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACProcessingUnit()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACProcessingUnit (\r\n    PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    if (ProcessingDesc->bLength < sizeof(USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Processing Unit Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                          0x%02X\\r\\n\",\r\n                     ProcessingDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     ProcessingDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     ProcessingDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\",\r\n                     ProcessingDesc->bUnitID);\r\n\r\n    AppendTextBuffer(\"wProcessType:                    0x%04X\",\r\n                     ProcessingDesc->wProcessType);\r\n\r\n    switch (ProcessingDesc->wProcessType)\r\n    {\r\n        case USB_AUDIO_PROCESS_UNDEFINED:\r\n            AppendTextBuffer(\"(Undefined Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_UPDOWNMIX:\r\n            AppendTextBuffer(\"(Up / Down Mix Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_DOLBYPROLOGIC:\r\n            AppendTextBuffer(\"(Dolby Prologic Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_3DSTEREOEXTENDER:\r\n            AppendTextBuffer(\"(3D-Stereo Extender Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_REVERBERATION:\r\n            AppendTextBuffer(\"(Reverberation Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_CHORUS:\r\n            AppendTextBuffer(\"(Chorus Process)\\r\\n\");\r\n            break;\r\n\r\n        case USB_AUDIO_PROCESS_DYNRANGECOMP:\r\n            AppendTextBuffer(\"(Dynamic Range Compressor Process)\\r\\n\");\r\n            break;\r\n\r\n        default:\r\n            AppendTextBuffer(\"\\r\\n\");\r\n            break;\r\n    }\r\n\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\",\r\n                     ProcessingDesc->bNrInPins);\r\n\r\n    for (i=0; i<ProcessingDesc->bNrInPins; i++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n                        i+1,\r\n                        ProcessingDesc->baSourceID[i]);\r\n    }\r\n\r\n    data = &ProcessingDesc->baSourceID[ProcessingDesc->bNrInPins];\r\n\r\n    AppendTextBuffer(\"bNrChannels:                       0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    AppendTextBuffer(\"wChannelConfig:                  0x%04X\\r\\n\",\r\n                     *(PUSHORT)data);\r\n\r\n    data = (PUCHAR) ((PUSHORT) data + 1);\r\n\r\n    AppendTextBuffer(\"iChannelNames:                     0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    i = *data++;\r\n\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\",\r\n                     i);\r\n\r\n    AppendTextBuffer(\"bmControls:\\r\\n\");\r\n\r\n    DisplayBytes(data, i);\r\n\r\n    data += i;\r\n\r\n    AppendTextBuffer(\"iProcessing:                       0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n\r\n    i = ProcessingDesc->bLength - 13 - ProcessingDesc->bNrInPins - i;\r\n\r\n    if (i)\r\n    {\r\n        AppendTextBuffer(\"Process Specific:\\r\\n\");\r\n\r\n        DisplayBytes(data, i);\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayACExtensionUnit()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayACExtensionUnit (\r\n    PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    if (ExtensionDesc->bLength < 13)\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Control Extension Unit Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     ExtensionDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     ExtensionDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     ExtensionDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\",\r\n                     ExtensionDesc->bUnitID);\r\n\r\n    AppendTextBuffer(\"wExtensionCode:                  0x%04X\\r\\n\",\r\n                     ExtensionDesc->wExtensionCode);\r\n\r\n\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\",\r\n                     ExtensionDesc->bNrInPins);\r\n\r\n    for (i=0; i<ExtensionDesc->bNrInPins; i++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n                        i+1,\r\n                        ExtensionDesc->baSourceID[i]);\r\n    }\r\n\r\n    data = &ExtensionDesc->baSourceID[ExtensionDesc->bNrInPins];\r\n\r\n    AppendTextBuffer(\"bNrChannels:                       0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    AppendTextBuffer(\"wChannelConfig:                  0x%04X\\r\\n\",\r\n                     *(PUSHORT)data);\r\n\r\n    data = (PUCHAR) ((PUSHORT) data + 1);\r\n\r\n    AppendTextBuffer(\"iChannelNames:                     0x%02X\\r\\n\",\r\n                     *data++);\r\n\r\n    i = *data++;\r\n\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\",\r\n                     i);\r\n\r\n    AppendTextBuffer(\"bmControls:\\r\\n\");\r\n\r\n    DisplayBytes(data, i);\r\n\r\n    data += i;\r\n\r\n    AppendTextBuffer(\"iExtension:                        0x%02X\\r\\n\",\r\n                     *data);\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayASGeneral()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayASGeneral (\r\n    PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc\r\n)\r\n{\r\n    PCHAR pStr = NULL;\r\n\r\n    if (GeneralDesc->bLength != sizeof(USB_AUDIO_GENERAL_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Streaming Class Specific Interface Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     GeneralDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     GeneralDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     GeneralDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bTerminalLink:                     0x%02X\\r\\n\",\r\n                     GeneralDesc->bTerminalLink);\r\n\r\n    AppendTextBuffer(\"bDelay:                            0x%02X\\r\\n\",\r\n                     GeneralDesc->bDelay);\r\n\r\n    AppendTextBuffer(\"wFormatTag:                      0x%04X\",\r\n                     GeneralDesc->wFormatTag);\r\n\r\n    pStr = GetStringFromList(slAudioFormatTypes,\r\n            sizeof(slAudioFormatTypes) / sizeof(STRINGLIST),\r\n            GeneralDesc->wFormatTag,\r\n            \"Invalid AC Format Type\");\r\n    AppendTextBuffer(\" (%s)\\r\\n\", pStr);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayCSEndpoint()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayCSEndpoint (\r\n    PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc\r\n)\r\n{\r\n    if (EndpointDesc->bLength != sizeof(USB_AUDIO_ENDPOINT_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Streaming Class Specific Audio Data Endpoint Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     EndpointDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     EndpointDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     EndpointDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\\r\\n\",\r\n                     EndpointDesc->bmAttributes);\r\n\r\n    AppendTextBuffer(\"bLockDelayUnits:                   0x%02X\\r\\n\",\r\n                     EndpointDesc->bLockDelayUnits);\r\n\r\n    AppendTextBuffer(\"wLockDelay:                      0x%04X\\r\\n\",\r\n                     EndpointDesc->wLockDelay);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayASFormatType()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayASFormatType (\r\n    PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc\r\n)\r\n{\r\n    UCHAR  i = 0;\r\n    UCHAR  n = 0;\r\n    ULONG  freq = 0;\r\n    PUCHAR data = NULL;\r\n\r\n    if (FormatDesc->bLength < sizeof(USB_AUDIO_COMMON_FORMAT_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Streaming Format Type Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     FormatDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     FormatDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     FormatDesc->bDescriptorSubtype);\r\n\r\n    AppendTextBuffer(\"bFormatType:                       0x%02X\\r\\n\",\r\n                     FormatDesc->bFormatType);\r\n\r\n\r\n    if (FormatDesc->bFormatType == 0x01 ||\r\n        FormatDesc->bFormatType == 0x03)\r\n    {\r\n        PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR FormatI_IIIDesc;\r\n\r\n        FormatI_IIIDesc = (PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR)FormatDesc;\r\n\r\n        AppendTextBuffer(\"bNrChannels:                       0x%02X\\r\\n\",\r\n                         FormatI_IIIDesc->bNrChannels);\r\n\r\n        AppendTextBuffer(\"bSubframeSize:                     0x%02X\\r\\n\",\r\n                         FormatI_IIIDesc->bSubframeSize);\r\n\r\n        AppendTextBuffer(\"bBitResolution:                    0x%02X\\r\\n\",\r\n                         FormatI_IIIDesc->bBitResolution);\r\n\r\n        AppendTextBuffer(\"bSamFreqType:                      0x%02X\\r\\n\",\r\n                         FormatI_IIIDesc->bSamFreqType);\r\n\r\n        data = (PUCHAR)(FormatI_IIIDesc + 1);\r\n\r\n        n = FormatI_IIIDesc->bSamFreqType;\r\n\r\n    }\r\n    else if (FormatDesc->bFormatType == 0x02)\r\n    {\r\n        PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR FormatIIDesc;\r\n\r\n        FormatIIDesc = (PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR)FormatDesc;\r\n\r\n        AppendTextBuffer(\"wMaxBitRate:                     0x%04X\\r\\n\",\r\n                         FormatIIDesc->wMaxBitRate);\r\n\r\n        AppendTextBuffer(\"wSamplesPerFrame:                0x%04X\\r\\n\",\r\n                         FormatIIDesc->wSamplesPerFrame);\r\n\r\n        AppendTextBuffer(\"bSamFreqType:                      0x%02X\\r\\n\",\r\n                         FormatIIDesc->bSamFreqType);\r\n\r\n        data = (PUCHAR)(FormatIIDesc + 1);\r\n\r\n        n = FormatIIDesc->bSamFreqType;\r\n    }\r\n    else\r\n    {\r\n        data = NULL;\r\n    }\r\n\r\n    if (data != NULL)\r\n    {\r\n        if (n == 0)\r\n        {\r\n            freq = (data[0]) + (data[1] << 8) + (data[2] << 16);\r\n            data += 3;\r\n\r\n            AppendTextBuffer(\"tLowerSamFreq:                 0x%06X (%d Hz)\\r\\n\",\r\n                             freq,\r\n                             freq);\r\n\r\n            freq = (data[0]) + (data[1] << 8) + (data[2] << 16);\r\n            data += 3;\r\n\r\n            AppendTextBuffer(\"tUpperSamFreq:                 0x%06X (%d Hz)\\r\\n\",\r\n                             freq,\r\n                             freq);\r\n        }\r\n        else\r\n        {\r\n            for (i=0; i<n; i++)\r\n            {\r\n                freq = (data[0]) + (data[1] << 8) + (data[2] << 16);\r\n                data += 3;\r\n\r\n                AppendTextBuffer(\"tSamFreq[%d]:                   0x%06X (%d Hz)\\r\\n\",\r\n                                 i+1,\r\n                                 freq,\r\n                                 freq);\r\n            }\r\n        }\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n DisplayASFormatSpecific()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nDisplayASFormatSpecific (\r\n    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc\r\n)\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>Audio Streaming Format Specific Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                     CommonDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                     CommonDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\",\r\n                     CommonDesc->bDescriptorSubtype);\r\n\r\n    DisplayBytes((PUCHAR)(CommonDesc + 1),\r\n                 CommonDesc->bLength);\r\n\r\n    return TRUE;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n DisplayBytes()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayBytes (\r\n    PUCHAR Data,\r\n    USHORT Len\r\n)\r\n{\r\n    USHORT i;\r\n\r\n    for (i = 0; i < Len; i++)\r\n    {\r\n        AppendTextBuffer(\"%02X \", Data[i]);\r\n\r\n        if (i % 16 == 15)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    }\r\n\r\n    if (i % 16 != 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/display.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2011 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\nDISPLAY.C\r\n\r\nAbstract:\r\n\r\nThis source file contains the routines which update the edit control\r\nto display information about the selected USB device.\r\n\r\nEnvironment:\r\n\r\nuser mode\r\n\r\nRevision History:\r\n\r\n04-25-97 : created\r\n03-28-03 : extensive changes to support new USBVCD\r\n03-28-08 : extensive changes to support new USB Video Class 1.1\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\nI N C L U D E S\r\n*****************************************************************************/\r\n\r\n#include \"uvcview.h\"\r\n#include \"h264.h\"\r\n#include <usb200.h>\r\n\r\n#include \"vndrlist.h\"\r\n#include \"langidlist.h\"\r\n\r\n/*****************************************************************************\r\nD E F I N E S\r\n*****************************************************************************/\r\n\r\n#define BUFFERALLOCINCREMENT        0x10000\r\n#define BUFFERMINFREESPACE          0x1000\r\n\r\n/*****************************************************************************\r\nT Y P E D E F S\r\n*****************************************************************************/\r\n\r\n//\r\n// Hardcoded information about specific EHCI controllers\r\n//\r\ntypedef struct _EHCI_CONTROLLER_DATA\r\n{\r\n    USHORT  VendorID;\r\n    USHORT  DeviceID;\r\n    UCHAR   DebugPortNumber;\r\n} EHCI_CONTROLLER_DATA, *PEHCI_CONTROLLER_DATA;\r\n\r\n\r\n/*****************************************************************************\r\nG L O B A L S    P R I V A T E    T O    T H I S    F I L E\r\n*****************************************************************************/\r\n\r\n// Workspace for text info which is used to update the edit control\r\n//\r\nCHAR  *TextBuffer = NULL;\r\nUINT   TextBufferLen = 0;\r\nUINT   TextBufferPos = 0;\r\n\r\nSTRINGLIST slPowerState [] =\r\n{\r\n    {WdmUsbPowerNotMapped,          \"S? (unmapped)   \", \"\"},\r\n\r\n    {WdmUsbPowerSystemUnspecified,  \"S? (unspecified)\", \"\"},\r\n    {WdmUsbPowerSystemWorking,      \"S0 (working)    \", \"\"},\r\n    {WdmUsbPowerSystemSleeping1,    \"S1 (sleep)      \", \"\"},\r\n    {WdmUsbPowerSystemSleeping2,    \"S2 (sleep)      \", \"\"},\r\n    {WdmUsbPowerSystemSleeping3,    \"S3 (sleep)      \", \"\"},\r\n    {WdmUsbPowerSystemHibernate,    \"S4 (Hibernate)  \", \"\"},\r\n    {WdmUsbPowerSystemShutdown,     \"S5 (shutdown)   \", \"\"},\r\n\r\n    {WdmUsbPowerDeviceUnspecified,  \"D? (unspecified)\", \"\"},\r\n    {WdmUsbPowerDeviceD0,           \"D0              \", \"\"},\r\n    {WdmUsbPowerDeviceD1,           \"D1              \", \"\"},\r\n    {WdmUsbPowerDeviceD2,           \"D2              \", \"\"},\r\n    {WdmUsbPowerDeviceD3,           \"D3              \", \"\"},\r\n};\r\n\r\nSTRINGLIST slControllerFlavor[] =\r\n{\r\n    { USB_HcGeneric, \"USB_HcGeneric\", \"\" },\r\n    { OHCI_Generic, \"OHCI_Generic\", \"\" },\r\n    { OHCI_Hydra, \"OHCI_Hydra\", \"\" },\r\n    { OHCI_NEC, \"OHCI_NEC\", \"\" },\r\n    { UHCI_Generic, \"UHCI_Generic\", \"\" },\r\n    { UHCI_Piix4, \"UHCI_Piix4\", \"\" },\r\n    { UHCI_Piix3, \"UHCI_Piix3\", \"\" },\r\n    { UHCI_Ich2, \"UHCI_Ich2\", \"\" },\r\n    { UHCI_Reserved204, \"UHCI_Reserved204\", \"\" },\r\n    { UHCI_Ich1, \"UHCI_Ich1\", \"\" },\r\n    { UHCI_Ich3m, \"UHCI_Ich3m\", \"\" },\r\n    { UHCI_Ich4, \"UHCI_Ich4\", \"\" },\r\n    { UHCI_Ich5, \"UHCI_Ich5\", \"\" },\r\n    { UHCI_Ich6, \"UHCI_Ich6\", \"\" },\r\n    { UHCI_Intel, \"UHCI_Intel\", \"\" },\r\n    { UHCI_VIA, \"UHCI_VIA\", \"\" },\r\n    { UHCI_VIA_x01, \"UHCI_VIA_x01\", \"\" },\r\n    { UHCI_VIA_x02, \"UHCI_VIA_x02\", \"\" },\r\n    { UHCI_VIA_x03, \"UHCI_VIA_x03\", \"\" },\r\n    { UHCI_VIA_x04, \"UHCI_VIA_x04\", \"\" },\r\n    { UHCI_VIA_x0E_FIFO, \"UHCI_VIA_x0E_FIFO\", \"\" },\r\n    { EHCI_Generic, \"EHCI_Generic\", \"\" },\r\n    { EHCI_NEC, \"EHCI_NEC\", \"\" },\r\n    { EHCI_Lucent, \"EHCI_Lucent\", \"\" },\r\n    { EHCI_NVIDIA_Tegra2, \"EHCI_NVIDIA_Tegra2\", \"\" },\r\n    { EHCI_NVIDIA_Tegra3, \"EHCI_NVIDIA_Tegra3\", \"\" },\r\n    { EHCI_Intel_Medfield, \"EHCI_Intel_Medfield\", \"\" }\r\n};\r\n\r\n//\r\n// For supporting pre Win8 versions of Windows, a hardcoded list is maintained for determining\r\n// debug port numbers.  As usbport.inf is augmented with new host controllers, this list should\r\n// be updated.\r\n//\r\n// The following entries do not have a debug port:\r\n// PCI\\VEN_8086&DEV_0806 - \"Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller MPH  - 0806\"\r\n// PCI\\VEN_8086&DEV_0811 - \"Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller SPM  - 0811\"\r\n//\r\n\r\nEHCI_CONTROLLER_DATA EhciControllerData[] =\r\n{\r\n    {0x8086, 0x24CD, 1}, // ICH4 - Intel(R) 82801DB/DBM USB 2.0 Enhanced Host Controller - 24CD\r\n    {0x8086, 0x24DD, 1}, // ICH5 - Intel(R) 82801EB USB2 Enhanced Host Controller - 24DD\r\n    {0x8086, 0x25AD, 1}, // ICH5 - Intel(R) 6300ESB USB2 Enhanced Host Controller - 25AD\r\n    {0x8086, 0x265C, 1}, // ICH6 - Intel(R) 82801FB/FBM USB2 Enhanced Host Controller - 265C\r\n    {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C\r\n    {0x8086, 0x27CC, 1}, // ICH7 - Intel(R) 82801G (ICH7 Family) USB2 Enhanced Host Controller - 27CC\r\n    {0x8086, 0x2836, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 2836\r\n    {0x8086, 0x283A, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 283A\r\n    {0x8086, 0x293A, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293A\r\n    {0x8086, 0x293C, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293C\r\n    {0x8086, 0x3A3A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3A\r\n    {0x8086, 0x3A3C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3C\r\n    {0x8086, 0x3A6A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6A\r\n    {0x8086, 0x3A6C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6C\r\n    {0x8086, 0x3B34, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Enhanced Host Controller - 3B34\r\n    {0x8086, 0x3B36, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Universal Host Controller - 3B36\r\n    {0x8086, 0x1C26, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C26\r\n    {0x8086, 0x1C2D, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C2D\r\n    {0x8086, 0x1D26, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #1 - 1D26\r\n    {0x8086, 0x1D2D, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #2 - 1D2D\r\n    {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C\r\n    {0x10DE, 0x00D8, 1},\r\n    {0,0,0},\r\n};\r\n\r\n\r\n/*****************************************************************************\r\nL O C A L    F U N C T I O N    P R O T O T Y P E S\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayPortConnectorProperties (\r\n    _In_     PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2\r\n    );\r\n\r\nvoid\r\nDisplayDevicePowerState (\r\n    _In_     PDEVICE_INFO_NODE DeviceInfoNode\r\n    );\r\n\r\nVOID\r\nDisplayHubInfo (\r\n    PUSB_HUB_INFORMATION HubInfo,\r\n    BOOL DisplayDescriptor\r\n    );\r\n\r\nVOID\r\nDisplayHubInfoEx (\r\n    PUSB_HUB_INFORMATION_EX    HubInfoEx\r\n    );\r\n\r\nVOID\r\nDisplayHubCapabilityEx (\r\n    PUSB_HUB_CAPABILITIES_EX HubCapabilityEx\r\n    );\r\n\r\nVOID\r\nDisplayPowerState(\r\n    PUSB_POWER_INFO pUPI\r\n    );\r\n\r\nVOID\r\nDisplayConnectionInfo (\r\n    _In_     PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectInfo,\r\n    _In_     PUSBDEVICEINFO                         info,\r\n    _In_     PSTRING_DESCRIPTOR_NODE                StringDescs,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2\r\n    );\r\n\r\nVOID\r\nDisplayPipeInfo (\r\n     ULONG           NumPipes,\r\n     USB_PIPE_INFO  *PipeInfo\r\n     );\r\n\r\nVOID\r\nDisplayConfigDesc (\r\n    PUSBDEVICEINFO                  info,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,\r\n    PSTRING_DESCRIPTOR_NODE         StringDescs\r\n    );\r\n\r\nVOID\r\nDisplayBosDescriptor (\r\n    PUSBDEVICEINFO            info,\r\n    PUSB_BOS_DESCRIPTOR       BosDesc,\r\n    PSTRING_DESCRIPTOR_NODE   StringDescs\r\n    );\r\n\r\nVOID\r\nDisplayBillboardCapabilityDescriptor (\r\n    PUSBDEVICEINFO info,\r\n    PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs\r\n);\r\n\r\nVOID\r\nDisplayDeviceQualifierDescriptor (\r\n    PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc\r\n    );\r\n\r\nVOID\r\nDisplayConfigurationDescriptor (\r\n    PUSBDEVICEINFO                  info,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,\r\n    PSTRING_DESCRIPTOR_NODE         StringDescs\r\n    );\r\n\r\nVOID\r\nDisplayInterfaceDescriptor (\r\n    PUSB_INTERFACE_DESCRIPTOR   InterfaceDesc,\r\n    PSTRING_DESCRIPTOR_NODE     StringDescs,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    );\r\n\r\nVOID\r\nDisplayEndpointDescriptor (\r\n    _In_     PUSB_ENDPOINT_DESCRIPTOR\r\n                        EndpointDesc,\r\n    _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR\r\n                        EpCompDesc,\r\n    _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR\r\n                        SspIsochCompDesc,\r\n    _In_     UCHAR      InterfaceClass,\r\n    _In_     BOOLEAN    EpCompDescAvail\r\n    );\r\n\r\nVOID\r\nDisplaySuperSpeedPlusIsochEndpointCompanionDescriptor(\r\n     _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc\r\n     );\r\n\r\nVOID\r\nDisplayEndointCompanionDescriptor (\r\n    _In_     PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc,\r\n    _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR\r\n                                                           SspIsochEpCompDesc,\r\n    _In_     UCHAR                                         DescType\r\n    );\r\n\r\n\r\nVOID\r\nDisplayHidDescriptor (\r\n    PUSB_HID_DESCRIPTOR         HidDesc\r\n    );\r\n\r\nVOID\r\nDisplayOTGDescriptor (\r\n    PUSB_OTG_DESCRIPTOR         OTGDesc\r\n    );\r\n\r\nvoid\r\nInitializePerDeviceSettings (\r\n    PUSBDEVICEINFO info\r\n    );\r\n\r\nUINT\r\nIsUVCDevice (\r\n    PUSBDEVICEINFO info\r\n    );\r\n\r\nVOID\r\nDisplayIADDescriptor (\r\n    PUSB_IAD_DESCRIPTOR         IADDesc,\r\n    PSTRING_DESCRIPTOR_NODE     StringDescs,\r\n    int                         nInterfaces,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    );\r\n\r\nVOID\r\nDisplayUSEnglishStringDescriptor (\r\n    UCHAR                       Index,\r\n    PSTRING_DESCRIPTOR_NODE     USStringDescs,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    );\r\n\r\nVOID\r\nDisplayUnknownDescriptor (\r\n    PUSB_COMMON_DESCRIPTOR      CommonDesc\r\n    );\r\n\r\nVOID\r\nDisplayRemainingUnknownDescriptor(\r\n    PUCHAR DescriptorData,\r\n    ULONG  Start,\r\n    ULONG  Stop\r\n    );\r\n\r\nPCHAR\r\nGetVendorString (\r\n    USHORT     idVendor\r\n    );\r\n\r\nPCHAR\r\nGetLangIDString (\r\n    USHORT     idLang\r\n    );\r\n\r\nUINT\r\nGetConfigurationSize (\r\n    PUSBDEVICEINFO info\r\n    );\r\n\r\nUINT\r\nGetInterfaceCount (\r\n    PUSBDEVICEINFO info\r\n    );\r\n\r\n\r\n/*****************************************************************************\r\nL O C A L    F U N C T I O N S\r\n*****************************************************************************/\r\n\r\n/*****************************************************************************\r\n\r\nNextDescriptor()\r\n\r\n*****************************************************************************/\r\n//__forceinline\r\nPUSB_COMMON_DESCRIPTOR\r\nNextDescriptor(\r\n    _In_ PUSB_COMMON_DESCRIPTOR Descriptor\r\n    )\r\n{\r\n    if (Descriptor->bLength == 0)\r\n    {\r\n        return NULL;\r\n    }\r\n    return (PUSB_COMMON_DESCRIPTOR)((PUCHAR)Descriptor + Descriptor->bLength);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetNextDescriptor()\r\n\r\n*****************************************************************************/\r\nPUSB_COMMON_DESCRIPTOR\r\nGetNextDescriptor(\r\n    _In_reads_bytes_(TotalLength)\r\n        PUSB_COMMON_DESCRIPTOR FirstDescriptor,\r\n    _In_\r\n        ULONG TotalLength,\r\n    _In_\r\n        PUSB_COMMON_DESCRIPTOR StartDescriptor,\r\n    _In_ long\r\n        DescriptorType\r\n    )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR currentDescriptor = NULL;\r\n    PUSB_COMMON_DESCRIPTOR endDescriptor     = NULL;\r\n\r\n    endDescriptor = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)FirstDescriptor + TotalLength);\r\n\r\n    if (StartDescriptor >= endDescriptor ||\r\n        NextDescriptor(StartDescriptor)>= endDescriptor)\r\n    {\r\n        return NULL;\r\n    }\r\n\r\n    if (DescriptorType == -1) // -1 means any type\r\n    {\r\n        return NextDescriptor(StartDescriptor);\r\n    }\r\n\r\n    currentDescriptor = StartDescriptor;\r\n\r\n    while (((currentDescriptor = NextDescriptor(currentDescriptor)) < endDescriptor)\r\n            && currentDescriptor != NULL)\r\n    {\r\n        if (currentDescriptor->bDescriptorType == (UCHAR)DescriptorType)\r\n        {\r\n            return currentDescriptor;\r\n        }\r\n    }\r\n    return NULL;\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nCreateTextBuffer()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nCreateTextBuffer (\r\n                  )\r\n{\r\n    // Allocate the buffer\r\n    //\r\n    TextBuffer = ALLOC(BUFFERALLOCINCREMENT);\r\n\r\n    if (TextBuffer == NULL)\r\n    {\r\n        OOPS();\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    TextBufferLen = BUFFERALLOCINCREMENT;\r\n\r\n    // Reset the buffer position and terminate the buffer\r\n    //\r\n    memset(TextBuffer, 0, BUFFERALLOCINCREMENT);\r\n    TextBufferPos = 0;\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDestroyTextBuffer()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDestroyTextBuffer (\r\n                   )\r\n{\r\n    if (TextBuffer != NULL)\r\n    {\r\n        FREE(TextBuffer);\r\n\r\n        TextBuffer = NULL;\r\n    }\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nResetTextBuffer()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nResetTextBuffer (\r\n                 )\r\n{\r\n    // Fail if the text buffer has not been allocated\r\n    //\r\n    if (TextBuffer == NULL)\r\n    {\r\n        OOPS();\r\n\r\n        return FALSE;\r\n    }\r\n\r\n    // Reset the buffer position and terminate the buffer\r\n    //\r\n    *TextBuffer = 0;\r\n    TextBufferPos = 0;\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nGetTextBufferPos()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nGetTextBufferPos (\r\n                   )\r\n{\r\n    return TextBufferPos;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nAppendTextBuffer()\r\n\r\n*****************************************************************************/\r\n\r\nVOID __cdecl\r\nAppendTextBuffer (\r\n    LPCTSTR lpFormat,\r\n    ...\r\n    )\r\n{\r\n    va_list arglist;\r\n    HRESULT hr = S_OK;\r\n    int     nPos = TextBufferPos;\r\n    char    LocalTextBuffer[512];\r\n\r\n    va_start(arglist, lpFormat);\r\n\r\n    // Make sure we have a healthy amount of space free in the buffer,\r\n    // reallocating the buffer if necessary.\r\n    //\r\n\r\n    if (TextBufferLen - TextBufferPos < BUFFERMINFREESPACE)\r\n    {\r\n        CHAR *TextBufferTmp;\r\n        UINT uNewTextBufferLen = 0;\r\n        hr = UIntAdd(TextBufferLen, BUFFERALLOCINCREMENT, &uNewTextBufferLen);\r\n\r\n        if (hr != S_OK)\r\n            {\r\n            // we've exceeded DWORD length of (2^32)-1 for buffer\r\n            OOPS();\r\n\r\n            return;\r\n            }\r\n\r\n        TextBufferTmp = REALLOC(TextBuffer, uNewTextBufferLen);\r\n\r\n        if (TextBufferTmp != NULL)\r\n        {\r\n            TextBuffer = TextBufferTmp;\r\n            TextBufferLen += BUFFERALLOCINCREMENT;  // update TextBufferLen to reflect the new, bigger size of the text buffer\r\n        }\r\n        else\r\n        {\r\n            // If GlobalReAlloc fails, the original memory is not freed,\r\n            // and the original handle and pointer are still valid.\r\n            //\r\n\r\n            OOPS();\r\n\r\n            return;\r\n        }\r\n    }\r\n\r\n    // Add the text to the end of the buffer\r\n    //\r\n    hr = StringCchVPrintf(LocalTextBuffer, sizeof(LocalTextBuffer), lpFormat, arglist);\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        size_t cbMax = 512;\r\n        size_t pcb = 0;\r\n\r\n        // Ensure TextBuffer is zero terminated\r\n        // The text buffer size is specified by TextBufferLen.\r\n        // the text buffer size will be bigger than BUFFERALLOCINCREMENT if the buffer has been reallocated more than\r\n        // once (which would happen if it had to be made bigger to hold more text)\r\n        hr = StringCbLength((LPCTSTR) TextBuffer,\r\n            TextBufferLen, // the maximum number of bytes allowed in TextBuffer.\r\n            &pcb);\r\n\r\n        if (FAILED(hr)) // buffer is not null-terminated, go ahead and do that\r\n        {\r\n            TextBuffer[TextBufferLen-1] = 0;\r\n        }\r\n        hr = StringCbLength((LPCTSTR) LocalTextBuffer, cbMax, &pcb);\r\n        if (SUCCEEDED(hr))\r\n        {\r\n            StringCbCatN(TextBuffer, TextBufferLen, LocalTextBuffer, pcb);\r\n\r\n            // Increment the text position by the number of charcters we just added to it.\r\n            TextBufferPos += (UINT) pcb;\r\n        }\r\n\r\n        // If DebugLog flag set, send output to the debugger\r\n        //\r\n        if (gLogDebug)\r\n        {\r\n            OutputDebugString(TextBuffer + nPos); // print the string just added to the text buffer\r\n        }\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//  GetTextBuffer\r\n//\r\n//  Returns the display text buffer\r\n//\r\n//*****************************************************************************\r\nPCHAR GetTextBuffer(void)\r\n{\r\n    return (TextBuffer);\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n//  GetEhciDebugPort\r\n//\r\n//  Returns debug port value if present for EHCI controller. 0 if its not present\r\n//\r\n//*****************************************************************************\r\nULONG GetEhciDebugPort(ULONG vendorId, ULONG deviceId)\r\n{\r\n    int i = 0;\r\n    ULONG debugPort = 0;\r\n\r\n    for (i = 0; EhciControllerData[i].VendorID != 0; i++)\r\n    {\r\n        if (vendorId == EhciControllerData[i].VendorID &&\r\n            deviceId == EhciControllerData[i].DeviceID)\r\n        {\r\n            debugPort = EhciControllerData[i].DebugPortNumber;\r\n            break;\r\n        }\r\n    }\r\n\r\n    return debugPort;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//  UpdateTreeItemDeviceInfo\r\n//\r\n//  hTreeItem - Handle of selected TreeView item for which information should\r\n//  be added to the TextBuffer global\r\n//\r\n//  The functions returns error status if AppendTextBuffer() used in Display*() functions\r\n//  fails. The display text would be missing or truncated in such cases.\r\n//*****************************************************************************\r\nHRESULT\r\nUpdateTreeItemDeviceInfo(\r\n        HWND hTreeWnd,\r\n        HTREEITEM hTreeItem\r\n        )\r\n{\r\n    TV_ITEM tvi;\r\n    PVOID   info;\r\n    ULONG   i;\r\n    HRESULT hr = S_OK;\r\n    PCHAR tviName = NULL;\r\n\r\n    SetLastError(0);\r\n\r\n#ifndef H264_SUPPORT\r\n    UNREFERENCED_PARAMETER(bShowVersion)\r\n#endif\r\n\r\n#ifdef H264_SUPPORT\r\n    ResetErrorCounts();\r\n#endif\r\n\r\n    tviName = ALLOC(256);\r\n\r\n    if(NULL == tviName)\r\n    {\r\n        OOPS();\r\n        hr = E_OUTOFMEMORY;\r\n        return hr;\r\n    }\r\n\r\n    //\r\n    // Get the name of the TreeView item, along with the a pointer to the\r\n    // info we stored about the item in the item's lParam.\r\n    //\r\n\r\n    tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;\r\n    tvi.hItem = hTreeItem;\r\n    tvi.pszText = (LPSTR) tviName;\r\n    tvi.cchTextMax = 256;\r\n\r\n    TreeView_GetItem(hTreeWnd,\r\n                     &tvi);\r\n\r\n    info = (PVOID)tvi.lParam;\r\n\r\n    AppendTextBuffer(tviName);\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    //\r\n    // If we didn't store any info for the item, just display the item's\r\n    // name, else display the info we stored for the item.\r\n    //\r\n    if (NULL != info)\r\n    {\r\n        PUSB_NODE_INFORMATION                  HubInfo = NULL;\r\n        PCHAR                                  HubName = NULL;\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfo = NULL;\r\n        PUSB_DESCRIPTOR_REQUEST                ConfigDesc = NULL;\r\n        PSTRING_DESCRIPTOR_NODE                StringDescs = NULL;\r\n        PUSB_HUB_INFORMATION_EX                HubInfoEx = NULL;\r\n        PUSB_HUB_CAPABILITIES_EX               HubCapabilityEx = NULL;\r\n        PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps = NULL;\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL;\r\n        PUSB_DESCRIPTOR_REQUEST                BosDesc = NULL;\r\n        PDEVICE_INFO_NODE                      DeviceInfoNode = NULL;\r\n\r\n        // The TextBuffer has the TreeView name; add 2 lines for display\r\n        AppendTextBuffer(\"\\r\\n\\r\\n\");\r\n\r\n        switch (*(PUSBDEVICEINFOTYPE)info)\r\n        {\r\n            case HostControllerInfo:\r\n            {\r\n                HTREEITEM       rootHubItem     = NULL;\r\n                BOOL            dbgPortFound    = FALSE;\r\n\r\n                AppendTextBuffer(\"DriverKey: %s\\r\\n\",\r\n                                 ((PUSBHOSTCONTROLLERINFO)info)->DriverKey);\r\n\r\n                AppendTextBuffer(\"VendorID: %04X\\r\\n\",\r\n                                 ((PUSBHOSTCONTROLLERINFO)info)->VendorID);\r\n\r\n                AppendTextBuffer(\"DeviceID: %04X\\r\\n\",\r\n                                 ((PUSBHOSTCONTROLLERINFO)info)->DeviceID);\r\n\r\n                AppendTextBuffer(\"SubSysID: %08X\\r\\n\",\r\n                                 ((PUSBHOSTCONTROLLERINFO)info)->SubSysID);\r\n\r\n                AppendTextBuffer(\"Revision: %02X\\r\\n\",\r\n                                 ((PUSBHOSTCONTROLLERINFO)info)->Revision);\r\n\r\n                //\r\n                // Search for the debug port number.  If running on Win8 or later,\r\n                // the USB_PORT_CONNECTOR_PROPERTIES structure will contain the\r\n                // port number.  If that fails, the list of known host controllers\r\n                // with debug ports will be searched.\r\n                //\r\n\r\n                AppendTextBuffer(\"\\r\\nDebug Port Number:  \");\r\n\r\n                rootHubItem = TreeView_GetChild(hTreeWnd, hTreeItem);\r\n\r\n                if (rootHubItem != NULL)\r\n                {\r\n                    HTREEITEM portItem = NULL;\r\n                    PVOID     portInfo;\r\n\r\n                    portItem = TreeView_GetChild(hTreeWnd, rootHubItem);\r\n\r\n                    while (portItem != NULL)\r\n                    {\r\n                        tvi.mask = TVIF_PARAM;\r\n                        tvi.hItem = portItem;\r\n                        tvi.pszText = NULL;\r\n                        tvi.cchTextMax = 0;\r\n\r\n                        TreeView_GetItem(hTreeWnd, &tvi);\r\n\r\n                        portInfo = (PVOID)tvi.lParam;\r\n\r\n                        //\r\n                        // Note that an empty port is a port without a device attached\r\n                        // is still a DeviceInfo instance.\r\n                        //\r\n\r\n                        if ((*(PUSBDEVICEINFOTYPE)portInfo) == DeviceInfo)\r\n                        {\r\n                            ConnectionInfo = ((PUSBDEVICEINFO)portInfo)->ConnectionInfo;\r\n                            PortConnectorProps = ((PUSBDEVICEINFO)portInfo)->PortConnectorProps;\r\n                        }\r\n                        else if ((*(PUSBDEVICEINFOTYPE)portInfo) == ExternalHubInfo)\r\n                        {\r\n                            ConnectionInfo = ((PUSBEXTERNALHUBINFO)portInfo)->ConnectionInfo;\r\n                            PortConnectorProps = ((PUSBEXTERNALHUBINFO)portInfo)->PortConnectorProps;\r\n\r\n                        }\r\n\r\n                        if (ConnectionInfo != NULL     &&\r\n                            PortConnectorProps != NULL &&\r\n                            PortConnectorProps->UsbPortProperties.PortIsDebugCapable)\r\n                        {\r\n                            dbgPortFound = TRUE;\r\n                            AppendTextBuffer(\"%d\\r\\n\", ((PUSBDEVICEINFO)portInfo)->ConnectionInfo->ConnectionIndex);\r\n                            break;\r\n                        }\r\n                        portItem = TreeView_GetNextSibling(hTreeWnd, portItem);\r\n                    }\r\n\r\n                    //\r\n                    // Resetting ConnectionInfo and PortConnectorProps to NULL so that they won't be erroneously\r\n                    // be displayed below.\r\n                    //\r\n\r\n                    ConnectionInfo = NULL;\r\n                    PortConnectorProps = NULL;\r\n                }\r\n                if (dbgPortFound == FALSE)\r\n                {\r\n                    for (i = 0; EhciControllerData[i].VendorID; i++)\r\n                    {\r\n                        if (((PUSBHOSTCONTROLLERINFO)info)->VendorID ==\r\n                              EhciControllerData[i].VendorID &&\r\n                            ((PUSBHOSTCONTROLLERINFO)info)->DeviceID ==\r\n                              EhciControllerData[i].DeviceID)\r\n                        {\r\n                            dbgPortFound = TRUE;\r\n                            AppendTextBuffer(\"%d\\r\\n\", EhciControllerData[i].DebugPortNumber);\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n                if (dbgPortFound == FALSE)\r\n                {\r\n                    AppendTextBuffer(\"None\\r\\n\");\r\n                }\r\n\r\n                //\r\n                // Display bus/device/function to help with setting debug\r\n                // settings.\r\n                //\r\n                if (((PUSBHOSTCONTROLLERINFO)info)->BusDeviceFunctionValid)\r\n                {\r\n                    AppendTextBuffer(\"Bus.Device.Function (in decimal): %d.%d.%d\\r\\n\",\r\n                                        ((PUSBHOSTCONTROLLERINFO)info)->BusNumber,\r\n                                        ((PUSBHOSTCONTROLLERINFO)info)->BusDevice,\r\n                                        ((PUSBHOSTCONTROLLERINFO)info)->BusFunction);\r\n                }\r\n\r\n                // Display the USB Host Controller Power State Info\r\n                {\r\n                    PUSB_POWER_INFO pUPI = (PUSB_POWER_INFO) &((PUSBHOSTCONTROLLERINFO)info)->USBPowerInfo[0];\r\n                    int                     nIndex = 0;\r\n                    int                     nPowerState = WdmUsbPowerSystemWorking;\r\n\r\n                    AppendTextBuffer(\"\\r\\nHost Controller Power State Mappings\\r\\n\");\r\n                    AppendTextBuffer(\"System State\\t\\tHost Controller\\t\\tRoot Hub\\tUSB wakeup\\tPowered\\r\\n\");\r\n                    for ( ; nPowerState < WdmUsbPowerSystemShutdown; nIndex++, nPowerState++, pUPI++)\r\n                    {\r\n                        DisplayPowerState(pUPI);\r\n                    }\r\n\r\n                    AppendTextBuffer(\"%s\\t%s\\r\\n\",\r\n                                    \"Last Sleep State\",\r\n                                    GetPowerStateString(pUPI->LastSystemSleepState)\r\n                                    );\r\n                }\r\n\r\n                break;\r\n            }\r\n\r\n            case RootHubInfo:\r\n                HubInfo   = ((PUSBROOTHUBINFO)info)->HubInfo;\r\n                HubName   = ((PUSBROOTHUBINFO)info)->HubName;\r\n                HubCapabilityEx  = ((PUSBROOTHUBINFO)info)->HubCapabilityEx;\r\n\r\n                AppendTextBuffer(\"Root Hub: %s\\r\\n\",\r\n                                 HubName);\r\n\r\n                break;\r\n\r\n            case ExternalHubInfo:\r\n                HubInfo            = ((PUSBEXTERNALHUBINFO)info)->HubInfo;\r\n                HubName            = ((PUSBEXTERNALHUBINFO)info)->HubName;\r\n                HubInfoEx          = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx;\r\n                HubCapabilityEx    = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx;\r\n                ConnectionInfo     = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo;\r\n                ConnectionInfoV2   = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2;\r\n                PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps;\r\n                ConfigDesc         = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc;\r\n                StringDescs        = ((PUSBEXTERNALHUBINFO)info)->StringDescs;\r\n                BosDesc            = ((PUSBEXTERNALHUBINFO)info)->BosDesc;\r\n                DeviceInfoNode     = ((PUSBEXTERNALHUBINFO)info)->DeviceInfoNode;\r\n\r\n                AppendTextBuffer(\"External Hub: %s\\r\\n\",\r\n                                 HubName);\r\n                break;\r\n\r\n            case DeviceInfo:\r\n                ConnectionInfo     = ((PUSBDEVICEINFO)info)->ConnectionInfo;\r\n                ConnectionInfoV2   = ((PUSBDEVICEINFO)info)->ConnectionInfoV2;\r\n                PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps;\r\n                ConfigDesc         = ((PUSBDEVICEINFO)info)->ConfigDesc;\r\n                StringDescs        = ((PUSBDEVICEINFO)info)->StringDescs;\r\n                BosDesc            = ((PUSBDEVICEINFO)info)->BosDesc;\r\n                DeviceInfoNode     = ((PUSBDEVICEINFO)info)->DeviceInfoNode;\r\n                break;\r\n        }\r\n\r\n        if (PortConnectorProps)\r\n        {\r\n            DisplayPortConnectorProperties(PortConnectorProps, ConnectionInfoV2);\r\n        }\r\n\r\n        if (DeviceInfoNode)\r\n        {\r\n            DisplayDevicePowerState(DeviceInfoNode);\r\n        }\r\n\r\n        if (HubInfo)\r\n        {\r\n            DisplayHubInfo(&HubInfo->u.HubInformation,\r\n                           (HubInfoEx == NULL));\r\n        }\r\n\r\n        if (HubInfoEx)\r\n        {\r\n            DisplayHubInfoEx(HubInfoEx);\r\n        }\r\n\r\n        if(HubCapabilityEx)\r\n        {\r\n            DisplayHubCapabilityEx(HubCapabilityEx);\r\n        }\r\n\r\n        if (ConnectionInfo)\r\n        {\r\n            DisplayConnectionInfo(ConnectionInfo,\r\n                (PUSBDEVICEINFO)info,\r\n                StringDescs,\r\n                ConnectionInfoV2);\r\n        }\r\n\r\n        if (ConfigDesc)\r\n        {\r\n            DisplayConfigDesc((PUSBDEVICEINFO)info,\r\n                (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigDesc + 1),\r\n                StringDescs);\r\n        }\r\n\r\n        if (BosDesc)\r\n        {\r\n            DisplayBosDescriptor((PUSBDEVICEINFO) info,\r\n                (PUSB_BOS_DESCRIPTOR) (BosDesc + 1),\r\n                StringDescs);\r\n        }\r\n    }\r\n\r\n    if(tviName != NULL)\r\n    {\r\n        FREE(tviName);\r\n    }\r\n\r\n    // AppendTextBuffer() which is used in Display*() functions uses GlobalRealloc() which can fail if realloc fails.\r\n    // Obtain last error code from GetLastError() and propagate the error to caller.\r\n    hr = HRESULT_FROM_WIN32(GetLastError());\r\n\r\n    return hr;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// UpdateEditControl()\r\n//\r\n// hTreeItem - Handle of selected TreeView item for which information should\r\n// be displayed in the edit control.\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nUpdateEditControl (\r\n    HWND      hEditWnd,\r\n    HWND      hTreeWnd,\r\n    HTREEITEM hTreeItem\r\n)\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    // Start with an empty text buffer.\r\n    //\r\n    if (!ResetTextBuffer())\r\n    {\r\n        return;\r\n    }\r\n\r\n    // Get the item information in global TextBuffer\r\n    hr = UpdateTreeItemDeviceInfo(hTreeWnd, hTreeItem);\r\n\r\n    if(FAILED(hr))\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n    // All done formatting text buffer with info, now update the edit\r\n    // control with the contents of the text buffer\r\n    //\r\n    SetWindowText(hEditWnd, TextBuffer);\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayPortConnectorProperties()\r\n\r\nPortConnectorProps - Info about the port connector properties.\r\n\r\n*****************************************************************************/\r\n\r\nvoid\r\nDisplayPortConnectorProperties (\r\n    _In_     PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2\r\n    )\r\n{\r\n    AppendTextBuffer(\"Is Port User Connectable:         %s\\r\\n\",\r\n                     PortConnectorProps->UsbPortProperties.PortIsUserConnectable\r\n                     ? \"yes\" : \"no\");\r\n\r\n    AppendTextBuffer(\"Is Port Debug Capable:            %s\\r\\n\",\r\n                     PortConnectorProps->UsbPortProperties.PortIsDebugCapable\r\n                     ? \"yes\" : \"no\");\r\n    AppendTextBuffer(\"Companion Port Number:            %d\\r\\n\",\r\n                     PortConnectorProps->CompanionPortNumber);\r\n    AppendTextBuffer(\"Companion Hub Symbolic Link Name: %ws\\r\\n\",\r\n                     PortConnectorProps->CompanionHubSymbolicLinkName);\r\n    if (ConnectionInfoV2 != NULL)\r\n    {\r\n        AppendTextBuffer(\"Protocols Supported:\\r\\n\");\r\n        AppendTextBuffer(\" USB 1.1:                         %s\\r\\n\",\r\n                         ConnectionInfoV2->SupportedUsbProtocols.Usb110\r\n                         ? \"yes\" : \"no\");\r\n        AppendTextBuffer(\" USB 2.0:                         %s\\r\\n\",\r\n                         ConnectionInfoV2->SupportedUsbProtocols.Usb200\r\n                         ? \"yes\" : \"no\");\r\n        AppendTextBuffer(\" USB 3.0:                         %s\\r\\n\",\r\n                         ConnectionInfoV2->SupportedUsbProtocols.Usb300\r\n                         ? \"yes\" : \"no\");\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n\");\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayDevicePowerState()\r\n\r\nDeviceInfoNode - Structure containing info used to acquire device state\r\n\r\n*****************************************************************************/\r\n\r\nvoid\r\nDisplayDevicePowerState (\r\n    _In_     PDEVICE_INFO_NODE DeviceInfoNode\r\n    )\r\n{\r\n\r\n    DEVICE_POWER_STATE powerState;\r\n\r\n    powerState = AcquireDevicePowerState(DeviceInfoNode);\r\n\r\n    AppendTextBuffer(\"Device Power State:               \");\r\n    if (powerState >= PowerDeviceD0 && powerState <= PowerDeviceD3)\r\n    {\r\n        AppendTextBuffer(\"PowerDeviceD%d\\r\\n\", powerState-1);\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"Invalid Device Power State Value %d\\r\\n\", powerState);\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n\");\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayHubDescriptorBase()\r\n\r\nHubDescriptor - hub descriptor, could also be PUSB_30_HUB_DESCRIPTOR which has\r\n                these field in common at the beginning of the data structure:\r\n\r\n                - UCHAR   bLength;\r\n                - UCHAR   bDescriptorType;\r\n                - UCHAR   bNumberOfPorts;\r\n                - USHORT  wHubCharacteristics;\r\n                - UCHAR   bPowerOnToPowerGood;\r\n                - UCHAR   bHubControlCurrent;\r\n\r\n*****************************************************************************/\r\nVOID\r\nDisplayHubDescriptorBase(\r\n    PUSB_HUB_DESCRIPTOR HubDescriptor\r\n    )\r\n{\r\n    USHORT wHubChar = 0;\r\n\r\n    AppendTextBuffer(\"Number of Ports:              %d\\r\\n\",\r\n        HubDescriptor->bNumberOfPorts);\r\n\r\n    wHubChar = HubDescriptor->wHubCharacteristics;\r\n\r\n    switch (wHubChar & 0x0003)\r\n    {\r\n    case 0x0000:\r\n        AppendTextBuffer(\"Power switching:              Ganged\\r\\n\");\r\n        break;\r\n\r\n    case 0x0001:\r\n        AppendTextBuffer(\"Power switching:              Individual\\r\\n\");\r\n        break;\r\n\r\n    case 0x0002:\r\n    case 0x0003:\r\n        AppendTextBuffer(\"Power switching:              None\\r\\n\");\r\n        break;\r\n    }\r\n\r\n    switch (wHubChar & 0x0004)\r\n    {\r\n    case 0x0000:\r\n        AppendTextBuffer(\"Compound device:              No\\r\\n\");\r\n        break;\r\n\r\n    case 0x0004:\r\n        AppendTextBuffer(\"Compound device:              Yes\\r\\n\");\r\n        break;\r\n    }\r\n\r\n    switch (wHubChar & 0x0018)\r\n    {\r\n    case 0x0000:\r\n        AppendTextBuffer(\"Over-current Protection:      Global\\r\\n\");\r\n        break;\r\n\r\n    case 0x0008:\r\n        AppendTextBuffer(\"Over-current Protection:      Individual\\r\\n\");\r\n        break;\r\n\r\n    case 0x0010:\r\n    case 0x0018:\r\n        AppendTextBuffer(\"No Over-current Protection (Bus Power Only)\\r\\n\");\r\n        break;\r\n    }\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayHubInfo()\r\n\r\nHubInfo - Info about the hub.\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayHubInfo (\r\n    PUSB_HUB_INFORMATION  HubInfo,\r\n    BOOL                  DisplayDescriptor\r\n    )\r\n{\r\n    AppendTextBuffer(\"Hub Power:                    %s\\r\\n\",\r\n        HubInfo->HubIsBusPowered ?\r\n        \"Bus Power\" : \"Self Power\");\r\n\r\n    if (DisplayDescriptor == TRUE)\r\n    {\r\n        DisplayHubDescriptorBase(&HubInfo->HubDescriptor);\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayHubInfoEx()\r\n\r\nHubInfo - Extended info about the hub.\r\n\r\n*****************************************************************************/\r\n\r\n\r\nVOID\r\nDisplayHubInfoEx (\r\n    PUSB_HUB_INFORMATION_EX    HubInfoEx\r\n    )\r\n{\r\n    AppendTextBuffer(\"Hub type:                     \");\r\n\r\n    switch (HubInfoEx->HubType) {\r\n\r\n        case UsbRootHub:\r\n            AppendTextBuffer(\"USB Root Hub\\r\\n\");\r\n            break;\r\n\r\n        case Usb20Hub:\r\n            AppendTextBuffer(\"USB 2.0 Hub\\r\\n\");\r\n            DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor);\r\n            break;\r\n\r\n        case Usb30Hub:\r\n            AppendTextBuffer(\"USB 3.0 Hub\\r\\n\");\r\n\r\n            //\r\n            // Note that the DisplayHubDescriptorBase will display the fields of either\r\n            // the legacy hub descriptor and the USB 3.0 descriptor which have the same\r\n            // offset\r\n            //\r\n\r\n            DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor);\r\n            AppendTextBuffer(\"Packet Header Decode Latency: 0x%x\\r\\n\", HubInfoEx->u.Usb30HubDescriptor.bHubHdrDecLat);\r\n            AppendTextBuffer(\"Delay:                        0x%x ns\\r\\n\", HubInfoEx->u.Usb30HubDescriptor.wHubDelay);\r\n\r\n            break;\r\n\r\n        default:\r\n            AppendTextBuffer(\"ERROR: Unknown hub type %d\\r\\n\", HubInfoEx->HubType);\r\n            break;\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n\");\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayHubCapabilityEx()\r\n\r\nHubCapabilityInfo - Hub capability information\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayHubCapabilityEx (\r\n    PUSB_HUB_CAPABILITIES_EX    HubCapabilityEx\r\n    )\r\n{\r\n    if(HubCapabilityEx != NULL)\r\n    {\r\n       AppendTextBuffer(\"High speed capable:           %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsHighSpeedCapable\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"High speed:                   %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsHighSpeed\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"Multiple transaction translations capable:                 %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsMultiTtCapable\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"Performs multiple transaction translations simultaneously: %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsMultiTt\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"Hub wakes when device is connected:                        %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsArmedWakeOnConnect\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"Hub is bus powered:           %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsBusPowered\r\n                         ? \"Yes\" : \"No\");\r\n       AppendTextBuffer(\"Hub is root:                  %s\\r\\n\",\r\n                         HubCapabilityEx->CapabilityFlags.HubIsRoot\r\n                         ? \"Yes\" : \"No\");\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayConnectionInfo()\r\n\r\nConnectInfo - Info about the connection.\r\n\r\nPUSB_NODE_CONNECTION_INFORMATION_EX    ConnectInfo,\r\nPSTRING_DESCRIPTOR_NODE             StringDescs\r\n\r\nDisplayConnectionInfo(info->ConnectionInfo,\r\ninfo->StringDescs);\r\n\r\nDisplayConnectionInfo (\r\nPUSB_NODE_CONNECTION_INFORMATION_EX    ConnectInfo,\r\nPSTRING_DESCRIPTOR_NODE             StringDescs\r\n)\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayConnectionInfo (\r\n    _In_     PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectInfo,\r\n    _In_     PUSBDEVICEINFO                         info,\r\n    _In_     PSTRING_DESCRIPTOR_NODE                StringDescs,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2\r\n)\r\n{\r\n\r\n    //@@DisplayConnectionInfo - Device Information\r\n    PCHAR                               VendorString = NULL;\r\n    UINT                                tog = 1;\r\n    UINT                                uIADcount = 0;\r\n\r\n    // No device connected\r\n    if (ConnectInfo->ConnectionStatus == NoDeviceConnected)\r\n    {\r\n        AppendTextBuffer(\"ConnectionStatus:      NoDeviceConnected\\r\\n\");\r\n        return;\r\n    }\r\n\r\n    // This is the entry point to the device display functions.\r\n    // First, save this device's PUSBDEVICEINFO address\r\n    // In a future version of this test, we will keep track of the the\r\n    //  descriptor that we're parsing (# of bytes from beginning of info->configuration descriptor)\r\n    // Then we can linked descriptors by reading forward through the remaining descriptors\r\n    //  while still keeping our place in this main DisplayConnectionInfo() and called\r\n    //  functions.\r\n    //\r\n    // We also initialize some global flags in uvcview.h that are used to\r\n    //  verify items in MJPEG, Uncompressed and Vendor Frame descriptors\r\n    //\r\n    InitializePerDeviceSettings(info);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n\r\n        AppendTextBuffer(\"       ---===>Device Information<===---\\r\\n\");\r\n\r\n        if (ConnectInfo->DeviceDescriptor.iProduct)\r\n        {\r\n            DisplayUSEnglishStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct,\r\n                StringDescs,\r\n                info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n        }\r\n\r\n        AppendTextBuffer(\"\\r\\nConnectionStatus:                  %s\\r\\n\",\r\n            ConnectionStatuses[ConnectInfo->ConnectionStatus]);\r\n\r\n        AppendTextBuffer(\"Current Config Value:              0x%02X\",\r\n            ConnectInfo->CurrentConfigurationValue);\r\n    }\r\n\r\n    switch (ConnectInfo->Speed){\r\n    case UsbLowSpeed:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Device Bus Speed: Low\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        gDeviceSpeed = UsbLowSpeed;\r\n        break;\r\n\r\n    case UsbFullSpeed:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Device Bus Speed: Full\");\r\n            if (ConnectionInfoV2 != NULL)\r\n            {\r\n                if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher)\r\n                {\r\n                    AppendTextBuffer(\" (is SuperSpeedPlus or higher capable)\\r\\n\");\r\n                }\r\n                else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher)\r\n                {\r\n                    AppendTextBuffer(\" (is SuperSpeed or higher capable)\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\" (is not SuperSpeed or higher capable)\\r\\n\");\r\n                }\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n         }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        gDeviceSpeed = UsbFullSpeed;\r\n        break;\r\n    case UsbHighSpeed:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Device Bus Speed: High\");\r\n            if (ConnectionInfoV2 != NULL)\r\n            {\r\n                if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher)\r\n                {\r\n                    AppendTextBuffer(\" (is SuperSpeedPlus or higher capable)\\r\\n\");\r\n                }\r\n                else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher)\r\n                {\r\n                    AppendTextBuffer(\" (is SuperSpeed or higher capable)\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\" (is not SuperSpeed or higher capable)\\r\\n\");\r\n                }\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        gDeviceSpeed = UsbHighSpeed;\r\n        break;\r\n\r\n    case UsbSuperSpeed:\r\n        if(gDoAnnotation)\r\n        {\r\n            if (ConnectionInfoV2 != NULL)\r\n            {\r\n                AppendTextBuffer(\"  -> Device Bus Speed: Super%s\\r\\n\",\r\n                    ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher\r\n                    ? \"SpeedPlus\"\r\n                    : \"Speed\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"  -> Device Bus Speed: Super Speed\\r\\n\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        gDeviceSpeed = UsbSuperSpeed;\r\n        break;\r\n\r\n    default:\r\n        if(gDoAnnotation){AppendTextBuffer(\"  -> Device Bus Speed: Unknown\\r\\n\");}\r\n        else {AppendTextBuffer(\"\\r\\n\");}\r\n    }\r\n\r\n    if(gDoAnnotation){\r\n        AppendTextBuffer(\"Device Address:                    0x%02X\\r\\n\",\r\n            ConnectInfo->DeviceAddress);\r\n\r\n        AppendTextBuffer(\"Open Pipes:                          %2d\\r\\n\",\r\n            ConnectInfo->NumberOfOpenPipes);\r\n    }\r\n\r\n    // No open pipes means the USB stack has not loaded the device\r\n    if (ConnectInfo->NumberOfOpenPipes == 0)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  No open pipes!\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Device Descriptor<===\\r\\n\");\r\n    //@@DisplayConnectionInfo - Device Descriptor\r\n\r\n    if (ConnectInfo->DeviceDescriptor.bLength != 18)\r\n    {\r\n        //@@TestCase A1.1\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the\r\n        //@@  required length in the USB Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            ConnectInfo->DeviceDescriptor.bLength,\r\n            18);\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.bDescriptorType);\r\n\r\n    //@@TestCase A1.2\r\n    //@@Not implemented - Priority 1\r\n    //@@Descriptor Field - bcdUSB\r\n    //@@Need to check that any UVC device is set to 0x0200 or later.\r\n    AppendTextBuffer(\"bcdUSB:                          0x%04X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.bcdUSB);\r\n\r\n    AppendTextBuffer(\"bDeviceClass:                      0x%02X\",\r\n        ConnectInfo->DeviceDescriptor.bDeviceClass);\r\n\r\n    // Quit on these device failures\r\n    if ((ConnectInfo->ConnectionStatus == DeviceFailedEnumeration) ||\r\n        (ConnectInfo->ConnectionStatus == DeviceGeneralFailure))\r\n    {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  Device enumeration failure\\r\\n\");\r\n        return;\r\n    }\r\n\r\n    // Is this an IAD device?\r\n    uIADcount = IsIADDevice((PUSBDEVICEINFO) info);\r\n\r\n    if (uIADcount)\r\n    {\r\n        // this device configuration has 1 or more IAD descriptors\r\n        if (ConnectInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE)\r\n        {\r\n            tog = 0;\r\n            if (gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> This is a Multi-interface Function Code Device\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n        } else {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: device class should be Multi-interface Function 0x%02X\\r\\n\"\\\r\n                \"          When IAD descriptor is used\\r\\n\",\r\n                USB_MISCELLANEOUS_DEVICE);\r\n        }\r\n        // Is this a UVC device?\r\n        g_chUVCversion = IsUVCDevice((PUSBDEVICEINFO) info);\r\n    }\r\n    else\r\n    {\r\n        // this is not an IAD device\r\n        switch (ConnectInfo->DeviceDescriptor.bDeviceClass)\r\n        {\r\n        case USB_INTERFACE_CLASS_DEVICE:\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is an Interface Class Defined Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_COMMUNICATION_DEVICE:\r\n            tog = 0;\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is a Communication Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_HUB_DEVICE:\r\n            tog = 0;\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is a HUB Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_DIAGNOSTIC_DEVICE:\r\n            tog = 0;\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is a Diagnostic Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_WIRELESS_CONTROLLER_DEVICE:\r\n            tog = 0;\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is a Wireless Controller(Bluetooth) Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_VENDOR_SPECIFIC_DEVICE:\r\n            tog = 0;\r\n            if(gDoAnnotation)\r\n            {AppendTextBuffer(\"  -> This is a Vendor Specific Device\\r\\n\");}\r\n            else {AppendTextBuffer(\"\\r\\n\");}\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_BILLBOARD:\r\n            tog = 0;\r\n            if (gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> This is a billboard class device\\r\\n\");\r\n            }\r\n            else { AppendTextBuffer(\"\\r\\n\"); }\r\n            break;\r\n\r\n        case USB_MISCELLANEOUS_DEVICE:\r\n            tog = 0;\r\n            //@@TestCase A1.3\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceClass\r\n            //@@Multi-interface Function code used for non-IAD device\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  Multi-interface Function code %d used for \"\\\r\n                \"device with no IAD descriptors\\r\\n\",\r\n                ConnectInfo->DeviceDescriptor.bDeviceClass);\r\n            break;\r\n\r\n        default:\r\n            //@@TestCase A1.4\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceClass\r\n            //@@An unknown device class has been defined\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  unknown bDeviceClass %d\\r\\n\",\r\n                ConnectInfo->DeviceDescriptor.bDeviceClass);\r\n            OOPS();\r\n            break;\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"bDeviceSubClass:                   0x%02X\",\r\n        ConnectInfo->DeviceDescriptor.bDeviceSubClass);\r\n\r\n    // check the subclass\r\n    if (uIADcount)\r\n    {\r\n        // this device configuration has 1 or more IAD descriptors\r\n        if (ConnectInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS)\r\n        {\r\n            if (gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> This is the Common Class Sub Class\\r\\n\");\r\n            } else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A1.5\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceSubClass\r\n            //@@An invalid device sub class used for Multi-interface Function (IAD) device\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: device SubClass should be USB Common Sub Class %d\\r\\n\"\\\r\n                \"          When IAD descriptor is used\\r\\n\",\r\n                USB_COMMON_SUB_CLASS);\r\n            OOPS();\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // Not an IAD device, so all subclass values are invalid\r\n        if(ConnectInfo->DeviceDescriptor.bDeviceSubClass > 0x00 &&\r\n            ConnectInfo->DeviceDescriptor.bDeviceSubClass < 0xFF)\r\n        {\r\n            //@@TestCase A1.6\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceSubClass\r\n            //@@An invalid device sub class has been defined\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  bDeviceSubClass of %d is invalid\\r\\n\",\r\n                ConnectInfo->DeviceDescriptor.bDeviceSubClass);\r\n            OOPS();\r\n        } else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"bDeviceProtocol:                   0x%02X\",\r\n        ConnectInfo->DeviceDescriptor.bDeviceProtocol);\r\n\r\n    // check the protocol\r\n    if (uIADcount)\r\n    {\r\n        // this device configuration has 1 or more IAD descriptors\r\n        if (ConnectInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL)\r\n        {\r\n            if (gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> This is the Interface Association Descriptor protocol\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A1.7\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceSubClass\r\n            //@@An invalid device sub class used for Multi-interface Function (IAD) device\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: device Protocol should be USB IAD Protocol %d\\r\\n\"\\\r\n                \"          When IAD descriptor is used\\r\\n\",\r\n                USB_IAD_PROTOCOL);\r\n            OOPS();\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // Not an IAD device, so all subclass values are invalid\r\n        if(ConnectInfo->DeviceDescriptor.bDeviceProtocol > 0x00 &&\r\n            ConnectInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1)\r\n        {\r\n            //@@TestCase A1.8\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDeviceProtocol\r\n            //@@An invalid device protocol has been defined\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  bDeviceProtocol of %d is invalid\\r\\n\",\r\n                ConnectInfo->DeviceDescriptor.bDeviceProtocol);\r\n            OOPS();\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"bMaxPacketSize0:                   0x%02X\",\r\n        ConnectInfo->DeviceDescriptor.bMaxPacketSize0);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\" = (%d) Bytes\\r\\n\",\r\n            ConnectInfo->DeviceDescriptor.bMaxPacketSize0);\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    switch (gDeviceSpeed){\r\n        case UsbLowSpeed:\r\n            if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 8)\r\n            {\r\n                //@@TestCase A1.9\r\n                //@@ERROR\r\n                //@@Descriptor Field - bMaxPacketSize0\r\n                //@@An invalid bMaxPacketSize0 has been defined for a low speed device\r\n                AppendTextBuffer(\"*!*ERROR:  Low Speed Devices require bMaxPacketSize0 = 8\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n        case UsbFullSpeed:\r\n            if(!(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 8 ||\r\n                ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 16 ||\r\n                ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 32 ||\r\n                ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 64))\r\n            {\r\n                //@@TestCase A1.10\r\n                //@@ERROR\r\n                //@@Descriptor Field - bMaxPacketSize0\r\n                //@@An invalid bMaxPacketSize0 has been defined for a full speed device\r\n                AppendTextBuffer(\"*!*ERROR:  Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n        case UsbHighSpeed:\r\n            if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 64)\r\n            {\r\n                //@@TestCase A1.11\r\n                //@@ERROR\r\n                //@@Descriptor Field - bMaxPacketSize0\r\n                //@@An invalid bMaxPacketSize0 has been defined for a high speed device\r\n                AppendTextBuffer(\"*!*ERROR:  High Speed Devices require bMaxPacketSize0 = 64\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n        case UsbSuperSpeed:\r\n            if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 9)\r\n            {\r\n                AppendTextBuffer(\"*!*ERROR:  SuperSpeed Devices require bMaxPacketSize0 = 9 (512)\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n    }\r\n\r\n    AppendTextBuffer(\"idVendor:                        0x%04X\",\r\n        ConnectInfo->DeviceDescriptor.idVendor);\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        VendorString = GetVendorString(ConnectInfo->DeviceDescriptor.idVendor);\r\n        if (VendorString != NULL)\r\n        {\r\n            AppendTextBuffer(\" = %s\\r\\n\",\r\n                VendorString);\r\n        }\r\n    }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    AppendTextBuffer(\"idProduct:                       0x%04X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.idProduct);\r\n\r\n    AppendTextBuffer(\"bcdDevice:                       0x%04X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.bcdDevice);\r\n\r\n    AppendTextBuffer(\"iManufacturer:                     0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.iManufacturer);\r\n\r\n    if (ConnectInfo->DeviceDescriptor.iManufacturer && gDoAnnotation)\r\n    {\r\n        DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iManufacturer,\r\n            StringDescs,\r\n            info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n    }\r\n\r\n    AppendTextBuffer(\"iProduct:                          0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.iProduct);\r\n\r\n    if (ConnectInfo->DeviceDescriptor.iProduct && gDoAnnotation)\r\n    {\r\n        DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct,\r\n            StringDescs,\r\n            info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n    }\r\n\r\n    AppendTextBuffer(\"iSerialNumber:                     0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.iSerialNumber);\r\n\r\n    if (ConnectInfo->DeviceDescriptor.iSerialNumber && gDoAnnotation)\r\n    {\r\n        DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iSerialNumber,\r\n            StringDescs,\r\n            info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n    }\r\n\r\n    AppendTextBuffer(\"bNumConfigurations:                0x%02X\\r\\n\",\r\n        ConnectInfo->DeviceDescriptor.bNumConfigurations);\r\n\r\n    if(ConnectInfo->DeviceDescriptor.bNumConfigurations != 1)\r\n    {\r\n        //@@TestCase A1.12\r\n        //@@CAUTION\r\n        //@@Descriptor Field - bNumConfigurations\r\n        //@@Most host controllers do not handle more than one configuration\r\n        AppendTextBuffer(\"*!*CAUTION:    Most host controllers will only work with \"\\\r\n            \"one configuration per speed\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (ConnectInfo->NumberOfOpenPipes)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n          ---===>Open Pipes<===---\\r\\n\");\r\n        DisplayPipeInfo(ConnectInfo->NumberOfOpenPipes,\r\n                        ConnectInfo->PipeList);\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayPipeInfo()\r\n\r\nNumPipes - Number of pipe for we info should be displayed.\r\n\r\nPipeInfo - Info about the pipes.\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayPipeInfo (\r\n    ULONG           NumPipes,\r\n    USB_PIPE_INFO  *PipeInfo\r\n    )\r\n{\r\n    ULONG i = 0;\r\n\r\n    for (i = 0; i < NumPipes; i++)\r\n    {\r\n        DisplayEndpointDescriptor(&PipeInfo[i].EndpointDescriptor, NULL, NULL, 0, FALSE);\r\n    }\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetControllerFlavorString()\r\n\r\nReturns the text for given controller flavor\r\n\r\n*****************************************************************************/\r\nPCHAR GetControllerFlavorString(USB_CONTROLLER_FLAVOR flavor)\r\n{\r\n    return(GetStringFromList(slControllerFlavor,\r\n                        sizeof(slControllerFlavor) / sizeof(STRINGLIST),\r\n                        flavor,\r\n                        STR_UNKNOWN_CONTROLLER_FLAVOR));\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nGetPowerStateString()\r\n\r\nReturns the descriptive string for given power state\r\n\r\n*****************************************************************************/\r\nPCHAR GetPowerStateString(WDMUSB_POWER_STATE powerState)\r\n{\r\n    return(GetStringFromList(slPowerState,\r\n                        sizeof(slPowerState) / sizeof(STRINGLIST),\r\n                        powerState,\r\n                        STR_INVALID_POWER_STATE));\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayPowerState()\r\n\r\nPUSB_POWER_INFO pUPI - USBUSER.H USB_Power_Info data\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayPowerState(\r\n    PUSB_POWER_INFO pUPI\r\n    )\r\n{\r\n    AppendTextBuffer(\"%s\\t%s\\t%s%s\\t\\t%s\\r\\n\",\r\n                        GetPowerStateString(pUPI->SystemState),\r\n                        GetPowerStateString(pUPI->HcDevicePowerState),\r\n                        GetPowerStateString(pUPI->RhDevicePowerState),\r\n                        pUPI->CanWakeup ? \"Yes\" : \"\",\r\n                        pUPI->IsPowered ? \"Yes\" : \"\"\r\n                     );\r\n    return;\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nValidateDescAddress()\r\n\r\nGiven a descriptor address and the Configuration Descriptor length\r\n    (saved in DisplayConfigDesc(), and initialized for each new device)\r\nreturn TRUE if the descriptor is within the Configuration length\r\nelse FALSE\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nValidateDescAddress (\r\n    PUSB_COMMON_DESCRIPTOR          commonDesc\r\n    )\r\n{\r\n    if ((PUCHAR) commonDesc + commonDesc->bLength <= g_descEnd)\r\n    {\r\n        return TRUE;\r\n    }\r\n    return FALSE;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayConfigDesc()\r\n\r\nConfigDesc - The Configuration Descriptor, and associated Interface and\r\nEndpoint Descriptors\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayConfigDesc (\r\n    PUSBDEVICEINFO                  info,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,\r\n    PSTRING_DESCRIPTOR_NODE         StringDescs\r\n    )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR          commonDesc = NULL;\r\n    UCHAR                           bInterfaceClass = 0;\r\n    UCHAR                           bInterfaceSubClass = 0;\r\n    UCHAR                           bInterfaceProtocol = 0;\r\n    BOOL                            displayUnknown = FALSE;\r\n\r\n    BOOL                            isSS;\r\n\r\n    isSS = info->ConnectionInfoV2\r\n        && info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher\r\n       ? TRUE\r\n       : FALSE;\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n\r\n    // initialize global Configuration start/end address and string desc address\r\n    g_pConfigDesc  = ConfigDesc;\r\n    g_pStringDescs = StringDescs;\r\n    g_descEnd      = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n\r\n    AppendTextBuffer(\"\\r\\n       ---===>Full Configuration Descriptor<===---\\r\\n\");\r\n\r\n    do\r\n    {\r\n        displayUnknown = FALSE;\r\n\r\n        switch (commonDesc->bDescriptorType)\r\n        {\r\n        case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE:\r\n            //@@DisplayConfigDesc - Device Qualifier Descriptor\r\n            if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR))\r\n            {\r\n                //@@TestCase A2.1\r\n                //@@ERROR\r\n                //@@Descriptor Field - bLength\r\n                //@@The declared length in the device descriptor is not equal to the\r\n                //@@  required length in the USB Device Specification\r\n                AppendTextBuffer(\"*!*ERROR:  bLength of %d for Device Qualifier incorrect, \"\\\r\n                    \"should be %d\\r\\n\",\r\n                    commonDesc->bLength,\r\n                    sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR));\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            DisplayDeviceQualifierDescriptor((PUSB_DEVICE_QUALIFIER_DESCRIPTOR)commonDesc);\r\n            break;\r\n\r\n        case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE:\r\n            //@@DisplayConfigDesc - Other Speed Configuration Descriptor\r\n            if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n            {\r\n                //@@TestCase A2.2\r\n                //@@ERROR\r\n                //@@Descriptor Field - bLength\r\n                //@@The declared length in the device descriptor is not equal to the\r\n                //@@  required length in the USB Device Specification\r\n                AppendTextBuffer(\"*!*ERROR:  bLength of %d for Other Speed Configuration \"\\\r\n                    \"incorrect, should be %d\\r\\n\",\r\n                    commonDesc->bLength,\r\n                    sizeof(USB_CONFIGURATION_DESCRIPTOR));\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n            }\r\n            DisplayConfigurationDescriptor(\r\n                (PUSBDEVICEINFO) info,\r\n                (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc,\r\n                StringDescs);\r\n            break;\r\n\r\n        case USB_CONFIGURATION_DESCRIPTOR_TYPE:\r\n            //@@DisplayConfigDesc - Configuration Descriptor\r\n            if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n            {\r\n                //@@TestCase A2.3\r\n                //@@ERROR\r\n                //@@Descriptor Field - bLength\r\n                //@@The declared length in the device descriptor is not equal to the\r\n                //@@required length in the USB Device Specification\r\n                AppendTextBuffer(\"*!*ERROR:  bLength of %d for Configuration incorrect, \"\\\r\n                    \"should be %d\\r\\n\",\r\n                    commonDesc->bLength,\r\n                    sizeof(USB_CONFIGURATION_DESCRIPTOR));\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            DisplayConfigurationDescriptor((PUSBDEVICEINFO)info,\r\n                (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc,\r\n                StringDescs);\r\n            break;\r\n\r\n        case USB_INTERFACE_DESCRIPTOR_TYPE:\r\n            //@@DisplayConfigDesc - Interface Descriptor\r\n            if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) &&\r\n                (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)))\r\n            {\r\n                //@@TestCase A2.4\r\n                //@@ERROR\r\n                //@@Descriptor Field - bLength\r\n                //@@The declared length in the device descriptor is not equal to the\r\n                //@@required length in the USB Device Specification\r\n                AppendTextBuffer(\"*!*ERROR:  bLength of %d for Interface incorrect, \"\\\r\n                    \"should be %d or %d\\r\\n\",\r\n                    commonDesc->bLength,\r\n                    sizeof(USB_INTERFACE_DESCRIPTOR),\r\n                    sizeof(USB_INTERFACE_DESCRIPTOR2));\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass;\r\n            bInterfaceSubClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass;\r\n            bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol;\r\n\r\n            DisplayInterfaceDescriptor(\r\n                    (PUSB_INTERFACE_DESCRIPTOR)commonDesc,\r\n                    StringDescs,\r\n                    info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n\r\n            break;\r\n\r\n        case USB_ENDPOINT_DESCRIPTOR_TYPE:\r\n            {\r\n                PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR epCompDesc = NULL;\r\n                PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR\r\n                                                              sspIsochCompDesc = NULL;\r\n\r\n\r\n                //@@DisplayConfigDesc - Endpoint Descriptor\r\n                if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) &&\r\n                    (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2)))\r\n                {\r\n                    //@@TestCase A2.5\r\n                    //@@ERROR\r\n                    //@@Descriptor Field - bLength\r\n                    //@@The declared length in the device descriptor is not equal to\r\n                    //@@  the required length in the USB Device Specification\r\n                    AppendTextBuffer(\"*!*ERROR:  bLength of %d for Endpoint incorrect, \"\\\r\n                        \"should be %d or %d\\r\\n\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_ENDPOINT_DESCRIPTOR),\r\n                        sizeof(USB_ENDPOINT_DESCRIPTOR2));\r\n                    OOPS();\r\n                    displayUnknown = TRUE;\r\n                    break;\r\n                }\r\n\r\n                if (isSS)\r\n                {\r\n                     epCompDesc = (PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR)\r\n                        GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, ConfigDesc->wTotalLength, commonDesc, -1);\r\n                }\r\n\r\n                if (epCompDesc != NULL &&\r\n                    epCompDesc->bmAttributes.Isochronous.SspCompanion == 1)\r\n                {\r\n                    sspIsochCompDesc = (PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR)\r\n                        GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc,\r\n                            ConfigDesc->wTotalLength,\r\n                            (PUSB_COMMON_DESCRIPTOR)epCompDesc,\r\n                            -1);\r\n                }\r\n\r\n                DisplayEndpointDescriptor((PUSB_ENDPOINT_DESCRIPTOR)commonDesc,\r\n                    epCompDesc,\r\n                    sspIsochCompDesc,\r\n                    bInterfaceClass,\r\n                    TRUE);\r\n\r\n                if (sspIsochCompDesc != NULL)\r\n                {\r\n                    commonDesc = (PUSB_COMMON_DESCRIPTOR)sspIsochCompDesc;\r\n                }\r\n                else if (epCompDesc != NULL)\r\n                {\r\n                     commonDesc = (PUSB_COMMON_DESCRIPTOR)epCompDesc;\r\n                }\r\n            }\r\n\r\n            break;\r\n\r\n        case USB_HID_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR))\r\n            {\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            DisplayHidDescriptor((PUSB_HID_DESCRIPTOR)commonDesc);\r\n            break;\r\n\r\n        case USB_OTG_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR))\r\n            {\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            DisplayOTGDescriptor((PUSB_OTG_DESCRIPTOR)commonDesc);\r\n            break;\r\n\r\n        case USB_IAD_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR))\r\n            {\r\n                OOPS();\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            DisplayIADDescriptor((PUSB_IAD_DESCRIPTOR)commonDesc, StringDescs,\r\n                    ConfigDesc->bNumInterfaces,\r\n                    info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n            break;\r\n\r\n        default:\r\n            //@@DisplayConfigDesc - Interface Class Device\r\n            // TODO: BUG: bInterfaceClass is initialized before this code\r\n            switch (bInterfaceClass)\r\n            {\r\n            case USB_DEVICE_CLASS_AUDIO:\r\n                displayUnknown = ! DisplayAudioDescriptor(\r\n                    (PUSB_AUDIO_COMMON_DESCRIPTOR)commonDesc,\r\n                    bInterfaceSubClass);\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_VIDEO:\r\n                displayUnknown = ! DisplayVideoDescriptor(\r\n                    (PVIDEO_SPECIFIC)commonDesc,\r\n                    bInterfaceSubClass,\r\n                    StringDescs,\r\n                    info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_RESERVED:\r\n                //@@TestCase A2.6\r\n                //@@ERROR\r\n                //@@Descriptor Field - bInterfaceClass\r\n                //@@An unknown interface class has been defined\r\n                AppendTextBuffer(\"*!*ERROR:  %d is a Reserved USB Device Interface Class\\r\\n\",\r\n                    USB_DEVICE_CLASS_RESERVED);\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_COMMUNICATIONS:\r\n                AppendTextBuffer(\"  -> This is a Communications (CDC Control) USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_HUMAN_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is a HID USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_MONITOR:\r\n                AppendTextBuffer(\"  -> This is a Monitor USB Device Interface Class (This may be obsolete)\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is a Physical Interface USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_POWER:\r\n                if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1)\r\n                {\r\n                    AppendTextBuffer(\"  -> This is an Image USB Device Interface Class\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\"  -> This is a Power USB Device Interface Class (This may be obsolete)\\r\\n\");\r\n                }\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_PRINTER:\r\n                AppendTextBuffer(\"  -> This is a Printer USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_STORAGE:\r\n                AppendTextBuffer(\"  -> This is a Mass Storage USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DEVICE_CLASS_HUB:\r\n                AppendTextBuffer(\"  -> This is a HUB USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_CDC_DATA_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is a CDC Data USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_CHIP_SMART_CARD_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is a Chip/Smart Card USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_CONTENT_SECURITY_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is a Content Security USB Device Interface Class\\r\\n\");\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_DIAGNOSTIC_DEVICE_INTERFACE:\r\n                if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1)\r\n                {\r\n                    AppendTextBuffer(\"  -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    //@@TestCase A2.7\r\n                    //@@CAUTION\r\n                    //@@Descriptor Field - bInterfaceClass\r\n                    //@@An unknown diagnostic interface class device has been defined\r\n                    AppendTextBuffer(\"*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n                    OOPS();\r\n                }\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_WIRELESS_CONTROLLER_INTERFACE:\r\n                if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1)\r\n                {\r\n                    AppendTextBuffer(\"  -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    //@@TestCase A2.8\r\n                    //@@CAUTION\r\n                    //@@Descriptor Field - bInterfaceClass\r\n                    //@@An unknown wireless controller interface class device has been defined\r\n                    AppendTextBuffer(\"*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n                    OOPS();\r\n                }\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            case USB_APPLICATION_SPECIFIC_INTERFACE:\r\n                AppendTextBuffer(\"  -> This is an Application Specific USB Device Interface Class\\r\\n\");\r\n\r\n                switch(bInterfaceSubClass)\r\n                {\r\n                case 1:\r\n                    AppendTextBuffer(\"  -> This is a Device Firmware Application Specific USB Device Interface Class\\r\\n\");\r\n                    break;\r\n                case 2:\r\n                    AppendTextBuffer(\"  -> This is an IrDA Bridge Application Specific USB Device Interface Class\\r\\n\");\r\n                    break;\r\n                case 3:\r\n                    AppendTextBuffer(\"  -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\\r\\n\");\r\n                    break;\r\n                default:\r\n                    //@@TestCase A2.9\r\n                    //@@CAUTION\r\n                    //@@Descriptor Field - bInterfaceClass\r\n                    //@@A possibly invalid interface class has been defined\r\n                    AppendTextBuffer(\"*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n                    OOPS();\r\n                }\r\n                displayUnknown = TRUE;\r\n                break;\r\n\r\n            default:\r\n                if (bInterfaceClass == USB_DEVICE_CLASS_VENDOR_SPECIFIC)\r\n                {\r\n                    AppendTextBuffer(\"  -> This is a Vendor Specific USB Device Interface Class\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    //@@TestCase A2.10\r\n                    //@@CAUTION\r\n                    //@@Descriptor Field - bInterfaceClass\r\n                    //@@An unknown interface class has been defined\r\n                    AppendTextBuffer(\"*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n                    OOPS();\r\n                }\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            break;\r\n        }\r\n\r\n        if (displayUnknown)\r\n        {\r\n            DisplayUnknownDescriptor(commonDesc);\r\n        }\r\n    } while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc,\r\n                                             ConfigDesc->wTotalLength,\r\n                                             commonDesc,\r\n                                             -1)) != NULL);\r\n\r\n#ifdef H264_SUPPORT\r\n    DoAdditionalErrorChecks();\r\n#endif\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayDeviceQualifierDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayDeviceQualifierDescriptor (\r\n    PUSB_DEVICE_QUALIFIER_DESCRIPTOR   DevQualDesc\r\n    )\r\n{\r\n    //@@DisplayDeviceQualifierDescriptor - Device Qualifier Descriptor\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Device Qualifier Descriptor<===\\r\\n\");\r\n\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        DevQualDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        DevQualDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bcdUSB:                          0x%04X\\r\\n\",\r\n        DevQualDesc->bcdUSB);\r\n\r\n    AppendTextBuffer(\"bDeviceClass:                      0x%02X\",\r\n        DevQualDesc->bDeviceClass);\r\n\r\n    switch (DevQualDesc->bDeviceClass)\r\n    {\r\n    case USB_INTERFACE_CLASS_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is an Interface Class Defined Device\\r\\n\");\r\n        }\r\n        break;\r\n\r\n    case USB_COMMUNICATION_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Communication Device\\r\\n\");\r\n        }\r\n        break;\r\n\r\n    case USB_HUB_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a HUB Device\\r\\n\");\r\n        }\r\n        break;\r\n\r\n    case USB_DIAGNOSTIC_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Diagnostic Device\\r\\n\");\r\n        }\r\n        break;\r\n\r\n    case USB_WIRELESS_CONTROLLER_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Wireless Controller(Bluetooth) Device\\r\\n\");\r\n        }\r\n        break;\r\n\r\n    case USB_VENDOR_SPECIFIC_DEVICE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Vendor Specific Device\\r\\n\");\r\n        }\r\n        break;\r\n    case USB_DEVICE_CLASS_BILLBOARD:\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a billboard class device\\r\\n\");\r\n        }\r\n        break;\r\n    default:\r\n        //@@TestCase A3.1\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDeviceClass\r\n        //@@An unknown device class has been defined\r\n        AppendTextBuffer(\"*!*ERROR:  bDeviceClass of %d is invalid\\r\\n\",\r\n            DevQualDesc->bDeviceClass);\r\n        OOPS();\r\n        break;\r\n    }\r\n\r\n    AppendTextBuffer(\"bDeviceSubClass:                   0x%02X\\r\\n\",\r\n        DevQualDesc->bDeviceSubClass);\r\n\r\n    if(DevQualDesc->bDeviceSubClass > 0x00 && DevQualDesc->bDeviceSubClass < 0xFF)\r\n    {\r\n        //@@TestCase A3.2\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDeviceSubClass\r\n        //@@An unknown device sub class has been defined\r\n        AppendTextBuffer(\"*!*ERROR:  bDeviceSubClass of %d is invalid\\r\\n\",\r\n            DevQualDesc->bDeviceSubClass);\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bDeviceProtocol:                   0x%02X\\r\\n\",\r\n        DevQualDesc->bDeviceProtocol);\r\n\r\n    if(DevQualDesc->bDeviceProtocol > 0x00 && DevQualDesc->bDeviceProtocol < 0xFF)\r\n    {\r\n        //@@TestCase A3.4\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDeviceProtocol\r\n        //@@An invalid device protocol has been defined\r\n        AppendTextBuffer(\"*!*ERROR:  bDeviceProtocol of %d is invalid\",\r\n            DevQualDesc->bDeviceProtocol);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase A3.5\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bcdDevice\r\n    //@@We should test to verify a valid bMaxPacketSize0 based on speed\r\n    AppendTextBuffer(\"bMaxPacketSize0:                   0x%02X\",\r\n        DevQualDesc->bMaxPacketSize0);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\" = (%d) Bytes\\r\\n\",\r\n            DevQualDesc->bMaxPacketSize0);\r\n    }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    AppendTextBuffer(\"bNumConfigurations:                0x%02X\\r\\n\",\r\n        DevQualDesc->bNumConfigurations);\r\n\r\n    if(DevQualDesc->bNumConfigurations != 1)\r\n    {\r\n        //@@TestCase A3.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - bNumConfigurations\r\n        //@@Most host controllers do not handle more than one configuration\r\n        AppendTextBuffer(\"*!*CAUTION:    Most host controllers will only work with one configuration per speed\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bReserved:                         0x%02X\\r\\n\",\r\n        DevQualDesc->bReserved);\r\n\r\n    if(DevQualDesc->bReserved != 0)\r\n    {\r\n        AppendTextBuffer(\"*!*WARNING:    bReserved needs to be set to 0 to be valid\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n\r\n}\r\n\r\nVOID\r\nDisplayUsb20ExtensionCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR extCapDesc\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>USB 2.0 Extension Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        extCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        extCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        extCapDesc->bDevCapabilityType);\r\n    AppendTextBuffer(\"bmAttributes:                      0x%08X\",\r\n        extCapDesc->bmAttributes);\r\n    if (extCapDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: bits 31..2 and bit 0 are reserved and must be 0\\r\\n\");\r\n        }\r\n    }\r\n    if (extCapDesc->bmAttributes.LPMCapable == 1)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Supports Link Power Management protocol\\r\\n\");\r\n        }\r\n    }\r\n    if (extCapDesc->bmAttributes.AsUlong == 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\nVOID\r\nDisplaySuperSpeedCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR ssCapDesc\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>SuperSpeed USB Device Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        ssCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        ssCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        ssCapDesc->bDevCapabilityType);\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\\r\\n\",\r\n        ssCapDesc->bmAttributes);\r\n    if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: bits 7:2 and bit 0 are reserved\\r\\n\");\r\n        }\r\n    }\r\n    if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> capable of generating Latency Tolerance Messages\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"wSpeedsSupported:                  0x%02X\\r\\n\",\r\n        ssCapDesc->wSpeedsSupported);\r\n\r\n    if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Supports low-speed operation\\r\\n\");\r\n        }\r\n    }\r\n    if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Supports full-speed operation\\r\\n\");\r\n        }\r\n    }\r\n    if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Supports high-speed operation\\r\\n\");\r\n        }\r\n    }\r\n    if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Supports SuperSpeed operation\\r\\n\");\r\n        }\r\n    }\r\n    if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: bits 15:4 are reserved\\r\\n\");\r\n        }\r\n    }\r\n    if (!gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n    AppendTextBuffer(\"bFunctionalitySupport:             0x%02X\",\r\n        ssCapDesc->bFunctionalitySupport);\r\n    if(gDoAnnotation)\r\n    {\r\n        switch (ssCapDesc->bFunctionalitySupport)\r\n        {\r\n        case UsbLowSpeed:\r\n            AppendTextBuffer(\" -> lowest speed = low-speed\\r\\n\");\r\n            break;\r\n        case UsbFullSpeed:\r\n            AppendTextBuffer(\" -> lowest speed = full-speed\\r\\n\");\r\n            break;\r\n        case UsbHighSpeed:\r\n            AppendTextBuffer(\" -> lowest speed = high-speed\\r\\n\");\r\n            break;\r\n        case UsbSuperSpeed:\r\n            AppendTextBuffer(\" -> lowest speed = SuperSpeed\\r\\n\");\r\n            break;\r\n        default:\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid value\\r\\n\");\r\n            break;\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"bU1DevExitLat:                     0x%02X\",\r\n        ssCapDesc->bU1DevExitLat);\r\n    if(gDoAnnotation)\r\n    {\r\n        if (ssCapDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE)\r\n        {\r\n            AppendTextBuffer(\" -> less than %d micro-seconds\\r\\n\",\r\n                ssCapDesc->bU1DevExitLat);\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid value\\r\\n\");\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"wU2DevExitLat:                     0x%04X\",\r\n        ssCapDesc->wU2DevExitLat);\r\n    if(gDoAnnotation)\r\n    {\r\n        if (ssCapDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE)\r\n        {\r\n            AppendTextBuffer(\" -> less than %d micro-seconds\\r\\n\",\r\n                ssCapDesc->wU2DevExitLat);\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid value\\r\\n\");\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\n\r\nVOID\r\nDisplaySuperSpeedPlusCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR sspCapDesc\r\n    )\r\n{\r\n    UCHAR i;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>SuperSpeed USB Device Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        sspCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        sspCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        sspCapDesc->bDevCapabilityType);\r\n    AppendTextBuffer(\"bReserved:                         0x%02X\\r\\n\",\r\n        sspCapDesc->bReserved);\r\n    if (sspCapDesc->bReserved != 0)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"bmAttributes:                      0x%08X\\r\\n\",\r\n        sspCapDesc->bmAttributes.AsUlong);\r\n    AppendTextBuffer(\"  SublinkSpeedAttrCount:           0x%02X\\r\\n\",\r\n        sspCapDesc->bmAttributes.SublinkSpeedAttrCount);\r\n    AppendTextBuffer(\"  SublinkSpeedIDCount:             0x%02X\\r\\n\",\r\n        sspCapDesc->bmAttributes.SublinkSpeedIDCount);\r\n\r\n    AppendTextBuffer(\"wFunctionalitySupport:             0x%04X\\r\\n\",\r\n        sspCapDesc->wFunctionalitySupport.AsUshort);\r\n    AppendTextBuffer(\"  SublinkSpeedAttrID:              0x%02X\\r\\n\",\r\n        sspCapDesc->wFunctionalitySupport.SublinkSpeedAttrID);\r\n    AppendTextBuffer(\"  Reserved:                        0x%02X\\r\\n\",\r\n        sspCapDesc->wFunctionalitySupport.Reserved);\r\n    if (sspCapDesc->wFunctionalitySupport.Reserved != 0)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"  MinRxLaneCount:                  0x%02X\\r\\n\",\r\n        sspCapDesc->wFunctionalitySupport.MinRxLaneCount);\r\n    AppendTextBuffer(\"  MinTxLaneCount:                  0x%02X\\r\\n\",\r\n        sspCapDesc->wFunctionalitySupport.MinTxLaneCount);\r\n\r\n    AppendTextBuffer(\"wReserved:                         0x%04X\\r\\n\",\r\n        sspCapDesc->wReserved);\r\n    if (sspCapDesc->wReserved != 0)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n\r\n    // The array size = SublinkSpeedAttrCount + 1\r\n    for (i = 0; i <= sspCapDesc->bmAttributes.SublinkSpeedAttrCount; i++)\r\n    {\r\n        PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED speed = &sspCapDesc->bmSublinkSpeedAttr[i];\r\n\r\n        AppendTextBuffer(\"bmSublinkSpeedAttr #:              0x%02X\\r\\n\",\r\n            i);\r\n        AppendTextBuffer(\"  SublinkSpeedAttrID:              0x%02X\\r\\n\",\r\n            speed->SublinkSpeedAttrID);\r\n        AppendTextBuffer(\"  LaneSpeedExponent:               0x%02X\",\r\n            speed->LaneSpeedExponent);\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (speed->LaneSpeedExponent)\r\n            {\r\n            case 0:\r\n                AppendTextBuffer(\" -> Bits per second\\r\\n\");\r\n                break;\r\n            case 1:\r\n                AppendTextBuffer(\" -> Kb/s\\r\\n\");\r\n                break;\r\n            case 2:\r\n                AppendTextBuffer(\" -> Mb/s\\r\\n\");\r\n                break;\r\n            case 3:\r\n                AppendTextBuffer(\" -> Gb/s\\r\\n\");\r\n                break;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"  SublinkTypeMode:                 0x%02X\",\r\n            speed->SublinkTypeMode);\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (speed->SublinkTypeMode)\r\n            {\r\n            case 0:\r\n                AppendTextBuffer(\" -> Symmetric\\r\\n\");\r\n                break;\r\n            case 1:\r\n                AppendTextBuffer(\" -> Asymmetric\\r\\n\");\r\n                break;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"  SublinkTypeDir:                  0x%02X\",\r\n            speed->SublinkTypeDir);\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (speed->SublinkTypeDir)\r\n            {\r\n            case 0:\r\n                AppendTextBuffer(\" -> Receive mode\\r\\n\");\r\n                break;\r\n            case 1:\r\n                AppendTextBuffer(\" -> Transmit mode\\r\\n\");\r\n                break;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"  Reserved:                        0x%02X\\r\\n\",\r\n            speed->Reserved);\r\n        AppendTextBuffer(\"  LinkProtocol:                    0x%02X\",\r\n            speed->LinkProtocol);\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (speed->LinkProtocol)\r\n            {\r\n            case 0:\r\n                AppendTextBuffer(\" -> SuperSpeed\\r\\n\");\r\n                break;\r\n            case 1:\r\n                AppendTextBuffer(\" -> SuperSpeedPlus\\r\\n\");\r\n                break;\r\n            default:\r\n                AppendTextBuffer(\" -> Reserved\\r\\n\");\r\n                break;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"  LaneSpeedMantissa:               0x%04X\\r\\n\",\r\n            speed->LaneSpeedMantissa);\r\n    }\r\n}\r\n\r\n\r\nVOID\r\nDisplayPlatformCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR platformCapDesc\r\n    )\r\n{\r\n    LPGUID pGuid;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Platform Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        platformCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        platformCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        platformCapDesc->bDevCapabilityType);\r\n\r\n    AppendTextBuffer(\"bReserved:                         0x%02X\\r\\n\",\r\n        platformCapDesc->bReserved);\r\n    if (platformCapDesc->bReserved != 0)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n\r\n    pGuid = (LPGUID)&platformCapDesc->PlatformCapabilityUuid;\r\n    AppendTextBuffer(\"Platform Capability UUID:          \");\r\n    AppendTextBuffer(\"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\\r\\n\",\r\n        pGuid->Data1,\r\n        pGuid->Data2,\r\n        pGuid->Data3,\r\n        pGuid->Data4[0],\r\n        pGuid->Data4[1],\r\n        pGuid->Data4[2],\r\n        pGuid->Data4[3],\r\n        pGuid->Data4[4],\r\n        pGuid->Data4[5],\r\n        pGuid->Data4[6],\r\n        pGuid->Data4[7]);\r\n\r\n    DisplayRemainingUnknownDescriptor((PUCHAR)platformCapDesc,\r\n                                        (ULONG)offsetof(USB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR, CapabililityData),\r\n                                        platformCapDesc->bLength);\r\n}\r\n\r\n\r\nVOID\r\nDisplayContainerIdCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR containerIdCapDesc\r\n    )\r\n{\r\n    LPGUID pGuid;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Container ID Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        containerIdCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        containerIdCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        containerIdCapDesc->bDevCapabilityType);\r\n    AppendTextBuffer(\"bReserved:                         0x%02X\\r\\n\",\r\n        containerIdCapDesc->bReserved);\r\n    if (containerIdCapDesc->bReserved != 0)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n\r\n    pGuid = (LPGUID)containerIdCapDesc->ContainerID;\r\n    AppendTextBuffer(\"Container ID:                      \");\r\n    AppendTextBuffer(\"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\\r\\n\",\r\n        pGuid->Data1,\r\n        pGuid->Data2,\r\n        pGuid->Data3,\r\n        pGuid->Data4[0],\r\n        pGuid->Data4[1],\r\n        pGuid->Data4[2],\r\n        pGuid->Data4[3],\r\n        pGuid->Data4[4],\r\n        pGuid->Data4[5],\r\n        pGuid->Data4[6],\r\n        pGuid->Data4[7]);\r\n}\r\n\r\nVOID\r\nDisplayBillboardCapabilityDescriptor (\r\n    PUSBDEVICEINFO info,\r\n    PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs\r\n    )\r\n{\r\n    UCHAR i = 0;\r\n    UCHAR bNumAlternateModes = 0;\r\n    UCHAR alternateModeConfiguration = 0;\r\n    UCHAR adjustedBLength = 0;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Billboard Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\",\r\n        billboardCapDesc->bLength);\r\n\r\n    adjustedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) +\r\n        sizeof(billboardCapDesc->AlternateMode[0]) * (billboardCapDesc->bNumberOfAlternateModes - 1);\r\n    AppendTextBuffer(\"  -> Actual Length: 0x%02X\\r\\n\", adjustedBLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        billboardCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X  -> Billboard capability\\r\\n\",\r\n        billboardCapDesc->bDevCapabilityType);\r\n    AppendTextBuffer(\"iAdditionalInfoURL:                0x%02X  ->\",\r\n        billboardCapDesc->iAddtionalInfoURL);\r\n    if (billboardCapDesc->iAddtionalInfoURL && gDoAnnotation) {\r\n        DisplayStringDescriptor(billboardCapDesc->iAddtionalInfoURL,\r\n            StringDescs,\r\n            info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified);\r\n    }\r\n    AppendTextBuffer(\"bNumberOfAlternateModes:           0x%02X\\r\\n\",\r\n        billboardCapDesc->bNumberOfAlternateModes);\r\n\r\n    if (billboardCapDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: Invalid bNumberofAlternateModes\\r\\n\");\r\n    }\r\n    AppendTextBuffer(\"bPreferredAlternateMode:           0x%02X\\r\\n\",\r\n        billboardCapDesc->bPreferredAlternateMode);\r\n\r\n    AppendTextBuffer(\"VCONN Power:                       0x%04X\",\r\n        billboardCapDesc->VconnPower);\r\n\r\n    if (billboardCapDesc->VconnPower.NoVconnPowerRequired)\r\n    {\r\n        AppendTextBuffer(\"  -> The adapter does not require Vconn Power. Bits 2..0 ignored\\r\\n\");\r\n    }\r\n    else\r\n    {\r\n        switch (billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality)\r\n        {\r\n        case 0:\r\n            AppendTextBuffer(\"  -> 1W needed by adapter for full functionality\\r\\n\");\r\n            break;\r\n        case 1:\r\n            AppendTextBuffer(\"  -> 1.5W needed by adapter for full functionality\\r\\n\");\r\n            break;\r\n        case 7:\r\n            AppendTextBuffer(\"  -> *!*ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used\\r\\n\");\r\n            break;\r\n        default:\r\n            AppendTextBuffer(\"  -> %2XW needed by adapter for full functionality\\r\\n\", billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality);\r\n        }\r\n    }\r\n\r\n    if (billboardCapDesc->VconnPower.Reserved)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: Reserved bits in VCONN Power being used\\r\\n\");\r\n    }\r\n    if (billboardCapDesc->bReserved)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: bReserved being used\\r\\n\");\r\n    }\r\n\r\n\r\n    bNumAlternateModes = billboardCapDesc->bNumberOfAlternateModes;\r\n    if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE)\r\n    {\r\n        bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE;\r\n    }\r\n    if (bNumAlternateModes > 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\nAlternate Modes Identified:\\r\\n\");\r\n    }\r\n    for (i = 0; i < bNumAlternateModes; i++)\r\n    {\r\n        alternateModeConfiguration = ((billboardCapDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3;\r\n        AppendTextBuffer(\"wSVID - 0x%04X  bAlternateMode - 0x%02X   ->\",\r\n            billboardCapDesc->AlternateMode[i].wSVID,\r\n            billboardCapDesc->AlternateMode[i].bAlternateMode,\r\n            billboardCapDesc->AlternateMode[i].iAlternateModeSetting);\r\n\r\n        switch (alternateModeConfiguration)\r\n        {\r\n        case 0:\r\n            AppendTextBuffer(\"Unspecified Error\\r\\n\");\r\n            break;\r\n        case 1:\r\n            AppendTextBuffer(\"Alternate Mode configuration not attempted\\r\\n\");\r\n            break;\r\n        case 2:\r\n            AppendTextBuffer(\"Alternate Mode configuration attempted but unsuccessful\\r\\n\");\r\n            break;\r\n        case 3:\r\n            AppendTextBuffer(\"Alternate Mode configuration successful\\r\\n\");\r\n            break;\r\n        }\r\n        AppendTextBuffer(\"iAlternateModeString - 0x%02X  \", billboardCapDesc->AlternateMode[i].iAlternateModeSetting);\r\n        if (billboardCapDesc->AlternateMode[i].iAlternateModeSetting && gDoAnnotation)\r\n        {\r\n            DisplayStringDescriptor(billboardCapDesc->AlternateMode[i].iAlternateModeSetting,\r\n                StringDescs,\r\n                info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified);\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\n\r\n#ifdef USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY\r\n\r\nVOID\r\nDisplayConfigurationSummaryCapabilityDescriptor (\r\n    PUSB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR configSummaryCapDesc\r\n    )\r\n{\r\n    UCHAR i;\r\n    AppendTextBuffer(\"\\r\\n          ===>Configuration Summary Capability Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bDevCapabilityType);\r\n\r\n    AppendTextBuffer(\"bcdVersion:                        0x%04X\\r\\n\",\r\n        configSummaryCapDesc->bcdVersion);\r\n    AppendTextBuffer(\"bConfigurationValue:               0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bConfigurationValue);\r\n    AppendTextBuffer(\"bMaxPower:                         0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bMaxPower);\r\n    AppendTextBuffer(\"bNumFunctions:                     0x%02X\\r\\n\",\r\n        configSummaryCapDesc->bNumFunctions);\r\n\r\n    for (i = 0; i < configSummaryCapDesc->bNumFunctions; i++)\r\n    {\r\n        AppendTextBuffer(\"Function #:                        0x%02X\\r\\n\",\r\n            i);\r\n        AppendTextBuffer(\"  bClass:                          0x%02X\\r\\n\",\r\n            configSummaryCapDesc->Function[i].bClass);\r\n        AppendTextBuffer(\"  bSubClass:                       0x%02X\\r\\n\",\r\n            configSummaryCapDesc->Function[i].bSubClass);\r\n        AppendTextBuffer(\"  bProtocol:                       0x%02X\\r\\n\",\r\n            configSummaryCapDesc->Function[i].bProtocol);\r\n    }\r\n}\r\n\r\n#endif\r\n\r\n/*****************************************************************************\r\n\r\nDisplayBosDescriptor()\r\n\r\nBosDesc - The Binary Object Store (BOS) Descriptor, and associated Descriptors\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayBosDescriptor (\r\n    PUSBDEVICEINFO          info,\r\n    PUSB_BOS_DESCRIPTOR     BosDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs\r\n    )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR            commonDesc = NULL;\r\n    PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>BOS Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        BosDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        BosDesc->bDescriptorType);\r\n    AppendTextBuffer(\"wTotalLength:                      0x%04X\\r\\n\",\r\n        BosDesc->wTotalLength);\r\n    AppendTextBuffer(\"bNumDeviceCaps:                    0x%02X\\r\\n\",\r\n        BosDesc->bNumDeviceCaps);\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)BosDesc;\r\n\r\n    while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)BosDesc,\r\n                                          BosDesc->wTotalLength,\r\n                                          commonDesc,\r\n                                          -1)) != NULL)\r\n    {\r\n        switch (commonDesc->bDescriptorType)\r\n        {\r\n        case USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE:\r\n\r\n            capDesc = (PUSB_DEVICE_CAPABILITY_DESCRIPTOR)commonDesc;\r\n\r\n            switch (capDesc->bDevCapabilityType)\r\n            {\r\n            case USB_DEVICE_CAPABILITY_USB20_EXTENSION:\r\n                DisplayUsb20ExtensionCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc);\r\n                break;\r\n            case USB_DEVICE_CAPABILITY_SUPERSPEED_USB:\r\n                DisplaySuperSpeedCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc);\r\n                break;\r\n            case USB_DEVICE_CAPABILITY_CONTAINER_ID:\r\n                DisplayContainerIdCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc);\r\n                break;\r\n            case USB_DEVICE_CAPABILITY_PLATFORM:\r\n                DisplayPlatformCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR)capDesc);\r\n                break;\r\n            case USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB:\r\n                DisplaySuperSpeedPlusCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR)capDesc);\r\n                break;\r\n            case USB_DEVICE_CAPABILITY_BILLBOARD:\r\n                DisplayBillboardCapabilityDescriptor((PUSBDEVICEINFO) info, (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc, StringDescs);\r\n                break;\r\n#ifdef USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY\r\n            case USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY:\r\n                DisplayConfigurationSummaryCapabilityDescriptor((PUSB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR)capDesc);\r\n                break;\r\n#endif\r\n            default:\r\n                AppendTextBuffer(\"\\r\\n          ===>Unknown Capability Descriptor<===\\r\\n\");\r\n\r\n                AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n                    capDesc->bLength);\r\n                AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                    capDesc->bDescriptorType);\r\n                AppendTextBuffer(\"bDevCapabilityType:                0x%02X\\r\\n\",\r\n                    capDesc->bDevCapabilityType);\r\n\r\n                DisplayRemainingUnknownDescriptor((PUCHAR)commonDesc,\r\n                                                  (ULONG)sizeof(USB_DEVICE_CAPABILITY_DESCRIPTOR),\r\n                                                  commonDesc->bLength);\r\n                break;\r\n            }\r\n            break;\r\n\r\n        default:\r\n            DisplayUnknownDescriptor(commonDesc);\r\n            break;\r\n        }\r\n    }\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayConfigurationDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayConfigurationDescriptor (\r\n    PUSBDEVICEINFO                  info,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,\r\n    PSTRING_DESCRIPTOR_NODE         StringDescs\r\n    )\r\n{\r\n    UINT    uCount = 0;\r\n    BOOL    isSS;\r\n\r\n\r\n    isSS = info->ConnectionInfoV2\r\n           && (info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher ||\r\n               info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)\r\n           ? TRUE\r\n           : FALSE;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Configuration Descriptor<===\\r\\n\");\r\n    //@@DisplayConfigurationDescriptor - Configuration Descriptor\r\n\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        ConfigDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        ConfigDesc->bDescriptorType);\r\n\r\n    //@@TestCase A4.1\r\n    //@@Priority 1\r\n    //@@Descriptor Field - wTotalLength\r\n    //@@Verify Configuration length is valid\r\n    AppendTextBuffer(\"wTotalLength:                    0x%04X\",\r\n        ConfigDesc->wTotalLength);\r\n    uCount = GetConfigurationSize(info);\r\n    if (uCount != ConfigDesc->wTotalLength) {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid total configuration size 0x%02X, should be 0x%02X\\r\\n\",\r\n            ConfigDesc->wTotalLength, uCount);\r\n    } else {\r\n        AppendTextBuffer(\"  -> Validated\\r\\n\");\r\n    }\r\n\r\n    //@@TestCase A4.2\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bNumInterfaces\r\n    //@@Verify the number of interfaces is valid\r\n    AppendTextBuffer(\"bNumInterfaces:                    0x%02X\\r\\n\",\r\n        ConfigDesc->bNumInterfaces);\r\n\r\n/* Need to check spec vs composite devices\r\n    uCount = GetInterfaceCount(info);\r\n    if (uCount != ConfigDesc->bNumInterfaces) {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid total Interfaces %d, should be %d\\r\\n\",\r\n            ConfigDesc->bNumInterfaces, uCount);\r\n    } else {\r\n        AppendTextBuffer(\"  -> Validated\\r\\n\");\r\n    }\r\n*/\r\n\r\n    AppendTextBuffer(\"bConfigurationValue:               0x%02X\\r\\n\",\r\n        ConfigDesc->bConfigurationValue);\r\n\r\n    if(ConfigDesc->bConfigurationValue != 1)\r\n    {\r\n        //@@TestCase A4.3\r\n        //@@CAUTION\r\n        //@@Descriptor Field - bConfigurationValue\r\n        //@@Most host controllers do not handle more than one configuration\r\n        AppendTextBuffer(\"*!*CAUTION:    Most host controllers will only work with one configuration per speed\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"iConfiguration:                    0x%02X\\r\\n\",\r\n        ConfigDesc->iConfiguration);\r\n\r\n    if (ConfigDesc->iConfiguration && gDoAnnotation)\r\n    {\r\n        DisplayStringDescriptor(ConfigDesc->iConfiguration,\r\n            StringDescs,\r\n            info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified);\r\n    }\r\n\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\",\r\n        ConfigDesc->bmAttributes);\r\n\r\n    if (info->ConnectionInfo->DeviceDescriptor.bcdUSB == 0x0100)\r\n    {\r\n        if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED)\r\n        {\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Self Powered\\r\\n\");\r\n            }\r\n        }\r\n        if (ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED)\r\n        {\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Bus Powered\\r\\n\");\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED)\r\n        {\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Self Powered\\r\\n\");\r\n            }\r\n        }\r\n        else\r\n        {\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Bus Powered\\r\\n\");\r\n            }\r\n        }\r\n        if ((ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED) == 0)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:    Bit 7 is reserved and must be set\\r\\n\");\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    if (ConfigDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP)\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Remote Wakeup\\r\\n\");\r\n        }\r\n    }\r\n\r\n    if (ConfigDesc->bmAttributes & USB_CONFIG_RESERVED)\r\n    {\r\n        //@@TestCase A4.4\r\n        //@@WARNING\r\n        //@@Descriptor Field - bmAttributes\r\n        //@@A bit has been set in reserved space\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:    Bits 4...0 are reserved\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"MaxPower:                          0x%02X\",\r\n        ConfigDesc->MaxPower);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\" = %3d mA\\r\\n\",\r\n            isSS ? ConfigDesc->MaxPower * 8 : ConfigDesc->MaxPower * 2);\r\n    }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayInterfaceDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayInterfaceDescriptor (\r\n    PUSB_INTERFACE_DESCRIPTOR   InterfaceDesc,\r\n    PSTRING_DESCRIPTOR_NODE     StringDescs,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayInterfaceDescriptor - Interface Descriptor\r\n    AppendTextBuffer(\"\\r\\n          ===>Interface Descriptor<===\\r\\n\");\r\n\r\n    //length checked in DisplayConfigDesc()\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        InterfaceDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        InterfaceDesc->bDescriptorType);\r\n\r\n    //@@TestCase A5.1\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bInterfaceNumber\r\n    //@@Question - Should we test to verify bInterfaceNumber is valid?\r\n    AppendTextBuffer(\"bInterfaceNumber:                  0x%02X\\r\\n\",\r\n        InterfaceDesc->bInterfaceNumber);\r\n\r\n    //@@TestCase A5.2\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bAlternateSetting\r\n    //@@Question - Should we test to verify bAlternateSetting is valid?\r\n    AppendTextBuffer(\"bAlternateSetting:                 0x%02X\\r\\n\",\r\n        InterfaceDesc->bAlternateSetting);\r\n\r\n    //@@TestCase A5.3\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bNumEndpoints\r\n    //@@Question - Should we test to verify bNumEndpoints is valid?\r\n    AppendTextBuffer(\"bNumEndpoints:                     0x%02X\\r\\n\",\r\n        InterfaceDesc->bNumEndpoints);\r\n\r\n    AppendTextBuffer(\"bInterfaceClass:                   0x%02X\",\r\n        InterfaceDesc->bInterfaceClass);\r\n\r\n    switch (InterfaceDesc->bInterfaceClass)\r\n    {\r\n    case USB_DEVICE_CLASS_AUDIO:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Audio Interface Class\\r\\n\");\r\n        }\r\n\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (InterfaceDesc->bInterfaceSubClass)\r\n            {\r\n            case USB_AUDIO_SUBCLASS_AUDIOCONTROL:\r\n                AppendTextBuffer(\"  -> Audio Control Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:\r\n                AppendTextBuffer(\"  -> Audio Streaming Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            case USB_AUDIO_SUBCLASS_MIDISTREAMING:\r\n                AppendTextBuffer(\"  -> MIDI Streaming Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            default:\r\n                //@@TestCase A5.4\r\n                //@@CAUTION\r\n                //@@Descriptor Field - bInterfaceSubClass\r\n                //@@Invalid bInterfaceSubClass\r\n                AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid bInterfaceSubClass\\r\\n\");\r\n                OOPS();\r\n                break;\r\n            }\r\n        }\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_VIDEO:\r\n        if(gDoAnnotation)\r\n            AppendTextBuffer(\"  -> Video Interface Class\\r\\n\");\r\n\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n\r\n        switch(InterfaceDesc->bInterfaceSubClass)\r\n        {\r\n        case VIDEO_SUBCLASS_CONTROL:\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Video Control Interface SubClass\\r\\n\");\r\n            }\r\n            break;\r\n\r\n        case VIDEO_SUBCLASS_STREAMING:\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Video Streaming Interface SubClass\\r\\n\");\r\n            }\r\n            break;\r\n\r\n        default:\r\n            //@@TestCase A5.5\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bInterfaceSubClass\r\n            //@@Invalid bInterfaceSubClass\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid bInterfaceSubClass\\r\\n\");\r\n            OOPS();\r\n            break;\r\n        }\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_HUMAN_INTERFACE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> HID Interface Class\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_HUB:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> HUB Interface Class\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_RESERVED:\r\n        //@@TestCase A5.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - bInterfaceClass\r\n        //@@A reserved USB Device Interface Class has been defined\r\n        AppendTextBuffer(\"\\r\\n*!*CAUTION:  %d is a Reserved USB Device Interface Class\\r\\n\",\r\n            USB_DEVICE_CLASS_RESERVED);\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_COMMUNICATIONS:\r\n        AppendTextBuffer(\"  -> This is Communications (CDC Control) USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_MONITOR:\r\n        AppendTextBuffer(\"  -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Physical Interface USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_POWER:\r\n        if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is an Image USB Device Interface Class\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Power USB Device Interface Class (This may be obsolete)\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_PRINTER:\r\n        AppendTextBuffer(\"  -> This is a Printer USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_STORAGE:\r\n        AppendTextBuffer(\"  -> This is a Mass Storage USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_CDC_DATA_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a CDC Data USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_CHIP_SMART_CARD_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Chip/Smart Card USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_CONTENT_SECURITY_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Content Security USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_DIAGNOSTIC_DEVICE_INTERFACE:\r\n        if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A5.7\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bInterfaceClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_WIRELESS_CONTROLLER_INTERFACE:\r\n        if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A5.8\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bInterfaceClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n\r\n    case USB_APPLICATION_SPECIFIC_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is an Application Specific USB Device Interface Class\\r\\n\");\r\n\r\n        switch(InterfaceDesc->bInterfaceSubClass)\r\n        {\r\n        case 1:\r\n            AppendTextBuffer(\"  -> This is a Device Firmware Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        case 2:\r\n            AppendTextBuffer(\"  -> This is an IrDA Bridge Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        case 3:\r\n            AppendTextBuffer(\"  -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        default:\r\n            //@@TestCase A5.9\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bInterfaceClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n    case USB_DEVICE_CLASS_BILLBOARD:\r\n        AppendTextBuffer(\"  -> Billboard Class\\r\\n\");\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\", InterfaceDesc->bInterfaceSubClass);\r\n        switch (InterfaceDesc->bInterfaceSubClass)\r\n        {\r\n        case 0:\r\n            AppendTextBuffer(\"  -> Billboard Subclass\\r\\n\");\r\n            break;\r\n        default:\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid bInterfaceSubClass\\r\\n\");\r\n            break;\r\n        }\r\n        break;\r\n\r\n    default:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Interface Class Unknown to USBView\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bInterfaceSubClass:                0x%02X\\r\\n\",\r\n            InterfaceDesc->bInterfaceSubClass);\r\n        break;\r\n    }\r\n\r\n    AppendTextBuffer(\"bInterfaceProtocol:                0x%02X\\r\\n\",\r\n        InterfaceDesc->bInterfaceProtocol);\r\n\r\n    //This is basically the check for PC_PROTOCOL_UNDEFINED\r\n    if ((InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) ||\r\n        (InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO))\r\n    {\r\n        if(InterfaceDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED)\r\n        {\r\n            //@@TestCase A5.10\r\n            //@@WARNING\r\n            //@@Descriptor Field - iInterface\r\n            //@@bInterfaceProtocol must be set to PC_PROTOCOL_UNDEFINED\r\n            AppendTextBuffer(\"*!*WARNING:  must be set to PC_PROTOCOL_UNDEFINED %d for this class\\r\\n\",\r\n                PC_PROTOCOL_UNDEFINED);\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"iInterface:                        0x%02X\\r\\n\",\r\n        InterfaceDesc->iInterface);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        if (InterfaceDesc->iInterface)\r\n        {\r\n            DisplayStringDescriptor(InterfaceDesc->iInterface,\r\n                StringDescs,\r\n                LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    if (InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2))\r\n    {\r\n        PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2;\r\n\r\n        interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)InterfaceDesc;\r\n\r\n        AppendTextBuffer(\"wNumClasses:                     0x%04X\\r\\n\",\r\n            interfaceDesc2->wNumClasses);\r\n    }\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayEndpointDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayEndpointDescriptor (\r\n    _In_     PUSB_ENDPOINT_DESCRIPTOR\r\n                        EndpointDesc,\r\n    _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR\r\n                        EpCompDesc,\r\n    _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR\r\n                        SspIsochEpCompDesc,\r\n    _In_     UCHAR      InterfaceClass,\r\n    _In_     BOOLEAN    EpCompDescAvail\r\n    )\r\n{\r\n    UCHAR epType = EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;\r\n    PUSB_HIGH_SPEED_MAXPACKET hsMaxPacket;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Endpoint Descriptor<===\\r\\n\");\r\n    //@@DisplayEndpointDescriptor - Endpoint Descriptor\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        EndpointDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        EndpointDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bEndpointAddress:                  0x%02X\",\r\n        EndpointDesc->bEndpointAddress);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        if(USB_ENDPOINT_DIRECTION_OUT(EndpointDesc->bEndpointAddress))\r\n        {\r\n            AppendTextBuffer(\"  -> Direction: OUT - EndpointID: %d\\r\\n\",\r\n                (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK));\r\n        }\r\n        else if(USB_ENDPOINT_DIRECTION_IN(EndpointDesc->bEndpointAddress))\r\n        {\r\n            AppendTextBuffer(\"  -> Direction: IN - EndpointID: %d\\r\\n\",\r\n                (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK));\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A6.1\r\n            //@@ERROR\r\n            //@@Descriptor Field - bEndpointAddress\r\n            //@@An invalid endpoint addressl has been defined\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  This appears to be an invalid bEndpointAddress\\r\\n\");\r\n            OOPS();\r\n        }\r\n    }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\",\r\n        EndpointDesc->bmAttributes);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"  -> \");\r\n\r\n        switch (epType)\r\n        {\r\n        case USB_ENDPOINT_TYPE_CONTROL:\r\n            AppendTextBuffer(\"Control Transfer Type\\r\\n\");\r\n            if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_CONTROL_RESERVED_MASK)\r\n            {\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:     Bits 7..2 are reserved and must be set to 0\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n\r\n        case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n            AppendTextBuffer(\"Isochronous Transfer Type, Synchronization Type = \");\r\n\r\n            switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION(EndpointDesc->bmAttributes))\r\n            {\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_NO_SYNCHRONIZATION:\r\n                AppendTextBuffer(\"No Synchronization\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ASYNCHRONOUS:\r\n                AppendTextBuffer(\"Asynchronous\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ADAPTIVE:\r\n                AppendTextBuffer(\"Adaptive\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_SYNCHRONOUS:\r\n                AppendTextBuffer(\"Synchronous\");\r\n                break;\r\n            }\r\n            AppendTextBuffer(\", Usage Type = \");\r\n\r\n            switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE(EndpointDesc->bmAttributes))\r\n            {\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_DATA_ENDOINT:\r\n                AppendTextBuffer(\"Data Endpoint\\r\\n\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_FEEDBACK_ENDPOINT:\r\n                AppendTextBuffer(\"Feedback Endpoint\\r\\n\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_IMPLICIT_FEEDBACK_DATA_ENDPOINT:\r\n                AppendTextBuffer(\"Implicit Feedback Data Endpoint\\r\\n\");\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_RESERVED:\r\n                //@@TestCase A6.2\r\n                //@@ERROR\r\n                //@@Descriptor Field - bmAttributes\r\n                //@@A reserved bit has a value\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:     This value is Reserved\\r\\n\");\r\n                OOPS();\r\n                break;\r\n            }\r\n            if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_ISOCHRONOUS_RESERVED_MASK)\r\n            {\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:     Bits 7..6 are reserved and must be set to 0\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n\r\n        case USB_ENDPOINT_TYPE_BULK:\r\n            AppendTextBuffer(\"Bulk Transfer Type\\r\\n\");\r\n            if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_BULK_RESERVED_MASK)\r\n            {\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:     Bits 7..2 are reserved and must be set to 0\\r\\n\");\r\n                OOPS();\r\n            }\r\n            break;\r\n\r\n        case USB_ENDPOINT_TYPE_INTERRUPT:\r\n\r\n            if (gDeviceSpeed != UsbSuperSpeed)\r\n            {\r\n                AppendTextBuffer(\"Interrupt Transfer Type\\r\\n\");\r\n                if (EndpointDesc->bmAttributes & USB_20_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK)\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n*!*ERROR:     Bits 7..2 are reserved and must be set to 0\\r\\n\");\r\n                    OOPS();\r\n                }\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"Interrupt Transfer Type, Usage Type = \");\r\n\r\n                switch (USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE(EndpointDesc->bmAttributes))\r\n                {\r\n                case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_PERIODIC:\r\n                    AppendTextBuffer(\"Periodic\\r\\n\");\r\n                    break;\r\n\r\n                case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_NOTIFICATION:\r\n                    AppendTextBuffer(\"Notification\\r\\n\");\r\n                    break;\r\n\r\n                case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED10:\r\n                case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED11:\r\n                    AppendTextBuffer(\"\\r\\n*!*ERROR:     This value is Reserved\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                if (EndpointDesc->bmAttributes & USB_30_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK)\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n*!*ERROR:     Bits 7..6 and 3..2 are reserved and must be set to 0\\r\\n\");\r\n                    OOPS();\r\n                }\r\n\r\n                if (EpCompDescAvail)\r\n                {\r\n                    if (EpCompDesc == NULL)\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n*!*ERROR:     Endpoint Companion Descriptor missing\\r\\n\");\r\n                        OOPS();\r\n                    }\r\n                    else if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 &&\r\n                        SspIsochEpCompDesc == NULL)\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n*!*ERROR:     SuperSpeedPlus Isoch Endpoint Companion Descriptor missing\\r\\n\");\r\n                        OOPS();\r\n                    }\r\n                }\r\n            }\r\n            break;\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    //@@TestCase A6.3\r\n    //@@Priority 1\r\n    //@@Descriptor Field - bInterfaceNumber\r\n    //@@Question - Should we test to verify bInterfaceNumber is valid?\r\n    AppendTextBuffer(\"wMaxPacketSize:                  0x%04X\",\r\n        EndpointDesc->wMaxPacketSize);\r\n    if(gDoAnnotation)\r\n    {\r\n        switch (gDeviceSpeed)\r\n        {\r\n        case UsbSuperSpeed:\r\n            switch (epType)\r\n            {\r\n            case USB_ENDPOINT_TYPE_BULK:\r\n                if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE)\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n*!*ERROR:     SuperSpeed Bulk endpoints must be %d bytes\\r\\n\",\r\n                        USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE);\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n\");\r\n                }\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_CONTROL:\r\n                if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE)\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n*!*ERROR:     SuperSpeed Control endpoints must be %d bytes\\r\\n\",\r\n                        USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE);\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n\");\r\n                }\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n\r\n                if (EpCompDesc != NULL)\r\n                {\r\n                    if (EpCompDesc->bMaxBurst > 0)\r\n                    {\r\n                        if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE)\r\n                        {\r\n                            AppendTextBuffer(\"\\r\\n*!*ERROR:     SuperSpeed isochronous endpoints must have wMaxPacketSize value of %d bytes\\r\\n\",\r\n                                USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE);\r\n                            AppendTextBuffer(\"                  when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\\r\\n\");\r\n                        }\r\n                        else\r\n                        {\r\n                            AppendTextBuffer(\"\\r\\n\");\r\n                        }\r\n                    }\r\n                    else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE)\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n*!*ERROR:     Invalid SuperSpeed isochronous maximum packet size\\r\\n\");\r\n                    }\r\n                    else\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n\");\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n\");\r\n                }\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_INTERRUPT:\r\n\r\n                if (EpCompDesc != NULL)\r\n                {\r\n                    if (EpCompDesc->bMaxBurst > 0)\r\n                    {\r\n                        if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE)\r\n                        {\r\n                            AppendTextBuffer(\"\\r\\n*!*ERROR:     SuperSpeed interrupt endpoints must have wMaxPacketSize value of %d bytes\\r\\n\",\r\n                                USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE);\r\n                            AppendTextBuffer(\"                  when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\\r\\n\");\r\n                        }\r\n                        else\r\n                        {\r\n                            AppendTextBuffer(\"\\r\\n\");\r\n                        }\r\n                    }\r\n                    else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE)\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n*!*ERROR:     Invalid SuperSpeed interrupt maximum packet size\\r\\n\");\r\n                    }\r\n                    else\r\n                    {\r\n                        AppendTextBuffer(\"\\r\\n\");\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\"\\r\\n\");\r\n                }\r\n                break;\r\n            }\r\n            break;\r\n\r\n        case UsbHighSpeed:\r\n            hsMaxPacket = (PUSB_HIGH_SPEED_MAXPACKET)&EndpointDesc->wMaxPacketSize;\r\n\r\n            switch (epType)\r\n            {\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n            case USB_ENDPOINT_TYPE_INTERRUPT:\r\n                switch (hsMaxPacket->HSmux) {\r\n                case 0:\r\n                    if ((hsMaxPacket->MaxPacket < 1) || (hsMaxPacket->MaxPacket >1024))\r\n                    {\r\n                        AppendTextBuffer(\"*!*ERROR:  Invalid maximum packet size, should be between 1 and 1024\\r\\n\");\r\n                    }\r\n                    break;\r\n\r\n                case 1:\r\n                    if ((hsMaxPacket->MaxPacket < 513) || (hsMaxPacket->MaxPacket >1024))\r\n                    {\r\n                        AppendTextBuffer(\"*!*ERROR:  Invalid maximum packet size, should be between 513 and 1024\\r\\n\");\r\n                    }\r\n                    break;\r\n\r\n                case 2:\r\n                    if ((hsMaxPacket->MaxPacket < 683) || (hsMaxPacket->MaxPacket >1024))\r\n                    {\r\n                        AppendTextBuffer(\"*!*ERROR:  Invalid maximum packet size, should be between 683 and 1024\\r\\n\");\r\n                    }\r\n                    break;\r\n\r\n                case 3:\r\n                    AppendTextBuffer(\"*!*ERROR:  Bits 12-11 set to Reserved value in wMaxPacketSize\\r\\n\");\r\n                    break;\r\n                }\r\n\r\n                AppendTextBuffer(\" = %d transactions per microframe, 0x%02X max bytes\\r\\n\", hsMaxPacket->HSmux + 1, hsMaxPacket->MaxPacket);\r\n                break;\r\n\r\n            case USB_ENDPOINT_TYPE_BULK:\r\n            case USB_ENDPOINT_TYPE_CONTROL:\r\n                AppendTextBuffer(\" = 0x%02X max bytes\\r\\n\", hsMaxPacket->MaxPacket);\r\n                break;\r\n            }\r\n            break;\r\n\r\n        case UsbFullSpeed:\r\n            // full speed\r\n            AppendTextBuffer(\" = 0x%02X bytes\\r\\n\",\r\n                EndpointDesc->wMaxPacketSize & 0x7FF);\r\n            break;\r\n        default:\r\n            // low or invalid speed\r\n            if (InterfaceClass == USB_DEVICE_CLASS_VIDEO)\r\n            {\r\n                AppendTextBuffer(\" = Invalid bus speed for USB Video Class\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n            break;\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    if (EndpointDesc->wMaxPacketSize & 0xE000)\r\n    {\r\n        //@@TestCase A6.4\r\n        //@@Priority 1\r\n        //@@OTG Descriptor Field - wMaxPacketSize\r\n        //@@Attribute bits D7-2 reserved (reset to 0)\r\n        AppendTextBuffer(\"*!*ERROR:  wMaxPacketSize bits 15-13 should be 0\\r\\n\");\r\n    }\r\n\r\n    if (EndpointDesc->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR))\r\n    {\r\n        //@@TestCase A6.5\r\n        //@@Priority 1\r\n        //@@Descriptor Field - bInterfaceNumber\r\n        //@@Question - Should we test to verify bInterfaceNumber is valid?\r\n        AppendTextBuffer(\"bInterval:                         0x%02X\\r\\n\",\r\n            EndpointDesc->bInterval);\r\n    }\r\n    else\r\n    {\r\n        PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2;\r\n\r\n        endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2)EndpointDesc;\r\n\r\n        AppendTextBuffer(\"wInterval:                       0x%04X\\r\\n\",\r\n            endpointDesc2->wInterval);\r\n\r\n        AppendTextBuffer(\"bSyncAddress:                      0x%02X\\r\\n\",\r\n            endpointDesc2->bSyncAddress);\r\n    }\r\n\r\n    if (EpCompDesc != NULL)\r\n    {\r\n        DisplayEndointCompanionDescriptor(EpCompDesc, SspIsochEpCompDesc, epType);\r\n    }\r\n    if (SspIsochEpCompDesc != NULL)\r\n    {\r\n        DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor(SspIsochEpCompDesc);\r\n    }\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplaySuperSpeedPlusIsochEndpointCompanionDescriptor()\r\n\r\n*****************************************************************************/\r\nVOID\r\nDisplaySuperSpeedPlusIsochEndpointCompanionDescriptor(\r\n     _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc\r\n     )\r\n     {\r\n    AppendTextBuffer(\"\\r\\n ===>SuperSpeedPlus Isochronous Endpoint Companion Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        SspIsochEpCompDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        SspIsochEpCompDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"wReserved:                         0x%02X\\r\\n\",\r\n        SspIsochEpCompDesc->wReserved);\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        if (SspIsochEpCompDesc->wReserved != 0)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR: field is reserved\\r\\n\");\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"dwBytesPerInterval:                0x%04X\\r\\n\",\r\n        SspIsochEpCompDesc->dwBytesPerInterval);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayEndointCompanionDescriptor()\r\n\r\n*****************************************************************************/\r\nVOID\r\nDisplayEndointCompanionDescriptor (\r\n    _In_     PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc,\r\n    _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc,\r\n    _In_     UCHAR                                         DescType\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n ===>SuperSpeed Endpoint Companion Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        EpCompDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        EpCompDesc->bDescriptorType);\r\n\r\n    AppendTextBuffer(\"bMaxBurst:                         0x%02X\\r\\n\",\r\n        EpCompDesc->bMaxBurst);\r\n\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\",\r\n        EpCompDesc->bmAttributes.AsUchar);\r\n    if(gDoAnnotation)\r\n    {\r\n        switch (DescType)\r\n        {\r\n        case USB_ENDPOINT_TYPE_CONTROL:\r\n        case USB_ENDPOINT_TYPE_INTERRUPT:\r\n            if (EpCompDesc->bmAttributes.AsUchar != 0)\r\n            {\r\n                AppendTextBuffer(\"*!*ERROR:  Control/Interrupt SuperSpeed endpoints do not support streams\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n            break;\r\n        case USB_ENDPOINT_TYPE_BULK:\r\n            if(EpCompDesc->bmAttributes.Bulk.MaxStreams == 0)\r\n            {\r\n                AppendTextBuffer(\"The bulk endpoint does not define streams (MaxStreams == 0)\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\" = %d streams supported\\r\\n\", 1 << EpCompDesc->bmAttributes.Bulk.MaxStreams);\r\n            }\r\n\r\n            if (EpCompDesc->bmAttributes.Bulk.Reserved1 != 0)\r\n            {\r\n                AppendTextBuffer(\"*!*ERROR:  bmAttributes bits 7-5 should be 0\\r\\n\");\r\n            }\r\n            break;\r\n\r\n        case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n            if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 0)\r\n            {\r\n                if (EpCompDesc->bMaxBurst == 0 &&\r\n                    EpCompDesc->bmAttributes.Isochronous.Mult != 0)\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR: SuperSpeed isochronous endpoint multiplier value should be zero if bMaxBurst is zero\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    AppendTextBuffer(\" = %d maximum number of packets within a service interval\\r\\n\",\r\n                        (EpCompDesc->bmAttributes.Isochronous.Mult + 1)*(EpCompDesc->bMaxBurst + 1));\r\n\r\n                    if (EpCompDesc->bmAttributes.Isochronous.Mult > USB_SUPERSPEED_ISOCHRONOUS_MAX_MULTIPLIER)\r\n                    {\r\n                        AppendTextBuffer(\"*!*ERROR:  Maximum SuperSpeed isochronous endpoint multiplier value exceeded\\r\\n\");\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (EpCompDesc->bMaxBurst != 0 && SspIsochEpCompDesc != NULL)\r\n                {\r\n                    AppendTextBuffer(\" = %d maximum number of packets within a service interval\\r\\n\",\r\n                        (SspIsochEpCompDesc->dwBytesPerInterval*USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) /\r\n                        EpCompDesc->bMaxBurst);\r\n                }\r\n            }\r\n\r\n            if (EpCompDesc->bmAttributes.Isochronous.Reserved2 != 0)\r\n            {\r\n                AppendTextBuffer(\"*!*ERROR:  bmAttributes bits 7-2 should be 0\\r\\n\");\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n            break;\r\n        }\r\n    }\r\n    AppendTextBuffer(\"wBytesPerInterval:                 0x%04X\\r\\n\",\r\n        EpCompDesc->wBytesPerInterval);\r\n\r\n    if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 &&\r\n        EpCompDesc->wBytesPerInterval != 0x1)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: SuperSpeed endpoint wBytesPerInterval value should be 1 if \\\r\n                         SuperSpeedPlus Isoch companion descriptor is present\\r\\n\");\r\n    }\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayHidDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayHidDescriptor (\r\n    PUSB_HID_DESCRIPTOR         HidDesc\r\n    )\r\n{\r\n    UCHAR i = 0;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>HID Descriptor<===\\r\\n\");\r\n\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        HidDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        HidDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bcdHID:                          0x%04X\\r\\n\",\r\n        HidDesc->bcdHID);\r\n    AppendTextBuffer(\"bCountryCode:                      0x%02X\\r\\n\",\r\n        HidDesc->bCountryCode);\r\n    AppendTextBuffer(\"bNumDescriptors:                   0x%02X\\r\\n\",\r\n        HidDesc->bNumDescriptors);\r\n\r\n    for (i=0; i<HidDesc->bNumDescriptors; i++)\r\n    {\r\n        if (HidDesc->OptionalDescriptors[i].bDescriptorType == 0x22) {\r\n            AppendTextBuffer(\"bDescriptorType:                   0x%02X (Report Descriptor)\\r\\n\",\r\n                HidDesc->OptionalDescriptors[i].bDescriptorType);\r\n        }\r\n        else {\r\n            AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n                HidDesc->OptionalDescriptors[i].bDescriptorType);\r\n        }\r\n\r\n        AppendTextBuffer(\"wDescriptorLength:               0x%04X\\r\\n\",\r\n            HidDesc->OptionalDescriptors[i].wDescriptorLength);\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayOTGDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayOTGDescriptor (\r\n    PUSB_OTG_DESCRIPTOR         OTGDesc\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>OTG Descriptor<===\\r\\n\");\r\n\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        OTGDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        OTGDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bmAttributes:                      0x%02X\",\r\n        OTGDesc->bmAttributes);\r\n\r\n    switch (OTGDesc->bmAttributes)\r\n    {\r\n    case 0:\r\n        break;\r\n    case 1:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> SRP support\\r\\n\");\r\n        }\r\n        break;\r\n    case 2:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> HNP support\\r\\n\");\r\n        }\r\n        break;\r\n    case 3:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> SRP and HNP support\\r\\n\");\r\n        }\r\n        break;\r\n    default:\r\n        //@@TestCase A6.5\r\n        //@@Priority 1\r\n        //@@OTG Descriptor Field - bmAttributes\r\n        //@@Attribute bits D7-2 reserved (reset to 0)\r\n        AppendTextBuffer(\"*!*ERROR:  bmAttributes bits 2-7 are reserved \"\\\r\n            \"(should be 0)\\r\\n\");\r\n        OOPS();\r\n        break;\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nInitializeGlobalFlags ()\r\n\r\nInitialize the global device flags in UVCView.h\r\n\r\n*****************************************************************************/\r\n\r\nvoid\r\nInitializePerDeviceSettings (\r\n    PUSBDEVICEINFO info\r\n    )\r\n{\r\n    // Save base address for this current device's info (including Configuration descriptor)\r\n    CurrentUSBDeviceInfo = info;\r\n\r\n    // Initialize Configuration descriptor length\r\n    dwConfigLength = 0;\r\n\r\n    // Save # of bytes from start of Configuration descriptor\r\n    // (Update this in the descriptor parsing routines)\r\n    dwConfigIndex = 0;\r\n\r\n    // Flags used in dispvid.c to display default Frame descriptor for MJPEG,\r\n    //  Uncompressed, Vendor and FrameBased Formats\r\n    g_chMJPEGFrameDefault = 0;\r\n    g_chUNCFrameDefault = 0;\r\n    g_chVendorFrameDefault = 0;\r\n    g_chFrameBasedFrameDefault = 0;\r\n\r\n    // Spec version of UVC device\r\n    g_chUVCversion = 0;\r\n\r\n    // Start and end address of the configuration descriptor and start of the string descriptors\r\n    g_pConfigDesc  = NULL;\r\n    g_pStringDescs = NULL;\r\n    g_descEnd      = NULL;\r\n\r\n    //\r\n    // The GetConfigDescriptor() function in enum.c does not always work\r\n    // If that fails, the Configuration descriptor will be NULL\r\n    //  and we can only display the device descriptor\r\n    //\r\n    CurrentConfigDesc = NULL;\r\n    if (NULL != info)\r\n    {\r\n         if (NULL != info->ConfigDesc)\r\n        {\r\n            CurrentConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1);\r\n\r\n            // Save the LENGTH of the Config descriptor\r\n            // Note that IsIADDevice() saves the ADDRESS of the END of the Config desc\r\n            // Be aware of the difference\r\n            dwConfigLength = CurrentConfigDesc->wTotalLength;\r\n        }\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nIsUVCDevice()\r\n\r\nReturn Spec version of UVC device\r\n 0x0  = Not a UVC device\r\n 0x10 = UVC 1.0\r\n 0x11 = UVC 1.1\r\n\r\n *****************************************************************************/\r\n\r\nUINT\r\nIsUVCDevice (\r\n    PUSBDEVICEINFO info\r\n    )\r\n{\r\n    PUSB_CONFIGURATION_DESCRIPTOR  ConfigDesc = NULL;\r\n    PUSB_COMMON_DESCRIPTOR         commonDesc = NULL;\r\n    PUCHAR                         descEnd = NULL;\r\n    UINT  uUVCversion = 0;\r\n\r\n    //\r\n    // The GetConfigDescriptor() function in enum.c does not always work\r\n    // If that fails, the Configuration descriptor will be NULL\r\n    //  and we can only display the device descriptor\r\n    //\r\n    if (NULL == info)\r\n    {\r\n        return 0;\r\n    }\r\n    if (NULL == info->ConfigDesc)\r\n    {\r\n        return 0;\r\n    }\r\n    ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1);\r\n    if (NULL == ConfigDesc)\r\n    {\r\n        return 0;\r\n    }\r\n\r\n    // We've got a good Configuration Descriptor\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n    descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n\r\n    // walk through all the descriptors looking for the VIDEO_CONTROL_HEADER_UNIT\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        if ((commonDesc->bDescriptorType == CS_INTERFACE) &&\r\n            (commonDesc->bLength > sizeof(VIDEO_CONTROL_HEADER_UNIT)))\r\n        {\r\n            // Right type, size. Now check subtype\r\n            PVIDEO_CONTROL_HEADER_UNIT pCSVC = NULL;\r\n            pCSVC = (PVIDEO_CONTROL_HEADER_UNIT) commonDesc;\r\n            if (VC_HEADER == pCSVC->bDescriptorSubtype)\r\n            {\r\n                // found the Class-specific VC Interface Header descriptor\r\n                uUVCversion = pCSVC->bcdVideoSpec;\r\n                // Save the version to global\r\n                g_chUVCversion = uUVCversion;\r\n                // We're done\r\n                break;\r\n            }\r\n        }\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uUVCversion);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nIsIADDevice()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nIsIADDevice (\r\n    PUSBDEVICEINFO info\r\n    )\r\n{\r\n    PUSB_CONFIGURATION_DESCRIPTOR  ConfigDesc = NULL;\r\n    PUSB_COMMON_DESCRIPTOR         commonDesc = NULL;\r\n    PUCHAR                         descEnd = NULL;\r\n    UINT  uIADcount = 0;\r\n\r\n    //\r\n    // The GetConfigDescriptor() function in enum.c does not always work\r\n    // If that fails, the Configuration descriptor will be NULL\r\n    //  and we can only display the device descriptor\r\n    //\r\n    if (NULL == info)\r\n    {\r\n        return 0;\r\n    }\r\n    if (NULL == info->ConfigDesc)\r\n    {\r\n        return 0;\r\n    }\r\n\r\n    ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1);\r\n    if (NULL != ConfigDesc)\r\n    {\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n        descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n    }\r\n\r\n    // return total number of IAD descriptors in this device configuration\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        if (commonDesc->bDescriptorType == USB_IAD_DESCRIPTOR_TYPE)\r\n        {\r\n            uIADcount++;\r\n        }\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uIADcount);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayIADDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayIADDescriptor (\r\n    PUSB_IAD_DESCRIPTOR         IADDesc,\r\n    PSTRING_DESCRIPTOR_NODE     StringDescs,\r\n    int                         nInterfaces,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>IAD Descriptor<===\\r\\n\");\r\n\r\n    //length checked in DisplayConfigDesc()\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        IADDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        IADDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bFirstInterface:                   0x%02X\\r\\n\",\r\n        IADDesc->bFirstInterface);\r\n    AppendTextBuffer(\"bInterfaceCount:                   0x%02X\\r\\n\",\r\n        IADDesc->bInterfaceCount);\r\n    if (IADDesc->bInterfaceCount == 1)\r\n    {\r\n        //@@TestCase A7.1\r\n        //@@Priority 1\r\n        //@@Standard IAD Descriptor Field - bInterfaceCount\r\n        //@@The number of interfaces must be greater than 1\r\n        AppendTextBuffer(\"*!*ERROR:  bInterfaceCount must be greater than 1 \\r\\n\");\r\n        OOPS();\r\n    }\r\n    if (nInterfaces < IADDesc->bFirstInterface + IADDesc->bInterfaceCount)\r\n    {\r\n        //@@TestCase A7.2\r\n        //@@Priority 1\r\n        //@@Standard IAD Descriptor Field - bInterfaceCount\r\n        //@@The total number of interfaces must be greater than or equal to\r\n        //@@  the highest linked interface number (base interface number plus count)\r\n        AppendTextBuffer(\"*!*ERROR:  The total number of interfaces (%d) must be greater \"\\\r\n            \"than or equal to\\r\\n\",\r\n            nInterfaces);\r\n        AppendTextBuffer(\"           the highest linked interface number (base %d + \"\\\r\n            \"count %d = %d)\\r\\n\",\r\n            IADDesc->bFirstInterface, IADDesc->bInterfaceCount,\r\n            (IADDesc->bFirstInterface + IADDesc->bInterfaceCount));\r\n        OOPS();\r\n    }\r\n    AppendTextBuffer(\"bFunctionClass:                    0x%02X\",\r\n        IADDesc->bFunctionClass);\r\n    if (IADDesc->bFunctionClass == 0)\r\n    {\r\n        //@@TestCase A7.3\r\n        //@@Priority 1\r\n        //@@Standard IAD Descriptor Field - bFunctionClass\r\n        //@@\"A value of zero is not allowed in this descriptor\"\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  bFunctionClass contains an illegal value 0 \\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    switch (IADDesc->bFunctionClass)\r\n    {\r\n    case USB_DEVICE_CLASS_AUDIO:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Audio Interface Class\\r\\n\");\r\n        }\r\n\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\",\r\n            IADDesc->bFunctionSubClass);\r\n\r\n        if(gDoAnnotation)\r\n        {\r\n            switch (IADDesc->bFunctionSubClass)\r\n            {\r\n            case USB_AUDIO_SUBCLASS_AUDIOCONTROL:\r\n                AppendTextBuffer(\"  -> Audio Control Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:\r\n                AppendTextBuffer(\"  -> Audio Streaming Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            case USB_AUDIO_SUBCLASS_MIDISTREAMING:\r\n                AppendTextBuffer(\"  -> MIDI Streaming Interface SubClass\\r\\n\");\r\n                break;\r\n\r\n            default:\r\n                //@@TestCase A7.4\r\n                //@@CAUTION\r\n                //@@Descriptor Field - bFunctionSubClass\r\n                //@@Invalid bFunctionSubClass\r\n                AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid bFunctionSubClass\\r\\n\");\r\n                OOPS();\r\n                break;\r\n            }\r\n        }\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_VIDEO:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Video Interface Class\\r\\n\");\r\n        }\r\n\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\",\r\n            IADDesc->bFunctionSubClass);\r\n\r\n        switch(IADDesc->bFunctionSubClass)\r\n        {\r\n        case SC_VIDEO_INTERFACE_COLLECTION:\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> Video Interface Collection\\r\\n\");\r\n            }\r\n            break;\r\n\r\n        default:\r\n            //@@TestCase A7.5\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bFunctionSubClass\r\n            //@@Invalid bFunctionSubClass\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:    This should be USB_VIDEO_SC_VIDEO_INTERFACE_COLLECTION %d\\r\\n\",\r\n                SC_VIDEO_INTERFACE_COLLECTION);\r\n            OOPS();\r\n            break;\r\n        }\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_HUMAN_INTERFACE:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> HID Interface Class\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_HUB:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> HUB Interface Class\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_RESERVED:\r\n        //@@TestCase A7.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - bFunctionClass\r\n        //@@A reserved USB Device Interface Class has been defined\r\n        AppendTextBuffer(\"\\r\\n*!*CAUTION:  %d is a Reserved USB Device Interface Class\\r\\n\",\r\n            USB_DEVICE_CLASS_RESERVED);\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_COMMUNICATIONS:\r\n        AppendTextBuffer(\"  -> This is Communications (CDC Control) USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_MONITOR:\r\n        AppendTextBuffer(\"  -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Physical Interface USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_POWER:\r\n        if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is an Image USB Device Interface Class\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Power USB Device Interface Class (This may be obsolete)\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_PRINTER:\r\n        AppendTextBuffer(\"  -> This is a Printer USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DEVICE_CLASS_STORAGE:\r\n        AppendTextBuffer(\"  -> This is a Mass Storage USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_CDC_DATA_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a CDC Data USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_CHIP_SMART_CARD_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Chip/Smart Card USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_CONTENT_SECURITY_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is a Content Security USB Device Interface Class\\r\\n\");\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_DIAGNOSTIC_DEVICE_INTERFACE:\r\n        if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A7.7\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bFunctionClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_WIRELESS_CONTROLLER_INTERFACE:\r\n        if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1)\r\n        {\r\n            AppendTextBuffer(\"  -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\\r\\n\");\r\n        }\r\n        else\r\n        {\r\n            //@@TestCase A7.8\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bFunctionClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    case USB_APPLICATION_SPECIFIC_INTERFACE:\r\n        AppendTextBuffer(\"  -> This is an Application Specific USB Device Interface Class\\r\\n\");\r\n\r\n        switch(IADDesc->bFunctionSubClass)\r\n        {\r\n        case 1:\r\n            AppendTextBuffer(\"  -> This is a Device Firmware Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        case 2:\r\n            AppendTextBuffer(\"  -> This is an IrDA Bridge Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        case 3:\r\n            AppendTextBuffer(\"  -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\\r\\n\");\r\n            break;\r\n        default:\r\n            //@@TestCase A7.9\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bFunctionClass\r\n            //@@Invalid Interface Class\r\n            AppendTextBuffer(\"\\r\\n*!*CAUTION:    This appears to be an invalid Interface Class\\r\\n\");\r\n            OOPS();\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n\r\n    default:\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Interface Class Unknown to USBView\\r\\n\");\r\n        }\r\n        AppendTextBuffer(\"bFunctionSubClass:                 0x%02X\\r\\n\",\r\n            IADDesc->bFunctionSubClass);\r\n        break;\r\n    }\r\n\r\n    AppendTextBuffer(\"bFunctionProtocol:                 0x%02X\",\r\n        IADDesc->bFunctionProtocol);\r\n\r\n    // check protocol for our class\r\n    if ((IADDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO))\r\n    {\r\n        // USB Video Class\r\n        if(IADDesc->bFunctionProtocol == PC_PROTOCOL_UNDEFINED)\r\n        {\r\n            // correct protocol for UVC\r\n            if(gDoAnnotation)\r\n            {\r\n                AppendTextBuffer(\"  -> PC_PROTOCOL_UNDEFINED protocol\\r\\n\");\r\n            } else {\r\n                AppendTextBuffer(\"\\r\\n\");\r\n            }\r\n        } else {\r\n            // incorrect protocol for UVC\r\n            //@@TestCase A7.10\r\n            //@@WARNING\r\n            //@@Descriptor Field - iInterface\r\n            //@@bFunctionProtocol must be set to PC_PROTOCOL_UNDEFINED\r\n            AppendTextBuffer(\"*!*WARNING:  must be set to PC_PROTOCOL_UNDEFINED %d for this class\\r\\n\",\r\n                PC_PROTOCOL_UNDEFINED);\r\n            OOPS();\r\n        }\r\n    } else {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"iFunction:                         0x%02X\\r\\n\",\r\n        IADDesc->iFunction);\r\n\r\n    if(gDoAnnotation)\r\n    {\r\n        if (IADDesc->iFunction)\r\n        {\r\n            DisplayStringDescriptor(IADDesc->iFunction,\r\n                StringDescs,\r\n                LatestDevicePowerState);\r\n        }\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetConfigurationSize()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nGetConfigurationSize (\r\n    PUSBDEVICEINFO info\r\n    )\r\n{\r\n    PUSB_CONFIGURATION_DESCRIPTOR\r\n        ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1);\r\n    PUSB_COMMON_DESCRIPTOR\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n    PUCHAR\r\n        descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n    UINT  uCount = 0;\r\n\r\n    // return this device configuration's total sum of descriptor lengths\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        uCount += commonDesc->bLength;\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uCount);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetInterfaceCount()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nGetInterfaceCount (\r\n    PUSBDEVICEINFO info\r\n    )\r\n{\r\n    // how do we handle composite devices?\r\n    PUSB_CONFIGURATION_DESCRIPTOR\r\n        ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1);\r\n    PUSB_COMMON_DESCRIPTOR\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n    PUCHAR\r\n        descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n    UINT  uCount = 0;\r\n\r\n    // return this device configuration's total number of interface descriptors\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        if (commonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)\r\n        {\r\n            uCount++;\r\n        }\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uCount);\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayUSEnglishStringDescriptor()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nDisplayUSEnglishStringDescriptor (\r\n    UCHAR                       Index,\r\n    PSTRING_DESCRIPTOR_NODE     USStringDescs,\r\n    DEVICE_POWER_STATE          LatestDevicePowerState\r\n    )\r\n{\r\n    ULONG nBytes = 0;\r\n    BOOLEAN FoundMatchingString = FALSE;\r\n    CHAR  pString[512];\r\n\r\n    //@@DisplayUSEnglishStringDescriptor - String Descriptor\r\n    for (; USStringDescs; USStringDescs = USStringDescs->Next)\r\n    {\r\n        if (USStringDescs->DescriptorIndex == Index && USStringDescs->LanguageID == 0x0409)\r\n        {\r\n            FoundMatchingString = TRUE;\r\n\r\n            AppendTextBuffer(\"English product name: \\\"\");\r\n            memset(pString, 0, 512);\r\n            nBytes = WideCharToMultiByte(\r\n                CP_ACP,     // CodePage\r\n                WC_NO_BEST_FIT_CHARS,\r\n                USStringDescs->StringDescriptor->bString,\r\n                (USStringDescs->StringDescriptor->bLength - 2) / 2,\r\n                pString,\r\n                512,\r\n                NULL,       // lpDefaultChar\r\n                NULL);      // pUsedDefaultChar\r\n            if (nBytes)\r\n                AppendTextBuffer(\"%s\\\"\\r\\n\", pString);\r\n            else\r\n                AppendTextBuffer(\"\\\"\\r\\n\", pString);\r\n            return;\r\n        }\r\n    }\r\n\r\n    //@@TestCase A8.1\r\n    //@@WARNING\r\n    //@@Descriptor Field - string index\r\n    //@@No support for english\r\n    if (!FoundMatchingString)\r\n    {\r\n        if (LatestDevicePowerState == PowerDeviceD0)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR:  No String Descriptor for index %d!\\r\\n\", Index);\r\n            OOPS();\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"String Descriptor for index %d not available while device is in low power state.\\r\\n\", Index);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  The index selected does not support English(US)\\r\\n\");\r\n        OOPS();\r\n    }\r\n    return;\r\n\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayStringDescriptor()\r\n\r\n*****************************************************************************/\r\nVOID\r\nDisplayStringDescriptor (\r\n    UCHAR                    Index,\r\n    PSTRING_DESCRIPTOR_NODE  StringDescs,\r\n    DEVICE_POWER_STATE       LatestDevicePowerState\r\n    )\r\n{\r\n    ULONG nBytes = 0;\r\n    BOOLEAN FoundMatchingString = FALSE;\r\n    PCHAR pStr = NULL;\r\n    CHAR  pString[512];\r\n\r\n    //@@DisplayStringDescriptor - String Descriptor\r\n\r\n    while (StringDescs)\r\n    {\r\n        if (StringDescs->DescriptorIndex == Index)\r\n        {\r\n            FoundMatchingString = TRUE;\r\n            if(gDoAnnotation)\r\n            {\r\n                pStr= GetLangIDString(StringDescs->LanguageID);\r\n                if(pStr)\r\n                {\r\n                    AppendTextBuffer(\"     %s  \\\"\",\r\n                        pStr);\r\n                }\r\n                else\r\n                {\r\n                    //@@TestCase A9.1\r\n                    //@@WARNING\r\n                    //@@Descriptor Field - string index\r\n                    //@@The Language ID does not match any known languages supported by USB ORG\r\n                    AppendTextBuffer(\"*!*WARNING:  %d is an invalid Language ID\\r\\n\",\r\n                        Index);\r\n                    OOPS();\r\n                }\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"     0x%04X:  \\\"\", StringDescs->LanguageID);\r\n            }\r\n            memset(pString, 0, 512);\r\n\r\n            if (StringDescs->StringDescriptor->bLength > sizeof(USHORT))\r\n            {\r\n                 nBytes = WideCharToMultiByte(\r\n                              CP_ACP,     // CodePage\r\n                              WC_NO_BEST_FIT_CHARS,\r\n                              StringDescs->StringDescriptor->bString,\r\n                              (StringDescs->StringDescriptor->bLength - 2) / 2,\r\n                              pString,\r\n                              512,\r\n                              NULL,       // lpDefaultChar\r\n                              NULL);      // pUsedDefaultChar\r\n                 if (nBytes)\r\n                 {\r\n                      AppendTextBuffer(\"%s\\\"\\r\\n\", pString);\r\n                 }\r\n                 else\r\n                 {\r\n                      AppendTextBuffer(\"\\\"\\r\\n\");\r\n                 }\r\n            }\r\n            else\r\n            {\r\n                 //\r\n                 // This is NULL string which is invalid\r\n                 //\r\n                 AppendTextBuffer(\"\\\"\\r\\n\");\r\n            }\r\n        }\r\n        StringDescs = StringDescs->Next;\r\n    }\r\n\r\n    if (!FoundMatchingString)\r\n    {\r\n        if (LatestDevicePowerState == PowerDeviceD0)\r\n        {\r\n            AppendTextBuffer(\"*!*ERROR:  No String Descriptor for index %d!\\r\\n\", Index);\r\n            OOPS();\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"String Descriptor for index %d not available while device is in low power state.\\r\\n\", Index);\r\n        }\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayUnknownDescriptor()\r\n\r\n*****************************************************************************/\r\nVOID\r\nDisplayUnknownDescriptor (\r\n    PUSB_COMMON_DESCRIPTOR      CommonDesc\r\n    )\r\n{\r\n    AppendTextBuffer(\"\\r\\n          ===>Descriptor Hex Dump<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\",\r\n        CommonDesc->bLength);\r\n\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\",\r\n        CommonDesc->bDescriptorType);\r\n\r\n    DisplayRemainingUnknownDescriptor((PUCHAR)CommonDesc, 0, CommonDesc->bLength);\r\n}\r\n\r\nVOID\r\nDisplayRemainingUnknownDescriptor(\r\n    PUCHAR DescriptorData,\r\n    ULONG  Start,\r\n    ULONG  Stop\r\n    )\r\n{\r\n    ULONG i;\r\n\r\n    for (i = Start; i < Stop; i++)\r\n    {\r\n        AppendTextBuffer(\"%02X \",\r\n            DescriptorData[i]);\r\n\r\n        if (i % 16 == 15)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    }\r\n\r\n    if (i % 16 != 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nGetVendorString()\r\n\r\nidVendor - USB Vendor ID\r\n\r\nReturn Value - Vendor name string associated with idVendor, or NULL if\r\nno vendor name string is found which is associated with idVendor.\r\n\r\n*****************************************************************************/\r\n\r\nPCHAR\r\nGetVendorString (\r\n    USHORT     idVendor\r\n    )\r\n{\r\n    PVENDOR_ID vendorID = NULL;\r\n\r\n    if (idVendor == 0x0000)\r\n    {\r\n        return NULL;\r\n    }\r\n\r\n    vendorID = USBVendorIDs;\r\n\r\n    while (vendorID->usVendorID != 0x0000)\r\n    {\r\n        if (vendorID->usVendorID == idVendor)\r\n        {\r\n            break;\r\n        }\r\n        vendorID++;\r\n    }\r\n\r\n    return (vendorID->szVendor);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetLangIDString()\r\n\r\nidVendor - USB Vendor ID\r\n\r\nReturn Value - Vendor name string associated with idVendor, or NULL if\r\nno vendor name string is found which is associated with idVendor.\r\n\r\n*****************************************************************************/\r\n\r\nPCHAR\r\nGetLangIDString (\r\n    USHORT     idLang\r\n    )\r\n{\r\n    PUSBLANGID langID = NULL;\r\n\r\n    if (idLang != 0x0000)\r\n    {\r\n        langID = USBLangIDs;\r\n\r\n        while (langID->usLangID != 0x0000)\r\n        {\r\n            if (langID->usLangID == idLang)\r\n            {\r\n                return (langID->szLanguage);\r\n            }\r\n            langID++;\r\n        }\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetStringFromList()\r\n\r\nPSTRINGLIST     slList,        - pointer to STRINGLIST used\r\n\r\nULONG ulNumElements, -\r\n    number of elements in that STRINGLIST calc before call with sizeof(slList) / sizeof(STRINGLIST),\r\nULONG or ULONGLONG (if H264_SUPPORT is defined)ulFlag -  - flag to look for\r\nPCHAR           szDefault      - string to return if no match\r\n\r\nReturn a string associated with a value from a stringtable.\r\n\r\nexample:\r\n    GetStringFromList(slPowerState,\r\n        sizeof(slPowerState) / sizeof(STRINGLIST),\r\n        pUPI->SystemState,\r\n        \"Invalid Power State\")\r\n\r\n*****************************************************************************/\r\n\r\nPCHAR\r\nGetStringFromList(\r\n    PSTRINGLIST     slList,\r\n    ULONG           ulNumElements,\r\n#ifdef H264_SUPPORT\r\n    ULONGLONG       ulFlag,\r\n#else\r\n    ULONG           ulFlag,\r\n#endif\r\n    _In_ PCHAR           szDefault\r\n    )\r\n{\r\n    // ulIndex is zero based, but ulNumElements is 1 based\r\n    // subtract 1 from ulNumElements so that are same base\r\n#ifdef H264_SUPPORT\r\n    ULONGLONG ulIndex = 0;\r\n#else\r\n    ULONG ulIndex = 0;\r\n#endif\r\n    ulNumElements--;\r\n\r\n\r\n    for ( ; ulIndex <= ulNumElements; ulIndex++)\r\n    {\r\n        if (ulFlag == slList[ulIndex].ulFlag)\r\n        {\r\n            return (slList[ulIndex].pszString);\r\n        }\r\n    }\r\n\r\n    return szDefault;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/dispvid.c",
    "content": "/*++\r\n\r\nCopyright (c) 2002-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\nDISPVID.C\r\n\r\nAbstract:\r\n\r\nThis source file contains routines which update the edit control\r\nto display information about USB Video descriptors.\r\n\r\nEnvironment:\r\n\r\nuser mode\r\n\r\nRevision History:\r\n\r\n11-22-2002 : created\r\n03-28-2003 : major revisions from latest specs.\r\n03-28-2008 : include USB Video Class 1.1\r\n\r\n--*/\r\n\r\n//*****************************************************************************\r\n// I N C L U D E S\r\n//*****************************************************************************\r\n\r\n#include \"uvcview.h\"\r\n#include \"h264.h\"\r\n\r\n//*****************************************************************************\r\n// G L O B A L S    P R I V A T E    T O    T H I S    F I L E\r\n//*****************************************************************************\r\n\r\nint StillMethod = 0;\r\n\r\n//\r\n// USB Device Class Definition for Video Devices 0.8b version\r\n//\r\n// 3.6.2.3  Camera Terminal Descriptor\r\n//\r\nSTRINGLIST slCameraControl1 [] =\r\n{\r\n    {1,         \"Scanning Mode\",            \"\"},\r\n    {2,         \"Auto-Exposure Mode\",       \"\"},\r\n    {4,         \"Auto-Exposure Priority\",   \"\"},\r\n    {8,         \"Exposure Time (Absolute)\", \"\"},\r\n    {0x10,      \"Exposure Time (Relative)\", \"\"},\r\n    {0x20,      \"Focus (Absolute)\",         \"\"},\r\n    {0x40,      \"Focus (Relative)\",         \"\"},\r\n    {0x80,      \"Iris (Absolute)\",          \"\"},\r\n};\r\nSTRINGLIST slCameraControl2 [] =\r\n{\r\n    {1,         \"Iris (Relative)\",          \"\"},\r\n    {2,         \"Zoom (Absolute)\",          \"\"},\r\n    {4,         \"Zoom (Relative)\",          \"\"},\r\n    {8,         \"PanTilt (Absolute)\",       \"\"},\r\n    {0x10,      \"PanTilt (Relative)\",       \"\"},\r\n    {0x20,      \"Roll (Absolute)\",          \"\"},\r\n    {0x40,      \"Roll (Relative)\",          \"\"},\r\n    {0x80,      \"Reserved\",                 \"\"},\r\n};\r\nSTRINGLIST slCameraControl3 [] =\r\n{\r\n    {1,         \"Reserved\",                 \"\"},\r\n    {2,         \"Focus, Auto\",              \"\"},\r\n    {4,         \"Privacy\",                  \"\"},\r\n    {8,         \"Focus, Simple\",            \"\"},\r\n    {0x10,      \"Window\",                   \"\"},\r\n    {0x20,      \"Region of Interest\",       \"\"},\r\n    {0x40,      \"Reserved\",                 \"\"},\r\n    {0x80,      \"Reserved\",                 \"\"},\r\n};\r\n\r\n// 3.6.2.5  Processing Unit Descriptor\r\n//\r\nSTRINGLIST slProcessorControls1 [] =\r\n{\r\n    {1,         \"Brightness\",                \"\"},\r\n    {2,         \"Contrast\",                  \"\"},\r\n    {4,         \"Hue\",                       \"\"},\r\n    {8,         \"Saturation\",                \"\"},\r\n    {0x10,      \"Sharpness\",                 \"\"},\r\n    {0x20,      \"Gamma\",                     \"\"},\r\n    {0x40,      \"White Balance Temperature\", \"\"},\r\n    {0x80,      \"White Balance Component\",   \"\"},\r\n};\r\nSTRINGLIST slProcessorControls2 [] =\r\n{\r\n    {1,         \"Backlight Compensation\",          \"\"},\r\n    {2,         \"Gain\",                            \"\"},\r\n    {4,         \"Power Line Frequency\",            \"\"},\r\n    {8,         \"Hue, Auto\",                       \"\"},\r\n    {0x10,      \"White Balance Temperature, Auto\", \"\"},\r\n    {0x20,      \"White Balance Component, Auto\",   \"\"},\r\n    {0x40,      \"Digital Multiplier\",              \"\"},\r\n    {0x80,      \"Digital Multiplier Limit\",        \"\"},\r\n};\r\nSTRINGLIST slProcessorControls3 [] =\r\n{\r\n    {1,         \"Analog Video Standard\",           \"\"},\r\n    {2,         \"Analog Video Lock Status\",        \"\"},\r\n    {4,         \"Contrast, Auto\",                  \"\"},\r\n    {8,         \"Reserved\",                        \"\"},\r\n    {0x10,      \"Reserved\",                        \"\"},\r\n    {0x20,      \"Reserved\",                        \"\"},\r\n    {0x40,      \"Reserved\",                        \"\"},\r\n    {0x80,      \"Reserved\",                        \"\"},\r\n};\r\n\r\n\r\nSTRINGLIST slProcessorVideoStandards [] =\r\n{\r\n    {1,         \"None\",                     \"\"},\r\n    {2,         \"NTSC  - 525/60\",           \"\"},\r\n    {4,         \"PAL   - 625/50\",           \"\"},\r\n    {8,         \"SECAM - 625/50\",           \"\"},\r\n    {0x10,      \"NTSC  - 625/50\",           \"\"},\r\n    {0x20,      \"PAL   - 525/60\",           \"\"},\r\n    {0x40,      \"Reserved\",                 \"\"},\r\n    {0x80,      \"Reserved\",                 \"\"},\r\n};\r\n\r\n// 3.8.2.1  Input Header Descriptor\r\n//\r\nSTRINGLIST slInputHeaderControls[]=\r\n{\r\n    {1,         \"Key Frame Rate\"         , \"\"},\r\n    {2,         \"P Frame Rate\"           , \"\"},\r\n    {4,         \"Compression Quality\"    , \"\"},\r\n    {8,         \"Compression Window Size\", \"\"},\r\n    {0x10,      \"Generate Key Frame\"     , \"\"},\r\n    {0x20,      \"Update Frame Segment\"   , \"\"},\r\n    {0x40,      \"Reserved\"               , \"\"},\r\n    {0x80,      \"Reserved\"               , \"\"},\r\n};\r\n\r\nSTRINGLIST slOutputHeaderControls[]=\r\n{\r\n    {1,         \"Key Frame Rate\"         , \"\"},\r\n    {2,         \"P Frame Rate\"           , \"\"},\r\n    {4,         \"Compression Quality\"    , \"\"},\r\n    {8,         \"Compression Window Size\", \"\"},\r\n    {0x10,      \"Reserved\"               , \"\"},\r\n    {0x20,      \"Reserved\"               , \"\"},\r\n    {0x40,      \"Reserved\"               , \"\"},\r\n    {0x80,      \"Reserved\"               , \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportControls[]=\r\n{\r\n    {1,         \"Transport Control\"            , \"\"},\r\n    {2,         \"Absolute Track Number Control\", \"\"},\r\n    {4,         \"Media Information\"            , \"\"},\r\n    {8,         \"Time Code Information\"        , \"\"},\r\n    {0x10,      \"Reserved\"                     , \"\"},\r\n    {0x20,      \"Reserved\"                     , \"\"},\r\n    {0x40,      \"Reserved\"                     , \"\"},\r\n    {0x80,      \"Reserved\"                     , \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportModes1[]=\r\n{\r\n    {1,         \"Play Forward\",         \"\"},\r\n    {2,         \"Pause\",                \"\"},\r\n    {4,         \"Rewind\",               \"\"},\r\n    {8,         \"Fast Forward\",         \"\"},\r\n    {0x10,      \"High Speed Rewind\",    \"\"},\r\n    {0x20,      \"Stop\",                 \"\"},\r\n    {0x40,      \"Eject\",                \"\"},\r\n    {0x80,      \"Play Next Frame\",      \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportModes2[]=\r\n{\r\n    {1,         \"Play Slowest Forward\", \"\"},\r\n    {2,         \"Play Slow Forward 4\",  \"\"},\r\n    {4,         \"Play Slow Forward 3\",  \"\"},\r\n    {8,         \"Play Slow Forward 2\",  \"\"},\r\n    {0x10,      \"Play Slow Forward 1\",  \"\"},\r\n    {0x20,      \"Play X1\",              \"\"},\r\n    {0x40,      \"Play Fast Forward 1\",  \"\"},\r\n    {0x80,      \"Play Fast Forward 2\",  \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportModes3[]=\r\n{\r\n    {1,         \"Play Fast Forward 3\",  \"\"},\r\n    {2,         \"Play Fast Forward 4\",  \"\"},\r\n    {4,         \"Play Fastest Forward\", \"\"},\r\n    {8,         \"Play Previous Frame\",  \"\"},\r\n    {0x10,      \"Play Slowest Reverse\", \"\"},\r\n    {0x20,      \"Play Slow Reverse 4\",  \"\"},\r\n    {0x40,      \"Play Slow Reverse 3\",  \"\"},\r\n    {0x80,      \"Play Slow Reverse 2\",  \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportModes4[]=\r\n{\r\n    {1,         \"Play Slow Reverse 1\",  \"\"},\r\n    {2,         \"Play X1 Reverse\",      \"\"},\r\n    {4,         \"Play Fast Reverse 1\",  \"\"},\r\n    {8,         \"Play Fast Reverse 2\",  \"\"},\r\n    {0x10,      \"Play Fast Reverse 3\",  \"\"},\r\n    {0x20,      \"Play Fast Reverse 4\",  \"\"},\r\n    {0x40,      \"Play Fastest Reverse\", \"\"},\r\n    {0x80,      \"Record StateStart\",    \"\"},\r\n};\r\n\r\nSTRINGLIST slMediaTransportModes5[]=\r\n{\r\n    {1,         \"Record Pause\",         \"\"},\r\n    {2,         \"Reserved\",             \"\"},\r\n    {4,         \"Reserved\",             \"\"},\r\n    {8,         \"Reserved\",             \"\"},\r\n    {0x10,      \"Reserved\",             \"\"},\r\n    {0x20,      \"Reserved\",             \"\"},\r\n    {0x40,      \"Reserved\",             \"\"},\r\n    {0x80,      \"Reserved\",             \"\"},\r\n};\r\n\r\nSTRINGLIST slInputTermTypes[]=\r\n{\r\n    {0x0100,    \"TT_VENDOR_SPECIFIC\",         \"I//O\"},\r\n    {0x0101,    \"TT_STREAMING\",               \"I//O\"},\r\n    {0x0400,    \"EXTERNAL_VENDOR_SPECIFIC\",   \"I//O\"},\r\n    {0x0401,    \"COMPOSITE_CONNECTOR\",        \"I//O\"},\r\n    {0x0402,    \"SVIDEO_CONNECTOR\",           \"I//O\"},\r\n    {0x0403,    \"COMPONENT_CONNECTOR\",        \"I//O\"},\r\n    {0x0200,    \"ITT_VENDOR_SPECIFIC\",        \"I\"},\r\n    {0x0201,    \"ITT_CAMERA\",                 \"I\"},\r\n    {0x0202,    \"ITT_MEDIA_TRANSPORT_INPUT\",  \"I\"},\r\n};\r\nSTRINGLIST slOutputTermTypes[]=\r\n{\r\n    {0x0100,    \"TT_VENDOR_SPECIFIC\",         \"I//O\"},\r\n    {0x0101,    \"TT_STREAMING\",               \"I//O\"},\r\n    {0x0400,    \"EXTERNAL_VENDOR_SPECIFIC\",   \"I//O\"},\r\n    {0x0401,    \"COMPOSITE_CONNECTOR\",        \"I//O\"},\r\n    {0x0402,    \"SVIDEO_CONNECTOR\",           \"I//O\"},\r\n    {0x0403,    \"COMPONENT_CONNECTOR\",        \"I//O\"},\r\n    {0x0300,    \"OTT_VENDOR_SPECIFIC\",        \"O\"},\r\n    {0x0301,    \"OTT_DISPLAY\",                \"O\"},\r\n    {0x0302,    \"OTT_MEDIA_TRANSPORT_OUTPUT\", \"O\"},\r\n};\r\n\r\n//*****************************************************************************\r\n// L O C A L    F U N C T I O N    P R O T O T Y P E S\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCHeader (\r\n                 PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc\r\n                 );\r\nBOOL\r\nDisplayVCInputTerminal (\r\n    PVIDEO_INPUT_TERMINAL   VidITDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    );\r\n\r\nBOOL\r\nDisplayVCOutputTerminal (\r\n    PVIDEO_OUTPUT_TERMINAL  VidOTDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    );\r\n\r\nBOOL\r\nDisplayVCCameraTerminal (\r\n                         PVIDEO_CAMERA_TERMINAL CameraDesc\r\n                         );\r\nBOOL\r\nDisplayVCMediaTransInputTerminal (\r\n                                  PVIDEO_INPUT_MTT VCMedTransInDesc\r\n                                  );\r\nBOOL\r\nDisplayVCMediaTransOutputTerminal (\r\n                                   PVIDEO_OUTPUT_MTT VCMedTransOutDesc\r\n                                   );\r\nBOOL\r\nDisplayVCSelectorUnit (\r\n    PVIDEO_SELECTOR_UNIT    VidSelectorDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    );\r\n\r\nBOOL\r\nDisplayVCProcessingUnit (\r\n    PVIDEO_PROCESSING_UNIT  VidProcessingDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    );\r\n\r\nBOOL\r\nDisplayVCExtensionUnit (\r\n    PVIDEO_EXTENSION_UNIT   VidExtensionDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    );\r\n\r\nBOOL\r\nDisplayVidInHeader (\r\n                    PVIDEO_STREAMING_INPUT_HEADER VidInHeaderDesc\r\n                    );\r\nBOOL\r\nDisplayVidOutHeader (\r\n                     PVIDEO_STREAMING_OUTPUT_HEADER VidOutHeaderDesc\r\n                     );\r\nBOOL\r\nDisplayStillImageFrame (\r\n                        PVIDEO_STILL_IMAGE_FRAME StillFrameDesc\r\n                        );\r\nBOOL\r\nDisplayColorMatching (\r\n                      PVIDEO_COLORFORMAT ColorMatchDesc\r\n                      );\r\nBOOL\r\nDisplayUncompressedFormat (\r\n                           PVIDEO_FORMAT_UNCOMPRESSED UnCompFormatDesc\r\n                           );\r\nBOOL\r\nDisplayUncompressedFrameType (\r\n                              PVIDEO_FRAME_UNCOMPRESSED UnCompFrameDesc\r\n                              );\r\nBOOL\r\nDisplayUnComContinuousFrameType(\r\n                                PVIDEO_FRAME_UNCOMPRESSED UContinuousDesc\r\n                                );\r\nBOOL\r\nDisplayUnComDiscreteFrameType(\r\n                              PVIDEO_FRAME_UNCOMPRESSED UDiscreteDesc\r\n                              );\r\nBOOL\r\nDisplayMJPEGFormat (\r\n                    PVIDEO_FORMAT_MJPEG MJPEGFormatDesc\r\n                    );\r\nBOOL\r\nDisplayMJPEGFrameType (\r\n                       PVIDEO_FRAME_MJPEG MJPEGFrameDesc\r\n                       );\r\nBOOL\r\nDisplayMJPEGContinuousFrameType(\r\n                                PVIDEO_FRAME_MJPEG MContinuousDesc\r\n                                );\r\nBOOL\r\nDisplayMJPEGDiscreteFrameType(\r\n                              PVIDEO_FRAME_MJPEG MDiscreteDesc\r\n                              );\r\nBOOL\r\nDisplayMPEG1SSFormat (\r\n                      PVIDEO_FORMAT_MPEG1SS MPEG1SSFormatDesc\r\n                      );\r\nBOOL\r\nDisplayMPEG2PSFormat (\r\n                      PVIDEO_FORMAT_MPEG2PS MPEG2PSFormatDesc\r\n                      );\r\nBOOL\r\nDisplayMPEG2TSFormat (\r\n                      PVIDEO_FORMAT_MPEG2TS MPEG2TSFormatDesc\r\n                      );\r\nBOOL\r\nDisplayMPEG4SLFormat (\r\n                      PVIDEO_FORMAT_MPEG4SL MPEG4SLFormatDesc\r\n                      );\r\nBOOL\r\nDisplayDVFormat (\r\n                 PVIDEO_FORMAT_DV DVFormatDesc\r\n                 );\r\nBOOL\r\nDisplayVendorVidFormat (\r\n                        PVIDEO_FORMAT_VENDOR VendorVidFormatDesc\r\n                        );\r\nBOOL\r\nDisplayVendorVidFrameType (\r\n                           PVIDEO_FRAME_VENDOR VendorVidFrameDesc\r\n                           );\r\nBOOL\r\nDisplayVendorVidContinuousFrameType(\r\n                                    PVIDEO_FRAME_VENDOR VContinuousDesc\r\n                                    );\r\nBOOL\r\nDisplayVendorVidDiscreteFrameType(\r\n                                  PVIDEO_FRAME_VENDOR VDiscreteDesc\r\n                                  );\r\nBOOL\r\nDisplayFramePayloadFormat(\r\n                          PVIDEO_FORMAT_FRAME FramePayloadFormatDesc\r\n                          );\r\nBOOL\r\nDisplayFramePayloadFrame(\r\n                         PVIDEO_FRAME_FRAME FramePayloadFrameDesc\r\n                         );\r\nBOOL\r\nDisplayFramePayloadContinuousFrameType(\r\n                                PVIDEO_FRAME_FRAME FContinuousDesc\r\n                                );\r\nBOOL\r\nDisplayFramePayloadDiscreteFrameType(\r\n                              PVIDEO_FRAME_FRAME FDiscreteDesc\r\n                              );\r\nBOOL\r\nDisplayStreamPayload(\r\n                     PVIDEO_FORMAT_STREAM StreamPayloadDesc\r\n                     );\r\nBOOL\r\nDisplayVSEndpoint (\r\n                   PVIDEO_CS_INTERRUPT VidEndpointDesc\r\n                   );\r\nVOID\r\nVDisplayBytes (\r\n               PUCHAR Data,\r\n               USHORT Len\r\n               );\r\nPCHAR\r\nVidFormatGUIDCodeToName (\r\n                         REFGUID VidFormatGUIDCode\r\n                         );\r\nUINT\r\nGetVCInterfaceSize (\r\n                    PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc\r\n                   );\r\nUINT\r\nCheckForColorMatchingDesc (\r\n                           PVIDEO_SPECIFIC FormatDesc,\r\n                           UCHAR bNumFrameDescriptors,\r\n                           UCHAR bDescriptorSubtype\r\n                          );\r\nUINT\r\nGetVSInterfaceSize (\r\n                    PUSB_COMMON_DESCRIPTOR VidInHeaderDesc,\r\n                    USHORT wTotalLength\r\n                   );\r\nBOOL\r\nValidateTerminalID(\r\n                   UINT uTerminalID\r\n                   );\r\nVOID\r\nVDisplayDescString (\r\n              UINT uControlSize,\r\n              PUCHAR pControl ,\r\n              PSTRINGLIST pslControl\r\n              );\r\n\r\n//*****************************************************************************\r\n// L O C A L    F U N C T I O N S\r\n//*****************************************************************************\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVideoDescriptor() UPDATED\r\n//\r\n// VidCommonDesc - An Video Class Descriptor\r\n//\r\n// bInterfaceSubClass - The SubClass of the Interface containing the descriptor\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVideoDescriptor (\r\n    PVIDEO_SPECIFIC VidCommonDesc,\r\n    UCHAR                        bInterfaceSubClass,\r\n    PSTRING_DESCRIPTOR_NODE      StringDescs,\r\n    DEVICE_POWER_STATE           LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVideoDescriptor -Class-Specific Video Descriptor\r\n    switch (VidCommonDesc->bDescriptorType)\r\n    {\r\n    case CS_INTERFACE:\r\n        //@@DisplayVideoDescriptor -Class-Specific Video Interface Descriptor\r\n        switch (bInterfaceSubClass)\r\n        {\r\n        case VIDEO_SUBCLASS_CONTROL:\r\n            //@@DisplayVideoDescriptor -Class-Specific Video Control Interface Descriptor\r\n            switch (VidCommonDesc->bDescriptorSubtype)\r\n            {\r\n            case VC_HEADER:\r\n                return DisplayVCHeader(\r\n                    (PVIDEO_CONTROL_HEADER_UNIT)VidCommonDesc);\r\n\r\n            case INPUT_TERMINAL:\r\n                return DisplayVCInputTerminal(\r\n                    (PVIDEO_INPUT_TERMINAL)VidCommonDesc,\r\n                    StringDescs,\r\n                    LatestDevicePowerState);\r\n\r\n            case OUTPUT_TERMINAL:\r\n                return DisplayVCOutputTerminal(\r\n                    (PVIDEO_OUTPUT_TERMINAL)VidCommonDesc,\r\n                    StringDescs,\r\n                    LatestDevicePowerState);\r\n\r\n            case SELECTOR_UNIT:\r\n                return DisplayVCSelectorUnit(\r\n                    (PVIDEO_SELECTOR_UNIT)VidCommonDesc,\r\n                    StringDescs,\r\n                    LatestDevicePowerState);\r\n\r\n            case PROCESSING_UNIT:\r\n                return DisplayVCProcessingUnit(\r\n                    (PVIDEO_PROCESSING_UNIT)VidCommonDesc,\r\n                    StringDescs,\r\n                    LatestDevicePowerState);\r\n\r\n            case EXTENSION_UNIT:\r\n                return DisplayVCExtensionUnit(\r\n                    (PVIDEO_EXTENSION_UNIT)VidCommonDesc,\r\n                    StringDescs,\r\n                    LatestDevicePowerState);\r\n\r\n#ifdef H264_SUPPORT\r\n            case H264_ENCODING_UNIT:\r\n                return DisplayVCH264EncodingUnit(\r\n                    (PVIDEO_ENCODING_UNIT)VidCommonDesc\r\n                    );\r\n\r\n#endif\r\n\r\n#ifdef H264_SUPPORT\r\n            case MAX_TYPE_UNIT+1:\r\n            // for H.264, the bDescriptorSubtype = 7, which is equal to MAX_TYPE_UNIT\r\n            // so now MAX_TYPE_UNIT needs to be set to 8\r\n            //(TODO: need to change nt\\sdpublic\\internal\\drivers\\inc\\uvcdesc.h's define\r\n            // of MAX_TYPE_UNIT from7 to 8, and ad the type for H.264 = 8)\r\n#else\r\n            case MAX_TYPE_UNIT:\r\n#endif\r\n                //@@TestCase B1.1\r\n                //@@CAUTION\r\n                //@@Descriptor Field - bDescriptorSubtype\r\n                //@@An undefined descriptor subtype has been defined\r\n                AppendTextBuffer(\"*!*CAUTION:  This is an undefined class specific \"\\\r\n                    \"Video Control bDescriptorSubtype\\r\\n\");\r\n                break;\r\n\r\n            default:\r\n                //@@TestCase B1.2\r\n                //@@ERROR\r\n                //@@Descriptor Field - bDescriptorSubtype\r\n                //@@An unknown descriptor subtype has been defined\r\n                AppendTextBuffer(\"*!*ERROR:  unknown bDescriptorSubtype\\r\\n\");\r\n                OOPS();\r\n                break;\r\n            }\r\n            break;\r\n\r\n        case VIDEO_SUBCLASS_STREAMING:\r\n            //@@DisplayVideoDescriptor -Class-Specific Video Streaming Interface Descriptor\r\n            switch (VidCommonDesc->bDescriptorSubtype)\r\n            {\r\n            case VS_INPUT_HEADER:\r\n                return DisplayVidInHeader(\r\n                    (PVIDEO_STREAMING_INPUT_HEADER)VidCommonDesc);\r\n\r\n            case VS_OUTPUT_HEADER:\r\n                return DisplayVidOutHeader(\r\n                    (PVIDEO_STREAMING_OUTPUT_HEADER)VidCommonDesc);\r\n\r\n            case VS_STILL_IMAGE_FRAME:\r\n                return DisplayStillImageFrame(\r\n                    (PVIDEO_STILL_IMAGE_FRAME)VidCommonDesc);\r\n\r\n            case VS_FORMAT_UNCOMPRESSED:\r\n#ifdef H264_SUPPORT\r\n                {\r\n                    BOOL retCode = DisplayUncompressedFormat( (PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc );\r\n                    g_expectedNumberOfUncompressedFrameFrameDescriptors += ((PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc)->bNumFrameDescriptors;\r\n                    return retCode;\r\n                }\r\n#else\r\n                return DisplayUncompressedFormat(\r\n                    (PVIDEO_FORMAT_UNCOMPRESSED)VidCommonDesc);\r\n#endif\r\n\r\n            case VS_FRAME_UNCOMPRESSED:\r\n#ifdef H264_SUPPORT\r\n                {\r\n                    BOOL retCode = DisplayUncompressedFrameType( (PVIDEO_FRAME_UNCOMPRESSED)VidCommonDesc );\r\n                    g_numberOfUncompressedFrameFrameDescriptors++;\r\n                    return retCode;\r\n                }\r\n#else\r\n                return DisplayUncompressedFrameType(\r\n                    (PVIDEO_FRAME_UNCOMPRESSED)VidCommonDesc);\r\n#endif\r\n\r\n#ifdef H264_SUPPORT\r\n            case VS_FORMAT_H264:\r\n                {\r\n                    BOOL retCode = DisplayVCH264Format( (PVIDEO_FORMAT_H264)VidCommonDesc );\r\n                    g_expectedNumberOfH264FrameDescriptors += ((PVIDEO_FORMAT_H264)VidCommonDesc)->bNumFrameDescriptors;\r\n                    return retCode;\r\n                }\r\n\r\n            case VS_FRAME_H264:\r\n                {\r\n                    BOOL  retCode = DisplayVCH264FrameType( (PVIDEO_FRAME_H264)VidCommonDesc );\r\n                    g_numberOfH264FrameDescriptors++;\r\n                    return retCode;\r\n                }\r\n#endif\r\n\r\n            case VS_FORMAT_MJPEG:\r\n#ifdef H264_SUPPORT // additional checks\r\n                {\r\n                    BOOL retCode = DisplayMJPEGFormat( (PVIDEO_FORMAT_MJPEG)VidCommonDesc );\r\n                    g_expectedNumberOfMJPEGFrameDescriptors += ((PVIDEO_FORMAT_MJPEG)VidCommonDesc)->bNumFrameDescriptors;\r\n                    return retCode;\r\n                }\r\n#else\r\n                return DisplayMJPEGFormat(\r\n                    (PVIDEO_FORMAT_MJPEG)VidCommonDesc);\r\n#endif\r\n\r\n            case VS_FRAME_MJPEG:\r\n#ifdef H264_SUPPORT\r\n                {\r\n                    BOOL  retCode = DisplayMJPEGFrameType( (PVIDEO_FRAME_MJPEG)VidCommonDesc );\r\n                    g_numberOfMJPEGFrameDescriptors++;\r\n                    return retCode;\r\n                }\r\n\r\n#else\r\n                return DisplayMJPEGFrameType(\r\n                    (PVIDEO_FRAME_MJPEG)VidCommonDesc);\r\n#endif\r\n\r\n\r\n\r\n            case VS_FORMAT_MPEG1:\r\n            {\r\n                if (UVC10 == g_chUVCversion)\r\n                {\r\n                    return DisplayMPEG1SSFormat(\r\n                        (PVIDEO_FORMAT_MPEG1SS)VidCommonDesc);\r\n                }\r\n                else // this format is obsoleted in UVC version >= 1.1\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR:  obsoleted bDescriptorSubtype\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FORMAT_MPEG2PS:\r\n            {\r\n                if (UVC10 == g_chUVCversion)\r\n                {\r\n                    return DisplayMPEG2PSFormat(\r\n                        (PVIDEO_FORMAT_MPEG2PS)VidCommonDesc);\r\n                }\r\n                else // this format is obsoleted in UVC version >= 1.1\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR:  obsoleted bDescriptorSubtype\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FORMAT_MPEG2TS:\r\n                return DisplayMPEG2TSFormat(\r\n                    (PVIDEO_FORMAT_MPEG2TS)VidCommonDesc);\r\n\r\n            case VS_FORMAT_MPEG4SL:\r\n            {\r\n                if (UVC10 == g_chUVCversion)\r\n                {\r\n                    return DisplayMPEG4SLFormat(\r\n                        (PVIDEO_FORMAT_MPEG4SL)VidCommonDesc);\r\n                }\r\n                else // this format is obsoleted in UVC version >= 1.1\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR:  obsoleted bDescriptorSubtype\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FORMAT_DV:\r\n                return DisplayDVFormat(\r\n                    (PVIDEO_FORMAT_DV)VidCommonDesc);\r\n\r\n            case VS_COLORFORMAT:\r\n                return DisplayColorMatching(\r\n                    (PVIDEO_COLORFORMAT)VidCommonDesc);\r\n\r\n            case VS_FORMAT_VENDOR:\r\n            {\r\n                if (UVC10 == g_chUVCversion)\r\n                {\r\n                     return DisplayVendorVidFormat(\r\n                        (PVIDEO_FORMAT_VENDOR)VidCommonDesc);\r\n                }\r\n                else // this format is obsoleted in UVC version >= 1.1\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR:  obsoleted bDescriptorSubtype\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FRAME_VENDOR:\r\n            {\r\n                if (UVC10 == g_chUVCversion)\r\n                {\r\n                    return DisplayVendorVidFrameType(\r\n                        (PVIDEO_FRAME_VENDOR)VidCommonDesc);\r\n                }\r\n                else // this format is obsoleted in UVC version >= 1.1\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR:  obsoleted bDescriptorSubtype\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FORMAT_FRAME_BASED:\r\n            {\r\n                if (UVC10 != g_chUVCversion)\r\n                {\r\n                    return DisplayFramePayloadFormat(\r\n                        (PVIDEO_FORMAT_FRAME)VidCommonDesc);\r\n                }\r\n                else // this format did not exist in UVC 1.0\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FRAME_FRAME_BASED:\r\n            {\r\n                if (UVC10 != g_chUVCversion)\r\n                {\r\n                    return DisplayFramePayloadFrame(\r\n                        (PVIDEO_FRAME_FRAME)VidCommonDesc);\r\n                }\r\n                else // this format did not exist in UVC 1.0\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_FORMAT_STREAM_BASED:\r\n            {\r\n                if (UVC10 != g_chUVCversion)\r\n                {\r\n                    return DisplayStreamPayload(\r\n                        (PVIDEO_FORMAT_STREAM)VidCommonDesc);\r\n                }\r\n                else // this format did not exist in UVC 1.0\r\n                {\r\n                    AppendTextBuffer(\"*!*ERROR: bDescriptorSubtype did not exist in UVC 1.0\\r\\n\");\r\n                    OOPS();\r\n                    break;\r\n                }\r\n            }\r\n\r\n            case VS_DESCRIPTOR_UNDEFINED:\r\n                //@@TestCase B1.3\r\n                //@@CAUTION\r\n                //@@Descriptor Field - bDescriptorSubtype\r\n                //@@An undefined descriptor subtype has been defined\r\n                AppendTextBuffer(\"*!*CAUTION:  This is an undefined class specific Video \"\\\r\n                    \"Streaming bDescriptorSubtype\\r\\n\");\r\n                break;\r\n\r\n            default:\r\n                //@@TestCase B1.4\r\n                //@@ERROR\r\n                //@@Descriptor Field - bDescriptorSubtype\r\n                //@@An unknown descriptor subtype has been defined\r\n                AppendTextBuffer(\"*!*ERROR:  unknown bDescriptorSubtype\\r\\n\");\r\n                OOPS();\r\n                break;\r\n            }\r\n            break;\r\n\r\n        default:\r\n            //@@TestCase B1.6\r\n            //@@ERROR\r\n            //@@Descriptor Field - bInterfaceSubClass\r\n            //@@An unknown interface sub-class has been defined\r\n            AppendTextBuffer(\"*!*ERROR:  unknown bInterfaceSubClass\\r\\n\");\r\n            OOPS();\r\n            break;\r\n        }\r\n        break;\r\n\r\n    case CS_ENDPOINT:\r\n        //@@DisplayVideoDescriptor -Class-Specific Video Endpoint Descriptor\r\n        switch (VidCommonDesc->bDescriptorSubtype)\r\n        {\r\n            //@@TestCase B1.7\r\n            //@@CAUTION\r\n            //@@Descriptor Field - bInterfaceSubtype\r\n            //@@An undefined descriptor subtype has been defined\r\n        case EP_UNDEFINED:\r\n            AppendTextBuffer(\"*!*CAUTION:  This is an undefined bDescriptorSubtype\\r\\n\");\r\n            break;\r\n            //@@TestCase B1.8\r\n            //@@Not yet implemented - Priority 3\r\n            //@@Descriptor Field - bDescriptorSubtype\r\n            //@@Question:  How valid are VIDEO_EP_GENERAL and VIDEO_EP_ENDPOINT?  Should we test?\r\n        case EP_GENERAL:\r\n            break;\r\n        case EP_ENDPOINT:\r\n            break;\r\n        case EP_INTERRUPT:\r\n            return DisplayVSEndpoint(\r\n                (PVIDEO_CS_INTERRUPT)VidCommonDesc);\r\n            break;\r\n        default:\r\n            //@@TestCase B1.9\r\n            //@@ERROR\r\n            //@@Descriptor Field - bDescriptorSubtype\r\n            //@@An unknown descriptor subtype has been defined\r\n            AppendTextBuffer(\"*!*CAUTION:  Unknown bDescriptorSubtype\");\r\n            break;\r\n        }\r\n        break;\r\n        //@@DisplayVideoDescriptor -Class-Specific Video Device Descriptor\r\n        //@@DisplayVideoDescriptor -Class-Specific Video Configuration Descriptor\r\n        //@@DisplayVideoDescriptor -Class-Specific Video String Descriptor\r\n        //@@DisplayVideoDescriptor -Class-Specific Video Undefined Descriptor\r\n        //@@TestCase B1.10\r\n        //@@Not yet implemented - Priority 3\r\n        //@@Descriptor -Class-Specific Device, Configuration, String, Undefined\r\n        //@@Descriptor Field - bDescriptorType\r\n        //@@Question:  How valid are these Descriptor Types?  Should we test?\r\n\r\n        /*        case USB_VIDEO_CS_DEVICE:\r\n        AppendTextBuffer(\"USB_VIDEO_CS_DEVICE bDescriptorType\\r\\n\");\r\n        break;\r\n\r\n        case USB_VIDEO_CS_CONFIGURATION:\r\n        AppendTextBuffer(\"USB_VIDEO_CS_CONFIGURATION bDescriptorType\\r\\n\");\r\n        break;\r\n\r\n        case USB_VIDEO_CS_STRING:\r\n        AppendTextBuffer(\"USB_VIDEO_CS_STRING bDescriptorType\\r\\n\");\r\n        break;\r\n\r\n        case USB_VIDEO_CS_UNDEFINED:\r\n        AppendTextBuffer(\"USB_VIDEO_CS_UNDEFINED bDescriptorType\\r\\n\");\r\n        break;\r\n        */\r\n    default:\r\n        //@@TestCase B1.11\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDescriptorType\r\n        //@@An unknown descriptor type has been defined\r\n        AppendTextBuffer(\"*!*CAUTION:  Unknown bDescriptorSubtype\");\r\n        OOPS();\r\n        break;\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCHeader()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCHeader (\r\n                 PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc\r\n                 )\r\n{\r\n    //@@DisplayVCHeader -Video Control Interface Header\r\n    UINT   i = 0;\r\n    UINT   uSize = 0;\r\n    PUCHAR pData = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Class-Specific Video Control Interface Header \"\\\r\n        \"Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VCInterfaceDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VCInterfaceDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VCInterfaceDesc->bDescriptorSubtype);\r\n    if ( UVC10 == g_chUVCversion )\r\n    {\r\n        AppendTextBuffer(\"bcdVDC:                          0x%04X\\r\\n\", VCInterfaceDesc->bcdVideoSpec);\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"bcdUVC:                          0x%04X\\r\\n\", VCInterfaceDesc->bcdVideoSpec);\r\n    }\r\n    AppendTextBuffer(\"wTotalLength:                    0x%04X\", VCInterfaceDesc->wTotalLength);\r\n\r\n    // Verify the total interface size (size of this header and all descriptors\r\n    //   following until and not including the first endpoint)\r\n    uSize = GetVCInterfaceSize(VCInterfaceDesc);\r\n    if (uSize != VCInterfaceDesc->wTotalLength) {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR: Invalid total interface size 0x%02X, should be 0x%02X\\r\\n\",\r\n            VCInterfaceDesc->wTotalLength, uSize);\r\n    } else {\r\n        AppendTextBuffer(\"  -> Validated\\r\\n\");\r\n    }\r\n    AppendTextBuffer(\"dwClockFreq:                 0x%08X\",\r\n        VCInterfaceDesc->dwClockFreq);\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\" = (%d) Hz\", VCInterfaceDesc->dwClockFreq);\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbInCollection:                     0x%02X\\r\\n\",\r\n        VCInterfaceDesc->bInCollection);\r\n\r\n    // baInterfaceNr is a variable length field\r\n    // Size is in bInCollection\r\n    for (i = 1, pData = (PUCHAR) &VCInterfaceDesc->bInCollection;\r\n        i <= VCInterfaceDesc->bInCollection; i++, pData++)\r\n    {\r\n        AppendTextBuffer(\"baInterfaceNr[%d]:                  0x%02X\\r\\n\",\r\n            i, *pData);\r\n    }\r\n\r\n    uSize = (sizeof(VIDEO_CONTROL_HEADER_UNIT) + VCInterfaceDesc->bInCollection);\r\n    if (VCInterfaceDesc->bLength != uSize)\r\n    {\r\n        //@@TestCase B2.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is less than required length in\r\n        //@@  the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            VCInterfaceDesc->bLength, uSize);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B2.2 (also in Descript.c)\r\n    //@@WARNING\r\n    //@@Descriptor Field - bcdVDC\r\n    //@@The bcdVDC version of the device is not the same as the version of used by USBView\r\n    if(VCInterfaceDesc->bcdVideoSpec < BCDVDC)\r\n    {\r\n        AppendTextBuffer(\"*!*WARNING: This device is set to the old USB Video \"\\\r\n            \"Class spec version 0x%04X\\r\\n\", VCInterfaceDesc->bcdVideoSpec);\r\n        OOPS();\r\n    }\r\n\r\n    if (VCInterfaceDesc->dwClockFreq < 1)\r\n    {\r\n        //@@TestCase B2.3 (Descript.c Line 70)\r\n        //@@WARNING\r\n        //@@dwClockFrequency should be greater than 0\r\n        //@@Question should we check that any non-zero value is accurate\r\n        AppendTextBuffer(\"*!*ERROR:  dwClockFreq must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B2.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - baInterfaceNr\r\n    //@@We should test to verify each interface number is valid?\r\n    //    for (i=0; i<VCInterfaceDesc->bInCollection; i++)\r\n    //      {AppendTextBuffer(\"baInterfaceNr[%d]:                  0x%02X\\r\\n\", i+1,\r\n    //        VCInterfaceDesc->baInterfaceNr[i]);}\r\n\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        switch(g_chUVCversion)\r\n        {\r\n        case UVC10:\r\n            AppendTextBuffer(\"USB Video Class device: spec version 1.0\\r\\n\");\r\n            break;\r\n        case UVC11:\r\n            AppendTextBuffer(\"USB Video Class device: spec version 1.1\\r\\n\");\r\n            break;\r\n#ifdef H264_SUPPORT\r\n        case UVC15:\r\n            AppendTextBuffer(\"USB Video Class device: spec version 1.5\\r\\n\");\r\n            break;\r\n#endif\r\n\r\n        default:\r\n            break;\r\n        }\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCInputTerminal()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCInputTerminal (\r\n    PVIDEO_INPUT_TERMINAL   VidITDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVCInputTerminal -Video Control Input Terminal\r\n    PCHAR pStr = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Input Terminal Descriptor<===\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidITDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidITDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidITDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bTerminalID:                       0x%02X\\r\\n\", VidITDesc->bTerminalID);\r\n    AppendTextBuffer(\"wTerminalType:                   0x%04X\", VidITDesc->wTerminalType);\r\n    if(gDoAnnotation)\r\n    {\r\n        pStr = GetStringFromList(slInputTermTypes,\r\n                sizeof(slInputTermTypes) / sizeof(STRINGLIST),\r\n                VidITDesc->wTerminalType,\r\n                \"Invalid Input Terminal Type\");\r\n        AppendTextBuffer(\" = (%s)\", pStr);\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\", VidITDesc->bAssocTerminal);\r\n    AppendTextBuffer(\"iTerminal:                         0x%02X\\r\\n\", VidITDesc->iTerminal);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (VidITDesc->iTerminal)\r\n        {\r\n            // if executing this code, the configuration descriptor has been\r\n            // obtained.  If a device is suspended, then its configuration\r\n            // descriptor was not obtained and we do not want errors to be\r\n            // displayed when string descriptors were not obtained.\r\n            DisplayStringDescriptor(VidITDesc->iTerminal, StringDescs, LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    if (VidITDesc->bLength < sizeof(VIDEO_INPUT_TERMINAL))\r\n    {\r\n        //@@TestCase B3.1  (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is less than required length in\r\n        //@@  the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d is too small\\r\\n\", VidITDesc->bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidITDesc->bTerminalID < 1)\r\n    {\r\n        //@@TestCase B3.2 (descript.c  line 133)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bTerminalID\r\n        //@@bTerminalID should be greater than 0\r\n        //@@Question: Should test to verify terminal number is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bTerminalID of %d is too small\\r\\n\", VidITDesc->bTerminalID);\r\n        OOPS();\r\n    }\r\n\r\n    if (!(pStr))\r\n    {\r\n        //@@TestCase B3.3\r\n        //@@CAUTION\r\n        //@@Descriptor Field - wTerminalType\r\n        //@@No valid Terminal Type was found\r\n        AppendTextBuffer(\"*!*CAUTION:  0x%04X is an unknown wTerminalType for an Input \"\\\r\n            \"Terminal\\r\\n\", VidITDesc->wTerminalType);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B3.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bAssocTerminal\r\n    //@@Should test to verify terminal number is valid?\r\n    //    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\", VidITDesc->bAssocTerminal);\r\n\r\n    switch (VidITDesc->wTerminalType)\r\n    {\r\n    case 0x0100:  // TT_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0101:  // TT_STREAMING Terminal Type\r\n        break;\r\n    case 0x0200:  // ITT_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0201:  // ITT_CAMERA Terminal Type\r\n        return DisplayVCCameraTerminal(\r\n            (PVIDEO_CAMERA_TERMINAL)VidITDesc);\r\n    case 0x0202:  // ITT_MEDIA_TRANSPORT_INPUT Terminal Type\r\n        return DisplayVCMediaTransInputTerminal(\r\n            (PVIDEO_INPUT_MTT)VidITDesc);\r\n    case 0x0400:  // EXTERNAL_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0401:  // COMPOSITE_CONNECTOR Terminal Type\r\n        break;\r\n    case 0x0402:  // SVIDEO_CONNECTOR Terminal Type\r\n        break;\r\n    case 0x0403:  // COMPONENT_CONNECTOR Terminal Type\r\n        break;\r\n    default:\r\n        break;\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCOutputTerminal()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCOutputTerminal (\r\n    PVIDEO_OUTPUT_TERMINAL  VidOTDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVCOutputTerminal -Video Control Output Terminal\r\n    PCHAR pStr = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Output Terminal Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidOTDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidOTDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidOTDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bTerminalID:                       0x%02X\\r\\n\", VidOTDesc->bTerminalID);\r\n    AppendTextBuffer(\"wTerminalType:                   0x%04X\", VidOTDesc->wTerminalType);\r\n    if(gDoAnnotation)\r\n    {\r\n        pStr = GetStringFromList(slOutputTermTypes,\r\n                sizeof(slOutputTermTypes) / sizeof(STRINGLIST),\r\n                VidOTDesc->wTerminalType,\r\n                \"Invalid Output Terminal Type\");\r\n        AppendTextBuffer(\" = (%s)\", pStr);\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\", VidOTDesc->bAssocTerminal);\r\n    AppendTextBuffer(\"bSourceID:                         0x%02X\\r\\n\", VidOTDesc->bSourceID);\r\n    AppendTextBuffer(\"iTerminal:                         0x%02X\\r\\n\", VidOTDesc->iTerminal);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (VidOTDesc->iTerminal)\r\n        {\r\n            // if executing this code, the configuration descriptor has been\r\n            // obtained.  If a device is suspended, then its configuration\r\n            // descriptor was not obtained and we do not want errors to be\r\n            // displayed when string descriptors were not obtained.\r\n            DisplayStringDescriptor(VidOTDesc->iTerminal, StringDescs, LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    if (VidOTDesc->bLength < sizeof(PVIDEO_OUTPUT_TERMINAL))\r\n    {\r\n        //@@TestCase B4.1  (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is less than required length in\r\n        //@@  the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d is too small\\r\\n\", VidOTDesc->bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidOTDesc->bTerminalID < 1)\r\n    {\r\n        //@@TestCase B4.2  (see Descript.c  line 328)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bTerminalID\r\n        //@@bTerminalID should be greater than 0\r\n        //@@Question: Should test to verify terminal number is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bTerminalID of %d is too small\\r\\n\", VidOTDesc->bTerminalID);\r\n        OOPS();\r\n    }\r\n\r\n\r\n    if (!(pStr))\r\n    {\r\n        //@@TestCase B4.3\r\n        //@@ERROR\r\n        //@@Descriptor Field - wTerminalType\r\n        //@@No valid Terminal Type was found\r\n        AppendTextBuffer(\"*!*ERROR:  0x%04X is an invalid wTerminalType for an Output Terminal\\r\\n\",\r\n            VidOTDesc->wTerminalType);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B4.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bAssocTerminal\r\n    //@@We should test to verify terminal number is valid\r\n    //    AppendTextBuffer(\"bAssocTerminal:                    0x%02X\\r\\n\", VidOTDesc->bAssocTerminal);\r\n\r\n    if (VidOTDesc->bSourceID < 1)\r\n    {\r\n        //@@TestCase B4.5  (see Descript.c  line 333)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bSourceID\r\n        //@@bSourceID should be greater than 0\r\n        //@@Question: Should test to verify source number is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bSourceID of %d is too small\\r\\n\", VidOTDesc->bSourceID);\r\n        OOPS();\r\n    }\r\n\r\n    switch (VidOTDesc->wTerminalType)\r\n    {\r\n    case 0x0100:  // TT_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0101:  // TT_STREAMING Terminal Type\r\n        break;\r\n    case 0x0300:  // OTT_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0301:  // OTT_DISPLAY Terminal Type\r\n        break;\r\n    case 0x0302:  // OTT_MEDIA_TRANSPORT_OUTPUT Terminal Type\r\n        return DisplayVCMediaTransOutputTerminal(\r\n            (PVIDEO_OUTPUT_MTT)VidOTDesc);\r\n    case 0x0400:  // EXTERNAL_VENDOR_SPECIFIC Terminal Type\r\n        break;\r\n    case 0x0401:  // COMPOSITE_CONNECTOR Terminal Type\r\n        break;\r\n    case 0x0402:  // SVIDEO_CONNECTOR Terminal Type\r\n        break;\r\n    case 0x0403:  // COMPONENT_CONNECTOR Terminal Type\r\n        break;\r\n    default:\r\n        break;\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCMediaTransInputTerminal()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCMediaTransInputTerminal(\r\n                                 PVIDEO_INPUT_MTT MediaTransportInDesc\r\n                                 )\r\n{\r\n    //@@DisplayVCMediaTransInputTerminal -Video Control Media Transport Input Terminal\r\n    UCHAR  p = 0;\r\n    PUCHAR pData = NULL;\r\n    size_t bLength = 0;\r\n\r\n    bLength = SizeOfVideoInputMTT(MediaTransportInDesc);\r\n\r\n    AppendTextBuffer(\"===>Additional Media Transport Input Terminal Data\\r\\n\");\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\",\r\n        MediaTransportInDesc->bControlSize);\r\n\r\n    // point to bControlSize\r\n    pData = & MediaTransportInDesc->bControlSize;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n        {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n            {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slMediaTransportControls,\r\n                    sizeof(slMediaTransportControls) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid MediaTransportCtrl bmControl value\"));\r\n\r\n            cMask = cMask << 1;\r\n            }\r\n    }\r\n\r\n    // point to bTransportModeSize\r\n    pData = pData + 2 ;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n        {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n            {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slMediaTransportModes1,\r\n                    sizeof(slMediaTransportModes1) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid MediaTransportMode value\"));\r\n\r\n            cMask = cMask << 1;\r\n            }\r\n\r\n        // Is there a second control?\r\n        if (1 < * pData)\r\n            {\r\n            // map the second control\r\n            for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 2);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes2,\r\n                        sizeof(slMediaTransportModes2) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a third control?\r\n        if (2 < * pData)\r\n            {\r\n            // map the third control\r\n            for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 3);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes3,\r\n                        sizeof(slMediaTransportModes3) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a fourth control?\r\n        if (3 < * pData)\r\n            {\r\n            // map the fourth control\r\n            for ( uBitIndex = 24, cMask = 1; uBitIndex < 32; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 4);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes4,\r\n                        sizeof(slMediaTransportModes4) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a fifth control?\r\n        if (4 < * pData)\r\n            {\r\n            // map the fifth control\r\n            for ( uBitIndex = 32, cMask = 1; uBitIndex < 40; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 5);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes5,\r\n                        sizeof(slMediaTransportModes5) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n    }\r\n\r\n    // The size of a Media Transport Descriptor is\r\n    //   the size of the Descriptor plus\r\n    //   (bControlSize - 1) plus\r\n    //   IF bmControls & 1 THEN 1 (bTransportModeSize) plus\r\n    //   bTransportModeSize\r\n    //\r\n//    p = sizeof(VIDEO_INPUT_MTT) +\r\n//        (MediaTransportInDesc->bControlSize - 1);\r\n//    if (MediaTransportInDesc->bmControls[0] & 1)\r\n//        p += 1 + (*pData);\r\n    if (MediaTransportInDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B5.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@Invalid Descriptor length\r\n        AppendTextBuffer(\"*!*ERROR:  Invalid descriptor bLength 0x%02X. \"\\\r\n            \"Should be 0x%02X\\r\\n\",\r\n            MediaTransportInDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCMediaTransOutputTerminal()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCMediaTransOutputTerminal(\r\n                                  PVIDEO_OUTPUT_MTT MediaTransportOutDesc\r\n                                  )\r\n{\r\n    //@@DisplayVCMediaTransOutputTerminal -Video Control Media Transport Output Terminal\r\n    UCHAR  p = 0;\r\n    PUCHAR pData = NULL;\r\n\r\n    AppendTextBuffer(\"===>Additional Media Transport Output Terminal Data\\r\\n\");\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\",\r\n        MediaTransportOutDesc->bControlSize);\r\n\r\n    // point to bControlSize\r\n    pData = & MediaTransportOutDesc->bControlSize;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n        {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n            {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slMediaTransportControls,\r\n                    sizeof(slMediaTransportControls) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid MediaTransportCtrl bmControl value\"));\r\n\r\n            cMask = cMask << 1;\r\n            }\r\n    }\r\n\r\n    // point to bTransportModeSize\r\n    pData = pData + 2 ;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n        {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n            {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slMediaTransportModes1,\r\n                    sizeof(slMediaTransportModes1) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid MediaTransportMode value\"));\r\n\r\n            cMask = cMask << 1;\r\n            }\r\n\r\n        // Is there a second control?\r\n        if (1 < * pData)\r\n            {\r\n            // map the second control\r\n            for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 2);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes2,\r\n                        sizeof(slMediaTransportModes2) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a third control?\r\n        if (2 < * pData)\r\n            {\r\n            // map the third control\r\n            for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 3);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes3,\r\n                        sizeof(slMediaTransportModes3) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a fourth control?\r\n        if (3 < * pData)\r\n            {\r\n            // map the fourth control\r\n            for ( uBitIndex = 24, cMask = 1; uBitIndex < 32; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 4);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes4,\r\n                        sizeof(slMediaTransportModes4) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a fifth control?\r\n        if (4 < * pData)\r\n            {\r\n            // map the fourth control\r\n            for ( uBitIndex = 32, cMask = 1; uBitIndex < 40; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 5);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slMediaTransportModes5,\r\n                        sizeof(slMediaTransportModes5) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid MediaTransportMode value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n    }\r\n\r\n    // The size of a Media Transport Descriptor is\r\n    //   the size of the Descriptor plus\r\n    //   (bControlSize - 1) plus\r\n    //   IF bmControls & 1 THEN 1 (bTransportModeSize) plus\r\n    //   bTransportModeSize\r\n    //\r\n    p = sizeof(VIDEO_OUTPUT_MTT) +\r\n        (MediaTransportOutDesc->bControlSize - 1);\r\n    if (MediaTransportOutDesc->bmControls[0] & 1)\r\n        p += 1 + (*pData);\r\n    if (MediaTransportOutDesc->bLength != p)\r\n    {\r\n        //@@TestCase B5.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@Invalid Descriptor length\r\n        AppendTextBuffer(\"*!*ERROR:  Invalid descriptor bLength 0x%02X. \"\\\r\n            \"Should be 0x%02X\\r\\n\",\r\n            MediaTransportOutDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCCameraTerminal()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCCameraTerminal(\r\n                        PVIDEO_CAMERA_TERMINAL CameraDesc\r\n                        )\r\n{\r\n    //@@DisplayVCCameraTerminal -Video Control Camera Terminal\r\n    UCHAR  p = 0;\r\n    PUCHAR pData = NULL;\r\n\r\n    AppendTextBuffer(\"===>Camera Input Terminal Data\\r\\n\");\r\n    AppendTextBuffer(\"wObjectiveFocalLengthMin:        0x%04X\\r\\n\", CameraDesc->wObjectiveFocalLengthMin);\r\n    AppendTextBuffer(\"wObjectiveFocalLengthMax:        0x%04X\\r\\n\", CameraDesc->wObjectiveFocalLengthMax);\r\n    AppendTextBuffer(\"wOcularFocalLength:              0x%04X\\r\\n\", CameraDesc->wOcularFocalLength);\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\", CameraDesc->bControlSize);\r\n\r\n    pData = &CameraDesc->bControlSize;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n        {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n            {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slCameraControl1,\r\n                    sizeof(slCameraControl1) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid CamCtrl bmControl value\"));\r\n\r\n            cMask = cMask << 1;\r\n            }\r\n\r\n        // Is there a second control?\r\n        if (1 < * pData)\r\n            {\r\n            // map the second control\r\n            for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 2);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slCameraControl2,\r\n                        sizeof(slCameraControl2) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid CamCtrl bmControl value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n        // Is there a third control?\r\n        if (2 < * pData)\r\n            {\r\n            // map the third control\r\n            for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + 3);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slCameraControl3,\r\n                        sizeof(slCameraControl3) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid CamCtrl bmControl value\"));\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n            }\r\n    }\r\n\r\n    p = (sizeof(VIDEO_CAMERA_TERMINAL) + CameraDesc->bControlSize);\r\n    if (CameraDesc->bLength != p)\r\n    {\r\n        //@@TestCase B7.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The descriptor should be the size of the descriptor structure\r\n        //@@  plus the number of controls\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            CameraDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B7.2\r\n    //@@Not yet implemented - Priority 3\r\n    //@@Descriptor Field - wObjectiveFocalLengthMin\r\n    //@@Question - Should we do any checking here?  What are the acceptable boundaries?\r\n    //@@Question - Is zero an acceptable value?\r\n    //    AppendTextBuffer(\"wObjectiveFocalLengthMin:        0x%04X\\r\\n\", CameraDesc->wObjectiveFocalLengthMin);\r\n\r\n    //@@TestCase B7.3\r\n    //@@Not yet implemented - Priority 3\r\n    //@@Descriptor Field - wObjectiveFocalLengthMax\r\n    //@@Question - Should we do any checking here?  What are the acceptable boundaries\r\n    //@@Question - Is zero an acceptable value?\r\n    //    AppendTextBuffer(\"wObjectiveFocalLengthMax:        0x%04X\\r\\n\", CameraDesc->wObjectiveFocalLengthMax);\r\n\r\n    //@@TestCase B7.4\r\n    //@@Not yet implemented - Priority 3\r\n    //@@Descriptor Field - wOcularFocalLength\r\n    //@@Question - Should we do any checking here?  What are the acceptable boundaries\r\n    //@@Question - Is zero an acceptable value?\r\n    //    AppendTextBuffer(\"wOcularFocalLength:              0x%04X\\r\\n\", CameraDesc->wOcularFocalLength);\r\n\r\n    //@@TestCase B7.5\r\n    //@@ERROR\r\n    //@@Descriptor Field - wObjectiveFocalLengthMin and wObjectiveFocalLengthMax\r\n    //@@Verify that wObjectiveFocalLengthMax is greater than wObjectiveFocalLengthMin\r\n    if(CameraDesc->wObjectiveFocalLengthMin > CameraDesc->wObjectiveFocalLengthMax)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  wObjectiveFocalLengthMin is larger than wObjectiveFocalLengthMax\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B7.6\r\n    //@@ERROR\r\n    //@@Descriptor Field - bControlSize\r\n    //@@Verify that wObjectiveFocalLengthMax is 3 or less\r\n    if(CameraDesc->bControlSize > 3)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  bControlSize must be 3 or less\\r\\n\");\r\n        OOPS();\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCSelectorUnit()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCSelectorUnit (\r\n    PVIDEO_SELECTOR_UNIT    VidSelectorDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVCSelectorUnit -Video Control Selector Unit\r\n    UCHAR  i = 0;\r\n    UCHAR  p = 0;\r\n    PUCHAR pData = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Selector Unit Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidSelectorDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidSelectorDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidSelectorDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\", VidSelectorDesc->bUnitID);\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\", VidSelectorDesc->bNrInPins);\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"===>List of Connected Unit and Terminal ID's\\r\\n\");\r\n    }\r\n    // baSourceID is a variable length field\r\n    // Size is in bNrInPins, must be at least 1 (so index starts at 1)\r\n    for (i = 1, pData = (PUCHAR) &VidSelectorDesc->baSourceID;\r\n        i <= VidSelectorDesc->bNrInPins; i++, pData++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n            i, *pData);\r\n    }\r\n\r\n    // get address of iSelector, the last field in this descriptor\r\n    pData = (PUCHAR) VidSelectorDesc + (VidSelectorDesc->bLength - 1);\r\n    AppendTextBuffer(\"iSelector:                         0x%02X\\r\\n\", *pData);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (*pData)\r\n        {\r\n            // if executing this code, the configuration descriptor has been\r\n            // obtained.  If a device is suspended, then its configuration\r\n            // descriptor was not obtained and we do not want errors to be\r\n            // displayed when string descriptors were not obtained.\r\n            DisplayStringDescriptor(*pData, StringDescs, LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    p = (sizeof(VIDEO_SELECTOR_UNIT) + VidSelectorDesc->bNrInPins + 1);\r\n    if (VidSelectorDesc->bLength != p)\r\n    {\r\n        //@@TestCase B8.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The descriptor should be the size of the descriptor structure plus the number of pins\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            VidSelectorDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidSelectorDesc->bUnitID < 1)\r\n    {\r\n        //@@TestCase B8.2 (Descript.c   Line 396)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bUnitID\r\n        //@@bUnitID must be greater than 0\r\n        //@@Question: Should we test to verify unit number is unique?\r\n        AppendTextBuffer(\"*!*ERROR:  bUnitID must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VidSelectorDesc->bNrInPins < 1)\r\n    {\r\n        //@@TestCase B8.3\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNrInPins\r\n        //@@bNrInPins should be greater than 0\r\n        //@@Question: Should test to verify total in pins is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bNrInPins must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    // baSourceID is a variable length field\r\n    // Size is in bNrInPins, must be at least 1 (so index starts at 1)\r\n    for (i = 1, pData = (PUCHAR) &VidSelectorDesc->baSourceID;\r\n        i <= VidSelectorDesc->bNrInPins; i++, pData++)\r\n    {\r\n        if (*pData < 1)\r\n        {\r\n            //@@TestCase B8.4\r\n            //@@ERROR\r\n            //@@Descriptor Field - baSourceID[]\r\n            //@@baSourceID should be greater than 0\r\n            AppendTextBuffer(\"*!*ERROR:  baSourceID[%d] must be non-zero\\r\\n\", i);\r\n            OOPS();\r\n        } else {\r\n            if (! ValidateTerminalID(*pData)) {\r\n            //@@TestCase B8.5\r\n            //@@ERROR\r\n            //@@Descriptor Field - baSourceID[]\r\n            //@@baSourceID should be a valid terminal ID\r\n            AppendTextBuffer(\"*!*ERROR:  baSourceID[%d] must be non-zero\\r\\n\", i);\r\n            OOPS();\r\n            }\r\n        }\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCProcessingUnit()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCProcessingUnit (\r\n    PVIDEO_PROCESSING_UNIT  VidProcessingDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVCProcessingUnit -Video Control Processor Unit\r\n    PUCHAR pData = NULL;\r\n    UCHAR  bLength = 0;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Processing Unit Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidProcessingDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidProcessingDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidProcessingDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\", VidProcessingDesc->bUnitID);\r\n    AppendTextBuffer(\"bSourceID:                         0x%02X\\r\\n\", VidProcessingDesc->bSourceID);\r\n    AppendTextBuffer(\"wMaxMultiplier:                  0x%04X\\r\\n\", VidProcessingDesc->wMaxMultiplier);\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\", VidProcessingDesc->bControlSize);\r\n\r\n    pData = &VidProcessingDesc->bControlSize;\r\n\r\n    // Are there any controls?\r\n    if (0 < * pData)\r\n    {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n        {\r\n            cCheckBit = cMask & *(pData + 1);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slProcessorControls1,\r\n                    sizeof(slProcessorControls1) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid PU bmControl value\"));\r\n\r\n            cMask = cMask << 1;\r\n        }\r\n\r\n        // Is there a second control?\r\n        if (1 < * pData)\r\n        {\r\n            // map the second control\r\n            for ( uBitIndex = 8, cMask = 1; uBitIndex < 16; uBitIndex++ )\r\n            {\r\n                cCheckBit = cMask & *(pData + 2);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slProcessorControls2,\r\n                        sizeof(slProcessorControls2) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid PU bmControl value\"));\r\n\r\n                cMask = cMask << 1;\r\n            }\r\n        }\r\n\r\n        // Is there a third control?\r\n        if (2 < * pData)\r\n        {\r\n            // map the third control\r\n            for ( uBitIndex = 16, cMask = 1; uBitIndex < 24; uBitIndex++ )\r\n            {\r\n                cCheckBit = cMask & *(pData + 3);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex,\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    GetStringFromList(slProcessorControls3,\r\n                        sizeof(slProcessorControls3) / sizeof(STRINGLIST),\r\n                        cMask,\r\n                        \"Invalid PU bmControl value\"));\r\n\r\n                cMask = cMask << 1;\r\n            }\r\n        }\r\n    }\r\n\r\n    // get address of iProcessing\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        // size of descriptor is struct size plus control size plus 2 if UVC11\r\n        bLength = sizeof(VIDEO_PROCESSING_UNIT) + 2 + VidProcessingDesc->bControlSize;\r\n        pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 2);\r\n    }\r\n    else // UVC 1.0\r\n    {\r\n        // size of descriptor is struct size plus control size plus 1 if UVC10\r\n        bLength = sizeof(VIDEO_PROCESSING_UNIT) + 1 + VidProcessingDesc->bControlSize;\r\n        pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 1);\r\n    }\r\n    AppendTextBuffer(\"iProcessing :                      0x%02X\\r\\n\", *pData);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (*pData)\r\n        {\r\n            // if executing this code, the configuration descriptor has been\r\n            // obtained.  If a device is suspended, then its configuration\r\n            // descriptor was not obtained and we do not want errors to be\r\n            // displayed when string descriptors were not obtained.\r\n            DisplayStringDescriptor(*pData, StringDescs, LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    // check for new UVC 1.1 bmVideoStandards fields\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        UINT  uBitIndex  = 0;\r\n        BYTE  cCheckBit = 0;\r\n        BYTE  cMask = 1;\r\n\r\n        pData = (PUCHAR) VidProcessingDesc + (VidProcessingDesc->bLength - 1);\r\n\r\n        AppendTextBuffer(\"bmVideoStandards :                 \");\r\n        VDisplayBytes(pData, 1);\r\n\r\n        // map the first control\r\n        for ( ; uBitIndex < 8; uBitIndex++ )\r\n        {\r\n            cCheckBit = cMask & *(pData);\r\n\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                uBitIndex,\r\n                cCheckBit ? 1 : 0,\r\n                cCheckBit ? \"yes - \" : \" no - \",\r\n                GetStringFromList(slProcessorVideoStandards,\r\n                    sizeof(slProcessorVideoStandards) / sizeof(STRINGLIST),\r\n                    cMask,\r\n                    \"Invalid PU bmVideoStandards value\"));\r\n\r\n            cMask = cMask << 1;\r\n        }\r\n    }\r\n\r\n    if (VidProcessingDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B9.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of 0x%02X incorrect, should be 0x%02X\\r\\n\",\r\n            VidProcessingDesc->bLength, bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidProcessingDesc->bUnitID < 1)\r\n    {\r\n        //@@TestCase B9.2 (Descript.c   Line 466)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bUnitID\r\n        //@@bUnitID must be greater than 0\r\n        //@@Question: Should we test to verify unit number is unique?\r\n        AppendTextBuffer(\"*!*ERROR:  bUnitID must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VidProcessingDesc->bSourceID < 1)\r\n    {\r\n        //@@TestCase B9.3 (Descript.c   Line 471)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bSourceID\r\n        //@@bSourceID must be non-zero\r\n        //@@Question: Should we test to verify the bSourceID is valid?\r\n        AppendTextBuffer(\"*!*ERROR:  bSourceID must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B9.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - wMaxMultiplier\r\n    //@@We should test to verify multiplier is valid\r\n    //    AppendTextBuffer(\"wMaxMultiplier:                  0x%04X\\r\\n\", VidProcessingDesc->wMaxMultiplier);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCExtensionUnit()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVCExtensionUnit (\r\n    PVIDEO_EXTENSION_UNIT   VidExtensionDesc,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n    )\r\n{\r\n    //@@DisplayVCExtensionUnit -Video Control Extension Unit\r\n    int     i = 0;\r\n    UCHAR   p = 0;\r\n    UCHAR   bControlSize = 0;\r\n    PUCHAR  pData = NULL;\r\n    OLECHAR szGUID[256];\r\n    size_t  bLength = 0;\r\n\r\n    bLength = SizeOfVideoExtensionUnit(VidExtensionDesc);\r\n\r\n    memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n    i = StringFromGUID2((REFGUID) &VidExtensionDesc->guidExtensionCode, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Extension Unit Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidExtensionDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidExtensionDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidExtensionDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X\\r\\n\", VidExtensionDesc->bUnitID);\r\n    AppendTextBuffer(\"guidExtensionCode:                 %S\\r\\n\", szGUID);\r\n    AppendTextBuffer(\"bNumControls:                      0x%02X\\r\\n\", VidExtensionDesc->bNumControls);\r\n    AppendTextBuffer(\"bNrInPins:                         0x%02X\\r\\n\", VidExtensionDesc->bNrInPins);\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"===>List of Connected Units and Terminal ID's\\r\\n\");\r\n    }\r\n    // baSourceID is a variable length field\r\n    // Size is in bNrInPins, must be at least 1 (so index starts at 1)\r\n    for (i = 1, pData = (PUCHAR) &VidExtensionDesc->baSourceID;\r\n        i <= VidExtensionDesc->bNrInPins; i++, pData++)\r\n    {\r\n        AppendTextBuffer(\"baSourceID[%d]:                     0x%02X\\r\\n\",\r\n            i, *pData);\r\n    }\r\n    // point to bControlSize (address of bNrInPins plus number of fields in bNrInPins\r\n    //   plus 1 for next field)\r\n    pData = &VidExtensionDesc->bNrInPins + VidExtensionDesc->bNrInPins +1;\r\n    bControlSize = *pData;\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\", bControlSize);\r\n\r\n    // Are there any controls?\r\n    if ( bControlSize > 0)\r\n    {\r\n        AppendTextBuffer(\"bmControls : \");\r\n        VDisplayBytes(pData + 1, *pData);\r\n\r\n        // Map one byte at a time of the bmControls field in the Video Control Extension Unit Descriptor\r\n        for (i = 1; i <= bControlSize; i++)\r\n        {\r\n            UINT  uBitIndex  = 0;\r\n            BYTE  cCheckBit = 0;\r\n            BYTE  cMask = 1;\r\n\r\n            // map byte\r\n            for ( ; uBitIndex < 8; uBitIndex++ )\r\n                {\r\n                cCheckBit = cMask & *(pData + i);\r\n\r\n                AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                    uBitIndex + 8 * (i-1),\r\n                    cCheckBit ? 1 : 0,\r\n                    cCheckBit ? \"yes - \" : \" no - \",\r\n                    \"Vendor-Specific (Optional)\");\r\n\r\n                cMask = cMask << 1;\r\n                }\r\n        }\r\n    }\r\n\r\n    // get address of iExtension\r\n    pData = &VidExtensionDesc->bNrInPins + VidExtensionDesc->bNrInPins + bControlSize + 2;\r\n//  pData = (PUCHAR) VidExtensionDesc + (VidExtensionDesc->bLength - 1);\r\n    AppendTextBuffer(\"iExtension:                        0x%02X\\r\\n\", *pData);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (*pData)\r\n        {\r\n            DisplayStringDescriptor(*pData,StringDescs, LatestDevicePowerState);\r\n        }\r\n    }\r\n\r\n    // size of descriptor struct size (23) + bNrInPins + bControlSize + iExtension size\r\n    //\r\n//  p = (sizeof(VIDEO_EXTENSION_UNIT)\r\n//      + VidExtensionDesc->bNrInPins + bControlSize + 1);\r\n    if (VidExtensionDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B10.1 (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the\r\n        //@@  required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of 0x%02X incorrect, should be 0x%02X\\r\\n\",\r\n            VidExtensionDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidExtensionDesc->bUnitID < 1)\r\n    {\r\n        //@@TestCase B10.2 (Descript.c  Line 517)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bUnitID\r\n        //@@bUnitID must be non-zero\r\n        //@@Question: Should we test to verify bUnitID is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bUnitID must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //bugbug do we need two\r\n    if (VidExtensionDesc->bNrInPins < 1)\r\n    {\r\n        //@@TestCase B10.3 (Descript.c  Line 522)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNrInPins\r\n        //@@bNrInPins must be non-zero\r\n        //@@Question: Should we test to verify bNrInPins is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bNrInPins must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    for (i = 1, pData = (PUCHAR) &VidExtensionDesc->baSourceID;\r\n        i <= VidExtensionDesc->bNrInPins; i++, pData++)\r\n    {\r\n        if (*pData == 0)\r\n        {\r\n            //@@TestCase B10.4  (Descript.c  Line 527)\r\n            //@@ERROR\r\n            //@@Descriptor Field - baSourceID[]\r\n            //@@baSourceID[] must be non-zero\r\n            //@@Question: Should we test to verify baSourceID is valid\r\n            AppendTextBuffer(\"*!*ERROR:  baSourceID[%d] must be non-zero\\r\\n\", *pData);\r\n            OOPS();\r\n        }\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVidInHeaderl()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVidInHeader (\r\n                    PVIDEO_STREAMING_INPUT_HEADER VidInHeaderDesc\r\n                    )\r\n{\r\n    //@@DisplayVidInHeader -Video Streaming Video Input Header\r\n    UINT   p = 0;\r\n    UINT   uCount = 0;\r\n    PUCHAR pData = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Class-Specific VS Video Input Header Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidInHeaderDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidInHeaderDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidInHeaderDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bNumFormats:                       0x%02X\\r\\n\", VidInHeaderDesc->bNumFormats);\r\n    AppendTextBuffer(\"wTotalLength:                    0x%04X\", VidInHeaderDesc->wTotalLength);\r\n\r\n    uCount = GetVSInterfaceSize((PUSB_COMMON_DESCRIPTOR) VidInHeaderDesc, VidInHeaderDesc->wTotalLength);\r\n    if (uCount != VidInHeaderDesc->wTotalLength) {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  invalid interface size 0x%02X, should be 0x%02X\\r\\n\",\r\n            VidInHeaderDesc->wTotalLength, uCount);\r\n    } else {\r\n        AppendTextBuffer(\"  -> Validated\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"bEndpointAddress:                  0x%02X\",\r\n        VidInHeaderDesc->bEndpointAddress);\r\n    if (USB_ENDPOINT_DIRECTION_IN(VidInHeaderDesc->bEndpointAddress))\r\n    {\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Direction: IN - EndpointID: %d\",\r\n                (VidInHeaderDesc->bEndpointAddress & 0x0F));\r\n        }\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n    AppendTextBuffer(\"bmInfo:                            0x%02X\", VidInHeaderDesc->bmInfo);\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"  -> Dynamic Format Change %sSupported\",\r\n            ! (VidInHeaderDesc->bmInfo & 0x01) ? \"not \" : \" \");\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbTerminalLink:                     0x%02X\\r\\n\",\r\n        VidInHeaderDesc->bTerminalLink);\r\n    AppendTextBuffer(\"bStillCaptureMethod:               0x%02X\",\r\n        VidInHeaderDesc->bStillCaptureMethod);\r\n\r\n    // globally save the StillMethod, then verify value\r\n    StillMethod = VidInHeaderDesc->bStillCaptureMethod;\r\n    if (StillMethod > 3)\r\n    {\r\n        //@@TestCase B11.1 (Descript.c Line 798)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bStillCaptureMethod\r\n        //@@bStillCaptureMethod is greater than 3\r\n        AppendTextBuffer(\"*!*ERROR:  invalid bStillCaptureMethod 0x%02X\\r\\n\",\r\n            VidInHeaderDesc->bStillCaptureMethod);\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Invalid Still Capture Method\");\r\n        }\r\n    }\r\n    else\r\n    {\r\n        if (0 == StillMethod)\r\n        {\r\n            AppendTextBuffer(\"  -> No Still Capture\");\r\n        }\r\n        else\r\n        {\r\n        AppendTextBuffer(\"  -> Still Capture Method %d\",\r\n            VidInHeaderDesc->bStillCaptureMethod);\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\nbTriggerSupport:                   0x%02X\",\r\n        VidInHeaderDesc->bTriggerSupport);\r\n    if(gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"  -> \");\r\n        if (! VidInHeaderDesc->bTriggerSupport)\r\n            AppendTextBuffer(\"No \");\r\n        AppendTextBuffer(\"Hardware Triggering Support\");\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    AppendTextBuffer(\"bTriggerUsage:                     0x%02X\",\r\n        VidInHeaderDesc->bTriggerUsage);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (VidInHeaderDesc->bTriggerSupport != 0)\r\n            {\r\n            if (VidInHeaderDesc->bTriggerUsage == 0)\r\n                AppendTextBuffer(\"  -> Host will initiate still image capture\");\r\n            if (VidInHeaderDesc->bTriggerUsage == 1)\r\n                AppendTextBuffer(\"  -> Host will notify client application of button event\");\r\n        }\r\n    }\r\n\r\n    AppendTextBuffer(\"\\r\\nbControlSize:                      0x%02X\\r\\n\",\r\n        VidInHeaderDesc->bControlSize);\r\n\r\n    // are there formats to display?\r\n    if (VidInHeaderDesc->bNumFormats)\r\n    {\r\n        UINT   uFormatIndex  = 1;\r\n        UINT   uBitIndex  = 0;\r\n        BYTE   cCheckBit = 0;\r\n        BYTE   cMask = 1;\r\n\r\n        // There are (bNumFormats) bmaControls fields, each with size (bControlSize)\r\n        pData = (PUCHAR) &(VidInHeaderDesc->bControlSize);\r\n\r\n        // VidInHeaderDesc->bNumFormats  -> number of formats\r\n        // VidInHeaderDesc->bControlSize -> size of EACH format control\r\n        // ((PUCHAR) &VidInHeaderDesc->bControlSize) + 1 -> address of first format control\r\n        for ( pData++ ; uFormatIndex <= VidInHeaderDesc->bNumFormats; uFormatIndex++ )\r\n            {\r\n            AppendTextBuffer(\"Video Payload Format %d             \", uFormatIndex);\r\n\r\n            // Handle case of 0 control size\r\n            if (! VidInHeaderDesc->bControlSize)\r\n                {\r\n                AppendTextBuffer(\"0x00\\r\\n\");\r\n                }\r\n            else\r\n                {\r\n                VDisplayBytes(pData, VidInHeaderDesc->bControlSize);\r\n\r\n                // map the first control\r\n                for (uBitIndex  = 0, cMask = 1; uBitIndex < 8; uBitIndex++ )\r\n                    {\r\n                    cCheckBit = cMask & *(pData);\r\n\r\n                    AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                        uBitIndex,\r\n                        cCheckBit ? 1 : 0,\r\n                        cCheckBit ? \"yes - \" : \" no - \",\r\n                        GetStringFromList(slInputHeaderControls,\r\n                            sizeof(slInputHeaderControls) / sizeof(STRINGLIST),\r\n                            cMask,\r\n                            \"Invalid Control value\"));\r\n\r\n                    cMask = cMask << 1;\r\n                    }\r\n                }\r\n            pData += VidInHeaderDesc->bControlSize;\r\n            }\r\n    }\r\n\r\n    p = (sizeof(VIDEO_STREAMING_INPUT_HEADER) +\r\n        (VidInHeaderDesc->bNumFormats * VidInHeaderDesc->bControlSize));\r\n    if (VidInHeaderDesc->bLength != p)\r\n    {\r\n        //@@TestCase B11.2  (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The descriptor should be the size of the descriptor structure\r\n        //@@  plus the number of formats times the size of each format\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            VidInHeaderDesc->bLength, p);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidInHeaderDesc->bNumFormats < 1)\r\n    {\r\n        //@@TestCase B11.3 (Descript.c  Line778)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFormats\r\n        //@@bNumFormats must be non-zero\r\n        //@@Question: Should we test to verify the non-zero value for bNumFormats is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFormats must be non-zero\\r\\n\",\r\n            VidInHeaderDesc->bNumFormats);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidInHeaderDesc->bEndpointAddress < 1)\r\n    {\r\n        //@@TestCase B11.4  (Descript.c  Line788)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bEndpointAddress\r\n        //@@bEndpointAddress should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bEndpointAddress is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bEndpointAddress of %d is too small\\r\\n\",\r\n            VidInHeaderDesc->bEndpointAddress);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B11.5\r\n    //@@ERROR\r\n    //@@Descriptor Field - bEndPointAddress\r\n    //@@The bEndPointAddress is set incorrectly according to the USB Video Device Specification\r\n    if (!USB_ENDPOINT_DIRECTION_IN(VidInHeaderDesc->bEndpointAddress)){\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  bEndPointAddress needs to have the Direction IN for this header\\r\\n\");\r\n        OOPS();}\r\n\r\n    //@@TestCase B11.6\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bmInfo\r\n    //@@We should validate that reserved bits are set to zero.\r\n    //    AppendTextBuffer(\"bmInfo:                            0x%02X\", VidInHeaderDesc->bmInfo);\r\n\r\n    if (VidInHeaderDesc->bTerminalLink < 1)\r\n    {\r\n        //@@TestCase B11.7 (Descript.c  Line 793)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bTerminalLink\r\n        //@@bTerminalLink should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bTerminalLink is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bTerminalLink of %d is too small\\r\\n\",\r\n            VidInHeaderDesc->bTerminalLink);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B11.8\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bTriggerSupport\r\n    //@@We should validate that reserved bits are set to zero.\r\n    //    AppendTextBuffer(\"bTriggerSupport:                   0x%02X\", VidInHeaderDesc->bTriggerSupport);\r\n\r\n    //@@TestCase B11.9\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bTriggerUsage\r\n    //@@We should validate that reserved bits are set to zero.\r\n    //    AppendTextBuffer(\"bTriggerUsage:                     0x%02X\", VidInHeaderDesc->bTriggerUsage);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVidOutHeader()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVidOutHeader (\r\n                     PVIDEO_STREAMING_OUTPUT_HEADER VidOutHeaderDesc\r\n                     )\r\n{\r\n    //@@DisplayVidOutHeader -Video Streaming Video Output Header\r\n    UINT  uCount = 0;\r\n    UCHAR bLength = sizeof(VIDEO_STREAMING_OUTPUT_HEADER);\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Class-Specific VS Video Output Header Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VidOutHeaderDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidOutHeaderDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidOutHeaderDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bNumFormats:                       0x%02X\\r\\n\", VidOutHeaderDesc->bNumFormats);\r\n    AppendTextBuffer(\"wTotalLength:                    0x%04X\", VidOutHeaderDesc->wTotalLength);\r\n\r\n    uCount = GetVSInterfaceSize((PUSB_COMMON_DESCRIPTOR) VidOutHeaderDesc, VidOutHeaderDesc->wTotalLength);\r\n    if (uCount != VidOutHeaderDesc->wTotalLength) {\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  invalid interface size 0x%02X, should be 0x%02X\\r\\n\",\r\n            VidOutHeaderDesc->wTotalLength, uCount);\r\n    } else {\r\n        AppendTextBuffer(\"  -> Validated\\r\\n\");\r\n    }\r\n\r\n    AppendTextBuffer(\"bEndpointAddress:                  0x%02X\", VidOutHeaderDesc->bEndpointAddress);\r\n    if(USB_ENDPOINT_DIRECTION_OUT(VidOutHeaderDesc->bEndpointAddress)) {\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Direction: OUT - EndpointID: %d\",\r\n                (VidOutHeaderDesc->bEndpointAddress & 0x0F));\r\n        }\r\n        AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    AppendTextBuffer(\"bTerminalLink:                     0x%02X\\r\\n\", VidOutHeaderDesc->bTerminalLink);\r\n\r\n    // UVC11 Video Output Header has additional fields, larger size\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n#endif\r\n    {\r\n        UCHAR   bControlSize = 0;\r\n        PUCHAR  pControls = NULL;\r\n\r\n        // bControlSize field is next after bTerminalLink\r\n        pControls = &(VidOutHeaderDesc->bTerminalLink)+1;\r\n        bControlSize = *(pControls);\r\n        // point to first bmaControls\r\n        pControls++;\r\n\r\n        // Size of UVC 1.1 Video Output Header is 1.0 size\r\n        //  plus 1 (bControlSize field) plus (number of formats * bControlSize)\r\n        bLength += 1 + (VidOutHeaderDesc->bNumFormats * bControlSize);\r\n\r\n        // Need new uvcdesc.h to handle new fields\r\n        AppendTextBuffer(\"bControlSize:                      0x%02X\\r\\n\", bControlSize);\r\n\r\n        // are there formats to display?\r\n        if (VidOutHeaderDesc->bNumFormats)\r\n        {\r\n            UINT   uFormatIndex  = 1;\r\n            UINT   uBitIndex  = 0;\r\n            BYTE   cCheckBit = 0;\r\n            BYTE   cMask = 1;\r\n\r\n            // There are (bNumFormats) bmaControls fields, each with size (bControlSize)\r\n            for ( ; uFormatIndex <= VidOutHeaderDesc->bNumFormats; uFormatIndex++, pControls ++)\r\n            {\r\n                AppendTextBuffer(\"Video Payload Format %d             \", uFormatIndex);\r\n\r\n                // Handle case of 0 control size\r\n                if (0 == bControlSize)\r\n                {\r\n                    AppendTextBuffer(\"0x00\\r\\n\");\r\n                }\r\n                else\r\n                {\r\n                    VDisplayBytes(pControls, bControlSize);\r\n\r\n                    // map the first control\r\n                    for (uBitIndex  = 0, cMask = 1; uBitIndex < 8; uBitIndex++ )\r\n                    {\r\n                        cCheckBit = cMask & *(pControls);\r\n\r\n                        AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                            uBitIndex,\r\n                            cCheckBit ? 1 : 0,\r\n                            cCheckBit ? \"yes - \" : \" no - \",\r\n                            GetStringFromList(slOutputHeaderControls,\r\n                                sizeof(slOutputHeaderControls) / sizeof(STRINGLIST),\r\n                                cMask,\r\n                                \"Invalid control value\"));\r\n\r\n                        cMask = cMask << 1;\r\n                    }\r\n                }\r\n            } // for ( pData++ ; uFormatIndex <= VidOutHeaderDesc->bNumFormats; uFormatIndex++ )\r\n        } // if (VidOutHeaderDesc->bNumFormats)\r\n    } // if (UVC11 == g_chUVCversion)\r\n\r\n    if (VidOutHeaderDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B12.1  (also in Descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the\r\n        //@@  required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            VidOutHeaderDesc->bLength,\r\n            sizeof(VIDEO_STREAMING_OUTPUT_HEADER));\r\n        OOPS();\r\n    }\r\n\r\n    if (VidOutHeaderDesc->bNumFormats < 1)\r\n    {\r\n        //@@TestCase B12.2 (Descript.c  Line 827)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFormats\r\n        //@@bNumFormats should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bNumFormats is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFormats of %d is too small\\r\\n\",\r\n            VidOutHeaderDesc->bNumFormats);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidOutHeaderDesc->wTotalLength < VidOutHeaderDesc->bLength)\r\n    {\r\n        //@@TestCase B12.3 (Descript.c  Line 832)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wTotalLength\r\n        //@@wTotalLength should be greater than bLength\r\n        //@@Question: Should we calculate wTotalLength to verify the value is valid\r\n        AppendTextBuffer(\"*!*ERROR:  wTotalLength of %d is small than the bLength of %d\\r\\n\",\r\n            VidOutHeaderDesc->wTotalLength,\r\n            VidOutHeaderDesc->bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (VidOutHeaderDesc->bEndpointAddress < 1)\r\n    {\r\n        //@@TestCase B12.4  (Descript.c  Line 837)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bEndpointAddress\r\n        //@@bEndpointAddress should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bEndpointAddress is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bEndpointAddress of %d is too small\\r\\n\",\r\n            VidOutHeaderDesc->bEndpointAddress);\r\n        OOPS();\r\n    }\r\n\r\n    if(!(USB_ENDPOINT_DIRECTION_OUT(VidOutHeaderDesc->bEndpointAddress))) {\r\n        //@@TestCase B12.5\r\n        //@@ERROR\r\n        //@@Descriptor Field - bEndPointAddress\r\n        //@@The bEndPointAddress is set for the wrong direction\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  bEndPointAddress needs to have the Direction OUT for this header\\r\\n\");\r\n        OOPS();}\r\n\r\n    if (VidOutHeaderDesc->bTerminalLink < 1)\r\n    {\r\n        //@@TestCase B12.6 (Descript.c  Line 842)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bTerminalLink\r\n        //@@bTerminalLink should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bTerminalLink is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bTerminalLink of %d is too small\\r\\n\",\r\n            VidOutHeaderDesc->bTerminalLink);\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayStillImageFrame()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayStillImageFrame (\r\n                        PVIDEO_STILL_IMAGE_FRAME StillFrameDesc\r\n                        )\r\n{\r\n    //@@DisplayStillImageFrame -Still Image Frame\r\n    VIDEO_STILL_IMAGE_RECT  * pXY;\r\n    PUCHAR      pbCurr = NULL;\r\n    UINT        i = 0;\r\n    UINT        uNumComp = 0;\r\n    UINT        uSize = 0;\r\n    size_t      bLength = 0;\r\n\r\n    bLength = SizeOfVideoStillImageFrame(StillFrameDesc);\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Still Image Frame Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", StillFrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", StillFrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", StillFrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bEndpointAddress:                  0x%02X\\r\\n\", StillFrameDesc->bEndpointAddress);\r\n    AppendTextBuffer(\"bNumImageSizePatterns:             0x%02X\\r\\n\",\r\n        StillFrameDesc->bNumImageSizePatterns);\r\n    if (StillFrameDesc->bNumImageSizePatterns < 1)\r\n    {\r\n        //@@TestCase B13.1 (also Descript.c Line 886)\r\n        //@@Not yet implemented - Priority 1\r\n        //@@Descriptor Field - bNumImageSizePatterns\r\n        //@@The bNumImageSizePatterns should be greater than 0\r\n        //@@Question: Should we test to verify the non-zero value for bNumImageSizePatterns is valid\r\n        AppendTextBuffer(\"*!*ERROR:  bNumImageSizePatterns must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    // point to first StillFrameDesc->dwStillImage structure\r\n    pXY = (VIDEO_STILL_IMAGE_RECT *) &StillFrameDesc->aStillRect[0];\r\n\r\n    for (i = 1; i <= StillFrameDesc->bNumImageSizePatterns; i++, pXY++)\r\n    {\r\n        AppendTextBuffer(\"wWidth[%d]:                       0x%04X\\r\\n\",\r\n            i, pXY->wWidth);\r\n        AppendTextBuffer(\"wHeight[%d]:                      0x%04X\\r\\n\",\r\n            i, pXY->wHeight);\r\n    }\r\n    // point to bNumCompressionPattern field (after variable count field dwStillImage)\r\n    pbCurr = (PUCHAR) pXY;\r\n    // get number of compression patterns\r\n    uNumComp = *pbCurr;\r\n\r\n    AppendTextBuffer(\"bNumCompressionPattern:            0x%02X\\r\\n\", *pbCurr++);\r\n    for (i = 1; i <= uNumComp; i++)\r\n    {\r\n        AppendTextBuffer(\"bCompression[%d]:                   0x%02X\\r\\n\",\r\n            i, *pbCurr++);\r\n    }\r\n\r\n    switch(StillMethod) {\r\n        case 0:\r\n            //@@TestCase B13.2\r\n            //@@ERROR\r\n            //@@Descriptor Field - Still Image Frame Type Descriptor\r\n            //@@An still method type has been defined that shouldn't use a Still Image Frame\r\n            AppendTextBuffer(\"*!*ERROR:  VS Video Input Header set to \"\\\r\n                \"No Still Method support\\r\\n\");\r\n            OOPS();\r\n        case 1:\r\n            //@@TestCase B13.3\r\n            //@@ERROR\r\n            //@@Descriptor Field - Still Image Frame Type Descriptor\r\n            //@@An still method type has been defined that shouldn't use a Still Image Frame\r\n            AppendTextBuffer(\"*!*ERROR:  VS Video Input Header set to \"\\\r\n                \"Still Method One support with a Still Image Frame descriptor\\r\\n\");\r\n            OOPS();\r\n        default:\r\n            break;}\r\n\r\n    if (StillFrameDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B13.4 (Also in descript.c)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is incorrect\r\n        AppendTextBuffer(\"*!*ERROR:  bLength 0x%02X incorrect, should be 0x%02X\\r\\n\",\r\n            StillFrameDesc->bLength, uSize);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B13.5\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bEndpointAddress\r\n    //@@Should test to verify endpoint validity\r\n    //    AppendTextBuffer(\"bEndpointAddress:                  0x%02X\", StillFrameDesc->bEndpointAddress);\r\n\r\n    if(USB_ENDPOINT_DIRECTION_IN(StillFrameDesc->bEndpointAddress) && StillMethod==3){\r\n        if((StillFrameDesc->bEndpointAddress) == 0){\r\n            //@@TestCase B13.6\r\n            //@@ERROR\r\n            //@@Descriptor Field - bEndPointAddress\r\n            //@@bEndPointAddress should be non-zero for 0 when using StillMethod 3\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  bEndpointAddress is reported as %d.  \"\\\r\n                \"This should be non-zero when using StillMethod 3.\\r\\n\",\r\n                (StillFrameDesc->bEndpointAddress));\r\n            OOPS(); }\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Direction: IN - EndpointID: %d\",\r\n                (StillFrameDesc->bEndpointAddress & 0x0F));\r\n        }\r\n        AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    else if(USB_ENDPOINT_DIRECTION_OUT(StillFrameDesc->bEndpointAddress) && StillMethod==2) {\r\n        if((StillFrameDesc->bEndpointAddress & 0x0F) != 0) {\r\n            //@@TestCase B13.7\r\n            //@@ERROR\r\n            //@@Descriptor Field - bEndPointAddress\r\n            //@@The EndpointID of bEndPointAddress should be set for 0 when using StillMethod 2\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  The EndpointID of the \"\\\r\n                \"bEndpointAddress is reported as %d.  This should be 0.\\r\\n\",\r\n                (StillFrameDesc->bEndpointAddress & 0x0F));\r\n            OOPS(); }\r\n        else {AppendTextBuffer(\"\\r\\n\");}}\r\n    else if (StillFrameDesc->bEndpointAddress != 0) {\r\n        //@@TestCase B13.8\r\n        //@@ERROR\r\n        //@@Descriptor Field - bEndPointAddress\r\n        //@@The bEndPointAddress should be set for 0 when not using StillMethod 2 or 3\r\n        AppendTextBuffer(\"\\r\\n*!*ERROR:  bEndPointAddress should be 0.\\r\\n\");\r\n        OOPS(); }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayColorMatching()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayColorMatching (\r\n                      PVIDEO_COLORFORMAT ColorMatchDesc\r\n                      )\r\n{\r\n    //@@DisplayColorMatching -Color Matching\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Color Matching Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", ColorMatchDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", ColorMatchDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", ColorMatchDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bColorPrimaries:                   0x%02X\\r\\n\", ColorMatchDesc->bColorPrimaries);\r\n    AppendTextBuffer(\"bTransferCharacteristics:          0x%02X\\r\\n\", ColorMatchDesc->bTransferCharacteristics);\r\n    AppendTextBuffer(\"bMatrixCoefficients:               0x%02X\\r\\n\", ColorMatchDesc->bMatrixCoefficients);\r\n\r\n    if (ColorMatchDesc->bLength != sizeof(VIDEO_COLORFORMAT))\r\n    {\r\n        //@@TestCase B14.1 (Descript.c Line 1596)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            ColorMatchDesc->bLength,\r\n            sizeof(VIDEO_COLORFORMAT));\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B14.2\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bColorPrimaries\r\n    //@@Question - Should we test to verify bColorPrimaries\r\n    //    AppendTextBuffer(\"bColorPrimaries:                   0x%02X\\r\\n\", ColorMatchDesc->bColorPrimaries);\r\n\r\n    //@@TestCase B14.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bTransferCharacteristics\r\n    //@@Question - Should we test to verify bTransferCharacteristics\r\n    //    AppendTextBuffer(\"bTransferCharacteristics:          0x%02X\\r\\n\", ColorMatchDesc->bTransferCharacteristics);\r\n\r\n    //@@TestCase B14.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bMatrixCoefficients\r\n    //@@Question - Should we test to verify bMatrixCoefficients\r\n    //    AppendTextBuffer(\"bMatrixCoefficients:               0x%02X\\r\\n\", ColorMatchDesc->bMatrixCoefficients);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayUncompressedFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayUncompressedFormat (\r\n                           PVIDEO_FORMAT_UNCOMPRESSED UnCompFormatDesc\r\n                           )\r\n{\r\n    //@@DisplayUncompressedFormat - Uncompressed Format\r\n    int i = 0;\r\n    PCHAR pStr = NULL;\r\n    OLECHAR szGUID[256];\r\n\r\n    // Initialize the default Frame\r\n    g_chUNCFrameDefault = UnCompFormatDesc->bDefaultFrameIndex;\r\n\r\n    memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n    i = StringFromGUID2((REFGUID) &UnCompFormatDesc->guidFormat, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Uncompressed Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", UnCompFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", UnCompFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", UnCompFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", UnCompFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bNumFrameDescriptors:              0x%02X\\r\\n\", UnCompFormatDesc->bNumFrameDescriptors);\r\n    AppendTextBuffer(\"guidFormat:                        %S\", szGUID);\r\n\r\n    pStr = VidFormatGUIDCodeToName((REFGUID) &UnCompFormatDesc->guidFormat);\r\n    if ( pStr )\r\n    {\r\n        if ( gDoAnnotation )\r\n        {\r\n            AppendTextBuffer(\" = %s Format\", pStr);\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n    AppendTextBuffer(\"bBitsPerPixel:                     0x%02X\\r\\n\", UnCompFormatDesc->bBitsPerPixel);\r\n    AppendTextBuffer(\"bDefaultFrameIndex:                0x%02X\\r\\n\", UnCompFormatDesc->bDefaultFrameIndex);\r\n\r\n    if (UnCompFormatDesc->bLength != sizeof(VIDEO_FORMAT_UNCOMPRESSED))\r\n    {\r\n        //@@TestCase B15.1 (descript.c line 925)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required\r\n        //@@length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            UnCompFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_UNCOMPRESSED));\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B15.2 (descript.c line 930)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bFormatIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFormatDesc->bNumFrameDescriptors == 0 )\r\n    {\r\n        //@@TestCase B15.3 (descript.c line 930)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFrameDescriptors\r\n        //@@bNumFrameDescriptors is set to zero which is not in accordance with the\r\n        //@@USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFrameDescriptors = 0, must have at least 1 Frame descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(!(pStr))\r\n    {\r\n        //@@TestCase B15.4\r\n        //@@WARNING\r\n        //@@Descriptor Field - guidFormat\r\n        //@@guidFormat is set to unknown or undefined format\r\n        AppendTextBuffer(\"\\r\\n*!*WARNING:  guidFormat is an unknown format\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFormatDesc->bBitsPerPixel == 0 )\r\n    {\r\n        //@@TestCase B15.5 (descript.c line 940)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bBitsPerPixel\r\n        //@@bBitsPerPixel is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bBitsPerPixel = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFormatDesc->bDefaultFrameIndex == 0 || UnCompFormatDesc->bDefaultFrameIndex >\r\n        UnCompFormatDesc->bNumFrameDescriptors)\r\n    {\r\n        //@@TestCase B15.6 (desctipt.c line 945)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDefaultFrameIndex\r\n        //@@The value for bDefaultFrameIndex is not greater than 0 or less than or equal to bNumFrameDescriptors\r\n        AppendTextBuffer(\"*!*ERROR:  The value %d for the bDefaultFrameIndex is out of range, this invalidates the descriptor\\r\\n*!*The proper range is 1 to %d)\",\r\n            UnCompFormatDesc->bDefaultFrameIndex,\r\n            UnCompFormatDesc->bNumFrameDescriptors);\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bAspectRatioX:                     0x%02X\\r\\n\",\r\n        UnCompFormatDesc->bAspectRatioX);\r\n    AppendTextBuffer(\"bAspectRatioY:                     0x%02X\",\r\n        UnCompFormatDesc->bAspectRatioY);\r\n\r\n    if (((UnCompFormatDesc->bmInterlaceFlags & 0x01) &&\r\n        (UnCompFormatDesc->bAspectRatioY != 0 &&\r\n        UnCompFormatDesc->bAspectRatioX != 0)))\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Aspect Ratio is set for a %d:%d display\",\r\n                (UnCompFormatDesc->bAspectRatioX),(UnCompFormatDesc->bAspectRatioY));\r\n        }\r\n        else\r\n        {\r\n            if (UnCompFormatDesc->bAspectRatioY != 0 || UnCompFormatDesc->bAspectRatioX != 0)\r\n            {\r\n                //@@TestCase B15.7\r\n                //@@ERROR\r\n                //@@Descriptor Field - bAspectRatioX, bAspectRatioY\r\n                //@@Verify that that bAspectRatioX and bAspectRatioY are  set to zero\r\n                //@@  if stream is non-interlaced\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:  Both bAspectRatioX and bAspectRatioY \"\\\r\n                    \"must equal 0 if stream is non-interlaced\");\r\n                OOPS();\r\n            }\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbmInterlaceFlags:                  0x%02X\\r\\n\",\r\n        UnCompFormatDesc->bmInterlaceFlags);\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"     D0    = 0x%02X Interlaced stream or variable: %s\\r\\n\",\r\n            (UnCompFormatDesc->bmInterlaceFlags & 1),\r\n            (UnCompFormatDesc->bmInterlaceFlags & 1) ? \"Yes\" : \"No\");\r\n        AppendTextBuffer(\"     D1    = 0x%02X Fields per frame: %s\\r\\n\",\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 1) & 1),\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 1) & 1) ? \"1 field\" : \"2 fields\");\r\n        AppendTextBuffer(\"     D2    = 0x%02X Field 1 first: %s\\r\\n\",\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 2) & 1),\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 2) & 1) ? \"Yes\" : \"No\");\r\n        //@@TestCase B15.9\r\n        //@@Not yet implemented - Priority 1\r\n        //@@Descriptor Field - bmInterlaceFlags\r\n        //@@Validate that reserved bits (D3) are set to zero.\r\n        AppendTextBuffer(\"     D3    = 0x%02X Reserved%s\\r\\n\",\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 3) & 1),\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 3) & 1) ?\r\n            \"\\r\\n*!*ERROR: Reserved to 0\" : \"\" );\r\n        AppendTextBuffer(\"     D4..5 = 0x%02X Field patterns  ->\",\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 4) & 3));\r\n        switch(UnCompFormatDesc->bmInterlaceFlags & 0x30)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Field 1 only\");\r\n            break;\r\n        case 0x10:\r\n            AppendTextBuffer(\" Field 2 only\");\r\n            break;\r\n        case 0x20:\r\n            AppendTextBuffer(\" Regular Pattern of fields 1 and 2\");\r\n            break;\r\n        case 0x30:\r\n            AppendTextBuffer(\" Random Pattern of fields 1 and 2\");\r\n            break;\r\n        }\r\n        AppendTextBuffer(\"\\r\\n     D6..7 = 0x%02X Display Mode  ->\",\r\n            ((UnCompFormatDesc->bmInterlaceFlags >> 6) & 3));\r\n\r\n        switch(UnCompFormatDesc->bmInterlaceFlags & 0xC0)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Bob only\");\r\n            break;\r\n        case 0x40:\r\n            AppendTextBuffer(\" Weave only\");\r\n            break;\r\n        case 0x80:\r\n            AppendTextBuffer(\" Bob or weave\");\r\n            break;\r\n        case 0xC0:\r\n            //@@TestCase B15.10\r\n            //@@Not yet implemented - Priority 3\r\n            //@@Descriptor Field - bmInterlaceFlags\r\n            //@@Question - Should we validate that reserved bits are set to zero?\r\n            AppendTextBuffer(\" Reserved\");\r\n            break;\r\n        }\r\n    }\r\n\r\n    //@@TestCase B15.11\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bCopyProtect\r\n    //@@Question - Are their reserved bits and should we validate that\r\n    //@@  reserved bits are set to zero?\r\n    AppendTextBuffer(\"\\r\\nbCopyProtect:                      0x%02X\",\r\n        UnCompFormatDesc->bCopyProtect);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (UnCompFormatDesc->bCopyProtect)\r\n            AppendTextBuffer(\"  -> Duplication Restricted\");\r\n        else\r\n            AppendTextBuffer(\"  -> Duplication Unrestricted\");\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    //@@TestCase B15.12\r\n    //@@We should check to make sure that a Color Matching Descriptor is included in the device\r\n    // Check that the correct number of Frame Descriptors and one Color Matching\r\n    //  descriptor follow\r\n    CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) UnCompFormatDesc,\r\n        UnCompFormatDesc->bNumFrameDescriptors, VS_FRAME_UNCOMPRESSED);\r\n\r\n    return TRUE;\r\n    }\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayUncompressedFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayUncompressedFrameType (\r\n                              PVIDEO_FRAME_UNCOMPRESSED UnCompFrameDesc\r\n                              )\r\n{\r\n    size_t bLength = 0;\r\n    bLength = SizeOfVideoFrameUncompressed(UnCompFrameDesc);\r\n\r\n    //@@DisplayUncompressedFrameType -Uncompressed Frame\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Uncompressed Frame Type Descriptor<===\\r\\n\");\r\n    if (gDoAnnotation)\r\n    {\r\n        if(UnCompFrameDesc->bFrameIndex == g_chUNCFrameDefault)\r\n        {\r\n            AppendTextBuffer(\"          --->This is the Default (optimum) Frame index\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", UnCompFrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", UnCompFrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", UnCompFrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFrameIndex:                       0x%02X\\r\\n\", UnCompFrameDesc->bFrameIndex);\r\n    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", UnCompFrameDesc->bmCapabilities);\r\n    AppendTextBuffer(\"wWidth:                          0x%04X = %d\\r\\n\", UnCompFrameDesc->wWidth, UnCompFrameDesc->wWidth);\r\n    AppendTextBuffer(\"wHeight:                         0x%04X = %d\\r\\n\", UnCompFrameDesc->wHeight, UnCompFrameDesc->wHeight);\r\n    AppendTextBuffer(\"dwMinBitRate:                0x%08X\\r\\n\", UnCompFrameDesc->dwMinBitRate);\r\n    AppendTextBuffer(\"dwMaxBitRate:                0x%08X\\r\\n\", UnCompFrameDesc->dwMaxBitRate);\r\n    AppendTextBuffer(\"dwMaxVideoFrameBufferSize:   0x%08X\\r\\n\", UnCompFrameDesc->dwMaxVideoFrameBufferSize);\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n    AppendTextBuffer(\"dwDefaultFrameInterval:      0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n        UnCompFrameDesc->dwDefaultFrameInterval,\r\n        ((double)UnCompFrameDesc->dwDefaultFrameInterval)/10000.0,\r\n        (10000000.0/((double)UnCompFrameDesc->dwDefaultFrameInterval))\r\n        );\r\n    AppendTextBuffer(\"bFrameIntervalType:                0x%02X\\r\\n\", UnCompFrameDesc->bFrameIntervalType);\r\n\r\n    if (UnCompFrameDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B15.1 (descript.c line 925)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required\r\n        //@@length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            UnCompFrameDesc->bLength, bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFrameDesc->bFrameIndex == 0 )\r\n    {\r\n        //@@TestCase B16.2 (descript.c line 991)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFrameIndex\r\n        //@@bFrameIndex must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  bFrameIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B16.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bmCapabilities\r\n    //@@Question:  Should we try to verify that bmCapabilities is valid?\r\n    //    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", UnCompFrameDesc->bmCapabilities);\r\n\r\n    if (UnCompFrameDesc->wWidth == 0 )\r\n    {\r\n        //@@TestCase B16.4 (descript.c line 996)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wWidth\r\n        //@@wWidth must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  wWidth must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFrameDesc->wHeight == 0 )\r\n    {\r\n        //@@TestCase B16.5 (descript.c line 1001)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wHeight\r\n        //@@wHeight must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  wHeight must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFrameDesc->dwMinBitRate == 0 )\r\n    {\r\n        //@@TestCase B16.6 (descript.c line 1006)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate\r\n        //@@dwMinBitRate must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFrameDesc->dwMaxBitRate == 0 )\r\n    {\r\n        //@@TestCase B16.7 (descript.c line 1011)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxBitRate\r\n        //@@dwMaxBitRate must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(UnCompFrameDesc->dwMinBitRate > UnCompFrameDesc->dwMaxBitRate)\r\n    {\r\n        //@@TestCase B16.8\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate and dwMaxBitRate\r\n        //@@Verify that dwMaxBitRate is greater than dwMinBitRate\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate should be less than dwMaxBitRate\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        if (UnCompFrameDesc->bFrameIntervalType == 1 &&\r\n            UnCompFrameDesc->dwMinBitRate != UnCompFrameDesc->dwMaxBitRate)\r\n        {\r\n            //@@TestCase B16.9\r\n            //@@WARNING\r\n            //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate\r\n            //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1\r\n            AppendTextBuffer(\"*!*WARNING:  if bFrameIntervalType is 1 then dwMinBitRate \"\\\r\n                \"should equal dwMaxBitRate\\r\\n\");\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    if (UnCompFrameDesc->dwMaxVideoFrameBufferSize == 0 )\r\n    {\r\n        //@@TestCase B16.10 (descript.c line 1015)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFrameIndex\r\n        //@@bFrameIndex must be nonzero\r\n        AppendTextBuffer(\"*!*WARNING:  dwMaxVideoFrameBufferSize must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (UnCompFrameDesc->dwDefaultFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B16.11 (descript.c line 1020)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwDefaultFrameInterval\r\n        //@@dwDefaultFrameInterval must be nonzero\r\n        AppendTextBuffer(\"*!*WARNING:  dwDefaultFrameInterval must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n    if (0 == UnCompFrameDesc->bFrameIntervalType)\r\n    {\r\n        DisplayUnComContinuousFrameType(UnCompFrameDesc);\r\n    }\r\n    else\r\n    {\r\n        DisplayUnComDiscreteFrameType(UnCompFrameDesc);\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayUnComContinuousFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayUnComContinuousFrameType(\r\n                                PVIDEO_FRAME_UNCOMPRESSED UContinuousDesc\r\n                                )\r\n{\r\n    //@@DisplayUnComContinuousFrameType -Uncompressed Continuous Frame\r\n    ULONG dwMinFrameInterval  = UContinuousDesc->adwFrameInterval[0];\r\n    ULONG dwMaxFrameInterval  = UContinuousDesc->adwFrameInterval[1];\r\n    ULONG dwFrameIntervalStep = UContinuousDesc->adwFrameInterval[2];\r\n\r\n    AppendTextBuffer(\"===>Additional Continuous Frame Type Data\\r\\n\");\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n\r\n    AppendTextBuffer(\"dwMinFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMinFrameInterval,\r\n        ((double)dwMinFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwMaxFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMaxFrameInterval,\r\n        ((double)dwMaxFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwFrameIntervalStep:         0x%08X\\r\\n\", dwFrameIntervalStep);\r\n\r\n    if (dwMinFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B17.2 (descript.c line 1025)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval\r\n        //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwMaxFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B17.3 (descript.c line 1025)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxFrameInterval\r\n        //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(dwMinFrameInterval  > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B17.4  (descript.c 1043)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B17.5\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 )\r\n    {\r\n        //@@TestCase B17.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - dwFrameIntervalStep\r\n        //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero\r\n        AppendTextBuffer(\"*!*CAUTION:  dwFrameIntervalStep equals zero, consider using discrete frames\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep )\r\n    {\r\n        //@@TestCase B17.7 (descript.c 1052)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMaxFrameInterval minus dwMinFrameInterval  is not evenly divisible by dwFrameIntervalStep, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval))\r\n    {\r\n        //@@TestCase B17.8 (descript.c line 1032)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*WARNING:  dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between dwMinFrameInterval and dwMaxFrameInterval\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayUnComDiscreteFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayUnComDiscreteFrameType(\r\n                              PVIDEO_FRAME_UNCOMPRESSED UDiscreteDesc\r\n                              )\r\n{\r\n    //@@DisplayUnComDiscreteFrameType -Uncompressed Discrete Frame\r\n    UINT    iNdex = 1;\r\n    UINT    iCurFrame = 0;\r\n    ULONG   * ulFrameInterval = NULL;\r\n\r\n    AppendTextBuffer(\"===>Additional Discrete Frame Type Data\\r\\n\");\r\n\r\n    // There are (UDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index)\r\n    for (; iNdex <= UDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++)\r\n    {\r\n        ulFrameInterval = &UDiscreteDesc->adwFrameInterval[iCurFrame];\r\n        // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n        // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n        // = 1/10,000 milliseconds\r\n\r\n\r\n        // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n        AppendTextBuffer(\"dwFrameInterval[%d]:          0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n            iNdex, *ulFrameInterval,\r\n            ((double)*ulFrameInterval)/10000.0,\r\n            (10000000.0/((double)*ulFrameInterval))\r\n            );\r\n        if (0 == *ulFrameInterval)\r\n        {\r\n            //@@TestCase B18.1 (descript.c line 1061)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[x] must be non-zero\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[%d] must be non-zero\\r\\n\", iNdex);\r\n            OOPS();\r\n        }\r\n        if ((iNdex > 1)&&(*ulFrameInterval <= UDiscreteDesc->adwFrameInterval[iCurFrame - 1]))\r\n        {\r\n            //@@TestCase B18.2 (descript.c line 1067)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1]\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[0x%02X] must be \"\\\r\n                \"greater than preceding dwFrameInterval[0x%02X]\\r\\n\", iNdex, iNdex - 1);\r\n            OOPS();\r\n        }\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMJPEGFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMJPEGFormat (\r\n                    PVIDEO_FORMAT_MJPEG MJPEGFormatDesc\r\n                    )\r\n{\r\n    //@@DisplayMJPEGFormat - MJPEG Format\r\n    // Initialize the default Frame\r\n    g_chMJPEGFrameDefault = MJPEGFormatDesc->bDefaultFrameIndex;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MJPEG Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MJPEGFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MJPEGFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MJPEGFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", MJPEGFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bNumFrameDescriptors:              0x%02X\\r\\n\", MJPEGFormatDesc->bNumFrameDescriptors);\r\n\r\n    if (MJPEGFormatDesc->bLength != sizeof(VIDEO_FORMAT_MJPEG))\r\n    {\r\n        //@@TestCase B19.1 (descript.c line 1098)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the\r\n        //@@  required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            MJPEGFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_MJPEG));\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B19.2 (descript.c line 1103)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with\r\n        //@@  the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bFormatIndex must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFormatDesc->bNumFrameDescriptors == 0 )\r\n    {\r\n        //@@TestCase B19.3 (descript.c line 1108)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFrameDescriptors\r\n        //@@bNumFrameDescriptors is set to zero which is not in accordance\r\n        //@@  with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFrameDescriptors must be non-zero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bmFlags:                           0x%02X\",\r\n        (MJPEGFormatDesc->bmFlags & 0x01));\r\n\r\n    //@@TestCase B19.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bmFlags\r\n    //@@We should validate that reserved bits are set to zero.\r\n    if (gDoAnnotation)\r\n    {\r\n        if(MJPEGFormatDesc->bmFlags & 0x01)\r\n        {\r\n            AppendTextBuffer(\"  -> Sample Size is Fixed\");\r\n        }\r\n        else\r\n        {\r\n            AppendTextBuffer(\"  -> Sample Size is Not Fixed\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbDefaultFrameIndex:                0x%02X\\r\\n\",\r\n        MJPEGFormatDesc->bDefaultFrameIndex);\r\n\r\n    if (MJPEGFormatDesc->bDefaultFrameIndex == 0 ||\r\n        MJPEGFormatDesc->bDefaultFrameIndex >\r\n        MJPEGFormatDesc->bNumFrameDescriptors)\r\n    {\r\n        //@@TestCase B19.5  (descript.c line 1113)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDefaultFrameIndex\r\n        //@@bDefaultFrameIndex is not in the domain of constrained by\r\n        //@@  bNumFrameDescriptors\r\n        AppendTextBuffer(\"*!*ERROR:  bDefaultFrameIndex 0x%02X invalid, should \"\\\r\n            \"be between 1 and 0x%02x/r/n\",\r\n            MJPEGFormatDesc->bDefaultFrameIndex,\r\n            MJPEGFormatDesc->bNumFrameDescriptors);\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bAspectRatioX:                     0x%02X\\r\\n\",\r\n        MJPEGFormatDesc->bAspectRatioX);\r\n    AppendTextBuffer(\"bAspectRatioY:                     0x%02X\",\r\n        MJPEGFormatDesc->bAspectRatioY);\r\n\r\n    if(((MJPEGFormatDesc->bmInterlaceFlags & 0x01) &&\r\n        ((MJPEGFormatDesc->bAspectRatioY != 0) &&\r\n        (MJPEGFormatDesc->bAspectRatioX != 0))))\r\n    {\r\n        if (gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Aspect Ratio is set for a %d:%d display\",\r\n                (MJPEGFormatDesc->bAspectRatioX), (MJPEGFormatDesc->bAspectRatioY));\r\n        }\r\n    }\r\n    else\r\n    {\r\n        if (MJPEGFormatDesc->bAspectRatioY != 0 || MJPEGFormatDesc->bAspectRatioX != 0)\r\n        {\r\n            //@@TestCase B19.6\r\n            //@@ERROR\r\n            //@@Descriptor Field - bAspectRatioX and bAspectRatioY\r\n            //@@Verify that that bAspectRatioX and bAspectRatioY are  set to zero\r\n            //@@  if stream is non-interlaced\r\n            AppendTextBuffer(\"\\r\\n*!*ERROR:  bAspectRatioX and bAspectRatioY must \"\\\r\n                \"be 0 if stream non-Interlaced\");\r\n            OOPS();\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbmInterlaceFlags:                  0x%02X\\r\\n\",\r\n        MJPEGFormatDesc->bmInterlaceFlags);\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"     D00   = %x %sInterlaced stream or variable\\r\\n\",\r\n            (MJPEGFormatDesc->bmInterlaceFlags & 1),\r\n            (MJPEGFormatDesc->bmInterlaceFlags & 1) ? \"\" : \" non-\");\r\n        AppendTextBuffer(\"     D01   = %x %s per frame\\r\\n\",\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 1) & 1),\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 1) & 1) ? \" 1 field\" : \" 2 fields\");\r\n        AppendTextBuffer(\"     D02   = %x  Field 1 %sfirst\\r\\n\",\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 2) & 1),\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 2) & 1) ? \"\" : \"not \");\r\n        //@@TestCase B19.7\r\n        //@@Not yet implemented - Priority 1\r\n        //@@Descriptor Field - bmInterlaceFlags\r\n        //@@Validate that reserved bits (D3) are set to zero.\r\n        AppendTextBuffer(\"     D03   = %x  Reserved%s\\r\\n\",\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 3) & 1),\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 3) & 1) ?\r\n            \"\\r\\n*!*ERROR: non zero\" : \"\" );\r\n        AppendTextBuffer(\"     D4..5 = %x  Field patterns  ->\",\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 4) & 3));\r\n        switch (MJPEGFormatDesc->bmInterlaceFlags & 0x30)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Field 1 only\");\r\n            break;\r\n        case 0x10:\r\n            AppendTextBuffer(\" Field 2 only\");\r\n            break;\r\n        case 0x20:\r\n            AppendTextBuffer(\" Regular Pattern of fields 1 and 2\");\r\n            break;\r\n        case 0x30:\r\n            AppendTextBuffer(\" Random Pattern of fields 1 and 2\");\r\n            break;\r\n        }\r\n        AppendTextBuffer(\"\\r\\n     D6..7 = %x  Display Mode  ->\",\r\n            ((MJPEGFormatDesc->bmInterlaceFlags >> 6) & 3));\r\n        switch(MJPEGFormatDesc->bmInterlaceFlags & 0xC0)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Bob only\");\r\n            break;\r\n        case 0x40:\r\n            AppendTextBuffer(\" Weave only\");\r\n            break;\r\n        case 0x80:\r\n            AppendTextBuffer(\" Bob or weave\");\r\n            break;\r\n        case 0xC0:\r\n            //@@TestCase B19.8\r\n            //@@Not yet implemented - Priority 3\r\n            //@@Descriptor Field - bmInterlaceFlags\r\n            //@@Question - Should we validate that reserved bits are set to zero?\r\n            AppendTextBuffer(\" Reserved\");\r\n            break;\r\n        }\r\n    }\r\n\r\n    //@@TestCase B19.9\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bCopyProtect\r\n    //@@Question - Are their reserved bits and should we validate that\r\n    //@@  reserved bits are set to zero?\r\n    AppendTextBuffer(\"\\r\\nbCopyProtect:                      0x%02X\",\r\n        MJPEGFormatDesc->bCopyProtect);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (MJPEGFormatDesc->bCopyProtect)\r\n            AppendTextBuffer(\"  -> Duplication Restricted\");\r\n        else\r\n            AppendTextBuffer(\"  -> Duplication Unrestricted\");\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    // Check that the correct number of Frame Descriptors and one Color Matching\r\n    //  descriptor follow\r\n    CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) MJPEGFormatDesc,\r\n        MJPEGFormatDesc->bNumFrameDescriptors, VS_FRAME_MJPEG);\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMJPEGFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMJPEGFrameType (\r\n                       PVIDEO_FRAME_MJPEG MJPEGFrameDesc\r\n                       )\r\n{\r\n    //@@DisplayMJPEGFrameType -MJPEG Frame\r\n    size_t bLength = 0;\r\n    bLength = SizeOfVideoFrameMjpeg(MJPEGFrameDesc);\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MJPEG Frame Type Descriptor<===\\r\\n\");\r\n    if (gDoAnnotation)\r\n    {\r\n        if(MJPEGFrameDesc->bFrameIndex == g_chMJPEGFrameDefault)\r\n        {\r\n            AppendTextBuffer(\"          --->This is the Default (optimum) Frame index\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MJPEGFrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MJPEGFrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MJPEGFrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFrameIndex:                       0x%02X\\r\\n\", MJPEGFrameDesc->bFrameIndex);\r\n    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", MJPEGFrameDesc->bmCapabilities);\r\n    AppendTextBuffer(\"wWidth:                          0x%04X = %d\\r\\n\", MJPEGFrameDesc->wWidth, MJPEGFrameDesc->wWidth);\r\n    AppendTextBuffer(\"wHeight:                         0x%04X = %d\\r\\n\", MJPEGFrameDesc->wHeight, MJPEGFrameDesc->wHeight);\r\n    AppendTextBuffer(\"dwMinBitRate:                0x%08X\\r\\n\", MJPEGFrameDesc->dwMinBitRate);\r\n    AppendTextBuffer(\"dwMaxBitRate:                0x%08X\\r\\n\", MJPEGFrameDesc->dwMaxBitRate);\r\n    AppendTextBuffer(\"dwMaxVideoFrameBufferSize:   0x%08X\\r\\n\", MJPEGFrameDesc->dwMaxVideoFrameBufferSize);\r\n\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n    AppendTextBuffer(\"dwDefaultFrameInterval:      0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n        MJPEGFrameDesc->dwDefaultFrameInterval,\r\n        ((double)MJPEGFrameDesc->dwDefaultFrameInterval)/10000.0,\r\n        (10000000.0/((double)MJPEGFrameDesc->dwDefaultFrameInterval))\r\n        );\r\n    AppendTextBuffer(\"bFrameIntervalType:                0x%02X\\r\\n\", MJPEGFrameDesc->bFrameIntervalType);\r\n\r\n    if (MJPEGFrameDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B20.1 (descript.c line 1154)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is less than required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d is incorrect, should be %d\\r\\n\",\r\n            MJPEGFrameDesc->bLength, bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->bFrameIndex == 0 )\r\n    {\r\n        //@@TestCase B20.2  (descript.c line 1159)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFrameIndex\r\n        //@@bFrameIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFrameIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B20.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bmCapabilities\r\n    //@@Question:  Should we try to verify that bmCapabilities is valid?\r\n    //    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", MJPEGFrameDesc->bmCapabilities);\r\n\r\n    if (MJPEGFrameDesc->wWidth == 0 )\r\n    {\r\n        //@@TestCase B20.4 (descript.c line 1164)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wWidth\r\n        //@@wWidth is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  wWidth = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->wHeight == 0 )\r\n    {\r\n        //@@TestCase B20.5 (descript.c line 1169)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wHeight\r\n        //@@wHeight is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  wHeight = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->dwMinBitRate == 0 )\r\n    {\r\n        //@@TestCase B20.6 (descript.c line 1174)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate\r\n        //@@dwMinBitRate is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->dwMaxBitRate == 0 )\r\n    {\r\n        //@@TestCase B20.7 (descript.c line 1179)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxBitRate\r\n        //@@dwMaxBitRate is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxBitRate = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(MJPEGFrameDesc->dwMinBitRate > MJPEGFrameDesc->dwMaxBitRate)\r\n    {\r\n        //@@TestCase B20.8\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate and dwMaxBitRate\r\n        //@@Verify that dwMaxBitRate is greater than dwMinBitRate\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate > dwMaxBitRate, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if(MJPEGFrameDesc->bFrameIntervalType == 1 && MJPEGFrameDesc->dwMinBitRate != MJPEGFrameDesc->dwMaxBitRate)\r\n    {\r\n        //@@TestCase B20.9\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate\r\n        //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1\r\n        AppendTextBuffer(\"*!*WARNING:  if bFrameIntervalType is 1 then dwMinBitRate should equal dwMaxBitRate\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->dwMaxVideoFrameBufferSize == 0 )\r\n    {\r\n        //@@TestCase B20.10  (descript.c line 1183)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxVideoFrameBufferSize\r\n        //@@dwMaxVideoFrameBufferSize is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxVideoFrameBufferSize = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (MJPEGFrameDesc->dwMaxVideoFrameBufferSize == 0 )\r\n    {\r\n        //@@TestCase B20.11  (descript.c line 1188)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwDefaultFrameInterval\r\n        //@@dwDefaultFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwDefaultFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (0 == MJPEGFrameDesc->bFrameIntervalType)\r\n    {\r\n        DisplayMJPEGContinuousFrameType(MJPEGFrameDesc);\r\n    }\r\n    else\r\n    {\r\n        DisplayMJPEGDiscreteFrameType(MJPEGFrameDesc);\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMJPEGContinuousFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMJPEGContinuousFrameType(\r\n                                PVIDEO_FRAME_MJPEG MContinuousDesc\r\n                                )\r\n{\r\n    //@@DisplayMJPEGContinuousFrameType - MJPEG Continuous Frame\r\n    ULONG dwMinFrameInterval  = MContinuousDesc->adwFrameInterval[0];\r\n    ULONG dwMaxFrameInterval  = MContinuousDesc->adwFrameInterval[1];\r\n    ULONG dwFrameIntervalStep = MContinuousDesc->adwFrameInterval[2];\r\n\r\n    AppendTextBuffer(\"===>Additional Continuous Frame Type Data\\r\\n\");\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n\r\n    AppendTextBuffer(\"dwMinFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMinFrameInterval,\r\n        ((double)dwMinFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwMaxFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMaxFrameInterval,\r\n        ((double)dwMaxFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwFrameIntervalStep:         0x%08X\\r\\n\", dwFrameIntervalStep);\r\n\r\n    if (dwMinFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B21.2   (descript.c line 1188)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval\r\n        //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwMaxFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B21.3  (descript.c line 1188)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxFrameInterval\r\n        //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(dwMinFrameInterval > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B21.4  (descript.c line 1211)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B21.5\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 )\r\n    {\r\n        //@@TestCase B21.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - dwFrameIntervalStep\r\n        //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero\r\n        AppendTextBuffer(\"*!*CAUTION:  dwFrameIntervalStep equals zero, consider using discrete frames\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep )\r\n    {\r\n        //@@TestCase B21.7  (descript.c line 1220)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMaxFrameInterval minus dwMinFrameInterval is not evenly divisible by dwFrameIntervalStep, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval))\r\n    {\r\n        //@@TestCase B21.8 (descript.c line 1200)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*WARNING:  dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between \\r\\n          *!*dwMinFrameInterval and dwMaxFrameInterval\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMJPEGDiscreteFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMJPEGDiscreteFrameType(\r\n                              PVIDEO_FRAME_MJPEG MDiscreteDesc\r\n                              )\r\n{\r\n    //@@DisplayMJPEGDiscreteFrameType -MJPEG Discrete Frame\r\n    UINT    iNdex = 1;\r\n    UINT    iCurFrame = 0;\r\n    ULONG   * ulFrameInterval = NULL;\r\n\r\n    AppendTextBuffer(\"===>Additional Discrete Frame TypeData\\r\\n\");\r\n\r\n    // There are (MDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index)\r\n    for (; iNdex <= MDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++)\r\n    {\r\n        ulFrameInterval = &MDiscreteDesc->adwFrameInterval[iCurFrame];\r\n        // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n        // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n        // = 1/10,000 milliseconds\r\n\r\n\r\n        // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n        AppendTextBuffer(\"dwFrameInterval[%d]:          0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n            iNdex, *ulFrameInterval,\r\n            ((double)*ulFrameInterval)/10000.0,\r\n            (10000000.0/((double)*ulFrameInterval))\r\n            );\r\n        if (0 == *ulFrameInterval)\r\n        {\r\n            //@@TestCase B22.1 (descript.c line 1229)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[x] must be non-zero\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[%d] must be non-zero\\r\\n\", iNdex);\r\n            OOPS();\r\n        }\r\n        if ((iNdex > 1)&&(*ulFrameInterval <= MDiscreteDesc->adwFrameInterval[iCurFrame - 1]))\r\n        {\r\n            //@@TestCase B22.2 (descript.c line 1235)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1]\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[0x%02X] must be \"\\\r\n                \"greater than preceding dwFrameInterval[0x%02X]\\r\\n\",  iNdex, iNdex - 1);\r\n            OOPS();\r\n        }\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMPEG1SSFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMPEG1SSFormat (\r\n                      PVIDEO_FORMAT_MPEG1SS MPEG1SSFormatDesc\r\n                      )\r\n{\r\n    //@@DisplayMPEG1SSFormat -MPEG1 SS Format\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MPEG1-SS Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MPEG1SSFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MPEG1SSFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MPEG1SSFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", MPEG1SSFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"wPacketLength:                     0x%02X\\r\\n\", MPEG1SSFormatDesc->bPacketLength);\r\n    AppendTextBuffer(\"wPackLength:                       0x%02X\\r\\n\", MPEG1SSFormatDesc->bPackLength);\r\n    AppendTextBuffer(\"bPackdataType:                     0x%02X\", (MPEG1SSFormatDesc->bPackDataType));\r\n    if(gDoAnnotation) {\r\n        if(MPEG1SSFormatDesc->bPackDataType & 0x01){AppendTextBuffer(\"  -> Pack data size fixed\\r\\n\");}\r\n        else    {AppendTextBuffer(\"  -> Pack data size variable\\r\\n\");  }}\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n\r\n    if (MPEG1SSFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG1SS))\r\n    {\r\n        //@@TestCase B23.1 (descript.c line 1514)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d.  USBView cannot correctly display descriptor\\r\\n\",\r\n            MPEG1SSFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_MPEG1SS));\r\n        OOPS();\r\n    }\r\n\r\n    if (MPEG1SSFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B23.2 (descript.c line 1519)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFormatIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B23.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bPackdataType\r\n    //@@Question - Should we validate that reserved bits are set to zero?\r\n    //    AppendTextBuffer(\"bPackdataType:                     0x%02X\", (MPEG1SSFormatDesc->bPackdataType & 0x01));\r\n\r\n    // This descriptor is deprecated for UVC 1.1\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\\r\\n\");\r\n    }\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\\r\\n\");\r\n    }\r\n#endif\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMPEG2PSFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMPEG2PSFormat (\r\n                      PVIDEO_FORMAT_MPEG2PS MPEG2PSFormatDesc\r\n                      )\r\n{\r\n    //@@DisplayMPEG2PSFormat -MPEG2 PS Format\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MPEG2-PS Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MPEG2PSFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MPEG2PSFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MPEG2PSFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", MPEG2PSFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bPacketLength:                     0x%02X\\r\\n\", MPEG2PSFormatDesc->bPacketLength);\r\n    AppendTextBuffer(\"bPackLength:                       0x%02X\\r\\n\", MPEG2PSFormatDesc->bPackLength);\r\n    AppendTextBuffer(\"bPackDataType:                     0x%02X\", (MPEG2PSFormatDesc->bPackDataType));\r\n\r\n    if (MPEG2PSFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG2PS))\r\n    {\r\n        //@@TestCase B24.1 (descript.c line 1542)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d.  USBView cannot correctly display descriptor\\r\\n\",\r\n            MPEG2PSFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_MPEG2PS));\r\n        OOPS();\r\n        AppendTextBuffer(\"*!*USBView will try to display the rest of the descriptor but results may not be accurate\\r\\n\");\r\n    }\r\n\r\n    if (MPEG2PSFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B24.2 (descript.c line 1547)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFormatIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B24.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bPackdataType\r\n    //@@Question - Should we validate that reserved bits are set to zero?\r\n    //    AppendTextBuffer(\"bPackdataType:                     0x%02X\", (MPEG2PSFormatDesc->bPackdataType & 0x01));\r\n\r\n    // This descriptor is deprecated for UVC 1.1\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\\r\\n\");\r\n    }\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\\r\\n\");\r\n    }\r\n#endif\r\n\r\n    return TRUE;\r\n\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMPEG2TSFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMPEG2TSFormat (\r\n                      PVIDEO_FORMAT_MPEG2TS MPEG2TSFormatDesc\r\n                      )\r\n{\r\n    //@@DisplayMPEG2TSFormat -MPEG2 TS Format\r\n    UCHAR bLength = sizeof(VIDEO_FORMAT_MPEG2TS);\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MPEG2-TS Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MPEG2TSFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MPEG2TSFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MPEG2TSFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", MPEG2TSFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bDataOffset:                       0x%02X\\r\\n\", MPEG2TSFormatDesc->bDataOffset);\r\n    AppendTextBuffer(\"bPacketLength:                     0x%02X\\r\\n\", MPEG2TSFormatDesc->bPacketLength);\r\n    AppendTextBuffer(\"bStrideLength:                     0x%02X\\r\\n\", MPEG2TSFormatDesc->bStrideLength);\r\n\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n#endif\r\n    {\r\n        int     i = 0;\r\n        PCHAR   pStr = NULL;\r\n        OLECHAR szGUID[256];\r\n        GUID    * pStrideGuid = NULL;\r\n\r\n        pStrideGuid = (GUID *) (&MPEG2TSFormatDesc->bStrideLength + 1);\r\n\r\n        memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n        i = StringFromGUID2((REFGUID) pStrideGuid, (LPOLESTR) szGUID, 255);\r\n        i++;\r\n        AppendTextBuffer(\"guidStrideFormat:                  %S\", szGUID);\r\n        pStr = VidFormatGUIDCodeToName((REFGUID) pStrideGuid);\r\n        if(gDoAnnotation)\r\n        {\r\n            if (pStr)\r\n            {\r\n                AppendTextBuffer(\" = %s Format\", pStr);\r\n            }\r\n        }\r\n        AppendTextBuffer(\"\\r\\n\");\r\n        bLength = sizeof(VIDEO_FORMAT_MPEG2TS) + sizeof(GUID);\r\n    }\r\n\r\n    if (MPEG2TSFormatDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B25.1 (descript.c line 1486)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            MPEG2TSFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_MPEG2TS));\r\n        OOPS();\r\n    }\r\n\r\n    if (MPEG2TSFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B25.2 (descript.c line 1491)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFormatIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B25.3\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bDataOffset, wPacket and wStride\r\n    //@@Question - Should we check that if bDataOffset is 0 that wPacket and wStride should equal each other\r\n    //    AppendTextBuffer(\"bDataOffset:                       0x%02X\\r\\n\", MPEG2TSFormatDesc->bDataOffset);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayMPEG4SLFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayMPEG4SLFormat (\r\n                      PVIDEO_FORMAT_MPEG4SL MPEG4SLFormatDesc\r\n                      )\r\n{\r\n    //@@DisplayMPEG4SLFormat -MPEG4 SL Format\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming MPEG4-SL Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", MPEG4SLFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", MPEG4SLFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", MPEG4SLFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", MPEG4SLFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bPacketLength:                     0x%02X\\r\\n\", MPEG4SLFormatDesc->bPacketLength);\r\n\r\n    if (MPEG4SLFormatDesc->bLength != sizeof(VIDEO_FORMAT_MPEG4SL))\r\n    {\r\n        //@@TestCase B26.1 (descript.c line 1568)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d.  USBView cannot correctly display descriptor\\r\\n\",\r\n            MPEG4SLFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_MPEG4SL));\r\n        OOPS();\r\n    }\r\n\r\n    if (MPEG4SLFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B26.2 (descript.c line 1573)\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFormatIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    // This descriptor is deprecated for UVC 1.1\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\\r\\n\");\r\n    }\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\\r\\n\");\r\n    }\r\n#endif\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayStreamPayload()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayStreamPayload (\r\n                      PVIDEO_FORMAT_STREAM StreamPayloadDesc\r\n                      )\r\n{\r\n    //@@DisplayStreamPayload -Stream Based Payload Format\r\n    PCHAR pStr = NULL;\r\n    OLECHAR szGUID[256];\r\n    int i = 0;\r\n\r\n    memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n    i = StringFromGUID2((REFGUID) &StreamPayloadDesc->guidFormat, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Stream Based Payload Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", StreamPayloadDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", StreamPayloadDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", StreamPayloadDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", StreamPayloadDesc->bFormatIndex);\r\n    AppendTextBuffer(\"guidFormat:                        %S\", szGUID);\r\n\r\n    pStr = VidFormatGUIDCodeToName((REFGUID) &StreamPayloadDesc->guidFormat);\r\n    if(gDoAnnotation)\r\n    {\r\n        if (pStr)\r\n        {\r\n            AppendTextBuffer(\" = %s Format\", pStr);\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n    AppendTextBuffer(\"dwPacketLength:                    0x%02X\\r\\n\", StreamPayloadDesc->dwPacketLength);\r\n\r\n    if (StreamPayloadDesc->bLength != sizeof(VIDEO_FORMAT_STREAM))\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            StreamPayloadDesc->bLength,\r\n            sizeof(PVIDEO_FORMAT_STREAM));\r\n        OOPS();\r\n    }\r\n\r\n    if (StreamPayloadDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@WARNING\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  bFormatIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    // This descriptor is new for UVC 1.1\r\n    if (UVC10 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\\r\\n\");\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayDVFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayDVFormat (\r\n                 PVIDEO_FORMAT_DV DVFormatDesc\r\n                 )\r\n{\r\n    //@@DisplayDVFormat -Digital Video Format\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming DV Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", DVFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", DVFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", DVFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", DVFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"dwMaxVideoFrameBufferSize:   0x%08X\\r\\n\", DVFormatDesc->dwMaxVideoFrameBufferSize);\r\n    AppendTextBuffer(\"bFormatType:                       0x%02X\\r\\n\", DVFormatDesc->bFormatType);\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"     D0..6 = Format Type  ->\");\r\n        switch(DVFormatDesc->bFormatType & 0x03)\r\n        {\r\n           case 0x00:\r\n               AppendTextBuffer(\" SD-DV\\r\\n\");\r\n               break;\r\n           case 0x01:\r\n               AppendTextBuffer(\" SDL-DV\\r\\n\");\r\n               break;\r\n           case 0x02:\r\n               AppendTextBuffer(\" HD-DV\\r\\n\");\r\n               break;\r\n           default:\r\n               AppendTextBuffer(\" Unknown Format\\r\\n\");\r\n               break;\r\n        }\r\n        if (DVFormatDesc->bFormatType & 0x80)\r\n            AppendTextBuffer(\"     D7    = 60Hz\");\r\n        else\r\n            AppendTextBuffer(\"     D7    = 50Hz\");\r\n        AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    if (DVFormatDesc->bLength != sizeof(VIDEO_FORMAT_DV))\r\n    {\r\n        //@@TestCase B27.1 (descript.c line 1453)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            DVFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_DV));\r\n        OOPS();\r\n    }\r\n\r\n    if (DVFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B27.2 (descript.c line 1458)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex invalid\r\n        AppendTextBuffer(\"*!*ERROR:  bFormatIndex of 0x%02X is invalid\\r\\n\",\r\n            DVFormatDesc->bFormatIndex);\r\n        OOPS();\r\n    }\r\n\r\n    if (DVFormatDesc->dwMaxVideoFrameBufferSize == 0 )\r\n    {\r\n        //@@TestCase B27.3 (descript.c line 1463)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxVideoFrameBufferSize\r\n        //@@dwMaxVideoFrameBufferSize invalid\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxVideoFrameBufferSize of 0x%02X is invalid\\r\\n\",\r\n            DVFormatDesc->dwMaxVideoFrameBufferSize);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B27.4\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bFormatType\r\n    //@@Question - Should we validate that reserved bits are set to zero?\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVidVendorFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVendorVidFormat (\r\n                        PVIDEO_FORMAT_VENDOR VendorVidFormatDesc\r\n                        )\r\n{\r\n    //@@DisplayVendorVidFormat -Vendor Video Format\r\n    OLECHAR szGUID[256];\r\n    int i = 0;\r\n\r\n    // Initialize the default Frame\r\n    g_chVendorFrameDefault = VendorVidFormatDesc->bDefaultFrameIndex;\r\n\r\n    memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n    i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidMajorFormat, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Vendor Video Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VendorVidFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VendorVidFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VendorVidFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", VendorVidFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bNumFrameDescriptors:              0x%02X\\r\\n\", VendorVidFormatDesc->bNumFrameDescriptors);\r\n    AppendTextBuffer(\"guidMajorFormat:                   %S\\r\\n\", szGUID);\r\n    i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidSubFormat, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n    AppendTextBuffer(\"guidSubFormat:                     %S\\r\\n\", szGUID);\r\n    i = StringFromGUID2((REFGUID) &VendorVidFormatDesc->guidSpecifier, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n    AppendTextBuffer(\"guidSpecifier:                     %S\\r\\n\", szGUID);\r\n    AppendTextBuffer(\"bPayloadClass:                     0x%02X\\r\\n\", VendorVidFormatDesc->bPayloadClass);\r\n    AppendTextBuffer(\"bDefaultFrameIndex:                0x%02X\\r\\n\", VendorVidFormatDesc->bDefaultFrameIndex);\r\n    AppendTextBuffer(\"bCopyProtect:                      0x%02X\", VendorVidFormatDesc->bCopyProtect);\r\n    if(gDoAnnotation) {\r\n        if(VendorVidFormatDesc->bCopyProtect) { AppendTextBuffer(\"  -> Duplication Restricted\\r\\n\");}\r\n        else {AppendTextBuffer(\"  -> Duplication Unrestricted\\r\\n\");}}\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    if (VendorVidFormatDesc->bLength != sizeof(VIDEO_FORMAT_VENDOR))\r\n    {\r\n        //@@TestCase B28.1 (descript.c line 1297)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d.  USBView cannot correctly display descriptor\\r\\n\",\r\n            VendorVidFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_VENDOR));\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@TestCase B28.2 (descript.c line 1302)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bFormatIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFormatDesc->bNumFrameDescriptors == 0 )\r\n    {\r\n        //@@TestCase B28.3 (descript.c line 1307)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFrameDescriptors\r\n        //@@bNumFrameDescriptors is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFrameDescriptors = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(VendorVidFormatDesc->bPayloadClass > 1)\r\n    {\r\n        //@@TestCase B28.4\r\n        //@@WARNING\r\n        //@@Descriptor Field - bPayloadClass\r\n        //@@bPayloadClass is using reserved space\r\n        AppendTextBuffer(\"*!*WARNING:  bPayloadClass is incorrectly using reserved space\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        if (gDoAnnotation)\r\n        {\r\n            if(VendorVidFormatDesc->bPayloadClass == 1) { AppendTextBuffer(\"  -> Using a Frame Based Payload\\r\\n\");}\r\n            else { AppendTextBuffer(\"  -> Using a Stream Based Payload\\r\\n\");}\r\n        }\r\n        else {AppendTextBuffer(\"\\r\\n\");}\r\n    }\r\n\r\n    if (VendorVidFormatDesc->bDefaultFrameIndex == 0 )\r\n    {\r\n        //@@TestCase B28.5 (descript.c line 1312)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDefaultFrameIndex\r\n        //@@bDefaultFrameIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bDefaultFrameIndex = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFormatDesc->bDefaultFrameIndex == 0 || VendorVidFormatDesc->bDefaultFrameIndex > VendorVidFormatDesc->bNumFrameDescriptors)\r\n    {\r\n        //@@TestCase B28.6\r\n        //@@WARNING\r\n        //@@Descriptor Field - bDefaultFrameIndex\r\n        //@@bDefaultFrameIndex is out of range\r\n        AppendTextBuffer(\"*!*WARNING:  The value %d for the bDefaultFrameIndex is out of range this invalidates the descriptor\\r\\n*!* The proper range is 1 to %d)\",\r\n            VendorVidFormatDesc->bDefaultFrameIndex,\r\n            VendorVidFormatDesc->bNumFrameDescriptors);\r\n        OOPS();\r\n    }\r\n\r\n    //@@TestCase B28.7\r\n    //@@Not yet implemented - Priority 1\r\n    //@@Descriptor Field - bCopyProtect\r\n    //@@Question - Are their reserved bits and should we validate that reserved bits are set to zero?\r\n    //    AppendTextBuffer(\"bCopyProtect:                      0x%02X\", VendorVidFormatDesc->bCopyProtect);\r\n\r\n    // Check that the correct number of Frame Descriptors and one Color Matching\r\n    //  descriptor follow\r\n    CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) VendorVidFormatDesc,\r\n        VendorVidFormatDesc->bNumFrameDescriptors, VS_FRAME_VENDOR);\r\n\r\n    // This descriptor is deprecated for UVC 1.1\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC version >= 1.1 devices\\r\\n\");\r\n    }\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\\r\\n\");\r\n    }\r\n#endif\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVendorVidFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVendorVidFrameType (\r\n                           PVIDEO_FRAME_VENDOR VendorVidFrameDesc\r\n                           )\r\n{\r\n    //@@DisplayVendorVidFrameType -Vendor Video Frame\r\n    size_t bLength = 0;\r\n    bLength = SizeOfVideoFrameVendor(VendorVidFrameDesc);\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Vendor Video Frame Type Descriptor<===\\r\\n\");\r\n    if (gDoAnnotation)\r\n    {\r\n        if(VendorVidFrameDesc->bFrameIndex == g_chVendorFrameDefault)\r\n        {\r\n            AppendTextBuffer(\"          --->This is the Default (optimum) Frame index\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", VendorVidFrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VendorVidFrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VendorVidFrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFrameIndex:                       0x%02X\\r\\n\", VendorVidFrameDesc->bFrameIndex);\r\n\r\n    if (VendorVidFrameDesc->bLength != bLength)\r\n    {\r\n        //@@TestCase B29.1 (descript.c line 1352)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is less than required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            VendorVidFrameDesc->bLength, bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFrameDesc->bFrameIndex == 0 )\r\n    {\r\n        //@@TestCase B29.2 (descript.c line 1357)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFrameIndex\r\n        //@@bFrameIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bFrameIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bmCapabilities:                    0x%02X\", VendorVidFrameDesc->bmCapabilities);\r\n\r\n    if(VendorVidFrameDesc->bmCapabilities & 0x01){\r\n        if(gDoAnnotation) { AppendTextBuffer(\"  -> Still Images are supported\\r\\n\");}\r\n        else {AppendTextBuffer(\"\\r\\n\");} }\r\n    else if (VendorVidFrameDesc->bmCapabilities & 0xFF)\r\n    {\r\n        //@@TestCase B29.3\r\n        //@@WARNING\r\n        //@@Descriptor Field - bmCapabilities\r\n        //@@bmCapabilities has a bit using reserved areas that should be set to zero\r\n        AppendTextBuffer(\"\\r\\n*!*WARNING:  bmCapabilities is using reserved areas.\\r\\n\");\r\n        OOPS(); }\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n    AppendTextBuffer(\"wWidth:                          0x%04X = %d\\r\\n\", VendorVidFrameDesc->wWidth, VendorVidFrameDesc->wWidth);\r\n    AppendTextBuffer(\"wHeight:                         0x%04X = %d\\r\\n\", VendorVidFrameDesc->wHeight, VendorVidFrameDesc->wHeight);\r\n    AppendTextBuffer(\"dwMinBitRate:                0x%08X\\r\\n\", VendorVidFrameDesc->dwMinBitRate);\r\n    AppendTextBuffer(\"dwMaxBitRate:                0x%08X\\r\\n\", VendorVidFrameDesc->dwMaxBitRate);\r\n    AppendTextBuffer(\"dwMaxVideoFrameBufferSize:   0x%08X\\r\\n\", VendorVidFrameDesc->dwMaxVideoFrameBufferSize);\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n    AppendTextBuffer(\"dwDefaultFrameInterval:      0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n        VendorVidFrameDesc->dwDefaultFrameInterval,\r\n        ((double)VendorVidFrameDesc->dwDefaultFrameInterval)/10000.0,\r\n        (10000000.0/((double)VendorVidFrameDesc->dwDefaultFrameInterval))\r\n        );\r\n    AppendTextBuffer(\"bFrameIntervalType:                0x%02X\\r\\n\", VendorVidFrameDesc->bFrameIntervalType);\r\n\r\n    if (VendorVidFrameDesc->wWidth == 0 )\r\n    {\r\n        //@@TestCase B29.4 (descript.c line 1362)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wWidth\r\n        //@@wWidth is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  wWidth must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFrameDesc->wHeight == 0 )\r\n    {\r\n        //@@TestCase B29.5 (descript.c line 1367)\r\n        //@@ERROR\r\n        //@@Descriptor Field - wHeight\r\n        //@@wHeight is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  wHeight must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFrameDesc->dwMinBitRate == 0 )\r\n    {\r\n        //@@TestCase B29.6 (descript.c line 1372)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate\r\n        //@@dwMinBitRate is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFrameDesc->dwMaxBitRate == 0 )\r\n    {\r\n        //@@TestCase B29.7 (descript.c line 1377)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxBitRate\r\n        //@@dwMaxBitRate is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(VendorVidFrameDesc->dwMinBitRate > VendorVidFrameDesc->dwMaxBitRate)\r\n    {\r\n        //@@TestCase B29.8\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate and dwMaxBitRate\r\n        //@@Verify that dwMaxBitRate is greater than dwMinBitRate\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate should be less than dwMaxBitRate\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        if (VendorVidFrameDesc->bFrameIntervalType == 1 &&\r\n            VendorVidFrameDesc->dwMinBitRate != VendorVidFrameDesc->dwMaxBitRate)\r\n        {\r\n            //@@TestCase B29.9\r\n            //@@WARNING\r\n            //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate\r\n            //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1\r\n            AppendTextBuffer(\"*!*WARNING:  if bFrameIntervalType is 1 then dwMinBitRate \"\\\r\n                \"should equal dwMaxBitRate\\r\\n\");\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    if (VendorVidFrameDesc->dwMaxVideoFrameBufferSize == 0 )\r\n    {\r\n        //@@TestCase B29.10 (descript.c line 1382)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwMaxVideoFrameBufferSize\r\n        //@@dwMaxVideoFrameBufferSize is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*WARNING:  dwMaxVideoFrameBufferSize must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n    if (VendorVidFrameDesc->dwDefaultFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B29.11 (descript.c line 1020)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwDefaultFrameInterval\r\n        //@@dwDefaultFrameInterval must be nonzero\r\n        AppendTextBuffer(\"*!*WARNING:  dwDefaultFrameInterval must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (VendorVidFrameDesc->bFrameIntervalType == 0)\r\n    {\r\n        DisplayVendorVidContinuousFrameType(VendorVidFrameDesc);\r\n    }\r\n    else\r\n    {\r\n        DisplayVendorVidDiscreteFrameType(VendorVidFrameDesc);\r\n    }\r\n    // This descriptor is deprecated for UVC 1.1\r\n#ifdef H264_SUPPORT\r\n    if (UVC10 != g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC  version >= 1.1 devices\\r\\n\");\r\n    }\r\n#else\r\n    if (UVC11 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.1 devices\\r\\n\");\r\n    }\r\n#endif\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVendorVidContinuousFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVendorVidContinuousFrameType(\r\n                                    PVIDEO_FRAME_VENDOR VContinuousDesc\r\n                                    )\r\n{\r\n    //@@DisplayVendorVidContinuousFrameType -Vendor Video Continuous Frame\r\n    ULONG dwMinFrameInterval  = VContinuousDesc->adwFrameInterval[0];\r\n    ULONG dwMaxFrameInterval  = VContinuousDesc->adwFrameInterval[1];\r\n    ULONG dwFrameIntervalStep = VContinuousDesc->adwFrameInterval[2];\r\n\r\n    AppendTextBuffer(\"===>Additional Continuous Frame Type Data\\r\\n\");\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n\r\n    AppendTextBuffer(\"dwMinFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMinFrameInterval,\r\n        ((double)dwMinFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwMaxFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMaxFrameInterval,\r\n        ((double)dwMaxFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5));\r\n    AppendTextBuffer(\"dwFrameIntervalStep:         0x%08X\\r\\n\", dwFrameIntervalStep);\r\n\r\n    if (dwMinFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B30.2  (descript.c line 1388)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval\r\n        //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwMaxFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B30.3 (descript.c line 1388)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxFrameInterval\r\n        //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(dwMinFrameInterval  > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B30.4  (descript.c line 1405)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval)\r\n    {\r\n        //@@TestCase B30.5\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 )\r\n    {\r\n        //@@TestCase B30.6\r\n        //@@CAUTION\r\n        //@@Descriptor Field - dwFrameIntervalStep\r\n        //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero\r\n        AppendTextBuffer(\"*!*CAUTION:  dwFrameIntervalStep equals zero, consider using discrete frames\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep )\r\n    {\r\n        //@@TestCase B30.7  (descript.c line 1414)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxFrameInterval minus dwMinFrameInterval  is not evenly divisible by dwFrameIntervalStep, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval))\r\n    {\r\n        //@@TestCase B30.8  (descript.c line 1394)\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*ERROR:  dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between \\r\\n          dwMinFrameInterval and dwMaxFrameInterval\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVendorVidDiscreteFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVendorVidDiscreteFrameType(\r\n                                  PVIDEO_FRAME_VENDOR VDiscreteDesc\r\n                                  )\r\n{\r\n    //@@DisplayVendorVidDiscreteFrameType -Vendor Video Discrete Frame\r\n    UINT    iNdex = 1;\r\n    UINT    iCurFrame = 0;\r\n    ULONG   * ulFrameInterval = NULL;\r\n\r\n    AppendTextBuffer(\"===>Additional Discrete Frame TypeData\\r\\n\");\r\n\r\n    // There are (VDiscreteDesc->bFrameIntervalType) dwFrameIntervals\r\n    for (; iNdex <= VDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++)\r\n    {\r\n        ulFrameInterval = &VDiscreteDesc->adwFrameInterval[iCurFrame];\r\n        // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n        // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n        // = 1/10,000 milliseconds\r\n\r\n\r\n        // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n        AppendTextBuffer(\"dwFrameInterval[%d]:          0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n            iNdex, *ulFrameInterval,\r\n            ((double)*ulFrameInterval)/10000.0,\r\n            (10000000.0/((double)*ulFrameInterval))\r\n            );\r\n        if (0 == *ulFrameInterval)\r\n        {\r\n            //@@TestCase B31.1 (descript.c line 1061)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[x] must be non-zero\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[%d] must be non-zero\\r\\n\", iNdex);\r\n            OOPS();\r\n        }\r\n        if ((iNdex > 1)&&(*ulFrameInterval <= VDiscreteDesc->adwFrameInterval[iCurFrame - 1]))\r\n        {\r\n            //@@TestCase B31.2 (descript.c line 1067)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1]\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[0x%02X] must be \"\\\r\n                \"greater than preceding dwFrameInterval[0x%02X]\\r\\n\", iNdex, iNdex - 1);\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayFramePayloadFormat()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayFramePayloadFormat (\r\n                           PVIDEO_FORMAT_FRAME FramePayloadFormatDesc\r\n                           )\r\n{\r\n    //@@DisplayFramePayloadFormat - FrameBased Payload Format\r\n    PCHAR pStr = NULL;\r\n    OLECHAR szGUID[256];\r\n    int i = 0;\r\n\r\n    // Initialize the default Frame\r\n    g_chFrameBasedFrameDefault = FramePayloadFormatDesc->bDefaultFrameIndex;\r\n\r\n    memset((LPOLESTR) szGUID, 0, sizeof(OLECHAR) * 256);\r\n    i = StringFromGUID2((REFGUID) &FramePayloadFormatDesc->guidFormat, (LPOLESTR) szGUID, 255);\r\n    i++;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Frame Based Payload Format Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", FramePayloadFormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", FramePayloadFormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", FramePayloadFormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X\\r\\n\", FramePayloadFormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bNumFrameDescriptors:              0x%02X\\r\\n\", FramePayloadFormatDesc->bNumFrameDescriptors);\r\n    AppendTextBuffer(\"guidFormat:                        %S\", szGUID);\r\n\r\n    pStr = VidFormatGUIDCodeToName((REFGUID) &FramePayloadFormatDesc->guidFormat);\r\n    if ( pStr )\r\n    {\r\n        if ( gDoAnnotation )\r\n        {\r\n            AppendTextBuffer(\" = %s Format\", pStr);\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n    AppendTextBuffer(\"bBitsPerPixel:                     0x%02X\\r\\n\", FramePayloadFormatDesc->bBitsPerPixel);\r\n    AppendTextBuffer(\"bDefaultFrameIndex:                0x%02X\\r\\n\", FramePayloadFormatDesc->bDefaultFrameIndex);\r\n\r\n    if (FramePayloadFormatDesc->bLength != sizeof(VIDEO_FORMAT_FRAME))\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required\r\n        //@@length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            FramePayloadFormatDesc->bLength,\r\n            sizeof(VIDEO_FORMAT_FRAME));\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFormatDesc->bFormatIndex == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFormatIndex\r\n        //@@bFormatIndex is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bFormatIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFormatDesc->bNumFrameDescriptors == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bNumFrameDescriptors\r\n        //@@bNumFrameDescriptors is set to zero which is not in accordance with the\r\n        //@@USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bNumFrameDescriptors = 0, must have at least 1 Frame descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(!(pStr))\r\n    {\r\n        //@@WARNING\r\n        //@@Descriptor Field - guidFormat\r\n        //@@guidFormat is set to unknown or undefined format\r\n        AppendTextBuffer(\"\\r\\n*!*WARNING:  guidFormat is an unknown format\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFormatDesc->bBitsPerPixel == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bBitsPerPixel\r\n        //@@bBitsPerPixel is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bBitsPerPixel = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFormatDesc->bDefaultFrameIndex == 0 || FramePayloadFormatDesc->bDefaultFrameIndex >\r\n        FramePayloadFormatDesc->bNumFrameDescriptors)\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bDefaultFrameIndex\r\n        //@@The value for bDefaultFrameIndex is not greater than 0 or less than or equal to bNumFrameDescriptors\r\n        AppendTextBuffer(\"*!*ERROR:  The value %d for the bDefaultFrameIndex is out of range, this invalidates the descriptor\\r\\n*!*The proper range is 1 to %d)\",\r\n            FramePayloadFormatDesc->bDefaultFrameIndex,\r\n            FramePayloadFormatDesc->bNumFrameDescriptors);\r\n        OOPS();\r\n    }\r\n\r\n    AppendTextBuffer(\"bAspectRatioX:                     0x%02X\\r\\n\",\r\n        FramePayloadFormatDesc->bAspectRatioX);\r\n    AppendTextBuffer(\"bAspectRatioY:                     0x%02X\",\r\n        FramePayloadFormatDesc->bAspectRatioY);\r\n\r\n    if (((FramePayloadFormatDesc->bmInterlaceFlags & 0x01) &&\r\n        (FramePayloadFormatDesc->bAspectRatioY != 0 &&\r\n        FramePayloadFormatDesc->bAspectRatioX != 0)))\r\n    {\r\n        if(gDoAnnotation)\r\n        {\r\n            AppendTextBuffer(\"  -> Aspect Ratio is set for a %d:%d display\",\r\n                (FramePayloadFormatDesc->bAspectRatioX),(FramePayloadFormatDesc->bAspectRatioY));\r\n        }\r\n        else\r\n        {\r\n            if (FramePayloadFormatDesc->bAspectRatioY != 0 || FramePayloadFormatDesc->bAspectRatioX != 0)\r\n            {\r\n                //@@ERROR\r\n                //@@Descriptor Field - bAspectRatioX, bAspectRatioY\r\n                //@@Verify that that bAspectRatioX and bAspectRatioY are  set to zero\r\n                //@@  if stream is non-interlaced\r\n                AppendTextBuffer(\"\\r\\n*!*ERROR:  Both bAspectRatioX and bAspectRatioY \"\\\r\n                    \"must equal 0 if stream is non-interlaced\");\r\n                OOPS();\r\n            }\r\n        }\r\n    }\r\n    AppendTextBuffer(\"\\r\\nbmInterlaceFlags:                  0x%02X\\r\\n\",\r\n        FramePayloadFormatDesc->bmInterlaceFlags);\r\n\r\n    if (gDoAnnotation)\r\n    {\r\n        AppendTextBuffer(\"     D0    = 0x%02X Interlaced stream or variable: %s\\r\\n\",\r\n            (FramePayloadFormatDesc->bmInterlaceFlags & 1),\r\n            (FramePayloadFormatDesc->bmInterlaceFlags & 1) ? \"Yes\" : \"No\");\r\n        AppendTextBuffer(\"     D1    = 0x%02X Fields per frame: %s\\r\\n\",\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 1) & 1),\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 1) & 1) ? \"1 field\" : \"2 fields\");\r\n        AppendTextBuffer(\"     D2    = 0x%02X Field 1 first: %s\\r\\n\",\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 2) & 1),\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 2) & 1) ? \"Yes\" : \"No\");\r\n        //@@Descriptor Field - bmInterlaceFlags\r\n        //@@Validate that reserved bits (D3) are set to zero.\r\n        AppendTextBuffer(\"     D3    = 0x%02X Reserved%s\\r\\n\",\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 3) & 1),\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 3) & 1) ?\r\n            \"\\r\\n*!*ERROR: Reserved to 0\" : \"\" );\r\n        AppendTextBuffer(\"     D4..5 = 0x%02X Field patterns  ->\",\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 4) & 3));\r\n        switch(FramePayloadFormatDesc->bmInterlaceFlags & 0x30)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Field 1 only\");\r\n            break;\r\n        case 0x10:\r\n            AppendTextBuffer(\" Field 2 only\");\r\n            break;\r\n        case 0x20:\r\n            AppendTextBuffer(\" Regular Pattern of fields 1 and 2\");\r\n            break;\r\n        case 0x30:\r\n            AppendTextBuffer(\" Random Pattern of fields 1 and 2\");\r\n            break;\r\n        }\r\n        AppendTextBuffer(\"\\r\\n     D6..7 = 0x%02X Display Mode  ->\",\r\n            ((FramePayloadFormatDesc->bmInterlaceFlags >> 6) & 3));\r\n\r\n        switch(FramePayloadFormatDesc->bmInterlaceFlags & 0xC0)\r\n        {\r\n        case 0x00:\r\n            AppendTextBuffer(\" Bob only\");\r\n            break;\r\n        case 0x40:\r\n            AppendTextBuffer(\" Weave only\");\r\n            break;\r\n        case 0x80:\r\n            AppendTextBuffer(\" Bob or weave\");\r\n            break;\r\n        case 0xC0:\r\n            //@@Descriptor Field - bmInterlaceFlags\r\n            //@@Question - Should we validate that reserved bits are set to zero?\r\n            AppendTextBuffer(\" Reserved\");\r\n            break;\r\n        }\r\n    }\r\n\r\n    //@@Descriptor Field - bCopyProtect\r\n    //@@Question - Are their reserved bits and should we validate that\r\n    //@@  reserved bits are set to zero?\r\n    AppendTextBuffer(\"\\r\\nbCopyProtect:                      0x%02X\",\r\n        FramePayloadFormatDesc->bCopyProtect);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (FramePayloadFormatDesc->bCopyProtect)\r\n            AppendTextBuffer(\"  -> Duplication Restricted\");\r\n        else\r\n            AppendTextBuffer(\"  -> Duplication Unrestricted\");\r\n    }\r\n\r\n    //@@Descriptor Field - bVariableSize\r\n    AppendTextBuffer(\"\\r\\nbVariableSize:                     0x%02X\",\r\n        FramePayloadFormatDesc->bVariableSize);\r\n    if (gDoAnnotation)\r\n    {\r\n        if (FramePayloadFormatDesc->bVariableSize)\r\n            AppendTextBuffer(\"  -> Variable Size\");\r\n        else\r\n            AppendTextBuffer(\"  -> Fixed Size\");\r\n    }\r\n    AppendTextBuffer(\"\\r\\n\");\r\n\r\n    // Check that the correct number of Frame Descriptors and one Color Matching\r\n    //  descriptor follow\r\n    CheckForColorMatchingDesc ((PVIDEO_SPECIFIC) FramePayloadFormatDesc,\r\n        FramePayloadFormatDesc->bNumFrameDescriptors, VS_FRAME_FRAME_BASED);\r\n\r\n    // This descriptor is new for UVC 1.1\r\n    if (UVC10 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\\r\\n\");\r\n    }\r\n    return TRUE;\r\n    }\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayFramePayloadFrame()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayFramePayloadFrame (\r\n                              PVIDEO_FRAME_FRAME FramePayloadFrameDesc\r\n                              )\r\n{\r\n    size_t bLength = 0;\r\n    bLength = SizeOfVideoFrameFrame(FramePayloadFrameDesc);\r\n\r\n    //@@DisplayFramePayloadFrame -Frame Based Payload Frame\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming Frame Based Payload Frame Type Descriptor<===\\r\\n\");\r\n    if (gDoAnnotation)\r\n    {\r\n        if(FramePayloadFrameDesc->bFrameIndex == g_chFrameBasedFrameDefault)\r\n        {\r\n            AppendTextBuffer(\"          --->This is the Default (optimum) Frame index\\r\\n\");\r\n        }\r\n    }\r\n    AppendTextBuffer(\"bLength:                           0x%02X\\r\\n\", FramePayloadFrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", FramePayloadFrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", FramePayloadFrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFrameIndex:                       0x%02X\\r\\n\", FramePayloadFrameDesc->bFrameIndex);\r\n    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", FramePayloadFrameDesc->bmCapabilities);\r\n    AppendTextBuffer(\"wWidth:                          0x%04X = %d\\r\\n\", FramePayloadFrameDesc->wWidth, FramePayloadFrameDesc->wWidth);\r\n    AppendTextBuffer(\"wHeight:                         0x%04X = %d\\r\\n\", FramePayloadFrameDesc->wHeight, FramePayloadFrameDesc->wHeight);\r\n    AppendTextBuffer(\"dwMinBitRate:                0x%08X\\r\\n\", FramePayloadFrameDesc->dwMinBitRate);\r\n    AppendTextBuffer(\"dwMaxBitRate:                0x%08X\\r\\n\", FramePayloadFrameDesc->dwMaxBitRate);\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n    AppendTextBuffer(\"dwDefaultFrameInterval:      0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n        FramePayloadFrameDesc->dwDefaultFrameInterval,\r\n        ((double)FramePayloadFrameDesc->dwDefaultFrameInterval)/10000.0,\r\n        (10000000.0/((double)FramePayloadFrameDesc->dwDefaultFrameInterval))\r\n        );\r\n    AppendTextBuffer(\"bFrameIntervalType:                0x%02X\\r\\n\", FramePayloadFrameDesc->bFrameIntervalType);\r\n\r\n    if (FramePayloadFrameDesc->bLength != bLength)\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required\r\n        //@@length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d\\r\\n\",\r\n            FramePayloadFrameDesc->bLength, bLength);\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFrameDesc->bFrameIndex == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - bFrameIndex\r\n        //@@bFrameIndex must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  bFrameIndex = 0, this is a 1 based index\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    //@@Descriptor Field - bmCapabilities\r\n    //@@Question:  Should we try to verify that bmCapabilities is valid?\r\n    //    AppendTextBuffer(\"bmCapabilities:                    0x%02X\\r\\n\", UnCompFrameDesc->bmCapabilities);\r\n\r\n    if (FramePayloadFrameDesc->wWidth == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - wWidth\r\n        //@@wWidth must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  wWidth must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFrameDesc->wHeight == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - wHeight\r\n        //@@wHeight must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  wHeight must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFrameDesc->dwMinBitRate == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate\r\n        //@@dwMinBitRate must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (FramePayloadFrameDesc->dwMaxBitRate == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxBitRate\r\n        //@@dwMaxBitRate must be nonzero\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxBitRate must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(FramePayloadFrameDesc->dwMinBitRate > FramePayloadFrameDesc->dwMaxBitRate)\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinBitRate and dwMaxBitRate\r\n        //@@Verify that dwMaxBitRate is greater than dwMinBitRate\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinBitRate should be less than dwMaxBitRate\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        if (FramePayloadFrameDesc->bFrameIntervalType == 1 &&\r\n            FramePayloadFrameDesc->dwMinBitRate != FramePayloadFrameDesc->dwMaxBitRate)\r\n        {\r\n            //@@WARNING\r\n            //@@Descriptor Field - bFrameIntervalType, dwMinBitRate, and dwMaxBitRate\r\n            //@@Verify that dwMaxBitRate is equal to dwMinBitRate if bFrameIntervalType is 1\r\n            AppendTextBuffer(\"*!*WARNING:  if bFrameIntervalType is 1 then dwMinBitRate \"\\\r\n                \"should equal dwMaxBitRate\\r\\n\");\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    if (FramePayloadFrameDesc->dwDefaultFrameInterval == 0 )\r\n    {\r\n        //@@TestCase B16.11 (descript.c line 1020)\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwDefaultFrameInterval\r\n        //@@dwDefaultFrameInterval must be nonzero\r\n        AppendTextBuffer(\"*!*WARNING:  dwDefaultFrameInterval must be nonzero\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (0 == FramePayloadFrameDesc->bFrameIntervalType)\r\n    {\r\n        DisplayFramePayloadContinuousFrameType(FramePayloadFrameDesc);\r\n    }\r\n    else\r\n    {\r\n        DisplayFramePayloadDiscreteFrameType(FramePayloadFrameDesc);\r\n    }\r\n    // This descriptor is new for UVC 1.1\r\n    if (UVC10 == g_chUVCversion)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR: This format is NOT ALLOWED for UVC 1.0 devices\\r\\n\");\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayFramePayloadContinuousFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayFramePayloadContinuousFrameType(\r\n                                PVIDEO_FRAME_FRAME FContinuousDesc\r\n                                )\r\n{\r\n    //@@DisplayFramePayloadContinuousFrameType -Frame Payload Continuous Frame\r\n    ULONG dwMinFrameInterval  = FContinuousDesc->adwFrameInterval[0];\r\n    ULONG dwMaxFrameInterval  = FContinuousDesc->adwFrameInterval[1];\r\n    ULONG dwFrameIntervalStep = FContinuousDesc->adwFrameInterval[2];\r\n\r\n    AppendTextBuffer(\"===>Additional Continuous Frame Type Data\\r\\n\");\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n\r\n    AppendTextBuffer(\"dwMinFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMinFrameInterval,\r\n        ((double)dwMinFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMinFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwMaxFrameInterval:          0x%08X = %lf mSec (%d Hz)\\r\\n\",\r\n        dwMaxFrameInterval,\r\n        ((double)dwMaxFrameInterval)/10000.0,\r\n        (ULONG)(10000000.0/((double)dwMaxFrameInterval) + 0.5));\r\n\r\n    AppendTextBuffer(\"dwFrameIntervalStep:         0x%08X\\r\\n\", dwFrameIntervalStep);\r\n\r\n    if (dwMinFrameInterval == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval\r\n        //@@dwMinFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwMaxFrameInterval == 0 )\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMaxFrameInterval\r\n        //@@dwMaxFrameInterval is set to zero which is not in accordance with the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  dwMaxFrameInterval = 0, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if(dwMinFrameInterval  > dwMaxFrameInterval)\r\n    {\r\n        //@@ERROR\r\n        //@@Descriptor Field - dwMinFrameInterval and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*ERROR:  dwMinFrameInterval is larger that dwMaxFrameInterval, this invalidates the descriptor\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMinFrameInterval + dwFrameIntervalStep) > dwMaxFrameInterval)\r\n    {\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that dwMaxFrameInterval is greater than dwMinFrameInterval combined with dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMinFrameInterval + dwFrameIntervalStep is greater than dwMaxFrameInterval, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) == 0 )\r\n    {\r\n        //@@CAUTION\r\n        //@@Descriptor Field - dwFrameIntervalStep\r\n        //@@Suggestion to use descrite frames if dwFrameIntervalStep is zero\r\n        AppendTextBuffer(\"*!*CAUTION:  dwFrameIntervalStep equals zero, consider using discrete frames\\r\\n\");\r\n        OOPS();\r\n    }\r\n    else if ((dwMaxFrameInterval - dwMinFrameInterval) % dwFrameIntervalStep )\r\n    {\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the difference between dwMaxFrameInterval and dwMinFrameInterval is evenly divisible by dwFrameIntervalStep\r\n        AppendTextBuffer(\"*!*WARNING:  dwMaxFrameInterval minus dwMinFrameInterval  is not evenly divisible by dwFrameIntervalStep, this could cause problems\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    if (dwFrameIntervalStep == 0 && (dwMaxFrameInterval - dwMinFrameInterval))\r\n    {\r\n        //@@WARNING\r\n        //@@Descriptor Field - dwFrameIntervalStep, dwMinFrameInterval, and dwMaxFrameInterval\r\n        //@@Verify that the dwFrameIntervalStep is not zero if there is a difference between dwMaxFrameInterval and dwMinFrameInterval\r\n        AppendTextBuffer(\"*!*WARNING:  dwFrameIntervalStep = 0, this invalidates the descriptor when there is a difference between dwMinFrameInterval and dwMaxFrameInterval\\r\\n\");\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayFramePayloadDiscreteFrameType()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayFramePayloadDiscreteFrameType(\r\n                              PVIDEO_FRAME_FRAME FDiscreteDesc\r\n                              )\r\n{\r\n    //@@DisplayFramePayloadDiscreteFrameType -Frame Based Payload Discrete Frame\r\n    UINT    iNdex = 1;\r\n    UINT    iCurFrame = 0;\r\n    ULONG   * ulFrameInterval = NULL;\r\n\r\n    AppendTextBuffer(\"===>Additional Discrete Frame Type Data\\r\\n\");\r\n\r\n    // There are (UDiscreteDesc->bFrameIntervalType) dwFrameIntervals (1 based index)\r\n    for (; iNdex <= FDiscreteDesc->bFrameIntervalType; iNdex++, iCurFrame++)\r\n    {\r\n        ulFrameInterval = &FDiscreteDesc->adwFrameInterval[iCurFrame];\r\n        // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n        // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n        // = 1/10,000 milliseconds\r\n\r\n\r\n        // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n        AppendTextBuffer(\"dwFrameInterval[%d]:          0x%08X = %lf mSec (%4.2f Hz)\\r\\n\",\r\n            iNdex, *ulFrameInterval,\r\n            ((double)*ulFrameInterval)/10000.0,\r\n            (10000000.0/((double)*ulFrameInterval))\r\n            );\r\n        if (0 == *ulFrameInterval)\r\n        {\r\n            //@@TestCase B18.1 (descript.c line 1061)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[x] must be non-zero\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[%d] must be non-zero\\r\\n\", iNdex);\r\n            OOPS();\r\n        }\r\n        if ((iNdex > 1)&&(*ulFrameInterval <= FDiscreteDesc->adwFrameInterval[iCurFrame - 1]))\r\n        {\r\n            //@@TestCase B18.2 (descript.c line 1067)\r\n            //@@ERROR\r\n            //@@Descriptor Field - dwFrameInterval[x]\r\n            //@@dwFrameInterval[n] must be greater than dwFrameInterval[n - 1]\r\n            AppendTextBuffer(\"*!*ERROR:  dwFrameInterval[0x%02X] must be \"\\\r\n                \"greater than preceding dwFrameInterval[0x%02X]\\r\\n\", iNdex, iNdex - 1);\r\n            OOPS();\r\n        }\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVSEndpoint()\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nDisplayVSEndpoint (\r\n                   PVIDEO_CS_INTERRUPT VidEndpointDesc\r\n                   )\r\n{\r\n    //@@DisplayVSEndpoint - Video Streaming Endpoint\r\n    AppendTextBuffer(\"\\r\\n          ===>Class-specific VC Interrupt Endpoint Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X \\r\\n\", VidEndpointDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X\\r\\n\", VidEndpointDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X\\r\\n\", VidEndpointDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"wMaxTransferSize:                0x%04X\", VidEndpointDesc->wMaxTransferSize);\r\n    if(gDoAnnotation) {\r\n        AppendTextBuffer(\" = (%d) Bytes\\r\\n\", VidEndpointDesc->wMaxTransferSize);}\r\n    else {AppendTextBuffer(\"\\r\\n\");}\r\n\r\n    if (VidEndpointDesc->bLength != sizeof(VIDEO_CS_INTERRUPT))\r\n    {\r\n        //@@TestCase B32.1 (descript.c line 1616)\r\n        //@@ERROR\r\n        //@@Descriptor Field - bLength\r\n        //@@The declared length in the device descriptor is not equal to the required length in the USB Video Device Specification\r\n        AppendTextBuffer(\"*!*ERROR:  bLength of %d incorrect, should be %d.  USBView cannot correctly display descriptor\\r\\n\",\r\n            VidEndpointDesc->bLength,\r\n            sizeof(VIDEO_CS_INTERRUPT));\r\n        OOPS();\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// VDisplayBytes()\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nVDisplayBytes (\r\n               PUCHAR Data,\r\n               USHORT Len\r\n               )\r\n{\r\n    USHORT i = 0;\r\n\r\n    for (i = 0; i < Len; i++)\r\n    {\r\n        AppendTextBuffer(\"0x%02X \", Data[i]);\r\n\r\n        if (i % 16 == 15)\r\n        {\r\n            AppendTextBuffer(\"\\r\\n\");\r\n        }\r\n    }\r\n\r\n    if (i % 16 != 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n\");\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// VidFormatGUIDCodeToName()\r\n//\r\n//*****************************************************************************\r\n\r\n\r\nPCHAR\r\nVidFormatGUIDCodeToName (\r\n                         REFGUID VidFormatGUIDCode\r\n                         )\r\n{\r\n    //  GUID pYUY2 = YUY2_Format;\r\n    //  GUID pNV12 = NV12_Format;\r\n    if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &YUY2_Format))\r\n    {\r\n        return (PCHAR) &\"YUY2\";\r\n    }\r\n    if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &NV12_Format))\r\n    {\r\n        return (PCHAR) &\"NV12\";\r\n    }\r\n#ifdef H264_SUPPORT\r\n    //  GUID pH264 = H264_Format;\r\n    if (IsEqualGUID(VidFormatGUIDCode, (REFGUID) &H264_Format))\r\n    {\r\n        return (PCHAR) &\"H.264\";\r\n    }\r\n#endif\r\n\r\n    return FALSE;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetVCInterfaceSize()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nGetVCInterfaceSize (\r\n                    PVIDEO_CONTROL_HEADER_UNIT VCInterfaceDesc\r\n                   )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR) VCInterfaceDesc;\r\n    PUCHAR descEnd = (PUCHAR) VCInterfaceDesc + VCInterfaceDesc->wTotalLength;\r\n    UINT  uCount = 0;\r\n\r\n    // return this interface's sum of descriptor lengths\r\n    //   starting from this header until (and not including) the first endpoint\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        if (commonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)\r\n            break;\r\n        uCount += commonDesc->bLength;\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uCount);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nCheckForColorMatchingDesc ()\r\n\r\nGiven starting address of format descriptor;\r\nnumber of frame descriptors;\r\nsubtype of frame to look for;\r\n\r\n1) walk through each descriptor\r\n= if desc is frame of given subtype, update counter\r\n= if desc is still frame, update counter\r\n= if desc is color matching descriptor, update counter\r\n! if frame is something else, break (all these frames should be consecutive)\r\n! if next frame is beyond ending address of configuration, break\r\n\r\nPASS\r\nframe count == numframes passed in\r\ncolor match == 1\r\nstill frames are handled in the video stream input header and the frame displays\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nCheckForColorMatchingDesc (\r\n                           PVIDEO_SPECIFIC pFormatDesc,\r\n                           UCHAR bNumFrameDescriptors,\r\n                           UCHAR bDescriptorSubtype\r\n                          )\r\n{\r\n    UINT  uFrameCount = 0;\r\n    UINT  uStillFrameCount = 0;\r\n    UINT  uColorCount = 0;\r\n\r\n    // DONE if the descriptor address is beyond the configuration range\r\n    for ( ; ValidateDescAddress ((PUSB_COMMON_DESCRIPTOR) pFormatDesc); )\r\n    {\r\n        // DONE if it's not an interface desc\r\n        if (CS_INTERFACE != pFormatDesc->bDescriptorType)\r\n        {\r\n            break;\r\n        }\r\n        switch (pFormatDesc->bDescriptorSubtype)\r\n        {\r\n            case VS_STILL_IMAGE_FRAME:\r\n                uStillFrameCount++;\r\n                break;\r\n            case VS_COLORFORMAT:\r\n                uColorCount++;\r\n                break;\r\n            default:\r\n                if (bDescriptorSubtype == pFormatDesc->bDescriptorSubtype)\r\n                {\r\n                    uFrameCount++;\r\n                }\r\n                break;\r\n        }\r\n        pFormatDesc = (PVIDEO_SPECIFIC) ((PUCHAR) pFormatDesc + pFormatDesc->bLength);\r\n    }\r\n    if (uFrameCount != bNumFrameDescriptors)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  Found %d frame descriptors (should be %d)\\r\\n\",\r\n            uFrameCount, bNumFrameDescriptors);\r\n    }\r\n    // We already check Still Frames in the Video Info Header and Still Frames displays\r\n    if (0 == uColorCount)\r\n    {\r\n        AppendTextBuffer(\"*!*ERROR:  no Color Matching Descriptor for this format\\r\\n\");\r\n    }\r\n    return (uColorCount);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nGetVSInterfaceSize()\r\n\r\n*****************************************************************************/\r\n\r\nUINT\r\nGetVSInterfaceSize (\r\n                    PUSB_COMMON_DESCRIPTOR VidInHeaderDesc,\r\n                    USHORT wTotalLength\r\n                   )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR) VidInHeaderDesc;\r\n    PUCHAR descEnd = (PUCHAR) VidInHeaderDesc + wTotalLength;\r\n    UINT  uCount = 0;\r\n\r\n    // return this interface's sum of descriptor lengths\r\n    //   starting from this header until (and not including) the first endpoint\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        if (commonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)\r\n            break;\r\n        uCount += commonDesc->bLength;\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n    return (uCount);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nValidateTerminalID()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nValidateTerminalID(\r\n                   UINT uTerminalID\r\n                   )\r\n{\r\n    UNREFERENCED_PARAMETER(uTerminalID);\r\n    return (TRUE);\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/enum.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2011 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    ENUM.C\r\n\r\nAbstract:\r\n\r\n    This source file contains the routines which enumerate the USB bus\r\n    and populate the TreeView control.\r\n\r\n    The enumeration process goes like this:\r\n\r\n    (1) Enumerate Host Controllers and Root Hubs\r\n    EnumerateHostControllers()\r\n    EnumerateHostController()\r\n    Host controllers currently have symbolic link names of the form HCDx,\r\n    where x starts at 0.  Use CreateFile() to open each host controller\r\n    symbolic link.  Create a node in the TreeView to represent each host\r\n    controller.\r\n\r\n    GetRootHubName()\r\n    After a host controller has been opened, send the host controller an\r\n    IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of\r\n    the root hub that is part of the host controller.\r\n\r\n    (2) Enumerate Hubs (Root Hubs and External Hubs)\r\n    EnumerateHub()\r\n    Given the name of a hub, use CreateFile() to map the hub.  Send the\r\n    hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the\r\n    hub, such as the number of downstream ports.  Create a node in the\r\n    TreeView to represent each hub.\r\n\r\n    (3) Enumerate Downstream Ports\r\n    EnumerateHubPorts()\r\n    Given an handle to an open hub and the number of downstream ports on\r\n    the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\r\n    request for each downstream port of the hub to get info about the\r\n    device (if any) attached to each port.  If there is a device attached\r\n    to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request\r\n    to get the symbolic link name of the hub attached to the downstream\r\n    port.  If there is a hub attached to the downstream port, recurse to\r\n    step (2).\r\n\r\n    GetAllStringDescriptors()\r\n    GetConfigDescriptor()\r\n    Create a node in the TreeView to represent each hub port\r\n    and attached device.\r\n\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    04-25-97 : created\r\n\r\n--*/\r\n\r\n//*****************************************************************************\r\n// I N C L U D E S\r\n//*****************************************************************************\r\n\r\n#include \"uvcview.h\"\r\n\r\n//*****************************************************************************\r\n// D E F I N E S\r\n//*****************************************************************************\r\n\r\n#define NUM_STRING_DESC_TO_GET 32\r\n\r\n//*****************************************************************************\r\n// L O C A L    F U N C T I O N    P R O T O T Y P E S\r\n//*****************************************************************************\r\n\r\nVOID\r\nEnumerateHostControllers (\r\n    HTREEITEM  hTreeParent,\r\n    ULONG     *DevicesConnected\r\n);\r\n\r\nVOID\r\nEnumerateHostController (\r\n    HTREEITEM                hTreeParent,\r\n    HANDLE                   hHCDev,\r\n    _Inout_ PCHAR            leafName,\r\n    _In_    HANDLE           deviceInfo,\r\n    _In_    PSP_DEVINFO_DATA deviceInfoData\r\n);\r\n\r\nVOID\r\nEnumerateHub (\r\n    HTREEITEM                                       hTreeParent,\r\n    _In_reads_(cbHubName) PCHAR                     HubName,\r\n    _In_ size_t                                     cbHubName,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfo,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2,\r\n    _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps,\r\n    _In_opt_ PUSB_DESCRIPTOR_REQUEST                ConfigDesc,\r\n    _In_opt_ PUSB_DESCRIPTOR_REQUEST                BosDesc,\r\n    _In_opt_ PSTRING_DESCRIPTOR_NODE                StringDescs,\r\n    _In_opt_ PUSB_DEVICE_PNP_STRINGS                DevProps\r\n);\r\n\r\nVOID\r\nEnumerateHubPorts (\r\n    HTREEITEM   hTreeParent,\r\n    HANDLE      hHubDevice,\r\n    ULONG       NumPorts\r\n);\r\n\r\nPCHAR GetRootHubName (\r\n    HANDLE HostController\r\n);\r\n\r\nPCHAR GetExternalHubName (\r\n    HANDLE  Hub,\r\n    ULONG   ConnectionIndex\r\n);\r\n\r\nPCHAR GetHCDDriverKeyName (\r\n    HANDLE  HCD\r\n);\r\n\r\nPCHAR GetDriverKeyName (\r\n    HANDLE  Hub,\r\n    ULONG   ConnectionIndex\r\n);\r\n\r\nPUSB_DESCRIPTOR_REQUEST\r\nGetConfigDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex,\r\n    UCHAR   DescriptorIndex\r\n    );\r\n\r\nPUSB_DESCRIPTOR_REQUEST\r\nGetBOSDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex\r\n    );\r\n\r\nDWORD\r\nGetHostControllerPowerMap(\r\n    HANDLE hHCDev,\r\n    PUSBHOSTCONTROLLERINFO hcInfo);\r\n\r\nDWORD\r\nGetHostControllerInfo(\r\n    HANDLE hHCDev,\r\n    PUSBHOSTCONTROLLERINFO hcInfo);\r\n\r\nPCHAR WideStrToMultiStr (\r\n     _In_reads_bytes_(cbWideStr) PWCHAR WideStr,\r\n     _In_ size_t                   cbWideStr\r\n     );\r\n\r\nBOOL\r\nAreThereStringDescriptors (\r\n    PUSB_DEVICE_DESCRIPTOR          DeviceDesc,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc\r\n);\r\n\r\nPSTRING_DESCRIPTOR_NODE\r\nGetAllStringDescriptors (\r\n    HANDLE                          hHubDevice,\r\n    ULONG                           ConnectionIndex,\r\n    PUSB_DEVICE_DESCRIPTOR          DeviceDesc,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc\r\n);\r\n\r\nPSTRING_DESCRIPTOR_NODE\r\nGetStringDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex,\r\n    UCHAR   DescriptorIndex,\r\n    USHORT  LanguageID\r\n);\r\n\r\nHRESULT\r\nGetStringDescriptors (\r\n    _In_ HANDLE                         hHubDevice,\r\n    _In_ ULONG                          ConnectionIndex,\r\n    _In_ UCHAR                          DescriptorIndex,\r\n    _In_ ULONG                          NumLanguageIDs,\r\n    _In_reads_(NumLanguageIDs) USHORT  *LanguageIDs,\r\n    _In_ PSTRING_DESCRIPTOR_NODE        StringDescNodeHead\r\n);\r\n\r\nvoid\r\nEnumerateAllDevices();\r\n\r\n\r\nvoid\r\nEnumerateAllDevicesWithGuid(\r\n    PDEVICE_GUID_LIST DeviceList,\r\n    LPGUID Guid\r\n    );\r\n\r\nvoid\r\nFreeDeviceInfoNode(\r\n    _In_ PDEVICE_INFO_NODE *ppNode\r\n    );\r\n\r\nPDEVICE_INFO_NODE\r\nFindMatchingDeviceNodeForDriverName(\r\n    _In_ PSTR    DriverKeyName,\r\n    _In_ BOOLEAN IsHub\r\n    );\r\n\r\n\r\n//*****************************************************************************\r\n// G L O B A L S\r\n//*****************************************************************************\r\n\r\n// List of enumerated host controllers.\r\n//\r\nLIST_ENTRY EnumeratedHCListHead =\r\n{\r\n    &EnumeratedHCListHead,\r\n    &EnumeratedHCListHead\r\n};\r\n\r\nDEVICE_GUID_LIST gHubList;\r\nDEVICE_GUID_LIST gDeviceList;\r\n\r\n\r\n//*****************************************************************************\r\n// G L O B A L S    P R I V A T E    T O    T H I S    F I L E\r\n//*****************************************************************************\r\n\r\nPCHAR ConnectionStatuses[] =\r\n{\r\n    \"\",                   // 0  - NoDeviceConnected\r\n    \"\",                   // 1  - DeviceConnected\r\n    \"FailedEnumeration\",  // 2  - DeviceFailedEnumeration\r\n    \"GeneralFailure\",     // 3  - DeviceGeneralFailure\r\n    \"Overcurrent\",        // 4  - DeviceCausedOvercurrent\r\n    \"NotEnoughPower\",     // 5  - DeviceNotEnoughPower\r\n    \"NotEnoughBandwidth\", // 6  - DeviceNotEnoughBandwidth\r\n    \"HubNestedTooDeeply\", // 7  - DeviceHubNestedTooDeeply\r\n    \"InLegacyHub\",        // 8  - DeviceInLegacyHub\r\n    \"Enumerating\",        // 9  - DeviceEnumerating\r\n    \"Reset\"               // 10 - DeviceReset\r\n};\r\n\r\nULONG TotalDevicesConnected;\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// EnumerateHostControllers()\r\n//\r\n// hTreeParent - Handle of the TreeView item under which host controllers\r\n// should be added.\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nEnumerateHostControllers (\r\n    HTREEITEM  hTreeParent,\r\n    ULONG     *DevicesConnected\r\n)\r\n{\r\n    HANDLE                           hHCDev = NULL;\r\n    HDEVINFO                         deviceInfo = NULL;\r\n    SP_DEVINFO_DATA                  deviceInfoData;\r\n    SP_DEVICE_INTERFACE_DATA         deviceInterfaceData;\r\n    PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = NULL;\r\n    ULONG                            index = 0;\r\n    ULONG                            requiredLength = 0;\r\n    BOOL                             success;\r\n\r\n    TotalDevicesConnected = 0;\r\n    TotalHubs = 0;\r\n\r\n    EnumerateAllDevices();\r\n\r\n    // Iterate over host controllers using the new GUID based interface\r\n    //\r\n    deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,\r\n                                     NULL,\r\n                                     NULL,\r\n                                     (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));\r\n\r\n    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r\n\r\n    for (index=0;\r\n         SetupDiEnumDeviceInfo(deviceInfo,\r\n                               index,\r\n                               &deviceInfoData);\r\n         index++)\r\n    {\r\n        deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);\r\n\r\n        success = SetupDiEnumDeviceInterfaces(deviceInfo,\r\n                                              0,\r\n                                              (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,\r\n                                              index,\r\n                                              &deviceInterfaceData);\r\n\r\n        if (!success)\r\n        {\r\n            OOPS();\r\n            break;\r\n        }\r\n\r\n        success = SetupDiGetDeviceInterfaceDetail(deviceInfo,\r\n                                                  &deviceInterfaceData,\r\n                                                  NULL,\r\n                                                  0,\r\n                                                  &requiredLength,\r\n                                                  NULL);\r\n\r\n        if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)\r\n        {\r\n            OOPS();\r\n            break;\r\n        }\r\n\r\n        deviceDetailData = ALLOC(requiredLength);\r\n        if (deviceDetailData == NULL)\r\n        {\r\n            OOPS();\r\n            break;\r\n        }\r\n\r\n        deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);\r\n\r\n        success = SetupDiGetDeviceInterfaceDetail(deviceInfo,\r\n                                                  &deviceInterfaceData,\r\n                                                  deviceDetailData,\r\n                                                  requiredLength,\r\n                                                  &requiredLength,\r\n                                                  NULL);\r\n\r\n        if (!success)\r\n        {\r\n            OOPS();\r\n            break;\r\n        }\r\n\r\n        hHCDev = CreateFile(deviceDetailData->DevicePath,\r\n                            GENERIC_WRITE,\r\n                            FILE_SHARE_WRITE,\r\n                            NULL,\r\n                            OPEN_EXISTING,\r\n                            0,\r\n                            NULL);\r\n\r\n        // If the handle is valid, then we've successfully opened a Host\r\n        // Controller.  Display some info about the Host Controller itself,\r\n        // then enumerate the Root Hub attached to the Host Controller.\r\n        //\r\n        if (hHCDev != INVALID_HANDLE_VALUE)\r\n        {\r\n            EnumerateHostController(hTreeParent,\r\n                                    hHCDev,\r\n                                    deviceDetailData->DevicePath,\r\n                                    deviceInfo,\r\n                                    &deviceInfoData);\r\n\r\n            CloseHandle(hHCDev);\r\n        }\r\n\r\n        FREE(deviceDetailData);\r\n    }\r\n\r\n    SetupDiDestroyDeviceInfoList(deviceInfo);\r\n\r\n    *DevicesConnected = TotalDevicesConnected;\r\n\r\n    return;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// EnumerateHostController()\r\n//\r\n// hTreeParent - Handle of the TreeView item under which host controllers\r\n// should be added.\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nEnumerateHostController (\r\n    HTREEITEM                hTreeParent,\r\n    HANDLE                   hHCDev,    _Inout_ PCHAR            leafName,\r\n    _In_    HANDLE           deviceInfo,\r\n    _In_    PSP_DEVINFO_DATA deviceInfoData\r\n)\r\n{\r\n    PCHAR                   driverKeyName = NULL;\r\n    HTREEITEM               hHCItem = NULL;\r\n    PCHAR                   rootHubName = NULL;\r\n    PLIST_ENTRY             listEntry = NULL;\r\n    PUSBHOSTCONTROLLERINFO  hcInfo = NULL;\r\n    PUSBHOSTCONTROLLERINFO  hcInfoInList = NULL;\r\n    DWORD                   dwSuccess;\r\n    BOOL                    success = FALSE;\r\n    ULONG                   deviceAndFunction = 0;\r\n    PUSB_DEVICE_PNP_STRINGS DevProps = NULL;\r\n\r\n\r\n    // Allocate a structure to hold information about this host controller.\r\n    //\r\n    hcInfo = (PUSBHOSTCONTROLLERINFO)ALLOC(sizeof(USBHOSTCONTROLLERINFO));\r\n\r\n    // just return if could not alloc memory\r\n    if (NULL == hcInfo)\r\n        return;\r\n\r\n    hcInfo->DeviceInfoType = HostControllerInfo;\r\n\r\n    // Obtain the driver key name for this host controller.\r\n    //\r\n    driverKeyName = GetHCDDriverKeyName(hHCDev);\r\n\r\n    if (NULL == driverKeyName)\r\n    {\r\n        // Failure obtaining driver key name.\r\n        OOPS();\r\n        FREE(hcInfo);\r\n        return;\r\n    }\r\n\r\n    // Don't enumerate this host controller again if it already\r\n    // on the list of enumerated host controllers.\r\n    //\r\n    listEntry = EnumeratedHCListHead.Flink;\r\n\r\n    while (listEntry != &EnumeratedHCListHead)\r\n    {\r\n        hcInfoInList = CONTAINING_RECORD(listEntry,\r\n                                         USBHOSTCONTROLLERINFO,\r\n                                         ListEntry);\r\n\r\n        if (strcmp(driverKeyName, hcInfoInList->DriverKey) == 0)\r\n        {\r\n            // Already on the list, exit\r\n            //\r\n            FREE(driverKeyName);\r\n            FREE(hcInfo);\r\n            return;\r\n        }\r\n\r\n        listEntry = listEntry->Flink;\r\n    }\r\n\r\n    // Obtain host controller device properties\r\n    {\r\n        size_t cbDriverName = 0;\r\n        HRESULT hr = S_OK;\r\n\r\n        hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName);\r\n        if (SUCCEEDED(hr))\r\n        {\r\n            DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName);\r\n        }\r\n    }\r\n\r\n    hcInfo->DriverKey = driverKeyName;\r\n\r\n    if (DevProps)\r\n    {\r\n        ULONG   ven, dev, subsys, rev;\r\n        ven = dev = subsys = rev = 0;\r\n\r\n        if (sscanf_s(DevProps->DeviceId,\r\n                   \"PCI\\\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x\",\r\n                   &ven, &dev, &subsys, &rev) != 4)\r\n        {\r\n            OOPS();\r\n        }\r\n\r\n        hcInfo->VendorID = ven;\r\n        hcInfo->DeviceID = dev;\r\n        hcInfo->SubSysID = subsys;\r\n        hcInfo->Revision = rev;\r\n        hcInfo->UsbDeviceProperties = DevProps;\r\n    }\r\n    else\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n    if (DevProps != NULL && DevProps->DeviceDesc != NULL)\r\n    {\r\n        leafName = DevProps->DeviceDesc;\r\n    }\r\n    else\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n    // Get the USB Host Controller power map\r\n    dwSuccess = GetHostControllerPowerMap(hHCDev, hcInfo);\r\n\r\n    if (ERROR_SUCCESS != dwSuccess)\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n\r\n    // Get bus, device, and function\r\n    //\r\n    hcInfo->BusDeviceFunctionValid = FALSE;\r\n\r\n    success = SetupDiGetDeviceRegistryProperty(deviceInfo,\r\n                                               deviceInfoData,\r\n                                               SPDRP_BUSNUMBER,\r\n                                               NULL,\r\n                                               (PBYTE)&hcInfo->BusNumber,\r\n                                               sizeof(hcInfo->BusNumber),\r\n                                               NULL);\r\n\r\n    if (success)\r\n    {\r\n        success = SetupDiGetDeviceRegistryProperty(deviceInfo,\r\n                                                   deviceInfoData,\r\n                                                   SPDRP_ADDRESS,\r\n                                                   NULL,\r\n                                                   (PBYTE)&deviceAndFunction,\r\n                                                   sizeof(deviceAndFunction),\r\n                                                   NULL);\r\n    }\r\n\r\n    if (success)\r\n    {\r\n        hcInfo->BusDevice = deviceAndFunction >> 16;\r\n        hcInfo->BusFunction = deviceAndFunction & 0xffff;\r\n        hcInfo->BusDeviceFunctionValid = TRUE;\r\n    }\r\n\r\n    // Get the USB Host Controller info\r\n    dwSuccess = GetHostControllerInfo(hHCDev, hcInfo);\r\n\r\n    if (ERROR_SUCCESS != dwSuccess)\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n    // Add this host controller to the USB device tree view.\r\n    //\r\n    hHCItem = AddLeaf(hTreeParent,\r\n                      (LPARAM)hcInfo,\r\n                      leafName,\r\n                      hcInfo->Revision == UsbSuperSpeed ? GoodSsDeviceIcon : GoodDeviceIcon);\r\n\r\n    if (NULL == hHCItem)\r\n    {\r\n        // Failure adding host controller to USB device tree\r\n        // view.\r\n\r\n        OOPS();\r\n        FREE(driverKeyName);\r\n        FREE(hcInfo);\r\n        return;\r\n    }\r\n\r\n    // Add this host controller to the list of enumerated\r\n    // host controllers.\r\n    //\r\n    InsertTailList(&EnumeratedHCListHead,\r\n                   &hcInfo->ListEntry);\r\n\r\n    // Get the name of the root hub for this host\r\n    // controller and then enumerate the root hub.\r\n    //\r\n    rootHubName = GetRootHubName(hHCDev);\r\n\r\n    if (rootHubName != NULL)\r\n    {\r\n        size_t cbHubName = 0;\r\n        HRESULT hr = S_OK;\r\n\r\n        hr = StringCbLength(rootHubName, MAX_DRIVER_KEY_NAME, &cbHubName);\r\n        if (SUCCEEDED(hr))\r\n        {\r\n            EnumerateHub(hHCItem,\r\n                         rootHubName,\r\n                         cbHubName,\r\n                         NULL,       // ConnectionInfo\r\n                         NULL,       // ConnectionInfoV2\r\n                         NULL,       // PortConnectorProps\r\n                         NULL,       // ConfigDesc\r\n                         NULL,       // BosDesc\r\n                         NULL,       // StringDescs\r\n                         NULL);      // We do not pass DevProps for RootHub\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // Failure obtaining root hub name.\r\n\r\n        OOPS();\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// EnumerateHub()\r\n//\r\n// hTreeParent - Handle of the TreeView item under which this hub should be\r\n// added.\r\n//\r\n// HubName - Name of this hub.  This pointer is kept so the caller can neither\r\n// free nor reuse this memory.\r\n//\r\n// ConnectionInfo - NULL if this is a root hub, else this is the connection\r\n// info for an external hub.  This pointer is kept so the caller can neither\r\n// free nor reuse this memory.\r\n//\r\n// ConfigDesc - NULL if this is a root hub, else this is the Configuration\r\n// Descriptor for an external hub.  This pointer is kept so the caller can\r\n// neither free nor reuse this memory.\r\n//\r\n// StringDescs - NULL if this is a root hub.\r\n//\r\n// DevProps - Device properties of the hub\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nEnumerateHub (\r\n    HTREEITEM                                       hTreeParent,\r\n    _In_reads_(cbHubName) PCHAR                     HubName,\r\n    _In_ size_t                                     cbHubName,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfo,\r\n    _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2,\r\n    _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps,\r\n    _In_opt_ PUSB_DESCRIPTOR_REQUEST                ConfigDesc,\r\n    _In_opt_ PUSB_DESCRIPTOR_REQUEST                BosDesc,\r\n    _In_opt_ PSTRING_DESCRIPTOR_NODE                StringDescs,\r\n    _In_opt_ PUSB_DEVICE_PNP_STRINGS                DevProps\r\n    )\r\n{\r\n    // Initialize locals to not allocated state so the error cleanup routine\r\n    // only tries to cleanup things that were successfully allocated.\r\n    //\r\n    PUSB_NODE_INFORMATION    hubInfo = NULL;\r\n    PUSB_HUB_INFORMATION_EX  hubInfoEx = NULL;\r\n    PUSB_HUB_CAPABILITIES_EX hubCapabilityEx = NULL;\r\n    HANDLE                  hHubDevice = INVALID_HANDLE_VALUE;\r\n    HTREEITEM               hItem = NULL;\r\n    PVOID                   info = NULL;\r\n    PCHAR                   deviceName = NULL;\r\n    ULONG                   nBytes = 0;\r\n    BOOL                    success = 0;\r\n    DWORD                   dwSizeOfLeafName = 0;\r\n    CHAR                    leafName[512] = {0};\r\n    HRESULT                 hr = S_OK;\r\n    size_t                  cchHeader = 0;\r\n    size_t                  cchFullHubName = 0;\r\n\r\n    // Allocate some space for a USBDEVICEINFO structure to hold the\r\n    // hub info, hub name, and connection info pointers.  GPTR zero\r\n    // initializes the structure for us.\r\n    //\r\n    info = ALLOC(sizeof(USBEXTERNALHUBINFO));\r\n    if (info == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    // Allocate some space for a USB_NODE_INFORMATION structure for this Hub\r\n    //\r\n    hubInfo = (PUSB_NODE_INFORMATION)ALLOC(sizeof(USB_NODE_INFORMATION));\r\n    if (hubInfo == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    hubInfoEx = (PUSB_HUB_INFORMATION_EX)ALLOC(sizeof(USB_HUB_INFORMATION_EX));\r\n    if (hubInfoEx == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    hubCapabilityEx = (PUSB_HUB_CAPABILITIES_EX)ALLOC(sizeof(USB_HUB_CAPABILITIES_EX));\r\n    if(hubCapabilityEx == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    // Keep copies of the Hub Name, Connection Info, and Configuration\r\n    // Descriptor pointers\r\n    //\r\n    ((PUSBROOTHUBINFO)info)->HubInfo   = hubInfo;\r\n    ((PUSBROOTHUBINFO)info)->HubName   = HubName;\r\n\r\n    if (ConnectionInfo != NULL)\r\n    {\r\n        ((PUSBEXTERNALHUBINFO)info)->DeviceInfoType = ExternalHubInfo;\r\n        ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo = ConnectionInfo;\r\n        ((PUSBEXTERNALHUBINFO)info)->ConfigDesc = ConfigDesc;\r\n        ((PUSBEXTERNALHUBINFO)info)->StringDescs = StringDescs;\r\n        ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps = PortConnectorProps;\r\n        ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = hubInfoEx;\r\n        ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = hubCapabilityEx;\r\n        ((PUSBEXTERNALHUBINFO)info)->BosDesc = BosDesc;\r\n        ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2 = ConnectionInfoV2;\r\n        ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties = DevProps;\r\n    }\r\n    else\r\n    {\r\n        ((PUSBROOTHUBINFO)info)->DeviceInfoType = RootHubInfo;\r\n        ((PUSBROOTHUBINFO)info)->HubInfoEx = hubInfoEx;\r\n        ((PUSBROOTHUBINFO)info)->HubCapabilityEx = hubCapabilityEx;\r\n        ((PUSBROOTHUBINFO)info)->PortConnectorProps = PortConnectorProps;\r\n        ((PUSBROOTHUBINFO)info)->UsbDeviceProperties = DevProps;\r\n    }\r\n\r\n    // Allocate a temp buffer for the full hub device name.\r\n    //\r\n    hr = StringCbLength(\"\\\\\\\\.\\\\\", MAX_DEVICE_PROP, &cchHeader);\r\n    if (FAILED(hr))\r\n    {\r\n        goto EnumerateHubError;\r\n    }\r\n    cchFullHubName = cchHeader + cbHubName + 1;\r\n    deviceName = (PCHAR)ALLOC((DWORD) cchFullHubName);\r\n    if (deviceName == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    // Create the full hub device name\r\n    //\r\n    hr = StringCchCopyN(deviceName, cchFullHubName, \"\\\\\\\\.\\\\\", cchHeader);\r\n    if (FAILED(hr))\r\n    {\r\n        goto EnumerateHubError;\r\n    }\r\n    hr = StringCchCatN(deviceName, cchFullHubName, HubName, cbHubName);\r\n    if (FAILED(hr))\r\n    {\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    // Try to hub the open device\r\n    //\r\n    hHubDevice = CreateFile(deviceName,\r\n                            GENERIC_WRITE,\r\n                            FILE_SHARE_WRITE,\r\n                            NULL,\r\n                            OPEN_EXISTING,\r\n                            0,\r\n                            NULL);\r\n\r\n    // Done with temp buffer for full hub device name\r\n    //\r\n    FREE(deviceName);\r\n\r\n    if (hHubDevice == INVALID_HANDLE_VALUE)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    //\r\n    // Now query USBHUB for the USB_NODE_INFORMATION structure for this hub.\r\n    // This will tell us the number of downstream ports to enumerate, among\r\n    // other things.\r\n    //\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_NODE_INFORMATION,\r\n                              hubInfo,\r\n                              sizeof(USB_NODE_INFORMATION),\r\n                              hubInfo,\r\n                              sizeof(USB_NODE_INFORMATION),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_HUB_INFORMATION_EX,\r\n                              hubInfoEx,\r\n                              sizeof(USB_HUB_INFORMATION_EX),\r\n                              hubInfoEx,\r\n                              sizeof(USB_HUB_INFORMATION_EX),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    //\r\n    // Fail gracefully for downlevel OS's from Win8\r\n    //\r\n    if (!success || nBytes < sizeof(USB_HUB_INFORMATION_EX))\r\n    {\r\n        FREE(hubInfoEx);\r\n        hubInfoEx = NULL;\r\n        if (ConnectionInfo != NULL)\r\n        {\r\n            ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = NULL;\r\n        }\r\n        else\r\n        {\r\n            ((PUSBROOTHUBINFO)info)->HubInfoEx = NULL;\r\n        }\r\n    }\r\n\r\n    //\r\n    // Obtain Hub Capabilities\r\n    //\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_HUB_CAPABILITIES_EX,\r\n                              hubCapabilityEx,\r\n                              sizeof(USB_HUB_CAPABILITIES_EX),\r\n                              hubCapabilityEx,\r\n                              sizeof(USB_HUB_CAPABILITIES_EX),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    //\r\n    // Fail gracefully\r\n    //\r\n    if (!success || nBytes < sizeof(USB_HUB_CAPABILITIES_EX))\r\n    {\r\n        FREE(hubCapabilityEx);\r\n        hubCapabilityEx = NULL;\r\n        if (ConnectionInfo != NULL)\r\n        {\r\n            ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = NULL;\r\n        }\r\n        else\r\n        {\r\n            ((PUSBROOTHUBINFO)info)->HubCapabilityEx = NULL;\r\n        }\r\n    }\r\n\r\n    // Build the leaf name from the port number and the device description\r\n    //\r\n    dwSizeOfLeafName = sizeof(leafName);\r\n    if (ConnectionInfo)\r\n    {\r\n        StringCchPrintf(leafName, dwSizeOfLeafName, \"[Port%d] \", ConnectionInfo->ConnectionIndex);\r\n        StringCchCat(leafName,\r\n            dwSizeOfLeafName,\r\n            ConnectionStatuses[ConnectionInfo->ConnectionStatus]);\r\n        StringCchCatN(leafName,\r\n            dwSizeOfLeafName,\r\n            \" :  \",\r\n            sizeof(\" :  \"));\r\n    }\r\n\r\n    if (DevProps)\r\n    {\r\n        size_t cbDeviceDesc = 0;\r\n        hr = StringCbLength(DevProps->DeviceDesc, MAX_DRIVER_KEY_NAME, &cbDeviceDesc);\r\n        if(SUCCEEDED(hr))\r\n        {\r\n            StringCchCatN(leafName,\r\n                    dwSizeOfLeafName,\r\n                    DevProps->DeviceDesc,\r\n                    cbDeviceDesc);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        if(ConnectionInfo != NULL)\r\n        {\r\n            // External hub\r\n            StringCchCatN(leafName,\r\n                    dwSizeOfLeafName,\r\n                    HubName,\r\n                    cbHubName);\r\n        }\r\n        else\r\n        {\r\n            // Root hub\r\n            StringCchCatN(leafName,\r\n                    dwSizeOfLeafName,\r\n                    \"RootHub\",\r\n                    sizeof(\"RootHub\"));\r\n        }\r\n    }\r\n\r\n    // Now add an item to the TreeView with the PUSBDEVICEINFO pointer info\r\n    // as the LPARAM reference value containing everything we know about the\r\n    // hub.\r\n    //\r\n    hItem = AddLeaf(hTreeParent,\r\n                    (LPARAM)info,\r\n                    leafName,\r\n                    HubIcon);\r\n\r\n    if (hItem == NULL)\r\n    {\r\n        OOPS();\r\n        goto EnumerateHubError;\r\n    }\r\n\r\n    // Now recursively enumerate the ports of this hub.\r\n    //\r\n    EnumerateHubPorts(\r\n        hItem,\r\n        hHubDevice,\r\n        hubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts\r\n        );\r\n\r\n\r\n    CloseHandle(hHubDevice);\r\n    return;\r\n\r\nEnumerateHubError:\r\n    //\r\n    // Clean up any stuff that got allocated\r\n    //\r\n\r\n    if (hHubDevice != INVALID_HANDLE_VALUE)\r\n    {\r\n        CloseHandle(hHubDevice);\r\n        hHubDevice = INVALID_HANDLE_VALUE;\r\n    }\r\n\r\n    if (hubInfo)\r\n    {\r\n        FREE(hubInfo);\r\n    }\r\n\r\n    if (hubInfoEx)\r\n    {\r\n        FREE(hubInfoEx);\r\n    }\r\n\r\n    if (info)\r\n    {\r\n        FREE(info);\r\n    }\r\n\r\n    if (HubName)\r\n    {\r\n        FREE(HubName);\r\n    }\r\n\r\n    if (ConnectionInfo)\r\n    {\r\n        FREE(ConnectionInfo);\r\n    }\r\n\r\n    if (ConfigDesc)\r\n    {\r\n        FREE(ConfigDesc);\r\n    }\r\n\r\n    if (BosDesc)\r\n    {\r\n        FREE(BosDesc);\r\n    }\r\n\r\n    if (StringDescs != NULL)\r\n    {\r\n        PSTRING_DESCRIPTOR_NODE Next;\r\n\r\n        do {\r\n\r\n            Next = StringDescs->Next;\r\n            FREE(StringDescs);\r\n            StringDescs = Next;\r\n\r\n        } while (StringDescs != NULL);\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// EnumerateHubPorts()\r\n//\r\n// hTreeParent - Handle of the TreeView item under which the hub port should\r\n// be added.\r\n//\r\n// hHubDevice - Handle of the hub device to enumerate.\r\n//\r\n// NumPorts - Number of ports on the hub.\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nEnumerateHubPorts (\r\n    HTREEITEM   hTreeParent,\r\n    HANDLE      hHubDevice,\r\n    ULONG       NumPorts\r\n)\r\n{\r\n    ULONG       index = 0;\r\n    BOOL        success = 0;\r\n    HRESULT     hr = S_OK;\r\n    PCHAR       driverKeyName = NULL;\r\n    PUSB_DEVICE_PNP_STRINGS DevProps;\r\n    DWORD       dwSizeOfLeafName = 0;\r\n    CHAR        leafName[512];\r\n    int         icon = 0;\r\n\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX    connectionInfoEx;\r\n    PUSB_PORT_CONNECTOR_PROPERTIES         pPortConnectorProps;\r\n    USB_PORT_CONNECTOR_PROPERTIES          portConnectorProps;\r\n    PUSB_DESCRIPTOR_REQUEST                configDesc;\r\n    PUSB_DESCRIPTOR_REQUEST                bosDesc;\r\n    PSTRING_DESCRIPTOR_NODE                stringDescs;\r\n    PUSBDEVICEINFO                         info;\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfoExV2;\r\n    PDEVICE_INFO_NODE                      pNode;\r\n\r\n    // Loop over all ports of the hub.\r\n    //\r\n    // Port indices are 1 based, not 0 based.\r\n    //\r\n    for (index = 1; index <= NumPorts; index++)\r\n    {\r\n        ULONG nBytesEx;\r\n        ULONG nBytes = 0;\r\n\r\n        connectionInfoEx = NULL;\r\n        pPortConnectorProps = NULL;\r\n        ZeroMemory(&portConnectorProps, sizeof(portConnectorProps));\r\n        configDesc = NULL;\r\n        bosDesc = NULL;\r\n        stringDescs = NULL;\r\n        info = NULL;\r\n        connectionInfoExV2 = NULL;\r\n        pNode = NULL;\r\n        DevProps = NULL;\r\n        ZeroMemory(leafName, sizeof(leafName));\r\n\r\n        //\r\n        // Allocate space to hold the connection info for this port.\r\n        // For now, allocate it big enough to hold info for 30 pipes.\r\n        //\r\n        // Endpoint numbers are 0-15.  Endpoint number 0 is the standard\r\n        // control endpoint which is not explicitly listed in the Configuration\r\n        // Descriptor.  There can be an IN endpoint and an OUT endpoint at\r\n        // endpoint numbers 1-15 so there can be a maximum of 30 endpoints\r\n        // per device configuration.\r\n        //\r\n        // Should probably size this dynamically at some point.\r\n        //\r\n\r\n        nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +\r\n                 (sizeof(USB_PIPE_INFO) * 30);\r\n\r\n        connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytesEx);\r\n\r\n        if (connectionInfoEx == NULL)\r\n        {\r\n            OOPS();\r\n            break;\r\n        }\r\n\r\n        connectionInfoExV2 = (PUSB_NODE_CONNECTION_INFORMATION_EX_V2)\r\n                                    ALLOC(sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2));\r\n\r\n        if (connectionInfoExV2 == NULL)\r\n        {\r\n            OOPS();\r\n            FREE(connectionInfoEx);\r\n            break;\r\n        }\r\n\r\n        //\r\n        // Now query USBHUB for the structures\r\n        // for this port.  This will tell us if a device is attached to this\r\n        // port, among other things.\r\n        // The fault tolerate code is executed first.\r\n        //\r\n\r\n        portConnectorProps.ConnectionIndex = index;\r\n\r\n        success = DeviceIoControl(hHubDevice,\r\n                                  IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES,\r\n                                  &portConnectorProps,\r\n                                  sizeof(USB_PORT_CONNECTOR_PROPERTIES),\r\n                                  &portConnectorProps,\r\n                                  sizeof(USB_PORT_CONNECTOR_PROPERTIES),\r\n                                  &nBytes,\r\n                                  NULL);\r\n\r\n        if (success && nBytes == sizeof(USB_PORT_CONNECTOR_PROPERTIES))\r\n        {\r\n            pPortConnectorProps = (PUSB_PORT_CONNECTOR_PROPERTIES)\r\n                                        ALLOC(portConnectorProps.ActualLength);\r\n\r\n            if (pPortConnectorProps != NULL)\r\n            {\r\n                pPortConnectorProps->ConnectionIndex = index;\r\n\r\n                success = DeviceIoControl(hHubDevice,\r\n                                          IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES,\r\n                                          pPortConnectorProps,\r\n                                          portConnectorProps.ActualLength,\r\n                                          pPortConnectorProps,\r\n                                          portConnectorProps.ActualLength,\r\n                                          &nBytes,\r\n                                          NULL);\r\n\r\n                if (!success || nBytes < portConnectorProps.ActualLength)\r\n                {\r\n                    FREE(pPortConnectorProps);\r\n                    pPortConnectorProps = NULL;\r\n                }\r\n            }\r\n        }\r\n\r\n        connectionInfoExV2->ConnectionIndex = index;\r\n        connectionInfoExV2->Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2);\r\n        connectionInfoExV2->SupportedUsbProtocols.Usb300 = 1;\r\n\r\n        success = DeviceIoControl(hHubDevice,\r\n                                  IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,\r\n                                  connectionInfoExV2,\r\n                                  sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2),\r\n                                  connectionInfoExV2,\r\n                                  sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2),\r\n                                  &nBytes,\r\n                                  NULL);\r\n\r\n        if (!success || nBytes < sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2))\r\n        {\r\n            FREE(connectionInfoExV2);\r\n            connectionInfoExV2 = NULL;\r\n        }\r\n\r\n        connectionInfoEx->ConnectionIndex = index;\r\n\r\n        success = DeviceIoControl(hHubDevice,\r\n                                  IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,\r\n                                  connectionInfoEx,\r\n                                  nBytesEx,\r\n                                  connectionInfoEx,\r\n                                  nBytesEx,\r\n                                  &nBytesEx,\r\n                                  NULL);\r\n\r\n        if (success)\r\n        {\r\n            //\r\n            // Since the USB_NODE_CONNECTION_INFORMATION_EX is used to display\r\n            // the device speed, but the hub driver doesn't support indication\r\n            // of superspeed, we overwrite the value if the super speed\r\n            // data structures are available and indicate the device is operating\r\n            // at SuperSpeed.\r\n            //\r\n\r\n            if (connectionInfoEx->Speed == UsbHighSpeed\r\n                && connectionInfoExV2 != NULL\r\n                && (connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher ||\r\n                    connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher))\r\n            {\r\n                connectionInfoEx->Speed = UsbSuperSpeed;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            PUSB_NODE_CONNECTION_INFORMATION    connectionInfo = NULL;\r\n\r\n            // Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\r\n            // instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\r\n            //\r\n\r\n            nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +\r\n                     sizeof(USB_PIPE_INFO) * 30;\r\n\r\n            connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)ALLOC(nBytes);\r\n\r\n            if (connectionInfo == NULL)\r\n            {\r\n                OOPS();\r\n\r\n                FREE(connectionInfoEx);\r\n                if (pPortConnectorProps != NULL)\r\n                {\r\n                    FREE(pPortConnectorProps);\r\n                }\r\n                if (connectionInfoExV2 != NULL)\r\n                {\r\n                    FREE(connectionInfoExV2);\r\n                }\r\n                continue;\r\n            }\r\n\r\n            connectionInfo->ConnectionIndex = index;\r\n\r\n            success = DeviceIoControl(hHubDevice,\r\n                                      IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,\r\n                                      connectionInfo,\r\n                                      nBytes,\r\n                                      connectionInfo,\r\n                                      nBytes,\r\n                                      &nBytes,\r\n                                      NULL);\r\n\r\n            if (!success)\r\n            {\r\n                OOPS();\r\n\r\n                FREE(connectionInfo);\r\n                FREE(connectionInfoEx);\r\n                if (pPortConnectorProps != NULL)\r\n                {\r\n                    FREE(pPortConnectorProps);\r\n                }\r\n                if (connectionInfoExV2 != NULL)\r\n                {\r\n                    FREE(connectionInfoExV2);\r\n                }\r\n                continue;\r\n            }\r\n\r\n            // Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into\r\n            // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure.\r\n            //\r\n            connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex;\r\n            connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor;\r\n            connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue;\r\n            connectionInfoEx->Speed = connectionInfo->LowSpeed ? UsbLowSpeed : UsbFullSpeed;\r\n            connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub;\r\n            connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress;\r\n            connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes;\r\n            connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus;\r\n\r\n            memcpy(&connectionInfoEx->PipeList[0],\r\n                   &connectionInfo->PipeList[0],\r\n                   sizeof(USB_PIPE_INFO) * 30);\r\n\r\n            FREE(connectionInfo);\r\n        }\r\n\r\n        // Update the count of connected devices\r\n        //\r\n        if (connectionInfoEx->ConnectionStatus == DeviceConnected)\r\n        {\r\n            TotalDevicesConnected++;\r\n        }\r\n\r\n        if (connectionInfoEx->DeviceIsHub)\r\n        {\r\n            TotalHubs++;\r\n        }\r\n\r\n        // If there is a device connected, get the Device Description\r\n        //\r\n        if (connectionInfoEx->ConnectionStatus != NoDeviceConnected)\r\n        {\r\n            driverKeyName = GetDriverKeyName(hHubDevice, index);\r\n\r\n            if (driverKeyName)\r\n            {\r\n                size_t cbDriverName = 0;\r\n\r\n                hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName);\r\n                if (SUCCEEDED(hr))\r\n                {\r\n                    DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName);\r\n                    pNode = FindMatchingDeviceNodeForDriverName(driverKeyName, connectionInfoEx->DeviceIsHub);\r\n                }\r\n                FREE(driverKeyName);\r\n            }\r\n\r\n        }\r\n\r\n        // If there is a device connected to the port, try to retrieve the\r\n        // Configuration Descriptor from the device.\r\n        //\r\n        if (gDoConfigDesc &&\r\n            connectionInfoEx->ConnectionStatus == DeviceConnected)\r\n        {\r\n            configDesc = GetConfigDescriptor(hHubDevice,\r\n                                             index,\r\n                                             0);\r\n        }\r\n        else\r\n        {\r\n            configDesc = NULL;\r\n        }\r\n\r\n        if (configDesc != NULL &&\r\n            connectionInfoEx->DeviceDescriptor.bcdUSB > 0x0200)\r\n        {\r\n            bosDesc = GetBOSDescriptor(hHubDevice,\r\n                                       index);\r\n        }\r\n        else\r\n        {\r\n            bosDesc = NULL;\r\n        }\r\n\r\n        if (configDesc != NULL &&\r\n            AreThereStringDescriptors(&connectionInfoEx->DeviceDescriptor,\r\n                                      (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1)))\r\n        {\r\n            stringDescs = GetAllStringDescriptors (\r\n                              hHubDevice,\r\n                              index,\r\n                              &connectionInfoEx->DeviceDescriptor,\r\n                              (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1));\r\n        }\r\n        else\r\n        {\r\n            stringDescs = NULL;\r\n        }\r\n\r\n        // If the device connected to the port is an external hub, get the\r\n        // name of the external hub and recursively enumerate it.\r\n        //\r\n        if (connectionInfoEx->DeviceIsHub)\r\n        {\r\n            PCHAR extHubName;\r\n            size_t cbHubName = 0;\r\n\r\n            extHubName = GetExternalHubName(hHubDevice, index);\r\n            if (extHubName != NULL)\r\n            {\r\n                hr = StringCbLength(extHubName, MAX_DRIVER_KEY_NAME, &cbHubName);\r\n                if (SUCCEEDED(hr))\r\n                {\r\n                    EnumerateHub(hTreeParent, //hPortItem,\r\n                            extHubName,\r\n                            cbHubName,\r\n                            connectionInfoEx,\r\n                            connectionInfoExV2,\r\n                            pPortConnectorProps,\r\n                            configDesc,\r\n                            bosDesc,\r\n                            stringDescs,\r\n                            DevProps);\r\n                }\r\n            }\r\n        }\r\n        else\r\n        {\r\n            // Allocate some space for a USBDEVICEINFO structure to hold the\r\n            // hub info, hub name, and connection info pointers.  GPTR zero\r\n            // initializes the structure for us.\r\n            //\r\n            info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO));\r\n\r\n            if (info == NULL)\r\n            {\r\n                OOPS();\r\n                if (configDesc != NULL)\r\n                {\r\n                    FREE(configDesc);\r\n                }\r\n                if (bosDesc != NULL)\r\n                {\r\n                    FREE(bosDesc);\r\n                }\r\n                FREE(connectionInfoEx);\r\n\r\n                if (pPortConnectorProps != NULL)\r\n                {\r\n                    FREE(pPortConnectorProps);\r\n                }\r\n                if (connectionInfoExV2 != NULL)\r\n                {\r\n                    FREE(connectionInfoExV2);\r\n                }\r\n                break;\r\n            }\r\n\r\n            info->DeviceInfoType = DeviceInfo;\r\n            info->ConnectionInfo = connectionInfoEx;\r\n            info->PortConnectorProps = pPortConnectorProps;\r\n            info->ConfigDesc = configDesc;\r\n            info->StringDescs = stringDescs;\r\n            info->BosDesc = bosDesc;\r\n            info->ConnectionInfoV2 = connectionInfoExV2;\r\n            info->UsbDeviceProperties = DevProps;\r\n            info->DeviceInfoNode = pNode;\r\n\r\n            StringCchPrintf(leafName, sizeof(leafName), \"[Port%d] \", index);\r\n\r\n            // Add error description if ConnectionStatus is other than NoDeviceConnected / DeviceConnected\r\n            StringCchCat(leafName,\r\n                sizeof(leafName),\r\n                ConnectionStatuses[connectionInfoEx->ConnectionStatus]);\r\n\r\n            if (DevProps)\r\n            {\r\n                size_t cchDeviceDesc = 0;\r\n\r\n                hr = StringCbLength(DevProps->DeviceDesc, MAX_DEVICE_PROP, &cchDeviceDesc);\r\n                if (FAILED(hr))\r\n                {\r\n                    OOPS();\r\n                }\r\n                dwSizeOfLeafName = sizeof(leafName);\r\n                StringCchCatN(leafName,\r\n                    dwSizeOfLeafName - 1,\r\n                    \" :  \",\r\n                    sizeof(\" :  \"));\r\n                StringCchCatN(leafName,\r\n                    dwSizeOfLeafName - 1,\r\n                    DevProps->DeviceDesc,\r\n                    cchDeviceDesc );\r\n            }\r\n\r\n            if (connectionInfoEx->ConnectionStatus == NoDeviceConnected)\r\n            {\r\n                if (connectionInfoExV2 != NULL &&\r\n                    connectionInfoExV2->SupportedUsbProtocols.Usb300 == 1)\r\n                {\r\n                    icon = NoSsDeviceIcon;\r\n                }\r\n                else\r\n                {\r\n                    icon = NoDeviceIcon;\r\n                }\r\n            }\r\n            else if (connectionInfoEx->CurrentConfigurationValue)\r\n            {\r\n                if (connectionInfoEx->Speed == UsbSuperSpeed)\r\n                {\r\n                    icon = GoodSsDeviceIcon;\r\n                }\r\n                else\r\n                {\r\n                    icon = GoodDeviceIcon;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                icon = BadDeviceIcon;\r\n            }\r\n\r\n            AddLeaf(hTreeParent, //hPortItem,\r\n                            (LPARAM)info,\r\n                            leafName,\r\n                            icon);\r\n        }\r\n    } // for\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// WideStrToMultiStr()\r\n//\r\n//*****************************************************************************\r\n\r\nPCHAR WideStrToMultiStr (\r\n                         _In_reads_bytes_(cbWideStr) PWCHAR WideStr,\r\n                         _In_ size_t                   cbWideStr\r\n                         )\r\n{\r\n    ULONG  nBytes = 0;\r\n    PCHAR  MultiStr = NULL;\r\n    PWCHAR pWideStr = NULL;\r\n\r\n    // Use local string to guarantee zero termination\r\n    pWideStr = (PWCHAR) ALLOC((DWORD) cbWideStr + sizeof(WCHAR));\r\n    if (NULL == pWideStr)\r\n    {\r\n        return NULL;\r\n    }\r\n    memset(pWideStr, 0, cbWideStr + sizeof(WCHAR));\r\n    memcpy(pWideStr, WideStr, cbWideStr);\r\n\r\n    // Get the length of the converted string\r\n    //\r\n    nBytes = WideCharToMultiByte(\r\n                 CP_ACP,\r\n                 WC_NO_BEST_FIT_CHARS,\r\n                 pWideStr,\r\n                 -1,\r\n                 NULL,\r\n                 0,\r\n                 NULL,\r\n                 NULL);\r\n\r\n    if (nBytes == 0)\r\n    {\r\n        FREE(pWideStr);\r\n        return NULL;\r\n    }\r\n\r\n    // Allocate space to hold the converted string\r\n    //\r\n    MultiStr = ALLOC(nBytes);\r\n    if (MultiStr == NULL)\r\n    {\r\n        FREE(pWideStr);\r\n        return NULL;\r\n    }\r\n\r\n    // Convert the string\r\n    //\r\n    nBytes = WideCharToMultiByte(\r\n                 CP_ACP,\r\n                 WC_NO_BEST_FIT_CHARS,\r\n                 pWideStr,\r\n                 -1,\r\n                 MultiStr,\r\n                 nBytes,\r\n                 NULL,\r\n                 NULL);\r\n\r\n    if (nBytes == 0)\r\n    {\r\n        FREE(MultiStr);\r\n        FREE(pWideStr);\r\n        return NULL;\r\n    }\r\n\r\n    FREE(pWideStr);\r\n    return MultiStr;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// GetRootHubName()\r\n//\r\n//*****************************************************************************\r\n\r\nPCHAR GetRootHubName (\r\n    HANDLE HostController\r\n)\r\n{\r\n    BOOL                success = 0;\r\n    ULONG               nBytes = 0;\r\n    USB_ROOT_HUB_NAME   rootHubName;\r\n    PUSB_ROOT_HUB_NAME  rootHubNameW = NULL;\r\n    PCHAR               rootHubNameA = NULL;\r\n\r\n    // Get the length of the name of the Root Hub attached to the\r\n    // Host Controller\r\n    //\r\n    success = DeviceIoControl(HostController,\r\n                              IOCTL_USB_GET_ROOT_HUB_NAME,\r\n                              0,\r\n                              0,\r\n                              &rootHubName,\r\n                              sizeof(rootHubName),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetRootHubNameError;\r\n    }\r\n\r\n    // Allocate space to hold the Root Hub name\r\n    //\r\n    nBytes = rootHubName.ActualLength;\r\n\r\n    rootHubNameW = ALLOC(nBytes);\r\n    if (rootHubNameW == NULL)\r\n    {\r\n        OOPS();\r\n        goto GetRootHubNameError;\r\n    }\r\n\r\n    // Get the name of the Root Hub attached to the Host Controller\r\n    //\r\n    success = DeviceIoControl(HostController,\r\n                              IOCTL_USB_GET_ROOT_HUB_NAME,\r\n                              NULL,\r\n                              0,\r\n                              rootHubNameW,\r\n                              nBytes,\r\n                              &nBytes,\r\n                              NULL);\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetRootHubNameError;\r\n    }\r\n\r\n    // Convert the Root Hub name\r\n    //\r\n    rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName, nBytes - sizeof(USB_ROOT_HUB_NAME) + sizeof(WCHAR));\r\n\r\n    // All done, free the uncoverted Root Hub name and return the\r\n    // converted Root Hub name\r\n    //\r\n    FREE(rootHubNameW);\r\n\r\n    return rootHubNameA;\r\n\r\nGetRootHubNameError:\r\n    // There was an error, free anything that was allocated\r\n    //\r\n    if (rootHubNameW != NULL)\r\n    {\r\n        FREE(rootHubNameW);\r\n        rootHubNameW = NULL;\r\n    }\r\n    return NULL;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetExternalHubName()\r\n//\r\n//*****************************************************************************\r\n\r\nPCHAR GetExternalHubName (\r\n    HANDLE  Hub,\r\n    ULONG   ConnectionIndex\r\n)\r\n{\r\n    BOOL                        success = 0;\r\n    ULONG                       nBytes = 0;\r\n    USB_NODE_CONNECTION_NAME    extHubName;\r\n    PUSB_NODE_CONNECTION_NAME   extHubNameW = NULL;\r\n    PCHAR                       extHubNameA = NULL;\r\n\r\n    // Get the length of the name of the external hub attached to the\r\n    // specified port.\r\n    //\r\n    extHubName.ConnectionIndex = ConnectionIndex;\r\n\r\n    success = DeviceIoControl(Hub,\r\n                              IOCTL_USB_GET_NODE_CONNECTION_NAME,\r\n                              &extHubName,\r\n                              sizeof(extHubName),\r\n                              &extHubName,\r\n                              sizeof(extHubName),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetExternalHubNameError;\r\n    }\r\n\r\n    // Allocate space to hold the external hub name\r\n    //\r\n    nBytes = extHubName.ActualLength;\r\n\r\n    if (nBytes <= sizeof(extHubName))\r\n    {\r\n        OOPS();\r\n        goto GetExternalHubNameError;\r\n    }\r\n\r\n    extHubNameW = ALLOC(nBytes);\r\n\r\n    if (extHubNameW == NULL)\r\n    {\r\n        OOPS();\r\n        goto GetExternalHubNameError;\r\n    }\r\n\r\n    // Get the name of the external hub attached to the specified port\r\n    //\r\n    extHubNameW->ConnectionIndex = ConnectionIndex;\r\n\r\n    success = DeviceIoControl(Hub,\r\n                              IOCTL_USB_GET_NODE_CONNECTION_NAME,\r\n                              extHubNameW,\r\n                              nBytes,\r\n                              extHubNameW,\r\n                              nBytes,\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetExternalHubNameError;\r\n    }\r\n\r\n    // Convert the External Hub name\r\n    //\r\n    extHubNameA = WideStrToMultiStr(extHubNameW->NodeName, nBytes - sizeof(USB_NODE_CONNECTION_NAME) + sizeof(WCHAR));\r\n\r\n    // All done, free the uncoverted external hub name and return the\r\n    // converted external hub name\r\n    //\r\n    FREE(extHubNameW);\r\n\r\n    return extHubNameA;\r\n\r\n\r\nGetExternalHubNameError:\r\n    // There was an error, free anything that was allocated\r\n    //\r\n    if (extHubNameW != NULL)\r\n    {\r\n        FREE(extHubNameW);\r\n        extHubNameW = NULL;\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetDriverKeyName()\r\n//\r\n//*****************************************************************************\r\n\r\nPCHAR GetDriverKeyName (\r\n    HANDLE  Hub,\r\n    ULONG   ConnectionIndex\r\n)\r\n{\r\n    BOOL                                success = 0;\r\n    ULONG                               nBytes = 0;\r\n    USB_NODE_CONNECTION_DRIVERKEY_NAME  driverKeyName;\r\n    PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW = NULL;\r\n    PCHAR                               driverKeyNameA = NULL;\r\n\r\n    // Get the length of the name of the driver key of the device attached to\r\n    // the specified port.\r\n    //\r\n    driverKeyName.ConnectionIndex = ConnectionIndex;\r\n\r\n    success = DeviceIoControl(Hub,\r\n                              IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,\r\n                              &driverKeyName,\r\n                              sizeof(driverKeyName),\r\n                              &driverKeyName,\r\n                              sizeof(driverKeyName),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetDriverKeyNameError;\r\n    }\r\n\r\n    // Allocate space to hold the driver key name\r\n    //\r\n    nBytes = driverKeyName.ActualLength;\r\n\r\n    if (nBytes <= sizeof(driverKeyName))\r\n    {\r\n        OOPS();\r\n        goto GetDriverKeyNameError;\r\n    }\r\n\r\n    driverKeyNameW = ALLOC(nBytes);\r\n    if (driverKeyNameW == NULL)\r\n    {\r\n        OOPS();\r\n        goto GetDriverKeyNameError;\r\n    }\r\n\r\n    // Get the name of the driver key of the device attached to\r\n    // the specified port.\r\n    //\r\n    driverKeyNameW->ConnectionIndex = ConnectionIndex;\r\n\r\n    success = DeviceIoControl(Hub,\r\n                              IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,\r\n                              driverKeyNameW,\r\n                              nBytes,\r\n                              driverKeyNameW,\r\n                              nBytes,\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetDriverKeyNameError;\r\n    }\r\n\r\n    // Convert the driver key name\r\n    //\r\n    driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) + sizeof(WCHAR));\r\n\r\n    // All done, free the uncoverted driver key name and return the\r\n    // converted driver key name\r\n    //\r\n    FREE(driverKeyNameW);\r\n\r\n    return driverKeyNameA;\r\n\r\n\r\nGetDriverKeyNameError:\r\n    // There was an error, free anything that was allocated\r\n    //\r\n    if (driverKeyNameW != NULL)\r\n    {\r\n        FREE(driverKeyNameW);\r\n        driverKeyNameW = NULL;\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetHCDDriverKeyName()\r\n//\r\n//*****************************************************************************\r\n\r\nPCHAR GetHCDDriverKeyName (\r\n    HANDLE  HCD\r\n)\r\n{\r\n    BOOL                    success = 0;\r\n    ULONG                   nBytes = 0;\r\n    USB_HCD_DRIVERKEY_NAME  driverKeyName = {0};\r\n    PUSB_HCD_DRIVERKEY_NAME driverKeyNameW = NULL;\r\n    PCHAR                   driverKeyNameA = NULL;\r\n\r\n    ZeroMemory(&driverKeyName, sizeof(driverKeyName));\r\n\r\n    // Get the length of the name of the driver key of the HCD\r\n    //\r\n    success = DeviceIoControl(HCD,\r\n                              IOCTL_GET_HCD_DRIVERKEY_NAME,\r\n                              &driverKeyName,\r\n                              sizeof(driverKeyName),\r\n                              &driverKeyName,\r\n                              sizeof(driverKeyName),\r\n                              &nBytes,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetHCDDriverKeyNameError;\r\n    }\r\n\r\n    // Allocate space to hold the driver key name\r\n    //\r\n    nBytes = driverKeyName.ActualLength;\r\n    if (nBytes <= sizeof(driverKeyName))\r\n    {\r\n        OOPS();\r\n        goto GetHCDDriverKeyNameError;\r\n    }\r\n\r\n    driverKeyNameW = ALLOC(nBytes);\r\n    if (driverKeyNameW == NULL)\r\n    {\r\n        OOPS();\r\n        goto GetHCDDriverKeyNameError;\r\n    }\r\n\r\n    // Get the name of the driver key of the device attached to\r\n    // the specified port.\r\n    //\r\n\r\n    success = DeviceIoControl(HCD,\r\n                              IOCTL_GET_HCD_DRIVERKEY_NAME,\r\n                              driverKeyNameW,\r\n                              nBytes,\r\n                              driverKeyNameW,\r\n                              nBytes,\r\n                              &nBytes,\r\n                              NULL);\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        goto GetHCDDriverKeyNameError;\r\n    }\r\n\r\n    //\r\n    // Convert the driver key name\r\n    // Pass the length of the DriverKeyName string\r\n    //\r\n\r\n    driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR));\r\n\r\n    // All done, free the uncoverted driver key name and return the\r\n    // converted driver key name\r\n    //\r\n    FREE(driverKeyNameW);\r\n\r\n    return driverKeyNameA;\r\n\r\nGetHCDDriverKeyNameError:\r\n    // There was an error, free anything that was allocated\r\n    //\r\n    if (driverKeyNameW != NULL)\r\n    {\r\n        FREE(driverKeyNameW);\r\n        driverKeyNameW = NULL;\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetConfigDescriptor()\r\n//\r\n// hHubDevice - Handle of the hub device containing the port from which the\r\n// Configuration Descriptor will be requested.\r\n//\r\n// ConnectionIndex - Identifies the port on the hub to which a device is\r\n// attached from which the Configuration Descriptor will be requested.\r\n//\r\n// DescriptorIndex - Configuration Descriptor index, zero based.\r\n//\r\n//*****************************************************************************\r\n\r\nPUSB_DESCRIPTOR_REQUEST\r\nGetConfigDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex,\r\n    UCHAR   DescriptorIndex\r\n)\r\n{\r\n    BOOL    success = 0;\r\n    ULONG   nBytes = 0;\r\n    ULONG   nBytesReturned = 0;\r\n\r\n    UCHAR   configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) +\r\n                             sizeof(USB_CONFIGURATION_DESCRIPTOR)];\r\n\r\n    PUSB_DESCRIPTOR_REQUEST         configDescReq = NULL;\r\n    PUSB_CONFIGURATION_DESCRIPTOR   configDesc = NULL;\r\n\r\n\r\n    // Request the Configuration Descriptor the first time using our\r\n    // local buffer, which is just big enough for the Cofiguration\r\n    // Descriptor itself.\r\n    //\r\n    nBytes = sizeof(configDescReqBuf);\r\n\r\n    configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf;\r\n    configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);\r\n\r\n    // Zero fill the entire request structure\r\n    //\r\n    memset(configDescReq, 0, nBytes);\r\n\r\n    // Indicate the port from which the descriptor will be requested\r\n    //\r\n    configDescReq->ConnectionIndex = ConnectionIndex;\r\n\r\n    //\r\n    // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this\r\n    // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.\r\n    //\r\n    // USBD will automatically initialize these fields:\r\n    //     bmRequest = 0x80\r\n    //     bRequest  = 0x06\r\n    //\r\n    // We must inititialize these fields:\r\n    //     wValue    = Descriptor Type (high) and Descriptor Index (low byte)\r\n    //     wIndex    = Zero (or Language ID for String Descriptors)\r\n    //     wLength   = Length of descriptor buffer\r\n    //\r\n    configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)\r\n                                        | DescriptorIndex;\r\n\r\n    configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));\r\n\r\n    // Now issue the get descriptor request.\r\n    //\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,\r\n                              configDescReq,\r\n                              nBytes,\r\n                              configDescReq,\r\n                              nBytes,\r\n                              &nBytesReturned,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (nBytes != nBytesReturned)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    // Now request the entire Configuration Descriptor using a dynamically\r\n    // allocated buffer which is sized big enough to hold the entire descriptor\r\n    //\r\n    nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength;\r\n\r\n    configDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes);\r\n\r\n    if (configDescReq == NULL)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);\r\n\r\n    // Indicate the port from which the descriptor will be requested\r\n    //\r\n    configDescReq->ConnectionIndex = ConnectionIndex;\r\n\r\n    //\r\n    // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this\r\n    // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.\r\n    //\r\n    // USBD will automatically initialize these fields:\r\n    //     bmRequest = 0x80\r\n    //     bRequest  = 0x06\r\n    //\r\n    // We must inititialize these fields:\r\n    //     wValue    = Descriptor Type (high) and Descriptor Index (low byte)\r\n    //     wIndex    = Zero (or Language ID for String Descriptors)\r\n    //     wLength   = Length of descriptor buffer\r\n    //\r\n    configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)\r\n                                        | DescriptorIndex;\r\n\r\n    configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));\r\n\r\n    // Now issue the get descriptor request.\r\n    //\r\n\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,\r\n                              configDescReq,\r\n                              nBytes,\r\n                              configDescReq,\r\n                              nBytes,\r\n                              &nBytesReturned,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        FREE(configDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    if (nBytes != nBytesReturned)\r\n    {\r\n        OOPS();\r\n        FREE(configDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)))\r\n    {\r\n        OOPS();\r\n        FREE(configDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    return configDescReq;\r\n}\r\n\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetBOSDescriptor()\r\n//\r\n// hHubDevice - Handle of the hub device containing the port from which the\r\n// Configuration Descriptor will be requested.\r\n//\r\n// ConnectionIndex - Identifies the port on the hub to which a device is\r\n// attached from which the BOS Descriptor will be requested.\r\n//\r\n//*****************************************************************************\r\n\r\nPUSB_DESCRIPTOR_REQUEST\r\nGetBOSDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex\r\n)\r\n{\r\n    BOOL    success = 0;\r\n    ULONG   nBytes = 0;\r\n    ULONG   nBytesReturned = 0;\r\n\r\n    UCHAR   bosDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) +\r\n                          sizeof(USB_BOS_DESCRIPTOR)];\r\n\r\n    PUSB_DESCRIPTOR_REQUEST bosDescReq = NULL;\r\n    PUSB_BOS_DESCRIPTOR     bosDesc = NULL;\r\n\r\n\r\n    // Request the BOS Descriptor the first time using our\r\n    // local buffer, which is just big enough for the BOS\r\n    // Descriptor itself.\r\n    //\r\n    nBytes = sizeof(bosDescReqBuf);\r\n\r\n    bosDescReq = (PUSB_DESCRIPTOR_REQUEST)bosDescReqBuf;\r\n    bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1);\r\n\r\n    // Zero fill the entire request structure\r\n    //\r\n    memset(bosDescReq, 0, nBytes);\r\n\r\n    // Indicate the port from which the descriptor will be requested\r\n    //\r\n    bosDescReq->ConnectionIndex = ConnectionIndex;\r\n\r\n    //\r\n    // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this\r\n    // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.\r\n    //\r\n    // USBD will automatically initialize these fields:\r\n    //     bmRequest = 0x80\r\n    //     bRequest  = 0x06\r\n    //\r\n    // We must inititialize these fields:\r\n    //     wValue    = Descriptor Type (high) and Descriptor Index (low byte)\r\n    //     wIndex    = Zero (or Language ID for String Descriptors)\r\n    //     wLength   = Length of descriptor buffer\r\n    //\r\n    bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8);\r\n\r\n    bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));\r\n\r\n    // Now issue the get descriptor request.\r\n    //\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,\r\n                              bosDescReq,\r\n                              nBytes,\r\n                              bosDescReq,\r\n                              nBytes,\r\n                              &nBytesReturned,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (nBytes != nBytesReturned)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (bosDesc->wTotalLength < sizeof(USB_BOS_DESCRIPTOR))\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    // Now request the entire BOS Descriptor using a dynamically\r\n    // allocated buffer which is sized big enough to hold the entire descriptor\r\n    //\r\n    nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + bosDesc->wTotalLength;\r\n\r\n    bosDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes);\r\n\r\n    if (bosDescReq == NULL)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1);\r\n\r\n    // Indicate the port from which the descriptor will be requested\r\n    //\r\n    bosDescReq->ConnectionIndex = ConnectionIndex;\r\n\r\n    //\r\n    // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this\r\n    // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.\r\n    //\r\n    // USBD will automatically initialize these fields:\r\n    //     bmRequest = 0x80\r\n    //     bRequest  = 0x06\r\n    //\r\n    // We must inititialize these fields:\r\n    //     wValue    = Descriptor Type (high) and Descriptor Index (low byte)\r\n    //     wIndex    = Zero (or Language ID for String Descriptors)\r\n    //     wLength   = Length of descriptor buffer\r\n    //\r\n    bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8);\r\n\r\n    bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));\r\n\r\n    // Now issue the get descriptor request.\r\n    //\r\n\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,\r\n                              bosDescReq,\r\n                              nBytes,\r\n                              bosDescReq,\r\n                              nBytes,\r\n                              &nBytesReturned,\r\n                              NULL);\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        FREE(bosDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    if (nBytes != nBytesReturned)\r\n    {\r\n        OOPS();\r\n        FREE(bosDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    if (bosDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)))\r\n    {\r\n        OOPS();\r\n        FREE(bosDescReq);\r\n        return NULL;\r\n    }\r\n\r\n    return bosDescReq;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// AreThereStringDescriptors()\r\n//\r\n// DeviceDesc - Device Descriptor for which String Descriptors should be\r\n// checked.\r\n//\r\n// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)\r\n// for which String Descriptors should be checked.\r\n//\r\n//*****************************************************************************\r\n\r\nBOOL\r\nAreThereStringDescriptors (\r\n    PUSB_DEVICE_DESCRIPTOR          DeviceDesc,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc\r\n)\r\n{\r\n    PUCHAR                  descEnd = NULL;\r\n    PUSB_COMMON_DESCRIPTOR  commonDesc = NULL;\r\n\r\n    //\r\n    // Check Device Descriptor strings\r\n    //\r\n\r\n    if (DeviceDesc->iManufacturer ||\r\n        DeviceDesc->iProduct      ||\r\n        DeviceDesc->iSerialNumber\r\n       )\r\n    {\r\n        return TRUE;\r\n    }\r\n\r\n\r\n    //\r\n    // Check the Configuration and Interface Descriptor strings\r\n    //\r\n\r\n    descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n           (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        switch (commonDesc->bDescriptorType)\r\n        {\r\n            case USB_CONFIGURATION_DESCRIPTOR_TYPE:\r\n            case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE:\r\n                if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n                {\r\n                    OOPS();\r\n                    break;\r\n                }\r\n                if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)\r\n                {\r\n                    return TRUE;\r\n                }\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n\r\n            case USB_INTERFACE_DESCRIPTOR_TYPE:\r\n                if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&\r\n                    commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))\r\n                {\r\n                    OOPS();\r\n                    break;\r\n                }\r\n                if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)\r\n                {\r\n                    return TRUE;\r\n                }\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n\r\n            default:\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n        }\r\n        break;\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetAllStringDescriptors()\r\n//\r\n// hHubDevice - Handle of the hub device containing the port from which the\r\n// String Descriptors will be requested.\r\n//\r\n// ConnectionIndex - Identifies the port on the hub to which a device is\r\n// attached from which the String Descriptors will be requested.\r\n//\r\n// DeviceDesc - Device Descriptor for which String Descriptors should be\r\n// requested.\r\n//\r\n// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)\r\n// for which String Descriptors should be requested.\r\n//\r\n//*****************************************************************************\r\n\r\nPSTRING_DESCRIPTOR_NODE\r\nGetAllStringDescriptors (\r\n    HANDLE                          hHubDevice,\r\n    ULONG                           ConnectionIndex,\r\n    PUSB_DEVICE_DESCRIPTOR          DeviceDesc,\r\n    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc\r\n)\r\n{\r\n    PSTRING_DESCRIPTOR_NODE supportedLanguagesString = NULL;\r\n    ULONG                   numLanguageIDs = 0;\r\n    USHORT                  *languageIDs = NULL;\r\n\r\n    PUCHAR                  descEnd = NULL;\r\n    PUSB_COMMON_DESCRIPTOR  commonDesc = NULL;\r\n    UCHAR                   uIndex = 1;\r\n    UCHAR                   bInterfaceClass = 0;\r\n    BOOL                    getMoreStrings = FALSE;\r\n    HRESULT                 hr = S_OK;\r\n\r\n    //\r\n    // Get the array of supported Language IDs, which is returned\r\n    // in String Descriptor 0\r\n    //\r\n    supportedLanguagesString = GetStringDescriptor(hHubDevice,\r\n                                                   ConnectionIndex,\r\n                                                   0,\r\n                                                   0);\r\n\r\n    if (supportedLanguagesString == NULL)\r\n    {\r\n        return NULL;\r\n    }\r\n\r\n    numLanguageIDs = (supportedLanguagesString->StringDescriptor->bLength - 2) / 2;\r\n\r\n    languageIDs = &supportedLanguagesString->StringDescriptor->bString[0];\r\n\r\n    //\r\n    // Get the Device Descriptor strings\r\n    //\r\n\r\n    if (DeviceDesc->iManufacturer)\r\n    {\r\n        GetStringDescriptors(hHubDevice,\r\n                             ConnectionIndex,\r\n                             DeviceDesc->iManufacturer,\r\n                             numLanguageIDs,\r\n                             languageIDs,\r\n                             supportedLanguagesString);\r\n    }\r\n\r\n    if (DeviceDesc->iProduct)\r\n    {\r\n        GetStringDescriptors(hHubDevice,\r\n                             ConnectionIndex,\r\n                             DeviceDesc->iProduct,\r\n                             numLanguageIDs,\r\n                             languageIDs,\r\n                             supportedLanguagesString);\r\n    }\r\n\r\n    if (DeviceDesc->iSerialNumber)\r\n    {\r\n        GetStringDescriptors(hHubDevice,\r\n                             ConnectionIndex,\r\n                             DeviceDesc->iSerialNumber,\r\n                             numLanguageIDs,\r\n                             languageIDs,\r\n                             supportedLanguagesString);\r\n    }\r\n\r\n    //\r\n    // Get the Configuration and Interface Descriptor strings\r\n    //\r\n\r\n    descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;\r\n\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n           (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        switch (commonDesc->bDescriptorType)\r\n        {\r\n            case USB_CONFIGURATION_DESCRIPTOR_TYPE:\r\n                if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n                {\r\n                    OOPS();\r\n                    break;\r\n                }\r\n                if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)\r\n                {\r\n                    GetStringDescriptors(hHubDevice,\r\n                                         ConnectionIndex,\r\n                                         ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration,\r\n                                         numLanguageIDs,\r\n                                         languageIDs,\r\n                                         supportedLanguagesString);\r\n                }\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n\r\n            case USB_IAD_DESCRIPTOR_TYPE:\r\n                if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR))\r\n                {\r\n                    OOPS();\r\n                    break;\r\n                }\r\n                if (((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction)\r\n                {\r\n                    GetStringDescriptors(hHubDevice,\r\n                                         ConnectionIndex,\r\n                                         ((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction,\r\n                                         numLanguageIDs,\r\n                                         languageIDs,\r\n                                         supportedLanguagesString);\r\n                }\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n\r\n            case USB_INTERFACE_DESCRIPTOR_TYPE:\r\n                if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&\r\n                    commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))\r\n                {\r\n                    OOPS();\r\n                    break;\r\n                }\r\n                if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)\r\n                {\r\n                    GetStringDescriptors(hHubDevice,\r\n                                         ConnectionIndex,\r\n                                         ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface,\r\n                                         numLanguageIDs,\r\n                                         languageIDs,\r\n                                         supportedLanguagesString);\r\n                }\r\n\r\n                //\r\n                // We need to display more string descriptors for the following\r\n                // interface classes\r\n                //\r\n                bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass;\r\n                if (bInterfaceClass == USB_DEVICE_CLASS_VIDEO)\r\n                {\r\n                    getMoreStrings = TRUE;\r\n                }\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n\r\n            default:\r\n                commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n                continue;\r\n        }\r\n        break;\r\n    }\r\n\r\n    if (getMoreStrings)\r\n    {\r\n        //\r\n        // We might need to display strings later that are referenced only in\r\n        // class-specific descriptors. Get String Descriptors 1 through 32 (an\r\n        // arbitrary upper limit for Strings needed due to \"bad devices\"\r\n        // returning an infinite repeat of Strings 0 through 4) until one is not\r\n        // found.\r\n        //\r\n        // There are also \"bad devices\" that have issues even querying 1-32, but\r\n        // historically USBView made this query, so the query should be safe for\r\n        // video devices.\r\n        //\r\n        for (uIndex = 1; SUCCEEDED(hr) && (uIndex < NUM_STRING_DESC_TO_GET); uIndex++)\r\n        {\r\n            hr = GetStringDescriptors(hHubDevice,\r\n                                      ConnectionIndex,\r\n                                      uIndex,\r\n                                      numLanguageIDs,\r\n                                      languageIDs,\r\n                                      supportedLanguagesString);\r\n        }\r\n    }\r\n\r\n    return supportedLanguagesString;\r\n}\r\n\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetStringDescriptor()\r\n//\r\n// hHubDevice - Handle of the hub device containing the port from which the\r\n// String Descriptor will be requested.\r\n//\r\n// ConnectionIndex - Identifies the port on the hub to which a device is\r\n// attached from which the String Descriptor will be requested.\r\n//\r\n// DescriptorIndex - String Descriptor index.\r\n//\r\n// LanguageID - Language in which the string should be requested.\r\n//\r\n//*****************************************************************************\r\n\r\nPSTRING_DESCRIPTOR_NODE\r\nGetStringDescriptor (\r\n    HANDLE  hHubDevice,\r\n    ULONG   ConnectionIndex,\r\n    UCHAR   DescriptorIndex,\r\n    USHORT  LanguageID\r\n)\r\n{\r\n    BOOL    success = 0;\r\n    ULONG   nBytes = 0;\r\n    ULONG   nBytesReturned = 0;\r\n\r\n    UCHAR   stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) +\r\n                             MAXIMUM_USB_STRING_LENGTH];\r\n\r\n    PUSB_DESCRIPTOR_REQUEST stringDescReq = NULL;\r\n    PUSB_STRING_DESCRIPTOR  stringDesc = NULL;\r\n    PSTRING_DESCRIPTOR_NODE stringDescNode = NULL;\r\n\r\n    nBytes = sizeof(stringDescReqBuf);\r\n\r\n    stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;\r\n    stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);\r\n\r\n    // Zero fill the entire request structure\r\n    //\r\n    memset(stringDescReq, 0, nBytes);\r\n\r\n    // Indicate the port from which the descriptor will be requested\r\n    //\r\n    stringDescReq->ConnectionIndex = ConnectionIndex;\r\n\r\n    //\r\n    // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this\r\n    // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.\r\n    //\r\n    // USBD will automatically initialize these fields:\r\n    //     bmRequest = 0x80\r\n    //     bRequest  = 0x06\r\n    //\r\n    // We must inititialize these fields:\r\n    //     wValue    = Descriptor Type (high) and Descriptor Index (low byte)\r\n    //     wIndex    = Zero (or Language ID for String Descriptors)\r\n    //     wLength   = Length of descriptor buffer\r\n    //\r\n    stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)\r\n                                        | DescriptorIndex;\r\n\r\n    stringDescReq->SetupPacket.wIndex = LanguageID;\r\n\r\n    stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));\r\n\r\n    // Now issue the get descriptor request.\r\n    //\r\n    success = DeviceIoControl(hHubDevice,\r\n                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,\r\n                              stringDescReq,\r\n                              nBytes,\r\n                              stringDescReq,\r\n                              nBytes,\r\n                              &nBytesReturned,\r\n                              NULL);\r\n\r\n    //\r\n    // Do some sanity checks on the return from the get descriptor request.\r\n    //\r\n\r\n    if (!success)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (nBytesReturned < 2)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    if (stringDesc->bLength % 2 != 0)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    //\r\n    // Looks good, allocate some (zero filled) space for the string descriptor\r\n    // node and copy the string descriptor to it.\r\n    //\r\n\r\n    stringDescNode = (PSTRING_DESCRIPTOR_NODE)ALLOC(sizeof(STRING_DESCRIPTOR_NODE) +\r\n                                                    stringDesc->bLength);\r\n\r\n    if (stringDescNode == NULL)\r\n    {\r\n        OOPS();\r\n        return NULL;\r\n    }\r\n\r\n    stringDescNode->DescriptorIndex = DescriptorIndex;\r\n    stringDescNode->LanguageID = LanguageID;\r\n\r\n    memcpy(stringDescNode->StringDescriptor,\r\n           stringDesc,\r\n           stringDesc->bLength);\r\n\r\n    return stringDescNode;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetStringDescriptors()\r\n//\r\n// hHubDevice - Handle of the hub device containing the port from which the\r\n// String Descriptor will be requested.\r\n//\r\n// ConnectionIndex - Identifies the port on the hub to which a device is\r\n// attached from which the String Descriptor will be requested.\r\n//\r\n// DescriptorIndex - String Descriptor index.\r\n//\r\n// NumLanguageIDs -  Number of languages in which the string should be\r\n// requested.\r\n//\r\n// LanguageIDs - Languages in which the string should be requested.\r\n//\r\n// StringDescNodeHead - First node in linked list of device's string descriptors\r\n//\r\n// Return Value: HRESULT indicating whether the string is on the list\r\n//\r\n//*****************************************************************************\r\n\r\nHRESULT\r\nGetStringDescriptors (\r\n    _In_ HANDLE                         hHubDevice,\r\n    _In_ ULONG                          ConnectionIndex,\r\n    _In_ UCHAR                          DescriptorIndex,\r\n    _In_ ULONG                          NumLanguageIDs,\r\n    _In_reads_(NumLanguageIDs) USHORT  *LanguageIDs,\r\n    _In_ PSTRING_DESCRIPTOR_NODE        StringDescNodeHead\r\n)\r\n{\r\n    PSTRING_DESCRIPTOR_NODE tail = NULL;\r\n    PSTRING_DESCRIPTOR_NODE trailing = NULL;\r\n    ULONG i = 0;\r\n\r\n    //\r\n    // Go to the end of the linked list, searching for the requested index to\r\n    // see if we've already retrieved it\r\n    //\r\n    for (tail = StringDescNodeHead; tail != NULL; tail = tail->Next)\r\n    {\r\n        if (tail->DescriptorIndex == DescriptorIndex)\r\n        {\r\n            return S_OK;\r\n        }\r\n\r\n        trailing = tail;\r\n    }\r\n\r\n    tail = trailing;\r\n\r\n    //\r\n    // Get the next String Descriptor. If this is NULL, then we're done (return)\r\n    // Otherwise, loop through all Language IDs\r\n    //\r\n    for (i = 0; (tail != NULL) && (i < NumLanguageIDs); i++)\r\n    {\r\n        tail->Next = GetStringDescriptor(hHubDevice,\r\n                                         ConnectionIndex,\r\n                                         DescriptorIndex,\r\n                                         LanguageIDs[i]);\r\n\r\n        tail = tail->Next;\r\n    }\r\n\r\n    if (tail == NULL)\r\n    {\r\n        return E_FAIL;\r\n    } else {\r\n        return S_OK;\r\n    }\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// CleanupItem()\r\n//\r\n//*****************************************************************************\r\n\r\nVOID\r\nCleanupItem (\r\n    HWND      hTreeWnd,\r\n    HTREEITEM hTreeItem,\r\n    PVOID pContext\r\n)\r\n{\r\n    TV_ITEM tvi;\r\n    PVOID   info = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(pContext);\r\n\r\n    tvi.mask = TVIF_HANDLE | TVIF_PARAM;\r\n    tvi.hItem = hTreeItem;\r\n\r\n    TreeView_GetItem(hTreeWnd,\r\n                     &tvi);\r\n\r\n    info = (PVOID)tvi.lParam;\r\n\r\n    if (info)\r\n    {\r\n        PCHAR                                  DriverKey = NULL;\r\n        PUSB_NODE_INFORMATION                  HubInfo = NULL;\r\n        PCHAR                                  HubName = NULL;\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfoEx = NULL;\r\n        PUSB_DESCRIPTOR_REQUEST                ConfigDesc = NULL;\r\n        PUSB_DESCRIPTOR_REQUEST                BosDesc = NULL;\r\n        PSTRING_DESCRIPTOR_NODE                StringDescs = NULL;\r\n        PUSB_HUB_INFORMATION_EX                HubInfoEx = NULL;\r\n        PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps = NULL;\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL;\r\n        PUSB_HUB_CAPABILITIES_EX               HubCapabilityEx = NULL;\r\n        PUSB_DEVICE_PNP_STRINGS                UsbDeviceProperties = NULL;\r\n        PUSB_CONTROLLER_INFO_0                 ControllerInfo = NULL;\r\n\r\n        //\r\n        // All structures except DEVICE_INFO_NODE are free'd up here. DEVICE_INFO_NODE structures are free'd while\r\n        // destroying device info lists (ClearDeviceList())\r\n        //\r\n        switch (*(PUSBDEVICEINFOTYPE)info)\r\n        {\r\n            case HostControllerInfo:\r\n                //\r\n                // Remove this host controller from the list of enumerated\r\n                // host controllers.\r\n                //\r\n                RemoveEntryList(&((PUSBHOSTCONTROLLERINFO)info)->ListEntry);\r\n                DriverKey = ((PUSBHOSTCONTROLLERINFO)info)->DriverKey;\r\n                ControllerInfo = ((PUSBHOSTCONTROLLERINFO)info)->ControllerInfo;\r\n                UsbDeviceProperties = ((PUSBHOSTCONTROLLERINFO)info)->UsbDeviceProperties;\r\n                break;\r\n\r\n            case RootHubInfo:\r\n                HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo;\r\n                HubInfoEx = ((PUSBROOTHUBINFO)info)->HubInfoEx;\r\n                HubName = ((PUSBROOTHUBINFO)info)->HubName;\r\n                PortConnectorProps = ((PUSBROOTHUBINFO)info)->PortConnectorProps;\r\n                UsbDeviceProperties = ((PUSBROOTHUBINFO)info)->UsbDeviceProperties;\r\n                HubCapabilityEx = ((PUSBROOTHUBINFO)info)->HubCapabilityEx;\r\n                break;\r\n\r\n            case ExternalHubInfo:\r\n                HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo;\r\n                HubInfoEx = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx;\r\n                HubName = ((PUSBEXTERNALHUBINFO)info)->HubName;\r\n                ConnectionInfoEx = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo;\r\n                PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps;\r\n                ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc;\r\n                BosDesc = ((PUSBEXTERNALHUBINFO)info)->BosDesc;\r\n                StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs;\r\n                ConnectionInfoV2 = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2;\r\n                UsbDeviceProperties = ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties;\r\n                HubCapabilityEx = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx;\r\n                break;\r\n\r\n            case DeviceInfo:\r\n                ConnectionInfoEx = ((PUSBDEVICEINFO)info)->ConnectionInfo;\r\n                PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps;\r\n                ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc;\r\n                BosDesc = ((PUSBDEVICEINFO)info)->BosDesc;\r\n                StringDescs = ((PUSBDEVICEINFO)info)->StringDescs;\r\n                ConnectionInfoV2 = ((PUSBDEVICEINFO)info)->ConnectionInfoV2;\r\n                UsbDeviceProperties = ((PUSBDEVICEINFO)info)->UsbDeviceProperties;\r\n                break;\r\n        }\r\n\r\n        if(UsbDeviceProperties)\r\n        {\r\n            FreeDeviceProperties(&UsbDeviceProperties);\r\n        }\r\n\r\n        if(ControllerInfo)\r\n        {\r\n            FREE(ControllerInfo);\r\n        }\r\n\r\n        if(HubCapabilityEx)\r\n        {\r\n            FREE(HubCapabilityEx);\r\n        }\r\n\r\n        if (DriverKey)\r\n        {\r\n            FREE(DriverKey);\r\n        }\r\n\r\n        if (HubInfo)\r\n        {\r\n            FREE(HubInfo);\r\n        }\r\n\r\n        if (HubName)\r\n        {\r\n            FREE(HubName);\r\n        }\r\n\r\n        if (ConfigDesc)\r\n        {\r\n            FREE(ConfigDesc);\r\n        }\r\n\r\n        if (BosDesc)\r\n        {\r\n            FREE(BosDesc);\r\n        }\r\n\r\n        if (StringDescs)\r\n        {\r\n            PSTRING_DESCRIPTOR_NODE Next;\r\n\r\n            do {\r\n\r\n                Next = StringDescs->Next;\r\n                FREE(StringDescs);\r\n                StringDescs = Next;\r\n\r\n            } while (StringDescs);\r\n        }\r\n\r\n        if (ConnectionInfoEx)\r\n        {\r\n            FREE(ConnectionInfoEx);\r\n        }\r\n\r\n        if (HubInfoEx)\r\n        {\r\n            FREE(HubInfoEx);\r\n        }\r\n\r\n        if (PortConnectorProps)\r\n        {\r\n            FREE(PortConnectorProps);\r\n        }\r\n\r\n        if (ConnectionInfoV2)\r\n        {\r\n            FREE(ConnectionInfoV2);\r\n        }\r\n\r\n        FREE(info);\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// GetHostControllerPowerMap()\r\n//\r\n// HANDLE hHCDev\r\n//      - handle to USB Host Controller\r\n//\r\n// PUSBHOSTCONTROLLERINFO hcInfo\r\n//      - data structure to receive the Power Map Info\r\n//\r\n// return DWORD dwError\r\n//      - return ERROR_SUCCESS or last error\r\n//\r\n//*****************************************************************************\r\n\r\nDWORD\r\nGetHostControllerPowerMap(\r\n    HANDLE hHCDev,\r\n    PUSBHOSTCONTROLLERINFO hcInfo)\r\n{\r\n    USBUSER_POWER_INFO_REQUEST UsbPowerInfoRequest;\r\n    PUSB_POWER_INFO            pUPI = &UsbPowerInfoRequest.PowerInformation ;\r\n    DWORD                      dwError = 0;\r\n    DWORD                      dwBytes = 0;\r\n    BOOL                       bSuccess = FALSE;\r\n    int                        nIndex = 0;\r\n    int                        nPowerState = WdmUsbPowerSystemWorking;\r\n\r\n    for ( ; nPowerState <= WdmUsbPowerSystemShutdown; nIndex++, nPowerState++)\r\n    {\r\n        // zero initialize our request\r\n        memset(&UsbPowerInfoRequest, 0, sizeof(UsbPowerInfoRequest));\r\n\r\n        // set the header and request sizes\r\n        UsbPowerInfoRequest.Header.UsbUserRequest = USBUSER_GET_POWER_STATE_MAP;\r\n        UsbPowerInfoRequest.Header.RequestBufferLength = sizeof(UsbPowerInfoRequest);\r\n        UsbPowerInfoRequest.PowerInformation.SystemState = nPowerState;\r\n\r\n        //\r\n        // Now query USBHUB for the USB_POWER_INFO structure for this hub.\r\n        // For Selective Suspend support\r\n        //\r\n        bSuccess = DeviceIoControl(hHCDev,\r\n                                  IOCTL_USB_USER_REQUEST,\r\n                                  &UsbPowerInfoRequest,\r\n                                  sizeof(UsbPowerInfoRequest),\r\n                                  &UsbPowerInfoRequest,\r\n                                  sizeof(UsbPowerInfoRequest),\r\n                                  &dwBytes,\r\n                                  NULL);\r\n\r\n        if (!bSuccess)\r\n        {\r\n            dwError = GetLastError();\r\n            OOPS();\r\n        }\r\n        else\r\n        {\r\n            // copy the data into our USB Host Controller's info structure\r\n            memcpy( &(hcInfo->USBPowerInfo[nIndex]), pUPI, sizeof(USB_POWER_INFO));\r\n        }\r\n    }\r\n\r\n    return dwError;\r\n}\r\n\r\nvoid\r\nEnumerateAllDevices()\r\n{\r\n    EnumerateAllDevicesWithGuid(&gDeviceList,\r\n                                (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE);\r\n\r\n    EnumerateAllDevicesWithGuid(&gHubList,\r\n                                (LPGUID)&GUID_DEVINTERFACE_USB_HUB);\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// GetHostControllerInfo()\r\n//\r\n// HANDLE hHCDev\r\n//      - handle to USB Host Controller\r\n//\r\n// PUSBHOSTCONTROLLERINFO hcInfo\r\n//      - data structure to receive the Power Map Info\r\n//\r\n// return DWORD dwError\r\n//      - return ERROR_SUCCESS or last error\r\n//\r\n//*****************************************************************************\r\n\r\nDWORD\r\nGetHostControllerInfo(\r\n    HANDLE hHCDev,\r\n    PUSBHOSTCONTROLLERINFO hcInfo)\r\n{\r\n    USBUSER_CONTROLLER_INFO_0 UsbControllerInfo;\r\n    DWORD                      dwError = 0;\r\n    DWORD                      dwBytes = 0;\r\n    BOOL                       bSuccess = FALSE;\r\n\r\n    memset(&UsbControllerInfo, 0, sizeof(UsbControllerInfo));\r\n\r\n    // set the header and request sizes\r\n    UsbControllerInfo.Header.UsbUserRequest = USBUSER_GET_CONTROLLER_INFO_0;\r\n    UsbControllerInfo.Header.RequestBufferLength = sizeof(UsbControllerInfo);\r\n\r\n    //\r\n    // Query for the USB_CONTROLLER_INFO_0 structure\r\n    //\r\n    bSuccess = DeviceIoControl(hHCDev,\r\n            IOCTL_USB_USER_REQUEST,\r\n            &UsbControllerInfo,\r\n            sizeof(UsbControllerInfo),\r\n            &UsbControllerInfo,\r\n            sizeof(UsbControllerInfo),\r\n            &dwBytes,\r\n            NULL);\r\n\r\n    if (!bSuccess)\r\n    {\r\n        dwError = GetLastError();\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        hcInfo->ControllerInfo = (PUSB_CONTROLLER_INFO_0) ALLOC(sizeof(USB_CONTROLLER_INFO_0));\r\n        if(NULL == hcInfo->ControllerInfo)\r\n        {\r\n            dwError = GetLastError();\r\n            OOPS();\r\n        }\r\n        else\r\n        {\r\n            // copy the data into our USB Host Controller's info structure\r\n            memcpy(hcInfo->ControllerInfo, &UsbControllerInfo.Info0, sizeof(USB_CONTROLLER_INFO_0));\r\n        }\r\n    }\r\n    return dwError;\r\n}\r\n\r\n_Success_(return == TRUE)\r\nBOOL\r\nGetDeviceProperty(\r\n    _In_    HDEVINFO         DeviceInfoSet,\r\n    _In_    PSP_DEVINFO_DATA DeviceInfoData,\r\n    _In_    DWORD            Property,\r\n    _Outptr_  LPTSTR        *ppBuffer\r\n    )\r\n{\r\n    BOOL bResult;\r\n    DWORD requiredLength = 0;\r\n    DWORD lastError;\r\n\r\n    if (ppBuffer == NULL)\r\n    {\r\n        return FALSE;\r\n    }\r\n\r\n    *ppBuffer = NULL;\r\n\r\n    bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,\r\n                                               DeviceInfoData,\r\n                                               Property ,\r\n                                               NULL,\r\n                                               NULL,\r\n                                               0,\r\n                                               &requiredLength);\r\n    lastError = GetLastError();\r\n\r\n    if ((requiredLength == 0) || (bResult != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER))\r\n    {\r\n        return FALSE;\r\n    }\r\n\r\n    *ppBuffer = ALLOC(requiredLength);\r\n\r\n    if (*ppBuffer == NULL)\r\n    {\r\n        return FALSE;\r\n    }\r\n\r\n    bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,\r\n                                                DeviceInfoData,\r\n                                                Property ,\r\n                                                NULL,\r\n                                                (PBYTE) *ppBuffer,\r\n                                                requiredLength,\r\n                                                &requiredLength);\r\n    if(bResult == FALSE)\r\n    {\r\n        FREE(*ppBuffer);\r\n        *ppBuffer = NULL;\r\n        return FALSE;\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\nvoid\r\nEnumerateAllDevicesWithGuid(\r\n    PDEVICE_GUID_LIST DeviceList,\r\n    LPGUID Guid\r\n    )\r\n{\r\n    if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE)\r\n    {\r\n        ClearDeviceList(DeviceList);\r\n    }\r\n\r\n    DeviceList->DeviceInfo = SetupDiGetClassDevs(Guid,\r\n                                     NULL,\r\n                                     NULL,\r\n                                     (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));\r\n\r\n    if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE)\r\n    {\r\n        ULONG                    index;\r\n        DWORD error;\r\n\r\n        error = 0;\r\n        index = 0;\r\n\r\n        while (error != ERROR_NO_MORE_ITEMS)\r\n        {\r\n            BOOL success;\r\n            PDEVICE_INFO_NODE pNode;\r\n\r\n            pNode = ALLOC(sizeof(DEVICE_INFO_NODE));\r\n            if (pNode == NULL)\r\n            {\r\n                OOPS();\r\n                break;\r\n            }\r\n            pNode->DeviceInfo = DeviceList->DeviceInfo;\r\n            pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);\r\n            pNode->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r\n\r\n            success = SetupDiEnumDeviceInfo(DeviceList->DeviceInfo,\r\n                                            index,\r\n                                            &pNode->DeviceInfoData);\r\n\r\n            index++;\r\n\r\n            if (success == FALSE)\r\n            {\r\n                error = GetLastError();\r\n\r\n                if (error != ERROR_NO_MORE_ITEMS)\r\n                {\r\n                    OOPS();\r\n                }\r\n\r\n                FreeDeviceInfoNode(&pNode);\r\n            }\r\n            else\r\n            {\r\n                BOOL   bResult;\r\n                ULONG  requiredLength;\r\n\r\n                bResult = GetDeviceProperty(DeviceList->DeviceInfo,\r\n                                            &pNode->DeviceInfoData,\r\n                                            SPDRP_DEVICEDESC,\r\n                                            &pNode->DeviceDescName);\r\n                if (bResult == FALSE)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                bResult = GetDeviceProperty(DeviceList->DeviceInfo,\r\n                                            &pNode->DeviceInfoData,\r\n                                            SPDRP_DRIVER,\r\n                                            &pNode->DeviceDriverName);\r\n                if (bResult == FALSE)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);\r\n\r\n                success = SetupDiEnumDeviceInterfaces(DeviceList->DeviceInfo,\r\n                                                      0,\r\n                                                      Guid,\r\n                                                      index-1,\r\n                                                      &pNode->DeviceInterfaceData);\r\n                if (!success)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo,\r\n                                                          &pNode->DeviceInterfaceData,\r\n                                                          NULL,\r\n                                                          0,\r\n                                                          &requiredLength,\r\n                                                          NULL);\r\n\r\n                error = GetLastError();\r\n\r\n                if (!success && error != ERROR_INSUFFICIENT_BUFFER)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                pNode->DeviceDetailData = ALLOC(requiredLength);\r\n\r\n                if (pNode->DeviceDetailData == NULL)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                pNode->DeviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);\r\n\r\n                success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo,\r\n                                                          &pNode->DeviceInterfaceData,\r\n                                                          pNode->DeviceDetailData,\r\n                                                          requiredLength,\r\n                                                          &requiredLength,\r\n                                                          NULL);\r\n                if (!success)\r\n                {\r\n                    FreeDeviceInfoNode(&pNode);\r\n                    OOPS();\r\n                    break;\r\n                }\r\n\r\n                InsertTailList(&DeviceList->ListHead, &pNode->ListEntry);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nDEVICE_POWER_STATE\r\nAcquireDevicePowerState(\r\n    _Inout_ PDEVICE_INFO_NODE pNode\r\n    )\r\n{\r\n    CM_POWER_DATA cmPowerData = {0};\r\n    BOOL bResult;\r\n\r\n    bResult =  SetupDiGetDeviceRegistryProperty(pNode->DeviceInfo,\r\n                                               &pNode->DeviceInfoData,\r\n                                               SPDRP_DEVICE_POWER_DATA,\r\n                                               NULL,\r\n                                               (PBYTE)&cmPowerData,\r\n                                               sizeof(cmPowerData),\r\n                                               NULL);\r\n\r\n    pNode->LatestDevicePowerState = bResult ? cmPowerData.PD_MostRecentPowerState : PowerDeviceUnspecified;\r\n\r\n    return pNode->LatestDevicePowerState;\r\n}\r\n\r\n\r\nvoid\r\nClearDeviceList(\r\n    PDEVICE_GUID_LIST DeviceList\r\n    )\r\n{\r\n    if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE)\r\n    {\r\n        SetupDiDestroyDeviceInfoList(DeviceList->DeviceInfo);\r\n        DeviceList->DeviceInfo = INVALID_HANDLE_VALUE;\r\n    }\r\n\r\n    while (!IsListEmpty(&DeviceList->ListHead))\r\n    {\r\n        PDEVICE_INFO_NODE pNode = NULL;\r\n        PLIST_ENTRY pEntry;\r\n\r\n        pEntry = RemoveHeadList(&DeviceList->ListHead);\r\n\r\n        pNode = CONTAINING_RECORD(pEntry,\r\n                                  DEVICE_INFO_NODE,\r\n                                  ListEntry);\r\n\r\n        FreeDeviceInfoNode(&pNode);\r\n    }\r\n}\r\n\r\nVOID\r\nFreeDeviceInfoNode(\r\n    _In_ PDEVICE_INFO_NODE *ppNode\r\n    )\r\n{\r\n    if (ppNode == NULL)\r\n    {\r\n        return;\r\n    }\r\n\r\n    if (*ppNode == NULL)\r\n    {\r\n        return;\r\n    }\r\n\r\n    if ((*ppNode)->DeviceDetailData != NULL)\r\n    {\r\n        FREE((*ppNode)->DeviceDetailData);\r\n    }\r\n\r\n    if ((*ppNode)->DeviceDescName != NULL)\r\n    {\r\n        FREE((*ppNode)->DeviceDescName);\r\n    }\r\n\r\n    if ((*ppNode)->DeviceDriverName != NULL)\r\n    {\r\n        FREE((*ppNode)->DeviceDriverName);\r\n    }\r\n\r\n    FREE(*ppNode);\r\n    *ppNode = NULL;\r\n}\r\n\r\nPDEVICE_INFO_NODE\r\nFindMatchingDeviceNodeForDriverName(\r\n    _In_ PSTR   DriverKeyName,\r\n    _In_ BOOLEAN IsHub\r\n    )\r\n{\r\n    PDEVICE_INFO_NODE pNode  = NULL;\r\n    PDEVICE_GUID_LIST pList  = NULL;\r\n    PLIST_ENTRY       pEntry = NULL;\r\n\r\n    pList = IsHub ? &gHubList : &gDeviceList;\r\n\r\n    pEntry = pList->ListHead.Flink;\r\n\r\n    while (pEntry != &pList->ListHead)\r\n    {\r\n        pNode = CONTAINING_RECORD(pEntry,\r\n                                  DEVICE_INFO_NODE,\r\n                                  ListEntry);\r\n        if (_stricmp(DriverKeyName, pNode->DeviceDriverName) == 0)\r\n        {\r\n            return pNode;\r\n        }\r\n\r\n        pEntry = pEntry->Flink;\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/h264.c",
    "content": "//*****************************************************************************\r\n// I N C L U D E S\r\n//*****************************************************************************\r\n\r\n#include \"uvcview.h\"\r\n#include \"h264.h\"\r\n\r\n#ifdef H264_SUPPORT\r\n\r\n//*****************************************************************************\r\n// G L O B A L S\r\n//*****************************************************************************\r\n// H.264 format\r\nUCHAR g_expectedNumberOfH264FrameDescriptors = 0;\r\nUCHAR g_numberOfH264FrameDescriptors = 0;\r\n\r\n// MJPEG format\r\nUCHAR g_expectedNumberOfMJPEGFrameDescriptors = 0;\r\nUCHAR g_numberOfMJPEGFrameDescriptors = 0;\r\n\r\n// Uncompressed frame format\r\nUCHAR g_expectedNumberOfUncompressedFrameFrameDescriptors = 0;\r\nUCHAR g_numberOfUncompressedFrameFrameDescriptors = 0;\r\n\r\n//*****************************************************************************\r\n//\r\n// external function prototypes\r\n//\r\n//*****************************************************************************\r\nextern VOID VDisplayBytes (PUCHAR Data, USHORT Len );\r\n\r\n//*****************************************************************************\r\n//\r\n// H.264 video format descriptor string tables\r\n//\r\n//*****************************************************************************\r\nSTRINGLIST slSliceModes[]=\r\n{\r\n    {1,         \"Maximum number of Macroblocks per slice mode\",    \"\"},\r\n    {2,         \"Target compressed size per slice mode\",           \"\"},\r\n    {4,         \"Number of slices per frame mode\",                 \"\"},\r\n    {8,         \"Number of Macroblock rows per slice mode\",        \"\"},\r\n    {0x10,      \"Reserved\",                                        \"\"},\r\n    {0x20,      \"Reserved\",                                        \"\"},\r\n    {0x40,      \"Reserved\",                                        \"\"},\r\n    {0x80,      \"Reserved\",                                        \"\"},\r\n};\r\n\r\n\r\nSTRINGLIST slSyncFrameTypes[]=\r\n{\r\n    {1,         \"Reset\"           ,                                                                      \"\"},\r\n    {2,         \"IDR frame with SPS and PPS\",                                                            \"\"},\r\n    {4,         \"IDR frame (with SPS and PPS) that is a long-term reference frame\",                      \"\"},\r\n    {8,         \"Non-IDR random-access I frame (with SPS and PPS)\",                                      \"\"},\r\n    {0x10,      \"Non-IDR random-access I frame (with SPS and PPS) that is a long-term reference frame\",  \"\"},\r\n    {0x20,      \"P frame that is a long-term reference frame\",                                           \"\"},\r\n    {0x40,      \"Gradual Decoder Refresh frames\",                                                        \"\"},\r\n    {0x80,      \"Reserved\",                                                                              \"\"},\r\n};\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// H.264 video frame rate descriptor string tables\r\n//\r\n//*****************************************************************************\r\nSTRINGLIST slUsage[]=\r\n{\r\n    {0x00000001,    \"Real-time/UCConfig mode 0\",        \"\"},  // 0\r\n    {0x00000002,    \"Real-time/UCConfig mode 1\",        \"\"},\r\n    {0x00000004,    \"Real-time/UCConfig mode 2Q\"        \"\"},\r\n    {0x00000008,    \"Real-time/UCConfig mode 2S\"        \"\"},\r\n    {0x00000010,    \"Real-time/UCConfig mode 3\",        \"\"},\r\n    {0x00000020,    \"Reserved\",                         \"\"},\r\n    {0x00000040,    \"Reserved\",                         \"\"},\r\n    {0x00000080,    \"Reserved\",                         \"\"},\r\n\r\n    {0x00000100,    \"Broadcast mode 0\",                \"\"}, // 8\r\n    {0x00000200,    \"Broadcast mode 1\",                \"\"},\r\n    {0x00000400,    \"Broadcast mode 2\",                \"\"},\r\n    {0x00000800,    \"Broadcast mode 3\",                \"\"},\r\n    {0x00001000,    \"Broadcast mode 4\",                \"\"},\r\n    {0x00002000,    \"Broadcast mode 5\",                \"\"},\r\n    {0x00004000,    \"Broadcast mode 6\",                \"\"},\r\n    {0x00008000,    \"Broadcast mode 7\",                \"\"},\r\n\r\n    {0x00010000,    \"File Storage mode with I and P slices (e.g. IPPP)\",            \"\"}, // 16\r\n    {0x00020000,    \"File Storage mode with I, P, and B slices (e.g. IB...BP)\",     \"\"}, // 17\r\n    {0x00040000,    \"File storage all I frame mode\",    \"\"}, // 18\r\n    {0x00080000,    \"Reserved\",                         \"\"}, // 19\r\n    {0x00100000,    \"Reserved\",                         \"\"}, // 20\r\n    {0x00200000,    \"Reserved\",                         \"\"}, // 21\r\n    {0x00400000,    \"Reserved\",                         \"\"}, // 22\r\n    {0x00800000,    \"Reserved\",                         \"\"}, // 23\r\n\r\n    {0x01000000,    \"MVC Stereo High Mode\",             \"\"}, // 24\r\n    {0x02000000,    \"MVC Multiview Mode\",               \"\"}, // 25\r\n    {0x04000000,    \"Reserved\",                         \"\"}, // 26\r\n    {0x08000000,    \"Reserved\",                         \"\"}, // 27\r\n    {0x10000000,    \"Reserved\",                         \"\"}, // 28\r\n    {0x20000000,    \"Reserved\",                         \"\"}, // 29\r\n    {0x40000000,    \"Reserved\",                         \"\"}, // 30\r\n    {0x80000000,    \"Reserved\",                         \"\"}, // 31\r\n\r\n };\r\nSTRINGLIST slCapabilities[]=\r\n{\r\n    {0x0001,    \"CAVLC only\",                       \"\"},\r\n    {0x0002,    \"CABAC only\",                       \"\"},\r\n    {0x0004,    \"Constant frame rate\",              \"\"},\r\n    {0x0008,    \"Separate QP for luma/chroma\",      \"\"},\r\n    {0x0010,    \"Separate QP for Cb/Cr\",            \"\"},\r\n    {0x0020,    \"No picture reordering\",            \"\"},\r\n    {0x0040,    \"Long-term reference frame\",        \"\"},\r\n    {0x0080,    \"Reserved\",                         \"\"},\r\n    {0x0100,    \"Reserved\",                         \"\"},\r\n    {0x0200,    \"Reserved\",                         \"\"},\r\n    {0x0400,    \"Reserved\",                         \"\"},\r\n    {0x0800,    \"Reserved\",                         \"\"},\r\n    {0x1000,    \"Reserved\",                         \"\"},\r\n    {0x2000,    \"Reserved\",                         \"\"},\r\n    {0x4000,    \"Reserved\",                         \"\"},\r\n    {0x8000,    \"Reserved\",                         \"\"},\r\n };\r\n\r\n\r\n\r\nSTRINGLIST slRateControlModes[]=\r\n{\r\n    {1,         \"Variable Bit Rate (VBR) with underflow allowed (H.264 low_delay_hrd_flag = 1)\",    \"\"},\r\n    {2,         \"Constant Bit Rate (CBR) (H.264 low_delay_hrd_flag = 0)\",                           \"\"},\r\n    {4,         \"Constant QP\",                                                                      \"\"},\r\n    {8,         \"Global VBR with underflow allowed (H.264 low_delay_hrd_flag = 1)\",                 \"\"},\r\n    {0x10,      \"VBR without underflow (H.264 low_delay_hrd_flag = 0)\",                             \"\"},\r\n    {0x20,      \"Global VBR without underflow (H.264 low_delay_hrd_flag = 0)\",                      \"\"},\r\n    {0x40,      \"Reserved\",                                                                         \"\"},\r\n    {0x80,      \"Reserved\",                                                                         \"\"},\r\n};\r\n\r\n\r\nSTRINGLIST slProfiles[]=\r\n{\r\n    {0x4200,    \"Baseline Profile\",                                 \"\"},\r\n    {0x4240,    \"Constrained Baseline Profile\",                     \"\"},\r\n    {0x4D00,    \"Main Profile\",                                     \"\"},\r\n    {0x5300,    \"Scalable Baseline Profile\",                        \"\"},\r\n    {0x5304,    \"Scalable Constrained Baseline Profile\",            \"\"},\r\n    {0x5600,    \"Scalable High Profile\",                            \"\"},\r\n    {0x5604,    \"Scalable Constrained High Profile\",                \"\"},\r\n    {0x6400,    \"High Profile\",                                     \"\"},\r\n    {0x640C,    \"Constrained High Profile\",                         \"\"},\r\n    {0x7600,    \"Multiview High Profile\",                           \"\"},\r\n    {0x8000,    \"Stereo High Profile\",                              \"\"},\r\n };\r\n\r\n//*****************************************************************************\r\n//\r\n// H.264 video encoding unit descriptor string tables\r\n//\r\n//*****************************************************************************\r\n\r\nSTRINGLIST slEncodingUnitControls[]=\r\n{\r\n    {0x000001,    \"Select Layer\",                                     \"\"}, // D0\r\n    {0x000002,    \"Profile and Toolset\",                              \"\"}, // D1\r\n    {0x000004,    \"Video Resolution\",                                 \"\"}, // D2\r\n    {0x000008,    \"Minimum Frame Interval\",                           \"\"}, // D3\r\n    {0x000010,    \"Slice Mode\",                                       \"\"}, // D4\r\n    {0x000020,    \"Rate Control Mode\",                                \"\"}, // D5\r\n    {0x000040,    \"Average Bit Rate\",                                 \"\"}, // D6\r\n    {0x000080,    \"CPB Size        \",                                 \"\"}, // D7\r\n    {0x000100,    \"Peak Bit Rate\",                                    \"\"}, // D8\r\n    {0x000200,    \"Quantization Parameter\",                           \"\"}, // D9\r\n    {0x000400,    \"Synchronization and Long-Term Reference Frame\",    \"\"}, // D10\r\n    {0x000800,    \"Long-Term Buffer Size\",                            \"\"}, // D11\r\n    {0x001000,    \"Picture Long-Term Reference\",                      \"\"}, // D12\r\n    {0x002000,    \"Valid LTR\",                                        \"\"}, // D13\r\n    {0x004000,    \"Level IDC\",                                        \"\"}, // D14\r\n    {0x008000,    \"SEI Message\",                                      \"\"}, // D15\r\n    {0x010000,    \"QP Range\",                                         \"\"}, // D16\r\n    {0x020000,    \"Priority ID\",                                      \"\"}, // D17\r\n    {0x040000,    \"Start or Stop Layer/View\",                         \"\"}, // D18\r\n    {0x080000,    \"Error Resiliency\",                                 \"\"}, // D19\r\n    {0x100000,    \"Reserved\",                                         \"\"}, // D20\r\n    {0x200000,    \"Reserved\",                                         \"\"}, // D21\r\n    {0x400000,    \"Reserved\",                                         \"\"}, // D22\r\n    {0x800000,    \"Reserved\",                                         \"\"}, // D23\r\n };\r\n\r\n//*****************************************************************************\r\n//\r\n// commaPrintNumber()\r\n//\r\n//*****************************************************************************\r\nchar * commaPrintNumber( ULONG number )\r\n{\r\n    static char comma = ',';\r\n    static char retbuf[30];\r\n    int digitCount = 0;\r\n\r\n    // null-terminate the string\r\n    char * pOutputString = &retbuf[ sizeof(retbuf)-1 ];\r\n    *pOutputString = '\\0';\r\n\r\n    do\r\n    {\r\n        // for every 3rd digit, add a comma to the output string\r\n        if ( ( digitCount%3 ) == 0 && ( digitCount != 0 ) )\r\n        {\r\n            *--pOutputString = comma;\r\n        }\r\n        *--pOutputString = '0' + number % 10;\r\n        number /= 10;\r\n        digitCount++;\r\n    }\r\n    while( number != 0 );\r\n\r\n    return pOutputString;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayBitmapData()\r\n//\r\n// Note that USB is always oriented Little Endian (least significant byte\r\n// at the lowest address).\r\n//\r\n// Inputs:\r\n// PUCHAR pData - pointer to least significant byte of the data\r\n// UCHAR  byteCount - number of bytes to print in the pData data buffer\r\n// char * stringLabel - string label to print for user's to identify the data type\r\n//\r\n//*****************************************************************************\r\nvoid DisplayBitmapData(_In_reads_(byteCount) PUCHAR pData, UCHAR byteCount,  _In_ char * stringLabel)\r\n{\r\n    UCHAR byteIndex;\r\n    UCHAR data;\r\n    UCHAR mask;\r\n    UCHAR bitIndex;\r\n    UCHAR checkBit = 0; // the bit we want to print\r\n\r\n    // print the label and all the bytes on the first line\r\n    AppendTextBuffer(\"%s : \", stringLabel);\r\n    VDisplayBytes( pData, byteCount );\r\n\r\n    for ( byteIndex = 0; byteIndex < byteCount; byteIndex++ )\r\n    {\r\n        data = pData[ byteIndex ];\r\n        checkBit = 0; // the control bit value we are going to print\r\n        for ( mask = 1, bitIndex = 0; bitIndex < 8; bitIndex++ )\r\n        {\r\n            checkBit =  data & mask;\r\n            AppendTextBuffer(\"     D%02d = %d  %s\\r\\n\",\r\n                bitIndex + 8 * byteIndex,   // increment bit count\r\n                checkBit ? 1 : 0,\r\n                checkBit ? \"yes\" : \" no\");\r\n            mask = mask << 1;\r\n        }\r\n\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayBitmapDataWithStrings()\r\n//\r\n// Note that USB is always oriented Little Endian (least significant byte\r\n// at the lowest address).\r\n//\r\n// This calls GetSTringFromList() to insert a string that corresonds to\r\n// the bit value being print.\r\n//\r\n// Inputs:\r\n// PUCHAR pData - pointer to least significant byte of the data\r\n// UCHAR  byteCount - number of bytes to print in the pData data buffer\r\n// char * stringLabel - string label to print for user's to identify the data type\r\n// STRINGLIST stringList - string table in which to look up bitmap strings\r\n// ULONG numEntriesInTable - number of entrys (strings) in the table\r\n//*****************************************************************************\r\nvoid DisplayBitmapDataWithStrings( _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount,\r\n                                   _In_ char * stringLabel,  _In_ PSTRINGLIST stringList,\r\n                                   ULONG numEntriesInTable)\r\n{\r\n\r\n    UCHAR byteIndex;\r\n    UCHAR data;\r\n    UCHAR byteMask;\r\n    ULONGLONG stringMask;\r\n    UCHAR bitIndex;\r\n    UCHAR checkBit = 0; // the bit we want to print\r\n\r\n    // print the label and all the bytes on the first line\r\n    AppendTextBuffer(\"%s : \", stringLabel);\r\n    VDisplayBytes( pData, byteCount );\r\n\r\n    for ( stringMask = 1, byteIndex = 0; byteIndex < byteCount; byteIndex++ )\r\n    {\r\n        data = pData[ byteIndex ];\r\n        checkBit = 0; // the control bit value we are going to print\r\n        for ( byteMask = 1, bitIndex = 0; bitIndex < 8; bitIndex++ )\r\n        {\r\n            checkBit =  data & byteMask;\r\n            AppendTextBuffer(\"     D%02d = %d  %s %s\\r\\n\",\r\n                bitIndex + 8 * byteIndex, // increment bit count\r\n                checkBit ? 1 : 0,\r\n                checkBit ? \"yes - \" : \" no - \",\r\n                   GetStringFromList(stringList,\r\n                        numEntriesInTable,\r\n                        stringMask,\r\n                        \"Reserved\"));\r\n\r\n            byteMask = byteMask << 1;\r\n            stringMask = stringMask << 1;\r\n        }\r\n\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCH264Format()\r\n//\r\n//*****************************************************************************\r\nBOOL DisplayVCH264Format( _In_reads_(sizeof(VIDEO_FORMAT_H264)) PVIDEO_FORMAT_H264 H264FormatDesc )\r\n{\r\n    if ( H264FormatDesc->bSimulcastSupport == 0 )\r\n    {\r\n        AppendTextBuffer(\"\\r\\n          ===>Video Streaming H.264 Format Type Descriptor<===\\r\\n\");\r\n    }\r\n    else\r\n    {\r\n        AppendTextBuffer(\"\\r\\n          ===>Video Streaming H.264 Simulcast Format Type Descriptor<===\\r\\n\");\r\n    }\r\n    AppendTextBuffer(\"bLength:                           0x%02X = %d\\r\\n\", H264FormatDesc->bLength,               H264FormatDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X \\r\\n\",     H264FormatDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X \\r\\n\",     H264FormatDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFormatIndex:                      0x%02X = %d\\r\\n\", H264FormatDesc->bFormatIndex,          H264FormatDesc->bFormatIndex);\r\n    AppendTextBuffer(\"bNumFrameDescriptors:              0x%02X = %d\\r\\n\", H264FormatDesc->bNumFrameDescriptors,  H264FormatDesc->bNumFrameDescriptors);\r\n    AppendTextBuffer(\"bDefaultFrameIndex:                0x%02X = %d\\r\\n\", H264FormatDesc->bDefaultFrameIndex,    H264FormatDesc->bDefaultFrameIndex);\r\n    AppendTextBuffer(\"bMaxCodecConfigDelay:              0x%02X = %d frames\\r\\n\", H264FormatDesc->bMaxCodecConfigDelay,  H264FormatDesc->bMaxCodecConfigDelay);\r\n    DisplayBitmapDataWithStrings( H264FormatDesc->bmSupportedSliceModes,     sizeof(H264FormatDesc->bmSupportedSliceModes),     \"bmSupportedSliceModes\",    slSliceModes,     sizeof(slSliceModes)/sizeof(STRINGLIST) );\r\n    DisplayBitmapDataWithStrings( H264FormatDesc->bmSupportedSyncFrameTypes,  sizeof(H264FormatDesc->bmSupportedSyncFrameTypes),  \"bmSupportedSyncFrameTypes\", slSyncFrameTypes, sizeof(slSyncFrameTypes)/sizeof(STRINGLIST) );\r\n\r\n    // handle bResolutionScaling\r\n    if (  H264FormatDesc->bResolutionScaling == 0 )\r\n    {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Not Supported\\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n    else if ( H264FormatDesc->bResolutionScaling == 1 )\r\n     {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Limited to 1.5 or 2.0 scaling in both directions, while maintaining the aspect ratio.\\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n    else if ( H264FormatDesc->bResolutionScaling == 2 )\r\n     {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Limited to 1.0, 1.5 or 2.0 scaling in either direction.\\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n    else if ( H264FormatDesc->bResolutionScaling == 3 )\r\n     {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Limited to resolutions reported by the associated Frame Descriptors\\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n    else if ( H264FormatDesc->bResolutionScaling == 4 )\r\n     {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Arbitrary scaling\\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n    else // 5 ... 255\r\n    {\r\n         AppendTextBuffer(\"bResolutionScaling:         0x%02X = %d, Reserved \\r\\n\",\r\n            H264FormatDesc->bResolutionScaling,\r\n            H264FormatDesc->bResolutionScaling );\r\n    }\r\n\r\n     // handle bSimulcastSupport\r\n    if ( H264FormatDesc->bSimulcastSupport == 0 )\r\n    {\r\n        AppendTextBuffer(\"bSimulcastSupport:                 0x%02X = %d, one stream\\r\\n\",\r\n            H264FormatDesc->bSimulcastSupport,\r\n            H264FormatDesc->bSimulcastSupport );\r\n    }\r\n    else if ( H264FormatDesc->bSimulcastSupport == 1 )\r\n    {\r\n        AppendTextBuffer(\"bSimulcastSupport:                 0x%02X = %d, multiple streams\\r\\n\",\r\n            H264FormatDesc->bSimulcastSupport,\r\n            H264FormatDesc->bSimulcastSupport );\r\n    }\r\n    else // ( H264FormatDesc->bSimulcastSupport > 1 )\r\n    {\r\n        AppendTextBuffer(\"bSimulcastSupport:                 0x%02X = %d *!*ERROR:  unknown bSimulcastSupport \\r\\n\",\r\n            H264FormatDesc->bSimulcastSupport,\r\n            H264FormatDesc->bSimulcastSupport,\r\n            H264FormatDesc->bSimulcastSupport );\r\n    }\r\n\r\n\r\n    DisplayBitmapDataWithStrings( &(H264FormatDesc->bmSupportedRateControlModes), sizeof(H264FormatDesc->bmSupportedRateControlModes), \"bmSupportedRateControlModes\",   slRateControlModes, sizeof(slRateControlModes)/sizeof(STRINGLIST) );\r\n\r\n    // Note that USB is Little Endian according to the UVC 2.0 spec\r\n\r\n\r\n    // Resolutions with no scalability\r\n    AppendTextBuffer(\"wMaxMBperSecOneResolutionNoScalability:                 0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecOneResolutionNoScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionNoScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecTwoResolutionsNoScalability:                0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecTwoResolutionsNoScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsNoScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecThreeResolutionsNoScalability:              0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecThreeResolutionsNoScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsNoScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecFourResolutionsNoScalability:               0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecFourResolutionsNoScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsNoScalability) );\r\n\r\n    // Resolutions with temporal scalability\r\n    AppendTextBuffer(\"wMaxMBperSecOneResolutionTemporalScalability:           0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecOneResolutionTemporalScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecTwoResolutionsTemporalScalability:          0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecThreeResolutionsTemporalScalability:        0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecFourResolutionsTemporalScalability:         0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecFourResolutionsTemporalScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalScalability) );\r\n\r\n    // Resolutions with temporal and quality scalability\r\n    AppendTextBuffer(\"wMaxMBperSecOneResolutionTemporalQualityScalability:    0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecOneResolutionTemporalQualityScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalQualityScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecTwoResolutionsTemporalQualityScalability:   0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalQualityScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalQualityScalability) );\r\n\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecThreeResolutionsTemporalQualityScalability: 0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalQualityScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalQualityScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecFourResolutionsTemporalQualityScalability:  0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecFourResolutionsTemporalQualityScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalQualityScalability) );\r\n\r\n    // Resolutions with temporal and spatial scalability\r\n    AppendTextBuffer(\"wMaxMBperSecOneResolutionTemporalSpatialScalability:    0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecOneResolutionTemporalSpatialScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionTemporalSpatialScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecTwoResolutionsTemporalSpatialScalability:   0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalSpatialScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsTemporalSpatialScalability) );\r\n\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecThreeResolutionsTemporalSpatialScalability: 0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalSpatialScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsTemporalSpatialScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecFourResolutionsTemporalSpatialScalability:  0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecFourResolutionsTemporalSpatialScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsTemporalSpatialScalability) );\r\n\r\n   // Resolutions with full scalability\r\n    AppendTextBuffer(\"wMaxMBperSecOneResolutionFullScalability:               0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecOneResolutionFullScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecOneResolutionFullScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecTwoResolutionsFullScalability:              0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecTwoResolutionsFullScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecTwoResolutionsFullScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecThreeResolutionsFullScalability:            0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecThreeResolutionsFullScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecThreeResolutionsFullScalability) );\r\n\r\n    AppendTextBuffer(\"wMaxMBperSecFourResolutionsFullScalability:             0x%04X (%s MB/sec)\\r\\n\",\r\n        H264FormatDesc->wMaxMBperSecFourResolutionsFullScalability,\r\n        commaPrintNumber(1000*H264FormatDesc->wMaxMBperSecFourResolutionsFullScalability) );\r\n\r\n\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCH264FrameType()\r\n//\r\n//*****************************************************************************\r\nBOOL DisplayVCH264FrameType( _In_reads_(sizeof(VIDEO_FRAME_H264)) PVIDEO_FRAME_H264 H264FrameDesc )\r\n{\r\n\r\n    ULONG frameIntervalIndex;\r\n    ULONG value;\r\n    ULONG i;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Streaming H.264 Frame Type Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X = %d\\r\\n\", H264FrameDesc->bLength,            H264FrameDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X \\r\\n\",     H264FrameDesc->bDescriptorType);\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X \\r\\n\",     H264FrameDesc->bDescriptorSubtype);\r\n    AppendTextBuffer(\"bFrameIndex:                       0x%02X = %d\\r\\n\", H264FrameDesc->bFrameIndex,        H264FrameDesc->bFrameIndex);\r\n    AppendTextBuffer(\"wWidth:                          0x%04X = %d\\r\\n\", H264FrameDesc->wWidth,               H264FrameDesc->wWidth);\r\n    AppendTextBuffer(\"wHeight:                         0x%04X = %d\\r\\n\", H264FrameDesc->wHeight,              H264FrameDesc->wHeight);\r\n    AppendTextBuffer(\"wSARwidth:                       0x%04X = %d\\r\\n\", H264FrameDesc->wSARwidth,            H264FrameDesc->wSARwidth);\r\n    AppendTextBuffer(\"wSARheight:                      0x%04X = %d\\r\\n\", H264FrameDesc->wSARheight,           H264FrameDesc->wSARheight);\r\n    AppendTextBuffer(\"wProfile:                        0x%04X - %s\\r\\n\", H264FrameDesc->wProfile,\r\n        GetStringFromList( slProfiles,                                  // string table\r\n                           sizeof(slProfiles)/sizeof(STRINGLIST),       // number of strings in the table\r\n                           H264FrameDesc->wProfile,                     // index of string we want to look up in the string table\r\n                           \"Unknown profile\" ) );                       // string to use if the lookup fails\r\n\r\n    AppendTextBuffer(\"bLevelIDC:                       0x%02X = %d = Level %01.01lf \\r\\n\",\r\n        H264FrameDesc->bLevelIDC, H264FrameDesc->bLevelIDC, H264FrameDesc->bLevelIDC/10.0 );\r\n\r\n    AppendTextBuffer(\"wConstrainedToolset:             0x%04X %s\\r\\n\", H264FrameDesc->wConstrainedToolset,\r\n        ((H264FrameDesc->wConstrainedToolset == 0) ? \"- Reserved\" : \"*!*ERROR: field is reserved and should be zero\"));\r\n\r\n    DisplayBitmapDataWithStrings( H264FrameDesc->bmSupportedUsages, sizeof(H264FrameDesc->bmSupportedUsages), \"bmSupportedUsages\", slUsage, sizeof(slUsage)/sizeof(STRINGLIST) );\r\n    DisplayBitmapDataWithStrings( H264FrameDesc->bmCapabilities, sizeof(H264FrameDesc->bmCapabilities), \"bmCapabilities\",         slCapabilities, sizeof(slCapabilities)/sizeof(STRINGLIST) );\r\n\r\n\r\n    // bmSVCCapabilities[4]\r\n    AppendTextBuffer(\"%s : \", \"bmSVCCapabilities\");\r\n    VDisplayBytes( &(H264FrameDesc->bmSVCCapabilities[0]), sizeof(H264FrameDesc->bmSVCCapabilities)  );\r\n    AppendTextBuffer(\"     D2..D0   = %d  Maximum number of temporal layers = %d\\r\\n\",\r\n        H264FrameDesc->bmSVCCapabilities[0] & 0x7,\r\n        (H264FrameDesc->bmSVCCapabilities[0] & 0x7) + 1 );\r\n    AppendTextBuffer(\"     D3       = %d %s - Rewrite Support\\r\\n\", (H264FrameDesc->bmSVCCapabilities[0] & 0x8) >> 3,\r\n        ((H264FrameDesc->bmSVCCapabilities[0] & 0x8) >> 3) ? \"yes\" : \" no\" );\r\n    AppendTextBuffer(\"     D6..D4   = %d  Maximum number of CGS layers = %d\\r\\n\",\r\n        (H264FrameDesc->bmSVCCapabilities[0] & 0x70) >> 4,\r\n        ((H264FrameDesc->bmSVCCapabilities[0] & 0x70) >> 4) + 1 );\r\n\r\n    value = ( H264FrameDesc->bmSVCCapabilities[1] << 8 ) | H264FrameDesc->bmSVCCapabilities[0];\r\n    value >>= 7;    // shift bit 7 right so that it ends up in the lsb of value\r\n    value &= 0x7;\r\n    AppendTextBuffer(\"     D9..D7   = %d  Number of MGS sublayers\\r\\n\", value );\r\n\r\n    AppendTextBuffer(\"     D10      = %d %s - Additional SNR scalability support in spatial enhancement layers\\r\\n\",\r\n        (H264FrameDesc->bmSVCCapabilities[1] & 0x4) >> 2,\r\n        ((H264FrameDesc->bmSVCCapabilities[1] & 0x4) >> 2) ? \"yes\" : \" no\");\r\n    AppendTextBuffer(\"     D13..D11 = %d  Maximum number of spatial layers = %d\\r\\n\",\r\n        (H264FrameDesc->bmSVCCapabilities[1] & 0x38) >> 3,\r\n        ((H264FrameDesc->bmSVCCapabilities[1] & 0x38) >> 3) + 1 );\r\n\r\n    value = ( H264FrameDesc->bmSVCCapabilities[3] << 16 ) | ( H264FrameDesc->bmSVCCapabilities[2] << 8 ) | H264FrameDesc->bmSVCCapabilities[1];\r\n    value >>= 6; // get bit 14 at LSB\r\n    for ( i = 0; i < 18; i++ )   // bits 31...14\r\n    {\r\n        AppendTextBuffer(\"     D%02d      = %d %s - Reserved \\r\\n\", 14 + i, value & 0x1, (value & 0x1) ? \"yes\" : \" no\"  );\r\n        value >>= 1;\r\n    }\r\n\r\n    // bmMVCCapabilities[4]\r\n    AppendTextBuffer(\"%s : \", \"bmMVCCapabilities\");\r\n    VDisplayBytes( &(H264FrameDesc->bmMVCCapabilities[0]), sizeof(H264FrameDesc->bmMVCCapabilities)  );\r\n    AppendTextBuffer(\"     D2..D0   = %d  Maximum number of temporal layers = %d\\r\\n\",\r\n        H264FrameDesc->bmMVCCapabilities[0] & 0x7,\r\n        ((H264FrameDesc->bmMVCCapabilities[0] & 0x7) + 1) );\r\n\r\n     value =  (H264FrameDesc->bmMVCCapabilities[1] << 8) |  H264FrameDesc->bmMVCCapabilities[0];\r\n     value >>= 3;    // shift bit 3 right so that it ends up in the lsb of value\r\n     value &= 0xff;\r\n     AppendTextBuffer(\"     D10..D3  = %d  Maximum number of view components = %d\\r\\n\",\r\n        value, value + 1);\r\n\r\n     value = (  (H264FrameDesc->bmMVCCapabilities[3] << 16) | (H264FrameDesc->bmMVCCapabilities[2] << 8) |  H264FrameDesc->bmMVCCapabilities[1] );\r\n     value >>= 3;    // shift bit 11 right so that it ends up in the lsb of value\r\n     for ( i = 0; i < 21; i++ )   // bits 31...11\r\n    {\r\n        AppendTextBuffer(\"     D%02d      = %d %s - Reserved \\r\\n\", 11 + i, value & 0x1, (value & 0x1) ? \"yes\" : \" no\" );\r\n        value >>= 1;\r\n    }\r\n\r\n\r\n    AppendTextBuffer(\"dwMinBitRate:                    0x%08X  = %s bps\\r\\n\", H264FrameDesc->dwMinBitRate, commaPrintNumber(H264FrameDesc->dwMinBitRate));\r\n    AppendTextBuffer(\"dwMaxBitRate:                    0x%08X  = %s bps\\r\\n\", H264FrameDesc->dwMaxBitRate, commaPrintNumber(H264FrameDesc->dwMaxBitRate));\r\n\r\n    // To convert the default frame interval, which is in 100 ns units,  to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n    AppendTextBuffer(\"dwDefaultFrameInterval:          0x%08X  = %lf mSec (%4.2f Hz) \\r\\n\",\r\n        H264FrameDesc->dwDefaultFrameInterval, ((double)H264FrameDesc->dwDefaultFrameInterval)/10000.0, (10000000.0/((double)H264FrameDesc->dwDefaultFrameInterval)));\r\n    AppendTextBuffer(\"bNumFrameIntervals:              0x%02X = %d\\r\\n\", H264FrameDesc->bNumFrameIntervals, H264FrameDesc->bNumFrameIntervals);\r\n\r\n\r\n    // frame interval 100 ns units.\r\n\r\n    //To convert the frame interval to seconds we would divide by 10,000,000.\r\n    // 100 ns = 10^(-7) seconds = 1/10,000,000\r\n\r\n    // To convert the frame interval to Hz, we divide by 10,000,000 and then take the inverse\r\n\r\n    // To convert the frame interval to  milliseconds, we divide by 10,000.\r\n    // 100 ns = 10^(-7) seconds = 10^(-7) sec * 1000 msec/sec = 10^(-7) * 10^3 milleseconds = 10^(-4) seconds\r\n    // = 1/10,000 milliseconds\r\n\r\n    for ( frameIntervalIndex = 0; frameIntervalIndex < H264FrameDesc->bNumFrameIntervals; frameIntervalIndex++ )\r\n    {\r\n        value = (ULONG)H264FrameDesc->dwFrameInterval[ frameIntervalIndex ];\r\n        AppendTextBuffer(\"dwFrameInterval[%d]: 0x%08x = %lf mSec (%4.2f Hz)\\r\\n\", frameIntervalIndex, value, ((double)value)/10000.0, (10000000.0/((double)value)) );\r\n\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// DisplayVCH264EncodingUnit()\r\n//\r\n//*****************************************************************************\r\nBOOL DisplayVCH264EncodingUnit(\r\n                        _In_reads_(sizeof(VIDEO_ENCODING_UNIT)) PVIDEO_ENCODING_UNIT VidEncodingDesc\r\n        )\r\n{\r\n\r\n    PUCHAR pControlsRunTimeData = NULL;\r\n\r\n    AppendTextBuffer(\"\\r\\n          ===>Video Control Encoding Unit Descriptor<===\\r\\n\");\r\n    AppendTextBuffer(\"bLength:                           0x%02X = %d\\r\\n\", VidEncodingDesc->bLength,        VidEncodingDesc->bLength);\r\n    AppendTextBuffer(\"bDescriptorType:                   0x%02X \\r\\n\",     VidEncodingDesc->bDescriptorType );\r\n    AppendTextBuffer(\"bDescriptorSubtype:                0x%02X \\r\\n\",     VidEncodingDesc->bDescriptorSubtype );\r\n    AppendTextBuffer(\"bUnitID:                           0x%02X = %d\\r\\n\", VidEncodingDesc->bUnitID,        VidEncodingDesc->bUnitID);\r\n    AppendTextBuffer(\"bSourceID:                         0x%02X = %d\\r\\n\", VidEncodingDesc->bSourceID,      VidEncodingDesc->bSourceID);\r\n    AppendTextBuffer(\"iEncoding:                         0x%02X = %d\\r\\n\", VidEncodingDesc->iEncoding,      VidEncodingDesc->iEncoding);\r\n    AppendTextBuffer(\"bControlSize:                      0x%02X = %d\\r\\n\", VidEncodingDesc->bControlSize,   VidEncodingDesc->bControlSize);\r\n\r\n    if ( VidEncodingDesc->bControlSize > 0)\r\n    {\r\n        // Encoding Unit Descriptor bmControls field\r\n        DisplayBitmapDataWithStrings( VidEncodingDesc->bmControls, VidEncodingDesc->bControlSize /* print bControlSize bytes worth of bitmap info */,\r\n            \"bmControls\", slEncodingUnitControls, sizeof(slEncodingUnitControls)/sizeof(STRINGLIST) );\r\n\r\n        // Encoding Unit Descriptor bmControlsRuntime field\r\n        pControlsRunTimeData = ((UCHAR *)(&VidEncodingDesc->bmControls)) + VidEncodingDesc->bControlSize;\r\n        DisplayBitmapDataWithStrings( pControlsRunTimeData, VidEncodingDesc->bControlSize /* print bControlSize bytes worth of bitmap info */,\r\n            \"bmControlsRuntime\", slEncodingUnitControls, sizeof(slEncodingUnitControls)/sizeof(STRINGLIST) );\r\n    }\r\n    return TRUE;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// DoAdditionalErrorChecks()\r\n//\r\n// Currently this function only checks to see that the number of frame\r\n// descriptors actually found equals the number specified in the corresponding\r\n// format descriptor.\r\n//\r\n// Because this potentially involves parsing multiple frame descriptors, we\r\n// call this routine after the video descriptor has been parsed and displayed.\r\n//\r\n//*****************************************************************************\r\nvoid DoAdditionalErrorChecks()\r\n{\r\n    if( g_expectedNumberOfH264FrameDescriptors > 0 || g_numberOfH264FrameDescriptors > 0\r\n        || g_expectedNumberOfUncompressedFrameFrameDescriptors > 0 || g_numberOfUncompressedFrameFrameDescriptors > 0\r\n        || g_expectedNumberOfMJPEGFrameDescriptors > 0 || g_numberOfMJPEGFrameDescriptors > 0)\r\n    {\r\n        AppendTextBuffer(\"\\r\\n          ===>Additional Error Checking<===\\r\\n\");\r\n\r\n        // H.264 frame descriptor\r\n        if( g_expectedNumberOfH264FrameDescriptors > 0 || g_numberOfH264FrameDescriptors > 0)\r\n        {\r\n            if ( g_expectedNumberOfH264FrameDescriptors == g_numberOfH264FrameDescriptors )\r\n            {\r\n                AppendTextBuffer(\"PASS: number of H.264 frame descriptors (%d) == number of frame descriptors (%d) specified in H.264 format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfH264FrameDescriptors, g_numberOfH264FrameDescriptors );\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"FAIL: number of H.264 frame descriptors (%d) != number of frame descriptors (%d) specified in H.264 format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfH264FrameDescriptors, g_numberOfH264FrameDescriptors );\r\n            }\r\n        }\r\n\r\n        // uncompressed frame descriptor\r\n        if( g_expectedNumberOfUncompressedFrameFrameDescriptors > 0 || g_numberOfUncompressedFrameFrameDescriptors > 0)\r\n        {\r\n\r\n            if ( g_expectedNumberOfUncompressedFrameFrameDescriptors == g_numberOfUncompressedFrameFrameDescriptors )\r\n            {\r\n                AppendTextBuffer(\"PASS: number of uncompressed-frame frame descriptors (%d) == number of frame descriptors (%d) specified in uncompressed format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfUncompressedFrameFrameDescriptors, g_numberOfUncompressedFrameFrameDescriptors );\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"FAIL: number of uncompressed-frame frame descriptors (%d) != number of frame descriptors (%d) specified in uncompressed format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfUncompressedFrameFrameDescriptors, g_numberOfUncompressedFrameFrameDescriptors );\r\n            }\r\n        }\r\n\r\n        // MJPEG frame descriptor\r\n        if( g_expectedNumberOfMJPEGFrameDescriptors > 0 || g_numberOfMJPEGFrameDescriptors > 0)\r\n        {\r\n            if ( g_expectedNumberOfMJPEGFrameDescriptors == g_numberOfMJPEGFrameDescriptors )\r\n            {\r\n                AppendTextBuffer(\"PASS: number of MJPEG frame descriptors (%d) == number of frame descriptors (%d) specified in MJPEG format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfMJPEGFrameDescriptors, g_numberOfMJPEGFrameDescriptors );\r\n            }\r\n            else\r\n            {\r\n                AppendTextBuffer(\"FAIL: number of MJPEG frame descriptors (%d) != number of frame descriptors (%d) specified in MJPEG format descriptor(s)\\r\\n\",\r\n                    g_expectedNumberOfMJPEGFrameDescriptors, g_numberOfMJPEGFrameDescriptors );\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n// ResetErrorCounts()\r\n//\r\n//*****************************************************************************\r\nvoid ResetErrorCounts()\r\n{\r\n\r\n    // H.264 format\r\n    g_expectedNumberOfH264FrameDescriptors = 0;\r\n    g_numberOfH264FrameDescriptors = 0;\r\n\r\n    // MJPEG format\r\n    g_expectedNumberOfMJPEGFrameDescriptors = 0;\r\n    g_numberOfMJPEGFrameDescriptors = 0;\r\n\r\n    // Uncompressed frame format\r\n    g_expectedNumberOfUncompressedFrameFrameDescriptors = 0;\r\n    g_numberOfUncompressedFrameFrameDescriptors = 0;\r\n}\r\n\r\n#endif //H264_SUPPORT\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/h264.h",
    "content": "#pragma once\r\n\r\n#ifdef H264_SUPPORT\r\n\r\n//*****************************************************************************\r\n//\r\n// external variables\r\n//\r\n//*****************************************************************************\r\nextern UCHAR g_expectedNumberOfH264FrameDescriptors;\r\nextern UCHAR g_numberOfH264FrameDescriptors;\r\n\r\nextern UCHAR g_expectedNumberOfMJPEGFrameDescriptors;\r\nextern UCHAR g_numberOfMJPEGFrameDescriptors;\r\n\r\nextern UCHAR g_expectedNumberOfUncompressedFrameFrameDescriptors;\r\nextern UCHAR g_numberOfUncompressedFrameFrameDescriptors;\r\n\r\n#endif\r\n\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// defines\r\n//\r\n//*****************************************************************************\r\n\r\n//Version information printed at lower left of UI Window and top of output text window\r\n#define USBVIEW_MAJOR_VERSION   2\r\n#define USBVIEW_MINOR_VERSION   0\r\n#define UVC_SPEC_MAJOR_VERSION  1\r\n#define UVC_SPEC_MINOR_VERSION  5\r\n\r\n\r\n// definitions take from the proposed UVC 1.5 spec\r\n#define VS_FORMAT_H264  0x13\r\n#define VS_FRAME_H264   0x14\r\n\r\n\r\n// Video Class-Specific VC Interface Descriptor Subtypes\r\n// Note, this needs to be added to the list already in C:\\nt\\sdpublic\\internal\\drivers\\inc\\uvcdesc.h\r\n// Also, note that MAX_TYPE_UNIT needs to be bumped up by 1 to account for this new subtype..\r\n#define H264_ENCODING_UNIT 7\r\n\r\n//*****************************************************************************\r\n//\r\n// struct definitions\r\n//\r\n//*****************************************************************************\r\n\r\n// VideoStreaming H.264 Format Descriptor\r\n#pragma pack(push, 1)       // pack on a 1 byte boundary\r\ntypedef struct _VIDEO_FORMAT_H264\r\n{                                                                   // offset (in bytes):\r\n    UCHAR bLength;                                                  // 0\r\n    UCHAR bDescriptorType;                                          // 1\r\n    UCHAR bDescriptorSubtype;                                       // 2\r\n    UCHAR bFormatIndex;                                             // 3\r\n    UCHAR bNumFrameDescriptors;                                     // 4\r\n    UCHAR bDefaultFrameIndex;                                       // 5\r\n    UCHAR bMaxCodecConfigDelay;                                     // 6\r\n    UCHAR bmSupportedSliceModes[1];                                 // 7\r\n    UCHAR bmSupportedSyncFrameTypes[1];                             // 8\r\n    UCHAR bResolutionScaling;                                       // 9\r\n    UCHAR bSimulcastSupport;                                        // 10\r\n    UCHAR bmSupportedRateControlModes;                              // 11\r\n\r\n    USHORT wMaxMBperSecOneResolutionNoScalability;                  // 12\r\n    USHORT wMaxMBperSecTwoResolutionsNoScalability;                 // 14\r\n    USHORT wMaxMBperSecThreeResolutionsNoScalability;               // 16\r\n    USHORT wMaxMBperSecFourResolutionsNoScalability;                // 18\r\n\r\n    USHORT wMaxMBperSecOneResolutionTemporalScalability;             // 20\r\n    USHORT wMaxMBperSecTwoResolutionsTemporalScalability;            // 22\r\n    USHORT wMaxMBperSecThreeResolutionsTemporalScalability;          // 24\r\n    USHORT wMaxMBperSecFourResolutionsTemporalScalability;           // 26\r\n\r\n    USHORT wMaxMBperSecOneResolutionTemporalQualityScalability;      // 28\r\n    USHORT wMaxMBperSecTwoResolutionsTemporalQualityScalability;     // 30\r\n    USHORT wMaxMBperSecThreeResolutionsTemporalQualityScalability;   // 32\r\n    USHORT wMaxMBperSecFourResolutionsTemporalQualityScalability;    // 34\r\n\r\n    USHORT wMaxMBperSecOneResolutionTemporalSpatialScalability;      // 36\r\n    USHORT wMaxMBperSecTwoResolutionsTemporalSpatialScalability;     // 38\r\n    USHORT wMaxMBperSecThreeResolutionsTemporalSpatialScalability;   // 40\r\n    USHORT wMaxMBperSecFourResolutionsTemporalSpatialScalability;    // 42\r\n\r\n    USHORT wMaxMBperSecOneResolutionFullScalability;                 // 44\r\n    USHORT wMaxMBperSecTwoResolutionsFullScalability;                // 46\r\n    USHORT wMaxMBperSecThreeResolutionsFullScalability;              // 48\r\n    USHORT wMaxMBperSecFourResolutionsFullScalability;               // 50\r\n} VIDEO_FORMAT_H264, *PVIDEO_FORMAT_H264;\r\n#pragma pack(pop)\r\n\r\n\r\n// VideoStreaming H.264 Frame Descriptor\r\n#pragma pack(push, 1)       // pack on a 1 byte boundary\r\n\r\n// Disable warning on zero sized array in CPP compiler\r\n#pragma warning(push)\r\n#pragma warning(disable:4200) // Zero sized array\r\n\r\ntypedef struct _VIDEO_FRAME_H264\r\n{                                               // offset (in bytes):\r\n    UCHAR  bLength;                             // 0\r\n    UCHAR  bDescriptorType;                     // 1\r\n    UCHAR  bDescriptorSubtype;                  // 2\r\n    UCHAR  bFrameIndex;                         // 3\r\n    USHORT wWidth;                              // 4\r\n    USHORT wHeight;                             // 6\r\n    USHORT wSARwidth;                           // 8\r\n    USHORT wSARheight;                          // 10\r\n    USHORT wProfile;                            // 12\r\n    UCHAR  bLevelIDC;                           // 14\r\n    USHORT wConstrainedToolset;                 // 15\r\n    UCHAR  bmSupportedUsages[4];                // 17\r\n    UCHAR  bmCapabilities[2];                   // 21\r\n    UCHAR  bmSVCCapabilities[4];                // 23\r\n    UCHAR  bmMVCCapabilities[4];                // 27\r\n    ULONG  dwMinBitRate;                        // 31\r\n    ULONG  dwMaxBitRate;                        // 35\r\n    ULONG  dwDefaultFrameInterval;              // 39\r\n    UCHAR  bNumFrameIntervals;                  // 43\r\n    ULONG  dwFrameInterval[];                   // 44 variable-length parameter\r\n} VIDEO_FRAME_H264, *PVIDEO_FRAME_H264;\r\n#pragma warning(pop)\r\n#pragma pack(pop)\r\n\r\n\r\n// VideoControl Encoding Unit Descriptor\r\n#pragma pack(push, 1)       // pack on a 1 byte boundary\r\n#pragma warning(push)\r\n#pragma warning(disable:4200) // Zero sized array\r\ntypedef struct //_VIDEO_ENCODING_UNIT\r\n{                                               // offset (in bytes):\r\n    UCHAR bLength;                              // 0\r\n    UCHAR bDescriptorType;                      // 1\r\n    UCHAR bDescriptorSubtype;                   // 2\r\n    UCHAR bUnitID;                              // 3\r\n    UCHAR bSourceID;                            // 4\r\n    UCHAR iEncoding;                            // 5\r\n    UCHAR bControlSize;                         // 6\r\n    UCHAR bmControls[];                         // 7 - variable-length parameter (bControlSize specifies the size)\r\n} VIDEO_ENCODING_UNIT, *PVIDEO_ENCODING_UNIT;\r\n// after bmControls[] there is also the variable-length parameter (bControlSize specifies the size:\r\n// UCHAR bmControlsRunTime[]\r\n#pragma warning(pop)\r\n#pragma pack(pop)\r\n\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// function prototypes\r\n//\r\n//*****************************************************************************\r\nBOOL DisplayVCH264Format( _In_reads_(sizeof(VIDEO_FORMAT_H264)) PVIDEO_FORMAT_H264 H264FormatDesc );\r\nBOOL DisplayVCH264FrameType( _In_reads_(sizeof(VIDEO_FRAME_H264)) PVIDEO_FRAME_H264 H264FrameDesc );\r\nBOOL DisplayVCH264EncodingUnit( _In_reads_(sizeof(VIDEO_ENCODING_UNIT))  PVIDEO_ENCODING_UNIT VidEncodingDesc );\r\nvoid DisplayBitmapData(  _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount,  _In_ char * stringLabel);\r\nvoid DisplayBitmapDataWithStrings(  _In_reads_(byteCount) PUCHAR pData, UCHAR byteCount,  _In_ char * stringLabel,  _In_ PSTRINGLIST stringList, ULONG numEntriesInTable );\r\nvoid DoAdditionalErrorChecks();\r\nvoid ResetErrorCounts();\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/langidlist.h",
    "content": "/*++\r\n\r\nCopyright (c) 2003-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    LANGIDLIST.H\r\n\r\nAbstract:\r\n\r\n    This file LANGIDLIST.H contains content from USB.org, and was reviewed\r\n    by LCA in June 2011. Per discussion with USB consortium counsel their\r\n    material is \"free to any use\".\r\n\r\n    This header file contains a list of all currently known USB Language IDs\r\n    and the language name associated with each Language ID.\r\n\r\n\r\n\r\nSource:\r\n    http://www.usb.org\r\n\r\nEnvironment:\r\n\r\n    Kernel & user mode\r\n\r\nRevision History:\r\n\r\n    03-28-03 : created\r\n\r\n--*/\r\n\r\n#ifndef   __LANGIDLIST_H__\r\n#define   __LANGIDLIST_H__\r\n\r\n//\r\n// Language ID structure\r\n//\r\ntypedef struct {\r\n    USHORT  usLangID;\r\n    PCHAR   szLanguage;\r\n} USBLANGID, *PUSBLANGID;\r\n\r\n//\r\n// This list built from information obtained on Nov-30-2000 from\r\n// http://www.usb.org\r\n//\r\n// This information has not been independently verified and no claims\r\n// are made here as to its accuracy.\r\n//\r\n\r\nUSBLANGID USBLangIDs[] =\r\n{\r\n    {1078   , /*    0x0436  */ \"Afrikaans\"},\r\n    {1052   , /*    0x041c  */ \"Albanian\"},\r\n    {1025   , /*    0x0401  */ \"Arabic (Saudi Arabia)\"},\r\n    {2049   , /*    0x0801  */ \"Arabic (Iraq)\"},\r\n    {3073   , /*    0x0c01  */ \"Arabic (Egypt)\"},\r\n    {4097   , /*    0x1001  */ \"Arabic (Libya)\"},\r\n    {5121   , /*    0x1401  */ \"Arabic (Algeria)\"},\r\n    {6145   , /*    0x1801  */ \"Arabic (Morocco)\"},\r\n    {7169   , /*    0x1c01  */ \"Arabic (Tunisia)\"},\r\n    {8193   , /*    0x2001  */ \"Arabic (Oman)\"},\r\n    {9217   , /*    0x2401  */ \"Arabic (Yemen)\"},\r\n    {10241  , /*    0x2801  */ \"Arabic (Syria)\"},\r\n    {11265  , /*    0x2c01  */ \"Arabic (Jordan)\"},\r\n    {12289  , /*    0x3001  */ \"Arabic (Lebanon)\"},\r\n    {13313  , /*    0x3401  */ \"Arabic (Kuwait)\"},\r\n    {14337  , /*    0x3801  */ \"Arabic (U.A.E.)\"},\r\n    {15361  , /*    0x3c01  */ \"Arabic (Bahrain)\"},\r\n    {16385  , /*    0x4001  */ \"Arabic (Qatar)  \"},\r\n    {1067   , /*    0x042b  */ \"Armenian\"},\r\n    {1101   , /*    0x044d  */ \"Assamese\"},\r\n    {1068   , /*    0x042c  */ \"Azeri (Latin)\"},\r\n    {2092   , /*    0x082c  */ \"Azeri (Cyrillic)\"},\r\n    {1069   , /*    0x042d  */ \"Basque\"},\r\n    {1059   , /*    0x0423  */ \"Belarussian\"},\r\n    {1093   , /*    0x0445  */ \"Bengali\"},\r\n    {1026   , /*    0x0402  */ \"Bulgarian\"},\r\n    {1109   , /*    0x0455  */ \"Burmese\"},\r\n    {1027   , /*    0x0403  */ \"Catalan\"},\r\n    {1028   , /*    0x0404  */ \"Chinese (Taiwan)\"},\r\n    {2052   , /*    0x0804  */ \"Chinese (PRC)\"},\r\n    {3076   , /*    0x0c04  */ \"Chinese (Hong Kong SAR, PRC)\"},\r\n    {4100   , /*    0x1004  */ \"Chinese (Singapore)\"},\r\n    {5124   , /*    0x1404  */ \"Chinese (MACAO SAR)\"},\r\n    {1050   , /*    0x041a  */ \"Croatian\"},\r\n    {1029   , /*    0x0405  */ \"Czech\"},\r\n    {1030   , /*    0x0406  */ \"Danish\"},\r\n    {1043   , /*    0x0413  */ \"Dutch (Netherlands)\"},\r\n    {2067   , /*    0x0813  */ \"Dutch (Belgium)\"},\r\n    {1033   , /*    0x0409  */ \"English (United States)\"},\r\n    {2057   , /*    0x0809  */ \"English (United Kingdom)\"},\r\n    {3081   , /*    0x0c09  */ \"English (Australian)\"},\r\n    {4105   , /*    0x1009  */ \"English (Canadian)\"},\r\n    {5129   , /*    0x1409  */ \"English (New Zealand)\"},\r\n    {6153   , /*    0x1809  */ \"English (Ireland)\"},\r\n    {7177   , /*    0x1c09  */ \"English (South Africa)\"},\r\n    {8201   , /*    0x2009  */ \"English (Jamaica)\"},\r\n    {9225   , /*    0x2409  */ \"English (Caribbean)\"},\r\n    {10249  , /*    0x2809  */ \"English (Belize)\"},\r\n    {11273  , /*    0x2c09  */ \"English (Trinidad)\"},\r\n    {12297  , /*    0x3009  */ \"English (Zimbabwe)\"},\r\n    {13321  , /*    0x3409  */ \"English (Philippines)\"},\r\n    {1061   , /*    0x0425  */ \"Estonian\"},\r\n    {1080   , /*    0x0438  */ \"Faeroese\"},\r\n    {1065   , /*    0x0429  */ \"Farsi   \"},\r\n    {1035   , /*    0x040b  */ \"Finnish\"},\r\n    {1036   , /*    0x040c  */ \"French (Standard)\"},\r\n    {2060   , /*    0x080c  */ \"French (Belgian)\"},\r\n    {3084   , /*    0x0c0c  */ \"French (Canadian)\"},\r\n    {4108   , /*    0x100c  */ \"French (Switzerland)\"},\r\n    {5132   , /*    0x140c  */ \"French (Luxembourg)\"},\r\n    {6156   , /*    0x180c  */ \"French (Monaco)\"},\r\n    {1079   , /*    0x0437  */ \"Georgian\"},\r\n    {1031   , /*    0x0407  */ \"German (Standard)\"},\r\n    {2055   , /*    0x0807  */ \"German (Switzerland)\"},\r\n    {3079   , /*    0x0c07  */ \"German (Austria)\"},\r\n    {4103   , /*    0x1007  */ \"German (Luxembourg)\"},\r\n    {5127   , /*    0x1407  */ \"German (Liechtenstein)\"},\r\n    {1032   , /*    0x0408  */ \"Greek\"},\r\n    {1095   , /*    0x0447  */ \"Gujarati\"},\r\n    {1037   , /*    0x040d  */ \"Hebrew\"},\r\n    {1081   , /*    0x0439  */ \"Hindi\"},\r\n    {1038   , /*    0x040e  */ \"Hungarian\"},\r\n    {1039   , /*    0x040f  */ \"Icelandic\"},\r\n    {1057   , /*    0x0421  */ \"Indonesian\"},\r\n    {1040   , /*    0x0410  */ \"Italian (Standard)\"},\r\n    {2064   , /*    0x0810  */ \"Italian (Switzerland)\"},\r\n    {1041   , /*    0x0411  */ \"Japanese\"},\r\n    {1099   , /*    0x044b  */ \"Kannada\"},\r\n    {2144   , /*    0x0860  */ \"Kashmiri (India)\"},\r\n    {1087   , /*    0x043f  */ \"Kazakh\"},\r\n    {1111   , /*    0x0457  */ \"Konkani\"},\r\n    {1042   , /*    0x0412  */ \"Korean\"},\r\n    {2066   , /*    0x0812  */ \"Korean (Johab)\"},\r\n    {1062   , /*    0x0426  */ \"Latvian\"},\r\n    {1063   , /*    0x0427  */ \"Lithuanian\"},\r\n    {2087   , /*    0x0827  */ \"Lithuanian (Classic)\"},\r\n    {1071   , /*    0x042f  */ \"Macedonia, Former Yugoslav Republic of\"},\r\n    {1086   , /*    0x043e  */ \"Malay (Malaysian)\"},\r\n    {2110   , /*    0x083e  */ \"Malay (Brunei Darussalam)\"},\r\n    {1100   , /*    0x044c  */ \"Malayalam\"},\r\n    {1112   , /*    0x0458  */ \"Manipuri\"},\r\n    {1102   , /*    0x044e  */ \"Marathi\"},\r\n    {2145   , /*    0x0861  */ \"Nepali (India)\"},\r\n    {1044   , /*    0x0414  */ \"Norwegian (Bokmal)\"},\r\n    {2068   , /*    0x0814  */ \"Norwegian (Nynorsk)\"},\r\n    {1096   , /*    0x0448  */ \"Odia\"},\r\n    {1045   , /*    0x0415  */ \"Polish\"},\r\n    {1046   , /*    0x0416  */ \"Portuguese (Brazil)\"},\r\n    {2070   , /*    0x0816  */ \"Portuguese (Portugal)\"},\r\n    {1094   , /*    0x0446  */ \"Punjabi\"},\r\n    {1048   , /*    0x0418  */ \"Romanian\"},\r\n    {1049   , /*    0x0419  */ \"Russian\"},\r\n    {1103   , /*    0x044f  */ \"Sanskrit\"},\r\n    {3098   , /*    0x0c1a  */ \"Serbian (Cyrillic)\"},\r\n    {2074   , /*    0x081a  */ \"Serbian (Latin)\"},\r\n    {1113   , /*    0x0459  */ \"Sindhi\"},\r\n    {1051   , /*    0x041b  */ \"Slovak\"},\r\n    {1060   , /*    0x0424  */ \"Slovenian\"},\r\n    {1034   , /*    0x040a  */ \"Spanish (Traditional Sort)\"},\r\n    {2058   , /*    0x080a  */ \"Spanish (Mexican)\"},\r\n    {3082   , /*    0x0c0a  */ \"Spanish (Modern Sort)\"},\r\n    {4106   , /*    0x100a  */ \"Spanish (Guatemala)\"},\r\n    {5130   , /*    0x140a  */ \"Spanish (Costa Rica)\"},\r\n    {6154   , /*    0x180a  */ \"Spanish (Panama)\"},\r\n    {7178   , /*    0x1c0a  */ \"Spanish (Dominican Republic)\"},\r\n    {8202   , /*    0x200a  */ \"Spanish (Venezuela)\"},\r\n    {9226   , /*    0x240a  */ \"Spanish (Colombia)\"},\r\n    {10250  , /*    0x280a  */ \"Spanish (Peru)\"},\r\n    {11274  , /*    0x2c0a  */ \"Spanish (Argentina)\"},\r\n    {12298  , /*    0x300a  */ \"Spanish (Ecuador)\"},\r\n    {13322  , /*    0x340a  */ \"Spanish (Chile)\"},\r\n    {14346  , /*    0x380a  */ \"Spanish (Uruguay)\"},\r\n    {15370  , /*    0x3c0a  */ \"Spanish (Paraguay)\"},\r\n    {16394  , /*    0x400a  */ \"Spanish (Bolivia)\"},\r\n    {17418  , /*    0x440a  */ \"Spanish (El Salvador)\"},\r\n    {18442  , /*    0x480a  */ \"Spanish (Honduras)\"},\r\n    {19466  , /*    0x4c0a  */ \"Spanish (Nicaragua)\"},\r\n    {20490  , /*    0x500a  */ \"Spanish (Puerto Rico)\"},\r\n    {1072   , /*    0x0430  */ \"Sutu\"},\r\n    {1089   , /*    0x0441  */ \"Swahili (Kenya)\"},\r\n    {1053   , /*    0x041d  */ \"Swedish\"},\r\n    {2077   , /*    0x081d  */ \"Swedish (Finland)\"},\r\n    {1097   , /*    0x0449  */ \"Tamil\"},\r\n    {1092   , /*    0x0444  */ \"Tatar (Tatarstan)\"},\r\n    {1098   , /*    0x044a  */ \"Telugu\"},\r\n    {1054   , /*    0x041e  */ \"Thai\"},\r\n    {1055   , /*    0x041f  */ \"Turkish\"},\r\n    {1058   , /*    0x0422  */ \"Ukrainian\"},\r\n    {1056   , /*    0x0420  */ \"Urdu (Pakistan)\"},\r\n    {2080   , /*    0x0820  */ \"Urdu (India)\"},\r\n    {1091   , /*    0x0443  */ \"Uzbek (Latin)\"},\r\n    {2115   , /*    0x0843  */ \"Uzbek (Cyrillic)\"},\r\n    {1066   , /*    0x042a  */ \"Vietnamese\"},\r\n    {1279   , /*    0x04ff  */ \"HID (Usage Data Descriptor)\"},\r\n    {61695  , /*    0xf0ff  */ \"HID (Vendor Defined 1)\"},\r\n    {62719  , /*    0xf4ff  */ \"HID (Vendor Defined 2)\"},\r\n    {63743  , /*    0xf8ff  */ \"HID (Vendor Defined 3)\"},\r\n    {64767  , /*    0xfcff  */ \"HID (Vendor Defined 4)\"},\r\n    { 0x00, \"End\"}\r\n};\r\n\r\n#endif /* __LANGIDLIST_H__ */\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/resource.h",
    "content": "/*++\r\nCopyright (c) 1998-2008 Microsoft Corporation, All Rights Reserved.\r\n--*/\r\n\r\n#define IDD_MAINDIALOG                  101\r\n#define IDR_MENU                        102\r\n#define IDD_ABOUT                       103\r\n#define IDI_ICON                        104\r\n#define IDC_SPLIT                       105\r\n#define IDACCEL                         106\r\n\r\n#define IDI_BADICON                     107\r\n#define IDI_COMPUTER                    108\r\n#define IDI_HUB                         109\r\n#define IDI_NODEVICE                    110\r\n#define IDI_SSICON                      111\r\n#define IDI_NOSSDEVICE                  112\r\n\r\n#define IDC_TREE                        1000\r\n#define IDC_EDIT                        1001\r\n#define IDC_STATUS                      1002\r\n\r\n#define IDS_STRINGBASE                  2000\r\n#define IDS_STANDARD_FONT               2001\r\n#define IDS_STANDARD_FONT_HEIGHT        2002\r\n#define IDS_STANDARD_FONT_WIDTH         2003\r\n#define IDS_USBVIEW_USAGE               2004\r\n#define IDS_USBVIEW_PRESSKEY            2005\r\n#define IDS_USBVIEW_INVALIDARG          2006\r\n#define IDS_USBVIEW_FILE_EXISTS_TXT     2007\r\n#define IDS_USBVIEW_FILE_EXISTS_XML     2008\r\n#define IDS_USBVIEW_INTERNAL_ERROR      2009\r\n#define IDS_USBVIEW_SAVED_TO            2010\r\n#define IDS_USBVIEW_INVALID_FILENAME    2011\r\n\r\n#define IDC_VERSION                     3000\r\n#define IDC_UVCVERSION                  3001\r\n\r\n#define ID_EXIT                         40001\r\n#define ID_REFRESH                      40002\r\n#define ID_AUTO_REFRESH                 40003\r\n#define ID_CONFIG_DESCRIPTORS           40004\r\n#define ID_ABOUT                        40005\r\n#define ID_ANNOTATION                   40007\r\n#define ID_UNUSED                       40008\r\n#define ID_LOG_DEBUG                    40009\r\n#define ID_SAVE                         40010\r\n#define ID_SAVEALL                      40011\r\n#define ID_SAVEXML                      40012\r\n#define IDC_STATIC                      0xFFFFFFFF\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/usbdesc.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    USBDESC.H\r\n\r\nAbstract:\r\n\r\n    This is a header file for USB descriptors which are not yet in\r\n    a standard system header file.\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    03-06-1998 : created\r\n    03-28-2003 : minor changes to support UVC and USB200\r\n\r\n--*/\r\n\r\n#pragma pack(push, 1)\r\n\r\n/*****************************************************************************\r\n D E F I N E S\r\n*****************************************************************************/\r\n\r\n//\r\n//Device Descriptor bDeviceClass values\r\n//\r\n#define USB_INTERFACE_CLASS_DEVICE      0x00\r\n#define USB_COMMUNICATION_DEVICE        0x02\r\n#define USB_HUB_DEVICE                  0x09\r\n#define USB_DEVICE_CLASS_BILLBOARD      0x11\r\n#define USB_DIAGNOSTIC_DEVICE           0xDC\r\n#define USB_WIRELESS_CONTROLLER_DEVICE  0xE0\r\n#define USB_MISCELLANEOUS_DEVICE        0xEF\r\n#define USB_VENDOR_SPECIFIC_DEVICE      0xFF\r\n\r\n//\r\n//Device Descriptor bDeviceSubClass values\r\n//\r\n#define USB_COMMON_SUB_CLASS            0x02\r\n\r\n//\r\n//Interface Descriptor bInterfaceClass values:\r\n//\r\n//#define USB_AUDIO_INTERFACE                0x01\r\n//#define USB_CDC_CONTROL_INTERFACE          0x02\r\n//#define USB_HID_INTERFACE                  0x03\r\n//#define USB_PHYSICAL_INTERFACE             0x05\r\n//#define USB_IMAGE_INTERFACE                0x06\r\n//#define USB_PRINTER_INTERFACE              0x07\r\n//#define USB_MASS_STORAGE_INTERFACE         0x08\r\n//#define USB_HUB_INTERFACE                  0x09\r\n#define USB_CDC_DATA_INTERFACE              0x0A\r\n#define USB_CHIP_SMART_CARD_INTERFACE       0x0B\r\n#define USB_CONTENT_SECURITY_INTERFACE      0x0D\r\n#define USB_DIAGNOSTIC_DEVICE_INTERFACE     0xDC\r\n#define USB_WIRELESS_CONTROLLER_INTERFACE   0xE0\r\n#define USB_APPLICATION_SPECIFIC_INTERFACE  0xFE\r\n//#define USB_VENDOR_SPECIFIC_INTERFACE      0xFF\r\n#define USB_HID_DESCRIPTOR_TYPE             0x21\r\n\r\n//\r\n//IAD protocol values\r\n//\r\n#define USB_IAD_PROTOCOL                    0x01\r\n\r\n//\r\n//Device class specific values\r\n//\r\n#define BILLBOARD_MAX_NUM_ALT_MODE  0x34\r\n\r\n//\r\n//USB 2.0 Specification Changes - New Descriptors\r\n//\r\n#define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE  0x07\r\n#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE            0x08\r\n#define USB_OTG_DESCRIPTOR_TYPE                        0x09\r\n#define USB_DEBUG_DESCRIPTOR_TYPE                      0x0A\r\n#define USB_IAD_DESCRIPTOR_TYPE                        0x0B\r\n\r\n//\r\n// USB Device Class Definition for Audio Devices\r\n// Appendix A.  Audio Device Class Codes\r\n//\r\n\r\n// A.2  Audio Interface Subclass Codes\r\n//\r\n#define USB_AUDIO_SUBCLASS_UNDEFINED        0x00\r\n#define USB_AUDIO_SUBCLASS_AUDIOCONTROL     0x01\r\n#define USB_AUDIO_SUBCLASS_AUDIOSTREAMING   0x02\r\n#define USB_AUDIO_SUBCLASS_MIDISTREAMING    0x03\r\n\r\n// A.4  Audio Class-Specific Descriptor Types\r\n//\r\n#define USB_AUDIO_CS_UNDEFINED              0x20\r\n#define USB_AUDIO_CS_DEVICE                 0x21\r\n#define USB_AUDIO_CS_CONFIGURATION          0x22\r\n#define USB_AUDIO_CS_STRING                 0x23\r\n#define USB_AUDIO_CS_INTERFACE              0x24\r\n#define USB_AUDIO_CS_ENDPOINT               0x25\r\n\r\n// A.5  Audio Class-Specific AC (Audio Control) Interface Descriptor Subtypes\r\n//\r\n#define USB_AUDIO_AC_UNDEFINED              0x00\r\n#define USB_AUDIO_AC_HEADER                 0x01\r\n#define USB_AUDIO_AC_INPUT_TERMINAL         0x02\r\n#define USB_AUDIO_AC_OUTPUT_TERMINAL        0x03\r\n#define USB_AUDIO_AC_MIXER_UNIT             0x04\r\n#define USB_AUDIO_AC_SELECTOR_UNIT          0x05\r\n#define USB_AUDIO_AC_FEATURE_UNIT           0x06\r\n#define USB_AUDIO_AC_PROCESSING_UNIT        0x07\r\n#define USB_AUDIO_AC_EXTENSION_UNIT         0x08\r\n\r\n// A.6  Audio Class-Specific AS (Audio Streaming) Interface Descriptor Subtypes\r\n//\r\n#define USB_AUDIO_AS_UNDEFINED              0x00\r\n#define USB_AUDIO_AS_GENERAL                0x01\r\n#define USB_AUDIO_AS_FORMAT_TYPE            0x02\r\n#define USB_AUDIO_AS_FORMAT_SPECIFIC        0x03\r\n\r\n// A.7 Processing Unit Process Types\r\n//\r\n#define USB_AUDIO_PROCESS_UNDEFINED         0x00\r\n#define USB_AUDIO_PROCESS_UPDOWNMIX         0x01\r\n#define USB_AUDIO_PROCESS_DOLBYPROLOGIC     0x02\r\n#define USB_AUDIO_PROCESS_3DSTEREOEXTENDER  0x03\r\n#define USB_AUDIO_PROCESS_REVERBERATION     0x04\r\n#define USB_AUDIO_PROCESS_CHORUS            0x05\r\n#define USB_AUDIO_PROCESS_DYNRANGECOMP      0x06\r\n\r\n\r\n/*****************************************************************************\r\n T Y P E D E F S\r\n*****************************************************************************/\r\n\r\n// HID Class HID Descriptor\r\n//\r\ntypedef struct _USB_HID_DESCRIPTOR\r\n{\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    USHORT  bcdHID;\r\n    UCHAR   bCountryCode;\r\n    UCHAR   bNumDescriptors;\r\n    struct\r\n    {\r\n        UCHAR   bDescriptorType;\r\n        USHORT  wDescriptorLength;\r\n    } OptionalDescriptors[1];\r\n} USB_HID_DESCRIPTOR, *PUSB_HID_DESCRIPTOR;\r\n\r\n\r\n// OTG Descriptor\r\n//\r\ntypedef struct _USB_OTG_DESCRIPTOR\r\n{\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bmAttributes;\r\n} USB_OTG_DESCRIPTOR, *PUSB_OTG_DESCRIPTOR;\r\n\r\n// IAD Descriptor\r\n//\r\ntypedef struct _USB_IAD_DESCRIPTOR\r\n{\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bFirstInterface;\r\n    UCHAR   bInterfaceCount;\r\n    UCHAR   bFunctionClass;\r\n    UCHAR   bFunctionSubClass;\r\n    UCHAR   bFunctionProtocol;\r\n    UCHAR   iFunction;\r\n} USB_IAD_DESCRIPTOR, *PUSB_IAD_DESCRIPTOR;\r\n\r\n\r\n// Common Class Endpoint Descriptor\r\n//\r\ntypedef struct _USB_ENDPOINT_DESCRIPTOR2 {\r\n    UCHAR  bLength;             // offset 0, size 1\r\n    UCHAR  bDescriptorType;     // offset 1, size 1\r\n    UCHAR  bEndpointAddress;    // offset 2, size 1\r\n    UCHAR  bmAttributes;        // offset 3, size 1\r\n    USHORT wMaxPacketSize;      // offset 4, size 2\r\n    USHORT wInterval;           // offset 6, size 2\r\n    UCHAR  bSyncAddress;        // offset 8, size 1\r\n} USB_ENDPOINT_DESCRIPTOR2, *PUSB_ENDPOINT_DESCRIPTOR2;\r\n\r\n// Common Class Interface Descriptor\r\n//\r\ntypedef struct _USB_INTERFACE_DESCRIPTOR2 {\r\n    UCHAR  bLength;             // offset 0, size 1\r\n    UCHAR  bDescriptorType;     // offset 1, size 1\r\n    UCHAR  bInterfaceNumber;    // offset 2, size 1\r\n    UCHAR  bAlternateSetting;   // offset 3, size 1\r\n    UCHAR  bNumEndpoints;       // offset 4, size 1\r\n    UCHAR  bInterfaceClass;     // offset 5, size 1\r\n    UCHAR  bInterfaceSubClass;  // offset 6, size 1\r\n    UCHAR  bInterfaceProtocol;  // offset 7, size 1\r\n    UCHAR  iInterface;          // offset 8, size 1\r\n    USHORT wNumClasses;         // offset 9, size 2\r\n} USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2;\r\n\r\n\r\n//\r\n// USB Device Class Definition for Audio Devices\r\n//\r\n\r\ntypedef struct _USB_AUDIO_COMMON_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n} USB_AUDIO_COMMON_DESCRIPTOR,\r\n*PUSB_AUDIO_COMMON_DESCRIPTOR;\r\n\r\n// 4.3.2 Class-Specific AC (Audio Control) Interface Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    USHORT bcdADC;\r\n    USHORT wTotalLength;\r\n    UCHAR  bInCollection;\r\n    UCHAR  baInterfaceNr[1];\r\n} USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR,\r\n*PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR;\r\n\r\n// 4.3.2.1 Input Terminal Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bTerminalID;\r\n    USHORT wTerminalType;\r\n    UCHAR  bAssocTerminal;\r\n    UCHAR  bNrChannels;\r\n    USHORT wChannelConfig;\r\n    UCHAR  iChannelNames;\r\n    UCHAR  iTerminal;\r\n} USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR,\r\n*PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR;\r\n\r\n// 4.3.2.2 Output Terminal Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bTerminalID;\r\n    USHORT wTerminalType;\r\n    UCHAR  bAssocTerminal;\r\n    UCHAR  bSourceID;\r\n    UCHAR  iTerminal;\r\n} USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR,\r\n*PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR;\r\n\r\n// 4.3.2.3 Mixer Unit Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_MIXER_UNIT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bUnitID;\r\n    UCHAR  bNrInPins;\r\n    UCHAR  baSourceID[1];\r\n} USB_AUDIO_MIXER_UNIT_DESCRIPTOR,\r\n*PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR;\r\n\r\n// 4.3.2.4 Selector Unit Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bUnitID;\r\n    UCHAR  bNrInPins;\r\n    UCHAR  baSourceID[1];\r\n} USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR,\r\n*PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR;\r\n\r\n// 4.3.2.5 Feature Unit Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_FEATURE_UNIT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bUnitID;\r\n    UCHAR  bSourceID;\r\n    UCHAR  bControlSize;\r\n    UCHAR  bmaControls[1];\r\n} USB_AUDIO_FEATURE_UNIT_DESCRIPTOR,\r\n*PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR;\r\n\r\n// 4.3.2.6 Processing Unit Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bUnitID;\r\n    USHORT wProcessType;\r\n    UCHAR  bNrInPins;\r\n    UCHAR  baSourceID[1];\r\n} USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR,\r\n*PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR;\r\n\r\n// 4.3.2.7 Extension Unit Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bUnitID;\r\n    USHORT wExtensionCode;\r\n    UCHAR  bNrInPins;\r\n    UCHAR  baSourceID[1];\r\n} USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR,\r\n*PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR;\r\n\r\n// 4.5.2 Class-Specific AS Interface Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_GENERAL_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bTerminalLink;\r\n    UCHAR  bDelay;\r\n    USHORT wFormatTag;\r\n} USB_AUDIO_GENERAL_DESCRIPTOR,\r\n*PUSB_AUDIO_GENERAL_DESCRIPTOR;\r\n\r\n// 4.6.1.2 Class-Specific AS Endpoint Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_ENDPOINT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bmAttributes;\r\n    UCHAR  bLockDelayUnits;\r\n    USHORT wLockDelay;\r\n} USB_AUDIO_ENDPOINT_DESCRIPTOR,\r\n*PUSB_AUDIO_ENDPOINT_DESCRIPTOR;\r\n\r\n//\r\n// USB Device Class Definition for Audio Data Formats\r\n//\r\n\r\ntypedef struct _USB_AUDIO_COMMON_FORMAT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bFormatType;\r\n} USB_AUDIO_COMMON_FORMAT_DESCRIPTOR,\r\n*PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR;\r\n\r\n\r\n// 2.1.5 Type I   Format Type Descriptor\r\n// 2.3.1 Type III Format Type Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bFormatType;\r\n    UCHAR  bNrChannels;\r\n    UCHAR  bSubframeSize;\r\n    UCHAR  bBitResolution;\r\n    UCHAR  bSamFreqType;\r\n} USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR,\r\n*PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR;\r\n\r\n\r\n// 2.2.6 Type II  Format Type Descriptor\r\n//\r\ntypedef struct _USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bFormatType;\r\n    USHORT wMaxBitRate;\r\n    USHORT wSamplesPerFrame;\r\n    UCHAR  bSamFreqType;\r\n} USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR,\r\n*PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR;\r\n\r\n#pragma pack(pop)\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/usbschema.hpp",
    "content": "﻿//\n// This file is auto-generated from XSD using the command:\n// xsd.exe /language:CPP /c /order /namespace:Microsoft.Kits.Samples.Usb\n//\n\n#pragma once\n\n#using <mscorlib.dll>\n#using <System.dll>\n#using <System.Xml.dll>\n\nusing namespace System::Security::Permissions;\n// \n// This source code was auto-generated by xsd, Version=4.0.30319.0.\n// \nnamespace Microsoft {\n    namespace Kits {\n        namespace Samples {\n            namespace Usb {\n    using namespace System::Xml::Serialization;\n    using namespace System;\n    ref class UvcViewAll;\n    ref class UvcViewType;\n    ref class MachineInfoType;\n    ref class NoDeviceType;\n    ref class PortConnectorType;\n    ref class UsbPortPropertiesType;\n    ref class NodeConnectionInfoExV2Type;\n    ref class UsbBillboardSVIDType;\n    ref class UsbBillboardCapabilityDescriptorType;\n    ref class UsbDispContIdCapExtDescriptorType;\n    ref class UsbUsb20ExtensionDescriptorType;\n    ref class UsbSuperSpeedExtensionDescriptorType;\n    ref class UsbBosDescriptorType;\n    ref class UsbDeviceUnknownDescriptorType;\n    ref class UsbDeviceIADDescriptorType;\n    ref class UsbDeviceClassType;\n    ref class UsbDeviceOTGDescriptorType;\n    ref class UsbDeviceHidOptionalDescriptorsType;\n    ref class UsbDeviceHidDescriptorType;\n    ref class UsbDeviceInterfaceDescriptorType;\n    ref class UsbDeviceQualifierDescriptorType;\n    ref class UsbConfigurationDescriptorType;\n    ref class UsbDeviceConfigurationType;\n    ref class EndpointDescriptorType;\n    ref class UsbDeviceType;\n    ref class NodeConnectionInfoExType;\n    ref class NodeConnectionInfoExStructType;\n    ref class UsbDeviceDescriptorType;\n    ref class UsbPipeInfoType;\n    ref class UsbDeviceClassDetailsType;\n    ref class ExternalHubType;\n    ref class HubNodeInformationType;\n    ref class HubInformationType;\n    ref class HubDescriptorType;\n    ref class HubCharacteristicsType;\n    ref class HubInformationExType;\n    ref class Hub30DescriptorType;\n    ref class HubCapabilitiesExType;\n    ref class RootHubType;\n    ref class UsbHCPowerStateType;\n    ref class UsbHCPowerStateMappingType;\n    ref class UsbHCDeviceInfoType;\n    ref class HostControllerType;\n    \n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public enum class UsbConnectionSpeedType {\n        \n        /// <remarks/>\n        Low,\n        \n        /// <remarks/>\n        Full,\n        \n        /// <remarks/>\n        High,\n        \n        /// <remarks/>\n        Super,\n        \n        /// <remarks/>\n        Unknown,\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public enum class UsbConnectionStatusType {\n        \n        /// <remarks/>\n        NoDeviceConnected,\n        \n        /// <remarks/>\n        DeviceConnected,\n        \n        /// <remarks/>\n        DeviceFailedEnumeration,\n        \n        /// <remarks/>\n        DeviceGeneralFailure,\n        \n        /// <remarks/>\n        DeviceCausedOvercurrent,\n        \n        /// <remarks/>\n        DeviceNotEnoughPower,\n        \n        /// <remarks/>\n        DeviceNotEnoughBandwidth,\n        \n        /// <remarks/>\n        DeviceHubNestedTooDeeply,\n        \n        /// <remarks/>\n        DeviceInLegacyHub,\n        \n        /// <remarks/>\n        DeviceEnumerating,\n        \n        /// <remarks/>\n        DeviceReset,\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public enum class DevicePowerStateType {\n        \n        /// <remarks/>\n        PowerDeviceUnspecified,\n        \n        /// <remarks/>\n        PowerDeviceD0,\n        \n        /// <remarks/>\n        PowerDeviceD1,\n        \n        /// <remarks/>\n        PowerDeviceD2,\n        \n        /// <remarks/>\n        PowerDeviceD3,\n        \n        /// <remarks/>\n        PowerDeviceMaximum,\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public enum class HubNodeType {\n        \n        /// <remarks/>\n        UsbHub,\n        \n        /// <remarks/>\n        UsbMiParent,\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public enum class HubTypeType {\n\n        /// <remarks/>\n        UnknownHubType,\n        \n        /// <remarks/>\n        UsbRootHub,\n        \n        /// <remarks/>\n        Usb20Hub,\n        \n        /// <remarks/>\n        Usb30Hub,\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(AnonymousType=true, Namespace=L\"USB\"), \n    System::Xml::Serialization::XmlRootAttribute(Namespace=L\"USB\", IsNullable=false)]\n    public ref class UvcViewAll {\n        \n        private: Microsoft::Kits::Samples::Usb::UvcViewType^  uvcViewField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::UvcViewType^  UvcView {\n            Microsoft::Kits::Samples::Usb::UvcViewType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UvcViewType^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UvcViewType {\n        \n        private: Microsoft::Kits::Samples::Usb::MachineInfoType^  machineInfoField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  usbTreeField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::MachineInfoType^  MachineInfo {\n            Microsoft::Kits::Samples::Usb::MachineInfoType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::MachineInfoType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlArrayAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1), \n        System::Xml::Serialization::XmlArrayItemAttribute(L\"UsbController\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, IsNullable=false)]\n        property cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  UsbTree {\n            cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class MachineInfoType {\n        \n        private: System::Byte uvcMajorVersionField;\n        \n        private: System::Byte uvcMinorVersionField;\n        \n        private: System::Byte uvcMajorSpecVersionField;\n        \n        private: System::Byte uvcMinorSpecVersionField;\n        \n        private: System::DateTime collectionTimeField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::Byte UvcMajorVersion {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::Byte UvcMinorVersion {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::Byte UvcMajorSpecVersion {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::Byte UvcMinorSpecVersion {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::DateTime CollectionTime {\n            System::DateTime get();\n            System::Void set(System::DateTime value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class NoDeviceType {\n        \n        private: Microsoft::Kits::Samples::Usb::PortConnectorType^  portConnectorField;\n        \n        private: System::String^  usbPortNumberField;\n        \n        private: System::String^  nameField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::PortConnectorType^  PortConnector {\n            Microsoft::Kits::Samples::Usb::PortConnectorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbPortNumber {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  Name {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class PortConnectorType {\n        \n        private: System::UInt64 connectionIndexField;\n        \n        private: System::UInt64 actualLengthField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  usbPortPropertiesField;\n        \n        private: System::UInt16 companionIndexField;\n        \n        private: System::UInt16 companionPortNumberField;\n        \n        private: System::String^  companionHubSymbolicLinkNameField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::UInt64 ConnectionIndex {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::UInt64 ActualLength {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  UsbPortProperties {\n            Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::UInt16 CompanionIndex {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::UInt16 CompanionPortNumber {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::String^  CompanionHubSymbolicLinkName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbPortPropertiesType {\n        \n        private: System::Boolean portIsUserConnectableField;\n        \n        private: System::Boolean portIsDebugCapableField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::Boolean PortIsUserConnectable {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::Boolean PortIsDebugCapable {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class NodeConnectionInfoExV2Type {\n        \n        private: System::UInt64 connectionIndexField;\n        \n        private: System::UInt64 lengthField;\n        \n        private: System::Boolean usb110SupportedField;\n        \n        private: System::Boolean usb200SupportedField;\n        \n        private: System::Boolean usb300SupportedField;\n        \n        private: System::Boolean deviceIsOperatingAtSuperSpeedOrHigherField;\n        \n        private: System::Boolean deviceIsSuperSpeedCapableOrHigherField;\n        \n        private: System::Boolean deviceIsOperatingAtSuperSpeedPlusOrHigherField;\n        \n        private: System::Boolean deviceIsSuperSpeedPlusCapableOrHigherField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::UInt64 ConnectionIndex {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::UInt64 Length {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::Boolean Usb110Supported {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::Boolean Usb200Supported {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::Boolean Usb300Supported {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::Boolean DeviceIsOperatingAtSuperSpeedOrHigher {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::Boolean DeviceIsSuperSpeedCapableOrHigher {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)]\n        property System::Boolean DeviceIsOperatingAtSuperSpeedPlusOrHigher {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property System::Boolean DeviceIsSuperSpeedPlusCapableOrHigher {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbBillboardSVIDType {\n        \n        private: System::String^  descriptionField;\n        \n        private: System::String^  alternateModeStringField;\n        \n        private: System::UInt16 wSVIDField;\n        \n        private: System::Byte bAlternateModeField;\n        \n        private: System::Byte iAlternateModeStringField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  Description {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  AlternateModeString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WSVID {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BAlternateMode {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IAlternateModeString {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbBillboardCapabilityDescriptorType {\n        \n        private: System::String^  vConnPowerField;\n        \n        private: System::String^  billboardDescriptorErrorsField;\n        \n        private: System::String^  addtionalInfoURLField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  usbBillboardSVIDField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bDevCapabilityTypeField;\n        \n        private: System::Byte iAddtionalInfoURLField;\n        \n        private: System::Byte bNumberOfAlternateModesField;\n        \n        private: System::Byte bPreferredAlternateModeField;\n        \n        private: System::Byte calculatedBLengthField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  VConnPower {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  BillboardDescriptorErrors {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  AddtionalInfoURL {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbBillboardSVID\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=3)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  UsbBillboardSVID {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDevCapabilityType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IAddtionalInfoURL {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BNumberOfAlternateModes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BPreferredAlternateMode {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte CalculatedBLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDispContIdCapExtDescriptorType {\n        \n        private: System::String^  reservedBitErrorField;\n        \n        private: System::String^  containerIdStrField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bReservedField;\n        \n        private: System::Byte bDevCapabilityTypeField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  ReservedBitError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  ContainerIdStr {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BReserved {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDevCapabilityType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbUsb20ExtensionDescriptorType {\n        \n        private: System::String^  reservedBitErrorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bDevCapabilityTypeField;\n        \n        private: System::UInt64 bmAttributesField;\n        \n        private: System::Boolean supportsLinkPowerManagementField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  ReservedBitError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDevCapabilityType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt64 BmAttributes {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean SupportsLinkPowerManagement {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbSuperSpeedExtensionDescriptorType {\n        \n        private: System::String^  reservedAttributesBitErrorField;\n        \n        private: System::String^  reservedSpeedBitErrorField;\n        \n        private: System::String^  reservedSpeedErrorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bDevCapabilityTypeField;\n        \n        private: System::UInt64 bmAttributesField;\n        \n        private: System::Boolean latencyToleranceMsgCapableField;\n        \n        private: System::Byte bFunctionalitySupportField;\n        \n        private: System::Byte bU1DevExitLatField;\n        \n        private: System::UInt16 wSpeedsSupportedField;\n        \n        private: System::UInt16 wU2DevExitLatField;\n        \n        private: System::Boolean supportsLowSpeedField;\n        \n        private: System::Boolean supportsFullSpeedField;\n        \n        private: System::Boolean supportsHighSpeedField;\n        \n        private: System::Boolean supportsSuperSpeedField;\n        \n        private: System::String^  lowestSpeedField;\n        \n        private: System::String^  u1DevExitLatencyStringField;\n        \n        private: System::String^  u2DevExitLatencyStringField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  ReservedAttributesBitError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  ReservedSpeedBitError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  ReservedSpeedError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDevCapabilityType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt64 BmAttributes {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean LatencyToleranceMsgCapable {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BFunctionalitySupport {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BU1DevExitLat {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WSpeedsSupported {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WU2DevExitLat {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean SupportsLowSpeed {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean SupportsFullSpeed {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean SupportsHighSpeed {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean SupportsSuperSpeed {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  LowestSpeed {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  U1DevExitLatencyString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  U2DevExitLatencyString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbBosDescriptorType {\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  unknownDescriptorField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  usbSuperSpeedExtensionDescriptorField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  usbUsb20ExtensionDescriptorField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  usbDispContIdCapExtDescriptorField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  usbBillboardCapabilityDescriptorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::UInt16 wTotalLengthField;\n        \n        private: System::Byte bNumDeviceCapsField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UnknownDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=0)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  UnknownDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbSuperSpeedExtensionDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=1)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  UsbSuperSpeedExtensionDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbUsb20ExtensionDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=2)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  UsbUsb20ExtensionDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbDispContIdCapExtDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=3)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  UsbDispContIdCapExtDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbBillboardCapabilityDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=4)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  UsbBillboardCapabilityDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WTotalLength {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BNumDeviceCaps {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceUnknownDescriptorType {\n        \n        private: System::String^  unknownDescriptorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  UnknownDescriptor {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceIADDescriptorType {\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  functionDetailsField;\n        \n        private: System::String^  interfaceErrorField;\n        \n        private: System::String^  functionClassErrorField;\n        \n        private: System::String^  protocolField;\n        \n        private: System::String^  stringDescField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bFirstInterfaceField;\n        \n        private: System::Byte bInterfaceCountField;\n        \n        private: System::Byte bFunctionClassField;\n        \n        private: System::Byte bFunctionSubclassField;\n        \n        private: System::Byte bFunctionProtocolField;\n        \n        private: System::Byte iFunctionField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  FunctionDetails {\n            Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  InterfaceError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  FunctionClassError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::String^  Protocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  StringDesc {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BFirstInterface {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BInterfaceCount {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BFunctionClass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BFunctionSubclass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BFunctionProtocol {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IFunction {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceClassType {\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::String^  deviceSubclassField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  DeviceSubclass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceOTGDescriptorType {\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bmAttributesField;\n        \n        private: System::String^  attributesStringField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BmAttributes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  AttributesString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceHidOptionalDescriptorsType {\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::UInt16 wDescriptorLengthField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WDescriptorLength {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceHidDescriptorType {\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  optionalDescriptorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::UInt16 bcdHIDField;\n        \n        private: System::Byte bCountryCodeField;\n        \n        private: System::Byte bNumDescriptorsField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"OptionalDescriptor\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=0)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  OptionalDescriptor {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 BcdHID {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BCountryCode {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BNumDescriptors {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceInterfaceDescriptorType {\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  interfaceDetailsField;\n        \n        private: System::String^  protocolErrorField;\n        \n        private: System::String^  stringDescField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::Byte bInterfaceNumberField;\n        \n        private: System::Byte bAlternateSettingField;\n        \n        private: System::Byte bNumEndpointsField;\n        \n        private: System::Byte bInterfaceClassField;\n        \n        private: System::Byte bInterfaceSubclassField;\n        \n        private: System::Byte bInterfaceProtocolField;\n        \n        private: System::Byte iInterfaceField;\n        \n        private: System::UInt16 wNumClassesField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  InterfaceDetails {\n            Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  ProtocolError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  StringDesc {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BInterfaceNumber {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BAlternateSetting {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BNumEndpoints {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BInterfaceClass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BInterfaceSubclass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BInterfaceProtocol {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IInterface {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WNumClasses {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceQualifierDescriptorType {\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::Byte maxPacketSizeInBytesField;\n        \n        private: System::Boolean maxPacketSizeInBytesFieldSpecified;\n        \n        private: System::String^  deviceClassErrorField;\n        \n        private: System::String^  deviceSubclassErrorField;\n        \n        private: System::String^  deviceProtocolErrorField;\n        \n        private: System::String^  deviceNumConfigErrorField;\n        \n        private: System::String^  reservedErrorField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::UInt16 bcdUSBField;\n        \n        private: System::Byte bDeviceClassField;\n        \n        private: System::Byte bDeviceSubclassField;\n        \n        private: System::Byte bDeviceProtocolField;\n        \n        private: System::Byte bMaxPacketSize0Field;\n        \n        private: System::Byte numConfigurationsField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::Byte MaxPacketSizeInBytes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlIgnoreAttribute]\n        property System::Boolean MaxPacketSizeInBytesSpecified {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  DeviceClassError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::String^  DeviceSubclassError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  DeviceProtocolError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::String^  DeviceNumConfigError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::String^  ReservedError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 BcdUSB {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDeviceClass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDeviceSubclass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDeviceProtocol {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BMaxPacketSize0 {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte NumConfigurations {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbConfigurationDescriptorType {\n        \n        private: System::String^  configDescErrorField;\n        \n        private: System::String^  confValueErrorField;\n        \n        private: System::String^  confStringDescField;\n        \n        private: System::String^  attributesStrField;\n        \n        private: System::String^  maxCurrentField;\n        \n        private: System::Byte bLengthField;\n        \n        private: System::Byte bDescriptorTypeField;\n        \n        private: System::UInt16 wTotalLengthField;\n        \n        private: System::Byte bNumInterfacesField;\n        \n        private: System::Byte bConfigurationValueField;\n        \n        private: System::Byte iConfigurationField;\n        \n        private: System::Byte bmAttributesField;\n        \n        private: System::Byte maxPowerField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  ConfigDescError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  ConfValueError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  ConfStringDesc {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::String^  AttributesStr {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  MaxCurrent {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BDescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WTotalLength {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BNumInterfaces {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BConfigurationValue {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IConfiguration {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte BmAttributes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte MaxPower {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceConfigurationType {\n        \n        private: System::String^  deviceQualifierErrorField;\n        \n        private: System::String^  speedConfigurationErrorField;\n        \n        private: System::String^  deviceConfigurationErrorField;\n        \n        private: System::String^  interfaceErrorField;\n        \n        private: System::String^  preReleaseErrorField;\n        \n        private: System::String^  endpointErrorField;\n        \n        private: System::String^  hidErrorField;\n        \n        private: System::String^  otgErrorField;\n        \n        private: System::String^  iadErrorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  deviceDetailsField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  configurationDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  deviceQualifierDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  interfaceDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  endpointDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  hidDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  otgDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  iadDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  unknownDescriptorField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  DeviceQualifierError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  SpeedConfigurationError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  DeviceConfigurationError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::String^  InterfaceError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  PreReleaseError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::String^  EndpointError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::String^  HidError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)]\n        property System::String^  OtgError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property System::String^  IadError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  DeviceDetails {\n            Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)]\n        property Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  ConfigurationDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  DeviceQualifierDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=12)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  InterfaceDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=13)]\n        property Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  EndpointDescriptor {\n            Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=14)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  HidDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=15)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  OtgDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=16)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  IadDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=17)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  UnknownDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class EndpointDescriptorType {\n        \n        private: System::Byte lengthField;\n        \n        private: System::Byte descriptorTypeField;\n        \n        private: System::Byte endpointAddressField;\n        \n        private: System::Byte attributesField;\n        \n        private: System::UInt16 maxPacketSizeField;\n        \n        private: System::Byte intervalField;\n        \n        private: System::UInt16 wIntervalField;\n        \n        private: System::Byte syncAddressField;\n        \n        private: System::String^  endpointDirectionField;\n        \n        private: System::Byte endpointIdField;\n        \n        private: System::String^  endpointTypeField;\n        \n        private: System::String^  endpointPacketInfoField;\n        \n        private: System::String^  endpointPacketSizeValidationField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte Length {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte EndpointAddress {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte Attributes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 MaxPacketSize {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte Interval {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 WInterval {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte SyncAddress {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  EndpointDirection {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte EndpointId {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  EndpointType {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  EndpointPacketInfo {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  EndpointPacketSizeValidation {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceType {\n        \n        private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  connectionInfoField;\n        \n        private: Microsoft::Kits::Samples::Usb::PortConnectorType^  portConnectorField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  deviceConfigurationField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  bosDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  connectionInfoV2Field;\n        \n        private: System::String^  usbPortNumberField;\n        \n        private: System::String^  serviceNameField;\n        \n        private: System::String^  hwIdField;\n        \n        private: System::String^  deviceIdField;\n        \n        private: System::String^  deviceNameField;\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::String^  usbProtocolField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  ConnectionInfo {\n            Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property Microsoft::Kits::Samples::Usb::PortConnectorType^  PortConnector {\n            Microsoft::Kits::Samples::Usb::PortConnectorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"DeviceConfiguration\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=2)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  DeviceConfiguration {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  BosDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  ConnectionInfoV2 {\n            Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbPortNumber {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  ServiceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HwId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbProtocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class NodeConnectionInfoExType {\n        \n        private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  connectionInfoStructField;\n        \n        private: System::String^  iProductStringDescEnField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  deviceClassDetailsField;\n        \n        private: System::Byte maxPacketSizeInBytesField;\n        \n        private: System::String^  vendorStringField;\n        \n        private: System::String^  manufacturerStringField;\n        \n        private: System::String^  productStringField;\n        \n        private: System::String^  langIdStringField;\n        \n        private: System::String^  serialStringField;\n        \n        private: System::String^  pipeInfoErrorField;\n        \n        private: System::String^  lengthErrorField;\n        \n        private: System::String^  deviceErrorField;\n        \n        private: System::String^  packetSizeErrorField;\n        \n        private: System::String^  configurationCountErrorField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  ConnectionInfoStruct {\n            Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  IProductStringDescEn {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  DeviceClassDetails {\n            Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::Byte MaxPacketSizeInBytes {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  VendorString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::String^  ManufacturerString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::String^  ProductString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)]\n        property System::String^  LangIdString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property System::String^  SerialString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)]\n        property System::String^  PipeInfoError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)]\n        property System::String^  LengthError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)]\n        property System::String^  DeviceError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=12)]\n        property System::String^  PacketSizeError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=13)]\n        property System::String^  ConfigurationCountError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class NodeConnectionInfoExStructType {\n        \n        private: System::UInt64 connectionIndexField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  deviceDescriptorField;\n        \n        private: System::Byte currentConfigurationValueField;\n        \n        private: System::Byte speedField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType speedStrField;\n        \n        private: System::Boolean deviceIsHubField;\n        \n        private: System::Byte deviceAddressField;\n        \n        private: System::UInt64 numOfOpenPipesField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbConnectionStatusType usbConnectionStatusField;\n        \n        private: Microsoft::Kits::Samples::Usb::DevicePowerStateType devicePowerStateField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  pipeField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::UInt64 ConnectionIndex {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  DeviceDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::Byte CurrentConfigurationValue {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::Byte Speed {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType SpeedStr {\n            Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::Boolean DeviceIsHub {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::Byte DeviceAddress {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)]\n        property System::UInt64 NumOfOpenPipes {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property Microsoft::Kits::Samples::Usb::UsbConnectionStatusType UsbConnectionStatus {\n            Microsoft::Kits::Samples::Usb::UsbConnectionStatusType get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbConnectionStatusType value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)]\n        property Microsoft::Kits::Samples::Usb::DevicePowerStateType DevicePowerState {\n            Microsoft::Kits::Samples::Usb::DevicePowerStateType get();\n            System::Void set(Microsoft::Kits::Samples::Usb::DevicePowerStateType value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"Pipe\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  Pipe {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceDescriptorType {\n        \n        private: System::Byte lengthField;\n        \n        private: System::Byte descriptorTypeField;\n        \n        private: System::UInt16 cdUSBField;\n        \n        private: System::Byte deviceClassField;\n        \n        private: System::Byte deviceSubclassField;\n        \n        private: System::Byte deviceProtocolField;\n        \n        private: System::Byte maxPacketSize0Field;\n        \n        private: System::UInt16 idVendorField;\n        \n        private: System::UInt16 idProductField;\n        \n        private: System::UInt16 cdDeviceField;\n        \n        private: System::Byte iManufacturerField;\n        \n        private: System::Byte iProductField;\n        \n        private: System::Byte iSerialNumberField;\n        \n        private: System::Byte numConfigurationsField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte Length {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 CdUSB {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DeviceClass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DeviceSubclass {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DeviceProtocol {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte MaxPacketSize0 {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 IdVendor {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 IdProduct {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 CdDevice {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IManufacturer {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte IProduct {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte ISerialNumber {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte NumConfigurations {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbPipeInfoType {\n        \n        private: Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  endpointDescriptorField;\n        \n        private: System::UInt64 scheduleOffsetField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  EndpointDescriptor {\n            Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::UInt64 ScheduleOffset {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbDeviceClassDetailsType {\n        \n        private: System::String^  deviceTypeField;\n        \n        private: System::String^  deviceTypeErrorField;\n        \n        private: System::String^  subclassTypeField;\n        \n        private: System::String^  subclassTypeErrorField;\n        \n        private: System::String^  deviceProtocolField;\n        \n        private: System::String^  deviceProtocolErrorField;\n        \n        private: System::UInt32 uvcVersionField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::String^  DeviceType {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  DeviceTypeError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  SubclassType {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::String^  SubclassTypeError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::String^  DeviceProtocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::String^  DeviceProtocolError {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::UInt32 UvcVersion {\n            System::UInt32 get();\n            System::Void set(System::UInt32 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class ExternalHubType {\n        \n        private: Microsoft::Kits::Samples::Usb::HubNodeInformationType^  hubNodeInformationField;\n        \n        private: System::String^  hubNameField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubInformationExType^  hubInformationExField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  hubCapabilityExField;\n        \n        private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  connectionInfoField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  usbDeviceField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  noDeviceField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  deviceConfigurationField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  bosDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  connectionInfoV2Field;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  externalHubField;\n        \n        private: Microsoft::Kits::Samples::Usb::PortConnectorType^  portConnectorField;\n        \n        private: System::String^  serviceNameField;\n        \n        private: System::String^  hwIdField;\n        \n        private: System::String^  deviceIdField;\n        \n        private: System::String^  deviceNameField;\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::String^  usbProtocolField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::HubNodeInformationType^  HubNodeInformation {\n            Microsoft::Kits::Samples::Usb::HubNodeInformationType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  HubName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::HubInformationExType^  HubInformationEx {\n            Microsoft::Kits::Samples::Usb::HubInformationExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubInformationExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  HubCapabilityEx {\n            Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  ConnectionInfo {\n            Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbDevice\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=5)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  UsbDevice {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"NoDevice\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  NoDevice {\n            cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"DeviceConfiguration\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=7)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  DeviceConfiguration {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  BosDescriptor {\n            Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)]\n        property Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  ConnectionInfoV2 {\n            Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"ExternalHub\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=10)]\n        property cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  ExternalHub {\n            cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)]\n        property Microsoft::Kits::Samples::Usb::PortConnectorType^  PortConnector {\n            Microsoft::Kits::Samples::Usb::PortConnectorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  ServiceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HwId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbProtocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubNodeInformationType {\n        \n        private: Microsoft::Kits::Samples::Usb::HubNodeType hubNodeField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubInformationType^  hubInformationField;\n        \n        private: System::UInt64 miParentNumberOfInterfacesField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::HubNodeType HubNode {\n            Microsoft::Kits::Samples::Usb::HubNodeType get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubNodeType value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property Microsoft::Kits::Samples::Usb::HubInformationType^  HubInformation {\n            Microsoft::Kits::Samples::Usb::HubInformationType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubInformationType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::UInt64 MiParentNumberOfInterfaces {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubInformationType {\n        \n        private: System::Boolean isRootHubField;\n        \n        private: System::Boolean isBusPoweredField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubDescriptorType^  hubDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  hubCharacteristicsField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::Boolean IsRootHub {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::Boolean IsBusPowered {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::HubDescriptorType^  HubDescriptor {\n            Microsoft::Kits::Samples::Usb::HubDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  HubCharacteristics {\n            Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubDescriptorType {\n        \n        private: System::Byte descriptorLengthField;\n        \n        private: System::Byte descriptorTypeField;\n        \n        private: System::Byte numberOfPortsField;\n        \n        private: System::Byte powerOntoPowerGoodField;\n        \n        private: System::Byte hubControlCurrentField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DescriptorLength {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte NumberOfPorts {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte PowerOntoPowerGood {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte HubControlCurrent {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubCharacteristicsType {\n        \n        private: System::UInt32 hubCharacteristicsValueField;\n        \n        private: System::String^  powerSwitchingField;\n        \n        private: System::Boolean compoundDeviceField;\n        \n        private: System::String^  overCurrentProtectionField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt32 HubCharacteristicsValue {\n            System::UInt32 get();\n            System::Void set(System::UInt32 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  PowerSwitching {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean CompoundDevice {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  OverCurrentProtection {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubInformationExType {\n        \n        private: Microsoft::Kits::Samples::Usb::HubTypeType hubTypeField;\n        \n        private: System::UInt16 highestPortNumberField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubDescriptorType^  hubDescriptorField;\n        \n        private: Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  hub30DescriptorField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::HubTypeType HubType {\n            Microsoft::Kits::Samples::Usb::HubTypeType get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubTypeType value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::UInt16 HighestPortNumber {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::HubDescriptorType^  HubDescriptor {\n            Microsoft::Kits::Samples::Usb::HubDescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubDescriptorType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  Hub30Descriptor {\n            Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class Hub30DescriptorType {\n        \n        private: System::Byte lengthField;\n        \n        private: System::Byte descriptorTypeField;\n        \n        private: System::Byte numberOfPortsField;\n        \n        private: System::UInt16 hubCharacteristicsField;\n        \n        private: System::Byte powerOntoPowerGoodField;\n        \n        private: System::Byte hubControlCurrentField;\n        \n        private: System::Byte hubHdrDecLatField;\n        \n        private: System::UInt16 hubDelayField;\n        \n        private: System::UInt16 deviceRemovableField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte Length {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte DescriptorType {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte NumberOfPorts {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 HubCharacteristics {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte PowerOntoPowerGood {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte HubControlCurrent {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Byte HubHdrDecLat {\n            System::Byte get();\n            System::Void set(System::Byte value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 HubDelay {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::UInt16 DeviceRemovable {\n            System::UInt16 get();\n            System::Void set(System::UInt16 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HubCapabilitiesExType {\n        \n        private: System::Boolean hubIsHighSpeedCapableField;\n        \n        private: System::Boolean hubIsHighSpeedField;\n        \n        private: System::Boolean hubIsMultiTtCapableField;\n        \n        private: System::Boolean hubIsMultiTtField;\n        \n        private: System::Boolean hubIsRootField;\n        \n        private: System::Boolean hubIsArmedWakeOnConnectField;\n        \n        private: System::Boolean hubIsBusPoweredField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsHighSpeedCapable {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsHighSpeed {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsMultiTtCapable {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsMultiTt {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsRoot {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsArmedWakeOnConnect {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean HubIsBusPowered {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class RootHubType {\n        \n        private: Microsoft::Kits::Samples::Usb::HubNodeInformationType^  hubNodeInformationField;\n        \n        private: System::String^  hubNameField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubInformationExType^  hubInformationExField;\n        \n        private: Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  hubCapabilityExField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  externalHubField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  usbDeviceField;\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  noDeviceField;\n        \n        private: System::String^  serviceNameField;\n        \n        private: System::String^  hwIdField;\n        \n        private: System::String^  deviceIdField;\n        \n        private: System::String^  deviceNameField;\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::String^  usbProtocolField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::HubNodeInformationType^  HubNodeInformation {\n            Microsoft::Kits::Samples::Usb::HubNodeInformationType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  HubName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::HubInformationExType^  HubInformationEx {\n            Microsoft::Kits::Samples::Usb::HubInformationExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubInformationExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  HubCapabilityEx {\n            Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"ExternalHub\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=4)]\n        property cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  ExternalHub {\n            cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"UsbDevice\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, \n        Order=5)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  UsbDevice {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"NoDevice\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  NoDevice {\n            cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  ServiceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HwId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbProtocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbHCPowerStateType {\n        \n        private: System::String^  systemStateField;\n        \n        private: System::String^  hostControllerStateField;\n        \n        private: System::String^  hubStateField;\n        \n        private: System::Boolean canWakeUpField;\n        \n        private: System::Boolean isPoweredField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  SystemState {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HostControllerState {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HubState {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean CanWakeUp {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::Boolean IsPowered {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbHCPowerStateMappingType {\n        \n        private: cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  powerMapField;\n        \n        private: System::String^  lastSleepStateField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(L\"PowerMap\", Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  PowerMap {\n            cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  get();\n            System::Void set(cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::String^  LastSleepState {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class UsbHCDeviceInfoType {\n        \n        private: System::Int64 vendorIdField;\n        \n        private: System::Int64 deviceIdField;\n        \n        private: System::String^  driverKeyField;\n        \n        private: System::Int64 subSysIdField;\n        \n        private: System::Int64 revisionField;\n        \n        private: System::UInt64 debugPortField;\n        \n        private: System::UInt64 numberOfRootPortsField;\n        \n        private: System::UInt64 controllerFlavorField;\n        \n        private: System::String^  controllerFlavorStringField;\n        \n        private: System::Boolean portSwitchingEnabledField;\n        \n        private: System::Boolean selectiveSuspendEnabledField;\n        \n        private: System::UInt64 legacyBiosField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property System::Int64 VendorId {\n            System::Int64 get();\n            System::Void set(System::Int64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property System::Int64 DeviceId {\n            System::Int64 get();\n            System::Void set(System::Int64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property System::String^  DriverKey {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=3)]\n        property System::Int64 SubSysId {\n            System::Int64 get();\n            System::Void set(System::Int64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=4)]\n        property System::Int64 Revision {\n            System::Int64 get();\n            System::Void set(System::Int64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=5)]\n        property System::UInt64 DebugPort {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=6)]\n        property System::UInt64 NumberOfRootPorts {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=7)]\n        property System::UInt64 ControllerFlavor {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=8)]\n        property System::String^  ControllerFlavorString {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=9)]\n        property System::Boolean PortSwitchingEnabled {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=10)]\n        property System::Boolean SelectiveSuspendEnabled {\n            System::Boolean get();\n            System::Void set(System::Boolean value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=11)]\n        property System::UInt64 LegacyBios {\n            System::UInt64 get();\n            System::Void set(System::UInt64 value);\n        }\n    };\n    \n    /// <remarks/>\n    [System::CodeDom::Compiler::GeneratedCodeAttribute(L\"xsd\", L\"4.6.24.0\"), \n    System::SerializableAttribute, \n    System::Diagnostics::DebuggerStepThroughAttribute, \n    System::ComponentModel::DesignerCategoryAttribute(L\"code\"), \n    System::Xml::Serialization::XmlTypeAttribute(Namespace=L\"USB\")]\n    public ref class HostControllerType {\n        \n        private: Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  controllerInfoField;\n        \n        private: Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  powerMappingField;\n        \n        private: Microsoft::Kits::Samples::Usb::RootHubType^  rootHubField;\n        \n        private: System::String^  serviceNameField;\n        \n        private: System::String^  hwIdField;\n        \n        private: System::String^  deviceIdField;\n        \n        private: System::String^  deviceNameField;\n        \n        private: System::String^  deviceClassField;\n        \n        private: System::String^  usbProtocolField;\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=0)]\n        property Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  ControllerInfo {\n            Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=1)]\n        property Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  PowerMapping {\n            Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlElementAttribute(Form=System::Xml::Schema::XmlSchemaForm::Unqualified, Order=2)]\n        property Microsoft::Kits::Samples::Usb::RootHubType^  RootHub {\n            Microsoft::Kits::Samples::Usb::RootHubType^  get();\n            System::Void set(Microsoft::Kits::Samples::Usb::RootHubType^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  ServiceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  HwId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceId {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceName {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  DeviceClass {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n        \n        /// <remarks/>\n        public: [System::Xml::Serialization::XmlAttributeAttribute]\n        property System::String^  UsbProtocol {\n            System::String^  get();\n            System::Void set(System::String^  value);\n        }\n    };\n            }\n        }\n    }\n}\nnamespace Microsoft {\n    namespace Kits {\n        namespace Samples {\n            namespace Usb {\n    \n    \n    \n    \n    \n    \n    \n    inline Microsoft::Kits::Samples::Usb::UvcViewType^  UvcViewAll::UvcView::get() {\n        return this->uvcViewField;\n    }\n    inline System::Void UvcViewAll::UvcView::set(Microsoft::Kits::Samples::Usb::UvcViewType^  value) {\n        this->uvcViewField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::MachineInfoType^  UvcViewType::MachineInfo::get() {\n        return this->machineInfoField;\n    }\n    inline System::Void UvcViewType::MachineInfo::set(Microsoft::Kits::Samples::Usb::MachineInfoType^  value) {\n        this->machineInfoField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  UvcViewType::UsbTree::get() {\n        return this->usbTreeField;\n    }\n    inline System::Void UvcViewType::UsbTree::set(cli::array< Microsoft::Kits::Samples::Usb::HostControllerType^  >^  value) {\n        this->usbTreeField = value;\n    }\n    \n    \n    inline System::Byte MachineInfoType::UvcMajorVersion::get() {\n        return this->uvcMajorVersionField;\n    }\n    inline System::Void MachineInfoType::UvcMajorVersion::set(System::Byte value) {\n        this->uvcMajorVersionField = value;\n    }\n    \n    inline System::Byte MachineInfoType::UvcMinorVersion::get() {\n        return this->uvcMinorVersionField;\n    }\n    inline System::Void MachineInfoType::UvcMinorVersion::set(System::Byte value) {\n        this->uvcMinorVersionField = value;\n    }\n    \n    inline System::Byte MachineInfoType::UvcMajorSpecVersion::get() {\n        return this->uvcMajorSpecVersionField;\n    }\n    inline System::Void MachineInfoType::UvcMajorSpecVersion::set(System::Byte value) {\n        this->uvcMajorSpecVersionField = value;\n    }\n    \n    inline System::Byte MachineInfoType::UvcMinorSpecVersion::get() {\n        return this->uvcMinorSpecVersionField;\n    }\n    inline System::Void MachineInfoType::UvcMinorSpecVersion::set(System::Byte value) {\n        this->uvcMinorSpecVersionField = value;\n    }\n    \n    inline System::DateTime MachineInfoType::CollectionTime::get() {\n        return this->collectionTimeField;\n    }\n    inline System::Void MachineInfoType::CollectionTime::set(System::DateTime value) {\n        this->collectionTimeField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::PortConnectorType^  NoDeviceType::PortConnector::get() {\n        return this->portConnectorField;\n    }\n    inline System::Void NoDeviceType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value) {\n        this->portConnectorField = value;\n    }\n    \n    inline System::String^  NoDeviceType::UsbPortNumber::get() {\n        return this->usbPortNumberField;\n    }\n    inline System::Void NoDeviceType::UsbPortNumber::set(System::String^  value) {\n        this->usbPortNumberField = value;\n    }\n    \n    inline System::String^  NoDeviceType::Name::get() {\n        return this->nameField;\n    }\n    inline System::Void NoDeviceType::Name::set(System::String^  value) {\n        this->nameField = value;\n    }\n    \n    \n    inline System::UInt64 PortConnectorType::ConnectionIndex::get() {\n        return this->connectionIndexField;\n    }\n    inline System::Void PortConnectorType::ConnectionIndex::set(System::UInt64 value) {\n        this->connectionIndexField = value;\n    }\n    \n    inline System::UInt64 PortConnectorType::ActualLength::get() {\n        return this->actualLengthField;\n    }\n    inline System::Void PortConnectorType::ActualLength::set(System::UInt64 value) {\n        this->actualLengthField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  PortConnectorType::UsbPortProperties::get() {\n        return this->usbPortPropertiesField;\n    }\n    inline System::Void PortConnectorType::UsbPortProperties::set(Microsoft::Kits::Samples::Usb::UsbPortPropertiesType^  value) {\n        this->usbPortPropertiesField = value;\n    }\n    \n    inline System::UInt16 PortConnectorType::CompanionIndex::get() {\n        return this->companionIndexField;\n    }\n    inline System::Void PortConnectorType::CompanionIndex::set(System::UInt16 value) {\n        this->companionIndexField = value;\n    }\n    \n    inline System::UInt16 PortConnectorType::CompanionPortNumber::get() {\n        return this->companionPortNumberField;\n    }\n    inline System::Void PortConnectorType::CompanionPortNumber::set(System::UInt16 value) {\n        this->companionPortNumberField = value;\n    }\n    \n    inline System::String^  PortConnectorType::CompanionHubSymbolicLinkName::get() {\n        return this->companionHubSymbolicLinkNameField;\n    }\n    inline System::Void PortConnectorType::CompanionHubSymbolicLinkName::set(System::String^  value) {\n        this->companionHubSymbolicLinkNameField = value;\n    }\n    \n    \n    inline System::Boolean UsbPortPropertiesType::PortIsUserConnectable::get() {\n        return this->portIsUserConnectableField;\n    }\n    inline System::Void UsbPortPropertiesType::PortIsUserConnectable::set(System::Boolean value) {\n        this->portIsUserConnectableField = value;\n    }\n    \n    inline System::Boolean UsbPortPropertiesType::PortIsDebugCapable::get() {\n        return this->portIsDebugCapableField;\n    }\n    inline System::Void UsbPortPropertiesType::PortIsDebugCapable::set(System::Boolean value) {\n        this->portIsDebugCapableField = value;\n    }\n    \n    \n    inline System::UInt64 NodeConnectionInfoExV2Type::ConnectionIndex::get() {\n        return this->connectionIndexField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::ConnectionIndex::set(System::UInt64 value) {\n        this->connectionIndexField = value;\n    }\n    \n    inline System::UInt64 NodeConnectionInfoExV2Type::Length::get() {\n        return this->lengthField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::Length::set(System::UInt64 value) {\n        this->lengthField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::Usb110Supported::get() {\n        return this->usb110SupportedField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::Usb110Supported::set(System::Boolean value) {\n        this->usb110SupportedField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::Usb200Supported::get() {\n        return this->usb200SupportedField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::Usb200Supported::set(System::Boolean value) {\n        this->usb200SupportedField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::Usb300Supported::get() {\n        return this->usb300SupportedField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::Usb300Supported::set(System::Boolean value) {\n        this->usb300SupportedField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedOrHigher::get() {\n        return this->deviceIsOperatingAtSuperSpeedOrHigherField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedOrHigher::set(System::Boolean value) {\n        this->deviceIsOperatingAtSuperSpeedOrHigherField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsSuperSpeedCapableOrHigher::get() {\n        return this->deviceIsSuperSpeedCapableOrHigherField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::DeviceIsSuperSpeedCapableOrHigher::set(System::Boolean value) {\n        this->deviceIsSuperSpeedCapableOrHigherField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedPlusOrHigher::get() {\n        return this->deviceIsOperatingAtSuperSpeedPlusOrHigherField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::DeviceIsOperatingAtSuperSpeedPlusOrHigher::set(System::Boolean value) {\n        this->deviceIsOperatingAtSuperSpeedPlusOrHigherField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExV2Type::DeviceIsSuperSpeedPlusCapableOrHigher::get() {\n        return this->deviceIsSuperSpeedPlusCapableOrHigherField;\n    }\n    inline System::Void NodeConnectionInfoExV2Type::DeviceIsSuperSpeedPlusCapableOrHigher::set(System::Boolean value) {\n        this->deviceIsSuperSpeedPlusCapableOrHigherField = value;\n    }\n    \n    \n    inline System::String^  UsbBillboardSVIDType::Description::get() {\n        return this->descriptionField;\n    }\n    inline System::Void UsbBillboardSVIDType::Description::set(System::String^  value) {\n        this->descriptionField = value;\n    }\n    \n    inline System::String^  UsbBillboardSVIDType::AlternateModeString::get() {\n        return this->alternateModeStringField;\n    }\n    inline System::Void UsbBillboardSVIDType::AlternateModeString::set(System::String^  value) {\n        this->alternateModeStringField = value;\n    }\n    \n    inline System::UInt16 UsbBillboardSVIDType::WSVID::get() {\n        return this->wSVIDField;\n    }\n    inline System::Void UsbBillboardSVIDType::WSVID::set(System::UInt16 value) {\n        this->wSVIDField = value;\n    }\n    \n    inline System::Byte UsbBillboardSVIDType::BAlternateMode::get() {\n        return this->bAlternateModeField;\n    }\n    inline System::Void UsbBillboardSVIDType::BAlternateMode::set(System::Byte value) {\n        this->bAlternateModeField = value;\n    }\n    \n    inline System::Byte UsbBillboardSVIDType::IAlternateModeString::get() {\n        return this->iAlternateModeStringField;\n    }\n    inline System::Void UsbBillboardSVIDType::IAlternateModeString::set(System::Byte value) {\n        this->iAlternateModeStringField = value;\n    }\n    \n    \n    inline System::String^  UsbBillboardCapabilityDescriptorType::VConnPower::get() {\n        return this->vConnPowerField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::VConnPower::set(System::String^  value) {\n        this->vConnPowerField = value;\n    }\n    \n    inline System::String^  UsbBillboardCapabilityDescriptorType::BillboardDescriptorErrors::get() {\n        return this->billboardDescriptorErrorsField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BillboardDescriptorErrors::set(System::String^  value) {\n        this->billboardDescriptorErrorsField = value;\n    }\n    \n    inline System::String^  UsbBillboardCapabilityDescriptorType::AddtionalInfoURL::get() {\n        return this->addtionalInfoURLField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::AddtionalInfoURL::set(System::String^  value) {\n        this->addtionalInfoURLField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  UsbBillboardCapabilityDescriptorType::UsbBillboardSVID::get() {\n        return this->usbBillboardSVIDField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::UsbBillboardSVID::set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardSVIDType^  >^  value) {\n        this->usbBillboardSVIDField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::BDevCapabilityType::get() {\n        return this->bDevCapabilityTypeField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BDevCapabilityType::set(System::Byte value) {\n        this->bDevCapabilityTypeField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::IAddtionalInfoURL::get() {\n        return this->iAddtionalInfoURLField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::IAddtionalInfoURL::set(System::Byte value) {\n        this->iAddtionalInfoURLField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::BNumberOfAlternateModes::get() {\n        return this->bNumberOfAlternateModesField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BNumberOfAlternateModes::set(System::Byte value) {\n        this->bNumberOfAlternateModesField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::BPreferredAlternateMode::get() {\n        return this->bPreferredAlternateModeField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::BPreferredAlternateMode::set(System::Byte value) {\n        this->bPreferredAlternateModeField = value;\n    }\n    \n    inline System::Byte UsbBillboardCapabilityDescriptorType::CalculatedBLength::get() {\n        return this->calculatedBLengthField;\n    }\n    inline System::Void UsbBillboardCapabilityDescriptorType::CalculatedBLength::set(System::Byte value) {\n        this->calculatedBLengthField = value;\n    }\n    \n    \n    inline System::String^  UsbDispContIdCapExtDescriptorType::ReservedBitError::get() {\n        return this->reservedBitErrorField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::ReservedBitError::set(System::String^  value) {\n        this->reservedBitErrorField = value;\n    }\n    \n    inline System::String^  UsbDispContIdCapExtDescriptorType::ContainerIdStr::get() {\n        return this->containerIdStrField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::ContainerIdStr::set(System::String^  value) {\n        this->containerIdStrField = value;\n    }\n    \n    inline System::Byte UsbDispContIdCapExtDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDispContIdCapExtDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbDispContIdCapExtDescriptorType::BReserved::get() {\n        return this->bReservedField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::BReserved::set(System::Byte value) {\n        this->bReservedField = value;\n    }\n    \n    inline System::Byte UsbDispContIdCapExtDescriptorType::BDevCapabilityType::get() {\n        return this->bDevCapabilityTypeField;\n    }\n    inline System::Void UsbDispContIdCapExtDescriptorType::BDevCapabilityType::set(System::Byte value) {\n        this->bDevCapabilityTypeField = value;\n    }\n    \n    \n    inline System::String^  UsbUsb20ExtensionDescriptorType::ReservedBitError::get() {\n        return this->reservedBitErrorField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::ReservedBitError::set(System::String^  value) {\n        this->reservedBitErrorField = value;\n    }\n    \n    inline System::Byte UsbUsb20ExtensionDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbUsb20ExtensionDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbUsb20ExtensionDescriptorType::BDevCapabilityType::get() {\n        return this->bDevCapabilityTypeField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::BDevCapabilityType::set(System::Byte value) {\n        this->bDevCapabilityTypeField = value;\n    }\n    \n    inline System::UInt64 UsbUsb20ExtensionDescriptorType::BmAttributes::get() {\n        return this->bmAttributesField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::BmAttributes::set(System::UInt64 value) {\n        this->bmAttributesField = value;\n    }\n    \n    inline System::Boolean UsbUsb20ExtensionDescriptorType::SupportsLinkPowerManagement::get() {\n        return this->supportsLinkPowerManagementField;\n    }\n    inline System::Void UsbUsb20ExtensionDescriptorType::SupportsLinkPowerManagement::set(System::Boolean value) {\n        this->supportsLinkPowerManagementField = value;\n    }\n    \n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::ReservedAttributesBitError::get() {\n        return this->reservedAttributesBitErrorField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedAttributesBitError::set(System::String^  value) {\n        this->reservedAttributesBitErrorField = value;\n    }\n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::ReservedSpeedBitError::get() {\n        return this->reservedSpeedBitErrorField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedSpeedBitError::set(System::String^  value) {\n        this->reservedSpeedBitErrorField = value;\n    }\n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::ReservedSpeedError::get() {\n        return this->reservedSpeedErrorField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::ReservedSpeedError::set(System::String^  value) {\n        this->reservedSpeedErrorField = value;\n    }\n    \n    inline System::Byte UsbSuperSpeedExtensionDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbSuperSpeedExtensionDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbSuperSpeedExtensionDescriptorType::BDevCapabilityType::get() {\n        return this->bDevCapabilityTypeField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BDevCapabilityType::set(System::Byte value) {\n        this->bDevCapabilityTypeField = value;\n    }\n    \n    inline System::UInt64 UsbSuperSpeedExtensionDescriptorType::BmAttributes::get() {\n        return this->bmAttributesField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BmAttributes::set(System::UInt64 value) {\n        this->bmAttributesField = value;\n    }\n    \n    inline System::Boolean UsbSuperSpeedExtensionDescriptorType::LatencyToleranceMsgCapable::get() {\n        return this->latencyToleranceMsgCapableField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::LatencyToleranceMsgCapable::set(System::Boolean value) {\n        this->latencyToleranceMsgCapableField = value;\n    }\n    \n    inline System::Byte UsbSuperSpeedExtensionDescriptorType::BFunctionalitySupport::get() {\n        return this->bFunctionalitySupportField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BFunctionalitySupport::set(System::Byte value) {\n        this->bFunctionalitySupportField = value;\n    }\n    \n    inline System::Byte UsbSuperSpeedExtensionDescriptorType::BU1DevExitLat::get() {\n        return this->bU1DevExitLatField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::BU1DevExitLat::set(System::Byte value) {\n        this->bU1DevExitLatField = value;\n    }\n    \n    inline System::UInt16 UsbSuperSpeedExtensionDescriptorType::WSpeedsSupported::get() {\n        return this->wSpeedsSupportedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::WSpeedsSupported::set(System::UInt16 value) {\n        this->wSpeedsSupportedField = value;\n    }\n    \n    inline System::UInt16 UsbSuperSpeedExtensionDescriptorType::WU2DevExitLat::get() {\n        return this->wU2DevExitLatField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::WU2DevExitLat::set(System::UInt16 value) {\n        this->wU2DevExitLatField = value;\n    }\n    \n    inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsLowSpeed::get() {\n        return this->supportsLowSpeedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsLowSpeed::set(System::Boolean value) {\n        this->supportsLowSpeedField = value;\n    }\n    \n    inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsFullSpeed::get() {\n        return this->supportsFullSpeedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsFullSpeed::set(System::Boolean value) {\n        this->supportsFullSpeedField = value;\n    }\n    \n    inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsHighSpeed::get() {\n        return this->supportsHighSpeedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsHighSpeed::set(System::Boolean value) {\n        this->supportsHighSpeedField = value;\n    }\n    \n    inline System::Boolean UsbSuperSpeedExtensionDescriptorType::SupportsSuperSpeed::get() {\n        return this->supportsSuperSpeedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::SupportsSuperSpeed::set(System::Boolean value) {\n        this->supportsSuperSpeedField = value;\n    }\n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::LowestSpeed::get() {\n        return this->lowestSpeedField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::LowestSpeed::set(System::String^  value) {\n        this->lowestSpeedField = value;\n    }\n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::U1DevExitLatencyString::get() {\n        return this->u1DevExitLatencyStringField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::U1DevExitLatencyString::set(System::String^  value) {\n        this->u1DevExitLatencyStringField = value;\n    }\n    \n    inline System::String^  UsbSuperSpeedExtensionDescriptorType::U2DevExitLatencyString::get() {\n        return this->u2DevExitLatencyStringField;\n    }\n    inline System::Void UsbSuperSpeedExtensionDescriptorType::U2DevExitLatencyString::set(System::String^  value) {\n        this->u2DevExitLatencyStringField = value;\n    }\n    \n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  UsbBosDescriptorType::UnknownDescriptor::get() {\n        return this->unknownDescriptorField;\n    }\n    inline System::Void UsbBosDescriptorType::UnknownDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  >^  value) {\n        this->unknownDescriptorField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  UsbBosDescriptorType::UsbSuperSpeedExtensionDescriptor::get() {\n        return this->usbSuperSpeedExtensionDescriptorField;\n    }\n    inline System::Void UsbBosDescriptorType::UsbSuperSpeedExtensionDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbSuperSpeedExtensionDescriptorType^  >^  value) {\n        this->usbSuperSpeedExtensionDescriptorField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  UsbBosDescriptorType::UsbUsb20ExtensionDescriptor::get() {\n        return this->usbUsb20ExtensionDescriptorField;\n    }\n    inline System::Void UsbBosDescriptorType::UsbUsb20ExtensionDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbUsb20ExtensionDescriptorType^  >^  value) {\n        this->usbUsb20ExtensionDescriptorField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  UsbBosDescriptorType::UsbDispContIdCapExtDescriptor::get() {\n        return this->usbDispContIdCapExtDescriptorField;\n    }\n    inline System::Void UsbBosDescriptorType::UsbDispContIdCapExtDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDispContIdCapExtDescriptorType^  >^  value) {\n        this->usbDispContIdCapExtDescriptorField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  UsbBosDescriptorType::UsbBillboardCapabilityDescriptor::get() {\n        return this->usbBillboardCapabilityDescriptorField;\n    }\n    inline System::Void UsbBosDescriptorType::UsbBillboardCapabilityDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbBillboardCapabilityDescriptorType^  >^  value) {\n        this->usbBillboardCapabilityDescriptorField = value;\n    }\n    \n    inline System::Byte UsbBosDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbBosDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbBosDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbBosDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbBosDescriptorType::WTotalLength::get() {\n        return this->wTotalLengthField;\n    }\n    inline System::Void UsbBosDescriptorType::WTotalLength::set(System::UInt16 value) {\n        this->wTotalLengthField = value;\n    }\n    \n    inline System::Byte UsbBosDescriptorType::BNumDeviceCaps::get() {\n        return this->bNumDeviceCapsField;\n    }\n    inline System::Void UsbBosDescriptorType::BNumDeviceCaps::set(System::Byte value) {\n        this->bNumDeviceCapsField = value;\n    }\n    \n    \n    inline System::String^  UsbDeviceUnknownDescriptorType::UnknownDescriptor::get() {\n        return this->unknownDescriptorField;\n    }\n    inline System::Void UsbDeviceUnknownDescriptorType::UnknownDescriptor::set(System::String^  value) {\n        this->unknownDescriptorField = value;\n    }\n    \n    inline System::Byte UsbDeviceUnknownDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceUnknownDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceUnknownDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceUnknownDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  UsbDeviceIADDescriptorType::FunctionDetails::get() {\n        return this->functionDetailsField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::FunctionDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value) {\n        this->functionDetailsField = value;\n    }\n    \n    inline System::String^  UsbDeviceIADDescriptorType::InterfaceError::get() {\n        return this->interfaceErrorField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::InterfaceError::set(System::String^  value) {\n        this->interfaceErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceIADDescriptorType::FunctionClassError::get() {\n        return this->functionClassErrorField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::FunctionClassError::set(System::String^  value) {\n        this->functionClassErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceIADDescriptorType::Protocol::get() {\n        return this->protocolField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::Protocol::set(System::String^  value) {\n        this->protocolField = value;\n    }\n    \n    inline System::String^  UsbDeviceIADDescriptorType::StringDesc::get() {\n        return this->stringDescField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::StringDesc::set(System::String^  value) {\n        this->stringDescField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BFirstInterface::get() {\n        return this->bFirstInterfaceField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BFirstInterface::set(System::Byte value) {\n        this->bFirstInterfaceField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BInterfaceCount::get() {\n        return this->bInterfaceCountField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BInterfaceCount::set(System::Byte value) {\n        this->bInterfaceCountField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BFunctionClass::get() {\n        return this->bFunctionClassField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BFunctionClass::set(System::Byte value) {\n        this->bFunctionClassField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BFunctionSubclass::get() {\n        return this->bFunctionSubclassField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BFunctionSubclass::set(System::Byte value) {\n        this->bFunctionSubclassField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::BFunctionProtocol::get() {\n        return this->bFunctionProtocolField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::BFunctionProtocol::set(System::Byte value) {\n        this->bFunctionProtocolField = value;\n    }\n    \n    inline System::Byte UsbDeviceIADDescriptorType::IFunction::get() {\n        return this->iFunctionField;\n    }\n    inline System::Void UsbDeviceIADDescriptorType::IFunction::set(System::Byte value) {\n        this->iFunctionField = value;\n    }\n    \n    \n    inline System::String^  UsbDeviceClassType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void UsbDeviceClassType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassType::DeviceSubclass::get() {\n        return this->deviceSubclassField;\n    }\n    inline System::Void UsbDeviceClassType::DeviceSubclass::set(System::String^  value) {\n        this->deviceSubclassField = value;\n    }\n    \n    \n    inline System::Byte UsbDeviceOTGDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceOTGDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceOTGDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceOTGDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbDeviceOTGDescriptorType::BmAttributes::get() {\n        return this->bmAttributesField;\n    }\n    inline System::Void UsbDeviceOTGDescriptorType::BmAttributes::set(System::Byte value) {\n        this->bmAttributesField = value;\n    }\n    \n    inline System::String^  UsbDeviceOTGDescriptorType::AttributesString::get() {\n        return this->attributesStringField;\n    }\n    inline System::Void UsbDeviceOTGDescriptorType::AttributesString::set(System::String^  value) {\n        this->attributesStringField = value;\n    }\n    \n    \n    inline System::Byte UsbDeviceHidOptionalDescriptorsType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceHidOptionalDescriptorsType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceHidOptionalDescriptorsType::WDescriptorLength::get() {\n        return this->wDescriptorLengthField;\n    }\n    inline System::Void UsbDeviceHidOptionalDescriptorsType::WDescriptorLength::set(System::UInt16 value) {\n        this->wDescriptorLengthField = value;\n    }\n    \n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  UsbDeviceHidDescriptorType::OptionalDescriptor::get() {\n        return this->optionalDescriptorField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::OptionalDescriptor::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceHidOptionalDescriptorsType^  >^  value) {\n        this->optionalDescriptorField = value;\n    }\n    \n    inline System::Byte UsbDeviceHidDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceHidDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceHidDescriptorType::BcdHID::get() {\n        return this->bcdHIDField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::BcdHID::set(System::UInt16 value) {\n        this->bcdHIDField = value;\n    }\n    \n    inline System::Byte UsbDeviceHidDescriptorType::BCountryCode::get() {\n        return this->bCountryCodeField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::BCountryCode::set(System::Byte value) {\n        this->bCountryCodeField = value;\n    }\n    \n    inline System::Byte UsbDeviceHidDescriptorType::BNumDescriptors::get() {\n        return this->bNumDescriptorsField;\n    }\n    inline System::Void UsbDeviceHidDescriptorType::BNumDescriptors::set(System::Byte value) {\n        this->bNumDescriptorsField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  UsbDeviceInterfaceDescriptorType::InterfaceDetails::get() {\n        return this->interfaceDetailsField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::InterfaceDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value) {\n        this->interfaceDetailsField = value;\n    }\n    \n    inline System::String^  UsbDeviceInterfaceDescriptorType::ProtocolError::get() {\n        return this->protocolErrorField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::ProtocolError::set(System::String^  value) {\n        this->protocolErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceInterfaceDescriptorType::StringDesc::get() {\n        return this->stringDescField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::StringDesc::set(System::String^  value) {\n        this->stringDescField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceNumber::get() {\n        return this->bInterfaceNumberField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceNumber::set(System::Byte value) {\n        this->bInterfaceNumberField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BAlternateSetting::get() {\n        return this->bAlternateSettingField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BAlternateSetting::set(System::Byte value) {\n        this->bAlternateSettingField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BNumEndpoints::get() {\n        return this->bNumEndpointsField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BNumEndpoints::set(System::Byte value) {\n        this->bNumEndpointsField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceClass::get() {\n        return this->bInterfaceClassField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceClass::set(System::Byte value) {\n        this->bInterfaceClassField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceSubclass::get() {\n        return this->bInterfaceSubclassField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceSubclass::set(System::Byte value) {\n        this->bInterfaceSubclassField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::BInterfaceProtocol::get() {\n        return this->bInterfaceProtocolField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::BInterfaceProtocol::set(System::Byte value) {\n        this->bInterfaceProtocolField = value;\n    }\n    \n    inline System::Byte UsbDeviceInterfaceDescriptorType::IInterface::get() {\n        return this->iInterfaceField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::IInterface::set(System::Byte value) {\n        this->iInterfaceField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceInterfaceDescriptorType::WNumClasses::get() {\n        return this->wNumClassesField;\n    }\n    inline System::Void UsbDeviceInterfaceDescriptorType::WNumClasses::set(System::UInt16 value) {\n        this->wNumClassesField = value;\n    }\n    \n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytes::get() {\n        return this->maxPacketSizeInBytesField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytes::set(System::Byte value) {\n        this->maxPacketSizeInBytesField = value;\n    }\n    \n    inline System::Boolean UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytesSpecified::get() {\n        return this->maxPacketSizeInBytesFieldSpecified;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::MaxPacketSizeInBytesSpecified::set(System::Boolean value) {\n        this->maxPacketSizeInBytesFieldSpecified = value;\n    }\n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::DeviceClassError::get() {\n        return this->deviceClassErrorField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::DeviceClassError::set(System::String^  value) {\n        this->deviceClassErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::DeviceSubclassError::get() {\n        return this->deviceSubclassErrorField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::DeviceSubclassError::set(System::String^  value) {\n        this->deviceSubclassErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::DeviceProtocolError::get() {\n        return this->deviceProtocolErrorField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::DeviceProtocolError::set(System::String^  value) {\n        this->deviceProtocolErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::DeviceNumConfigError::get() {\n        return this->deviceNumConfigErrorField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::DeviceNumConfigError::set(System::String^  value) {\n        this->deviceNumConfigErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceQualifierDescriptorType::ReservedError::get() {\n        return this->reservedErrorField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::ReservedError::set(System::String^  value) {\n        this->reservedErrorField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceQualifierDescriptorType::BcdUSB::get() {\n        return this->bcdUSBField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BcdUSB::set(System::UInt16 value) {\n        this->bcdUSBField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceClass::get() {\n        return this->bDeviceClassField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BDeviceClass::set(System::Byte value) {\n        this->bDeviceClassField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceSubclass::get() {\n        return this->bDeviceSubclassField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BDeviceSubclass::set(System::Byte value) {\n        this->bDeviceSubclassField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BDeviceProtocol::get() {\n        return this->bDeviceProtocolField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BDeviceProtocol::set(System::Byte value) {\n        this->bDeviceProtocolField = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::BMaxPacketSize0::get() {\n        return this->bMaxPacketSize0Field;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::BMaxPacketSize0::set(System::Byte value) {\n        this->bMaxPacketSize0Field = value;\n    }\n    \n    inline System::Byte UsbDeviceQualifierDescriptorType::NumConfigurations::get() {\n        return this->numConfigurationsField;\n    }\n    inline System::Void UsbDeviceQualifierDescriptorType::NumConfigurations::set(System::Byte value) {\n        this->numConfigurationsField = value;\n    }\n    \n    \n    inline System::String^  UsbConfigurationDescriptorType::ConfigDescError::get() {\n        return this->configDescErrorField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::ConfigDescError::set(System::String^  value) {\n        this->configDescErrorField = value;\n    }\n    \n    inline System::String^  UsbConfigurationDescriptorType::ConfValueError::get() {\n        return this->confValueErrorField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::ConfValueError::set(System::String^  value) {\n        this->confValueErrorField = value;\n    }\n    \n    inline System::String^  UsbConfigurationDescriptorType::ConfStringDesc::get() {\n        return this->confStringDescField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::ConfStringDesc::set(System::String^  value) {\n        this->confStringDescField = value;\n    }\n    \n    inline System::String^  UsbConfigurationDescriptorType::AttributesStr::get() {\n        return this->attributesStrField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::AttributesStr::set(System::String^  value) {\n        this->attributesStrField = value;\n    }\n    \n    inline System::String^  UsbConfigurationDescriptorType::MaxCurrent::get() {\n        return this->maxCurrentField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::MaxCurrent::set(System::String^  value) {\n        this->maxCurrentField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::BLength::get() {\n        return this->bLengthField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::BLength::set(System::Byte value) {\n        this->bLengthField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::BDescriptorType::get() {\n        return this->bDescriptorTypeField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::BDescriptorType::set(System::Byte value) {\n        this->bDescriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbConfigurationDescriptorType::WTotalLength::get() {\n        return this->wTotalLengthField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::WTotalLength::set(System::UInt16 value) {\n        this->wTotalLengthField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::BNumInterfaces::get() {\n        return this->bNumInterfacesField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::BNumInterfaces::set(System::Byte value) {\n        this->bNumInterfacesField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::BConfigurationValue::get() {\n        return this->bConfigurationValueField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::BConfigurationValue::set(System::Byte value) {\n        this->bConfigurationValueField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::IConfiguration::get() {\n        return this->iConfigurationField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::IConfiguration::set(System::Byte value) {\n        this->iConfigurationField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::BmAttributes::get() {\n        return this->bmAttributesField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::BmAttributes::set(System::Byte value) {\n        this->bmAttributesField = value;\n    }\n    \n    inline System::Byte UsbConfigurationDescriptorType::MaxPower::get() {\n        return this->maxPowerField;\n    }\n    inline System::Void UsbConfigurationDescriptorType::MaxPower::set(System::Byte value) {\n        this->maxPowerField = value;\n    }\n    \n    \n    inline System::String^  UsbDeviceConfigurationType::DeviceQualifierError::get() {\n        return this->deviceQualifierErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::DeviceQualifierError::set(System::String^  value) {\n        this->deviceQualifierErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::SpeedConfigurationError::get() {\n        return this->speedConfigurationErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::SpeedConfigurationError::set(System::String^  value) {\n        this->speedConfigurationErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::DeviceConfigurationError::get() {\n        return this->deviceConfigurationErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::DeviceConfigurationError::set(System::String^  value) {\n        this->deviceConfigurationErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::InterfaceError::get() {\n        return this->interfaceErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::InterfaceError::set(System::String^  value) {\n        this->interfaceErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::PreReleaseError::get() {\n        return this->preReleaseErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::PreReleaseError::set(System::String^  value) {\n        this->preReleaseErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::EndpointError::get() {\n        return this->endpointErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::EndpointError::set(System::String^  value) {\n        this->endpointErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::HidError::get() {\n        return this->hidErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::HidError::set(System::String^  value) {\n        this->hidErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::OtgError::get() {\n        return this->otgErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::OtgError::set(System::String^  value) {\n        this->otgErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceConfigurationType::IadError::get() {\n        return this->iadErrorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::IadError::set(System::String^  value) {\n        this->iadErrorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  UsbDeviceConfigurationType::DeviceDetails::get() {\n        return this->deviceDetailsField;\n    }\n    inline System::Void UsbDeviceConfigurationType::DeviceDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassType^  value) {\n        this->deviceDetailsField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  UsbDeviceConfigurationType::ConfigurationDescriptor::get() {\n        return this->configurationDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::ConfigurationDescriptor::set(Microsoft::Kits::Samples::Usb::UsbConfigurationDescriptorType^  value) {\n        this->configurationDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  UsbDeviceConfigurationType::DeviceQualifierDescriptor::get() {\n        return this->deviceQualifierDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::DeviceQualifierDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceQualifierDescriptorType^  value) {\n        this->deviceQualifierDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  UsbDeviceConfigurationType::InterfaceDescriptor::get() {\n        return this->interfaceDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::InterfaceDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceInterfaceDescriptorType^  value) {\n        this->interfaceDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  UsbDeviceConfigurationType::EndpointDescriptor::get() {\n        return this->endpointDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::EndpointDescriptor::set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  value) {\n        this->endpointDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  UsbDeviceConfigurationType::HidDescriptor::get() {\n        return this->hidDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::HidDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceHidDescriptorType^  value) {\n        this->hidDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  UsbDeviceConfigurationType::OtgDescriptor::get() {\n        return this->otgDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::OtgDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceOTGDescriptorType^  value) {\n        this->otgDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  UsbDeviceConfigurationType::IadDescriptor::get() {\n        return this->iadDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::IadDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceIADDescriptorType^  value) {\n        this->iadDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  UsbDeviceConfigurationType::UnknownDescriptor::get() {\n        return this->unknownDescriptorField;\n    }\n    inline System::Void UsbDeviceConfigurationType::UnknownDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceUnknownDescriptorType^  value) {\n        this->unknownDescriptorField = value;\n    }\n    \n    \n    inline System::Byte EndpointDescriptorType::Length::get() {\n        return this->lengthField;\n    }\n    inline System::Void EndpointDescriptorType::Length::set(System::Byte value) {\n        this->lengthField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::DescriptorType::get() {\n        return this->descriptorTypeField;\n    }\n    inline System::Void EndpointDescriptorType::DescriptorType::set(System::Byte value) {\n        this->descriptorTypeField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::EndpointAddress::get() {\n        return this->endpointAddressField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointAddress::set(System::Byte value) {\n        this->endpointAddressField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::Attributes::get() {\n        return this->attributesField;\n    }\n    inline System::Void EndpointDescriptorType::Attributes::set(System::Byte value) {\n        this->attributesField = value;\n    }\n    \n    inline System::UInt16 EndpointDescriptorType::MaxPacketSize::get() {\n        return this->maxPacketSizeField;\n    }\n    inline System::Void EndpointDescriptorType::MaxPacketSize::set(System::UInt16 value) {\n        this->maxPacketSizeField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::Interval::get() {\n        return this->intervalField;\n    }\n    inline System::Void EndpointDescriptorType::Interval::set(System::Byte value) {\n        this->intervalField = value;\n    }\n    \n    inline System::UInt16 EndpointDescriptorType::WInterval::get() {\n        return this->wIntervalField;\n    }\n    inline System::Void EndpointDescriptorType::WInterval::set(System::UInt16 value) {\n        this->wIntervalField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::SyncAddress::get() {\n        return this->syncAddressField;\n    }\n    inline System::Void EndpointDescriptorType::SyncAddress::set(System::Byte value) {\n        this->syncAddressField = value;\n    }\n    \n    inline System::String^  EndpointDescriptorType::EndpointDirection::get() {\n        return this->endpointDirectionField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointDirection::set(System::String^  value) {\n        this->endpointDirectionField = value;\n    }\n    \n    inline System::Byte EndpointDescriptorType::EndpointId::get() {\n        return this->endpointIdField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointId::set(System::Byte value) {\n        this->endpointIdField = value;\n    }\n    \n    inline System::String^  EndpointDescriptorType::EndpointType::get() {\n        return this->endpointTypeField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointType::set(System::String^  value) {\n        this->endpointTypeField = value;\n    }\n    \n    inline System::String^  EndpointDescriptorType::EndpointPacketInfo::get() {\n        return this->endpointPacketInfoField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointPacketInfo::set(System::String^  value) {\n        this->endpointPacketInfoField = value;\n    }\n    \n    inline System::String^  EndpointDescriptorType::EndpointPacketSizeValidation::get() {\n        return this->endpointPacketSizeValidationField;\n    }\n    inline System::Void EndpointDescriptorType::EndpointPacketSizeValidation::set(System::String^  value) {\n        this->endpointPacketSizeValidationField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  UsbDeviceType::ConnectionInfo::get() {\n        return this->connectionInfoField;\n    }\n    inline System::Void UsbDeviceType::ConnectionInfo::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  value) {\n        this->connectionInfoField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::PortConnectorType^  UsbDeviceType::PortConnector::get() {\n        return this->portConnectorField;\n    }\n    inline System::Void UsbDeviceType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value) {\n        this->portConnectorField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  UsbDeviceType::DeviceConfiguration::get() {\n        return this->deviceConfigurationField;\n    }\n    inline System::Void UsbDeviceType::DeviceConfiguration::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  value) {\n        this->deviceConfigurationField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  UsbDeviceType::BosDescriptor::get() {\n        return this->bosDescriptorField;\n    }\n    inline System::Void UsbDeviceType::BosDescriptor::set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  value) {\n        this->bosDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  UsbDeviceType::ConnectionInfoV2::get() {\n        return this->connectionInfoV2Field;\n    }\n    inline System::Void UsbDeviceType::ConnectionInfoV2::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  value) {\n        this->connectionInfoV2Field = value;\n    }\n    \n    inline System::String^  UsbDeviceType::UsbPortNumber::get() {\n        return this->usbPortNumberField;\n    }\n    inline System::Void UsbDeviceType::UsbPortNumber::set(System::String^  value) {\n        this->usbPortNumberField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::ServiceName::get() {\n        return this->serviceNameField;\n    }\n    inline System::Void UsbDeviceType::ServiceName::set(System::String^  value) {\n        this->serviceNameField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::HwId::get() {\n        return this->hwIdField;\n    }\n    inline System::Void UsbDeviceType::HwId::set(System::String^  value) {\n        this->hwIdField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::DeviceId::get() {\n        return this->deviceIdField;\n    }\n    inline System::Void UsbDeviceType::DeviceId::set(System::String^  value) {\n        this->deviceIdField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::DeviceName::get() {\n        return this->deviceNameField;\n    }\n    inline System::Void UsbDeviceType::DeviceName::set(System::String^  value) {\n        this->deviceNameField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void UsbDeviceType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::String^  UsbDeviceType::UsbProtocol::get() {\n        return this->usbProtocolField;\n    }\n    inline System::Void UsbDeviceType::UsbProtocol::set(System::String^  value) {\n        this->usbProtocolField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  NodeConnectionInfoExType::ConnectionInfoStruct::get() {\n        return this->connectionInfoStructField;\n    }\n    inline System::Void NodeConnectionInfoExType::ConnectionInfoStruct::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExStructType^  value) {\n        this->connectionInfoStructField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::IProductStringDescEn::get() {\n        return this->iProductStringDescEnField;\n    }\n    inline System::Void NodeConnectionInfoExType::IProductStringDescEn::set(System::String^  value) {\n        this->iProductStringDescEnField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  NodeConnectionInfoExType::DeviceClassDetails::get() {\n        return this->deviceClassDetailsField;\n    }\n    inline System::Void NodeConnectionInfoExType::DeviceClassDetails::set(Microsoft::Kits::Samples::Usb::UsbDeviceClassDetailsType^  value) {\n        this->deviceClassDetailsField = value;\n    }\n    \n    inline System::Byte NodeConnectionInfoExType::MaxPacketSizeInBytes::get() {\n        return this->maxPacketSizeInBytesField;\n    }\n    inline System::Void NodeConnectionInfoExType::MaxPacketSizeInBytes::set(System::Byte value) {\n        this->maxPacketSizeInBytesField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::VendorString::get() {\n        return this->vendorStringField;\n    }\n    inline System::Void NodeConnectionInfoExType::VendorString::set(System::String^  value) {\n        this->vendorStringField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::ManufacturerString::get() {\n        return this->manufacturerStringField;\n    }\n    inline System::Void NodeConnectionInfoExType::ManufacturerString::set(System::String^  value) {\n        this->manufacturerStringField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::ProductString::get() {\n        return this->productStringField;\n    }\n    inline System::Void NodeConnectionInfoExType::ProductString::set(System::String^  value) {\n        this->productStringField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::LangIdString::get() {\n        return this->langIdStringField;\n    }\n    inline System::Void NodeConnectionInfoExType::LangIdString::set(System::String^  value) {\n        this->langIdStringField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::SerialString::get() {\n        return this->serialStringField;\n    }\n    inline System::Void NodeConnectionInfoExType::SerialString::set(System::String^  value) {\n        this->serialStringField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::PipeInfoError::get() {\n        return this->pipeInfoErrorField;\n    }\n    inline System::Void NodeConnectionInfoExType::PipeInfoError::set(System::String^  value) {\n        this->pipeInfoErrorField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::LengthError::get() {\n        return this->lengthErrorField;\n    }\n    inline System::Void NodeConnectionInfoExType::LengthError::set(System::String^  value) {\n        this->lengthErrorField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::DeviceError::get() {\n        return this->deviceErrorField;\n    }\n    inline System::Void NodeConnectionInfoExType::DeviceError::set(System::String^  value) {\n        this->deviceErrorField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::PacketSizeError::get() {\n        return this->packetSizeErrorField;\n    }\n    inline System::Void NodeConnectionInfoExType::PacketSizeError::set(System::String^  value) {\n        this->packetSizeErrorField = value;\n    }\n    \n    inline System::String^  NodeConnectionInfoExType::ConfigurationCountError::get() {\n        return this->configurationCountErrorField;\n    }\n    inline System::Void NodeConnectionInfoExType::ConfigurationCountError::set(System::String^  value) {\n        this->configurationCountErrorField = value;\n    }\n    \n    \n    inline System::UInt64 NodeConnectionInfoExStructType::ConnectionIndex::get() {\n        return this->connectionIndexField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::ConnectionIndex::set(System::UInt64 value) {\n        this->connectionIndexField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  NodeConnectionInfoExStructType::DeviceDescriptor::get() {\n        return this->deviceDescriptorField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::DeviceDescriptor::set(Microsoft::Kits::Samples::Usb::UsbDeviceDescriptorType^  value) {\n        this->deviceDescriptorField = value;\n    }\n    \n    inline System::Byte NodeConnectionInfoExStructType::CurrentConfigurationValue::get() {\n        return this->currentConfigurationValueField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::CurrentConfigurationValue::set(System::Byte value) {\n        this->currentConfigurationValueField = value;\n    }\n    \n    inline System::Byte NodeConnectionInfoExStructType::Speed::get() {\n        return this->speedField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::Speed::set(System::Byte value) {\n        this->speedField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType NodeConnectionInfoExStructType::SpeedStr::get() {\n        return this->speedStrField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::SpeedStr::set(Microsoft::Kits::Samples::Usb::UsbConnectionSpeedType value) {\n        this->speedStrField = value;\n    }\n    \n    inline System::Boolean NodeConnectionInfoExStructType::DeviceIsHub::get() {\n        return this->deviceIsHubField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::DeviceIsHub::set(System::Boolean value) {\n        this->deviceIsHubField = value;\n    }\n    \n    inline System::Byte NodeConnectionInfoExStructType::DeviceAddress::get() {\n        return this->deviceAddressField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::DeviceAddress::set(System::Byte value) {\n        this->deviceAddressField = value;\n    }\n    \n    inline System::UInt64 NodeConnectionInfoExStructType::NumOfOpenPipes::get() {\n        return this->numOfOpenPipesField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::NumOfOpenPipes::set(System::UInt64 value) {\n        this->numOfOpenPipesField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbConnectionStatusType NodeConnectionInfoExStructType::UsbConnectionStatus::get() {\n        return this->usbConnectionStatusField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::UsbConnectionStatus::set(Microsoft::Kits::Samples::Usb::UsbConnectionStatusType value) {\n        this->usbConnectionStatusField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::DevicePowerStateType NodeConnectionInfoExStructType::DevicePowerState::get() {\n        return this->devicePowerStateField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::DevicePowerState::set(Microsoft::Kits::Samples::Usb::DevicePowerStateType value) {\n        this->devicePowerStateField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  NodeConnectionInfoExStructType::Pipe::get() {\n        return this->pipeField;\n    }\n    inline System::Void NodeConnectionInfoExStructType::Pipe::set(cli::array< Microsoft::Kits::Samples::Usb::UsbPipeInfoType^  >^  value) {\n        this->pipeField = value;\n    }\n    \n    \n    inline System::Byte UsbDeviceDescriptorType::Length::get() {\n        return this->lengthField;\n    }\n    inline System::Void UsbDeviceDescriptorType::Length::set(System::Byte value) {\n        this->lengthField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::DescriptorType::get() {\n        return this->descriptorTypeField;\n    }\n    inline System::Void UsbDeviceDescriptorType::DescriptorType::set(System::Byte value) {\n        this->descriptorTypeField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceDescriptorType::CdUSB::get() {\n        return this->cdUSBField;\n    }\n    inline System::Void UsbDeviceDescriptorType::CdUSB::set(System::UInt16 value) {\n        this->cdUSBField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void UsbDeviceDescriptorType::DeviceClass::set(System::Byte value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::DeviceSubclass::get() {\n        return this->deviceSubclassField;\n    }\n    inline System::Void UsbDeviceDescriptorType::DeviceSubclass::set(System::Byte value) {\n        this->deviceSubclassField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::DeviceProtocol::get() {\n        return this->deviceProtocolField;\n    }\n    inline System::Void UsbDeviceDescriptorType::DeviceProtocol::set(System::Byte value) {\n        this->deviceProtocolField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::MaxPacketSize0::get() {\n        return this->maxPacketSize0Field;\n    }\n    inline System::Void UsbDeviceDescriptorType::MaxPacketSize0::set(System::Byte value) {\n        this->maxPacketSize0Field = value;\n    }\n    \n    inline System::UInt16 UsbDeviceDescriptorType::IdVendor::get() {\n        return this->idVendorField;\n    }\n    inline System::Void UsbDeviceDescriptorType::IdVendor::set(System::UInt16 value) {\n        this->idVendorField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceDescriptorType::IdProduct::get() {\n        return this->idProductField;\n    }\n    inline System::Void UsbDeviceDescriptorType::IdProduct::set(System::UInt16 value) {\n        this->idProductField = value;\n    }\n    \n    inline System::UInt16 UsbDeviceDescriptorType::CdDevice::get() {\n        return this->cdDeviceField;\n    }\n    inline System::Void UsbDeviceDescriptorType::CdDevice::set(System::UInt16 value) {\n        this->cdDeviceField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::IManufacturer::get() {\n        return this->iManufacturerField;\n    }\n    inline System::Void UsbDeviceDescriptorType::IManufacturer::set(System::Byte value) {\n        this->iManufacturerField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::IProduct::get() {\n        return this->iProductField;\n    }\n    inline System::Void UsbDeviceDescriptorType::IProduct::set(System::Byte value) {\n        this->iProductField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::ISerialNumber::get() {\n        return this->iSerialNumberField;\n    }\n    inline System::Void UsbDeviceDescriptorType::ISerialNumber::set(System::Byte value) {\n        this->iSerialNumberField = value;\n    }\n    \n    inline System::Byte UsbDeviceDescriptorType::NumConfigurations::get() {\n        return this->numConfigurationsField;\n    }\n    inline System::Void UsbDeviceDescriptorType::NumConfigurations::set(System::Byte value) {\n        this->numConfigurationsField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  UsbPipeInfoType::EndpointDescriptor::get() {\n        return this->endpointDescriptorField;\n    }\n    inline System::Void UsbPipeInfoType::EndpointDescriptor::set(Microsoft::Kits::Samples::Usb::EndpointDescriptorType^  value) {\n        this->endpointDescriptorField = value;\n    }\n    \n    inline System::UInt64 UsbPipeInfoType::ScheduleOffset::get() {\n        return this->scheduleOffsetField;\n    }\n    inline System::Void UsbPipeInfoType::ScheduleOffset::set(System::UInt64 value) {\n        this->scheduleOffsetField = value;\n    }\n    \n    \n    inline System::String^  UsbDeviceClassDetailsType::DeviceType::get() {\n        return this->deviceTypeField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::DeviceType::set(System::String^  value) {\n        this->deviceTypeField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassDetailsType::DeviceTypeError::get() {\n        return this->deviceTypeErrorField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::DeviceTypeError::set(System::String^  value) {\n        this->deviceTypeErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassDetailsType::SubclassType::get() {\n        return this->subclassTypeField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::SubclassType::set(System::String^  value) {\n        this->subclassTypeField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassDetailsType::SubclassTypeError::get() {\n        return this->subclassTypeErrorField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::SubclassTypeError::set(System::String^  value) {\n        this->subclassTypeErrorField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassDetailsType::DeviceProtocol::get() {\n        return this->deviceProtocolField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::DeviceProtocol::set(System::String^  value) {\n        this->deviceProtocolField = value;\n    }\n    \n    inline System::String^  UsbDeviceClassDetailsType::DeviceProtocolError::get() {\n        return this->deviceProtocolErrorField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::DeviceProtocolError::set(System::String^  value) {\n        this->deviceProtocolErrorField = value;\n    }\n    \n    inline System::UInt32 UsbDeviceClassDetailsType::UvcVersion::get() {\n        return this->uvcVersionField;\n    }\n    inline System::Void UsbDeviceClassDetailsType::UvcVersion::set(System::UInt32 value) {\n        this->uvcVersionField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::HubNodeInformationType^  ExternalHubType::HubNodeInformation::get() {\n        return this->hubNodeInformationField;\n    }\n    inline System::Void ExternalHubType::HubNodeInformation::set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^  value) {\n        this->hubNodeInformationField = value;\n    }\n    \n    inline System::String^  ExternalHubType::HubName::get() {\n        return this->hubNameField;\n    }\n    inline System::Void ExternalHubType::HubName::set(System::String^  value) {\n        this->hubNameField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubInformationExType^  ExternalHubType::HubInformationEx::get() {\n        return this->hubInformationExField;\n    }\n    inline System::Void ExternalHubType::HubInformationEx::set(Microsoft::Kits::Samples::Usb::HubInformationExType^  value) {\n        this->hubInformationExField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  ExternalHubType::HubCapabilityEx::get() {\n        return this->hubCapabilityExField;\n    }\n    inline System::Void ExternalHubType::HubCapabilityEx::set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  value) {\n        this->hubCapabilityExField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  ExternalHubType::ConnectionInfo::get() {\n        return this->connectionInfoField;\n    }\n    inline System::Void ExternalHubType::ConnectionInfo::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExType^  value) {\n        this->connectionInfoField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  ExternalHubType::UsbDevice::get() {\n        return this->usbDeviceField;\n    }\n    inline System::Void ExternalHubType::UsbDevice::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  value) {\n        this->usbDeviceField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  ExternalHubType::NoDevice::get() {\n        return this->noDeviceField;\n    }\n    inline System::Void ExternalHubType::NoDevice::set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  value) {\n        this->noDeviceField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  ExternalHubType::DeviceConfiguration::get() {\n        return this->deviceConfigurationField;\n    }\n    inline System::Void ExternalHubType::DeviceConfiguration::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceConfigurationType^  >^  value) {\n        this->deviceConfigurationField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  ExternalHubType::BosDescriptor::get() {\n        return this->bosDescriptorField;\n    }\n    inline System::Void ExternalHubType::BosDescriptor::set(Microsoft::Kits::Samples::Usb::UsbBosDescriptorType^  value) {\n        this->bosDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  ExternalHubType::ConnectionInfoV2::get() {\n        return this->connectionInfoV2Field;\n    }\n    inline System::Void ExternalHubType::ConnectionInfoV2::set(Microsoft::Kits::Samples::Usb::NodeConnectionInfoExV2Type^  value) {\n        this->connectionInfoV2Field = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  ExternalHubType::ExternalHub::get() {\n        return this->externalHubField;\n    }\n    inline System::Void ExternalHubType::ExternalHub::set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  value) {\n        this->externalHubField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::PortConnectorType^  ExternalHubType::PortConnector::get() {\n        return this->portConnectorField;\n    }\n    inline System::Void ExternalHubType::PortConnector::set(Microsoft::Kits::Samples::Usb::PortConnectorType^  value) {\n        this->portConnectorField = value;\n    }\n    \n    inline System::String^  ExternalHubType::ServiceName::get() {\n        return this->serviceNameField;\n    }\n    inline System::Void ExternalHubType::ServiceName::set(System::String^  value) {\n        this->serviceNameField = value;\n    }\n    \n    inline System::String^  ExternalHubType::HwId::get() {\n        return this->hwIdField;\n    }\n    inline System::Void ExternalHubType::HwId::set(System::String^  value) {\n        this->hwIdField = value;\n    }\n    \n    inline System::String^  ExternalHubType::DeviceId::get() {\n        return this->deviceIdField;\n    }\n    inline System::Void ExternalHubType::DeviceId::set(System::String^  value) {\n        this->deviceIdField = value;\n    }\n    \n    inline System::String^  ExternalHubType::DeviceName::get() {\n        return this->deviceNameField;\n    }\n    inline System::Void ExternalHubType::DeviceName::set(System::String^  value) {\n        this->deviceNameField = value;\n    }\n    \n    inline System::String^  ExternalHubType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void ExternalHubType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::String^  ExternalHubType::UsbProtocol::get() {\n        return this->usbProtocolField;\n    }\n    inline System::Void ExternalHubType::UsbProtocol::set(System::String^  value) {\n        this->usbProtocolField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::HubNodeType HubNodeInformationType::HubNode::get() {\n        return this->hubNodeField;\n    }\n    inline System::Void HubNodeInformationType::HubNode::set(Microsoft::Kits::Samples::Usb::HubNodeType value) {\n        this->hubNodeField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubInformationType^  HubNodeInformationType::HubInformation::get() {\n        return this->hubInformationField;\n    }\n    inline System::Void HubNodeInformationType::HubInformation::set(Microsoft::Kits::Samples::Usb::HubInformationType^  value) {\n        this->hubInformationField = value;\n    }\n    \n    inline System::UInt64 HubNodeInformationType::MiParentNumberOfInterfaces::get() {\n        return this->miParentNumberOfInterfacesField;\n    }\n    inline System::Void HubNodeInformationType::MiParentNumberOfInterfaces::set(System::UInt64 value) {\n        this->miParentNumberOfInterfacesField = value;\n    }\n    \n    \n    inline System::Boolean HubInformationType::IsRootHub::get() {\n        return this->isRootHubField;\n    }\n    inline System::Void HubInformationType::IsRootHub::set(System::Boolean value) {\n        this->isRootHubField = value;\n    }\n    \n    inline System::Boolean HubInformationType::IsBusPowered::get() {\n        return this->isBusPoweredField;\n    }\n    inline System::Void HubInformationType::IsBusPowered::set(System::Boolean value) {\n        this->isBusPoweredField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubDescriptorType^  HubInformationType::HubDescriptor::get() {\n        return this->hubDescriptorField;\n    }\n    inline System::Void HubInformationType::HubDescriptor::set(Microsoft::Kits::Samples::Usb::HubDescriptorType^  value) {\n        this->hubDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  HubInformationType::HubCharacteristics::get() {\n        return this->hubCharacteristicsField;\n    }\n    inline System::Void HubInformationType::HubCharacteristics::set(Microsoft::Kits::Samples::Usb::HubCharacteristicsType^  value) {\n        this->hubCharacteristicsField = value;\n    }\n    \n    \n    inline System::Byte HubDescriptorType::DescriptorLength::get() {\n        return this->descriptorLengthField;\n    }\n    inline System::Void HubDescriptorType::DescriptorLength::set(System::Byte value) {\n        this->descriptorLengthField = value;\n    }\n    \n    inline System::Byte HubDescriptorType::DescriptorType::get() {\n        return this->descriptorTypeField;\n    }\n    inline System::Void HubDescriptorType::DescriptorType::set(System::Byte value) {\n        this->descriptorTypeField = value;\n    }\n    \n    inline System::Byte HubDescriptorType::NumberOfPorts::get() {\n        return this->numberOfPortsField;\n    }\n    inline System::Void HubDescriptorType::NumberOfPorts::set(System::Byte value) {\n        this->numberOfPortsField = value;\n    }\n    \n    inline System::Byte HubDescriptorType::PowerOntoPowerGood::get() {\n        return this->powerOntoPowerGoodField;\n    }\n    inline System::Void HubDescriptorType::PowerOntoPowerGood::set(System::Byte value) {\n        this->powerOntoPowerGoodField = value;\n    }\n    \n    inline System::Byte HubDescriptorType::HubControlCurrent::get() {\n        return this->hubControlCurrentField;\n    }\n    inline System::Void HubDescriptorType::HubControlCurrent::set(System::Byte value) {\n        this->hubControlCurrentField = value;\n    }\n    \n    \n    inline System::UInt32 HubCharacteristicsType::HubCharacteristicsValue::get() {\n        return this->hubCharacteristicsValueField;\n    }\n    inline System::Void HubCharacteristicsType::HubCharacteristicsValue::set(System::UInt32 value) {\n        this->hubCharacteristicsValueField = value;\n    }\n    \n    inline System::String^  HubCharacteristicsType::PowerSwitching::get() {\n        return this->powerSwitchingField;\n    }\n    inline System::Void HubCharacteristicsType::PowerSwitching::set(System::String^  value) {\n        this->powerSwitchingField = value;\n    }\n    \n    inline System::Boolean HubCharacteristicsType::CompoundDevice::get() {\n        return this->compoundDeviceField;\n    }\n    inline System::Void HubCharacteristicsType::CompoundDevice::set(System::Boolean value) {\n        this->compoundDeviceField = value;\n    }\n    \n    inline System::String^  HubCharacteristicsType::OverCurrentProtection::get() {\n        return this->overCurrentProtectionField;\n    }\n    inline System::Void HubCharacteristicsType::OverCurrentProtection::set(System::String^  value) {\n        this->overCurrentProtectionField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::HubTypeType HubInformationExType::HubType::get() {\n        return this->hubTypeField;\n    }\n    inline System::Void HubInformationExType::HubType::set(Microsoft::Kits::Samples::Usb::HubTypeType value) {\n        this->hubTypeField = value;\n    }\n    \n    inline System::UInt16 HubInformationExType::HighestPortNumber::get() {\n        return this->highestPortNumberField;\n    }\n    inline System::Void HubInformationExType::HighestPortNumber::set(System::UInt16 value) {\n        this->highestPortNumberField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubDescriptorType^  HubInformationExType::HubDescriptor::get() {\n        return this->hubDescriptorField;\n    }\n    inline System::Void HubInformationExType::HubDescriptor::set(Microsoft::Kits::Samples::Usb::HubDescriptorType^  value) {\n        this->hubDescriptorField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  HubInformationExType::Hub30Descriptor::get() {\n        return this->hub30DescriptorField;\n    }\n    inline System::Void HubInformationExType::Hub30Descriptor::set(Microsoft::Kits::Samples::Usb::Hub30DescriptorType^  value) {\n        this->hub30DescriptorField = value;\n    }\n    \n    \n    inline System::Byte Hub30DescriptorType::Length::get() {\n        return this->lengthField;\n    }\n    inline System::Void Hub30DescriptorType::Length::set(System::Byte value) {\n        this->lengthField = value;\n    }\n    \n    inline System::Byte Hub30DescriptorType::DescriptorType::get() {\n        return this->descriptorTypeField;\n    }\n    inline System::Void Hub30DescriptorType::DescriptorType::set(System::Byte value) {\n        this->descriptorTypeField = value;\n    }\n    \n    inline System::Byte Hub30DescriptorType::NumberOfPorts::get() {\n        return this->numberOfPortsField;\n    }\n    inline System::Void Hub30DescriptorType::NumberOfPorts::set(System::Byte value) {\n        this->numberOfPortsField = value;\n    }\n    \n    inline System::UInt16 Hub30DescriptorType::HubCharacteristics::get() {\n        return this->hubCharacteristicsField;\n    }\n    inline System::Void Hub30DescriptorType::HubCharacteristics::set(System::UInt16 value) {\n        this->hubCharacteristicsField = value;\n    }\n    \n    inline System::Byte Hub30DescriptorType::PowerOntoPowerGood::get() {\n        return this->powerOntoPowerGoodField;\n    }\n    inline System::Void Hub30DescriptorType::PowerOntoPowerGood::set(System::Byte value) {\n        this->powerOntoPowerGoodField = value;\n    }\n    \n    inline System::Byte Hub30DescriptorType::HubControlCurrent::get() {\n        return this->hubControlCurrentField;\n    }\n    inline System::Void Hub30DescriptorType::HubControlCurrent::set(System::Byte value) {\n        this->hubControlCurrentField = value;\n    }\n    \n    inline System::Byte Hub30DescriptorType::HubHdrDecLat::get() {\n        return this->hubHdrDecLatField;\n    }\n    inline System::Void Hub30DescriptorType::HubHdrDecLat::set(System::Byte value) {\n        this->hubHdrDecLatField = value;\n    }\n    \n    inline System::UInt16 Hub30DescriptorType::HubDelay::get() {\n        return this->hubDelayField;\n    }\n    inline System::Void Hub30DescriptorType::HubDelay::set(System::UInt16 value) {\n        this->hubDelayField = value;\n    }\n    \n    inline System::UInt16 Hub30DescriptorType::DeviceRemovable::get() {\n        return this->deviceRemovableField;\n    }\n    inline System::Void Hub30DescriptorType::DeviceRemovable::set(System::UInt16 value) {\n        this->deviceRemovableField = value;\n    }\n    \n    \n    inline System::Boolean HubCapabilitiesExType::HubIsHighSpeedCapable::get() {\n        return this->hubIsHighSpeedCapableField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsHighSpeedCapable::set(System::Boolean value) {\n        this->hubIsHighSpeedCapableField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsHighSpeed::get() {\n        return this->hubIsHighSpeedField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsHighSpeed::set(System::Boolean value) {\n        this->hubIsHighSpeedField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsMultiTtCapable::get() {\n        return this->hubIsMultiTtCapableField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsMultiTtCapable::set(System::Boolean value) {\n        this->hubIsMultiTtCapableField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsMultiTt::get() {\n        return this->hubIsMultiTtField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsMultiTt::set(System::Boolean value) {\n        this->hubIsMultiTtField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsRoot::get() {\n        return this->hubIsRootField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsRoot::set(System::Boolean value) {\n        this->hubIsRootField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsArmedWakeOnConnect::get() {\n        return this->hubIsArmedWakeOnConnectField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsArmedWakeOnConnect::set(System::Boolean value) {\n        this->hubIsArmedWakeOnConnectField = value;\n    }\n    \n    inline System::Boolean HubCapabilitiesExType::HubIsBusPowered::get() {\n        return this->hubIsBusPoweredField;\n    }\n    inline System::Void HubCapabilitiesExType::HubIsBusPowered::set(System::Boolean value) {\n        this->hubIsBusPoweredField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::HubNodeInformationType^  RootHubType::HubNodeInformation::get() {\n        return this->hubNodeInformationField;\n    }\n    inline System::Void RootHubType::HubNodeInformation::set(Microsoft::Kits::Samples::Usb::HubNodeInformationType^  value) {\n        this->hubNodeInformationField = value;\n    }\n    \n    inline System::String^  RootHubType::HubName::get() {\n        return this->hubNameField;\n    }\n    inline System::Void RootHubType::HubName::set(System::String^  value) {\n        this->hubNameField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubInformationExType^  RootHubType::HubInformationEx::get() {\n        return this->hubInformationExField;\n    }\n    inline System::Void RootHubType::HubInformationEx::set(Microsoft::Kits::Samples::Usb::HubInformationExType^  value) {\n        this->hubInformationExField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  RootHubType::HubCapabilityEx::get() {\n        return this->hubCapabilityExField;\n    }\n    inline System::Void RootHubType::HubCapabilityEx::set(Microsoft::Kits::Samples::Usb::HubCapabilitiesExType^  value) {\n        this->hubCapabilityExField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  RootHubType::ExternalHub::get() {\n        return this->externalHubField;\n    }\n    inline System::Void RootHubType::ExternalHub::set(cli::array< Microsoft::Kits::Samples::Usb::ExternalHubType^  >^  value) {\n        this->externalHubField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  RootHubType::UsbDevice::get() {\n        return this->usbDeviceField;\n    }\n    inline System::Void RootHubType::UsbDevice::set(cli::array< Microsoft::Kits::Samples::Usb::UsbDeviceType^  >^  value) {\n        this->usbDeviceField = value;\n    }\n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  RootHubType::NoDevice::get() {\n        return this->noDeviceField;\n    }\n    inline System::Void RootHubType::NoDevice::set(cli::array< Microsoft::Kits::Samples::Usb::NoDeviceType^  >^  value) {\n        this->noDeviceField = value;\n    }\n    \n    inline System::String^  RootHubType::ServiceName::get() {\n        return this->serviceNameField;\n    }\n    inline System::Void RootHubType::ServiceName::set(System::String^  value) {\n        this->serviceNameField = value;\n    }\n    \n    inline System::String^  RootHubType::HwId::get() {\n        return this->hwIdField;\n    }\n    inline System::Void RootHubType::HwId::set(System::String^  value) {\n        this->hwIdField = value;\n    }\n    \n    inline System::String^  RootHubType::DeviceId::get() {\n        return this->deviceIdField;\n    }\n    inline System::Void RootHubType::DeviceId::set(System::String^  value) {\n        this->deviceIdField = value;\n    }\n    \n    inline System::String^  RootHubType::DeviceName::get() {\n        return this->deviceNameField;\n    }\n    inline System::Void RootHubType::DeviceName::set(System::String^  value) {\n        this->deviceNameField = value;\n    }\n    \n    inline System::String^  RootHubType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void RootHubType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::String^  RootHubType::UsbProtocol::get() {\n        return this->usbProtocolField;\n    }\n    inline System::Void RootHubType::UsbProtocol::set(System::String^  value) {\n        this->usbProtocolField = value;\n    }\n    \n    \n    inline System::String^  UsbHCPowerStateType::SystemState::get() {\n        return this->systemStateField;\n    }\n    inline System::Void UsbHCPowerStateType::SystemState::set(System::String^  value) {\n        this->systemStateField = value;\n    }\n    \n    inline System::String^  UsbHCPowerStateType::HostControllerState::get() {\n        return this->hostControllerStateField;\n    }\n    inline System::Void UsbHCPowerStateType::HostControllerState::set(System::String^  value) {\n        this->hostControllerStateField = value;\n    }\n    \n    inline System::String^  UsbHCPowerStateType::HubState::get() {\n        return this->hubStateField;\n    }\n    inline System::Void UsbHCPowerStateType::HubState::set(System::String^  value) {\n        this->hubStateField = value;\n    }\n    \n    inline System::Boolean UsbHCPowerStateType::CanWakeUp::get() {\n        return this->canWakeUpField;\n    }\n    inline System::Void UsbHCPowerStateType::CanWakeUp::set(System::Boolean value) {\n        this->canWakeUpField = value;\n    }\n    \n    inline System::Boolean UsbHCPowerStateType::IsPowered::get() {\n        return this->isPoweredField;\n    }\n    inline System::Void UsbHCPowerStateType::IsPowered::set(System::Boolean value) {\n        this->isPoweredField = value;\n    }\n    \n    \n    inline cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  UsbHCPowerStateMappingType::PowerMap::get() {\n        return this->powerMapField;\n    }\n    inline System::Void UsbHCPowerStateMappingType::PowerMap::set(cli::array< Microsoft::Kits::Samples::Usb::UsbHCPowerStateType^  >^  value) {\n        this->powerMapField = value;\n    }\n    \n    inline System::String^  UsbHCPowerStateMappingType::LastSleepState::get() {\n        return this->lastSleepStateField;\n    }\n    inline System::Void UsbHCPowerStateMappingType::LastSleepState::set(System::String^  value) {\n        this->lastSleepStateField = value;\n    }\n    \n    \n    inline System::Int64 UsbHCDeviceInfoType::VendorId::get() {\n        return this->vendorIdField;\n    }\n    inline System::Void UsbHCDeviceInfoType::VendorId::set(System::Int64 value) {\n        this->vendorIdField = value;\n    }\n    \n    inline System::Int64 UsbHCDeviceInfoType::DeviceId::get() {\n        return this->deviceIdField;\n    }\n    inline System::Void UsbHCDeviceInfoType::DeviceId::set(System::Int64 value) {\n        this->deviceIdField = value;\n    }\n    \n    inline System::String^  UsbHCDeviceInfoType::DriverKey::get() {\n        return this->driverKeyField;\n    }\n    inline System::Void UsbHCDeviceInfoType::DriverKey::set(System::String^  value) {\n        this->driverKeyField = value;\n    }\n    \n    inline System::Int64 UsbHCDeviceInfoType::SubSysId::get() {\n        return this->subSysIdField;\n    }\n    inline System::Void UsbHCDeviceInfoType::SubSysId::set(System::Int64 value) {\n        this->subSysIdField = value;\n    }\n    \n    inline System::Int64 UsbHCDeviceInfoType::Revision::get() {\n        return this->revisionField;\n    }\n    inline System::Void UsbHCDeviceInfoType::Revision::set(System::Int64 value) {\n        this->revisionField = value;\n    }\n    \n    inline System::UInt64 UsbHCDeviceInfoType::DebugPort::get() {\n        return this->debugPortField;\n    }\n    inline System::Void UsbHCDeviceInfoType::DebugPort::set(System::UInt64 value) {\n        this->debugPortField = value;\n    }\n    \n    inline System::UInt64 UsbHCDeviceInfoType::NumberOfRootPorts::get() {\n        return this->numberOfRootPortsField;\n    }\n    inline System::Void UsbHCDeviceInfoType::NumberOfRootPorts::set(System::UInt64 value) {\n        this->numberOfRootPortsField = value;\n    }\n    \n    inline System::UInt64 UsbHCDeviceInfoType::ControllerFlavor::get() {\n        return this->controllerFlavorField;\n    }\n    inline System::Void UsbHCDeviceInfoType::ControllerFlavor::set(System::UInt64 value) {\n        this->controllerFlavorField = value;\n    }\n    \n    inline System::String^  UsbHCDeviceInfoType::ControllerFlavorString::get() {\n        return this->controllerFlavorStringField;\n    }\n    inline System::Void UsbHCDeviceInfoType::ControllerFlavorString::set(System::String^  value) {\n        this->controllerFlavorStringField = value;\n    }\n    \n    inline System::Boolean UsbHCDeviceInfoType::PortSwitchingEnabled::get() {\n        return this->portSwitchingEnabledField;\n    }\n    inline System::Void UsbHCDeviceInfoType::PortSwitchingEnabled::set(System::Boolean value) {\n        this->portSwitchingEnabledField = value;\n    }\n    \n    inline System::Boolean UsbHCDeviceInfoType::SelectiveSuspendEnabled::get() {\n        return this->selectiveSuspendEnabledField;\n    }\n    inline System::Void UsbHCDeviceInfoType::SelectiveSuspendEnabled::set(System::Boolean value) {\n        this->selectiveSuspendEnabledField = value;\n    }\n    \n    inline System::UInt64 UsbHCDeviceInfoType::LegacyBios::get() {\n        return this->legacyBiosField;\n    }\n    inline System::Void UsbHCDeviceInfoType::LegacyBios::set(System::UInt64 value) {\n        this->legacyBiosField = value;\n    }\n    \n    \n    inline Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  HostControllerType::ControllerInfo::get() {\n        return this->controllerInfoField;\n    }\n    inline System::Void HostControllerType::ControllerInfo::set(Microsoft::Kits::Samples::Usb::UsbHCDeviceInfoType^  value) {\n        this->controllerInfoField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  HostControllerType::PowerMapping::get() {\n        return this->powerMappingField;\n    }\n    inline System::Void HostControllerType::PowerMapping::set(Microsoft::Kits::Samples::Usb::UsbHCPowerStateMappingType^  value) {\n        this->powerMappingField = value;\n    }\n    \n    inline Microsoft::Kits::Samples::Usb::RootHubType^  HostControllerType::RootHub::get() {\n        return this->rootHubField;\n    }\n    inline System::Void HostControllerType::RootHub::set(Microsoft::Kits::Samples::Usb::RootHubType^  value) {\n        this->rootHubField = value;\n    }\n    \n    inline System::String^  HostControllerType::ServiceName::get() {\n        return this->serviceNameField;\n    }\n    inline System::Void HostControllerType::ServiceName::set(System::String^  value) {\n        this->serviceNameField = value;\n    }\n    \n    inline System::String^  HostControllerType::HwId::get() {\n        return this->hwIdField;\n    }\n    inline System::Void HostControllerType::HwId::set(System::String^  value) {\n        this->hwIdField = value;\n    }\n    \n    inline System::String^  HostControllerType::DeviceId::get() {\n        return this->deviceIdField;\n    }\n    inline System::Void HostControllerType::DeviceId::set(System::String^  value) {\n        this->deviceIdField = value;\n    }\n    \n    inline System::String^  HostControllerType::DeviceName::get() {\n        return this->deviceNameField;\n    }\n    inline System::Void HostControllerType::DeviceName::set(System::String^  value) {\n        this->deviceNameField = value;\n    }\n    \n    inline System::String^  HostControllerType::DeviceClass::get() {\n        return this->deviceClassField;\n    }\n    inline System::Void HostControllerType::DeviceClass::set(System::String^  value) {\n        this->deviceClassField = value;\n    }\n    \n    inline System::String^  HostControllerType::UsbProtocol::get() {\n        return this->usbProtocolField;\n    }\n    inline System::Void HostControllerType::UsbProtocol::set(System::String^  value) {\n        this->usbProtocolField = value;\n    }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/usbviddesc.h",
    "content": "/*++\r\n\r\nCopyright (c) 2002-2003 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    USBVIDDESC.H\r\n\r\nAbstract:\r\n\r\n    This is a header file for USB Video Class Specific descriptors which are not yet in\r\n    a standard system header file.\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    11-20-2002 : created\r\n    03-28-2003 : major updates to support latest UVC specs\r\n\r\n--*/\r\n\r\n#pragma pack(push, 1)\r\n\r\n/*****************************************************************************\r\n D E F I N E S\r\n*****************************************************************************/\r\n\r\n//global version for USB Video Class spec version\r\n#define BCDVDC     0x0083\r\n\r\n//\r\n// USB Device Class Definition for Video Devices v8.c\r\n// Appendix A.  Video Device Class Codes\r\n//\r\n\r\n// A.1 Video Interface Class Code\r\n//TBD Normally would be in USB100.h but not official yet\r\n#define USB_DEVICE_CLASS_VIDEO             0x0E\r\n#define USB_DEVICE_CLASS_VIDEO_PRERELEASE  0xFF\r\n//CC_VIDEO in spec.  The rest of the codes will be USB_VIDEO plus text from spec codes\r\n\r\n// A.2  Video Interface Subclass Codes\r\n//\r\n#define USB_VIDEO_SC_UNDEFINED                   0x00\r\n#define USB_VIDEO_SC_VIDEOCONTROL                0x01\r\n#define USB_VIDEO_SC_VIDEOSTREAMING              0x02\r\n#define USB_VIDEO_SC_VIDEO_INTERFACE_COLLECTION  0x03\r\n\r\n// A.3  Video Interface Protocol Codes\r\n//\r\n#define USB_VIDEO_PC_PROTOCOL_UNDEFINED     0x00\r\n\r\n// A.4  Video Class-Specific Descriptor Types\r\n//\r\n#define USB_VIDEO_CS_UNDEFINED              0x20\r\n#define USB_VIDEO_CS_DEVICE                 0x21\r\n#define USB_VIDEO_CS_CONFIGURATION          0x22\r\n#define USB_VIDEO_CS_STRING                 0x23\r\n#define USB_VIDEO_CS_INTERFACE              0x24\r\n#define USB_VIDEO_CS_ENDPOINT               0x25\r\n\r\n// A.5  Video Class-Specific VC (Video Control) Interface Descriptor Subtypes\r\n//\r\n#define USB_VIDEO_VC_DESCRIPTOR_UNDEFINED   0x00\r\n#define USB_VIDEO_VC_HEADER                 0x01\r\n#define USB_VIDEO_VC_INPUT_TERMINAL         0x02\r\n#define USB_VIDEO_VC_OUTPUT_TERMINAL        0x03\r\n#define USB_VIDEO_VC_SELECTOR_UNIT          0x04\r\n#define USB_VIDEO_VC_PROCESSING_UNIT        0x05\r\n#define USB_VIDEO_VC_EXTENSION_UNIT         0x06\r\n\r\n// A.6  Video Class-Specific VS (Video Streaming) Interface Descriptor Subtypes\r\n//\r\n#define USB_VIDEO_VS_UNDEFINED              0x00\r\n#define USB_VIDEO_VS_INPUT_HEADER           0x01\r\n#define USB_VIDEO_VS_OUTPUT_HEADER          0x02\r\n#define USB_VIDEO_VS_STILL_IMAGE_FRAME      0x03\r\n#define USB_VIDEO_VS_FORMAT_UNCOMPRESSED    0x04\r\n#define USB_VIDEO_VS_FRAME_UNCOMPRESSED     0x05\r\n#define USB_VIDEO_VS_FORMAT_MJPEG           0x06\r\n#define USB_VIDEO_VS_FRAME_MJPEG            0x07\r\n#define USB_VIDEO_VS_FORMAT_MPEG1           0x08\r\n#define USB_VIDEO_VS_FORMAT_MPEG2PS         0x09\r\n#define USB_VIDEO_VS_FORMAT_MPEG2TS         0x0A\r\n#define USB_VIDEO_VS_FORMAT_MPEG4SL         0x0B\r\n#define USB_VIDEO_VS_FORMAT_DV              0x0C\r\n#define USB_VIDEO_VS_COLORFORMAT            0x0D\r\n#define USB_VIDEO_VS_FORMAT_VENDOR          0x0E\r\n#define USB_VIDEO_VS_FRAME_VENDOR           0x0F\r\n\r\n// A.7 Video Class-Specific Endpoint Descriptor Subtypes\r\n//\r\n#define USB_VIDEO_EP_UNDEFINED              0x00\r\n#define USB_VIDEO_EP_GENERAL                0x01\r\n#define USB_VIDEO_EP_ENDPOINT               0x02\r\n#define USB_VIDEO_EP_INTERRUPT              0x03\r\n\r\n//\r\n// Below definitions only necessary if testing requests\r\n//\r\n// A.8 Video Class-Specific Request Codes\r\n//\r\n#define USB_VIDEO_RC_UNDEFINED  0x00\r\n#define USB_VIDEO_SET_CUR       0x01\r\n#define USB_VIDEO_GET_CUR       0x81\r\n#define USB_VIDEO_GET_MIN       0x82\r\n#define USB_VIDEO_GET_MAX       0x83\r\n#define USB_VIDEO_GET_RES       0x84\r\n#define USB_VIDEO_GET_LEN       0x85\r\n#define USB_VIDEO_GET_INFO      0x86\r\n#define USB_VIDEO_GET_DEF       0x87\r\n\r\n// A.9 Control Selector Codes\r\n// A.9.1 VideoControl Interface Control Selectors\r\n#define USB_VIDEO_VC_UNDEFINED_CONTROL            0x00\r\n#define USB_VIDEO_VC_VIDEO_POWER_MODE_CONTROL     0x01\r\n#define USB_VIDEO_VC_REQUEST_ERROR_CODE_CONTROL   0x02\r\n#define USB_VIDEO_VC_INDICATE_HOST_CLOCK_CONTROL  0x03\r\n\r\n//A.9.2 Terminal Control Selectors\r\n//\r\n#define USB_VIDEO_TE_CONTROL_UNDEFINED  0x00\r\n\r\n//A.9.3 Selector Unit Control Selectors\r\n//\r\n#define USB_VIDEO_SU_CONTROL_UNDEFINED     0x00\r\n#define USB_VIDEO_SU_INPUT_SELECT_CONTROL  0x01\r\n\r\n//A.9.4 Camera Terminal Control Selectors\r\n//\r\n#define USB_VIDEO_CT_CONTROL_UNDEFINED               0x00\r\n#define USB_VIDEO_CT_SCANNING_MODE_CONTROL           0x01\r\n#define USB_VIDEO_CT_AE_MODE_CONTROL                 0x02\r\n#define USB_VIDEO_CT_AE_PRIORITY_CONTROL             0x03\r\n#define USB_VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL  0x04\r\n#define USB_VIDEO_CT_EXPOSURE_TIME_RELATIVE_CONTROL  0x05\r\n#define USB_VIDEO_CT_FOCUS_ABSOLUTE_CONTROL          0x06\r\n#define USB_VIDEO_CT_FOCUS_RELATIVE_CONTROL          0x07\r\n#define USB_VIDEO_CT_FOCUS_AUTO_CONTROL              0x08\r\n#define USB_VIDEO_CT_IRIS_ABSOLUTE_CONTROL           0x09\r\n#define USB_VIDEO_CT_IRIS_RELATIVE_CONTROL           0x0A\r\n#define USB_VIDEO_CT_ZOOM_ABSOLUTE_CONTROL           0x0B\r\n#define USB_VIDEO_CT_ZOOM_RELATIVE_CONTROL           0x0C\r\n#define USB_VIDEO_CT_PANTILT_ABSOLUTE_CONTROL        0x0D\r\n#define USB_VIDEO_CT_PANTILT_RELATIVE_CONTROL        0x0E\r\n#define USB_VIDEO_CT_ROLL_ABSOLUTE_CONTROL           0x0F\r\n#define USB_VIDEO_CT_ROLL_RELATIVE_CONTROL           0x10\r\n\r\n//A.9.5 Processing Unit Control Selectors\r\n//\r\n#define USB_VIDEO_PU_CONTROL_UNDEFINED                       0x04\r\n#define USB_VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL          0x01\r\n#define USB_VIDEO_PU_BRIGHTNESS_CONTROL                      0x02\r\n#define USB_VIDEO_PU_CONTRAST_CONTROL                        0x03\r\n#define USB_VIDEO_PU_GAIN_CONTROL                            0x04\r\n#define USB_VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL            0x05\r\n#define USB_VIDEO_PU_HUE_CONTROL                             0x06\r\n#define USB_VIDEO_PU_SATURATION_CONTROL                      0x07\r\n#define USB_VIDEO_PU_SHARPNESS_CONTROL                       0x08\r\n#define USB_VIDEO_PU_GAMMA_CONTROL                           0x09\r\n#define USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL       0x0A\r\n#define USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL  0x0B\r\n#define USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL         0x0C\r\n#define USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL    0x0D\r\n#define USB_VIDEO_PU_DIGITAL_MULTIPLIER_CONTROL              0x0E\r\n#define USB_VIDEO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL        0x0F\r\n#define USB_VIDEO_PU_HUE_AUTO_CONTROL                        0x10\r\n\r\n//A.9.6 Extension Unit Control Selectors\r\n//\r\n#define USB_VIDEO_XU_CONTROL_UNDEFINED  0x00\r\n\r\n//A.9.7 VideoStreaming Interface Control Selectors\r\n//\r\n#define USB_VIDEO_VS_CONTROL_UNDEFINED             0x00\r\n#define USB_VIDEO_VS_PROBE_CONTROL                 0x01\r\n#define USB_VIDEO_VS_COMMIT_CONTROL                0x02\r\n#define USB_VIDEO_VS_STILL_PROBE_CONTROL           0x03\r\n#define USB_VIDEO_VS_STILL_COMMIT_CONTROL          0x04\r\n#define USB_VIDEO_VS_STILL_IMAGE_TRIGGER_CONTROL   0x05\r\n#define USB_VIDEO_VS_STREAM_ERROR_CODE_CONTROL     0x06\r\n#define USB_VIDEO_VS_GENERATE_KEY_FRAME_CONTROL    0x07\r\n#define USB_VIDEO_VS_UPDATE_FRAME_SEGMENT_CONTROL  0x08\r\n#define USB_VIDEO_VS_SYNCH_DELAY_CONTROL           0x09\r\n\r\n#define TapeControls       0\r\n#define TransportModes     1\r\n#define CameraControls     2\r\n#define ProcessorControls  3\r\n#define InHeaderControls   4\r\n\r\n/*****************************************************************************\r\n T Y P E D E F S\r\n*****************************************************************************/\r\n\r\n\r\n/*****************************************************************************\r\n USB Device Class Definition for Video Devices v8.b\r\n*****************************************************************************/\r\n\r\ntypedef struct _USB_VIDEO_COMMON_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n} USB_VIDEO_COMMON_DESCRIPTOR,\r\n*PUSB_VIDEO_COMMON_DESCRIPTOR;\r\n\r\n// 3.6.2 Class-Specific VC (Video Control) Interface Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    USHORT   bcdVDC;\r\n    USHORT   wTotalLength;\r\n    ULONG32  dwClockFrequency;\r\n    UCHAR    bInCollection;\r\n//    UCHAR    baInterfaceNr;          // variable length (0 minimum)\r\n} USB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR,\r\n*PUSB_VIDEO_VC_INTERFACE_HEADER_DESCRIPTOR;\r\n\r\n// 3.6.2.1 Input Terminal Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_INPUT_TERMINAL_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bTerminalID;\r\n    USHORT   wTerminalType;\r\n    UCHAR    bAssocTerminal;\r\n    UCHAR    iTerminal;\r\n} USB_VIDEO_INPUT_TERMINAL_DESCRIPTOR,\r\n*PUSB_VIDEO_INPUT_TERMINAL_DESCRIPTOR;\r\n\r\n// 3.6.2.2 Output Terminal Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bTerminalID;\r\n    USHORT   wTerminalType;\r\n    UCHAR    bAssocTerminal;\r\n    UCHAR    bSourceID;\r\n    UCHAR    iTerminal;\r\n} USB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR,\r\n*PUSB_VIDEO_OUTPUT_TERMINAL_DESCRIPTOR;\r\n\r\n// 3.6.2.3 Camera Unit Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bTerminalID;\r\n    USHORT   wTerminalType;\r\n    UCHAR    bAssocTerminal;\r\n    UCHAR    iTerminal;\r\n    USHORT   wObjectiveFocalLengthMin;\r\n    USHORT   wObjectiveFocalLengthMax;\r\n    USHORT   wOcularFocalLength;\r\n    UCHAR    bControlSize;\r\n//    UCHAR    bmControls;               // variable length (0 min, 3 max)\r\n} USB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR,\r\n*PUSB_VIDEO_CAMERA_TERMINAL_DESCRIPTOR;\r\n\r\n// 3.6.2.4 Selector Unit Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_SELECTOR_UNIT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bUnitID;\r\n    UCHAR    bNrInPins;\r\n    UCHAR    baSourceID;               // variable length (1 minimum)\r\n    UCHAR    iSelector;\r\n} USB_VIDEO_SELECTOR_UNIT_DESCRIPTOR,\r\n*PUSB_VIDEO_SELECTOR_UNIT_DESCRIPTOR;\r\n\r\n// 3.6.2.5 Processing Unit Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_PROCESSING_UNIT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bUnitID;\r\n    UCHAR    bSourceID;\r\n    USHORT   wMaxMultiplier;\r\n    UCHAR    bControlSize;\r\n//    UCHAR    bmControls;             // variable length (0 minimum)\r\n    UCHAR    iProcessing;\r\n} USB_VIDEO_PROCESSING_UNIT_DESCRIPTOR,\r\n*PUSB_VIDEO_PROCESSING_UNIT_DESCRIPTOR;\r\n\r\n// 3.6.2.6 Extension Unit Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_EXTENSION_UNIT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bUnitID;\r\n    GUID     guidExtensionCode;\r\n    UCHAR    bNumControls;\r\n    UCHAR    bNrInPins;\r\n    UCHAR    baSourceID;               // variable length (1 minimum)\r\n//    UCHAR    bControlSize;\r\n//    UCHAR    bmControls;             // variable length (0 minimum)\r\n//    UCHAR    iExtension;\r\n} USB_VIDEO_EXTENSION_UNIT_DESCRIPTOR,\r\n*PUSB_VIDEO_EXTENSION_UNIT_DESCRIPTOR;\r\n\r\n// 3.7.2.2 Class-Specific VC Interrupt EndPoint Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubType;\r\n    USHORT   wMaxTransferSize;\r\n} USB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR,\r\n*PUSB_VIDEO_VC_INTERRUPT_ENDPOINT_DESCRIPTOR;\r\n// 3.8.2.1 Class-Specific Input Header Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_INPUT_HEADER_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bNumFormats;\r\n    USHORT   wTotalLength;\r\n    UCHAR    bEndpointAddress;\r\n    UCHAR    bmInfo;\r\n    UCHAR    bTerminalLink;\r\n    UCHAR    bStillCaptureMethod;\r\n    UCHAR    bTriggerSupport;\r\n    UCHAR    bTriggerUsage;\r\n    UCHAR    bControlSize;\r\n//    UCHAR    bmaControls;            // variable length (0 minimum)\r\n} USB_VIDEO_INPUT_HEADER_DESCRIPTOR,\r\n*PUSB_VIDEO_INPUT_HEADER_DESCRIPTOR;\r\n\r\n// 3.8.2.2 Class-Specific Output Header Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_OUTPUT_HEADER_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bNumFormats;\r\n    USHORT wTotalLength;\r\n    UCHAR  bEndpointAddress;\r\n    UCHAR  bTerminalLink;\r\n} USB_VIDEO_OUTPUT_HEADER_DESCRIPTOR,\r\n*PUSB_VIDEO_OUTPUT_HEADER_DESCRIPTOR;\r\n\r\n// 3.8.2.3  Payload Format Descriptors\r\n//Payload Format Descriptor  Document\r\n//Uncompressed Video         DWGVideo Payload Uncompressed 0.xx.doc\r\n//MJPEG Video                DWGVideo Payload MJPEG Format Ver0.xx.doc\r\n//MPEG1 System Stream        DWGVideo Payload MPEG1 System Stream, MPEG2-PS Format Ver0.xx.doc\r\n//MPEG2 PS                   DWGVideo Payload MPEG1 System Stream, MPEG2-PS Format Ver0.xx.doc\r\n//MPEG-2 TS                  DWGVideo Payload MPEG2TS Format Ver0.xx.doc\r\n//MPEG-4 SL                  DWGVideo Payload MPEG4 SL format Ver0.xx.doc\r\n//DV                         DWGVideo Payload DV Format Ver0.xx.doc\r\n\r\n// 3.8.2.4  Video Frame Descriptor\r\n//\r\n//Video Frame Descriptor     Document\r\n//Uncompressed               DWGVideo Payload Uncompressed 0.xx.doc\r\n//MJPEG                      DWGVideo Payload MJPEG Format Ver0.xx.doc\r\n\r\n// 3.8.2.5  Still Image Frame Descriptor\r\n//\r\ntypedef struct _VIDEO_STILL_IMAGE {\r\n    USHORT  wWidth;\r\n    USHORT  wHeight;\r\n} VIDEO_STILL_IMAGE,\r\n*PVIDEO_STILL_IMAGE;\r\n\r\ntypedef struct _USB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR {\r\n    UCHAR              bLength;\r\n    UCHAR              bDescriptorType;\r\n    UCHAR              bDescriptorSubtype;\r\n    UCHAR              bEndpointAddress;\r\n    UCHAR              bNumImageSizePatterns;\r\n    VIDEO_STILL_IMAGE  dwStillImage;             // variable count\r\n    UCHAR              bNumCompressionPattern;\r\n    UCHAR              bCompression;             // variable count\r\n} USB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR,\r\n*PUSB_VIDEO_STILL_IMAGE_FRAME_DESCRIPTOR;\r\n\r\n// 3.8.2.6  Color Matching Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_COLOR_MATCHING_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bColorPrimaries;\r\n    UCHAR  bTransferCharacteristics;\r\n    UCHAR  bMatrixCoefficients;\r\n} USB_VIDEO_COLOR_MATCHING_DESCRIPTOR,\r\n*PUSB_VIDEO_COLOR_MATCHING_DESCRIPTOR;\r\n/*\r\n// 3.9.1  Class-specific VC Interrupt Endpoint Descriptor\r\ntypedef struct _USB_VIDEO_VS_ENDPOINT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubType;\r\n    USHORT  wMaxTransferSize;\r\n} USB_VIDEO_VS_ENDPOINT_DESCRIPTOR,\r\n*PUSB_VIDEO_VS_ENDPOINT_DESCRIPTOR;\r\n*/\r\n//\r\n// USB Device Class Definition for Video Devices: Uncompressed Payload 0.8a Draft Revision\r\n//\r\n\r\n// 3.1.1    Uncompressed Video Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFormatIndex;\r\n    UCHAR    bNumFrameDescriptors;\r\n    GUID     guidFormat;\r\n    UCHAR    bBitsPerPixel;\r\n    UCHAR    bDefaultFrameIndex;\r\n    UCHAR    bAspectRatioX;\r\n    UCHAR    bAspectRatioY;\r\n    UCHAR    bmInterlaceFlags;\r\n    UCHAR    bCopyProtect;\r\n} USB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_UNCOMPRESSED_FORMAT_DESCRIPTOR;\r\n\r\n// 3.1.2    Uncompressed Video Frame Descriptor Common\r\n//\r\ntypedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n} USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON,\r\n*PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_COMMON;\r\n\r\n// 3.1.2    Uncompressed Video Frame Descriptor - Continuous\r\n//\r\ntypedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwMinFrameInterval;\r\n    ULONG32  dwMaxFrameInterval;\r\n    ULONG32  dwFrameIntervalStep;\r\n} USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS,\r\n*PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_CONTINUOUS;\r\n\r\n// 3.1.2    Uncompressed Video Frame Descriptor - Discrete\r\n//\r\ntypedef struct _USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwFrameInterval;                    // variable count\r\n} USB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE,\r\n*PUSB_VIDEO_UNCOMPRESSED_FRAME_DESCRIPTOR_DISCRETE;\r\n\r\n//\r\n// USB Device Class Definition for Video Devices: Motion-JPEG Payload 0.8a Draft Revision\r\n// 3.1.1    MJPEG Video Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_MJPEG_FORMAT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bFormatIndex;\r\n    UCHAR  bNumFrameDescriptors;\r\n    UCHAR  bmFlags;\r\n    UCHAR  bDefaultFrameIndex;\r\n    UCHAR  bAspectRatioX;\r\n    UCHAR  bAspectRatioY;\r\n    UCHAR  bmInterlaceFlags;\r\n    UCHAR  bCopyProtect;\r\n} USB_VIDEO_MJPEG_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_MJPEG_FORMAT_DESCRIPTOR;\r\n\r\n// 3.1.2    MJPEG Video Frame Descriptors Common\r\n//\r\ntypedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n} USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON,\r\n*PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_COMMON;\r\n\r\n// 3.1.2    MJPEG Video Frame Descriptors - Continuous\r\n//\r\ntypedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwMinFrameInterval;\r\n    ULONG32  dwMaxFrameInterval;\r\n    ULONG32  dwFrameIntervalStep;\r\n} USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS,\r\n*PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_CONTINUOUS;\r\n\r\n// 3.1.2    MJPEG Video Frame Descriptors -Discrete\r\n//\r\ntypedef struct _USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwFrameInterval;                    // variable count\r\n} USB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE,\r\n*PUSB_VIDEO_MJPEG_FRAME_DESCRIPTOR_DISCRETE;\r\n\r\n//\r\n// USB Device Class Definition for Video Devices: MPEG1-SS, MPEG2-PS Payload 0.8a Draft Revision\r\n// 3.1.1    MPEG1 System Stream Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bFormatIndex;\r\n    USHORT  wPacketLength;\r\n    USHORT  wPackLength;\r\n    UCHAR   bPackdataType;\r\n} USB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_MPEG1_SS_FORMAT_DESCRIPTOR;\r\n\r\n// 3.1.2    MPEG2 PS Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bFormatIndex;\r\n    USHORT  wPacketLength;\r\n    USHORT  wPackLength;\r\n    UCHAR   bPackdataType;\r\n} USB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_MPEG2_PS_FORMAT_DESCRIPTOR;\r\n\r\n//\r\n// USB Device Class Definition for Video Devices: MPEG-2 TS Payload 0.8a Draft Revision\r\n// 3.1.1    MPEG-2 TS Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bFormatIndex;\r\n    UCHAR   bDataOffset;\r\n    UCHAR   bPacketLength;\r\n    UCHAR   bStrideLength;\r\n} USB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_MPEG2_TS_FORMAT_DESCRIPTOR;\r\n\r\n//\r\n// USB Device Class Definition for Video Devices: MPEG4 SL Payload 0.8a Draft Revision\r\n// 3.1.1    MPEG4 SL Format Descriptor\r\n//\r\ntypedef struct _USB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bFormatIndex;\r\n    USHORT  wPacketLength;\r\n} USB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_MPEG4_SL_FORMAT_DESCRIPTOR;\r\n\r\n// USB Device Class Definition for Video Devices: DV Payload 0.8a Draft Revision\r\n// 3.1.1    DV Format Descriptor\r\ntypedef struct _USB_VIDEO_DV_FORMAT_DESCRIPTOR {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFormatIndex;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    UCHAR    bFormatType;\r\n} USB_VIDEO_DV_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_DV_FORMAT_DESCRIPTOR;\r\n\r\n// USB Device Class Definition for Video Devices: Vendor Payload 0.8c Draft Revision\r\n// 3.1.1    Vendor Video Format Descriptor\r\ntypedef struct _USB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR {\r\n    UCHAR  bLength;\r\n    UCHAR  bDescriptorType;\r\n    UCHAR  bDescriptorSubtype;\r\n    UCHAR  bFormatIndex;\r\n    UCHAR  bNumFrameDescriptors;\r\n    GUID   guidMajorFormat;\r\n    GUID   guidSubFormat;\r\n    GUID   guidSpecifier;\r\n    UCHAR  bPayloadClass;\r\n    UCHAR  bDefaultFrameIndex;\r\n    UCHAR  bCopyProtect;\r\n} USB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR,\r\n*PUSB_VIDEO_VENDOR_VIDEO_FORMAT_DESCRIPTOR;\r\n\r\n// USB Device Class Definition for Video Devices: Vendor Payload 0.8c Draft Revision\r\n// 3.1.2    Vendor Video Frame Descriptor\r\ntypedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n} USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON,\r\n*PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_COMMON;\r\n\r\ntypedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwMinFrameInterval;\r\n    ULONG32  dwMaxFrameInterval;\r\n    ULONG32  dwFrameIntervalStep;\r\n} USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS,\r\n*PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_CONTINUOUS;\r\n\r\ntypedef struct _USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE {\r\n    UCHAR    bLength;\r\n    UCHAR    bDescriptorType;\r\n    UCHAR    bDescriptorSubtype;\r\n    UCHAR    bFrameIndex;\r\n    UCHAR    bmCapabilities;\r\n    USHORT   wWidth;\r\n    USHORT   wHeight;\r\n    ULONG32  dwMinBitRate;\r\n    ULONG32  dwMaxBitRate;\r\n    ULONG32  dwMaxVideoFrameBufferSize;\r\n    ULONG32  dwDefaultFrameInterval;\r\n    UCHAR    bFrameIntervalType;\r\n    ULONG32  dwFrameInterval;                    // variable count\r\n} USB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE,\r\n*PUSB_VIDEO_VENDOR_VIDEO_FRAME_DESCRIPTOR_DISCRETE;\r\n\r\n// USB Device Class Definition for Video Devices: Media Transport Terminal 0.8a Draft Revision\r\n// 3.1  Media Transport Input Descriptor\r\ntypedef struct _USB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bTerminalID;\r\n    USHORT  wTerminalType;\r\n    UCHAR   bAssocTerminal;\r\n    UCHAR   iTerminal;\r\n    UCHAR   bControlSize;\r\n    UCHAR   bmControls;                          // variable size (min 1)\r\n//    UCHAR   bTransportModeSize;                // variable count (min 0)\r\n//    UCHAR   bmTransportModes;                  // variable count (min 0)\r\n} USB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR,\r\n*PUSB_VIDEO_MEDIA_TRANSPORT_INPUT_DESCRIPTOR;\r\n\r\n// 3.2  Media Transport Output Descriptor\r\ntypedef struct _USB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR {\r\n    UCHAR   bLength;\r\n    UCHAR   bDescriptorType;\r\n    UCHAR   bDescriptorSubtype;\r\n    UCHAR   bTerminalID;\r\n    USHORT  wTerminalType;\r\n    UCHAR   bAssocTerminal;\r\n    UCHAR   bSourceID;\r\n    UCHAR   iTerminal;\r\n    UCHAR   bControlSize;\r\n    UCHAR   bmControls;                          // variable size (min 1)\r\n//    UCHAR   bTransportModeSize;                // variable count (min 0)\r\n//    UCHAR   bmTransportModes;                  // variable count (min 0)\r\n} USB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR,\r\n*PUSB_VIDEO_MEDIA_TRANSPORT_OUTPUT_DESCRIPTOR;\r\n\r\n#pragma pack(pop)\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/uvcdesc.h",
    "content": "//+-------------------------------------------------------------------------\r\n//\r\n//  Microsoft Windows\r\n//\r\n//  Copyright (C) Microsoft Corporation, 1999 - 2008\r\n//\r\n//  File:       uvcdesc.h\r\n//\r\n//  This header is from the UVC 1.1 USBVideo driver\r\n//\r\n//--------------------------------------------------------------------------\r\n\r\n#ifndef ___UVCDESC_H___\r\n#define ___UVCDESC_H___\r\n\r\n\r\n// USB Video Device Class Code\r\n#define USB_DEVICE_CLASS_VIDEO     0x0E\r\n\r\n// Video sub-classes\r\n#define SUBCLASS_UNDEFINED              0x00\r\n#define VIDEO_SUBCLASS_CONTROL          0x01\r\n#define VIDEO_SUBCLASS_STREAMING        0x02\r\n\r\n// Video Class-Specific Descriptor Types\r\n#define CS_UNDEFINED     0x20\r\n#define CS_DEVICE        0x21\r\n#define CS_CONFIGURATION 0x22\r\n#define CS_STRING        0x23\r\n#define CS_INTERFACE     0x24\r\n#define CS_ENDPOINT      0x25\r\n\r\n// Video Class-Specific VC Interface Descriptor Subtypes\r\n#define VC_HEADER       0x01\r\n#define INPUT_TERMINAL  0x02\r\n#define OUTPUT_TERMINAL 0x03\r\n#define SELECTOR_UNIT   0x04\r\n#define PROCESSING_UNIT 0x05\r\n#define EXTENSION_UNIT  0x06\r\n#define MAX_TYPE_UNIT   0x07\r\n\r\n// Video Class-Specific VS Interface Descriptor Subtypes\r\n#define VS_DESCRIPTOR_UNDEFINED 0x00\r\n#define VS_INPUT_HEADER         0x01\r\n#define VS_OUTPUT_HEADER        0x02\r\n#define VS_STILL_IMAGE_FRAME    0x03\r\n#define VS_FORMAT_UNCOMPRESSED  0x04\r\n#define VS_FRAME_UNCOMPRESSED   0x05\r\n#define VS_FORMAT_MJPEG         0x06\r\n#define VS_FRAME_MJPEG          0x07\r\n#define VS_FORMAT_MPEG1         0x08\r\n#define VS_FORMAT_MPEG2PS       0x09\r\n#define VS_FORMAT_MPEG2TS       0x0A\r\n#define VS_FORMAT_MPEG4SL       0x0B\r\n#define VS_FORMAT_DV            0x0C\r\n#define VS_COLORFORMAT          0x0D\r\n#define VS_FORMAT_VENDOR        0x0E\r\n#define VS_FRAME_VENDOR         0x0F\r\n\r\n// Video Class-Specific Endpoint Descriptor Subtypes\r\n#define EP_UNDEFINED            0x00\r\n#define EP_GENERAL              0x01\r\n#define EP_ENDPOINT             0x02\r\n#define EP_INTERRUPT            0x03\r\n\r\n// Video Class-Specific Terminal Types\r\n#define TERMINAL_TYPE_VENDOR_SPECIFIC           0x0100\r\n#define TERMINAL_TYPE_USB_STREAMING             0x0101\r\n#define TERMINAL_TYPE_INPUT_MASK                0x0200\r\n#define TERMINAL_TYPE_INPUT_VENDOR_SPECIFIC     0x0200\r\n#define TERMINAL_TYPE_INPUT_CAMERA              0x0201\r\n#define TERMINAL_TYPE_INPUT_MEDIA_TRANSPORT     0x0202\r\n#define TERMINAL_TYPE_OUTPUT_MASK               0x0300\r\n#define TERMINAL_TYPE_OUTPUT_VENDOR_SPECIFIC    0x0300\r\n#define TERMINAL_TYPE_OUTPUT_DISPLAY            0x0301\r\n#define TERMINAL_TYPE_OUTPUT_MEDIA_TRANSPORT    0x0302\r\n#define TERMINAL_TYPE_EXTERNAL_VENDOR_SPECIFIC  0x0400\r\n#define TERMINAL_TYPE_EXTERNAL_UNDEFINED        0x0400\r\n#define TERMINAL_TYPE_EXTERNAL_COMPOSITE        0x0401\r\n#define TERMINAL_TYPE_EXTERNAL_SVIDEO           0x0402\r\n#define TERMINAL_TYPE_EXTERNAL_COMPONENT        0x0403\r\n\r\n\r\n// Controls for error checking only\r\n#define DEV_SPECIFIC_CONTROL 0x1001\r\n\r\n// Map KSNODE_TYPE GUIDs to Indexes\r\n#define NODE_TYPE_NONE              0\r\n#define NODE_TYPE_STREAMING         1\r\n#define NODE_TYPE_INPUT_TERMINAL    2\r\n#define NODE_TYPE_OUTPUT_TERMINAL   3\r\n#define NODE_TYPE_SELECTOR          4\r\n#define NODE_TYPE_PROCESSING        5\r\n#define NODE_TYPE_CAMERA_TERMINAL   6\r\n#define NODE_TYPE_INPUT_MTT         7\r\n#define NODE_TYPE_OUTPUT_MTT        8\r\n#define NODE_TYPE_DEV_SPEC          9\r\n#define NODE_TYPE_MAX               9\r\n\r\n// USB bmRequestType values\r\n#define USBVIDEO_INTERFACE_SET        0x21\r\n#define USBVIDEO_ENDPOINT_SET         0x22\r\n#define USBVIDEO_INTERFACE_GET        0xA1\r\n#define USBVIDEO_ENDPOINT_GET         0xA2\r\n\r\n// Video Class-specific specific requests\r\n#define CLASS_SPECIFIC_GET_MASK 0x80\r\n\r\n#define RC_UNDEFINED 0x00\r\n#define SET_CUR 0x01\r\n#define GET_CUR 0x81\r\n#define GET_MIN 0x82\r\n#define GET_MAX 0x83\r\n#define GET_RES 0x84\r\n#define GET_LEN 0x85\r\n#define GET_INFO 0x86\r\n#define GET_DEF 0x87\r\n\r\n// Power Mode Control constants\r\n#define POWER_MODE_CONTROL_FULL                   0x0\r\n#define POWER_MODE_CONTROL_DEV_DEPENDENT          0x1\r\n\r\n// Video Class-specific Processing Unit Controls\r\n#define PU_CONTROL_UNDEFINED                      0x00\r\n#define PU_BACKLIGHT_COMPENSATION_CONTROL         0x01\r\n#define PU_BRIGHTNESS_CONTROL                     0x02\r\n#define PU_CONTRAST_CONTROL                       0x03\r\n#define PU_GAIN_CONTROL                           0x04\r\n#define PU_POWER_LINE_FREQUENCY_CONTROL           0x05\r\n#define PU_HUE_CONTROL                            0x06\r\n#define PU_SATURATION_CONTROL                     0x07\r\n#define PU_SHARPNESS_CONTROL                      0x08\r\n#define PU_GAMMA_CONTROL                          0x09\r\n#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x0A\r\n#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0B\r\n#define PU_WHITE_BALANCE_COMPONENT_CONTROL        0x0C\r\n#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x0D\r\n#define PU_DIGITAL_MULTIPLIER_CONTROL             0x0E\r\n#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x0F\r\n#define PU_HUE_AUTO_CONTROL                       0x10\r\n#define PU_ANALOG_VIDEO_STANDARD_CONTROL          0x11\r\n#define PU_ANALOG_LOCK_STATUS_CONTROL             0x12\r\n\r\n// Video Class-specific Camera Terminal Controls\r\n#define CT_CONTROL_UNDEFINED                0x00\r\n#define CT_SCANNING_MODE_CONTROL            0x01\r\n#define CT_AE_MODE_CONTROL                  0x02\r\n#define CT_AE_PRIORITY_CONTROL              0x03\r\n#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL   0x04\r\n#define CT_EXPOSURE_TIME_RELATIVE_CONTROL   0x05\r\n#define CT_FOCUS_ABSOLUTE_CONTROL           0x06\r\n#define CT_FOCUS_RELATIVE_CONTROL           0x07\r\n#define CT_FOCUS_AUTO_CONTROL               0x08\r\n#define CT_IRIS_ABSOLUTE_CONTROL            0x09\r\n#define CT_IRIS_RELATIVE_CONTROL            0x0A\r\n#define CT_ZOOM_ABSOLUTE_CONTROL            0x0B\r\n#define CT_ZOOM_RELATIVE_CONTROL            0x0C\r\n#define CT_PANTILT_ABSOLUTE_CONTROL         0x0D\r\n#define CT_PANTILT_RELATIVE_CONTROL         0x0E\r\n#define CT_ROLL_ABSOLUTE_CONTROL            0x0F\r\n#define CT_ROLL_RELATIVE_CONTROL            0x10\r\n#define CT_PRIVACY_CONTROL                  0x11\r\n\r\n#define CT_RELATIVE_INCREASE                0x01\r\n#define CT_RELATIVE_DECREASE                0xff\r\n#define CT_RELATIVE_STOP                    0x00\r\n\r\n// Selector Unit Control Selector\r\n#define SU_INPUT_SELECT_CONTROL             0x01\r\n\r\n// Media Tape Transport Control Selector\r\n#define MTT_CONTROL_UNDEFINED               0x00\r\n#define MTT_TRANSPORT_CONTROL               0x01\r\n#define MTT_ATN_INFORMATION_CONTROL         0x02\r\n#define MTT_MEDIA_INFORMATION_CONTROL       0x03\r\n#define MTT_TIME_CODE_INFORMATION_CONTROL   0x04\r\n\r\n// Media Transport Terminal States\r\n#define MTT_STATE_PLAY_NEXT_FRAME           0x00\r\n#define MTT_STATE_PLAY_FWD_SLOWEST          0x01\r\n#define MTT_STATE_PLAY_SLOW_FWD_4           0x02\r\n#define MTT_STATE_PLAY_SLOW_FWD_3           0x03\r\n#define MTT_STATE_PLAY_SLOW_FWD_2           0x04\r\n#define MTT_STATE_PLAY_SLOW_FWD_1           0x05\r\n#define MTT_STATE_PLAY_X1                   0x06\r\n#define MTT_STATE_PLAY_FAST_FWD_1           0x07\r\n#define MTT_STATE_PLAY_FAST_FWD_2           0x08\r\n#define MTT_STATE_PLAY_FAST_FWD_3           0x09\r\n#define MTT_STATE_PLAY_FAST_FWD_4           0x0A\r\n#define MTT_STATE_PLAY_FASTEST_FWD          0x0B\r\n#define MTT_STATE_PLAY_PREV_FRAME           0x0C\r\n#define MTT_STATE_PLAY_SLOWEST_REV          0x0D\r\n#define MTT_STATE_PLAY_SLOW_REV_4           0x0E\r\n#define MTT_STATE_PLAY_SLOW_REV_3           0x0F\r\n#define MTT_STATE_PLAY_SLOW_REV_2           0x10\r\n#define MTT_STATE_PLAY_SLOW_REV_1           0x11\r\n#define MTT_STATE_PLAY_REV                  0x12\r\n#define MTT_STATE_PLAY_FAST_REV_1           0x13\r\n#define MTT_STATE_PLAY_FAST_REV_2           0x14\r\n#define MTT_STATE_PLAY_FAST_REV_3           0x15\r\n#define MTT_STATE_PLAY_FAST_REV_4           0x16\r\n#define MTT_STATE_PLAY_FASTEST_REV          0x17\r\n#define MTT_STATE_PLAY                      0x18\r\n#define MTT_STATE_PAUSE                     0x19\r\n#define MTT_STATE_PLAY_REVERSE_PAUSE        0x1A\r\n\r\n\r\n#define MTT_STATE_STOP                      0x40\r\n#define MTT_STATE_FAST_FORWARD              0x41\r\n#define MTT_STATE_REWIND                    0x42\r\n#define MTT_STATE_HIGH_SPEED_REWIND         0x43\r\n\r\n#define MTT_STATE_RECORD_START              0x50\r\n#define MTT_STATE_RECORD_PAUSE              0x51\r\n\r\n#define MTT_STATE_EJECT                     0x60\r\n\r\n#define MTT_STATE_PLAY_SLOW_FWD_X           0x70\r\n#define MTT_STATE_PLAY_FAST_FWD_X           0x71\r\n#define MTT_STATE_PLAY_SLOW_REV_X           0x72\r\n#define MTT_STATE_PLAY_FAST_REV_X           0x73\r\n#define MTT_STATE_STOP_START                0x74\r\n#define MTT_STATE_STOP_END                  0x75\r\n#define MTT_STATE_STOP_EMERGENCY            0x76\r\n#define MTT_STATE_STOP_CONDENSATION         0x77\r\n#define MTT_STATE_UNSPECIFIED               0x7F\r\n\r\n// Video Control Interface Control Selectors\r\n#define VC_UNDEFINED_CONTROL            0x00\r\n#define VC_VIDEO_POWER_MODE_CONTROL     0x01\r\n#define VC_REQUEST_ERROR_CODE_CONTROL   0x02\r\n\r\n// VideoStreaming Interface Control Selectors\r\n#define VS_CONTROL_UNDEFINED            0x00\r\n#define VS_PROBE_CONTROL                0x01\r\n#define VS_COMMIT_CONTROL               0x02\r\n#define VS_STILL_PROBE_CONTROL          0x03\r\n#define VS_STILL_COMMIT_CONTROL         0x04\r\n#define VS_STILL_IMAGE_TRIGGER_CONTROL  0x05\r\n#define VS_STREAM_ERROR_CODE_CONTROL    0x06\r\n#define VS_GENERATE_KEY_FRAME_CONTROL   0x07\r\n#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08\r\n#define VS_SYNC_DELAY_CONTROL           0x09\r\n\r\n// Probe commit bitmap framing info\r\n#define VS_PROBE_COMMIT_BIT_FID 0x01\r\n#define VS_PROBE_COMMIT_BIT_EOF 0x02\r\n\r\n// Stream payload header Bit Field Header bits\r\n#define BFH_FID 0x01 // Frame ID bit\r\n#define BFH_EOF 0x02 // End of Frame bit\r\n#define BFH_PTS 0x04 // Presentation Time Stamp bit\r\n#define BFH_SCR 0x08 // Source Clock Reference bit\r\n#define BFH_RES 0x10 // Reserved bit\r\n#define BFH_STI 0x20 // Still image bit\r\n#define BFH_ERR 0x40 // Error bit\r\n#define BFH_EOH 0x80 // End of header bit\r\n\r\n#define HDR_LENGTH 1 // Length of header length field in bytes\r\n#define BFH_LENGTH 1 // Length of BFH field in bytes\r\n#define PTS_LENGTH 4 // Length of PTS field in bytes\r\n#define SCR_LENGTH 6 // Length of SCR field in bytes\r\n\r\n// USB Video Status Codes (Request Error Code Control)\r\n#define USBVIDEO_RE_STATUS_NOERROR          0x00\r\n#define USBVIDEO_RE_STATUS_NOT_READY        0x01\r\n#define USBVIDEO_RE_STATUS_WRONG_STATE      0x02\r\n#define USBVIDEO_RE_STATUS_POWER            0x03\r\n#define USBVIDEO_RE_STATUS_OUT_OF_RANGE     0x04\r\n#define USBVIDEO_RE_STATUS_INVALID_UNIT     0x05\r\n#define USBVIDEO_RE_STATUS_INVALID_CONTROL  0x06\r\n#define USBVIDEO_RE_STATUS_UNKNOWN          0x07\r\n\r\n// USB Video Device Status Codes (Stream Error Code Control)\r\n#define USBVIDEO_SE_STATUS_NOERROR                0x00\r\n#define USBVIDEO_SE_STATUS_PROTECTED_CONTENT      0x01\r\n#define USBVIDEO_SE_STATUS_INPUT_BUFFER_UNDERRUN  0x02\r\n#define USBVIDEO_SE_STATUS_DATA_DICONTINUITY      0x03\r\n#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_UNDERRUN 0x04\r\n#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_OVERRUN  0x05\r\n#define USBVIDEO_SE_STATUS_FORMAT_CHANGE          0x06\r\n#define USBVIDEO_SE_STATUS_STILL_IMAGE_ERROR      0x07\r\n#define USBVIDEO_SE_STATUS_UNKNOWN                0x08\r\n\r\n// Status Interrupt Types\r\n#define STATUS_INTERRUPT_VC 1\r\n#define STATUS_INTERRUPT_VS 2\r\n\r\n// Status Interrupt Attributes\r\n#define STATUS_INTERRUPT_ATTRIBUTE_VALUE          0x00\r\n#define STATUS_INTERRUPT_ATTRIBUTE_INFO           0x01\r\n#define STATUS_INTERRUPT_ATTRIBUTE_FAILURE        0x02\r\n\r\n// VideoStreaming interface interrupt types\r\n#define VS_INTERRUPT_EVENT_BUTTON_PRESS         0x00\r\n#define VS_INTERRUPT_VALUE_BUTTON_RELEASE       0x00\r\n#define VS_INTERRUPT_VALUE_BUTTON_PRESS         0x01\r\n\r\n// Get Info Values\r\n#define USBVIDEO_ASYNC_CONTROL    0x10\r\n#define USBVIDEO_SETTABLE_CONTROL 0x2\r\n\r\n#define MAX_INTERRUPT_PACKET_VALUE_SIZE 8\r\n\r\n// Frame descriptor frame interval array offsets\r\n#define MIN_FRAME_INTERVAL_OFFSET  0\r\n#define MAX_FRAME_INTERVAL_OFFSET  1\r\n#define FRAME_INTERVAL_STEP_OFFSET 2\r\n\r\n// Still image capture methods\r\n#define STILL_CAPTURE_METHOD_NONE 0\r\n#define STILL_CAPTURE_METHOD_1 1\r\n#define STILL_CAPTURE_METHOD_2 2\r\n#define STILL_CAPTURE_METHOD_3 3\r\n\r\n// Still image trigger control states\r\n#define STILL_IMAGE_TRIGGER_NORMAL         0\r\n#define STILL_IMAGE_TRIGGER_TRANSMIT       1\r\n#define STILL_IMAGE_TRIGGER_TRANSMIT_BULK  2\r\n#define STILL_IMAGE_TRIGGER_TRANSMIT_ABORT 3\r\n\r\n// Endpoint descriptor masks\r\n#define EP_DESCRIPTOR_TRANSACTION_SIZE_MASK 0x07ff\r\n#define EP_DESCRIPTOR_NUM_TRANSACTION_MASK  0x1800\r\n#define EP_DESCRIPTOR_NUM_TRANSACTION_OFFSET 11\r\n\r\n\r\n// Copy protection flag defined in the Uncompressed Payload Spec\r\n#define USB_VIDEO_UNCOMPRESSED_RESTRICT_DUPLICATION 1\r\n\r\n// Interlace flags\r\n#define INTERLACE_FLAGS_SUPPORTED_MASK         0x01\r\n#define INTERLACE_FLAGS_FIELDS_PER_FRAME_MASK  0x02\r\n#define INTERLACE_FLAGS_FIELDS_PER_FRAME_2     0x00\r\n#define INTERLACE_FLAGS_FIELDS_PER_FRAME_1     0x02\r\n#define INTERLACE_FLAGS_FIELD_1_FIRST_MASK     0x04\r\n#define INTERLACE_FLAGS_FIELD_PATTERN_MASK     0x30\r\n#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD1   0x00\r\n#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD2   0x10\r\n#define INTERLACE_FLAGS_FIELD_PATTERN_REGULAR  0x20\r\n#define INTERLACE_FLAGS_FIELD_PATTERN_RANDOM   0x30\r\n#define INTERLACE_FLAGS_DISPLAY_MODE_MASK      0xC0\r\n#define INTERLACE_FLAGS_DISPLAY_MODE_BOB       0x00\r\n#define INTERLACE_FLAGS_DISPLAY_MODE_WEAVE     0x40\r\n#define INTERLACE_FLAGS_DISPLAY_MODE_BOB_WEAVE 0x80\r\n\r\n// Color Matching Flags\r\n#define UVC_PRIMARIES_UNKNOWN            0x0\r\n#define UVC_PRIMARIES_BT709              0x1\r\n#define UVC_PRIMARIES_BT470_2M           0x2\r\n#define UVC_PRIMARIES_BT470_2BG          0x3\r\n#define UVC_PRIMARIES_SMPTE_170M         0x4\r\n#define UVC_PRIMARIES_SMPTE_240M         0x5\r\n\r\n#define UVC_GAMMA_UNKNOWN                0x0\r\n#define UVC_GAMMA_BT709                  0x1\r\n#define UVC_GAMMA_BT470_2M               0x2\r\n#define UVC_GAMMA_BT470_2BG              0x3\r\n#define UVC_GAMMA_SMPTE_170M             0x4\r\n#define UVC_GAMMA_SMPTE_240M             0x5\r\n#define UVC_GAMMA_LINEAR                 0x6\r\n#define UVC_GAMMA_sRGB                   0x7\r\n\r\n#define UVC_TRANSFER_MATRIX_UNKNOWN      0x0\r\n#define UVC_TRANSFER_MATRIX_BT709        0x1\r\n#define UVC_TRANSFER_MATRIX_FCC          0x2\r\n#define UVC_TRANSFER_MATRIX_BT470_2BG    0x3\r\n#define UVC_TRANSFER_MATRIX_BT601        0x4\r\n#define UVC_TRANSFER_MATRIX_SMPTE_240M   0x5\r\n\r\n//\r\n// BEGIN - VDC Descriptor and Control Structures\r\n//\r\n#pragma warning( disable : 4200 ) // Allow zero-sized arrays at end of structs\r\n#pragma pack( push, vdc_descriptor_structs, 1)\r\n\r\n// Video Specific Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // descriptor subtype\r\n} VIDEO_SPECIFIC, *PVIDEO_SPECIFIC;\r\n\r\n#define SIZEOF_VIDEO_SPECIFIC(pDesc) sizeof(VIDEO_SPECIFIC)\r\n\r\n\r\n// Video Unit Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // descriptor subtype\r\n    UCHAR bUnitID;              // Constant uniquely identifying the Unit\r\n} VIDEO_UNIT, *PVIDEO_UNIT;\r\n\r\n#define SIZEOF_VIDEO_UNIT(pDesc) sizeof(VIDEO_UNIT)\r\n\r\n// VideoControl Header Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // VC_HEADER descriptor subtype\r\n    USHORT bcdVideoSpec;        // USB video class spec revision number\r\n    USHORT wTotalLength;        // Total length, including all units and terminals\r\n    ULONG dwClockFreq;          // Device clock frequency in Hz\r\n    UCHAR bInCollection;        // number of video streaming interfaces\r\n    UCHAR baInterfaceNr[];      // interface number array\r\n} VIDEO_CONTROL_HEADER_UNIT, *PVIDEO_CONTROL_HEADER_UNIT;\r\n\r\n#define SIZEOF_VIDEO_CONTROL_HEADER_UNIT(pDesc) \\\r\n    ((sizeof(VIDEO_CONTROL_HEADER_UNIT) + (pDesc)->bInCollection))\r\n\r\n\r\n// VideoControl Input Terminal Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // INPUT_TERMINAL descriptor subtype\r\n    UCHAR bTerminalID;          // Constant uniquely identifying the Terminal\r\n    USHORT wTerminalType;       // Constant characterizing the terminal type\r\n    UCHAR bAssocTerminal;       // ID of associated output terminal\r\n    UCHAR iTerminal;            // Index of string descriptor\r\n} VIDEO_INPUT_TERMINAL, *PVIDEO_INPUT_TERMINAL;\r\n\r\n#define SIZEOF_VIDEO_INPUT_TERMINAL(pDesc) sizeof(VIDEO_INPUT_TERMINAL)\r\n\r\n\r\n// VideoControl Output Terminal Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // OUTPUT_TERMINAL descriptor subtype\r\n    UCHAR bTerminalID;          // Constant uniquely identifying the Terminal\r\n    USHORT wTerminalType;       // Constant characterizing the terminal type\r\n    UCHAR bAssocTerminal;       // ID of associated input terminal\r\n    UCHAR bSourceID;            // ID of source unit/terminal\r\n    UCHAR iTerminal;            // Index of string descriptor\r\n} VIDEO_OUTPUT_TERMINAL, *PVIDEO_OUTPUT_TERMINAL;\r\n\r\n#define SIZEOF_VIDEO_OUTPUT_TERMINAL(pDesc) sizeof(VIDEO_OUTPUT_TERMINAL)\r\n\r\n\r\n// VideoControl Camera Terminal Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // INPUT_TERMINAL descriptor subtype\r\n    UCHAR bTerminalID;          // Constant uniquely identifying the Terminal\r\n    USHORT wTerminalType;       // Sensor type\r\n    UCHAR bAssocTerminal;       // ID of associated output terminal\r\n    UCHAR iTerminal;            // Index of string descriptor\r\n    USHORT wObjectiveFocalLengthMin; // Min focal length for zoom\r\n    USHORT wObjectiveFocalLengthMax; // Max focal length for zoom\r\n    USHORT wOcularFocalLength;  // Ocular focal length for zoom\r\n    UCHAR bControlSize;         // Size of bmControls field\r\n    UCHAR bmControls[];         // Bitmap of controls supported\r\n} VIDEO_CAMERA_TERMINAL, *PVIDEO_CAMERA_TERMINAL;\r\n\r\n#define SIZEOF_VIDEO_CAMERA_TERMINAL(pDesc) \\\r\n    (sizeof(VIDEO_CAMERA_TERMINAL) + (pDesc)->bControlSize)\r\n\r\n\r\n// Media Transport Input Terminal Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // INPUT_TERMINAL descriptor subtype\r\n    UCHAR bTerminalID;          // Constant uniquely identifying the Terminal\r\n    USHORT wTerminalType;       // Media Transport type\r\n    UCHAR bAssocTerminal;       // ID of associated output terminal\r\n    UCHAR iTerminal;            // Index of string descriptor\r\n    UCHAR bControlSize;         // Size of bmControls field\r\n    UCHAR bmControls[];         // Bitmap of controls supported\r\n} VIDEO_INPUT_MTT, *PVIDEO_INPUT_MTT;\r\n\r\n\r\n__inline size_t SizeOfVideoInputMTT(_In_ PVIDEO_INPUT_MTT pDesc)\r\n{\r\n    UCHAR bTransportModeSize;\r\n    PUCHAR pbCurr;\r\n\r\n    pbCurr = pDesc->bmControls + pDesc->bControlSize;\r\n    bTransportModeSize = *pbCurr;\r\n\r\n    return sizeof(VIDEO_INPUT_MTT) + pDesc->bControlSize + 1 + bTransportModeSize;\r\n}\r\n\r\n#define SIZEOF_VIDEO_INPUT_MTT(pDesc) SizeOfVideoInputMTT(pDesc)\r\n\r\n\r\n// Media Transport Output Terminal Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // OUTPUT_TERMINAL descriptor subtype\r\n    UCHAR bTerminalID;          // Constant uniquely identifying the Terminal\r\n    USHORT wTerminalType;       // Media Transport type\r\n    UCHAR bAssocTerminal;       // ID of associated output terminal\r\n    UCHAR bSourceID;            // ID of source unit/terminal\r\n    UCHAR iTerminal;            // Index of string descriptor\r\n    UCHAR bControlSize;         // Size of bmControls field\r\n    UCHAR bmControls[];         // Bitmap of controls supported\r\n} VIDEO_OUTPUT_MTT, *PVIDEO_OUTPUT_MTT;\r\n\r\n\r\n__inline size_t SizeOfVideoOutputMTT(_In_ PVIDEO_OUTPUT_MTT pDesc)\r\n{\r\n    UCHAR bTransportModeSize;\r\n    PUCHAR pbCurr;\r\n\r\n    pbCurr = pDesc->bmControls + pDesc->bControlSize;\r\n    bTransportModeSize = *pbCurr;\r\n\r\n    return sizeof(VIDEO_OUTPUT_MTT) + pDesc->bControlSize + 1+ bTransportModeSize;\r\n}\r\n\r\n#define SIZEOF_VIDEO_OUTPUT_MTT(pDesc) SizeOfVideoOutputMTT(pDesc)\r\n\r\n\r\n// VideoControl Selector Unit Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // SELECTOR_UNIT descriptor subtype\r\n    UCHAR bUnitID;              // Constant uniquely identifying the Unit\r\n    UCHAR bNrInPins;            // Number of input pins\r\n    UCHAR baSourceID[];         // IDs of connected units/terminals\r\n} VIDEO_SELECTOR_UNIT, *PVIDEO_SELECTOR_UNIT;\r\n\r\n#define SIZEOF_VIDEO_SELECTOR_UNIT(pDesc) \\\r\n    (sizeof(VIDEO_SELECTOR_UNIT) + (pDesc)->bNrInPins + 1)\r\n\r\n\r\n// VideoControl Processing Unit Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // PROCESSING_UNIT descriptor subtype\r\n    UCHAR bUnitID;              // Constant uniquely identifying the Unit\r\n    UCHAR bSourceID;            // ID of connected unit/terminal\r\n    USHORT wMaxMultiplier;      // Maximum digital magnification\r\n    UCHAR bControlSize;         // Size of bmControls field\r\n    UCHAR bmControls[];         // Bitmap of controls supported\r\n} VIDEO_PROCESSING_UNIT, *PVIDEO_PROCESSING_UNIT;\r\n\r\n#define SIZEOF_VIDEO_PROCESSING_UNIT(pDesc) \\\r\n    (sizeof(VIDEO_PROCESSING_UNIT) + 1 + (pDesc)->bControlSize)\r\n\r\n\r\n// VideoControl Extension Unit Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // EXTENSION_UNIT descriptor subtype\r\n    UCHAR bUnitID;              // Constant uniquely identifying the Unit\r\n    GUID guidExtensionCode;     // Vendor-specific code identifying extension unit\r\n    UCHAR bNumControls;         // Number of controls in Extension Unit\r\n    UCHAR bNrInPins;            // Number of input pins\r\n    UCHAR baSourceID[];         // IDs of connected units/terminals\r\n} VIDEO_EXTENSION_UNIT, *PVIDEO_EXTENSION_UNIT;\r\n// this is followed by bControlSize, bmControls and iExtension (1 byte)\r\n\r\n__inline size_t SizeOfVideoExtensionUnit(PVIDEO_EXTENSION_UNIT pDesc)\r\n{\r\n    UCHAR bControlSize;\r\n    PUCHAR pbCurr;\r\n\r\n    // baSourceID is an array, and hence understood to be an address\r\n    pbCurr = pDesc->baSourceID + pDesc->bNrInPins;\r\n    if (((ULONG_PTR) pbCurr < (ULONG_PTR) pDesc->baSourceID) ||\r\n        (ULONG_PTR) pbCurr >= (ULONG_PTR)((UCHAR *) pDesc + pDesc->bLength))\r\n        return 0;\r\n\r\n    bControlSize = *pbCurr;\r\n    return 24 + pDesc->bNrInPins + bControlSize;\r\n}\r\n\r\n#define SIZEOF_VIDEO_EXTENSION_UNIT(pDesc) SizeOfVideoExtensionUnit(pDesc)\r\n\r\n\r\n// Class-specific Interrupt Endpoint Descriptor\r\ntypedef struct {\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_ENDPOINT descriptor type\r\n    UCHAR bDescriptorSubtype;   // EP_INTERRUPT descriptor subtype\r\n    USHORT wMaxTransferSize;    // Max interrupt payload size\r\n} VIDEO_CS_INTERRUPT, *PVIDEO_CS_INTERRUPT;\r\n\r\n#define SIZEOF_VIDEO_CS_INTERRUPT(pDesc) sizeof(VIDEO_CS_INTERRUPT)\r\n\r\n\r\n// VideoStreaming Input Header Descriptor\r\ntypedef struct _VIDEO_STREAMING_INPUT_HEADER\r\n{\r\n    UCHAR bLength;              // Size of this descriptor in bytes\r\n    UCHAR bDescriptorType;      // CS_INTERFACE descriptor type\r\n    UCHAR bDescriptorSubtype;   // VS_INPUT_HEADER descriptor subtype\r\n    UCHAR bNumFormats;\r\n    USHORT wTotalLength;\r\n    UCHAR bEndpointAddress;\r\n    UCHAR bmInfo;\r\n    UCHAR bTerminalLink;\r\n    UCHAR bStillCaptureMethod;\r\n    UCHAR bTriggerSupport;\r\n    UCHAR bTriggerUsage;\r\n    UCHAR bControlSize;\r\n    UCHAR bmaControls[];\r\n} VIDEO_STREAMING_INPUT_HEADER, *PVIDEO_STREAMING_INPUT_HEADER;\r\n\r\n#define SIZEOF_VIDEO_STREAMING_INPUT_HEADER(pDesc) \\\r\n    (sizeof(VIDEO_STREAMING_INPUT_HEADER) + (pDesc->bNumFormats * pDesc->bControlSize))\r\n\r\n\r\n// VideoStreaming Output Header Descriptor\r\ntypedef struct _VIDEO_STREAMING_OUTPUT_HEADER\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bNumFormats;\r\n    USHORT wTotalLength;\r\n    UCHAR bEndpointAddress;\r\n    UCHAR bTerminalLink;\r\n} VIDEO_STREAMING_OUTPUT_HEADER, *PVIDEO_STREAMING_OUTPUT_HEADER;\r\n\r\n#define SIZEOF_VIDEO_STREAMING_OUTPUT_HEADER(pDesc) sizeof(VIDEO_STREAMING_OUTPUT_HEADER)\r\n\r\n\r\ntypedef struct _VIDEO_STILL_IMAGE_RECT\r\n{\r\n    USHORT wWidth;\r\n    USHORT wHeight;\r\n} VIDEO_STILL_IMAGE_RECT;\r\n\r\n// VideoStreaming Still Image Frame Descriptor\r\ntypedef struct _VIDEO_STILL_IMAGE_FRAME\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bEndpointAddress;\r\n    UCHAR bNumImageSizePatterns;\r\n    VIDEO_STILL_IMAGE_RECT aStillRect[];\r\n} VIDEO_STILL_IMAGE_FRAME, *PVIDEO_STILL_IMAGE_FRAME;\r\n\r\n__inline size_t SizeOfVideoStillImageFrame(PVIDEO_STILL_IMAGE_FRAME pDesc)\r\n{\r\n    UCHAR bNumCompressionPatterns;\r\n    PUCHAR pbCurr;\r\n\r\n    pbCurr = (PUCHAR) pDesc->aStillRect + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns);\r\n    bNumCompressionPatterns = *pbCurr;\r\n\r\n    return (sizeof(VIDEO_STILL_IMAGE_FRAME) +\r\n           (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns) +\r\n           1 + bNumCompressionPatterns);\r\n}\r\n\r\n#define SIZEOF_VIDEO_STILL_IMAGE_FRAME(pDesc) SizeOfVideoStillImageFrame(pDesc)\r\n\r\n\r\n// VideoStreaming Color Matching Descriptor\r\ntypedef struct _VIDEO_COLORFORMAT\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bColorPrimaries;\r\n    UCHAR bTransferCharacteristics;\r\n    UCHAR bMatrixCoefficients;\r\n} VIDEO_COLORFORMAT, *PVIDEO_COLORFORMAT;\r\n\r\n#define SIZEOF_VIDEO_COLORFORMAT(pDesc) sizeof(VIDEO_COLORFORMAT)\r\n\r\n\r\n// VideoStreaming Uncompressed Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_UNCOMPRESSED\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bNumFrameDescriptors;\r\n    GUID guidFormat;\r\n    UCHAR bBitsPerPixel;\r\n    UCHAR bDefaultFrameIndex;\r\n    UCHAR bAspectRatioX;\r\n    UCHAR bAspectRatioY;\r\n    UCHAR bmInterlaceFlags;\r\n    UCHAR bCopyProtect;\r\n} VIDEO_FORMAT_UNCOMPRESSED, *PVIDEO_FORMAT_UNCOMPRESSED;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_UNCOMPRESSED(pDesc) sizeof(VIDEO_FORMAT_UNCOMPRESSED)\r\n\r\n\r\n// VideoStreaming Uncompressed Frame Descriptor\r\ntypedef struct _VIDEO_FRAME_UNCOMPRESSED\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFrameIndex;\r\n    UCHAR bmCapabilities;\r\n    USHORT wWidth;\r\n    USHORT wHeight;\r\n    ULONG dwMinBitRate;\r\n    ULONG dwMaxBitRate;\r\n    ULONG dwMaxVideoFrameBufferSize;\r\n    ULONG dwDefaultFrameInterval;\r\n    UCHAR bFrameIntervalType;\r\n    ULONG adwFrameInterval[];\r\n} VIDEO_FRAME_UNCOMPRESSED, *PVIDEO_FRAME_UNCOMPRESSED;\r\n\r\n\r\n__inline size_t SizeOfVideoFrameUncompressed(_In_ PVIDEO_FRAME_UNCOMPRESSED pDesc)\r\n{\r\n    if (pDesc->bFrameIntervalType == 0) { // Continuous\r\n        return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (3 * sizeof(ULONG));\r\n    }\r\n    else { // Discrete\r\n        return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (pDesc->bFrameIntervalType * sizeof(ULONG));\r\n    }\r\n}\r\n\r\n#define SIZEOF_VIDEO_FRAME_UNCOMPRESSED(pDesc) SizeOfVideoFrameUncompressed(pDesc)\r\n\r\n\r\n// VideoStreaming MJPEG Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_MJPEG\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bNumFrameDescriptors;\r\n    UCHAR bmFlags;\r\n    UCHAR bDefaultFrameIndex;\r\n    UCHAR bAspectRatioX;\r\n    UCHAR bAspectRatioY;\r\n    UCHAR bmInterlaceFlags;\r\n    UCHAR bCopyProtect;\r\n} VIDEO_FORMAT_MJPEG, *PVIDEO_FORMAT_MJPEG;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_MJPEG(pDesc) sizeof(VIDEO_FORMAT_MJPEG)\r\n\r\n\r\n// VideoStreaming MJPEG Frame Descriptor\r\ntypedef struct _VIDEO_FRAME_MJPEG\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFrameIndex;\r\n    UCHAR bmCapabilities;\r\n    USHORT wWidth;\r\n    USHORT wHeight;\r\n    ULONG dwMinBitRate;\r\n    ULONG dwMaxBitRate;\r\n    ULONG dwMaxVideoFrameBufferSize;\r\n    ULONG dwDefaultFrameInterval;\r\n    UCHAR bFrameIntervalType;\r\n    ULONG adwFrameInterval[];\r\n} VIDEO_FRAME_MJPEG, *PVIDEO_FRAME_MJPEG;\r\n\r\n\r\n__inline size_t SizeOfVideoFrameMjpeg(_In_ PVIDEO_FRAME_MJPEG pDesc)\r\n{\r\n    if (pDesc->bFrameIntervalType == 0) { // Continuous\r\n        return sizeof(VIDEO_FRAME_MJPEG) + (3 * sizeof(ULONG));\r\n    }\r\n    else { // Discrete\r\n        return sizeof(VIDEO_FRAME_MJPEG) + (pDesc->bFrameIntervalType * sizeof(ULONG));\r\n    }\r\n}\r\n\r\n#define SIZEOF_VIDEO_FRAME_MJPEG(pDesc) SizeOfVideoFrameMjpeg(pDesc)\r\n\r\n\r\n// VideoStreaming Vendor Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_VENDOR\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bNumFrameDescriptors;\r\n    GUID  guidMajorFormat;\r\n    GUID  guidSubFormat;\r\n    GUID  guidSpecifier;\r\n    UCHAR bPayloadClass;\r\n    UCHAR bDefaultFrameIndex;\r\n    UCHAR bCopyProtect;\r\n} VIDEO_FORMAT_VENDOR, *PVIDEO_FORMAT_VENDOR;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_VENDOR(pDesc) sizeof(VIDEO_FORMAT_VENDOR)\r\n\r\n\r\n// VideoStreaming Vendor Frame Descriptor\r\ntypedef struct _VIDEO_FRAME_VENDOR\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFrameIndex;\r\n    UCHAR bmCapabilities;\r\n    USHORT wWidth;\r\n    USHORT wHeight;\r\n    ULONG dwMinBitRate;\r\n    ULONG dwMaxBitRate;\r\n    ULONG dwMaxVideoFrameBufferSize;\r\n    ULONG dwDefaultFrameInterval;\r\n    UCHAR bFrameIntervalType;\r\n    DWORD adwFrameInterval[];\r\n} VIDEO_FRAME_VENDOR, *PVIDEO_FRAME_VENDOR;\r\n\r\n__inline size_t SizeOfVideoFrameVendor(_In_ PVIDEO_FRAME_VENDOR pDesc)\r\n{\r\n    if (pDesc->bFrameIntervalType == 0) { // Continuous\r\n        return sizeof(VIDEO_FRAME_VENDOR) + (3 * sizeof(ULONG));\r\n    }\r\n    else { // Discrete\r\n        return sizeof(VIDEO_FRAME_VENDOR) + (pDesc->bFrameIntervalType * sizeof(ULONG));\r\n    }\r\n}\r\n\r\n#define SIZEOF_VIDEO_FRAME_VENDOR(pDesc) SizeOfVideoFrameVendor(pDesc)\r\n\r\n\r\n// VideoStreaming DV Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_DV\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    ULONG dwMaxVideoFrameBufferSize;\r\n    UCHAR bFormatType;\r\n} VIDEO_FORMAT_DV, *PVIDEO_FORMAT_DV;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_DV(pDesc) sizeof(VIDEO_FORMAT_DV)\r\n\r\n\r\n// VideoStreaming MPEG2-TS Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_MPEG2TS\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bDataOffset;\r\n    UCHAR bPacketLength;\r\n    UCHAR bStrideLength;\r\n} VIDEO_FORMAT_MPEG2TS, *PVIDEO_FORMAT_MPEG2TS;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_MPEG2TS(pDesc) sizeof(VIDEO_FORMAT_MPEG2TS)\r\n\r\n\r\n// VideoStreaming MPEG1 System Stream Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_MPEG1SS\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bPacketLength;\r\n    UCHAR bPackLength;\r\n    UCHAR bPackDataType;\r\n} VIDEO_FORMAT_MPEG1SS, *PVIDEO_FORMAT_MPEG1SS;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_MPEG1SS(pDesc) sizeof(VIDEO_FORMAT_MPEG1SS)\r\n\r\n\r\n// VideoStreaming MPEG2-PS Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_MPEG2PS\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bPacketLength;\r\n    UCHAR bPackLength;\r\n    UCHAR bPackDataType;\r\n} VIDEO_FORMAT_MPEG2PS, *PVIDEO_FORMAT_MPEG2PS;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_MPEG2PS(pDesc) sizeof(VIDEO_FORMAT_MPEG2PS)\r\n\r\n\r\n// VideoStreaming MPEG4-SL Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_MPEG4SL\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bPacketLength;\r\n} VIDEO_FORMAT_MPEG4SL, *PVIDEO_FORMAT_MPEG4SL;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_MPEG4SL(pDesc) sizeof(VIDEO_FORMAT_MPEG4SL)\r\n\r\n// VideoStreaming Probe/Commit Control\r\ntypedef struct _VS_PROBE_COMMIT_CONTROL\r\n{\r\n    USHORT bmHint;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bFrameIndex;\r\n    ULONG dwFrameInterval;\r\n    USHORT wKeyFrameRate;\r\n    USHORT wPFrameRate;\r\n    USHORT wCompQuality;\r\n    USHORT wCompWindowSize;\r\n    USHORT wDelay;\r\n    ULONG dwMaxVideoFrameSize;\r\n    ULONG dwMaxPayloadTransferSize;\r\n} VS_PROBE_COMMIT_CONTROL, *PVS_PROBE_COMMIT_CONTROL;\r\n\r\n// VideoStreaming Still Probe/Commit Control\r\ntypedef struct _VS_STILL_PROBE_COMMIT_CONTROL\r\n{\r\n    UCHAR bFormatIndex;\r\n    UCHAR bFrameIndex;\r\n    UCHAR bCompressionIndex;\r\n    ULONG dwMaxVideoFrameSize;\r\n    ULONG dwMaxPayloadTransferSize;\r\n} VS_STILL_PROBE_COMMIT_CONTROL, *PVS_STILL_PROBE_COMMIT_CONTROL;\r\n\r\n\r\n// Status Interrupt Packet (Video Control)\r\ntypedef struct _VC_INTERRUPT_PACKET\r\n{\r\n    UCHAR bStatusType;\r\n    UCHAR bOriginator;\r\n    UCHAR bEvent;\r\n    UCHAR bSelector;\r\n    UCHAR bAttribute;\r\n    UCHAR bValue[1];\r\n} VC_INTERRUPT_PACKET, *PVC_INTERRUPT_PACKET;\r\n\r\n// Status Interrupt Packet (Video Control)\r\ntypedef struct _VC_INTERRUPT_PACKET_EX\r\n{\r\n    UCHAR bStatusType;\r\n    UCHAR bOriginator;\r\n    UCHAR bEvent;\r\n    UCHAR bSelector;\r\n    UCHAR bAttribute;\r\n    UCHAR bValue[MAX_INTERRUPT_PACKET_VALUE_SIZE];\r\n} VC_INTERRUPT_PACKET_EX, *PVC_INTERRUPT_PACKET_EX;\r\n\r\n// Status Interrupt Packet (Video Streaming)\r\ntypedef struct _VS_INTERRUPT_PACKET\r\n{\r\n    UCHAR bStatusType;\r\n    UCHAR bOriginator;\r\n    UCHAR bEvent;\r\n    UCHAR bValue[1];\r\n} VS_INTERRUPT_PACKET, *PVS_INTERRUPT_PACKET;\r\n\r\n// Status Interrupt Packet (Generic)\r\ntypedef struct _VIDEO_INTERRUPT_PACKET\r\n{\r\n    UCHAR bStatusType;\r\n    UCHAR bOriginator;\r\n} VIDEO_INTERRUPT_PACKET, *PVIDEO_INTERRUPT_PACKET;\r\n\r\n\r\n// Relative property struct\r\ntypedef struct _VIDEO_RELATIVE_PROPERTY\r\n{\r\n    UCHAR bValue;\r\n    UCHAR bSpeed;\r\n} VIDEO_RELATIVE_PROPERTY, *PVIDEO_RELATIVE_PROPERTY;\r\n\r\n// Relative Zoom control struct\r\ntypedef struct _ZOOM_RELATIVE_PROPERTY\r\n{\r\n    UCHAR bZoom;\r\n    UCHAR bDigitalZoom;\r\n    UCHAR bSpeed;\r\n} ZOOM_RELATIVE_PROPERTY, *PZOOM_RELATIVE_PROPERTY;\r\n\r\n// Relative pan-tilt struct\r\ntypedef struct _PANTILT_RELATIVE_PROPERTY\r\n{\r\n    UCHAR bPanRelative;\r\n    UCHAR bPanSpeed;\r\n    UCHAR bTiltRelative;\r\n    UCHAR bTiltSpeed;\r\n} PANTILT_RELATIVE_PROPERTY, *PPANTILT_RELATIVE_PROPERTY;\r\n\r\ntypedef struct _MEDIA_INFORMATION_CONTROL\r\n{\r\n    UCHAR bmMediaType;\r\n    UCHAR bmWriteProtect;\r\n} MEDIA_INFORMATION_CONTROL, *PMEDIA_INFORMATION_CONTROL;\r\n\r\ntypedef struct _TIME_CODE_INFORMATION_CONTROL\r\n{\r\n    UCHAR bcdFrame;\r\n    UCHAR bcdSecond;\r\n    UCHAR bcdMinute;\r\n    UCHAR bcdHour;\r\n} TIME_CODE_INFORMATION_CONTROL, *PTIME_CODE_INFORMATION_CONTROL;\r\n\r\ntypedef struct _ATN_INFORMATION_CONTROL\r\n{\r\n    UCHAR bmMediaType;\r\n    DWORD dwATN_Data;\r\n} ATN_INFORMATION_CONTROL, *PATN_INFORMATION_CONTROL;\r\n\r\n#define VS_FORMAT_FRAME_BASED   0x10\r\n#define VS_FRAME_FRAME_BASED    0x11\r\n#define VS_FORMAT_STREAM_BASED  0x12\r\n\r\n// Format Descriptor for UVC 1.1 frame based format\r\ntypedef struct _VIDEO_FORMAT_FRAME\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bNumFrameDescriptors;\r\n    GUID guidFormat;\r\n    UCHAR bBitsPerPixel;\r\n    UCHAR bDefaultFrameIndex;\r\n    UCHAR bAspectRatioX;\r\n    UCHAR bAspectRatioY;\r\n    UCHAR bmInterlaceFlags;\r\n    UCHAR bCopyProtect;\r\n    UCHAR bVariableSize;\r\n} VIDEO_FORMAT_FRAME, *PVIDEO_FORMAT_FRAME;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_FRAME(pDesc) sizeof(VIDEO_FORMAT_FRAME)\r\n\r\n\r\n// Frame Descriptor for UVC 1.1 frame based format\r\ntypedef struct _VIDEO_FRAME_FRAME\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFrameIndex;\r\n    UCHAR bmCapabilities;\r\n    USHORT wWidth;\r\n    USHORT wHeight;\r\n    ULONG dwMinBitRate;\r\n    ULONG dwMaxBitRate;\r\n    ULONG dwDefaultFrameInterval;\r\n    UCHAR bFrameIntervalType;\r\n    ULONG dwBytesPerLine;\r\n    ULONG adwFrameInterval[];\r\n} VIDEO_FRAME_FRAME, *PVIDEO_FRAME_FRAME;\r\n\r\n__inline size_t SizeOfVideoFrameFrame(_In_ PVIDEO_FRAME_FRAME pDesc)\r\n{\r\n    if (pDesc->bFrameIntervalType == 0) { // Continuous\r\n        return sizeof(VIDEO_FRAME_FRAME) + (3 * sizeof(ULONG));\r\n    }\r\n    else { // Discrete\r\n        return sizeof(VIDEO_FRAME_FRAME) + (pDesc->bFrameIntervalType * sizeof(ULONG));\r\n    }\r\n}\r\n\r\n#define SIZEOF_VIDEO_FRAME_FRAME(pDesc) SizeOfVideoFrameFrame(pDesc)\r\n\r\n// VideoStreaming Stream Based Format Descriptor\r\ntypedef struct _VIDEO_FORMAT_STREAM\r\n{\r\n    UCHAR bLength;\r\n    UCHAR bDescriptorType;\r\n    UCHAR bDescriptorSubtype;\r\n    UCHAR bFormatIndex;\r\n    GUID guidFormat;\r\n    ULONG dwPacketLength;\r\n} VIDEO_FORMAT_STREAM, *PVIDEO_FORMAT_STREAM;\r\n\r\n#define SIZEOF_VIDEO_FORMAT_STREAM(pDesc) sizeof(VIDEO_FORMAT_STREAM)\r\n\r\n// VideoStreaming Probe/Commit Control\r\ntypedef struct _VS_PROBE_COMMIT_CONTROL2\r\n{\r\n    USHORT bmHint;\r\n    UCHAR bFormatIndex;\r\n    UCHAR bFrameIndex;\r\n    ULONG dwFrameInterval;\r\n    USHORT wKeyFrameRate;\r\n    USHORT wPFrameRate;\r\n    USHORT wCompQuality;\r\n    USHORT wCompWindowSize;\r\n    USHORT wDelay;\r\n    ULONG dwMaxVideoFrameSize;\r\n    ULONG dwMaxPayloadTransferSize;\r\n    ULONG dwClockFrequency;\r\n    UCHAR bmFramingInfo;\r\n    UCHAR bPreferredVersion;\r\n    UCHAR bMinVersion;\r\n    UCHAR bMaxVersion;\r\n} VS_PROBE_COMMIT_CONTROL2, *PVS_PROBE_COMMIT_CONTROL2;\r\n\r\n#pragma pack( pop, vdc_descriptor_structs )\r\n#pragma warning( default : 4200 )\r\n\r\n\r\n//\r\n// END - VDC Descriptor and Control Structures\r\n//\r\n\r\n#endif // ___UVCDESC_H___\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/uvcview.c",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2011 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\nUSBVIEW.C\r\n\r\nAbstract:\r\n\r\nThis is the GUI goop for the USBVIEW application.\r\n\r\nEnvironment:\r\n\r\nuser mode\r\n\r\nRevision History:\r\n\r\n04-25-97 : created\r\n11-20-02 : minor changes to support more reporting options\r\n04/13/2005 : major bug fixing\r\n07/01/2008 : add UVC 1.1 support and move to Dev branch\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\nI N C L U D E S\r\n*****************************************************************************/\r\n\r\n#include \"resource.h\"\r\n#include \"uvcview.h\"\r\n#include \"h264.h\"\r\n#include \"xmlhelper.h\"\r\n\r\n#include <commdlg.h>\r\n\r\n\r\n/*****************************************************************************\r\nD E F I N E S\r\n*****************************************************************************/\r\n\r\n// window control defines\r\n//\r\n#define SIZEBAR             0\r\n#define WINDOWSCALEFACTOR   15\r\n\r\n/*****************************************************************************\r\n L O C A L  T Y P E D E F S\r\n*****************************************************************************/\r\ntypedef struct _TREEITEMINFO\r\n{\r\n    struct _TREEITEMINFO *Next;\r\n    USHORT Depth;\r\n    PCHAR Name;\r\n\r\n} TREEITEMINFO, *PTREEITEMINFO;\r\n\r\n\r\n/*****************************************************************************\r\nL O C A L    E N U M S\r\n*****************************************************************************/\r\n\r\ntypedef enum _USBVIEW_SAVE_FILE_TYPE\r\n{\r\n    UsbViewNone = 0,\r\n    UsbViewXmlFile,\r\n    UsbViewTxtFile\r\n} USBVIEW_SAVE_FILE_TYPE;\r\n\r\n/*****************************************************************************\r\nL O C A L    F U N C T I O N    P R O T O T Y P E S\r\n*****************************************************************************/\r\n\r\nint WINAPI\r\nWinMain (\r\n         _In_ HINSTANCE hInstance,\r\n         _In_opt_ HINSTANCE hPrevInstance,\r\n         _In_ LPSTR lpszCmdLine,\r\n         _In_ int nCmdShow\r\n         );\r\n\r\nBOOL\r\nCreateMainWindow (\r\n                  int nCmdShow\r\n                  );\r\n\r\nVOID\r\nResizeWindows (\r\n               BOOL    bSizeBar,\r\n               int     BarLocation\r\n               );\r\n\r\nLRESULT CALLBACK\r\nMainDlgProc (\r\n             HWND   hwnd,\r\n             UINT   uMsg,\r\n             WPARAM wParam,\r\n             LPARAM lParam\r\n             );\r\n\r\nBOOL\r\nUSBView_OnInitDialog (\r\n                      HWND    hWnd,\r\n                      HWND    hWndFocus,\r\n                      LPARAM  lParam\r\n                      );\r\n\r\nVOID\r\nUSBView_OnClose (\r\n                 HWND hWnd\r\n                 );\r\n\r\nVOID\r\nUSBView_OnCommand (\r\n                   HWND hWnd,\r\n                   int  id,\r\n                   HWND hwndCtl,\r\n                   UINT codeNotify\r\n                   );\r\n\r\nVOID\r\nUSBView_OnLButtonDown (\r\n                       HWND hWnd,\r\n                       BOOL fDoubleClick,\r\n                       int  x,\r\n                       int  y,\r\n                       UINT keyFlags\r\n                       );\r\n\r\nVOID\r\nUSBView_OnLButtonUp (\r\n                     HWND hWnd,\r\n                     int  x,\r\n                     int  y,\r\n                     UINT keyFlags\r\n                     );\r\n\r\nVOID\r\nUSBView_OnMouseMove (\r\n                     HWND hWnd,\r\n                     int  x,\r\n                     int  y,\r\n                     UINT keyFlags\r\n                     );\r\n\r\nVOID\r\nUSBView_OnSize (\r\n                HWND hWnd,\r\n                UINT state,\r\n                int  cx,\r\n                int  cy\r\n                );\r\n\r\nLRESULT\r\nUSBView_OnNotify (\r\n                  HWND    hWnd,\r\n                  int     DlgItem,\r\n                  LPNMHDR lpNMHdr\r\n                  );\r\n\r\nBOOL\r\nUSBView_OnDeviceChange (\r\n                        HWND  hwnd,\r\n                        UINT  uEvent,\r\n                        DWORD dwEventData\r\n                        );\r\n\r\nVOID DestroyTree (VOID);\r\n\r\nVOID RefreshTree (VOID);\r\n\r\nLRESULT CALLBACK\r\nAboutDlgProc (\r\n              HWND   hwnd,\r\n              UINT   uMsg,\r\n              WPARAM wParam,\r\n              LPARAM lParam\r\n              );\r\n\r\nVOID\r\nWalkTree (\r\n          _In_ HTREEITEM        hTreeItem,\r\n          _In_ LPFNTREECALLBACK lpfnTreeCallback,\r\n          _In_opt_ PVOID            pContext\r\n          );\r\n\r\nVOID\r\nExpandItem (\r\n            HWND      hTreeWnd,\r\n            HTREEITEM hTreeItem,\r\n            PVOID     pContext\r\n            );\r\n\r\nVOID\r\nAddItemInformationToFile(\r\n            HWND hTreeWnd,\r\n            HTREEITEM hTreeItem,\r\n            PVOID pContext\r\n        );\r\n\r\nDWORD\r\nDisplayLastError(\r\n          _Inout_updates_bytes_(count) char    *szString,\r\n          int     count);\r\n\r\nVOID AddItemInformationToXmlView(\r\n    HWND hTreeWnd,\r\n    HTREEITEM hTreeItem,\r\n    PVOID pContext\r\n    );\r\nHRESULT InitializeConsole();\r\nVOID UnInitializeConsole();\r\nBOOL IsStdOutFile();\r\nVOID DisplayMessage(DWORD dwMsgId, ...);\r\nVOID PrintString(LPTSTR lpszString);\r\nLPTSTR WStringToAnsiString(LPWSTR lpwszString);\r\nVOID WaitForKeyPress();\r\nBOOL ProcessCommandLine();\r\nHRESULT ProcessCommandSaveFile(LPTSTR szFileName, DWORD dwCreationDisposition, USBVIEW_SAVE_FILE_TYPE fileType);\r\nHRESULT SaveAllInformationAsText(LPTSTR lpstrTextFileName, DWORD dwCreationDisposition);\r\nHRESULT SaveAllInformationAsXml(LPTSTR lpstrTextFileName , DWORD dwCreationDisposition);\r\n\r\n/*****************************************************************************\r\nG L O B A L S\r\n*****************************************************************************/\r\nBOOL gDoConfigDesc = TRUE;\r\nBOOL gDoAnnotation = TRUE;\r\nBOOL gLogDebug     = FALSE;\r\nint  TotalHubs     = 0;\r\n\r\nextern DEVICE_GUID_LIST gHubList;\r\nextern DEVICE_GUID_LIST gDeviceList;\r\n\r\n/*****************************************************************************\r\nG L O B A L S    P R I V A T E    T O    T H I S    F I L E\r\n*****************************************************************************/\r\n\r\nHINSTANCE       ghInstance       = NULL;\r\nHWND            ghMainWnd        = NULL;\r\nHWND            ghTreeWnd        = NULL;\r\nHWND            ghEditWnd        = NULL;\r\nHWND            ghStatusWnd      = NULL;\r\nHMENU           ghMainMenu       = NULL;\r\nHTREEITEM       ghTreeRoot       = NULL;\r\nHCURSOR         ghSplitCursor    = NULL;\r\nHDEVNOTIFY      gNotifyDevHandle = NULL;\r\nHDEVNOTIFY      gNotifyHubHandle = NULL;\r\nHANDLE          ghStdOut         = NULL;\r\n\r\nBOOL            gbConsoleFile  = FALSE;\r\nBOOL            gbConsoleInitialized = FALSE;\r\nBOOL            gbButtonDown     = FALSE;\r\nBOOL            gDoAutoRefresh   = TRUE;\r\n\r\nint             gBarLocation     = 0;\r\nint             giGoodDevice     = 0;\r\nint             giBadDevice      = 0;\r\nint             giComputer       = 0;\r\nint             giHub            = 0;\r\nint             giNoDevice       = 0;\r\nint             giGoodSsDevice   = 0;\r\nint             giNoSsDevice     = 0;\r\n\r\n\r\n/*****************************************************************************\r\n\r\nWinMain()\r\n\r\n*****************************************************************************/\r\n\r\nint WINAPI\r\nWinMain (\r\n         _In_ HINSTANCE hInstance,\r\n         _In_opt_ HINSTANCE hPrevInstance,\r\n         _In_ LPSTR lpszCmdLine,\r\n         _In_ int nCmdShow\r\n         )\r\n{\r\n    MSG     msg;\r\n    HACCEL  hAccel;\r\n    int retStatus = 0;\r\n\r\n    UNREFERENCED_PARAMETER(hPrevInstance);\r\n    UNREFERENCED_PARAMETER(lpszCmdLine);\r\n\r\n    InitXmlHelper();\r\n\r\n    ghInstance = hInstance;\r\n\r\n    ghSplitCursor = LoadCursor(ghInstance,\r\n        MAKEINTRESOURCE(IDC_SPLIT));\r\n\r\n    if (!ghSplitCursor)\r\n    {\r\n        OOPS();\r\n        return retStatus;\r\n    }\r\n\r\n    hAccel = LoadAccelerators(ghInstance,\r\n        MAKEINTRESOURCE(IDACCEL));\r\n\r\n    if (!hAccel)\r\n    {\r\n        OOPS();\r\n        return retStatus;\r\n    }\r\n\r\n    if (!CreateTextBuffer())\r\n    {\r\n        return retStatus;\r\n    }\r\n\r\n    if (!ProcessCommandLine())\r\n    {\r\n        // There were no command line flags, open GUI\r\n        if (CreateMainWindow(nCmdShow))\r\n        {\r\n            while (GetMessage(&msg, NULL, 0, 0))\r\n            {\r\n                if (!TranslateAccelerator(ghMainWnd,\r\n                            hAccel,\r\n                            &msg) &&\r\n                        !IsDialogMessage(ghMainWnd,\r\n                            &msg))\r\n                {\r\n                    TranslateMessage(&msg);\r\n                    DispatchMessage(&msg);\r\n                }\r\n            }\r\n            retStatus = 1;\r\n        }\r\n    }\r\n\r\n    DestroyTextBuffer();\r\n\r\n    ReleaseXmlWriter();\r\n\r\n    CHECKFORLEAKS();\r\n\r\n    return retStatus;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nProcessCommandLine()\r\n\r\nParses the command line and takes appropriate actions. Returns FALSE If there is no action to\r\nperform\r\n*****************************************************************************/\r\nBOOL ProcessCommandLine()\r\n{\r\n    LPWSTR *szArgList = NULL;\r\n    LPTSTR szArg = NULL;\r\n    LPTSTR szAnsiArg= NULL;\r\n    BOOL quietMode = FALSE;\r\n\r\n    HRESULT hr = S_OK;\r\n    DWORD dwCreationDisposition = CREATE_NEW;\r\n    USBVIEW_SAVE_FILE_TYPE fileType = UsbViewNone;\r\n\r\n    int nArgs = 0;\r\n    int i = 0;\r\n    BOOL bStatus = FALSE;\r\n    BOOL bStopArgProcessing = FALSE;\r\n\r\n    szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);\r\n\r\n    // If there are no arguments we return false\r\n    bStatus = (nArgs > 1)? TRUE:FALSE;\r\n\r\n    if (NULL != szArgList)\r\n    {\r\n        if (nArgs > 1)\r\n        {\r\n            // If there are arguments, initialize console for ouput\r\n            InitializeConsole();\r\n        }\r\n\r\n        for (i = 1; (i < nArgs) && (bStopArgProcessing == FALSE); i++)\r\n        {\r\n            // Convert argument to ANSI string for futher processing\r\n\r\n            szAnsiArg = WStringToAnsiString(szArgList[i]);\r\n\r\n            if(NULL == szAnsiArg)\r\n            {\r\n                DisplayMessage(IDS_USBVIEW_INVALIDARG, szAnsiArg);\r\n                DisplayMessage(IDS_USBVIEW_USAGE);\r\n                break;\r\n            }\r\n\r\n            if (0 == _stricmp(szAnsiArg, \"/?\"))\r\n            {\r\n                DisplayMessage(IDS_USBVIEW_USAGE);\r\n                break;\r\n            }\r\n            else if (NULL != StrStrI(szAnsiArg, \"/saveall:\"))\r\n            {\r\n                fileType = UsbViewTxtFile;\r\n            }\r\n            else if (NULL != StrStrI(szAnsiArg, \"/savexml:\"))\r\n            {\r\n                fileType = UsbViewXmlFile;\r\n            }\r\n            else if (0 == _stricmp(szAnsiArg, \"/f\"))\r\n            {\r\n                dwCreationDisposition = CREATE_ALWAYS;\r\n            }\r\n            else if (0 == _stricmp(szAnsiArg, \"/q\"))\r\n            {\r\n                quietMode = TRUE;\r\n            }\r\n            else\r\n            {\r\n                DisplayMessage(IDS_USBVIEW_INVALIDARG, szAnsiArg);\r\n                DisplayMessage(IDS_USBVIEW_USAGE);\r\n                bStopArgProcessing = TRUE;\r\n            }\r\n\r\n            if (fileType != UsbViewNone)\r\n            {\r\n                // Save view information as to file\r\n                szArg = strchr(szAnsiArg, ':');\r\n\r\n                if (NULL == szArg || strlen(szArg) == 1)\r\n                {\r\n                    // No ':' or just a ':'\r\n                    DisplayMessage(IDS_USBVIEW_INVALID_FILENAME, szAnsiArg);\r\n                    DisplayMessage(IDS_USBVIEW_USAGE);\r\n                    bStopArgProcessing = TRUE;\r\n                }\r\n                else\r\n                {\r\n                    hr = ProcessCommandSaveFile(szArg + 1, dwCreationDisposition, fileType);\r\n\r\n                    if (FAILED(hr))\r\n                    {\r\n                        // No more processing\r\n                        bStopArgProcessing = TRUE;\r\n                    }\r\n\r\n                    fileType = UsbViewNone;\r\n                }\r\n            }\r\n\r\n            if (NULL != szAnsiArg)\r\n            {\r\n                LocalFree(szAnsiArg);\r\n            }\r\n        }\r\n\r\n        if(!quietMode)\r\n        {\r\n            WaitForKeyPress();\r\n        }\r\n\r\n        if (gbConsoleInitialized)\r\n        {\r\n            UnInitializeConsole();\r\n        }\r\n\r\n        LocalFree(szArgList);\r\n    }\r\n    return bStatus;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nProcessCommandSaveFile()\r\n\r\nProcess the save file command line\r\n\r\n*****************************************************************************/\r\nHRESULT ProcessCommandSaveFile(LPTSTR szFileName, DWORD dwCreationDisposition, USBVIEW_SAVE_FILE_TYPE fileType)\r\n{\r\n    HRESULT hr = S_OK;\r\n    LPTSTR szErrorBuffer = NULL;\r\n\r\n    if (UsbViewNone == fileType || NULL == szFileName)\r\n    {\r\n        hr = E_INVALIDARG;\r\n        // Invalid arguments, return\r\n        return (hr);\r\n    }\r\n\r\n    // The UI is not created yet, open the UI, but HIDE it\r\n    CreateMainWindow(SW_HIDE);\r\n\r\n    if (UsbViewXmlFile == fileType)\r\n    {\r\n        hr = SaveAllInformationAsXml(szFileName, dwCreationDisposition);\r\n    }\r\n\r\n    if (UsbViewTxtFile == fileType)\r\n    {\r\n        hr = SaveAllInformationAsText(szFileName, dwCreationDisposition);\r\n    }\r\n\r\n    if (FAILED(hr))\r\n    {\r\n        if (GetLastError() == ERROR_FILE_EXISTS || hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS))\r\n        {\r\n            // The operation failed because the file we tried to write to already existed and '/f' option\r\n            // was not present. Display error message to user describing '/f' option\r\n            switch(fileType)\r\n            {\r\n                case UsbViewXmlFile:\r\n                    DisplayMessage(IDS_USBVIEW_FILE_EXISTS_XML, szFileName);\r\n                    break;\r\n                case UsbViewTxtFile:\r\n                    DisplayMessage(IDS_USBVIEW_FILE_EXISTS_TXT, szFileName);\r\n                    break;\r\n                default:\r\n                    DisplayMessage(IDS_USBVIEW_INTERNAL_ERROR);\r\n                    break;\r\n            }\r\n        }\r\n        else\r\n        {\r\n            // Try to obtain system error message\r\n            FormatMessage(\r\n                    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,\r\n                    NULL,\r\n                    hr,\r\n                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r\n                    (LPTSTR) &szErrorBuffer,        // FormatMessage expects this buffer to be cast as LPTSTR\r\n                    0,\r\n                    NULL);\r\n            PrintString(\"Unable to save file.\\n\");\r\n            PrintString(szErrorBuffer);\r\n            LocalFree(szErrorBuffer);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // Display file saved to message in console\r\n        DisplayMessage(IDS_USBVIEW_SAVED_TO, szFileName);\r\n    }\r\n\r\n    return (hr);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nInitializeConsole()\r\n\r\nInitializes the std output in console\r\n\r\n*****************************************************************************/\r\nHRESULT InitializeConsole()\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    SetLastError(0);\r\n\r\n    // Find if STD_OUTPUT is a console or has been redirected to a File\r\n    gbConsoleFile = IsStdOutFile();\r\n\r\n    if (!gbConsoleFile)\r\n    {\r\n        // Output is not redirected and GUI application do not have console by default, create a console\r\n        if(AllocConsole())\r\n        {\r\n#pragma warning(disable:4996) // We don' need the FILE * returned by freopen\r\n            // Reopen STDOUT , STDIN and STDERR\r\n            if((freopen(\"conout$\", \"w\", stdout) != NULL) &&\r\n                    (freopen(\"conin$\", \"r\", stdin)  != NULL) &&\r\n                    (freopen(\"conout$\",\"w\", stderr) != NULL))\r\n            {\r\n                gbConsoleInitialized = TRUE;\r\n                ghStdOut = GetStdHandle(STD_OUTPUT_HANDLE);\r\n            }\r\n#pragma warning(default:4996)\r\n        }\r\n    }\r\n\r\n    if (INVALID_HANDLE_VALUE == ghStdOut || FALSE == gbConsoleInitialized)\r\n    {\r\n        hr = HRESULT_FROM_WIN32(GetLastError());\r\n        OOPS();\r\n    }\r\n    return hr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUnInitializeConsole()\r\n\r\nUnInitializes the console\r\n\r\n*****************************************************************************/\r\nVOID UnInitializeConsole()\r\n{\r\n    gbConsoleInitialized = FALSE;\r\n    FreeConsole();\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nIsStdOutFile()\r\n\r\nFinds if the STD_OUTPUT has been redirected to a file\r\n*****************************************************************************/\r\nBOOL IsStdOutFile()\r\n{\r\n    unsigned htype;\r\n    HANDLE hFile;\r\n\r\n    // 1 = STDOUT\r\n    hFile = (HANDLE) _get_osfhandle(1);\r\n    htype = GetFileType(hFile);\r\n    htype &= ~FILE_TYPE_REMOTE;\r\n\r\n\r\n    // Check if file type is character file\r\n    if (FILE_TYPE_DISK == htype)\r\n    {\r\n        return TRUE;\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDisplayMessage()\r\n\r\nDisplays a message to standard output\r\n*****************************************************************************/\r\nVOID DisplayMessage(DWORD dwResId, ...)\r\n{\r\n    CHAR szFormat[4096];\r\n    HRESULT hr = S_OK;\r\n    LPTSTR lpszMessage = NULL;\r\n    DWORD dwLen = 0;\r\n    va_list ap;\r\n\r\n    va_start(ap, dwResId);\r\n\r\n    // Initialize console if needed\r\n    if (!gbConsoleInitialized)\r\n    {\r\n        hr = InitializeConsole();\r\n        if (FAILED(hr))\r\n        {\r\n            OOPS();\r\n            return;\r\n        }\r\n    }\r\n\r\n    // Load the string resource\r\n    dwLen = LoadString(GetModuleHandle(NULL),\r\n            dwResId,\r\n            szFormat,\r\n            ARRAYSIZE(szFormat)\r\n            );\r\n\r\n    if(0 == dwLen)\r\n    {\r\n        PrintString(\"Unable to find message for given resource ID\");\r\n\r\n        // Return if resource ID could not be found\r\n        return;\r\n    }\r\n\r\n    dwLen = FormatMessage(\r\n                FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,\r\n                szFormat,\r\n                dwResId,\r\n                0,\r\n                (LPTSTR) &lpszMessage,\r\n                ARRAYSIZE(szFormat),\r\n                &ap);\r\n\r\n    if (dwLen > 0)\r\n    {\r\n        PrintString(lpszMessage);\r\n        LocalFree(lpszMessage);\r\n    }\r\n    else\r\n    {\r\n        PrintString(\"Unable to find message for given ID\");\r\n    }\r\n\r\n    va_end(ap);\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nWStringToAnsiString()\r\n\r\nConverts the Wide char string to ANSI string and returns the allocated ANSI string.\r\n*****************************************************************************/\r\nLPTSTR WStringToAnsiString(LPWSTR lpwszString)\r\n{\r\n    int strLen = 0;\r\n    LPTSTR szAnsiBuffer = NULL;\r\n\r\n    szAnsiBuffer = LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(CHAR));\r\n\r\n    // Convert string from from WCHAR to ANSI\r\n    if (NULL != szAnsiBuffer)\r\n    {\r\n        strLen = WideCharToMultiByte(\r\n                CP_ACP,\r\n                0,\r\n                lpwszString,\r\n                -1,\r\n                szAnsiBuffer,\r\n                MAX_PATH + 1,\r\n                NULL,\r\n                NULL);\r\n\r\n        if (strLen > 0)\r\n        {\r\n            return szAnsiBuffer;\r\n        }\r\n    }\r\n    return NULL;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nPrintString()\r\n\r\nDisplays a string to standard output\r\n*****************************************************************************/\r\nVOID PrintString(LPTSTR lpszString)\r\n{\r\n    DWORD dwBytesWritten = 0;\r\n    size_t Len = 0;\r\n    LPSTR lpOemString = NULL;\r\n\r\n    if (INVALID_HANDLE_VALUE == ghStdOut || NULL == lpszString)\r\n    {\r\n        OOPS();\r\n        // Return if invalid inputs\r\n        return;\r\n    }\r\n\r\n    if (FAILED(StringCchLength(lpszString, OUTPUT_MESSAGE_MAX_LENGTH, &Len)))\r\n    {\r\n        OOPS();\r\n        // Return if string is too long\r\n        return;\r\n    }\r\n\r\n    if (gbConsoleFile)\r\n    {\r\n        // Console has been redirected to a file, ex: `usbview /savexml:xx > test.txt`. We need to use WriteFile instead of\r\n        // WriteConsole for text output.\r\n        lpOemString = (LPSTR) LocalAlloc(LPTR, (Len + 1) * sizeof(CHAR));\r\n        if (lpOemString != NULL)\r\n        {\r\n            if (CharToOemBuff(lpszString, lpOemString, (DWORD) Len))\r\n            {\r\n                WriteFile(ghStdOut, (LPVOID) lpOemString, (DWORD) Len, &dwBytesWritten, NULL);\r\n            }\r\n            else\r\n            {\r\n                OOPS();\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // Write to std out in console\r\n        WriteConsole(ghStdOut, (LPVOID) lpszString, (DWORD) Len, &dwBytesWritten, NULL);\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nWaitForKeyPress()\r\n\r\nWaits for key press in case of console\r\n*****************************************************************************/\r\nVOID WaitForKeyPress()\r\n{\r\n    // Wait for key press if console\r\n    if (!gbConsoleFile && gbConsoleInitialized)\r\n    {\r\n        DisplayMessage(IDS_USBVIEW_PRESSKEY);\r\n        (VOID) _getch();\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nCreateMainWindow()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nCreateMainWindow (\r\n                  int nCmdShow\r\n                  )\r\n{\r\n    RECT rc;\r\n\r\n    InitCommonControls();\r\n\r\n    ghMainWnd = CreateDialog(ghInstance,\r\n        MAKEINTRESOURCE(IDD_MAINDIALOG),\r\n        NULL,\r\n        (DLGPROC) MainDlgProc);\r\n\r\n    if (ghMainWnd == NULL)\r\n    {\r\n        OOPS();\r\n        return FALSE;\r\n    }\r\n\r\n    GetWindowRect(ghMainWnd, &rc);\r\n\r\n    gBarLocation = (rc.right - rc.left) / 3;\r\n\r\n    ResizeWindows(FALSE, 0);\r\n\r\n    ShowWindow(ghMainWnd, nCmdShow);\r\n\r\n    UpdateWindow(ghMainWnd);\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nResizeWindows()\r\n\r\nHandles resizing the two child windows of the main window.  If\r\nbSizeBar is true, then the sizing is happening because the user is\r\nmoving the bar.  If bSizeBar is false, the sizing is happening\r\nbecause of the WM_SIZE or something like that.\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nResizeWindows (\r\n               BOOL    bSizeBar,\r\n               int     BarLocation\r\n               )\r\n{\r\n    RECT    MainClientRect;\r\n    RECT    MainWindowRect;\r\n    RECT    TreeWindowRect;\r\n    RECT    StatusWindowRect;\r\n    int     right;\r\n\r\n    // Is the user moving the bar?\r\n    //\r\n    if (!bSizeBar)\r\n    {\r\n        BarLocation = gBarLocation;\r\n    }\r\n\r\n    GetClientRect(ghMainWnd, &MainClientRect);\r\n\r\n    GetWindowRect(ghStatusWnd, &StatusWindowRect);\r\n\r\n    // Make sure the bar is in a OK location\r\n    //\r\n    if (bSizeBar)\r\n    {\r\n        if (BarLocation <\r\n            GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR)\r\n        {\r\n            return;\r\n        }\r\n\r\n        if ((MainClientRect.right - BarLocation) <\r\n            GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR)\r\n        {\r\n            return;\r\n        }\r\n    }\r\n\r\n    // Save the bar location\r\n    //\r\n    gBarLocation = BarLocation;\r\n\r\n    // Move the tree window\r\n    //\r\n    MoveWindow(ghTreeWnd,\r\n        0,\r\n        0,\r\n        BarLocation,\r\n        MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top,\r\n        TRUE);\r\n\r\n    // Get the size of the window (in case move window failed\r\n    //\r\n    GetWindowRect(ghTreeWnd, &TreeWindowRect);\r\n    GetWindowRect(ghMainWnd, &MainWindowRect);\r\n\r\n    right = TreeWindowRect.right - MainWindowRect.left;\r\n\r\n    // Move the edit window with respect to the tree window\r\n    //\r\n    MoveWindow(ghEditWnd,\r\n        right+SIZEBAR,\r\n        0,\r\n        MainClientRect.right-(right+SIZEBAR),\r\n        MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top,\r\n        TRUE);\r\n\r\n    // Move the Status window with respect to the tree window\r\n    //\r\n    MoveWindow(ghStatusWnd,\r\n        0,\r\n        MainClientRect.bottom - StatusWindowRect.bottom + StatusWindowRect.top,\r\n        MainClientRect.right,\r\n        StatusWindowRect.bottom - StatusWindowRect.top,\r\n        TRUE);\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nMainWndProc()\r\n\r\n*****************************************************************************/\r\n\r\nLRESULT CALLBACK\r\nMainDlgProc (\r\n             HWND   hWnd,\r\n             UINT   uMsg,\r\n             WPARAM wParam,\r\n             LPARAM lParam\r\n             )\r\n{\r\n\r\n    switch (uMsg)\r\n    {\r\n\r\n        HANDLE_MSG(hWnd, WM_INITDIALOG,     USBView_OnInitDialog);\r\n        HANDLE_MSG(hWnd, WM_CLOSE,          USBView_OnClose);\r\n        HANDLE_MSG(hWnd, WM_COMMAND,        USBView_OnCommand);\r\n        HANDLE_MSG(hWnd, WM_LBUTTONDOWN,    USBView_OnLButtonDown);\r\n        HANDLE_MSG(hWnd, WM_LBUTTONUP,      USBView_OnLButtonUp);\r\n        HANDLE_MSG(hWnd, WM_MOUSEMOVE,      USBView_OnMouseMove);\r\n        HANDLE_MSG(hWnd, WM_SIZE,           USBView_OnSize);\r\n        HANDLE_MSG(hWnd, WM_NOTIFY,         USBView_OnNotify);\r\n        HANDLE_MSG(hWnd, WM_DEVICECHANGE,   USBView_OnDeviceChange);\r\n    }\r\n\r\n    return 0;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnInitDialog()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nUSBView_OnInitDialog (\r\n                      HWND    hWnd,\r\n                      HWND    hWndFocus,\r\n                      LPARAM  lParam\r\n                      )\r\n{\r\n    HFONT                           hFont;\r\n    HIMAGELIST                      himl;\r\n    HICON                           hicon;\r\n    DEV_BROADCAST_DEVICEINTERFACE   broadcastInterface;\r\n\r\n    UNREFERENCED_PARAMETER(lParam);\r\n    UNREFERENCED_PARAMETER(hWndFocus);\r\n\r\n    // Register to receive notification when a USB device is plugged in.\r\n    broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);\r\n    broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;\r\n\r\n    memcpy( &(broadcastInterface.dbcc_classguid),\r\n        &(GUID_DEVINTERFACE_USB_DEVICE),\r\n        sizeof(struct _GUID));\r\n\r\n    gNotifyDevHandle = RegisterDeviceNotification(hWnd,\r\n        &broadcastInterface,\r\n        DEVICE_NOTIFY_WINDOW_HANDLE);\r\n\r\n    // Now register for Hub notifications.\r\n    memcpy( &(broadcastInterface.dbcc_classguid),\r\n        &(GUID_CLASS_USBHUB),\r\n        sizeof(struct _GUID));\r\n\r\n    gNotifyHubHandle = RegisterDeviceNotification(hWnd,\r\n        &broadcastInterface,\r\n        DEVICE_NOTIFY_WINDOW_HANDLE);\r\n\r\n    gHubList.DeviceInfo = INVALID_HANDLE_VALUE;\r\n    InitializeListHead(&gHubList.ListHead);\r\n    gDeviceList.DeviceInfo = INVALID_HANDLE_VALUE;\r\n    InitializeListHead(&gDeviceList.ListHead);\r\n\r\n    //end add\r\n\r\n    ghTreeWnd = GetDlgItem(hWnd, IDC_TREE);\r\n\r\n    //added\r\n    if ((himl = ImageList_Create(15, 15,\r\n        FALSE, 2, 0)) == NULL)\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n    if(himl != NULL)\r\n    {\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_ICON));\r\n        giGoodDevice = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_BADICON));\r\n        giBadDevice = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_COMPUTER));\r\n        giComputer = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_HUB));\r\n        giHub = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_NODEVICE));\r\n        giNoDevice = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_SSICON));\r\n        giGoodSsDevice = ImageList_AddIcon(himl, hicon);\r\n\r\n        hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_NOSSDEVICE));\r\n        giNoSsDevice = ImageList_AddIcon(himl, hicon);\r\n\r\n        TreeView_SetImageList(ghTreeWnd, himl, TVSIL_NORMAL);\r\n        // end add\r\n    }\r\n\r\n    ghEditWnd = GetDlgItem(hWnd, IDC_EDIT);\r\n\r\n#ifdef H264_SUPPORT\r\n    // set the edit control to have a max text limit size\r\n    SendMessage(ghEditWnd, EM_LIMITTEXT, 0 /* USE DEFAULT MAX*/, 0);\r\n#endif\r\n\r\n    ghStatusWnd = GetDlgItem(hWnd, IDC_STATUS);\r\n    ghMainMenu = GetMenu(hWnd);\r\n    if (ghMainMenu == NULL)\r\n    {\r\n        OOPS();\r\n    }\r\n    {\r\n        CHAR pszFont[256];\r\n        CHAR pszHeight[8];\r\n\r\n        memset(pszFont, 0, sizeof(pszFont));\r\n        LoadString(ghInstance, IDS_STANDARD_FONT, pszFont, sizeof(pszFont) - 1);\r\n        memset(pszHeight, 0, sizeof(pszHeight));\r\n        LoadString(ghInstance, IDS_STANDARD_FONT_HEIGHT, pszHeight, sizeof(pszHeight) - 1);\r\n\r\n        hFont  = CreateFont((int) pszHeight[0],  0, 0, 0,\r\n            400, 0, 0, 0,\r\n            0,   1, 2, 1,\r\n            49, pszFont);\r\n    }\r\n    SendMessage(ghEditWnd,\r\n        WM_SETFONT,\r\n        (WPARAM) hFont,\r\n        0);\r\n\r\n    RefreshTree();\r\n\r\n    return FALSE;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnClose()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnClose (\r\n                 HWND hWnd\r\n                 )\r\n{\r\n\r\n    UNREFERENCED_PARAMETER(hWnd);\r\n\r\n    DestroyTree();\r\n\r\n    PostQuitMessage(0);\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nAddItemInformationToFile()\r\n\r\nSaves the information about the current item to the list\r\n*****************************************************************************/\r\nVOID\r\nAddItemInformationToFile(\r\n            HWND hTreeWnd,\r\n            HTREEITEM hTreeItem,\r\n            PVOID pContext\r\n        )\r\n{\r\n    HRESULT hr = S_OK;\r\n    HANDLE hf = NULL;\r\n    DWORD dwBytesWritten = 0;\r\n\r\n    hf = *((PHANDLE) pContext);\r\n\r\n    ResetTextBuffer();\r\n\r\n    hr = UpdateTreeItemDeviceInfo(hTreeWnd, hTreeItem);\r\n\r\n    if (FAILED(hr))\r\n    {\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        WriteFile(hf, GetTextBuffer(), GetTextBufferPos()*sizeof(CHAR), &dwBytesWritten, NULL);\r\n    }\r\n\r\n    ResetTextBuffer();\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nSaveAllInformationAsText()\r\n\r\nSaves the entire USB tree as a text file\r\n*****************************************************************************/\r\nHRESULT\r\nSaveAllInformationAsText(\r\n        LPTSTR lpstrTextFileName,\r\n        DWORD dwCreationDisposition\r\n        )\r\n{\r\n    HRESULT hr = S_OK;\r\n    HANDLE hf = NULL;\r\n\r\n    hf = CreateFile(lpstrTextFileName,\r\n            GENERIC_WRITE,\r\n            0,\r\n            NULL,\r\n            dwCreationDisposition,\r\n            FILE_ATTRIBUTE_NORMAL,\r\n            NULL);\r\n\r\n    if (hf == INVALID_HANDLE_VALUE)\r\n    {\r\n        hr = HRESULT_FROM_WIN32(GetLastError());\r\n        OOPS();\r\n    }\r\n    else\r\n    {\r\n        if (GetLastError() == ERROR_ALREADY_EXISTS)\r\n        {\r\n            // CreateFile() sets this error if we are overwriting an existing file\r\n            // Reset this error to avoid false alarms\r\n            SetLastError(0);\r\n        }\r\n\r\n        if (ghTreeRoot == NULL)\r\n        {\r\n            // If tree has not been populated yet, try a refresh\r\n            RefreshTree();\r\n        }\r\n\r\n        if (ghTreeRoot)\r\n        {\r\n\r\n            LockFile(hf, 0, 0, 0, 0);\r\n            WalkTreeTopDown(ghTreeRoot, AddItemInformationToFile, &hf, NULL);\r\n            UnlockFile(hf, 0, 0, 0, 0);\r\n            CloseHandle(hf);\r\n\r\n            hr = S_OK;\r\n        }\r\n        else\r\n        {\r\n            hr = HRESULT_FROM_WIN32(GetLastError());\r\n            OOPS();\r\n        }\r\n    }\r\n\r\n    ResetTextBuffer();\r\n    return hr;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnCommand()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnCommand (\r\n                   HWND hWnd,\r\n                   int  id,\r\n                   HWND hwndCtl,\r\n                   UINT codeNotify\r\n                   )\r\n{\r\n    MENUITEMINFO menuInfo;\r\n    char            szFile[MAX_PATH + 1];\r\n    OPENFILENAME    ofn;\r\n    HANDLE          hf = NULL;\r\n    DWORD           dwBytesWritten = 0;\r\n    int             nTextLength = 0;\r\n    size_t          lengthToNull = 0;\r\n    HRESULT         hr = S_OK;\r\n\r\n    UNREFERENCED_PARAMETER(hwndCtl);\r\n    UNREFERENCED_PARAMETER(codeNotify);\r\n\r\n    //initialize save dialog variables\r\n    memset(szFile, 0, sizeof(szFile));\r\n    memset(&ofn, 0, sizeof(OPENFILENAME));\r\n\r\n    ofn.lStructSize     = sizeof(OPENFILENAME);\r\n    ofn.hwndOwner       = hWnd;\r\n    ofn.nFilterIndex    = 1;\r\n    ofn.lpstrFile       = szFile;\r\n    ofn.nMaxFile        = MAX_PATH;\r\n    ofn.lpstrFileTitle  = NULL;\r\n    ofn.nMaxFileTitle   = 0;\r\n    ofn.lpstrInitialDir = 0;\r\n    ofn.lpstrTitle      = NULL;\r\n    ofn.Flags           = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;\r\n\r\n\r\n    switch (id)\r\n    {\r\n    case ID_AUTO_REFRESH:\r\n        gDoAutoRefresh = !gDoAutoRefresh;\r\n        menuInfo.cbSize = sizeof(menuInfo);\r\n        menuInfo.fMask  = MIIM_STATE;\r\n        menuInfo.fState = gDoAutoRefresh ? MFS_CHECKED : MFS_UNCHECKED;\r\n        SetMenuItemInfo(ghMainMenu,\r\n            id,\r\n            FALSE,\r\n            &menuInfo);\r\n        break;\r\n\r\n    case ID_SAVE:\r\n        {\r\n            // initialize the save file name\r\n            StringCchCopy(szFile, MAX_PATH, \"USBView.txt\");\r\n            ofn.lpstrFilter     = \"Text\\0*.TXT\\0\\0\";\r\n            ofn.lpstrDefExt     = \"txt\";\r\n\r\n            //call dialog box\r\n            if (! GetSaveFileName(&ofn))\r\n            {\r\n                OOPS();\r\n                break;\r\n            }\r\n\r\n            //create new file\r\n            hf = CreateFile((LPTSTR)ofn.lpstrFile,\r\n                GENERIC_WRITE,\r\n                0,\r\n                NULL,\r\n                CREATE_ALWAYS,\r\n                FILE_ATTRIBUTE_NORMAL,\r\n                NULL);\r\n            if (hf == INVALID_HANDLE_VALUE)\r\n            {\r\n                OOPS();\r\n            }\r\n            else\r\n            {\r\n                char *szText = NULL;\r\n\r\n                //get data from display window to transfer to file\r\n                nTextLength = GetWindowTextLength(ghEditWnd);\r\n                nTextLength++;\r\n\r\n                szText = ALLOC((DWORD)nTextLength);\r\n                if (NULL != szText)\r\n                {\r\n                    GetWindowText(ghEditWnd, (LPSTR) szText, nTextLength);\r\n\r\n                    //\r\n                    // Constrain length to the first null, which should be at\r\n                    // the end of the window text. This prevents writing extra\r\n                    // null characters.\r\n                    //\r\n                    if (StringCchLength(szText, nTextLength, &lengthToNull) == S_OK)\r\n                    {\r\n                        nTextLength = (int) lengthToNull;\r\n\r\n                        //lock the file, write to the file, unlock file\r\n                        LockFile(hf, 0, 0, 0, 0);\r\n\r\n                        WriteFile(hf, szText, nTextLength, &dwBytesWritten, NULL);\r\n\r\n                        UnlockFile(hf, 0, 0, 0, 0);\r\n                    }\r\n                    else\r\n                    {\r\n                        OOPS();\r\n                    }\r\n                    CloseHandle(hf);\r\n                    FREE(szText);\r\n                }\r\n                else\r\n                {\r\n                    OOPS();\r\n                }\r\n            }\r\n\r\n           break;\r\n        }\r\n\r\n    case ID_SAVEALL:\r\n        {\r\n            // initialize the save file name\r\n            StringCchCopy(szFile, MAX_PATH, \"USBViewAll.txt\");\r\n            ofn.lpstrFilter     = \"Text\\0*.txt\\0\\0\";\r\n            ofn.lpstrDefExt     = \"txt\";\r\n\r\n            //call dialog box\r\n            if (! GetSaveFileName(&ofn))\r\n            {\r\n                OOPS();\r\n                break;\r\n            }\r\n\r\n            // Save the file, overwrite in case of UI since UI gives popup for confirmation\r\n            hr = SaveAllInformationAsText(ofn.lpstrFile, CREATE_ALWAYS);\r\n            if (FAILED(hr))\r\n            {\r\n                OOPS();\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n    case ID_SAVEXML:\r\n        {\r\n            // initialize the save file name\r\n            StringCchCopy(szFile, MAX_PATH, \"USBViewAll.xml\");\r\n            ofn.lpstrFilter     = \"Xml\\0*.xml\\0\\0\";\r\n            ofn.lpstrDefExt     = \"xml\";\r\n\r\n            //call dialog box\r\n            if (! GetSaveFileName(&ofn))\r\n            {\r\n                OOPS();\r\n                break;\r\n            }\r\n\r\n            // Save the file, overwrite in case of UI since UI gives popup for confirmation\r\n            hr = SaveAllInformationAsXml(ofn.lpstrFile, CREATE_ALWAYS);\r\n            if (FAILED(hr))\r\n            {\r\n                OOPS();\r\n            }\r\n\r\n            break;\r\n        }\r\n\r\n    case ID_CONFIG_DESCRIPTORS:\r\n        gDoConfigDesc = !gDoConfigDesc;\r\n        menuInfo.cbSize = sizeof(menuInfo);\r\n        menuInfo.fMask  = MIIM_STATE;\r\n        menuInfo.fState = gDoConfigDesc ? MFS_CHECKED : MFS_UNCHECKED;\r\n        SetMenuItemInfo(ghMainMenu,\r\n            id,\r\n            FALSE,\r\n            &menuInfo);\r\n        break;\r\n\r\n    case ID_ANNOTATION:\r\n        gDoAnnotation = !gDoAnnotation;\r\n        menuInfo.cbSize = sizeof(menuInfo);\r\n        menuInfo.fMask  = MIIM_STATE;\r\n        menuInfo.fState = gDoAnnotation ? MFS_CHECKED : MFS_UNCHECKED;\r\n        SetMenuItemInfo(ghMainMenu,\r\n            id,\r\n            FALSE,\r\n            &menuInfo);\r\n        break;\r\n\r\n    case ID_LOG_DEBUG:\r\n        gLogDebug       = !gLogDebug;\r\n        menuInfo.cbSize = sizeof(menuInfo);\r\n        menuInfo.fMask  = MIIM_STATE;\r\n        menuInfo.fState = gLogDebug ? MFS_CHECKED : MFS_UNCHECKED;\r\n        SetMenuItemInfo(ghMainMenu,\r\n            id,\r\n            FALSE,\r\n            &menuInfo);\r\n        break;\r\n\r\n    case ID_ABOUT:\r\n        DialogBox(ghInstance,\r\n            MAKEINTRESOURCE(IDD_ABOUT),\r\n            ghMainWnd,\r\n            (DLGPROC) AboutDlgProc);\r\n        break;\r\n\r\n    case ID_EXIT:\r\n        UnregisterDeviceNotification(gNotifyDevHandle);\r\n        UnregisterDeviceNotification(gNotifyHubHandle);\r\n        DestroyTree();\r\n        PostQuitMessage(0);\r\n        break;\r\n\r\n    case ID_REFRESH:\r\n        RefreshTree();\r\n        break;\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnLButtonDown()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnLButtonDown (\r\n                       HWND hWnd,\r\n                       BOOL fDoubleClick,\r\n                       int  x,\r\n                       int  y,\r\n                       UINT keyFlags\r\n                       )\r\n{\r\n\r\n    UNREFERENCED_PARAMETER(fDoubleClick);\r\n    UNREFERENCED_PARAMETER(x);\r\n    UNREFERENCED_PARAMETER(y);\r\n    UNREFERENCED_PARAMETER(keyFlags);\r\n\r\n    gbButtonDown = TRUE;\r\n    SetCapture(hWnd);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnLButtonUp()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnLButtonUp (\r\n                     HWND hWnd,\r\n                     int  x,\r\n                     int  y,\r\n                     UINT keyFlags\r\n                     )\r\n{\r\n\r\n    UNREFERENCED_PARAMETER(hWnd);\r\n    UNREFERENCED_PARAMETER(x);\r\n    UNREFERENCED_PARAMETER(y);\r\n    UNREFERENCED_PARAMETER(keyFlags);\r\n\r\n    gbButtonDown = FALSE;\r\n    ReleaseCapture();\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnMouseMove()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnMouseMove (\r\n                     HWND hWnd,\r\n                     int  x,\r\n                     int  y,\r\n                     UINT keyFlags\r\n                     )\r\n{\r\n    UNREFERENCED_PARAMETER(hWnd);\r\n    UNREFERENCED_PARAMETER(y);\r\n    UNREFERENCED_PARAMETER(keyFlags);\r\n\r\n    SetCursor(ghSplitCursor);\r\n\r\n    if (gbButtonDown)\r\n    {\r\n        ResizeWindows(TRUE, x);\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnSize();\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nUSBView_OnSize (\r\n                HWND hWnd,\r\n                UINT state,\r\n                int  cx,\r\n                int  cy\r\n                )\r\n{\r\n    UNREFERENCED_PARAMETER(hWnd);\r\n    UNREFERENCED_PARAMETER(state);\r\n    UNREFERENCED_PARAMETER(cx);\r\n    UNREFERENCED_PARAMETER(cy);\r\n\r\n    ResizeWindows(FALSE, 0);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnNotify()\r\n\r\n*****************************************************************************/\r\n\r\nLRESULT\r\nUSBView_OnNotify (\r\n                  HWND    hWnd,\r\n                  int     DlgItem,\r\n                  LPNMHDR lpNMHdr\r\n                  )\r\n{\r\n    UNREFERENCED_PARAMETER(hWnd);\r\n    UNREFERENCED_PARAMETER(DlgItem);\r\n\r\n    if (lpNMHdr->code == TVN_SELCHANGED)\r\n    {\r\n        HTREEITEM hTreeItem;\r\n\r\n        hTreeItem = ((NM_TREEVIEW *)lpNMHdr)->itemNew.hItem;\r\n\r\n        if (hTreeItem)\r\n        {\r\n            UpdateEditControl(ghEditWnd,\r\n                ghTreeWnd,\r\n                hTreeItem);\r\n        }\r\n    }\r\n\r\n    return 0;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nUSBView_OnDeviceChange()\r\n\r\n*****************************************************************************/\r\n\r\nBOOL\r\nUSBView_OnDeviceChange (\r\n                        HWND  hwnd,\r\n                        UINT  uEvent,\r\n                        DWORD dwEventData\r\n                        )\r\n{\r\n    UNREFERENCED_PARAMETER(hwnd);\r\n    UNREFERENCED_PARAMETER(dwEventData);\r\n\r\n    if (gDoAutoRefresh)\r\n    {\r\n        switch (uEvent)\r\n        {\r\n        case DBT_DEVICEARRIVAL:\r\n        case DBT_DEVICEREMOVECOMPLETE:\r\n            RefreshTree();\r\n            break;\r\n        }\r\n    }\r\n\r\n    return TRUE;\r\n}\r\n\r\n\r\n\r\n/*****************************************************************************\r\n\r\nDestroyTree()\r\n\r\n*****************************************************************************/\r\n\r\nVOID DestroyTree (VOID)\r\n{\r\n    // Clear the selection of the TreeView, so that when the tree is\r\n    // destroyed, the control won't try to constantly \"shift\" the\r\n    // selection to another item.\r\n    //\r\n    TreeView_SelectItem(ghTreeWnd, NULL);\r\n\r\n    // Destroy the current contents of the TreeView\r\n    //\r\n    if (ghTreeRoot)\r\n    {\r\n        WalkTree(ghTreeRoot, CleanupItem, NULL);\r\n\r\n        TreeView_DeleteAllItems(ghTreeWnd);\r\n\r\n        ghTreeRoot = NULL;\r\n    }\r\n\r\n    ClearDeviceList(&gDeviceList);\r\n    ClearDeviceList(&gHubList);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nRefreshTree()\r\n\r\n*****************************************************************************/\r\n\r\nVOID RefreshTree (VOID)\r\n{\r\n    CHAR  statusText[128];\r\n    ULONG devicesConnected;\r\n\r\n    // Clear the edit control\r\n    //\r\n    SetWindowText(ghEditWnd, \"\");\r\n\r\n    // Destroy the current contents of the TreeView\r\n    //\r\n    DestroyTree();\r\n\r\n    // Create the root tree node\r\n    //\r\n    ghTreeRoot = AddLeaf(TVI_ROOT, 0, \"My Computer\", ComputerIcon);\r\n\r\n    if (ghTreeRoot != NULL)\r\n    {\r\n        // Enumerate all USB buses and populate the tree\r\n        //\r\n        EnumerateHostControllers(ghTreeRoot, &devicesConnected);\r\n\r\n        //\r\n        // Expand all tree nodes\r\n        //\r\n        WalkTree(ghTreeRoot, ExpandItem, NULL);\r\n\r\n        // Update Status Line with number of devices connected\r\n        //\r\n        memset(statusText, 0, sizeof(statusText));\r\n        StringCchPrintf(statusText, sizeof(statusText),\r\n#ifdef H264_SUPPORT\r\n        \"UVC Spec Version: %d.%d Version: %d.%d Devices Connected: %d   Hubs Connected: %d\",\r\n        UVC_SPEC_MAJOR_VERSION, UVC_SPEC_MINOR_VERSION, USBVIEW_MAJOR_VERSION, USBVIEW_MINOR_VERSION,\r\n        devicesConnected, TotalHubs);\r\n#else\r\n        \"Devices Connected: %d   Hubs Connected: %d\",\r\n        devicesConnected, TotalHubs);\r\n#endif\r\n\r\n        SetWindowText(ghStatusWnd, statusText);\r\n    }\r\n    else\r\n    {\r\n        OOPS();\r\n    }\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nAboutDlgProc()\r\n\r\n*****************************************************************************/\r\n\r\nLRESULT CALLBACK\r\nAboutDlgProc (\r\n              HWND   hwnd,\r\n              UINT   uMsg,\r\n              WPARAM wParam,\r\n              LPARAM lParam\r\n              )\r\n{\r\n    UNREFERENCED_PARAMETER(lParam);\r\n\r\n    switch (uMsg)\r\n    {\r\n    case WM_INITDIALOG:\r\n        {\r\n            HRESULT hr;\r\n            char TextBuffer[TEXT_ITEM_LENGTH];\r\n            HWND hItem;\r\n\r\n            hItem = GetDlgItem(hwnd, IDC_VERSION);\r\n\r\n            if (hItem != NULL)\r\n            {\r\n                hr = StringCbPrintfA(TextBuffer,\r\n                                     sizeof(TextBuffer),\r\n                                     \"USBView version: %d.%d\",\r\n                                     USBVIEW_MAJOR_VERSION,\r\n                                     USBVIEW_MINOR_VERSION);\r\n                if (SUCCEEDED(hr))\r\n                {\r\n                    SetWindowText(hItem,TextBuffer);\r\n                }\r\n            }\r\n\r\n            hItem = GetDlgItem(hwnd, IDC_UVCVERSION);\r\n\r\n            if (hItem != NULL)\r\n            {\r\n                hr = StringCbPrintfA(TextBuffer,\r\n                                     sizeof(TextBuffer),\r\n                                     \"USB Video Class Spec version: %d.%d\",\r\n                                     UVC_SPEC_MAJOR_VERSION,\r\n                                     UVC_SPEC_MINOR_VERSION);\r\n                if (SUCCEEDED(hr))\r\n                {\r\n                    SetWindowText(hItem,TextBuffer);\r\n                }\r\n            }\r\n        }\r\n        break;\r\n    case WM_COMMAND:\r\n\r\n        switch (LOWORD(wParam))\r\n        {\r\n        case IDOK:\r\n        case IDCANCEL:\r\n\r\n            EndDialog (hwnd, 0);\r\n            break;\r\n        }\r\n        break;\r\n\r\n    }\r\n\r\n    return FALSE;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nAddLeaf()\r\n\r\n*****************************************************************************/\r\n\r\nHTREEITEM\r\nAddLeaf (\r\n         HTREEITEM hTreeParent,\r\n         LPARAM    lParam,\r\n         _In_ LPTSTR    lpszText,\r\n         TREEICON  TreeIcon\r\n         )\r\n{\r\n    TV_INSERTSTRUCT tvins;\r\n    HTREEITEM       hti;\r\n\r\n    memset(&tvins, 0, sizeof(tvins));\r\n\r\n    // Set the parent item\r\n    //\r\n    tvins.hParent = hTreeParent;\r\n\r\n    tvins.hInsertAfter = TVI_LAST;\r\n\r\n    // pszText and lParam members are valid\r\n    //\r\n    tvins.item.mask = TVIF_TEXT | TVIF_PARAM;\r\n\r\n    // Set the text of the item.\r\n    //\r\n    tvins.item.pszText = lpszText;\r\n\r\n    // Set the user context item\r\n    //\r\n    tvins.item.lParam = lParam;\r\n\r\n    // Add the item to the tree-view control.\r\n    //\r\n    hti = TreeView_InsertItem(ghTreeWnd, &tvins);\r\n\r\n    // added\r\n    tvins.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;\r\n    tvins.item.hItem = hti;\r\n\r\n    // Determine which icon to display for the device\r\n    //\r\n    switch (TreeIcon)\r\n    {\r\n        case ComputerIcon:\r\n            tvins.item.iImage = giComputer;\r\n            tvins.item.iSelectedImage = giComputer;\r\n            break;\r\n\r\n        case HubIcon:\r\n            tvins.item.iImage = giHub;\r\n            tvins.item.iSelectedImage = giHub;\r\n            break;\r\n\r\n        case NoDeviceIcon:\r\n            tvins.item.iImage = giNoDevice;\r\n            tvins.item.iSelectedImage = giNoDevice;\r\n            break;\r\n\r\n        case GoodDeviceIcon:\r\n            tvins.item.iImage = giGoodDevice;\r\n            tvins.item.iSelectedImage = giGoodDevice;\r\n            break;\r\n\r\n        case GoodSsDeviceIcon:\r\n            tvins.item.iImage = giGoodSsDevice;\r\n            tvins.item.iSelectedImage = giGoodSsDevice;\r\n            break;\r\n\r\n        case NoSsDeviceIcon:\r\n            tvins.item.iImage = giNoSsDevice;\r\n            tvins.item.iSelectedImage = giNoSsDevice;\r\n            break;\r\n\r\n        case BadDeviceIcon:\r\n        default:\r\n            tvins.item.iImage = giBadDevice;\r\n            tvins.item.iSelectedImage = giBadDevice;\r\n            break;\r\n    }\r\n    TreeView_SetItem(ghTreeWnd, &tvins.item);\r\n\r\n    return hti;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nWalkTreeTopDown()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nWalkTreeTopDown(\r\n          _In_ HTREEITEM        hTreeItem,\r\n          _In_ LPFNTREECALLBACK lpfnTreeCallback,\r\n          _In_opt_ PVOID            pContext,\r\n          _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback\r\n          )\r\n{\r\n    if (hTreeItem)\r\n    {\r\n        HTREEITEM hTreeChild = TreeView_GetChild(ghTreeWnd, hTreeItem);\r\n        HTREEITEM hTreeSibling = TreeView_GetNextSibling(ghTreeWnd, hTreeItem);\r\n\r\n        //\r\n        // Call the lpfnCallBack on the node itself.\r\n        //\r\n        (*lpfnTreeCallback)(ghTreeWnd, hTreeItem, pContext);\r\n\r\n        //\r\n        // Recursively call WalkTree on the node's first child.\r\n        //\r\n\r\n        if (hTreeChild)\r\n        {\r\n            WalkTreeTopDown(hTreeChild,\r\n                    lpfnTreeCallback,\r\n                    pContext,\r\n                    lpfnTreeNotifyCallback);\r\n        }\r\n\r\n        //\r\n        // Recursively call WalkTree on the node's first sibling.\r\n        //\r\n        if (hTreeSibling)\r\n        {\r\n            WalkTreeTopDown(hTreeSibling,\r\n                    lpfnTreeCallback,\r\n                    pContext,\r\n                    lpfnTreeNotifyCallback);\r\n        }\r\n        else\r\n        {\r\n            // If there are no more siblings, we have reached the end of\r\n            // list of child nodes. Call notify function\r\n            if (lpfnTreeNotifyCallback != NULL)\r\n            {\r\n                (*lpfnTreeNotifyCallback)(pContext);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nWalkTree()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nWalkTree (\r\n          _In_ HTREEITEM        hTreeItem,\r\n          _In_ LPFNTREECALLBACK lpfnTreeCallback,\r\n          _In_opt_ PVOID            pContext\r\n          )\r\n{\r\n    if (hTreeItem)\r\n    {\r\n        // Recursively call WalkTree on the node's first child.\r\n        //\r\n        WalkTree(TreeView_GetChild(ghTreeWnd, hTreeItem),\r\n            lpfnTreeCallback,\r\n            pContext);\r\n\r\n        //\r\n        // Call the lpfnCallBack on the node itself.\r\n        //\r\n        (*lpfnTreeCallback)(ghTreeWnd, hTreeItem, pContext);\r\n\r\n        //\r\n        //\r\n        // Recursively call WalkTree on the node's first sibling.\r\n        //\r\n        WalkTree(TreeView_GetNextSibling(ghTreeWnd, hTreeItem),\r\n            lpfnTreeCallback,\r\n            pContext);\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nExpandItem()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nExpandItem (\r\n            HWND      hTreeWnd,\r\n            HTREEITEM hTreeItem,\r\n            PVOID     pContext\r\n            )\r\n{\r\n    //\r\n    // Make this node visible.\r\n    //\r\n    UNREFERENCED_PARAMETER(pContext);\r\n\r\n    TreeView_Expand(hTreeWnd, hTreeItem, TVE_EXPAND);\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nSaveAllInformationAsXML()\r\n\r\nSaves the entire USB tree as an XML file\r\n*****************************************************************************/\r\nHRESULT\r\nSaveAllInformationAsXml(\r\n        LPTSTR lpstrTextFileName,\r\n        DWORD dwCreationDisposition\r\n        )\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    if (ghTreeRoot == NULL)\r\n    {\r\n        // If tree has not been populated yet, try a refresh\r\n        RefreshTree();\r\n    }\r\n    if (ghTreeRoot)\r\n    {\r\n        WalkTreeTopDown(ghTreeRoot, AddItemInformationToXmlView, NULL, XmlNotifyEndOfNodeList);\r\n\r\n        hr = SaveXml(lpstrTextFileName, dwCreationDisposition);\r\n    }\r\n    else\r\n    {\r\n        hr = E_FAIL;\r\n        OOPS();\r\n    }\r\n    ResetTextBuffer();\r\n    return hr;\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//  AddItemInformationToXmlView\r\n//\r\n//  hTreeItem - Handle of selected TreeView item for which information should\r\n//  be added to the XML View\r\n//\r\n//*****************************************************************************\r\nVOID\r\nAddItemInformationToXmlView(\r\n        HWND hTreeWnd,\r\n        HTREEITEM hTreeItem,\r\n        PVOID pContext\r\n        )\r\n{\r\n    TV_ITEM tvi;\r\n    PVOID   info;\r\n    PCHAR tviName = NULL;\r\n\r\n    UNREFERENCED_PARAMETER(pContext);\r\n\r\n#ifdef H264_SUPPORT\r\n    ResetErrorCounts();\r\n#endif\r\n\r\n    tviName = (PCHAR) ALLOC(256);\r\n\r\n    if (NULL == tviName)\r\n    {\r\n        return;\r\n    }\r\n\r\n    //\r\n    // Get the name of the TreeView item, along with the a pointer to the\r\n    // info we stored about the item in the item's lParam.\r\n    //\r\n\r\n    tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;\r\n    tvi.hItem = hTreeItem;\r\n    tvi.pszText = (LPSTR) tviName;\r\n    tvi.cchTextMax = 256;\r\n\r\n    TreeView_GetItem(hTreeWnd,\r\n            &tvi);\r\n\r\n    info = (PVOID)tvi.lParam;\r\n\r\n    if (NULL != info)\r\n    {\r\n        //\r\n        // Add Item to XML object\r\n        //\r\n        switch (*(PUSBDEVICEINFOTYPE)info)\r\n        {\r\n            case HostControllerInfo:\r\n                XmlAddHostController(tviName, (PUSBHOSTCONTROLLERINFO) info);\r\n                break;\r\n\r\n            case RootHubInfo:\r\n                XmlAddRootHub(tviName, (PUSBROOTHUBINFO) info);\r\n                break;\r\n\r\n            case ExternalHubInfo:\r\n                XmlAddExternalHub(tviName, (PUSBEXTERNALHUBINFO) info);\r\n                break;\r\n\r\n            case DeviceInfo:\r\n                XmlAddUsbDevice(tviName, (PUSBDEVICEINFO) info);\r\n                break;\r\n        }\r\n\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\nDisplayLastError()\r\n\r\n*****************************************************************************/\r\n\r\nDWORD\r\nDisplayLastError(\r\n          _Inout_updates_bytes_(count) char *szString,\r\n          int count)\r\n{\r\n    LPVOID lpMsgBuf;\r\n\r\n    // get the last error code\r\n    DWORD dwError = GetLastError();\r\n\r\n    // get the system message for this error code\r\n    if (FormatMessage(\r\n        FORMAT_MESSAGE_ALLOCATE_BUFFER |\r\n        FORMAT_MESSAGE_FROM_SYSTEM |\r\n        FORMAT_MESSAGE_IGNORE_INSERTS,\r\n        NULL,\r\n        dwError,\r\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r\n        (LPTSTR) &lpMsgBuf,\r\n        0,\r\n        NULL ))\r\n    {\r\n        StringCchPrintf(szString, count, \"Error: %s\", (LPTSTR)lpMsgBuf );\r\n    }\r\n\r\n    // Free the local buffer\r\n    LocalFree( lpMsgBuf );\r\n\r\n    // return the error\r\n    return dwError;\r\n}\r\n\r\n#if DBG\r\n\r\n/*****************************************************************************\r\n\r\nOops()\r\n\r\n*****************************************************************************/\r\n\r\nVOID\r\nOops\r\n(\r\n    _In_ PCHAR  File,\r\n    ULONG       Line\r\n )\r\n{\r\n    char szBuf[1024];\r\n    LPTSTR lpMsgBuf;\r\n    DWORD dwGLE = GetLastError();\r\n\r\n    memset(szBuf, 0, sizeof(szBuf));\r\n\r\n    // get the system message for this error code\r\n    if (FormatMessage(\r\n        FORMAT_MESSAGE_ALLOCATE_BUFFER |\r\n        FORMAT_MESSAGE_FROM_SYSTEM,\r\n        NULL,\r\n        dwGLE,\r\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r\n        (LPTSTR) &lpMsgBuf,\r\n        0,\r\n        NULL))\r\n    {\r\n        StringCchPrintf(szBuf, sizeof(szBuf),\r\n            \"File: %s, Line %d\\r\\nGetLastError 0x%x %u %s\\n\",\r\n            File, Line, dwGLE, dwGLE, lpMsgBuf);\r\n    }\r\n    else\r\n    {\r\n        StringCchPrintf(szBuf, sizeof(szBuf),\r\n            \"File: %s, Line %d\\r\\nGetLastError 0x%x %u\\r\\n\",\r\n            File, Line, dwGLE, dwGLE);\r\n    }\r\n    OutputDebugString(szBuf);\r\n\r\n    // Free the system allocated local buffer\r\n    LocalFree(lpMsgBuf);\r\n\r\n    return;\r\n}\r\n\r\n#endif\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/uvcview.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    UVCVIEW.H\r\n\r\nAbstract:\r\n\r\n    This is the header file for UVCVIEW\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    04-25-97 : created\r\n    04/13/2005 : major bug fixing\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\n I N C L U D E S\r\n*****************************************************************************/\r\n#include <windows.h>\r\n#include <windowsx.h>\r\n#include <initguid.h>\r\n#include <devioctl.h>\r\n#include <dbt.h>\r\n#include <stdio.h>\r\n#include <commctrl.h>\r\n#include <usbioctl.h>\r\n#include <usbiodef.h>\r\n#include <intsafe.h>\r\n#include <strsafe.h>\r\n#include <specstrings.h>\r\n#include <usb.h>\r\n#include <usbuser.h>\r\n#include <basetyps.h>\r\n#include <wtypes.h>\r\n#include <objbase.h>\r\n#include <io.h>\r\n#include <conio.h>\r\n#include <shellapi.h>\r\n#include <cfgmgr32.h>\r\n#include <shlwapi.h>\r\n#include <setupapi.h>\r\n#include <winioctl.h>\r\n#include <devpkey.h>\r\n#include <math.h>\r\n\r\n// This is mostly a private USB Audio descriptor header\r\n#include \"usbdesc.h\"\r\n\r\n// This is the inbox USBVideo driver descriptor header (copied locally)\r\n#include \"uvcdesc.h\"\r\n\r\n/*****************************************************************************\r\n P R A G M A S\r\n*****************************************************************************/\r\n\r\n#pragma once\r\n\r\n/*****************************************************************************\r\n D E F I N E S\r\n*****************************************************************************/\r\n\r\n// define H264_SUPPORT to add H.264 support to uvcview.exe\r\n#define H264_SUPPORT\r\n\r\n#define TEXT_ITEM_LENGTH 64\r\n\r\n#ifdef  DEBUG\r\n#undef  DBG\r\n#define DBG 1\r\n#endif\r\n\r\n#if DBG\r\n#define OOPS() Oops(__FILE__, __LINE__)\r\n#else\r\n#define  OOPS()\r\n#endif\r\n\r\n#if DBG\r\n\r\n#define ALLOC(dwBytes) MyAlloc(__FILE__, __LINE__, (dwBytes))\r\n\r\n#define REALLOC(hMem, dwBytes) MyReAlloc((hMem), (dwBytes))\r\n\r\n#define FREE(hMem)  MyFree((hMem))\r\n\r\n#define CHECKFORLEAKS() MyCheckForLeaks()\r\n\r\n#else\r\n\r\n#define ALLOC(dwBytes) GlobalAlloc(GPTR,(dwBytes))\r\n\r\n#define REALLOC(hMem, dwBytes) GlobalReAlloc((hMem), (dwBytes), (GMEM_MOVEABLE|GMEM_ZEROINIT))\r\n\r\n#define FREE(hMem)  GlobalFree((hMem))\r\n\r\n#define CHECKFORLEAKS()\r\n\r\n#endif\r\n\r\n#define DEVICE_CONFIGURATION_TEXT_LENGTH 10240\r\n\r\n#define STR_INVALID_POWER_STATE    \"(invalid state) \"\r\n#define STR_UNKNOWN_CONTROLLER_FLAVOR \"Unknown\"\r\n\r\nFORCEINLINE\r\nVOID\r\nInitializeListHead(\r\n    _Out_ PLIST_ENTRY ListHead\r\n    )\r\n{\r\n    ListHead->Flink = ListHead->Blink = ListHead;\r\n}\r\n\r\n//\r\n//  BOOLEAN\r\n//  IsListEmpty(\r\n//      PLIST_ENTRY ListHead\r\n//      );\r\n//\r\n\r\n#define IsListEmpty(ListHead) \\\r\n    ((ListHead)->Flink == (ListHead))\r\n\r\n//\r\n//  PLIST_ENTRY\r\n//  RemoveHeadList(\r\n//      PLIST_ENTRY ListHead\r\n//      );\r\n//\r\n\r\n#define RemoveHeadList(ListHead) \\\r\n    (ListHead)->Flink;\\\r\n    {RemoveEntryList((ListHead)->Flink)}\r\n\r\n//\r\n//  VOID\r\n//  RemoveEntryList(\r\n//      PLIST_ENTRY Entry\r\n//      );\r\n//\r\n\r\n#define RemoveEntryList(Entry) {\\\r\n    PLIST_ENTRY _EX_Blink;\\\r\n    PLIST_ENTRY _EX_Flink;\\\r\n    _EX_Flink = (Entry)->Flink;\\\r\n    _EX_Blink = (Entry)->Blink;\\\r\n    _EX_Blink->Flink = _EX_Flink;\\\r\n    _EX_Flink->Blink = _EX_Blink;\\\r\n    }\r\n\r\n//\r\n//  VOID\r\n//  InsertTailList(\r\n//      PLIST_ENTRY ListHead,\r\n//      PLIST_ENTRY Entry\r\n//      );\r\n//\r\n\r\n#define InsertTailList(ListHead,Entry) {\\\r\n    PLIST_ENTRY _EX_Blink;\\\r\n    PLIST_ENTRY _EX_ListHead;\\\r\n    _EX_ListHead = (ListHead);\\\r\n    _EX_Blink = _EX_ListHead->Blink;\\\r\n    (Entry)->Flink = _EX_ListHead;\\\r\n    (Entry)->Blink = _EX_Blink;\\\r\n    _EX_Blink->Flink = (Entry);\\\r\n    _EX_ListHead->Blink = (Entry);\\\r\n    }\r\n\r\n// global version for USB Video Class spec version (pre-release)\r\n#define BCDVDC     0x0083\r\n\r\n// A.2  Video Interface Subclass Codes\r\n#define SC_VIDEO_INTERFACE_COLLECTION  0x03\r\n\r\n// A.3  Video Interface Protocol Codes\r\n#define PC_PROTOCOL_UNDEFINED     0x00\r\n\r\n// USB Video Class spec version\r\n#define NOT_UVC 0x0\r\n#define UVC10   0x100\r\n#define UVC11   0x110\r\n\r\n#ifdef H264_SUPPORT\r\n#define UVC15   0x150\r\n#endif\r\n\r\n#define OUTPUT_MESSAGE_MAX_LENGTH    1024\r\n#define MAX_DEVICE_PROP 200\r\n#define MAX_DRIVER_KEY_NAME 256\r\n\r\n/*****************************************************************************\r\n T Y P E D E F S\r\n*****************************************************************************/\r\n\r\ntypedef enum _TREEICON\r\n{\r\n    ComputerIcon,\r\n    HubIcon,\r\n    NoDeviceIcon,\r\n    GoodDeviceIcon,\r\n    BadDeviceIcon,\r\n    GoodSsDeviceIcon,\r\n    NoSsDeviceIcon\r\n} TREEICON;\r\n\r\n// Callback function for walking TreeView items\r\n//\r\ntypedef VOID\r\n(*LPFNTREECALLBACK)(\r\n    HWND        hTreeWnd,\r\n    HTREEITEM   hTreeItem,\r\n    PVOID       pContext\r\n);\r\n\r\n\r\n// Callback notification function called at end of every tree depth\r\ntypedef VOID\r\n(*LPFNTREENOTIFYCALLBACK)(PVOID pContext);\r\n\r\n//\r\n// Structure used to build a linked list of String Descriptors\r\n// retrieved from a device.\r\n//\r\n\r\ntypedef struct _STRING_DESCRIPTOR_NODE\r\n{\r\n    struct _STRING_DESCRIPTOR_NODE *Next;\r\n    UCHAR                           DescriptorIndex;\r\n    USHORT                          LanguageID;\r\n    USB_STRING_DESCRIPTOR           StringDescriptor[1];\r\n} STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE;\r\n\r\n//\r\n// A collection of device properties. The device can be hub, host controller or usb device\r\n//\r\ntypedef struct _USB_DEVICE_PNP_STRINGS\r\n{\r\n    PCHAR DeviceId;\r\n    PCHAR DeviceDesc;\r\n    PCHAR HwId;\r\n    PCHAR Service;\r\n    PCHAR DeviceClass;\r\n    PCHAR PowerState;\r\n} USB_DEVICE_PNP_STRINGS, *PUSB_DEVICE_PNP_STRINGS;\r\n\r\ntypedef struct _DEVICE_INFO_NODE {\r\n    HDEVINFO                         DeviceInfo;\r\n    LIST_ENTRY                       ListEntry;\r\n    SP_DEVINFO_DATA                  DeviceInfoData;\r\n    SP_DEVICE_INTERFACE_DATA         DeviceInterfaceData;\r\n    PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetailData;\r\n    PSTR                             DeviceDescName;\r\n    ULONG                            DeviceDescNameLength;\r\n    PSTR                             DeviceDriverName;\r\n    ULONG                            DeviceDriverNameLength;\r\n    DEVICE_POWER_STATE               LatestDevicePowerState;\r\n} DEVICE_INFO_NODE, *PDEVICE_INFO_NODE;\r\n\r\n//\r\n// Structures assocated with TreeView items through the lParam.  When an item\r\n// is selected, the lParam is retrieved and the structure it which it points\r\n// is used to display information in the edit control.\r\n//\r\n\r\ntypedef enum _USBDEVICEINFOTYPE\r\n{\r\n    HostControllerInfo,\r\n    RootHubInfo,\r\n    ExternalHubInfo,\r\n    DeviceInfo\r\n} USBDEVICEINFOTYPE, *PUSBDEVICEINFOTYPE;\r\n\r\ntypedef struct _USBHOSTCONTROLLERINFO\r\n{\r\n    USBDEVICEINFOTYPE                   DeviceInfoType;\r\n    LIST_ENTRY                          ListEntry;\r\n    PCHAR                               DriverKey;\r\n    ULONG                               VendorID;\r\n    ULONG                               DeviceID;\r\n    ULONG                               SubSysID;\r\n    ULONG                               Revision;\r\n    USB_POWER_INFO                      USBPowerInfo[6];\r\n    BOOL                                BusDeviceFunctionValid;\r\n    ULONG                               BusNumber;\r\n    USHORT                              BusDevice;\r\n    USHORT                              BusFunction;\r\n    PUSB_CONTROLLER_INFO_0              ControllerInfo;\r\n    PUSB_DEVICE_PNP_STRINGS             UsbDeviceProperties;\r\n} USBHOSTCONTROLLERINFO, *PUSBHOSTCONTROLLERINFO;\r\n\r\ntypedef struct _USBROOTHUBINFO\r\n{\r\n    USBDEVICEINFOTYPE                   DeviceInfoType;\r\n    PUSB_NODE_INFORMATION               HubInfo;\r\n    PUSB_HUB_INFORMATION_EX             HubInfoEx;\r\n    PCHAR                               HubName;\r\n    PUSB_PORT_CONNECTOR_PROPERTIES      PortConnectorProps;\r\n    PUSB_DEVICE_PNP_STRINGS             UsbDeviceProperties;\r\n    PDEVICE_INFO_NODE                   DeviceInfoNode;\r\n    PUSB_HUB_CAPABILITIES_EX            HubCapabilityEx;\r\n\r\n} USBROOTHUBINFO, *PUSBROOTHUBINFO;\r\n\r\ntypedef struct _USBEXTERNALHUBINFO\r\n{\r\n    USBDEVICEINFOTYPE                      DeviceInfoType;\r\n    PUSB_NODE_INFORMATION                  HubInfo;\r\n    PUSB_HUB_INFORMATION_EX                HubInfoEx;\r\n    PCHAR                                  HubName;\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfo;\r\n    PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps;\r\n    PUSB_DESCRIPTOR_REQUEST                ConfigDesc;\r\n    PUSB_DESCRIPTOR_REQUEST                BosDesc;\r\n    PSTRING_DESCRIPTOR_NODE                StringDescs;\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB\r\n    PUSB_DEVICE_PNP_STRINGS                UsbDeviceProperties;\r\n    PDEVICE_INFO_NODE                      DeviceInfoNode;\r\n    PUSB_HUB_CAPABILITIES_EX               HubCapabilityEx;\r\n} USBEXTERNALHUBINFO, *PUSBEXTERNALHUBINFO;\r\n\r\n\r\n// HubInfo, HubName may be in USBDEVICEINFOTYPE, so they can be removed\r\ntypedef struct\r\n{\r\n    USBDEVICEINFOTYPE                      DeviceInfoType;\r\n    PUSB_NODE_INFORMATION                  HubInfo;          // NULL if not a HUB\r\n    PUSB_HUB_INFORMATION_EX                HubInfoEx;        // NULL if not a HUB\r\n    PCHAR                                  HubName;          // NULL if not a HUB\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectionInfo;   // NULL if root HUB\r\n    PUSB_PORT_CONNECTOR_PROPERTIES         PortConnectorProps;\r\n    PUSB_DESCRIPTOR_REQUEST                ConfigDesc;       // NULL if root HUB\r\n    PUSB_DESCRIPTOR_REQUEST                BosDesc;          // NULL if root HUB\r\n    PSTRING_DESCRIPTOR_NODE                StringDescs;\r\n    PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB\r\n    PUSB_DEVICE_PNP_STRINGS                UsbDeviceProperties;\r\n    PDEVICE_INFO_NODE                      DeviceInfoNode;\r\n    PUSB_HUB_CAPABILITIES_EX               HubCapabilityEx;  // NULL if not a HUB\r\n} USBDEVICEINFO, *PUSBDEVICEINFO;\r\n\r\ntypedef struct _STRINGLIST\r\n{\r\n#ifdef H264_SUPPORT\r\n    ULONGLONG       ulFlag;\r\n#else\r\n    ULONG           ulFlag;\r\n#endif\r\n    PCHAR     pszString;\r\n    PCHAR     pszModifier;\r\n\r\n} STRINGLIST, * PSTRINGLIST;\r\n\r\ntypedef struct _DEVICE_GUID_LIST {\r\n    HDEVINFO   DeviceInfo;\r\n    LIST_ENTRY ListHead;\r\n} DEVICE_GUID_LIST, *PDEVICE_GUID_LIST;\r\n\r\n\r\n/*****************************************************************************\r\n G L O B A L S\r\n*****************************************************************************/\r\n\r\n//\r\n// USBVIEW.C\r\n//\r\n\r\nBOOL gDoConfigDesc;\r\nBOOL gDoAnnotation;\r\nBOOL gLogDebug;\r\nint  TotalHubs;\r\n\r\n//\r\n// ENUM.C\r\n//\r\n\r\nPCHAR ConnectionStatuses[];\r\n\r\n//\r\n// DISPVID.C\r\n//\r\nDEFINE_GUID(YUY2_Format,0x32595559L,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71);\r\nDEFINE_GUID(NV12_Format,0x3231564EL,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71);\r\n\r\n#ifdef H264_SUPPORT\r\nDEFINE_GUID(H264_Format,0x34363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);\r\n#endif\r\n\r\n// The following flags/variables are all initialized in Display.c InitializePerDeviceSettings()\r\n//\r\n// Save the default frame from the MJPEG, Uncompressed, Vendor and Frame Based Format descriptor\r\n// Check for this when processing the individual Frame descriptors\r\nUCHAR   g_chMJPEGFrameDefault;\r\nUCHAR   g_chUNCFrameDefault;\r\nUCHAR   g_chVendorFrameDefault;\r\nUCHAR   g_chFrameBasedFrameDefault;\r\n\r\n// Spec version of UVC device\r\nUINT g_chUVCversion;\r\n\r\n// Base address of the USBDEVICEINFO for device we're parsing\r\nPUSBDEVICEINFO CurrentUSBDeviceInfo;\r\n\r\n// Base address of the Configuration descriptor we're parsing\r\nPUSB_CONFIGURATION_DESCRIPTOR  CurrentConfigDesc;\r\n\r\n// Length of the current configuration descriptor\r\nDWORD dwConfigLength;\r\n// Our current position from the beginning of the config descriptor\r\nDWORD dwConfigIndex;\r\n\r\n//\r\n// DISPLAY.C\r\n//\r\nint gDeviceSpeed;\r\n\r\n// Save the current Configuration starting and ending addresses\r\n// Used in ValidateDescAddress()\r\n//\r\nPUSB_CONFIGURATION_DESCRIPTOR   g_pConfigDesc;\r\nPSTRING_DESCRIPTOR_NODE         g_pStringDescs;\r\nPUCHAR                          g_descEnd;\r\n\r\n/*****************************************************************************\r\n F U N C T I O N    P R O T O T Y P E S\r\n*****************************************************************************/\r\n\r\n//\r\n// USBVIEW.C\r\n//\r\n\r\nHTREEITEM\r\nAddLeaf (\r\n    HTREEITEM hTreeParent,\r\n    LPARAM    lParam,\r\n    _In_ LPTSTR    lpszText,\r\n    TREEICON  TreeIcon\r\n);\r\n\r\nVOID\r\nOops\r\n(\r\n    _In_ PCHAR  File,\r\n    ULONG       Line\r\n);\r\n\r\n//\r\n// DISPLAY.C\r\n//\r\n\r\nEXTERN_C UINT IsIADDevice (PUSBDEVICEINFO info);\r\nEXTERN_C UINT IsUVCDevice (PUSBDEVICEINFO info);\r\nEXTERN_C PCHAR GetVendorString(USHORT idVendor);\r\nEXTERN_C PCHAR GetLangIDString(USHORT idLang);\r\nEXTERN_C UINT GetConfigurationSize (PUSBDEVICEINFO info);\r\nEXTERN_C PUSB_COMMON_DESCRIPTOR\r\nGetNextDescriptor(\r\n    _In_reads_bytes_(TotalLength)\r\n        PUSB_COMMON_DESCRIPTOR FirstDescriptor,\r\n    _In_\r\n        ULONG TotalLength,\r\n    _In_\r\n        PUSB_COMMON_DESCRIPTOR StartDescriptor,\r\n    _In_ long\r\n        DescriptorType\r\n    );\r\n\r\nHRESULT\r\nUpdateTreeItemDeviceInfo(\r\n        HWND hTreeWnd,\r\n        HTREEITEM hTreeItem\r\n        );\r\n\r\nPCHAR\r\nGetTextBuffer(\r\n);\r\n\r\nBOOL\r\nResetTextBuffer(\r\n);\r\n\r\nBOOL\r\nCreateTextBuffer (\r\n);\r\n\r\nVOID\r\nDestroyTextBuffer (\r\n);\r\n\r\nUINT\r\nGetTextBufferPos (\r\n);\r\n\r\nVOID\r\nUpdateEditControl (\r\n    HWND      hEditWnd,\r\n    HWND      hTreeWnd,\r\n    HTREEITEM hTreeItem\r\n);\r\n\r\n\r\nVOID __cdecl\r\nAppendBuffer (\r\n    LPCTSTR lpFormat,\r\n    ...\r\n);\r\n\r\nVOID __cdecl\r\nAppendTextBuffer (\r\n    LPCTSTR lpFormat,\r\n    ...\r\n);\r\n\r\nVOID\r\nDisplayStringDescriptor (\r\n    UCHAR                   Index,\r\n    PSTRING_DESCRIPTOR_NODE StringDescs,\r\n    DEVICE_POWER_STATE      LatestDevicePowerState\r\n);\r\n\r\nPCHAR\r\nGetStringFromList(\r\n            PSTRINGLIST     slPowerState,\r\n            ULONG           ulNumElements,\r\n\r\n#ifdef H264_SUPPORT\r\n            ULONGLONG      ulFlag,\r\n#else\r\n            ULONG          ulFlag,\r\n#endif\r\n       _In_ PCHAR           szDefault\r\n            );\r\n\r\nEXTERN_C PCHAR GetPowerStateString(\r\n            WDMUSB_POWER_STATE powerState\r\n            );\r\n\r\nEXTERN_C PCHAR GetControllerFlavorString(\r\n            USB_CONTROLLER_FLAVOR flavor\r\n            );\r\n\r\nEXTERN_C ULONG GetEhciDebugPort(\r\n            ULONG vendorId,\r\n            ULONG deviceId\r\n            );\r\n\r\nVOID\r\nWalkTreeTopDown(\r\n          _In_ HTREEITEM        hTreeItem,\r\n          _In_ LPFNTREECALLBACK lpfnTreeCallback,\r\n          _In_opt_ PVOID            pContext,\r\n          _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback\r\n          );\r\n\r\nVOID RefreshTree (VOID);\r\n\r\n//\r\n// ENUM.C\r\n//\r\n\r\nVOID\r\nEnumerateHostControllers (\r\n    HTREEITEM  hTreeParent,\r\n    ULONG     *DevicesConnected\r\n    );\r\n\r\n\r\nVOID\r\nCleanupItem (\r\n    HWND      hTreeWnd,\r\n    HTREEITEM hTreeItem,\r\n    PVOID pContext\r\n    );\r\n\r\nDEVICE_POWER_STATE\r\nAcquireDevicePowerState(\r\n    _Inout_ PDEVICE_INFO_NODE pNode\r\n    );\r\n\r\n_Success_(return == TRUE)\r\nBOOL\r\nGetDeviceProperty(\r\n    _In_    HDEVINFO         DeviceInfoSet,\r\n    _In_    PSP_DEVINFO_DATA DeviceInfoData,\r\n    _In_    DWORD            Property,\r\n    _Outptr_ LPTSTR         *ppBuffer\r\n    );\r\n\r\nvoid\r\nClearDeviceList(\r\n    PDEVICE_GUID_LIST DeviceList\r\n    );\r\n\r\n//\r\n// DEBUG.C\r\n//\r\n\r\n_Success_(return != NULL)\r\n_Post_writable_byte_size_(dwBytes)\r\nHGLOBAL\r\nMyAlloc (\r\n    _In_    PCHAR   File,\r\n    ULONG   Line,\r\n    DWORD   dwBytes\r\n    );\r\n\r\n_Success_(return != NULL)\r\n_Post_writable_byte_size_(dwBytes)\r\nHGLOBAL\r\nMyReAlloc (\r\n    HGLOBAL hMem,\r\n    DWORD   dwBytes\r\n    );\r\n\r\nHGLOBAL\r\nMyFree (\r\n    HGLOBAL hMem\r\n    );\r\n\r\nVOID\r\nMyCheckForLeaks (\r\n    VOID\r\n    );\r\n\r\n//\r\n// DEVNODE.C\r\n//\r\n\r\n\r\nPUSB_DEVICE_PNP_STRINGS\r\nDriverNameToDeviceProperties(\r\n    _In_reads_bytes_(cbDriverName) PCHAR   DriverName,\r\n    _In_ size_t                       cbDriverName\r\n    );\r\n\r\nVOID FreeDeviceProperties(\r\n        _In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps\r\n        );\r\n//\r\n// DISPAUD.C\r\n//\r\n\r\nBOOL\r\nDisplayAudioDescriptor (\r\n    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc,\r\n    UCHAR                        bInterfaceSubClass\r\n    );\r\n\r\n//\r\n// DISPVID.C\r\n//\r\n\r\nBOOL\r\nDisplayVideoDescriptor (\r\n    PVIDEO_SPECIFIC VidCommonDesc,\r\n    UCHAR                        bInterfaceSubClass,\r\n    PSTRING_DESCRIPTOR_NODE      StringDescs,\r\n    DEVICE_POWER_STATE           LatestDevicePowerState\r\n    );\r\n\r\n//\r\n// DISPLAY.C\r\n//\r\n\r\nBOOL\r\nValidateDescAddress (\r\n    PUSB_COMMON_DESCRIPTOR          commonDesc\r\n    );\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/uvcview.rc",
    "content": "#include <windows.h>\r\n#include <commctrl.h>\r\n#include \"resource.h\"\r\n#include <ntverp.h>\r\n\r\n//////////////////////////////////////////////////////////////////////////////\r\n//\r\n// VERSION\r\n//\r\n#define VER_FILEDESCRIPTION_STR     \"Microsoft\\256 Windows(TM) USB device viewer\"\r\n#define VER_INTERNALNAME_STR        \"USBView\"\r\n#define VER_ORIGINALFILENAME_STR    VER_INTERNALNAME_STR\r\n#define VER_LEGALCOPYRIGHT_STR      \"Copyright \\251 Microsoft Corporation 1996-2011  All Rights Reserved.\"\r\n\r\n#define VER_FILETYPE     VFT_APP\r\n#define VER_FILESUBTYPE  VFT2_UNKNOWN\r\n\r\n#include <common.ver>\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////////\r\n//\r\n// ICON\r\n//\r\nIDI_ICON                ICON    DISCARDABLE     \"USB.ICO\"\r\nIDI_BADICON             ICON    DISCARDABLE     \"BANG.ICO\"\r\nIDI_COMPUTER            ICON    DISCARDABLE     \"MONITOR.ICO\"\r\nIDI_HUB                 ICON    DISCARDABLE     \"HUB.ICO\"\r\nIDI_NODEVICE            ICON    DISCARDABLE     \"PORT.ICO\"\r\nIDI_NOSSDEVICE          ICON    DISCARDABLE     \"SSPORT.ICO\"\r\nIDI_SSICON              ICON    DISCARDABLE     \"SSUSB.ICO\"\r\n\r\n//////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Cursor\r\n//\r\nIDC_SPLIT               CURSOR  DISCARDABLE     \"SPLIT.CUR\"\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Dialog\r\n//\r\n\r\nIDD_MAINDIALOG DIALOGEX 0, 0, 415, 243\r\nSTYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU |\r\n    WS_THICKFRAME\r\nCAPTION \"USB Device Viewer\"\r\nMENU IDR_MENU\r\nFONT 8, \"MS Shell Dlg\"\r\nBEGIN\r\n    CONTROL         \"Tree1\",IDC_TREE,\"SysTreeView32\",TVS_HASBUTTONS |\r\n                    TVS_HASLINES | TVS_LINESATROOT | WS_BORDER | WS_TABSTOP,\r\n                    0,0,120,234,WS_EX_CLIENTEDGE\r\n    EDITTEXT        IDC_EDIT,120,0,295,234,ES_MULTILINE | ES_READONLY |\r\n                    WS_VSCROLL | WS_HSCROLL\r\n    CONTROL         \"Devices Connected: 0\",IDC_STATUS,\"msctls_statusbar32\",\r\n                    SBARS_SIZEGRIP,\r\n                    0,235,415,8\r\nEND\r\n\r\n\r\nIDD_ABOUT DIALOG DISCARDABLE  0, 0, 230, 117\r\nSTYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r\nCAPTION \"About USBView\"\r\nFONT 8, \"MS Shell Dlg\"\r\nBEGIN\r\n    DEFPUSHBUTTON   \"OK\",IDOK,90,100,50,14\r\n    LTEXT           \"USB Device Viewer\",IDC_STATIC,54,15,104,8\r\n    LTEXT           VER_LEGALCOPYRIGHT_STR,IDC_STATIC,54,45,145,8\r\n    EDITTEXT        IDC_VERSION,54,60,110,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\r\n    EDITTEXT        IDC_UVCVERSION,54,75,110,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER\r\n    ICON            IDI_ICON,IDC_STATIC,15,15,21,20\r\nEND\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Menu\r\n//\r\n\r\nIDR_MENU MENU DISCARDABLE\r\nBEGIN\r\n    POPUP \"&File\"\r\n    BEGIN\r\n        MENUITEM \"&Refresh\\tF5\",        ID_REFRESH\r\n        MENUITEM SEPARATOR\r\n        MENUITEM \"Save Current &View ...\"        ID_SAVE\r\n        MENUITEM \"Save As (&txt) ...\",      ID_SAVEALL\r\n        MENUITEM \"Save As (&xml) ...\\tF2\",  ID_SAVEXML\r\n        MENUITEM SEPARATOR\r\n\r\n        MENUITEM \"E&xit\",         ID_EXIT\r\n    END\r\n    POPUP \"&Options\"\r\n    BEGIN\r\n        MENUITEM \"&Auto Refresh\",                   ID_AUTO_REFRESH, CHECKED\r\n        MENUITEM \"Show &Config Descriptors\",        ID_CONFIG_DESCRIPTORS, CHECKED\r\n        MENUITEM SEPARATOR\r\n//      MENUITEM \"&Show Description Annotations\",   ID_ANNOTATION, CHECKED\r\n        MENUITEM \"&Log to debugger\",                ID_LOG_DEBUG\r\n    END\r\n    POPUP \"&Help\"\r\n    BEGIN\r\n        MENUITEM \"&About\",                      ID_ABOUT\r\n    END\r\nEND\r\n\r\n//////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Accelerator\r\n//\r\n\r\nIDACCEL ACCELERATORS DISCARDABLE\r\nBEGIN\r\n    VK_F5,          ID_REFRESH,            VIRTKEY,NOINVERT\r\n    VK_F2,          ID_SAVEXML,            VIRTKEY,NOINVERT\r\nEND\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// String Table\r\n//\r\n\r\nSTRINGTABLE\r\nBEGIN\r\n    IDS_STRINGBASE              \"Base string\"\r\nEND\r\n\r\nSTRINGTABLE\r\nBEGIN\r\n    IDS_STANDARD_FONT           \"Courier\"\r\n    IDS_STANDARD_FONT_HEIGHT    \"\\13\"\r\n    IDS_STANDARD_FONT_WIDTH     \"\\8\"\r\nEND\r\n\r\nSTRINGTABLE DISCARDABLE\r\nBEGIN\r\n    IDS_USBVIEW_USAGE               \"usbview usage:\\nusbview [/?]\\n\\t/? - this usage message.\\\r\n                                    \\n\\t/q quiet mode, does not display 'Press any key to continue ...\\n\\t\\\r\n                                    \\nusbview [/q] [/f] /saveall:<filename.txt>\\\r\n                                    \\n\\tsaveall - saves the USB tree view as a text file\\\r\n                                    \\n\\t/f - overwrite file if it already exists\\n\\nusbview [/q] [/f] /savexml:<filename.xml>\\\r\n                                    \\n\\tsavexml - saves the USB tree view as a xml file\\n\\t/f - overwrite file if it already exists\\n\\n\"\r\n    IDS_USBVIEW_PRESSKEY            \"Press any key to continue ...\\n\"\r\n    IDS_USBVIEW_INVALIDARG          \"Invalid argument: [%1]\\n\"\r\n    IDS_USBVIEW_FILE_EXISTS_TXT     \"File: [%1] already exists, try `usbview /f /saveall:[%1]` to force overwrite\\n\"\r\n    IDS_USBVIEW_FILE_EXISTS_XML     \"File: [%1] already exists, try `usbview /f /savexml:[%1]` to force overwrite\\n\"\r\n    IDS_USBVIEW_INTERNAL_ERROR      \"An internal error occured, please report this as a bug\\n\"\r\n    IDS_USBVIEW_SAVED_TO            \"Usbview information saved to file : [%1]\\n\"\r\n    IDS_USBVIEW_INVALID_FILENAME    \"The argument : [%1] is invalid or incomplete.\\n\"\r\nEND\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/vndrlist.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2008 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    VNDRLIST.H\r\n\r\nAbstract:\r\n\r\n    This header file contains a list of all currently known USB Vendor IDs\r\n    and the vendor name associated with each Vendor ID.\r\n\r\nSource:\r\n\r\n    http://www.usb.org\r\n\r\nEnvironment:\r\n\r\n    Kernel & user mode\r\n\r\nRevision History:\r\n\r\n    04-25-97 : created\r\n    03-28-03 : refreshed with latest list from usb.org\r\n    05-04-05 : refreshed with latest list from usb.org\r\n    05-02-07 : refreshed with latest list from usb.org\r\n    03-19-08 : refreshed with latest list from usb.org\r\n\r\n--*/\r\n\r\n#ifndef   __VNDRLIST_H__\r\n#define   __VNDRLIST_H__\r\n\r\n//\r\n// Vendor ID structure\r\n//\r\ntypedef struct _VENDOR_ID {\r\n    USHORT  usVendorID;\r\n    PCHAR   szVendor;\r\n} VENDOR_ID, *PVENDOR_ID;\r\n\r\n//\r\n// This list built from information obtained from\r\n// http://www.usb.org/developers/tools/\r\n//\r\n// This information has not been independently verified and no claims\r\n// are made here as to its accuracy.\r\n//\r\n// 10978 total\r\n//\r\nVENDOR_ID USBVendorIDs[] =\r\n{\r\n    { 0x0079, \"Shenzhen Longshengwei Technology, Co., Ltd.\"  },\r\n    { 0x013A, \"Aimgene Technology Co., Ltd\"  },\r\n    { 0x03CC, \"GN OTOMETRICS\"  },\r\n    { 0x03E8, \"EndPoints Inc.\"  },\r\n    { 0x03E9, \"Thesys Microelectronics\"  },\r\n    { 0x03EA, \"Data Broadcasting Corp.\"  },\r\n    { 0x03EB, \"Atmel Corporation\"  },\r\n    { 0x03EC, \"Iwatsu America Inc.\"  },\r\n    { 0x03ED, \"Mitel Corporation\"  },\r\n    { 0x03EE, \"Mitsumi\"  },\r\n    { 0x03F0, \"HP Inc.\"  },\r\n    { 0x03F1, \"Genoa Technology\"  },\r\n    { 0x03F2, \"Oak Technology, Inc\"  },\r\n    { 0x03F3, \"Adaptec, Inc.\"  },\r\n    { 0x03F4, \"Diebold, Inc.\"  },\r\n    { 0x03F5, \"Siemens Electromechanical\"  },\r\n    { 0x03F7, \"Tulip Computers International\"  },\r\n    { 0x03F8, \"Epson Imaging Technology Center\"  },\r\n    { 0x03F9, \"KeyTronic Corp.\"  },\r\n    { 0x03FB, \"OPTi Inc.\"  },\r\n    { 0x03FC, \"Elitegroup Computer Systems\"  },\r\n    { 0x03FD, \"Xilinx Inc.\"  },\r\n    { 0x03FE, \"Farallon Comunications\"  },\r\n    { 0x03FF, \"Weitek Corporation\"  },\r\n    { 0x0400, \"National Semiconductor\"  },\r\n    { 0x0401, \"National Registry Inc.\"  },\r\n    { 0x0402, \"ALi Corporation\"  },\r\n    { 0x0403, \"Future Technology Devices International Limited\"  },\r\n    { 0x0404, \"NCR Corporation\"  },\r\n    { 0x0405, \"inSilicon\"  },\r\n    { 0x0406, \"Fujitsu-ICL Computers\"  },\r\n    { 0x0407, \"Fujitsu Personal Systems, Inc.\"  },\r\n    { 0x0408, \"Quanta Computer Inc.\"  },\r\n    { 0x0409, \"NEC Corporation\"  },\r\n    { 0x040A, \"Eastman Kodak Company\"  },\r\n    { 0x040B, \"Weltrend Semiconductor\"  },\r\n    { 0x040C, \"VTech Computers Ltd\"  },\r\n    { 0x040D, \"VIA Technologies, Inc.\"  },\r\n    { 0x040E, \"MCCI Corporation\"  },\r\n    { 0x040F, \"Echo Speech Corporation\"  },\r\n    { 0x0410, \"Isis Distributed Systems, Inc.\"  },\r\n    { 0x0411, \"BUFFALO INC.\"  },\r\n    { 0x0412, \"Award Software International\"  },\r\n    { 0x0413, \"Leadtek Research Inc.\"  },\r\n    { 0x0414, \"Giga-Byte Technology Co., Ltd.\"  },\r\n    { 0x0416, \"Nuvoton Technology Corp.\"  },\r\n    { 0x0417, \"Symbios, Inc.\"  },\r\n    { 0x0418, \"AST Research\"  },\r\n    { 0x0419, \"Samsung Info. Systems America Inc.\"  },\r\n    { 0x041A, \"Phoenix Technologies Ltd.\"  },\r\n    { 0x041B, \"d'TV\"  },\r\n    { 0x041D, \"S3 Incorporated\"  },\r\n    { 0x041E, \"Creative Labs\"  },\r\n    { 0x041F, \"LCS Telegraphics\"  },\r\n    { 0x0420, \"Chips and Technologies\"  },\r\n    { 0x0421, \"Nokia Corporation\"  },\r\n    { 0x0422, \"ADI Systems Inc.\"  },\r\n    { 0x0423, \"CATC\"  },\r\n    { 0x0424, \"Microchip-SMSC\"  },\r\n    { 0x0425, \"Freescale Semiconductor Hong Kong Limited\"  },\r\n    { 0x0426, \"Integrated Device Technology\"  },\r\n    { 0x0427, \"Motorola Electronics Taiwan Ltd.\"  },\r\n    { 0x0428, \"Advanced Gravis Computer Ltd.\"  },\r\n    { 0x0429, \"Cirrus Logic Inc.\"  },\r\n    { 0x042A, \"Ericsson Austrian, AG\"  },\r\n    { 0x042C, \"Innovative Semiconductors, Inc.\"  },\r\n    { 0x042D, \"Micronics\"  },\r\n    { 0x042E, \"Acer, Inc.(2)\"  },\r\n    { 0x042F, \"Molex Inc.\"  },\r\n    { 0x0430, \"Fujitsu Component Limited\"  },\r\n    { 0x0431, \"ITAC Systems, Inc.\"  },\r\n    { 0x0432, \"Unisys Corp.\"  },\r\n    { 0x0433, \"Alps Electric Inc.\"  },\r\n    { 0x0434, \"Samsung Info. Systems America Inc.(2)\"  },\r\n    { 0x0435, \"Hyundai Electronics America\"  },\r\n    { 0x0436, \"Taugagreining HF\"  },\r\n    { 0x0437, \"Framatome Connectors USA\"  },\r\n    { 0x0438, \"Advanced Micro Devices\"  },\r\n    { 0x0439, \"Voice Technologies Group\"  },\r\n    { 0x043C, \"Lucid Designs\"  },\r\n    { 0x043D, \"Lexmark International Inc.\"  },\r\n    { 0x043E, \"LG Electronics USA Inc.\"  },\r\n    { 0x043F, \"RadiSys Corporation\"  },\r\n    { 0x0440, \"EIZO NANAO CORPORATION\"  },\r\n    { 0x0441, \"Winbond Systems Lab.\"  },\r\n    { 0x0442, \"Cygnion Corp.\"  },\r\n    { 0x0443, \"Gateway 2000\"  },\r\n    { 0x0445, \"Agere Systems\"  },\r\n    { 0x0446, \"NMB Technologies Corporation\"  },\r\n    { 0x0447, \"Momentum Microsystems\"  },\r\n    { 0x0449, \"Eldim\"  },\r\n    { 0x044A, \"Shamrock Technology Co., Ltd.\"  },\r\n    { 0x044B, \"WSI\"  },\r\n    { 0x044C, \"CCL/ITRI\"  },\r\n    { 0x044D, \"Siemens Nixdorf AG\"  },\r\n    { 0x044E, \"Alps Electric Co., Ltd.\"  },\r\n    { 0x044F, \"ThrustMaster, Inc.\"  },\r\n    { 0x0450, \"DFI Inc.\"  },\r\n    { 0x0451, \"Texas Instruments\"  },\r\n    { 0x0452, \"Mitsubishi Electric & Electronics US, Inc.\"  },\r\n    { 0x0453, \"CMD Technology\"  },\r\n    { 0x0454, \"Vobis Microcomputer AGO\"  },\r\n    { 0x0455, \"Telematics International, Inc.\"  },\r\n    { 0x0456, \"Analog Devices, Inc.\"  },\r\n    { 0x0457, \"Silicon Integrated Systems Corp.\"  },\r\n    { 0x0458, \"KYE Systems Corp.\"  },\r\n    { 0x0459, \"Adobe Systems, Inc.\"  },\r\n    { 0x045A, \"SONICblue Incorporated\"  },\r\n    { 0x045B, \"Renesas Electronics Corp.\"  },\r\n    { 0x045D, \"Nortel Networks\"  },\r\n    { 0x045E, \"Microsoft Corporation\"  },\r\n    { 0x0460, \"Ace Cad Enterprise Co., Ltd.\"  },\r\n    { 0x0461, \"Primax Electronics\"  },\r\n    { 0x0463, \"EATON\"  },\r\n    { 0x0464, \"AMP/Tycoelectronics\"  },\r\n    { 0x0465, \"Pacific Micro Computing\"  },\r\n    { 0x0467, \"AT&T Paradyne\"  },\r\n    { 0x0468, \"Wieson Technologies Co., Ltd.\"  },\r\n    { 0x046A, \"CHERRY\"  },\r\n    { 0x046B, \"American Megatrends\"  },\r\n    { 0x046C, \"Toshiba Corporation, Digital Media Network Company\"  },\r\n    { 0x046D, \"Logitech Inc.\"  },\r\n    { 0x046E, \"Behavior Tech Computer Corporation\"  },\r\n    { 0x046F, \"Crystal Semiconductor\"  },\r\n    { 0x0471, \"Philips Consumer Lifestyle BV\"  },\r\n    { 0x0472, \"Oracle\"  },\r\n    { 0x0473, \"Sanyo Information Business Co., Ltd.\"  },\r\n    { 0x0474, \"Sanyo Electric Co. Ltd.\"  },\r\n    { 0x0475, \"TECO Electric & Machinery Co., Ltd.\"  },\r\n    { 0x0476, \"AESP\"  },\r\n    { 0x0477, \"Seagate Technology\"  },\r\n    { 0x0478, \"Connectix Corp.\"  },\r\n    { 0x0479, \"Advanced Peripheral Laboratories\"  },\r\n    { 0x047A, \"Semtech Corporation\"  },\r\n    { 0x047B, \"Silitek Corp.\"  },\r\n    { 0x047D, \"Kensington\"  },\r\n    { 0x047E, \"Avago Technologies Inc.\"  },\r\n    { 0x047F, \"Plantronics, Inc.\"  },\r\n    { 0x0480, \"Toshiba America Info. Systems, Inc.\"  },\r\n    { 0x0481, \"Zenith Data Systems\"  },\r\n    { 0x0482, \"Kyocera Corporation\"  },\r\n    { 0x0483, \"STMicroelectronics\"  },\r\n    { 0x0484, \"Specialix\"  },\r\n    { 0x0485, \"Nokia Monitors\"  },\r\n    { 0x0486, \"ASUS Computers Inc.\"  },\r\n    { 0x0487, \"Stewart Connector\"  },\r\n    { 0x0488, \"Cirque Corporation\"  },\r\n    { 0x0489, \"Foxconn - Hon Hai\"  },\r\n    { 0x048A, \"S-MOS Systems, Inc.\"  },\r\n    { 0x048C, \"Alps Electric Ireland Ltd.\"  },\r\n    { 0x048D, \"ITE Tech Inc.\"  },\r\n    { 0x048F, \"Eicon Tech.\"  },\r\n    { 0x0490, \"United Microelectronic Corporation (UMC)\"  },\r\n    { 0x0491, \"Capetronic Kaohsiung Corp.\"  },\r\n    { 0x0492, \"Samsung Semiconductor, Inc.\"  },\r\n    { 0x0493, \"MAG Technology Co., Ltd.\"  },\r\n    { 0x0495, \"ESS Technology, Inc.\"  },\r\n    { 0x0496, \"Micron Electronics\"  },\r\n    { 0x0497, \"Smile International, Inc.\"  },\r\n    { 0x0498, \"Capetronic (Kaohsiung) Corp.\"  },\r\n    { 0x0499, \"Yamaha Corporation\"  },\r\n    { 0x049A, \"Gandalf Technologies Ltd.\"  },\r\n    { 0x049B, \"Curtis Computer Products\"  },\r\n    { 0x049C, \"Acer Advanced Labs, Inc.\"  },\r\n    { 0x049D, \"VLSI Technology, Inc.\"  },\r\n    { 0x049F, \"Compaq Computer Corporation\"  },\r\n    { 0x04A0, \"Digital Equipment Corp.\"  },\r\n    { 0x04A1, \"SystemSoft Corporation\"  },\r\n    { 0x04A2, \"FirePower Systems\"  },\r\n    { 0x04A3, \"Trident Microsystems Inc.\"  },\r\n    { 0x04A4, \"Hitachi, Ltd.\"  },\r\n    { 0x04A5, \"BenQ Corporation\"  },\r\n    { 0x04A6, \"Nokia Display Products\"  },\r\n    { 0x04A7, \"Visioneer\"  },\r\n    { 0x04A8, \"Multivideo Labs, Inc.\"  },\r\n    { 0x04A9, \"Canon Inc.\"  },\r\n    { 0x04AA, \"Daewoo Teletech Co., Ltd.\"  },\r\n    { 0x04AB, \"Chromatic Research\"  },\r\n    { 0x04AC, \"Micro Audiometrics Corp.\"  },\r\n    { 0x04AD, \"Dooin Electronics\"  },\r\n    { 0x04AE, \"Brooktree Corporation\"  },\r\n    { 0x04AF, \"Winnov L.P.\"  },\r\n    { 0x04B0, \"Nikon Corporation\"  },\r\n    { 0x04B1, \"Pan International\"  },\r\n    { 0x04B3, \"IBM Corporation\"  },\r\n    { 0x04B4, \"Cypress Semiconductor\"  },\r\n    { 0x04B5, \"ROHM Co., Ltd.\"  },\r\n    { 0x04B6, \"Hint Corporation\"  },\r\n    { 0x04B7, \"Compal Electronics, Inc.\"  },\r\n    { 0x04B8, \"Seiko Epson Corp.\"  },\r\n    { 0x04B9, \"SafeNet, Inc.\"  },\r\n    { 0x04BA, \"Toucan Systems Limited\"  },\r\n    { 0x04BB, \"I-O Data Device, Inc.\"  },\r\n    { 0x04BC, \"Digital Systems Associates\"  },\r\n    { 0x04BD, \"Toshiba Electronics Taiwan Corp.\"  },\r\n    { 0x04BE, \"Telia Research AB\"  },\r\n    { 0x04BF, \"TDK Corporation\"  },\r\n    { 0x04C2, \"Methode Electronics Far East Pte Ltd.\"  },\r\n    { 0x04C3, \"Maxi Switch, Inc.\"  },\r\n    { 0x04C4, \"Lockheed Martin Energy Research\"  },\r\n    { 0x04C5, \"Fujitsu Ltd.\"  },\r\n    { 0x04C6, \"Toshiba America Electronic Components\"  },\r\n    { 0x04C7, \"Micro Macro Technologies\"  },\r\n    { 0x04C8, \"Konica Corporation\"  },\r\n    { 0x04CA, \"Lite-On Technology Corp.\"  },\r\n    { 0x04CB, \"FUJIFILM Corporation\"  },\r\n    { 0x04CC, \"ST-Ericsson\"  },\r\n    { 0x04CD, \"Tatung Company of America, Inc.\"  },\r\n    { 0x04CE, \"ScanLogic Corporation\"  },\r\n    { 0x04CF, \"Myson Century, Inc.\"  },\r\n    { 0x04D0, \"Digi International\"  },\r\n    { 0x04D1, \"ITT Cannon\"  },\r\n    { 0x04D2, \"Altec Lansing Technologies, Inc.\"  },\r\n    { 0x04D3, \"VidUS, Inc.\"  },\r\n    { 0x04D4, \"LSI Logic Inc.\"  },\r\n    { 0x04D5, \"Forte Technologies, Inc.\"  },\r\n    { 0x04D6, \"Mentor Graphics\"  },\r\n    { 0x04D7, \"Oki Semiconductor\"  },\r\n    { 0x04D8, \"Microchip Technology Inc.\"  },\r\n    { 0x04D9, \"Holtek Semiconductor, Inc.\"  },\r\n    { 0x04DA, \"Panasonic Corporation\"  },\r\n    { 0x04DB, \"Hypertec Ltd.\"  },\r\n    { 0x04DC, \"Huan Hsin Holdings Ltd.\"  },\r\n    { 0x04DD, \"Sharp Corporation\"  },\r\n    { 0x04DE, \"MindShare, Inc.\"  },\r\n    { 0x04DF, \"ePadLink\"  },\r\n    { 0x04E1, \"Iiyama Corporation\"  },\r\n    { 0x04E2, \"Exar Corporation\"  },\r\n    { 0x04E3, \"Zilog\"  },\r\n    { 0x04E4, \"ACC Microelectronics\"  },\r\n    { 0x04E5, \"Promise Technology\"  },\r\n    { 0x04E6, \"Identiv, Inc.\"  },\r\n    { 0x04E7, \"Elo TouchSystems\"  },\r\n    { 0x04E8, \"Samsung Electronics Co., Ltd.\"  },\r\n    { 0x04E9, \"PC-Tel, Inc.\"  },\r\n    { 0x04EA, \"Sipex Corporation\"  },\r\n    { 0x04EB, \"Northstar Systems Corp.\"  },\r\n    { 0x04EC, \"Tokyo Electron Device Limited\"  },\r\n    { 0x04ED, \"Annabooks\"  },\r\n    { 0x04EF, \"Pacific Electronic International, Inc.\"  },\r\n    { 0x04F0, \"Daewoo Electronics Co., Ltd.\"  },\r\n    { 0x04F1, \"Victor Company of Japan, Limited\"  },\r\n    { 0x04F2, \"Chicony Electronics Co., Ltd.\"  },\r\n    { 0x04F3, \"ELAN Microelectronics Corportation\"  },\r\n    { 0x04F4, \"Harting Elektronik Inc.\"  },\r\n    { 0x04F5, \"Fujitsu-ICL Systems, Inc.\"  },\r\n    { 0x04F6, \"Norand Corporation\"  },\r\n    { 0x04F7, \"Newnex Technology Corp.\"  },\r\n    { 0x04F8, \"FuturePlus Systems\"  },\r\n    { 0x04F9, \"Brother Industries, Ltd.\"  },\r\n    { 0x04FA, \"Dallas Semiconductor\"  },\r\n    { 0x04FB, \"Biostar Microtech Int'l Corp.\"  },\r\n    { 0x04FC, \"SUNPLUS TECHNOLOGY CO., LTD.\"  },\r\n    { 0x04FD, \"Soliton Systems K.K.\"  },\r\n    { 0x04FE, \"PFU Limited\"  },\r\n    { 0x04FF, \"E-CMOS Corp.\"  },\r\n    { 0x0500, \"Siam United Hi-Tech\"  },\r\n    { 0x0501, \"Fujikura/DDK\"  },\r\n    { 0x0502, \"Acer, Inc.\"  },\r\n    { 0x0503, \"Hitachi America Ltd.\"  },\r\n    { 0x0504, \"Hayes Microcomputer Products\"  },\r\n    { 0x0505, \"Digital Home Corporation\"  },\r\n    { 0x0506, \"3Com Corporation\"  },\r\n    { 0x0507, \"Hosiden Corporation\"  },\r\n    { 0x0508, \"Clarion Co., Ltd.\"  },\r\n    { 0x0509, \"Aztech Systems Ltd\"  },\r\n    { 0x050A, \"Cinch Connectors\"  },\r\n    { 0x050B, \"Cable System International\"  },\r\n    { 0x050C, \"InnoMedia, Inc.\"  },\r\n    { 0x050D, \"Belkin International, Inc.\"  },\r\n    { 0x050E, \"Neon Technology, Inc.\"  },\r\n    { 0x050F, \"KC Technology Inc.\"  },\r\n    { 0x0510, \"Sejin Electron Inc.\"  },\r\n    { 0x0511, \"N*ABLE Technologies, Inc (Data Book)\"  },\r\n    { 0x0512, \"Hualon Microelectronics Corp.\"  },\r\n    { 0x0513, \"digital-X, Inc.\"  },\r\n    { 0x0514, \"FCI Electronics\"  },\r\n    { 0x0515, \"ACTC\"  },\r\n    { 0x0516, \"Longwell Electronics/Longwell Company\"  },\r\n    { 0x0517, \"Butterfly Communications\"  },\r\n    { 0x0518, \"EzKEY Corp.\"  },\r\n    { 0x0519, \"Star Micronics Co., LTD\"  },\r\n    { 0x051A, \"WYSE Technology\"  },\r\n    { 0x051C, \"Shuttle Inc.\"  },\r\n    { 0x051D, \"American Power Conversion\"  },\r\n    { 0x051E, \"Scientific Atlanta, Inc.\"  },\r\n    { 0x051F, \"IO Systems Inc.\"  },\r\n    { 0x0520, \"Taiwan Semiconductor Manufacturing Co.\"  },\r\n    { 0x0521, \"Airborn Connectors\"  },\r\n    { 0x0522, \"ACON, Advanced-Connectek, Inc.\"  },\r\n    { 0x0523, \"ATEN GMBH\"  },\r\n    { 0x0524, \"Sola Electronics\"  },\r\n    { 0x0525, \"PLX Technology, Inc.\"  },\r\n    { 0x0526, \"Temic MHS S.A.\"  },\r\n    { 0x0527, \"ALTRA\"  },\r\n    { 0x0528, \"ATI Technologies, Inc.\"  },\r\n    { 0x0529, \"SafeNet Data Security (Israel) Ltd.\"  },\r\n    { 0x052A, \"Crescent Heart Software\"  },\r\n    { 0x052B, \"Tekom Technologies, Inc\"  },\r\n    { 0x052C, \"Canon Development Americas\"  },\r\n    { 0x052D, \"Avid Electronics Corp.\"  },\r\n    { 0x052E, \"Standard Microsystems Corp. (1)\"  },\r\n    { 0x052F, \"Unicore Software, Inc.\"  },\r\n    { 0x0530, \"American Microsystems Inc.\"  },\r\n    { 0x0531, \"Wacom Technology Corp.\"  },\r\n    { 0x0532, \"Systech Corporation\"  },\r\n    { 0x0533, \"Alcatel Mobile Phones\"  },\r\n    { 0x0534, \"Motorola\"  },\r\n    { 0x0535, \"LIH TZU Electric Co., Ltd.\"  },\r\n    { 0x0536, \"Hand Held Products (Honeywell International Inc.)\"  },\r\n    { 0x0537, \"Inventec Corporation\"  },\r\n    { 0x0538, \"The SCO Group\"  },\r\n    { 0x0539, \"Shyh Shiun Terminals Co. LTD\"  },\r\n    { 0x053A, \"Preh KeyTec GmbH\"  },\r\n    { 0x053B, \"Global Village Communication\"  },\r\n    { 0x053C, \"Institut of Microelectronic & Mechatronic Systems\"  },\r\n    { 0x053D, \"Silicon Architect\"  },\r\n    { 0x053E, \"Mobility Electronics\"  },\r\n    { 0x053F, \"Synopsys, Inc.\"  },\r\n    { 0x0540, \"UniAccess AB\"  },\r\n    { 0x0541, \"Sirf Technology, Inc\"  },\r\n    { 0x0542, \"MICOM Communications Corp.\"  },\r\n    { 0x0543, \"ViewSonic Corporation\"  },\r\n    { 0x0544, \"Cristie Electronics Ltd.\"  },\r\n    { 0x0545, \"Veo\"  },\r\n    { 0x0546, \"Polaroid Corporation\"  },\r\n    { 0x0547, \"Anchor Chips Inc.\"  },\r\n    { 0x0548, \"Tyan Computer Corp.\"  },\r\n    { 0x0549, \"Pixera Corporation\"  },\r\n    { 0x054A, \"Fujitsu Microelectronics, Inc.\"  },\r\n    { 0x054B, \"New Media Corporation\"  },\r\n    { 0x054C, \"Sony Corporation\"  },\r\n    { 0x054D, \"Try Corporation\"  },\r\n    { 0x054E, \"Proside Corporation\"  },\r\n    { 0x054F, \"WYSE Technology Taiwan\"  },\r\n    { 0x0550, \"Fuji Xerox Co., Ltd.\"  },\r\n    { 0x0551, \"CompuTrend Systems, Inc.\"  },\r\n    { 0x0552, \"Philips Monitors\"  },\r\n    { 0x0553, \"STMicroelectronics Imaging Division\"  },\r\n    { 0x0554, \"Dictaphone Corp.\"  },\r\n    { 0x0555, \"ANAM S&T Co., Ltd.\"  },\r\n    { 0x0556, \"Asahi Kasei Microdevices Corporation\"  },\r\n    { 0x0557, \"ATEN International Co. Ltd.\"  },\r\n    { 0x0558, \"Truevision, Inc.\"  },\r\n    { 0x0559, \"Cadence Design Systems, Inc.\"  },\r\n    { 0x055A, \"Kenwood USA\"  },\r\n    { 0x055B, \"KnowledgeTek, Inc.\"  },\r\n    { 0x055C, \"Proton Electronic Ind.\"  },\r\n    { 0x055D, \"Samsung Electro-Mechanics Co.\"  },\r\n    { 0x055E, \"Optoma Corporation\"  },\r\n    { 0x055F, \"Mustek Systems Inc.\"  },\r\n    { 0x0560, \"Interface Corporation\"  },\r\n    { 0x0561, \"Oasis Design, Inc.\"  },\r\n    { 0x0562, \"Telex Communications Inc.\"  },\r\n    { 0x0563, \"Immersion Corporation\"  },\r\n    { 0x0564, \"Kodak Digital Product Center, Japan Ltd.\"  },\r\n    { 0x0565, \"Peracom Networks, Inc.\"  },\r\n    { 0x0566, \"Monterey International Corp.\"  },\r\n    { 0x0567, \"Xyratex\"  },\r\n    { 0x0568, \"Quartz Ingenierie\"  },\r\n    { 0x0569, \"SegaSoft\"  },\r\n    { 0x056A, \"WACOM Co., Ltd.\"  },\r\n    { 0x056B, \"Decicon Incorporated\"  },\r\n    { 0x056C, \"Belkin Research & Development\"  },\r\n    { 0x056D, \"EIZO Corporation\"  },\r\n    { 0x056E, \"Elecom Co., Ltd.\"  },\r\n    { 0x056F, \"Korea Data Systems Co., Ltd.\"  },\r\n    { 0x0570, \"Epson America\"  },\r\n    { 0x0571, \"XLR8, Inc.\"  },\r\n    { 0x0572, \"Conexant Systems, Inc.\"  },\r\n    { 0x0573, \"Zoran Corporation\"  },\r\n    { 0x0574, \"City University of Hong Kong\"  },\r\n    { 0x0575, \"Philips Creative Display Solutions\"  },\r\n    { 0x0576, \"BAFO/Quality Computer Accessories\"  },\r\n    { 0x0577, \"ELSA\"  },\r\n    { 0x0578, \"Intrinsix Corp.\"  },\r\n    { 0x0579, \"GVC Corporation\"  },\r\n    { 0x057A, \"Samsung Electronics America\"  },\r\n    { 0x057B, \"Y-E Data, Inc.\"  },\r\n    { 0x057C, \"AVM GmbH\"  },\r\n    { 0x057D, \"Shark Multimedia Inc.\"  },\r\n    { 0x057E, \"Nintendo Co., Ltd.\"  },\r\n    { 0x057F, \"QuickShot Limited\"  },\r\n    { 0x0580, \"Denron Inc.\"  },\r\n    { 0x0581, \"Racal Data Group\"  },\r\n    { 0x0582, \"Roland Corporation\"  },\r\n    { 0x0583, \"Padix Co., Ltd.\"  },\r\n    { 0x0584, \"RATOC Systems, Inc.\"  },\r\n    { 0x0585, \"FlashPoint Technology, Inc.\"  },\r\n    { 0x0586, \"ZyXEL Communications Corp\"  },\r\n    { 0x0587, \"Matsushita Kotobuki Electronics Industries America\"  },\r\n    { 0x0588, \"Sapien Design\"  },\r\n    { 0x0589, \"Victron\"  },\r\n    { 0x058A, \"Nohau Corporation\"  },\r\n    { 0x058B, \"Infineon Technologies\"  },\r\n    { 0x058C, \"In Focus Systems\"  },\r\n    { 0x058D, \"Micrel Semiconductor\"  },\r\n    { 0x058E, \"Tripath Technology Inc.\"  },\r\n    { 0x058F, \"Alcor Micro, Corp.\"  },\r\n    { 0x0590, \"OMRON Corporation\"  },\r\n    { 0x0591, \"Questra Consulting\"  },\r\n    { 0x0592, \"Powerware Corporation\"  },\r\n    { 0x0593, \"Incite\"  },\r\n    { 0x0594, \"Princeton Graphic Systems\"  },\r\n    { 0x0595, \"Zoran Microelectronics Ltd.\"  },\r\n    { 0x0596, \"3M Touch Systems\"  },\r\n    { 0x0597, \"Trisignal Communications\"  },\r\n    { 0x0598, \"Niigata Canotec Co., Inc.\"  },\r\n    { 0x0599, \"Brilliance Semiconductor Inc.\"  },\r\n    { 0x059A, \"Spectrum Signal Processing Inc.\"  },\r\n    { 0x059B, \"Iomega Corporation\"  },\r\n    { 0x059C, \"A-Trend Technology Co., Ltd.\"  },\r\n    { 0x059D, \"Advanced Input Devices\"  },\r\n    { 0x059E, \"Intelligent Instrumentation\"  },\r\n    { 0x059F, \"LaCie\"  },\r\n    { 0x05A0, \"Vetronix Corporation\"  },\r\n    { 0x05A1, \"UKC Electronics Corporation\"  },\r\n    { 0x05A2, \"Fuji Film Microdevices Co. Ltd.\"  },\r\n    { 0x05A3, \"TransDimension-NH LLC\"  },\r\n    { 0x05A4, \"Ortek Technology, Inc.\"  },\r\n    { 0x05A5, \"Sampo Technology Corp.\"  },\r\n    { 0x05A6, \"Cisco Systems, Inc.\"  },\r\n    { 0x05A7, \"Bose Corporation\"  },\r\n    { 0x05A8, \"Spacetec IMC Corporation\"  },\r\n    { 0x05A9, \"OmniVision Technologies, Inc.\"  },\r\n    { 0x05AA, \"Utilux South China Ltd.\"  },\r\n    { 0x05AB, \"In-System Design\"  },\r\n    { 0x05AC, \"Apple\"  },\r\n    { 0x05AD, \"Y.C. Cable U.S.A., Inc\"  },\r\n    { 0x05AE, \"Synopsys, Inc.(2)\"  },\r\n    { 0x05AF, \"Sunrex Technology Corp.\"  },\r\n    { 0x05B0, \"Fountain Technologies, Inc\"  },\r\n    { 0x05B1, \"First International Computer, Inc.\"  },\r\n    { 0x05B2, \"Focus Electronics\"  },\r\n    { 0x05B4, \"HYUNDAI Electronics Industries Co., Ltd.\"  },\r\n    { 0x05B5, \"Dialogic Corp\"  },\r\n    { 0x05B6, \"Proxima Corporation\"  },\r\n    { 0x05B7, \"Medianix Semiconductor, Inc.\"  },\r\n    { 0x05B8, \"Sysgration\"  },\r\n    { 0x05B9, \"Philips Research Laboratories\"  },\r\n    { 0x05BA, \"DigitalPersona, Inc.\"  },\r\n    { 0x05BB, \"Grey Cell Systems\"  },\r\n    { 0x05BD, \"RAFI GmbH & Co. KG\"  },\r\n    { 0x05BE, \"Tyco Electronics Corp., a TE Connectivity Ltd. company\"  },\r\n    { 0x05BF, \"S & S Research\"  },\r\n    { 0x05C0, \"Keil Software\"  },\r\n    { 0x05C1, \"MegaChips Corporation\"  },\r\n    { 0x05C2, \"Media Phonics (Suisse) S.A.\"  },\r\n    { 0x05C3, \"VME Microsystems\"  },\r\n    { 0x05C5, \"Digi International Inc.\"  },\r\n    { 0x05C6, \"Qualcomm, Inc\"  },\r\n    { 0x05C7, \"Qtronix Corp\"  },\r\n    { 0x05C8, \"Foxlink/Cheng Uei Precision Industry Co., Ltd\"  },\r\n    { 0x05C9, \"Semtech\"  },\r\n    { 0x05CA, \"Ricoh Company Ltd.\"  },\r\n    { 0x05CB, \"PowerVision Technologies Inc.\"  },\r\n    { 0x05CC, \"Neue ELSA GmbH\"  },\r\n    { 0x05CD, \"Silicom LTD.\"  },\r\n    { 0x05CE, \"sci-worx GmbH\"  },\r\n    { 0x05CF, \"Sung Forn Co. LTD.\"  },\r\n    { 0x05D0, \"GE Medical Systems Lunar\"  },\r\n    { 0x05D1, \"Brainboxes Limited\"  },\r\n    { 0x05D2, \"Wave Systems Corp.\"  },\r\n    { 0x05D3, \"Tohoku Ricoh Co., Ltd.\"  },\r\n    { 0x05D5, \"Super Gate Technology Co., LTD\"  },\r\n    { 0x05D6, \"Philips Semiconductors, CICT\"  },\r\n    { 0x05D7, \"Thomas & Betts\"  },\r\n    { 0x05D8, \"Ultima Electronics Corp.\"  },\r\n    { 0x05D9, \"TPG IPB, Inc.\"  },\r\n    { 0x05DA, \"Microtek International Inc.\"  },\r\n    { 0x05DB, \"Sun Corporation\"  },\r\n    { 0x05DC, \"Lexar Media, Inc.\"  },\r\n    { 0x05DD, \"Delta Electronics Inc.\"  },\r\n    { 0x05DE, \"Crucial Technology\"  },\r\n    { 0x05DF, \"Silicon Vision Inc.\"  },\r\n    { 0x05E0, \"Symbol Technologies\"  },\r\n    { 0x05E1, \"Syntek Semiconductor Co., Ltd.\"  },\r\n    { 0x05E2, \"ElecVision Inc.\"  },\r\n    { 0x05E3, \"Genesys Logic, Inc.\"  },\r\n    { 0x05E4, \"Red Wing Corporation\"  },\r\n    { 0x05E5, \"Fuji Electric Co., Ltd.\"  },\r\n    { 0x05E6, \"Keithley Instruments\"  },\r\n    { 0x05E7, \"EIZO Nanao Technologies Inc.\"  },\r\n    { 0x05E8, \"ICC, Inc.\"  },\r\n    { 0x05E9, \"Kawasaki Microelectronics America, Inc.\"  },\r\n    { 0x05EA, \"Evergreen Systems International\"  },\r\n    { 0x05EB, \"FFC Limited\"  },\r\n    { 0x05EC, \"COM21, Inc.\"  },\r\n    { 0x05EE, \"Cytechinfo Inc.\"  },\r\n    { 0x05EF, \"Anko Electronic Co., Ltd.\"  },\r\n    { 0x05F0, \"Canopus Co., Ltd.\"  },\r\n    { 0x05F2, \"Dexin Corporation, Ltd.\"  },\r\n    { 0x05F3, \"PI Engineering, Inc.\"  },\r\n    { 0x05F4, \"Davis AS\"  },\r\n    { 0x05F5, \"Unixtar Technology Inc.\"  },\r\n    { 0x05F6, \"Envision Peripherals, Inc.\"  },\r\n    { 0x05F7, \"Silicon Portals Inc.\"  },\r\n    { 0x05F8, \"Phase Metrics\"  },\r\n    { 0x05F9, \"Datalogic ADC\"  },\r\n    { 0x05FA, \"Siemens Telecommunications Systems Limited\"  },\r\n    { 0x05FC, \"Harman Multimedia\"  },\r\n    { 0x05FD, \"STD Manufacturing Ltd.\"  },\r\n    { 0x05FE, \"CHIC TECHNOLOGY CORP\"  },\r\n    { 0x05FF, \"LeCroy Corporation\"  },\r\n    { 0x0600, \"Barco\"  },\r\n    { 0x0601, \"Jazz Hipster Corporation\"  },\r\n    { 0x0602, \"Vista Imaging Inc.\"  },\r\n    { 0x0603, \"Novatek Microelectronics Corp.\"  },\r\n    { 0x0604, \"Jean Co, Ltd.\"  },\r\n    { 0x0605, \"Anchor C&C Co., Ltd.\"  },\r\n    { 0x0606, \"Royal Information Electronics Co., Ltd.\"  },\r\n    { 0x0607, \"Bridge Information Co., Ltd.\"  },\r\n    { 0x0608, \"Genrad Ads\"  },\r\n    { 0x0609, \"SMK Manufacturing Inc.\"  },\r\n    { 0x060A, \"Worth Data, Inc.\"  },\r\n    { 0x060B, \"Solid Year Co., LTD.\"  },\r\n    { 0x060C, \"EEH Datalink Gmbh\"  },\r\n    { 0x060D, \"Auctor Corporation\"  },\r\n    { 0x060E, \"Transmonde Technologies, Inc.\"  },\r\n    { 0x060F, \"Joinsoon Electronics Mfg. Co., Ltd.\"  },\r\n    { 0x0610, \"Costar Electronics Inc.\"  },\r\n    { 0x0611, \"JVCKENWOOD Nagaoka Corp.\"  },\r\n    { 0x0612, \"TV Interactive Corp.\"  },\r\n    { 0x0613, \"TransAct Technologies Incorporated\"  },\r\n    { 0x0614, \"Bio-Rad Laboratories\"  },\r\n    { 0x0615, \"Quabbin Wire & Cable Co., INC.\"  },\r\n    { 0x0616, \"Future Techno Designs PVT. LTD.\"  },\r\n    { 0x0617, \"Swiss Federal Institute of Technology\"  },\r\n    { 0x0618, \"Chia Shin Technology Corp.\"  },\r\n    { 0x0619, \"Seiko Instruments Inc.\"  },\r\n    { 0x061A, \"Veridicom2\"  },\r\n    { 0x061B, \"Promptus Communications, Inc.\"  },\r\n    { 0x061C, \"Act Labs, Ltd.\"  },\r\n    { 0x061D, \"Quatech, Inc.\"  },\r\n    { 0x061E, \"Nissei Electric Co.\"  },\r\n    { 0x0620, \"Alaris, Inc.\"  },\r\n    { 0x0621, \"ODU-Steckverbindungssysteme GmbH & Co. KG\"  },\r\n    { 0x0622, \"Iotech, Inc.\"  },\r\n    { 0x0623, \"Littelfuse, Inc.\"  },\r\n    { 0x0624, \"Avocent Corporation\"  },\r\n    { 0x0625, \"TiMedia Technology Co., Ltd.\"  },\r\n    { 0x0626, \"Nippon Systems Development Co., Ltd.\"  },\r\n    { 0x0627, \"Adomax Technology Co., Ltd.\"  },\r\n    { 0x0628, \"Tasking Software Inc.\"  },\r\n    { 0x0629, \"Zida Technologies Limited\"  },\r\n    { 0x062A, \"MosArt Semiconductor Corp.\"  },\r\n    { 0x062B, \"Greatlink Electronics Taiwan Ltd.\"  },\r\n    { 0x062C, \"Institute for Information Industry\"  },\r\n    { 0x062D, \"Taiwan Tai-Hao Enterprises Co. Ltd.\"  },\r\n    { 0x062E, \"JPC-MAIN SUPER Inc.\"  },\r\n    { 0x062F, \"Sin Sheng Terminal & Machine Inc.\"  },\r\n    { 0x0630, \"ORL\"  },\r\n    { 0x0631, \"JUJO Electronics Corporation\"  },\r\n    { 0x0632, \"Marquette Medical Systems, Inc.\"  },\r\n    { 0x0633, \"Cyrix Corporation\"  },\r\n    { 0x0634, \"Micron Technology, Inc.\"  },\r\n    { 0x0635, \"Methode Electronics, Inc.\"  },\r\n    { 0x0636, \"Sierra Imaging, Inc.\"  },\r\n    { 0x0637, \"Gunz Limited\"  },\r\n    { 0x0638, \"Avision, Inc.\"  },\r\n    { 0x0639, \"Chrontel, Inc.\"  },\r\n    { 0x063A, \"Techwin Corporation\"  },\r\n    { 0x063B, \"Taugagreining HF (2)\"  },\r\n    { 0x063C, \"Yamaichi Electronics Co., Ltd. (Sakura)\"  },\r\n    { 0x063D, \"Fong Kai Industrial Co., Ltd.\"  },\r\n    { 0x063E, \"RealMedia Technology, Inc.\"  },\r\n    { 0x063F, \"New Technology Cable Ltd.\"  },\r\n    { 0x0640, \"Hitex Development Tools\"  },\r\n    { 0x0641, \"Woods Industries, Inc.\"  },\r\n    { 0x0642, \"VIA Medical Corporation\"  },\r\n    { 0x0643, \"NOVATUS, Inc.\"  },\r\n    { 0x0644, \"TEAC Corporation\"  },\r\n    { 0x0645, \"Ethentica Inc.\"  },\r\n    { 0x0647, \"Acton Research Corporation\"  },\r\n    { 0x0649, \"Weli Science Co., Ltd\"  },\r\n    { 0x064A, \"Technical Corp.\"  },\r\n    { 0x064B, \"Analog Devices, Inc. Development Tools\"  },\r\n    { 0x064C, \"Ji-Haw Industrial Co., Ltd\"  },\r\n    { 0x064D, \"TriTech Microelectronics Ltd\"  },\r\n    { 0x064E, \"Suyin Corporation\"  },\r\n    { 0x064F, \"WIBU-Systems AG\"  },\r\n    { 0x0650, \"Dynapro Systems\"  },\r\n    { 0x0651, \"Likom Technology Sdn. Bhd.\"  },\r\n    { 0x0652, \"Stargate Solutions, Inc.\"  },\r\n    { 0x0653, \"CNF Inc.\"  },\r\n    { 0x0654, \"Granite Microsystems, Inc.\"  },\r\n    { 0x0655, \"Space Shuttle Hi-Tech Co.,Ltd.\"  },\r\n    { 0x0656, \"Glory Mark Electronic Ltd.\"  },\r\n    { 0x0657, \"Tekcon Electronics Corp.\"  },\r\n    { 0x0658, \"Sigma Designs, Inc.\"  },\r\n    { 0x0659, \"AETHRA\"  },\r\n    { 0x065A, \"Optoelectronics Co., Ltd.\"  },\r\n    { 0x065B, \"Tracewell Systems\"  },\r\n    { 0x065C, \"Brentwood Medical Technology Corp.\"  },\r\n    { 0x065D, \"ATTO Technology, Inc.\"  },\r\n    { 0x065E, \"Silicon Graphics\"  },\r\n    { 0x065F, \"Good Way Technology Co., Ltd. & GWC technology Inc\"  },\r\n    { 0x0660, \"TSAY-E (BVI) International Inc.\"  },\r\n    { 0x0661, \"Hamamatsu Photonics K.K.\"  },\r\n    { 0x0662, \"Kansai Electric Co., Ltd.\"  },\r\n    { 0x0663, \"Topmax Electronic Co., Ltd.\"  },\r\n    { 0x0664, \"ET&T\"  },\r\n    { 0x0665, \"WayTech Development, Inc.\"  },\r\n    { 0x0667, \"Antona Corporation\"  },\r\n    { 0x0668, \"WordWand\"  },\r\n    { 0x0669, \"Oce' Printing Systems GmbH\"  },\r\n    { 0x066A, \"Total Technologies, Ltd.\"  },\r\n    { 0x066B, \"SCM Microsystems Japan, Inc.\"  },\r\n    { 0x066C, \"ASK ASA\"  },\r\n    { 0x066D, \"Entrega Technologies Inc.\"  },\r\n    { 0x066E, \"Acer Semiconductor America, Inc.\"  },\r\n    { 0x066F, \"Freescale Semiconductor, Inc. - Sigmatel\"  },\r\n    { 0x0670, \"Sequel Imaging, Inc.\"  },\r\n    { 0x0671, \"Keisoku Giken Co., Ltd.\"  },\r\n    { 0x0672, \"Labtec Inc.\"  },\r\n    { 0x0673, \"HCL Peripherals Limited\"  },\r\n    { 0x0674, \"Key Mouse Electronic Enterprise Co., Ltd.\"  },\r\n    { 0x0675, \"DrayTek Corp.\"  },\r\n    { 0x0676, \"Teles AG\"  },\r\n    { 0x0677, \"Aiwa Co., Ltd.\"  },\r\n    { 0x0678, \"ACARD Technology Corp.\"  },\r\n    { 0x0679, \"WaterGate Software, Inc.\"  },\r\n    { 0x067A, \"ADS ANKER GmbH\"  },\r\n    { 0x067B, \"Prolific Technology, Inc.\"  },\r\n    { 0x067C, \"Efficient Networks, Inc.\"  },\r\n    { 0x067D, \"Hohner Corp.\"  },\r\n    { 0x067E, \"Intermec Technologies (S) Pte Ltd.\"  },\r\n    { 0x067F, \"Virata Ltd.\"  },\r\n    { 0x0680, \"Realtek Semiconductor Corp., CPP Div.\"  },\r\n    { 0x0681, \"Siemens Information and Communication Products\"  },\r\n    { 0x0683, \"Dataq Instruments, Inc.\"  },\r\n    { 0x0684, \"Cytec Corporation\"  },\r\n    { 0x0685, \"ISDN*tek\"  },\r\n    { 0x0686, \"KONICA MINOLTA TECHNOLOGY CENTER, INC.\"  },\r\n    { 0x0687, \"Sycard Technology\"  },\r\n    { 0x0688, \"Microprocess Ingenierie\"  },\r\n    { 0x0689, \"Elesys Inc.\"  },\r\n    { 0x068A, \"Pertech Inc.\"  },\r\n    { 0x068B, \"Potrans International, Inc.\"  },\r\n    { 0x068C, \"Tokin Corporation, Card Media Systems Department\"  },\r\n    { 0x068D, \"Medical Measurement Systems B.V.\"  },\r\n    { 0x068E, \"CH Products\"  },\r\n    { 0x068F, \"Nihon Kohden Corporation\"  },\r\n    { 0x0690, \"Golden Bridge Electech Inc.\"  },\r\n    { 0x0691, \"Denter System Co., Ltd.\"  },\r\n    { 0x0692, \"Klippel GmbH\"  },\r\n    { 0x0693, \"Hagiwara Solutions Co., Ltd.\"  },\r\n    { 0x0694, \"The LEGO Company\"  },\r\n    { 0x0695, \"ODU-USA, Inc.\"  },\r\n    { 0x0696, \"Carroll Touch\"  },\r\n    { 0x0697, \"Oxford Instruments (Medical Systems Division)\"  },\r\n    { 0x0698, \"Chuntex (CTX)\"  },\r\n    { 0x0699, \"Tektronix, Inc.\"  },\r\n    { 0x069A, \"Askey Computer Corporation\"  },\r\n    { 0x069B, \"Technicolor SA\"  },\r\n    { 0x069C, \"HST High Soft Tech GmbH\"  },\r\n    { 0x069D, \"Hughes Network Systems (HNS)\"  },\r\n    { 0x069E, \"Welcat Inc.\"  },\r\n    { 0x069F, \"Tron b.v.\"  },\r\n    { 0x06A0, \"USB Systems Design\"  },\r\n    { 0x06A1, \"Alexon Co., Ltd.\"  },\r\n    { 0x06A2, \"Topro Technology Inc.\"  },\r\n    { 0x06A3, \"Logitech Europe S.A.\"  },\r\n    { 0x06A4, \"Xiamen Doowell Electron Co., Ltd.\"  },\r\n    { 0x06A5, \"Divio\"  },\r\n    { 0x06A7, \"MicroStore, Inc.\"  },\r\n    { 0x06A8, \"Topaz Systems, Inc.\"  },\r\n    { 0x06A9, \"Westell\"  },\r\n    { 0x06AA, \"Sysgration Ltd.\"  },\r\n    { 0x06AB, \"Johnathon Freeman Technologies\"  },\r\n    { 0x06AC, \"Fujitsu Laboratories of America, Inc.\"  },\r\n    { 0x06AD, \"Greatland Electronics Taiwan Ltd.\"  },\r\n    { 0x06AE, \"Eurofins Digital Testing Belgium\"  },\r\n    { 0x06AF, \"Harting, Inc. of North America\"  },\r\n    { 0x06B0, \"Alva B.V.\"  },\r\n    { 0x06B1, \"Signtech USA, Ltd.\"  },\r\n    { 0x06B2, \"N*ABLE Technologies, Inc.\"  },\r\n    { 0x06B3, \"Galil Motion Control\"  },\r\n    { 0x06B4, \"Citron GmbH\"  },\r\n    { 0x06B5, \"Stanford Research Systems\"  },\r\n    { 0x06B6, \"Leda Media Products\"  },\r\n    { 0x06B8, \"Pixela Corporation\"  },\r\n    { 0x06B9, \"Thomson Telecom\"  },\r\n    { 0x06BA, \"Smooth Cord & Connector Co., Ltd.\"  },\r\n    { 0x06BB, \"EDA Inc.\"  },\r\n    { 0x06BC, \"Oki Data Corporation\"  },\r\n    { 0x06BD, \"AGFA-Gevaert NV\"  },\r\n    { 0x06BE, \"AME Optimedia Technology Co. Ltd.\"  },\r\n    { 0x06BF, \"Leoco Corporation\"  },\r\n    { 0x06C0, \"AllSpirit Co., Ltd.\"  },\r\n    { 0x06C2, \"Microlynx Systems Ltd.\"  },\r\n    { 0x06C3, \"Foss Tecator AB\"  },\r\n    { 0x06C4, \"Bizlink Technology, Inc.\"  },\r\n    { 0x06C5, \"Hagenuk, GmbH\"  },\r\n    { 0x06C6, \"Infowave Software Inc.\"  },\r\n    { 0x06C7, \"Storm Technology Inc.\"  },\r\n    { 0x06C8, \"SIIG, Inc.\"  },\r\n    { 0x06C9, \"Taxan (Europe) Ltd.\"  },\r\n    { 0x06CA, \"Newer Technology, Inc.\"  },\r\n    { 0x06CB, \"Synaptics Inc.\"  },\r\n    { 0x06CC, \"Terayon Communication Systems\"  },\r\n    { 0x06CD, \"Keyspan\"  },\r\n    { 0x06CE, \"Contec Co., Ltd.\"  },\r\n    { 0x06CF, \"Spheron VR- Bonnet und Steuerwald GdbR\"  },\r\n    { 0x06D0, \"LapLink, Inc.\"  },\r\n    { 0x06D1, \"Daewoo Electronics Co Ltd\"  },\r\n    { 0x06D2, \"Pioneer Microsystems\"  },\r\n    { 0x06D3, \"Mitsubishi Electric Corporation\"  },\r\n    { 0x06D4, \"Cisco Systems(2)\"  },\r\n    { 0x06D5, \"Toshiba America Electronic Components, Inc.\"  },\r\n    { 0x06D6, \"Aashima Technology B.V.\"  },\r\n    { 0x06D7, \"Network Computing Devices (NCD)\"  },\r\n    { 0x06D8, \"Technical Marketing Research, Inc.\"  },\r\n    { 0x06D9, \"Atmel-TEMIC Semiconductor GmbH\"  },\r\n    { 0x06DA, \"Phoenixtec Power Co., Ltd.\"  },\r\n    { 0x06DB, \"Paradyne\"  },\r\n    { 0x06DC, \"Foxlink Image Technology Co., Ltd.\"  },\r\n    { 0x06DD, \"Impact Technologies\"  },\r\n    { 0x06DE, \"Heisei Technology Co., Ltd.\"  },\r\n    { 0x06E0, \"Multi-Tech Systems, Inc.\"  },\r\n    { 0x06E1, \"ADS Technologies, Inc.\"  },\r\n    { 0x06E2, \"Trio Motion Technology Limited\"  },\r\n    { 0x06E4, \"Alcatel Microelectronics\"  },\r\n    { 0x06E5, \"Lusher Technologies\"  },\r\n    { 0x06E6, \"Tiger Jet Network, Inc.\"  },\r\n    { 0x06E7, \"Universal Electronics Inc.\"  },\r\n    { 0x06E8, \"Braemar Inc.\"  },\r\n    { 0x06E9, \"Nippon Electric Industry Co., Ltd.\"  },\r\n    { 0x06EA, \"Sirius Technologies Limited\"  },\r\n    { 0x06EB, \"PC Expert Tech. Co., Ltd.\"  },\r\n    { 0x06EC, \"ADInstruments Ltd.\"  },\r\n    { 0x06ED, \"Datastor Technology\"  },\r\n    { 0x06EF, \"I.A.C. Geometrische Ingenieurs B.V.\"  },\r\n    { 0x06F0, \"T.N.C Industrial Co., Ltd.\"  },\r\n    { 0x06F1, \"Opcode Systems Inc.\"  },\r\n    { 0x06F2, \"Emine Technology Company\"  },\r\n    { 0x06F3, \"Flexion Systems Ltd.\"  },\r\n    { 0x06F4, \"First Person Gaming\"  },\r\n    { 0x06F5, \"Midian Production Distribution\"  },\r\n    { 0x06F6, \"Wintrend Technology Co., Ltd.\"  },\r\n    { 0x06F7, \"Wish Technologies\"  },\r\n    { 0x06F8, \"Guillemot Corporation\"  },\r\n    { 0x06F9, \"Asyst Electronic\"  },\r\n    { 0x06FA, \"HSD S.r.L\"  },\r\n    { 0x06FB, \"Hitachi Device Engineering Ltd.\"  },\r\n    { 0x06FC, \"Motorola Semiconductor Products Sector/US\"  },\r\n    { 0x06FD, \"Boston Acoustics\"  },\r\n    { 0x06FE, \"Gallant Computer, Inc.\"  },\r\n    { 0x06FF, \"Mediacom Technologies Pte Ltd.\"  },\r\n    { 0x0701, \"Supercomal Wire & Cable SDN. BHD.\"  },\r\n    { 0x0702, \"PixStream Incorporated\"  },\r\n    { 0x0703, \"Bvtech Industry Inc.\"  },\r\n    { 0x0704, \"Vorum Research Corporation\"  },\r\n    { 0x0705, \"NKK Corporation\"  },\r\n    { 0x0706, \"Ariel Corporation\"  },\r\n    { 0x0707, \"SMC Networks, Inc.\"  },\r\n    { 0x0708, \"Putercom Co., Ltd.\"  },\r\n    { 0x0709, \"Parthus Technologies\"  },\r\n    { 0x070A, \"Oki Electric Industry Co., Ltd.\"  },\r\n    { 0x070B, \"Hasco Int., Inc.\"  },\r\n    { 0x070C, \"Titan Electronics Inc.\"  },\r\n    { 0x070D, \"Comoss Electronic Co., Ltd.\"  },\r\n    { 0x070E, \"Excel Cell Electronic Co., Ltd.\"  },\r\n    { 0x070F, \"Oce' -Technologies B.V.\"  },\r\n    { 0x0710, \"Connect Tech Inc.\"  },\r\n    { 0x0711, \"Magic Control Technology Corp.\"  },\r\n    { 0x0712, \"Verity Instruments, Inc.\"  },\r\n    { 0x0713, \"Interval Research Corp.\"  },\r\n    { 0x0714, \"New Motion International Co., Ltd\"  },\r\n    { 0x0715, \"Liang Tei Co., Ltd.\"  },\r\n    { 0x0716, \"Oxus Research S.A.\"  },\r\n    { 0x0717, \"ZNK Corporation\"  },\r\n    { 0x0718, \"Imation Corp.\"  },\r\n    { 0x0719, \"Tremon Enterprises Co., Ltd.\"  },\r\n    { 0x071A, \"FLIR Explosives\"  },\r\n    { 0x071B, \"Domain Technologies, Inc.\"  },\r\n    { 0x071C, \"Xionics Document Technologies, Inc.\"  },\r\n    { 0x071D, \"Dialogic Corporation\"  },\r\n    { 0x071E, \"Ariston Technologies\"  },\r\n    { 0x071F, \"ARS Technologies Ltd.\"  },\r\n    { 0x0720, \"Keyence Corporation\"  },\r\n    { 0x0721, \"HMedia Technology Inc.\"  },\r\n    { 0x0722, \"Consero\"  },\r\n    { 0x0723, \"Centillium Communications Corporation\"  },\r\n    { 0x0724, \"Lawson Labs, Inc.\"  },\r\n    { 0x0725, \"Applied Precision Inc.\"  },\r\n    { 0x0726, \"Vanguard International Semiconductor-America\"  },\r\n    { 0x0727, \"C&H Technologies, Inc.\"  },\r\n    { 0x0728, \"Avermedia\"  },\r\n    { 0x0729, \"CY&S Industrial Co., Ltd.\"  },\r\n    { 0x072A, \"Luminex Corporation\"  },\r\n    { 0x072B, \"Dnova Corporation\"  },\r\n    { 0x072C, \"OTSO\"  },\r\n    { 0x072D, \"Able Communications, Inc.\"  },\r\n    { 0x072E, \"Sunix Co., Ltd.\"  },\r\n    { 0x072F, \"Advanced Card Systems Ltd.\"  },\r\n    { 0x0730, \"Indus Instruments\"  },\r\n    { 0x0731, \"Susteen, Inc.\"  },\r\n    { 0x0732, \"Goldfull Electronics & Telecommunications Corp.\"  },\r\n    { 0x0733, \"ViewQuest Technologies, Inc.\"  },\r\n    { 0x0734, \"LASAT Communications A/S\"  },\r\n    { 0x0735, \"Asuscom Network, Inc.\"  },\r\n    { 0x0736, \"Lorom Industrial Co., Ltd.\"  },\r\n    { 0x0737, \"Snap-on Diagnostics\"  },\r\n    { 0x0738, \"Mad Catz, Inc.\"  },\r\n    { 0x0739, \"Cue Network Corporation\"  },\r\n    { 0x073A, \"Chaplet Systems, Inc.\"  },\r\n    { 0x073B, \"Suncom Technologies\"  },\r\n    { 0x073C, \"Industrial Electronic Engineers, Inc.\"  },\r\n    { 0x073D, \"Eutronsec Spa\"  },\r\n    { 0x073E, \"Sigma Itec, Inc.\"  },\r\n    { 0x073F, \"Data Electronics (Aust) Pty, Ltd.\"  },\r\n    { 0x0740, \"Full Enterprise Corp.\"  },\r\n    { 0x0741, \"Momentum US Inc.\"  },\r\n    { 0x0742, \"Stollmann EtV GmbH\"  },\r\n    { 0x0743, \"Bonig und Kallenback oHG\"  },\r\n    { 0x0744, \"GMK Electronic Design GmbH\"  },\r\n    { 0x0745, \"Syntech Information Co., Ltd.\"  },\r\n    { 0x0746, \"ONKYO Corporation\"  },\r\n    { 0x0747, \"Labway Corporation\"  },\r\n    { 0x0748, \"Strong Man Enterprise Co., Ltd.\"  },\r\n    { 0x0749, \"EVer Electronics Corp.\"  },\r\n    { 0x074A, \"Ming Fortune Industry Co., Ltd.\"  },\r\n    { 0x074B, \"Polestar Tech. Corp.\"  },\r\n    { 0x074C, \"C-C-C Group PLC\"  },\r\n    { 0x074D, \"Micronas GmbH\"  },\r\n    { 0x074E, \"Digital Stream Corporation\"  },\r\n    { 0x074F, \"Microflip, Inc\"  },\r\n    { 0x0750, \"Innovative Integration\"  },\r\n    { 0x0751, \"Info Network Systems\"  },\r\n    { 0x0752, \"Non-Standard, TSG\"  },\r\n    { 0x0753, \"Mocom Softeare GmbH & Co. KG\"  },\r\n    { 0x0754, \"SyQuest Technology\"  },\r\n    { 0x0755, \"Aureal Semiconductor\"  },\r\n    { 0x0756, \"RSI Systems\"  },\r\n    { 0x0757, \"Network Technologies, Inc.\"  },\r\n    { 0x0758, \"Carl Zeiss Jena GmbH\"  },\r\n    { 0x0759, \"Cellvision Systems, Inc.\"  },\r\n    { 0x075A, \"SEL Inc.\"  },\r\n    { 0x075B, \"Sophisticated Circuits, Inc.\"  },\r\n    { 0x075C, \"Ulan Co., Ltd.\"  },\r\n    { 0x075D, \"Microdowell SRL\"  },\r\n    { 0x075E, \"ABIT Corporation\"  },\r\n    { 0x075F, \"CITEL Technologies, Ltd.\"  },\r\n    { 0x0760, \"JL Cooper Electronics\"  },\r\n    { 0x0761, \"MasTech, Inc.\"  },\r\n    { 0x0762, \"Coretex Corporation\"  },\r\n    { 0x0763, \"M-Audio\"  },\r\n    { 0x0764, \"Cyber Power Systems, Inc.\"  },\r\n    { 0x0765, \"X-Rite Incorporated\"  },\r\n    { 0x0766, \"Jess-Link Products Co., Ltd. (JPC)\"  },\r\n    { 0x0767, \"Tokheim Corporation\"  },\r\n    { 0x0768, \"Camtel Technology Corp.\"  },\r\n    { 0x0769, \"SURECOM Technology Corp.\"  },\r\n    { 0x076A, \"Conceptual Systems\"  },\r\n    { 0x076B, \"HID Global GmbH\"  },\r\n    { 0x076C, \"Partner Tech\"  },\r\n    { 0x076D, \"Denso Corporation\"  },\r\n    { 0x076E, \"Kuan Tech Enterprise Co., Ltd.\"  },\r\n    { 0x076F, \"Jhen Vei Electronic Co., Ltd.\"  },\r\n    { 0x0770, \"Welch Allyn, Inc - Medical Division\"  },\r\n    { 0x0771, \"MicroCraft\"  },\r\n    { 0x0772, \"TFL LAN, Inc\"  },\r\n    { 0x0773, \"Spital Sangyo Co., Ltd.\"  },\r\n    { 0x0774, \"AmTRAN Technology Co., Ltd.\"  },\r\n    { 0x0775, \"Longshine Electronics Corp.\"  },\r\n    { 0x0776, \"Inalways Corporation\"  },\r\n    { 0x0777, \"Comda Advanced Technology Corporation\"  },\r\n    { 0x0778, \"Volex, Inc.\"  },\r\n    { 0x0779, \"Fairchild Semiconductor\"  },\r\n    { 0x077A, \"NIDEC SANKYO CORPORATION\"  },\r\n    { 0x077B, \"Linksys\"  },\r\n    { 0x077C, \"Forward Electronics Co., Ltd.\"  },\r\n    { 0x077D, \"Griffin Technology LLC\"  },\r\n    { 0x077E, \"Softing GmbH\"  },\r\n    { 0x077F, \"Well Excellent & Most Corp.\"  },\r\n    { 0x0780, \"ORGA Kartensysteme GmbH\"  },\r\n    { 0x0781, \"Western Digital, Sandisk\"  },\r\n    { 0x0782, \"Trackerball\"  },\r\n    { 0x0783, \"C3PO, S.L.\"  },\r\n    { 0x0784, \"Pretec Corporation\"  },\r\n    { 0x0785, \"Willnet Inc.\"  },\r\n    { 0x0786, \"Jeil Data Systems Co., Ltd.\"  },\r\n    { 0x0787, \"Abera System Corp\"  },\r\n    { 0x0788, \"3Cam Technology, Inc\"  },\r\n    { 0x0789, \"Logitec Corporation\"  },\r\n    { 0x078A, \"Tandy Electronics (China) Ltd.\"  },\r\n    { 0x078B, \"Happ Controls\"  },\r\n    { 0x078C, \"CalComp\"  },\r\n    { 0x078D, \"Presto Technologies Inc.\"  },\r\n    { 0x078E, \"San Shih Electrical Enterprise Co. Ltd.\"  },\r\n    { 0x078F, \"Troy XCD, Inc.\"  },\r\n    { 0x0790, \"Pro-Image Manufacturing Co., Ltd\"  },\r\n    { 0x0791, \"Copartner Technology Corporation\"  },\r\n    { 0x0792, \"Axis Communications AB\"  },\r\n    { 0x0793, \"Wha Yu Industrial Co., Ltd.\"  },\r\n    { 0x0794, \"ABL Electronics Corporation\"  },\r\n    { 0x0795, \"RealChip Inc.\"  },\r\n    { 0x0796, \"Certicom Corp.\"  },\r\n    { 0x0797, \"Grandtech Semiconductor Corporation\"  },\r\n    { 0x0798, \"F.J. Tieman BV\"  },\r\n    { 0x0799, \"Boulder Creek Engineering\"  },\r\n    { 0x079A, \"Aptec Instruments\"  },\r\n    { 0x079B, \"Sagem SA\"  },\r\n    { 0x079C, \"Sun Communications Inc.\"  },\r\n    { 0x079D, \"Alfadata Computer Corp.\"  },\r\n    { 0x079E, \"Tokin Corporation\"  },\r\n    { 0x079F, \"VMETRO asa\"  },\r\n    { 0x07A0, \"Leiderdorp Instruments\"  },\r\n    { 0x07A1, \"Digicom Spa\"  },\r\n    { 0x07A2, \"National Technical Systems\"  },\r\n    { 0x07A3, \"ONNTO Corp.\"  },\r\n    { 0x07A4, \"Be Incorporated\"  },\r\n    { 0x07A5, \"Tietech Co., Ltd.\"  },\r\n    { 0x07A6, \"Infineon-ADMtek Co., Ltd.\"  },\r\n    { 0x07A7, \"Mediatronix BV\"  },\r\n    { 0x07A8, \"Home Office PSDB\"  },\r\n    { 0x07A9, \"Sandmartin Company Ltd.\"  },\r\n    { 0x07AA, \"Corega Inc.\"  },\r\n    { 0x07AB, \"Freecom Technologies\"  },\r\n    { 0x07AC, \"Fortress U&T Ltd.\"  },\r\n    { 0x07AD, \"ECO Chemie\"  },\r\n    { 0x07AE, \"C&C Technic Taiwan Co., Ltd.\"  },\r\n    { 0x07AF, \"Microtech International, Inc.\"  },\r\n    { 0x07B0, \"Billion Electric Co., Ltd\"  },\r\n    { 0x07B1, \"IMP, Inc.\"  },\r\n    { 0x07B2, \"Motorola BCS\"  },\r\n    { 0x07B3, \"Plustek, Inc.\"  },\r\n    { 0x07B4, \"OLYMPUS CORPORATION\"  },\r\n    { 0x07B5, \"Mega World International Ltd.\"  },\r\n    { 0x07B6, \"Marubun Corp.\"  },\r\n    { 0x07B7, \"TIME Interconnect Ltd.\"  },\r\n    { 0x07B8, \"AboCom Systems, Inc.\"  },\r\n    { 0x07B9, \"Reynolds Medical\"  },\r\n    { 0x07BA, \"Accurate Technologies, Inc.\"  },\r\n    { 0x07BB, \"Intelogis Inc\"  },\r\n    { 0x07BC, \"Canon Computer Systems, Inc.\"  },\r\n    { 0x07BD, \"Webgear Inc.\"  },\r\n    { 0x07BE, \"Veridicom\"  },\r\n    { 0x07BF, \"TestQuest, Inc.\"  },\r\n    { 0x07C0, \"Code Mercenaries\"  },\r\n    { 0x07C1, \"Keisokugiken Corporation\"  },\r\n    { 0x07C2, \"Varatouch Technology Inc.\"  },\r\n    { 0x07C3, \"J-Works, Inc.\"  },\r\n    { 0x07C4, \"Datafab Systems Inc.\"  },\r\n    { 0x07C5, \"APG Cash Drawer\"  },\r\n    { 0x07C6, \"ShareWave, Inc.\"  },\r\n    { 0x07C7, \"Powertech Industrial Co., Ltd.\"  },\r\n    { 0x07C8, \"B.U.G., Inc.\"  },\r\n    { 0x07C9, \"Allied Telesis Inc\"  },\r\n    { 0x07CA, \"AVerMedia Technologies, Inc.\"  },\r\n    { 0x07CB, \"Kingmax Technology Inc.\"  },\r\n    { 0x07CC, \"LIWANLI Innovation Co., Ltd\"  },\r\n    { 0x07CD, \"Hteck Corp.\"  },\r\n    { 0x07CE, \"Nidec-Shimpo Corp.\"  },\r\n    { 0x07CF, \"Casio Computer Co., Ltd.\"  },\r\n    { 0x07D0, \"Dazzle Multimedia\"  },\r\n    { 0x07D2, \"Aptio Products Inc.\"  },\r\n    { 0x07D3, \"Cyberdata Corp.\"  },\r\n    { 0x07D4, \"Aloka Co., Ltd.\"  },\r\n    { 0x07D5, \"Radiant Systems, Inc.\"  },\r\n    { 0x07D6, \"MENICX International Co., Ltd.\"  },\r\n    { 0x07D7, \"GCC Technologies, Inc.\"  },\r\n    { 0x07D8, \"Network Suginami Kokoto\"  },\r\n    { 0x07D9, \"Compuapps\"  },\r\n    { 0x07DA, \"Arasan Chip Systems Inc.\"  },\r\n    { 0x07DB, \"Mental Models, Inc.\"  },\r\n    { 0x07DC, \"OCTAL-Engenharia de Sistemas S.A.\"  },\r\n    { 0x07DD, \"Hampshire Company, Inc.\"  },\r\n    { 0x07DE, \"Best Data Products\"  },\r\n    { 0x07DF, \"David Electronics Company, Ltd.\"  },\r\n    { 0x07E0, \"NCP Engineering\"  },\r\n    { 0x07E1, \"Acer Netxus Incorporated\"  },\r\n    { 0x07E2, \"Elmeg GmbH & Co., Ltd.\"  },\r\n    { 0x07E3, \"Planex Communications, Inc.\"  },\r\n    { 0x07E4, \"Movado Enterprise Co., Ltd.\"  },\r\n    { 0x07E5, \"QPS, Inc.\"  },\r\n    { 0x07E6, \"Allied Cable Corporation\"  },\r\n    { 0x07E7, \"Mirvo Toys, Inc.\"  },\r\n    { 0x07E8, \"Labsystems\"  },\r\n    { 0x07E9, \"Sanyo Technosound Co., Ltd.\"  },\r\n    { 0x07EA, \"Iwatsu Electric Co., Ltd.\"  },\r\n    { 0x07EB, \"Double-H Technology Co., Ltd.\"  },\r\n    { 0x07EC, \"Taiyo Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x07ED, \"Precision MicroDynamics, Inc.\"  },\r\n    { 0x07EE, \"Logware GmbH\"  },\r\n    { 0x07EF, \"Suite Technology Systems\"  },\r\n    { 0x07F0, \"PS Communications Ltd.\"  },\r\n    { 0x07F1, \"Picostar, Inc.\"  },\r\n    { 0x07F2, \"BPT Enterprises\"  },\r\n    { 0x07F3, \"L3 Systems\"  },\r\n    { 0x07F4, \"Joritel International B.V.\"  },\r\n    { 0x07F5, \"Amiable Technologies, Inc.\"  },\r\n    { 0x07F6, \"Circuit Assembly Corp.\"  },\r\n    { 0x07F7, \"Century Corporation\"  },\r\n    { 0x07F8, \"Eskape Labs\"  },\r\n    { 0x07F9, \"Dotop Technology, Inc.\"  },\r\n    { 0x07FA, \"FHLP\"  },\r\n    { 0x07FB, \"Digi-Tek, Inc.\"  },\r\n    { 0x07FC, \"Protec Microsystems\"  },\r\n    { 0x07FD, \"Mark of the Unicorn, Inc.\"  },\r\n    { 0x07FE, \"Net Eyes, Inc.\"  },\r\n    { 0x07FF, \"Sectra AB\"  },\r\n    { 0x0800, \"Kortex International\"  },\r\n    { 0x0801, \"Mag-Tek\"  },\r\n    { 0x0802, \"Mako Technologies, LLC\"  },\r\n    { 0x0803, \"Zoom Telephonics, Inc.\"  },\r\n    { 0x0804, \"Neuron Corporation\"  },\r\n    { 0x0805, \"Iruma Soft Co., Ltd.\"  },\r\n    { 0x0806, \"Clinton Electronics Corp.\"  },\r\n    { 0x0807, \"SIIX Corporation\"  },\r\n    { 0x0808, \"InfiMed, Inc.\"  },\r\n    { 0x0809, \"Genicom LP\"  },\r\n    { 0x080A, \"Evermuch Technology Co., Ltd.\"  },\r\n    { 0x080B, \"Cross Match Technologies, Inc.\"  },\r\n    { 0x080C, \"Datalogic S.p.A.\"  },\r\n    { 0x080D, \"TECO Image Systems Co., Ltd.\"  },\r\n    { 0x080E, \"Sound Technology, Inc.\"  },\r\n    { 0x080F, \"Deschutes Corporation\"  },\r\n    { 0x0810, \"Personal Communication Systems, Inc.\"  },\r\n    { 0x0811, \"Fimet\"  },\r\n    { 0x0812, \"E-Tech, Inc.\"  },\r\n    { 0x0813, \"Mattel, Inc.\"  },\r\n    { 0x0814, \"EBI Systems, Inc.\"  },\r\n    { 0x0815, \"Scintrex\"  },\r\n    { 0x0816, \"ABB Automation Products AB\"  },\r\n    { 0x0817, \"Interzeag Medical Technology\"  },\r\n    { 0x0818, \"NTT Electronics Corporation\"  },\r\n    { 0x0819, \"Syncrosoft GMBH\"  },\r\n    { 0x081A, \"MG Logic Pte Ltd.\"  },\r\n    { 0x081B, \"Indigita Corporation\"  },\r\n    { 0x081C, \"MIPSYS\"  },\r\n    { 0x081D, \"VlerZwo Software GbR\"  },\r\n    { 0x081E, \"AlphaSmart, Inc.\"  },\r\n    { 0x081F, \"Totsu Engineering, Inc.\"  },\r\n    { 0x0820, \"Verax Engineering\"  },\r\n    { 0x0821, \"A.T. Cross\"  },\r\n    { 0x0822, \"REUDO Corporation\"  },\r\n    { 0x0823, \"Tactex Controls, Inc.\"  },\r\n    { 0x0824, \"M.S.E. GmbH\"  },\r\n    { 0x0825, \"GC Protronics\"  },\r\n    { 0x0826, \"Data Transit\"  },\r\n    { 0x0827, \"BroadLogic, Inc.\"  },\r\n    { 0x0828, \"Sato Corporation\"  },\r\n    { 0x0829, \"DirecTV Broadband\"  },\r\n    { 0x082A, \"Object Co., Ltd.\"  },\r\n    { 0x082B, \"TrophyTrex\"  },\r\n    { 0x082C, \"Japan Digital Laboratory Co., Ltd.\"  },\r\n    { 0x082D, \"Handspring, Inc.\"  },\r\n    { 0x082E, \"Suni Imaging Microsystems, Inc.\"  },\r\n    { 0x082F, \"ACACIA\"  },\r\n    { 0x0830, \"Palm Inc.\"  },\r\n    { 0x0831, \"Chong Tsi Su Enterprise Co., Ltd\"  },\r\n    { 0x0832, \"Kouwell Electronics Corp.\"  },\r\n    { 0x0833, \"Sourcenext Corporation\"  },\r\n    { 0x0834, \"Ciponic Technology Co., Ltd.\"  },\r\n    { 0x0835, \"Action Star Technology Co., Ltd.\"  },\r\n    { 0x0836, \"Evertz Microsystems Ltd.\"  },\r\n    { 0x0837, \"Renishaw PLC\"  },\r\n    { 0x0838, \"Precision MicroControl Corporation\"  },\r\n    { 0x0839, \"Samsung Techwin\"  },\r\n    { 0x083A, \"Accton Technology Corporation\"  },\r\n    { 0x083B, \"Dr. Neuhaus Telekommunikation GmbH\"  },\r\n    { 0x083C, \"Jaeger Messtechnik GmbH\"  },\r\n    { 0x083D, \"Nakayo Telecommunication, Inc.\"  },\r\n    { 0x083E, \"2-Tel B.V.\"  },\r\n    { 0x083F, \"Boca Global, Inc.\"  },\r\n    { 0x0840, \"Argosy Research Inc.\"  },\r\n    { 0x0841, \"Rioport.com Inc.\"  },\r\n    { 0x0842, \"ESA MESSTECHNIK GMBH\"  },\r\n    { 0x0843, \"Mcom As\"  },\r\n    { 0x0844, \"Welland Industrial Co., Ltd.\"  },\r\n    { 0x0845, \"EES Technik fur Musik\"  },\r\n    { 0x0846, \"NETGEAR, Inc.\"  },\r\n    { 0x0847, \"Interack Communications Inc.\"  },\r\n    { 0x0848, \"Accton Technology Co., Ltd.\"  },\r\n    { 0x0849, \"SC&T International, Inc.\"  },\r\n    { 0x084A, \"Wipro Limited\"  },\r\n    { 0x084B, \"Castlewood Systems\"  },\r\n    { 0x084C, \"The Japan Steel Works, Ltd.\"  },\r\n    { 0x084D, \"Minton Optic Industry Co., Ltd.\"  },\r\n    { 0x084E, \"KidBoard, Inc. dba KBGear Interactive\"  },\r\n    { 0x084F, \"EMPEG Ltd\"  },\r\n    { 0x0850, \"FastPoint Technologies, Inc.\"  },\r\n    { 0x0851, \"Macronix International Co., Ltd.\"  },\r\n    { 0x0852, \"CSEM\"  },\r\n    { 0x0853, \"Topre Corporation\"  },\r\n    { 0x0854, \"Active Wire, Inc.\"  },\r\n    { 0x0855, \"JMBS Developpements\"  },\r\n    { 0x0856, \"B&B Electronics\"  },\r\n    { 0x0857, \"Gerber Scientific Products, Inc.\"  },\r\n    { 0x0858, \"Hitachi Maxell Ltd.\"  },\r\n    { 0x0859, \"Minolta Systems Laboratory, Inc.\"  },\r\n    { 0x085A, \"Xircom\"  },\r\n    { 0x085B, \"Kurt Manufacturing\"  },\r\n    { 0x085C, \"Color Vision Inc.\"  },\r\n    { 0x085D, \"Ambient Technologies, Inc.\"  },\r\n    { 0x085E, \"NaftEL Technologies LTD.\"  },\r\n    { 0x085F, \"Canberra Industries\"  },\r\n    { 0x0860, \"Momentum Data System\"  },\r\n    { 0x0861, \"Cambridge Research Systems Ltd.\"  },\r\n    { 0x0862, \"Teletrol Systems, Inc.\"  },\r\n    { 0x0863, \"Filanet Corporation\"  },\r\n    { 0x0864, \"Roper International Ltd.\"  },\r\n    { 0x0865, \"MICROLAB\"  },\r\n    { 0x0866, \"PEI Electronics, Inc.\"  },\r\n    { 0x0867, \"Data Translation, Inc.\"  },\r\n    { 0x0868, \"Electrical Geodesics, Inc.\"  },\r\n    { 0x0869, \"Visual Interaction\"  },\r\n    { 0x086A, \"Emagic Soft-und Hardware Gmbh\"  },\r\n    { 0x086B, \"ROHM Co. Ltd.\"  },\r\n    { 0x086C, \"DeTeWe\"  },\r\n    { 0x086D, \"ICE Technology\"  },\r\n    { 0x086E, \"System TALKS Inc.\"  },\r\n    { 0x086F, \"MEC IMEX INC-HPT\"  },\r\n    { 0x0870, \"Metricom, Inc.\"  },\r\n    { 0x0871, \"Merge Technologies Inc.\"  },\r\n    { 0x0872, \"Broadxent, Inc.\"  },\r\n    { 0x0873, \"Xpeed Inc.\"  },\r\n    { 0x0874, \"A-Tec Subsystem, Inc.\"  },\r\n    { 0x0875, \"Mecel AB\"  },\r\n    { 0x0876, \"3M Home Health Systems\"  },\r\n    { 0x0877, \"Lew Engineering\"  },\r\n    { 0x0878, \"SYSTEC Computer Gmbh\"  },\r\n    { 0x0879, \"Comtrol Corporation\"  },\r\n    { 0x087A, \"Getemed GmbH\"  },\r\n    { 0x087B, \"Cornerstone Peripherals Technology\"  },\r\n    { 0x087C, \"ADESSO/Kbtek America Inc.\"  },\r\n    { 0x087D, \"JATON Corporation\"  },\r\n    { 0x087E, \"Fujitsu Computer Products of America\"  },\r\n    { 0x087F, \"QualCore Logic Inc\"  },\r\n    { 0x0880, \"APT Technologies Inc.\"  },\r\n    { 0x0881, \"Sistemas Y Redes Telematicas, Sire S.L.\"  },\r\n    { 0x0882, \"Rightec Research\"  },\r\n    { 0x0883, \"Recording Industry Association of America (RIAA)\"  },\r\n    { 0x0884, \"USB Systems\"  },\r\n    { 0x0885, \"Boca Research, Inc.\"  },\r\n    { 0x0887, \"Hannstar Electronics Corp.\"  },\r\n    { 0x0889, \"Current Works, Inc.\"  },\r\n    { 0x088A, \"TechTools\"  },\r\n    { 0x088B, \"MassWorks\"  },\r\n    { 0x088C, \"Swecoin AB\"  },\r\n    { 0x088D, \"Engineering Spirit\"  },\r\n    { 0x088E, \"Pace Anti-Piracy, Inc.\"  },\r\n    { 0x088F, \"Husky Computers Limited\"  },\r\n    { 0x0890, \"Consultronics Ltd.\"  },\r\n    { 0x0891, \"Drager Medizintechnik Gmbh.\"  },\r\n    { 0x0892, \"DioGraphy Inc.\"  },\r\n    { 0x0893, \"Bartec\"  },\r\n    { 0x0894, \"TSI Incorporated\"  },\r\n    { 0x0895, \"Kanitech A/S\"  },\r\n    { 0x0896, \"Starseed Enterprises AG\"  },\r\n    { 0x0897, \"Lauterbach GmbH\"  },\r\n    { 0x0898, \"3M Canada\"  },\r\n    { 0x0899, \"Grieshaber & Co. AG\"  },\r\n    { 0x089A, \"Koepruelue Engineering\"  },\r\n    { 0x089B, \"Digital-3, LLC.\"  },\r\n    { 0x089C, \"United Technologies Research Cntr.\"  },\r\n    { 0x089D, \"Icron Technologies Corporation\"  },\r\n    { 0x089E, \"NST Co., Ltd.\"  },\r\n    { 0x089F, \"Primex Aerospace Co.\"  },\r\n    { 0x08A0, \"Logic Meca Co., Ltd.\"  },\r\n    { 0x08A1, \"Studio Zee\"  },\r\n    { 0x08A2, \"Millennia Systems, Inc.\"  },\r\n    { 0x08A3, \"Hyowon Software\"  },\r\n    { 0x08A4, \"YTG Smartech Inc.\"  },\r\n    { 0x08A5, \"e9 Inc.\"  },\r\n    { 0x08A6, \"Toshiba Tec Corporation\"  },\r\n    { 0x08A7, \"General Cybernetics Inc.\"  },\r\n    { 0x08A8, \"Andrea Electronics\"  },\r\n    { 0x08A9, \"CWAV\"  },\r\n    { 0x08AA, \"Kernel Productions, Inc.\"  },\r\n    { 0x08AB, \"Innolab Pte. Ltd.\"  },\r\n    { 0x08AC, \"Macraigor Systems LLC\"  },\r\n    { 0x08AD, \"Toyota Technical Development Corporation (TTDC)\"  },\r\n    { 0x08AE, \"Macally (Mace Group, Inc.)\"  },\r\n    { 0x08AF, \"Hamilton Co.\"  },\r\n    { 0x08B0, \"Metrohm Ltd.\"  },\r\n    { 0x08B1, \"High Technology Laboratory s.r.l\"  },\r\n    { 0x08B2, \"BIOTRONIK GmbH & Co.\"  },\r\n    { 0x08B3, \"Voice It Worldwide, Inc.\"  },\r\n    { 0x08B4, \"Sorenson Communications\"  },\r\n    { 0x08B5, \"Correlator.com\"  },\r\n    { 0x08B6, \"Imagek, Inc.\"  },\r\n    { 0x08B7, \"NATSU Corporation Limited\"  },\r\n    { 0x08B8, \"J. Gordon Electronic Design, Inc.\"  },\r\n    { 0x08B9, \"General Wireless Operations Inc\"  },\r\n    { 0x08BA, \"Fujitsu General Limited\"  },\r\n    { 0x08BB, \"Texas Instruments Japan\"  },\r\n    { 0x08BC, \"Dr. G. Schuhfried GmbH\"  },\r\n    { 0x08BD, \"Citizen Watch Co., Ltd.\"  },\r\n    { 0x08BE, \"Meilenstein GmbH\"  },\r\n    { 0x08BF, \"Nova Engineering, Inc.\"  },\r\n    { 0x08C0, \"Braintronics B.V.\"  },\r\n    { 0x08C1, \"Timestep Electronics Ltd.\"  },\r\n    { 0x08C2, \"ArgoCraft Co., Ltd.\"  },\r\n    { 0x08C3, \"Precise Biometrics\"  },\r\n    { 0x08C4, \"Proxim CBU\"  },\r\n    { 0x08C5, \"Moreton Bay\"  },\r\n    { 0x08C6, \"Scalex Corporation\"  },\r\n    { 0x08C7, \"TAI TWUN ENTERPRISE CO., LTD.\"  },\r\n    { 0x08C8, \"2Wire, Inc\"  },\r\n    { 0x08C9, \"Nippon Telegraph and Telephone Corp.\"  },\r\n    { 0x08CA, \"AIPTEK International Inc.\"  },\r\n    { 0x08CB, \"Cyber Innovate, Inc.\"  },\r\n    { 0x08CC, \"ifak system GmbH\"  },\r\n    { 0x08CD, \"Jue Hsun Ind. Corp.\"  },\r\n    { 0x08CE, \"Long Well Electronics Corp.\"  },\r\n    { 0x08CF, \"Productivity Enhancement Products\"  },\r\n    { 0x08D0, \"Tasco Electronics Co., Inc.\"  },\r\n    { 0x08D1, \"Smartbridges Pte. Ltd.\"  },\r\n    { 0x08D2, \"Dialog4 System Engineering Gmbh.\"  },\r\n    { 0x08D3, \"Virtual Ink\"  },\r\n    { 0x08D4, \"Siemens PC Systeme GmbH\"  },\r\n    { 0x08D5, \"Cambridge Heart, Inc.\"  },\r\n    { 0x08D6, \"Itautec Philco S.A.\"  },\r\n    { 0x08D7, \"Opticon, Inc.\"  },\r\n    { 0x08D8, \"Huntsville Microsystems, Inc.\"  },\r\n    { 0x08D9, \"Increment P Corporation\"  },\r\n    { 0x08DA, \"A W Electronics, Inc.\"  },\r\n    { 0x08DB, \"IXXAT Automation GmbH\"  },\r\n    { 0x08DC, \"Animo Limited\"  },\r\n    { 0x08DD, \"Billionton Systems, Inc.\"  },\r\n    { 0x08DE, \"Touchstone Software\"  },\r\n    { 0x08DF, \"Spyrus Inc.\"  },\r\n    { 0x08E0, \"Geodesic Designs, Inc.\"  },\r\n    { 0x08E1, \"LSI JAPAN Co., Ltd\"  },\r\n    { 0x08E2, \"SafeNet China Ltd.\"  },\r\n    { 0x08E3, \"OLITEC\"  },\r\n    { 0x08E4, \"Pioneer Corporation\"  },\r\n    { 0x08E5, \"LITRONIC\"  },\r\n    { 0x08E6, \"Gemalto SA\"  },\r\n    { 0x08E7, \"PAN-INTERNATIONAL WIRE & CABLE (M) SDN BHD\"  },\r\n    { 0x08E8, \"Integrated Memory Logic\"  },\r\n    { 0x08E9, \"Extended Systems, Inc.\"  },\r\n    { 0x08EA, \"Ericsson Inc.\"  },\r\n    { 0x08EB, \"Asulab SA\"  },\r\n    { 0x08EC, \"M-Systems Flash Disk Pioneers\"  },\r\n    { 0x08ED, \"Instrumentation Metrics, Inc.\"  },\r\n    { 0x08EE, \"CCSI/HESSO\"  },\r\n    { 0x08EF, \"PixelVision\"  },\r\n    { 0x08F0, \"CardScan Inc.\"  },\r\n    { 0x08F1, \"CTI Electronics Corporation\"  },\r\n    { 0x08F2, \"Constance Technology Co., Ltd.\"  },\r\n    { 0x08F3, \"Wintime Electronics Corp.\"  },\r\n    { 0x08F4, \"Telia ProSoft AB\"  },\r\n    { 0x08F5, \"SYSTEC Co., Ltd.\"  },\r\n    { 0x08F6, \"Logic 3 International Limited\"  },\r\n    { 0x08F7, \"Vernier Software\"  },\r\n    { 0x08F8, \"Keen Top International Enterprise Co., Ltd.\"  },\r\n    { 0x08F9, \"Wipro Technologies\"  },\r\n    { 0x08FA, \"CAERE\"  },\r\n    { 0x08FB, \"Socket Mobile, Inc.\"  },\r\n    { 0x08FC, \"Sicon International\"  },\r\n    { 0x08FD, \"Digianswer A/S\"  },\r\n    { 0x08FE, \"GDSYSTEMS\"  },\r\n    { 0x08FF, \"AuthenTec, Inc.\"  },\r\n    { 0x0901, \"VST Technologies\"  },\r\n    { 0x0902, \"iDream Technologies Pte Ltd\"  },\r\n    { 0x0903, \"Infolibria\"  },\r\n    { 0x0904, \"Frank Audiodata\"  },\r\n    { 0x0905, \"ISDG\"  },\r\n    { 0x0906, \"FARADAY Technology Corp.\"  },\r\n    { 0x0907, \"Addison Technology Europe B.V.\"  },\r\n    { 0x0908, \"Siemens Automation & Drives\"  },\r\n    { 0x0909, \"Audio-Technica Corp.\"  },\r\n    { 0x090A, \"Trumpion Microelectronics Inc\"  },\r\n    { 0x090B, \"Neurosmith\"  },\r\n    { 0x090C, \"Silicon Motion, Inc. - Taiwan\"  },\r\n    { 0x090D, \"MULTIPORT Computer Vertriebs GmbH\"  },\r\n    { 0x090E, \"Shining Technology, Inc.\"  },\r\n    { 0x090F, \"Fujitsu Devices Inc.\"  },\r\n    { 0x0910, \"Alation Systems, Inc.\"  },\r\n    { 0x0911, \"Philips Speech Processing\"  },\r\n    { 0x0912, \"Voquette, Inc.\"  },\r\n    { 0x0913, \"Asante' Technologies, Inc.\"  },\r\n    { 0x0914, \"Bally Gaming, Inc.\"  },\r\n    { 0x0915, \"GlobespanVirata, Inc.\"  },\r\n    { 0x0916, \"DH electronics GmbH\"  },\r\n    { 0x0917, \"SmartDisk Corporation\"  },\r\n    { 0x0918, \"Planet Portal.com\"  },\r\n    { 0x0919, \"Sound Vision Inc.\"  },\r\n    { 0x091A, \"Inter-Cable Systems, Inc.\"  },\r\n    { 0x091B, \"Raleigh Technology Corporation\"  },\r\n    { 0x091C, \"Bormann EDV + Zubehoer GmbH\"  },\r\n    { 0x091D, \"A. K. Barns Ltd.\"  },\r\n    { 0x091E, \"Garmin International\"  },\r\n    { 0x091F, \"U-JIN Mesco Co., Ltd.\"  },\r\n    { 0x0920, \"Echelon Corporation\"  },\r\n    { 0x0921, \"GoHubs, inc.\"  },\r\n    { 0x0922, \"Dymo Corporation\"  },\r\n    { 0x0923, \"IC Media Corporation\"  },\r\n    { 0x0924, \"Xerox Corporation\"  },\r\n    { 0x0925, \"Lakeview Research\"  },\r\n    { 0x0926, \"Sound Devices, LLC\"  },\r\n    { 0x0927, \"Summus, Ltd.\"  },\r\n    { 0x0928, \"Oxford Semiconductor Ltd.\"  },\r\n    { 0x0929, \"American Biometric Company\"  },\r\n    { 0x092A, \"Toshiba Information & Industrial Sys. And Services\"  },\r\n    { 0x092B, \"Sena Technologies, Inc.\"  },\r\n    { 0x092C, \"Shanghai Bell Company Limited\"  },\r\n    { 0x092D, \"OYO Instruments\"  },\r\n    { 0x092E, \"Markpoint AB\"  },\r\n    { 0x092F, \"Northern Embedded Science\"  },\r\n    { 0x0930, \"Toshiba Corporation\"  },\r\n    { 0x0931, \"Harmonic Data Systems Ltd.\"  },\r\n    { 0x0932, \"Crescentec Corporation\"  },\r\n    { 0x0933, \"Quantum Corp.\"  },\r\n    { 0x0934, \"Spirent Communications\"  },\r\n    { 0x0935, \"Accurite Technologies, Inc.\"  },\r\n    { 0x0936, \"DynamicNakedAudio Inc.\"  },\r\n    { 0x0937, \"Scania CV AB\"  },\r\n    { 0x0938, \"Virtual DSP Corporation\"  },\r\n    { 0x0939, \"Lumberg, Inc.\"  },\r\n    { 0x093A, \"Pixart Imaging, Inc.\"  },\r\n    { 0x093B, \"Plextor LLC\"  },\r\n    { 0x093C, \"Intrepid Control Systems, Inc.\"  },\r\n    { 0x093D, \"InnoSync, Inc.\"  },\r\n    { 0x093E, \"J.S.T. Mfg. Co., Ltd.\"  },\r\n    { 0x093F, \"OLYMPIA Telecom Vertriebs GmbH\"  },\r\n    { 0x0940, \"Japan Storage Battery Co., Ltd.\"  },\r\n    { 0x0941, \"Photobit Corporation\"  },\r\n    { 0x0942, \"i2Go.com, LLC\"  },\r\n    { 0x0943, \"HCL Technologies Ltd.\"  },\r\n    { 0x0944, \"KORG, Inc.\"  },\r\n    { 0x0945, \"PASCO Scientific\"  },\r\n    { 0x0946, \"GEMSTAR TECHOLOGY DEVELOPMENT LIMITED\"  },\r\n    { 0x0947, \"Videonics, Inc.\"  },\r\n    { 0x0948, \"Kronauer Music In Digital\"  },\r\n    { 0x0949, \"Hitachi Kokusai Electric Inc.\"  },\r\n    { 0x094A, \"Luckytech Technology Co., Ltd\"  },\r\n    { 0x094B, \"Linkup Systems Corporation\"  },\r\n    { 0x094C, \"Metanetics Corporation\"  },\r\n    { 0x094D, \"Cable Television Laboratories\"  },\r\n    { 0x094E, \"Head Acoustics\"  },\r\n    { 0x094F, \"Yano Electric Co., Ltd.\"  },\r\n    { 0x0950, \"TechniSat Sateliltenfernsehprodukte Gmbh\"  },\r\n    { 0x0951, \"Kingston Technology Company\"  },\r\n    { 0x0952, \"DCOM Enterprise Co., Ltd.\"  },\r\n    { 0x0953, \"PLG\"  },\r\n    { 0x0954, \"RPM Systems Corporation\"  },\r\n    { 0x0955, \"NVIDIA\"  },\r\n    { 0x0956, \"BSquare Corporation\"  },\r\n    { 0x0957, \"Agilent Technologies, Inc.\"  },\r\n    { 0x0958, \"BioLink Technologies International, Inc.\"  },\r\n    { 0x0959, \"Cologne Chip AG\"  },\r\n    { 0x095A, \"Portsmith\"  },\r\n    { 0x095B, \"Medialogic Corporation\"  },\r\n    { 0x095C, \"K-Tec Electronics\"  },\r\n    { 0x095D, \"Polycom, Inc.\"  },\r\n    { 0x095E, \"USB Design Labs\"  },\r\n    { 0x095F, \"TTO Engineering\"  },\r\n    { 0x0960, \"Bcom Electronics, Inc.\"  },\r\n    { 0x0961, \"Portatec Corporation\"  },\r\n    { 0x0962, \"SAMx\"  },\r\n    { 0x0963, \"Instrument Solutions\"  },\r\n    { 0x0964, \"Bitran Corporation\"  },\r\n    { 0x0965, \"PAR Technologies, Inc.\"  },\r\n    { 0x0966, \"HanGo Electronics Co., Ltd.\"  },\r\n    { 0x0967, \"Acer NeWeb Corporation\"  },\r\n    { 0x0969, \"Magellan Corp.\"  },\r\n    { 0x096A, \"Koizumi Computer, Inc.\"  },\r\n    { 0x096B, \"ML Electronics Ltd.\"  },\r\n    { 0x096C, \"GOPEL electronic GmbH\"  },\r\n    { 0x096D, \"PennyLan\"  },\r\n    { 0x096E, \"Feitian Technologies Co., Ltd.\"  },\r\n    { 0x096F, \"Memory Link\"  },\r\n    { 0x0970, \"K.S. Vector Co., Ltd.\"  },\r\n    { 0x0971, \"GretagMacbeth AG\"  },\r\n    { 0x0972, \"Musicbird\"  },\r\n    { 0x0973, \"Axalto\"  },\r\n    { 0x0974, \"Eye Communication Systems, Inc\"  },\r\n    { 0x0975, \"OL'E Communications, Inc.\"  },\r\n    { 0x0976, \"Adirondack Wire & Cable\"  },\r\n    { 0x0977, \"Lightsurf Technologies\"  },\r\n    { 0x0978, \"Beckhoff Gmbh\"  },\r\n    { 0x0979, \"Jeilin Technology Corp., Ltd.\"  },\r\n    { 0x097A, \"Minds At Work LLC\"  },\r\n    { 0x097B, \"Knudsen Engineering Limited\"  },\r\n    { 0x097C, \"Marunix Co., Ltd.\"  },\r\n    { 0x097D, \"Rosun Technologies, Inc.\"  },\r\n    { 0x097E, \"Biopac Systems Inc.\"  },\r\n    { 0x097F, \"Barun Electronics Co. Ltd.\"  },\r\n    { 0x0980, \"Posh Mfg. Ltd.\"  },\r\n    { 0x0981, \"Oak Technology Ltd.\"  },\r\n    { 0x0982, \"Covadis S.A.\"  },\r\n    { 0x0983, \"Nissha Printing Co., Ltd.\"  },\r\n    { 0x0984, \"Apricorn\"  },\r\n    { 0x0985, \"Cab Produkttechnik\"  },\r\n    { 0x0986, \"Panasonic Electric Works Co., Ltd.\"  },\r\n    { 0x0987, \"MicroSpeed Inc\"  },\r\n    { 0x0988, \"Teraoka Seiko Co. Ltd\"  },\r\n    { 0x0989, \"Digitel Co. LTD\"  },\r\n    { 0x098A, \"Neopost\"  },\r\n    { 0x098B, \"Kingtel Telecommunication Corp.\"  },\r\n    { 0x098C, \"Vitana Corporation\"  },\r\n    { 0x098D, \"INDesign\"  },\r\n    { 0x098E, \"Integrated Intellectual Property Inc.\"  },\r\n    { 0x098F, \"TEXIO CORPORATION\"  },\r\n    { 0x0990, \"General Instrument Corp.\"  },\r\n    { 0x0992, \"Bandai Co., Ltd.\"  },\r\n    { 0x0993, \"NuvoMedia, Inc.\"  },\r\n    { 0x0994, \"Dionex Softron GmbH\"  },\r\n    { 0x0995, \"Simple Jet Technology Co., Ltd.\"  },\r\n    { 0x0996, \"Integrated Telecom Express, Inc.\"  },\r\n    { 0x0997, \"Xerox Corporation/Non-Networked Products\"  },\r\n    { 0x0998, \"Atech Totalsolution Co., Ltd.\"  },\r\n    { 0x0999, \"Ocean Optics, Inc.\"  },\r\n    { 0x099A, \"ZIPPY TECHNOLOGY CORP.\"  },\r\n    { 0x099B, \"HIROTA SEISAKUSHO LTD.\"  },\r\n    { 0x099C, \"Florida Probe, Inc.\"  },\r\n    { 0x099D, \"NEC San-ei Instruments, Ltd.\"  },\r\n    { 0x099E, \"Trimble\"  },\r\n    { 0x099F, \"Summa N.V.\"  },\r\n    { 0x09A0, \"Altec Computersysteme GmbH\"  },\r\n    { 0x09A1, \"ELMO COMPANY, LIMITED\"  },\r\n    { 0x09A2, \"Telemann Co., Ltd.\"  },\r\n    { 0x09A3, \"PairGain Technologies\"  },\r\n    { 0x09A4, \"Contech Research, Inc.\"  },\r\n    { 0x09A5, \"VCON Telecommunications\"  },\r\n    { 0x09A6, \"Poinchips\"  },\r\n    { 0x09A7, \"Data Transmission Network Corp.\"  },\r\n    { 0x09A8, \"Lin Shiung Enterprise Co., Ltd.\"  },\r\n    { 0x09A9, \"Smart Card Technologies Co., Ltd.\"  },\r\n    { 0x09AA, \"Intersil Corporation\"  },\r\n    { 0x09AB, \"Japan Cash Machine Co., Ltd.\"  },\r\n    { 0x09AC, \"DIGIGRAM\"  },\r\n    { 0x09AD, \"The MITRE Corporation\"  },\r\n    { 0x09AE, \"Tripp Lite\"  },\r\n    { 0x09AF, \"G.i.N. mbH\"  },\r\n    { 0x09B0, \"Fargo Electronics, Inc.\"  },\r\n    { 0x09B1, \"Ositech Communications Incorporated\"  },\r\n    { 0x09B2, \"Franklin Electronic Publishers\"  },\r\n    { 0x09B3, \"Simplex Solution Inc.\"  },\r\n    { 0x09B4, \"MDS Gateways\"  },\r\n    { 0x09B5, \"Celltrix Technology Co., Ltd.\"  },\r\n    { 0x09B6, \"SmithMyers Communications Limited\"  },\r\n    { 0x09B7, \"FAIRLIGHT ESP\"  },\r\n    { 0x09B8, \"PhoeniX . Incorporated\"  },\r\n    { 0x09B9, \"CentLand inc.\"  },\r\n    { 0x09BA, \"Chumtronix N.V.\"  },\r\n    { 0x09BB, \"Eule Industrie- & Datentechnik GmbH & Co. KG\"  },\r\n    { 0x09BC, \"Audivo GmbH\"  },\r\n    { 0x09BD, \"Haptix Creation Pte Ltd\"  },\r\n    { 0x09BE, \"Prosisa Overseas LLC\"  },\r\n    { 0x09BF, \"Auerswald GmbH & Co. KG\"  },\r\n    { 0x09C0, \"Molecular Devices LLC\"  },\r\n    { 0x09C1, \"ARRIS International\"  },\r\n    { 0x09C2, \"NISCA Corporation\"  },\r\n    { 0x09C3, \"ACTIVCARD, INC.\"  },\r\n    { 0x09C4, \"ACTiSYS Corporation\"  },\r\n    { 0x09C5, \"Memory Corporation\"  },\r\n    { 0x09C6, \"Inovatec S.p.A.\"  },\r\n    { 0x09C7, \"PUBCOMPANY s.r.l.\"  },\r\n    { 0x09C8, \"Carrot Systems Inc.\"  },\r\n    { 0x09C9, \"U.S. Digital Corp.\"  },\r\n    { 0x09CA, \"BMC Messsysteme GmbH\"  },\r\n    { 0x09CB, \"Flir Systems\"  },\r\n    { 0x09CC, \"Workbit Corporation\"  },\r\n    { 0x09CD, \"Psion Connect Ltd.\"  },\r\n    { 0x09CE, \"City Electronics Ltd.\"  },\r\n    { 0x09CF, \"Electronics Testing Center, Taiwan\"  },\r\n    { 0x09D1, \"NeoMagic Inc.\"  },\r\n    { 0x09D2, \"Vreelin Engineering Inc.\"  },\r\n    { 0x09D3, \"COM ONE\"  },\r\n    { 0x09D4, \"Asahi Engineering Co., Ltd.\"  },\r\n    { 0x09D5, \"DigiTech\"  },\r\n    { 0x09D6, \"Berkeley Varitronics Systems\"  },\r\n    { 0x09D7, \"NovAtel Inc.\"  },\r\n    { 0x09D8, \"Elatec GmbH\"  },\r\n    { 0x09D9, \"Jungo\"  },\r\n    { 0x09DA, \"A-FOUR TECH CO., LTD.\"  },\r\n    { 0x09DB, \"Measurement Computing Corporation\"  },\r\n    { 0x09DC, \"AIMEX Corporation\"  },\r\n    { 0x09DD, \"Fellowes Inc.\"  },\r\n    { 0x09DE, \"ViQuest Technology\"  },\r\n    { 0x09DF, \"Addonics Technologies Corp.\"  },\r\n    { 0x09E0, \"Johnson Matthey PLC, Trading as Tracerco\"  },\r\n    { 0x09E1, \"Intellon Corporation\"  },\r\n    { 0x09E2, \"Surface Imaging Systems (S.I.S.)\"  },\r\n    { 0x09E3, \"WIZnet\"  },\r\n    { 0x09E4, \"Unidata\"  },\r\n    { 0x09E5, \"Jo-Dan International, Inc.\"  },\r\n    { 0x09E6, \"Silutia, Inc.\"  },\r\n    { 0x09E7, \"Real 3D, Inc.\"  },\r\n    { 0x09E8, \"AKAI professional M.I. Corp.\"  },\r\n    { 0x09E9, \"CHEN-SOURCE INC.\"  },\r\n    { 0x09EA, \"ShareCall Technologies\"  },\r\n    { 0x09EB, \"Sonicbox, Inc.\"  },\r\n    { 0x09EC, \"COINT Multimedia Systems\"  },\r\n    { 0x09ED, \"Viking Sewing Machines AB\"  },\r\n    { 0x09EE, \"Jesmay Electronics Co., Ltd.\"  },\r\n    { 0x09EF, \"XITEL PTY Limited\"  },\r\n    { 0x09F0, \"Perpetual Technologies, LLC\"  },\r\n    { 0x09F1, \"Eshed Robotec\"  },\r\n    { 0x09F2, \"hema Elektronik GmbH\"  },\r\n    { 0x09F3, \"GoFlight, Inc.\"  },\r\n    { 0x09F4, \"Microlink Corporation\"  },\r\n    { 0x09F5, \"ARESCOM\"  },\r\n    { 0x09F6, \"RocketChips, Inc.\"  },\r\n    { 0x09F7, \"EDU-SCIENCE (H.K.) LIMITED\"  },\r\n    { 0x09F8, \"SoftConnex Technologies, Inc.\"  },\r\n    { 0x09F9, \"Bay Associates\"  },\r\n    { 0x09FA, \"Mtek Vision\"  },\r\n    { 0x09FB, \"Altera\"  },\r\n    { 0x09FC, \"Silicon Mountain Design\"  },\r\n    { 0x09FD, \"MM - Manager Memory\"  },\r\n    { 0x09FE, \"Goldteck International Inc.\"  },\r\n    { 0x09FF, \"Gain Technology Corp.\"  },\r\n    { 0x0A00, \"Liquid Audio\"  },\r\n    { 0x0A01, \"ViA, Inc.\"  },\r\n    { 0x0A02, \"DIATECNIC\"  },\r\n    { 0x0A03, \"Globe Wireless, Inc.\"  },\r\n    { 0x0A04, \"Star, Inc.\"  },\r\n    { 0x0A05, \"University of Kansas\"  },\r\n    { 0x0A06, \"BSQUARE Slicon Valley\"  },\r\n    { 0x0A07, \"Ontrak Control Systems Inc.\"  },\r\n    { 0x0A08, \"Lorenz GmbH\"  },\r\n    { 0x0A09, \"Datadesk Technologies Inc.\"  },\r\n    { 0x0A0A, \"LIEWENTHAL ELECTRONICS LTD.\"  },\r\n    { 0x0A0B, \"Cybex Computer Products Corporation\"  },\r\n    { 0x0A0C, \"MIRAD\"  },\r\n    { 0x0A0D, \"VIPS France\"  },\r\n    { 0x0A0E, \"AGFEO\"  },\r\n    { 0x0A0F, \"Liesegang\"  },\r\n    { 0x0A10, \"Combinova AB\"  },\r\n    { 0x0A11, \"Xentec Incorporated\"  },\r\n    { 0x0A12, \"Cambridge Silicon Radio Ltd.\"  },\r\n    { 0x0A13, \"Telebyte Inc.\"  },\r\n    { 0x0A14, \"Spacelabs Healthcare\"  },\r\n    { 0x0A15, \"Scalar Corporation\"  },\r\n    { 0x0A16, \"Trek Technology (S) Pte Ltd\"  },\r\n    { 0x0A17, \"HOYA Corporation\"  },\r\n    { 0x0A18, \"Heidelberger Druckmaschinen AG\"  },\r\n    { 0x0A19, \"Hua Geng Technologies Inc.\"  },\r\n    { 0x0A1A, \"Astro-Med, Inc.\"  },\r\n    { 0x0A1B, \"Wolfvision GmbH\"  },\r\n    { 0x0A1C, \"Micro Systemation AB\"  },\r\n    { 0x0A1D, \"T-Nova Deutsche Telekom Innovationsgesellschaft\"  },\r\n    { 0x0A1E, \"Netcraft (Pty) Ltd.\"  },\r\n    { 0x0A1F, \"Tesco Co.\"  },\r\n    { 0x0A20, \"SystemBase Co., Ltd.\"  },\r\n    { 0x0A21, \"Physio-Control, Inc.\"  },\r\n    { 0x0A22, \"Century Semiconductor USA, Inc.\"  },\r\n    { 0x0A23, \"NDS Technologies Israel Ltd.\"  },\r\n    { 0x0A24, \"Boca Design, Inc.\"  },\r\n    { 0x0A25, \"3M Germany\"  },\r\n    { 0x0A26, \"Cyberware\"  },\r\n    { 0x0A27, \"Datacard Group\"  },\r\n    { 0x0A28, \"Ensure Technologies, Inc.\"  },\r\n    { 0x0A29, \"Marketcast\"  },\r\n    { 0x0A2A, \"Fortune Electronics & Plastic (International) Ltd.\"  },\r\n    { 0x0A2B, \"Muller & Sebastiani Elektronik GmbH\"  },\r\n    { 0x0A2C, \"Ak Modul Bus Computer GmbH\"  },\r\n    { 0x0A2D, \"Advanced Measurement Technology\"  },\r\n    { 0x0A2E, \"ONE-O-ONE iSOLUTIONS\"  },\r\n    { 0x0A2F, \"Prime Systems, Inc.\"  },\r\n    { 0x0A30, \"WAW-Tronics\"  },\r\n    { 0x0A31, \"Data System Co., Ltd.\"  },\r\n    { 0x0A32, \"Addatel ApS\"  },\r\n    { 0x0A33, \"Intermind Inc.\"  },\r\n    { 0x0A34, \"TG3 Electronics, Inc.\"  },\r\n    { 0x0A35, \"Radikal Technologies\"  },\r\n    { 0x0A36, \"GS Technical Support Center\"  },\r\n    { 0x0A37, \"Concept Development\"  },\r\n    { 0x0A38, \"I.R.I.S.\"  },\r\n    { 0x0A39, \"Gilat Satellite Networks Ltd.\"  },\r\n    { 0x0A3A, \"PentaMedia Co., Ltd.\"  },\r\n    { 0x0A3B, \"Hitachi Information Technology Co., Ltd.\"  },\r\n    { 0x0A3C, \"NTT DoCoMo,Inc.\"  },\r\n    { 0x0A3D, \"Varo Vision\"  },\r\n    { 0x0A3E, \"REINHARDT System- und Messelectronic GmbH\"  },\r\n    { 0x0A3F, \"Swissonic AG\"  },\r\n    { 0x0A40, \"PaloDEx Group Oy\"  },\r\n    { 0x0A41, \"SEKONIC corporation\"  },\r\n    { 0x0A42, \"Medtronic Functional Diagnostics\"  },\r\n    { 0x0A43, \"Boca Systems Inc.\"  },\r\n    { 0x0A44, \"TurboLinux\"  },\r\n    { 0x0A45, \"Look&Say co., Ltd.\"  },\r\n    { 0x0A46, \"Davicom Semiconductor, Inc.\"  },\r\n    { 0x0A47, \"Hirose Electric Co., Ltd.\"  },\r\n    { 0x0A48, \"I/O Interconnect\"  },\r\n    { 0x0A4A, \"propagamma kommunikation\"  },\r\n    { 0x0A4B, \"Fujitsu Media Devices Limited\"  },\r\n    { 0x0A4C, \"COMPUTEX Co., Ltd.\"  },\r\n    { 0x0A4D, \"Evolution Electronics Ltd.\"  },\r\n    { 0x0A4E, \"Steinberg Soft-und Hardware GmbH\"  },\r\n    { 0x0A4F, \"Litton Systems Inc.\"  },\r\n    { 0x0A50, \"Mimaki Engineering Co., Ltd.\"  },\r\n    { 0x0A51, \"Sony Electronics Inc.\"  },\r\n    { 0x0A52, \"JEBSEE ELECTRONICS CO., LTD.\"  },\r\n    { 0x0A53, \"Portable Peripheral Co., Ltd.\"  },\r\n    { 0x0A54, \"Applied Signal Technology, Inc.\"  },\r\n    { 0x0A55, \"ThermoQuest Corporation\"  },\r\n    { 0x0A56, \"EAE electronics GmbH\"  },\r\n    { 0x0A57, \"Joachim Koopmann Software\"  },\r\n    { 0x0A58, \"DIGIDENT LTD.\"  },\r\n    { 0x0A59, \"Convergence Instruments\"  },\r\n    { 0x0A5B, \"EASICS NV\"  },\r\n    { 0x0A5C, \"Broadcom Corp.\"  },\r\n    { 0x0A5D, \"Diatrend Corporation\"  },\r\n    { 0x0A5E, \"Spinnaker Systems Inc.\"  },\r\n    { 0x0A5F, \"Zebra Technologies\"  },\r\n    { 0x0A60, \"Future Networks, Inc.\"  },\r\n    { 0x0A61, \"DTI sa\"  },\r\n    { 0x0A62, \"MPMan.com, Inc.\"  },\r\n    { 0x0A63, \"Prism Media Products Ltd.\"  },\r\n    { 0x0A64, \"Padcom Inc.\"  },\r\n    { 0x0A65, \"FullAudio, Inc.\"  },\r\n    { 0x0A66, \"ClearCube Technology\"  },\r\n    { 0x0A67, \"Medeli Electronics Co, Ltd.\"  },\r\n    { 0x0A68, \"COMAIDE Corporation\"  },\r\n    { 0x0A69, \"Chroma ate Inc.\"  },\r\n    { 0x0A6A, \"Newcom Inc.\"  },\r\n    { 0x0A6B, \"Green House Co., Ltd.\"  },\r\n    { 0x0A6C, \"Integrated Circuit Systems Inc.\"  },\r\n    { 0x0A6D, \"UPS Manufacturing\"  },\r\n    { 0x0A6E, \"Benwin\"  },\r\n    { 0x0A6F, \"Core Technology, Inc.\"  },\r\n    { 0x0A70, \"International Game Technology\"  },\r\n    { 0x0A71, \"VIPColor Technologies USA, Inc.\"  },\r\n    { 0x0A72, \"Sanwa Denshi\"  },\r\n    { 0x0A73, \"SYDEC N.V.\"  },\r\n    { 0x0A74, \"Adaptive Networks, Inc.\"  },\r\n    { 0x0A75, \"Jeol USA, Inc.\"  },\r\n    { 0x0A76, \"I-Jam Multi-Media, LLC\"  },\r\n    { 0x0A77, \"Janome Sewing Machine Co., Ltd.\"  },\r\n    { 0x0A78, \"GREATSUN\"  },\r\n    { 0x0A79, \"Geocast Network Systems, Inc.\"  },\r\n    { 0x0A7A, \"Towitoko AG\"  },\r\n    { 0x0A7B, \"R & D Co., Ltd.\"  },\r\n    { 0x0A7C, \"QUANCOM Informationssysteme GmbH\"  },\r\n    { 0x0A7D, \"Intertek NSTL\"  },\r\n    { 0x0A7E, \"Octagon Systems Corporation\"  },\r\n    { 0x0A7F, \"AVerMedia MicroSystems\"  },\r\n    { 0x0A80, \"Rexon Technology Corp., Ltd\"  },\r\n    { 0x0A81, \"CHESEN ELECTRONICS CORP.\"  },\r\n    { 0x0A82, \"SYSCAN\"  },\r\n    { 0x0A83, \"NextComm, Inc.\"  },\r\n    { 0x0A84, \"Maui Innovative Peripherals\"  },\r\n    { 0x0A85, \"IDEXX LABS\"  },\r\n    { 0x0A86, \"NITGen Co., Ltd.\"  },\r\n    { 0x0A87, \"Tucker-Davis Technologies, Inc.\"  },\r\n    { 0x0A88, \"PAH-RAN TECH., INC.\"  },\r\n    { 0x0A89, \"Active Company\"  },\r\n    { 0x0A8A, \"American Magnetics\"  },\r\n    { 0x0A8B, \"Intelliworxx Inc.\"  },\r\n    { 0x0A8C, \"Tecmar\"  },\r\n    { 0x0A8D, \"Picturetel\"  },\r\n    { 0x0A8E, \"Japan Aviation Electronics Industry Ltd. (JAE)\"  },\r\n    { 0x0A8F, \"Young Chang Co. Ltd.\"  },\r\n    { 0x0A90, \"Candy Technology Co., Ltd.\"  },\r\n    { 0x0A91, \"Globlink Technology Inc.\"  },\r\n    { 0x0A92, \"EGO SYStems Inc.\"  },\r\n    { 0x0A93, \"C Technologies AB (publ)\"  },\r\n    { 0x0A94, \"Intersense\"  },\r\n    { 0x0A95, \"Origin Instruments Corporation\"  },\r\n    { 0x0A96, \"Evation.com\"  },\r\n    { 0x0A97, \"Guardware Systems Ltd.\"  },\r\n    { 0x0A98, \"TECHNO ART CO., LTD\"  },\r\n    { 0x0A99, \"Talon Technology\"  },\r\n    { 0x0A9A, \"Business Navigator\"  },\r\n    { 0x0A9B, \"Input/Output Inc.\"  },\r\n    { 0x0A9C, \"Applied Cytometry Systems\"  },\r\n    { 0x0A9D, \"Jung & Dusch GmbH\"  },\r\n    { 0x0A9E, \"Performance Concepts, Inc.\"  },\r\n    { 0x0A9F, \"Sim-Addicts Design Group\"  },\r\n    { 0x0AA0, \"Vtech Communications Ltd.\"  },\r\n    { 0x0AA1, \"Amer.com\"  },\r\n    { 0x0AA2, \"Delta Tau Data Systems, Inc.\"  },\r\n    { 0x0AA3, \"Lava Computer Mfg. Inc.\"  },\r\n    { 0x0AA4, \"Develco Elektronik\"  },\r\n    { 0x0AA5, \"First International Digital\"  },\r\n    { 0x0AA6, \"Perception Digital Limited\"  },\r\n    { 0x0AA7, \"Wincor Nixdorf GmbH & Co KG\"  },\r\n    { 0x0AA8, \"TriGem Computer, Inc.\"  },\r\n    { 0x0AA9, \"Baromtec Co.\"  },\r\n    { 0x0AAA, \"Japan CBM Corporation\"  },\r\n    { 0x0AAB, \"Vision Shape Europe SA.\"  },\r\n    { 0x0AAC, \"iCompression Inc.\"  },\r\n    { 0x0AAD, \"Rohde & Schwarz GmbH & Co. KG\"  },\r\n    { 0x0AAE, \"NEC infrontia Corporation\"  },\r\n    { 0x0AAF, \"digitalway co., ltd.\"  },\r\n    { 0x0AB0, \"Arrow Strong Electronics CO. LTD\"  },\r\n    { 0x0AB1, \"Feig Electronic GmbH\"  },\r\n    { 0x0AB2, \"Sintefex Audio LDA\"  },\r\n    { 0x0AB3, \"CANON FINETECH INC.\"  },\r\n    { 0x0AB4, \"esd electronic system design gmbh\"  },\r\n    { 0x0AB5, \"Beckman Coulter, Inc.\"  },\r\n    { 0x0AB6, \"Labsystems Oy\"  },\r\n    { 0x0AB7, \"Cross electronics, inc.\"  },\r\n    { 0x0AB8, \"TelePhotogenics, Inc.\"  },\r\n    { 0x0AB9, \"Identcode Ltd.\"  },\r\n    { 0x0ABA, \"University of Geneva\"  },\r\n    { 0x0ABB, \"Travsys BV\"  },\r\n    { 0x0ABC, \"Life-Tech, Inc.\"  },\r\n    { 0x0ABD, \"Wako Rubber Industries Co., Ltd.\"  },\r\n    { 0x0ABE, \"STEREOLINK.COM\"  },\r\n    { 0x0ABF, \"DeVaSys\"  },\r\n    { 0x0AC0, \"Nidek Co., Ltd.\"  },\r\n    { 0x0AC1, \"MicroDatec GmbH\"  },\r\n    { 0x0AC2, \"BrainMaster Technologies, Inc.\"  },\r\n    { 0x0AC3, \"ON Semiconductor (System Solutions Co., Ltd)\"  },\r\n    { 0x0AC4, \"LECO CORPORATION\"  },\r\n    { 0x0AC5, \"I & C Corporation\"  },\r\n    { 0x0AC6, \"Singing Electrons, Inc.\"  },\r\n    { 0x0AC7, \"Panwest Corporation\"  },\r\n    { 0x0AC8, \"Vimicro Corporation\"  },\r\n    { 0x0AC9, \"Micro Solutions, Inc.\"  },\r\n    { 0x0ACA, \"The Open Group\"  },\r\n    { 0x0ACB, \"DEICY CORPORATION\"  },\r\n    { 0x0ACC, \"Koga Electronics Co.\"  },\r\n    { 0x0ACD, \"ID Tech\"  },\r\n    { 0x0ACE, \"ZyDAS Technology Corporation\"  },\r\n    { 0x0ACF, \"Intoto, Inc.\"  },\r\n    { 0x0AD0, \"Intellix Corp.\"  },\r\n    { 0x0AD1, \"Remotec Technology Ltd.\"  },\r\n    { 0x0AD2, \"Service & Quality Technology Co., Ltd.\"  },\r\n    { 0x0AD3, \"Bolton Engineering, Inc.\"  },\r\n    { 0x0AD4, \"TIGEREX ENTERPRISE CO., LTD.\"  },\r\n    { 0x0AD5, \"kuwatec, Inc.\"  },\r\n    { 0x0AD6, \"Vir A/S\"  },\r\n    { 0x0AD7, \"Lynium L.L.C.\"  },\r\n    { 0x0AD8, \"Aidonic Corporation\"  },\r\n    { 0x0AD9, \"Avolites Ltd.\"  },\r\n    { 0x0ADA, \"Data Encryption Systems Ltd\"  },\r\n    { 0x0ADB, \"T.A.M. Co., Ltd.\"  },\r\n    { 0x0ADC, \"KE Knestel Elektronik GmbH\"  },\r\n    { 0x0ADD, \"Alliance Distribution\"  },\r\n    { 0x0ADE, \"Microft Co., Ltd.\"  },\r\n    { 0x0ADF, \"Arial Phone L.L.C.\"  },\r\n    { 0x0AE0, \"Collins Medical\"  },\r\n    { 0x0AE1, \"Protein Solutions, Inc.\"  },\r\n    { 0x0AE2, \"NERA SATCOM ASA\"  },\r\n    { 0x0AE3, \"Allion Labs, Inc.\"  },\r\n    { 0x0AE4, \"Taito Corporation\"  },\r\n    { 0x0AE5, \"MacroSystem Digital Video AG\"  },\r\n    { 0x0AE6, \"EVI, Inc.\"  },\r\n    { 0x0AE7, \"Neodym Systems Inc.\"  },\r\n    { 0x0AE8, \"System Support Co., Ltd.\"  },\r\n    { 0x0AE9, \"North Shore Circuit Design L.L.P.\"  },\r\n    { 0x0AEA, \"SciEssence, LLC\"  },\r\n    { 0x0AEB, \"TTP Communications Ltd.\"  },\r\n    { 0x0AEC, \"Neodio Technologies Corporation\"  },\r\n    { 0x0AED, \"ScottCare Corporation\"  },\r\n    { 0x0AEE, \"Max Co., Ltd.\"  },\r\n    { 0x0AEF, \"Simple Systems, Ltd.\"  },\r\n    { 0x0AF0, \"Option NV\"  },\r\n    { 0x0AF1, \"KYOEI Co., Ltd.\"  },\r\n    { 0x0AF2, \"CARTS, LLC\"  },\r\n    { 0x0AF3, \"Scale Master Technology, LLC.\"  },\r\n    { 0x0AF4, \"ARTRONICS CO. LTD\"  },\r\n    { 0x0AF5, \"Nakamichi\"  },\r\n    { 0x0AF6, \"SILVER I CO., LTD.\"  },\r\n    { 0x0AF7, \"B2C2, Inc.\"  },\r\n    { 0x0AF8, \"Taiwan Regular Electronics Co., Ltd.\"  },\r\n    { 0x0AF9, \"NEW AFA TECHNOLOGY CO., LTD\"  },\r\n    { 0x0AFA, \"DMC Co., Ltd.\"  },\r\n    { 0x0AFB, \"OO-ALC/TISMD-CAPRE\"  },\r\n    { 0x0AFC, \"Zaptronix Ltd\"  },\r\n    { 0x0AFD, \"Tateno Dennou, Inc.\"  },\r\n    { 0x0AFE, \"Cummins Engine Company\"  },\r\n    { 0x0AFF, \"Jump Zone Network Products, Inc.\"  },\r\n    { 0x0B00, \"INGENICO\"  },\r\n    { 0x0B01, \"Techno-Holon Corporation\"  },\r\n    { 0x0B02, \"Avery Weigh-Tronix\"  },\r\n    { 0x0B03, \"ARCA TECHNOLOGIES, LTD.\"  },\r\n    { 0x0B04, \"EURESYS S.A.\"  },\r\n    { 0x0B05, \"ASUSTek Computer Inc.\"  },\r\n    { 0x0B06, \"Digital Ink, Inc.\"  },\r\n    { 0x0B07, \"Telebau GmbH\"  },\r\n    { 0x0B08, \"Lightwell Co., Ltd ZAX Division\"  },\r\n    { 0x0B09, \"Allophonic Electronics L.t.d.\"  },\r\n    { 0x0B0A, \"FARO Technologies INC.\"  },\r\n    { 0x0B0B, \"Datamax Corporation\"  },\r\n    { 0x0B0C, \"Todos Data System AB\"  },\r\n    { 0x0B0D, \"Project Lab\"  },\r\n    { 0x0B0E, \"GN Audio\"  },\r\n    { 0x0B0F, \"AVID Technology\"  },\r\n    { 0x0B10, \"Pcally\"  },\r\n    { 0x0B11, \"I Tech Solutions Co., Ltd.\"  },\r\n    { 0x0B12, \"T-Metrics, Inc.\"  },\r\n    { 0x0B13, \"Practical Micro Design, Inc.\"  },\r\n    { 0x0B14, \"Real Sport, Inc.\"  },\r\n    { 0x0B15, \"Actia Do Brasil Ind. E. Com. Ltda.\"  },\r\n    { 0x0B16, \"onscreen24\"  },\r\n    { 0x0B17, \"Scantron Corporation\"  },\r\n    { 0x0B18, \"Shimizu Works, Hitachi Air Conditioning Systems Co\"  },\r\n    { 0x0B19, \"Color Kinetics Inc.\"  },\r\n    { 0x0B1B, \"Bematech Ind. Com. Equip. Elect. S.A.\"  },\r\n    { 0x0B1C, \"York Electronics Centre\"  },\r\n    { 0x0B1D, \"Erich Jaeger GmbH\"  },\r\n    { 0x0B1E, \"Electronic Warfare Associates, Inc. (EWA)\"  },\r\n    { 0x0B1F, \"Insyde Software Corp.\"  },\r\n    { 0x0B20, \"TransDimension Inc.\"  },\r\n    { 0x0B21, \"Yokogawa Electric Corporation\"  },\r\n    { 0x0B22, \"Japan System Development Co. Ltd.\"  },\r\n    { 0x0B23, \"Pan-Asia Electronics Co., Ltd.\"  },\r\n    { 0x0B24, \"ITX E-Globaledge Corporation\"  },\r\n    { 0x0B25, \"Advanced Programming Concepts, Inc.\"  },\r\n    { 0x0B26, \"Applied Scientific Instrumentation Inc.\"  },\r\n    { 0x0B27, \"Ritek Corporation\"  },\r\n    { 0x0B28, \"Kenwood Corporation\"  },\r\n    { 0x0B29, \"Intertex Data AB\"  },\r\n    { 0x0B2A, \"Glotrex Co., Ltd.\"  },\r\n    { 0x0B2C, \"Village Center, Inc.\"  },\r\n    { 0x0B2D, \"Akatsuki Electronic work & study Corp.\"  },\r\n    { 0x0B2E, \"CTL Inc.\"  },\r\n    { 0x0B2F, \"Clarkspur Design, Inc.\"  },\r\n    { 0x0B30, \"NewHeights Software\"  },\r\n    { 0x0B31, \"Kyowa Electronic Instruments Co., Ltd.\"  },\r\n    { 0x0B32, \"Utrecht University MBF\"  },\r\n    { 0x0B33, \"Contour Design, Inc.\"  },\r\n    { 0x0B34, \"KNP Technologies\"  },\r\n    { 0x0B35, \"Solutions Cubed\"  },\r\n    { 0x0B36, \"Iizuna Signal Processing Lab Inc.\"  },\r\n    { 0x0B37, \"Hitachi ULSI Systems Co., Ltd.\"  },\r\n    { 0x0B39, \"Omnidirectional Control Technology Inc.\"  },\r\n    { 0x0B3A, \"IPaxess\"  },\r\n    { 0x0B3B, \"Bromax Communications, Inc.\"  },\r\n    { 0x0B3C, \"Olivetti S.p.A\"  },\r\n    { 0x0B3E, \"Kikusui Electronics Corporation\"  },\r\n    { 0x0B3F, \"Mitec Systems, Inc.\"  },\r\n    { 0x0B40, \"RF Solutions Ltd.\"  },\r\n    { 0x0B41, \"Hal Corporation\"  },\r\n    { 0x0B42, \"LENZE GmbH & Co KG\"  },\r\n    { 0x0B43, \"Sixth Avenue Designs\"  },\r\n    { 0x0B44, \"Programa Tools, Inc.\"  },\r\n    { 0x0B45, \"Event Electronics, LLC\"  },\r\n    { 0x0B46, \"Nuark Co., Ltd.\"  },\r\n    { 0x0B47, \"Sportbug.com, Inc\"  },\r\n    { 0x0B48, \"TechnoTrend AG\"  },\r\n    { 0x0B49, \"ASCII Corporation\"  },\r\n    { 0x0B4A, \"Pocket Pyro, Inc.\"  },\r\n    { 0x0B4B, \"XFX Creation Inc.\"  },\r\n    { 0x0B4C, \"Comvurgent\"  },\r\n    { 0x0B4D, \"Graphtec\"  },\r\n    { 0x0B4E, \"Musical Electronics Ltd.\"  },\r\n    { 0x0B4F, \"Neuralog, Inc.\"  },\r\n    { 0x0B50, \"Starlight Marketing (H.K.) Ltd.\"  },\r\n    { 0x0B51, \"USB KITS\"  },\r\n    { 0x0B52, \"Zight Corporation\"  },\r\n    { 0x0B54, \"Sinbon Electronics Co., Ltd.\"  },\r\n    { 0x0B55, \"Sendtek Corporation\"  },\r\n    { 0x0B56, \"TYI Systems Ltd.\"  },\r\n    { 0x0B57, \"Hanwang Technology Co., LTD.\"  },\r\n    { 0x0B59, \"Lake Communications Ltd.\"  },\r\n    { 0x0B5A, \"Corel Corporation\"  },\r\n    { 0x0B5B, \"Anritsu Corporation\"  },\r\n    { 0x0B5C, \"IDEAL Industries Inc.\"  },\r\n    { 0x0B5D, \"Music Playground Inc.\"  },\r\n    { 0x0B5E, \"Luciol Instruments\"  },\r\n    { 0x0B5F, \"Green Electronics Co., Ltd.\"  },\r\n    { 0x0B60, \"SiConnect Ltd.\"  },\r\n    { 0x0B61, \"NEC Display Solutions, Ltd.\"  },\r\n    { 0x0B62, \"Orange Micro, Inc.\"  },\r\n    { 0x0B63, \"ADLink Technology Inc.\"  },\r\n    { 0x0B64, \"Wonderful Wire Cable Co., Ltd\"  },\r\n    { 0x0B65, \"Expert Magnetics Corp.\"  },\r\n    { 0x0B66, \"Cybiko Inc.\"  },\r\n    { 0x0B67, \"Fairbanks Scales\"  },\r\n    { 0x0B68, \"SenDEC Corporation\"  },\r\n    { 0x0B69, \"CacheVision\"  },\r\n    { 0x0B6A, \"Maxim Integrated Products\"  },\r\n    { 0x0B6B, \"Ashling Microsystems Ltd.\"  },\r\n    { 0x0B6C, \"FreeSystems Pte Ltd\"  },\r\n    { 0x0B6D, \"The Graphics Network Limited\"  },\r\n    { 0x0B6E, \"Neurosoft, Inc.\"  },\r\n    { 0x0B6F, \"Nagano Japan Radio Co., Ltd\"  },\r\n    { 0x0B70, \"PortalPlayer, Inc.\"  },\r\n    { 0x0B71, \"SHIN-EI Sangyo Co., Ltd.\"  },\r\n    { 0x0B72, \"Embedded Wireless Technology Co. Ltd.\"  },\r\n    { 0x0B73, \"Computone Corp.\"  },\r\n    { 0x0B75, \"Roland DG Corporation\"  },\r\n    { 0x0B76, \"Pro-Tech Services Inc.\"  },\r\n    { 0x0B77, \"RJS, Inc.\"  },\r\n    { 0x0B78, \"ATSKY\"  },\r\n    { 0x0B79, \"Sunrise Telecom, Inc.\"  },\r\n    { 0x0B7A, \"Zeevo, Inc.\"  },\r\n    { 0x0B7B, \"Taiko Denki Co., Ltd.\"  },\r\n    { 0x0B7C, \"ITRAN Communications Ltd.\"  },\r\n    { 0x0B7D, \"Astrodesign, Inc.\"  },\r\n    { 0x0B7E, \"Kurusugawa Electronics Incorporate\"  },\r\n    { 0x0B7F, \"Scantech BV\"  },\r\n    { 0x0B80, \"Omtronix Engineering Corp.\"  },\r\n    { 0x0B81, \"id3 Semiconductors\"  },\r\n    { 0x0B82, \"TravRoute, a division of ALK Associates, Inc.\"  },\r\n    { 0x0B83, \"OCTAX Microscience\"  },\r\n    { 0x0B84, \"Rextron Technology, Inc.\"  },\r\n    { 0x0B85, \"Elkat Electronics (M) SDN. BHD.\"  },\r\n    { 0x0B86, \"Exputer Systems, Inc.\"  },\r\n    { 0x0B87, \"Plus-One I & T Inc.\"  },\r\n    { 0x0B88, \"Sigma Koki Co., Ltd. Technology Center\"  },\r\n    { 0x0B89, \"Advanced Digital Broadcast Ltd.\"  },\r\n    { 0x0B8A, \"YARC Systems Corporation\"  },\r\n    { 0x0B8B, \"American Microsystems, Ltd.\"  },\r\n    { 0x0B8C, \"SMART Technologies Inc.\"  },\r\n    { 0x0B8D, \"Microsystems Development Technologies, Inc.\"  },\r\n    { 0x0B8E, \"Dartcom\"  },\r\n    { 0x0B8F, \"Visual Environment\"  },\r\n    { 0x0B90, \"DACTRON INC.\"  },\r\n    { 0x0B91, \"DesignTech International, Inc.\"  },\r\n    { 0x0B92, \"SINAR AG\"  },\r\n    { 0x0B93, \"Marantz Japan, Inc.\"  },\r\n    { 0x0B94, \"NEOREX Co., Ltd.\"  },\r\n    { 0x0B95, \"ASIX Electronics Corporation\"  },\r\n    { 0x0B96, \"SEWON TELECOM\"  },\r\n    { 0x0B97, \"O2Micro, Inc.\"  },\r\n    { 0x0B98, \"Playmates Toys Inc.\"  },\r\n    { 0x0B99, \"Audio International, Inc.\"  },\r\n    { 0x0B9A, \"Namco Limited\"  },\r\n    { 0x0B9B, \"Dipl.-Ing. Stefan Kunde\"  },\r\n    { 0x0B9C, \"Melco Embroidery Systems\"  },\r\n    { 0x0B9D, \"Softprotec Co.\"  },\r\n    { 0x0B9E, \"Asylum Research\"  },\r\n    { 0x0B9F, \"Chippo Technologies\"  },\r\n    { 0x0BA0, \"Turtle Industry Co., Ltd.\"  },\r\n    { 0x0BA1, \"Jowit Company Limited\"  },\r\n    { 0x0BA2, \"Line Media Research CO., LTD.\"  },\r\n    { 0x0BA3, \"Taiko Electric Works, Ltd.\"  },\r\n    { 0x0BA4, \"Nagano Oki Electric Co., Ltd.\"  },\r\n    { 0x0BA5, \"Clemex Technologies Inc.\"  },\r\n    { 0x0BA6, \"3DM Devices Inc\"  },\r\n    { 0x0BA7, \"CVC Networks Co., Ltd.\"  },\r\n    { 0x0BA8, \"CastleNet Technology Inc.\"  },\r\n    { 0x0BA9, \"Misawa Homes Co., Ltd.\"  },\r\n    { 0x0BAA, \"Dr. Gerhard Schmidt GmbH\"  },\r\n    { 0x0BAB, \"House Ear Institute\"  },\r\n    { 0x0BAC, \"Biometric Access Corporation\"  },\r\n    { 0x0BAD, \"Festo Didactic Ltd/Ltee\"  },\r\n    { 0x0BAE, \"IGEN International, Inc.\"  },\r\n    { 0x0BAF, \"U.S. Robotics\"  },\r\n    { 0x0BB0, \"Concord Camera Corp.\"  },\r\n    { 0x0BB1, \"Infinilink Corporation\"  },\r\n    { 0x0BB2, \"Ambit Microsystems Corporation\"  },\r\n    { 0x0BB3, \"Ofuji Technology\"  },\r\n    { 0x0BB4, \"HTC Corporation\"  },\r\n    { 0x0BB5, \"Murata Manufacturing Co., Ltd.\"  },\r\n    { 0x0BB6, \"Network Alchemy\"  },\r\n    { 0x0BB7, \"Joytech Computer Company Limited\"  },\r\n    { 0x0BB8, \"Renesas Technology Sales Co., Ltd.\"  },\r\n    { 0x0BB9, \"Eiger M & C CO., LTD.\"  },\r\n    { 0x0BBA, \"ZACCESS Systems\"  },\r\n    { 0x0BBB, \"General Meters Corporation\"  },\r\n    { 0x0BBC, \"Assistive Technology, Inc.\"  },\r\n    { 0x0BBD, \"System Connection, Inc\"  },\r\n    { 0x0BBE, \"ShibaSoku Co., Ltd.\"  },\r\n    { 0x0BBF, \"Algo Communication Products Ltd.\"  },\r\n    { 0x0BC0, \"Knilink Technology Inc.\"  },\r\n    { 0x0BC1, \"FUW YNG ELECTRONICS COMPANY LTD\"  },\r\n    { 0x0BC2, \"Seagate Technology LLC\"  },\r\n    { 0x0BC3, \"IPWireless, Inc.\"  },\r\n    { 0x0BC4, \"Microcube Corp.\"  },\r\n    { 0x0BC5, \"JCN Co., Ltd.\"  },\r\n    { 0x0BC6, \"ExWAY Inc.\"  },\r\n    { 0x0BC7, \"X10 Wireless Technology, Inc.\"  },\r\n    { 0x0BC8, \"Telmax Communications\"  },\r\n    { 0x0BC9, \"ECI Telecom Ltd\"  },\r\n    { 0x0BCA, \"Startek Engineering Incorporated\"  },\r\n    { 0x0BCB, \"Perfect Technic Enterprise Co. LTD\"  },\r\n    { 0x0BCC, \"Dolphin Interactive\"  },\r\n    { 0x0BCD, \"Mbeware Inc.\"  },\r\n    { 0x0BCE, \"I-TEC hanshin Incorporated Company\"  },\r\n    { 0x0BCF, \"Chuo-Engineering Ltd.\"  },\r\n    { 0x0BD0, \"Trenz Electronic\"  },\r\n    { 0x0BD1, \"Blue Sky Labs, Inc.\"  },\r\n    { 0x0BD2, \"Union Biometrica\"  },\r\n    { 0x0BD3, \"OPHIR OPTRONICS LTD\"  },\r\n    { 0x0BD4, \"NISSIN INC.\"  },\r\n    { 0x0BD5, \"Rabbit House Corporation\"  },\r\n    { 0x0BD6, \"Renaissance Learning Inc.\"  },\r\n    { 0x0BD7, \"Andrew Pargeter & Associates\"  },\r\n    { 0x0BD8, \"Gamry Instruments, Inc.\"  },\r\n    { 0x0BD9, \"Liberty Instruments, Inc.\"  },\r\n    { 0x0BDA, \"Realtek Semiconductor Corp.\"  },\r\n    { 0x0BDB, \"Ericsson AB\"  },\r\n    { 0x0BDC, \"Y Media Corporation\"  },\r\n    { 0x0BDD, \"Orange PCS\"  },\r\n    { 0x0BDE, \"Thuris Corporation\"  },\r\n    { 0x0BDF, \"PopcomNet Co., Ltd\"  },\r\n    { 0x0BE0, \"Silicon Magic Co., LTD\"  },\r\n    { 0x0BE1, \"COM DEV Wireless\"  },\r\n    { 0x0BE2, \"Kanda Tsushin Kogyo Co., LTD\"  },\r\n    { 0x0BE3, \"TOYO Corporation\"  },\r\n    { 0x0BE4, \"Elka International Ltd.\"  },\r\n    { 0x0BE5, \"DOME Imaging Systems, Inc\"  },\r\n    { 0x0BE6, \"Wonderful Photoelectricity (DongGuan), Co., Ltd.\"  },\r\n    { 0x0BE7, \"Zanthic Technologies Inc.\"  },\r\n    { 0x0BE8, \"M@inNet Communication\"  },\r\n    { 0x0BE9, \"Realistic Interactive, Inc.\"  },\r\n    { 0x0BEA, \"Bryce Office Systems\"  },\r\n    { 0x0BEB, \"RPA Electronics Design, LLC\"  },\r\n    { 0x0BEC, \"Idaho Technology\"  },\r\n    { 0x0BED, \"MEI, Inc.\"  },\r\n    { 0x0BEE, \"LTK International Limited\"  },\r\n    { 0x0BEF, \"Way2Call Communications\"  },\r\n    { 0x0BF0, \"Pace Micro Technology PLC\"  },\r\n    { 0x0BF1, \"Intracom S.A.\"  },\r\n    { 0x0BF2, \"Konexx\"  },\r\n    { 0x0BF3, \"CTI Co., Ltd.\"  },\r\n    { 0x0BF4, \"Kuraya-Sanseido Co., Ltd.\"  },\r\n    { 0x0BF5, \"Xactex Corporation\"  },\r\n    { 0x0BF6, \"Addonics Technologies, Inc.\"  },\r\n    { 0x0BF7, \"Sunny Giken Inc.\"  },\r\n    { 0x0BF8, \"Fujitsu Technology Solutions GmbH\"  },\r\n    { 0x0BF9, \"QPICT, Inc.\"  },\r\n    { 0x0BFA, \"NKE Corporation\"  },\r\n    { 0x0BFB, \"Grass Valley Group\"  },\r\n    { 0x0BFC, \"Zero Mass Products Inc.\"  },\r\n    { 0x0BFD, \"KVASER AB\"  },\r\n    { 0x0BFE, \"Morphy Planning & Co., Ltd\"  },\r\n    { 0x0BFF, \"Damotech Inc.\"  },\r\n    { 0x0C00, \"ATM Computer\"  },\r\n    { 0x0C01, \"K-One Telecom Co., Ltd.\"  },\r\n    { 0x0C02, \"Shinko Seisakusho Co., LTD\"  },\r\n    { 0x0C03, \"SAXA Inc.\"  },\r\n    { 0x0C04, \"MOTO Development Group, Inc.\"  },\r\n    { 0x0C05, \"Appian Graphics\"  },\r\n    { 0x0C06, \"Hasbro, Inc.\"  },\r\n    { 0x0C07, \"Infinite Data Storage LTD\"  },\r\n    { 0x0C08, \"ei Corporation\"  },\r\n    { 0x0C09, \"Comjet Information System\"  },\r\n    { 0x0C0A, \"Highpoint Technologies, Inc.\"  },\r\n    { 0x0C0B, \"Dura Micro, Inc.\"  },\r\n    { 0x0C0C, \"OPTIKON 2000 S.P.A.\"  },\r\n    { 0x0C0D, \"Callify Communications & Software Ltd.\"  },\r\n    { 0x0C0E, \"Korea eBook Inc.\"  },\r\n    { 0x0C0F, \"IDS Innomic GmbH\"  },\r\n    { 0x0C10, \"Silicon Wave\"  },\r\n    { 0x0C11, \"Multigon Industries\"  },\r\n    { 0x0C12, \"Zeroplus Technology Co; LTD\"  },\r\n    { 0x0C13, \"Orion Electronics International\"  },\r\n    { 0x0C14, \"Parallel Technologies, Inc.\"  },\r\n    { 0x0C15, \"Iris Graphics\"  },\r\n    { 0x0C16, \"Gyration, Inc.\"  },\r\n    { 0x0C17, \"Cyberboard A/S\"  },\r\n    { 0x0C18, \"SynerTek Korea, Inc.\"  },\r\n    { 0x0C19, \"cyberPIXIE, Inc.\"  },\r\n    { 0x0C1A, \"Silicon Motion, Inc.\"  },\r\n    { 0x0C1B, \"MIPS TECHNOLOGIES\"  },\r\n    { 0x0C1C, \"Hang Zhou Silan Microelectronics Co. Ltd\"  },\r\n    { 0x0C1D, \"Digital Audio Corporation\"  },\r\n    { 0x0C1E, \"TAKAYA CORP.\"  },\r\n    { 0x0C1F, \"Magicard Ltd\"  },\r\n    { 0x0C20, \"Viditec Inc.\"  },\r\n    { 0x0C21, \"Lunatronic\"  },\r\n    { 0x0C22, \"TallyGenicom LP\"  },\r\n    { 0x0C23, \"Lernout + Hauspie (L + H)\"  },\r\n    { 0x0C24, \"Taiyo Yuden Co., Ltd.\"  },\r\n    { 0x0C25, \"Sampo Corporation\"  },\r\n    { 0x0C26, \"Icom Inc.\"  },\r\n    { 0x0C27, \"RF Ideas\"  },\r\n    { 0x0C28, \"ICCC\"  },\r\n    { 0x0C29, \"SOGECLAIR aerospace\"  },\r\n    { 0x0C2A, \"AFP Imaging Corp.\"  },\r\n    { 0x0C2B, \"AT system\"  },\r\n    { 0x0C2C, \"Controller Technologies Corporation\"  },\r\n    { 0x0C2D, \"Scientific Data Systems, Inc.\"  },\r\n    { 0x0C2E, \"Honeywell Scanning & Mobility\"  },\r\n    { 0x0C2F, \"Starcover GmbH\"  },\r\n    { 0x0C30, \"MUTOH EUROPE N.V.\"  },\r\n    { 0x0C31, \"Cosmo Techs Co., Ltd.\"  },\r\n    { 0x0C32, \"Weibel Scientific A/S\"  },\r\n    { 0x0C33, \"GN Otometrics A/S\"  },\r\n    { 0x0C34, \"Interisa Electronica\"  },\r\n    { 0x0C35, \"Eagletron Inc.\"  },\r\n    { 0x0C36, \"E INK CORPORATION\"  },\r\n    { 0x0C37, \"e.Digital\"  },\r\n    { 0x0C38, \"Der An Electric Wire & Cable Co. Ltd.\"  },\r\n    { 0x0C39, \"Aeroflex\"  },\r\n    { 0x0C3A, \"Furui Precise Component (Kunshan) Co., Ltd\"  },\r\n    { 0x0C3B, \"Komatsu Ltd.\"  },\r\n    { 0x0C3C, \"Radius Co., Ltd.\"  },\r\n    { 0x0C3D, \"Innocom, Inc.\"  },\r\n    { 0x0C3E, \"NEXTCELL INC.\"  },\r\n    { 0x0C3F, \"Street Smart Security\"  },\r\n    { 0x0C40, \"Navini Networks, Inc\"  },\r\n    { 0x0C41, \"findtheDOT\"  },\r\n    { 0x0C42, \"OMAX Corporation\"  },\r\n    { 0x0C43, \"BIOMETRIKA\"  },\r\n    { 0x0C44, \"Motorola iDEN\"  },\r\n    { 0x0C45, \"Sonix Technology Co., Ltd.\"  },\r\n    { 0x0C46, \"WaveRider Communications, Inc\"  },\r\n    { 0x0C47, \"TECAN Group AG\"  },\r\n    { 0x0C48, \"MARPOSS S.p.A.\"  },\r\n    { 0x0C49, \"Gigahertz-Optik GmbH\"  },\r\n    { 0x0C4A, \"ALGE-TIMING GmbH & Co\"  },\r\n    { 0x0C4B, \"REINER Kartengeraete GmbH & Co.KG\"  },\r\n    { 0x0C4C, \"Needham's Electronics Inc\"  },\r\n    { 0x0C4D, \"ICHIRO.ORG\"  },\r\n    { 0x0C4E, \"Sonic Innovations, Inc.\"  },\r\n    { 0x0C4F, \"01dB-Stell\"  },\r\n    { 0x0C50, \"Forvus Research Inc.\"  },\r\n    { 0x0C51, \"Trax Softworks, Inc.\"  },\r\n    { 0x0C52, \"Sealevel Systems, Inc.\"  },\r\n    { 0x0C53, \"ViewPLUS Inc.\"  },\r\n    { 0x0C54, \"GLORY LTD.\"  },\r\n    { 0x0C55, \"Spectrum Digital Inc.\"  },\r\n    { 0x0C56, \"Billion Bright (HK) Corporation Limited\"  },\r\n    { 0x0C57, \"Imaginative Design Operation Co. Ltd.\"  },\r\n    { 0x0C58, \"Vidar Systems Corporation\"  },\r\n    { 0x0C59, \"Dong Guan Shinko Wire Co., Ltd.\"  },\r\n    { 0x0C5A, \"TRS International Mfg., Inc.\"  },\r\n    { 0x0C5B, \"EDEC Co., Ltd.\"  },\r\n    { 0x0C5C, \"Obbligato Objectives\"  },\r\n    { 0x0C5D, \"Musitronics GmbH\"  },\r\n    { 0x0C5E, \"Xytronix Research & Design\"  },\r\n    { 0x0C5F, \"WAVESYSTEMS\"  },\r\n    { 0x0C60, \"Apogee Electronics Corporation\"  },\r\n    { 0x0C61, \"Network Security Technology Co.\"  },\r\n    { 0x0C62, \"Chant Sincere Co., Ltd\"  },\r\n    { 0x0C63, \"Toko, Inc.\"  },\r\n    { 0x0C64, \"Signality System Engineering Co., Ltd.\"  },\r\n    { 0x0C65, \"Eminence Enterprise Co., Ltd.\"  },\r\n    { 0x0C66, \"REXON ELECTRONICS CORP.\"  },\r\n    { 0x0C67, \"Concept Telecom Ltd\"  },\r\n    { 0x0C68, \"Whanam Electronics Co., Ltd.\"  },\r\n    { 0x0C69, \"COMPUTechnic AG\"  },\r\n    { 0x0C6A, \"Ackerman Computer Sciences\"  },\r\n    { 0x0C6B, \"Spectrum Techniques, Inc\"  },\r\n    { 0x0C6C, \"JETI Technische Instrumente GmbH\"  },\r\n    { 0x0C6D, \"Aardvark\"  },\r\n    { 0x0C6E, \"Zaxus Limited\"  },\r\n    { 0x0C6F, \"SCC Research\"  },\r\n    { 0x0C70, \"MCT Elektronikladen\"  },\r\n    { 0x0C71, \"Fa. Hydrotechnik\"  },\r\n    { 0x0C72, \"PEAK-System-Technik\"  },\r\n    { 0x0C73, \"Omega Well Monitoring\"  },\r\n    { 0x0C74, \"Optronic Laboratories, Inc.\"  },\r\n    { 0x0C75, \"Ripmax Plc\"  },\r\n    { 0x0C76, \"Solid State System Co., Ltd.\"  },\r\n    { 0x0C77, \"SIPIX GROUP LIMITED\"  },\r\n    { 0x0C78, \"Detto Corporation\"  },\r\n    { 0x0C79, \"NuConnex Technologies PTE LTD\"  },\r\n    { 0x0C7A, \"Wing-Span Enterprise Co., Ltd.\"  },\r\n    { 0x0C7B, \"Link Instruments, Inc.\"  },\r\n    { 0x0C7C, \"TMS International BV\"  },\r\n    { 0x0C7E, \"KIRK telecom\"  },\r\n    { 0x0C7F, \"SoftBaugh, Inc.\"  },\r\n    { 0x0C80, \"Optim Electronics\"  },\r\n    { 0x0C81, \"Dragon State Ltd.\"  },\r\n    { 0x0C82, \"Impeccable Instruments, LLC\"  },\r\n    { 0x0C83, \"Cylink\"  },\r\n    { 0x0C84, \"Howell Instruments, Inc.\"  },\r\n    { 0x0C85, \"Lectra Systemes\"  },\r\n    { 0x0C86, \"NDA Technologies, Inc.\"  },\r\n    { 0x0C87, \"Aubit, Ltd.\"  },\r\n    { 0x0C88, \"Kyocera Wireless Inc.\"  },\r\n    { 0x0C89, \"Honda Tsushin Kogyo Co., Ltd\"  },\r\n    { 0x0C8A, \"Cast Lighting Limited\"  },\r\n    { 0x0C8B, \"Wavefly Corporation\"  },\r\n    { 0x0C8C, \"Coactive Networks\"  },\r\n    { 0x0C8D, \"Greenlee Textron, Inc.\"  },\r\n    { 0x0C8E, \"Cesscom Co., Ltd.\"  },\r\n    { 0x0C8F, \"Applied Microsystems\"  },\r\n    { 0x0C90, \"American Arium\"  },\r\n    { 0x0C91, \"FPGA Information\"  },\r\n    { 0x0C92, \"Nixvue Systems PTE LTD\"  },\r\n    { 0x0C93, \"Alara Inc.\"  },\r\n    { 0x0C94, \"SAGEM Denmark\"  },\r\n    { 0x0C95, \"Kyushu-Kyohan Co., Ltd.\"  },\r\n    { 0x0C96, \"TOPCON Positioning Systems\"  },\r\n    { 0x0C97, \"GRE America, Inc.\"  },\r\n    { 0x0C98, \"Berkshire Products, Inc.\"  },\r\n    { 0x0C99, \"Innochips Co., Ltd.\"  },\r\n    { 0x0C9A, \"Hanool Robotics Corp\"  },\r\n    { 0x0C9B, \"Jobin Yvon, Inc.\"  },\r\n    { 0x0C9C, \"Brand Innovators\"  },\r\n    { 0x0C9D, \"DyOcean\"  },\r\n    { 0x0C9E, \"PLEXUS MULTIMEDIA PTE LTD\"  },\r\n    { 0x0C9F, \"Extenex Corporation\"  },\r\n    { 0x0CA0, \"Robert Bosch GmbH - Automotive Aftermarket\"  },\r\n    { 0x0CA1, \"Mentor Engineering, Inc.\"  },\r\n    { 0x0CA2, \"Zyfer\"  },\r\n    { 0x0CA3, \"SEGA CORPORATION\"  },\r\n    { 0x0CA4, \"ST&T INSTRUMENT CORP.\"  },\r\n    { 0x0CA5, \"BAE SYSTEMS CANADA INC.\"  },\r\n    { 0x0CA6, \"Castles Technology Co. Ltd.\"  },\r\n    { 0x0CA7, \"Information Systems Laboratories\"  },\r\n    { 0x0CA8, \"Digital Audio Labs, Inc.\"  },\r\n    { 0x0CA9, \"Institut fuer Rundfunktechnik\"  },\r\n    { 0x0CAA, \"Allied Telesis K.K.\"  },\r\n    { 0x0CAB, \"Melon Technos Co., Ltd.\"  },\r\n    { 0x0CAC, \"NEC Electronics (Europe) GmbH\"  },\r\n    { 0x0CAD, \"Motorola Solutions\"  },\r\n    { 0x0CAE, \"swissvoice ag\"  },\r\n    { 0x0CAF, \"Buslink\"  },\r\n    { 0x0CB0, \"Flying Pig Systems\"  },\r\n    { 0x0CB1, \"Innovonics, Inc.\"  },\r\n    { 0x0CB2, \"Softmark\"  },\r\n    { 0x0CB3, \"FitzSimons Automation\"  },\r\n    { 0x0CB4, \"PalmMicro Communications, Inc.\"  },\r\n    { 0x0CB5, \"Esel International Company Ltd.\"  },\r\n    { 0x0CB6, \"Celestix Networks PTE LTD\"  },\r\n    { 0x0CB7, \"Singatron Enterprise Co. Ltd.\"  },\r\n    { 0x0CB8, \"Opticis Co., Ltd.\"  },\r\n    { 0x0CB9, \"VTECH INFORMATIONS LTD.\"  },\r\n    { 0x0CBA, \"Trust Electronic (Shanghai) Co., Ltd.\"  },\r\n    { 0x0CBB, \"Shanghai Darong Electronics Co., Ltd.\"  },\r\n    { 0x0CBC, \"PALMAX Technology Co., Ltd.\"  },\r\n    { 0x0CBD, \"Pentel Co., Ltd. (Electronics Equipment Div.)\"  },\r\n    { 0x0CBE, \"Keryx Technologies, Inc.\"  },\r\n    { 0x0CBF, \"Union Genius Computer Co., Ltd\"  },\r\n    { 0x0CC0, \"Kuon Yi Industrial Corp.\"  },\r\n    { 0x0CC2, \"Timex Corporation\"  },\r\n    { 0x0CC3, \"Rimage Corporation\"  },\r\n    { 0x0CC4, \"emsys Embedded Systems GmbH\"  },\r\n    { 0x0CC5, \"SENDO\"  },\r\n    { 0x0CC6, \"INTERMAGIC CORP.\"  },\r\n    { 0x0CC7, \"Kontron Medical AG\"  },\r\n    { 0x0CC8, \"Technotools Corporation\"  },\r\n    { 0x0CC9, \"BroadMAX Technologies, Inc.\"  },\r\n    { 0x0CCA, \"Amphenol Corporation\"  },\r\n    { 0x0CCB, \"SKNET CORPORATION LTD.\"  },\r\n    { 0x0CCC, \"DOMEX TECHNOLOGY CORPORATION\"  },\r\n    { 0x0CCD, \"TerraTec Electronic GmbH\"  },\r\n    { 0x0CCE, \"Optical Imaging Inc.\"  },\r\n    { 0x0CCF, \"T&D CORPORATION\"  },\r\n    { 0x0CD0, \"Art Haven 9 Co., Ltd\"  },\r\n    { 0x0CD1, \"Premier Technologies, Inc.\"  },\r\n    { 0x0CD2, \"C-MAP SRL\"  },\r\n    { 0x0CD3, \"Pretorian Manufacturing Ltd\"  },\r\n    { 0x0CD4, \"Amplex\"  },\r\n    { 0x0CD5, \"Colorado Circuitworks, Inc.\"  },\r\n    { 0x0CD6, \"Scheldt & Bachmann GmbH\"  },\r\n    { 0x0CD7, \"NEWCHIP S.r.l.\"  },\r\n    { 0x0CD8, \"JS Digitech, Inc.\"  },\r\n    { 0x0CD9, \"Shin Din Cable Ltd.\"  },\r\n    { 0x0CDA, \"INTERFACE K.K.\"  },\r\n    { 0x0CDB, \"OSMOOZE S.A.\"  },\r\n    { 0x0CDC, \"HIJI HIGH-TECH CO., LTD.\"  },\r\n    { 0x0CDD, \"Fidelica Microsystems, Inc.\"  },\r\n    { 0x0CDE, \"Z-Com INC.\"  },\r\n    { 0x0CDF, \"BUZZ-VC\"  },\r\n    { 0x0CE0, \"ZAPEX Research Ltd.\"  },\r\n    { 0x0CE1, \"Pepperoni Light\"  },\r\n    { 0x0CE2, \"Eltech Solutions Inc.\"  },\r\n    { 0x0CE3, \"MaxVision Corporation\"  },\r\n    { 0x0CE4, \"JOOHONG\"  },\r\n    { 0x0CE5, \"Hemisphere West\"  },\r\n    { 0x0CE6, \"First Silicon Solutions, Inc.\"  },\r\n    { 0x0CE7, \"Bakker IT Services BV\"  },\r\n    { 0x0CE8, \"Interflex Datensysteme GmbH\"  },\r\n    { 0x0CE9, \"Pico Technology Limited\"  },\r\n    { 0x0CEA, \"PRO TECH COMMUNICATIONS INC.\"  },\r\n    { 0x0CEB, \"Sophia Systems Co., Ltd.\"  },\r\n    { 0x0CEC, \"Cyverse Corp.\"  },\r\n    { 0x0CED, \"MAYCOM Audio Systems b.v.\"  },\r\n    { 0x0CEE, \"Gaitmat II\"  },\r\n    { 0x0CEF, \"Contex A/S\"  },\r\n    { 0x0CF0, \"Cadac Electronics plc.\"  },\r\n    { 0x0CF1, \"e-CONN ELECTRONIC CO., LTD.\"  },\r\n    { 0x0CF2, \"ENE Technology Inc.\"  },\r\n    { 0x0CF3, \"Qualcomm Atheros, Inc.\"  },\r\n    { 0x0CF4, \"Fomtex Corporation\"  },\r\n    { 0x0CF5, \"Cellink Co., Ltd.\"  },\r\n    { 0x0CF6, \"Compucable Corporation\"  },\r\n    { 0x0CF7, \"ishoni Networks\"  },\r\n    { 0x0CF8, \"Clarisys Incorporated\"  },\r\n    { 0x0CF9, \"Central System Research Co., Ltd.\"  },\r\n    { 0x0CFA, \"Inviso, Inc.\"  },\r\n    { 0x0CFB, \"SEnergy Corporation\"  },\r\n    { 0x0CFC, \"Konica-Minolta\"  },\r\n    { 0x0CFD, \"Hitex UK Ltd.\"  },\r\n    { 0x0CFE, \"L.J. Technical Systems Ltd.\"  },\r\n    { 0x0CFF, \"SAFA MEDIA CO., LTD.\"  },\r\n    { 0x0D00, \"Polar Instruments Ltd\"  },\r\n    { 0x0D01, \"Red Bird LLC\"  },\r\n    { 0x0D02, \"Vestibular Technolgies\"  },\r\n    { 0x0D03, \"Triad Spectrum Ltd.\"  },\r\n    { 0x0D04, \"Addmaster Corporation\"  },\r\n    { 0x0D05, \"Chung Nam Electronics Co. Ltd.\"  },\r\n    { 0x0D06, \"telos EDV Systementwicklung GmbH\"  },\r\n    { 0x0D07, \"TAUREUS s.r.o.\"  },\r\n    { 0x0D08, \"UTStarcom (Hangzhou) Telecom Co., Ltd\"  },\r\n    { 0x0D09, \"MMELECTRONICS\"  },\r\n    { 0x0D0A, \"Colourfull Creations\"  },\r\n    { 0x0D0B, \"Contemporary Controls\"  },\r\n    { 0x0D0C, \"Astron Electronics Co., Ltd.\"  },\r\n    { 0x0D0D, \"MKNet Corporation\"  },\r\n    { 0x0D0E, \"Hybrid Networks, Inc\"  },\r\n    { 0x0D0F, \"Feng Shin Cable Co. Ltd.\"  },\r\n    { 0x0D10, \"Elastic Networks\"  },\r\n    { 0x0D11, \"Maspro Denkoh Corp.\"  },\r\n    { 0x0D12, \"Hansol Electronics Inc.\"  },\r\n    { 0x0D13, \"BMF CORPORATION\"  },\r\n    { 0x0D14, \"Array Comm, Inc.\"  },\r\n    { 0x0D15, \"OnStream b.v.\"  },\r\n    { 0x0D16, \"Hi-Touch Imaging Technologies Co., Ltd.\"  },\r\n    { 0x0D17, \"NALTEC, Inc.\"  },\r\n    { 0x0D18, \"coaXmedia\"  },\r\n    { 0x0D19, \"Shanghai Hank Connection Co., Ltd.\"  },\r\n    { 0x0D1A, \"COMTECH SYSTEMS, INC\"  },\r\n    { 0x0D1B, \"EC Engineering, LLC\"  },\r\n    { 0x0D1C, \"MACSEMA, INC\"  },\r\n    { 0x0D1D, \"GEMAC mbH\"  },\r\n    { 0x0D1E, \"Eone Inc.\"  },\r\n    { 0x0D1F, \"imc MessSysteme GmbH\"  },\r\n    { 0x0D20, \"Malcom Co., Ltd.\"  },\r\n    { 0x0D22, \"Rojone Pty Ltd\"  },\r\n    { 0x0D23, \"SATAKE USA INC.\"  },\r\n    { 0x0D24, \"Trapper Data AB\"  },\r\n    { 0x0D25, \"PENTTECH Engineering Systems AB\"  },\r\n    { 0x0D26, \"Micro-Vu\"  },\r\n    { 0x0D27, \"CLEARJET GmbH\"  },\r\n    { 0x0D28, \"ARM Ltd\"  },\r\n    { 0x0D29, \"Eng Resource Inc\"  },\r\n    { 0x0D2A, \"FIELDSERVER TECHNOLOGIES\"  },\r\n    { 0x0D2B, \"DAINIPPON SCREEN\"  },\r\n    { 0x0D2C, \"3M Library Systems\"  },\r\n    { 0x0D2D, \"GigaSysNet\"  },\r\n    { 0x0D2E, \"Feedback Instruments Ltd\"  },\r\n    { 0x0D2F, \"Andamiro Co., Ltd.\"  },\r\n    { 0x0D30, \"Vision Electronics Co., Ltd.\"  },\r\n    { 0x0D31, \"Arizona Cooperative Power\"  },\r\n    { 0x0D32, \"Leo Hui Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x0D33, \"AirSpeak Inc.\"  },\r\n    { 0x0D34, \"Moxi Digital, Inc.\"  },\r\n    { 0x0D35, \"Dah Kun Co., Ltd.\"  },\r\n    { 0x0D36, \"Tellabs\"  },\r\n    { 0x0D37, \"PRISM\"  },\r\n    { 0x0D38, \"Nihon Culture-soft Service Co., Ltd.\"  },\r\n    { 0x0D3A, \"Posiflex Technologies, Inc.\"  },\r\n    { 0x0D3B, \"SANYO TECNICA Co., Ltd.\"  },\r\n    { 0x0D3C, \"SRI CABLE TECHNOLOGY LTD.\"  },\r\n    { 0x0D3D, \"TANGTOP TECHNOLOGY CO., LTD.\"  },\r\n    { 0x0D3E, \"Fitcom, inc.\"  },\r\n    { 0x0D3F, \"MTS Systems Corporation\"  },\r\n    { 0x0D40, \"Ascor Inc.\"  },\r\n    { 0x0D41, \"Ta Yun Electronic Technology Co., Ltd.\"  },\r\n    { 0x0D42, \"FULL DER CO., LTD.\"  },\r\n    { 0x0D43, \"iCableSystem Co., Ltd.\"  },\r\n    { 0x0D44, \"AFG Elektronik GmbH\"  },\r\n    { 0x0D45, \"Union Data Corporation\"  },\r\n    { 0x0D46, \"KOBIL Systems GmbH\"  },\r\n    { 0x0D47, \"KOPEK PACIFIC LTD.\"  },\r\n    { 0x0D48, \"PROMETHEAN\"  },\r\n    { 0x0D49, \"Maxtor\"  },\r\n    { 0x0D4A, \"NF Corporation\"  },\r\n    { 0x0D4B, \"Grape Systems Inc.\"  },\r\n    { 0x0D4C, \"TEDAS AG\"  },\r\n    { 0x0D4D, \"Coherent Inc.\"  },\r\n    { 0x0D4E, \"Agere Systems Netherland BV\"  },\r\n    { 0x0D4F, \"EADS AIRBUS FRANCE\"  },\r\n    { 0x0D50, \"Cleware GmbH\"  },\r\n    { 0x0D51, \"Volex (Asia) Pte Ltd\"  },\r\n    { 0x0D52, \"YAMAHA Motor Co., Ltd\"  },\r\n    { 0x0D53, \"HMI Co., Ltd.\"  },\r\n    { 0x0D54, \"HOLON Corporation\"  },\r\n    { 0x0D55, \"ASKA Technologies Inc.\"  },\r\n    { 0x0D56, \"AVLAB Technology, Inc.\"  },\r\n    { 0x0D57, \"SOLOMON Microtech Ltd.\"  },\r\n    { 0x0D59, \"CDS electronics bv\"  },\r\n    { 0x0D5A, \"Hoshino Metal Industries, Ltd.\"  },\r\n    { 0x0D5B, \"LOGIC CORPORATION\"  },\r\n    { 0x0D5C, \"Eumitcom Technology Inc.\"  },\r\n    { 0x0D5D, \"Telesis Technologies, Inc.\"  },\r\n    { 0x0D5E, \"MYACOM LTD\"  },\r\n    { 0x0D5F, \"CSI, Inc.\"  },\r\n    { 0x0D60, \"IVL Technologies Ltd.\"  },\r\n    { 0x0D61, \"MEILU ELECTRONICS (SHENZHEN) CO., LTD.\"  },\r\n    { 0x0D62, \"Darfon Electronics Corp.\"  },\r\n    { 0x0D63, \"Fritz Gegauf AG\"  },\r\n    { 0x0D64, \"DXG Technology Corp.\"  },\r\n    { 0x0D65, \"KMJP CO., LTD.\"  },\r\n    { 0x0D66, \"TMT\"  },\r\n    { 0x0D67, \"Advanet Inc.\"  },\r\n    { 0x0D68, \"Super Link Electronics Co., Ltd.\"  },\r\n    { 0x0D69, \"NSI\"  },\r\n    { 0x0D6A, \"eMegaTech International Corp.\"  },\r\n    { 0x0D6B, \"And-Or Logic\"  },\r\n    { 0x0D6C, \"CANMAX Technology Ltd.\"  },\r\n    { 0x0D6D, \"Mitsubishi Elec. Micro-Computer App. Software Co.\"  },\r\n    { 0x0D6E, \"Forum Trading Ltd. (UK)\"  },\r\n    { 0x0D70, \"Try Computer Co. LTD.\"  },\r\n    { 0x0D71, \"Hirakawa Hewtech Corp.\"  },\r\n    { 0x0D72, \"Winmate Communication Inc.\"  },\r\n    { 0x0D73, \"Hit's Communications INC.\"  },\r\n    { 0x0D74, \"Dreams Come True Co., Ltd.\"  },\r\n    { 0x0D75, \"LET'S Corporation, Ltd.\"  },\r\n    { 0x0D76, \"MFP Korea, Inc.\"  },\r\n    { 0x0D77, \"Power Sentry/Newpoint\"  },\r\n    { 0x0D78, \"Japan Distributor Corporation\"  },\r\n    { 0x0D79, \"Assistive Technology Engineering Lab\"  },\r\n    { 0x0D7A, \"MARX CryptoTech LP\"  },\r\n    { 0x0D7B, \"Wellco Technology Co., Ltd.\"  },\r\n    { 0x0D7C, \"Taiwan Line Tek Electronic Co., Ltd.\"  },\r\n    { 0x0D7D, \"Add-On Technology Co., Ltd.\"  },\r\n    { 0x0D7E, \"American Computer & Digital Components\"  },\r\n    { 0x0D7F, \"Essential Reality LLC\"  },\r\n    { 0x0D80, \"H.R. Silvine Electronics Inc.\"  },\r\n    { 0x0D81, \"TechnoVision\"  },\r\n    { 0x0D83, \"Think Outside, Inc.\"  },\r\n    { 0x0D84, \"ELECTRO-SYSTEM Co., Ltd.\"  },\r\n    { 0x0D85, \"Identix Incorporated\"  },\r\n    { 0x0D86, \"Marconi\"  },\r\n    { 0x0D87, \"Dolby Laboratories Inc.\"  },\r\n    { 0x0D88, \"Miyoshi Corp.\"  },\r\n    { 0x0D89, \"Oz Software\"  },\r\n    { 0x0D8A, \"KING JIM CO., LTD.\"  },\r\n    { 0x0D8B, \"Ascom Telecommunications Ltd.\"  },\r\n    { 0x0D8C, \"C-MEDIA ELECTRONICS INC.\"  },\r\n    { 0x0D8D, \"Promotion & Display Technology Ltd.\"  },\r\n    { 0x0D8E, \"Global Sun Technology Inc.\"  },\r\n    { 0x0D8F, \"Pitney Bowes\"  },\r\n    { 0x0D90, \"Sure-Fire Electrical Corporation\"  },\r\n    { 0x0D91, \"ALPHA PROJECT Co., Ltd.\"  },\r\n    { 0x0D92, \"Mega & Game\"  },\r\n    { 0x0D93, \"Nishitomo Co., Ltd.\"  },\r\n    { 0x0D94, \"Advanced Logic Technology (ALT)\"  },\r\n    { 0x0D95, \"Numonics Corp.\"  },\r\n    { 0x0D96, \"Skanhex Technology Inc.\"  },\r\n    { 0x0D97, \"Santa Barbara Instrument Group (SBIG)\"  },\r\n    { 0x0D98, \"Mars Semiconductor Corp.\"  },\r\n    { 0x0D99, \"Trazer Technologies Inc.\"  },\r\n    { 0x0D9A, \"RTX Telecom A/S\"  },\r\n    { 0x0D9B, \"Tat Shing Electrical Co.\"  },\r\n    { 0x0D9C, \"Chee Chen Hi-Technology Co., Ltd.\"  },\r\n    { 0x0D9D, \"Sanwa Supply Inc\"  },\r\n    { 0x0D9E, \"Avaya\"  },\r\n    { 0x0D9F, \"Powercom Co., Ltd.\"  },\r\n    { 0x0DA0, \"Danger Research\"  },\r\n    { 0x0DA1, \"Suzhou Peter's Precise Industrial Co., Ltd.\"  },\r\n    { 0x0DA2, \"Land Instruments International Ltd.\"  },\r\n    { 0x0DA3, \"Nippon Electro-Sensory Devices Corporation\"  },\r\n    { 0x0DA4, \"POLAR ELECTRO OY\"  },\r\n    { 0x0DA5, \"TOKYO MAGNETIC PRINTING CO., LTD.\"  },\r\n    { 0x0DA6, \"Aimtron Technology Corp.\"  },\r\n    { 0x0DA7, \"IOGEAR, Inc.\"  },\r\n    { 0x0DA8, \"softDSP Co., Ltd.\"  },\r\n    { 0x0DA9, \"DigiLife Technology Inc.\"  },\r\n    { 0x0DAA, \"Derelek\"  },\r\n    { 0x0DAB, \"Diasonic Technology Co., Ltd.\"  },\r\n    { 0x0DAC, \"Smart Card Technology, Inc.\"  },\r\n    { 0x0DAD, \"Westover Scientific\"  },\r\n    { 0x0DAE, \"SERIAL SYSTEM LTD\"  },\r\n    { 0x0DAF, \"NXTV, Inc.\"  },\r\n    { 0x0DB0, \"Micro-Star International Co., Ltd.\"  },\r\n    { 0x0DB1, \"Wen Te Electronics Co., Ltd.\"  },\r\n    { 0x0DB2, \"Shian Hwi Plug Parts, Plastic Factory\"  },\r\n    { 0x0DB3, \"Tekram Technology Co. Ltd.\"  },\r\n    { 0x0DB4, \"Chung Fu Chen Yeh Enterprise Corporation\"  },\r\n    { 0x0DB5, \"Azio Ltd.\"  },\r\n    { 0x0DB6, \"SIMS Valley Co., Ltd.\"  },\r\n    { 0x0DB7, \"ELCON Systemtechnik GmbH\"  },\r\n    { 0x0DB8, \"Garear Taiwan Co., Ltd.\"  },\r\n    { 0x0DB9, \"EMKAY\"  },\r\n    { 0x0DBA, \"DIGIDESIGN\"  },\r\n    { 0x0DBB, \"Luna Analytics, Inc.\"  },\r\n    { 0x0DBC, \"A&D Company, Limited\"  },\r\n    { 0x0DBD, \"Bruker Biospin\"  },\r\n    { 0x0DBE, \"Jiuh Shiuh Precision Industry Co., Ltd.\"  },\r\n    { 0x0DBF, \"Jess-Link International\"  },\r\n    { 0x0DC0, \"G7 Solutions\"  },\r\n    { 0x0DC1, \"Tamagawa Seiki Co., Ltd.\"  },\r\n    { 0x0DC3, \"Athena Smartcard Solutions Inc.\"  },\r\n    { 0x0DC4, \"inXtron, Inc.\"  },\r\n    { 0x0DC5, \"SDK Co, Ltd.\"  },\r\n    { 0x0DC6, \"Precision Squared Technology Corporation\"  },\r\n    { 0x0DC7, \"First Cable Line, Inc.\"  },\r\n    { 0x0DC8, \"WINTEC Corporation\"  },\r\n    { 0x0DC9, \"Arvel Corp.\"  },\r\n    { 0x0DCA, \"SMaL Camera Technologies, Inc.\"  },\r\n    { 0x0DCB, \"RocketPod, Inc.\"  },\r\n    { 0x0DCC, \"Largan Digital\"  },\r\n    { 0x0DCD, \"NetworkFab Corporation\"  },\r\n    { 0x0DCE, \"E-MU Systems, Inc., d.b.a. E-MU/ENSONIQ\"  },\r\n    { 0x0DCF, \"Analytik Jena AG\"  },\r\n    { 0x0DD0, \"Access Solutions\"  },\r\n    { 0x0DD1, \"Contek Electronics Co., Ltd.\"  },\r\n    { 0x0DD2, \"Power Quotient International Co., Ltd.\"  },\r\n    { 0x0DD3, \"MediaQ\"  },\r\n    { 0x0DD4, \"Custom Engineering SPA\"  },\r\n    { 0x0DD5, \"California Micro Devices\"  },\r\n    { 0x0DD6, \"TECHKON GmbH\"  },\r\n    { 0x0DD7, \"KOCOM CO., LTD\"  },\r\n    { 0x0DD8, \"Netac Technology Co., Ltd.\"  },\r\n    { 0x0DD9, \"HighSpeed Surfing\"  },\r\n    { 0x0DDA, \"Integrated Silicon Solution, Inc\"  },\r\n    { 0x0DDB, \"Tamarack Inc.\"  },\r\n    { 0x0DDC, \"Takaotec\"  },\r\n    { 0x0DDD, \"Datelink Technology Co., Ltd.\"  },\r\n    { 0x0DDE, \"UBICOM, INC\"  },\r\n    { 0x0DDF, \"DriveCam Video Systems\"  },\r\n    { 0x0DE1, \"Vidicode Datacommunicatie BV\"  },\r\n    { 0x0DE2, \"Acom Data\"  },\r\n    { 0x0DE3, \"RFTECH CO., LTD.\"  },\r\n    { 0x0DE4, \"Aron Digital Inc.\"  },\r\n    { 0x0DE5, \"Secure2Net, Inc. USA\"  },\r\n    { 0x0DE6, \"Dentsply Int'l - Gendex Dental Division\"  },\r\n    { 0x0DE7, \"USBmicro\"  },\r\n    { 0x0DE8, \"Delsy Electronic Components AG\"  },\r\n    { 0x0DE9, \"Technische Industrie TACX BV\"  },\r\n    { 0x0DEA, \"UTECH Electronic (D.G.) Co., Ltd.\"  },\r\n    { 0x0DEB, \"Lean Horn Co.\"  },\r\n    { 0x0DEC, \"Callserve Communications Ltd.\"  },\r\n    { 0x0DED, \"Novasonics\"  },\r\n    { 0x0DEE, \"Lifetime Memory Products\"  },\r\n    { 0x0DEF, \"Full Rise Electronic Co., Ltd.\"  },\r\n    { 0x0DF0, \"GE Yokogawa Medical Systems, Ltd.\"  },\r\n    { 0x0DF1, \"Envoy Medical Corporation\"  },\r\n    { 0x0DF2, \"Nisshin Electronics Co., Ltd.\"  },\r\n    { 0x0DF3, \"VeriTek Co., Ltd.\"  },\r\n    { 0x0DF4, \"Net & Sys Co., Ltd.\"  },\r\n    { 0x0DF5, \"Yamatake Corporation\"  },\r\n    { 0x0DF6, \"Sitecom Europe B.V.\"  },\r\n    { 0x0DF7, \"Mobile Action Technology Inc.\"  },\r\n    { 0x0DF8, \"Hoya Computer Co., Ltd.\"  },\r\n    { 0x0DF9, \"Nice Fountain Industrial Co., Ltd.\"  },\r\n    { 0x0DFA, \"Toyo Networks & System Integration Co., Ltd.\"  },\r\n    { 0x0DFB, \"Daisy Technology\"  },\r\n    { 0x0DFC, \"General Touch Technology Co., Ltd.\"  },\r\n    { 0x0DFD, \"Suruga Seiki Co., Ltd.\"  },\r\n    { 0x0DFE, \"Interactive Metronome\"  },\r\n    { 0x0DFF, \"Deodeo Corporation\"  },\r\n    { 0x0E00, \"Novar GmbH\"  },\r\n    { 0x0E01, \"Sheng Xiang Investment Ltd.\"  },\r\n    { 0x0E02, \"Doowon Co., LTD\"  },\r\n    { 0x0E03, \"Nippon Systemware Co., Ltd.\"  },\r\n    { 0x0E04, \"PowerCom Technology Co., Ltd.\"  },\r\n    { 0x0E05, \"Nordic ID\"  },\r\n    { 0x0E06, \"Personal Telecom, Inc.\"  },\r\n    { 0x0E07, \"Viewtek Co., Ltd\"  },\r\n    { 0x0E08, \"Winbest Technology Co., Ltd.\"  },\r\n    { 0x0E09, \"Winskon Cabling Specialist Co., Ltd.\"  },\r\n    { 0x0E0A, \"JAEIK Information & Communication Co., Ltd.\"  },\r\n    { 0x0E0B, \"Fujitsu Denso Ltd.\"  },\r\n    { 0x0E0C, \"Gesytec GmbH\"  },\r\n    { 0x0E0D, \"Picoquant GmbH\"  },\r\n    { 0x0E0E, \"Fuji Data System Co., Ltd.\"  },\r\n    { 0x0E0F, \"VMWare, Inc.\"  },\r\n    { 0x0E10, \"TERUMO Corporation (Suruga Factory)\"  },\r\n    { 0x0E11, \"Neurotec\"  },\r\n    { 0x0E12, \"Danam Communications Inc.\"  },\r\n    { 0x0E13, \"Lugh Networks, Inc.\"  },\r\n    { 0x0E14, \"Hunter Engineering Co.\"  },\r\n    { 0x0E15, \"Tellert Elektronik GmbH\"  },\r\n    { 0x0E16, \"JMTEK, LLC\"  },\r\n    { 0x0E17, \"Walex Electronic Ltd.\"  },\r\n    { 0x0E18, \"UNIWIDE Technologies\"  },\r\n    { 0x0E19, \"OeRSTED, Inc.\"  },\r\n    { 0x0E1A, \"RDM Corporation\"  },\r\n    { 0x0E1B, \"Crewave Co., Ltd.\"  },\r\n    { 0x0E1C, \"Beijing Hi-tech Wealth Software Technology Co.\"  },\r\n    { 0x0E1D, \"International Parts & Information Co., Ltd.\"  },\r\n    { 0x0E1E, \"Green Hills Software, Inc.\"  },\r\n    { 0x0E1F, \"Cabin Industrial Co., Ltd.\"  },\r\n    { 0x0E20, \"Pegasus Technologies Ltd.\"  },\r\n    { 0x0E21, \"Cowon Systems, Inc.\"  },\r\n    { 0x0E22, \"Symbian Ltd.\"  },\r\n    { 0x0E23, \"Liou Yuane International Ltd.\"  },\r\n    { 0x0E24, \"Samson Electric Wire Co., Ltd.\"  },\r\n    { 0x0E25, \"VinChip Systems, Inc.\"  },\r\n    { 0x0E26, \"J-Phone East Co., Ltd.\"  },\r\n    { 0x0E27, \"Thunder Island Limited\"  },\r\n    { 0x0E28, \"Industrial Control Systems\"  },\r\n    { 0x0E29, \"CB Sciences, Inc.\"  },\r\n    { 0x0E2A, \"Flight Link Inc.\"  },\r\n    { 0x0E2B, \"Kumamoto Techno Corporation\"  },\r\n    { 0x0E2C, \"Intersoft Electronics N.V.\"  },\r\n    { 0x0E2D, \"SKF Condition Monitoring\"  },\r\n    { 0x0E2E, \"Brady Corporation\"  },\r\n    { 0x0E2F, \"Daisen Electronic Industrial Co., Ltd.\"  },\r\n    { 0x0E30, \"HeartMath LLC\"  },\r\n    { 0x0E31, \"Biosign\"  },\r\n    { 0x0E32, \"ICONAG - Intelligent Control AG\"  },\r\n    { 0x0E33, \"Luna Innovations, Inc.\"  },\r\n    { 0x0E34, \"Micro Computer Control Corp.\"  },\r\n    { 0x0E35, \"3Pea Technologies, Inc.\"  },\r\n    { 0x0E36, \"TiePie engineering\"  },\r\n    { 0x0E37, \"Alpha Data Corp.\"  },\r\n    { 0x0E38, \"Stratitec, Inc.\"  },\r\n    { 0x0E39, \"Smart Modular Technologies, Inc.\"  },\r\n    { 0x0E3A, \"Neostar Technology Co., Ltd.\"  },\r\n    { 0x0E3B, \"Mansella Ltd.\"  },\r\n    { 0x0E3C, \"Raytec Electronic Co., Ltd.\"  },\r\n    { 0x0E3D, \"Metex Corporation\"  },\r\n    { 0x0E3E, \"Good Technology, Inc.\"  },\r\n    { 0x0E3F, \"AM Group Corp.\"  },\r\n    { 0x0E40, \"Proteq LTDA\"  },\r\n    { 0x0E41, \"Line 6, Inc.\"  },\r\n    { 0x0E42, \"Puretek Industrial Co., Ltd.\"  },\r\n    { 0x0E43, \"Holly Lin International Technology Inc.\"  },\r\n    { 0x0E44, \"Sun-Riseful Technology Co., Ltd.\"  },\r\n    { 0x0E45, \"SafeNet B.V.\"  },\r\n    { 0x0E46, \"Delphi Corporation\"  },\r\n    { 0x0E47, \"AMANO Corporation\"  },\r\n    { 0x0E48, \"Julia Corporation Limited\"  },\r\n    { 0x0E49, \"Ingenieurbuero Chanda AG\"  },\r\n    { 0x0E4A, \"Shenzhen Bao Hing Electric Wire & Cable Mfr. Co.\"  },\r\n    { 0x0E4B, \"System General Corp.\"  },\r\n    { 0x0E4C, \"Radica Games Ltd.\"  },\r\n    { 0x0E4D, \"Hong Shi Precision Corp.\"  },\r\n    { 0x0E4E, \"Lih Duo Intl. Co., Ltd.\"  },\r\n    { 0x0E4F, \"Data Ray Corp.\"  },\r\n    { 0x0E50, \"TDi GmbH TechnoData Interware\"  },\r\n    { 0x0E51, \"Therapy Information & Communication System Inc.\"  },\r\n    { 0x0E52, \"Mindready Solutions (NI) Ltd.\"  },\r\n    { 0x0E53, \"King Tester Corporation\"  },\r\n    { 0x0E54, \"KDE, Inc.\"  },\r\n    { 0x0E55, \"Speed Dragon Multimedia Ltd.\"  },\r\n    { 0x0E56, \"Cenix Digicom Co., Ltd.\"  },\r\n    { 0x0E57, \"Loas Co., Ltd\"  },\r\n    { 0x0E58, \"Technology For Energy Corp.\"  },\r\n    { 0x0E59, \"Bourns, Inc.\"  },\r\n    { 0x0E5A, \"ACTIVE CO., LTD.\"  },\r\n    { 0x0E5B, \"Union Power Information Industrial Co., Ltd.\"  },\r\n    { 0x0E5C, \"Shenzhen Bitland Information Technology Co., Ltd.\"  },\r\n    { 0x0E5D, \"Neltron Industrial Co., Ltd.\"  },\r\n    { 0x0E5E, \"Conwise Technology Co., Ltd.\"  },\r\n    { 0x0E5F, \"Entone Technologies\"  },\r\n    { 0x0E60, \"XAVi Technologies Corp.\"  },\r\n    { 0x0E61, \"E-Pen InMotion Inc.\"  },\r\n    { 0x0E62, \"Shandong CVIC Software Engineering Co., Ltd.\"  },\r\n    { 0x0E63, \"SECUREPIA Inc.\"  },\r\n    { 0x0E64, \"Nida Corporation\"  },\r\n    { 0x0E65, \"Skycom Tek Co., Ltd\"  },\r\n    { 0x0E66, \"Hawking Technologies, Inc.\"  },\r\n    { 0x0E67, \"Fossil\"  },\r\n    { 0x0E68, \"Artec\"  },\r\n    { 0x0E69, \"A Global Partner Corporation\"  },\r\n    { 0x0E6A, \"Megawin Technology Co., Ltd.\"  },\r\n    { 0x0E6B, \"DMA Korea Co., Ltd\"  },\r\n    { 0x0E6C, \"E & D Co., Ltd.\"  },\r\n    { 0x0E6D, \"Tenovis Business Communication\"  },\r\n    { 0x0E6E, \"Volvo Car Corporation\"  },\r\n    { 0x0E6F, \"Performance Designed Products, LLC\"  },\r\n    { 0x0E70, \"Tokyo Electronic Industry Co, LTD.\"  },\r\n    { 0x0E71, \"Schwarzer GmbH\"  },\r\n    { 0x0E72, \"Hsi-Chin Electronics Co., Ltd.\"  },\r\n    { 0x0E73, \"MCK Communications, Inc.\"  },\r\n    { 0x0E74, \"Accu-Automation Corp.\"  },\r\n    { 0x0E75, \"TVS Electronics Limited\"  },\r\n    { 0x0E76, \"Seiko S-Yard Co., Ltd\"  },\r\n    { 0x0E77, \"Weinzierl Engineering GmbH\"  },\r\n    { 0x0E78, \"Ascom Powerline Communications Ltd.\"  },\r\n    { 0x0E79, \"ARCHOS SA\"  },\r\n    { 0x0E7A, \"Indocomp Systems Inc.\"  },\r\n    { 0x0E7B, \"On-Tech Industry Co., Ltd.\"  },\r\n    { 0x0E7C, \"Legend Holdings Limited\"  },\r\n    { 0x0E7D, \"Eutectics Inc.\"  },\r\n    { 0x0E7E, \"G.Mate, Inc.\"  },\r\n    { 0x0E7F, \"Keysight Technologies, Inc. - AFM division\"  },\r\n    { 0x0E80, \"GateHouse A/S\"  },\r\n    { 0x0E81, \"System Consultants Co., Ltd.\"  },\r\n    { 0x0E82, \"Ching Tai Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x0E83, \"Shin An Wire & Cable Co.\"  },\r\n    { 0x0E84, \"Elelux International Ltd.\"  },\r\n    { 0x0E85, \"Dynavox Systems LLC\"  },\r\n    { 0x0E86, \"Watthour Engineering Co., Inc.\"  },\r\n    { 0x0E87, \"Internet Security Co., Ltd\"  },\r\n    { 0x0E88, \"ELBIO\"  },\r\n    { 0x0E89, \"PRT Manufacturing Ltd.\"  },\r\n    { 0x0E8A, \"FinePoint Innovations, Inc.\"  },\r\n    { 0x0E8B, \"KAO SHIN PRECISION INDUSTRY CO., LTD.\"  },\r\n    { 0x0E8C, \"Well Force Electronic Co., Ltd\"  },\r\n    { 0x0E8D, \"MediaTek Inc.\"  },\r\n    { 0x0E8E, \"Stuart Tyrrell Developments\"  },\r\n    { 0x0E8F, \"Pansignal Technology Inc.\"  },\r\n    { 0x0E90, \"CRU\"  },\r\n    { 0x0E91, \"VTech Engineering Canada Ltd.\"  },\r\n    { 0x0E92, \"C'S GLORY ENTERPRISE CO., LTD.\"  },\r\n    { 0x0E93, \"eM Technics Co., Ltd.\"  },\r\n    { 0x0E94, \"Sirona Dental Systems GmbH\"  },\r\n    { 0x0E95, \"Future Technology Co., Ltd\"  },\r\n    { 0x0E96, \"APLUX Communications Ltd.\"  },\r\n    { 0x0E97, \"Fingerworks, Inc.\"  },\r\n    { 0x0E98, \"Advanced Analogic Technologies, Inc.\"  },\r\n    { 0x0E99, \"Parallel Dice Co., Ltd.\"  },\r\n    { 0x0E9A, \"TA HSING INDUSTRIES LTD.\"  },\r\n    { 0x0E9B, \"ADTEC CORPORATION\"  },\r\n    { 0x0E9C, \"StreamZap, Inc.\"  },\r\n    { 0x0E9D, \"Hitron Technologies, Inc.\"  },\r\n    { 0x0E9E, \"Japan System Design Co.\"  },\r\n    { 0x0E9F, \"TAMURA CORPORATION\"  },\r\n    { 0x0EA0, \"Ours Technology Inc.\"  },\r\n    { 0x0EA1, \"Infinite Communication Terminals Ltd.\"  },\r\n    { 0x0EA2, \"Triumph Technology Corp.\"  },\r\n    { 0x0EA3, \"Rion Co., Ltd.\"  },\r\n    { 0x0EA4, \"Intelligent Hearing Systems\"  },\r\n    { 0x0EA5, \"DATA SYSTEM TECHNOLOGY CO., LTD.\"  },\r\n    { 0x0EA6, \"Nihon Computer Co., Ltd.\"  },\r\n    { 0x0EA7, \"MSL Enterprises Corp.\"  },\r\n    { 0x0EA8, \"CenDyne, Inc.\"  },\r\n    { 0x0EA9, \"J&J ENGINEERING INC.\"  },\r\n    { 0x0EAA, \"TOKYO SOKKI KENKYUJO CO., LTD.\"  },\r\n    { 0x0EAB, \"Yiso Telecom\"  },\r\n    { 0x0EAC, \"ALCATech GmbH\"  },\r\n    { 0x0EAD, \"HUMAX Co., Ltd.\"  },\r\n    { 0x0EAE, \"Alcon Labs\"  },\r\n    { 0x0EAF, \"Grandex International Corporation\"  },\r\n    { 0x0EB0, \"Amigo Technology Co., Ltd.\"  },\r\n    { 0x0EB1, \"WIS Technologies, Inc.\"  },\r\n    { 0x0EB2, \"Y-S ELECTRONIC CO., LTD.\"  },\r\n    { 0x0EB3, \"Saint Technology Corp.\"  },\r\n    { 0x0EB4, \"IPLAN Inc.\"  },\r\n    { 0x0EB5, \"@pos.com\"  },\r\n    { 0x0EB6, \"GAMEPARK, Inc.\"  },\r\n    { 0x0EB7, \"Endor AG\"  },\r\n    { 0x0EB8, \"Mettler-Toledo (Albstadt) GmbH\"  },\r\n    { 0x0EB9, \"SKY Electronics\"  },\r\n    { 0x0EBA, \"iWOW Connections Pte Ltd\"  },\r\n    { 0x0EBB, \"Thermo Nicolet Corp.\"  },\r\n    { 0x0EBC, \"CHOIS Technology\"  },\r\n    { 0x0EBD, \"Kyowa Electronics Co., Ltd.\"  },\r\n    { 0x0EBE, \"VWEB Corporation\"  },\r\n    { 0x0EBF, \"Omega Technology Inc.\"  },\r\n    { 0x0EC0, \"LHI Technology (China) Co., Ltd.\"  },\r\n    { 0x0EC1, \"ABIT Computer Corporation\"  },\r\n    { 0x0EC2, \"Sweetray Industrial Ltd.\"  },\r\n    { 0x0EC3, \"Axell Corporation\"  },\r\n    { 0x0EC4, \"Ballracing Developments Ltd.\"  },\r\n    { 0x0EC5, \"GT Information System Co., Ltd.\"  },\r\n    { 0x0EC6, \"InnoVISION Multimedia Limited\"  },\r\n    { 0x0EC7, \"Theta Link Corporation\"  },\r\n    { 0x0EC8, \"Mitechno Co., Ltd.\"  },\r\n    { 0x0EC9, \"HemoCue AB\"  },\r\n    { 0x0ECA, \"Mit System Co., Ltd.\"  },\r\n    { 0x0ECB, \"Harman Kardon\"  },\r\n    { 0x0ECC, \"Samsung SDS\"  },\r\n    { 0x0ECD, \"Lite-On IT Corp.\"  },\r\n    { 0x0ECE, \"TaiSol Electronics Co., Ltd.\"  },\r\n    { 0x0ECF, \"Phogenix Imaging, LLC\"  },\r\n    { 0x0ED0, \"LANergy Limited\"  },\r\n    { 0x0ED1, \"Tai Guen Enterprise Co., Ltd.\"  },\r\n    { 0x0ED2, \"Kyoto Micro Computer Co., LTD.\"  },\r\n    { 0x0ED3, \"Wing-Tech Enterprise Co., Ltd.\"  },\r\n    { 0x0ED4, \"Ross Video\"  },\r\n    { 0x0ED5, \"ChronoLogic Pty. Ltd.\"  },\r\n    { 0x0ED6, \"TECHNOS JAPAN Co., LTD.\"  },\r\n    { 0x0ED7, \"COSMODOG, LTD.\"  },\r\n    { 0x0ED8, \"ASAHI SPECTRA CO., LTD.\"  },\r\n    { 0x0ED9, \"Holy Stone Enterprise Co., Ltd.\"  },\r\n    { 0x0EDA, \"NORITAKE ITRON CORPORATION\"  },\r\n    { 0x0EDB, \"AboveTech, Inc.\"  },\r\n    { 0x0EDC, \"GALTRONICS\"  },\r\n    { 0x0EDD, \"KOWA COMPANY, LTD.\"  },\r\n    { 0x0EDE, \"TOD Co., Ltd.\"  },\r\n    { 0x0EDF, \"e-MDT Co., Ltd.\"  },\r\n    { 0x0EE0, \"SHIMA SEIKI MFG., LTD.\"  },\r\n    { 0x0EE1, \"Sarotech Co., Ltd.\"  },\r\n    { 0x0EE2, \"AMI Semiconductor Inc.\"  },\r\n    { 0x0EE3, \"ComTrue Technology Corporation (Taiwan)\"  },\r\n    { 0x0EE4, \"Sunrich Technology (H.K.) Ltd.\"  },\r\n    { 0x0EE5, \"Medical Graphics Corporation\"  },\r\n    { 0x0EE6, \"Takacom Corporation\"  },\r\n    { 0x0EE7, \"Furuno Electric Co., Ltd.\"  },\r\n    { 0x0EE8, \"Triz Communications Group\"  },\r\n    { 0x0EE9, \"JPK Systems Limited\"  },\r\n    { 0x0EEA, \"William Demant Holding A/S\"  },\r\n    { 0x0EEB, \"Design Of Systems On Silicon, S.A. (DS2)\"  },\r\n    { 0x0EEC, \"Tritek Co., Ltd.\"  },\r\n    { 0x0EED, \"CCP Co., Ltd.\"  },\r\n    { 0x0EEE, \"Digital STREAM Technology, Inc.\"  },\r\n    { 0x0EEF, \"eGalax Inc.\"  },\r\n    { 0x0EF0, \"Hitachi Cable, Ltd.\"  },\r\n    { 0x0EF1, \"Aichi Micro Intelligent Corporation\"  },\r\n    { 0x0EF2, \"I/OMAGIC CORPORATION\"  },\r\n    { 0x0EF3, \"Lynn Products, Inc.\"  },\r\n    { 0x0EF4, \"DSI Datotech\"  },\r\n    { 0x0EF5, \"PointChips\"  },\r\n    { 0x0EF6, \"Yield Microelectronics Corp.\"  },\r\n    { 0x0EF7, \"SM Tech Co., Ltd.\"  },\r\n    { 0x0EF8, \"ECT Inc.\"  },\r\n    { 0x0EF9, \"eHome TV, Inc. DBA Fuze3 Technologies\"  },\r\n    { 0x0EFA, \"Corepro Entertainment\"  },\r\n    { 0x0EFB, \"ARKRAY, Inc.\"  },\r\n    { 0x0EFC, \"ELMEX COMPANY Ltd.\"  },\r\n    { 0x0EFD, \"Oasis Semiconductor\"  },\r\n    { 0x0EFE, \"WEM TECHNOLOGY INC.\"  },\r\n    { 0x0EFF, \"CSIRO-TIP\"  },\r\n    { 0x0F00, \"ndd Medizintechnik AG\"  },\r\n    { 0x0F01, \"EXPAN Electronics Co., Ltd.\"  },\r\n    { 0x0F02, \"MobileAria\"  },\r\n    { 0x0F03, \"Jet Power Technology Co., Ltd.\"  },\r\n    { 0x0F04, \"Softlok International Limited\"  },\r\n    { 0x0F05, \"Quanta Network Systems Inc.\"  },\r\n    { 0x0F06, \"Visual Frontier Precision Corp.\"  },\r\n    { 0x0F07, \"Pakon\"  },\r\n    { 0x0F08, \"CSL Wire & Plug (Shen Zhen) Company\"  },\r\n    { 0x0F09, \"Sandel Arionics Inc.\"  },\r\n    { 0x0F0B, \"Great Computer Corporation\"  },\r\n    { 0x0F0C, \"CAS Corporation\"  },\r\n    { 0x0F0D, \"HORI CO., LTD.\"  },\r\n    { 0x0F0E, \"Energyfull & Hi-Top International Ltd.\"  },\r\n    { 0x0F0F, \"NANOPTIX INC.\"  },\r\n    { 0x0F10, \"Personal Information Systems Co., Ltd.\"  },\r\n    { 0x0F11, \"Leybold Didactic GMBH\"  },\r\n    { 0x0F12, \"MARS ENGINEERING CORPORATION\"  },\r\n    { 0x0F13, \"Acetek Technology Co., Ltd.\"  },\r\n    { 0x0F14, \"XIRING\"  },\r\n    { 0x0F15, \"PlayMore Corporation\"  },\r\n    { 0x0F16, \"GLOBAL VIEW CO. LTD.\"  },\r\n    { 0x0F17, \"Correlant Communications\"  },\r\n    { 0x0F18, \"Finger Lakes Instrumentation, LLC\"  },\r\n    { 0x0F19, \"ORACOM CO., Ltd.\"  },\r\n    { 0x0F1A, \"General Information Systems Ltd.\"  },\r\n    { 0x0F1B, \"Onset Computer Corporation\"  },\r\n    { 0x0F1C, \"Funai Electric Co., Ltd.\"  },\r\n    { 0x0F1D, \"Iwill Corporation\"  },\r\n    { 0x0F1E, \"INVAIR Technologies AG\"  },\r\n    { 0x0F1F, \"Laxtha\"  },\r\n    { 0x0F20, \"GENNUM CORPORATION\"  },\r\n    { 0x0F21, \"IOI Technology Corporation\"  },\r\n    { 0x0F22, \"SENIOR INDUSTRIES, INC.\"  },\r\n    { 0x0F23, \"Leader Tech Manufacturer Co., Ltd\"  },\r\n    { 0x0F24, \"FLEX-P INDUSTRIES SDN.BHD.\"  },\r\n    { 0x0F25, \"Primera Technology Inc.\"  },\r\n    { 0x0F26, \"B.G. Technologies, Inc.\"  },\r\n    { 0x0F27, \"Alpes DEIS\"  },\r\n    { 0x0F28, \"ESEC SA\"  },\r\n    { 0x0F29, \"TIPTEL AG\"  },\r\n    { 0x0F2A, \"Marconi Data Systems\"  },\r\n    { 0x0F2B, \"XEMICS SA\"  },\r\n    { 0x0F2D, \"ViPower, Inc.\"  },\r\n    { 0x0F2E, \"Good Man Corporation\"  },\r\n    { 0x0F2F, \"Priva Design Services\"  },\r\n    { 0x0F30, \"Jess Technology Co., Ltd.\"  },\r\n    { 0x0F31, \"Chrysalis Development\"  },\r\n    { 0x0F32, \"YFC-BonEagle Electric Co., Ltd.\"  },\r\n    { 0x0F33, \"Futek Electronics, Co., Ltd.\"  },\r\n    { 0x0F34, \"Hokuto Denshi Co., Ltd.\"  },\r\n    { 0x0F35, \"Kinpo Electronics, Inc.\"  },\r\n    { 0x0F36, \"Philips Medical Systems Ultrasound\"  },\r\n    { 0x0F37, \"Kokuyo Co., Ltd.\"  },\r\n    { 0x0F38, \"Nien-Yi Industrial Corp.\"  },\r\n    { 0x0F39, \"Heng Yu Technology (HK) Ltd.\"  },\r\n    { 0x0F3A, \"Aidensi Giken\"  },\r\n    { 0x0F3B, \"IR-LINK\"  },\r\n    { 0x0F3C, \"Numesa, Inc.\"  },\r\n    { 0x0F3D, \"AirPrime Inc.\"  },\r\n    { 0x0F3E, \"Aastra Broadband\"  },\r\n    { 0x0F3F, \"FEI Electron Optics B.V.\"  },\r\n    { 0x0F40, \"Denver Instrument Company\"  },\r\n    { 0x0F41, \"RDC Semiconductor Co., Ltd.\"  },\r\n    { 0x0F42, \"Nital Consulting Services, Inc.\"  },\r\n    { 0x0F43, \"LiteON Semiconductor Corp.\"  },\r\n    { 0x0F44, \"Polhemus Incorporated\"  },\r\n    { 0x0F45, \"International Road Dynamics\"  },\r\n    { 0x0F46, \"KIHOKU Electronic Co., Ltd.\"  },\r\n    { 0x0F47, \"SN Systems Ltd.\"  },\r\n    { 0x0F48, \"Durand Interstellar, Inc.\"  },\r\n    { 0x0F49, \"Evolis\"  },\r\n    { 0x0F4A, \"Planmeca Oy\"  },\r\n    { 0x0F4B, \"St. John Technology Co., Ltd.\"  },\r\n    { 0x0F4C, \"WORLDWIDE CABLE OPTO CORP.\"  },\r\n    { 0x0F4D, \"Microtune, Inc.\"  },\r\n    { 0x0F4E, \"Freedom Scientific\"  },\r\n    { 0x0F4F, \"INVENTEL\"  },\r\n    { 0x0F50, \"LeadingSpect Corporation\"  },\r\n    { 0x0F51, \"Zeta Broadband Inc.\"  },\r\n    { 0x0F52, \"Wing Kei Electrical Production Ltd.\"  },\r\n    { 0x0F53, \"Taiyo Cable (Dongguan) Co. Ltd.\"  },\r\n    { 0x0F54, \"Kawai Musical Instruments Mfg. Co., Ltd.\"  },\r\n    { 0x0F55, \"AmbiCom, Inc.\"  },\r\n    { 0x0F56, \"SecureTech Corp.\"  },\r\n    { 0x0F57, \"WavePlus Tech. Co., Ltd.\"  },\r\n    { 0x0F58, \"JASCO Corporation\"  },\r\n    { 0x0F59, \"NCI/Newcomb Company, Inc.\"  },\r\n    { 0x0F5A, \"Cogency Semiconductor Inc.\"  },\r\n    { 0x0F5B, \"Ritech International Ltd.\"  },\r\n    { 0x0F5C, \"PRAIRIECOMM, INC.\"  },\r\n    { 0x0F5D, \"NewAge International, LLC\"  },\r\n    { 0x0F5E, \"LEADER ELECTRONICS CORP.\"  },\r\n    { 0x0F5F, \"Key Technology Corporation\"  },\r\n    { 0x0F60, \"GuangZhou Chief Tech Electronic Technology Co. Ltd.\"  },\r\n    { 0x0F61, \"Varian Inc.\"  },\r\n    { 0x0F62, \"Acrox Technologies Co., Ltd.\"  },\r\n    { 0x0F63, \"Leapfrog Enterprises\"  },\r\n    { 0x0F64, \"ZAE Research, Inc.\"  },\r\n    { 0x0F65, \"Dataflex Design Communications Limited\"  },\r\n    { 0x0F66, \"Toshiba Global Commerce Solutions\"  },\r\n    { 0x0F67, \"Quantum3D, Inc.\"  },\r\n    { 0x0F68, \"UQUEST, LTD.\"  },\r\n    { 0x0F69, \"DIONEX CORPORATION\"  },\r\n    { 0x0F6A, \"Vibren Technologies Inc.\"  },\r\n    { 0x0F6B, \"OHM ELECTRIC CO., LTD.\"  },\r\n    { 0x0F6C, \"DnC Tech., Inc.\"  },\r\n    { 0x0F6D, \"WillPoD Co., Ltd.\"  },\r\n    { 0x0F6E, \"INTELLIGENT SYSTEMS CO., LTD.\"  },\r\n    { 0x0F6F, \"Samtec GmbH\"  },\r\n    { 0x0F70, \"YOZAN Inc.\"  },\r\n    { 0x0F71, \"Systems Integration Solutions Inc.\"  },\r\n    { 0x0F72, \"Robert Bosch GmbH - Chassis Systems Control\"  },\r\n    { 0x0F73, \"DFI\"  },\r\n    { 0x0F74, \"KOSUGI GIKEN Co, Ltd.\"  },\r\n    { 0x0F75, \"Future Internet\"  },\r\n    { 0x0F76, \"Vacon Plc\"  },\r\n    { 0x0F77, \"Fasstech\"  },\r\n    { 0x0F78, \"Guntermann & Drunck GmbH\"  },\r\n    { 0x0F79, \"Transonic Systems, Inc.\"  },\r\n    { 0x0F7A, \"EE Tools, Inc.\"  },\r\n    { 0x0F7B, \"Hivertec Inc.\"  },\r\n    { 0x0F7C, \"DQ Technology, Inc.\"  },\r\n    { 0x0F7D, \"NetBotz, Inc.\"  },\r\n    { 0x0F7E, \"Fluke\"  },\r\n    { 0x0F7F, \"Lansmont Corporation\"  },\r\n    { 0x0F80, \"OCULUS Optikgeraete GmbH\"  },\r\n    { 0x0F81, \"DP Computers Pte. Ltd.\"  },\r\n    { 0x0F82, \"IMedia Semiconductor Corporation\"  },\r\n    { 0x0F83, \"Ernst Reiner GmbH & Co. KG\"  },\r\n    { 0x0F84, \"A.E.B. S.R.L.\"  },\r\n    { 0x0F85, \"IDX Company, Ltd.\"  },\r\n    { 0x0F86, \"Cedar Audio Limited\"  },\r\n    { 0x0F87, \"HUMANDATA LTD.\"  },\r\n    { 0x0F88, \"VTech Holdings Ltd.\"  },\r\n    { 0x0F89, \"Leading Edge Co., Ltd.\"  },\r\n    { 0x0F8A, \"Centro De Tecnologia de las Comunicaciones, S.A.\"  },\r\n    { 0x0F8B, \"Yazaki Corporation\"  },\r\n    { 0x0F8C, \"Young Generation International Corp.\"  },\r\n    { 0x0F8D, \"Uniwill Computer Corp.\"  },\r\n    { 0x0F8E, \"Kingnet Technology Co., Ltd.\"  },\r\n    { 0x0F8F, \"SOMA NETWORKS\"  },\r\n    { 0x0F90, \"Quad Engineering Solutions LLC\"  },\r\n    { 0x0F91, \"UNIPULSE Corporation\"  },\r\n    { 0x0F92, \"JASTEC CO., LTD.\"  },\r\n    { 0x0F93, \"Sondex Limited\"  },\r\n    { 0x0F94, \"FALCOM GmbH\"  },\r\n    { 0x0F95, \"TOKYO SOKUSHIN CO., LTD.\"  },\r\n    { 0x0F96, \"NEC-Mitsubishi Electric Visual Systems Corp.\"  },\r\n    { 0x0F97, \"CviLux Corporation\"  },\r\n    { 0x0F98, \"CYBERBANK CORP.\"  },\r\n    { 0x0F99, \"Biopia Co., Ltd.\"  },\r\n    { 0x0F9A, \"Sistel S.R.L.\"  },\r\n    { 0x0F9B, \"G-Card Technology Co., Ltd.\"  },\r\n    { 0x0F9C, \"HYUN WON INC.\"  },\r\n    { 0x0F9D, \"Opteon Corporation\"  },\r\n    { 0x0F9E, \"Lucent Technologies\"  },\r\n    { 0x0F9F, \"Racewood Technology Co., Ltd.\"  },\r\n    { 0x0FA0, \"TRITTON TECHNOLOGIES\"  },\r\n    { 0x0FA1, \"AIJI System Co., Ltd.\"  },\r\n    { 0x0FA2, \"TAG Systems Racing Products, Inc.\"  },\r\n    { 0x0FA3, \"Chief Land Electronic Co., Ltd.\"  },\r\n    { 0x0FA4, \"ATL Technology\"  },\r\n    { 0x0FA5, \"SOTEC CO., LTD.\"  },\r\n    { 0x0FA6, \"CMD AG\"  },\r\n    { 0x0FA7, \"EPOX COMPUTER CO., LTD.\"  },\r\n    { 0x0FA8, \"Logic Controls, Inc.\"  },\r\n    { 0x0FA9, \"Shenzhen Motion Control Technology Co., Ltd.\"  },\r\n    { 0x0FAA, \"Changrime Telecom Co., Ltd.\"  },\r\n    { 0x0FAB, \"ISZ\"  },\r\n    { 0x0FAC, \"Current Stone Co., Ltd.\"  },\r\n    { 0x0FAD, \"Ultravision Ltd.\"  },\r\n    { 0x0FAE, \"Redsun Technology Corp.\"  },\r\n    { 0x0FAF, \"Winpoint Electronic Corp.\"  },\r\n    { 0x0FB0, \"Haurtian Wire & Cable Co., Ltd.\"  },\r\n    { 0x0FB1, \"SuperGate Technologies\"  },\r\n    { 0x0FB2, \"Conteck Co., Ltd.\"  },\r\n    { 0x0FB3, \"SYMAGERY MICROSYSTEMS INC.\"  },\r\n    { 0x0FB4, \"Smiths Detection\"  },\r\n    { 0x0FB5, \"NIHON DENJI SOKKI CO., LTD.\"  },\r\n    { 0x0FB6, \"Heber Ltd.\"  },\r\n    { 0x0FB7, \"East Press Co., Ltd.\"  },\r\n    { 0x0FB8, \"Wistron Corporation\"  },\r\n    { 0x0FB9, \"AACOM CORPORATION\"  },\r\n    { 0x0FBA, \"SAN SHING ELECTRONICS CO., LTD..\"  },\r\n    { 0x0FBB, \"Bitwise Systems, Inc.\"  },\r\n    { 0x0FBC, \"Schick Technologies\"  },\r\n    { 0x0FBD, \"Siblings Investment Inc. (dba vantecusa)\"  },\r\n    { 0x0FBE, \"Applied Diabetes Research, Inc.\"  },\r\n    { 0x0FBF, \"Certifiable Innovations\"  },\r\n    { 0x0FC0, \"NUDIAN ELECTRON CO., LTD.\"  },\r\n    { 0x0FC1, \"MITAC INTERNATIONAL CORP.\"  },\r\n    { 0x0FC2, \"PLUG AND JACK INDUSTRIAL INC.\"  },\r\n    { 0x0FC3, \"BRAINTREE COMMUNICATIONS\"  },\r\n    { 0x0FC4, \"Yamato Electric Industry Co., Ltd.\"  },\r\n    { 0x0FC5, \"Delcom Engineering\"  },\r\n    { 0x0FC6, \"Dataplus Supplies, Inc.\"  },\r\n    { 0x0FC7, \"BES Technology Group\"  },\r\n    { 0x0FC8, \"Phoenix Co., Ltd.\"  },\r\n    { 0x0FC9, \"Tecom Co., Ltd.\"  },\r\n    { 0x0FCA, \"BlackBerry Limited\"  },\r\n    { 0x0FCB, \"Suzuken Co., Ltd.\"  },\r\n    { 0x0FCC, \"Marushin-Denshi Co., Ltd.\"  },\r\n    { 0x0FCD, \"Centurion, Inc.\"  },\r\n    { 0x0FCE, \"Sony Mobile Communications\"  },\r\n    { 0x0FCF, \"Dynastream Innovations Inc.\"  },\r\n    { 0x0FD0, \"2L international B.V.\"  },\r\n    { 0x0FD1, \"Giant Electronics Ltd.\"  },\r\n    { 0x0FD2, \"SEAC BANCHE S.P.A.\"  },\r\n    { 0x0FD3, \"Marconi Applied Technologies Ltd.\"  },\r\n    { 0x0FD4, \"Tenovis GmbH & Co., KG\"  },\r\n    { 0x0FD5, \"Direct Access Technology, Inc.\"  },\r\n    { 0x0FD6, \"Mexmal Mayorista S.A. de C.V.\"  },\r\n    { 0x0FD7, \"Jeulin S.A.\"  },\r\n    { 0x0FD8, \"LARSEN & BRUSGAARD\"  },\r\n    { 0x0FD9, \"El Gato Software LLC\"  },\r\n    { 0x0FDA, \"Quantec Networks GmbH\"  },\r\n    { 0x0FDB, \"Comtech EF Data\"  },\r\n    { 0x0FDC, \"Micro Plus\"  },\r\n    { 0x0FDD, \"Yuyama Mfg. Co., Ltd.\"  },\r\n    { 0x0FDE, \"IDT DATA SYSTEM LIMITED\"  },\r\n    { 0x0FDF, \"Foveon Inc.\"  },\r\n    { 0x0FE0, \"AONEPROTECH Co., Ltd.\"  },\r\n    { 0x0FE1, \"MADWAVES ApS\"  },\r\n    { 0x0FE2, \"Air Techniques, Inc.\"  },\r\n    { 0x0FE3, \"ACCEL CORP.\"  },\r\n    { 0x0FE4, \"IN-TECH ELECTRONICS LIMITED\"  },\r\n    { 0x0FE5, \"TC&C ELECTRONIC CO.,LTD (SUNTECC, INC.)\"  },\r\n    { 0x0FE6, \"Sospita ASA\"  },\r\n    { 0x0FE7, \"Mitutoyo Corporation\"  },\r\n    { 0x0FE8, \"TurboComm Tech. Inc.\"  },\r\n    { 0x0FE9, \"DVICO Inc.\"  },\r\n    { 0x0FEA, \"United Computer Accessories\"  },\r\n    { 0x0FEB, \"CRS ELECTRONIC CO., LTD.\"  },\r\n    { 0x0FEC, \"UMC Electronics Co., Ltd.\"  },\r\n    { 0x0FED, \"ACCESS CO., LTD.\"  },\r\n    { 0x0FEE, \"Xsido Corporation\"  },\r\n    { 0x0FEF, \"MJ RESEARCH, INC.\"  },\r\n    { 0x0FF0, \"Physical Electronics\"  },\r\n    { 0x0FF1, \"Minato Electronics, Inc.\"  },\r\n    { 0x0FF2, \"EZMAX CO., LTD.\"  },\r\n    { 0x0FF3, \"Dimentor\"  },\r\n    { 0x0FF4, \"POLYMATECH CO., LTD.\"  },\r\n    { 0x0FF5, \"OYO-ELECTRIC CO., LTD.\"  },\r\n    { 0x0FF6, \"Core Valley Co., Ltd.\"  },\r\n    { 0x0FF7, \"CHI SHING COMPUTER ACCESSORIES CO., LTD.\"  },\r\n    { 0x0FF8, \"iXs Research Corporation\"  },\r\n    { 0x0FF9, \"FHC., Inc. Frederick Haer & Co.\"  },\r\n    { 0x0FFA, \"ELENTEC CO., LTD.\"  },\r\n    { 0x0FFB, \"Avail Corporation\"  },\r\n    { 0x0FFC, \"Clavia Digital Musical Instruments AB\"  },\r\n    { 0x0FFD, \"AKATSUKI ELECTRIC MFG. CO., LTD.\"  },\r\n    { 0x0FFE, \"ASKA Corporation\"  },\r\n    { 0x0FFF, \"Aopen Inc.\"  },\r\n    { 0x1000, \"Speed Tech Corp.\"  },\r\n    { 0x1001, \"Ritronics Components (S) Pte. Ltd.\"  },\r\n    { 0x1002, \"Spa Design Ltd.\"  },\r\n    { 0x1003, \"SIGMA CORPORATION\"  },\r\n    { 0x1004, \"LG Electronics Inc.\"  },\r\n    { 0x1005, \"Apacer Technology Inc.\"  },\r\n    { 0x1006, \"Reign Com Ltd.\"  },\r\n    { 0x1007, \"Samphone Electronic Co., Ltd.\"  },\r\n    { 0x1008, \"Futaba Corporation\"  },\r\n    { 0x1009, \"Lumanate, Inc.\"  },\r\n    { 0x100A, \"AVC Technology\"  },\r\n    { 0x100B, \"Chou Chin Industrial Co., Ltd.\"  },\r\n    { 0x100C, \"eMachines, inc\"  },\r\n    { 0x100D, \"NETOPIA, INC.\"  },\r\n    { 0x100E, \"North American Pacific Industries, Corp.\"  },\r\n    { 0x100F, \"Trek Inc.\"  },\r\n    { 0x1010, \"FUKUDA DENSHI CO., LTD.\"  },\r\n    { 0x1011, \"Mobile Media Tech.\"  },\r\n    { 0x1012, \"SDKM Fibres, Wires & Cables Berhad\"  },\r\n    { 0x1013, \"TST-Touchless Sensor Technology AG\"  },\r\n    { 0x1014, \"Densitron Technologies PLC\"  },\r\n    { 0x1015, \"Softronics Pty. Ltd.\"  },\r\n    { 0x1016, \"Xiamen Hung's Enterprise Co., Ltd.\"  },\r\n    { 0x1017, \"SPEEDY INDUSTRIAL SUPPLIES PTE. LTD.\"  },\r\n    { 0x1018, \"Mindtell Inc.\"  },\r\n    { 0x1019, \"Fostex Corporation\"  },\r\n    { 0x101A, \"Annecy Electronique\"  },\r\n    { 0x101B, \"Digital Innovations\"  },\r\n    { 0x101C, \"Teradyne Diagnostic Solutions Ltd.\"  },\r\n    { 0x101D, \"Aerospace Information Corporation Limited\"  },\r\n    { 0x101E, \"Fronius International GmbH\"  },\r\n    { 0x101F, \"Pocketec\"  },\r\n    { 0x1020, \"Paten Wireless Technology Inc.\"  },\r\n    { 0x1021, \"Time Management, Inc.\"  },\r\n    { 0x1022, \"Shinko Shoji Co., Ltd.\"  },\r\n    { 0x1023, \"CHRONIX Inc.\"  },\r\n    { 0x1024, \"ASEC CO., LTD.\"  },\r\n    { 0x1025, \"Technology Testing Lab\"  },\r\n    { 0x1026, \"Newly Corporation\"  },\r\n    { 0x1027, \"Time Domain\"  },\r\n    { 0x1028, \"Inovys Corporation\"  },\r\n    { 0x1029, \"Atlantic Coast Telesys\"  },\r\n    { 0x102A, \"RAMOS Technology Co., Ltd.\"  },\r\n    { 0x102B, \"Infotronic America, Inc.\"  },\r\n    { 0x102C, \"Etoms Electronics Corp.\"  },\r\n    { 0x102D, \"Winic Corporation\"  },\r\n    { 0x102E, \"Binstead Systems Ltd.\"  },\r\n    { 0x102F, \"WENZHOU YIHUA CONNECTOR CO.,LTD.\"  },\r\n    { 0x1030, \"Asoka USA Corporation\"  },\r\n    { 0x1031, \"Comax Technology Inc.\"  },\r\n    { 0x1032, \"C-One Technology Corp.\"  },\r\n    { 0x1033, \"Nucam Corporation\"  },\r\n    { 0x1034, \"Teramecs Co., Ltd.\"  },\r\n    { 0x1035, \"Cyber Solid Laboratory\"  },\r\n    { 0x1036, \"ELLAB A/S\"  },\r\n    { 0x1037, \"Red Lion Controls LP\"  },\r\n    { 0x1038, \"SteelSeries ApS\"  },\r\n    { 0x1039, \"devolo AG\"  },\r\n    { 0x103A, \"I+ME ACTIA GmbH\"  },\r\n    { 0x103B, \"Quatographic AG\"  },\r\n    { 0x103C, \"AMX Corp.\"  },\r\n    { 0x103D, \"Stanton Magnetics, Inc.\"  },\r\n    { 0x103E, \"Thurlby-Thandar Instruments Ltd.\"  },\r\n    { 0x103F, \"Tectech inc.\"  },\r\n    { 0x1040, \"Valiant Technology Ltd.\"  },\r\n    { 0x1041, \"Kongsberg Defence Communications AS\"  },\r\n    { 0x1042, \"CARDIO SISTEMAS COML. INDL. LTDA.\"  },\r\n    { 0x1043, \"iCreate Technologies Corporation\"  },\r\n    { 0x1044, \"Chu Yuen Enterprise Co., Ltd.\"  },\r\n    { 0x1045, \"Transiciel Technologies\"  },\r\n    { 0x1046, \"Hitachi Asahi Electronics Co., Ltd.\"  },\r\n    { 0x1047, \"HOYA CORPORATION Vision Care Company\"  },\r\n    { 0x1048, \"Targus International LLC\"  },\r\n    { 0x1049, \"Studio Technologies, Inc.\"  },\r\n    { 0x104A, \"WACOH Corporation\"  },\r\n    { 0x104B, \"CSM GmbH\"  },\r\n    { 0x104C, \"AMCO TEC International Inc.\"  },\r\n    { 0x104D, \"Newport Corporation\"  },\r\n    { 0x104E, \"Halliburton Energy Services\"  },\r\n    { 0x104F, \"W B Electronics\"  },\r\n    { 0x1050, \"Yubico AB\"  },\r\n    { 0x1051, \"Nippon Printer Engineering Inc.\"  },\r\n    { 0x1052, \"U-Medica Inc.\"  },\r\n    { 0x1053, \"Immanuel Electronics Co., Ltd.\"  },\r\n    { 0x1054, \"BMS International Beheer N.V.\"  },\r\n    { 0x1055, \"Complex Micro Interconnection Co., Ltd.\"  },\r\n    { 0x1056, \"Hsin Chen Ent Co., Ltd.\"  },\r\n    { 0x1057, \"ON Semiconductor\"  },\r\n    { 0x1058, \"Western Digital, Branded\"  },\r\n    { 0x1059, \"Giesecke & Devrient GmbH\"  },\r\n    { 0x105A, \"DDS, Inc.\"  },\r\n    { 0x105B, \"TOKIWA WEST Co., Ltd.\"  },\r\n    { 0x105C, \"Freeway Electronic Wire & Cable (Dongguan) Co., Ltd.\"  },\r\n    { 0x105D, \"Delkin Devices, Inc.\"  },\r\n    { 0x105E, \"Valence Semiconductor Design Limited\"  },\r\n    { 0x105F, \"Chin Shong Enterprise Co., Ltd.\"  },\r\n    { 0x1060, \"Easthome Industrial Co., Ltd.\"  },\r\n    { 0x1061, \"Cardinal Components Inc.\"  },\r\n    { 0x1062, \"Sumitomo Electric Industries, Ltd.\"  },\r\n    { 0x1063, \"LPKF Laser & Electronics AG\"  },\r\n    { 0x1064, \"INNOPLUS Co., Ltd.\"  },\r\n    { 0x1065, \"ImageQuest Co., Ltd.\"  },\r\n    { 0x1066, \"Eten Information Systems Co., Ltd.\"  },\r\n    { 0x1067, \"L-3 Communications\"  },\r\n    { 0x1068, \"Micropi Elettronica\"  },\r\n    { 0x1069, \"Easy Digital Concept\"  },\r\n    { 0x106A, \"Loyal Legend Limited\"  },\r\n    { 0x106B, \"MED Associates Inc. , sue@med-associates.com\"  },\r\n    { 0x106C, \"Curitel Communications, Inc.\"  },\r\n    { 0x106D, \"San Chieh Manufacturing Ltd.\"  },\r\n    { 0x106E, \"ConectL\"  },\r\n    { 0x106F, \"Money Controls\"  },\r\n    { 0x1070, \"TAKAMISAWA CYBERNETICS CO., LTD.\"  },\r\n    { 0x1071, \"Paxton Access Ltd.\"  },\r\n    { 0x1072, \"FDI Matelec\"  },\r\n    { 0x1073, \"Lifetron Co., Ltd.\"  },\r\n    { 0x1074, \"TECHNO SOFT SYSTEMNICS INC.\"  },\r\n    { 0x1075, \"TOKYO KEIKI INC.\"  },\r\n    { 0x1076, \"GCT Semiconductor, Inc.\"  },\r\n    { 0x1077, \"VoiceBox Technologies Inc.\"  },\r\n    { 0x1078, \"Maycom Co., Ltd.\"  },\r\n    { 0x1079, \"Suisei Electronics System Co., Ltd.\"  },\r\n    { 0x107A, \"Optionexist Limited\"  },\r\n    { 0x107B, \"X E Systems Inc.\"  },\r\n    { 0x107C, \"Whelen Engineering Company Inc.\"  },\r\n    { 0x107D, \"Arlec Australia Limited\"  },\r\n    { 0x107E, \"MIDORIYA ELECTRIC CO., LTD.\"  },\r\n    { 0x107F, \"KidzMouse, Inc.\"  },\r\n    { 0x1080, \"Musetel Co., Ltd.\"  },\r\n    { 0x1081, \"VG Electracon, Inc.\"  },\r\n    { 0x1082, \"Shin-Etsukaken Co., Ltd.\"  },\r\n    { 0x1083, \"CANON ELECTRONICS INC.\"  },\r\n    { 0x1084, \"PANTECH CO., LTD.\"  },\r\n    { 0x1085, \"Datalaster\"  },\r\n    { 0x1086, \"Smart System Inc.\"  },\r\n    { 0x1087, \"Shanghai Ewaytek Co., Ltd.\"  },\r\n    { 0x1088, \"Archtek Telecom Co.\"  },\r\n    { 0x1089, \"On Track Innovations Ltd.\"  },\r\n    { 0x108A, \"Chloride Power Protection\"  },\r\n    { 0x108B, \"Grand-tek Technology Co., Ltd.\"  },\r\n    { 0x108C, \"Robert Bosch GmbH\"  },\r\n    { 0x108D, \"Mitsui Zosen Systems Research Inc.\"  },\r\n    { 0x108E, \"Lotes Co., Ltd.\"  },\r\n    { 0x108F, \"HIOKI E.E. CORPORATION\"  },\r\n    { 0x1090, \"DSP Research Inc.\"  },\r\n    { 0x1091, \"DR. JOHANNES HEIDENHAIN GmbH\"  },\r\n    { 0x1092, \"TOPDEK Semiconductor Inc.\"  },\r\n    { 0x1093, \"SongPro, Inc.\"  },\r\n    { 0x1094, \"NextEngine, Inc.\"  },\r\n    { 0x1095, \"Good Work Systems\"  },\r\n    { 0x1096, \"NIO Corporation\"  },\r\n    { 0x1097, \"Computational Systems Incorporated\"  },\r\n    { 0x1098, \"Raytek Corp.\"  },\r\n    { 0x1099, \"Surface Optics Corporation\"  },\r\n    { 0x109A, \"DATASOFT Systems GmbH\"  },\r\n    { 0x109B, \"Qingdao Hisense Communication Co., Ltd.\"  },\r\n    { 0x109C, \"Electronic Trade Solutions Ltd.\"  },\r\n    { 0x109D, \"NAVIUS CO., LTD.\"  },\r\n    { 0x109E, \"Finger System Inc.\"  },\r\n    { 0x109F, \"eSOL Co., Ltd.\"  },\r\n    { 0x10A0, \"HIROTECH, INC.\"  },\r\n    { 0x10A1, \"target-systemelectronic gmbh\"  },\r\n    { 0x10A2, \"HYUNDAI NETWORKS, INC.\"  },\r\n    { 0x10A3, \"MITSUBISHI MATERIALS CORPORATION\"  },\r\n    { 0x10A4, \"Frontier Silicon Ltd.\"  },\r\n    { 0x10A5, \"FINGERPRINT CARDS AB\"  },\r\n    { 0x10A6, \"SKYUP TECHNOLOGY CORPORATION\"  },\r\n    { 0x10A7, \"3i techs Development Corp\"  },\r\n    { 0x10A8, \"Imaging Devices, Inc.\"  },\r\n    { 0x10A9, \"SK Teletech Co., Ltd.\"  },\r\n    { 0x10AA, \"Cables To Go\"  },\r\n    { 0x10AB, \"Universal Global Scientific Industrial Co., Ltd.\"  },\r\n    { 0x10AC, \"Honeywell, Inc.\"  },\r\n    { 0x10AD, \"Impact Instrumentation Inc.\"  },\r\n    { 0x10AE, \"Princeton Technology Corp.\"  },\r\n    { 0x10AF, \"Liebert Corporation\"  },\r\n    { 0x10B0, \"IPmental Inc.\"  },\r\n    { 0x10B1, \"Safe Valley Inc.\"  },\r\n    { 0x10B2, \"Data East Corporation\"  },\r\n    { 0x10B3, \"Roke Manor Research Limited\"  },\r\n    { 0x10B4, \"Guardtec, Inc.\"  },\r\n    { 0x10B5, \"Comodo\"  },\r\n    { 0x10B6, \"Dynojet Research, Inc.\"  },\r\n    { 0x10B7, \"VSM Medtech Ltd.\"  },\r\n    { 0x10B8, \"DIBCOM\"  },\r\n    { 0x10B9, \"Prime Electronics & Satellitics, Inc.\"  },\r\n    { 0x10BA, \"Dong-Guan Sintai Optical Co., Ltd.\"  },\r\n    { 0x10BB, \"TM Technology Inc.\"  },\r\n    { 0x10BC, \"Dinging Technology Co., Ltd.\"  },\r\n    { 0x10BD, \"TMT TECHNOLOGY, INC.\"  },\r\n    { 0x10BE, \"KBM Electronic System Design\"  },\r\n    { 0x10BF, \"Smarthome\"  },\r\n    { 0x10C0, \"SougaSoft Co., Ltd.\"  },\r\n    { 0x10C1, \"Kyokuto Electric Co., Ltd.\"  },\r\n    { 0x10C2, \"Phasespace, Inc.\"  },\r\n    { 0x10C3, \"Universal Laser Systems\"  },\r\n    { 0x10C4, \"Silicon Laboratories, Inc.\"  },\r\n    { 0x10C5, \"Sanei Electric Inc.\"  },\r\n    { 0x10C6, \"Intec, Inc.\"  },\r\n    { 0x10C7, \"Touchstone Technology Co., Ltd.\"  },\r\n    { 0x10C8, \"SIGMACOM CO., LTD.\"  },\r\n    { 0x10C9, \"ZUKEN Inc.\"  },\r\n    { 0x10CA, \"Xrosstech, Inc.\"  },\r\n    { 0x10CB, \"eratech\"  },\r\n    { 0x10CC, \"GBM Connector Co., Ltd.\"  },\r\n    { 0x10CD, \"Kycon Inc.\"  },\r\n    { 0x10CE, \"Shinko Electric Co., Ltd.\"  },\r\n    { 0x10CF, \"Velleman Components\"  },\r\n    { 0x10D0, \"Tokai University Educational System\"  },\r\n    { 0x10D1, \"HBM GmbH\"  },\r\n    { 0x10D2, \"Adams IT Services\"  },\r\n    { 0x10D3, \"Trimos SA\"  },\r\n    { 0x10D4, \"Man Boon Manufactory Ltd.\"  },\r\n    { 0x10D5, \"Uni Class Technology Co., Ltd.\"  },\r\n    { 0x10D6, \"Actions Semiconductor Co., Ltd.\"  },\r\n    { 0x10D7, \"Array Corporation\"  },\r\n    { 0x10D8, \"ACTIKEY S.A.\"  },\r\n    { 0x10D9, \"Tecnova Corporation\"  },\r\n    { 0x10DA, \"HOWTEL CO., LTD.\"  },\r\n    { 0x10DB, \"Prior Scientific Instruments Ltd.\"  },\r\n    { 0x10DC, \"Evolve Communications\"  },\r\n    { 0x10DD, \"VerNova, Inc.\"  },\r\n    { 0x10DE, \"Authenex, Inc.\"  },\r\n    { 0x10DF, \"In-Win Development Inc.\"  },\r\n    { 0x10E0, \"Bella Corporation\"  },\r\n    { 0x10E1, \"CABLEPLUS LTD.\"  },\r\n    { 0x10E2, \"Nada Electronics, Ltd.\"  },\r\n    { 0x10E3, \"tec5 AG\"  },\r\n    { 0x10E4, \"Trans-Lux Corporation & Subsidiaries\"  },\r\n    { 0x10E5, \"MACTek\"  },\r\n    { 0x10E6, \"Altotec Hard- und Software GmbH\"  },\r\n    { 0x10E7, \"dSPACE GmbH\"  },\r\n    { 0x10E8, \"Kumahira Co., Ltd.\"  },\r\n    { 0x10E9, \"XIA LLC\"  },\r\n    { 0x10EA, \"ELITRONIC s.r.o.\"  },\r\n    { 0x10EB, \"FREEBOX SA\"  },\r\n    { 0x10EC, \"Vast Technologies Inc.\"  },\r\n    { 0x10ED, \"KDS USA, Inc.\"  },\r\n    { 0x10EE, \"Compuprint\"  },\r\n    { 0x10EF, \"Integrity Instruments Inc.\"  },\r\n    { 0x10F0, \"Etronics Corp.\"  },\r\n    { 0x10F1, \"Inventec Multimedia & Telecom Corp.\"  },\r\n    { 0x10F2, \"Autonics Co., Ltd.\"  },\r\n    { 0x10F3, \"Vercel Development Inc.\"  },\r\n    { 0x10F4, \"INcoder Technology CO., Ltd.\"  },\r\n    { 0x10F5, \"Voyetra Turtle Beach, Inc.\"  },\r\n    { 0x10F6, \"IMAGENICS Co., Ltd.\"  },\r\n    { 0x10F7, \"Hando Computer Co., Ltd\"  },\r\n    { 0x10F8, \"CESYS GmbH\"  },\r\n    { 0x10F9, \"NSD Corporation\"  },\r\n    { 0x10FA, \"CHINO Corporation\"  },\r\n    { 0x10FB, \"Pictos Technologies, Inc.\"  },\r\n    { 0x10FC, \"MICRELEC\"  },\r\n    { 0x10FD, \"Animation Technologies Inc.\"  },\r\n    { 0x10FE, \"Thrane & Thrane A/S\"  },\r\n    { 0x10FF, \"Bellwave\"  },\r\n    { 0x1100, \"VirTouch Ltd.\"  },\r\n    { 0x1101, \"EASYPASS INDUSTRIAL CO., LTD.\"  },\r\n    { 0x1102, \"Instrument Systems GmbH\"  },\r\n    { 0x1103, \"Brain Products GmbH\"  },\r\n    { 0x1104, \"TOA Corporation\"  },\r\n    { 0x1105, \"MAP Medizin-Technologie GmbH\"  },\r\n    { 0x1106, \"OrangeHouse Co., Ltd.\"  },\r\n    { 0x1107, \"CreamWare GmbH\"  },\r\n    { 0x1108, \"BRIGHTCOM TECHNOLOGIES LTD.\"  },\r\n    { 0x1109, \"LG Industrial Systems Co., Ltd.\"  },\r\n    { 0x110A, \"Moxa Inc.\"  },\r\n    { 0x110B, \"NAKI INTERNATIONAL\"  },\r\n    { 0x110C, \"Computer Network Technology\"  },\r\n    { 0x110D, \"Hitachi Car Engineering Co., Ltd.\"  },\r\n    { 0x110E, \"Innotrac Diagnostics OY\"  },\r\n    { 0x110F, \"OneVision Corporation\"  },\r\n    { 0x1110, \"Analog Devices Canada Ltd.\"  },\r\n    { 0x1111, \"Siemens Healthcare Diagnostics Inc.\"  },\r\n    { 0x1112, \"Golden Bright (Sichuan) Electronic Technology Co Ltd\"  },\r\n    { 0x1113, \"Medion AG\"  },\r\n    { 0x1114, \"Psion Teklogix Inc.\"  },\r\n    { 0x1115, \"Data Link Co., Ltd.\"  },\r\n    { 0x1116, \"Compro Technology Inc.\"  },\r\n    { 0x1117, \"11 WAVE TECHNOLOGY, INC.\"  },\r\n    { 0x1118, \"MotoSAT\"  },\r\n    { 0x1119, \"GCS General Control Systems GmbH\"  },\r\n    { 0x111A, \"The Nippon Signal Co., Ltd.\"  },\r\n    { 0x111B, \"Kyusyu Ten Ltd.\"  },\r\n    { 0x111C, \"point electronic GmbH\"  },\r\n    { 0x111D, \"Centon Electronics\"  },\r\n    { 0x111E, \"VSO ELECTRONICS CO., LTD.\"  },\r\n    { 0x111F, \"BANCOR S.R.L.\"  },\r\n    { 0x1120, \"Voipac, s.r.o.\"  },\r\n    { 0x1121, \"Kore Technology Limited\"  },\r\n    { 0x1122, \"Klein & Melgert Developments B.V.\"  },\r\n    { 0x1123, \"Hi-Tech Instruments, Inc.\"  },\r\n    { 0x1124, \"REnex Technology Limited\"  },\r\n    { 0x1125, \"Industrial Computing Ltd.\"  },\r\n    { 0x1126, \"Protonic - Holland\"  },\r\n    { 0x1127, \"BANK25 Co., Ltd.\"  },\r\n    { 0x1128, \"STEAG ETA-Optik GmbH\"  },\r\n    { 0x1129, \"Jung Myung Telecom Co., Ltd.\"  },\r\n    { 0x112A, \"RedRat Ltd.\"  },\r\n    { 0x112B, \"Stenograph L.L.C.\"  },\r\n    { 0x112C, \"Ethics Organization of Computer Software\"  },\r\n    { 0x112D, \"SYSMEX CORPORATION\"  },\r\n    { 0x112E, \"Master Hill Electric Wire and Cable Co., Ltd.\"  },\r\n    { 0x112F, \"Cellon International\"  },\r\n    { 0x1130, \"Tenx Technology, Inc.\"  },\r\n    { 0x1131, \"Integrated System Solution Corp.\"  },\r\n    { 0x1132, \"Visoduck discount GmbH\"  },\r\n    { 0x1133, \"Sanei Electric Co., Ltd.\"  },\r\n    { 0x1134, \"Tri-L Data Systems, Inc.\"  },\r\n    { 0x1135, \"imo-elektronik GmbH\"  },\r\n    { 0x1136, \"CTS ELECTRONICS\"  },\r\n    { 0x1137, \"Beyond LSI, Inc.\"  },\r\n    { 0x1138, \"Greenwood Engineering A/S\"  },\r\n    { 0x1139, \"Wavetrend\"  },\r\n    { 0x113B, \"Hana Micron, Inc.\"  },\r\n    { 0x113C, \"Arintech Co., Ltd.\"  },\r\n    { 0x113D, \"Mapower Electronics Co. Ltd.\"  },\r\n    { 0x113E, \"KDK Electric Wire (H.K.) Co., Ltd.\"  },\r\n    { 0x113F, \"Integrated Biometrics\"  },\r\n    { 0x1140, \"Ultra-Scan Corporation\"  },\r\n    { 0x1141, \"V ONE MULTIMEDIA PTE LTD\"  },\r\n    { 0x1142, \"CYBERSCAN TECH. INC.\"  },\r\n    { 0x1143, \"Wako Pure Chemical Industries, Ltd..\"  },\r\n    { 0x1144, \"MURATA MACHINERY, LTD.\"  },\r\n    { 0x1145, \"Japan Radio Co., Ltd.\"  },\r\n    { 0x1146, \"Shimane SANYO Electric Co., Ltd.\"  },\r\n    { 0x1147, \"Ever Great Electric Wire and Cable Co., Ltd.\"  },\r\n    { 0x1148, \"KGS Corporation\"  },\r\n    { 0x1149, \"TAMA TECH LAB CORP.\"  },\r\n    { 0x114A, \"TANITA Corporation (1)\"  },\r\n    { 0x114B, \"Sphairon Technologies GmbH\"  },\r\n    { 0x114C, \"Tinius Olsen Testing Machine Co., Inc.\"  },\r\n    { 0x114D, \"Alpha Imaging Technology Corp.\"  },\r\n    { 0x114E, \"Digital Electronics Corporation\"  },\r\n    { 0x114F, \"WAVECOM\"  },\r\n    { 0x1150, \"Don Alan Pty. Ltd.\"  },\r\n    { 0x1151, \"World Wide Licenses Limited\"  },\r\n    { 0x1152, \"Codonics, Inc.\"  },\r\n    { 0x1153, \"Tritec Co., Ltd.\"  },\r\n    { 0x1154, \"BEB Industrie-Elektronik AG\"  },\r\n    { 0x1155, \"DICESVA S.L.\"  },\r\n    { 0x1156, \"Cybertech bv\"  },\r\n    { 0x1157, \"EKS Oy\"  },\r\n    { 0x1158, \"Syn-Tech Systems Inc.\"  },\r\n    { 0x1159, \"Micro Application Laboratory Corp.\"  },\r\n    { 0x115A, \"Extreme Speed\"  },\r\n    { 0x115B, \"Salix Technology Co., Ltd.\"  },\r\n    { 0x115C, \"CORESMA\"  },\r\n    { 0x115D, \"ADTEK SYSTEM SCIENCE CO., LTD.\"  },\r\n    { 0x115E, \"Group Sense Ltd.\"  },\r\n    { 0x115F, \"Dataring Systems\"  },\r\n    { 0x1160, \"Invocon, Inc.\"  },\r\n    { 0x1161, \"Port Denshi Co., Ltd.\"  },\r\n    { 0x1162, \"Secugen Corporation\"  },\r\n    { 0x1163, \"DeLorme Publishing Inc.\"  },\r\n    { 0x1164, \"YUAN High-Tech Development Co., Ltd.\"  },\r\n    { 0x1165, \"Telson Electronics Co., Ltd.\"  },\r\n    { 0x1166, \"Bantam Interactive Technologies\"  },\r\n    { 0x1167, \"Salient Systems Corporation\"  },\r\n    { 0x1168, \"BizConn International Corp.\"  },\r\n    { 0x1169, \"Adirondack Optics\"  },\r\n    { 0x116A, \"JJL Technologies, LLC\"  },\r\n    { 0x116B, \"Pigeon Point Systems\"  },\r\n    { 0x116C, \"SecureEye, Inc.\"  },\r\n    { 0x116D, \"Filmetrics, Inc.\"  },\r\n    { 0x116E, \"Gigastorage Corp.\"  },\r\n    { 0x116F, \"Silicon 10 Technology Corp.\"  },\r\n    { 0x1170, \"Tadiran Com. Ltd.\"  },\r\n    { 0x1171, \"CRE Technology Co., Ltd.\"  },\r\n    { 0x1172, \"Telegate Co., Ltd.\"  },\r\n    { 0x1173, \"Esko-Graphics\"  },\r\n    { 0x1174, \"Techno-One Co., Ltd.\"  },\r\n    { 0x1175, \"Sheng Yih Technologies Co., Ltd.\"  },\r\n    { 0x1176, \"Japan Touchscreen Distributions, Inc.\"  },\r\n    { 0x1177, \"Hitachi Communication Technologies, Ltd.\"  },\r\n    { 0x1178, \"Kamaya Electric Co., Ltd.\"  },\r\n    { 0x1179, \"Bio-logic Systems Corp.\"  },\r\n    { 0x117A, \"Ishikawa Seisakusho, Ltd.\"  },\r\n    { 0x117B, \"Primetech Engineering Corporation\"  },\r\n    { 0x117C, \"SOFTIDEA s.r.o.\"  },\r\n    { 0x117D, \"Santa Electronic Inc.\"  },\r\n    { 0x117E, \"JNC, Inc.\"  },\r\n    { 0x117F, \"Princeton Technology, Ltd.\"  },\r\n    { 0x1180, \"Spectra-Physics\"  },\r\n    { 0x1181, \"USB NET\"  },\r\n    { 0x1182, \"Venture Corporation Limited\"  },\r\n    { 0x1183, \"Digital Dream Co. Europe Ltd.\"  },\r\n    { 0x1184, \"Kyocera Elco Corporation\"  },\r\n    { 0x1185, \"Projectiondesign AS\"  },\r\n    { 0x1186, \"Scientec System\"  },\r\n    { 0x1187, \"Techno Valley Co., Ltd.\"  },\r\n    { 0x1188, \"Bloomberg L.P.\"  },\r\n    { 0x1189, \"Trisat IndTry Computer Co. LTD.\"  },\r\n    { 0x118A, \"KEBA AG\"  },\r\n    { 0x118B, \"AXIOMTEK Co., Ltd.\"  },\r\n    { 0x118C, \"INFINIT GmbH\"  },\r\n    { 0x118D, \"Gould Instrument Systems\"  },\r\n    { 0x118E, \"Hermstedt AG\"  },\r\n    { 0x118F, \"You Yang Technology Co., Ltd.\"  },\r\n    { 0x1190, \"Tripace\"  },\r\n    { 0x1191, \"Loyalty Founder Enterprise Co., Ltd.\"  },\r\n    { 0x1192, \"Matsusada Precision Inc.\"  },\r\n    { 0x1193, \"H2I TECHNOLOGIES\"  },\r\n    { 0x1194, \"GLORY AZ System Co., Ltd.\"  },\r\n    { 0x1195, \"ELECTROLINE\"  },\r\n    { 0x1196, \"Yankee Robotics, LLC\"  },\r\n    { 0x1197, \"Technoimagia Co., Ltd.\"  },\r\n    { 0x1198, \"StarShine Technology Corp.\"  },\r\n    { 0x1199, \"Sierra Wireless Inc.\"  },\r\n    { 0x119A, \"DONG GUAN JALINK ELECTRONICES CO.,LTD\"  },\r\n    { 0x119B, \"ruwido austria GmbH\"  },\r\n    { 0x119C, \"SK MEDICAL ELECTRONICS CO.,LTD\"  },\r\n    { 0x119D, \"Saka-Techno Science Co., Ltd.\"  },\r\n    { 0x119E, \"Engineered Audio, LLC.\"  },\r\n    { 0x119F, \"TECNOS CO., LTD.\"  },\r\n    { 0x11A0, \"Chipcon\"  },\r\n    { 0x11A1, \"Mikrap AG\"  },\r\n    { 0x11A2, \"SitecSoft Co., Ltd.\"  },\r\n    { 0x11A3, \"Technovas Co., Ltd.\"  },\r\n    { 0x11A4, \"THE FURUKAWA ELECTRIC CO., LTD.\"  },\r\n    { 0x11A5, \"TOKYO RIKAKIKAI CO., LTD.\"  },\r\n    { 0x11A6, \"VRmagic GmbH\"  },\r\n    { 0x11A7, \"SNAPSHIELD LTD.\"  },\r\n    { 0x11A8, \"Hoeft & Wessel AG\"  },\r\n    { 0x11A9, \"Parker Hannifin\"  },\r\n    { 0x11AA, \"GlobalMedia Group, LLC\"  },\r\n    { 0x11AB, \"Exito Electronics Co., Ltd.\"  },\r\n    { 0x11AC, \"Nike, Inc.\"  },\r\n    { 0x11AD, \"SANWA ELECTRIC INSTRUMENT CO., LTD.\"  },\r\n    { 0x11AE, \"Stoelting Co.\"  },\r\n    { 0x11AF, \"Valence Semiconductor\"  },\r\n    { 0x11B0, \"ATECH FLASH TECHNOLOGY\"  },\r\n    { 0x11B1, \"New Motion Tec. Corp.\"  },\r\n    { 0x11B2, \"Bizerba GmbH & Co. KG\"  },\r\n    { 0x11B3, \"MONYA Corporation\"  },\r\n    { 0x11B4, \"SPIELO\"  },\r\n    { 0x11B5, \"ADVANTECH EQUIPMENT CORP.\"  },\r\n    { 0x11B6, \"Diskware Co., Ltd.\"  },\r\n    { 0x11B7, \"Embla\"  },\r\n    { 0x11B8, \"CROSS S&T Inc.\"  },\r\n    { 0x11B9, \"IST Electronics, Inc.\"  },\r\n    { 0x11BA, \"Sasem Co., Ltd.\"  },\r\n    { 0x11BB, \"YaMu Solutions\"  },\r\n    { 0x11BC, \"Taipei EELY-ECW Co., Ltd.\"  },\r\n    { 0x11BD, \"UBINETICS LIMITED\"  },\r\n    { 0x11BE, \"Martin Professional A/S\"  },\r\n    { 0x11BF, \"SonoSite, Inc.\"  },\r\n    { 0x11C0, \"Sanmos Microelectronics Corp.\"  },\r\n    { 0x11C1, \"Wako Giken Kogyo Co., Ltd.\"  },\r\n    { 0x11C2, \"EYESPYFX\"  },\r\n    { 0x11C3, \"Kaizen Frogpad, LLC\"  },\r\n    { 0x11C4, \"DALLANTBANK, INC.\"  },\r\n    { 0x11C5, \"INMAX TECHNOLOGY CORP.\"  },\r\n    { 0x11C6, \"Guzik Technical Enterprises\"  },\r\n    { 0x11C7, \"Reliance Electric Limited\"  },\r\n    { 0x11C8, \"Fullcom Technology Corp.\"  },\r\n    { 0x11C9, \"Monster Cable Products, Inc.\"  },\r\n    { 0x11CA, \"VeriFone\"  },\r\n    { 0x11CB, \"Magni Systems, Inc.\"  },\r\n    { 0x11CC, \"AIM SRL\"  },\r\n    { 0x11CD, \"KTEK Co., Ltd.\"  },\r\n    { 0x11CE, \"Argolis BV\"  },\r\n    { 0x11CF, \"Nemoto Kyorindo Co., Ltd.\"  },\r\n    { 0x11D0, \"TOPCON CORPORATION, Opthalmic & Medical Instrument Dept\"  },\r\n    { 0x11D1, \"Far Touch Inc.\"  },\r\n    { 0x11D2, \"BW Technologies Ltd.\"  },\r\n    { 0x11D3, \"Elias Technology, Inc.\"  },\r\n    { 0x11D4, \"Unitac Co., Ltd.\"  },\r\n    { 0x11D5, \"Polyvision Corporation\"  },\r\n    { 0x11D6, \"FUJIFILM AXIA CO., LTD.\"  },\r\n    { 0x11D7, \"Kokusai Electric Alpha Co., Ltd.\"  },\r\n    { 0x11D8, \"Zybertek\"  },\r\n    { 0x11D9, \"Itronix Corporation\"  },\r\n    { 0x11DA, \"Tekscan, Inc.\"  },\r\n    { 0x11DB, \"Topfield Co., Ltd.\"  },\r\n    { 0x11DC, \"STELECTRIC A/S\"  },\r\n    { 0x11DD, \"DRAGONCHIP LTD.\"  },\r\n    { 0x11DE, \"La Generale Multimedia\"  },\r\n    { 0x11DF, \"ROI Computer AG\"  },\r\n    { 0x11E0, \"SUNX Limited\"  },\r\n    { 0x11E1, \"Encentuate Pte. Ltd.\"  },\r\n    { 0x11E2, \"SPECSOFT CONSULTING INC\"  },\r\n    { 0x11E3, \"GfS-Hofheim\"  },\r\n    { 0x11E4, \"STANDARD ELECTRONICS TELECOM INC.\"  },\r\n    { 0x11E5, \"CHUFON Technology Co., Ltd.\"  },\r\n    { 0x11E6, \"K.I. Technology Co. Ltd.\"  },\r\n    { 0x11E7, \"Rockford Corporation\"  },\r\n    { 0x11E8, \"NAAT Technology Corp.\"  },\r\n    { 0x11E9, \"Wincan Technology Co., Ltd.\"  },\r\n    { 0x11EA, \"Panram International Corp.\"  },\r\n    { 0x11EB, \"VTech Innovation L.P. dba Advanced American Telephones\"  },\r\n    { 0x11EC, \"Hitachi Computer Peripherals Co., Ltd.\"  },\r\n    { 0x11ED, \"Shimizu Technology Inc.\"  },\r\n    { 0x11EE, \"ASAHI ELECTRIC CO., LTD.\"  },\r\n    { 0x11EF, \"Cableplus Industrial Co., Ltd.\"  },\r\n    { 0x11F0, \"Matthew Ward Solutions\"  },\r\n    { 0x11F1, \"Cal-Comp Electronics (Thailand) Public Co., Ltd.\"  },\r\n    { 0x11F2, \"Chain Tay Technology Co., Ltd.\"  },\r\n    { 0x11F3, \"ROUND Co., Ltd.\"  },\r\n    { 0x11F4, \"Kyoritsu Electric Corporation\"  },\r\n    { 0x11F5, \"Siemens Mobile Phones\"  },\r\n    { 0x11F6, \"NetIndex Inc.\"  },\r\n    { 0x11F7, \"ALCATEL BUSINESS SYSTEMS\"  },\r\n    { 0x11F8, \"BodyMedia, Inc.\"  },\r\n    { 0x11F9, \"Cryptocard Corporation\"  },\r\n    { 0x11FA, \"Code Corporation\"  },\r\n    { 0x11FB, \"HORIBA, Ltd.\"  },\r\n    { 0x11FC, \"ANCOT CORPORATION\"  },\r\n    { 0x11FD, \"EKE-Electronics Ltd.\"  },\r\n    { 0x11FE, \"SHENZHEN CHANGXUNXING ELECTRONIC CO., LTD.\"  },\r\n    { 0x11FF, \"LITE STAR ELECTRONICS TECHNOLOGIES, CO. LTD.\"  },\r\n    { 0x1200, \"Spellman High Voltage Electronics Corp.\"  },\r\n    { 0x1201, \"Practical Automation, Inc.\"  },\r\n    { 0x1202, \"KUK JE TONG SHIN CO., LTD.\"  },\r\n    { 0x1203, \"Taiwan Semiconductor Co., Ltd.\"  },\r\n    { 0x1204, \"SATEC\"  },\r\n    { 0x1205, \"NV ADB TTV TECHNOLOGIES SA\"  },\r\n    { 0x1206, \"Synnix Technology Co.\"  },\r\n    { 0x1207, \"Cardinal Health UK 232 Ltd.\"  },\r\n    { 0x1208, \"Seiko Epson Corp.- System Device\"  },\r\n    { 0x120A, \"Wintest Corp.\"  },\r\n    { 0x120B, \"Dension Audio Systems Ltd.\"  },\r\n    { 0x120C, \"ALF, Inc.\"  },\r\n    { 0x120D, \"(AVL) DiTEST Fahrzeugdiagnose GmbH\"  },\r\n    { 0x120E, \"HUDSON SOFT CO., LTD.\"  },\r\n    { 0x120F, \"Magellan Navigation, Inc.\"  },\r\n    { 0x1210, \"Harman\"  },\r\n    { 0x1211, \"COSMED S.r.l.\"  },\r\n    { 0x1212, \"D'Crypt Pte Ltd.\"  },\r\n    { 0x1213, \"Fukko System Co., Ltd.\"  },\r\n    { 0x1214, \"Dr. Bott KG\"  },\r\n    { 0x1215, \"Towa Engineering Corporation\"  },\r\n    { 0x1216, \"ProMinent Dosiertechnik GmbH\"  },\r\n    { 0x1217, \"Goyatek Technology Inc.\"  },\r\n    { 0x1218, \"Geutebrueck GmbH\"  },\r\n    { 0x1219, \"COMPAL COMMUNICATIONS, INC.\"  },\r\n    { 0x121A, \"TimeKeeping Systems, Inc.\"  },\r\n    { 0x121B, \"FEC Inc.\"  },\r\n    { 0x121C, \"Raysis Co., Ltd.\"  },\r\n    { 0x121D, \"Intelligent Computer Solutions\"  },\r\n    { 0x121E, \"Jungsoft Co., Ltd.\"  },\r\n    { 0x121F, \"Panini S.P.A.\"  },\r\n    { 0x1220, \"TC Group A/S\"  },\r\n    { 0x1221, \"Averatec, Inc.\"  },\r\n    { 0x1222, \"Tipro Keyboards D.O.O.\"  },\r\n    { 0x1223, \"SKYCABLE ENTERPRISE CO., LTD.\"  },\r\n    { 0x1224, \"SCATT, ZAO\"  },\r\n    { 0x1225, \"HI-P Tech Corporation\"  },\r\n    { 0x1226, \"Keihin Corporation\"  },\r\n    { 0x1227, \"T-RAC INTERNATIONAL, INC.\"  },\r\n    { 0x1228, \"DATAPAQ\"  },\r\n    { 0x1229, \"EPO Science & Technology Inc.\"  },\r\n    { 0x122A, \"WABCO GmbH & Co., OHG\"  },\r\n    { 0x122B, \"Midas Lab Inc.\"  },\r\n    { 0x122C, \"Qbtech AB\"  },\r\n    { 0x122D, \"Hitachi Information & Control Solutions, Ltd.\"  },\r\n    { 0x122E, \"IOLINE\"  },\r\n    { 0x122F, \"Takimaging\"  },\r\n    { 0x1230, \"MIPSABG Chipidea, Lda.\"  },\r\n    { 0x1231, \"CHI MEI COMMUNICATION SYSTEMS, INC.\"  },\r\n    { 0x1232, \"SolitonWave Co., Ltd.\"  },\r\n    { 0x1233, \"Targa Systems Div. L-3 Communications\"  },\r\n    { 0x1234, \"Micro Science Co., Ltd.\"  },\r\n    { 0x1235, \"Focusrite Audio Engineering Ltd\"  },\r\n    { 0x1236, \"Nozaki Insatsu Shigyo Co., Ltd.\"  },\r\n    { 0x1237, \"Technowave Ltd.\"  },\r\n    { 0x1238, \"Bridgekey Corp.\"  },\r\n    { 0x1239, \"Antex Electronics\"  },\r\n    { 0x123A, \"Spectra Technologies Holdings Co., Ltd.\"  },\r\n    { 0x123B, \"De La Rue Systems Automatizacao\"  },\r\n    { 0x123C, \"K-Won C & C Co., Ltd.\"  },\r\n    { 0x123D, \"Microplex Printware AG\"  },\r\n    { 0x123E, \"A.T. WORKS, Inc.\"  },\r\n    { 0x123F, \"DURAPOWER TECHNOLOGY LTD.\"  },\r\n    { 0x1240, \"HUMUS MOG CO., LTD.\"  },\r\n    { 0x1241, \"OTSUKA ELECTRONICS CO., LTD.\"  },\r\n    { 0x1242, \"MAC SYSTEM CO., LTD.\"  },\r\n    { 0x1243, \"Fujikura Ltd., Fiber Optic System Division\"  },\r\n    { 0x1244, \"DResearch Digital Media Systems GmbH\"  },\r\n    { 0x1245, \"R/D Tech Inc.\"  },\r\n    { 0x1246, \"CTO S.p.A.\"  },\r\n    { 0x1247, \"JAPAN PRECISION INSTRUMENTS, INC.\"  },\r\n    { 0x1248, \"Vector Informatik GmbH\"  },\r\n    { 0x1249, \"TRACESPAN Communications Ltd.\"  },\r\n    { 0x124A, \"AirVast Technology Inc.\"  },\r\n    { 0x124B, \"NYKO Technologies, Inc.\"  },\r\n    { 0x124C, \"MEMORY EXPERTS International Inc.\"  },\r\n    { 0x124D, \"Just Rams PLC\"  },\r\n    { 0x124E, \"YEM Inc.\"  },\r\n    { 0x124F, \"Beijing JingHuiJiaDe Tech. Co., Ltd.\"  },\r\n    { 0x1250, \"TECMAG\"  },\r\n    { 0x1251, \"Iwaya Corporation\"  },\r\n    { 0x1252, \"Nextway Co., Ltd.\"  },\r\n    { 0x1253, \"Erebus Limited\"  },\r\n    { 0x1254, \"Empirical Systems\"  },\r\n    { 0x1255, \"ASCII Solutions, Inc.\"  },\r\n    { 0x1256, \"Spectronic Denmark A/S\"  },\r\n    { 0x1257, \"AudioScience\"  },\r\n    { 0x1258, \"Continental Automotive Trading UK Ltd.\"  },\r\n    { 0x1259, \"Deutsche Montan Technologie GmbH\"  },\r\n    { 0x125A, \"Shintake Sangyo Co., Ltd.\"  },\r\n    { 0x125B, \"VIDEX\"  },\r\n    { 0x125C, \"Apogee Instruments, Inc.\"  },\r\n    { 0x125D, \"Advanced Technology (UK) PLC\"  },\r\n    { 0x125E, \"Bosch Automotive Service Solutions\"  },\r\n    { 0x125F, \"ADATA Technology Co., Ltd.\"  },\r\n    { 0x1260, \"Cores Inc.\"  },\r\n    { 0x1261, \"All Ring Tech Co., Ltd.\"  },\r\n    { 0x1262, \"MICRO VISION CO., LTD.\"  },\r\n    { 0x1263, \"Opti Japan Corporation\"  },\r\n    { 0x1264, \"Covidien Energy-based Devices\"  },\r\n    { 0x1265, \"Good Mind Industries Co., Ltd.\"  },\r\n    { 0x1266, \"Pirelli Cavi e Sistemi Telecom S.p.A.\"  },\r\n    { 0x1267, \"SILCOR\"  },\r\n    { 0x1268, \"icube Corp.\"  },\r\n    { 0x1269, \"Sequoia Voting Systems Inc.\"  },\r\n    { 0x126A, \"CHH Electronics Ltd.\"  },\r\n    { 0x126B, \"Veridian Systems\"  },\r\n    { 0x126C, \"Aristocrat Technologies\"  },\r\n    { 0x126D, \"Bel Stewart\"  },\r\n    { 0x126E, \"Strobe Data, Inc.\"  },\r\n    { 0x126F, \"TwinMOS Technologies ME FZE\"  },\r\n    { 0x1270, \"Procomp Informatics Ltd.\"  },\r\n    { 0x1271, \"Foxda Technology Industrial (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1272, \"Linear Technology Corporation\"  },\r\n    { 0x1273, \"HANEX Co., Ltd.\"  },\r\n    { 0x1274, \"Matin, Inc.\"  },\r\n    { 0x1275, \"Xaxero Marine Software Engineering Ltd.\"  },\r\n    { 0x1276, \"QVS\"  },\r\n    { 0x1277, \"Silicon Media Inc.\"  },\r\n    { 0x1278, \"Starlight Xpress Ltd.\"  },\r\n    { 0x1279, \"Cheesecote Mountain Camac\"  },\r\n    { 0x127A, \"Electrophysics Corp.\"  },\r\n    { 0x127B, \"The Technology Partnership (TTP)\"  },\r\n    { 0x127C, \"Comarco Wireless\"  },\r\n    { 0x127D, \"RAiO Technology Inc.\"  },\r\n    { 0x127E, \"Hugelent Telecommunication (SuZhou) Co., Ltd.\"  },\r\n    { 0x127F, \"IPACS Hans-Borchers-Gruentjens GbR (IPACS)\"  },\r\n    { 0x1280, \"Animeta Systems Inc.\"  },\r\n    { 0x1281, \"Gean Sen Electronic Co., Ltd.\"  },\r\n    { 0x1282, \"Falco Electronics Mexico\"  },\r\n    { 0x1283, \"zebris Medizintechnik GmbH\"  },\r\n    { 0x1284, \"YEC Co., Ltd.\"  },\r\n    { 0x1285, \"Schindler Aufzuge AG\"  },\r\n    { 0x1286, \"MARVELL SEMICONDUCTOR, INC.\"  },\r\n    { 0x1287, \"Infomove Co., Ltd.\"  },\r\n    { 0x1288, \"Micro Advantage Inc.\"  },\r\n    { 0x1289, \"Nippon Telesoft Co., Ltd.\"  },\r\n    { 0x128A, \"Asia Vital Components Co., Ltd.\"  },\r\n    { 0x128B, \"Medicapture, Inc.\"  },\r\n    { 0x128C, \"ITW Food Equipment Group, LLC dba Hobart Corporation\"  },\r\n    { 0x128D, \"Testo AG\"  },\r\n    { 0x128E, \"Stormblue Co., Ltd.\"  },\r\n    { 0x128F, \"Guidant Corporation\"  },\r\n    { 0x1290, \"Musicus GmbH\"  },\r\n    { 0x1291, \"Flarion Technologies\"  },\r\n    { 0x1292, \"Fire International Ltd.\"  },\r\n    { 0x1293, \"Mitsubishi Electric Engineering Co., Ltd.\"  },\r\n    { 0x1294, \"RISO KAGAKU CORP.\"  },\r\n    { 0x1295, \"A & G Souzioni Digitali\"  },\r\n    { 0x1296, \"RadioScape\"  },\r\n    { 0x1297, \"DEKTEC Digital Video B.V.\"  },\r\n    { 0x1298, \"Genlyte Controls\"  },\r\n    { 0x1299, \"DGStation Co., Ltd.\"  },\r\n    { 0x129A, \"PULSTEC INDUSTRIAL CO., LTD.\"  },\r\n    { 0x129B, \"CyberTAN Technology Inc.\"  },\r\n    { 0x129C, \"Min Aik Technology Co., Ltd.\"  },\r\n    { 0x129D, \"Yueqing Longhua Electronics Factory\"  },\r\n    { 0x129E, \"Aceeca Limited\"  },\r\n    { 0x129F, \"Howtek Devices Corp.\"  },\r\n    { 0x12A0, \"CDC Point S.p.A.\"  },\r\n    { 0x12A1, \"Tohken Co., Ltd.\"  },\r\n    { 0x12A2, \"E28 (Shanghai) Ltd.\"  },\r\n    { 0x12A3, \"KENT WORLD CO., LTD.\"  },\r\n    { 0x12A4, \"Guangdong Matsunichi Communications Technology Co., Ltd\"  },\r\n    { 0x12A5, \"Sola/Hevi-Duty\"  },\r\n    { 0x12A6, \"ULVAC-PHI, Inc.\"  },\r\n    { 0x12A7, \"Trendchip Technologies Corp.\"  },\r\n    { 0x12A8, \"Clovertech Inc.\"  },\r\n    { 0x12A9, \"Sunwave Technology Corp.\"  },\r\n    { 0x12AA, \"Bustec Production Ltd.\"  },\r\n    { 0x12AB, \"Honey Bee (Hong Kong) Limited\"  },\r\n    { 0x12AC, \"Compact Light System Norway A/S\"  },\r\n    { 0x12AD, \"Asahi Seiko Co., Ltd.\"  },\r\n    { 0x12AE, \"Matsunichi Communication Holdings Limited\"  },\r\n    { 0x12AF, \"Baldor UK Ltd.\"  },\r\n    { 0x12B0, \"Axciton Systems, Inc.\"  },\r\n    { 0x12B1, \"HIMECS CO., LTD.\"  },\r\n    { 0x12B2, \"DICKSON Company\"  },\r\n    { 0x12B3, \"Megaforce Company Ltd.\"  },\r\n    { 0x12B4, \"Hanchang System Corporation\"  },\r\n    { 0x12B5, \"World Touch Gaming , Inc.\"  },\r\n    { 0x12B6, \"Naito Densei Machida Mfg. Co., Ltd.\"  },\r\n    { 0x12B7, \"Genesis Microchip Inc.\"  },\r\n    { 0x12B8, \"Zhejiang Xinya Electronic Technology Co., Ltd.\"  },\r\n    { 0x12B9, \"Freehand Systems, Inc.\"  },\r\n    { 0x12BA, \"Sony Computer Entertainment America\"  },\r\n    { 0x12BB, \"Paltronics, Inc.\"  },\r\n    { 0x12BC, \"Hakusan Corporation\"  },\r\n    { 0x12BD, \"Sun Light Application Co., Ltd.\"  },\r\n    { 0x12BE, \"Dynex Technologies\"  },\r\n    { 0x12BF, \"Matrix Multimedia Ltd.\"  },\r\n    { 0x12C0, \"Sencore, Inc.\"  },\r\n    { 0x12C1, \"ARTRAY CO., LTD.\"  },\r\n    { 0x12C2, \"HHB Communications Ltd.\"  },\r\n    { 0x12C3, \"Fiso Technologies, Inc.\"  },\r\n    { 0x12C4, \"Autocue Ltd.\"  },\r\n    { 0x12C5, \"XN Technologies, Inc.\"  },\r\n    { 0x12C6, \"Bosch Security Systems\"  },\r\n    { 0x12C7, \"Hismartech Co., Ltd.\"  },\r\n    { 0x12C8, \"XiMeta Inc.\"  },\r\n    { 0x12C9, \"Newmen Technology Corp. Ltd.\"  },\r\n    { 0x12CA, \"Cables To Go International Manufacturing Co., Ltd.\"  },\r\n    { 0x12CB, \"Dallmeier electronic GmbH\"  },\r\n    { 0x12CC, \"Printherm\"  },\r\n    { 0x12CD, \"Cables Unlimited\"  },\r\n    { 0x12CE, \"Hakko Electronics Co., Ltd.\"  },\r\n    { 0x12CF, \"Dexin Corporation\"  },\r\n    { 0x12D0, \"ITG Research & Development Center\"  },\r\n    { 0x12D1, \"Huawei Technologies Co., Ltd.\"  },\r\n    { 0x12D2, \"LINE TECH INDUSTRIAL CO., LTD.\"  },\r\n    { 0x12D3, \"Linak A/S\"  },\r\n    { 0x12D4, \"Infonics Pty. Limited\"  },\r\n    { 0x12D5, \"Strategic Vista Corp.\"  },\r\n    { 0x12D6, \"EMS Dr. Thomas Wuensche\"  },\r\n    { 0x12D7, \"Better Holdings (HK) Limited\"  },\r\n    { 0x12D8, \"Araneus Information Systems Oy\"  },\r\n    { 0x12D9, \"DIGITFAB INTERNATIONAL CO., LTD.\"  },\r\n    { 0x12DA, \"Simavionics, Inc.\"  },\r\n    { 0x12DB, \"Planar Systems, Inc.\"  },\r\n    { 0x12DC, \"MMGEAR Co., Ltd.\"  },\r\n    { 0x12DD, \"JFE Advantech Co., Ltd.\"  },\r\n    { 0x12DE, \"National Display Systems\"  },\r\n    { 0x12DF, \"Sumitomo 3M Limited\"  },\r\n    { 0x12E0, \"Electronica Mecanica Y Control S.A.\"  },\r\n    { 0x12E1, \"FDK CORPORATION\"  },\r\n    { 0x12E2, \"Bonso Electronic Ltd.\"  },\r\n    { 0x12E3, \"1417188 Ontario Ltd.\"  },\r\n    { 0x12E4, \"Bruel & Kjaer Sound & Vibration Meas. A/S\"  },\r\n    { 0x12E5, \"Interactive Computer Products, Inc.\"  },\r\n    { 0x12E6, \"Waldorf-Music AG\"  },\r\n    { 0x12E7, \"Sugiyama Electron Co., Ltd.\"  },\r\n    { 0x12E8, \"ZAN Messgeraete\"  },\r\n    { 0x12E9, \"Mindspeed Technologies\"  },\r\n    { 0x12EA, \"Microlink Systems\"  },\r\n    { 0x12EB, \"MITSUI & CO., LTD.\"  },\r\n    { 0x12EC, \"KYORITSU ELECTRICAL INSTRUMENTS WORKS, LTD. (R&D Center\"  },\r\n    { 0x12ED, \"Techno Kit Corporation\"  },\r\n    { 0x12EE, \"Avery Dennison Deutschland GmbH\"  },\r\n    { 0x12EF, \"Tapwave, Inc.\"  },\r\n    { 0x12F0, \"KROHNE\"  },\r\n    { 0x12F1, \"OHIRA GIKEN, IND. CO., LTD.\"  },\r\n    { 0x12F2, \"VIEWPLUS TECHNOLOGIES, INC.\"  },\r\n    { 0x12F3, \"FORMOSA TELETEK CORPORATION\"  },\r\n    { 0x12F4, \"Glovic Electronics Corp.\"  },\r\n    { 0x12F5, \"Dynamic System Electronics Corp.\"  },\r\n    { 0x12F6, \"Aichi Tokei Denki Co., Ltd.\"  },\r\n    { 0x12F7, \"Memorex Products, Inc.\"  },\r\n    { 0x12F8, \"Evolution Technologies, Inc.\"  },\r\n    { 0x12F9, \"RF-LINK SYSTEMS, INC.\"  },\r\n    { 0x12FA, \"RF Micro Devices\"  },\r\n    { 0x12FB, \"SSD JAPAN CO., Ltd\"  },\r\n    { 0x12FC, \"eGenium S.r.l.\"  },\r\n    { 0x12FD, \"AIN COMM. TECHNOLOGY CO., LTD.\"  },\r\n    { 0x12FE, \"E.U CONNECTOR(M) SDN BHD.\"  },\r\n    { 0x12FF, \"Fascinating Electronics, Inc.\"  },\r\n    { 0x1300, \"Muscle Corporation\"  },\r\n    { 0x1301, \"Woehler Messgeraete Kehrgeraete GmbH\"  },\r\n    { 0x1302, \"Wildseed Ltd.\"  },\r\n    { 0x1303, \"Lloyd Research (Projects) Ltd.\"  },\r\n    { 0x1304, \"MEDIALINK-I, Inc.\"  },\r\n    { 0x1305, \"ELSE Ltd.\"  },\r\n    { 0x1306, \"Torcon Instruments Inc.\"  },\r\n    { 0x1307, \"USBest Technology Inc.\"  },\r\n    { 0x1308, \"Precision Photonics Corp.\"  },\r\n    { 0x1309, \"Sabine, Inc.\"  },\r\n    { 0x130A, \"SIBATA SCIENTIFIC TECHNOLOGY, LTD.\"  },\r\n    { 0x130B, \"MPC Products\"  },\r\n    { 0x130C, \"Quest Technologies\"  },\r\n    { 0x130D, \"Loyal Technology Corporation\"  },\r\n    { 0x130E, \"Microlink Communications Inc.\"  },\r\n    { 0x130F, \"AGFA NDT, Krautkramer Ultrasonic Systems\"  },\r\n    { 0x1310, \"Air2U Inc.\"  },\r\n    { 0x1311, \"EDX Epi-Scan Corp\"  },\r\n    { 0x1312, \"ICS Electronics\"  },\r\n    { 0x1313, \"THORLABS, INC\"  },\r\n    { 0x1314, \"Ryoko Electric Co., Ltd.\"  },\r\n    { 0x1315, \"Prairie Systems & Equip. Ltd. O/A Massload Technologies\"  },\r\n    { 0x1316, \"JUNGLE Inc\"  },\r\n    { 0x1317, \"PC-CRAFT Co., Ltd.\"  },\r\n    { 0x1318, \"O'RITE TECHNOLOGY Co., Ltd.\"  },\r\n    { 0x1319, \"Peekel Instruments B.V.\"  },\r\n    { 0x131A, \"VERYWELL CO., LTD.\"  },\r\n    { 0x131B, \"Rowley Associates Ltd.\"  },\r\n    { 0x131C, \"Staples, Inc.\"  },\r\n    { 0x131D, \"Natural Point\"  },\r\n    { 0x131E, \"Duerr Dental GmbH & Co., KG\"  },\r\n    { 0x131F, \"Ayuttha Technology Corp.\"  },\r\n    { 0x1320, \"Jaguar International Corporation\"  },\r\n    { 0x1321, \"Lectrosonics, Inc.\"  },\r\n    { 0x1322, \"Z/I Imaging\"  },\r\n    { 0x1323, \"Zeustech Company Limited\"  },\r\n    { 0x1324, \"H-Mod, Inc.\"  },\r\n    { 0x1325, \"Austriamicrosystems AG\"  },\r\n    { 0x1326, \"Force Control Industries Inc.\"  },\r\n    { 0x1327, \"Avtec, Inc.\"  },\r\n    { 0x1328, \"Iris Power Engineering\"  },\r\n    { 0x1329, \"Appairent Technologies, Inc.\"  },\r\n    { 0x132A, \"Envara\"  },\r\n    { 0x132B, \"Konica Minolta, Inc.\"  },\r\n    { 0x132C, \"Le Prestique International (H.K.) Ltd.\"  },\r\n    { 0x132D, \"GE Healthcare Life Sciences\"  },\r\n    { 0x132E, \"Kwang Jang Corporation\"  },\r\n    { 0x132F, \"ViALUX GmbH\"  },\r\n    { 0x1330, \"ALFANUCLEAR S.A.\"  },\r\n    { 0x1331, \"Panic Inc.\"  },\r\n    { 0x1332, \"Moral Follow System Co., Ltd.\"  },\r\n    { 0x1333, \"Ultra Electronics Precision Air & Land Systems\"  },\r\n    { 0x1334, \"ADC Corporation\"  },\r\n    { 0x1335, \"PLUS Corporation\"  },\r\n    { 0x1336, \"IMM-Gruppe\"  },\r\n    { 0x1337, \"Radiant Networks Plc\"  },\r\n    { 0x1338, \"IT CONCEPTS LLC\"  },\r\n    { 0x1339, \"Akashi Corporation\"  },\r\n    { 0x133A, \"Vyyo Inc.\"  },\r\n    { 0x133B, \"FLASH SUPPORT GROUP, INC.\"  },\r\n    { 0x133C, \"G-Design Technology\"  },\r\n    { 0x133D, \"Jasco Products Company\"  },\r\n    { 0x133E, \"Kemper Digital GmbH\"  },\r\n    { 0x133F, \"Hwayoung RF Solution Inc.\"  },\r\n    { 0x1340, \"Escherlogic Inc.\"  },\r\n    { 0x1341, \"Lavry Engineering\"  },\r\n    { 0x1342, \"Sutter Instrument Company\"  },\r\n    { 0x1343, \"Heiwa Tokei Mfg. Co., Ltd\"  },\r\n    { 0x1344, \"TCI, Inc. d/b/a TCI Medical\"  },\r\n    { 0x1345, \"Sino Lite Technology Corp.\"  },\r\n    { 0x1346, \"Mediatek Corp.\"  },\r\n    { 0x1347, \"Moravian Instruments, Inc.\"  },\r\n    { 0x1348, \"Katsuragawa Electric Co., Ltd.\"  },\r\n    { 0x1349, \"Esaote/Pie Medical Equipment\"  },\r\n    { 0x134A, \"iX Group\"  },\r\n    { 0x134B, \"El Pusk Co., Ltd.\"  },\r\n    { 0x134C, \"Panjit International Inc.\"  },\r\n    { 0x134D, \"Danfoss Drives A/S\"  },\r\n    { 0x134E, \"Digby's Bitpile, Inc. D.B.A. D Bit\"  },\r\n    { 0x134F, \"Addvalue Communications Pte Ltd.\"  },\r\n    { 0x1350, \"UniqueICs, LLC\"  },\r\n    { 0x1351, \"Crossware Associates\"  },\r\n    { 0x1352, \"Km2Net\"  },\r\n    { 0x1353, \"Shenzhen Coship Software Co., Ltd.\"  },\r\n    { 0x1354, \"FACTS Engineering LLC\"  },\r\n    { 0x1355, \"Ethicon Endo-Surgery, Inc.\"  },\r\n    { 0x1356, \"Techpoint Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x1357, \"P & E Microcomputer Systems, Inc.\"  },\r\n    { 0x1358, \"SKYLIGHT DIGITAL INC.\"  },\r\n    { 0x1359, \"RKC INSTRUMENT INC.\"  },\r\n    { 0x135A, \"URMET TLC S.p.A. - Servizio Amministrativo\"  },\r\n    { 0x135B, \"M-System Co., Ltd.\"  },\r\n    { 0x135C, \"Real-Time Essentials, Inc.\"  },\r\n    { 0x135D, \"ALGOTEX SRL\"  },\r\n    { 0x135E, \"Insta Elektro GmbH\"  },\r\n    { 0x135F, \"Control Development, Inc.\"  },\r\n    { 0x1360, \"FREETRON COM LTD.\"  },\r\n    { 0x1361, \"Thinktel Korea Co., Ltd.\"  },\r\n    { 0x1362, \"IMAGICA Corp.\"  },\r\n    { 0x1363, \"Axsun Technologies, Inc.\"  },\r\n    { 0x1364, \"SHARP TAKAYA ELECTRONICS INDUSTRY CO., LTD.\"  },\r\n    { 0x1365, \"TOYO JIKI INDUSTRY CO., LTD.\"  },\r\n    { 0x1366, \"SEGGER Microcontroller Systems GmbH\"  },\r\n    { 0x1367, \"The Soundbeam Project\"  },\r\n    { 0x1368, \"TelePaq Technology Inc.\"  },\r\n    { 0x1369, \"FASL LLC.\"  },\r\n    { 0x136A, \"Pelco\"  },\r\n    { 0x136B, \"STEC\"  },\r\n    { 0x136C, \"Datastor Technology Co., Ltd.\"  },\r\n    { 0x136D, \"Brainchild\"  },\r\n    { 0x136E, \"Andor Technology\"  },\r\n    { 0x136F, \"Nielsen Media Research\"  },\r\n    { 0x1370, \"Swissbit AG\"  },\r\n    { 0x1371, \"Micro Technology Co., Ltd.\"  },\r\n    { 0x1372, \"AMAC Tek Co., Ltd.\"  },\r\n    { 0x1373, \"Radical Research, Inc.\"  },\r\n    { 0x1374, \"American Anko Co.\"  },\r\n    { 0x1375, \"TCL MOBILE COMMUNICATION CO., LTD.\"  },\r\n    { 0x1376, \"Vimtron Electronics Co., Ltd.\"  },\r\n    { 0x1377, \"Sennheiser Electronic\"  },\r\n    { 0x1378, \"HIRATA Corporation\"  },\r\n    { 0x1379, \"Inprocomm, Inc.\"  },\r\n    { 0x137A, \"Weldon Technologies, Inc.\"  },\r\n    { 0x137B, \"SCAPS GmbH\"  },\r\n    { 0x137C, \"Yaskawa Electric Corporation\"  },\r\n    { 0x137D, \"Diodes Incorporated\"  },\r\n    { 0x137E, \"XL Microwave, Inc.\"  },\r\n    { 0x137F, \"Sata Hi Tech Services\"  },\r\n    { 0x1380, \"Staveley Instruments\"  },\r\n    { 0x1381, \"N-LINE SYSTEM CO., LTD.\"  },\r\n    { 0x1382, \"Systemware Inc.\"  },\r\n    { 0x1383, \"Application Corporation\"  },\r\n    { 0x1384, \"Device Drivers Limited\"  },\r\n    { 0x1385, \"Variscite Ltd.\"  },\r\n    { 0x1386, \"SCD Tech Inc.\"  },\r\n    { 0x1387, \"Advanced Technical Group\"  },\r\n    { 0x1388, \"Southern Vision Systems, Inc.\"  },\r\n    { 0x1389, \"Coolnection Technology Co., Ltd.\"  },\r\n    { 0x138A, \"Validity Inc.\"  },\r\n    { 0x138B, \"AMS Limited, Integrated Systems\"  },\r\n    { 0x138C, \"Fortemedia, Inc.\"  },\r\n    { 0x138D, \"CPI GmbH\"  },\r\n    { 0x138E, \"RAISONANCE\"  },\r\n    { 0x138F, \"Saia-Burgess Controls Ltd.\"  },\r\n    { 0x1390, \"TomTom International B.V.\"  },\r\n    { 0x1391, \"IdealTEK\"  },\r\n    { 0x1392, \"SAGE INSTRUMENTS\"  },\r\n    { 0x1393, \"ELNEC s.r.o.\"  },\r\n    { 0x1394, \"Gemini 2000 Ltd.\"  },\r\n    { 0x1395, \"Sennheiser Communications A/S\"  },\r\n    { 0x1396, \"Greenliant Systems, Inc.\"  },\r\n    { 0x1397, \"Behringer Spezielle Studiotechnik GmbH\"  },\r\n    { 0x1398, \"Nintendo of America\"  },\r\n    { 0x1399, \"Thai Wonderful Wire Cable Co., Ltd.\"  },\r\n    { 0x139A, \"Infinitec Co., Ltd.\"  },\r\n    { 0x139B, \"Thomas Enterprises, Inc.\"  },\r\n    { 0x139C, \"Deltronics\"  },\r\n    { 0x139D, \"Digisafe Pte. Ltd.\"  },\r\n    { 0x139E, \"Valueplus Inc.\"  },\r\n    { 0x139F, \"Audio Technology Switzerland SA\"  },\r\n    { 0x13A0, \"Essilor International\"  },\r\n    { 0x13A1, \"Canas Co., Ltd.\"  },\r\n    { 0x13A2, \"Pesa Switching Systems, Inc.\"  },\r\n    { 0x13A3, \"Dynon Instruments\"  },\r\n    { 0x13A4, \"Equipment Systems & Devices\"  },\r\n    { 0x13A5, \"Sammy Corporation\"  },\r\n    { 0x13A6, \"Jeppesen Sanderson Inc.\"  },\r\n    { 0x13A7, \"Circuit Design, Inc.\"  },\r\n    { 0x13A8, \"Grandtec Electronic Corp\"  },\r\n    { 0x13A9, \"YAMAMOTO-MS CO., LTD.\"  },\r\n    { 0x13AA, \"Sinar Electronics Limited\"  },\r\n    { 0x13AB, \"MicroMade Galka i Drozdz sp.j\"  },\r\n    { 0x13AC, \"DAQ Systems\"  },\r\n    { 0x13AD, \"Baltech AG\"  },\r\n    { 0x13AE, \"CIM-USA Inc.\"  },\r\n    { 0x13AF, \"Handheld Entertainment\"  },\r\n    { 0x13B0, \"PerkinElmer Optoelectronics\"  },\r\n    { 0x13B1, \"Cisco-Linksys, LLC\"  },\r\n    { 0x13B2, \"ALESIS\"  },\r\n    { 0x13B3, \"Nippon Dics Co., Ltd.\"  },\r\n    { 0x13B4, \"Dolch Computer Systems\"  },\r\n    { 0x13B5, \"INVENTECH, INC.\"  },\r\n    { 0x13B6, \"ISABELLENHUETTE Heusler GmbH KG\"  },\r\n    { 0x13B7, \"Keymark Technology Co., Ltd.\"  },\r\n    { 0x13B8, \"PDM Electronic Co., Ltd.\"  },\r\n    { 0x13B9, \"Cimcore\"  },\r\n    { 0x13BA, \"Yung Ray Technology Co., Ltd.\"  },\r\n    { 0x13BB, \"Covidien Respiratory and Monitoring Solutions\"  },\r\n    { 0x13BC, \"Imaging Supersonic Laboratories Co., Ltd.\"  },\r\n    { 0x13BD, \"Remote Technologies, Inc.\"  },\r\n    { 0x13BE, \"Ricoh Printing Systems, Ltd.\"  },\r\n    { 0x13BF, \"Accusys, Inc.\"  },\r\n    { 0x13C0, \"Stream Labs\"  },\r\n    { 0x13C1, \"Vivitar Corporation\"  },\r\n    { 0x13C2, \"SATO KEIRYOKI MFG. CO., LTD.\"  },\r\n    { 0x13C3, \"SCT Performance, LLC\"  },\r\n    { 0x13C4, \"StationZ Inc.\"  },\r\n    { 0x13C5, \"MELFAS, INC.\"  },\r\n    { 0x13C6, \"Hasointech Co., Ltd.\"  },\r\n    { 0x13C7, \"ANDO ELECTRIC CO., LTD.\"  },\r\n    { 0x13C8, \"Togami Electric Mfg. Co., Ltd.\"  },\r\n    { 0x13C9, \"LinearX Systems Inc.\"  },\r\n    { 0x13CA, \"JyeTai Precision Industrial Co., Ltd.\"  },\r\n    { 0x13CB, \"JTEK Technology Corporation\"  },\r\n    { 0x13CC, \"Cellvic Corporation\"  },\r\n    { 0x13CD, \"ABCD Aging Biorhythms and Computer Diagnostics GmbH\"  },\r\n    { 0x13CE, \"Cypherix (Pty) Ltd.\"  },\r\n    { 0x13CF, \"Wisair Ltd.\"  },\r\n    { 0x13D0, \"Swedect AB\"  },\r\n    { 0x13D1, \"A-Max Technology Macao Commercial Offshore Co. Ltd.\"  },\r\n    { 0x13D2, \"Intelligraphics, Inc.\"  },\r\n    { 0x13D3, \"AzureWave Technologies, Inc.\"  },\r\n    { 0x13D4, \"IWATSU TEST INSTRUMENTS CORPORATION\"  },\r\n    { 0x13D5, \"International Electronics Inc.\"  },\r\n    { 0x13D6, \"Appside\"  },\r\n    { 0x13D7, \"Tableau, LLC\"  },\r\n    { 0x13D8, \"University of Stirling\"  },\r\n    { 0x13D9, \"Blazepoint Limited\"  },\r\n    { 0x13DA, \"OPTEX CO., LTD.\"  },\r\n    { 0x13DB, \"Zastron Electronic (Shenzhen) Co. Ltd.\"  },\r\n    { 0x13DC, \"ALEREON, INC.\"  },\r\n    { 0x13DD, \"i.Tech Dynamic Limited\"  },\r\n    { 0x13DE, \"LANKOM ELECTRONICS CO., LTD.\"  },\r\n    { 0x13DF, \"Good Fancy Enterprise Co., Ltd.\"  },\r\n    { 0x13E0, \"Taiwan Silicon Electronics Corp.\"  },\r\n    { 0x13E1, \"Kaibo Wire & Cable (Shenzhen) Co., Ltd.\"  },\r\n    { 0x13E2, \"Parallax, Inc.\"  },\r\n    { 0x13E3, \"SoniqCast, LLC\"  },\r\n    { 0x13E4, \"Audio Precision\"  },\r\n    { 0x13E5, \"Sigma Audio Research Ltd.\"  },\r\n    { 0x13E6, \"TechnoScope Co., Ltd.\"  },\r\n    { 0x13E7, \"Gantner Pigeon Systems GmbH\"  },\r\n    { 0x13E8, \"PalmSource Inc.\"  },\r\n    { 0x13E9, \"Ununpentium, LLC\"  },\r\n    { 0x13EA, \"I/F - COM A/S\"  },\r\n    { 0x13EB, \"PILZ GMBH & CO. KG\"  },\r\n    { 0x13EC, \"Chyau Yuan Technology Co., Ltd.\"  },\r\n    { 0x13ED, \"Wooju Communications Co., Ltd.\"  },\r\n    { 0x13EE, \"ATLab Inc.\"  },\r\n    { 0x13EF, \"Turner Technology\"  },\r\n    { 0x13F0, \"DIGENT CO., Ltd.\"  },\r\n    { 0x13F1, \"AP Instruments\"  },\r\n    { 0x13F2, \"Tech Micro Corporation\"  },\r\n    { 0x13F3, \"Amulet Hotkey\"  },\r\n    { 0x13F4, \"Verisity Design Inc.\"  },\r\n    { 0x13F5, \"X-TEL Communications, Inc.\"  },\r\n    { 0x13F6, \"Aspen Touch Solutions, Inc.\"  },\r\n    { 0x13F7, \"Corevalley Co., Ltd.\"  },\r\n    { 0x13F8, \"EZPnP Technologies Corp.\"  },\r\n    { 0x13F9, \"Impsys Digital Security AB\"  },\r\n    { 0x13FA, \"Radiantech, Inc.\"  },\r\n    { 0x13FB, \"Noritsu Koki Co., Ltd.\"  },\r\n    { 0x13FC, \"Compucat Research Pty Limited\"  },\r\n    { 0x13FD, \"Initio (HK) Corporation Limited\"  },\r\n    { 0x13FE, \"Phison Electronics Corp.\"  },\r\n    { 0x13FF, \"VIEWCON ELECTRONIC LTD.\"  },\r\n    { 0x1400, \"Axxion Group Corp.\"  },\r\n    { 0x1401, \"Fulhua Microelectronics Corp.\"  },\r\n    { 0x1402, \"Bowe Bell & Howell\"  },\r\n    { 0x1403, \"Sitronix Technology Corp.\"  },\r\n    { 0x1404, \"Fundamental Software Incorporated\"  },\r\n    { 0x1405, \"Cooper Security Ltd.\"  },\r\n    { 0x1406, \"Systemneeds, Inc.\"  },\r\n    { 0x1407, \"Coin Mechanisms Inc.\"  },\r\n    { 0x1408, \"Comark Ltd.\"  },\r\n    { 0x1409, \"IDS Imaging Development Systems GmbH\"  },\r\n    { 0x140A, \"Koyo Electronics Industries Co., Ltd.\"  },\r\n    { 0x140B, \"Vertex Standard Co., Ltd.\"  },\r\n    { 0x140C, \"MITS Electronics\"  },\r\n    { 0x140D, \"Japan Novel Corporation\"  },\r\n    { 0x140E, \"Telechips, Inc.\"  },\r\n    { 0x140F, \"i-WAVER\"  },\r\n    { 0x1410, \"Novatel Wireless, Inc.\"  },\r\n    { 0x1411, \"SKIDATA AG\"  },\r\n    { 0x1412, \"IMADA CO., LTD.\"  },\r\n    { 0x1413, \"Telsey S.p.A.\"  },\r\n    { 0x1415, \"Sony Computer Entertainment Europe\"  },\r\n    { 0x1416, \"Axeon Limited\"  },\r\n    { 0x1417, \"Butterfly Media\"  },\r\n    { 0x1418, \"MediaPower Technology Corporation\"  },\r\n    { 0x1419, \"ABILITY ENTERPRISE CO., LTD.\"  },\r\n    { 0x141A, \"Realm Systems Inc.\"  },\r\n    { 0x141B, \"METRAWARE\"  },\r\n    { 0x141C, \"Leviton Manufacturing\"  },\r\n    { 0x141D, \"J.FIT Co., Ltd.\"  },\r\n    { 0x141E, \"Ikegami Tsushinki Co., Ltd.\"  },\r\n    { 0x141F, \"SHIMADZU CORPORATION\"  },\r\n    { 0x1420, \"Lyrtech Inc.\"  },\r\n    { 0x1421, \"Sentech Co., Ltd.\"  },\r\n    { 0x1422, \"Bird Electronic Corporation\"  },\r\n    { 0x1423, \"ANCA Pty. Ltd.\"  },\r\n    { 0x1424, \"Posnet Polska S.A.\"  },\r\n    { 0x1425, \"IBEX Technology Co., Ltd.\"  },\r\n    { 0x1426, \"NADEX Co., Ltd.\"  },\r\n    { 0x1427, \"Global Display Solutions S.P.A.\"  },\r\n    { 0x1428, \"Improvision Ltd.\"  },\r\n    { 0x1429, \"Vega Technologies Industrial (Austria) Co.\"  },\r\n    { 0x142A, \"Thales-e-Transactions\"  },\r\n    { 0x142B, \"Arbiter Systems, Inc.\"  },\r\n    { 0x142C, \"SOMA OPTICS, LTD.\"  },\r\n    { 0x142D, \"Sanblaze Technology, Inc.\"  },\r\n    { 0x142E, \"TAMS Inc.\"  },\r\n    { 0x142F, \"IO Display Systems\"  },\r\n    { 0x1430, \"Activision\"  },\r\n    { 0x1431, \"Pertech Resources, Inc.\"  },\r\n    { 0x1432, \"Beijing Watertek Information Technology Co., Ltd.\"  },\r\n    { 0x1433, \"TRANWO TECHNOLOGY CORP.\"  },\r\n    { 0x1434, \"Comart System Co., Ltd.\"  },\r\n    { 0x1435, \"Wistron NeWeb Corp.\"  },\r\n    { 0x1436, \"Denali Software, Inc.\"  },\r\n    { 0x1437, \"Carl Zeiss\"  },\r\n    { 0x1438, \"My3ia (Beijing) Technology Ltd.\"  },\r\n    { 0x1439, \"Wind River Systems Inc.\"  },\r\n    { 0x143A, \"CP Technologies\"  },\r\n    { 0x143B, \"RHESCA Company Limited\"  },\r\n    { 0x143C, \"Altek Corporation\"  },\r\n    { 0x143D, \"FUKOKU INDUSTRY CO., LTD.\"  },\r\n    { 0x143E, \"IAV GmbH\"  },\r\n    { 0x143F, \"IDEC IZUMI CORPORATION\"  },\r\n    { 0x1440, \"Jaalaa, Inc.\"  },\r\n    { 0x1441, \"MARIAN GbR\"  },\r\n    { 0x1442, \"Canadian Bank Note Company, Limited\"  },\r\n    { 0x1443, \"Digilent Inc.\"  },\r\n    { 0x1444, \"H & S Instruments Inc.\"  },\r\n    { 0x1445, \"JUSTER CO., LTD.\"  },\r\n    { 0x1446, \"X.J. Group Ltd.\"  },\r\n    { 0x1447, \"Cognex Corporation\"  },\r\n    { 0x1448, \"Biosystems LLC\"  },\r\n    { 0x1449, \"SHIMADEN CO., LTD.\"  },\r\n    { 0x144A, \"Megger\"  },\r\n    { 0x144B, \"MADENTEC LTD.\"  },\r\n    { 0x144C, \"Always On UPS Systems Inc.\"  },\r\n    { 0x144D, \"K-SUN Corporation\"  },\r\n    { 0x144E, \"Westar Corporation\"  },\r\n    { 0x144F, \"K-jump Health Co., Ltd.\"  },\r\n    { 0x1450, \"Melec Inc.\"  },\r\n    { 0x1451, \"Force Dimension LLC\"  },\r\n    { 0x1452, \"DAI NIPPON PRINTING CO., LTD.\"  },\r\n    { 0x1453, \"Epilog Corporation\"  },\r\n    { 0x1454, \"China IWNCOMM Co., Ltd.\"  },\r\n    { 0x1455, \"Georgia Technology Corp.\"  },\r\n    { 0x1456, \"Extending Wire & Cable Co., Ltd.\"  },\r\n    { 0x1457, \"DAE-A Mediatech Co., Ltd.\"  },\r\n    { 0x1458, \"Rauland-Borg Corporation\"  },\r\n    { 0x1459, \"Shanghai Simax Micro-electronics Co., Ltd.\"  },\r\n    { 0x145A, \"All-Systems Electronics Pty. Ltd.\"  },\r\n    { 0x145B, \"Lead-Type Precision Electronics Co., Ltd.\"  },\r\n    { 0x145C, \"Busch-Jaeger-Elektro GmbH\"  },\r\n    { 0x145D, \"Sopac Ltd.\"  },\r\n    { 0x145E, \"Forschungszentrum Karlsruhe GmbH\"  },\r\n    { 0x145F, \"Trust International BV\"  },\r\n    { 0x1460, \"TATUNG Company\"  },\r\n    { 0x1461, \"Staccato Communications\"  },\r\n    { 0x1462, \"Bright Computech Co., Ltd.\"  },\r\n    { 0x1463, \"BBWM Corp.\"  },\r\n    { 0x1464, \"Asiamajor Inc.\"  },\r\n    { 0x1465, \"Michilin Prosperity Co., Ltd.\"  },\r\n    { 0x1466, \"H2 Developer Group\"  },\r\n    { 0x1467, \"Clearly Superior Technologies\"  },\r\n    { 0x1468, \"CSE Co., Ltd.\"  },\r\n    { 0x1469, \"ELECTRIM CORPORATION\"  },\r\n    { 0x146A, \"Knobloch GmbH\"  },\r\n    { 0x146B, \"BigBen Interactive Limited\"  },\r\n    { 0x146C, \"HETEC Datensysteme GmbH\"  },\r\n    { 0x146D, \"Progeny Inc.\"  },\r\n    { 0x146E, \"ClearOne Communications\"  },\r\n    { 0x146F, \"Unity Electrical Ind. Ltd.\"  },\r\n    { 0x1470, \"STARRIVER TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1471, \"Open Labs, Inc.\"  },\r\n    { 0x1472, \"Hangzhou H3C Technologies Co., Ltd.\"  },\r\n    { 0x1473, \"Dingo Incorporated\"  },\r\n    { 0x1474, \"Lamp Express USA, Inc.\"  },\r\n    { 0x1475, \"NAC Image Technology Incorporated\"  },\r\n    { 0x1476, \"Westech Korea Inc.\"  },\r\n    { 0x1477, \"XIROKU INC.\"  },\r\n    { 0x1478, \"Link World Electric Inc.\"  },\r\n    { 0x1479, \"Datalux Corporation\"  },\r\n    { 0x147A, \"Formosa21 Inc.\"  },\r\n    { 0x147B, \"ABB STOTZ-KONTAKT GmbH\"  },\r\n    { 0x147C, \"KeyGhost Ltd.\"  },\r\n    { 0x147D, \"Tosoh Corporation\"  },\r\n    { 0x147E, \"UPEK Inc.\"  },\r\n    { 0x147F, \"Hama GmbH & Co., KG\"  },\r\n    { 0x1480, \"SITEK S.p.a.\"  },\r\n    { 0x1481, \"MHT S.p.A.\"  },\r\n    { 0x1482, \"Vaillant GmbH\"  },\r\n    { 0x1483, \"Shenzhen MingWah Aohan High Technology Co., Ltd.\"  },\r\n    { 0x1484, \"Triad Semiconductor, Inc.\"  },\r\n    { 0x1485, \"OrangeWare Corp.\"  },\r\n    { 0x1486, \"SCM PC-CARD GmbH\"  },\r\n    { 0x1487, \"DSP Group, Ltd.\"  },\r\n    { 0x1488, \"Orion Technology Corp.\"  },\r\n    { 0x1489, \"Sakura Finetek USA, Inc.\"  },\r\n    { 0x148A, \"MICROVISION\"  },\r\n    { 0x148B, \"HandEra, Inc.\"  },\r\n    { 0x148C, \"Colortrac Ltd.\"  },\r\n    { 0x148D, \"DESMA Co., Ltd.\"  },\r\n    { 0x148E, \"EVATRONIX SA\"  },\r\n    { 0x148F, \"Ralink Technology, Corp.\"  },\r\n    { 0x1490, \"Digitek Spa\"  },\r\n    { 0x1491, \"Futronic Technology Co., Ltd.\"  },\r\n    { 0x1492, \"Farsharp Imaging Technology Corp.\"  },\r\n    { 0x1493, \"Suunto\"  },\r\n    { 0x1495, \"Elprotronic Inc.\"  },\r\n    { 0x1496, \"Tunturi Oy Ltd.\"  },\r\n    { 0x1497, \"Panstrong Company Ltd.\"  },\r\n    { 0x1498, \"ULi Electronics Inc.\"  },\r\n    { 0x1499, \"G-STAR Communications, Ltd.\"  },\r\n    { 0x149A, \"Imagination Technologies\"  },\r\n    { 0x149B, \"Ivoclar Vivadent AG\"  },\r\n    { 0x149C, \"TonerHead.com\"  },\r\n    { 0x149D, \"QMotions Inc.\"  },\r\n    { 0x149E, \"Amkor Technology\"  },\r\n    { 0x149F, \"Wits Technologies Pte. Ltd.\"  },\r\n    { 0x14A0, \"WAVE Corporation\"  },\r\n    { 0x14A1, \"Sunhayato Corp.\"  },\r\n    { 0x14A2, \"Big Dutchman (Skandinavien) A/S\"  },\r\n    { 0x14A3, \"Wipotec GmbH\"  },\r\n    { 0x14A4, \"Kyerim Industrial Co.\"  },\r\n    { 0x14A5, \"I-ROCKS TECHNOLOGY CO., LTD.\"  },\r\n    { 0x14A6, \"Interface Masters, Inc.\"  },\r\n    { 0x14A7, \"LanReady Technologies, Inc.\"  },\r\n    { 0x14A8, \"1C Company\"  },\r\n    { 0x14A9, \"Smar Research Corp.\"  },\r\n    { 0x14AA, \"WideView Technology Inc.\"  },\r\n    { 0x14AB, \"Technisches Buero Koenig\"  },\r\n    { 0x14AC, \"Coolstf.com\"  },\r\n    { 0x14AD, \"CTK Corporation\"  },\r\n    { 0x14AE, \"Printronix Inc.\"  },\r\n    { 0x14AF, \"ATP Electronics Inc.\"  },\r\n    { 0x14B0, \"StarTech.com Ltd.\"  },\r\n    { 0x14B1, \"I.E. Gesellschaft fuer Industrieelektronik mbH\"  },\r\n    { 0x14B2, \"Alpha Networks Inc.\"  },\r\n    { 0x14B3, \"CHUO ELECTRIC WORKS CO., LTD.\"  },\r\n    { 0x14B4, \"Appliances Corp.\"  },\r\n    { 0x14B5, \"NTS Telecom\"  },\r\n    { 0x14B6, \"Mimic Technologies Inc.\"  },\r\n    { 0x14B7, \"In2Games Limited\"  },\r\n    { 0x14B8, \"UNITEK TECHNOLOGY CORPORATION\"  },\r\n    { 0x14B9, \"BP Microsystems\"  },\r\n    { 0x14BA, \"FLOVEL CO., LTD.\"  },\r\n    { 0x14BB, \"Assembly Tech. Co., Ltd.\"  },\r\n    { 0x14BC, \"NordNav Technologies AB\"  },\r\n    { 0x14BD, \"Eintech Co., Ltd.\"  },\r\n    { 0x14BE, \"Crestron Electronics, Inc.\"  },\r\n    { 0x14BF, \"Everbee Networks\"  },\r\n    { 0x14C0, \"Rockwell Automation, Inc.\"  },\r\n    { 0x14C1, \"SOHYA TECHNOLOGY CO., LTD.\"  },\r\n    { 0x14C2, \"Gemlight Computer Ltd.\"  },\r\n    { 0x14C3, \"VOXELLE LTD.\"  },\r\n    { 0x14C4, \"CLOVER Electronics Co., Ltd.\"  },\r\n    { 0x14C5, \"AudioControl\"  },\r\n    { 0x14C6, \"Trigon Components, Inc.\"  },\r\n    { 0x14C7, \"Hartmann GmbH\"  },\r\n    { 0x14C8, \"Zytronic Displays Limited\"  },\r\n    { 0x14C9, \"IXOS Ltd. Bvi\"  },\r\n    { 0x14CA, \"Technol Seven Co., Ltd.\"  },\r\n    { 0x14CB, \"Dynapoint, Inc.\"  },\r\n    { 0x14CC, \"WIN TONG ELECTRONICS CO., LTD.\"  },\r\n    { 0x14CD, \"MOAI ELECTRONICS CORPORATION\"  },\r\n    { 0x14CE, \"Spectra, Inc.\"  },\r\n    { 0x14CF, \"Measurement Systems Inc.\"  },\r\n    { 0x14D0, \"Dentrix Dental Systems, Inc.\"  },\r\n    { 0x14D1, \"Maximo Products LLC\"  },\r\n    { 0x14D2, \"BITS CO., LTD.\"  },\r\n    { 0x14D3, \"Y2 Corporation\"  },\r\n    { 0x14D4, \"Telequip Corporation\"  },\r\n    { 0x14D5, \"Electronic Theatre Controls\"  },\r\n    { 0x14D6, \"Beijing Zhijiu Technology Co., Ltd.\"  },\r\n    { 0x14D7, \"Toppan Printing Co., Ltd.\"  },\r\n    { 0x14D8, \"JAMER INDUSTRIES CO., LTD.\"  },\r\n    { 0x14D9, \"Advanced Flash Memory Card Technology Ltd.\"  },\r\n    { 0x14DA, \"Horng Technical Enterprise Co., Ltd.\"  },\r\n    { 0x14DB, \"TOA Musendenki Co., Ltd.\"  },\r\n    { 0x14DC, \"Ftech Co., Ltd.\"  },\r\n    { 0x14DD, \"Raritan Computer, Inc.\"  },\r\n    { 0x14DE, \"Jetway Information Co., Ltd.\"  },\r\n    { 0x14DF, \"COMPRION GmbH\"  },\r\n    { 0x14E0, \"Winradio Communications\"  },\r\n    { 0x14E1, \"Imagination Broadway Ltd\"  },\r\n    { 0x14E2, \"Avistar Communications Corporation\"  },\r\n    { 0x14E3, \"Medmont Pty Ltd.\"  },\r\n    { 0x14E4, \"S.CAM Co., Ltd.\"  },\r\n    { 0x14E5, \"Zinitix Co., Ltd\"  },\r\n    { 0x14E6, \"Micromed Biotecnologia Ltda.\"  },\r\n    { 0x14E7, \"ISS Incorporated\"  },\r\n    { 0x14E8, \"Animated Lighting LC\"  },\r\n    { 0x14E9, \"Lifetouch, Inc.\"  },\r\n    { 0x14EA, \"Kosaka Laboratory Ltd.\"  },\r\n    { 0x14EB, \"Pendulum Instruments AB\"  },\r\n    { 0x14EC, \"Vansco Electronics Ltd.\"  },\r\n    { 0x14ED, \"Shure Inc.\"  },\r\n    { 0x14EE, \"INFORAD Ltd.\"  },\r\n    { 0x14EF, \"AVICLink Corporation\"  },\r\n    { 0x14F0, \"GE\"  },\r\n    { 0x14F1, \"America Hears, LLC.\"  },\r\n    { 0x14F2, \"Axess AG\"  },\r\n    { 0x14F3, \"BAP IMAGE SYSTEMS\"  },\r\n    { 0x14F4, \"Accell Corporation\"  },\r\n    { 0x14F5, \"SourceQuest, Inc.\"  },\r\n    { 0x14F6, \"Symbium Corporation\"  },\r\n    { 0x14F7, \"TechniSat Digital GmbH\"  },\r\n    { 0x14F8, \"Chenrol Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x14F9, \"Full Conductor Electric Appliance Manufacturer\"  },\r\n    { 0x14FA, \"The Wild Divine Project\"  },\r\n    { 0x14FB, \"JAI\"  },\r\n    { 0x14FC, \"Signami LLC\"  },\r\n    { 0x14FD, \"IPC Information Systems\"  },\r\n    { 0x14FE, \"Madrics Media GmbH Europe\"  },\r\n    { 0x14FF, \"Twinhead International Corp.\"  },\r\n    { 0x1500, \"Ellisys\"  },\r\n    { 0x1501, \"Pine-Tum Enterprise Co., Ltd.\"  },\r\n    { 0x1502, \"Peavey Electronics\"  },\r\n    { 0x1503, \"Stretch Inc.\"  },\r\n    { 0x1504, \"Bixolon Co., Ltd.\"  },\r\n    { 0x1505, \"Extraordinary Technologies Pty. Ltd.-Trading as Halcro\"  },\r\n    { 0x1506, \"T.D. Technecon Ltd.\"  },\r\n    { 0x1507, \"APIM INFORMATIQUE\"  },\r\n    { 0x1508, \"MAATEL\"  },\r\n    { 0x1509, \"LI-COR Biosciences, Inc.\"  },\r\n    { 0x150A, \"TiVo Inc.\"  },\r\n    { 0x150B, \"COLLEX COMMUNICATION CORP.\"  },\r\n    { 0x150C, \"Brightwell Dispenses Ltd.\"  },\r\n    { 0x150D, \"PR Electronics A/S\"  },\r\n    { 0x150E, \"Ono Sokki Co., Ltd.\"  },\r\n    { 0x150F, \"Nidec Nemicon Corporation\"  },\r\n    { 0x1510, \"RACEWOOD TELECOM CO., LTD.\"  },\r\n    { 0x1511, \"BridgeCo, AG\"  },\r\n    { 0x1512, \"Software Technologies Group, Inc.\"  },\r\n    { 0x1513, \"Hypercom\"  },\r\n    { 0x1514, \"Microsemi, SOC Products Group\"  },\r\n    { 0x1515, \"Hexon Media Pte Ltd\"  },\r\n    { 0x1516, \"Skymedi Corporation\"  },\r\n    { 0x1517, \"Precisa Instruments AG\"  },\r\n    { 0x1518, \"Cheshire Engineering Corporation\"  },\r\n    { 0x1519, \"Comneon GmbH Co., Ohg.\"  },\r\n    { 0x151A, \"RoyalTek Company Ltd.\"  },\r\n    { 0x151B, \"HOSTNET CO.\"  },\r\n    { 0x151C, \"VeriSilicon Holdings Co., Ltd.\"  },\r\n    { 0x151D, \"P W Allen & Co.\"  },\r\n    { 0x151E, \"Circad Design Ltd.\"  },\r\n    { 0x151F, \"Opal Kelly Incorporated\"  },\r\n    { 0x1520, \"Bitwire Corp.\"  },\r\n    { 0x1521, \"S++ Simulation Services\"  },\r\n    { 0x1522, \"Educational Insights\"  },\r\n    { 0x1523, \"Hitachi High-Tech Science Corporation\"  },\r\n    { 0x1524, \"SCIENTEX Inc.\"  },\r\n    { 0x1525, \"Newson Engineering NV\"  },\r\n    { 0x1526, \"ARDUC Co., Ltd.\"  },\r\n    { 0x1527, \"iQue Ltd.\"  },\r\n    { 0x1528, \"HighAndes Limited\"  },\r\n    { 0x1529, \"UBIQUAM CO., LTD.\"  },\r\n    { 0x152A, \"Thesycon Systemsoftware & Consulting GmbH\"  },\r\n    { 0x152B, \"MIR-Medical International Research\"  },\r\n    { 0x152C, \"titel++\"  },\r\n    { 0x152D, \"JMicron Technology Corp.\"  },\r\n    { 0x152E, \"HLDS (Hitachi-LG Data Storage, Inc.)\"  },\r\n    { 0x152F, \"PRO-MECH CORPORATION\"  },\r\n    { 0x1530, \"Martsoft Corp.\"  },\r\n    { 0x1531, \"MICRODIA Ltd.\"  },\r\n    { 0x1532, \"Razer (Asia-Pacific) Pte Ltd.\"  },\r\n    { 0x1533, \"AEPTEC Microsystems, Inc.\"  },\r\n    { 0x1534, \"Advanced Research Corporation\"  },\r\n    { 0x1535, \"Practical Engineering Incorporated\"  },\r\n    { 0x1536, \"Neonode Technologies AB\"  },\r\n    { 0x1537, \"Power Up Manufacturing\"  },\r\n    { 0x1538, \"IES Elektronikentwicklung\"  },\r\n    { 0x1539, \"AFG-Engineering GmbH\"  },\r\n    { 0x153A, \"WMS Gaming Inc.\"  },\r\n    { 0x153B, \"ERCO Leuchten GmbH\"  },\r\n    { 0x153C, \"Guger Technologies OEG\"  },\r\n    { 0x153D, \"Adam Tech\"  },\r\n    { 0x153E, \"abKey ptd ltd.\"  },\r\n    { 0x153F, \"UNIBRAIN S.A.\"  },\r\n    { 0x1540, \"Phihong Technology Co., Ltd.\"  },\r\n    { 0x1541, \"Better Light, Inc.\"  },\r\n    { 0x1542, \"Gemini Industries, Inc.\"  },\r\n    { 0x1543, \"Buxco Research Systems\"  },\r\n    { 0x1544, \"Alphamosaic Ltd.\"  },\r\n    { 0x1545, \"Kistler Instrumente AG\"  },\r\n    { 0x1546, \"u-blox AG\"  },\r\n    { 0x1547, \"S. Goers IT-Solutions\"  },\r\n    { 0x1548, \"Centrepoint Technologies\"  },\r\n    { 0x1549, \"Beamex Oy Ab\"  },\r\n    { 0x154A, \"ID Innovations Incorporated\"  },\r\n    { 0x154B, \"PNY Technologies Inc.\"  },\r\n    { 0x154C, \"AutoXray Inc.\"  },\r\n    { 0x154D, \"Rapid Conn, Connect County Holdings Bhd\"  },\r\n    { 0x154E, \"D & M Holdings, Inc.\"  },\r\n    { 0x154F, \"Shandong New Beiyang Information Technology Co., Ltd.\"  },\r\n    { 0x1550, \"Cardinal Health, Inc.\"  },\r\n    { 0x1551, \"SAIC/IISBU\"  },\r\n    { 0x1552, \"DALLAB (M) SDN BHD (587734-A)\"  },\r\n    { 0x1553, \"Raytheon Commercial Infrared\"  },\r\n    { 0x1554, \"Prolink Microsystems Corporation\"  },\r\n    { 0x1555, \"OWEN Ltd.\"  },\r\n    { 0x1556, \"CERN\"  },\r\n    { 0x1557, \"OQO\"  },\r\n    { 0x1558, \"Microbus Designs Ltd.\"  },\r\n    { 0x1559, \"The Toro Company\"  },\r\n    { 0x155A, \"ELDAT GmbH\"  },\r\n    { 0x155B, \"Shanghai Huahong Integrated Circuit Co., Ltd.\"  },\r\n    { 0x155C, \"Meyers Technology\"  },\r\n    { 0x155D, \"National Rejectors, Inc. GmbH\"  },\r\n    { 0x155E, \"DUPLO SEIKO CORPORATION\"  },\r\n    { 0x155F, \"Cobra Electronics Corporation\"  },\r\n    { 0x1560, \"Supra, A UTC Fire & Security Company\"  },\r\n    { 0x1561, \"LaunchPadOffice Inc.\"  },\r\n    { 0x1562, \"Infowize Technologies Corporation\"  },\r\n    { 0x1563, \"Micronet Corporation\"  },\r\n    { 0x1564, \"Gizmondo Europe Ltd.\"  },\r\n    { 0x1565, \"Advance Modules\"  },\r\n    { 0x1566, \"WIN ACCORD LTD.\"  },\r\n    { 0x1567, \"MUTOH Industries Ltd.\"  },\r\n    { 0x1568, \"Sunf Pu Technology (Dong-Guan) Co., Ltd.\"  },\r\n    { 0x1569, \"Mad City Labs, Inc.\"  },\r\n    { 0x156A, \"Logical Solutions, Inc.\"  },\r\n    { 0x156B, \"Cairn Research Ltd.\"  },\r\n    { 0x156C, \"Meade Instruments Corp.\"  },\r\n    { 0x156D, \"OMICRON electronics GmbH\"  },\r\n    { 0x156E, \"MVox Electronics\"  },\r\n    { 0x156F, \"Quantum Corporation\"  },\r\n    { 0x1570, \"ALLTOP TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1571, \"NIKON-TRIMBLE CO., LTD.\"  },\r\n    { 0x1572, \"Ricreations, Inc.\"  },\r\n    { 0x1573, \"Gradiente Eletronica S.A.\"  },\r\n    { 0x1574, \"HKW-Elektronik GmbH\"  },\r\n    { 0x1575, \"Video Associates Labs, Inc.\"  },\r\n    { 0x1576, \"Maretron\"  },\r\n    { 0x1577, \"MIYUKI ELEX CO., LTD.\"  },\r\n    { 0x1578, \"Beijing Huaqi Information Digital Technology Co., Ltd.\"  },\r\n    { 0x1579, \"Reputed Industrial Company Limited\"  },\r\n    { 0x157A, \"Lowrance Electronics, Inc.\"  },\r\n    { 0x157B, \"Ketron SRL\"  },\r\n    { 0x157C, \"Eurosoft (UK) Ltd.\"  },\r\n    { 0x157D, \"Tokyo Sokuteikizai Co., Ltd.\"  },\r\n    { 0x157E, \"U-MEDIA Communications, Inc.\"  },\r\n    { 0x157F, \"Levon Limited\"  },\r\n    { 0x1580, \"Real Time Logic, Inc.\"  },\r\n    { 0x1581, \"IGB Communication Co., Ltd.\"  },\r\n    { 0x1582, \"Asia Pacifc Microsystems, Inc.\"  },\r\n    { 0x1583, \"EUCHNER GmbH & Co. KG\"  },\r\n    { 0x1584, \"Prueftechnik AG\"  },\r\n    { 0x1585, \"IKeyInfinity Inc.\"  },\r\n    { 0x1586, \"Palconn Technology Co., Ltd.\"  },\r\n    { 0x1587, \"SMA Solar Technology AG\"  },\r\n    { 0x1588, \"Fine Instruments Corporation\"  },\r\n    { 0x1589, \"Arcus Technology Inc.\"  },\r\n    { 0x158A, \"BOBE Industrie-Elektronik\"  },\r\n    { 0x158B, \"Righttag Inc.\"  },\r\n    { 0x158C, \"LINFOS CO., LTD.\"  },\r\n    { 0x158D, \"Oakley Inc.\"  },\r\n    { 0x158E, \"Acterna Germany GmbH\"  },\r\n    { 0x158F, \"Tai Yip Electrical Co., Ltd.\"  },\r\n    { 0x1590, \"Onsu Data Telecommunication Technology (Shenzhen) Fty.\"  },\r\n    { 0x1591, \"Advanced Product Design & Mfg. Inc.\"  },\r\n    { 0x1592, \"Tokyo Drawing Ltd.\"  },\r\n    { 0x1593, \"Vector International bvba\"  },\r\n    { 0x1594, \"Lockheed Martin Missiles & Fire Control\"  },\r\n    { 0x1595, \"Flexiworld Technologies, Inc.\"  },\r\n    { 0x1596, \"Kilodyne LLC\"  },\r\n    { 0x1597, \"KCodes Corporation\"  },\r\n    { 0x1598, \"Kunshan Guoji Electronics Co., Ltd.\"  },\r\n    { 0x1599, \"ANRITSU METER CO., LTD.\"  },\r\n    { 0x159A, \"SkuTek Instrumentation\"  },\r\n    { 0x159B, \"Zitte Corporation\"  },\r\n    { 0x159C, \"Binary Acoustic Technology\"  },\r\n    { 0x159D, \"Boone Cable Works & Electronics\"  },\r\n    { 0x159E, \"SmartSwing, Inc.\"  },\r\n    { 0x159F, \"Beijer Electronics AB\"  },\r\n    { 0x15A0, \"Zarlink Semiconductor\"  },\r\n    { 0x15A1, \"Nicety Technologies Inc.\"  },\r\n    { 0x15A2, \"Freescale Semiconductor, Inc.\"  },\r\n    { 0x15A3, \"Larson Davis, Inc.\"  },\r\n    { 0x15A4, \"Afa Technologies, Inc.\"  },\r\n    { 0x15A5, \"CIT Engineering NV\"  },\r\n    { 0x15A6, \"Unicos Corporation\"  },\r\n    { 0x15A7, \"APPSware Wireless LLC dba Apriva\"  },\r\n    { 0x15A8, \"Shen Zhen Teamspower Electronics Co., Ltd.\"  },\r\n    { 0x15A9, \"Gemtek Technology Co., Ltd.\"  },\r\n    { 0x15AA, \"GuangDong Ya Lian Technology Co., Ltd\"  },\r\n    { 0x15AB, \"Virgin HealthMiles, Inc.\"  },\r\n    { 0x15AC, \"Smartware\"  },\r\n    { 0x15AD, \"Bleile Datentechnik GmbH\"  },\r\n    { 0x15AE, \"KAYSER-THREDE GMBH\"  },\r\n    { 0x15AF, \"Jenaer Antriebstechnik GmbH\"  },\r\n    { 0x15B0, \"Pacific Instruments, Inc.\"  },\r\n    { 0x15B1, \"MiTAC Technology Corporation\"  },\r\n    { 0x15B2, \"Audio Dev AB\"  },\r\n    { 0x15B3, \"GL Sciences Inc.\"  },\r\n    { 0x15B4, \"Orient Power Multimedia Ltd.\"  },\r\n    { 0x15B5, \"ANUBIS ELECTRONIC GmbH\"  },\r\n    { 0x15B6, \"Dialog Semiconductor GmbH\"  },\r\n    { 0x15B7, \"Hyper Stimulator International Pty Ltd.\"  },\r\n    { 0x15B8, \"Serome Electronics, Inc.\"  },\r\n    { 0x15B9, \"USD Corporation\"  },\r\n    { 0x15BA, \"Olimex Ltd.\"  },\r\n    { 0x15BB, \"CopyPro , Inc.\"  },\r\n    { 0x15BC, \"Daktronics Inc.\"  },\r\n    { 0x15BD, \"Sigmaelectronics Co., Ltd.\"  },\r\n    { 0x15BE, \"EssNet Interactive AB\"  },\r\n    { 0x15BF, \"ESA, Inc.\"  },\r\n    { 0x15C0, \"CJM\"  },\r\n    { 0x15C1, \"Amirix Systems Inc.\"  },\r\n    { 0x15C2, \"SoundGraph, Inc.\"  },\r\n    { 0x15C3, \"m.u.t - GmbH\"  },\r\n    { 0x15C4, \"Global Marketing Alliance, Inc.\"  },\r\n    { 0x15C5, \"Pressure Profile Systems, Inc.\"  },\r\n    { 0x15C6, \"Laboratoires MXM\"  },\r\n    { 0x15C7, \"IRI-Ubiteq, Inc.\"  },\r\n    { 0x15C8, \"KTF Technologies\"  },\r\n    { 0x15C9, \"D-Box Technologies\"  },\r\n    { 0x15CA, \"TEXTECH INTERNATIONAL LTD.\"  },\r\n    { 0x15CB, \"Activis Polska\"  },\r\n    { 0x15CC, \"GL Communications Inc.\"  },\r\n    { 0x15CD, \"DeFelsko Corporation\"  },\r\n    { 0x15CE, \"Oriental R&D Co., Ltd.\"  },\r\n    { 0x15CF, \"AVTOR Ltd..\"  },\r\n    { 0x15D0, \"AIRSTAR Inc.\"  },\r\n    { 0x15D1, \"Hokuyo Automatic Co., Ltd.\"  },\r\n    { 0x15D2, \"REA Elektronik GmbH\"  },\r\n    { 0x15D3, \"Symmetric Research\"  },\r\n    { 0x15D4, \"Opinionmeter International, Ltd.\"  },\r\n    { 0x15D5, \"Coulomb Electronics Ltd.\"  },\r\n    { 0x15D6, \"Fitness Expert\"  },\r\n    { 0x15D7, \"amaxa GmbH\"  },\r\n    { 0x15D8, \"Grundig Business Systems GmbH\"  },\r\n    { 0x15D9, \"Apexone Microelectronics Inc.\"  },\r\n    { 0x15DA, \"Cooper - Atkins Corporation\"  },\r\n    { 0x15DB, \"Philip Harris Education\"  },\r\n    { 0x15DC, \"Hynix Semiconductor Inc.\"  },\r\n    { 0x15DD, \"Axona Limited\"  },\r\n    { 0x15DE, \"Spatial Freedom, Inc.\"  },\r\n    { 0x15DF, \"Helmut Fischer GmbH + Co. KG\"  },\r\n    { 0x15E0, \"Seong Ji Industrial Co., Ltd.\"  },\r\n    { 0x15E1, \"RSA Security Inc.\"  },\r\n    { 0x15E2, \"Bionopoly LLC\"  },\r\n    { 0x15E3, \"NEURICAM SPA\"  },\r\n    { 0x15E4, \"Numark Industries\"  },\r\n    { 0x15E5, \"Micro Systems Inc.\"  },\r\n    { 0x15E6, \"Turnkey Ltd.\"  },\r\n    { 0x15E7, \"Media Systems Ltd.\"  },\r\n    { 0x15E8, \"Micro Tools Inc.\"  },\r\n    { 0x15E9, \"Pacific Digital Corp.\"  },\r\n    { 0x15EA, \"C-guys Inc.\"  },\r\n    { 0x15EB, \"VIA Telecom\"  },\r\n    { 0x15EC, \"Belcarra Technologies Corp.\"  },\r\n    { 0x15ED, \"UCA Technology Inc.\"  },\r\n    { 0x15EE, \"Quorum Communications, Inc.\"  },\r\n    { 0x15EF, \"MSilicon Electronics, Inc.\"  },\r\n    { 0x15F0, \"Technex Lab Co., Ltd.\"  },\r\n    { 0x15F1, \"Mortara Instrument, Inc.\"  },\r\n    { 0x15F2, \"Chyron Corp.\"  },\r\n    { 0x15F3, \"AquaCube Inc.\"  },\r\n    { 0x15F4, \"Computer & Entertainment, Inc.\"  },\r\n    { 0x15F5, \"Mobitek Communication Corp.\"  },\r\n    { 0x15F6, \"ASICS World Services Ltd.\"  },\r\n    { 0x15F7, \"HANTEL CO., LTD.\"  },\r\n    { 0x15F8, \"Vianet, Inc.\"  },\r\n    { 0x15F9, \"SunCorp Industrial Limited\"  },\r\n    { 0x15FA, \"Department of Defense\"  },\r\n    { 0x15FB, \"R-Quest Technologies , LLC\"  },\r\n    { 0x15FC, \"Humen Xintai Electrical Wires Factory\"  },\r\n    { 0x15FD, \"XEMAX Co., Ltd.\"  },\r\n    { 0x15FE, \"Bio-Rad Laboratories Deeside\"  },\r\n    { 0x15FF, \"Heartsine Technologies Ltd.\"  },\r\n    { 0x1600, \"Monisys Limited\"  },\r\n    { 0x1601, \"Avenues in Leather\"  },\r\n    { 0x1602, \"CompUSA Inc.\"  },\r\n    { 0x1603, \"ERGODEX Corp.\"  },\r\n    { 0x1604, \"Kyokko Seiko Co., Ltd.\"  },\r\n    { 0x1605, \"Acces I/O Products, Inc.\"  },\r\n    { 0x1606, \"UMAX Data Systems Inc.\"  },\r\n    { 0x1607, \"ESE Corporate\"  },\r\n    { 0x1608, \"Inside Out Networks, a division of Digi International\"  },\r\n    { 0x1609, \"K-byte (ACI Group)\"  },\r\n    { 0x160A, \"VIA Networking Technologies, Inc.\"  },\r\n    { 0x160B, \"CSI Wireless Inc.\"  },\r\n    { 0x160C, \"Shanghai Tiananxin Information & Tech., Co., Ltd.\"  },\r\n    { 0x160D, \"Samtec\"  },\r\n    { 0x160E, \"INRO Consultants Inc.\"  },\r\n    { 0x160F, \"Strand Lighting Limited\"  },\r\n    { 0x1610, \"Q-Sense AB\"  },\r\n    { 0x1611, \"Vita-Mix Corporation\"  },\r\n    { 0x1612, \"Soft DB Inc.\"  },\r\n    { 0x1613, \"Airconnect Solutions (Asia) Ltd.\"  },\r\n    { 0x1614, \"Amoi Electronics Co., Ltd.\"  },\r\n    { 0x1615, \"Rock Data Services Ltd.\"  },\r\n    { 0x1616, \"Cute Mobile Corp.\"  },\r\n    { 0x1617, \"Navman\"  },\r\n    { 0x1618, \"Redpine Signals, Inc.\"  },\r\n    { 0x1619, \"L & K Precision Technology Co., Ltd.\"  },\r\n    { 0x161A, \"Celeraise Investments Ltd.\"  },\r\n    { 0x161B, \"MYCOM, INC.\"  },\r\n    { 0x161C, \"DigiTech Systems Co., Ltd.\"  },\r\n    { 0x161D, \"Delfin Technologies Ltd.\"  },\r\n    { 0x161E, \"Aerotech Inc.\"  },\r\n    { 0x161F, \"Prosisa International LLC\"  },\r\n    { 0x1620, \"Accesstek Inc.\"  },\r\n    { 0x1621, \"Wionics Research\"  },\r\n    { 0x1622, \"California Instruments\"  },\r\n    { 0x1623, \"Mindtech Limited\"  },\r\n    { 0x1624, \"AIOI Systems, USA Corp.\"  },\r\n    { 0x1625, \"ViaSat UK\"  },\r\n    { 0x1626, \"Advance Data Technology Corporation\"  },\r\n    { 0x1627, \"IPextreme, Inc.\"  },\r\n    { 0x1628, \"Stonestreet One, Inc.\"  },\r\n    { 0x1629, \"Erae Electronics\"  },\r\n    { 0x162A, \"Airgo Networks Inc.\"  },\r\n    { 0x162B, \"Acksys\"  },\r\n    { 0x162C, \"Ecler Laboratorio de Electroacustica S.A.\"  },\r\n    { 0x162D, \"Control Instruments Development (Pty) Ltd.\"  },\r\n    { 0x162E, \"Joytech Europe Ltd.\"  },\r\n    { 0x162F, \"WiQuest Communications, Inc.\"  },\r\n    { 0x1630, \"QformX\"  },\r\n    { 0x1631, \"Focus Enhancements\"  },\r\n    { 0x1632, \"Data Ray Inc.\"  },\r\n    { 0x1633, \"AIM GmbH\"  },\r\n    { 0x1634, \"ABB Switzerland Ltd.\"  },\r\n    { 0x1635, \"Doble Engineering Co.\"  },\r\n    { 0x1636, \"Kobe-Addtech Co., Ltd.\"  },\r\n    { 0x1637, \"LZAE LUMEL SA\"  },\r\n    { 0x1638, \"Skyworks Solutions\"  },\r\n    { 0x1639, \"BeRiver Electronics Co., Ltd.\"  },\r\n    { 0x163A, \"Traficon N.V.\"  },\r\n    { 0x163B, \"Controlled Speed Engineering Ltd.\"  },\r\n    { 0x163C, \"Watchdata System Co., Ltd.\"  },\r\n    { 0x163D, \"Million Tech Dev. Ltd.\"  },\r\n    { 0x163E, \"Dezhou HongJu Communication Technology Co., Ltd.\"  },\r\n    { 0x163F, \"AVEX Technologies, Inc.\"  },\r\n    { 0x1640, \"M3 Electronics, Inc.\"  },\r\n    { 0x1641, \"eMagin Corporation\"  },\r\n    { 0x1642, \"AquaSensors LLC\"  },\r\n    { 0x1643, \"Sanwa Newtec Co., Ltd.\"  },\r\n    { 0x1644, \"Active Technologies SRL\"  },\r\n    { 0x1645, \"Smiths Heimann Biometrics GmbH\"  },\r\n    { 0x1646, \"Altronic, Inc.\"  },\r\n    { 0x1647, \"Horizon Navigation, Inc.\"  },\r\n    { 0x1648, \"Wood Head Software & Electronics\"  },\r\n    { 0x1649, \"Softec Microsystems\"  },\r\n    { 0x164A, \"ChipX\"  },\r\n    { 0x164B, \"Lytech Technology Inc.\"  },\r\n    { 0x164C, \"Matrix Vision GmbH\"  },\r\n    { 0x164D, \"DASAN Networks, Inc.\"  },\r\n    { 0x164E, \"Picotest Corp.\"  },\r\n    { 0x164F, \"Kinkei System Co., Ltd.\"  },\r\n    { 0x1650, \"Remopro Technology Inc.\"  },\r\n    { 0x1651, \"PACOMP\"  },\r\n    { 0x1652, \"EFull Tech. Corp. Ltd.\"  },\r\n    { 0x1653, \"Nissho Electronics Co., Ltd.\"  },\r\n    { 0x1654, \"Stamer Musikanlagen GmbH\"  },\r\n    { 0x1655, \"Dtron Co., Ltd.\"  },\r\n    { 0x1656, \"QSC Audio Products, Inc.\"  },\r\n    { 0x1657, \"Struck Innovative Systeme GmbH\"  },\r\n    { 0x1658, \"Grayhill Inc.\"  },\r\n    { 0x1659, \"Lathem Time Corp.\"  },\r\n    { 0x165A, \"E.D.P. SRL\"  },\r\n    { 0x165B, \"Frontier Design Group\"  },\r\n    { 0x165C, \"Kondo Kagaku Co., Ltd.\"  },\r\n    { 0x165D, \"Orange Tree Technologies Ltd.\"  },\r\n    { 0x165E, \"Pangolin\"  },\r\n    { 0x165F, \"Ansync Inc.\"  },\r\n    { 0x1660, \"Creatix Polymedia GmbH\"  },\r\n    { 0x1661, \"DVS Korea Co., Ltd.\"  },\r\n    { 0x1662, \"Positivo Informatica LTDA\"  },\r\n    { 0x1663, \"Sercel, Inc.\"  },\r\n    { 0x1664, \"ARGOX INFORMATION CO., LTD.\"  },\r\n    { 0x1665, \"General Dynamics Canada\"  },\r\n    { 0x1666, \"Vanguard Instruments Co., Inc.\"  },\r\n    { 0x1667, \"GIGA-TMS, INC.\"  },\r\n    { 0x1668, \"Actiontec Electronics, Inc.\"  },\r\n    { 0x1669, \"PiKRON s.r.o.\"  },\r\n    { 0x166A, \"Clipsal Integrated Systems\"  },\r\n    { 0x166B, \"PedalPax Corporation\"  },\r\n    { 0x166C, \"Technology Driven Solutions Ltd\"  },\r\n    { 0x166D, \"MCS Logic Inc.\"  },\r\n    { 0x166E, \"SerComm Corporation\"  },\r\n    { 0x166F, \"Idetech Europe S.A.\"  },\r\n    { 0x1670, \"Hach Company\"  },\r\n    { 0x1671, \"Telular Corporation\"  },\r\n    { 0x1672, \"MBS GmbH\"  },\r\n    { 0x1673, \"ROBOTIKER\"  },\r\n    { 0x1674, \"Pantone, Inc.\"  },\r\n    { 0x1675, \"SE-IR Corporation\"  },\r\n    { 0x1676, \"I-Ware Laboratory Co., Ltd.\"  },\r\n    { 0x1677, \"China Integrated Circuit Design Corp., Ltd.\"  },\r\n    { 0x1678, \"Matsunichi Information Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1679, \"Total Phase\"  },\r\n    { 0x167A, \"USBWARE\"  },\r\n    { 0x167B, \"Pure Digital Technologies\"  },\r\n    { 0x167C, \"Vionics\"  },\r\n    { 0x167D, \"SIM Security & Electronic System GmbH\"  },\r\n    { 0x167E, \"Videa Technology Inc.\"  },\r\n    { 0x167F, \"Actigraph, LLC\"  },\r\n    { 0x1680, \"KaVo Dental GmbH\"  },\r\n    { 0x1681, \"Prevo Technologies, Inc.\"  },\r\n    { 0x1682, \"Maxwise Production Enterprise Ltd.\"  },\r\n    { 0x1683, \"DualCor Technologies, Inc.\"  },\r\n    { 0x1684, \"Godspeed Computer Corp.\"  },\r\n    { 0x1685, \"Tanic Electroics Ltd.\"  },\r\n    { 0x1686, \"ZOOM Corporation\"  },\r\n    { 0x1687, \"Kingmax Digital Inc.\"  },\r\n    { 0x1688, \"AerotechTelub AB\"  },\r\n    { 0x1689, \"Griffin International Companies, Inc.\"  },\r\n    { 0x168A, \"Veeco Instruments\"  },\r\n    { 0x168B, \"BTC Secu Co., Ltd.\"  },\r\n    { 0x168C, \"Tabor Electroics Ltd.\"  },\r\n    { 0x168D, \"YSI, Inc.\"  },\r\n    { 0x168E, \"iMetrikus Inc.\"  },\r\n    { 0x168F, \"ETA S.A. Manufacture Horlogere Suisse\"  },\r\n    { 0x1690, \"Simple Solutions\"  },\r\n    { 0x1691, \"Landers Instruments\"  },\r\n    { 0x1692, \"Weatherford\"  },\r\n    { 0x1693, \"Zultys Technologies\"  },\r\n    { 0x1694, \"Cassidian Communications\"  },\r\n    { 0x1695, \"FATAR, S.r.l.\"  },\r\n    { 0x1696, \"Hitachi Advanced Digital, Inc.\"  },\r\n    { 0x1697, \"VTEC TEST, INC.\"  },\r\n    { 0x1698, \"Eurosmart\"  },\r\n    { 0x1699, \"United RadioTek Inc.\"  },\r\n    { 0x169A, \"Ten X Technology Inc.\"  },\r\n    { 0x169B, \"aitronic GmbH\"  },\r\n    { 0x169C, \"DMS\"  },\r\n    { 0x169E, \"Groupics.com, Inc.\"  },\r\n    { 0x169F, \"Monolith Inc.\"  },\r\n    { 0x16A0, \"Real Thoughts GmbH\"  },\r\n    { 0x16A1, \"Trilithic, Inc.\"  },\r\n    { 0x16A2, \"Sypris Test and Measurement (FW Bell)\"  },\r\n    { 0x16A3, \"B & W Tek Inc.\"  },\r\n    { 0x16A4, \"Sagutech Microsystems\"  },\r\n    { 0x16A5, \"Shenzhen Zhengerya Technology Co., Ltd.\"  },\r\n    { 0x16A6, \"UNIGRAF OY\"  },\r\n    { 0x16A7, \"Sauer-Danfoss\"  },\r\n    { 0x16A8, \"Nice Systems\"  },\r\n    { 0x16A9, \"Worth-Pfaff Innovations, Inc.\"  },\r\n    { 0x16AA, \"Symtx Inc.\"  },\r\n    { 0x16AB, \"InnoWireless Co. Ltd.\"  },\r\n    { 0x16AC, \"Dongguan ChingLung Wire & Cable Co., Ltd.\"  },\r\n    { 0x16AD, \"Siemens VDO Trading GmbH\"  },\r\n    { 0x16AE, \"ELSA Japan Inc.\"  },\r\n    { 0x16AF, \"Intelligent Mechatronic Systems\"  },\r\n    { 0x16B0, \"Infosight Corp.\"  },\r\n    { 0x16B1, \"Cami Research Inc.\"  },\r\n    { 0x16B2, \"Bruxton Corporation\"  },\r\n    { 0x16B3, \"Eizoken Inc.\"  },\r\n    { 0x16B4, \"Digital Cube\"  },\r\n    { 0x16B5, \"PerSen Technologies, Inc.\"  },\r\n    { 0x16B6, \"Nexus Technology Inc.\"  },\r\n    { 0x16B7, \"Pulsafeeder Inc.\"  },\r\n    { 0x16B8, \"Honeywell Life Safety\"  },\r\n    { 0x16B9, \"Origin Technologies Limited\"  },\r\n    { 0x16BA, \"SmarTec\"  },\r\n    { 0x16BB, \"Tomra Systems ASA\"  },\r\n    { 0x16BC, \"JOBO AG\"  },\r\n    { 0x16BD, \"Leica Geosystems AG\"  },\r\n    { 0x16BE, \"RyuSyo Industrial Co., Ltd.\"  },\r\n    { 0x16BF, \"CAST, INC.\"  },\r\n    { 0x16C0, \"Van Ooijen Technische Informatica\"  },\r\n    { 0x16C1, \"Lucas-Nuelle GmbH\"  },\r\n    { 0x16C2, \"Amphenol-Data Telecom\"  },\r\n    { 0x16C3, \"Nihon Kaiheiki Ind. Co., Ltd.\"  },\r\n    { 0x16C4, \"SavaJe Technologies, Inc.\"  },\r\n    { 0x16C5, \"Cryptek Inc.\"  },\r\n    { 0x16C6, \"NDS Surgical Imaging, LLC\"  },\r\n    { 0x16C7, \"Crystal Technology, Inc.\"  },\r\n    { 0x16C8, \"Technische Universiteit Eindhoven\"  },\r\n    { 0x16C9, \"OCT Co., Ltd.\"  },\r\n    { 0x16CA, \"Wireless Cables Inc.\"  },\r\n    { 0x16CB, \"Highwater Designs Limited\"  },\r\n    { 0x16CC, \"silex technology, Inc.\"  },\r\n    { 0x16CD, \"Brian Moore Guitars, Inc.\"  },\r\n    { 0x16CE, \"IPFlex Inc.\"  },\r\n    { 0x16CF, \"YAZAKI PARTS CO., LTD.\"  },\r\n    { 0x16D1, \"SUPREMA, INC.\"  },\r\n    { 0x16D2, \"TOMEY\"  },\r\n    { 0x16D3, \"Frontline Test Equipment, Inc.\"  },\r\n    { 0x16D4, \"SRTechnologies\"  },\r\n    { 0x16D5, \"AnyDATA Corporation\"  },\r\n    { 0x16D6, \"Jablotron\"  },\r\n    { 0x16D7, \"Aprilis, Inc.\"  },\r\n    { 0x16D8, \"CMOTECH CO., LTD.\"  },\r\n    { 0x16D9, \"A7 Engineering, Inc.\"  },\r\n    { 0x16DA, \"Linkam Scientific Instruments Ltd.\"  },\r\n    { 0x16DB, \"Eridon Corporation\"  },\r\n    { 0x16DC, \"W-IE-NE-R, Plein & Baus GmbH\"  },\r\n    { 0x16DD, \"YOSHIDA SEIKI CO., LTD.\"  },\r\n    { 0x16DE, \"Schneider Electric\"  },\r\n    { 0x16DF, \"King Billion Electronics Co., Ltd.\"  },\r\n    { 0x16E0, \"Lumex Ltd.\"  },\r\n    { 0x16E1, \"Bed Check Corporation\"  },\r\n    { 0x16E2, \"Hitachi I E Systems Co., Ltd.\"  },\r\n    { 0x16E3, \"ITM Inc.\"  },\r\n    { 0x16E4, \"Franklin Electric Co., Inc.\"  },\r\n    { 0x16E5, \"TOKYO KEIKI RAIL TECHNO INC.\"  },\r\n    { 0x16E6, \"Diginfo Technology Corporation\"  },\r\n    { 0x16E7, \"United Keys, Inc.\"  },\r\n    { 0x16E8, \"Frontier Information Enterprise, Inc.\"  },\r\n    { 0x16E9, \"Dr. Gal Ben-David\"  },\r\n    { 0x16EA, \"Avionica, Inc.\"  },\r\n    { 0x16EB, \"Helvar\"  },\r\n    { 0x16EC, \"ASAHI GLASS CO., LTD.\"  },\r\n    { 0x16ED, \"Parker Vision Inc.\"  },\r\n    { 0x16EE, \"Ryvor Corp.\"  },\r\n    { 0x16EF, \"Global Safety & Security Solutions OY\"  },\r\n    { 0x16F0, \"GN ReSound\"  },\r\n    { 0x16F1, \"Versus Technology, Inc.\"  },\r\n    { 0x16F2, \"St. Jude Medical AB\"  },\r\n    { 0x16F3, \"Hammer Storage/Bell Microproducts\"  },\r\n    { 0x16F4, \"Lineeye Co., Ltd.\"  },\r\n    { 0x16F5, \"Futurelogic Inc.\"  },\r\n    { 0x16F6, \"Shin Tek Inc.\"  },\r\n    { 0x16F7, \"Japan Gals Co., Ltd.\"  },\r\n    { 0x16F8, \"Ever Bright Wire Factory\"  },\r\n    { 0x16F9, \"Astrosys International Limited\"  },\r\n    { 0x16FA, \"Shachihata Inc.\"  },\r\n    { 0x16FB, \"MICRONIX CORPORATION\"  },\r\n    { 0x16FC, \"TRICOM TECHNOLOGIES, INC.\"  },\r\n    { 0x16FD, \"Reakin Technology Corporation\"  },\r\n    { 0x16FE, \"Su Zhou Song Qing Electronical Co., Ltd.\"  },\r\n    { 0x16FF, \"Ultimate Technology Corp.\"  },\r\n    { 0x1700, \"Hunt Engineering (UK) Ltd.\"  },\r\n    { 0x1701, \"Peyroutet Telecom\"  },\r\n    { 0x1702, \"Softcare Ltd.\"  },\r\n    { 0x1703, \"NormSoft, Inc.\"  },\r\n    { 0x1704, \"ANIMATICS CORP.\"  },\r\n    { 0x1705, \"Aerosonic Corporation\"  },\r\n    { 0x1706, \"BlueView Technologies, Inc.\"  },\r\n    { 0x1707, \"ARTIMI\"  },\r\n    { 0x1708, \"Mibudenki Industrial Co., Ltd.\"  },\r\n    { 0x1709, \"Sanmina-SCI\"  },\r\n    { 0x170A, \"MAXTEK, INC.\"  },\r\n    { 0x170B, \"Phonic Corp.\"  },\r\n    { 0x170C, \"BlueTree Wireless Data\"  },\r\n    { 0x170D, \"Avnera\"  },\r\n    { 0x170E, \"Iris Corporation Berhad\"  },\r\n    { 0x170F, \"UbiBro Technolgies Inc.\"  },\r\n    { 0x1710, \"AZIO Corporation\"  },\r\n    { 0x1711, \"Leica Microsystems CMS GmbH\"  },\r\n    { 0x1712, \"Fujitsu LSI Technology Ltd.\"  },\r\n    { 0x1713, \"Enter Tech Co., Ltd\"  },\r\n    { 0x1714, \"iCRco\"  },\r\n    { 0x1715, \"NL Technology\"  },\r\n    { 0x1716, \"LHR Technologies\"  },\r\n    { 0x1717, \"Formats Unlimited, Inc.\"  },\r\n    { 0x1718, \"Mobile Doctor Co., Ltd.\"  },\r\n    { 0x1719, \"American Technology Corp.\"  },\r\n    { 0x171A, \"PSi Printer Systems international GmbH\"  },\r\n    { 0x171B, \"NT Ware Systemprogrammierung GmbH\"  },\r\n    { 0x171C, \"IER\"  },\r\n    { 0x171E, \"PACIFIC CORPORATION\"  },\r\n    { 0x171F, \"CHIPNUTS TECHNOLOGY INC.\"  },\r\n    { 0x1720, \"Innova Electronics Corp.\"  },\r\n    { 0x1721, \"ELAD SRL\"  },\r\n    { 0x1722, \"Axicon Auto ID LTD\"  },\r\n    { 0x1723, \"Datatronics Technology, Inc\"  },\r\n    { 0x1724, \"Lumenera Corporation\"  },\r\n    { 0x1725, \"HI-TECH Software\"  },\r\n    { 0x1726, \"Axesstel, Inc.\"  },\r\n    { 0x1727, \"RiCHIP Incorporated\"  },\r\n    { 0x1728, \"BYTE TOOLS INC.\"  },\r\n    { 0x1729, \"CONSULTRONICS EUROPE LTD.\"  },\r\n    { 0x172A, \"wenglor sensoric gmbh\"  },\r\n    { 0x172B, \"CompuSoft A/S\"  },\r\n    { 0x172C, \"Silicon Optix\"  },\r\n    { 0x172D, \"AccFast Technology Corp.\"  },\r\n    { 0x172E, \"ELECTION SYSTEMS & Software\"  },\r\n    { 0x172F, \"WALTOP International Corporation\"  },\r\n    { 0x1730, \"MERCURY\"  },\r\n    { 0x1731, \"DATA DISPLAY AG\"  },\r\n    { 0x1732, \"NETENRICH INC.\"  },\r\n    { 0x1733, \"NUBYTECH INC.\"  },\r\n    { 0x1734, \"IPdrum AB\"  },\r\n    { 0x1735, \"Satloc LLC (CSI Wireless)\"  },\r\n    { 0x1736, \"CANON IMAGING SYSTEMS INC.\"  },\r\n    { 0x1737, \"Hong Kong Applied Science and Technology Research Inst.\"  },\r\n    { 0x1738, \"Asicen Technology Corp.\"  },\r\n    { 0x1739, \"Radiant Technologies Inc.\"  },\r\n    { 0x173A, \"F. Hoffmann-La Roche AG\"  },\r\n    { 0x173B, \"Cadillac Jack Inc.\"  },\r\n    { 0x173C, \"Signalcraft Technologies Inc.\"  },\r\n    { 0x173D, \"Great Pleasure Electronics Co. LTD.\"  },\r\n    { 0x173E, \"Devlin Electronics Ltd.\"  },\r\n    { 0x173F, \"Peyer Engineering\"  },\r\n    { 0x1740, \"Senao International Co., Ltd.\"  },\r\n    { 0x1741, \"Techino Science Co., Ltd.\"  },\r\n    { 0x1742, \"Nippon Chemi-Con Corp.\"  },\r\n    { 0x1743, \"General Atomics\"  },\r\n    { 0x1744, \"Sanwa Electronic Instrument Co. Ltd.\"  },\r\n    { 0x1745, \"Video Simplex, Inc.\"  },\r\n    { 0x1746, \"Edge Products\"  },\r\n    { 0x1747, \"CML MICROCIRCUITS (UK) LTD\"  },\r\n    { 0x1748, \"MQP Electronics Ltd.\"  },\r\n    { 0x1749, \"MAGO MOBILE LTD\"  },\r\n    { 0x174A, \"Endress + Hauser\"  },\r\n    { 0x174B, \"BARACODA\"  },\r\n    { 0x174C, \"ASMedia Technology Inc.\"  },\r\n    { 0x174D, \"Broadcast System & Design ApS\"  },\r\n    { 0x174E, \"Xi'an Tongshi Data Co., Ltd.\"  },\r\n    { 0x174F, \"D-MAX Technology Co., Ltd.\"  },\r\n    { 0x1750, \"Hirschmann Automation and Control GmbH\"  },\r\n    { 0x1751, \"EMPIRISOFT CORPORATION\"  },\r\n    { 0x1752, \"Liyitec Incorporated\"  },\r\n    { 0x1753, \"Tecvan Informatica LTDA\"  },\r\n    { 0x1754, \"GERSTEL GmbH & Co. KG\"  },\r\n    { 0x1755, \"Electronics and Telecommunication Research Institute\"  },\r\n    { 0x1756, \"ENENSYS Technologies\"  },\r\n    { 0x1757, \"ST-MICHAEL STRATEGIES\"  },\r\n    { 0x1758, \"FUTURECOM SYSTEMS GROUP INC.\"  },\r\n    { 0x1759, \"LucidPort Technology, Inc.\"  },\r\n    { 0x175A, \"Lantronix\"  },\r\n    { 0x175B, \"Dongguan Init Technology Co., Ltd.\"  },\r\n    { 0x175C, \"Isolcell Italia SpA\"  },\r\n    { 0x175D, \"Caterpillar Inc.\"  },\r\n    { 0x175E, \"AT KidSystems Inc.\"  },\r\n    { 0x175F, \"I-BIT Corporation\"  },\r\n    { 0x1760, \"RAYLASE AG\"  },\r\n    { 0x1761, \"RC GROUP (Holdings) Limited\"  },\r\n    { 0x1763, \"USAF\"  },\r\n    { 0x1764, \"KANOMAX JAPAN INC.\"  },\r\n    { 0x1765, \"VK Corporation\"  },\r\n    { 0x1766, \"Hip Interactive Inc.\"  },\r\n    { 0x1767, \"KIS Photo Mc Group\"  },\r\n    { 0x1769, \"ARTEK Inc.\"  },\r\n    { 0x176A, \"GLOBALSAT TECHNOLOGY CORPORATION\"  },\r\n    { 0x176B, \"ATOP ELECTRONICS CO., LTD.\"  },\r\n    { 0x176C, \"Advanced Electronic Designs\"  },\r\n    { 0x176D, \"Mbridge Systems, Inc.\"  },\r\n    { 0x176E, \"UD electronic corp.\"  },\r\n    { 0x176F, \"Astralink Technology Pte Ltd\"  },\r\n    { 0x1770, \"precisionWave Corporation\"  },\r\n    { 0x1771, \"Shenzhen Alex Connector Co., Ltd.\"  },\r\n    { 0x1772, \"System Level Solutions, Inc.\"  },\r\n    { 0x1773, \"InSync Speech Technologies, Inc.\"  },\r\n    { 0x1774, \"Strawberry Linux Co., Ltd.\"  },\r\n    { 0x1775, \"RADAR-TRONIC KFT.\"  },\r\n    { 0x1776, \"HYPERLABS, Inc.\"  },\r\n    { 0x1777, \"Microscan Systems, Inc.\"  },\r\n    { 0x1778, \"PChome Online Inc.\"  },\r\n    { 0x1779, \"Optek Electronics Co., Ltd.\"  },\r\n    { 0x177A, \"Explore Semiconductor, Inc.\"  },\r\n    { 0x177B, \"Cetus Engineering\"  },\r\n    { 0x177C, \"AD Information & Communications Co., Ltd\"  },\r\n    { 0x177D, \"Delta Industrie Service\"  },\r\n    { 0x177E, \"mils electronic GmbH & Co Kg\"  },\r\n    { 0x177F, \"Sweex Europe B.V.\"  },\r\n    { 0x1780, \"TENDYRON CORPORATION\"  },\r\n    { 0x1781, \"MECANIQUE\"  },\r\n    { 0x1782, \"Spreadtrum Hong Kong Limited\"  },\r\n    { 0x1783, \"Foster Flight, Inc.\"  },\r\n    { 0x1784, \"TopSeed Technology Corp.\"  },\r\n    { 0x1785, \"CARALLON LIMITED\"  },\r\n    { 0x1786, \"Xeltek Inc.\"  },\r\n    { 0x1787, \"TRIDENT SYSTEMS, INC.\"  },\r\n    { 0x1788, \"ShenZhen Litkconn Technology Co., Ltd.\"  },\r\n    { 0x1789, \"Ascom (Schweiz) AG\"  },\r\n    { 0x178A, \"Prentke Romich Company\"  },\r\n    { 0x178B, \"Panduit Corp.\"  },\r\n    { 0x178C, \"URTEK TECHNOLOGIES INC.\"  },\r\n    { 0x178D, \"CEIVA Logic, Inc.\"  },\r\n    { 0x178E, \"Movimento Group AB\"  },\r\n    { 0x1790, \"Ueda Japan Radio Co., Ltd.\"  },\r\n    { 0x1791, \"SYNTHETIC PLANNING INDUSTRY CO., LTD.\"  },\r\n    { 0x1792, \"LINK GmbH\"  },\r\n    { 0x1793, \"Heim Systems GmbH\"  },\r\n    { 0x1794, \"MA'AGALIM COMPUTER SYSTEMS Ltd.\"  },\r\n    { 0x1795, \"INTEGRATION ASSOCIATES INCORPORATED\"  },\r\n    { 0x1796, \"Printrex, Inc.\"  },\r\n    { 0x1797, \"JALCO CO., LTD.\"  },\r\n    { 0x1798, \"TYPE TECHNOLOGY INC.\"  },\r\n    { 0x1799, \"Thales Norway AS\"  },\r\n    { 0x179A, \"Conrad Electronic GmbH\"  },\r\n    { 0x179B, \"HANDSFULL TECHNOLOGY CORP.\"  },\r\n    { 0x179C, \"Net-2Com Corporation\"  },\r\n    { 0x179D, \"Ricavision International Inc.\"  },\r\n    { 0x179E, \"Silicon Engines\"  },\r\n    { 0x179F, \"CLIQ LIMITED\"  },\r\n    { 0x17A0, \"Samson Technologies Corp.\"  },\r\n    { 0x17A1, \"Taiwan Advanced Sensors Corporation\"  },\r\n    { 0x17A2, \"Vantage Controls, Inc.\"  },\r\n    { 0x17A3, \"OnTime tek Inc.\"  },\r\n    { 0x17A4, \"Concept 2\"  },\r\n    { 0x17A5, \"Advanced Connection Technology Inc.\"  },\r\n    { 0x17A6, \"Astron Clinica Ltd.\"  },\r\n    { 0x17A7, \"MICOMSOFT CO., LTD.\"  },\r\n    { 0x17A8, \"Kamstrup A/S\"  },\r\n    { 0x17A9, \"MULTIMEDIA GAMES, INC.\"  },\r\n    { 0x17AA, \"SETEK Elektronik AB\"  },\r\n    { 0x17AB, \"i-Bulldog Co., Ltd.\"  },\r\n    { 0x17AC, \"Dengen Automation Co., Ltd.\"  },\r\n    { 0x17AD, \"TRIOC AB\"  },\r\n    { 0x17AE, \"NAD Electronics International/A Div. of Lenbrook Ind.\"  },\r\n    { 0x17AF, \"GIGABYTE Communications Inc.\"  },\r\n    { 0x17B0, \"Weinmann Geraete fuer Medizen GmbH+Co. KG\"  },\r\n    { 0x17B1, \"ViaSat, Inc.\"  },\r\n    { 0x17B2, \"Metec GmbH\"  },\r\n    { 0x17B3, \"Grey Innovation Pty., Ltd.\"  },\r\n    { 0x17B4, \"Apres Health & Fitness\"  },\r\n    { 0x17B5, \"Lunatone Industrielle Elektronik GmbH\"  },\r\n    { 0x17B6, \"Hydronix Limited\"  },\r\n    { 0x17B7, \"Sinter Information Corp.\"  },\r\n    { 0x17B8, \"Trojan Technologies Private Limited\"  },\r\n    { 0x17B9, \"Green Bit S.p.A.\"  },\r\n    { 0x17BA, \"Sauris GmbH\"  },\r\n    { 0x17BB, \"Weihai Dongxing Electronics Co., Ltd.\"  },\r\n    { 0x17BC, \"Advanced Peripherals Technologies, Inc.\"  },\r\n    { 0x17BD, \"Citron Electronic Co., Ltd.\"  },\r\n    { 0x17BE, \"Dongguan Yangming Precision of Plastic Metal Elec Co Lt\"  },\r\n    { 0x17BF, \"Ampere Inc.\"  },\r\n    { 0x17C0, \"ED Co., Ltd.\"  },\r\n    { 0x17C1, \"Sirius XM Radio\"  },\r\n    { 0x17C2, \"Ingenient Technologies\"  },\r\n    { 0x17C3, \"SGB Group Ltd.\"  },\r\n    { 0x17C4, \"VISIOWAVE SA\"  },\r\n    { 0x17C5, \"Hantle System Co., Ltd.\"  },\r\n    { 0x17C6, \"Magnetox\"  },\r\n    { 0x17C7, \"AIM Infrarot-Module GmbH\"  },\r\n    { 0x17C8, \"Ringway Tech (JiangSu) Co., Ltd.\"  },\r\n    { 0x17C9, \"Andros Incorporated\"  },\r\n    { 0x17CA, \"CyberPak Co.\"  },\r\n    { 0x17CB, \"CHINA HUAXU GOLDEN CARD CO., LTD.\"  },\r\n    { 0x17CC, \"Native Instruments Software Synthesis GmbH\"  },\r\n    { 0x17CD, \"Basler Electric\"  },\r\n    { 0x17CE, \"Keymile AG\"  },\r\n    { 0x17CF, \"Hip Hing Cable & Plug Mfy. Ltd.\"  },\r\n    { 0x17D0, \"Sanford L.P.\"  },\r\n    { 0x17D1, \"ViDisys GmbH\"  },\r\n    { 0x17D2, \"Radiometer Medical ApS\"  },\r\n    { 0x17D3, \"Korea Techtron Co., Ltd.\"  },\r\n    { 0x17D4, \"Kenetics Innovations Pte. Ltd., Singapore\"  },\r\n    { 0x17D5, \"ImageMap Inc.\"  },\r\n    { 0x17D6, \"Samsung Electronics Research Institute\"  },\r\n    { 0x17D7, \"Copley Controls Corp.\"  },\r\n    { 0x17D8, \"Rapattoni Corporation\"  },\r\n    { 0x17D9, \"Rasteme Systems Co., Ltd.\"  },\r\n    { 0x17DA, \"GEMIT GmbH\"  },\r\n    { 0x17DB, \"CYNOVE\"  },\r\n    { 0x17DC, \"Thermoteknix Systems Ltd.\"  },\r\n    { 0x17DD, \"Simply Automated, Incorporated\"  },\r\n    { 0x17DE, \"Grant Instruments\"  },\r\n    { 0x17DF, \"SOUTHWING\"  },\r\n    { 0x17E0, \"Big Sky Laser\"  },\r\n    { 0x17E1, \"ORTHOFIX\"  },\r\n    { 0x17E2, \"PIKAONE\"  },\r\n    { 0x17E3, \"Beck IPC GmbH\"  },\r\n    { 0x17E4, \"OKB SAPR\"  },\r\n    { 0x17E5, \"Memcorp Inc.\"  },\r\n    { 0x17E6, \"Quantel Medical\"  },\r\n    { 0x17E7, \"Sirah Laser-und Plasmatechnik GmbH\"  },\r\n    { 0x17E8, \"Visionee S.R.L.\"  },\r\n    { 0x17E9, \"DisplayLink (UK) Ltd.\"  },\r\n    { 0x17EA, \"Web Technology Corp\"  },\r\n    { 0x17EB, \"Cornice, Inc.\"  },\r\n    { 0x17EC, \"Telsource\"  },\r\n    { 0x17ED, \"Sumita Optical Glass, Inc.\"  },\r\n    { 0x17EE, \"Personal Media Corporation\"  },\r\n    { 0x17EF, \"Lenovo\"  },\r\n    { 0x17F0, \"Bestronic Industry Co., Ltd.\"  },\r\n    { 0x17F1, \"Microjet Technology Co., Ltd.\"  },\r\n    { 0x17F2, \"Xmultiple Technologies Inc.\"  },\r\n    { 0x17F3, \"Terascala, Inc.\"  },\r\n    { 0x17F4, \"AgaMatrix, Inc.\"  },\r\n    { 0x17F5, \"K.K. Rocky\"  },\r\n    { 0x17F6, \"Unicomp, Inc\"  },\r\n    { 0x17F7, \"Metroptic Technologies Ltd.\"  },\r\n    { 0x17F8, \"Enustech, Inc.\"  },\r\n    { 0x17F9, \"GIE Sesam-Vitale\"  },\r\n    { 0x17FA, \"DOSHISHA CORPORATION\"  },\r\n    { 0x17FB, \"Emutec Inc.\"  },\r\n    { 0x17FC, \"Vitesse Semiconductor Corp.\"  },\r\n    { 0x17FD, \"Formac GmbH\"  },\r\n    { 0x17FE, \"NIPPON PULSE MOTOR CO., LTD.\"  },\r\n    { 0x17FF, \"Unication Co., Ltd\"  },\r\n    { 0x1800, \"Shandong Yuanda Net & Multimedia Co., Ltd.\"  },\r\n    { 0x1801, \"Southern Data Comm, Inc.\"  },\r\n    { 0x1802, \"SYN-TEK Technologies Inc.\"  },\r\n    { 0x1803, \"Secutronix\"  },\r\n    { 0x1804, \"Clemens GmbH\"  },\r\n    { 0x1805, \"Digital Peripheral Solutions Inc.\"  },\r\n    { 0x1806, \"New Index AS\"  },\r\n    { 0x1807, \"Par-Tech Inc.\"  },\r\n    { 0x1808, \"Multiplex Engineering Inc.\"  },\r\n    { 0x1809, \"Advantech Co., Ltd.\"  },\r\n    { 0x180A, \"Technosystem Co., Ltd.\"  },\r\n    { 0x180B, \"Photo Research, Inc.\"  },\r\n    { 0x180C, \"Power Digital Card Co., Ltd.\"  },\r\n    { 0x180D, \"U3, LLC\"  },\r\n    { 0x180E, \"Audisoft Technologies\"  },\r\n    { 0x180F, \"Phonak Communications AG\"  },\r\n    { 0x1810, \"Wanshih Electronic Co., Ltd.\"  },\r\n    { 0x1811, \"Blackspot Interactive Ltd.\"  },\r\n    { 0x1812, \"GEWI GmbH\"  },\r\n    { 0x1813, \"HAGIWARA ELECTRIC Co., Ltd.\"  },\r\n    { 0x1814, \"Fashionow Co. Ltd.\"  },\r\n    { 0x1815, \"Horizon Semiconductors Ltd.\"  },\r\n    { 0x1816, \"Directed Electronics\"  },\r\n    { 0x1817, \"Digital Authentication Technologies, Inc.\"  },\r\n    { 0x1818, \"Osteosys Co., Ltd.\"  },\r\n    { 0x1819, \"Quality Vision International, Inc.\"  },\r\n    { 0x181A, \"Fotonation\"  },\r\n    { 0x181B, \"Current Designs, Inc.\"  },\r\n    { 0x181C, \"Rensselaer Polytechnic Institute\"  },\r\n    { 0x181D, \"Axon Systems Inc.\"  },\r\n    { 0x181E, \"Advanced Tracking Technologies, Inc.\"  },\r\n    { 0x181F, \"NAKAJIMA ALL Co., Ltd.\"  },\r\n    { 0x1820, \"DSM - Messtechnik GmbH\"  },\r\n    { 0x1821, \"INwireless Co., Ltd\"  },\r\n    { 0x1822, \"DIGIBIO TECHNOLOGY CORP.\"  },\r\n    { 0x1823, \"CelleBrite Mobile Synchronization\"  },\r\n    { 0x1824, \"Aval Nagasaki Corp.\"  },\r\n    { 0x1825, \"Star-Dundee Ltd.\"  },\r\n    { 0x1826, \"Xitron Inc.\"  },\r\n    { 0x1827, \"Sanko Electronics Co., Ltd.\"  },\r\n    { 0x1828, \"TSR Silicon Resources, Inc.\"  },\r\n    { 0x1829, \"Dongguan YuQiu Electronics Co., Ltd.\"  },\r\n    { 0x182A, \"Signalion GmbH\"  },\r\n    { 0x182B, \"Chest M.I., Incorporated\"  },\r\n    { 0x182C, \"Caliper LifeSciences\"  },\r\n    { 0x182D, \"Accutron Limited\"  },\r\n    { 0x182E, \"System Instruments Co., Ltd.\"  },\r\n    { 0x182F, \"Worldwide Productions Inc.\"  },\r\n    { 0x1830, \"I CAP Technologies, Inc.\"  },\r\n    { 0x1831, \"Gwo Jinn Industries Co., Ltd.\"  },\r\n    { 0x1832, \"Huizhou Shenghua Industrial Co., Ltd.\"  },\r\n    { 0x1833, \"Genuine Technologies Co., Ltd.\"  },\r\n    { 0x1834, \"SONEL S.A.\"  },\r\n    { 0x1835, \"Lust Drivetronics GmbH\"  },\r\n    { 0x1836, \"ePoint Technology\"  },\r\n    { 0x1837, \"Hokuto Denko Corporation\"  },\r\n    { 0x1838, \"Real Networks, Inc.\"  },\r\n    { 0x1839, \"AnexTEK Global Inc.\"  },\r\n    { 0x183A, \"Mediafour Corporation\"  },\r\n    { 0x183B, \"SIDACON Systemtechnik GmbH\"  },\r\n    { 0x183C, \"Saab AB\"  },\r\n    { 0x183D, \"F3 Inc.\"  },\r\n    { 0x183E, \"Robonik India Pvt. Ltd.\"  },\r\n    { 0x183F, \"i-BEAD Co., Ltd.\"  },\r\n    { 0x1840, \"Cognitive Solutions, Inc.\"  },\r\n    { 0x1841, \"SEIKO TIME SYSTEM INC.\"  },\r\n    { 0x1842, \"Keen High Technologies (HK) Ltd.\"  },\r\n    { 0x1843, \"Vaisala\"  },\r\n    { 0x1844, \"Radiotechnika Marketing Sp.zo.o\"  },\r\n    { 0x1845, \"Cion Technology Corporation\"  },\r\n    { 0x1846, \"microEngineering Labs, Inc.\"  },\r\n    { 0x1847, \"Global Payment Technologies, Inc.\"  },\r\n    { 0x1848, \"Eurochannels Holding B.V.\"  },\r\n    { 0x1849, \"Centurion Systems (Pty) Ltd.\"  },\r\n    { 0x184A, \"EB Neuro SPA\"  },\r\n    { 0x184B, \"ARION Technology Inc.\"  },\r\n    { 0x184C, \"Centice\"  },\r\n    { 0x184D, \"Dansk Automat Expert A/S\"  },\r\n    { 0x184E, \"SyGade Solutions (Pty) Ltd.\"  },\r\n    { 0x184F, \"K2L GmbH\"  },\r\n    { 0x1850, \"Andigilog, Inc.\"  },\r\n    { 0x1851, \"ULTRASONIC ENGINEERING CO., LTD.\"  },\r\n    { 0x1852, \"Galaxy Far East Corp\"  },\r\n    { 0x1853, \"MITSUBISHI PRECISION CO., LTD.\"  },\r\n    { 0x1854, \"Memory Devices Ltd.\"  },\r\n    { 0x1855, \"Redpay Secure Payments\"  },\r\n    { 0x1856, \"Imaginova\"  },\r\n    { 0x1857, \"Picosecond Pulse Labs\"  },\r\n    { 0x1858, \"CELLSYSTEM CO., LTD\"  },\r\n    { 0x1859, \"Speech Technology Center, Ltd.\"  },\r\n    { 0x185A, \"WinProbe Corporation\"  },\r\n    { 0x185B, \"IG-Development\"  },\r\n    { 0x185C, \"Omnisec AG\"  },\r\n    { 0x185D, \"Origgio Limited\"  },\r\n    { 0x185E, \"Meritech Co., Ltd.\"  },\r\n    { 0x185F, \"Stinger Systems Inc.\"  },\r\n    { 0x1860, \"HYUPJIN I & C CO, LTD.\"  },\r\n    { 0x1861, \"Tech Technology Industrial Company\"  },\r\n    { 0x1862, \"Teridian Semiconductor Corp.\"  },\r\n    { 0x1863, \"Wave Technology Co., Ltd.\"  },\r\n    { 0x1864, \"Digital Art System\"  },\r\n    { 0x1865, \"Europlex Technologies\"  },\r\n    { 0x1866, \"Union Community Co., Ltd.\"  },\r\n    { 0x1867, \"Control Microsystems\"  },\r\n    { 0x1868, \"Index Braille AB\"  },\r\n    { 0x1869, \"RTS Automation GmbH\"  },\r\n    { 0x186A, \"Pivot International, Inc.\"  },\r\n    { 0x186B, \"Holophase Incorporated\"  },\r\n    { 0x186C, \"Miyachi Corporation\"  },\r\n    { 0x186D, \"Evermore Innovations\"  },\r\n    { 0x186E, \"Reel Stream LLC\"  },\r\n    { 0x186F, \"Motion Lingo, LLC\"  },\r\n    { 0x1870, \"Nexio Co., Ltd.\"  },\r\n    { 0x1871, \"Aveo Technology Corp.\"  },\r\n    { 0x1872, \"Cobalt Technologies Co., Ltd.\"  },\r\n    { 0x1873, \"Etrovision Technology\"  },\r\n    { 0x1874, \"Nexilion Inc.\"  },\r\n    { 0x1875, \"Humo Laboratory, Ltd.\"  },\r\n    { 0x1876, \"MG Industrieelektronik GmbH\"  },\r\n    { 0x1877, \"SANEI HYTECHS Co., Ltd.\"  },\r\n    { 0x1878, \"Sumitomo Heavy Industries, Ltd.\"  },\r\n    { 0x1879, \"Spin Semiconductor Inc.\"  },\r\n    { 0x187A, \"Mediachorus Inc.\"  },\r\n    { 0x187B, \"Dent Instruments, Inc.\"  },\r\n    { 0x187C, \"Alienware Corporation\"  },\r\n    { 0x187D, \"Ardware Ltd.\"  },\r\n    { 0x187E, \"Sentelic Corporation\"  },\r\n    { 0x187F, \"Siano Mobile Silicon Ltd.\"  },\r\n    { 0x1880, \"Vericon Co., Ltd./Jinn Shyang Precision Industrial Co.,\"  },\r\n    { 0x1881, \"Interactive Learning Technologies\"  },\r\n    { 0x1882, \"TransChip Israel Ltd.\"  },\r\n    { 0x1883, \"Tanaka S/S Ltd.\"  },\r\n    { 0x1884, \"Liyuh Technology Ltd.\"  },\r\n    { 0x1885, \"Ascalade Communications Inc.\"  },\r\n    { 0x1886, \"Metalink Ltd.\"  },\r\n    { 0x1887, \"Fishcamp Engineering\"  },\r\n    { 0x1888, \"Livingston Products, Inc.\"  },\r\n    { 0x1889, \"DME Corporation\"  },\r\n    { 0x188A, \"Moeller\"  },\r\n    { 0x188B, \"Showa Electric Laboratory Co., Ltd.\"  },\r\n    { 0x188C, \"Epos Development Ltd.\"  },\r\n    { 0x188D, \"Across Techno, Inc.\"  },\r\n    { 0x188E, \"Neopost Technologies\"  },\r\n    { 0x188F, \"Zefatek Co., Ltd.\"  },\r\n    { 0x1890, \"MEDIAN Inc.\"  },\r\n    { 0x1891, \"XSENSOR Technology Corp.\"  },\r\n    { 0x1892, \"Accuri Instruments, Inc.\"  },\r\n    { 0x1893, \"Ginga Software, Inc.\"  },\r\n    { 0x1894, \"SyntheSys Research, Inc.\"  },\r\n    { 0x1895, \"tesa scribos GmbH\"  },\r\n    { 0x1896, \"Legacy Electronics, Inc.\"  },\r\n    { 0x1897, \"Evertop Wire Cable Co.\"  },\r\n    { 0x1898, \"Summit Microelectronics\"  },\r\n    { 0x1899, \"Linkiss Co., Ltd.\"  },\r\n    { 0x189A, \"Earth Computer Technologies, Inc.\"  },\r\n    { 0x189B, \"Trimax Electronics Co., Ltd.\"  },\r\n    { 0x189C, \"Walletex Microelectronics Ltd.\"  },\r\n    { 0x189D, \"Navionics Inc.\"  },\r\n    { 0x189E, \"Net Insight AB\"  },\r\n    { 0x189F, \"3Shape A/S\"  },\r\n    { 0x18A0, \"Kongsberg Maritime AS\"  },\r\n    { 0x18A1, \"Ionwerks, Inc.\"  },\r\n    { 0x18A2, \"PSIA Corp.\"  },\r\n    { 0x18A3, \"DIGIFRIENDS CO., LTD.\"  },\r\n    { 0x18A4, \"CSSN, Inc. dba Card Scanning Solutions\"  },\r\n    { 0x18A5, \"Verbatim Americas LLC\"  },\r\n    { 0x18A6, \"Peripheral Dynamics Inc.\"  },\r\n    { 0x18A7, \"Omniprint Inc.\"  },\r\n    { 0x18A8, \"Smiths Medical MD\"  },\r\n    { 0x18A9, \"Veri-Tek International\"  },\r\n    { 0x18AA, \"MedRx Inc.\"  },\r\n    { 0x18AB, \"Applied Data Systems, Inc.\"  },\r\n    { 0x18AC, \"STRATEC Biomedical Systems AG\"  },\r\n    { 0x18AD, \"Invisible Technologies, Inc.\"  },\r\n    { 0x18AE, \"MTT Corporation\"  },\r\n    { 0x18AF, \"LN Systems Limited\"  },\r\n    { 0x18B0, \"Mikrodidakt AB\"  },\r\n    { 0x18B1, \"Elmak Ltd.\"  },\r\n    { 0x18B2, \"CINTEL FRANCE\"  },\r\n    { 0x18B3, \"RAYDON Corporation\"  },\r\n    { 0x18B4, \"e3C Inc.\"  },\r\n    { 0x18B5, \"Klipsch Audio\"  },\r\n    { 0x18B6, \"Mikkon Technology Limited\"  },\r\n    { 0x18B7, \"Zotek Electronic Co., Ltd.\"  },\r\n    { 0x18B8, \"Securewave SA\"  },\r\n    { 0x18B9, \"Clixxun GmbH\"  },\r\n    { 0x18BA, \"Bell Fruit Games\"  },\r\n    { 0x18BB, \"G7 Productivity Systems\"  },\r\n    { 0x18BC, \"Muro Co., Ltd\"  },\r\n    { 0x18BD, \"MNBT Co., Ltd.\"  },\r\n    { 0x18BE, \"Kingfisher International\"  },\r\n    { 0x18BF, \"Ensyc Technologies\"  },\r\n    { 0x18C0, \"Gatekeeper Systems Inc.\"  },\r\n    { 0x18C1, \"Shenzhen SDMC Microelectronics Co., Ltd.\"  },\r\n    { 0x18C2, \"AccuSport International, Inc.\"  },\r\n    { 0x18C3, \"Elite Semiconductor Memory Technology Inc. (ESMT)\"  },\r\n    { 0x18C4, \"ServerEngines LLC\"  },\r\n    { 0x18C5, \"Corega Taiwan, Inc.\"  },\r\n    { 0x18C6, \"Aurora Photonics\"  },\r\n    { 0x18C7, \"Nagano Tectron Co., Ltd\"  },\r\n    { 0x18C8, \"Computerprox Corp.\"  },\r\n    { 0x18C9, \"Exfo Electro-Optical Engineering Inc.\"  },\r\n    { 0x18CA, \"Canon Korea Business Solutions Inc.\"  },\r\n    { 0x18CB, \"Fr. Sauter AG\"  },\r\n    { 0x18CC, \"Osaki Electric Co., Ltd.\"  },\r\n    { 0x18CD, \"Pico Instruments LLC\"  },\r\n    { 0x18CE, \"DTC Communications, Inc\"  },\r\n    { 0x18CF, \"Tung Shu Mei Industrial Co., Ltd.\"  },\r\n    { 0x18D0, \"Uniform Industrial Corp.\"  },\r\n    { 0x18D1, \"Google Inc.\"  },\r\n    { 0x18D2, \"Raptor Gaming Technology GmbH\"  },\r\n    { 0x18D3, \"L&V Design\"  },\r\n    { 0x18D4, \"ABI Electronics Ltd.\"  },\r\n    { 0x18D5, \"Starline International Group Limited\"  },\r\n    { 0x18D6, \"Ruetz Technologies\"  },\r\n    { 0x18D7, \"New Scale Technologies\"  },\r\n    { 0x18D8, \"Individual Computers\"  },\r\n    { 0x18D9, \"Kaba\"  },\r\n    { 0x18DA, \"Phonol Inc.\"  },\r\n    { 0x18DB, \"Compix Incorporated\"  },\r\n    { 0x18DC, \"LKC Technologies, Inc.\"  },\r\n    { 0x18DD, \"Docuport WC\"  },\r\n    { 0x18DE, \"Cyto Pulse Sciences, Inc\"  },\r\n    { 0x18DF, \"Cinea Inc.\"  },\r\n    { 0x18E0, \"Source Technologies, LLC\"  },\r\n    { 0x18E1, \"Drew Technologies Inc.\"  },\r\n    { 0x18E2, \"S.J. Electronics Co., Ltd\"  },\r\n    { 0x18E3, \"Fitilink Integrated Technology, Inc.\"  },\r\n    { 0x18E4, \"SB Solutions, Inc\"  },\r\n    { 0x18E5, \"Ablaze Systems LLC\"  },\r\n    { 0x18E6, \"Gobex AS\"  },\r\n    { 0x18E7, \"Truscott Designs\"  },\r\n    { 0x18E8, \"Mondo Systems\"  },\r\n    { 0x18E9, \"Numsite Corporation\"  },\r\n    { 0x18EA, \"Matrox Electronic Systems\"  },\r\n    { 0x18EB, \"nDezign, Inc.\"  },\r\n    { 0x18EC, \"Arkmicro Technologies Inc.\"  },\r\n    { 0x18ED, \"Tyco Safety Products\"  },\r\n    { 0x18EE, \"Holm Acoustics\"  },\r\n    { 0x18EF, \"ELV Elektronik AG\"  },\r\n    { 0x18F0, \"AVAL DATA CORPORATION\"  },\r\n    { 0x18F1, \"AL Tech, Inc.\"  },\r\n    { 0x18F2, \"Rasotto S.N.C.\"  },\r\n    { 0x18F3, \"Miglia Technology Ltd.\"  },\r\n    { 0x18F4, \"Vtech Engineering Corporation\"  },\r\n    { 0x18F5, \"Esterline Mason\"  },\r\n    { 0x18F6, \"Zermatt Systems Inc\"  },\r\n    { 0x18F7, \"ImageStream Internet Solutions Inc..\"  },\r\n    { 0x18F8, \"Teitsu Denshi Kenkyusho Co., Ltd.\"  },\r\n    { 0x18F9, \"EX COMPANY LIMITED\"  },\r\n    { 0x18FA, \"Kuang Ying Computer Equipment Co., Ltd.\"  },\r\n    { 0x18FB, \"Scriptel Corporation\"  },\r\n    { 0x18FC, \"Kinyo Co., Ltd.\"  },\r\n    { 0x18FD, \"FineArch Inc.\"  },\r\n    { 0x18FE, \"SecuriMetrics, Inc.\"  },\r\n    { 0x18FF, \"HYUNDAI Digital Technology Co., Ltd.\"  },\r\n    { 0x1900, \"Future Wave, Inc.\"  },\r\n    { 0x1901, \"GE Healthcare\"  },\r\n    { 0x1902, \"CSIRO Marine & Atmospheric Research\"  },\r\n    { 0x1903, \"ANEX SYSTEM LTD.\"  },\r\n    { 0x1904, \"LVI Low Vision International AB\"  },\r\n    { 0x1905, \"EGEMEN Bilgisayar Muh ve San LTD STI\"  },\r\n    { 0x1906, \"Seoro Tech Co., Ltd.\"  },\r\n    { 0x1907, \"Elcoteq Design Center Oy\"  },\r\n    { 0x1908, \"APPOTECH LIMITED\"  },\r\n    { 0x1909, \"ABB Inc. Totalflow Division\"  },\r\n    { 0x190A, \"Freewide Inc.\"  },\r\n    { 0x190B, \"Metasoft S.C.\"  },\r\n    { 0x190C, \"ierise Inc.\"  },\r\n    { 0x190D, \"Motorola GSG\"  },\r\n    { 0x190E, \"YAMASA Tokei-Keiki Co, Ltd\"  },\r\n    { 0x190F, \"YA HORNG ELECTRONIC CO., LTD.\"  },\r\n    { 0x1910, \"Seriprint-Ziprip UK Limited\"  },\r\n    { 0x1911, \"Nihon Dengyo Kosaku Co., Ltd.\"  },\r\n    { 0x1912, \"Yukyung Technologies Co, Ltd\"  },\r\n    { 0x1913, \"Atomynet, Inc.\"  },\r\n    { 0x1914, \"Alco Digital Devices Limited\"  },\r\n    { 0x1915, \"Nordic Semiconductor ASA\"  },\r\n    { 0x1916, \"Juniper Systems, Inc.\"  },\r\n    { 0x1917, \"Imagetech Corporation\"  },\r\n    { 0x1918, \"NanoSystem Solutions, Inc.\"  },\r\n    { 0x1919, \"Pixelworks\"  },\r\n    { 0x191A, \"PATLITE Corporation\"  },\r\n    { 0x191B, \"PICOCEL Co., Ltd.\"  },\r\n    { 0x191C, \"Innovative Technology Limited\"  },\r\n    { 0x191D, \"Midtronics, Inc.\"  },\r\n    { 0x191E, \"Monsoon Multimedia Inc.\"  },\r\n    { 0x191F, \"Venetex Co., Ltd.\"  },\r\n    { 0x1920, \"U.S. Digital Television, LLC\"  },\r\n    { 0x1921, \"Interson Corporation\"  },\r\n    { 0x1922, \"Power 7 Technologies Corp.\"  },\r\n    { 0x1923, \"FitSense Technology, Inc.\"  },\r\n    { 0x1924, \"QnAp iT\"  },\r\n    { 0x1925, \"InnoFaith beauty sciences B.V.\"  },\r\n    { 0x1926, \"NextWindow Limited\"  },\r\n    { 0x1927, \"Vulcan Portals Inc.\"  },\r\n    { 0x1928, \"PROCEQ SA\"  },\r\n    { 0x1929, \"Wagner Owen Corporation\"  },\r\n    { 0x192A, \"Intek\"  },\r\n    { 0x192B, \"KVH Industries, Inc.\"  },\r\n    { 0x192C, \"Twig Com Oy\"  },\r\n    { 0x192D, \"AgileTV\"  },\r\n    { 0x192E, \"Bioanalytical Systems\"  },\r\n    { 0x192F, \"Avago Technologies, Pte.\"  },\r\n    { 0x1930, \"Shenzhen Xianhe Technology Co., Ltd.\"  },\r\n    { 0x1931, \"Ningbo Broad Telecommunication Co., Ltd.\"  },\r\n    { 0x1932, \"Daniels Electronics Ltd.\"  },\r\n    { 0x1933, \"TASER INTERNATIONAL INC.\"  },\r\n    { 0x1934, \"SAKAI Medical Co., Ltd.\"  },\r\n    { 0x1935, \"Elektron Music Machines AB\"  },\r\n    { 0x1936, \"Asaka Riken Co., Ltd\"  },\r\n    { 0x1937, \"Dynjab Technologies Pty. Ltd.\"  },\r\n    { 0x1938, \"Meinberg Funkuhren GmbH & Co. KG\"  },\r\n    { 0x1939, \"Hilscher GmbH\"  },\r\n    { 0x193A, \"Lipman Electronic Engineering Ltd.\"  },\r\n    { 0x193B, \"Power Monitors, Inc.\"  },\r\n    { 0x193C, \"COGELEC\"  },\r\n    { 0x193D, \"MAXIAN Co., Ltd.\"  },\r\n    { 0x193E, \"Chestnut Hill Sound Inc.\"  },\r\n    { 0x193F, \"OPDICOM PTY LTD\"  },\r\n    { 0x1940, \"U.S. Music Corporation\"  },\r\n    { 0x1941, \"Top Eight Industrial Corp.\"  },\r\n    { 0x1942, \"GAMING PARTNERS INTERNATIONAL\"  },\r\n    { 0x1943, \"Sensoray\"  },\r\n    { 0x1944, \"Wegener Communications\"  },\r\n    { 0x1945, \"O-Pen\"  },\r\n    { 0x1946, \"Irisguard UK Ltd\"  },\r\n    { 0x1947, \"Harris Corporation\"  },\r\n    { 0x1948, \"Darlitech International Co., Ltd.\"  },\r\n    { 0x1949, \"Lab126\"  },\r\n    { 0x194A, \"Secure Design Institute Co., Ltd.\"  },\r\n    { 0x194B, \"Yanago Design Inc.\"  },\r\n    { 0x194C, \"Scanivalve Corp.\"  },\r\n    { 0x194D, \"Kern AG\"  },\r\n    { 0x194E, \"acam-messelectronic GmbH\"  },\r\n    { 0x194F, \"PreSonus Audio Electronics\"  },\r\n    { 0x1950, \"FUJINON CORPORATION\"  },\r\n    { 0x1951, \"Hyperstone GmbH\"  },\r\n    { 0x1952, \"X-TEMPO DESIGNS LLC\"  },\r\n    { 0x1953, \"Ironkey Inc.\"  },\r\n    { 0x1954, \"Radiient Technologies\"  },\r\n    { 0x1955, \"4G Systems GmbH\"  },\r\n    { 0x1956, \"The SmartPill Corporation\"  },\r\n    { 0x1957, \"BIOS Corporation\"  },\r\n    { 0x1958, \"Office Depot, Inc.\"  },\r\n    { 0x1959, \"DRS Signal Solutions Inc.\"  },\r\n    { 0x195A, \"Technology Link Corporation\"  },\r\n    { 0x195B, \"Huge China Industrial Ltd.\"  },\r\n    { 0x195C, \"NewSight\"  },\r\n    { 0x195D, \"Itron Technology Inc.\"  },\r\n    { 0x195E, \"Datakey Electronics\"  },\r\n    { 0x195F, \"GODEX INTERNATIONAL CO., LTD.\"  },\r\n    { 0x1960, \"Brains Corporation\"  },\r\n    { 0x1961, \"Grupo CD World S.L.\"  },\r\n    { 0x1962, \"Vstone Corp.\"  },\r\n    { 0x1963, \"IK MULTIMEDIA PRODUCTION srl\"  },\r\n    { 0x1964, \"ID Technica Sales Co., Ltd.\"  },\r\n    { 0x1965, \"Uniden Corporation\"  },\r\n    { 0x1966, \"ELESTA GmbH\"  },\r\n    { 0x1967, \"CASIO HITACHI Mobile Communications Co., Ltd.\"  },\r\n    { 0x1968, \"Global Silicon Ltd.\"  },\r\n    { 0x1969, \"TM-Research, Inc.\"  },\r\n    { 0x196A, \"SmartCom\"  },\r\n    { 0x196B, \"Wispro Technology Inc.\"  },\r\n    { 0x196C, \"EMKA Technologies\"  },\r\n    { 0x196D, \"InnoDisk Corporation\"  },\r\n    { 0x196E, \"SEI\"  },\r\n    { 0x196F, \"Otoichi Corporation\"  },\r\n    { 0x1970, \"Dane-Elec Corp. USA\"  },\r\n    { 0x1971, \"Real ID Technology Co., Ltd.\"  },\r\n    { 0x1972, \"Diagnostic Instruments, Inc.\"  },\r\n    { 0x1973, \"SpectraLink Corporation\"  },\r\n    { 0x1974, \"LOSTEAKA, Inc.\"  },\r\n    { 0x1975, \"Dongguan Guneetal Wire & Cable Co., Ltd.\"  },\r\n    { 0x1976, \"Chipsbrand Microelectronics (HK) Co., Ltd.\"  },\r\n    { 0x1977, \"Thales\"  },\r\n    { 0x1978, \"Lismore Instruments Limited\"  },\r\n    { 0x1979, \"Suga Digital Technology Limited\"  },\r\n    { 0x197A, \"Kellendonk Elektronik GmbH\"  },\r\n    { 0x197B, \"Way Systems Inc.\"  },\r\n    { 0x197C, \"JSC Videofon MV\"  },\r\n    { 0x197D, \"Leuze electronic GmbH & Co. KG\"  },\r\n    { 0x197E, \"scemtec Transponder Technology GmbH\"  },\r\n    { 0x197F, \"Triton\"  },\r\n    { 0x1980, \"Storage Appliance Corp.\"  },\r\n    { 0x1981, \"Matrix Audio Designs Inc.\"  },\r\n    { 0x1982, \"Hitel Italia S.P.A.\"  },\r\n    { 0x1983, \"Icera Inc.\"  },\r\n    { 0x1984, \"Targetti Sankey S.P.A.\"  },\r\n    { 0x1985, \"Elmos Co., Ltd.\"  },\r\n    { 0x1986, \"Excelitas Technologies Corporation\"  },\r\n    { 0x1987, \"Camille Bauer AG\"  },\r\n    { 0x1988, \"Novar Controls\"  },\r\n    { 0x1989, \"Nuconn Technology Corp.\"  },\r\n    { 0x198A, \"MODMEN Co., Ltd.\"  },\r\n    { 0x198B, \"Fluid Imaging Technologies, Inc\"  },\r\n    { 0x198C, \"c-scape\"  },\r\n    { 0x198D, \"Fairchild Imaging\"  },\r\n    { 0x198E, \"Ingrid, Inc.\"  },\r\n    { 0x198F, \"Beceem Communications Inc.\"  },\r\n    { 0x1990, \"Acron Precision Industrial Co., Ltd.\"  },\r\n    { 0x1991, \"AAI Corporation\"  },\r\n    { 0x1992, \"Avantes B.V.\"  },\r\n    { 0x1993, \"Bluetop Technology Co., Ltd.\"  },\r\n    { 0x1994, \"ZMM Ltd.\"  },\r\n    { 0x1995, \"Trillium Technology PTY LTD.\"  },\r\n    { 0x1996, \"PixeLINK\"  },\r\n    { 0x1997, \"CEFLA S.C.R.L.\"  },\r\n    { 0x1998, \"JENOPTIK Laser, Optik, Systeme GmbH\"  },\r\n    { 0x1999, \"iba AG\"  },\r\n    { 0x199A, \"DNA-Technology\"  },\r\n    { 0x199B, \"MicroStrain, Inc.\"  },\r\n    { 0x199C, \"Richnex Microelectronics Corporation\"  },\r\n    { 0x199D, \"Dexxon Groupe\"  },\r\n    { 0x199E, \"The Imaging Source Europe GmbH\"  },\r\n    { 0x199F, \"Benica Corporation\"  },\r\n    { 0x19A0, \"Krautkramer Japan Co., Ltd.\"  },\r\n    { 0x19A1, \"Zeecraft Tech.\"  },\r\n    { 0x19A2, \"SICK AG\"  },\r\n    { 0x19A3, \"ASmobile Communication Inc.\"  },\r\n    { 0x19A4, \"Unique Medical Co., Ltd.\"  },\r\n    { 0x19A5, \"Harris RF Communication\"  },\r\n    { 0x19A6, \"UBISYS TECHNOLOGIES\"  },\r\n    { 0x19A7, \"SuperTop International Corp.\"  },\r\n    { 0x19A8, \"Biforst Technology Inc.\"  },\r\n    { 0x19A9, \"Musashi Co., Ltd.\"  },\r\n    { 0x19AA, \"musicobo\"  },\r\n    { 0x19AB, \"Bodelin Technologies\"  },\r\n    { 0x19AC, \"Hardworks, Inc.\"  },\r\n    { 0x19AD, \"RiTTO GmbH & Co. KG\"  },\r\n    { 0x19AE, \"KeeLog\"  },\r\n    { 0x19AF, \"Innomax Technology Ltd.\"  },\r\n    { 0x19B0, \"Sobal Corporation\"  },\r\n    { 0x19B1, \"Kyoritsu Radio Co., Ltd.\"  },\r\n    { 0x19B2, \"Batronix Elektronik\"  },\r\n    { 0x19B3, \"SPOTWAVE WIRELESS\"  },\r\n    { 0x19B4, \"CELESTRON\"  },\r\n    { 0x19B5, \"B & W Group\"  },\r\n    { 0x19B6, \"Infotech Logistic, LLC\"  },\r\n    { 0x19B7, \"SK-Electronics Co. Ltd.\"  },\r\n    { 0x19B8, \"Control Technology Inc.\"  },\r\n    { 0x19B9, \"Drobo, Inc.\"  },\r\n    { 0x19BA, \"ebro Electronic GmbH & Co. KG\"  },\r\n    { 0x19BB, \"Informtest\"  },\r\n    { 0x19BC, \"ioLab Systems Inc.\"  },\r\n    { 0x19BD, \"Celluon, Inc.\"  },\r\n    { 0x19BE, \"Guidance Software, Inc.\"  },\r\n    { 0x19BF, \"HASHIMOTO Electronic Industry Co., Ltd.\"  },\r\n    { 0x19C0, \"TeraTron GmbH\"  },\r\n    { 0x19C1, \"Digital Info Technology Pte. Ltd.\"  },\r\n    { 0x19C2, \"TARGA GmbH\"  },\r\n    { 0x19C3, \"Riskema Informatica e Automacao Ltda.\"  },\r\n    { 0x19C4, \"Control Gaging, Inc.\"  },\r\n    { 0x19C5, \"Danaher Sensors and Controls\"  },\r\n    { 0x19C6, \"Harmony Microelectronic Inc.\"  },\r\n    { 0x19C7, \"WEG Equipamentos Eltricos S.A. - Automao\"  },\r\n    { 0x19C8, \"Secure Key LLC\"  },\r\n    { 0x19C9, \"Electronic Sports\"  },\r\n    { 0x19CA, \"Sandio Technology Corp.\"  },\r\n    { 0x19CB, \"EMS (European) LTD.\"  },\r\n    { 0x19CC, \"SCIEN Co.\"  },\r\n    { 0x19CD, \"D. O. Tel Co., Ltd.\"  },\r\n    { 0x19CE, \"SINUS Messtechnik GmbH\"  },\r\n    { 0x19CF, \"Parrot SA\"  },\r\n    { 0x19D0, \"Pan Pacific Enterprise Co., Inc.\"  },\r\n    { 0x19D1, \"Channaa\"  },\r\n    { 0x19D2, \"ZTE Corporation\"  },\r\n    { 0x19D3, \"Zucchetti Centro Sistemi SPA\"  },\r\n    { 0x19D4, \"I Bee, K.K.\"  },\r\n    { 0x19D5, \"CNB Technology Inc.\"  },\r\n    { 0x19D6, \"WIDE Corporation\"  },\r\n    { 0x19D7, \"Unitop New Technology Co., Ltd.\"  },\r\n    { 0x19D8, \"Smart Point SA\"  },\r\n    { 0x19D9, \"Fujitsu Ten Limited\"  },\r\n    { 0x19DA, \"MUSE Inc.\"  },\r\n    { 0x19DB, \"GeBE Elektronik und Feinwerktechnik GmbH\"  },\r\n    { 0x19DC, \"Communications & Power Industries\"  },\r\n    { 0x19DD, \"NEXVU TECHNOLOGIES, Inc.\"  },\r\n    { 0x19DE, \"MITEQ Inc.\"  },\r\n    { 0x19DF, \"AlpnaCom\"  },\r\n    { 0x19E0, \"Micro-Nits Co., Ltd.\"  },\r\n    { 0x19E1, \"WeiDuan Electronic Accessory (S.Z.) Co., Ltd.\"  },\r\n    { 0x19E2, \"Solomon Systech Limited\"  },\r\n    { 0x19E3, \"Bae Systems IEWS\"  },\r\n    { 0x19E4, \"In-Situ Inc.\"  },\r\n    { 0x19E5, \"Jetmobile\"  },\r\n    { 0x19E6, \"Apex Digital Inc.\"  },\r\n    { 0x19E7, \"Charismathics GmbH\"  },\r\n    { 0x19E8, \"Industrial Technology Research Institute\"  },\r\n    { 0x19E9, \"Bartec Auto ID Ltd.\"  },\r\n    { 0x19EA, \"Lung Hwa Electronics Co., Ltd.\"  },\r\n    { 0x19EB, \"ACE Antenna, Advanced Technology R&D Team.\"  },\r\n    { 0x19EC, \"Forth Dimension Displays Ltd.\"  },\r\n    { 0x19ED, \"Plastic Logic Ltd.\"  },\r\n    { 0x19EE, \"Modern Marketing Concepts Inc.\"  },\r\n    { 0x19EF, \"Pak Heng Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x19F0, \"Jyh Woei Industrial Co., Ltd.\"  },\r\n    { 0x19F1, \"SindoRicoh Co., LTD.\"  },\r\n    { 0x19F2, \"INFOMARK Co., Ltd.\"  },\r\n    { 0x19F3, \"JAPAN Kyastem Co., Ltd.\"  },\r\n    { 0x19F4, \"Malvern Instruments Ltd\"  },\r\n    { 0x19F5, \"Nationz Technologies Inc.\"  },\r\n    { 0x19F6, \"J. A. Woollam Co. Inc.\"  },\r\n    { 0x19F7, \"Rode Microphones\"  },\r\n    { 0x19F8, \"RoboTech srl\"  },\r\n    { 0x19F9, \"Megadata (Europe) PLC\"  },\r\n    { 0x19FA, \"SHENZHEN GAMEWARE ELECTRONIC CO., LTD.\"  },\r\n    { 0x19FB, \"VLSI Solution Oy\"  },\r\n    { 0x19FC, \"BioControl A/S\"  },\r\n    { 0x19FD, \"MTI Instruments\"  },\r\n    { 0x19FE, \"Micromap Corporation\"  },\r\n    { 0x19FF, \"Best Buy China Ltd.\"  },\r\n    { 0x1A00, \"Polymax Precision Industry Co., Ltd.\"  },\r\n    { 0x1A01, \"Siemens Power Transmission & Dist. Energy Automation\"  },\r\n    { 0x1A02, \"DLoG GmbH\"  },\r\n    { 0x1A03, \"HORIBA ITECH Co., Ltd.\"  },\r\n    { 0x1A04, \"ASTRO MACHINE CORP.\"  },\r\n    { 0x1A05, \"Media Lab., Inc\"  },\r\n    { 0x1A06, \"Beijing Deng Hong Technology Co., Ltd.\"  },\r\n    { 0x1A07, \"HID\"  },\r\n    { 0x1A08, \"Bellwood International, Inc.\"  },\r\n    { 0x1A09, \"DILANO GmbH\"  },\r\n    { 0x1A0B, \"Teleste OYJ\"  },\r\n    { 0x1A0C, \"Sunkorea Electronics Co., Ltd.\"  },\r\n    { 0x1A0D, \"Ladybug Technologies LLC\"  },\r\n    { 0x1A0E, \"Sasse Elektronik GmbH\"  },\r\n    { 0x1A0F, \"HT-ITALIA\"  },\r\n    { 0x1A10, \"KWANG SUNG ELECTRONICS H.K. Co., Ltd.\"  },\r\n    { 0x1A11, \"eMDee Technology, Inc.\"  },\r\n    { 0x1A12, \"KES Co., Ltd.\"  },\r\n    { 0x1A13, \"Plasmon\"  },\r\n    { 0x1A14, \"Brainvision Inc.\"  },\r\n    { 0x1A15, \"Amphenol-Tuchel Electronics GmbH\"  },\r\n    { 0x1A16, \"General Dynamics\"  },\r\n    { 0x1A17, \"Oticon A/S\"  },\r\n    { 0x1A18, \"Quadzilla Performance Technologies, Inc.\"  },\r\n    { 0x1A19, \"DDTIC Corporation Ltd.\"  },\r\n    { 0x1A1A, \"ASIACORP INTERNATIONAL LTD.\"  },\r\n    { 0x1A1B, \"Fischer-Zoth GmbH\"  },\r\n    { 0x1A1C, \"Mercury Computer Systems AG\"  },\r\n    { 0x1A1D, \"Syncomm Technology Corp.\"  },\r\n    { 0x1A1E, \"Dekart s.r.l.\"  },\r\n    { 0x1A1F, \"Ikanos Communications Inc.\"  },\r\n    { 0x1A20, \"Mind Logic Co., Ltd.\"  },\r\n    { 0x1A21, \"ASITEQ Co., Ltd.\"  },\r\n    { 0x1A22, \"Kenwin Industrial (HK) Ltd.\"  },\r\n    { 0x1A23, \"Hangzhou YiHeng Technologies Co., Ltd.\"  },\r\n    { 0x1A24, \"Beyondwiz Co., Ltd.\"  },\r\n    { 0x1A25, \"Amphenol East Asia Ltd.\"  },\r\n    { 0x1A26, \"APSI (Asia Pacific Satellite Industry)\"  },\r\n    { 0x1A27, \"Senior Technologies\"  },\r\n    { 0x1A28, \"NOVITUS SA\"  },\r\n    { 0x1A29, \"ABOV Semiconductor Co., Ltd.\"  },\r\n    { 0x1A2A, \"Seagate Branded Solutions\"  },\r\n    { 0x1A2B, \"NTI Corporation\"  },\r\n    { 0x1A2C, \"Wuxi China Resources Semico Co., Ltd.\"  },\r\n    { 0x1A2D, \"WEBSYNC Co., Ltd.\"  },\r\n    { 0x1A2E, \"Lanner Electronics Inc.\"  },\r\n    { 0x1A2F, \"Tetradyne Software Inc.\"  },\r\n    { 0x1A30, \"New Media Life\"  },\r\n    { 0x1A31, \"SPEX SamplePrep, LLC\"  },\r\n    { 0x1A32, \"Verint Video Technology GmbH\"  },\r\n    { 0x1A33, \"Schmid & Partner Engineering AG\"  },\r\n    { 0x1A34, \"King Chuang Tech & Electronic Co., Ltd.\"  },\r\n    { 0x1A35, \"Artesyn Technologies Inc.\"  },\r\n    { 0x1A36, \"Topdisk Technology Limited\"  },\r\n    { 0x1A37, \"Stayhealthy Inc.\"  },\r\n    { 0x1A38, \"Nemo-Q International AB\"  },\r\n    { 0x1A39, \"GBC Scientific Equipment\"  },\r\n    { 0x1A3A, \"Laerdal Medical AS\"  },\r\n    { 0x1A3B, \"South Mountain Technologies, Ltd.\"  },\r\n    { 0x1A3C, \"New Image Co., Ltd.\"  },\r\n    { 0x1A3D, \"ELGA LabWater (VWS UK LTD)\"  },\r\n    { 0x1A3E, \"INTEVAC\"  },\r\n    { 0x1A3F, \"Hokkei Industries Co., Ltd.\"  },\r\n    { 0x1A40, \"TERMINUS TECHNOLOGY INC.\"  },\r\n    { 0x1A41, \"Action Electronics Co., Ltd.\"  },\r\n    { 0x1A42, \"CROSSLINK GmbH\"  },\r\n    { 0x1A43, \"JTEKT CORPORATION\"  },\r\n    { 0x1A44, \"VASCO Data Security NV\"  },\r\n    { 0x1A45, \"Wavelength Electronics Inc.\"  },\r\n    { 0x1A46, \"JAVAD GNSS, Inc.\"  },\r\n    { 0x1A47, \"iQBio, Inc.\"  },\r\n    { 0x1A48, \"KYOHRITSU ELECTRONIC INDUSTRY Co., Ltd.\"  },\r\n    { 0x1A49, \"TOKYO SEIMITSU CO., LTD.\"  },\r\n    { 0x1A4A, \"Silicon Image\"  },\r\n    { 0x1A4B, \"SafeBoot International B.V.\"  },\r\n    { 0x1A4C, \"PMC\"  },\r\n    { 0x1A4D, \"N-CRYPT, Inc.\"  },\r\n    { 0x1A4E, \"SIMS Corp.\"  },\r\n    { 0x1A4F, \"Haliplex PTY Ltd.\"  },\r\n    { 0x1A50, \"Mechatro Inc.\"  },\r\n    { 0x1A51, \"FRWD Technologies Ltd.\"  },\r\n    { 0x1A52, \"MediaPhy Corporation\"  },\r\n    { 0x1A53, \"SANDBOX Co., Ltd\"  },\r\n    { 0x1A54, \"Oestling Markiersysteme GmbH\"  },\r\n    { 0x1A55, \"Raytheon Systems Limited\"  },\r\n    { 0x1A56, \"East Port Technology Co., Ltd.\"  },\r\n    { 0x1A57, \"ARESIS d.o.o.\"  },\r\n    { 0x1A58, \"Miranda Technologies Inc.\"  },\r\n    { 0x1A59, \"HAAG-STREIT AG\"  },\r\n    { 0x1A5A, \"Tandberg Data\"  },\r\n    { 0x1A5B, \"Entner Electronics KEG\"  },\r\n    { 0x1A5C, \"Arkino Corporation Limited\"  },\r\n    { 0x1A5D, \"Daikin Denshi Kogyo Co., Ltd.\"  },\r\n    { 0x1A5E, \"Edixia\"  },\r\n    { 0x1A5F, \"Sonatest Limited\"  },\r\n    { 0x1A60, \"Joytoto Co., Ltd.\"  },\r\n    { 0x1A61, \"Abbott Diabetes Care\"  },\r\n    { 0x1A62, \"DAT H.K. LIMITED\"  },\r\n    { 0x1A63, \"Canfield Scientific, Inc.\"  },\r\n    { 0x1A64, \"MASTERVOLT INTERNATIONAL\"  },\r\n    { 0x1A65, \"ELEKTRINA d.o.o., podjetje za razvoj elektronike\"  },\r\n    { 0x1A66, \"Andatek Technology, Ltd.\"  },\r\n    { 0x1A67, \"Privaris\"  },\r\n    { 0x1A68, \"Double Top Technology Ltd.\"  },\r\n    { 0x1A69, \"Kalon Semiconductor, Inc.\"  },\r\n    { 0x1A6A, \"Cypress Semiconductor GmbH\"  },\r\n    { 0x1A6B, \"Taiwin Electronics Co., Ltd.\"  },\r\n    { 0x1A6C, \"Hivion Co., Ltd.\"  },\r\n    { 0x1A6D, \"SamYoung Electronics Co., Ltd\"  },\r\n    { 0x1A6E, \"Global Unichip Corp.\"  },\r\n    { 0x1A6F, \"Sagem Orga GmbH\"  },\r\n    { 0x1A70, \"Items Technology Co., Ltd.\"  },\r\n    { 0x1A71, \"SEIDEL Elektronik GmbH Nfg. KG\"  },\r\n    { 0x1A72, \"Physik Instrumente (PI) GmbH & Co. KG\"  },\r\n    { 0x1A73, \"Huntron Inc.\"  },\r\n    { 0x1A74, \"Oberthur Technologies\"  },\r\n    { 0x1A75, \"Nautilus Hyosung\"  },\r\n    { 0x1A76, \"JADAK Technologies, Inc.\"  },\r\n    { 0x1A77, \"American Master Import 26, Inc.\"  },\r\n    { 0x1A78, \"AirLink Communications, Inc.\"  },\r\n    { 0x1A79, \"Ascensia Diabetes Care\"  },\r\n    { 0x1A7A, \"Softron Co., Ltd.\"  },\r\n    { 0x1A7B, \"Lumberg Connect GmbH\"  },\r\n    { 0x1A7C, \"Evoluent LLC\"  },\r\n    { 0x1A7D, \"Systex Corporation\"  },\r\n    { 0x1A7E, \"MELTEC Systementwicklung\"  },\r\n    { 0x1A7F, \"SSD COMPANY LIMITED\"  },\r\n    { 0x1A80, \"Zhong Ming Wire Cable Technology (Xiamen) Co., Ltd.\"  },\r\n    { 0x1A81, \"G.Tech Technology Ltd.\"  },\r\n    { 0x1A82, \"Proconn Technology Co., Ltd.\"  },\r\n    { 0x1A83, \"Socle Technology Corp.\"  },\r\n    { 0x1A84, \"COBB Tuning, Inc.\"  },\r\n    { 0x1A85, \"Southwest Research Institute\"  },\r\n    { 0x1A86, \"Nanjing Qinherg Electronics Co., Ltd.\"  },\r\n    { 0x1A87, \"TechLab 2000 Ltd. Co., Sp Zo.o.\"  },\r\n    { 0x1A88, \"WowWee Limited\"  },\r\n    { 0x1A89, \"Dynalith Systems Co., Ltd.\"  },\r\n    { 0x1A8A, \"Simula Technology Inc.\"  },\r\n    { 0x1A8B, \"SGS Taiwan Ltd.\"  },\r\n    { 0x1A8C, \"MagicEyes Digital Co., Ltd\"  },\r\n    { 0x1A8D, \"BandRich Inc.\"  },\r\n    { 0x1A8E, \"XiTRON Technologies\"  },\r\n    { 0x1A8F, \"Harman Becker Automotive Systems, GmbH\"  },\r\n    { 0x1A90, \"Resource Data Management\"  },\r\n    { 0x1A91, \"GEOMC Co., Ltd.\"  },\r\n    { 0x1A92, \"Berkash Enterprise\"  },\r\n    { 0x1A93, \"Promotional Technologies International Corp.\"  },\r\n    { 0x1A94, \"STWTECH Co., Ltd.\"  },\r\n    { 0x1A95, \"Sextant Labs, Inc.\"  },\r\n    { 0x1A96, \"Harman Becker Automotive Systems, Inc.\"  },\r\n    { 0x1A97, \"XM Satellite Radio Inc.\"  },\r\n    { 0x1A98, \"Leica Camera AG\"  },\r\n    { 0x1A99, \"Asia Tai Technology (Dongguan) Co., Ltd.\"  },\r\n    { 0x1A9A, \"Verari Systems, Inc.\"  },\r\n    { 0x1A9B, \"Balboa Instruments\"  },\r\n    { 0x1A9C, \"Inomed Medizintechnik GmbH\"  },\r\n    { 0x1A9D, \"TrafficSim Co., Ltd.\"  },\r\n    { 0x1A9E, \"Epicenter, Inc.\"  },\r\n    { 0x1A9F, \"Hysitron Incorporated\"  },\r\n    { 0x1AA0, \"Auto Enginuity, L.L.C.\"  },\r\n    { 0x1AA1, \"Vestax Corporation\"  },\r\n    { 0x1AA2, \"ORIENTAL MOTOR CO., LTD.\"  },\r\n    { 0x1AA3, \"ZOLL Medical Corporation\"  },\r\n    { 0x1AA4, \"Data Drive Thru, Inc.\"  },\r\n    { 0x1AA5, \"UBeacon Technologies, Inc.\"  },\r\n    { 0x1AA6, \"eFortune Technology Corp.\"  },\r\n    { 0x1AA7, \"SiliconSystems, Inc.\"  },\r\n    { 0x1AA8, \"Waves Audio Ltd.\"  },\r\n    { 0x1AA9, \"Home Phone Tunes Inc.\"  },\r\n    { 0x1AAA, \"Taylor Associates/Communications, Inc.\"  },\r\n    { 0x1AAB, \"SilverCreations Software AG\"  },\r\n    { 0x1AAC, \"Witschi Electronic AG\"  },\r\n    { 0x1AAD, \"KeeTouch Electronic Co., Ltd.\"  },\r\n    { 0x1AAE, \"Johnson Component & Equipments Co., Ltd.\"  },\r\n    { 0x1AAF, \"Intellectual Property Library Company\"  },\r\n    { 0x1AB0, \"DAEWOO ELECTRONIC COMPONENTS CO., LTD.\"  },\r\n    { 0x1AB1, \"Rigol Technologies, Inc.\"  },\r\n    { 0x1AB2, \"Allied Vision Technologies GmbH\"  },\r\n    { 0x1AB3, \"M and C System\"  },\r\n    { 0x1AB4, \"Japan Remote Control Co., Ltd.\"  },\r\n    { 0x1AB5, \"Hamamatsu TOA Electronics, Inc.\"  },\r\n    { 0x1AB6, \"Integrated Technology Corp.\"  },\r\n    { 0x1AB7, \"GLOBAL VR, Inc.\"  },\r\n    { 0x1AB8, \"Pen Laboratory Inc.\"  },\r\n    { 0x1AB9, \"Nomadio Inc.\"  },\r\n    { 0x1ABA, \"Kenton Electronics Limited\"  },\r\n    { 0x1ABB, \"Airo Wireless Media Inc.\"  },\r\n    { 0x1ABC, \"Fuji Photo Film USA\"  },\r\n    { 0x1ABD, \"PERTO S.A.\"  },\r\n    { 0x1ABE, \"MP3Car.com Inc\"  },\r\n    { 0x1ABF, \"ANIMA Corporation\"  },\r\n    { 0x1AC0, \"SOKKIA Co., Ltd.\"  },\r\n    { 0x1AC1, \"LIANHE TECHNOLOGIES, INC.\"  },\r\n    { 0x1AC2, \"DESKO GmbH\"  },\r\n    { 0x1AC3, \"DISK KING Technology Co., Ltd.\"  },\r\n    { 0x1AC4, \"CAO Group, Inc.\"  },\r\n    { 0x1AC5, \"Electronic Engineering Solutions S.L.\"  },\r\n    { 0x1AC6, \"JAPAN ADE LTD.\"  },\r\n    { 0x1AC7, \"Modular Communication Systems, Inc.\"  },\r\n    { 0x1AC8, \"Toyota Industries Corporation\"  },\r\n    { 0x1AC9, \"Broadxent Pte. Ltd.\"  },\r\n    { 0x1ACA, \"Bluebird Soft Inc.\"  },\r\n    { 0x1ACB, \"Salcomp Plc\"  },\r\n    { 0x1ACC, \"Ta Horng Musical Instrument Co., Ltd.\"  },\r\n    { 0x1ACD, \"MKS Instruments\"  },\r\n    { 0x1ACE, \"Temento Systems\"  },\r\n    { 0x1ACF, \"International Manufacturing & Engineering Services Co.\"  },\r\n    { 0x1AD0, \"Cygnetron, Inc.\"  },\r\n    { 0x1AD1, \"Desan Wire Co., Ltd.\"  },\r\n    { 0x1AD2, \"Mesa Imaging AG\"  },\r\n    { 0x1AD3, \"Advanced Technetix, Inc.\"  },\r\n    { 0x1AD4, \"Advanced Printing Systems\"  },\r\n    { 0x1AD5, \"Gentec-EO\"  },\r\n    { 0x1AD6, \"General Dynamics SATCOM Technologies, State College Fac\"  },\r\n    { 0x1AD7, \"A.B.O. Co., Ltd.\"  },\r\n    { 0x1AD8, \"Motion Control i Vsters AB\"  },\r\n    { 0x1AD9, \"Rocket Gaming Systems\"  },\r\n    { 0x1ADA, \"VEGA Grieshaber KG\"  },\r\n    { 0x1ADB, \"Schweitzer Engineering Laboratories\"  },\r\n    { 0x1ADC, \"Turbolinux, Inc.\"  },\r\n    { 0x1ADD, \"Marshall Electronics, Inc.\"  },\r\n    { 0x1ADE, \"SpinMaster Ltd.\"  },\r\n    { 0x1ADF, \"digital design GmbH\"  },\r\n    { 0x1AE0, \"Axiomatic Technologies Corp.\"  },\r\n    { 0x1AE1, \"Hoffman Engineering\"  },\r\n    { 0x1AE2, \"A-JET Technology Co., LTD.\"  },\r\n    { 0x1AE3, \"Chung Young Digital Corp., Ltd.\"  },\r\n    { 0x1AE4, \"ic-design Reinhard Gottinger GmbH\"  },\r\n    { 0x1AE5, \"Jianduan Technology (Shenzhen) Co., Ltd\"  },\r\n    { 0x1AE6, \"JOA Telecom Co., Ltd.\"  },\r\n    { 0x1AE7, \"Joellenbeck GmbH\"  },\r\n    { 0x1AE8, \"Myway Labs Co., Ltd.\"  },\r\n    { 0x1AE9, \"arnotec GmbH\"  },\r\n    { 0x1AEA, \"Mobilygen Corporation\"  },\r\n    { 0x1AEB, \"NIHON UNICA CORPORATION\"  },\r\n    { 0x1AEC, \"PORTEK TECHNOLOGY CORPORATION\"  },\r\n    { 0x1AED, \"High Top Precision Electronic Co., Ltd.\"  },\r\n    { 0x1AEE, \"SHEN ZHEN REX TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1AEF, \"Octekconn Incorporation\"  },\r\n    { 0x1AF0, \"SuperPix Micro Technology Limited\"  },\r\n    { 0x1AF1, \"Connect One, Ltd.\"  },\r\n    { 0x1AF2, \"AXSionics AG\"  },\r\n    { 0x1AF3, \"Smarthome Technology Limited\"  },\r\n    { 0x1AF4, \"NCS Pearson, Inc.\"  },\r\n    { 0x1AF5, \"Arima Communications Corp.\"  },\r\n    { 0x1AF6, \"SL International Ltd.\"  },\r\n    { 0x1AF7, \"GRAPHIN CO., LTD.\"  },\r\n    { 0x1AF8, \"JS-ROBOTICS\"  },\r\n    { 0x1AF9, \"Alvarion Ltd.\"  },\r\n    { 0x1AFA, \"Mobinnova Corp.\"  },\r\n    { 0x1AFB, \"Kirche Jesu Christi der Heiligen der Letzten Tage\"  },\r\n    { 0x1AFC, \"Blue Orb\"  },\r\n    { 0x1AFD, \"FarSite Communications Limited\"  },\r\n    { 0x1AFE, \"A. Eberle GmbH & Co. KG\"  },\r\n    { 0x1AFF, \"Defibtech, LLC\"  },\r\n    { 0x1B00, \"Uster Technologies, Inc.\"  },\r\n    { 0x1B01, \"ETA Chips, Co.\"  },\r\n    { 0x1B02, \"MEN Mikro Elektronik GmbH\"  },\r\n    { 0x1B03, \"Moog Japan Ltd.\"  },\r\n    { 0x1B04, \"MEILHAUS Electronic GmbH\"  },\r\n    { 0x1B05, \"Cracol Developments Ltd.\"  },\r\n    { 0x1B06, \"OPGAL\"  },\r\n    { 0x1B07, \"WEY Technology AG\"  },\r\n    { 0x1B08, \"Actimo Inc.\"  },\r\n    { 0x1B09, \"MISUZU INDUSTRIES CORPORATION\"  },\r\n    { 0x1B0A, \"Sense Technology Inc.\"  },\r\n    { 0x1B0B, \"Lambda Systems Inc.\"  },\r\n    { 0x1B0C, \"MYTECS Co., Ltd.\"  },\r\n    { 0x1B0D, \"SmarDTV\"  },\r\n    { 0x1B0E, \"BLUTRONICS S.R.L.\"  },\r\n    { 0x1B0F, \"EKS-ELEKTRONIKSERVICE GmbH\"  },\r\n    { 0x1B10, \"KAGA COMPONENTS CO., LTD.\"  },\r\n    { 0x1B11, \"OneClick Technologies Ltd.\"  },\r\n    { 0x1B12, \"Eventide, Inc.\"  },\r\n    { 0x1B13, \"Neuf Cegetel\"  },\r\n    { 0x1B14, \"Ergotron, Inc.\"  },\r\n    { 0x1B15, \"i3micro technology ab\"  },\r\n    { 0x1B16, \"LinTech GmbH Berlin\"  },\r\n    { 0x1B17, \"SHENZHEN e-loam Technology Co., Ltd.\"  },\r\n    { 0x1B18, \"Mikrolab Entwicklungsgesellschaft fur Elektroniksysteme\"  },\r\n    { 0x1B19, \"RADA Electronic Industries Ltd.\"  },\r\n    { 0x1B1A, \"Tianjin China-Silicon Microelectronics Co., Ltd.\"  },\r\n    { 0x1B1B, \"Shenzhen MD Electric Co., Ltd.\"  },\r\n    { 0x1B1C, \"CORSAIR MEMORY INC.\"  },\r\n    { 0x1B1D, \"Torian Wireless Ltd.\"  },\r\n    { 0x1B1E, \"General Imaging Company\"  },\r\n    { 0x1B1F, \"eQ-3 Entwicklung GmbH\"  },\r\n    { 0x1B20, \"MStar Semiconductor, Inc.\"  },\r\n    { 0x1B21, \"XenICs nv\"  },\r\n    { 0x1B22, \"WiLinx Corp.\"  },\r\n    { 0x1B23, \"Skyray Instrument Co., Ltd.\"  },\r\n    { 0x1B24, \"Telegent Systems Inc.\"  },\r\n    { 0x1B25, \"ALE\"  },\r\n    { 0x1B26, \"Plug Power\"  },\r\n    { 0x1B27, \"Current Electronics Inc.\"  },\r\n    { 0x1B28, \"NAVIsis Inc.\"  },\r\n    { 0x1B29, \"Industrie Dial Face S.p.A.\"  },\r\n    { 0x1B2A, \"MICRO EMISSION CO., LTD.\"  },\r\n    { 0x1B2B, \"Neural Image Co., Ltd.\"  },\r\n    { 0x1B2C, \"Advanced Thermal Solutions, Inc.\"  },\r\n    { 0x1B2D, \"Photon Inc.\"  },\r\n    { 0x1B2E, \"ETANI ELECTRONICS CO., LTD.\"  },\r\n    { 0x1B2F, \"Ihara Electronic Industries Co.,Ltd.\"  },\r\n    { 0x1B30, \"STZ QSBV Ilmenau\"  },\r\n    { 0x1B31, \"Renu Electronics Pvt. Ltd.\"  },\r\n    { 0x1B32, \"Ugobe, Inc.\"  },\r\n    { 0x1B33, \"3DV Systems Ltd.\"  },\r\n    { 0x1B34, \"EyeTalk Systems, Inc.\"  },\r\n    { 0x1B35, \"Paradigm Electronics Inc.\"  },\r\n    { 0x1B36, \"ViXS Systems, Inc.\"  },\r\n    { 0x1B37, \"Savant Systems, LLC\"  },\r\n    { 0x1B38, \"ALBAHITH TECHNOLOGIES\"  },\r\n    { 0x1B39, \"ViaMichelin SAS\"  },\r\n    { 0x1B3A, \"JUMO GmbH & Co. KG\"  },\r\n    { 0x1B3B, \"iPassion Technology Inc.\"  },\r\n    { 0x1B3C, \"DEVI A/S\"  },\r\n    { 0x1B3D, \"Matrix Orbital\"  },\r\n    { 0x1B3E, \"STIL SA\"  },\r\n    { 0x1B3F, \"Generalplus Technology Inc.\"  },\r\n    { 0x1B40, \"AISIN SEIKI CO., LTD.\"  },\r\n    { 0x1B41, \"Fujitsu Australia Limited\"  },\r\n    { 0x1B42, \"Cardinal Scale Manufacturing Company\"  },\r\n    { 0x1B43, \"Extron Design Services\"  },\r\n    { 0x1B44, \"Elite Co., Ltd.\"  },\r\n    { 0x1B45, \"Cyan Technology Ltd.\"  },\r\n    { 0x1B46, \"Holylite Microelectronics Corp.\"  },\r\n    { 0x1B47, \"Energizer Holdings, Inc.\"  },\r\n    { 0x1B48, \"Plastron Precision Co., Ltd.\"  },\r\n    { 0x1B49, \"Applied Printed Electronics Research, LLC\"  },\r\n    { 0x1B4A, \"Gem-Med, S.L.\"  },\r\n    { 0x1B4B, \"Watson Marlow Ltd.\"  },\r\n    { 0x1B4C, \"Unitron Group\"  },\r\n    { 0x1B4D, \"Objet Geometries Ltd.\"  },\r\n    { 0x1B4E, \"ELPRO-BUCHS AG\"  },\r\n    { 0x1B4F, \"Spark Fun Electronics\"  },\r\n    { 0x1B50, \"DictaNet Software AG\"  },\r\n    { 0x1B51, \"Kundisch GmbH & Co. KG\"  },\r\n    { 0x1B52, \"A.R. Hungary, Inc.\"  },\r\n    { 0x1B53, \"DANI Instruments S.p.A.\"  },\r\n    { 0x1B54, \"COMMIT Incorporated\"  },\r\n    { 0x1B55, \"ZKSoftware Inc.\"  },\r\n    { 0x1B56, \"V.I.O., Inc.\"  },\r\n    { 0x1B57, \"ATREE Inc.\"  },\r\n    { 0x1B58, \"Sumitomo Elec Ind Ltd. Lightwave Network Products Div.\"  },\r\n    { 0x1B59, \"K.S. Terminals Inc.\"  },\r\n    { 0x1B5A, \"Chao Zhou Kai Yuan Electric Co., Ltd.\"  },\r\n    { 0x1B5B, \"Homoth Medizinelektronik\"  },\r\n    { 0x1B5C, \"ICP DAS Co., Ltd.\"  },\r\n    { 0x1B5D, \"MV Circuit Design, Inc.\"  },\r\n    { 0x1B5E, \"General Engine Management Systems Ltd.\"  },\r\n    { 0x1B5F, \"Wayne Dalton Corp.\"  },\r\n    { 0x1B60, \"NanoDrop Technologies, Inc.\"  },\r\n    { 0x1B61, \"n-Trance Security Ltd.\"  },\r\n    { 0x1B62, \"Shenzhen Aoni Electronic Industry Co., Ltd.\"  },\r\n    { 0x1B63, \"Seedsware Corporation\"  },\r\n    { 0x1B64, \"C.G. Development Ltd.\"  },\r\n    { 0x1B65, \"The Hong Kong Standards and Testing Centre Ltd.\"  },\r\n    { 0x1B66, \"Bontempi-Farfisa Sigma S.p.A.\"  },\r\n    { 0x1B67, \"Toradex AG\"  },\r\n    { 0x1B68, \"ZAFENA AB\"  },\r\n    { 0x1B69, \"KLA-Tencor\"  },\r\n    { 0x1B6A, \"HIKARI Co., Ltd.\"  },\r\n    { 0x1B6B, \"Modiotek Co., Ltd.\"  },\r\n    { 0x1B6C, \"Techno Veins Co., Ltd.\"  },\r\n    { 0x1B6D, \"IDpendant GmbH\"  },\r\n    { 0x1B6E, \"HS Automatic ApS\"  },\r\n    { 0x1B6F, \"Federal Signal Vama S.A.\"  },\r\n    { 0x1B70, \"Minicom Advanced Systems\"  },\r\n    { 0x1B71, \"Huizhou 10Moons Technology Development Co., Ltd.\"  },\r\n    { 0x1B72, \"ATERGI TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1B73, \"Vehicle Camera Systems Ltd\"  },\r\n    { 0x1B74, \"MODAFUN, Inc.\"  },\r\n    { 0x1B75, \"OvisLink Corp.\"  },\r\n    { 0x1B76, \"Legend Silicon Corp.\"  },\r\n    { 0x1B77, \"Protec, Inc.\"  },\r\n    { 0x1B78, \"LOGICPACK CO., LTD.\"  },\r\n    { 0x1B79, \"WingsTek, Inc.\"  },\r\n    { 0x1B7A, \"Electrox\"  },\r\n    { 0x1B7B, \"Ingersoll Rand Co.\"  },\r\n    { 0x1B7C, \"io Corporation\"  },\r\n    { 0x1B7D, \"SUNGIL TELECOM\"  },\r\n    { 0x1B7E, \"Lutron Electronics Inc.\"  },\r\n    { 0x1B7F, \"EMC Corporation\"  },\r\n    { 0x1B80, \"KWorld Computer Co., Ltd.\"  },\r\n    { 0x1B81, \"Kratos Analytical Ltd.\"  },\r\n    { 0x1B82, \"Mcube Technology Co., Ltd.\"  },\r\n    { 0x1B83, \"Megatone systems and Technologies LTD.\"  },\r\n    { 0x1B84, \"WALTHER Data GmbH Scan-Solutions\"  },\r\n    { 0x1B85, \"INNOVA S.A.\"  },\r\n    { 0x1B86, \"Dongguan Guanshang Electronics Co., Ltd.\"  },\r\n    { 0x1B87, \"Davis Instruments\"  },\r\n    { 0x1B88, \"ShenMing Electron (Dong Guan) Co., Ltd.\"  },\r\n    { 0x1B89, \"iCache, Incorporated\"  },\r\n    { 0x1B8A, \"Quellan, Inc.\"  },\r\n    { 0x1B8B, \"PROCES-DATA A/S\"  },\r\n    { 0x1B8C, \"Altium Limited\"  },\r\n    { 0x1B8D, \"e-MOVE Technology Co., Ltd.\"  },\r\n    { 0x1B8E, \"Amlogic, Inc.\"  },\r\n    { 0x1B8F, \"Super Talent Technology, Inc.\"  },\r\n    { 0x1B90, \"Deep Sea Electronics Plc\"  },\r\n    { 0x1B91, \"Zicplay SA\"  },\r\n    { 0x1B92, \"Trysys Co., Ltd.\"  },\r\n    { 0x1B93, \"Phoenix Contact GmbH & Co. KG\"  },\r\n    { 0x1B94, \"Yoggie Security Systems\"  },\r\n    { 0x1B95, \"EVC electronic GmbH\"  },\r\n    { 0x1B96, \"N-Trig\"  },\r\n    { 0x1B97, \"Metronix GmbH\"  },\r\n    { 0x1B98, \"YMax Communications Corp.\"  },\r\n    { 0x1B99, \"Shenzhen Yuanchuan Electronic\"  },\r\n    { 0x1B9A, \"Applied Vision Systems Corporation\"  },\r\n    { 0x1B9B, \"Microtrac, Inc.\"  },\r\n    { 0x1B9C, \"Maki Manufacturing Co., Ltd.\"  },\r\n    { 0x1B9D, \"Sigma Instruments, Inc.\"  },\r\n    { 0x1B9E, \"ARCoptix S.A\"  },\r\n    { 0x1B9F, \"GHI Electronics, LLC\"  },\r\n    { 0x1BA0, \"Jiangmen Kong Yue Jolimark Information Technology Ltd.\"  },\r\n    { 0x1BA1, \"JINQ CHERN ENTERPRISE CO., LTD.\"  },\r\n    { 0x1BA2, \"Lite Metals & Plastic (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1BA3, \"EmbeddedFusion Ltd.\"  },\r\n    { 0x1BA4, \"Ember Corporation\"  },\r\n    { 0x1BA5, \"Futiro\"  },\r\n    { 0x1BA6, \"Abilis Systems\"  },\r\n    { 0x1BA7, \"Xantech Corporation\"  },\r\n    { 0x1BA8, \"China Telecommunication Technology Labs\"  },\r\n    { 0x1BA9, \"Renau Electronic Laboratories\"  },\r\n    { 0x1BAA, \"Transcell Technology, Inc.\"  },\r\n    { 0x1BAB, \"MATT R.P.Traczynscy Sp.J.\"  },\r\n    { 0x1BAC, \"Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.\"  },\r\n    { 0x1BAD, \"Harmonix Music Systems, Inc.\"  },\r\n    { 0x1BAE, \"Vuzix Corporation\"  },\r\n    { 0x1BAF, \"NIIGATA SEIMITSU CO., LTD.\"  },\r\n    { 0x1BB0, \"LBS PLUS Co., Ltd.\"  },\r\n    { 0x1BB1, \"Commodore International Corporation\"  },\r\n    { 0x1BB2, \"G.T. trading Srl\"  },\r\n    { 0x1BB3, \"Holzworth Instrumentation LLC\"  },\r\n    { 0x1BB4, \"Satmap Systems Ltd.\"  },\r\n    { 0x1BB5, \"SEF Roboter GmbH\"  },\r\n    { 0x1BB6, \"PdMA Corporation\"  },\r\n    { 0x1BB7, \"DGT Sp. z o.o.\"  },\r\n    { 0x1BB8, \"MIZOUE PROJECT JAPAN Corporation\"  },\r\n    { 0x1BB9, \"Qpixel Technology, Inc.\"  },\r\n    { 0x1BBA, \"Medicomp, Inc.\"  },\r\n    { 0x1BBB, \"TCL Communication Ltd\"  },\r\n    { 0x1BBC, \"KATHREIN-Werke KG\"  },\r\n    { 0x1BBD, \"Videology Imaging Solutions, Inc.\"  },\r\n    { 0x1BBE, \"CE+T s.a.\"  },\r\n    { 0x1BBF, \"Littfinski DatenTechnik (LDT)\"  },\r\n    { 0x1BC0, \"Senselock Software Technology Co.,Ltd\"  },\r\n    { 0x1BC1, \"ACE ELECTRONIQUE\"  },\r\n    { 0x1BC2, \"SEW-EURODRIVE GmbH & Co. KG\"  },\r\n    { 0x1BC3, \"Fujian START Computer Equipment Co., Ltd.\"  },\r\n    { 0x1BC4, \"Ford Motor Co.\"  },\r\n    { 0x1BC5, \"AVIXE Technology (China) Ltd.\"  },\r\n    { 0x1BC6, \"Yurex, Inc.\"  },\r\n    { 0x1BC7, \"Telit Wireless Solutions\"  },\r\n    { 0x1BC8, \"MDS Technology Co., Ltd.\"  },\r\n    { 0x1BC9, \"Alti-2 Inc.\"  },\r\n    { 0x1BCA, \"Ishii Hyoki Co., Ltd.\"  },\r\n    { 0x1BCB, \"Cubic Defence NZ Limited\"  },\r\n    { 0x1BCC, \"TopScan Ltd.\"  },\r\n    { 0x1BCD, \"AZKOYEN\"  },\r\n    { 0x1BCE, \"Contac Cable Industrial Limited\"  },\r\n    { 0x1BCF, \"Sunplus Innovation Technology Inc.\"  },\r\n    { 0x1BD0, \"Hangzhou Riyue Electronics Co., Ltd.\"  },\r\n    { 0x1BD1, \"Companion Worlds, Inc.\"  },\r\n    { 0x1BD2, \"Beijing G & D Card Systems Co., Ltd.\"  },\r\n    { 0x1BD3, \"3layer Engineering\"  },\r\n    { 0x1BD4, \"FastVDO Inc.\"  },\r\n    { 0x1BD5, \"BG Systems, Inc.\"  },\r\n    { 0x1BD6, \"Lodam electronics\"  },\r\n    { 0x1BD7, \"TouchNetworks, Inc.\"  },\r\n    { 0x1BD8, \"Image Computer Systems Limited\"  },\r\n    { 0x1BD9, \"Emerson\"  },\r\n    { 0x1BDA, \"University of Southampton\"  },\r\n    { 0x1BDB, \"Spectral Applied Research\"  },\r\n    { 0x1BDC, \"Slacker\"  },\r\n    { 0x1BDD, \"QiGO Inc\"  },\r\n    { 0x1BDE, \"P-TWO INDUSTRIES, INC.\"  },\r\n    { 0x1BDF, \"Electrone Americas Ltd., Co.\"  },\r\n    { 0x1BE0, \"Analog Devices, Inc. - Test Technology Group\"  },\r\n    { 0x1BE1, \"LG-Ericsson Co., Ltd\"  },\r\n    { 0x1BE2, \"Shenzhen Fametech Electronic Co., Ltd.\"  },\r\n    { 0x1BE3, \"WAGO Kontakttechnik GmbH & Co. KG\"  },\r\n    { 0x1BE4, \"Integrated Digital Technologies, Inc. (IDTI)\"  },\r\n    { 0x1BE5, \"NetLogic Microsystems\"  },\r\n    { 0x1BE6, \"NAVENTO TECHNOLOGIES\"  },\r\n    { 0x1BE7, \"CPR Tools, Inc.\"  },\r\n    { 0x1BE8, \"MEDAV GmbH\"  },\r\n    { 0x1BE9, \"CONCH ELECTRONIC CO., LTD.\"  },\r\n    { 0x1BEA, \"ATTO Corporation\"  },\r\n    { 0x1BEB, \"HOYA CANDEO OPTRONICS CORPORATION\"  },\r\n    { 0x1BEC, \"isMedia Co., Ltd.\"  },\r\n    { 0x1BED, \"OPT Corporation\"  },\r\n    { 0x1BEE, \"KCI Medical Products (UK) Ltd.\"  },\r\n    { 0x1BEF, \"Shenzhen Tongyuan Network-Communication Cables Co., Ltd\"  },\r\n    { 0x1BF0, \"RealVision Inc.\"  },\r\n    { 0x1BF1, \"HENGSTLER\"  },\r\n    { 0x1BF2, \"Newport Media, Inc.\"  },\r\n    { 0x1BF3, \"WAVES SYSTEM / SONAMIX\"  },\r\n    { 0x1BF4, \"ABB / Drives\"  },\r\n    { 0x1BF5, \"Extranet Systems Inc.\"  },\r\n    { 0x1BF6, \"Orient Semiconductor Electronics, Ltd.\"  },\r\n    { 0x1BF7, \"Axiotron, Inc.\"  },\r\n    { 0x1BF8, \"Game Mechanisms LLC\"  },\r\n    { 0x1BF9, \"TRACTEL SAS\"  },\r\n    { 0x1BFA, \"METROLAB TECHNOLOGY SA\"  },\r\n    { 0x1BFB, \"ALLIED PANELS\"  },\r\n    { 0x1BFC, \"Guidance Interactive Healthcare\"  },\r\n    { 0x1BFD, \"RISINTECH INC.\"  },\r\n    { 0x1BFE, \"SEOHWA TELECOM Co., LTD.\"  },\r\n    { 0x1BFF, \"IonOptix Corp.\"  },\r\n    { 0x1C00, \"prodaSafe GmbH\"  },\r\n    { 0x1C01, \"No Climb Products Ltd.\"  },\r\n    { 0x1C02, \"Kreton Corporation\"  },\r\n    { 0x1C03, \"DDL CO., LTD.\"  },\r\n    { 0x1C04, \"QNAP System Inc.\"  },\r\n    { 0x1C05, \"Rockwell Collins\"  },\r\n    { 0x1C06, \"SeekTech, Inc.\"  },\r\n    { 0x1C07, \"CEntrance, Inc.\"  },\r\n    { 0x1C08, \"Arcus-EDS GmbH\"  },\r\n    { 0x1C09, \"RAMTEX Engineering ApS\"  },\r\n    { 0x1C0A, \"MaxRise Inc.\"  },\r\n    { 0x1C0B, \"Kato Tech Co., Ltd.\"  },\r\n    { 0x1C0C, \"Ionics EMS Inc.\"  },\r\n    { 0x1C0D, \"Relm Wireless\"  },\r\n    { 0x1C0E, \"Qstik plc\"  },\r\n    { 0x1C0F, \"NEOTECHKNO\"  },\r\n    { 0x1C10, \"Lanterra Industrial Co., Ltd.\"  },\r\n    { 0x1C11, \"UNIMTEC Co., Ltd.\"  },\r\n    { 0x1C12, \"CONITEC DATENSYSTEME GmbH\"  },\r\n    { 0x1C13, \"ALECTRONIC LIMITED\"  },\r\n    { 0x1C14, \"SENSITIVE OBJECT\"  },\r\n    { 0x1C15, \"TeleWell Oy\"  },\r\n    { 0x1C16, \"Afit Corporation\"  },\r\n    { 0x1C17, \"LAB REHAB PTE LTD.\"  },\r\n    { 0x1C18, \"Apria Technology\"  },\r\n    { 0x1C19, \"Charder Electronic Co., Ltd.\"  },\r\n    { 0x1C1A, \"Datel Electronics Ltd.\"  },\r\n    { 0x1C1B, \"Volkswagen of America, Inc.\"  },\r\n    { 0x1C1C, \"Schmartz Inc.\"  },\r\n    { 0x1C1D, \"GASTEC CORPORATION\"  },\r\n    { 0x1C1E, \"Focused Test, Inc.\"  },\r\n    { 0x1C1F, \"Goldvish S.A.\"  },\r\n    { 0x1C20, \"Fuji Electric Device Technology Co., Ltd.\"  },\r\n    { 0x1C21, \"ADDMM LLC\"  },\r\n    { 0x1C22, \"ZHONGSHAN CHIANG YU ELECTRIC CO., LTD.\"  },\r\n    { 0x1C23, \"Enzytek Technology Inc.\"  },\r\n    { 0x1C24, \"DIGITAL IMAGING SYSTEMS GmbH\"  },\r\n    { 0x1C25, \"Sunwell Electronics Ltd.\"  },\r\n    { 0x1C26, \"Shanghai Haiying Electronics Co., Ltd.\"  },\r\n    { 0x1C27, \"SHENZHEN DNS INDUSTRIES CO., LTD.\"  },\r\n    { 0x1C28, \"PMDTechnologies\"  },\r\n    { 0x1C29, \"Elster Group\"  },\r\n    { 0x1C2A, \"NAVIGON AG\"  },\r\n    { 0x1C2B, \"SIEB & MEYER AG\"  },\r\n    { 0x1C2C, \"QUANTEL LTD.\"  },\r\n    { 0x1C2D, \"Barloworld Scientific Limited\"  },\r\n    { 0x1C2E, \"LiveWire Test Labs, Inc.\"  },\r\n    { 0x1C2F, \"Wessex Advanced Switching Products Ltd.\"  },\r\n    { 0x1C30, \"Li Creative Technologies, Inc.\"  },\r\n    { 0x1C31, \"LS Mtron Ltd.\"  },\r\n    { 0x1C32, \"INTELBANQ\"  },\r\n    { 0x1C33, \"EK-TEAM GmbH\"  },\r\n    { 0x1C34, \"Pro-Active\"  },\r\n    { 0x1C35, \"Superna Inc.\"  },\r\n    { 0x1C36, \"Axiom Manufacturing\"  },\r\n    { 0x1C37, \"Sonavation, Inc.\"  },\r\n    { 0x1C38, \"Kirin Techno-System Company, Limited\"  },\r\n    { 0x1C39, \"Quantronix, Inc.\"  },\r\n    { 0x1C3A, \"CCV Deutschland GmbH\"  },\r\n    { 0x1C3B, \"Nivis, LLC\"  },\r\n    { 0x1C3C, \"INFOTURE, INC.\"  },\r\n    { 0x1C3D, \"NONIN MEDICAL INC.\"  },\r\n    { 0x1C3E, \"Wep Peripherals\"  },\r\n    { 0x1C3F, \"Amfit, Inc.\"  },\r\n    { 0x1C40, \"EZ PROTOTYPES\"  },\r\n    { 0x1C41, \"CompX Fort\"  },\r\n    { 0x1C42, \"VERCET LLC\"  },\r\n    { 0x1C43, \"PeCon GmbH\"  },\r\n    { 0x1C44, \"Fukasawa Co.\"  },\r\n    { 0x1C45, \"NavCom Technology Inc.\"  },\r\n    { 0x1C46, \"Hitachi Zosen Corporation\"  },\r\n    { 0x1C47, \"Andrew Telecommunication Product SRL\"  },\r\n    { 0x1C48, \"International Truck and Engine Corporation\"  },\r\n    { 0x1C49, \"Cherng Weei Technology Corp.\"  },\r\n    { 0x1C4A, \"Cathay Tri-Tech., Inc.\"  },\r\n    { 0x1C4B, \"Geratherm Respiratory GmbH\"  },\r\n    { 0x1C4C, \"SYSTECH\"  },\r\n    { 0x1C4D, \"Everest Display Inc.\"  },\r\n    { 0x1C4E, \"Koninklijke Gazelle N.V.\"  },\r\n    { 0x1C4F, \"Beijing Sigmachip Co., Ltd.\"  },\r\n    { 0x1C50, \"Chatsworth Data Corporation\"  },\r\n    { 0x1C51, \"Wisecube Co., Ltd.\"  },\r\n    { 0x1C52, \"FLEETWOOD ELECTRONICS LTD.\"  },\r\n    { 0x1C53, \"Heartland Data Co.\"  },\r\n    { 0x1C54, \"NU-LEC INDUSTRIES\"  },\r\n    { 0x1C55, \"LGS\"  },\r\n    { 0x1C56, \"RED DIGITAL CINEMA\"  },\r\n    { 0x1C57, \"Zalman Tech Co., Ltd.\"  },\r\n    { 0x1C58, \"IVA Corporation\"  },\r\n    { 0x1C59, \"SIXNET, LLC\"  },\r\n    { 0x1C5A, \"Fisher and Paykel Healthcare Limited\"  },\r\n    { 0x1C5B, \"FUTURE WAVES PTE Ltd.\"  },\r\n    { 0x1C5C, \"CELLMETRIC LTD.\"  },\r\n    { 0x1C5D, \"KB Kommutatcionnoy apparatury LTD.\"  },\r\n    { 0x1C5E, \"Fueltech Ind. & Com. Prod. Elet. Ltda.\"  },\r\n    { 0x1C5F, \"Watec Co., Ltd.\"  },\r\n    { 0x1C60, \"Vision & Control GmbH\"  },\r\n    { 0x1C61, \"ASI DataMyte, Inc.\"  },\r\n    { 0x1C62, \"LITEPOINT CORP.\"  },\r\n    { 0x1C63, \"DLP Design, Inc.\"  },\r\n    { 0x1C64, \"QSI Corporation\"  },\r\n    { 0x1C65, \"PROCENTEC\"  },\r\n    { 0x1C66, \"The Trane Company\"  },\r\n    { 0x1C67, \"Sugar Creek Solutions LLC\"  },\r\n    { 0x1C68, \"Trace Systems, Inc.\"  },\r\n    { 0x1C69, \"MPB Communications\"  },\r\n    { 0x1C6A, \"Regula Ltd.\"  },\r\n    { 0x1C6B, \"Philips & Lite-ON Digital Solutions Corporation\"  },\r\n    { 0x1C6C, \"Skydigital Inc.\"  },\r\n    { 0x1C6D, \"Bioptigen Inc.\"  },\r\n    { 0x1C6E, \"MINELAB ELECTRONICS PTY LTD.\"  },\r\n    { 0x1C6F, \"SUN-A CORPORATION\"  },\r\n    { 0x1C70, \"Wessa Engineering\"  },\r\n    { 0x1C71, \"HUMANWARE LTD.\"  },\r\n    { 0x1C72, \"EMTEC Elektronische Messtechnik GmbH\"  },\r\n    { 0x1C73, \"AMT Co., Ltd.\"  },\r\n    { 0x1C74, \"PHOTOVOX srl\"  },\r\n    { 0x1C75, \"ARTURIA\"  },\r\n    { 0x1C76, \"Sun-Light Electronic Technologies Inc.\"  },\r\n    { 0x1C77, \"Kaetat Industrial Co., Ltd.\"  },\r\n    { 0x1C78, \"Mindray DS USA, Inc.\"  },\r\n    { 0x1C79, \"Unigen Corporation\"  },\r\n    { 0x1C7A, \"Egis Technology, Inc.\"  },\r\n    { 0x1C7B, \"Shenzhen Luxshare Precision Industry Co., Ltd.\"  },\r\n    { 0x1C7C, \"DELCOP LLC\"  },\r\n    { 0x1C7D, \"STARKEY LABORATORIES INC.\"  },\r\n    { 0x1C7E, \"Hydrometer GmbH\"  },\r\n    { 0x1C7F, \"FILTRONIC DEFENCE LIMITED\"  },\r\n    { 0x1C80, \"Hoffmann + Krippner GmbH\"  },\r\n    { 0x1C81, \"MOTOSOFT b.v.\"  },\r\n    { 0x1C82, \"Atracsys LLC\"  },\r\n    { 0x1C83, \"BEKA Elektronik\"  },\r\n    { 0x1C84, \"DRS Tactical Systems\"  },\r\n    { 0x1C85, \"Audyssey Laboratories, Inc.\"  },\r\n    { 0x1C86, \"Tallahassee Technologies, Inc.\"  },\r\n    { 0x1C87, \"2N TELEKOMUNIKACE a.s.\"  },\r\n    { 0x1C88, \"Somagic, Inc.\"  },\r\n    { 0x1C89, \"HONGKONG WEIDIDA ELECTRON LIMITED\"  },\r\n    { 0x1C8A, \"SHIN HEUNG PRECISION CO., LTD.\"  },\r\n    { 0x1C8B, \"Bridgestone Cycle Co., Ltd.\"  },\r\n    { 0x1C8C, \"noax Technologies AG\"  },\r\n    { 0x1C8D, \"Payter BV\"  },\r\n    { 0x1C8E, \"ASTRON INTERNATIONAL CORP.\"  },\r\n    { 0x1C8F, \"Scolis Technologies (India) Pvt. Ltd.\"  },\r\n    { 0x1C90, \"Pixela (Shanghai) Co., Ltd.\"  },\r\n    { 0x1C91, \"Hutchinson Technology Incorporated\"  },\r\n    { 0x1C92, \"JDD Enterprises\"  },\r\n    { 0x1C93, \"Airspan Networks\"  },\r\n    { 0x1C94, \"Maerzhaeuser Wetzlar GmbH & Co. KG.\"  },\r\n    { 0x1C95, \"OVATION SYSTEMS LIMITED\"  },\r\n    { 0x1C96, \"Tesselon, LLC\"  },\r\n    { 0x1C97, \"PEBBLE ENTERTAINMENT GmbH\"  },\r\n    { 0x1C98, \"ALPINE ELECTRONICS, INC.\"  },\r\n    { 0x1C99, \"KETEREX, Inc.\"  },\r\n    { 0x1C9A, \"Simple Step LLC\"  },\r\n    { 0x1C9B, \"Ohden Co., Ltd.\"  },\r\n    { 0x1C9C, \"Technological Solutions Laboratory\"  },\r\n    { 0x1C9D, \"Descuentos y Electronicos AVA\"  },\r\n    { 0x1C9E, \"Shanghai Longcheer 3G Technology Co., Ltd.\"  },\r\n    { 0x1C9F, \"SISS Technology Inc.\"  },\r\n    { 0x1CA0, \"ACCARIO Inc.\"  },\r\n    { 0x1CA1, \"Symwave, Inc.\"  },\r\n    { 0x1CA2, \"G-coder Systems AB\"  },\r\n    { 0x1CA3, \"CAPAZ GmbH\"  },\r\n    { 0x1CA4, \"METRICO WIRELESS INC.\"  },\r\n    { 0x1CA5, \"HASLER RAIL AG\"  },\r\n    { 0x1CA6, \"TECHNO-AP Limited Company\"  },\r\n    { 0x1CA7, \"BAE SYSTEMS AUSTRALIA LIMITED\"  },\r\n    { 0x1CA8, \"ROCCAT STUDIO GmbH\"  },\r\n    { 0x1CA9, \"THE TINTOMETER LTD.\"  },\r\n    { 0x1CAA, \"Accel Semiconductor Corp.\"  },\r\n    { 0x1CAB, \"SCS Engineering, Inc.\"  },\r\n    { 0x1CAC, \"SHENZHEN KINSTONE D&T DEVELOP CO., LTD.\"  },\r\n    { 0x1CAD, \"ONE-TOO\"  },\r\n    { 0x1CAE, \"MPMAN\"  },\r\n    { 0x1CAF, \"2WCOM GmbH\"  },\r\n    { 0x1CB0, \"LEGRAND FRANCE\"  },\r\n    { 0x1CB1, \"Enforce Device Inc.\"  },\r\n    { 0x1CB2, \"PCO AG\"  },\r\n    { 0x1CB3, \"Aces Electronics Co., Ltd.\"  },\r\n    { 0x1CB4, \"OPEX CORPORATION\"  },\r\n    { 0x1CB5, \"Boonton Electronics\"  },\r\n    { 0x1CB6, \"IDEACOM TECHNOLOGY INC.\"  },\r\n    { 0x1CB7, \"EASTERN TIMES TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1CB8, \"Ferguson Beauregard\"  },\r\n    { 0x1CB9, \"DIVERSIFIED TECHNICAL SYSTEMS, INC.\"  },\r\n    { 0x1CBA, \"MERIDIAN AUDIO LTD.\"  },\r\n    { 0x1CBB, \"DATATEC CO., LTD.\"  },\r\n    { 0x1CBC, \"Zizzle, LLC\"  },\r\n    { 0x1CBD, \"Wha Shin Co., Ltd.\"  },\r\n    { 0x1CBE, \"Texas Instruments - Stellaris\"  },\r\n    { 0x1CBF, \"FORTAT SKYMARK INDUSTRIAL COMPANY\"  },\r\n    { 0x1CC0, \"PlantSense\"  },\r\n    { 0x1CC1, \"EXAKTIME INC.\"  },\r\n    { 0x1CC2, \"CC Systems AB\"  },\r\n    { 0x1CC3, \"Biocomfort Diagnostics GmbH & Co. KG\"  },\r\n    { 0x1CC4, \"Byte Paradigm sprl\"  },\r\n    { 0x1CC5, \"Rane Corporation\"  },\r\n    { 0x1CC6, \"Digital Force Technologies\"  },\r\n    { 0x1CC7, \"GELOGIC\"  },\r\n    { 0x1CC8, \"Iofy Corporation\"  },\r\n    { 0x1CC9, \"COMAP, spol. s r. o.\"  },\r\n    { 0x1CCA, \"NextWave Broadband Inc.\"  },\r\n    { 0x1CCB, \"Lattebox Co., Ltd.\"  },\r\n    { 0x1CCC, \"DA-DESIGN OY\"  },\r\n    { 0x1CCD, \"Bodatong Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1CCE, \"DATA MODUL\"  },\r\n    { 0x1CCF, \"Konami Digital Entertainment Co., Ltd.\"  },\r\n    { 0x1CD0, \"VEGATECH CO., LTD.\"  },\r\n    { 0x1CD1, \"ARTAFLEX\"  },\r\n    { 0x1CD2, \"Christ Elektronik GmbH\"  },\r\n    { 0x1CD3, \"ATSUMI ELECTRIC CO., LTD.\"  },\r\n    { 0x1CD4, \"adp corporation\"  },\r\n    { 0x1CD5, \"Firecomms Ltd.\"  },\r\n    { 0x1CD6, \"Antonio Precise Products Manufactory Ltd.\"  },\r\n    { 0x1CD7, \"GMC-I Gossen-Metrawatt GmbH\"  },\r\n    { 0x1CD8, \"Dash Navigation, Inc.\"  },\r\n    { 0x1CD9, \"TL Industries\"  },\r\n    { 0x1CDA, \"NAVICO\"  },\r\n    { 0x1CDB, \"Cat Technologies Ltd.\"  },\r\n    { 0x1CDC, \"Advanced Medical Electronics Corp.\"  },\r\n    { 0x1CDD, \"YOOSAMFLUTE CO., LTD.\"  },\r\n    { 0x1CDE, \"Telecommunications Technology Association (TTA)\"  },\r\n    { 0x1CDF, \"WonTen Technology Co., Ltd.\"  },\r\n    { 0x1CE0, \"EDIMAX TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1CE1, \"Amphenol KAE\"  },\r\n    { 0x1CE2, \"Extron Electronics\"  },\r\n    { 0x1CE3, \"Australian Simulation Control Systems Pty., Ltd.\"  },\r\n    { 0x1CE4, \"High Leah Electronics, Inc.\"  },\r\n    { 0x1CE5, \"SimPhonics, Inc.\"  },\r\n    { 0x1CE6, \"SOPRO\"  },\r\n    { 0x1CE7, \"FASY SPA\"  },\r\n    { 0x1CE8, \"Alcorn McBride, Inc.\"  },\r\n    { 0x1CE9, \"Cadmus Payment Solutions Ltd.\"  },\r\n    { 0x1CEA, \"MESTEK, INC.\"  },\r\n    { 0x1CEB, \"SMARTWI\"  },\r\n    { 0x1CEC, \"Siemens AG I & S Postal Automation\"  },\r\n    { 0x1CED, \"DEWESOFT d.o.o.\"  },\r\n    { 0x1CEE, \"Production Technology Center Kyushuu\"  },\r\n    { 0x1CEF, \"Siemens LD-A\"  },\r\n    { 0x1CF0, \"SA VALIDY\"  },\r\n    { 0x1CF1, \"dresden elektronik ingenieurtechnik gmbh\"  },\r\n    { 0x1CF2, \"TrellisWare Technologies, Inc.\"  },\r\n    { 0x1CF3, \"Lion Power Co., Ltd.\"  },\r\n    { 0x1CF4, \"SK INTERFACES LTD.\"  },\r\n    { 0x1CF5, \"Swirlnet A/S\"  },\r\n    { 0x1CF6, \"Atlantic Zeiser GmbH\"  },\r\n    { 0x1CF7, \"Electric-Spin\"  },\r\n    { 0x1CF8, \"Biometric Associates\"  },\r\n    { 0x1CF9, \"Aipermon GmbH & Co. KG\"  },\r\n    { 0x1CFA, \"Daco Scientific Limited\"  },\r\n    { 0x1CFB, \"Livescribe Inc.\"  },\r\n    { 0x1CFC, \"ANDES TECHNOLOGY CORPORATION\"  },\r\n    { 0x1CFD, \"Flextronics Digital Design Japan, LTD.\"  },\r\n    { 0x1CFE, \"Cryptsoft Pty. Ltd.\"  },\r\n    { 0x1CFF, \"Tad Radio of Canada Inc.\"  },\r\n    { 0x1D00, \"MicroStone Corporation\"  },\r\n    { 0x1D01, \"SNIF Labs\"  },\r\n    { 0x1D02, \"DevGuru\"  },\r\n    { 0x1D03, \"ICON INTERNATIONAL DIGITAL LIMITED\"  },\r\n    { 0x1D04, \"Itronics\"  },\r\n    { 0x1D05, \"DESTURA S.R.L.\"  },\r\n    { 0x1D06, \"BBK ELECTRONICS CORPORATION LIMITED\"  },\r\n    { 0x1D07, \"Solid-Motion\"  },\r\n    { 0x1D08, \"NINGBO HENTEK DRAGON ELECTRONICS CO., LTD.\"  },\r\n    { 0x1D09, \"TechFaith Wireless Technology Limited\"  },\r\n    { 0x1D0A, \"Visteon Corporation\"  },\r\n    { 0x1D0B, \"HAN HUA CABLE & WIRE TECHNOLOGY (J.X.) CO., LTD.\"  },\r\n    { 0x1D0C, \"LAKS GmbH\"  },\r\n    { 0x1D0D, \"TDK Marketing Europe GmbH\"  },\r\n    { 0x1D0E, \"deister electronic GmbH\"  },\r\n    { 0x1D0F, \"NEO ELECTRONICS (HK) CO., LIMITED\"  },\r\n    { 0x1D10, \"Jiangsu Shinco Digital Technology Co., Ltd.\"  },\r\n    { 0x1D11, \"Xtend Technologies Pvt. Ltd.\"  },\r\n    { 0x1D12, \"UAB TELTONIKA\"  },\r\n    { 0x1D13, \"L3 Communications - Telemetry West\"  },\r\n    { 0x1D14, \"ALPHA-SAT TECHNOLOGY LIMITED\"  },\r\n    { 0x1D15, \"FUJIFILM RECORDING MEDIA GmbH\"  },\r\n    { 0x1D16, \"KABA MAS CORPORATION\"  },\r\n    { 0x1D17, \"C-THRU MUSIC Ltd.\"  },\r\n    { 0x1D18, \"APICAL INSTRUMENTS, INC.\"  },\r\n    { 0x1D19, \"Dexatek Technology Ltd.\"  },\r\n    { 0x1D1A, \"Boeckeler Instruments, Inc.\"  },\r\n    { 0x1D1B, \"HumanBeams Inc.\"  },\r\n    { 0x1D1C, \"Novatron Oy\"  },\r\n    { 0x1D1D, \"SYNESTHESIA CORPORATION\"  },\r\n    { 0x1D1E, \"OFFCODE\"  },\r\n    { 0x1D1F, \"Diostech Co., Ltd.\"  },\r\n    { 0x1D20, \"SAMTACK INC.\"  },\r\n    { 0x1D21, \"COMPUSULT LIMITED\"  },\r\n    { 0x1D22, \"ELCOM s.r.o.\"  },\r\n    { 0x1D23, \"Netsushin Co., Ltd.\"  },\r\n    { 0x1D24, \"PHOTON KINETICS\"  },\r\n    { 0x1D25, \"Trinity Security Systems, Inc.\"  },\r\n    { 0x1D26, \"ADVANCED ELECTRONICS LTD.\"  },\r\n    { 0x1D27, \"Prime Sense Ltd.\"  },\r\n    { 0x1D28, \"JORDAN VALLEY SEMICONDUCTORS LTD.\"  },\r\n    { 0x1D29, \"Horng Tong Enterprise Co., Ltd.\"  },\r\n    { 0x1D2A, \"LyconSys GmbH & Co. KG\"  },\r\n    { 0x1D2B, \"BEN-RI ELECTRONICA S.A.\"  },\r\n    { 0x1D2C, \"equinux AG\"  },\r\n    { 0x1D2D, \"Fraunhofer IBMT\"  },\r\n    { 0x1D2E, \"I.S.V. Co., Ltd.\"  },\r\n    { 0x1D2F, \"JACO, INC.\"  },\r\n    { 0x1D30, \"Sinosun Technology Ltd.\"  },\r\n    { 0x1D31, \"XINTRONIX LIMITED\"  },\r\n    { 0x1D32, \"ELECTRONICA MECHATRONIC SYSTEMS (I) PVT. LTD.\"  },\r\n    { 0x1D33, \"Lockheed Martin - Maritime Systems & Sensors\"  },\r\n    { 0x1D34, \"DREAM LINK LTD.\"  },\r\n    { 0x1D35, \"ISS Manufacturing Limited\"  },\r\n    { 0x1D36, \"Volucris, Inc.\"  },\r\n    { 0x1D37, \"Phoenix Microelectronics (China) Co., Ltd.\"  },\r\n    { 0x1D38, \"Ergowerx Int'l LLC/Smartfish Technologies\"  },\r\n    { 0x1D39, \"XECURENEXUS Co., LTD.\"  },\r\n    { 0x1D3A, \"P. R. Glassel & Associates, Inc.\"  },\r\n    { 0x1D3B, \"J & C Technology Co., Ltd.\"  },\r\n    { 0x1D3C, \"Tomei Tsushin Kogyo Co., Ltd.\"  },\r\n    { 0x1D3D, \"R&D Center of Biometric Technology-BMSTU\"  },\r\n    { 0x1D3E, \"EMCON Emanation Control Limited\"  },\r\n    { 0x1D3F, \"Photon Control Inc.\"  },\r\n    { 0x1D40, \"EDANIS Elektronik AG\"  },\r\n    { 0x1D41, \"Teletronic Rossendorf GmbH\"  },\r\n    { 0x1D42, \"DRAGON JOY LIMITED\"  },\r\n    { 0x1D43, \"Montage Technology, Inc.\"  },\r\n    { 0x1D44, \"Adirondack Digital Imaging Systems, Inc.\"  },\r\n    { 0x1D45, \"Qisda Corporation\"  },\r\n    { 0x1D46, \"nSys Design Systems\"  },\r\n    { 0x1D47, \"ATAUCE\"  },\r\n    { 0x1D48, \"Shenzhen XinYonghui Precise Technology Co., Ltd.\"  },\r\n    { 0x1D49, \"SHENZHEN LINKCONN ELECTRONICS CO., LTD.\"  },\r\n    { 0x1D4A, \"HKS Co., Ltd.\"  },\r\n    { 0x1D4B, \"DARIM VISION CO.\"  },\r\n    { 0x1D4C, \"ARK-DESIGN Co., Ltd.\"  },\r\n    { 0x1D4D, \"Pegatron Corporation\"  },\r\n    { 0x1D4E, \"INPHI CORPORATION\"  },\r\n    { 0x1D4F, \"ADVANCED CHIP EXPRESS INC.\"  },\r\n    { 0x1D50, \"OPENMOKO, Inc.\"  },\r\n    { 0x1D51, \"Sengital Limited\"  },\r\n    { 0x1D52, \"ELECTROBYTE di GARAVAGLIA MATTIA\"  },\r\n    { 0x1D53, \"Innofidei Inc.\"  },\r\n    { 0x1D54, \"ZARAM TECHNOLOGY, Inc.\"  },\r\n    { 0x1D55, \"XRONet Corporation\"  },\r\n    { 0x1D56, \"Verico International Co., Ltd.\"  },\r\n    { 0x1D57, \"Feeling Technology Corp.\"  },\r\n    { 0x1D58, \"SUZUKI Engineering\"  },\r\n    { 0x1D59, \"3DSP\"  },\r\n    { 0x1D5A, \"Hillcrest Laboratories, Inc.\"  },\r\n    { 0x1D5B, \"Smartronix, Inc.\"  },\r\n    { 0x1D5C, \"Fresco Logic Inc.\"  },\r\n    { 0x1D5D, \"QIXING INDUSTRIAL (HK) CO.\"  },\r\n    { 0x1D5E, \"Tonium AB\"  },\r\n    { 0x1D5F, \"ViVOtech, Inc.\"  },\r\n    { 0x1D60, \"ASAP International Co., Ltd.\"  },\r\n    { 0x1D61, \"ACCEMIC GmbH & CO. KG\"  },\r\n    { 0x1D62, \"KYORITSU ELECTRIC CO., LTD.\"  },\r\n    { 0x1D63, \"Nippon Seiki Co., Ltd.\"  },\r\n    { 0x1D64, \"MobilMAX Technology Inc.\"  },\r\n    { 0x1D65, \"Moteurs LEROY SOMER\"  },\r\n    { 0x1D66, \"StreamBuster\"  },\r\n    { 0x1D67, \"DYNAMIC INNOVATIONS LIMITED\"  },\r\n    { 0x1D68, \"SEMA ELECTRONICS (H.K.) CO., Ltd.\"  },\r\n    { 0x1D69, \"Walta Electronic Co., Ltd.\"  },\r\n    { 0x1D6A, \"ARICENT TECHNOLOGIES (HOLDINGS) LTD.\"  },\r\n    { 0x1D6B, \"The Linux Foundation\"  },\r\n    { 0x1D6C, \"Man & Machine, Inc.\"  },\r\n    { 0x1D6D, \"VARISYS LIMITED\"  },\r\n    { 0x1D6E, \"EUROTECH\"  },\r\n    { 0x1D6F, \"Seluxit\"  },\r\n    { 0x1D70, \"MULTIPLE ACCESS COMMUNICATIONS LTD.\"  },\r\n    { 0x1D71, \"Finisar Corporation\"  },\r\n    { 0x1D72, \"Mobiltex Data Ltd.\"  },\r\n    { 0x1D73, \"Signal Processing Devices Sweden AB\"  },\r\n    { 0x1D74, \"LG Innotek Co., Ltd.\"  },\r\n    { 0x1D75, \"DICOM, spol. s r.o.\"  },\r\n    { 0x1D76, \"LongCheng Electronic & Communication CO., LTD.\"  },\r\n    { 0x1D77, \"Yueqing Changling Electronic Instrument Corp., Ltd.\"  },\r\n    { 0x1D78, \"CAMBRIDGE SEMICONDUCTOR LTD.\"  },\r\n    { 0x1D79, \"Shenzhen Innosystem Technology Ltd.\"  },\r\n    { 0x1D7A, \"SHINWA INTERNATIONAL HOLDINGS LTD.\"  },\r\n    { 0x1D7B, \"Single Strand Co., Ltd.\"  },\r\n    { 0x1D7C, \"KarmelSonix\"  },\r\n    { 0x1D7D, \"Seoul Commtech Co., Ltd.\"  },\r\n    { 0x1D7E, \"WAVESAT\"  },\r\n    { 0x1D7F, \"MoBeam, Inc.\"  },\r\n    { 0x1D80, \"PLDA\"  },\r\n    { 0x1D81, \"YongXin Plastic & Hardware Co., Ltd.\"  },\r\n    { 0x1D82, \"HERTZ SYSTEMTECHNIK GmbH\"  },\r\n    { 0x1D83, \"Mantech International\"  },\r\n    { 0x1D84, \"Kechenda Plastic Electronic Factory\"  },\r\n    { 0x1D85, \"NINGBO SHUNSHENG COMMUNICATION APPARATUS CO., LTD.\"  },\r\n    { 0x1D86, \"C.D.N. CORPORATION\"  },\r\n    { 0x1D87, \"RHK TECHNOLOGY, INC.\"  },\r\n    { 0x1D88, \"Mahr GmbH\"  },\r\n    { 0x1D89, \"Hunter Associates\"  },\r\n    { 0x1D8A, \"OSASI Technos Inc. (Tokyo Headquarters)\"  },\r\n    { 0x1D8B, \"MEDTRONIC\"  },\r\n    { 0x1D8C, \"Wuxi AlphaScale IC Systems, Inc.\"  },\r\n    { 0x1D8D, \"EXEO SYSTEMS\"  },\r\n    { 0x1D8E, \"Capistrano Labs, Inc.\"  },\r\n    { 0x1D8F, \"Viprinet GmbH\"  },\r\n    { 0x1D90, \"CITIZEN SYSTEMS JAPAN CO., LTD.\"  },\r\n    { 0x1D91, \"BYD COMPANY LIMITED\"  },\r\n    { 0x1D92, \"SPECTRONIC DEVICES LTD.\"  },\r\n    { 0x1D93, \"Tokyo System Development Co., Ltd.\"  },\r\n    { 0x1D94, \"ENCIRIS TECHNOLOGIES\"  },\r\n    { 0x1D95, \"SYSTRONIK Elektronik und Systemtechnik GmbH\"  },\r\n    { 0x1D96, \"CHIRSON LTD.\"  },\r\n    { 0x1D97, \"Telonics\"  },\r\n    { 0x1D98, \"OUTLINE ELECTRONICS LTD.\"  },\r\n    { 0x1D99, \"Shanghai HSIC Application System Co., Ltd.\"  },\r\n    { 0x1D9A, \"Vubiq, Inc.\"  },\r\n    { 0x1D9B, \"Techno Source\"  },\r\n    { 0x1D9C, \"SONIM TECHNOLOGIES, INC.\"  },\r\n    { 0x1D9D, \"Sigma Elektro GmbH\"  },\r\n    { 0x1D9E, \"CSR, Inc.\"  },\r\n    { 0x1D9F, \"KUNMING ELECTRONICS CO., LTD.\"  },\r\n    { 0x1DA0, \"Parade Technologies, Inc.\"  },\r\n    { 0x1DA1, \"COVIDENCE A/S\"  },\r\n    { 0x1DA2, \"LAMBDA, INC.\"  },\r\n    { 0x1DA3, \"bebro electronic GmbH\"  },\r\n    { 0x1DA4, \"BTICINO\"  },\r\n    { 0x1DA5, \"CATHEXIS INNOVATIONS INC.\"  },\r\n    { 0x1DA6, \"Inepro BV\"  },\r\n    { 0x1DA7, \"ENDRA Inc.\"  },\r\n    { 0x1DA8, \"VIOLET\"  },\r\n    { 0x1DA9, \"In-Circuit GmbH\"  },\r\n    { 0x1DAA, \"Alcatel-Lucent\"  },\r\n    { 0x1DAB, \"MAGELLAN GPS\"  },\r\n    { 0x1DAC, \"MOBOTIX AG\"  },\r\n    { 0x1DAD, \"DATNET KFT\"  },\r\n    { 0x1DAE, \"ellipsis INC.\"  },\r\n    { 0x1DAF, \"Breas Medical AB\"  },\r\n    { 0x1DB0, \"GreenPeak Technologies NV\"  },\r\n    { 0x1DB1, \"Reliable Controls Corporation\"  },\r\n    { 0x1DB2, \"Duali Inc.\"  },\r\n    { 0x1DB3, \"Arcelik A.S.\"  },\r\n    { 0x1DB4, \"Montalvo Systems\"  },\r\n    { 0x1DB5, \"BRYSTON LTD.\"  },\r\n    { 0x1DB6, \"eDimensional, Inc.\"  },\r\n    { 0x1DB7, \"SMedia Technology Corporation\"  },\r\n    { 0x1DB8, \"HD MEDICAL INC.\"  },\r\n    { 0x1DB9, \"LITEN UP TECHNOLOGIES INC.\"  },\r\n    { 0x1DBA, \"BancTec, Inc.\"  },\r\n    { 0x1DBB, \"Condalo GmbH\"  },\r\n    { 0x1DBC, \"Shenzhen HOJY Technology Co., Ltd.\"  },\r\n    { 0x1DBD, \"Terawins\"  },\r\n    { 0x1DBE, \"S.R.N. Corporation\"  },\r\n    { 0x1DBF, \"Signostics Pty. Ltd.\"  },\r\n    { 0x1DC0, \"DATAFIELD INDIA PVT.LTD.\"  },\r\n    { 0x1DC1, \"Laser Drive\"  },\r\n    { 0x1DC2, \"Datalogic Mobile Inc.\"  },\r\n    { 0x1DC3, \"PoLabs\"  },\r\n    { 0x1DC4, \"TRANSICS\"  },\r\n    { 0x1DC5, \"Pixim Inc.\"  },\r\n    { 0x1DC6, \"Miyama, Inc.\"  },\r\n    { 0x1DC7, \"Leroy Automatique Industrielle\"  },\r\n    { 0x1DC8, \"GC Corporation\"  },\r\n    { 0x1DC9, \"Hitachi Koki Co., Ltd.\"  },\r\n    { 0x1DCA, \"The IVOXX Corp.\"  },\r\n    { 0x1DCB, \"IFTEST AG\"  },\r\n    { 0x1DCC, \"Document Capture Technologies, Inc.\"  },\r\n    { 0x1DCD, \"HIN KUI MACHINE & METAL INDUSTRIAL CO., LTD.\"  },\r\n    { 0x1DCE, \"SIMTEC Elektronik GmbH\"  },\r\n    { 0x1DCF, \"INVIX Co., Ltd.\"  },\r\n    { 0x1DD0, \"ABB AS, Division Automation Products\"  },\r\n    { 0x1DD1, \"EFJohnson\"  },\r\n    { 0x1DD2, \"LEO BODNAR\"  },\r\n    { 0x1DD3, \"Dajac, Inc.\"  },\r\n    { 0x1DD4, \"ARMELIN WIDGET CORPORATION\"  },\r\n    { 0x1DD5, \"MetaGeek, LLC\"  },\r\n    { 0x1DD6, \"Solomon Technology Corp.\"  },\r\n    { 0x1DD7, \"REDMERE TECHNOLOGY\"  },\r\n    { 0x1DD8, \"BUFFALO KOKUYO SUPPLY INC.\"  },\r\n    { 0x1DD9, \"EFFICERE TECHNOLOGIES\"  },\r\n    { 0x1DDA, \"TA Instruments\"  },\r\n    { 0x1DDB, \"Abon Touchsystems Inc.\"  },\r\n    { 0x1DDC, \"id Quantique\"  },\r\n    { 0x1DDD, \"DOKING ELECTRONIC TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1DDE, \"TridonicAtco\"  },\r\n    { 0x1DDF, \"L&T Technology Services\"  },\r\n    { 0x1DE0, \"Shenzhen Excelstor Technology Ltd.\"  },\r\n    { 0x1DE1, \"Actions Microelectronics Co., Ltd.\"  },\r\n    { 0x1DE2, \"ENTERY INDUSTRIAL CO., LTD.\"  },\r\n    { 0x1DE3, \"SHENZHEN REX ELECTRONICS CO., LTD.\"  },\r\n    { 0x1DE4, \"DAEWOO ELECTRONICS CORPORATION\"  },\r\n    { 0x1DE5, \"AMONTEC\"  },\r\n    { 0x1DE6, \"MICRORISC S.R.O.\"  },\r\n    { 0x1DE7, \"MIDAS TECHNOLOGY\"  },\r\n    { 0x1DE8, \"Applied Systems Engineering, Inc.\"  },\r\n    { 0x1DE9, \"Seco Technology Co., Ltd.\"  },\r\n    { 0x1DEA, \"Yesin Electronics Technology Co., Ltd.\"  },\r\n    { 0x1DEB, \"SHIUH CHI PRECISION INDUSTRY CO., LTD.\"  },\r\n    { 0x1DEC, \"HAGER CONTROLS SAS\"  },\r\n    { 0x1DED, \"COOLIT SYSTEMS, INC.\"  },\r\n    { 0x1DEE, \"JCM II, Inc.\"  },\r\n    { 0x1DEF, \"KYOTO KAGAKU CO., LTD.\"  },\r\n    { 0x1DF0, \"TRICKLESTAR LIMITED\"  },\r\n    { 0x1DF1, \"HUATIANYUAN ELECTRONIC INDUSTRY CO., LTD.\"  },\r\n    { 0x1DF2, \"China Telecommunication Technology Labs - Terminals\"  },\r\n    { 0x1DF3, \"CRESYN CO., LTD.\"  },\r\n    { 0x1DF4, \"SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD.\"  },\r\n    { 0x1DF5, \"Universal Remote Control, Inc.\"  },\r\n    { 0x1DF6, \"TakeMS International AG\"  },\r\n    { 0x1DF7, \"Mirics Semiconductor Ltd.\"  },\r\n    { 0x1DF8, \"The Charles Machine Works, Inc.\"  },\r\n    { 0x1DF9, \"Komax AG\"  },\r\n    { 0x1DFA, \"BLOCKMASTER AB\"  },\r\n    { 0x1DFB, \"marco Systemanalyse und Entwicklung GmbH\"  },\r\n    { 0x1DFC, \"YUNNAN NANTIAN ELECTRONICS INFORMATION CO., LTD.\"  },\r\n    { 0x1DFD, \"Quality Thermistor, Inc.\"  },\r\n    { 0x1DFE, \"BEDA Precision\"  },\r\n    { 0x1DFF, \"InfraRed Integrated Systems Ltd.\"  },\r\n    { 0x1E00, \"Jupiter Systems\"  },\r\n    { 0x1E01, \"Dynalloy, Inc.\"  },\r\n    { 0x1E02, \"GLOBEMASTER TECHNOLOGIES CO., LTD.\"  },\r\n    { 0x1E03, \"OXFORD INSTRUMENTS ANALYTICAL OY\"  },\r\n    { 0x1E04, \"Coolsand Technologies (Hong Kong) Ltd.\"  },\r\n    { 0x1E05, \"Microtronic AG\"  },\r\n    { 0x1E06, \"Moore Industries International\"  },\r\n    { 0x1E07, \"GETA ELECTRONICS (DONG GUAN) CO., LTD.\"  },\r\n    { 0x1E08, \"Inventure, Inc.\"  },\r\n    { 0x1E09, \"Baldwin Boxall Communication Ltd.\"  },\r\n    { 0x1E0A, \"NOX Medical\"  },\r\n    { 0x1E0B, \"TUBITAK UEKAE\"  },\r\n    { 0x1E0C, \"NATIONAL HYBRID, INC.\"  },\r\n    { 0x1E0D, \"NEOWAVE\"  },\r\n    { 0x1E0E, \"SHANGHAI BASECOM LTD.\"  },\r\n    { 0x1E0F, \"mSilica Inc.\"  },\r\n    { 0x1E10, \"FLIR Integrated Imaging Solutions\"  },\r\n    { 0x1E11, \"Hoya Xponent\"  },\r\n    { 0x1E12, \"OCTRIAN\"  },\r\n    { 0x1E13, \"Burgundy Electric, LLC\"  },\r\n    { 0x1E14, \"YANtide Corporation\"  },\r\n    { 0x1E15, \"mStation\"  },\r\n    { 0x1E16, \"SMARTIO\"  },\r\n    { 0x1E17, \"Mirion Technologies Inc.\"  },\r\n    { 0x1E18, \"MIGHT Co., Ltd.\"  },\r\n    { 0x1E19, \"Torus Networks Co., Ltd.\"  },\r\n    { 0x1E1A, \"HITEC RCD KOREA\"  },\r\n    { 0x1E1B, \"e-Practical Solutions\"  },\r\n    { 0x1E1C, \"CMS PRODUCTS\"  },\r\n    { 0x1E1D, \"Kanguru Solutions\"  },\r\n    { 0x1E1E, \"Trans New Technology, Inc.\"  },\r\n    { 0x1E1F, \"INVIA\"  },\r\n    { 0x1E20, \"JDSU\"  },\r\n    { 0x1E21, \"NEONUMERIC\"  },\r\n    { 0x1E22, \"LEDCO\"  },\r\n    { 0x1E23, \"Aeronix, Inc.\"  },\r\n    { 0x1E24, \"Cine-tal Systems, Inc.\"  },\r\n    { 0x1E25, \"3M Cogent, Inc.\"  },\r\n    { 0x1E26, \"Multi Channel Systems MCS GmbH\"  },\r\n    { 0x1E27, \"NASA / Johnson Space Center / EV2\"  },\r\n    { 0x1E28, \"Raptor Innovations International\"  },\r\n    { 0x1E29, \"Festo AG & Co. KG\"  },\r\n    { 0x1E2A, \"NANOFORTI INC.\"  },\r\n    { 0x1E2B, \"3M CMD (Communication Markets Division)\"  },\r\n    { 0x1E2C, \"KRONIK ELEKTRONIK SANAYI VETICARET LIMITED SIRKETI\"  },\r\n    { 0x1E2D, \"Cinterion Wireless Modules GmbH\"  },\r\n    { 0x1E2E, \"Syrinx Industrial Electronics b.v.\"  },\r\n    { 0x1E2F, \"Celrun Co., Ltd.\"  },\r\n    { 0x1E30, \"Kohler Co.\"  },\r\n    { 0x1E31, \"Greatbatch\"  },\r\n    { 0x1E32, \"Opti-Sciences, Inc.\"  },\r\n    { 0x1E33, \"KOBIAN CANADA INC.\"  },\r\n    { 0x1E34, \"Sensory, Inc.\"  },\r\n    { 0x1E35, \"BELLING Co., Ltd.\"  },\r\n    { 0x1E36, \"Insulet Corporation\"  },\r\n    { 0x1E37, \"Rehoboth Tech. Co., Ltd.\"  },\r\n    { 0x1E38, \"QRS Music Technologies Inc.\"  },\r\n    { 0x1E39, \"YIS Corporation\"  },\r\n    { 0x1E3A, \"Continental Automotive Systems Inc.\"  },\r\n    { 0x1E3B, \"MICROBIT 2.0 AB\"  },\r\n    { 0x1E3C, \"Vapor Bus Int'l Div of Westinghouse Air Brake Tech Corp\"  },\r\n    { 0x1E3D, \"Chipsbrand Technologies (HK) Co., Limited\"  },\r\n    { 0x1E3E, \"EMS Aviation\"  },\r\n    { 0x1E3F, \"JJ Keller & Associates Inc.\"  },\r\n    { 0x1E40, \"SciLog, Inc.\"  },\r\n    { 0x1E41, \"Cleverscope Ltd.\"  },\r\n    { 0x1E42, \"SSE GmbH\"  },\r\n    { 0x1E43, \"Sagem Mobiles\"  },\r\n    { 0x1E44, \"SHIMANO INC.\"  },\r\n    { 0x1E45, \"TADANO LTD.\"  },\r\n    { 0x1E46, \"Danfoss A/S\"  },\r\n    { 0x1E47, \"HUNG TA H.T.ENTERPRISE CO., LTD.\"  },\r\n    { 0x1E48, \"LABAU Technology\"  },\r\n    { 0x1E49, \"FES LLC\"  },\r\n    { 0x1E4A, \"CHIRON TECHNOLOGY LTD.\"  },\r\n    { 0x1E4B, \"exxact GmbH\"  },\r\n    { 0x1E4C, \"Stereotaxis, Inc.\"  },\r\n    { 0x1E4D, \"BST International GmbH\"  },\r\n    { 0x1E4E, \"Etron Technology, Inc.\"  },\r\n    { 0x1E4F, \"SECOM Co., Ltd.\"  },\r\n    { 0x1E50, \"VILTECHMEDA UAB\"  },\r\n    { 0x1E51, \"DiMoto\"  },\r\n    { 0x1E52, \"SZ TELSTAR CO., LTD.\"  },\r\n    { 0x1E53, \"WYPLAY\"  },\r\n    { 0x1E54, \"TypeMatrix Inc.\"  },\r\n    { 0x1E55, \"Memorysolution GmbH\"  },\r\n    { 0x1E56, \"EURINTEL\"  },\r\n    { 0x1E57, \"Bundesdruckerei GmbH\"  },\r\n    { 0x1E58, \"Horner APG\"  },\r\n    { 0x1E59, \"inTera Tecnologia\"  },\r\n    { 0x1E5A, \"VOXTRONIC TECHNOLOGY\"  },\r\n    { 0x1E5B, \"APRICO A/S\"  },\r\n    { 0x1E5C, \"Enova Technology Corp.\"  },\r\n    { 0x1E5D, \"SAT Corporation\"  },\r\n    { 0x1E5E, \"Touch International\"  },\r\n    { 0x1E5F, \"Relpol SA\"  },\r\n    { 0x1E60, \"SEA Signalisation\"  },\r\n    { 0x1E61, \"Anoto AB\"  },\r\n    { 0x1E62, \"Uriver Inc.\"  },\r\n    { 0x1E63, \"DRAEGER MEDICAL\"  },\r\n    { 0x1E64, \"IMSTORAGE CO., LTD.\"  },\r\n    { 0x1E65, \"THE BOEING CO.\"  },\r\n    { 0x1E66, \"KAPSYS\"  },\r\n    { 0x1E67, \"Orban/CRL Systems, Inc.\"  },\r\n    { 0x1E68, \"TrekStor GmbH & Co. KG\"  },\r\n    { 0x1E69, \"Hormann Funkwerk Kolleda GmbH\"  },\r\n    { 0x1E6A, \"RGB Spectrum\"  },\r\n    { 0x1E6B, \"iRex Technologies B.V.\"  },\r\n    { 0x1E6C, \"Sureshotgps Pty. Ltd.\"  },\r\n    { 0x1E6D, \"WAN SHIH ELECTRONIC (H.K.) CO., LTD.\"  },\r\n    { 0x1E6E, \"F&D Feinwerk-Und Drucktechnik GmbH\"  },\r\n    { 0x1E6F, \"Images Scientific Instruments Inc.\"  },\r\n    { 0x1E70, \"POSBRO Inc.\"  },\r\n    { 0x1E71, \"NZXT Corporation\"  },\r\n    { 0x1E72, \"Federal Signal Corporation\"  },\r\n    { 0x1E73, \"COMLINK ELECTRONICS CO., LTD.\"  },\r\n    { 0x1E74, \"COBY COMMUNICATIONS, LIMITED\"  },\r\n    { 0x1E75, \"TLS Communication GmbH\"  },\r\n    { 0x1E76, \"Proview Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1E77, \"Core Micro Technology Inc.\"  },\r\n    { 0x1E78, \"Flextronics R & D (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1E79, \"ISA Co., Ltd.\"  },\r\n    { 0x1E7A, \"The Tsurumi-Seiki Company, Limited\"  },\r\n    { 0x1E7B, \"Zurich Instruments AG\"  },\r\n    { 0x1E7C, \"biostep GmbH\"  },\r\n    { 0x1E7D, \"ROCCAT GmbH\"  },\r\n    { 0x1E7E, \"Bright Star Engineering Inc.\"  },\r\n    { 0x1E7F, \"NEXS ELECTRONIC CORP.\"  },\r\n    { 0x1E80, \"InterDigital Communications LLC\"  },\r\n    { 0x1E81, \"KIDS PREFERRED, LLC.\"  },\r\n    { 0x1E82, \"Nortech Systems\"  },\r\n    { 0x1E83, \"AMICUS WIRELESS\"  },\r\n    { 0x1E84, \"VIVAX CORPORATION\"  },\r\n    { 0x1E85, \"Gigaset Communications GmbH\"  },\r\n    { 0x1E86, \"Japan Meditech Co., Ltd.\"  },\r\n    { 0x1E87, \"W&W Communications Inc.\"  },\r\n    { 0x1E88, \"GBS Laboratories, LLC\"  },\r\n    { 0x1E89, \"Vtion Information Technology (Fujian) Co., Ltd.\"  },\r\n    { 0x1E8A, \"HIBEST Electronic (DongGuan) Co., Ltd.\"  },\r\n    { 0x1E8B, \"ImTech, Inc.\"  },\r\n    { 0x1E8C, \"Data Conversion Systems Ltd.\"  },\r\n    { 0x1E8D, \"HIGHVOLT Prueftechnik Dresden GmbH\"  },\r\n    { 0x1E8E, \"EADS Secure Networks\"  },\r\n    { 0x1E8F, \"PublicSolution GmbH\"  },\r\n    { 0x1E90, \"Mego Afek\"  },\r\n    { 0x1E91, \"Other World Computing\"  },\r\n    { 0x1E92, \"Beyond Question Learning Technologies, Inc.\"  },\r\n    { 0x1E93, \"GSI Group\"  },\r\n    { 0x1E94, \"RealD\"  },\r\n    { 0x1E95, \"DIRECTV, Inc.\"  },\r\n    { 0x1E96, \"BlueAnt Wireless\"  },\r\n    { 0x1E97, \"TOMMYCA HONG KONG LIMITED\"  },\r\n    { 0x1E98, \"COMPASS SYSTEMS CORP.\"  },\r\n    { 0x1E99, \"General Dynamics C4 Systems\"  },\r\n    { 0x1E9A, \"MANTHAN SEMICONDUCTOR PVT. LTD.\"  },\r\n    { 0x1E9B, \"Netcom Sicherheitstechnik GmbH\"  },\r\n    { 0x1E9C, \"FirstPaper, LLC\"  },\r\n    { 0x1E9D, \"GEOTEST AG\"  },\r\n    { 0x1E9E, \"InnoSys Inc.\"  },\r\n    { 0x1E9F, \"Chase Peabody and Associates, Inc.\"  },\r\n    { 0x1EA0, \"DiabloSport, Inc.\"  },\r\n    { 0x1EA1, \"NANOBASE\"  },\r\n    { 0x1EA2, \"N.V. Nederlandsche Apparatenfabriek Nedap\"  },\r\n    { 0x1EA3, \"Concraft Holding Co., Ltd.\"  },\r\n    { 0x1EA4, \"MOBILE SYSTEM TECHNOLOGIES INC.\"  },\r\n    { 0x1EA5, \"CEN LINK CO., LTD.\"  },\r\n    { 0x1EA6, \"novero GmbH\"  },\r\n    { 0x1EA7, \"SEMITEK INTERNATIONAL (HK) HOLDING LTD.\"  },\r\n    { 0x1EA8, \"Shenzhen Excelsecu Data Technology Co., Ltd.\"  },\r\n    { 0x1EA9, \"ANDERS ELECTRONICS PLC\"  },\r\n    { 0x1EAA, \"Zeebo, Inc.\"  },\r\n    { 0x1EAB, \"Fujian Newland Auto-ID Tech. Co., Ltd.\"  },\r\n    { 0x1EAC, \"Thinkware Systems\"  },\r\n    { 0x1EAD, \"Industrial Control Communications, Inc.\"  },\r\n    { 0x1EAE, \"YESCNC CO., LTD.\"  },\r\n    { 0x1EAF, \"Continental Trading GmbH\"  },\r\n    { 0x1EB0, \"Centers for Disease Control & Prevention (CDC)\"  },\r\n    { 0x1EB1, \"Kramer Electronics Ltd.\"  },\r\n    { 0x1EB2, \"IWAKI CO., LTD.\"  },\r\n    { 0x1EB3, \"SAE MAGNETICS (HK) LTD.\"  },\r\n    { 0x1EB4, \"YuhDing Precision Industry (KunShan) Co., Ltd.\"  },\r\n    { 0x1EB5, \"Diablo Technologies Inc.\"  },\r\n    { 0x1EB6, \"PHYLINKS LIMITED\"  },\r\n    { 0x1EB7, \"WIN WIN PRECISION INDUSTRIAL CO., LTD.\"  },\r\n    { 0x1EB8, \"MODACOM CO., LTD.\"  },\r\n    { 0x1EB9, \"Campbell Scientific Inc.\"  },\r\n    { 0x1EBA, \"HITTITE MICROWAVE CORP.\"  },\r\n    { 0x1EBB, \"NuCORE Technology, Inc.\"  },\r\n    { 0x1EBC, \"Beijing Novel-Super Media Investment Co., Ltd.\"  },\r\n    { 0x1EBD, \"Wireless Matrix Corp.\"  },\r\n    { 0x1EBE, \"Qwizdom, Inc.\"  },\r\n    { 0x1EBF, \"Yulong Computer Telecommunication Scientific\"  },\r\n    { 0x1EC0, \"VIGORHOOD PHOTOELECTRIC SHENZHEN CO., LTD.\"  },\r\n    { 0x1EC1, \"PROTEK DEVICES\"  },\r\n    { 0x1EC2, \"CHUO ELECTRONICS CO., LTD.\"  },\r\n    { 0x1EC3, \"ANDREAS STIHL AG & Co. KG\"  },\r\n    { 0x1EC4, \"ELTRONIC SOLUTION A/S\"  },\r\n    { 0x1EC5, \"SIDSA\"  },\r\n    { 0x1EC6, \"PHYWORKS LTD.\"  },\r\n    { 0x1EC7, \"Gefen Inc.\"  },\r\n    { 0x1EC8, \"TelePath Technologies Co., Ltd.\"  },\r\n    { 0x1EC9, \"MOSER BAER INDIA LIMITED\"  },\r\n    { 0x1ECA, \"Mintpass Co., Ltd.\"  },\r\n    { 0x1ECB, \"Advanced Mobile Telecom Co., Ltd.\"  },\r\n    { 0x1ECC, \"Enfora, Inc.\"  },\r\n    { 0x1ECD, \"Alverix Inc.\"  },\r\n    { 0x1ECE, \"MyungMin Systems, Inc.\"  },\r\n    { 0x1ECF, \"MDR Grup S.R.L.\"  },\r\n    { 0x1ED0, \"Hirschmann Car Communication GmbH\"  },\r\n    { 0x1ED1, \"DIGITAL CHINA NETWORKS (BEIJING) LIMITED\"  },\r\n    { 0x1ED2, \"Crevis Co., Ltd.\"  },\r\n    { 0x1ED3, \"Forsis GmbH\"  },\r\n    { 0x1ED4, \"Transwitch (Israel) Ltd.\"  },\r\n    { 0x1ED5, \"LLC GlobalTest\"  },\r\n    { 0x1ED6, \"adidas International\"  },\r\n    { 0x1ED7, \"Headplay, Inc.\"  },\r\n    { 0x1ED8, \"Fender Musical Instruments Corp.\"  },\r\n    { 0x1ED9, \"ALBUMteam, Ltd.\"  },\r\n    { 0x1EDA, \"AIRTIES WIRELESS NETWORKS\"  },\r\n    { 0x1EDB, \"BLACKMAGIC DESIGN PTY.\"  },\r\n    { 0x1EDC, \"B-DeltaCom\"  },\r\n    { 0x1EDD, \"IRIDIUM SATELLITE LLC\"  },\r\n    { 0x1EDE, \"steute Schaltgerate GmbH & Co. KG\"  },\r\n    { 0x1EDF, \"Selectwireless Co., Ltd.\"  },\r\n    { 0x1EE0, \"KYUDEN TECHNOSYSTEMS CORPORATION\"  },\r\n    { 0x1EE1, \"Matrix Key Inc.\"  },\r\n    { 0x1EE2, \"NOVA GAMING\"  },\r\n    { 0x1EE3, \"3D INNOVATIONS, LLC\"  },\r\n    { 0x1EE4, \"Luff Technology Co., Ltd.\"  },\r\n    { 0x1EE5, \"Spring Soft K.K.\"  },\r\n    { 0x1EE6, \"SHENZHEN EVERWIN PRECISION TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1EE7, \"EPCOS\"  },\r\n    { 0x1EE8, \"ONDA COMMUNICATION S.p.a.\"  },\r\n    { 0x1EE9, \"PC PARTNER LIMITED\"  },\r\n    { 0x1EEA, \"Yullin Technologies Co., Ltd.\"  },\r\n    { 0x1EEB, \"GEOTATE\"  },\r\n    { 0x1EEC, \"CTC Analytics AG\"  },\r\n    { 0x1EED, \"Helo Oy / Helo Ltd.\"  },\r\n    { 0x1EEE, \"RigiSystems AG\"  },\r\n    { 0x1EEF, \"I.C.Y. B.V.\"  },\r\n    { 0x1EF0, \"Thunder Tiger Corp.\"  },\r\n    { 0x1EF1, \"PQ Computing Ltd.\"  },\r\n    { 0x1EF2, \"Vircion Inc.\"  },\r\n    { 0x1EF3, \"JIANGXI SHIP ELECTRONICS CO., LTD.\"  },\r\n    { 0x1EF4, \"TATA ELXSI LTD.\"  },\r\n    { 0x1EF5, \"Impinj, Inc.\"  },\r\n    { 0x1EF6, \"EADS Deutschland GmbH\"  },\r\n    { 0x1EF7, \"ZiiLABS Ltd.\"  },\r\n    { 0x1EF8, \"CRITICAL LINK, LLC\"  },\r\n    { 0x1EF9, \"US Army Electronic Proving Ground\"  },\r\n    { 0x1EFA, \"SEIKO Precision Inc.\"  },\r\n    { 0x1EFB, \"IMI Hydronic Engineering International SA\"  },\r\n    { 0x1EFC, \"IMOGEN STUDIO\"  },\r\n    { 0x1EFD, \"ROFIN-SINAR LASER GMBH\"  },\r\n    { 0x1EFE, \"Sound Design Technologies\"  },\r\n    { 0x1EFF, \"Kinemetrics, Inc.\"  },\r\n    { 0x1F00, \"YUEQING ZHONGLI COMPUTER ELECTRONICS CO., LTD.\"  },\r\n    { 0x1F01, \"Geo Studio Technology\"  },\r\n    { 0x1F02, \"Australian National University\"  },\r\n    { 0x1F03, \"PTW Freiburg GmbH\"  },\r\n    { 0x1F04, \"Watlow\"  },\r\n    { 0x1F05, \"Kyosai Technos Co., Ltd.\"  },\r\n    { 0x1F06, \"K.T.E.-Keter Technologies Europe\"  },\r\n    { 0x1F07, \"OPTOQUEST Co., Ltd.\"  },\r\n    { 0x1F08, \"Digital Ally Inc.\"  },\r\n    { 0x1F09, \"DURAG GmbH\"  },\r\n    { 0x1F0A, \"AUROX Ltd.\"  },\r\n    { 0x1F0B, \"INTRONIX TEST INSTURMENTS, INC.\"  },\r\n    { 0x1F0C, \"Fourier Systems Ltd.\"  },\r\n    { 0x1F0D, \"NAMOS\"  },\r\n    { 0x1F0E, \"Inflexis Corporation\"  },\r\n    { 0x1F0F, \"Action Technology (SZ) Co., Ltd.\"  },\r\n    { 0x1F10, \"LTW TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1F11, \"VIRAGE LOGIC\"  },\r\n    { 0x1F12, \"Photometrics\"  },\r\n    { 0x1F13, \"CENTURY SYSTEMS Co., Ltd.\"  },\r\n    { 0x1F14, \"Astoria Networks GmbH\"  },\r\n    { 0x1F15, \"Schmitt Industries Inc.\"  },\r\n    { 0x1F16, \"Olidata SpA\"  },\r\n    { 0x1F17, \"APIS Device, Inc.\"  },\r\n    { 0x1F18, \"Teseq GmbH\"  },\r\n    { 0x1F19, \"POLATIS INC.\"  },\r\n    { 0x1F1A, \"Sanden Retail Systems Corporation\"  },\r\n    { 0x1F1B, \"NORTHROP GRUMMAN SPERRY MARINE\"  },\r\n    { 0x1F1C, \"LXE, INC.\"  },\r\n    { 0x1F1D, \"How Weih Precision Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x1F1E, \"TSIEN (UK) LTD.\"  },\r\n    { 0x1F1F, \"RaaX Co., Ltd.\"  },\r\n    { 0x1F20, \"Shenzhen Tenwei Electronics Co., Ltd.\"  },\r\n    { 0x1F21, \"Scosche Industries\"  },\r\n    { 0x1F22, \"STAr Technologies, Inc.\"  },\r\n    { 0x1F23, \"KOUEI SYSTEM, LTD.\"  },\r\n    { 0x1F24, \"EBTRON INC.\"  },\r\n    { 0x1F25, \"Victron Energy B.V.\"  },\r\n    { 0x1F26, \"INCAP GmbH\"  },\r\n    { 0x1F27, \"KEE Action Sports (Hater Paintball)\"  },\r\n    { 0x1F28, \"Cal-Comp Electronics & Communications\"  },\r\n    { 0x1F29, \"Analogix Semiconductor, Inc.\"  },\r\n    { 0x1F2A, \"Scene Double Ltd.\"  },\r\n    { 0x1F2B, \"JUKI CORPORATION\"  },\r\n    { 0x1F2C, \"SELESTA INGEGNERIA SPA\"  },\r\n    { 0x1F2D, \"Liteye Systems, Inc.\"  },\r\n    { 0x1F2E, \"ARMOUR GROUP PLC.\"  },\r\n    { 0x1F2F, \"UPOS SYSTEM SP. Z O.O.\"  },\r\n    { 0x1F30, \"RENA GmbH\"  },\r\n    { 0x1F31, \"SASKEN COMMUNICATION TECH LTD.\"  },\r\n    { 0x1F32, \"COCHLEAR TECHNOLOGY CENTRE BELGIUM\"  },\r\n    { 0x1F33, \"GrupoPIE Portugal, S.A.\"  },\r\n    { 0x1F34, \"Dutronics\"  },\r\n    { 0x1F35, \"Amphenol ShouhMin Industry (ShenZhen) Co., Ltd\"  },\r\n    { 0x1F36, \"ddm hopt + schuler GmbH & Co. KG\"  },\r\n    { 0x1F37, \"Next Step Solutions Limited\"  },\r\n    { 0x1F38, \"Kesumo, LLC\"  },\r\n    { 0x1F39, \"Sumitomo Electric Networks, Inc.\"  },\r\n    { 0x1F3A, \"Allwinner Technology Co., Ltd.\"  },\r\n    { 0x1F3B, \"Biocryptodisk Sdn Bhd\"  },\r\n    { 0x1F3C, \"Chang Yang Electronics Company Ltd.\"  },\r\n    { 0x1F3D, \"Advanced Engineering Services Co., Ltd.\"  },\r\n    { 0x1F3E, \"Telenot Electronic GmbH\"  },\r\n    { 0x1F3F, \"SECA GmbH & Co. KG\"  },\r\n    { 0x1F40, \"JiangSu Dongda Integrated Circuits Sys. Eng. Tech. Co.\"  },\r\n    { 0x1F41, \"Nipro Diagnostics, Inc\"  },\r\n    { 0x1F42, \"ID2P TECHNOLOGIES, INC.\"  },\r\n    { 0x1F43, \"RAPID BRIDGE LLC\"  },\r\n    { 0x1F44, \"Digital Business Process (dba: The Neat Company)\"  },\r\n    { 0x1F45, \"QUALCOMM ENTERPRISE SERVICES\"  },\r\n    { 0x1F46, \"Gener8, Inc.\"  },\r\n    { 0x1F47, \"Orb Networks, Inc.\"  },\r\n    { 0x1F48, \"H-TRONIC GmbH\"  },\r\n    { 0x1F49, \"Exelis, Inc.\"  },\r\n    { 0x1F4A, \"Key Ingredient Corporation\"  },\r\n    { 0x1F4B, \"Precision System Science Co., Ltd.\"  },\r\n    { 0x1F4C, \"Cyber Sport Pty., Ltd.\"  },\r\n    { 0x1F4D, \"SHENZHEN GENIATECH INC., LTD.\"  },\r\n    { 0x1F4E, \"OFF-NET SERVICE LIMITED\"  },\r\n    { 0x1F4F, \"EXAR CORPORATION - JAPAN\"  },\r\n    { 0x1F50, \"KEMPPI OY\"  },\r\n    { 0x1F51, \"Helmut Hund GmbH\"  },\r\n    { 0x1F52, \"Systems & Electronic Development FZCO (SEDCO)\"  },\r\n    { 0x1F53, \"SK telesys\"  },\r\n    { 0x1F54, \"LOEC, INC.\"  },\r\n    { 0x1F55, \"Fujitsu Electronics Europe GmbH\"  },\r\n    { 0x1F56, \"MUT\"  },\r\n    { 0x1F57, \"PIGNOLO S.P.A.\"  },\r\n    { 0x1F58, \"Inmarsat\"  },\r\n    { 0x1F59, \"EL.MO. S.P.A.\"  },\r\n    { 0x1F5A, \"Micronova srl.\"  },\r\n    { 0x1F5B, \"KYODO COMMUNICATIONS & ELECTRONICS INC.\"  },\r\n    { 0x1F5C, \"MIDORI ANZEN CO., LTD.\"  },\r\n    { 0x1F5D, \"Mobii Systems (Pty) Ltd.\"  },\r\n    { 0x1F5E, \"Johnson Outdoors Marine Electronics, Inc.\"  },\r\n    { 0x1F5F, \"NETCLEUS SYSTEMS Corporation\"  },\r\n    { 0x1F60, \"Young at Heart International Ltd.\"  },\r\n    { 0x1F61, \"Flexocard GmbH\"  },\r\n    { 0x1F62, \"Elquest Corporation\"  },\r\n    { 0x1F63, \"IriTech, Inc.\"  },\r\n    { 0x1F64, \"actionXL, Inc.\"  },\r\n    { 0x1F65, \"Taylor Technologies, Co., Ltd.\"  },\r\n    { 0x1F66, \"Hokkaido Electronics Corporation\"  },\r\n    { 0x1F67, \"MICRO INNOVATIONS CORP.\"  },\r\n    { 0x1F68, \"General Dynamics UK Limited\"  },\r\n    { 0x1F69, \"NVIS, Inc.\"  },\r\n    { 0x1F6A, \"AJA VIDEO SYSTEMS INC.\"  },\r\n    { 0x1F6B, \"Muve, Inc.\"  },\r\n    { 0x1F6C, \"Cadex Electronics Inc.\"  },\r\n    { 0x1F6D, \"AMTI\"  },\r\n    { 0x1F6E, \"AccuVein LLC\"  },\r\n    { 0x1F6F, \"ALIPHCOM, INC.\"  },\r\n    { 0x1F70, \"MKD Technology Inc.\"  },\r\n    { 0x1F71, \"Huaya Microelectronics (HK) Ltd.\"  },\r\n    { 0x1F72, \"GM INSTRUMENTS LTD.\"  },\r\n    { 0x1F73, \"Record4Free.TV AG\"  },\r\n    { 0x1F74, \"UNISTO Ltd.\"  },\r\n    { 0x1F75, \"Innostor Co., Ltd.\"  },\r\n    { 0x1F76, \"CYBER-RAIN, INC.\"  },\r\n    { 0x1F77, \"POSITRON PUBLIC SAFETY SYSTEMS\"  },\r\n    { 0x1F78, \"UNION TOOL CO.\"  },\r\n    { 0x1F79, \"Rosen Technology and Research Center GmbH\"  },\r\n    { 0x1F7A, \"WhiteOak Controls Inc.\"  },\r\n    { 0x1F7B, \"AVMAP SRL\"  },\r\n    { 0x1F7C, \"Voltopia e.U.\"  },\r\n    { 0x1F7D, \"UNICARD S.A.\"  },\r\n    { 0x1F7E, \"Canon India Private Limited\"  },\r\n    { 0x1F7F, \"NOVA Sensors\"  },\r\n    { 0x1F80, \"MagicPixel Inc.\"  },\r\n    { 0x1F81, \"HYB D.O.O.\"  },\r\n    { 0x1F82, \"TANDBERG TELECOM AS\"  },\r\n    { 0x1F83, \"Beauty Up Co., Ltd.\"  },\r\n    { 0x1F84, \"Inverness Medical Innovations, Inc.\"  },\r\n    { 0x1F85, \"Netronix Inc.\"  },\r\n    { 0x1F86, \"Skyworth Overseas Development Limited\"  },\r\n    { 0x1F87, \"STANTUM\"  },\r\n    { 0x1F88, \"Modu Ltd.\"  },\r\n    { 0x1F89, \"Dongguan Goldconn Electronics Co., Ltd.\"  },\r\n    { 0x1F8A, \"Morning Star Industrial Co., Ltd.\"  },\r\n    { 0x1F8B, \"Rittal GmbH & Co. KG\"  },\r\n    { 0x1F8C, \"Reference, LLC.\"  },\r\n    { 0x1F8D, \"DEVICE FUNCTIONS\"  },\r\n    { 0x1F8E, \"SENSE INSIDE GmbH\"  },\r\n    { 0x1F8F, \"Narda Safety Test Solutions GmbH\"  },\r\n    { 0x1F90, \"PURE TECHNOLOGIES\"  },\r\n    { 0x1F91, \"Wilhelm Mikroelektronik GmbH\"  },\r\n    { 0x1F92, \"INTERNATIONAL TECHNIDYNE CORP.\"  },\r\n    { 0x1F93, \"Alcohol Monitoring Systems, Inc.\"  },\r\n    { 0x1F94, \"Microhard Systems Inc.\"  },\r\n    { 0x1F95, \"Art of Technology AG\"  },\r\n    { 0x1F96, \"Ascend Geo, LLC\"  },\r\n    { 0x1F97, \"OZMO, INC. DBA OZMO DEVICES\"  },\r\n    { 0x1F98, \"DSP Design Limited\"  },\r\n    { 0x1F99, \"TOKAI RIKEN CO., LTD.\"  },\r\n    { 0x1F9A, \"Barron Associates, Inc.\"  },\r\n    { 0x1F9B, \"UBIQUITI Networks, Inc.\"  },\r\n    { 0x1F9C, \"ARVOO Engineering BV\"  },\r\n    { 0x1F9D, \"Tri Works\"  },\r\n    { 0x1F9E, \"MUTECH LIMITED\"  },\r\n    { 0x1F9F, \"CasaTools, LLC\"  },\r\n    { 0x1FA0, \"XLNT IDEA, INC.\"  },\r\n    { 0x1FA1, \"Curtis Instruments, Inc.\"  },\r\n    { 0x1FA2, \"AMETEK DENMARK A/S\"  },\r\n    { 0x1FA3, \"LAIRD TECHNOLOGIES\"  },\r\n    { 0x1FA4, \"BRIDGEPORT INSTRUMENTS, LLC\"  },\r\n    { 0x1FA5, \"DELTA DORE\"  },\r\n    { 0x1FA6, \"Daylight Solutions, Inc.\"  },\r\n    { 0x1FA7, \"COSMOS WEB CO., LTD.\"  },\r\n    { 0x1FA8, \"TCL Technoly Electronics (Hui Zhou) Co., Ltd.\"  },\r\n    { 0x1FA9, \"Digital Information Technologies Corporation\"  },\r\n    { 0x1FAA, \"Zhong Shan City Li Tai Electronic Industrial Co., Ltd.\"  },\r\n    { 0x1FAB, \"SAMSUNG DIGITAL IMAGING CO., LTD.\"  },\r\n    { 0x1FAC, \"Franklin Technology Inc.\"  },\r\n    { 0x1FAD, \"Cresta Technology Inc.\"  },\r\n    { 0x1FAE, \"Lumidigm, Inc.\"  },\r\n    { 0x1FAF, \"Weintek Labs, Inc.\"  },\r\n    { 0x1FB0, \"Discera, Inc.\"  },\r\n    { 0x1FB1, \"Weatronic GmbH\"  },\r\n    { 0x1FB2, \"WITHINGS\"  },\r\n    { 0x1FB3, \"Matchbeeper AB\"  },\r\n    { 0x1FB4, \"Owl Computing Technologies, Inc.\"  },\r\n    { 0x1FB5, \"Unify Software and Solutions GmbH & Co. KG\"  },\r\n    { 0x1FB6, \"SheKel\"  },\r\n    { 0x1FB7, \"J & D Tech Co., Ltd.\"  },\r\n    { 0x1FB8, \"DORMA TIME + ACCESS GmbH\"  },\r\n    { 0x1FB9, \"Lake Shore Cryotronics, Inc.\"  },\r\n    { 0x1FBA, \"DERMALOG Identification Systems GmbH\"  },\r\n    { 0x1FBB, \"PC Worth Int'l Co., Ltd.\"  },\r\n    { 0x1FBC, \"Kurzweil Education Systems, Inc.\"  },\r\n    { 0x1FBD, \"STACK LTD.\"  },\r\n    { 0x1FBE, \"CGS\"  },\r\n    { 0x1FBF, \"OVAL Corporation\"  },\r\n    { 0x1FC0, \"JUNE-ON Co., Ltd.\"  },\r\n    { 0x1FC1, \"Blue Chip Technology Limited\"  },\r\n    { 0x1FC2, \"Poken SA\"  },\r\n    { 0x1FC3, \"ICOP Digital, Inc.\"  },\r\n    { 0x1FC4, \"Alfons Haar Maschinenbau GmbH & Co. KG\"  },\r\n    { 0x1FC5, \"Adaxys Solutions AG\"  },\r\n    { 0x1FC6, \"LAUREL BANK MACHINES CO., LTD.\"  },\r\n    { 0x1FC7, \"mrs GmbH\"  },\r\n    { 0x1FC8, \"Medis Technologies Ltd.\"  },\r\n    { 0x1FC9, \"NXP Semiconductors\"  },\r\n    { 0x1FCA, \"ON TIM Technologies Ltd.\"  },\r\n    { 0x1FCB, \"Thermo Process Instruments\"  },\r\n    { 0x1FCC, \"Hiro\"  },\r\n    { 0x1FCD, \"Aurora Scientific Inc.\"  },\r\n    { 0x1FCE, \"WEBSCAN Inc.\"  },\r\n    { 0x1FCF, \"ACK Co., Ltd.\"  },\r\n    { 0x1FD0, \"GILSON S.A.S.\"  },\r\n    { 0x1FD1, \"TEKWorx Limited\"  },\r\n    { 0x1FD2, \"LG Display Co., Ltd.\"  },\r\n    { 0x1FD3, \"ASK SA\"  },\r\n    { 0x1FD4, \"FINSECUR\"  },\r\n    { 0x1FD5, \"Dream Multimedia GmbH\"  },\r\n    { 0x1FD6, \"Logitek Electronic Systems, Inc.\"  },\r\n    { 0x1FD7, \"ASELSAN Elektronik Sanayi ve Ticaret. A.S.\"  },\r\n    { 0x1FD8, \"Guangzhou Tianhe Changjiang Communication Industrial Co\"  },\r\n    { 0x1FD9, \"Knox Company\"  },\r\n    { 0x1FDA, \"Beckwith Electric Co., Inc.\"  },\r\n    { 0x1FDB, \"Delphin Technology AG\"  },\r\n    { 0x1FDC, \"HOSA TECHNOLOGY, INC.\"  },\r\n    { 0x1FDD, \"CHASE GLORY INDUSTRIAL LTD.\"  },\r\n    { 0x1FDE, \"ILX Lightwave\"  },\r\n    { 0x1FDF, \"SEPURA PLC\"  },\r\n    { 0x1FE0, \"REALFLEET Co., Ltd.\"  },\r\n    { 0x1FE1, \"Ubixum, Inc.\"  },\r\n    { 0x1FE2, \"Aetas Systems Inc.\"  },\r\n    { 0x1FE3, \"Amaranthine, LLC\"  },\r\n    { 0x1FE4, \"HANDY TECH ELEKTRONIK GmbH\"  },\r\n    { 0x1FE5, \"KUKA Roboter GmbH\"  },\r\n    { 0x1FE6, \"BOOKHAM INC.\"  },\r\n    { 0x1FE7, \"VERTEX WIRELESS CO., LTD.\"  },\r\n    { 0x1FE8, \"103mm Tech\"  },\r\n    { 0x1FE9, \"Harvard Bioscience\"  },\r\n    { 0x1FEA, \"SIMPLO TECHNOLOGY CO., LTD.\"  },\r\n    { 0x1FEB, \"Tecella\"  },\r\n    { 0x1FEC, \"NIAN YEONG ENTERPRISE CO., LTD.\"  },\r\n    { 0x1FED, \"SYSACOM R&D Plus Inc.\"  },\r\n    { 0x1FEE, \"GALILEO ENGINEERING SRL\"  },\r\n    { 0x1FEF, \"RESOL - Elektronische Regelungen GmbH\"  },\r\n    { 0x1FF0, \"Kyoto Electronics Manufacturing Co., Ltd.\"  },\r\n    { 0x1FF1, \"Remote Operations Solutions\"  },\r\n    { 0x1FF2, \"Carl Valentin GmbH\"  },\r\n    { 0x1FF3, \"SINTEF Energy Research\"  },\r\n    { 0x1FF4, \"HYUNDAI PETATEL INC.\"  },\r\n    { 0x1FF5, \"Changzhou Wujin BEST Electronic Cables Co., Ltd.\"  },\r\n    { 0x1FF6, \"ClickTech LLC\"  },\r\n    { 0x1FF7, \"Guangzhou Shi Rui Electronics Co., Ltd.\"  },\r\n    { 0x1FF8, \"Infinite Memories\"  },\r\n    { 0x1FF9, \"Schulze Elektronik GmbH\"  },\r\n    { 0x1FFA, \"ARYGON Technologies AG\"  },\r\n    { 0x1FFB, \"Pololu Corporation\"  },\r\n    { 0x1FFC, \"Azimut Production Association JSC\"  },\r\n    { 0x1FFD, \"TESSERA, INC.\"  },\r\n    { 0x1FFE, \"HOST ENGINEERING, INC.\"  },\r\n    { 0x1FFF, \"Ideofy Inc.\"  },\r\n    { 0x2000, \"RongTong Info & Tech Co., Ltd.\"  },\r\n    { 0x2001, \"D-Link Corporation\"  },\r\n    { 0x2002, \"DAP Technologies Ltd.\"  },\r\n    { 0x2003, \"detectomat GmbH\"  },\r\n    { 0x2004, \"Shanghai Bellmann Digital Source Co., Ltd.\"  },\r\n    { 0x2005, \"Balluff GmbH\"  },\r\n    { 0x2006, \"Lenovo Mobile Communication Technology Ltd.\"  },\r\n    { 0x2007, \"LEYIO\"  },\r\n    { 0x2008, \"ThingMagic, Inc.\"  },\r\n    { 0x2009, \"MPEDIA\"  },\r\n    { 0x200A, \"ADVANCED RELAY CORP.\"  },\r\n    { 0x200B, \"TRANSISTOR DEVICES INC.\"  },\r\n    { 0x200C, \"HANPIN ELECTRON CO., LTD.\"  },\r\n    { 0x200D, \"Belkin Electronic (Changzhou) Co., Ltd.\"  },\r\n    { 0x200E, \"DAIICHI PARTS (HK) CO., LTD.\"  },\r\n    { 0x200F, \"Progind Srl\"  },\r\n    { 0x2010, \"Tectonica Australia Pty. Ltd.\"  },\r\n    { 0x2011, \"SHENZHEN HEXIN COM. TECH. CO., LTD.\"  },\r\n    { 0x2012, \"Applied Radar, Inc.\"  },\r\n    { 0x2013, \"PCTV Systems\"  },\r\n    { 0x2014, \"ONKEN CORPORATION\"  },\r\n    { 0x2015, \"Shenzhen Ephone Communication Technology Co., Ltd.\"  },\r\n    { 0x2016, \"Norbit AS\"  },\r\n    { 0x2017, \"NAL Research Corporation\"  },\r\n    { 0x2018, \"SilverPAC, Inc.\"  },\r\n    { 0x2019, \"Electronics Development Corp.\"  },\r\n    { 0x201A, \"Vortran Laser Technology, Inc.\"  },\r\n    { 0x201B, \"1064138 Ontario Ltd. O/A UNI-TEC ELECTRONICS\"  },\r\n    { 0x201C, \"Freeport Resources Enterprises Corp.\"  },\r\n    { 0x201D, \"Dongguan Shunhui Electronic Co., Ltd.\"  },\r\n    { 0x201E, \"Qingdao Haier Telecom Co., Ltd.\"  },\r\n    { 0x201F, \"W.E.M. INC.\"  },\r\n    { 0x2020, \"Shanghai BroadMobi Communication Technology Co., Ltd.\"  },\r\n    { 0x2021, \"Smartd ltd\"  },\r\n    { 0x2022, \"AMICON Ltd.\"  },\r\n    { 0x2023, \"Berthold Technologies GmbH & Co. KG\"  },\r\n    { 0x2024, \"Shoto Technologies LLC\"  },\r\n    { 0x2025, \"NANOSENSE\"  },\r\n    { 0x2026, \"EASUN REYROLLE LIMITED\"  },\r\n    { 0x2027, \"LOAD SYSTEMS INTERNATIONAL, INC.\"  },\r\n    { 0x2028, \"DETAS TECHNOLOGY LTD.\"  },\r\n    { 0x2029, \"MYTRAK HEALTH SYSTEM INC.\"  },\r\n    { 0x202A, \"Fast Forward Video, Inc.\"  },\r\n    { 0x202B, \"Damalini AB\"  },\r\n    { 0x202C, \"Enhanced Vision\"  },\r\n    { 0x202D, \"Snowbush IP (a division of Gennum)\"  },\r\n    { 0x202E, \"Lumio Inc.\"  },\r\n    { 0x202F, \"US ARMY RDECOM-ARDEC\"  },\r\n    { 0x2030, \"VITEC Multimedia\"  },\r\n    { 0x2031, \"Vistec AG\"  },\r\n    { 0x2032, \"GFMesstechnik GmbH\"  },\r\n    { 0x2033, \"WYMA Tecnologia Ltda.\"  },\r\n    { 0x2034, \"iSoft Silicon, Inc.\"  },\r\n    { 0x2035, \"seowonintech\"  },\r\n    { 0x2036, \"Eitech Co., Ltd.\"  },\r\n    { 0x2037, \"Control Devices Australia Pty., Ltd.\"  },\r\n    { 0x2038, \"Wescor Inc.\"  },\r\n    { 0x2039, \"SE-Elektronic GmbH\"  },\r\n    { 0x203A, \"Parallels, Inc.\"  },\r\n    { 0x203B, \"EIT, Inc.\"  },\r\n    { 0x203C, \"Steptechnica Co., Ltd.\"  },\r\n    { 0x203D, \"Encore Electronics\"  },\r\n    { 0x203E, \"Pascher Instruments AB\"  },\r\n    { 0x203F, \"WPG System Pte. Ltd.\"  },\r\n    { 0x2040, \"Hauppauge Computer Works, Inc.\"  },\r\n    { 0x2041, \"WILL BEST (ELECTRONICS) LTD.\"  },\r\n    { 0x2042, \"Eberspaecher Electronics GmbH & Co. KG\"  },\r\n    { 0x2043, \"Mobius Microsystems\"  },\r\n    { 0x2044, \"NOVUS PRODUTOS ELETRONICOS LTDA.\"  },\r\n    { 0x2045, \"EMH - Energie-Messtechnik GmbH\"  },\r\n    { 0x2046, \"AbleNet Inc.\"  },\r\n    { 0x2047, \"Texas Instruments Incorporated (MSP430 Group)\"  },\r\n    { 0x2048, \"Hongtech Electronics Co., Ltd.\"  },\r\n    { 0x2049, \"APACEWAVE TECHNOLOGIES\"  },\r\n    { 0x204A, \"Enclustra GmbH\"  },\r\n    { 0x204B, \"HANSHIN INFORMATION TECHNOLOGY INC.\"  },\r\n    { 0x204C, \"M7Lab., Co., Ltd.\"  },\r\n    { 0x204D, \"Orthodyne Electronics\"  },\r\n    { 0x204E, \"LINO MANFROTTO + CO. S.P.A.\"  },\r\n    { 0x204F, \"VIDEOTEC SpA\"  },\r\n    { 0x2050, \"CBF Systems, Inc.\"  },\r\n    { 0x2051, \"N.A.T. GmbH\"  },\r\n    { 0x2052, \"Movidius Ltd.\"  },\r\n    { 0x2053, \"HANSHIN TERMINAL CO., LTD.\"  },\r\n    { 0x2054, \"Source R & D Inc. (DBA WARPIA)\"  },\r\n    { 0x2055, \"Opti B. I. Communications, Ltd.\"  },\r\n    { 0x2056, \"CliniComp International Inc.\"  },\r\n    { 0x2057, \"DICE ELECTRONICS, LLC\"  },\r\n    { 0x2058, \"NANO RIVER TECHNOLOGIES\"  },\r\n    { 0x2059, \"SMART Temps LLC\"  },\r\n    { 0x205A, \"Hankook Tire\"  },\r\n    { 0x205B, \"TRUMPF Medizin Systeme GmbH\"  },\r\n    { 0x205C, \"Shenzhen Tronixin Electronics Co., Ltd.\"  },\r\n    { 0x205D, \"RESMED LTD.\"  },\r\n    { 0x205E, \"CTI PRODUCTS, Inc.\"  },\r\n    { 0x205F, \"Capella Microsystems Inc.\"  },\r\n    { 0x2060, \"U.S. Army Aviation & Missile R & D & Engineering Center\"  },\r\n    { 0x2061, \"FIGMENT DESIGN LABORATORIES\"  },\r\n    { 0x2062, \"Trulife\"  },\r\n    { 0x2063, \"AirMagnet Inc.\"  },\r\n    { 0x2064, \"Shenzhen AnNet Technology Co., Ltd.\"  },\r\n    { 0x2065, \"MEASUREMENT SPECIALTIES INC.\"  },\r\n    { 0x2066, \"Unicorn Electronics Components Co., Ltd.\"  },\r\n    { 0x2067, \"TSB LAO COMPANY LIMITED\"  },\r\n    { 0x2068, \"Seven 45 Studios\"  },\r\n    { 0x2069, \"Vanguard Rugged Storage, LLC\"  },\r\n    { 0x206A, \"Fujian Star-net Communication Co., Ltd.\"  },\r\n    { 0x206B, \"CETIM\"  },\r\n    { 0x206C, \"Seeker Technology Corp.\"  },\r\n    { 0x206D, \"Hunan GreatWall Information Financial Equipment Co.Ltd.\"  },\r\n    { 0x206E, \"ZAO MIRCOM\"  },\r\n    { 0x206F, \"JTOUCH Corporation\"  },\r\n    { 0x2070, \"Infinite Response, Inc.\"  },\r\n    { 0x2071, \"SYSTEM S.P.A.\"  },\r\n    { 0x2072, \"GOOD YEAR ELECTRONIC MFG. CO., LTD.\"  },\r\n    { 0x2073, \"Shenzhen R-Way Technology Co., Ltd.\"  },\r\n    { 0x2074, \"UNIVERSAL CHAMPION ELECTROACOUSTIC TECHNOLOGY COMPANY\"  },\r\n    { 0x2075, \"SecureKey Technologies Inc.\"  },\r\n    { 0x2076, \"SHINKAWA Sensor Technology, Inc.\"  },\r\n    { 0x2077, \"Shenzhen Gongjin Electronics Co., Ltd.\"  },\r\n    { 0x2078, \"Epsilon Electronics, Inc dba Power Acoustik Electronics\"  },\r\n    { 0x2079, \"New Concept Gaming Ltd.\"  },\r\n    { 0x207A, \"C.E.T.W.I.N System Solutions Sweden AB\"  },\r\n    { 0x207B, \"Technetix Group Ltd.\"  },\r\n    { 0x207C, \"NESA International, Inc.\"  },\r\n    { 0x207D, \"CESI Technology Co., Ltd.\"  },\r\n    { 0x207E, \"ENHANCED VIDEO DEVICES, INC.\"  },\r\n    { 0x207F, \"Profound BV\"  },\r\n    { 0x2080, \"Barnes and Noble\"  },\r\n    { 0x2081, \"UTRONIX Elektronikutreckling AB\"  },\r\n    { 0x2082, \"EKOMINI INC.\"  },\r\n    { 0x2083, \"XEL SOLUTIONS LTD.\"  },\r\n    { 0x2084, \"I Zone Technologies Co., Ltd.\"  },\r\n    { 0x2085, \"SIXENSE ENTERTAINMENT INC.\"  },\r\n    { 0x2086, \"SHENZHEN CATIC INFORMATION TECHNOLOGY INDUSTRY CO., LTD\"  },\r\n    { 0x2087, \"Cando Corporation\"  },\r\n    { 0x2088, \"WALTON CHAINTECH CORPORATION\"  },\r\n    { 0x2089, \"microdrones GmbH\"  },\r\n    { 0x208A, \"TECHNO ROAD Inc.\"  },\r\n    { 0x208B, \"KONTRON EMBEDDED COMPUTERS GmbH\"  },\r\n    { 0x208C, \"Linkbit, Inc.\"  },\r\n    { 0x208D, \"Attero Tech, LLC\"  },\r\n    { 0x208E, \"Luxshare-ICT\"  },\r\n    { 0x208F, \"Chi Mei Optoelectronics Corporation\"  },\r\n    { 0x2090, \"Transition Networks\"  },\r\n    { 0x2091, \"Callpod, Inc.\"  },\r\n    { 0x2092, \"Logina\"  },\r\n    { 0x2093, \"Ambu A/S\"  },\r\n    { 0x2094, \"Yoostar Entertainment Group, Inc.\"  },\r\n    { 0x2095, \"CE LINK LIMITED\"  },\r\n    { 0x2096, \"Shenzhen Microconn Investment and Development Co., Ltd.\"  },\r\n    { 0x2097, \"USBPARTNER\"  },\r\n    { 0x2098, \"TouchTable, Inc.\"  },\r\n    { 0x2099, \"Systematic Development Group, LLC\"  },\r\n    { 0x209A, \"Avedis Zildjian Company\"  },\r\n    { 0x209B, \"SATEL OY\"  },\r\n    { 0x209C, \"iPulse Systems\"  },\r\n    { 0x209D, \"Vector Co., Ltd.\"  },\r\n    { 0x209E, \"GlideTV Inc.\"  },\r\n    { 0x209F, \"Alcolizer Technology\"  },\r\n    { 0x20A0, \"Flirc\"  },\r\n    { 0x20A1, \"BRAINZSQUARE CO., LTD.\"  },\r\n    { 0x20A2, \"SCANMATIK\"  },\r\n    { 0x20A3, \"Sterilucent\"  },\r\n    { 0x20A4, \"Itron Metering Solutions\"  },\r\n    { 0x20A5, \"Cardiorobotics, Inc.\"  },\r\n    { 0x20A6, \"ZheJiang SEENSUN Communication&Electronic Equipment Co.\"  },\r\n    { 0x20A7, \"GREAT LUSTRE (SPEEDY) CO., LTD.\"  },\r\n    { 0x20A8, \"nLighten Technologies (Shanghai) Co., Ltd.\"  },\r\n    { 0x20A9, \"Autotronic Controls Corp.\"  },\r\n    { 0x20AA, \"ED-CONTRIVE Co., Ltd.\"  },\r\n    { 0x20AB, \"Identification International, Inc.\"  },\r\n    { 0x20AC, \"Wintek Corporation\"  },\r\n    { 0x20AD, \"Japan Probe Co., Ltd.\"  },\r\n    { 0x20AE, \"SoCChip (Wuxi Youxin IC Design Co., Ltd.)\"  },\r\n    { 0x20AF, \"Shenzhen CARVE Electronics Co., Ltd.\"  },\r\n    { 0x20B0, \"ICOMM TELE LIMITED\"  },\r\n    { 0x20B1, \"XMOS Ltd.\"  },\r\n    { 0x20B2, \"Clubbhouse Inventions LLC\"  },\r\n    { 0x20B3, \"Hannstouch Solution Inc.\"  },\r\n    { 0x20B4, \"SANDBRIDGE TECHNOLOGIES, INC.\"  },\r\n    { 0x20B5, \"ACD Gruppe\"  },\r\n    { 0x20B6, \"Bohle AG\"  },\r\n    { 0x20B7, \"Qi Hardware, Inc.\"  },\r\n    { 0x20B8, \"PARA INDUSTRIAL CO., LTD.\"  },\r\n    { 0x20B9, \"TLAY Technologies Co., Ltd.\"  },\r\n    { 0x20BA, \"jwin Electronics Corp.\"  },\r\n    { 0x20BB, \"THALES TRANSPORTATION SYSTEMS\"  },\r\n    { 0x20BC, \"Guangzhou Pingzhong Electronic Technology Co., Ltd.\"  },\r\n    { 0x20BD, \"KETEK\"  },\r\n    { 0x20BE, \"BURY GmbH & Co. KG\"  },\r\n    { 0x20BF, \"Dwyer Instruments, Inc.\"  },\r\n    { 0x20C0, \"FENGHUA KINGSUN CO., LTD.\"  },\r\n    { 0x20C1, \"HARWIN ASIA PTE. LTD.\"  },\r\n    { 0x20C2, \"Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab\"  },\r\n    { 0x20C3, \"TECNOMOTOR ELETRONICA DO BRASIL S/A\"  },\r\n    { 0x20C4, \"Communications Laboratories, Inc. (Comlabs)\"  },\r\n    { 0x20C5, \"A.U. Physics Enterprises\"  },\r\n    { 0x20C6, \"Mutto Optronics Corporation\"  },\r\n    { 0x20C7, \"HMC INTERNATIONAL\"  },\r\n    { 0x20C8, \"CEC TELECOM CO., LTD.\"  },\r\n    { 0x20C9, \"SYSTEMCORP Pty., Ltd.\"  },\r\n    { 0x20CA, \"TRIPHOS Co., Ltd.\"  },\r\n    { 0x20CB, \"Dave Smith Instruments\"  },\r\n    { 0x20CC, \"TAKARA\"  },\r\n    { 0x20CD, \"Schweers Informationstechnologie GmbH\"  },\r\n    { 0x20CE, \"Mini-Circuits\"  },\r\n    { 0x20CF, \"Gridmark Limited\"  },\r\n    { 0x20D0, \"FRESENIUS VIAL\"  },\r\n    { 0x20D1, \"Dascom Europe GmbH\"  },\r\n    { 0x20D2, \"ROBOTEQ INC.\"  },\r\n    { 0x20D3, \"Provo Craft\"  },\r\n    { 0x20D4, \"SCDi\"  },\r\n    { 0x20D5, \"Lenexpo Inc. (dba: Atlona)\"  },\r\n    { 0x20D6, \"Bensussen Deutsch & Associates, Inc. (BDA)\"  },\r\n    { 0x20D7, \"SHENZHEN ZILI ELECTRONICS CO. LTD.\"  },\r\n    { 0x20D8, \"Changzhou Xinchao Technologies, Inc.\"  },\r\n    { 0x20D9, \"ZHEJIANG YONGCHENGGONG DIANSU.CO., LTD.\"  },\r\n    { 0x20DA, \"LumaSense Technologies A/S\"  },\r\n    { 0x20DB, \"KTS GmbH\"  },\r\n    { 0x20DC, \"KCS Digital, Inc.\"  },\r\n    { 0x20DD, \"FORTREND TAIWAN SCIENTIFIC CORP.\"  },\r\n    { 0x20DE, \"OneSail HK Ltd.\"  },\r\n    { 0x20DF, \"SIMTEC ELECTRONICS\"  },\r\n    { 0x20E0, \"Realway Electronics Technology Limited\"  },\r\n    { 0x20E1, \"Daiichi Co., Ltd.\"  },\r\n    { 0x20E2, \"ASEQ INSTRUMENTS\"  },\r\n    { 0x20E3, \"LAUDA DR.R.WOBSER GMBH & CO. KG\"  },\r\n    { 0x20E4, \"Onecell Technologies\"  },\r\n    { 0x20E5, \"Cardreader, Inc.\"  },\r\n    { 0x20E6, \"Brooks Automation, Inc.\"  },\r\n    { 0x20E7, \"Scientific Digital Imaging plc\"  },\r\n    { 0x20E8, \"Jow Tong Technology Co., Ltd.\"  },\r\n    { 0x20E9, \"adp Gauselmann GmbH\"  },\r\n    { 0x20EA, \"CACTUS TECHNOLOGIES, LIMITED\"  },\r\n    { 0x20EB, \"AOS Technologies AG\"  },\r\n    { 0x20EC, \"AMBIR TECHNOLOGY, INC.\"  },\r\n    { 0x20ED, \"TRANZFINITY, INC.\"  },\r\n    { 0x20EE, \"Emotiva Audio Corp.\"  },\r\n    { 0x20EF, \"TIGRIS Elektronik GmbH\"  },\r\n    { 0x20F0, \"Insight Technology Incorporated\"  },\r\n    { 0x20F1, \"NET GmbH\"  },\r\n    { 0x20F2, \"Secured Mobility\"  },\r\n    { 0x20F3, \"Flexcore\"  },\r\n    { 0x20F4, \"TRENDnet\"  },\r\n    { 0x20F5, \"MKS Instruments - Technology for Productivity\"  },\r\n    { 0x20F6, \"EXMAN ELECTRIC\"  },\r\n    { 0x20F7, \"XIMEA s.r.o.\"  },\r\n    { 0x20F8, \"Guangzhou Somic Digital & Electronic Technology Co, Ltd\"  },\r\n    { 0x20F9, \"Medical Computer Systems, Ltd.\"  },\r\n    { 0x20FA, \"IC Intracom\"  },\r\n    { 0x20FB, \"Aptina Imaging Corporation\"  },\r\n    { 0x20FC, \"PIE SOFT LAB CORPORATION\"  },\r\n    { 0x20FD, \"NOVO NORDISK A/S\"  },\r\n    { 0x20FE, \"Bittium USA Inc.\"  },\r\n    { 0x20FF, \"PNI Sensor Corp.\"  },\r\n    { 0x2100, \"RT Systems Inc.\"  },\r\n    { 0x2101, \"NAS Technologies Corp.\"  },\r\n    { 0x2102, \"Vitalograph Ltd.\"  },\r\n    { 0x2103, \"OHMORI ELECTRIC INDUSTRIES CO., LTD.\"  },\r\n    { 0x2104, \"Tobii AB\"  },\r\n    { 0x2105, \"Retail Innovation HTT AB\"  },\r\n    { 0x2106, \"Sharp Korea Corporation\"  },\r\n    { 0x2107, \"Amstore CD Production Ltd.\"  },\r\n    { 0x2108, \"NEATO ROBOTICS\"  },\r\n    { 0x2109, \"VIA Labs, Inc.\"  },\r\n    { 0x210A, \"PULSUS TECHNOLOGIES\"  },\r\n    { 0x210B, \"Work Microwave GmbH\"  },\r\n    { 0x210C, \"DOT HILL SYSTEMS\"  },\r\n    { 0x210D, \"Plastoform Industries Ltd.\"  },\r\n    { 0x210E, \"Commscope\"  },\r\n    { 0x210F, \"Tyco / Scott Health & Safety\"  },\r\n    { 0x2110, \"carina system co., ltd.\"  },\r\n    { 0x2111, \"alphaNUCLEAR Inc.\"  },\r\n    { 0x2112, \"Point Of Pay Pty. Ltd.\"  },\r\n    { 0x2113, \"Softkinetic\"  },\r\n    { 0x2114, \"Innovision Technology Corporation Ltd.\"  },\r\n    { 0x2115, \"Alliance Material Co., Ltd.\"  },\r\n    { 0x2116, \"KT Tech Inc.\"  },\r\n    { 0x2117, \"Frama AG\"  },\r\n    { 0x2118, \"RF WINDOW\"  },\r\n    { 0x2119, \"MoreDNA Technology Co., Ltd.\"  },\r\n    { 0x211A, \"PILLKEY HOLDING BV\"  },\r\n    { 0x211B, \"MENTOR GmbH & Co. Praezisions-Bauteile KG\"  },\r\n    { 0x211C, \"SWENC Technology Co., Ltd.\"  },\r\n    { 0x211D, \"Mutualink, Inc.\"  },\r\n    { 0x211E, \"Dongbu HiTek\"  },\r\n    { 0x211F, \"XINETWORKS CO., LTD.\"  },\r\n    { 0x2120, \"Odirrus Limited\"  },\r\n    { 0x2121, \"Escort Data Logging Systems Ltd.\"  },\r\n    { 0x2122, \"ZEDEL\"  },\r\n    { 0x2123, \"SYNTEK DEVELOPMENT LTD.\"  },\r\n    { 0x2124, \"ELSAGDATAMAT S.P.A.\"  },\r\n    { 0x2125, \"FIBERPRO INC.\"  },\r\n    { 0x2126, \"SUZA INTERNATIONAL FRANCE\"  },\r\n    { 0x2127, \"FutureDial, Inc.\"  },\r\n    { 0x2128, \"Naval Research Laboratory\"  },\r\n    { 0x2129, \"Tokushu Denshi Kairo, Inc.\"  },\r\n    { 0x212A, \"Kappa optronics GmbH\"  },\r\n    { 0x212B, \"GR Telecom Co., Ltd.\"  },\r\n    { 0x212C, \"Shenzhen Linoya Electronic Co., Ltd.\"  },\r\n    { 0x212D, \"Dong Guan City Wanhong Electric Co., Ltd.\"  },\r\n    { 0x212E, \"Amphenol AssembleTech (Xiamen) Co., Ltd.\"  },\r\n    { 0x212F, \"SUZUKI MUSICAL INST. MFG. CO., LTD.\"  },\r\n    { 0x2130, \"Sanmu Communication Technology (H.K.) Ltd.\"  },\r\n    { 0x2131, \"IES Co., Ltd.\"  },\r\n    { 0x2132, \"EDAS, Inc.\"  },\r\n    { 0x2133, \"SIGNOTEC GmbH\"  },\r\n    { 0x2134, \"CANESTA, INC.\"  },\r\n    { 0x2135, \"W.O.M. World of Medicine AG\"  },\r\n    { 0x2136, \"Compunow Trading Corp.\"  },\r\n    { 0x2137, \"Beyonics Technology Limited\"  },\r\n    { 0x2138, \"iVina, Inc.\"  },\r\n    { 0x2139, \"Eigenlabs Ltd.\"  },\r\n    { 0x213A, \"Carlo Gavazzi\"  },\r\n    { 0x213B, \"UICO, Inc.\"  },\r\n    { 0x213C, \"ICON Health & Fitness\"  },\r\n    { 0x213D, \"DRS Data & Imaging Systems, Inc.\"  },\r\n    { 0x213E, \"Phase Matrix, Inc.\"  },\r\n    { 0x213F, \"Digitron Instrumentation Ltd.\"  },\r\n    { 0x2140, \"Sichuan Jiuzhou Electric Group Co., Ltd.\"  },\r\n    { 0x2141, \"ZT Group Int'l, Inc.\"  },\r\n    { 0x2142, \"Enginuity Communications\"  },\r\n    { 0x2143, \"InDevR Inc.\"  },\r\n    { 0x2144, \"Sea Tel, Inc.\"  },\r\n    { 0x2145, \"Ballard Technology\"  },\r\n    { 0x2146, \"Victorinox AG\"  },\r\n    { 0x2147, \"Chin-Ban Electronics (Hong Kong) Co., Ltd.\"  },\r\n    { 0x2148, \"Visteon Sistemas Automotives Ltda.\"  },\r\n    { 0x2149, \"MasTouch Optoelectronics Technologies Co., Ltd.\"  },\r\n    { 0x214A, \"Interlink Electronics\"  },\r\n    { 0x214B, \"AMECO TECHNOLOGIES (SHENZHEN) CO., LTD.\"  },\r\n    { 0x214C, \"Y Soft Corporation\"  },\r\n    { 0x214D, \"SyTech Corporation\"  },\r\n    { 0x214E, \"Swiftpoint Limited\"  },\r\n    { 0x214F, \"Attainment Company, Inc.\"  },\r\n    { 0x2150, \"AZOTEQ (PTY) LTD.\"  },\r\n    { 0x2151, \"SeaSpace Corporation\"  },\r\n    { 0x2152, \"AD Semiconductor Co., Ltd.\"  },\r\n    { 0x2153, \"Mastertouch Solutions Electronics Co., Ltd.\"  },\r\n    { 0x2154, \"Trace Lighting Ltd.\"  },\r\n    { 0x2155, \"Teledyne Controls\"  },\r\n    { 0x2156, \"Weistech Technology Co., Ltd.\"  },\r\n    { 0x2157, \"Digital Imaging Technology\"  },\r\n    { 0x2158, \"TA WEI TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2159, \"TRIASX Pty Ltd.\"  },\r\n    { 0x215A, \"Sling Media, Inc.\"  },\r\n    { 0x215B, \"2D Debus & Diebold Messsysteme GmbH\"  },\r\n    { 0x215C, \"OTOVATION, LLC\"  },\r\n    { 0x215D, \"GeNUA mbH\"  },\r\n    { 0x215E, \"ST Embedded Engineering, LLC\"  },\r\n    { 0x215F, \"DECIMATOR DESIGN PTY LTD.\"  },\r\n    { 0x2160, \"PULOON Technology Inc.\"  },\r\n    { 0x2161, \"BEA SA\"  },\r\n    { 0x2162, \"Prime Audio Inc.\"  },\r\n    { 0x2163, \"Digital Rapids Corp.\"  },\r\n    { 0x2164, \"Witek System\"  },\r\n    { 0x2165, \"CONTROL SOLUTIONS, INC.\"  },\r\n    { 0x2166, \"JVC KENWOOD Corporation\"  },\r\n    { 0x2167, \"Zhejiang Fousine Science & Technology Co., Ltd.\"  },\r\n    { 0x2168, \"TZYR HWEY ENTERPRISE CO., LTD.\"  },\r\n    { 0x2169, \"TIANJIN SHENNAN INFORMATION SECURITY CO., LTD.\"  },\r\n    { 0x216A, \"Shenzhen San Jing Electronics Co., Ltd.\"  },\r\n    { 0x216B, \"XceedID Corporation\"  },\r\n    { 0x216C, \"UniDisplay Inc.\"  },\r\n    { 0x216D, \"BENSON MEDICAL INSTRUMENTS\"  },\r\n    { 0x216E, \"KHOMP INDUSTRIA E COMERCIO LTDA\"  },\r\n    { 0x216F, \"ALTAIR SEMICONDUCTOR\"  },\r\n    { 0x2170, \"Wurtec, Inc.\"  },\r\n    { 0x2171, \"Bokam Engineering, Inc.\"  },\r\n    { 0x2172, \"Torrey Pines Logic, Inc.\"  },\r\n    { 0x2173, \"HUIZHOU HUANGJI PRECISIONS FLEX ELECTRONICAL CO., LTD.\"  },\r\n    { 0x2174, \"Transcend Information, Inc.\"  },\r\n    { 0x2175, \"Light Blue Optics, Inc.\"  },\r\n    { 0x2176, \"TMC - Allion Test Labs\"  },\r\n    { 0x2177, \"CHAUVIN ARNOUX\"  },\r\n    { 0x2178, \"Ion Science\"  },\r\n    { 0x2179, \"UGtizer Corp.\"  },\r\n    { 0x217A, \"Triple Eye\"  },\r\n    { 0x217B, \"BDP Semiconductors Ltd.\"  },\r\n    { 0x217C, \"Sensitech Inc.\"  },\r\n    { 0x217D, \"Bilcare Technologies Singapore Pte. Ltd.\"  },\r\n    { 0x217E, \"TP RADIO\"  },\r\n    { 0x217F, \"REAL EAR A/S\"  },\r\n    { 0x2180, \"Icare Finland Oy\"  },\r\n    { 0x2181, \"GLOBAL TRAFFIC TECHNOLOGIES, LLC\"  },\r\n    { 0x2182, \"XAC Automation Corp.\"  },\r\n    { 0x2183, \"Bonutti Research\"  },\r\n    { 0x2184, \"GOOD WILL Instrument Co., Ltd.\"  },\r\n    { 0x2185, \"FUJIWORK Co., Ltd.\"  },\r\n    { 0x2186, \"Home Server Technologies Inc.\"  },\r\n    { 0x2187, \"ESPACE SERVICES MULTIMEDIAS\"  },\r\n    { 0x2188, \"CalDigit, Inc.\"  },\r\n    { 0x2189, \"SEMNTECH\"  },\r\n    { 0x218A, \"EXELYS LLC\"  },\r\n    { 0x218B, \"Blackbird Technologies Inc.\"  },\r\n    { 0x218C, \"Gammadata Instrument AB\"  },\r\n    { 0x218D, \"Adaptive I/O Technologies, Inc.\"  },\r\n    { 0x218E, \"UNITRO-Fleischmann\"  },\r\n    { 0x218F, \"DHEF INC.\"  },\r\n    { 0x2190, \"esonic Co., Ltd.\"  },\r\n    { 0x2191, \"SecureAT Co., Ltd.\"  },\r\n    { 0x2192, \"FlexRadio Systems\"  },\r\n    { 0x2193, \"Schnick-Schnack-Systems GmbH\"  },\r\n    { 0x2194, \"ROTH + WEBER GmbH\"  },\r\n    { 0x2195, \"Hans Eckes Hardware & Software\"  },\r\n    { 0x2196, \"XPMOBILE\"  },\r\n    { 0x2197, \"W & D, LLC\"  },\r\n    { 0x2198, \"Wonde Proud Technology Co., Ltd.\"  },\r\n    { 0x2199, \"Image and Information Technology\"  },\r\n    { 0x219A, \"COSMO ELECTRONICS CO., LTD.\"  },\r\n    { 0x219B, \"TPK Touch Solutions Inc.\"  },\r\n    { 0x219C, \"SEAL ONE AG\"  },\r\n    { 0x219D, \"BDR Technologies Ltd.\"  },\r\n    { 0x219E, \"VALKEE OY\"  },\r\n    { 0x219F, \"VENTIS\"  },\r\n    { 0x21A0, \"AXELSPACE Corporation\"  },\r\n    { 0x21A1, \"EMOTIV SYSTEMS INC.\"  },\r\n    { 0x21A2, \"ABB Low Voltage Products\"  },\r\n    { 0x21A3, \"Optcom Co., Ltd.\"  },\r\n    { 0x21A4, \"ELECTRONIC ARTS\"  },\r\n    { 0x21A5, \"Genesis Technology USA, Inc.\"  },\r\n    { 0x21A6, \"YUPITERU CORPORATION\"  },\r\n    { 0x21A7, \"PAYPRINT SRL\"  },\r\n    { 0x21A8, \"GE Intelligent Platforms, Inc.\"  },\r\n    { 0x21A9, \"Saleae LLC\"  },\r\n    { 0x21AA, \"TAKASAKI KYODO COMPUTING CENTER CO., LTD.\"  },\r\n    { 0x21AB, \"Planeta Informatica Ltda.\"  },\r\n    { 0x21AC, \"infoSense Technology Inc.\"  },\r\n    { 0x21AD, \"Wobbegong Fitness and Therapy Products Pty. Ltd.\"  },\r\n    { 0x21AE, \"Philips and Neusoft Medical System Co., Ltd.\"  },\r\n    { 0x21AF, \"Euro-CB Phils. Inc.\"  },\r\n    { 0x21B0, \"Grace Industries, Incorporated\"  },\r\n    { 0x21B1, \"TATA CONSULTANCY SERVICES\"  },\r\n    { 0x21B2, \"Felix Meier GmbH\"  },\r\n    { 0x21B3, \"Dongguan Teconn Electronics Technology Co., Ltd.\"  },\r\n    { 0x21B4, \"Wavelength Audio, Ltd.\"  },\r\n    { 0x21B5, \"SHENZHEN JASON ELECTRONICS CO., LTD.\"  },\r\n    { 0x21B6, \"EUROAVIONICS GmbH & Co. KG\"  },\r\n    { 0x21B7, \"STAIB INSTRUMENTE GmbH\"  },\r\n    { 0x21B8, \"KONTRONIK GmbH\"  },\r\n    { 0x21B9, \"ZP ENGINEERING s.r.l.\"  },\r\n    { 0x21BA, \"SI2 MICROSYSTEMS, Ltd.\"  },\r\n    { 0x21BB, \"WWPass Corporation\"  },\r\n    { 0x21BC, \"Skyhawke Technologies, LLC\"  },\r\n    { 0x21BD, \"Code Red Technologies, Ltd.\"  },\r\n    { 0x21BE, \"KEC Co., Ltd.\"  },\r\n    { 0x21BF, \"Mayo Clinic\"  },\r\n    { 0x21C0, \"PIXTREE, Inc.\"  },\r\n    { 0x21C1, \"Baumann Electronic Controls, LLC\"  },\r\n    { 0x21C2, \"Shenzhen V-Interface Technology Co., Ltd.\"  },\r\n    { 0x21C3, \"MASIMO LABORATORIES INC.\"  },\r\n    { 0x21C4, \"Longsys Electronics (HK) Co., Ltd.\"  },\r\n    { 0x21C5, \"Vukic Computer Instruments GmbH\"  },\r\n    { 0x21C6, \"PSS Hong Kong Limited\"  },\r\n    { 0x21C7, \"Unisoku Co., Ltd.\"  },\r\n    { 0x21C8, \"IDONDEMAND INC.\"  },\r\n    { 0x21C9, \"Innoteletek, Inc.\"  },\r\n    { 0x21CA, \"RAE Systems Inc.\"  },\r\n    { 0x21CB, \"Vodafone Ltd.\"  },\r\n    { 0x21CC, \"ChipsWork Microelectronics Corp.\"  },\r\n    { 0x21CD, \"Infoxelle Co., Ltd.\"  },\r\n    { 0x21CE, \"Polostar Technology Corporation\"  },\r\n    { 0x21CF, \"HISATOMI ELECTRIC IND. CO., LTD.\"  },\r\n    { 0x21D0, \"Red Rapids\"  },\r\n    { 0x21D1, \"ADDER TECHNOLOGY LTD.\"  },\r\n    { 0x21D2, \"NeoLAB Convergence\"  },\r\n    { 0x21D3, \"Compupack Technology Co., Ltd.\"  },\r\n    { 0x21D4, \"Eduplayer Co., Ltd.\"  },\r\n    { 0x21D5, \"M.G.F.\"  },\r\n    { 0x21D6, \"Agecodagis SARL\"  },\r\n    { 0x21D7, \"VINCIAMO, Inc.\"  },\r\n    { 0x21D8, \"P & A Technologies, Inc.\"  },\r\n    { 0x21D9, \"Verification Technology, Inc.\"  },\r\n    { 0x21DA, \"Valor Auto Companion, Inc.\"  },\r\n    { 0x21DB, \"G-Max Technology Co., Ltd.\"  },\r\n    { 0x21DC, \"ABB S.p.A., Low Voltage Products Division\"  },\r\n    { 0x21DD, \"Looxcie, Inc.\"  },\r\n    { 0x21DE, \"Cloud Engines, Inc.\"  },\r\n    { 0x21DF, \"Quanser Consulting Inc.\"  },\r\n    { 0x21E0, \"OpenPattern\"  },\r\n    { 0x21E1, \"CAEN S.P.A.\"  },\r\n    { 0x21E2, \"Ascension Technology Corp.\"  },\r\n    { 0x21E3, \"Crest Technology Inc.\"  },\r\n    { 0x21E4, \"Xcellen Co., Ltd.\"  },\r\n    { 0x21E5, \"Kruglov Evgeniy Vladimirovich\"  },\r\n    { 0x21E6, \"OCZ Technology Group\"  },\r\n    { 0x21E7, \"Sagemcom Broadband SAS\"  },\r\n    { 0x21E8, \"BOEHNKE + PARTNER GmbH Steuerungssysteme\"  },\r\n    { 0x21E9, \"Jiafuh Metal & Plastic (ShenZhen) Co., Ltd.\"  },\r\n    { 0x21EA, \"JUST MAKE ELECTRONICS CO., LTD.\"  },\r\n    { 0x21EB, \"KOKORO CO., LTD.\"  },\r\n    { 0x21EC, \"ApniCure, Inc.\"  },\r\n    { 0x21ED, \"Accuphase Laboratories, Inc.\"  },\r\n    { 0x21EE, \"MAVIN TECHNOLOGY INC.\"  },\r\n    { 0x21EF, \"FEMTO Messtechnik GmbH\"  },\r\n    { 0x21F0, \"LivingLab Development Co., Ltd.\"  },\r\n    { 0x21F1, \"ABS Group AB\"  },\r\n    { 0x21F2, \"Palmer Environmental Ltd.\"  },\r\n    { 0x21F3, \"Inspired Instruments Inc.\"  },\r\n    { 0x21F4, \"Minebea Technologies Taiwan Co., Ltd.\"  },\r\n    { 0x21F5, \"Shenzhen Strong Rising Electronics Co., Ltd.\"  },\r\n    { 0x21F6, \"QSR Automations, Inc.\"  },\r\n    { 0x21F7, \"Wuerth-Elektronik eiSos GmbH & Co. KG\"  },\r\n    { 0x21F8, \"Goeasily Int'l Co., Ltd.\"  },\r\n    { 0x21F9, \"American Thermal Instruments\"  },\r\n    { 0x21FA, \"Pitsco, Inc.\"  },\r\n    { 0x21FB, \"HELIOS Electronic Design & Manufacture\"  },\r\n    { 0x21FC, \"Thum + Mahr GmbH\"  },\r\n    { 0x21FD, \"Associated Controls (Australia) Pty., Limited\"  },\r\n    { 0x21FE, \"ELAP S.p.A.\"  },\r\n    { 0x21FF, \"DEIF A/S\"  },\r\n    { 0x2200, \"Nuribom\"  },\r\n    { 0x2201, \"Elan Digital Systems Ltd.\"  },\r\n    { 0x2202, \"Walex Electronic (Wu Xi) Co., Ltd.\"  },\r\n    { 0x2203, \"Shin Shin Co., Ltd.\"  },\r\n    { 0x2204, \"Innov-X Systems Inc.\"  },\r\n    { 0x2205, \"3eYamaichi Electronics Co., Ltd.\"  },\r\n    { 0x2206, \"Wiretek International Investment Ltd.\"  },\r\n    { 0x2207, \"Fuzhou Rockchip Electronics Co., Ltd.\"  },\r\n    { 0x2208, \"CONNFLY ELECTRONIC CO., LTD.\"  },\r\n    { 0x2209, \"SPoT LLC\"  },\r\n    { 0x220A, \"Anton Paar GmbH\"  },\r\n    { 0x220B, \"IKARIA Holdings, Inc.\"  },\r\n    { 0x220C, \"Island Technology Co., Ltd.\"  },\r\n    { 0x220D, \"Humanline Co., Ltd.\"  },\r\n    { 0x220E, \"NetComm Ltd.\"  },\r\n    { 0x220F, \"Italdata Ingegneria Dell'Idea s.p.a.\"  },\r\n    { 0x2210, \"Klavis Technologies\"  },\r\n    { 0x2211, \"FLUID COMPONENTS INTERNATIONAL LLC\"  },\r\n    { 0x2212, \"Dev-Audio Pty. Ltd. (Dev-Audio)\"  },\r\n    { 0x2213, \"Ascon Co., Ltd.\"  },\r\n    { 0x2214, \"Pollin Electronic GmbH\"  },\r\n    { 0x2215, \"InCOMM Technologies Co., Ltd.\"  },\r\n    { 0x2216, \"Environmental Systems Corporation\"  },\r\n    { 0x2217, \"FTS Forest Technology Systems Ltd.\"  },\r\n    { 0x2218, \"Listen Technologies Corp.\"  },\r\n    { 0x2219, \"Hogahm Technology\"  },\r\n    { 0x221A, \"ZTEX\"  },\r\n    { 0x221B, \"Kyodo Denshi Engineering Co., Ltd.\"  },\r\n    { 0x221C, \"CORTEX TECHNOLOGY APS\"  },\r\n    { 0x221D, \"fischertechnik GmbH\"  },\r\n    { 0x221E, \"Linktec Technologies Co., Ltd.\"  },\r\n    { 0x221F, \"Resolution Audio\"  },\r\n    { 0x2220, \"FAMAS SYSTEM S.P.A.\"  },\r\n    { 0x2221, \"EnovateIT Inc.\"  },\r\n    { 0x2222, \"SOFTMECHA\"  },\r\n    { 0x2223, \"Ratioplast-Optoelectronics GmbH\"  },\r\n    { 0x2224, \"LM Technologies Ltd.\"  },\r\n    { 0x2225, \"GETT Geratetechnik GmbH\"  },\r\n    { 0x2226, \"PLANAR LLC\"  },\r\n    { 0x2227, \"Northtronics Pty., Ltd.\"  },\r\n    { 0x2228, \"Dantec Dynamics A/S\"  },\r\n    { 0x2229, \"Key Technologies, Inc.\"  },\r\n    { 0x222A, \"ILI TECHNOLOGY CORP.\"  },\r\n    { 0x222B, \"ALPHAMEDIA CO., LTD.\"  },\r\n    { 0x222C, \"TOHAN DENSHI KIKI Co., Ltd.\"  },\r\n    { 0x222D, \"LEIFHEIT AG\"  },\r\n    { 0x222E, \"OXYSEC s.r.l.\"  },\r\n    { 0x222F, \"Tcom Technology Co., Ltd.\"  },\r\n    { 0x2230, \"Plugable Technologies\"  },\r\n    { 0x2231, \"Coregate Inc.\"  },\r\n    { 0x2232, \"NAMUGA Co., Ltd.\"  },\r\n    { 0x2233, \"ARGtek Communication Inc.\"  },\r\n    { 0x2234, \"T-CONN PRECISION CORPORATION\"  },\r\n    { 0x2235, \"WoundVision\"  },\r\n    { 0x2236, \"ACELLA\"  },\r\n    { 0x2237, \"Kobo Inc.\"  },\r\n    { 0x2238, \"ELMO Motion Control Ltd.\"  },\r\n    { 0x2239, \"PEIKER acustic GmbH & Co., KG\"  },\r\n    { 0x223A, \"BKtel Communications GmbH\"  },\r\n    { 0x223B, \"Crystalfontz America, Inc.\"  },\r\n    { 0x223C, \"Audio Research Corp.\"  },\r\n    { 0x223D, \"AlfaPlus Semiconductor, Inc.\"  },\r\n    { 0x223E, \"Home Electronics\"  },\r\n    { 0x223F, \"Oga, Inc.\"  },\r\n    { 0x2240, \"NETTALK.COM INC.\"  },\r\n    { 0x2241, \"Envision Interface Engineering, LLC\"  },\r\n    { 0x2242, \"Zhihe Electronics Technology Co., Ltd.\"  },\r\n    { 0x2243, \"EMIC CORPORATION\"  },\r\n    { 0x2244, \"Kronos\"  },\r\n    { 0x2245, \"ASPEED Technology Inc.\"  },\r\n    { 0x2246, \"Nanjing Frentec Co., Ltd.\"  },\r\n    { 0x2247, \"CHUNGHWA PICTURE TUBES, LTD.\"  },\r\n    { 0x2248, \"KAISE CORPORATION\"  },\r\n    { 0x2249, \"Long Range Systems, Inc.\"  },\r\n    { 0x224A, \"ORMEC SYSTEMS CORP.\"  },\r\n    { 0x224B, \"Sirit Inc.\"  },\r\n    { 0x224C, \"Datron World Communications, Inc.\"  },\r\n    { 0x224D, \"Tescom Co., Ltd.\"  },\r\n    { 0x224E, \"RDH2 Science\"  },\r\n    { 0x224F, \"APDM, INC.\"  },\r\n    { 0x2250, \"Evernew Wire & Cable Co., Ltd.\"  },\r\n    { 0x2251, \"QuieTek Corp.\"  },\r\n    { 0x2252, \"TSANSUN TECH. CO., LTD.\"  },\r\n    { 0x2253, \"Arpage AG\"  },\r\n    { 0x2254, \"RPO\"  },\r\n    { 0x2255, \"COOPER WIRELESS\"  },\r\n    { 0x2256, \"Mathias Fuchss Software - Entwicklung\"  },\r\n    { 0x2257, \"On the Go Video, Inc.\"  },\r\n    { 0x2258, \"D+H Mechatronic AG\"  },\r\n    { 0x2259, \"Skypine Electronics (Shenzhen) Co., Ltd.\"  },\r\n    { 0x225A, \"Vivanco GmbH\"  },\r\n    { 0x225B, \"Lineage Power\"  },\r\n    { 0x225C, \"Digital Check Corp\"  },\r\n    { 0x225D, \"Sagem Securite\"  },\r\n    { 0x225E, \"Unholtz-Dickie Corp.\"  },\r\n    { 0x225F, \"Ace Karaoke Corp.\"  },\r\n    { 0x2260, \"Multigig, Inc.\"  },\r\n    { 0x2261, \"DOM-Sicherheitstechnik GmbH & Co. KG\"  },\r\n    { 0x2262, \"VIETTEL GROUP\"  },\r\n    { 0x2263, \"Nuovations\"  },\r\n    { 0x2264, \"Entourage Systems, Inc.\"  },\r\n    { 0x2265, \"DailyCare BioMedical Inc.\"  },\r\n    { 0x2266, \"Psychology Software Tools, Inc.\"  },\r\n    { 0x2267, \"Boreal Genomics\"  },\r\n    { 0x2268, \"EXSUSS, Inc.\"  },\r\n    { 0x2269, \"Schlumberger Ltd.\"  },\r\n    { 0x226A, \"Ooma, Inc.\"  },\r\n    { 0x226B, \"Bruker Nano GmbH\"  },\r\n    { 0x226C, \"HAL Communications Corp.\"  },\r\n    { 0x226D, \"Wrenchman, Inc.\"  },\r\n    { 0x226E, \"DISPLAX\"  },\r\n    { 0x226F, \"Koyo Trading Co., Ltd.\"  },\r\n    { 0x2270, \"XiaMen GaoLuChang Electronics Co. Ltd.\"  },\r\n    { 0x2271, \"Karl Storz GmbH & Co. KG\"  },\r\n    { 0x2272, \"E.E.P.D.\"  },\r\n    { 0x2273, \"IMAX Corporation\"  },\r\n    { 0x2274, \"Morgan Schaffer Inc.\"  },\r\n    { 0x2275, \"ReliOn Inc.\"  },\r\n    { 0x2276, \"Pioneer CBC\"  },\r\n    { 0x2277, \"Ortho Neuro Technologies, Inc.\"  },\r\n    { 0x2278, \"Infratec Datentechnik GmbH\"  },\r\n    { 0x2279, \"Goossens Engineering\"  },\r\n    { 0x227A, \"FLOM Corporation\"  },\r\n    { 0x227B, \"CYBELEC SA\"  },\r\n    { 0x227C, \"S. & A.S. LTD.\"  },\r\n    { 0x227D, \"Unitec Co., Ltd.\"  },\r\n    { 0x227E, \"JSC <SATIS-TL-94>\"  },\r\n    { 0x227F, \"Granite River Labs\"  },\r\n    { 0x2280, \"Life Technologies Corp.\"  },\r\n    { 0x2281, \"GI CORPORATION\"  },\r\n    { 0x2282, \"Mamiya Digital Imaging Co., Ltd.\"  },\r\n    { 0x2283, \"NIHON DEMPA KOGYO Co., Ltd.\"  },\r\n    { 0x2284, \"SuperSonic Inc.\"  },\r\n    { 0x2285, \"IRIS ID\"  },\r\n    { 0x2286, \"Altierre Corporation\"  },\r\n    { 0x2287, \"Shenzhen Oversea Win Technology Co., Ltd.\"  },\r\n    { 0x2288, \"Dt&C (Digital Technology and Certification)\"  },\r\n    { 0x2289, \"Sun Fair Electric Wire & Cable (HK) Co., Ltd.\"  },\r\n    { 0x228A, \"Hotron Precision Electronic Ind. Corp.\"  },\r\n    { 0x228B, \"Shenzhen DLK Electronics Technology Co., Ltd.\"  },\r\n    { 0x228C, \"Analogic Corporation\"  },\r\n    { 0x228D, \"8D TECHNOLOGIES INC.\"  },\r\n    { 0x228E, \"EKO Instruments Co., Ltd.\"  },\r\n    { 0x228F, \"SIGMATEK GmbH & Co. KG\"  },\r\n    { 0x2290, \"Touchplus information Corp.\"  },\r\n    { 0x2291, \"Vallen Systeme GmbH\"  },\r\n    { 0x2292, \"Global Industrial Services, Ltd.\"  },\r\n    { 0x2293, \"Berger Elektronik GmbH\"  },\r\n    { 0x2294, \"KoCo Connector AG\"  },\r\n    { 0x2295, \"Sound ID\"  },\r\n    { 0x2296, \"Musashi Engineering Company Limited\"  },\r\n    { 0x2297, \"Grain Media, Inc.\"  },\r\n    { 0x2298, \"PULSION Medical Systems AG\"  },\r\n    { 0x2299, \"BRAIN VISION SYSTEMS (BVS)\"  },\r\n    { 0x229A, \"Control Express Finland OY\"  },\r\n    { 0x229B, \"SFC Smart Fuel Cell AG\"  },\r\n    { 0x229C, \"Raytheon Company\"  },\r\n    { 0x229D, \"Solacia Inc.\"  },\r\n    { 0x229E, \"JV2R - MacWay\"  },\r\n    { 0x229F, \"RRC power solutions GmbH\"  },\r\n    { 0x22A0, \"Winpos System Co., Ltd.\"  },\r\n    { 0x22A1, \"Shenzhen Jiuzhou Electric Co., Ltd.\"  },\r\n    { 0x22A2, \"Disruptive Ltd.\"  },\r\n    { 0x22A3, \"DexCom\"  },\r\n    { 0x22A4, \"InnoComm Mobile Technology Corp.\"  },\r\n    { 0x22A5, \"Yu Jeong System Co., Ltd.\"  },\r\n    { 0x22A6, \"Pie Digital, Inc.\"  },\r\n    { 0x22A7, \"Fortinet, Inc.\"  },\r\n    { 0x22A8, \"OTTO\"  },\r\n    { 0x22A9, \"Valor Communication, Inc.\"  },\r\n    { 0x22AA, \"AppliedMicro\"  },\r\n    { 0x22AB, \"Trigence Semiconductor, Inc.\"  },\r\n    { 0x22AC, \"Sensor Switch, Inc.\"  },\r\n    { 0x22AD, \"DCP Microdevelopments Limited\"  },\r\n    { 0x22AE, \"Buerkert Werke GmbH\"  },\r\n    { 0x22AF, \"JW Fishers Mfg.\"  },\r\n    { 0x22B0, \"Business Security OL AB\"  },\r\n    { 0x22B1, \"Secret Labs LLC\"  },\r\n    { 0x22B2, \"EDGE Tech Corp.\"  },\r\n    { 0x22B3, \"SOMFY\"  },\r\n    { 0x22B4, \"NIPPON ANTENNA Co., Ltd.\"  },\r\n    { 0x22B5, \"Thyracont Vacuum Instruments GmbH\"  },\r\n    { 0x22B6, \"IMTRADEX Hoer-/Sprechsysteme GmbH\"  },\r\n    { 0x22B7, \"Unjo AB\"  },\r\n    { 0x22B8, \"Motorola Mobility Inc.\"  },\r\n    { 0x22B9, \"eTurboTouch Technology Inc.\"  },\r\n    { 0x22BA, \"Technology Innovation Holdings Ltd.\"  },\r\n    { 0x22BB, \"Saris Cycling Group\"  },\r\n    { 0x22BC, \"OPWILL Technologies (Beijing) Co., Ltd.\"  },\r\n    { 0x22BD, \"Basis Software, Inc.\"  },\r\n    { 0x22BE, \"Cheetah-Medical Ltd.\"  },\r\n    { 0x22BF, \"Bit Cauldron Corporation\"  },\r\n    { 0x22C0, \"ReLia Diagnostic Systems, Inc.\"  },\r\n    { 0x22C1, \"ATEK Products, LLC\"  },\r\n    { 0x22C2, \"Fast And Safe Technology Co., Ltd.\"  },\r\n    { 0x22C3, \"Tsinghua Tongfang Co., Ltd.\"  },\r\n    { 0x22C4, \"Fresenius Medical Care Deutschland GmbH\"  },\r\n    { 0x22C5, \"Himax Technologies, Inc.\"  },\r\n    { 0x22C6, \"Baker Hughes Production Quest\"  },\r\n    { 0x22C7, \"MEMUP\"  },\r\n    { 0x22C8, \"Shenzhen Xinerchang Electronics Co., Ltd.\"  },\r\n    { 0x22C9, \"StepOver GmbH\"  },\r\n    { 0x22CA, \"Amimon Ltd.\"  },\r\n    { 0x22CB, \"Forware Spain S.L.\"  },\r\n    { 0x22CC, \"LAONEX CO., LTD.\"  },\r\n    { 0x22CD, \"Kinova\"  },\r\n    { 0x22CE, \"Metters Industries\"  },\r\n    { 0x22CF, \"Marquess Co., Limited\"  },\r\n    { 0x22D0, \"Norsonic AS\"  },\r\n    { 0x22D1, \"ZeitControl GmbH\"  },\r\n    { 0x22D2, \"ZETT OPTICS GmbH\"  },\r\n    { 0x22D3, \"FAAC SpA\"  },\r\n    { 0x22D4, \"Laview Technology Ltd.\"  },\r\n    { 0x22D5, \"Yellow Soft Co., Ltd.\"  },\r\n    { 0x22D6, \"Numatic International Ltd.\"  },\r\n    { 0x22D7, \"IntelliTech International, Inc.\"  },\r\n    { 0x22D8, \"Shantery Co., Ltd.\"  },\r\n    { 0x22D9, \"GuangDong OPPO Mobile Telecommunications Corp., Ltd.\"  },\r\n    { 0x22DA, \"TXTR GmbH\"  },\r\n    { 0x22DB, \"Phase One A/S\"  },\r\n    { 0x22DC, \"TILERA CORPORATION\"  },\r\n    { 0x22DD, \"Kawasaki Heavy Industries, Ltd.\"  },\r\n    { 0x22DE, \"WeTelecom\"  },\r\n    { 0x22DF, \"Medicom-MTD\"  },\r\n    { 0x22E0, \"Secunet Security Networks AG\"  },\r\n    { 0x22E1, \"TempoTec Corp\"  },\r\n    { 0x22E2, \"IDEA!\"  },\r\n    { 0x22E3, \"Escort, Inc.\"  },\r\n    { 0x22E4, \"Shenyang Tongzhen Precision Electronic Technology Co.\"  },\r\n    { 0x22E5, \"Mine Safety Appliances Co.\"  },\r\n    { 0x22E6, \"Labo America, Inc.\"  },\r\n    { 0x22E7, \"ZAFFER BVBA\"  },\r\n    { 0x22E8, \"Audio Partnership\"  },\r\n    { 0x22E9, \"Orion Diagnostica OY\"  },\r\n    { 0x22EA, \"Bit Trade One, Ltd.\"  },\r\n    { 0x22EB, \"Vizimax Inc.\"  },\r\n    { 0x22EC, \"Kozio, Inc.\"  },\r\n    { 0x22ED, \"HannStar Display Corp.\"  },\r\n    { 0x22EE, \"Struers A/S\"  },\r\n    { 0x22EF, \"Edutor Technologies India Private Limited\"  },\r\n    { 0x22F0, \"Allen + Heath Ltd.\"  },\r\n    { 0x22F1, \"DATEQ BV\"  },\r\n    { 0x22F2, \"Quest Payment Systems\"  },\r\n    { 0x22F3, \"Zephyr Technology Corporation\"  },\r\n    { 0x22F4, \"Olive Global Holding Pvt. Ltd.\"  },\r\n    { 0x22F5, \"oTHE Technology Inc.\"  },\r\n    { 0x22F6, \"Clear Pulse Co., Ltd.\"  },\r\n    { 0x22F7, \"Drivven, Inc.\"  },\r\n    { 0x22F8, \"Universal Sats Ltd.\"  },\r\n    { 0x22F9, \"Compass, s.r.l.\"  },\r\n    { 0x22FA, \"Sifteo Inc.\"  },\r\n    { 0x22FB, \"Beijing Chiplight IC Design Co., Ltd.\"  },\r\n    { 0x22FC, \"ModusLink Global Solutions, Inc.\"  },\r\n    { 0x22FD, \"Miltope Corp.\"  },\r\n    { 0x22FE, \"Protium Technologies, Inc.\"  },\r\n    { 0x22FF, \"Avnet\"  },\r\n    { 0x2300, \"Nanjing Magon Opto-Electrical Science & Technology Co.\"  },\r\n    { 0x2301, \"Imaginant Inc.\"  },\r\n    { 0x2302, \"Rafael Advanced Defense Systems Ltd.\"  },\r\n    { 0x2303, \"Grosvenor Technology Ltd.\"  },\r\n    { 0x2304, \"Pinnacle\"  },\r\n    { 0x2305, \"Lindemann Audiotechnik GmbH\"  },\r\n    { 0x2306, \"Syba Multimedia, Inc.\"  },\r\n    { 0x2307, \"Madboy Audio International Oy\"  },\r\n    { 0x2308, \"UV Networks, Inc.\"  },\r\n    { 0x2309, \"TimeLink Inc.\"  },\r\n    { 0x230A, \"Data Locker Inc.\"  },\r\n    { 0x230B, \"Shanda Interactive Entertainment Limited\"  },\r\n    { 0x230C, \"GarTech Enterprises, Inc.\"  },\r\n    { 0x230D, \"Linktop Technology Co., Ltd.\"  },\r\n    { 0x230E, \"eDAQ Pty., Ltd.\"  },\r\n    { 0x230F, \"applause.elfmimi.jp\"  },\r\n    { 0x2310, \"WCE, Inc.\"  },\r\n    { 0x2311, \"Francotyp-Postalia GmbH\"  },\r\n    { 0x2312, \"Learning Curve Brands, Inc.\"  },\r\n    { 0x2313, \"Kunshan Jiahua Electronics Co., Ltd.\"  },\r\n    { 0x2314, \"INQ Mobile Limited\"  },\r\n    { 0x2315, \"Avery Design Systems, Inc.\"  },\r\n    { 0x2316, \"DongGuan Potec Electric Industrial Co., Ltd.\"  },\r\n    { 0x2317, \"Huawei Device Co., Ltd.\"  },\r\n    { 0x2318, \"Solar Components LLC\"  },\r\n    { 0x2319, \"Loewe Opta GmbH\"  },\r\n    { 0x231A, \"SANWA KAGAKU KENKYUSHO CO., LTD.\"  },\r\n    { 0x231B, \"winner story Co., Ltd.\"  },\r\n    { 0x231C, \"SONUUS LIMITED\"  },\r\n    { 0x231D, \"Fervian Technologies Limited\"  },\r\n    { 0x231E, \"Chongqing CYIT Communication Technologies Co., Ltd.\"  },\r\n    { 0x231F, \"FandF Co., Ltd.\"  },\r\n    { 0x2320, \"Redring AB\"  },\r\n    { 0x2321, \"iKingdom Corp. (d.b.a. iConnectivity)\"  },\r\n    { 0x2322, \"RichWave Technology Corp.\"  },\r\n    { 0x2323, \"EFI TECHNOLOGY s.r.l.\"  },\r\n    { 0x2324, \"Ubisense Limited\"  },\r\n    { 0x2325, \"Simbex\"  },\r\n    { 0x2326, \"CKM Electronics Co., Ltd.\"  },\r\n    { 0x2327, \"DreamSecurity\"  },\r\n    { 0x2328, \"Radio Systems Corporation\"  },\r\n    { 0x2329, \"Infinite Technologies JLT\"  },\r\n    { 0x232A, \"Skalar Analytical b.v.\"  },\r\n    { 0x232B, \"Zhuhai Pantum Technology Co., Ltd.\"  },\r\n    { 0x232C, \"Digital Lumens\"  },\r\n    { 0x232D, \"Edinburgh Instruments Ltd.\"  },\r\n    { 0x232E, \"EA, Elektro-Automatik GmbH & Co. KG\"  },\r\n    { 0x232F, \"Motic China Group Co., Ltd.\"  },\r\n    { 0x2330, \"Tensorcom, Inc.\"  },\r\n    { 0x2331, \"PUZZLE LOGIC INC.\"  },\r\n    { 0x2332, \"Coges S.p.A.\"  },\r\n    { 0x2333, \"Zamzee Co.\"  },\r\n    { 0x2334, \"Opticos srl\"  },\r\n    { 0x2335, \"Personable Inc.\"  },\r\n    { 0x2336, \"Vix Technology (Aust) Ltd.\"  },\r\n    { 0x2337, \"linked IP GmbH\"  },\r\n    { 0x2338, \"RedE Innovations\"  },\r\n    { 0x2339, \"Sierra Nevada Corporation\"  },\r\n    { 0x233A, \"Telpar\"  },\r\n    { 0x233B, \"taberna pro medicum GmbH\"  },\r\n    { 0x233C, \"Julabo\"  },\r\n    { 0x233D, \"Microtech System\"  },\r\n    { 0x233E, \"Aastra Telecom Inc.\"  },\r\n    { 0x233F, \"Stage Tec GmbH\"  },\r\n    { 0x2340, \"Teleepoch Limited\"  },\r\n    { 0x2341, \"Arduino, LLC\"  },\r\n    { 0x2342, \"nextEDGE Technology, K.K.\"  },\r\n    { 0x2343, \"AquaScan A/S\"  },\r\n    { 0x2344, \"HAMBURG INDUSTRIES CO., LTD.\"  },\r\n    { 0x2345, \"ZOWIE GEAR\"  },\r\n    { 0x2346, \"Data Transfer & Communications Ltd.\"  },\r\n    { 0x2347, \"iControl Networks\"  },\r\n    { 0x2348, \"Ubisys Technology\"  },\r\n    { 0x2349, \"P2 Engineering Group, LLC\"  },\r\n    { 0x234A, \"Cypress Technology Co., Ltd.\"  },\r\n    { 0x234B, \"Free Software Initiative of Japan\"  },\r\n    { 0x234C, \"Zenverge Inc.\"  },\r\n    { 0x234D, \"Skype Inc.\"  },\r\n    { 0x234E, \"Anewin\"  },\r\n    { 0x234F, \"VaniOs Consulting\"  },\r\n    { 0x2350, \"ZiiLABS Pte. Ltd.\"  },\r\n    { 0x2351, \"EmbCodeAB\"  },\r\n    { 0x2352, \"SKYTEX Technology Inc.\"  },\r\n    { 0x2353, \"PHiON Technology Inc.\"  },\r\n    { 0x2354, \"BirdBrain Technologies LLC\"  },\r\n    { 0x2355, \"Pacific Northwest National Laboratory (PNNL)\"  },\r\n    { 0x2356, \"Grid Connect Inc.\"  },\r\n    { 0x2357, \"TP-LINK Technologies Co., Ltd.\"  },\r\n    { 0x2358, \"Greenconn Corporation\"  },\r\n    { 0x2359, \"Shenzhen Autone-Tronic Technology Co., Ltd.\"  },\r\n    { 0x235A, \"Top Yang Technology Enterprise Co., Ltd.\"  },\r\n    { 0x235B, \"KangXiang Electronic Co., Ltd.\"  },\r\n    { 0x235C, \"Neuralieve\"  },\r\n    { 0x235D, \"Wavepod Technologies LLC\"  },\r\n    { 0x235E, \"Sage Electronic Engineering LLC\"  },\r\n    { 0x235F, \"Delux Technology Co., Ltd.\"  },\r\n    { 0x2360, \"AudioProbe Inc.\"  },\r\n    { 0x2361, \"Artiza Networks, Inc.\"  },\r\n    { 0x2362, \"Intuity Medical\"  },\r\n    { 0x2363, \"SplitFish Ltd.\"  },\r\n    { 0x2364, \"Friedrich Leutert GmbH & Co. KG\"  },\r\n    { 0x2365, \"Midwest Microwave Solutions\"  },\r\n    { 0x2366, \"Bitmanufaktur GmbH\"  },\r\n    { 0x2367, \"Teenage Engineering\"  },\r\n    { 0x2368, \"Peterson Electro-Musical Products, Inc.\"  },\r\n    { 0x2369, \"Telspan Data, LLC\"  },\r\n    { 0x236A, \"SiBEAM, Inc.\"  },\r\n    { 0x236B, \"Era Optoelectronics Inc.\"  },\r\n    { 0x236C, \"ZheJiang Chunsheng Electronics Co., Ltd.\"  },\r\n    { 0x236D, \"e-supplies Co., Ltd.\"  },\r\n    { 0x236E, \"Idex ASA\"  },\r\n    { 0x236F, \"Risun Electric Information Technology Co., Ltd.\"  },\r\n    { 0x2370, \"Vlatacom d.o.o.\"  },\r\n    { 0x2371, \"Zetron, Inc.\"  },\r\n    { 0x2372, \"Shenzhen Techaser Technologies Co., Ltd.\"  },\r\n    { 0x2373, \"Pumatronix Equipamentos Eletronicos Ltda.\"  },\r\n    { 0x2374, \"Codan Limited\"  },\r\n    { 0x2375, \"Nexell Co., Ltd.\"  },\r\n    { 0x2376, \"Realfiction Aps\"  },\r\n    { 0x2377, \"Musa srl\"  },\r\n    { 0x2378, \"OnLive, INC.\"  },\r\n    { 0x2379, \"Geotechnical Instruments (UK) Ltd.\"  },\r\n    { 0x237A, \"Danatronics, Corp.\"  },\r\n    { 0x237B, \"YUKAI Engineering\"  },\r\n    { 0x237C, \"POWERVAR\"  },\r\n    { 0x237D, \"CradlePoint, Inc.\"  },\r\n    { 0x237E, \"Ernie Ball, Inc.\"  },\r\n    { 0x237F, \"He Shan World Fair Electronics Technology Ltd.\"  },\r\n    { 0x2380, \"Law Enforcement Associates, Inc.\"  },\r\n    { 0x2381, \"IPE Music\"  },\r\n    { 0x2382, \"Trigaudio, Inc.\"  },\r\n    { 0x2383, \"Super Pioneer Co., Ltd.\"  },\r\n    { 0x2384, \"Tamara Electronics Design\"  },\r\n    { 0x2385, \"Booyco Electronics (Pty) Ltd.\"  },\r\n    { 0x2386, \"Raydium Semiconductor Corporation\"  },\r\n    { 0x2387, \"N&S Services, Inc. dba XIM Technologies\"  },\r\n    { 0x2388, \"High Density Devices\"  },\r\n    { 0x2389, \"ShenZhen Handin Tech Co., Ltd.\"  },\r\n    { 0x238A, \"ASAHI SANGYO CO., LTD.\"  },\r\n    { 0x238B, \"Hytera Communications Co., Ltd.\"  },\r\n    { 0x238C, \"Japan Care Net Service Corporation\"  },\r\n    { 0x238D, \"OMNIO Corporation\"  },\r\n    { 0x238E, \"Xtralis\"  },\r\n    { 0x238F, \"TRS Star GmbH\"  },\r\n    { 0x2390, \"Triex Technologies, Inc.\"  },\r\n    { 0x2391, \"FUKUDA CO., LTD.\"  },\r\n    { 0x2392, \"Deltatee Enterprises Ltd.\"  },\r\n    { 0x2393, \"WonATech Co., Ltd.\"  },\r\n    { 0x2394, \"J.MORITA MFG. CORP.\"  },\r\n    { 0x2395, \"CNOGA MEDICAL LTD.\"  },\r\n    { 0x2396, \"Advanced Multi Tech Pte. Ltd.\"  },\r\n    { 0x2397, \"Simaudio Ltd.\"  },\r\n    { 0x2398, \"Bluetechnix\"  },\r\n    { 0x2399, \"Lightwares\"  },\r\n    { 0x239A, \"Adafruit Industries LLC\"  },\r\n    { 0x239B, \"TZ Medical, Inc.\"  },\r\n    { 0x239C, \"Braebon Medical Corporation\"  },\r\n    { 0x239D, \"Memjet Labels, Inc.\"  },\r\n    { 0x239E, \"Rubin Informatikai Zrt.\"  },\r\n    { 0x239F, \"Nikola Engineering Inc.\"  },\r\n    { 0x23A0, \"BIFIT\"  },\r\n    { 0x23A1, \"Pepperl+Fuchs GmbH\"  },\r\n    { 0x23A2, \"Mobile Peak Holdings, Ltd.\"  },\r\n    { 0x23A3, \"Dongguan City ShengJing Electronics Co., Ltd.\"  },\r\n    { 0x23A4, \"MINGTECH CHINA CO., LTD.\"  },\r\n    { 0x23A5, \"Instytut Fotonowy Sp. Z o.o.\"  },\r\n    { 0x23A6, \"Tronical Components GmbH\"  },\r\n    { 0x23A7, \"System In Frontier Inc.\"  },\r\n    { 0x23A8, \"Sagio A/S\"  },\r\n    { 0x23A9, \"SiliconGo Microelectronics Inc.\"  },\r\n    { 0x23AA, \"DOK (HK) Trading Limited\"  },\r\n    { 0x23AB, \"SZZT ELECTRONICS CO., LTD\"  },\r\n    { 0x23AC, \"Marunix Electron Limited\"  },\r\n    { 0x23AD, \"voxeljet technology GmbH\"  },\r\n    { 0x23AE, \"DIGITAL DEVICES UG\"  },\r\n    { 0x23AF, \"iOWA AB\"  },\r\n    { 0x23B0, \"Seniorsoft Development Co., Ltd.\"  },\r\n    { 0x23B1, \"Riken Keiki Co., Ltd.\"  },\r\n    { 0x23B2, \"SEER Technology, Inc.\"  },\r\n    { 0x23B3, \"Straubtec GmbH & Co. KG\"  },\r\n    { 0x23B4, \"Dental Wings Inc.\"  },\r\n    { 0x23B5, \"Crowcon Detection Instruments Limited\"  },\r\n    { 0x23B6, \"FULL ELECTRONIC system\"  },\r\n    { 0x23B7, \"Isca Networks\"  },\r\n    { 0x23B8, \"Daruma Telecomunicacoes e Informatica S/A\"  },\r\n    { 0x23B9, \"Green Energy Options Ltd.\"  },\r\n    { 0x23BA, \"Playback Designs LLC\"  },\r\n    { 0x23BB, \"EMI STOP CORP.\"  },\r\n    { 0x23BC, \"ARIDIAN TECHNOLOGY COMPANY INC.\"  },\r\n    { 0x23BD, \"Musashi Engineering, Inc.\"  },\r\n    { 0x23BE, \"Raynet Technologies Pte. Ltd.\"  },\r\n    { 0x23BF, \"Environics Oy\"  },\r\n    { 0x23C0, \"Kotec\"  },\r\n    { 0x23C1, \"MakerBot Industries\"  },\r\n    { 0x23C2, \"CREALOGIX E-Banking AG\"  },\r\n    { 0x23C3, \"Cydle Corp.\"  },\r\n    { 0x23C4, \"Media Engineering\"  },\r\n    { 0x23C5, \"Promega Corporation\"  },\r\n    { 0x23C6, \"plawa-feinwerktechnik GmbH & Co. KG\"  },\r\n    { 0x23C7, \"GCI Technologies Corp.\"  },\r\n    { 0x23C8, \"IML Ltd.\"  },\r\n    { 0x23C9, \"IRM Touch Inc.\"  },\r\n    { 0x23CA, \"IHP GmbH Innovations for High Performance Microelectro\"  },\r\n    { 0x23CB, \"Point Core SARL\"  },\r\n    { 0x23CC, \"Avitech International Corp.\"  },\r\n    { 0x23CD, \"Avconn Precise Connector Co., Ltd.\"  },\r\n    { 0x23CE, \"Gembird Electronics Ltd.\"  },\r\n    { 0x23CF, \"Admesy BV\"  },\r\n    { 0x23D0, \"Youjie\"  },\r\n    { 0x23D1, \"LUFFT Mess-und Regeltechnik GmbH\"  },\r\n    { 0x23D2, \"WEAVERSMIND Inc.\"  },\r\n    { 0x23D3, \"RFTECH SRL\"  },\r\n    { 0x23D4, \"ALLTRAX, Inc.\"  },\r\n    { 0x23D5, \"SerialTek\"  },\r\n    { 0x23D6, \"DONGGUAN LICHENG ELECTRONICS CO., LTD.\"  },\r\n    { 0x23D7, \"PENNYWISE PERIPHERALS PTY. LTD.\"  },\r\n    { 0x23D8, \"CREATOR (CHINA) TECH CO., LTD.\"  },\r\n    { 0x23D9, \"SIGLEAD Inc.\"  },\r\n    { 0x23DA, \"THK Co., Ltd.\"  },\r\n    { 0x23DB, \"Sonicweld\"  },\r\n    { 0x23DC, \"Phonic Ear, Inc. Frontrow Division\"  },\r\n    { 0x23DD, \"Ningbo Sunny Opotech Co., Ltd.\"  },\r\n    { 0x23DE, \"ZAO Papillon\"  },\r\n    { 0x23DF, \"WebAthletics BV\"  },\r\n    { 0x23E0, \"BitifEye Digital Test Solutions GmbH\"  },\r\n    { 0x23E1, \"Vidyo, Inc.\"  },\r\n    { 0x23E2, \"Shape Medical Systems, Inc.\"  },\r\n    { 0x23E3, \"Christie Digital Systems Canada Inc.\"  },\r\n    { 0x23E4, \"General Microsystems Sdn Bhd\"  },\r\n    { 0x23E5, \"Antelope Audio\"  },\r\n    { 0x23E6, \"DIGIT MOBILE INC.\"  },\r\n    { 0x23E7, \"ROGER Dariusz Wensker Grzegorz Wensker S.P.j.\"  },\r\n    { 0x23E8, \"Propellerhead Software AB\"  },\r\n    { 0x23E9, \"Peregrine Technology Co., Ltd.\"  },\r\n    { 0x23EA, \"Inputek\"  },\r\n    { 0x23EB, \"TOPPAN FORMS CO., LTD.\"  },\r\n    { 0x23EC, \"Alacer Biomedica Industria Eletronica Ltda.\"  },\r\n    { 0x23ED, \"Optomotive, mehatronika d.o.o.\"  },\r\n    { 0x23EE, \"Sofird, Inc.\"  },\r\n    { 0x23EF, \"PPHU AWEX RAFAL STANUCH\"  },\r\n    { 0x23F0, \"Ecotronics Limited\"  },\r\n    { 0x23F1, \"WIMM Labs\"  },\r\n    { 0x23F2, \"Northern Digital Inc.\"  },\r\n    { 0x23F3, \"Funke Digital TV\"  },\r\n    { 0x23F4, \"NXT Plc\"  },\r\n    { 0x23F5, \"Speed Conn Electronics (Shenzhen) Co., Ltd.\"  },\r\n    { 0x23F6, \"Gamesman Ltd.\"  },\r\n    { 0x23F7, \"TechRhythm, Inc.\"  },\r\n    { 0x23F8, \"Xiangde Electronic Technologies (Shenzhen) Co., Ltd.\"  },\r\n    { 0x23F9, \"RT Systems (Pty) Ltd.\"  },\r\n    { 0x23FA, \"DJO, LLC\"  },\r\n    { 0x23FB, \"Janich & Klass Computertechnik GmbH\"  },\r\n    { 0x23FC, \"SesKion GmbH\"  },\r\n    { 0x23FD, \"AWare, Inc.\"  },\r\n    { 0x23FE, \"Express Way Limited\"  },\r\n    { 0x23FF, \"UIworks Electronics\"  },\r\n    { 0x2400, \"Shenzhen Chuangyitong Technology Co., Ltd\"  },\r\n    { 0x2401, \"Deltronic Labs\"  },\r\n    { 0x2402, \"DA FACT\"  },\r\n    { 0x2403, \"XTRAMUS TECHNOLOGIES\"  },\r\n    { 0x2404, \"GE MDS\"  },\r\n    { 0x2405, \"Custom Computer Services, Inc.\"  },\r\n    { 0x2406, \"WIseKey\"  },\r\n    { 0x2407, \"Incasolution Co., Ltd.\"  },\r\n    { 0x2408, \"Catalyst Enterprises, Inc.\"  },\r\n    { 0x2409, \"BCInet, Inc.\"  },\r\n    { 0x240A, \"Infron Teknolojik Sistemleri San. Ve Tic. Ltd. STI\"  },\r\n    { 0x240B, \"Kawamura Electric, Inc.\"  },\r\n    { 0x240C, \"Maples Micro System Corp\"  },\r\n    { 0x240D, \"Chinachip Technology Limited\"  },\r\n    { 0x240E, \"JEFF ROWLAND DESIGN GROUP, INC\"  },\r\n    { 0x240F, \"Trantek Electronics Co., Ltd.\"  },\r\n    { 0x2410, \"Tenebraex Corp.\"  },\r\n    { 0x2411, \"Industrial Scientific Oldham SAS\"  },\r\n    { 0x2412, \"Invision Biometrics Ltd.\"  },\r\n    { 0x2413, \"Skyviia Corporation\"  },\r\n    { 0x2414, \"Leopold Kostal GmbH & Co. KG\"  },\r\n    { 0x2415, \"CipherLab Co., Ltd.\"  },\r\n    { 0x2416, \"FUTURE DESIGNS, INC.\"  },\r\n    { 0x2417, \"INIT GmbH\"  },\r\n    { 0x2418, \"Irphotonics\"  },\r\n    { 0x2419, \"Shenzhen Dnine Technology Co., Ltd.\"  },\r\n    { 0x241A, \"The Silanna Group Pty. Ltd.\"  },\r\n    { 0x241B, \"Dongguan City Qirui Electronics Co., Ltd.\"  },\r\n    { 0x241C, \"ATMOS Medizin Technik GmbH & Co. KG\"  },\r\n    { 0x241D, \"Redbird Flight Simulations, Inc.\"  },\r\n    { 0x241E, \"SHENZHEN FUNDUN TECHNOLOGY CO., LTD.\"  },\r\n    { 0x241F, \"Global Geo Supplies, Inc.\"  },\r\n    { 0x2420, \"M Seven System Limited\"  },\r\n    { 0x2421, \"Anasphere, Inc.\"  },\r\n    { 0x2422, \"Tom Communication Industrial Co., Ltd.\"  },\r\n    { 0x2423, \"Bio-Med Devices Inc.\"  },\r\n    { 0x2424, \"CREATZ Inc.\"  },\r\n    { 0x2425, \"PIQX Imaging Pte. Ltd.\"  },\r\n    { 0x2426, \"Johnson Controls, Inc. - Building Efficiency Business\"  },\r\n    { 0x2427, \"Winkelmann UK Ltd.\"  },\r\n    { 0x2428, \"SANTEC CORPORATION\"  },\r\n    { 0x2429, \"IWSCOPE Inc.\"  },\r\n    { 0x242A, \"HUR OY\"  },\r\n    { 0x242B, \"Philips Healthcare\"  },\r\n    { 0x242C, \"ARMSTEL, Inc.\"  },\r\n    { 0x242D, \"Flastar Technology Co., Ltd.\"  },\r\n    { 0x242E, \"Vossloh-Schwabe Deutschland GmbH\"  },\r\n    { 0x242F, \"GPH Co., Ltd.\"  },\r\n    { 0x2430, \"APE GmbH\"  },\r\n    { 0x2431, \"Yamazaki Co., Ltd.\"  },\r\n    { 0x2432, \"Ceton Corp.\"  },\r\n    { 0x2433, \"Asetek A/S\"  },\r\n    { 0x2434, \"NOVA electronics, Inc.\"  },\r\n    { 0x2435, \"PAKSENSE, INC.\"  },\r\n    { 0x2436, \"MediTECH Electronic GmbH\"  },\r\n    { 0x2437, \"NIKETECH ELECTRONICS GROUP LIMITED\"  },\r\n    { 0x2438, \"Innopower Technology Corporation\"  },\r\n    { 0x2439, \"Comex Electronics AB\"  },\r\n    { 0x243A, \"Mobile Devices Ingenierie\"  },\r\n    { 0x243B, \"OTAX Electronics (ShenZhen) Co., Ltd.\"  },\r\n    { 0x243C, \"DiZiC Co., Ltd.\"  },\r\n    { 0x243D, \"emz - Hanauer GmbH & Co KGaA\"  },\r\n    { 0x243E, \"Savi Elettronica srl\"  },\r\n    { 0x243F, \"Photonic GesmbH & Co. KG\"  },\r\n    { 0x2440, \"RB GeneralEkonomik\"  },\r\n    { 0x2441, \"TV One\"  },\r\n    { 0x2442, \"University of Central Florida\"  },\r\n    { 0x2443, \"Aessent Technology Ltd.\"  },\r\n    { 0x2444, \"NetModule AG\"  },\r\n    { 0x2445, \"TOMY Company, Ltd.\"  },\r\n    { 0x2446, \"Avionics Interface Technologies\"  },\r\n    { 0x2447, \"Knick Elektronische Messgerate GmbH & Co. KG\"  },\r\n    { 0x2448, \"Winterhalter GmbH\"  },\r\n    { 0x2449, \"SHAEFER GmbH\"  },\r\n    { 0x244A, \"Onzo Ltd.\"  },\r\n    { 0x244B, \"Applied Technical Systems\"  },\r\n    { 0x244C, \"MinebeaMitsumi Inc.\"  },\r\n    { 0x244D, \"Pantec Biosolutions AG\"  },\r\n    { 0x244E, \"ShopGuard Ltd.\"  },\r\n    { 0x244F, \"iWall A/S\"  },\r\n    { 0x2450, \"Boule Medical AB\"  },\r\n    { 0x2451, \"AEM Performance Electronics\"  },\r\n    { 0x2452, \"Speeder Electronics Co., Ltd.\"  },\r\n    { 0x2453, \"BAANTO\"  },\r\n    { 0x2454, \"Velosti Technology Limited\"  },\r\n    { 0x2455, \"Anton/Bauer, Inc.\"  },\r\n    { 0x2456, \"CKD NIKKI DENSO CO., LTD\"  },\r\n    { 0x2457, \"Alcomp. Inc.\"  },\r\n    { 0x2458, \"Bluegiga Technologies Oy\"  },\r\n    { 0x2459, \"Secure Holdings Limited\"  },\r\n    { 0x245A, \"KONDOH SEISAKUSHO Co., Ltd.\"  },\r\n    { 0x245B, \"Zixsys Inc.\"  },\r\n    { 0x245C, \"Steinbauer Electronics GmbH\"  },\r\n    { 0x245D, \"ID Technologies\"  },\r\n    { 0x245E, \"LNT - Automation GmbH\"  },\r\n    { 0x245F, \"Chord Electronics Limited\"  },\r\n    { 0x2460, \"NELS, Ltd.\"  },\r\n    { 0x2461, \"Beam Communications\"  },\r\n    { 0x2462, \"IDENTICA S.A.\"  },\r\n    { 0x2463, \"BAP Precision Ltd.\"  },\r\n    { 0x2464, \"Nestlabs\"  },\r\n    { 0x2465, \"Microsoft Surface Hub\"  },\r\n    { 0x2466, \"Fractal Audio Systems, LLC\"  },\r\n    { 0x2467, \"Nektar Technology, Inc.\"  },\r\n    { 0x2468, \"New Cosmos Electric Co., Ltd.\"  },\r\n    { 0x2469, \"Gloria Music Corp.\"  },\r\n    { 0x246A, \"UNH Interoperability Laboratory\"  },\r\n    { 0x246B, \"Perfect Fortune Electric Wire & Cable (ShenZhen) Co. Ltd.\"  },\r\n    { 0x246C, \"Shanghai Fudan Microelectronics Co., Ltd.\"  },\r\n    { 0x246D, \"TrackMan A/S\"  },\r\n    { 0x246E, \"Movinto Fun AB\"  },\r\n    { 0x246F, \"STORK PRINTS AUSTRIA GmbH\"  },\r\n    { 0x2470, \"Hale Microsystems\"  },\r\n    { 0x2471, \"Bloonn Srl\"  },\r\n    { 0x2472, \"Bossa Nova Robotics, Inc.\"  },\r\n    { 0x2473, \"Trend Control Systems Limited\"  },\r\n    { 0x2474, \"Stamps.com\"  },\r\n    { 0x2475, \"JCM American Corporation\"  },\r\n    { 0x2476, \"Yost Engineering Inc.\"  },\r\n    { 0x2477, \"UbiVelox\"  },\r\n    { 0x2478, \"Sonix Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x2479, \"smartek d.o.o.\"  },\r\n    { 0x247A, \"Suzhou Jutze Technologies Co., Ltd\"  },\r\n    { 0x247B, \"Digibras Industria do Brasil S.A\"  },\r\n    { 0x247C, \"Fullconn Industry Inc.\"  },\r\n    { 0x247D, \"JARGY CO. LTD.\"  },\r\n    { 0x247E, \"GEWA music GmbH\"  },\r\n    { 0x247F, \"Lynx Studio Technology, Inc.\"  },\r\n    { 0x2480, \"Omniware Inc.\"  },\r\n    { 0x2481, \"Shenzhen SKY DRAGON Audio-Video Technology Co., Ltd.\"  },\r\n    { 0x2482, \"SmartRoom LLC\"  },\r\n    { 0x2483, \"Valups Corp.\"  },\r\n    { 0x2484, \"Unipolar Optics-Electrical Technology Co., Ltd.\"  },\r\n    { 0x2485, \"Dream SAS\"  },\r\n    { 0x2486, \"DCG Systems, Inc.\"  },\r\n    { 0x2487, \"SHANGHAI VEI SHENG AUTO PARTS MANUFACTURING CO., LTD.\"  },\r\n    { 0x2488, \"SuperD Co., Ltd.\"  },\r\n    { 0x2489, \"Irvine Sensors Corporation\"  },\r\n    { 0x248A, \"TeLink Semiconductor (Shanghai) Co., Ltd.\"  },\r\n    { 0x248B, \"DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD.\"  },\r\n    { 0x248C, \"Avicenna Instruments, LLC\"  },\r\n    { 0x248D, \"Digital Matter Pty Ltd.\"  },\r\n    { 0x248E, \"Pulsar Informatics, Inc.\"  },\r\n    { 0x248F, \"HMS Industrial Networks AB\"  },\r\n    { 0x2490, \"Zealtek electronic Co. Ltd.\"  },\r\n    { 0x2491, \"OBSERVATOR instruments b.v.\"  },\r\n    { 0x2492, \"Mofiria Corporation\"  },\r\n    { 0x2493, \"Sensolutions Inc.\"  },\r\n    { 0x2494, \"Invoxia\"  },\r\n    { 0x2495, \"Summit Semiconductor LLC\"  },\r\n    { 0x2496, \"Dongguan DaTang Industrial Investment Co., Ltd.\"  },\r\n    { 0x2497, \"HyunWoo Electronics Co., Ltd.\"  },\r\n    { 0x2498, \"Aurora SFC Systems, Inc.\"  },\r\n    { 0x2499, \"Governors America Corp.\"  },\r\n    { 0x249A, \"Anedio, LLC\"  },\r\n    { 0x249B, \"Miller Electric Mfg. Co.\"  },\r\n    { 0x249C, \"M2TECH SRL\"  },\r\n    { 0x249D, \"Ken-A-Vision Manufacturing Company, Inc.\"  },\r\n    { 0x249E, \"Tlab West Systems AB\"  },\r\n    { 0x249F, \"ABC PCB Sarl\"  },\r\n    { 0x24A0, \"VIMAR SPA\"  },\r\n    { 0x24A1, \"AUTONICS Corporation\"  },\r\n    { 0x24A2, \"SafeTech Ltd.\"  },\r\n    { 0x24A3, \"BioTillion, LLC\"  },\r\n    { 0x24A4, \"Primare AB\"  },\r\n    { 0x24A5, \"OWANDY\"  },\r\n    { 0x24A6, \"Shenzhen Pangngai Industrial Co., Ltd.\"  },\r\n    { 0x24A7, \"PROMAX ELECTRONICA S.A.\"  },\r\n    { 0x24A8, \"Hermes electronic GmbH\"  },\r\n    { 0x24A9, \"ASolid Technology Co., Ltd.\"  },\r\n    { 0x24AA, \"Wasatch Photonics\"  },\r\n    { 0x24AB, \"IMERJ LTD.\"  },\r\n    { 0x24AC, \"ToMiTec GmbH\"  },\r\n    { 0x24AD, \"embedded brains GmbH\"  },\r\n    { 0x24AE, \"Shenzhen Rapoo Technology Co., Ltd.\"  },\r\n    { 0x24AF, \"Integrated Corporation\"  },\r\n    { 0x24B0, \"Echometer Company\"  },\r\n    { 0x24B1, \"SCR Engineers Ltd.\"  },\r\n    { 0x24B2, \"DelSys Inc.\"  },\r\n    { 0x24B3, \"Simbionix Ltd.\"  },\r\n    { 0x24B4, \"Leema Acoustics\"  },\r\n    { 0x24B5, \"3C TEK CORP.\"  },\r\n    { 0x24B6, \"Shenzhen New-Conn International Co., Ltd.\"  },\r\n    { 0x24B7, \"Medical Equipment Europe GmbH\"  },\r\n    { 0x24B8, \"DongGuan CJ TOUCH Electronic Co., Ltd.\"  },\r\n    { 0x24B9, \"Hoshin Electronics Co., Ltd.\"  },\r\n    { 0x24BA, \"PRADOTEC Corporation Sdn. Bhd.\"  },\r\n    { 0x24BB, \"SHANGHAI LIGHTSURFING INFORMATION TECHNOLOGY CO., LTD.\"  },\r\n    { 0x24BC, \"Sartorius AG\"  },\r\n    { 0x24BD, \"Smart Solution\"  },\r\n    { 0x24BE, \"Mutewatch AB\"  },\r\n    { 0x24BF, \"NBS Payment Solutions, Inc.\"  },\r\n    { 0x24C0, \"Chaney Instrument Co.\"  },\r\n    { 0x24C1, \"Maction Technologies, Inc.\"  },\r\n    { 0x24C2, \"DiCon Fiberoptics, Inc.\"  },\r\n    { 0x24C3, \"Covaris, Inc.\"  },\r\n    { 0x24C4, \"CMITECH Co., Ltd.\"  },\r\n    { 0x24C5, \"HUINTECH\"  },\r\n    { 0x24C6, \"Xbox 3rd Party Partners\"  },\r\n    { 0x24C7, \"Laser Technology, Inc.\"  },\r\n    { 0x24C8, \"CHAPP INC.\"  },\r\n    { 0x24C9, \"Pilot Electronic (China) Ltd.\"  },\r\n    { 0x24CA, \"SMARTEH d.o.o.\"  },\r\n    { 0x24CB, \"Servotronix Motion Control Ltd.\"  },\r\n    { 0x24CC, \"JSB Tech Pte. Ltd.\"  },\r\n    { 0x24CD, \"Viking360.com LLC\"  },\r\n    { 0x24CE, \"Shenzhen Deren Electronic Co., Ltd.\"  },\r\n    { 0x24CF, \"Lytro, Inc.\"  },\r\n    { 0x24D0, \"Smith Micro Software, Inc.\"  },\r\n    { 0x24D1, \"POS & Solution Company\"  },\r\n    { 0x24D2, \"DADT Holdings, LLC\"  },\r\n    { 0x24D3, \"Lexking Technology Co., Ltd.\"  },\r\n    { 0x24D4, \"KOMATSU ELECTRONIC CO., LTD.\"  },\r\n    { 0x24D5, \"SATEL Ltd.\"  },\r\n    { 0x24D6, \"Develer S.r.l.\"  },\r\n    { 0x24D7, \"ACORDE TECHNOLOGIES\"  },\r\n    { 0x24D8, \"Pittway Tecnologica Srl\"  },\r\n    { 0x24D9, \"Unfors Instruments AB\"  },\r\n    { 0x24DA, \"KYOCERA ELCO Korea Co., Ltd.\"  },\r\n    { 0x24DB, \"DDUSB Technology\"  },\r\n    { 0x24DC, \"Aladdin Software Security R.D.\"  },\r\n    { 0x24DD, \"Kingspan Environmental Ltd.\"  },\r\n    { 0x24DE, \"Navicron\"  },\r\n    { 0x24DF, \"ALGO System. Co\"  },\r\n    { 0x24E0, \"Yoctopuce Sarl\"  },\r\n    { 0x24E1, \"Paratronic S.A.\"  },\r\n    { 0x24E2, \"Digital Information Technology Studies (Shenzhen) Ltd.\"  },\r\n    { 0x24E3, \"Beijing TianYu Communication Equipment Co., Ltd.\"  },\r\n    { 0x24E4, \"Bytec Group Limited\"  },\r\n    { 0x24E5, \"Lanmark Controls Inc.\"  },\r\n    { 0x24E6, \"ACI Analytical Control Instruments GmbH\"  },\r\n    { 0x24E7, \"maxon motor ag\"  },\r\n    { 0x24E8, \"ivee\"  },\r\n    { 0x24E9, \"Microelectronics Technology Inc.\"  },\r\n    { 0x24EA, \"ZEBEX INDUSTRIES INC.\"  },\r\n    { 0x24EB, \"SHENZHEN PCTX TECHNOLOGY DEVELOPMENT CO., LTD.\"  },\r\n    { 0x24EC, \"CE-Infosys GmbH\"  },\r\n    { 0x24ED, \"ZEN FACTORY GROUP (ASIA) LTD.\"  },\r\n    { 0x24EE, \"A C S Co., Ltd.\"  },\r\n    { 0x24EF, \"DATONG PLC\"  },\r\n    { 0x24F0, \"Das Keyboard - Metadot\"  },\r\n    { 0x24F1, \"Silicon Communication Technology\"  },\r\n    { 0x24F2, \"Secure Electrans LTD.\"  },\r\n    { 0x24F3, \"MartinLogan Ltd.\"  },\r\n    { 0x24F4, \"Mind Media BV\"  },\r\n    { 0x24F5, \"QRS Diagnostic\"  },\r\n    { 0x24F6, \"Aplix IP Holdings Corporation\"  },\r\n    { 0x24F7, \"Seneye Ltd.\"  },\r\n    { 0x24F8, \"Bang & Olufsen A/S\"  },\r\n    { 0x24F9, \"TOSHIBA MITSUBISHI-ELECTRIC INDUSTRIAL SYSTEMS CORP.\"  },\r\n    { 0x24FA, \"Vectronix AG\"  },\r\n    { 0x24FB, \"GTECH Corporation\"  },\r\n    { 0x24FC, \"GPEG International\"  },\r\n    { 0x24FD, \"Nichiyu Giken Kogyo Co., Ltd.\"  },\r\n    { 0x24FE, \"GOMETRICS, S.L.\"  },\r\n    { 0x24FF, \"Acroname Inc.\"  },\r\n    { 0x2500, \"Ettus Research LLC\"  },\r\n    { 0x2501, \"Bridge Publications, Inc.\"  },\r\n    { 0x2502, \"Canadian Automotive Instruments Ltd.\"  },\r\n    { 0x2503, \"Kurth Electronic GmbH\"  },\r\n    { 0x2504, \"Nemic Lambda Ltd.\"  },\r\n    { 0x2505, \"Xiroku Accupoint Technology Inc.\"  },\r\n    { 0x2506, \"Hind Technology Group\"  },\r\n    { 0x2507, \"Advion BioSystems\"  },\r\n    { 0x2508, \"Symplex Communications, Inc.\"  },\r\n    { 0x2509, \"Chain-In Electronic Co., Ltd.\"  },\r\n    { 0x250A, \"H-Squared\"  },\r\n    { 0x250B, \"Nautilus Lifeline Ltd.\"  },\r\n    { 0x250C, \"PHX Inc.\"  },\r\n    { 0x250D, \"Alstom Grid SAS\"  },\r\n    { 0x250E, \"Beijing MOPS Technology Co., Ltd.\"  },\r\n    { 0x250F, \"itplants ltd.\"  },\r\n    { 0x2510, \"SE Elektronische Systeme\"  },\r\n    { 0x2511, \"Morita Tech Co., Ltd.\"  },\r\n    { 0x2512, \"RNDPLUS Co., Ltd.\"  },\r\n    { 0x2513, \"RMI Laser, LLC\"  },\r\n    { 0x2514, \"Fullpower Technologies\"  },\r\n    { 0x2515, \"AMITEK\"  },\r\n    { 0x2516, \"Cooler Master Co., Ltd.\"  },\r\n    { 0x2517, \"Marel EHF\"  },\r\n    { 0x2518, \"Anite Telecoms Inc.\"  },\r\n    { 0x2519, \"n-gineric gmbh\"  },\r\n    { 0x251A, \"Daiichi Electronics\"  },\r\n    { 0x251B, \"Stable Imaging Solutions, LLC\"  },\r\n    { 0x251C, \"snom technology AG\"  },\r\n    { 0x251D, \"Fortebio Inc.\"  },\r\n    { 0x251E, \"Polara Engineering, Inc.\"  },\r\n    { 0x251F, \"Golden Emperor International Ltd.\"  },\r\n    { 0x2520, \"ANA-U GmbH\"  },\r\n    { 0x2521, \"Fundacion Tekniker\"  },\r\n    { 0x2522, \"Light Harmonic\"  },\r\n    { 0x2523, \"Recon Instruments Inc.\"  },\r\n    { 0x2524, \"CVRx\"  },\r\n    { 0x2525, \"Barron McCann Technology Ltd.\"  },\r\n    { 0x2526, \"Weide Electronics Co., Ltd.\"  },\r\n    { 0x2527, \"Software Bisque, Inc.\"  },\r\n    { 0x2528, \"BittWare Inc.\"  },\r\n    { 0x2529, \"SUZHOU XINYA ELECTRIC COMMUNICATION CO., LTD.\"  },\r\n    { 0x252A, \"SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD.\"  },\r\n    { 0x252B, \"TOP Exactitude Industry (ShenZhen) Co., Ltd.\"  },\r\n    { 0x252C, \"VIGO System S.A.\"  },\r\n    { 0x252D, \"Nokia Siemens Networks\"  },\r\n    { 0x252E, \"Heliox Technologies, Inc.\"  },\r\n    { 0x252F, \"Pentronic AB\"  },\r\n    { 0x2530, \"STT Emtec AB\"  },\r\n    { 0x2531, \"Proteus Industries Inc.\"  },\r\n    { 0x2532, \"C.R.D.E. (Cahors Group)\"  },\r\n    { 0x2533, \"Osaka Micro Computer, Inc.\"  },\r\n    { 0x2534, \"Russia's Institute of Radionavigation and Time\"  },\r\n    { 0x2535, \"ShenZhen Hogend Precision Technology Co., Ltd.\"  },\r\n    { 0x2536, \"Ubisys Technology Co., Ltd.\"  },\r\n    { 0x2537, \"Norel Systems Ltd.\"  },\r\n    { 0x2538, \"Cochlear Ltd.\"  },\r\n    { 0x2539, \"Club Electronics\"  },\r\n    { 0x253A, \"System Sacom Industry Corporation\"  },\r\n    { 0x253B, \"RCF S.p.a.\"  },\r\n    { 0x253C, \"Tri-Tech Manufacturing Inc.\"  },\r\n    { 0x253D, \"Koss Corporation\"  },\r\n    { 0x253E, \"Creative Product Design Pty., Ltd.\"  },\r\n    { 0x253F, \"ORANGE IT INC.\"  },\r\n    { 0x2540, \"Applied Materials\"  },\r\n    { 0x2541, \"Shanghai AisinoChip Electronics Technology Co., Ltd.\"  },\r\n    { 0x2542, \"Ditron S.R.L.\"  },\r\n    { 0x2543, \"Spark Dental Technology Limited\"  },\r\n    { 0x2544, \"Energy Micro AS\"  },\r\n    { 0x2545, \"Digital Foci, Inc.\"  },\r\n    { 0x2546, \"Ravensburger Spieleverlag GmbH\"  },\r\n    { 0x2547, \"YiDu Technology\"  },\r\n    { 0x2548, \"Pulse-Eight Limited\"  },\r\n    { 0x2549, \"Librestream Technologies\"  },\r\n    { 0x254A, \"Enegate Co., Ltd.\"  },\r\n    { 0x254B, \"Toy Toy Toy Ltd.\"  },\r\n    { 0x254C, \"X6D Limited\"  },\r\n    { 0x254D, \"ICAR VISION SYSTEMS S.L.\"  },\r\n    { 0x254E, \"SHF Communication Technologies AG\"  },\r\n    { 0x254F, \"Jigeon Technologies Co., Ltd.\"  },\r\n    { 0x2550, \"Teledyne\"  },\r\n    { 0x2551, \"A.E.B. Industriale S.r.l.\"  },\r\n    { 0x2552, \"Striiv, Inc.\"  },\r\n    { 0x2553, \"C8 MediSensor\"  },\r\n    { 0x2554, \"ASSA ABLOY AB\"  },\r\n    { 0x2555, \"Pulse Tracer, Inc.\"  },\r\n    { 0x2556, \"United Radio-Electronic Technologies Co., Ltd.\"  },\r\n    { 0x2557, \"Robatech AG\"  },\r\n    { 0x2558, \"INTECH ELECTRONICS CORP.\"  },\r\n    { 0x2559, \"Jangus Music, Inc. (dba Wi Digital Systems)\"  },\r\n    { 0x255A, \"TaiDoc Technology Corp.\"  },\r\n    { 0x255B, \"NDI Technologies, Inc.\"  },\r\n    { 0x255C, \"HOSIWELL TECHNOLOGY CO., LTD.\"  },\r\n    { 0x255D, \"ATEECS\"  },\r\n    { 0x255E, \"Beijing Bonxeon Technology Co., Ltd.\"  },\r\n    { 0x255F, \"DORNIER-LTF GmbH\"  },\r\n    { 0x2560, \"e-con Systems India Private Limited\"  },\r\n    { 0x2561, \"Brookhaven Instruments Corp.\"  },\r\n    { 0x2562, \"SHENGZHEN MAYA ELECTRONICS CREATION CO. LTD.\"  },\r\n    { 0x2563, \"Shenzhen ShanWan Technology Co., Ltd.\"  },\r\n    { 0x2564, \"TESSERA TECHNOLOGY INC.\"  },\r\n    { 0x2565, \"Cyclone Industries Limited\"  },\r\n    { 0x2566, \"Cryptera A/S\"  },\r\n    { 0x2567, \"DongGuan LongTao Electronic Co., Ltd.\"  },\r\n    { 0x2568, \"ALL LINK CONN. TECHNOLOGY CORP.\"  },\r\n    { 0x2569, \"DongGuan City MingJi Electronics Co., Ltd.\"  },\r\n    { 0x256A, \"TAIAN TECHNOLOGY (WUXI) Co., Ltd.\"  },\r\n    { 0x256B, \"Perreaux Industries Ltd.\"  },\r\n    { 0x256C, \"GRAPHICS TECHNOLOGY (HK) CO., LIMITED\"  },\r\n    { 0x256D, \"Compal Broadband Networks, Inc.\"  },\r\n    { 0x256E, \"Valuest Co., Ltd.\"  },\r\n    { 0x256F, \"3D CONNEXION SAM\"  },\r\n    { 0x2570, \"AVID Technologies, Inc.\"  },\r\n    { 0x2571, \"CHIPMAST TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2572, \"Vmarker\"  },\r\n    { 0x2573, \"ESI Audiotechnik GmbH\"  },\r\n    { 0x2574, \"AVer Information Inc.\"  },\r\n    { 0x2575, \"Weida Hi-Tech Co., Ltd.\"  },\r\n    { 0x2576, \"AFO Co., Ltd.\"  },\r\n    { 0x2577, \"LCDVF LLC\"  },\r\n    { 0x2578, \"MPEC Technology Limited\"  },\r\n    { 0x2579, \"Dongguan Wisechamp Electronic Co., Ltd.\"  },\r\n    { 0x257A, \"Shanghai Yuga Information Technology Co., Ltd.\"  },\r\n    { 0x257B, \"shenzhen dcard smart card tech. co., ltd.\"  },\r\n    { 0x257C, \"Richard Woehr GmbH\"  },\r\n    { 0x257D, \"Panovel Technology Corporation\"  },\r\n    { 0x257E, \"RFL Electronics Inc.\"  },\r\n    { 0x257F, \"8devices\"  },\r\n    { 0x2580, \"DJ Techtools (Golden Sol Music LLC. Is Holding Co.)\"  },\r\n    { 0x2581, \"Plug-up\"  },\r\n    { 0x2582, \"Helmholz GmbH & Co. KG\"  },\r\n    { 0x2583, \"VECTRUX DISTRIBUTORS LLC\"  },\r\n    { 0x2584, \"COSMO CO., LTD.\"  },\r\n    { 0x2585, \"HomeChip Ltd.\"  },\r\n    { 0x2586, \"PLANET Technology Corporation\"  },\r\n    { 0x2587, \"Ningbo Jiatang Electronic Co., Ltd.\"  },\r\n    { 0x2588, \"Infinitegra, Inc.\"  },\r\n    { 0x2589, \"Argon Technology Corporation\"  },\r\n    { 0x258A, \"Sino Wealth Electronic Ltd.\"  },\r\n    { 0x258B, \"KORYO ELECTRONICS CO., LTD.\"  },\r\n    { 0x258C, \"Fastec Imaging Corporation\"  },\r\n    { 0x258D, \"Sequans Communications\"  },\r\n    { 0x258E, \"ENJsoft Co., Ltd.\"  },\r\n    { 0x258F, \"CME\"  },\r\n    { 0x2590, \"MuChip Co., Ltd.\"  },\r\n    { 0x2591, \"Optimus Semiconductor Inc.\"  },\r\n    { 0x2592, \"Quest International\"  },\r\n    { 0x2593, \"CELIZION, Inc.\"  },\r\n    { 0x2594, \"Acsys Technologies Ltd.\"  },\r\n    { 0x2595, \"SANYO DENKI CO., LTD.\"  },\r\n    { 0x2596, \"Twisted Melon Inc.\"  },\r\n    { 0x2597, \"Diagnostic Systems Associates Inc.\"  },\r\n    { 0x2598, \"Aerocrine\"  },\r\n    { 0x2599, \"Q-tag AG\"  },\r\n    { 0x259A, \"TriQuint Semiconductor\"  },\r\n    { 0x259B, \"INUVIO\"  },\r\n    { 0x259C, \"Immedia Semiconductor Inc.\"  },\r\n    { 0x259D, \"RCA DA AMAZONIA LTDA\"  },\r\n    { 0x259E, \"American Messaging Services LLC\"  },\r\n    { 0x259F, \"THERMO KING\"  },\r\n    { 0x25A0, \"Ciegus Ltd.\"  },\r\n    { 0x25A1, \"Suitable Technologies, Inc.\"  },\r\n    { 0x25A2, \"LEMKE ENG.\"  },\r\n    { 0x25A3, \"Nanoteq (Pty) Ltd.\"  },\r\n    { 0x25A4, \"ALGOLTEK, INC.\"  },\r\n    { 0x25A5, \"Yakel Enterprises LLC\"  },\r\n    { 0x25A6, \"AADI AS\"  },\r\n    { 0x25A7, \"Beken Corporation\"  },\r\n    { 0x25A8, \"Guangzhou Geoelectron Science & Technology Co., Ltd.\"  },\r\n    { 0x25A9, \"Advanced Bionics\"  },\r\n    { 0x25AA, \"Top Victory Investments Ltd. (HK)\"  },\r\n    { 0x25AB, \"Carmanah Signs\"  },\r\n    { 0x25AC, \"PLIGG\"  },\r\n    { 0x25AD, \"Aurora Networks, Inc.\"  },\r\n    { 0x25AE, \"OXIPULSE\"  },\r\n    { 0x25AF, \"C&A Marketing\"  },\r\n    { 0x25B0, \"Musical Fidelity\"  },\r\n    { 0x25B1, \"Disc Soft Ltd.\"  },\r\n    { 0x25B2, \"DRS-RSTA, Inc.\"  },\r\n    { 0x25B3, \"DongGuan Elinke Industrial Co., Ltd.\"  },\r\n    { 0x25B4, \"Fairhaven Health\"  },\r\n    { 0x25B5, \"FlatFrog Laboratories AB\"  },\r\n    { 0x25B6, \"Fructel AB\"  },\r\n    { 0x25B7, \"Neomitic Technologies S.A. de C.V.\"  },\r\n    { 0x25B8, \"Neutronics Inc.\"  },\r\n    { 0x25B9, \"Nujira Ltd.\"  },\r\n    { 0x25BA, \"WITec Wissenschaftliche Instrumente & Technologie GmbH\"  },\r\n    { 0x25BB, \"Brunner Elektronik AG\"  },\r\n    { 0x25BC, \"CETRTA POT\"  },\r\n    { 0x25BD, \"TECHEYE SYSTEMS INC.\"  },\r\n    { 0x25BE, \"Infinite Z\"  },\r\n    { 0x25BF, \"Elegant Invention\"  },\r\n    { 0x25C0, \"Beyond Music Industrial Co., Ltd.\"  },\r\n    { 0x25C1, \"Vaddio\"  },\r\n    { 0x25C2, \"Smith + Nephew Inc.\"  },\r\n    { 0x25C3, \"Phorus\"  },\r\n    { 0x25C4, \"A & R Cambridge Ltd.\"  },\r\n    { 0x25C5, \"Securetec Detektions Systeme AG\"  },\r\n    { 0x25C6, \"AVA Group A/S\"  },\r\n    { 0x25C7, \"MEGATRON Elektronik AG & Co.\"  },\r\n    { 0x25C8, \"Visualplanet Ltd.\"  },\r\n    { 0x25C9, \"Proximiant\"  },\r\n    { 0x25CA, \"Hovding Sverige AB\"  },\r\n    { 0x25CB, \"ELZET80 Mikrocomputer Giesler & Danne GmbH & Co. KG\"  },\r\n    { 0x25CC, \"NKC Co., Ltd.\"  },\r\n    { 0x25CD, \"Edwards Ltd.\"  },\r\n    { 0x25CE, \"MYTEK DIGITAL\"  },\r\n    { 0x25CF, \"Corning Optical Communications LLC\"  },\r\n    { 0x25D0, \"AeVee Laboratories LLC\"  },\r\n    { 0x25D1, \"TOKAI-DENSHI Inc.\"  },\r\n    { 0x25D2, \"MRA Tek LLC\"  },\r\n    { 0x25D3, \"Zhe Jiang Huasheng Technology Co., Ltd.\"  },\r\n    { 0x25D4, \"LOOPCOMM TECHNOLOGY, INC.\"  },\r\n    { 0x25D5, \"DATATON AB\"  },\r\n    { 0x25D6, \"KOUZIRO Co., Ltd.\"  },\r\n    { 0x25D7, \"Audiomatica srl\"  },\r\n    { 0x25D8, \"Serious Integrated, Inc.\"  },\r\n    { 0x25D9, \"Monarch Innovative Technologies Pvt. Ltd.\"  },\r\n    { 0x25DA, \"NETATMO\"  },\r\n    { 0x25DB, \"Merrick Industries, Inc.\"  },\r\n    { 0x25DC, \"Cobolt AB\"  },\r\n    { 0x25DD, \"bit4id srl\"  },\r\n    { 0x25DE, \"Gasmet Technologies OY\"  },\r\n    { 0x25DF, \"TTE Systems Ltd.\"  },\r\n    { 0x25E0, \"MULTIPLEX Modellsport GmbH & Co. KG\"  },\r\n    { 0x25E1, \"Daimler AG\"  },\r\n    { 0x25E2, \"Domain Surgical\"  },\r\n    { 0x25E3, \"SCI Innovations Ltd.\"  },\r\n    { 0x25E4, \"AnaJet\"  },\r\n    { 0x25E5, \"ALLFLEX EUROPE\"  },\r\n    { 0x25E6, \"Digital Drilling Data Systems, LLC\"  },\r\n    { 0x25E7, \"EIFELWERK Butler Systeme GmbH\"  },\r\n    { 0x25E8, \"ATOLL Electronique\"  },\r\n    { 0x25E9, \"Leybold Vacuum\"  },\r\n    { 0x25EA, \"Aeroflex Weinschel\"  },\r\n    { 0x25EB, \"Medical Intubation Technology Corp.\"  },\r\n    { 0x25EC, \"VELUX A/S\"  },\r\n    { 0x25ED, \"Logic PD\"  },\r\n    { 0x25EE, \"Mimoco\"  },\r\n    { 0x25EF, \"BLITZ Co., Ltd.\"  },\r\n    { 0x25F0, \"GOODBETTERBEST Ltd.\"  },\r\n    { 0x25F1, \"Eden Innovations\"  },\r\n    { 0x25F2, \"Dongguan Jinyue Electronics Co., Ltd.\"  },\r\n    { 0x25F3, \"Kicker\"  },\r\n    { 0x25F4, \"ADVANSEE\"  },\r\n    { 0x25F5, \"Lucas Holding bv\"  },\r\n    { 0x25F6, \"SaferZone Co., Ltd.\"  },\r\n    { 0x25F7, \"Engineea Remote Technologies S.L.\"  },\r\n    { 0x25F8, \"Keypair Co., Ltd.\"  },\r\n    { 0x25F9, \"Donbass Soft Ltd. & Co. KG\"  },\r\n    { 0x25FA, \"SoftEther Corporation\"  },\r\n    { 0x25FB, \"RICOH IMAGING COMPANY, LTD.\"  },\r\n    { 0x25FC, \"RWA (Hong Kong) Limited\"  },\r\n    { 0x25FD, \"Neuromonics Inc.\"  },\r\n    { 0x25FE, \"Providence Enterprise Limited\"  },\r\n    { 0x25FF, \"Watermark Medical, Inc.\"  },\r\n    { 0x2600, \"SMARTCORE Inc.\"  },\r\n    { 0x2601, \"OFI Testing Equipment, Inc.\"  },\r\n    { 0x2602, \"Magenta Research Ltd.\"  },\r\n    { 0x2603, \"Swyx Solutions AG\"  },\r\n    { 0x2604, \"Shenzhen Tenda Technology, Ltd.\"  },\r\n    { 0x2605, \"OSRAM SYLVANIA\"  },\r\n    { 0x2606, \"O-Network Engineering AB\"  },\r\n    { 0x2607, \"Prox Dynamics AS\"  },\r\n    { 0x2608, \"OLHO tronic GmbH\"  },\r\n    { 0x2609, \"FICOSA\"  },\r\n    { 0x260A, \"SPEMOT AG\"  },\r\n    { 0x260B, \"Schneider Electric Canada Inc. - Division of PCT\"  },\r\n    { 0x260C, \"Saiko Systems Ltd.\"  },\r\n    { 0x260D, \"DongGuan Togran Electronic Co., Ltd.\"  },\r\n    { 0x260E, \"DongGuan HYX Industrial Co., Ltd.\"  },\r\n    { 0x260F, \"VITY\"  },\r\n    { 0x2610, \"Egan Teamboard Inc.\"  },\r\n    { 0x2611, \"I.C.E. Co., Ltd.\"  },\r\n    { 0x2612, \"Crave Innovations\"  },\r\n    { 0x2613, \"Gerd Bar GmbH\"  },\r\n    { 0x2614, \"VMC Consulting Corporation\"  },\r\n    { 0x2615, \"Gammaflux L.P.\"  },\r\n    { 0x2616, \"PS Audio\"  },\r\n    { 0x2617, \"Front-End Technology, Inc.\"  },\r\n    { 0x2618, \"MicroGate Systems Ltd.\"  },\r\n    { 0x2619, \"Advanced Silicon SA\"  },\r\n    { 0x261A, \"Shandong Synthesis Electronic Technology Co., Ltd.\"  },\r\n    { 0x261B, \"INTELLIGENT ENERGY, LTD.\"  },\r\n    { 0x261C, \"EISST Limited\"  },\r\n    { 0x261D, \"Arkham Technology\"  },\r\n    { 0x261E, \"IFAM GmbH Erfurt\"  },\r\n    { 0x261F, \"Cooper Industries\"  },\r\n    { 0x2620, \"SUE unicon.uz Scientific, Engineering & Marketing RC\"  },\r\n    { 0x2621, \"CLIXUP LLC\"  },\r\n    { 0x2622, \"IAG Group Limited\"  },\r\n    { 0x2623, \"SGR Audio Pty Ltd.\"  },\r\n    { 0x2624, \"L-3 Communications - Communications Systems West\"  },\r\n    { 0x2625, \"MilDef AB\"  },\r\n    { 0x2626, \"Aruba Networks\"  },\r\n    { 0x2627, \"Vectron Systems AG\"  },\r\n    { 0x2628, \"TEN-TEC, INC.\"  },\r\n    { 0x2629, \"Winstars Technology Limited\"  },\r\n    { 0x262A, \"SAVITECH CORP.\"  },\r\n    { 0x262B, \"YTOP Electronics Technical (Kunshan) Co., Ltd.\"  },\r\n    { 0x262C, \"Scannx\"  },\r\n    { 0x262D, \"Fujian Witsi Microelectronics Technology Co., Ltd.\"  },\r\n    { 0x262E, \"UNITEX Corporation\"  },\r\n    { 0x262F, \"MELAG Medizintechnik oHG\"  },\r\n    { 0x2630, \"ifm electronic gmbh\"  },\r\n    { 0x2631, \"NEOPROT TECNOLOGIA EM INFORMATICA LTDA.\"  },\r\n    { 0x2632, \"ENSPERT Inc.\"  },\r\n    { 0x2633, \"Inno Audio & Video (HK) Limited\"  },\r\n    { 0x2634, \"E.M.S. S.R.L.\"  },\r\n    { 0x2635, \"uHDevice Technology Ltd.\"  },\r\n    { 0x2636, \"MED-EL Medical Electronics\"  },\r\n    { 0x2637, \"TAEWOONG MEDICAL. CO., LTD.\"  },\r\n    { 0x2638, \"Becker-Antriebe GmbH\"  },\r\n    { 0x2639, \"Xsens Technologies B.V.\"  },\r\n    { 0x263A, \"Maury Microwave\"  },\r\n    { 0x263B, \"Time & Data Systems International Ltd.\"  },\r\n    { 0x263C, \"Schultes Microcomputer-Vertriebs-GmbH & Co KG\"  },\r\n    { 0x263D, \"pls Programmierbare Logik & Systeme GmbH\"  },\r\n    { 0x263E, \"Odin TeleSystems Inc.\"  },\r\n    { 0x263F, \"ES-Experts, Ltd.\"  },\r\n    { 0x2640, \"Banner Engineering\"  },\r\n    { 0x2641, \"PRO TUNE ELECTRONIC SYSTEMS\"  },\r\n    { 0x2642, \"NPP ELIKS America Inc. DBA T&M Atlantic\"  },\r\n    { 0x2643, \"COMVOX AUDIO CO., LTD.\"  },\r\n    { 0x2644, \"Sioux Electronics B.V.\"  },\r\n    { 0x2645, \"Lead Data Inc.\"  },\r\n    { 0x2646, \"Bel Canto Design, Ltd.\"  },\r\n    { 0x2647, \"FORMER ENGINEERING SERVICE CO., LTD.\"  },\r\n    { 0x2648, \"Telongo LLC\"  },\r\n    { 0x2649, \"Soundspring Audio, Inc\"  },\r\n    { 0x264A, \"THERMALTAKE Technology Co., Ltd.\"  },\r\n    { 0x264B, \"Industrial Indexing Systems\"  },\r\n    { 0x264C, \"Si14 SpA\"  },\r\n    { 0x264D, \"Wolfrum Elektronik & Avionik\"  },\r\n    { 0x264E, \"3i Corporation\"  },\r\n    { 0x264F, \"RF Controls, LLC\"  },\r\n    { 0x2650, \"Electronics For Imaging, Inc.\"  },\r\n    { 0x2651, \"Otis Instruments Inc.\"  },\r\n    { 0x2652, \"Fallbrook Technologies, Inc.\"  },\r\n    { 0x2653, \"AutoHotBox\"  },\r\n    { 0x2654, \"DarklingX, LLC\"  },\r\n    { 0x2655, \"Moog Inc.\"  },\r\n    { 0x2656, \"Ashcroft Inc.\"  },\r\n    { 0x2657, \"Embedia Technologies Corporation\"  },\r\n    { 0x2658, \"Sintermask GmbH\"  },\r\n    { 0x2659, \"Sundtek\"  },\r\n    { 0x265A, \"3Brain GmbH\"  },\r\n    { 0x265B, \"D-tect Systems\"  },\r\n    { 0x265C, \"IDEX Health + Science LLC\"  },\r\n    { 0x265D, \"H. Schomaecker GmbH\"  },\r\n    { 0x265E, \"JSC Engineering Centre Energoservice\"  },\r\n    { 0x265F, \"Azatrax\"  },\r\n    { 0x2660, \"YEONG DER (SUM-EM) Enterprises Co., Ltd.\"  },\r\n    { 0x2661, \"WorldCast Systems\"  },\r\n    { 0x2662, \"MOOG Music Inc.\"  },\r\n    { 0x2663, \"JOMESA Messsysteme GmbH\"  },\r\n    { 0x2664, \"NOHMI BOSAI Ltd.\"  },\r\n    { 0x2665, \"Yamaki Electric Corporation\"  },\r\n    { 0x2666, \"BLX IC Design Corp., Ltd.\"  },\r\n    { 0x2667, \"SuZhou ZhongXingLian Precision Industrial Co., Ltd.\"  },\r\n    { 0x2668, \"Shenzhen Yuwenfa Electronic Technology Co., Ltd.\"  },\r\n    { 0x2669, \"ME4SURE, Inc.\"  },\r\n    { 0x266A, \"Linear LLC\"  },\r\n    { 0x266B, \"ProSys Development Services\"  },\r\n    { 0x266C, \"Brightsight BV\"  },\r\n    { 0x266D, \"Ergotest Innovation A.S.\"  },\r\n    { 0x266E, \"Multimedia Link, Inc.\"  },\r\n    { 0x266F, \"Shanghai Zhengyuan Technologies Co., Ltd.\"  },\r\n    { 0x2670, \"Zhengzhou Xin Da Jie An Information Technology Co., Ltd\"  },\r\n    { 0x2671, \"Innovative Logic\"  },\r\n    { 0x2672, \"GoPro\"  },\r\n    { 0x2673, \"Wadia Digital\"  },\r\n    { 0x2674, \"Hoyt Monitor Technologies, LLC\"  },\r\n    { 0x2675, \"Peter Huber Kaeltemaschinenbau GmbH\"  },\r\n    { 0x2676, \"Basler AG\"  },\r\n    { 0x2677, \"Winegard Company\"  },\r\n    { 0x2678, \"Sky Deutschland GmbH & Co. KG\"  },\r\n    { 0x2679, \"BESTMEDIA CD-Recordable GmbH & Co. KG\"  },\r\n    { 0x267A, \"Xi'an YEP Telecommunication Technology Co., Ltd.\"  },\r\n    { 0x267B, \"Palpilot International Corp.\"  },\r\n    { 0x267C, \"OptiGene Limited\"  },\r\n    { 0x267D, \"KOHZU Precision Co., Ltd.\"  },\r\n    { 0x267E, \"E.D. Bullard Company\"  },\r\n    { 0x267F, \"Acromag Inc.\"  },\r\n    { 0x2680, \"DIGICO UK Limited\"  },\r\n    { 0x2681, \"MYLAPS B.V.\"  },\r\n    { 0x2682, \"ROBOX S.P.A.\"  },\r\n    { 0x2683, \"Gazogiken Co., Ltd.\"  },\r\n    { 0x2684, \"Funkwerk Security Communications GmbH\"  },\r\n    { 0x2685, \"Cardo Systems Inc.\"  },\r\n    { 0x2686, \"IP LABS Inc.\"  },\r\n    { 0x2687, \"FITBIT\"  },\r\n    { 0x2688, \"Stratasys Inc.\"  },\r\n    { 0x2689, \"StepOver Inc.\"  },\r\n    { 0x268A, \"QEES\"  },\r\n    { 0x268B, \"Dimension Engineering LLC\"  },\r\n    { 0x268C, \"AMS-TAOS\"  },\r\n    { 0x268D, \"WEISS ENGINEERING LTD.\"  },\r\n    { 0x268E, \"xyzmo Software GmbH\"  },\r\n    { 0x268F, \"LETech Co., Ltd.\"  },\r\n    { 0x2690, \"K.K. Rabbit\"  },\r\n    { 0x2691, \"ZINK Imaging, Inc.\"  },\r\n    { 0x2692, \"CELLIENT CO., LTD.\"  },\r\n    { 0x2693, \"Silvershore Technology Partners\"  },\r\n    { 0x2694, \"RoboteX Inc.\"  },\r\n    { 0x2695, \"DynaGen Technologies Inc.\"  },\r\n    { 0x2696, \"Sensovation AG\"  },\r\n    { 0x2697, \"Anfatec Instruments\"  },\r\n    { 0x2698, \"EVTD Inc.\"  },\r\n    { 0x2699, \"ECOUS Corp.\"  },\r\n    { 0x269A, \"BETTER MANAGE INVESTMENTS LIMITED\"  },\r\n    { 0x269B, \"Novel Data Solutions (Suzhou) Corporation\"  },\r\n    { 0x269C, \"ECTRON CORPORATION\"  },\r\n    { 0x269D, \"Accessible Technologies, Inc.\"  },\r\n    { 0x269E, \"Astro Gaming\"  },\r\n    { 0x269F, \"DKL TECHNOLOGY (SHENZHEN) CO., LTD.\"  },\r\n    { 0x26A0, \"MIDAS\"  },\r\n    { 0x26A1, \"Miris AB\"  },\r\n    { 0x26A2, \"Eppendorf AG\"  },\r\n    { 0x26A3, \"EMKO ELEKTRONIK SAN. VE TIC. AS\"  },\r\n    { 0x26A4, \"Blue Goji\"  },\r\n    { 0x26A5, \"CAL TEST ELECTRONICS, INC.\"  },\r\n    { 0x26A6, \"Radio Design Group, Inc.\"  },\r\n    { 0x26A7, \"LOG-IN, Inc.\"  },\r\n    { 0x26A8, \"UNIREX CORPORATION\"  },\r\n    { 0x26A9, \"Research Industrial Systems IT-Engineering (RISE) GmbH\"  },\r\n    { 0x26AA, \"YAESU MUSEN CO., LTD.\"  },\r\n    { 0x26AB, \"Motion Control Systems, Inc.\"  },\r\n    { 0x26AC, \"3D Robotics Inc.\"  },\r\n    { 0x26AD, \"Global Distribution GmbH\"  },\r\n    { 0x26AE, \"Oscium\"  },\r\n    { 0x26AF, \"Bombardier Transportation GmbH, TCMS Development Ctr 2\"  },\r\n    { 0x26B0, \"Zhejiang Senda Electronics Co., Ltd.\"  },\r\n    { 0x26B1, \"Bassett Electronic Systems Limited\"  },\r\n    { 0x26B2, \"RST Instruments Ltd.\"  },\r\n    { 0x26B3, \"Global Inkjet Systems\"  },\r\n    { 0x26B4, \"Sensor Technology Limited\"  },\r\n    { 0x26B5, \"ELECTROCOMPANIET AS\"  },\r\n    { 0x26B6, \"Pacom Systems Pty. Ltd.\"  },\r\n    { 0x26B7, \"Azusatekuno\"  },\r\n    { 0x26B8, \"InkControl, LLC\"  },\r\n    { 0x26B9, \"Satlantic LP\"  },\r\n    { 0x26BA, \"Freetronics Pty Ltd.\"  },\r\n    { 0x26BB, \"Omega Elektronik Sanayi ve Ticaret A.S.\"  },\r\n    { 0x26BC, \"CARDIN ELETTRONICA S.p.A.\"  },\r\n    { 0x26BD, \"Integral Memory Plc.\"  },\r\n    { 0x26BE, \"AKASA (ASIA) CORP.\"  },\r\n    { 0x26BF, \"Broadway System, Inc.\"  },\r\n    { 0x26C0, \"RADIODETECTION LTD.\"  },\r\n    { 0x26C1, \"Viola Audio Laboratories\"  },\r\n    { 0x26C2, \"FUTURE UNIVERSITY HAKODATE\"  },\r\n    { 0x26C3, \"HARLEY-DAVIDSON MOTOR COMPANY\"  },\r\n    { 0x26C4, \"Logic Way GmbH\"  },\r\n    { 0x26C5, \"TOKAI RUBBER INDUSTRIES, LTD.\"  },\r\n    { 0x26C6, \"GRAF-SYTECO GmbH & Co. KG\"  },\r\n    { 0x26C7, \"Beijing Stone New Technology Industry Co., Ltd.\"  },\r\n    { 0x26C8, \"SCHMID mme - electronic product engineering\"  },\r\n    { 0x26C9, \"SPM INSTRUMENT AB\"  },\r\n    { 0x26CA, \"MSY Inc.\"  },\r\n    { 0x26CB, \"Sung Kyung Precision Co., Ltd.\"  },\r\n    { 0x26CC, \"Hunting Titan\"  },\r\n    { 0x26CD, \"Blendology Limited\"  },\r\n    { 0x26CE, \"ASRock Inc.\"  },\r\n    { 0x26CF, \"The Gate Technologies\"  },\r\n    { 0x26D0, \"ZK Celltest, Inc.\"  },\r\n    { 0x26D1, \"THORLABS LTD.\"  },\r\n    { 0x26D2, \"Jiangsu Yinhe Electronics Co., Ltd.\"  },\r\n    { 0x26D3, \"VIBRATION INSTRUMENTS CO., LTD.\"  },\r\n    { 0x26D4, \"Truesense Imaging\"  },\r\n    { 0x26D5, \"Equinox Payments, LLC\"  },\r\n    { 0x26D6, \"Sistemi Elettronici Di Addonizio Luisa\"  },\r\n    { 0x26D7, \"POPSPA (HK) LTD.\"  },\r\n    { 0x26D8, \"APR, LLC\"  },\r\n    { 0x26D9, \"ATC-NY\"  },\r\n    { 0x26DA, \"Dabi Atlante\"  },\r\n    { 0x26DB, \"American DJ Supply\"  },\r\n    { 0x26DC, \"Gato Audio\"  },\r\n    { 0x26DD, \"Monnit Corp.\"  },\r\n    { 0x26DE, \"Velocity Micro, Inc.\"  },\r\n    { 0x26DF, \"University of Cambridge\"  },\r\n    { 0x26E0, \"Shenzhen Shixin Digital Co., Ltd.\"  },\r\n    { 0x26E1, \"CrucialTec Co., Ltd.\"  },\r\n    { 0x26E2, \"Ingenieurbuero Dietzsch und Thiele PartG\"  },\r\n    { 0x26E3, \"SHENZHEN EXCEL DIGITAL TECHNOLOGY CO., LTD.\"  },\r\n    { 0x26E4, \"VIZIO, Inc.\"  },\r\n    { 0x26E5, \"Shaghal Ltd.\"  },\r\n    { 0x26E6, \"ORC Manufacturing Co., Ltd.\"  },\r\n    { 0x26E7, \"Fishman\"  },\r\n    { 0x26E8, \"Camgian Microsystems\"  },\r\n    { 0x26E9, \"Lumenergi Inc.\"  },\r\n    { 0x26EA, \"OPTOVUE INC.\"  },\r\n    { 0x26EB, \"emtrion GmbH\"  },\r\n    { 0x26EC, \"SLE quality engineering GmbH & Co. KG\"  },\r\n    { 0x26ED, \"a.tron3d GmbH\"  },\r\n    { 0x26EE, \"Grimm Audio\"  },\r\n    { 0x26EF, \"TAKEBISHI CORPORATION\"  },\r\n    { 0x26F0, \"EDM Corporation\"  },\r\n    { 0x26F1, \"Fujian LANDI Commercial Equipment Co., Ltd.\"  },\r\n    { 0x26F2, \"AUDIS SARL\"  },\r\n    { 0x26F3, \"Raven Systems Design, Inc.\"  },\r\n    { 0x26F4, \"RTW GmbH & Co. KG\"  },\r\n    { 0x26F5, \"Morning Star Digital Connector Co., Ltd.\"  },\r\n    { 0x26F6, \"Sea-Bird Electronics\"  },\r\n    { 0x26F7, \"BFFT GmbH\"  },\r\n    { 0x26F8, \"Salon Transcripts, Inc.\"  },\r\n    { 0x26F9, \"Outstanding Technology Co., Ltd.\"  },\r\n    { 0x26FA, \"DAQ SYSTEM Co., Ltd.\"  },\r\n    { 0x26FB, \"FLIR Advanced Imaging Systems\"  },\r\n    { 0x26FC, \"Raven Industries\"  },\r\n    { 0x26FD, \"Foot Levelers, Inc.\"  },\r\n    { 0x26FE, \"ESPROS Photonics AG\"  },\r\n    { 0x26FF, \"MIA Corporation\"  },\r\n    { 0x2700, \"MITACHI CO., LTD.\"  },\r\n    { 0x2701, \"Pro Design Electronic GmbH\"  },\r\n    { 0x2702, \"Hobart GmbH\"  },\r\n    { 0x2703, \"Greenwave Reality Pte. Ltd.\"  },\r\n    { 0x2704, \"Unisun Innovation Incorporated\"  },\r\n    { 0x2705, \"CardioGrip Corporation\"  },\r\n    { 0x2706, \"iKey, Ltd.\"  },\r\n    { 0x2707, \"Bardac Corporation\"  },\r\n    { 0x2708, \"Audient Limited\"  },\r\n    { 0x2709, \"ZEON CORPORATION\"  },\r\n    { 0x270A, \"Channel Islands Audio\"  },\r\n    { 0x270B, \"MSHeli Srl\"  },\r\n    { 0x270C, \"Inhon Computer Co., Ltd.\"  },\r\n    { 0x270D, \"ROSAND Technologies\"  },\r\n    { 0x270E, \"Applied Security Inc.\"  },\r\n    { 0x270F, \"Western Digital, HGST\"  },\r\n    { 0x2710, \"Kontron America, Inc.\"  },\r\n    { 0x2711, \"ASD Inc.\"  },\r\n    { 0x2712, \"US Army Benet Laboratories\"  },\r\n    { 0x2713, \"Datalink Electronics Ltd.\"  },\r\n    { 0x2714, \"i'm S.p.A.\"  },\r\n    { 0x2715, \"Photron Limited\"  },\r\n    { 0x2716, \"YUEN DA ELECTRONIC PRODUCTS FACTORY\"  },\r\n    { 0x2717, \"Xiaomi Communications Co., Ltd.\"  },\r\n    { 0x2718, \"Tamaggo\"  },\r\n    { 0x2719, \"4iiii Innovations Inc.\"  },\r\n    { 0x271A, \"KONE Industrial Ltd.\"  },\r\n    { 0x271B, \"Tec.to\"  },\r\n    { 0x271C, \"KDDI Technology Corporation\"  },\r\n    { 0x271D, \"Gionee Communication Equipment Co., Ltd. ShenZhen\"  },\r\n    { 0x271E, \"Changzhou Traful Electronic Co., Ltd.\"  },\r\n    { 0x271F, \"Shanghai Nufront Electronic Technology Co., Ltd.\"  },\r\n    { 0x2720, \"motrona GmbH\"  },\r\n    { 0x2721, \"Germaneers GmbH\"  },\r\n    { 0x2722, \"TRANIT\"  },\r\n    { 0x2723, \"KUK Electronic AG\"  },\r\n    { 0x2724, \"XS Technology, Inc.\"  },\r\n    { 0x2725, \"L-3 Applied Signal & Image Technology\"  },\r\n    { 0x2726, \"Universal Electronics Inc. (dba: TVIEW)\"  },\r\n    { 0x2727, \"ANM OPTO LIMITED\"  },\r\n    { 0x2728, \"STX-Med SPRL\"  },\r\n    { 0x2729, \"Regenersis (Glenrothes) Ltd.\"  },\r\n    { 0x272A, \"StarLeaf Limited\"  },\r\n    { 0x272B, \"VAT Vakuumventile AG\"  },\r\n    { 0x272C, \"IAR Systems\"  },\r\n    { 0x272D, \"AKAR GAME LTD.\"  },\r\n    { 0x272E, \"Teratronik elektronische Systeme GmbH\"  },\r\n    { 0x272F, \"tommis gmbh, Ingenieurburo f. Nachrichtentechnik u. Aut\"  },\r\n    { 0x2730, \"Camozzi spa\"  },\r\n    { 0x2731, \"Pebble Audio Oy\"  },\r\n    { 0x2732, \"Samsung Medison Co., Ltd.\"  },\r\n    { 0x2733, \"ShenZhen SunSonny Electronic Technology Co., Ltd.\"  },\r\n    { 0x2734, \"Wuhan XinAn LuoJia Technologies Co., Ltd.\"  },\r\n    { 0x2735, \"Wilk Elektronik S.A.\"  },\r\n    { 0x2736, \"Silver Palm Technologies LLC\"  },\r\n    { 0x2737, \"Blu Controls\"  },\r\n    { 0x2738, \"Bad Rabby Designs\"  },\r\n    { 0x2739, \"BluePacket Communications Co., Ltd.\"  },\r\n    { 0x273A, \"Singular Technology Co., Ltd.\"  },\r\n    { 0x273B, \"TecScan Systems Inc.\"  },\r\n    { 0x273C, \"Etherstack Limited\"  },\r\n    { 0x273D, \"Thrimona Corporation\"  },\r\n    { 0x273E, \"LIFODAS\"  },\r\n    { 0x273F, \"Hughski Limited\"  },\r\n    { 0x2740, \"Apparent Corporation\"  },\r\n    { 0x2741, \"N2 Imaging Systems\"  },\r\n    { 0x2742, \"Organ Recovery Systems, Inc.\"  },\r\n    { 0x2743, \"XS Embedded GmbH\"  },\r\n    { 0x2744, \"RIKEN KEIKI NARA MFG. Co., Ltd.\"  },\r\n    { 0x2745, \"Unitech Electronics Co., Ltd.\"  },\r\n    { 0x2746, \"Shenzhen YishunTai Metal Factory\"  },\r\n    { 0x2747, \"AHA INC. Co., Ltd.\"  },\r\n    { 0x2748, \"Stresstech Oy\"  },\r\n    { 0x2749, \"GMV SISTEMAS\"  },\r\n    { 0x274A, \"Qdac Inc.\"  },\r\n    { 0x274B, \"Automotive Data Solutions, Inc.\"  },\r\n    { 0x274C, \"Atos Worldline\"  },\r\n    { 0x274D, \"FXI Technologies AS\"  },\r\n    { 0x274E, \"VECTRONIC Aerospace GmbH\"  },\r\n    { 0x274F, \"Dacuda AG\"  },\r\n    { 0x2750, \"SafeLine Sweden AB\"  },\r\n    { 0x2751, \"AMI International, Inc.\"  },\r\n    { 0x2752, \"miniDSP Ltd.\"  },\r\n    { 0x2753, \"Danville Signal Processing, Inc.\"  },\r\n    { 0x2754, \"Trapeze Software Group, Inc.\"  },\r\n    { 0x2755, \"Cosmic Circuits Pvt. Ltd.\"  },\r\n    { 0x2756, \"Victor Hasselblad AB\"  },\r\n    { 0x2757, \"HiteVision Digital Media Technology Co., Ltd.\"  },\r\n    { 0x2758, \"MobileEco Co., Ltd.\"  },\r\n    { 0x2759, \"Philip Morris Products S.A.\"  },\r\n    { 0x275A, \"Vertex Aquaristik GmbH\"  },\r\n    { 0x275B, \"PROPACK\"  },\r\n    { 0x275C, \"NITA, LLC\"  },\r\n    { 0x275D, \"NewSoc Tech Limited\"  },\r\n    { 0x275E, \"Scent Sciences Corporation\"  },\r\n    { 0x275F, \"Vishay Measurements Group, Inc.\"  },\r\n    { 0x2760, \"Oxigraf, Inc.\"  },\r\n    { 0x2761, \"CAST Navigation LLC\"  },\r\n    { 0x2762, \"FERMAX ELECTRONICA S.A.U.\"  },\r\n    { 0x2763, \"PRIMES GmbH\"  },\r\n    { 0x2764, \"Ouman Oy\"  },\r\n    { 0x2765, \"Firstbeat Technologies Ltd.\"  },\r\n    { 0x2766, \"LifeScan\"  },\r\n    { 0x2767, \"Cheetah Hi-Tech, Inc.\"  },\r\n    { 0x2768, \"DongGuan City Lian Zhi Electronic Technology Co. Ltd.\"  },\r\n    { 0x2769, \"SPI ENGINEERING Co., Ltd.\"  },\r\n    { 0x276A, \"SUGIYAMA ELECTRIC SYSTEM INC.\"  },\r\n    { 0x276B, \"CTI INFORMATION CENTER CO., LTD.\"  },\r\n    { 0x276C, \"PROTEI\"  },\r\n    { 0x276D, \"YSTEK Technology Company\"  },\r\n    { 0x276E, \"RGB Lasersysteme GmbH\"  },\r\n    { 0x276F, \"Lightware Visual Engineering\"  },\r\n    { 0x2771, \"TTE Corporation\"  },\r\n    { 0x2772, \"Audio Tuning Vertriebs GmbH\"  },\r\n    { 0x2773, \"HILTI AG\"  },\r\n    { 0x2774, \"Novasina AG\"  },\r\n    { 0x2775, \"Sonardyne International Ltd.\"  },\r\n    { 0x2776, \"KFI Trading s.r.l.\"  },\r\n    { 0x2777, \"SingTrix LLC\"  },\r\n    { 0x2778, \"Cypher Labs LLC\"  },\r\n    { 0x2779, \"Qualnetics Corporation\"  },\r\n    { 0x277A, \"Occipital, Inc.\"  },\r\n    { 0x277B, \"Moxtek, Inc\"  },\r\n    { 0x277C, \"SignalCore, Inc.\"  },\r\n    { 0x277D, \"Microcom Corporation\"  },\r\n    { 0x277E, \"Sportable Scoreboards, Inc.\"  },\r\n    { 0x277F, \"DongGuan City Shangjie Electronic Co., Ltd.\"  },\r\n    { 0x2780, \"M31 Technology Corp.\"  },\r\n    { 0x2781, \"Liteconn Co., Ltd.\"  },\r\n    { 0x2782, \"TTS Inc.\"  },\r\n    { 0x2783, \"Aktina Medical Corp.\"  },\r\n    { 0x2784, \"A-One Co., Ltd.\"  },\r\n    { 0x2785, \"Mayekawa Mfg. Co., Ltd.\"  },\r\n    { 0x2786, \"Switch Science, Incorporation\"  },\r\n    { 0x2787, \"AVTECH Corporation\"  },\r\n    { 0x2788, \"Sanwin (HK) Electronic Technology Co., Ltd.\"  },\r\n    { 0x2789, \"Suzhou WEIJU Electronics Technology Co., Ltd.\"  },\r\n    { 0x278A, \"MARSHAL Corporation\"  },\r\n    { 0x278B, \"The Rotel Co., Ltd.\"  },\r\n    { 0x278C, \"NAGATA ELECTRIC CO., LTD.\"  },\r\n    { 0x278D, \"GPSports Systems Pty., Ltd.\"  },\r\n    { 0x278E, \"TSS AB\"  },\r\n    { 0x278F, \"Bosch Sicherheitssysteme Engineering GmbH\"  },\r\n    { 0x2790, \"Cobalt Digital, Inc.\"  },\r\n    { 0x2791, \"SunTech Medical, Inc.\"  },\r\n    { 0x2792, \"SYSTEC Co., Limited\"  },\r\n    { 0x2793, \"i-KAIST\"  },\r\n    { 0x2794, \"SilverPlus, Inc.\"  },\r\n    { 0x2795, \"QuantaScope Biotech\"  },\r\n    { 0x2796, \"Zhejiang Wellcom Technology Co., Ltd.\"  },\r\n    { 0x2797, \"EUROIMMUN AG\"  },\r\n    { 0x2798, \"Turning Technologies\"  },\r\n    { 0x2799, \"Colorimetry Research, Inc.\"  },\r\n    { 0x279A, \"Naim Audio Limited\"  },\r\n    { 0x279B, \"Bluefish Technologies Pty Ltd.\"  },\r\n    { 0x279C, \"Advanced Anaesthesia Specialists\"  },\r\n    { 0x279D, \"Towa Electronics Co., Ltd.\"  },\r\n    { 0x279E, \"Syntronix Corporation\"  },\r\n    { 0x279F, \"Hiragawa Electronics Industry Co., Ltd.\"  },\r\n    { 0x27A0, \"Mondokey Limited\"  },\r\n    { 0x27A1, \"Autoliv Romania S.R.L.\"  },\r\n    { 0x27A2, \"T.I.T. ENG CO., LTD.\"  },\r\n    { 0x27A3, \"AU Optronics Corporation\"  },\r\n    { 0x27A4, \"Digital Act Inc.\"  },\r\n    { 0x27A5, \"Advantest Corporation\"  },\r\n    { 0x27A6, \"iRobot Corporation\"  },\r\n    { 0x27A7, \"Delta Computer Systems, Inc.\"  },\r\n    { 0x27A8, \"Square Inc.\"  },\r\n    { 0x27A9, \"Global Mixed-mode Technology Inc.\"  },\r\n    { 0x27AA, \"Just Connector Kunshan Co., Ltd.\"  },\r\n    { 0x27AB, \"Shenzhen Maxmade Technology Co., Ltd.\"  },\r\n    { 0x27AC, \"GP Electronics (HK) Limited\"  },\r\n    { 0x27AD, \"PAUL HARTMANN AG\"  },\r\n    { 0x27AE, \"TeleOrbit GmbH\"  },\r\n    { 0x27AF, \"HANNA Instruments, Inc.\"  },\r\n    { 0x27B0, \"FOXPRO Inc.\"  },\r\n    { 0x27B1, \"UltiMachine\"  },\r\n    { 0x27B2, \"OrthoAccel Technologies, Inc.\"  },\r\n    { 0x27B3, \"Secure Systems Limited\"  },\r\n    { 0x27B4, \"Duerkopp Adler AG\"  },\r\n    { 0x27B5, \"J-MEX Inc.\"  },\r\n    { 0x27B6, \"TechnoKom Ltd.\"  },\r\n    { 0x27B7, \"Fraunhofer IMS\"  },\r\n    { 0x27B8, \"ThingM Corporation\"  },\r\n    { 0x27B9, \"Ziotech Corp\"  },\r\n    { 0x27BA, \"Aoptix Technologies, Inc.\"  },\r\n    { 0x27BB, \"Plenom A/S\"  },\r\n    { 0x27BC, \"KeyView\"  },\r\n    { 0x27BD, \"Codethink Limited\"  },\r\n    { 0x27BE, \"InHand Electronics, Inc.\"  },\r\n    { 0x27BF, \"Dongguan CPO Electronic Co., Ltd.\"  },\r\n    { 0x27C0, \"Cadwell Laboratories, Inc.\"  },\r\n    { 0x27C1, \"ARKAMI\"  },\r\n    { 0x27C2, \"ArcBotics LLC\"  },\r\n    { 0x27C3, \"Danfoss Turbocor Compressors Inc.\"  },\r\n    { 0x27C4, \"KRYPTUS\"  },\r\n    { 0x27C5, \"SRT Marine Technology Limited\"  },\r\n    { 0x27C6, \"Shenzhen Huiding Technology Co. Ltd.\"  },\r\n    { 0x27C7, \"TransluSense, LLC\"  },\r\n    { 0x27C8, \"Rigaku Corporation\"  },\r\n    { 0x27C9, \"ElaraTek LTD.\"  },\r\n    { 0x27CA, \"JayBird LLC\"  },\r\n    { 0x27CB, \"ANXA Limited Hong Kong\"  },\r\n    { 0x27CC, \"GHL Matthias Gross GmbH & Co. KG\"  },\r\n    { 0x27CD, \"GHEO SA\"  },\r\n    { 0x27CE, \"Double Power Technology Inc.\"  },\r\n    { 0x27CF, \"Weidmueller Interface GmbH & Co. KG\"  },\r\n    { 0x27D0, \"Traxon Technologies Europe GmbH\"  },\r\n    { 0x27D1, \"Angelbird Technologies GmbH\"  },\r\n    { 0x27D2, \"EURONOVATE SA\"  },\r\n    { 0x27D3, \"PRECIA MOLEN\"  },\r\n    { 0x27D4, \"Blackstar Amplification Ltd.\"  },\r\n    { 0x27D5, \"BSkyB LTD.\"  },\r\n    { 0x27D6, \"T3 Innovation\"  },\r\n    { 0x27D7, \"Senova Systems, Inc.\"  },\r\n    { 0x27D8, \"Patriot Memory\"  },\r\n    { 0x27D9, \"Gallagher Group Limited\"  },\r\n    { 0x27DA, \"S Net Media Inc.\"  },\r\n    { 0x27DB, \"Hiitop Technology Limited\"  },\r\n    { 0x27DC, \"Tennant Company\"  },\r\n    { 0x27DD, \"Shenzhen MinDe Electronics Technology Ltd.\"  },\r\n    { 0x27DE, \"Newtec Cy\"  },\r\n    { 0x27DF, \"Charles Novacroft Direct Limited\"  },\r\n    { 0x27E0, \"Stelulu Technology\"  },\r\n    { 0x27E1, \"TRX Systems, Inc.\"  },\r\n    { 0x27E2, \"Natus Medical Incorproated\"  },\r\n    { 0x27E3, \"Chemyx Inc.\"  },\r\n    { 0x27E4, \"Easybotics LLC\"  },\r\n    { 0x27E5, \"Shiroshita Industrial Co., Ltd.\"  },\r\n    { 0x27E6, \"SENECA srl\"  },\r\n    { 0x27E7, \"AVIWEST\"  },\r\n    { 0x27E8, \"takwak GmbH\"  },\r\n    { 0x27E9, \"Soeks Limited\"  },\r\n    { 0x27EA, \"Goldmund International\"  },\r\n    { 0x27EB, \"ACCUCOMM, INC.\"  },\r\n    { 0x27EC, \"SEETECH CO., LTD.\"  },\r\n    { 0x27ED, \"Tescom-Emerson Process Management\"  },\r\n    { 0x27EE, \"DashLogic Inc.\"  },\r\n    { 0x27EF, \"TAIYO SEIKI CO., LTD.\"  },\r\n    { 0x27F0, \"DITECT Corporation\"  },\r\n    { 0x27F1, \"VERTU Corporation Limited\"  },\r\n    { 0x27F2, \"Softnautics Private Limited\"  },\r\n    { 0x27F3, \"Indutherm Erwaermungsanlagen GmbH\"  },\r\n    { 0x27F4, \"LEGIC Identsystems Ltd.\"  },\r\n    { 0x27F5, \"Relume Technologies, Inc.\"  },\r\n    { 0x27F6, \"Advanced Simulation Technology Inc.\"  },\r\n    { 0x27F7, \"Wyred 4 Sound\"  },\r\n    { 0x27F8, \"Wikipad, Inc.\"  },\r\n    { 0x27F9, \"MIDAS Elektronik GmbH\"  },\r\n    { 0x27FA, \"Afag Automation AG\"  },\r\n    { 0x27FB, \"Barclays\"  },\r\n    { 0x27FC, \"CAREL SPA\"  },\r\n    { 0x27FD, \"GI Therapies Pty Ltd.\"  },\r\n    { 0x27FE, \"DONGGUAN Rakecorp Co., Ltd.\"  },\r\n    { 0x27FF, \"Cashway Technology Co., Ltd.\"  },\r\n    { 0x2800, \"iluminage, Inc.\"  },\r\n    { 0x2801, \"Pear Sports LLC\"  },\r\n    { 0x2802, \"Moixa Technology\"  },\r\n    { 0x2803, \"StarLine LLC\"  },\r\n    { 0x2804, \"4MOD Technology\"  },\r\n    { 0x2805, \"Shenzhen N-Pass Mobile Technology, Ltd.\"  },\r\n    { 0x2806, \"RF DataTech\"  },\r\n    { 0x2807, \"Elliptic Laboratories AS\"  },\r\n    { 0x2808, \"FocalTech Systems, Ltd.\"  },\r\n    { 0x2809, \"Sept Co., Ltd.\"  },\r\n    { 0x280A, \"Culti Co., Ltd.\"  },\r\n    { 0x280B, \"Dukane Corporation\"  },\r\n    { 0x280C, \"Linera\"  },\r\n    { 0x280D, \"Ai Electronic Industry Co., Ltd.\"  },\r\n    { 0x280E, \"Leaf Imaging Ltd.\"  },\r\n    { 0x280F, \"MBit Wireless, Inc.\"  },\r\n    { 0x2810, \"Aphex, LLC\"  },\r\n    { 0x2811, \"DigiTalks INC.\"  },\r\n    { 0x2812, \"Bridge Semiconductor Corp.\"  },\r\n    { 0x2813, \"Brookfield Engineering Laboratories Inc.\"  },\r\n    { 0x2814, \"OOO SMS-Soft\"  },\r\n    { 0x2815, \"KING TSUSHIN KOGYO CO., LTD.\"  },\r\n    { 0x2816, \"Harvard Photonix\"  },\r\n    { 0x2817, \"Test Equipment Plus\"  },\r\n    { 0x2818, \"Codex Digital Limited\"  },\r\n    { 0x2819, \"MESSRING Systembau MSG GmbH\"  },\r\n    { 0x281A, \"SWAC Automation Consult GmbH\"  },\r\n    { 0x281B, \"HiES Tech s.r.o.\"  },\r\n    { 0x281C, \"Presidium Instruments Pte. Ltd.\"  },\r\n    { 0x281D, \"AISIN AW CO., LTD.\"  },\r\n    { 0x281E, \"Symphodia Phil\"  },\r\n    { 0x281F, \"Motion Control, Inc.\"  },\r\n    { 0x2820, \"Sanovas\"  },\r\n    { 0x2821, \"Aclima Inc.\"  },\r\n    { 0x2822, \"REFLEXdigital\"  },\r\n    { 0x2823, \"Dongguan Jiumutong Industry Co., Ltd.\"  },\r\n    { 0x2824, \"Vollsun Ltd.\"  },\r\n    { 0x2825, \"Baumer Optronic GmbH\"  },\r\n    { 0x2826, \"BSH Bosch und Siemens Hausgerate GmbH\"  },\r\n    { 0x2827, \"DIGITTRADE GmbH\"  },\r\n    { 0x2828, \"SAPHYMO\"  },\r\n    { 0x2829, \"Scanomat A/S\"  },\r\n    { 0x282A, \"REDL GmbH\"  },\r\n    { 0x282B, \"Aevoe Inc.\"  },\r\n    { 0x282C, \"Reichert, Inc.\"  },\r\n    { 0x282D, \"Aeromax Technology Co., Ltd.\"  },\r\n    { 0x282E, \"Vectawave Technology Ltd.\"  },\r\n    { 0x282F, \"SANKEN ELECTRIC CO., LTD.\"  },\r\n    { 0x2830, \"GD-Broadband\"  },\r\n    { 0x2831, \"Power Integrations\"  },\r\n    { 0x2832, \"Applied Research Associates\"  },\r\n    { 0x2833, \"Oculus VR LLC\"  },\r\n    { 0x2834, \"JM Concept\"  },\r\n    { 0x2835, \"SEIDENSHA ELECTRONICS Co., Ltd.\"  },\r\n    { 0x2836, \"OUYA Inc.\"  },\r\n    { 0x2837, \"Tunstall Healthcare (UK) Ltd.\"  },\r\n    { 0x2838, \"Ontorix GmbH\"  },\r\n    { 0x2839, \"Grass Elektronik\"  },\r\n    { 0x283A, \"HIKe Mobile Co., Ltd.\"  },\r\n    { 0x283B, \"Cellon Communications Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x283C, \"HIGH TEK HARNESS ENTERPRISE CO., LTD.\"  },\r\n    { 0x283D, \"SigNET (AC) Ltd.\"  },\r\n    { 0x283E, \"DECATHLON SA\"  },\r\n    { 0x283F, \"Elprosys Sp. Z.o.o.\"  },\r\n    { 0x2840, \"Taiwan Carol Electronics Co., Ltd.\"  },\r\n    { 0x2841, \"Artvision Technologies Inc.\"  },\r\n    { 0x2842, \"RobotGroup\"  },\r\n    { 0x2843, \"SyncMOS Technologies International, Inc.\"  },\r\n    { 0x2844, \"ELSIST Srl\"  },\r\n    { 0x2845, \"Systec Designs BV\"  },\r\n    { 0x2846, \"ATRON electronic GmbH\"  },\r\n    { 0x2847, \"TMG TE GmbH\"  },\r\n    { 0x2848, \"Sentons USA, Inc.\"  },\r\n    { 0x2849, \"Astronics Advanced Electronic Systems Corp.\"  },\r\n    { 0x284A, \"Yangtze Optical Fibre and Cable Company Ltd.\"  },\r\n    { 0x284B, \"Leadingui Co., Ltd.\"  },\r\n    { 0x284C, \"Full in Hope Co., Ltd.\"  },\r\n    { 0x284D, \"Qltouch Tech Co., Ltd.\"  },\r\n    { 0x284E, \"Flysky RC Model Co., Ltd.\"  },\r\n    { 0x284F, \"ANTLIA SA\"  },\r\n    { 0x2850, \"Intellectual Property Group SA\"  },\r\n    { 0x2851, \"RETIA, a.s.\"  },\r\n    { 0x2852, \"Virtual Console, LLC\"  },\r\n    { 0x2853, \"Ralston Instruments\"  },\r\n    { 0x2854, \"Great River Technology\"  },\r\n    { 0x2855, \"System Dimensions, Inc.\"  },\r\n    { 0x2856, \"Thales Alenia Space - Italia\"  },\r\n    { 0x2857, \"Skardin Industrial Corporation\"  },\r\n    { 0x2858, \"PT Doo Won Precision Indonesia\"  },\r\n    { 0x2859, \"Viconn Technology (HK) Co., Ltd.\"  },\r\n    { 0x285A, \"AiM Touch Technology Co., Ltd.\"  },\r\n    { 0x285B, \"HARDWARE & SOFTWARE TECHNOLOGY CO., LTD.\"  },\r\n    { 0x285C, \"URMET S.p.a.\"  },\r\n    { 0x285D, \"Alarm.com, Inc.\"  },\r\n    { 0x285E, \"Occam Robotics\"  },\r\n    { 0x285F, \"CyWee Group Limited\"  },\r\n    { 0x2860, \"WISYCOM UNIPERSONALE s.r.l.\"  },\r\n    { 0x2861, \"Pacific Image Electronics Co., Ltd.\"  },\r\n    { 0x2862, \"DeVilbiss Healthcare LLC\"  },\r\n    { 0x2863, \"BIOMATIQUES IDENTIFICATION SOLUTIONS PRIVATE LIMITED\"  },\r\n    { 0x2864, \"Wenngo Inc.\"  },\r\n    { 0x2865, \"VIKING GmbH\"  },\r\n    { 0x2866, \"SLOW CONTROL\"  },\r\n    { 0x2867, \"DASCOM\"  },\r\n    { 0x2868, \"Chakra Energetics Ltd.\"  },\r\n    { 0x2869, \"Comfort Audio AB\"  },\r\n    { 0x286A, \"Dipl. - Ing. H. Horstmann GmbH\"  },\r\n    { 0x286B, \"STANEO SAS\"  },\r\n    { 0x286C, \"Atest-Gaz A. M. Pachole sp. j.\"  },\r\n    { 0x286D, \"Production Resource Group, LLC\"  },\r\n    { 0x286E, \"Geosense Inc.\"  },\r\n    { 0x286F, \"Bretford Manufacturing Inc.\"  },\r\n    { 0x2870, \"Typhoon HIL, Inc.\"  },\r\n    { 0x2871, \"BYK-Gardner GmbH\"  },\r\n    { 0x2872, \"Brite Semiconductor (Shanghai) Corporation\"  },\r\n    { 0x2873, \"Spire Payments Holdings S.a.r.l.\"  },\r\n    { 0x2874, \"Dexter Research Center, Inc.\"  },\r\n    { 0x2875, \"nVideon, Inc.\"  },\r\n    { 0x2876, \"Safety Innovations, Inc.\"  },\r\n    { 0x2877, \"BrightSign LLC\"  },\r\n    { 0x2878, \"Cabletech Electronics (Hong Kong) Co., Ltd.\"  },\r\n    { 0x2879, \"Rancore Technologies Private Limited\"  },\r\n    { 0x287A, \"Shenzhen Bojuxing Industrial Development Co., Ltd.\"  },\r\n    { 0x287B, \"Pro-Tech\"  },\r\n    { 0x287C, \"Special Recording Systems Ltd.\"  },\r\n    { 0x287D, \"Pettersson Elektronik AB\"  },\r\n    { 0x287E, \"Silicon Designs, Inc.\"  },\r\n    { 0x287F, \"Beijing Jinke XinAn Technology Co., Ltd.\"  },\r\n    { 0x2880, \"Black Diamond Video\"  },\r\n    { 0x2881, \"DX Antenna Co., Ltd.\"  },\r\n    { 0x2882, \"GCOMM CORPORATION\"  },\r\n    { 0x2883, \"abatec group AG\"  },\r\n    { 0x2884, \"Bor\"  },\r\n    { 0x2885, \"Quantec SA\"  },\r\n    { 0x2886, \"Seeed Technology Co., Ltd.\"  },\r\n    { 0x2887, \"Specwerkz\"  },\r\n    { 0x2888, \"VEX Robotics, Inc.\"  },\r\n    { 0x2889, \"TrueVision Systems, Inc.\"  },\r\n    { 0x288A, \"LEXIBOOK LIMITED\"  },\r\n    { 0x288B, \"Hierstar (Suzhou)\"  },\r\n    { 0x288C, \"Moswell Co., Ltd.\"  },\r\n    { 0x288D, \"Centre for Development of Advanced Computing (C-DAC)\"  },\r\n    { 0x288E, \"mce-systems Ltd.\"  },\r\n    { 0x288F, \"Voxx Accessories Corp.\"  },\r\n    { 0x2890, \"Teknic, Inc.\"  },\r\n    { 0x2891, \"Flytec AG\"  },\r\n    { 0x2892, \"NAVIgard\"  },\r\n    { 0x2893, \"LEVEL Ltd.\"  },\r\n    { 0x2894, \"Hovercam\"  },\r\n    { 0x2895, \"INIM Electronics s.r.l.\"  },\r\n    { 0x2896, \"TTAF Elektronik Sanayi ve Ticaret Ltd. Sti.\"  },\r\n    { 0x2897, \"SDJ Technologies, Inc.\"  },\r\n    { 0x2898, \"Accumetrics Associates, Inc.\"  },\r\n    { 0x2899, \"Toptronic Industrial Co., Ltd.\"  },\r\n    { 0x289A, \"Scan-Sense A.S.\"  },\r\n    { 0x289B, \"DRACAL Technologies Inc.\"  },\r\n    { 0x289C, \"TLS Corp.\"  },\r\n    { 0x289D, \"Tyrian Systems, Inc.\"  },\r\n    { 0x289E, \"Esselte Leitz GmbH & Co. KG\"  },\r\n    { 0x289F, \"inoage GmbH\"  },\r\n    { 0x28A0, \"I-CUBE TECHNOLOGY Co., Ltd.\"  },\r\n    { 0x28A1, \"AVEST-SYSTEMS Private Unitary Enterprise\"  },\r\n    { 0x28A2, \"Meadowlark Optics Incorporated\"  },\r\n    { 0x28A3, \"SensoMotoric Instruments GmbH\"  },\r\n    { 0x28A4, \"Objective Solutions Sweden AB\"  },\r\n    { 0x28A5, \"TCS John Huxley\"  },\r\n    { 0x28A6, \"E-SEEK Inc.\"  },\r\n    { 0x28A7, \"Hugo Brennenstuhl GmbH & Co. KG\"  },\r\n    { 0x28A8, \"AT Sciences, LLC\"  },\r\n    { 0x28A9, \"Alpha Technologies\"  },\r\n    { 0x28AA, \"Realta Entertainment Group\"  },\r\n    { 0x28AB, \"Navigil Ltd.\"  },\r\n    { 0x28AC, \"euroBRAILLE\"  },\r\n    { 0x28AD, \"iDTRONIC GmbH\"  },\r\n    { 0x28AE, \"Zynaptic Limited\"  },\r\n    { 0x28AF, \"Sharkbay Technologies Pte. Ltd.\"  },\r\n    { 0x28B0, \"PMC - Sierra\"  },\r\n    { 0x28B1, \"EcoTech, Inc.\"  },\r\n    { 0x28B2, \"Siemens Infrastructure & Cities\"  },\r\n    { 0x28B3, \"Profoto AB\"  },\r\n    { 0x28B4, \"TOACK Corporation\"  },\r\n    { 0x28B5, \"Solacom Inc.\"  },\r\n    { 0x28B6, \"Alcohol Countermeasure Systems Corp.\"  },\r\n    { 0x28B7, \"Pleora Technologies Inc.\"  },\r\n    { 0x28B8, \"Swiss Authentication Research & Development AG\"  },\r\n    { 0x28B9, \"Kapsch TrafficCom AB\"  },\r\n    { 0x28BA, \"RSscan International NV\"  },\r\n    { 0x28BB, \"ICP Systems b.v.\"  },\r\n    { 0x28BC, \"Cyplex Corporation\"  },\r\n    { 0x28BD, \"GuangZhou Ugee Computer Technology Co., Ltd.\"  },\r\n    { 0x28BE, \"GMG TECH. Co., Ltd.\"  },\r\n    { 0x28BF, \"Vitetech Int'l Co., Ltd.\"  },\r\n    { 0x28C0, \"SCVNGR, Inc.\"  },\r\n    { 0x28C1, \"DOMMEL GmbH\"  },\r\n    { 0x28C2, \"Tapko Technologies GmbH\"  },\r\n    { 0x28C3, \"MITSUBISHI ELECTRIC SYSTEM & SERVICE CO., LTD.\"  },\r\n    { 0x28C4, \"GALA, Inc.\"  },\r\n    { 0x28C5, \"ShenZhen Innovate-link Precision Hardware Co., Ltd.\"  },\r\n    { 0x28C6, \"FASTLITE\"  },\r\n    { 0x28C7, \"Ultimaker BV\"  },\r\n    { 0x28C8, \"ULTRACHIP Inc.\"  },\r\n    { 0x28C9, \"DongGuan City DHE Wire & Cable Co., Ltd.\"  },\r\n    { 0x28CA, \"NUMATA Corporation\"  },\r\n    { 0x28CB, \"GO engineering GmbH\"  },\r\n    { 0x28CC, \"MIWA ELECTRIC CO., LTD.\"  },\r\n    { 0x28CD, \"SMARTMATIC INTERNATIONAL CORP.\"  },\r\n    { 0x28CE, \"Changzhou Shi Wujin Miqi East Electronic Co., Ltd.\"  },\r\n    { 0x28CF, \"Asiatelco Technologies Co.\"  },\r\n    { 0x28D0, \"Stryker Corporation\"  },\r\n    { 0x28D1, \"Technomedica Co., Ltd.\"  },\r\n    { 0x28D2, \"FTK Corporation\"  },\r\n    { 0x28D3, \"Golden Transmart International Co., Ltd.\"  },\r\n    { 0x28D4, \"DEVIALET SAS\"  },\r\n    { 0x28D5, \"Vicor Corporation\"  },\r\n    { 0x28D6, \"Electrogamez USA Inc.\"  },\r\n    { 0x28D7, \"Tekron International\"  },\r\n    { 0x28D8, \"Panda Ocean Inc.\"  },\r\n    { 0x28D9, \"Shenzhen Yoshuo Precision Components Co., Ltd.\"  },\r\n    { 0x28DA, \"G.SKILL Int'l Enterprice Co., Ltd.\"  },\r\n    { 0x28DB, \"Konftel AB\"  },\r\n    { 0x28DC, \"Power Electronics International, Inc.\"  },\r\n    { 0x28DD, \"AIWA COMPANY LTD. - Love Harmony (LH)\"  },\r\n    { 0x28DE, \"Valve Corporation\"  },\r\n    { 0x28DF, \"EMBED-IT\"  },\r\n    { 0x28E0, \"PRASIMAX\"  },\r\n    { 0x28E1, \"Shenzhen iSolution Technologies Co., Ltd.\"  },\r\n    { 0x28E2, \"Surplus Electronic Technology Co., Ltd.\"  },\r\n    { 0x28E3, \"Apollo Electrical Technology Co., Ltd.\"  },\r\n    { 0x28E4, \"RKS, Inc.\"  },\r\n    { 0x28E5, \"MEP TECH\"  },\r\n    { 0x28E6, \"BIAMP SYSTEMS\"  },\r\n    { 0x28E7, \"Glyph Production Technologies\"  },\r\n    { 0x28E8, \"Jefferson Audio Video Systems, Inc.\"  },\r\n    { 0x28E9, \"GigaDevice Semiconductor (Beijing) Inc.\"  },\r\n    { 0x28EA, \"Dongguan Vast Electronics Co.,Ltd\"  },\r\n    { 0x28EB, \"SHEN ZHEN SHI YUAN AI HARDWARE ELECTRONIC CO., LTD.\"  },\r\n    { 0x28EC, \"Transcom Instruments Co., Ltd.\"  },\r\n    { 0x28ED, \"Shenzhen AraTek Biometrics Technology Co., Ltd.\"  },\r\n    { 0x28EE, \"China Mobile Group Device Co., Ltd.\"  },\r\n    { 0x28EF, \"SEEFRONT GmbH\"  },\r\n    { 0x28F0, \"Elcus Electronic Company JSC\"  },\r\n    { 0x28F1, \"Leddartech Inc.\"  },\r\n    { 0x28F2, \"Applied Vision Corporation\"  },\r\n    { 0x28F3, \"Clover Network\"  },\r\n    { 0x28F4, \"Sonoma Wire Works\"  },\r\n    { 0x28F5, \"Electrolux Laundry Systems Sweden AB\"  },\r\n    { 0x28F6, \"SERVOMEX Group Ltd.\"  },\r\n    { 0x28F7, \"ANYWIRE CORPORATION\"  },\r\n    { 0x28F8, \"VTECH Technology Corp.\"  },\r\n    { 0x28F9, \"Comcraft\"  },\r\n    { 0x28FA, \"iProtoXi Oy\"  },\r\n    { 0x28FB, \"Shin Hwa Contech Co., Ltd.\"  },\r\n    { 0x28FC, \"Shandong Sinochiptp Electronic Technology Co., Ltd.\"  },\r\n    { 0x28FD, \"Wolfson Microelectronics Plc.\"  },\r\n    { 0x28FE, \"Marquardt Mechatronik GmbH\"  },\r\n    { 0x28FF, \"MIRAENANOTECH\"  },\r\n    { 0x2900, \"Labsphere\"  },\r\n    { 0x2901, \"Tolomatic Inc.\"  },\r\n    { 0x2902, \"Woodward Inc.\"  },\r\n    { 0x2903, \"Lightspeed Aviation\"  },\r\n    { 0x2904, \"Charon Technologies LLC\"  },\r\n    { 0x2905, \"iDea USA Products Inc.\"  },\r\n    { 0x2906, \"Masimo Corporation\"  },\r\n    { 0x2907, \"Mimetics Inc.\"  },\r\n    { 0x2908, \"Shenzhen Sen5 Technology Co., Ltd.\"  },\r\n    { 0x2909, \"Active Mind Technology\"  },\r\n    { 0x290A, \"Electronic Systems Technology, Inc.\"  },\r\n    { 0x290B, \"Beats Electronics LLC\"  },\r\n    { 0x290C, \"R. Hamilton & Co. Ltd.\"  },\r\n    { 0x290D, \"IBCONN Technologies (Shenzhen) Co., Ltd.\"  },\r\n    { 0x290E, \"Fugoo Inc.\"  },\r\n    { 0x290F, \"AFL Noyes\"  },\r\n    { 0x2910, \"Cree, Inc.\"  },\r\n    { 0x2911, \"Penetek, Inc.\"  },\r\n    { 0x2912, \"Management Company ATOL Ltd.\"  },\r\n    { 0x2913, \"Teladin Co., Ltd.\"  },\r\n    { 0x2914, \"Kent Displays Inc.\"  },\r\n    { 0x2915, \"Sage Microelectronics Corp.\"  },\r\n    { 0x2916, \"Yota Devices Ltd.\"  },\r\n    { 0x2917, \"Pan Xin Precision Electronics Co., Ltd.\"  },\r\n    { 0x2918, \"Gigatronik Ingolstadt GmbH\"  },\r\n    { 0x2919, \"GE Analytical Instruments\"  },\r\n    { 0x291A, \"Anker Technology Co., Limited\"  },\r\n    { 0x291B, \"LONTEX PIOTR LONDZIN\"  },\r\n    { 0x291C, \"KEISOKUKI CENTER CO., LTD.\"  },\r\n    { 0x291D, \"Research & Development Center ELVEES OJSC\"  },\r\n    { 0x291E, \"Shanghai DynamiCode Company Ltd.\"  },\r\n    { 0x291F, \"CBN Inc.\"  },\r\n    { 0x2920, \"Fiberplex Technologies, LLC\"  },\r\n    { 0x2921, \"BiovenTus, LLC\"  },\r\n    { 0x2922, \"Dongguan Digi-in Digital Technology Co., Ltd.\"  },\r\n    { 0x2923, \"Vprime\"  },\r\n    { 0x2924, \"Chinon Corporation\"  },\r\n    { 0x2925, \"Flight System Consulting Inc.\"  },\r\n    { 0x2926, \"Wildlife Acoustics, Inc.\"  },\r\n    { 0x2927, \"BF1 Systems Ltd.\"  },\r\n    { 0x2928, \"Dongguan Sineng Electronic Technology Co., Ltd.\"  },\r\n    { 0x2929, \"Shenzhen Taishan Online Technology Co., Ltd.\"  },\r\n    { 0x292A, \"T1Visions, Inc.\"  },\r\n    { 0x292B, \"Precision Audio Device Lab Limited\"  },\r\n    { 0x292C, \"GENUSION, Inc.\"  },\r\n    { 0x292D, \"Wellitec Development Limited\"  },\r\n    { 0x292E, \"HOYA Service Corporation\"  },\r\n    { 0x292F, \"Nanotec Electronic GmbH & Co. KG\"  },\r\n    { 0x2930, \"Ineda Systems Inc.\"  },\r\n    { 0x2931, \"Jolla Ltd.\"  },\r\n    { 0x2932, \"Peraso Technologies, Inc.\"  },\r\n    { 0x2933, \"IEI Integration Corp.\"  },\r\n    { 0x2934, \"CETA Testsysteme GmbH\"  },\r\n    { 0x2935, \"Nanjing Magewell Electronics Co., Ltd.\"  },\r\n    { 0x2936, \"LEAP Motion\"  },\r\n    { 0x2937, \"Tmax Digital Inc.\"  },\r\n    { 0x2938, \"Aides Technology Co., Ltd.\"  },\r\n    { 0x2939, \"Zaber Technologies Inc.\"  },\r\n    { 0x293A, \"The SmarTV Company\"  },\r\n    { 0x293B, \"Lucent Medical Systems, Inc.\"  },\r\n    { 0x293C, \"Comcast\"  },\r\n    { 0x293D, \"Medicatec Inc.\"  },\r\n    { 0x293E, \"EIDEN Co., Ltd.\"  },\r\n    { 0x293F, \"Gan Zhou DPT-Technology Co., Ltd.\"  },\r\n    { 0x2940, \"Shenzhen Yiwanda Electronics Co., Ltd.\"  },\r\n    { 0x2941, \"Sanofi-Aventis Deutschland GmbH\"  },\r\n    { 0x2942, \"SoftLab - NSK\"  },\r\n    { 0x2943, \"ZAGG Inc.\"  },\r\n    { 0x2944, \"RailComm\"  },\r\n    { 0x2945, \"Matrix Design Group, LLC\"  },\r\n    { 0x2946, \"OnAsset Intelligence Inc.\"  },\r\n    { 0x2947, \"KAPELSE\"  },\r\n    { 0x2948, \"Access Network Technology Limited\"  },\r\n    { 0x2949, \"Shenzhen JSR Technology Co., Ltd.\"  },\r\n    { 0x294A, \"Shenzhen Xinguodu Technology Co., Ltd.\"  },\r\n    { 0x294B, \"snakebyte Asia Ltd.\"  },\r\n    { 0x294C, \"Terminus Circuits Pvt Ltd.\"  },\r\n    { 0x294D, \"Cellwise Holding Co., Ltd.\"  },\r\n    { 0x294E, \"SHIH HUA TECHNOLOGY LTD.\"  },\r\n    { 0x294F, \"Dollar Connection Ltd.\"  },\r\n    { 0x2950, \"Resource One Inc.\"  },\r\n    { 0x2951, \"Raytrix GmbH\"  },\r\n    { 0x2952, \"Seba Dynatronic GmbH\"  },\r\n    { 0x2953, \"Axes System sp. Z.o.o.\"  },\r\n    { 0x2954, \"Human Design Medical, LLC\"  },\r\n    { 0x2955, \"Baidu Online Network Technology (Beijing) Co., Ltd.\"  },\r\n    { 0x2956, \"Alfatest Ind. e Com. Produtos Eletronicos S/A\"  },\r\n    { 0x2957, \"OBSIDIAN RESEARCH CORPORATION\"  },\r\n    { 0x2958, \"Eleven Engineering Inc.\"  },\r\n    { 0x2959, \"Inuitive\"  },\r\n    { 0x295A, \"ENERMAX TECHNOLOGY CORPORATION\"  },\r\n    { 0x295B, \"eflow Inc.\"  },\r\n    { 0x295C, \"MediaNet M. Hermsen\"  },\r\n    { 0x295D, \"Positive Grid\"  },\r\n    { 0x295E, \"Britelite Enterprises\"  },\r\n    { 0x295F, \"Tecvox Connectivity, LLC\"  },\r\n    { 0x2960, \"Power Probe, Inc.\"  },\r\n    { 0x2961, \"Miselu Inc.\"  },\r\n    { 0x2962, \"Wilocity Ltd.\"  },\r\n    { 0x2963, \"BIO-key International, Inc.\"  },\r\n    { 0x2964, \"Kintech Co., Ltd.\"  },\r\n    { 0x2965, \"Kortek\"  },\r\n    { 0x2966, \"Schatz AG\"  },\r\n    { 0x2967, \"St. Andrews Instrumentation Ltd.\"  },\r\n    { 0x2968, \"Phoenix Avionics Systems, LLC\"  },\r\n    { 0x2969, \"Sumix\"  },\r\n    { 0x296A, \"Nitero, Inc.\"  },\r\n    { 0x296B, \"Xacti Corporation\"  },\r\n    { 0x296C, \"KNC ONE GmbH - Research & Development\"  },\r\n    { 0x296D, \"Azuri Technologies Ltd\"  },\r\n    { 0x296E, \"LG CNS Co., Ltd.\"  },\r\n    { 0x296F, \"Broadsound Corporation\"  },\r\n    { 0x2970, \"MERIDIAN SOFTWARE SYSTEMS LIMITED\"  },\r\n    { 0x2971, \"Ory Laboratory Ltd.\"  },\r\n    { 0x2972, \"FiiO Electronics Technology Co., Ltd.\"  },\r\n    { 0x2973, \"Wild Elektronik & Kunststoff GmbH & Co. KG\"  },\r\n    { 0x2974, \"Printrbot, Inc.\"  },\r\n    { 0x2975, \"MPC Research Ltd.\"  },\r\n    { 0x2976, \"COMOTA Co., Ltd.\"  },\r\n    { 0x2977, \"Shenzhen Zowee Technology Co., Ltd.\"  },\r\n    { 0x2978, \"Imaging Solutions Group of NY, Inc.\"  },\r\n    { 0x2979, \"Williams Sound, LLC\"  },\r\n    { 0x297A, \"Innovative Developments LLC\"  },\r\n    { 0x297B, \"ALKERIA s.r.l.\"  },\r\n    { 0x297C, \"HashFast Technologies LLC\"  },\r\n    { 0x297D, \"Krypton Solutions\"  },\r\n    { 0x297E, \"Shenzhen DTEC Electronic Technology Co., Ltd.\"  },\r\n    { 0x297F, \"Emerging Technology (Holdings) Ltd.\"  },\r\n    { 0x2980, \"CiDELEC\"  },\r\n    { 0x2981, \"Elektron Technology UK Limited\"  },\r\n    { 0x2982, \"Ableton AG\"  },\r\n    { 0x2983, \"Coyote System\"  },\r\n    { 0x2984, \"Glensound Electronics Ltd.\"  },\r\n    { 0x2985, \"DUALO\"  },\r\n    { 0x2986, \"Rapt Touch (Ireland) Ltd.\"  },\r\n    { 0x2987, \"Lyve Minds, Inc.\"  },\r\n    { 0x2988, \"3D Systems Corporation\"  },\r\n    { 0x2989, \"Nanjing Fujitsu Electronics Information Technology Co., Ltd\"  },\r\n    { 0x298A, \"Singeen Electronics Technologies (Dongguan) Co., Ltd.\"  },\r\n    { 0x298B, \"Hanil ProTech\"  },\r\n    { 0x298C, \"GL Solutions Inc.\"  },\r\n    { 0x298D, \"NEXT Biometrics\"  },\r\n    { 0x298E, \"Delta Controls\"  },\r\n    { 0x298F, \"NIHON DENON CO., LTD.\"  },\r\n    { 0x2990, \"SHIGA MEC Company Limited\"  },\r\n    { 0x2991, \"Orbitsound Ltd\"  },\r\n    { 0x2992, \"Lantos Technologies, Inc.\"  },\r\n    { 0x2993, \"ADPlaus Technology Limited\"  },\r\n    { 0x2995, \"Resodyn Corporation\"  },\r\n    { 0x2996, \"Delphi Data Connectivity\"  },\r\n    { 0x2997, \"Inogeni Inc.\"  },\r\n    { 0x2998, \"EOS S.r.l.\"  },\r\n    { 0x2999, \"Fourtec Technologies Ltd.\"  },\r\n    { 0x299A, \"Ogi Systems Ltd. by A.A. Lab Systems\"  },\r\n    { 0x299B, \"Ohio Semitronics, Inc.\"  },\r\n    { 0x299C, \"WINTOUCH Co., Ltd.\"  },\r\n    { 0x299D, \"Horst Platz Beratungs und Vertriebs GmbH\"  },\r\n    { 0x299E, \"TRE INNOVATORER AB\"  },\r\n    { 0x299F, \"MESTEC Technologies\"  },\r\n    { 0x29A0, \"Bang & Olufsen Medicom A/S\"  },\r\n    { 0x29A1, \"Union Electric Plug & Connector Corp.\"  },\r\n    { 0x29A2, \"MUTEC GmbH\"  },\r\n    { 0x29A3, \"Cista System Corporation\"  },\r\n    { 0x29A4, \"Source Audio LLC\"  },\r\n    { 0x29A5, \"Harbo Entertainment LLC\"  },\r\n    { 0x29A6, \"Chiyoda Electronics Co., Ltd.\"  },\r\n    { 0x29A7, \"Tekinvest Holding Ltd.\"  },\r\n    { 0x29A8, \"Lester Electrical\"  },\r\n    { 0x29A9, \"Smartisan Technology Co., Ltd.\"  },\r\n    { 0x29AA, \"Zivix, LLC\"  },\r\n    { 0x29AB, \"The Eye Tribe\"  },\r\n    { 0x29AC, \"Cool Control (S.D.) Ltd.\"  },\r\n    { 0x29AD, \"Quest Engineering & Development, Inc.\"  },\r\n    { 0x29AE, \"Japan Lifeline Co., Ltd.\"  },\r\n    { 0x29AF, \"Zhongshan K-Mate General Electronics Co., Ltd.\"  },\r\n    { 0x29B0, \"Diebold Financial Equipment Co., Ltd.\"  },\r\n    { 0x29B1, \"Dongguan Haitai Precision Electronic Technology Co Ltd\"  },\r\n    { 0x29B2, \"Canova Tech\"  },\r\n    { 0x29B3, \"Dowling Software\"  },\r\n    { 0x29B4, \"Shenzhen Carbetter Technology Co., Ltd.\"  },\r\n    { 0x29B5, \"PN Devices Int'l Limited\"  },\r\n    { 0x29B6, \"Gowin Technology International Holdings Limited\"  },\r\n    { 0x29B7, \"X.O.Ware, Inc.\"  },\r\n    { 0x29B8, \"Hawk-Owl Systems\"  },\r\n    { 0x29B9, \"S.I.C.E.S. S.r.l.\"  },\r\n    { 0x29BA, \"TOPTICA Photonics AG\"  },\r\n    { 0x29BB, \"SMUFS Biometric Solutions\"  },\r\n    { 0x29BC, \"IMBEL - Industria de Material Belico do Brasil\"  },\r\n    { 0x29BD, \"Silicon Works\"  },\r\n    { 0x29BE, \"Mamiya-OP NEQUOS Co., Ltd.\"  },\r\n    { 0x29BF, \"BalanceMaster, Inc.\"  },\r\n    { 0x29C0, \"Canopy Co.\"  },\r\n    { 0x29C1, \"TazTag\"  },\r\n    { 0x29C2, \"Lewitt GmbH\"  },\r\n    { 0x29C3, \"Noviga\"  },\r\n    { 0x29C4, \"SoundHawk Corporation\"  },\r\n    { 0x29C5, \"Peachtree Audio\"  },\r\n    { 0x29C6, \"Shenzhen Jiali Asia Industry Co., Ltd.\"  },\r\n    { 0x29C7, \"HANRICO ANFU ELECTRONICS CO., LTD.\"  },\r\n    { 0x29C8, \"Samil CTS Co., Ltd.\"  },\r\n    { 0x29C9, \"BEEVC-Electronic Systems, LDA\"  },\r\n    { 0x29CA, \"Cross the Road Electronics, LLC\"  },\r\n    { 0x29CB, \"Xima Software\"  },\r\n    { 0x29CC, \"Kodak Alaris\"  },\r\n    { 0x29CD, \"Carotron, Inc.\"  },\r\n    { 0x29CE, \"JGR Optics Inc.\"  },\r\n    { 0x29CF, \"Richtek Technology Corporation\"  },\r\n    { 0x29D0, \"ShenZhen Synergy Digital Co., Ltd.\"  },\r\n    { 0x29D1, \"Binatone Electronics Int. Ltd.\"  },\r\n    { 0x29D2, \"Crypto Control Limited\"  },\r\n    { 0x29D3, \"HESS Cash Systems GmbH & Co. KG\"  },\r\n    { 0x29D4, \"Twin Development S.A.\"  },\r\n    { 0x29D5, \"Alibaba Cloud Computing Ltd.\"  },\r\n    { 0x29D6, \"Ara Hub Design Inc.\"  },\r\n    { 0x29D7, \"Suritel\"  },\r\n    { 0x29D8, \"Vigor Electric Corporation\"  },\r\n    { 0x29D9, \"San-Eisha, Ltd.\"  },\r\n    { 0x29DA, \"The Modal Shop\"  },\r\n    { 0x29DB, \"Shenzhen iBoard Technology Co., Ltd.\"  },\r\n    { 0x29DC, \"TOHO Electronics Inc.\"  },\r\n    { 0x29DD, \"Embedded Micro\"  },\r\n    { 0x29DE, \"Korea Electric Terminal Co., Ltd.\"  },\r\n    { 0x29DF, \"SMIT(HK) Limited\"  },\r\n    { 0x29E0, \"ARCCRA Technology Co., Ltd.\"  },\r\n    { 0x29E1, \"TOSEI ENGINEERING CORP.\"  },\r\n    { 0x29E2, \"Huatune Technology (Shanghai) Co., Ltd.\"  },\r\n    { 0x29E3, \"Bio-Medical Research\"  },\r\n    { 0x29E4, \"Prestigio Plaza Ltd.\"  },\r\n    { 0x29E5, \"Dongguan Kechenda Electronic Technology Co., Ltd.\"  },\r\n    { 0x29E6, \"Fengshun Peiying Electro-Acoustic Co., Ltd.\"  },\r\n    { 0x29E7, \"Brunel University\"  },\r\n    { 0x29E8, \"4Links Limited\"  },\r\n    { 0x29E9, \"Quanttus, Inc.\"  },\r\n    { 0x29EA, \"Kinesis Corporation\"  },\r\n    { 0x29EB, \"Virtuix Inc.\"  },\r\n    { 0x29EC, \"R. Stahl\"  },\r\n    { 0x29ED, \"CERA\"  },\r\n    { 0x29EE, \"Pinnacle Response Ltd.\"  },\r\n    { 0x29EF, \"GamePop Inc.\"  },\r\n    { 0x29F0, \"WirePath Home Systems dba Snap AV\"  },\r\n    { 0x29F1, \"0XF8 Limited\"  },\r\n    { 0x29F2, \"RECO Gesellschaft fur Industriefilterregelung mbH\"  },\r\n    { 0x29F3, \"Resonessence Labs\"  },\r\n    { 0x29F4, \"NeuroSky, Inc.\"  },\r\n    { 0x29F5, \"AirNetix, LLC\"  },\r\n    { 0x29F6, \"Evoko Unlimited AB\"  },\r\n    { 0x29F7, \"Matica Technologies AG\"  },\r\n    { 0x29F8, \"MD ELEKTRONIK GmbH\"  },\r\n    { 0x29F9, \"EnerLab, LLC\"  },\r\n    { 0x29FA, \"LogTag Recorders Ltd.\"  },\r\n    { 0x29FB, \"JSK Co., Ltd.\"  },\r\n    { 0x29FC, \"Namsung Corporation\"  },\r\n    { 0x29FD, \"Bad Elf, LLC\"  },\r\n    { 0x29FE, \"GEO Semiconductor Inc.\"  },\r\n    { 0x29FF, \"Thalmic Labs Inc.\"  },\r\n    { 0x2A00, \"NTLab\"  },\r\n    { 0x2A01, \"Amuseway Korea Co., Ltd.\"  },\r\n    { 0x2A02, \"OJI LTD.\"  },\r\n    { 0x2A03, \"dog hunter AG\"  },\r\n    { 0x2A04, \"Microtech Laboratory Inc.\"  },\r\n    { 0x2A05, \"EXO LABS INC.\"  },\r\n    { 0x2A06, \"HiFiMAN Electronics\"  },\r\n    { 0x2A07, \"ise GmbH\"  },\r\n    { 0x2A08, \"Marshall Amplification PLC\"  },\r\n    { 0x2A09, \"cytonome\"  },\r\n    { 0x2A0A, \"All Star International Trading\"  },\r\n    { 0x2A0B, \"Leopard Imaging Inc.\"  },\r\n    { 0x2A0C, \"MultiSoft Systems Ltd.\"  },\r\n    { 0x2A0D, \"ADVANCE Co., Ltd.\"  },\r\n    { 0x2A0E, \"Shenzhen DreamSource Technology Co., Ltd.\"  },\r\n    { 0x2A0F, \"Shenzhen Giec Electronics Co., Ltd.\"  },\r\n    { 0x2A10, \"Powerway Electronics Co., Ltd.\"  },\r\n    { 0x2A11, \"P3 Ingenieurgesellschaft mbH\"  },\r\n    { 0x2A12, \"Vreo Limited\"  },\r\n    { 0x2A13, \"Grabba International\"  },\r\n    { 0x2A14, \"Kanex\"  },\r\n    { 0x2A15, \"navAero AB\"  },\r\n    { 0x2A16, \"Hella Gutmann Solutions\"  },\r\n    { 0x2A17, \"UDEA Electronic Ltd.\"  },\r\n    { 0x2A18, \"King Abdulaziz City for Science and Technology\"  },\r\n    { 0x2A19, \"Numato Systems Pvt. Ltd.\"  },\r\n    { 0x2A1A, \"ASCOT GmbH\"  },\r\n    { 0x2A1B, \"DRS Power & Control Technologies, Inc.\"  },\r\n    { 0x2A1C, \"ThinkWrite\"  },\r\n    { 0x2A1D, \"Oxford Nanopore Technologies\"  },\r\n    { 0x2A1E, \"Obsidian Technology\"  },\r\n    { 0x2A1F, \"Lucent Trans Electronics Co., Ltd.\"  },\r\n    { 0x2A20, \"GUOGUANG GROUP CO., LTD.\"  },\r\n    { 0x2A21, \"ROL Ergo AB\"  },\r\n    { 0x2A22, \"CDEX CORP.\"  },\r\n    { 0x2A23, \"Artec Design\"  },\r\n    { 0x2A24, \"CNPLUS\"  },\r\n    { 0x2A25, \"Fourstar Group\"  },\r\n    { 0x2A26, \"Tragant International Co., Ltd.\"  },\r\n    { 0x2A27, \"DongGuan LianGang Optoelectronic Technology Co., Ltd.\"  },\r\n    { 0x2A28, \"Higbie, LLC dba kinetuex\"  },\r\n    { 0x2A29, \"PayPal, Inc.\"  },\r\n    { 0x2A2A, \"TARGAMITE LLC\"  },\r\n    { 0x2A2B, \"NooElec Inc.\"  },\r\n    { 0x2A2C, \"Bkav Corporation\"  },\r\n    { 0x2A2D, \"Atrust Computer Corp.\"  },\r\n    { 0x2A2E, \"VIA Alliance Semiconductor Co., Ltd.\"  },\r\n    { 0x2A2F, \"BSUN Electronics Co., Ltd.\"  },\r\n    { 0x2A30, \"KORR Medical Technologies\"  },\r\n    { 0x2A31, \"Sandia National Laboratories\"  },\r\n    { 0x2A32, \"Centre for Advanced Transport Engineering and Research\"  },\r\n    { 0x2A33, \"NTT R&D Laboratories\"  },\r\n    { 0x2A34, \"KT System, Inc.\"  },\r\n    { 0x2A35, \"Quatius Limited\"  },\r\n    { 0x2A36, \"MOS Co., Ltd.\"  },\r\n    { 0x2A37, \"RTD Embedded Technologies, Inc.\"  },\r\n    { 0x2A38, \"Electronic Design Inc.\"  },\r\n    { 0x2A39, \"RME GmbH\"  },\r\n    { 0x2A3A, \"K'NEX Limited Partnership Group\"  },\r\n    { 0x2A3B, \"Eschenbach Optik GmbH\"  },\r\n    { 0x2A3C, \"TRINAMIC Motion Control GmbH & Co. KG\"  },\r\n    { 0x2A3D, \"FIME\"  },\r\n    { 0x2A3E, \"Atlas Copco\"  },\r\n    { 0x2A3F, \"Yasunaga Corporation\"  },\r\n    { 0x2A40, \"Shenzhen Choseal Industrial Co., Ltd.\"  },\r\n    { 0x2A41, \"Canyon Semiconductor\"  },\r\n    { 0x2A42, \"Spectra7 Microsystems Corp.\"  },\r\n    { 0x2A43, \"Ekosur S.A.\"  },\r\n    { 0x2A44, \"FUEL3D Technologies Limited\"  },\r\n    { 0x2A45, \"Meizu Technology Co., Ltd.\"  },\r\n    { 0x2A46, \"Hubei Yingtong Telecommunication Cable Inc.\"  },\r\n    { 0x2A47, \"Mundo Reader SL\"  },\r\n    { 0x2A48, \"Pointmobile\"  },\r\n    { 0x2A49, \"UNOWHY\"  },\r\n    { 0x2A4A, \"threeRivers 3D, Inc.\"  },\r\n    { 0x2A4B, \"EMULEX Corporation\"  },\r\n    { 0x2A4C, \"Tianjin SharpNow Technology Co., Ltd.\"  },\r\n    { 0x2A4D, \"Wilder Technologies\"  },\r\n    { 0x2A4E, \"Henge Docks, LLC\"  },\r\n    { 0x2A4F, \"L-3 Communications Avionics Systems\"  },\r\n    { 0x2A50, \"Akizuki Denshi Tsusho Co., Ltd.\"  },\r\n    { 0x2A51, \"Multiclet Corp.\"  },\r\n    { 0x2A52, \"L CARD Ltd.\"  },\r\n    { 0x2A53, \"x-odos GmbH\"  },\r\n    { 0x2A54, \"Black Diamond Advanced Technology, LLC\"  },\r\n    { 0x2A56, \"eemagine Medical Imaging Solutions GmbH\"  },\r\n    { 0x2A57, \"Bellingham + Stanley Limited\"  },\r\n    { 0x2A58, \"ALIGN Corporation Limited\"  },\r\n    { 0x2A59, \"The Whistler Group\"  },\r\n    { 0x2A5A, \"Kromek Group Plc.\"  },\r\n    { 0x2A5B, \"Integrity Applications Ltd.\"  },\r\n    { 0x2A5C, \"Dalian Zonewin Electronics Co., Ltd.\"  },\r\n    { 0x2A5D, \"Zhejiang Wanli Jo Ju Automation Technonolgy Co., Ltd.\"  },\r\n    { 0x2A5E, \"The Chemours Company\"  },\r\n    { 0x2A5F, \"Tencent Technology (Shenzhen) Company Limited\"  },\r\n    { 0x2A60, \"Oscadi SAS\"  },\r\n    { 0x2A61, \"Ellex Medical Pty Ltd.\"  },\r\n    { 0x2A62, \"Flymaster Avionics, LDA\"  },\r\n    { 0x2A63, \"Postek Electronics Co., Ltd.\"  },\r\n    { 0x2A64, \"Zhejiang Songcheng Electronics Co., Ltd.\"  },\r\n    { 0x2A65, \"FreeWave Technologies, Inc.\"  },\r\n    { 0x2A66, \"JoyLabz LLC\"  },\r\n    { 0x2A67, \"Chart Industries\"  },\r\n    { 0x2A68, \"CheckSum, LLC\"  },\r\n    { 0x2A69, \"EDIC Systems Inc.\"  },\r\n    { 0x2A6A, \"PINTSCH TIEFENBACH GmbH\"  },\r\n    { 0x2A6B, \"VSN Mobil\"  },\r\n    { 0x2A6C, \"Silego Technology\"  },\r\n    { 0x2A6D, \"SAsync, LLC\"  },\r\n    { 0x2A6E, \"Bare Conductive Ltd.\"  },\r\n    { 0x2A6F, \"Shenzhen Justtide Tech Co., Ltd.\"  },\r\n    { 0x2A70, \"Shenzhen Oneplus Science and Technology Co., Inc.\"  },\r\n    { 0x2A71, \"Eyelock, Inc.\"  },\r\n    { 0x2A72, \"Omega Engineering\"  },\r\n    { 0x2A73, \"IMAC Co., Ltd.\"  },\r\n    { 0x2A74, \"Innoflight Tech., Ltd.\"  },\r\n    { 0x2A75, \"Delta Dansk Elektronik, Lys & Akustik\"  },\r\n    { 0x2A76, \"Microsemi Corporation (Phoenix)\"  },\r\n    { 0x2A77, \"American Printing House for the Blind\"  },\r\n    { 0x2A78, \"mySkin, Inc.\"  },\r\n    { 0x2A79, \"S.E. Technologies Limited\"  },\r\n    { 0x2A7A, \"Beijing Casue Technology Co., Ltd.\"  },\r\n    { 0x2A7B, \"Bellwether Electronic Corp.\"  },\r\n    { 0x2A7C, \"Acute Technology Inc.\"  },\r\n    { 0x2A7D, \"ParTech, Inc.\"  },\r\n    { 0x2A7E, \"VAIO Corporation\"  },\r\n    { 0x2A7F, \"Perixx Computer GmbH\"  },\r\n    { 0x2A80, \"Smart Start Inc.\"  },\r\n    { 0x2A81, \"Hale Products, Inc.\"  },\r\n    { 0x2A82, \"Printek, Inc.\"  },\r\n    { 0x2A83, \"Autodesk Inc.\"  },\r\n    { 0x2A84, \"ATE Systems\"  },\r\n    { 0x2A85, \"HANK ELECTRONICS CO., LTD\"  },\r\n    { 0x2A86, \"KITRIS AG\"  },\r\n    { 0x2A87, \"Kummler + Matter AG\"  },\r\n    { 0x2A88, \"DFU Technology Ltd.\"  },\r\n    { 0x2A89, \"Robert Bosch Tool Corporation\"  },\r\n    { 0x2A8A, \"Benchmark Drives GmbH & Co. KG\"  },\r\n    { 0x2A8B, \"I.C. Lercher GmbH & Co. KG\"  },\r\n    { 0x2A8C, \"Sonnet Technologies, Inc.\"  },\r\n    { 0x2A8D, \"Keysight Technologies Inc.\"  },\r\n    { 0x2A8E, \"Starlink Electronics Corp.\"  },\r\n    { 0x2A8F, \"Manutronics Vietnam Joint Stock Company\"  },\r\n    { 0x2A90, \"NowComputing, LLC\"  },\r\n    { 0x2A91, \"Seed Industrial Designing Co., Ltd.\"  },\r\n    { 0x2A92, \"Woosim Systems Inc.\"  },\r\n    { 0x2A93, \"Enblink Co., Ltd.\"  },\r\n    { 0x2A94, \"G2 Touch Co., Ltd.\"  },\r\n    { 0x2A95, \"Flipkart Internet Pvt. Ltd.\"  },\r\n    { 0x2A96, \"Micromax Informatics Ltd\"  },\r\n    { 0x2A97, \"Broadway Semiconductor, Inc.\"  },\r\n    { 0x2A98, \"Calix\"  },\r\n    { 0x2A99, \"Humanistic Robotics, Inc.\"  },\r\n    { 0x2A9A, \"SRAM, LLC\"  },\r\n    { 0x2A9B, \"Doblet Inc.\"  },\r\n    { 0x2A9C, \"Olorin AB\"  },\r\n    { 0x2A9D, \"LawMate International Co., Ltd.\"  },\r\n    { 0x2A9E, \"SEIKO SOLUTIONS Inc.\"  },\r\n    { 0x2A9F, \"Mobelisk LLC\"  },\r\n    { 0x2AA0, \"Casco Products Corp.\"  },\r\n    { 0x2AA1, \"Ivanhoe (DE), Inc.\"  },\r\n    { 0x2AA2, \"GTI Spindle Technology, Inc.\"  },\r\n    { 0x2AA3, \"Strike Technologies a Division of Penbro Kelnick (Pty) Ltd\"  },\r\n    { 0x2AA4, \"Voim Technologies Inc.\"  },\r\n    { 0x2AA5, \"Pen Generations, Inc.\"  },\r\n    { 0x2AA6, \"ChengFong International Limited\"  },\r\n    { 0x2AA7, \"MJC Techno Co., Ltd.\"  },\r\n    { 0x2AA8, \"Resus Industries NV\"  },\r\n    { 0x2AA9, \"Infrared Cameras Inc.\"  },\r\n    { 0x2AAA, \"Virtium Technology, Inc.\"  },\r\n    { 0x2AAB, \"Field and Company LLC, dba Leef USA\"  },\r\n    { 0x2AAC, \"Elinchrom S.A.\"  },\r\n    { 0x2AAD, \"iCatch Technology, Inc.\"  },\r\n    { 0x2AAE, \"Chipone Technology (Beijing) Co., Ltd.\"  },\r\n    { 0x2AAF, \"Xiamen Hanin Electronic Technology Co., Ltd.\"  },\r\n    { 0x2AB0, \"GM Global Technology Operations LLC\"  },\r\n    { 0x2AB1, \"Tesco Stores Ltd.\"  },\r\n    { 0x2AB2, \"Maktar, Inc.\"  },\r\n    { 0x2AB3, \"Key Asic Inc.\"  },\r\n    { 0x2AB4, \"Line Seiki Co., Ltd.\"  },\r\n    { 0x2AB5, \"Micro-Technica Co., Ltd.\"  },\r\n    { 0x2AB6, \"T+A Elektroakustik GmbH + Co. KG\"  },\r\n    { 0x2AB7, \"foc.us\"  },\r\n    { 0x2AB8, \"Meggitt (Orange County), Inc.\"  },\r\n    { 0x2AB9, \"Monsoon Solutions, Inc.\"  },\r\n    { 0x2ABA, \"MagneMotion Inc.\"  },\r\n    { 0x2ABB, \"HiDeep Inc.\"  },\r\n    { 0x2ABC, \"Beijing Kingrich Medical Technology Co., Ltd.\"  },\r\n    { 0x2ABD, \"Meeteasy Technology Limited\"  },\r\n    { 0x2ABE, \"Bluink Ltd\"  },\r\n    { 0x2ABF, \"Revolabs, Inc.\"  },\r\n    { 0x2AC0, \"POWA Technologies Ltd.\"  },\r\n    { 0x2AC1, \"Lattice Semiconductor Corp\"  },\r\n    { 0x2AC2, \"Toreck Co., Ltd.\"  },\r\n    { 0x2AC3, \"Foshan Nanhai Saga Audio Equipment Co., Ltd.\"  },\r\n    { 0x2AC4, \"BlackBox Biometrics, Inc.\"  },\r\n    { 0x2AC5, \"PhotoFast Co., Ltd.\"  },\r\n    { 0x2AC6, \"HAKKO Corporation\"  },\r\n    { 0x2AC7, \"Ultrahaptics Limited\"  },\r\n    { 0x2AC8, \"SimonsVoss Technologies GmbH\"  },\r\n    { 0x2AC9, \"TELPA Telekomunikasyon Tic. A.S. Brand: General Mobile\"  },\r\n    { 0x2ACA, \"Toledo do Brasil Industria de Balancas Ltda.\"  },\r\n    { 0x2ACB, \"Pole/Zero Acquisition, Inc.\"  },\r\n    { 0x2ACC, \"illunis LLC\"  },\r\n    { 0x2ACD, \"Silergy Corp.\"  },\r\n    { 0x2ACE, \"Tonetron Electronic Ltd.\"  },\r\n    { 0x2ACF, \"Ruffy Controls Inc.\"  },\r\n    { 0x2AD0, \"Holley Performance Products (CANADA) Inc.\"  },\r\n    { 0x2AD1, \"Pictronic GmbH\"  },\r\n    { 0x2AD2, \"Allnic Audio\"  },\r\n    { 0x2AD3, \"Shenzhen Hali-Power Industrial Co., Ltd.\"  },\r\n    { 0x2AD4, \"L&F Corporation\"  },\r\n    { 0x2AD5, \"Baikal Electronics JSC\"  },\r\n    { 0x2AD6, \"Cozumo, Inc.\"  },\r\n    { 0x2AD7, \"RHENAC Systems GmbH\"  },\r\n    { 0x2AD8, \"i2s\"  },\r\n    { 0x2AD9, \"Zound Industries International AB\"  },\r\n    { 0x2ADA, \"McCarthy Music Corp.\"  },\r\n    { 0x2ADB, \"I-PEX (Dai-ichi Seiko)\"  },\r\n    { 0x2ADC, \"Absolute USA\"  },\r\n    { 0x2ADD, \"SEE-PLUS INDUSTRIAL LTD.\"  },\r\n    { 0x2ADE, \"Orga BV\"  },\r\n    { 0x2ADF, \"Noiseless Security A/S\"  },\r\n    { 0x2AE0, \"Auma Riester GmbH & Co. KG\"  },\r\n    { 0x2AE1, \"EDEC PROGRESS CO., LTD.\"  },\r\n    { 0x2AE2, \"VXi Corporation\"  },\r\n    { 0x2AE3, \"Jiuzhou Digital (Hong Kong) Limited\"  },\r\n    { 0x2AE4, \"Next! s.c. Slawomir Piela, Bartlomiej Dryja\"  },\r\n    { 0x2AE5, \"Fairphone B.V.\"  },\r\n    { 0x2AE6, \"e-distribuzione Spa\"  },\r\n    { 0x2AE7, \"Advanced Media, Inc.\"  },\r\n    { 0x2AE8, \"Quintic Microelectronics (Wuxi) Co., Ltd.\"  },\r\n    { 0x2AE9, \"Regal Beloit Canada ULC. dba Thomson Power Systems\"  },\r\n    { 0x2AEA, \"Protonex Technology Corporation\"  },\r\n    { 0x2AEB, \"NovaTech, LLC\"  },\r\n    { 0x2AEC, \"Ambiq Micro, Inc.\"  },\r\n    { 0x2AED, \"Technology Launch, LLC\"  },\r\n    { 0x2AEE, \"Adapt-IP Company\"  },\r\n    { 0x2AEF, \"Coronado Electronics, Inc.\"  },\r\n    { 0x2AF0, \"Zhejiang Yuesui Electron Stock Co., Ltd.\"  },\r\n    { 0x2AF1, \"Innovation Spring Tech, Inc.\"  },\r\n    { 0x2AF2, \"CIS Corporation\"  },\r\n    { 0x2AF3, \"Rehan Electronics Ltd.\"  },\r\n    { 0x2AF4, \"ROLI Ltd.\"  },\r\n    { 0x2AF5, \"Libratone A/S\"  },\r\n    { 0x2AF6, \"Nix Sensor Ltd.\"  },\r\n    { 0x2AF7, \"Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd.\"  },\r\n    { 0x2AF8, \"Jiangsu Toppower Automotive Electronics Co., Ltd.\"  },\r\n    { 0x2AF9, \"Drapho Electronics Technology Co., Ltd.\"  },\r\n    { 0x2AFA, \"Yokogawa Digital Computer Corporation\"  },\r\n    { 0x2AFB, \"EMC, Electronic Music Components\"  },\r\n    { 0x2AFC, \"Savox Communications OY AB\"  },\r\n    { 0x2AFD, \"McIntosh Laboratory, Inc.\"  },\r\n    { 0x2AFE, \"IntriCon\"  },\r\n    { 0x2AFF, \"ARP Corporation\"  },\r\n    { 0x2B00, \"Novitec Co., Ltd.\"  },\r\n    { 0x2B01, \"Zimi Corporation\"  },\r\n    { 0x2B02, \"AMGOO Telecom Co., Ltd.\"  },\r\n    { 0x2B03, \"STEREOLABS\"  },\r\n    { 0x2B04, \"Spark Labs, Inc.\"  },\r\n    { 0x2B05, \"Warn Industries\"  },\r\n    { 0x2B06, \"TEControl\"  },\r\n    { 0x2B07, \"ESA Elektroschaltanlagen Grimma GmbH\"  },\r\n    { 0x2B08, \"KYOEI ENGINEERING Co., Ltd.\"  },\r\n    { 0x2B09, \"Shenzhen Lidacheng Technology Co., Ltd.\"  },\r\n    { 0x2B0A, \"AMICCOM Electronics Corporation\"  },\r\n    { 0x2B0B, \"Qtul Enterprises\"  },\r\n    { 0x2B0C, \"Goclever Sp z o.o.\"  },\r\n    { 0x2B0D, \"Dongguan Yulian Electronic Industrial Co., Ltd.\"  },\r\n    { 0x2B0E, \"Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited\"  },\r\n    { 0x2B0F, \"Best Integration Technology Co., Ltd.\"  },\r\n    { 0x2B10, \"Cardiac Insight, Inc.\"  },\r\n    { 0x2B11, \"Europe Net Srl\"  },\r\n    { 0x2B12, \"DeepSpar\"  },\r\n    { 0x2B13, \"Lightcomm Technology Co., Ltd.\"  },\r\n    { 0x2B14, \"EverPro Technologies Company, Ltd.\"  },\r\n    { 0x2B15, \"Rosenberger Hochfrequenztechnik\"  },\r\n    { 0x2B16, \"Spirometrix, Inc.\"  },\r\n    { 0x2B17, \"Jaguar Land Rover\"  },\r\n    { 0x2B18, \"ProSign GmbH\"  },\r\n    { 0x2B19, \"JBSignal Co.\"  },\r\n    { 0x2B1A, \"Fortune Ship Technology (HK) Limited\"  },\r\n    { 0x2B1B, \"Dongguan City Sanji Electronics Co., Ltd.\"  },\r\n    { 0x2B1C, \"Shenzhen Virtual Reality Technology Company Limited\"  },\r\n    { 0x2B1D, \"Lintes Technology Co., Ltd.\"  },\r\n    { 0x2B1E, \"NFUZD Technology Inc\"  },\r\n    { 0x2B1F, \"KinnexA, Inc.\"  },\r\n    { 0x2B20, \"WaveLynx Technologies Corporation\"  },\r\n    { 0x2B21, \"Project Florida\"  },\r\n    { 0x2B22, \"Metra Electronics Corp.\"  },\r\n    { 0x2B23, \"Red Hat, Inc.\"  },\r\n    { 0x2B24, \"KeepKey, LLC\"  },\r\n    { 0x2B25, \"Logos Biosystems, Inc.\"  },\r\n    { 0x2B26, \"Oltrade LLC\"  },\r\n    { 0x2B27, \"FluxData Incorporated\"  },\r\n    { 0x2B28, \"Enovation Controls, LLC\"  },\r\n    { 0x2B29, \"Lezyne\"  },\r\n    { 0x2B2A, \"BDX\"  },\r\n    { 0x2B2B, \"BITwave PTE LTD.\"  },\r\n    { 0x2B2C, \"S1nn GmbH & Co. KG\"  },\r\n    { 0x2B2D, \"AEG Power Solutions GmbH\"  },\r\n    { 0x2B2E, \"pei tel Communications GmbH\"  },\r\n    { 0x2B2F, \"UL TS B.V.\"  },\r\n    { 0x2B30, \"Neratec Solutions AG\"  },\r\n    { 0x2B31, \"JVIS USA, LLC\"  },\r\n    { 0x2B32, \"NVS Technologies AG\"  },\r\n    { 0x2B33, \"Commend International GmbH\"  },\r\n    { 0x2B34, \"Seemahale Telecoms\"  },\r\n    { 0x2B35, \"Assem Technology Co., Ltd.\"  },\r\n    { 0x2B36, \"Dongguan City Jianghan Electronics Co., Ltd.\"  },\r\n    { 0x2B37, \"Huizhou Desay SV Automotive Co., Ltd.\"  },\r\n    { 0x2B38, \"Ningbo Rixing Electronics Co., Ltd.\"  },\r\n    { 0x2B39, \"KANAI ELECTRONIC APPLIANCE Co., Ltd.\"  },\r\n    { 0x2B3A, \"Cirrus Research plc\"  },\r\n    { 0x2B3B, \"ScriptPro, LLC\"  },\r\n    { 0x2B3C, \"Technikos Sports Inc.\"  },\r\n    { 0x2B3D, \"GuangDong YuanFeng Automotive Electroics Co., Ltd.\"  },\r\n    { 0x2B3E, \"NewAE Technology Inc.\"  },\r\n    { 0x2B3F, \"ATL-SD Co., Ltd.\"  },\r\n    { 0x2B40, \"Matsumura Engineering Co., Ltd.\"  },\r\n    { 0x2B41, \"Image Match Design Inc.\"  },\r\n    { 0x2B42, \"NEXO S.A.\"  },\r\n    { 0x2B43, \"Doro AB\"  },\r\n    { 0x2B44, \"Wildfire, Inc.\"  },\r\n    { 0x2B45, \"PRA Audio Systems, Inc.\"  },\r\n    { 0x2B46, \"Centerm Information Co., Ltd.\"  },\r\n    { 0x2B47, \"Huizhou Aorora Science & Technology Co., Ltd.\"  },\r\n    { 0x2B48, \"Sounding Audio Industrial Limited\"  },\r\n    { 0x2B49, \"GECO Incorporated\"  },\r\n    { 0x2B4A, \"Yueqing Huaxin Electronic Co., Ltd.\"  },\r\n    { 0x2B4B, \"China Hualu Group Co., Ltd.\"  },\r\n    { 0x2B4C, \"Beijing SHENQI Technology Co., Ltd.\"  },\r\n    { 0x2B4D, \"SMC Corporation\"  },\r\n    { 0x2B4E, \"Microcabin Inc.\"  },\r\n    { 0x2B4F, \"Aeroscout Ltd. (Stanley Healthcare)\"  },\r\n    { 0x2B50, \"Denchi Power Ltd.\"  },\r\n    { 0x2B51, \"Pax Instruments\"  },\r\n    { 0x2B52, \"Dongguan Evermax Electronics Technology Co., Ltd.\"  },\r\n    { 0x2B53, \"Shenzhen Supernature Multimedia Co., Ltd.\"  },\r\n    { 0x2B54, \"AMPAK Technology Inc.\"  },\r\n    { 0x2B55, \"FUJIFILM Imaging Systems Co., Ltd.\"  },\r\n    { 0x2B56, \"The Crypto Group\"  },\r\n    { 0x2B57, \"GIROPTIC\"  },\r\n    { 0x2B58, \"DJ Sound Electronics, LLC / BiZi Inc.\"  },\r\n    { 0x2B59, \"ESI Motion\"  },\r\n    { 0x2B5A, \"Universal Audio, Inc.\"  },\r\n    { 0x2B5B, \"Xiamen Home Meitu Technology Co., Ltd.\"  },\r\n    { 0x2B5C, \"B&B Exporting Limited\"  },\r\n    { 0x2B5D, \"GSL Solutions, Inc.\"  },\r\n    { 0x2B5E, \"Audio Alchemy\"  },\r\n    { 0x2B5F, \"b-plus GmbH\"  },\r\n    { 0x2B60, \"Viking Technology\"  },\r\n    { 0x2B61, \"Universal Biosensors, Inc.\"  },\r\n    { 0x2B62, \"ICP Entwicklungs GmbH\"  },\r\n    { 0x2B63, \"Inora Technologies, Inc.\"  },\r\n    { 0x2B64, \"Cyanogen Inc.\"  },\r\n    { 0x2B65, \"Atelier Vision Corporation\"  },\r\n    { 0x2B66, \"Clinton Instrument Company\"  },\r\n    { 0x2B67, \"Lifesize, Inc.\"  },\r\n    { 0x2B68, \"FLEXIM - Flexible Industriemesstechnik GmbH\"  },\r\n    { 0x2B69, \"Humax Automotive Co., Ltd.\"  },\r\n    { 0x2B6A, \"FUJI TECOM INC.\"  },\r\n    { 0x2B6B, \"Colorix SA\"  },\r\n    { 0x2B6C, \"Transbit Sp. z o.o.\"  },\r\n    { 0x2B6D, \"SATORI ELECTRIC CO., LTD.\"  },\r\n    { 0x2B6E, \"Airviz Inc.\"  },\r\n    { 0x2B6F, \"Revolution Education Ltd.\"  },\r\n    { 0x2B70, \"Micran, Research & Production Company\"  },\r\n    { 0x2B71, \"Zhejiang Flashforge 3D Technology Co., Ltd.\"  },\r\n    { 0x2B72, \"RT Corporation\"  },\r\n    { 0x2B73, \"Pioneer DJ Corporation\"  },\r\n    { 0x2B74, \"Embedded Intelligence, Inc.\"  },\r\n    { 0x2B75, \"New Matter\"  },\r\n    { 0x2B76, \"Shanghai Wingtech Electronic Technology Co., Ltd.\"  },\r\n    { 0x2B77, \"Epiphan Systems Inc.\"  },\r\n    { 0x2B78, \"Elyctis\"  },\r\n    { 0x2B79, \"Radio Sound, Inc.\"  },\r\n    { 0x2B7A, \"Spin Master Far East Ltd.\"  },\r\n    { 0x2B7B, \"Gigaset Digital Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x2B7C, \"Noveltek Semiconductor Corp.\"  },\r\n    { 0x2B7D, \"ZEITEC Semiconductor Co., Ltd.\"  },\r\n    { 0x2B7E, \"Shenzhen Kingcome Optoelectronic Co., Ltd.\"  },\r\n    { 0x2B7F, \"NanoTS Co., Ltd.\"  },\r\n    { 0x2B80, \"Miyuki Giken Co., Ltd.\"  },\r\n    { 0x2B81, \"PULAX Corporation\"  },\r\n    { 0x2B82, \"TELE RADIO AB\"  },\r\n    { 0x2B83, \"Silicon Line GmbH\"  },\r\n    { 0x2B84, \"Ever Win International Corp.\"  },\r\n    { 0x2B85, \"YICHUN YILIAN PRINT TECH CO., LTD.\"  },\r\n    { 0x2B86, \"MITSUBISHI HITACHI POWER SYSTEMS ENGINEERING CO., LTD.\"  },\r\n    { 0x2B87, \"ATP Industries Group Ltd.\"  },\r\n    { 0x2B88, \"Socionext Inc.\"  },\r\n    { 0x2B89, \"Ugreen Group Limited\"  },\r\n    { 0x2B8A, \"Shanghai Pateo Electronic Equipment Mfg. Co., Ltd.\"  },\r\n    { 0x2B8B, \"Inner Mongolia Yinan Science & Technology Dev. Co., Ltd\"  },\r\n    { 0x2B8C, \"EDGE I&D\"  },\r\n    { 0x2B8D, \"Dr. Fritz Faulhaber GmbH & Co. KG\"  },\r\n    { 0x2B8E, \"Pentair PLC\"  },\r\n    { 0x2B8F, \"DxO Labs Corp.\"  },\r\n    { 0x2B90, \"ACR Braendli & Voegeli AG\"  },\r\n    { 0x2B91, \"The Fredericks Company\"  },\r\n    { 0x2B92, \"i-BLADES, Inc.\"  },\r\n    { 0x2B93, \"Altia Systems Inc.\"  },\r\n    { 0x2B94, \"ShenZhen Baoyuanda Electronics Co., Ltd.\"  },\r\n    { 0x2B95, \"iST - Integrated Service Technology Inc.\"  },\r\n    { 0x2B96, \"HYUNDAI MOBIS Co., Ltd.\"  },\r\n    { 0x2B97, \"Digen Co., Ltd.\"  },\r\n    { 0x2B98, \"Glenair, Inc.\"  },\r\n    { 0x2B99, \"360fly, Inc.\"  },\r\n    { 0x2B9A, \"HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD.\"  },\r\n    { 0x2B9B, \"Zhongshan Aute Electronics Technology Co., Ltd.\"  },\r\n    { 0x2B9C, \"Guangdong King Link Industrial Co., Ltd.\"  },\r\n    { 0x2B9D, \"HARTING Electric GmbH & Co. KG\"  },\r\n    { 0x2B9E, \"ZPower LLC\"  },\r\n    { 0x2B9F, \"Scietera Technologies, Inc.\"  },\r\n    { 0x2BA0, \"InVue Security Products\"  },\r\n    { 0x2BA1, \"I-Sheng Electric Wire & Cable Co., Ltd.\"  },\r\n    { 0x2BA2, \"China Daheng Group Inc Beijing Image Vision Tech Branch\"  },\r\n    { 0x2BA3, \"Shenzhen FeiTianXia Technology Ltd.\"  },\r\n    { 0x2BA4, \"Shenzhen HengJia New Energy Auto Part Co., Ltd.\"  },\r\n    { 0x2BA5, \"Yueguan Network Technology (Shanghai) Co., Ltd.\"  },\r\n    { 0x2BA6, \"Cyberith GmbH\"  },\r\n    { 0x2BA7, \"77 Elektronika Kft.\"  },\r\n    { 0x2BA8, \"YUDU EASON ELECTRONIC CO., LTD.\"  },\r\n    { 0x2BA9, \"YanFeng Visteon Automotive Electronics Co., Ltd.\"  },\r\n    { 0x2BAA, \"New World Technologies Inc.\"  },\r\n    { 0x2BAB, \"Grandstream Networks, Inc.\"  },\r\n    { 0x2BAC, \"Polyera Corporation\"  },\r\n    { 0x2BAD, \"XinJi Technologies Ltd.\"  },\r\n    { 0x2BAE, \"Holinail H.K. Limited\"  },\r\n    { 0x2BAF, \"Getac Technology Corp.\"  },\r\n    { 0x2BB0, \"ITES Co., Ltd.\"  },\r\n    { 0x2BB1, \"Validata LLC\"  },\r\n    { 0x2BB2, \"HIDEX OY\"  },\r\n    { 0x2BB3, \"Elcoa Industria e Comercio Ltda\"  },\r\n    { 0x2BB4, \"PRINK Srl\"  },\r\n    { 0x2BB5, \"Silk ID Systems\"  },\r\n    { 0x2BB6, \"3D Imaging & Simulations Corp. (3DISC)\"  },\r\n    { 0x2BB7, \"Dongguan ChengXiang Industrial Co., Ltd.\"  },\r\n    { 0x2BB8, \"OCC (Zhuhai) Electronic Co., Ltd.\"  },\r\n    { 0x2BB9, \"ARGUS-SPECTRUM\"  },\r\n    { 0x2BBA, \"Sinseader Electronic Co., Ltd.\"  },\r\n    { 0x2BBB, \"DONGGUAN YELLOW KNIFE Industrial Co., Ltd.\"  },\r\n    { 0x2BBC, \"Guided Ultrasonics Ltd\"  },\r\n    { 0x2BBD, \"RF Creations Ltd.\"  },\r\n    { 0x2BBE, \"Chengyi Semiconductors (Shanghai) Co., Ltd.\"  },\r\n    { 0x2BBF, \"Shenzhen Shinning Electronic Co., Ltd.\"  },\r\n    { 0x2BC0, \"Shenzhen WFD Electronics Co., Ltd.\"  },\r\n    { 0x2BC1, \"Dongguan Sino Syncs Industrial Co., Ltd.\"  },\r\n    { 0x2BC2, \"JNTC Co., Ltd.\"  },\r\n    { 0x2BC3, \"Nihon Mechatronics Co., Ltd.\"  },\r\n    { 0x2BC4, \"SR Research Ltd.\"  },\r\n    { 0x2BC5, \"Orbbec 3D Tech. Int'l Inc.\"  },\r\n    { 0x2BC6, \"Server Technology, Inc.\"  },\r\n    { 0x2BC7, \"Zounds Hearing Inc.\"  },\r\n    { 0x2BC8, \"DONGGUAN POLIXIN ELECTRIC CO., LTD.\"  },\r\n    { 0x2BC9, \"Tama Electric (Suzhou) Co., Ltd.\"  },\r\n    { 0x2BCA, \"Exvision, Inc.\"  },\r\n    { 0x2BCB, \"Tanaka Electric Industry Co., Ltd.\"  },\r\n    { 0x2BCC, \"InoTec GmbH Organisationssysteme\"  },\r\n    { 0x2BCD, \"Keyprocessor BV\"  },\r\n    { 0x2BCE, \"UV Partners\"  },\r\n    { 0x2BCF, \"Magtrol, Inc.\"  },\r\n    { 0x2BD0, \"mophie, LLC\"  },\r\n    { 0x2BD1, \"Spectran LLC\"  },\r\n    { 0x2BD2, \"Nabtesco Corporation\"  },\r\n    { 0x2BD3, \"Dongguan ULT-unite electronic technology co., LTD\"  },\r\n    { 0x2BD4, \"JL Audio, Inc.\"  },\r\n    { 0x2BD5, \"Cable Matters Inc.\"  },\r\n    { 0x2BD6, \"CoroWare, Inc.\"  },\r\n    { 0x2BD7, \"EcuTek International Ltd.\"  },\r\n    { 0x2BD8, \"ROPEX Industrie-Elektronik GmbH\"  },\r\n    { 0x2BD9, \"Huddly\"  },\r\n    { 0x2BDA, \"Panono GmbH\"  },\r\n    { 0x2BDB, \"LOVEOX CO., LTD.\"  },\r\n    { 0x2BDC, \"Automation Electronics Inc.\"  },\r\n    { 0x2BDD, \"Charm Sciences Inc.\"  },\r\n    { 0x2BDE, \"Pickering Interfaces Limited\"  },\r\n    { 0x2BDF, \"Hangzhou Hikvision Digital Technology Co., Ltd.\"  },\r\n    { 0x2BE0, \"Fullink Technology Co., Ltd\"  },\r\n    { 0x2BE1, \"AutoChips Inc.\"  },\r\n    { 0x2BE2, \"Electric Connector Technology Co., Ltd.\"  },\r\n    { 0x2BE3, \"Hydac Electronic GmbH\"  },\r\n    { 0x2BE4, \"Cojali S.L. ES-B13210489\"  },\r\n    { 0x2BE5, \"LELTEK\"  },\r\n    { 0x2BE6, \"Dongguan KaiWin Electronics Co., Ltd.\"  },\r\n    { 0x2BE7, \"BEFS Co., Ltd.\"  },\r\n    { 0x2BE8, \"Archisite, Inc.\"  },\r\n    { 0x2BE9, \"Magneti Marelli S.p.A Electr BL\"  },\r\n    { 0x2BEA, \"Inspire Medical Systems\"  },\r\n    { 0x2BEB, \"Gateworks Corporation\"  },\r\n    { 0x2BEC, \"Lumantek Co., Ltd.\"  },\r\n    { 0x2BED, \"Econoburn LLC\"  },\r\n    { 0x2BEE, \"Ventev Mobile\"  },\r\n    { 0x2BEF, \"Quanta Storage Inc.\"  },\r\n    { 0x2BF0, \"Tech-Top Technology Limited\"  },\r\n    { 0x2BF1, \"Murakami Color Research Laboratory\"  },\r\n    { 0x2BF2, \"ABB India Limited\"  },\r\n    { 0x2BF3, \"Photek Ltd.\"  },\r\n    { 0x2BF4, \"Thunderbird International DBA Spectec\"  },\r\n    { 0x2BF5, \"Shenzhen YOOBAO Technology Co., Ltd.\"  },\r\n    { 0x2BF6, \"Shenzhen Sinotek Technology Co., Ltd.\"  },\r\n    { 0x2BF7, \"KEYW\"  },\r\n    { 0x2BF8, \"Visual Land Inc.\"  },\r\n    { 0x2BF9, \"Poynt Co.\"  },\r\n    { 0x2BFA, \"High Country Tek\"  },\r\n    { 0x2BFB, \"Strattec Advanced Logic, LLC\"  },\r\n    { 0x2BFC, \"Sulon Technologies Inc.\"  },\r\n    { 0x2BFD, \"Kinematics GmbH\"  },\r\n    { 0x2BFE, \"Novexx Solutions GmbH\"  },\r\n    { 0x2BFF, \"Shindengen Electric Mfg. Co., Ltd.\"  },\r\n    { 0x2C00, \"MEEM SL Ltd\"  },\r\n    { 0x2C01, \"Dongguan Arin Electronics Technology Co., Ltd.\"  },\r\n    { 0x2C02, \"DongGuan City JianNuo Electronics Co., Ltd.\"  },\r\n    { 0x2C03, \"Barrett Communications Pty. Ltd.\"  },\r\n    { 0x2C04, \"Shenzhen XOX Electronics Co., Ltd.\"  },\r\n    { 0x2C05, \"Protop International Inc.\"  },\r\n    { 0x2C06, \"Microsemi Semiconductor (US) Inc.\"  },\r\n    { 0x2C07, \"Webcloak LLC\"  },\r\n    { 0x2C08, \"INVECAS INC.\"  },\r\n    { 0x2C09, \"Prediktor Medical AS\"  },\r\n    { 0x2C0A, \"ATANS Technology Inc.\"  },\r\n    { 0x2C0B, \"Triple Win Precision Technology Co., Ltd.\"  },\r\n    { 0x2C0C, \"IC Realtech\"  },\r\n    { 0x2C0D, \"Embrava Pty Ltd\"  },\r\n    { 0x2C0E, \"Unity Scientific\"  },\r\n    { 0x2C0F, \"Mantra Softech (India) Pvt Ltd\"  },\r\n    { 0x2C10, \"Sinotronics Co., Ltd.\"  },\r\n    { 0x2C11, \"ALLBEST ELECTRONICS TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2C12, \"Shenzhen Xin Kai Feng Electronics Factory\"  },\r\n    { 0x2C13, \"MOST WELL Technology Corp.\"  },\r\n    { 0x2C14, \"Buffalo Memory Co., Ltd.\"  },\r\n    { 0x2C15, \"Xentris Wireless\"  },\r\n    { 0x2C16, \"Priferential Accessories Ltd\"  },\r\n    { 0x2C17, \"SVS-VISTEK GmbH\"  },\r\n    { 0x2C18, \"Euclideon Pty. Ltd.\"  },\r\n    { 0x2C19, \"Sunlike Technology Co., Ltd.\"  },\r\n    { 0x2C1A, \"Young Fast Optoelectronics Co., Ltd.\"  },\r\n    { 0x2C1B, \"ISAW Camera Inc\"  },\r\n    { 0x2C1C, \"Daesung Eltec., Ltd\"  },\r\n    { 0x2C1D, \"Makita Corporation\"  },\r\n    { 0x2C1E, \"Global Fire Equipment S.A.\"  },\r\n    { 0x2C1F, \"Cashmaster International Limited\"  },\r\n    { 0x2C20, \"Pulsar Instruments Plc.\"  },\r\n    { 0x2C21, \"Prynt Corp.\"  },\r\n    { 0x2C22, \"Qanba USA, LLC\"  },\r\n    { 0x2C23, \"Super Micro Computer Inc.\"  },\r\n    { 0x2C24, \"SONOTEC Ultraschallsensorik Halle GmbH\"  },\r\n    { 0x2C25, \"Shanghai TAIDU INTELLIGENT TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2C26, \"Micromax International Corporation\"  },\r\n    { 0x2C27, \"YAWATA Electric Industrial Co., Ltd.\"  },\r\n    { 0x2C28, \"Granite River Labs Japan Ltd.\"  },\r\n    { 0x2C29, \"Coagent Enterprise Limited\"  },\r\n    { 0x2C2A, \"LEIA Inc.\"  },\r\n    { 0x2C2B, \"NetScout Systems, Inc.\"  },\r\n    { 0x2C2C, \"Fortify Technologies, LLC\"  },\r\n    { 0x2C2D, \"Shenzhen Ebull Technology Limited\"  },\r\n    { 0x2C2E, \"Hualun Technology Co., Ltd.\"  },\r\n    { 0x2C2F, \"Sensel, Inc.\"  },\r\n    { 0x2C30, \"Ariadne's Thread (USA), Inc. dba Immerex\"  },\r\n    { 0x2C31, \"tinnos\"  },\r\n    { 0x2C32, \"MCS Micronic Computer Systeme GmbH\"  },\r\n    { 0x2C33, \"Shinobiya.com Co., Ltd.\"  },\r\n    { 0x2C34, \"Xerox Business Services (Switzerland) AG\"  },\r\n    { 0x2C35, \"Decto, Inc.\"  },\r\n    { 0x2C36, \"Bonsai Lab, Inc.\"  },\r\n    { 0x2C37, \"Shenzhen Adition Audio Science & Technology Co., Ltd.\"  },\r\n    { 0x2C38, \"Goldenconn Electronics Technology (Suzhou) Co., Ltd.\"  },\r\n    { 0x2C39, \"JIB Electronics Technology Co., Ltd.\"  },\r\n    { 0x2C3A, \"Changzhou Shinco Automotive Electronics Co., Ltd.\"  },\r\n    { 0x2C3B, \"Shenzhen Hangsheng Electronics Corp., Ltd.\"  },\r\n    { 0x2C3C, \"Beartooth Radio, Inc.\"  },\r\n    { 0x2C3D, \"Audience, A Knowles Company\"  },\r\n    { 0x2C3E, \"Verizon Telematics, Inc.\"  },\r\n    { 0x2C3F, \"Nextbit Systems, Inc.\"  },\r\n    { 0x2C40, \"Leadtrend\"  },\r\n    { 0x2C41, \"Adaptertek Technology Co., Ltd.\"  },\r\n    { 0x2C42, \"Feature Integration Technology Inc.\"  },\r\n    { 0x2C43, \"Avegant Corporation\"  },\r\n    { 0x2C44, \"Digital Design Corporation\"  },\r\n    { 0x2C45, \"Reid Heath Ltd.\"  },\r\n    { 0x2C46, \"Soehnle Industrial Solutions GmbH\"  },\r\n    { 0x2C47, \"Chunghsin International Electronics Co., Ltd.\"  },\r\n    { 0x2C48, \"Delphi Electrical Centers (Shanghai) Co., Ltd.\"  },\r\n    { 0x2C49, \"Chikuma Seiki Co., Ltd.\"  },\r\n    { 0x2C4A, \"System Industrie Electronic GmbH\"  },\r\n    { 0x2C4B, \"Huntleigh Healthcare Ltd.\"  },\r\n    { 0x2C4C, \"Double Robotics, Inc.\"  },\r\n    { 0x2C4D, \"VVETEK DOO\"  },\r\n    { 0x2C4E, \"Mercusys Technologies Co., Limited\"  },\r\n    { 0x2C4F, \"Canon Electronic Business Machines (H.K.) Co., Ltd.\"  },\r\n    { 0x2C50, \"Vinghog AS\"  },\r\n    { 0x2C51, \"Lambda Acoustic\"  },\r\n    { 0x2C52, \"Comio Communication Co., Ltd.\"  },\r\n    { 0x2C53, \"Huizhou Foryou General Electronics Co., Ltd.\"  },\r\n    { 0x2C54, \"LifeWatch Technologies Ltd.\"  },\r\n    { 0x2C55, \"Magicleap\"  },\r\n    { 0x2C56, \"Pocket Radar Inc.\"  },\r\n    { 0x2C57, \"BMT Messtechnik GmbH\"  },\r\n    { 0x2C58, \"Dyden Corporation\"  },\r\n    { 0x2C59, \"EBARA CORPORATION\"  },\r\n    { 0x2C5A, \"Mobilus Automotive Inc\"  },\r\n    { 0x2C5B, \"Shenglan Technology Co. Ltd\"  },\r\n    { 0x2C5C, \"Neusoft Corporation\"  },\r\n    { 0x2C5D, \"SIP Simya Electronics Technology Co., Ltd.\"  },\r\n    { 0x2C5E, \"ELVES Automotive Co., Ltd\"  },\r\n    { 0x2C5F, \"YOODS Co., Ltd.\"  },\r\n    { 0x2C60, \"Sirin LABS AG\"  },\r\n    { 0x2C61, \"Jadmam Corporation dba: Boytone\"  },\r\n    { 0x2C62, \"Trice Medical\"  },\r\n    { 0x2C63, \"Electronica Steren, S.A. de C.V.\"  },\r\n    { 0x2C64, \"Creaform Inc. (Ametek Ultra Precision Technologies)\"  },\r\n    { 0x2C65, \"Nokia Technologies\"  },\r\n    { 0x2C66, \"EMOTIQ srl\"  },\r\n    { 0x2C67, \"VentureCraft, Ltd.\"  },\r\n    { 0x2C68, \"EMRight Technology Co., Ltd.\"  },\r\n    { 0x2C69, \"BBPOS Limited\"  },\r\n    { 0x2C6A, \"Joint Stock Company Research Centre Module\"  },\r\n    { 0x2C6B, \"System JD Co., Ltd\"  },\r\n    { 0x2C6C, \"Nano TouchSystems co., Ltd.\"  },\r\n    { 0x2C6D, \"Gibson Innovations\"  },\r\n    { 0x2C6E, \"Shen Zhen Xian Shuo Technology Co. Ltd.\"  },\r\n    { 0x2C6F, \"PST Eletronica LTDA\"  },\r\n    { 0x2C70, \"PERI, Inc.\"  },\r\n    { 0x2C71, \"Bozhou BoTong Information Technology Co., Ltd.\"  },\r\n    { 0x2C72, \"BlueberryE GmbH\"  },\r\n    { 0x2C73, \"Qiku Internet Network Scientific (Shenzhen) Co., Ltd.\"  },\r\n    { 0x2C74, \"CJSC Nordavind\"  },\r\n    { 0x2C75, \"Net And Print Inc.\"  },\r\n    { 0x2C76, \"DATAPATH LTD\"  },\r\n    { 0x2C77, \"Profindustry GmbH\"  },\r\n    { 0x2C78, \"BRAGI GmbH\"  },\r\n    { 0x2C79, \"WAWGD, Inc. (DBA: Foresight Sports)\"  },\r\n    { 0x2C7A, \"AutoNavi Software Co., Ltd.\"  },\r\n    { 0x2C7B, \"Beijing ASU Tech Co., Ltd.\"  },\r\n    { 0x2C7C, \"Anysmart Technologies Co., Ltd.\"  },\r\n    { 0x2C7D, \"Shenzhen Protruly Electronic Co., Ltd.\"  },\r\n    { 0x2C7E, \"Dongguan Allpass Electronic Co., Ltd.\"  },\r\n    { 0x2C7F, \"SHENZHEN D-VITEC INDUSTRIAL CO., LTD.\"  },\r\n    { 0x2C80, \"motomobile AG\"  },\r\n    { 0x2C81, \"Indie Semiconductor\"  },\r\n    { 0x2C82, \"Cloud9 Technologies LLC\"  },\r\n    { 0x2C83, \"LRP electronic GmbH\"  },\r\n    { 0x2C84, \"Innodezign MauRitius Limited\"  },\r\n    { 0x2C85, \"Audientes\"  },\r\n    { 0x2C86, \"Ultraflux\"  },\r\n    { 0x2C87, \"ISKN\"  },\r\n    { 0x2C88, \"K-Tronic SRL\"  },\r\n    { 0x2C89, \"Younes Medical Technologies\"  },\r\n    { 0x2C8A, \"Advanced Casino Electronics\"  },\r\n    { 0x2C8B, \"Huizhou Dehong Technology Co., Ltd.\"  },\r\n    { 0x2C8C, \"PowerCenter Technology Limited\"  },\r\n    { 0x2C8D, \"Mizco International, Inc.\"  },\r\n    { 0x2C8E, \"Unique Secure Limited\"  },\r\n    { 0x2C8F, \"Regulus Company Ltd.\"  },\r\n    { 0x2C90, \"I. AM. PLUS, LLC\"  },\r\n    { 0x2C91, \"Corigine, Inc.\"  },\r\n    { 0x2C92, \"Ningbo Yinzhou Shengke Electronics Co., Ltd.\"  },\r\n    { 0x2C93, \"SWFL Inc. dba: Filament\"  },\r\n    { 0x2C94, \"HIRATSUKA Engineering Co., Ltd.\"  },\r\n    { 0x2C95, \"TOSHIBA MACHINE CO., LTD.\"  },\r\n    { 0x2C96, \"KBS Industrieelektronik GmbH\"  },\r\n    { 0x2C97, \"LEDGER\"  },\r\n    { 0x2C98, \"Fosfomatic Technology LLC\"  },\r\n    { 0x2C99, \"Prusa Research s.r.o.\"  },\r\n    { 0x2C9A, \"Lawo AG\"  },\r\n    { 0x2C9B, \"SPECIM, Spectral Imaging Ltd.\"  },\r\n    { 0x2C9C, \"Vayyar Imaging LTD.\"  },\r\n    { 0x2C9D, \"Nod Inc.\"  },\r\n    { 0x2C9E, \"Shanghai Linguo Technology Co.,Ltd.\"  },\r\n    { 0x2C9F, \"e-Smart Systems Pvt. Ltd.\"  },\r\n    { 0x2CA0, \"Leagtech Jiangxi Electronic Co., Ltd.\"  },\r\n    { 0x2CA1, \"Veetone Technologies Limited\"  },\r\n    { 0x2CA2, \"GuangZhou MingPing Electronics Technology\"  },\r\n    { 0x2CA3, \"DJI Technology Co., Ltd.\"  },\r\n    { 0x2CA4, \"Shenzhen Alex Technology Co., Ltd.\"  },\r\n    { 0x2CA5, \"Fussen Technology Co., Ltd.\"  },\r\n    { 0x2CA6, \"Dai-ichi Dentsu Ltd.\"  },\r\n    { 0x2CA7, \"Heptagon Advanced Micro Optics\"  },\r\n    { 0x2CA8, \"STATSports\"  },\r\n    { 0x2CA9, \"JITS TECHNOLOGY CO., LIMITED\"  },\r\n    { 0x2CAA, \"LIVV Brand llc\"  },\r\n    { 0x2CAB, \"AppWorld S. de R.L. de C.V.\"  },\r\n    { 0x2CAC, \"MGF Sviesos Konversija, UAB\"  },\r\n    { 0x2CAD, \"EMS Security Group Ltd.\"  },\r\n    { 0x2CAE, \"Clyde Broadcast Products Ltd.\"  },\r\n    { 0x2CAF, \"IDS GmbH\"  },\r\n    { 0x2CB0, \"Creative bits Solutions\"  },\r\n    { 0x2CB1, \"Avista Corporation\"  },\r\n    { 0x2CB2, \"NAGANO KEIKI CO., LTD.\"  },\r\n    { 0x2CB3, \"Shenzhen Bolin Image Science Technology Co., Ltd.\"  },\r\n    { 0x2CB4, \"Ava Enterprises, Inc. dba Boss Audio Systems\"  },\r\n    { 0x2CB5, \"SUS Corp.\"  },\r\n    { 0x2CB6, \"Borqs Hong Kong Limited\"  },\r\n    { 0x2CB7, \"Fibocom Wireless Inc.\"  },\r\n    { 0x2CB8, \"Shenzhen Sydixon Electronic Technology Co., Ltd.\"  },\r\n    { 0x2CB9, \"On-Bright Electronics (Shanghai) Co., Ltd.\"  },\r\n    { 0x2CBA, \"Dongguan Puxu Industrial Co., Ltd.\"  },\r\n    { 0x2CBB, \"Shenzhen Soling Indusrtial Co., Ltd.\"  },\r\n    { 0x2CBD, \"EGGCYTE, INC.\"  },\r\n    { 0x2CBE, \"uQontrol\"  },\r\n    { 0x2CBF, \"Donggguan Yuhua Electronic Co., Ltd.\"  },\r\n    { 0x2CC0, \"Hangzhou Zero Zero Technology Co., Ltd.\"  },\r\n    { 0x2CC1, \"SIGFOX\"  },\r\n    { 0x2CC2, \"Lautsprecher Teufel GmbH\"  },\r\n    { 0x2CC3, \"A-VEKT K.K.\"  },\r\n    { 0x2CC4, \"Sanden Advanced Technology Corporation\"  },\r\n    { 0x2CC5, \"Metatronics\"  },\r\n    { 0x2CC6, \"Prodigy Technovations Pvt Ltd\"  },\r\n    { 0x2CC7, \"EmergiTech, Inc\"  },\r\n    { 0x2CC8, \"Hewlett Packard Enterprise\"  },\r\n    { 0x2CC9, \"Monolithic Power Systems Inc.\"  },\r\n    { 0x2CCA, \"Amphenol Advanced Sensors\"  },\r\n    { 0x2CCB, \"USB Memory Direct\"  },\r\n    { 0x2CCC, \"Silicon Mitus Inc.\"  },\r\n    { 0x2CCD, \"ITOS Inc.\"  },\r\n    { 0x2CCE, \"SMARTY Performance King SA\"  },\r\n    { 0x2CCF, \"Hypersecu Information Systems, Inc.\"  },\r\n    { 0x2CD0, \"Technics Global Electronics & JCE Co., Ltd.\"  },\r\n    { 0x2CD1, \"Tamron Co., Ltd.\"  },\r\n    { 0x2CD2, \"Mikrotikls S/A\"  },\r\n    { 0x2CD3, \"Life Robotics Inc.\"  },\r\n    { 0x2CD4, \"NGK SPARK PLUG CO., LTD.\"  },\r\n    { 0x2CD5, \"Institut Dr. Foerster GmbH & Co. KG\"  },\r\n    { 0x2CD6, \"Immersive Media\"  },\r\n    { 0x2CD7, \"Cosemi Technologies Inc.\"  },\r\n    { 0x2CD8, \"Nanoport Technology, Inc.\"  },\r\n    { 0x2CD9, \"Cambrionix Ltd\"  },\r\n    { 0x2CDA, \"CXUN Co. Ltd.\"  },\r\n    { 0x2CDB, \"China Tsp Inc\"  },\r\n    { 0x2CDC, \"Sea & Sun Technology GmbH\"  },\r\n    { 0x2CDD, \"IAI Corporation\"  },\r\n    { 0x2CDE, \"RTI International\"  },\r\n    { 0x2CDF, \"Tecno Alarm S.R.L.\"  },\r\n    { 0x2CE0, \"iClassmate Educational Technologies Co., Ltd.\"  },\r\n    { 0x2CE1, \"Gradus Group\"  },\r\n    { 0x2CE2, \"Yanfeng Visteon (Chongqing) Automotive Electronics Co\"  },\r\n    { 0x2CE3, \"Alcorlink Corp.\"  },\r\n    { 0x2CE4, \"ISBC Ltd.\"  },\r\n    { 0x2CE5, \"InX8 Inc dba AKiTiO\"  },\r\n    { 0x2CE6, \"SDAN Tecchnology Co., Ltd.\"  },\r\n    { 0x2CE7, \"Lemobile Information Technology (Beijing) Co., Ltd.\"  },\r\n    { 0x2CE8, \"DongGuan Hongweixiang Electronic Technology Co., Ltd.\"  },\r\n    { 0x2CE9, \"Suzhu Jingshi Electronic Technology Co., Ltd.\"  },\r\n    { 0x2CEA, \"Zhong Shan City Richsound Electronic Industrial Ltd.\"  },\r\n    { 0x2CEB, \"Dongguang Kangbang Electronics Co., Ltd.\"  },\r\n    { 0x2CEC, \"Ascon Tecnologic\"  },\r\n    { 0x2CED, \"KMC Controls, Inc.\"  },\r\n    { 0x2CEE, \"Winpower Qmadix Technology Co., Ltd.\"  },\r\n    { 0x2CEF, \"Toptest Technologies Co., Ltd.\"  },\r\n    { 0x2CF0, \"Nuand, LLC\"  },\r\n    { 0x2CF1, \"DTS, Inc.\"  },\r\n    { 0x2CF2, \"KUNSHAN DLK Electronics Technology Co., Ltd.\"  },\r\n    { 0x2CF3, \"Konekt, Inc.\"  },\r\n    { 0x2CF4, \"CAM2 Technologies, LLC dba: Czitek\"  },\r\n    { 0x2CF5, \"EBARA REFRIGERATION EQUIPMENT & SYSTEMS CO., LTD.\"  },\r\n    { 0x2CF6, \"Eye-Fi, Inc.\"  },\r\n    { 0x2CF7, \"PPST, Inc.\"  },\r\n    { 0x2CF8, \"Itron\"  },\r\n    { 0x2CF9, \"Terrafix Ltd.\"  },\r\n    { 0x2CFA, \"Meta Company\"  },\r\n    { 0x2CFB, \"Nanchang Haozhun Electronics Co., Ltd.\"  },\r\n    { 0x2CFC, \"DeLaval International AB\"  },\r\n    { 0x2CFD, \"GoerTek Inc.\"  },\r\n    { 0x2CFE, \"Alpha Data Parallel Systems\"  },\r\n    { 0x2CFF, \"ITHAKi\"  },\r\n    { 0x2D00, \"VDO Cyclecomputing, Cycle Parts GmbH\"  },\r\n    { 0x2D01, \"Gopod Group Limited\"  },\r\n    { 0x2D02, \"Zhi Sheng Electronics Technology Co., Ltd.\"  },\r\n    { 0x2D03, \"ECCO Safety Group\"  },\r\n    { 0x2D05, \"Technology Solutions (UK) Limited\"  },\r\n    { 0x2D06, \"Jireh Industries Ltd.\"  },\r\n    { 0x2D07, \"MSI.TOKYO, Inc.\"  },\r\n    { 0x2D08, \"ZIT Ltd.\"  },\r\n    { 0x2D09, \"Dongguan Evervictory Electronic Co., Ltd.\"  },\r\n    { 0x2D0A, \"Kingsignal Technology Co., Ltd.\"  },\r\n    { 0x2D0B, \"IPD CO., LTD\"  },\r\n    { 0x2D0C, \"B & P Automation Dynamics Ltd\"  },\r\n    { 0x2D0D, \"Star Vision Electronics Limited\"  },\r\n    { 0x2D0E, \"Linxee (Beijing) Technology LTD.\"  },\r\n    { 0x2D0F, \"M8TRIX TECH LLC\"  },\r\n    { 0x2D10, \"Shenzhen San Guan Si Yuan Technology Limited\"  },\r\n    { 0x2D11, \"Servelec Technologies\"  },\r\n    { 0x2D12, \"SICPA Security Solutions SA\"  },\r\n    { 0x2D13, \"DONG GUAN EBEN ELECTRONIC CO., LTD\"  },\r\n    { 0x2D14, \"Palit Microsystems Ltd\"  },\r\n    { 0x2D15, \"Si-Ware Systems\"  },\r\n    { 0x2D16, \"DONGGUAN WELLINK ELECTRONIC CO., LTD.\"  },\r\n    { 0x2D17, \"TECHVIWIN INTERNATIONAL (HONGKONG) LIMITED\"  },\r\n    { 0x2D18, \"Hui Zhou Kai Yue Electronics Co., Ltd\"  },\r\n    { 0x2D19, \"Churchill Navigation\"  },\r\n    { 0x2D1A, \"Phononic\"  },\r\n    { 0x2D1B, \"Suzhou Yourfriend Electronic Co., Ltd.\"  },\r\n    { 0x2D1C, \"Club 3D BV\"  },\r\n    { 0x2D1D, \"Design Pool Limited\"  },\r\n    { 0x2D1E, \"Excalibur\"  },\r\n    { 0x2D1F, \"Wacom Taiwan Information Co. Ltd.\"  },\r\n    { 0x2D20, \"UL LLC\"  },\r\n    { 0x2D21, \"Koozyt, Inc.\"  },\r\n    { 0x2D22, \"SEIKOSHA Co., Ltd.\"  },\r\n    { 0x2D23, \"Shenzhen Microtest Automation Co., Ltd.\"  },\r\n    { 0x2D24, \"Warwick Audio Technologies Ltd\"  },\r\n    { 0x2D25, \"Kronegger GmbH\"  },\r\n    { 0x2D26, \"Greenfield Technology\"  },\r\n    { 0x2D27, \"Global Optics Limited\"  },\r\n    { 0x2D28, \"Beijing ANTVR Technology Co., LTD\"  },\r\n    { 0x2D29, \"Beijing Baofengmojing Technologies Co. Ltd\"  },\r\n    { 0x2D2A, \"Shenzhen ZDT Technology Co., LTD\"  },\r\n    { 0x2D2B, \"STYL Solutions Pte Ltd\"  },\r\n    { 0x2D2C, \"Tankya Developing Co., Limited\"  },\r\n    { 0x2D2D, \"Guangzhou Botao Information Technology Co., Ltd\"  },\r\n    { 0x2D2E, \"Hieyoung International (Hong Kong) Limited\"  },\r\n    { 0x2D2F, \"PT Phototechnics AG\"  },\r\n    { 0x2D30, \"Addasound Denmark A/S\"  },\r\n    { 0x2D31, \"Synox Tech Co., Ltd.\"  },\r\n    { 0x2D32, \"JR Technik Co., Ltd.\"  },\r\n    { 0x2D33, \"Elysia-raytest GmbH\"  },\r\n    { 0x2D34, \"Nureva Inc.\"  },\r\n    { 0x2D35, \"SIGMA TECH. CO., LTD\"  },\r\n    { 0x2D36, \"Blu5 View Pte. Ltd.\"  },\r\n    { 0x2D37, \"Xprinter Co., Ltd\"  },\r\n    { 0x2D38, \"Shanghai OXi Technology Co., Ltd\"  },\r\n    { 0x2D39, \"Roofer Technology (Shenzhen) Co. Ltd\"  },\r\n    { 0x2D3A, \"Le Touch (Shenzhen) Electronics Co., Ltd.\"  },\r\n    { 0x2D3B, \"Lencheng Electronics Co., Ltd\"  },\r\n    { 0x2D3C, \"FOVE, Inc.\"  },\r\n    { 0x2D3D, \"Battlespace Simulations, Inc.\"  },\r\n    { 0x2D3E, \"Technica Del Arte BV\"  },\r\n    { 0x2D3F, \"ViCentra B.V.\"  },\r\n    { 0x2D40, \"Beijing Pico Technology Co., Ltd.\"  },\r\n    { 0x2D41, \"Dongguan Mankind Plastic Electronics Co., Ltd\"  },\r\n    { 0x2D42, \"Protech Electronics & Technology Limited\"  },\r\n    { 0x2D43, \"OSSIC Corporation\"  },\r\n    { 0x2D44, \"FAMAR FUEGUINA S.A.\"  },\r\n    { 0x2D45, \"JSC TION SMART MICROCLIMATE\"  },\r\n    { 0x2D46, \"JSC Yukon Advanced Optics Worldwide\"  },\r\n    { 0x2D47, \"INVENCO GROUP LIMITED\"  },\r\n    { 0x2D48, \"StarBridge, Inc.\"  },\r\n    { 0x2D49, \"Shanghai Deepoon Technology Co., Ltd.\"  },\r\n    { 0x2D4A, \"Helioway Enterprises Co., Ltd\"  },\r\n    { 0x2D4B, \"Dongguan Hongwei Electronics Co.,Ltd\"  },\r\n    { 0x2D4C, \"Ixtra Tech Inc\"  },\r\n    { 0x2D4D, \"Razer Inc\"  },\r\n    { 0x2D4E, \"Electronic Equipment BV\"  },\r\n    { 0x2D4F, \"Dongguan Hanker Electronic Technology Co., Ltd.\"  },\r\n    { 0x2D50, \"CryLaS - Crystal Laser Systems GmbH\"  },\r\n    { 0x2D51, \"NITTA Corporation\"  },\r\n    { 0x2D52, \"YiQin Electronics Co.,Ltd\"  },\r\n    { 0x2D53, \"OWOW Products B.V.\"  },\r\n    { 0x2D54, \"C-Smartlink Information Technology Co., Ltd.\"  },\r\n    { 0x2D55, \"Nagravision SA\"  },\r\n    { 0x2D56, \"DongGuan Kelta Electro Mechanical Products CO, LTD\"  },\r\n    { 0x2D58, \"Lyra Semiconductor Incorporated\"  },\r\n    { 0x2D59, \"Sunyking Technology Co., Ltd\"  },\r\n    { 0x2D5A, \"Shenzhen YAAN Precision Connector Co., Ltd.\"  },\r\n    { 0x2D5B, \"SunTo Technology (Shen Zhen) Corporation Limited\"  },\r\n    { 0x2D5C, \"Daiwoo Electronics Lo., LTD\"  },\r\n    { 0x2D5D, \"Loctek Ergonomic Technology Corp.\"  },\r\n    { 0x2D5E, \"Sky UK Limited\"  },\r\n    { 0x2D5F, \"Shanghai Yuewen information technology Co., Ltd.\"  },\r\n    { 0x2D60, \"Comarch S.A.\"  },\r\n    { 0x2D61, \"Shenzhen Hongjixin Plastic & Electronics Co., Ltd\"  },\r\n    { 0x2D62, \"Weifang Genius Electronics Co.,Ltd.\"  },\r\n    { 0x2D63, \"Cable Technology Corp.\"  },\r\n    { 0x2D64, \"H.D.T. S.R.L\"  },\r\n    { 0x2D65, \"DPA Microphones\"  },\r\n    { 0x2D66, \"Oley Company Limited\"  },\r\n    { 0x2D67, \"Fengfan (Suzhou) Audio Technology Co., Ltd.\"  },\r\n    { 0x2D68, \"Lumulabs d.o.o.\"  },\r\n    { 0x2D6A, \"AIPHONE Co., LTD\"  },\r\n    { 0x2D6B, \"NetUP Inc.\"  },\r\n    { 0x2D6C, \"Sphericam Inc.\"  },\r\n    { 0x2D6D, \"Shenzhen HaiWei Technology Co., LTD\"  },\r\n    { 0x2D6E, \"Jiangsu Jing Lian Electronic Technology Co., Ltd\"  },\r\n    { 0x2D6F, \"Tobii Dynavox\"  },\r\n    { 0x2D70, \"Zhongshan Winner Electronic Technology CO., LTD\"  },\r\n    { 0x2D71, \"OVERKIZ\"  },\r\n    { 0x2D72, \"DOGAWIST - Investment GmbH\"  },\r\n    { 0x2D73, \"XtremeMac Sarl\"  },\r\n    { 0x2D74, \"CMO America; dba ZipKord Solutions\"  },\r\n    { 0x2D75, \"Shenzhen Taiji Electronics Co., Ltd.\"  },\r\n    { 0x2D76, \"SiliConch Systems Private Limited\"  },\r\n    { 0x2D77, \"SweDeltaco AB\"  },\r\n    { 0x2D78, \"Dental Imaging Technology Corporation\"  },\r\n    { 0x2D79, \"Shenzhen Legendary Technologies Co., LTD.\"  },\r\n    { 0x2D7A, \"Dongguan JingFeng Electronics Technology Co., Ltd\"  },\r\n    { 0x2D7B, \"Panasonic Lighting Americas, Inc.\"  },\r\n    { 0x2D7C, \"Dongguan City Qingda Electronic Co., Ltd.\"  },\r\n    { 0x2D7D, \"Televes S.A.\"  },\r\n    { 0x2D7E, \"NISSIN ELECTRIC Corporation\"  },\r\n    { 0x2D7F, \"Sinar Photography AG\"  },\r\n    { 0x2D80, \"Pendo Technology China Corporation\"  },\r\n    { 0x2D81, \"Evollve Inc.\"  },\r\n    { 0x2D82, \"boud\"  },\r\n    { 0x2D84, \"Zhuhai J-Speed Technology Co., Ltd.\"  },\r\n    { 0x2D85, \"Asahi Electronics Laboratory\"  },\r\n    { 0x2D86, \"Dongguan Team Force Electronic Co., Ltd\"  },\r\n    { 0x2D87, \"Zhuhai Spark Electronic Equipment Co., Ltd\"  },\r\n    { 0x2D88, \"Prinics Co., Ltd.\"  },\r\n    { 0x2D89, \"Ekahau\"  },\r\n    { 0x2D8A, \"I-O Conn (GuangDong) Technologies Co., Ltd\"  },\r\n    { 0x2D8B, \"Eclatkey Semiconductor Technology Company Limited\"  },\r\n    { 0x2D8C, \"Hongrida Electronic Technology Co. LTD\"  },\r\n    { 0x2D8D, \"MISUMI Corporation\"  },\r\n    { 0x2D8E, \"Color Sentinel Systems, LLC\"  },\r\n    { 0x2D8F, \"Shenzhen Bing Chuang Wei Technology Co., Ltd.\"  },\r\n    { 0x2D90, \"Humanplus\"  },\r\n    { 0x2D91, \"SDI Technologies Inc.\"  },\r\n    { 0x2D92, \"Shanghai Fengtian Electronic Co., LTD.\"  },\r\n    { 0x2D93, \"STK TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2D94, \"TokenWorks Inc.\"  },\r\n    { 0x2D95, \"Vivo Mobile Communication Co., Ltd.\"  },\r\n    { 0x2D96, \"SHENZHEN WAMAXLINK ELECTRONIC TECHNOLOGY CO., LTD\"  },\r\n    { 0x2D97, \"Dong Guan JingHe Electronics Technology Co., Ltd\"  },\r\n    { 0x2D98, \"Shenzhen Ruiming Technology Co., Ltd.\"  },\r\n    { 0x2D99, \"Edifier International Limited\"  },\r\n    { 0x2D9A, \"Jiangsu GuoGuang Electronic Information Technology Co.,\"  },\r\n    { 0x2D9B, \"iStorage Limited\"  },\r\n    { 0x2D9C, \"Global Connector Technology\"  },\r\n    { 0x2D9D, \"Dongguan Suntes Electronics Technology Co., Ltd.\"  },\r\n    { 0x2D9E, \"Sivantos GmbH\"  },\r\n    { 0x2D9F, \"SABRENT\"  },\r\n    { 0x2DA0, \"IN-VISION Digital Imaging Optics GmbH\"  },\r\n    { 0x2DA1, \"Koden Electronics Co., Ltd\"  },\r\n    { 0x2DA2, \"CIMA SPA con socio unico\"  },\r\n    { 0x2DA3, \"Superior Communications\"  },\r\n    { 0x2DA4, \"GE Multilin\"  },\r\n    { 0x2DA5, \"Tokai Rika Create Corporation\"  },\r\n    { 0x2DA6, \"SiChuan Rui Thai Electronic Technology Co., Ltd.\"  },\r\n    { 0x2DA7, \"Topland Corporation\"  },\r\n    { 0x2DA8, \"Harmonic Drive Systems Inc.\"  },\r\n    { 0x2DA9, \"ELECTRONIC ASSEMBLY GmbH\"  },\r\n    { 0x2DAA, \"Shenzhen Jing Tuo Jin Electronics Co., Ltd.\"  },\r\n    { 0x2DAB, \"CYD Electronics (Shenzhen) Co., Ltd.\"  },\r\n    { 0x2DAC, \"Shenzhen YZB Electronics Technology Co., Ltd\"  },\r\n    { 0x2DAD, \"GoerTek Dynaudio Co., Ltd\"  },\r\n    { 0x2DAE, \"Hex Technology Limited\"  },\r\n    { 0x2DAF, \"IF Link Electronics Co Limited\"  },\r\n    { 0x2DB0, \"Shenzhen Welltech Cable Co., Ltd\"  },\r\n    { 0x2DB1, \"DongGuan Greatek Electronics Technology Co., LTD\"  },\r\n    { 0x2DB2, \"Imperx, Inc\"  },\r\n    { 0x2DB3, \"i Digital Galaxy Ltd.\"  },\r\n    { 0x2DB4, \"Dongguan Changtuo Hardware Technology Co., Ltd.\"  },\r\n    { 0x2DB5, \"Fuji Ceramics Corporation\"  },\r\n    { 0x2DB6, \"Kunshan 3e Electronics Co., Ltd.\"  },\r\n    { 0x2DB7, \"Premium Sound Solutions Sdn. Bhd.\"  },\r\n    { 0x2DB8, \"Foshan Yami Electric Ltd.\"  },\r\n    { 0x2DB9, \"Danelec Marine A/S\"  },\r\n    { 0x2DBA, \"Houwa System Design, k.k\"  },\r\n    { 0x2DBB, \"Huajie IMI Technology Co., Ltd.\"  },\r\n    { 0x2DBC, \"Mikroelektronika d.o.o\"  },\r\n    { 0x2DBD, \"Shanghai Xiaoyi Technology Co., Ltd\"  },\r\n    { 0x2DBE, \"MA Lighting Technology GmbH\"  },\r\n    { 0x2DBF, \"Tul Corporation\"  },\r\n    { 0x2DC0, \"Chipsea Technologies (Shenzhen) Corp\"  },\r\n    { 0x2DC1, \"littleBits\"  },\r\n    { 0x2DC2, \"MintWave Co., Ltd.\"  },\r\n    { 0x2DC3, \"Action Industries (M) SDN BHD\"  },\r\n    { 0x2DC4, \"Six 15 Technologies\"  },\r\n    { 0x2DC5, \"Cytek Biosciences, Inc.\"  },\r\n    { 0x2DC6, \"Dongguan Kingtron Electronics Technology Co., Ltd.\"  },\r\n    { 0x2DC7, \"Lacroix Sofrel\"  },\r\n    { 0x2DC8, \"8BITDO TECHNOLOGY HK LIMITED\"  },\r\n    { 0x2DC9, \"3T B.V.\"  },\r\n    { 0x2DCA, \"OEM Systems Co., Ltd.\"  },\r\n    { 0x2DCB, \"i-Money Technology Co., Ltd.\"  },\r\n    { 0x2DCC, \"Suzhou Keda Technology Co., Ltd.\"  },\r\n    { 0x2DCD, \"Yeonho Electronics\"  },\r\n    { 0x2DCE, \"Shen Zhen Farmer Technology Co., Limited\"  },\r\n    { 0x2DCF, \"Dialog Semiconductor (UK) Ltd\"  },\r\n    { 0x2DD0, \"iBaby Labs, Inc\"  },\r\n    { 0x2DD1, \"Empathy Co., Ltd.\"  },\r\n    { 0x2DD2, \"HARNICS Co., LTD.\"  },\r\n    { 0x2DD3, \"Viscell, LLC\"  },\r\n    { 0x2DD5, \"Gingy Technology Inc.\"  },\r\n    { 0x2DD6, \"Suzhou SuperMax Smart System Co., Ltd.\"  },\r\n    { 0x2DD7, \"enRoute Co., Ltd.\"  },\r\n    { 0x2DD8, \"Perception Sensors and Instrumentation Ltd\"  },\r\n    { 0x2DD9, \"Dong Guan Fei Tai Electronics CO., LTD.\"  },\r\n    { 0x2DDA, \"Miura Systems Ltd\"  },\r\n    { 0x2DDB, \"Shenzhen DAK Technology Co., Ltd\"  },\r\n    { 0x2DDC, \"Audiolink Co., Ltd\"  },\r\n    { 0x2DDD, \"Princeton Infrared Technologies, Inc.\"  },\r\n    { 0x2DDE, \"The Chamberlain Group, Inc.\"  },\r\n    { 0x2DDF, \"BOMTECH ELECTRONICS CO., LTD.\"  },\r\n    { 0x2DE0, \"Active-semi, Inc\"  },\r\n    { 0x2DE1, \"Jiang Su Denseting Precision Technology Co., Ltd.\"  },\r\n    { 0x2DE2, \"PathPartner Technology Pvt. Ltd\"  },\r\n    { 0x2DE3, \"Shanghai Yitu Technology Co., Ltd.\"  },\r\n    { 0x2DE4, \"Best Case and Accessories, Inc.\"  },\r\n    { 0x2DE5, \"KaiJet Technology International Limited, Inc. dba j5create\"  },\r\n    { 0x2DE6, \"Amazon Fulfillment Services, Inc.\"  },\r\n    { 0x2DE7, \"The LightCo, Inc.\"  },\r\n    { 0x2DE8, \"Shenzhen City Xiaoduan Electrical Co., LTD.\"  },\r\n    { 0x2DE9, \"CAR MATE MFG. CO., LTD.\"  },\r\n    { 0x2DEA, \"LightFactor\"  },\r\n    { 0x2DEB, \"Hold-Key Electric Wire & Cable Co Ltd\"  },\r\n    { 0x2DEC, \"ZNi Technology Co., Ltd\"  },\r\n    { 0x2DED, \"Aquil Star Precision Industrial (Shenzhen) Co., Ltd\"  },\r\n    { 0x2DEE, \"Shenzhen MeiG Smart Technology Co., Ltd\"  },\r\n    { 0x2DEF, \"Kirale Technologies SL\"  },\r\n    { 0x2DF0, \"CANVASBIO CO., LTD\"  },\r\n    { 0x2DF1, \"Inovonics Corp\"  },\r\n    { 0x2DF2, \"LIPS Corporation\"  },\r\n    { 0x2DF3, \"LongSung Technology (Shanghai) Co., Ltd.\"  },\r\n    { 0x2DF4, \"Jumplux Technology Co., Ltd.\"  },\r\n    { 0x2DF5, \"Helium Systems Inc.\"  },\r\n    { 0x2DF6, \"Greektown Casino-Hotel, LLC\"  },\r\n    { 0x2DF7, \"Fastwel Group Ltd.\"  },\r\n    { 0x2DF8, \"ITEST\"  },\r\n    { 0x2DF9, \"EZQuest, Inc.\"  },\r\n    { 0x2DFA, \"3DRUDDER\"  },\r\n    { 0x2DFB, \"Bren-Tronics, Inc.\"  },\r\n    { 0x2DFC, \"Graphic Products\"  },\r\n    { 0x2DFD, \"Ubisoft Entertainment SA\"  },\r\n    { 0x2DFE, \"Next Thing Co.\"  },\r\n    { 0x2DFF, \"Unicept GmbH\"  },\r\n    { 0x2E00, \"CIB Security Inc\"  },\r\n    { 0x2E01, \"Symetrix, Inc.\"  },\r\n    { 0x2E02, \"Softiron\"  },\r\n    { 0x2E03, \"Zhejiang Dahua Technology Co., Ltd.\"  },\r\n    { 0x2E04, \"HMD Global Oy\"  },\r\n    { 0x2E05, \"CKD Corporation\"  },\r\n    { 0x2E06, \"Shenzhen Junlan Electronic Ltd\"  },\r\n    { 0x2E07, \"Lafayette Instrument Company\"  },\r\n    { 0x2E08, \"Zhongshan Dumei Weite Electronics Co., Ltd\"  },\r\n    { 0x2E09, \"Beijing LLVision Technology Co. LTD\"  },\r\n    { 0x2E0A, \"Dytran Instruments\"  },\r\n    { 0x2E0B, \"Datafield Industries (HK) Ltd\"  },\r\n    { 0x2E0C, \"Shenzhen Mek Intellisys PTE Ltd\"  },\r\n    { 0x2E0D, \"Suzhou FanglinTechnology Co., Ltd\"  },\r\n    { 0x2E0E, \"Hatteland Display AS\"  },\r\n    { 0x2E0F, \"Institute for Defense Analyses / Center for Computing Sciences\"  },\r\n    { 0x2E10, \"LinkMTech Inc.\"  },\r\n    { 0x2E11, \"ShenZhen ShenTai WeiXiang Electronics Co., Ltd\"  },\r\n    { 0x2E12, \"Hongkong Chenyang Electronic Co., Limited\"  },\r\n    { 0x2E13, \"Intelligent Automation (Zhuhai) Co., Ltd\"  },\r\n    { 0x2E14, \"Expressive\"  },\r\n    { 0x2E15, \"Now Technologies\"  },\r\n    { 0x2E16, \"Glosys Inc.\"  },\r\n    { 0x2E17, \"Essential Products, Inc.\"  },\r\n    { 0x2E18, \"NorthStar Battery Company, LLC\"  },\r\n    { 0x2E19, \"Additel Corporation\"  },\r\n    { 0x2E1A, \"Shenzhen Arashi Vision Company Limited\"  },\r\n    { 0x2E1B, \"BeiJie Electronics Technology Co., Ltd\"  },\r\n    { 0x2E1C, \"Shenzhen Auto-Link World Information Technology Co., Ltd.\"  },\r\n    { 0x2E1D, \"Clarion (Malaysia) Sdn. Bhd.\"  },\r\n    { 0x2E1E, \"Sound Technology (C.Q.) Co., Ltd\"  },\r\n    { 0x2E1F, \"BrainScope Company, Inc.\"  },\r\n    { 0x2E20, \"Guangzhou Long Do Co.,Ltd\"  },\r\n    { 0x2E21, \"DOSCH&AMAND Research GmbH&CoKG\"  },\r\n    { 0x2E22, \"DongGuan LinSong precision electronics CO., LTD\"  },\r\n    { 0x2E23, \"Shenzhen Baojia Battery Technology Co., Ltd.\"  },\r\n    { 0x2E24, \"Hyperkin Inc.\"  },\r\n    { 0x2E25, \"Gold Cable (Zhongshan) Electronic Co., Ltd.\"  },\r\n    { 0x2E26, \"Monoprice, Inc.\"  },\r\n    { 0x2E27, \"Lion Semiconductor\"  },\r\n    { 0x2E28, \"VOLTRONIC POWER TECHNOLOGY CORP.\"  },\r\n    { 0x2E29, \"Clas Ohlson AB\"  },\r\n    { 0x2E2B, \"Shenzhen Qinps Technology Co Limited\"  },\r\n    { 0x2E2C, \"Dashine Electronics Co, Ltd\"  },\r\n    { 0x2E2D, \"Anaren Inc.\"  },\r\n    { 0x2E2E, \"First Design System Inc.\"  },\r\n    { 0x2E2F, \"Gulden Ophthalmics, Inc.\"  },\r\n    { 0x2E30, \"Andon Health Co., Ltd.\"  },\r\n    { 0x2E31, \"Thine Electronics, Inc.\"  },\r\n    { 0x2E32, \"Shenzhen Red Star Electronics Co., Ltd.\"  },\r\n    { 0x2E33, \"Squarehead Technology\"  },\r\n    { 0x2E34, \"ALLDATA LLC\"  },\r\n    { 0x2E35, \"Shenzhen PYS Industrial Co., LTD\"  },\r\n    { 0x2E36, \"Depo Electronics Limited\"  },\r\n    { 0x2E37, \"IRISO ELECTRONICS CO., LTD\"  },\r\n    { 0x2E38, \"OHM ELECTRONIC INC.\"  },\r\n    { 0x2E39, \"Epic Tech, LLC\"  },\r\n    { 0x2E3A, \"Nanaboshi Electric Mfg. Co., Ltd.\"  },\r\n    { 0x2E3B, \"uSens Inc\"  },\r\n    { 0x2E3C, \"ARTERY Technology Co., Ltd.\"  },\r\n    { 0x2E3D, \"ASWAN ELEC. SALES CO., LTD.\"  },\r\n    { 0x2E3E, \"Karma Automotive\"  },\r\n    { 0x2E3F, \"Poly-Planar Group LLC\"  },\r\n    { 0x2E40, \"Mobile Technologies Inc\"  },\r\n    { 0x2E41, \"DONGGUAN RONGDEKANG ELECTRONIC TECHNOLOGY CO., LTD.\"  },\r\n    { 0x2E42, \"Hunan Ronghe Microelectronics Co., Ltd.\"  },\r\n    { 0x2E43, \"Owl Labs, Inc\"  },\r\n    { 0x2E44, \"Idealens Technology (Chengdu) Co., Ltd.\"  },\r\n    { 0x2E45, \"Widex A/S\"  },\r\n    { 0x2E46, \"Mobileconn Technology Co., Ltd.\"  },\r\n    { 0x2E47, \"X-Media Tech, Inc.\"  },\r\n    { 0x2E48, \"Andromium Inc.\"  },\r\n    { 0x2E49, \"A&T Corporation\"  },\r\n    { 0x2E4A, \"Xiamen Jinhaode Electronic Co., Ltd\"  },\r\n    { 0x2E4B, \"ART SPA\"  },\r\n    { 0x2E4C, \"Carter Duncan Corp.\"  },\r\n    { 0x2E4D, \"Vinpower, Inc.\"  },\r\n    { 0x2E4E, \"METER Group, Inc\"  },\r\n    { 0x2E4F, \"Audiotec Fischer GmbH\"  },\r\n    { 0x2E50, \"beyerdynamic GmbH & Co. KG\"  },\r\n    { 0x2E51, \"EVER Sp. Z.o.o.\"  },\r\n    { 0x2E52, \"Toughbuilt Industries Inc\"  },\r\n    { 0x2E53, \"Shenzhen East-Toptech Electronic Technology Co., Ltd\"  },\r\n    { 0x2E54, \"Yin Run Precise Metal Products CO., LTD.\"  },\r\n    { 0x2E55, \"FIP Formatura Iniezione Polimeri an Aliaxis Company\"  },\r\n    { 0x2E56, \"Juchin Technology (JIANGXI) Co., Ltd\"  },\r\n    { 0x2E57, \"MEGWARE Computer Vertrieb und Service GmbH\"  },\r\n    { 0x2E58, \"GONGNIU GROUP CO., LTD.\"  },\r\n    { 0x2E59, \"Maui Imaging, Inc.\"  },\r\n    { 0x2E5A, \"Mysher Technology Co., Ltd.\"  },\r\n    { 0x2E5B, \"Fitipower Integrated Technology Inc.\"  },\r\n    { 0x2E5C, \"Y.H.S. Co., Ltd\"  },\r\n    { 0x2E5D, \"Dong Guan LM-Link Precise Electronic Co., Ltd.\"  },\r\n    { 0x2E5E, \"Mei Shun He Electronic Limited\"  },\r\n    { 0x2E5F, \"Shenzhen BTC Technology Co., Ltd.\"  },\r\n    { 0x2E60, \"castAR, Inc.\"  },\r\n    { 0x2E61, \"NetBurner, Inc.\"  },\r\n    { 0x2E62, \"Will Semiconductor Co., LTD\"  },\r\n    { 0x2E63, \"Polaris-Labs Shenzhen Co., Ltd\"  },\r\n    { 0x2E64, \"Shenzhen Kaibao Technology Co., Ltd.\"  },\r\n    { 0x2E65, \"Kunshan Xintaili Precision Components Co., Ltd.\"  },\r\n    { 0x2E66, \"SALICRU, S.A.\"  },\r\n    { 0x2E67, \"Elevation Lab, Inc.\"  },\r\n    { 0x2E68, \"Tessonics Inc.\"  },\r\n    { 0x2E69, \"Swift Navigation Inc\"  },\r\n    { 0x2E6A, \"Wilderness Labs Inc.\"  },\r\n    { 0x2E6B, \"DMX, LLC dba Mood Media\"  },\r\n    { 0x2E6C, \"Uwatec AG\"  },\r\n    { 0x2E6D, \"Laser Argentina S.A.\"  },\r\n    { 0x2E6E, \"E4D Technologies LLC\"  },\r\n    { 0x2E6F, \"Areca Technology Corporation\"  },\r\n    { 0x2E70, \"Revision Electronics & Power Systems Inc.\"  },\r\n    { 0x2E71, \"Futurepath Electronics Technology (Dongguan) Co., Ltd.\"  },\r\n    { 0x2E72, \"DongGuan YongHao Electronics Co., LTD\"  },\r\n    { 0x2E73, \"Backyard Brains\"  },\r\n    { 0x2E74, \"Magenta Labs Inc.\"  },\r\n    { 0x2E75, \"Shanghai Hinge Electronic Technologies Co., Ltd.\"  },\r\n    { 0x2E76, \"Guangdong Jinrun Electronics Co., Ltd.\"  },\r\n    { 0x2E77, \"LOGICDATA Electronics & Software Entwicklungs GmbH\"  },\r\n    { 0x2E78, \"ES Gear Ltd.\"  },\r\n    { 0x2E79, \"NP System Development Co., Ltd.\"  },\r\n    { 0x2E7A, \"Jiangsu BDSTAR Navigation Electronic Co., Ltd.\"  },\r\n    { 0x2E7B, \"Terrada Music Score CO., Ltd.\"  },\r\n    { 0x2E7C, \"Pyramid Solutions\"  },\r\n    { 0x2E7D, \"Shenzhen Xin Yong Yang Technology Co., Ltd.\"  },\r\n    { 0x2E7E, \"ValueHD Corporation\"  },\r\n    { 0x2E7F, \"Aries Manufacturing - a division of Boss Tech Products Inc.\"  },\r\n    { 0x2E80, \"Join Tek Corporation Co., Ltd.\"  },\r\n    { 0x2E81, \"Zodiac Inflight Innovations\"  },\r\n    { 0x2E82, \"Sapphire Technology Limited\"  },\r\n    { 0x2E83, \"Ocean Tek Enterprise Co., Ltd.\"  },\r\n    { 0x2E84, \"Sheng San Electronics (Shen Zhen) Co., Ltd.\"  },\r\n    { 0x2E85, \"Verizon\"  },\r\n    { 0x2E86, \"SBO HEARING A/S\"  },\r\n    { 0x2E87, \"Shenzhen Injoinic Technology Co., Ltd.\"  },\r\n    { 0x2E88, \"Huada Semiconductor Corporation Limited\"  },\r\n    { 0x2E89, \"Group Dekko, Inc.\"  },\r\n    { 0x2E8A, \"Raspberry Pi (Trading) Limited\"  },\r\n    { 0x2E8B, \"Asia Optical International Ltd.\"  },\r\n    { 0x2E8C, \"Aisino Wincor Manufacturing (Shanghai) Co., Ltd.\"  },\r\n    { 0x2E8D, \"YSC Science Technique Electron (Yi Chun) Co., Ltd\"  },\r\n    { 0x2E8E, \"Bitatek CO., LTD\"  },\r\n    { 0x2E8F, \"Shenzhen Weiduli Technology Co., Ltd.\"  },\r\n    { 0x2E90, \"Wireless Media Tech CO., Limited\"  },\r\n    { 0x2E91, \"Shenzhen Suprint Smart Technology Co., Ltd.\"  },\r\n    { 0x2E92, \"bioMerieux, Inc.\"  },\r\n    { 0x2E93, \"Shenzhen Huikeyuan Electronic Technology Co., Ltd.\"  },\r\n    { 0x2E94, \"Graviton Inc.\"  },\r\n    { 0x2E95, \"Scuf Gaming International, LLC\"  },\r\n    { 0x2E96, \"Aspect Microsystems Corp.\"  },\r\n    { 0x2E97, \"Aerocool Advanced Technologies Corporation\"  },\r\n    { 0x2E98, \"Nekteck, Inc.\"  },\r\n    { 0x2E99, \"Hynetek Semiconductor Co., Ltd\"  },\r\n    { 0x2E9A, \"MS Solutions Co., Ltd.\"  },\r\n    { 0x2E9B, \"New Imaging Technologies\"  },\r\n    { 0x2E9C, \"Shenzhen Silkway Technology Co., Ltd.\"  },\r\n    { 0x2E9D, \"Resolved Instruments Inc.\"  },\r\n    { 0x2E9E, \"SoundAI Technology Co., Ltd.\"  },\r\n    { 0x2E9F, \"EyeTech Digital Systems, Inc.\"  },\r\n    { 0x2EA0, \"Magnescale Co., Ltd.\"  },\r\n    { 0x2EA1, \"DASANELECTRON CO., LTD\"  },\r\n    { 0x2EA2, \"Ningbo Kangda Electronic Co., Ltd.\"  },\r\n    { 0x2EA3, \"POSLAB Technology Corporation\"  },\r\n    { 0x2EA4, \"Hubbell Incorporated (Delaware), Wiring Device Kellems Division\"  },\r\n    { 0x2EA5, \"Dongguanshi Qitaiprecision Moulds Co., Ltd.\"  },\r\n    { 0x2EA6, \"Foreign Trade Corporation dba. Technocel\"  },\r\n    { 0x2EA7, \"Muhanbit\"  },\r\n    { 0x2EA8, \"Changsha JingJia Microelectronics Co., LTD.\"  },\r\n    { 0x2EA9, \"Yuneec International (China) Co., Ltd.\"  },\r\n    { 0x2EAA, \"TSUME S.A.\"  },\r\n    { 0x2EAB, \"Zong Cable Technology Co., Ltd.\"  },\r\n    { 0x2EAC, \"Jia Yang Electronics (Dongguan) Co., Ltd.\"  },\r\n    { 0x2EAD, \"Align Technology Inc.\"  },\r\n    { 0x2EAE, \"Shenzhen TOMTOP Technology Co., Ltd.\"  },\r\n    { 0x2EAF, \"microsonic co., ltd.\"  },\r\n    { 0x2EB0, \"Commtech, Inc.\"  },\r\n    { 0x2EB1, \"Samsung SmartThings\"  },\r\n    { 0x2EB2, \"Markus Klotz GmbH\"  },\r\n    { 0x2EB3, \"Shenzhen Tokwa Precision Technology Co., Ltd.\"  },\r\n    { 0x2EB4, \"Beijer Automotive BV\"  },\r\n    { 0x2EB5, \"Dongguan HengYue Communication Technology Co., Ltd.\"  },\r\n    { 0x2EB6, \"The Vehicle Group LTD\"  },\r\n    { 0x2EB7, \"Digital Divide Systems Ltd.\"  },\r\n    { 0x2EB8, \"Yueqing Nuode Electronic Technology Co., Ltd.\"  },\r\n    { 0x2EB9, \"SSI Computer Corp.\"  },\r\n    { 0x2EBA, \"Shenzhen E&C Smart Link Technology Co., Ltd.\"  },\r\n    { 0x2EBB, \"Shanghai Tuzheng Information Technology Co., Ltd.\"  },\r\n    { 0x2EBC, \"RAIDON Technology Inc.\"  },\r\n    { 0x2EBD, \"Netstor Technology Co., Ltd.\"  },\r\n    { 0x2EBE, \"Delphi Automotive Systems, LLC\"  },\r\n    { 0x2EBF, \"Shenzhen D&D Technology Co., Ltd\"  },\r\n    { 0x2EC0, \"GuideTech\"  },\r\n    { 0x2EC1, \"Avid Identification Systems, Inc.\"  },\r\n    { 0x2EC2, \"Loupedeck Oy\"  },\r\n    { 0x2EC3, \"Shenzhen Huntkey Electric Co., Ltd.\"  },\r\n    { 0x2EC4, \"tetralux S.a.r.l.\"  },\r\n    { 0x2EC5, \"Ariba Technology Co., LTD.\"  },\r\n    { 0x2EC6, \"Facebook, Inc.\"  },\r\n    { 0x2EC7, \"ITECH Electronic Co., Ltd.\"  },\r\n    { 0x2EC8, \"Ningbo Prime Electronic Co., Ltd.\"  },\r\n    { 0x2EC9, \"Shenzhou Rongan Technology (Beijing) Limited\"  },\r\n    { 0x2ECA, \"AQuantia Corp\"  },\r\n    { 0x2ECB, \"Zhejiang Quzhou Gelinte Wire and Cable Co., Ltd.\"  },\r\n    { 0x2ECC, \"ASR Microelectronics (Shanghai) Co., Ltd.\"  },\r\n    { 0x2ECD, \"EUROICC\"  },\r\n    { 0x2ECE, \"E-Lead Electronic Co., Ltd.\"  },\r\n    { 0x2ECF, \"Fluo Technology Ltd.\"  },\r\n    { 0x2ED0, \"Mind Alive Inc.\"  },\r\n    { 0x2ED1, \"QBit Semiconductor LTD\"  },\r\n    { 0x2ED2, \"APOLLO GIKEN Co., Ltd.\"  },\r\n    { 0x2ED3, \"Shenzhen Xinhongya Electronics Corporation\"  },\r\n    { 0x2ED4, \"Butterfly Network Inc.\"  },\r\n    { 0x2ED5, \"QSAN Technology, Inc.\"  },\r\n    { 0x2ED6, \"Shenzhen Xinliyang Co., Ltd.\"  },\r\n    { 0x2ED7, \"Libratel Inc\"  },\r\n    { 0x2ED8, \"Dongguan Lontion Industrial Co., Ltd.\"  },\r\n    { 0x2ED9, \"Microscopes International, LLC\"  },\r\n    { 0x2EDA, \"Wenzhou Haitong Communication Electronics Co., Ltd.\"  },\r\n    { 0x2EDB, \"NeuroHabilitation Corporation\"  },\r\n    { 0x2EDC, \"Nippon Techno Lab., Inc.\"  },\r\n    { 0x2EDD, \"reMarkable AS\"  },\r\n    { 0x2EDE, \"Technik Industrial Company Limited\"  },\r\n    { 0x2EDF, \"Huizhou Wealth Metal Micro Control Limited\"  },\r\n    { 0x2EE0, \"Pogotec Inc.\"  },\r\n    { 0x2EE1, \"Safetrust Inc\"  },\r\n    { 0x2EE2, \"Kashimura Co., Ltd.\"  },\r\n    { 0x2EE3, \"Kin Keung Electrical Mfg. Ltd.\"  },\r\n    { 0x2EE4, \"Osprey Video, Inc.\"  },\r\n    { 0x2EE6, \"NEURODIGITAL TECHNOLOGIES, S.L.\"  },\r\n    { 0x2EE7, \"GOOGFIT TECH LIMITED\"  },\r\n    { 0x2EE8, \"Zunidata Systems, Inc.\"  },\r\n    { 0x2EE9, \"Adigal LLC\"  },\r\n    { 0x2EEA, \"Loma Systems\"  },\r\n    { 0x2EEB, \"Jianduan Technology (Shenzhen) Co., Ltd.\"  },\r\n    { 0x2EEC, \"Sensor Industries Limited\"  },\r\n    { 0x2EED, \"Shenzhen Panhui Technologies Co., Ltd.\"  },\r\n    { 0x2EEE, \"Beijing Qunli Tiancheng Network Technology Company\"  },\r\n    { 0x2EEF, \"Booz Allen Hamilton\"  },\r\n    { 0x2EF0, \"Zhongshan Auxus Electronic Technology Co., Ltd.\"  },\r\n    { 0x2EF1, \"Tatvik Biosystems Private Limited\"  },\r\n    { 0x2EF2, \"Shenzhen Goodwin Technology Co., Ltd.\"  },\r\n    { 0x2FB2, \"Fujitsu Limited\"  },\r\n    { 0x3176, \"WHANAM ELECTRONICS CO., Ltd. MS division\"  },\r\n    { 0x3552, \"BD Consumer Healthcare\"  },\r\n    { 0x3636, \"INVIBRO\"  },\r\n    { 0x3884, \"Nicolet Biomedical Inc., a Viasys Healthcare Co.\"  },\r\n    { 0x3923, \"National Instruments\"  },\r\n    { 0x4102, \"iRiver\"  },\r\n    { 0x413C, \"Dell Inc.\"  },\r\n    { 0x4234, \"Powervar Inc. (UPS Products)\"  },\r\n    { 0x4242, \"USB Design By Example\"  },\r\n    { 0x4317, \"Broadcom WLAN\"  },\r\n    { 0x4426, \"TANITA Corporation\"  },\r\n    { 0x4745, \"Beijing Tiertime Technology Co., Ltd.\"  },\r\n    { 0x4791, \"Western Digital, G-Tech\"  },\r\n    { 0x4909, \"GE Healthcare Bio-Sciences AB\"  },\r\n    { 0x4971, \"HITACHI GLOBAL STORAGE TECHNOLOGIES\"  },\r\n    { 0x4B53, \"Key Soft Service\"  },\r\n    { 0x4C46, \"DSPecialists GmbH\"  },\r\n    { 0x4DDC, \"Data Device Corporation\"  },\r\n    { 0x5058, \"ProXense, LLC\"  },\r\n    { 0x5245, \"RESPIRONICS, INC.\"  },\r\n    { 0x544D, \"Transmeta Corporation\"  },\r\n    { 0x5543, \"UC-Logic Technology Corp.\"  },\r\n    { 0x5555, \"Number Five, Software\"  },\r\n    { 0x55AA, \"OnSpec Electronic Inc.\"  },\r\n    { 0x5986, \"BISON ELECTRONICS INC.\"  },\r\n    { 0x6000, \"TRIDENT MICROSYSTEMS (Far East) Ltd.\"  },\r\n    { 0x630F, \"Leapfrog Schoolhouse\"  },\r\n    { 0x636C, \"CoreLogic, Inc.\"  },\r\n    { 0x6400, \"Springer Design, Inc.\"  },\r\n    { 0x6A75, \"Shanghai Jujo Electronics Co., Ltd.\"  },\r\n    { 0x735F, \"Beijing Techshino Technology Co., Ltd.\"  },\r\n    { 0x8020, \"Trinity, Inc.\"  },\r\n    { 0x8086, \"Intel Corporation\"  },\r\n    { 0x8087, \"Intel\"  },\r\n    { 0x8829, \"Beijing Daming Wuzhou Science & Technology Co., Ltd.\"  },\r\n    { 0x8873, \"Dengineer Co., Ltd.\"  },\r\n    { 0x9696, \"Digital Arts, Inc.\"  },\r\n    { 0x9710, \"Moschip Semiconductor Technology\"  },\r\n    { 0xA600, \"ASIX s.r.o.\"  },\r\n    { 0xA625, \"Wuhan Tianyu Information Industry Co., Ltd.\"  },\r\n    { 0xBEE5, \"BEE SYSTEMS LLC\"  },\r\n    { 0xC0B8, \"Corbett Life Science\"  },\r\n    { 0xC10C, \"Given Imaging\"  },\r\n    { 0xCACE, \"CACE Technologies\"  },\r\n    { 0xCC42, \"Cardio Control NV\"  },\r\n    { 0xEA01, \"Eagle Technology\"  },\r\n    { 0xEB1A, \"Empia Technology, Inc.\"  },\r\n    { 0xFF01, \"DisplayPort (VESA)\"  },\r\n    { 0xFF02, \"MHL, LLC\"  },\r\n    { 0xFF03, \"MIPI Debug\"  },\r\n    { 0xFF04, \"HDMI\"  },\r\n    { 0x0000, \"Vendor ID not listed with USB.org\"  }\r\n};\r\n\r\n#endif /* __VNDRLIST_H__ */\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"usbview\")\n    add_rules(\"win.sdk.application\")\n    add_files(\"*.c\", \"*.rc\")\n    add_files(\"xmlhelper.cpp\", {rules = \"win.sdk.dotnet\"})\n    set_exceptions(\"none\")\n\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/xmlhelper.cpp",
    "content": "/*++\r\n\r\n  Copyright (c) 1997-2011 Microsoft Corporation\r\n\r\n  Module Name:\r\n\r\n  XMLHELPER.CPP\r\n\r\nAbstract:\r\n\r\nThis source file contains helper APIs for reading writing XML\r\n\r\nEnvironment:\r\n\r\nuser mode\r\n\r\nRevision History:\r\n\r\n05-05-11 : created\r\n\r\n--*/\r\n\r\n/*****************************************************************************\r\n  I N C L U D E S\r\n *****************************************************************************/\r\n#include \"uvcview.h\"\r\n#include \"h264.h\"\r\n#include \"xmlhelper.h\"\r\n\r\n// usbschema.hpp is autogenerated from schema during build PASS0\r\n#include \"usbschema.hpp\"\r\n\r\n// Include code analysis suppressions\r\n#include \"codeanalysis.h\"\r\n\r\n/*****************************************************************************\r\n  D E F I N E S\r\n *****************************************************************************/\r\n#define COBJMACROS\r\n\r\n#define PACHAR_TO_STRING(X)   ((X != NULL)? gcnew String(Marshal::PtrToStringAnsi((IntPtr) X )):nullptr)\r\n#define PWCHAR_TO_STRING(X)   ((X != NULL)? gcnew String(Marshal::PtrToStringUni((IntPtr) X )):nullptr)\r\n\r\n#define MAX_STRING_DESCRIPTOR_LENGTH    512\r\n#define STRING_DESCRIPTOR_EN_LANGUAGE_ID    0x0409\r\n#define DEVICE_DESCRIPTOR_LENGTH    18\r\n\r\n#define SERVICE_EHCI \"usbehci\"\r\n#define SERVICE_XHCI \"usbxhci\"\r\n#define SERVICE_OHCI \"usbohci\"\r\n#define SERVICE_UHCI \"usbuhci\"\r\n\r\n#define USB_1_1      \"USB 1.1\"\r\n#define USB_2_0      \"USB 2.0\"\r\n#define USB_3_0      \"USB 3.0\"\r\n#define USB_GENERIC  \"USB GENERIC (UNKNOWN)\"\r\n\r\n/*****************************************************************************\r\n  N A M E S P A C E S\r\n *****************************************************************************/\r\n\r\nusing namespace System;\r\nusing namespace System::IO;\r\nusing namespace System::Runtime::InteropServices;\r\nusing namespace System::Collections;\r\nusing namespace Microsoft::Kits::Samples::Usb;\r\n\r\n\r\n/*****************************************************************************\r\n  G L O B A L S\r\n *****************************************************************************/\r\n\r\nnamespace Microsoft\r\n{\r\n    namespace Kits\r\n    {\r\n        namespace Samples\r\n        {\r\n            namespace Usb\r\n            {\r\n                public ref class XmlGlobal sealed\r\n                {\r\n                    private:\r\n                        static XmlGlobal ^ pInstance = gcnew XmlGlobal();\r\n\r\n                        // Empty private constructor\r\n                        XmlGlobal()\r\n                        {\r\n                        }\r\n\r\n                    public:\r\n                        //\r\n                        // Globals for XML view\r\n                        //\r\n                        property UvcViewAll ^ ViewAll;\r\n                        property bool XmlViewInitialized;\r\n\r\n                        //\r\n                        // Stack of parents of a given node. This is used for finding\r\n                        // where a given object should be added\r\n                        //\r\n\r\n#if CODE_ANALYSIS\r\n                        // ParentStack need not be constant since we will only have one instance of this object\r\n                        [SuppressMessage(\"Microsoft.Usage\", \"CA2211:NonConstantFieldsShouldNotBeVisible\")]\r\n#endif\r\n                            static Stack ^ ParentStack = gcnew Stack();\r\n\r\n                        static XmlGlobal ^ Instance()\r\n                        {\r\n                            return pInstance;\r\n                        }\r\n                };\r\n            };\r\n        };\r\n    };\r\n};\r\n\r\n#define gXmlView              ((XmlGlobal::Instance())->ViewAll->UvcView)\r\n#define gXmlViewInitialized   ((XmlGlobal::Instance())->XmlViewInitialized)\r\n#define gXmlStack             ((XmlGlobal::Instance())->ParentStack)\r\n\r\n/*****************************************************************************\r\n  D E C L A R A T I O N S\r\n *****************************************************************************/\r\n\r\nString ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly);\r\nvoid XmlAddHostControllerPowerMapping( UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo);\r\nString ^ XmlGetDeviceClassString(UCHAR deviceClass);\r\nvoid XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo);\r\nvoid XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor);\r\nvoid XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor);\r\nvoid XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps);\r\nvoid XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar);\r\nHRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo);\r\nHRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx);\r\nHRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, USB_HUB_CAPABILITIES_EX hubCapEx);\r\nExternalHubType ^ AddExternalHub(Object ^parent);\r\nNoDeviceType ^ AddDisconnectedPort(Object ^parent);\r\nUsbDeviceType ^ AddUsbDevice(Object ^parent);\r\nvoid XmlAddEndpointDescriptor(\r\n        EndpointDescriptorType ^usbXmlEndpointDescriptor,\r\n        PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor,\r\n        UCHAR connectionSpeed);\r\nvoid XmlAddPipeInformation(\r\n        array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList,\r\n        PUSB_PIPE_INFO pipeInfo,\r\n        ULONG numPipes,\r\n        UCHAR connectionSpeed);\r\nvoid XmlAddUsbDeviceDescriptor(\r\n        UsbDeviceDescriptorType ^usbXmlDeviceDescriptor,\r\n        PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor);\r\nvoid XmlAddConfigurationDescriptor(\r\n        UsbConfigurationDescriptorType ^ confXmlDesc,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc);\r\nvoid XmlAddDeviceQualDescriptor(\r\n        UsbDeviceQualifierDescriptorType ^ qualXmlDesc,\r\n        PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc);\r\nvoid XmlAddDeviceConfiguration(\r\n        UsbDeviceConfigurationType ^ confXmlDesc,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        int numInterfaces);\r\nvoid XmlAddConnectionInfoSt(\r\n        NodeConnectionInfoExStructType ^xmlConnectionInfoSt,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PDEVICE_INFO_NODE pNode);\r\nString ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc);\r\nString ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly);\r\nString ^ XmlGetDeviceClassString(UCHAR deviceClass);\r\nbool XmlAddDeviceClassDetails(\r\n        UsbDeviceClassDetailsType ^ deviceDetails,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PUSBDEVICEINFO deviceInfo);\r\nvoid XmlAddConnectionInfo(\r\n        NodeConnectionInfoExType ^xmlConnectionInfo,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        PDEVICE_INFO_NODE pNode);\r\nvoid XmlAddHidDescriptor(\r\n        UsbDeviceHidDescriptorType ^ hidXmlDesc,\r\n        PUSB_HID_DESCRIPTOR hidDesc);\r\nvoid XmlAddDeviceInterfaceDescriptor(\r\n        UsbDeviceInterfaceDescriptorType ^ ifXmlDesc,\r\n        PUSB_INTERFACE_DESCRIPTOR ifDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc);\r\nvoid XmlAddOTGDescriptor(\r\n        UsbDeviceOTGDescriptorType ^ otgXmlDesc,\r\n        PUSB_OTG_DESCRIPTOR otgDesc);\r\nvoid XmlAddIADDescriptor(\r\n        UsbDeviceIADDescriptorType ^ iadXmlDesc,\r\n        PUSB_IAD_DESCRIPTOR iadDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        int nInterfaces);\r\narray < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors(\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDescs,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc);\r\nUsbBosDescriptorType ^ XmlGetBosDescriptor(\r\n        PUSB_BOS_DESCRIPTOR bosDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        );\r\nUsbDeviceClassType ^ XmlGetDeviceClass(UCHAR deviceClass, UCHAR deviceSubClass, UCHAR deviceProtocol);\r\nUsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor(\r\n        PUSB_COMMON_DESCRIPTOR unknownDesc\r\n        );\r\nUsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc\r\n        );\r\nUsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc\r\n        );\r\nUsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc\r\n        );\r\nUsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        );\r\n\r\n/*****************************************************************************\r\n  D E F I N I T I O N S\r\n *****************************************************************************/\r\n\r\n/*****************************************************************************\r\n  XmlNotifyEndOfNodeList\r\n\r\n  This function is called back by WalkTreeTopDown() function to notify us\r\n  that there are no more children to add for the current parent\r\n\r\n *****************************************************************************/\r\nVOID XmlNotifyEndOfNodeList(PVOID pContext)\r\n{\r\n    UNREFERENCED_PARAMETER(pContext);\r\n\r\n    if (gXmlStack != nullptr && gXmlStack->Count > 0)\r\n    {\r\n        // Remove the last parent on the stack\r\n        gXmlStack->Pop();\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHostControllerPowerMapping()\r\n\r\n  add power info to xml structure\r\n *****************************************************************************/\r\nvoid XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo)\r\n{\r\n    int i, powerState;\r\n    PUSB_POWER_INFO pUPI = usbHCPowerInfo;\r\n    UsbHCPowerStateType ^ pwrState = nullptr;\r\n\r\n    xmlPwrInfo->PowerMap = gcnew array<UsbHCPowerStateType ^> (WdmUsbPowerSystemShutdown);\r\n\r\n    for(i = 0, powerState = WdmUsbPowerSystemWorking; powerState < WdmUsbPowerSystemShutdown; i++, powerState++, pUPI++)\r\n    {\r\n        xmlPwrInfo->PowerMap[i] = gcnew UsbHCPowerStateType();\r\n        pwrState = xmlPwrInfo->PowerMap[i];\r\n        pwrState->SystemState = PACHAR_TO_STRING(GetPowerStateString(pUPI->SystemState));\r\n        pwrState->HostControllerState = PACHAR_TO_STRING(GetPowerStateString(pUPI->HcDevicePowerState));\r\n        pwrState->HubState = PACHAR_TO_STRING(GetPowerStateString(pUPI->RhDevicePowerState));\r\n        pwrState->CanWakeUp = pUPI->CanWakeup? true:false;\r\n        pwrState->IsPowered = pUPI->IsPowered? true:false;\r\n    }\r\n\r\n    xmlPwrInfo->LastSleepState = PACHAR_TO_STRING(GetPowerStateString(pUPI->LastSystemSleepState));\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHostController()\r\n\r\n  Add an host controller to XML view\r\n *****************************************************************************/\r\n\r\nHRESULT XmlAddHostController(PSTR hcName, PUSBHOSTCONTROLLERINFO hcInfo)\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    UNREFERENCED_PARAMETER(hcName);\r\n\r\n    HostControllerType ^ hc = nullptr;\r\n    //\r\n    // Check if the USB Tree array has been initialized\r\n    // It would have been great if XSD had a way of generating a list instead of array, but it does not\r\n    // So we have to do array.Resize everytime\r\n    //\r\n    if (gXmlView->UsbTree == nullptr)\r\n    {\r\n        // This is the first time we are being called, initialize the array with 1 element\r\n        gXmlView->UsbTree = gcnew array<HostControllerType ^>(1);\r\n        gXmlView->UsbTree[0] = gcnew HostControllerType();\r\n        hc = gXmlView->UsbTree[0];\r\n    }\r\n    else\r\n    {\r\n        // Create a new array every time as Array.Resize does not seem to work in our case (CLI)\r\n        // We do this using ArrayList.\r\n        ArrayList ^hcList = gcnew ArrayList;\r\n        hcList->AddRange(gXmlView->UsbTree);\r\n        hc = gcnew HostControllerType();\r\n        hcList->Add(hc);\r\n        gXmlView->UsbTree = reinterpret_cast<array<HostControllerType ^>^> (hcList->ToArray(HostControllerType::typeid));\r\n    }\r\n\r\n    if (hc != nullptr)\r\n    {\r\n        ULONG debugPort = 0;\r\n\r\n        UsbHCDeviceInfoType ^ ci = nullptr;\r\n        UsbHCPowerStateMappingType ^ pm = nullptr;\r\n\r\n        if (NULL != hcInfo->UsbDeviceProperties)\r\n        {\r\n            hc->HwId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->HwId);\r\n            hc->DeviceId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceId);\r\n            hc->ServiceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->Service);\r\n            hc->DeviceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceDesc);\r\n            hc->DeviceClass = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceClass);\r\n\r\n            bool foundUsbProtocol = false;\r\n            if (hcInfo->UsbDeviceProperties->Service != NULL)\r\n            {\r\n                foundUsbProtocol = true;\r\n\r\n                if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_OHCI) == 0)\r\n                {\r\n                    hc->UsbProtocol = gcnew String(USB_1_1);\r\n                }\r\n                else if(_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_EHCI) == 0 ||\r\n                _stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_UHCI) == 0)\r\n                {\r\n                    hc->UsbProtocol = gcnew String(USB_2_0);\r\n                }\r\n                else if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_XHCI) == 0)\r\n                {\r\n                    hc->UsbProtocol = gcnew String(USB_3_0);\r\n                }\r\n                else\r\n                {\r\n                    foundUsbProtocol = false;\r\n                }\r\n            }\r\n\r\n            if (!foundUsbProtocol)\r\n            {\r\n                // If protocol lookup failed based on service name, try Controller flavor\r\n                if(NULL != hcInfo->ControllerInfo)\r\n                {\r\n                    USB_CONTROLLER_FLAVOR flavor = hcInfo->ControllerInfo->ControllerFlavor;\r\n\r\n                    if(flavor == USB_HcGeneric)\r\n                    {\r\n                        hc->UsbProtocol = gcnew String(USB_GENERIC);\r\n                    }\r\n                    else if(flavor >= OHCI_Generic && flavor < UHCI_Generic)\r\n                    {\r\n                        hc->UsbProtocol = gcnew String(USB_1_1);\r\n                    }\r\n                    else if(flavor >= UHCI_Generic && flavor <= EHCI_Generic)\r\n                    {\r\n                        hc->UsbProtocol = gcnew String(USB_2_0);\r\n                    }\r\n                    else if(flavor > EHCI_Generic)\r\n                    {\r\n                        hc->UsbProtocol = gcnew String(USB_3_0);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        hc->ControllerInfo = gcnew UsbHCDeviceInfoType();\r\n        hc->PowerMapping = gcnew UsbHCPowerStateMappingType();\r\n        ci = hc->ControllerInfo;\r\n        pm = hc->PowerMapping;\r\n\r\n        ci->VendorId = hcInfo->VendorID;\r\n        ci->DeviceId = hcInfo->DeviceID;\r\n        ci->DriverKey = PACHAR_TO_STRING(hcInfo->DriverKey);\r\n        ci->SubSysId = hcInfo->SubSysID;\r\n        ci->Revision = hcInfo->Revision;\r\n\r\n        if(NULL != hcInfo->ControllerInfo)\r\n        {\r\n            ci->NumberOfRootPorts = hcInfo->ControllerInfo->NumberOfRootPorts;\r\n            ci->ControllerFlavor = hcInfo->ControllerInfo->ControllerFlavor;\r\n            ci->PortSwitchingEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_PORT_POWER_SWITCHING)? true: false;\r\n            ci->SelectiveSuspendEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_SEL_SUSPEND)? true: false;\r\n            ci->LegacyBios = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_LEGACY_BIOS)? true: false;\r\n            ci->ControllerFlavorString = PACHAR_TO_STRING(GetControllerFlavorString(hcInfo->ControllerInfo->ControllerFlavor));\r\n        }\r\n\r\n        // Add power mappings\r\n        XmlAddHostControllerPowerMapping(pm, (PUSB_POWER_INFO) (&(hcInfo->USBPowerInfo[0])));\r\n\r\n        // Add debug port\r\n        debugPort = GetEhciDebugPort(hcInfo->VendorID, hcInfo->DeviceID);\r\n        if (debugPort > 0)\r\n        {\r\n            ci->DebugPort = debugPort;\r\n        }\r\n\r\n        gXmlStack->Push(hc);\r\n\r\n    }\r\n    else\r\n    {\r\n        hr = E_FAIL;\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHub30Descriptor()\r\n\r\n  Adds the hub 3.0 descriptor to the given hub object\r\n *****************************************************************************/\r\nvoid XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor)\r\n{\r\n\r\n    if (nullptr != hub30Desc && NULL != hub30Descriptor)\r\n    {\r\n        hub30Desc->Length = hub30Descriptor->bLength;\r\n        hub30Desc->DescriptorType = hub30Descriptor->bDescriptorType;\r\n        hub30Desc->NumberOfPorts = hub30Descriptor->bNumberOfPorts;\r\n        hub30Desc->HubCharacteristics = hub30Descriptor->wHubCharacteristics;\r\n        hub30Desc->PowerOntoPowerGood = hub30Descriptor->bPowerOnToPowerGood;\r\n        hub30Desc->HubControlCurrent = hub30Descriptor->bHubControlCurrent;\r\n        hub30Desc->HubHdrDecLat = hub30Descriptor->bHubHdrDecLat;\r\n        hub30Desc->DeviceRemovable = hub30Descriptor->DeviceRemovable;\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHubDescriptor()\r\n\r\n  Adds the hub descriptor to the given hub object\r\n *****************************************************************************/\r\nvoid XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor)\r\n{\r\n    if (nullptr != hubDesc && NULL != hubDescriptor)\r\n    {\r\n        hubDesc->DescriptorLength = hubDescriptor->bDescriptorLength;\r\n        hubDesc->DescriptorType = hubDescriptor->bDescriptorType;\r\n        hubDesc->NumberOfPorts = hubDescriptor->bNumberOfPorts;\r\n        hubDesc->PowerOntoPowerGood = hubDescriptor->bPowerOnToPowerGood;\r\n        hubDesc->HubControlCurrent = hubDescriptor->bHubControlCurrent;\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddPortConnectorProps()\r\n\r\n  Adds the port connector properties to XML file\r\n *****************************************************************************/\r\nvoid XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps)\r\n{\r\n    if (NULL != portProps)\r\n    {\r\n        portXmlProps->UsbPortProperties = gcnew UsbPortPropertiesType();\r\n\r\n        portXmlProps->ConnectionIndex = portProps->ConnectionIndex;\r\n        portXmlProps->ActualLength = portProps->ActualLength;\r\n        portXmlProps->CompanionIndex = portProps->CompanionIndex;\r\n        portXmlProps->CompanionPortNumber = portProps->CompanionPortNumber;\r\n        portXmlProps->CompanionHubSymbolicLinkName = PWCHAR_TO_STRING(portProps->CompanionHubSymbolicLinkName);\r\n\r\n        portXmlProps->UsbPortProperties->PortIsUserConnectable = portProps->UsbPortProperties.PortIsUserConnectable? true:false;\r\n        portXmlProps->UsbPortProperties->PortIsDebugCapable = portProps->UsbPortProperties.PortIsDebugCapable? true:false;\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddConnectionInfoV2()\r\n\r\n  Adds the V2 connection info structure\r\n *****************************************************************************/\r\nvoid XmlAddConnectionInfoV2(NodeConnectionInfoExV2Type ^ connectionXmlInfo, PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfo)\r\n{\r\n    if (NULL != connectionInfo)\r\n    {\r\n        connectionXmlInfo->ConnectionIndex = connectionInfo->ConnectionIndex;\r\n        connectionXmlInfo->Length = connectionInfo->Length;\r\n\r\n        connectionXmlInfo->Usb110Supported = connectionInfo->SupportedUsbProtocols.Usb110? true:false;\r\n        connectionXmlInfo->Usb200Supported = connectionInfo->SupportedUsbProtocols.Usb200? true:false;\r\n        connectionXmlInfo->Usb300Supported = connectionInfo->SupportedUsbProtocols.Usb300? true:false;\r\n\r\n        connectionXmlInfo->DeviceIsOperatingAtSuperSpeedOrHigher =\r\n            connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedOrHigher;\r\n\r\n        connectionXmlInfo->DeviceIsSuperSpeedCapableOrHigher =\r\n            connectionInfo->Flags.DeviceIsSuperSpeedCapableOrHigher;\r\n\r\n        connectionXmlInfo->DeviceIsOperatingAtSuperSpeedPlusOrHigher =\r\n            connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher;\r\n\r\n        connectionXmlInfo->DeviceIsSuperSpeedPlusCapableOrHigher =\r\n            connectionInfo->Flags.DeviceIsSuperSpeedPlusCapableOrHigher;\r\n\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHubCharacteristics()\r\n\r\n  Adds the hub characteristics to the given hub object\r\n *****************************************************************************/\r\nvoid XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar)\r\n{\r\n    HubCharacteristicsType ^hubC = nullptr;\r\n\r\n    hubI->HubCharacteristics = gcnew HubCharacteristicsType();\r\n    hubC = hubI->HubCharacteristics;\r\n    hubC->HubCharacteristicsValue = hubChar;\r\n    switch(hubChar & 0x3)\r\n    {\r\n        case 0x0:\r\n            hubC->PowerSwitching = gcnew String(\"Ganged\");\r\n            break;\r\n        case 0x1:\r\n            hubC->PowerSwitching = gcnew String(\"Individual\");\r\n            break;\r\n        case 0x2:\r\n        case 0x3:\r\n            hubC->PowerSwitching = gcnew String(\"None\");\r\n            break;\r\n        default:\r\n            hubC->PowerSwitching = gcnew String(\"Unknown\");\r\n    }\r\n\r\n    hubC->CompoundDevice = (hubChar & 0x4)? true:false;\r\n\r\n    switch(hubChar & 0x18)\r\n    {\r\n        case 0x0:\r\n            hubC->OverCurrentProtection = gcnew String(\"Global\");\r\n            break;\r\n        case 0x8:\r\n            hubC->OverCurrentProtection = gcnew String(\"Individual\");\r\n            break;\r\n        case 0x10:\r\n        case 0x18:\r\n            hubC->OverCurrentProtection = gcnew String(\"No protection, bus power only\");\r\n            break;\r\n        default:\r\n            hubC->OverCurrentProtection = gcnew String(\"Unknown\");\r\n    }\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHubNodeInformation()\r\n\r\n  Adds the node information to the hub object\r\n *****************************************************************************/\r\nHRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo)\r\n{\r\n    PUSB_HUB_INFORMATION hubInfo = NULL;\r\n\r\n    if (NULL == nodeInfo)\r\n    {\r\n        return E_FAIL;\r\n    }\r\n\r\n    hubInfo = &(nodeInfo->u.HubInformation);\r\n    ni->HubNode = static_cast<HubNodeType> (nodeInfo->NodeType);\r\n\r\n    ni->HubInformation = gcnew HubInformationType();\r\n    ni->HubInformation->IsRootHub = true;\r\n    ni->HubInformation->IsBusPowered = hubInfo->HubIsBusPowered? true:false;\r\n\r\n    // Add hub characteristics\r\n    XmlAddHubCharacteristics(ni->HubInformation, hubInfo->HubDescriptor.wHubCharacteristics);\r\n    // Add descriptor\r\n    ni->HubInformation->HubDescriptor = gcnew HubDescriptorType();\r\n    XmlAddHubDescriptor(ni->HubInformation->HubDescriptor, &(hubInfo->HubDescriptor));\r\n\r\n    return S_OK;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHubInformation()\r\n\r\n  Adds the node information to the hub object\r\n *****************************************************************************/\r\nHRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx)\r\n{\r\n    HubDescriptorType ^hubDesc = nullptr;\r\n    Hub30DescriptorType ^hub30Desc = nullptr;\r\n\r\n    if (NULL == hubInfoEx)\r\n    {\r\n        return E_FAIL;\r\n    }\r\n\r\n    ex->HubType = static_cast<HubTypeType> (hubInfoEx->HubType);\r\n    ex->HighestPortNumber = hubInfoEx->HighestPortNumber;\r\n    switch(hubInfoEx->HubType)\r\n    {\r\n        case UsbRootHub:\r\n        case Usb20Hub:\r\n            ex->HubDescriptor = hubDesc = gcnew HubDescriptorType();\r\n            XmlAddHubDescriptor(hubDesc, &(hubInfoEx->u.UsbHubDescriptor));\r\n            break;\r\n        case Usb30Hub:\r\n            ex->Hub30Descriptor = hub30Desc = gcnew Hub30DescriptorType();\r\n            XmlAddHub30Descriptor(hub30Desc, &(hubInfoEx->u.Usb30HubDescriptor));\r\n            break;\r\n    }\r\n    return S_OK;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHubCapabilitiesEx()\r\n\r\n  Adds the hub capabilities information to the hub object\r\n *****************************************************************************/\r\nHRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, PUSB_HUB_CAPABILITIES_EX hubCapEx)\r\n{\r\n    if(NULL != hubCapEx)\r\n    {\r\n        ex->HubIsHighSpeedCapable = hubCapEx->CapabilityFlags.HubIsHighSpeedCapable?true:false;\r\n        ex->HubIsHighSpeed  = hubCapEx->CapabilityFlags.HubIsHighSpeed?true:false;\r\n        ex->HubIsMultiTtCapable = hubCapEx->CapabilityFlags.HubIsMultiTtCapable?true:false;\r\n        ex->HubIsMultiTt = hubCapEx->CapabilityFlags.HubIsMultiTt?true:false;\r\n        ex->HubIsRoot = hubCapEx->CapabilityFlags.HubIsRoot?true:false;\r\n        ex->HubIsArmedWakeOnConnect = hubCapEx->CapabilityFlags.HubIsArmedWakeOnConnect?true:false;\r\n        ex->HubIsBusPowered  = hubCapEx->CapabilityFlags.HubIsBusPowered?true:false;\r\n    }\r\n    return S_OK;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  ExternalHubType ^ AddExternalHub(Object ^parent)\r\n\r\n  This routine finds the type of the parent and adds an external hub object to the\r\n  parent's list of external hubs. The newly created object is returned\r\n  We are using arrays insted of better types of collections becaused the code generated\r\n  by xsd.exe does not support other types.\r\n *****************************************************************************/\r\nExternalHubType ^ AddExternalHub(Object ^parent)\r\n{\r\n    RootHubType ^ rhParent = nullptr;\r\n    ExternalHubType ^ ehParent = nullptr;\r\n    array<ExternalHubType ^> ^ exHubArray = nullptr;\r\n    ExternalHubType ^ exHub = nullptr;\r\n    boolean arrayCreated = false;\r\n\r\n    // An external hub can be connected to a Root Hub or another External Hub\r\n    // We need to determine the type of the object.\r\n\r\n    // Try root hub first\r\n\r\n    rhParent = dynamic_cast<RootHubType ^> (parent);\r\n    if (rhParent == nullptr)\r\n    {\r\n        // RootHub cast was not successfult, try external hub\r\n        ehParent = dynamic_cast<ExternalHubType ^> (parent);\r\n        if (ehParent != nullptr)\r\n        {\r\n            // External hub parent\r\n            if (ehParent->ExternalHub == nullptr)\r\n            {\r\n                // First hub in the list of external hubs\r\n                ehParent->ExternalHub = gcnew array<ExternalHubType ^> (1);\r\n                arrayCreated = true;\r\n            }\r\n            exHubArray = ehParent->ExternalHub;\r\n        }\r\n\r\n    }\r\n    else\r\n    {\r\n        // Parent is a root hub\r\n        if (rhParent->ExternalHub == nullptr)\r\n        {\r\n            // First hub in root hub list\r\n            rhParent->ExternalHub = gcnew array<ExternalHubType ^>(1);\r\n            arrayCreated = true;\r\n        }\r\n        exHubArray = rhParent->ExternalHub;\r\n    }\r\n\r\n    if (exHubArray != nullptr)\r\n    {\r\n        if (arrayCreated)\r\n        {\r\n            // We created the array in this function, so we use offset 0\r\n            exHubArray[0] = gcnew ExternalHubType();\r\n            exHub = exHubArray[0];\r\n        }\r\n        else\r\n        {\r\n            // The array was already present, we need to do elaborate things\r\n            // as array.resize does not work.\r\n            ArrayList ^exList = gcnew ArrayList();\r\n            exList->AddRange(exHubArray);\r\n            exHub = gcnew ExternalHubType();\r\n            exList->Add(exHub);\r\n\r\n            if (rhParent != nullptr)\r\n            {\r\n                rhParent->ExternalHub = reinterpret_cast<array<ExternalHubType ^>^> (exList->ToArray(ExternalHubType::typeid));\r\n            }\r\n            else\r\n            {\r\n                ehParent->ExternalHub = reinterpret_cast<array<ExternalHubType ^>^> (exList->ToArray(ExternalHubType::typeid));\r\n            }\r\n        }\r\n    }\r\n    return exHub;\r\n}\r\n/*****************************************************************************\r\n\r\n  NoDeviceType ^ AddDisconnectedPort(Object ^parent)\r\n\r\n  This routine finds the type of the parent and adds a empty port connection object to the\r\n  parent's list of devices. The newly created object is returned\r\n  We are using arrays insted of better types of collections becaused the code generated\r\n  by xsd.exe does not support other types.\r\n *****************************************************************************/\r\nNoDeviceType ^ AddDisconnectedPort(Object ^parent)\r\n{\r\n    RootHubType ^ rhParent = nullptr;\r\n    ExternalHubType ^ ehParent = nullptr;\r\n    array<NoDeviceType ^> ^ devicesArray = nullptr;\r\n    NoDeviceType ^ noD = nullptr;\r\n    boolean arrayCreated = false;\r\n\r\n    // An external hub can be connected to a Root Hub or another External Hub\r\n    // We need to determine the type of the object.\r\n\r\n    // Try RH first\r\n\r\n    rhParent = dynamic_cast<RootHubType ^> (parent);\r\n    if (rhParent == nullptr)\r\n    {\r\n        // RootHub cast was not successfult, try external hub\r\n        ehParent = dynamic_cast<ExternalHubType ^> (parent);\r\n        if (ehParent != nullptr)\r\n        {\r\n            // External hub parent\r\n            if (ehParent->NoDevice == nullptr)\r\n            {\r\n                // First hub in the list of external hubs\r\n                ehParent->NoDevice = gcnew array<NoDeviceType ^> (1);\r\n                arrayCreated = true;\r\n            }\r\n            devicesArray = ehParent->NoDevice;\r\n        }\r\n\r\n    }\r\n    else\r\n    {\r\n        // Parent is a root hub\r\n        if (rhParent->NoDevice == nullptr)\r\n        {\r\n            // First hub in root hub list\r\n            rhParent->NoDevice = gcnew array<NoDeviceType ^>(1);\r\n            arrayCreated = true;\r\n        }\r\n        devicesArray = rhParent->NoDevice;\r\n    }\r\n\r\n    if (devicesArray != nullptr)\r\n    {\r\n        if (arrayCreated)\r\n        {\r\n            // We created the array in this function, so we use offset 0\r\n            devicesArray[0] = gcnew NoDeviceType();\r\n            noD = devicesArray[0];\r\n        }\r\n        else\r\n        {\r\n            // The array was already present, we need to do elaborate things\r\n            // as array.resize does not work.\r\n            ArrayList ^exList = gcnew ArrayList();\r\n            exList->AddRange(devicesArray);\r\n            noD = gcnew NoDeviceType();\r\n            exList->Add(noD);\r\n\r\n            if (rhParent != nullptr)\r\n            {\r\n                rhParent->NoDevice = reinterpret_cast<array<NoDeviceType ^>^> (exList->ToArray(NoDeviceType::typeid));\r\n            }\r\n            else\r\n            {\r\n                ehParent->NoDevice = reinterpret_cast<array<NoDeviceType ^>^> (exList->ToArray(NoDeviceType::typeid));\r\n            }\r\n        }\r\n    }\r\n    return noD;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  UsbDeviceType ^ AddUsbDevice(Object ^parent)\r\n\r\n  This routine finds the type of the parent and adds a port connection object to the\r\n  parent's list of port connectors. The newly created object is returned\r\n  We are using arrays insted of better types of collections becaused the code generated\r\n  by xsd.exe does not support other types.\r\n *****************************************************************************/\r\nUsbDeviceType ^ AddUsbDevice(Object ^parent)\r\n{\r\n    RootHubType ^ rhParent = nullptr;\r\n    ExternalHubType ^ ehParent = nullptr;\r\n    array<UsbDeviceType ^> ^ devicesArray = nullptr;\r\n    UsbDeviceType ^ usbD = nullptr;\r\n    boolean arrayCreated = false;\r\n\r\n    // An external hub can be connected to a Root Hub or another External Hub\r\n    // We need to determine the type of the object.\r\n\r\n    // Try RH first\r\n\r\n    rhParent = dynamic_cast<RootHubType ^> (parent);\r\n    if (rhParent == nullptr)\r\n    {\r\n        // RootHub cast was not successfult, try external hub\r\n        ehParent = dynamic_cast<ExternalHubType ^> (parent);\r\n        if (ehParent != nullptr)\r\n        {\r\n            // External hub parent\r\n            if (ehParent->UsbDevice == nullptr)\r\n            {\r\n                // First hub in the list of external hubs\r\n                ehParent->UsbDevice = gcnew array<UsbDeviceType ^> (1);\r\n                arrayCreated = true;\r\n            }\r\n            devicesArray = ehParent->UsbDevice;\r\n        }\r\n\r\n    }\r\n    else\r\n    {\r\n        // Parent is a root hub\r\n        if (rhParent->UsbDevice == nullptr)\r\n        {\r\n            // First hub in root hub list\r\n            rhParent->UsbDevice = gcnew array<UsbDeviceType ^>(1);\r\n            arrayCreated = true;\r\n        }\r\n        devicesArray = rhParent->UsbDevice;\r\n    }\r\n\r\n    if (devicesArray != nullptr)\r\n    {\r\n        if (arrayCreated)\r\n        {\r\n            // We created the array in this function, so we use offset 0\r\n            devicesArray[0] = gcnew UsbDeviceType();\r\n            usbD = devicesArray[0];\r\n        }\r\n        else\r\n        {\r\n            // The array was already present, we need to do elaborate things\r\n            // as array.resize does not work.\r\n            ArrayList ^exList = gcnew ArrayList();\r\n            exList->AddRange(devicesArray);\r\n            usbD = gcnew UsbDeviceType();\r\n            exList->Add(usbD);\r\n\r\n            if (rhParent != nullptr)\r\n            {\r\n                rhParent->UsbDevice = reinterpret_cast<array<UsbDeviceType ^>^> (exList->ToArray(UsbDeviceType::typeid));\r\n            }\r\n            else\r\n            {\r\n                ehParent->UsbDevice = reinterpret_cast<array<UsbDeviceType ^>^> (exList->ToArray(UsbDeviceType::typeid));\r\n            }\r\n        }\r\n    }\r\n    return usbD;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddIADDescriptor()\r\n\r\n  This routine adds usb IAD descriptor\r\n *****************************************************************************/\r\nvoid XmlAddIADDescriptor(\r\n        UsbDeviceIADDescriptorType ^ iadXmlDesc,\r\n        PUSB_IAD_DESCRIPTOR iadDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        int nInterfaces)\r\n{\r\n    if (NULL == iadDesc || NULL == stringDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    // Update structure fields\r\n    iadXmlDesc->BLength = iadDesc->bLength;\r\n    iadXmlDesc->BDescriptorType = iadDesc->bDescriptorType;\r\n    iadXmlDesc->BFirstInterface = iadDesc->bFirstInterface;\r\n    iadXmlDesc->BInterfaceCount = iadDesc->bInterfaceCount;\r\n    iadXmlDesc->BFunctionClass = iadDesc->bFunctionClass;\r\n    iadXmlDesc->BFunctionSubclass = iadDesc->bFunctionSubClass;\r\n    iadXmlDesc->BFunctionProtocol = iadDesc->bFunctionProtocol;\r\n    iadXmlDesc->IFunction = iadDesc->iFunction;\r\n\r\n    // Validate fields\r\n    if (iadDesc->bInterfaceCount == 1)\r\n    {\r\n        iadXmlDesc->InterfaceError = gcnew String(\"ERROR: bInterfaceCount must be greater than 1\");\r\n    }\r\n    if (nInterfaces < iadDesc->bFirstInterface + iadDesc->bInterfaceCount)\r\n    {\r\n        iadXmlDesc->InterfaceError = gcnew String(\"ERROR:  The total number of interfaces\");\r\n        iadXmlDesc->InterfaceError += nInterfaces;\r\n        iadXmlDesc->InterfaceError += \" must be greater than or equal to the highest linked interface number (base \";\r\n        iadXmlDesc->InterfaceError += iadDesc->bFirstInterface;\r\n        iadXmlDesc->InterfaceError += \" + count \";\r\n        iadXmlDesc->InterfaceError += iadDesc->bInterfaceCount;\r\n        iadXmlDesc->InterfaceError += \" = \";\r\n        iadXmlDesc->InterfaceError += (iadDesc->bFirstInterface + iadDesc->bInterfaceCount);\r\n        iadXmlDesc->InterfaceError += \" )\";\r\n    }\r\n    if (iadDesc->bFunctionClass == 0)\r\n    {\r\n        iadXmlDesc->FunctionClassError = gcnew String(\"ERROR: bFunctionClass contains an illegal value 0\");\r\n    }\r\n\r\n    iadXmlDesc->FunctionDetails = XmlGetDeviceClass(\r\n            iadDesc->bFunctionClass,\r\n            iadDesc->bFunctionSubClass,\r\n            iadDesc->bFunctionProtocol);\r\n\r\n    // Protocol check\r\n    if (iadDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO)\r\n    {\r\n        if (iadDesc->bFunctionProtocol != PC_PROTOCOL_UNDEFINED)\r\n        {\r\n            iadXmlDesc->Protocol= gcnew String(\"WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED\");\r\n            iadXmlDesc->Protocol+= \" for this class but is set to: \";\r\n            iadXmlDesc->Protocol+= iadDesc->bFunctionProtocol;\r\n        }\r\n        else\r\n        {\r\n            iadXmlDesc->Protocol = gcnew String(\"PC_PROTOCOL_UNDEFINED protocol\");\r\n        }\r\n    }\r\n\r\n    if (iadDesc->iFunction)\r\n    {\r\n        // Add String descriptor\r\n        iadXmlDesc->StringDesc = XmlGetStringDescriptor(\r\n                iadDesc->iFunction,\r\n                stringDesc,\r\n                false);\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddOTGDescriptor()\r\n\r\n  This routine adds usb OTG descriptor\r\n *****************************************************************************/\r\nvoid XmlAddOTGDescriptor(\r\n        UsbDeviceOTGDescriptorType ^ otgXmlDesc,\r\n        PUSB_OTG_DESCRIPTOR otgDesc)\r\n{\r\n    if (NULL == otgDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    otgXmlDesc->BLength = otgDesc->bLength;\r\n    otgXmlDesc->BDescriptorType = otgDesc->bDescriptorType;\r\n    otgXmlDesc->BmAttributes = otgDesc->bmAttributes;\r\n\r\n    // Add descriptive fields\r\n    switch (otgDesc->bmAttributes)\r\n    {\r\n        case 0:\r\n            break;\r\n        case 1:\r\n            otgXmlDesc->AttributesString = gcnew String(\"SRP support\");\r\n            break;\r\n        case 2:\r\n            otgXmlDesc->AttributesString = gcnew String(\"HNP support\");\r\n            break;\r\n        case 3:\r\n            otgXmlDesc->AttributesString = gcnew String(\"SRP and HNP support\");\r\n            break;\r\n        default:\r\n            otgXmlDesc->AttributesString = gcnew String(\"ERROR:  bmAttributes bits 2-7 are reserved should be 0)\");\r\n            break;\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddHidDescriptor()\r\n\r\n  This routine adds usb HID descriptor\r\n *****************************************************************************/\r\nvoid XmlAddHidDescriptor(\r\n        UsbDeviceHidDescriptorType ^ hidXmlDesc,\r\n        PUSB_HID_DESCRIPTOR hidDesc\r\n        )\r\n{\r\n    int i = 0;\r\n\r\n    if (NULL == hidDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    hidXmlDesc->BLength = hidDesc->bLength;\r\n    hidXmlDesc->BDescriptorType = hidDesc->bDescriptorType;\r\n    hidXmlDesc->BcdHID = hidDesc->bcdHID;\r\n    hidXmlDesc->BCountryCode = hidDesc->bCountryCode;\r\n    hidXmlDesc->BNumDescriptors = hidDesc->bNumDescriptors;\r\n\r\n    // Add optional descriptors\r\n    if (hidDesc->bNumDescriptors > 0)\r\n    {\r\n        hidXmlDesc->OptionalDescriptor = gcnew array <UsbDeviceHidOptionalDescriptorsType ^>(hidDesc->bNumDescriptors);\r\n        for(i=0; i < hidDesc->bNumDescriptors; i++)\r\n        {\r\n            hidXmlDesc->OptionalDescriptor[i] = gcnew UsbDeviceHidOptionalDescriptorsType();\r\n            hidXmlDesc->OptionalDescriptor[i]->BDescriptorType = hidDesc->OptionalDescriptors[i].bDescriptorType;\r\n            hidXmlDesc->OptionalDescriptor[i]->WDescriptorLength = hidDesc->OptionalDescriptors[i].wDescriptorLength;\r\n        }\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetUnknownDescriptor()\r\n\r\n  This routine gets a usb unknown descriptor object form unknown descriptor\r\n *****************************************************************************/\r\nUsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor(\r\n        PUSB_COMMON_DESCRIPTOR unknownDesc\r\n        )\r\n{\r\n    int i = 0;\r\n    UsbDeviceUnknownDescriptorType ^ unknownXmlDesc = nullptr;\r\n\r\n    if (NULL == unknownDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    unknownXmlDesc = gcnew UsbDeviceUnknownDescriptorType();\r\n    unknownXmlDesc->BLength = unknownDesc->bLength;\r\n    unknownXmlDesc->BDescriptorType = unknownDesc->bDescriptorType;\r\n\r\n    // Add optional descriptors\r\n    if (unknownDesc->bLength > 0)\r\n    {\r\n        unknownXmlDesc->UnknownDescriptor = gcnew String(\"Unknown descriptor->\");\r\n        for(i=0; i < unknownDesc->bLength; i++)\r\n        {\r\n            unknownXmlDesc->UnknownDescriptor += String::Format(\"0x{0:X} \", ((PUCHAR) unknownDesc)[i]);\r\n        }\r\n    }\r\n    return unknownXmlDesc;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddEndpointDescriptor()\r\n\r\n  This routine adds usb endpoint descriptor and verbose fields\r\n *****************************************************************************/\r\nvoid XmlAddEndpointDescriptor(\r\n        EndpointDescriptorType ^usbXmlEndpointDescriptor,\r\n        PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor,\r\n        UCHAR connectionSpeed\r\n        )\r\n{\r\n    EndpointDescriptorType ^ue = usbXmlEndpointDescriptor;\r\n    ULONG maxBytes = endPointDescriptor->wMaxPacketSize & 0x7FF;\r\n\r\n    // Add structure values\r\n    ue->Length = endPointDescriptor->bLength;\r\n    ue->DescriptorType = endPointDescriptor->bDescriptorType;\r\n    ue->EndpointAddress = endPointDescriptor->bEndpointAddress;\r\n    ue->Attributes = endPointDescriptor->bmAttributes;\r\n    ue->MaxPacketSize = endPointDescriptor->wMaxPacketSize;\r\n\r\n    // Add verbose fields\r\n    ue->EndpointId = endPointDescriptor->bEndpointAddress & 0x0F;\r\n\r\n    // Add endpoint direction\r\n    if (USB_ENDPOINT_DIRECTION_OUT(endPointDescriptor->bEndpointAddress))\r\n    {\r\n        ue->EndpointDirection = gcnew String(\"Out\");\r\n    }\r\n    else if (USB_ENDPOINT_DIRECTION_IN(endPointDescriptor->bEndpointAddress))\r\n    {\r\n        ue->EndpointDirection = gcnew String(\"In\");\r\n    }\r\n\r\n    // Add endpoint type\r\n    switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK)\r\n    {\r\n        case USB_ENDPOINT_TYPE_CONTROL:\r\n            ue->EndpointType = gcnew String(\"Control Transfer Type\");\r\n            break;\r\n        case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n            switch (endPointDescriptor->bmAttributes & 0x0C)\r\n            {\r\n                case 0x00:\r\n                    ue->EndpointType = gcnew String(\"Ischronous Transfer Type - No Synchronization\");\r\n                    break;\r\n\r\n                case 0x04:\r\n                    ue->EndpointType = gcnew String(\"Ischronous Transfer Type - Asynchronous\");\r\n                    break;\r\n\r\n                case 0x08:\r\n                    ue->EndpointType = gcnew String(\"Ischronous Transfer Type - Adaptive\");\r\n                    break;\r\n\r\n                case 0x0C:\r\n                    ue->EndpointType = gcnew String(\"Ischronous Transfer Type - Synchronous\");\r\n                    break;\r\n            }\r\n            break;\r\n        case USB_ENDPOINT_TYPE_BULK:\r\n            ue->EndpointType = gcnew String(\"Bulk Transfer Type\");\r\n            break;\r\n\r\n        case USB_ENDPOINT_TYPE_INTERRUPT:\r\n            ue->EndpointType = gcnew String(\"Interrupt Transfer Type\");\r\n            break;\r\n    }\r\n\r\n    // Add packet info\r\n    switch (connectionSpeed)\r\n    {\r\n        case UsbHighSpeed:\r\n            if (endPointDescriptor->bmAttributes & 1) {\r\n                ULONG transactions = ((endPointDescriptor->wMaxPacketSize & 0x1800) >> 11) + 1;\r\n                // Isoc or Interrupt endpoint\r\n                ue->EndpointPacketInfo = gcnew String(\r\n                        transactions + \" transactions per microframe, \" +\r\n                        maxBytes + \" max bytes\");\r\n            }\r\n            else\r\n            {\r\n                // Bulk endpoint\r\n                ue->EndpointPacketInfo = gcnew String(maxBytes + \" max bytes\");\r\n            }\r\n            break;\r\n        case UsbFullSpeed:\r\n            ue->EndpointPacketInfo = gcnew String(maxBytes + \" max bytes\");\r\n            break;\r\n        default:\r\n            // Low or Invalid speed\r\n            ue->EndpointPacketInfo = gcnew String(\"Invalid bus speed\");\r\n            break;\r\n    }\r\n\r\n    // Add validation\r\n    if (endPointDescriptor->wMaxPacketSize & 0xE000)\r\n    {\r\n        ue->EndpointPacketSizeValidation = gcnew String(\"ERROR: wMaxPacketSize bits 15-13 should be 0\");\r\n    } else if (connectionSpeed==UsbHighSpeed)\r\n    {\r\n        USHORT hsMux;\r\n\r\n        hsMux = (endPointDescriptor->wMaxPacketSize >> 11) & 0x03;\r\n\r\n        switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK)\r\n            {\r\n            case USB_ENDPOINT_TYPE_ISOCHRONOUS:\r\n            case USB_ENDPOINT_TYPE_INTERRUPT:\r\n                switch (hsMux) {\r\n                case 0:\r\n                    if ((maxBytes < 1) || (maxBytes > 1024))\r\n                    {\r\n                        ue->EndpointPacketSizeValidation = gcnew String(\"ERROR: Invalid maximum packet size, should be between 1 and 1024\");\r\n                    }\r\n                    break;\r\n\r\n                case 1:\r\n                    if ((maxBytes < 513) || (maxBytes > 1024))\r\n                    {\r\n                        ue->EndpointPacketSizeValidation = gcnew String(\"ERROR: Invalid maximum packet size, should be between 513 and 1024\");\r\n                    }\r\n                    break;\r\n\r\n                case 2:\r\n                    if ((maxBytes < 683) || (maxBytes > 1024))\r\n                    {\r\n                        ue->EndpointPacketSizeValidation = gcnew String(\"ERROR: Invalid maximum packet size, should be between 683 and 1024\");\r\n                    }\r\n                    break;\r\n\r\n                case 3:\r\n                    ue->EndpointPacketSizeValidation = gcnew String(\"ERROR: Bits 12-11 set to reserved value\\r\\n\");\r\n                    break;\r\n            }\r\n        }\r\n    }\r\n\r\n    // Add interval\r\n    if (endPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR))\r\n    {\r\n        ue->Interval = endPointDescriptor->bInterval;\r\n    }\r\n    else\r\n    {\r\n        PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2) endPointDescriptor;\r\n        ue->WInterval = endpointDesc2->wInterval;\r\n        ue->SyncAddress = endpointDesc2->bSyncAddress;\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddPipeInformation()\r\n\r\n  This routine adds all the pipe information for device\r\n *****************************************************************************/\r\nvoid XmlAddPipeInformation(\r\n        array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList,\r\n        PUSB_PIPE_INFO pipeInfo,\r\n        ULONG numPipes,\r\n        UCHAR connectionSpeed\r\n        )\r\n{\r\n    ULONG i = 0;\r\n\r\n    for(i = 0; i< numPipes; i++)\r\n    {\r\n        // Add all pipe in the list\r\n        usbXmlPipeInfoList[i] = gcnew UsbPipeInfoType();\r\n        usbXmlPipeInfoList[i]->EndpointDescriptor = gcnew EndpointDescriptorType();\r\n        XmlAddEndpointDescriptor(\r\n                usbXmlPipeInfoList[i]->EndpointDescriptor,\r\n                &pipeInfo[i].EndpointDescriptor,\r\n                connectionSpeed);\r\n        usbXmlPipeInfoList[i]->ScheduleOffset = pipeInfo->ScheduleOffset;\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddUsbDeviceDescriptor()\r\n\r\n  This routine adds usb device descriptor\r\n *****************************************************************************/\r\nvoid XmlAddUsbDeviceDescriptor(\r\n        UsbDeviceDescriptorType ^usbXmlDeviceDescriptor,\r\n        PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor)\r\n{\r\n    UsbDeviceDescriptorType ^ud = usbXmlDeviceDescriptor;\r\n\r\n    // Map all fields explicitly\r\n\r\n    ud->Length = usbDeviceDescriptor->bLength;\r\n    ud->DescriptorType = usbDeviceDescriptor->bDescriptorType;\r\n    ud->CdUSB= usbDeviceDescriptor->bcdUSB;\r\n    ud->DeviceClass = usbDeviceDescriptor->bDeviceClass;\r\n    ud->DeviceSubclass = usbDeviceDescriptor->bDeviceSubClass;\r\n    ud->DeviceProtocol = usbDeviceDescriptor->bDeviceProtocol;\r\n    ud->MaxPacketSize0 = usbDeviceDescriptor->bMaxPacketSize0;\r\n    ud->IdVendor = usbDeviceDescriptor->idVendor;\r\n    ud->IdProduct = usbDeviceDescriptor->idProduct ;\r\n    ud->CdDevice = usbDeviceDescriptor->bcdDevice;\r\n    ud->IManufacturer = usbDeviceDescriptor->iManufacturer;\r\n    ud->IProduct = usbDeviceDescriptor->iProduct;\r\n    ud->ISerialNumber = usbDeviceDescriptor->iSerialNumber;\r\n    ud->NumConfigurations = usbDeviceDescriptor->bNumConfigurations;\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddConfigurationDescriptor()\r\n\r\n  This routine adds the configuration descriptor\r\n *****************************************************************************/\r\nvoid XmlAddConfigurationDescriptor(\r\n        UsbConfigurationDescriptorType ^ confXmlDesc,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        )\r\n\r\n{\r\n    UINT uCount = 0;\r\n    BOOL isSuperSpeed = FALSE;\r\n\r\n    if (NULL == configDesc || NULL == deviceInfo)\r\n    {\r\n        return;\r\n    }\r\n\r\n    if(deviceInfo->ConnectionInfoV2 &&\r\n       (deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher ||\r\n        deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher))\r\n    {\r\n        isSuperSpeed = TRUE;\r\n    }\r\n\r\n    confXmlDesc->BLength = configDesc->bLength;\r\n    confXmlDesc->BDescriptorType = configDesc->bDescriptorType;\r\n    confXmlDesc->WTotalLength = configDesc->wTotalLength;\r\n    confXmlDesc->BNumInterfaces = configDesc->bNumInterfaces;\r\n    confXmlDesc->BConfigurationValue = configDesc->bConfigurationValue;\r\n    confXmlDesc->IConfiguration = configDesc->iConfiguration;\r\n    confXmlDesc->BmAttributes = configDesc->bmAttributes;\r\n    confXmlDesc->MaxPower = configDesc->MaxPower;\r\n\r\n    uCount = GetConfigurationSize(deviceInfo);\r\n\r\n    if (uCount != configDesc->wTotalLength)\r\n    {\r\n        confXmlDesc->ConfigDescError = gcnew String(\"ERROR: Invalid total configuration size \" +\r\n                configDesc->wTotalLength + \", should be \" +  uCount);\r\n    }\r\n\r\n    if (configDesc->bConfigurationValue != 1)\r\n    {\r\n        confXmlDesc->ConfValueError = gcnew String(\"CAUTION: Most host controllers will only work with one configuration per speed\");\r\n    }\r\n\r\n    if (configDesc->iConfiguration)\r\n    {\r\n        confXmlDesc->ConfStringDesc = XmlGetStringDescriptor(\r\n                configDesc->iConfiguration,\r\n                stringDesc,\r\n                false);\r\n    }\r\n\r\n    if (configDesc->bmAttributes & USB_CONFIG_BUS_POWERED)\r\n    {\r\n        confXmlDesc->AttributesStr = gcnew String(\"Bus Powered\");\r\n    }\r\n    else if (configDesc->bmAttributes & USB_CONFIG_SELF_POWERED)\r\n    {\r\n        confXmlDesc->AttributesStr = gcnew String(\"Self Powered\");\r\n    }\r\n    else if (configDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP)\r\n    {\r\n        confXmlDesc->AttributesStr = gcnew String(\"Remote Wakeup\");\r\n    }\r\n    else\r\n    {\r\n        confXmlDesc->AttributesStr = gcnew String(\"WARNING: bmAttributes is using reserved space\");\r\n    }\r\n\r\n    confXmlDesc->MaxCurrent = gcnew String(\"\");\r\n    confXmlDesc->MaxCurrent += (isSuperSpeed?configDesc->MaxPower * 8:configDesc->MaxPower * 2);\r\n    confXmlDesc->MaxCurrent += \" mA\";\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetDeviceClass()\r\n\r\n  This routine returns the interface class and subclass for given interface descriptor\r\n *****************************************************************************/\r\nUsbDeviceClassType ^ XmlGetDeviceClass(UCHAR bInterfaceClass, UCHAR bInterfaceSubclass, UCHAR bInterfaceProtocol)\r\n{\r\n    String ^ deviceClass = nullptr;\r\n    String ^ deviceSubclass = nullptr;\r\n    UsbDeviceClassType ^ deviceDetails = gcnew UsbDeviceClassType();\r\n\r\n    switch (bInterfaceClass)\r\n    {\r\n        case USB_DEVICE_CLASS_AUDIO:\r\n            deviceClass = gcnew String(\"Audio Interface\");\r\n\r\n            switch (bInterfaceSubclass)\r\n            {\r\n                case USB_AUDIO_SUBCLASS_AUDIOCONTROL:\r\n                    deviceSubclass = gcnew String(\"Audio Control Interface\");\r\n                    break;\r\n\r\n                case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:\r\n                    deviceSubclass = gcnew String(\"Audio Streaming Interface\");\r\n                    break;\r\n\r\n                case USB_AUDIO_SUBCLASS_MIDISTREAMING:\r\n                    deviceSubclass = gcnew String(\"MIDI Streaming Interface\");\r\n                    break;\r\n\r\n                default:\r\n                    deviceSubclass = gcnew String(\"CAUTION: This appears to be an invalid bInterfaceSubclass : \");\r\n                    deviceSubclass += bInterfaceSubclass;\r\n                    break;\r\n            }\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_VIDEO:\r\n            deviceClass = gcnew String(\"Video Interface\");\r\n\r\n            switch(bInterfaceSubclass)\r\n            {\r\n                case VIDEO_SUBCLASS_CONTROL:\r\n                    deviceSubclass = gcnew String(\"Video Control\");\r\n                    break;\r\n\r\n                case VIDEO_SUBCLASS_STREAMING:\r\n                    deviceSubclass = gcnew String(\"Video Streaming\");\r\n                    break;\r\n\r\n                default:\r\n                    deviceSubclass = gcnew String(\"CAUTION: This appears to be an invalid bInterfaceSubclass : \");\r\n                    deviceSubclass += bInterfaceSubclass;\r\n                    break;\r\n            }\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_VENDOR_SPECIFIC:\r\n            deviceClass = gcnew String(\"Vendor Specific Device\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_HUMAN_INTERFACE:\r\n\r\n            deviceClass = gcnew String(\"HID Interface\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_HUB:\r\n            deviceClass = gcnew String(\"HUB Interface\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_RESERVED:\r\n            deviceClass = gcnew String(\"CAUTION: Reserved USB Device Interface Class\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_COMMUNICATIONS:\r\n            deviceClass = gcnew String(\"Communications (CDC Control) USB Device\\r\\n\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_MONITOR:\r\n            deviceClass = gcnew String(\"Monitor USB Device Interface Class*** (This may be obsolete)\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:\r\n            deviceClass = gcnew String(\"Physical Interface USB Device\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_POWER:\r\n            if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1)\r\n            {\r\n                deviceClass = gcnew String(\"Image USB Device\");\r\n            }\r\n            else\r\n            {\r\n                deviceClass = gcnew String(\"Power USB Device (This may be obsolete)\");\r\n            }\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_PRINTER:\r\n            deviceClass = gcnew String(\"Printer USB Device\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_STORAGE:\r\n            deviceClass = gcnew String(\"Mass Storage USB Device\");\r\n            break;\r\n\r\n        case USB_CDC_DATA_INTERFACE:\r\n            deviceClass = gcnew String(\"CDC Data USB Device\");\r\n            break;\r\n\r\n        case USB_CHIP_SMART_CARD_INTERFACE:\r\n            deviceClass = gcnew String(\"Chip/Smart Card USB Device\");\r\n            break;\r\n\r\n        case USB_CONTENT_SECURITY_INTERFACE:\r\n            deviceClass = gcnew String(\"Content Security USB Device\");\r\n            break;\r\n\r\n        case USB_DIAGNOSTIC_DEVICE_INTERFACE:\r\n            if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1)\r\n            {\r\n                deviceClass = gcnew String(\"Reprogrammable USB2 Compliance Diagnostic Device USB Device\");\r\n            }\r\n            else\r\n            {\r\n                deviceClass = gcnew String(\"CAUTION: This appears to be an invalid device class: \");\r\n                deviceClass += bInterfaceClass;\r\n            }\r\n            break;\r\n\r\n        case USB_WIRELESS_CONTROLLER_INTERFACE:\r\n            if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1)\r\n            {\r\n                deviceClass = gcnew String(\"Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\");\r\n            }\r\n            else\r\n            {\r\n                deviceClass = gcnew String(\"CAUTION: This appears to be an invalid device class: \");\r\n                deviceClass += bInterfaceClass;\r\n            }\r\n            break;\r\n\r\n        case USB_APPLICATION_SPECIFIC_INTERFACE:\r\n            deviceClass = gcnew String(\"Application Specific USB Device\");\r\n\r\n            switch(bInterfaceSubclass)\r\n            {\r\n                case 1:\r\n                    deviceSubclass = gcnew String(\"Device Firmware Application Specific USB Device\");\r\n                    break;\r\n                case 2:\r\n                    deviceSubclass = gcnew String(\"IrDA Bridge Application Specific USB Device\");\r\n                    break;\r\n                case 3:\r\n                    deviceSubclass = gcnew String(\"Test & Measurement Class (USBTMC) Application Specific USB Device\");\r\n                    break;\r\n                default:\r\n                    deviceSubclass = gcnew String(\"CAUTION: This appears to be an invalid bInterfaceSubclass : \");\r\n                    deviceSubclass += bInterfaceSubclass;\r\n            }\r\n            break;\r\n        case USB_DEVICE_CLASS_BILLBOARD:\r\n            deviceClass = gcnew String(\"Billboard Class\");\r\n            switch (bInterfaceSubclass)\r\n            {\r\n            case 0:\r\n                deviceSubclass = gcnew String(\"Billboard Subclass\");\r\n                break;\r\n            default:\r\n                deviceSubclass = gcnew String(\"CAUTION: This appears to be an invalid bInterfaceSubClass\");\r\n                break;\r\n            }\r\n            break;\r\n        default:\r\n\r\n            deviceClass = gcnew String(\"Interface Class unknown : \");\r\n            deviceClass += bInterfaceClass;\r\n            break;\r\n    }\r\n\r\n    // Return class and subclass\r\n\r\n    deviceDetails->DeviceClass = deviceClass;\r\n    deviceDetails->DeviceSubclass = deviceSubclass;\r\n\r\n    return deviceDetails;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddInterfaceDescriptor()\r\n\r\n  This routine adds the device interface descriptor\r\n *****************************************************************************/\r\nvoid XmlAddDeviceInterfaceDescriptor(\r\n        UsbDeviceInterfaceDescriptorType ^ ifXmlDesc,\r\n        PUSB_INTERFACE_DESCRIPTOR ifDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc)\r\n{\r\n    if (NULL == ifDesc || NULL == stringDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    // Update structure fields\r\n    ifXmlDesc->BLength = ifDesc->bLength;\r\n    ifXmlDesc->BDescriptorType = ifDesc->bDescriptorType;\r\n    ifXmlDesc->BInterfaceNumber = ifDesc->bInterfaceNumber;\r\n    ifXmlDesc->BAlternateSetting = ifDesc->bAlternateSetting;\r\n    ifXmlDesc->BNumEndpoints = ifDesc->bNumEndpoints;\r\n    ifXmlDesc->BInterfaceClass = ifDesc->bInterfaceClass;\r\n    ifXmlDesc->BInterfaceSubclass = ifDesc->bInterfaceSubClass;\r\n    ifXmlDesc->BInterfaceProtocol = ifDesc->bInterfaceProtocol;\r\n    ifXmlDesc->IInterface = ifDesc->iInterface;\r\n\r\n    // Update class and sub class\r\n    ifXmlDesc->InterfaceDetails = XmlGetDeviceClass(\r\n            ifDesc->bInterfaceClass,\r\n            ifDesc->bInterfaceSubClass,\r\n            ifDesc->bInterfaceProtocol);\r\n\r\n    //This is basically the check for PC_PROTOCOL_UNDEFINED\r\n    if ((ifDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) ||\r\n            (ifDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO))\r\n    {\r\n        if (ifDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED)\r\n        {\r\n            ifXmlDesc->ProtocolError = gcnew String(\"WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED\");\r\n            ifXmlDesc->ProtocolError += \" for this class but is set to: \";\r\n            ifXmlDesc->ProtocolError += ifDesc->bInterfaceProtocol;\r\n        }\r\n    }\r\n\r\n    if (ifDesc->iInterface)\r\n    {\r\n        // Add String descriptor\r\n        ifXmlDesc->StringDesc = XmlGetStringDescriptor(\r\n                ifDesc->iInterface,\r\n                stringDesc,\r\n                false);\r\n    }\r\n\r\n    if (ifDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2))\r\n    {\r\n        PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2;\r\n\r\n        interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)ifDesc;\r\n\r\n        ifXmlDesc->WNumClasses = interfaceDesc2->wNumClasses;\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddDeviceQualDescriptor()\r\n\r\n  This routine adds the device qualifier descriptor\r\n *****************************************************************************/\r\n\r\nvoid XmlAddDeviceQualDescriptor(\r\n        UsbDeviceQualifierDescriptorType ^ qualXmlDesc,\r\n        PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc)\r\n{\r\n    if (NULL == qualDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    // Add structure fields\r\n    qualXmlDesc->BLength = qualDesc->bLength;\r\n    qualXmlDesc->BDescriptorType = qualDesc->bDescriptorType;\r\n    qualXmlDesc->BcdUSB = qualDesc->bcdUSB;\r\n    qualXmlDesc->BDeviceClass = qualDesc->bDeviceClass;\r\n    qualXmlDesc->BDeviceSubclass = qualDesc->bDeviceSubClass;\r\n    qualXmlDesc->BDeviceProtocol = qualDesc->bDeviceProtocol;\r\n    qualXmlDesc->BMaxPacketSize0 = qualDesc->bMaxPacketSize0;\r\n    qualXmlDesc->NumConfigurations = qualDesc->bNumConfigurations;\r\n\r\n    // Get device class string\r\n    qualXmlDesc->DeviceClass = XmlGetDeviceClassString(qualDesc->bDeviceClass);\r\n\r\n    if (qualDesc->bDeviceSubClass > 0x00 && qualDesc->bDeviceSubClass < 0xFF)\r\n    {\r\n        qualXmlDesc->DeviceSubclassError = gcnew String(\"ERROR:  bDeviceSubClass is invalid : \");\r\n        qualXmlDesc->DeviceSubclassError += qualDesc->bDeviceSubClass;\r\n    }\r\n\r\n    if (qualDesc->bDeviceProtocol > 0x00 && qualDesc->bDeviceProtocol < 0xFF)\r\n    {\r\n        qualXmlDesc->DeviceProtocolError = gcnew String(\"ERROR:  bDeviceProtocol is invalid : \");\r\n        qualXmlDesc->DeviceProtocolError += qualDesc->bDeviceProtocol;\r\n    }\r\n\r\n    qualXmlDesc->MaxPacketSizeInBytes = qualDesc->bMaxPacketSize0;\r\n\r\n    if (qualDesc->bNumConfigurations != 1)\r\n    {\r\n        qualXmlDesc->DeviceNumConfigError = gcnew String(\r\n                \"CAUTION: Most host controllers will only work with one configuration per speed\");\r\n    }\r\n\r\n    if (qualDesc->bReserved != 0)\r\n    {\r\n        qualXmlDesc->ReservedError = gcnew String(\"WARNING: bReserved needs to be set to 0 to be valid - \" +\r\n                                                        qualDesc->bReserved);\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddAddConfigDescriptors()\r\n\r\n  This routine adds the all the config descriptors\r\n *****************************************************************************/\r\narray < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors(\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDescs,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        )\r\n{\r\n    array < UsbDeviceConfigurationType ^> ^ confXmlDescs = nullptr;\r\n    PUSB_COMMON_DESCRIPTOR commonDesc = NULL;\r\n    PUCHAR descEnd = NULL;\r\n    ArrayList ^confList = gcnew ArrayList;\r\n    UsbDeviceConfigurationType ^ deviceConf = nullptr;\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR) configDescs;\r\n    descEnd = (PUCHAR) configDescs + configDescs->wTotalLength;\r\n\r\n    while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&\r\n        (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)\r\n    {\r\n        // Add the config descriptor\r\n        deviceConf = gcnew UsbDeviceConfigurationType();\r\n\r\n        XmlAddDeviceConfiguration(\r\n                deviceConf,\r\n                deviceInfo,\r\n                (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc,\r\n                stringDesc,\r\n                configDescs->bNumInterfaces\r\n                );\r\n\r\n        confList->Add(deviceConf);\r\n        commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength);\r\n    }\r\n\r\n    confXmlDescs = reinterpret_cast<array<UsbDeviceConfigurationType ^>^> (confList->ToArray(UsbDeviceConfigurationType::typeid));\r\n    return confXmlDescs;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddDeviceConfiguration()\r\n\r\n  This routine adds the device configuration\r\n *****************************************************************************/\r\nvoid XmlAddDeviceConfiguration(\r\n        UsbDeviceConfigurationType ^ confXmlDesc,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PUSB_CONFIGURATION_DESCRIPTOR configDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        int numInterfaces\r\n        )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR commonDesc = NULL;\r\n    UCHAR bInterfaceClass = 0;\r\n    UCHAR bInterfaceSubclass = 0;\r\n    UCHAR bInterfaceProtocol = 0;\r\n    BOOL displayUnknown = FALSE;\r\n\r\n    if (NULL == deviceInfo || NULL == configDesc || NULL == stringDesc)\r\n    {\r\n        return;\r\n    }\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR)configDesc;\r\n    displayUnknown = FALSE;\r\n\r\n    switch (commonDesc->bDescriptorType)\r\n    {\r\n        case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR))\r\n            {\r\n                // Validate descriptor\r\n                confXmlDesc->DeviceQualifierError = String::Format(\r\n                        \"ERROR: Device Qualifier bLength value incorrect Obtained: {0} Expected {1}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n            // Add device Qual descriptor\r\n            confXmlDesc->DeviceQualifierDescriptor = gcnew UsbDeviceQualifierDescriptorType();\r\n\r\n            XmlAddDeviceQualDescriptor(\r\n                 confXmlDesc->DeviceQualifierDescriptor,\r\n                 (PUSB_DEVICE_QUALIFIER_DESCRIPTOR) commonDesc);\r\n            break;\r\n\r\n        case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n            {\r\n                // Validate descriptor\r\n                confXmlDesc->SpeedConfigurationError = String::Format(\r\n                        \"ERROR: Other speed configuration bLength value incorrect Obtained: {0} Expected {1}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_CONFIGURATION_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n            }\r\n\r\n            // Add configuration desc\r\n            confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType();\r\n\r\n            XmlAddConfigurationDescriptor(\r\n                    confXmlDesc->ConfigurationDescriptor,\r\n                    deviceInfo,\r\n                    (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc,\r\n                    stringDesc);\r\n            break;\r\n\r\n        case USB_CONFIGURATION_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))\r\n            {\r\n                // Validate descriptor\r\n                confXmlDesc->SpeedConfigurationError = String::Format(\r\n                        \"ERROR: Configuration bLength value incorrect Obtained: {0} Expected {1}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_CONFIGURATION_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n\r\n            // Add configuration desc\r\n            confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType();\r\n            XmlAddConfigurationDescriptor(\r\n                    confXmlDesc->ConfigurationDescriptor,\r\n                    deviceInfo,\r\n                    (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc,\r\n                    stringDesc);\r\n            break;\r\n\r\n        case USB_INTERFACE_DESCRIPTOR_TYPE:\r\n            if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) &&\r\n                    (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)))\r\n            {\r\n                // Validate descriptor\r\n                confXmlDesc->InterfaceError = String::Format(\r\n                        \"ERROR: Interface bLength value incorrect Obtained: {0} Expected: {1} or {2}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_INTERFACE_DESCRIPTOR),\r\n                        sizeof(USB_INTERFACE_DESCRIPTOR2));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n\r\n            // Add interface descriptor\r\n            bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass;\r\n            bInterfaceSubclass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass;\r\n            bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol;\r\n\r\n            confXmlDesc->InterfaceDescriptor = gcnew UsbDeviceInterfaceDescriptorType();\r\n            XmlAddDeviceInterfaceDescriptor(\r\n                    confXmlDesc->InterfaceDescriptor,\r\n                    (PUSB_INTERFACE_DESCRIPTOR) commonDesc,\r\n                    stringDesc\r\n                    );\r\n\r\n        case USB_ENDPOINT_DESCRIPTOR_TYPE:\r\n            if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) &&\r\n                    (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2)))\r\n            {\r\n                // Validate endpoint descriptor\r\n                confXmlDesc->EndpointError = String::Format(\r\n                        \"ERROR: Endpoint bLength value incorrect Obtained: {0} Expected: {1} or {2}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_ENDPOINT_DESCRIPTOR),\r\n                        sizeof(USB_ENDPOINT_DESCRIPTOR2));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n\r\n            confXmlDesc->EndpointDescriptor = gcnew EndpointDescriptorType();\r\n\r\n            if (NULL != deviceInfo->ConnectionInfo)\r\n            {\r\n                // Add endpoint descriptor\r\n                XmlAddEndpointDescriptor(\r\n                        confXmlDesc->EndpointDescriptor,\r\n                        (PUSB_ENDPOINT_DESCRIPTOR) commonDesc,\r\n                        deviceInfo->ConnectionInfo->Speed);\r\n            }\r\n\r\n            break;\r\n\r\n        case USB_HID_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR))\r\n            {\r\n                // Validate HID\r\n                confXmlDesc->HidError = String::Format(\r\n                        \"ERROR: HID bLength value incorrect Obtained: {0} Expected: {1}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_HID_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n\r\n            // Add HID descriptor\r\n            confXmlDesc->HidDescriptor = gcnew UsbDeviceHidDescriptorType();\r\n            XmlAddHidDescriptor(\r\n                    confXmlDesc->HidDescriptor,\r\n                    (PUSB_HID_DESCRIPTOR) commonDesc\r\n                    );\r\n            break;\r\n\r\n        case USB_OTG_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR))\r\n            {\r\n                // Validate length\r\n                confXmlDesc->HidError = String::Format(\r\n                        \"ERROR: OTG bLength value incorrect Obtained: {0} Expected: {1}\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_OTG_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n                break;\r\n            }\r\n\r\n            // Add OTG descriptor\r\n            confXmlDesc->OtgDescriptor = gcnew UsbDeviceOTGDescriptorType();\r\n            XmlAddOTGDescriptor(\r\n                    confXmlDesc->OtgDescriptor,\r\n                    (PUSB_OTG_DESCRIPTOR) commonDesc\r\n                    );\r\n            break;\r\n\r\n        case USB_IAD_DESCRIPTOR_TYPE:\r\n            if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR))\r\n            {\r\n                // Validate length\r\n                confXmlDesc->IadError = String::Format(\r\n                        \"ERROR: IAD bLength value incorrect\",\r\n                        commonDesc->bLength,\r\n                        sizeof(USB_OTG_DESCRIPTOR));\r\n                displayUnknown = TRUE;\r\n            }\r\n\r\n            // Add IAD descriptor\r\n            confXmlDesc->IadDescriptor = gcnew UsbDeviceIADDescriptorType();\r\n            XmlAddIADDescriptor(\r\n                    confXmlDesc->IadDescriptor,\r\n                    (PUSB_IAD_DESCRIPTOR) commonDesc,\r\n                    stringDesc,\r\n                    numInterfaces\r\n                    );\r\n            break;\r\n\r\n        default:\r\n            // Interface class device (?)\r\n            confXmlDesc->DeviceDetails = XmlGetDeviceClass(\r\n                    ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceClass,\r\n                    ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceSubClass,\r\n                    ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceProtocol\r\n                    );\r\n            break;\r\n    }\r\n\r\n    if (displayUnknown)\r\n    {\r\n        // Add unknown descriptor\r\n        confXmlDesc->UnknownDescriptor = XmlGetUnknownDescriptor(commonDesc);\r\n    }\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddConnectionInfoSt()\r\n\r\n  This routine adds connection information structures for the device\r\n *****************************************************************************/\r\nvoid XmlAddConnectionInfoSt(\r\n        NodeConnectionInfoExStructType ^xmlConnectionInfoSt,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PDEVICE_INFO_NODE pNode)\r\n{\r\n    NodeConnectionInfoExStructType ^nS = xmlConnectionInfoSt;\r\n\r\n    nS->ConnectionIndex = connectionInfo->ConnectionIndex;\r\n\r\n    nS->DeviceDescriptor = gcnew UsbDeviceDescriptorType();\r\n\r\n    XmlAddUsbDeviceDescriptor(nS->DeviceDescriptor, &(connectionInfo->DeviceDescriptor));\r\n\r\n    nS->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue;\r\n    nS->Speed = connectionInfo->Speed;\r\n    nS->SpeedStr = static_cast<UsbConnectionSpeedType> (connectionInfo->Speed);\r\n    nS->DeviceIsHub = connectionInfo->DeviceIsHub? true: false;\r\n    nS->NumOfOpenPipes = connectionInfo->NumberOfOpenPipes;\r\n    nS->UsbConnectionStatus = static_cast<UsbConnectionStatusType> (connectionInfo->ConnectionStatus);\r\n\r\n    if(NULL != pNode)\r\n    {\r\n        nS->DevicePowerState = static_cast<DevicePowerStateType>(pNode->LatestDevicePowerState);\r\n    }\r\n    else\r\n    {\r\n        nS->DevicePowerState = static_cast<DevicePowerStateType>(PowerDeviceUnspecified);\r\n    }\r\n\r\n    // Add the pipe list\r\n    if (connectionInfo->NumberOfOpenPipes > 0)\r\n    {\r\n        nS->Pipe =  gcnew array <UsbPipeInfoType ^>(connectionInfo->NumberOfOpenPipes);\r\n        XmlAddPipeInformation(\r\n                nS->Pipe,\r\n                connectionInfo->PipeList,\r\n                connectionInfo->NumberOfOpenPipes,\r\n                connectionInfo->Speed\r\n                );\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetLangIdString()\r\n\r\n  Obtains the language string for given string descriptor index\r\n *****************************************************************************/\r\nString ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc)\r\n{\r\n    String ^langIdStr = nullptr;\r\n    bool foundDescriptor = false;\r\n\r\n    while(stringDesc)\r\n    {\r\n        if (stringDesc->DescriptorIndex == index)\r\n        {\r\n            langIdStr = PACHAR_TO_STRING(GetLangIDString(stringDesc->LanguageID));\r\n\r\n            if (langIdStr == nullptr)\r\n            {\r\n                langIdStr = gcnew String(\"WARNING: Invalid language ID: \" + stringDesc->LanguageID);\r\n            }\r\n            foundDescriptor = true;\r\n            break;\r\n        }\r\n        stringDesc = stringDesc->Next;\r\n    }\r\n\r\n    if (foundDescriptor == false)\r\n    {\r\n        // If no descriptor was found, return error message in field\r\n        langIdStr = gcnew String(\"ERROR: No String descriptor for index \" + index);\r\n    }\r\n\r\n    return langIdStr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetStringDescriptor()\r\n\r\n  Obtains the string descriptor for given string descriptor index\r\n *****************************************************************************/\r\n\r\nString ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly)\r\n{\r\n    ULONG nBytes = 0;\r\n\r\n    CHAR pString[MAX_STRING_DESCRIPTOR_LENGTH];\r\n    String ^desc = nullptr;\r\n    bool foundDescriptor = false;\r\n    bool foundNonEnglishDescriptor = false;\r\n\r\n    ZeroMemory(pString, MAX_STRING_DESCRIPTOR_LENGTH);\r\n\r\n    while(stringDesc)\r\n    {\r\n        if (stringDesc->DescriptorIndex == index)\r\n        {\r\n            if (enOnly && stringDesc->LanguageID != STRING_DESCRIPTOR_EN_LANGUAGE_ID)\r\n            {\r\n                // If we are required to return only english descriptor, continue\r\n                foundNonEnglishDescriptor = true;\r\n                continue;\r\n            }\r\n\r\n            nBytes = WideCharToMultiByte(\r\n                    CP_ACP,\r\n                    WC_NO_BEST_FIT_CHARS,\r\n                    stringDesc->StringDescriptor->bString,\r\n                    (stringDesc->StringDescriptor->bLength -2)/2,\r\n                    pString,\r\n                    MAX_STRING_DESCRIPTOR_LENGTH,\r\n                    NULL,\r\n                    NULL\r\n                    );\r\n\r\n            if (nBytes)\r\n            {\r\n                foundDescriptor = true;\r\n                desc = PACHAR_TO_STRING(pString);\r\n            }\r\n            break;\r\n        }\r\n        stringDesc = stringDesc->Next;\r\n    }\r\n\r\n    if ((foundDescriptor == false) && (foundNonEnglishDescriptor == false))\r\n    {\r\n        // If no descriptor was found, return error message in field\r\n        desc = gcnew String(\"ERROR: No String descriptor for index \" +\r\n                    index);\r\n    }\r\n    else if ((foundDescriptor == false) && (foundNonEnglishDescriptor == true) && (enOnly))\r\n    {\r\n        desc = gcnew String(\"ERROR: The index \" + index + \" does not support English(US)\");\r\n    }\r\n\r\n    return desc;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetDeviceClassString()\r\n\r\n  Returns the device class string for given device class ID\r\n *****************************************************************************/\r\n\r\nString ^ XmlGetDeviceClassString(UCHAR deviceClass)\r\n{\r\n    String ^ deviceClassStr = nullptr;\r\n\r\n    // Not an IAD device\r\n    switch (deviceClass)\r\n    {\r\n        case USB_INTERFACE_CLASS_DEVICE:\r\n            deviceClassStr = gcnew String(\"Interface Class Defined Device\");\r\n            break;\r\n\r\n        case USB_COMMUNICATION_DEVICE:\r\n            deviceClassStr = gcnew String(\"Communication Device\");\r\n            break;\r\n\r\n        case USB_HUB_DEVICE:\r\n            deviceClassStr = gcnew String(\"Hub Device\");\r\n            break;\r\n\r\n        case USB_DIAGNOSTIC_DEVICE:\r\n            deviceClassStr = gcnew String(\"Diagnostic Device\");\r\n            break;\r\n\r\n        case USB_WIRELESS_CONTROLLER_DEVICE:\r\n            deviceClassStr = gcnew String(\"Wireless Controller(Bluetooth) Device\");\r\n            break;\r\n\r\n        case USB_VENDOR_SPECIFIC_DEVICE:\r\n            deviceClassStr = gcnew String(\"Vendor specific device\");\r\n            break;\r\n\r\n        case USB_DEVICE_CLASS_BILLBOARD:\r\n            deviceClassStr = gcnew String(\"Billboard class device\");\r\n            break;\r\n\r\n        default:\r\n            deviceClassStr= gcnew String(\"ERROR: unknown bDeviceClass\" + deviceClass);\r\n            break;\r\n    }\r\n    return deviceClassStr;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddDeviceClassDetails()\r\n\r\n  This routine adds device class details\r\n *****************************************************************************/\r\nbool XmlAddDeviceClassDetails(\r\n        UsbDeviceClassDetailsType ^ deviceDetails,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PUSBDEVICEINFO deviceInfo)\r\n{\r\n    UINT uIADcount = 0;\r\n    bool tog = true;\r\n\r\n    uIADcount = IsIADDevice((PUSBDEVICEINFO) deviceInfo);\r\n\r\n    if (uIADcount)\r\n    {\r\n        // IAD device, check validity of device class\r\n        if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE)\r\n        {\r\n            tog = false;\r\n            deviceDetails->DeviceType = gcnew String(\"Multi-interface Function Code Device\");\r\n        }\r\n        else {\r\n            deviceDetails->DeviceTypeError = gcnew String(\"ERROR: device class should be Multi-interface Function \" +\r\n                                                          USB_MISCELLANEOUS_DEVICE +\r\n                                                          \"is used\");\r\n        }\r\n        deviceDetails->UvcVersion = IsUVCDevice((PUSBDEVICEINFO) deviceInfo);\r\n\r\n        // This device configuration has 1 or more IAD descriptors\r\n        if (connectionInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS)\r\n        {\r\n            deviceDetails->SubclassType = gcnew String(\"Common Class Sub Class\");\r\n        }\r\n        else\r\n        {\r\n            deviceDetails->SubclassTypeError = gcnew String(\"ERROR: device SubClass should be USB Common Sub Class\" +\r\n                                                            USB_COMMON_SUB_CLASS +\r\n                                                            \" when IAD descriptor is used\");\r\n        }\r\n\r\n        // Check device protocol\r\n        if (connectionInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL)\r\n        {\r\n            deviceDetails->DeviceProtocol = gcnew String(\"Interface Association Descriptor protocol\");\r\n        }\r\n        else\r\n        {\r\n            deviceDetails->DeviceProtocolError = gcnew String(\"ERROR: device Protocol should be USB IAD Protocol \" +\r\n                                                               USB_IAD_PROTOCOL +\r\n                                                              \" when IAD descriptor is used\");\r\n        }\r\n\r\n    }\r\n    else\r\n    {\r\n        deviceDetails->DeviceType =  XmlGetDeviceClassString(connectionInfo->DeviceDescriptor.bDeviceClass);\r\n\r\n        if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_BILLBOARD &&\r\n            (connectionInfo->DeviceDescriptor.bDeviceSubClass != 0x0 ||\r\n            connectionInfo->DeviceDescriptor.bDeviceProtocol != 0x0))\r\n        {\r\n            deviceDetails->DeviceTypeError = gcnew String(\"ERROR: Billboard device has invalid bDeviceSubclass/bDeviceProtocol\");\r\n        }\r\n\r\n        if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE)\r\n        {\r\n            deviceDetails->DeviceTypeError = gcnew String(\"ERROR:  Multi-interface Function code \" +\r\n                    connectionInfo->DeviceDescriptor.bDeviceClass +\r\n                    \" used for device with no IAD descriptors\");\r\n        }\r\n\r\n        if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_COMMUNICATION_DEVICE  ||\r\n                connectionInfo->DeviceDescriptor.bDeviceClass == USB_HUB_DEVICE ||\r\n                connectionInfo->DeviceDescriptor.bDeviceClass == USB_DIAGNOSTIC_DEVICE ||\r\n                connectionInfo->DeviceDescriptor.bDeviceClass == USB_WIRELESS_CONTROLLER_DEVICE ||\r\n                connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE ||\r\n                connectionInfo->DeviceDescriptor.bDeviceClass == USB_VENDOR_SPECIFIC_DEVICE)\r\n        {\r\n            tog = false;\r\n        }\r\n\r\n        // Not an IAD device, so all subclass values are invalid\r\n        if (connectionInfo->DeviceDescriptor.bDeviceSubClass > 0x00 &&\r\n            connectionInfo->DeviceDescriptor.bDeviceSubClass < 0xFF)\r\n        {\r\n            deviceDetails->SubclassTypeError = gcnew String(\"ERROR:  bDeviceSubClass is invalid - \" +\r\n                                                            connectionInfo->DeviceDescriptor.bDeviceSubClass);\r\n        }\r\n\r\n          // Not an IAD device, so all subclass values are invalid, check protocol\r\n        if (connectionInfo->DeviceDescriptor.bDeviceProtocol > 0x00 &&\r\n            connectionInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1)\r\n        {\r\n            deviceDetails->DeviceProtocolError = gcnew String(\"ERROR:  bDeviceProtocol is invalid - \" +\r\n                                                            connectionInfo->DeviceDescriptor.bDeviceProtocol);\r\n        }\r\n    }\r\n\r\n    return tog;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddConnectionInfo()\r\n\r\n  This routine adds connection information for the device\r\n *****************************************************************************/\r\nvoid XmlAddConnectionInfo(\r\n        NodeConnectionInfoExType ^xmlConnectionInfo,\r\n        PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo,\r\n        PUSBDEVICEINFO deviceInfo,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc,\r\n        PDEVICE_INFO_NODE pNode)\r\n{\r\n    NodeConnectionInfoExType ^ nc = xmlConnectionInfo;\r\n    bool tog = true;\r\n    nc->ConnectionInfoStruct = gcnew  NodeConnectionInfoExStructType();\r\n\r\n    // Update the structure\r\n    XmlAddConnectionInfoSt(nc->ConnectionInfoStruct, connectionInfo, pNode);\r\n\r\n    // Add verbose fields\r\n    if (connectionInfo->ConnectionStatus == NoDeviceConnected)\r\n    {\r\n        // No device connected, nothing to do\r\n        return;\r\n    }\r\n\r\n    if (connectionInfo->DeviceDescriptor.iProduct)\r\n    {\r\n        // Add EN version of string descriptor\r\n\r\n        nc->IProductStringDescEn = XmlGetStringDescriptor(\r\n                connectionInfo->DeviceDescriptor.iProduct,\r\n                stringDesc,\r\n                true);\r\n    }\r\n\r\n    // Check open pipes count\r\n    if (connectionInfo->NumberOfOpenPipes == 0)\r\n    {\r\n        nc->PipeInfoError = gcnew String(\"ERROR: No open pipes\");\r\n    }\r\n\r\n    // Check device descriptor length\r\n    if (connectionInfo->DeviceDescriptor.bLength != DEVICE_DESCRIPTOR_LENGTH)\r\n    {\r\n        nc->LengthError = gcnew String(\"ERROR: bLength \" +\r\n                connectionInfo->DeviceDescriptor.bLength +\r\n                \" incorrect, should be \" +\r\n                DEVICE_DESCRIPTOR_LENGTH\r\n                );\r\n    }\r\n\r\n    // Check for device error\r\n    if ((connectionInfo->ConnectionStatus == DeviceFailedEnumeration) ||\r\n            (connectionInfo->ConnectionStatus == DeviceGeneralFailure))\r\n    {\r\n        nc->DeviceError = gcnew String(\"ERROR:  Device enumeration failure\");\r\n    }\r\n    else\r\n    {\r\n        nc->DeviceClassDetails = gcnew UsbDeviceClassDetailsType();\r\n\r\n        // Add device class details\r\n        tog = XmlAddDeviceClassDetails(\r\n                nc->DeviceClassDetails,\r\n                connectionInfo,\r\n                deviceInfo);\r\n\r\n        nc->MaxPacketSizeInBytes = connectionInfo->DeviceDescriptor.bMaxPacketSize0;\r\n\r\n        // Validate speed\r\n        switch (connectionInfo->Speed)\r\n        {\r\n            case UsbLowSpeed:\r\n                if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 8)\r\n                {\r\n                    nc->PacketSizeError = gcnew String(\"ERROR:  Low Speed Devices require bMaxPacketSize0 = 8\");\r\n                }\r\n                break;\r\n            case UsbFullSpeed:\r\n                if (!(connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 8 ||\r\n                            connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 16 ||\r\n                            connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 32 ||\r\n                            connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 64))\r\n                {\r\n                    nc->PacketSizeError = gcnew String(\"ERROR:  Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64\");\r\n                }\r\n                break;\r\n            case UsbHighSpeed:\r\n                if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 64)\r\n                {\r\n                    nc->PacketSizeError = gcnew String(\"ERROR:  High Speed Devices require bMaxPacketSize0 = 64\");\r\n                }\r\n                break;\r\n        }\r\n\r\n        // Get string descriptors\r\n        nc->VendorString = PACHAR_TO_STRING(GetVendorString(connectionInfo->DeviceDescriptor.idVendor));\r\n\r\n        nc->ManufacturerString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iManufacturer, stringDesc, false);\r\n        nc->ProductString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iProduct, stringDesc, false);\r\n        nc->LangIdString =  XmlGetLangIdString(connectionInfo->DeviceDescriptor.iProduct, stringDesc);\r\n        nc->SerialString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iSerialNumber, stringDesc, false);\r\n\r\n        // Validate configuration\r\n        if (connectionInfo->DeviceDescriptor.bNumConfigurations != 1)\r\n        {\r\n            nc->ConfigurationCountError = gcnew String(\"WARNING: Most host controllers will only work with \"\\\r\n                                                        \"one configuration per speed\");\r\n        }\r\n    }\r\n    return;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddExternalHub()\r\n\r\n  Add a external to the parent Host Controller or hub. This is determined by the\r\n  last object pushed on the stack\r\n *****************************************************************************/\r\nHRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo)\r\n{\r\n    HRESULT hr = S_OK;\r\n    Object ^ parent = gXmlStack->Peek();\r\n    ExternalHubType ^exHub = nullptr;\r\n\r\n    UNREFERENCED_PARAMETER(ehName);\r\n\r\n    if (NULL == ehInfo)\r\n    {\r\n        return E_FAIL;\r\n    }\r\n\r\n    exHub = AddExternalHub(parent);\r\n\r\n    if (exHub != nullptr)\r\n    {\r\n        exHub->HubName = PACHAR_TO_STRING(ehInfo->HubName);\r\n\r\n        if (NULL != ehInfo->UsbDeviceProperties)\r\n        {\r\n            exHub->HwId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->HwId);\r\n            exHub->DeviceId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceId);\r\n            exHub->ServiceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->Service);\r\n            exHub->DeviceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceDesc);\r\n            exHub->DeviceClass = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceClass);\r\n        }\r\n\r\n        exHub->HubNodeInformation = gcnew HubNodeInformationType();\r\n        XmlAddHubNodeInformation(exHub->HubNodeInformation, ehInfo->HubInfo);\r\n\r\n        exHub->HubInformationEx = gcnew HubInformationExType();\r\n        XmlAddHubInformationEx(exHub->HubInformationEx, ehInfo->HubInfoEx);\r\n\r\n        exHub->HubCapabilityEx = gcnew HubCapabilitiesExType();\r\n        XmlAddHubCapabilitiesEx(exHub->HubCapabilityEx, ehInfo->HubCapabilityEx);\r\n\r\n        exHub->ConnectionInfo = gcnew NodeConnectionInfoExType();\r\n\r\n        // Update protocol\r\n        if (NULL != ehInfo->ConnectionInfo)\r\n        {\r\n            switch(ehInfo->ConnectionInfo->Speed)\r\n            {\r\n                case UsbLowSpeed:\r\n                case UsbFullSpeed:\r\n                    exHub->UsbProtocol = gcnew String(USB_1_1);\r\n                    break;\r\n                case UsbHighSpeed:\r\n                    exHub->UsbProtocol = gcnew String(USB_2_0);\r\n                    break;\r\n                case UsbSuperSpeed:\r\n                    exHub->UsbProtocol = gcnew String(USB_3_0);\r\n                    break;\r\n            }\r\n        }\r\n\r\n        // Add connection info\r\n        XmlAddConnectionInfo(\r\n                exHub->ConnectionInfo,\r\n                ehInfo->ConnectionInfo,\r\n                (PUSBDEVICEINFO) ehInfo,\r\n                ehInfo->StringDescs,\r\n                ehInfo->DeviceInfoNode\r\n                );\r\n\r\n        // Add port connectors\r\n        if (NULL != ehInfo->PortConnectorProps)\r\n        {\r\n            exHub->PortConnector = gcnew PortConnectorType();\r\n\r\n            XmlAddPortConnectorProps(\r\n                    exHub->PortConnector,\r\n                    ehInfo->PortConnectorProps\r\n                    );\r\n        }\r\n        // Add connection info V2\r\n        exHub->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type();\r\n\r\n        XmlAddConnectionInfoV2(\r\n                exHub->ConnectionInfoV2,\r\n                ehInfo->ConnectionInfoV2\r\n                );\r\n\r\n        // Add configuration descriptor\r\n        if (NULL != ehInfo->ConfigDesc)\r\n        {\r\n            exHub->DeviceConfiguration = XmlGetConfigDescriptors(\r\n                (PUSBDEVICEINFO) ehInfo,\r\n                (PUSB_CONFIGURATION_DESCRIPTOR) (ehInfo->ConfigDesc + 1),\r\n                ehInfo->StringDescs\r\n                );\r\n        }\r\n\r\n        // Add BOS descriptor\r\n        if (NULL != ehInfo->BosDesc)\r\n        {\r\n            exHub->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (ehInfo->BosDesc + 1), ehInfo->StringDescs);\r\n        }\r\n\r\n        gXmlStack->Push(exHub);\r\n    }\r\n    else\r\n    {\r\n        hr = E_FAIL;\r\n    }\r\n    return hr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetBosDescriptor()\r\n\r\n  Gets the Bos descriptor object for given BOS descriptor\r\n *****************************************************************************/\r\nUsbBosDescriptorType ^ XmlGetBosDescriptor(\r\n        PUSB_BOS_DESCRIPTOR bosDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        )\r\n{\r\n    PUSB_COMMON_DESCRIPTOR commonDesc = NULL;\r\n    PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL;\r\n    UsbBosDescriptorType ^ bosXmlDesc = nullptr;\r\n    ArrayList ^usb20CapExtDescList = gcnew ArrayList();\r\n    ArrayList ^usbSuperSpeedExtDescList = gcnew ArrayList();\r\n    ArrayList ^usbContIdCapExtDescList = gcnew ArrayList();\r\n    ArrayList ^usbUnknownDescList = gcnew ArrayList();\r\n    ArrayList ^usbBillboardDescList = gcnew ArrayList();\r\n\r\n    if(NULL == bosDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    // Initialize attributes\r\n    bosXmlDesc = gcnew UsbBosDescriptorType();\r\n    bosXmlDesc->BLength = bosDesc->bLength;\r\n    bosXmlDesc->BDescriptorType = bosDesc->bDescriptorType;\r\n    bosXmlDesc->WTotalLength = bosDesc->wTotalLength;\r\n    bosXmlDesc->BNumDeviceCaps = bosDesc->bNumDeviceCaps;\r\n\r\n    commonDesc = (PUSB_COMMON_DESCRIPTOR) bosDesc;\r\n\r\n    while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR) bosDesc,\r\n                    bosDesc->wTotalLength,\r\n                    commonDesc,\r\n                    -1)) != NULL)\r\n    {\r\n        switch (commonDesc->bDescriptorType)\r\n        {\r\n            case USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE:\r\n                capDesc = (PUSB_DEVICE_CAPABILITY_DESCRIPTOR)commonDesc;\r\n                switch (capDesc->bDevCapabilityType)\r\n                {\r\n                    case USB_DEVICE_CAPABILITY_USB20_EXTENSION:\r\n                        usb20CapExtDescList->Add(\r\n                                XmlGetUsb20CapabilityExtensionDescriptor(\r\n                                    (PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc\r\n                                    )\r\n                                );\r\n                        break;\r\n                    case USB_DEVICE_CAPABILITY_SUPERSPEED_USB:\r\n                        usbSuperSpeedExtDescList->Add(\r\n                                XmlGetSuperSpeedCapabilityExtensionDescriptor(\r\n                                    (PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc\r\n                                    )\r\n                                );\r\n                        break;\r\n                    case USB_DEVICE_CAPABILITY_CONTAINER_ID:\r\n                        usbContIdCapExtDescList->Add(\r\n                                XmlGetContainerIdCapabilityExtensionDescriptor(\r\n                                    (PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc\r\n                                    )\r\n                                );\r\n                        break;\r\n                    case USB_DEVICE_CAPABILITY_BILLBOARD:\r\n                        usbBillboardDescList->Add(\r\n                            XmlGetBillboardCapabilityDescriptor(\r\n                                (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc,\r\n                                stringDesc\r\n                                )\r\n                            );\r\n                        break;\r\n                    default:\r\n                        usbUnknownDescList->Add(\r\n                                XmlGetUnknownDescriptor(\r\n                                    (PUSB_COMMON_DESCRIPTOR) capDesc\r\n                                    )\r\n                                );\r\n                        break;\r\n                }\r\n                break;\r\n            default:\r\n                usbUnknownDescList->Add(XmlGetUnknownDescriptor(commonDesc));\r\n                break;\r\n        }\r\n    }\r\n\r\n    // Convert lists to arrays for and add to Bos Descriptor\r\n    bosXmlDesc->UnknownDescriptor = reinterpret_cast<array<UsbDeviceUnknownDescriptorType ^>^> (\r\n            usbUnknownDescList->ToArray(UsbDeviceUnknownDescriptorType::typeid)\r\n            );\r\n    bosXmlDesc->UsbSuperSpeedExtensionDescriptor = reinterpret_cast<array<UsbSuperSpeedExtensionDescriptorType ^>^> (\r\n            usbSuperSpeedExtDescList->ToArray(UsbSuperSpeedExtensionDescriptorType::typeid)\r\n            );\r\n    bosXmlDesc->UsbUsb20ExtensionDescriptor = reinterpret_cast<array<UsbUsb20ExtensionDescriptorType ^>^> (\r\n            usb20CapExtDescList->ToArray(UsbUsb20ExtensionDescriptorType::typeid)\r\n            );\r\n    bosXmlDesc->UsbDispContIdCapExtDescriptor = reinterpret_cast<array<UsbDispContIdCapExtDescriptorType ^>^> (\r\n            usbContIdCapExtDescList->ToArray(UsbDispContIdCapExtDescriptorType::typeid)\r\n            );\r\n    bosXmlDesc->UsbBillboardCapabilityDescriptor = reinterpret_cast<array<UsbBillboardCapabilityDescriptorType ^>^> (\r\n        usbBillboardDescList->ToArray(UsbBillboardCapabilityDescriptorType::typeid)\r\n        );\r\n\r\n    return bosXmlDesc;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetUsb20CapabilityExtensionDescriptor()\r\n\r\n  Gets a Usb20Capability extension descriptor object from the given descriptor\r\n *****************************************************************************/\r\nUsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc\r\n        )\r\n{\r\n    UsbUsb20ExtensionDescriptorType ^ capXmlDesc = nullptr;\r\n\r\n    if(NULL == capDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    capXmlDesc = gcnew UsbUsb20ExtensionDescriptorType();\r\n\r\n    capXmlDesc->BLength = capDesc->bLength;\r\n    capXmlDesc->BDescriptorType = capDesc->bDescriptorType;\r\n    capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType;\r\n    capXmlDesc->BmAttributes = capDesc->bmAttributes.AsUlong;\r\n\r\n    if (capDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK)\r\n    {\r\n        capXmlDesc->ReservedBitError = gcnew String(\"ERROR: bits 31..2 and bit 0 are reserved and must be 0\");\r\n    }\r\n    if (capDesc->bmAttributes.LPMCapable == 1)\r\n    {\r\n        capXmlDesc->SupportsLinkPowerManagement = true;\r\n    }\r\n\r\n    return capXmlDesc;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetSuperSpeedCapabilityExtensionDescriptor()\r\n\r\n  Gets a Super speed capability extension descriptor object from the given descriptor\r\n *****************************************************************************/\r\nUsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc\r\n        )\r\n{\r\n    UsbSuperSpeedExtensionDescriptorType ^ capXmlDesc = nullptr;\r\n\r\n    if(NULL == capDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    capXmlDesc = gcnew UsbSuperSpeedExtensionDescriptorType();\r\n\r\n    capXmlDesc->BLength = capDesc->bLength;\r\n    capXmlDesc->BDescriptorType = capDesc->bDescriptorType;\r\n    capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType;\r\n    capXmlDesc->BmAttributes = capDesc->bmAttributes;\r\n    capXmlDesc->BU1DevExitLat = capDesc->bU1DevExitLat;\r\n    capXmlDesc->WSpeedsSupported = capDesc->wSpeedsSupported;\r\n    capXmlDesc->WU2DevExitLat = capDesc->wU2DevExitLat;\r\n    capXmlDesc->BFunctionalitySupport = capDesc->bFunctionalitySupport;\r\n\r\n    // Add descriptive fields\r\n    if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK)\r\n    {\r\n        capXmlDesc->ReservedAttributesBitError = gcnew String(\"ERROR: bits 7:2 and bit 0 are reserved\");\r\n    }\r\n    if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE)\r\n    {\r\n        capXmlDesc->LatencyToleranceMsgCapable = true;\r\n    }\r\n    if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW)\r\n    {\r\n        capXmlDesc->SupportsLowSpeed = true;\r\n    }\r\n    if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL)\r\n    {\r\n        capXmlDesc->SupportsFullSpeed = true;\r\n    }\r\n    if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH)\r\n    {\r\n        capXmlDesc->SupportsHighSpeed = true;\r\n    }\r\n    if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER)\r\n    {\r\n        capXmlDesc->SupportsSuperSpeed = true;\r\n    }\r\n    if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK)\r\n    {\r\n        capXmlDesc->ReservedSpeedError = gcnew String(\"ERROR: bits 15:4 are reserved\");\r\n    }\r\n\r\n\r\n    switch (capDesc->bFunctionalitySupport)\r\n    {\r\n        case UsbLowSpeed:\r\n            capXmlDesc->LowestSpeed  = gcnew String(\"low-speed\");\r\n            break;\r\n        case UsbFullSpeed:\r\n            capXmlDesc->LowestSpeed  = gcnew String(\"full-speed\");\r\n            break;\r\n        case UsbHighSpeed:\r\n            capXmlDesc->LowestSpeed  = gcnew String(\"high-speed\");\r\n            break;\r\n        case UsbSuperSpeed:\r\n            capXmlDesc->LowestSpeed  = gcnew String(\"SuperSpeed\");\r\n            break;\r\n        default:\r\n            capXmlDesc->LowestSpeed  = gcnew String(\"ERROR: Invalid value\");\r\n            break;\r\n    }\r\n\r\n    if (capDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE)\r\n    {\r\n        capXmlDesc->U1DevExitLatencyString  = String::Format(\"Less than {0} micro-seconds\", capDesc->bU1DevExitLat);\r\n    }\r\n    else\r\n    {\r\n        capXmlDesc->U1DevExitLatencyString  = gcnew String(\"ERROR: Invalid value\");\r\n    }\r\n\r\n    if (capDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE)\r\n    {\r\n        capXmlDesc->U2DevExitLatencyString  = String::Format(\"Less than {0} micro-seconds\", capDesc->wU2DevExitLat);\r\n    }\r\n    else\r\n    {\r\n        capXmlDesc->U2DevExitLatencyString  = gcnew String(\"ERROR: Invalid value\");\r\n    }\r\n\r\n    return capXmlDesc;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlGetContainerIdCapabilityExtensionDescriptor()\r\n\r\n  Gets a Usb20Capability extension descriptor object from the given descriptor\r\n *****************************************************************************/\r\nUsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc\r\n        )\r\n{\r\n    UsbDispContIdCapExtDescriptorType ^ capXmlDesc = nullptr;\r\n    LPGUID pGuid = NULL;\r\n\r\n    if(NULL == capDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    capXmlDesc = gcnew UsbDispContIdCapExtDescriptorType();\r\n\r\n    capXmlDesc->BLength = capDesc->bLength;\r\n    capXmlDesc->BDescriptorType = capDesc->bDescriptorType;\r\n    capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType;\r\n    capXmlDesc->BReserved = capDesc->bReserved;\r\n\r\n    if (capDesc->bReserved != 0)\r\n    {\r\n        capXmlDesc->ReservedBitError = gcnew String(\"ERROR: field is reserved and should be zero\");\r\n    }\r\n\r\n    pGuid = (LPGUID) capDesc->ContainerID;\r\n\r\n    capXmlDesc->ContainerIdStr = String::Format(\"{0:X}-{1:X}-{2:X}-{3:X}{4:X}-{5:X}{6:X}{7:X}{8:X}{9:X}{10:X}\",\r\n            pGuid->Data1,\r\n            pGuid->Data2,\r\n            pGuid->Data3,\r\n            pGuid->Data4[0],\r\n            pGuid->Data4[1],\r\n            pGuid->Data4[2],\r\n            pGuid->Data4[3],\r\n            pGuid->Data4[4],\r\n            pGuid->Data4[5],\r\n            pGuid->Data4[6],\r\n            pGuid->Data4[7]);\r\n\r\n    return capXmlDesc;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\nXmlGetBillboardCapabilityDescriptor()\r\n\r\nGets a billboard capability descriptor from a given descriptor\r\n*****************************************************************************/\r\nUsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor(\r\n        PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc,\r\n        PSTRING_DESCRIPTOR_NODE stringDesc\r\n        )\r\n{\r\n    UCHAR                                  i = 0;\r\n    UCHAR                                  bNumAlternateModes = 0;\r\n    UCHAR                                  alternateModeConfiguration = 0;\r\n    UsbBillboardCapabilityDescriptorType ^ capXmlDesc = nullptr;\r\n    UsbBillboardSVIDType ^                 svidXmlDesc = nullptr;\r\n    ArrayList ^                            usbSVIDDescList = gcnew ArrayList();\r\n\r\n\r\n    if (NULL == capDesc)\r\n    {\r\n        return nullptr;\r\n    }\r\n\r\n    capXmlDesc = gcnew UsbBillboardCapabilityDescriptorType();\r\n\r\n\r\n    capXmlDesc->BLength = capDesc->bLength;\r\n    capXmlDesc->BDescriptorType = capDesc->bDescriptorType;\r\n    capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType;\r\n    capXmlDesc->IAddtionalInfoURL = capDesc->iAddtionalInfoURL;\r\n    capXmlDesc->BNumberOfAlternateModes = capDesc->bNumberOfAlternateModes;\r\n    capXmlDesc->BPreferredAlternateMode = capDesc->bPreferredAlternateMode;\r\n    capXmlDesc->CalculatedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) +\r\n            sizeof(capDesc->AlternateMode[0]) * (capDesc->bNumberOfAlternateModes - 1);\r\n    capXmlDesc->BillboardDescriptorErrors = gcnew String(\"\");\r\n    capXmlDesc->AddtionalInfoURL = XmlGetStringDescriptor(\r\n            capDesc->iAddtionalInfoURL,\r\n            stringDesc,\r\n            false\r\n            );\r\n\r\n    if (capDesc->VconnPower.NoVconnPowerRequired)\r\n    {\r\n        capXmlDesc->VConnPower = gcnew String(\"The adapter does not require Vconn Power. Bits 2..0 ignored\");\r\n    }\r\n    else\r\n    {\r\n        switch (capDesc->VconnPower.VConnPowerNeededForFullFunctionality)\r\n        {\r\n        case 0:\r\n            capXmlDesc->VConnPower = gcnew String(\"1W needed by adapter for full functionality\");\r\n            break;\r\n        case 1:\r\n            capXmlDesc->VConnPower = gcnew String(\"1.5W needed by adapter for full functionality\");\r\n            break;\r\n        case 7:\r\n            capXmlDesc->BillboardDescriptorErrors += \"ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used\";\r\n            break;\r\n        default:\r\n            capXmlDesc->VConnPower = gcnew String(String::Format(\"{0} W needed by adapter for full functionality\", capDesc->VconnPower.VConnPowerNeededForFullFunctionality));\r\n        }\r\n    }\r\n\r\n    if (capDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE)\r\n    {\r\n        capXmlDesc->BillboardDescriptorErrors += \"ERROR: Invalid bNumberofAlternateModes; \";\r\n    }\r\n    if (capDesc->VconnPower.Reserved)\r\n    {\r\n        capXmlDesc->BillboardDescriptorErrors += \"ERROR: Reserved bits in VCONN Power being used; \";\r\n    }\r\n    if (capDesc->bReserved)\r\n    {\r\n        capXmlDesc->BillboardDescriptorErrors += \"ERROR: bReserved being used; \";\r\n    }\r\n\r\n    bNumAlternateModes = capDesc->bNumberOfAlternateModes;\r\n    if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE)\r\n    {\r\n        bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE;\r\n    }\r\n    for (i = 0; i < bNumAlternateModes; i++)\r\n    {\r\n        svidXmlDesc = gcnew UsbBillboardSVIDType();\r\n        alternateModeConfiguration = ((capDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3;\r\n        svidXmlDesc->WSVID = capDesc->AlternateMode[i].wSVID;\r\n        svidXmlDesc->BAlternateMode = capDesc->AlternateMode[i].bAlternateMode;\r\n        svidXmlDesc->IAlternateModeString = capDesc->AlternateMode[i].iAlternateModeSetting;\r\n        svidXmlDesc->AlternateModeString = XmlGetStringDescriptor(\r\n            capDesc->AlternateMode[i].iAlternateModeSetting,\r\n            stringDesc,\r\n            false\r\n            );\r\n\r\n        switch (alternateModeConfiguration)\r\n        {\r\n        case 0:\r\n            svidXmlDesc->Description = gcnew String(\"Unspecified Error\");\r\n            break;\r\n        case 1:\r\n            svidXmlDesc->Description = gcnew String(\"Alternate Mode configuration not attempted\");\r\n            break;\r\n        case 2:\r\n            svidXmlDesc->Description = gcnew String(\"Alternate Mode configuration attempted but unsuccessful\");\r\n            break;\r\n        case 3:\r\n            svidXmlDesc->Description = gcnew String(\"Alternate Mode configuration successful\");\r\n            break;\r\n        }\r\n        usbSVIDDescList->Add(svidXmlDesc);\r\n    }\r\n    capXmlDesc->UsbBillboardSVID = reinterpret_cast<array<UsbBillboardSVIDType ^>^> (\r\n        usbSVIDDescList->ToArray(UsbBillboardSVIDType::typeid));\r\n\r\n    return capXmlDesc;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddUsbDevice()\r\n\r\n  Add a external to the parent Host Controller or hub. This is determined by the\r\n  last object pushed on the stack\r\n *****************************************************************************/\r\nHRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo)\r\n{\r\n    HRESULT hr = S_OK;\r\n    Object ^ parent = gXmlStack->Peek();\r\n    UsbDeviceType ^usbDevice = nullptr;\r\n    NoDeviceType ^noDevice = nullptr;\r\n\r\n    if (NULL == deviceInfo)\r\n    {\r\n        return E_FAIL;\r\n    }\r\n\r\n    if (deviceInfo->ConfigDesc == NULL)\r\n    {\r\n        // There is no USB device on this port, add a NoDevice type here instead of USB device\r\n        noDevice = AddDisconnectedPort(parent);\r\n\r\n        if (nullptr != noDevice)\r\n        {\r\n            noDevice->UsbPortNumber = gcnew String(\"\");\r\n            noDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex;\r\n            noDevice->Name = PACHAR_TO_STRING(devName);\r\n        }\r\n        else\r\n        {\r\n            hr = E_FAIL;\r\n        }\r\n    }\r\n\r\n    else\r\n    {\r\n        usbDevice = AddUsbDevice(parent);\r\n\r\n        if (nullptr != usbDevice)\r\n        {\r\n            // Update device information\r\n            if (NULL != deviceInfo->UsbDeviceProperties)\r\n            {\r\n                usbDevice->HwId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->HwId);\r\n                usbDevice->DeviceId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceId);\r\n                usbDevice->ServiceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->Service);\r\n                usbDevice->DeviceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceDesc);\r\n                usbDevice->DeviceClass = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceClass);\r\n            }\r\n\r\n            // Update port number\r\n            usbDevice->UsbPortNumber = gcnew String(\"\");\r\n            usbDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex;\r\n            usbDevice->ConnectionInfo = gcnew NodeConnectionInfoExType();\r\n\r\n            // Update protocol\r\n            if (NULL != deviceInfo->ConnectionInfo)\r\n            {\r\n                switch(deviceInfo->ConnectionInfo->Speed)\r\n                {\r\n                    case UsbLowSpeed:\r\n                    case UsbFullSpeed:\r\n                        usbDevice->UsbProtocol = gcnew String(USB_1_1);\r\n                        break;\r\n                    case UsbHighSpeed:\r\n                        usbDevice->UsbProtocol = gcnew String(USB_2_0);\r\n                        break;\r\n                    case UsbSuperSpeed:\r\n                        usbDevice->UsbProtocol = gcnew String(USB_3_0);\r\n                        break;\r\n                }\r\n            }\r\n\r\n            // Add connection info\r\n            XmlAddConnectionInfo(\r\n                    usbDevice->ConnectionInfo,\r\n                    deviceInfo->ConnectionInfo,\r\n                    (PUSBDEVICEINFO) deviceInfo,\r\n                    deviceInfo->StringDescs,\r\n                    deviceInfo->DeviceInfoNode\r\n                    );\r\n\r\n            // Add port connector\r\n            if (NULL != deviceInfo->PortConnectorProps)\r\n            {\r\n                usbDevice->PortConnector =  gcnew PortConnectorType();\r\n\r\n                XmlAddPortConnectorProps(\r\n                        usbDevice->PortConnector,\r\n                        deviceInfo->PortConnectorProps\r\n                        );\r\n            }\r\n\r\n            // Add connectiontion info V2\r\n            if (NULL != deviceInfo->ConnectionInfoV2)\r\n            {\r\n                usbDevice->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type();\r\n                XmlAddConnectionInfoV2(\r\n                        usbDevice->ConnectionInfoV2,\r\n                        deviceInfo->ConnectionInfoV2\r\n                        );\r\n            }\r\n\r\n            // Add configuration descriptor\r\n            if (NULL != deviceInfo->ConfigDesc)\r\n            {\r\n                // The device configuration is allocated by XmlGetConfigDescriptors()\r\n                usbDevice->DeviceConfiguration = XmlGetConfigDescriptors(\r\n                        (PUSBDEVICEINFO) deviceInfo,\r\n                        (PUSB_CONFIGURATION_DESCRIPTOR) (deviceInfo->ConfigDesc + 1),\r\n                        deviceInfo->StringDescs\r\n                        );\r\n            }\r\n\r\n            // Add BOS descriptor\r\n            if (NULL != deviceInfo->BosDesc)\r\n            {\r\n                usbDevice->BosDescriptor = XmlGetBosDescriptor(\r\n                        (PUSB_BOS_DESCRIPTOR) (deviceInfo->BosDesc + 1),\r\n                        deviceInfo->StringDescs\r\n                        );\r\n            }\r\n        }\r\n        else\r\n        {\r\n            hr = E_FAIL;\r\n        }\r\n    }\r\n    return hr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlAddRootHub()\r\n\r\n  Add a root hub to the parent Host Controller\r\n *****************************************************************************/\r\nHRESULT XmlAddRootHub(PSTR rhName, PUSBROOTHUBINFO rhInfo)\r\n{\r\n    HRESULT hr = S_OK;\r\n    Object ^ parent = gXmlStack->Peek();\r\n    HostControllerType ^ hcParent = nullptr;\r\n    PSTR rootHubName = rhInfo->HubName;\r\n\r\n    UNREFERENCED_PARAMETER(rhName);\r\n\r\n    hcParent = dynamic_cast<HostControllerType ^> (parent);\r\n\r\n    if (hcParent != nullptr)\r\n    {\r\n        RootHubType ^ rh = nullptr;\r\n        hcParent = (HostControllerType ^) parent;\r\n        hcParent->RootHub = gcnew RootHubType();\r\n\r\n        rh = hcParent->RootHub;\r\n        rh->HubName = PACHAR_TO_STRING(rootHubName);\r\n\r\n        if (NULL != rhInfo->UsbDeviceProperties)\r\n        {\r\n            rh->HwId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->HwId);\r\n            rh->DeviceId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceId);\r\n            rh->ServiceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->Service);\r\n            rh->DeviceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceDesc);\r\n            rh->DeviceClass = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceClass);\r\n\r\n            // Roothub protocol is same as HC protocol\r\n            rh->UsbProtocol = hcParent->UsbProtocol;\r\n        }\r\n\r\n        rh->HubNodeInformation = gcnew HubNodeInformationType();\r\n        XmlAddHubNodeInformation(rh->HubNodeInformation, rhInfo->HubInfo);\r\n\r\n        rh->HubInformationEx = gcnew HubInformationExType();\r\n        XmlAddHubInformationEx(rh->HubInformationEx, rhInfo->HubInfoEx);\r\n\r\n        rh->HubCapabilityEx = gcnew HubCapabilitiesExType();\r\n        XmlAddHubCapabilitiesEx(rh->HubCapabilityEx, rhInfo->HubCapabilityEx);\r\n\r\n        // Push root hub on to stack\r\n        gXmlStack->Push(rh);\r\n    }\r\n    else\r\n    {\r\n        // Root hub should be connected to a host controller\r\n        hr = E_FAIL;\r\n    }\r\n    return S_OK;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  XmlSetVersion()\r\n\r\n  Set version information in XML tree\r\n *****************************************************************************/\r\nVOID XmlSetVersion(\r\n        UCHAR uvcMajorVersion,\r\n        UCHAR uvcMinorVersion,\r\n        UCHAR uvcMajorSpecVersion,\r\n        UCHAR uvcMinorSpecVersion\r\n        )\r\n{\r\n    MachineInfoType ^ mInfo;\r\n    gXmlView->MachineInfo = gcnew MachineInfoType();\r\n\r\n    mInfo = gXmlView->MachineInfo;\r\n\r\n    mInfo->UvcMajorVersion = uvcMajorVersion;\r\n    mInfo->UvcMinorVersion = uvcMinorVersion;\r\n    mInfo->UvcMajorSpecVersion = uvcMajorSpecVersion;\r\n    mInfo->UvcMinorSpecVersion = uvcMinorSpecVersion;\r\n\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  InitXmlHelper()\r\n\r\n  Initialize XML helper\r\n *****************************************************************************/\r\nHRESULT InitXmlHelper()\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    (XmlGlobal::Instance())->ViewAll = gcnew UvcViewAll();\r\n    (XmlGlobal::Instance())->ViewAll->UvcView = gcnew UvcViewType();\r\n\r\n    //\r\n    // Initialize fields to null so we can check against them for allocation\r\n    //\r\n    (XmlGlobal::Instance())->ViewAll->UvcView->MachineInfo = nullptr;\r\n    (XmlGlobal::Instance())->ViewAll->UvcView->UsbTree = nullptr;\r\n\r\n    XmlSetVersion(\r\n            UVC_SPEC_MAJOR_VERSION,\r\n            UVC_SPEC_MINOR_VERSION,\r\n            USBVIEW_MAJOR_VERSION,\r\n            USBVIEW_MINOR_VERSION\r\n            );\r\n\r\n    gXmlStack->Push(gXmlView);\r\n\r\n    gXmlViewInitialized = TRUE;\r\n\r\n    return hr;\r\n}\r\n\r\n/*****************************************************************************\r\n\r\n  SaveXml()\r\n\r\n  Saves the inmemory USB view as XML file\r\n *****************************************************************************/\r\nHRESULT SaveXml(LPTSTR szfileName, DWORD dwCreationDisposition)\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    if (gXmlViewInitialized)\r\n    {\r\n        try\r\n        {\r\n            String ^fileName = PACHAR_TO_STRING(szfileName);\r\n            XmlSerializer ^ serializer = gcnew XmlSerializer(UvcViewAll::typeid);\r\n            TextWriter ^ writer = nullptr;\r\n\r\n            if (dwCreationDisposition != CREATE_ALWAYS)\r\n            {\r\n                // Check if file exits and return failure if it does\r\n                if (File::Exists(fileName))\r\n                {\r\n                    hr =  HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);\r\n                }\r\n            }\r\n\r\n            // Check if file name is NULL\r\n            if (String::IsNullOrEmpty(fileName))\r\n            {\r\n                hr = E_INVALIDARG;\r\n            }\r\n\r\n            if (SUCCEEDED(hr))\r\n            {\r\n                writer = gcnew StreamWriter(fileName);\r\n                serializer->Serialize(writer, (XmlGlobal::Instance())->ViewAll);\r\n                writer->Close();\r\n            }\r\n\r\n            // Release and reinit XML View for next iteration if requested\r\n            ReleaseXmlWriter();\r\n            InitXmlHelper();\r\n\r\n        }\r\n        catch(Exception ^ ex)\r\n        {\r\n            hr = (HRESULT) Marshal::GetHRForException(ex);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        hr = E_FAIL;\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\n\r\n/*****************************************************************************\r\n\r\n  ReleaseXmlWriter()\r\n\r\n *****************************************************************************/\r\nHRESULT ReleaseXmlWriter()\r\n{\r\n    HRESULT hr = S_OK;\r\n\r\n    if (gXmlViewInitialized)\r\n    {\r\n        gXmlViewInitialized = FALSE;\r\n        delete XmlGlobal::Instance();\r\n    }\r\n\r\n    return hr;\r\n}\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/usbview/xmlhelper.h",
    "content": "/*++\r\n\r\nCopyright (c) 1997-2011 Microsoft Corporation\r\n\r\nModule Name:\r\n\r\n    XMLHELPER.H\r\n\r\nAbstract:\r\n\r\n    This helper file declaration for XML helper APIs\r\n\r\nEnvironment:\r\n\r\n    user mode\r\n\r\nRevision History:\r\n\r\n    05-05-11 : created\r\n\r\n--*/\r\n\r\n#pragma once\r\n\r\n/*****************************************************************************\r\n I N C L U D E S\r\n*****************************************************************************/\r\n#include \"uvcview.h\"\r\n\r\nEXTERN_C HRESULT InitXmlHelper();\r\nEXTERN_C HRESULT ReleaseXmlWriter();\r\nEXTERN_C HRESULT SaveXml(LPTSTR szfileName, DWORD dwCreationDisposition);\r\nEXTERN_C HRESULT XmlAddHostController(\r\n    PSTR hcName,\r\n    PUSBHOSTCONTROLLERINFO hcInfo\r\n    );\r\nEXTERN_C HRESULT XmlAddRootHub(PSTR rhName, PUSBROOTHUBINFO rhInfo);\r\nEXTERN_C HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo);\r\nEXTERN_C HRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo);\r\nEXTERN_C VOID XmlNotifyEndOfNodeList(PVOID pContext);\r\n\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/main.cpp",
    "content": "// testw.cpp : Defines the entry point for the application.\r\n//\r\n\r\n#include \"stdafx.h\"\r\n#include \"test.h\"\r\n\r\n#define MAX_LOADSTRING 100\r\n\r\n// Global Variables:\r\nHINSTANCE hInst;\t\t\t\t\t\t\t\t// current instance\r\nTCHAR szTitle[MAX_LOADSTRING];\t\t\t\t\t// The title bar text\r\nTCHAR szWindowClass[MAX_LOADSTRING];\t\t\t// the main window class name\r\n\r\n// Forward declarations of functions included in this code module:\r\nATOM\t\t\t\tMyRegisterClass(HINSTANCE hInstance);\r\nBOOL\t\t\t\tInitInstance(HINSTANCE, int);\r\nLRESULT CALLBACK\tWndProc(HWND, UINT, WPARAM, LPARAM);\r\nINT_PTR CALLBACK\tAbout(HWND, UINT, WPARAM, LPARAM);\r\n\r\nint APIENTRY _tWinMain(HINSTANCE hInstance,\r\n                     HINSTANCE hPrevInstance,\r\n                     LPTSTR    lpCmdLine,\r\n                     int       nCmdShow)\r\n{\r\n\tUNREFERENCED_PARAMETER(hPrevInstance);\r\n\tUNREFERENCED_PARAMETER(lpCmdLine);\r\n\r\n \t// TODO: Place code here.\r\n\tMSG msg;\r\n\tHACCEL hAccelTable;\r\n\r\n\t// Initialize global strings\r\n\tLoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);\r\n\tLoadString(hInstance, IDC_TESTW, szWindowClass, MAX_LOADSTRING);\r\n\tMyRegisterClass(hInstance);\r\n\r\n\t// Perform application initialization:\r\n\tif (!InitInstance (hInstance, nCmdShow))\r\n\t{\r\n\t\treturn FALSE;\r\n\t}\r\n\r\n\thAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTW));\r\n\r\n\t// Main message loop:\r\n\twhile (GetMessage(&msg, NULL, 0, 0))\r\n\t{\r\n\t\tif (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))\r\n\t\t{\r\n\t\t\tTranslateMessage(&msg);\r\n\t\t\tDispatchMessage(&msg);\r\n\t\t}\r\n\t}\r\n\r\n\treturn (int) msg.wParam;\r\n}\r\n\r\n\r\n\r\n//\r\n//  FUNCTION: MyRegisterClass()\r\n//\r\n//  PURPOSE: Registers the window class.\r\n//\r\n//  COMMENTS:\r\n//\r\n//    This function and its usage are only necessary if you want this code\r\n//    to be compatible with Win32 systems prior to the 'RegisterClassEx'\r\n//    function that was added to Windows 95. It is important to call this function\r\n//    so that the application will get 'well formed' small icons associated\r\n//    with it.\r\n//\r\nATOM MyRegisterClass(HINSTANCE hInstance)\r\n{\r\n\tWNDCLASSEX wcex;\r\n\r\n\twcex.cbSize = sizeof(WNDCLASSEX);\r\n\r\n\twcex.style\t\t\t= CS_HREDRAW | CS_VREDRAW;\r\n\twcex.lpfnWndProc\t= WndProc;\r\n\twcex.cbClsExtra\t\t= 0;\r\n\twcex.cbWndExtra\t\t= 0;\r\n\twcex.hInstance\t\t= hInstance;\r\n\twcex.hIcon\t\t\t= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTW));\r\n\twcex.hCursor\t\t= LoadCursor(NULL, IDC_ARROW);\r\n\twcex.hbrBackground\t= (HBRUSH)(COLOR_WINDOW+1);\r\n\twcex.lpszMenuName\t= MAKEINTRESOURCE(IDC_TESTW);\r\n\twcex.lpszClassName\t= szWindowClass;\r\n\twcex.hIconSm\t\t= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));\r\n\r\n\treturn RegisterClassEx(&wcex);\r\n}\r\n\r\n//\r\n//   FUNCTION: InitInstance(HINSTANCE, int)\r\n//\r\n//   PURPOSE: Saves instance handle and creates main window\r\n//\r\n//   COMMENTS:\r\n//\r\n//        In this function, we save the instance handle in a global variable and\r\n//        create and display the main program window.\r\n//\r\nBOOL InitInstance(HINSTANCE hInstance, int nCmdShow)\r\n{\r\n   HWND hWnd;\r\n\r\n   hInst = hInstance; // Store instance handle in our global variable\r\n\r\n   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,\r\n      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);\r\n\r\n   if (!hWnd)\r\n   {\r\n      return FALSE;\r\n   }\r\n\r\n   ShowWindow(hWnd, nCmdShow);\r\n   UpdateWindow(hWnd);\r\n\r\n   return TRUE;\r\n}\r\n\r\n//\r\n//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)\r\n//\r\n//  PURPOSE:  Processes messages for the main window.\r\n//\r\n//  WM_COMMAND\t- process the application menu\r\n//  WM_PAINT\t- Paint the main window\r\n//  WM_DESTROY\t- post a quit message and return\r\n//\r\n//\r\nLRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r\n{\r\n\tint wmId, wmEvent;\r\n\tPAINTSTRUCT ps;\r\n\tHDC hdc;\r\n\r\n\tswitch (message)\r\n\t{\r\n\tcase WM_COMMAND:\r\n\t\twmId    = LOWORD(wParam);\r\n\t\twmEvent = HIWORD(wParam);\r\n\t\t// Parse the menu selections:\r\n\t\tswitch (wmId)\r\n\t\t{\r\n\t\tcase IDM_ABOUT:\r\n\t\t\tDialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);\r\n\t\t\tbreak;\r\n\t\tcase IDM_EXIT:\r\n\t\t\tDestroyWindow(hWnd);\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn DefWindowProc(hWnd, message, wParam, lParam);\r\n\t\t}\r\n\t\tbreak;\r\n\tcase WM_PAINT:\r\n\t\thdc = BeginPaint(hWnd, &ps);\r\n\t\t// TODO: Add any drawing code here...\r\n\t\tEndPaint(hWnd, &ps);\r\n\t\tbreak;\r\n\tcase WM_DESTROY:\r\n\t\tPostQuitMessage(0);\r\n\t\tbreak;\r\n\tdefault:\r\n\t\treturn DefWindowProc(hWnd, message, wParam, lParam);\r\n\t}\r\n\treturn 0;\r\n}\r\n\r\n// Message handler for about box.\r\nINT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r\n{\r\n\tUNREFERENCED_PARAMETER(lParam);\r\n\tswitch (message)\r\n\t{\r\n\tcase WM_INITDIALOG:\r\n\t\treturn (INT_PTR)TRUE;\r\n\r\n\tcase WM_COMMAND:\r\n\t\tif (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)\r\n\t\t{\r\n\t\t\tEndDialog(hDlg, LOWORD(wParam));\r\n\t\t\treturn (INT_PTR)TRUE;\r\n\t\t}\r\n\t\tbreak;\r\n\t}\r\n\treturn (INT_PTR)FALSE;\r\n}\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by test.rc\r\n//\r\n\r\n#define IDS_APP_TITLE\t\t\t103\r\n\r\n#define IDR_MAINFRAME\t\t\t128\r\n#define IDD_TESTW_DIALOG\t102\r\n#define IDD_ABOUTBOX\t\t\t103\r\n#define IDM_ABOUT\t\t\t\t104\r\n#define IDM_EXIT\t\t\t\t105\r\n#define IDI_TESTW\t\t\t107\r\n#define IDI_SMALL\t\t\t\t108\r\n#define IDC_TESTW\t\t\t109\r\n#define IDC_MYICON\t\t\t\t2\r\n#ifndef IDC_STATIC\r\n#define IDC_STATIC\t\t\t\t-1\r\n#endif\r\n// Next default values for new objects\r\n//\r\n#ifdef APSTUDIO_INVOKED\r\n#ifndef APSTUDIO_READONLY_SYMBOLS\r\n\r\n#define _APS_NO_MFC\t\t\t\t\t130\r\n#define _APS_NEXT_RESOURCE_VALUE\t129\r\n#define _APS_NEXT_COMMAND_VALUE\t\t32771\r\n#define _APS_NEXT_CONTROL_VALUE\t\t1000\r\n#define _APS_NEXT_SYMED_VALUE\t\t110\r\n#endif\r\n#endif\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\r\n// testw.pch will be the pre-compiled header\r\n// stdafx.obj will contain the pre-compiled type information\r\n\r\n#include \"stdafx.h\"\r\n\r\n// TODO: reference any additional headers you need in STDAFX.H\r\n// and not in this file\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\r\n// or project specific include files that are used frequently, but\r\n// are changed infrequently\r\n//\r\n\r\n#pragma once\r\n\r\n#include \"targetver.h\"\r\n\r\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\r\n// Windows Header Files:\r\n#include <windows.h>\r\n\r\n// C RunTime Header Files\r\n#include <stdlib.h>\r\n#include <malloc.h>\r\n#include <memory.h>\r\n#include <tchar.h>\r\n\r\n\r\n// TODO: reference additional headers your program requires here\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/targetver.h",
    "content": "#pragma once\r\n\r\n// The following macros define the minimum required platform.  The minimum required platform\r\n// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run\r\n// your application.  The macros work by enabling all features available on platform versions up to and\r\n// including the version specified.\r\n\r\n// Modify the following defines if you have to target a platform prior to the ones specified below.\r\n// Refer to MSDN for the latest info on corresponding values for different platforms.\r\n#ifndef WINVER                          // Specifies that the minimum required platform is Windows Vista.\r\n#define WINVER 0x0600           // Change this to the appropriate value to target other versions of Windows.\r\n#endif\r\n\r\n#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.\r\n#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.\r\n#endif\r\n\r\n#ifndef _WIN32_WINDOWS          // Specifies that the minimum required platform is Windows 98.\r\n#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.\r\n#endif\r\n\r\n#ifndef _WIN32_IE                       // Specifies that the minimum required platform is Internet Explorer 7.0.\r\n#define _WIN32_IE 0x0700        // Change this to the appropriate value to target other versions of IE.\r\n#endif\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/test",
    "content": "//Microsoft Visual C++ generated resource script.\r\n//\r\n#include \"resource.h\"\r\n\r\n#define APSTUDIO_READONLY_SYMBOLS\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 2 resource.\r\n//\r\n#ifndef APSTUDIO_INVOKED\r\n#include \"targetver.h\"\r\n#endif\r\n#define APSTUDIO_HIDDEN_SYMBOLS\r\n#include \"windows.h\"\r\n#undef APSTUDIO_HIDDEN_SYMBOLS\r\n/////////////////////////////////////////////////////////////////////////////\r\n#undef APSTUDIO_READONLY_SYMBOLS\r\n\r\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\nLANGUAGE 9, 1\r\n#pragma code_page(936)\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Icon\r\n//\r\n\r\n// Icon with lowest ID value placed first to ensure application icon\r\n// remains consistent on all systems.\r\n\r\nIDI_TESTW       ICON         \"testw.ico\"\r\nIDI_SMALL               ICON         \"small.ico\"\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Menu\r\n//\r\n\r\nIDC_TESTW MENU\r\nBEGIN\r\n    POPUP \"&File\"\r\n    BEGIN\r\n        MENUITEM \"E&xit\",                IDM_EXIT\r\n    END\r\n    POPUP \"&Help\"\r\n    BEGIN\r\n        MENUITEM \"&About ...\",           IDM_ABOUT\r\n    END\r\nEND\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Accelerator\r\n//\r\n\r\nIDC_TESTW ACCELERATORS\r\nBEGIN\r\n    \"?\",            IDM_ABOUT,              ASCII,  ALT\r\n    \"/\",            IDM_ABOUT,              ASCII,  ALT\r\nEND\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Dialog\r\n//\r\n\r\nIDD_ABOUTBOX DIALOGEX 0, 0, 170, 62\r\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\r\nCAPTION \"About testw\"\r\nFONT 8, \"MS Shell Dlg\"\r\nBEGIN\r\n    ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20\r\n    LTEXT           \"testw, Version 1.0\",IDC_STATIC,42,14,114,8,SS_NOPREFIX\r\n    LTEXT           \"Copyright (C) 2020\",IDC_STATIC,42,26,114,8\r\n    DEFPUSHBUTTON   \"OK\",IDOK,113,41,50,14,WS_GROUP\r\nEND\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// DESIGNINFO\r\n//\r\n\r\n#ifdef APSTUDIO_INVOKED\r\nGUIDELINES DESIGNINFO\r\nBEGIN\r\n    IDD_ABOUTBOX, DIALOG\r\n    BEGIN\r\n        LEFTMARGIN, 7\r\n        RIGHTMARGIN, 163\r\n        TOPMARGIN, 7\r\n        BOTTOMMARGIN, 55\r\n    END\r\nEND\r\n#endif    // APSTUDIO_INVOKED\r\n\r\n#ifdef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// TEXTINCLUDE\r\n//\r\n1 TEXTINCLUDE\r\nBEGIN\r\n    \"resource.h\\0\"\r\nEND\r\n\r\n2 TEXTINCLUDE\r\nBEGIN\r\n\t\"#ifndef APSTUDIO_INVOKED\\r\\n\"\r\n    \"#include \"\"targetver.h\"\"\\r\\n\"\r\n    \"#endif\\r\\n\"\r\n    \"#define APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\r\n    \"#include \"\"windows.h\"\"\\r\\n\"\r\n    \"#undef APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n3 TEXTINCLUDE\r\nBEGIN\r\n    \"\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n#endif    // APSTUDIO_INVOKED\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// String Table\r\n//\r\n\r\nSTRINGTABLE\r\nBEGIN\r\n   IDC_TESTW   \"TESTW\"\r\n   IDS_APP_TITLE       \"testw\"\r\nEND\r\n\r\n#endif\r\n/////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\n\r\n#ifndef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 3 resource.\r\n//\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n#endif    // not APSTUDIO_INVOKED\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/test.h",
    "content": "#pragma once\r\n\r\n#include \"resource.h\"\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/test.rc",
    "content": "//Microsoft Visual C++ generated resource script.\r\n//\r\n#include \"resource.h\"\r\n\r\n#define APSTUDIO_READONLY_SYMBOLS\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 2 resource.\r\n//\r\n#ifndef APSTUDIO_INVOKED\r\n#include \"targetver.h\"\r\n#endif\r\n#define APSTUDIO_HIDDEN_SYMBOLS\r\n#include \"windows.h\"\r\n#undef APSTUDIO_HIDDEN_SYMBOLS\r\n/////////////////////////////////////////////////////////////////////////////\r\n#undef APSTUDIO_READONLY_SYMBOLS\r\n\r\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\nLANGUAGE 9, 1\r\n#pragma code_page(936)\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Icon\r\n//\r\n\r\n// Icon with lowest ID value placed first to ensure application icon\r\n// remains consistent on all systems.\r\n\r\nIDI_TESTW       ICON         \"test.ico\"\r\nIDI_SMALL               ICON         \"small.ico\"\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Menu\r\n//\r\n\r\nIDC_TESTW MENU\r\nBEGIN\r\n    POPUP \"&File\"\r\n    BEGIN\r\n        MENUITEM \"E&xit\",                IDM_EXIT\r\n    END\r\n    POPUP \"&Help\"\r\n    BEGIN\r\n        MENUITEM \"&About ...\",           IDM_ABOUT\r\n    END\r\nEND\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Accelerator\r\n//\r\n\r\nIDC_TESTW ACCELERATORS\r\nBEGIN\r\n    \"?\",            IDM_ABOUT,              ASCII,  ALT\r\n    \"/\",            IDM_ABOUT,              ASCII,  ALT\r\nEND\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Dialog\r\n//\r\n\r\nIDD_ABOUTBOX DIALOGEX 0, 0, 170, 62\r\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\r\nCAPTION \"About testw\"\r\nFONT 8, \"MS Shell Dlg\"\r\nBEGIN\r\n    ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20\r\n    LTEXT           \"testw, Version 1.0\",IDC_STATIC,42,14,114,8,SS_NOPREFIX\r\n    LTEXT           \"Copyright (C) 2020\",IDC_STATIC,42,26,114,8\r\n    DEFPUSHBUTTON   \"OK\",IDOK,113,41,50,14,WS_GROUP\r\nEND\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// DESIGNINFO\r\n//\r\n\r\n#ifdef APSTUDIO_INVOKED\r\nGUIDELINES DESIGNINFO\r\nBEGIN\r\n    IDD_ABOUTBOX, DIALOG\r\n    BEGIN\r\n        LEFTMARGIN, 7\r\n        RIGHTMARGIN, 163\r\n        TOPMARGIN, 7\r\n        BOTTOMMARGIN, 55\r\n    END\r\nEND\r\n#endif    // APSTUDIO_INVOKED\r\n\r\n#ifdef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// TEXTINCLUDE\r\n//\r\n1 TEXTINCLUDE\r\nBEGIN\r\n    \"resource.h\\0\"\r\nEND\r\n\r\n2 TEXTINCLUDE\r\nBEGIN\r\n\t\"#ifndef APSTUDIO_INVOKED\\r\\n\"\r\n    \"#include \"\"targetver.h\"\"\\r\\n\"\r\n    \"#endif\\r\\n\"\r\n    \"#define APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\r\n    \"#include \"\"windows.h\"\"\\r\\n\"\r\n    \"#undef APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n3 TEXTINCLUDE\r\nBEGIN\r\n    \"\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n#endif    // APSTUDIO_INVOKED\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// String Table\r\n//\r\n\r\nSTRINGTABLE\r\nBEGIN\r\n   IDC_TESTW   \"TESTW\"\r\n   IDS_APP_TITLE       \"testw\"\r\nEND\r\n\r\n#endif\r\n/////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\n\r\n#ifndef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 3 resource.\r\n//\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n#endif    // not APSTUDIO_INVOKED\r\n"
  },
  {
    "path": "tests/projects/windows/winsdk/windemo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"win.sdk.application\")\n    add_files(\"*.rc\", \"*.cpp\")\n\n"
  },
  {
    "path": "tests/projects/xmake_cli/hello/src/lni/main.c",
    "content": "#include <xmake/xmake.h>\n\nstatic tb_byte_t const g_luafiles_data[] = {\n    #include \"luafiles.xmz.h\"\n};\n\nstatic tb_int_t lni_test_hello(lua_State* lua) {\n    lua_pushliteral(lua, \"hello xmake!\");\n    return 1;\n}\n\nstatic tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State* lua) {\n    static luaL_Reg const lni_test_funcs[] = {\n        {\"hello\", lni_test_hello}\n    ,   {tb_null, tb_null}\n    };\n    xm_engine_register(engine, \"test\", lni_test_funcs);\n    xm_engine_add_embedfiles(engine, g_luafiles_data, sizeof(g_luafiles_data));\n}\n\ntb_int_t main(tb_int_t argc, tb_char_t** argv) {\n    tb_char_t* taskargv[] = {\"lua\", \"-D\", \"lua.main\", tb_null};\n    return xm_engine_run(\"hello\", argc, argv, taskargv, lni_initalizer);\n}\n"
  },
  {
    "path": "tests/projects/xmake_cli/hello/src/lua/main.lua",
    "content": "import(\"core.base.option\")\nimport(\"lib.lni.test\")\n\nfunction main ()\n    print(test.hello())\n    local argv = option.get(\"arguments\")\n    if argv then\n        print(argv)\n    end\nend\n"
  },
  {
    "path": "tests/projects/xmake_cli/hello/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"libxmake\")\n\ntarget(\"hello\")\n    add_rules(\"xmake.cli\")\n    add_files(\"src/lni/*.c\")\n    add_files(\"src/lua/*.lua\", {rootdir = \"src\"})\n    add_packages(\"libxmake\")\n\n"
  },
  {
    "path": "tests/projects/xmake_cli/ide_integration/assets/targetpath.lua",
    "content": "import(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"lib.lni\")\n\nfunction main (targetname)\n    config.load()\n    if not os.isfile(os.projectfile()) then\n        return\n    end\n\n    local target = nil\n    if targetname then\n        target = project.target(targetname)\n    end\n    if not target then\n        for _, t in pairs(project.targets()) do\n            local default = t:get(\"default\")\n            if (default == nil or default == true) and t:get(\"kind\") == \"binary\" then\n                target = t\n                break\n            end\n        end\n    end\n\n    if target then\n        local targetfile = target:targetfile()\n        if not path.is_absolute(targetfile) then\n            targetfile = path.absolute(targetfile, os.projectdir())\n        end\n        lni.result = targetfile\n    end\nend\n"
  },
  {
    "path": "tests/projects/xmake_cli/ide_integration/assets/targets.lua",
    "content": "import(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.base.json\")\nimport(\"lib.lni\")\n\nfunction main ()\n    config.load()\n\n    local names = {}\n    for name, _ in pairs((project.targets())) do\n        table.insert(names, name)\n    end\n    table.sort(names)\n    if json.mark_as_array then\n        json.mark_as_array(names)\n    end\n    lni.result = json.encode(names)\nend\n"
  },
  {
    "path": "tests/projects/xmake_cli/ide_integration/src/main.c",
    "content": "#include <xmake/xmake.h>\n\nstatic lua_State* g_lua = tb_null;\nstatic tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State* lua) {\n    g_lua = lua;\n}\n\nstatic tb_char_t const* load_scriptfile(xm_engine_ref_t engine, tb_char_t const* filepath, tb_char_t const* arg1) {\n    // reset result first\n    lua_getglobal(g_lua, \"_lni\");\n    lua_pushnil(g_lua);\n    lua_setfield(g_lua, -2, \"result\");\n    lua_pop(g_lua, 1);\n\n    // load script and get result (string)\n    tb_char_t* argv[] = {\"xmake\"};\n    tb_char_t* taskargv[] = {\"lua\", \"-D\", (tb_char_t*)filepath, (tb_char_t*)arg1, tb_null};\n    tb_char_t const* result = tb_null;\n    if (xm_engine_main(engine, 1, argv, taskargv) == 0) {\n        lua_getglobal(g_lua, \"_lni\");\n        lua_getfield(g_lua, -1, \"result\");\n        if (lua_isstring(g_lua, -1)) {\n            result = tb_strdup(lua_tostring(g_lua, -1));\n        }\n        lua_pop(g_lua, 2);\n    }\n    return result;\n}\n\nstatic tb_void_t dump_targets(xm_engine_ref_t engine) {\n    tb_trace_i(\"------------------------- targets -------------------------\");\n    tb_char_t const* result = load_scriptfile(engine, \"assets/targets.lua\", tb_null);\n    if (result) {\n        tb_trace_i(\"result: %s\", result);\n        tb_free(result);\n    }\n}\n\nstatic tb_void_t dump_targetpath(xm_engine_ref_t engine) {\n    tb_trace_i(\"------------------------- targetpath -------------------------\");\n    tb_char_t const* result = load_scriptfile(engine, \"assets/targetpath.lua\", \"ide\");\n    if (result) {\n        tb_trace_i(\"result: %s\", result);\n        tb_free(result);\n    }\n}\n\ntb_int_t main(tb_int_t argc, tb_char_t** argv) {\n    if (xm_init()) {\n        xm_engine_ref_t engine = xm_engine_init(\"xmake\", lni_initalizer);\n        if (engine) {\n            dump_targets(engine);\n            dump_targetpath(engine);\n            xm_engine_exit(engine);\n        }\n        xm_exit();\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/xmake_cli/ide_integration/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"libxmake\")\ntarget(\"ide\")\n    add_files(\"src/*.c\")\n    add_packages(\"libxmake\")\n    set_rundir(\".\")\n\n"
  },
  {
    "path": "tests/projects/xmake_cli/xmake/src/main.c",
    "content": "#include <xmake/xmake.h>\n\ntb_int_t main(tb_int_t argc, tb_char_t** argv) {\n    return xm_engine_run(\"xmake\", argc, argv, tb_null, tb_null);\n}\n"
  },
  {
    "path": "tests/projects/xmake_cli/xmake/src/xmake.rc",
    "content": "#include \"xmake.config.h\"\n#include \"winres.h\"\n\n#define _STR(x) #x\n#define STR(x) _STR(x)\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0\n PRODUCTVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS_NT_WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE VFT2_UNKNOWN\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"000004B0\"\n        BEGIN\n            VALUE \"Comments\", \"A cross-platform build utility based on Lua\\nwebsite: https://xmake.io\"\n            VALUE \"CompanyName\", \"The Xmake Open Source Community\"\n            VALUE \"FileDescription\", \"XMake build utility\"\n            VALUE \"FileVersion\", XM_CONFIG_VERSION \"+\" STR(XM_CONFIG_VERSION_BUILD)\n            VALUE \"InternalName\", \"xmake\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2015-present Ruki Wang, https://xmake.io\"\n            VALUE \"LegalTrademarks\", \"\"\n            VALUE \"OriginalFilename\", \"xmake.exe\"\n            VALUE \"ProductName\", \"XMake\"\n            VALUE \"ProductVersion\", XM_CONFIG_VERSION \"+\" STR(XM_CONFIG_VERSION_BUILD)\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0, 1200\n    END\nEND\n\n\nIDI_APP ICON DISCARDABLE \"xmake.ico\"\n"
  },
  {
    "path": "tests/projects/xmake_cli/xmake/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"libxmake\")\ntarget(\"xmake\")\n    add_files(\"src/*.c\")\n    if is_plat(\"windows\") then\n        add_files(\"src/*.rc\")\n    end\n    add_packages(\"libxmake\")\n\n"
  },
  {
    "path": "tests/projects/zig/console/src/main.zig",
    "content": "const std = @import(\"std\");\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s}!\\n\", .{\"world\"});\n}\n"
  },
  {
    "path": "tests/projects/zig/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_files(\"src/*.zig\")\n\n"
  },
  {
    "path": "tests/projects/zig/console_c_call_zig/src/main.c",
    "content": "#include <stdio.h>\n\nint add(int a, int b);\nint main(int argc, char **argv) {\n    int result = add(42, 1337);\n    printf(\"%d\\n\", result);\n    return 0;\n}\n"
  },
  {
    "path": "tests/projects/zig/console_c_call_zig/src/test.zig",
    "content": "export fn add(a: i32, b: i32) i32 {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/zig/console_c_call_zig/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"zig >=0.10\")\n\ntarget(\"demo\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    add_files(\"src/*.zig\")\n    set_toolchains(\"@zig\")\n\n"
  },
  {
    "path": "tests/projects/zig/shared_library/src/main.zig",
    "content": "const std = @import(\"std\");\n\nextern fn add(a: i32, b: i32) i32;\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s} - {d}!\\n\", .{\"world\", add(1, 1)});\n}\n"
  },
  {
    "path": "tests/projects/zig/shared_library/src/test.zig",
    "content": "export fn add(a: i32, b: i32) i32 {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/zig/shared_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"testlib\")\n    set_kind(\"shared\")\n    add_files(\"src/test.zig\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"testlib\")\n    add_files(\"src/main.zig\")\n\n"
  },
  {
    "path": "tests/projects/zig/static_library/src/main.zig",
    "content": "const std = @import(\"std\");\n\nextern fn add(a: i32, b: i32) i32;\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s} - {d}!\\n\", .{\"world\", add(1, 1)});\n}\n"
  },
  {
    "path": "tests/projects/zig/static_library/src/test.zig",
    "content": "export fn add(a: i32, b: i32) i32 {\n    return a + b;\n}\n"
  },
  {
    "path": "tests/projects/zig/static_library/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"testlib\")\n    set_kind(\"static\")\n    add_files(\"src/test.zig\")\n\ntarget(\"test\")\n    set_kind(\"binary\")\n    add_deps(\"testlib\")\n    add_files(\"src/main.zig\")\n\n"
  },
  {
    "path": "tests/run.lua",
    "content": "-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"runner\", {rootdir = os.scriptdir()})\n\nfunction _run_test(script, opt)\n    runner(script, opt)\nend\n\n-- run test with the given name\nfunction _run_test_filter(name)\n    local tests = {}\n    local root = path.absolute(os.scriptdir())\n    for _, script in ipairs(os.files(path.join(root, \"**\", name, \"**\", \"test.lua\"))) do\n        if not script:find(\".xmake\", 1, true) then\n            table.insert(tests, path.absolute(script))\n        end\n    end\n    for _, script in ipairs(os.files(path.join(root, name, \"**\", \"test.lua\"))) do\n        if not script:find(\".xmake\", 1, true) then\n            table.insert(tests, path.absolute(script))\n        end\n    end\n    for _, script in ipairs(os.files(path.join(root, \"**\", name, \"test.lua\"))) do\n        table.insert(tests, path.absolute(script))\n    end\n    for _, script in ipairs(os.files(path.join(root, name, \"test.lua\"))) do\n        table.insert(tests, path.absolute(script))\n    end\n\n    tests = table.unique(tests)\n    if #tests == 0 then\n        utils.warning(\"no test have run, please check your filter .. (%s)\", name)\n    else\n        cprint(\"> %d test(s) found\", #tests)\n        if option.get(\"diagnosis\") then\n            for _, v in ipairs(tests) do\n                cprint(\">     %s\", v)\n            end\n        end\n        for i, v in ipairs(tests) do\n            _run_test(v, {index = i, total = #tests})\n        end\n        cprint(\"> %d test(s) succeed\", #tests)\n    end\nend\n\nfunction main(name)\n    return _run_test_filter(name or \"/\")\nend\n"
  },
  {
    "path": "tests/runner.lua",
    "content": "import(\"core.base.option\")\nimport(\"test_utils.context\", { alias = \"test_context\" })\n\nfunction main(script, opt)\n    opt = opt or {}\n\n    if os.isdir(script) then\n        script = path.join(script, \"test.lua\")\n    end\n    script = path.absolute(script)\n    assert(path.filename(script) == \"test.lua\", \"file(%s) should named `test.lua`\", script)\n    assert(os.isfile(script), \"should be a file\")\n\n    -- disable statistics\n    os.setenv(\"XMAKE_STATS\", \"false\")\n\n    -- init test context\n    local context = test_context(script)\n\n    local root = path.directory(script)\n    local verbose = option.get(\"verbose\") or option.get(\"diagnosis\")\n\n    -- trace\n    cprint(\">> [%d/%d]: testing %s ...\", opt.index, opt.total, path.relative(root))\n\n    -- get test functions\n    local data = import(\"test\", { rootdir = root, anonymous = true })\n    if data.main then\n        -- ignore everthing when we found a main function\n        data = { test_main = data.main }\n    end\n\n    -- enter script directory\n    local old_dir = os.cd(root)\n\n    -- run test\n    local succeed_count = 0\n    local start_time = os.mclock()\n    for k, v in pairs(data) do\n        if k:startswith(\"test\") and type(v) == \"function\" then\n            if verbose then\n                print(\">>     running %s ...\", k)\n            end\n            context.func = v\n            context.funcname = k\n            local result = try\n            {\n                function ()\n                    -- set workdir for each test\n                    os.cd(root)\n                    return v(context)\n                end,\n                catch\n                {\n                    function (errors)\n                        if errors then\n                            errors = tostring(errors)\n                        end\n                        if errors and not errors:find(\"aborting because of \") then\n                            context:print_error(errors, v, \"unhandled error\")\n                        else\n                            raise(errors)\n                        end\n                    end\n                }\n            }\n            if context:is_skipped(result) then\n                print(\">>     skipped %s : %s\", k, result.reason)\n            end\n            succeed_count = succeed_count + 1\n        end\n    end\n    if verbose then\n        print(\">>   finished %d test method(s), spent %0.02fs\", succeed_count, (os.mclock() - start_time) / 1000)\n    end\n\n    -- leave script directory\n    os.cd(old_dir)\nend\n"
  },
  {
    "path": "tests/test/test.lua",
    "content": "function test_are_same(t)\n    t:are_same(1, 1)\n    t:are_same(\"1\", \"1\")\n    t:are_same(nil, nil)\n    t:are_same(true, true)\n    t:are_same(1.34, 1.34)\n    t:are_same(test_are_same, test_are_same)\n\n    t:are_not_same({}, {})\n    t:are_not_same(1, \"1\")\nend\n\nfunction test_are_equal(t)\n    t:are_equal(1, 1)\n    t:are_equal(\"1\", \"1\")\n    t:are_equal(nil, nil)\n    t:are_equal(true, true)\n    t:are_equal(1.34, 1.34)\n    t:are_equal(test_are_same, test_are_same)\n    t:are_equal({}, {})\n    t:are_equal({ a = 1 }, { a = 1 })\n    t:are_equal({ a = { a= 1}}, { a = {a=1} })\n\n    t:are_not_equal(1, \"1\")\n    t:are_not_equal({ a = 1 }, { a = 1, b = 2 })\n    t:are_not_equal({ a = 1, c = 3 }, { a = 1, b = 2 })\n    t:are_not_equal({ a = 1}, { a = 1, b = 2 })\n    t:are_not_equal({ a = { a= 1}}, { a = {a=2} })\nend\n\n\nfunction test_require(t)\n    t:require(true)\n    t:require({})\n    t:require(0)\n    t:require(\"\")\n\n    t:require_not(false)\n    t:require_not(nil)\nend\n\nfunction test_will_raise(t)\n    t:will_raise(function ()\n        raise(\"error: xxx\")\n    end, \"error\")\n    t:will_raise(function ()\n        raise(\" \")\n    end, \"%s\")\n    t:will_raise(function ()\n        raise(\"\")\n    end)\n\n    t:will_raise(function ()\n        print(\"A test failed message will be printed\")\n        t:will_raise(function() end)\n    end, \"aborting because of ${red}failed assertion${reset}\")\nend\n\n"
  },
  {
    "path": "tests/test_utils/check.lua",
    "content": "\n\nfunction _tablelength(table)\n  local count = 0\n  for _ in pairs(table) do count = count + 1 end\n  return count\nend\n\nfunction _get_rep(value)\n    if type(value) == \"nil\" then return \"(nil)\" end\n    if type(value) == \"string\" then return \"`\" .. value .. \"`\" end\n    return tostring(value)\nend\n\nfunction same(actual, expected)\n    if actual ~= actual and expected ~= expected then\n        return true, _get_rep(actual), _get_rep(expected)\n    end\n    return actual == expected, _get_rep(actual), _get_rep(expected)\nend\n\nfunction equal(actual, expected)\n    local same, ap, ep = same(actual, expected)\n    if same then return true, ap, ep end\n    if type(expected) == \"table\" and type(actual) == \"table\" then\n        local al = _tablelength(actual)\n        local el = _tablelength(expected)\n        if al ~= el then\n            return false, vformat(\"{...(%d elements)}\", al), vformat(\"{...(%d elements)}\", el)\n        end\n        for k, v in pairs(expected) do\n            local av = actual[k]\n            local eq, app, epp = equal(av, v)\n            if not eq then\n                return false, vformat(\"{[%s] = %s, ...}\", k, app), vformat(\"{[%s] = %s, ...}\", k, epp)\n            end\n        end\n        return true, \"{...}\", \"{...}\"\n    end\n    return false, ap, ep\nend"
  },
  {
    "path": "tests/test_utils/context.lua",
    "content": "import(\"test_build\")\nimport(\"test_skip\")\nimport(\"test_assert\")\n\nfunction main(filename)\n    local context = { filename = filename }\n    table.join2(context, test_build())\n    table.join2(context, test_skip())\n    table.join2(context, test_assert())\n    return context\nend\n"
  },
  {
    "path": "tests/test_utils/print_error.lua",
    "content": "\nfunction _getinfo(v)\n    local info = debug.getinfo(v)\n    if info == nil then return end\n    if info and info.source:startswith(\"@\") then\n        info.fullpath = path.absolute(vformat(info.source:sub(2)), os.workingdir())\n        info.path = path.relative(info.fullpath, os.workingdir())\n    end\n    return info\nend\n\nfunction _getfuncs(funcs_or_filename)\n    local funcs = nil\n    if type(funcs_or_filename) == \"function\" then\n        funcs = { _getinfo(funcs_or_filename) }\n    elseif type(funcs_or_filename) == \"table\" then\n        funcs = {}\n        for _, v in ipairs(funcs_or_filename) do\n            table.join2(funcs, _getfuncs(v))\n        end\n    else\n        assert(type(funcs_or_filename) == \"string\")\n        funcs_or_filename = path.absolute(funcs_or_filename)\n        funcs = {}\n        local uplevel = 2\n        local func = nil\n        repeat\n            func = _getinfo(uplevel)\n            if func and func.fullpath == funcs_or_filename then\n                table.insert(funcs, func)\n            end\n            uplevel = uplevel + 1\n        until func == nil\n    end\n    return funcs\nend\n\nfunction main(t, message, funcs_or_filename, abort_reason)\n    local funcs = _getfuncs(funcs_or_filename)\n    cprint(\">>     ${red}test failed:${reset} %s\", message)\n    for _, func in ipairs(funcs) do\n        local line = (func.currentline >= 0) and func.currentline or func.linedefined\n        local name = (func.func == t.func) and t.funcname or func.name or \"(anonymous)\"\n        cprint(\">>       function %s ${underline}%s${reset}:${bright}%d${reset}\", name, func.path, line)\n    end\n    raise(\"aborting because of ${red}%s${reset} ...\", abort_reason or \"failed assertion\")\nend"
  },
  {
    "path": "tests/test_utils/test_assert.lua",
    "content": "\n\nimport(\"check\")\n\nlocal test_assert = { print_error = import(\"print_error\", { anonymous = true }).main }\n\nfunction test_assert:require(value)\n    if not value then\n        self:print_error(vformat(\"require ${green}true${reset} but got ${red}%s${reset}\", value), self.filename)\n    end\nend\n\nfunction test_assert:require_not(value)\n    if value then\n        self:print_error(vformat(\"require ${green}false${reset} but got ${red}%s${reset}\", value), self.filename)\n    end\nend\n\nfunction test_assert:are_same(actual, expected)\n    local r, ap, ep = check.same(actual, expected)\n    if not r then\n        self:print_error(format(\"expected: ${green}%s${reset}, actual ${red}%s${reset}\", ep, ap), self.filename)\n    end\nend\n\nfunction test_assert:are_not_same(actual, expected)\n    local r, ap, ep = check.same(actual, expected)\n    if r then\n        self:print_error(format(\"expected: ${green}%s${reset}, actual ${red}%s${reset}\", ep, ap), self.filename)\n    end\nend\n\n\nfunction test_assert:are_equal(actual, expected)\n    local r, ap, ep = check.equal(actual, expected)\n    if not r then\n        self:print_error(format(\"expected: ${green}%s${reset}, actual ${red}%s${reset}\", ep, ap), self.filename)\n    end\nend\n\nfunction test_assert:are_not_equal(actual, expected)\n    local r, ap, ep = check.equal(actual, expected)\n    if r then\n        self:print_error(format(\"expected: ${green}%s${reset}, actual ${red}%s${reset}\", ep, ap), self.filename)\n    end\nend\n\ntest_assert._will_raise_stack = {}\nfunction test_assert:will_raise(func, message_pattern)\n    table.insert(self._will_raise_stack, 1, debug.getinfo(2).func)\n    try\n    {\n        func,\n        finally\n        {\n            function (ok, error)\n                local funcs = { func, unpack(self._will_raise_stack) }\n                if ok then\n                    self:print_error(\"expected raise but finished successfully\", funcs)\n                elseif message_pattern and not error:find(message_pattern, 1, true) and not error:find(message_pattern) then\n                    self:print_error(format(\"expected raise with message ${green}%s${reset} but got ${red}%s${reset}\", message_pattern, error), funcs)\n                end\n            end\n        }\n    }\n    table.remove(self._will_raise_stack, 1)\nend\n\nfunction main()\n    return test_assert\nend\n"
  },
  {
    "path": "tests/test_utils/test_build.lua",
    "content": "local test_build = {}\n\nfunction test_build:build(argv)\n    os.exec(\"xmake f -c -D -y\")\n    os.exec(\"xmake -D\")\nend\n\nfunction main()\n    return test_build\nend\n"
  },
  {
    "path": "tests/test_utils/test_skip.lua",
    "content": "local test_skip = { _is_skipped_tag = {true} }\n\nfunction test_skip:skip(reason)\n    return { is_skipped = self._is_skipped_tag, reason = reason, context = self }\nend\n\nfunction test_skip:is_skipped(result)\n    return result and result.context and result.context._is_skipped_tag == result.is_skipped\nend\n\nfunction main()\n    return test_skip\nend"
  },
  {
    "path": "tests/ui/desktop.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        desktop.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.button\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- show desktop, menubar and statusbar\n    self:insert(self:desktop())\n    self:insert(self:menubar())\n    self:insert(self:statusbar())\n\n    -- init title\n    self:menubar():title():text_set(\"Menu Bar (Hello)\")\n\n    -- add title label\n    self:desktop():insert(label:new(\"title\", rect {0, 0, 12, 1}, \"hello ltui!\"):textattr_set(\"white\"), {centerx = true})\n\n    -- add yes button\n    self:desktop():insert(button:new(\"yes\", rect {0, 1, 7, 2}, \"< Yes >\"):textattr_set(\"white\"), {centerx = true})\n\n    -- add no button\n    self:desktop():insert(button:new(\"no\", rect {0, 2, 6, 3}, \"< No >\"):textattr_set(\"white\"), {centerx = true})\nend\n\n-- on event\nfunction demo:on_event(e)\n    if application.on_event(self, e) then\n        return true\n    end\n    if e.type == event.ev_keyboard then\n        self:statusbar():info():text_set(e.key_name)\n        if e.key_name == \"s\" then\n            self:statusbar():show(not self:statusbar():state(\"visible\"))\n        elseif e.key_name == \"m\" then\n            self:menubar():show(not self:menubar():state(\"visible\"))\n        elseif e.key_name == \"d\" then\n            self:desktop():show(not self:desktop():state(\"visible\"))\n        end\n    end\nend\n\n-- on resize\nfunction demo:on_resize()\n    for v in self:desktop():views() do\n        self:center(v, {centerx = true})\n    end\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/dialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dialog.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.boxdialog\")\nimport(\"core.ui.textdialog\")\nimport(\"core.ui.inputdialog\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- init main dialog\n    self:insert(self:dialog_main())\n\n    -- init input dialog\n    self:insert(self:dialog_input(), {centerx = true, centery = true})\n\n    -- init tips dialog\n    self:insert(self:dialog_tips(), {centerx = true, centery = true})\nend\n\n-- main dialog\nfunction demo:dialog_main()\n    local dialog_main = self._DIALOG_MAIN\n    if not dialog_main then\n        dialog_main = boxdialog:new(\"dialog.main\", rect {1, 1, self:width() - 1, self:height() - 1}, \"main dialog\")\n        dialog_main:text():text_set(\"The project focuses on making development and building easier and provides many features (.e.g package, install, plugin, macro, action, option, task ...), so that any developer can quickly pick it up and enjoy the productivity boost when developing and building project.\")\n        dialog_main:button_add(\"tips\", \"< Tips >\", function (v) self:view(\"dialog.tips\"):show(true, {focused = true}) end)\n        dialog_main:button_add(\"input\", \"< Input >\", function (v) self:view(\"dialog.input\"):show(true, {focused = true}) end)\n        dialog_main:button_add(\"help\", \"< Help >\", function (v) self:insert(self:dialog_help()) end)\n        dialog_main:button_add(\"quit\", \"< Quit >\", \"cm_quit\")\n        self._DIALOG_MAIN = dialog_main\n    end\n    return dialog_main\nend\n\n-- help dialog\nfunction demo:dialog_help()\n    local dialog_help = self._DIALOG_HELP\n    if not dialog_help then\n        dialog_help = textdialog:new(\"dialog.help\", rect {1, 1, self:width() - 1, self:height() - 1}, \"README\")\n        dialog_help:option_set(\"scrollable\", true)\n        local helptext = nil\n        local file = io.open(\"./LICENSE.md\", 'r')\n        if file then\n            helptext = file:read(\"*a\")\n            file:close()\n        end\n        if helptext then\n            dialog_help:text():text_set(helptext)\n        end\n        dialog_help:button_add(\"exit\", \"< Exit >\", function (v) self:remove(dialog_help) end)\n        self._DIALOG_HELP = dialog_help\n    end\n    return dialog_help\nend\n\n-- input dialog\nfunction demo:dialog_input()\n    local dialog_input = self._DIALOG_INPUT\n    if not dialog_input then\n        dialog_input = inputdialog:new(\"dialog.input\", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background())\n        dialog_input:frame():background_set(\"cyan\")\n        dialog_input:text():text_set(\"please input text:\"):textattr_set(\"red\")\n        dialog_input:button_add(\"no\", \"< No >\", function (v) dialog_input:show(false) end)\n        dialog_input:button_add(\"yes\", \"< Yes >\", function (v)\n                                                      self:dialog_main():text():text_set(dialog_input:textedit():text())\n                                                      dialog_input:show(false)\n                                                  end)\n        dialog_input:show(false)\n        self._DIALOG_INPUT = dialog_input\n    end\n    return dialog_input\nend\n\n-- tips dialog\nfunction demo:dialog_tips()\n    local dialog_tips = self._DIALOG_TIPS\n    if not dialog_tips then\n        dialog_tips = textdialog:new(\"dialog.tips\", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background())\n        dialog_tips:frame():background_set(\"cyan\")\n        dialog_tips:text():text_set(\"hello ltui! (https://tboox.org)\\nA cross-platform terminal ui library based on Lua\"):textattr_set(\"red\")\n        dialog_tips:button_add(\"yes\", \"< Yes >\", function (v) dialog_tips:show(false) end)\n        dialog_tips:button_add(\"no\", \"< No >\", function (v) dialog_tips:show(false) end)\n        self._DIALOG_TIPS = dialog_tips\n    end\n    return dialog_tips\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:dialog_main():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    self:dialog_help():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    self:center(self:dialog_input(), {centerx = true, centery = true})\n    self:center(self:dialog_tips(), {centerx = true, centery = true})\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/events.lua",
    "content": "--!A cross-platform terminal ui library based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        events.lua\n--\n\n-- imports\nimport(\"core.ui.rect\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.window\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"black\")\n\n    -- init body window\n    self:insert(self:body_window())\n\n    -- init teste\n    self:body_window():panel():insert(self:teste())\nend\n\n-- get body window\nfunction demo:body_window()\n    if not self._BODY_WINDOW then\n        self._BODY_WINDOW = window:new(\"window.body\", rect {1, 1, self:width() - 1, self:height() - 1}, \"main window\")\n    end\n    return self._BODY_WINDOW\nend\n\n-- get teste label\nfunction demo:teste()\n    if not self._TESTE then\n        self._TESTE = label:new('demo.label', rect {0, 0, 40, 5}, 'this is a test')\n    end\n    return self._TESTE\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    application.on_resize(self)\nend\n\n-- on event\nfunction demo:on_event(e)\n    if e.type < event.ev_max then\n        self:teste():text_set('type: ' ..\n            tostring(e.type) ..\n            '; name: ' ..\n            tostring(e.key_name or e.btn_name) ..\n            '; code: ' ..\n            tostring(e.key_code or e.x) ..\n            '; meta: ' ..\n            tostring(e.key_code or e.y))\n    end\n    application.on_event(self, e)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/inputdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        inputdialog.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.inputdialog\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- init input dialog\n    self:insert(self:dialog_input(), {centerx = true, centery = true})\nend\n\n-- input dialog\nfunction demo:dialog_input()\n    local dialog_input = self._DIALOG_INPUT\n    if not dialog_input then\n        dialog_input = inputdialog:new(\"dialog.input\", rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)})\n        dialog_input:text():text_set(\"please input text:\")\n        dialog_input:button_add(\"no\", \"< No >\", function (v) dialog_input:quit() end)\n        dialog_input:button_add(\"yes\", \"< Yes >\", function (v) dialog_input:quit() end)\n        self._DIALOG_INPUT = dialog_input\n    end\n    return dialog_input\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:dialog_input():bounds_set(rect{0, 0, math.floor(self:width() / 2), math.floor(self:height() / 3)})\n    self:center(self:dialog_input(), {centerx = true, centery = true})\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/mconfdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mconfdialog.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.action\")\nimport(\"core.ui.menuconf\")\nimport(\"core.ui.mconfdialog\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- init configs\n    local configs_sub2 = {}\n    table.insert(configs_sub2, menuconf.boolean {description = \"boolean config sub-item2\"})\n    table.insert(configs_sub2, menuconf.number {value = 10, default = 10, description = \"number config sub-item2\"})\n    table.insert(configs_sub2, menuconf.string {value = \"armv7\", description = \"string config sub-item2\"})\n    table.insert(configs_sub2, menuconf.menu {description = \"menu config sub-item2\"})\n\n    local configs_sub = {}\n    table.insert(configs_sub, menuconf.boolean {description = \"boolean config sub-item\"})\n    table.insert(configs_sub, menuconf.number {value = 90, default = 10, description = \"number config sub-item\"})\n    table.insert(configs_sub, menuconf.string {value = \"arm64\", description = \"string config sub-item\"})\n    table.insert(configs_sub, menuconf.menu {description = \"menu config sub-item\", configs = configs_sub2})\n    table.insert(configs_sub, menuconf.choice {value = 2, values = {2, 5, 16, 87}, description = \"choice config sub-item\"})\n\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item1\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item2\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item3\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item4\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item5\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item6\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item7\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item8\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item9\"})\n\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item10\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item11\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item12\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item13\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item14\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item15\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item16\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item17\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item18\"})\n    table.insert(configs_sub, menuconf.number {value = 6, default = 10, description = \"number config item19\"})\n\n    local configs = {}\n    table.insert(configs, menuconf.boolean {description = \"boolean config item\"})\n    table.insert(configs, menuconf.boolean {default = true, new = false, description = {\"boolean config item2\",\n                                                                                        \"  - more description info\",\n                                                                                        \"  - more description info\",\n                                                                                        \"  - more description info\"}})\n    table.insert(configs, menuconf.number {value = 6, default = 10, description = \"number config item\"})\n    table.insert(configs, menuconf.string {value = \"x86_64\", description = \"string config item\"})\n    table.insert(configs, menuconf.menu {description = \"menu config item\", configs = configs_sub})\n    table.insert(configs, menuconf.choice {value = 3, values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, default = 2, description = \"choice config item\"})\n\n    -- init menu config dialog\n    self:dialog_mconf():load(configs)\n    self:insert(self:dialog_mconf())\nend\n\n-- get mconfdialog\nfunction demo:dialog_mconf()\n    local dialog_mconf = self._DIALOG_MCONF\n    if not dialog_mconf then\n        dialog_mconf = mconfdialog:new(\"mconfdialog.main\", rect{1, 1, self:width() - 1, self:height() - 1}, \"menu config\")\n        dialog_mconf:action_set(action.ac_on_exit, function (v) self:quit() end)\n        dialog_mconf:action_set(action.ac_on_save, function (v)\n            -- TODO save configs\n            dialog_mconf:quit()\n        end)\n        self._DIALOG_MCONF = dialog_mconf\n    end\n    return dialog_mconf\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:dialog_mconf():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1})\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/utf8dialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki, laelnasan\n-- @file        inputdialog.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.button\")\nimport(\"core.ui.boxdialog\")\nimport(\"core.ui.textdialog\")\nimport(\"core.ui.inputdialog\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- init main dialog\n    self:insert(self:dialog_main())\n\n    -- init input dialog\n    self:insert(self:dialog_input(), {centerx = true, centery = true})\n\n    -- init tips dialog\n    self:insert(self:dialog_tips(), {centerx = true, centery = true})\nend\n\n-- main dialog\nfunction demo:dialog_main()\n    local dialog_main = self._DIALOG_MAIN\n    if not dialog_main then\n        dialog_main = boxdialog:new(\"dialog.main\", rect {1, 1, self:width() - 1, self:height() - 1}, \"main dialog\")\n        dialog_main:text():text_set([[LTUI是一个基于lua的跨平台字符终端UI界面库。\n此框架源于xmake中图形化菜单配置的需求，类似linux kernel的menuconf去配置编译参数，因此基于curses和lua实现了一整套跨平台的字符终端ui库。 而样式风格基本上完全参照的kconfig-frontends，当然用户也可以自己定制不同的ui风格。]])\n        dialog_main:button_add(\"tips\", \"< ☝ Tips >\", function (v) self:view(\"dialog.tips\"):show(true, {focused = true}) end)\n        dialog_main:button_add(\"input\", \"< ☺ Input >\", function (v) self:view(\"dialog.input\"):show(true, {focused = true}) end)\n        dialog_main:button_add(\"help\", \"< ☕Help >\", function (v) self:insert(self:dialog_help()) end)\n        dialog_main:button_add(\"quit\", \"< ☠ Quit >\", \"cm_quit\")\n        self._DIALOG_MAIN = dialog_main\n    end\n    return dialog_main\nend\n\n-- help dialog\nfunction demo:dialog_help()\n    local dialog_help = self._DIALOG_HELP\n    if not dialog_help then\n        dialog_help = textdialog:new(\"dialog.help\", rect {1, 1, self:width() - 1, self:height() - 1}, \"README\")\n        dialog_help:option_set(\"scrollable\", true)\n        local helptext = nil\n        local file = io.open(\"./LICENSE.md\", 'r')\n        if file then\n            helptext = file:read(\"*a\")\n            file:close()\n        end\n        if helptext then\n            dialog_help:text():text_set(helptext)\n        end\n        dialog_help:button_add(\"exit\", \"< Exit >\", function (v) self:remove(dialog_help) end)\n        self._DIALOG_HELP = dialog_help\n    end\n    return dialog_help\nend\n\n-- input dialog\nfunction demo:dialog_input()\n    local dialog_input = self._DIALOG_INPUT\n    if not dialog_input then\n        dialog_input = inputdialog:new(\"dialog.input\", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background())\n        dialog_input:frame():background_set(\"cyan\")\n        dialog_input:text():text_set(\"please input text:\"):textattr_set(\"red\")\n        dialog_input:button_add(\"no\", \"< No >\", function (v) dialog_input:show(false) end)\n        dialog_input:button_add(\"yes\", \"< Yes >\", function (v)\n                                                      self:dialog_main():text():text_set(dialog_input:textedit():text())\n                                                      dialog_input:show(false)\n                                                  end)\n        dialog_input:show(false)\n        self._DIALOG_INPUT = dialog_input\n    end\n    return dialog_input\nend\n\n-- tips dialog\nfunction demo:dialog_tips()\n    local dialog_tips = self._DIALOG_TIPS\n    if not dialog_tips then\n        dialog_tips = textdialog:new(\"dialog.tips\", rect {0, 0, 50, 8}):background_set(self:dialog_main():frame():background())\n        dialog_tips:frame():background_set(\"cyan\")\n        dialog_tips:text():text_set(\"hello ltui! (https://tboox.org)\\nA cross-platform terminal ui library based on Lua\"):textattr_set(\"red\")\n        dialog_tips:button_add(\"yes\", \"< Yes >\", function (v) dialog_tips:show(false) end)\n        dialog_tips:button_add(\"no\", \"< No >\", function (v) dialog_tips:show(false) end)\n        self._DIALOG_TIPS = dialog_tips\n    end\n    return dialog_tips\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:dialog_main():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    self:dialog_help():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    self:center(self:dialog_input(), {centerx = true, centery = true})\n    self:center(self:dialog_tips(), {centerx = true, centery = true})\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "tests/ui/window.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-2020, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        window.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.window\")\nimport(\"core.ui.application\")\n\n-- the demo application\nlocal demo = application()\n\n-- init demo\nfunction demo:init()\n\n    -- init name\n    application.init(self, \"demo\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- init body window\n    self:insert(self:body_window())\nend\n\n-- get body window\nfunction demo:body_window()\n    if not self._BODY_WINDOW then\n        self._BODY_WINDOW = window:new(\"window.body\", rect {1, 1, self:width() - 1, self:height() - 1}, \"main window\", true)\n    end\n    return self._BODY_WINDOW\nend\n\n-- on resize\nfunction demo:on_resize()\n    self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})\n    application.on_resize(self)\nend\n\n-- main entry\nfunction main(...)\n    demo:run(...)\nend\n"
  },
  {
    "path": "xmake/actions/build/build.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\nimport(\"deprecated.build\", {alias = \"deprecated_build\"})\n\n-- run prepare jobs\nfunction _prepare(targets_root, opt)\n    opt = opt or {}\n    opt.job_kind = \"prepare\"\n    opt.progress_factor = 0.05\n    target_buildutils.run_targetjobs(targets_root, opt)\nend\n\n-- run build jobs\nfunction _build(targets_root, opt)\n    opt = opt or {}\n    opt.job_kind = \"build\"\n    opt.progress_factor = 0.95\n    if distcc_build_client.is_connected() then\n        opt.distcc = distcc_build_client.singleton()\n        if project.policy(\"build.distcc.remote_only\") then\n            opt.remote_only = true\n        end\n    end\n    target_buildutils.run_targetjobs(targets_root, opt)\nend\n\nfunction main(targetnames, opt)\n\n    -- get root targets\n    local targets_root = target_buildutils.get_root_targets(targetnames, opt)\n\n    -- prepare to build\n    _prepare(targets_root, opt)\n\n    -- do build\n    if project.policy(\"build.jobgraph\") then\n        _build(targets_root, opt)\n    else\n        deprecated_build(targets_root, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/actions/build/build_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\nimport(\"deprecated.build_files\", {alias = \"deprecated_build_files\"})\n\n-- convert all sourcefiles to lua pattern\nfunction _get_file_patterns(sourcefiles)\n    local patterns = {}\n    if not sourcefiles then\n        return patterns\n    end\n    for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do\n\n        -- get the excludes\n        local pattern  = sourcefile:trim()\n        local excludes = pattern:match(\"|.*$\")\n        if excludes then excludes = excludes:split(\"|\", {plain = true}) end\n\n        -- translate excludes\n        if excludes then\n            local _excludes = {}\n            for _, exclude in ipairs(excludes) do\n                exclude = path.translate(exclude)\n                exclude = path.pattern(exclude)\n                table.insert(_excludes, exclude)\n            end\n            excludes = _excludes\n        end\n\n        -- translate path and remove some repeat separators\n        pattern = path.translate(pattern:gsub(\"|.*$\", \"\"))\n\n        -- remove \"./\" or '.\\\\' prefix\n        if pattern:sub(1, 2):find('%.[/\\\\]') then\n            pattern = pattern:sub(3)\n        end\n\n        -- get the root directory\n        local rootdir = pattern\n        local startpos = pattern:find(\"*\", 1, true)\n        if startpos then\n            rootdir = rootdir:sub(1, startpos - 1)\n        end\n        rootdir = path.directory(rootdir)\n\n        -- convert to lua path pattern\n        pattern = path.pattern(pattern)\n        table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir})\n    end\n    return patterns\nend\n\n-- run prepare files jobs\nfunction _prepare_files(targets_root, opt)\n    opt = opt or {}\n    opt.job_kind = \"prepare\"\n    opt.progress_factor = 0.05\n    opt.filepatterns = _get_file_patterns(opt.sourcefiles)\n    target_buildutils.run_filejobs(targets_root, opt)\nend\n\n-- run build files jobs\nfunction _build_files(targets_root, opt)\n    opt = opt or {}\n    opt.job_kind = \"build\"\n    opt.progress_factor = 0.95\n    opt.filepatterns = _get_file_patterns(opt.sourcefiles)\n    if distcc_build_client.is_connected() then\n        opt.distcc = distcc_build_client.singleton()\n    end\n    if not target_buildutils.run_filejobs(targets_root, opt) then\n        if opt.sourcefiles then\n            wprint(\"%s not found!\", opt.sourcefiles)\n        else\n            wprint(\"no files found!\")\n        end\n    end\nend\n\nfunction main(targetnames, opt)\n\n    -- get root targets\n    local targets_root = target_buildutils.get_root_targets(targetnames, opt)\n\n    -- prepare to build files\n    _prepare_files(targets_root, opt)\n\n    -- do build files\n    if project.policy(\"build.jobgraph\") then\n        _build_files(targets_root, opt)\n    else\n        deprecated_build_files(targets_root, opt)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/actions/build/check.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_targets.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\nimport(\"private.check.checker\")\nimport(\"private.check.show\")\n\nfunction main(targetnames, opt)\n    opt = opt or {}\n\n    -- get targets\n    local targets = {}\n    if targetnames then\n        for _, targetname in ipairs(table.wrap(targetnames)) do\n            table.insert(targets, project.target(targetname))\n        end\n    else\n        for _, target in pairs(project.targets()) do\n            if target:is_enabled() then\n                local group = target:get(\"group\")\n                if (target:is_default() and not group_pattern) or option.get(\"all\") or (group_pattern and group and group:match(group_pattern)) then\n                    table.insert(targets, target)\n                end\n            end\n        end\n    end\n\n    -- do check\n    local checkers = checker.checkers()\n    for name, info in table.orderpairs(checkers) do\n        if (info.build and opt.build) or (info.build_failure and opt.build_failure) then\n            local check = import(\"private.check.checkers.\" .. name, {anonymous = true})\n            for _, target in ipairs(targets) do\n                check({target = target, show = show.wshow})\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/actions/build/cleaner.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cleaner.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.process\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.package.package\")\nimport(\"core.platform.platform\")\n\n-- clean up temporary files once a day\nfunction cleanup()\n\n    -- has been cleaned up today?\n    local markfile = path.join(os.tmpdir(), \"cleanup\", os.date(\"%y%m%d\") .. \".mark\")\n    if os.isfile(markfile) then\n        return\n    end\n\n    -- mark as posted first, avoid posting it repeatly\n    io.writefile(markfile, \"ok\")\n\n    -- init argument list\n    local argv = {\"lua\", path.join(os.scriptdir(), \"cleaner.lua\")}\n    for _, name in ipairs({\"root\", \"file\", \"project\", \"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\"}) do\n        local value = option.get(name)\n        if type(value) == \"string\" then\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        elseif value then\n            table.insert(argv, \"--\" .. name)\n        end\n    end\n\n    -- try to post it in background\n    try\n    {\n        function ()\n            process.openv(os.programfile(), argv, {stdout = path.join(os.tmpdir(), \"cleaner.log\"), detach = true}):close()\n        end\n    }\nend\n\n-- the main function\nfunction main()\n\n    -- clean up the temporary files at last 30 days, @see os.tmpdir()\n    local parentdir = path.directory(os.tmpdir())\n    for day = 1, 30 do\n        local tmpdir = path.join(parentdir, os.date(\"%y%m%d\", os.time() - day * 24 * 3600))\n        if os.isdir(tmpdir) then\n            print(\"cleanup %s ..\", tmpdir)\n            os.tryrm(tmpdir)\n        end\n    end\n\n    -- clean up the temporary files of project at last 30 days, @see project.tmpdir()\n    if os.isfile(os.projectfile()) then\n        local parentdir = path.directory(project.tmpdir())\n        for day = 1, 30 do\n            local tmpdir = path.join(parentdir, os.date(\"%y%m%d\", os.time() - day * 24 * 3600))\n            if os.isdir(tmpdir) then\n                print(\"cleanup %s ..\", tmpdir)\n                os.tryrm(tmpdir)\n            end\n        end\n    end\n\n    -- clean up the previous month package cache files, @see package.cachedir()\n    local cachedir = path.join(package.cachedir({rootonly = true}), os.date(\"%y%m\", os.time() - 31 * 24 * 3600))\n    if os.isdir(cachedir) and cachedir ~= package.cachedir() then\n        print(\"cleanup %s ..\", cachedir)\n        os.tryrm(cachedir)\n    end\nend\n"
  },
  {
    "path": "xmake/actions/build/deprecated/build.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.async.jobpool\")\nimport(\"async.runjobs\")\nimport(\"private.utils.batchcmds\")\nimport(\"core.base.hashset\")\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\n\n-- clean target for rebuilding\nfunction _clean_target(target)\n    if target:targetfile() then\n        os.tryrm(target:symbolfile())\n        os.tryrm(target:targetfile())\n    end\nend\n\n-- add builtin batch jobs\nfunction _add_batchjobs_builtin(batchjobs, rootjob, target)\n\n    -- uses the rules script?\n    local job, job_leaf\n    for _, r in irpairs(target:orderules()) do -- reverse rules order for batchjobs:addjob()\n        local script = r:script(\"build\")\n        if script then\n            if r:extraconf(\"build\", \"batch\") then\n                job, job_leaf = assert(script(target, batchjobs, {rootjob = job or rootjob}), \"rule(%s):on_build(): no returned job!\", r:name())\n            elseif r:extraconf(\"build\", \"jobgraph\") then\n                wprint(\"rule(%s) with jobgraph found, please enable `build.jobgraph` policy first!\", r:name())\n            else\n                job = batchjobs:addjob(\"rule/\" .. r:name() .. \"/build\", function (index, total, opt)\n                    script(target, {progress = opt.progress})\n                end, {rootjob = job or rootjob})\n            end\n        else\n            local buildcmd = r:script(\"buildcmd\")\n            if buildcmd then\n                job = batchjobs:addjob(\"rule/\" .. r:name() .. \"/build\", function (index, total, opt)\n                    local batchcmds_ = batchcmds.new({target = target})\n                    buildcmd(target, batchcmds_, {progress = opt.progress})\n                    batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n                end, {rootjob = job or rootjob})\n            end\n        end\n    end\n\n    -- uses the builtin target script\n    if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object() or target:is_moduleonly()) then\n        job, job_leaf = import(\"kinds.\" .. target:kind(), {anonymous = true})(batchjobs, rootjob, target)\n    end\n    job = job or rootjob\n    return job, job_leaf or job\nend\n\n-- add batch jobs\nfunction _add_batchjobs(batchjobs, rootjob, target)\n\n    local job, job_leaf\n    local script = target:script(\"build\")\n    if not script then\n        -- do builtin batch jobs\n        job, job_leaf = _add_batchjobs_builtin(batchjobs, rootjob, target)\n    elseif target:extraconf(\"build\", \"batch\") then\n        -- do custom batch script\n        -- e.g.\n        -- target(\"test\")\n        --     on_build(function (target, batchjobs, opt)\n        --         return batchjobs:addjob(\"test\", function (idx, total)\n        --             print(\"build it\")\n        --         end, {rootjob = opt.rootjob})\n        --     end, {batch = true})\n        --\n        job, job_leaf = assert(script(target, batchjobs, {rootjob = rootjob}), \"target(%s):on_build(): no returned job!\", target:name())\n    else\n        -- do custom script directly\n        -- e.g.\n        --\n        -- target(\"test\")\n        --     on_build(function (target, opt)\n        --         print(\"build it\")\n        --     end)\n        --\n        job = batchjobs:addjob(target:name() .. \"/build\", function (index, total, opt)\n            script(target, {progress = opt.progress})\n        end, {rootjob = rootjob})\n    end\n    return job, job_leaf or job\nend\n\n-- add batch jobs for the given target\nfunction _add_batchjobs_for_target(batchjobs, rootjob, target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- add after_build job for target\n    local pkgenvs = _g.pkgenvs or {}\n    _g.pkgenvs = pkgenvs\n    local job_build_after = batchjobs:addjob(target:name() .. \"/after_build\", function (index, total, opt)\n\n        -- do after_build\n        local progress = opt.progress\n        local after_build = target:script(\"build_after\")\n        if after_build then\n            after_build(target, {progress = progress})\n        end\n        for _, r in ipairs(target:orderules()) do\n            local after_build = r:script(\"build_after\")\n            if after_build then\n                after_build(target, {progress = progress})\n            else\n                local after_buildcmd = r:script(\"buildcmd_after\")\n                if after_buildcmd then\n                    local batchcmds_ = batchcmds.new({target = target})\n                    after_buildcmd(target, batchcmds_, {progress = progress})\n                    batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n                end\n            end\n        end\n\n        -- restore environments\n        if target:pkgenvs() then\n            pkgenvs.oldenvs = pkgenvs.oldenvs or os.getenvs()\n            pkgenvs.newenvs = pkgenvs.newenvs or {}\n            pkgenvs.newenvs[target] = nil\n            local newenvs = pkgenvs.oldenvs\n            for _, envs in pairs(pkgenvs.newenvs) do\n                newenvs = os.joinenvs(envs, newenvs)\n            end\n            os.setenvs(newenvs)\n        end\n\n    end, {rootjob = rootjob})\n\n    -- add batch jobs for target, @note only on_build script support batch jobs\n    local job_build, job_build_leaf = _add_batchjobs(batchjobs, job_build_after, target)\n\n    -- add before_build job for target\n    local job_build_before = batchjobs:addjob(target:name() .. \"/before_build\", function (index, total, opt)\n\n        -- enter package environments\n        -- https://github.com/xmake-io/xmake/issues/4033\n        --\n        -- maybe mixing envs isn't a great solution,\n        -- but it's the most efficient compromise compared to setting envs in every on_build_file.\n        --\n        if target:pkgenvs() then\n            pkgenvs.oldenvs = pkgenvs.oldenvs or os.getenvs()\n            pkgenvs.newenvs = pkgenvs.newenvs or {}\n            pkgenvs.newenvs[target] = target:pkgenvs()\n            local newenvs = pkgenvs.oldenvs\n            for _, envs in pairs(pkgenvs.newenvs) do\n                newenvs = os.joinenvs(envs, newenvs)\n            end\n            os.setenvs(newenvs)\n        end\n\n        -- clean target if rebuild\n        if target:is_rebuilt() and not option.get(\"dry-run\") then\n            _clean_target(target)\n        end\n\n        -- do before_build\n        -- we cannot add batchjobs for this rule scripts, @see https://github.com/xmake-io/xmake/issues/2684\n        local progress = opt.progress\n        local before_build = target:script(\"build_before\")\n        if before_build then\n            before_build(target, {progress = progress})\n        end\n        for _, r in ipairs(target:orderules()) do\n            local before_build = r:script(\"build_before\")\n            if before_build then\n                before_build(target, {progress = progress})\n            else\n                local before_buildcmd = r:script(\"buildcmd_before\")\n                if before_buildcmd then\n                    local batchcmds_ = batchcmds.new({target = target})\n                    before_buildcmd(target, batchcmds_, {progress = progress})\n                    batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n                end\n            end\n        end\n    end, {rootjob = job_build_leaf})\n    return job_build_before, job_build, job_build_after\nend\n\n-- add batch jobs for the given target and deps\nfunction _add_batchjobs_for_target_and_deps(batchjobs, rootjob, target, jobrefs, jobrefs_before)\n    local targetjob_ref = jobrefs[target:name()]\n    if targetjob_ref then\n        batchjobs:add(targetjob_ref, rootjob)\n    else\n        local job_build_before, job_build, job_build_after = _add_batchjobs_for_target(batchjobs, rootjob, target)\n        if job_build_before and job_build and job_build_after then\n            jobrefs[target:name()] = job_build_after\n            jobrefs_before[target:name()] = job_build_before\n            for _, depname in ipairs(target:get(\"deps\")) do\n                local dep = project.target(depname, {namespace = target:namespace()})\n                local targetjob = job_build\n                -- @see https://github.com/xmake-io/xmake/discussions/2500\n                if dep:policy(\"build.across_targets_in_parallel\") == false then\n                    targetjob = job_build_before\n                end\n                _add_batchjobs_for_target_and_deps(batchjobs, targetjob, dep, jobrefs, jobrefs_before)\n            end\n        end\n    end\nend\n\n-- get batch jobs\nfunction _get_batchjobs(targets_root, opt)\n\n    -- generate batch jobs for default or all targets\n    local jobrefs = {}\n    local jobrefs_before = {}\n    local batchjobs = jobpool.new()\n    for _, target in ipairs(targets_root) do\n        _add_batchjobs_for_target_and_deps(batchjobs, batchjobs:rootjob(), target, jobrefs, jobrefs_before)\n    end\n\n    -- add fence jobs, @see https://github.com/xmake-io/xmake/issues/5003\n    for _, target in ipairs(project.ordertargets()) do\n        local target_job_before = jobrefs_before[target:name()]\n        if target_job_before then\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:policy(\"build.fence\") then\n                    local fence_job = jobrefs[dep:name()]\n                    if fence_job then\n                        batchjobs:add(fence_job, target_job_before)\n                    end\n                end\n            end\n        end\n    end\n\n    return batchjobs\nend\n\nfunction main(targets_root, opt)\n\n    -- enable distcc?\n    local distcc\n    if distcc_build_client.is_connected() then\n        distcc = distcc_build_client.singleton()\n    end\n\n    -- build all jobs\n    local batchjobs = _get_batchjobs(targets_root, opt)\n    if batchjobs and batchjobs:size() > 0 then\n        local curdir = os.curdir()\n        runjobs(\"build\", batchjobs, {on_exit = function (errors)\n            import(\"utils.progress\")\n            if errors then\n                progress.show_output(\"\")\n            end\n        end, comax = option.get(\"jobs\") or 1, curdir = curdir, distcc = distcc})\n        os.cd(curdir)\n    end\nend\n"
  },
  {
    "path": "xmake/actions/build/deprecated/build_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.async.jobpool\")\nimport(\"async.runjobs\")\nimport(\"kinds.object\")\n\n-- match source files\nfunction _match_sourcefiles(sourcefile, filepatterns)\n    for _, filepattern in ipairs(filepatterns) do\n        if sourcefile:match(filepattern.pattern) == sourcefile then\n            if filepattern.excludes then\n                if filepattern.rootdir and sourcefile:startswith(filepattern.rootdir) then\n                    sourcefile = sourcefile:sub(#filepattern.rootdir + 2)\n                end\n                for _, exclude in ipairs(filepattern.excludes) do\n                    if sourcefile:match(exclude) == sourcefile then\n                        return false\n                    end\n                end\n            end\n            return true\n        end\n    end\nend\n\n-- add batch jobs\nfunction _add_batchjobs(batchjobs, rootjob, target, filepatterns)\n    local newbatches = {}\n    local sourcecount = 0\n    for rulename, sourcebatch in pairs(target:sourcebatches()) do\n        local objectfiles = sourcebatch.objectfiles\n        local dependfiles = sourcebatch.dependfiles\n        local sourcekind  = sourcebatch.sourcekind\n        for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            if _match_sourcefiles(sourcefile, filepatterns) then\n                local newbatch = newbatches[rulename]\n                if not newbatch then\n                    newbatch             = {}\n                    newbatch.sourcekind  = sourcekind\n                    newbatch.rulename    = rulename\n                    newbatch.sourcefiles = {}\n                end\n                table.insert(newbatch.sourcefiles, sourcefile)\n                if objectfiles then\n                    newbatch.objectfiles = newbatch.objectfiles or {}\n                    table.insert(newbatch.objectfiles, objectfiles[idx])\n                end\n                if dependfiles then\n                    newbatch.dependfiles = newbatch.dependfiles or {}\n                    table.insert(newbatch.dependfiles, dependfiles[idx])\n                end\n                newbatches[rulename] = newbatch\n                sourcecount = sourcecount + 1\n            end\n        end\n    end\n    if sourcecount > 0 then\n        return object.add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, newbatches)\n    end\nend\n\n-- add batch jobs for the given target\nfunction _add_batchjobs_for_target(batchjobs, rootjob, target, filepatterns)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- add batch jobs for target\n    return _add_batchjobs(batchjobs, rootjob, target, filepatterns)\nend\n\n-- add batch jobs for the given target and deps\nfunction _add_batchjobs_for_target_and_deps(batchjobs, rootjob, jobrefs, target, filepatterns)\n    local targetjob_ref = jobrefs[target:name()]\n    if targetjob_ref then\n        batchjobs:add(targetjob_ref, rootjob)\n    else\n        local targetjob, targetjob_root = _add_batchjobs_for_target(batchjobs, rootjob, target, filepatterns)\n        if targetjob and targetjob_root then\n            jobrefs[target:name()] = targetjob_root\n            if not option.get(\"shallow\") then\n                for _, depname in ipairs(target:get(\"deps\")) do\n                    _add_batchjobs_for_target_and_deps(batchjobs, targetjob, jobrefs,\n                        project.target(depname, {namespace = target:namespace()}), filepatterns)\n                end\n            end\n        end\n    end\nend\n\n-- get batch jobs\nfunction _get_batchjobs(targets_root, opt)\n\n    -- convert all sourcefiles to lua pattern\n    local filepatterns = _get_file_patterns(opt.sourcefiles)\n\n    -- generate batch jobs for default or all targets\n    local jobrefs = {}\n    local batchjobs = jobpool.new()\n    for _, target in pairs(targets_root) do\n        _add_batchjobs_for_target_and_deps(batchjobs, batchjobs:rootjob(), jobrefs, target, filepatterns)\n    end\n    return batchjobs\nend\n\n-- convert all sourcefiles to lua pattern\nfunction _get_file_patterns(sourcefiles)\n    local patterns = {}\n    for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do\n\n        -- get the excludes\n        local pattern  = sourcefile:trim()\n        local excludes = pattern:match(\"|.*$\")\n        if excludes then excludes = excludes:split(\"|\", {plain = true}) end\n\n        -- translate excludes\n        if excludes then\n            local _excludes = {}\n            for _, exclude in ipairs(excludes) do\n                exclude = path.translate(exclude)\n                exclude = path.pattern(exclude)\n                table.insert(_excludes, exclude)\n            end\n            excludes = _excludes\n        end\n\n        -- translate path and remove some repeat separators\n        pattern = path.translate(pattern:gsub(\"|.*$\", \"\"))\n\n        -- remove \"./\" or '.\\\\' prefix\n        if pattern:sub(1, 2):find('%.[/\\\\]') then\n            pattern = pattern:sub(3)\n        end\n\n        -- get the root directory\n        local rootdir = pattern\n        local startpos = pattern:find(\"*\", 1, true)\n        if startpos then\n            rootdir = rootdir:sub(1, startpos - 1)\n        end\n        rootdir = path.directory(rootdir)\n\n        -- convert to lua path pattern\n        pattern = path.pattern(pattern)\n        table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir})\n    end\n    return patterns\nend\n\nfunction main(targets_root, opt)\n\n    -- build all jobs\n    local batchjobs = _get_batchjobs(targets_root, opt)\n    if batchjobs and batchjobs:size() > 0 then\n        local curdir = os.curdir()\n        runjobs(\"build_files\", batchjobs, {comax = option.get(\"jobs\") or 1, curdir = curdir})\n        os.cd(curdir)\n    else\n        wprint(\"%s not found!\", opt.sourcefiles)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/binary.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        binary.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.theme.theme\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"private.utils.batchcmds\")\nimport(\"object\", {alias = \"object_target\"})\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\n\n-- do link target\nfunction _do_link_target(target, opt)\n    local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target})\n    local linkflags = linkinst:linkflags({target = target})\n\n    -- need build this target?\n    local depfiles = target_buildutils.get_linkdepfiles(target)\n    local dryrun = option.get(\"dry-run\")\n    local depvalues = {linkinst:program(), linkflags}\n    depend.on_changed(function ()\n        local filename = target:filename()\n        if target:namespace() then\n            filename = target:namespace() .. \"::\" .. filename\n        end\n        progress.show(opt.progress, \"${color.build.target}linking.$(mode) %s\", filename)\n\n        local targetfile = target:targetfile()\n        local objectfiles = target:objectfiles()\n        local verbose = option.get(\"verbose\")\n        if verbose then\n            -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows\n            print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true}))\n        end\n\n        if not dryrun then\n            assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags}))\n        end\n    end, {dependfile = target:dependfile(),\n          lastmtime = os.mtime(target:targetfile()),\n          changed = target:is_rebuilt() or option.get(\"linkonly\"),\n          values = depvalues, files = depfiles, dryrun = dryrun})\nend\n\n-- on link the given target\nfunction _on_link_target(target, opt)\n\n    -- link target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_link = r:script(\"link\")\n        if on_link then\n            on_link(target, opt)\n            done = true\n        end\n        local on_linkcmd = r:script(\"linkcmd\")\n        if on_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            on_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do link\n    _do_link_target(target, opt)\nend\n\n-- link target\nfunction _link_target(target, opt)\n\n    -- do before link for target\n    local before_link = target:script(\"link_before\")\n    if before_link then\n        before_link(target, opt)\n    end\n\n    -- do before link for rules\n    for _, r in ipairs(target:orderules()) do\n        local before_link = r:script(\"link_before\")\n        if before_link then\n            before_link(target, opt)\n        end\n        local before_linkcmd = r:script(\"linkcmd_before\")\n        if before_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            before_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\n\n    -- on link\n    target:script(\"link\", _on_link_target)(target, opt)\n\n    -- do after link for target\n    local after_link = target:script(\"link_after\")\n    if after_link then\n        after_link(target, opt)\n    end\n\n    -- do after link for rules\n    for _, r in ipairs(target:orderules()) do\n        local after_link = r:script(\"link_after\")\n        if after_link then\n            after_link(target, opt)\n        end\n        local after_linkcmd = r:script(\"linkcmd_after\")\n        if after_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            after_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\nend\n\n-- add batch jobs for building binary target\nfunction main(batchjobs, rootjob, target)\n\n    -- add link job\n    local job_link = batchjobs:addjob(target:name() .. \"/link\", function (index, total, opt)\n        _link_target(target, {progress = opt.progress})\n    end, {rootjob = rootjob})\n\n    -- we only need to return and depend the link job for each target,\n    -- so we can compile the source files for each target in parallel\n    --\n    -- unless call set_policy(\"build.across_targets_in_parallel\", false) to disable to build across targets in parallel.\n    --\n    local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target)\n    return target:policy(\"build.across_targets_in_parallel\") == false and job_objects or job_link, job_objects\nend\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/moduleonly.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        moduleonly.lua\n--\n\n-- imports\ninherit(\"object\")\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/object.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        object.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"async.runjobs\")\nimport(\"private.utils.batchcmds\")\nimport(\"rule_groups\")\n\n-- has scripts for the custom rule\nfunction _has_scripts_for_rule(ruleinst, suffix)\n\n    -- add batch jobs for xx_build_files\n    local scriptname = \"build_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n    local script = ruleinst:script(scriptname)\n    if script then\n        return true\n    end\n\n    -- add batch jobs for xx_build_file\n    scriptname = \"build_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n    script = ruleinst:script(scriptname)\n    if script then\n        return true\n    end\n\n    -- add batch jobs for xx_buildcmd_files\n    scriptname = \"buildcmd_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n    script = ruleinst:script(scriptname)\n    if script then\n        return true\n    end\n\n    -- add batch jobs for xx_buildcmd_file\n    scriptname = \"buildcmd_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n    script = ruleinst:script(scriptname)\n    if script then\n        return true\n    end\nend\n\n-- has scripts for target\nfunction _has_scripts_for_target(target, suffix)\n    local scriptname = \"build_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n    local script = target:script(scriptname)\n    if script then\n        return true\n    else\n        scriptname = \"build_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n        script = target:script(scriptname)\n        if script then\n            return true\n        end\n    end\nend\n\n-- has scripts for group\nfunction _has_scripts_for_group(group, suffix)\n    for _, item in pairs(group) do\n        if item.target and _has_scripts_for_target(item.target, suffix) then\n            return true\n        end\n        if item.rule and _has_scripts_for_rule(item.rule, suffix) then\n            return true\n        end\n    end\nend\n\n-- add batch jobs for the custom rule\nfunction _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix)\n\n    -- get rule\n    local rulename = assert(sourcebatch.rulename, \"unknown rule for sourcebatch!\")\n    local ruleinst = rule_groups.get_rule(target, rulename)\n\n    -- add batch jobs for xx_build_files\n    local scriptname = \"build_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n    local script = ruleinst:script(scriptname)\n    if script then\n        if ruleinst:extraconf(scriptname, \"batch\") then\n            script(target, batchjobs, sourcebatch, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, \"distcc\")})\n        else\n            batchjobs:addjob(\"rule/\" .. rulename .. \"/\" .. scriptname, function (index, total, opt)\n                script(target, sourcebatch, {progress = opt.progress})\n            end, {rootjob = rootjob})\n        end\n    end\n\n    -- add batch jobs for xx_build_file\n    if not script then\n        scriptname = \"build_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n        script = ruleinst:script(scriptname)\n        if script then\n            local sourcekind = sourcebatch.sourcekind\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                batchjobs:addjob(sourcefile, function (index, total, opt)\n                    script(target, sourcefile, {sourcekind = sourcekind, progress = opt.progress})\n                end, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, \"distcc\")})\n            end\n        end\n    end\n\n    -- add batch jobs for xx_buildcmd_files\n    if not script then\n        scriptname = \"buildcmd_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n        script = ruleinst:script(scriptname)\n        if script then\n            batchjobs:addjob(\"rule/\" .. rulename .. \"/\" .. scriptname, function (index, total, opt)\n                local batchcmds_ = batchcmds.new({target = target})\n                local distcc = ruleinst:extraconf(scriptname, \"distcc\")\n                script(target, batchcmds_, sourcebatch, {progress = opt.progress, distcc = distcc})\n                batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n            end, {rootjob = rootjob})\n        end\n    end\n\n    -- add batch jobs for xx_buildcmd_file\n    if not script then\n        scriptname = \"buildcmd_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n        script = ruleinst:script(scriptname)\n        if script then\n            local sourcekind = sourcebatch.sourcekind\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                batchjobs:addjob(sourcefile, function (index, total, opt)\n                    local batchcmds_ = batchcmds.new({target = target})\n                    script(target, batchcmds_, sourcefile, {sourcekind = sourcekind, progress = opt.progress})\n                    batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n                end, {rootjob = rootjob, distcc = ruleinst:extraconf(scriptname, \"distcc\")})\n            end\n        end\n    end\nend\n\n-- add batch jobs for target\nfunction _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suffix)\n\n    -- we just build sourcebatch with on_build_files scripts\n    --\n    -- for example, c++.build and c++.build.modules.builder rules have same sourcefiles,\n    -- but we just build it for c++.build\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/3171\n    --\n    local rulename = sourcebatch.rulename\n    if rulename then\n        local ruleinst = rule_groups.get_rule(target, rulename)\n        if not ruleinst:script(\"build_file\") and\n            not ruleinst:script(\"build_files\") then\n            return\n        end\n    end\n\n    -- add batch jobs\n    local scriptname = \"build_files\" .. (suffix and (\"_\" .. suffix) or \"\")\n    local script = target:script(scriptname)\n    if script then\n        if target:extraconf(scriptname, \"batch\") then\n            script(target, batchjobs, sourcebatch, {rootjob = rootjob, distcc = target:extraconf(scriptname, \"distcc\")})\n        else\n            batchjobs:addjob(target:name() .. \"/\" .. scriptname, function (index, total, opt)\n                script(target, sourcebatch, {progress = opt.progress})\n            end, {rootjob = rootjob})\n        end\n        return true\n    else\n        scriptname = \"build_file\" .. (suffix and (\"_\" .. suffix) or \"\")\n        script = target:script(scriptname)\n        if script then\n            local sourcekind = sourcebatch.sourcekind\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                batchjobs:addjob(sourcefile, function (index, total, opt)\n                    script(target, sourcefile, {sourcekind = sourcekind, progress = opt.progress})\n                end, {rootjob = rootjob, distcc = target:extraconf(scriptname, \"distcc\")})\n            end\n            return true\n        end\n    end\nend\n\n-- add batch jobs for group\nfunction _add_batchjobs_for_group(batchjobs, rootjob, target, group, suffix)\n    for _, item in pairs(group) do\n        local sourcebatch = item.sourcebatch\n        if item.target then\n            _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suffix)\n        end\n        -- override on_xxx script in target? we need to ignore rule scripts\n        if item.rule and (suffix or not _has_scripts_for_target(target, suffix)) then\n            _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix)\n        end\n    end\nend\n\n-- add batch jobs for building source files\nfunction add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, sourcebatches)\n\n    -- build sourcebatch groups first\n    local groups = rule_groups.build_sourcebatch_groups(target, sourcebatches)\n\n    -- add batch jobs for build_after\n    local groups_root\n    local groups_leaf = rootjob\n    for idx, group in ipairs(groups) do\n        if _has_scripts_for_group(group, \"after\") then\n            batchjobs:group_enter(target:name() .. \"/after_build_files\" .. idx)\n            _add_batchjobs_for_group(batchjobs, groups_leaf, target, group, \"after\")\n            groups_leaf = batchjobs:group_leave() or groups_leaf\n            groups_root = groups_root or groups_leaf\n        end\n    end\n\n    -- add batch jobs for build\n    for idx, group in ipairs(groups) do\n        if _has_scripts_for_group(group) then\n            batchjobs:group_enter(target:name() .. \"/build_files\" .. idx)\n            _add_batchjobs_for_group(batchjobs, groups_leaf, target, group)\n            groups_leaf = batchjobs:group_leave() or groups_leaf\n            groups_root = groups_root or groups_leaf\n        end\n    end\n\n    -- add batch jobs for build_before\n    for idx, group in ipairs(groups) do\n        if _has_scripts_for_group(group, \"before\") then\n            batchjobs:group_enter(target:name() .. \"/before_build_files\" .. idx)\n            _add_batchjobs_for_group(batchjobs, groups_leaf, target, group, \"before\")\n            groups_leaf = batchjobs:group_leave() or groups_leaf\n            groups_root = groups_root or groups_leaf\n        end\n    end\n    return groups_leaf, groups_root or groups_leaf\nend\n\n-- add batch jobs for building object files\nfunction add_batchjobs_for_object(batchjobs, rootjob, target)\n    return add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, target:sourcebatches())\nend\n\n-- add batch jobs for building object target\nfunction main(batchjobs, rootjob, target)\n\n    -- add a fake link job\n    local job_link = batchjobs:addjob(target:name() .. \"/fakelink\", function (index, total, opt)\n    end, {rootjob = rootjob})\n\n    -- we only need to return and depend the link job for each target,\n    -- so we can compile the source files for each target in parallel\n    --\n    -- unless call set_policy(\"build.across_targets_in_parallel\", false) to disable to build across targets in parallel.\n    --\n    local job_objects = add_batchjobs_for_object(batchjobs, job_link, target)\n    return target:policy(\"build.across_targets_in_parallel\") == false and job_objects or job_link, job_objects\nend\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/rule_groups.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rule_groups.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\n-- get rule\n-- @note we need to get rule from target first, because we maybe will inject and replace builtin rule in target\nfunction get_rule(target, rulename)\n    local ruleinst = assert(target:rule(rulename) or project.rule(rulename, {namespace = target:namespace()}) or\n        rule.rule(rulename), \"unknown rule: %s\", rulename)\n    return ruleinst\nend\n\n-- get max depth of rule\nfunction _get_rule_max_depth(target, ruleinst, depth)\n    local max_depth = depth\n    for _, depname in ipairs(ruleinst:get(\"deps\")) do\n        local dep = get_rule(target, depname)\n        local dep_depth = depth\n        if ruleinst:extraconf(\"deps\", depname, \"order\") then\n            dep_depth = dep_depth + 1\n        end\n        local cur_depth = _get_rule_max_depth(target, dep, dep_depth)\n        if cur_depth > max_depth then\n            max_depth = cur_depth\n        end\n    end\n    return max_depth\nend\n\n-- build sourcebatch groups for target\nfunction _build_sourcebatch_groups_for_target(groups, target, sourcebatches)\n    local group = groups[1]\n    for _, sourcebatch in pairs(sourcebatches) do\n        local rulename = assert(sourcebatch.rulename, \"unknown rule for sourcebatch!\")\n        local item = group[rulename] or {}\n        item.target = target\n        item.sourcebatch = sourcebatch\n        group[rulename] = item\n    end\nend\n\n-- build sourcebatch groups for rules\nfunction _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)\n    for _, sourcebatch in pairs(sourcebatches) do\n        local rulename = assert(sourcebatch.rulename, \"unknown rule for sourcebatch!\")\n        local ruleinst = get_rule(target, rulename)\n        local depth = _get_rule_max_depth(target, ruleinst, 1)\n        local group = groups[depth]\n        if group == nil then\n            group = {}\n            groups[depth] = group\n        end\n        local item = group[rulename] or {}\n        item.rule = ruleinst\n        item.sourcebatch = sourcebatch\n        group[rulename] = item\n    end\nend\n\n-- build sourcebatch groups by rule dependencies order, e.g. `add_deps(\"qt.ui\", {order = true})`\n--\n-- @see https://github.com/xmake-io/xmake/issues/2814\n--\nfunction build_sourcebatch_groups(target, sourcebatches)\n    local groups = {{}}\n    _build_sourcebatch_groups_for_target(groups, target, sourcebatches)\n    _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)\n    if #groups > 0 then\n        groups = table.reverse(groups)\n    end\n    return groups\nend\n\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/shared.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        shared.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.theme.theme\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"private.utils.batchcmds\")\nimport(\"object\", {alias = \"object_target\"})\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\n\n-- do link target\nfunction _do_link_target(target, opt)\n    local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target})\n    local linkflags = linkinst:linkflags({target = target})\n\n    -- need build this target?\n    local depfiles = target_buildutils.get_linkdepfiles(target)\n    local dryrun = option.get(\"dry-run\")\n    local depvalues = {linkinst:program(), linkflags}\n    depend.on_changed(function ()\n        local filename = target:filename()\n        if target:namespace() then\n            filename = target:namespace() .. \"::\" .. filename\n        end\n        progress.show(opt.progress, \"${color.build.target}linking.$(mode) %s\", filename)\n\n        local targetfile = target:targetfile()\n        local objectfiles = target:objectfiles()\n        local verbose = option.get(\"verbose\")\n        if verbose then\n            -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows\n            print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true}))\n        end\n\n        if not dryrun then\n            assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags}))\n        end\n\n    end, {dependfile = target:dependfile(),\n          lastmtime = os.mtime(target:targetfile()),\n          changed = target:is_rebuilt() or option.get(\"linkonly\"),\n          values = depvalues, files = depfiles, dryrun = dryrun})\nend\n\n-- on link the given target\nfunction _on_link_target(target, opt)\n\n    -- link target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_link = r:script(\"link\")\n        if on_link then\n            on_link(target, opt)\n            done = true\n        end\n        local on_linkcmd = r:script(\"linkcmd\")\n        if on_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            on_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do link\n    _do_link_target(target, opt)\nend\n\n-- link target\nfunction _link_target(target, opt)\n\n    -- do before link for target\n    local before_link = target:script(\"link_before\")\n    if before_link then\n        before_link(target, opt)\n    end\n\n    -- do before link for rules\n    for _, r in ipairs(target:orderules()) do\n        local before_link = r:script(\"link_before\")\n        if before_link then\n            before_link(target, opt)\n        end\n        local before_linkcmd = r:script(\"linkcmd_before\")\n        if before_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            before_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\n\n    -- on link\n    target:script(\"link\", _on_link_target)(target, opt)\n\n    -- do after link for target\n    local after_link = target:script(\"link_after\")\n    if after_link then\n        after_link(target, opt)\n    end\n\n    -- do after link for rules\n    for _, r in ipairs(target:orderules()) do\n        local after_link = r:script(\"link_after\")\n        if after_link then\n            after_link(target, opt)\n        end\n        local after_linkcmd = r:script(\"linkcmd_after\")\n        if after_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            after_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\nend\n\n-- add batch jobs for building shared target\nfunction main(batchjobs, rootjob, target)\n\n    -- add link job\n    local job_link = batchjobs:addjob(target:name() .. \"/link\", function (index, total, opt)\n        _link_target(target, {progress = opt.progress})\n    end, {rootjob = rootjob})\n\n    -- we only need to return and depend the link job for each target,\n    -- so we can compile the source files for each target in parallel\n    --\n    -- unless call set_policy(\"build.across_targets_in_parallel\", false) to disable to build across targets in parallel.\n    --\n    local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target)\n    return target:policy(\"build.across_targets_in_parallel\") == false and job_objects or job_link, job_objects\nend\n"
  },
  {
    "path": "xmake/actions/build/deprecated/kinds/static.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        static.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.theme.theme\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"private.utils.batchcmds\")\nimport(\"object\", {alias = \"object_target\"})\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\n\n-- do link target\nfunction _do_link_target(target, opt)\n    local linkinst = linker.load(target:kind(), target:sourcekinds(), {target = target})\n    local linkflags = linkinst:linkflags({target = target})\n\n    -- need build this target?\n    local depfiles = target_buildutils.get_linkdepfiles(target)\n    local dryrun = option.get(\"dry-run\")\n    local depvalues = {linkinst:program(), linkflags}\n    depend.on_changed(function ()\n        local filename = target:filename()\n        if target:namespace() then\n            filename = target:namespace() .. \"::\" .. filename\n        end\n        progress.show(opt.progress, \"${color.build.target}archiving.$(mode) %s\", filename)\n\n        local targetfile = target:targetfile()\n        local objectfiles = target:objectfiles()\n        local verbose = option.get(\"verbose\")\n        if verbose then\n            -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows\n            print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true}))\n        end\n\n        if not dryrun then\n            assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags}))\n        end\n\n    end, {dependfile = target:dependfile(),\n          lastmtime = os.mtime(target:targetfile()),\n          changed = target:is_rebuilt() or option.get(\"linkonly\"),\n          values = depvalues, files = depfiles, dryrun = dryrun})\nend\n\n-- on link the given target\nfunction _on_link_target(target, opt)\n\n    -- link target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_link = r:script(\"link\")\n        if on_link then\n            on_link(target, opt)\n            done = true\n        end\n        local on_linkcmd = r:script(\"linkcmd\")\n        if on_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            on_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do link\n    _do_link_target(target, opt)\nend\n\n-- link target\nfunction _link_target(target, opt)\n\n    -- do before link for target\n    local before_link = target:script(\"link_before\")\n    if before_link then\n        before_link(target, opt)\n    end\n\n    -- do before link for rules\n    for _, r in ipairs(target:orderules()) do\n        local before_link = r:script(\"link_before\")\n        if before_link then\n            before_link(target, opt)\n        end\n        local before_linkcmd = r:script(\"linkcmd_before\")\n        if before_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            before_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\n\n    -- on link\n    target:script(\"link\", _on_link_target)(target, opt)\n\n    -- do after link for target\n    local after_link = target:script(\"link_after\")\n    if after_link then\n        after_link(target, opt)\n    end\n\n    -- do after link for rules\n    for _, r in ipairs(target:orderules()) do\n        local after_link = r:script(\"link_after\")\n        if after_link then\n            after_link(target, opt)\n        end\n        local after_linkcmd = r:script(\"linkcmd_after\")\n        if after_linkcmd then\n            local batchcmds_ = batchcmds.new({target = target})\n            after_linkcmd(target, batchcmds_, {progress = opt.progress})\n            batchcmds_:runcmds({changed = target:is_rebuilt(), dryrun = option.get(\"dry-run\")})\n        end\n    end\nend\n\n-- add batch jobs for building static target\nfunction main(batchjobs, rootjob, target)\n\n    -- add link job\n    local job_link = batchjobs:addjob(target:name() .. \"/link\", function (index, total, opt)\n        _link_target(target, {progress = opt.progress})\n    end, {rootjob = rootjob})\n\n    -- we only need to return and depend the link job for each target,\n    -- so we can compile the source files for each target in parallel\n    --\n    -- unless call set_policy(\"build.across_targets_in_parallel\", false) to disable to build across targets in parallel.\n    --\n    local job_objects = object_target.add_batchjobs_for_object(batchjobs, job_link, target)\n    return target:policy(\"build.across_targets_in_parallel\") == false and job_objects or job_link, job_objects\nend\n"
  },
  {
    "path": "xmake/actions/build/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.task\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.detectcache\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.theme.theme\")\nimport(\"utils.progress\")\nimport(\"build\")\nimport(\"build_files\")\nimport(\"cleaner\")\nimport(\"check\", {alias = \"check_targets\"})\nimport(\"private.cache.build_cache\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"private.utils.statistics\")\nimport(\"private.action.utils\", {alias = \"action_utils\"})\nimport(\"private.detect.check_targetname\")\n\n-- try building it\nfunction _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname)\n    if configfile and tool and (trybuild or utils.confirm({default = true,\n            description = \"${bright}\" .. path.filename(configfile) .. \"${clear} found, try building it or you can run `${bright}xmake f --trybuild=${clear}` to set buildsystem\"})) then\n        if not trybuild then\n            task.run(\"config\", {trybuild = trybuild_detected})\n        end\n        tool.build()\n        return true\n    end\nend\n\n-- do build for the third-party buildsystem\nfunction _try_build()\n\n    -- load config\n    config.load()\n\n    -- rebuild it? do clean first\n    local targetname = option.get(\"target\")\n    if option.get(\"rebuild\") then\n        task.run(\"clean\", {target = targetname})\n    end\n\n    -- get the buildsystem tool\n    local configfile = nil\n    local tool = nil\n    local trybuild = config.get(\"trybuild\")\n    local trybuild_detected = nil\n    if trybuild then\n        tool = import(\"private.action.trybuild.\" .. trybuild, {try = true, anonymous = true})\n        if tool then\n            configfile = tool.detect()\n        else\n            raise(\"unknown build tool: %s\", trybuild)\n        end\n        return _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname)\n    else\n        for _, name in ipairs({\"xrepo\", \"autoconf\", \"cmake\", \"meson\", \"scons\", \"bazel\", \"msbuild\", \"xcodebuild\", \"make\", \"ninja\", \"ndkbuild\"}) do\n            tool = import(\"private.action.trybuild.\" .. name, {anonymous = true})\n            configfile = tool.detect()\n            if configfile then\n                trybuild_detected = name\n                if _do_try_build(configfile, tool, trybuild, trybuild_detected, targetname) then\n                    return true\n                end\n            end\n        end\n    end\nend\n\n-- do global project rules\nfunction _do_project_rules(scriptname, opt)\n    for _, rulename in ipairs(project.get(\"target.rules\")) do\n        local r = project.rule(rulename) or rule.rule(rulename)\n        if r and r:kind() == \"project\" then\n            local buildscript = r:script(scriptname)\n            if buildscript then\n                buildscript(opt)\n            end\n        end\n    end\nend\n\n-- do build\nfunction _do_build(targetname, opt)\n    local sourcefiles = option.get(\"files\")\n    if sourcefiles then\n        build_files(targetname, {group_pattern = opt.group_pattern, sourcefiles = sourcefiles})\n    else\n        build(targetname, {group_pattern = opt.group_pattern})\n    end\nend\n\n-- build targets\nfunction build_targets(targetnames, opt)\n    opt = opt or {}\n    try\n    {\n        function ()\n\n            -- do rules before building\n            _do_project_rules(\"build_before\")\n\n            -- do build\n            _do_build(targetnames, opt)\n\n            -- do check\n            check_targets(targetnames, {build = true})\n\n            -- save toolchain configs\n            toolchain.save()\n\n            -- save detect cache\n            detectcache:save()\n\n            -- dump cache stats\n            if option.get(\"diagnosis\") then\n                build_cache.dump_stats()\n            end\n        end,\n        catch\n        {\n            function (errors)\n\n                -- @see https://github.com/xmake-io/xmake/issues/3401\n                check_targets(targetnames, {build_failure = true})\n\n                -- do rules after building\n                _do_project_rules(\"build_after\", {errors = errors})\n\n                -- save toolchain configs\n                toolchain.save()\n\n                -- save detect cache\n                detectcache:save()\n\n                -- raise\n                if errors then\n                    raise(errors)\n                elseif opt.group_pattern then\n                    raise(\"build targets with group(%s) failed!\", opt.group_pattern)\n                elseif targetnames then\n                    targetnames = table.wrap(targetnames)\n                    raise(\"build target: %s failed!\", table.concat(targetnames, \", \"))\n                else\n                    raise(\"build target failed!\")\n                end\n            end\n        }\n    }\n\n    -- do rules after building\n    _do_project_rules(\"build_after\")\nend\n\nfunction main(opt)\n    opt = opt or {}\n\n    -- try building it using third-party buildsystem if xmake.lua not exists\n    if not os.isfile(project.rootfile()) and _try_build() then\n        return\n    end\n\n    -- post statistics before locking project\n    statistics.post()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- lock the whole project\n    project.lock()\n\n    -- config it first\n    local targetname, group_pattern = action_utils.get_target_and_group()\n    task.run(\"config\", {}, {disable_dump = true})\n\n    -- check target name\n    if targetname then\n        assert(check_targetname(targetname))\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- clean up temporary files once a day\n    cleaner.cleanup()\n\n    -- build targets\n    local build_time = os.mclock()\n    build_targets(targetname, {group_pattern = group_pattern})\n    build_time = os.mclock() - build_time\n\n    -- leave project directory\n    os.cd(oldir)\n\n    -- unlock the whole project\n    project.unlock()\n\n    -- trace\n    if not opt.disable_dump then\n        local str = \"\"\n        if build_time then\n            str = string.format(\", spent %ss\", build_time / 1000)\n        end\n        progress.show(100, \"${color.success}build ok%s\", str)\n    end\nend\n"
  },
  {
    "path": "xmake/actions/build/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"build\")\n    set_category(\"main\")\n    on_run(\"main\")\n    set_menu {\n                usage = \"xmake [task] [options] [target]\"\n            ,   description = \"Build targets if no given tasks.\"\n            ,   shortname = 'b'\n            ,   options =\n                {\n                    {nil, \"version\",    \"k\",  nil   , \"Print the version number and exit.\"                            }\n                ,   {'b', \"build\",      \"k\",  nil   , \"Build target. This is default building mode and optional.\"     }\n                ,   {'r', \"rebuild\",    \"k\",  nil   , \"Rebuild the target.\"                                           }\n                ,   {'a', \"all\",        \"k\",  nil   , \"Build all targets.\"                                            }\n                ,   {nil, \"shallow\",    \"k\",  nil   , \"Only re-build the given targets without dependencies.\"         }\n                ,   {'g', \"group\",      \"kv\", nil   , \"Build all targets of the given group. It support path pattern matching.\",\n                                                      \"e.g.\",\n                                                      \"    xmake -g test\",\n                                                      \"    xmake -g test_*\",\n                                                      \"    xmake --group=benchmark/*\"                                 }\n                ,   {nil, \"dry-run\",    \"k\",  nil   , \"Dry run to build target.\"                                      }\n\n                ,   {}\n                ,   {'j', \"jobs\",       \"kv\", tostring(os.default_njob()),\n                                                      \"Set the number of parallel compilation jobs.\"                  }\n                ,   {nil, \"linkjobs\",   \"kv\", nil,    \"Set the number of parallel link jobs.\"                         }\n                ,   {'w', \"warning\",    \"k\",  false , \"Enable the warnings output. (deprecated)\"                      }\n                ,   {nil, \"linkonly\",   \"k\",  false , \"Only link targets if object files have been compiled.\"         }\n                ,   {nil, \"files\",      \"kv\", nil   , \"Build the given source files.\",\n                                                      \"e.g. \",\n                                                      \"    - xmake --files=src/main.c\",\n                                                      \"    - xmake --files='src/*.c' [target]\",\n                                                      \"    - xmake --files='src/**.c|excluded_file.c'\",\n                                                      \"    - xmake --files='src/main.c\" .. path.envsep() .. \"src/test.c'\"  }\n\n                ,   {}\n                ,   {nil, \"target\",     \"v\",  nil   , \"The target name. It will build all default targets if this parameter is not specified.\"\n                                                    , values = function (complete, opt) return import(\"private.utils.complete_helper.targets\")(complete, opt) end }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/actions/clean/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.base.global\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"private.action.clean.remove_files\")\nimport(\"target.action.clean\", {alias = \"_do_clean_target\"})\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"private.detect.check_targetname\")\n\n-- on clean target\nfunction _on_clean_target(target)\n\n    -- build target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_clean = r:script(\"clean\")\n        if on_clean then\n            on_clean(target)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do clean\n    _do_clean_target(target)\nend\n\n-- clean the given target files\nfunction _clean_target(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"clean_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_clean = r:script(\"clean_before\")\n                if before_clean then\n                    before_clean(target)\n                end\n            end\n        end\n    ,   target:script(\"clean\", _on_clean_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_clean = r:script(\"clean_after\")\n                if after_clean then\n                    after_clean(target)\n                end\n            end\n        end\n    ,   target:script(\"clean_after\")\n    }\n\n    -- run the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\nend\n\n-- clean the given targets\nfunction _clean_targets(targets)\n    for _, target in ipairs(targets) do\n        _clean_target(target)\n    end\nend\n\n-- clean target\nfunction _clean(targetname)\n    if targetname then\n        local target = assert(check_targetname(targetname))\n        _clean_target(target)\n    else\n        _clean_targets(project.ordertargets())\n    end\nend\n\n-- clean configuration cache\nfunction _clean_configs()\n    if option.get(\"all\") then\n        -- we need to close it first after removing file lock\n        project.filelock():close()\n        remove_files(config.directory())\n    end\nend\n\n-- do clean for the third-party buildsystem\nfunction _try_clean()\n\n    -- load config\n    config.load()\n\n    -- get the buildsystem tool\n    local configfile = nil\n    local tool = nil\n    local trybuild = config.get(\"trybuild\")\n    if trybuild then\n        tool = import(\"private.action.trybuild.\" .. trybuild, {try = true, anonymous = true})\n        if tool then\n            configfile = tool.detect()\n        end\n    end\n\n    -- try cleaning it\n    if configfile and tool and trybuild then\n        tool.clean()\n    end\nend\n\nfunction main()\n\n    -- try cleaning it using third-party buildsystem if xmake.lua not exists\n    if not os.isfile(project.rootfile()) then\n        return _try_clean()\n    end\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load config first\n    task.run(\"config\", {require = false}, {disable_dump = true})\n\n    -- lock the whole project\n    project.lock()\n\n    -- get the target name\n    local targetname = option.get(\"target\")\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- clean target\n    _clean(targetname)\n\n    -- unlock the whole project\n    project.unlock()\n\n    -- we must call it after unlocking project because it will remove project lockfile\n    _clean_configs()\n\n    -- leave project directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/actions/clean/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"clean\")\n    set_category(\"action\")\n    on_run(\"main\")\n\n    set_menu {\n                usage = \"xmake clean|c [options] [target]\"\n            ,   description = \"Remove all binary and temporary files.\"\n            ,   shortname = 'c'\n\n            ,   options =\n                {\n                    {'a', \"all\",        \"k\",  nil   , \"Clean all auto-generated files by xmake.\"                      }\n\n                ,   {}\n                ,   {nil, \"target\",     \"v\",  nil   , \"The target name. It will clean all default targets if this parameter is not specified.\"\n                                                    , values = function (complete, opt) return import(\"private.utils.complete_helper.targets\")(complete, opt) end }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/actions/config/configfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configfiles.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_tool\")\n\n-- get all configuration files\nfunction _get_configfiles()\n    local configfiles = {}\n    for _, target in table.orderpairs(project.targets()) do\n        if target:is_enabled() then\n\n            -- get configuration files for target\n            local srcfiles, dstfiles, fileinfos = target:configfiles()\n            for idx, srcfile in ipairs(srcfiles) do\n\n                -- get destinate file and file info\n                local dstfile  = dstfiles[idx]\n                local fileinfo = fileinfos[idx]\n\n                -- get source info\n                local srcinfo = configfiles[dstfile]\n                if not srcinfo then\n                    srcinfo = {}\n                    configfiles[dstfile] = srcinfo\n                end\n\n                -- save source file\n                if srcinfo.srcfile then\n                    assert(path.absolute(srcinfo.srcfile) == path.absolute(srcfile), \"file(%s) and file(%s) are writing a same file(%s)\", srcfile, srcinfo.srcfile, dstfile)\n                else\n                    srcinfo.srcfile  = srcfile\n                    srcinfo.fileinfo = fileinfo\n                end\n\n                -- we use first target to get dependfile path\n                -- @see https://github.com/xmake-io/xmake/issues/3321\n                if not srcinfo.dependfile then\n                    srcinfo.dependfile = target:dependfile(srcfile)\n                end\n\n                -- always update?\n                local always_update = target:policy(\"build.always_update_configfiles\")\n                if always_update == nil then\n                    always_update = project.policy(\"build.always_update_configfiles\")\n                end\n                srcinfo.always_update = always_update\n\n                -- save targets\n                srcinfo.targets = srcinfo.targets or {}\n                table.insert(srcinfo.targets, target)\n\n                -- save preprocessors\n                local preprocessor = fileinfo and fileinfo.preprocessor\n                if preprocessor then\n                    srcinfo.preprocessors = srcinfo.preprocessors or {}\n                    table.insert(srcinfo.preprocessors, preprocessor)\n                end\n            end\n        end\n    end\n    return configfiles\nend\n\n-- get the builtin variables\nfunction _get_builtinvars_target(target)\n\n    -- get version variables\n    local builtinvars = {}\n    local version, version_build = target:version()\n    if version then\n        builtinvars.VERSION = version\n        try {function ()\n            local v = semver.new(version)\n            if v then\n                builtinvars.VERSION_MAJOR = v:major()\n                builtinvars.VERSION_MINOR = v:minor()\n                builtinvars.VERSION_ALTER = v:patch()\n            end\n        end}\n        if version_build then\n            builtinvars.VERSION_BUILD = version_build\n        end\n    end\n    return builtinvars\nend\n\n-- get the git builtin variables\nfunction _get_builtinvars_git(builtinvars)\n    local cmds =\n    {\n        GIT_TAG         = {\"describe\", \"--tags\"},\n        GIT_TAG_LONG    = {\"describe\", \"--tags\", \"--long\"},\n        GIT_BRANCH      = {\"rev-parse\", \"--abbrev-ref\", \"HEAD\"},\n        GIT_COMMIT      = {\"rev-parse\", \"--short\", \"HEAD\"},\n        GIT_COMMIT_LONG = {\"rev-parse\", \"HEAD\"},\n        GIT_COMMIT_DATE = {\"log\", \"-1\", \"--date=format:%Y%m%d%H%M%S\", \"--format=%ad\"}\n    }\n    for name, argv in pairs(cmds) do\n        builtinvars[name] = function ()\n            local result\n            local git = find_tool(\"git\")\n            if git then\n                result = try {function ()\n                    return os.iorunv(git.program, argv)\n                end}\n            end\n            if not result then\n                result = \"none\"\n            end\n            return result:trim()\n        end\n    end\nend\n\n-- get the global builtin variables\nfunction _get_builtinvars_global()\n    local builtinvars = _g.builtinvars_global\n    if builtinvars == nil then\n        builtinvars =\n        {\n            arch  = config.get(\"arch\") or os.arch()\n        ,   plat  = config.get(\"plat\") or os.host()\n        ,   host  = os.host()\n        ,   mode  = config.get(\"mode\") or \"release\"\n        ,   debug = is_mode(\"debug\") and 1 or 0\n        ,   os    = platform.os()\n        }\n        local builtinvars_upper = {}\n        for name, value in pairs(builtinvars) do\n            builtinvars_upper[name:upper()] = type(value) == \"string\" and value:upper() or value\n        end\n        table.join2(builtinvars, builtinvars_upper)\n        _get_builtinvars_git(builtinvars)\n        _g.builtinvars_global = builtinvars\n    end\n    return builtinvars\nend\n\nfunction _preprocess_define_value(name, value, opt)\n    opt = opt or {}\n    local extraconf = opt.extraconf\n    if value == nil then\n        value = (\"/* #undef %s */\"):format(name)\n    elseif type(value) == \"boolean\" then\n        if value then\n            value = (\"#define %s 1\"):format(name)\n        else\n            value = (\"/* #define %s 0 */\"):format(name)\n        end\n    elseif type(value) == \"number\" then\n        value = (\"#define %s %d\"):format(name, value)\n    elseif type(value) == \"string\" then\n        local quote = true\n        local escape = false\n        if extraconf then\n            -- disable to wrap quote, @see https://github.com/xmake-io/xmake/issues/1694\n            if extraconf.quote == false then\n                quote = false\n            end\n            -- escape path seperator when with quote, @see https://github.com/xmake-io/xmake/issues/1872\n            if quote and extraconf.escape then\n                escape = true\n            end\n        end\n        if quote then\n            if escape then\n                value = value:gsub(\"\\\\\", \"\\\\\\\\\")\n            end\n            value = (\"#define %s \\\"%s\\\"\"):format(name, value)\n        else\n            value = (\"#define %s %s\"):format(name, value)\n        end\n    else\n        raise(\"unknown variable(%s) type: %s\", name, type(value))\n    end\n    return value\nend\n\nfunction _preprocess_default_value(name, value, opt)\n    opt = opt or {}\n    local default = table.unpack(opt.argv or {})\n    assert(default ~= nil, \"please set default value for variable(%s)\", variable)\n\n    if value == nil then\n        value = default\n    else\n        value = tostring(value)\n    end\n    return value\nend\n\nfunction _preprocess_define_export_value(name, value, opt)\n    value = ([[#ifdef %s_STATIC\n#  define %s_EXPORT\n#else\n#  if defined(_WIN32)\n#    define %s_EXPORT __declspec(dllexport)\n#  elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#    define %s_EXPORT __attribute__((visibility(\"default\")))\n#  else\n#    define %s_EXPORT\n#  endif\n#endif\n]]):format(name, name, name, name, name)\n    return value\nend\n\n-- get variable value\nfunction _get_variable_value(variables, name, opt)\n    opt = opt or {}\n    local preprocessor_name = opt.preprocessor_name\n    local preprocessor_argv = opt.preprocessor_argv\n    local configfile = opt.configfile\n    local value = variables[name]\n    local extraconf = variables[\"__extraconf_\" .. name]\n    if preprocessor_name then\n        local preprocessed = false\n        if opt.preprocessors then\n            for _, preprocessor in ipairs(opt.preprocessors) do\n                value = preprocessor(preprocessor_name, name, value, {argv = preprocessor_argv, extraconf = extraconf})\n                if value ~= nil then\n                    preprocessed = true\n                    break\n                end\n            end\n        end\n        if not preprocessed then\n            local preprocessors = _g._preprocessors\n            if preprocessors == nil then\n                preprocessors = {\n                    define = _preprocess_define_value,\n                    default = _preprocess_default_value,\n                    define_export = _preprocess_define_export_value\n                }\n                _g._preprocessors = preprocessors\n            end\n            local preprocessor = preprocessors[preprocessor_name]\n            if preprocessor == nil then\n                raise(\"unknown variable keyword, ${%s %s}\", preprocessor_name, name)\n            end\n            value = preprocessor(name, value, {argv = preprocessor_argv, extraconf = extraconf})\n        end\n        assert(value ~= nil, \"cannot get variable(%s %s) in %s.\", preprocessor_name, name, configfile)\n    else\n        assert(value ~= nil, \"cannot get variable(%s) in %s.\", name, configfile)\n    end\n    dprint(\"  > replace %s -> %s\", name, value)\n    if type(value) == \"table\" then\n        dprint(\"invalid variable value\", value)\n    end\n    return value\nend\n\n-- generate the configuration file\nfunction _generate_configfile(srcfile, dstfile, fileinfo, targets, preprocessors)\n\n    -- trace\n    if option.get(\"verbose\") then\n        cprint(\"${dim}generating %s to %s ..\", srcfile, dstfile)\n    end\n\n    -- only copy it?\n    if fileinfo.onlycopy then\n        if os.mtime(srcfile) > os.mtime(dstfile) then\n            os.cp(srcfile, dstfile)\n        end\n    else\n        -- generate to the temporary file first\n        local dstfile_tmp = os.tmpfile(srcfile)\n        os.tryrm(dstfile_tmp)\n        os.cp(srcfile, dstfile_tmp)\n\n        -- get all variables\n        local variables = fileinfo.variables or {}\n        for _, target in ipairs(targets) do\n\n            -- get variables from the target\n            for name, value in pairs(target:get(\"configvar\")) do\n                if variables[name] == nil then\n                    value = table.unwrap(value)\n                    variables[name] = value\n                    variables[\"__extraconf_\" .. name] = target:extraconf(\"configvar.\" .. name, value)\n                end\n            end\n\n            -- get variables from the target.options\n            for _, opt in ipairs(target:orderopts()) do\n                for name, value in pairs(opt:get(\"configvar\")) do\n                    if variables[name] == nil then\n                        variables[name] = table.unwrap(value)\n                        variables[\"__extraconf_\" .. name] = opt:extraconf(\"configvar.\" .. name, value)\n                    end\n                end\n            end\n\n            -- get the builtin variables from the target\n            for name, value in pairs(_get_builtinvars_target(target)) do\n                if type(value) == \"function\" then\n                    value = value()\n                end\n                if variables[name] == nil then\n                    variables[name] = value\n                end\n            end\n        end\n        -- get the global builtin variables\n        for name, value in pairs(_get_builtinvars_global()) do\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if variables[name] == nil then\n                variables[name] = value\n            end\n        end\n\n        -- replace all variables\n        local pattern = fileinfo.pattern or \"%${([^\\n]-)}\"\n        io.gsub(dstfile_tmp, \"(\" .. pattern .. \")\", function(_, variable)\n            variable = variable:trim()\n\n            local preprocessor_argv\n            local preprocessor_name\n            local parts = variable:split(\"%s\")\n            if #parts > 1 then\n                preprocessor_name = parts[1]\n                variable = parts[2]\n                preprocessor_argv = table.slice(parts, 3)\n            end\n\n            return _get_variable_value(variables, variable, {preprocessor_name = preprocessor_name,\n                preprocessor_argv = preprocessor_argv, configfile = srcfile, preprocessors = preprocessors})\n        end)\n\n        -- update file if the content is changed\n        if os.isfile(dstfile_tmp) then\n            os.cp(dstfile_tmp, dstfile, {copy_if_different = true})\n        end\n    end\n\n    -- trace\n    cprint(\"generating %s ... ${color.success}${text.success}\", srcfile)\nend\n\n-- the main entry function\nfunction main(opt)\n\n    -- enter project directory\n    opt = opt or {}\n    local oldir = os.cd(project.directory())\n\n    -- generate all configuration files\n    local configfiles = _get_configfiles()\n    for dstfile, srcinfo in pairs(configfiles) do\n        depend.on_changed(function ()\n            _generate_configfile(srcinfo.srcfile, dstfile, srcinfo.fileinfo, srcinfo.targets, srcinfo.preprocessors)\n        end, {files = srcinfo.srcfile,\n              lastmtime = os.mtime(dstfile),\n              dependfile = srcinfo.dependfile,\n              changed = opt.force or srcinfo.always_update})\n    end\n\n    -- leave project directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/actions/config/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"private.detect.find_platform\")\nimport(\"core.cache.localcache\")\nimport(\"core.cache.detectcache\")\nimport(\"scangen\")\nimport(\"menuconf\", {alias = \"menuconf_show\"})\nimport(\"configfiles\", {alias = \"generate_configfiles\"})\nimport(\"private.action.require.register\", {alias = \"register_packages\"})\nimport(\"private.action.require.install\", {alias = \"install_packages\"})\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- filter option\nfunction _option_filter(name)\n    local options =\n    {\n        target      = true\n    ,   file        = true\n    ,   root        = true\n    ,   yes         = true\n    ,   quiet       = true\n    ,   confirm     = true\n    ,   project     = true\n    ,   verbose     = true\n    ,   diagnosis   = true\n    ,   require     = true\n    ,   export      = true\n    ,   import      = true\n    ,   check       = true\n    ,   menu        = true\n    }\n    return not options[name]\nend\n\n-- host changed?\nfunction _host_changed()\n    return os.host() ~= config.read(\"host\")\nend\n\n-- need check\nfunction _need_check(changed)\n\n    -- clean?\n    if not changed then\n        changed = option.get(\"clean\") or option.get(\"check\")\n    end\n\n    -- check for all project files\n    local mtimes = project.mtimes()\n    if not changed then\n        local mtimes_prev = localcache.get(\"config\", \"mtimes\")\n        if mtimes_prev then\n            for file, mtime in pairs(mtimes) do\n                -- modified? reconfig and rebuild it\n                local mtime_prev = mtimes_prev[file]\n                if not mtime_prev or mtime > mtime_prev then\n                    changed = true\n                    break\n                end\n            end\n        end\n    end\n\n    -- unfinished config/recheck\n    if not changed and localcache.get(\"config\", \"recheck\") then\n        changed = true\n    end\n\n    -- Has xmake been updated? force to check config again\n    -- we need to clean the dirty config cache of the old version\n    if not changed then\n        if os.mtime(path.join(os.programdir(), \"core\", \"main.lua\")) > os.mtime(config.filepath()) then\n            changed = true\n            os.touch(config.filepath(), {mtime = os.time()})\n        end\n    end\n    return changed\nend\n\n-- check target\nfunction _check_target(target, checked_targets)\n    if not checked_targets[target:fullname()] then\n        checked_targets[target:fullname()] = target\n        for _, depname in ipairs(target:get(\"deps\")) do\n            local deptarget = project.target(depname, {namespace = target:namespace()})\n            assert(deptarget, \"unknown target(%s) for %s.deps!\", depname, target:fullname())\n            _check_target(deptarget, checked_targets)\n        end\n    end\nend\n\n-- check targets\nfunction _check_targets()\n    assert(not project.is_loaded(), \"project and targets may have been loaded early!\")\n    local checked_targets = {}\n    for _, target in pairs(project.targets()) do\n        _check_target(target, checked_targets)\n    end\nend\n\n-- find default mode\nfunction _find_default_mode()\n    local mode = config.mode()\n    if not mode then\n        mode = project.get(\"defaultmode\")\n        if not mode then\n            mode = \"release\"\n        end\n        config.set(\"mode\", mode)\n    end\n    return mode\nend\n\n-- check configs\nfunction _check_configs()\n    -- check allowed modes\n    local mode = config.mode()\n    local allowed_modes = project.allowed_modes()\n    if allowed_modes then\n        if not allowed_modes:has(mode) then\n            local allowed_modes_str = table.concat(allowed_modes:to_array(), \", \")\n            raise(\"`%s` is not a valid complation mode for this project, please use one of %s\", mode, allowed_modes_str)\n        end\n    end\n\n    -- check allowed plats\n    local plat = config.plat()\n    local allowed_plats = project.allowed_plats()\n    if allowed_plats then\n        if not allowed_plats:has(plat) then\n            local allowed_plats_str = table.concat(allowed_plats:to_array(), \", \")\n            raise(\"`%s` is not a valid platform for this project, please use one of %s\", plat, allowed_plats_str)\n        end\n    end\n\n    -- check allowed archs\n    local arch = config.arch()\n    local allowed_archs = project.allowed_archs(config.plat())\n    if allowed_archs then\n        if not allowed_archs:has(arch) then\n            local allowed_archs_str = table.concat(allowed_archs:to_array(), \", \")\n            raise(\"`%s` is not a valid complation arch for this project, please use one of %s\", arch, allowed_archs_str)\n        end\n    end\nend\n\n-- export configs\nfunction _export_configs()\n    local exportfile = option.get(\"export\")\n    if exportfile then\n        config.save(exportfile, {public = true})\n    end\nend\n\nfunction main(opt)\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- avoid running this task repeatly\n    opt = opt or {}\n    if _g.configured then return end\n    _g.configured = true\n\n    -- scan project and generate it if xmake.lua not exists\n    local autogen = false\n    local trybuild = option.get(\"trybuild\")\n    if not os.isfile(project.rootfile()) and not trybuild then\n        autogen = utils.confirm({default = false, description = \"xmake.lua not found, try generating it\"})\n        if autogen then\n            scangen()\n        else\n            os.exit()\n        end\n    end\n\n    -- check the working directory\n    if not option.get(\"project\") and not option.get(\"file\") and -- no given project path\n        not localcache.get(\"project\", \"projectdir\") and -- no cached project path\n        not localcache.get(\"project\", \"projectfile\") and\n        os.isdir(os.projectdir()) then\n        if path.translate(os.projectdir()) ~= path.translate(os.workingdir()) then\n            wprint([[You are working in the project directory(%s) and you can also\nforce to build in current directory via run `xmake -P .`]], os.projectdir())\n        end\n    end\n\n    -- lock the whole project\n    project.lock()\n\n    -- enter menu config\n    local options_changed = false\n    if option.get(\"menu\") then\n        options_changed = menuconf_show()\n    end\n\n    -- load the project configuration\n    --\n    -- priority: option > option_cache > global > option_default > config_check > project_check > config_cache\n    --\n\n    -- get the options\n    local options = nil\n    for name, value in pairs(option.options()) do\n        if _option_filter(name) then\n            options = options or {}\n            options[name] = value\n        end\n    end\n\n    -- merge options from the given import file\n    local importfile = option.get(\"import\")\n    if importfile then\n        assert(os.isfile(importfile), \"%s not found!\", importfile)\n        -- we need to use readonly, @see https://github.com/xmake-io/xmake/issues/2278\n        local import_configs = io.load(importfile)\n        if import_configs then\n            for name, value in pairs(import_configs) do\n                options = options or {}\n                if options[name] == nil then\n                    options[name] = value\n                end\n            end\n        end\n    end\n\n    -- override configuration from the options or cache\n    local options_history = {}\n    if not option.get(\"clean\") and not autogen then\n        options_history = localcache.get(\"config\", \"options\") or {}\n        options = options or options_history\n    end\n    for name, value in pairs(options) do\n        -- Is options changed by argument options?\n        options_changed = options_changed or options_history[name] ~= value\n        -- @note override it and mark as readonly (highest priority)\n        config.set(name, value, {readonly = true})\n    end\n\n    -- merge the cached configuration\n    --\n    -- @note we cannot load cache config when switching platform, arch ..\n    -- so we need known whether options have been changed\n    --\n    local configcache_loaded = false\n    if not options_changed and not option.get(\"clean\") and not _host_changed() then\n        configcache_loaded = config.load()\n    end\n\n    -- merge the global configuration\n    for name, value in pairs(global.options()) do\n        if config.get(name) == nil then\n            config.set(name, value)\n        end\n    end\n\n    -- merge the default options\n    for name, value in pairs(option.defaults()) do\n        if _option_filter(name) and config.get(name) == nil then\n            config.set(name, value)\n        end\n    end\n\n    -- merge the project options after default options\n    for name, value in pairs(project.get(\"config\")) do\n        value = table.unwrap(value)\n        assert(type(value) == \"string\" or type(value) == \"boolean\" or type(value) == \"number\", \"set_config(%s): unsupported value type(%s)\", name, type(value))\n        if not config.readonly(name) then\n            config.set(name, value)\n        end\n    end\n\n    -- find default mode\n    local mode = _find_default_mode()\n    assert(mode == config.mode())\n\n    -- find default platform and save to configuration\n    local plat, arch = find_platform({global = true})\n    assert(plat == config.plat())\n    assert(arch == config.arch())\n\n    -- load platform instance\n    local instance_plat = platform.load(plat, arch)\n\n    -- merge the checked configuration\n    local recheck = _need_check(options_changed or not configcache_loaded or autogen)\n    if recheck then\n\n        -- clear cached configuration\n        if option.get(\"clean\") then\n            localcache.clear(\"config\")\n        end\n\n        -- clear some local caches\n        localcache.clear(\"detect\")\n        localcache.clear(\"option\")\n        localcache.clear(\"package\")\n        localcache.clear(\"toolchain\")\n        localcache.set(\"config\", \"recheck\", true)\n        if not opt.loadonly then\n            localcache.save()\n        end\n\n        -- check platform\n        instance_plat:check()\n\n        -- check project options\n        if not trybuild then\n            project.check_options()\n        end\n    end\n\n    -- translate the build directory\n    local builddir = config.get(\"builddir\")\n    if config.get(\"buildir\") then\n        wprint(\"`xmake f --buildir=` has been deprecated, please use `xmake f -o/--builddir=`\")\n        builddir = config.get(\"buildir\")\n        config.set(\"builddir\", builddir, {readonly = true, force = true})\n    end\n    if builddir and path.is_absolute(builddir) then\n        config.set(\"builddir\", path.relative(builddir, project.directory()), {readonly = true, force = true})\n    end\n\n    -- only config for building project using third-party buildsystem\n    if not trybuild then\n\n        -- check configs\n        _check_configs()\n\n        -- install and register packages\n        local require_enable = option.boolean(option.get(\"require\"))\n        if (recheck or require_enable) then\n            if require_enable ~= false then\n                install_packages()\n            else\n                register_packages()\n            end\n        end\n\n        -- check target and ensure to load all targets, @note we must load targets after installing required packages,\n        -- otherwise has_package() will be invalid.\n        _check_targets()\n\n        -- check target toolchains\n        if recheck then\n            target_utils.check_target_toolchains()\n        end\n\n        -- load targets\n        project.load_targets({recheck = recheck})\n\n        -- update the config files\n        generate_configfiles({force = recheck})\n    end\n\n    -- dump config\n    if option.get(\"verbose\") and not opt.disable_dump then\n        config.dump()\n    end\n\n    -- export configs\n    if option.get(\"export\") then\n        _export_configs()\n    end\n\n    -- save configs and caches\n    if not opt.loadonly then\n        -- we need to save it and enable external working mode\n        -- if we configure the given project directory\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/3342\n        --\n        local projectdir = option.get(\"project\")\n        local projectfile = option.get(\"file\")\n        if projectdir or projectfile then\n            localcache.set(\"project\", \"projectdir\", projectdir)\n            localcache.set(\"project\", \"projectfile\", projectfile)\n            localcache.save(\"project\")\n        end\n\n        -- save options and config cache\n        localcache.set(\"config\", \"recheck\", false)\n        localcache.set(\"config\", \"mtimes\", project.mtimes())\n        config.save()\n        localcache.set(\"config\", \"options\", options)\n        localcache.save(\"config\")\n\n        -- save toolchain cache\n        toolchain.save()\n\n        -- save detect cache\n        detectcache:save()\n    end\n\n    -- unlock the whole project\n    project.unlock()\nend\n"
  },
  {
    "path": "xmake/actions/config/menuconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menuconf.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.action\")\nimport(\"core.ui.menuconf\")\nimport(\"core.ui.mconfdialog\")\nimport(\"core.ui.application\")\nimport(\"private.detect.find_platform\")\n\n-- the app application\nlocal app = application()\n\n-- init app\nfunction app:init()\n\n    -- init name\n    application.init(self, \"app.config\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- insert menu config dialog\n    self:insert(self:mconfdialog())\n\n    -- load configs\n    self:load(not option.get(\"clean\"))\nend\n\n-- get menu config dialog\nfunction app:mconfdialog()\n    if not self._MCONFDIALOG then\n        local mconfdialog = mconfdialog:new(\"app.config.mconfdialog\", rect{1, 1, self:width() - 1, self:height() - 1}, \"menu config\")\n        mconfdialog:action_set(action.ac_on_exit, function (v)\n            self:quit()\n            os.exit()\n        end)\n        mconfdialog:action_set(action.ac_on_save, function (v)\n            self:save()\n            self:quit()\n        end)\n        self._MCONFDIALOG = mconfdialog\n    end\n    return self._MCONFDIALOG\nend\n\n-- on resize\nfunction app:on_resize()\n    self:mconfdialog():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1})\n    application.on_resize(self)\nend\n\n-- filter option\nfunction app:_filter_option(name)\n    local options =\n    {\n        target      = true\n    ,   file        = true\n    ,   root        = true\n    ,   yes         = true\n    ,   quiet       = true\n    ,   confirm     = true\n    ,   project     = true\n    ,   verbose     = true\n    ,   diagnosis   = true\n    ,   require     = true\n    ,   version     = true\n    ,   help        = true\n    ,   clean       = true\n    ,   menu        = true\n    ,   import      = true\n    ,   export      = true\n    ,   check       = true\n    }\n    return not options[name] and not project.option(name)\nend\n\n-- get or make menu by category\nfunction app:_menu_by_category(root, configs, menus, category)\n\n    -- is root?\n    if category == \".\" or category == \"\" then\n        return\n    end\n\n    -- attempt to get menu first\n    local menu = menus[category]\n    if not menu then\n\n        -- get config path\n        local parentdir = path.directory(category)\n        local config_path = path.join(root, parentdir == \".\" and \"\" or parentdir)\n\n        -- make a new menu\n        menu = menuconf.menu {name = category, path = config_path, description = path.basename(category), configs = {}}\n        menus[category] = menu\n\n        -- insert to the parent or root configs\n        local parent = self:_menu_by_category(root, configs, menus, parentdir)\n        table.insert(parent and parent.configs or configs, menu)\n    end\n    return menu\nend\n\n-- make configs by category\nfunction app:_make_configs_by_category(root, options_by_category, cache, get_option_info)\n\n    -- make configs category\n    --\n    -- root category: \".\"\n    -- category path: \"a\", \"a/b\", \"a/b/c\" ...\n    --\n    local menus = {}\n    local configs = {}\n    local categories = table.orderkeys(options_by_category)\n    for _, category in ipairs(categories) do\n\n        -- get or make menu by category\n        local options  = options_by_category[category]\n        local menu = self:_menu_by_category(root, configs, menus, category)\n\n        -- get sub-configs\n        local subconfigs = menu and menu.configs or configs\n\n        -- insert options to sub-configs\n        for _, opt in ipairs(options) do\n\n            -- get option info\n            local info = get_option_info(opt)\n\n            -- new value?\n            local newvalue = true\n\n            -- load value\n            local value = nil\n            if cache then\n                value = config.get(info.name)\n                if value ~= nil and info.kind == \"choice\" and info.values then\n                    for idx, val in ipairs(info.values) do\n                        if value == val then\n                            value = idx\n                            break\n                        end\n                    end\n                end\n                if value ~= nil then\n                    newvalue = false\n                end\n            end\n\n            -- find the menu index in subconfigs\n            local menu_index = #subconfigs + 1\n            for idx, subconfig in ipairs(subconfigs) do\n                if subconfig.kind == \"menu\" then\n                    menu_index = idx\n                    break\n                end\n            end\n\n            -- get config path\n            local config_path = path.join(root, category == \".\" and \"\" or category)\n\n            -- insert config before all sub-menus\n            if info.kind == \"string\" then\n                table.insert(subconfigs, menu_index, menuconf.string {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo})\n            elseif info.kind == \"boolean\" then\n                table.insert(subconfigs, menu_index, menuconf.boolean {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo})\n            elseif info.kind == \"choice\" then\n                table.insert(subconfigs, menu_index, menuconf.choice {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, values = info.values, description = info.description, sourceinfo = info.sourceinfo})\n            end\n        end\n    end\n\n    -- done\n    return configs\nend\n\n-- get basic configs\nfunction app:_basic_configs(cache)\n\n    -- get configs from the cache first\n    local configs = self._BASIC_CONFIGS\n    if configs then\n        return configs\n    end\n\n    -- get config menu\n    local menu = option.taskmenu(\"config\")\n\n    -- merge options by category\n    local category = \".\"\n    local options = menu and menu.options or {}\n    local options_by_category = {}\n    local keys = table.orderkeys(options)\n    for _, key in ipairs(keys) do\n        local opt = options[key]\n        local name = opt[2] or opt[1]\n        if name and self:_filter_option(name) then\n            options_by_category[category] = options_by_category[category] or {}\n            table.insert(options_by_category[category], opt)\n        elseif opt.category then\n            category = opt.category\n        end\n    end\n\n    -- make configs by category\n    self._BASIC_CONFIGS = self:_make_configs_by_category(\"Basic Configuration\", options_by_category, cache, function (opt)\n\n        -- get option\n        local name    = opt[2] or opt[1]\n        local default = opt[4]\n        local kind    = (opt[3] == \"k\" or type(default) == \"boolean\") and \"boolean\" or \"string\"\n\n        -- get default values\n        if name == \"plat\" then\n            default = find_platform()\n        elseif name == \"arch\" then\n            _, default = find_platform()\n        elseif name == \"mode\" then\n            default = project.get(\"defaultmode\")\n            if not default then\n                default = \"release\"\n            end\n        end\n\n        -- choice option?\n        local values = opt.values\n        if values then\n            if type(values) == \"function\" then\n                values = values(false, {menuconf = true})\n            end\n            values = table.wrap(values)\n            for idx, value in ipairs(values) do\n                if default == value then\n                    default = idx\n                    break\n                end\n            end\n        end\n        if values then\n            kind = \"choice\"\n        end\n\n        -- get description\n        local description = {}\n        for i = 5, 64 do\n            local desc = opt[i]\n            if type(desc) == \"function\" then\n                desc = desc()\n            end\n            if type(desc) == \"string\" then\n                table.insert(description, desc)\n            elseif type(desc) == \"table\" then\n                table.join2(description, desc)\n            else\n                break\n            end\n        end\n\n        -- make option info\n        return {name = name, kind = kind, default = default, values = values, description = description}\n    end)\n    return self._BASIC_CONFIGS\nend\n\n-- get project configs\nfunction app:_project_configs(cache)\n\n    -- get configs from the cache first\n    local configs = self._PROJECT_CONFIGS\n    if configs then\n        return configs\n    end\n\n    -- merge options by category\n    local options = project.options()\n    local options_by_category = {}\n    local keys = table.orderkeys(options)\n    for _, key in ipairs(keys) do\n        local opt = options[key]\n        if opt:showmenu() ~= false then\n            local category = \".\"\n            if opt:get(\"category\") then category = table.unwrap(opt:get(\"category\")) end\n            options_by_category[category] = options_by_category[category] or {}\n            table.insert(options_by_category[category], opt)\n        end\n    end\n\n    -- make configs by category\n    self._PROJECT_CONFIGS = self:_make_configs_by_category(\"Project Configuration\", options_by_category, cache, function (opt)\n\n        -- the default value\n        local default = \"auto\"\n        if opt:get(\"default\") ~= nil then\n            default = opt:get(\"default\")\n        end\n\n        -- get kind\n        local kind = (type(default) == \"string\") and \"string\" or \"boolean\"\n\n        -- get description\n        local description = opt:description()\n\n        -- get source info\n        local sourceinfo = (opt:get(\"__sourceinfo_description\") or {})[type(description) == \"table\" and description[1] or description]\n\n        -- choice option?\n        local values = opt:get(\"values\")\n        if values then\n            kind = \"choice\"\n            values = table.wrap(values)\n            for idx, value in ipairs(values) do\n                if default == value then\n                    default = idx\n                    break\n                end\n            end\n        end\n        return {name = opt:name(), kind = kind, default = default, values = values, description = description, sourceinfo = sourceinfo}\n    end)\n    return self._PROJECT_CONFIGS\nend\n\n-- save the given configs\nfunction app:_save_configs(configs)\n    local options = option.options()\n    for _, conf in pairs(configs) do\n        if conf.kind == \"menu\" then\n            self:_save_configs(conf.configs)\n        elseif not conf.new and (conf.kind == \"boolean\" or conf.kind == \"string\") then\n            options[conf.name] = conf.value\n        elseif not conf.new and (conf.kind == \"choice\") then\n            options[conf.name] = conf.values[conf.value]\n        end\n    end\nend\n\n-- Have configs been changed?\nfunction app:_configs_changed()\n    return self._CONFIGS_CHANGED\nend\n\n-- load configs from options\nfunction app:load(cache)\n\n    -- merge configuration from the given import file or cache\n    local loaded = false\n    local importfile = option.get(\"import\")\n    if importfile and os.isfile(importfile) then\n        loaded = config.load(importfile)\n    elseif cache then\n        loaded = config.load()\n    end\n\n    -- clear configs first\n    self._BASIC_CONFIGS = nil\n    self._PROJECT_CONFIGS = nil\n\n    -- load configs\n    local configs = {}\n    table.insert(configs, menuconf.menu {description = \"Basic Configuration\", configs = self:_basic_configs(cache)})\n    table.insert(configs, menuconf.menu {description = \"Project Configuration\", configs = self:_project_configs(cache)})\n    self:mconfdialog():load(configs)\n\n    -- the previous config is only for loading menuconf, so clear config now\n    if loaded then\n        config.clear()\n    end\nend\n\n-- save configs to options\nfunction app:save()\n    self:_save_configs(self:_basic_configs())\n    self:_save_configs(self:_project_configs())\n    self._CONFIGS_CHANGED = true\nend\n\n-- main entry\nfunction main(...)\n    app:run(...)\n    return app:_configs_changed()\nend\n"
  },
  {
    "path": "xmake/actions/config/scangen.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scangen.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- scan project and generate xmake.lua automaticlly if the project codes exist\nfunction main()\n\n    -- trace\n    cprint(\"${color.warning}xmake.lua not found, scanning files ..\")\n\n    -- scan source files for the current directory\n    local targetkinds = {}\n    local sourcefiles = {}\n    local sourcefiles_main = {}\n    for extension, sourcekind in pairs(language.extensions()) do\n\n        -- load language instance\n        local instance = language.load_sk(sourcekind)\n\n        -- get check main() script\n        local check_main = instance:get(\"check_main\")\n\n        -- scan source files\n        local filecount = 0\n        for _, sourcefile in ipairs(os.files(\"*\" .. extension)) do\n            if check_main and check_main(sourcefile) then\n                table.insert(sourcefiles_main, sourcefile)\n            else\n                table.insert(sourcefiles, sourcefile)\n            end\n            filecount = filecount + 1\n        end\n\n        -- add targetkinds\n        if filecount > 0 then\n            for targetkind, _ in pairs(instance:kinds()) do\n                targetkinds[targetkind] = true\n            end\n        end\n    end\n    sourcefiles         = table.unique(sourcefiles)\n    sourcefiles_main    = table.unique(sourcefiles_main)\n\n    -- project not found\n    if #sourcefiles == 0 and #sourcefiles_main == 0 then\n        raise(\"project not found!\")\n    end\n\n    -- generate xmake.lua\n    local file = io.open(\"xmake.lua\", \"w\")\n    if file then\n\n        -- get target name\n        local targetname = path.basename(os.curdir())\n\n        -- define static/binary target\n        if #sourcefiles > 0 then\n\n            -- get targetkind\n            local targetkind = nil\n            if targetkinds[\"static\"] then\n                targetkind = \"static\"\n            elseif targetkinds[\"binary\"] then\n                targetkind = \"binary\"\n            end\n            assert(targetkind, \"unknown target kind!\")\n\n            -- trace\n            cprint(\"target(${magenta}%s${clear}): %s\", targetname, targetkind)\n\n            -- add rules\n            file:print(\"add_rules(\\\"mode.debug\\\", \\\"mode.release\\\")\")\n            file:print(\"\")\n\n            -- add target\n            file:print(\"target(\\\"%s\\\")\", targetname)\n            file:print(\"    set_kind(\\\"%s\\\")\", targetkind)\n            for _, sourcefile in ipairs(sourcefiles) do\n                cprint(\"    ${green}[+]: ${clear}%s\", sourcefile)\n                file:print(\"    add_files(\\\"%s\\\")\", sourcefile)\n            end\n            file:print(\"\")\n        end\n\n        -- define binary targets\n        for _, sourcefile in ipairs(sourcefiles_main) do\n\n            -- trace\n            local name = path.basename(sourcefile)\n            if name == targetname then\n                name = name .. \"1\"\n            end\n            cprint(\"target(${magenta}%s${clear}): binary\", name)\n            cprint(\"    ${green}[+]: ${clear}%s\", sourcefile)\n\n            -- add target\n            file:print(\"target(\\\"%s\\\")\", name)\n            file:print(\"    set_kind(\\\"binary\\\")\")\n            file:print(\"    add_files(\\\"%s\\\")\", sourcefile)\n            file:print(\"\")\n\n            -- add deps\n            if #sourcefiles > 0 then\n                file:print(\"    add_deps(\\\"%s\\\")\", targetname)\n                file:print(\"\")\n            end\n        end\n\n        -- add FAQ\n        file:print(io.readfile(path.join(os.programdir(), \"scripts\", \"faq.lua\")))\n\n        -- exit file\n        file:close()\n    end\n\n    -- generate .gitignore if not exists\n    if not os.isfile(\".gitignore\") then\n        os.cp(\"$(programdir)/scripts/gitignore\", \".gitignore\")\n    end\n\n    -- trace\n    cprint(\"${color.success}xmake.lua generated, scan ok!\")\nend\n"
  },
  {
    "path": "xmake/actions/config/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nfunction _plat_values(complete, opt)\n    import(\"core.platform.platform\")\n    import(\"core.base.hashset\")\n    import(\"core.project.project\")\n\n    if not complete or not opt.arch then\n        local plats = try {function () return project.allowed_plats() end}\n        if plats then\n            return plats:to_array()\n        end\n        return platform.plats()\n    end\n\n    -- arch has given, find all supported platforms\n    local plats = {}\n    for _, plat in ipairs(platform.plats()) do\n        local archs = hashset.from(platform.archs(plat))\n        if archs:has(opt.arch) then\n            table.insert(plats, plat)\n        end\n    end\n    return plats\nend\n\nfunction _arch_values(complete, opt)\n    opt = opt or {}\n    if opt.helpmenu then\n        return\n    end\n\n    -- imports\n    import(\"core.project.project\")\n    import(\"core.platform.platform\")\n    import(\"core.base.hashset\")\n\n    -- get all platforms\n    local plats = try {function () return project.allowed_plats() end}\n    if plats then\n        plats = plats:to_array()\n    end\n    plats = plats or platform.plats()\n\n    -- get all architectures\n    local archset = hashset.new()\n    for _, plat in ipairs(opt.plat and { opt.plat } or plats) do\n        local archs = try {function () return project.allowed_archs(plat) end}\n        if archs then\n            archs = archs:to_array()\n        end\n        if not archs then\n            archs = platform.archs(plat)\n        end\n        if archs then\n            for _, arch in ipairs(archs) do\n                archset:insert(arch)\n            end\n        end\n    end\n    return archset:to_array()\nend\n\nfunction _arch_description()\n    import(\"core.project.project\")\n    import(\"core.platform.platform\")\n\n    -- get all platforms\n    local plats = try {function () return project.allowed_plats() end}\n    if plats then\n        plats = plats:to_array()\n    end\n    plats = plats or platform.plats()\n\n    -- get all architectures\n    local description = {}\n    for i, plat in ipairs(plats) do\n        local archs = try {function () return project.allowed_archs(plat) end}\n        if archs then\n            archs = archs:to_array()\n        end\n        if not archs then\n            archs = platform.archs(plat)\n        end\n        if archs and #archs > 0 then\n            local desc = \"    - \" .. plat .. \":\"\n            for _, arch in ipairs(archs) do\n                desc = desc .. \" \" .. arch\n            end\n            table.insert(description, desc)\n        end\n    end\n    return description\nend\n\nfunction _mode_values(complete, opt)\n    import(\"core.project.project\")\n    opt = opt or {}\n    local modes = try {function()\n        if opt.menuconf then\n            -- we cannot load target.mode in menuconf\n            local allowed_modes = project.allowed_modes()\n            if allowed_modes then\n                return allowed_modes:to_array()\n            end\n        else\n            return project.modes()\n        end\n    end}\n    if not modes then\n        modes = {\"debug\", \"release\"}\n    end\n    return modes\nend\n\nfunction _target_values(complete, opt)\n    return import(\"private.utils.complete_helper.targets\")(complete, opt)\nend\n\n-- the toolchains is too much, so we just show all for menuconf and auto-complete mode.\n-- @see https://github.com/xmake-io/xmake/issues/3436\n--\nfunction _toolchain_values(complete, opt)\n    opt = opt or {}\n    if complete or opt.menuconf then\n        import(\"core.tool.toolchain\")\n        return toolchain.list()\n    end\nend\n\nfunction _project_menu_options()\n    import(\"core.project.menu\")\n    return menu.options()\nend\n\nfunction _language_menu_options()\n    import(\"core.language.menu\")\n    return menu.options(\"config\")\nend\n\nfunction _platform_menu_options()\n    import(\"core.platform.menu\")\n    return menu.options(\"config\")\nend\n\ntask(\"config\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n                usage = \"xmake config|f [options]\",\n                description = \"Configure the project.\",\n                shortname = 'f',\n                options = {\n                    {'c', \"clean\",      \"k\",  nil       ,   \"Clean the cached user configs and detection cache.\"},\n                    {nil, \"check\",      \"k\",  nil       ,   \"Just ignore detection cache and force to check all, it will reserve the cached user configs.\"},\n                    {nil, \"export\",     \"kv\", nil       ,   \"Export the current configuration to the given file.\"\n                                                        ,   \"    e.g.\"\n                                                        ,   \"    - xmake f -m debug -xxx=y --export=build/config.txt\"},\n                    {nil, \"import\",     \"kv\", nil       ,   \"Import configs from the given file.\"\n                                                        ,   \"    e.g.\"\n                                                        ,   \"    - xmake f -import=build/config.txt\"},\n                    {nil, \"menu\",       \"k\",  nil       ,   \"Configure project with a menu-driven user interface.\"},\n                    {category = \".\"},\n                    {'p', \"plat\",       \"kv\", \"auto\"    ,   \"Compile for the given platform.\", values = _plat_values},\n                    {'a', \"arch\",       \"kv\", \"auto\"    ,   \"Compile for the given architecture.\", _arch_description, values = _arch_values},\n                    {'m', \"mode\",       \"kv\", \"auto\" ,      \"Compile for the given mode.\", values = _mode_values},\n                    {'k', \"kind\",       \"kv\", \"static\"  ,   \"Compile for the given target kind.\", values = {\"static\", \"shared\", \"binary\"}},\n                    {nil, \"host\",       \"kv\", \"$(host)\" ,   \"Set the current host environment.\"},\n                    {nil, \"policies\",    \"kv\", nil       ,  \"Set the project policies.\",\n                                                            \"    e.g.\",\n                                                            \"    - xmake f --policies=package.fetch_only\",\n                                                            \"    - xmake f --policies=package.precompiled:n,package.install_only\"},\n                    {category = \"Package Configuration\"},\n                    {nil, \"require\",    \"kv\",   nil     ,   \"Require all dependent packages?\", values = {\"yes\", \"no\"}},\n                    {nil, \"pkg_searchdirs\", \"kv\", nil       , \"The search directories of the remote package.\"\n                                                            , \"    e.g.\"\n                                                            , \"    - xmake f --pkg_searchdirs=/dir1\" .. path.envsep() .. \"/dir2\"},\n                    {category = \"Cross Complation Configuration\"},\n                    {nil, \"cross\",      \"kv\", nil,          \"Set cross toolchains prefix\"\n                                                          , \"e.g.\"\n                                                          , \"    - i386-mingw32-\"\n                                                          , \"    - arm-linux-androideabi-\"},\n                    {nil, \"target_os\",  \"kv\", nil,          \"Set target os only for cross-complation\"},\n                    {nil, \"bin\",        \"kv\", nil,          \"Set cross toolchains bin directory\"\n                                                          , \"e.g.\"\n                                                          , \"    - sdk/bin (/arm-linux-gcc ..)\"},\n                    {nil, \"sdk\",        \"kv\", nil,          \"Set cross SDK directory\"\n                                                          , \"e.g.\"\n                                                          , \"    - sdk/bin\"\n                                                          , \"    - sdk/lib\"\n                                                          , \"    - sdk/include\"},\n                    {nil, \"toolchain\",  \"kv\", nil,          \"Set toolchain name\"\n                                                          , \"e.g. \"\n                                                          , \"    - xmake f --toolchain=clang\"\n                                                          , \"    - xmake f --toolchain=[cross|llvm|sdcc ..] --sdk=/xxx\"\n                                                          , \"    - run `xmake show -l toolchains` to get all toolchains\"\n                                                          , values = _toolchain_values},\n                    {nil, \"toolchain_host\", \"kv\", nil,      \"Set host toolchain name, it's only for building packages on host machine.\"\n                                                          , \"e.g. \"\n                                                          , \"    - xmake f --toolchain_host=clang\"\n                                                          , \"    - xmake f --toolchain_host=[cross|llvm|sdcc ..] --sdk=/xxx\"\n                                                          , \"    - run `xmake show -l toolchains` to get all toolchains\"\n                                                          , values = _toolchain_values},\n                    {nil, \"runtimes\", \"kv\", nil,          \"Set the compiler runtime library.\"\n                                                          , \"e.g. \"\n                                                          , \"    - xmake f --runtimes=MTd\"\n                                                          , \"    - xmake f --runtimes=MT,c++_static\"\n                                                          , values = {\"MT\", \"MTd\", \"MD\", \"MDd\",             -- only for msvc\n                                                                      \"c++_static\", \"c++_shared\",           -- gcc/clang/android ndk\n                                                                      \"stdc++_static\", \"stdc++_shared\",     -- gcc/clang\n                                                                      \"gnustl_static\", \"gnustl_shared\",     -- only for old android ndk\n                                                                      \"stlport_static\", \"stlport_shared\"}}, -- only for old android ndk\n                    _language_menu_options,\n                    _platform_menu_options,\n                    {category = \"Other Configuration\"},\n                    {nil, \"debugger\",   \"kv\", \"auto\"    , \"Set debugger\"},\n                    {nil, \"ccache\",     \"kv\", true      , \"Enable or disable the c/c++ compiler cache.\"},\n                    {nil, \"ccachedir\",  \"kv\", nil       , \"Set the ccache directory.\"},\n                    {nil, \"trybuild\",   \"kv\", nil       , \"Enable try-build mode and set the third-party buildsystem tool.\",\n                                                            \"e.g.\",\n                                                            \"    - xmake f --trybuild=auto; xmake\",\n                                                            \"    - xmake f --trybuild=autoconf -p android --ndk=xxx; xmake\",\n                                                            \"\",\n                                                            \"the third-party buildsystems:\"\n                                                        ,   values = {\"auto\", \"make\", \"autoconf\", \"cmake\", \"scons\", \"meson\", \"bazel\", \"ninja\", \"msbuild\", \"xcodebuild\", \"ndkbuild\", \"xrepo\"}},\n                    {nil, \"tryconfigs\", \"kv\", nil       ,   \"Set the extra configurations of the third-party buildsystem for the try-build mode.\",\n                                                            \"e.g.\",\n                                                            \"    - xmake f --trybuild=autoconf --tryconfigs='--enable-shared=no'\"},\n                    {'o', \"builddir\",   \"kv\", \"build\"   , \"Set build directory.\"},\n                    {nil, \"buildir\",    \"kv\", nil       , \"Set build directory. (deprecated)\"},\n                    {},\n                    {category = \"Project Configuration\"},\n                    _project_menu_options}}\n\n\n\n"
  },
  {
    "path": "xmake/actions/create/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\nimport(\"actions.create.template\", {rootdir = os.programdir()})\n\n-- validate template component against path traversal\nfunction _validate_template_component(name, value)\n    if #value == 0 or value == \".\" or value == \"..\"\n        or value:find(\"/\", 1, true) or value:find(\"\\\\\", 1, true)\n        or value:find(\":\", 1, true) or value:find(\"\\0\", 1, true) then\n        raise(\"invalid %s: %s!\", name, value)\n    end\nend\n\n-- get template language from template id\nfunction _get_language_from_template(templateid)\n    local lang = option.get(\"language\")\n    if lang then\n        _validate_template_component(\"language\", lang)\n    end\n    if not templateid or not lang or template.templatedir(lang, templateid) then\n        return lang\n    end\n    local langs = template.languages_for_template(templateid)\n    if #langs == 1 then\n        return langs[1]\n    elseif #langs > 1 then\n        raise(\"template(%s): please pass -l/--language, supported languages: %s\", templateid, table.concat(langs, \", \"))\n    end\n    return lang\nend\n\n-- get template id from command line options\nfunction _get_templateid()\n    local templateid = option.get(\"template\")\n    _validate_template_component(\"template id\", templateid)\n    return templateid\nend\n\n-- get target name from command line options\nfunction _get_targetname()\n    return option.get(\"target\") or path.basename(project.directory()) or \"demo\"\nend\n\n-- list all supported templates for each language\n--\n-- output is in tree format:\n--   <source>\n--     <language>\n--       <template>\nfunction _list_templates(lang_filter)\n    local rootinfos = template.rootinfos()\n    local languages = template.languages()\n    if lang_filter then\n        _validate_template_component(\"language\", lang_filter)\n        if not table.contains(languages, lang_filter) then\n            raise(\"unknown language(%s), supported languages: %s\", lang_filter, table.concat(languages, \", \"))\n        end\n        languages = {lang_filter}\n    end\n\n    -- map a template directory to its root meta (repo/global/builtin)\n    local rootinfo_of = function (dir)\n        if not dir then\n            return\n        end\n        dir = path.absolute(dir)\n        for _, info in ipairs(rootinfos) do\n            local rootdir = path.absolute(info.dir)\n            if dir == rootdir or dir:startswith(rootdir .. path.sep()) then\n                return info\n            end\n        end\n    end\n\n    local sourcekey_of = function (info)\n        if not info then\n            return \"unknown\"\n        end\n        if info.kind == \"repo\" then\n            return \"repo:\" .. info.name\n        end\n        return info.kind or \"unknown\"\n    end\n\n    local groups = {}\n    for _, lang in ipairs(languages) do\n        local templates = template.templates(lang)\n        if templates and #templates > 0 then\n            for _, name in ipairs(templates) do\n                local sourcedir = template.templatedir(lang, name)\n                local info = rootinfo_of(sourcedir)\n                local key = sourcekey_of(info)\n                local group = groups[key]\n                if not group then\n                    group = {info = info, langs = {}}\n                    groups[key] = group\n                end\n                group.langs[lang] = group.langs[lang] or {}\n                table.insert(group.langs[lang], name)\n            end\n        end\n    end\n\n    local groupkeys = {}\n    local inserted = {}\n    for _, info in ipairs(rootinfos) do\n        local key = sourcekey_of(info)\n        if groups[key] and not inserted[key] then\n            table.insert(groupkeys, key)\n            inserted[key] = true\n        end\n    end\n    if groups[\"unknown\"] and not inserted[\"unknown\"] then\n        table.insert(groupkeys, \"unknown\")\n        inserted[\"unknown\"] = true\n    end\n\n    for _, key in ipairs(groupkeys) do\n        local group = groups[key]\n        if group then\n            local info = group.info\n            if info and info.kind == \"repo\" then\n                local branch = info.branch and (\" \" .. info.branch) or \"\"\n                cprint(\"${bright}%s${reset}: %s%s\", info.name, info.url or \"\", branch)\n            else\n                cprint(\"${bright}%s${reset}\", (info and info.kind) or \"unknown\")\n            end\n            local langs = {}\n            for lang, _ in pairs(group.langs) do\n                table.insert(langs, lang)\n            end\n            table.sort(langs)\n            for _, lang in ipairs(langs) do\n                cprint(\"  ${bright}%s${reset}\", lang)\n                local templates = group.langs[lang]\n                table.sort(templates)\n                for _, name in ipairs(templates) do\n                    print(\"    - %s\", name)\n                end\n            end\n            print(\"\")\n        end\n    end\nend\n\n-- create project from template\nfunction _create_project(lang, templateid, targetname)\n    assert(targetname ~= \".\", \"you should specify ${red}-P${reset} instead of directly using ${red}.${reset}\")\n    assert(lang, \"no language!\")\n    assert(templateid, \"no template id!\")\n\n    -- get project directory\n    local projectdir = path.absolute(option.get(\"project\") or path.join(os.curdir(), targetname))\n    if not os.isdir(projectdir) then\n        -- make the project directory if not exists\n        os.mkdir(projectdir)\n    end\n\n    -- xmake.lua exists?\n    if os.isfile(path.join(projectdir, \"xmake.lua\")) and not option.get(\"force\") then\n        raise(\"project (${underline}%s/xmake.lua${reset}) exists!\", projectdir)\n    end\n\n    -- empty project?\n    os.tryrm(path.join(projectdir, \".xmake\"))\n    if not os.emptydir(projectdir) and not option.get(\"force\") then\n        -- otherwise, check whether it is empty\n        raise(\"project directory (${underline}%s${reset}) is not empty!\", projectdir)\n    end\n\n    -- enter the project directory\n    os.cd(projectdir)\n\n    -- create project\n    local sourcedir = template.templatedir(lang, templateid)\n    if not sourcedir then\n        raise(\"template(%s/%s): not found!\\nyou can try:\\n  - xrepo update-repo (update repositories)\\n  - xmake create --list (show available templates)\", lang, templateid)\n    end\n\n    -- get the builtin variables\n    local builtinvars = template.builtinvars(targetname)\n\n    -- copy template project files\n    local createdfiles = template.copy_files(sourcedir, projectdir)\n\n    -- copy the default .gitignore\n    if not os.isfile(path.join(projectdir, \".gitignore\")) then\n        os.cp(path.join(os.programdir(), \"scripts\", \"gitignore\"), path.join(projectdir, \".gitignore\"))\n        table.insert(createdfiles, path.join(projectdir, \".gitignore\"))\n    end\n\n    -- replace template variables\n    template.replace_variables_in_files(createdfiles, builtinvars)\n\n    -- done\n    table.sort(createdfiles)\n    for _, file in ipairs(createdfiles) do\n        cprint(\"  ${green}[+]: ${clear}%s\", path.relative(file, projectdir))\n    end\nend\n\nfunction main()\n    os.cd(os.workingdir())\n\n    -- `xmake create --list` only prints available templates and exits.\n    if option.get(\"list\") then\n        local explicit_language = option.options() and option.options().language\n        _list_templates(explicit_language)\n        return\n    end\n\n    local targetname = _get_targetname()\n    local templateid = _get_templateid()\n    local lang = _get_language_from_template(templateid)\n\n    -- create project from template\n    cprint(\"${bright}create %s ...\", targetname)\n    _create_project(lang, templateid, targetname)\n    cprint(\"${color.success}create ok!\")\nend\n"
  },
  {
    "path": "xmake/actions/create/template.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        template.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"core.base.hashset\")\nimport(\"core.language.language\")\nimport(\"core.package.repository\")\n\n-- some builtin template variables in xmake.lua\nfunction builtinvars(targetname)\n    return {TARGET_NAME = targetname,\n            FAQ = function() return io.readfile(path.join(os.programdir(), \"scripts\", \"faq.lua\")) end}\nend\n\n-- get all template roots with extra meta information\n--\n-- priority:\n--   1. repo:     <global-repo>/templates (including builtin repo templates)\n--   2. global:   <globaldir>/templates\nfunction rootinfos()\n    local results = {}\n\n    -- get template directories from global repositories\n    local repos = repository.repositories({global = true, network = false})\n    if repos then\n        for _, repo in ipairs(repos) do\n            local templatesdir = path.join(repo:directory(), \"templates\")\n            if os.isdir(templatesdir) then\n                table.insert(results, {kind = \"repo\", name = repo:name(), url = repo:url(), branch = repo:branch(), dir = templatesdir})\n            end\n        end\n    end\n\n    -- get template directories from global and builtin\n    local dir = path.join(global.directory(), \"templates\")\n    if os.isdir(dir) then\n        table.insert(results, {kind = \"global\", dir = dir})\n    end\n    return results\nend\n\n-- get template root directories\nfunction rootdirs()\n    local results = {}\n    for _, info in ipairs(rootinfos()) do\n        table.insert(results, info.dir)\n    end\n    return results\nend\n\n-- get template root directory\nfunction _templateid_subdir(templateid)\n    local items = templateid:split(\".\", {plain = true})\n    if not items or #items == 0 then\n        return\n    end\n    for _, item in ipairs(items) do\n        if #item == 0 then\n            return\n        end\n    end\n    return path.join(table.unpack(items))\nend\n\nfunction templatedir(lang, templateid)\n    assert(lang)\n    assert(templateid)\n    for _, rootdir in ipairs(rootdirs()) do\n        local subdir = _templateid_subdir(templateid)\n        if subdir then\n            local dir = path.join(rootdir, lang, subdir)\n            if os.isfile(path.join(dir, \"xmake.lua\")) then\n                return dir\n            end\n        end\n    end\nend\n\n-- copy template files to project directory\nfunction copy_files(sourcedir, projectdir)\n    local createdfiles = {}\n    for _, srcfile in ipairs(os.files(path.join(sourcedir, \"**\"))) do\n        local relpath = path.relative(srcfile, sourcedir)\n        local dstfile = path.absolute(path.join(projectdir, relpath))\n        os.mkdir(path.directory(dstfile))\n        os.cp(srcfile, dstfile, {writeable = true})\n        table.insert(createdfiles, dstfile)\n    end\n    return createdfiles\nend\n\n-- only replace variables in template source files and xmake.lua\nfunction _need_replace_variables(filepath)\n    if not os.isfile(filepath) then\n        return false\n    end\n    if path.filename(filepath):lower() == \"xmake.lua\" then\n        return true\n    end\n    local extension = path.extension(filepath)\n    if extension then\n        return language.extensions()[extension:lower()] ~= nil\n    end\nend\n\n-- replace variables in files\nfunction replace_variables_in_files(files, vars)\n    local pattern = \"%${(.-)}\"\n    for _, file in ipairs(files) do\n        if _need_replace_variables(file) then\n            io.gsub(file, \"(\" .. pattern .. \")\", function(_, variable)\n                variable = variable:trim()\n                local value = vars[variable]\n                if value == nil then\n                    return \"${\" .. variable .. \"}\"\n                end\n                return type(value) == \"function\" and value() or tostring(value)\n            end, {encoding = \"binary\"})\n        end\n    end\nend\n\n-- get all languages from templates\nfunction languages()\n    local found = hashset.new()\n    for _, rootdir in ipairs(rootdirs()) do\n        local languages_dirs = os.dirs(path.join(rootdir, \"*\"))\n        if languages_dirs then\n            for _, d in ipairs(languages_dirs) do\n                found:insert(path.filename(d))\n            end\n        end\n    end\n    local results = found:to_array()\n    table.sort(results)\n    return results\nend\n\n-- get all templates for the given language\nfunction templates(lang)\n    assert(lang)\n    local found = hashset.new()\n    for _, rootdir in ipairs(rootdirs()) do\n        local templateroot = path.join(rootdir, lang)\n        local configfiles = os.files(path.join(templateroot, \"**\", \"xmake.lua\"))\n        if configfiles then\n            local templatedirs = {}\n            for _, configfile in ipairs(configfiles) do\n                local templatedir = path.directory(configfile)\n                local relpath = path.relative(templatedir, templateroot)\n                if relpath and relpath ~= \".\" then\n                    table.insert(templatedirs, {dir = templatedir, relpath = relpath})\n                end\n            end\n            table.sort(templatedirs, function(a, b) return #a.relpath < #b.relpath end)\n            local accepted = {}\n            for _, item in ipairs(templatedirs) do\n                local ok = true\n                for _, root in ipairs(accepted) do\n                    if item.dir:startswith(root .. path.sep()) then\n                        ok = false\n                        break\n                    end\n                end\n                if ok then\n                    table.insert(accepted, item.dir)\n                    found:insert((item.relpath:gsub(\"[/\\\\]\", \".\")))\n                end\n            end\n        end\n    end\n    local results = found:to_array()\n    table.sort(results)\n    return results\nend\n\n-- get languages for the given template\nfunction languages_for_template(templateid)\n    local accepted = {}\n    for _, lang in ipairs(languages()) do\n        if templatedir(lang, templateid) then\n            table.insert(accepted, lang)\n        end\n    end\n    return accepted\nend\n\n-- get templates with all supported languages\nfunction templates_with_languages()\n    local templates_map = {}\n    for _, lang in ipairs(languages()) do\n        for _, name in ipairs(templates(lang)) do\n            templates_map[name] = templates_map[name] or {}\n            if not table.contains(templates_map[name], lang) then\n                table.insert(templates_map[name], lang)\n            end\n        end\n    end\n    return templates_map\nend\n"
  },
  {
    "path": "xmake/actions/create/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"create\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake create [options] [target]\",\n        description = \"Create a new project.\",\n        options = {\n            {'f', \"force\",      \"k\",   nil,         \"Force to create project in a non-empty directory.\"},\n            {nil, \"list\",       \"k\",   nil,         \"List all templates for each language.\"\n                                                  , \"    e.g.\"\n                                                  , \"    - xmake create --list\"\n                                                  , \"    - xmake create --list -l c++\"},\n            {'l', \"language\",   \"kv\", \"c++\",        \"The project language\",\n                                                    values = function (complete, opt)\n                                                        import(\"actions.create.template\", {rootdir = os.programdir()})\n\n                                                        local languages = template.languages()\n                                                        if not complete or not opt.template then\n                                                            return languages\n                                                        end\n                                                        return template.languages_for_template(opt.template)\n                                                    end                                                             },\n            {'t', \"template\",   \"kv\", \"console\",    \"Select the project template id or name of the given language.\",\n                                                    \"    Use `xmake create --list` to view all templates.\",\n                                                    values = function (complete, opt)\n                                                        if complete then\n                                                            import(\"actions.create.template\", {rootdir = os.programdir()})\n                                                            import(\"core.base.hashset\")\n                                                            local templates_set = hashset.new()\n                                                            local languages = opt.language and {opt.language} or template.languages()\n                                                            for _, l in ipairs(languages) do\n                                                                for _, t in ipairs(template.templates(l)) do\n                                                                    templates_set:insert(t)\n                                                                end\n                                                            end\n                                                            local templates = templates_set:to_array()\n                                                            table.sort(templates)\n                                                            return templates\n                                                        end\n                                                    end},\n            {},\n            {nil, \"target\",     \"v\",  nil,          \"Create the given target.\"\n                                                  , \"Uses the project name as target if not exists.\"}\n        }\n    }\n"
  },
  {
    "path": "xmake/actions/global/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.theme.theme\")\nimport(\"core.cache.global_detectcache\")\nimport(\"menuconf\", {alias = \"menuconf_show\"})\n\n-- main\nfunction main()\n\n    -- enter menu config\n    if option.get(\"menu\") then\n        menuconf_show()\n    end\n\n    -- load the global configure\n    --\n    -- priority: option > option_default > config_check > global_cache\n    --\n    if option.get(\"clean\") then\n        global.clear()\n    end\n\n    -- override the option configure\n    local changed = false\n    for name, value in pairs(option.options()) do\n        if name ~= \"verbose\" then\n            -- the config value is changed by argument options?\n            changed = changed or global.get(name) ~= value\n\n            -- @note override it and mark as readonly\n            global.set(name, value, {readonly = true})\n        end\n    end\n\n    -- merge the default options\n    for name, value in pairs(option.defaults()) do\n        if name ~= \"verbose\" and global.get(name) == nil then\n            global.set(name, value)\n        end\n    end\n\n    -- load and check theme\n    local themename = option.get(\"theme\")\n    if themename then\n        theme.load(themename)\n    end\n\n    -- save it\n    global.save()\n\n    -- clear detect cache\n    if option.get(\"clean\") or option.get(\"check\") then\n        global_detectcache:clear()\n        global_detectcache:save()\n    end\n\n    -- dump it\n    global.dump()\nend\n"
  },
  {
    "path": "xmake/actions/global/menuconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menuconf.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.view\")\nimport(\"core.ui.label\")\nimport(\"core.ui.event\")\nimport(\"core.ui.action\")\nimport(\"core.ui.menuconf\")\nimport(\"core.ui.mconfdialog\")\nimport(\"core.ui.application\")\n\n-- the app application\nlocal app = application()\n\n-- init app\nfunction app:init()\n\n    -- init name\n    application.init(self, \"app.config\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- insert menu config dialog\n    self:insert(self:mconfdialog())\n\n    -- load configs\n    self:load()\nend\n\n-- get menu config dialog\nfunction app:mconfdialog()\n    if not self._MCONFDIALOG then\n        local mconfdialog = mconfdialog:new(\"app.config.mconfdialog\", rect {1, 1, self:width() - 1, self:height() - 1}, \"menu config\")\n        mconfdialog:action_set(action.ac_on_exit, function (v)\n            self:quit()\n            os.exit()\n        end)\n        mconfdialog:action_set(action.ac_on_save, function (v)\n            self:save()\n            self:quit()\n        end)\n        self._MCONFDIALOG = mconfdialog\n    end\n    return self._MCONFDIALOG\nend\n\n-- on resize\nfunction app:on_resize()\n    self:mconfdialog():bounds_set(rect{1, 1, self:width() - 1, self:height() - 1})\n    application.on_resize(self)\nend\n\n-- filter option\nfunction app:_filter_option(name)\n    local options =\n    {\n        file        = true\n    ,   root        = true\n    ,   yes         = true\n    ,   quiet       = true\n    ,   confirm     = true\n    ,   project     = true\n    ,   verbose     = true\n    ,   diagnosis   = true\n    ,   version     = true\n    ,   help        = true\n    ,   clean       = true\n    ,   menu        = true\n    ,   check       = true\n    }\n    return not options[name]\nend\n\n-- get or make menu by category\nfunction app:_menu_by_category(root, configs, menus, category)\n\n    -- is root?\n    if category == \".\" or category == \"\" then\n        return\n    end\n\n    -- attempt to get menu first\n    local menu = menus[category]\n    if not menu then\n\n        -- get config path\n        local parentdir = path.directory(category)\n        local config_path = path.join(root, parentdir == \".\" and \"\" or parentdir)\n\n        -- make a new menu\n        menu = menuconf.menu {name = category, path = config_path, description = path.basename(category), configs = {}}\n        menus[category] = menu\n\n        -- insert to the parent or root configs\n        local parent = self:_menu_by_category(root, configs, menus, parentdir)\n        table.insert(parent and parent.configs or configs, menu)\n    end\n    return menu\nend\n\n-- make configs by category\nfunction app:_make_configs_by_category(root, options_by_category, cache, get_option_info)\n\n    -- make configs category\n    --\n    -- root category: \".\"\n    -- category path: \"a\", \"a/b\", \"a/b/c\" ...\n    --\n    local menus = {}\n    local configs = {}\n    for category, options in pairs(options_by_category) do\n\n        -- get or make menu by category\n        local menu = self:_menu_by_category(root, configs, menus, category)\n\n        -- get sub-configs\n        local subconfigs = menu and menu.configs or configs\n\n        -- insert options to sub-configs\n        for _, opt in ipairs(options) do\n\n            -- get option info\n            local info = get_option_info(opt)\n\n            -- new value?\n            local newvalue = true\n\n            -- load value\n            local value = nil\n            if cache then\n                value = global.get(info.name)\n                if value ~= nil and info.kind == \"choice\" and info.values then\n                    for idx, val in ipairs(info.values) do\n                        if value == val then\n                            value = idx\n                            break\n                        end\n                    end\n                end\n                if value ~= nil then\n                    newvalue = false\n                end\n            end\n\n            -- find the menu index in subconfigs\n            local menu_index = #subconfigs + 1\n            for idx, subconfig in ipairs(subconfigs) do\n                if subconfig.kind == \"menu\" then\n                    menu_index = idx\n                    break\n                end\n            end\n\n            -- get config path\n            local config_path = path.join(root, category == \".\" and \"\" or category)\n\n            -- insert config before all sub-menus\n            if info.kind == \"string\" then\n                table.insert(subconfigs, menu_index, menuconf.string {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo})\n            elseif info.kind == \"boolean\" then\n                table.insert(subconfigs, menu_index, menuconf.boolean {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, description = info.description, sourceinfo = info.sourceinfo})\n            elseif info.kind == \"choice\" then\n                table.insert(subconfigs, menu_index, menuconf.choice {name = info.name, value = value, new = newvalue, default = info.default, path = config_path, values = info.values, description = info.description, sourceinfo = info.sourceinfo})\n            end\n        end\n    end\n\n    -- done\n    return configs\nend\n\n-- get global configs\nfunction app:_global_configs(cache)\n\n    -- get configs from the cache first\n    local configs = self._GLOBAL_CONFIGS\n    if configs then\n        return configs\n    end\n\n    -- get config menu\n    local menu = option.taskmenu(\"global\")\n\n    -- merge options by category\n    local category = \".\"\n    local options = menu and menu.options or {}\n    local options_by_category = {}\n    for _, opt in pairs(options) do\n        local name = opt[2] or opt[1]\n        if name and self:_filter_option(name) then\n            options_by_category[category] = options_by_category[category] or {}\n            table.insert(options_by_category[category], opt)\n        elseif opt.category then\n            category = opt.category\n        end\n    end\n\n    -- make configs by category\n    self._GLOBAL_CONFIGS = self:_make_configs_by_category(\"Global Configuration\", options_by_category, cache, function (opt)\n\n        -- get default\n        local default = opt[4]\n\n        -- get kind\n        local kind = (opt[3] == \"k\" or type(default) == \"boolean\") and \"boolean\" or \"string\"\n\n        -- choice option?\n        local values = opt.values\n        if values then\n            if type(values) == \"function\" then\n                values = values()\n            end\n            values = table.wrap(values)\n            for idx, value in ipairs(values) do\n                if default == value then\n                    default = idx\n                    break\n                end\n            end\n        end\n        if values then\n            kind = \"choice\"\n        end\n\n        -- get description\n        local description = {}\n        for i = 5, 64 do\n            local desc = opt[i]\n            if type(desc) == \"function\" then\n                desc = desc()\n            end\n            if type(desc) == \"string\" then\n                table.insert(description, desc)\n            elseif type(desc) == \"table\" then\n                table.join2(description, desc)\n            else\n                break\n            end\n        end\n\n        -- make option info\n        return {name = opt[2] or opt[1], kind = kind, default = default, values = values, description = description}\n    end)\n    return self._GLOBAL_CONFIGS\nend\n\n-- save the given configs\nfunction app:_save_configs(configs)\n    local options = option.options()\n    for _, conf in pairs(configs) do\n        if conf.kind == \"menu\" then\n            self:_save_configs(conf.configs)\n        elseif not conf.new and (conf.kind == \"boolean\" or conf.kind == \"string\") then\n            options[conf.name] = conf.value\n        elseif not conf.new and (conf.kind == \"choice\") then\n            options[conf.name] = conf.values[conf.value]\n        end\n    end\nend\n\n-- load configs from options\nfunction app:load()\n\n    -- clean the global configuration\n    if option.get(\"clean\") then\n        global.clear()\n    end\n\n    -- clear configs first\n    self._GLOBAL_CONFIGS = nil\n\n    -- load configs\n    local configs = {}\n    table.insert(configs, menuconf.menu {description = \"Global Configuration\", configs = self:_global_configs(cache)})\n    self:mconfdialog():load(configs)\n\n    -- the previous config is only for loading menuconf, so clear config now\n    if option.get(\"clean\") then\n        global.clear()\n    end\nend\n\n-- save configs to options\nfunction app:save()\n    self:_save_configs(self:_global_configs())\nend\n\n-- main entry\nfunction main(...)\n    app:run(...)\nend\n"
  },
  {
    "path": "xmake/actions/global/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"global\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n                usage = \"xmake global|g [options] [target]\",\n                description = \"Configure the global options for xmake.\",\n                shortname = 'g',\n                options = {\n                    {'c', \"clean\",          \"k\",  nil       , \"Clean the cached user configs and detection cache.\"},\n                    {nil, \"check\",          \"k\",  nil       , \"Just ignore detection cache and force to check all, it will reserve the cached user configs.\"},\n                    {nil, \"menu\",           \"k\" , nil       , \"Configure with a menu-driven user interface.\"              },\n                    {category = \".\"},\n                    {nil, \"theme\",          \"kv\", \"default\" , \"The theme name.\"\n                                                          , values = function ()\n                                                               return import(\"core.theme.theme.names\")()\n                                                           end},\n                    {nil, \"debugger\",       \"kv\", \"auto\"    , \"The debugger program path.\"                                },\n                    {nil, \"ccache\",         \"kv\", nil       , \"Enable or disable the c/c++ compiler cache.\"               },\n                    {category = \"Build Configuration\"},\n                    {nil, \"cachedir\",       \"kv\", nil       , \"The global cache directory.\"                               },\n                    {nil, \"policies\",       \"kv\", nil       , \"Set the global project policies.\",\n                                                            \"    e.g.\",\n                                                            \"    - xmake g --policies=run.autobuild\",\n                                                            \"    - xmake g --policies=build.warning:n\"                      },\n                    -- network configuration\n                    {category = \"Network Configuration\"},\n                    {nil, \"network\",        \"kv\", \"public\" , \"Set the network mode.\"\n                                                           , values = {\"public\", \"private\"}                               },\n                    {nil, \"insecure-ssl\",   \"kv\", nil      , \"Disable to check ssl certificates for downloading.\"         },\n                    {'x', \"proxy\",          \"kv\", nil      , \"Use proxy on given port. [protocol://]host[:port]\"\n                                                           , \"    e.g.\"\n                                                           , \"    - xmake g --proxy='http://host:port'\"\n                                                           , \"    - xmake g --proxy='https://host:port'\"\n                                                           , \"    - xmake g --proxy='socks5://host:port'\"                },\n                    {nil, \"proxy_hosts\",    \"kv\", nil       , \"Only enable proxy for the given hosts list, it will enable all if be unset,\"\n                                                           , \"and we can pass match pattern to list:\"\n                                                           , \"    e.g.\"\n                                                           , \"    - xmake g --proxy_hosts='github.com,gitlab.*,*.xmake.io'\"},\n                    {nil, \"proxy_pac\",      \"kv\", \"pac.lua\" , \"Set the auto proxy configuration file.\"\n                                                           , \"    e.g.\"\n                                                           , \"    - xmake g --proxy_pac=pac.lua (in $(globaldir) or absolute path)\"\n                                                           , \"    - function main(url, host)\"\n                                                           , \"          if host == 'github.com' then\"\n                                                           , \"               return true\"\n                                                           , \"          end\"\n                                                           , \"      end\"\n                                                           , \"\"\n                                                           , \"Builtin pac files:\"\n                                                           , function ()\n                                                                local description = {}\n                                                                local pacfiles = os.files(path.join(os.programdir(), \"scripts\", \"pac\", \"*.lua\"))\n                                                                for _, pacfile in ipairs(pacfiles) do\n                                                                    table.insert(description, \"    - \" .. path.filename(pacfile))\n                                                                end\n                                                                return description\n                                                             end},\n\n                    -- package configuration\n                    {category = \"Package Configuration\"},\n                    {nil, \"pkg_searchdirs\", \"kv\", nil      , \"The search directories of the remote package.\"\n                                                           , \"    e.g.\"\n                                                           , \"    - xmake g --pkg_searchdirs=/dir1\" .. path.envsep() .. \"/dir2\"},\n                    {nil, \"pkg_cachedir\",   \"kv\", nil      , \"The cache root directory of the remote package.\"},\n                    {nil, \"pkg_installdir\", \"kv\", nil      , \"The install root directory of the remote package.\"},\n\n                    -- show platform menu options\n                    {category = \"Platform Configuration\"},\n                    function ()\n                       import(\"core.platform.menu\")\n                       return menu.options(\"global\")\n                    end\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/actions/install/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"core.project.rule\")\nimport(\"core.project.project\")\nimport(\"target.action.install\", {alias = \"_do_install_target\"})\n\n-- on install target\nfunction _on_install_target(target)\n\n    -- trace\n    print(\"installing %s ..\", target:name())\n\n    -- build target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_install = r:script(\"install\")\n        if on_install then\n            on_install(target)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do install\n    _do_install_target(target, {\n        headers = option.get(\"headers\"),\n        binaries = option.get(\"binaries\"),\n        libraries = option.get(\"libraries\"),\n        packages = option.get(\"packages\")})\nend\n\n-- install the given target\nfunction _install_target(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"install_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_install = r:script(\"install_before\")\n                if before_install then\n                    before_install(target)\n                end\n            end\n        end\n    ,   target:script(\"install\", _on_install_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_install = r:script(\"install_after\")\n                if after_install then\n                    after_install(target)\n                end\n            end\n        end\n    ,   target:script(\"install_after\")\n    }\n\n    -- install the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n\n    -- leave project directory\n    os.cd(oldir)\nend\n\n-- install the given targets\nfunction _install_targets(targets)\n    for _, target in ipairs(targets) do\n        _install_target(target)\n    end\nend\n\n-- install targets\nfunction main(targetname, group_pattern)\n    local targets = {}\n    if targetname and not targetname:startswith(\"__\") then\n        local target = project.target(targetname)\n        table.insert(targets, target)\n    else\n        for _, target in ipairs(project.ordertargets()) do\n            local group = target:get(\"group\")\n            if (target:is_default() and not group_pattern) or targetname == \"__all\" or (group_pattern and group and group:match(group_pattern)) then\n                table.insert(targets, target)\n            end\n        end\n    end\n    if #targets > 0 then\n        _install_targets(table.unique(targets))\n    end\nend\n"
  },
  {
    "path": "xmake/actions/install/install_admin.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_admin.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"install\")\n\nfunction main(targetname, group_pattern, installdir, bindir, libdir, includedir)\n    local verbose = option.get(\"verbose\")\n    if group_pattern and #group_pattern == 0 then\n        group_pattern = nil\n    end\n    if installdir and #installdir == 0 then\n        installdir = nil\n    end\n    if bindir and #bindir == 0 then\n        bindir = nil\n    end\n    if libdir and #libdir == 0 then\n        libdir = nil\n    end\n    if includedir and #includedir == 0 then\n        includedir = nil\n    end\n\n    os.cd(project.directory())\n    config.load()\n    platform.load(config.plat())\n\n    -- save the current option and push a new option context\n    option.save()\n    option.set(\"verbose\", verbose)\n    if installdir then\n        option.set(\"installdir\", installdir)\n    end\n    if bindir then\n        option.set(\"bindir\", bindir)\n    end\n    if libdir then\n        option.set(\"libdir\", libdir)\n    end\n    if includedir then\n        option.set(\"includedir\", includedir)\n    end\n\n    -- install target\n    install(targetname, group_pattern)\n    option.restore()\nend\n"
  },
  {
    "path": "xmake/actions/install/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.base.privilege\")\nimport(\"privilege.sudo\")\nimport(\"install\")\nimport(\"private.action.utils\", {alias = \"action_utils\"})\n\n-- check targets\nfunction _check_targets(targetname, group_pattern)\n\n    -- get targets\n    local targets = {}\n    if targetname then\n        table.insert(targets, project.target(targetname))\n    else\n        -- install default or all targets\n        for _, target in pairs(project.targets()) do\n            local group = target:get(\"group\")\n            if (target:is_default() and not group_pattern) or option.get(\"all\") or (group_pattern and group and group:match(group_pattern)) then\n                table.insert(targets, target)\n            end\n        end\n    end\n\n    -- filter and check targets with builtin-install script\n    local targetnames = {}\n    for _, target in ipairs(targets) do\n        if target:targetfile() and target:is_enabled() and not target:script(\"install\") then\n            local targetfile = target:targetfile()\n            if targetfile and not os.isfile(targetfile) then\n                table.insert(targetnames, target:name())\n            end\n        end\n    end\n\n    -- there are targets that have not yet been built?\n    if #targetnames > 0 then\n        raise(\"please run `$xmake build [target]` to build the following targets first:\\n  -> \" .. table.concat(targetnames, '\\n  -> '))\n    end\nend\n\nfunction main()\n\n    -- load config first\n    task.run(\"config\", {require = false}, {disable_dump = true})\n\n    -- check targets first\n    local targetname, group_pattern = action_utils.get_target_and_group()\n    _check_targets(targetname, group_pattern)\n\n    -- attempt to install directly\n    try\n    {\n        function ()\n            install(targetname or (option.get(\"all\") and \"__all\" or \"__def\"), group_pattern)\n            cprint(\"${color.success}install ok!\")\n        end,\n\n        catch\n        {\n            -- failed or not permission? request administrator permission and install it again\n            function (errors)\n\n                -- try get privilege\n                if privilege.get() then\n                    local ok = try\n                    {\n                        function ()\n                            install(targetname or (option.get(\"all\") and \"__all\" or \"__def\"), group_pattern)\n                            cprint(\"${color.success}install ok!\")\n                            return true\n                        end\n                    }\n\n                    -- release privilege\n                    privilege.store()\n                    if ok then\n                        return\n                    end\n                end\n\n                -- continue to install with administrator permission?\n                local ok = false\n                if sudo.has() and option.get(\"admin\") then\n\n                    -- install target with administrator permission\n                    sudo.execl(path.join(os.scriptdir(), \"install_admin.lua\"), {\n                        targetname or (option.get(\"all\") and \"__all\" or \"__def\"),\n                        group_pattern or \"\", option.get(\"installdir\") or \"\",\n                        option.get(\"bindir\"),\n                        option.get(\"libdir\"),\n                        option.get(\"includedir\")})\n                    cprint(\"${color.success}install ok!\")\n                    ok = true\n                end\n                if not ok then\n                    local syserror = os.syserror()\n                    if syserror == os.SYSERR_NOT_PERM or syserror == os.SYSERR_NOT_ACCESS then\n                        wprint(\"please pass the --admin parameter to `xmake install` to request administrator permissions!\")\n                    end\n                end\n                assert(ok, \"install failed, %s\", errors or \"unknown reason\")\n            end\n        }\n    }\nend\n"
  },
  {
    "path": "xmake/actions/install/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"install\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake install|i [options] [target]\",\n        description = \"Package and install the target binary files.\",\n        shortname = 'i',\n        options = {\n            {'o', \"installdir\", \"kv\", nil   , \"Set the install directory.\",\n                                              \"e.g.\",\n                                              \"    $ xmake install -o /usr/local\",\n                                              \"or  $ DESTDIR=/usr/local xmake install\",\n                                              \"or  $ INSTALLDIR=/usr/local xmake install\" },\n            {nil, \"bindir\",     \"kv\", nil   , \"Set install binaries directory in INSTALLDIR/DIR. (default: ${installdir}/bin)\"},\n            {nil, \"libdir\",     \"kv\", nil   , \"Set install libraries directory in INSTALLDIR/DIR. (default: ${installdir}/lib)\"},\n            {nil, \"includedir\", \"kv\", nil   , \"Set install includes directory in INSTALLDIR/DIR. (default: ${installdir}/include)\"},\n            {'g', \"group\",      \"kv\",  nil  , \"Install all targets of the given group. It support path pattern matching.\",\n                                              \"e.g.\",\n                                              \"    xmake install -g test\",\n                                              \"    xmake install -g test_*\",\n                                              \"    xmake install --group=benchmark/*\"     },\n            {'a', \"all\",        \"k\",  nil   , \"Install all targets.\"                      },\n            {nil, \"binaries\",   \"kv\", true  , \"Enable or disable install binary files.\"   },\n            {nil, \"headers\",    \"kv\", true  , \"Enable or disable install header files.\"   },\n            {nil, \"libraries\",  \"kv\", true  , \"Enable or disable install library files.\"  },\n            {nil, \"packages\",   \"kv\", true  , \"Enable or disable install package files.\"  },\n            {},\n            {nil, \"admin\",      \"k\",  nil   , \"Try to request administrator permission to install\"},\n            {},\n            {nil, \"target\",     \"v\",  nil   , \"The target name. It will install all default targets if this parameter is not specified.\",\n                                              values = function (complete, opt)\n                                                  return import(\"private.utils.complete_helper.targets\")(complete, opt)\n                                              end}\n        }\n    }\n\n"
  },
  {
    "path": "xmake/actions/package/local/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"target.action.install\")\nimport(\"private.detect.check_targetname\")\n\n-- get library deps\nfunction _get_librarydeps(target)\n    local librarydeps = {}\n    for _, depname in ipairs(target:get(\"deps\")) do\n        local dep = project.target(depname, {namespace = target:namespace()})\n        if not ((target:is_binary() or target:is_shared()) and dep:is_static()) then\n            table.insert(librarydeps, dep:name():lower())\n        end\n    end\n    return librarydeps\nend\n\n-- do package target\nfunction _do_package_target(target)\n    if target:is_phony() then\n        return\n    end\n\n    -- do install\n    local packagedir  = target:packagedir()\n    local installdir  = path.join(packagedir, target:plat(), target:arch(), config.mode())\n    install(target, {installdir = installdir, libdir = \"lib\", bindir = \"bin\", includedir = \"include\"})\n\n    -- generate xmake.lua\n    local packagename = target:name():lower()\n    local file = io.open(path.join(packagedir, \"xmake.lua\"), \"w\")\n    if file then\n        file:print(\"package(\\\"%s\\\")\", packagename)\n        if target:is_binary() then\n            file:print(\"    set_kind(\\\"binary\\\")\")\n        elseif target:is_headeronly() then\n            file:print(\"    set_kind(\\\"library\\\", {headeronly = true})\")\n        elseif target:is_moduleonly() then\n            file:print(\"    set_kind(\\\"library\\\", {moduleonly = true})\")\n        end\n        local homepage = option.get(\"homepage\")\n        if homepage then\n            file:print(\"    set_homepage(\\\"%s\\\")\", homepage)\n        end\n        local description = option.get(\"description\") or (\"The \" .. packagename .. \" package\")\n        file:print(\"    set_description(\\\"%s\\\")\", description)\n        if target:license() then\n            file:print(\"    set_license(\\\"%s\\\")\", target:license())\n        end\n        file:print(\"\")\n        local has_deps = false\n        local deps = _get_librarydeps(target)\n        if #deps > 0 then\n            file:print(\"    add_deps(\\\"%s\\\")\", table.concat(deps, \"\\\", \\\"\"))\n            has_deps = true\n        end\n        -- export packages as deps, @see https://github.com/xmake-io/xmake/issues/4202\n        if target:is_library() then\n            local interface\n            if target:is_shared() then\n                interface = true\n            end\n            for _, pkg in ipairs(target:orderpkgs({interface = interface})) do\n                local requireconf_str\n                local requireconf = pkg:requireconf()\n                if requireconf then\n                    local conf = table.clone(requireconf)\n                    conf.alias = nil\n                    requireconf_str = string.serialize(conf, {indent = false, strip = true})\n                end\n                if requireconf_str and requireconf_str ~= \"{}\" then\n                    file:print(\"    add_deps(\\\"%s\\\", %s)\", pkg:requirestr(), requireconf_str)\n                else\n                    file:print(\"    add_deps(\\\"%s\\\")\", pkg:requirestr())\n                end\n                has_deps = true\n            end\n        end\n        if has_deps then\n            file:print(\"\")\n        end\n\n        if target:is_library() and not target:is_headeronly() and not target:is_moduleonly() then\n            file:print([[    add_configs(\"shared\", {description = \"Build shared library.\", default = %s, type = \"boolean\", readonly = true})]], target:is_shared() and \"true\" or \"false\")\n            file:print(\"\")\n        end\n        file:print([[\n    on_load(function (package)\n        package:set(\"installdir\", path.join(os.scriptdir(), package:plat(), package:arch(), package:mode()))\n    end)\n]])\n        if target:is_binary() then\n            file:print([[\n    on_fetch(function (package)\n        return {program = path.join(package:installdir(\"bin\"), \"%s\")}\n    end)]], path.filename(target:targetfile()))\n        elseif target:is_headeronly() or target:is_moduleonly() then\n            file:print([[\n    on_fetch(function (package)\n        local result = {}\n        result.includedirs = package:installdir(\"include\")\n        return result\n    end)]])\n        elseif target:is_library() then\n            file:print([[\n    on_fetch(function (package)\n        local result = {}\n        local libfiledir = (package:config(\"shared\") and package:is_plat(\"windows\", \"mingw\")) and \"bin\" or \"lib\"\n        result.links = \"%s\"\n        result.linkdirs = package:installdir(\"lib\")\n        result.includedirs = package:installdir(\"include\")\n        result.libfiles = path.join(package:installdir(libfiledir), \"%s\")\n        return result\n    end)]], target:linkname(), path.filename(target:targetfile()))\n        end\n\n        file:close()\n    end\n    print(\"package(%s): %s generated\", packagename, packagedir)\nend\n\n-- package target\nfunction _on_package_target(target)\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_package = r:script(\"package\")\n        if on_package then\n            on_package(target)\n            done = true\n        end\n    end\n    if done then return end\n    _do_package_target(target)\nend\n\n-- package the given target\nfunction _package_target(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"package_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_package = r:script(\"package_before\")\n                if before_package then\n                    before_package(target)\n                end\n            end\n        end\n    ,   target:script(\"package\", _on_package_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_package = r:script(\"package_after\")\n                if after_package then\n                    after_package(target)\n                end\n            end\n        end\n    ,   target:script(\"package_after\")\n    }\n\n    -- package the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n\n    -- leave project directory\n    os.cd(oldir)\nend\n\n-- package the given targets\nfunction _package_targets(targets)\n    for _, target in ipairs(targets) do\n        _package_target(target)\n    end\nend\n\n-- main\nfunction main()\n\n    -- lock the whole project\n    project.lock()\n\n    -- get the target name\n    local targetname = option.get(\"target\")\n\n    -- build it first\n    task.run(\"build\", {target = targetname, all = option.get(\"all\")})\n\n    -- package the given target?\n    if targetname then\n        local target = assert(check_targetname(targetname))\n        _package_target(target)\n    else\n        -- package default or all targets\n        for _, target in ipairs(project.ordertargets()) do\n            if target:is_default() or option.get(\"all\") then\n                _package_target(target)\n            end\n        end\n    end\n\n    -- unlock the whole project\n    project.unlock()\nend\n"
  },
  {
    "path": "xmake/actions/package/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\n\n-- main entry\nfunction main()\n    local format = option.get(\"format\") or \"local\"\n    local maps = hashset.from({\"local\", \"remote\", \"oldpkg\"})\n    if maps:has(format) then\n        import(format)()\n    else\n        raise(\"invalid package format: %s\", format or \"missing\")\n    end\nend\n"
  },
  {
    "path": "xmake/actions/package/oldpkg/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.detect.check_targetname\")\n\n-- package library\nfunction _package_library(target)\n\n    -- the output directory\n    local outputdir = option.get(\"outputdir\") or config.builddir()\n\n    -- the target name\n    local targetname = target:name()\n\n    -- copy the library file to the output directory\n    if not target:is_headeronly() then\n        os.vcp(target:targetfile(), format(\"%s/%s.pkg/$(plat)/$(arch)/lib/$(mode)/%s\", outputdir, targetname, path.filename(target:targetfile())))\n\n        -- copy the symbol file to the output directory\n        local symbolfile = target:symbolfile()\n        if os.isfile(symbolfile) then\n            os.vcp(symbolfile, format(\"%s/%s.pkg/$(plat)/$(arch)/lib/$(mode)/%s\", outputdir, targetname, path.filename(symbolfile)))\n        end\n    end\n\n    -- copy *.lib for shared/windows (*.dll) target\n    -- @see https://github.com/xmake-io/xmake/issues/787\n    local target_implib = target:artifactfile(\"implib\")\n    if target_implib and os.isfile(target_implib) then\n        os.vcp(target_implib, format(\"%s/%s.pkg/$(plat)/$(arch)/lib/$(mode)/\", outputdir, targetname))\n    end\n\n    -- copy headers\n    local srcheaders, dstheaders = target:headerfiles(format(\"%s/%s.pkg/$(plat)/$(arch)/include\", outputdir, targetname))\n    if srcheaders and dstheaders then\n        local i = 1\n        for _, srcheader in ipairs(srcheaders) do\n            local dstheader = dstheaders[i]\n            if dstheader then\n                os.vcp(srcheader, dstheader)\n            end\n            i = i + 1\n        end\n    end\n\n    -- make xmake.lua\n    local file = io.open(format(\"%s/%s.pkg/xmake.lua\", outputdir, targetname), \"w\")\n    if file then\n        file:print(\"option(\\\"%s\\\")\", targetname)\n        file:print(\"    set_showmenu(true)\")\n        file:print(\"    set_category(\\\"package\\\")\")\n        if not target:is_headeronly() then\n            file:print(\"    add_links(\\\"%s\\\")\", target:basename())\n            file:write(\"    add_linkdirs(\\\"$(plat)/$(arch)/lib/$(mode)\\\")\\n\")\n        end\n        file:write(\"    add_includedirs(\\\"$(plat)/$(arch)/include\\\")\\n\")\n        local languages = target:get(\"languages\")\n        if languages then\n            file:print(\"    set_languages(\\\"%s\\\")\", table.concat(table.wrap(languages), \"\\\", \\\"\"))\n        end\n        file:close()\n    end\nend\n\n-- do package target\nfunction _do_package_target(target)\n    if not target:is_phony() then\n        local scripts =\n        {\n            binary     = function (target) end\n        ,   static     = _package_library\n        ,   shared     = _package_library\n        ,   headeronly = _package_library\n        }\n        local kind = target:kind()\n        local script = scripts[kind]\n        if script then\n            script(target)\n        end\n    end\nend\n\n-- package target\nfunction _on_package_target(target)\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_package = r:script(\"package\")\n        if on_package then\n            on_package(target)\n            done = true\n        end\n    end\n    if done then return end\n    _do_package_target(target)\nend\n\n-- package the given target\nfunction _package_target(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"package_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_package = r:script(\"package_before\")\n                if before_package then\n                    before_package(target)\n                end\n            end\n        end\n    ,   target:script(\"package\", _on_package_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_package = r:script(\"package_after\")\n                if after_package then\n                    after_package(target)\n                end\n            end\n        end\n    ,   target:script(\"package_after\")\n    }\n\n    -- package the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n\n    -- leave project directory\n    os.cd(oldir)\nend\n\n-- package the given targets\nfunction _package_targets(targets)\n    for _, target in ipairs(targets) do\n        _package_target(target)\n    end\nend\n\n-- main\nfunction main()\n\n    -- lock the whole project\n    project.lock()\n\n    -- get the target name\n    local targetname = option.get(\"target\")\n\n    -- build it first\n    task.run(\"build\", {target = targetname, all = option.get(\"all\")})\n\n    -- package the given target?\n    if targetname then\n        local target = assert(check_targetname(targetname))\n        _package_targets(target:orderdeps())\n        _package_target(target)\n    else\n        -- package default or all targets\n        for _, target in ipairs(project.ordertargets()) do\n            if target:is_default() or option.get(\"all\") then\n                _package_target(target)\n            end\n        end\n    end\n\n    -- unlock the whole project\n    project.unlock()\nend\n"
  },
  {
    "path": "xmake/actions/package/remote/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.base.bit\")\nimport(\"private.detect.check_targetname\")\n\n-- get library deps\nfunction _get_librarydeps(target)\n    local librarydeps = {}\n    for _, depname in ipairs(target:get(\"deps\")) do\n        local dep = project.target(depname, {namespace = target:namespace()})\n        if not ((target:is_binary() or target:is_shared()) and dep:is_static()) then\n            table.insert(librarydeps, dep:name():lower())\n        end\n    end\n    return librarydeps\nend\n\n-- package remote\nfunction _package_remote(target)\n\n    -- get the output directory\n    local packagedir  = target:packagedir()\n    local packagename = target:name():lower()\n\n    -- generate xmake.lua\n    local file = io.open(path.join(packagedir, \"xmake.lua\"), \"w\")\n    if file then\n        local deps = _get_librarydeps(target)\n        file:print(\"package(\\\"%s\\\")\", packagename)\n        if target:is_binary() then\n            file:print(\"    set_kind(\\\"binary\\\")\")\n        elseif target:is_headeronly() then\n            file:print(\"    set_kind(\\\"library\\\", {headeronly = true})\")\n        elseif target:is_moduleonly() then\n            file:print(\"    set_kind(\\\"library\\\", {moduleonly = true})\")\n        end\n        local homepage = option.get(\"homepage\")\n        if homepage then\n            file:print(\"    set_homepage(\\\"%s\\\")\", homepage)\n        end\n        local description = option.get(\"description\") or (\"The \" .. packagename .. \" package\")\n        file:print(\"    set_description(\\\"%s\\\")\", description)\n        if target:license() then\n            file:print(\"    set_license(\\\"%s\\\")\", target:license())\n        end\n        if #deps > 0 then\n            file:print(\"    add_deps(\\\"%s\\\")\", table.concat(deps, \"\\\", \\\"\"))\n        end\n        -- export packages as deps, @see https://github.com/xmake-io/xmake/issues/4202\n        local interface\n        if target:is_shared() then\n            interface = true\n        end\n        for _, pkg in ipairs(target:orderpkgs({interface = interface})) do\n            local requireconf_str\n            local requireconf = pkg:requireconf()\n            if requireconf then\n                local conf = table.clone(requireconf)\n                conf.alias = nil\n                requireconf_str = string.serialize(conf, {indent = false, strip = true})\n            end\n            if requireconf_str and requireconf_str ~= \"{}\" then\n                file:print(\"    add_deps(\\\"%s\\\", %s)\", pkg:requirestr(), requireconf_str)\n            else\n                file:print(\"    add_deps(\\\"%s\\\")\", pkg:requirestr())\n            end\n        end\n        file:print(\"\")\n        local url = option.get(\"url\") or \"https://github.com/myrepo/foo.git\"\n        local version = option.get(\"version\") or target:version() and (target:version()) or \"1.0\"\n        local shasum = option.get(\"shasum\") or \"<shasum256 or gitcommit>\"\n        file:print(\"    add_urls(\\\"%s\\\")\", url)\n        file:print(\"    add_versions(\\\"%s\\\", \\\"%s\\\")\", version, shasum)\n        file:print(\"\")\n        file:print([[\n    on_install(function (package)\n        local configs = {}\n        if package:config(\"shared\") then\n            configs.kind = \"shared\"\n        end\n        import(\"package.tools.xmake\").install(package, configs)\n    end)\n\n    on_test(function (package)\n        -- TODO check includes and interfaces\n        -- assert(package:has_cfuncs(\"foo\", {includes = \"foo.h\"})\n    end)]])\n        file:close()\n    end\n\n    -- show tips\n    print(\"package(%s): %s generated\", packagename, packagedir)\nend\n\n-- package target\nfunction _package_target(target)\n    if not target:is_phony() then\n        local scripts =\n        {\n            binary     = _package_remote\n        ,   static     = _package_remote\n        ,   shared     = _package_remote\n        ,   headeronly = _package_remote\n        ,   moduleonly = _package_remote\n        }\n        local kind = target:kind()\n        local script = scripts[kind]\n        if script then\n            script(target)\n        end\n    end\nend\n\n-- package the given targets\nfunction _package_targets(targets)\n    for _, target in ipairs(targets) do\n        _package_target(target)\n    end\nend\n\n-- main\nfunction main()\n\n    -- lock the whole project\n    project.lock()\n\n    -- load config\n    config.load()\n\n    -- package the given target?\n    local targetname = option.get(\"target\")\n    if targetname then\n        local target = assert(check_targetname(targetname))\n        _package_target(target)\n    else\n        -- package default or all targets\n        for _, target in ipairs(project.ordertargets()) do\n            if target:is_default() or option.get(\"all\") then\n                _package_target(target)\n            end\n        end\n    end\n\n    -- unlock the whole project\n    project.unlock()\nend\n\n"
  },
  {
    "path": "xmake/actions/package/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"package\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake package|p [options] [target]\",\n        description = \"Package target.\",\n        shortname = 'p',\n        options = {\n            {'o', \"outputdir\",  \"kv\", nil,       \"Set the output directory.\"},\n            {'a', \"all\",        \"k\",  nil,       \"Package all targets.\"},\n            {},\n            {'f', \"format\",     \"kv\", \"local\",   \"Set the package format.\",\n                                                 values = {\"oldpkg\", \"local\", \"remote\"}},\n            {nil, \"homepage\",   \"kv\",  nil,      \"Set the homepage of package.\"},\n            {nil, \"description\",\"kv\",  nil,      \"Set the description of package.\"},\n            {nil, \"url\",        \"kv\",  nil,      \"Set the url of remote package.\"},\n            {nil, \"version\",    \"kv\",  nil,      \"Set the version of remote package.\"},\n            {nil, \"shasum\",     \"kv\",  nil,      \"Set the sha256 or commit of remote package.\"},\n            {},\n            {nil, \"target\",     \"v\",  nil,       \"The target name. It will package all default targets if this parameter is not specified.\",\n                                                 values = function (complete, opt)\n                                                     return import(\"private.utils.complete_helper.targets\")(complete, opt)\n                                                 end }\n        }\n    }\n\n\n\n"
  },
  {
    "path": "xmake/actions/require/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"private.action.require.list\")\nimport(\"private.action.require.scan\")\nimport(\"private.action.require.info\")\nimport(\"private.action.require.fetch\")\nimport(\"private.action.require.clean\")\nimport(\"private.action.require.search\")\nimport(\"private.action.require.export\")\nimport(\"private.action.require.import\", {alias = \"import_packages\"})\nimport(\"private.action.require.install\")\nimport(\"private.action.require.uninstall\")\nimport(\"private.action.require.download\")\nimport(\"private.action.require.check\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\n\n--\n-- the default repositories:\n--     xmake-repo https://github.com/xmake-io/xmake-repo.git\n--\n-- add other repositories:\n--     xmake repo --add other-repo https://github.com/other/other-repo.git\n-- or\n--     add_repositories(\"other-repo https://github.com/other/other-repo.git\")\n--\n-- add requires:\n--\n--     add_requires(\"tboox.tbox >=1.5.1\", \"zlib >=1.2.11\")\n--     add_requires(\"zlib master\")\n--     add_requires(\"xmake-repo@tboox.tbox >=1.5.1\")\n--     add_requires(\"https://github.com/tboox/tbox.git@tboox.tbox >=1.5.1\")\n--\n-- add package dependencies:\n--\n--     target(\"test\")\n--         add_packages(\"tboox.tbox\", \"zlib\")\n--\n\n-- load project\nfunction _load_project()\n\n    -- config it first\n    task.run(\"config\", {require = false}, {disable_dump = true})\n\n    -- enter project directory\n    os.cd(project.directory())\nend\n\n-- main\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load project first\n    _load_project()\n\n    -- clean all installed packages cache\n    if option.get(\"clean\") then\n\n        clean(option.get(\"requires\"))\n\n    -- search for the given packages from repositories\n    elseif option.get(\"search\") then\n\n        search(option.get(\"requires\"))\n\n    -- uninstall the installed packages\n    elseif option.get(\"uninstall\") then\n\n        uninstall(option.get(\"requires\"))\n\n    -- export the installed packages\n    elseif option.get(\"export\") then\n\n        export(option.get(\"requires\"))\n\n    -- import the installed packages\n    elseif option.get(\"import\") then\n\n        import_packages(option.get(\"requires\"))\n\n    -- show the given package info\n    elseif option.get(\"info\") then\n\n        info(option.get(\"requires\"))\n\n    -- fetch the library info of the given packages\n    elseif option.get(\"fetch\") then\n\n        fetch(option.get(\"requires\"))\n\n    -- download the given package source archive files\n    elseif option.get(\"download\") then\n\n        download(option.get(\"requires\"))\n\n    -- check the given packages\n    elseif option.get(\"check\") then\n\n        check(option.get(\"requires\"))\n\n    -- list all package dependencies in project\n    elseif option.get(\"list\") then\n\n        list()\n\n    -- scan the given or all packages\n    elseif option.get(\"scan\") then\n\n        scan(option.get(\"requires\"))\n\n    -- install and upgrade all outdated package dependencies by default if no arguments\n    else\n        install(option.get(\"requires\"))\n    end\nend\n\n"
  },
  {
    "path": "xmake/actions/require/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        require.lua\n--\n\n-- define task\ntask(\"require\")\n\n    -- set category\n    set_category(\"action\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake require [options] [packages]\"\n\n                -- description\n            ,   description = \"Install and update required packages.\"\n\n                -- xmake q\n            ,   shortname = 'q'\n\n                -- options\n            ,   options =\n                {\n                    {'c', \"clean\",      \"k\",  nil,       \"Clear all package caches and uninstall all not-referenced packages.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --clean\",\n                                                         \"    $ xmake require --clean zlib tbox pcr*\"                          }\n                ,   {nil, \"clean_modes\",\"kv\", nil,       \"Set the modes of cleaning packages.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --clean --clean_modes=cache,package\"             }\n                ,   {'f', \"force\",      \"k\",  nil,       \"Force to reinstall all package dependencies.\"                        }\n                ,   {'j', \"jobs\",       \"kv\", tostring(os.default_njob()),\n                                                         \"Set the number of parallel compilation jobs.\"                        }\n                ,   {nil, \"linkjobs\",   \"kv\", nil,       \"Set the number of parallel link jobs.\"                               }\n                ,   {nil, \"shallow\",    \"k\",  nil,       \"Does not install or download dependent packages.\"                    }\n                ,   {nil, \"build\",      \"k\",  nil,       \"Always build and install packages from source.\"                      }\n                ,   {'l', \"list\",       \"k\",  nil,       \"List all package dependencies in project.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --list\"                                          }\n                ,   {nil, \"scan\",       \"k\",  nil,       \"Scan the given or all installed packages.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --scan\",\n                                                         \"    $ xmake require --scan zlib tbox pcr*\"                           }\n                ,   {                                                                                                          }\n                ,   {nil, \"info\",       \"k\",  nil,       \"Show the given package info.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --info tbox\"                                     }\n                ,   {nil, \"check\",      \"k\",  nil,      \"Check whether the given package is supported\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --check tbox\"                                    }\n                ,   {nil, \"fetch\",      \"k\",  nil,      \"Fetch the library info of given package.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --fetch tbox\"                                    }\n                ,   {nil, \"fetch_modes\",\"kv\", nil,      \"Set the modes of fetching packages.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --fetch --fetch_modes=cflags,external tbox\",\n                                                         \"    $ xmake require --fetch --fetch_modes=deps,cflags,ldflags tbox\"  }\n                ,   {'s', \"search\",     \"k\",  nil,       \"Search for the given packages from repositories.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --search tbox\"                                   }\n                ,   {nil, \"upgrade\",    \"k\",  nil,       \"Upgrade the installed packages.\"                                     }\n                ,   {nil, \"download\",   \"k\",  nil,       \"Only download the given package source archive files.\"               }\n                ,   {nil, \"uninstall\",  \"k\",  nil,       \"Uninstall the installed packages.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --uninstall\",\n                                                         \"    $ xmake require --uninstall tbox\",\n                                                         \"    $ xmake require --uninstall --extra=\\\"{debug=true}\\\" tbox\"       }\n                ,   {nil, \"export\",     \"k\", nil,        \"Export the installed packages and their dependencies.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --export\",\n                                                         \"    $ xmake require --export tbox zlib\",\n                                                         \"    $ xmake require --export --packagedir=packagesdir zlib\",\n                                                         \"    $ xmake require --export --extra=\\\"{debug=true}\\\" tbox\"          }\n                ,   {nil, \"import\",     \"k\", nil,        \"Import the installed packages and their dependencies.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require --import\",\n                                                         \"    $ xmake require --import tbox zlib\",\n                                                         \"    $ xmake require --import --packagedir=packagesdir zlib\",\n                                                         \"    $ xmake require --import --extra=\\\"{debug=true}\\\" tbox\"          }\n                ,   {nil, \"packagedir\", \"kv\", \"packages\",\"Set the packages directory for exporting, importing and downloading.\"}\n                ,   {nil, \"debugdir\",   \"kv\", nil,       \"Set the source directory of the current package for debugging.\"      }\n                ,   {nil, \"extra\",      \"kv\", nil,       \"Set the extra info of packages.\"                                     }\n                ,   {                                                                                                          }\n                ,   {nil, \"requires\",   \"vs\", nil,       \"The package requires.\",\n                                                         \"e.g.\",\n                                                         \"    $ xmake require zlib tbox\",\n                                                         \"    $ xmake require \\\"zlib >=1.2.11\\\" \\\"tbox master\\\"\",\n                                                         \"    $ xmake require --extra=\\\"{debug=true,configs={xxx=true}}\\\" tbox\"}\n                }\n            }\n"
  },
  {
    "path": "xmake/actions/run/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.config\")\nimport(\"core.base.global\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"devel.debugger\")\nimport(\"async.runjobs\")\nimport(\"private.action.run.runenvs\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"private.detect.check_targetname\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.utils\", {alias = \"action_utils\"})\n\nfunction _run_wasi_target(targetfile, args, opt)\n    opt = opt or {}\n    local rundir = opt.rundir\n    local addenvs = opt.addenvs\n    local setenvs = opt.setenvs\n    local wasmtime = find_tool(\"wasmtime\")\n    if wasmtime then\n        local runargs = {targetfile}\n        if args and #args > 0 then\n            table.join2(runargs, args)\n        end\n        os.execv(wasmtime.program, runargs, {\n            curdir = rundir, detach = option.get(\"detach\"), addenvs = addenvs, setenvs = setenvs})\n    else\n        raise(\"wasmtime not found, which is required for running wasi target!\")\n    end\nend\n\nfunction _run_wasm_target_in_browser(targetfile, opt)\n    opt = opt or {}\n    local rundir = opt.rundir\n    local addenvs = opt.addenvs\n    local setenvs = opt.setenvs\n    -- prefer the .html file over .js for browser targets\n    -- @see https://github.com/xmake-io/xmake/issues/7340\n    local htmlfile = targetfile:gsub(\"%.js$\", \".html\")\n    if htmlfile ~= targetfile and os.isfile(htmlfile) then\n        targetfile = htmlfile\n    end\n    local emrun = find_tool(\"emrun\")\n    if emrun then\n        os.execv(emrun.program, {\"--serve_root\", path.directory(targetfile), targetfile}, {\n            curdir = rundir, detach = option.get(\"detach\"), addenvs = addenvs, setenvs = setenvs})\n    else\n        local python = find_tool(\"python3\")\n        if not python then\n            raise(\"emrun or python not found, which is required for running wasm target in browser!\")\n        end\n        local url = \"http://localhost:8000/\" .. path.unix(path.relative(targetfile, rundir))\n        print(\"please open the url in browser\")\n        cprint(\"${color.success}%s${clear}\", url)\n        os.execv(python.program, {\"-m\", \"http.server\", \"--bind\", \"127.0.0.1\", \"8000\"}, {\n            curdir = rundir, detach = option.get(\"detach\"), addenvs = addenvs, setenvs = setenvs})\n    end\nend\n\n-- run target\nfunction _do_run_target(target)\n\n    -- only for binary program\n    if not target:is_binary() then\n        return\n    end\n\n    -- get the run directory of target\n    local rundir = target:rundir()\n\n    -- get the absolute target file path\n    local targetfile = path.absolute(target:targetfile())\n\n    -- get the run environments\n    local addenvs, setenvs = runenvs.make(target)\n\n    -- get run arguments\n    local args = table.wrap(option.get(\"arguments\") or target:get(\"runargs\"))\n\n    -- run wasm target\n    if target:is_plat(\"wasm\") then\n        if target:has_tool(\"cc\", \"emcc\") then\n            _run_wasm_target_in_browser(targetfile, {rundir = rundir, addenvs = addenvs, setenvs = setenvs})\n        else\n            _run_wasi_target(targetfile, args, {rundir = rundir, addenvs = addenvs, setenvs = setenvs})\n        end\n        return\n    end\n\n    -- run windows target on non-windows host via wine\n    if not is_host(\"windows\") and target:is_plat(\"windows\") then\n        local wine = assert(find_tool(\"wine\"), \"wine not found!\")\n        table.insert(args, 1, targetfile)\n        targetfile = wine.program\n    end\n\n    -- enable GUI error dialogs (Windows only)\n    -- @see https://github.com/xmake-io/xmake/issues/7176\n    local old_errormode\n    if target:policy(\"run.windows_error_dialog\") and winos.set_error_mode then\n        old_errormode = winos.set_error_mode(0)\n    end\n\n    -- debugging?\n    if option.get(\"debug\") then\n        debugger.run(targetfile, args, {curdir = rundir, addenvs = addenvs, setenvs = setenvs})\n    else\n        os.execv(targetfile, args, {curdir = rundir, detach = option.get(\"detach\"), addenvs = addenvs, setenvs = setenvs})\n    end\n\n    -- restore error mode\n    if old_errormode then\n        winos.set_error_mode(old_errormode)\n    end\nend\n\n-- run target\nfunction _on_run_target(target)\n\n    -- build target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_run = r:script(\"run\")\n        if on_run then\n            on_run(target)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do run\n    _do_run_target(target)\nend\n\n-- recursively add target envs\nfunction _add_target_pkgenvs(target, targets_added)\n    if targets_added[target:name()] then\n        return\n    end\n    targets_added[target:name()] = true\n    os.addenvs(target:pkgenvs())\n    for _, dep in ipairs(target:orderdeps()) do\n        _add_target_pkgenvs(dep, targets_added)\n    end\nend\n\n-- run the given target\nfunction _run(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter the environments of the target packages\n    local oldenvs = os.getenvs()\n    _add_target_pkgenvs(target, {})\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"run_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_run = r:script(\"run_before\")\n                if before_run then\n                    before_run(target)\n                end\n            end\n        end\n    ,   target:script(\"run\", _on_run_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_run = r:script(\"run_after\")\n                if after_run then\n                    after_run(target)\n                end\n            end\n        end\n    ,   target:script(\"run_after\")\n    }\n\n    -- run the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\nend\n\n-- check if the target is runnable\nfunction _is_runnable(target)\n    if target:is_binary() or target:script(\"run\") then\n        return true\n    end\n    for _, r in ipairs(target:orderules()) do\n        if r:script(\"run\") then\n            return true\n        end\n    end\nend\n\n-- check targets\nfunction _check_targets(targetname, group_pattern)\n\n    -- get targets\n    local targets = {}\n    if targetname then\n        local target = assert(check_targetname(targetname))\n        table.insert(targets, target)\n    else\n        for _, target in ipairs(project.ordertargets()) do\n            if _is_runnable(target) then\n                local group = target:get(\"group\")\n                if (target:is_default() and not group_pattern) or option.get(\"all\") or (group_pattern and group and group:match(group_pattern)) then\n                    table.insert(targets, target)\n                end\n            end\n        end\n    end\n\n    -- filter and check targets with builtin-run script\n    local targetnames = {}\n    for _, target in ipairs(targets) do\n        if target:targetfile() and target:is_enabled() and not target:script(\"run\") then\n            local targetfile = target:targetfile()\n            if targetfile and not os.isfile(targetfile) then\n                table.insert(targetnames, target:name())\n            end\n        end\n    end\n\n    -- there are targets that have not yet been built?\n    if #targetnames > 0 then\n        raise(\"please run `$xmake build [target]` to build the following targets first:\\n  -> \" .. table.concat(targetnames, '\\n  -> '))\n    end\nend\n\n-- main\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load config first\n    config.load()\n\n    -- Automatically build before running\n    if project.policy(\"run.autobuild\") then\n        -- we need clear the previous config and reload it\n        -- to avoid trigger recheck configs\n        config.clear()\n        task.run(\"build\", {target = option.get(\"target\"), all = option.get(\"all\")}, {disable_dump = true})\n    else\n        -- it will call on_config, we need to avoid repeat call it when autobuild is enabled.\n        project.load_targets()\n    end\n\n    -- check targets first\n    local targetname, group_pattern = action_utils.get_target_and_group()\n    _check_targets(targetname, group_pattern)\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- run the given target?\n    if targetname then\n        _run(project.target(targetname))\n    else\n        local targets = {}\n        for _, target in ipairs(project.ordertargets()) do\n            if _is_runnable(target) then\n                local group = target:get(\"group\")\n                if (target:is_default() and not group_pattern) or option.get(\"all\") or (group_pattern and group and group:match(group_pattern)) then\n                    table.insert(targets, target)\n                end\n            end\n        end\n        local jobs = tonumber(option.get(\"jobs\") or \"1\")\n        runjobs(\"run_targets\", function (index)\n            local target = targets[index]\n            if target then\n                _run(target)\n            end\n        end, {total = #targets,\n              comax = jobs,\n              isolate = true})\n    end\n\n    -- leave project directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/actions/run/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define task\ntask(\"run\")\n\n    -- set category\n    set_category(\"action\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake run|r [options] [target] [arguments]\"\n\n                -- description\n            ,   description = \"Run the project target.\"\n\n                -- xmake r\n            ,   shortname = 'r'\n\n                -- options\n            ,   options =\n                {\n                    {'d', \"debug\",      \"k\",   nil  , \"Run and debug the given target.\"                                    }\n                ,   {'a', \"all\",        \"k\",   nil  , \"Run all targets.\"                                                   }\n                ,   {'g', \"group\",      \"kv\",  nil  , \"Run all targets of the given group. It support path pattern matching.\",\n                                                      \"e.g.\",\n                                                      \"    xmake run -g test\",\n                                                      \"    xmake run -g test_*\",\n                                                      \"    xmake run --group=benchmark/*\"                                  }\n                ,   {'w', \"workdir\",    \"kv\",  nil  , \"Work directory of running targets, default is folder of targetfile\",\n                                                      \"e.g.\",\n                                                      \"    xmake run -w .\",\n                                                      \"    xmake run --workdir=`pwd`\"                                      }\n                ,   {'j', \"jobs\",       \"kv\", \"1\",    \"Set the number of parallel compilation jobs.\"                       }\n                ,   {nil, \"detach\",     \"k\", nil,     \"Run targets in detached processes.\"                                 }\n                ,   {}\n                ,   {nil, \"target\",     \"v\",   nil  , \"The target name. It will run all default targets if this parameter is not specified.\"\n                                                    , values = function (complete, opt)\n                                                            return import(\"private.utils.complete_helper.runable_targets\")(complete, opt)\n                                                        end }\n\n                ,   {nil, \"arguments\",  \"vs\",  nil  , \"The target arguments\"                                               }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/actions/service/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.server_config\")\nimport(\"private.service.client_config\")\nimport(\"private.service.start_service\")\nimport(\"private.service.restart_service\")\nimport(\"private.service.stop_service\")\nimport(\"private.service.connect_service\")\nimport(\"private.service.reconnect_service\")\nimport(\"private.service.disconnect_service\")\nimport(\"private.service.clean_files\")\nimport(\"private.service.sync_files\")\nimport(\"private.service.pull_files\")\nimport(\"private.service.add_user\")\nimport(\"private.service.rm_user\")\nimport(\"private.service.gen_token\")\nimport(\"private.service.show_logs\")\nimport(\"private.service.show_status\")\n\nfunction main()\n    -- @note we need the load server config before loading the client config,\n    -- because we need the same local token in both configs\n    server_config.load()\n    client_config.load()\n    if option.get(\"start\") then\n        start_service({daemon = true})\n    elseif option.get(\"restart\") then\n        restart_service()\n    elseif option.get(\"stop\") then\n        stop_service()\n    elseif option.get(\"connect\") then\n        connect_service()\n    elseif option.get(\"reconnect\") then\n        reconnect_service()\n    elseif option.get(\"disconnect\") then\n        disconnect_service()\n    elseif option.get(\"clean\") then\n        clean_files()\n    elseif option.get(\"sync\") then\n        sync_files()\n    elseif option.get(\"pull\") then\n        local values = option.get(\"values\") or {}\n        pull_files(values[1], values[2])\n    elseif option.get(\"gen-token\") then\n        gen_token()\n    elseif option.get(\"add-user\") then\n        add_user(option.get(\"add-user\"))\n    elseif option.get(\"rm-user\") then\n        rm_user(option.get(\"rm-user\"))\n    elseif option.get(\"logs\") then\n        show_logs()\n    elseif option.get(\"status\") then\n        show_status()\n    else\n        start_service()\n    end\nend\n\n"
  },
  {
    "path": "xmake/actions/service/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        service.lua\n--\n\ntask(\"service\")\n    set_category(\"action\")\n    on_run(\"main\")\n\n    set_menu {usage = \"xmake service [options]\",\n              description = \"Start service for remote or distributed compilation and etc.\",\n              options = {\n                {nil, \"start\",      \"k\",  nil, \"Start daemon service.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --start\",\n                                               \"    - xmake service --start --remote\",\n                                               \"    - xmake service --start --distcc\",\n                                               \"    - xmake service --start --remote --distcc\"               },\n                {nil, \"restart\",    \"k\",  nil, \"Restart daemon service.\"                                     },\n                {nil, \"stop\" ,      \"k\",  nil, \"Stop daemon service.\"                                        },\n                {nil, \"connect\" ,   \"k\",  nil, \"Connect current project to the remote daemon service.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --connect\",\n                                               \"    - xmake service --connect --remote\",\n                                               \"    - xmake service --connect --distcc\",\n                                               \"    - xmake service --connect --remote --distcc\",\n                                               \"    - xmake service --connect --host=windows\",\n                                               \"    - xmake service --connect --host=10.5.139.8:9691\"             },\n                {nil, \"session\" ,   \"kv\",  nil,\"Connect with the given session name, it will generate a session id via name.\",\n                                               \"e.g.\",\n                                               \"    -- xmake service --connect --ccache --session=foo\"       },\n                {nil, \"reconnect\",  \"k\",  nil, \"Reconnect current project to the remote daemon service.\"     },\n                {nil, \"disconnect\", \"k\",  nil, \"Disconnect current project in the remote daemon service.\"    },\n                {nil, \"remote\",     \"k\",  nil, \"Start or connect the remote build service.\"                  },\n                {nil, \"distcc\",     \"k\",  nil, \"Start or connect the distributed build service.\"             },\n                {nil, \"ccache\",     \"k\",  nil, \"Start or connect the remote c/c++ cache service.\"            },\n                {nil, \"sync\",       \"k\",  nil, \"Sync current project files in the remote daemon service.\"    },\n                {nil, \"xmakesrc\",   \"kv\", nil, \"Sync xmake program files in the remote daemon service.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --sync --xmakesrc=/xmakeproj/xmake\"      },\n                {nil, \"pull\",       \"k\",  nil, \"Pull the given file or directory in the remote daemon service.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --pull build outputdir\",\n                                               \"    - xmake service --pull 'build/**' outputdir\"             },\n                {nil, \"clean\",      \"k\",  nil, \"Clean current project files in the remote daemon service.\"   },\n                {nil, \"all\",        \"k\",  nil, \"Clean all project files in the remote daemon service.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --clean --all\"                           },\n                {nil, \"add-user\",   \"kv\", nil, \"Add user in the server.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --add-user=root\"                         },\n                {nil, \"rm-user\",    \"kv\", nil, \"Remove user in the server.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --rm-user=root\"                          },\n                {nil, \"gen-token\",  \"k\",  nil, \"Generate a new token in the server.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --gen-token\"                             },\n                {nil, \"host\",       \"kv\", nil, \"Connect to the specific host by name or address.\",\n                                               \"e.g.\",\n                                               \"    - xmake service --connect --host=windows\",\n                                               \"    - xmake service --connect --host=10.5.139.8:9691\",\n                                               \"    - xmake service --connect --host=10.5.139.8\"        },\n                {nil, \"logs\",       \"k\",  nil, \"Show service logs if the daemon service has been started.\"   },\n                {nil, \"status\",     \"k\",  nil, \"Show service status if the daemon service has been started.\" },\n                {nil, \"values\",     \"vs\", nil, \"The values list for pull/.. options.\" }\n             }}\n"
  },
  {
    "path": "xmake/actions/test/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.config\")\nimport(\"core.base.global\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.theme.theme\")\nimport(\"async.runjobs\")\nimport(\"private.action.run.runenvs\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"actions.build.main\", {rootdir = os.programdir(), alias = \"build_action\"})\nimport(\"utils.progress\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- Load expected outputs from files for pass_output_files/fail_output_files.\n-- Resolve relative paths from the target scriptdir.\n-- https://github.com/xmake-io/xmake/issues/7255\nfunction _load_output_files(target, files, opt)\n    files = table.wrap(files)\n    if #files == 0 then\n        return {}\n    end\n    local scriptdir = target and target:scriptdir() or nil\n    local outputs = {}\n    for _, file in ipairs(files) do\n        local filepath = path.absolute(file, scriptdir)\n        if not os.isfile(filepath) then\n            raise(\"file not found: %s\", filepath)\n        end\n        local data = io.readfile(filepath)\n        if opt.trim_output and data then\n            data = data:trim()\n        end\n        table.insert(outputs, data)\n    end\n    return outputs\nend\n\n-- test target\nfunction _do_test_target(target, opt)\n    opt = opt or {}\n\n    -- early out: results were computed during build\n    if opt.build_should_fail or opt.build_should_pass then\n        if opt.errors then\n            vprint(opt.errors)\n        end\n        return opt.passed\n    end\n\n    -- get run environments\n    local envs = opt.runenvs\n    if not envs then\n        local addenvs, setenvs = runenvs.make(target)\n        envs = runenvs.join(addenvs, setenvs)\n    end\n\n    -- run test\n    local outdata\n    local errors\n    local rundir = opt.rundir or target:rundir()\n    local targetfile = path.absolute(target:targetfile())\n    local runargs = table.wrap(opt.runargs or target:get(\"runargs\"))\n    local autogendir = path.join(target:autogendir(), \"tests\")\n    local logname = opt.name:gsub(\"[/\\\\>=<|%*]\", \"_\")\n    local outfile = path.absolute(path.join(autogendir, logname .. \".out\"))\n    local errfile = path.absolute(path.join(autogendir, logname .. \".err\"))\n    if opt.realtime_output then\n        outfile = nil\n        errfile = nil\n        assert(not opt.pass_outputs and not opt.fail_outputs and not opt.pass_output_files and not opt.fail_output_files,\n            \"add_tests(%s): we cannot check pass_outputs/fail_outputs in real output mode\", opt.name)\n    else\n        os.tryrm(outfile)\n        os.tryrm(errfile)\n    end\n    os.mkdir(autogendir)\n    local should_fail = opt.should_fail or false\n    local run_timeout = opt.run_timeout\n    local ok, syserrors = os.execv(targetfile, runargs, {try = true, timeout = run_timeout,\n        curdir = rundir, envs = envs, stdout = outfile, stderr = errfile})\n    local outdata = (outfile and os.isfile(outfile)) and io.readfile(outfile) or \"\"\n    local errdata = (errfile and os.isfile(errfile)) and io.readfile(errfile) or \"\"\n    if outdata and #outdata > 0 then\n        opt.stdout = outdata\n    end\n    if errdata and #errdata > 0 then\n        opt.stderr = errdata\n    end\n    if opt.trim_output and outdata then\n        outdata = outdata:trim()\n    end\n    if ok ~= 0 then\n        if not errors or #errors == 0 then\n            if ok ~= nil then\n                if syserrors then\n                    errors = string.format(\"run %s failed, exit code: %d, exit error: %s\", opt.name, ok, syserrors)\n                else\n                    errors = string.format(\"run %s failed, exit code: %d\", opt.name, ok)\n                end\n            else\n                errors = string.format(\"run %s failed, exit error: %s\", opt.name, syserrors and syserrors or \"unknown reason\")\n            end\n        end\n    end\n    if outfile then\n        os.tryrm(outfile)\n    end\n    if errfile then\n        os.tryrm(errfile)\n    end\n\n    local passed\n    if ok == 0 then\n        local pass_outputs = table.wrap(opt.pass_outputs)\n        local fail_outputs = table.wrap(opt.fail_outputs)\n        table.join2(pass_outputs, _load_output_files(target, opt.pass_output_files, opt))\n        table.join2(fail_outputs, _load_output_files(target, opt.fail_output_files, opt))\n        for _, pass_output in ipairs(pass_outputs) do\n            if opt.plain then\n                if pass_output == outdata then\n                    passed = true\n                    break\n                end\n            else\n                if outdata:match(\"^\" .. pass_output .. \"$\") then\n                    passed = true\n                    break\n                end\n            end\n        end\n        for _, fail_output in ipairs(fail_outputs) do\n            if opt.plain then\n                if fail_output == outdata then\n                    passed = false\n                    if not errors or #errors == 0 then\n                        errors = string.format(\"matched failed output: ${color.failure}%s${clear}\", fail_output)\n                        local actual_output = outdata\n                        if not option.get(\"diagnosis\") then\n                            actual_output = outdata:sub(1, 64)\n                            if #outdata > #actual_output then\n                                actual_output = actual_output .. \"...\"\n                            end\n                        end\n                        errors = errors .. \", actual output: ${color.failure}\" .. actual_output\n                    end\n                    break\n                end\n            else\n                if outdata:match(\"^\" .. fail_output .. \"$\") then\n                    passed = false\n                    if not errors or #errors == 0 then\n                        errors = string.format(\"matched failed output: ${color.failure}%s${clear}\", fail_output)\n                        local actual_output = outdata\n                        if not option.get(\"diagnosis\") then\n                            actual_output = outdata:sub(1, 64)\n                            if #outdata > #actual_output then\n                                actual_output = actual_output .. \"...\"\n                            end\n                        end\n                        errors = errors .. \", actual output: ${color.failure}\" .. actual_output\n                    end\n                    break\n                end\n            end\n        end\n        if passed == nil then\n            if #pass_outputs == 0 then\n                passed = true\n            else\n                passed = false\n                if not errors or #errors == 0 then\n                    errors = string.format(\"not matched passed output: ${color.success}%s${clear}\", table.concat(pass_outputs, \", \"))\n                    local actual_output = outdata\n                    if not option.get(\"diagnosis\") then\n                        actual_output = outdata:sub(1, 64)\n                        if #outdata > #actual_output then\n                            actual_output = actual_output .. \"...\"\n                        end\n                    end\n                    errors = errors .. \", actual output: ${color.failure}\" .. actual_output\n                end\n            end\n        end\n    end\n\n    if should_fail then\n        if not passed then\n            passed = true\n            errors = nil -- clear errors, since failure was expected\n        else\n            passed = false\n            local extra_info = string.format(\"Test %s unexpectedly passed (should fail)\", opt.name)\n            if errors and #errors > 0 then\n                errors = errors .. \"\\n\" .. extra_info\n            else\n                errors = extra_info\n            end\n        end\n    end\n\n    if errors and #errors > 0 then\n        opt.errors = errors\n    end\n\n    return passed\nend\n\n-- test target\nfunction _on_test_target(target, opt)\n\n    -- build target with rules\n    local passed\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_test = r:script(\"test\")\n        if on_test then\n            passed = on_test(target, opt)\n            done = true\n        end\n    end\n    if done then\n        return passed\n    end\n\n    -- do test\n    return _do_test_target(target, opt)\nend\n\n-- recursively add target envs\nfunction _add_target_pkgenvs(target, targets_added)\n    if targets_added[target:name()] then\n        return\n    end\n    targets_added[target:name()] = true\n    os.addenvs(target:pkgenvs())\n    for _, dep in ipairs(target:orderdeps()) do\n        _add_target_pkgenvs(dep, targets_added)\n    end\nend\n\n-- run the given test\nfunction _run_test(target, test)\n\n    -- enter the environments of the target packages\n    local oldenvs = os.getenvs()\n    _add_target_pkgenvs(target, {})\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"test_before\")\n    ,   function (target, opt)\n            for _, r in ipairs(target:orderules()) do\n                local before_test = r:script(\"test_before\")\n                if before_test then\n                    before_test(target, opt)\n                end\n            end\n        end\n    ,   target:script(\"test\", _on_test_target)\n    ,   function (target, opt)\n            for _, r in ipairs(target:orderules()) do\n                local after_test = r:script(\"test_after\")\n                if after_test then\n                    after_test(target, opt)\n                end\n            end\n        end\n    ,   target:script(\"test_after\")\n    }\n\n    -- run the target scripts\n    local passed\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            local ok = script(target, test)\n            if i == 3 then\n                passed = ok\n            end\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n    return passed\nend\n\nfunction _show_output(testinfo, kind)\n    local output = testinfo[kind]\n    if output then\n        if option.get(\"diagnosis\") then\n            local target = testinfo.target\n            local autogendir = path.join(target:autogendir(), \"tests\")\n            local logfile = path.join(autogendir, testinfo.name .. \".\" .. kind .. \".log\")\n            io.writefile(logfile, output)\n            print(\"%s: %s\", kind, logfile)\n        elseif option.get(\"verbose\") then\n            io.write(kind .. \": \" .. output .. \"\\n\")\n        end\n    end\nend\n\n-- run tests\nfunction _run_tests(tests)\n    local ordertests = {}\n    local maxwidth = 0\n    for name, testinfo in table.orderpairs(tests) do\n        table.insert(ordertests, testinfo)\n        if #testinfo.name > maxwidth then\n            maxwidth = #testinfo.name\n        end\n    end\n    if #ordertests == 0 then\n        print(\"nothing to test\")\n        return\n    end\n\n    -- temporarily switch to scroll mode to avoid progress refresh interference with test output\n    -- @see https://github.com/xmake-io/xmake/issues/7045\n    progress.set_style(\"scroll\")\n\n    -- do test\n    local spent = os.mclock()\n    print(\"running tests ...\")\n    local report = {passed = 0, total = #ordertests, tests = {}}\n    local jobs = tonumber(option.get(\"jobs\")) or os.default_njob()\n    runjobs(\"run_tests\", function (index, total, opt)\n        local testinfo = ordertests[index]\n        if testinfo then\n            progress.show(opt.progress, \"running.test %s\", testinfo.name)\n\n            local target = testinfo.target\n            testinfo.target = nil\n            local spent = os.mclock()\n            local passed = _run_test(target, testinfo)\n            spent = os.mclock() - spent\n            if passed then\n                report.passed = report.passed + 1\n            end\n            table.insert(report.tests, {\n                target = target,\n                name = testinfo.name,\n                passed = passed,\n                spent = spent,\n                should_fail = testinfo.should_fail or false,\n                stdout = testinfo.stdout,\n                stderr = testinfo.stderr,\n                errors = testinfo.errors})\n\n            -- stop it if be failed?\n            if not passed then\n                local stop = target:policy(\"test.stop_on_first_failure\")\n                if stop == nil then\n                    stop = project.policy(\"test.stop_on_first_failure\")\n                end\n                if stop then\n                    raise(errors)\n                end\n            end\n        end\n    end, {total = #ordertests,\n          comax = jobs,\n          isolate = true,\n          progress_refresh = true})\n\n    -- restore the original progress style\n    progress.restore_style()\n\n    -- generate report\n    spent = os.mclock() - spent\n    local passed_rate = math.floor(report.passed * 100 / report.total)\n\n    local failed_tests = {}\n    local expected_failures = {}\n    local unexpected_passes = {}\n\n    print(\"\")\n    print(\"report of tests:\")\n    for idx, testinfo in ipairs(report.tests) do\n        -- Result label and color logic\n        local result_label\n        local result_color\n\n        if testinfo.should_fail then\n            if testinfo.passed then\n                table.insert(expected_failures, testinfo.name)\n                result_label = \"expected failure\"\n                result_color = \"${color.warning}\"\n            else\n                table.insert(unexpected_passes, testinfo.name)\n                result_label = \"unexpected pass\"\n                result_color = \"${color.failure}\"\n            end\n        else\n            if testinfo.passed then\n                result_label = \"passed\"\n                result_color = \"${color.success}\"\n            else\n                result_label = \"failed\"\n                result_color = \"${color.failure}\"\n                table.insert(failed_tests, testinfo.name)\n            end\n        end\n\n        local progress_format = result_color .. theme.get(\"text.build.progress_format\") .. \":${clear} \"\n        if option.get(\"verbose\") or option.get(\"diagnosis\") then\n            progress_format = progress_format .. \"${dim}\"\n        end\n\n        -- Build aligned output line\n        local padding = maxwidth - #testinfo.name\n        local filler = string.rep(\".\", padding)\n        local progress_percent = math.floor(idx * 100 / #report.tests)\n        cprint(progress_format .. \"%s %s \" .. result_color .. \"%s${clear} ${bright}%0.3fs\",\n            progress_percent, testinfo.name, filler, result_label, testinfo.spent / 1000)\n\n        _show_output(testinfo, \"stdout\")\n        _show_output(testinfo, \"stderr\")\n        _show_output(testinfo, \"errors\")\n    end\n\n    -- Print the summary\n    if #failed_tests > 0 or #expected_failures > 0 or #unexpected_passes > 0 then\n        cprint(\"\\nDetailed summary:\")\n    end\n    if #failed_tests > 0 then\n        cprint(\"${color.failure}Failed tests:${clear}\")\n        for _, name in ipairs(failed_tests) do\n            print(\" - \" .. name)\n        end\n    end\n\n    if #unexpected_passes > 0 then\n        cprint(\"${color.failure}Unexpected passes:${clear}\")\n        for _, name in ipairs(unexpected_passes) do\n            print(\" - \" .. name)\n        end\n    end\n\n    if #expected_failures > 0 then\n        cprint(\"${color.warning}Expected failures:${clear}\")\n        for _, name in ipairs(expected_failures) do\n            print(\" - \" .. name)\n        end\n    end\n\n    local summary = string.format(\"\\n${color.success}%d%%%%${clear} tests passed, ${color.failure}%d${clear} test(s) failed\", passed_rate, #failed_tests)\n    if #unexpected_passes > 0 then\n        summary = summary .. string.format(\", ${color.failure}%d${clear} unexpected pass(es)\", #unexpected_passes)\n    end\n    if #expected_failures > 0 then\n        summary = summary .. string.format(\", ${color.warning}%d${clear} expected failure(s)\", #expected_failures)\n    end\n\n    summary = summary .. string.format(\" out of ${bright}%d${clear}, spent ${bright}%0.3fs\", report.total, spent / 1000)\n    cprint(summary)\n\n    local return_zero = project.policy(\"test.return_zero_on_failure\")\n    if not return_zero and report.passed < report.total then\n        raise()\n    end\nend\n\n-- try to build the given target\nfunction _try_build_target(targetname)\n    local errors\n    local passed = try {\n        function ()\n            build_action.build_targets(targetname)\n            return true\n        end,\n        catch {\n            function (errs)\n                errors = tostring(errs)\n            end\n        }\n    }\n    return passed, errors\nend\n\n-- get tests, export this for the `project` plugin\nfunction get_tests()\n    local tests = {}\n    local group_pattern = option.get(\"group\")\n    if group_pattern then\n        group_pattern = \"^\" .. path.pattern(group_pattern) .. \"$\"\n    end\n    for _, target in ipairs(project.ordertargets()) do\n        for _, name in ipairs(target:get(\"tests\")) do\n            local extra = target:extraconf(\"tests\", name)\n            local testname = target:name() .. \"/\" .. name\n            local testinfo = {name = testname, target = target}\n            if extra then\n                table.join2(testinfo, extra)\n                if extra.files then\n                    local target_new = target:clone()\n                    local scriptdir = target:scriptdir()\n                    target_new:name_set(target:name() .. \"_\" .. name)\n                    for _, file in ipairs(extra.files) do\n                        file = path.absolute(file, scriptdir)\n                        file = path.relative(file, os.projectdir())\n                        target_new:add(\"files\", file, {defines = extra.defines,\n                                                       cflags = extra.cflags,\n                                                       cxflags = extra.cxflags,\n                                                       cxxflags = extra.cxxflags,\n                                                       undefines = extra.undefines,\n                                                       languages = extra.languages})\n                        project.target_add(target_new)\n                    end\n                    for _, file in ipairs(extra.remove_files) do\n                        file = path.absolute(file, scriptdir)\n                        file = path.relative(file, os.projectdir())\n                        target_new:remove(\"files\", file)\n                    end\n                    if extra.kind then\n                        target_new:set(\"kind\", kind)\n                    end\n                    if extra.frameworks then\n                        target_new:add(\"frameworks\", extra.frameworks)\n                    end\n                    if extra.links then\n                        target_new:add(\"links\", extra.links)\n                    end\n                    if extra.syslinks then\n                        target_new:add(\"syslinks\", extra.syslinks)\n                    end\n                    if extra.packages then\n                        target_new:add(\"packages\", extra.packages)\n                    end\n                    target_utils.config_target(target_new)\n                    testinfo.target = target_new\n                end\n            end\n            if not testinfo.group then\n                testinfo.group = target:get(\"group\")\n            end\n\n            local group = testinfo.group\n            if (not group_pattern) or (group_pattern and group and group:match(group_pattern)) then\n                tests[testname] = testinfo\n            end\n        end\n    end\n    return tests\nend\n\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load config first\n    task.run(\"config\", {}, {disable_dump = true})\n\n    -- lock the whole project\n    project.lock()\n\n    -- get tests\n    local tests = get_tests()\n    local test_patterns = option.get(\"tests\")\n    if test_patterns then\n        local tests_new = {}\n        for _, pattern in ipairs(test_patterns) do\n            pattern = \"^\" .. path.pattern(pattern) .. \"$\"\n            for name, testinfo in pairs(tests) do\n                if name:match(pattern) then\n                    tests_new[name] = testinfo\n                end\n            end\n        end\n        tests = tests_new\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- build targets with the given tests first\n    local targetnames = {}\n    for _, testinfo in table.orderpairs(tests) do\n        local targetname = testinfo.target:fullname()\n        if testinfo.build_should_pass then\n            local passed, errors = _try_build_target(targetname)\n            testinfo.passed = passed\n            testinfo.errors = errors\n        elseif testinfo.build_should_fail then\n            local built, _ = _try_build_target(targetname)\n            testinfo.passed = not built\n            if built then\n                testinfo.errors = \"Build succeeded when failure was expected\"\n            end\n        else\n            table.insert(targetnames, targetname)\n        end\n    end\n    if #targetnames > 0 then\n        build_action.build_targets(targetnames)\n    end\n\n    -- run tests\n    _run_tests(tests)\n\n    -- leave project directory\n    os.cd(oldir)\n\n    -- unlock the whole project\n    project.unlock()\nend\n"
  },
  {
    "path": "xmake/actions/test/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"test\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake test [options] [tests]\",\n        description = \"Run the project tests.\",\n        options = {\n            {'g', \"group\",      \"kv\",  nil  , \"Run all tests of the given group. It support path pattern matching.\",\n                                              \"e.g.\",\n                                              \"    xmake test -g test\",\n                                              \"    xmake test -g test_*\",\n                                              \"    xmake test --group=benchmark/*\"                                  },\n            {'w', \"workdir\",    \"kv\",  nil  , \"Work directory of running targets, default is folder of targetfile\",\n                                              \"e.g.\",\n                                              \"    xmake test -w .\",\n                                              \"    xmake test --workdir=`pwd`\"                                      },\n            {'j', \"jobs\",       \"kv\", tostring(os.default_njob()), \"Set the number of parallel compilation jobs.\"   },\n            {'r', \"rebuild\",    \"k\",  nil   , \"Rebuild the target.\"                                                 },\n            {},\n            {nil, \"tests\",     \"vs\",  nil   , \"The test names. It support pattern matching.\",\n                                              \"e.g.\",\n                                              \"    xmake test foo\",\n                                              \"    xmake test */foo\",\n                                              \"    xmake test targetname/*\"                                         }\n        }\n    }\n\n\n\n"
  },
  {
    "path": "xmake/actions/uninstall/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.platform.platform\")\nimport(\"core.base.privilege\")\nimport(\"privilege.sudo\")\nimport(\"uninstall\")\nimport(\"private.action.utils\", {alias = \"action_utils\"})\n\nfunction main()\n\n    -- load config first\n    task.run(\"config\", {require = false}, {disable_dump = true})\n\n    -- attempt to uninstall directly, TODO group_pattern\n    local targetname, group_pattern = action_utils.get_target_and_group()\n    try\n    {\n        function ()\n            uninstall(targetname)\n            cprint(\"${color.success}uninstall ok!\")\n        end,\n\n        catch\n        {\n            -- failed or not permission? request administrator permission and uninstall it again\n            function (errors)\n\n                -- try get privilege\n                if privilege.get() then\n                    local ok = try\n                    {\n                        function ()\n                            uninstall(targetname)\n                            cprint(\"${color.success}uninstall ok!\")\n                            return true\n                        end\n                    }\n\n                    -- release privilege\n                    privilege.store()\n                    if ok then\n                        return\n                    end\n                end\n\n                -- continue to uninstall with administrator permission?\n                local ok = false\n                if sudo.has() and option.get(\"admin\") then\n\n                    -- uninstall target with administrator permission\n                    sudo.execl(path.join(os.scriptdir(), \"uninstall_admin.lua\"), {\n                        targetname or \"__all\",\n                        option.get(\"installdir\") or \"\",\n                        option.get(\"bindir\"),\n                        option.get(\"libdir\"),\n                        option.get(\"includedir\")})\n\n                    -- trace\n                    cprint(\"${color.success}uninstall ok!\")\n                    ok = true\n                end\n                if not ok then\n                    local syserror = os.syserror()\n                    if syserror == os.SYSERR_NOT_PERM or syserror == os.SYSERR_NOT_ACCESS then\n                        wprint(\"please pass the --admin parameter to `xmake uninstall` to request administrator permissions!\")\n                    end\n                end\n                assert(ok, \"uninstall failed, %s\", errors or \"unknown reason\")\n            end\n        }\n    }\nend\n"
  },
  {
    "path": "xmake/actions/uninstall/uninstall.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.project.rule\")\nimport(\"core.project.project\")\nimport(\"target.action.uninstall\", {alias = \"_do_uninstall_target\"})\n\n-- on uninstall target\nfunction _on_uninstall_target(target)\n\n    -- trace\n    print(\"uninstalling %s ..\", target:name())\n\n    -- build target with rules\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_uninstall = r:script(\"uninstall\")\n        if on_uninstall then\n            on_uninstall(target)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- do uninstall\n    _do_uninstall_target(target)\nend\n\n-- uninstall the given target\nfunction _uninstall_target(target)\n\n    -- has been disabled?\n    if not target:is_enabled() then\n        return\n    end\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- the target scripts\n    local scripts =\n    {\n        target:script(\"uninstall_before\")\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_uninstall = r:script(\"uninstall_before\")\n                if before_uninstall then\n                    before_uninstall(target)\n                end\n            end\n        end\n    ,   target:script(\"uninstall\", _on_uninstall_target)\n    ,   function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_uninstall = r:script(\"uninstall_after\")\n                if after_uninstall then\n                    after_uninstall(target)\n                end\n            end\n        end\n    ,   target:script(\"uninstall_after\")\n    }\n\n    -- uninstall the target scripts\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target)\n        end\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n\n    -- leave project directory\n    os.cd(oldir)\nend\n\n-- uninstall the given targets\nfunction _uninstall_targets(targets)\n    for _, target in ipairs(targets) do\n        _uninstall_target(target)\n    end\nend\n\n-- uninstall\nfunction main(targetname)\n    local targets = {}\n    if targetname and not targetname:startswith(\"__\") then\n        local target = project.target(targetname)\n        table.insert(targets, target)\n    else\n        for _, target in ipairs(project.ordertargets()) do\n            local group = target:get(\"group\")\n            if (target:is_default() and not group_pattern) or targetname == \"__all\" or (group_pattern and group and group:match(group_pattern)) then\n                table.insert(targets, target)\n            end\n        end\n    end\n    if #targets > 0 then\n        _uninstall_targets(table.unique(targets))\n    end\nend\n"
  },
  {
    "path": "xmake/actions/uninstall/uninstall_admin.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall_admin.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"uninstall\")\n\nfunction main(targetname, installdir, bindir, libdir, includedir)\n    local verbose = option.get(\"verbose\")\n    if installdir and #installdir == 0 then\n        installdir = nil\n    end\n    if bindir and #bindir == 0 then\n        bindir = nil\n    end\n    if libdir and #libdir == 0 then\n        libdir = nil\n    end\n    if includedir and #includedir == 0 then\n        includedir = nil\n    end\n\n    os.cd(project.directory())\n    config.load()\n    platform.load(config.plat())\n\n    -- save the current option and push a new option context\n    option.save()\n    option.set(\"verbose\", verbose)\n    if installdir then\n        option.set(\"installdir\", installdir)\n    end\n    if bindir then\n        option.set(\"bindir\", bindir)\n    end\n    if libdir then\n        option.set(\"libdir\", libdir)\n    end\n    if includedir then\n        option.set(\"includedir\", includedir)\n    end\n    -- uninstall target\n    uninstall(targetname ~= \"__all\" and targetname or nil)\n    option.restore()\nend\n"
  },
  {
    "path": "xmake/actions/uninstall/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"uninstall\")\n    set_category(\"action\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake uninstall|u [options] [target]\",\n        description = \"Uninstall the project binary files.\",\n        shortname = 'u',\n        options = {\n            {nil, \"installdir\", \"kv\", nil   , \"Set the install directory.\",\n                                              \"e.g.\",\n                                              \"    $ xmake uninstall --installdir=/usr/local\",\n                                              \"or  $ DESTDIR=/usr/local xmake uninstall\",\n                                              \"or  $ INSTALLDIR=/usr/local xmake uninstall\" },\n            {nil, \"bindir\",     \"kv\", nil   , \"Set install binaries directory in INSTALLDIR/DIR. (default: ${installdir}/bin)\"},\n            {nil, \"libdir\",     \"kv\", nil   , \"Set install libraries directory in INSTALLDIR/DIR. (default: ${installdir}/lib)\"},\n            {nil, \"includedir\", \"kv\", nil   , \"Set install includes directory in INSTALLDIR/DIR. (default: ${installdir}/include)\"},\n            {'g', \"group\",      \"kv\",  nil  , \"Uninstall all targets of the given group. It support path pattern matching.\",\n                                              \"e.g.\",\n                                              \"    xmake uninstall -g test\",\n                                              \"    xmake uninstall -g test_*\",\n                                              \"    xmake uninstall --group=benchmark/*\"     },\n            {nil, \"admin\",      \"k\",  nil   , \"Try to request administrator permission to uninstall\"},\n            {                                                                               },\n            {nil, \"target\",     \"v\",  nil   , \"The target name. It will uninstall all default targets if this parameter is not specified.\",\n                                              values = function (complete, opt)\n                                                return import(\"private.utils.complete_helper.targets\")(complete, opt)\n                                              end}\n        }\n    }\n\n"
  },
  {
    "path": "xmake/actions/update/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.base.process\")\nimport(\"core.base.tty\")\nimport(\"net.http\")\nimport(\"devel.git\")\nimport(\"net.fasturl\")\nimport(\"core.base.privilege\")\nimport(\"privilege.sudo\")\nimport(\"async.runjobs\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.update.fetch_version\")\nimport(\"utils.archive\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- the installer filename for windows\nlocal win_installer_name = \"xmake-installer.exe\"\n\n-- run program with privilege\nfunction _sudo_v(program, params)\n\n    -- attempt to install directly\n    return try\n    {\n        function ()\n            os.vrunv(program, params)\n            return true\n        end,\n\n        catch\n        {\n            -- failed or not permission? request administrator permission and run it again\n            function (errors)\n\n                -- trace\n                vprint(errors)\n\n                -- try get privilege\n                if privilege.get() then\n                    local ok = try\n                    {\n                        function ()\n                            os.vrunv(program, params)\n                            return true\n                        end\n                    }\n\n                    -- release privilege\n                    privilege.store()\n\n                    -- ok?\n                    if ok then\n                        return true\n                    end\n                end\n\n                -- show tips\n                local command = program .. \" \" ..os.args(params)\n                cprint(\"\\r${bright color.error}error: ${clear}run `%s` failed, may permission denied!\", command)\n\n                -- continue to install with administrator permission?\n                if sudo.has() then\n\n                    -- confirm to install?\n                    local confirm = utils.confirm({ default = true, description = format(\"try continue to run `%s` with administrator permission again\", command) })\n                    if confirm then\n                        sudo.vrunv(program, params)\n                        return true\n                    end\n                end\n            end\n        }\n    }\nend\n\n-- run program witn admin user\nfunction _run_win_v(program, commands, admin)\n    local sudo_vbs = path.join(os.programdir(), \"scripts\", \"run.vbs\")\n    local temp_vbs = os.tmpfile() .. \".vbs\"\n    os.cp(sudo_vbs, temp_vbs)\n    local params = table.join(\"/Nologo\", temp_vbs, \"W\" .. (admin and \"A\" or \"N\") , program, commands)\n    process.openv(\"cscript\", params, {detach = true}):close()\nend\n\n-- do uninstall\nfunction _uninstall()\n\n    -- remove shell profile\n    local profiles = {}\n    if is_host(\"windows\") then\n        for _, shell in ipairs({\"pwsh\", \"powershell\"}) do\n            for _, type in ipairs({\"AllUsersAllHosts\", \"CurrentUserAllHosts\", \"CurrentUserCurrentHost\"}) do\n                local psshell = find_tool(shell)\n                if psshell then\n                    local outdata, errdata = try {function () return os.iorunv(psshell.program, {\"-c\", \"Write-Output $PROFILE.\" .. type}) end}\n                    if outdata then\n                        table.insert(profiles, outdata:trim())\n                    end\n                end\n            end\n        end\n    else\n        for _, filename in ipairs({\".zshrc\", \".bashrc\", \".kshrc\", \".bash_profile\", \".profile\"}) do\n            table.insert(profiles, path.join(os.getenv(\"HOME\"), filename))\n        end\n    end\n    for _, profile in ipairs(profiles) do\n        if os.isfile(profile) then\n            io.gsub(profile, \"# >>> xmake >>>.-# <<< xmake <<<\", \"\")\n        end\n    end\n\n    -- remove program\n    if is_host(\"windows\") then\n        local uninstaller = path.join(os.programdir(), \"uninstall.exe\")\n        if os.isfile(uninstaller) then\n            -- UAC on win7\n            local params = option.get(\"quiet\") and { \"/S\" } or {}\n            if winos:version():gt(\"winxp\") then\n                _run_win_v(uninstaller, params, true)\n            else\n                _run_win_v(uninstaller, params, false)\n            end\n        else\n            raise(\"the uninstaller(%s) not found!\", uninstaller)\n        end\n    else\n        if os.programdir():startswith(\"/usr/\") then\n            _sudo_v(os.programfile(), {\"lua\", \"rm\", os.programdir()})\n            for _, f in ipairs({\"/usr/local/bin/xmake\", \"/usr/local/bin/xrepo\", \"/usr/bin/xmake\", \"/usr/bin/xrepo\"}) do\n                if os.isfile(f) then\n                    _sudo_v(os.programfile(), {\"lua\", \"rm\", f})\n                end\n            end\n        else\n            os.rm(os.programdir())\n            os.rm(os.programfile())\n            os.rm(\"~/.local/bin/xmake\")\n            os.rm(\"~/.local/bin/xrepo\")\n        end\n    end\nend\n\n-- do install\nfunction _install(sourcedir)\n\n    -- the install task\n    local install_task = function ()\n\n        -- get the install directory\n        local installdir = is_host(\"windows\") and os.programdir() or \"~/.local/bin\"\n\n        -- trace\n        tty.erase_line_to_start().cr()\n        cprintf(\"${yellow}  => ${clear}installing to %s .. \", installdir)\n        local ok = try\n        {\n            function ()\n\n                -- install it\n                os.cd(sourcedir)\n                if is_host(\"windows\") then\n                    if os.isfile(win_installer_name) then\n                        -- /D sets the default installation directory ($INSTDIR), overriding InstallDir and InstallDirRegKey. It must be the last parameter used in the command line and must not contain any quotes, even if the path contains spaces. Only absolute paths are supported.\n                        local params = (\"/D=\" .. os.programdir()):split(\"%s\", { strict = true })\n                        -- @see https://github.com/xmake-io/xmake/issues/1576\n                        local no_admin = try {function () return winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\XMake;NoAdmin\") end}\n                        if no_admin == nil then\n                            no_admin = try {function () return winos.registry_query(\"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\XMake;NoAdmin\") end}\n                        end\n                        if no_admin ~= nil then\n                            no_admin = tostring(no_admin):lower() == \"true\"\n                        else\n                            local testfile = path.join(os.programdir(), \"temp-install\")\n                            no_admin = os.trycp(path.join(os.programdir(), \"scripts\", \"run.vbs\"), testfile)\n                            os.tryrm(testfile)\n                        end\n                        if no_admin then table.insert(params, 1, \"/NOADMIN\") end\n                        -- need UAC?\n                        if winos:version():gt(\"winxp\") then\n                            _run_win_v(win_installer_name, params, not no_admin)\n                        else\n                            _run_win_v(win_installer_name, params, false)\n                        end\n                    else\n                        raise(\"the installer(%s) not found!\", win_installer_name)\n                    end\n                else\n                    if os.isfile(\"./configure\") then\n                        os.vrun(\"./configure\")\n                    end\n                    os.vrunv(\"make\", {\"-j4\"})\n                    process.openv(\"./scripts/get.sh\", {\"__local__\", \"__install_only__\"}, {stdout = os.tmpfile(), stderr = os.tmpfile(), detach = true}):close()\n                end\n                return true\n            end,\n            catch\n            {\n                function (errors)\n                    vprint(errors)\n                end\n            }\n        }\n\n        -- trace\n        if ok then\n            tty.erase_line_to_start().cr()\n            cprint(\"${yellow}  => ${clear}install to %s .. ${color.success}${text.success}\", installdir)\n        else\n            raise(\"install failed!\")\n        end\n    end\n\n    -- do install\n    if option.get(\"verbose\") then\n        install_task()\n    else\n        runjobs(\"update/install\", install_task, {waiting_indicator = true})\n    end\nend\n\n-- do install script\nfunction _install_script(sourcedir)\n\n    -- trace\n    cprintf(\"\\r${yellow}  => ${clear}install script to %s .. \", os.programdir())\n\n    local source = path.join(sourcedir, \"xmake\")\n    local dirname = path.filename(os.programdir())\n    if dirname ~= \"xmake\" then\n        local target = path.join(sourcedir, dirname)\n        os.mv(source, target)\n        source = target\n    end\n\n    local ok = try\n    {\n        function ()\n            if is_host(\"windows\") then\n                local script_original = path.join(os.programdir(), \"scripts\", \"update-script.bat\")\n                local script = os.tmpfile() .. \".bat\"\n                os.cp(script_original, script)\n                local params = { \"/c\", script, os.programdir(), source }\n                os.tryrm(script_original .. \".bak\")\n                local access = os.trymv(script_original, script_original .. \".bak\")\n                _run_win_v(\"cmd\", params, not access)\n                return true\n            else\n                local script = path.join(os.programdir(), \"scripts\", \"update-script.sh\")\n                return _sudo_v(\"sh\", { script, os.programdir(), source })\n            end\n        end,\n        catch\n        {\n            function (errors)\n                vprint(errors)\n            end\n        }\n    }\n    -- trace\n    if ok then\n        cprint(\"${color.success}${text.success}\")\n    else\n        cprint(\"${color.failure}${text.failure}\")\n    end\nend\n\n-- initialize shells\nfunction _initialize_shell()\n\n    local target, command\n    if is_host(\"windows\") then\n        local psshell = find_tool(\"pwsh\") or find_tool(\"powershell\")\n        local outdata, errdata = try {function () return os.iorunv(psshell.program, {\"-c\", \"Write-Output $PROFILE.CurrentUserAllHosts\"}) end}\n        if outdata then\n            target = outdata:trim()\n            local profile = path.join(os.programdir(), \"scripts\", \"profile-win.ps1\")\n            command = format(\"if (Test-Path -Path \\\"%s\\\" -PathType Leaf) {\\n    . \\\"%s\\\"\\n}\", profile, profile)\n        else\n            raise(\"failed to get profile location from powershell!\")\n        end\n    else\n        target = \"~/.profile\"\n        local shell = os.shell()\n        if shell:endswith(\"bash\") then target = (is_host(\"macosx\") and \"~/.bash_profile\" or \"~/.bashrc\")\n        elseif shell:endswith(\"zsh\") then target = \"~/.zshrc\"\n        elseif shell:endswith(\"ksh\") then target = \"~/.kshrc\"\n        elseif shell:endswith(\"fish\") then target = \"~/.config/fish/config.fish\"\n        end\n        local profile_home = path.absolute(\"~/.xmake/profile\")\n        command = (\"test -f \\\"%s\\\" && source \\\"%s\\\"\"):format(profile_home, profile_home)\n\n        -- write home profile\n        local profile = \"$XMAKE_PROGRAM_DIR/scripts/profile-unix.sh\"\n        local profile_fish = \"$XMAKE_PROGRAM_DIR/scripts/profile-unix.fish\"\n        local bridge_command = format([[export XMAKE_ROOTDIR=\"%s\"\nexport XMAKE_PROGRAM_DIR=\"%s\"\n# export PATH=\"$XMAKE_ROOTDIR:$PATH\"\ntest $FISH_VERSION && test -f \"%s\" && source \"%s\" && exit 0\ntest -f \"%s\" && source \"%s\"\n]], path.directory(os.programfile()), os.programdir(), profile_fish, profile_fish, profile, profile)\n        io.writefile(profile_home, bridge_command)\n    end\n\n    -- trace\n    cprintf(\"\\r${yellow}  => ${clear}installing shell integration to %s .. \", target)\n\n    local ok = try\n    {\n        function ()\n            local file = \"\"\n            if os.isfile(target) then\n                file = io.readfile(target)\n                file = file:gsub(\"# >>> xmake >>>.-# <<< xmake <<<\", \"\")\n                if file ~= \"\" and not file:endswith(\"\\n\") then\n                    file = file .. \"\\n\"\n                end\n            end\n            file = file .. \"# >>> xmake >>>\\n\" .. command .. \"\\n# <<< xmake <<<\\n\"\n            io.writefile(target, file)\n            return true\n        end,\n        catch\n        {\n            function (errors)\n                vprint(errors)\n            end\n        }\n    }\n    -- trace\n    if ok then\n        cprint(\"${color.success}${text.success}\")\n        if not is_host(\"windows\") then\n            print(\"Reload shell profile by running the following command now!\")\n            cprint(\"${bright}source ~/.xmake/profile${clear}\")\n        end\n    else\n        cprint(\"${color.failure}${text.failure}\")\n    end\nend\n\nfunction _check_repo(sourcedir)\n    -- this file will exists for long time\n    if not os.isfile(path.join(sourcedir, \"xmake/core/_xmake_main.lua\")) then\n        raise(\"invalid xmake repo, please check your input!\")\n    end\nend\n\nfunction _check_win_installer(sourcedir)\n    local file = path.join(sourcedir, win_installer_name)\n    if not os.isfile(file) then\n        raise(\"installer not found at \" .. sourcedir)\n    end\n\n    local fp = io.open(file, \"rb\")\n    local header = fp:read(math.min(1000, fp:size()))\n    fp:close()\n    if header:startswith(\"MZ\") then\n        return\n    end\n    if header:find('\\0', 1, true) or not option.get(\"verbose\") then\n        raise(\"installer is broken\")\n    else\n        -- may be a text file, print content for debug\n        raise(\"installer is broken: \" .. header)\n    end\nend\n\n-- main\nfunction main()\n\n    -- only uninstall it\n    if option.get(\"uninstall\") then\n\n        -- do uninstall\n        _uninstall()\n\n        -- trace\n        cprint(\"${color.success}uninstall ok!\")\n        return\n    end\n\n    -- initialize for shell interaction\n    if option.get(\"integrate\") then\n        _initialize_shell()\n        return\n    end\n\n    -- enter environment\n    environment.enter()\n\n    -- has been installed?\n    local fetchinfo   = assert(fetch_version(option.get(\"xmakever\")), \"cannot fetch xmake version info!\")\n    local is_official = fetchinfo.is_official\n    local mainurls    = fetchinfo.urls\n    local version     = fetchinfo.version\n    if is_official and xmake.version():eq(version) and not option.get(\"force\") then\n        cprint(\"${bright}xmake %s has been installed!\", version)\n        return\n    end\n\n    -- get urls on windows\n    local script_only = option.get(\"scriptonly\")\n    if is_host(\"windows\") and not script_only then\n        if not is_official then\n            raise(\"not support to update from unofficial source on windows, missing '--scriptonly' flag?\")\n        end\n\n        local winarch = os.arch() == \"x64\" and \"win64\" or \"win32\"\n        if version:find('.', 1, true) then\n            mainurls = {format(\"https://github.com/xmake-io/xmake/releases/download/%s/xmake-%s.%s.exe\", version, version, winarch),\n                        format(\"https://fastly.jsdelivr.net/gh/xmake-mirror/xmake-releases@%s/xmake-%s.%s.exe.zip\", version, version, winarch),\n                        format(\"https://gitlab.com/xmake-mirror/xmake-releases/-/raw/%s/xmake-%s.%s.exe.zip\", (version:gsub(\"^v\", \"\")), version, winarch)}\n        else\n            -- regard as a git branch, fetch from ci\n            local tags = fetchinfo.tags\n            table.sort(tags)\n            local latest_version = tags[#tags] or (\"v\" .. xmake.version():shortstr())\n            mainurls = {format(\"https://github.com/xmake-io/xmake/releases/download/%s/xmake-%s.%s.exe\", latest_version, version, winarch)}\n        end\n\n        -- re-sort mainurls\n        fasturl.add(mainurls)\n        mainurls = fasturl.sort(mainurls)\n    end\n\n    -- trace\n    if is_official then\n        cprint(\"update version ${green}%s${clear} from official source ..\", version)\n    else\n        cprint(\"update version ${green}%s${clear} from ${underline}%s${clear} ..\", version, mainurls[1])\n    end\n\n    -- get the temporary source directory without ramdisk (maybe too large)\n    local sourcedir = path.join(os.tmpdir({ramdisk = false}), \"xmakesrc\", version)\n    vprint(\"prepared to download to temp dir %s ..\", sourcedir)\n\n    -- all user provided urls are considered as git url since check has been performed in fetch_version\n    local install_from_git = not is_official or git.checkurl(mainurls[1])\n\n    -- the download task\n    local download_task = function ()\n        for idx, url in ipairs(mainurls) do\n            tty.erase_line_to_start().cr()\n            cprintf(\"${yellow}  => ${clear}downloading %s .. \", url)\n            local ok = try\n            {\n                function ()\n                    os.tryrm(sourcedir)\n                    if not install_from_git then\n                        os.mkdir(sourcedir)\n                        local installerfile = path.join(sourcedir, win_installer_name)\n                        if url:endswith(\".zip\") then\n                            http.download(url, installerfile .. \".zip\")\n                            archive.extract(installerfile .. \".zip\", installerfile .. \".dir\")\n                            local file = find_file(\"*.exe\", installerfile .. \".dir\")\n                            if file then\n                                os.cp(file, installerfile)\n                            end\n                        else\n                            http.download(url, installerfile)\n                        end\n                    else\n                        git.clone(url, {depth = 1, shallow_submodules = true, recurse_submodules = not script_only, branch = version, outputdir = sourcedir})\n                    end\n                    return true\n                end,\n                catch\n                {\n                    function (errors)\n                        vprint(errors)\n                    end\n                }\n            }\n            tty.erase_line_to_start().cr()\n            if ok then\n                cprint(\"${yellow}  => ${clear}download %s .. ${color.success}${text.success}\", url)\n                break\n            else\n                cprint(\"${yellow}  => ${clear}download %s .. ${color.failure}${text.failure}\", url)\n            end\n            if not ok and idx == #mainurls then\n                raise(\"download failed!\")\n            end\n        end\n    end\n\n    -- do download\n    if option.get(\"verbose\") then\n        download_task()\n    else\n        runjobs(\"update/download\", download_task, {waiting_indicator = true})\n    end\n\n    -- leave environment\n    environment.leave()\n\n    if install_from_git then\n        _check_repo(sourcedir)\n    else\n        _check_win_installer(sourcedir)\n    end\n\n    -- do install\n    if script_only then\n        _install_script(sourcedir)\n    else\n        _install(sourcedir)\n    end\nend\n\n"
  },
  {
    "path": "xmake/actions/update/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define task\ntask(\"update\")\n\n    -- set category\n    set_category(\"action\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake update [options] [xmakever]\"\n\n                -- description\n            ,   description = \"Update and uninstall the xmake program.\"\n\n                -- options\n            ,   options =\n                {\n                    {nil, \"uninstall\",   \"k\",   nil,    \"Uninstall the current xmake program.\"                     }\n                ,   {                                                                                              }\n                ,   {'s', \"scriptonly\",  \"k\",   nil,    \"Update scripts only.\"                                     }\n                ,   {nil, \"integrate\",   \"k\",   nil,    \"Integrate xmake with default shell.\"                  }\n                ,   {'f', \"force\",       \"k\",   nil,    \"Force to update and reinstall the given version.\"         }\n                ,   {nil, \"xmakever\",    \"v\",   nil,    \"The given xmake version, or a git source (and branch). \",\n                                                        \"e.g.\",\n                                                        \"    from official source: \",\n                                                        \"        latest, ~2.2.3, dev, master\",\n                                                        \"    from custom source:\",\n                                                        \"        https://github.com/xmake-io/xmake\",\n                                                        \"        github:xmake-io/xmake#~2.2.3\",\n                                                        \"        git://github.com/xmake-io/xmake.git#master\",\n                                                        values = function (complete)\n                                                            if not complete then\n                                                                return\n                                                            end\n                                                            return try{ function ()\n                                                                import(\"private.action.update.fetch_version\")\n\n                                                                local seg = complete:split('#', { plain = true, limit = 2, strict = true })\n                                                                if #seg == 1 then\n                                                                    if seg[1]:find(':', 1, true) then\n                                                                        -- incomplete custom source\n                                                                        return\n                                                                    else\n                                                                        seg[1] = \"\"\n                                                                    end\n                                                                end\n\n                                                                local versions = fetch_version(seg[1])\n                                                                for i,v in ipairs(versions.tags) do\n                                                                    if v:startswith(\"v\") and #v > 5 then\n                                                                        versions.tags[i] = v:sub(2)\n                                                                    end\n                                                                end\n                                                                local candidates = table.join(\"latest\", versions.branches, table.reverse(versions.tags))\n                                                                if versions.is_official then\n                                                                    return candidates\n                                                                else\n                                                                    for i, v in ipairs(candidates) do\n                                                                        candidates[i] = seg[1] .. \"#\" .. v\n                                                                    end\n                                                                    return candidates\n                                                                end\n                                                            end }\n                                                        end}\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/core/_xmake_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        _xmake_main.lua\n--\n\n-- init namespace: xmake\nxmake                   = xmake or {}\nxmake._NAME             = _NAME or \"xmake\"\nxmake._ARGV             = _ARGV\nxmake._HOST             = _HOST\nxmake._ARCH             = _ARCH\nxmake._SUBHOST          = _SUBHOST\nxmake._SUBARCH          = _SUBARCH\nxmake._XMAKE_ARCH       = _XMAKE_ARCH\nxmake._VERSION          = _VERSION\nxmake._VERSION_SHORT    = _VERSION_SHORT\nxmake._PROGRAM_DIR      = _PROGRAM_DIR\nxmake._PROGRAM_FILE     = _PROGRAM_FILE\nxmake._PROJECT_DIR      = _PROJECT_DIR\nxmake._PROJECT_FILE     = \"xmake.lua\"\nxmake._WORKING_DIR      = os.curdir()\nxmake._FEATURES         = _FEATURES\nxmake._LUAJIT           = _LUAJIT\nxmake._EMBED            = _EMBED\nxmake._THREAD_CALLBACK  = _THREAD_CALLBACK\nxmake._THREAD_CALLINFO  = _THREAD_CALLINFO\n\n-- we need not any arguments in sub-thread.\n-- because it always uses CommandLineToArgvW() on windows, so we need to reset it.\nif _THREAD_CALLBACK then\n    xmake._ARGV = {}\nend\n\n-- In order to be compatible with updates from lower versions of engine core\n-- @see https://github.com/xmake-io/xmake/issues/1694#issuecomment-925507210\nif xmake._LUAJIT == nil then\n    xmake._LUAJIT = true\nend\n\n-- has debugger?\nif xmake._HAS_DEBUGGER == nil then\n    if os.getenv(\"EMMYLUA_DEBUGGER\") then\n        xmake._HAS_DEBUGGER = true\n    else\n        xmake._HAS_DEBUGGER = false\n    end\nend\n\n-- load the given lua file\nfunction _loadfile_impl(filepath, mode, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init displaypath\n    local binary = false\n    local displaypath = opt.displaypath\n    if displaypath == nil then\n        displaypath = filepath\n        if filepath:startswith(xmake._WORKING_DIR) then\n            displaypath = path.translate(\"./\" .. path.relative(filepath, xmake._WORKING_DIR))\n        elseif filepath:startswith(xmake._PROGRAM_DIR) then\n            binary = true -- read file by binary mode, will be faster\n            displaypath = path.translate(\"@programdir/\" .. path.relative(filepath, xmake._PROGRAM_DIR))\n        elseif filepath:startswith(xmake._PROJECT_DIR) then\n            local projectname = path.filename(xmake._PROJECT_DIR)\n            displaypath = path.translate(\"@projectdir(\" .. projectname .. \")/\" .. path.relative(filepath, xmake._PROJECT_DIR))\n        end\n    end\n\n    -- we use raw file path if debugger is enabled\n    if xmake._HAS_DEBUGGER then\n        displaypath = filepath\n    end\n\n    -- load script data from file\n    local file, ferrors = io.file_open(filepath, binary and \"rb\" or \"r\")\n    if not file then\n        ferrors = string.format(\"file(%s): %s\", filepath, ferrors or \"open failed!\")\n        return nil, ferrors\n    end\n\n    local data, rerrors = io.file_read(file, \"a\")\n    if not data then\n        rerrors = string.format(\"file(%s): %s\", filepath, rerrors or \"read failed!\")\n        return nil, rerrors\n    end\n    io.file_close(file)\n\n    -- do on_load()\n    if opt.on_load then\n        data = opt.on_load(data) or data\n    end\n\n    -- load script from string\n    return load(data, \"@\" .. displaypath, mode)\nend\n\n-- init loadfile\n--\n-- @param filepath      the lua file path\n-- @param mode          the load mode, e.g 't', 'b' or 'bt' (default)\n-- @param opt           the arguments option, e.g. {displaypath = \"\", nocache = true}\n--\nlocal _loadcache = {}\nfunction loadfile(filepath, mode, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get absolute path\n    filepath = path.absolute(filepath)\n\n    -- attempt to load script from cache first\n    local mtime = nil\n    local cache = (not opt.nocache) and _loadcache[filepath] or nil\n    if cache and cache.script then\n        mtime = os.mtime(filepath)\n        if mtime > 0 and cache.mtime == mtime then\n            return cache.script, nil\n        end\n    end\n\n    -- load file\n    local script, errors = _loadfile_impl(filepath, mode, opt)\n    if script then\n        _loadcache[filepath] = {script = script, mtime = mtime or os.mtime(filepath)}\n    end\n    return script, errors\nend\n\n-- init package path, package.searchers for lua5.4\ntable.insert(package.loaders or package.searchers, 2, function(v)\n    local filepath = xmake._PROGRAM_DIR .. \"/core/\" .. v .. \".lua\"\n    local script, serr = _loadfile_impl(filepath)\n    if not script then\n        return \"\\n\\tfailed to load \" .. filepath .. \" : \" .. serr\n    end\n    return script\nend)\n\n-- load modules\nlocal main = require(\"main\")\n\n-- the main function\nfunction _xmake_main()\n    return main.entry()\nend\n"
  },
  {
    "path": "xmake/core/base/base64.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        base64.lua\n--\n\n-- define module: base64\nlocal base64  = base64 or {}\n\n-- load modules\nlocal io    = require(\"base/io\")\nlocal utils = require(\"base/utils\")\nlocal bytes = require(\"base/bytes\")\n\n-- save metatable and builtin functions\nbase64._encode  = base64._encode or base64.encode\nbase64._decode  = base64._decode or base64.decode\n\n-- decode base64 string to the data\n--\n-- @param base64str       the base64 string\n--\n-- @return              the data\n--\nfunction base64.decode(base64str)\n    local data = base64._decode(base64str)\n    if not data then\n        return nil, string.format(\"decode base64 failed\")\n    end\n    return bytes(data)\nend\n\n-- encode data to the base64 string\n--\n-- @param data          the data\n--\n-- @return              the base64 string\n--\nfunction base64.encode(data)\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    local base64str, errors = base64._encode(dataaddr, datasize)\n    if not base64str then\n        return nil, errors or string.format(\"encode base64 failed\")\n    end\n    return base64str\nend\n\n-- return module: base64\nreturn base64\n"
  },
  {
    "path": "xmake/core/base/binutils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        binutils.lua\n--\n\n-- define module\nlocal binutils = binutils or {}\n\n-- load modules\nlocal os = require(\"base/os\")\n\n-- save original interfaces\nbinutils._bin2c = binutils._bin2c or binutils.bin2c\nbinutils._bin2coff = binutils._bin2coff or binutils.bin2coff\nbinutils._bin2macho = binutils._bin2macho or binutils.bin2macho\nbinutils._bin2elf = binutils._bin2elf or binutils.bin2elf\nbinutils._readsyms = binutils._readsyms or binutils.readsyms\nbinutils._deplibs = binutils._deplibs or binutils.deplibs\nbinutils._rpath_list = binutils._rpath_list or binutils.rpath_list\nbinutils._rpath_clean = binutils._rpath_clean or binutils.rpath_clean\nbinutils._extractlib = binutils._extractlib or binutils.extractlib\nbinutils._format = binutils._format or binutils.format\n\n-- generate c/c++ code from the binary file\nfunction binutils.bin2c(binaryfile, outputfile, opt)\n    opt = opt or {}\n    if binutils._bin2c then\n        return binutils._bin2c(binaryfile, outputfile, opt.linewidth or 32, opt.nozeroend or false)\n    else\n        -- fallback to old implementation if C implementation not available\n        return nil, \"C implementation not available\"\n    end\nend\n\n-- generate object file from the binary file\n-- @param binaryfile  the binary file path\n-- @param outputfile  the output object file path\n-- @param opt         the options\n--                      - format: the object file format (coff, elf, macho), required\n--                      - symbol_prefix: the symbol prefix (default: _binary_)\n--                      - arch: the target architecture (default: x86_64)\n--                      - plat: the target platform (default: macosx, only for macho)\n--                      - basename: the base name for symbols\n--                      - target_minver: the target minimum version (only for macho)\n--                      - xcode_sdkver: the Xcode SDK version (only for macho)\n--                      - zeroend: append null terminator (default: false)\nfunction binutils.bin2obj(binaryfile, outputfile, opt)\n    opt = opt or {}\n    local format = opt.format\n    if not format then\n        -- auto-detect format based on host platform\n        local host = os.host()\n        if host == \"windows\" or host == \"mingw\" or host == \"msys\" or host == \"cygwin\" then\n            format = \"coff\"\n        elseif host == \"macosx\" or host == \"iphoneos\" or host == \"watchos\" or host == \"appletvos\" then\n            format = \"macho\"\n        else\n            format = \"elf\"\n        end\n    end\n    format = format:lower()\n\n    if format == \"coff\" then\n        if not binutils._bin2coff then\n            return nil, \"binutils._bin2coff not available (C implementation not compiled)\"\n        end\n        return binutils._bin2coff(binaryfile, outputfile, opt.symbol_prefix or \"_binary_\", opt.arch or \"x86_64\", opt.basename, opt.zeroend or false)\n    elseif format == \"macho\" then\n        if not binutils._bin2macho then\n            return nil, \"binutils._bin2macho not available (C implementation not compiled)\"\n        end\n        return binutils._bin2macho(binaryfile, outputfile, opt.symbol_prefix or \"_binary_\", opt.plat or \"macosx\", opt.arch or \"x86_64\", opt.basename, opt.target_minver, opt.xcode_sdkver, opt.zeroend or false)\n    elseif format == \"elf\" then\n        if not binutils._bin2elf then\n            return nil, \"binutils._bin2elf not available (C implementation not compiled)\"\n        end\n        return binutils._bin2elf(binaryfile, outputfile, opt.symbol_prefix or \"_binary_\", opt.arch or \"x86_64\", opt.basename, opt.zeroend or false)\n    else\n        return nil, string.format(\"unsupported format '%s' (supported: coff, elf, macho)\", format)\n    end\nend\n\n-- get binary file format (auto-detect format: coff, elf, macho, ar, pe, unknown)\nfunction binutils.format(binaryfile)\n    if binutils._format then\n        return binutils._format(binaryfile)\n    else\n        return nil, \"C implementation not available\"\n    end\nend\n\n\n-- read symbols from object file (auto-detect format: COFF, ELF, or Mach-O)\nfunction binutils.readsyms(binaryfile)\n    if binutils._readsyms then\n        return binutils._readsyms(binaryfile)\n    else\n        return nil, \"C implementation not available\"\n    end\nend\n\n-- get dependent libraries from binary file (auto-detect format: COFF, ELF, or Mach-O)\nfunction binutils.deplibs(binaryfile)\n    if binutils._deplibs then\n        return binutils._deplibs(binaryfile)\n    else\n        return nil, \"C implementation not available\"\n    end\nend\n\n-- get rpath list from binary file (auto-detect format: ELF or Mach-O)\nfunction binutils.rpath_list(binaryfile)\n    if binutils._rpath_list then\n        return binutils._rpath_list(binaryfile)\n    else\n        return nil, \"internal rpath_list not supported!\"\n    end\nend\n\n-- insert rpath to binary file (auto-detect format: ELF or Mach-O)\n\n-- clean rpaths from binary file (auto-detect format: ELF or Mach-O)\nfunction binutils.rpath_clean(binaryfile)\n    if binutils._rpath_clean then\n        return binutils._rpath_clean(binaryfile)\n    else\n        return false, \"internal rpath_clean not supported!\"\n    end\nend\n\n-- extract static library to directory\n-- Supports AR format (.a) and MSVC lib format (.lib)\n-- @param libraryfile the static library file path (.a or .lib)\n-- @param outputdir    the output directory to extract object files\n-- @param opt          the options (optional)\n--                       - plain: extract all object files to the same directory (default: true)\n-- @return             true on success, false and error message on failure\nfunction binutils.extractlib(libraryfile, outputdir, opt)\n    if binutils._extractlib then\n        local ok, errors = binutils._extractlib(libraryfile, outputdir, opt and opt.plain)\n        if ok then\n            return true\n        else\n            return false, errors or \"unknown error\"\n        end\n    else\n        return false, \"C implementation not available\"\n    end\nend\n\n-- return module\nreturn binutils\n"
  },
  {
    "path": "xmake/core/base/bit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bit.lua\n--\n\nreturn (xmake._LUAJIT and require(\"bit\") or require(\"base/compat/bit\"))\n"
  },
  {
    "path": "xmake/core/base/bloom_filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bloom_filter.lua\n--\n\n-- define module: bloom_filter\nlocal bloom_filter = bloom_filter or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal io    = require(\"base/io\")\nlocal utils = require(\"base/utils\")\nlocal bytes = require(\"base/bytes\")\nlocal table = require(\"base/table\")\n\n-- save metatable and builtin functions\nbloom_filter._open     = bloom_filter._open or bloom_filter.open\nbloom_filter._close    = bloom_filter._close or bloom_filter.close\nbloom_filter._data     = bloom_filter._data or bloom_filter.data\nbloom_filter._size     = bloom_filter._size or bloom_filter.size\nbloom_filter._data_set = bloom_filter._data_set or bloom_filter.data_set\nbloom_filter._clear    = bloom_filter._clear or bloom_filter.clear\nbloom_filter._set      = bloom_filter._set or bloom_filter.set\nbloom_filter._get      = bloom_filter._get or bloom_filter.get\n\n-- the bloom filter probability\nbloom_filter.PROBABILITY_0_1         = 3  -- 1 / 2^3 = 0.125 ~= 0.1\nbloom_filter.PROBABILITY_0_01        = 6  -- 1 / 2^6 = 0.015625 ~= 0.01\nbloom_filter.PROBABILITY_0_001       = 10 -- 1 / 2^10 = 0.0009765625 ~= 0.001\nbloom_filter.PROBABILITY_0_0001      = 13 -- 1 / 2^13 = 0.0001220703125 ~= 0.0001\nbloom_filter.PROBABILITY_0_00001     = 16 -- 1 / 2^16 = 0.0000152587890625 ~= 0.00001\nbloom_filter.PROBABILITY_0_000001    = 20 -- 1 / 2^20 = 0.00000095367431640625 ~= 0.000001\n\n-- new a bloom filter\nfunction _instance.new(handle)\n    local instance   = table.inherit(_instance)\n    instance._HANDLE = handle\n    setmetatable(instance, _instance)\n    return instance\nend\n\n-- get cdata of the bloom filter\nfunction _instance:cdata()\n    return self._HANDLE\nend\n\n-- get the bloom filter data\nfunction _instance:data()\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- get the bloom filter data\n    local data = bloom_filter._data(self:cdata())\n    local size = bloom_filter._size(self:cdata())\n    if not data or size == 0 then\n        return nil, \"no data!\"\n    end\n\n    -- mount this data\n    return bytes(size, data)\nend\n\n-- set the bloom filter data\nfunction _instance:data_set(data)\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- set data\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    if not dataaddr or datasize == 0 then\n        return false, \"empty data!\"\n    end\n    return bloom_filter._data_set(self:cdata(), dataaddr, datasize)\nend\n\n-- clear the bloom filter data\nfunction _instance:clear()\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- do clear\n    return bloom_filter._clear(self:cdata())\nend\n\n-- set the bloom filter data item\n--\n--@code\n-- if bloom_filter:set(item)) then\n--     print(\"this data not exists, set ok!\")\n-- else\n--     -- note: maybe false positives\n--     print(\"this data have been existed, set failed!\")\n-- end\n--@endcode\n--\nfunction _instance:set(item)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- do set\n    ok = bloom_filter._set(self:cdata(), item)\n    return true, ok\nend\n\n-- get the bloom filter data item\n--\n--@code\n-- if bloom_filter:get(item)) then\n--     -- note: maybe false positives\n--     print(\"this data have been existed, get ok!\")\n-- else\n--     print(\"this data not exists, get failed!\")\n-- end\n--@endcode\n--\nfunction _instance:get(item)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- do get\n    ok = bloom_filter._get(self:cdata(), item)\n    return true, ok\nend\n\n-- ensure it is opened\nfunction _instance:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(bloom_filter)\nfunction _instance:__tostring()\n    return string.format(\"<bloom_filter: %s>\", self:cdata())\nend\n\n-- gc(bloom_filter)\nfunction _instance:__gc()\n    if self:cdata() and bloom_filter._close(self:cdata()) then\n        self._HANDLE = nil\n    end\nend\n\n-- new a bloom filter, e.g. {probability = 0.001, hash_count = 3, item_maxn = 1000000}\nfunction bloom_filter.new(opt)\n    opt = opt or {}\n    local probability = opt.probability or 0.001\n    local maps = {\n        [0.1] = bloom_filter.PROBABILITY_0_1,\n        [0.01] = bloom_filter.PROBABILITY_0_01,\n        [0.001] = bloom_filter.PROBABILITY_0_001,\n        [0.0001] = bloom_filter.PROBABILITY_0_0001,\n        [0.00001] = bloom_filter.PROBABILITY_0_00001,\n        [0.000001] = bloom_filter.PROBABILITY_0_000001\n    }\n    probability = assert(maps[probability], \"invalid probability(%f)\", probability)\n    local hash_count = opt.hash_count or 3\n    local item_maxn = opt.item_maxn or 1000000\n    local handle, errors = bloom_filter._open(probability, hash_count, item_maxn)\n    if handle then\n        return _instance.new(handle)\n    else\n        return nil, errors or \"failed to open a bloom filter!\"\n    end\nend\n\n-- return module: bloom_filter\nreturn bloom_filter\n"
  },
  {
    "path": "xmake/core/base/bytes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bytes.lua\n--\n\n-- define module: bytes\nlocal bytes = bytes or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal bit        = require(\"base/bit\")\nlocal os         = require(\"base/os\")\nlocal utils      = require(\"base/utils\")\nlocal todisplay  = require(\"base/todisplay\")\nlocal libc       = require(\"base/libc\")\nlocal table      = require(\"base/table\")\n\n-- new a bytes instance\n--\n-- bytes(size[, init]): allocates a buffer of given size, init with given number or char value\n-- bytes(size, ptr [, manage]): mounts buffer on existing storage (manage memory or not)\n-- bytes(str): mounts a buffer from the given string\n-- bytes(bytes, start, last): mounts a buffer from another one, with start/last limits\n-- bytes(bytes1, bytes2, bytes3, ...): allocates and concat buffer from list of byte buffers\n-- bytes(bytes): allocates a buffer from another one (strict replica, sharing memory)\n-- bytes({bytes1, bytes2, ...}): allocates and concat buffer from a list of byte buffers (table)\n-- bytes({})/bytes(): allocate an empty buffer\n--\nfunction _instance.new(...)\n    local args = {...}\n    local arg1, arg2, arg3 = table.unpack(args)\n    local instance = table.inherit(_instance)\n    if type(arg1) == \"number\" then\n        local size = arg1\n        local arg2_type = type(arg2)\n        if arg2_type == \"cdata\" or arg2_type == \"userdata\" then\n            -- bytes(size, ptr [, manage]): mounts buffer on existing storage (manage memory or not)\n            local ptr = arg2\n            local manage = arg3\n            if manage then\n                instance._CDATA   = libc.dataptr(ptr, {gc = true})\n                instance._MANAGED = true\n            else\n                instance._CDATA   = libc.dataptr(ptr)\n                instance._MANAGED = false\n            end\n        else\n            -- bytes(size[, init]): allocates a buffer of given size\n            local init\n            if arg2 then\n                if arg2_type == \"number\" then\n                    init = arg2\n                elseif arg2_type == \"string\" then\n                    init = arg2:byte()\n                else\n                    os.raise(\"invalid arguments #2 for bytes(size, ...), cdata, string, number or nil expected!\")\n                end\n            end\n            local ptr = libc.malloc(size, {gc = true})\n            if init then\n                libc.memset(ptr, init, size)\n            end\n            instance._CDATA   = ptr\n            instance._MANAGED = true\n        end\n        instance._SIZE     = size\n        instance._READONLY = false\n    elseif type(arg1) == \"string\" then\n        -- bytes(str): mounts a buffer from the given string\n        local str = arg1\n        instance._SIZE     = #str\n        instance._CDATA    = libc.dataptr(str)\n        instance._REF      = str -- keep ref for GC\n        instance._MANAGED  = false\n        instance._READONLY = true\n    elseif type(arg1) == \"table\" then\n        if type(arg2) == 'number' then\n            -- bytes(bytes, start, last): mounts a buffer from another one, with start/last limits:\n            local b = arg1\n            local start = arg2 or 1\n            local last = arg3 or b:size()\n            if start < 1 or last > b:size() then\n                os.raise(\"incorrect bounds(%d-%d) for bytes(...)!\", start, last)\n            end\n            instance._SIZE     = last - start + 1\n            instance._CDATA    = b:cdata() - 1 + start\n            instance._REF      = b -- keep lua ref for GC\n            instance._MANAGED  = false\n            instance._READONLY = b:readonly()\n        elseif type(arg2) == \"table\" then\n            -- bytes(bytes1, bytes2, bytes3, ...): allocates and concat buffer from list of byte buffers\n            instance._SIZE = 0\n            for _, b in ipairs(args) do\n                instance._SIZE = instance._SIZE + b:size()\n            end\n            instance._CDATA = libc.malloc(instance._SIZE, {gc = true})\n            local offset = 0\n            for _, b in ipairs(args) do\n                libc.memcpy(instance._CDATA + offset, b:cdata(), b:size())\n                offset = offset + b:size()\n            end\n            instance._MANAGED  = true\n            instance._READONLY = false\n        elseif not arg2 and arg1[1] and type(arg1[1]) == 'table' then\n            -- bytes({bytes1, bytes2, ...}): allocates and concat buffer from a list of byte buffers (table)\n            args = arg1\n            instance._SIZE = 0\n            for _, b in ipairs(args) do\n                instance._SIZE = instance._SIZE + b:size()\n            end\n            instance._CDATA = libc.malloc(instance._SIZE, {gc = true})\n            local offset = 0\n            for _, b in ipairs(args) do\n                libc.memcpy(instance._CDATA + offset, b._CDATA, b:size())\n                offset = offset + b:size()\n            end\n            instance._MANAGED  = true\n            instance._READONLY = false\n        elseif not arg2 and arg1.size and arg1:size() > 0 then\n            -- bytes(bytes): allocates a buffer from another one (strict replica, sharing memory)\n            local b = arg1\n            local start = 1\n            local last = arg3 or b:size()\n            if start < 1 or last > b:size() then\n                os.raise(\"incorrect bounds(%d-%d)!\", start, last)\n            end\n            instance._SIZE     = last - start + 1\n            instance._CDATA    = b:cdata() -1 + start\n            instance._REF      = b -- keep lua ref for GC\n            instance._MANAGED  = false\n            instance._READONLY = b:readonly()\n        else\n            -- bytes({}): allocate an empty buffer\n            instance._SIZE     = 0\n            instance._CDATA    = nil\n            instance._MANAGED  = false\n            instance._READONLY = true\n        end\n    elseif arg1 == nil then\n        -- bytes(): allocate an empty buffer\n        instance._SIZE     = 0\n        instance._CDATA    = nil\n        instance._MANAGED  = false\n        instance._READONLY = true\n    end\n    if instance:size() == nil then\n        os.raise(\"invalid arguments for bytes(...)!\")\n    end\n    setmetatable(instance, _instance)\n    return instance\nend\n\n-- get bytes size\nfunction _instance:size()\n    return self._SIZE\nend\n\n-- get bytes data\nfunction _instance:cdata()\n    return self._CDATA\nend\n\n-- get data address\nfunction _instance:caddr()\n    return libc.ptraddr(self:cdata())\nend\n\n-- readonly?\nfunction _instance:readonly()\n    return self._READONLY\nend\n\n-- bytes:ipairs()\nfunction _instance:ipairs()\n    local index = 0\n    return function (...)\n        if index < self:size() then\n            index = index + 1\n            return index, self[index]\n        end\n    end\nend\n\n-- get a slice of bytes\nfunction _instance:slice(start, last)\n    return bytes(self, start, last)\nend\n\n-- copy bytes\nfunction _instance:copy(src, start, last)\n    if self:readonly() then\n        os.raise(\"%s: cannot be modified!\", self)\n    end\n    if type(src) == \"string\" then\n        src = bytes(src)\n    end\n    local srcsize = src:size()\n    start = start or 1\n    last = last or srcsize\n    if start < 1 or start > srcsize then\n        os.raise(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > srcsize + start - 1 then\n        os.raise(\"%s: invalid last(%d)!\", self, last)\n    end\n    local copysize = last + 1 - start\n    if copysize > self:size() then\n        os.raise(\"%s: cannot copy bytes, src:size(%d) must be smaller than %d!\", self, copysize, self:size())\n    end\n    libc.memcpy(self:cdata(), src:cdata() + start - 1, copysize)\n    return self\nend\n\n-- copy bytes to the given position\nfunction _instance:copy2(pos, src, start, last)\n    if self:readonly() then\n        os.raise(\"%s: cannot be modified!\", self)\n    end\n    if type(src) == \"string\" then\n        src = bytes(src)\n    end\n    local srcsize = src:size()\n    start = start or 1\n    last = last or srcsize\n    if start < 1 or start > srcsize then\n        os.raise(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > srcsize + start - 1 then\n        os.raise(\"%s: invalid last(%d)!\", self, last)\n    end\n    if pos < 1 or pos > self:size() then\n        os.raise(\"%s: invalid pos(%d)!\", self, pos)\n    end\n    local copysize = last + 1 - start\n    local leftsize = self:size() + 1 - pos\n    if copysize > leftsize then\n        os.raise(\"%s: cannot copy bytes, src:size(%d) must be smaller than %d!\", self, copysize, leftsize)\n    end\n    libc.memcpy(self:cdata() + pos - 1, src:cdata() + start - 1, copysize)\n    return self\nend\n\n-- move bytes to the begin position\nfunction _instance:move(start, last)\n    if self:readonly() then\n        os.raise(\"%s: cannot be modified!\", self)\n    end\n    local totalsize = self:size()\n    start = start or 1\n    last = last or totalsize\n    if start < 1 or start > totalsize then\n        os.raise(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > totalsize + start - 1 then\n        os.raise(\"%s: invalid last(%d)!\", self, last)\n    end\n    local movesize = last + 1 - start\n    if movesize > totalsize then\n        os.raise(\"%s: cannot move bytes, move size(%d) must be smaller than %d!\", self, movesize, totalsize)\n    end\n    libc.memmov(self:cdata(), self:cdata() + start - 1, movesize)\n    return self\nend\n\n-- move bytes to the given position\nfunction _instance:move2(pos, start, last)\n    if self:readonly() then\n        os.raise(\"%s: cannot be modified!\", self)\n    end\n    local totalsize = self:size()\n    start = start or 1\n    last = last or totalsize\n    if start < 1 or start > totalsize then\n        os.raise(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > totalsize + start - 1 then\n        os.raise(\"%s: invalid last(%d)!\", self, last)\n    end\n    if pos < 1 or pos > totalsize then\n        os.raise(\"%s: invalid pos(%d)!\", self, pos)\n    end\n    local movesize = last + 1 - start\n    local leftsize = totalsize + 1 - pos\n    if movesize > leftsize then\n        os.raise(\"%s: cannot move bytes, move size(%d) must be smaller than %d!\", self, movesize, leftsize)\n    end\n    libc.memmov(self:cdata() + pos - 1, self:cdata() + start - 1, movesize)\n    return self\nend\n\n-- clone a new bytes buffer\nfunction _instance:clone()\n    local new = bytes(self:size())\n    new:copy(self)\n    return new\nend\n\n-- dump whole bytes data\nfunction _instance:dump(start, last)\n    start = start or 1\n    last = last or self:size()\n    local i    = 0\n    local n    = 147\n    local p    = start - 1\n    local e    = last\n    local line = nil\n    while p < e do\n        line = \"\"\n        if p + 0x20 <= e then\n\n            -- dump offset\n            line = line .. string.format(\"${color.dump.anchor}%08X ${color.dump.number}\", p)\n\n            -- dump data\n            for i = 0, 0x20 - 1 do\n                if (i % 4) == 0 then\n                    line = line .. \" \"\n                end\n                line = line .. string.format(\" %02X\", self[p + i + 1])\n            end\n\n            -- dump spaces\n            line = line .. \"  \"\n\n            -- dump characters\n            line = line .. \"${color.dump.string}\"\n            for i = 0, 0x20 - 1 do\n                local v = self[p + i + 1]\n                if v > 0x1f and v < 0x7f then\n                    line = line .. string.format(\"%c\", v)\n                else\n                    line = line .. '.'\n                end\n            end\n            line = line .. \"${clear}\"\n\n            -- dump line\n            utils.cprint(line)\n\n            -- next line\n            p = p + 0x20\n\n        elseif p < e then\n\n            -- init padding\n            local padding = n - 0x20\n\n            -- dump offset\n            line = line .. string.format(\"${color.dump.anchor}%08X ${color.dump.number}\", p)\n            if padding >= 9 then\n                padding = padding - 9\n            end\n\n            -- dump data\n            local left = e - p\n            for i = 0, left - 1 do\n                if (i % 4) == 0 then\n                    line = line .. \" \"\n                    if padding then\n                        padding = padding - 1\n                    end\n                end\n                line = line .. string.format(\" %02X\", self[p + i + 1])\n                if padding >= 3 then\n                    padding = padding - 3\n                end\n            end\n\n            -- dump spaces\n            while padding > 0 do\n                line = line .. \" \"\n                padding = padding - 1\n            end\n\n            -- dump characters\n            line = line .. \"${color.dump.string}\"\n            for i = 0, left - 1 do\n                local v = self[p + i + 1]\n                if v > 0x1f and v < 0x7f then\n                    line = line .. string.format(\"%c\", v)\n                else\n                    line = line .. '.'\n                end\n            end\n            line = line .. \"${clear}\"\n\n            -- dump line\n            utils.cprint(line)\n\n            -- next line\n            p = p + left\n\n        else\n            break\n        end\n    end\nend\n\n-- convert bytes to string\nfunction _instance:str(i, j)\n    local offset = i and i - 1 or 0\n    return libc.strndup(self:cdata() + offset, (j or self:size()) - offset)\nend\n\n-- get uint8 value\nfunction _instance:u8(offset)\n    return self[offset]\nend\n\n-- set uint8 value\nfunction _instance:u8_set(offset, value)\n    self[offset] = bit.band(value, 0xff)\n    return self\nend\n\n-- get sint8 value\nfunction _instance:s8(offset)\n    local value = self[offset]\n    return value < 0x80 and value or -0x100 + value\nend\n\n-- get uint16 little-endian value\nfunction _instance:u16le(offset)\n    return bit.lshift(self[offset + 1], 8) + self[offset]\nend\n\n-- set uint16 little-endian value\nfunction _instance:u16le_set(offset, value)\n    self[offset + 1] = bit.band(bit.rshift(value, 8), 0xff)\n    self[offset] = bit.band(value, 0xff)\n    return self\nend\n\n-- get uint16 big-endian value\nfunction _instance:u16be(offset)\n    return bit.lshift(self[offset], 8) + self[offset + 1]\nend\n\n-- set uint16 big-endian value\nfunction _instance:u16be_set(offset, value)\n    self[offset] = bit.band(bit.rshift(value, 8), 0xff)\n    self[offset + 1] = bit.band(value, 0xff)\n    return self\nend\n\n-- get sint16 little-endian value\nfunction _instance:s16le(offset)\n    local value = self:u16le(offset)\n    return value < 0x8000 and value or -0x10000 + value\nend\n\n-- get sint16 big-endian value\nfunction _instance:s16be(offset)\n    local value = self:u16be(offset)\n    return value < 0x8000 and value or -0x10000 + value\nend\n\n-- get uint32 little-endian value\nfunction _instance:u32le(offset)\n    return bit.lshift(self[offset + 3], 24) + bit.lshift(self[offset + 2], 16) + bit.lshift(self[offset + 1], 8) + self[offset]\nend\n\n-- set uint32 little-endian value\nfunction _instance:u32le_set(offset, value)\n    self[offset + 3] = bit.band(bit.rshift(value, 24), 0xff)\n    self[offset + 2] = bit.band(bit.rshift(value, 16), 0xff)\n    self[offset + 1] = bit.band(bit.rshift(value, 8), 0xff)\n    self[offset] = bit.band(value, 0xff)\n    return self\nend\n\n-- get uint32 big-endian value\nfunction _instance:u32be(offset)\n   return bit.lshift(self[offset], 24) + bit.lshift(self[offset + 1], 16) + bit.lshift(self[offset + 2], 8) + self[offset + 3]\nend\n\n-- set uint32 big-endian value\nfunction _instance:u32be_set(offset, value)\n    self[offset] = bit.band(bit.rshift(value, 24), 0xff)\n    self[offset + 1] = bit.band(bit.rshift(value, 16), 0xff)\n    self[offset + 2] = bit.band(bit.rshift(value, 8), 0xff)\n    self[offset + 3] = bit.band(value, 0xff)\n    return self\nend\n\n-- get sint32 little-endian value\nfunction _instance:s32le(offset)\n   return bit.tobit(self:u32le(offset))\nend\n\n-- get sint32 big-endian value\nfunction _instance:s32be(offset)\n   return bit.tobit(self:u32be(offset))\nend\n\n-- get byte or bytes slice at the given index position\n--\n-- bytes[1]\n-- bytes[{1, 2}]\n--\nfunction _instance:__index(key)\n    if type(key) == \"number\" then\n        if key < 1 or key > self:size() then\n            os.raise(\"%s: index(%d/%d) out of bounds!\", self, key, self:size())\n        end\n        return libc.byteof(self._CDATA, key - 1)\n    elseif type(key) == \"table\" then\n        local start, last = key[1], key[2]\n        return self:slice(start, last)\n    end\n    return rawget(self, key)\nend\n\n-- set byte or bytes slice at the given index position\n--\n-- bytes[1] = 0x1\n-- bytes[{1, 2}] = bytes(2)\n--\nfunction _instance:__newindex(key, value)\n    if self:readonly() then\n        os.raise(\"%s: cannot modify value at index[%s]!\", self, key)\n    end\n    if type(key) == \"number\" then\n        if key < 1 or key > self:size() then\n            os.raise(\"%s: index(%d/%d) out of bounds!\", self, key, self:size())\n        end\n        libc.setbyte(self._CDATA, key - 1, value)\n        return\n    elseif type(key) == \"table\" then\n        local start, last = key[1], key[2]\n        self:slice(start, last):copy(value)\n        return\n    end\n    rawset(self, key, value)\nend\n\n-- concat two bytes buffer\nfunction _instance:__concat(other)\n    local new = bytes(self:size() + other:size())\n    new:slice(1, self:size()):copy(self)\n    new:slice(self:size() + 1, new:size()):copy(other)\n    return new\nend\n\n-- tostring(bytes)\nfunction _instance:__tostring()\n    return \"<bytes: \" .. self:size() .. \">\"\nend\n\n-- todisplay(bytes)\nfunction _instance:__todisplay()\n    local parts = {}\n    local size = self:size()\n    if size > 8 then\n        size = 8\n    end\n    for i = 1, size do\n        parts[i] = \"0x\" .. bit.tohex(self[i], 2)\n    end\n    return \"bytes${reset}(\" .. todisplay(self:size()) .. \") <${color.dump.number}\" .. table.concat(parts, \" \") .. (self:size() > 8 and \"${reset} ..>\" or \"${reset}>\")\nend\n\n-- it's only called for lua runtime, because bytes is not userdata\nfunction _instance:__gc()\n    if self._MANAGED and self._CDATA then\n        libc.free(self._CDATA)\n        self._CDATA = nil\n    end\nend\n\n-- new an bytes instance\nfunction bytes.new(...)\n    return _instance.new(...)\nend\n\n-- is instance of bytes?\nfunction bytes.instance_of(data)\n    if type(data) == \"table\" and data.cdata and data.size then\n        return true\n    end\n    return false\nend\n\n-- register call function\nsetmetatable(bytes, {\n    __call = function (_, ...)\n        return bytes.new(...)\n    end,\n    __todisplay = function()\n        return todisplay(bytes.new)\n    end\n})\n\n-- return module: bytes\nreturn bytes\n"
  },
  {
    "path": "xmake/core/base/cli.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        cli.lua\n--\n\n-- define module\nlocal cli = cli or {}\nlocal segment = cli._segment or {}\n\n-- load modules\nlocal string    = require(\"base/string\")\nlocal hashset   = require(\"base/hashset\")\n\nsegment.__index = segment\ncli._segment = segment\n\nfunction segment:__tostring()\n    return self.string\nend\n\nfunction segment:__todisplay()\n    return string.format(\"${color.dump.string}%s${reset} ${color.dump.keyword}(%s)${reset}\", self.string, self.type)\nend\n\nfunction segment:is(type)\n    return self.type == type\nend\n\nfunction cli._make_segment(type, string, argv, argi, obj)\n    obj.type = type\n    obj.string = string\n    obj.argv = argv\n    obj.argi = argi\n    return setmetatable(obj, segment)\nend\n\nfunction cli._make_arg(value, argv, argi)\n    return cli._make_segment(\"arg\", value, argv, argi, { value = value })\nend\n\nfunction cli._make_flag(key, short, argv, argi)\n    return cli._make_segment(\"flag\", short and (\"-\" .. key) or (\"--\" .. key), argv, argi, { key = key, value = true, short = short or false })\nend\n\nfunction cli._make_option(key, value, short, argv, argi)\n    return cli._make_segment(\"option\", short and (\"-\" .. key .. \" \" .. value) or (\"--\" .. key .. \"=\" .. value), argv, argi, { key = key, value = value, short = short or false })\nend\n\n-- parse a argv string, command & sub-command should be omitted before calling this function\n-- @see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html\nfunction cli.parse(args, flags)\n    return cli.parsev(os.argv(args), flags)\nend\n\n-- parse a argv array, command & sub-command should be omitted before calling this function\n-- @see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html\nfunction cli.parsev(argv, flags)\n\n    local parsed = {}\n    local raw = false\n    local index = 1\n    local value = nil\n    flags = hashset.from(flags or {})\n\n    while index <= #argv do\n        value = argv[index]\n        if raw or not value:startswith(\"-\") or #value < 2 then\n            -- all args after \"--\" or first arg, args don\"t start with \"-\", and short args (include a single char \"-\")\n            raw = true\n            table.insert(parsed, cli._make_arg(value, argv, index))\n        elseif value == \"--\" then\n            -- stop parsing after \"--\"\n            raw = true\n            table.insert(parsed, cli._make_segment(\"sep\", \"--\", argv, index, {}))\n        elseif value:startswith(\"--\") then\n            -- \"--key:value\", \"--key=value\", \"--long-flag\"\n            local sep = value:find(\"[=:]\", 3, false)\n            -- ignore namespace, e.g. `--namespace::opt=`\n            if sep and value:sub(sep, sep + 1) == \"::\" then\n                sep = value:find(\"=\", 3, false)\n            end\n            if sep then\n                table.insert(parsed, cli._make_option(value:sub(3, sep - 1), value:sub(sep + 1), false, argv, index))\n            else\n                table.insert(parsed, cli._make_flag(value:sub(3), false, argv, index))\n            end\n        else\n            local strp = 2\n            while strp <= #value do\n                local ch = value:sub(strp, strp)\n                if flags:has(ch) then\n                    -- is a flag\n                    table.insert(parsed, cli._make_flag(ch, true, argv, index))\n                else\n                    -- is an option\n                    if strp == #value then\n                        -- is last char, use next arg as value\n                        table.insert(parsed, cli._make_option(ch, argv[index + 1] or \"\", true, argv, index))\n                        index = index + 1\n                    else\n                        -- is not last char, use remaining as value\n                        table.insert(parsed, cli._make_option(ch, value:sub(strp + 1), true, argv, index))\n                        strp = #value\n                    end\n                end\n                strp = strp + 1\n            end\n        end\n        index = index + 1\n    end\n    return parsed\nend\n\n-- return module\nreturn cli\n"
  },
  {
    "path": "xmake/core/base/colors.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        colors.lua\n--\n\n-- define module\nlocal colors = colors or {}\n\n-- load modules\nlocal tty -- lazy loading it\nlocal emoji = require(\"base/emoji\")\n\n-- the color8 keys\n--\n-- from https://github.com/hoelzro/ansicolors\n--\ncolors._keys8 =\n{\n    -- attributes\n    reset       = 0\n,   clear       = 0\n,   default     = 0\n,   bright      = 1\n,   dim         = 2\n,   underline   = 4\n,   blink       = 5\n,   reverse     = 7\n,   hidden      = 8\n\n    -- foreground\n,   black       = 30\n,   red         = 31\n,   green       = 32\n,   yellow      = 33\n,   blue        = 34\n,   magenta     = 35\n,   cyan        = 36\n,   white       = 37\n\n    -- background\n,   onblack     = 40\n,   onred       = 41\n,   ongreen     = 42\n,   onyellow    = 43\n,   onblue      = 44\n,   onmagenta   = 45\n,   oncyan      = 46\n,   onwhite     = 47\n}\n\n-- the color256 keys\n--\n-- from https://github.com/hoelzro/ansicolors\n--\ncolors._keys256 =\n{\n    -- attributes\n    reset       = 0\n,   clear       = 0\n,   default     = 0\n,   bright      = 1\n,   dim         = 2\n,   underline   = 4\n,   blink       = 5\n,   reverse     = 7\n,   hidden      = 8\n\n    -- foreground\n,   black       = \"38;5;0\"\n,   red         = \"38;5;1\"\n,   green       = \"38;5;2\"\n,   yellow      = \"38;5;3\"\n,   blue        = \"38;5;4\"\n,   magenta     = \"38;5;5\"\n,   cyan        = \"38;5;6\"\n,   white       = \"38;5;7\"\n\n    -- background\n,   onblack     = \"48;5;0\"\n,   onred       = \"48;5;1\"\n,   ongreen     = \"48;5;2\"\n,   onyellow    = \"48;5;3\"\n,   onblue      = \"48;5;4\"\n,   onmagenta   = \"48;5;5\"\n,   oncyan      = \"48;5;6\"\n,   onwhite     = \"48;5;7\"\n}\n\n-- the 24bits color keys\n--\n-- from https://github.com/hoelzro/ansicolors\n--\ncolors._keys24 =\n{\n    -- attributes\n    reset       = 0\n,   clear       = 0\n,   default     = 0\n,   bright      = 1\n,   dim         = 2\n,   underline   = 4\n,   blink       = 5\n,   reverse     = 7\n,   hidden      = 8\n\n    -- foreground\n,   black       = \"38;2;0;0;0\"\n,   red         = \"38;2;255;0;0\"\n,   green       = \"38;2;0;255;0\"\n,   yellow      = \"38;2;255;255;0\"\n,   blue        = \"38;2;0;0;255\"\n,   magenta     = \"38;2;255;0;255\"\n,   cyan        = \"38;2;0;255;255\"\n,   white       = \"38;2;255;255;255\"\n\n    -- background\n,   onblack     = \"48;2;0;0;0\"\n,   onred       = \"48;2;255;0;0\"\n,   ongreen     = \"48;2;0;255;0\"\n,   onyellow    = \"48;2;255;255;0\"\n,   onblue      = \"48;2;0;0;255\"\n,   onmagenta   = \"48;2;255;0;255\"\n,   oncyan      = \"48;2;0;255;255\"\n,   onwhite     = \"48;2;255;255;255\"\n}\n\n-- the escape string\ncolors._ESC = '\\x1b[%sm'\n\n-- make rainbow truecolor code by the index of characters\n--\n-- @param index     the index of characters\n-- @param seed      the seed, 0-255, default: random\n-- @param freq      the frequency, default: 0.1\n-- @param spread    the spread, default: 3.0\n--\n--\nfunction colors.rainbow24(index, seed, freq, spread)\n\n    -- init values\n    seed   = seed\n    freq   = freq or 0.1\n    spread = spread or 3.0\n    index  = seed + index / spread\n\n    -- make colors\n    local red   = math.sin(freq * index + 0) * 127 + 128\n    local green = math.sin(freq * index + 2 * math.pi / 3) * 127 + 128\n    local blue  = math.sin(freq * index + 4 * math.pi / 3) * 127 + 128\n\n    -- make code\n    return string.format(\"%d;%d;%d\", math.floor(red), math.floor(green), math.floor(blue))\nend\n\n-- make rainbow color256 code by the index of characters (16-256)\n--\n-- @param index     the index of characters\n-- @param seed      the seed, 0-255, default: random\n-- @param freq      the frequency, default: 0.1\n-- @param spread    the spread, default: 3.0\n--\n--\nfunction colors.rainbow256(index, seed, freq, spread)\n\n    -- init values\n    seed   = seed\n    freq   = freq or 0.1\n    spread = spread or 3.0\n    index  = seed + index / spread\n\n    -- make color code\n    local code = math.floor((freq * index) % 240 + 18)\n\n    -- make code\n    return string.format(\"#%d\", code)\nend\n\n-- translate colors from the string\n--\n-- @param str          the string with colors\n-- @param opt          options\n--                       patch_reset: wrap str with `\"${reset}\"`?\n--                       ignore_unknown: ignore unknown codes like `\"${unknown_code}\"`?\n--                       plain: false\n--\n-- 8 colors:\n--\n-- \"${red}hello\"\n-- \"${onred}hello${clear} xmake\"\n-- \"${bright red underline}hello\"\n-- \"${dim red}hello\"\n-- \"${blink red}hello\"\n-- \"${reverse red}hello xmake\"\n--\n-- 256 colors:\n--\n-- \"${#255}hello\"\n-- \"${on#255}hello${clear} xmake\"\n-- \"${bright #255; underline}hello\"\n-- \"${bright on#255 #10}hello${clear} xmake\"\n--\n-- true colors:\n--\n-- \"${255;0;0}hello\"\n-- \"${on;255;0;0}hello${clear} xmake\"\n-- \"${bright 255;0;0 underline}hello\"\n-- \"${bright on;255;0;0 0;255;0}hello${clear} xmake\"\n--\n-- emoji:\n--\n-- \"${beer}hello${beer}world\"\n--\n-- theme:\n-- \"${color.error}\"\n-- \"${bright color.warning}\"\n--\n-- text:\n-- \"${hello xmake}\"\n-- \"${hello xmake $beer}\"\n--\nfunction colors.translate(str, opt)\n\n    -- check string\n    if not str then\n        return nil\n    end\n\n    opt = opt or {}\n\n    -- get theme\n    local theme = colors.theme()\n\n    -- patch reset\n    if opt.patch_reset ~= false then\n        str = \"${reset}\" .. str .. \"${reset}\"\n    end\n\n    -- translate color blocks, e.g. ${red}, ${color.xxx}, ${emoji}\n    tty = tty or require(\"base/tty\")\n    local has_color8   = tty.has_color8()\n    local has_color256 = tty.has_color256()\n    local has_color24  = tty.has_color24()\n    local has_emoji    = tty.has_emoji()\n    str = str:gsub(\"(%${(.-)})\", function(_, word)\n\n        -- not supported? ignore it\n        local nocolors = false\n        if not has_color8 and not has_color256 and not has_color24 then\n            nocolors = true\n        end\n\n        -- is plain theme? no colors and no emoji\n        local noemoji = not has_emoji\n        if opt.plain or (theme and theme:name() == \"plain\") then\n            nocolors = true\n            noemoji = true\n        end\n\n        -- get keys\n        local keys = has_color256 and colors._keys256 or colors._keys8\n        if has_color24 then\n            keys = colors._keys24\n        end\n\n        -- split words\n        local blocks_raw = word:split(' ', {plain = true})\n\n        -- translate theme color first, e.g ${color.error}\n        local blocks = {}\n        for _, block in ipairs(blocks_raw) do\n            if theme then\n                local theme_block = theme:get(block)\n                if theme_block then\n                    for _, theme_block_sub in ipairs(theme_block:split(' ', {plain = true})) do\n                        table.insert(blocks, theme_block_sub)\n                    end\n                else\n                    table.insert(blocks, block)\n                end\n            elseif block:startswith(\"color.\") or block:startswith(\"text.\") then\n                local default_theme = {[\"color.error\"] = \"red\", [\"color.warning\"] = \"yellow\", [\"text.error\"] = \"error\", [\"text.warning\"] = \"warning\"}\n                local theme_block = default_theme[block]\n                if theme_block then\n                    table.insert(blocks, theme_block)\n                else\n                    table.insert(blocks, block)\n                end\n            else\n                table.insert(blocks, block)\n            end\n        end\n\n        -- make color buffer\n        local text_buffer = {}\n        local color_buffer = {}\n        for _, block in ipairs(blocks) do\n\n            -- get the color code\n            local code = keys[block]\n            if not code then\n                if has_color24 and block:find(\";\", 1, true) then\n                    if block:startswith(\"on;\") then\n                        code = block:gsub(\"on;\", \"48;2;\")\n                    else\n                        code = \"38;2;\" .. block\n                    end\n                elseif has_color256 and block:find(\"#\", 1, true) then\n                    if block:startswith(\"on#\") then\n                        code = block:gsub(\"on#\", \"48;5;\")\n                    else\n                        code = block:gsub(\"#\", \"38;5;\")\n                    end\n                elseif block:startswith(\"$\") then\n                    -- plain text, do not translate emoji\n                    table.insert(text_buffer, block:sub(2))\n                elseif not noemoji then\n                    -- get emoji code\n                    local emoji_code = emoji.translate(block)\n                    if emoji_code then\n                        table.insert(text_buffer, emoji_code)\n                    elseif not opt.ignore_unknown then\n                        -- unknown code, regard as plain text\n                        table.insert(text_buffer, block)\n                    end\n                elseif not opt.ignore_unknown then\n                    table.insert(text_buffer, block)\n                end\n            end\n\n            -- save this code\n            table.insert(color_buffer, code)\n        end\n\n        -- make result\n        local result = \"\"\n        if #color_buffer > 0 and not nocolors then\n            result = result .. colors._ESC:format(table.concat(color_buffer, \";\"))\n        end\n        if #text_buffer > 0 then\n            result = result .. table.concat(text_buffer, \" \")\n        end\n        return result\n    end)\n    return str\nend\n\n-- ignore all colors\nfunction colors.ignore(str)\n    if str then\n        -- strip \"${red}\" and \"${theme color}\"\n        str = colors.translate(str, {plain = true})\n        -- strip color code, e.g. for clang/gcc color diagnostics output\n        return (str:gsub(\"\\x1b%[.-m\", \"\"))\n    end\nend\n\n-- get theme\nfunction colors.theme()\n    return colors._THEME\nend\n\n-- set theme\nfunction colors.theme_set(theme)\n    colors._THEME = theme\nend\n\n-- return module\nreturn colors\n"
  },
  {
    "path": "xmake/core/base/compat/bit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bit.lua\n--\n\n-- define module: bit\nlocal bit = bit or {}\n\n-- bit/and operation\nfunction bit.band(a, b)\n    return a & b\nend\n\n-- bit/or operation\nfunction bit.bor(a, b)\n    return a | b\nend\n\n-- bit/xor operation\nfunction bit.bxor(a, b)\n    return a ~ b\nend\n\n-- bit/not operation\nfunction bit.bnot(a)\n    return ~a\nend\n\n-- bit/lshift operation\nfunction bit.lshift(a, b)\n    return a << b\nend\n\n-- bit/rshift operation\nfunction bit.rshift(a, b)\n    return a >> b\nend\n\n-- tobit operation\nfunction bit.tobit(x)\n    return x & 0xffffffff\nend\n\n-- tohex operation\nfunction bit.tohex(x, n)\n    n = n or 8\n    local up\n    if n <= 0 then\n        if n == 0 then return '' end\n        up = true\n        n = - n\n    end\n    x = x & (16 ^ n - 1)\n    return ('%0'..n..(up and 'X' or 'x')):format(x)\nend\n\n-- return module: bit\nreturn bit\n"
  },
  {
    "path": "xmake/core/base/compat/env.lua",
    "content": "-- (c) 2012 David Manura.  Licensed under the same terms as Lua 5.1/5.2 (MIT license).\n-- Permission is hereby granted, free of charge, to any person obtaining a copy\n-- of this software and associated documentation files (the \"Software\"), to deal\n-- in the Software without restriction, including without limitation the rights\n-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n-- copies of the Software, and to permit persons to whom the Software is\n-- furnished to do so, subject to the following conditions:\n--\n-- The above copyright notice and this permission notice shall be included in\n-- all copies or substantial portions of the Software.\n--\n-- THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n-- THE SOFTWARE.\n--\n-- @author      David Manura, ruki\n-- @file        env.lua\n--\n\n-- define module: env\nlocal env = env or {}\n\n-- from https://github.com/davidm/lua-inspect/blob/master/lib/luainspect/compat_env.lua\nif _G.setfenv then -- Lua 5.1\n    env.setfenv = _G.setfenv\n    env.getfenv = _G.getfenv\nelse -- >= Lua 5.2\n    -- helper function for `getfenv`/`setfenv`\n    local function envlookup(f)\n        local name, val\n        local up = 0\n        local unknown\n        repeat\n            up = up + 1; name, val = debug.getupvalue(f, up)\n            if name == '' then unknown = true end\n        until name == '_ENV' or name == nil\n        if name ~= '_ENV' then\n            up = nil\n            if unknown then error(\"upvalues not readable in Lua 5.2 when debug info missing\", 3) end\n        end\n        return (name == '_ENV') and up, val, unknown\n    end\n\n    -- helper function for `getfenv`/`setfenv`\n    local function envhelper(f, name)\n        if type(f) == 'number' then\n            if f < 0 then\n                error((\"bad argument #1 to '%s' (level must be non-negative)\"):format(name), 3)\n            elseif f < 1 then\n                error(\"thread environments unsupported in Lua 5.2\", 3) --[*]\n            end\n            f = debug.getinfo(f + 2, 'f').func\n        elseif type(f) ~= 'function' then\n            error((\"bad argument #1 to '%s' (number expected, got %s)\"):format(name, type(f)), 2)\n        end\n        return f\n    end\n    -- [*] might simulate with table keyed by coroutine.running()\n\n    -- 5.1 style `setfenv` implemented in 5.2\n    function env.setfenv(f, t)\n        local f = envhelper(f, 'setfenv')\n        local up, val, unknown = envlookup(f)\n        if up then\n            debug.upvaluejoin(f, up, function() return up end, 1) -- unique upvalue [*]\n            debug.setupvalue(f, up, t)\n        else\n            local what = debug.getinfo(f, 'S').what\n            if what ~= 'Lua' and what ~= 'main' then -- not Lua func\n                error(\"'setfenv' cannot change environment of given object\", 2)\n            end -- else ignore no _ENV upvalue (warning: incompatible with 5.1)\n        end\n    end\n    -- [*] http://lua-users.org/lists/lua-l/2010-06/msg00313.html\n\n    -- 5.1 style `getfenv` implemented in 5.2\n    function env.getfenv(f)\n        if f == 0 then return _G end -- simulated behavior\n        local f = envhelper(f or 1, 'getfenv')\n        local up, val = envlookup(f)\n        if not up then return _G end -- simulated behavior [**]\n        return val\n    end\n    -- [**] possible reasons: no _ENV upvalue, C function\n\n    -- register to global\n    _G.setfenv = env.setfenv\n    _G.getfenv = env.getfenv\n    debug.setfenv = env.setfenv\n    debug.getfenv = env.getfenv\nend\n\n-- return module: env\nreturn env\n"
  },
  {
    "path": "xmake/core/base/coroutine.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        coroutine.lua\n--\n\n-- define module: coroutine\nlocal coroutine = coroutine or {}\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal option    = require(\"base/option\")\nlocal string    = require(\"base/string\")\n\n-- save original interfaces\ncoroutine._resume  = coroutine._resume or coroutine.resume\n\n-- resume coroutine\nfunction coroutine.resume(co, ...)\n    local ok, results = coroutine._resume(co, ...)\n    if not ok then\n\n        -- get errors\n        local errors = results\n        if option.get(\"diagnosis\") then\n            errors = debug.traceback(co, results)\n        elseif type(results) == \"string\" then\n            -- remove the prefix info\n            local _, pos = results:find(\":%d+: \")\n            if pos then\n                errors = results:sub(pos + 1)\n            end\n        end\n        return false, errors\n    end\n    return true, results\nend\n\n-- return module: coroutine\nreturn coroutine\n"
  },
  {
    "path": "xmake/core/base/cpu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cpu.lua\n--\n\n-- define module\nlocal cpu = cpu or {}\n\n-- load modules\nlocal os      = require(\"base/os\")\nlocal winos   = require(\"base/winos\")\nlocal io      = require(\"base/io\")\nlocal hashset = require(\"base/hashset\")\n\n-- get cpu micro architecture for Intel\n--\n-- @see https://en.wikichip.org/wiki/intel/cpuid\n-- https://github.com/xmake-io/xmake/issues/1120\n--\nfunction cpu._march_intel()\n    local cpu_family = cpu.family()\n    local cpu_model  = cpu.model()\n    if cpu_family == 3 then\n        return \"80386\"\n    elseif cpu_family == 4 then\n        if cpu_model >= 1 and cpu_model <= 9 then\n            return \"80486\"\n        end\n    elseif cpu_family == 5 then\n        if cpu_model == 9 or cpu_model == 10 then\n            return \"Lakemont\"\n        elseif cpu_model == 1 or cpu_model == 2 or\n                cpu_model == 4 or cpu_model == 7 or cpu_model == 8 then\n            return \"P5\"\n        end\n    elseif cpu_family == 6 then\n        -- mic architecture\n        if cpu_model == 133 then\n            return \"Knights Mill\"\n        elseif cpu_model == 87 then\n            return \"Knights Landing\"\n        end\n\n        -- small cores\n        if cpu_model == 134 then\n            return \"Tremont\"\n        elseif cpu_model == 122 then\n            return \"Goldmont Plus\"\n        elseif cpu_model == 95 or cpu_model == 92 then\n            return \"Goldmont\"\n        elseif cpu_model == 76 then\n            return \"Airmont\"\n        elseif cpu_model == 93 or cpu_model == 90 or\n                cpu_model == 77 or cpu_model == 74 or cpu_model == 55 then\n            return \"Silvermont\"\n        elseif cpu_model == 54 or cpu_model == 53 or cpu_model == 39 then\n            return \"Saltwell\"\n        elseif cpu_model == 38 or cpu_model == 28 then\n            return \"Bonnell\"\n        end\n\n        -- big cores\n        if cpu_model == 183 then\n            return \"Raptor Lake\"\n        elseif cpu_model == 151 or cpu_model == 154 then\n            return \"Alder Lake\"\n        elseif cpu_model == 167 then\n            return \"Rocket Lake\"\n        elseif cpu_model == 140 then\n            return \"Tiger Lake\"\n        elseif cpu_model == 126 or cpu_model == 125 then\n            return \"Ice Lake\"\n        elseif cpu_model == 165 then\n            return \"Comet Lake\"\n        elseif cpu_model == 102 then\n            return \"Cannon Lake\"\n        elseif cpu_model == 142 or cpu_model == 158 then\n            return \"Kaby Lake\"\n        elseif cpu_model == 94 or cpu_model == 78 or cpu_model == 85 then\n            return \"Skylake\"\n        elseif cpu_model == 71 or cpu_model == 61 or cpu_model == 79 or cpu_model == 86 then\n            return \"Broadwell\"\n        elseif cpu_model == 70 or cpu_model == 69 or cpu_model == 60 or cpu_model == 63 then\n            return \"Haswell\"\n        elseif cpu_model == 58 or cpu_model == 62 then\n            return \"Ivy Bridge\"\n        elseif cpu_model == 42 or cpu_model == 45 then\n            return \"Sandy Bridge\"\n        elseif cpu_model == 37 or cpu_model == 44 or cpu_model == 47 then\n            return \"Westmere\"\n        elseif cpu_model == 31 or cpu_model == 30 or cpu_model == 46 or cpu_model == 26 then\n            return \"Nehalem\"\n        elseif cpu_model == 23 or cpu_model == 29 then\n            return \"Penryn\"\n        elseif cpu_model == 22 or cpu_model == 15 then\n            return \"Core\"\n        elseif cpu_model == 14 then\n            return \"Modified Pentium M\"\n        elseif cpu_model == 21 or cpu_model == 13 or cpu_model == 9 then\n            return \"Pentium M\"\n        elseif cpu_model == 11 or cpu_model == 10 or cpu_model == 8 or cpu_model == 7 or\n                cpu_model == 6 or cpu_model == 5 or cpu_model == 1 then\n            return \"P6\"\n        end\n    elseif cpu_family == 7 then\n        -- TODO Itanium\n    elseif cpu_family == 11 then\n        if cpu_model == 0 then\n            return \"knights-ferry\"\n        elseif cpu_model == 1 then\n            return \"knights-corner\"\n        end\n    elseif cpu_family == 15 then\n        if cpu_model <= 6 then\n            return \"netburst\"\n        end\n    end\nend\n\n-- get cpu micro architecture for AMD\n--\n-- @see https://en.wikichip.org/wiki/amd/cpuid\n--\nfunction cpu._march_amd()\n    local cpu_family = cpu.family()\n    local cpu_model  = cpu.model()\n    if cpu_family == 25 then\n        return \"Zen 3\"\n    elseif cpu_family == 24 then\n        return \"Zen\"\n    elseif cpu_family == 23 then\n        if cpu_model == 144 or cpu_model == 113 or cpu_model == 96 or cpu_model == 49 then\n            return \"Zen 2\"\n        elseif cpu_model == 24 or cpu_model == 8 then\n            return \"Zen+\"\n        else\n            return \"Zen\"\n        end\n    elseif cpu_family == 22 then\n        return \"AMD 16h\"\n    elseif cpu_family == 21 then\n        if cpu_model < 2 then\n            return \"Bulldozer\"\n        else\n            -- TODO and Steamroller, Excavator ..\n            return \"Piledriver\"\n        end\n    elseif cpu_family == 20 then\n        return \"Bobcat\"\n    elseif cpu_family == 16 then\n        return \"K10\"\n    elseif cpu_family == 15 then\n        if cpu_model > 64 then\n            return \"K8-sse3\"\n        else\n            return \"K8\"\n        end\n    end\nend\n\n-- get cpu info\nfunction cpu._info()\n    local cpuinfo = cpu._CPUINFO\n    if cpuinfo == nil then\n        cpuinfo = {}\n        if os.host() == \"macosx\" then\n            local ok, sysctl_result = os.iorun(\"/usr/sbin/sysctl -n machdep.cpu.vendor machdep.cpu.model machdep.cpu.family machdep.cpu.features machdep.cpu.brand_string\")\n            if ok and sysctl_result then\n                sysctl_result = sysctl_result:trim():split('\\n', {plain = true})\n                cpuinfo.vendor_id      = sysctl_result[1]\n                cpuinfo.cpu_model      = sysctl_result[2]\n                cpuinfo.cpu_family     = sysctl_result[3]\n                cpuinfo.cpu_features   = sysctl_result[4]\n                if cpuinfo.cpu_features then\n                    cpuinfo.cpu_features = cpuinfo.cpu_features:lower():gsub(\"%.\", \"_\")\n                end\n                cpuinfo.cpu_model_name = sysctl_result[5]\n            end\n        elseif os.host() == \"linux\" then\n            -- FIXME\n            -- local proc_cpuinfo = io.readfile(\"/proc/cpuinfo\")\n            local ok, proc_cpuinfo = os.iorun(\"cat /proc/cpuinfo\")\n            if ok and proc_cpuinfo then\n                for _, line in ipairs(proc_cpuinfo:split('\\n', {plain = true})) do\n                    if not cpuinfo.vendor_id and line:startswith(\"vendor_id\") then\n                        cpuinfo.vendor_id = line:match(\"vendor_id%s+:%s+(.*)\")\n                    end\n                    if not cpuinfo.cpu_model and line:startswith(\"model\") then\n                        cpuinfo.cpu_model = line:match(\"model%s+:%s+(.*)\")\n                    end\n                    if not cpuinfo.cpu_model_name and line:startswith(\"model name\") then\n                        cpuinfo.cpu_model_name = line:match(\"model name%s+:%s+(.*)\")\n                    end\n                    if not cpuinfo.cpu_family and line:startswith(\"cpu family\") then\n                        cpuinfo.cpu_family = line:match(\"cpu family%s+:%s+(.*)\")\n                    end\n                    if not cpuinfo.cpu_features and line:startswith(\"flags\") then\n                        cpuinfo.cpu_features = line:match(\"flags%s+:%s+(.*)\")\n                    end\n                    -- termux on android\n                    if not cpuinfo.cpu_features and line:startswith(\"Features\") then\n                        cpuinfo.cpu_features = line:match(\"Features%s+:%s+(.*)\")\n                    end\n                end\n            end\n        elseif os.host() == \"windows\" then\n            cpuinfo.vendor_id      = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0;VendorIdentifier\")\n            cpuinfo.cpu_model_name = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0;ProcessorNameString\")\n            local cpu_id = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0;Identifier\")\n            if cpu_id then\n                local cpu_family, cpu_model = cpu_id:match(\"Family (%d+) Model (%d+)\")\n                cpuinfo.cpu_family = cpu_family\n                cpuinfo.cpu_model  = cpu_model\n            end\n        elseif os.host() == \"bsd\" then\n            local ok, dmesginfo = os.iorun(\"dmesg\")\n            if ok and dmesginfo then\n                for _, line in ipairs(dmesginfo:split('\\n', {plain = true})) do\n                    if not cpuinfo.vendor_id and line:find(\"Origin=\", 1, true) then\n                        cpuinfo.vendor_id = line:match(\"Origin=\\\"(.-)\\\"\")\n                    end\n                    if not cpuinfo.cpu_model and line:find(\"Model=\", 1, true) then\n                        cpuinfo.cpu_model = line:match(\"Model=([%d%w]+)\")\n                    end\n                    if not cpuinfo.cpu_family and line:find(\"Family=\", 1, true) then\n                        cpuinfo.cpu_family = line:match(\"Family=([%d%w]+)\")\n                    end\n                    if line:find(\"Features=\", 1, true) then\n                        local cpu_features = line:match(\"Features=.*<(.-)>\")\n                        if cpu_features then\n                            if cpuinfo.cpu_features then\n                                cpuinfo.cpu_features = cpuinfo.cpu_features .. \",\" .. cpu_features\n                            else\n                                cpuinfo.cpu_features = cpu_features\n                            end\n                        end\n                    end\n                end\n                if cpuinfo.cpu_features then\n                    cpuinfo.cpu_features = cpuinfo.cpu_features:lower():gsub(\",\", \" \")\n                end\n                local ok, cpu_model_name = os.iorun(\"sysctl -n hw.model\")\n                if ok and cpu_model_name then\n                    cpuinfo.cpu_model_name = cpu_model_name:trim()\n                end\n            end\n        end\n        cpu._CPUINFO = cpuinfo\n    end\n    return cpuinfo\nend\n\n-- get cpu stats info\nfunction cpu._statinfo(name)\n    local stats = cpu._STATS\n    local stime = cpu._STIME\n    if stats == nil or stime == nil or os.time() - stime > 1 then -- cache 1s\n        stats = os._cpuinfo()\n        cpu._STATS = stats\n        cpu._STIME = os.time()\n    end\n    if name then\n        return stats[name]\n    else\n        return stats\n    end\nend\n\n-- get vendor id\nfunction cpu.vendor()\n    return cpu._info().vendor_id\nend\n\n-- get cpu model\nfunction cpu.model()\n    local cpu_model = cpu._info().cpu_model\n    return cpu_model and tonumber(cpu_model)\nend\n\n-- get cpu model name\nfunction cpu.model_name()\n    return cpu._info().cpu_model_name\nend\n\n-- get cpu family\nfunction cpu.family()\n    local cpu_family = cpu._info().cpu_family\n    return cpu_family and tonumber(cpu_family)\nend\n\n-- get cpu features\nfunction cpu.features()\n    return cpu._info().cpu_features\nend\n\n-- has the given feature?\nfunction cpu.has_feature(name)\n    local features = cpu._FEATURES\n    if not features then\n        features = cpu.features()\n        if features then\n            features = hashset.from(features:split('%s'))\n        end\n        cpu._FEATURES = features\n    end\n    return features:has(name)\nend\n\n-- get cpu micro architecture\nfunction cpu.march()\n    local march = cpu._MARCH\n    if march == nil then\n        local cpu_vendor = cpu.vendor()\n        if cpu_vendor == \"GenuineIntel\" then\n            march = cpu._march_intel()\n        elseif cpu_vendor == \"AuthenticAMD\" then\n            march = cpu._march_amd()\n        end\n        cpu._MARCH = march\n    end\n    return march\nend\n\n-- get cpu number\nfunction cpu.number()\n    return cpu._statinfo(\"ncpu\")\nend\n\n-- get cpu usage rate\nfunction cpu.usagerate()\n    return cpu._statinfo(\"usagerate\")\nend\n\n-- get cpu info\nfunction cpu.info(name)\n    local cpuinfo = {}\n    cpuinfo.vendor     = cpu.vendor()\n    cpuinfo.model      = cpu.model()\n    cpuinfo.family     = cpu.family()\n    cpuinfo.march      = cpu.march()\n    cpuinfo.ncpu       = cpu.number()\n    cpuinfo.features   = cpu.features()\n    cpuinfo.usagerate  = cpu.usagerate()\n    cpuinfo.model_name = cpu.model_name()\n    if name then\n        return cpuinfo[name]\n    else\n        return cpuinfo\n    end\nend\n\n-- return module\nreturn cpu\n"
  },
  {
    "path": "xmake/core/base/debugger.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        debugger.lua\n--\n\n-- define module\nlocal debugger = {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\n\n-- start emmylua debugger\n--\n-- e.g.\n--\n-- xrepo env -b emmylua_debugger xmake --version\n--\nfunction debugger:_start_emmylua_debugger()\n    local debugger_libfile = os.getenv(\"EMMYLUA_DEBUGGER\")\n    local script, errors = package.loadlib(debugger_libfile, \"luaopen_emmy_core\")\n    if not script then\n        return false, errors\n    end\n    local debugger_inst = script()\n    if not debugger_inst then\n        return false, \"cannot get debugger module!\"\n    end\n    debugger_inst.tcpListen(\"localhost\", 9966)\n    debugger_inst.waitIDE()\n    debugger_inst.breakHere()\n    return true\nend\n\n-- start debugging\nfunction debugger:start()\n    if self:has_emmylua() then\n        return self:_start_emmylua_debugger()\n    end\nend\n\n-- has emmylua debugger?\nfunction debugger:has_emmylua()\n    local debugger_libfile = os.getenv(\"EMMYLUA_DEBUGGER\")\n    if debugger_libfile and os.isfile(debugger_libfile) then\n        return true\n    end\nend\n\n-- debugger is enabled?\nfunction debugger:enabled()\n    return self:has_emmylua()\nend\n\n-- return module\nreturn debugger\n\n"
  },
  {
    "path": "xmake/core/base/deprecated.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        deprecated.lua\n--\n\n-- define module\nlocal deprecated = deprecated or {}\n\n-- add deprecated entry\nfunction deprecated.add(newformat, oldformat, ...)\n\n    local utils = require(\"base/utils\")\n    local old = string.format(oldformat, ...)\n    local new = newformat and string.format(newformat, ...) or false\n    if new then\n        utils.warning(\"%s is deprecated, please uses %s instead of it\", old, new)\n    else\n        utils.warning(\"%s is deprecated, please remove it\", old)\n    end\nend\n\n-- return module\nreturn deprecated\n"
  },
  {
    "path": "xmake/core/base/dump.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        dump.lua\n--\n\n-- define module\nlocal dump = dump or {}\n\n-- load modules\nlocal todisplay = require(\"base/todisplay\")\n\n-- print string\nfunction dump._print_string(str, as_key)\n    io.write(todisplay._print_string(str, as_key))\nend\n\n-- print keyword\nfunction dump._print_keyword(keyword)\n    io.write(todisplay._print_keyword(keyword))\nend\n\n-- print function\nfunction dump._print_function(func, as_key)\n    if as_key then\n        io.write(todisplay._translate(\"${reset}${color.dump.function}\"),\n            todisplay._format(\"text.dump.default_format\", \"%s\", func),\n            todisplay._translate(\"${reset}\"))\n    else\n        io.write(todisplay._print_function(func))\n    end\nend\n\n-- print scalar value\nfunction dump._print_scalar(value, as_key)\n    if type(value) == \"string\" then\n        dump._print_string(value, as_key)\n    elseif type(value) == \"function\" then\n        dump._print_function(value, as_key)\n    else\n        io.write(todisplay._print_scalar(value))\n    end\nend\n\n-- print anchor\nfunction dump._print_anchor(printed_set_value)\n    io.write(todisplay._translate(\"${color.dump.anchor}\"),\n        todisplay._format(\"text.dump.anchor\", \"&%s\", printed_set_value.id),\n        todisplay._translate(\"${reset}\"))\nend\n\n-- print reference\nfunction dump._print_reference(printed_set_value)\n    io.write(todisplay._translate(\"${color.dump.reference}\"),\n        todisplay._format(\"text.dump.reference\", \"*%s\", printed_set_value.id),\n        todisplay._translate(\"${reset}\"))\nend\n\n-- print anchor and store to printed_set\nfunction dump._print_table_anchor(value, printed_set)\n    io.write(\" \")\n    if printed_set[value].id then\n        dump._print_anchor(printed_set[value])\n        printed_set.refs[value] = printed_set[value]\n    end\nend\n\n-- print metatable of value\nfunction dump._print_metatable(value, metatable, inner_indent, printed_set, print_archor)\n    if not metatable then\n        return false\n    end\n\n    -- print metamethods\n    local has_record = false\n    local has_index_table = false\n    for k, v in pairs(metatable) do\n        if k == \"__index\" and type(v) == \"table\" then\n            has_index_table = true\n        elseif k:startswith(\"__\") then\n            if not has_record then\n                has_record = true\n                if print_archor then\n                    dump._print_table_anchor(value, printed_set)\n                end\n            end\n            io.write(\"\\n\", inner_indent)\n            local funcname = k:sub(3)\n            dump._print_keyword(funcname)\n            io.write(todisplay._translate(\"${reset} ${dim}=${reset} \"))\n            if funcname == \"tostring\" or funcname == \"len\" or funcname == \"todisplay\" then\n                local ok, result = pcall(v, value, value)\n                if ok then\n                    if funcname == \"todisplay\" and type(result) == \"string\" then\n                        io.write(todisplay._translate(result))\n                    else\n                        dump._print_scalar(result)\n                    end\n                    io.write(todisplay._translate(\"${dim} (evaluated)${reset}\"))\n                else\n                    dump._print_scalar(v)\n                end\n            elseif v and printed_set.refs[v] then\n                dump._print_reference(printed_set.refs[v])\n            else\n                dump._print_scalar(v)\n            end\n            io.write(\",\")\n        end\n    end\n\n    if not has_index_table then\n        return has_record\n    end\n\n    -- print index methods\n    local index_table = metatable and rawget(metatable, \"__index\")\n    for k, v in pairs(index_table) do\n        -- hide private interfaces\n        if type(k) ~= \"string\" or not k:startswith(\"_\") then\n            if not has_record then\n                has_record = true\n                if print_archor then\n                    dump._print_table_anchor(value, printed_set)\n                end\n            end\n            io.write(\"\\n\", inner_indent)\n            dump._print_keyword(\"(\")\n            dump._print_scalar(k, true)\n            dump._print_keyword(\")\")\n            io.write(todisplay._translate(\"${reset} ${dim}=${reset} \"))\n            if v and printed_set.refs[v] then\n                dump._print_reference(printed_set.refs[v])\n            else\n                dump._print_scalar(v)\n            end\n            io.write(\",\")\n        end\n    end\n    return has_record\nend\n\n-- init printed_set\nfunction dump._init_printed_set(printed_set, value)\n    assert(type(value) == \"table\")\n    for k, v in pairs(value) do\n        if type(v) == \"table\" then\n            -- has reference? v -> printed_set[v].obj\n            if printed_set[v] then\n                local obj = printed_set[v].obj\n                if not printed_set[obj].id then\n                    printed_set.id = printed_set.id + 1\n                    printed_set[obj].id = printed_set.id\n                end\n            else\n                printed_set[v] = {obj = v, name = k}\n                dump._init_printed_set(printed_set, v)\n            end\n        end\n    end\nend\n\n-- returns printed_set, is_first_level\nfunction dump._get_printed_set(printed_set, value)\n    local first_level = not printed_set\n    if type(printed_set) ~= \"table\" then\n        printed_set = {id = 0, refs = {}}\n        if type(value) == \"table\" then\n            printed_set[value] = {obj = value}\n            dump._init_printed_set(printed_set, value)\n        end\n    end\n    return printed_set, first_level\nend\n\n-- print udata\nfunction dump._print_udata(value, first_indent, remain_indent, printed_set)\n\n    local first_level\n    local metatable = debug.getmetatable(value)\n    printed_set, first_level = dump._get_printed_set(printed_set, metatable)\n    io.write(first_indent)\n\n    if not first_level then\n        io.write(todisplay._print_udata_scalar(value))\n    end\n    local inner_indent = remain_indent .. \"  \"\n\n    -- print open brackets\n    io.write(todisplay._translate(\"${reset}${color.dump.udata}[${reset}\"))\n\n    -- print metatable\n    local no_value = not dump._print_metatable(value, metatable, inner_indent, printed_set, false)\n\n    -- print close brackets\n    if no_value then\n        io.write(todisplay._translate(\" ${color.dump.udata}]${reset}\"))\n    else\n        io.write(\"\\b \\n\", remain_indent, todisplay._translate(\"${reset}${color.dump.udata}]${reset}\"))\n    end\nend\n\n-- print table\nfunction dump._print_table(value, first_indent, remain_indent, printed_set)\n\n    local first_level\n    printed_set, first_level = dump._get_printed_set(printed_set, value)\n    io.write(first_indent)\n    local metatable = debug.getmetatable(value)\n    local tostringmethod = metatable and (rawget(metatable, \"__todisplay\") or rawget(metatable, \"__tostring\"))\n    if not first_level and tostringmethod then\n        return dump._print_scalar(value)\n    end\n\n    local inner_indent = remain_indent .. \"  \"\n    local first_value = true\n\n    -- print open brackets\n    io.write(todisplay._translate(\"${reset}${color.dump.table}{${reset}\"))\n\n    local function print_newline()\n        if first_value then\n            dump._print_table_anchor(value, printed_set)\n            first_value = false\n        end\n        io.write(\"\\n\", inner_indent)\n    end\n\n    -- print metatable\n    if first_level then\n        first_value = not dump._print_metatable(value, metatable, inner_indent, printed_set, true)\n    end\n\n    -- print array items\n    local is_arr = (value[1] ~= nil) and (table.maxn(value) < 2 * #value)\n    if is_arr then\n        for i = 1, table.maxn(value) do\n            print_newline()\n            local v = value[i]\n            if type(v) == \"table\" then\n                if printed_set.refs[v] then\n                    dump._print_reference(printed_set.refs[v])\n                else\n                    dump._print_table(v, \"\", inner_indent, printed_set)\n                end\n            else\n                dump._print_scalar(v)\n            end\n            io.write(\",\")\n        end\n    end\n\n    -- print data\n    for k, v in pairs(value) do\n        if not is_arr or type(k) ~= \"number\" then\n            print_newline()\n            dump._print_scalar(k, true)\n            io.write(todisplay._translate(\"${reset} ${dim}=${reset} \"))\n            if type(v) == \"table\" then\n                if printed_set.refs[v] then\n                    dump._print_reference(printed_set.refs[v])\n                else\n                    dump._print_table(v, \"\", inner_indent, printed_set)\n                end\n            else\n                dump._print_scalar(v)\n            end\n            io.write(\",\")\n        end\n    end\n\n    -- print close brackets\n    if first_value then\n        io.write(todisplay._translate(\" ${color.dump.table}}${reset}\"))\n    else\n        io.write(\"\\b \\n\", remain_indent, todisplay._translate(\"${reset}${color.dump.table}}${reset}\"))\n    end\nend\n\n-- print value\nfunction dump._print(value, indent, verbose)\n    indent = tostring(indent or \"\")\n    if type(value) == \"table\" then\n        dump._print_table(value, indent, indent:gsub(\".\", \" \"), not verbose)\n    elseif type(value) == \"userdata\" then\n        dump._print_udata(value, indent, indent:gsub(\".\", \" \"), not verbose)\n    else\n        io.write(indent)\n        dump._print_scalar(value)\n    end\n    io.write(\"\\n\")\nend\n\nreturn dump._print\n"
  },
  {
    "path": "xmake/core/base/emoji.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        emoji.lua\n--\n\n-- define module\nlocal emoji = emoji or {}\n\n-- the emoji keys\n--\n-- from http://www.emoji-cheat-sheet.com/\n-- and https://weechat.org/files/scripts/pending/emoji.lua\n--\nemoji.keys =\n{\n    four=\"4⃣\",kiss_ww=\"👩❤💋👩\",maple_leaf=\"🍁\",waxing_gibbous_moon=\"🌔\",bike=\"🚲\",recycle=\"♻\",family_mwgb=\"👨👩👧👦\",flag_dk=\"🇩🇰\",thought_balloon=\"💭\",oncoming_automobile=\"🚘\",guardsman_tone5=\"💂🏿\",tickets=\"🎟\",school=\"🏫\",house_abandoned=\"🏚\",blue_book=\"📘\",video_game=\"🎮\",triumph=\"😤\",suspension_railway=\"🚟\",umbrella=\"☔\",levitate=\"🕴\",cactus=\"🌵\",monorail=\"🚝\",stars=\"🌠\",new=\"🆕\",herb=\"🌿\",pouting_cat=\"😾\",blue_heart=\"💙\",[\"100\"]=\"💯\",leaves=\"🍃\",family_mwbb=\"👨👩👦👦\",information_desk_person_tone2=\"💁🏼\",dragon_face=\"🐲\",track_next=\"⏭\",cloud_snow=\"🌨\",flag_jp=\"🇯🇵\",children_crossing=\"🚸\",information_desk_person_tone1=\"💁🏻\",arrow_up_down=\"↕\",mount_fuji=\"🗻\",massage_tone1=\"💆🏻\",flag_mq=\"🇲🇶\",massage_tone3=\"💆🏽\",massage_tone2=\"💆🏼\",massage_tone5=\"💆🏿\",flag_je=\"🇯🇪\",flag_jm=\"🇯🇲\",flag_jo=\"🇯🇴\",red_car=\"🚗\",hospital=\"🏥\",red_circle=\"🔴\",princess=\"👸\",tm=\"™\",curly_loop=\"➰\",boy_tone5=\"👦🏿\",pouch=\"👝\",boy_tone3=\"👦🏽\",boy_tone1=\"👦🏻\",izakaya_lantern=\"🏮\",fist_tone5=\"✊🏿\",fist_tone4=\"✊🏾\",fist_tone1=\"✊🏻\",fist_tone3=\"✊🏽\",fist_tone2=\"✊🏼\",arrow_lower_left=\"↙\",game_die=\"🎲\",pushpin=\"📌\",dividers=\"🗂\",dolphin=\"🐬\",night_with_stars=\"🌃\",cruise_ship=\"🛳\",white_medium_small_square=\"◽\",kissing_closed_eyes=\"😚\",earth_americas=\"🌎\",[\"end\"]=\"🔚\",mouse=\"🐭\",rewind=\"⏪\",beach=\"🏖\",pizza=\"🍕\",briefcase=\"💼\",customs=\"🛃\",heartpulse=\"💗\",sparkler=\"🎇\",sparkles=\"✨\",hand_splayed_tone1=\"🖐🏻\",snowman2=\"☃\",tulip=\"🌷\",speaking_head=\"🗣\",ambulance=\"🚑\",office=\"🏢\",clapper=\"🎬\",keyboard=\"⌨\",japan=\"🗾\",post_office=\"🏣\",dizzy_face=\"😵\",imp=\"👿\",flag_ve=\"🇻🇪\",coffee=\"☕\",flag_vg=\"🇻🇬\",flag_va=\"🇻🇦\",flag_vc=\"🇻🇨\",flag_vn=\"🇻🇳\",flag_vi=\"🇻🇮\",open_mouth=\"😮\",flag_vu=\"🇻🇺\",page_with_curl=\"📃\",bank=\"🏦\",bread=\"🍞\",oncoming_police_car=\"🚔\",capricorn=\"♑\",point_left=\"👈\",tokyo_tower=\"🗼\",fishing_pole_and_fish=\"🎣\",thumbsdown=\"👎\",telescope=\"🔭\",spider=\"🕷\",u7121=\"🈚\",camera_with_flash=\"📸\",lifter=\"🏋\",sweet_potato=\"🍠\",lock_with_ink_pen=\"🔏\",ok_woman_tone2=\"🙆🏼\",ok_woman_tone3=\"🙆🏽\",smirk=\"😏\",baggage_claim=\"🛄\",cherry_blossom=\"🌸\",sparkle=\"❇\",zap=\"⚡\",construction_site=\"🏗\",dancers=\"👯\",flower_playing_cards=\"🎴\",hatching_chick=\"🐣\",free=\"🆓\",bullettrain_side=\"🚄\",poultry_leg=\"🍗\",grapes=\"🍇\",smirk_cat=\"😼\",lollipop=\"🍭\",water_buffalo=\"🐃\",black_medium_small_square=\"◾\",atm=\"🏧\",gift_heart=\"💝\",older_woman_tone5=\"👵🏿\",older_woman_tone4=\"👵🏾\",older_woman_tone1=\"👵🏻\",older_woman_tone3=\"👵🏽\",older_woman_tone2=\"👵🏼\",scissors=\"✂\",woman_tone2=\"👩🏼\",basketball=\"🏀\",hammer_pick=\"⚒\",top=\"🔝\",clock630=\"🕡\",raising_hand_tone5=\"🙋🏿\",railway_track=\"🛤\",nail_care=\"💅\",crossed_flags=\"🎌\",minibus=\"🚐\",white_sun_cloud=\"🌥\",shower=\"🚿\",smile_cat=\"😸\",dog2=\"🐕\",loud_sound=\"🔊\",kaaba=\"🕋\",runner=\"🏃\",ram=\"🐏\",writing_hand=\"✍\",rat=\"🐀\",rice_scene=\"🎑\",milky_way=\"🌌\",vulcan_tone5=\"🖖🏿\",necktie=\"👔\",kissing_cat=\"😽\",snowflake=\"❄\",paintbrush=\"🖌\",crystal_ball=\"🔮\",mountain_bicyclist_tone4=\"🚵🏾\",mountain_bicyclist_tone3=\"🚵🏽\",mountain_bicyclist_tone2=\"🚵🏼\",mountain_bicyclist_tone1=\"🚵🏻\",koko=\"🈁\",flag_it=\"🇮🇹\",flag_iq=\"🇮🇶\",flag_is=\"🇮🇸\",flag_ir=\"🇮🇷\",flag_im=\"🇮🇲\",flag_il=\"🇮🇱\",flag_io=\"🇮🇴\",flag_in=\"🇮🇳\",flag_ie=\"🇮🇪\",flag_id=\"🇮🇩\",flag_ic=\"🇮🇨\",ballot_box_with_check=\"☑\",mountain_bicyclist_tone5=\"🚵🏿\",metal=\"🤘\",dog=\"🐶\",pineapple=\"🍍\",no_good_tone3=\"🙅🏽\",no_good_tone2=\"🙅🏼\",no_good_tone1=\"🙅🏻\",scream=\"😱\",no_good_tone5=\"🙅🏿\",no_good_tone4=\"🙅🏾\",flag_ua=\"🇺🇦\",bomb=\"💣\",flag_ug=\"🇺🇬\",flag_um=\"🇺🇲\",flag_us=\"🇺🇸\",construction_worker_tone1=\"👷🏻\",radio=\"📻\",flag_uy=\"🇺🇾\",flag_uz=\"🇺🇿\",person_with_blond_hair_tone1=\"👱🏻\",cupid=\"💘\",mens=\"🚹\",rice=\"🍚\",point_right_tone1=\"👉🏻\",point_right_tone3=\"👉🏽\",point_right_tone2=\"👉🏼\",sunglasses=\"😎\",point_right_tone4=\"👉🏾\",watch=\"⌚\",frowning=\"😦\",watermelon=\"🍉\",wedding=\"💒\",person_frowning_tone4=\"🙍🏾\",person_frowning_tone5=\"🙍🏿\",person_frowning_tone2=\"🙍🏼\",person_frowning_tone3=\"🙍🏽\",person_frowning_tone1=\"🙍🏻\",flag_gw=\"🇬🇼\",flag_gu=\"🇬🇺\",flag_gt=\"🇬🇹\",flag_gs=\"🇬🇸\",flag_gr=\"🇬🇷\",flag_gq=\"🇬🇶\",flag_gp=\"🇬🇵\",flag_gy=\"🇬🇾\",flag_gg=\"🇬🇬\",flag_gf=\"🇬🇫\",microscope=\"🔬\",flag_gd=\"🇬🇩\",flag_gb=\"🇬🇧\",flag_ga=\"🇬🇦\",flag_gn=\"🇬🇳\",flag_gm=\"🇬🇲\",flag_gl=\"🇬🇱\",japanese_ogre=\"👹\",flag_gi=\"🇬🇮\",flag_gh=\"🇬🇭\",man_with_turban=\"👳\",star_and_crescent=\"☪\",writing_hand_tone3=\"✍🏽\",dromedary_camel=\"🐪\",hash=\"#⃣\",hammer=\"🔨\",hourglass=\"⌛\",postbox=\"📮\",writing_hand_tone5=\"✍🏿\",writing_hand_tone4=\"✍🏾\",wc=\"🚾\",aquarius=\"♒\",couple_with_heart=\"💑\",ok_woman=\"🙆\",raised_hands_tone4=\"🙌🏾\",cop=\"👮\",raised_hands_tone1=\"🙌🏻\",cow=\"🐮\",raised_hands_tone3=\"🙌🏽\",white_large_square=\"⬜\",pig_nose=\"🐽\",ice_skate=\"⛸\",hotsprings=\"♨\",tone5=\"🏿\",three=\"3⃣\",beer=\"🍺\",stadium=\"🏟\",airplane_departure=\"🛫\",heavy_division_sign=\"➗\",flag_black=\"🏴\",mushroom=\"🍄\",record_button=\"⏺\",vulcan=\"🖖\",dash=\"💨\",wind_chime=\"🎐\",anchor=\"⚓\",seven=\"7⃣\",flag_hr=\"🇭🇷\",roller_coaster=\"🎢\",pen_ballpoint=\"🖊\",sushi=\"🍣\",flag_ht=\"🇭🇹\",flag_hu=\"🇭🇺\",flag_hk=\"🇭🇰\",dizzy=\"💫\",flag_hn=\"🇭🇳\",flag_hm=\"🇭🇲\",arrow_forward=\"▶\",violin=\"🎻\",orthodox_cross=\"☦\",id=\"🆔\",heart_decoration=\"💟\",first_quarter_moon=\"🌓\",satellite=\"📡\",tone3=\"🏽\",christmas_tree=\"🎄\",unicorn=\"🦄\",broken_heart=\"💔\",ocean=\"🌊\",hearts=\"♥\",snowman=\"⛄\",person_with_blond_hair_tone4=\"👱🏾\",person_with_blond_hair_tone5=\"👱🏿\",person_with_blond_hair_tone2=\"👱🏼\",person_with_blond_hair_tone3=\"👱🏽\",yen=\"💴\",straight_ruler=\"📏\",sleepy=\"😪\",green_apple=\"🍏\",white_medium_square=\"◻\",flag_fr=\"🇫🇷\",grey_exclamation=\"❕\",innocent=\"😇\",flag_fm=\"🇫🇲\",flag_fo=\"🇫🇴\",flag_fi=\"🇫🇮\",flag_fj=\"🇫🇯\",flag_fk=\"🇫🇰\",menorah=\"🕎\",yin_yang=\"☯\",clock130=\"🕜\",gift=\"🎁\",prayer_beads=\"📿\",stuck_out_tongue=\"😛\",om_symbol=\"🕉\",city_dusk=\"🌆\",massage_tone4=\"💆🏾\",couple_ww=\"👩❤👩\",crown=\"👑\",sparkling_heart=\"💖\",clubs=\"♣\",person_with_pouting_face=\"🙎\",newspaper2=\"🗞\",fog=\"🌫\",dango=\"🍡\",large_orange_diamond=\"🔶\",flag_tn=\"🇹🇳\",flag_to=\"🇹🇴\",point_up=\"☝\",flag_tm=\"🇹🇲\",flag_tj=\"🇹🇯\",flag_tk=\"🇹🇰\",flag_th=\"🇹🇭\",flag_tf=\"🇹🇫\",flag_tg=\"🇹🇬\",corn=\"🌽\",flag_tc=\"🇹🇨\",flag_ta=\"🇹🇦\",flag_tz=\"🇹🇿\",flag_tv=\"🇹🇻\",flag_tw=\"🇹🇼\",flag_tt=\"🇹🇹\",flag_tr=\"🇹🇷\",eight_spoked_asterisk=\"✳\",trophy=\"🏆\",black_small_square=\"▪\",o=\"⭕\",no_bell=\"🔕\",curry=\"🍛\",alembic=\"⚗\",sob=\"😭\",waxing_crescent_moon=\"🌒\",tiger2=\"🐅\",two=\"2⃣\",sos=\"🆘\",compression=\"🗜\",heavy_multiplication_x=\"✖\",tennis=\"🎾\",fireworks=\"🎆\",skull_crossbones=\"☠\",astonished=\"😲\",congratulations=\"㊗\",grey_question=\"❔\",arrow_upper_left=\"↖\",arrow_double_up=\"⏫\",triangular_flag_on_post=\"🚩\",gemini=\"♊\",door=\"🚪\",ship=\"🚢\",point_down_tone3=\"👇🏽\",point_down_tone4=\"👇🏾\",point_down_tone5=\"👇🏿\",movie_camera=\"🎥\",ng=\"🆖\",couple_mm=\"👨❤👨\",football=\"🏈\",asterisk=\"*⃣\",taurus=\"♉\",articulated_lorry=\"🚛\",police_car=\"🚓\",flushed=\"😳\",spades=\"♠\",cloud_lightning=\"🌩\",wine_glass=\"🍷\",clock830=\"🕣\",punch_tone2=\"👊🏼\",punch_tone3=\"👊🏽\",punch_tone1=\"👊🏻\",department_store=\"🏬\",punch_tone4=\"👊🏾\",punch_tone5=\"👊🏿\",crocodile=\"🐊\",white_square_button=\"🔳\",hole=\"🕳\",boy_tone2=\"👦🏼\",mountain_cableway=\"🚠\",melon=\"🍈\",persevere=\"😣\",trident=\"🔱\",head_bandage=\"🤕\",u7a7a=\"🈳\",cool=\"🆒\",high_brightness=\"🔆\",deciduous_tree=\"🌳\",white_flower=\"💮\",gun=\"🔫\",flag_sk=\"🇸🇰\",flag_sj=\"🇸🇯\",flag_si=\"🇸🇮\",flag_sh=\"🇸🇭\",flag_so=\"🇸🇴\",flag_sn=\"🇸🇳\",flag_sm=\"🇸🇲\",flag_sl=\"🇸🇱\",flag_sc=\"🇸🇨\",flag_sb=\"🇸🇧\",flag_sa=\"🇸🇦\",flag_sg=\"🇸🇬\",flag_tl=\"🇹🇱\",flag_se=\"🇸🇪\",arrow_left=\"⬅\",flag_sz=\"🇸🇿\",flag_sy=\"🇸🇾\",small_orange_diamond=\"🔸\",flag_ss=\"🇸🇸\",flag_sr=\"🇸🇷\",flag_sv=\"🇸🇻\",flag_st=\"🇸🇹\",file_folder=\"📁\",flag_td=\"🇹🇩\",[\"1234\"]=\"🔢\",smiling_imp=\"😈\",surfer_tone2=\"🏄🏼\",surfer_tone3=\"🏄🏽\",surfer_tone4=\"🏄🏾\",surfer_tone5=\"🏄🏿\",amphora=\"🏺\",baseball=\"⚾\",boy=\"👦\",flag_es=\"🇪🇸\",raised_hands=\"🙌\",flag_eu=\"🇪🇺\",flag_et=\"🇪🇹\",heavy_plus_sign=\"➕\",bow=\"🙇\",flag_ea=\"🇪🇦\",flag_ec=\"🇪🇨\",flag_ee=\"🇪🇪\",light_rail=\"🚈\",flag_eg=\"🇪🇬\",flag_eh=\"🇪🇭\",massage=\"💆\",man_with_gua_pi_mao_tone4=\"👲🏾\",man_with_gua_pi_mao_tone3=\"👲🏽\",outbox_tray=\"📤\",clock330=\"🕞\",projector=\"📽\",sake=\"🍶\",confounded=\"😖\",angry=\"😠\",iphone=\"📱\",sweat_smile=\"😅\",aries=\"♈\",ear_of_rice=\"🌾\",mouse2=\"🐁\",bicyclist_tone4=\"🚴🏾\",bicyclist_tone5=\"🚴🏿\",guardsman=\"💂\",bicyclist_tone1=\"🚴🏻\",bicyclist_tone2=\"🚴🏼\",bicyclist_tone3=\"🚴🏽\",envelope=\"✉\",money_with_wings=\"💸\",beers=\"🍻\",heart_exclamation=\"❣\",notepad_spiral=\"🗒\",cat=\"🐱\",running_shirt_with_sash=\"🎽\",ferry=\"⛴\",spy=\"🕵\",chart_with_upwards_trend=\"📈\",green_heart=\"💚\",confused=\"😕\",angel_tone4=\"👼🏾\",scorpius=\"♏\",sailboat=\"⛵\",elephant=\"🐘\",map=\"🗺\",disappointed_relieved=\"😥\",flag_xk=\"🇽🇰\",motorway=\"🛣\",sun_with_face=\"🌞\",birthday=\"🎂\",mag=\"🔍\",date=\"📅\",dove=\"🕊\",man=\"👨\",octopus=\"🐙\",wheelchair=\"♿\",truck=\"🚚\",sa=\"🈂\",shield=\"🛡\",haircut=\"💇\",last_quarter_moon_with_face=\"🌜\",rosette=\"🏵\",currency_exchange=\"💱\",mailbox_with_no_mail=\"📭\",bath=\"🛀\",clock930=\"🕤\",bowling=\"🎳\",turtle=\"🐢\",pause_button=\"⏸\",construction_worker=\"👷\",unlock=\"🔓\",anger_right=\"🗯\",beetle=\"🐞\",girl=\"👧\",sunrise=\"🌅\",exclamation=\"❗\",flag_dz=\"🇩🇿\",family_mmgg=\"👨👨👧👧\",factory=\"🏭\",flag_do=\"🇩🇴\",flag_dm=\"🇩🇲\",flag_dj=\"🇩🇯\",mouse_three_button=\"🖱\",flag_dg=\"🇩🇬\",flag_de=\"🇩🇪\",star_of_david=\"✡\",reminder_ribbon=\"🎗\",grimacing=\"😬\",thumbsup_tone3=\"👍🏽\",thumbsup_tone2=\"👍🏼\",thumbsup_tone1=\"👍🏻\",musical_note=\"🎵\",thumbsup_tone5=\"👍🏿\",thumbsup_tone4=\"👍🏾\",high_heel=\"👠\",green_book=\"📗\",headphones=\"🎧\",flag_aw=\"🇦🇼\",stop_button=\"⏹\",yum=\"😋\",flag_aq=\"🇦🇶\",warning=\"⚠\",cheese=\"🧀\",ophiuchus=\"⛎\",revolving_hearts=\"💞\",one=\"1⃣\",ring=\"💍\",point_right=\"👉\",sheep=\"🐑\",bookmark=\"🔖\",spider_web=\"🕸\",eyes=\"👀\",flag_ro=\"🇷🇴\",flag_re=\"🇷🇪\",flag_rs=\"🇷🇸\",sweat_drops=\"💦\",flag_ru=\"🇷🇺\",flag_rw=\"🇷🇼\",middle_finger=\"🖕\",race_car=\"🏎\",evergreen_tree=\"🌲\",biohazard=\"☣\",girl_tone3=\"👧🏽\",scream_cat=\"🙀\",computer=\"💻\",hourglass_flowing_sand=\"⏳\",flag_lb=\"🇱🇧\",tophat=\"🎩\",clock1230=\"🕧\",tractor=\"🚜\",u6709=\"🈶\",u6708=\"🈷\",crying_cat_face=\"😿\",angel=\"👼\",ant=\"🐜\",information_desk_person=\"💁\",anger=\"💢\",mailbox_with_mail=\"📬\",pencil2=\"✏\",wink=\"😉\",thermometer=\"🌡\",relaxed=\"☺\",printer=\"🖨\",credit_card=\"💳\",checkered_flag=\"🏁\",family_mmg=\"👨👨👧\",pager=\"📟\",family_mmb=\"👨👨👦\",radioactive=\"☢\",fried_shrimp=\"🍤\",link=\"🔗\",walking=\"🚶\",city_sunset=\"🌇\",shopping_bags=\"🛍\",hockey=\"🏒\",arrow_up=\"⬆\",gem=\"💎\",negative_squared_cross_mark=\"❎\",worried=\"😟\",walking_tone5=\"🚶🏿\",walking_tone1=\"🚶🏻\",hear_no_evil=\"🙉\",convenience_store=\"🏪\",seat=\"💺\",girl_tone1=\"👧🏻\",cloud_rain=\"🌧\",girl_tone2=\"👧🏼\",girl_tone5=\"👧🏿\",girl_tone4=\"👧🏾\",parking=\"🅿\",pisces=\"♓\",calendar=\"📆\",loudspeaker=\"📢\",camping=\"🏕\",bicyclist=\"🚴\",label=\"🏷\",diamonds=\"♦\",older_man_tone1=\"👴🏻\",older_man_tone3=\"👴🏽\",older_man_tone2=\"👴🏼\",older_man_tone5=\"👴🏿\",older_man_tone4=\"👴🏾\",microphone2=\"🎙\",raising_hand=\"🙋\",hot_pepper=\"🌶\",guitar=\"🎸\",tropical_drink=\"🍹\",upside_down=\"🙃\",restroom=\"🚻\",pen_fountain=\"🖋\",comet=\"☄\",cancer=\"♋\",jeans=\"👖\",flag_qa=\"🇶🇦\",boar=\"🐗\",turkey=\"🦃\",person_with_blond_hair=\"👱\",oden=\"🍢\",stuck_out_tongue_closed_eyes=\"😝\",helicopter=\"🚁\",control_knobs=\"🎛\",performing_arts=\"🎭\",tiger=\"🐯\",foggy=\"🌁\",sound=\"🔉\",flag_cz=\"🇨🇿\",flag_cy=\"🇨🇾\",flag_cx=\"🇨🇽\",speech_balloon=\"💬\",seedling=\"🌱\",flag_cr=\"🇨🇷\",envelope_with_arrow=\"📩\",flag_cp=\"🇨🇵\",flag_cw=\"🇨🇼\",flag_cv=\"🇨🇻\",flag_cu=\"🇨🇺\",flag_ck=\"🇨🇰\",flag_ci=\"🇨🇮\",flag_ch=\"🇨🇭\",flag_co=\"🇨🇴\",flag_cn=\"🇨🇳\",flag_cm=\"🇨🇲\",u5408=\"🈴\",flag_cc=\"🇨🇨\",flag_ca=\"🇨🇦\",flag_cg=\"🇨🇬\",flag_cf=\"🇨🇫\",flag_cd=\"🇨🇩\",purse=\"👛\",telephone=\"☎\",sleeping=\"😴\",point_down_tone1=\"👇🏻\",frowning2=\"☹\",point_down_tone2=\"👇🏼\",muscle_tone4=\"💪🏾\",muscle_tone5=\"💪🏿\",synagogue=\"🕍\",muscle_tone1=\"💪🏻\",muscle_tone2=\"💪🏼\",muscle_tone3=\"💪🏽\",clap_tone5=\"👏🏿\",clap_tone4=\"👏🏾\",clap_tone1=\"👏🏻\",train2=\"🚆\",clap_tone2=\"👏🏼\",oil=\"🛢\",diamond_shape_with_a_dot_inside=\"💠\",barber=\"💈\",metal_tone3=\"🤘🏽\",ice_cream=\"🍨\",rowboat_tone4=\"🚣🏾\",burrito=\"🌯\",metal_tone1=\"🤘🏻\",joystick=\"🕹\",rowboat_tone1=\"🚣🏻\",taxi=\"🚕\",u7533=\"🈸\",racehorse=\"🐎\",snowboarder=\"🏂\",thinking=\"🤔\",wave_tone1=\"👋🏻\",wave_tone2=\"👋🏼\",wave_tone3=\"👋🏽\",wave_tone4=\"👋🏾\",wave_tone5=\"👋🏿\",desktop=\"🖥\",stopwatch=\"⏱\",pill=\"💊\",skier=\"⛷\",orange_book=\"📙\",dart=\"🎯\",disappointed=\"😞\",grin=\"😁\",place_of_worship=\"🛐\",japanese_goblin=\"👺\",arrows_counterclockwise=\"🔄\",laughing=\"😆\",clap=\"👏\",left_right_arrow=\"↔\",japanese_castle=\"🏯\",nail_care_tone4=\"💅🏾\",nail_care_tone5=\"💅🏿\",nail_care_tone2=\"💅🏼\",nail_care_tone3=\"💅🏽\",nail_care_tone1=\"💅🏻\",raised_hand_tone4=\"✋🏾\",raised_hand_tone5=\"✋🏿\",raised_hand_tone1=\"✋🏻\",raised_hand_tone2=\"✋🏼\",raised_hand_tone3=\"✋🏽\",point_left_tone3=\"👈🏽\",point_left_tone2=\"👈🏼\",tanabata_tree=\"🎋\",point_left_tone5=\"👈🏿\",point_left_tone4=\"👈🏾\",o2=\"🅾\",knife=\"🔪\",volcano=\"🌋\",kissing_heart=\"😘\",on=\"🔛\",ok=\"🆗\",package=\"📦\",island=\"🏝\",arrow_right=\"➡\",chart_with_downwards_trend=\"📉\",haircut_tone3=\"💇🏽\",wolf=\"🐺\",ox=\"🐂\",dagger=\"🗡\",full_moon_with_face=\"🌝\",syringe=\"💉\",flag_by=\"🇧🇾\",flag_bz=\"🇧🇿\",flag_bq=\"🇧🇶\",flag_br=\"🇧🇷\",flag_bs=\"🇧🇸\",flag_bt=\"🇧🇹\",flag_bv=\"🇧🇻\",flag_bw=\"🇧🇼\",flag_bh=\"🇧🇭\",flag_bi=\"🇧🇮\",flag_bj=\"🇧🇯\",flag_bl=\"🇧🇱\",flag_bm=\"🇧🇲\",flag_bn=\"🇧🇳\",flag_bo=\"🇧🇴\",flag_ba=\"🇧🇦\",flag_bb=\"🇧🇧\",flag_bd=\"🇧🇩\",flag_be=\"🇧🇪\",flag_bf=\"🇧🇫\",flag_bg=\"🇧🇬\",satellite_orbital=\"🛰\",radio_button=\"🔘\",arrow_heading_down=\"⤵\",rage=\"😡\",whale2=\"🐋\",vhs=\"📼\",hand_splayed_tone3=\"🖐🏽\",strawberry=\"🍓\",[\"non-potable_water\"]=\"🚱\",hand_splayed_tone5=\"🖐🏿\",star2=\"🌟\",toilet=\"🚽\",ab=\"🆎\",cinema=\"🎦\",floppy_disk=\"💾\",princess_tone4=\"👸🏾\",princess_tone5=\"👸🏿\",princess_tone2=\"👸🏼\",nerd=\"🤓\",telephone_receiver=\"📞\",princess_tone1=\"👸🏻\",arrow_double_down=\"⏬\",clock1030=\"🕥\",flag_pr=\"🇵🇷\",flag_ps=\"🇵🇸\",poop=\"💩\",flag_pw=\"🇵🇼\",flag_pt=\"🇵🇹\",flag_py=\"🇵🇾\",pear=\"🍐\",m=\"Ⓜ\",flag_pa=\"🇵🇦\",flag_pf=\"🇵🇫\",flag_pg=\"🇵🇬\",flag_pe=\"🇵🇪\",flag_pk=\"🇵🇰\",flag_ph=\"🇵🇭\",flag_pn=\"🇵🇳\",flag_pl=\"🇵🇱\",flag_pm=\"🇵🇲\",mask=\"😷\",hushed=\"😯\",sunrise_over_mountains=\"🌄\",partly_sunny=\"⛅\",dollar=\"💵\",helmet_with_cross=\"⛑\",smoking=\"🚬\",no_bicycles=\"🚳\",man_with_gua_pi_mao=\"👲\",tv=\"📺\",open_hands=\"👐\",rotating_light=\"🚨\",information_desk_person_tone4=\"💁🏾\",information_desk_person_tone5=\"💁🏿\",part_alternation_mark=\"〽\",pray_tone5=\"🙏🏿\",pray_tone4=\"🙏🏾\",pray_tone3=\"🙏🏽\",pray_tone2=\"🙏🏼\",pray_tone1=\"🙏🏻\",smile=\"😄\",large_blue_circle=\"🔵\",man_tone4=\"👨🏾\",man_tone5=\"👨🏿\",fax=\"📠\",woman=\"👩\",man_tone1=\"👨🏻\",man_tone2=\"👨🏼\",man_tone3=\"👨🏽\",eye_in_speech_bubble=\"👁🗨\",blowfish=\"🐡\",card_box=\"🗃\",ticket=\"🎫\",ramen=\"🍜\",twisted_rightwards_arrows=\"🔀\",swimmer_tone4=\"🏊🏾\",swimmer_tone5=\"🏊🏿\",swimmer_tone1=\"🏊🏻\",swimmer_tone2=\"🏊🏼\",swimmer_tone3=\"🏊🏽\",saxophone=\"🎷\",bath_tone1=\"🛀🏻\",notebook_with_decorative_cover=\"📔\",bath_tone3=\"🛀🏽\",ten=\"🔟\",raising_hand_tone4=\"🙋🏾\",tea=\"🍵\",raising_hand_tone1=\"🙋🏻\",raising_hand_tone2=\"🙋🏼\",raising_hand_tone3=\"🙋🏽\",zero=\"0⃣\",ribbon=\"🎀\",santa_tone1=\"🎅🏻\",abc=\"🔤\",clock=\"🕰\",purple_heart=\"💜\",bow_tone1=\"🙇🏻\",no_smoking=\"🚭\",flag_cl=\"🇨🇱\",surfer=\"🏄\",newspaper=\"📰\",busstop=\"🚏\",new_moon=\"🌑\",traffic_light=\"🚥\",thumbsup=\"👍\",no_entry=\"⛔\",name_badge=\"📛\",classical_building=\"🏛\",hamster=\"🐹\",pick=\"⛏\",two_women_holding_hands=\"👭\",family_mmbb=\"👨👨👦👦\",family=\"👪\",rice_cracker=\"🍘\",wind_blowing_face=\"🌬\",inbox_tray=\"📥\",tired_face=\"😫\",carousel_horse=\"🎠\",eye=\"👁\",poodle=\"🐩\",chestnut=\"🌰\",slight_smile=\"🙂\",mailbox_closed=\"📪\",cloud_tornado=\"🌪\",jack_o_lantern=\"🎃\",lifter_tone3=\"🏋🏽\",lifter_tone2=\"🏋🏼\",lifter_tone1=\"🏋🏻\",lifter_tone5=\"🏋🏿\",lifter_tone4=\"🏋🏾\",nine=\"9⃣\",chocolate_bar=\"🍫\",v=\"✌\",man_with_turban_tone4=\"👳🏾\",man_with_turban_tone5=\"👳🏿\",man_with_turban_tone2=\"👳🏼\",man_with_turban_tone3=\"👳🏽\",man_with_turban_tone1=\"👳🏻\",family_wwbb=\"👩👩👦👦\",hamburger=\"🍔\",accept=\"🉑\",airplane=\"✈\",dress=\"👗\",speedboat=\"🚤\",ledger=\"📒\",goat=\"🐐\",flag_ae=\"🇦🇪\",flag_ad=\"🇦🇩\",flag_ag=\"🇦🇬\",flag_af=\"🇦🇫\",flag_ac=\"🇦🇨\",flag_am=\"🇦🇲\",flag_al=\"🇦🇱\",flag_ao=\"🇦🇴\",flag_ai=\"🇦🇮\",flag_au=\"🇦🇺\",flag_at=\"🇦🇹\",fork_and_knife=\"🍴\",fast_forward=\"⏩\",flag_as=\"🇦🇸\",flag_ar=\"🇦🇷\",cow2=\"🐄\",flag_ax=\"🇦🇽\",flag_az=\"🇦🇿\",a=\"🅰\",volleyball=\"🏐\",dragon=\"🐉\",wrench=\"🔧\",point_up_2=\"👆\",egg=\"🍳\",small_red_triangle=\"🔺\",soon=\"🔜\",bow_tone4=\"🙇🏾\",joy_cat=\"😹\",pray=\"🙏\",dark_sunglasses=\"🕶\",rugby_football=\"🏉\",soccer=\"⚽\",dolls=\"🎎\",monkey_face=\"🐵\",clap_tone3=\"👏🏽\",bar_chart=\"📊\",european_castle=\"🏰\",military_medal=\"🎖\",frame_photo=\"🖼\",rice_ball=\"🍙\",trolleybus=\"🚎\",older_woman=\"👵\",information_source=\"ℹ\",postal_horn=\"📯\",house=\"🏠\",fish=\"🐟\",bride_with_veil=\"👰\",fist=\"✊\",lipstick=\"💄\",fountain=\"⛲\",cyclone=\"🌀\",thumbsdown_tone2=\"👎🏼\",thumbsdown_tone3=\"👎🏽\",thumbsdown_tone1=\"👎🏻\",thumbsdown_tone4=\"👎🏾\",thumbsdown_tone5=\"👎🏿\",cookie=\"🍪\",heartbeat=\"💓\",blush=\"😊\",fire_engine=\"🚒\",feet=\"🐾\",horse=\"🐴\",blossom=\"🌼\",crossed_swords=\"⚔\",station=\"🚉\",clock730=\"🕢\",banana=\"🍌\",relieved=\"😌\",hotel=\"🏨\",park=\"🏞\",aerial_tramway=\"🚡\",flag_sd=\"🇸🇩\",panda_face=\"🐼\",b=\"🅱\",flag_sx=\"🇸🇽\",six_pointed_star=\"🔯\",shaved_ice=\"🍧\",chipmunk=\"🐿\",mountain=\"⛰\",koala=\"🐨\",white_small_square=\"▫\",open_hands_tone2=\"👐🏼\",open_hands_tone3=\"👐🏽\",u55b6=\"🈺\",open_hands_tone1=\"👐🏻\",open_hands_tone4=\"👐🏾\",open_hands_tone5=\"👐🏿\",baby_tone5=\"👶🏿\",baby_tone4=\"👶🏾\",baby_tone3=\"👶🏽\",baby_tone2=\"👶🏼\",baby_tone1=\"👶🏻\",chart=\"💹\",beach_umbrella=\"⛱\",basketball_player_tone5=\"⛹🏿\",basketball_player_tone4=\"⛹🏾\",basketball_player_tone1=\"⛹🏻\",basketball_player_tone3=\"⛹🏽\",basketball_player_tone2=\"⛹🏼\",mans_shoe=\"👞\",shinto_shrine=\"⛩\",ideograph_advantage=\"🉐\",airplane_arriving=\"🛬\",golf=\"⛳\",minidisc=\"💽\",hugging=\"🤗\",crayon=\"🖍\",point_down=\"👇\",copyright=\"©\",person_with_pouting_face_tone2=\"🙎🏼\",person_with_pouting_face_tone3=\"🙎🏽\",person_with_pouting_face_tone1=\"🙎🏻\",person_with_pouting_face_tone4=\"🙎🏾\",person_with_pouting_face_tone5=\"🙎🏿\",busts_in_silhouette=\"👥\",alarm_clock=\"⏰\",couplekiss=\"💏\",circus_tent=\"🎪\",sunny=\"☀\",incoming_envelope=\"📨\",yellow_heart=\"💛\",cry=\"😢\",x=\"❌\",arrow_up_small=\"🔼\",art=\"🎨\",surfer_tone1=\"🏄🏻\",bride_with_veil_tone4=\"👰🏾\",bride_with_veil_tone5=\"👰🏿\",bride_with_veil_tone2=\"👰🏼\",bride_with_veil_tone3=\"👰🏽\",bride_with_veil_tone1=\"👰🏻\",hibiscus=\"🌺\",black_joker=\"🃏\",raised_hand=\"✋\",no_mouth=\"😶\",basketball_player=\"⛹\",champagne=\"🍾\",no_entry_sign=\"🚫\",older_man=\"👴\",moyai=\"🗿\",mailbox=\"📫\",slight_frown=\"🙁\",statue_of_liberty=\"🗽\",mega=\"📣\",eggplant=\"🍆\",rose=\"🌹\",bell=\"🔔\",battery=\"🔋\",wastebasket=\"🗑\",dancer=\"💃\",page_facing_up=\"📄\",church=\"⛪\",underage=\"🔞\",secret=\"㊙\",clock430=\"🕟\",fork_knife_plate=\"🍽\",u7981=\"🈲\",fire=\"🔥\",cold_sweat=\"😰\",flag_er=\"🇪🇷\",family_mwgg=\"👨👩👧👧\",heart_eyes=\"😍\",guardsman_tone1=\"💂🏻\",guardsman_tone2=\"💂🏼\",guardsman_tone3=\"💂🏽\",guardsman_tone4=\"💂🏾\",earth_africa=\"🌍\",arrow_right_hook=\"↪\",spy_tone2=\"🕵🏼\",closed_umbrella=\"🌂\",bikini=\"👙\",vertical_traffic_light=\"🚦\",kissing=\"😗\",loop=\"➿\",potable_water=\"🚰\",pound=\"💷\",[\"fleur-de-lis\"]=\"⚜\",key2=\"🗝\",heavy_dollar_sign=\"💲\",shamrock=\"☘\",boy_tone4=\"👦🏾\",shirt=\"👕\",kimono=\"👘\",left_luggage=\"🛅\",meat_on_bone=\"🍖\",ok_woman_tone4=\"🙆🏾\",ok_woman_tone5=\"🙆🏿\",arrow_heading_up=\"⤴\",calendar_spiral=\"🗓\",snail=\"🐌\",ok_woman_tone1=\"🙆🏻\",arrow_down_small=\"🔽\",leopard=\"🐆\",paperclips=\"🖇\",cityscape=\"🏙\",woman_tone1=\"👩🏻\",slot_machine=\"🎰\",woman_tone3=\"👩🏽\",woman_tone4=\"👩🏾\",woman_tone5=\"👩🏿\",euro=\"💶\",musical_score=\"🎼\",triangular_ruler=\"📐\",flags=\"🎏\",five=\"5⃣\",love_hotel=\"🏩\",hotdog=\"🌭\",speak_no_evil=\"🙊\",eyeglasses=\"👓\",dancer_tone4=\"💃🏾\",dancer_tone5=\"💃🏿\",vulcan_tone4=\"🖖🏾\",bridge_at_night=\"🌉\",writing_hand_tone1=\"✍🏻\",couch=\"🛋\",vulcan_tone1=\"🖖🏻\",vulcan_tone2=\"🖖🏼\",vulcan_tone3=\"🖖🏽\",womans_hat=\"👒\",sandal=\"👡\",cherries=\"🍒\",full_moon=\"🌕\",flag_om=\"🇴🇲\",play_pause=\"⏯\",couple=\"👫\",money_mouth=\"🤑\",womans_clothes=\"👚\",globe_with_meridians=\"🌐\",bath_tone5=\"🛀🏿\",bangbang=\"‼\",stuck_out_tongue_winking_eye=\"😜\",heart=\"❤\",bamboo=\"🎍\",mahjong=\"🀄\",waning_gibbous_moon=\"🌖\",back=\"🔙\",point_up_2_tone4=\"👆🏾\",point_up_2_tone5=\"👆🏿\",lips=\"👄\",point_up_2_tone1=\"👆🏻\",point_up_2_tone2=\"👆🏼\",point_up_2_tone3=\"👆🏽\",candle=\"🕯\",middle_finger_tone3=\"🖕🏽\",middle_finger_tone2=\"🖕🏼\",middle_finger_tone1=\"🖕🏻\",middle_finger_tone5=\"🖕🏿\",middle_finger_tone4=\"🖕🏾\",heavy_minus_sign=\"➖\",nose=\"👃\",zzz=\"💤\",stew=\"🍲\",santa=\"🎅\",tropical_fish=\"🐠\",point_up_tone1=\"☝🏻\",point_up_tone3=\"☝🏽\",point_up_tone2=\"☝🏼\",point_up_tone5=\"☝🏿\",point_up_tone4=\"☝🏾\",field_hockey=\"🏑\",school_satchel=\"🎒\",womens=\"🚺\",baby_symbol=\"🚼\",baby_chick=\"🐤\",ok_hand_tone2=\"👌🏼\",ok_hand_tone3=\"👌🏽\",ok_hand_tone1=\"👌🏻\",ok_hand_tone4=\"👌🏾\",ok_hand_tone5=\"👌🏿\",family_mmgb=\"👨👨👧👦\",last_quarter_moon=\"🌗\",tada=\"🎉\",clock530=\"🕠\",question=\"❓\",registered=\"®\",level_slider=\"🎚\",black_circle=\"⚫\",atom=\"⚛\",penguin=\"🐧\",electric_plug=\"🔌\",skull=\"💀\",kiss_mm=\"👨❤💋👨\",walking_tone4=\"🚶🏾\",fries=\"🍟\",up=\"🆙\",walking_tone3=\"🚶🏽\",walking_tone2=\"🚶🏼\",athletic_shoe=\"👟\",hatched_chick=\"🐥\",black_nib=\"✒\",black_large_square=\"⬛\",bow_and_arrow=\"🏹\",rainbow=\"🌈\",metal_tone5=\"🤘🏿\",metal_tone4=\"🤘🏾\",lemon=\"🍋\",metal_tone2=\"🤘🏼\",peach=\"🍑\",peace=\"☮\",steam_locomotive=\"🚂\",oncoming_bus=\"🚍\",heart_eyes_cat=\"😻\",smiley=\"😃\",haircut_tone1=\"💇🏻\",haircut_tone2=\"💇🏼\",u6e80=\"🈵\",haircut_tone4=\"💇🏾\",haircut_tone5=\"💇🏿\",black_medium_square=\"◼\",closed_book=\"📕\",desert=\"🏜\",expressionless=\"😑\",dvd=\"📀\",construction_worker_tone2=\"👷🏼\",construction_worker_tone3=\"👷🏽\",construction_worker_tone4=\"👷🏾\",construction_worker_tone5=\"👷🏿\",mag_right=\"🔎\",bento=\"🍱\",scroll=\"📜\",flag_nl=\"🇳🇱\",flag_no=\"🇳🇴\",flag_ni=\"🇳🇮\",european_post_office=\"🏤\",flag_ne=\"🇳🇪\",flag_nf=\"🇳🇫\",flag_ng=\"🇳🇬\",flag_na=\"🇳🇦\",flag_nc=\"🇳🇨\",alien=\"👽\",first_quarter_moon_with_face=\"🌛\",flag_nz=\"🇳🇿\",flag_nu=\"🇳🇺\",golfer=\"🏌\",flag_np=\"🇳🇵\",flag_nr=\"🇳🇷\",anguished=\"😧\",mosque=\"🕌\",point_left_tone1=\"👈🏻\",ear_tone1=\"👂🏻\",ear_tone2=\"👂🏼\",ear_tone3=\"👂🏽\",ear_tone4=\"👂🏾\",ear_tone5=\"👂🏿\",eight_pointed_black_star=\"✴\",wave=\"👋\",runner_tone5=\"🏃🏿\",runner_tone4=\"🏃🏾\",runner_tone3=\"🏃🏽\",runner_tone2=\"🏃🏼\",runner_tone1=\"🏃🏻\",railway_car=\"🚃\",notes=\"🎶\",no_good=\"🙅\",trackball=\"🖲\",spaghetti=\"🍝\",love_letter=\"💌\",clipboard=\"📋\",baby_bottle=\"🍼\",bird=\"🐦\",card_index=\"📇\",punch=\"👊\",leo=\"♌\",house_with_garden=\"🏡\",family_wwgg=\"👩👩👧👧\",family_wwgb=\"👩👩👧👦\",see_no_evil=\"🙈\",metro=\"🚇\",popcorn=\"🍿\",apple=\"🍎\",scales=\"⚖\",sleeping_accommodation=\"🛌\",clock230=\"🕝\",tools=\"🛠\",cloud=\"☁\",honey_pot=\"🍯\",ballot_box=\"🗳\",frog=\"🐸\",camera=\"📷\",crab=\"🦀\",video_camera=\"📹\",pencil=\"📝\",thunder_cloud_rain=\"⛈\",mountain_bicyclist=\"🚵\",tangerine=\"🍊\",train=\"🚋\",rabbit=\"🐰\",baby=\"👶\",palm_tree=\"🌴\",capital_abcd=\"🔠\",put_litter_in_its_place=\"🚮\",coffin=\"⚰\",abcd=\"🔡\",lock=\"🔒\",pig2=\"🐖\",family_mwg=\"👨👩👧\",point_right_tone5=\"👉🏿\",trumpet=\"🎺\",film_frames=\"🎞\",six=\"6⃣\",leftwards_arrow_with_hook=\"↩\",earth_asia=\"🌏\",heavy_check_mark=\"✔\",notebook=\"📓\",taco=\"🌮\",tomato=\"🍅\",robot=\"🤖\",mute=\"🔇\",symbols=\"🔣\",motorcycle=\"🏍\",thermometer_face=\"🤒\",paperclip=\"📎\",moneybag=\"💰\",neutral_face=\"😐\",white_sun_rain_cloud=\"🌦\",snake=\"🐍\",kiss=\"💋\",blue_car=\"🚙\",confetti_ball=\"🎊\",tram=\"🚊\",repeat_one=\"🔂\",smiley_cat=\"😺\",beginner=\"🔰\",mobile_phone_off=\"📴\",books=\"📚\",[\"8ball\"]=\"🎱\",cocktail=\"🍸\",flag_ge=\"🇬🇪\",horse_racing_tone2=\"🏇🏼\",flag_mh=\"🇲🇭\",flag_mk=\"🇲🇰\",flag_mm=\"🇲🇲\",flag_ml=\"🇲🇱\",flag_mo=\"🇲🇴\",flag_mn=\"🇲🇳\",flag_ma=\"🇲🇦\",flag_mc=\"🇲🇨\",flag_me=\"🇲🇪\",flag_md=\"🇲🇩\",flag_mg=\"🇲🇬\",flag_mf=\"🇲🇫\",flag_my=\"🇲🇾\",flag_mx=\"🇲🇽\",flag_mz=\"🇲🇿\",mountain_snow=\"🏔\",flag_mp=\"🇲🇵\",flag_ms=\"🇲🇸\",flag_mr=\"🇲🇷\",flag_mu=\"🇲🇺\",flag_mt=\"🇲🇹\",flag_mw=\"🇲🇼\",flag_mv=\"🇲🇻\",timer=\"⏲\",passport_control=\"🛂\",small_blue_diamond=\"🔹\",lion_face=\"🦁\",white_check_mark=\"✅\",bouquet=\"💐\",track_previous=\"⏮\",monkey=\"🐒\",tone4=\"🏾\",closed_lock_with_key=\"🔐\",family_wwb=\"👩👩👦\",family_wwg=\"👩👩👧\",tone1=\"🏻\",crescent_moon=\"🌙\",shell=\"🐚\",gear=\"⚙\",tone2=\"🏼\",small_red_triangle_down=\"🔻\",nut_and_bolt=\"🔩\",umbrella2=\"☂\",unamused=\"😒\",fuelpump=\"⛽\",bed=\"🛏\",bee=\"🐝\",round_pushpin=\"📍\",flag_white=\"🏳\",microphone=\"🎤\",bus=\"🚌\",eight=\"8⃣\",handbag=\"👜\",medal=\"🏅\",arrows_clockwise=\"🔃\",urn=\"⚱\",bookmark_tabs=\"📑\",new_moon_with_face=\"🌚\",fallen_leaf=\"🍂\",horse_racing=\"🏇\",chicken=\"🐔\",ear=\"👂\",wheel_of_dharma=\"☸\",arrow_lower_right=\"↘\",man_with_gua_pi_mao_tone5=\"👲🏿\",scorpion=\"🦂\",waning_crescent_moon=\"🌘\",man_with_gua_pi_mao_tone2=\"👲🏼\",man_with_gua_pi_mao_tone1=\"👲🏻\",bug=\"🐛\",virgo=\"♍\",libra=\"♎\",angel_tone1=\"👼🏻\",angel_tone3=\"👼🏽\",angel_tone2=\"👼🏼\",angel_tone5=\"👼🏿\",sagittarius=\"♐\",bear=\"🐻\",information_desk_person_tone3=\"💁🏽\",no_mobile_phones=\"📵\",hand_splayed=\"🖐\",motorboat=\"🛥\",calling=\"📲\",interrobang=\"⁉\",oncoming_taxi=\"🚖\",flag_lt=\"🇱🇹\",flag_lu=\"🇱🇺\",flag_lr=\"🇱🇷\",flag_ls=\"🇱🇸\",flag_ly=\"🇱🇾\",bellhop=\"🛎\",arrow_down=\"⬇\",flag_lc=\"🇱🇨\",flag_la=\"🇱🇦\",flag_lk=\"🇱🇰\",flag_li=\"🇱🇮\",ferris_wheel=\"🎡\",hand_splayed_tone2=\"🖐🏼\",large_blue_diamond=\"🔷\",cat2=\"🐈\",icecream=\"🍦\",tent=\"⛺\",joy=\"😂\",hand_splayed_tone4=\"🖐🏾\",file_cabinet=\"🗄\",key=\"🔑\",weary=\"😩\",bath_tone2=\"🛀🏼\",flag_lv=\"🇱🇻\",low_brightness=\"🔅\",rowboat_tone5=\"🚣🏿\",rowboat_tone2=\"🚣🏼\",rowboat_tone3=\"🚣🏽\",four_leaf_clover=\"🍀\",space_invader=\"👾\",cl=\"🆑\",cd=\"💿\",bath_tone4=\"🛀🏾\",flag_za=\"🇿🇦\",swimmer=\"🏊\",wavy_dash=\"〰\",flag_zm=\"🇿🇲\",flag_zw=\"🇿🇼\",raised_hands_tone5=\"🙌🏿\",two_hearts=\"💕\",bulb=\"💡\",cop_tone4=\"👮🏾\",cop_tone5=\"👮🏿\",cop_tone2=\"👮🏼\",cop_tone3=\"👮🏽\",cop_tone1=\"👮🏻\",open_file_folder=\"📂\",homes=\"🏘\",raised_hands_tone2=\"🙌🏼\",fearful=\"😨\",grinning=\"😀\",bow_tone5=\"🙇🏿\",santa_tone3=\"🎅🏽\",santa_tone2=\"🎅🏼\",santa_tone5=\"🎅🏿\",santa_tone4=\"🎅🏾\",bow_tone2=\"🙇🏼\",bow_tone3=\"🙇🏽\",bathtub=\"🛁\",ping_pong=\"🏓\",u5272=\"🈹\",rooster=\"🐓\",vs=\"🆚\",bullettrain_front=\"🚅\",airplane_small=\"🛩\",white_circle=\"⚪\",balloon=\"🎈\",cross=\"✝\",princess_tone3=\"👸🏽\",speaker=\"🔈\",zipper_mouth=\"🤐\",u6307=\"🈯\",whale=\"🐳\",pensive=\"😔\",signal_strength=\"📶\",muscle=\"💪\",rocket=\"🚀\",camel=\"🐫\",boot=\"👢\",flashlight=\"🔦\",spy_tone4=\"🕵🏾\",spy_tone5=\"🕵🏿\",ski=\"🎿\",spy_tone3=\"🕵🏽\",musical_keyboard=\"🎹\",spy_tone1=\"🕵🏻\",rolling_eyes=\"🙄\",clock1=\"🕐\",clock2=\"🕑\",clock3=\"🕒\",clock4=\"🕓\",clock5=\"🕔\",clock6=\"🕕\",clock7=\"🕖\",clock8=\"🕗\",clock9=\"🕘\",doughnut=\"🍩\",dancer_tone1=\"💃🏻\",dancer_tone2=\"💃🏼\",dancer_tone3=\"💃🏽\",candy=\"🍬\",two_men_holding_hands=\"👬\",badminton=\"🏸\",bust_in_silhouette=\"👤\",writing_hand_tone2=\"✍🏼\",sunflower=\"🌻\",[\"e-mail\"]=\"📧\",chains=\"⛓\",kissing_smiling_eyes=\"😙\",fish_cake=\"🍥\",no_pedestrians=\"🚷\",v_tone4=\"✌🏾\",v_tone5=\"✌🏿\",v_tone1=\"✌🏻\",v_tone2=\"✌🏼\",v_tone3=\"✌🏽\",arrow_backward=\"◀\",clock12=\"🕛\",clock10=\"🕙\",clock11=\"🕚\",sweat=\"😓\",mountain_railway=\"🚞\",tongue=\"👅\",black_square_button=\"🔲\",do_not_litter=\"🚯\",nose_tone4=\"👃🏾\",nose_tone5=\"👃🏿\",nose_tone2=\"👃🏼\",nose_tone3=\"👃🏽\",nose_tone1=\"👃🏻\",horse_racing_tone5=\"🏇🏿\",horse_racing_tone4=\"🏇🏾\",horse_racing_tone3=\"🏇🏽\",ok_hand=\"👌\",horse_racing_tone1=\"🏇🏻\",custard=\"🍮\",rowboat=\"🚣\",white_sun_small_cloud=\"🌤\",flag_kr=\"🇰🇷\",cricket=\"🏏\",flag_kp=\"🇰🇵\",flag_kw=\"🇰🇼\",flag_kz=\"🇰🇿\",flag_ky=\"🇰🇾\",construction=\"🚧\",flag_kg=\"🇰🇬\",flag_ke=\"🇰🇪\",flag_ki=\"🇰🇮\",flag_kh=\"🇰🇭\",flag_kn=\"🇰🇳\",flag_km=\"🇰🇲\",cake=\"🍰\",flag_wf=\"🇼🇫\",mortar_board=\"🎓\",pig=\"🐷\",flag_ws=\"🇼🇸\",person_frowning=\"🙍\",arrow_upper_right=\"↗\",book=\"📖\",clock1130=\"🕦\",boom=\"💥\",[\"repeat\"]=\"🔁\",star=\"⭐\",rabbit2=\"🐇\",footprints=\"👣\",ghost=\"👻\",droplet=\"💧\",vibration_mode=\"📳\",flag_ye=\"🇾🇪\",flag_yt=\"🇾🇹\",\n}\n\n-- translate the string to emoji\nfunction emoji.translate(str)\n\n    -- translate it\n    local chars = emoji.keys[str]\n\n    -- ok?\n    return chars\nend\n\n-- return module\nreturn emoji\n"
  },
  {
    "path": "xmake/core/base/filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        filter.lua\n--\n\n-- define module: filter\nlocal filter = filter or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal winos     = require(\"base/winos\")\nlocal table     = require(\"base/table\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal scheduler = require(\"base/scheduler\")\n\n-- globals\nlocal escape_table1 = {[\"$\"] = \"\\001\", [\"(\"] = \"\\002\", [\")\"] = \"\\003\", [\"%\"] = \"\\004\"}\nlocal escape_table2 = {[\"\\001\"] = \"$\", [\"\\002\"] = \"(\", [\"\\003\"] = \")\", [\"\\004\"] = \"%\"}\n\n-- new filter instance\nfunction filter.new()\n\n    -- init an filter instance\n    local self = table.inherit(filter)\n\n    -- init handler\n    self._HANDLERS = {}\n\n    -- ok\n    return self\nend\n\n-- filter the shell command\n--\n-- e.g.\n--\n-- print(\"$(shell echo hello xmake)\")\n-- add_ldflags(\"$(shell pkg-config --libs sqlite3)\")\n--\nfunction filter.shell(cmd)\n\n    -- empty?\n    if #cmd == 0 then\n        os.raise(\"empty $(shell)!\")\n    end\n\n    -- run shell\n    scheduler:enable(false) -- disable coroutine scheduler to fix `attempt to yield across C-call boundary` when call gsub -> yield\n    local ok, outdata, errdata = os.iorun(cmd)\n    scheduler:enable(true)\n    if not ok then\n        os.raise(\"run $(shell %s) failed, errors: %s\", cmd, errdata or \"\")\n    end\n\n    -- trim it\n    if outdata then\n        outdata = outdata:trim()\n    end\n\n    -- return the shell result\n    return outdata\nend\n\n-- filter the environment variables\nfunction filter.env(name)\n    return os.getenv(name)\nend\n\n-- filter the winreg path\nfunction filter.reg(path)\n\n    -- must be windows\n    if os.host() ~= \"windows\" then\n        return\n    end\n\n    -- query registry value\n    return (winos.registry_query(path))\nend\n\n-- set handlers\nfunction filter:set_handlers(handlers)\n    self._HANDLERS = handlers\nend\n\n-- get handlers\nfunction filter:handlers()\n    return self._HANDLERS\nend\n\n-- register handler\nfunction filter:register(name, handler)\n    self._HANDLERS[name] = handler\nend\n\n-- get variable value\nfunction filter:get(variable)\n\n    -- check\n    assert(variable)\n\n    -- is shell?\n    if variable:startswith(\"shell \") then\n        return filter.shell(variable:sub(7))\n    -- is environment variable?\n    elseif variable:startswith(\"env \") then\n        return filter.env(variable:sub(5))\n    elseif variable:startswith(\"reg \") then\n        return filter.reg(variable:sub(5))\n    end\n\n    -- parse variable:mode\n    local varmode   = variable:split(':')\n    local mode      = varmode[2]\n    variable        = varmode[1]\n\n    -- handler it\n    local result = nil\n    for name, handler in pairs(self._HANDLERS) do\n        result = handler(variable)\n        if result then\n            break\n        end\n    end\n\n    -- TODO need improve\n    -- handle mode\n    if mode and result then\n        if mode == \"upper\" then\n            result = result:upper()\n        elseif mode == \"lower\" then\n            result = result:lower()\n        end\n    end\n\n    -- ok?\n    return result\nend\n\n-- filter the builtin variables: \"hello $(variable)\" for string\n--\n-- e.g.\n--\n-- print(\"$(host)\")\n-- print(\"$(env PATH)\")\n-- print(\"$(shell echo hello xmake!)\")\n-- print(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name)\")\n--\nfunction filter:handle(value)\n\n    -- check\n    assert(type(value) == \"string\")\n\n    -- escape \"%$\", \"%(\", \"%)\", \"%%\" to \"\\001\", \"\\002\", \"\\003\", \"\\004\"\n    value = value:gsub(\"%%([%$%(%)%%])\", function (ch) return escape_table1[ch] end)\n\n    -- filter the builtin variables\n    local values = {}\n    local variables = {}\n    value:gsub(\"%$%((.-)%)\", function (variable)\n        table.insert(variables, variable)\n    end)\n    -- we cannot call self:get() in gsub, because it will trigger \"attempt to yield a c-call boundary\"\n    for _, variable in ipairs(variables) do\n        -- escape \"%$\", \"%(\", \"%)\", \"%%\" to \"$\", \"(\", \")\", \"%\"\n        local name = variable:gsub(\"[\\001\\002\\003\\004]\", function (ch) return escape_table2[ch] end)\n        values[variable] = self:get(name) or \"\"\n    end\n    value = value:gsub(\"%$%((.-)%)\", function (variable)\n        return values[variable]\n    end)\n    return value:gsub(\"[\\001\\002\\003\\004]\", function (ch) return escape_table2[ch] end)\nend\n\n-- return module: filter\nreturn filter\n"
  },
  {
    "path": "xmake/core/base/fwatcher.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fwatcher.lua\n--\n\n-- define module: fwatcher\nlocal fwatcher   = fwatcher or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal string    = require(\"base/string\")\nlocal coroutine = require(\"base/coroutine\")\nlocal scheduler = require(\"base/scheduler\")\n\n-- save original interfaces\nfwatcher._open       = fwatcher._open or fwatcher.open\nfwatcher._add        = fwatcher._add or fwatcher.add\nfwatcher._remove     = fwatcher._remove or fwatcher.remove\nfwatcher._wait       = fwatcher._wait or fwatcher.wait\nfwatcher._close      = fwatcher._close or fwatcher.close\n\n-- the fwatcher event type, @see tbox/platform/fwatcher.h\nfwatcher.ET_MODIFY = 1\nfwatcher.ET_CREATE = 2\nfwatcher.ET_DELETE = 4\n\n-- get cdata of fwatcher\nfunction _instance:cdata()\n    local cdata = self._CDATA\n    if not cdata and not self._CLOSED then\n        cdata = fwatcher._open()\n        self._CDATA = cdata\n    end\n    return cdata\nend\n\n-- get poller object type, poller.OT_FWATCHER\nfunction _instance:otype()\n    return 4\nend\n\n-- add watch directory, e.g. {recursion = true}\nfunction _instance:add(watchdir, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- add watchdir\n    opt = opt or {}\n    local ok, errors = fwatcher._add(self:cdata(), watchdir, opt.recursion or false)\n    if not ok then\n        errors = string.format(\"<fwatcher>: add %s failed, %s\", watchdir, errors or \"unknown errors\")\n    end\n    return ok, errors\nend\n\n-- remove watch directory\nfunction _instance:remove(watchdir)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- remove watchdir\n    opt = opt or {}\n    local ok, errors = fwatcher._remove(self:cdata(), watchdir)\n    if not ok then\n        errors = string.format(\"<fwatcher>: remove %s failed, %s\", watchdir, errors or \"unknown errors\")\n    end\n    return ok, errors\nend\n\n-- wait event\n--\n-- @param timeout   the timeout\n--\n-- @return          ok, event, e.g {type = fwatcher.ET_MODIFY, path = \"/tmp\"}\n--\nfunction _instance:wait(timeout)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- wait events\n    local result = -1\n    local event_or_errors = nil\n    if scheduler:co_running() then\n        result, event_or_errors = scheduler:poller_waitfs(self, timeout or -1)\n    else\n        result, event_or_errors = fwatcher._wait(self:cdata(), timeout or -1)\n    end\n    if result < 0 and event_or_errors then\n        event_or_errors = string.format(\"<fwatcher>: wait failed, %s\", event_or_errors)\n    end\n    return result, event_or_errors\nend\n\n-- close instance\nfunction _instance:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- cancel pipe events from the scheduler\n    if scheduler:co_running() then\n        ok, errors = scheduler:poller_cancel(self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- close fwatcher\n    ok = fwatcher._close(self:cdata())\n    if ok then\n        self._CDATA = nil\n        self._CLOSED = true\n    end\n    return ok\nend\n\n-- ensure the fwatcher is opened\nfunction _instance:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"<fwatcher:%s>: has been closed!\", self:cdata())\n    end\n    return true\nend\n\n-- add watchdir\nfunction fwatcher.add(watchdir, opt)\n    return _instance:add(watchdir, opt)\nend\n\n-- remove watchdir\nfunction fwatcher.remove(watchdir)\n    return _instance:remove(watchdir)\nend\n\n-- wait event\nfunction fwatcher.wait(timeout)\n    return _instance:wait(timeout)\nend\n\n-- watch directories\n--\n-- @param watchdirs     the watch directories, pattern path string or path list\n-- @param callback      the event callback\n-- @param opt           the option, e.g. {timeout = -1, recursion = true}\n--\n-- @code\n-- fwatcher.watchdirs(\"/tmp/test_*\", function (event)\n--   print(event)\n-- end, {timeout = -1, recursion = true})\n-- @endcode\nfunction fwatcher.watchdirs(watchdirs, callback, opt)\n\n    -- add watch directories\n    opt = opt or {}\n    if type(watchdirs) == \"string\" then\n        watchdirs = os.dirs(watchdirs)\n    end\n    local ok = true\n    local errors = nil\n    for _, watchdir in ipairs(watchdirs) do\n        ok, errors = fwatcher.add(watchdir, opt)\n        if not ok then\n            break\n        end\n    end\n\n    -- do watch\n    while ok do\n        local result, event_or_errors = fwatcher.wait(opt.timeout or -1)\n        if result < 0 then\n            ok = false\n            errors = event_or_errors\n            break\n        end\n        if result > 0 then\n            callback(event_or_errors)\n        end\n    end\n\n    -- remove watch directories\n    for _, watchdir in ipairs(watchdirs) do\n        local result, rm_errors = fwatcher.remove(watchdir)\n        if not result then\n            ok = false\n            errors = errors or rm_errors\n            break\n        end\n    end\n    return ok, errors\nend\n\n-- watch the created file path in directories\n--\n-- @param watchdirs     the watch directories, pattern path string or path list\n-- @param callback      the event callback\n-- @param opt           the option, e.g. {timeout = -1, recursion = true}\n--\n-- @code\n-- fwatcher.on_created(\"/tmp/test_*\", function (filepath)\n--   print(filepath)\n-- end, {timeout = -1, recursion = true})\n-- @endcode\nfunction fwatcher.on_created(watchdirs, callback, opt)\n    return fwatcher.watchdirs(watchdirs, function (event)\n        if event and event.type == fwatcher.ET_CREATE then\n            callback(event.path)\n        end\n    end, opt)\nend\n\n-- watch the modified file path in directories\n--\n-- @param watchdirs     the watch directories, pattern path string or path list\n-- @param callback      the event callback\n-- @param opt           the option, e.g. {timeout = -1, recursion = true}\n--\n-- @code\n-- fwatcher.on_modified(\"/tmp/test_*\", function (filepath)\n--   print(filepath)\n-- end, {timeout = -1, recursion = true})\n-- @endcode\nfunction fwatcher.on_modified(watchdirs, callback, opt)\n    return fwatcher.watchdirs(watchdirs, function (event)\n        if event and event.type == fwatcher.ET_MODIFY then\n            callback(event.path)\n        end\n    end, opt)\nend\n\n-- watch the deleted file path in directories\n--\n-- @param watchdirs     the watch directories, pattern path string or path list\n-- @param callback      the event callback\n-- @param opt           the option, e.g. {timeout = -1, recursion = true}\n--\n-- @code\n-- fwatcher.on_deleted(\"/tmp/test_*\", function (filepath)\n--   print(filepath)\n-- end, {timeout = -1, recursion = true})\n-- @endcode\nfunction fwatcher.on_deleted(watchdirs, callback, opt)\n    return fwatcher.watchdirs(watchdirs, function (event)\n        if event and event.type == fwatcher.ET_DELETE then\n            callback(event.path)\n        end\n    end, opt)\nend\n\nreturn fwatcher\n"
  },
  {
    "path": "xmake/core/base/global.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        global.lua\n--\n\n-- define module\nlocal global = global or {}\n\n-- load modules\nlocal io            = require(\"base/io\")\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal utils         = require(\"base/utils\")\nlocal option        = require(\"base/option\")\n\n-- get the current given configure\nfunction global.get(name)\n    local value = nil\n    if global._CONFIGS then\n        value = global._CONFIGS[name]\n        if type(value) == \"string\" and value == \"auto\" then\n            value = nil\n        end\n    end\n    return value\nend\n\n-- this global name is readonly?\nfunction global.readonly(name)\n    return global._MODES and global._MODES[\"__readonly_\" .. name]\nend\n\n-- set the given configure to the current\n--\n-- @param name  the name\n-- @param value the value\n-- @param opt   the argument options, e.g. {readonly = false, force = false}\n--\nfunction global.set(name, value, opt)\n\n    -- check\n    assert(name)\n\n    -- init options\n    opt = opt or {}\n\n    -- check readonly\n    assert(opt.force or not global.readonly(name), \"cannot set readonly global: \" .. name)\n\n    -- set it\n    global._CONFIGS = global._CONFIGS or {}\n    global._CONFIGS[name] = value\n\n    -- mark as readonly\n    if opt.readonly then\n        global._MODES = global._MODES or {}\n        global._MODES[\"__readonly_\" .. name] = true\n    end\nend\n\n-- get all options\nfunction global.options()\n\n    -- remove values with \"auto\" and private item\n    local configs = {}\n    for name, value in pairs(table.wrap(global._CONFIGS)) do\n        if not name:find(\"^_%u+\") and name ~= \"__version\" and (type(value) ~= \"string\" or value ~= \"auto\") then\n            configs[name] = value\n        end\n    end\n    return configs\nend\n\n-- get the configure file\nfunction global.filepath()\n    return path.join(global.directory(), xmake._NAME .. \".conf\")\nend\n\n-- get the global configure directory\nfunction global.directory()\n    if global._DIRECTORY == nil then\n        local name = \".\" .. xmake._NAME\n        local rootdir = os.getenv(\"XMAKE_GLOBALDIR\")\n        if not rootdir then\n            -- compatible with the old `%appdata%/.xmake` directory if it exists\n            local appdata = (os.host() == \"windows\") and os.getenv(\"APPDATA\")\n            if appdata and os.isdir(path.join(appdata, name)) then\n                rootdir = appdata\n            else\n                rootdir = path.translate(\"~\")\n            end\n        end\n        global._DIRECTORY = path.join(rootdir, name)\n    end\n    return global._DIRECTORY\nend\n\n-- get the global cache directory\nfunction global.cachedir()\n    return global.get(\"cachedir\") or path.join(global.directory(), \"cache\")\nend\n\n-- load the global configuration\nfunction global.load()\n\n    -- load configure from the file first\n    local filepath = global.filepath()\n    if os.isfile(filepath) then\n\n        -- load configs\n        local results, errors = io.load(filepath)\n        if not results then\n            return false, errors\n        end\n\n        -- merge the configure\n        for name, value in pairs(results) do\n            if global.get(name) == nil then\n                global.set(name, value)\n            end\n        end\n    end\n    return true\nend\n\n-- save the global configure\nfunction global.save()\n\n    -- the options\n    local options = global.options()\n    assert(options)\n\n    -- add version\n    options.__version = xmake._VERSION_SHORT\n\n    -- save it\n    return io.save(global.filepath(), options)\nend\n\n-- clear config\nfunction global.clear()\n    global._MODES = nil\n    global._CONFIGS = nil\nend\n\n-- dump the configure\nfunction global.dump()\n    if not option.get(\"quiet\") then\n        utils.print(\"configure\")\n        utils.print(\"{\")\n        for name, value in pairs(global.options()) do\n            if not name:startswith(\"__\") then\n                utils.print(\"    %s = %s\", name, value)\n            end\n        end\n        utils.print(\"}\")\n    end\nend\n\n-- return module\nreturn global\n"
  },
  {
    "path": "xmake/core/base/graph.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        graph.lua\n--\n\n-- load modules\nlocal table   = require(\"base/table\")\nlocal queue   = require(\"base/queue\")\nlocal object  = require(\"base/object\")\nlocal hashset = require(\"base/hashset\")\nlocal utils   = require(\"base/utils\")\n\n-- define module\nlocal graph = graph or object { _init = {\"_directed\"} } {true}\nlocal edge = edge or object { _init = {\"_from\", \"_to\"} }\n\n-- new edge, from -> to\nfunction edge.new(from, to)\n    return edge {from, to}\nend\n\nfunction edge:from()\n    return self._from\nend\n\nfunction edge:to()\n    return self._to\nend\n\nfunction edge:other(v)\n    if v == self._from then\n        return self._to\n    else\n        return self._from\n    end\nend\n\nfunction edge:__tostring()\n    return string.format(\"<edge:%s-%s>\", self:from(), self:to())\nend\n\n-- clear graph\nfunction graph:clear()\n    self._vertices = {}\n    self._edges = {}\n    self._adjacent_edges = {}\n    self._edges_map = {}\n\n    -- clear partial topological sort state\n    self:partial_topo_sort_reset()\nend\n\n-- is empty?\nfunction graph:empty()\n    return #self:vertices() == 0\nend\n\n-- is directed?\nfunction graph:is_directed()\n    return self._directed\nend\n\n-- get vertices\nfunction graph:vertices()\n    return self._vertices\nend\n\n-- get adjacent edges of the the given vertex\nfunction graph:adjacent_edges(v)\n    return self._adjacent_edges[v]\nend\n\n-- get the vertex at the given index\nfunction graph:vertex(idx)\n    return self:vertices()[idx]\nend\n\n-- has the given vertex?\nfunction graph:has_vertex(v)\n    return self._adjacent_edges[v] ~= nil\nend\n\n-- add an isolated without edges\nfunction graph:add_vertex(v)\n    if not self:has_vertex(v) then\n        table.insert(self._vertices, v)\n        self._adjacent_edges[v] = {}\n    end\n\n    -- reset partial topological sort state since graph structure changed\n    self._partial_topo_dirty = true\nend\n\n-- remove the given vertex?\nfunction graph:remove_vertex(v)\n    local contains = false\n    table.remove_if(self._vertices, function (_, item)\n        if item == v then\n            contains = true\n            return true\n        end\n    end)\n    if contains then\n        -- remove all touching edges\n        local touching = {}\n        for _, e in ipairs(self._edges) do\n            if e:from() == v or e:to() == v then\n                table.insert(touching, {e:from(), e:to()})\n            end\n        end\n        for _, pair in ipairs(touching) do\n            self:remove_edge(pair[1], pair[2])\n        end\n        self._edges_map[v] = nil\n        self._adjacent_edges[v] = nil\n\n        -- reset partial topological sort state since graph structure changed\n        self._partial_topo_dirty = true\n    end\nend\n\n-- reset partial topological sort state\nfunction graph:partial_topo_sort_reset()\n    self._partial_topo_in_progress = false\n    self._partial_topo_in_degree = nil\n    self._partial_topo_queue = nil\n    self._partial_topo_processed = nil\n    self._partial_topo_finished = 0\n    self._partial_topo_has_cycle = nil\n    self._partial_topo_dirty = false\nend\n\n-- get next node in topological order\n--\n-- @param limit     the maximum number of nodes to return\n-- @return          array of nodes with zero in-degree, empty when complete\n-- @return          has_cycle indicates if a cycle was detected\n--\n-- @code\n--      dag:partial_topo_sort_reset()\n--\n--      local node, has_cycle\n--      local order_vertices = {}\n--      while true do\n--          node, has_cycle = dag:partial_topo_sort_next()\n--          if node then\n--              table.insert(order_vertices, node)\n--              dag:partial_topo_sort_remove(node)\n--          else\n--              if has_cycle then\n--                  -- find cycle\n--              end\n--              break\n--          end\n--      end\n-- @endcode\n--\n-- e.g.\n--\n-- edges: a (indegree: 0) -> b -> c\n--\n-- add_edge(a, b)\n-- add_edge(b, c)\n--\n-- local node1, has_cycle = g:partial_topo_sort_next() -- return a\n-- local node2, has_cycle = g:partial_topo_sort_next() -- return b\n-- local node3, has_cycle = g:partial_topo_sort_next() -- return c\n-- local node4, has_cycle = g:partial_topo_sort_next() -- return nil (empty, all done)\n--\nfunction graph:partial_topo_sort_next()\n\n    -- recompute all nodes if has dirty nodes\n    if self._partial_topo_dirty then\n        self:_partial_topo_sort_recompute_dirty()\n    end\n\n    -- check if we already detected a cycle\n    if self._partial_topo_has_cycle then\n        return nil, true\n    end\n\n    -- initialize topological sort state if not already in progress\n    if not self._partial_topo_in_progress then\n        if not self:_partial_topo_sort_init() then\n            return nil, false\n        end\n        self._partial_topo_in_progress = true\n    end\n\n    -- get one node with zero in-degree\n    local node\n    local partial_topo_queue = self._partial_topo_queue\n    local partial_topo_processed = self._partial_topo_processed\n    while not partial_topo_queue:empty() do\n        local v = partial_topo_queue:pop()\n        if partial_topo_processed:has(v) then\n            self:partial_topo_sort_remove(v)\n        else\n            node = v\n            partial_topo_processed:insert(node)\n            break\n        end\n    end\n\n    return node, self._partial_topo_has_cycle\nend\n\n-- remove node and update in-degrees based on the nodes in this node\nfunction graph:partial_topo_sort_remove(node)\n    if node == nil then\n        return\n    end\n    self._partial_topo_finished = self._partial_topo_finished + 1\n    local edges = self:adjacent_edges(node)\n    if edges then\n        local partial_topo_in_degree = self._partial_topo_in_degree\n        local partial_topo_queue = self._partial_topo_queue\n        for _, e in ipairs(edges) do\n            if e:from() == node then\n                local w = e:to()\n                local in_degree = partial_topo_in_degree[w] - 1\n                partial_topo_in_degree[w] = in_degree\n                if in_degree == 0 then\n                    partial_topo_queue:push(w)\n                end\n            end\n        end\n    end\n\n    if self._partial_topo_queue:empty() and self._partial_topo_processed:size() == self._partial_topo_finished then\n        self._partial_topo_has_cycle = self._partial_topo_finished ~= #self:vertices()\n    end\nend\n\n-- topological sort, use kahn's algorithm\n--\n-- e.g.\n--\n-- edges: a (indegree: 0) -> b -> c\n--\n-- add_edge(a, b)\n-- add_edge(b, c)\n--\n-- it will return {a, b, c}\nfunction graph:topo_sort()\n    if not self:is_directed() then\n        return\n    end\n\n    -- calculate in-degree for each vertex\n    local in_degree = {}\n    for _, v in ipairs(self:vertices()) do\n        in_degree[v] = 0\n    end\n\n    -- count incoming edges for each vertex\n    for _, v in ipairs(self:vertices()) do\n        local edges = self:adjacent_edges(v)\n        if edges then\n            for _, e in ipairs(edges) do\n                if e:from() == v then\n                    local w = e:to()\n                    in_degree[w] = (in_degree[w] or 0) + 1\n                end\n            end\n        end\n    end\n\n    -- queue of vertices with no incoming edges (no dependencies)\n    local queue = queue.new()\n    for _, v in ipairs(self:vertices()) do\n        if in_degree[v] == 0 then\n            queue:push(v)\n        end\n    end\n\n    -- process queue\n    local order_vertices = {}\n    while not queue:empty() do\n        -- remove a vertex with no incoming edges\n        local v = queue:pop()\n        table.insert(order_vertices, v)\n\n        -- for each outgoing edge, remove it and update in-degrees\n        local edges = self:adjacent_edges(v)\n        if edges then\n            for _, e in ipairs(edges) do\n                if e:from() == v then\n                    local w = e:to()\n                    local d = in_degree[w] - 1\n                    in_degree[w] = d\n                    if d == 0 then\n                        queue:push(w)\n                    end\n                end\n            end\n        end\n    end\n\n    -- if we couldn't process all vertices, there must be a cycle\n    local has_cycle = #order_vertices ~= #self:vertices()\n    return order_vertices, has_cycle\nend\n\n-- deprecated\nfunction graph:topological_sort()\n    return self:topo_sort()\nend\n\n-- find cycle\nfunction graph:find_cycle()\n    local visited = {}\n    local stack = {}\n    local cycle = {}\n\n    local function dfs(v)\n        visited[v] = true\n        stack[v] = true\n        table.insert(cycle, v)\n        local edges = self:adjacent_edges(v)\n        if edges then\n            for _, e in ipairs(edges) do\n                local w = e:other(v)\n                if not visited[w] then\n                    if dfs(w) then\n                        return true\n                    elseif stack[w] then\n                        return true\n                    end\n                elseif stack[w] then\n                    for i = #cycle, 1, -1 do\n                        if cycle[i] == w then\n                            cycle = table.slice(cycle, i)\n                            return true\n                        end\n                    end\n                end\n            end\n        end\n        table.remove(cycle)\n        stack[v] = false\n        return false\n    end\n\n    for _, v in ipairs(self:vertices()) do\n        if not visited[v] then\n            if dfs(v) then\n                return cycle\n            end\n        end\n    end\nend\n\n-- get edges\nfunction graph:edges()\n    return self._edges\nend\n\n-- add edge\nfunction graph:add_edge(from, to)\n    if self:has_edge(from, to) then\n        return\n    end\n    self:add_vertex(from)\n    self:add_vertex(to)\n    local e = edge.new(from, to)\n    local edges_map = self._edges_map\n    edges_map[from] = edges_map[from] or {}\n    edges_map[from][to] = true\n    if self:is_directed() then\n        table.insert(self._adjacent_edges[from], e)\n    else\n        edges_map[to] = edges_map[to] or {}\n        edges_map[to][from] = true\n        table.insert(self._adjacent_edges[from], e)\n        table.insert(self._adjacent_edges[to], e)\n    end\n    table.insert(self._edges, e)\n\n    -- reset partial topological sort state since graph structure changed\n    self._partial_topo_dirty = true\nend\n\n-- remove edge\nfunction graph:remove_edge(from, to)\n    if not self:has_edge(from, to) then\n        return\n    end\n    local directed = self:is_directed()\n    local edges = self._edges\n    local target_index\n    local target_edge\n    for idx, e in ipairs(edges) do\n        local match = (e:from() == from and e:to() == to)\n        if not directed then\n            match = match or (e:from() == to and e:to() == from)\n        end\n        if match then\n            target_index = idx\n            target_edge = e\n            break\n        end\n    end\n    assert(target_edge, string.format(\"graph.remove_edge(%s, %s): edge not found\", tostring(from), tostring(to)))\n\n    table.remove(edges, target_index)\n\n    local function remove_from_adj(vertex)\n        local adj = self._adjacent_edges[vertex]\n        if adj then\n            table.remove_if(adj, function (_, e) return e == target_edge end)\n        end\n    end\n\n    remove_from_adj(target_edge:from())\n    remove_from_adj(target_edge:to())\n\n    local edges_map = self._edges_map\n    local function clear_map(u, v)\n        local map = edges_map[u]\n        if map then\n            map[v] = nil\n            if not next(map) then\n                edges_map[u] = nil\n            end\n        end\n    end\n\n    clear_map(target_edge:from(), target_edge:to())\n    if not directed then\n        clear_map(target_edge:to(), target_edge:from())\n    end\n\n    self._partial_topo_dirty = true\nend\n\n-- has the given edge?\nfunction graph:has_edge(from, to)\n    local edges_map = self._edges_map\n    local from_map = edges_map[from]\n    if self:is_directed() then\n        return from_map and from_map[to]\n    else\n        local to_map = edges_map[to]\n        return from_map and to_map and from_map[to] and to_map[from]\n    end\nend\n\n-- clone graph\nfunction graph:clone()\n    local gh = graph.new(self:is_directed())\n    for _, e in ipairs(self._edges) do\n        gh:add_edge(e:from(), e:to())\n    end\n    return gh\nend\n\n-- reverse graph\nfunction graph:reverse()\n    if not self:is_directed() then\n        return self:clone()\n    end\n    local gh = graph.new(self:is_directed())\n    for _, e in ipairs(self._edges) do\n        gh:add_edge(e:to(), e:from())\n    end\n    return gh\nend\n\n-- dump graph\nfunction graph:dump()\n    local vertices = self:vertices()\n    local edges = self:edges()\n    utils.cprint(\"graph: %s, vertices: %d, edges: %d\", self:is_directed() and \"directed\" or \"not-directed\", #vertices, #edges)\n    utils.cprint(\"vertices: \")\n    for _, v in ipairs(vertices) do\n        utils.cprint(\"  %s\", v)\n    end\n    utils.cprint(\"\")\n    utils.cprint(\"edges: \")\n    for _, e in ipairs(edges) do\n        utils.cprint(\"  %s ${color.dump.reference}->${clear} %s\", e:from(), e:to())\n    end\nend\n\n-- initialize topological sort state if not already in progress\nfunction graph:_partial_topo_sort_init()\n    if not self:is_directed() then\n        return false\n    end\n\n    -- calculate in-degree for each vertex\n    self._partial_topo_in_degree = {}\n    for _, v in ipairs(self:vertices()) do\n        self._partial_topo_in_degree[v] = 0\n    end\n\n    -- count incoming edges for each vertex\n    local partial_topo_in_degree = self._partial_topo_in_degree\n    for _, v in ipairs(self:vertices()) do\n        local edges = self:adjacent_edges(v)\n        if edges then\n            for _, e in ipairs(edges) do\n                if e:from() == v then\n                    local w = e:to()\n                    partial_topo_in_degree[w] = (partial_topo_in_degree[w] or 0) + 1\n                end\n            end\n        end\n    end\n\n    -- initialize queue with vertices that have no incoming edges\n    self._partial_topo_queue = queue.new()\n    local partial_topo_queue = self._partial_topo_queue\n    for _, v in ipairs(self:vertices()) do\n        if partial_topo_in_degree[v] == 0 then\n            partial_topo_queue:push(v)\n        end\n    end\n\n    self._partial_topo_processed = self._partial_topo_processed or hashset.new()\n    return true\nend\n\n-- recompute all dirty nodes\n--\n-- TODO we recompute all nodes now, but we should optimize to recompute only dirty nodes\nfunction graph:_partial_topo_sort_recompute_dirty()\n    self._partial_topo_in_progress = false\n    self._partial_topo_in_degree = nil\n    self._partial_topo_queue = nil\n    self._partial_topo_finished = 0\n    self._partial_topo_has_cycle = nil\n    self._partial_topo_dirty = false\nend\n\n-- new graph\nfunction graph.new(directed)\n    local gh = graph {directed}\n    gh:clear()\n    return gh\nend\n\n-- return module: graph\nreturn graph\n"
  },
  {
    "path": "xmake/core/base/hash.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        hash.lua\n--\n\n-- define module: hash\nlocal hash  = hash or {}\n\n-- load modules\nlocal io    = require(\"base/io\")\nlocal utils = require(\"base/utils\")\nlocal bytes = require(\"base/bytes\")\nlocal libc  = require(\"base/libc\")\n\n-- save metatable and builtin functions\nhash._md5 = hash._md5 or hash.md5\nhash._sha = hash._sha or hash.sha\nhash._xxhash = hash._xxhash or hash.xxhash\nhash._rand32 = hash._rand32 or hash.rand32\nhash._rand64 = hash._rand64 or hash.rand64\nhash._rand128 = hash._rand128 or hash.rand128\n\n-- generate md5 from the given file or data\nfunction hash.md5(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._md5(dataaddr, datasize)\n    else\n        hashstr, errors = hash._md5(file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate sha1 from the given file or data\nfunction hash.sha1(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._sha(160, dataaddr, datasize)\n    else\n        hashstr, errors = hash._sha(160, file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate sha256 from the given file or data\nfunction hash.sha256(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._sha(256, dataaddr, datasize)\n    else\n        hashstr, errors = hash._sha(256, file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate uuid, e.g \"91E8ECF1-417F-4EDF-A574-E22D7D8D204A\"\nfunction hash.uuid(str)\n    return hash.uuid4(str)\nend\n\n-- generate xxhash32 from the given file or data\nfunction hash.xxhash32(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._xxhash(32, dataaddr, datasize)\n    else\n        hashstr, errors = hash._xxhash(32, file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate xxhash64 from the given file or data\nfunction hash.xxhash64(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._xxhash(64, dataaddr, datasize)\n    else\n        hashstr, errors = hash._xxhash(64, file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate xxhash128 from the given file or data\nfunction hash.xxhash128(file_or_data)\n    local hashstr, errors\n    if bytes.instance_of(file_or_data) then\n        local datasize = file_or_data:size()\n        local dataaddr = file_or_data:caddr()\n        hashstr, errors = hash._xxhash(128, dataaddr, datasize)\n    else\n        hashstr, errors = hash._xxhash(128, file_or_data)\n    end\n    return hashstr, errors\nend\n\n-- generate hash32 from string, e.g. \"91e8ecf1\"\nfunction hash.strhash32(str)\n    if hash._rand32 then\n        local data = libc.ptraddr(libc.dataptr(str))\n        local size = #str\n        return hash._xxhash(32, data, size)\n    else\n        -- we need to be compatible with the old binary core (<= v3.0.3)\n        return hash.uuid4(str):split(\"-\", {plain = true})[1]:lower()\n    end\nend\n\n-- generate hash64 from string, e.g. \"91e8ecf191e8ecf1\"\nfunction hash.strhash64(str)\n    local data = libc.ptraddr(libc.dataptr(str))\n    local size = #str\n    return hash._xxhash(64, data, size)\nend\n\n-- generate hash128 from string, e.g. \"91e8ecf1417f4edfa574e22d7d8d204a\"\nfunction hash.strhash128(str)\n    local data = libc.ptraddr(libc.dataptr(str))\n    local size = #str\n    return hash._xxhash(128, data, size)\nend\n\n-- generate random32 hash\n-- @note it is easy to trigger hash conflicts\nfunction hash.rand32()\n    if hash._rand32 then\n        return hash._rand32()\n    else\n        return hash.strhash32(tostring(math.random()))\n    end\nend\n\n-- generate random64 hash\nfunction hash.rand64()\n    if hash._rand64 then\n        return hash._rand64()\n    else\n        return hash.strhash64(tostring(math.random()))\n    end\nend\n\n-- generate random128 hash\nfunction hash.rand128()\n    if hash._rand128 then\n        return hash._rand128()\n    else\n        return hash.strhash128(tostring(math.random()))\n    end\nend\n\n-- return module: hash\nreturn hash\n"
  },
  {
    "path": "xmake/core/base/hashset.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu, ruki\n-- @file        hashset.lua\n--\n\n-- load modules\nlocal object    = require(\"base/object\")\nlocal table     = require(\"base/table\")\nlocal todisplay = require(\"base/todisplay\")\n\n-- define module\nlocal hashset = hashset or object { _init = {\"_DATA\", \"_SIZE\"} }\n\n-- representaion for nil key\nhashset._NIL = setmetatable({}, {\n    __todisplay = function()\n        return \"${reset}${color.dump.keyword}nil${reset}\"\n    end,\n    __tostring = function()\n        return \"symbol(nil)\"\n    end\n})\n\nfunction hashset._to_key(key)\n    if key == nil then\n        key = hashset._NIL\n    end\n    return key\nend\n\n-- h1 == h1?\nfunction hashset:__eq(h)\n    if self._DATA == h._DATA then\n        return true\n    end\n    if self:size() ~= h:size() then\n        return false\n    end\n    for item in h:items() do\n        if not self:has(item) then\n            return false\n        end\n    end\n    return true\nend\n\n-- to display\nfunction hashset:__todisplay()\n    return string.format(\"hashset${reset}(%s) {%s}\", todisplay(self._SIZE), table.concat(table.imap(table.keys(self._DATA), function (i, k)\n        if i > 10 then\n            return nil\n        elseif i == 10 and self._SIZE ~= 10 then\n            return \"...\"\n        else\n            return todisplay(k)\n        end\n    end), \", \"))\nend\n\n-- check value is in hashset\nfunction hashset:has(value)\n    value = hashset._to_key(value)\n    return self._DATA[value] or false\nend\n\n-- insert value to hashset, returns false if value has already in the hashset\nfunction hashset:insert(value)\n    value = hashset._to_key(value)\n    local result = not (self._DATA[value] or false)\n    if result then\n        self._DATA[value] = true\n        self._SIZE = self._SIZE + 1\n    end\n    return result\nend\n\n-- remove value from hashset, returns false if value is not in the hashset\nfunction hashset:remove(value)\n    value = hashset._to_key(value)\n    local result = self._DATA[value] or false\n    if result then\n        self._DATA[value] = nil\n        self._SIZE = self._SIZE - 1\n    end\n    return result\nend\n\n-- convert hashset to an array, nil in the set will be ignored\nfunction hashset:to_array()\n    local result = {}\n    for item in self:items() do\n        if item ~= nil then\n            table.insert(result, item)\n        end\n    end\n    return result\nend\n\n-- iterate items\n--\n-- @code\n-- for item in instance:items() do\n--   ...\n-- end\n-- @endcode\n--\nfunction hashset:items()\n    return function (t, item)\n        local k, _ = next(t._DATA, item)\n        if k == hashset._NIL then\n            return nil\n        else\n            return k\n        end\n    end, self, nil\nend\n\n-- iterate order items\n--\n-- @code\n-- for item in instance:orderitems() do\n--   ...\n-- end\n-- @endcode\n--\nfunction hashset:orderitems()\n    local orderkeys = table.orderkeys(self._DATA, function (a, b)\n        if a == hashset._NIL then\n            a = math.inf\n        end\n        if b == hashset._NIL then\n            b = math.inf\n        end\n        if type(a) == \"table\" then\n            a = tostring(a)\n        end\n        if type(b) == \"table\" then\n            b = tostring(b)\n        end\n        return a < b\n    end)\n    local i = 1\n    return function (t, k)\n        k = orderkeys[i]\n        i = i + 1\n        if k == hashset._NIL then\n            return nil\n        else\n            return k\n        end\n    end, self, nil\nend\n\n-- iterate keys (deprecated, please use items())\n--\n-- @code\n-- for _, key in instance:keys() do\n--   ...\n-- end\n-- @endcode\n--\nfunction hashset:keys()\n    return function (t, key)\n        local k, _ = next(t._DATA, key)\n        if k == hashset._NIL then\n            return k, nil\n        else\n            return k, k\n        end\n    end, self, nil\nend\n\n-- iterate order keys (deprecated, please use orderitems())\n--\n-- @code\n-- for _, key in instance:orderkeys() do\n--   ...\n-- end\n-- @endcode\n--\nfunction hashset:orderkeys()\n    local orderkeys = table.keys(self._DATA)\n    table.sort(orderkeys, function (a, b)\n        if a == hashset._NIL then\n            a = math.inf\n        end\n        if b == hashset._NIL then\n            b = math.inf\n        end\n        if type(a) == \"table\" then\n            a = tostring(a)\n        end\n        if type(b) == \"table\" then\n            b = tostring(b)\n        end\n        return a < b\n    end)\n    local i = 1\n    return function (t, k)\n        k = orderkeys[i]\n        i = i + 1\n        if k == hashset._NIL then\n            return k, nil\n        else\n            return k, k\n        end\n    end, self, nil\nend\n\n-- get size of hashset\nfunction hashset:size()\n    return self._SIZE\nend\n\n-- is empty?\nfunction hashset:empty()\n    return self:size() == 0\nend\n\n-- get data of hashset\nfunction hashset:data()\n    return self._DATA\nend\n\n-- clear hashset\nfunction hashset:clear()\n    self._DATA = {}\n    self._SIZE = 0\nend\n\n-- clone hashset\nfunction hashset:clone()\n    local h = hashset.new()\n    h._SIZE = self._SIZE\n    h._DATA = table.clone(self._DATA)\n    return h\nend\n\n-- construct from list of items\nfunction hashset.of(...)\n    local result = hashset.new()\n    local data = table.pack(...)\n    for i = 1, data.n do\n        result:insert(data[i])\n    end\n    return result\nend\n\n-- construct from an array\nfunction hashset.from(array)\n    local result = hashset.new()\n    for i = 1, #array do\n        result:insert(array[i])\n    end\n    return result\nend\n\n-- new hashset\nfunction hashset.new()\n    return hashset {{}, 0}\nend\n\n-- return module: hashset\nreturn hashset\n"
  },
  {
    "path": "xmake/core/base/heap.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- priority queue implemented as a binary heap.\n-- written by Cosmin Apreutesei. Public Domain.\n--\n-- @see https://github.com/luapower/heap\n--\n-- modified by  ruki\n-- @file        heap.lua\n--\n\n-- define module: heap\nlocal heap  = heap or {}\n\nlocal ffi --init on demand so that the module can be used without luajit\nlocal assert, floor = assert, math.floor\n\n-- heap algorithm working over abstract API that counts from one.\nfunction heap._make(add, remove, swap, length, cmp)\n\n    local function moveup(child)\n        local parent = floor(child / 2)\n        while child > 1 and cmp(child, parent) do\n            swap(child, parent)\n            child = parent\n            parent = floor(child / 2)\n        end\n        return child\n    end\n\n    local function movedown(parent)\n        local last = length()\n        local child = parent * 2\n        while child <= last do\n            if child + 1 <= last and cmp(child + 1, child) then\n                child = child + 1 -- sibling is smaller\n            end\n            if not cmp(child, parent) then break end\n            swap(parent, child)\n            parent = child\n            child = parent * 2\n        end\n        return parent\n    end\n\n    local function push(...)\n        add(...)\n        return moveup(length())\n    end\n\n    local function pop(i)\n        swap(i, length())\n        remove()\n        movedown(i)\n    end\n\n    local function rebalance(i)\n        if moveup(i) == i then\n            movedown(i)\n        end\n    end\n    return push, pop, rebalance\nend\n\n-- cdata heap working over a cdata array\nfunction heap.cdataheap(h)\n    ffi = ffi or require(\"ffi\")\n    assert(h and h.size, \"size expected\")\n    assert(h.size >= 2, \"size too small\")\n    assert(h.ctype, \"ctype expected\")\n    local ctype = ffi.typeof(h.ctype)\n    h.data = h.data or ffi.new(ffi.typeof(\"$[?]\", ctype), h.size)\n    local t, n, maxn = h.data, h.length or 0, h.size - 1\n    local function add(v) n = n + 1; t[n] = v end\n    local function rem() n = n - 1 end\n    local function swap(i, j) t[0] = t[i]; t[i] = t[j]; t[j] = t[0] end\n    local function length() return n end\n    local cmp = h.cmp and\n        function(i, j) return h.cmp(t[i], t[j]) end or\n        function(i, j) return t[i] < t[j] end\n    local push, pop, rebalance = heap._make(add, rem, swap, length, cmp)\n\n    local function get(i, box)\n        assert(i >= 1 and i <= n, \"invalid index\")\n        if box then\n            box[0] = t[i]\n        else\n            return ffi.new(ctype, t[i])\n        end\n    end\n    function h:push(v)\n        assert(n < maxn, \"buffer overflow\")\n        push(v)\n    end\n    function h:pop(i, box)\n        assert(n > 0, \"buffer underflow\")\n        local v = get(i or 1, box)\n        pop(i or 1)\n        return v\n    end\n    function h:peek(i, box)\n        return get(i or 1, box)\n    end\n    function h:replace(i, v)\n        assert(i >= 1 and i <= n, \"invalid index\")\n        t[i] = v\n        rebalance(i)\n    end\n    h.length = length\n    return h\nend\n\n-- value heap working over a Lua table\nfunction heap.valueheap(h)\n    h = h or {}\n    local t, n = h, #h\n    local function add(v) n = n + 1; t[n] = v end\n    local function rem() t[n] = nil; n = n - 1 end\n    local function swap(i, j) t[i], t[j] = t[j], t[i] end\n    local function length() return n end\n    local cmp = h.cmp and\n        function(i, j) return h.cmp(t[i], t[j]) end or\n        function(i, j) return t[i] < t[j] end\n    local push, pop, rebalance = heap._make(add, rem, swap, length, cmp)\n\n    local function get(i)\n        assert(i >= 1 and i <= n, \"invalid index\")\n        return t[i]\n    end\n    function h:push(v)\n        assert(v ~= nil, \"invalid value\")\n        push(v)\n    end\n    function h:pop(i)\n        assert(n > 0, \"buffer underflow\")\n        local v = get(i or 1)\n        pop(i or 1)\n        return v\n    end\n    function h:peek(i)\n        return get(i or 1)\n    end\n    function h:replace(i, v)\n        assert(i >= 1 and i <= n, \"invalid index\")\n        t[i] = v\n        rebalance(i)\n    end\n    h.length = length\n    return h\nend\n\n-- return module: heap\nreturn heap\n"
  },
  {
    "path": "xmake/core/base/interpreter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        interpreter.lua\n--\n\n-- define module: interpreter\nlocal interpreter = interpreter or {}\n\n-- load modules\nlocal os         = require(\"base/os\")\nlocal path       = require(\"base/path\")\nlocal table      = require(\"base/table\")\nlocal utils      = require(\"base/utils\")\nlocal string     = require(\"base/string\")\nlocal hashset    = require(\"base/hashset\")\nlocal scopeinfo  = require(\"base/scopeinfo\")\nlocal deprecated = require(\"base/deprecated\")\nlocal sandbox    = require(\"sandbox/sandbox\")\n\n-- raise without interpreter stack\n-- @see https://github.com/xmake-io/xmake/issues/3553\nfunction interpreter._raise(errors)\n    os.raise(\"[nobacktrace]: \" .. (errors or \"\"))\nend\n\n-- traceback\nfunction interpreter._traceback(errors)\n\n    -- disable backtrace?\n    if errors then\n        local _, pos = errors:find(\"[nobacktrace]: \", 1, true)\n        if pos then\n            return errors:sub(pos + 1)\n        end\n    end\n\n    -- init results\n    local results = \"\"\n    if errors then\n        results = errors .. \"\\n\"\n    end\n    results = results .. \"stack traceback:\\n\"\n\n    -- make results\n    local level = 2\n    while true do\n\n        -- get debug info\n        local info = debug.getinfo(level, \"Sln\")\n\n        -- end?\n        if not info then\n            break\n        end\n\n        -- function?\n        if info.what == \"C\" then\n            results = results .. string.format(\"    [C]: in function '%s'\\n\", info.name)\n        elseif info.name then\n            results = results .. string.format(\"    [%s:%d]: in function '%s'\\n\", info.short_src, info.currentline, info.name)\n        elseif info.what == \"main\" then\n            results = results .. string.format(\"    [%s:%d]: in main chunk\\n\", info.short_src, info.currentline)\n            break\n        else\n            results = results .. string.format(\"    [%s:%d]:\\n\", info.short_src, info.currentline)\n        end\n\n        -- next\n        level = level + 1\n    end\n    return results\nend\n\n-- merge the current root values to the previous scope\nfunction interpreter:_merge_root_scope(root, root_prev, override)\n    root_prev = root_prev or {}\n    for scope_kind_and_name, _ in pairs(root or {}) do\n        -- only merge sub-scope for each kind(\"target@@xxxx\") or __rootkind\n        -- we need to ignore the sub-root scope e.g. target{} after fetching root scope\n        --\n        if scope_kind_and_name:find(\"@@\", 1, true) or scope_kind_and_name == \"__rootkind\" then\n            local scope_values = root_prev[scope_kind_and_name] or {}\n            local scope_root   = root[scope_kind_and_name] or {}\n            for name, values in pairs(scope_root) do\n                if not name:startswith(\"__override_\") then\n                    if scope_root[\"__override_\" .. name] then\n                        if override or scope_values[name] == nil then\n                            scope_values[name] = values\n                        end\n                    else\n                        scope_values[name] = table.join(values, scope_values[name] or {})\n                    end\n                end\n            end\n            root_prev[scope_kind_and_name] = scope_values\n        end\n    end\n    return root_prev\nend\n\n-- fetch the root values to the child values in root scope\n-- and we will only use the child values if be override mode\nfunction interpreter:_fetch_root_scope(root)\n    for scope_kind_and_name, _ in pairs(root or {}) do\n\n        -- is scope_kind@@scope_name?\n        scope_kind_and_name = scope_kind_and_name:split(\"@@\", {plain = true})\n        if #scope_kind_and_name == 2 then\n            local scope_kind = scope_kind_and_name[1]\n            local scope_name = scope_kind_and_name[2]\n\n            -- we only fetch the root values to the target values, e.g. target@@ns1::ns2::bar\"\n            -- and ignore root namespace values, e.g. target@@ns1::ns2::\n            if not scope_name:endswith(\"::\") then\n                local scope_values = root[scope_kind .. \"@@\" .. scope_name] or {}\n                local namespaces = scope_name:split(\"::\", {plain = true})\n                table.remove(namespaces)\n                table.insert(namespaces, 1, \"\")\n\n                -- add values in global root scope, all namespace root scopes\n                local namespace\n                local scope_rootkeys = {}\n                for idx, namespace_part in ipairs(namespaces) do\n                    local scope_rootkey = scope_kind\n                    if idx ~= 1 then\n                        if not namespace then\n                            namespace = namespace_part\n                        else\n                            namespace = namespace .. \"::\" .. namespace_part\n                        end\n                        scope_rootkey = scope_kind .. \"@@\" .. namespace .. \"::\"\n                    end\n                    table.insert(scope_rootkeys, scope_rootkey)\n                end\n                -- we need to add root values in head\n                --\n                -- e.g.\n                -- add root values to ns1::ns2::bar from target@@ns1::ns2::\n                -- add root values to ns1::ns2::bar from target@@ns1::\n                -- add root values to ns1::ns2::bar from target\n                --\n                for idx = #scope_rootkeys, 1, -1 do\n                    local scope_rootkey = scope_rootkeys[idx]\n                    local scope_root = root[scope_rootkey] or {}\n                    for name, values in pairs(scope_root) do\n                        if not name:startswith(\"__override_\") then\n                            if scope_root[\"__override_\" .. name] then\n                                if scope_values[name] == nil then\n                                    scope_values[name] = values\n                                    scope_values[\"__override_\" .. name] = true\n                                end\n                            else\n                                scope_values[name] = table.join(values, scope_values[name] or {})\n                            end\n                        end\n                    end\n                end\n                root[scope_kind .. \"@@\" .. scope_name] = scope_values\n            end\n        end\n    end\nend\n\n-- save api source info, e.g. call api() in sourcefile:linenumber\nfunction interpreter:_save_sourceinfo_to_scope(scope, apiname, values)\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    local sourceinfo = debug.getinfo(3, \"Sl\")\n    if sourceinfo then\n        scope[\"__sourceinfo_\" .. apiname] = scope[\"__sourceinfo_\" .. apiname] or {}\n        local sourcescope = scope[\"__sourceinfo_\" .. apiname]\n        for _, value in ipairs(values) do\n            if type(value) == \"string\" then\n                sourcescope[value] = {file = sourceinfo.short_src or sourceinfo.source, line = sourceinfo.currentline}\n            end\n        end\n    end\nend\n\n-- register scope end: scopename_end()\nfunction interpreter:_api_register_scope_end(...)\n    assert(self and self._PUBLIC and self._PRIVATE)\n    for _, apiname in ipairs({...}) do\n\n        -- register scope api\n        self:api_register(nil, apiname .. \"_end\", function (self, ...)\n            assert(self and self._PRIVATE and apiname)\n\n            -- enter root scope\n            local scopes = self._PRIVATE._SCOPES\n            scopes._CURRENT = nil\n            scopes._CURRENT_KIND = nil\n        end)\n    end\nend\n\n-- register scope api: xxx_apiname()\nfunction interpreter:_api_register_scope_api(scope_kind, action, apifunc, ...)\n    assert(self and self._PUBLIC and self._PRIVATE)\n    assert(apifunc)\n\n    -- done\n    for _, apiname in ipairs({...}) do\n\n        -- check\n        assert(apiname)\n\n        -- the full name\n        local fullname = apiname\n        if action ~= nil then\n            fullname = action .. \"_\" .. apiname\n        end\n\n        -- register scope api\n        self:api_register(scope_kind, fullname, function (self, ...)\n\n            -- check\n            assert(self and self._PRIVATE and apiname)\n\n            -- the scopes\n            local scopes = self._PRIVATE._SCOPES\n            assert(scopes)\n\n            -- call function\n            return apifunc(self, scopes, apiname, ...)\n        end)\n    end\nend\n\n-- register api: xxx_values()\nfunction interpreter:_api_register_xxx_values(scope_kind, action, apifunc, ...)\n    assert(self and self._PUBLIC and self._PRIVATE)\n    assert(action and apifunc)\n\n    -- uses the root scope kind if no scope kind\n    if not scope_kind then\n        scope_kind = \"__rootkind\"\n    end\n\n    -- define implementation\n    local implementation = function (self, scopes, apiname, ...)\n\n        -- init root scopes\n        local namespace = self._PRIVATE._NAMESPACE_STR\n        scopes._ROOT = scopes._ROOT or {}\n\n        -- init current root scope\n        local rootkey = scope_kind\n        if namespace then\n            rootkey = scope_kind .. \"@@\" .. namespace .. \"::\"\n        end\n        local root = scopes._ROOT[rootkey] or {}\n        scopes._ROOT[rootkey] = root\n\n        -- clear the current scope if be not belong to the current scope kind\n        if scopes._CURRENT and scopes._CURRENT_KIND ~= scope_kind then\n            os.raise(\"%s() cannot be called in %s(), please move it to the %s scope!\", apiname, scopes._CURRENT_KIND, scope_kind == \"__rootkind\" and \"root\" or scope_kind)\n            scopes._CURRENT = nil\n        end\n\n        -- the current scope\n        local scope = scopes._CURRENT or root\n        assert(scope)\n\n        -- set values (set, on, before, after ...)? mark as \"override\"\n        if apiname and (action ~= \"add\" and action ~= \"del\" and action ~= \"remove\") then\n            scope[\"__override_\" .. apiname] = true\n        end\n\n        -- save api source info, e.g. call api() in sourcefile:linenumber\n        self:_save_sourceinfo_to_scope(scope, apiname, {...})\n\n        -- call function\n        return apifunc(self, scope, apiname, ...)\n    end\n\n    -- register implementation\n    self:_api_register_scope_api(scope_kind, action, implementation, ...)\nend\n\n-- register api for xxx_script\nfunction interpreter:_api_register_xxx_script(scope_kind, action, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- patch action to name\n        if action ~= \"on\" then\n            name = name .. \"_\" .. action\n        end\n\n        -- get arguments, pattern1, pattern2, ..., script function or name\n        local args = {...}\n\n        -- get and save extra config\n        local extra_config = args[#args]\n        if table.is_dictionary(extra_config) then\n            table.remove(args)\n            scope[\"__extra_\" .. name] = extra_config\n        end\n\n        -- mark as override\n        scope[\"__override_\" .. name] = true\n\n        -- get patterns\n        local patterns = {}\n        if #args > 1 then\n            patterns = table.slice(args, 1, #args - 1)\n        end\n\n        -- get script function or name\n        local script_func_or_name = args[#args]\n\n        -- get script\n        local script, errors = self:_script(script_func_or_name)\n        if not script then\n            if #patterns > 0 then\n                os.raise(\"%s_%s(%s, %s): %s\", action, name, table.concat(patterns, ', '), tostring(script_func_or_name), errors)\n            else\n                os.raise(\"%s_%s(%s): %s\", action, name, tostring(script_func_or_name), errors)\n            end\n        end\n\n        -- save script for all patterns\n        if #patterns > 0 then\n            local scripts = scope[name] or {}\n            for _, pattern in ipairs(patterns) do\n\n                -- check\n                assert(type(pattern) == \"string\")\n\n                -- convert pattern to a lua pattern ('*' => '.*')\n                pattern = pattern:gsub(\"([%+%.%-%^%$%%])\", \"%%%1\")\n                pattern = pattern:gsub(\"%*\", \"\\001\")\n                pattern = pattern:gsub(\"\\001\", \".*\")\n\n                -- save script\n                if type(scripts) == \"table\" then\n                    scripts[pattern] = script\n                elseif type(scripts) == \"function\" then\n                    scripts = {__generic__ = scripts}\n                    scripts[pattern] = script\n                end\n            end\n            scope[name] = scripts\n        else\n            -- save the generic script\n            local scripts = scope[name]\n            if type(scripts) == \"table\" then\n                scripts[\"__generic__\"] = script\n            else\n                scripts = script\n            end\n            scope[name] = scripts\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, action, implementation, ...)\nend\n\n-- translate api paths\nfunction interpreter:_api_translate_paths(values, apiname, infolevel)\n    local results = {}\n    for _, p in ipairs(values) do\n        if type(p) ~= \"string\" or #p == 0 then\n            local sourceinfo = debug.getinfo(infolevel or 3, \"Sl\")\n            interpreter._raise(string.format(\"%s(%s): invalid path value at %s:%d\", apiname, tostring(p),\n                sourceinfo.short_src or sourceinfo.source, sourceinfo.currentline))\n        end\n        if not p:find(\"^%s-%$%(.-%)\") and not path.is_absolute(p) then\n            table.insert(results, path.relative(path.absolute(p, self:scriptdir()), self:rootdir()))\n        else\n            table.insert(results, p)\n        end\n    end\n    return results\nend\n\n-- get api function within scope\nfunction interpreter:_api_within_scope(scope_kind, apiname)\n    local priv = self._PRIVATE\n    assert(priv)\n\n    -- the scopes\n    local scopes = priv._SCOPES\n    assert(scopes)\n\n    -- get scope api\n    if scope_kind and priv._APIS then\n\n        -- get api function\n        local api_scope = priv._APIS[scope_kind]\n        if api_scope then\n            return api_scope[apiname]\n        end\n    end\nend\n\n-- set api function within scope\nfunction interpreter:_api_within_scope_set(scope_kind, apiname, apifunc)\n    local priv = self._PRIVATE\n    assert(priv)\n\n    -- the scopes\n    local scopes = priv._SCOPES\n    assert(scopes)\n\n    -- get scope api\n    if scope_kind and priv._APIS then\n\n        -- get api function\n        local api_scope = priv._APIS[scope_kind]\n        if api_scope then\n            api_scope[apiname] = apifunc\n        end\n    end\nend\n\n-- clear results\nfunction interpreter:_clear()\n    assert(self and self._PRIVATE)\n\n    -- clear it\n    self._PRIVATE._SCOPES = {}\n    self._PRIVATE._MTIMES = {}\nend\n\n-- filter values\nfunction interpreter:_filter(values, level)\n    assert(self and values ~= nil)\n\n    -- return values directly if no filter\n    local filter = self._PRIVATE._FILTER\n    if filter == nil then\n        return values\n    end\n\n    -- init level\n    if level == nil then\n        level = 0\n    end\n\n    -- filter keyvalues\n    if table.is_dictionary(values) then\n        local results = {}\n        for key, value in pairs(values) do\n            key = (type(key) == \"string\" and filter:handle(key) or key)\n            if type(value) == \"string\" then\n                results[key] = filter:handle(value)\n            elseif type(value) == \"table\" and level < 1 then\n                results[key] = self:_filter(value, level + 1) -- only filter 2 levels for table values\n            else\n                results[key] = value\n            end\n            values = results\n        end\n    else\n        -- filter value or arrays\n        values = table.wrap(values)\n        for idx = 1, #values do\n            local value = values[idx]\n            if type(value) == \"string\" then\n                value = filter:handle(value)\n            elseif table.is_array(value) then\n                for i = 1, #value do\n                    local v = value[i]\n                    if type(v) == \"string\" then\n                        v = filter:handle(v)\n                    elseif type(v) == \"table\" and level < 1 then\n                        v = self:_filter(v, level + 1)\n                    end\n                    value[i] = v\n                end\n            end\n            values[idx] = value\n        end\n    end\n    return values\nend\n\n-- handle scope data\nfunction interpreter:_handle(scope, deduplicate, enable_filter)\n    assert(scope)\n\n    -- remove repeat values and unwrap it\n    local results = {}\n    for name, values in pairs(scope) do\n\n        -- filter values\n        --\n        -- @note we need to do filter before removing repeat values\n        -- https://github.com/xmake-io/xmake/issues/1732\n        if enable_filter then\n            values = self:_filter(values)\n        end\n\n        -- remove repeat first for each slice with removed item (__remove_xxx)\n        if deduplicate and not table.is_dictionary(values) then\n            local policy = self:deduplication_policy(name)\n            if policy ~= false then\n                local unique_func = policy == \"toleft\" and table.reverse_unique or table.unique\n                values = unique_func(values, function (v) return type(v) == \"string\" and v:startswith(\"__remove_\") end)\n            end\n        end\n\n        -- unwrap it if be only one\n        values = table.unwrap(values)\n\n        -- update it\n        results[name] = values\n    end\n    return results\nend\n\n-- make results\nfunction interpreter:_make(scope_kind, deduplicate, enable_filter)\n    assert(self and self._PRIVATE)\n\n    -- the scopes\n    local scopes = self._PRIVATE._SCOPES\n\n    -- empty scope?\n    if not scopes or not scopes._ROOT then\n        os.raise(\"the scope %s() is empty!\", scope_kind)\n    end\n\n    -- get the root scope info of the given scope kind, e.g. root.target\n    local results = {}\n    local scope_opt = {interpreter = self, deduplicate = deduplicate, enable_filter = enable_filter}\n    if scope_kind and scope_kind:startswith(\"root.\") then\n        local root_scope = {}\n        local empty = true\n        local kind_prefix = scope_kind:sub(6)\n        for kind, scope in pairs(scopes._ROOT) do\n            if kind:startswith(kind_prefix) then\n                local namespace = kind:match(kind_prefix .. \"@@(.+)::\")\n                if namespace or kind == kind_prefix then\n                    for k, v in pairs(scope) do\n                        if namespace then\n                            root_scope[namespace .. \"::\" .. k] = v\n                        else\n                            root_scope[k] = v\n                        end\n                    end\n                end\n                empty = false\n            end\n        end\n        if root_scope and not empty then\n            results = self:_handle(root_scope, deduplicate, enable_filter)\n        end\n        return scopeinfo.new(scope_kind, results, scope_opt)\n\n    -- get the root scope info without scope kind\n    elseif scope_kind == \"root\" or scope_kind == nil then\n        local root_scope = {}\n        local empty = true\n        for kind, scope in pairs(scopes._ROOT) do\n            if kind:startswith(\"__rootkind\") then\n                local namespace = kind:match(\"__rootkind@@(.+)::\")\n                if namespace or kind == \"__rootkind\" then\n                    for k, v in pairs(scope) do\n                        if namespace then\n                            root_scope[namespace .. \"::\" .. k] = v\n                        else\n                            root_scope[k] = v\n                        end\n                    end\n                end\n                empty = false\n            end\n        end\n        if root_scope and not empty then\n            results = self:_handle(root_scope, deduplicate, enable_filter)\n        end\n        return scopeinfo.new(scope_kind, results, scope_opt)\n\n    -- get the results of the given scope kind\n    elseif scope_kind then\n\n        -- not this scope for kind?\n        local scope_for_kind = scopes[scope_kind]\n        if scope_for_kind then\n\n            -- fetch the root values in root scope first\n            self:_fetch_root_scope(scopes._ROOT)\n\n            -- merge results\n            for scope_name, scope in pairs(scope_for_kind) do\n\n                -- add scope values\n                local scope_values = {}\n                for name, values in pairs(scope) do\n                    if not name:startswith(\"__override_\") then\n                        scope_values[name] = values\n                    end\n                end\n\n                -- merge root values with the given scope name\n                local scope_root = scopes._ROOT[scope_kind .. \"@@\" .. scope_name]\n                if scope_root then\n                    for name, values in pairs(scope_root) do\n                        if not scope[\"__override_\" .. name] then\n                            scope_values[name] = table.join(values, scope_values[name] or {})\n                        end\n                    end\n                end\n\n                -- add this scope\n                results[scope_name] = scopeinfo.new(scope_kind, self:_handle(scope_values, deduplicate, enable_filter), scope_opt)\n            end\n        end\n    end\n    return results\nend\n\n-- load script\nfunction interpreter:_script(script)\n\n    -- this script is module name? import it first\n    if type(script) == \"string\" then\n\n        -- import module as script\n        local modulename = script\n        script = function (...)\n\n            -- import it\n            _g._module = _g._module or import(modulename, {anonymous = true})\n            return _g._module(...)\n        end\n    end\n\n    -- make sandbox instance with the given script\n    local instance, errors = sandbox.new(script, {filter = self:filter(), rootdir = self:scriptdir(), namespace = self:namespace()})\n    if not instance then\n        return nil, errors\n    end\n\n    -- get sandbox script\n    return instance:script()\nend\n\n-- get builtin modules\nfunction interpreter.builtin_modules()\n    local builtin_modules = interpreter._BUILTIN_MODULES\n    if builtin_modules == nil then\n        builtin_modules = {}\n        local builtin_module_files = os.match(path.join(os.programdir(), \"core/sandbox/modules/interpreter/*.lua\"))\n        if builtin_module_files then\n            for _, builtin_module_file in ipairs(builtin_module_files) do\n                local module_name = path.basename(builtin_module_file)\n                assert(module_name)\n\n                local script, errors = loadfile(builtin_module_file)\n                if script then\n                    local ok, results = utils.trycall(script)\n                    if not ok then\n                        os.raise(results)\n                    end\n                    builtin_modules[module_name] = results\n                else\n                    os.raise(errors)\n                end\n            end\n        end\n        interpreter._BUILTIN_MODULES = builtin_modules\n    end\n    return builtin_modules\nend\n\n-- new an interpreter instance\nfunction interpreter.new()\n\n    -- init an interpreter instance\n    local instance = {  _PUBLIC = {}\n                    ,   _PRIVATE = {    _SCOPES = {}\n                                    ,   _MTIMES = {}\n                                    ,   _SCRIPT_FILES = {}\n                                    ,   _FILTER = require(\"base/filter\").new()}}\n\n    -- inherit the interfaces of interpreter\n    table.inherit2(instance, interpreter)\n\n    -- dispatch the api calling for scope\n    setmetatable(instance._PUBLIC, { __index = function (tbl, key)\n\n                                            -- get interpreter instance\n                                            if type(key) == \"string\" and key == \"_INTERPRETER\" and rawget(tbl, \"_INTERPRETER_READABLE\") then\n                                                return instance\n                                            end\n\n                                            -- get the scope kind\n                                            local priv          = instance._PRIVATE\n                                            local current_kind  = priv._SCOPES._CURRENT_KIND\n                                            local scope_kind    = current_kind or priv._ROOTSCOPE\n\n                                            -- get the api function from the given scope\n                                            local apifunc = instance:_api_within_scope(scope_kind, key)\n\n                                            -- get the api function from the root scope\n                                            if not apifunc and priv._ROOTAPIS then\n                                                apifunc = priv._ROOTAPIS[key]\n                                            end\n\n                                            -- ok?\n                                            return apifunc\n                                    end\n                                ,   __newindex = function (tbl, key, val)\n                                        if type(key) == \"string\" and (key == \"_INTERPRETER\" or key == \"_INTERPRETER_READABLE\") then\n                                            return\n                                        end\n                                        rawset(tbl, key, val)\n                                    end})\n\n    -- register the builtin interfaces\n    instance:api_register(nil, \"includes\",     interpreter.api_builtin_includes)\n    instance:api_register(nil, \"add_subdirs\",  interpreter.api_builtin_add_subdirs)\n    instance:api_register(nil, \"add_subfiles\", interpreter.api_builtin_add_subfiles)\n    instance:api_register(nil, \"set_xmakever\", interpreter.api_builtin_set_xmakever)\n    instance:api_register(nil, \"namespace\",    interpreter.api_builtin_namespace)\n    instance:api_register(nil, \"namespace_end\",interpreter.api_builtin_namespace_end)\n\n    -- register the interpreter interfaces\n    instance:api_register(nil, \"interp_save_scope\",    interpreter.api_interp_save_scope)\n    instance:api_register(nil, \"interp_restore_scope\", interpreter.api_interp_restore_scope)\n    instance:api_register(nil, \"interp_get_scopekind\", interpreter.api_interp_get_scopekind)\n    instance:api_register(nil, \"interp_get_scopename\", interpreter.api_interp_get_scopename)\n    instance:api_register(nil, \"interp_add_scopeapis\", interpreter.api_interp_add_scopeapis)\n\n    -- register the builtin modules\n    for module_name, module in pairs(interpreter.builtin_modules()) do\n        instance:api_register_builtin(module_name, module)\n    end\n\n    -- ok?\n    return instance\nend\n\n-- load script file, e.g. xmake.lua\n--\n-- @param opt   {on_load_data = function (data) return data end}\n--\nfunction interpreter:load(file, opt)\n    assert(self and self._PUBLIC and self._PRIVATE and file)\n\n    -- load the script\n    opt = opt or {}\n    local script, errors = loadfile(file, \"bt\", {on_load = opt.on_load_data})\n    if not script then\n        return nil, errors\n    end\n\n    -- clear first\n    self:_clear()\n\n    -- translate to absolute file path for scriptdir/rootdir\n    -- we need to normalize path for rootdir, @see https://github.com/xmake-io/xmake/issues/6995\n    file = path.normalize(path.absolute(file))\n\n    -- init the current file\n    self._PRIVATE._CURFILE = file\n    self._PRIVATE._SCRIPT_FILES = {file}\n\n    -- init the root directory\n    self._PRIVATE._ROOTDIR = path.directory(file)\n    assert(self._PRIVATE._ROOTDIR)\n\n    -- init mtime for the current file\n    self._PRIVATE._MTIMES[path.relative(file, self._PRIVATE._ROOTDIR)] = os.mtime(file)\n\n    -- bind public scope\n    setfenv(script, self._PUBLIC)\n\n    -- do interpreter\n    return xpcall(script, interpreter._traceback)\nend\n\n-- make results\nfunction interpreter:make(scope_kind, deduplicate, enable_filter)\n\n    -- get the results with the given scope\n    self._PENDING = true\n    local ok, results = xpcall(interpreter._make, interpreter._traceback, self, scope_kind, deduplicate, enable_filter)\n    self._PENDING = false\n    if not ok then\n        return nil, results\n    end\n    return results\nend\n\n-- is pending?\nfunction interpreter:pending()\n    return self._PENDING\nend\n\n-- get all loaded script files (xmake.lua)\nfunction interpreter:scriptfiles()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._SCRIPT_FILES\nend\n\n-- get mtimes\nfunction interpreter:mtimes()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._MTIMES\nend\n\n-- get current namespace\nfunction interpreter:namespace()\n    return self._PRIVATE._NAMESPACE_STR\nend\n\n-- get namespaces\nfunction interpreter:namespaces()\n    local namespaces = self._PRIVATE._NAMESPACES\n    return namespaces and namespaces:to_array()\nend\n\n-- get filter\nfunction interpreter:filter()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._FILTER\nend\n\n-- get root directory\nfunction interpreter:rootdir()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._ROOTDIR\nend\n\n-- set root directory\nfunction interpreter:rootdir_set(rootdir)\n    assert(self and self._PRIVATE and rootdir)\n    self._PRIVATE._ROOTDIR = rootdir\nend\n\n-- get script directory\nfunction interpreter:scriptdir()\n    assert(self and self._PRIVATE and self._PRIVATE._CURFILE)\n    return path.directory(self._PRIVATE._CURFILE)\nend\n\n-- set root scope kind\n--\n-- the root api will affect these scopes\n--\nfunction interpreter:rootscope_set(scope_kind)\n    assert(self and self._PRIVATE)\n    self._PRIVATE._ROOTSCOPE = scope_kind\nend\n\n-- get the deduplication policy\nfunction interpreter:deduplication_policy(name)\n    local policies = self._PRIVATE._DEDUPLICATION_POLICIES\n    if name then\n        return policies and policies[name]\n    else\n        return policies\n    end\nend\n\n-- set the deduplication policy\n--\n-- we need to be able to precisely control the direction of deduplication of different types of values.\n-- the default is to de-duplicate from left to right, but like links/syslinks need to be de-duplicated from right to left.\n--\n-- e.g\n--\n-- interp:deduplication_set(\"defines\", \"right\") -- remove duplicates to the right (default)\n-- interp:deduplication_set(\"links\", \"left\") -- remove duplicates to the left\n-- interp:deduplication_set(\"links\", false) -- disable deduplication\n--\n-- @see https://github.com/xmake-io/xmake/issues/1903\n--\nfunction interpreter:deduplication_policy_set(name, policy)\n    self._PRIVATE._DEDUPLICATION_POLICIES = self._PRIVATE._DEDUPLICATION_POLICIES or {}\n    self._PRIVATE._DEDUPLICATION_POLICIES[name] = policy\nend\n\n-- get apis\nfunction interpreter:apis(scope_kind)\n    assert(self and self._PRIVATE)\n\n    -- get apis from the given scope kind\n    if scope_kind and scope_kind ~= \"__rootkind\" then\n        local apis = self._PRIVATE._APIS\n        return apis and apis[scope_kind] or {}\n    else\n        return self._PRIVATE._ROOTAPIS or {}\n    end\nend\n\n-- get api definitions\nfunction interpreter:api_definitions()\n    return self._API_DEFINITIONS\nend\n\n-- register api\n--\n-- interp:api_register(nil, \"apiroot\", function () end)\n-- interp:api_register(\"scope_kind\", \"apiname\", function () end)\n--\n-- result:\n--\n-- _PRIVATE\n-- {\n--      _APIS\n--      {\n--          scope_kind\n--          {\n--              apiname = function () end\n--          }\n--      }\n--\n--      _ROOTAPIS\n--      {\n--          apiroot = function () end\n--      }\n-- }\n--\nfunction interpreter:api_register(scope_kind, name, func)\n    assert(self and self._PUBLIC and self._PRIVATE)\n    assert(name and func)\n\n    -- register api to the given scope kind\n    if scope_kind and scope_kind ~= \"__rootkind\" then\n\n        -- get apis\n        self._PRIVATE._APIS = self._PRIVATE._APIS or {}\n        local apis = self._PRIVATE._APIS\n\n        -- get scope\n        apis[scope_kind] = apis[scope_kind] or {}\n        local scope = apis[scope_kind]\n\n        -- register api\n        scope[name] = function (...)\n            return func(self, ...)\n        end\n    else\n\n        -- get root apis\n        self._PRIVATE._ROOTAPIS = self._PRIVATE._ROOTAPIS or {}\n        local apis = self._PRIVATE._ROOTAPIS\n\n        -- register api to the root scope\n        apis[name] = function (...)\n            return func(self, ...)\n        end\n    end\nend\n\n-- register api for builtin\nfunction interpreter:api_register_builtin(name, func)\n    assert(self and self._PUBLIC and func)\n    self._PUBLIC[name] = func\nend\n\n-- register api for scope()\n--\n-- interp:api_register_scope(\"scope_kind1\", \"scope_kind2\")\n--\n-- api:\n--   set_$(scope_kind1)(\"scope_name1\")\n--       ...\n--\n--   set_$(scope_kind2)(\"scope_name1\", \"scope_name2\")\n--       ...\n--\n-- result:\n--\n-- _PRIVATE\n-- {\n--      _SCOPES\n--      {\n--          scope_kind1\n--          {\n--              \"namespace1::scope_name1\"\n--              {\n--\n--              }\n--          }\n--\n--          scope_kind2\n--          {\n--              \"namespace1::namespace2::scope_name1\"\n--              {\n--\n--              }\n--\n--              \"scope_name2\" <-- _SCOPES._CURRENT\n--              {\n--                   __scriptdir = \"\" (the directory of xmake.lua)\n--              }\n--          }\n--      }\n-- }\n--\nfunction interpreter:api_register_scope(...)\n\n    -- define implementation\n    local implementation = function (self, scopes, scope_kind, ...)\n        local scope_args = table.pack(...)\n        local scope_name = scope_args[1]\n        local scope_info = scope_args[2]\n        local namespace = self._PRIVATE._NAMESPACE_STR\n        if scope_name ~= nil and namespace then\n            scope_name = namespace .. \"::\" .. scope_name\n        end\n\n        -- check invalid scope name, @see https://github.com/xmake-io/xmake/issues/4547\n        if scope_args.n > 0 and type(scope_name) ~= \"string\" then\n            local errors = string.format(\"%s(%s): invalid %s name\", scope_kind, scope_name, scope_kind)\n            local sourceinfo = debug.getinfo(2, \"Sl\")\n            if sourceinfo then\n                errors = string.format(\"%s:%s: %s\", sourceinfo.short_src or sourceinfo.source, sourceinfo.currentline, errors)\n            end\n            interpreter._raise(errors)\n        end\n\n        -- init scope for kind\n        local scope_for_kind = scopes[scope_kind] or {}\n        scopes[scope_kind] = scope_for_kind\n\n        -- enter the given scope\n        if scope_name ~= nil then\n\n            -- init scope for name\n            local scope = scope_for_kind[scope_name] or {}\n            scope_for_kind[scope_name] = scope\n\n            -- save the current scope\n            scopes._CURRENT = scope\n\n            -- save script directory of scope when enter this scope first\n            scope.__scriptdir = scope.__scriptdir or self:scriptdir()\n        else\n\n            -- enter root scope\n            scopes._CURRENT = nil\n        end\n\n        -- update the current scope kind\n        scopes._CURRENT_KIND = scope_kind\n\n        -- init scope_kind.scope_name for the current root scope\n        scopes._ROOT = scopes._ROOT or {}\n        if scope_name ~= nil then\n            scopes._ROOT[scope_kind .. \"@@\" .. scope_name] = {}\n        elseif namespace then\n            scopes._ROOT[scope_kind .. \"@@\" .. namespace .. \"::\"] = {}\n        end\n\n        -- with scope info? translate it\n        --\n        -- e.g.\n        -- option(\"text\", {showmenu = true, default = true, description = \"test option\"})\n        -- target(\"tbox\", {kind = \"static\", files = {\"src/*.c\", \"*.cpp\"}})\n        --\n        if scope_info and table.is_dictionary(scope_info) then\n            for name, values in pairs(scope_info) do\n                local apifunc = self:api_func(\"set_\" .. name) or self:api_func(\"add_\" .. name) or self:api_func(\"on_\" .. name) or self:api_func(name)\n                if apifunc then\n                    apifunc(table.unpack(table.wrap(values)))\n                else\n                    os.raise(\"unknown %s for %s(\\\"%s\\\")\", name, scope_kind, scope_name)\n                end\n            end\n\n            -- enter root scope\n            scopes._CURRENT = nil\n            scopes._CURRENT_KIND = nil\n        -- with scope function?\n        --\n        -- e.g.\n        --\n        --  target(\"foo\", function ()\n        --      set_kind(\"binary\")\n        --      add_files(\"src/*.cpp\")\n        --  end)\n        --\n        elseif scope_info and type(scope_info) == \"function\" then\n\n            -- configure scope info\n            scope_info()\n\n            -- enter root scope\n            scopes._CURRENT = nil\n            scopes._CURRENT_KIND = nil\n        end\n    end\n\n    -- register implementation to the root scope\n    self:_api_register_scope_api(nil, nil, implementation, ...)\n\n    -- register scope end\n    self:_api_register_scope_end(...)\nend\n\n-- register api for set_values\n--\n-- interp:api_register_set_values(\"scope_kind\", \"name1\", \"name2\", ...)\n--\n-- api:\n--   set_$(name1)(\"value1\")\n--   set_$(name2)(\"value1\", \"value2\", ...)\n--\n-- result:\n--\n-- _PRIVATE\n-- {\n--      _SCOPES\n--      {\n--          _ROOT\n--          {\n--              scope_kind\n--              {\n--                  name1 = {\"value3\"}\n--              }\n--              scope_kind@@namespace::\n--              {\n--                  name2 = {\"value3\"}\n--              }\n--          }\n--\n--          scope_kind\n--          {\n--              \"namespace::scope_name\" <-- _SCOPES._CURRENT\n--              {\n--                  name1 = {\"value1\"}\n--                  name2 = {\"value1\", \"value2\", ...}\n--\n--                  __override_name1 = true <- override\n--              }\n--          }\n--      }\n-- }\n--\nfunction interpreter:api_register_set_values(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- @note we need to mark table value as meta object to avoid wrap/unwrap\n        -- if these values cannot be expanded, especially when there is only one value\n        --\n        -- e.g. set_shflags({\"-Wl,-exported_symbols_list\", exportfile}, {force = true, expand = false})\n        if extra_config and extra_config.expand == false then\n            for _, value in ipairs(values) do\n                table.wrap_lock(value)\n            end\n        else\n            -- expand values\n            values = table.join(table.unpack(values))\n        end\n\n        -- save values\n        if #values > 0 then\n            scope[name] = values\n        else\n            -- set(\"xx\", nil)? remove it\n            scope[name] = nil\n        end\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            for _, value in ipairs(values) do\n                extrascope[value] = extra_config\n            end\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"set\", implementation, ...)\nend\n\n-- register api for add_values\nfunction interpreter:api_register_add_values(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- @note we need to mark table value as meta object to avoid wrap/unwrap\n        -- if these values cannot be expanded, especially when there is only one value\n        --\n        -- e.g. add_shflags({\"-Wl,-exported_symbols_list\", exportfile}, {force = true, expand = false})\n        if extra_config and extra_config.expand == false then\n            for _, value in ipairs(values) do\n                table.wrap_lock(value)\n            end\n        else\n            -- expand values\n            values = table.join(table.unpack(values))\n        end\n\n        -- save values\n        scope[name] = table.join2(scope[name] or {}, values)\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            for _, value in ipairs(values) do\n                extrascope[value] = extra_config\n            end\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"add\", implementation, ...)\nend\n\n-- register api for set_keyvalues\n--\n-- interp:api_register_set_keyvalues(\"scope_kind\", \"name1\", \"name2\", ...)\n--\n-- api:\n--   set_$(name1)(\"key\", \"value1\")\n--   set_$(name2)(\"key\", \"value1\", \"value2\", ...)\n--\n-- get:\n--\n--   get(\"name\")     => {key => values}\n--   get(\"name.key\") => values\n--\nfunction interpreter:api_register_set_keyvalues(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, key, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- save values to \"name\"\n        scope[name] = scope[name] or {}\n        scope[name][key] = table.unwrap(values) -- expand values if only one\n\n        -- save values to \"name.key\"\n        local name_key = name .. \".\" .. key\n        scope[name_key] = scope[name][key]\n\n        -- fix override attributes\n        scope[\"__override_\" .. name] = false\n        scope[\"__override_\" .. name_key] = true\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name_key] = scope[\"__extra_\" .. name_key] or {}\n            local extrascope = scope[\"__extra_\" .. name_key]\n            for _, value in ipairs(values) do\n                extrascope[value] = extra_config\n            end\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"set\", implementation, ...)\nend\n\n-- register api for set_groups\nfunction interpreter:api_register_set_groups(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- expand values\n        values = table.join(table.unpack(values))\n        table.wrap_lock(values)\n\n        -- save values\n        scope[name] = values\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            local key = table.concat(values, \"_\")\n            extrascope[key] = extra_config\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"set\", implementation, ...)\nend\n\n-- register api for add_groups\nfunction interpreter:api_register_add_groups(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- expand values\n        values = table.join(table.unpack(values))\n\n        -- save values\n        --\n        -- @note maybe scope[name] has been unwrapped, we need wrap it first\n        -- https://github.com/xmake-io/xmake/issues/4428\n        scope[name] = table.wrap(scope[name])\n        table.wrap_lock(values)\n        table.insert(scope[name], values)\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            local key = table.concat(values, \"_\")\n            extrascope[key] = extra_config\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"add\", implementation, ...)\nend\n\n-- register api for add_keyvalues\n--\n-- interp:api_register_add_keyvalues(\"scope_kind\", \"name1\", \"name2\", ...)\n--\nfunction interpreter:api_register_add_keyvalues(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, key, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- save values to \"name\"\n        scope[name] = scope[name] or {}\n        if scope[name][key] == nil then\n            -- expand values if only one\n            scope[name][key] = table.unwrap(values)\n        else\n            scope[name][key] = table.join2(table.wrap(scope[name][key]), values)\n        end\n\n        -- save values to \"name.key\"\n        local name_key = name .. \".\" .. key\n        scope[name_key] = scope[name][key]\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name_key] = scope[\"__extra_\" .. name_key] or {}\n            local extrascope = scope[\"__extra_\" .. name_key]\n            for _, value in ipairs(values) do\n                extrascope[value] = extra_config\n            end\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"add\", implementation, ...)\nend\n\n-- register api for on_script\nfunction interpreter:api_register_on_script(scope_kind, ...)\n    self:_api_register_xxx_script(scope_kind, \"on\", ...)\nend\n\n-- register api for before_script\nfunction interpreter:api_register_before_script(scope_kind, ...)\n    self:_api_register_xxx_script(scope_kind, \"before\", ...)\nend\n\n-- register api for after_script\nfunction interpreter:api_register_after_script(scope_kind, ...)\n    self:_api_register_xxx_script(scope_kind, \"after\", ...)\nend\n\n-- register api for set_dictionary\nfunction interpreter:api_register_set_dictionary(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, dict_or_key, value, extra_config)\n\n        -- check\n        if type(dict_or_key) == \"table\" then\n            scope[name] = dict_or_key\n        elseif type(dict_or_key) == \"string\" and value ~= nil then\n            scope[name] = {[dict_or_key] = value}\n            -- save extra config\n            if extra_config and table.is_dictionary(extra_config) then\n                scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n                local extrascope = scope[\"__extra_\" .. name]\n                extrascope[dict_or_key] = extra_config\n            end\n        else\n            -- error\n            os.raise(\"set_%s(%s): invalid value type!\", name, type(dict))\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"set\", implementation, ...)\nend\n\n-- register api for add_dictionary\nfunction interpreter:api_register_add_dictionary(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, dict_or_key, value, extra_config)\n\n        -- check\n        scope[name] = scope[name] or {}\n        if type(dict_or_key) == \"table\" then\n            table.join2(scope[name], dict_or_key)\n            extra_config = value\n        elseif type(dict_or_key) == \"string\" and value ~= nil then\n            scope[name][dict_or_key] = value\n            -- save extra config\n            if extra_config and table.is_dictionary(extra_config) then\n                scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n                local extrascope = scope[\"__extra_\" .. name]\n                extrascope[dict_or_key] = extra_config\n            end\n        else\n            -- error\n            os.raise(\"add_%s(%s): invalid value type!\", name, type(dict))\n        end\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"add\", implementation, ...)\nend\n\n-- register api for set_paths\nfunction interpreter:api_register_set_paths(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- translate paths\n        values = table.join(table.unpack(values))\n        local paths = self:_api_translate_paths(values, \"set_\" .. name)\n\n        -- save values\n        scope[name] = paths\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            for _, value in ipairs(paths) do\n                extrascope[value] = extra_config\n            end\n        end\n\n        -- save api source info, e.g. call api() in sourcefile:linenumber\n        self:_save_sourceinfo_to_scope(scope, name, paths)\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"set\", implementation, ...)\nend\n\n-- register api for del_paths (deprecated)\nfunction interpreter:api_register_del_paths(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- translate paths\n        local values = table.join(...)\n        local paths = self:_api_translate_paths(values, \"del_\" .. name)\n\n        -- it has been marked as deprecated\n        deprecated.add(\"remove_\" .. name .. \"(%s)\", \"del_\" .. name .. \"(%s)\", table.concat(values, \", \"), table.concat(values, \", \"))\n\n        -- mark these paths as deleted\n        local paths_deleted = {}\n        for _, pathname in ipairs(paths) do\n            table.insert(paths_deleted, \"__remove_\" .. pathname)\n        end\n\n        -- save values\n        scope[name] = table.join2(scope[name] or {}, paths_deleted)\n\n        -- save api source info, e.g. call api() in sourcefile:linenumber\n        self:_save_sourceinfo_to_scope(scope, name, paths)\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"del\", implementation, ...)\nend\n\n-- register api for remove_paths\nfunction interpreter:api_register_remove_paths(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- translate paths\n        local values = table.join(...)\n        local paths = self:_api_translate_paths(values, \"remove_\" .. name)\n\n        -- mark these paths as removed\n        local paths_removed = {}\n        for _, pathname in ipairs(paths) do\n            table.insert(paths_removed, \"__remove_\" .. pathname)\n        end\n\n        -- save values\n        scope[name] = table.join2(scope[name] or {}, paths_removed)\n\n        -- save api source info, e.g. call api() in sourcefile:linenumber\n        self:_save_sourceinfo_to_scope(scope, name, paths)\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"remove\", implementation, ...)\nend\n\n-- register api for add_paths\nfunction interpreter:api_register_add_paths(scope_kind, ...)\n\n    -- define implementation\n    local implementation = function (self, scope, name, ...)\n\n        -- get extra config\n        local values = {...}\n        local extra_config = values[#values]\n        if table.is_dictionary(extra_config) then\n            table.remove(values)\n        else\n            extra_config = nil\n        end\n\n        -- translate paths\n        values = table.join(table.unpack(values))\n        local paths = self:_api_translate_paths(values, \"add_\" .. name)\n\n        -- save values\n        scope[name] = table.join2(scope[name] or {}, paths)\n\n        -- save extra config\n        if extra_config then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            for _, value in ipairs(paths) do\n                extrascope[value] = extra_config\n            end\n        end\n\n        -- save api source info, e.g. call api() in sourcefile:linenumber\n        self:_save_sourceinfo_to_scope(scope, name, paths)\n    end\n\n    -- register implementation\n    self:_api_register_xxx_values(scope_kind, \"add\", implementation, ...)\nend\n\n-- define apis\n--\n-- @code\n--  interp:api_define\n--  {\n--      values =\n--      {\n--          -- target.add_xxx\n--          \"target.add_links\"\n--      ,   \"target.add_gcflags\"\n--      ,   \"target.add_ldflags\"\n--      ,   \"target.add_arflags\"\n--      ,   \"target.add_shflags\"\n--\n--          -- option.add_xxx\n--      ,   \"option.add_links\"\n--      ,   \"option.add_gcflags\"\n--      ,   \"option.add_ldflags\"\n--      ,   \"option.add_arflags\"\n--      ,   \"option.add_shflags\"\n--\n--          -- is_xxx\n--      ,   {\"is_os\", function (interp, ...) end}\n--      }\n--  ,   paths =\n--      {\n--          -- target.add_xxx\n--          \"target.add_linkdirs\"\n--          -- option.add_xxx\n--      ,   \"option.add_linkdirs\"\n--      }\n--  }\n-- @endcode\n--\nfunction interpreter:api_define(apis)\n\n    -- register apis\n    local scopes = {}\n    local definitions = self._API_DEFINITIONS or {}\n    for apitype, apifuncs in pairs(apis) do\n        for _, apifunc in ipairs(apifuncs) do\n\n            -- is {\"apifunc\", apiscript}?\n            local apiscript = nil\n            if type(apifunc) == \"table\" then\n\n                -- check\n                assert(#apifunc == 2 and type(apifunc[2]) == \"function\")\n\n                -- get function and script\n                apiscript   = apifunc[2]\n                apifunc     = apifunc[1]\n            end\n\n            -- register api definition, \"scope.apiname\" => \"apitype\"\n            definitions[apifunc] = apitype\n\n            -- get api function\n            local apiscope = nil\n            local funcname = nil\n            apifunc = apifunc:split('.', {plain = true})\n            assert(apifunc)\n            if #apifunc == 2 then\n                apiscope = apifunc[1]\n                funcname = apifunc[2]\n            else\n                funcname = apifunc[1]\n            end\n            assert(funcname)\n\n            -- register api script directly\n            if apiscript ~= nil then\n                self:api_register(apiscope, funcname, apiscript)\n            else\n\n                -- get function prefix\n                local prefix = nil\n                for _, name in ipairs({\"set\", \"add\", \"del\", \"remove\", \"on\", \"before\", \"after\"}) do\n                    if funcname:startswith(name .. \"_\") then\n                        prefix = name\n                        break\n                    end\n                end\n                assert(prefix)\n\n                -- get function name\n                funcname = funcname:sub(#prefix + 2)\n\n                -- get register\n                local register = self[string.format(\"api_register_%s_%s\", prefix, apitype)]\n                if not register then\n                    os.raise(\"interp:api_register_%s_%s() is unknown!\", prefix, apitype)\n                end\n\n                -- register scope first\n                if apiscope ~= nil and not scopes[apiscope] then\n                    self:api_register_scope(apiscope)\n                    scopes[apiscope] = true\n                end\n\n                -- register api\n                register(self, apiscope, funcname)\n            end\n        end\n    end\n    self._API_DEFINITIONS = definitions\nend\n\n-- the builtin api: set_xmakever()\nfunction interpreter:api_builtin_set_xmakever(minver)\n\n    -- no version\n    if not minver then\n        interpreter._raise(\"set_xmakever(): no version!\")\n    end\n\n    -- parse minimum version\n    local minvers = minver:split('.', {plain = true})\n    if not minvers or #minvers ~= 3 then\n        interpreter._raise(string.format(\"set_xmakever(\\\"%s\\\"): invalid version format!\", minver))\n    end\n\n    -- make minimum numerical version\n    local minvers_num = minvers[1] * 100 + minvers[2] * 10 + minvers[3]\n\n    -- parse current version\n    local curvers = xmake._VERSION_SHORT:split('.', {plain = true})\n\n    -- make current numerical version\n    local curvers_num = curvers[1] * 100 + curvers[2] * 10 + curvers[3]\n\n    -- check version\n    if curvers_num < minvers_num then\n        interpreter._raise(string.format(\"xmake v%s < v%s, please run `$xmake update` to upgrade xmake!\", xmake._VERSION_SHORT, minver))\n    end\nend\n\n-- the builtin api: includes()\nfunction interpreter:api_builtin_includes(...)\n    assert(self and self._PRIVATE and self._PRIVATE._ROOTDIR and self._PRIVATE._MTIMES)\n    local curfile = self._PRIVATE._CURFILE\n    local scopes = self._PRIVATE._SCOPES\n\n    -- find all files\n    local subpaths = table.join(...)\n    local subpaths_matched = {}\n    for _, subpath in ipairs(subpaths) do\n        local found = false\n        -- attempt to find files from programdir/includes/*.lua\n        -- e.g. includes(\"@builtin/check\")\n        if subpath:startswith(\"@builtin/\") then\n            local builtin_path = subpath:sub(10)\n            local files\n            if builtin_path:endswith(\".lua\") then\n                files = os.files(path.join(os.programdir(), \"includes\", builtin_path))\n            else\n                files = os.files(path.join(os.programdir(), \"includes\", builtin_path, \"xmake.lua\"))\n            end\n            if files and #files > 0 then\n                table.join2(subpaths_matched, files)\n                found = true\n            end\n        end\n        -- find the given files from the project directory\n        if not found then\n            local files\n            if subpath:endswith(\".lua\") then\n                files = os.files(subpath)\n            else\n                -- @see https://github.com/xmake-io/xmake/issues/6026\n                files = os.files(path.join(subpath, \"xmake.lua\"))\n            end\n            if files and #files > 0 then\n                table.join2(subpaths_matched, files)\n                found = true\n            end\n        end\n        -- attempt to find files from programdir/includes/*.lua (deprecated)\n        if not found and not path.is_absolute(subpath) then\n            -- e.g. includes(\"check_cflags.lua\")\n            if subpath:startswith(\"check_\") then\n                local files = os.files(path.join(os.programdir(), \"includes\", \"check\", subpath))\n                if files and #files > 0 then\n                    table.join2(subpaths_matched, files)\n                    found = true\n                    utils.warning(\"deprecated: please use includes(\\\"@builtin/check\\\") instead of includes(\\\"%s\\\")\", subpath)\n                end\n            elseif subpath:startswith(\"qt_\") then\n                local files = os.files(path.join(os.programdir(), \"includes\", \"qt\", subpath))\n                if files and #files > 0 then\n                    table.join2(subpaths_matched, files)\n                    found = true\n                    utils.warning(\"deprecated: please use includes(\\\"@builtin/qt\\\") instead of includes(\\\"%s\\\")\", subpath)\n                end\n            end\n        end\n        if not found then\n            utils.warning(\"includes(\\\"%s\\\") cannot find any files!\", subpath)\n        end\n    end\n\n    -- includes all files\n    for _, subpath in ipairs(subpaths_matched) do\n        if subpath and type(subpath) == \"string\" then\n\n            -- the file path\n            local file = subpath\n            if not subpath:endswith(\".lua\") then\n                file = path.join(subpath, path.filename(curfile))\n            end\n\n            -- get the absolute file path\n            if not path.is_absolute(file) then\n                file = path.absolute(file)\n            end\n\n            -- update the current file\n            self._PRIVATE._CURFILE = file\n            table.insert(self._PRIVATE._SCRIPT_FILES, file)\n\n            -- load the file script\n            local script, errors = loadfile(file)\n            if script then\n\n                -- bind public scope\n                setfenv(script, self._PUBLIC)\n\n                -- save the previous root scope\n                local root_prev = scopes._ROOT\n\n                -- save the previous scope\n                local scope_prev = scopes._CURRENT\n\n                -- save the previous scope kind\n                local scope_kind_prev = scopes._CURRENT_KIND\n\n                -- clear the current root scope\n                scopes._ROOT = nil\n\n                -- clear the current scope, force to enter root scope\n                scopes._CURRENT = nil\n\n                -- enter the script directory\n                local oldir = os.cd(path.directory(file))\n\n                -- done interpreter\n                local ok, errors = xpcall(script, interpreter._traceback)\n                if not ok then\n                    interpreter._raise(errors)\n                end\n\n                -- leave the script directory\n                os.cd(oldir)\n\n                -- restore the previous scope kind\n                scopes._CURRENT_KIND = scope_kind_prev\n\n                -- restore the previous scope\n                scopes._CURRENT = scope_prev\n\n                -- fetch the root values in root scopes first\n                self:_fetch_root_scope(scopes._ROOT)\n\n                -- restore the previous root scope and merge current root scope\n                -- it will override the previous values if the current values are override mode\n                -- so we priority use the values in subdirs scope\n                scopes._ROOT = self:_merge_root_scope(scopes._ROOT, root_prev, true)\n\n                -- get mtime of the file\n                self._PRIVATE._MTIMES[path.relative(file, self._PRIVATE._ROOTDIR)] = os.mtime(file)\n            else\n                interpreter._raise(errors)\n            end\n        end\n    end\n\n    -- restore the current file\n    self._PRIVATE._CURFILE = curfile\nend\n\n-- the builtin api: add_subdirs(), deprecated\nfunction interpreter:api_builtin_add_subdirs(...)\n    self:api_builtin_includes(...)\n    local dirs = {...}\n    deprecated.add(\"includes(%s)\", \"add_subdirs(%s)\", table.concat(dirs, \", \"), table.concat(dirs, \", \"))\nend\n\n-- the builtin api: add_subfiles(), deprecated\nfunction interpreter:api_builtin_add_subfiles(...)\n    self:api_builtin_includes(...)\n    local files = {...}\n    deprecated.add(\"includes(%s)\", \"add_subfiles(%s)\", table.concat(files, \", \"), table.concat(files, \", \"))\nend\n\n-- the builtin api: namespace()\nfunction interpreter:api_builtin_namespace(name, callback)\n\n    -- enter root scope\n    self:api_interp_save_scope()\n    local scopes = self._PRIVATE._SCOPES\n    scopes._CURRENT = nil\n    scopes._CURRENT_KIND = nil\n\n    -- enter namespace\n    local namespace = self._PRIVATE._NAMESPACE\n    if namespace == nil then\n        namespace = {}\n        self._PRIVATE._NAMESPACE = namespace\n    end\n    table.insert(namespace, name)\n    self._PRIVATE._NAMESPACE_STR = table.concat(namespace, \"::\")\n    -- save namespaces\n    local namespaces = self._PRIVATE._NAMESPACES\n    if namespaces == nil then\n        namespaces = hashset.new()\n        self._PRIVATE._NAMESPACES = namespaces\n    end\n    namespaces:insert(self._PRIVATE._NAMESPACE_STR)\n    if callback and type(callback) == \"function\" then\n        callback()\n        self:api_builtin_namespace_end()\n    end\nend\n\n-- the builtin api: namespace_end()\nfunction interpreter:api_builtin_namespace_end()\n    assert(self and self._PRIVATE)\n    local namespace = self._PRIVATE._NAMESPACE\n    if namespace then\n        table.remove(namespace)\n    end\n    if namespace and #namespace > 0 then\n        self._PRIVATE._NAMESPACE_STR = table.concat(namespace, \"::\")\n    else\n        self._PRIVATE._NAMESPACE_STR = nil\n    end\n    self:api_interp_restore_scope()\nend\n\n-- the interpreter api: interp_save_scope()\n-- save the current scope\nfunction interpreter:api_interp_save_scope()\n    assert(self and self._PRIVATE)\n\n    -- the scopes\n    local scopes = self._PRIVATE._SCOPES\n    assert(scopes)\n\n    -- save the current scope\n    local scope = {}\n    scope._CURRENT      = scopes._CURRENT\n    scope._CURRENT_KIND = scopes._CURRENT_KIND\n    self._PRIVATE._SCOPES_SAVED = self._PRIVATE._SCOPES_SAVED or {}\n    table.insert(self._PRIVATE._SCOPES_SAVED, scope)\nend\n\n-- the interpreter api: interp_restore_scope()\n-- restore the current scope\nfunction interpreter:api_interp_restore_scope()\n    assert(self and self._PRIVATE)\n\n    -- the scopes\n    local scopes = self._PRIVATE._SCOPES\n    assert(scopes)\n\n    -- restore it\n    local scopes_saved = self._PRIVATE._SCOPES_SAVED\n    if scopes_saved and #scopes_saved > 0 then\n        local scope = scopes_saved[#scopes_saved]\n        if scope then\n            scopes._CURRENT      = scope._CURRENT\n            scopes._CURRENT_KIND = scope._CURRENT_KIND\n            table.remove(scopes_saved, #scopes_saved)\n        end\n    end\nend\n\n-- the interpreter api: interp_get_scopekind()\nfunction interpreter:api_interp_get_scopekind()\n    local scopes = self._PRIVATE._SCOPES\n    return scopes._CURRENT_KIND\nend\n\n-- the interpreter api: interp_get_scopename()\nfunction interpreter:api_interp_get_scopename()\n    local scopes = self._PRIVATE._SCOPES\n    local scope_kind = scopes._CURRENT_KIND\n    if scope_kind and scopes[scope_kind] then\n        local scope_current = scopes._CURRENT\n        for name, scope in pairs(scopes[scope_kind]) do\n            if scope_current == scope then\n                return name\n            end\n        end\n    end\nend\n\n-- the interpreter api: interp_add_scopeapis()\nfunction interpreter:api_interp_add_scopeapis(...)\n    local apis = {...}\n    local extra_config = apis[#apis]\n    if table.is_dictionary(extra_config) then\n        table.remove(apis)\n    else\n        extra_config = nil\n    end\n    if extra_config and #apis == 0 then\n        self:api_define(extra_config)\n    else\n        local kind = \"values\"\n        if extra_config and extra_config.kind then\n            kind = extra_config.kind\n        end\n        return self:api_define({[kind] = apis})\n    end\nend\n\n-- get api function\nfunction interpreter:api_func(apiname)\n    assert(self and self._PUBLIC and apiname)\n    return self._PUBLIC[apiname]\nend\n\n-- call api\nfunction interpreter:api_call(apiname, ...)\n    assert(self and apiname)\n\n    local apifunc = self:api_func(apiname)\n    if not apifunc then\n        os.raise(\"call %s() failed, this api not found!\", apiname)\n    end\n    return apifunc(...)\nend\n\n-- get current instance in the interpreter modules\nfunction interpreter.instance(script)\n\n    -- get the sandbox instance from the given script\n    local instance = nil\n    if script then\n        local scope = getfenv(script)\n        if scope then\n            rawset(scope, \"_INTERPRETER_READABLE\", true)\n            instance = scope._INTERPRETER\n            rawset(scope, \"_INTERPRETER_READABLE\", nil)\n        end\n        if instance then return instance end\n    end\n\n    -- find self instance for the current sandbox\n    local level = 2\n    while level < 32 do\n        local scope = getfenv(level)\n        if scope then\n            rawset(scope, \"_INTERPRETER_READABLE\", true)\n            instance = scope._INTERPRETER\n            rawset(scope, \"_INTERPRETER_READABLE\", nil)\n        end\n        if instance then\n            break\n        end\n        level = level + 1\n    end\n    return instance\nend\n\n-- return module: interpreter\nreturn interpreter\n"
  },
  {
    "path": "xmake/core/base/io.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        io.lua\n--\n\n-- define module\nlocal io        = io or {}\nlocal _file     = _file or {}\nlocal _filelock = _filelock or {}\n\n-- load modules\nlocal path      = require(\"base/path\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal todisplay = require(\"base/todisplay\")\n\n-- save metatable and builtin functions\nio._file        = _file\nio._filelock    = _filelock\nio._stdfile     = io._stdfile or io.stdfile\n\n-- new a file\nfunction _file.new(filepath, cdata, isstdfile)\n    local file = table.inherit(_file)\n    file._PATH = isstdfile and filepath or path.absolute(filepath)\n    file._FILE = cdata\n    setmetatable(file, _file)\n    return file\nend\n\n-- get the file name\nfunction _file:name()\n    if not self._NAME then\n        self._NAME = path.filename(self:path())\n    end\n    return self._NAME\nend\n\n-- get the file path\nfunction _file:path()\n    return self._PATH\nend\n\n-- close file\nfunction _file:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- close file\n    ok, errors = io.file_close(self:cdata())\n    if ok then\n        self._FILE = nil\n    end\n    return ok, errors\nend\n\n-- tostring(file)\nfunction _file:__tostring()\n    local str = self:path()\n    if #str > 16 then\n        str = \"..\" .. str:sub(#str - 16, #str)\n    end\n    return \"<file: \" .. str .. \">\"\nend\n\n-- todisplay(file)\nfunction _file:__todisplay()\n    local size = _file.size(self)\n    local filepath = _file.path(self)\n    if not size then\n        return string.format(\"file${reset} %s\", todisplay(filepath))\n    end\n\n    local unit = \"B\"\n    if size >= 1000 then\n        size = size / 1024\n        unit = \"KiB\"\n    end\n    if size >= 1000 then\n        size = size / 1024\n        unit = \"MiB\"\n    end\n    if size >= 1000 then\n        size = size / 1024\n        unit = \"GiB\"\n    end\n    return string.format(\"file${reset}(${color.dump.number}%.3f%s${reset}) %s\", size, unit, todisplay(filepath))\nend\n\n-- gc(file)\nfunction _file:__gc()\n    if self:cdata() and io.file_close(self:cdata()) then\n        -- remove ref to notify gc that it should be freed\n        self._FILE = nil\n    end\nend\n\n-- get file length\nfunction _file:__len()\n    return _file.size(self)\nend\n\n-- get cdata\nfunction _file:cdata()\n    return self._FILE\nend\n\n-- get file rawfd\nfunction _file:rawfd()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- get file rawfd\n    local result, errors = io.file_rawfd(self:cdata())\n    if not result and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- get file size\nfunction _file:size()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- get file size\n    local result, errors = io.file_size(self:cdata())\n    if not result and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- read data from file\n--\n-- @param fmt       the reading format\n-- @param opt       the options\n--                  - continuation (concat string with the given continuation characters)\n--\nfunction _file:read(fmt, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- read file\n    opt = opt or {}\n    local result, errors = io.file_read(self:cdata(), fmt, opt.continuation)\n    if errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- is readable?\nfunction _file:readable()\n\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    return io.file_readable(self:cdata())\nend\n\n-- write data to file\nfunction _file:write(...)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- data items\n    local items = table.pack(...)\n    for idx, item in ipairs(items) do\n        if type(item) == \"table\" and item.caddr and item.size then\n            -- write bytes\n            items[idx] = {data = item:caddr(), size = item:size()}\n        end\n    end\n\n    -- write file\n    ok, errors = io.file_write(self:cdata(), table.unpack(items))\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- seek offset at file\nfunction _file:seek(whence, offset)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- seek file\n    local result, errors = io.file_seek(self:cdata(), whence, offset)\n    if not result and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- flush data to file\nfunction _file:flush()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- flush file\n    ok, errors = io.file_flush(self:cdata())\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- this file is a tty?\nfunction _file:isatty()\n    local isatty_cached = self._ISATTY\n    if isatty_cached ~= nil then\n        return isatty_cached\n    end\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- is a tty?\n    ok, errors = io.file_isatty(self:cdata())\n    if ok == nil and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    self._ISATTY = ok\n    return ok, errors\nend\n\n-- ensure the file is opened\nfunction _file:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- read all lines from file\nfunction _file:lines(opt)\n    opt = opt or {}\n    return function()\n        local l = _file.read(self, \"l\", opt)\n        if not l and opt.close_on_finished then\n            _file.close(self)\n        end\n        return l\n    end\nend\n\n-- print file\nfunction _file:print(...)\n    return _file.write(self, string.format(...), \"\\n\")\nend\n\n-- printf file\nfunction _file:printf(...)\n    return _file.write(self, string.format(...))\nend\n\n-- save object\nfunction _file:save(object, opt)\n    local str, errors = string.serialize(object, opt)\n    if errors then\n        return false, errors\n    else\n        return _file.write(self, str)\n    end\nend\n\n-- load object\nfunction _file:load()\n    local data, err = _file.read(self, \"*all\")\n    if err then\n        return nil, err\n    end\n    if data and type(data) == \"string\" then\n        return data:deserialize()\n    end\nend\n\n-- new an filelock\nfunction _filelock.new(lockpath, lock)\n    local filelock = table.inherit(_filelock)\n    filelock._PATH = path.absolute(lockpath)\n    filelock._LOCK = lock\n    filelock._LOCKED_NUM = 0\n    setmetatable(filelock, _filelock)\n    return filelock\nend\n\n-- get the filelock name\nfunction _filelock:name()\n    if not self._NAME then\n        self._NAME = path.filename(self:path())\n    end\n    return self._NAME\nend\n\n-- get the filelock path\nfunction _filelock:path()\n    return self._PATH\nend\n\n-- get the cdata\nfunction _filelock:cdata()\n    return self._LOCK\nend\n\n-- is locked?\nfunction _filelock:islocked()\n    return self._LOCKED_NUM > 0\nend\n\n-- lock file\n--\n-- @param opt       the argument option, {shared = true}\n--\n-- @return          ok, errors\n--\nfunction _filelock:lock(opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- lock it\n    if self._LOCKED_NUM > 0 or io.filelock_lock(self:cdata(), opt) then\n        self._LOCKED_NUM = self._LOCKED_NUM + 1\n        return true\n    else\n        return false, string.format(\"%s: lock failed!\", self)\n    end\nend\n\n-- try to lock file\n--\n-- @param opt       the argument option, {shared = true}\n--\n-- @return          ok, errors\n--\nfunction _filelock:trylock(opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- try lock it\n    if self._LOCKED_NUM > 0 or io.filelock_trylock(self:cdata(), opt) then\n        self._LOCKED_NUM = self._LOCKED_NUM + 1\n        return true\n    else\n        return false, string.format(\"%s: trylock failed!\", self)\n    end\nend\n\n-- unlock file\nfunction _filelock:unlock(opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- unlock it\n    if self._LOCKED_NUM > 1 or (self._LOCKED_NUM > 0 and io.filelock_unlock(self:cdata())) then\n        if self._LOCKED_NUM > 0 then\n            self._LOCKED_NUM = self._LOCKED_NUM - 1\n        else\n            self._LOCKED_NUM = 0\n        end\n        return true\n    else\n        return false, string.format(\"%s: unlock failed!\", self)\n    end\nend\n\n-- close filelock\nfunction _filelock:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- close it\n    ok = io.filelock_close(self:cdata())\n    if ok then\n        self._LOCK = nil\n        self._LOCKED_NUM = 0\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _filelock:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(filelock)\nfunction _filelock:__tostring()\n    local str = _filelock.path(self)\n    if #str > 16 then\n        str = \"..\" .. str:sub(#str - 16, #str)\n    end\n    return \"<filelock: \" .. str .. \">\"\nend\n\n-- todisplay(filelock)\nfunction _filelock:__todisplay()\n    local str = _filelock.path(self)\n    return \"filelock${reset} \" .. todisplay(str)\nend\n\n-- gc(filelock)\nfunction _filelock:__gc()\n    if self:cdata() and io.filelock_close(self:cdata()) then\n        self._LOCK = nil\n        self._LOCKED_NUM = 0\n    end\nend\n\n-- read all lines from file\nfunction io.lines(filepath, opt)\n    opt = opt or {}\n    if opt.close_on_finished == nil then\n        opt.close_on_finished = true\n    end\n    local file = io.open(filepath, \"r\", opt)\n    if not file then\n        return function() return nil end\n    end\n    return file:lines(opt)\nend\n\n-- read all data from file\nfunction io.readfile(filepath, opt)\n    opt = opt or {}\n    local file, errors = io.open(tostring(filepath), \"r\", opt)\n    if not file then\n        return nil, errors\n    end\n    local data, err = file:read(\"*all\", opt)\n    file:close()\n    return data, err\nend\n\nfunction io.read(fmt, opt)\n    return io.stdin:read(fmt, opt)\nend\n\nfunction io.readable()\n    return io.stdin:readable()\nend\n\nfunction io.write(...)\n    return io.stdout:write(...)\nend\n\nfunction io.print(...)\n    return io.stdout:print(...)\nend\n\nfunction io.printf(...)\n    return io.stdout:printf(...)\nend\n\nfunction io.flush()\n    return io.stdout:flush()\nend\n\n-- write data to file\nfunction io.writefile(filepath, data, opt)\n    opt = opt or {}\n    local file, errors = io.open(tostring(filepath), \"w\", opt)\n    if not file then\n        return false, errors\n    end\n    file:write(data)\n    file:close()\n    return true\nend\n\n-- isatty\nfunction io.isatty(file)\n    file = file or io.stdout\n    return file:isatty()\nend\n\n-- get std file, /dev/stdin, /dev/stdout, /dev/stderr\nfunction io.stdfile(filepath)\n    local file = nil\n    if filepath == \"/dev/stdin\" then\n        file = io._stdfile(1)\n    elseif filepath == \"/dev/stdout\" then\n        file = io._stdfile(2)\n    elseif filepath == \"/dev/stderr\" then\n        file = io._stdfile(3)\n    end\n    if file then\n        return _file.new(filepath, file, true)\n    else\n        return nil, string.format(\"failed to get std file: %s\", filepath)\n    end\nend\n\n-- open file\n--\n-- @param filepath      the file path\n-- @param mode          the open mode, e.g. 'r', 'rb', 'w+', 'a+', ..\n-- @param opt           the options\n--                      - encoding, e.g. utf8, utf16, utf16le, utf16be ..\n--\nfunction io.open(filepath, mode, opt)\n\n    -- init option and mode\n    opt  = opt or {}\n    mode = mode or \"r\"\n\n    -- open it\n    filepath = tostring(filepath)\n    local file = io.file_open(filepath, mode .. (opt.encoding or \"\"))\n    if file then\n        return _file.new(filepath, file)\n    else\n        return nil, string.format(\"cannot open file: %s, %s\", filepath, os.strerror())\n    end\nend\n\n-- open a filelock\nfunction io.openlock(filepath)\n    filepath = tostring(filepath)\n    local lock = io.filelock_open(filepath)\n    if lock then\n        return _filelock.new(filepath, lock)\n    else\n        return nil, string.format(\"cannot open lock: %s, %s\", filepath, os.strerror())\n    end\nend\n\n-- close file\nfunction io.close(file)\n    return (file or io.stdout):close()\nend\n\n-- convert file encoding\n--\n-- @param inputfile     the input file path\n-- @param outputfile    the output file path\n-- @param opt           the options\n--                      - from: the input encoding, e.g. utf8, utf8bom, utf16, utf16le, utf16lebom, utf16be, gb2312, gbk, iso8859, ucs2, ucs4, utf32 .. (default: utf8)\n--                      - to: the output encoding, e.g. utf8, utf8bom, utf16, utf16le, utf16lebom, utf16be, gb2312, gbk, iso8859, ucs2, ucs4, utf32 .. (default: utf8)\nfunction io.convert(inputfile, outputfile, opt)\n    opt = opt or {}\n    inputfile = tostring(inputfile)\n    outputfile = tostring(outputfile)\n    local from = opt.from or \"utf8\"\n    local to = opt.to or \"utf8\"\n\n    -- try using c implementation first\n    if io.file_convert and io.file_convert(inputfile, outputfile, from, to) then\n        return true\n    end\n\n    -- fallback to lua implementation (slow but works)\n    local content, errors = io.readfile(inputfile, {encoding = from})\n    if not content then\n        return false, errors\n    end\n    return io.writefile(outputfile, content, {encoding = to})\nend\n\n-- save object the the given filepath\nfunction io.save(filepath, object, opt)\n    opt = opt or {}\n    assert(filepath and object)\n    filepath = tostring(filepath)\n\n    -- we save it when file is only changed, we can ensure file modify time.\n    local oldstr\n    if opt.only_changed and os.isfile(filepath) then\n        oldstr = io.readfile(filepath, {encoding = \"binary\"})\n    end\n\n    local ok, errors, str\n    str, errors = string.serialize(object, opt)\n    if str then\n        local write = true\n        if opt.only_changed then\n            if oldstr == str then\n                write = false\n            end\n        end\n        if write then\n            ok, errors = io.writefile(filepath, str, {encoding = \"binary\"})\n        else\n            ok = true\n        end\n    end\n    if not ok then\n        return false, string.format(\"save %s failed, %s!\", filepath, errors)\n    end\n    return true\nend\n\n-- load object from the given file\nfunction io.load(filepath, opt)\n    assert(filepath)\n\n    opt = opt or {}\n    filepath = tostring(filepath)\n    local file, err = io.open(filepath, \"rb\", opt)\n    if err then\n        return nil, err\n    end\n    local result, errors = file:load()\n    file:close()\n    return result, errors\nend\n\n-- gsub the given file and return replaced data\nfunction io.gsub(filepath, pattern, replace, opt)\n\n    -- read all data from file\n    opt = opt or {}\n    local data, errors = io.readfile(filepath, opt)\n    if not data then return nil, 0, errors end\n\n    -- replace it\n    local count = 0\n    if type(data) == \"string\" then\n        data, count = data:gsub(pattern, replace)\n    else\n        return nil, 0, string.format(\"data is not string!\")\n    end\n\n    -- replace ok?\n    if count ~= 0 then\n        -- write all data to file\n        local ok, errors = io.writefile(filepath, data, opt)\n        if not ok then return nil, 0, errors end\n    end\n    return data, count\nend\n\n-- replace text of the given file and return new file data\nfunction io.replace(filepath, pattern, replace, opt)\n    opt = opt or {}\n    local data, errors = io.readfile(filepath, opt)\n    if not data then return nil, 0, errors end\n\n    local count = 0\n    if type(data) == \"string\" then\n        data, count = data:replace(pattern, replace, opt)\n    else\n        return nil, 0, string.format(\"data is not string!\")\n    end\n    if count ~= 0 then\n        local ok, errors = io.writefile(filepath, data, opt)\n        if not ok then return nil, 0, errors end\n    end\n    return data, count\nend\n\n-- insert text before line number in the given file and return new file data\nfunction io.insert(filepath, lineidx, text, opt)\n    opt = opt or {}\n    local data, errors = io.readfile(filepath, opt)\n    if not data then return nil, errors end\n\n    local newdata\n    if type(data) == \"string\" then\n        newdata = {}\n        for idx, line in ipairs(data:split(\"\\n\")) do\n            if idx == lineidx then\n                table.insert(newdata, text)\n            end\n            table.insert(newdata, line)\n        end\n    else\n        return nil, string.format(\"data is not string!\")\n    end\n    if newdata and #newdata > 0 then\n        local rn = data:find(\"\\r\\n\", 1, true)\n        data = table.concat(newdata, rn and \"\\r\\n\" or \"\\n\")\n        local ok, errors = io.writefile(filepath, data, opt)\n        if not ok then return nil, errors end\n    end\n    return data, count\nend\n\n-- cat the given file\nfunction io.cat(filepath, linecount, opt)\n    opt = opt or {}\n    local file = io.open(filepath, \"r\", opt)\n    if file then\n        local count = 1\n        for line in file:lines(opt) do\n            io.write(line, \"\\n\")\n            if linecount and count >= linecount then\n                break\n            end\n            count = count + 1\n        end\n        file:close()\n    end\nend\n\n-- tail the given file\nfunction io.tail(filepath, linecount, opt)\n    opt = opt or {}\n    if linecount < 0 then\n        return io.cat(filepath, opt)\n    end\n\n    -- open file\n    local file = io.open(filepath, \"r\", opt)\n    if file then\n        local lines = {}\n        for line in file:lines(opt) do\n            table.insert(lines, line)\n        end\n\n        local tails = {}\n        if #lines ~= 0 then\n            local count = 1\n            for index = #lines, 1, -1 do\n                table.insert(tails, lines[index])\n                if linecount and count >= linecount then\n                    break\n                end\n                count = count + 1\n            end\n        end\n\n        if #tails ~= 0 then\n            for index = #tails, 1, -1 do\n                io.print(tails[index])\n            end\n        end\n        file:close()\n    end\nend\n\n-- lazy loading stdfile\nio.stdin  = nil\nio.stdout = nil\nio.stderr = nil\nsetmetatable(io, { __index = function (tbl, key)\n        local val = rawget(tbl, key)\n        if val == nil and (key == \"stdin\" or key == \"stdout\" or key == \"stderr\") then\n            val = io.stdfile(\"/dev/\" .. key)\n            if val ~= nil then\n                rawset(tbl, key, val)\n            end\n        end\n        return val\n    end})\n\n-- return module\nreturn io\n"
  },
  {
    "path": "xmake/core/base/json.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        json.lua\n--\n\n-- define module: json\nlocal json  = json or {}\n\n-- load modules\nlocal io    = require(\"base/io\")\nlocal os    = require(\"base/os\")\nlocal table = require(\"base/table\")\nlocal utils = require(\"base/utils\")\n\n-- export null\njson.purenull = {}\nsetmetatable(json.purenull, {\n    __is_json_null = true,\n    __eq = function (obj)\n        if type(obj) == \"table\" then\n            local mt = getmetatable(obj)\n            if mt and mt.__is_json_null then\n                return true\n            end\n        end\n        return false\n    end,\n    __tostring = function()\n        return \"null\"\n    end})\nif cjson then\n    json.null = cjson.null\nelse\n    json.null = json.purenull\nend\n\nfunction json._pure_kind_of(obj)\n    if type(obj) ~= \"table\" then\n        return type(obj)\n    end\n    if json.is_marked_as_array(obj) then\n        return \"array\"\n    end\n    if obj == json.purenull then\n        return \"nil\"\n    end\n    local i = 1\n    for _ in pairs(obj) do\n        if obj[i] ~= nil then\n            i = i + 1\n        else\n            return \"table\"\n        end\n    end\n    if i == 1 then\n        return \"table\"\n    else\n        return \"array\"\n    end\nend\n\nfunction json._pure_escape_str(s)\n    local in_char  = {'\\\\', '\"', '/', '\\b', '\\f', '\\n', '\\r', '\\t'}\n    local out_char = {'\\\\', '\"', '/',  'b',  'f',  'n',  'r',  't'}\n    for i, c in ipairs(in_char) do\n        s = s:gsub(c, '\\\\' .. out_char[i])\n    end\n    return s\nend\n\nfunction json._pure_skip_delim(str, pos, delim, err_if_missing)\n    pos = pos + #str:match('^%s*', pos)\n    if str:sub(pos, pos) ~= delim then\n        if err_if_missing then\n            os.raise(\"expected %s near position %d\", delim, pos)\n        end\n        return pos, false\n    end\n    return pos + 1, true\nend\n\nfunction json._pure_parse_str_val(str, pos, val)\n    val = val or ''\n    local early_end_error = \"end of input found while parsing string.\"\n    if pos > #str then\n        os.raise(early_end_error)\n    end\n    local c = str:sub(pos, pos)\n    if c == '\"'  then\n        return val, pos + 1\n    end\n    if c ~= '\\\\' then\n        return json._pure_parse_str_val(str, pos + 1, val .. c)\n    end\n\n    -- we must have a \\ character.\n    local esc_map = {b = '\\b', f = '\\f', n = '\\n', r = '\\r', t = '\\t'}\n    local nextc = str:sub(pos + 1, pos + 1)\n    if not nextc then\n        os.raise(early_end_error)\n    end\n    return json._pure_parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))\nend\n\nfunction json._pure_parse_num_val(str, pos)\n    local num_str\n    if str:sub(pos, pos + 1) == \"0x\" then\n        num_str = str:match('^-?0[xX][0-9a-fA-F]+', pos)\n    else\n        num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)\n    end\n    local val = tonumber(num_str)\n    if not val then\n        os.raise(\"error parsing number at position %d\", pos)\n    end\n    return val, pos + #num_str\nend\n\nfunction json._pure_stringify(obj, level, as_key, opt)\n    opt = opt or {}\n    level = level or 0\n    local pretty = opt.pretty\n    local orderkeys = opt.orderkeys\n    if orderkeys == nil and pretty then\n        orderkeys = true\n    end\n    local indent_step = pretty and (opt.indent or 4) or nil\n    local newline = pretty and \"\\n\" or \"\"\n    local curr_indent = indent_step and string.rep(\" \", indent_step * level) or nil\n    local child_indent = indent_step and string.rep(\" \", indent_step * (level + 1)) or nil\n    local s = {}\n    local kind = json._pure_kind_of(obj)\n    if kind == \"array\" then\n        if as_key then\n            os.raise(\"can\\'t encode array as key.\")\n        end\n        s[#s + 1] = '['\n        local arrlen = #obj\n        if pretty and arrlen > 0 then\n            s[#s + 1] = newline\n        end\n        for idx = 1, arrlen do\n            if idx > 1 then\n                s[#s + 1] = ','\n                if pretty then\n                    s[#s + 1] = newline\n                end\n            end\n            if pretty then\n                s[#s + 1] = child_indent\n            end\n            s[#s + 1] = json._pure_stringify(obj[idx], level + 1, false, opt)\n        end\n        if pretty and arrlen > 0 then\n            s[#s + 1] = newline\n            s[#s + 1] = curr_indent\n        end\n        s[#s + 1] = ']'\n    elseif kind == \"table\" then\n        if as_key then\n            os.raise(\"can\\'t encode table as key.\")\n        end\n        s[#s + 1] = '{'\n        local first = true\n        local iter = orderkeys and table.orderpairs or pairs\n        for k, v in iter(obj) do\n            if not first then\n                s[#s + 1] = ','\n            end\n            if pretty then\n                s[#s + 1] = newline\n                s[#s + 1] = child_indent\n            end\n            s[#s + 1] = json._pure_stringify(k, level + 1, true, opt)\n            s[#s + 1] = ':'\n            if pretty then\n                s[#s + 1] = ' '\n            end\n            s[#s + 1] = json._pure_stringify(v, level + 1, false, opt)\n            first = false\n        end\n        if pretty and not first then\n            s[#s + 1] = newline\n            s[#s + 1] = curr_indent\n        end\n        s[#s + 1] = '}'\n    elseif kind == \"string\" then\n        return '\"' .. json._pure_escape_str(obj) .. '\"'\n    elseif kind == \"number\" then\n        if as_key then\n            return '\"' .. tostring(obj) .. '\"'\n        end\n        return tostring(obj)\n    elseif kind == \"boolean\" then\n        return tostring(obj)\n    elseif kind == \"nil\" then\n        return \"null\"\n    else\n        os.raise(\"unknown type: %s\", kind)\n    end\n    return table.concat(s)\nend\n\nfunction json._pure_parse(str, pos, end_delim)\n    pos = pos or 1\n    if pos > #str then\n        os.raise(\"reached unexpected end of input.\")\n    end\n    -- skip whitespace.\n    local pos = pos + #str:match('^%s*', pos)\n    local first = str:sub(pos, pos)\n    if first == '{' then\n        local obj, key, delim_found = {}, true, true\n        pos = pos + 1\n        while true do\n            key, pos = json._pure_parse(str, pos, '}')\n            if key == nil then\n                return obj, pos\n            end\n            if not delim_found then\n                os.raise(\"comma missing between object items.\")\n            end\n            pos = json._pure_skip_delim(str, pos, ':', true)  -- true -> error if missing.\n            obj[key], pos = json._pure_parse(str, pos)\n            pos, delim_found = json._pure_skip_delim(str, pos, ',')\n        end\n    elseif first == '[' then\n        local arr, val, delim_found = {}, true, true\n        json.mark_as_array(arr)\n        pos = pos + 1\n        while true do\n            val, pos = json._pure_parse(str, pos, ']')\n            if val == nil then\n                return arr, pos\n            end\n            if not delim_found then\n                os.raise(\"comma missing between array items.\")\n            end\n            arr[#arr + 1] = val\n            pos, delim_found = json._pure_skip_delim(str, pos, ',')\n        end\n    elseif first == '\"' then\n        return json._pure_parse_str_val(str, pos + 1)\n    elseif first == '-' or first:match(\"%d\") then\n        return json._pure_parse_num_val(str, pos)\n    elseif first == end_delim then\n        -- end of an object or array.\n        return nil, pos + 1\n    else\n        local literals = {[\"true\"] = true, [\"false\"] = false, [\"null\"] = json.purenull}\n        for lit_str, lit_val in pairs(literals) do\n            local lit_end = pos + #lit_str - 1\n            if str:sub(pos, lit_end) == lit_str then\n                return lit_val, lit_end + 1\n            end\n        end\n        local pos_info_str = \"position \" .. pos .. \": \" .. str:sub(pos, pos + 10)\n        os.raise(\"invalid json syntax starting at \" .. pos_info_str)\n    end\nend\n\n-- decode json string using pure lua\nfunction json._pure_decode(jsonstr, opt)\n    return json._pure_parse(jsonstr)\nend\n\n-- encode json string using pua lua\nfunction json._pure_encode(luatable, opt)\n    return json._pure_stringify(luatable, 0, false, opt)\nend\n\n-- support empty array\n-- @see https://github.com/mpx/lua-cjson/issues/11\nfunction json.mark_as_array(luatable)\n    local mt = getmetatable(luatable) or {}\n    mt.__is_cjson_array = true\n    return setmetatable(luatable, mt)\nend\n\n-- is marked as array?\nfunction json.is_marked_as_array(luatable)\n    local mt = getmetatable(luatable)\n    return mt and mt.__is_cjson_array\nend\n\n-- decode json string to the lua table\n--\n-- @param jsonstr       the json string\n-- @param opt           the options\n--\n-- @return              the lua table\n--\nfunction json.decode(jsonstr, opt)\n    local decode = cjson and cjson.decode or json._pure_decode\n    if opt and opt.pure then\n        decode = json._pure_decode\n    end\n    local ok, luatable_or_errors = utils.trycall(decode, nil, jsonstr)\n    if not ok then\n        return nil, string.format(\"decode json failed, %s\", luatable_or_errors)\n    end\n    return luatable_or_errors\nend\n\n-- encode lua table to the json string\n--\n-- @param luatable      the lua table\n-- @param opt           the options\n--\n-- @return              the json string\n--\nfunction json.encode(luatable, opt)\n    local use_pure = not cjson or (opt and (opt.pure or opt.pretty))\n    local encode = use_pure and json._pure_encode or cjson.encode\n    local ok, jsonstr_or_errors\n    if use_pure then\n        ok, jsonstr_or_errors = utils.trycall(encode, nil, luatable, opt)\n    else\n        ok, jsonstr_or_errors = utils.trycall(encode, nil, luatable)\n    end\n    if not ok then\n        return nil, string.format(\"encode json failed, %s\", jsonstr_or_errors)\n    end\n    return jsonstr_or_errors\nend\n\n-- load json file to the lua table\n--\n-- @param filepath      the json file path\n-- @param opt           the options\n--                      - encoding for io/file, e.g. utf8, utf16, utf16le, utf16be ..\n--                      - continuation for io/read (concat string with the given continuation characters)\n--\n-- @return              the lua table\n--\nfunction json.loadfile(filepath, opt)\n    local filedata, errors = io.readfile(filepath, opt)\n    if not filedata then\n        return nil, errors\n    end\n    return json.decode(filedata, opt)\nend\n\n-- save lua table to the json file\n--\n-- @param filepath      the json file path\n-- @param luatable      the lua table\n-- @param opt           the options\n--                      - encoding for io/file, e.g. utf8, utf16, utf16le, utf16be ..\n--\n-- @return              the json string\n--\nfunction json.savefile(filepath, luatable, opt)\n    local jsonstr, errors = json.encode(luatable, opt)\n    if not jsonstr then\n        return false, errors\n    end\n    return io.writefile(filepath, jsonstr, opt)\nend\n\n-- return module: json\nreturn json\n"
  },
  {
    "path": "xmake/core/base/libc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        libc.lua\n--\n\n-- define module: libc\nlocal libc = libc or {}\n\n-- save original interfaces\nlibc._malloc  = libc._malloc or libc.malloc\nlibc._free    = libc._free or libc.free\nlibc._memcpy  = libc._memcpy or libc.memcpy\nlibc._memmov  = libc._memmov or libc.memmov\nlibc._memset  = libc._memset or libc.memset\nlibc._strndup = libc._strndup or libc.strndup\nlibc._dataptr = libc._dataptr or libc.dataptr\nlibc._byteof  = libc._byteof or libc.byteof\nlibc._setbyte = libc._setbyte or libc.setbyte\n\n-- load modules\nlocal ffi = xmake._LUAJIT and require(\"ffi\")\n\n-- define ffi interfaces\nif ffi then\n    ffi.cdef[[\n        void* malloc(size_t size);\n        void  free(void* data);\n        void* memmove(void* dest, const void* src, size_t n);\n    ]]\nend\n\nfunction libc.malloc(size, opt)\n    if ffi then\n        if opt and opt.gc then\n            return ffi.gc(ffi.cast(\"unsigned char*\", ffi.C.malloc(size)), ffi.C.free)\n        else\n            return ffi.cast(\"unsigned char*\", ffi.C.malloc(size))\n        end\n    else\n        local data, errors = libc._malloc(size)\n        if not data then\n            os.raise(errors)\n        end\n        return data\n    end\nend\n\nfunction libc.free(data)\n    if ffi then\n        return ffi.C.free(data)\n    else\n        return libc._free(data)\n    end\nend\n\nfunction libc.memcpy(dst, src, size)\n    if ffi then\n        return ffi.copy(dst, src, size)\n    else\n        return libc._memcpy(dst, src, size)\n    end\nend\n\nfunction libc.memmov(dst, src, size)\n    if ffi then\n        return ffi.C.memmove(dst, src, size)\n    else\n        return libc._memmov(dst, src, size)\n    end\nend\n\nfunction libc.memset(data, ch, size)\n    if ffi then\n        return ffi.fill(data, size, ch)\n    else\n        libc._memset(data, ch, size)\n    end\nend\n\nfunction libc.strndup(s, n)\n    if ffi then\n        return ffi.string(s, n)\n    else\n        local s, errors = libc._strndup(s, n)\n        if not s then\n            os.raise(errors)\n        end\n        return s\n    end\nend\n\nfunction libc.byteof(data, offset)\n    if ffi then\n        return data[offset]\n    else\n        return libc._byteof(data, offset)\n    end\nend\n\nfunction libc.setbyte(data, offset, value)\n    if ffi then\n        data[offset] = value\n    else\n        return libc._setbyte(data, offset, value)\n    end\nend\n\nfunction libc.dataptr(data, opt)\n    opt = opt or {}\n    if ffi and opt.ffi ~= false then\n        if opt.gc then\n            return ffi.gc(ffi.cast(\"unsigned char*\", data), ffi.C.free)\n        else\n            return ffi.cast(\"unsigned char*\", data)\n        end\n    else\n        return type(data) == \"number\" and data or libc._dataptr(data)\n    end\nend\n\nfunction libc.ptraddr(data, opt)\n    opt = opt or {}\n    if ffi and opt.ffi ~= false then\n        return tonumber(ffi.cast('unsigned long long', data))\n    else\n        return data\n    end\nend\n\n-- return module: libc\nreturn libc\n"
  },
  {
    "path": "xmake/core/base/linuxos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linuxos.lua\n--\n\n-- define module: linuxos\nlocal linuxos = linuxos or {}\n\n-- load modules\nlocal os     = require(\"base/os\")\nlocal path   = require(\"base/path\")\nlocal semver = require(\"base/semver\")\n\n-- get lsb_release information\n--\n-- e.g.\n--\n-- Distributor ID:\tUbuntu\n-- Description:\tUbuntu 16.04.7 LTS\n-- Release:\t16.04\n-- Codename:\txenial\n--\nfunction linuxos._lsb_release()\n    local lsb_release = linuxos._LSB_RELEASE\n    if lsb_release == nil then\n        local ok, result = os.iorun(\"lsb_release -a\")\n        if ok then\n            lsb_release = result\n        end\n        if lsb_release then\n            lsb_release = lsb_release:trim():lower()\n        end\n        linuxos._LSB_RELEASE = lsb_release or false\n    end\n    return lsb_release or nil\nend\n\n-- get uname information\nfunction linuxos._uname_r()\n    local uname_r = linuxos._UNAME_R\n    if uname_r == nil then\n        local ok, result = os.iorun(\"uname -r\")\n        if ok then\n            uname_r = result\n        end\n        if uname_r then\n            uname_r = uname_r:trim():lower()\n        end\n        linuxos._UNAME_R = uname_r or false\n    end\n    return uname_r or nil\nend\n\n-- get system name\n--\n-- e.g.\n--  - ubuntu\n--  - debian\n--  - archlinux\n--  - rhel\n--  - centos\n--  - fedora\n--  - opensuse\n--  - ...\nfunction linuxos.name()\n    local name = linuxos._NAME\n    if name == nil then\n        -- get it from /etc/os-release first\n        if name == nil and os.isfile(\"/etc/os-release\") then\n            local os_release = io.readfile(\"/etc/os-release\")\n            if os_release then\n                os_release = os_release:trim():lower()\n                if os_release:find(\"arch linux\", 1, true) or os_release:find(\"archlinux\", 1, true) then\n                    name = \"archlinux\"\n                elseif os_release:find(\"centos linux\", 1, true) or os_release:find(\"centos\", 1, true) then\n                    name = \"centos\"\n                elseif os_release:find(\"fedora\", 1, true) then\n                    name = \"fedora\"\n                elseif os_release:find(\"uos\", 1, true) then\n                    name = \"uos\"\n                elseif os_release:find(\"deepin\", 1, true) then\n                    name = \"deepin\"\n                elseif os_release:find(\"linux mint\", 1, true) or os_release:find(\"linuxmint\", 1, true) then\n                    name = \"linuxmint\"\n                -- kylin contains keyword 'UBUNTU_CODENAME', so we check kylin before ubuntu\n                elseif os_release:find(\"kylin\", 1, true) then\n                    name = \"kylin\"\n                elseif os_release:find(\"ubuntu\", 1, true) then\n                    name = \"ubuntu\"\n                elseif os_release:find(\"debian\", 1, true) then\n                    name = \"debian\"\n                elseif os_release:find(\"gentoo linux\", 1, true) then\n                    name = \"gentoo\"\n                elseif os_release:find(\"opensuse\", 1, true) then\n                    name = \"opensuse\"\n                elseif os_release:find(\"manjaro\", 1, true) then\n                    name = \"manjaro\"\n                elseif os_release:find(\"nixos\", 1, true) then\n                    name = \"nixos\"\n                elseif os_release:find(\"alpine\", 1, true) then\n                    name = \"alpine\"\n                end\n            end\n        end\n\n        -- get it from lsb release\n        if name == nil then\n            local lsb_release = linuxos._lsb_release()\n            if lsb_release and lsb_release:find(\"ubuntu\", 1, true) then\n                name = \"ubuntu\"\n            end\n        end\n\n        -- is archlinux?\n        if name == nil and os.isfile(\"/etc/arch-release\") then\n            name = \"archlinux\"\n        end\n\n        -- unknown\n        name = name or \"unknown\"\n        linuxos._NAME = name\n    end\n    return name\nend\n\n-- get system version\nfunction linuxos.version()\n    local version = linuxos._VERSION\n    if version == nil then\n\n        -- get it from /etc/os-release first\n        if version == nil and os.isfile(\"/etc/os-release\") then\n            local os_release = io.readfile(\"/etc/os-release\")\n            if os_release then\n                os_release = os_release:trim():lower():split(\"\\n\")\n                for _, line in ipairs(os_release) do\n                    -- ubuntu: VERSION=\"16.04.7 LTS (Xenial Xerus)\"\n                    -- fedora: VERSION=\"32 (Container Image)\"\n                    -- debian: VERSION=\"9 (stretch)\"\n                    -- kylin : VERSION=\"V10(kylin)\"\n                    if line:find(\"version=\") then\n                        line = line:sub(9)\n                        version = semver.match(line)\n                        if not version then\n                            version = line:match(\"\\\"(%d+)%s+.*\\\"\")\n                            if version then\n                                version = semver.new(version .. \".0\")\n                            end\n                        end\n                        -- is kylin?\n                        if not version and line:find(\"kylin\", 1, true) then\n                            version = line:match(\"\\\"v(%d+)%(kylin%)\\\"\")\n                            if version then\n                                version = semver.new(version .. \".0\")\n                            end\n                        end\n                        if version then\n                            break\n                        end\n                    end\n                end\n            end\n        end\n\n        -- get it from lsb release\n        if version == nil then\n            local lsb_release = linuxos._lsb_release()\n            if lsb_release and lsb_release:find(\"ubuntu\", 1, true) then\n                for _, line in ipairs(lsb_release:split(\"\\n\")) do\n                    -- release:\t16.04\n                    if line:find(\"release:\") then\n                        version = semver.match(line, 9)\n                        if version then\n                            break\n                        end\n                    end\n                end\n            end\n        end\n        linuxos._VERSION = version\n    end\n    return version\nend\n\n-- get linux kernel version\nfunction linuxos.kernelver()\n    local version = linuxos._KERNELVER\n    if version == nil then\n        if version == nil then\n            local uname_r = linuxos._uname_r()\n            if uname_r then\n                version = semver.match(uname_r)\n            end\n        end\n        linuxos._KERNELVER = version\n    end\n    return version\nend\n\n-- return module: linuxos\nreturn linuxos\n"
  },
  {
    "path": "xmake/core/base/list.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        list.lua\n--\n\n-- load modules\nlocal object = require(\"base/object\")\n\n-- define module\nlocal list = list or object { _init = {\"_length\"} } {0}\n\n-- clear list\nfunction list:clear()\n    self._length = 0\n    self._first  = nil\n    self._last   = nil\nend\n\n-- insert item after the given item\nfunction list:insert(t, after)\n    if not after then\n        return self:insert_last(t)\n    end\n    assert(t ~= after)\n    if after._next then\n        after._next._prev = t\n        t._next = after._next\n    else\n        self._last = t\n    end\n    t._prev = after\n    after._next = t\n    self._length = self._length + 1\nend\n\n-- insert the first item in head\nfunction list:insert_first(t)\n    if self._first then\n        self._first._prev = t\n        t._next = self._first\n        self._first = t\n    else\n        self._first = t\n        self._last = t\n    end\n    self._length = self._length + 1\nend\n\n-- insert the last item in tail\nfunction list:insert_last(t)\n    if self._last then\n        self._last._next = t\n        t._prev = self._last\n        self._last = t\n    else\n        self._first = t\n        self._last = t\n    end\n    self._length = self._length + 1\nend\n\n-- remove item\nfunction list:remove(t)\n    if t._next then\n        if t._prev then\n            t._next._prev = t._prev\n            t._prev._next = t._next\n        else\n            assert(t == self._first)\n            t._next._prev = nil\n            self._first = t._next\n        end\n    elseif t._prev then\n        assert(t == self._last)\n        t._prev._next = nil\n        self._last = t._prev\n    else\n        assert(t == self._first and t == self._last)\n        self._first = nil\n        self._last = nil\n    end\n    t._next = nil\n    t._prev = nil\n    self._length = self._length - 1\n    return t\nend\n\n-- remove the first item\nfunction list:remove_first()\n    if not self._first then\n        return\n    end\n    local t = self._first\n    if t._next then\n        t._next._prev = nil\n        self._first = t._next\n        t._next = nil\n    else\n        self._first = nil\n        self._last = nil\n    end\n    self._length = self._length - 1\n    return t\nend\n\n-- remove last item\nfunction list:remove_last()\n    if not self._last then\n        return\n    end\n    local t = self._last\n    if t._prev then\n        t._prev._next = nil\n        self._last = t._prev\n        t._prev = nil\n    else\n        self._first = nil\n        self._last = nil\n    end\n    self._length = self._length - 1\n    return t\nend\n\n-- push item to tail\nfunction list:push(t)\n    self:insert_last(t)\nend\n\n-- pop item from tail\nfunction list:pop()\n    self:remove_last()\nend\n\n-- shift item: 1 2 3 <- 2 3\nfunction list:shift()\n    self:remove_first()\nend\n\n-- unshift item: 1 2 -> t 1 2\nfunction list:unshift(t)\n    self:insert_first(t)\nend\n\n-- get first item\nfunction list:first()\n    return self._first\nend\n\n-- get last item\nfunction list:last()\n    return self._last\nend\n\n-- get next item\nfunction list:next(last)\n    if last then\n        return last._next\n    else\n        return self._first\n    end\nend\n\n-- get the previous item\nfunction list:prev(last)\n    if last then\n        return last._prev\n    else\n        return self._last\n    end\nend\n\n-- get list size\nfunction list:size()\n    return self._length\nend\n\n-- is empty?\nfunction list:empty()\n    return self:size() == 0\nend\n\n-- get items\n--\n-- e.g.\n--\n-- for item in list:items() do\n--     print(item)\n-- end\n--\nfunction list:items()\n    local iter = function (list, item)\n        return list:next(item)\n    end\n    return iter, self, nil\nend\n\n-- get reverse items\nfunction list:ritems()\n    local iter = function (list, item)\n        return list:prev(item)\n    end\n    return iter, self, nil\nend\n\n-- new list\nfunction list.new()\n    return list()\nend\n\n-- return module: list\nreturn list\n"
  },
  {
    "path": "xmake/core/base/log.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--o\n-- @author      ruki\n-- @file        log.lua\n--\n\n-- define module: log\nlocal log = log or {}\n\n-- get the log file\nfunction log:file()\n\n    -- disable?\n    if self._ENABLE ~= nil and not self._ENABLE then\n        return\n    end\n\n    -- get the output file\n    if self._FILE == nil then\n        local outputfile = self:outputfile()\n        if outputfile then\n\n            -- get directory\n            local i = outputfile:lastof(\"[/\\\\]\")\n            if i then\n                if i > 1 then i = i - 1 end\n                dir = outputfile:sub(1, i)\n            else\n                dir = \".\"\n            end\n\n            -- ensure the directory\n            if not os.isdir(dir) then\n                os.mkdir(dir)\n            end\n\n            -- open the log file\n            self._FILE = io.open(outputfile, 'w+')\n        end\n        self._FILE = self._FILE or false\n    end\n    return self._FILE\nend\n\n-- get the output file\nfunction log:outputfile()\n    if self._LOGFILE == nil then\n        self._LOGFILE = os.getenv(\"XMAKE_LOGFILE\") or false\n    end\n    return self._LOGFILE\nend\n\n-- clear log\nfunction log:clear(state)\n    if os.isfile(self:outputfile()) then\n        io.writefile(self:outputfile(), \"\")\n    end\nend\n\n-- enable log\nfunction log:enable(state)\n    self._ENABLE = state\nend\n\n-- flush log to file\nfunction log:flush()\n    local file = self:file()\n    if file then\n        file:flush()\n    end\nend\n\n-- close the log file\nfunction log:close()\n    local file = self:file()\n    if file then\n        file:close()\n    end\nend\n\n-- print log to the log file\nfunction log:print(...)\n    local file = self:file()\n    if file then\n        file:write(string.format(...) .. \"\\n\")\n    end\nend\n\n-- print variables to the log file\nfunction log:printv(...)\n    local file = self:file()\n    if file then\n        local values = {...}\n        for i, v in ipairs(values) do\n            -- dump basic type\n            if type(v) == \"string\" or type(v) == \"boolean\" or type(v) == \"number\" then\n                file:write(tostring(v))\n            else\n                file:write(\"<\" .. tostring(v) .. \">\")\n            end\n            if i ~= #values then\n                file:write(\" \")\n            end\n        end\n        file:write('\\n')\n    end\nend\n\n-- printf log to the log file\nfunction log:printf(...)\n    local file = self:file()\n    if file then\n        file:write(string.format(...))\n    end\nend\n\n-- write log the log file\nfunction log:write(...)\n    local file = self:file()\n    if file then\n        file:write(...)\n    end\nend\n\n-- return module: log\nreturn log\n"
  },
  {
    "path": "xmake/core/base/macos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        macos.lua\n--\n\n-- define module: macos\nlocal macos = macos or {}\n\n-- load modules\nlocal os     = require(\"base/os\")\nlocal semver = require(\"base/semver\")\n\n-- get system version\nfunction macos.version()\n\n    -- get it from cache first\n    if macos._VERSION ~= nil then\n        return macos._VERSION\n    end\n\n    -- get mac version\n    local macver = nil\n    local ok, verstr = os.iorun(\"sw_vers -productVersion\")\n    if ok and verstr then\n        macver = semver.new(verstr:trim())\n    end\n    macos._VERSION = macver or false\n    return macver\nend\n\n-- return module: macos\nreturn macos\n"
  },
  {
    "path": "xmake/core/base/math.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        math.lua\n--\n\n-- define module\nlocal math = math or {}\n\n-- init constants\nmath.nan   = 0/0 -- use 0/0 instead of math.log(-1) for better cross-platform compatibility (e.g., Solaris)\nmath.e     = math.exp(1)\nmath.inf   = 1/0 -- @see http://lua-users.org/wiki/InfAndNanComparisons\n\n-- check a number is int\n--\n-- @returns true for int, otherwise false\n--\nfunction math:isint()\n    assert(type(self) == \"number\", \"number expacted\")\n    return self == math.floor(self) and self ~= math.huge and self ~= -math.huge\nend\n\n-- check a number is inf or -inf\n--\n-- @returns 1 for inf,  -1 for -inf, otherwise false\n--\nfunction math:isinf()\n    assert(type(self) == \"number\", \"number expacted\")\n    if self == math.inf then\n        return 1\n    elseif self == -math.inf then\n        return -1\n    else\n        return false\n    end\nend\n\n-- check a number is nan\n--\n-- @returns true for nan, otherwise false\n--\nfunction math:isnan()\n    assert(type(self) == \"number\", \"number expacted\")\n    return self ~= self\nend\n\n\n-- return module\nreturn math\n"
  },
  {
    "path": "xmake/core/base/memory.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        memory.lua\n--\n\n-- define module\nlocal memory = memory or {}\n\n-- load modules\nlocal os = require(\"base/os\")\n\n-- get memory info\nfunction memory.info(name)\n    local meminfo = memory._MEMINFO\n    local memtime = memory._MEMTIME\n    if meminfo == nil or memtime == nil or os.time() - memtime > 10 then -- cache 10s\n        meminfo = os._meminfo()\n        if meminfo.totalsize and meminfo.availsize then\n            meminfo.usagerate = (meminfo.totalsize - meminfo.availsize) / meminfo.totalsize\n        else\n            meminfo.usagerate = 0\n        end\n        memory._MEMINFO = meminfo\n        memory._MEMTIME = os.time()\n    end\n    if name then\n        return meminfo[name]\n    else\n        return meminfo\n    end\nend\n\n-- return module\nreturn memory\n"
  },
  {
    "path": "xmake/core/base/object.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        object.lua\n--\n\n-- define module: object\nlocal object = object or {}\n\n-- taken from 'std' library: http://luaforge.net/projects/stdlib/\n-- and http://lua-cui.sourceforge.net/\n--\n-- local point = object { _init = {\"x\", \"y\"} }\n--\n-- local p1 = point {1, 2}\n--  > p1 {x = 1, y = 2}\n--\n\n-- permute some indices of a table\nlocal function permute (p, t)\n    local u = {}\n    for i, v in pairs (t) do\n        if p[i] ~= nil then\n            u[p[i]] = v\n        else\n            u[i] = v\n        end\n    end\n    return u\nend\n\n-- make a shallow copy of a table, including any\nlocal function clone (t)\n    local u = setmetatable ({}, getmetatable (t))\n    for i, v in pairs (t) do\n        u[i] = v\n    end\n    return u\nend\n\n-- merge two tables\n--\n-- If there are duplicate fields, u's will be used. The metatable of\n-- the returned table is that of t\n--\nlocal function merge (t, u)\n    local r = clone (t)\n    for i, v in pairs (u) do\n        r[i] = v\n    end\n    return r\nend\n\n-- root object\n--\n-- List of fields to be initialised by the\n-- constructor: assuming the default _clone, the\n-- numbered values in an object constructor are\n-- assigned to the fields given in _init\n--\nlocal object = { _init = {} }\nsetmetatable (object, object)\n\n-- object constructor\n--\n-- @param initial values for fields in\n--\n-- @return new object\n--\nfunction object:_clone (values)\n    local object = merge(self, permute(self._init, values or {}))\n    return setmetatable (object, object)\nend\n\n-- local x = object {}\nfunction object.__call (...)\n  return (...)._clone (...)\nend\n\n-- return module: object\nreturn object\n"
  },
  {
    "path": "xmake/core/base/option.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        option.lua\n--\n\n-- define module: option\nlocal option = {}\n\n-- load modules\nlocal cli       = require(\"base/cli\")\nlocal table     = require(\"base/table\")\nlocal tty       = require(\"base/tty\")\nlocal colors    = require(\"base/colors\")\nlocal text      = require(\"base/text\")\n\n-- translate the menu\nfunction option._translate(menu)\n    local submenus_all = {}\n    for k, submenu in pairs(menu) do\n        if type(submenu) == \"function\" then\n            local ok, _submenus_or_errors = pcall(submenu)\n            if ok and _submenus_or_errors then\n                for k, m in pairs(_submenus_or_errors) do\n                    submenus_all[k] = m\n                end\n            else\n                return false, (_submenus_or_errors or \"translate option menu failed!\")\n            end\n        else\n            submenus_all[k] = submenu\n        end\n    end\n    table.copy2(menu, submenus_all)\n\n    option._MENU = menu\n    return true\nend\n\n-- show menu in narrow mode?\nfunction option._modenarrow()\n    local width = os.getwinsize().width\n    return width > 0 and width < 60\nend\n\n-- get the top context\nfunction option._context()\n    local contexts = option._CONTEXTS\n    if contexts then\n        return contexts[#contexts]\n    end\nend\n\n-- save context\nfunction option.save(taskname)\n    option._CONTEXTS = option._CONTEXTS or {}\n    local context = {options = {}, defaults = {}, taskname = taskname}\n    if taskname then\n        context.defaults = option.defaults(taskname) or context.defaults\n    end\n    table.insert(option._CONTEXTS, context)\n    return context\nend\n\n-- restore context\nfunction option.restore()\n    if option._CONTEXTS then\n        table.remove(option._CONTEXTS)\n    end\nend\n\n-- the command line\nfunction option.cmdline()\n    if not xmake._ARGS then\n        xmake._ARGS = os.args(xmake._ARGV)\n    end\n    return \"xmake \" .. xmake._ARGS\nend\n\n-- init the option\nfunction option.init(menu)\n    -- translate menu\n    local ok, errors = option._translate(menu)\n    if not ok then\n        return false, errors\n    end\n\n    -- the main menu\n    local main = option.taskmenu(\"main\")\n    assert(main)\n\n    -- new top context\n    local context = option.save()\n    assert(context)\n\n    -- check command\n    if xmake._COMMAND then\n\n        -- find the current task and save it\n        for taskname, taskinfo in pairs(main.tasks) do\n            if taskname == xmake._COMMAND or taskinfo.shortname == xmake._COMMAND then\n                context.taskname = taskname\n                break\n            end\n        end\n\n        -- not found?\n        if not context.taskname or not menu[context.taskname] then\n            option.show_main()\n            return false, \"invalid task: \" .. xmake._COMMAND\n        end\n    end\n\n    local options = table.wrap(option.taskmenu().options)\n\n    -- parse remain parts\n    local results, err = option.parse(xmake._COMMAND_ARGV, options, { populate_defaults = false })\n    if not results then\n        option.show_menu(context.taskname)\n        return false, err\n    end\n\n    -- finish parsing\n    context.options = results\n\n    -- init the default value\n    option.populate_defaults(options, context.defaults)\n    return true\nend\n\n-- parse arguments with the given options\nfunction option.parse(argv, options, opt)\n    assert(argv and options)\n    opt = opt or { populate_defaults = true }\n\n    -- parse arguments\n    local results   = {}\n    local flags = {}\n    for _, o in ipairs(options) do\n\n        -- get mode and name\n        local mode = o[3]\n        local name = o[2]\n        assert(o and ((mode ~= \"v\" and mode ~= \"vs\") or name))\n\n        -- fill short flags\n        if o[3] == \"k\" and o[1] then\n            table.insert(flags, o[1])\n        end\n    end\n\n    -- run parser\n    local pargs = cli.parsev(argv, flags)\n\n    -- save parse results\n    for i, arg in ipairs(pargs) do\n        if arg.type == \"option\" or arg.type == \"flag\" then\n\n            -- find option or flag\n            local name_idx = arg.short and 1 or 2\n            local match_opt = nil\n            for _, o in pairs(options) do\n                local name = o[name_idx]\n                if name == arg.key then\n                    match_opt = o\n                    break\n                end\n            end\n\n            -- save option\n            if match_opt and ((arg.type == \"option\" and match_opt[3] ~= \"k\") or (arg.type == \"flag\" and match_opt[3] == \"k\")) then\n                results[match_opt[2] or match_opt[1]] = option.boolean(arg.value)\n            else\n                if opt.allow_unknown then\n                    results[arg.key] = option.boolean(arg.value)\n                else\n                    return nil, string.format(\"Invalid %s: %s\", arg.type, arg)\n                end\n            end\n\n        elseif arg.type == \"arg\" then\n\n            -- find a value option with name\n            local match_opt = nil\n            for _, o in ipairs(options) do\n\n                -- get mode and name\n                local mode = o[3]\n                local name = o[2]\n\n                -- is value and with name?\n                if mode == \"v\" and name and not results[name] then\n                    match_opt = o\n                    break\n                -- is values and with name?\n                elseif mode == \"vs\" and name then\n                    match_opt = o\n                    break\n                end\n            end\n\n            -- ok? save this value with name opt[2]\n            if match_opt then\n\n                -- get mode and name\n                local mode = match_opt[3]\n                local name = match_opt[2]\n\n                -- save value\n                if mode == \"v\" then\n                    results[name] = arg.value\n                elseif mode == \"vs\" then\n                    -- the option\n                    local o = results[name]\n                    if not o then\n                        results[name] = {}\n                        o = results[name]\n                    end\n\n                    -- append value\n                    table.insert(o, arg.value)\n                end\n            else\n\n                -- failed\n                if opt.allow_unknown then\n                    if arg.key then\n                        results[arg.key] = arg.value\n                    else\n                        -- the option\n                        local o = results[\"$ARGS\"]\n                        if not o then\n                            results[\"$ARGS\"] = {}\n                            o = results[\"$ARGS\"]\n                        end\n\n                        -- append value\n                        table.insert(o, arg.value)\n                    end\n                else\n                    return nil, \"invalid argument: \" .. arg.value\n                end\n            end\n        end\n    end\n\n    -- init the default value\n    if opt.populate_defaults then\n        option.populate_defaults(options, results)\n    end\n    return results\nend\n\n-- fill defined with option's default value, in place\nfunction option.populate_defaults(options, defined)\n    assert(options and defined)\n\n    -- populate the default value\n    for _, o in ipairs(options) do\n\n        -- the long name\n        local longname = o[2]\n\n        -- key=value?\n        if o[3] == \"kv\" then\n\n            local shortname = o[1]\n            -- the key\n            local key = longname or shortname\n            assert(key)\n\n            -- move value to key if needed\n            if shortname and defined[shortname] ~= nil then\n                defined[key], defined[shortname] = defined[shortname], nil\n            end\n\n            -- save the default value\n            if defined[key] == nil then\n                defined[key] = o[4]\n            end\n\n        -- value with name?\n        elseif o[3] == \"v\" and longname then\n\n            -- save the default value\n            if defined[longname] == nil then\n                defined[longname] = o[4]\n            end\n        end\n    end\nend\n\n\n-- get the current task name\nfunction option.taskname()\n    return option._context().taskname\nend\n\n-- get the task menu\nfunction option.taskmenu(task)\n    assert(option._MENU)\n\n    task = task or option.taskname() or \"main\"\n    local taskmenu = option._MENU[task]\n    if type(taskmenu) == \"function\" then\n        taskmenu = taskmenu()\n        option._MENU[task] = taskmenu\n    end\n    return taskmenu\nend\n\n-- get the given option value for the current task\nfunction option.get(name)\n    local options = option.options()\n    if options then\n        local value = options[name]\n        if value == nil then\n            value = option.default(name)\n        end\n        return value\n    end\nend\n\n-- set the given option for the current task\nfunction option.set(name, value)\n    -- cannot be the first context for menu\n    assert(#option._CONTEXTS > 1)\n\n    -- the options\n    local options = option.options()\n    assert(options)\n\n    -- set it\n    options[name] = value\nend\n\n-- get the boolean value\nfunction option.boolean(value)\n    if type(value) == \"string\" then\n        local v = value:lower()\n        if v == \"true\" or v == \"yes\" or v == \"y\" then value = true\n        elseif v == \"false\" or v == \"no\" or v == \"n\" then value = false\n        end\n    end\n    return value\nend\n\n-- get the given default option value for the current task\nfunction option.default(name)\n    assert(name)\n\n    local defaults = option.defaults()\n    assert(defaults)\n\n    return defaults[name]\nend\n\n-- get the current options\nfunction option.options()\n    local context = option._context()\n    if context then\n        return context.options\n    end\nend\n\n-- get all default options for the current or given task\nfunction option.defaults(task)\n\n    -- get the default options for the current task\n    if task == nil then\n        return option._context().defaults\n    end\n\n    -- the task menu\n    local taskmenu = option.taskmenu(task)\n\n    -- get the default options for the given task\n    local defaults = {}\n    if taskmenu then\n        option.populate_defaults(taskmenu.options, defaults)\n    end\n    return defaults\nend\n\n-- show update tips\nfunction option.show_update_tips()\n\n    -- show latest version\n    local versionfile = path.join(os.tmpdir(), \"latest_version\")\n    if os.isfile(versionfile) then\n        local versioninfo = io.load(versionfile)\n        if versioninfo and versioninfo.version and semver.compare(versioninfo.version, xmake._VERSION_SHORT) > 0 then\n            local updatetips = nil\n            if os.host() == \"windows\" then\n                updatetips = string.format([[\n   ==========================================================================\n  | ${bright yellow}A new version of xmake is available!${clear}                                     |\n  |                                                                          |\n  | To update to the latest version ${bright}%s${clear}, run \"xmake update\".              |\n   ==========================================================================\n]], versioninfo.version)\n            else\n                updatetips = string.format([[\n  ╔════════════════════════════════════════════════════════════════════════════╗\n  ║ ${bright yellow}A new version of xmake is available!${clear}                                       ║\n  ║                                                                            ║\n  ║ To update to the latest version ${bright}%s${clear}, run \"xmake update\".                ║\n  ╚════════════════════════════════════════════════════════════════════════════╝\n]], versioninfo.version)\n            end\n            io.print(colors.translate(updatetips))\n        end\n    end\nend\n\n-- show logo\nfunction option.show_logo(logo, opt)\n\n    -- define logo\n    logo = logo or [[\n                         _\n    __  ___ __  __  __ _| | ______\n    \\ \\/ / |  \\/  |/ _  | |/ / __ \\\n     >  <  | \\__/ | /_| |   <  ___/\n    /_/\\_\\_|_|  |_|\\__ \\|_|\\_\\____|\n\n                         by ruki, xmake.io\n]]\n\n    -- make rainbow for logo\n    opt = opt or {}\n    if tty.has_color24() or tty.has_color256() then\n        local lines = {}\n        local seed  = opt.seed or 236\n        for _, line in ipairs(logo:split(\"\\n\")) do\n            local i = 0\n            local line2 = \"\"\n            line:gsub(\".\", function (c)\n                local code = tty.has_color24() and colors.rainbow24(i, seed) or colors.rainbow256(i, seed)\n                line2 = string.format(\"%s${bright %s}%s\", line2, code, c)\n                i = i + 1\n            end)\n            table.insert(lines, line2)\n        end\n        logo = table.concat(lines, \"\\n\")\n    end\n\n    -- show logo\n    io.print(colors.translate(logo))\n\n    -- define footer\n    local footer = [[\n    ${point_right}  ${bright}Manual${clear}: ${underline}https://xmake.io/guide/quick-start${clear}\n    ${pray}  ${bright}Donate${clear}: ${underline}https://xmake.io/about/sponsor${clear}\n]]\n\n    -- show footer\n    io.print(colors.translate(footer))\n\n    -- show update tips\n    option.show_update_tips()\nend\n\n-- show the menu\nfunction option.show_menu(task)\n\n    -- no task? print main menu\n    if not task then\n        option.show_main()\n        return\n    end\n\n    -- the menu\n    local menu = option._MENU\n    assert(menu)\n\n    -- the task menu\n    local taskmenu = option.taskmenu(task)\n    assert(taskmenu)\n\n    -- print title\n    if menu.title then\n        io.print(colors.translate(menu.title))\n    end\n\n    -- print copyright\n    if menu.copyright then\n        io.print(colors.translate(menu.copyright))\n    end\n\n    -- show logo\n    option.show_logo()\n\n    -- print usage\n    if taskmenu.usage then\n        io.print(\"\")\n        io.print(colors.translate(\"${bright}Usage: $${default color.menu.usage}\" .. taskmenu.usage .. \"${clear}\"))\n    end\n\n    -- print description\n    if taskmenu.description then\n        io.print(\"\")\n        io.print(colors.translate(taskmenu.description))\n    end\n\n    -- print options\n    if taskmenu.options then\n        option.show_options(taskmenu.options, task)\n    end\nend\n\n-- show the main menu\nfunction option.show_main()\n\n    -- the menu\n    local menu = option._MENU\n    assert(menu)\n\n    -- the main menu\n    local main = option.taskmenu(\"main\")\n    assert(main)\n\n    -- print title\n    if menu.title then\n        io.print(colors.translate(menu.title))\n    end\n\n    -- print copyright\n    if menu.copyright then\n        io.print(colors.translate(menu.copyright))\n    end\n\n    -- show logo\n    option.show_logo()\n\n    -- print usage\n    if main.usage then\n        io.print(\"\")\n        io.print(colors.translate(\"${bright}Usage: $${default color.menu.usage}\" .. main.usage .. \"${clear}\"))\n    end\n\n    -- print description\n    if main.description then\n        io.print(\"\")\n        io.print(colors.translate(main.description))\n    end\n\n    -- print tasks\n    if main.tasks then\n\n        local narrow = option._modenarrow()\n\n        -- make task categories\n        local categories = {}\n        for taskname, taskinfo in pairs(main.tasks) do\n\n            -- the category name\n            local categoryname = taskinfo.category or \"task\"\n            if categoryname == \"main\" then\n                categoryname = \"action\"\n            end\n\n            -- the category task\n            local category = categories[categoryname] or { name = categoryname, tasks = {} }\n            categories[categoryname] = category\n\n            -- add task to the category\n            category.tasks[taskname] = taskinfo\n        end\n\n        -- sort categories\n        categories = table.values(categories)\n        table.sort(categories, function (a, b)\n            if a.name == \"action\" then\n                return true\n            end\n            return a.name < b.name\n        end)\n\n        -- dump tasks by categories\n        local tablecontent = {}\n        for _, category in ipairs(categories) do\n\n            -- the category name and task\n            assert(category.name and category.tasks)\n\n            -- print category name\n            table.insert(tablecontent, {})\n            table.insert(tablecontent, {{string.format(\"%s%ss: \", string.sub(category.name, 1, 1):upper(), string.sub(category.name, 2)), style=\"${reset bright}\"}})\n\n            -- print tasks\n            for taskname, taskinfo in table.orderpairs(category.tasks) do\n\n                -- init the task line\n                local taskline = string.format(narrow and \"  %s%s\" or \"    %s%s\",\n                    taskinfo.shortname and (taskinfo.shortname .. \", \") or \"   \",\n                    taskname)\n                table.insert(tablecontent, {taskline, colors.translate(taskinfo.description or \"\")})\n            end\n        end\n\n        -- set table styles\n        tablecontent.style = {\"${color.menu.main.task.name}\"}\n        tablecontent.width = {nil, \"auto\"}\n        tablecontent.sep = narrow and \"  \" or \"    \"\n\n        -- print table\n        io.write(text.table(tablecontent))\n    end\n\n    -- print options\n    if main.options then\n        option.show_options(main.options, \"build\")\n    end\nend\n\n-- show the options menu\nfunction option.show_options(options, taskname)\n    assert(options)\n\n    -- remove repeat empty lines\n    local is_action = false\n    local emptyline_count = 0\n    local printed_options = {}\n    for _, opt in ipairs(options) do\n        if opt.category and printed_options[#printed_options].category then\n            table.remove(printed_options)\n        end\n        table.insert(printed_options, opt)\n        if opt.category and opt.category == \"action\" then\n            is_action = true\n        end\n    end\n    if printed_options[#printed_options].category then\n        table.remove(printed_options)\n    end\n\n    -- narrow mode?\n    local narrow = option._modenarrow()\n\n    -- print header\n    local tablecontent = {}\n    table.insert(tablecontent, {})\n    if is_action then\n        table.insert(tablecontent, {{\"Common options:\", style=\"${reset bright}\"}})\n    else\n        table.insert(tablecontent, {{\"Options:\", style=\"${reset bright}\"}})\n    end\n\n    -- print options\n    local categories = {}\n    for _, opt in ipairs(printed_options) do\n        if opt.category and opt.category == \"action\" then\n            -- the following options are belong action? show command section\n            --\n            -- @see core/base/task.lua: translate menu\n            --\n            table.insert(tablecontent, {})\n            table.insert(tablecontent, {{\"Command options (\" .. taskname .. \"):\", style=\"${reset bright}\"}})\n        elseif opt.category and opt.category ~= \".\" then\n            local category_root = opt.category:split(\"/\")[1]\n            if not categories[category_root] then\n                table.insert(tablecontent, {})\n                table.insert(tablecontent, {{\"Command options (\" .. opt.category .. \"):\", style=\"${reset bright}\"}})\n                categories[category_root] = true\n            end\n        elseif opt[3] == nil then\n            table.insert(tablecontent, {})\n        else\n\n            -- append the shortname\n            local shortname = opt[1]\n            local name      = opt[2]\n            local mode      = opt[3]\n            local default   = opt[4]\n\n            local title1, title2\n            local kvplaceholder = mode == \"kv\" and ((type(default) == \"boolean\") and \"[y|n]\" or(name and name:upper() or \"XXX\"))\n            if shortname then\n                if mode == \"kv\" then\n                    title1 = \"-\" .. shortname .. \" \" .. kvplaceholder\n                else\n                    title1 = \"-\" .. shortname\n                end\n            end\n\n            -- append the name\n            if name then\n                local leading = mode:startswith(\"k\") and \"--\" or \"  \"\n                local kv\n                if mode == \"k\" then\n                    kv = name\n                elseif mode == \"kv\" then\n                    kv = name .. \"=\" .. kvplaceholder\n                elseif mode == \"vs\" then\n                    kv = name .. \" ...\"\n                else\n                    kv = name\n                end\n                title2 = leading .. kv\n            elseif mode == \"v\" or mode == \"vs\" then\n                title2 = \"    ...\"\n            end\n\n            -- get description\n            local optdespn = table.maxn(opt)\n            local description = table.move(opt, 5, optdespn, 1, table.new(optdespn - 5 + 1, 0))\n            if #description == 0 then\n                description[1] = \"\"\n            end\n\n            -- transform description\n            local desp_strs = table.new(#description, 0)\n            for _, v in ipairs(description) do\n                if type(v) == \"function\" then\n                    v = v()\n                end\n                if type(v) == \"string\" then\n                    table.insert(desp_strs, colors.translate(v))\n                elseif type(v) == \"table\" then\n                    table.move(v, 1, #v, #desp_strs + 1, desp_strs)\n                end\n            end\n\n            -- append the default value\n            if default then\n                local defaultval = tostring(default)\n                if type(default) == \"boolean\" then\n                    defaultval = default and \"y\" or \"n\"\n                end\n                local def_desp = colors.translate(string.format(\" (default: ${bright}%s${clear})\", defaultval))\n                desp_strs[1] = desp_strs[1] .. def_desp\n            end\n\n            -- append values\n            local values = opt.values\n            if type(values) == \"function\" then\n                values = values(false, {helpmenu = true})\n            end\n            if values then\n                for _, value in ipairs(table.wrap(values)) do\n                    table.insert(desp_strs, \"    - \" .. tostring(value))\n                end\n            end\n\n            -- insert row\n            if narrow then\n                if title1 then\n                    table.insert(tablecontent, {{\"  \" .. title1, \"   \" .. title2 }, desp_strs})\n                else\n                    table.insert(tablecontent, {{\"  \" .. title2 }, desp_strs})\n                end\n            else\n                if title1 then\n                    table.insert(tablecontent, {\"    \" .. title1 .. \", \" .. title2 , desp_strs})\n                else\n                    table.insert(tablecontent, {\"        \" .. title2 , desp_strs})\n                end\n            end\n        end\n    end\n\n    -- set table styles\n    tablecontent.style = {\"${color.menu.option.name}\"}\n    tablecontent.width = {nil, \"auto\"}\n    tablecontent.sep = narrow and \"  \" or \"    \"\n\n    -- print table\n    io.write(text.table(tablecontent))\nend\n\n-- return module: option\nreturn option\n"
  },
  {
    "path": "xmake/core/base/os.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        os.lua\n--\n\n-- define module\nlocal os = os or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal log       = require(\"base/log\")\nlocal path      = require(\"base/path\")\nlocal table     = require(\"base/table\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal process   = require(\"base/process\")\n\n-- save original interfaces\nos._uid      = os._uid or os.uid\nos._gid      = os._gid or os.gid\nos._getpid   = os._getpid or os.getpid\nos._exit     = os._exit or os.exit\nos._mkdir    = os._mkdir or os.mkdir\nos._rmdir    = os._rmdir or os.rmdir\nos._touch    = os._touch or os.touch\nos._tmpdir   = os._tmpdir or os.tmpdir\nos._curdir   = os._curdir or os.curdir\nos._fscase   = os._fscase or os.fscase\nos._setenv   = os._setenv or os.setenv\nos._getenvs  = os._getenvs or os.getenvs\nos._cpuinfo  = os._cpuinfo or os.cpuinfo\nos._meminfo  = os._meminfo or os.meminfo\nos._readlink = os._readlink or os.readlink\nos._access   = os._access or os.access\n\n-- syserror code\nos.SYSERR_UNKNOWN     = -1\nos.SYSERR_NONE        = 0\nos.SYSERR_NOT_PERM    = 1\nos.SYSERR_NOT_FILEDIR = 2\nos.SYSERR_NOT_ACCESS  = 3\n\n-- get the async task\nfunction os._async_task()\n    local async_task = os._ASYNC_TASK\n    if async_task == nil then\n        async_task = require(\"base/private/async_task\")\n        os._ASYNC_TASK = async_task\n    end\n    return async_task\nend\n\n-- copy single file or directory\nfunction os._cp(src, dst, rootdir, opt)\n    opt = opt or {}\n    assert(src and dst)\n\n    -- reserve the source directory structure if opt.rootdir is given\n    if rootdir then\n        if not path.is_absolute(src) then\n            src = path.absolute(src)\n        end\n        if not src:startswith(rootdir) then\n            return false, string.format(\"cannot copy file %s to %s, invalid rootdir(%s)\", src, dst, rootdir)\n        end\n    end\n\n    -- is file or link?\n    local symlink = opt.symlink\n    local writeable = opt.writeable\n    local copy_if_different = opt.copy_if_different\n    if os.isfile(src) or (symlink and os.islink(src)) then\n\n        -- the destination is directory? append the filename\n        if os.isdir(dst) or path.islastsep(dst) then\n            if rootdir then\n                dst = path.join(dst, path.relative(src, rootdir))\n            else\n                dst = path.join(dst, path.filename(src))\n            end\n        end\n\n        -- copy or link file\n        if opt.force and os.isfile(dst) then\n            os.rmfile(dst)\n        end\n        if not os.cpfile(src, dst, symlink, writeable, copy_if_different) then\n            local errors = os.strerror()\n            if symlink and os.islink(src) then\n                local reallink = os.readlink(src)\n                return false, string.format(\"cannot link %s(%s) to %s, %s\", src, reallink, dst, errors)\n            else\n                return false, string.format(\"cannot copy file %s to %s, %s\", src, dst, errors)\n            end\n        end\n    -- is directory?\n    elseif os.isdir(src) then\n\n        -- the destination directory exists? append the filename\n        if os.isdir(dst) or path.islastsep(dst) then\n            if rootdir then\n                dst = path.join(dst, path.relative(src, rootdir))\n            else\n                dst = path.join(dst, path.filename(path.translate(src)))\n            end\n        end\n\n        -- copy directory\n        if not os.cpdir(src, dst, symlink, copy_if_different) then\n            return false, string.format(\"cannot copy directory %s to %s,  %s\", src, dst, os.strerror())\n        end\n    else\n        return false, string.format(\"cannot copy file %s, file not found!\", src)\n    end\n    return true\nend\n\n-- move single file or directory\nfunction os._mv(src, dst, opt)\n    opt = opt or {}\n    assert(src and dst)\n\n    if os.exists(src) then\n\n        -- the destination directory exists? append the filename\n        if os.isdir(dst) or path.islastsep(dst) then\n            dst = path.join(dst, path.filename(path.translate(src)))\n        end\n\n        -- move file or directory\n        if opt.force and os.isfile(dst) then\n            os.rmfile(dst)\n        end\n        if not os.rename(src, dst) then\n            return false, string.format(\"cannot move %s to %s %s\", src, dst, os.strerror())\n        end\n    else\n        return false, string.format(\"cannot move %s to %s, file %s not found!\", src, dst, os.strerror())\n    end\n    return true\nend\n\n-- remove single file or directory\nfunction os._rm(filedir)\n    assert(filedir)\n\n    -- is file or link?\n    if os.isfile(filedir) or os.islink(filedir) then\n        if not os.rmfile(filedir) then\n            return false, string.format(\"cannot remove file %s %s\", filedir, os.strerror())\n        end\n    -- is directory?\n    elseif os.isdir(filedir) then\n        if not os.rmdir(filedir) then\n            return false, string.format(\"cannot remove directory %s %s\", filedir, os.strerror())\n        end\n    end\n    return true\nend\n\n-- remove empty parent directories of this file path\nfunction os._rm_empty_parentdirs(filepath)\n    local parentdir = path.directory(filepath)\n    while parentdir and os.isdir(parentdir) and os.emptydir(parentdir) do\n        local ok, errors = os._rm(parentdir)\n        if not ok then\n            return false, errors\n        end\n        parentdir = path.directory(parentdir)\n    end\n    return true\nend\n\n-- get the ramdisk root directory\n-- https://github.com/xmake-io/xmake/issues/3408\nfunction os._ramdir()\n    local ramdir_root = os._ROOT_RAMDIR\n    if ramdir_root == nil then\n        ramdir_root = os.getenv(\"XMAKE_RAMDIR\")\n    end\n    if ramdir_root == nil then\n        ramdir_root = false\n        os._ROOT_RAMDIR = ramdir_root\n    end\n    return ramdir_root or nil\nend\n\n-- if tmpdir_root is a symbolic link, os.tmpdir() may return a path that differs\n-- from the path style returned by os.curdir() (e.g. on Haiku).\n--\n-- Using a consistent root path can avoid errors in relative path resolution.\n--\n-- e.g.\n-- tmpdir: /tmp/.xmake0/260217/ -> /boot/system/cache/tmp/.xmake0/260217\n-- curdir: /boot/system/cache/tmp/.xmake0/260217\nfunction os._resolve_tmpdir(tmpdir_root)\n    if os.islink(tmpdir_root) then\n        tmpdir_root = os.readlink(tmpdir_root) or tmpdir_root\n    end\n    return tmpdir_root\nend\n\n-- set on change environments callback for scheduler\nfunction os._sched_chenvs_set(envs)\n    os._SCHED_CHENVS = envs\nend\n\n-- set on change directory callback for scheduler\nfunction os._sched_chdir_set(chdir)\n    os._SCHED_CHDIR = chdir\nend\n\n-- notify the current directory have been changed\nfunction os._notify_curdir_changed()\n    os._CURDIR = nil\n    if os._SCHED_CHDIR then\n        os._SCHED_CHDIR(os.curdir())\n    end\nend\n\n-- notify envs have been changed\nfunction os._notify_envs_changed(envs)\n    if os._SCHED_CHENVS then\n        os._SCHED_CHENVS(envs)\n    end\nend\n\n-- the current host is belong to the given hosts?\nfunction os._is_host(host, ...)\n    if not host then\n        return false\n    end\n\n    -- exists this host? and escape '-'\n    for _, h in ipairs(table.join(...)) do\n        if h and type(h) == \"string\" and host:find(h:gsub(\"%-\", \"%%-\")) then\n            return true\n        end\n    end\nend\n\n-- the current platform is belong to the given architectures?\nfunction os._is_arch(arch, ...)\n    if not arch then\n        return false\n    end\n\n    -- exists this architecture? and escape '-'\n    for _, a in ipairs(table.join(...)) do\n        if a and type(a) == \"string\" and arch:find(\"^\" .. a:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- match wildcard files\nfunction os._match_wildcard_pathes(v)\n    if v:find(\"*\", 1, true) then\n        return (os.filedirs(v))\n    end\n    return v\nend\n\n-- split too long path environment variable for windows\n--\n-- @see https://github.com/xmake-io/xmake-repo/pull/489\n-- https://stackoverflow.com/questions/34491244/environment-variable-is-too-large-on-windows-10\n--\nfunction os._deduplicate_pathenv(value)\n    if value and #value > 4096 then\n        local itemset = {}\n        local results = {}\n        for _, item in ipairs(path.splitenv(value)) do\n            if not itemset[item] then\n                table.insert(results, item)\n                itemset[item] = true\n            end\n        end\n        if #results > 0 then\n            value = path.joinenv(results)\n        end\n    end\n    return value\nend\n\n-- trace process for profile(stuck,trace)?\nfunction os._is_tracing_process()\n    local is_tracing = os._IS_TRACING_PROCESS\n    if is_tracing == nil then\n        local profile = os.getenv(\"XMAKE_PROFILE\")\n        if profile then\n            profile = profile:trim()\n            if profile == \"trace\" or profile == \"stuck\" then\n                is_tracing = true\n            end\n        end\n        is_tracing = is_tracing or false\n        os._IS_TRACING_PROCESS = is_tracing\n    end\n    return is_tracing\nend\n\n-- profile process performance?\nfunction os._is_profiling_process_perf()\n    local is_profiling = os._IS_PROFILING_PROCESS_PERF\n    if is_profiling == nil then\n        local profile = os.getenv(\"XMAKE_PROFILE\")\n        if profile then\n            profile = profile:trim()\n            if profile == \"perf:process\" then\n                is_profiling = true\n            end\n        end\n        is_profiling = is_profiling or false\n        os._IS_PROFILING_PROCESS_PERF = is_profiling\n    end\n    return is_profiling\nend\n\n-- run all exit callback\nfunction os._run_exit_cbs(ok, errors)\n\n    -- show process performance reports\n    local profileperf = os._is_profiling_process_perf()\n    if profileperf then\n        if os._PROCESS_PROFILEINFO then\n            local perfinfo = {}\n            local totaltime = 0\n            for runcmd, profileinfo in pairs(os._PROCESS_PROFILEINFO) do\n                profileinfo.runcmd = runcmd\n                totaltime = totaltime + profileinfo.totaltime\n                table.insert(perfinfo, profileinfo)\n            end\n            table.sort(perfinfo, function (a, b) return a.totaltime > b.totaltime end)\n            for _, profileinfo in ipairs(perfinfo) do\n                local percent = (profileinfo.totaltime / totaltime) * 100\n                if percent < 1 then\n                    break\n                end\n                utils.print(\"%6.3f, %6.2f%%, %7d, %s\", profileinfo.totaltime, percent, profileinfo.runcount, profileinfo.runcmd)\n            end\n        end\n    end\n\n    local exit_callbacks = os._EXIT_CALLBACKS\n    if exit_callbacks then\n        for _, cb in ipairs(exit_callbacks) do\n            cb(ok, errors)\n        end\n    end\nend\n\n-- get shell path, e.g. sh, bash\nfunction os._get_shell_path(opt)\n    opt = opt or {}\n    local setenvs = opt.setenvs or opt.envs or {}\n    local addenvs = opt.addenvs or {}\n    local paths = {}\n    local p = setenvs.PATH\n    if type(p) == \"string\" then\n        p = path.splitenv(p)\n    end\n    if p then\n        table.join2(paths, p)\n    end\n    p = addenvs.PATH\n    if type(p) == \"string\" then\n        p = path.splitenv(p)\n    end\n    if p then\n        table.join2(paths, p)\n    end\n    for _, p in ipairs(paths) do\n        for _, name in ipairs({\"sh\", \"bash\"}) do\n            local filepath = path.join(p, name)\n            if os.isexec(filepath) then\n                return filepath\n            end\n        end\n    end\nend\n\n-- match files or directories\n--\n-- @param pattern   the search pattern\n--                  uses \"*\" to match any part of a file or directory name,\n--                  uses \"**\" to recurse into subdirectories.\n--\n-- @param mode      the match mode\n--                  - only find file:           'f' or false or nil\n--                  - only find directory:      'd' or true\n--                  - find file and directory:  'a'\n-- @return          the result array and count\n--\n-- @code\n-- local dirs, count = os.match(\"./src/*\", true)\n-- local files, count = os.match(\"./src/**.c\")\n-- local file = os.match(\"./src/test.c\", 'f', function (filepath, isdir)\n--                  return true   -- continue it\n--                  return false  -- break it\n--              end)\n-- @endcode\n--\nfunction os.match(pattern, mode, opt)\n\n    -- do it in the asynchronous task\n    if type(opt) == \"table\" and opt.async and xmake.in_main_thread() then\n        return os._async_task().match(pattern, mode)\n    end\n\n    -- extract callback\n    local callback = type(opt) == \"function\" and opt or (type(opt) == \"table\" and opt.callback or nil)\n\n    -- support path instance\n    pattern = tostring(pattern)\n\n    -- get the excludes\n    local excludes = pattern:match(\"|.*$\")\n    if excludes then excludes = excludes:split(\"|\", {plain = true}) end\n\n    -- translate excludes\n    if excludes then\n        local _excludes = {}\n        for _, exclude in ipairs(excludes) do\n            exclude = path.translate(exclude)\n            exclude = path.pattern(exclude)\n            table.insert(_excludes, exclude)\n        end\n        excludes = _excludes\n    end\n\n    -- translate path and remove some repeat separators\n    pattern = path.translate((pattern:gsub(\"|.*$\", \"\")))\n\n    -- translate mode\n    if type(mode) == \"string\" then\n        local modes = {a = -1, f = 0, d = 1}\n        mode = modes[mode]\n        assert(mode, \"invalid match mode: %s\", mode)\n    elseif mode then\n        mode = 1\n    else\n        mode = 0\n    end\n\n    -- match the single file without wildchard?\n    if os.isfile(pattern) then\n        if mode <= 0 then\n            return {pattern}, 1\n        else\n            return {}, 0\n        end\n    -- match the single directory without wildchard?\n    elseif os.isdir(pattern) then\n        if (mode == -1 or mode == 1) then\n            return {pattern}, 1\n        else\n            return {}, 0\n        end\n    end\n\n    -- remove \"./\" or '.\\\\' prefix\n    if pattern:sub(1, 2):find('%.[/\\\\]') then\n        pattern = pattern:sub(3)\n    end\n\n    -- get the root directory\n    local rootdir = pattern\n    local startpos = pattern:find(\"*\", 1, true)\n    if startpos then\n        rootdir = rootdir:sub(1, startpos - 1)\n    end\n    rootdir = path.directory(rootdir .. \"_\") -- patch '_' to avoid getting incorrect directory for `/foo/*`\n\n    -- compute the recursion level\n    --\n    -- infinite recursion: src/**.c\n    -- limit recursion level: src/*/*.c\n    local recursion = 0\n    if pattern:find(\"**\", 1, true) then\n        recursion = -1\n    else\n        -- \"src/*/*.c\" -> \"*/\" -> recursion level: 1\n        -- \"src/*/main.c\" -> \"*/\" -> recursion level: 1\n        -- \"src/*/subdir/main.c\" -> \"*//\" -> recursion level: 2\n        if startpos then\n            local _, seps = pattern:sub(startpos):gsub(\"[/\\\\]\", \"\")\n            if seps > 0 then\n                recursion = seps\n            end\n        end\n    end\n\n    -- convert pattern to a lua pattern\n    pattern = path.pattern(pattern)\n\n    -- find it\n    return os.find(rootdir, pattern, recursion, mode, excludes, callback)\nend\n\n-- match directories\n--\n-- @note only return {} without count to simplify code, e.g. table.unpack(os.dirs(\"\"))\n--\nfunction os.dirs(pattern, opt)\n    return (os.match(pattern, 'd', opt))\nend\n\n-- match files\nfunction os.files(pattern, opt)\n    return (os.match(pattern, 'f', opt))\nend\n\n-- match files and directories\nfunction os.filedirs(pattern, opt)\n    return (os.match(pattern, 'a', opt))\nend\n\n-- copy files or directories and we can reserve the source directory structure\n--\n-- @param srcpath   the source file path\n-- @param dstpath   the destination file path\n-- @param opt       the copy option. e.g. {rootdir, symlink, writeable, force, copy_if_different}\n--\n-- e.g. os.cp(\"src/**.h\", \"/tmp/\", {rootdir = \"src\", symlink = true})\nfunction os.cp(srcpath, dstpath, opt)\n\n    -- check arguments\n    if not srcpath or not dstpath then\n        return false, string.format(\"invalid arguments!\")\n    end\n\n    -- do it in the asynchronous task\n    if opt and opt.async and xmake.in_main_thread() then\n        return os._async_task().cp(srcpath, dstpath, {detach = opt.detach})\n    end\n\n    -- reserve the source directory structure if opt.rootdir is given\n    local rootdir = opt and opt.rootdir\n    if rootdir then\n        rootdir = tostring(rootdir)\n        if not path.is_absolute(rootdir) then\n            rootdir = path.absolute(rootdir)\n        end\n    end\n\n    -- copy files or directories\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    local srcpathes = os._match_wildcard_pathes(srcpath)\n    if type(srcpathes) == \"string\" then\n        return os._cp(srcpathes, dstpath, rootdir, opt)\n    else\n        for _, _srcpath in ipairs(srcpathes) do\n            local ok, errors = os._cp(_srcpath, dstpath, rootdir, opt)\n            if not ok then\n                return false, errors\n            end\n        end\n    end\n    return true\nend\n\n-- move files or directories\nfunction os.mv(srcpath, dstpath, opt)\n\n    -- check arguments\n    if not srcpath or not dstpath then\n        return false, string.format(\"invalid arguments!\")\n    end\n\n    -- copy files or directories\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    local srcpathes = os._match_wildcard_pathes(srcpath)\n    if type(srcpathes) == \"string\" then\n        return os._mv(srcpathes, dstpath, opt)\n    else\n        for _, _srcpath in ipairs(srcpathes) do\n            local ok, errors = os._mv(_srcpath, dstpath, opt)\n            if not ok then\n                return false, errors\n            end\n        end\n    end\n    return true\nend\n\n-- remove files or directories\nfunction os.rm(filepath, opt)\n    opt = opt or {}\n\n    -- check arguments\n    if not filepath then\n        return false, string.format(\"invalid arguments!\")\n    end\n\n    -- do it in the asynchronous task\n    if opt.async and xmake.in_main_thread() then\n       return os._async_task().rm(filepath, {detach = opt.detach})\n    end\n\n    -- remove file or directories\n    filepath = tostring(filepath)\n    local filepathes = os._match_wildcard_pathes(filepath)\n    if type(filepathes) == \"string\" then\n        local ok, errors = os._rm(filepathes)\n        if not ok then\n            return false, errors\n        end\n        if opt.emptydirs then\n            return os._rm_empty_parentdirs(filepathes)\n        end\n    else\n        for _, _filepath in ipairs(filepathes) do\n            local ok, errors = os._rm(_filepath)\n            if not ok then\n                return false, errors\n            end\n            if opt.emptydirs then\n                ok, errors = os._rm_empty_parentdirs(_filepath)\n                if not ok then\n                    return false, errors\n                end\n            end\n        end\n    end\n    return true\nend\n\n-- link file or directory to the new symfile\nfunction os.ln(srcpath, dstpath, opt)\n    opt = opt or {}\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    if opt.force and os.isfile(dstpath) then\n        os.rmfile(dstpath)\n    end\n    if not os.link(srcpath, dstpath) then\n        return false, string.format(\"cannot link %s to %s, %s\", srcpath, dstpath, os.strerror())\n    end\n    return true\nend\n\n-- change to directory\nfunction os.cd(dir)\n    assert(dir)\n\n    -- we can only change directory in main thread\n    if not xmake.in_main_thread() then\n        local thread = require(\"base/thread\")\n        os.raise(\"we cannot change directory in non-main thread(%s)\", thread.running() or \"unknown\")\n    end\n\n    -- support path instance\n    dir = tostring(dir)\n\n    -- change to the previous directory?\n    local oldir = os.curdir()\n    if dir == \"-\" then\n        if os._PREDIR then\n            dir = os._PREDIR\n            os._PREDIR = nil\n        else\n            return nil, string.format(\"not found the previous directory %s\", os.strerror())\n        end\n    end\n\n    -- no changed?\n    if dir == oldir then\n        return oldir\n    end\n\n    -- do change directory\n    if os.isdir(dir) then\n        if not os.chdir(dir) then\n            return nil, string.format(\"cannot change directory %s %s\", dir, os.strerror())\n        end\n        os._PREDIR = oldir\n    else\n        return nil, string.format(\"cannot change directory %s, not found this directory %s\", dir, os.strerror())\n    end\n\n    os._notify_curdir_changed()\n    return oldir\nend\n\n-- touch file or directory, it will modify atime/mtime or create a new file\n-- we will do not change it if atime/mtime is zero\nfunction os.touch(filepath, opt)\n    opt = opt or {}\n    if os._touch and not os._touch(filepath, opt.atime or 0, opt.mtime or 0) then\n        return false, string.format(\"cannot touch %s, %s\", filepath, os.strerror())\n    end\n    return true\nend\n\n-- create directories\nfunction os.mkdir(dir)\n\n    -- check arguments\n    if not dir then\n        return false, string.format(\"invalid arguments!\")\n    end\n\n    -- support path instance\n    dir = tostring(dir)\n\n    -- create directories\n    local dirs = table.wrap(os._match_wildcard_pathes(dir))\n    for _, _dir in ipairs(dirs) do\n        if not os._mkdir(_dir) then\n            return false, string.format(\"cannot create directory: %s, %s\", _dir, os.strerror())\n        end\n    end\n    return true\nend\n\n-- remove directories\nfunction os.rmdir(dir, opt)\n\n    -- check arguments\n    if not dir then\n        return false, string.format(\"invalid arguments!\")\n    end\n\n    -- do it in the asynchronous task\n    if opt and opt.async and xmake.in_main_thread() then\n        return os._async_task().rmdir(dir, {detach = opt.detach})\n    end\n\n    -- support path instance\n    dir = tostring(dir)\n\n    -- remove directories\n    local dirs = table.wrap(os._match_wildcard_pathes(dir))\n    for _, _dir in ipairs(dirs) do\n        if not os._rmdir(_dir) then\n            return false, string.format(\"cannot remove directory: %s, %s\", _dir, os.strerror())\n        end\n    end\n    return true\nend\n\n-- get the current directory\nfunction os.curdir()\n    local curdir = os._CURDIR\n    if curdir == nil then\n        curdir = os._curdir()\n        os._CURDIR = curdir\n    end\n    return curdir\nend\n\n-- get the temporary directory\nfunction os.tmpdir(opt)\n\n    -- is in fakeroot? @note: uid always be 0 in root and fakeroot\n    if os._FAKEROOT == nil then\n        local ldpath = os.getenv(\"LD_LIBRARY_PATH\")\n        if ldpath and ldpath:find(\"libfakeroot\", 1, true) then\n            os._FAKEROOT = true\n        else\n            os._FAKEROOT = false\n        end\n    end\n\n    -- get root tmpdir\n    local tmpdir_root = nil\n    if opt and opt.ramdisk == false then\n        tmpdir_root = os._ROOT_TMPDIR\n        if os._ROOT_TMPDIR == nil then\n            tmpdir_root = (os.getenv(\"XMAKE_TMPDIR\") or os.getenv(\"TMPDIR\") or os._tmpdir()):trim()\n            tmpdir_root = os._resolve_tmpdir(tmpdir_root)\n            os._ROOT_TMPDIR = tmpdir_root\n        end\n    else\n        tmpdir_root = os._ROOT_TMPDIR_RAM\n        if os._ROOT_TMPDIR_RAM == nil then\n            tmpdir_root = (os.getenv(\"XMAKE_TMPDIR\") or os._ramdir() or os.getenv(\"TMPDIR\") or os._tmpdir()):trim()\n            tmpdir_root = os._resolve_tmpdir(tmpdir_root)\n            os._ROOT_TMPDIR_RAM = tmpdir_root\n        end\n    end\n\n    -- make sub-directory name\n    local subdir = os._TMPSUBDIR\n    if not subdir then\n        local name = \".\" .. xmake._NAME\n        subdir = path.join((os._FAKEROOT and (name .. \"fake\") or name) .. (os.uid().euid or \"\"), os.date(\"%y%m%d\"))\n        os._TMPSUBDIR = subdir\n    end\n\n    -- get a temporary directory for each user\n    local tmpdir = path.join(tmpdir_root, subdir)\n    if not os.isdir(tmpdir) then\n        os.mkdir(tmpdir)\n    end\n    return tmpdir\nend\n\n-- generate the temporary file path\n--\n-- e.g.\n-- os.tmpfile(\"key\")\n-- os.tmpfile({key = \"xxx\", ramdisk = false})\n--\nfunction os.tmpfile(opt_or_key)\n    local opt\n    local key = opt_or_key\n    if type(key) == \"table\" then\n        key = opt_or_key.key\n        opt = opt_or_key\n    end\n    local filename = \"_\" .. (key and hash.strhash128(key) or (hash.rand128()))\n    return path.join(os.tmpdir(opt), filename)\nend\n\n-- exit program\nfunction os.exit(...)\n    return os._exit(...)\nend\n\n-- register exit callback\n--\n-- e.g.\n-- os.atexit(function (ok, errors)\n--     print(ok, errors)\n-- end)\n--\nfunction os.atexit(on_exit)\n    local exit_callbacks = os._EXIT_CALLBACKS\n    if exit_callbacks == nil then\n        exit_callbacks = {}\n        os._EXIT_CALLBACKS = exit_callbacks\n    end\n    table.insert(exit_callbacks, on_exit)\nend\n\n-- run command\nfunction os.run(cmd)\n\n    -- parse arguments\n    local argv = os.argv(cmd)\n    if not argv or #argv <= 0 then\n        return false, string.format(\"invalid command: %s\", cmd)\n    end\n\n    -- run it\n    return os.runv(argv[1], table.slice(argv, 2))\nend\n\n-- run command with arguments list\nfunction os.runv(program, argv, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- make temporary log file\n    local logfile = os.tmpfile()\n\n    -- execute it\n    local ok, errors = os.execv(program, argv, table.join(opt, {stdout = opt.stdout or logfile, stderr = opt.stderr or logfile}))\n    if ok ~= 0 then\n\n        -- get command\n        local cmd = program\n        if argv then\n            cmd = cmd .. \" \" .. os.args(argv)\n        end\n\n        -- get subprocess errors\n        if ok ~= nil then\n            errors = io.readfile(logfile)\n            if not errors or #errors == 0 then\n                errors = string.format(\"runv(%s) failed(%d)\", cmd, ok)\n            end\n        else\n            errors = string.format(\"cannot runv(%s), %s\", cmd, errors and errors or \"unknown reason\")\n        end\n\n        os.rm(logfile)\n        return false, errors\n    end\n    os.rm(logfile)\n    return true\nend\n\n-- execute command\nfunction os.exec(cmd)\n\n    -- parse arguments\n    local argv = os.argv(cmd)\n    if not argv or #argv <= 0 then\n        return -1\n    end\n\n    -- run it\n    return os.execv(argv[1], table.slice(argv, 2))\nend\n\n-- execute command with arguments list\n--\n-- @param program     \"clang\", \"xcrun -sdk macosx clang\", \"~/dir/test\\ xxx/clang\"\n--        filename    \"clang\", \"xcrun\"\", \"~/dir/test\\ xxx/clang\"\n-- @param argv        the arguments\n-- @param opt         the options, e.g. {stdin = filepath/file/pipe, stdout = filepath/file/pipe, stderr = filepath/file/pipe,\n--                                       envs = {PATH = \"xxx;xx\", CFLAGS = \"xx\"}}\n--\nfunction os.execv(program, argv, opt)\n\n    -- is not executable program file?\n    opt = opt or {}\n    local filename = tostring(program)\n    if not os.isexec(program) then\n\n        -- parse the filename and arguments, e.g. \"xcrun -sdk macosx clang\"\n        local splitinfo = program:split(\"%s\")\n        filename = splitinfo[1]\n        if #splitinfo > 1 then\n            argv = table.join(table.slice(splitinfo, 2), argv)\n        end\n    end\n\n    -- run shell file? parse `#!/usr/bin/env bash` in xx.sh\n    --\n    -- e.g. os.execv(\"./configure\", {\"--help\"}) => os.execv(\"/usr/bin/env\", {\"bash\", \"./configure\", \"--help\"})\n    if opt.shell and os.isfile(filename) then\n        local shellfile = filename\n        local file = io.open(filename, 'r')\n        for line in file:lines() do\n            if line and line:startswith(\"#!\") then\n                -- we cannot run `/bin/sh` directly on windows\n                -- because `/bin/sh` is not real file path, maybe we need to convert it.\n                local host = os.host()\n                if host == \"windows\" then\n                    filename = os._get_shell_path(opt) or \"sh\"\n                    argv = table.join(shellfile, argv)\n                else\n                    line = line:sub(3)\n                    local shellargv = {}\n                    local splitinfo = line:split(\"%s\")\n                    filename = splitinfo[1]\n                    if #splitinfo > 1 then\n                        shellargv = table.slice(splitinfo, 2)\n                    end\n                    table.insert(shellargv, shellfile)\n                    table.join2(shellargv, argv)\n                    argv = shellargv\n                end\n                break\n            end\n        end\n        file:close()\n    end\n\n    -- uses the given environments?\n    local envs = nil\n    local setenvs = opt.setenvs or opt.envs\n    local addenvs = opt.addenvs\n    if setenvs or addenvs then\n        local envars = os.getenvs()\n        if setenvs then\n            for k, v in pairs(setenvs) do\n                if type(v) == \"table\" then\n                    v = path.joinenv(v)\n                end\n                envars[k] = v\n            end\n        end\n        if addenvs then\n            for k, v in pairs(addenvs) do\n                if type(v) == \"table\" then\n                    v = path.joinenv(v)\n                end\n                local o = envars[k]\n                if o then\n                    v = v .. path.envsep() .. o\n                end\n                envars[k] = v\n            end\n        end\n        envs = {}\n        for k, v in pairs(envars) do\n            -- we try to fix too long value before running process\n            if type(v) == \"string\" and #v > 4096 and os.host() == \"windows\" then\n                v = os._deduplicate_pathenv(v)\n            end\n            table.insert(envs, k .. '=' .. v)\n        end\n    end\n\n    -- init open options\n    local openopt = {\n        envs = envs,\n        stdin = opt.stdin,\n        stdout = opt.stdout,\n        stderr = opt.stderr,\n        curdir = opt.curdir,\n        detach = opt.detach,\n        exclusive = opt.exclusive}\n\n    -- profile process performance\n    local runtime\n    local profileperf = os._is_profiling_process_perf()\n    if profileperf then\n        runtime = os.mclock()\n    end\n\n    -- open command\n    local ok = -1\n    local errors\n    local proc = process.openv(filename, argv or {}, openopt)\n    if proc ~= nil then\n\n        -- trace process\n        if os._is_tracing_process() then\n            -- we cannot use cprint, it will cause dead-loop on windows, winos.version/os.iorunv\n            utils.print(\"%s: %s %s\", proc, filename, argv and os.args(argv) or \"\")\n        end\n\n        -- wait process\n        if not opt.detach then\n            local waitok, status = proc:wait(opt.timeout or -1)\n            if waitok > 0 then\n                ok = status\n                if ok and ok ~= 0 then\n                    errors = process.get_exit_errors(filename, ok)\n                end\n            elseif waitok == 0 and opt.timeout then\n                proc:kill()\n                waitok, status = proc:wait(-1)\n                if waitok > 0 then\n                    ok = status\n                end\n                errors = \"wait process timeout\"\n            end\n        else\n            ok = 0\n        end\n\n        -- close process\n        proc:close()\n\n        -- save profile info\n        if profileperf then\n            runtime = os.mclock() - runtime\n\n            local profileinfo = os._PROCESS_PROFILEINFO\n            if profileinfo == nil then\n                profileinfo = {}\n                os._PROCESS_PROFILEINFO = profileinfo\n            end\n\n            local runcmd\n            runcmd = filename\n            if argv and #argv > 0 then\n                runcmd = runcmd .. \" \" .. os.args(argv)\n            end\n            local perfinfo = profileinfo[runcmd]\n            if perfinfo == nil then\n                perfinfo = {}\n                profileinfo[runcmd] = perfinfo\n            end\n            perfinfo.totaltime = (perfinfo.totaltime or 0) + runtime\n            perfinfo.runcount = (perfinfo.runcount or 0) + 1\n        end\n    else\n        -- cannot execute process\n        return nil, os.strerror()\n    end\n    return ok, errors\nend\n\n-- run command and return output and error data\nfunction os.iorun(cmd)\n\n    -- parse arguments\n    local argv = os.argv(cmd)\n    if not argv or #argv <= 0 then\n        return false, string.format(\"invalid command: %s\", cmd)\n    end\n\n    -- run it\n    return os.iorunv(argv[1], table.slice(argv, 2))\nend\n\n-- run command with arguments and return output and error data\nfunction os.iorunv(program, argv, opt)\n\n    -- make temporary output and error file\n    opt = opt or {}\n    local outfile = os.tmpfile()\n    local errfile = os.tmpfile()\n\n    -- run command\n    local ok, errors = os.execv(program, argv, table.join(opt, {stdout = outfile, stderr = errfile}))\n    if ok == nil then\n        local cmd = program\n        if argv then\n            cmd = cmd .. \" \" .. os.args(argv)\n        end\n        errors = string.format(\"cannot runv(%s), %s\", cmd, errors or \"unknown reason\")\n    end\n\n    -- get output and error data\n    local outdata = io.readfile(outfile)\n    local errdata = io.readfile(errfile)\n\n    -- remove the temporary output and error file\n    os.rm(outfile)\n    os.rm(errfile)\n    return ok == 0, outdata, errdata, errors\nend\n\n-- raise an exception and abort the current script\n--\n-- the parent function will capture it if we uses pcall or xpcall\n--\nfunction os.raiselevel(level, msg, ...)\n\n    -- set level of this function\n    level = level + 1\n\n    -- flush log\n    log:flush()\n\n    -- flush io buffer\n    io.flush()\n\n    -- raise it\n    if type(msg) == \"string\" then\n        error(string.tryformat(msg, ...), level)\n    elseif type(msg) == \"table\" then\n        local errobjstr, errors = string.serialize(msg, {strip = true, indent = false})\n        if errobjstr then\n            error(\"[@encode(error)]: \" .. errobjstr, level)\n        else\n            error(errors, level)\n        end\n    elseif msg ~= nil then\n        error(tostring(msg), level)\n    else\n        error(msg, level)\n    end\nend\n\n-- raise an exception and abort the current script\n--\n-- the parent function will capture it if we uses pcall or xpcall\n--\nfunction os.raise(msg, ...)\n    -- add return to make it a tail call\n    return os.raiselevel(1, msg, ...)\nend\n\n-- is executable program file?\nfunction os.isexec(filepath)\n    if os.host() == \"windows\" then\n        local exts_map = os._ISEXEC_WINDOWS_EXTS_MAP\n        if not exts_map then\n            local exts = {\".exe\", \".com\", \".cmd\", \".bat\", \".ps1\", \".sh\"}\n            exts_map = {}\n            for _, ext in ipairs(exts) do\n                exts_map[ext] = true\n            end\n            os._ISEXEC_WINDOWS_EXTS_MAP = exts_map\n        end\n        if os.isfile(filepath) then\n            local extension = path.extension(filepath)\n            if extension and #extension > 0 then\n                if exts_map[extension:lower()] then\n                    return true\n                end\n            else\n                -- detect executable file header\n                --\n                -- @note only for files without extension, because .dll is also PE\n                -- pe: native windows executables\n                -- ape: cosmocc/APE executables (e.g. `cosmocc -o foo.exe ...`)\n                -- shebang: scripts starting with `#!`\n                local format = nil\n                if binutils and binutils.format then\n                    format = binutils.format(filepath)\n                end\n                if format == \"pe\" or format == \"ape\" or format == \"shebang\" then\n                    return true\n                end\n            end\n        end\n        for suffix, _ in pairs(exts_map) do\n            if os.isfile(filepath .. suffix) then\n                return true\n            end\n        end\n    elseif os.isfile(filepath) then\n        if os._access then\n            return os._access(filepath, \"x\")\n        else\n            return true\n        end\n    end\n    return false\nend\n\n-- get system host\nfunction os.host()\n    return xmake._HOST\nend\n\n-- get system architecture\nfunction os.arch()\n    return xmake._ARCH\nend\n\n-- get subsystem host, e.g. msys, cygwin on windows\nfunction os.subhost()\n    return xmake._SUBHOST\nend\n\n-- get subsystem host architecture\nfunction os.subarch()\n    return xmake._SUBARCH\nend\n\n-- get features\nfunction os.features()\n    return xmake._FEATURES\nend\n\n-- the current host is belong to the given hosts?\nfunction os.is_host(...)\n    return os._is_host(os.host(), ...)\nend\n\n-- the current architecture is belong to the given architectures?\nfunction os.is_arch(...)\n    return os._is_arch(os.arch(), ...)\nend\n\n-- the current subsystem host is belong to the given hosts?\nfunction os.is_subhost(...)\n    return os._is_host(os.subhost(), ...)\nend\n\n-- the current subsystem architecture is belong to the given architectures?\nfunction os.is_subarch(...)\n    return os._is_arch(os.subarch(), ...)\nend\n\n-- get the system null device\nfunction os.nuldev(input)\n\n    if input then\n        if os.host() == \"windows\" then\n            -- init the input nuldev\n            if xmake._NULDEV_INPUT == nil then\n                -- create an empty file\n                --\n                -- for fix issue on mingw:\n                -- $ gcc -fopenmp -S -o nul -xc nul\n                -- gcc: fatal error：input file 'nul' is the same as output file\n                --\n                local inputfile = os.tmpfile()\n                io.writefile(inputfile, \"\")\n                xmake._NULDEV_INPUT = inputfile\n            end\n        else\n            if xmake._NULDEV_INPUT == nil then\n                xmake._NULDEV_INPUT = \"/dev/null\"\n            end\n        end\n        return xmake._NULDEV_INPUT\n    else\n        if os.host() == \"windows\" then\n            -- @note cannot cache this file path to avoid multi-processes writing to the same file at the same time\n            return os.tmpfile()\n        else\n            if xmake._NULDEV_OUTPUT == nil then\n                xmake._NULDEV_OUTPUT = \"/dev/null\"\n            end\n            return xmake._NULDEV_OUTPUT\n        end\n    end\nend\n\n-- get uid\nfunction os.uid(...)\n    os._UID = {}\n    if os._uid then\n        os._UID = os._uid(...) or {}\n    end\n    return os._UID\nend\n\n-- get gid\nfunction os.gid(...)\n    os._GID = {}\n    if os._gid then\n        os._GID = os._gid(...) or {}\n    end\n    return os._GID\nend\n\n-- get pid\nfunction os.getpid(...)\n    local pid = os._PID\n    if pid == nil then\n        pid = os._getpid()\n        os._PID = pid\n    end\n    return pid\nend\n\n-- check the current command is running as root\nfunction os.isroot()\n    return os.uid().euid == 0\nend\n\n-- is case-insensitive filesystem?\nfunction os.fscase(filepath)\n    if os._FSCASE == nil or filepath then\n        if os._fscase then\n            if filepath then\n                assert(os.exists(filepath), filepath .. \" not found in os.fscase()\")\n            else\n                local tmpdir = os.tmpdir()\n                if not os.isdir(tmpdir) then\n                    os.mkdir(tmpdir)\n                end\n                filepath = tmpdir\n            end\n            local fscase = os._fscase(filepath)\n            if fscase ~= -1 then\n                os._FSCASE = (fscase == 1)\n                return os._FSCASE\n            end\n        end\n        if os.host() == \"windows\" then\n            os._FSCASE = false\n        else\n\n            -- get temporary directory\n            local tmpdir = os.tmpdir()\n\n            -- get matching pattern, this is equal to os.filedirs(path.join(tmpdir, \"*\"))\n            --\n            -- @note we cannot use os.match() becase os.fscase() will be called in os.match()\n            --\n            local pattern = path.join(tmpdir, \"*\")\n            pattern = pattern:gsub(\"([%+%.%-%^%$%(%)%%])\", \"%%%1\")\n            pattern = pattern:gsub(\"%*\", \"\\002\")\n            pattern = pattern:gsub(\"\\002\", \"[^/]*\")\n\n            -- attempt to detect it\n            local file = os.find(tmpdir, pattern, 0, -1, nil, function (file, isdir) return false end)\n            if file and #file > 0 then\n                local file1 = file[1]\n                local file2 = file1:gsub(\".\",  function (ch) return (ch >= 'a' and ch <= 'z') and ch:upper() or ch:lower() end)\n                os._FSCASE = not (os.exists(file1) and os.exists(file2))\n            else\n                os._FSCASE = true\n            end\n        end\n    end\n    return os._FSCASE\nend\n\n-- get shell\nfunction os.shell()\n    return require(\"base/tty\").shell()\nend\n\n-- get term\nfunction os.term()\n    return require(\"base/tty\").term()\nend\n\n-- get all current environments variables\nfunction os.getenvs()\n    local envs = os._getenvs()\n    if envs then\n        -- we need to be compatible with the old binary core, if it's array (<= v3.0.3)\n        if envs[1] ~= nil then\n            local result = {}\n            for _, line in ipairs(envs) do\n                local p = line:find('=', 1, true)\n                if p then\n                    local key = line:sub(1, p - 1):trim()\n                    -- only translate Path to PATH on windows\n                    -- @see https://github.com/xmake-io/xmake/issues/3752\n                    if os.host() == \"windows\" and key:lower() == \"path\" then\n                        key = key:upper()\n                    end\n                    local values = line:sub(p + 1):trim()\n                    if #key > 0 then\n                        result[key] = values\n                    end\n                end\n            end\n            envs = result\n        end\n    end\n    return envs\nend\n\n-- set all current environment variables\n-- e.g. envs[\"PATH\"] = \"/xxx:/yyy/foo\"\nfunction os.setenvs(envs)\n    local oldenvs = os.getenvs()\n    if envs then\n        local changed = false\n        -- remove new added values\n        for name, _ in pairs(oldenvs) do\n            if not envs[name] then\n                if os._setenv(name, \"\") then\n                    changed = true\n                end\n            end\n        end\n        -- change values\n        for name, values in pairs(envs) do\n            if oldenvs[name] ~= values then\n                if os._setenv(name, values) then\n                    changed = true\n                end\n            end\n        end\n        if changed then\n            os._notify_envs_changed(envs)\n        end\n    end\n    return oldenvs\nend\n\n-- add environment variables\n-- e.g. envs[\"PATH\"] = \"/xxx:/yyy/foo\"\nfunction os.addenvs(envs)\n    local oldenvs = os.getenvs()\n    if envs then\n        local changed = false\n        for name, values in pairs(envs) do\n            local ok\n            local oldenv = oldenvs[name]\n            if oldenv == \"\" or oldenv == nil then\n                ok = os._setenv(name, values)\n            elseif not oldenv:startswith(values) then\n                ok = os._setenv(name, values .. path.envsep() .. oldenv)\n            end\n            if ok then\n                changed = true\n            end\n        end\n        if changed then\n            os._notify_envs_changed()\n        end\n    end\n    return oldenvs\nend\n\n-- join environment variables\nfunction os.joinenvs(envs, oldenvs)\n    oldenvs = oldenvs or os.getenvs()\n    local newenvs = oldenvs\n    if envs then\n        newenvs = table.copy(oldenvs)\n        for name, values in pairs(envs) do\n            local oldenv = oldenvs[name]\n            if oldenv == \"\" or oldenv == nil then\n                newenvs[name] = values\n            elseif not oldenv:startswith(values) then\n                newenvs[name] = values .. path.envsep() .. oldenv\n            end\n        end\n    end\n    return newenvs\nend\n\n-- set values to environment variable\nfunction os.setenv(name, ...)\n    local ok\n    local values = {...}\n    if #values <= 1 then\n        -- keep compatible with original implementation\n        ok = os._setenv(name, values[1] or \"\")\n    else\n        ok = os._setenv(name, path.joinenv(values))\n    end\n    if ok then\n        os._notify_envs_changed()\n    end\n    return ok\nend\n\n-- add values to environment variable\nfunction os.addenv(name, ...)\n    local values = {...}\n    if #values > 0 then\n        local ok\n        local changed = false\n        local oldenv = os.getenv(name)\n        local appendenv = path.joinenv(values)\n        if oldenv == \"\" or oldenv == nil then\n            ok = os._setenv(name, appendenv)\n            if ok then\n                changed = true\n            end\n        elseif not oldenv:startswith(appendenv) then\n            ok = os._setenv(name, appendenv .. path.envsep() .. oldenv)\n            if ok then\n                changed = true\n            end\n        else\n            ok = true\n        end\n        if changed then\n            os._notify_envs_changed()\n        end\n        return ok\n    else\n        return true\n    end\nend\n\n-- set values to environment variable with the given seperator\nfunction os.setenvp(name, values, sep)\n    sep = sep or path.envsep()\n    local ok = os._setenv(name, table.concat(table.wrap(values), sep))\n    if ok then\n        os._notify_envs_changed()\n    end\n    return ok\nend\n\n-- add values to environment variable with the given seperator\nfunction os.addenvp(name, values, sep)\n    sep = sep or path.envsep()\n    values = table.wrap(values)\n    if #values > 0 then\n        local ok\n        local changed = false\n        local oldenv = os.getenv(name)\n        local appendenv = table.concat(values, sep)\n        if oldenv == \"\" or oldenv == nil then\n            ok = os._setenv(name, appendenv)\n            if ok then\n                changed = true\n            end\n        elseif not oldenv:startswith(appendenv) then\n            ok = os._setenv(name, appendenv .. sep .. oldenv)\n            if ok then\n                changed = true\n            end\n        else\n            ok = true\n        end\n        if changed then\n            os._notify_envs_changed()\n        end\n        return ok\n    else\n        return true\n    end\nend\n\n-- read string data from pasteboard\nfunction os.pbpaste()\n    if os.host() == \"macosx\" then\n        local ok, result = os.iorun(\"pbpaste\")\n        if ok then\n            return result\n        end\n    elseif os.host() == \"linux\" then\n        local ok, result = os.iorun(\"xsel --clipboard --output\")\n        if ok then\n            return result\n        end\n    else\n        -- TODO\n    end\nend\n\n-- copy string data to pasteboard\nfunction os.pbcopy(data)\n    if os.host() == \"macosx\" then\n        os.run(\"bash -c \\\"echo '\" .. data .. \"' | pbcopy\\\"\")\n    elseif os.host() == \"linux\" then\n        os.run(\"bash -c \\\"echo '\" .. data .. \"' | xsel --clipboard --input\\\"\")\n    else\n        -- TODO\n    end\nend\n\n-- get cpu info\nfunction os.cpuinfo(name)\n    return require(\"base/cpu\").info(name)\nend\n\n-- get memory info\nfunction os.meminfo(name)\n    return require(\"base/memory\").info(name)\nend\n\n-- get the default parallel jobs number\nfunction os.default_njob()\n    local njob\n    local ncpu = os.cpuinfo().ncpu\n    if ncpu > 2 then\n        njob = ncpu + 2\n        if os.host() == \"windows\" and njob > 128 then\n            njob = 128\n        end\n        if njob > 512 then\n            njob = 512\n        end\n    elseif ncpu == 2 then\n        njob = 3\n    else\n        njob = 2\n    end\n    return njob or 2\nend\n\n-- read the content of symlink\nfunction os.readlink(symlink)\n    return os._readlink(path.absolute(symlink))\nend\n\n-- get the program directory\nfunction os.programdir()\n    return xmake._PROGRAM_DIR\nend\n\n-- get the program file\nfunction os.programfile()\n    return xmake._PROGRAM_FILE\nend\n\n-- get the working directory\nfunction os.workingdir()\n    return xmake._WORKING_DIR\nend\n\n-- get the project directory\nfunction os.projectdir()\n    return xmake._PROJECT_DIR\nend\n\n-- get the project file\nfunction os.projectfile()\n    return xmake._PROJECT_FILE\nend\n\n-- return module\nreturn os\n"
  },
  {
    "path": "xmake/core/base/path.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        path.lua\n--\n\n-- define module: path\nlocal path = path or {}\n\n-- load modules\nlocal string = require(\"base/string\")\nlocal table  = require(\"base/table\")\nlocal _instance = _instance or {}\n\n-- save original interfaces\npath._absolute = path._absolute or path.absolute\npath._relative = path._relative or path.relative\npath._translate = path._translate or path.translate\npath._directory = path._directory or path.directory\n\n-- new a path\nfunction _instance.new(p, transform)\n    local instance = table.inherit(_instance)\n    instance._RAWSTR = p\n    instance._TRANSFORM = transform\n    setmetatable(instance, _instance)\n    table.wrap_lock(instance)\n    instance:_update()\n    return instance\nend\n\n-- update path string\nfunction _instance:_update()\n    local transform = self._TRANSFORM\n    if transform then\n        self._STR = transform(self:rawstr())\n    else\n        self._STR = self:rawstr()\n    end\nend\n\nfunction _instance:str()\n    return self._STR\nend\n\nfunction _instance:rawstr()\n    return self._RAWSTR\nend\n\nfunction _instance:set(p)\n    self._RAWSTR = tostring(p)\n    self:_update()\n    return self\nend\n\nfunction _instance:empty()\n    local str = self._STR\n    return str == nil or #str == 0\nend\n\nfunction _instance:transform_set(transform)\n    self._TRANSFORM = transform\n    self:_update()\n    return self\nend\n\nfunction _instance:clone()\n    return path.new(self:rawstr(), self._TRANSFORM)\nend\n\nfunction _instance:normalize()\n    return path.new(path.normalize(self:str()), self._TRANSFORM)\nend\n\nfunction _instance:translate(opt)\n    return path.new(path.translate(self:str(), opt), self._TRANSFORM)\nend\n\nfunction _instance:unix()\n    return path.new(path.unix(self:str()), self._TRANSFORM)\nend\n\nfunction _instance:filename()\n    return path.filename(self:str())\nend\n\nfunction _instance:basename()\n    return path.basename(self:str())\nend\n\nfunction _instance:extension()\n    return path.extension(self:str())\nend\n\nfunction _instance:startswith(prefix)\n    return self:str():startswith(tostring(prefix))\nend\n\nfunction _instance:endswith(suffix)\n    return self:str():endswith(tostring(suffix))\nend\n\nfunction _instance:directory()\n    return path.new(path.directory(self:str()), self._TRANSFORM)\nend\n\nfunction _instance:absolute(rootdir)\n    return path.new(path.absolute(self:str(), rootdir), self._TRANSFORM)\nend\n\nfunction _instance:relative(rootdir)\n    return path.new(path.relative(self:str(), rootdir), self._TRANSFORM)\nend\n\nfunction _instance:join(...)\n    local items = {self:str()}\n    for _, item in ipairs(table.pack(...)) do\n        table.insert(items, tostring(item))\n    end\n    return path.new(path.join(table.unpack(items)), self._TRANSFORM)\nend\n\nfunction _instance:split()\n    return path.split(self:str())\nend\n\nfunction _instance:splitenv()\n    return path.splitenv(self:str())\nend\n\n-- concat two paths\nfunction _instance:__concat(other)\n    if path.instance_of(self) then\n        return path.new(path.join(self:str(), tostring(other)), self._TRANSFORM)\n    elseif type(self) == \"string\" then\n        return path.new(tostring(other), function (p)\n            return self .. p\n        end)\n    else\n        os.raise(\"cannot concat %s/%s\", tostring(self), type(self))\n    end\nend\n\n-- tostring(path)\nfunction _instance:__tostring()\n    return not self:empty() and self:str() or \"\"\nend\n\n-- todisplay(path)\nfunction _instance:__todisplay()\n    return \"<path: \" .. (self:empty() and \"empty\" or self:str()) .. \">\"\nend\n\n-- get unix-style path, it is usually used on windows\n-- @see https://github.com/xmake-io/xmake/issues/4731\nfunction path.unix(p)\n    return (tostring(p):gsub(path.sep(), \"/\"))\nend\n\n-- get cygwin-style path, e.g. c:\\, C:\\ -> /c/\nfunction path.cygwin(p)\n    return (tostring(p):gsub(\"^(%w):\", function (drive)\n        return \"/\" .. drive:lower()\n    end):gsub(\"\\\\\", \"/\"))\nend\n\n-- translate path\n--\n-- @param p     the path\n-- @param opt   the option, e.g. {normalize = true}\n--\nfunction path.translate(p, opt)\n    return path._translate(tostring(p), opt)\nend\n\n-- path.translate:\n-- - transform the path separator\n-- - expand the user directory with the prefix: ~\n-- - remove tail separator\n-- - reduce the repeat path separator, \"////\" => \"/\"\n--\n-- path.normalize:\n-- - reduce \"././\" => \".\"\n-- - reduce \"/xxx/..\" => \"/\"\n--\nfunction path.normalize(p)\n    return path.translate(tostring(p), {normalize = true})\nend\n\n-- get the directory of the path\nfunction path.directory(p, sep)\n    p = tostring(p)\n    if path._directory then\n        return path._directory(p, sep)\n    else\n        -- compatible with lower version core binary\n        local i =  0\n        if sep then\n            -- if the path has been normalized, we can quickly find it with a unique path separator prompt\n            i = p:lastof(sep, true) or 0\n        else\n            i = math.max(p:lastof('/', true) or 0, p:lastof('\\\\', true) or 0)\n        end\n        if i > 0 then\n            if i > 1 then i = i - 1 end\n            return p:sub(1, i)\n        else\n            return \".\"\n        end\n    end\nend\n\n-- get absolute path\nfunction path.absolute(p, rootdir)\n    if rootdir then\n        rootdir = tostring(rootdir)\n    end\n    return path._absolute(tostring(p), rootdir)\nend\n\n-- get relative path\nfunction path.relative(p, rootdir)\n    if rootdir then\n        rootdir = tostring(rootdir)\n    end\n    return path._relative(tostring(p), rootdir)\nend\n\n-- get the filename of the path\nfunction path.filename(p, sep)\n    p = tostring(p)\n    local i =  0\n    if sep then\n        -- if the path has been normalized, we can quickly find it with a unique path separator prompt\n        i = p:lastof(sep, true) or 0\n    else\n        i = math.max(p:lastof('/', true) or 0, p:lastof('\\\\', true) or 0)\n    end\n    if i > 0 then\n        return p:sub(i + 1)\n    else\n        return p\n    end\nend\n\n-- get the basename of the path\nfunction path.basename(p)\n    p = tostring(p)\n    local name = path.filename(p)\n    local i = name:lastof(\".\", true)\n    if i then\n        return name:sub(1, i - 1)\n    else\n        return name\n    end\nend\n\n-- get the file extension of the path: .xxx\nfunction path.extension(p, level)\n    p = tostring(p)\n    local i = p:lastof(\".\", true)\n    if i then\n        local ext = p:sub(i)\n        if ext:find(\"[/\\\\]\") then\n            return \"\"\n        end\n        if level and level > 1 then\n            return path.extension(p:sub(1, i - 1), level - 1) .. ext\n        end\n        return ext\n    else\n        return \"\"\n    end\nend\n\n-- join path\nfunction path.join(p, ...)\n    p = tostring(p)\n    return path.translate(p .. path.sep() .. table.concat({...}, path.sep()))\nend\n\n-- split path by the separator\nfunction path.split(p)\n    p = tostring(p)\n    return p:split(\"[/\\\\]\")\nend\n\n-- get the path seperator\nfunction path.sep()\n    local sep = path._SEP\n    if not sep then\n        sep = xmake._FEATURES.path_sep\n        path._SEP = sep\n    end\n    return sep\nend\n\n-- get the path seperator of environment variable\nfunction path.envsep()\n    local envsep = path._ENVSEP\n    if not envsep then\n        envsep = xmake._FEATURES.path_envsep\n        path._ENVSEP = envsep\n    end\n    return envsep\nend\n\n-- split environment variable with `path.envsep()`,\n-- also handles more speical cases such as posix flags and windows quoted paths\nfunction path.splitenv(env_path)\n    local result = {}\n    if xmake._HOST == \"windows\" then\n        while #env_path > 0 do\n            if env_path:startswith(path.envsep()) then\n                env_path = env_path:sub(2)\n            elseif env_path:startswith('\"') then\n                -- path quoted with, can contain `;`\n                local p_end = env_path:find('\"' .. path.envsep(), 2, true) or env_path:find('\"$', 2) or (#env_path + 1)\n                table.insert(result, env_path:sub(2, p_end - 1))\n                env_path = env_path:sub(p_end + 1)\n            else\n                local p_end = env_path:find(path.envsep(), 2, true) or (#env_path + 1)\n                table.insert(result, env_path:sub(1, p_end - 1))\n                env_path = env_path:sub(p_end)\n            end\n        end\n    else\n        -- see https://git.kernel.org/pub/scm/utils/dash/dash.git/tree/src/exec.c?h=v0.5.9.1&id=afe0e0152e4dc12d84be3c02d6d62b0456d68580#n173\n        -- no escape sequences, so `:` and `%` is invalid in environment variable\n        for _, v in ipairs(env_path:split(path.envsep(), { plain = true })) do\n            -- flag for shells, style `<path>%<flag>`\n            local flag = v:find(\"%\", 1, true)\n            if flag then\n                v = v:sub(1, flag - 1)\n            end\n            if #v > 0 then\n                table.insert(result, v)\n            end\n        end\n    end\n\n    return result\nend\n\n-- concat environment variable with `path.envsep()`,\n-- also handles more speical cases such as posix flags and windows quoted paths\nfunction path.joinenv(paths, envsep)\n    if not paths or #paths == 0 then\n        return \"\"\n    end\n    envsep = envsep or path.envsep()\n    if xmake._HOST == \"windows\" then\n        local tab = {}\n        for _, v in ipairs(paths) do\n            if v ~= \"\" then\n                if v:find(envsep, 1, true) then\n                    v = '\"' .. v .. '\"'\n                end\n                table.insert(tab, v)\n            end\n        end\n        return table.concat(tab, envsep)\n    else\n        return table.concat(paths, envsep)\n    end\nend\n\n-- the last character is the path seperator?\nfunction path.islastsep(p)\n    p = tostring(p)\n    local sep = p:sub(#p, #p)\n    return xmake._HOST == \"windows\" and (sep == '\\\\' or sep == '/') or (sep == '/')\nend\n\n-- convert path pattern to a lua pattern\nfunction path.pattern(pattern)\n\n    -- translate wildcards, e.g. *, **\n    pattern = pattern:gsub(\"([%+%.%-%^%$%(%)%%])\", \"%%%1\")\n    pattern = pattern:gsub(\"%*%*\", \"\\001\")\n    pattern = pattern:gsub(\"%*\", \"\\002\")\n    pattern = pattern:gsub(\"\\001\", \".*\")\n    if path.sep() == '\\\\' then\n        pattern = pattern:gsub(\"\\002\", \"[^/\\\\]*\")\n    else\n        pattern = pattern:gsub(\"\\002\", \"[^/]*\")\n    end\n\n    -- case-insensitive filesystem?\n    if not os.fscase() then\n        pattern = string.ipattern(pattern, true)\n    end\n    return pattern\nend\n\n-- get cygwin-style path on msys2/cygwin, e.g. \"c:\\xxx\" -> \"/c/xxx\"\nfunction path.cygwin_path(p)\n    p = tostring(p)\n    p = p:gsub(\"\\\\\", \"/\")\n    local pos = p:find(\":/\")\n    if pos == 2 then\n        return \"/\" .. p:sub(1, 1) .. p:sub(3)\n    end\n    return p\nend\n\n-- new a path instance\nfunction path.new(p, transform)\n    if path.instance_of(p) then\n        p = tostring(p)\n    end\n    return _instance.new(p, transform)\nend\n\n-- is path instance?\nfunction path.instance_of(p)\n    return type(p) == \"table\" and p.normalize and p._RAWSTR\nend\n\n-- register call function\n--\n-- local p = path(\"/tmp/a\")\n-- local p = path(\"/tmp/a\", function (p) return \"--key=\" .. p end)\nsetmetatable(path, {\n    __call = function (_, ...)\n        return path.new(...)\n    end,\n})\n\n-- return module: path\nreturn path\n"
  },
  {
    "path": "xmake/core/base/pipe.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pipe.lua\n--\n\n-- define module\nlocal pipe      = pipe or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal bytes     = require(\"base/bytes\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal scheduler = require(\"base/scheduler\")\n\n-- the pipe events, @see tbox/platform/pipe.h\npipe.EV_READ  = 1\npipe.EV_WRITE = 2\npipe.EV_CONN  = 2\n\n-- new a pipe file\nfunction _instance.new(cdata, name)\n    local pipefile = table.inherit(_instance)\n    pipefile._NAME = name\n    pipefile._PIPE = cdata\n    setmetatable(pipefile, _instance)\n    return pipefile\nend\n\n-- get the pipe name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get poller object type, poller.OT_PIPE\nfunction _instance:otype()\n    return 2\nend\n\n-- get cdata of pipe file\nfunction _instance:cdata()\n    return self._PIPE\nend\n\n-- write data to pipe file\nfunction _instance:write(data, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- get data address and size for bytes and string\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or datasize\n    if start < 1 or start > datasize then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > datasize + start - 1 then\n        return -1, string.format(\"%s: invalid last(%d)!\", self, last)\n    end\n\n    -- write it\n    local write = 0\n    local real = 0\n    local errors = nil\n    if opt.block then\n        local size = last + 1 - start\n        while start <= last do\n            real, errors = io.pipe_write(self:cdata(), dataaddr + start - 1, last + 1 - start)\n            if real > 0 then\n                write = write + real\n                start = start + real\n            elseif real == 0 then\n                local events, waiterrs = _instance.wait(self, pipe.EV_WRITE, opt.timeout or -1)\n                if events ~= pipe.EV_WRITE then\n                    errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n        if write ~= size then\n            write = -1\n        end\n    else\n        write, errors = io.pipe_write(self:cdata(), dataaddr + start - 1, last + 1 - start)\n        if write < 0 and errors then\n            errors = string.format(\"%s: %s\", self, errors)\n        end\n    end\n    return write, errors\nend\n\n-- read data from pipe\nfunction _instance:read(buff, size, opt)\n    assert(buff)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- check buffer\n    size = size or buff:size()\n    if buff:size() < size then\n        return -1, string.format(\"%s: too small buffer!\", self)\n    end\n\n    -- check size\n    if size == 0 then\n        return 0\n    elseif size == nil or size < 0 then\n        return -1, string.format(\"%s: invalid size(%d)!\", self, size)\n    end\n\n    -- init start in buffer\n    opt = opt or {}\n    local start = opt.start or 1\n    local pos = start - 1\n    if start >= buff:size() or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n\n    -- read it\n    local read = 0\n    local real = 0\n    local data_or_errors = nil\n    if opt.block then\n        local results = {}\n        while read < size do\n            real, data_or_errors = io.pipe_read(self:cdata(), buff:caddr() + pos + read, math.min(buff:size() - pos - read, size - read))\n            if real > 0 then\n                read = read + real\n            elseif real == 0 then\n                local events, waiterrs = _instance.wait(self, pipe.EV_READ, opt.timeout or -1)\n                if events ~= pipe.EV_READ then\n                    data_or_errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n        if read == size then\n            data_or_errors = buff:slice(start, read)\n        else\n            read = -1\n        end\n    else\n        read, data_or_errors = io.pipe_read(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n        if read > 0 then\n            data_or_errors = buff:slice(start, read)\n        end\n    end\n    if read < 0 and data_or_errors then\n        data_or_errors = string.format(\"%s: %s\", self, data_or_errors)\n    end\n    return read, data_or_errors\nend\n\n-- connect pipe, only for named pipe (server-side)\nfunction _instance:connect(opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- only for named pipe\n    if not self:name() then\n        return -1, string.format(\"%s: cannot connect to anonymous pipe!\", self)\n    end\n\n    -- connect it\n    local ok, errors = io.pipe_connect(self:cdata())\n    if ok == 0 then\n        opt = opt or {}\n        local events, waiterrs = _instance.wait(self, pipe.EV_CONN, opt.timeout or -1)\n        if events == pipe.EV_CONN then\n            ok, errors = io.pipe_connect(self:cdata())\n        else\n            errors = waiterrs\n        end\n    end\n    if ok < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- wait pipe events\nfunction _instance:wait(events, timeout)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- wait events\n    local result = -1\n    local errors = nil\n    if scheduler:co_running() then\n        result, errors = scheduler:poller_wait(self, events, timeout or -1)\n    else\n        result, errors = io.pipe_wait(self:cdata(), events, timeout or -1)\n    end\n    if result < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- close pipe file\nfunction _instance:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- cancel pipe events from the scheduler\n    if scheduler:co_running() then\n        ok, errors = scheduler:poller_cancel(self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- close it\n    ok = io.pipe_close(self:cdata())\n    if ok then\n        self._PIPE = nil\n    end\n    return ok\nend\n\n-- ensure the pipe is opened\nfunction _instance:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(pipe)\nfunction _instance:__tostring()\n    return \"<pipe: \" .. (self:name() or \"anonymous\") .. \">\"\nend\n\n-- gc(pipe)\nfunction _instance:__gc()\n    if self:cdata() and io.pipe_close(self:cdata()) then\n        self._PIPE = nil\n    end\nend\n\n-- new a pipe\nfunction pipe.new(cdata, name)\n    return _instance.new(cdata, name)\nend\n\n-- open a named pipe file\n--\n-- 1. named pipe (server-side):\n--\n-- local pipe, errors = pipe.open(\"xxx\", 'w')\n-- if pipe then\n--    if pipe:connect() then\n--        pipe:write(...)\n--    end\n--    pipe:close()\n-- end\n--\n-- 2. named pipe (client-side):\n--\n-- local pipe, errors = pipe.open(\"xxx\")\n-- if pipe then\n--    pipe:read(...)\n--    pipe:close()\n-- end\n--\n-- mode: \"r\", \"w\", \"rB\" (block), \"wB\" (block), \"rA\" (non-block), \"wA\" (non-block)\n--\nfunction pipe.open(name, mode, buffsize)\n\n    -- open named pipe\n    local pipefile, errors = io.pipe_open(name, mode, buffsize or 0)\n    if pipefile then\n        return _instance.new(pipefile, name)\n    else\n        return nil, string.format(\"failed to open pipe: %s, %s\", name, errors or \"unknown reason\")\n    end\nend\n\n-- open anonymous pipe pair\n--\n-- local rpipe, wpipe, errors = pipe.openpair()\n-- rpipe:read(...)\n-- wpipe:write(...)\n--\n-- mode:\n--\n-- \"BB\": read block/write block\n-- \"BA\": read block/write non-block\n-- \"AB\": read non-block/write block\n-- \"AA\": read non-block/write non-block (default)\n--\nfunction pipe.openpair(mode, buffsize)\n\n    -- open anonymous pipe pair\n    local rpipefile, wpipefile, errors = io.pipe_openpair(mode, buffsize or 0)\n    if rpipefile and wpipefile then\n        return _instance.new(rpipefile), _instance.new(wpipefile)\n    else\n        return nil, nil, string.format(\"failed to open anonymous pipe pair, %s\", errors or \"unknown reason\")\n    end\nend\n\n-- return module\nreturn pipe\n"
  },
  {
    "path": "xmake/core/base/poller.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        poller.lua\n--\n\n-- define module\nlocal poller = poller or {}\n\n-- load modules\nlocal io     = require(\"base/io\")\nlocal string = require(\"base/string\")\n\n-- the poller object type, @see tbox/platform/poller.h\npoller.OT_SOCK     = 1\npoller.OT_PIPE     = 2\npoller.OT_PROC     = 3\npoller.OT_FWATCHER = 4\n\n-- the poller events, @see tbox/platform/poller.h\npoller.EV_POLLER_RECV    = 1\npoller.EV_POLLER_SEND    = 2\npoller.EV_POLLER_CONN    = poller.EV_POLLER_SEND\npoller.EV_POLLER_ACPT    = poller.EV_POLLER_RECV\npoller.EV_POLLER_CLEAR   = 0x0010 -- edge trigger. after the event is retrieved by the user, its state is reset\npoller.EV_POLLER_ONESHOT = 0x0010 -- causes the event to return only the first occurrence of the filter being triggered\npoller.EV_POLLER_EOF     = 0x0100 -- the event flag will be marked if the connection be closed in the edge trigger\npoller.EV_POLLER_ERROR   = 0x0200 -- socket error after waiting\n\n-- get poller object data\nfunction poller:_pollerdata(cdata)\n    return self._POLLERDATA and self._POLLERDATA[cdata] or nil\nend\n\n-- set poller object data\nfunction poller:_pollerdata_set(cdata, data)\n    local pollerdata = self._POLLERDATA\n    if not pollerdata then\n        pollerdata = {}\n        self._POLLERDATA = pollerdata\n    end\n    pollerdata[cdata] = data\nend\n\n-- support events?\nfunction poller:support(events)\n    return io.poller_support(events)\nend\n\n-- spank poller to break the wait() and return all triggered events\nfunction poller:spank()\n    io.poller_spank()\nend\n\n-- insert object events to poller\nfunction poller:insert(obj, events, udata)\n\n    -- insert it\n    local ok, errors = io.poller_insert(obj:otype(), obj:cdata(), events)\n    if not ok then\n        return false, string.format(\"%s: insert events(%d) to poller failed, %s\", obj, events, errors or \"unknown reason\")\n    end\n\n    -- save poller object data and save obj/ref for gc\n    self:_pollerdata_set(obj:cdata(), {obj, udata})\n    return true\nend\n\n-- modify object events in poller\nfunction poller:modify(obj, events, udata)\n\n    -- modify it\n    local ok, errors = io.poller_modify(obj:otype(), obj:cdata(), events)\n    if not ok then\n        return false, string.format(\"%s: modify events(%d) to poller failed, %s\", obj, events, errors or \"unknown reason\")\n    end\n\n    -- update poller object data\n    self:_pollerdata_set(obj:cdata(), {obj, udata})\n    return true\nend\n\n-- remove object from poller\nfunction poller:remove(obj)\n\n    -- remove it\n    local ok, errors = io.poller_remove(obj:otype(), obj:cdata())\n    if not ok then\n        return false, string.format(\"%s: remove events from poller failed, %s\", obj, errors or \"unknown reason\")\n    end\n\n    -- remove poller object data\n    self:_pollerdata_set(obj, nil)\n    return true\nend\n\n-- wait object events in poller\nfunction poller:wait(timeout)\n\n    -- wait it\n    local events, count = io.poller_wait(timeout or -1)\n    if count < 0 then\n        return -1, \"wait events in poller failed!\"\n    end\n\n    -- check count\n    if count > 0 and count ~= #events then\n        return -1, string.format(\"events(%d) != %d in poller!\", #events, count)\n    end\n\n    -- wrap objects with cdata\n    local results = {}\n    if events then\n        for _, v in ipairs(events) do\n            local otype  = v[1]\n            local cdata  = v[2]\n            local events = v[3]\n            local pollerdata   = self:_pollerdata(cdata)\n            if not pollerdata then\n                return -1, string.format(\"no object data for cdata(%s)!\", cdata)\n            end\n            local obj = pollerdata[1]\n            assert(obj and obj:otype() == otype and obj:cdata() == cdata)\n            table.insert(results, {obj, events, pollerdata[2]})\n        end\n    end\n    return count, results\nend\n\n-- return module\nreturn poller\n"
  },
  {
    "path": "xmake/core/base/private/async_task.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        async_task.lua\n--\n\n-- define module: async_task\nlocal async_task = async_task or {}\n\n-- load modules\nlocal os     = require(\"base/os\")\nlocal utils  = require(\"base/utils\")\nlocal thread = require(\"base/thread\")\nlocal option = require(\"base/option\")\nlocal path   = require(\"base/path\")\nlocal pipe_event = require(\"base/private/pipe_event\")\n\n-- the task status\nlocal is_stopped = false\nlocal is_started = false\n\n-- the task event and queue\nlocal task_event = nil\nlocal task_queue = nil\nlocal task_mutex = nil\n\n-- object pool for sharedata\nlocal sharedata_pool = {}\n\nfunction async_task._absolute_dirs(searchdirs)\n    local dirs = {}\n    if searchdirs then\n        for _, directory in ipairs(searchdirs) do\n            local dir = tostring(directory)\n            if #dir > 0 then\n                table.insert(dirs, path.absolute(dir))\n            end\n        end\n    end\n    return dirs\nend\n\nfunction async_task._get_event()\n    return pipe_event.new(\"async_task\")\nend\n\nfunction async_task._put_event(event)\n    if event then\n        event:close()\n    end\nend\n\n-- get sharedata from pool or create new one\nfunction async_task._get_sharedata()\n    local sharedata = table.remove(sharedata_pool)\n    if not sharedata then\n        sharedata = thread.sharedata()\n    else\n        sharedata:clear()\n    end\n    return sharedata\nend\n\n-- return sharedata to pool\nfunction async_task._put_sharedata(sharedata)\n    if sharedata then\n        table.insert(sharedata_pool, sharedata)\n    end\nend\n\n-- the asynchronous task loop\nfunction async_task._loop(event, queue, mutex, is_stopped, is_diagnosis)\n    local os = require(\"base/os\")\n    local try = require(\"sandbox/modules/try\")\n    local thread = require(\"base/thread\")\n\n    local function dprint(...)\n        if is_diagnosis then\n            print(...)\n        end\n    end\n\n    local function _restore_thread_objects(cmd)\n        if cmd.event_data then\n            local event, errors = thread._deserialize_object(cmd.event_data)\n            assert(event, errors or \"failed to deserialize event\")\n            cmd.event = event\n        end\n        if cmd.result_data then\n            local result, errors = thread._deserialize_object(cmd.result_data)\n            assert(result, errors or \"failed to deserialize result\")\n            cmd.result = result\n        end\n    end\n\n    local function _runcmd_cp(cmd)\n        os.cp(cmd.srcpath, cmd.dstpath)\n    end\n    local function _runcmd_rm(cmd)\n        os.rm(cmd.filepath)\n    end\n    local function _runcmd_rmdir(cmd)\n        os.rmdir(cmd.dir)\n    end\n    local function _runcmd_match(cmd)\n        return os.match(cmd.pattern, cmd.mode)\n    end\n    local function _runcmd_find_file(cmd)\n        local find_file = require(\"sandbox/modules/import/lib/detect/find_file\")\n        return find_file._find_from_directories(cmd.name, cmd.searchdirs or {}, cmd.suffixes or {})\n    end\n    local function _runcmd_find_path(cmd)\n        local find_path = require(\"sandbox/modules/import/lib/detect/find_path\")\n        return find_path._find_from_directories(cmd.name, cmd.searchdirs or {}, cmd.suffixes or {})\n    end\n    local function _runcmd_find_directory(cmd)\n        local find_directory = require(\"sandbox/modules/import/lib/detect/find_directory\")\n        return find_directory._find_from_directories(cmd.name, cmd.searchdirs or {}, cmd.suffixes or {})\n    end\n    local function _runcmd_find_library(cmd)\n        local find_library = require(\"sandbox/modules/import/lib/detect/find_library\")\n        return find_library._find_from_directories(cmd.names or {}, cmd.searchdirs or {}, cmd.kinds or {}, cmd.suffixes or {}, cmd.opt or {})\n    end\n    local runops = {\n        cp    = _runcmd_cp,\n        rm    = _runcmd_rm,\n        rmdir = _runcmd_rmdir,\n        match = _runcmd_match,\n        find_file = _runcmd_find_file,\n        find_path = _runcmd_find_path,\n        find_directory = _runcmd_find_directory,\n        find_library = _runcmd_find_library\n    }\n    local function _runcmd(cmd)\n\n        _restore_thread_objects(cmd)\n\n        local ok = true\n        local errors\n        local result_data\n        local runop = runops[cmd.kind]\n        if runop then\n            try\n            {\n                function ()\n                    local ret = runop(cmd)\n                    if ret then\n                        result_data = ret\n                    end\n                end,\n                catch\n                {\n                    function (errs)\n                        ok = false\n                        errors = tostring(errs)\n                    end\n                }\n            }\n        end\n\n        -- notify completion if event is provided\n        if cmd.event and cmd.result then\n            cmd.result:set({ok = ok, errors = errors, data = result_data})\n            cmd.event:post()\n        end\n    end\n\n    dprint(\"async_task: started\")\n    while not is_stopped:get() do\n        if event:wait(-1) > 0 then\n\n            -- fetch all tasks from queue at once\n            local cmds = {}\n            mutex:lock()\n            while not queue:empty() do\n                local cmd = queue:pop()\n                if cmd then\n                    table.insert(cmds, cmd)\n                end\n            end\n            mutex:unlock()\n\n            -- execute tasks without holding lock\n            dprint(\"async_task: handling tasks(%d) ..\", #cmds)\n            for _, cmd in ipairs(cmds) do\n                _runcmd(cmd)\n            end\n        end\n    end\n    dprint(\"async_task: exited\")\nend\n\n-- start the asynchronous task\nfunction async_task._start()\n    assert(task_queue == nil and task_event == nil and task_mutex == nil)\n    task_event = thread.event()\n    task_queue = thread.queue()\n    task_mutex = thread.mutex()\n    local task_is_stopped = thread.sharedata()\n    local task_thread = thread.new(async_task._loop, {\n        name = \"core.base.async_task\", internal = true,\n        argv = {task_event, task_queue, task_mutex, task_is_stopped, option.get(\"diagnosis\")}})\n    local ok, errors = task_thread:start()\n    if not ok then\n        return false, errors\n    end\n    os.atexit(function (errors)\n        if task_thread then\n            is_stopped = true\n\n            -- Perhaps the thread hasn't started yet.\n            -- Let's wait a while and let it finish executing the tasks in the current queue.\n            utils.dprint(\"async_task: wait the pending tasks(%d) for exiting ..\", task_queue:size())\n            task_mutex:lock()\n            local is_empty = task_queue:empty()\n            task_mutex:unlock()\n            if not is_empty then\n                task_event:post()\n                os.sleep(300)\n            end\n            task_is_stopped:set(true)\n            task_event:post()\n\n            utils.dprint(\"async_task: wait thread for exiting ..\")\n            task_thread:wait(-1)\n            utils.dprint(\"async_task: wait finished\")\n        end\n    end)\n    return true\nend\n\n-- ensure the asynchronous task is started\nfunction async_task._ensure_started()\n    if is_stopped then\n        return false, string.format(\"async_task has been stopped\")\n    end\n    if not is_started then\n        local ok, errors = async_task._start()\n        if ok then\n            is_started = true\n        end\n        return ok, errors\n    end\n    assert(task_queue and task_event)\n    return true\nend\n\n-- post task and wait for result\nfunction async_task._post_task(cmd, is_detach, return_data)\n    local cmd_event\n    local cmd_result\n\n    -- create pipe and result for non-detach mode\n    if not is_detach then\n        cmd_event = async_task._get_event()\n        if not cmd_event then\n            return false, \"failed to acquire event\"\n        end\n        cmd_result = async_task._get_sharedata()\n        cmd.result_data = thread._serialize_object(cmd_result)\n        if not cmd.result_data then\n            async_task._put_sharedata(cmd_result)\n            async_task._put_event(cmd_event)\n            return false, \"failed to serialize sharedata\"\n        end\n        cmd.event_data = thread._serialize_object(cmd_event)\n        if not cmd.event_data then\n            async_task._put_sharedata(cmd_result)\n            async_task._put_event(cmd_event)\n            return false, \"failed to serialize event\"\n        end\n    end\n\n    task_mutex:lock()\n    task_queue:push(cmd)\n    task_mutex:unlock()\n\n    task_event:post()\n\n    if is_detach then\n        return true\n    end\n\n    local wait_ok, wait_errors = cmd_event:wait(-1)\n\n    local result\n    if wait_ok then\n        result = cmd_result:get()\n    end\n    async_task._put_sharedata(cmd_result)\n    async_task._put_event(cmd_event)\n\n    if not wait_ok then\n        return false, wait_errors or \"wait event failed\"\n    end\n\n    if result and result.ok then\n        if return_data then\n            local data = result.data\n            if type(data) == \"table\" then\n                return data, #data\n            elseif data ~= nil then\n                return data\n            else\n                return nil, 0\n            end\n        else\n            return true\n        end\n    else\n        if return_data then\n            return nil, 0\n        else\n            return false, result and result.errors or \"unknown error\"\n        end\n    end\nend\n\n-- copy files or directories\nfunction async_task.cp(srcpath, dstpath, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return false, errors\n    end\n    local cmd = {kind = \"cp\", srcpath = path.absolute(tostring(srcpath)), dstpath = path.absolute(tostring(dstpath))}\n    return async_task._post_task(cmd, opt.detach, false)\nend\n\n-- remove files or directories\nfunction async_task.rm(filepath, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return false, errors\n    end\n    local cmd = {kind = \"rm\", filepath = path.absolute(tostring(filepath))}\n    return async_task._post_task(cmd, opt.detach, false)\nend\n\n-- remove directories\nfunction async_task.rmdir(dir, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return false, errors\n    end\n    local cmd = {kind = \"rmdir\", dir = path.absolute(tostring(dir))}\n    return async_task._post_task(cmd, opt.detach, false)\nend\n\n-- match files or directories\nfunction async_task.match(pattern, mode)\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return nil, errors\n    end\n    local cmd = {kind = \"match\", pattern = path.absolute(tostring(pattern)), mode = mode}\n    return async_task._post_task(cmd, false, true)\nend\n\n-- find file\nfunction async_task.find_file(name, searchdirs, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return nil, errors\n    end\n    local dirs = async_task._absolute_dirs(searchdirs)\n    local suffixes = {}\n    if opt.suffixes then\n        for _, suffix in ipairs(opt.suffixes) do\n            table.insert(suffixes, tostring(suffix))\n        end\n    end\n    local cmd = {kind = \"find_file\", name = tostring(name), searchdirs = dirs, suffixes = suffixes}\n    return async_task._post_task(cmd, false, true)\nend\n\n-- find path\nfunction async_task.find_path(name, searchdirs, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return nil, errors\n    end\n    local dirs = async_task._absolute_dirs(searchdirs)\n    local suffixes = {}\n    if opt.suffixes then\n        for _, suffix in ipairs(opt.suffixes) do\n            table.insert(suffixes, tostring(suffix))\n        end\n    end\n    local cmd = {kind = \"find_path\", name = tostring(name), searchdirs = dirs, suffixes = suffixes}\n    return async_task._post_task(cmd, false, true)\nend\n\n-- find directory\nfunction async_task.find_directory(name, searchdirs, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return nil, errors\n    end\n    local dirs = async_task._absolute_dirs(searchdirs)\n    local suffixes = {}\n    if opt.suffixes then\n        for _, suffix in ipairs(opt.suffixes) do\n            table.insert(suffixes, tostring(suffix))\n        end\n    end\n    local cmd = {kind = \"find_directory\", name = tostring(name), searchdirs = dirs, suffixes = suffixes}\n    return async_task._post_task(cmd, false, true)\nend\n\n-- find library\nfunction async_task.find_library(names, searchdirs, kinds, opt)\n    opt = opt or {}\n    local ok, errors = async_task._ensure_started()\n    if not ok then\n        return nil, errors\n    end\n    local dirs = async_task._absolute_dirs(searchdirs)\n    local suffixes = {}\n    if opt.suffixes then\n        for _, suffix in ipairs(opt.suffixes) do\n            table.insert(suffixes, tostring(suffix))\n        end\n    end\n    local names_list = {}\n    if names then\n        if type(names) == \"table\" then\n            for _, name in ipairs(names) do\n                table.insert(names_list, tostring(name))\n            end\n        else\n            table.insert(names_list, tostring(names))\n        end\n    end\n    local kinds_list = {}\n    if kinds then\n        for _, kind in ipairs(kinds) do\n            table.insert(kinds_list, tostring(kind))\n        end\n    end\n    local cmd = {kind = \"find_library\", names = names_list, searchdirs = dirs, kinds = kinds_list, suffixes = suffixes, opt = {plat = opt.plat}}\n    return async_task._post_task(cmd, false, true)\nend\n\n-- return module: async_task\nreturn async_task\n\n"
  },
  {
    "path": "xmake/core/base/private/instance_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        instance_deps.lua\n--\n\n-- define module\nlocal instance_deps = instance_deps or {}\n\n-- load modules\nlocal option = require(\"base/option\")\nlocal string = require(\"base/string\")\nlocal table = require(\"base/table\")\n\n-- load deps for instance: e.g. option, instance and rule\n--\n-- e.g.\n--\n-- a.deps = b\n-- b.deps = c\n-- foo.deps = a d\n--\n-- foo.orderdeps: d -> c -> b -> a\n--\n-- if they're targets, their links order is reverse(orderdeps), e.g. foo: a -> b -> c -> d\n--\nfunction instance_deps.load_deps(instance, instances, deps, orderdeps, depspath, walkdep)\n    local plaindeps = table.wrap(instance:get(\"deps\"))\n    local total = #plaindeps\n    for idx, _ in ipairs(plaindeps) do\n        -- we reverse to get the flat dependencies in order to ensure the correct linking order\n        -- @see https://github.com/xmake-io/xmake/issues/3144\n        local depname = plaindeps[total + 1 - idx]\n        local depinst = instances[depname]\n        if depinst == nil and instance.namespace then\n            local namespace = instance:namespace()\n            if namespace then\n                depinst = instances[namespace .. \"::\" .. depname]\n            end\n        end\n        if depinst then\n            local continue_walk = true\n            if walkdep then\n                continue_walk = walkdep(instance, depinst)\n            end\n            if continue_walk then\n                if not deps[depname] then\n                    deps[depname] = depinst\n                    local depspath_sub\n                    if depspath then\n                        for idx, name in ipairs(depspath) do\n                            if name == depname then\n                                local circular_deps = table.slice(depspath, idx)\n                                table.insert(circular_deps, depname)\n                                os.raise(\"circular dependency(%s) detected!\", table.concat(circular_deps, \", \"))\n                            end\n                        end\n                        depspath_sub = table.join(depspath, depname)\n                    end\n                    instance_deps.load_deps(depinst, instances, deps, orderdeps, depspath_sub, walkdep)\n                    table.insert(orderdeps, depinst)\n                end\n            end\n        end\n    end\nend\n\n-- sort the given instance with deps\nfunction instance_deps._sort_instance(instance, instances, orderinstances, instancerefs, depspath)\n    if not instancerefs[instance:fullname()] then\n        instancerefs[instance:fullname()] = true\n        for _, depname in ipairs(table.wrap(instance:get(\"deps\"))) do\n            local depinst = instances[depname]\n            if depinst == nil and instance.namespace then\n                local namespace = instance:namespace()\n                if namespace then\n                    depinst = instances[namespace .. \"::\" .. depname]\n                end\n            end\n            if depinst then\n                local depspath_sub\n                if depspath then\n                    for idx, name in ipairs(depspath) do\n                        if name == depname then\n                            local circular_deps = table.slice(depspath, idx)\n                            table.insert(circular_deps, depname)\n                            os.raise(\"circular dependency(%s) detected!\", table.concat(circular_deps, \", \"))\n                        end\n                    end\n                    depspath_sub = table.join(depspath, depinst:fullname())\n                end\n                instance_deps._sort_instance(depinst, instances, orderinstances, instancerefs, depspath_sub)\n            end\n        end\n        table.insert(orderinstances, instance)\n    end\nend\n\n-- sort instances with deps\n--\n-- e.g.\n--\n-- a.deps = b\n-- b.deps = c\n-- foo.deps = a d\n--\n-- orderdeps: c -> b -> a -> d -> foo\nfunction instance_deps.sort(instances)\n    local refs = {}\n    local orderinstances = {}\n    for _, instance in table.orderpairs(instances) do\n        instance_deps._sort_instance(instance, instances, orderinstances, refs, {instance:fullname()})\n    end\n    return orderinstances\nend\n\n-- return module\nreturn instance_deps\n\n"
  },
  {
    "path": "xmake/core/base/private/is_cross.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_cross.lua\n--\n\n-- load modules\nlocal os = require(\"base/os\")\n\n-- is cross-compilation?\nfunction is_cross(plat, arch)\n    plat = plat or os.subhost()\n    arch = arch or os.subarch()\n    local host_os = os.host()\n    if host_os == \"windows\" then\n        if plat == \"windows\" then\n            local host_arch = os.arch()\n            -- maybe cross-compilation for arm64 on x86/x64\n            if (host_arch == \"x86\" or host_arch == \"x64\") and arch == \"arm64\" then\n                return true\n            -- maybe cross-compilation for x86/64 on arm64\n            elseif host_arch == \"arm64\" and arch ~= \"arm64\" then\n                return true\n            end\n            return false\n        elseif plat == \"mingw\" then\n            return false\n        end\n    end\n    if plat ~= os.host() and plat ~= os.subhost() then\n        return true\n    end\n    if arch ~= os.arch() and arch ~= os.subarch() then\n        return true\n    end\n    return false\nend\n\nreturn is_cross\n"
  },
  {
    "path": "xmake/core/base/private/match_copyfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        match_copyfiles.lua\n--\n\n-- load modules\nlocal table = require(\"base/table\")\nlocal utils = require(\"base/utils\")\nlocal path  = require(\"base/path\")\nlocal os    = require(\"base/os\")\n\n-- match the copyfiles for instance\n-- e.g.\n--\n-- add_headerfiles\n-- add_configfiles\n-- add_installfiles\n-- add_extrafiles\nfunction match_copyfiles(instance, filetype, outputdir, opt)\n    opt = opt or {}\n\n    -- get copyfiles?\n    local copyfiles = opt.copyfiles or instance:get(filetype)\n    if not copyfiles then\n        return\n    end\n\n    -- get the extra information\n    local extrainfo = table.wrap(instance:extraconf(filetype))\n\n    -- get the source paths and destinate paths\n    local srcfiles = {}\n    local dstfiles = {}\n    local fileinfos = {}\n    local srcfiles_removed = {}\n    local removed_count = 0\n    for _, copyfile in ipairs(table.wrap(copyfiles)) do\n\n        -- mark as removed files?\n        local removed = false\n        local prefix = \"__remove_\"\n        if copyfile:startswith(prefix) then\n            copyfile = copyfile:sub(#prefix + 1)\n            removed = true\n        end\n\n        -- get the root directory\n        local rootdir, count = copyfile:gsub(\"|.*$\", \"\"):gsub(\"%(.*%)$\", \"\")\n        if count == 0 then\n            rootdir = nil\n        end\n        if rootdir and rootdir:trim() == \"\" then\n            rootdir = \".\"\n        end\n\n        -- remove '(' and ')'\n        local srcpaths = copyfile:gsub(\"[%(%)]\", \"\")\n        if srcpaths then\n\n            -- get the source paths\n            srcpaths = os.match(srcpaths)\n            if srcpaths and #srcpaths > 0 then\n                if removed then\n                    removed_count = removed_count + #srcpaths\n                    table.join2(srcfiles_removed, srcpaths)\n                else\n\n                    -- add the source copied files\n                    table.join2(srcfiles, srcpaths)\n\n                    -- get the file info\n                    local fileinfo = extrainfo[copyfile] or {}\n\n                    -- get the prefix directory\n                    local prefixdir = fileinfo.prefixdir\n                    if fileinfo.rootdir then\n                        rootdir = fileinfo.rootdir\n                    end\n\n                    -- add the destinate copied files\n                    for _, srcpath in ipairs(srcpaths) do\n\n                        if outputdir then\n                            -- get the destinate directory\n                            local dstdir = outputdir\n                            if prefixdir then\n                                dstdir = path.join(dstdir, prefixdir)\n                            end\n\n                            -- the destinate file\n                            local dstfile = nil\n                            if rootdir then\n                                dstfile = path.absolute(path.relative(srcpath, rootdir), dstdir)\n                            else\n                                dstfile = path.join(dstdir, path.filename(srcpath))\n                            end\n                            assert(dstfile)\n\n                            -- modify filename\n                            if fileinfo.filename then\n                                dstfile = path.join(path.directory(dstfile), fileinfo.filename)\n                            end\n\n                            -- filter the destinate file path\n                            if opt.pathfilter then\n                                dstfile = opt.pathfilter(dstfile, fileinfo)\n                            end\n\n                            -- add it\n                            table.insert(dstfiles, dstfile)\n                        end\n\n                        table.insert(fileinfos, fileinfo)\n                    end\n                end\n            end\n        end\n    end\n\n    -- remove all srcfiles which need be removed\n    if removed_count > 0 then\n        table.remove_if(srcfiles, function (i, srcfile)\n            for _, removed_file in ipairs(srcfiles_removed) do\n                local pattern = path.translate((removed_file:gsub(\"|.*$\", \"\")))\n                if pattern:sub(1, 2):find('%.[/\\\\]') then\n                    pattern = pattern:sub(3)\n                end\n                pattern = path.pattern(pattern)\n                if srcfile:match(pattern) then\n                    if i <= #dstfiles then\n                        table.remove(dstfiles, i)\n                    end\n                    return true\n                end\n            end\n        end)\n    end\n    return srcfiles, dstfiles, fileinfos\nend\n\nreturn match_copyfiles\n"
  },
  {
    "path": "xmake/core/base/private/pipe_event.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pipe_event.lua\n--\n\n-- define module\nlocal pipe_event = pipe_event or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal pipe   = require(\"base/pipe\")\nlocal libc   = require(\"base/libc\")\nlocal bytes  = require(\"base/bytes\")\nlocal table  = require(\"base/table\")\n\nfunction _instance.new(name)\n    local event = table.inherit(_instance)\n    event._PIPE_EVENT = true\n    event._BUFFER = bytes(2)\n    event._NAME = name or \"pipe_event\"\n    local reader, writer, errors = pipe.openpair(\"AA\")\n    if not reader or not writer then\n        if reader then reader:close() end\n        if writer then writer:close() end\n        return nil, errors or \"failed to open pipe\"\n    end\n    event._READER = reader\n    event._WRITER = writer\n    event._WRITER_PTR = nil\n    return event\nend\n\nfunction _instance:name()\n    return self._NAME\nend\n\nfunction _instance:post()\n    local writer = self._WRITER\n    if not writer then\n        return false, \"pipe event writer closed\"\n    end\n    local ok, errors = writer:write(\"1\", {block = true})\n    if ok < 0 then\n        return false, errors or \"pipe event post failed\"\n    end\n    writer:close()\n    self._WRITER = nil\n    self._WRITER_PTR = nil\n    return true\nend\n\nfunction _instance:wait(timeout)\n    if not self._READER then\n        return false, \"pipe event reader closed\"\n    end\n    local read, read_errors = self._READER:read(self._BUFFER, 1, {block = true, timeout = timeout})\n    if read < 0 then\n        return false, read_errors\n    end\n    return read\nend\n\nfunction _instance:close()\n    if self._READER then\n        self._READER:close()\n    end\n    if self._WRITER then\n        self._WRITER:close()\n    end\n    self._READER = nil\n    self._WRITER = nil\n    self._WRITER_PTR = nil\nend\n\n-- return pipe cdata for serialization (writer pointer is stable for passing across threads)\nfunction _instance:cdata()\n    if self._WRITER then\n        return self._WRITER:cdata()\n    end\n    return self._WRITER_PTR\nend\n\nfunction _instance:__gc()\n    self:close()\nend\n\nfunction _instance:_serialize()\n    if not self._WRITER and self._WRITER_PTR then\n        return {ptr = self._WRITER_PTR, name = self:name()}\n    end\n    if not self._WRITER then\n        return nil\n    end\n    local ptr = libc.dataptr(self._WRITER:cdata(), {ffi = false})\n    if not ptr then\n        return nil\n    end\n    self._WRITER._PIPE = nil\n    self._WRITER = nil\n    self._WRITER_PTR = ptr\n    return {ptr = ptr, name = self:name()}\nend\n\nfunction _instance:_deserialize(data)\n    if not data or not data.ptr then\n        return false, \"invalid pipe event data\"\n    end\n    self:close()\n    local writer = pipe.new(libc.ptraddr(data.ptr, {ffi = false}))\n    if not writer then\n        return false, \"invalid pipe pointer\"\n    end\n    self._NAME = data.name or self._NAME or \"pipe_event\"\n    self._WRITER = writer\n    self._WRITER_PTR = data.ptr\n    return true\nend\n\nfunction pipe_event.new(name)\n    return _instance.new(name)\nend\n\nreturn pipe_event\n\n\n"
  },
  {
    "path": "xmake/core/base/private/select_script.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        select_script.lua\n--\n\n-- load modules\nlocal table   = require(\"base/table\")\nlocal utils   = require(\"base/utils\")\nlocal hashset = require(\"base/hashset\")\n\n-- match pattern, matched mode: plat|arch, excluded mode: !plat|arch\nfunction _match_pattern(pattern, plat, arch, opt)\n    opt = opt or {}\n    local excluded = opt.excluded\n    local subhost = opt.subhost or os.subhost()\n    local subarch = opt.subarch or os.subarch()\n    local splitinfo = pattern:split(\"|\", {strict = true, plain = true})\n    local pattern_plat = splitinfo[1]\n    local pattern_arch = splitinfo[2]\n    if pattern_plat and #pattern_plat > 0 then\n        local matched = false\n        local is_excluded_pattern = pattern_plat:find('!', 1, true)\n        if excluded and is_excluded_pattern then\n            matched = not ('!' .. plat):match('^' .. pattern_plat .. '$')\n        elseif not is_excluded_pattern then\n            matched = plat:match('^' .. pattern_plat .. '$')\n        end\n        if not matched then\n            return false\n        end\n    end\n    if pattern_arch and #pattern_arch > 0 then\n        -- support native arch, e.g. macosx|native\n        -- @see https://github.com/xmake-io/xmake/issues/4657\n        pattern_arch = pattern_arch:gsub(\"native\", subarch)\n\n        local matched = false\n        local is_excluded_pattern = pattern_arch:find('!', 1, true)\n        if excluded and is_excluded_pattern then\n            matched = not ('!' .. arch):match('^' .. pattern_arch .. '$')\n        elseif not is_excluded_pattern then\n            matched = arch:match('^' .. pattern_arch .. '$')\n        end\n        if not matched then\n            return false\n        end\n    end\n    if not pattern_plat and not pattern_arch then\n        os.raise(\"invalid script pattern: %s\", pattern)\n    end\n    return true\nend\n\n\n-- match patterns\nfunction _match_patterns(patterns, plat, arch, opt)\n    for _, pattern in ipairs(patterns) do\n        if _match_pattern(pattern, plat, arch, opt) then\n            return true\n        end\n    end\nend\n\n-- mattch the script pattern\n--\n-- @note interpreter has converted pattern to a lua pattern ('*' => '.*')\n--\n-- matched pattern:\n--  plat|arch@subhost|subarch\n--\n-- e.g.\n--\n-- `@linux`\n-- `@linux|x86_64`\n-- `@macosx,linux`\n-- `android@macosx,linux`\n-- `android|armeabi-v7a@macosx,linux`\n-- `android|armeabi-v7a,iphoneos@macosx,linux|x86_64`\n-- `android|armeabi-v7a@linux|x86_64`\n-- `linux|*`\n--\n-- excluded pattern:\n--  !plat|!arch@!subhost|!subarch\n--\n-- e.g.\n--\n-- `@!linux`\n-- `@!linux|x86_64`\n-- `@!macosx,!linux`\n-- `!android@macosx,!linux`\n-- `android|!armeabi-v7a@macosx,!linux`\n-- `android|armeabi-v7a,!iphoneos@macosx,!linux|x86_64`\n-- `!android|armeabi-v7a@!linux|!x86_64`\n-- `!linux|*`\n--\nfunction _match_script_pattern(pattern, opt)\n    opt = opt or {}\n    local splitinfo = pattern:split(\"@\", {strict = true, plain = true})\n    local plat_part = splitinfo[1]\n    local host_part = splitinfo[2]\n    local plat_patterns\n    if plat_part and #plat_part > 0 then\n        plat_patterns = plat_part:split(\",\", {plain = true})\n    end\n    local host_patterns\n    if host_part and #host_part > 0 then\n        host_patterns = host_part:split(\",\", {plain = true})\n    end\n    local plat = opt.plat or \"\"\n    local arch = opt.arch or \"\"\n    local subhost = opt.subhost or os.subhost()\n    local subarch = opt.subarch or os.subarch()\n    if plat_patterns and #plat_patterns > 0 then\n        if _match_patterns(plat_patterns, plat, arch, opt) then\n            if host_patterns and #host_patterns > 0 and\n                not _match_patterns(host_patterns, subhost, subarch, opt) then\n                return false\n            end\n            return true\n        end\n    else\n        if host_patterns and #host_patterns > 0 then\n            return _match_patterns(host_patterns, subhost, subarch, opt)\n        end\n    end\nend\n\n-- match the script expression pattern\n--\n-- e.g.\n-- !wasm|!arm* and !cross|!arm*\n-- wasm|!arm* or cross\n-- (!macosx and !iphoneos) or (!linux|!arm* and !cross|!arm*)\n--\nfunction _match_script(pattern, opt)\n    local idx = 0\n    local funcs = {}\n    local keywords = hashset.of(\"and\", \"or\")\n    local has_logical_op = false\n    local pattern_expr = pattern:gsub(\"[^%(%)%s]+\", function (w)\n        if keywords:has(w) then\n            has_logical_op = true\n            return\n        end\n        local name = \"func_\" .. idx\n        local func = function ()\n            return _match_script_pattern(w, opt)\n        end\n        funcs[name] = func\n        idx = idx + 1\n        return name .. \"()\"\n    end)\n    if has_logical_op then\n        local script = assert(load(\"return (\" .. pattern_expr .. \")\"), \"invalid pattern: \" .. pattern)\n        setfenv(script, funcs)\n        local ok, results = utils.trycall(script)\n        if not ok then\n            os.raise(\"invalid pattern: %s, error: %s\", pattern, results or \"unknown\")\n        end\n        return results\n    else\n        return _match_script_pattern(pattern, opt)\n    end\nend\n\n-- select the matched pattern script for the current platform/architecture\nfunction select_script(scripts, opt)\n    opt = opt or {}\n    local result = nil\n    if type(scripts) == \"function\" then\n        result = scripts\n    elseif type(scripts) == \"table\" then\n        local script_matched\n        for pattern, script in pairs(scripts) do\n            if not pattern:startswith(\"__\") and _match_script(pattern, opt) then\n                script_matched = script\n                break\n            end\n        end\n        if not script_matched then\n            local scripts_fallback = {}\n            local patterns_fallback = {}\n            local excluded_opt = table.join(opt, {excluded = true})\n            for pattern, script in pairs(scripts) do\n                if not pattern:startswith(\"__\") and _match_script(pattern, excluded_opt) then\n                    table.insert(scripts_fallback, script)\n                    table.insert(patterns_fallback, pattern)\n                end\n            end\n            script_matched = scripts_fallback[1]\n            if script_matched and #scripts_fallback > 0 then\n                local conflict_patterns = {patterns_fallback[1]}\n                for idx, script in ipairs(scripts_fallback) do\n                    local pattern = patterns_fallback[idx]\n                    if script ~= script_matched then\n                        table.insert(conflict_patterns, pattern)\n                    end\n                end\n                if #conflict_patterns > 1 then\n                    utils.warning(\"multiple script patterns are matched, %s\", table.concat(conflict_patterns, \", \"))\n                end\n            end\n        end\n        result = script_matched or scripts[\"__generic__\"]\n    end\n    return result\nend\n\nreturn select_script\n"
  },
  {
    "path": "xmake/core/base/privilege.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      TitanSnow\n-- @file        privilege.lua\n--\n\n-- define module\nlocal privilege = privilege or {}\n\n-- load modules\nlocal os = require(\"base/os\")\n\n-- store privilege\nfunction privilege.store()\n\n    -- check if root\n    if not os.isroot() then\n        return false\n    end\n\n    local owner = {}\n    -- sudo will set SUDO_UID & SUDO_GID\n    -- so that can easily get original uid & gid\n    local sudo_uid = os.getenv(\"SUDO_UID\")\n    local sudo_gid = os.getenv(\"SUDO_GID\")\n    if sudo_uid and sudo_gid then\n        owner.uid = sudo_uid\n        owner.gid = sudo_gid\n    else\n        -- find projectdir's owner\n        local projectdir = xmake._PROJECT_DIR\n        assert(projectdir)\n        owner = os.getown(projectdir)\n        if not owner then\n\n            -- fallback to current dir\n            owner = os.getown(os.curdir())\n            if not owner then\n                return false\n            end\n        end\n    end\n\n    -- set gid\n    if os.gid(owner.gid).errno ~= 0 then\n        return false\n    end\n\n    -- set uid\n    if os.uid({ruid = owner.uid}).errno ~= 0 or os.uid({euid = owner.uid}).errno ~= 0 then\n        return false\n    end\n\n    -- set flag\n    privilege._HAS_PRIVILEGE = true\n\n    -- ok\n    return true\nend\n\n-- check if has stored privilege\nfunction privilege.has()\n    return privilege._HAS_PRIVILEGE or false\nend\n\nfunction privilege.get()\n\n    -- has?\n    if privilege._HAS_PRIVILEGE ~= true then\n        return false\n    end\n\n    -- set uid\n    if os.uid({euid = 0}).errno ~= 0 or os.uid({ruid = 0}).errno ~= 0 then\n        return false\n    end\n\n    -- set gid\n    if os.gid(0).errno ~= 0 then\n        return false\n    end\n\n    return true\nend\n\n-- return module\nreturn privilege\n"
  },
  {
    "path": "xmake/core/base/process.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        process.lua\n--\n\n-- define module: process\nlocal process   = process or {}\nlocal _subprocess = _subprocess or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal path      = require(\"base/path\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal coroutine = require(\"base/coroutine\")\nlocal scheduler = require(\"base/scheduler\")\n\n-- save original interfaces\nprocess._open       = process._open or process.open\nprocess._openv      = process._openv or process.openv\nprocess._wait       = process._wait or process.wait\nprocess._kill       = process._kill or process.kill\nprocess._close      = process._close or process.close\nprocess.wait        = nil\nprocess.kill        = nil\nprocess.close       = nil\nprocess._subprocess = _subprocess\n\n-- new an subprocess\nfunction _subprocess.new(program, proc)\n    local subprocess = table.inherit(_subprocess)\n    subprocess._PROGRAM = program\n    subprocess._PROC    = proc\n    setmetatable(subprocess, _subprocess)\n    return subprocess\nend\n\n-- get the process name\nfunction _subprocess:name()\n    if not self._NAME then\n        self._NAME = path.filename(self:program())\n    end\n    return self._NAME\nend\n\n-- get the process program\nfunction _subprocess:program()\n    return self._PROGRAM\nend\n\n-- get cdata of process\nfunction _subprocess:cdata()\n    return self._PROC\nend\n\n-- get poller object type, poller.OT_PROC\nfunction _subprocess:otype()\n    return 3\nend\n\n-- wait subprocess\n--\n-- @param timeout   the timeout\n--\n-- @return          ok, status\n--\nfunction _subprocess:wait(timeout)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- wait events\n    local result = -1\n    local status_or_errors = nil\n    if scheduler:co_running() then\n        result, status_or_errors = scheduler:poller_waitproc(self, timeout or -1)\n    else\n        result, status_or_errors = process._wait(self:cdata(), timeout or -1)\n    end\n    if result < 0 and status_or_errors then\n        status_or_errors = string.format(\"%s: %s\", self, status_or_errors)\n    end\n    return result, status_or_errors\nend\n\n-- kill subprocess\nfunction _subprocess:kill()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- kill process\n    process._kill(self:cdata())\n    return true\nend\n\n-- close subprocess\nfunction _subprocess:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- cancel pipe events from the scheduler\n    if scheduler:co_running() then\n        ok, errors = scheduler:poller_cancel(self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- close process\n    ok = process._close(self:cdata())\n    if ok then\n        self._PROC = nil\n    end\n    return ok\nend\n\n-- ensure the process is opened\nfunction _subprocess:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(subprocess)\nfunction _subprocess:__tostring()\n    return \"<subprocess: \" .. self:name() .. \">\"\nend\n\n-- gc(subprocess)\nfunction _subprocess:__gc()\n    if self._PROC and process._close(self._PROC) then\n        self._PROC = nil\n    end\nend\n\n-- open a subprocess\n--\n-- @param command   the process command\n-- @param opt       the option arguments, e.g. {stdin = filepath/file/pipe, stdout = filepath/file/pipe, stderr = filepath/file/pipe, envs = {\"PATH=xxx\", \"XXX=yyy\"}})\n--\n-- @return          the subprocess\n--\nfunction process.open(command, opt)\n\n    -- get stdin and pass to subprocess\n    opt = opt or {}\n    local stdin = opt.stdin\n    if type(stdin) == \"string\" then\n        opt.inpath = stdin\n    elseif type(stdin) == \"table\" then\n        if stdin.otype and stdin:otype() == 2 then\n            opt.inpipe = stdin:cdata()\n        else\n            opt.infile = stdin:cdata()\n        end\n    end\n\n    -- get stdout and pass to subprocess\n    local stdout = opt.stdout\n    if type(stdout) == \"string\" then\n        opt.outpath = stdout\n    elseif type(stdout) == \"table\" then\n        if stdout.otype and stdout:otype() == 2 then\n            opt.outpipe = stdout:cdata()\n        else\n            opt.outfile = stdout:cdata()\n        end\n    end\n\n    -- get stderr and pass to subprocess\n    local stderr = opt.stderr\n    if type(stderr) == \"string\" then\n        opt.errpath = stderr\n    elseif type(stderr) == \"table\" then\n        if stderr.otype and stderr:otype() == 2 then\n            opt.errpipe = stderr:cdata()\n        else\n            opt.errfile = stderr:cdata()\n        end\n    end\n\n    -- open subprocess\n    local proc = process._open(command, opt)\n    if proc then\n        return _subprocess.new(command:split(' ', {plain = true})[1], proc)\n    else\n        return nil, string.format(\"open process(%s) failed!\", command)\n    end\nend\n\n-- open a subprocess with the arguments list\n--\n-- @param program   the program\n-- @param argv      the arguments list\n-- @param opt       the option arguments, e.g. {stdin = filepath/file/pipe, stdout = filepath/file/pipe, stderr = filepath/file/pipe, envs = {\"PATH=xxx\", \"XXX=yyy\"}})\n--\n-- @return          the subprocess\n--\nfunction process.openv(program, argv, opt)\n\n    -- get stdin and pass to subprocess\n    opt = opt or {}\n    local stdin = opt.stdin\n    if type(stdin) == \"string\" then\n        opt.inpath = stdin\n    elseif type(stdin) == \"table\" then\n        if stdin.otype and stdin:otype() == 2 then\n            opt.inpipe = stdin:cdata()\n        else\n            opt.infile = stdin:cdata()\n        end\n    end\n\n    -- get stdout and pass to subprocess\n    local stdout = opt.stdout\n    if type(stdout) == \"string\" then\n        opt.outpath = stdout\n    elseif type(stdout) == \"table\" then\n        if stdout.otype and stdout:otype() == 2 then\n            opt.outpipe = stdout:cdata()\n        else\n            opt.outfile = stdout:cdata()\n        end\n    end\n\n    -- get stderr and pass to subprocess\n    local stderr = opt.stderr\n    if type(stderr) == \"string\" then\n        opt.errpath = stderr\n    elseif type(stderr) == \"table\" then\n        if stderr.otype and stderr:otype() == 2 then\n            opt.errpipe = stderr:cdata()\n        else\n            opt.errfile = stderr:cdata()\n        end\n    end\n\n    -- open subprocess\n    local proc = process._openv(program, argv, opt)\n    if proc then\n        return _subprocess.new(program, proc)\n    else\n        return nil, string.format(\"openv process(%s, %s) failed!\", program, os.args(argv))\n    end\nend\n\n-- get missing dlls\nfunction process._get_missing_dlls(program)\n    local missing = {}\n    if not os.isexec(program) then\n        return missing\n    end\n\n    -- get paths\n    local pathenv = os.getenv(\"PATH\") or \"\"\n    local paths = path.splitenv(pathenv)\n    table.insert(paths, 1, path.directory(program))\n\n    -- find missing dlls\n    local sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\n    local get_depend_libraries = sandbox_module.import(\"utils.binary.deplibs\", {anonymous = true})\n    local imports = get_depend_libraries(program, {recursive = true}) or {}\n    for i, dll in ipairs(imports) do\n        imports[i] = path.filename(dll)\n    end\n    for _, dll in ipairs(imports) do\n        local found = false\n        for _, p in ipairs(paths) do\n            if os.isfile(path.join(p, dll)) then\n                found = true\n                break\n            end\n        end\n        if not found then\n            table.insert(missing, dll)\n        end\n    end\n    return missing\nend\n\n-- get process exit errors\nfunction process.get_exit_errors(program, exitcode)\n    local errors\n    if os.is_host(\"windows\") then\n        -- DLL is missing, 0xC0000135\n        if exitcode == -1073741515 then\n            local missing_dlls = process._get_missing_dlls(program)\n            if #missing_dlls > 0 then\n                errors = string.format(\"system error 0xC0000135 (STATUS_DLL_NOT_FOUND).\\nThe application failed to start because the following DLLs were not found:\\n  - %s\\nPlease check your PATH environment variable or copy the missing DLLs to the executable directory.\", table.concat(missing_dlls, \"\\n  - \"))\n            else\n                errors = string.format(\"system error 0xC0000135 (STATUS_DLL_NOT_FOUND).\\nThe application failed to start because a dependent DLL was not found.\\nPlease check your PATH environment variable or copy the missing DLL to the executable directory.\")\n            end\n        end\n    end\n    return errors\nend\n\n\n-- return module: process\nreturn process\n"
  },
  {
    "path": "xmake/core/base/profiler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        profiler.lua\n--\n\n-- define module\nlocal profiler = {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal heap      = require(\"base/heap\")\nlocal table     = require(\"base/table\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\n\n-- get the function key\nfunction profiler:_func_key(funcinfo)\n    local name = funcinfo.name or 'anonymous'\n    local line = funcinfo.linedefined or 0\n    local source = funcinfo.short_src or 'C_FUNC'\n    return name .. source .. line\nend\n\n-- get the function title\nfunction profiler:_func_title(funcinfo)\n    local name = funcinfo.name or 'anonymous'\n    local line = string.format(\"%d\", funcinfo.linedefined or 0)\n    local source = funcinfo.short_src or 'C_FUNC'\n    if os.isfile(source) then\n        source = path.relative(source, xmake._PROGRAM_DIR)\n    end\n    return string.format(\"%-30s: %s: %s\", name, source, line)\nend\n\n-- get the function report\nfunction profiler:_func_report(funcinfo)\n    local key = self:_func_key(funcinfo)\n    local report = self._REPORTS_BY_KEY[key]\n    if not report then\n        report = {\n            funcinfo    = funcinfo,\n            callcount   = 0,\n            totaltime   = 0\n        }\n        self._REPORTS_BY_KEY[key] = report\n        table.insert(self._REPORTS, report)\n    end\n    return report\nend\n\n-- get the tag key\nfunction profiler:_tag_key(name, argv)\n    local key = name\n    if argv then\n        for _, item in ipairs(argv) do\n            if type(item) == \"table\" then\n                key = key .. os.args(item)\n            else\n                key = key .. tostring(item)\n            end\n        end\n    end\n    return key\nend\n\n-- get the tag title\nfunction profiler:_tag_title(name, argv)\n    local key = name\n    if argv then\n        for _, item in ipairs(argv) do\n            if type(item) == \"table\" then\n                key = key .. \": \" .. os.args(item)\n            else\n                key = key .. \": \" .. tostring(item)\n            end\n        end\n    end\n    return key\nend\n\n-- get the tag report\nfunction profiler:_tag_report(name, argv)\n    self._REPORTS_BY_KEY = self._REPORTS_BY_KEY or {}\n    local key = self:_tag_key(name, argv)\n    local report = self._REPORTS_BY_KEY[key]\n    if not report then\n        report = {\n            name        = name,\n            argv        = argv,\n            callcount   = 0,\n            totaltime   = 0\n        }\n        self._REPORTS_BY_KEY[key] = report\n        self._REPORTS = self._REPORTS or {}\n        table.insert(self._REPORTS, report)\n    end\n    return report\nend\n\n-- profiling call\nfunction profiler:_profiling_call(funcinfo)\n    local report = self:_func_report(funcinfo)\n    report.calltime    = os.mclock()\n    report.callcount   = report.callcount + 1\nend\n\n-- profiling return\nfunction profiler:_profiling_return(funcinfo)\n    local stoptime = os.mclock()\n    local report = self:_func_report(funcinfo)\n    if report.calltime and report.calltime > 0 then\n\t\treport.totaltime = report.totaltime + (stoptime - report.calltime)\n        report.calltime = 0\n\tend\nend\n\n-- the profiling handler\nfunction profiler._profiling_handler(hooktype)\n    local funcinfo = debug.getinfo(2, 'nS')\n    if hooktype == \"call\" then\n        profiler:_profiling_call(funcinfo)\n    elseif hooktype == \"return\" then\n        profiler:_profiling_return(funcinfo)\n    end\nend\n\n-- the tracing handler\nfunction profiler._tracing_handler(hooktype)\n    local funcinfo = debug.getinfo(2, 'nS')\n    if hooktype == \"call\" then\n        local name = funcinfo.name\n        local source = funcinfo.short_src\n        if name and source and source:endswith(\".lua\") then\n            local line = string.format(\"%d\", funcinfo.linedefined or 0)\n            utils.print(\"%-30s: %s: %s\", name, source, line)\n        end\n    end\nend\n\n-- start profiling\nfunction profiler:start()\n    if self:is_trace() then\n        debug.sethook(profiler._tracing_handler, 'cr', 0)\n    elseif self:is_perf(\"call\") then\n        self._REPORTS        = self._REPORTS or {}\n        self._REPORTS_BY_KEY = self._REPORTS_BY_KEY or {}\n        self._STARTIME       = self._STARTIME or os.mclock()\n        debug.sethook(profiler._profiling_handler, 'cr', 0)\n    end\nend\n\n-- stop profiling\nfunction profiler:stop()\n    if self:is_trace() then\n        debug.sethook()\n    elseif self:is_perf(\"call\") then\n        self._STOPTIME = os.mclock()\n        debug.sethook()\n\n        -- calculate the total time\n        local totaltime = self._STOPTIME - self._STARTIME\n\n        -- sort reports\n        local reports = self._REPORTS or {}\n        table.sort(reports, function(a, b)\n            return a.totaltime > b.totaltime\n        end)\n\n        -- show and save reports\n        local report_lines = \"\"\n        local outfile = path.join(os.tmpdir(), \"perf-call-\" .. os.date(\"%d-%m-%y-%S-%M-%H\") .. \".log\")\n        for _, report in ipairs(reports) do\n            local percent = (report.totaltime / totaltime) * 100\n            if percent < 1 then\n                break\n            end\n            local report_line = string.format(\"%6.3f, %6.2f%%, %7d, %s\", report.totaltime / 1000.0, percent, report.callcount, self:_func_title(report.funcinfo))\n            report_lines = report_lines .. report_line .. \"\\n\"\n            utils.print(report_line)\n        end\n        utils.print(\"full log written to %s\", outfile)\n        io.writefile(outfile, report_lines)\n    elseif self:is_perf(\"tag\") then\n\n        -- sort reports, topN\n        local reports = self._REPORTS or {}\n        local h = heap.valueheap({cmp = function(a, b)\n            return a.totaltime > b.totaltime\n        end})\n        for _, report in ipairs(reports) do\n            h:push(report)\n        end\n\n        -- show and save reports\n        local count = 0\n        local max_count = 64\n        local outfile = path.join(os.tmpdir(), \"perf-tag-\" .. os.date(\"%d-%m-%y-%S-%M-%H\") .. \".log\")\n        local report_lines = \"\"\n        while h:length() > 0 do\n            local report = h:pop()\n            local report_line = string.format(\"%6.3f, %7d, %s\", report.totaltime / 1000.0, report.callcount, self:_tag_title(report.name, report.argv))\n            report_lines = report_lines .. report_line .. \"\\n\"\n            count = count + 1\n        end\n        if count <= max_count then\n            utils.print(report_lines)\n        elseif count > max_count then\n            local max_count_lines = {table.unpack(report_lines:split(\"\\n\"), 1, max_count)}\n            utils.print(table.concat(max_count_lines, \"\\n\"))\n            utils.print(\"...\")\n            count = count + 1\n        end\n        utils.print(\"full log written to %s\", outfile)\n        io.writefile(outfile, report_lines)\n   end\nend\n\n-- enter the given tag for perf:tag\nfunction profiler:enter(name, ...)\n    local is_perf_tag = self._IS_PERF_TAG\n    if is_perf_tag == nil then\n        is_perf_tag = self:is_perf(\"tag\")\n        self._IS_PERF_TAG = is_perf_tag\n    end\n    if is_perf_tag then\n        local argv = table.pack(...)\n        local report = self:_tag_report(name, argv)\n        report.calltime    = os.mclock()\n        report.callcount   = report.callcount + 1\n    end\nend\n\n-- leave the given tag for perf:tag\nfunction profiler:leave(name, ...)\n    local is_perf_tag = self._IS_PERF_TAG\n    if is_perf_tag == nil then\n        is_perf_tag = self:is_perf(\"tag\")\n        self._IS_PERF_TAG = is_perf_tag\n    end\n    if is_perf_tag then\n        local stoptime = os.mclock()\n        local argv = table.pack(...)\n        local report = self:_tag_report(name, argv)\n        if report.calltime and report.calltime > 0 then\n            report.totaltime = report.totaltime + (stoptime - report.calltime)\n            report.calltime = 0\n        end\n    end\nend\n\n-- get profiler mode, e.g. perf:call, perf:tag, perf:process, trace\nfunction profiler:mode()\n    local mode = self._MODE\n    if mode == nil then\n        mode = os.getenv(\"XMAKE_PROFILE\") or false\n        self._MODE = mode\n    end\n    return mode or nil\nend\n\n-- is trace?\nfunction profiler:is_trace()\n    local mode = self:mode()\n    return mode and mode == \"trace\"\nend\n\n-- is perf?\nfunction profiler:is_perf(name)\n    local mode = self:mode()\n    if mode and name then\n        return mode == \"perf:\" .. name\n    end\nend\n\n-- profiler is enabled?\nfunction profiler:enabled()\n    return self:is_perf(\"call\") or self:is_perf(\"tag\") or self:is_trace()\nend\n\n-- return module\nreturn profiler\n"
  },
  {
    "path": "xmake/core/base/queue.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        queue.lua\n--\n\n-- load modules\nlocal object = require(\"base/object\")\n\n-- define module\nlocal queue = queue or object {_init = {\"_first\", \"_last\"}} {1, 0}\n\n-- clear queue\nfunction queue:clear()\n    self._first = 1\n    self._last = 0\nend\n\n-- push item to queue\nfunction queue:push(item)\n    local last = self._last + 1\n    self._last = last\n    self[last] = item\nend\n\n-- pop item from queue\nfunction queue:pop()\n    local first = self._first\n    if first > self._last then\n        return nil\n    end\n\n    local value = self[first]\n    self[first] = nil\n    self._first = first + 1\n    return value\nend\n\n-- get queue size\nfunction queue:size()\n    return self._last - self._first + 1\nend\n\n-- is queue empty?\nfunction queue:empty()\n    return self._first > self._last\nend\n\n-- peek the first item of queue\nfunction queue:first()\n    if self._first > self._last then\n        return nil\n    end\n    return self[self._first]\nend\n\n-- peek the last item of queue\nfunction queue:last()\n    if self._first > self._last then\n        return nil\n    end\n    return self[self._last]\nend\n\n-- iterator for all items (forward)\n--\n-- e.g.\n--\n-- for item in queue:items() do\n--     print(item)\n-- end\n--\nfunction queue:items()\n    local index = self._first - 1\n    local last = self._last\n    return function()\n        index = index + 1\n        if index <= last then\n            return self[index]\n        end\n    end\nend\n\n-- iterator for all items (reverse)\nfunction queue:ritems()\n    local index = self._last + 1\n    local first = self._first\n    return function()\n        index = index - 1\n        if index >= first then\n            return self[index]\n        end\n    end\nend\n\n-- clone queue\nfunction queue:clone()\n    local q = queue.new()\n    for i = self._first, self._last do\n        q:push(self[i])\n    end\n    return q\nend\n\n-- new queue\nfunction queue.new()\n    return queue()\nend\n\n-- return module: queue\nreturn queue\n"
  },
  {
    "path": "xmake/core/base/scheduler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scheduler.lua\n--\n\n-- define module: scheduler\nlocal scheduler  = scheduler or {}\nlocal _coroutine = _coroutine or {}\nlocal _semaphore = _semaphore or {}\n\n-- load modules\nlocal table     = require(\"base/table\")\nlocal utils     = require(\"base/utils\")\nlocal option    = require(\"base/option\")\nlocal string    = require(\"base/string\")\nlocal poller    = require(\"base/poller\")\nlocal timer     = require(\"base/timer\")\nlocal hashset   = require(\"base/hashset\")\nlocal queue     = require(\"base/queue\")\nlocal coroutine = require(\"base/coroutine\")\nlocal bit       = require(\"base/bit\")\n\n-- new a semaphore instance\nfunction _semaphore.new(name, value)\n    local instance    = table.inherit(_semaphore)\n    instance._NAME    = name\n    instance._VALUE   = value or 0\n    instance._WAITING = queue.new()\n    instance._POSTING = false\n    setmetatable(instance, _semaphore)\n    return instance\nend\n\n-- get the semaphore name\nfunction _semaphore:name()\n    return self._NAME or \"none\"\nend\n\n-- post the semaphore value\nfunction _semaphore:post(value)\n    if self._POSTING then\n        return self._VALUE\n    end\n    self._POSTING = true\n    local new_value = self._VALUE + value\n    self._VALUE = new_value\n    if new_value > 0 then\n        local waiting = self._WAITING\n        local post_count = 0\n        while not waiting:empty() do\n            local co = waiting:pop()\n            if not co:is_suspended() then\n                self._POSTING = false\n                return -1, string.format(\"%s cannot be resumed, status: %s\", co, co:status())\n            end\n            local ok, errors = scheduler:co_resume(co)\n            if not ok then\n                self._POSTING = false\n                return -1, errors\n            end\n            post_count = post_count + 1\n            if post_count >= new_value then\n                break\n            end\n        end\n    end\n    self._POSTING = false\n    return new_value\nend\n\n-- wait the semaphore\nfunction _semaphore:wait(timeout)\n\n    -- get the running coroutine\n    local running = scheduler:co_running()\n    if not running then\n        return -1, \"we must call semaphore:wait() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not scheduler._STARTED then\n        return -1, \"the scheduler is stopped!\"\n    end\n\n    -- update value\n    local value = self._VALUE\n    if value > 0 then\n        self._VALUE = value - 1\n        return value\n    end\n\n    -- no signal? return immediately if timeout is zero\n    if timeout == 0 then\n        return 0\n    end\n\n    -- wait semaphore\n    self._WAITING:push(running)\n    if timeout > 0 then\n        scheduler:_timer():post(function (cancel)\n            if running:is_suspended() then\n                return scheduler:co_resume(running, true)\n            end\n            return true\n        end, timeout)\n    end\n\n    while true do\n        local timeout = scheduler:co_suspend()\n\n        local value = self._VALUE\n        if value > 0 then\n            self._VALUE = value - 1\n            return value\n        end\n\n        if timeout then\n            break\n        end\n\n        -- continue to wait it\n        self._WAITING:push(running)\n    end\n    return 0\nend\n\n-- tostring(semaphore)\nfunction _semaphore:__tostring()\n    return string.format(\"<co_semaphore: %s/%d>\", self:name(), self._VALUE)\nend\n\n-- new a coroutine instance\nfunction _coroutine.new(name, thread)\n    local instance   = table.inherit(_coroutine)\n    instance._NAME   = name\n    instance._THREAD = thread\n    setmetatable(instance, _coroutine)\n    return instance\nend\n\n-- get the coroutine name\nfunction _coroutine:name()\n    return self._NAME or \"none\"\nend\n\n-- set the coroutine name\nfunction _coroutine:name_set(name)\n    self._NAME = name\nend\n\n-- get the waiting poller object\nfunction _coroutine:waitobj()\n    return self._WAITOBJ\nend\n\n-- set the waiting poller object\nfunction _coroutine:waitobj_set(obj)\n    self._WAITOBJ = obj\nend\n\n-- get user private data\nfunction _coroutine:data(name)\n    return self._DATA and self._DATA[name]\nend\n\n-- set user private data\nfunction _coroutine:data_set(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = data\nend\n\n-- add user private data\nfunction _coroutine:data_add(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = table.unwrap(table.join(self._DATA[name] or {}, data))\nend\n\n-- get the raw coroutine thread\nfunction _coroutine:thread()\n    return self._THREAD\nend\n\n-- get the coroutine status\nfunction _coroutine:status()\n    return coroutine.status(self:thread())\nend\n\n-- is dead?\nfunction _coroutine:is_dead()\n    return self:status() == \"dead\"\nend\n\n-- is running?\nfunction _coroutine:is_running()\n    return self:status() == \"running\"\nend\n\n-- is suspended?\nfunction _coroutine:is_suspended()\n    return self:status() == \"suspended\"\nend\n\n-- is isolated?\nfunction _coroutine:is_isolated()\n    return self._ISOLATED\nend\n\n-- isolate coroutine environments\nfunction _coroutine:isolate(isolate)\n    self._ISOLATED = isolate\nend\n\n-- get the current timer task\nfunction _coroutine:_timer_task()\n    return self._TIMER_TASK\nend\n\n-- set the timer task\nfunction _coroutine:_timer_task_set(task)\n    self._TIMER_TASK = task\nend\n\n-- tostring(coroutine)\nfunction _coroutine:__tostring()\n    return string.format(\"<co: %s/%s>\", self:name(), self:status())\nend\n\n-- gc(coroutine)\nfunction _coroutine:__gc()\n    self._THREAD = nil\nend\n\n-- get the timer of scheduler\nfunction scheduler:_timer()\n    local t = self._TIMER\n    if t == nil then\n        t = timer:new()\n        self._TIMER = t\n    end\n    return t\nend\n\n-- get poller object data for socket, pipe, process, fwatcher object\nfunction scheduler:_poller_data(obj)\n    return self._POLLERDATA and self._POLLERDATA[obj] or nil\nend\n\n-- set poller object data\n--\n-- data.co_recv:            the suspended coroutine for waiting poller/recv\n-- data.co_send:            the suspended coroutine for waiting poller/send\n-- data.poller_events_wait: the waited events for poller\n-- data.poller_events_save: the saved events for poller (triggered)\n--\nfunction scheduler:_poller_data_set(obj, data)\n    local pollerdata = self._POLLERDATA\n    if not pollerdata then\n        pollerdata = {}\n        self._POLLERDATA = pollerdata\n    end\n    pollerdata[obj] = data\nend\n\n-- resume the suspended coroutine after poller callback\nfunction scheduler:_poller_resume_co(co, events)\n\n    -- cancel timer task if exists\n    local timer_task = co:_timer_task()\n    if timer_task then\n        timer_task.cancel = true\n    end\n\n    -- the scheduler has been stopped? mark events as error to stop the coroutine\n    if not self._STARTED then\n        events = poller.EV_POLLER_ERROR\n    end\n\n    -- this coroutine must be suspended, (maybe also dead)\n    if not co:is_suspended() then\n        return false, string.format(\"%s cannot be resumed, status: %s\", co, co:status())\n    end\n\n    -- resume this coroutine task\n    co:waitobj_set(nil)\n    return self:co_resume(co, (bit.band(events, poller.EV_POLLER_ERROR) ~= 0) and -1 or events)\nend\n\n-- the poller events callback\nfunction scheduler:_poller_events_cb(obj, events)\n\n    -- get poller object data\n    local pollerdata = self:_poller_data(obj)\n    if not pollerdata then\n        return false, string.format(\"%s: cannot get poller data!\", obj)\n    end\n\n    -- is process/fwatcher object?\n    if obj:otype() == poller.OT_PROC or obj:otype() == poller.OT_FWATCHER then\n\n        -- resume coroutine and return the process exit status/fwatcher event\n        pollerdata.object_event = events\n\n        -- waiting process/fwatcher? resume this coroutine\n        if pollerdata.co_waiting then\n            local co_waiting = pollerdata.co_waiting\n            pollerdata.co_waiting = nil\n            return self:_poller_resume_co(co_waiting, 1)\n        else\n            pollerdata.object_pending = 1\n        end\n        return true\n    end\n\n    -- get poller object events\n    local events_prev_wait = pollerdata.poller_events_wait\n    local events_prev_save = pollerdata.poller_events_save\n\n    -- eof for edge trigger?\n    if bit.band(events, poller.EV_POLLER_EOF) ~= 0 then\n        -- cache this eof as next recv/send event\n        events = bit.band(events, bit.bnot(poller.EV_POLLER_EOF))\n        events_prev_save = bit.bor(events_prev_save, events_prev_wait)\n        pollerdata.poller_events_save = events_prev_save\n    end\n\n    -- get the waiting coroutines\n    local co_recv = bit.band(events, poller.EV_POLLER_RECV) ~= 0 and pollerdata.co_recv or nil\n    local co_send = bit.band(events, poller.EV_POLLER_SEND) ~= 0 and pollerdata.co_send or nil\n\n    -- return the events result for the waiting coroutines\n    if co_recv and co_recv == co_send then\n        pollerdata.co_recv = nil\n        pollerdata.co_send = nil\n        return self:_poller_resume_co(co_recv, events)\n    else\n\n        if co_recv then\n            pollerdata.co_recv = nil\n            local ok, errors = self:_poller_resume_co(co_recv, bit.band(events, bit.bnot(poller.EV_POLLER_SEND)))\n            if not ok then\n                return false, errors\n            end\n            events = bit.band(events, bit.bnot(poller.EV_POLLER_RECV))\n        end\n        if co_send then\n            pollerdata.co_send = nil\n            local ok, errors = self:_poller_resume_co(co_send, bit.band(events, bit.bnot(poller.EV_POLLER_RECV)))\n            if not ok then\n                return false, errors\n            end\n            events = bit.band(events, bit.bnot(poller.EV_POLLER_SEND))\n        end\n\n        -- no coroutines are waiting? cache this events\n        if bit.band(events, poller.EV_POLLER_RECV) ~= 0 or bit.band(events, poller.EV_POLLER_SEND) ~= 0 then\n            events_prev_save = bit.bor(events_prev_save, events)\n            pollerdata.poller_events_save = events_prev_save\n        end\n    end\n    return true\nend\n\n-- update the current directory hash of current coroutine\nfunction scheduler:_co_curdir_update(curdir)\n\n    -- get running coroutine\n    local running = self:co_running()\n    if not running then\n        return\n    end\n\n    -- save the current directory\n    curdir = curdir or os.curdir()\n    local co_curdirs = self._CO_CURDIRS\n    if not co_curdirs then\n        co_curdirs = {}\n        self._CO_CURDIRS = co_curdirs\n    end\n    co_curdirs[running] = curdir\n    self._CO_CURDIR_CURRENT = curdir\nend\n\n-- update the current environments hash of current coroutine\nfunction scheduler:_co_curenvs_update(envs)\n\n    -- get running coroutine\n    local running = self:co_running()\n    if not running then\n        return\n    end\n\n    -- save the current directory hash\n    local envs_hash = \"\"\n    envs = envs or os.getenvs()\n    for _, key in ipairs(table.orderkeys(envs)) do\n        envs_hash = envs_hash .. key:upper() .. envs[key]\n    end\n    envs_hash = hash.strhash64(envs_hash)\n    self._CO_CURENVS_HASH = envs_hash\n\n    -- save the current directory for each coroutine\n    local co_curenvs = self._CO_CURENVS\n    if not co_curenvs then\n        co_curenvs = {}\n        self._CO_CURENVS = co_curenvs\n    end\n    co_curenvs[running] = {envs_hash, envs}\nend\n\n-- resume it's waiting coroutine if all coroutines are dead in group\nfunction scheduler:_co_groups_resume()\n\n    local resumed_count = 0\n    local co_groups = self._CO_GROUPS\n    if co_groups then\n        local co_groups_waiting = self._CO_GROUPS_WAITING\n        local co_resumed_list = {}\n        for name, co_group in pairs(co_groups) do\n\n            -- get coroutine and limit in waiting group\n            local item = co_groups_waiting and co_groups_waiting[name] or nil\n            if item then\n                local co_waiting = item[1]\n                local limit = item[2]\n\n                -- get dead coroutines count in this group\n                local count = 0\n                for _, co in ipairs(co_group) do\n                    if count < limit then\n                        if co:is_dead() then\n                            count = count + 1\n                        end\n                    else\n                        break\n                    end\n                end\n\n                -- resume the waiting coroutine of this group if some coroutines are dead in this group\n                if count >= limit and co_waiting and co_waiting:is_suspended() then\n                    resumed_count = resumed_count + 1\n                    self._CO_GROUPS_WAITING[name] = nil\n                    table.insert(co_resumed_list, co_waiting)\n                end\n            end\n        end\n        if #co_resumed_list > 0 then\n            for _, co_waiting in ipairs(co_resumed_list) do\n                local ok, errors = self:co_resume(co_waiting)\n                if not ok then\n                    return -1, errors\n                end\n            end\n        end\n    end\n    return resumed_count\nend\n\n-- get profiler\nfunction scheduler:_profiler()\n    local profiler = self._PROFILE\n    if profiler == nil then\n        profiler = require(\"base/profiler\")\n        if not profiler:enabled() then\n            profiler = false\n        end\n    end\n    return profiler or nil\nend\n\n-- start a new coroutine task\nfunction scheduler:co_start(cotask, ...)\n    return self:co_start_named(nil, cotask, ...)\nend\n\n-- start a new named coroutine task\nfunction scheduler:co_start_named(coname, cotask, ...)\n    return self:co_start_withopt({name = coname}, cotask, ...)\nend\n\n-- start a new coroutine task with options\nfunction scheduler:co_start_withopt(opt, cotask, ...)\n\n    -- check coroutine task\n    opt = opt or {}\n    local coname = opt.name\n    if not cotask then\n        return nil, string.format(\"cannot start coroutine, invalid cotask(%s/%s)\", coname and coname or \"anonymous\", cotask)\n    end\n\n    -- start coroutine\n    local co\n    co = _coroutine.new(coname, coroutine.create(function(...)\n        local profiler = self:_profiler()\n        if profiler and profiler:enabled() then\n            profiler:start()\n        end\n        self:_co_curdir_update()\n        self:_co_curenvs_update()\n        cotask(...)\n        self:co_tasks()[co:thread()] = nil\n        if self:co_count() > 0 then\n            self._CO_COUNT = self:co_count() - 1\n        end\n    end))\n    if opt.isolate then\n        co:isolate(true)\n    end\n    self:co_tasks()[co:thread()] = co\n    self._CO_COUNT = self:co_count() + 1\n    if self._STARTED then\n        local ok, errors = self:co_resume(co, ...)\n        if not ok then\n            return nil, errors\n        end\n    else\n        self._CO_READY_TASKS = self._CO_READY_TASKS or {}\n        table.insert(self._CO_READY_TASKS, {co, table.pack(...)})\n    end\n\n    -- add this coroutine to the pending groups\n    local co_groups_pending = self._CO_GROUPS_PENDING\n    if co_groups_pending then\n        for _, co_group_pending in pairs(co_groups_pending) do\n            table.insert(co_group_pending, co)\n        end\n    end\n    return co\nend\n\n-- resume the given coroutine\nfunction scheduler:co_resume(co, ...)\n\n    -- do resume\n    local ok, errors = coroutine.resume(co:thread(), ...)\n\n    local running = self:co_running()\n    if running then\n\n        -- has the current directory been changed? restore it\n        local curdir = self._CO_CURDIR_CURRENT\n        local olddir = self._CO_CURDIRS and self._CO_CURDIRS[running] or nil\n        if olddir and curdir ~= olddir then -- hash changed?\n            os.cd(olddir)\n        end\n\n        -- has the current environments been changed? restore it\n        local curenvs = self._CO_CURENVS_HASH\n        local oldenvs = self._CO_CURENVS and self._CO_CURENVS[running] or nil\n        if oldenvs and curenvs ~= oldenvs[1] and running:is_isolated() then -- hash changed?\n            os.setenvs(oldenvs[2])\n        end\n    end\n\n    return ok, errors\nend\n\n-- suspend the current coroutine\nfunction scheduler:co_suspend(...)\n\n    -- suspend it\n    local results = table.pack(coroutine.yield(...))\n\n    -- has the current directory been changed? restore it\n    local running = assert(self:co_running())\n    local curdir = self._CO_CURDIR_CURRENT\n    local olddir = self._CO_CURDIRS and self._CO_CURDIRS[running] or nil\n    if olddir and curdir ~= olddir then -- hash changed?\n        os.cd(olddir)\n    end\n\n    -- has the current environments been changed? restore it\n    local curenvs = self._CO_CURENVS_HASH\n    local oldenvs = self._CO_CURENVS and self._CO_CURENVS[running] or nil\n    if oldenvs and curenvs ~= oldenvs[1] and running:is_isolated() then -- hash changed?\n        os.setenvs(oldenvs[2])\n    end\n\n    -- return results\n    return table.unpack(results)\nend\n\n-- yield the current coroutine\nfunction scheduler:co_yield()\n    return scheduler.co_sleep(self, 1)\nend\n\n-- sleep some times (ms)\nfunction scheduler:co_sleep(ms)\n\n    -- we don't need to sleep\n    if ms == 0 then\n        return true\n    end\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return false, \"we must call sleep() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return false, \"the scheduler is stopped!\"\n    end\n\n    -- register timeout task to timer\n    self:_timer():post(function (cancel)\n        if running:is_suspended() then\n            return self:co_resume(running)\n        end\n        return true\n    end, ms)\n\n    -- wait\n    self:co_suspend()\n    return true\nend\n\n-- lock the current coroutine\nfunction scheduler:co_lock(lockname)\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return false, \"we must call co_lock() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return false, \"the scheduler is stopped!\"\n    end\n\n    -- do lock\n    local co_locked_tasks = self._CO_LOCKED_TASKS\n    if co_locked_tasks == nil then\n        co_locked_tasks = {}\n        self._CO_LOCKED_TASKS = co_locked_tasks\n    end\n    while true do\n\n        -- try to lock it\n        if co_locked_tasks[lockname] == nil then\n            co_locked_tasks[lockname] = running\n            return true\n        -- has been locked by the current coroutine\n        elseif co_locked_tasks[lockname] == running then\n            return true\n        end\n\n        -- register timeout task to timer\n        local function timer_callback (cancel)\n            if co_locked_tasks[lockname] == nil then\n                if running:is_suspended() then\n                    return self:co_resume(running)\n                end\n            else\n                self:_timer():post(timer_callback, 500)\n            end\n            return true\n        end\n        self:_timer():post(timer_callback, 500)\n\n        -- wait\n        self:co_suspend()\n    end\n    return true\nend\n\n-- unlock the current coroutine\nfunction scheduler:co_unlock(lockname)\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return false, \"we must call co_unlock() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return false, \"the scheduler is stopped!\"\n    end\n\n    -- do unlock\n    local co_locked_tasks = self._CO_LOCKED_TASKS\n    if co_locked_tasks == nil then\n        co_locked_tasks = {}\n        self._CO_LOCKED_TASKS = co_locked_tasks\n    end\n    if co_locked_tasks[lockname] == nil then\n        return false, string.format(\"we need to call lock(%s) first before calling unlock(%s)\", lockname, lockname)\n    end\n    if co_locked_tasks[lockname] == running then\n        co_locked_tasks[lockname] = nil\n    else\n        return false, string.format(\"unlock(%s) is called in other %s\", lockname, running)\n    end\n    return true\nend\n\n-- get the given coroutine group\nfunction scheduler:co_group(name)\n    return self._CO_GROUPS and self._CO_GROUPS[name]\nend\n\n-- begin coroutine group\nfunction scheduler:co_group_begin(name, scopefunc)\n\n    -- enter groups\n    self._CO_GROUPS = self._CO_GROUPS or {}\n    self._CO_GROUPS_PENDING = self._CO_GROUPS_PENDING or {}\n    if self._CO_GROUPS_PENDING[name] then\n        return false, string.format(\"co_group(%s): already exists!\", name)\n    end\n    self._CO_GROUPS_PENDING[name] = self._CO_GROUPS_PENDING[name] or {}\n\n    -- call the scope function\n    local co_group = self._CO_GROUPS[name] or {}\n    local ok, errors = utils.trycall(scopefunc, nil, co_group)\n    if not ok then\n        return false, errors\n    end\n\n    -- leave groups\n    self._CO_GROUPS[name] = co_group\n    table.join2(self._CO_GROUPS[name], self._CO_GROUPS_PENDING[name])\n    self._CO_GROUPS_PENDING[name] = nil\n    return true\nend\n\n-- wait for finishing the given coroutine group\nfunction scheduler:co_group_wait(name, opt)\n\n    -- get coroutine group\n    local co_group = self:co_group(name)\n    if not co_group or #co_group == 0 then\n        -- no coroutines in this group\n        return true\n    end\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return false, \"we must call co_group_wait() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return false, \"the scheduler is stopped!\"\n    end\n\n    -- get limit count\n    local limit = opt and opt.limit or #co_group\n\n    -- wait it\n    local count\n    repeat\n        count = 0\n        for _, co in ipairs(co_group) do\n            if count < limit then\n                if co:is_dead() then\n                    count = count + 1\n                end\n            else\n                break\n            end\n        end\n        if count < limit then\n            self._CO_GROUPS_WAITING = self._CO_GROUPS_WAITING or {}\n            self._CO_GROUPS_WAITING[name] = {running, limit}\n            self:co_suspend()\n        end\n    until count >= limit\n\n    -- remove all dead coroutines in group\n    if limit == #co_group and count == limit then\n        self._CO_GROUPS[name] = nil\n    else\n        for i = #co_group, 1, -1 do\n            local co = co_group[i]\n            if co:is_dead() then\n                table.remove(co_group, i)\n            end\n        end\n    end\n    return true\nend\n\n-- get waiting objects for the given group name\nfunction scheduler:co_group_waitobjs(name)\n    local objs = hashset.new()\n    for _, co in ipairs(table.wrap(self:co_group(name))) do\n        if not co:is_dead() then\n            local obj = co:waitobj()\n            if obj then\n                objs:insert(obj)\n            end\n        end\n    end\n    return objs\nend\n\n-- get the current running coroutine\nfunction scheduler:co_running()\n    if self._ENABLED then\n        local running = coroutine.running()\n        return running and self:co_tasks()[running] or nil\n    end\nend\n\n-- get all coroutine tasks\nfunction scheduler:co_tasks()\n    local cotasks = self._CO_TASKS\n    if not cotasks then\n        cotasks = {}\n        self._CO_TASKS = cotasks\n    end\n    return cotasks\nend\n\n-- get all coroutine count\nfunction scheduler:co_count()\n    return self._CO_COUNT or 0\nend\n\n-- new a coroutine semaphore\nfunction scheduler:co_semaphore(name, value)\n    return _semaphore.new(name, value)\nend\n\n-- wait poller object io events, only for socket and pipe object\nfunction scheduler:poller_wait(obj, events, timeout)\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return -1, \"we must call poller_wait() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return -1, \"the scheduler is stopped!\"\n    end\n\n    -- check the object type\n    local otype = obj:otype()\n    if otype ~= poller.OT_SOCK and otype ~= poller.OT_PIPE then\n        return -1, string.format(\"%s: invalid object type(%d)!\", obj, otype)\n    end\n\n    -- get and allocate poller object data\n    local pollerdata = self:_poller_data(obj)\n    if not pollerdata then\n        pollerdata = {poller_events_wait = 0, poller_events_save = 0}\n        self:_poller_data_set(obj, pollerdata)\n    end\n\n    -- enable edge-trigger mode if be supported\n    if self._SUPPORT_EV_POLLER_CLEAR and (otype == poller.OT_SOCK or otype == poller.OT_PIPE) then\n        events = bit.bor(events, poller.EV_POLLER_CLEAR)\n    end\n\n    -- get the previous poller object events\n    local events_wait = events\n    if pollerdata.poller_events_wait ~= 0 then\n\n        -- return the cached events directly if the waiting events exists cache\n        local events_prev_wait = pollerdata.poller_events_wait\n        local events_prev_save = pollerdata.poller_events_save\n        if events_prev_save ~= 0 and bit.band(events_prev_wait, events) ~= 0 then\n\n            -- check error?\n            if bit.band(events_prev_save, poller.EV_POLLER_ERROR) ~= 0 then\n                pollerdata.poller_events_save = 0\n                return -1, string.format(\"%s: events error!\", obj)\n            end\n\n            -- clear cache events\n            pollerdata.poller_events_save = bit.band(events_prev_save, bit.bnot(events))\n\n            -- return the cached events\n            return bit.band(events_prev_save, events)\n        end\n\n        -- modify the wait events and reserve the pending events in other coroutine\n        events_wait = events_prev_wait\n        if bit.band(events_wait, poller.EV_POLLER_RECV) ~= 0 and not pollerdata.co_recv then\n            events_wait = bit.band(events_wait, bit.bnot(poller.EV_POLLER_RECV))\n        end\n        if bit.band(events_wait, poller.EV_POLLER_SEND) ~= 0 and not pollerdata.co_send then\n            events_wait = bit.band(events_wait, bit.bnot(poller.EV_POLLER_SEND))\n        end\n        events_wait = bit.bor(events_wait, events)\n\n        -- modify poller object from poller for waiting events if the waiting events has been changed\n        if bit.band(events_prev_wait, events_wait) ~= events_wait then\n\n            -- maybe wait recv/send at same time\n            local ok, errors = poller:modify(obj, events_wait, self._poller_events_cb)\n            if not ok then\n                return -1, errors\n            end\n        end\n    else\n\n        -- insert poller object events\n        local ok, errors = poller:insert(obj, events_wait, self._poller_events_cb)\n        if not ok then\n            return -1, errors\n        end\n    end\n\n    -- register timeout task to timer\n    local timer_task = nil\n    if timeout > 0 then\n        timer_task = self:_timer():post(function (cancel)\n            if not cancel and running:is_suspended() then\n                running:waitobj_set(nil)\n                return self:co_resume(running, 0)\n            end\n            return true\n        end, timeout)\n    end\n    running:_timer_task_set(timer_task)\n\n    -- save waiting events\n    pollerdata.poller_events_wait = events_wait\n    pollerdata.poller_events_save = 0\n\n    -- save the current coroutine\n    if bit.band(events, poller.EV_POLLER_RECV) ~= 0 then\n        pollerdata.co_recv = running\n    end\n    if bit.band(events, poller.EV_POLLER_SEND) ~= 0 then\n        pollerdata.co_send = running\n    end\n\n    -- save the waiting poller object\n    running:waitobj_set(obj)\n\n    -- wait\n    return self:co_suspend()\nend\n\n-- wait poller object/process status\nfunction scheduler:poller_waitproc(obj, timeout)\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return -1, \"we must call poller_wait() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return -1, \"the scheduler is stopped!\"\n    end\n\n    -- check the object type\n    local otype = obj:otype()\n    if otype ~= poller.OT_PROC then\n        return -1, string.format(\"%s: invalid object type(%d)!\", obj, otype)\n    end\n\n    -- get and allocate poller object data\n    local pollerdata = self:_poller_data(obj)\n    if not pollerdata then\n        pollerdata = {object_pending = 0, object_event = 0}\n        self:_poller_data_set(obj, pollerdata)\n    end\n\n    -- has pending process status?\n    if pollerdata.object_pending ~= 0 then\n        pollerdata.object_pending = 0\n        return 1, pollerdata.object_event\n    end\n\n    -- insert poller object to poller for waiting process\n    local ok, errors = poller:insert(obj, 0, self._poller_events_cb)\n    if not ok then\n        return -1, errors\n    end\n\n    -- register timeout task to timer\n    local timer_task = nil\n    if timeout > 0 then\n        timer_task = self:_timer():post(function (cancel)\n            if not cancel and running:is_suspended() then\n                pollerdata.co_waiting = nil\n                running:waitobj_set(nil)\n                return self:co_resume(running, 0)\n            end\n            return true\n        end, timeout)\n    end\n    running:_timer_task_set(timer_task)\n\n    -- set process status\n    pollerdata.object_event  = 0\n    pollerdata.object_pending = 0\n    pollerdata.co_waiting   = running\n\n    -- save the waiting poller object\n    running:waitobj_set(obj)\n\n    -- wait\n    local ok = self:co_suspend()\n    return ok, pollerdata.object_event\nend\n\n-- wait poller object/fwatcher status\nfunction scheduler:poller_waitfs(obj, timeout)\n\n    -- get the running coroutine\n    local running = self:co_running()\n    if not running then\n        return -1, \"we must call poller_wait() in coroutine with scheduler!\"\n    end\n\n    -- is stopped?\n    if not self._STARTED then\n        return -1, \"the scheduler is stopped!\"\n    end\n\n    -- check the object type\n    local otype = obj:otype()\n    if otype ~= poller.OT_FWATCHER then\n        return -1, string.format(\"%s: invalid object type(%d)!\", obj, otype)\n    end\n\n    -- get and allocate poller object data\n    local pollerdata = self:_poller_data(obj)\n    if not pollerdata then\n        pollerdata = {object_pending = 0, object_event = 0}\n        self:_poller_data_set(obj, pollerdata)\n    end\n\n    -- has pending process status?\n    if pollerdata.object_pending ~= 0 then\n        pollerdata.object_pending = 0\n        return 1, pollerdata.object_event\n    end\n\n    -- insert poller object to poller for waiting fwatcher\n    local ok, errors = poller:insert(obj, 0, self._poller_events_cb)\n    if not ok then\n        return -1, errors\n    end\n\n    -- register timeout task to timer\n    local timer_task = nil\n    if timeout > 0 then\n        timer_task = self:_timer():post(function (cancel)\n            if not cancel and running:is_suspended() then\n                pollerdata.co_waiting = nil\n                running:waitobj_set(nil)\n                return self:co_resume(running, 0)\n            end\n            return true\n        end, timeout)\n    end\n    running:_timer_task_set(timer_task)\n\n    -- set fwatcher status\n    pollerdata.object_event  = 0\n    pollerdata.object_pending = 0\n    pollerdata.co_waiting   = running\n\n    -- save the waiting poller object\n    running:waitobj_set(obj)\n\n    -- wait\n    local ok = self:co_suspend()\n    return ok, pollerdata.object_event\nend\n\n-- cancel poller object events\nfunction scheduler:poller_cancel(obj)\n\n    -- reset the pollerdata data\n    local pollerdata = self:_poller_data(obj)\n    if pollerdata then\n        if pollerdata.poller_events_wait ~= 0 or obj:otype() == poller.OT_PROC or obj:otype() == poller.OT_FWATCHER then\n            local ok, errors = poller:remove(obj)\n            if not ok then\n                return false, errors\n            end\n        end\n        self:_poller_data_set(obj, nil)\n    end\n    return true\nend\n\n-- enable or disable to scheduler\nfunction scheduler:enable(enabled)\n    self._ENABLED = enabled\nend\n\n-- stop the scheduler loop\nfunction scheduler:stop()\n    -- mark scheduler status as stopped and spank the poller:wait()\n    self._STARTED = false\n    poller:spank()\n    return true\nend\n\n-- run loop, schedule coroutine with socket/io, sub-processes, fwatcher\nfunction scheduler:runloop()\n\n    -- start loop\n    self._STARTED = true\n    self._ENABLED = true\n\n    -- ensure poller has been initialized first (for windows/iocp) and check edge-trigger mode (for epoll/kqueue)\n    if poller:support(poller.EV_POLLER_CLEAR) then\n        self._SUPPORT_EV_POLLER_CLEAR = true\n    end\n\n    -- set on change directory callback for scheduler\n    os._sched_chdir_set(function (curdir)\n        self:_co_curdir_update(curdir)\n    end)\n\n    -- set on change environments callback for scheduler\n    os._sched_chenvs_set(function (envs)\n        self:_co_curenvs_update(envs)\n    end)\n\n    -- start all ready coroutine tasks\n    local co_ready_tasks = self._CO_READY_TASKS\n    if co_ready_tasks then\n        for _, task in pairs(co_ready_tasks) do\n            local co   = task[1]\n            local argv = task[2]\n            local ok, errors = self:co_resume(co, table.unpack(argv))\n            if not ok then\n                return false, errors\n            end\n        end\n    end\n    self._CO_READY_TASKS = nil\n\n    -- run loop\n    opt = opt or {}\n    local ok = true\n    local errors = nil\n    local timeout = -1\n    while self._STARTED and self:co_count() > 0 do\n\n        -- resume it's waiting coroutine if some coroutines are dead in group\n        local resumed_count, resumed_errors = self:_co_groups_resume()\n        if resumed_count < 0 then\n            ok = false\n            errors = resumed_errors\n            break\n        elseif resumed_count == 0 then\n\n            -- get the next timeout\n            timeout = self:_timer():delay() or 1000\n\n            -- wait events\n            local count, events = poller:wait(timeout)\n            if count < 0 then\n                ok = false\n                errors = events\n                break\n            end\n\n            -- resume all suspended tasks with events\n            for _, e in ipairs(events) do\n                local obj       = e[1]\n                local objevents = e[2]\n                local eventfunc = e[3]\n                if eventfunc then\n                    ok, errors = eventfunc(self, obj, objevents)\n                    if not ok then\n                        -- This causes a direct exit from the entire runloop and\n                        -- a quick escape from nested try-catch blocks and coroutines groups.\n                        --\n                        -- So some try-catch cannot catch these errors, such as when a build fails (in build group).\n                        -- @see https://github.com/xmake-io/xmake/issues/3401\n                        --\n                        -- We should catch it in coroutines and re-throw it outside scheduler,\n                        -- it will avoid co_resume to get and return this error.\n                        --\n                        -- e.g. we can see runjobs.lua implementation\n                        break\n                    end\n                end\n            end\n            if not ok then\n                break\n            end\n        end\n\n        -- spank the timer and trigger all timeout tasks\n        ok, errors = self:_timer():next()\n        if not ok then\n            break\n        end\n    end\n\n    -- mark the loop as stopped first\n    self._STARTED = false\n\n    -- cancel all timeout tasks and trigger them\n    self:_timer():kill()\n\n    -- finished and we need not resume other pending coroutines, because xmake will be aborted directly if fails\n    return ok, errors\nend\n\n-- return module: scheduler\nreturn scheduler\n"
  },
  {
    "path": "xmake/core/base/scopeinfo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scopeinfo.lua\n--\n\n-- define module\nlocal scopeinfo = scopeinfo or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal io         = require(\"base/io\")\nlocal os         = require(\"base/os\")\nlocal path       = require(\"base/path\")\nlocal table      = require(\"base/table\")\nlocal utils      = require(\"base/utils\")\nlocal deprecated = require(\"base/deprecated\")\n\n-- new an instance\nfunction _instance.new(kind, info, opt)\n    opt = opt or {}\n    local instance = table.inherit(_instance)\n    instance._KIND = kind or \"root\"\n    instance._INFO = info\n    instance._INTERPRETER = opt.interpreter\n    instance._DEDUPLICATE = opt.deduplicate\n    instance._ENABLE_FILTER = opt.enable_filter\n    return instance\nend\n\n-- get apis\nfunction _instance:_apis()\n    local interp = self:interpreter()\n    if interp then\n        return interp:api_definitions()\n    end\nend\n\n-- get the given api type\nfunction _instance:_api_type(name)\n    local apis = self:_apis()\n    if apis then\n        return apis[self:kind() .. '.' .. name]\n    end\nend\n\n-- handle the api values\nfunction _instance:_api_handle(name, values)\n    local interp = self:interpreter()\n    if interp then\n\n        -- remove repeat first for each slice with deleted item (__remove_xxx)\n        if self._DEDUPLICATE and not table.is_dictionary(values) then\n            local policy = interp:deduplication_policy(name)\n            if policy ~= false then\n                local unique_func = policy == \"toleft\" and table.reverse_unique or table.unique\n                values = unique_func(values, function (v) return type(v) == \"string\" and v:startswith(\"__remove_\") end)\n            end\n        end\n\n        -- filter values\n        if self._ENABLE_FILTER then\n            values = interp:_filter(values)\n        end\n    end\n\n    -- unwrap it if be only one\n    return table.unwrap(values)\nend\n\n-- save api source info, e.g. call api() in sourcefile:linenumber\nfunction _instance:_api_save_sourceinfo_to_scope(scope, apiname, values)\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    local sourceinfo = debug.getinfo(5, \"Sl\")\n    if sourceinfo then\n        scope[\"__sourceinfo_\" .. apiname] = scope[\"__sourceinfo_\" .. apiname] or {}\n        local sourcescope = scope[\"__sourceinfo_\" .. apiname]\n        for _, value in ipairs(values) do\n            if type(value) == \"string\" then\n                sourcescope[value] = {file = sourceinfo.short_src or sourceinfo.source, line = sourceinfo.currentline}\n            end\n        end\n    end\nend\n\n-- set the api values to the scope info\nfunction _instance:_api_set_values(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- @note we need to mark table value as meta object to avoid wrap/unwrap\n    -- if these values cannot be expanded, especially when there is only one value\n    --\n    -- e.g. target:set(\"shflags\", {\"-Wl,-exported_symbols_list\", exportfile}, {force = true, expand = false})\n    if extra_config and extra_config.expand == false then\n        for _, value in ipairs(values) do\n            table.wrap_lock(value)\n        end\n    else\n        -- expand values\n        values = table.join(table.unpack(values))\n    end\n\n    -- handle values\n    local handled_values = self:_api_handle(name, values)\n\n    -- save values\n    if type(handled_values) == \"table\" and table.empty(handled_values) then\n        -- set(\"xx\", nil)? remove it\n        scope[name] = nil\n    else\n        scope[name] = handled_values\n    end\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        for _, value in ipairs(values) do\n            extrascope[value] = extra_config\n        end\n    end\nend\n\n-- add the api values to the scope info\nfunction _instance:_api_add_values(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- @note we need to mark table value as meta object to avoid wrap/unwrap\n    -- if these values cannot be expanded, especially when there is only one value\n    --\n    -- e.g. target:add(\"shflags\", {\"-Wl,-exported_symbols_list\", exportfile}, {force = true, expand = false})\n    if extra_config and extra_config.expand == false then\n        for _, value in ipairs(values) do\n            table.wrap_lock(value)\n        end\n    else\n        -- expand values\n        values = table.join(table.unpack(values))\n    end\n\n    -- save values\n    scope[name] = self:_api_handle(name, table.join2(table.wrap(scope[name]), values))\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        for _, value in ipairs(values) do\n            extrascope[value] = extra_config\n        end\n    end\nend\n\n-- set the api groups to the scope info\nfunction _instance:_api_set_groups(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- expand values\n    values = table.join(table.unpack(values))\n\n    -- save values\n    table.wrap_lock(values)\n    scope[name] = values\n    scope[name] = self:_api_handle(name, scope[name])\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        local key = table.concat(values, \"_\")\n        extrascope[key] = extra_config\n    end\nend\n\n-- add the api groups to the scope info\nfunction _instance:_api_add_groups(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- expand values\n    values = table.join(table.unpack(values))\n\n    -- save values\n    --\n    -- @note maybe scope[name] has been unwrapped, we need wrap it first\n    -- https://github.com/xmake-io/xmake/issues/4428\n    scope[name] = table.wrap(scope[name])\n    table.wrap_lock(values)\n    table.insert(scope[name], values)\n    scope[name] = self:_api_handle(name, scope[name])\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        local key = table.concat(values, \"_\")\n        extrascope[key] = extra_config\n    end\nend\n\n-- set the api key-values to the scope info\nfunction _instance:_api_set_keyvalues(name, key, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- save values to \"name\"\n    scope[name] = scope[name] or {}\n    scope[name][key] = self:_api_handle(name, values)\n\n    -- save values to \"name.key\"\n    local name_key = name .. \".\" .. key\n    scope[name_key] = scope[name][key]\n\n    -- fix override attributes\n    scope[\"__override_\" .. name] = false\n    scope[\"__override_\" .. name_key] = true\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name_key] = scope[\"__extra_\" .. name_key] or {}\n        local extrascope = scope[\"__extra_\" .. name_key]\n        for _, value in ipairs(values) do\n            extrascope[value] = extra_config\n        end\n    end\nend\n\n-- add the api key-values to the scope info\nfunction _instance:_api_add_keyvalues(name, key, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- save values to \"name\"\n    scope[name] = scope[name] or {}\n    if scope[name][key] == nil then\n        scope[name][key] = self:_api_handle(name, values)\n    else\n        scope[name][key] = self:_api_handle(name, table.join2(table.wrap(scope[name][key]), values))\n    end\n\n    -- save values to \"name.key\"\n    local name_key = name .. \".\" .. key\n    scope[name_key] = scope[name][key]\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name_key] = scope[\"__extra_\" .. name_key] or {}\n        local extrascope = scope[\"__extra_\" .. name_key]\n        for _, value in ipairs(values) do\n            extrascope[value] = extra_config\n        end\n    end\nend\n\n-- set the api dictionary to the scope info\nfunction _instance:_api_set_dictionary(name, dict_or_key, value, extra_config)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- check\n    if type(dict_or_key) == \"table\" then\n        local dict = {}\n        for k, v in pairs(dict_or_key) do\n            dict[k] = self:_api_handle(name, v)\n        end\n        scope[name] = dict\n    elseif type(dict_or_key) == \"string\" and value ~= nil then\n        scope[name] = {[dict_or_key] = self:_api_handle(name, value)}\n        -- save extra config\n        if extra_config and table.is_dictionary(extra_config) then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            extrascope[dict_or_key] = extra_config\n        end\n    else\n        -- error\n        os.raise(\"%s:set(%s, ...): invalid value type!\", self:kind(), name, type(dict))\n    end\nend\n\n-- add the api dictionary to the scope info\nfunction _instance:_api_add_dictionary(name, dict_or_key, value, extra_config)\n    local scope = self._INFO\n    scope[name] = scope[name] or {}\n    if type(dict_or_key) == \"table\" then\n        local dict = {}\n        for k, v in pairs(dict_or_key) do\n            dict[k] = self:_api_handle(name, v)\n        end\n        table.join2(scope[name], dict)\n    elseif type(dict_or_key) == \"string\" and value ~= nil then\n        scope[name][dict_or_key] = self:_api_handle(name, value)\n        -- save extra config\n        if extra_config and table.is_dictionary(extra_config) then\n            scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n            local extrascope = scope[\"__extra_\" .. name]\n            extrascope[dict_or_key] = extra_config\n        end\n    else\n        -- error\n        os.raise(\"%s:add(%s, ...): invalid value type!\", self:kind(), name, type(dict))\n    end\nend\n\n-- set the api paths to the scope info\nfunction _instance:_api_set_paths(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get interpreter\n    local interp = self:interpreter()\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- expand values\n    values = table.join(table.unpack(values))\n\n    -- translate paths\n    local paths = interp:_api_translate_paths(values, \"set_\" .. name, 5)\n\n    -- save values\n    scope[name] = self:_api_handle(name, paths)\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        for _, value in ipairs(paths) do\n            extrascope[value] = extra_config\n        end\n    end\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    self:_api_save_sourceinfo_to_scope(scope, name, paths)\nend\n\n-- add the api paths to the scope info\nfunction _instance:_api_add_paths(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get interpreter\n    local interp = self:interpreter()\n\n    -- get extra config\n    local values = {...}\n    local extra_config = values[#values]\n    if table.is_dictionary(extra_config) then\n        table.remove(values)\n    else\n        extra_config = nil\n    end\n\n    -- expand values\n    values = table.join(table.unpack(values))\n\n    -- translate paths\n    local paths = interp:_api_translate_paths(values, \"add_\" .. name, 5)\n\n    -- save values\n    scope[name] = self:_api_handle(name, table.join2(table.wrap(scope[name]), paths))\n\n    -- save extra config\n    if extra_config then\n        scope[\"__extra_\" .. name] = scope[\"__extra_\" .. name] or {}\n        local extrascope = scope[\"__extra_\" .. name]\n        for _, value in ipairs(paths) do\n            extrascope[value] = extra_config\n        end\n    end\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    self:_api_save_sourceinfo_to_scope(scope, name, paths)\nend\n\n-- remove the api paths to the scope info (deprecated)\nfunction _instance:_api_del_paths(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get interpreter\n    local interp = self:interpreter()\n\n    -- expand values\n    values = table.join(...)\n\n    -- it has been marked as deprecated\n    deprecated.add(\"remove_\" .. name .. \"(%s)\", \"del_\" .. name .. \"(%s)\", table.concat(values, \", \"), table.concat(values, \", \"))\n\n    -- translate paths\n    local paths = interp:_api_translate_paths(values, \"del_\" .. name, 5)\n\n    -- mark these paths as deleted\n    local paths_deleted = {}\n    for _, pathname in ipairs(paths) do\n        table.insert(paths_deleted, \"__remove_\" .. pathname)\n    end\n\n    -- save values\n    scope[name] = self:_api_handle(name, table.join2(table.wrap(scope[name]), paths_deleted))\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    self:_api_save_sourceinfo_to_scope(scope, name, paths)\nend\n\n-- remove the api paths to the scope info\nfunction _instance:_api_remove_paths(name, ...)\n\n    -- get the scope info\n    local scope = self._INFO\n\n    -- get interpreter\n    local interp = self:interpreter()\n\n    -- expand values\n    values = table.join(...)\n\n    -- translate paths\n    local paths = interp:_api_translate_paths(values, \"remove_\" .. name, 5)\n\n    -- mark these paths as removed\n    local paths_removed = {}\n    for _, pathname in ipairs(paths) do\n        table.insert(paths_removed, \"__remove_\" .. pathname)\n    end\n\n    -- save values\n    scope[name] = self:_api_handle(name, table.join2(table.wrap(scope[name]), paths_removed))\n\n    -- save api source info, e.g. call api() in sourcefile:linenumber\n    self:_api_save_sourceinfo_to_scope(scope, name, paths)\nend\n\n-- get the scope kind\nfunction _instance:kind()\n    return self._KIND\nend\n\n-- is root scope?\nfunction _instance:is_root()\n    return self:kind() == \"root\"\nend\n\n-- get all scope info\nfunction _instance:info()\n    return self._INFO\nend\n\n-- get interpreter\nfunction _instance:interpreter()\n    return self._INTERPRETER\nend\n\n-- get the scope info from the given name\nfunction _instance:get(name)\n    return self._INFO[name]\nend\n\n-- set the value to the scope info\nfunction _instance:set(name, value)\n    self._INFO[name] = value\nend\n\n-- set the api values to the scope info\nfunction _instance:apival_set(name, ...)\n    if type(name) == \"string\" then\n        local api_type = self:_api_type(\"set_\" .. name)\n        if api_type then\n            local set_xxx = self[\"_api_set_\" .. api_type]\n            if set_xxx then\n                set_xxx(self, name, ...)\n            else\n                os.raise(\"unknown apitype(%s) for %s:set(%s, ...)\", api_type, self:kind(), name)\n            end\n        else\n            -- unknown api values? only set values\n            self:_api_set_values(name, ...)\n        end\n\n    -- set array, e.g. set({{links = ..}, {links = ..}})\n    elseif table.is_array(name) then\n        local array = name\n        for _, dict in ipairs(array) do\n            for k, v in pairs(dict) do\n                self:apival_set(k, table.unpack(table.wrap(v)))\n            end\n        end\n\n    -- set dictionary, e.g. set({links = ..})\n    elseif table.is_dictionary(name) then\n        local dict = name\n        for k, v in pairs(dict) do\n            self:apival_set(k, table.unpack(table.wrap(v)))\n        end\n    elseif name ~= nil then\n        os.raise(\"unknown type(%s) for %s:set(%s, ...)\", type(name), self:kind(), name)\n    end\nend\n\n-- add the api values to the scope info\nfunction _instance:apival_add(name, ...)\n    if type(name) == \"string\" then\n        local api_type = self:_api_type(\"add_\" .. name)\n        if api_type then\n            local add_xxx = self[\"_api_add_\" .. api_type]\n            if add_xxx then\n                add_xxx(self, name, ...)\n            else\n                os.raise(\"unknown apitype(%s) for %s:add(%s, ...)\", api_type, self:kind(), name)\n            end\n        else\n            -- unknown api values? only add values\n            self:_api_add_values(name, ...)\n        end\n\n    -- add array, e.g. add({{links = ..}, {links = ..}})\n    elseif table.is_array(name) then\n        local array = name\n        for _, dict in ipairs(array) do\n            for k, v in pairs(dict) do\n                self:apival_add(k, table.unpack(table.wrap(v)))\n            end\n        end\n\n    -- add dictionary, e.g. add({links = ..})\n    elseif table.is_dictionary(name) then\n        local dict = name\n        for k, v in pairs(dict) do\n            self:apival_add(k, table.unpack(table.wrap(v)))\n        end\n    elseif name ~= nil then\n        os.raise(\"unknown type(%s) for %s:add(%s, ...)\", type(name), self:kind(), name)\n    end\nend\n\n-- remove the api values to the scope info (deprecated)\nfunction _instance:apival_del(name, ...)\n    if type(name) == \"string\" then\n        local api_type = self:_api_type(\"del_\" .. name)\n        if api_type then\n            local del_xxx = self[\"_api_remove_\" .. api_type]\n            if del_xxx then\n                del_xxx(self, name, ...)\n            else\n                os.raise(\"unknown apitype(%s) for %s:del(%s, ...)\", api_type, self:kind(), name)\n            end\n        else\n            os.raise(\"unknown api(%s) for %s:del(%s, ...)\", name, self:kind(), name)\n        end\n    elseif name ~= nil then\n        -- TODO\n        os.raise(\"cannot support to remove a dictionary!\")\n    end\nend\n\n-- remove the api values to the scope info\nfunction _instance:apival_remove(name, ...)\n    if type(name) == \"string\" then\n        local api_type = self:_api_type(\"remove_\" .. name)\n        if api_type then\n            local remove_xxx = self[\"_api_remove_\" .. api_type]\n            if remove_xxx then\n                remove_xxx(self, name, ...)\n            else\n                os.raise(\"unknown apitype(%s) for %s:remove(%s, ...)\", api_type, self:kind(), name)\n            end\n        else\n            os.raise(\"unknown api(%s) for %s:remove(%s, ...)\", name, self:kind(), name)\n        end\n    elseif name ~= nil then\n        -- TODO\n        os.raise(\"cannot support to remove a dictionary!\")\n    end\nend\n\n-- get the extra configuration\n--\n-- e.g.\n--\n-- add_includedirs(\"inc\", {public = true})\n--\n-- function (target)\n--     _instance:extraconf(\"includedirs\", \"inc\", \"public\")  -> true\n--     _instance:extraconf(\"includedirs\", \"inc\")  -> {public = true}\n--     _instance:extraconf(\"includedirs\")  -> {inc = {public = true}}\n-- end\n--\nfunction _instance:extraconf(name, item, key)\n\n    -- get extra configurations\n    local extraconfs = self._EXTRACONFS\n    if not extraconfs then\n        extraconfs = {}\n        self._EXTRACONFS = extraconfs\n    end\n\n    -- get configuration\n    local extraconf = extraconfs[name]\n    if not extraconf then\n        extraconf = self:get(\"__extra_\" .. name)\n        extraconfs[name] = extraconf\n    end\n\n    -- get configuration value\n    local value = extraconf\n    if item then\n        value = extraconf and extraconf[item] or nil\n        if value == nil and extraconf and type(item) == \"table\" then\n            value = extraconf[table.concat(item, \"_\")]\n        end\n        if value and key then\n            value = value[key]\n        end\n    end\n    return value\nend\n\n-- set the extra configuration\n--\n-- e.g.\n--\n-- add_includedirs(\"inc\", {public = true})\n--\n-- function (target)\n--     _instance:extraconf_set(\"includedirs\", \"inc\", \"public\", true)\n--     _instance:extraconf_set(\"includedirs\", \"inc\", {public = true})\n--     _instance:extraconf_set(\"includedirs\", {inc = {public = true}})\n-- end\n--\nfunction _instance:extraconf_set(name, item, key, value)\n    if key ~= nil then\n        local extraconf = self:get(\"__extra_\" .. name) or {}\n        if value ~= nil then\n            extraconf[item] = extraconf[item] or {}\n            extraconf[item][key] = value\n        else\n            extraconf[item] = key\n        end\n        self:set(\"__extra_\" .. name, extraconf)\n    else\n        self:set(\"__extra_\" .. name, item)\n    end\nend\n\n-- get configuration source information of the given api item\n--\n-- e.g.\n-- self:get(\"defines\", \"TEST\")\n--  - add_defines(\"TEST\")\n--    - src/xmake.lua:10\n--\nfunction _instance:sourceinfo(name, item)\n    return (self:get(\"__sourceinfo_\" .. name) or {})[item]\nend\n\n-- clone a new instance from the current\nfunction _instance:clone()\n    return _instance.new(self:kind(), table.clone(self:info(), 3), { -- @note we need do deep clone\n        interpreter = self:interpreter(),\n        deduplicate = self._DEDUPLICATE,\n        enable_filter = self._ENABLE_FILTER})\nend\n\n-- new a scope instance\nfunction scopeinfo.new(...)\n    return _instance.new(...)\nend\n\n-- return module\nreturn scopeinfo\n"
  },
  {
    "path": "xmake/core/base/semver.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        semver.lua\n--\n\n-- define module: semver\nlocal semver = semver or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal string    = require(\"base/string\")\n\n-- get the version info\nfunction _instance:get(name)\n    local value = self._INFO[name]\n    if value ~= nil then\n        return value\n    end\nend\n\n-- get the major version, e.g. v{major}.{minor}.{patch}\nfunction _instance:major()\n    return self:get(\"major\")\nend\n\n-- get the minor version\nfunction _instance:minor()\n    return self:get(\"minor\")\nend\n\n-- get the patch version\nfunction _instance:patch()\n    return self:get(\"patch\")\nend\n\n-- get the build version, e.g. v1.0.1+{build}\nfunction _instance:build()\n    return self:get(\"build\")\nend\n\n-- get the prerelease version, e.g. v1.0.1-{prerelease}\nfunction _instance:prerelease()\n    return self:get(\"prerelease\")\nend\n\n-- get the raw version string\nfunction _instance:rawstr()\n    return self:get(\"raw\")\nend\n\n-- get the short version string\nfunction _instance:shortstr()\n    local str = self:major()\n    if self:minor() then\n        str = str .. \".\" .. self:minor()\n    end\n    if self:patch() then\n        str = str .. \".\" .. self:patch()\n    end\n    return str\nend\n\n-- satisfies the given semantic version(e.g. '> 1.0 < 2.0', '~1.5')?\nfunction _instance:satisfies(version)\n    return semver.satisfies(self:rawstr(), version)\nend\n\n-- is in the given version range, [version1, version2]?\nfunction _instance:at(version1, version2)\n    return self:ge(version1) and self:le(version2)\nend\n\n-- add string compatible interface, string.sub\nfunction _instance:sub(...)\n    return self:rawstr():sub(...)\nend\n\n-- add string compatible interface, string.gsub\nfunction _instance:gsub(...)\n    return self:rawstr():gsub(...)\nend\n\n-- add string compatible interface, string.split\nfunction _instance:split(...)\n    return self:rawstr():split(...)\nend\n\n-- add string compatible interface, string.startswith\nfunction _instance:startswith(...)\n    return self:rawstr():startswith(...)\nend\n\n-- add string compatible interface, string.endswith\nfunction _instance:endswith(...)\n    return self:rawstr():endswith(...)\nend\n\n-- v1 == v2 (str/ver)?\nfunction _instance:eq(version)\n    if type(version) == \"string\" then\n        return semver.compare(self:rawstr(), version) == 0\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) == 0\n    end\nend\n\n-- v1 < v2 (str/ver)?\nfunction _instance:lt(version)\n    if type(version) == \"string\" then\n        return semver.compare(self:rawstr(), version) < 0\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) < 0\n    end\nend\n\n-- v1 <= v2 (str/ver)?\nfunction _instance:le(version)\n    if type(version) == \"string\" then\n        return semver.compare(self:rawstr(), version) <= 0\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) <= 0\n    end\nend\n\n-- v1 > v2 (str/ver)?\nfunction _instance:gt(version)\n    return not self:le(version)\nend\n\n-- v1 >= v2 (str/ver)?\nfunction _instance:ge(version)\n    return not self:lt(version)\nend\n\n-- v1 == v2?\nfunction _instance:__eq(version)\n    if type(self) == \"string\" then\n        return version:eq(self)\n    else\n        return self:eq(version)\n    end\nend\n\n-- v1 < v2?\nfunction _instance:__lt(version)\n    if type(self) == \"string\" then\n        return version:gt(self)\n    else\n        return self:lt(version)\n    end\nend\n\n-- v1 <= v2?\nfunction _instance:__le(version)\n    if type(self) == \"string\" then\n        return version:ge(self)\n    else\n        return self:le(version)\n    end\nend\n\n-- get the raw version string\nfunction _instance:__tostring()\n    return self:rawstr()\nend\n\n-- add string compatible interface, e.g. version .. str\nfunction _instance.__concat(op1, op2)\n    if type(op1) == \"string\" then\n        return op1 .. op2:rawstr()\n    elseif type(op2) == \"string\" then\n        return op1:rawstr() .. op2\n    else\n        return op1:rawstr() .. op2:rawstr()\n    end\nend\n\n-- new an instance\nfunction semver.new(version)\n\n    -- parse version first\n    local info, errors = semver.parse(version)\n    if not info then\n        return nil, errors\n    end\n\n    -- new an instance\n    local instance = table.inherit(_instance)\n    instance._INFO = info\n    return instance\nend\n\n-- try to match valid version from string\nfunction semver.match(str, pos, pattern)\n    local patterns = pattern or {\"%d+[.]%d+[-+.%w]*\", \"%d+[.]%d+[.]%d+\", \"%d+[.]%d+\"}\n    for _, pattern in ipairs(table.wrap(patterns)) do\n        local version_str = str:match(pattern, pos)\n        if version_str then\n            local info = semver.parse(version_str)\n            if info then\n                local instance = table.inherit(_instance)\n                instance._INFO = info\n                return instance\n            end\n        end\n    end\nend\n\n-- return module: semver\nreturn semver\n"
  },
  {
    "path": "xmake/core/base/serialize.lua",
    "content": "\n--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu, ruki\n-- @file        serialize.lua\n--\n\n-- define module: serialize\nlocal serialize  = serialize or {}\nlocal stub       = serialize._stub or {}\nserialize._stub  = stub\nserialize._dump  = serialize._dump or string._dump or string.dump\nserialize._BCTAG = xmake._LUAJIT and \"\\27LJ\" or \"\\27Lua\"\nstub.isstub      = setmetatable({}, { __tostring = function() return \"stub indentifier\" end })\nstub.__index     = stub\n\n-- load modules\nlocal math      = require(\"base/math\")\nlocal table     = require(\"base/table\")\nlocal hashset   = require(\"base/hashset\")\n\nfunction stub:__call(root, fenv)\n    return self.resolver(root, fenv, table.unpack(self.params, 1, self.params.n))\nend\n\nfunction stub:__tostring()\n    local fparams = {}\n    for i = 1, self.params.n do\n        fparams[i] = serialize._make(self.params[i], {})\n    end\n    return string.format(\"%s(%s)\", self.name, table.concat(fparams, \", \"))\nend\n\n-- reserved keywords in lua\nfunction serialize._keywords()\n    local keywords = serialize._KEYWORDS\n    if not keywords then\n        keywords  = hashset.of(\"and\", \"break\", \"do\", \"else\", \"elseif\", \"end\", \"false\", \"for\", \"function\", \"goto\", \"if\", \"in\", \"local\", \"nil\", \"not\", \"or\", \"repeat\", \"return\", \"then\", \"true\", \"until\", \"while\")\n        serialize._KEYWORDS = keywords\n    end\n    return keywords\nend\n\nfunction serialize._makestring(str, opt)\n    if string.find(str, \"\\\\\", 1, true) and not string.find(str, \"[%c%]%\\n]\") then\n        return string.format(\"[[%s]]\", str)\n    else\n        return string.format(\"%q\", str)\n    end\nend\n\nfunction serialize._makedefault(val, opt)\n    return tostring(val)\nend\n\nfunction serialize._maketable(obj, opt, level, pathsegs, reftab)\n\n    level = level or 0\n    reftab = reftab or {}\n    pathsegs = pathsegs or {}\n    reftab[obj] = table.copy(pathsegs)\n\n    -- serialize child items\n    local childlevel = level + 1\n    local serialized = {}\n    local numidxcount = 0\n    local isarr = true\n    local maxn = 0\n    for k, v in pairs(obj) do\n        -- check key\n        if type(k) == \"number\" then\n            -- only checks when it may be an array\n            if isarr then\n                numidxcount = numidxcount + 1\n                if k < 1 or not math.isint(k) then\n                    isarr = false\n                elseif k > maxn then\n                    maxn = k\n                end\n            end\n        elseif type(k) == \"string\" then\n            isarr = false\n        else\n            return nil, string.format(\"cannot serialize table with key of %s: <%s>\", type(k), k)\n        end\n\n        -- serialize value\n        local sval, err\n        if type(v) == \"table\" then\n            if reftab[v] then\n                sval, err = serialize._makeref(reftab[v], opt)\n            else\n                table.insert(pathsegs, k)\n                sval, err = serialize._maketable(v, opt, childlevel, pathsegs, reftab)\n                table.remove(pathsegs)\n            end\n        else\n            sval, err = serialize._make(v, opt)\n        end\n        if err ~= nil then\n            return nil, err\n        end\n        serialized[k] = sval\n    end\n\n    -- empty table\n    if isarr and numidxcount == 0 then\n        return opt.indentstr and \"{ }\" or \"{}\"\n    end\n\n    -- too sparse\n    if numidxcount * 2 < maxn then\n        isarr = false\n    end\n\n    -- make body\n    local bodystrs = {}\n    if isarr then\n        for i = 1, maxn do\n            bodystrs[i] = serialized[i] or \"nil\"\n        end\n    else\n        local dformat = opt.indentstr and \"%s = %s\" or \"%s=%s\"\n        local sformat = opt.indentstr and \"[%q] = %s\" or \"[%q]=%s\"\n        local nformat = opt.indentstr and \"[%s] = %s\" or \"[%s]=%s\"\n        local keywords = serialize._keywords()\n        local makepairs = opt.orderkeys and table.orderpairs or pairs\n        for k, v in makepairs(serialized) do\n            local format\n            -- serialize key\n            if type(k) == \"string\" then\n                if keywords:has(k) or not k:match(\"^[%a_][%w_]*$\") then\n                    format = sformat\n                else\n                    format = dformat\n                end\n            else -- type(k) == \"number\"\n                format = nformat\n            end\n            -- concat k = v\n            table.insert(bodystrs, string.format(format, k, v))\n        end\n    end\n\n    -- make head and tail\n    local headstr, bodysep, tailstr\n    if opt.indentstr then\n        local indent = \"\\n\" .. string.rep(opt.indentstr, level)\n        tailstr = indent .. \"}\"\n        indent = indent .. opt.indentstr\n        headstr = \"{\" .. indent\n        bodysep = \",\" .. indent\n    else\n        headstr, bodysep, tailstr = \"{\", \",\", \"}\"\n    end\n\n    -- concat together\n    return headstr .. table.concat(bodystrs, bodysep) .. tailstr\nend\n\nfunction serialize._makefunction(func, opt)\n    local ok, bytecode = pcall(serialize._dump, func, opt.strip)\n    if not ok then\n        return nil, string.format(\"%s: <%s>\", bytecode, func)\n    end\n    return string.format(\"func%q\", bytecode)\nend\n\nfunction serialize._resolvefunction(root, fenv, bytecode)\n    if type(bytecode) ~= \"string\" then\n        return nil, string.format(\"invalid bytecode (string expected, got %s)\", type(bytecode))\n    end\n    if not bytecode:startswith(serialize._BCTAG) then\n        return nil, \"cannot load incompatible bytecode\"\n    end\n\n    -- resolve funccode\n    local func, err = load(bytecode, \"=(func)\", \"b\", fenv)\n    if err ~= nil then\n        if err:startswith(\"(func): \") then\n            err = err:sub(#\"(func): \" + 1)\n        end\n        return nil, err\n    end\n\n    -- try restore upvalues\n    if fenv then\n        for i = 1, math.huge do\n            local upname = debug.getupvalue(func, i)\n            if upname == nil or upname == \"\" then\n                break\n            end\n            debug.setupvalue(func, i, fenv[upname])\n        end\n    end\n    return func\nend\n\nfunction serialize._makeref(pathsegs, opt)\n\n    -- root reference\n    if pathsegs[1] == nil then\n        return \"ref()\"\n    end\n\n    -- use replicas to avoid infinite generation of nested strings, e.g ref(\"\\\"xx\\\"\") => ref(\"\\\\\\\"xx\\\\\\\"\") => ..\n    local pathrefs = {}\n    for i, v in ipairs(pathsegs) do\n        pathrefs[i] = serialize._make(v, opt)\n    end\n\n    return \"ref(\" .. table.concat(pathrefs, opt.indentstr and \", \" or \",\") .. \")\"\nend\n\nfunction serialize._resolveref(root, fenv, ...)\n    local pathsegs = table.pack(\"<root>\", ...)\n    local pos = root\n    for i = 2, pathsegs.n do\n        local pathseg = pathsegs[i]\n        if type(pathseg) ~= \"string\" and type(pathseg) ~= \"number\" then\n            return nil, \"path segments should be string or number\"\n        end\n        if type(pos) ~= \"table\" then\n            local vpre = serialize._make(pathseg, {})\n            local pathstr = table.concat(pathsegs, \"/\", 1, i)\n            return nil, string.format(\"unable to resolve [%s] in %s, which is %s\", vpre, pathstr, pos)\n        end\n        pos = pos[pathseg]\n    end\n    return pos\nend\n\n-- make string with the level\nfunction serialize._make(obj, opt)\n\n    -- call make* by type\n    if type(obj) == \"string\" then\n        return serialize._makestring(obj, opt)\n    elseif type(obj) == \"boolean\" or type(obj) == \"nil\" then\n        return serialize._makedefault(obj, opt)\n    elseif type(obj) == \"number\" then\n        if math.isnan(obj) then -- fix nan for lua 5.3, -nan(ind)\n            return \"nan\"\n        end\n        local inf_val = math.isinf(obj)\n        if inf_val == 1 then -- fix huge for Solaris\n            return \"inf\"\n        elseif inf_val == -1 then -- fix -huge for Solaris\n            return \"-inf\"\n        end\n        return serialize._makedefault(obj, opt)\n    elseif type(obj) == \"table\" then\n        return serialize._maketable(obj, opt)\n    elseif type(obj) == \"function\" then\n        return serialize._makefunction(obj, opt)\n    else\n        return nil, string.format(\"cannot serialize %s: <%s>\", type(obj), obj)\n    end\nend\n\nfunction serialize._generateindentstr(indent)\n\n    -- init indent, from nil, boolean, number or string to false or string\n    if not indent then\n        -- no indent\n        return nil\n    elseif indent == true then\n        -- 4 spaces\n        return \"    \"\n    elseif type(indent) == \"number\" then\n        if indent < 0 then\n            return nil\n        elseif indent > 20 then\n            return nil, \"invalid opt.indent, too large\"\n        else\n            -- indent spaces\n            return string.rep(\" \", indent)\n        end\n    elseif type(indent) == \"string\" then\n        -- only whitespaces allowed\n        if not (indent:trim() == \"\") then\n            return nil, \"invalid opt.indent, only whitespaces are accepted\"\n        end\n        return indent\n    else\n        return nil, \"invalid opt.indent, should be boolean, number or string\"\n    end\nend\n\n-- serialize to string from the given obj\n--\n-- @param opt           serialize options\n--\n-- @return              string, errors\n--\nfunction serialize.save(obj, opt)\n\n    -- init options\n    if opt == true then\n        opt = { strip = true, binary = false, indent = false }\n    elseif not opt then\n        opt = {}\n    end\n\n    if opt.strip == nil then opt.strip = false end\n    if opt.binary == nil then opt.binary = false end\n    if opt.indent == nil then opt.indent = true end\n\n    local indent, ierrors = serialize._generateindentstr(opt.indent)\n    if ierrors then\n        return nil, ierrors\n    end\n    opt.indentstr = indent\n\n    -- make string\n    local ok, result, errors = pcall(serialize._make, obj, opt)\n    if not ok then\n        errors = \"cannot serialize: \" .. result\n    end\n\n    -- ok?\n    if errors ~= nil then\n        return nil, errors\n    end\n\n    if not opt.binary then\n        return result\n    end\n\n    -- binary mode\n    local func, lerr = load(\"return \" .. result, \"=\")\n    if lerr ~= nil then\n        return nil, lerr\n    end\n\n    local dump, derr = serialize._dump(func, true)\n    if derr ~= nil then\n        return nil, derr\n    end\n\n    -- return shorter representation\n    return (#dump < #result) and dump or result\nend\n\n-- called by functions in deserialize environment\n-- create a function (called stub) to finish deserialization\nfunction serialize._createstub(name, resolver, env, ...)\n    env.has_stub = true\n    return setmetatable({ name = name, resolver = resolver, params = table.pack(...)}, stub)\nend\n\n-- after deserialization by load()\n-- use this routine to call all stubs in deserialzed data\n--\n-- @param       obj   obj to search stubs\n--              root     root obj\n--              fenv     fenv of deserialzer caller\n--              pathseg  path key for current item\nfunction serialize._resolvestub(obj, root, fenv, pathseg)\n    if type(obj) ~= \"table\" then\n        return obj\n    end\n\n    if obj.isstub == stub.isstub then\n        local ok, result_or_errors, errors = pcall(obj, root, fenv)\n        if ok and errors == nil then\n            return result_or_errors\n        end\n\n        -- resolve & concat path only if error occurs\n        local pathsegs = {}\n        local level = 1\n        while true do\n            if debug.getinfo(level, \"f\").func ~= serialize._resolvestub then\n                break\n            end\n            local _, p = debug.getlocal(level, 4)\n            table.insert(pathsegs, 1, p)\n            level = level + 1\n        end\n        -- make error message\n        local errmsg = (ok and errors) or result_or_errors or \"unspecified error\"\n        return nil, string.format(\"failed to resolve stub '%s' at %s: %s\", obj.name, table.concat(pathsegs, \"/\"), errmsg)\n    end\n\n    for k, v in pairs(obj) do\n        local result, errors = serialize._resolvestub(v, root, fenv, k)\n        if errors ~= nil then\n            return nil, errors\n        end\n        obj[k] = result\n    end\n    return obj\nend\n\n-- create a env for deserialze load() call\nfunction serialize._createenv()\n    local env = { nan = math.nan, inf = math.huge }\n    function env.ref(...)\n        return serialize._createstub(\"ref\", serialize._resolveref, env, ...)\n    end\n    function env.func(...)\n        return serialize._createstub(\"func\", serialize._resolvefunction, env, ...)\n    end\n    return env\nend\n\n-- load table from string in table\nfunction serialize._load(str)\n\n    -- load table as script\n    local result = nil\n    local binary = str:startswith(serialize._BCTAG)\n    if not binary then\n        str = \"return \" .. str\n    end\n\n    -- load string\n    local env = serialize._createenv()\n    local script, errors = load(str, binary and \"=(b)\" or \"=(t)\", binary and \"b\" or \"t\", env)\n    if script then\n        local ok, obj = pcall(script)\n        if ok then\n            result = obj\n            if env.has_stub then\n                local fenv = debug.getfenv(debug.getinfo(3, \"f\").func)\n                result, errors = serialize._resolvestub(result, result, fenv, \"<root>\")\n            end\n        else\n            errors = tostring(obj)\n        end\n    end\n\n    if errors then\n        local data\n        if binary then\n            data = \"<binary data>\"\n        elseif #str > 30 then\n            data = string.format(\"%q... \", str:sub(8, 27))\n        else\n            data = string.format(\"%q\", str:sub(8))\n        end\n        -- error\n        return nil, string.format(\"cannot deserialize %s: %s\", data, errors)\n    end\n\n    return result\nend\n\n-- deserialize string to obj\n--\n-- @param str           the serialized string\n--\n-- @return              obj, errors\n--\nfunction serialize.load(str)\n    assert(str)\n\n    -- load string\n    local result, errors = serialize._load(str)\n    if errors ~= nil then\n        return nil, errors\n    end\n    return result\nend\n\n-- return module: serialize\nreturn serialize\n"
  },
  {
    "path": "xmake/core/base/signal.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        signal.lua\n--\n\n-- define module: signal\nlocal signal = signal or {}\n\n-- load modules\nlocal os = require(\"base/os\")\n\n-- signal code\nsignal.SIGINT = 2\n\n-- register signal handler\nfunction signal.register(signo, handler)\n    os.signal(signo, handler)\nend\n\n-- reset signal, SIGDFL\nfunction signal.reset(signo)\n    os.signal(signo, 1)\nend\n\n-- ignore signal, SIGIGN\nfunction signal.ignore(signo)\n    os.signal(signo, 2)\nend\n\n-- return module: signal\nreturn signal\n"
  },
  {
    "path": "xmake/core/base/singleton.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        singleton.lua\n--\n\n-- define module\nlocal singleton = singleton or {}\n\n-- get a singleton instance and create it if not exists\n--\n-- e.g.\n--\n-- function get_xxx()\n--      return {xxx = 1}\n-- end\n-- local instance = singleton.get(\"key\", get_xxx)\n--\n-- Or\n--\n-- function get_xxx()\n--\n--     -- get instance\n--     local instance, inited = singleton.get(get_xxx)\n--     if inited then\n--          return instance\n--     end\n--\n--     -- init instance\n--     instance.xxx = 1\n--     return instance\n-- end\n--\nfunction singleton.get(key, init)\n\n    -- get key\n    key = tostring(key)\n\n    -- get all instances\n    local instances = singleton.instances()\n\n    -- get singleton instance\n    local inited = true\n    local instance = instances[key]\n    if instance == nil then\n\n        -- init instance\n        if init then\n            instance = init()\n        else\n            -- mark as not inited\n            inited = false\n\n            -- init instance\n            instance = {}\n        end\n\n        -- save this instance\n        instances[key] = instance\n    end\n    return instance, inited\nend\n\n-- get all singleton instances\nfunction singleton.instances()\n    local instances = singleton._INSTANCES\n    if not instances then\n        instances = {}\n        singleton._INSTANCES = instances\n    end\n    return instances\nend\n\n-- return module: singleton\nreturn singleton\n"
  },
  {
    "path": "xmake/core/base/socket.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        socket.lua\n--\n\n-- define module\nlocal socket      = socket or {}\nlocal _instance   = _instance or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal libc      = require(\"base/libc\")\nlocal bytes     = require(\"base/bytes\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal scheduler = require(\"base/scheduler\")\n\n-- the socket types\nsocket.TCP   = 1\nsocket.UDP   = 2\nsocket.ICMP  = 3\n\n-- the socket families\nsocket.IPV4  = 1\nsocket.IPV6  = 2\nsocket.UNIX  = 3\n\n-- the socket events, @see tbox/platform/socket.h\nsocket.EV_RECV = 1\nsocket.EV_SEND = 2\nsocket.EV_CONN = socket.EV_SEND\nsocket.EV_ACPT = socket.EV_RECV\n\n-- the socket control code\nsocket.CTRL_SET_RECVBUFF = 2\nsocket.CTRL_SET_SENDBUFF = 4\n\n-- new a socket\nfunction _instance.new(socktype, family, sock)\n    local instance   = table.inherit(_instance)\n    instance._SOCK   = sock\n    instance._TYPE   = socktype\n    instance._FAMILY = family\n    setmetatable(instance, _instance)\n    return instance\nend\n\n-- get socket type\nfunction _instance:type()\n    return self._TYPE\nend\n\n-- get socket family\nfunction _instance:family()\n    return self._FAMILY\nend\n\n-- get cdata of socket\nfunction _instance:cdata()\n    return self._SOCK\nend\n\n-- get poller object type, poller.OT_SOCK\nfunction _instance:otype()\n    return 1\nend\n\n-- get socket rawfd\nfunction _instance:rawfd()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- get rawfd\n    local result, errors = io.socket_rawfd(self:cdata())\n    if not result and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- get socket peer address\nfunction _instance:peeraddr()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    -- get peer address\n    local result, errors = io.socket_peeraddr(self:cdata())\n    if not result and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- control socket\nfunction _instance:ctrl(code, value)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- control it\n    local ok, errors = io.socket_ctrl(self:cdata(), code, value)\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- bind socket\nfunction _instance:bind(addr, port)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- bind it\n    local ok, errors = io.socket_bind(self:cdata(), addr, port, self:family())\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- bind socket from the unix address\nfunction _instance:bind_unix(addr, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- must be unix socket\n    if self:family() ~= socket.UNIX then\n        return -1, string.format(\"%s: must be unix socket!\", self)\n    end\n\n    -- bind it\n    opt = opt or {}\n    local ok, errors = io.socket_bind(self:cdata(), addr, opt.is_abstract, self:family())\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- listen socket\nfunction _instance:listen(backlog)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- listen it\n    local ok, errors = io.socket_listen(self:cdata(), backlog or 10)\n    if not ok and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- accept socket\nfunction _instance:accept(opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- accept it\n    local sock, errors = io.socket_accept(self:cdata())\n    if not sock and not errors then\n        opt = opt or {}\n        local events, waiterrs = _instance.wait(self, socket.EV_ACPT, opt.timeout or -1)\n        if events == socket.EV_ACPT then\n            sock, errors = io.socket_accept(self:cdata())\n        else\n            errors = waiterrs\n        end\n    end\n    if not sock and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    if sock then\n        sock = _instance.new(self:type(), self:family(), sock)\n    end\n    return sock, errors\nend\n\n-- connect socket\nfunction _instance:connect(addr, port, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- connect it\n    local ok, errors = io.socket_connect(self:cdata(), addr, port, self:family())\n    if ok == 0 then\n        opt = opt or {}\n\n        -- trace socket\n        if socket._is_tracing_socket() then\n            print(string.format(\"%s: connecting %s:%d, timeout: %d\", self, addr, port, opt.timeout or -1))\n        end\n\n        local events, waiterrs = _instance.wait(self, socket.EV_CONN, opt.timeout or -1)\n        if events == socket.EV_CONN then\n            ok, errors = io.socket_connect(self:cdata(), addr, port, self:family())\n        else\n            errors = waiterrs\n        end\n    end\n    if ok < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- connect socket from the unix address\nfunction _instance:connect_unix(addr, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- must be unix socket\n    if self:family() ~= socket.UNIX then\n        return -1, string.format(\"%s: must be unix socket!\", self)\n    end\n\n    -- connect it\n    opt = opt or {}\n    local ok, errors = io.socket_connect(self:cdata(), addr, opt.is_abstract, self:family())\n    if ok == 0 then\n        local events, waiterrs = _instance.wait(self, socket.EV_CONN, opt.timeout or -1)\n        if events == socket.EV_CONN then\n            ok, errors = io.socket_connect(self:cdata(), addr, opt.is_abstract, self:family())\n        else\n            errors = waiterrs\n        end\n    end\n    if ok < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return ok, errors\nend\n\n-- send data to socket\nfunction _instance:send(data, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- get data address and size for bytes and string\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or datasize\n    if start < 1 or start > datasize then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > datasize + start - 1 then\n        return -1, string.format(\"%s: invalid last(%d)!\", self, last)\n    end\n\n    -- send it\n    local send = 0\n    local real = 0\n    local wait = false\n    local errors = nil\n    if opt.block then\n        local size = last + 1 - start\n        while start <= last do\n            real, errors = io.socket_send(self:cdata(), dataaddr + start - 1, last + 1 - start)\n            if real > 0 then\n                send = send + real\n                start = start + real\n                wait = false\n            elseif real == 0 and not wait then\n                local events, waiterrs = _instance.wait(self, socket.EV_SEND, opt.timeout or -1)\n                if events == socket.EV_SEND then\n                    wait = true\n                elseif events == 0 then\n                    os.raise(\"%s: send timeout!\", self)\n                else\n                    errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n        if send ~= size then\n            send = -1\n        end\n    else\n        send, errors = io.socket_send(self:cdata(), dataaddr + start - 1, last + 1 - start)\n        if send < 0 and errors then\n            errors = string.format(\"%s: %s\", self, errors)\n        end\n    end\n    return send, errors\nend\n\n-- send file to socket\nfunction _instance:sendfile(file, opt)\n\n    -- ensure the socket opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- ensure the file opened\n    local ok, errors = file:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- empty file?\n    if file:size() == 0 then\n        return -1, string.format(\"%s: send empty file!\", self)\n    end\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or file:size()\n\n    -- check start and last\n    if start > last or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d) and last(%d)!\", self, start, last)\n    end\n\n    -- send it\n    local send = 0\n    local real = 0\n    local wait = false\n    local errors = nil\n    if opt.block then\n        local size = last + 1 - start\n        while start <= last do\n            real, errors = io.socket_sendfile(self:cdata(), file._FILE, start, last)\n            if real > 0 then\n                send = send + real\n                start = start + real\n                wait = false\n            elseif real == 0 and not wait then\n                local events, waiterrs = _instance.wait(self, socket.EV_SEND, opt.timeout or -1)\n                if events == socket.EV_SEND then\n                    wait = true\n                elseif events == 0 then\n                    os.raise(\"%s: sendfile timeout!\", self)\n                else\n                    errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n        if send ~= size then\n            send = -1\n        end\n    else\n        send, errors = io.socket_sendfile(self:cdata(), file._FILE, start, last)\n        if send < 0 and errors then\n            errors = string.format(\"%s: %s\", self, errors)\n        end\n    end\n    return send, errors\nend\n\n-- recv data from socket\nfunction _instance:recv(buff, size, opt)\n    assert(buff)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- check buffer\n    size = size or buff:size()\n    if buff:size() < size then\n        return -1, string.format(\"%s: too small buffer!\", self)\n    end\n\n    -- check size\n    if size == 0 then\n        return 0\n    elseif size == nil or size < 0 then\n        return -1, string.format(\"%s: invalid size(%d)!\", self, size)\n    end\n\n    -- init start in buffer\n    opt = opt or {}\n    local start = opt.start or 1\n    local pos = start - 1\n    if start >= buff:size() or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n\n    -- recv it\n    local recv = 0\n    local real = 0\n    local wait = false\n    local data_or_errors = nil\n    if opt.block then\n        while recv < size do\n            real, data_or_errors = io.socket_recv(self:cdata(), buff:caddr() + pos + recv, math.min(buff:size() - pos - recv, size - recv))\n            if real > 0 then\n                recv = recv + real\n                wait = false\n            elseif real == 0 and not wait then\n                local events, waiterrs = _instance.wait(self, socket.EV_RECV, opt.timeout or -1)\n                if events == socket.EV_RECV then\n                    wait = true\n                elseif events == 0 then\n                    os.raise(\"%s: recv timeout!\", self)\n                else\n                    data_or_errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n        if recv == size then\n            data_or_errors = buff:slice(start, recv)\n        else\n            recv = -1\n        end\n    else\n        recv, data_or_errors = io.socket_recv(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n        if recv > 0 then\n            data_or_errors = buff:slice(start, recv)\n        end\n    end\n    if recv < 0 and data_or_errors then\n        data_or_errors = string.format(\"%s: %s\", self, data_or_errors)\n    end\n    return recv, data_or_errors\nend\n\n-- send udp data to peer\nfunction _instance:sendto(data, addr, port, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- only for udp\n    if self:type() ~= socket.UDP then\n        return -1, string.format(\"%s: sendto() only for udp socket!\", self)\n    end\n\n    -- check address\n    if not addr or not port then\n        return -1, string.format(\"%s: sendto empty address!\", self)\n    end\n\n    -- get data address and size for bytes and string\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or datasize\n    if start < 1 or start > datasize then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > datasize + start - 1 then\n        return -1, string.format(\"%s: invalid last(%d)!\", self, last)\n    end\n\n    -- send it\n    local send = 0\n    local wait = false\n    local errors = nil\n    if opt.block then\n        while true do\n            send, errors = io.socket_sendto(self:cdata(), dataaddr + start - 1, last + 1 - start, addr, port, self:family())\n            if send == 0 and not wait then\n                local events, waiterrs = _instance.wait(self, socket.EV_SEND, opt.timeout or -1)\n                if events == socket.EV_SEND then\n                    wait = true\n                else\n                    errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n    else\n        send, errors = io.socket_sendto(self:cdata(), dataaddr + start - 1, last + 1 - start, addr, port, self:family())\n        if send < 0 and errors then\n            errors = string.format(\"%s: %s\", self, errors)\n        end\n    end\n    return send, errors\nend\n\n-- recv udp data from peer\nfunction _instance:recvfrom(buff, size, opt)\n    assert(buff)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- only for udp\n    if self:type() ~= socket.UDP then\n        return -1, string.format(\"%s: sendto() only for udp socket!\", self)\n    end\n\n    -- check buffer\n    size = size or buff:size()\n    if buff:size() < size then\n        return -1, string.format(\"%s: too small buffer!\", self)\n    end\n\n    -- check size\n    if size == 0 then\n        return 0\n    elseif size == nil or size < 0 then\n        return -1, string.format(\"%s: invalid size(%d)!\", self, size)\n    end\n\n    -- init start in buffer\n    opt = opt or {}\n    local start = opt.start or 1\n    local pos = start - 1\n    if start >= buff:size() or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n\n    -- recv it\n    local recv = 0\n    local wait = false\n    local data_or_errors = nil\n    if opt.block then\n        while true do\n            recv, data_or_errors, addr, port = io.socket_recvfrom(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n            if recv > 0 then\n                data_or_errors = buff:slice(start, recv)\n                break\n            elseif recv == 0 and not wait then\n                local events, waiterrs = _instance.wait(self, socket.EV_RECV, opt.timeout or -1)\n                if events == socket.EV_RECV then\n                    wait = true\n                else\n                    recv = -1\n                    data_or_errors = waiterrs\n                    break\n                end\n            else\n                break\n            end\n        end\n    else\n        recv, data_or_errors, addr, port = io.socket_recvfrom(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n        if recv > 0 then\n            data_or_errors = buff:slice(start, recv)\n        end\n    end\n    if recv < 0 and data_or_errors then\n        data_or_errors = string.format(\"%s: %s\", self, data_or_errors)\n    end\n    return recv, data_or_errors, addr, port\nend\n\n-- wait socket events\nfunction _instance:wait(events, timeout)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- wait events\n    local result = -1\n    local errors = nil\n    if scheduler:co_running() then\n        result, errors = scheduler:poller_wait(self, events, timeout or -1)\n    else\n        result, errors = io.socket_wait(self:cdata(), events, timeout or -1)\n    end\n    if result < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return result, errors\nend\n\n-- kill socket\nfunction _instance:kill()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- kill it\n    io.socket_kill(self:cdata())\n    return true\nend\n\n-- close socket\nfunction _instance:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- cancel socket events from the scheduler\n    if scheduler:co_running() then\n        ok, errors = scheduler:poller_cancel(self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- close it\n    ok = io.socket_close(self:cdata())\n    if ok then\n        self._SOCK = nil\n    end\n    return ok\nend\n\n-- ensure the socket is opened\nfunction _instance:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(socket)\nfunction _instance:__tostring()\n    local rawfd = self:cdata() and self:rawfd() or \"closed\"\n    local types = {\"tcp\", \"udp\", \"icmp\"}\n    return string.format(\"<socket: %s%s/%s>\", types[self:type()], self:family() == socket.IPV6 and \"6\" or \"4\", rawfd)\nend\n\n-- gc(socket)\nfunction _instance:__gc()\n    if self:cdata() and io.socket_close(self:cdata()) then\n        self._SOCK = nil\n    end\nend\n\n-- trace socket for profile(stuck,trace)?\nfunction socket._is_tracing_socket()\n    local is_tracing = socket._IS_TRACING_SOCKET\n    if is_tracing == nil then\n        local profile = os.getenv(\"XMAKE_PROFILE\")\n        if profile then\n            profile = profile:trim()\n            if profile == \"trace\" or profile == \"stuck\" then\n                is_tracing = true\n            end\n        end\n        is_tracing = is_tracing or false\n        socket._IS_TRACING_SOCKET = is_tracing\n    end\n    return is_tracing\nend\n\n-- open a socket\n--\n-- @param socktype      the socket type, e.g. tcp, udp, icmp\n-- @param family        the address family, e.g. ipv4, ipv6\n--\n-- @return the socket instance\n--\nfunction socket.open(socktype, family)\n    socktype = socktype or socket.TCP\n    family   = family or socket.IPV4\n    local sock, errors = io.socket_open(socktype, family)\n    if sock then\n        return _instance.new(socktype, family, sock)\n    else\n        return nil, errors or string.format(\"failed to open socket(%s/%s)!\", socktype, family)\n    end\nend\n\n-- open tcp socket\nfunction socket.tcp(opt)\n    opt = opt or {}\n    return socket.open(socket.TCP, opt.family or socket.IPV4)\nend\n\n-- open udp socket\nfunction socket.udp(opt)\n    opt = opt or {}\n    return socket.open(socket.UDP, opt.family or socket.IPV4)\nend\n\n-- open unix socket\nfunction socket.unix(opt)\n    return socket.open(socket.TCP, socket.UNIX)\nend\n\n-- open and bind tcp socket\nfunction socket.bind(addr, port, opt)\n    local sock, errors = socket.tcp(opt)\n    if not sock then\n        return nil, errors\n    end\n    local ok, errors = sock:bind(addr, port)\n    if not ok then\n        sock:close()\n        return nil, string.format(\"bind %s:%s failed, %s!\", addr, port, errors or \"unknown reason\")\n    end\n    return sock\nend\n\n-- open and bind tcp socket from the unix address\nfunction socket.bind_unix(addr, opt)\n    local sock, errors = socket.unix(opt)\n    if not sock then\n        return nil, errors\n    end\n    local ok, errors = sock:bind_unix(addr, opt)\n    if not ok then\n        sock:close()\n        return nil, string.format(\"bind unix://%s failed, %s!\", addr, errors or \"unknown reason\")\n    end\n    return sock\nend\n\n-- open and connect tcp socket\nfunction socket.connect(addr, port, opt)\n    local sock, errors = socket.tcp(opt)\n    if not sock then\n        return nil, errors\n    end\n    local ok, errors = sock:connect(addr, port, opt)\n    if ok <= 0 then\n        sock:close()\n        return nil, errors\n    end\n    return sock\nend\n\n-- open and connect tcp socket from the unix address\nfunction socket.connect_unix(addr, opt)\n    local sock, errors = socket.unix(opt)\n    if not sock then\n        return nil, errors\n    end\n    local ok, errors = sock:connect_unix(addr, opt)\n    if ok <= 0 then\n        sock:close()\n        return nil, errors\n    end\n    return sock\nend\n\n-- return module\nreturn socket\n"
  },
  {
    "path": "xmake/core/base/string.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        string.lua\n--\n\n-- define module: string\nlocal string = string or {}\n\n-- load modules\nlocal deprecated = require(\"base/deprecated\")\nlocal serialize  = require(\"base/serialize\")\nlocal bit        = require(\"base/bit\")\n\n-- save original interfaces\nstring._dump   = string._dump or string.dump\nstring._trim   = string._trim or string.trim\nstring._split  = string._split or string.split\nstring._lastof = string._lastof or string.lastof\n\n-- find the last substring with the given pattern\nfunction string:lastof(pattern, plain)\n\n    -- is plain text? use the native implementation\n    if plain then\n        return string._lastof(self, pattern)\n    end\n\n    -- find the last substring\n    local curr = 0\n    repeat\n        local next = self:find(pattern, curr + 1, plain)\n        if next then\n            curr = next\n        end\n    until (not next)\n\n    -- found?\n    if curr > 0 then\n        return curr\n    end\nend\n\n-- split string with the given substring/characters\n--\n-- pattern match and ignore empty string\n-- (\"1\\n\\n2\\n3\"):split('\\n') => 1, 2, 3\n-- (\"abc123123xyz123abc\"):split('123') => abc, xyz, abc\n-- (\"abc123123xyz123abc\"):split('[123]+') => abc, xyz, abc\n--\n-- plain match and ignore empty string\n-- (\"1\\n\\n2\\n3\"):split('\\n', {plain = true}) => 1, 2, 3\n-- (\"abc123123xyz123abc\"):split('123', {plain = true}) => abc, xyz, abc\n--\n-- pattern match and contains empty string\n-- (\"1\\n\\n2\\n3\"):split('\\n', {strict = true}) => 1, , 2, 3\n-- (\"abc123123xyz123abc\"):split('123', {strict = true}) => abc, , xyz, abc\n-- (\"abc123123xyz123abc\"):split('[123]+', {strict = true}) => abc, xyz, abc\n--\n-- plain match and contains empty string\n-- (\"1\\n\\n2\\n3\"):split('\\n', {plain = true, strict = true}) => 1, , 2, 3\n-- (\"abc123123xyz123abc\"):split('123', {plain = true, strict = true}) => abc, , xyz, abc\n--\n-- limit split count\n-- (\"1\\n\\n2\\n3\"):split('\\n', {limit = 2}) => 1, 2\\n3\n-- (\"1.2.3.4.5\"):split('%.', {limit = 3}) => 1, 2, 3.4.5\n--\nfunction string:split(delimiter, opt)\n    if #delimiter == 0 then\n        os.raise(\"string.split(%s, \\\"\\\") use empty delimiter\", self)\n    end\n    local limit, plain, strict\n    if opt then\n        limit = opt.limit\n        plain = opt.plain\n        strict = opt.strict\n    end\n    if plain then\n        return string._split(self, delimiter, strict, limit)\n    end\n    local start = 1\n    local result = {}\n    local pos, epos = self:find(delimiter, start, plain)\n    while pos do\n        local substr = self:sub(start, pos - 1)\n        if (#substr > 0) or strict then\n            if limit and limit > 0 and #result + 1 >= limit then\n                break\n            end\n            table.insert(result, substr)\n        end\n        start = epos + 1\n        pos, epos = self:find(delimiter, start, plain)\n    end\n    if start <= #self then\n        table.insert(result, self:sub(start))\n    elseif strict and (not limit or #result < limit) then\n        if start == #self + 1 then\n            table.insert(result, \"\")\n        end\n    end\n    return result\nend\n\n-- trim the spaces\nfunction string:trim(trimchars)\n    return string._trim(self, trimchars, 0)\nend\n\n-- trim the left spaces\nfunction string:ltrim(trimchars)\n    return string._trim(self, trimchars, -1)\nend\n\n-- trim the right spaces\nfunction string:rtrim(trimchars)\n    return string._trim(self, trimchars, 1)\nend\n\n-- replace text\nfunction string:replace(old, new, opt)\n    if opt and opt.plain then\n        local b, e = self:find(old, 1, true)\n        if b == nil then\n            return self, 0\n        else\n            local str, count = self:sub(e + 1):replace(old, new, opt)\n            return (self:sub(1, b - 1) .. new .. str), count + 1\n        end\n    else\n        return self:gsub(old, new)\n    end\nend\n\n-- try to format\nfunction string.tryformat(format, ...)\n    local ok, str = pcall(string.format, format, ...)\n    if ok then\n        return str\n    else\n        return tostring(format)\n    end\nend\n\n-- case-insensitive pattern-matching\n--\n-- print((\"src/dadasd.C\"):match(string.ipattern(\"sR[cd]/.*%.c\", true)))\n-- print((\"src/dadasd.C\"):match(string.ipattern(\"src/.*%.c\", true)))\n--\n-- print(string.ipattern(\"sR[cd]/.*%.c\"))\n--   [sS][rR][cd]/.*%.[cC]\n--\n-- print(string.ipattern(\"sR[cd]/.*%.c\", true))\n--   [sS][rR][cCdD]/.*%.[cC]\n--\nfunction string.ipattern(pattern, brackets)\n    local tmp = {}\n    local i = 1\n    while i <= #pattern do\n\n        -- get current charactor\n        local char = pattern:sub(i, i)\n\n        -- escape?\n        if char == '%' then\n            tmp[#tmp + 1] = char\n            i = i + 1\n            char = pattern:sub(i,i)\n            tmp[#tmp + 1] = char\n\n            -- '%bxy'? add next 2 chars\n            if char == 'b' then\n                tmp[#tmp + 1] = pattern:sub(i + 1, i + 2)\n                i = i + 2\n            end\n        -- brackets?\n        elseif char == '[' then\n            tmp[#tmp + 1] = char\n            i = i + 1\n            while i <= #pattern do\n                char = pattern:sub(i, i)\n                if char == '%' then\n                    tmp[#tmp + 1] = char\n                    tmp[#tmp + 1] = pattern:sub(i + 1, i + 1)\n                    i = i + 1\n                elseif char:match(\"%a\") then\n                    tmp[#tmp + 1] = not brackets and char or char:lower() .. char:upper()\n                else\n                    tmp[#tmp + 1] = char\n                end\n                if char == ']' then break end\n                i = i + 1\n            end\n        -- letter, [aA]\n        elseif char:match(\"%a\") then\n            tmp[#tmp + 1] = '[' .. char:lower() .. char:upper() .. ']'\n        else\n            tmp[#tmp + 1] = char\n        end\n        i = i + 1\n    end\n    return table.concat(tmp)\nend\n\n-- @deprecated\n-- dump to string from the given object (more readable)\n--\n-- @param deflate       deflate empty characters\n--\n-- @return              string, errors\n--\nfunction string.dump(object, deflate)\n    deprecated.add(\"utils.dump() or string.serialize()\", \"string.dump()\")\n    return string.serialize(object, deflate)\nend\n\n-- serialize to string from the given object\n--\n-- @param opt           serialize options\n--                      e.g. { strip = true, binary = false, indent = true }\n--\n-- @return              string, errors\n--\nfunction string.serialize(object, opt)\n    return serialize.save(object, opt)\nend\n\n-- deserialize string to object\n--\n-- @param str           the serialized string\n--\n-- @return              object, errors\n--\nfunction string:deserialize()\n    return serialize.load(self)\nend\n\n-- compute the Levenshtein distance between two strings\n--\n-- @param str2  the string to compare against\n-- @param opt   the options, e.g. {sub = 1, ins = 1, del = 1}\n--\n-- @return      the levenshtein distance\n--\nfunction string:levenshtein(str2, opt)\n    opt = opt or {}\n    local sub = opt.sub or 1\n    local ins = opt.ins or 1\n    local del = opt.del or 1\n\n    local str1 = self\n    local len1 = #str1\n    local len2 = #str2\n\n    if len1 == 0 then\n        return len2\n    elseif len2 == 0 then\n        return len1\n    elseif str1 == str2 then\n        return 0\n    end\n\n    local row1 = {}\n    local row2 = {}\n    local sub_cost = 0\n\n    for i = 1, len2 + 1 do\n        row1[i] = (i - 1) * ins\n    end\n    for i = 1, len1 do\n        row2[1] = i * del\n        for j = 1, len2 do\n            sub_cost = (str1:byte(i) == str2:byte(j)) and 0 or sub\n            row2[j + 1] = math.min(row1[j + 1] + del, row2[j] + ins, row1[j] + sub_cost)\n        end\n        row1, row2 = row2, row1\n    end\n    return row1[len2 + 1]\nend\n\n-- encode: ' ', '=', '\\\"', '<' (deprecated)\nfunction string:encode()\n    deprecated.add(nil, \"string:encode()\")\n    return (self:gsub(\"[%s=\\\"<]\", function (w) return string.format(\"%%%x\", w:byte()) end))\nend\n\n-- decode: ' ', '=', '\\\"' (deprecated)\nfunction string:decode()\n    deprecated.add(nil, \"string:decode()\")\n    return (self:gsub(\"%%(%x%x)\", function (w) return string.char(tonumber(w, 16)) end))\nend\n\n-- unicode character width in the given index (deprecated)\nfunction string:wcwidth(idx)\n\n    -- deprecated\n    deprecated.add(\"utf8.width(char)\", \"string:wcwidth(idx)\")\n\n    -- get codepoint and width\n    local utf8 = utf8 or require(\"base/utf8\")\n    local code = utf8.codepoint(self, idx)\n    return utf8.width(code)\nend\n\n-- unicode string width in given start index (deprecated)\nfunction string:wcswidth(idx)\n\n    -- deprecated\n    deprecated.add(\"utf8.width(str)\", \"string:wcswidth(idx)\")\n\n    -- get width\n    local utf8 = utf8 or require(\"base/utf8\")\n    if idx and idx > 1 then\n        return utf8.width(self:sub(idx))\n    else\n        return utf8.width(self)\n    end\nend\n\n-- return module: string\nreturn string\n"
  },
  {
    "path": "xmake/core/base/table.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        table.lua\n--\n\n-- define module: table\nlocal table = table or {}\n\n-- clear table\nif not table.clear then\n    if xmake._LUAJIT then\n        table.clear = require(\"table.clear\")\n    else\n        function table.clear(t)\n            for k, v in pairs(t) do\n                t[k] = nil\n            end\n        end\n    end\nend\n\n-- new table\nif not table.new then\n    if xmake._LUAJIT then\n        table.new = require(\"table.new\")\n    else\n        function table.new(narray, nhash)\n            -- TODO\n            return {}\n        end\n    end\nend\n\n-- get array length\nif not table.getn then\n    function table.getn(t)\n        return #t\n    end\nend\n\n-- get array max integer key for lua5.4\nif not table.maxn then\n    function table.maxn(t)\n        local max = 0\n        for k, _ in pairs(t) do\n            if type(k) == \"number\" and k > max then\n                max = k\n            end\n        end\n        return max\n    end\nend\n\n-- move values of table(a1) to table(a2)\n--\n-- disable the builtin implementation for android termux/arm64, it will crash when calling `table.move({1, 1}, 1, 2, 1, {})`\n--\n-- @see https://github.com/xmake-io/xmake/pull/667#issuecomment-575859604\n--\nif xmake._ARCH:startswith(\"arm\") then\n    function table.move(a1, f, e, t, a2)\n        if a2 == nil then a2 = a1 end\n        assert(a1)\n        assert(a2)\n        if e >= f then\n            local d = t - f\n            if t > e or t <= f or a2 ~= a1 then\n                for i = f, e do a2[i + d] = a1[i] end\n            else\n                for i = e, f, -1 do a2[i + d] = a1[i] end\n            end\n        end\n        return a2\n    end\nend\n\n-- join all objects and tables\nfunction table.join(...)\n    local result = {}\n    for _, t in ipairs({...}) do\n        if type(t) == \"table\" and not t.__wrap_locked__ then\n            for k, v in pairs(t) do\n                if type(k) == \"number\" then table.insert(result, v)\n                else result[k] = v end\n            end\n        else\n            table.insert(result, t)\n        end\n    end\n    return result\nend\n\n-- join all objects and tables to self\nfunction table.join2(self, ...)\n    for _, t in ipairs({...}) do\n        if type(t) == \"table\" and not t.__wrap_locked__ then\n            for k, v in pairs(t) do\n                if type(k) == \"number\" then table.insert(self, v)\n                else self[k] = v end\n            end\n        else\n            table.insert(self, t)\n        end\n    end\n    return self\nend\n\n-- shallow join all objects, it will not expand all table values\nfunction table.shallow_join(...)\n    local result = {}\n    for _, t in ipairs({...}) do\n        table.insert(result, t)\n    end\n    return result\nend\n\n\n-- shallow join all objects, it will not expand all table values\nfunction table.shallow_join2(self, ...)\n    for _, t in ipairs({...}) do\n        table.insert(self, t)\n    end\n    return self\nend\n\n-- swap items in array\nfunction table.swap(array, i, j)\n    local val = array[i]\n    array[i] = array[j]\n    array[j] = val\nend\n\n-- append all objects to array\nfunction table.append(array, ...)\n    for _, value in ipairs({...}) do\n        table.insert(array, value)\n    end\n    return array\nend\n\n-- clone table\n--\n-- @param depth   e.g. shallow: 1, deep: -1\n--\nfunction table.clone(self, depth)\n    depth = depth or 1\n    local result = self\n    if type(self) == \"table\" and depth > 0 then\n        result = {}\n        for k, v in pairs(self) do\n            result[k] = table.clone(v, depth - 1)\n        end\n    end\n    return result\nend\n\n-- copy the table (deprecated, please use table.clone)\nfunction table.copy(copied)\n    local result = {}\n    copied = copied or {}\n    for k, v in pairs(table.wrap(copied)) do\n        result[k] = v\n    end\n    return result\nend\n\n-- copy the table to self\nfunction table.copy2(self, copied)\n    table.clear(self)\n    copied = copied or {}\n    for k, v in pairs(table.wrap(copied)) do\n        self[k] = v\n    end\nend\n\n-- inherit interfaces and create a new instance\nfunction table.inherit(...)\n    local classes = {...}\n    local instance = {}\n    local metainfo = {}\n    for _, clasz in ipairs(classes) do\n        for k, v in pairs(clasz) do\n            if type(v) == \"function\" then\n                if k:startswith(\"__\") then\n                    if metainfo[k] == nil then\n                        metainfo[k] = v\n                    end\n                else\n                    if instance[k] == nil then\n                        instance[k] = v\n                    else\n                        instance[\"_super_\" .. k] = v\n                    end\n                end\n            end\n        end\n    end\n    setmetatable(instance, metainfo)\n    return instance\nend\n\n-- inherit interfaces from the given class\nfunction table.inherit2(self, ...)\n    local classes = {...}\n    local metainfo = getmetatable(self) or {}\n    for _, clasz in ipairs(classes) do\n        for k, v in pairs(clasz) do\n            if type(v) == \"function\" then\n                if k:startswith(\"__\") then\n                    if metainfo[k] == nil then\n                        metainfo[k] = v\n                    end\n                else\n                    if self[k] == nil then\n                        self[k] = v\n                    else\n                        self[\"_super_\" .. k] = v\n                    end\n                end\n            end\n        end\n    end\n    setmetatable(self, metainfo)\n    return self\nend\n\n-- slice table array\nfunction table.slice(self, first, last, step)\n    local sliced = {}\n    for i = first or 1, last or #self, step or 1 do\n        sliced[#sliced + 1] = self[i]\n    end\n    return sliced\nend\n\n-- is array?\nfunction table.is_array(array)\n    return type(array) == \"table\" and array[1] ~= nil\nend\n\n-- is dictionary?\nfunction table.is_dictionary(dict)\n    return type(dict) == \"table\" and dict[1] == nil\nend\n\n-- does contain the given values in table?\n-- contains arg1 or arg2 ...\nfunction table.contains(t, arg1, arg2, ...)\n    local found = false\n    if arg2 == nil then -- only one value\n        if table.is_array(t) then\n            for _, v in ipairs(t) do\n                if v == arg1 then\n                    found = true\n                    break\n                end\n            end\n        else\n            for _, v in pairs(t) do\n                if v == arg1 then\n                    found = true\n                    break\n                end\n            end\n        end\n    else\n        local values = {}\n        local args = table.pack(arg1, arg2, ...)\n        for _, arg in ipairs(args) do\n            values[arg] = true\n        end\n        if table.is_array(t) then\n            for _, v in ipairs(t) do\n                if values[v] then\n                    found = true\n                    break\n                end\n            end\n        else\n            for _, v in pairs(t) do\n                if values[v] then\n                    found = true\n                    break\n                end\n            end\n        end\n    end\n    return found\nend\n\n-- read data from iterator, push them to an array\n-- usage: table.to_array(ipairs(\"a\", \"b\")) -> {{1,\"a\",n=2},{2,\"b\",n=2}},2\n-- usage: table.to_array(io.lines(\"file\")) -> {\"line 1\",\"line 2\", ... , \"line n\"},n\nfunction table.to_array(iterator, state, var)\n    local result = {}\n    local count = 0\n    while true do\n        local data = table.pack(iterator(state, var))\n        if data[1] == nil then break end\n        var = data[1]\n\n        if data.n == 1 then\n            table.insert(result, var)\n        else\n            table.insert(result, data)\n        end\n        count = count + 1\n    end\n\n    return result, count\nend\n\n-- unwrap array if be only one value\nfunction table.unwrap(array)\n    if type(array) == \"table\" and not array.__wrap_locked__ then\n        if #array == 1 then\n            return array[1]\n        end\n    end\n    return array\nend\n\n-- wrap value to array\nfunction table.wrap(value)\n    if nil == value then\n        return {}\n    end\n    if type(value) ~= \"table\" or value.__wrap_locked__ then\n        return {value}\n    end\n    return value\nend\n\n-- lock table value to avoid unwrap\n--\n-- a = {1}, wrap(a): {1}, unwrap(a): 1\n-- a = wrap_lock({1}), wrap(a): {a}, unwrap(a): a\nfunction table.wrap_lock(value)\n    if type(value) == \"table\" then\n        value.__wrap_locked__ = true\n    end\n    return value\nend\n\n-- unlock table value to unwrap\nfunction table.wrap_unlock(value)\n    if type(value) == \"table\" then\n        value.__wrap_locked__ = nil\n    end\n    return value\nend\n\n-- remove repeat from the given array\nfunction table.unique(array, barrier)\n    if table.is_array(array) then\n        if table.getn(array) ~= 1 then\n            local exists = {}\n            local unique = {}\n            for _, v in ipairs(array) do\n                -- exists barrier? clear the current existed items\n                if barrier and barrier(v) then\n                    exists = {}\n                end\n                -- add unique item\n                if not exists[v] then\n                    exists[v] = true\n                    table.insert(unique, v)\n                end\n            end\n            if array.__wrap_locked__ then\n                table.wrap_lock(unique)\n            end\n            array = unique\n        end\n    end\n    return array\nend\n\n-- reverse to remove repeat from the given array\nfunction table.reverse_unique(array, barrier)\n    if table.is_array(array) then\n        if table.getn(array) ~= 1 then\n            local exists = {}\n            local unique = {}\n            local n = #array\n            for i = 1, n do\n                local v = array[n - i + 1]\n                -- exists barrier? clear the current existed items\n                if barrier and barrier(v) then\n                    exists = {}\n                end\n                -- add unique item\n                if not exists[v] then\n                    exists[v] = true\n                    table.insert(unique, 1, v)\n                end\n            end\n            if array.__wrap_locked__ then\n                table.wrap_lock(unique)\n            end\n            array = unique\n        end\n    end\n    return array\nend\n\n-- pack arguments into a table\n-- polyfill of lua 5.2, @see https://www.lua.org/manual/5.2/manual.html#pdf-table.pack\nfunction table.pack(...)\n    return { n = select(\"#\", ...), ... }\nend\n\n-- table.unpack table values\n-- polyfill of lua 5.2, @see https://www.lua.org/manual/5.2/manual.html#pdf-unpack\ntable.unpack = table.unpack or unpack\n\n-- get keys of a table\nfunction table.keys(tbl)\n    local keyset = {}\n    local n = 0\n    for k, _ in pairs(tbl) do\n        n = n + 1\n        keyset[n] = k\n    end\n    return keyset, n\nend\n\n-- get order keys of a table\nfunction table.orderkeys(tbl, callback)\n    local callback = type(callback) == \"function\" and callback or nil\n    local keys = table.keys(tbl)\n    if callback then\n        table.sort(keys, callback)\n    else\n        local ok = pcall(table.sort, keys)\n        if not ok then\n            -- maybe sort strings and numbers, {1, 2, \"a\"}\n            table.sort(keys, function (a, b) return tostring(a) < tostring(b) end)\n        end\n    end\n    return keys\nend\n\n-- order key/value iterator\n--\n-- for k, v in table.orderpairs(t) do\n--   TODO\n-- end\nfunction table.orderpairs(t, callback)\n    if type(t) ~= \"table\" then\n        t = t ~= nil and {t} or {}\n    end\n    local orderkeys = table.orderkeys(t, callback)\n    local i = 1\n    return function (t, k)\n        k = orderkeys[i]\n        i = i + 1\n        return k, t[k]\n    end, t, nil\nend\n\n-- get values of a table\nfunction table.values(tbl)\n    local valueset = {}\n    local n = 0\n    for _, v in pairs(tbl) do\n        n = n + 1\n        valueset[n] = v\n    end\n    return valueset, n\nend\n\n-- map values to a new table\nfunction table.map(tbl, mapper)\n    local newtbl = {}\n    for k, v in pairs(tbl) do\n        newtbl[k] = mapper(k, v)\n    end\n    return newtbl\nend\n\n-- map values to a new array\nfunction table.imap(arr, mapper)\n    local newarr = {}\n    for k, v in ipairs(arr) do\n        table.insert(newarr, mapper(k, v))\n    end\n    return newarr\nend\n\n-- reverse table values\nfunction table.reverse(arr)\n    local revarr = {}\n    local l = #arr\n    for i = 1, l do\n        revarr[i] = arr[l - i + 1]\n    end\n    return revarr\nend\n\n-- remove values if predicate is matched\nfunction table.remove_if(tbl, pred)\n    if table.is_array(tbl) then\n        for i = #tbl, 1, -1 do\n            if pred(i, tbl[i]) then\n                table.remove(tbl, i)\n            end\n        end\n    else\n        for k, v in pairs(tbl) do\n            if pred(k, v) then\n                tbl[k] = nil\n            end\n        end\n    end\n    return tbl\nend\n\n-- is empty table?\nfunction table.empty(tbl)\n    return type(tbl) == \"table\" and next(tbl) == nil\nend\n\n-- return indices or keys for the given value\nfunction table.find(tbl, value)\n    local result\n    if table.is_array(tbl) then\n        for i, v in ipairs(tbl) do\n            if v == value then\n                result = result or {}\n                table.insert(result, i)\n            end\n        end\n    else\n        for k, v in pairs(tbl) do\n            if v == value then\n                result = result or {}\n                table.insert(result, k)\n            end\n        end\n    end\n    return result\nend\n\n-- return indices or keys if predicate is matched\nfunction table.find_if(tbl, pred)\n    local result\n    if table.is_array(tbl) then\n        for i, v in ipairs(tbl) do\n            if pred(i, v) then\n                result = result or {}\n                table.insert(result, i)\n            end\n        end\n    else\n        for k, v in pairs(tbl) do\n            if pred(k, v) then\n                result = result or {}\n                table.insert(result, k)\n            end\n        end\n    end\n    return result\nend\n\n-- return first index for the given value\nfunction table.find_first(tbl, value)\n    for i, v in ipairs(tbl) do\n        if v == value then\n            return i\n        end\n    end\nend\n\n-- return first index if predicate is matched\nfunction table.find_first_if(tbl, pred)\n    for i, v in ipairs(tbl) do\n        if pred(i, v) then\n            return i\n        end\n    end\nend\n\n-- return module: table\nreturn table\n"
  },
  {
    "path": "xmake/core/base/task.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        task.lua\n--\n\n-- define module: task\nlocal task = task or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal table         = require(\"base/table\")\nlocal string        = require(\"base/string\")\nlocal global        = require(\"base/global\")\nlocal hashset       = require(\"base/hashset\")\nlocal interpreter   = require(\"base/interpreter\")\nlocal sandbox       = require(\"sandbox/sandbox\")\nlocal config        = require(\"project/config\")\nlocal sandbox_os    = require(\"sandbox/modules/os\")\n\nfunction task.common_options()\n    local common_options = task._COMMON_OPTIONS\n    if not common_options then\n        common_options = {\n            {'q', \"quiet\",     \"k\",  nil,   \"Quiet operation.\"                                          }\n        ,   {'y', \"yes\",       \"k\",  nil,   \"Input yes by default if need user confirm.\"                }\n        ,   {nil, \"confirm\",   \"kv\", nil,   \"Input the given result if need user confirm.\"\n                                        ,   values = function ()\n                                                return {\"yes\", \"no\", \"def\"}\n                                            end                                                         }\n        ,   {'v', \"verbose\",   \"k\",  nil,   \"Print lots of verbose information for users.\"              }\n        ,   {nil, \"root\",      \"k\",  nil,   \"Allow to run xmake as root.\"                               }\n        ,   {'D', \"diagnosis\", \"k\",  nil,   \"Print lots of diagnosis information (backtrace, check info ..) only for developers.\"\n                                        ,   \"And we can append -v to get more whole information.\"\n                                        ,   \"    e.g. $ xmake -vD\"                                      }\n        ,   {'h', \"help\",      \"k\",  nil,   \"Print this help message and exit.\"                         }\n        ,   {}\n        ,   {'F', \"file\",      \"kv\", nil,   \"Read a given xmake.lua file.\"                              }\n        ,   {'P', \"project\",   \"kv\", nil,   \"Change to the given project directory.\"\n                                        ,   \"Search priority:\"\n                                        ,   \"    1. The Given Command Argument\"\n                                        ,   \"    2. The Envirnoment Variable: XMAKE_PROJECT_DIR\"\n                                        ,   \"    3. The Current Directory\"                              }\n        ,   {category = \"action\"}\n        }\n        task._COMMON_OPTIONS = common_options\n    end\n    return task._COMMON_OPTIONS\nend\n\nfunction task._common_option_names()\n    local common_names = task._COMMON_OPTION_NAMES\n    if not common_names then\n        common_names = hashset.new()\n        for i, v in ipairs(task.common_options()) do\n            if v and v[1] then\n                common_names:insert(v[1])\n            end\n            if v and v[2] then\n                common_names:insert(v[2])\n            end\n        end\n        task._COMMON_OPTION_NAMES = common_names\n    end\n    return common_names\nend\n\n-- the directories of tasks\nfunction task._directories()\n    return {path.join(global.directory(), \"plugins\"),\n            path.join(os.programdir(), \"plugins\"),\n            path.join(os.programdir(), \"actions\")}\nend\n\n-- translate menu\nfunction task._translate_menu(taskname, menu)\n    local interp = task._interpreter()\n    local options = menu.options\n    if options then\n\n        -- make full options\n        local options_full = {}\n        for _, opt in ipairs(options) do\n            if type(opt) == \"function\" then\n                local ok, results = sandbox.load(opt)\n                if ok then\n                    if results then\n                        for _, opt in ipairs(results) do\n                            table.insert(options_full, opt)\n                        end\n                    end\n                else\n                    return nil, string.format(\"taskmenu: %s\", results)\n                end\n            else\n                table.insert(options_full, opt)\n            end\n        end\n\n        -- update the options\n        options = options_full\n        menu.options = options_full\n\n        -- filter options\n        if interp:filter() then\n            for _, opt in ipairs(options) do\n\n                -- filter default\n                local default = opt[4]\n                if type(default) == \"string\" then\n                    opt[4] = interp:filter():handle(default)\n                end\n\n                -- filter description\n                for i = 5, 64 do\n\n                    -- the description, @note some option may be nil\n                    local description = opt[i]\n                    if not description then break end\n\n                    -- the description is string?\n                    if type(description) == \"string\" then\n                        opt[i] = interp:filter():handle(description)\n\n                    -- the description is function? wrap it for calling it in the sandbox\n                    elseif type(description) == \"function\" then\n                        opt[i] = function ()\n\n                            -- call it in the sandbox\n                            local ok, results = sandbox.load(description)\n                            if not ok then\n                                return nil, string.format(\"taskmenu: %s\", results)\n                            end\n                            return results\n                        end\n                    end\n                end\n            end\n        end\n\n        -- add common options, we need to avoid repeat because the main/build task will be inserted twice\n        if not menu._common_options then\n            local common_option_names = task._common_option_names()\n            for _, v in ipairs(options) do\n                local option_name = v[2] or v[1]\n                if option_name and common_option_names:has(option_name) then\n                    utils.warning(\"task(%s): option name '%s' is a built-in name and may cause conflicts, please rename it.\", taskname, option_name)\n                end\n            end\n\n            for i, v in ipairs(task.common_options()) do\n                table.insert(options, i, v)\n            end\n            menu._common_options = true\n        end\n    end\n    return menu\nend\n\n-- the interpreter\nfunction task._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if task._INTERPRETER then\n        return task._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(task.apis())\n\n    -- set filter\n    interp:filter():register(\"task\", function (variable)\n\n        -- check\n        assert(variable)\n\n        -- attempt to get it directly from the configure\n        local result = config.get(variable)\n        if not result or type(result) ~= \"string\" then\n\n            -- init maps\n            local maps =\n            {\n                host        = os.host()\n            ,   subhost     = os.subhost()\n            ,   tmpdir      = function () return os.tmpdir() end\n            ,   curdir      = function () return os.curdir() end\n            ,   scriptdir   = function () return sandbox_os.scriptdir() end\n            ,   globaldir   = global.directory()\n            ,   configdir   = config.directory()\n            ,   projectdir  = os.projectdir()\n            ,   programdir  = os.programdir()\n            }\n\n            -- map it\n            result = maps[variable]\n            if type(result) == \"function\" then\n                result = result()\n            end\n        end\n\n        -- ok?\n        return result\n    end)\n\n    -- save interpreter\n    task._INTERPRETER = interp\n\n    -- ok?\n    return interp\nend\n\n-- bind script with a sandbox instance\nfunction task._bind_script(interp, script)\n    local instance, errors = sandbox.new(script, {\n        filter = interp:filter(), rootdir = interp:rootdir(), namespace = interp:namespace()})\n    if not instance then\n        return nil, errors\n    end\n    assert(instance:script())\n    return instance:script()\nend\n\n-- bind tasks for menu with a sandbox instance\nfunction task._bind(tasks, interp)\n\n    -- check\n    assert(tasks)\n\n    -- get interpreter\n    interp = interp or task._interpreter()\n    assert(interp)\n\n    -- bind sandbox for menus\n    for _, taskinst in pairs(tasks) do\n\n        -- has task menu?\n        local taskmenu = taskinst:get(\"menu\")\n        if taskmenu then\n\n            -- translate options\n            local options = taskmenu.options\n            if options then\n\n                -- make full options\n                local errors = nil\n                local options_full = {}\n                for _, opt in ipairs(options) do\n\n                    -- this option is function? translate it\n                    if type(opt) == \"function\" then\n                        opt, errors = task._bind_script(interp, opt)\n                        if not opt then\n                            return false, errors\n                        end\n                    end\n\n                    -- insert option\n                    table.insert(options_full, opt)\n                end\n\n                -- update the options\n                options = options_full\n                taskmenu.options = options_full\n\n                -- bind sandbox for scripts in option\n                for _, opt in ipairs(options) do\n\n                    -- bind description and values\n                    if type(opt) == \"table\" then\n\n                        -- bind description\n                        for i = 5, 64 do\n\n                            -- the description, @note some option may be nil\n                            local description = opt[i]\n                            if not description then break end\n\n                            -- the description is function? wrap it for calling it in the sandbox\n                            if type(description) == \"function\" then\n                                description, errors = task._bind_script(interp, description)\n                                if not description then\n                                    return false, errors\n                                end\n                                opt[i] = description\n                            end\n                        end\n\n                        -- bind values\n                        if type(opt.values) == \"function\" then\n                            local values, errors = task._bind_script(interp, opt.values)\n                            if not values then\n                                return false, errors\n                            end\n                            opt.values = values\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return true\nend\n\n-- load the given task script file\nfunction task._load(filepath)\n\n    -- get interpreter\n    local interp = task._interpreter()\n    assert(interp)\n\n    -- load script\n    local ok, errors = interp:load(filepath)\n    if not ok and os.isfile(filepath) then\n        return nil, errors\n    end\n\n    -- load tasks\n    local tasks, errors = interp:make(\"task\", true, true)\n    if not tasks then\n        return nil, errors\n    end\n\n    -- bind tasks for menu with an sandbox instance\n    local ok, errors = task._bind(tasks)\n    if not ok then\n        return nil, errors\n    end\n    return tasks\nend\n\n-- get task apis\nfunction task.apis()\n    return {\n        values = {\n            -- task.set_xxx\n            \"task.set_category\"     -- main, action, plugin, task (default)\n        },\n        dictionary = {\n            -- task.set_xxx\n            \"task.set_menu\"\n        },\n        script = {\n            -- task.on_xxx\n            \"task.on_run\"\n        }\n    }\nend\n\n-- new a task instance\nfunction task.new(name, info)\n    local instance = table.inherit(task)\n    if name then\n        local parts = name:split(\"::\", {plain = true})\n        instance._NAME = parts[#parts]\n        table.remove(parts)\n        if #parts > 0 then\n            instance._NAMESPACE = table.concat(parts, \"::\")\n        end\n    end\n    instance._INFO = info\n    return instance\nend\n\n-- get global tasks\nfunction task.tasks()\n    if task._TASKS then\n        return task._TASKS\n    end\n\n    -- load tasks\n    local tasks = {}\n    local dirs = task._directories()\n    for _, dir in ipairs(dirs) do\n        local files = os.files(path.join(dir, \"*\", \"xmake.lua\"))\n        if files then\n            for _, filepath in ipairs(files) do\n                local results, errors = task._load(filepath)\n                if results then\n                    table.join2(tasks, results)\n                else\n                    os.raise(errors)\n                end\n            end\n        end\n    end\n    local instances = {}\n    for taskname, taskinfo in pairs(tasks) do\n        instances[taskname] = task.new(taskname, taskinfo)\n    end\n    task._TASKS = instances\n    return instances\nend\n\n-- get the given global task\nfunction task.task(name)\n    return task.tasks()[name]\nend\n\n-- get the task menu\nfunction task.menu(tasks)\n    local menu = {}\n    for taskname, taskinst in pairs(tasks) do\n        local taskmenu = taskinst:get(\"menu\")\n        if taskmenu then\n            -- delay to load main menu\n            if taskinst:get(\"category\") == \"main\" then\n                menu.main = function ()\n\n                    -- translate main menu\n                    local mainmenu, errors = task._translate_menu(taskname, taskmenu)\n                    if not mainmenu then\n                        os.raise(errors)\n                    end\n\n                    -- make tasks for the main menu\n                    mainmenu.tasks = {}\n                    for name, inst in pairs(tasks) do\n                        local m = inst:get(\"menu\")\n                        if m then\n                            mainmenu.tasks[name] = {\n                                category    = inst:get(\"category\")\n                            ,   shortname   = m.shortname\n                            ,   description = m.description\n                            }\n                        end\n                    end\n                    return mainmenu\n                end\n            end\n\n            -- delay to load task menu\n            menu[taskname] = function ()\n                local result, errors = task._translate_menu(taskname, taskmenu)\n                if not result then\n                    os.raise(errors)\n                end\n                return result\n            end\n        end\n    end\n    return menu\nend\n\n-- get the task info\nfunction task:get(name)\n    return self._INFO:get(name)\nend\n\n-- get the task name\nfunction task:name()\n    return self._NAME\nend\n\n-- get the namespace\nfunction task:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name\nfunction task:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- run given task\nfunction task:run(...)\n    local on_run = self:get(\"run\")\n    if not on_run then\n        return false, string.format(\"task(\\\"%s\\\"): no run script, please call on_run() first!\", self:fullname())\n    end\n\n    -- save the current directory\n    local curdir = os.curdir()\n\n    -- run task\n    local ok, errors = sandbox.load(on_run, ...)\n\n    -- restore the current directory\n    os.cd(curdir)\n    return ok, errors\nend\n\n-- return module: task\nreturn task\n"
  },
  {
    "path": "xmake/core/base/text.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        text.lua\n--\n\n-- define module\nlocal text = text or {}\n\n-- load modules\nlocal string    = require(\"base/string\")\nlocal colors    = require(\"base/colors\")\nlocal math      = require(\"base/math\")\nlocal table     = require(\"base/table\")\n\n\nfunction text._iswbr(ch)\n    if not text._CHARWBR then\n        text._CHARWBR = {\n            [(' '):byte()] = 100,\n            [('\\n'):byte()] = 100,\n            [('\\t'):byte()] = 100,\n            [('\\v'):byte()] = 100,\n            [('\\f'):byte()] = 100,\n            [('\\r'):byte()] = 100,\n            [('-'):byte()] = 90,\n            [(')'):byte()] = 50,\n            [(']'):byte()] = 50,\n            [('}'):byte()] = 50,\n            [(','):byte()] = 50,\n            [('='):byte()] = 40,\n            [('|'):byte()] = 40,\n        }\n    end\n    return text._CHARWBR[ch] or false\nend\n\nfunction text._charwidth(ch)\n    if ch == 0x09 then\n        -- TAB\n        return 4\n    elseif ch == 0x08 then\n        -- BS\n        return -1\n    elseif ch <= 0x1F or ch == 0x7F then\n        -- other control chars\n        return 0\n    else\n        return 1\n    end\nend\n\nfunction text._nextwbr(self, iter)\n    local ptr = iter.pos + 1\n    local width = iter.width\n    local str = self.str\n    local e = self.j\n\n    if ptr > e then\n        return nil\n    end\n\n    while ptr <= e do\n        local byte = str:byte(ptr)\n\n        -- ansi sequence, skip it\n        if byte == 27 and ptr + 2 <= e and str:byte(ptr + 1) == 91 then\n            local ansiend = false\n            ptr = ptr + 2\n            while ptr <= e do\n                local b = str:byte(ptr)\n                if b == 109 then\n                    ansiend = true\n                    break\n                end\n                ptr = ptr + 1\n            end\n            if not ansiend then\n                -- ansi sequence not finished in [i, j], no more wbr in the range\n                return nil\n            end\n        else\n            width = width + text._charwidth(byte)\n            local wbr = text._iswbr(byte)\n            if wbr then\n                return { pos = ptr, width = width, quality = wbr }\n            end\n        end\n        ptr = ptr + 1\n    end\n\n    -- wbr at end of string\n    return { pos = e, width = width, quality = 100 }\nend\n\nfunction text._iterwbr(str, i, j, wordbreak)\n    if not i then\n        i = 1\n    elseif i < 0 then\n        i = #str + 1 + i\n    end\n    if not j then\n        j = #str\n    elseif j < 0 then\n        j = #str + 1 + j\n    end\n    return text._nextwbr, { str = str, i = i, j = j, wordbreak = wordbreak }, { pos = i - 1, width = 0 }\nend\n\n-- @see https://unicode.org/reports/tr14/\nfunction text._lastwbr(str, width, wordbreak)\n\n    -- check\n    assert(#str >= width)\n\n    if wordbreak == \"breakall\" then\n        -- To prevent overflow, word may be broken at any character\n        return width\n    else\n\n        if (text._iswbr(str:byte(width + 1)) or -1) >= 100 then\n            -- exact break\n            return width\n        end\n\n        local wbr_candidate\n        for wbr in text._iterwbr(str, 1, #str, wordbreak) do\n            if not wbr_candidate then\n                -- not candidate yet? always use a wbr\n                wbr_candidate = wbr\n            elseif (wbr.quality >= wbr_candidate.quality or wbr.quality >= 80) and wbr.width <= width then\n                -- in range, replace with a higher quality wbr\n                wbr_candidate = wbr\n            end\n            if wbr.width > width then\n                break\n            end\n        end\n\n        if wbr_candidate then\n            return wbr_candidate.pos\n        end\n\n        -- not found in all str\n        return #str\n    end\nend\n\n-- break lines\nfunction text.wordwrap(str, width, opt)\n\n    opt = opt or {}\n\n    -- split to lines\n    if type(str) == \"table\" then\n        str = table.concat(str, \"\\n\")\n    end\n    local lines = tostring(str):split(\"\\n\", {plain = true, strict = true})\n\n    local result = table.new(#lines, 0)\n    local actual_width = 0\n\n    -- handle lines\n    for _, v in ipairs(lines) do\n\n        -- remove tailing spaces, include \"\\r\", which will be produced by `(\"l1\\r\\nl2\"):split(...)`\n        v = v:rtrim()\n\n        while #v > width do\n\n            -- find word break chance\n            local wbr = text._lastwbr(v, width, opt.wordbreak)\n\n            -- break line\n            local line = v:sub(1, wbr):rtrim()\n            actual_width = math.max(#line, actual_width)\n            table.insert(result, line)\n            v = v:sub(wbr + 1):ltrim()\n\n            -- prevent empty line\n            if #v == 0 then\n                v = nil\n                break\n            end\n        end\n\n        -- put remaining parts\n        if v then\n            actual_width = math.max(#v, actual_width)\n            table.insert(result, v)\n        end\n    end\n\n    -- ok\n    return result, actual_width\nend\n\nfunction text._format_cell(cell, width, opt)\n    local result = table.new(#cell, 0)\n    local max_width = 0\n    for _, v in ipairs(cell) do\n        local lines, aw = text.wordwrap(tostring(v), width[2], opt)\n        table.move(lines, 1, #lines, #result + 1, result)\n        max_width = math.max(max_width, aw)\n    end\n    cell.formatted = result\n    cell.width = max_width\nend\n\nfunction text._format_col(col, width, opt)\n    local max_width = 0\n    for i = 1, table.maxn(col) do\n        local v = col[i]\n        -- skip span cells\n        if v and not v.span then\n            text._format_cell(v, width, opt)\n            max_width = math.max(max_width, v.width)\n        end\n    end\n    col.width = max_width\nend\n\n\n-- make a table with colors\n--\n-- @param data         table data, array of array of cells with optional styles\n--                       eg: {\n--                             {\"1\", nil, \"3\"},  -- use nil to make previous cell to span next column\n--                             {\"4\", \"5\", {\"line1\", \"line2\", style=\"${yellow}\", align = \"r\"}}, -- multi-line content & set style or align for cell\n--                             {\"7\", \"8\", {\"9\", style=\"${reset}${red}\"}, style=\"${bright}\", align = \"c\"}, -- set style or align for row\n--                             style = {\"${underline}\"}, -- set style for columns\n--                                                       -- or use \"${underline}\" for all columns\n--                             width = { 20, {10, 50}, \"auto\"},\n--                               -- 2 numbers - min and max width (nil for not set, eg: {nil, 50});\n--                               -- a number - width, num is equivalent to {num, num};\n--                               -- nil - no limit, equivalent to {nil, nil}\n--                               -- \"auto\" - use remain space of console, only one \"auto\" column is allowed\n--                             align = {\"l\", \"r\", \"c\"} -- align mode for each column, \"left\", \"center\" or \"right\"\n--                                                     -- or use a string for the whole table\n--                             sep = \"${dim} | \", -- table colunm sepertor, default is \" | \", use \"\" to hide\n--                           }\n--                     priority of style and align: cell > row > col\n-- @param opt          options for color rendering and word wrapping\nfunction text.table(data, opt)\n\n    assert(data)\n\n    -- init options\n    opt = opt or { ignore_unknown = true }\n    data.sep = data.sep or \" | \"\n    opt.patch_reset = false\n\n    -- col ordered cells\n    local cols = table.new(1, 0)\n    local n_row = table.maxn(data)\n    local n_col = 1\n\n    -- count cols\n    for i = 1, n_row do\n        local row = data[i]\n        if row == nil then\n            data[i] = {{\"\"}}\n        else\n            n_col = math.max(n_col, table.maxn(row))\n        end\n    end\n\n    -- reorder\n    for i = 1, n_row do\n        local row = data[i]\n        local p_cell = nil\n        for j = 1, n_col do\n            local cell = row[j]\n            if cell ~= nil and type(cell) ~= \"table\" then\n                -- wrap cells if needed\n                cell = {tostring(cell)}\n            elseif cell == nil and j == 1 then\n                cell = {\"\"}\n            end\n            local col = cols[j]\n            if not col then\n                col = table.new(n_row, 0)\n                cols[j] = col\n            end\n            if cell then\n                col[i] = cell\n                p_cell = cell\n            else\n                p_cell.span = (p_cell.span or 1) + 1\n            end\n        end\n    end\n\n    -- load column options\n    data.width = data.width or table.new(n_col, 0)\n    data.align = data.align or table.new(n_col, 0)\n    data.style = data.style or table.new(n_col, 0)\n\n    local style = \"\"\n    if type(data.style) == \"string\" then\n        style = data.style\n        data.style = table.new(n_col, 0)\n        data.sep = style .. data.sep .. \"${reset}\"\n    end\n\n    local align = \"l\"\n    if type(data.align) == \"string\" then\n        align = data.align\n        data.align = table.new(n_col, 0)\n    end\n\n    local sep = colors.translate(data.sep, opt)\n    local sep_len = #colors.ignore(data.sep, opt)\n\n    -- index of auto col\n    local auto_col = nil\n    for i = 1, n_col do\n\n        -- load width\n        local w = data.width[i]\n        if w ~= \"auto\" then\n            local wl, wu\n            if w == nil then\n                wl, wu = 0, math.huge\n            elseif type(w) == \"number\" then\n                if math.isnan(w) or math.isinf(w) then\n                    wl, wu = 0, math.huge\n                else\n                    wl, wu = w, w\n                end\n            else\n                wl, wu = w[1], w[2]\n            end\n            wl = wl or 0\n            wu = wu or math.huge\n            data.width[i] = {wl, wu}\n        else\n            assert(not auto_col, \"Only one 'auto' colunm is allowed.\")\n            auto_col = i\n        end\n\n        -- load align\n        cols[i].align = (data.align[i] or align):sub(1, 1):lower()\n        -- load style\n        cols[i].style = data.style[i] or style\n    end\n\n    -- format table\n\n    -- 1. format non-auto cols\n    for i, col in ipairs(cols) do\n        if i ~= auto_col then\n            text._format_col(col, data.width[i], opt)\n        end\n    end\n\n    if auto_col then\n\n        -- 2. caculate auto col width\n        local auto_width = os.getwinsize().width\n        for i = 1, n_col do\n            if i ~= auto_col then\n                auto_width = auto_width - cols[i].width\n            end\n        end\n        auto_width = math.max(0, auto_width - sep_len * (n_col - 1))\n        data.width[auto_col] = {0,auto_width}\n\n        -- 3. format auto col\n        text._format_col(cols[auto_col], data.width[auto_col], opt)\n    end\n\n    -- 4. format span cell\n    for i, col in ipairs(cols) do\n\n        for j = 1, n_row do\n            local cell = col[j]\n            if cell and cell.span then\n                local w, wl = 0, 0\n                for ci = 0, (cell.span - 1) do\n                    -- actual width of spanned cols\n                    w = w + cols[i + ci].width\n                    -- min width of spanned cols\n                    wl = wl + data.width[i + ci][1]\n                end\n                text._format_cell(cell, {0, math.max(w, wl) + sep_len * (cell.span - 1)}, opt)\n            end\n        end\n    end\n\n    -- render cells\n\n    -- row ordered cells\n    local rows = table.new(n_row, 0)\n\n    -- reorder\n    for i = 1, n_row do\n        local d_row = data[i] or {}\n        local row = table.new(n_col, 0)\n        local line = 1\n        for j = 1, n_col do\n            local cell = cols[j][i]\n            if cell then\n                assert(cell.formatted)\n                line = math.max(#cell.formatted, line)\n            end\n            row[j] = cell\n        end\n        row.line = line\n\n        -- load align\n        if d_row.align then\n            row.align = d_row.align:sub(1, 1):lower()\n        end\n\n        -- load style\n        row.style = d_row.style or \"\"\n\n        rows[i] = row\n    end\n\n    local results = table.new(n_row, 0)\n    local reset = colors.translate(\"${reset}\", opt)\n    for i, row in ipairs(rows) do\n        for l = 1, row.line do\n            local cells = table.new(n_col, 0)\n            local j = 1\n            while j <= n_col do\n\n                local cell = row[j]\n                assert(cell)\n                local col = cols[j]\n\n                if l == 1 then\n                    cell.align = cell.align or row.align or col.align\n                    cell.style = colors.translate((col.style or \"\") .. (row.style or \"\") .. (cell.style or \"\"), opt)\n                end\n\n                local str = cell.formatted[l] or \"\"\n                local width = col.width\n                local span = cell.span or 1\n                if cell.span then\n                    for ci = (j + 1), (j + span - 1) do\n                        width = width + cols[ci].width\n                    end\n                    width = width + sep_len * (span - 1)\n                end\n\n                local padded\n                if cell.align == \"r\" then\n                    -- right align\n                    padded = string.rep(\" \", width - #str) .. str\n                elseif cell.align == \"c\" then\n                    -- centered\n                    local padding = width - #str\n                    local lp = math.floor(padding / 2)\n                    local rp = math.ceil(padding / 2)\n                    padded = string.rep(\" \", lp) .. str .. string.rep(\" \", rp)\n                else\n                    --left align, emit tailing spaces for last colunm\n                    padded = str .. ((j + span == n_col + 1) and \"\" or string.rep(\" \", width - #str))\n                end\n                table.insert(cells, cell.style .. padded .. reset)\n                j = j + span\n            end\n            table.insert(results, table.concat(cells, sep))\n        end\n    end\n\n    -- concat rendered rows\n    results[#results + 1] = \"\"\n    return table.concat(results, \"\\n\")\nend\n\n-- return module\nreturn text\n"
  },
  {
    "path": "xmake/core/base/thread.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        thread.lua\n--\n\n-- define module\nlocal thread     = thread or {}\nlocal _thread    = _thread or {}\nlocal _mutex     = _mutex or {}\nlocal _event     = _event or {}\nlocal _semaphore = _semaphore or {}\nlocal _queue     = _queue or {}\nlocal _sharedata = _sharedata or {}\n\n-- load modules\nlocal io         = require(\"base/io\")\nlocal libc       = require(\"base/libc\")\nlocal pipe       = require(\"base/pipe\")\nlocal pipe_event = require(\"base/private/pipe_event\")\nlocal bytes      = require(\"base/bytes\")\nlocal table      = require(\"base/table\")\nlocal string     = require(\"base/string\")\nlocal scheduler  = require(\"base/scheduler\")\nlocal sandbox    = require(\"sandbox/sandbox\")\n\n-- the thread status\nthread.STATUS_READY     = 1\nthread.STATUS_RUNNING   = 2\nthread.STATUS_SUSPENDED = 3\nthread.STATUS_DEAD      = 4\n\n-- new a thread\nfunction _thread.new(callback, opt)\n    opt = opt or {}\n    local instance = table.inherit(_thread)\n    instance._NAME      = opt.name or \"anonymous\"\n    instance._ARGV      = opt.argv\n    instance._CALLBACK  = callback\n    instance._STACKSIZE = opt.stacksize or 0\n    instance._STATUS    = thread.STATUS_READY\n    instance._INTERNAL  = opt.internal\n    setmetatable(instance, _thread)\n    return instance\nend\n\n-- get thread name\nfunction _thread:name()\n    return self._NAME\nend\n\n-- get cdata of thread\nfunction _thread:cdata()\n    return self._HANLDE\nend\n\n-- get thread status\nfunction _thread:status()\n    return self._STATUS\nend\n\n-- is ready?\nfunction _thread:is_ready()\n    return self:status() == thread.STATUS_READY\nend\n\n-- is running?\nfunction _thread:is_running()\n    return self:status() == thread.STATUS_RUNNING\nend\n\n-- is suspended?\nfunction _thread:is_suspended()\n    return self:status() == thread.STATUS_SUSPENDED\nend\n\n-- is dead?\nfunction _thread:is_dead()\n    return self:status() == thread.STATUS_DEAD\nend\n\n-- start thread\nfunction _thread:start()\n    if not self:is_ready() then\n        return nil, string.format(\"%s: cannot start non-ready thread!\", self)\n    end\n    assert(not self:cdata())\n\n    -- translate arguments (mutex, ...)\n    local argv = {}\n    for _, arg in ipairs(self._ARGV) do\n        if type(arg) == \"table\" then\n            -- try to serialize thread object (mutex, event, semaphore, queue, sharedata)\n            local serialized = thread._serialize_object(arg)\n            if serialized then\n                arg = serialized\n            end\n        end\n        table.insert(argv, arg)\n    end\n\n    -- init callback info\n    local is_internal = self._INTERNAL\n    local callback = string._dump(self._CALLBACK)\n    local callinfo = {name = self:name(), argv = argv, internal = is_internal}\n\n    -- we need a pipe pair to wait and listen thread exit event\n    if not is_internal then\n        local rpipe, wpipe = pipe.openpair(\"AA\")\n        self._RPIPE = rpipe\n        callinfo.wpipe = libc.dataptr(wpipe:cdata(), {ffi = false})\n        -- we need to suppress gc to free it, because it has been transfer to thread in another lua state instance\n        wpipe._PIPE = nil\n    end\n\n    -- serialize and pass callback and arguments to this thread\n    -- we do not use string.serialize to serialize callback, because it's slower (deserialize)\n    -- and we cannot strip function debug info, we need to reserve _ENV, and other upvalue names\n    callinfo = string.serialize(callinfo, {strip = true, indent = false})\n\n    -- init and start thread\n    local handle, errors = thread.thread_init(self:name(), callback, callinfo, self._STACKSIZE)\n    if not handle then\n        return nil, errors or string.format(\"%s: failed to create thread!\", self)\n    end\n\n    self._HANLDE = handle\n    self._STATUS = thread.STATUS_RUNNING\n    return true\nend\n\n-- suspend thread\nfunction _thread:suspend()\n    if not self:is_running() then\n        return nil, string.format(\"%s: cannot suspend non-running thread!\", self)\n    end\n    assert(self:cdata())\n\n    local ok, errors = thread.thread_suspend(self:cdata())\n    if not ok then\n        return nil, errors or string.format(\"%s: failed to suspend thread!\", self)\n    end\n\n    self._STATUS = thread.STATUS_SUSPENDED\n    return true\nend\n\n-- resume thread\nfunction _thread:resume()\n    if not self:is_suspended() then\n        return nil, string.format(\"%s: cannot suspend non-suspended thread!\", self)\n    end\n    assert(self:cdata())\n\n    local ok, errors = thread.thread_resume(self:cdata())\n    if not ok then\n        return nil, errors or string.format(\"%s: failed to resume thread!\", self)\n    end\n\n    self._STATUS = thread.STATUS_RUNNING\n    return true\nend\n\n-- wait thread\nfunction _thread:wait(timeout)\n    if self:is_dead() then\n        return 1\n    elseif self:is_ready() then\n        return -1, string.format(\"%s: cannot wait ready thread!\", self)\n    end\n    assert(self:cdata())\n\n    local ok, errors\n    local rpipe = self._RPIPE\n    if rpipe and scheduler:co_running() then\n        local buff = bytes(16)\n        local read, data_or_errors = rpipe:read(buff, 1, {block = true, timeout = timeout})\n        if read > 0 then\n            ok = 1\n        else\n            ok = read\n            errors = data_or_errors\n        end\n    end\n    if not rpipe then\n        local waitok, wait_errors = thread.thread_wait(self:cdata(), timeout)\n        if ok == nil or ok > 0 then\n            ok = waitok\n            errors = wait_errors\n        end\n    end\n    if ok < 0 then\n        return -1, errors or string.format(\"%s: failed to resume thread!\", self)\n    end\n\n    if rpipe then\n        rpipe:close()\n        self._RPIPE = nil\n    end\n\n    if ok > 0 then\n        self._STATUS = thread.STATUS_DEAD\n    end\n    return ok\nend\n\n-- tostring(thread)\nfunction _thread:__tostring()\n    local status_strs = self._STATUS_STRS\n    if not status_strs then\n        status_strs = {\n            [thread.STATUS_READY]     = \"ready\",\n            [thread.STATUS_RUNNING]   = \"running\",\n            [thread.STATUS_SUSPENDED] = \"suspended\",\n            [thread.STATUS_DEAD]      = \"dead\"\n        }\n        self._STATUS_STRS = status_strs\n    end\n    return string.format(\"<thread: %s/%s>\", self:name(), status_strs[self:status()])\nend\n\n-- gc(thread)\nfunction _thread:__gc()\n    if self:cdata() and self:is_dead() and thread.thread_exit(self:cdata()) then\n        self._HANLDE = nil\n    end\n    if self._RPIPE then\n        self._RPIPE:close()\n        self._RPIPE = nil\n    end\nend\n\n-- new an mutex\nfunction _mutex.new(name, cdata)\n    local mutex = table.inherit(_mutex)\n    mutex._NAME = name\n    mutex._MUTEX = cdata\n    mutex._LOCKED_NUM = 0\n    setmetatable(mutex, _mutex)\n    return mutex\nend\n\n-- get the mutex name\nfunction _mutex:name()\n    return self._NAME\nend\n\n-- get the cdata\nfunction _mutex:cdata()\n    return self._MUTEX\nend\n\n-- is locked?\nfunction _mutex:islocked()\n    return self._LOCKED_NUM > 0\nend\n\n-- lock mutex\n--\n-- @return          ok, errors\n--\nfunction _mutex:lock()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if self._LOCKED_NUM > 0 or thread.mutex_lock(self:cdata()) then\n        self._LOCKED_NUM = self._LOCKED_NUM + 1\n        return true\n    else\n        return false, string.format(\"%s: lock failed!\", self)\n    end\nend\n\n-- try to lock mutex\n--\n-- @param opt       the argument option, {shared = true}\n--\n-- @return          ok, errors\n--\nfunction _mutex:trylock(opt)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if self._LOCKED_NUM > 0 or thread.mutex_trylock(self:cdata(), opt) then\n        self._LOCKED_NUM = self._LOCKED_NUM + 1\n        return true\n    else\n        return false, string.format(\"%s: trylock failed!\", self)\n    end\nend\n\n-- unlock mutex\nfunction _mutex:unlock(opt)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if self._LOCKED_NUM > 1 or (self._LOCKED_NUM > 0 and thread.mutex_unlock(self:cdata())) then\n        if self._LOCKED_NUM > 0 then\n            self._LOCKED_NUM = self._LOCKED_NUM - 1\n        else\n            self._LOCKED_NUM = 0\n        end\n        return true\n    else\n        return false, string.format(\"%s: unlock failed!\", self)\n    end\nend\n\n-- close mutex\nfunction _mutex:close()\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    -- close it\n    ok = thread.mutex_exit(self:cdata())\n    if ok then\n        self._MUTEX = nil\n        self._LOCKED_NUM = 0\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _mutex:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(mutex)\nfunction _mutex:__tostring()\n    return \"<mutex: \" .. (self:name() or tostring(self:cdata())) .. \">\"\nend\n\n-- gc(mutex)\nfunction _mutex:__gc()\n    if self:cdata() and thread.mutex_exit(self:cdata()) then\n        self._MUTEX = nil\n        self._LOCKED_NUM = 0\n    end\nend\n\n-- new an event\nfunction _event.new(name, cdata)\n    local event = table.inherit(_event)\n    event._NAME = name\n    event._EVENT = cdata\n    setmetatable(event, _event)\n    return event\nend\n\n-- get the event name\nfunction _event:name()\n    return self._NAME\nend\n\n-- get the cdata\nfunction _event:cdata()\n    return self._EVENT\nend\n\n-- post event\n--\n-- @return          ok, errors\n--\nfunction _event:post()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if not thread.event_post(self:cdata()) then\n        return false, string.format(\"%s: post failed!\", self)\n    end\n    return true\nend\n\n-- wait event\nfunction _event:wait(timeout)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    local ok, errors = thread.event_wait(self:cdata(), timeout)\n    if ok < 0 then\n        return false, string.format(\"%s: wait failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- close event\nfunction _event:close()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    ok = thread.event_exit(self:cdata())\n    if ok then\n        self._EVENT = nil\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _event:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(event)\nfunction _event:__tostring()\n    return \"<event: \" .. (self:name() or tostring(self:cdata())) .. \">\"\nend\n\n-- gc(event)\nfunction _event:__gc()\n    if self:cdata() and thread.event_exit(self:cdata()) then\n        self._EVENT = nil\n    end\nend\n\n-- new an semaphore\nfunction _semaphore.new(name, cdata)\n    local semaphore = table.inherit(_semaphore)\n    semaphore._NAME = name\n    semaphore._SEMAPHORE = cdata\n    setmetatable(semaphore, _semaphore)\n    return semaphore\nend\n\n-- get the semaphore name\nfunction _semaphore:name()\n    return self._NAME\nend\n\n-- get the cdata\nfunction _semaphore:cdata()\n    return self._SEMAPHORE\nend\n\n-- post semaphore\n--\n-- @param value     the semaphore value\n--\n-- @return          ok, errors\n--\nfunction _semaphore:post(value)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if not thread.semaphore_post(self:cdata(), value) then\n        return false, string.format(\"%s: post failed!\", self)\n    end\n    return true\nend\n\n-- wait semaphore\nfunction _semaphore:wait(timeout)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    local ok, errors = thread.semaphore_wait(self:cdata(), timeout)\n    if ok < 0 then\n        return false, string.format(\"%s: wait failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- close semaphore\nfunction _semaphore:close()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    ok = thread.semaphore_exit(self:cdata())\n    if ok then\n        self._SEMAPHORE = nil\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _semaphore:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(semaphore)\nfunction _semaphore:__tostring()\n    return \"<semaphore: \" .. (self:name() or tostring(self:cdata())) .. \">\"\nend\n\n-- gc(semaphore)\nfunction _semaphore:__gc()\n    if self:cdata() and thread.semaphore_exit(self:cdata()) then\n        self._SEMAPHORE = nil\n    end\nend\n\n-- new an queue\nfunction _queue.new(name, cdata)\n    local queue = table.inherit(_queue)\n    queue._NAME = name\n    queue._QUEUE = cdata\n    setmetatable(queue, _queue)\n    return queue\nend\n\n-- get the queue name\nfunction _queue:name()\n    return self._NAME\nend\n\n-- get the cdata\nfunction _queue:cdata()\n    return self._QUEUE\nend\n\n-- get queue size\nfunction _queue:size()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    return thread.queue_size(self:cdata())\nend\n\n-- is empty queue?\nfunction _queue:empty()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors\n    end\n\n    return thread.queue_size(self:cdata()) == 0\nend\n\n-- clear queue\nfunction _queue:clear()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    local ok, errors = thread.queue_clear(self:cdata())\n    if not ok then\n        return false, string.format(\"%s: clear failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- push queue item\nfunction _queue:push(value)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if type(value) == \"table\" then\n        value = string.serialize(value, {strip = true, indent = false})\n        if value == nil then\n            return false, string.format(\"%s: cannot serialize value: %s\", self, value)\n        end\n        value = \"__table_\" .. value\n    end\n\n    local ok, errors = thread.queue_push(self:cdata(), value)\n    if not ok then\n        return false, string.format(\"%s: push item failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- pop queue item\nfunction _queue:pop()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors or \"unknown\"\n    end\n\n    local value, errors = thread.queue_pop(self:cdata())\n    if value == nil and errors then\n        return nil, string.format(\"%s: push item failed, errors: %s!\", self, errors or \"unknown\")\n    end\n\n    if type(value) == \"string\" and value:startswith(\"__table_\") then\n        value = value:sub(9)\n        value, errors = string.deserialize(value)\n        if not value then\n            return nil, string.format(\"invalid queue item, %s!\", errors or \"unknown\")\n        end\n    end\n    return value\nend\n\n-- close queue\nfunction _queue:close()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    ok = thread.queue_exit(self:cdata())\n    if ok then\n        self._QUEUE = nil\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _queue:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(queue)\nfunction _queue:__tostring()\n    return \"<queue: \" .. (self:name() or tostring(self:cdata())) .. \">\"\nend\n\n-- gc(queue)\nfunction _queue:__gc()\n    if self:cdata() and thread.queue_exit(self:cdata()) then\n        self._QUEUE = nil\n    end\nend\n\n-- new an sharedata\nfunction _sharedata.new(name, cdata)\n    local sharedata = table.inherit(_sharedata)\n    sharedata._NAME = name\n    sharedata._SHAREDATA = cdata\n    setmetatable(sharedata, _sharedata)\n    return sharedata\nend\n\n-- get the sharedata name\nfunction _sharedata:name()\n    return self._NAME\nend\n\n-- get the cdata\nfunction _sharedata:cdata()\n    return self._SHAREDATA\nend\n\n-- clear sharedata\nfunction _sharedata:clear()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    local ok, errors = thread.sharedata_clear(self:cdata())\n    if not ok then\n        return false, string.format(\"%s: clear failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- set sharedata\nfunction _sharedata:set(value)\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    if type(value) == \"table\" then\n        value = string.serialize(value, {strip = true, indent = false})\n        if value == nil then\n            return false, string.format(\"%s: cannot serialize value: %s\", self, value)\n        end\n        value = \"__table_\" .. value\n    end\n\n    local ok, errors = thread.sharedata_set(self:cdata(), value)\n    if not ok then\n        return false, string.format(\"%s: set sharedata failed, errors: %s!\", self, errors or \"unknown\")\n    end\n    return ok\nend\n\n-- get sharedata\nfunction _sharedata:get()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return nil, errors or \"unknown\"\n    end\n\n    local value, errors = thread.sharedata_get(self:cdata())\n    if value == nil and errors then\n        return nil, string.format(\"%s: get sharedata failed, errors: %s!\", self, errors or \"unknown\")\n    end\n\n    if type(value) == \"string\" and value:startswith(\"__table_\") then\n        value = value:sub(9)\n        value, errors = string.deserialize(value)\n        if not value then\n            return nil, string.format(\"invalid sharedata, %s!\", errors or \"unknown\")\n        end\n    end\n    return value\nend\n\n-- close sharedata\nfunction _sharedata:close()\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return false, errors\n    end\n\n    ok = thread.sharedata_exit(self:cdata())\n    if ok then\n        self._SHAREDATA = nil\n    end\n    return ok\nend\n\n-- ensure the file is opened\nfunction _sharedata:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(sharedata)\nfunction _sharedata:__tostring()\n    return \"<sharedata: \" .. (self:name() or tostring(self:cdata())) .. \">\"\nend\n\n-- gc(sharedata)\nfunction _sharedata:__gc()\n    if self:cdata() and thread.sharedata_exit(self:cdata()) then\n        self._SHAREDATA = nil\n    end\nend\n\n-- serialize thread object for passing through queue or table (private helper)\n-- this is used when you need to pass thread objects (mutex, event, semaphore, queue, sharedata)\n-- through a queue or embed them in a table\n-- returns a table with serialized caddr that can be pushed to queue\nfunction thread._serialize_object(obj)\n    if not obj or type(obj) ~= \"table\" or not obj.cdata then\n        return nil\n    end\n\n    local result = {}\n    -- detect object type by checking internal marker\n    if obj._MUTEX then\n        thread.mutex_incref(obj:cdata())\n        result.mutex = true\n        result.name = obj:name()\n        result.caddr = libc.dataptr(obj:cdata(), {ffi = false})\n    elseif obj._EVENT then\n        thread.event_incref(obj:cdata())\n        result.event = true\n        result.name = obj:name()\n        result.caddr = libc.dataptr(obj:cdata(), {ffi = false})\n    elseif obj._SEMAPHORE then\n        thread.semaphore_incref(obj:cdata())\n        result.semaphore = true\n        result.name = obj:name()\n        result.caddr = libc.dataptr(obj:cdata(), {ffi = false})\n    elseif obj._QUEUE then\n        thread.queue_incref(obj:cdata())\n        result.queue = true\n        result.name = obj:name()\n        result.caddr = libc.dataptr(obj:cdata(), {ffi = false})\n    elseif obj._SHAREDATA then\n        thread.sharedata_incref(obj:cdata())\n        result.sharedata = true\n        result.name = obj:name()\n        result.caddr = libc.dataptr(obj:cdata(), {ffi = false})\n    elseif obj._PIPE_EVENT then\n        local data = obj:_serialize()\n        if not data then\n            return nil\n        end\n        result.pipe_event = true\n        result.ptr = data.ptr\n        result.name = data.name\n        result.caddr = data.ptr\n    else\n        return nil\n    end\n\n    return result\nend\n\n-- deserialize thread object from serialized data (private helper)\n-- this is used to restore thread objects (mutex, event, semaphore, queue, sharedata)\n-- from serialized caddr received through queue or from table\nfunction thread._deserialize_object(data)\n    if not data or type(data) ~= \"table\" or not data.caddr then\n        return nil\n    end\n\n    local cdata = libc.ptraddr(data.caddr, {ffi = false})\n    if data.mutex then\n        return _mutex.new(data.name, cdata)\n    elseif data.event then\n        return _event.new(data.name, cdata)\n    elseif data.semaphore then\n        return _semaphore.new(data.name, cdata)\n    elseif data.queue then\n        return _queue.new(data.name, cdata)\n    elseif data.sharedata then\n        return _sharedata.new(data.name, cdata)\n    elseif data.pipe_event then\n        local event = pipe_event.new(data.name)\n        if not event then\n            return nil, \"failed to create pipe event\"\n        end\n        local ok, errors = event:_deserialize({ptr = data.ptr, name = data.name})\n        if not ok then\n            return nil, errors\n        end\n        return event\n    end\n\n    return nil\nend\n\n-- run thread\nfunction thread._run_thread(callback_str, callinfo_str)\n\n    -- load callback info\n    local callinfo\n    local argv\n    local threadname\n    local wpipe\n    local is_internal = false\n    if callinfo_str then\n        local result, errors = string.deserialize(callinfo_str)\n        if not result then\n            return false, string.format(\"invalid thread callinfo, %s!\", errors or \"unknown\")\n        end\n        callinfo = result\n        if callinfo then\n            argv = callinfo.argv\n            threadname = callinfo.name\n            is_internal = callinfo.internal\n            if callinfo.wpipe then\n                wpipe = pipe.new(libc.ptraddr(callinfo.wpipe, {ffi = false}))\n            end\n        end\n    end\n\n    -- load callback\n    local callback\n    local fenvs = {}\n    if callback_str then\n        local script, errors = load(callback_str, \"=(thread)\", \"b\", fenvs)\n        if not script then\n            return false, string.format(\"cannot load thread(%s) callback, %s!\", threadname or \"unknown\", errors or \"unknown\")\n        end\n        for i = 1, math.huge do\n            local upname, upvalue = debug.getupvalue(script, i)\n            if upname == nil or upname == \"\" then\n                break\n            end\n            if upvalue == nil then\n                return false, string.format(\"we cannot access upvalue(%s) in thread(%s) callback!\", upname, threadname or \"unknown\")\n            end\n        end\n        callback = script\n    end\n    if not callback then\n        return false, \"no thread callback\"\n    end\n\n    -- bind sandbox\n    local sandbox_inst, errors = sandbox.new(callback)\n    if not sandbox_inst then\n        return false, errors\n    end\n\n    -- if it's an internal thread, we need to bind some additional internal interfaces.\n    if is_internal then\n        sandbox_inst:api_register_builtin(\"require\", require)\n    end\n\n    -- save the running thread name\n    thread._RUNNING = threadname\n\n    -- translate arguments (mutex, event, semaphore, queue, sharedata, ...)\n    if argv then\n        local newargv = {}\n        for _, arg in ipairs(argv) do\n            if type(arg) == \"table\" and arg.caddr then\n                -- try to deserialize thread object\n                local obj = thread._deserialize_object(arg)\n                if obj then\n                    arg = obj\n                end\n            end\n            table.insert(newargv, arg)\n        end\n        argv = newargv\n    end\n\n    -- do callback\n    local ok, errors = sandbox.load(sandbox_inst:script(), table.unpack(argv or {}))\n\n    -- thread is finished, we need to notify the waited thread\n    if wpipe then\n        local ok, errors = wpipe:write(\"1\", {block = true})\n        if ok < 0 then\n            return false, errors\n        end\n        wpipe:close()\n    end\n    return ok, errors\nend\n\n-- new a thread\n--\n-- @param callback      the thread callback\n-- @param opt           the thread options, e.g. {name = \"\", argv = {}, stacksize = 8192}\n--\n-- @return the thread instance\n--\nfunction thread.new(callback, opt)\n    if callback == nil then\n        return nil, \"invalid thread, callback is nil\"\n    end\n    return _thread.new(callback, opt)\nend\n\n-- get the running thread name\nfunction thread.running()\n    return thread._RUNNING\nend\n\n-- open a mutex\nfunction thread.mutex(name)\n    local mutex = thread.mutex_init()\n    if mutex then\n        return _mutex.new(name, mutex)\n    else\n        return nil, string.format(\"cannot open mutex: %s\", os.strerror())\n    end\nend\n\n-- open a event\nfunction thread.event(name)\n    local event = thread.event_init()\n    if event then\n        return _event.new(name, event)\n    else\n        return nil, string.format(\"cannot open event: %s\", os.strerror())\n    end\nend\n\n-- open a semaphore\nfunction thread.semaphore(name, value)\n    local semaphore = thread.semaphore_init(value or 0)\n    if semaphore then\n        return _semaphore.new(name, semaphore)\n    else\n        return nil, string.format(\"cannot open semaphore: %s\", os.strerror())\n    end\nend\n\n-- open a queue\nfunction thread.queue(name)\n    local queue = thread.queue_init()\n    if queue then\n        return _queue.new(name, queue)\n    else\n        return nil, string.format(\"cannot open queue: %s\", os.strerror())\n    end\nend\n\n-- open a sharedata\nfunction thread.sharedata(name)\n    local sharedata = thread.sharedata_init()\n    if sharedata then\n        return _sharedata.new(name, sharedata)\n    else\n        return nil, string.format(\"cannot open sharedata: %s\", os.strerror())\n    end\nend\n\n-- return module\nreturn thread\n\n"
  },
  {
    "path": "xmake/core/base/timer.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        timer.lua\n--\n\n-- load modules\nlocal heap   = require(\"base/heap\")\nlocal object = require(\"base/object\")\n\n-- define module: timer\nlocal timer  = timer or object()\n\n-- tostring(timer)\nfunction timer:__tostring()\n    return string.format(\"<timer: %s>\", self:name())\nend\n\n-- get all timer tasks\nfunction timer:_tasks()\n    return self._TASKS\nend\n\n-- post timer task after delay and will be auto-remove it after be expired\nfunction timer:post(func, delay, opt)\n    return self:post_at(func, os.mclock() + delay, delay, opt)\nend\n\n-- post timer task at the absolute time and will be auto-remove it after be expired\n--\n-- we can mark the returned task as canceled to cancel the pending task, e.g. task.cancel = true\n--\nfunction timer:post_at(func, when, period, opt)\n    opt = opt or {}\n    local task = {when = when, func = func, period = period, continuous = opt.continuous, cancel = false}\n    self:_tasks():push(task)\n    return task\nend\n\n-- post timer task after the relative time and will be auto-remove it after be expired\nfunction timer:post_after(func, after, period, opt)\n    return self:post_at(func, os.mclock() + after, period, opt)\nend\n\n-- get the delay of next task\nfunction timer:delay()\n    local delay = nil\n    local tasks = self:_tasks()\n    if tasks:length() > 0 then\n        local task = tasks:peek()\n        if task then\n            local now = os.mclock()\n            delay = task.when > now and task.when - now or 0\n        end\n    end\n    return delay\nend\n\n-- run the timer next loop\nfunction timer:next()\n    local tasks = self:_tasks()\n    while tasks:length() > 0 do\n        local triggered = false\n        local task = tasks:peek()\n        if task then\n            -- timeout or canceled?\n            if task.cancel or task.when <= os.mclock() then\n                tasks:pop()\n                if task.continuous and not task.cancel then\n                    task.when = os.mclock() + task.period\n                    tasks:push(task)\n                end\n                -- run timer task\n                if task.func then\n                    local ok, errors = task.func(task.cancel)\n                    if not ok then\n                        return false, errors\n                    end\n                    triggered = true\n                end\n            end\n        end\n        if not triggered then\n            break\n        end\n    end\n    return true\nend\n\n-- kill all timer tasks\nfunction timer:kill()\n    local tasks = self:_tasks()\n    while tasks:length() > 0 do\n        local task = tasks:peek()\n        if task then\n            tasks:pop()\n            if task.func then\n                -- cancel it\n                task.func(true)\n            end\n        end\n    end\nend\n\n-- get timer name\nfunction timer:name()\n    return self._NAME\nend\n\n-- init timer\nfunction timer:init(name)\n    self._NAME  = name or \"none\"\n    self._TASKS = heap.valueheap {cmp = function(a, b)\n        return a.when < b.when\n    end}\nend\n\n-- new timer\nfunction timer:new(name)\n    self = self()\n    self:init(name)\n    return self\nend\n\n-- return module: timer\nreturn timer\n"
  },
  {
    "path": "xmake/core/base/todisplay.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        todisplay.lua\n--\n\n-- define module\nlocal todisplay = todisplay or {}\n\n-- load modules\nlocal colors  = require(\"base/colors\")\nlocal math    = require(\"base/math\")\n\n\nfunction todisplay._reset()\n    local reset = todisplay._RESET\n    if not reset then\n        reset = colors.translate(\"${reset}\")\n        todisplay._RESET = reset\n    end\n    return reset\nend\n\n-- format string with theme colors\nfunction todisplay._format(fmtkey, fmtdefault, ...)\n    local theme = colors.theme()\n    if theme then\n        return colors.translate(string.format(theme:get(fmtkey), ...), { patch_reset = false, ignore_unknown = true })\n    else\n        return string.format(fmtdefault, ...)\n    end\nend\n\n-- translate string with theme formats\nfunction todisplay._translate(str)\n    local theme = colors.theme()\n    if theme then\n        return colors.translate(str, { patch_reset = false, ignore_unknown = true })\n    else\n        return colors.ignore(str)\n    end\nend\n\n-- print keyword\nfunction todisplay._print_keyword(keyword)\n    return todisplay._translate(\"${reset}${color.dump.keyword}\") .. tostring(keyword) .. todisplay._reset()\nend\n\n-- print string\nfunction todisplay._print_string(str, as_key)\n    local quote = (not as_key) or (not str:match(\"^[a-zA-Z_][a-zA-Z0-9_]*$\"))\n    if quote then\n        return todisplay._translate([[${reset}${color.dump.string_quote}\"${reset}${color.dump.string}]])\n            .. str\n            .. todisplay._translate([[${reset}${color.dump.string_quote}\"${reset}]])\n    else\n        return todisplay._translate(\"${reset}${color.dump.string}\") .. str .. todisplay._reset()\n    end\nend\n\n-- print number\nfunction todisplay._print_number(num)\n    return todisplay._translate(\"${reset}${color.dump.number}\") .. tostring(num) .. todisplay._reset()\nend\n\n-- print function\nfunction todisplay._print_function(func)\n    local funcinfo = debug.getinfo(func)\n    local srcinfo = funcinfo.short_src\n    if funcinfo.linedefined >= 0 then\n        srcinfo = srcinfo .. \":\" .. funcinfo.linedefined\n    end\n    local funcname = funcinfo.name and (funcinfo.name .. \" \") or \"\"\n    return todisplay._translate(\"${reset}${color.dump.function}function ${bright}\")\n        .. funcname\n        .. todisplay._translate(\"${reset}${dim}\")\n        .. srcinfo .. todisplay._reset()\nend\n\nfunction todisplay._get_tostr_method(value)\n    local metatable = debug.getmetatable(value)\n    if metatable then\n        local __todisplay = rawget(metatable, \"__todisplay\")\n        local __tostring = rawget(metatable, \"__tostring\")\n        return __todisplay, __tostring\n    end\n    return nil, nil\nend\n\n-- print value with default format\nfunction todisplay._print_default_scalar(value, style, formatkey)\n    local __todisplay, __tostring = todisplay._get_tostr_method(value)\n    if __todisplay then\n        local ok, str = pcall(__todisplay, value)\n        if ok then\n            value = todisplay._translate(str)\n            -- disable format\n            formatkey = nil\n        end\n    elseif __tostring then\n        local ok, str = pcall(__tostring, value)\n        if ok then\n            value = str\n        end\n    end\n    if formatkey then\n        value = todisplay._format(formatkey, \"%s\", value)\n    end\n    local reset = todisplay._reset()\n    return reset .. todisplay._translate(style) .. value .. reset\nend\n\n-- print udata value with scalar format\nfunction todisplay._print_udata_scalar(value)\n    return todisplay._print_default_scalar(value, \"${color.dump.udata}\", \"text.dump.udata_format\")\nend\n\n-- print table value with scalar format\nfunction todisplay._print_table_scalar(value, expand)\n    if debug.getmetatable(value) or not expand then\n        return todisplay._print_default_scalar(value, \"${color.dump.table}\", \"text.dump.table_format\")\n    end\n    local pvalues = {}\n    local has_string_key = false\n    local as, ae = math.huge, -math.huge\n\n    local k, v\n    for i = 1, 10 do\n        k, v = next(value, k)\n        if k == nil then break end\n\n        if type(k) == \"string\" then\n            pvalues[k] = todisplay._print_scalar(v, false)\n            has_string_key = true\n        elseif type(k) == \"number\" and math.isint(k) then\n            pvalues[k] = todisplay._print_scalar(v, false)\n            as = math.min(k, as)\n            ae = math.max(k, ae)\n        else\n            -- no common table or array\n            return todisplay._print_default_scalar(value, \"${color.dump.table}\", \"text.dump.table_format\")\n        end\n    end\n    if k ~= nil then\n        -- to large\n        return todisplay._print_default_scalar(value, \"${color.dump.table}\", \"text.dump.table_format\")\n    end\n\n    local results = {}\n    local is_arr = as >= 1 and ae <= 20\n    if is_arr then\n        local nilstr\n        for i = 1, ae do\n            local pv = pvalues[i]\n            if pv == nil then\n                if not nilstr then\n                    nilstr = todisplay._print_keyword(\"nil\")\n                end\n                pv = nilstr\n            end\n            results[i] = pv\n        end\n    end\n    if has_string_key then\n        for pk, pv in pairs(pvalues) do\n            if type(pk) == \"string\" then\n                local pkstr = todisplay._print_string(pk, true)\n                table.insert(results, pkstr .. \" = \" .. pv)\n            elseif not is_arr then\n                local pkstr = todisplay._print_number(pk)\n                table.insert(results, pkstr .. \" = \" .. pv)\n            end\n        end\n    end\n    if #results == 0 then\n        return todisplay._translate(\"${reset}${color.dump.table}\") .. \"{ }\" .. todisplay._reset()\n    end\n    return todisplay._translate(\"${reset}${color.dump.table}\") .. \"{ \" .. table.concat(results, \", \") ..\" }\" .. todisplay._reset()\nend\n\n-- print scalar value\nfunction todisplay._print_scalar(value, expand)\n    if type(value) == \"nil\" or type(value) == \"boolean\" then\n        return todisplay._print_keyword(value)\n    elseif type(value) == \"number\" then\n        return todisplay._print_number(value)\n    elseif type(value) == \"string\" then\n        return todisplay._print_string(value)\n    elseif type(value) == \"function\" then\n        return todisplay._print_function(value)\n    elseif type(value) == \"userdata\" then\n        return todisplay._print_udata_scalar(value)\n    elseif type(value) == \"table\" then\n        return todisplay._print_table_scalar(value, expand)\n    else\n        return todisplay._print_default_scalar(value, \"${color.dump.default}\", \"text.dump.default_format\")\n    end\nend\n\nfunction todisplay.print(value)\n    return todisplay._print_scalar(value, true)\nend\n\nsetmetatable(todisplay, {\n    __call = function (_, ...)\n        return todisplay.print(...)\n    end\n})\n\nreturn todisplay\n"
  },
  {
    "path": "xmake/core/base/tty.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tty.lua\n--\n\n-- define module\nlocal tty = tty or {}\n\n-- load modules\nlocal io = require(\"base/io\")\nlocal path = require(\"base/path\")\n\n-- save metatable and builtin functions\ntty._term_mode = tty._term_mode or tty.term_mode\ntty._session_id = tty._session_id or tty.session_id\n\n-- @see https://www2.ccs.neu.edu/research/gpc/VonaUtils/vona/terminal/vtansi.htm\n-- http://www.termsys.demon.co.uk/vtansi.htm\n\n-- write control characters\nfunction tty._iowrite(...)\n    local isatty = tty._ISATTY\n    if isatty == nil then\n        isatty = io.isatty()\n        tty._ISATTY = isatty\n    end\n    if isatty then\n        io.write(...)\n    end\nend\n\n-- get colorterm setting\n--\n-- COLORTERM: 8color/color8, 256color/color256, truecolor, nocolor\n--\nfunction tty._colorterm()\n    local colorterm = tty._COLORTERM\n    if colorterm == nil then\n        colorterm = os.getenv(\"XMAKE_COLORTERM\") or os.getenv(\"COLORTERM\") or \"\"\n        tty._COLORTERM = colorterm\n    end\n    return colorterm\nend\n\n-- erases from the current cursor position to the end of the current line.\nfunction tty.erase_line_to_end()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[K\")\n    end\n    return tty\nend\n\n-- erases from the current cursor position to the start of the current line.\nfunction tty.erase_line_to_start()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[1K\")\n    end\n    return tty\nend\n\n-- erases the entire current line\nfunction tty.erase_line()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[2K\")\n    end\n    return tty\nend\n\n-- erases the screen from the current line down to the bottom of the screen.\nfunction tty.erase_down()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[J\")\n    end\n    return tty\nend\n\n-- erases the screen from the current line up to the top of the screen.\nfunction tty.erase_up()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[1J\")\n    end\n    return tty\nend\n\n-- erases the screen with the background colour and moves the cursor to home.\nfunction tty.erase_screen()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[2J\")\n    end\n    return tty\nend\n\n-- save current cursor position.\nfunction tty.cursor_save()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[s\")\n    end\n    return tty\nend\n\n-- restores cursor position after a save cursor.\nfunction tty.cursor_restore()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[u\")\n    end\n    return tty\nend\n\n-- save current cursor position and color attrs\nfunction tty.cursor_and_attrs_save()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b7\")\n    end\n    return tty\nend\n\n-- restores cursor position and color attrs after a save cursor.\nfunction tty.cursor_and_attrs_restore()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b8\")\n    end\n    return tty\nend\n\n-- move cursor to absolute position (row, col)\n-- row and col are 1-based (1, 1) is the top-left corner\nfunction tty.cursor_move(row, col)\n    if tty.has_vtansi() then\n        row = row or 1\n        col = col or 1\n        if row > 0 and col > 0 then\n            tty._iowrite(string.format(\"\\x1b[%d;%dH\", row, col))\n        end\n    end\n    return tty\nend\n\n-- move cursor up by n lines\nfunction tty.cursor_move_up(n)\n    if tty.has_vtansi() then\n        n = n or 1\n        if n > 0 then\n            tty._iowrite(string.format(\"\\x1b[%dA\", n))\n        end\n    end\n    return tty\nend\n\n-- move cursor down by n lines\nfunction tty.cursor_move_down(n)\n    if tty.has_vtansi() then\n        n = n or 1\n        if n > 0 then\n            tty._iowrite(string.format(\"\\x1b[%dB\", n))\n        end\n    end\n    return tty\nend\n\n-- move cursor forward (right) by n columns\nfunction tty.cursor_move_right(n)\n    if tty.has_vtansi() then\n        n = n or 1\n        if n > 0 then\n            tty._iowrite(string.format(\"\\x1b[%dC\", n))\n        end\n    end\n    return tty\nend\n\n-- move cursor backward (left) by n columns\nfunction tty.cursor_move_left(n)\n    if tty.has_vtansi() then\n        n = n or 1\n        if n > 0 then\n            tty._iowrite(string.format(\"\\x1b[%dD\", n))\n        end\n    end\n    return tty\nend\n\n-- move cursor to specified column\nfunction tty.cursor_move_to_col(col)\n    if tty.has_vtansi() then\n        col = col or 1\n        if col > 0 then\n            tty._iowrite(string.format(\"\\x1b[%dG\", col))\n        end\n    end\n    return tty\nend\n\n-- hide cursor\nfunction tty.cursor_hide()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[?25l\")\n    end\n    return tty\nend\n\n-- show cursor\nfunction tty.cursor_show()\n    if tty.has_vtansi() then\n        tty._iowrite(\"\\x1b[?25h\")\n    end\n    return tty\nend\n\n-- carriage return\nfunction tty.cr()\n    tty._iowrite(\"\\r\")\n    return tty\nend\n\n-- flush control\nfunction tty.flush()\n    if io.isatty() then\n        io.flush()\n    end\n    return tty\nend\n\nfunction tty._find_shell_from_parent_on_windows()\n    local shell\n    local winos = require(\"base/winos\")\n    if winos.processes then\n        local processes = winos.processes()\n        if processes then\n            local pid = os.getpid()\n            local processes_map = {}\n            for _, process in ipairs(processes) do\n                processes_map[process.pid] = process\n            end\n            local count = 0\n            while pid and pid ~= 0 and count < 10 do\n                count = count + 1\n                local process = processes_map[pid]\n                if not process then\n                    break\n                end\n                local name = process.name\n                if name then\n                    name = name:lower()\n                    if name:sub(-4) == \".exe\" then\n                        name = name:sub(1, #name - 4)\n                    end\n                    for _, shellname in ipairs({\"zsh\", \"bash\", \"fish\", \"nu\", \"elvish\", \"pwsh\", \"powershell\", \"cmd\", \"sh\"}) do\n                        if name == shellname then\n                            shell = shellname\n                            break\n                        end\n                    end\n                end\n                if shell then\n                    break\n                end\n                pid = process.parent_pid or process.ppid -- for backward compatibility\n            end\n        end\n    end\n\n    if not shell then\n        local subhost = xmake._SUBHOST\n        if subhost == \"windows\" then\n            if os.getenv(\"PROMPT\") then\n                shell = \"cmd\"\n            else\n                local ok, result = os.iorun(\"pwsh -v\")\n                if ok then\n                    shell = \"pwsh\"\n                else\n                    shell = \"powershell\"\n                end\n            end\n        end\n    end\n    return shell\nend\n\n\nfunction tty._find_shell_from_parent_on_linux()\n    local pid = os.getpid()\n    local count = 0\n    local shell\n    while pid ~= 0 and count < 4 do\n        count = count + 1\n        local shell_name = nil\n        local shell_path = nil\n        if os.isfile(\"/proc/\" .. pid .. \"/exe\") then\n            local link = os.readlink(\"/proc/\" .. pid .. \"/exe\")\n            if link then\n                shell_path = link\n            end\n        end\n\n        if not shell_path and os.isfile(\"/proc/\" .. pid .. \"/comm\") then\n             shell_name = io.readfile(\"/proc/\" .. pid .. \"/comm\")\n             if shell_name then\n                 shell_name = shell_name:trim()\n             end\n        end\n        if shell_path then\n            shell_name = path.filename(shell_path)\n        end\n\n        if shell_name then\n            shell_name = shell_name:ltrim(\"-\")\n            for _, name in ipairs({\"zsh\", \"bash\", \"fish\", \"nu\", \"elvish\", \"pwsh\", \"sh\"}) do\n                if shell_name == name then\n                    shell = name\n                    break\n                end\n            end\n            if shell then\n                break\n            end\n        end\n\n        local stat = io.readfile(\"/proc/\" .. pid .. \"/stat\")\n        local ppid = stat and tonumber(stat:match(\".*%) %S+ (%d+)\"))\n        if not ppid or ppid == 0 then\n            break\n        end\n        pid = ppid\n    end\n    return shell\nend\n\n-- find the shell from the parent process\nfunction tty._find_shell_from_parent()\n\n    -- for windows\n    if os.host() == \"windows\" then\n        return tty._find_shell_from_parent_on_windows()\n    end\n\n    -- for linux\n    if os.host() == \"linux\" and os.isfile(\"/proc/self/stat\") then\n        return tty._find_shell_from_parent_on_linux()\n    end\nend\n\n-- get shell name\nfunction tty.shell()\n    local shell = tty._SHELL\n    if shell == nil then\n        if os.getenv(\"NU_VERSION\") then\n            shell = \"nu\"\n        end\n        -- try to find the shell from the parent process\n        if not shell then\n            shell = tty._find_shell_from_parent()\n        end\n\n        if not shell then\n            shell = os.getenv(\"XMAKE_SHELL\")\n        end\n        if not shell then\n            shell = os.getenv(\"SHELL\")\n            if shell then\n                for _, shellname in ipairs({\"zsh\", \"bash\", \"fish\", \"nu\", \"elvish\", \"pwsh\", \"sh\"}) do\n                    if shell:find(shellname) then\n                        shell = shellname\n                        break\n                    end\n                end\n            end\n        end\n        tty._SHELL = shell or \"sh\"\n    end\n    return tty._SHELL\nend\n\n-- get terminal name\n--  - xterm\n--  - cmd\n--  - vstudio (in visual studio)\n--  - vscode (in vscode)\n--  - msys2\n--  - cygwin\n--  - pwsh\n--  - powershell\n--  - mintty\n--  - windows-terminal\n--  - gnome-terminal\n--  - xfce4-terminal\n--  - konsole\n--  - terminator\n--  - rxvt\n--  - lxterminal\n--  - ghostty\n--  - unknown\n--\nfunction tty.term()\n    local term = tty._TERM\n    if term == nil then\n\n        -- get term from $TERM_PROGRAM\n        if term == nil then\n            local TERM_PROGRAM = os.getenv(\"TERM_PROGRAM\")\n            if TERM_PROGRAM ~= nil then\n                if TERM_PROGRAM:find(\"vscode\", 1, true) then\n                    term = \"vscode\"\n                elseif TERM_PROGRAM == \"mintty\" then\n                    term = \"mintty\" -- git bash\n                elseif TERM_PROGRAM == \"ghostty\" then\n                    term = \"ghostty\"\n                end\n            end\n        end\n\n        -- get term from $TERM\n        if term == nil then\n            local TERM = os.getenv(\"TERM\")\n            if TERM ~= nil then\n                if TERM:find(\"ghostty\", 1, true) then\n                    term = \"ghostty\"\n                elseif TERM:find(\"xterm\", 1, true) then\n                    term = \"xterm\"\n                elseif TERM == \"cygwin\" then\n                    term = \"cygwin\"\n                elseif TERM:find(\"alacritty\", 1, true) then\n                    term = \"alacritty\"\n                end\n            end\n        end\n\n        -- get term from system\n        if term == nil then\n            local subhost = xmake._SUBHOST\n            if subhost == \"windows\" then\n                if os.getenv(\"XMAKE_IN_VSTUDIO\") then\n                    term = \"vstudio\"\n                elseif os.getenv(\"WT_SESSION\") then\n                    term = \"windows-terminal\"\n                else\n                    term = tty.shell()\n                end\n            elseif subhost == \"msys\" then\n                term = \"msys2\"\n            elseif subhost == \"cygwin\" then\n                term = \"cygwin\"\n            elseif subhost == \"macosx\" then\n                term = \"xterm\"\n            end\n        end\n        tty._TERM = term or \"unknown\"\n    end\n    return tty._TERM\nend\n\n-- has emoji?\nfunction tty.has_emoji()\n    local has_emoji = tty._HAS_EMOJI\n    if has_emoji == nil then\n        local term = tty.term()\n        local winos = require(\"base/winos\")\n\n        -- before win8? disable it\n        if has_emoji == nil and (os.host() == \"windows\" and winos.version():le(\"win8\")) then\n            has_emoji = false\n        end\n\n        -- on msys2/cygwin/powershell? disable it\n        if has_emoji == nil and (term == \"msys2\" or term == \"cygwin\" or term == \"powershell\") then\n            has_emoji = false\n        end\n\n        -- enable it by default\n        if has_emoji == nil then\n            has_emoji = true\n        end\n        tty._HAS_EMOJI = has_emoji or false\n    end\n    return has_emoji\nend\n\n-- has vtansi?\nfunction tty.has_vtansi()\n    return tty.has_color8()\nend\n\n-- has 8 colors?\nfunction tty.has_color8()\n    local has_color8 = tty._HAS_COLOR8\n    if has_color8 == nil then\n\n        -- detect it from $COLORTERM\n        if has_color8 == nil then\n            local colorterm = tty._colorterm()\n            if colorterm == \"nocolor\" then\n                has_color8 = false\n            elseif colorterm and colorterm:find(\"8color\", 1, true) then\n                has_color8 = true\n            elseif tty.has_color256() or tty.has_color24() then\n                has_color8 = true\n            end\n        end\n\n        -- detect it from $TERM\n        local term = tty.term()\n        if has_color8 == nil then\n            if term == \"vstudio\" then\n                has_color8 = false\n            elseif term == \"xterm\" or term == \"mintty\" then\n                has_color8 = true\n            end\n        end\n\n        -- detect it from system\n        if has_color8 == nil then\n            if os.host() == \"windows\" then\n                local winos = require(\"base/winos\")\n                if os.getenv(\"ANSICON\") then\n                    has_color8 = true\n                elseif winos.version():le(\"win8\") then\n                    has_color8 = false\n                else\n                    has_color8 = true\n                end\n            else\n                -- alway enabled for unix-like system\n                has_color8 = true\n            end\n        end\n        tty._HAS_COLOR8 = has_color8 or false\n    end\n    return has_color8\nend\n\n-- has 256 colors?\nfunction tty.has_color256()\n\n    local has_color256 = tty._HAS_COLOR256\n    if has_color256 == nil then\n\n        -- detect it from $COLORTERM\n        if has_color256 == nil then\n            local colorterm = tty._colorterm()\n            if colorterm == \"nocolor\" then\n                has_color256 = false\n            elseif colorterm and (colorterm:find(\"256color\", 1, true) or colorterm:find(\"color256\", 1, true)) then\n                has_color256 = true\n            elseif tty.has_color24() then\n                has_color256 = true\n            end\n        end\n\n        -- detect it from $TERM\n        local term = tty.term()\n        local term_env = os.getenv(\"TERM\")\n        if has_color256 == nil then\n            if term == \"vstudio\" then\n                has_color256 = false\n            elseif term_env and (term_env:find(\"256color\", 1, true) or term_env:find(\"color256\", 1, true)) then\n                has_color256 = true\n            end\n        end\n\n        -- detect it from system\n        if has_color256 == nil then\n            if os.host() == \"windows\" then\n                has_color256 = false\n            elseif os.host() == \"linux\" or os.host(\"macosx\") then\n                -- alway enabled for linux/macOS, $TERM maybe xterm, not xterm-256color, but it is supported\n                has_color256 = true\n            else\n                has_color256 = false\n            end\n        end\n        tty._HAS_COLOR256 = has_color256 or false\n    end\n    return has_color256\nend\n\n-- has 24bits true color?\n--\n-- There's no reliable way, and ncurses/terminfo's maintainer expressed he has no intent on introducing support.\n-- S-Lang author added a check for $COLORTERM containing either \"truecolor\" or \"24bit\" (case sensitive).\n-- In turn, VTE, Konsole and iTerm2 set this variable to \"truecolor\" (it's been there in VTE for a while,\n-- it's relatively new and maybe still git-only in Konsole and iTerm2).\n--\n-- This is obviously not a reliable method, and is not forwarded via sudo, ssh etc. However, whenever it errs,\n-- it errs on the safe side: does not advertise support whereas it's actually supported.\n-- App developers can freely choose to check for this same variable, or introduce their own method\n-- (e.g. an option in their config file), whichever matches better the overall design of the given app.\n-- Checking $COLORTERM is recommended though, since that would lead to a more unique desktop experience\n-- where the user has to set one variable only and it takes effect across all the apps, rather than something\n-- separately for each app.\n--\nfunction tty.has_color24()\n\n    local has_color24 = tty._HAS_COLOR24\n    if has_color24 == nil then\n\n        -- detect it from $COLORTERM\n        if has_color24 == nil then\n            local colorterm = tty._colorterm()\n            if colorterm == \"nocolor\" then\n                has_color24 = false\n            elseif colorterm and (colorterm:find(\"truecolor\", 1, true) or colorterm:find(\"24bit\", 1, true)) then\n                has_color24 = true\n            end\n        end\n\n        -- detect it from $TERM\n        local term = tty.term()\n        local term_env = os.getenv(\"TERM\")\n        if has_color256 == nil then\n            if term == \"vstudio\" then\n                has_color256 = false\n            elseif term_env and (term_env:find(\"truecolor\", 1, true) or term_env:find(\"24bit\", 1, true)) then\n                has_color256 = true\n            end\n        end\n        tty._HAS_COLOR24 = has_color24 or false\n    end\n    return has_color24\nend\n\n-- get term mode, e.g. stdin, stdout, stderr\n--\n-- local oldmode = tty.term_mode(stdtype)\n-- local oldmode = tty.term_mode(stdtype, newmode)\n--\nfunction tty.term_mode(stdtype, newmode)\n    local oldmode = 0\n    if tty._term_mode then\n        if stdtype == \"stdin\" then\n            oldmode = tty._term_mode(1, newmode)\n        elseif stdtype == \"stdout\" then\n            oldmode = tty._term_mode(2, newmode)\n        elseif stdtype == \"stderr\" then\n            oldmode = tty._term_mode(3, newmode)\n        end\n    end\n    return oldmode\nend\n\n-- get session id\nfunction tty.session_id()\n    local session_id = tty._SESSION_ID\n    if session_id == nil then\n        if tty._session_id then\n            local sid = tty._session_id()\n            if sid then\n                local hash = require(\"base/hash\")\n                session_id = hash.strhash32(sid)\n            end\n        end\n        if not session_id then\n            session_id = \"00000000\"\n        end\n        tty._SESSION_ID = session_id\n    end\n    return session_id\nend\n\n-- return module\nreturn tty\n"
  },
  {
    "path": "xmake/core/base/utf8.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utf8.lua\n\n-- define module: utf8\nlocal utf8 = utf8 or {}\n\n-- @desc        The utf8 module\n--              It provides basic support for UTF-8 encoding.\n--              It is compatible with Lua 5.3+ utf8 library.\n--\n-- @interface   utf8.len(s [, i [, j [, lax]]])\n-- @interface   utf8.char(...)\n-- @interface   utf8.codepoint(s [, i [, j]])\n-- @interface   utf8.offset(s, n [, i])\n-- @interface   utf8.codes(s [, lax])\n-- @interface   utf8.sub(s, i [, j])\n-- @interface   utf8.reverse(s)\n-- @interface   utf8.lastof(s, pattern [, plain])\n-- @interface   utf8.find(s, pattern [, init [, plain]])\n-- @interface   utf8.width(s)\n-- @interface   utf8.byte(s [, i [, j]])\n--\n\n-- the utf8 bom\nif not utf8.bom then\n    utf8.bom = \"\\239\\187\\191\"\nend\n\n-- the char pattern\nif not utf8.charpattern then\n    utf8.charpattern = \"[\\0-\\x7F\\xC2-\\xFD][\\x80-\\xBF]*\"\nend\n\n-- return module: utf8\nreturn utf8\n"
  },
  {
    "path": "xmake/core/base/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- define module\nlocal utils = utils or {}\n\n-- load modules\nlocal option = require(\"base/option\")\nlocal colors = require(\"base/colors\")\nlocal string = require(\"base/string\")\nlocal log    = require(\"base/log\")\nlocal io     = require(\"base/io\")\nlocal dump   = require(\"base/dump\")\nlocal text   = require(\"base/text\")\n\n\n-- dump values\nfunction utils.dump(...)\n    if option.get(\"quiet\") then\n        return ...\n    end\n\n    local diagnosis = option.get(\"diagnosis\")\n\n    -- show caller info\n    if diagnosis then\n        local info = debug.getinfo(2)\n        local line = info.currentline\n        if not line or line < 0 then line = info.linedefined end\n        io.write(string.format(\"dump from %s %s:%s\\n\", info.name or \"<anonymous>\", info.source, line))\n    end\n\n    local values = table.pack(...)\n    if values.n == 0 then\n        return\n    end\n\n    if values.n == 1 then\n        dump(values[1], \"\", diagnosis)\n    else\n        for i = 1, values.n do\n            dump(values[i], string.format(\"%2d: \", i), diagnosis)\n        end\n    end\n\n    return table.unpack(values, 1, values.n)\nend\n\n-- print string with newline\nfunction utils._print(...)\n\n    -- print it if not quiet\n    if not option.get(\"quiet\") then\n        local values = {...}\n        for i, v in ipairs(values) do\n            -- dump basic type\n            if type(v) == \"string\" or type(v) == \"boolean\" or type(v) == \"number\" then\n                io.write(tostring(v))\n            -- dump table\n            elseif type(v) == \"table\" then\n                dump(v)\n            else\n                io.write(\"<\" .. tostring(v) .. \">\")\n            end\n            if i ~= #values then\n                io.write(\" \")\n            end\n        end\n        io.write('\\n')\n    end\nend\n\n-- print string without newline\nfunction utils._iowrite(...)\n\n    -- print it if not quiet\n    if not option.get(\"quiet\") then\n        io.write(...)\n    end\nend\n\n-- decode errors if errors is encoded table string\nfunction utils._decode_errors(errors)\n    if not errors then\n        return\n    end\n    local _, pos = errors:find(\"[@encode(error)]: \", 1, true)\n    if pos then\n        -- strip traceback (maybe from coroutine.resume)\n        local errs = errors:sub(pos + 1)\n        local stack = nil\n        local stackpos = errs:find(\"}\\nstack traceback:\", 1, true)\n        if stackpos and stackpos > 1 then\n            stack = errs:sub(stackpos + 2)\n            errs  = errs:sub(1, stackpos)\n        end\n        errors, errs = errs:deserialize()\n        if not errors then\n            errors = errs\n        end\n        if type(errors) == \"table\" then\n            if stack then\n                errors._stack = stack\n            end\n            setmetatable(errors,\n            {\n                __tostring = function (self)\n                    local result = self.errors\n                    if not result then\n                        result = string.serialize(self, {strip = true, indent = false})\n                    end\n                    result = result or \"\"\n                    if self._stack then\n                        result = result .. \"\\n\" .. self._stack\n                    end\n                    return result\n                end,\n                __concat = function (self, other)\n                    return tostring(self) .. tostring(other)\n                end\n            })\n        end\n        return errors\n    end\nend\n\n-- print format string with newline\nfunction utils.print(format, ...)\n    assert(format)\n    local message = string.tryformat(format, ...)\n    utils._print(message)\n    log:printv(message)\nend\n\n-- print format string without newline\nfunction utils.printf(format, ...)\n    assert(format)\n    local message = string.tryformat(format, ...)\n    utils._iowrite(message)\n    log:write(message)\nend\n\n-- print format string and colors with newline\nfunction utils.cprint(format, ...)\n    assert(format)\n    local message = string.tryformat(format, ...)\n    utils._print(colors.translate(message))\n    if log:file() then\n        log:printv(colors.ignore(message))\n    end\nend\n\n-- print format string and colors without newline\nfunction utils.cprintf(format, ...)\n    assert(format)\n    local message = string.tryformat(format, ...)\n    utils._iowrite(colors.translate(message))\n    if log:file() then\n        log:write(colors.ignore(message))\n    end\nend\n\n-- print the verbose information\nfunction utils.vprint(format, ...)\n    if (option.get(\"verbose\") or option.get(\"diagnosis\")) and format ~= nil then\n        utils.print(format, ...)\n    end\nend\n\n-- print the verbose information without newline\nfunction utils.vprintf(format, ...)\n    if (option.get(\"verbose\") or option.get(\"diagnosis\")) and format ~= nil then\n        utils.printf(format, ...)\n    end\nend\n\n-- print the diagnosis information\nfunction utils.dprint(format, ...)\n    if option.get(\"diagnosis\") and format ~= nil then\n        utils.print(format, ...)\n    end\nend\n\n-- print the diagnosis information without newline\nfunction utils.dprintf(format, ...)\n    if option.get(\"diagnosis\") and format ~= nil then\n        utils.printf(format, ...)\n    end\nend\n\n-- print the error information\nfunction utils.error(format, ...)\n    if format ~= nil then\n        local errors = string.tryformat(format, ...)\n        local decoded_errors = utils._decode_errors(errors)\n        if decoded_errors then\n            errors = tostring(decoded_errors)\n        end\n        utils.cprint(\"${bright color.error}${text.error}: ${clear}\" .. errors)\n        log:flush()\n    end\nend\n\n-- add warning message\nfunction utils.warning(format, ...)\n    if option.get(\"quiet\") then\n        return\n    end\n\n    -- format message\n    local args = table.pack(...)\n    local msg = (args.n > 0 and string.tryformat(format, ...) or format)\n\n    -- init warnings\n    local warnings = utils._WARNINGS\n    if not warnings then\n        warnings = {}\n        utils._WARNINGS = warnings\n    end\n\n    -- add warning msg\n    table.insert(warnings, msg)\nend\n\n-- show warnings\nfunction utils.show_warnings()\n    local warnings = utils._WARNINGS\n    if warnings then\n        for idx, msg in ipairs(table.unique(warnings)) do\n            if not option.get(\"verbose\") and idx > 1 then\n                utils.cprint(\"${bright color.warning}${text.warning}: ${color.warning}add -v for getting more warnings ..\")\n                break\n            end\n            utils.cprint(\"${bright color.warning}${text.warning}: ${color.warning}%s\", msg)\n        end\n    end\nend\n\n-- try to call script\nfunction utils.trycall(script, traceback, ...)\n    return xpcall(script, function (errors)\n\n            -- get traceback\n            traceback = traceback or debug.traceback\n\n            -- decode it if errors is encoded table string\n            local decoded_errors = utils._decode_errors(errors)\n            if decoded_errors then\n                return decoded_errors\n            end\n            return traceback(errors)\n        end, ...)\nend\n\n-- get confirm result\n--\n-- @code\n-- if utils.confirm({description = \"xmake.lua not found, try generating it\", default = true}) then\n--    TODO\n-- end\n-- @endcode\n--\nfunction utils.confirm(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get default\n    local default = opt.default\n    if default == nil then\n        default = false\n    end\n\n    -- get description\n    local description = opt.description or \"\"\n\n    -- get confirm result\n    local result = option.get(\"yes\") or option.get(\"confirm\")\n    if type(result) == \"string\" then\n        result = result:lower()\n        if result == \"d\" or result == \"def\" then\n            result = default\n        else\n            result = nil\n        end\n    end\n\n    -- get user confirm\n    if result == nil then\n\n        -- show tips\n        if type(description) == \"function\" then\n            description()\n        else\n            utils.cprint(\"${bright color.warning}note: ${clear}%s (pass -y or --confirm=y/n/d to skip confirm)?\", description)\n        end\n\n        -- get answer\n        if opt.answer then\n            result = opt.answer()\n        else\n            utils.cprint(\"please input: ${bright}%s${clear} (y/n)\", default and \"y\" or \"n\")\n            io.flush()\n            result = option.boolean((io.read() or \"false\"):trim())\n            if type(result) ~= \"boolean\" then\n                result = default\n            end\n        end\n    end\n    return result\nend\n\nfunction utils.table(data, opt)\n    utils.printf(text.table(data, opt))\nend\n\nfunction utils.vtable(data, opt)\n    utils.vprintf(text.table(data, opt))\nend\n\n-- return module\nreturn utils\n"
  },
  {
    "path": "xmake/core/base/winos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        winos.lua\n--\n\n-- define module: winos\nlocal winos = winos or {}\n\n-- load modules\nlocal os     = require(\"base/os\")\nlocal path   = require(\"base/path\")\nlocal semver = require(\"base/semver\")\n\nwinos._ansi_cp         = winos._ansi_cp or winos.ansi_cp\nwinos._oem_cp          = winos._oem_cp  or winos.oem_cp\nwinos._registry_query  = winos._registry_query or winos.registry_query\nwinos._registry_keys   = winos._registry_keys or winos.registry_keys\nwinos._registry_values = winos._registry_values or winos.registry_values\nwinos._processes       = winos._processes or winos.processes\n\nfunction winos.ansi_cp()\n    if not winos._ANSI_CP then\n         winos._ANSI_CP = winos._ansi_cp()\n    end\n    return winos._ANSI_CP\nend\n\nfunction winos.oem_cp()\n    if not winos._OEM_CP then\n         winos._OEM_CP = winos._oem_cp()\n    end\n    return winos._OEM_CP\nend\n\nif not winos.processes then\n    winos.processes = winos._processes\nend\n\n-- get windows version from name\nfunction winos._version_from_name(name)\n    winos._VERSIONS = winos._VERSIONS or {\n        nt4      = \"4.0\"\n    ,   win2k    = \"5.0\"\n    ,   winxp    = \"5.1\"\n    ,   ws03     = \"5.2\"\n    ,   win6     = \"6.0\"\n    ,   vista    = \"6.0\"\n    ,   ws08     = \"6.0\"\n    ,   longhorn = \"6.0\"\n    ,   win7     = \"6.1\"\n    ,   win8     = \"6.2\"\n    ,   winblue  = \"6.3\"\n    ,   win81    = \"6.3\"\n    ,   win10    = \"10.0\"\n    ,   win11    = \"10.0.22000\"\n    }\n    return winos._VERSIONS[name]\nend\n\n-- v1 == v2 with name (winxp, win10, ..)?\nfunction winos._version_eq(self, version)\n    if type(version) == \"string\" then\n        local namever = winos._version_from_name(version)\n        if namever then\n            return semver.compare(self:major() .. '.' .. self:minor(), namever) == 0\n        else\n            return semver.compare(self:rawstr(), version) == 0\n        end\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) == 0\n    end\nend\n\n-- v1 < v2 with name (winxp, win10, ..)?\nfunction winos._version_lt(self, version)\n    if type(version) == \"string\" then\n        local namever = winos._version_from_name(version)\n        if namever then\n            return semver.compare(self:major() .. '.' .. self:minor(), namever) < 0\n        else\n            return semver.compare(self:rawstr(), version) < 0\n        end\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) < 0\n    end\nend\n\n-- v1 <= v2 with name (winxp, win10, ..)?\nfunction winos._version_le(self, version)\n    if type(version) == \"string\" then\n        local namever = winos._version_from_name(version)\n        if namever then\n            return semver.compare(self:major() .. '.' .. self:minor(), namever) <= 0\n        else\n            return semver.compare(self:rawstr(), version) <= 0\n        end\n    elseif type(version) == \"table\" then\n        return semver.compare(self:rawstr(), version:rawstr()) <= 0\n    end\nend\n\n-- get system version\nfunction winos.version()\n    local winver = winos._VERSION\n    if winver == nil then\n\n        -- get winver\n        local ok, verstr = os.iorun(\"cmd /c ver\")\n        if ok and verstr then\n            winver = verstr:match(\"%[.-([%d%.]+)]\")\n            if winver then\n                winver = winver:trim()\n                local sem_winver\n                local seg = 0\n                for num in winver:gmatch(\"%d+\") do\n                    if seg == 0 then\n                        sem_winver = num\n                    elseif seg == 3 then\n                        sem_winver = sem_winver .. \"+\" .. num\n                    else\n                        sem_winver = sem_winver .. \".\" .. num\n                    end\n                    seg = seg + 1\n                end\n                if sem_winver then\n                    winver = semver.new(sem_winver)\n                end\n            end\n        end\n        if not winver then\n            winver = semver.new(\"0.0\")\n        end\n\n        -- rewrite comparator\n        winver.eq = winos._version_eq\n        winver.lt = winos._version_lt\n        winver.le = winos._version_le\n        winos._VERSION = winver\n    end\n    return winver\nend\n\n-- get command arguments on windows to solve 8192 character command line length limit\nfunction winos.cmdargv(argv, opt)\n\n    -- too long arguments?\n    local limit = 4096\n    local argn = 0\n    for _, arg in ipairs(argv) do\n        arg = tostring(arg)\n        argn = argn + #arg\n        if argn > limit then\n            break\n        end\n    end\n    if argn > limit then\n        opt = opt or {}\n        local argsfile = os.tmpfile(opt.tmpkey or os.args(argv)) .. \".args.txt\"\n        local f = io.open(argsfile, 'w', {encoding = os.is_host(\"windows\") and \"ansi\"})\n        if f then\n            -- we need to split args file to solve `fatal error LNK1170: line in command file contains 131071 or more characters`\n            -- @see https://github.com/xmake-io/xmake/issues/812\n            local idx = 1\n            while idx <= #argv do\n                arg = tostring(argv[idx])\n                arg1 = argv[idx + 1]\n                if arg1 then\n                    arg1 = tostring(arg1)\n                end\n                -- we need to ensure `/name value` in same line,\n                -- otherwise cl.exe will prompt that the corresponding parameter value cannot be found\n                --\n                -- e.g.\n                --\n                -- /sourceDependencies xxxx.json\n                -- -Dxxx\n                -- foo.obj\n                --\n\n                -- if host is not Windows, paths may start with '/', which conflicts with '/<argname>'\n                -- note that checking if the next argument ends with '.json' will only work for /sourceDependencies\n                -- other arguments will remain broken, perhaps we should discuss a better solution\n                if idx + 1 <= #argv and arg:find(\"^[-/]\") and (os.is_host(\"windows\") and (not arg1:find(\"^[-/]\")) or (arg1:endswith(\".json\"))) then\n                    f:write(os.args(arg, {escape = opt.escape}) .. \" \")\n                    f:write(os.args(arg1, {escape = opt.escape}) .. \"\\n\")\n                    idx = idx + 2\n                else\n                    f:write(os.args(arg, {escape = opt.escape}) .. \"\\n\")\n                    idx = idx + 1\n                end\n            end\n            f:close()\n        end\n        argv = {\"@\" .. argsfile}\n    end\n    return argv\nend\n\n-- query registry value\n--\n-- @param keypath   the key path\n-- @return          the value and errors\n--\n-- @code\n-- local value, errors = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\")\n-- local value, errors = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\")\n-- @endcode\n--\nfunction winos.registry_query(keypath)\n\n    -- get value name\n    local splitinfo = keypath:split(';', {plain = true})\n    local valuename = splitinfo[2] or \"\"\n    keypath = splitinfo[1]\n\n    -- get rootkey, e.g. HKEY_LOCAL_MACHINE\n    local rootkey\n    local p = keypath:find(\"\\\\\", 1, true)\n    if p then\n        rootkey = keypath:sub(1, p - 1)\n    end\n    if not rootkey then\n        return nil, \"root key not found!\"\n    end\n\n    -- get the root directory\n    local rootdir = keypath:sub(p + 1)\n\n    -- query value\n    return winos._registry_query(rootkey, rootdir, valuename)\nend\n\n-- get registry key paths\n--\n-- @param keypath   the key path (support key pattern, e.g. \\\\a\\\\b;xx*yy)\n--                  uses \"*\" to match any part of a key path,\n--                  uses \"**\" to recurse into subkey paths.\n-- @return          the result array and errors\n--\n-- @code\n-- local keys, errors = winos.registry_keys(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\*\\\\Windows NT\\\\*\\\\CurrentVersion\\\\AeDebug\")\n-- local keys, errors = winos.registry_keys(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\**\")\n-- @endcode\n--\nfunction winos.registry_keys(keypath)\n\n    -- get rootkey, e.g. HKEY_LOCAL_MACHINE\n    local rootkey\n    local p = keypath:find(\"\\\\\", 1, true)\n    if p then\n        rootkey = keypath:sub(1, p - 1)\n    end\n    if not rootkey then\n        return\n    end\n    keypath = keypath:sub(p + 1)\n\n    -- get the root directory\n    local pattern\n    local rootdir = keypath\n    p = rootdir:find(\"*\", 1, true)\n    if p then\n        pattern = path.pattern(rootdir)\n        rootdir = path.directory(rootdir:sub(1, p - 1))\n    end\n\n    -- compute the recursion level\n    --\n    -- infinite recursion: aaa\\\\**\n    -- limit recursion level: aaa\\\\*\\\\*\n    local recursion = 0\n    if keypath:find(\"**\", 1, true) then\n        recursion = -1\n    else\n        -- \"aaa\\\\*\\\\*\" -> \"*\\\\\" -> recursion level: 1\n        -- \"aaa\\\\*\\\\xxx\" -> \"*\\\\\" -> recursion level: 1\n        -- \"aaa\\\\*\\\\subkey\\\\xxx\" -> \"*\\\\\\\\\" -> recursion level: 2\n        if p then\n            local _, seps = keypath:sub(p):gsub(\"\\\\\", \"\")\n            if seps > 0 then\n                recursion = seps\n            end\n        end\n    end\n\n    -- get keys\n    local keys = {}\n    local count, errors = winos._registry_keys(rootkey, rootdir, recursion, function (key)\n        if not pattern or key:match(\"^\" .. pattern .. \"$\") then\n            table.insert(keys, rootkey .. '\\\\' .. key)\n            if #keys > 4096 then\n                return false\n            end\n        end\n        return true\n    end)\n    if #keys > 4096 then\n        return nil, \"too much registry keys: \" .. keypath\n    end\n    if count ~= nil then\n        return keys\n    else\n        return nil, errors\n    end\nend\n\n-- get registry values from the given key path\n--\n-- @param keypath   the key path (support value pattern, e.g. \\\\a\\\\b;xx*yy)\n--                  uses \"*\" to match value name,\n-- @return          the values array and errors\n--\n-- @code\n-- local values, errors = winos.registry_values(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug\")\n-- local values, errors = winos.registry_values(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debug*\")\n-- @endcode\n--\nfunction winos.registry_values(keypath)\n\n    -- get value pattern\n    local splitinfo = keypath:split(';', {plain = true})\n    local pattern = splitinfo[2]\n    if pattern then\n        pattern = path.pattern(pattern)\n    end\n    keypath = splitinfo[1]\n\n    -- get rootkey, e.g. HKEY_LOCAL_MACHINE\n    local rootkey\n    local p = keypath:find(\"\\\\\", 1, true)\n    if p then\n        rootkey = keypath:sub(1, p - 1)\n    end\n    if not rootkey then\n        return nil, \"root key not found!\"\n    end\n\n    -- get the root directory\n    local rootdir = keypath:sub(p + 1)\n\n    -- get value names\n    local value_names = {}\n    local count, errors = winos._registry_values(rootkey, rootdir, function (value_name)\n        if not pattern or value_name:match(\"^\" .. pattern .. \"$\") then\n            table.insert(value_names, rootkey .. \"\\\\\" .. rootdir .. \";\" .. value_name)\n        end\n        return true\n    end)\n    if count ~= nil then\n        return value_names\n    else\n        return nil, errors\n    end\nend\n\n-- inherit handles in CreateProcess safely?\n-- https://github.com/xmake-io/xmake/issues/2902#issuecomment-1326934902\n--\nfunction winos.inherit_handles_safely()\n    local inherit_handles_safely = winos._INHERIT_HANDLES_SAFELY\n    if inherit_handles_safely == nil then\n        inherit_handles_safely = winos.version():ge(\"win7\") or false\n        winos._INHERIT_HANDLES_SAFELY = inherit_handles_safely\n    end\n    return inherit_handles_safely\nend\n\n-- return module: winos\nreturn winos\n"
  },
  {
    "path": "xmake/core/base/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define module: xmake\nlocal xmake = xmake or {}\n\n-- load modules\nlocal semver = require(\"base/semver\")\n\n-- get name\nfunction xmake.name()\n    return xmake._NAME or \"xmake\"\nend\n\n-- get xmake version, e.g. v2.5.8+dev.d4cff6e11\nfunction xmake.version()\n    if xmake._VERSION_CACHE == nil then\n        xmake._VERSION_CACHE = semver.new(xmake._VERSION) or false\n    end\n    return xmake._VERSION_CACHE or nil\nend\n\n-- get the xmake binary architecture\nfunction xmake.arch()\n    return xmake._XMAKE_ARCH\nend\n\n-- get the git branch of xmake version, e.g. build: {\"dev\", \"d4cff6e11\"}\nfunction xmake.branch()\n    return xmake.version():build()[1]\nend\n\n-- get the program directory\nfunction xmake.programdir()\n    return xmake._PROGRAM_DIR\nend\n\n-- get the program file\nfunction xmake.programfile()\n    return xmake._PROGRAM_FILE\nend\n\n-- use luajit?\nfunction xmake.luajit()\n    return xmake._LUAJIT\nend\n\n-- is embed?\nfunction xmake.is_embed()\n    return xmake._EMBED or false\nend\n\n-- in main thread?\nfunction xmake.in_main_thread()\n    return xmake._THREAD_CALLBACK == nil\nend\n\n-- get command arguments\nfunction xmake.argv()\n    return xmake._ARGV\nend\n\n-- return module: xmake\nreturn xmake\n"
  },
  {
    "path": "xmake/core/base/xml.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xml.lua\n--\n\n-- define module: xml\nlocal xml = xml or {}\n\n-- load modules\nlocal io     = require(\"base/io\")\nlocal os     = require(\"base/os\")\nlocal table  = require(\"base/table\")\nlocal string = require(\"base/string\")\n\n-- XML node structure (mutable DOM-style tables):\n-- {\n--     name     = \"element-name\" | nil (for non-element nodes)\n--     kind     = \"element\" | \"text\" | \"comment\" | \"cdata\" | \"doctype\" | \"document\"\n--     attrs    = { key = value, ... } or nil (only for elements)\n--     text     = \"raw text\" (for text/comment/cdata/doctype nodes)\n--     children = { child1, child2, ... } or nil (for elements or document nodes)\n--     prolog   = { comment/doctypes before root } or nil (only on root element)\n-- }\n--\n-- Quick start:\n--   local doc = assert(xml.decode([[\n--     <?xml version=\"1.0\"?><root id=\"1\"><item id=\"foo\">hello</item></root>\n--   ]]))\n--   local item = assert(xml.find(doc, \"//item[@id='foo']\"))\n--   item.attrs.lang = \"en\"                    -- mutate attributes directly\n--   item.children = {xml.text(\"world\")}       -- replace children with new nodes\n--   table.insert(doc.children, xml.comment(\"generated by xmake\"))\n--   table.insert(doc.children, xml.new({name = \"extra\", children = {xml.text(\"42\")}}))\n--   local pretty = assert(xml.encode(doc, {pretty = true}))\n--   -- save or reuse `pretty`\n--\n-- Streaming example (no full DOM in memory):\n--   xml.scan(xml_text, function(node)\n--       if node.name == \"item\" then\n--           print(\"item payload:\", xml.text_of(node))\n--           if xml.text_of(node) == \"stop\" then\n--               return false -- early terminate\n--           end\n--       end\n--   end)\n--\n\n-- decode entities\nfunction xml._decode_entities(str)\n    return (str:gsub(\"&lt;\", \"<\")\n               :gsub(\"&gt;\", \">\")\n               :gsub(\"&apos;\", \"'\")\n               :gsub(\"&quot;\", \"\\\"\")\n               :gsub(\"&amp;\", \"&\"))\nend\n\n-- encode raw text for xml element content\nfunction xml._encode_text(str)\n    return (str:gsub(\"&\", \"&amp;\")\n               :gsub(\"<\", \"&lt;\")\n               :gsub(\">\", \"&gt;\"))\nend\n\n-- encode attribute value for xml output\nfunction xml._encode_attr(str)\n    return xml._encode_text(str):gsub(\"\\\"\", \"&quot;\")\nend\n\n-- parse attribute string to table (or nil if empty)\nfunction xml._parse_attrs(attrstr)\n    local attrs\n    local i, len = 1, #attrstr\n    while i <= len do\n        local key, value_start = attrstr:match(\"^%s*([%w_:%-%.]+)%s*=%s*()\", i)\n        if not key then\n            break\n        end\n        local value\n        local first_char = attrstr:sub(value_start, value_start)\n        if first_char == \"\\\"\" or first_char == \"'\" then\n            local closing = attrstr:find(first_char, value_start + 1, true)\n            if not closing then\n                break\n            end\n            value = attrstr:sub(value_start + 1, closing - 1)\n            i = closing + 1\n        else\n            local j = value_start\n            while j <= len do\n                local ch = attrstr:sub(j, j)\n                if ch:match(\"%s\") or ch == \">\" or (ch == \"/\" and attrstr:sub(j + 1, j + 1) == \">\") then\n                    break\n                end\n                j = j + 1\n            end\n            value = attrstr:sub(value_start, j - 1)\n            i = j\n        end\n        attrs = attrs or {}\n        attrs[key] = xml._decode_entities(value)\n    end\n    return attrs\nend\n\n-- iterate element children and optional prolog nodes\nfunction xml._each_child(node, callback)\n    if not node or not callback then\n        return\n    end\n    if node.children then\n        for _, child in ipairs(node.children) do\n            callback(child)\n        end\n    end\n    if node.prolog then\n        for _, child in ipairs(node.prolog) do\n            callback(child)\n        end\n    end\nend\n\n-- collect descendants that match predicate\nfunction xml._collect_descendants(node, matcher, results)\n    results = results or {}\n    xml._each_child(node, function(child)\n        if matcher(child) then\n            table.insert(results, child)\n        end\n        xml._collect_descendants(child, matcher, results)\n    end)\n    return results\nend\n\n-- parse xpath expression into steps\nfunction xml._parse_xpath(path)\n    local steps = {}\n    local len = #path\n    local i = 1\n    local first = true\n    while i <= len do\n        local axis\n        if path:sub(i, i + 1) == \"//\" then\n            axis = \"descendant\"\n            i = i + 2\n        elseif path:sub(i, i) == \"/\" then\n            axis = \"child\"\n            i = i + 1\n        elseif first then\n            axis = \"self\"\n        else\n            axis = \"child\"\n        end\n        while path:sub(i, i) == \"/\" do\n            if path:sub(i, i + 1) == \"//\" then\n                axis = \"descendant\"\n                i = i + 2\n            else\n                axis = \"child\"\n                i = i + 1\n            end\n        end\n        if i > len then\n            break\n        end\n        local start = i\n        local depth = 0\n        while i <= len do\n            local ch = path:sub(i, i)\n            if ch == \"[\" then\n                depth = depth + 1\n            elseif ch == \"]\" then\n                depth = depth - 1\n            elseif ch == \"/\" and depth == 0 then\n                break\n            end\n            i = i + 1\n        end\n        local segment = path:sub(start, i - 1):trim()\n        if segment ~= \"\" then\n            local step = xml._parse_xpath_segment(segment, axis)\n            table.insert(steps, step)\n        end\n        first = false\n    end\n    return steps\nend\n\n-- parse a single xpath step\nfunction xml._parse_xpath_segment(segment, axis)\n    local step = {axis = axis or \"child\", predicates = {}}\n    local name = segment:gsub(\"%b[]\", \"\")\n    name = name:trim()\n    if name == \"\" or name == \"*\" then\n        step.node_test = \"any\"\n    elseif name == \".\" then\n        step.node_test = \"self\"\n    elseif name == \"text()\" then\n        step.node_test = \"text\"\n    elseif name == \"comment()\" then\n        step.node_test = \"comment\"\n    elseif name == \"cdata()\" then\n        step.node_test = \"cdata\"\n    elseif name == \"doctype()\" then\n        step.node_test = \"doctype\"\n    else\n        step.node_test = \"name\"\n        step.name = name\n    end\n    for predicate in segment:gmatch(\"%b[]\") do\n        local expr = predicate:sub(2, -2):trim()\n        if expr ~= \"\" then\n            local number_index = tonumber(expr)\n            if number_index then\n                step.indexes = step.indexes or {}\n                table.insert(step.indexes, number_index)\n            else\n                local attr_key, quote, attr_value = expr:match(\"^@([%w_:%-%.]+)%s*=%s*(['\\\"])(.-)%2$\")\n                if attr_key then\n                    table.insert(step.predicates, {type = \"attr\", key = attr_key, value = attr_value})\n                else\n                    local attr_exists = expr:match(\"^@([%w_:%-%.]+)%s*$\")\n                    if attr_exists then\n                        table.insert(step.predicates, {type = \"attr_exists\", key = attr_exists})\n                    else\n                        local text_value = expr:match(\"^text%(%s*%)%s*=%s*\\\"(.-)\\\"$\")\n                        if not text_value then\n                            text_value = expr:match(\"^text%(%s*%)%s*=%s*'(.-)'$\")\n                        end\n                        if text_value then\n                            table.insert(step.predicates, {type = \"text\", value = text_value})\n                        else\n                            step.unsupported = true\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return step\nend\n\n-- check whether node matches xpath step\nfunction xml._match_xpath_node(node, step)\n    if step.unsupported then\n        return false\n    end\n    local nodetype = step.node_test or \"name\"\n    if nodetype == \"self\" then\n        -- always match, predicates will refine\n    elseif nodetype == \"any\" then\n        -- match every node\n    elseif nodetype == \"node\" then\n        -- unused for now\n    elseif nodetype == \"text\" then\n        if node.kind ~= \"text\" then\n            return false\n        end\n    elseif nodetype == \"comment\" then\n        if node.kind ~= \"comment\" then\n            return false\n        end\n    elseif nodetype == \"cdata\" then\n        if node.kind ~= \"cdata\" then\n            return false\n        end\n    elseif nodetype == \"doctype\" then\n        if node.kind ~= \"doctype\" then\n            return false\n        end\n    else\n        if node.kind ~= \"element\" then\n            return false\n        end\n        if step.name and step.name ~= \"*\" and node.name ~= step.name then\n            return false\n        end\n    end\n    if step.predicates then\n        for _, predicate in ipairs(step.predicates) do\n            if predicate.type == \"attr\" then\n                if not node.attrs or node.attrs[predicate.key] ~= predicate.value then\n                    return false\n                end\n            elseif predicate.type == \"attr_exists\" then\n                if not node.attrs or node.attrs[predicate.key] == nil then\n                    return false\n                end\n            elseif predicate.type == \"text\" then\n                if xml.text_of(node) ~= predicate.value then\n                    return false\n                end\n            end\n        end\n    end\n    return true\nend\n\n-- apply positional predicates\nfunction xml._apply_xpath_indexes(nodes, indexes)\n    if not indexes or #indexes == 0 then\n        return nodes\n    end\n    local current = nodes\n    for _, index in ipairs(indexes) do\n        local selected = current[index]\n        if not selected then\n            return {}\n        end\n        current = {selected}\n    end\n    return current\nend\n\n-- append normalized text node to top element on stack\nfunction xml._append_text(stack, text, opt)\n    opt = opt or {}\n    if opt.trim_text then\n        text = string.trim(text)\n    end\n    if text == \"\" then\n        return\n    end\n    if not opt.keep_whitespace_nodes and text:match(\"^%s*$\") then\n        return\n    end\n    local top = stack[#stack]\n    top.children = top.children or {}\n    table.insert(top.children, xml.text(xml._decode_entities(text)))\nend\n\n-- ensure closing tag matches stack and pop it\nfunction xml._handle_closing(stack, tagname)\n    local top = stack[#stack]\n    if not top or top.name ~= tagname then\n        return nil, string.format(\"malformed xml: unexpected closing </%s>\", tagname)\n    end\n    table.remove(stack)\n    return top\nend\n\n-- compute indent string for pretty output\nfunction xml._indent(opt, level)\n    if not opt.pretty then\n        return \"\"\n    end\n    local indent = opt.indent or 4\n    local indentchar = opt.indentchar or \" \"\n    if type(indent) == \"number\" then\n        return string.rep(indentchar, indent * level)\n    end\n    return indent:rep(level)\nend\n\nfunction xml._encode_node(node, opt, level)\n    opt = opt or {}\n    level = level or 0\n    if node.kind == \"document\" then\n        local parts = {}\n        if node.children then\n            for _, child in ipairs(node.children) do\n                table.insert(parts, xml._encode_node(child, opt, level))\n            end\n        end\n        return table.concat(parts, opt.pretty and \"\\n\" or \"\")\n    elseif node.kind == \"text\" then\n        local indent = xml._indent(opt, level)\n        local text = xml._encode_text(tostring(node.text or \"\"))\n        if opt.pretty then\n            return indent .. text\n        end\n        return text\n    elseif node.kind == \"comment\" then\n        return xml._indent(opt, level) .. string.format(\"<!--%s-->\", tostring(node.text or \"\"))\n    elseif node.kind == \"cdata\" then\n        return xml._indent(opt, level) .. string.format(\"<![CDATA[%s]]>\", tostring(node.text or \"\"))\n    elseif node.kind == \"doctype\" then\n        return xml._indent(opt, level) .. string.format(\"<!DOCTYPE %s>\", tostring(node.text or \"\"))\n    end\n    local attrs = {}\n    for k, v in pairs(node.attrs or {}) do\n        table.insert(attrs, string.format('%s=\"%s\"', k, xml._encode_attr(tostring(v))))\n    end\n    table.sort(attrs)\n    local open = \"<\" .. node.name\n    if #attrs > 0 then\n        open = open .. \" \" .. table.concat(attrs, \" \")\n    end\n    if not node.children or #node.children == 0 then\n        return xml._indent(opt, level) .. open .. \"/>\"\n    end\n    local newline = opt.pretty and \"\\n\" or \"\"\n    if #node.children == 1 and node.children[1].kind == \"text\" then\n        local text = xml._encode_text(tostring(node.children[1].text or \"\"))\n        return string.format(\"%s%s>%s</%s>\", xml._indent(opt, level), open, text, node.name)\n    end\n    local result = {}\n    table.insert(result, xml._indent(opt, level) .. open .. \">\")\n    if node.children then\n        for _, child in ipairs(node.children) do\n            table.insert(result, xml._encode_node(child, opt, level + 1))\n        end\n    end\n    table.insert(result, xml._indent(opt, level) .. \"</\" .. node.name .. \">\")\n    return table.concat(result, newline ~= \"\" and newline or \"\")\nend\n\n-- create an xml element node\n-- e.g. `local node = xml.new({name = \"item\", attrs = {id = \"1\"}, children = {xml.text(\"value\")}})`\n--\n-- @param opt    table with name/attrs/children/kind/text fields\n-- @return       node table\n--\nfunction xml.new(opt)\n    opt = opt or {}\n    return {\n        name = opt.name,\n        attrs = opt.attrs,\n        kind = opt.kind or \"element\",\n        text = opt.text,\n        children = opt.children\n    }\nend\n\n-- create a text node\n-- e.g. `local textnode = xml.text(\"hello\")`\n--\n-- @param value  string content\n-- @return       text node\n--\nfunction xml.text(value)\n    return xml.new({kind = \"text\", text = value or \"\"})\nend\n\n-- create an empty element node\n-- e.g. `local br = xml.empty(\"br\", {class = \"line\"})`\n--\n-- @param name   element name\n-- @param attrs  attribute table\n-- @return       element node\n--\nfunction xml.empty(name, attrs)\n    return xml.new({name = name, attrs = attrs})\nend\n\n-- create a comment node\n-- e.g. `local comment = xml.comment(\"generated by xmake\")`\n--\n-- @param value  comment text\n-- @return       comment node\n--\nfunction xml.comment(value)\n    return xml.new({kind = \"comment\", text = value or \"\"})\nend\n\n-- create a cdata node\n-- e.g. `local cdata = xml.cdata(\"if (a < b) { ... }\")`\n--\n-- @param value  cdata text\n-- @return       cdata node\n--\nfunction xml.cdata(value)\n    return xml.new({kind = \"cdata\", text = value or \"\"})\nend\n\n-- create a doctype node\n-- e.g. `local doc = xml.doctype('html')`\n--\n-- @param value  doctype payload\n-- @return       doctype node\n--\nfunction xml.doctype(value)\n    return xml.new({kind = \"doctype\", text = value or \"\"})\nend\n\n-- decode xml string to tree node(s)\n-- e.g. `local doc, err = xml.decode(\"<root><item>foo</item></root>\")`\n--\n-- @param data   xml string\n-- @param opt    options (e.g. {trim_text = true} to strip leading/trailing text, keep_whitespace_nodes = true)\n-- @return       root node or list on success, nil + error on failure\n--\nfunction xml.decode(data, opt)\n    opt = opt or {}\n    local root_children = {}\n    local doc_node = {kind = \"document\", children = root_children}\n    local stack = {doc_node}\n    local function ensure_children(node)\n        if not node.children then\n            if node == doc_node then\n                node.children = root_children\n            else\n                node.children = {}\n            end\n        end\n        return node.children\n    end\n    local i = 1\n    local len = #data\n    while i <= len do\n        local lt = data:find(\"<\", i, true)\n        if not lt then\n            local text = data:sub(i)\n            xml._append_text(stack, text, opt)\n            break\n        end\n        if lt > i then\n            local text = data:sub(i, lt - 1)\n            xml._append_text(stack, text, opt)\n        end\n        if data:sub(lt + 1, lt + 3) == \"!--\" then\n            local close = data:find(\"-->\", lt + 4, true)\n            if not close then\n                return nil, \"unterminated xml comment\"\n            end\n            local value = data:sub(lt + 4, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            table.insert(children, xml.comment(value))\n            i = close + 3\n        elseif data:sub(lt + 1, lt + 8) == \"![CDATA[\" then\n            local close = data:find(\"]]>\", lt + 9, true)\n            if not close then\n                return nil, \"unterminated cdata section\"\n            end\n            local value = data:sub(lt + 9, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            table.insert(children, xml.cdata(value))\n            i = close + 3\n        elseif data:sub(lt + 1, lt + 8):upper() == \"!DOCTYPE\" then\n            local close = data:find(\">\", lt + 8, true)\n            if not close then\n                return nil, \"unterminated doctype declaration\"\n            end\n            local value = data:sub(lt + 9, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            table.insert(children, xml.doctype(value))\n            i = close + 1\n        elseif data:sub(lt + 1, lt + 1) == \"?\" then\n            local close = data:find(\"?>\", lt + 2, true)\n            if not close then\n                return nil, \"unterminated xml declaration\"\n            end\n            i = close + 2\n        elseif data:sub(lt + 1, lt + 1) == \"!\" then\n            local close = data:find(\">\", lt + 2, true)\n            if not close then\n                return nil, \"unterminated xml declaration\"\n            end\n            i = close + 1\n        elseif data:sub(lt + 1, lt + 1) == \"/\" then\n            local close = data:find(\">\", lt + 1, true)\n            if not close then\n                return nil, \"unterminated closing tag\"\n            end\n            local tagname = data:sub(lt + 2, close - 1):match(\"^%s*([^%s>]+)\")\n            local node, err = xml._handle_closing(stack, tagname)\n            if not node then\n                return nil, err\n            end\n            i = close + 1\n        else\n            local close = data:find(\">\", lt + 1, true)\n            if not close then\n                return nil, \"unterminated opening tag\"\n            end\n            local inside = data:sub(lt + 1, close - 1)\n            local selfclose = inside:find(\"/%s*$\")\n            if selfclose then\n                inside = inside:gsub(\"/%s*$\", \"\")\n            end\n            local tagname, attrstr = inside:match(\"^%s*([^%s>]+)%s*(.-)%s*$\")\n            local attrs = xml._parse_attrs(attrstr or \"\")\n            local node = xml.empty(tagname, attrs)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            table.insert(children, node)\n            if not selfclose then\n                table.insert(stack, node)\n            end\n            i = close + 1\n        end\n    end\n    if #stack ~= 1 then\n        return nil, \"malformed xml: unclosed tags\"\n    end\n    local element_nodes = {}\n    for _, child in ipairs(root_children) do\n        if child.kind == \"element\" then\n            table.insert(element_nodes, child)\n        end\n    end\n    if #element_nodes == 1 then\n        local rootnode = element_nodes[1]\n        local prolog = {}\n        for _, child in ipairs(root_children) do\n            if child ~= rootnode then\n                if not (child.kind == \"text\" and (child.text or \"\"):match(\"^%s*$\")) then\n                    table.insert(prolog, child)\n                end\n            end\n        end\n        if #prolog > 0 then\n            rootnode.prolog = prolog\n        end\n        return rootnode\n    end\n    return root_children\nend\n\n-- stream parse xml data\n--\n-- @param data        xml string\n-- @param callback    function(node) -> true|false (return false to stop scanning)\n-- @param opt         options (e.g. {trim_text = true}, {keep_whitespace_nodes = true})\n-- @return            true on success or nil, error on failure\n--\nfunction xml.scan(data, callback, opt)\n    opt = opt or {}\n    local root_children = {}\n    local doc_node = {kind = \"document\", children = root_children}\n    local stack = {doc_node}\n    local stop = false\n    local function ensure_children(node)\n        if not node.children then\n            if node == doc_node then\n                node.children = root_children\n            else\n                node.children = {}\n            end\n        end\n        return node.children\n    end\n    local function emit(node)\n        if callback and node.kind ~= \"document\" then\n            if callback(node) == false then\n                stop = true\n            end\n        end\n    end\n    local i = 1\n    local len = #data\n    while i <= len do\n        if stop then\n            break\n        end\n        local lt = data:find(\"<\", i, true)\n        if not lt then\n            local text = data:sub(i)\n            xml._append_text(stack, text, opt)\n            break\n        end\n        if lt > i then\n            local text = data:sub(i, lt - 1)\n            xml._append_text(stack, text, opt)\n        end\n        if data:sub(lt + 1, lt + 3) == \"!--\" then\n            local close = data:find(\"-->\", lt + 4, true)\n            if not close then\n                return nil, \"unterminated xml comment\"\n            end\n            local value = data:sub(lt + 4, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            local node = xml.comment(value)\n            table.insert(children, node)\n            emit(node)\n            i = close + 3\n        elseif data:sub(lt + 1, lt + 8) == \"![CDATA[\" then\n            local close = data:find(\"]]>\", lt + 9, true)\n            if not close then\n                return nil, \"unterminated cdata section\"\n            end\n            local value = data:sub(lt + 9, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            local node = xml.cdata(value)\n            table.insert(children, node)\n            emit(node)\n            i = close + 3\n        elseif data:sub(lt + 1, lt + 8):upper() == \"!DOCTYPE\" then\n            local close = data:find(\">\", lt + 8, true)\n            if not close then\n                return nil, \"unterminated doctype declaration\"\n            end\n            local value = data:sub(lt + 9, close - 1)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            local node = xml.doctype(value)\n            table.insert(children, node)\n            emit(node)\n            i = close + 1\n        elseif data:sub(lt + 1, lt + 1) == \"?\" then\n            local close = data:find(\"?>\", lt + 2, true)\n            if not close then\n                return nil, \"unterminated xml declaration\"\n            end\n            i = close + 2\n        elseif data:sub(lt + 1, lt + 1) == \"!\" then\n            local close = data:find(\">\", lt + 2, true)\n            if not close then\n                return nil, \"unterminated xml declaration\"\n            end\n            i = close + 1\n        elseif data:sub(lt + 1, lt + 1) == \"/\" then\n            local close = data:find(\">\", lt + 1, true)\n            if not close then\n                return nil, \"unterminated closing tag\"\n            end\n            local tagname = data:sub(lt + 2, close - 1):match(\"^%s*([^%s>]+)\")\n            local node, err = xml._handle_closing(stack, tagname)\n            if not node then\n                return nil, err\n            end\n            emit(node)\n            i = close + 1\n        else\n            local close = data:find(\">\", lt + 1, true)\n            if not close then\n                return nil, \"unterminated opening tag\"\n            end\n            local inside = data:sub(lt + 1, close - 1)\n            local selfclose = inside:find(\"/%s*$\")\n            if selfclose then\n                inside = inside:gsub(\"/%s*$\", \"\")\n            end\n            local tagname, attrstr = inside:match(\"^%s*([^%s>]+)%s*(.-)%s*$\")\n            local attrs = xml._parse_attrs(attrstr or \"\")\n            local node = xml.empty(tagname, attrs)\n            local top = stack[#stack]\n            local children = ensure_children(top)\n            table.insert(children, node)\n            if not selfclose then\n                table.insert(stack, node)\n            else\n                emit(node)\n            end\n            i = close + 1\n        end\n    end\n    return true\nend\n\n-- encode xml node to string\n-- e.g. `local xmlstr = xml.encode(node, {pretty = true, indent = 2})`\n--\n-- @param node   xml node\n-- @param opt    options (pretty, indent, etc.)\n-- @return       xml string or nil, err\n--\nfunction xml.encode(node, opt)\n    opt = opt or {}\n    local fragments = {}\n    local prolog = node.prolog\n    if prolog then\n        for _, child in ipairs(prolog) do\n            table.insert(fragments, xml._encode_node(child, opt, 0))\n            if opt.pretty then\n                table.insert(fragments, \"\\n\")\n            end\n        end\n    end\n    table.insert(fragments, xml._encode_node(node, opt, 0))\n    return table.concat(fragments)\nend\n\n-- load xml file\n-- e.g. `local doc, err = xml.loadfile(\"foo.xml\")`\n--\n-- @param filepath  file path\n-- @param opt       read/decode options\n-- @return          node or nil + error\n--\nfunction xml.loadfile(filepath, opt)\n    local data, err = io.readfile(filepath, opt)\n    if not data then\n        return nil, err\n    end\n    return xml.decode(data, opt)\nend\n\n-- save xml node to file\n-- e.g. `assert(xml.savefile(\"foo.xml\", node, {pretty = true}))`\n--\n-- @param filepath  destination file\n-- @param node      xml node\n-- @param opt       encode/write options\n-- @return          true on success or nil + error message\n--\nfunction xml.savefile(filepath, node, opt)\n    local data = xml.encode(node, opt)\n    if not data then\n        return nil, \"failed to encode xml\"\n    end\n    return io.writefile(filepath, data, opt)\nend\n\n-- find the first matching node with an XPath-like expression\n-- e.g. `xml.find(doc, \"//dict/key[@name='CFBundleName']\")`\n--\n-- Supported syntax:\n--   - `/` child axis, `//` descendant-or-self axis\n--   - `*`, `text()`, `comment()`, `cdata()`, `doctype()`, `.`\n--   - Attribute predicates: `[@id='foo']`, `[@enabled]`\n--   - Text predicate: `[text()='value']`\n--   - Positional predicate: `[2]`\n--\n-- @param node   root node\n-- @param path   xpath-like string\n-- @return       first matched node or nil\n--\nfunction xml.find(node, path)\n    if not node or not path or path == \"\" then\n        return nil\n    end\n    local steps = xml._parse_xpath(path)\n    if #steps == 0 then\n        return nil\n    end\n    local current\n    if path:sub(1, 1) == \"/\" then\n        current = {{kind = \"document\", children = {node}}}\n    else\n        current = {node}\n    end\n    for _, step in ipairs(steps) do\n        local matches = {}\n        if step.axis == \"self\" then\n            for _, candidate in ipairs(current) do\n                if xml._match_xpath_node(candidate, step) then\n                    table.insert(matches, candidate)\n                end\n            end\n        elseif step.axis == \"child\" then\n            for _, parent in ipairs(current) do\n                xml._each_child(parent, function(child)\n                    if xml._match_xpath_node(child, step) then\n                        table.insert(matches, child)\n                    end\n                end)\n            end\n        elseif step.axis == \"descendant\" then\n            for _, parent in ipairs(current) do\n                if xml._match_xpath_node(parent, step) then\n                    table.insert(matches, parent)\n                end\n                xml._collect_descendants(parent, function(desc)\n                    return xml._match_xpath_node(desc, step)\n                end, matches)\n            end\n        else\n            return nil\n        end\n        matches = xml._apply_xpath_indexes(matches, step.indexes)\n        if #matches == 0 then\n            return nil\n        end\n        current = matches\n    end\n    return current[1]\nend\n\n-- get concatenated text from child nodes\n-- e.g. `local text = xml.text_of(xml.decode(\"<item>foo</item>\"))`\n--\n-- @param node   xml node\n-- @return       concatenated string\n--\nfunction xml.text_of(node)\n    if not node or not node.children then\n        return \"\"\n    end\n    local buffer = {}\n    for _, child in ipairs(node.children) do\n        if child.kind == \"text\" then\n            table.insert(buffer, child.text or \"\")\n        end\n    end\n    return table.concat(buffer, \"\")\nend\n\nreturn xml\n\n"
  },
  {
    "path": "xmake/core/cache/detectcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        detectcache.lua\n--\n\nreturn require(\"cache/localcache\").cache(\"detect\")\n\n"
  },
  {
    "path": "xmake/core/cache/global_detectcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        global_detectcache.lua\n--\n\nreturn require(\"cache/globalcache\").cache(\"detect\")\n\n"
  },
  {
    "path": "xmake/core/cache/globalcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        globalcache.lua\n--\n\n-- define module: globalcache\nlocal globalcache  = globalcache or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal table   = require(\"base/table\")\nlocal io      = require(\"base/io\")\nlocal os      = require(\"base/os\")\nlocal path    = require(\"base/path\")\nlocal global  = require(\"base/global\")\n\n-- new an instance\nfunction _instance.new(name)\n    local instance = table.inherit(_instance)\n    instance._NAME = name\n    instance:load()\n    instance._DATA = instance._DATA or {}\n    return instance\nend\n\n-- get cache name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get cache data\nfunction _instance:data()\n    return self._DATA\nend\n\n-- load cache\nfunction _instance:load()\n    local result = io.load(path.join(global.cachedir(), self:name()))\n    if result ~= nil then\n        self._DATA = result\n    end\nend\n\n-- save cache\nfunction _instance:save()\n    local ok, errors = io.save(path.join(global.cachedir(), self:name()), self._DATA)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- get cache value in level/1\nfunction _instance:get(key)\n    return self._DATA[key]\nend\n\n-- get cache value in level/2\nfunction _instance:get2(key1, key2)\n    local value1 = self:get(key1)\n    if value1 ~= nil then\n        return value1[key2]\n    end\nend\n\n-- get cache value in level/3\nfunction _instance:get3(key1, key2, key3)\n    local value2 = self:get2(key1)\n    if value2 ~= nil then\n        return value2[key3]\n    end\nend\n\n-- set cache value in level/1\nfunction _instance:set(key, value)\n    self._DATA[key] = value\nend\n\n-- set cache value in level/2\nfunction _instance:set2(key1, key2, value2)\n    local value1 = self:get(key1)\n    if value1 == nil then\n        value1 = {}\n        self:set(key1, value1)\n    end\n    value1[key2] = value2\nend\n\n-- set cache value in level/3\nfunction _instance:set3(key1, key2, key3, value3)\n    local value2 = self:get2(key1, key2)\n    if value2 == nil then\n        value2 = {}\n        self:set2(key1, key2, value2)\n    end\n    value2[key3] = value3\nend\n\n-- clear cache scopes\nfunction _instance:clear()\n    self._DATA = {}\nend\n\n-- get cache instance\nfunction globalcache.cache(cachename)\n    local caches = globalcache._CACHES\n    if not caches then\n        caches = {}\n        globalcache._CACHES = caches\n    end\n    local instance = caches[cachename]\n    if not instance then\n        instance = _instance.new(cachename)\n        caches[cachename] = instance\n    end\n    return instance\nend\n\n-- get all caches\nfunction globalcache.caches(opt)\n    opt = opt or {}\n    if opt.flush then\n        for _, cachefile in ipairs(os.files(path.join(global.cachedir(), \"*\"))) do\n            local cachename = path.filename(cachefile)\n            globalcache.cache(cachename)\n        end\n    end\n    return globalcache._CACHES\nend\n\n-- get cache value in level/1\nfunction globalcache.get(cachename, key)\n    return globalcache.cache(cachename):get(key)\nend\n\n-- get cache value in level/2\nfunction globalcache.get2(cachename, key1, key2)\n    return globalcache.cache(cachename):get2(key1, key2)\nend\n\n-- get cache value in level/3\nfunction globalcache.get3(cachename, key1, key2, key3)\n    return globalcache.cache(cachename):get3(key1, key2, key3)\nend\n\n-- set cache value in level/1\nfunction globalcache.set(cachename, key, value)\n    return globalcache.cache(cachename):set(key, value)\nend\n\n-- set cache value in level/2\nfunction globalcache.set2(cachename, key1, key2, value)\n    return globalcache.cache(cachename):set2(key1, key2, value)\nend\n\n-- set cache value in level/3\nfunction globalcache.set3(cachename, key1, key2, key3, value)\n    return globalcache.cache(cachename):set3(key1, key2, key3, value)\nend\n\n-- save the given cache, it will save all caches if cache name is nil\nfunction globalcache.save(cachename)\n    if cachename then\n        globalcache.cache(cachename):save()\n    else\n        local caches = globalcache.caches()\n        if caches then\n            for _, cache in pairs(caches) do\n                cache:save()\n            end\n        end\n    end\nend\n\n-- clear the given cache, it will clear all caches if cache name is nil\nfunction globalcache.clear(cachename)\n    if cachename then\n        globalcache.cache(cachename):clear()\n    else\n        local caches = globalcache.caches({flush = true})\n        if caches then\n            for _, cache in pairs(caches) do\n                cache:clear()\n            end\n        end\n    end\nend\n\n-- return module: globalcache\nreturn globalcache\n\n\n"
  },
  {
    "path": "xmake/core/cache/localcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        localcache.lua\n--\n\n-- define module: localcache\nlocal localcache  = localcache or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal table   = require(\"base/table\")\nlocal io      = require(\"base/io\")\nlocal os      = require(\"base/os\")\nlocal path    = require(\"base/path\")\nlocal config  = require(\"project/config\")\n\n-- new an instance\nfunction _instance.new(name)\n    local instance = table.inherit(_instance)\n    instance._NAME = name\n    instance:load()\n    instance._DATA = instance._DATA or {}\n    return instance\nend\n\n-- get cache name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get cache data\nfunction _instance:data()\n    return self._DATA\nend\n\n-- load cache\nfunction _instance:load()\n    if os.isfile(os.projectfile()) or os.isdir(config.directory()) then\n        local result = io.load(path.join(config.cachedir(), self:name()))\n        if result ~= nil then\n            self._DATA = result\n        end\n    end\nend\n\n-- save cache\nfunction _instance:save()\n    -- for xmake project or trybuild mode\n    if os.isfile(os.projectfile()) or os.isdir(config.directory()) then\n        local ok, errors = io.save(path.join(config.cachedir(), self:name()), self._DATA)\n        if not ok then\n            os.raise(errors)\n        end\n    end\nend\n\n-- get cache value in level/1\nfunction _instance:get(key)\n    return self._DATA[key]\nend\n\n-- get cache value in level/2\nfunction _instance:get2(key1, key2)\n    local value1 = self:get(key1)\n    if value1 ~= nil then\n        return value1[key2]\n    end\nend\n\n-- get cache value in level/3\nfunction _instance:get3(key1, key2, key3)\n    local value2 = self:get2(key1, key2)\n    if value2 ~= nil then\n        return value2[key3]\n    end\nend\n\n-- set cache value in level/1\nfunction _instance:set(key, value)\n    self._DATA[key] = value\nend\n\n-- set cache value in level/2\nfunction _instance:set2(key1, key2, value2)\n    local value1 = self:get(key1)\n    if value1 == nil then\n        value1 = {}\n        self:set(key1, value1)\n    end\n    value1[key2] = value2\nend\n\n-- set cache value in level/3\nfunction _instance:set3(key1, key2, key3, value3)\n    local value2 = self:get2(key1, key2)\n    if value2 == nil then\n        value2 = {}\n        self:set2(key1, key2, value2)\n    end\n    value2[key3] = value3\nend\n\n-- clear cache scopes\nfunction _instance:clear()\n    self._DATA = {}\nend\n\n-- get cache instance\nfunction localcache.cache(cachename)\n    local caches = localcache._CACHES\n    if not caches then\n        caches = {}\n        localcache._CACHES = caches\n    end\n    local instance = caches[cachename]\n    if not instance then\n        instance = _instance.new(cachename)\n        caches[cachename] = instance\n    end\n    return instance\nend\n\n-- get all caches\nfunction localcache.caches(opt)\n    opt = opt or {}\n    if opt.flush then\n        for _, cachefile in ipairs(os.files(path.join(config.cachedir(), \"*\"))) do\n            local cachename = path.filename(cachefile)\n            localcache.cache(cachename)\n        end\n    end\n    return localcache._CACHES\nend\n\n-- get cache value in level/1\nfunction localcache.get(cachename, key)\n    return localcache.cache(cachename):get(key)\nend\n\n-- get cache value in level/2\nfunction localcache.get2(cachename, key1, key2)\n    return localcache.cache(cachename):get2(key1, key2)\nend\n\n-- get cache value in level/3\nfunction localcache.get3(cachename, key1, key2, key3)\n    return localcache.cache(cachename):get3(key1, key2, key3)\nend\n\n-- set cache value in level/1\nfunction localcache.set(cachename, key, value)\n    return localcache.cache(cachename):set(key, value)\nend\n\n-- set cache value in level/2\nfunction localcache.set2(cachename, key1, key2, value)\n    return localcache.cache(cachename):set2(key1, key2, value)\nend\n\n-- set cache value in level/3\nfunction localcache.set3(cachename, key1, key2, key3, value)\n    return localcache.cache(cachename):set3(key1, key2, key3, value)\nend\n\n-- save the given cache, it will save all caches if cache name is nil\nfunction localcache.save(cachename)\n    if cachename then\n        localcache.cache(cachename):save()\n    else\n        local caches = localcache.caches()\n        if caches then\n            for _, cache in pairs(caches) do\n                cache:save()\n            end\n        end\n    end\nend\n\n-- clear the given cache, it will clear all caches if cache name is nil\nfunction localcache.clear(cachename)\n    if cachename then\n        localcache.cache(cachename):clear()\n    else\n        local caches = localcache.caches({flush = true})\n        if caches then\n            for _, cache in pairs(caches) do\n                cache:clear()\n            end\n        end\n    end\nend\n\n-- return module: localcache\nreturn localcache\n\n"
  },
  {
    "path": "xmake/core/cache/memcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        memcache.lua\n--\n\n-- define module: memcache\nlocal memcache  = memcache or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal table = require(\"base/table\")\n\n-- new an instance\nfunction _instance.new(name)\n    local instance = table.inherit(_instance)\n    instance._NAME = name\n    instance._DATA = {}\n    return instance\nend\n\n-- get cache name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get cache data\nfunction _instance:data()\n    return self._DATA\nend\n\n-- get cache value in level/1\nfunction _instance:get(key)\n    return self._DATA[key]\nend\n\n-- get cache value in level/2\nfunction _instance:get2(key1, key2)\n    local value1 = self:get(key1)\n    if value1 ~= nil then\n        return value1[key2]\n    end\nend\n\n-- get cache value in level/3\nfunction _instance:get3(key1, key2, key3)\n    local value2 = self:get2(key1, key2)\n    if value2 ~= nil then\n        return value2[key3]\n    end\nend\n\n-- set cache value in level/1\nfunction _instance:set(key, value)\n    self._DATA[key] = value\nend\n\n-- set cache value in level/2\nfunction _instance:set2(key1, key2, value2)\n    local value1 = self:get(key1)\n    if value1 == nil then\n        value1 = {}\n        self:set(key1, value1)\n    end\n    value1[key2] = value2\nend\n\n-- set cache value in level/3\nfunction _instance:set3(key1, key2, key3, value3)\n    local value2 = self:get2(key1, key2)\n    if value2 == nil then\n        value2 = {}\n        self:set2(key1, key2, value2)\n    end\n    value2[key3] = value3\nend\n\n-- clear cache scopes\nfunction _instance:clear()\n    self._DATA = {}\nend\n\n-- get cache instance\nfunction memcache.cache(cachename)\n    local caches = memcache._CACHES\n    if not caches then\n        caches = {}\n        memcache._CACHES = caches\n    end\n    local instance = caches[cachename]\n    if not instance then\n        instance = _instance.new(cachename)\n        caches[cachename] = instance\n    end\n    return instance\nend\n\n-- get all caches\nfunction memcache.caches()\n    return memcache._CACHES\nend\n\n-- get cache value in level/1\nfunction memcache.get(cachename, key)\n    return memcache.cache(cachename):get(key)\nend\n\n-- get cache value in level/2\nfunction memcache.get2(cachename, key1, key2)\n    return memcache.cache(cachename):get2(key1, key2)\nend\n\n-- get cache value in level/3\nfunction memcache.get3(cachename, key1, key2, key3)\n    return memcache.cache(cachename):get3(key1, key2, key3)\nend\n\n-- set cache value in level/1\nfunction memcache.set(cachename, key, value)\n    return memcache.cache(cachename):set(key, value)\nend\n\n-- set cache value in level/2\nfunction memcache.set2(cachename, key1, key2, value)\n    return memcache.cache(cachename):set2(key1, key2, value)\nend\n\n-- set cache value in level/3\nfunction memcache.set3(cachename, key1, key2, key3, value)\n    return memcache.cache(cachename):set3(key1, key2, key3, value)\nend\n\n-- clear the given cache, it will clear all caches if cache name is nil\nfunction memcache.clear(cachename)\n    local caches = memcache.caches()\n    if caches then\n        for _, cache in pairs(caches) do\n            if cachename then\n                if cache:name() == cachename then\n                    cache:clear()\n                end\n            else\n                cache:clear()\n            end\n        end\n    end\nend\n\n-- return module: memcache\nreturn memcache\n"
  },
  {
    "path": "xmake/core/compress/lz4.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lz4.lua\n--\n\n-- define module: lz4\nlocal lz4 = lz4 or {}\nlocal _cstream = _cstream or {}\nlocal _dstream = _dstream or {}\n\n-- load modules\nlocal io    = require(\"base/io\")\nlocal utils = require(\"base/utils\")\nlocal bytes = require(\"base/bytes\")\nlocal table = require(\"base/table\")\n\n-- save metatable and builtin functions\nlz4._compress                = lz4._compress or lz4.compress\nlz4._decompress              = lz4._decompress or lz4.decompress\nlz4._block_compress          = lz4._block_compress or lz4.block_compress\nlz4._block_decompress        = lz4._block_decompress or lz4.block_decompress\nlz4._compress_file           = lz4._compress_file or lz4.compress_file\nlz4._decompress_file         = lz4._decompress_file or lz4.decompress_file\nlz4._compress_stream_open    = lz4._compress_stream_open or lz4.compress_stream_open\nlz4._compress_stream_read    = lz4._compress_stream_read or lz4.compress_stream_read\nlz4._compress_stream_write   = lz4._compress_stream_write or lz4.compress_stream_write\nlz4._compress_stream_close   = lz4._compress_stream_close or lz4.compress_stream_close\nlz4._decompress_stream_open  = lz4._decompress_stream_open or lz4.decompress_stream_open\nlz4._decompress_stream_read  = lz4._decompress_stream_read or lz4.decompress_stream_read\nlz4._decompress_stream_write = lz4._decompress_stream_write or lz4.decompress_stream_write\nlz4._decompress_stream_close = lz4._decompress_stream_close or lz4.decompress_stream_close\n\n-- new a compress stream\nfunction _cstream.new(handle)\n    local instance   = table.inherit(_cstream)\n    instance._HANDLE = handle\n    setmetatable(instance, _cstream)\n    return instance\nend\n\n-- get cdata of stream\nfunction _cstream:cdata()\n    return self._HANDLE\nend\n\n-- read data from stream\nfunction _cstream:read(buff, size, opt)\n    assert(buff)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- check buffer\n    size = size or buff:size()\n    if buff:size() < size then\n        return -1, string.format(\"%s: too small buffer!\", self)\n    end\n\n    -- check size\n    if size == 0 then\n        return 0\n    elseif size == nil or size < 0 then\n        return -1, string.format(\"%s: invalid size(%d)!\", self, size)\n    end\n\n    -- init start in buffer\n    opt = opt or {}\n    local start = opt.start or 1\n    local pos = start - 1\n    if start >= buff:size() or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n\n    -- read it\n    local read, data_or_errors = lz4._compress_stream_read(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n    if read > 0 then\n        data_or_errors = buff:slice(start, read)\n    end\n    if read < 0 and data_or_errors then\n        data_or_errors = string.format(\"%s: %s\", self, data_or_errors)\n    end\n    return read, data_or_errors\nend\n\n-- write data to stream\nfunction _cstream:write(data, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- get data address and size for bytes and string\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or datasize\n    if start < 1 or start > datasize then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > datasize + start - 1 then\n        return -1, string.format(\"%s: invalid last(%d)!\", self, last)\n    end\n\n    -- write it\n    local errors = nil\n    local write, errors = lz4._compress_stream_write(self:cdata(), dataaddr + start - 1, last + 1 - start, opt.beof)\n    if write < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return write, errors\nend\n\n-- ensure it is opened\nfunction _cstream:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(stream)\nfunction _cstream:__tostring()\n    return string.format(\"<lz4/cstream: %s>\", self:cdata())\nend\n\n-- gc(stream)\nfunction _cstream:__gc()\n    if self:cdata() and lz4._compress_stream_close(self:cdata()) then\n        self._HANDLE = nil\n    end\nend\n\n-- new a decompress stream\nfunction _dstream.new(handle)\n    local instance   = table.inherit(_dstream)\n    instance._HANDLE = handle\n    setmetatable(instance, _dstream)\n    return instance\nend\n\n-- get cdata of stream\nfunction _dstream:cdata()\n    return self._HANDLE\nend\n\n-- read data from stream\nfunction _dstream:read(buff, size, opt)\n    assert(buff)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- check buffer\n    size = size or buff:size()\n    if buff:size() < size then\n        return -1, string.format(\"%s: too small buffer!\", self)\n    end\n\n    -- check size\n    if size == 0 then\n        return 0\n    elseif size == nil or size < 0 then\n        return -1, string.format(\"%s: invalid size(%d)!\", self, size)\n    end\n\n    -- init start in buffer\n    opt = opt or {}\n    local start = opt.start or 1\n    local pos = start - 1\n    if start >= buff:size() or start < 1 then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n\n    -- read it\n    local read, data_or_errors = lz4._decompress_stream_read(self:cdata(), buff:caddr() + pos, math.min(buff:size() - pos, size))\n    if read > 0 then\n        data_or_errors = buff:slice(start, read)\n    end\n    if read < 0 and data_or_errors then\n        data_or_errors = string.format(\"%s: %s\", self, data_or_errors)\n    end\n    return read, data_or_errors\nend\n\n-- write data to stream\nfunction _dstream:write(data, opt)\n\n    -- ensure opened\n    local ok, errors = self:_ensure_opened()\n    if not ok then\n        return -1, errors\n    end\n\n    -- get data address and size for bytes and string\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n\n    -- init start and last\n    opt = opt or {}\n    local start = opt.start or 1\n    local last = opt.last or datasize\n    if start < 1 or start > datasize then\n        return -1, string.format(\"%s: invalid start(%d)!\", self, start)\n    end\n    if last < start - 1 or last > datasize + start - 1 then\n        return -1, string.format(\"%s: invalid last(%d)!\", self, last)\n    end\n\n    -- write it\n    local errors = nil\n    local write, errors = lz4._decompress_stream_write(self:cdata(), dataaddr + start - 1, last + 1 - start, opt.beof)\n    if write < 0 and errors then\n        errors = string.format(\"%s: %s\", self, errors)\n    end\n    return write, errors\nend\n\n-- ensure it is opened\nfunction _dstream:_ensure_opened()\n    if not self:cdata() then\n        return false, string.format(\"%s: has been closed!\", self)\n    end\n    return true\nend\n\n-- tostring(stream)\nfunction _dstream:__tostring()\n    return string.format(\"<lz4/dstream: %s>\", self:cdata())\nend\n\n-- gc(stream)\nfunction _dstream:__gc()\n    if self:cdata() and lz4._decompress_stream_close(self:cdata()) then\n        self._HANDLE = nil\n    end\nend\n\n-- open a compress stream\nfunction lz4.compress_stream(opt)\n    local handle, errors = lz4._compress_stream_open()\n    if handle then\n        return _cstream.new(handle)\n    else\n        return nil, errors or \"failed to open compress stream!\"\n    end\nend\n\n-- open a decompress stream\nfunction lz4.decompress_stream(opt)\n    local handle, errors = lz4._decompress_stream_open()\n    if handle then\n        return _dstream.new(handle)\n    else\n        return nil, errors or \"failed to open decompress stream!\"\n    end\nend\n\n-- compress frame data\n--\n-- @param data          the data\n-- @param opt           the options\n--\n-- @return              the result data\n--\nfunction lz4.compress(data, opt)\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    local result, errors = lz4._compress(dataaddr, datasize)\n    if not result then\n        return nil, errors or string.format(\"compress frame data failed, %s\", errors or \"unknown\")\n    end\n    return bytes(result)\nend\n\n-- decompres frame data\n--\n-- @param data          the data\n-- @param opt           the options\n--\n-- @return              the result data\n--\nfunction lz4.decompress(data, opt)\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    local result, errors = lz4._decompress(dataaddr, datasize)\n    if not result then\n        return nil, string.format(\"decompress frame data failed, %s\", errors or \"unknown\")\n    end\n    return bytes(result)\nend\n\n-- compress file data\nfunction lz4.compress_file(srcpath, dstpath, opt)\n    local ok, errors = lz4._compress_file(tostring(srcpath), tostring(dstpath))\n    if not ok then\n        errors = string.format(\"compress file %s failed!\", srcpath, errors or os.strerror() or \"unknown\")\n    end\n    return ok, errors\nend\n\n-- decompress file data\nfunction lz4.decompress_file(srcpath, dstpath, opt)\n    local ok, errors = lz4._decompress_file(tostring(srcpath), tostring(dstpath))\n    if not ok then\n        errors = string.format(\"decompress file %s failed!\", srcpath, errors or os.strerror() or \"unknown\")\n    end\n    return ok, errors\nend\n\n-- compress block data\n--\n-- @param data          the data\n-- @param opt           the options\n--\n-- @return              the result data\n--\nfunction lz4.block_compress(data, opt)\n    if type(data) == \"string\" then\n        data = bytes(data)\n    end\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    local result, errors = lz4._block_compress(dataaddr, datasize)\n    if not result then\n        return nil, errors or string.format(\"compress block data failed, %s\", errors or \"unknown\")\n    end\n    return bytes(result)\nend\n\n-- decompres block data\n--\n-- @param data          the data\n-- @param realsize      the decompressed real size\n-- @param opt           the options\n--\n-- @return              the result data\n--\nfunction lz4.block_decompress(data, realsize, opt)\n    local datasize = data:size()\n    local dataaddr = data:caddr()\n    local result, errors = lz4._block_decompress(dataaddr, datasize, realsize)\n    if not result then\n        return nil, string.format(\"decompress block data failed, %s\", errors or \"unknown\")\n    end\n    return bytes(result)\nend\n\n-- return module: lz4\nreturn lz4\n"
  },
  {
    "path": "xmake/core/language/language.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        language.lua\n--\n\n-- define module\nlocal language      = language or {}\nlocal _instance     = _instance or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal utils         = require(\"base/utils\")\nlocal table         = require(\"base/table\")\nlocal interpreter   = require(\"base/interpreter\")\nlocal sandbox       = require(\"sandbox/sandbox\")\nlocal config        = require(\"project/config\")\nlocal global        = require(\"base/global\")\n\n-- new an instance\nfunction _instance.new(name, info, rootdir)\n    local instance    = table.inherit(_instance)\n    instance._NAME    = name\n    instance._INFO    = info\n    instance._ROOTDIR = rootdir\n    return instance\nend\n\n-- get the language configure\nfunction _instance:get(name)\n    local info = self._INFO:info()\n    local value = info[name]\n    if value ~= nil then\n        return value\n    end\n\n    if self._g == nil and info.load ~= nil then\n        local ok, results = sandbox.load(info.load)\n        if not ok then\n            os.raise(results)\n        end\n        self._g = results\n    end\n    return self._g[name]\nend\n\n-- get the language menu\nfunction _instance:menu()\n    return self._INFO:get(\"menu\")\nend\n\n-- get the language name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the source extensions\nfunction _instance:extensions()\n    if self._EXTENSIONS then\n        return self._EXTENSIONS\n    end\n\n    -- get extensions\n    local extensions = {}\n    for sourcekind, exts in pairs(self:sourcekinds()) do\n        for _, extension in ipairs(table.wrap(exts)) do\n            extensions[extension:lower()] = sourcekind\n        end\n    end\n\n    self._EXTENSIONS = extensions\n    return extensions\nend\n\n-- get the rules\nfunction _instance:rules()\n    return self._INFO:get(\"rules\")\nend\n\n-- get the source kinds\nfunction _instance:sourcekinds()\n    return self._INFO:get(\"sourcekinds\")\nend\n\n-- get the source flags\nfunction _instance:sourceflags()\n    return self._INFO:get(\"sourceflags\")\nend\n\n-- get the target kinds (targetkind => linkerkind)\n--\n-- e.g.\n-- {binary = \"ld\", static = \"ar\", shared = \"sh\"}\n--\nfunction _instance:kinds()\n    return self._INFO:get(\"targetkinds\")\nend\n\n-- get the target flags (targetkind => linkerflag)\n--\n-- e.g.\n-- {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n--\nfunction _instance:targetflags()\n    return self._INFO:get(\"targetflags\")\nend\n\n-- get the mixing kinds for linker\n--\n-- e.g.\n-- {\"cc\", \"cxx\"}\n--\nfunction _instance:mixingkinds()\n    return self._INFO:get(\"mixingkinds\")\nend\n\n-- get the language kinds\nfunction _instance:langkinds()\n    return self._INFO:get(\"langkinds\")\nend\n\n-- get the name flags\nfunction _instance:nameflags()\n\n    -- attempt to get it from cache first\n    if self._NAMEFLAGS then\n        return self._NAMEFLAGS\n    end\n\n    -- get nameflags\n    local results = {}\n    for targetkind, nameflags in pairs(table.wrap(self._INFO:get(\"nameflags\"))) do\n\n        -- make tool info\n        local toolinfo = results[targetkind] or {}\n        for _, namedflag in ipairs(nameflags) do\n\n            -- split it by '.'\n            local splitinfo = namedflag:split('.', {plain = true})\n            assert(#splitinfo == 2)\n\n            -- get flag scope\n            local flagscope = splitinfo[1]\n            assert(flagscope)\n\n            -- get flag info\n            local flaginfo = splitinfo[2]:split(':')\n\n            -- get flag name\n            local flagname = flaginfo[1]\n            assert(flagname)\n\n            -- get check state\n            local checkstate = false\n            if #flaginfo == 2 and flaginfo[2] == \"check\" then\n                checkstate = true\n            end\n\n            -- insert this flag info\n            table.insert(toolinfo, {flagscope, flagname, checkstate})\n        end\n\n        -- save this tool info\n        results[targetkind] = toolinfo\n    end\n\n    -- cache this results\n    self._NAMEFLAGS = results\n    return results\nend\n\n-- the directory of language\nfunction language._directory()\n    return path.join(os.programdir(), \"languages\")\nend\n\n-- the interpreter\nfunction language._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if language._INTERPRETER then\n        return language._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define\n    {\n        values =\n        {\n            -- language.set_xxx\n            \"language.set_mixingkinds\"\n            -- language.add_xxx\n        ,   \"language.add_rules\"\n        }\n    ,   script =\n        {\n            -- language.on_xxx\n            \"language.on_load\"\n        ,   \"language.on_check_main\"\n        }\n    ,   dictionary =\n        {\n            -- language.set_xxx\n            \"language.set_menu\"\n        ,   \"language.set_nameflags\"\n        ,   \"language.set_langkinds\"\n        ,   \"language.set_sourcekinds\"\n        ,   \"language.set_sourceflags\"\n        ,   \"language.set_targetkinds\"\n        ,   \"language.set_targetflags\"\n        }\n    }\n    language._INTERPRETER = interp\n    return interp\nend\n\n-- load the language from the given name (c++, objc++, swift, golang, asm, ...)\nfunction language.load(name)\n\n    -- load all languages\n    if not name then\n        if not language._LANGUAGES then\n            for _, name in ipairs(table.wrap(os.dirs(path.join(language._directory(), \"*\")))) do\n                local instance, errors = language.load(path.basename(name))\n                if not instance then\n                    return nil, errors\n                end\n            end\n        end\n        return language._LANGUAGES\n    end\n\n    -- get it directly from cache dirst\n    language._LANGUAGES = language._LANGUAGES or {}\n    if language._LANGUAGES[name] then\n        return language._LANGUAGES[name]\n    end\n\n    -- find the language script path\n    local scriptpath = path.join(path.join(language._directory(), name), \"xmake.lua\")\n    if not os.isfile(scriptpath) then\n        return nil, string.format(\"the language %s not found!\", name)\n    end\n\n    -- not exists?\n    if not scriptpath or not os.isfile(scriptpath) then\n        return nil, string.format(\"the language %s not found!\", name)\n    end\n\n    -- get interpreter\n    local interp = language._interpreter()\n\n    -- load script\n    local ok, errors = interp:load(scriptpath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load language\n    local results, errors = interp:make(\"language\", true, false)\n    if not results and os.isfile(scriptpath) then\n        return nil, errors\n    end\n\n    -- check the language name\n    if not results[name] then\n        return nil, string.format(\"the language %s not found!\", name)\n    end\n\n    -- new an instance\n    local instance, errors = _instance.new(name, results[name], language._interpreter():rootdir())\n    if not instance then\n        return nil, errors\n    end\n    language._LANGUAGES[name] = instance\n    return instance\nend\n\n-- load the language from the given source kind: cc, cxx, mm, mxx, sc, gc, as ..\nfunction language.load_sk(sourcekind)\n\n    -- load all languages\n    local languages, errors = language.load()\n    if not languages then\n        return nil, errors\n    end\n\n    -- make source kind as lower\n    sourcekind = sourcekind:lower()\n\n    -- get it directly from cache dirst\n    language._LANGUAGES_OF_SK = language._LANGUAGES_OF_SK or {}\n    if language._LANGUAGES_OF_SK[sourcekind] then\n        return language._LANGUAGES_OF_SK[sourcekind]\n    end\n\n    -- find language instance\n    local result = nil\n    for _, instance in pairs(languages) do\n        if instance:sourcekinds()[sourcekind] ~= nil then\n            result = instance\n            break\n        end\n    end\n    if not result then\n        return nil, string.format(\"unknown language sourcekind: %s\", sourcekind)\n    end\n    language._LANGUAGES_OF_SK[sourcekind] = result\n    return result\nend\n\n-- load the language from the given source extension: .c, .cpp, .m, .mm, .swift, .go, .s ..\nfunction language.load_ex(extension)\n\n    -- load all languages\n    local languages, errors = language.load()\n    if not languages then\n        return nil, errors\n    end\n\n    -- make source extension as lower\n    extension = extension:lower()\n\n    -- get it directly from cache dirst\n    language._LANGUAGES_OF_EX = language._LANGUAGES_OF_EX or {}\n    if language._LANGUAGES_OF_EX[extension] then\n        return language._LANGUAGES_OF_EX[extension]\n    end\n\n    -- find language instance\n    local result = nil\n    for _, instance in pairs(languages) do\n        if instance:extensions()[extension] ~= nil then\n            result = instance\n            break\n        end\n    end\n    if not result then\n        return nil, string.format(\"unknown language source extension: %s\", extension)\n    end\n    language._LANGUAGES_OF_EX[extension] = result\n    return result\nend\n\n\n-- load the language apis\nfunction language.apis()\n    local apis = language._APIS\n    if not apis then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        apis = {values = {}, groups = {}, paths = {}, custom = {}, dictionary = {}}\n        for name, instance in pairs(languages) do\n            local instance_apis = instance:get(\"apis\")\n            if instance_apis then\n                table.join2(apis.values,     table.wrap(instance_apis.values))\n                table.join2(apis.groups,     table.wrap(instance_apis.groups))\n                table.join2(apis.paths,      table.wrap(instance_apis.paths))\n                table.join2(apis.custom,     table.wrap(instance_apis.custom))\n                table.join2(apis.dictionary, table.wrap(instance_apis.dictionary))\n            end\n        end\n        apis.values = table.unique(apis.values)\n        apis.groups = table.unique(apis.groups)\n        apis.paths  = table.unique(apis.paths)\n        apis.custom = table.unique(apis.custom)\n        language._APIS = apis\n    end\n    return apis\nend\n\n-- get language source extensions\n--\n-- e.g.\n--\n-- {\n--      [\".c\"]      = cc\n-- ,    [\".cc\"]     = cxx\n-- ,    [\".cpp\"]    = cxx\n-- ,    [\".m\"]      = mm\n-- ,    [\".mm\"]     = mxx\n-- ,    [\".swift\"]  = sc\n-- ,    [\".go\"]     = gc\n-- }\n--\nfunction language.extensions()\n    local extensions = language._EXTENSIONS\n    if not extensions then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        extensions = {}\n        for name, instance in pairs(languages) do\n            table.join2(extensions, instance:extensions())\n        end\n        language._EXTENSIONS = extensions\n    end\n    return extensions\nend\n\n-- get language source kinds\n--\n-- e.g.\n--\n-- {\n--      cc  = \".c\"\n-- ,    cxx = {\".cc\", \".cpp\", \".cxx\"}\n-- ,    mm  = \".m\"\n-- ,    mxx = \".mm\"\n-- ,    sc  = \".swift\"\n-- ,    gc  = \".go\"\n-- }\n--\nfunction language.sourcekinds()\n    local sourcekinds = language._SOURCEKINDS\n    if not sourcekinds then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        sourcekinds = {}\n        for name, instance in pairs(languages) do\n            table.join2(sourcekinds, instance:sourcekinds())\n        end\n        language._SOURCEKINDS = sourcekinds\n    end\n    return sourcekinds\nend\n\n-- get language source flags\n--\n-- e.g.\n--\n-- {\n--      cc  = {\"cflags\", \"cxflags\"}\n-- ,    cxx = {\"cxxflags\", \"cxflags\"}\n-- ,    ...\n-- }\n--\nfunction language.sourceflags()\n    local sourceflags = language._SOURCEFLAGS\n    if not sourceflags then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        sourceflags = {}\n        for name, instance in pairs(languages) do\n            table.join2(sourceflags, instance:sourceflags())\n        end\n        language._SOURCEFLAGS = sourceflags\n    end\n    return sourceflags\nend\n\n-- get source kind of the source file name\nfunction language.sourcekind_of(sourcefile)\n\n    -- get the source file extension\n    local extension = path.extension(sourcefile)\n    if not extension then\n        return nil, string.format(\"%s has not extension\", sourcefile)\n    end\n\n    -- get extensions\n    local extensions = language.extensions()\n\n    -- get source kind from extension\n    local sourcekind = extensions[extension:lower()]\n    if not sourcekind then\n        return nil, string.format(\"%s is unknown extension\", extension)\n    end\n    return sourcekind\nend\n\n-- get extension of the source kind\nfunction language.extension_of(sourcekind)\n    local extension = table.wrap(language.sourcekinds()[sourcekind])[1]\n    if not extension then\n        return nil, string.format(\"%s is unknown source kind\", sourcekind)\n    end\n    return extension\nend\n\n-- get linker infos(kind and flag) of the target kind and the source kinds\nfunction language.linkerinfos_of(targetkind, sourcekinds)\n\n    -- load linkerinfos\n    local linkerinfos = language._LINKERINFOS\n    if not linkerinfos then\n\n        -- load all languages\n        local languages, errors = language.load()\n        if not languages then\n            return nil, errors\n        end\n\n        -- make linker infos\n        linkerinfos = {}\n        for name, instance in pairs(languages) do\n            for _, mixingkind in ipairs(table.wrap(instance:mixingkinds())) do\n                local targetflags = instance:targetflags()\n                for _targetkind, linkerkind in pairs(table.wrap(instance:kinds())) do\n\n                    -- init linker info\n                    linkerinfos[_targetkind] = linkerinfos[_targetkind] or {}\n                    linkerinfos[_targetkind][linkerkind] = linkerinfos[_targetkind][linkerkind] or {}\n                    local linkerinfo = linkerinfos[_targetkind][linkerkind]\n\n                    -- sve linker info\n                    local linkerflag = targetflags[_targetkind]\n                    linkerinfo.linkerkind = linkerkind\n                    if linkerflag then\n                        linkerinfo.linkerflag = linkerflag\n                    end\n                    linkerinfo.mixingkinds = linkerinfo.mixingkinds or {}\n                    linkerinfo.mixingkinds[mixingkind] = 1\n                    linkerinfo.sourcecount = (linkerinfo.sourcecount or 0) + 1\n                end\n            end\n        end\n        language._LINKERINFOS = linkerinfos\n    end\n\n    -- find suitable linkers\n    local results = {}\n    for _, linkerinfo in pairs(table.wrap(linkerinfos[targetkind])) do\n\n        -- match all source kinds?\n        local count = 0\n        for _, sourcekind in ipairs(sourcekinds) do\n            count = count + (linkerinfo.mixingkinds[sourcekind] or 0)\n        end\n        if count == #sourcekinds then\n            table.insert(results, linkerinfo)\n        end\n    end\n    if #results > 0 then\n        -- sort it by most matches\n        table.sort(results, function(a, b) return a.sourcecount > b.sourcecount end)\n        return results\n    end\n\n    -- not suitable linker\n    return nil, string.format(\"no suitable linker for %s.{%s}\", targetkind, table.concat(sourcekinds, ' '))\nend\n\n-- get language target kinds\n--\n-- e.g.\n--\n-- {\n--      binary = {\"ld\", \"gcld\", \"dcld\"}\n-- ,    static = {\"ar\", \"gcar\", \"dcar\"}\n-- ,    shared = {\"sh\", \"dcsh\"}\n-- }\n--\nfunction language.targetkinds()\n    local targetkinds = language._TARGETKINDS\n    if not targetkinds then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        targetkinds = {}\n        for name, instance in pairs(languages) do\n            for targetkind, linkerkind in pairs(table.wrap(instance:kinds())) do\n                targetkinds[targetkind] = targetkinds[targetkind] or {}\n                table.insert(targetkinds[targetkind], linkerkind)\n            end\n        end\n        for targetkind, linkerkinds in pairs(targetkinds) do\n            targetkinds[targetkind] = table.unique(linkerkinds)\n        end\n        language._TARGETKINDS = targetkinds\n    end\n    return targetkinds\nend\n\n-- get language kinds (langkind => sourcekind)\n--\n-- e.g.\n--\n-- {\n--      c           = \"cc\"\n-- ,    cxx         = \"cxx\"\n-- ,    m           = \"mm\"\n-- ,    mxx         = \"mxx\"\n-- ,    swift       = \"sc\"\n-- ,    go          = \"gc\"\n-- ,    as          = \"as\"\n-- ,    rust        = \"rc\"\n-- ,    d           = \"dc\"\n-- }\n--\nfunction language.langkinds()\n    local langkinds = language._LANGKINDS\n    if not langkinds then\n        local languages, errors = language.load()\n        if not languages then\n            os.raise(errors)\n        end\n        langkinds = {}\n        for name, instance in pairs(languages) do\n            table.join2(langkinds, instance:langkinds())\n        end\n        language._LANGKINDS = langkinds\n    end\n    return langkinds\nend\n\nreturn language\n"
  },
  {
    "path": "xmake/core/language/menu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menu.lua\n--\n\n-- define module\nlocal menu          = menu or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal utils         = require(\"base/utils\")\nlocal table         = require(\"base/table\")\nlocal language      = require(\"language/language\")\n\n-- get the option menu for action: xmake config or global\nfunction menu.options(action)\n\n    -- check\n    assert(action)\n\n    -- load all languages\n    local languages, errors = language.load()\n    if not languages then\n        os.raise(errors)\n    end\n\n    -- load and merge all language options\n    local exist     = {}\n    local results   = {}\n    for _, instance in pairs(languages) do\n\n        -- get menu\n        local menu = instance:menu()\n        if menu then\n\n            -- get the options for this action\n            local options = menu[action]\n            if options then\n\n                -- get the language option\n                for _, option in ipairs(options) do\n\n                    -- merge it and remove repeat\n                    local name = option[2] or option[1]\n                    if name then\n                        if not exist[name] then\n                            table.insert(results, option)\n                            exist[name] = true\n                        end\n                    else\n                        table.insert(results, option)\n                    end\n                end\n            end\n        end\n    end\n\n    -- ok?\n    return results\nend\n\n-- return module\nreturn menu\n"
  },
  {
    "path": "xmake/core/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- define module: main\nlocal main = main or {}\n\n-- load modules\nlocal env           = require(\"base/compat/env\")\nlocal os            = require(\"base/os\")\nlocal log           = require(\"base/log\")\nlocal path          = require(\"base/path\")\nlocal utils         = require(\"base/utils\")\nlocal option        = require(\"base/option\")\nlocal table         = require(\"base/table\")\nlocal global        = require(\"base/global\")\nlocal privilege     = require(\"base/privilege\")\nlocal task          = require(\"base/task\")\nlocal colors        = require(\"base/colors\")\nlocal process       = require(\"base/process\")\nlocal scheduler     = require(\"base/scheduler\")\nlocal theme         = require(\"theme/theme\")\nlocal config        = require(\"project/config\")\nlocal project       = require(\"project/project\")\nlocal localcache    = require(\"cache/localcache\")\nlocal profiler      = require(\"base/profiler\")\nlocal debugger      = require(\"base/debugger\")\nlocal thread        = require(\"base/thread\")\n\n-- init the option menu\nlocal menu =\n{\n    title = \"${bright}xmake v\" .. _VERSION .. \", A cross-platform build utility based on \" .. (xmake._LUAJIT and \"LuaJIT\" or \"Lua\") .. \"${clear}\"\n,   copyright = \"Copyright (C) 2015-present Ruki Wang, ${underline}https://xmake.io${clear}\"\n\n    -- the tasks: xmake [task]\n,   function ()\n        local tasks = task.tasks() or {}\n        if xmake.in_main_thread() then\n            local ok, project_tasks = pcall(project.tasks)\n            if ok then\n                table.join2(tasks, project_tasks)\n            end\n        end\n        return task.menu(tasks)\n    end\n\n}\n\n-- show help and version info\nfunction main._show_help()\n    if option.get(\"help\") then\n        option.show_menu(option.taskname())\n        return true\n    elseif option.get(\"version\") and not option.taskname() then\n        if menu.title then\n            utils.cprint(menu.title)\n        end\n        if menu.copyright then\n            utils.cprint(menu.copyright)\n        end\n        option.show_logo()\n        return true\n    end\nend\n\n-- find the root project file\nfunction main._find_root(projectfile)\n\n    -- make all parent directories\n    local dirs = {}\n    local dir = path.directory(projectfile)\n    while os.isdir(dir) do\n        table.insert(dirs, 1, dir)\n        local parentdir = path.directory(dir)\n        if parentdir and parentdir ~= dir and parentdir ~= '.' then\n            dir = parentdir\n        else\n            break\n        end\n    end\n\n    -- find the first `xmake.lua` from it's parent directory\n    for _, dir in ipairs(dirs) do\n        local file = path.join(dir, \"xmake.lua\")\n        if os.isfile(file) then\n           return file\n        end\n    end\n    return projectfile\nend\n\n-- get project directory and project file from the argument option\n--\n-- @note we need to put `-P` in the first argument avoid option.parse() parsing errors\n-- e.g. `xmake f -c -P xxx` will be parsed as `-c=-P`, it's incorrect.\n--\n-- @see https://github.com/xmake-io/xmake/issues/4857\n--\nfunction main._basicparse()\n\n    -- check command\n    if xmake._ARGV[1] and not xmake._ARGV[1]:startswith('-') then\n        -- regard it as command name\n        xmake._COMMAND = xmake._ARGV[1]\n        xmake._COMMAND_ARGV = table.move(xmake._ARGV, 2, #xmake._ARGV, 1, table.new(#xmake._ARGV - 1, 0))\n    else\n        xmake._COMMAND_ARGV = xmake._ARGV\n    end\n\n    -- parse options, only parse -P xxx/-F xxx/--project=xxx/--file=xxx\n    local options = {}\n    local argv = xmake._COMMAND_ARGV\n    local idx = 1\n    while idx <= #argv do\n        local arg = argv[idx]\n        if arg == \"-P\" and idx < #argv then\n            options.project = argv[idx + 1]\n            idx = idx + 1\n        elseif arg == \"-F\" and idx < #argv then\n            options.file = argv[idx + 1]\n            idx = idx + 1\n        elseif arg:startswith(\"--project=\") then\n            options.project = arg:sub(11)\n        elseif arg:startswith(\"--file=\") then\n            options.file = arg:sub(8)\n        end\n        idx = idx + 1\n        if options.project and options.file then\n            break\n        end\n    end\n    return options\nend\n\n-- get the project configuration from cache if we are in the independent working directory\n-- @see https://github.com/xmake-io/xmake/issues/3342\n--\nfunction main._projectconf(name)\n    local rootdir = os.getenv(\"XMAKE_CONFIGDIR\")\n    -- we switch to independent working directory\n    -- @see https://github.com/xmake-io/xmake/issues/820\n    if not rootdir and os.isdir(path.join(os.workingdir(), \".\" .. xmake._NAME)) then\n        rootdir = os.workingdir()\n    end\n    local cachefile = path.join(rootdir, \".\" .. xmake._NAME, os.host(), os.arch(), \"cache\", \"project\")\n    if os.isfile(cachefile) then\n        local cacheinfo = io.load(cachefile)\n        if cacheinfo then\n            return cacheinfo[name]\n        end\n    end\nend\n\n-- the init function for main\nfunction main._init()\n\n    -- start debugger\n    if debugger:enabled() then\n        local ok, errors = debugger:start()\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- disable scheduler first\n    scheduler:enable(false)\n\n    -- get project directory and project file from the argument option\n    local options, errors = main._basicparse()\n    if not options then\n        return false, errors\n    end\n\n    -- init project paths only for xmake engine\n    if xmake._NAME == \"xmake\" then\n        local opt_projectdir, opt_projectfile = options.project, options.file\n\n        -- init the project directory\n        local projectdir = opt_projectdir or main._projectconf(\"projectdir\") or xmake._PROJECT_DIR\n        if projectdir and not path.is_absolute(projectdir) then\n            projectdir = path.absolute(projectdir)\n        elseif projectdir then\n            projectdir = path.translate(projectdir)\n        end\n        xmake._PROJECT_DIR = projectdir\n        assert(projectdir)\n\n        -- init the xmake.lua file path\n        local projectfile = opt_projectfile or main._projectconf(\"projectfile\") or xmake._PROJECT_FILE\n        if projectfile and not path.is_absolute(projectfile) then\n            projectfile = path.absolute(projectfile, projectdir)\n        end\n        xmake._PROJECT_FILE = projectfile\n        assert(projectfile)\n\n        -- find the root project file\n        if not os.isfile(projectfile) or (not opt_projectdir and not opt_projectfile) then\n            projectfile = main._find_root(projectfile)\n        end\n\n        -- update and enter project\n        xmake._PROJECT_DIR  = path.directory(projectfile)\n        xmake._PROJECT_FILE = projectfile\n\n        -- enter the project directory\n        if os.isdir(os.projectdir()) and xmake.in_main_thread() then\n            os.cd(os.projectdir())\n        end\n    else\n        -- patch a fake project file and directory for other lua programs with xmake/engine\n        xmake._PROJECT_DIR  = path.join(os.tmpdir(), \"local\")\n        xmake._PROJECT_FILE = path.join(xmake._PROJECT_DIR, xmake._NAME .. \".lua\")\n    end\n    return true\nend\n\n-- exit main program\nfunction main._exit(ok, errors)\n\n    -- run all exit callbacks\n    os._run_exit_cbs(ok, errors)\n\n    -- show errors\n    local retval = 0\n    if not ok then\n        retval = -1\n        if errors then\n            utils.error(errors)\n        end\n    end\n\n    -- show warnings\n    utils.show_warnings()\n\n    -- close log\n    log:close()\n\n    -- return exit code\n    return retval\nend\n\n-- limit root? @see https://github.com/xmake-io/xmake/pull/4513\nfunction main._limit_root()\n    return not option.get(\"root\") and os.getenv(\"XMAKE_ROOT\") ~= 'y' and os.host() ~= 'haiku'\nend\n\n-- run task\nfunction main._run_task(taskname)\n    local taskinst = task.task(taskname) or project.task(taskname)\n    if not taskinst then\n        return false, string.format(\"do unknown task(%s)!\", taskname)\n    end\n\n    scheduler:co_start_named(\"xmake \" .. taskname, function ()\n        local ok, errors = taskinst:run()\n        if not ok then\n            os.raise(errors)\n        end\n    end)\n    return true\nend\n\n-- the main entry function\nfunction main.entry()\n\n    -- init\n    local ok, errors = main._init()\n    if not ok then\n        return main._exit(ok, errors)\n    end\n\n    -- load global configuration\n    ok, errors = global.load()\n    if not ok then\n        return main._exit(ok, errors)\n    end\n\n    -- load theme\n    local theme_inst = theme.load(os.getenv(\"XMAKE_THEME\") or global.get(\"theme\")) or theme.load(\"default\")\n    if theme_inst then\n        colors.theme_set(theme_inst)\n    end\n\n    -- init option\n    ok, errors = option.init(menu)\n    if not ok then\n        return main._exit(ok, errors)\n    end\n\n    if xmake.in_main_thread() then\n\n        -- check run command as root\n        if main._limit_root() then\n            if os.isroot() then\n                errors = [[Running xmake as root is extremely dangerous and no longer supported.\n    As xmake does not drop privileges on installation you would be giving all\n    build scripts full access to your system.\n    Or you can add `--root` option or XMAKE_ROOT=y to allow run as root temporarily.\n                ]]\n                return main._exit(false, errors)\n            end\n        end\n\n        -- show help?\n        if main._show_help() then\n            return main._exit(true)\n        end\n\n        -- save command lines to history and we need to make sure that the .xmake directory is not generated everywhere\n        local skip_history = (os.getenv('XMAKE_SKIP_HISTORY') or ''):trim()\n        if os.projectfile() and os.isfile(os.projectfile()) and os.isdir(config.directory()) and skip_history == '' then\n            local cmdlines = table.wrap(localcache.get(\"history\", \"cmdlines\"))\n            if #cmdlines > 64 then\n                table.remove(cmdlines, 1)\n            end\n            table.insert(cmdlines, option.cmdline())\n            localcache.set(\"history\", \"cmdlines\", cmdlines)\n            localcache.save(\"history\")\n        end\n    end\n\n    -- enable scheduler\n    scheduler:enable(true)\n\n    -- run task or thread\n    local thread_callback = xmake._THREAD_CALLBACK\n    if thread_callback then\n        ok, errors = thread._run_thread(thread_callback, xmake._THREAD_CALLINFO)\n    else\n        ok, errors = main._run_task(option.taskname() or \"build\")\n    end\n    if not ok then\n        return main._exit(ok, errors)\n    end\n\n    -- start runloop\n    ok, errors = scheduler:runloop()\n    if not ok then\n        return main._exit(ok, errors)\n    end\n\n    -- stop profiling\n    if profiler:enabled() then\n        profiler:stop()\n    end\n\n    -- exit normally\n    return main._exit(true)\nend\n\n-- return module: main\nreturn main\n\n"
  },
  {
    "path": "xmake/core/package/component.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        component.lua\n--\n\n-- define module\nlocal component = component or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal io             = require(\"base/io\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal option         = require(\"base/option\")\nlocal hashset        = require(\"base/hashset\")\nlocal scopeinfo      = require(\"base/scopeinfo\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal language       = require(\"language/language\")\nlocal sandbox        = require(\"sandbox/sandbox\")\n\n-- new an instance\nfunction _instance.new(name, opt)\n    opt = opt or {}\n    local instance = table.inherit(_instance)\n    instance._NAME    = name\n    instance._INFO    = scopeinfo.new(\"component\", {}, {interpreter = component._interpreter()})\n    instance._PACKAGE = opt.package\n    return instance\nend\n\n-- get the component name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the type: component\nfunction _instance:type()\n    return \"component\"\nend\n\n-- get the it's package\nfunction _instance:package()\n    return self._PACKAGE\nend\n\n-- get the component configuration\nfunction _instance:get(name)\n    return self._INFO:get(name)\nend\n\n-- set the value to the component info\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\nend\n\n-- add the value to the component info\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    local conf = self._INFO:extraconf(name, item, key)\n    if conf == nil then\n        conf = self:package():extraconf(name, item, key)\n    end\n    return conf\nend\n\n-- set the extra configuration\nfunction _instance:extraconf_set(name, item, key, value)\n    return self._INFO:extraconf_set(name, item, key, value)\nend\n\n-- get on_component script\nfunction _instance:_on_component()\n    local script = self:package():get(\"component\")\n    local result = nil\n    if type(script) == \"function\" then\n        result = script\n    elseif type(script) == \"table\" then\n        result = script[self:name()]\n        result = result or script[\"__generic__\"]\n    end\n    return result\nend\n\n-- load this component\nfunction _instance:_load()\n    local loaded = self._LOADED\n    if not loaded then\n        local script = self:_on_component()\n        if script then\n            local ok, errors = sandbox.load(script, self:package(), self)\n            if not ok then\n                os.raise(\"load component(%s) failed, %s\", self:name(), errors or \"unknown errors\")\n            end\n        end\n        self._LOADED = true\n    end\nend\n\n-- the interpreter\nfunction component._interpreter()\n    local interp = component._INTERPRETER\n    if not interp then\n        interp = interpreter.new()\n        interp:api_define(component.apis())\n        interp:api_define(language.apis())\n        component._INTERPRETER = interp\n    end\n    return interp\nend\n\n-- get component apis\nfunction component.apis()\n    return {\n        values = {\n            -- component.add_xxx\n           \"component.add_extsources\"\n        }\n    }\nend\n\n-- new component\nfunction component.new(name, opt)\n    return _instance.new(name, opt)\nend\n\n-- return module\nreturn component\n"
  },
  {
    "path": "xmake/core/package/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- define module\nlocal package   = {}\nlocal _instance = {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal io             = require(\"base/io\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal global         = require(\"base/global\")\nlocal semver         = require(\"base/semver\")\nlocal option         = require(\"base/option\")\nlocal hashset        = require(\"base/hashset\")\nlocal scopeinfo      = require(\"base/scopeinfo\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal select_script  = require(\"base/private/select_script\")\nlocal is_cross       = require(\"base/private/is_cross\")\nlocal memcache       = require(\"cache/memcache\")\nlocal toolchain      = require(\"tool/toolchain\")\nlocal compiler       = require(\"tool/compiler\")\nlocal linker         = require(\"tool/linker\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal config         = require(\"project/config\")\nlocal policy         = require(\"project/policy\")\nlocal platform       = require(\"platform/platform\")\nlocal platform_menu  = require(\"platform/menu\")\nlocal component      = require(\"package/component\")\nlocal scheme         = require(\"package/scheme\")\nlocal language       = require(\"language/language\")\nlocal language_menu  = require(\"language/menu\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal sandbox_os     = require(\"sandbox/modules/os\")\nlocal sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- new an instance\nfunction _instance.new(name, info, opt)\n    opt = opt or {}\n    local instance = table.inherit(_instance)\n    if name then\n        local parts = name:split(\"::\", {plain = true})\n        local managers = package._memcache():get(\"managers\")\n        if managers == nil and #parts == 2 then\n            managers = hashset.new()\n            for _, dir in ipairs(os.dirs(path.join(os.programdir(), \"modules/package/manager/*\"))) do\n                managers:insert(path.filename(dir))\n            end\n            package._memcache():set(\"managers\", managers)\n        end\n        if #parts == 2 and managers and managers:has(parts[1]) then\n            instance._NAME = name\n        else\n            instance._NAME = parts[#parts]\n            table.remove(parts)\n            if #parts > 0 then\n                instance._NAMESPACE = table.concat(parts, \"::\")\n            end\n        end\n    end\n    instance._INFO      = info\n    instance._REPO      = opt.repo\n    instance._SCRIPTDIR = opt.scriptdir and path.absolute(opt.scriptdir)\n    return instance\nend\n\n-- get memcache\nfunction _instance:memcache()\n    local cache = self._MEMCACHE\n    if not cache then\n        cache = memcache.cache(\"core.package.package.\" .. tostring(self))\n        self._MEMCACHE = cache\n    end\n    return cache\nend\n\n-- get the package name without namespace\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name (with namespace)\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get the display name (with namespace and ~label)\nfunction _instance:displayname()\n    return self._DISPLAYNAME\nend\n\n-- set the display name\nfunction _instance:displayname_set(displayname)\n    self._DISPLAYNAME = displayname\nend\n\n-- get the type: package\nfunction _instance:type()\n    return \"package\"\nend\n\n-- get the base package\nfunction _instance:base()\n    return self._BASE\nend\n\n-- get the package configuration\nfunction _instance:get(name)\n    local value = self._INFO:get(name)\n    if name == \"configs\" then\n        -- we need to merge it, because current builtin configs always exists\n        if self:base() then\n            local configs_base = self:base():get(\"configs\")\n            if configs_base then\n                value = table.unique(table.join(value or {}, configs_base))\n            end\n        end\n    elseif value == nil and self:base() then\n        value = self:base():get(name)\n    end\n    if value ~= nil then\n        return value\n    end\nend\n\n-- set the value to the package info\nfunction _instance:set(name, ...)\n    if self._SOURCE_INITED then\n        -- we can use set/add to modify urls, .. in on_load() if urls have been inited.\n        -- but we cannot init urls, ... in on_load() if it has been not inited\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/5148\n        -- https://github.com/xmake-io/xmake-repo/pull/4204\n        if self:_sourceset():has(name) and self:get(name) == nil then\n            os.raise(\"'%s' can only be initied in on_source() or the description scope.\", name)\n        end\n    end\n    self._INFO:apival_set(name, ...)\nend\n\n-- add the value to the package info\nfunction _instance:add(name, ...)\n    if self._SOURCE_INITED then\n        if self:_sourceset():has(name) and self:get(name) == nil then\n            os.raise(\"'%s' can only be initied in on_source() or the description scope.\", name)\n        end\n    end\n    self._INFO:apival_add(name, ...)\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    local conf = self._INFO:extraconf(name, item, key)\n    if conf == nil and self:base() then\n        conf = self:base():extraconf(name, item, key)\n    end\n    return conf\nend\n\n-- set the extra configuration\nfunction _instance:extraconf_set(name, item, key, value)\n    return self._INFO:extraconf_set(name, item, key, value)\nend\n\n-- get configuration source information of the given api item\nfunction _instance:sourceinfo(name, item)\n    return self._INFO:sourceinfo(name, item)\nend\n\n-- get the package license\nfunction _instance:license()\n    return self:get(\"license\")\nend\n\n-- get the package description\nfunction _instance:description()\n    return self:get(\"description\")\nend\n\n-- get the platform of package\nfunction _instance:plat()\n    if self._PLAT then\n        return self._PLAT\n    end\n    if self:is_host() then\n        return os.subhost()\n    end\n    local requireinfo = self:requireinfo()\n    if requireinfo and requireinfo.plat then\n        return requireinfo.plat\n    end\n    return package.targetplat()\nend\n\n-- get the architecture of package\nfunction _instance:arch()\n    if self._ARCH then\n        return self._ARCH\n    end\n    if self:is_host() then\n        return os.subarch()\n    end\n    return self:targetarch()\nend\n\n-- set the package platform\nfunction _instance:plat_set(plat)\n    self._PLAT = plat\nend\n\n-- set the package architecture\nfunction _instance:arch_set(arch)\n    self._ARCH = arch\nend\n\n-- get the target os\nfunction _instance:targetos()\n    local requireinfo = self:requireinfo()\n    if requireinfo and requireinfo.targetos then\n        return requireinfo.targetos\n    end\n    return config.get(\"target_os\") or platform.os()\nend\n\n-- get the target architecture\nfunction _instance:targetarch()\n    local requireinfo = self:requireinfo()\n    if requireinfo and requireinfo.arch then\n        return requireinfo.arch\n    end\n    return package.targetarch()\nend\n\n-- get the build mode\nfunction _instance:mode()\n    return self:is_debug() and \"debug\" or \"release\"\nend\n\n-- get the repository of this package\nfunction _instance:repo()\n    return self._REPO\nend\n\n-- the current platform is belong to the given platforms?\nfunction _instance:is_plat(...)\n    local plat = self:plat()\n    for _, v in ipairs(table.pack(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current architecture is belong to the given architectures?\nfunction _instance:is_arch(...)\n    local arch = self:arch()\n    for _, v in ipairs(table.pack(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- is 64bits architecture?\nfunction _instance:is_arch64()\n    return self:is_arch(\".+64.*\")\nend\n\n-- the current platform is belong to the given target os?\nfunction _instance:is_targetos(...)\n    local targetos = self:targetos()\n    for _, v in ipairs(table.join(...)) do\n        if v and targetos == v then\n            return true\n        end\n    end\nend\n\n-- the current architecture is belong to the given target architectures?\nfunction _instance:is_targetarch(...)\n    local targetarch = self:targetarch()\n    for _, v in ipairs(table.pack(...)) do\n        if v and targetarch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- get the package alias\nfunction _instance:alias()\n    local requireinfo = self:requireinfo()\n    if requireinfo then\n        return requireinfo.alias\n    end\nend\n\n-- get external package sources, e.g. pkgconfig::xxx, system::xxx, conan::xxx\n-- we can use it to improve self:fetch() for find_package\nfunction _instance:extsources()\n    return self:get(\"extsources\")\nend\n\n-- get urls\nfunction _instance:urls()\n    return self:current_scheme():urls()\nend\n\n-- get urls\nfunction _instance:urls_set(urls)\n    self:current_scheme():urls_set(urls)\nend\n\n-- get the alias of url, @note need raw url\nfunction _instance:url_alias(url)\n    return self:current_scheme():url_alias(url)\nend\n\n-- get the version filter of url, @note need raw url\nfunction _instance:url_version(url)\n    return self:current_scheme():url_version(url)\nend\n\n-- get the excludes paths of url\n-- @note it supports the path pattern, but it only supports for archiver.\nfunction _instance:url_excludes(url)\n    return self:current_scheme():url_excludes(url)\nend\n\n-- get the includes paths of url\n-- @note it does not support the path pattern, and it only supports for git url now.\n-- @see https://github.com/xmake-io/xmake/issues/6071\nfunction _instance:url_includes(url)\n    return self:current_scheme():url_includes(url)\nend\n\n-- get the http headers of url, @note need raw url\nfunction _instance:url_http_headers(url)\n    return self:current_scheme():url_http_headers(url)\nend\n\n-- install the precompiled artifacts first\nfunction _instance:use_precompiled_artifacts(artifacts_info)\n\n    -- init the precompiled scheme\n    local current_scheme = self:current_scheme()\n    local precompiled_scheme = scheme.new(\"__precompiled__\", {package = self})\n    precompiled_scheme:urls_set(table.wrap(artifacts_info.urls))\n    local versions_list = table.clone(current_scheme:_versions_list())\n    versions_list[self:version_str()] = artifacts_info.sha256\n    precompiled_scheme._VERSIONS_LIST = versions_list\n    precompiled_scheme._VERSION = current_scheme._VERSION\n    precompiled_scheme._VERSION_STR = current_scheme._VERSION_STR\n    precompiled_scheme._TAG = current_scheme._TAG\n    precompiled_scheme._COMMIT = current_scheme._COMMIT\n    precompiled_scheme._BRANCH = current_scheme._BRANCH\n\n    precompiled_scheme:set(\"install\", function (package)\n        sandbox_module.import(\"lib.detect.find_path\")\n        local rootdir = find_path(\"manifest.txt\", path.join(os.curdir(), \"*\", \"*\", \"*\"))\n        if not rootdir then\n            os.raise(\"package(%s): manifest.txt not found when installing artifacts!\", package:displayname())\n        end\n        os.cp(path.join(rootdir, \"*\"), package:installdir(), {symlink = true})\n        local manifest = package:manifest_load()\n        if not manifest then\n            os.raise(\"package(%s): load manifest.txt failed when installing artifacts!\", package:displayname())\n        end\n        if manifest.vars then\n            for k, v in pairs(manifest.vars) do\n                package:set(k, v)\n            end\n        end\n        if manifest.components then\n            local vars = manifest.components.vars\n            if vars then\n                for component_name, component_vars in pairs(vars) do\n                    local comp = package:component(component_name)\n                    if comp then\n                        for k, v in pairs(component_vars) do\n                            comp:set(k, v)\n                        end\n                    end\n                end\n            end\n        end\n        if manifest.envs then\n            local envs = self:_rawenvs()\n            for k, v in pairs(manifest.envs) do\n                envs[k] = v\n            end\n        end\n        -- save the remote install directory to fix the install path in .cmake/.pc files for precompiled artifacts\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/2210\n        --\n        manifest.artifacts = manifest.artifacts or {}\n        manifest.artifacts.remotedir = manifest.artifacts.installdir\n    end)\n\n    -- add the precompiled scheme\n    table.insert(self:schemes_orderlist(), 1, precompiled_scheme)\n    self:schemes()[precompiled_scheme:name()] = precompiled_scheme\n    self._CURRENT_SCHEME = precompiled_scheme\nend\n\n-- is this package built?\nfunction _instance:is_built()\n    return not self:is_precompiled()\nend\n\n-- is this package precompiled?\nfunction _instance:is_precompiled()\n    return self:current_scheme():is_precompiled()\nend\n\n-- get the given dependent package\nfunction _instance:dep(name)\n    local deps = self:deps()\n    if deps then\n        return deps[name]\n    end\nend\n\n-- get deps\nfunction _instance:deps()\n    return self._DEPS\nend\n\n-- get order deps\nfunction _instance:orderdeps()\n    return self._ORDERDEPS\nend\n\n-- get plain deps\nfunction _instance:plaindeps()\n    return self._PLAINDEPS\nend\n\n-- get library dep\nfunction _instance:librarydep(name, opt)\n    local key = \"librarydeps_map_\" .. ((opt and opt.private) and \"private\" or \"\")\n    local librarydeps_map = self:memcache():get(key)\n    if not librarydeps_map then\n        librarydeps_map = {}\n        for _, dep in ipairs(self:librarydeps()) do\n            librarydeps_map[dep:name()] = dep\n        end\n        self:memcache():set(key, librarydeps_map)\n    end\n    return librarydeps_map[name]\nend\n\n-- get library deps with correct link order\nfunction _instance:librarydeps(opt)\n    if opt and opt.private then\n        return self._LIBRARYDEPS_WITH_PRIVATE\n    else\n        return self._LIBRARYDEPS\n    end\nend\n\n-- get parents\nfunction _instance:parents(packagename)\n    local parents = self._PARENTS\n    if parents then\n        if packagename then\n            return parents[packagename]\n        else\n            local results = self._PARENTS_PLAIN\n            if not results then\n                results = {}\n                for _, parentpkgs in pairs(parents) do\n                    table.join2(results, parentpkgs)\n                end\n                results = table.unique(results)\n                self._PARENTS_PLAIN = results\n            end\n            if #results > 0 then\n                return results\n            end\n        end\n    end\nend\n\n-- add parents\nfunction _instance:parents_add(...)\n    self._PARENTS = self._PARENTS or {}\n    for _, parent in ipairs({...}) do\n        -- maybe multiple parents will depend on it\n        -- @see https://github.com/xmake-io/xmake/issues/3065\n        local parentpkgs = self._PARENTS[parent:name()]\n        if not parentpkgs then\n            parentpkgs = {}\n            self._PARENTS[parent:name()] = parentpkgs\n        end\n        table.insert(parentpkgs, parent)\n        self._PARENTS_PLAIN = nil\n    end\nend\n\n-- get hash of the source package for the url_alias@version_str\nfunction _instance:sourcehash(url_alias)\n    return self:current_scheme():sourcehash(url_alias)\nend\n\n-- get revision(commit, tag, branch) of the url_alias@version_str, only for git url\nfunction _instance:revision(url_alias)\n    return self:current_scheme():revision(url_alias)\nend\n\n-- get the package policy\nfunction _instance:policy(name)\n    local policies = self._POLICIES\n    if not policies then\n        policies = self:get(\"policy\")\n        self._POLICIES = policies\n        if policies then\n            local defined_policies = policy.policies()\n            for name, _ in pairs(policies) do\n                if not defined_policies[name] then\n                    utils.warning(\"unknown policy(%s), please run `xmake l core.project.policy.policies` if you want to all policies\", name)\n                end\n            end\n        end\n    end\n    return policy.check(name, policies and policies[name])\nend\n\n-- get the package kind\n--\n-- - binary\n-- - toolchain (is also binary)\n-- - library(default)\n--\nfunction _instance:kind()\n    local kind\n    local requireinfo = self:requireinfo()\n    if requireinfo then\n        kind = requireinfo.kind\n    end\n    if not kind then\n        kind = self:get(\"kind\")\n    end\n    return kind\nend\n\n-- is binary package?\nfunction _instance:is_binary()\n    return self:kind() == \"binary\" or self:kind() == \"toolchain\"\nend\n\n-- is toolchain package?\nfunction _instance:is_toolchain()\n    return self:kind() == \"toolchain\"\nend\n\n-- is library package?\nfunction _instance:is_library()\n    return self:kind() == nil or self:kind() == \"library\"\nend\n\n-- is template package?\nfunction _instance:is_template()\n    return self:kind() == \"template\"\nend\n\n-- is header only?\nfunction _instance:is_headeronly()\n    return self:is_library() and self:extraconf(\"kind\", \"library\", \"headeronly\")\nend\n\n-- is module only?\nfunction _instance:is_moduleonly()\n    return self:is_library() and self:extraconf(\"kind\", \"library\", \"moduleonly\")\nend\n\n-- is top level? user top requires in xmake.lua\nfunction _instance:is_toplevel()\n    local requireinfo = self:requireinfo()\n    return requireinfo and requireinfo.is_toplevel\nend\n\n-- is the system package?\nfunction _instance:is_system()\n    return self._is_system\nend\n\n-- is the third-party package? e.g. brew::pcre2/libpcre2-8, conan::OpenSSL/1.0.2n@conan/stable\n-- we need to install and find package by third-party package manager directly\n--\nfunction _instance:is_thirdparty()\n    return self._is_thirdparty\nend\n\n-- is fetch only?\nfunction _instance:is_fetchonly()\n    local project = package._project()\n    if project and project.policy(\"package.fetch_only\") then\n        return true\n    end\n    -- only fetch script\n    if self:get(\"fetch\") and not self:get(\"install\") then\n        return true\n    end\n    -- only from system\n    local requireinfo = self:requireinfo()\n    if requireinfo and requireinfo.system then\n        return true\n    end\n    return false\nend\n\n-- is optional package?\nfunction _instance:is_optional()\n    local requireinfo = self:requireinfo()\n    return requireinfo and requireinfo.optional or false\nend\n\n-- is private package?\nfunction _instance:is_private()\n    local requireinfo = self:requireinfo()\n    return requireinfo and requireinfo.private or false\nend\n\n-- verify sha256sum and versions?\nfunction _instance:is_verify()\n    local requireinfo = self:requireinfo()\n    local verify = requireinfo and requireinfo.verify\n    if verify == nil then\n        verify = true\n    end\n    return verify\nend\n\n-- is debug package?\nfunction _instance:is_debug()\n    return self:config(\"debug\") or self:config(\"asan\")\nend\n\n-- should keep package source code after installing?\nfunction _instance:has_source()\n    local project = package._project()\n    return self:is_debug() or\n           self:is_source_embed() or\n           (project and project.policy(\"package.keep_source\")) or\n           self:policy(\"package.keep_source\")\nend\n\n-- is the supported package?\nfunction _instance:is_supported()\n    -- attempt to get the install script with the current plat/arch\n    return self:script(\"install\") ~= nil\nend\n\n-- support parallelize for installation?\nfunction _instance:is_parallelize()\n    return self:get(\"parallelize\") ~= false\nend\n\n-- is local embed source code package?\n-- we install directly from the local source code instead of downloading it remotely\nfunction _instance:is_source_embed()\n    return self:get(\"sourcedir\") and #self:urls() == 0 and self:script(\"install\")\nend\n\n-- is local embed binary package? it's come from `xmake package`\nfunction _instance:is_binary_embed()\n    return self:get(\"installdir\") and #self:urls() == 0 and not self:script(\"install\") and self:script(\"fetch\")\nend\n\n-- is local package?\n-- we will use local installdir and cachedir in current project\nfunction _instance:is_local()\n    return self._IS_LOCAL or self:is_source_embed() or self:is_binary_embed() or self:is_thirdparty()\nend\n\n-- is debug package? (deprecated)\nfunction _instance:debug()\n    return self:is_debug()\nend\n\n-- is host package?\n--\n-- @note It is different from not is_cross() in that users do not use host packages directly,\n-- they are usually used to build library packages.\nfunction _instance:is_host()\n    local requireinfo = self:requireinfo()\n    if requireinfo and requireinfo.host then\n        return true\n    end\n    return self:is_binary()\nend\n\n-- is cross-compilation?\nfunction _instance:is_cross()\n    if self:is_host() then\n        return false\n    end\n    return is_cross(self:plat(), self:arch())\nend\n\n-- mark it as local package\nfunction _instance:_mark_as_local(is_local)\n    if self:is_local() ~= is_local then\n        self._INSTALLDIR = nil\n        self._IS_LOCAL = is_local\n    end\nend\n\n-- use external includes?\nfunction _instance:use_external_includes()\n    local external = self:requireinfo().external\n    if external == nil then\n        local project = package._project()\n        if project then\n            external = project.policy(\"package.include_external_headers\")\n        end\n    end\n    if external == nil then\n        external = self:policy(\"package.include_external_headers\")\n    end\n    -- disable -Isystem for external packages as it seems to break. e.g. assimp\n    -- @see https://github.com/msys2/MINGW-packages/issues/10761\n    if external == nil and self:is_plat(\"mingw\") and os.is_subhost(\"msys\") then\n        external = false\n    end\n    if external == nil then\n        external = true\n    end\n    return external\nend\n\n-- get the filelock of the whole package directory\nfunction _instance:filelock()\n    local filelock = self._FILELOCK\n    if filelock == nil then\n        filelock = io.openlock(path.join(self:cachedir(), \"package.lock\"))\n        if not filelock then\n            os.raise(\"cannot create filelock for package(%s)!\", self:name())\n        end\n        self._FILELOCK = filelock\n    end\n    return filelock\nend\n\n-- lock the whole package\nfunction _instance:lock(opt)\n    if self:filelock():trylock(opt) then\n        return true\n    else\n        utils.cprint(\"${color.warning}package(%s) is being accessed by other processes, please wait!\", self:name())\n    end\n    local ok, errors = self:filelock():lock(opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- unlock the whole package\nfunction _instance:unlock()\n    local ok, errors = self:filelock():unlock()\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- get the source directory\nfunction _instance:sourcedir()\n    return self:get(\"sourcedir\")\nend\n\n-- get the build directory\nfunction _instance:builddir()\n    local builddir = self._BUILDDIR\n    if not builddir then\n        if self:is_local() then\n            local name = self:name():lower():gsub(\"::\", \"_\")\n            local rootdir = path.join(config.builddir({absolute = true}), \".packages\", name:sub(1, 1):lower(), name, self:version_str())\n            builddir = path.join(rootdir, \"cache\", \"build_\" .. hash.rand32())\n        else\n            builddir = \"build_\" .. hash.rand32()\n        end\n        self._BUILDDIR = builddir\n    end\n    return builddir\nend\n\n-- get the build directory (deprecated)\nfunction _instance:buildir()\n    utils.warning(\"package:buildir() has been deprecated, please use package:builddir()\")\n    return self:builddir()\nend\n\n-- get the cached directory of this package\nfunction _instance:cachedir()\n    local cachedir = self._CACHEDIR\n    if not cachedir then\n        cachedir = self:get(\"cachedir\")\n        if not cachedir then\n            -- we need to use displayname (with package id) to avoid\n            -- multiple processes accessing it at the same time.\n            --\n            -- @see https://github.com/libbpf/libbpf-bootstrap/pull/259#issuecomment-1994914188\n            --\n            -- e.g.\n            --\n            -- lock elfutils#1 /home/runner/.xmake/cache/packages/2403/e/elfutils/0.189\n            -- lock elfutils /home/runner/.xmake/cache/packages/2403/e/elfutils/0.189\n            -- package(elfutils) is being accessed by other processes, please wait!\n            --\n            local name = self:displayname():lower():gsub(\"::\", \"_\"):gsub(\"#\", \"_\")\n            local version_str = self:version_str()\n            -- strip invalid characters on windows, e.g. `>= <=`\n            if version_str and os.is_host(\"windows\") then\n                version_str = version_str:gsub(\"[>=<|%*]\", \"\")\n            end\n            if self:is_local() then\n                cachedir = path.join(config.builddir({absolute = true}), \".packages\", name:sub(1, 1):lower(), name, version_str, \"cache\")\n            else\n                cachedir = path.join(package.cachedir(), name:sub(1, 1):lower(), name, version_str)\n            end\n        end\n        self._CACHEDIR = cachedir\n    end\n    return cachedir\nend\n\n-- get the installed directory of this package\nfunction _instance:installdir(...)\n    local installdir = self._INSTALLDIR\n    if not installdir then\n        installdir = self:get(\"installdir\")\n        if not installdir then\n            local name = self:name():lower():gsub(\"::\", \"_\")\n            if self:is_local() then\n                installdir = path.join(config.builddir({absolute = true}), \".packages\", name:sub(1, 1):lower(), name)\n            else\n                installdir = path.join(package.installdir(), name:sub(1, 1):lower(), name)\n            end\n            local version_str = self:version_str()\n            if version_str then\n                -- strip invalid characters on windows, e.g. `>= <=`\n                if os.is_host(\"windows\") then\n                    version_str = version_str:gsub(\"[>=<|%*]\", \"\")\n                end\n                installdir = path.join(installdir, version_str)\n            end\n            installdir = path.join(installdir, self:buildhash())\n        end\n        self._INSTALLDIR = installdir\n    end\n    local dirs = table.pack(...)\n    local opt = dirs[dirs.n]\n    if table.is_dictionary(opt) then\n        table.remove(dirs)\n    else\n        opt = nil\n    end\n    local dir = path.join(installdir, table.unpack(dirs))\n    if opt and opt.readonly then\n        return dir\n    end\n    if not os.isdir(dir)then\n        os.mkdir(dir)\n    end\n    return dir\nend\n\n-- get the script directory\nfunction _instance:scriptdir()\n    return self._SCRIPTDIR\nend\n\n-- get the rules directory\nfunction _instance:rulesdir()\n    local rulesdir = self._RULESDIR\n    if rulesdir == nil then\n        if self:repo() == nil and self:base() then\n            rulesdir = self:base():rulesdir()\n        else\n            rulesdir = path.join(self:scriptdir(), \"rules\")\n            if not os.isdir(rulesdir) and self:base() then\n                rulesdir = self:base():rulesdir()\n            end\n        end\n        if rulesdir == nil or not os.isdir(rulesdir) then\n            rulesdir = false\n        end\n        self._RULESDIR = rulesdir\n    end\n    return rulesdir or nil\nend\n\n-- get the references info of this package\nfunction _instance:references()\n    local references_file = path.join(self:installdir({readonly = true}), \"references.txt\")\n    if os.isfile(references_file) then\n        local references, errors = io.load(references_file)\n        if not references then\n            os.raise(errors)\n        end\n        return references\n    end\nend\n\n-- get the manifest file of this package\nfunction _instance:manifest_file()\n    return path.join(self:installdir({readonly = true}), \"manifest.txt\")\nend\n\n-- load the manifest file of this package\nfunction _instance:manifest_load()\n    local manifest = self._MANIFEST\n    if not manifest then\n        local manifest_file = self:manifest_file()\n        if os.isfile(manifest_file) then\n            local errors = nil\n            manifest, errors = io.load(manifest_file)\n            if not manifest then\n                os.raise(errors)\n            end\n            self._MANIFEST = manifest\n        end\n    end\n    return manifest\nend\n\n-- save the manifest file of this package\nfunction _instance:manifest_save()\n\n    -- make manifest\n    local manifest       = {}\n    manifest.name        = self:name()\n    manifest.license     = self:license()\n    manifest.description = self:description()\n    manifest.version     = self:version_str()\n    manifest.kind        = self:kind()\n    manifest.plat        = self:plat()\n    manifest.arch        = self:arch()\n    manifest.mode        = self:mode()\n    manifest.configs     = self:configs()\n    manifest.envs        = self:_rawenvs()\n\n    -- ensure pathenvs are written deterministically\n    manifest.pathenvs = table.to_array(self:_pathenvs():orderitems())\n\n    -- save enabled library deps\n    if self:librarydeps() then\n        manifest.librarydeps = {}\n        for _, dep in ipairs(self:librarydeps()) do\n            if dep:exists() then\n                table.insert(manifest.librarydeps, dep:name())\n            end\n        end\n    end\n\n    -- save deps\n    if self:librarydeps() then\n        manifest.deps = {}\n        for _, dep in ipairs(self:librarydeps()) do\n            manifest.deps[dep:name()] = {\n                version = dep:version_str(),\n                buildhash = dep:buildhash()\n            }\n        end\n    end\n\n    -- save global variables and component variables\n    local vars\n    local extras\n    local components\n    local apis = language.apis()\n    for _, apiname in ipairs(table.join(apis.values, apis.paths, apis.groups)) do\n        if apiname:startswith(\"package.add_\") or apiname:startswith(\"package.set_\")  then\n            local name = apiname:sub(13)\n            local values = self:get(name)\n            if values ~= nil then\n                vars = vars or {}\n                vars[name] = values\n                local extra = self:extraconf(name)\n                if extra then\n                    extras = extras or {}\n                    extras[name] = extra\n                end\n            end\n            for _, component_name in ipairs(table.wrap(self:get(\"components\"))) do\n                local comp = self:component(component_name)\n                if comp then\n                    local component_values = comp:get(name)\n                    if component_values ~= nil then\n                        components = components or {}\n                        components.vars = components.vars or {}\n                        components.vars[component_name] = components.vars[component_name] or {}\n                        components.vars[component_name][name] = component_values\n                    end\n                end\n            end\n        end\n    end\n    manifest.vars = vars\n    manifest.extras = extras\n    manifest.components = components\n\n    -- save repository\n    local repo = self:repo()\n    if repo then\n        manifest.repo        = {}\n        manifest.repo.name   = repo:name()\n        manifest.repo.url    = repo:url()\n        manifest.repo.branch = repo:branch()\n        manifest.repo.commit = repo:commit()\n    end\n\n    -- save artifacts information to fix the install path in .cmake/.pc files for precompiled artifacts\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/2210\n    --\n    manifest.artifacts = {}\n    manifest.artifacts.installdir = self:installdir()\n    local current_manifest = self:manifest_load()\n    if current_manifest and current_manifest.artifacts then\n        manifest.artifacts.remotedir = current_manifest.artifacts.remotedir\n    end\n\n    -- save manifest\n    local ok, errors = io.save(self:manifest_file(), manifest, { orderkeys = true })\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- get the source configuration set\nfunction _instance:_sourceset()\n    local sourceset = self._SOURCESET\n    if sourceset == nil then\n        sourceset = hashset.of(\"urls\", \"versions\", \"versionfiles\", \"configs\")\n        self._SOURCESET = sourceset\n    end\n    return sourceset\nend\n\n-- init package source\nfunction _instance:_init_source()\n    local inited = self._SOURCE_INITED\n    if not inited then\n        local on_source = self:script(\"source\")\n        if on_source then\n            on_source(self)\n        end\n    end\nend\n\n-- load package\nfunction _instance:_load()\n    self._SOURCE_INITED = true\n    local loaded = self._LOADED\n    if not loaded then\n\n        -- load on_load script\n        local on_load = self:script(\"load\")\n        if on_load then\n            on_load(self)\n        end\n        \n        -- load all components\n        self:_load_components()\n\n        -- load environments from the manifest to enable the environments of on_install()\n        self:_load_envs()\n    end\nend\n\n-- mark as loaded package\nfunction _instance:_mark_as_loaded()\n    self._LOADED = true\nend\n\n-- get the raw environments\nfunction _instance:_rawenvs()\n    local envs = self._RAWENVS\n    if not envs then\n        envs = {}\n\n        -- add bin PATH\n        local bindirs = self:get(\"bindirs\")\n        if bindirs then\n            envs.PATH = table.wrap(bindirs)\n        elseif self:is_binary() then\n            envs.PATH = {\"bin\"}\n        elseif os.host() == \"windows\" and self:is_plat(\"windows\", \"mingw\") and not self:is_cross() and self:config(\"shared\") then\n            -- bin/*.dll for windows\n            envs.PATH = {\"bin\"}\n        end\n\n        -- add LD_LIBRARY_PATH to load *.so directory\n        if os.host() ~= \"windows\" and self:is_plat(os.host()) and not self:is_cross() and self:config(\"shared\") then\n            envs.LD_LIBRARY_PATH = {\"lib\"}\n            if os.host() == \"macosx\" then\n                envs.DYLD_LIBRARY_PATH = {\"lib\"}\n            end\n        end\n        self._RAWENVS = envs\n    end\n    return envs\nend\n\n-- get path environment keys\nfunction _instance:_pathenvs()\n    local pathenvs = self._PATHENVS\n    if pathenvs == nil then\n        pathenvs = hashset.from {\n            \"PATH\",\n            \"LD_LIBRARY_PATH\",\n            \"DYLD_LIBRARY_PATH\",\n            \"PKG_CONFIG_PATH\",\n            \"ACLOCAL_PATH\",\n            \"CMAKE_PREFIX_PATH\",\n            \"PYTHONPATH\"\n        }\n        self._PATHENVS = pathenvs\n    end\n    return pathenvs\nend\n\n-- mark as path environments\nfunction _instance:mark_as_pathenv(name)\n    self:_pathenvs():insert(name)\nend\n\n-- get the exported environments\nfunction _instance:envs()\n    local envs = {}\n    for name, values in pairs(self:_rawenvs()) do\n        if self:_pathenvs():has(name) then\n            local newvalues = {}\n            for _, value in ipairs(values) do\n                if path.is_absolute(value) then\n                    table.insert(newvalues, value)\n                else\n                    table.insert(newvalues, path.normalize(path.join(self:installdir({readonly = true}), value)))\n                end\n            end\n            values = newvalues\n        end\n        envs[name] = values\n    end\n    return envs\nend\n\n-- load the package environments from the manifest\nfunction _instance:_load_envs()\n    local manifest = self:manifest_load()\n    if manifest then\n        local envs = self:_rawenvs()\n        for name, values in pairs(manifest.envs) do\n            envs[name] = values\n        end\n    end\nend\n\n-- load all components\nfunction _instance:_load_components()\n    for _, component_inst in pairs(self:components()) do\n        component_inst:_load()\n    end\nend\n\n-- enter the package environments\nfunction _instance:envs_enter()\n    local installdir = self:installdir({readonly = true})\n    for name, values in pairs(self:envs()) do\n        os.addenv(name, table.unpack(table.wrap(values)))\n    end\nend\n\n-- get the given environment variable\nfunction _instance:getenv(name)\n    return self:_rawenvs()[name]\nend\n\n-- set the given environment variable\nfunction _instance:setenv(name, ...)\n    self:_rawenvs()[name] = {...}\nend\n\n-- add the given environment variable\nfunction _instance:addenv(name, ...)\n    self:_rawenvs()[name] = table.join(self:_rawenvs()[name] or {}, ...)\nend\n\n-- get the given build environment variable\nfunction _instance:build_getenv(name)\n    return self:build_envs(true)[name]\nend\n\n-- set the given build environment variable\nfunction _instance:build_setenv(name, ...)\n    self:build_envs(true)[name] = table.unwrap({...})\nend\n\n-- add the given build environment variable\nfunction _instance:build_addenv(name, ...)\n    self:build_envs(true)[name] = table.unwrap(table.join(table.wrap(self:build_envs()[name]), ...))\nend\n\n-- get the build environments\nfunction _instance:build_envs(lazy_loading)\n    local build_envs = self._BUILD_ENVS\n    if build_envs == nil then\n        -- lazy loading the given environment value and cache it\n        build_envs = {}\n        local builtin_configs = hashset.of(\"cflags\", \"cxflags\", \"cxxflags\", \"ldflags\", \"shflags\", \"asflags\")\n        setmetatable(build_envs, { __index = function (tbl, key)\n            local result = {}\n            local value = config.get(key)\n            if value == nil then\n                value = self:tool(key)\n            end\n            if value then\n                table.join2(result, value)\n            end\n            -- we can only get the builtin config values\n            -- https://github.com/xmake-io/xmake/issues/6897\n            if builtin_configs:has(key) then\n                value = self:config(key)\n                if value then\n                    table.join2(result, value)\n                end\n            end\n            value = self:toolconfig(key)\n            if value then\n                table.join2(result, value)\n            end\n            result = table.unique(result)\n            if #result > 0 then\n                result = table.unwrap(result)\n                rawset(tbl, key, result)\n                return result\n            end\n            return rawget(tbl, key)\n        end})\n\n        -- save build environments\n        self._BUILD_ENVS = build_envs\n    end\n\n    -- force to load all values if need\n    if not lazy_loading then\n        for _, opt in ipairs(table.join(language_menu.options(\"config\"), platform_menu.options(\"config\"))) do\n            local optname = opt[2]\n            if type(optname) == \"string\" then\n                -- we only need to index it to force load it's value\n                local value = build_envs[optname]\n            end\n        end\n    end\n    return build_envs\nend\n\n-- get runtimes\nfunction _instance:runtimes()\n    local runtimes = self:memcache():get(\"runtimes\")\n    if runtimes == nil then\n        runtimes = self:config(\"runtimes\")\n        if runtimes then\n            local runtimes_current = runtimes:split(\",\", {plain = true})\n            runtimes = table.unwrap(runtimes_current)\n        end\n        runtimes = runtimes or false\n        self:memcache():set(\"runtimes\", runtimes)\n    end\n    return runtimes or nil\nend\n\n-- has the given runtime for the current toolchains?\nfunction _instance:has_runtime(...)\n    local runtimes_set = self:memcache():get(\"runtimes_set\")\n    if runtimes_set == nil then\n        runtimes_set = hashset.from(table.wrap(self:runtimes()))\n        self:memcache():set(\"runtimes_set\", runtimes_set)\n    end\n    for _, v in ipairs(table.pack(...)) do\n        if runtimes_set:has(v) then\n            return true\n        end\n    end\nend\n\n-- get the given toolchain\nfunction _instance:toolchain(name)\n    local toolchains_map = self:memcache():get(\"toolchains_map\")\n    if toolchains_map == nil then\n        toolchains_map = {}\n        local toolchains = self:toolchains()\n        if toolchains then\n            for _, toolchain_inst in ipairs(toolchains) do\n                toolchains_map[toolchain_inst:name()] = toolchain_inst\n            end\n        end\n        self:memcache():set(\"toolchains_map\", toolchains_map)\n    end\n    if not toolchains_map[name] then\n        toolchains_map[name] = toolchain.load(name, {plat = self:plat(), arch = self:arch()})\n    end\n    return toolchains_map[name]\nend\n\n-- get toolchains\nfunction _instance:toolchains()\n    local toolchains = self._TOOLCHAINS\n    if toolchains == nil then\n        local project = package._project()\n        for _, name in ipairs(table.wrap(self:config(\"toolchains\"))) do\n            local toolchain_opt = project and project.extraconf(\"target.toolchains\", name) or {}\n            toolchain_opt.plat = self:plat()\n            toolchain_opt.arch = self:arch()\n            toolchain_opt.namespace = self:namespace()\n            local toolchain_inst, errors = toolchain.load(name, toolchain_opt)\n            if not toolchain_inst and project then\n                toolchain_inst = project.toolchain(name, toolchain_opt)\n            end\n            if not toolchain_inst then\n                os.raise(errors)\n            end\n            toolchains = toolchains or {}\n            table.insert(toolchains, toolchain_inst)\n        end\n        self._TOOLCHAINS = toolchains or false\n    end\n    return toolchains or nil\nend\n\n-- get the program and name of the given tool kind\nfunction _instance:tool(toolkind)\n    if self:toolchains() then\n        local cachekey = \"package_\" .. tostring(self)\n        return toolchain.tool(self:toolchains(), toolkind, {cachekey = cachekey, plat = self:plat(), arch = self:arch()})\n    else\n        return platform.tool(toolkind, self:plat(), self:arch(), {host = self:is_host()})\n    end\nend\n\n-- get tool configuration from the toolchains\nfunction _instance:toolconfig(name)\n    if self:toolchains() then\n        local cachekey = \"package_\" .. tostring(self)\n        return toolchain.toolconfig(self:toolchains(), name, {cachekey = cachekey, plat = self:plat(), arch = self:arch()})\n    else\n        return platform.toolconfig(name, self:plat(), self:arch(), {host = self:is_host()})\n    end\nend\n\n-- get the package compiler\nfunction _instance:compiler(sourcekind)\n    local compilerinst = self:memcache():get2(\"compiler\", sourcekind)\n    if not compilerinst then\n        if not sourcekind then\n            os.raise(\"please pass sourcekind to the first argument of package:compiler(), e.g. cc, cxx, as\")\n        end\n        local instance, errors = compiler.load(sourcekind, self)\n        if not instance then\n            os.raise(errors)\n        end\n        compilerinst = instance\n        self:memcache():set2(\"compiler\", sourcekind, compilerinst)\n    end\n    return compilerinst\nend\n\n-- get the package linker\nfunction _instance:linker(targetkind, sourcekinds)\n    local linkerinst = self:memcache():get3(\"linker\", targetkind, sourcekinds)\n    if not linkerinst then\n        if not sourcekinds then\n            os.raise(\"please pass sourcekinds to the second argument of package:linker(), e.g. cc, cxx, as\")\n        end\n        local instance, errors = linker.load(targetkind, sourcekinds, self)\n        if not instance then\n            os.raise(errors)\n        end\n        linkerinst = instance\n        self:memcache():set3(\"linker\", targetkind, sourcekinds, linkerinst)\n    end\n    return linkerinst\nend\n\n-- has the given tool for the current package?\n--\n-- e.g.\n--\n-- if package:has_tool(\"cc\", \"clang\", \"gcc\") then\n--    ...\n-- end\nfunction _instance:has_tool(toolkind, ...)\n    local target_utils = package._target_utils\n    if target_utils == nil then\n        target_utils = sandbox_module.import(\"private.utils.target\", {anonymous = true})\n        package._target_utils = target_utils\n    end\n    local _, toolname = self:tool(toolkind)\n    return target_utils.has_tool(toolname, table.pack(...))\nend\n\n-- get the user private data\nfunction _instance:data(name)\n    return self._DATA and self._DATA[name] or nil\nend\n\n-- set user private data\nfunction _instance:data_set(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = data\nend\n\n-- add user private data\nfunction _instance:data_add(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = table.unwrap(table.join(self._DATA[name] or {}, data))\nend\n\n-- get the downloaded original file\nfunction _instance:originfile()\n    return self._ORIGINFILE\nend\n\n-- set the downloaded original file\nfunction _instance:originfile_set(filepath)\n    self._ORIGINFILE = filepath\nend\n\n-- get versions list\nfunction _instance:_versions_list()\n    return self:current_scheme():_versions_list()\nend\n\n-- get versions\nfunction _instance:versions()\n    return self:current_scheme():versions()\nend\n\n-- get the version\nfunction _instance:version()\n    return self:current_scheme():version()\nend\n\n-- get the version string\nfunction _instance:version_str()\n    return self:current_scheme():version_str()\nend\n\n-- set the version, source: branch, tag, version\nfunction _instance:version_set(version, source)\n    self:current_scheme():version_set(version, source)\nend\n\n-- get branch version\nfunction _instance:branch()\n    return self:current_scheme():branch()\nend\n\n-- get tag version\nfunction _instance:tag()\n    return self:current_scheme():tag()\nend\n\n-- get commit version\nfunction _instance:commit()\n    return self:current_scheme():commit()\nend\n\n-- is git ref?\nfunction _instance:gitref()\n    return self:current_scheme():gitref()\nend\n\n-- get the require info\nfunction _instance:requireinfo()\n    return self._REQUIREINFO\nend\n\n-- set the require info\nfunction _instance:requireinfo_set(requireinfo)\n    self._REQUIREINFO = requireinfo\nend\n\n-- get label\nfunction _instance:label()\n    local requireinfo = self:requireinfo()\n    return requireinfo and requireinfo.label\nend\n\n-- invalidate configs\nfunction _instance:_invalidate_configs()\n    self._CONFIGS = nil\n    self._CONFIGS_FOR_BUILDHASH = nil\nend\n\n-- get the given configuration value of package\nfunction _instance:config(name)\n    local value\n    local configs = self:configs()\n    if configs then\n        value = configs[name]\n        -- vs_runtime is deprecated now\n        if name == \"vs_runtime\" then\n            local runtimes = configs.runtimes\n            if runtimes then\n                for _, item in ipairs(runtimes:split(\",\")) do\n                    if item:startswith(\"MT\") or item:startswith(\"MD\") then\n                        value = item\n                        break\n                    end\n                end\n            end\n            utils.warning(\"please use package:runtimes() or package:has_runtime() instead of package:config(\\\"vs_runtime\\\")\")\n        end\n    end\n    return value\nend\n\n-- set configuration value\nfunction _instance:config_set(name, value)\n    local configs = self:configs()\n    if configs then\n        configs[name] = value\n    end\nend\n\n-- get the configurations of package\nfunction _instance:configs()\n    local configs = self._CONFIGS\n    if configs == nil then\n        local configs_defined = self:get(\"configs\")\n        if configs_defined then\n            configs = {}\n            local requireinfo = self:requireinfo()\n            local configs_required = requireinfo and requireinfo.configs or {}\n            local configs_overrided = requireinfo and requireinfo.configs_overrided or {}\n            for _, name in ipairs(table.wrap(configs_defined)) do\n                local value = configs_overrided[name] or configs_required[name]\n                if value == nil then\n                    value = self:extraconf(\"configs\", name, \"default\")\n                    -- support for the deprecated vs_runtime in add_configs\n                    if name == \"runtimes\" and value == nil then\n                        value = self:extraconf(\"configs\", \"vs_runtime\", \"default\")\n                    end\n                end\n                configs[name] = value\n            end\n        else\n            configs = false\n        end\n        self._CONFIGS = configs\n    end\n    return configs and configs or nil\nend\n\n-- get the given configuration value of package for buildhash\nfunction _instance:_config_for_buildhash(name)\n    local value\n    local configs = self:_configs_for_buildhash()\n    if configs then\n        value = configs[name]\n    end\n    return value\nend\n\n-- get the configurations of package for buildhash\n-- @note on_test still need these configs\nfunction _instance:_configs_for_buildhash()\n    local configs = self._CONFIGS_FOR_BUILDHASH\n    if configs == nil then\n        local configs_defined = self:get(\"configs\")\n        if configs_defined then\n            configs = {}\n            local requireinfo = self:requireinfo()\n            local configs_required = requireinfo and requireinfo.configs or {}\n            local configs_overrided = requireinfo and requireinfo.configs_overrided or {}\n            local ignored_configs_for_buildhash = hashset.from(requireinfo and requireinfo.ignored_configs_for_buildhash or {})\n            for _, name in ipairs(table.wrap(configs_defined)) do\n                if not ignored_configs_for_buildhash:has(name) then\n                    local value = configs_overrided[name] or configs_required[name]\n                    if value == nil then\n                        value = self:extraconf(\"configs\", name, \"default\")\n                        -- support for the deprecated vs_runtime in add_configs\n                        if name == \"runtimes\" and value == nil then\n                            value = self:extraconf(\"configs\", \"vs_runtime\", \"default\")\n                        end\n                    end\n                    configs[name] = value\n                end\n            end\n        else\n            configs = false\n        end\n        self._CONFIGS_FOR_BUILDHASH = configs\n    end\n    return configs and configs or nil\nend\n\n-- compute the build hash\nfunction _instance:_compute_buildhash()\n    self._BUILDHASH_PREPARED = true\n    self:buildhash()\nend\n\n-- hash.strhash128 has been switched to xxhash.\n-- For compatibility, the old hash algorithm is still used here.\nfunction _instance:_strhash128(str)\n    return hash.uuid4(str):replace(\"-\", \"\", {plain = true}):lower()\nend\n\n-- get the build hash\nfunction _instance:buildhash()\n    local buildhash = self._BUILDHASH\n    if buildhash == nil then\n        if not self._BUILDHASH_PREPARED then\n            os.raise(\"package:buildhash() must be called after loading package\")\n        end\n        local function _get_buildhash(configs, opt)\n            opt = opt or {}\n            local str = self:plat() .. self:arch()\n            local label = self:label()\n            if label then\n                str = str .. label\n            end\n            if configs then\n\n                -- with old vs_runtime configs\n                -- https://github.com/xmake-io/xmake/issues/4477\n                if opt.vs_runtime then\n                    configs = table.clone(configs)\n                    configs.vs_runtime = configs.runtimes\n                    configs.runtimes = nil\n                end\n\n                -- since luajit v2.1, the key order of the table is random and undefined.\n                -- We cannot directly deserialize the table, so the result may be different each time\n                local configs_order = {}\n                for k, v in pairs(table.wrap(configs)) do\n                    if type(v) == \"table\" then\n                        v = string.serialize(v, {strip = true, indent = false, orderkeys = true})\n                    end\n                    table.insert(configs_order, k .. \"=\" .. tostring(v))\n                end\n                table.sort(configs_order)\n\n                -- we need to be compatible with the hash value string for the previous luajit version\n                local configs_str = string.serialize(configs_order, true)\n                configs_str = configs_str:gsub(\"\\\"\", \"\")\n                str = str .. configs_str\n            end\n            if opt.sourcehash ~= false then\n                local sourcehashs = hashset.new()\n                for _, url in ipairs(self:urls()) do\n                    local url_alias = self:url_alias(url)\n                    local sourcehash = self:sourcehash(url_alias)\n                    if sourcehash then\n                        sourcehashs:insert(sourcehash)\n                    end\n                end\n                if not sourcehashs:empty() then\n                    local hashs = sourcehashs:to_array()\n                    table.sort(hashs)\n                    str = str .. \"_\" .. table.concat(hashs, \"_\")\n                end\n            end\n            local toolchains = self:_config_for_buildhash(\"toolchains\")\n            if opt.toolchains ~= false and toolchains then\n                toolchains = table.copy(table.wrap(toolchains))\n                table.sort(toolchains)\n                str = str .. \"_\" .. table.concat(toolchains, \"_\")\n            end\n            return self:_strhash128(str)\n        end\n        local function _get_installdir(...)\n            local name = self:name():lower():gsub(\"::\", \"_\")\n            local dir = path.join(package.installdir(), name:sub(1, 1):lower(), name)\n            if self:version_str() then\n                dir = path.join(dir, self:version_str())\n            end\n            return path.join(dir, ...)\n        end\n\n        -- we need to be compatible with the hash value string for the previous xmake version\n        -- without builtin pic configuration (< 2.5.1).\n        if self:_config_for_buildhash(\"pic\") then\n            local configs = table.copy(self:_configs_for_buildhash())\n            configs.pic = nil\n            buildhash = _get_buildhash(configs, {sourcehash = false, toolchains = false})\n            if not os.isdir(_get_installdir(buildhash)) then\n                buildhash = nil\n            end\n        end\n\n        -- we need to be compatible with the hash value string for the previous xmake version\n        -- without sourcehash (< 2.5.2)\n        if not buildhash then\n            buildhash = _get_buildhash(self:_configs_for_buildhash(), {sourcehash = false, toolchains = false})\n            if not os.isdir(_get_installdir(buildhash)) then\n                buildhash = nil\n            end\n        end\n\n        -- we need to be compatible with the previous xmake version\n        -- without toolchains (< 2.6.4)\n        if not buildhash then\n            buildhash = _get_buildhash(self:_configs_for_buildhash(), {toolchains = false})\n            if not os.isdir(_get_installdir(buildhash)) then\n                buildhash = nil\n            end\n        end\n\n        -- we need to be compatible with the previous xmake version\n        -- with deprecated vs_runtime (< 2.8.7)\n        -- @see https://github.com/xmake-io/xmake/issues/4477\n        if not buildhash then\n            buildhash = _get_buildhash(self:_configs_for_buildhash(), {vs_runtime = true})\n            if not os.isdir(_get_installdir(buildhash)) then\n                buildhash = nil\n            end\n        end\n\n        -- get build hash for current version\n        if not buildhash then\n            buildhash = _get_buildhash(self:_configs_for_buildhash())\n        end\n        self._BUILDHASH = buildhash\n    end\n    return buildhash\nend\n\n-- get the group name\nfunction _instance:group()\n    local requireinfo = self:requireinfo()\n    if requireinfo then\n        return requireinfo.group\n    end\nend\n\n-- get xxx_script\nfunction _instance:script(name, generic)\n\n    -- get script\n    local script = self:current_scheme():get(name) or self:get(name)\n    local result = select_script(script, {plat = self:plat(), arch = self:arch()}) or generic\n\n    -- imports some modules first\n    if result and result ~= generic then\n        local scope = getfenv(result)\n        if scope then\n            for _, modulename in ipairs(table.wrap(self:get(\"imports\"))) do\n                scope[sandbox_module.name(modulename)] = sandbox_module.import(modulename, {\n                    rootdir = self:scriptdir(), anonymous = true})\n            end\n        end\n    end\n    return result\nend\n\n-- do fetch tool\nfunction _instance:_fetch_tool(opt)\n    opt = opt or {}\n    local fetchinfo\n    local on_fetch = self:script(\"fetch\")\n    if on_fetch then\n        fetchinfo = on_fetch(self, {force = opt.force,\n                                    system = opt.system,\n                                    require_version = opt.require_version})\n        if fetchinfo and opt.require_version and opt.require_version:find(\".\", 1, true) then\n            local version = type(fetchinfo) == \"table\" and fetchinfo.version\n            if not (version and (version == opt.require_version or semver.satisfies(version, opt.require_version))) then\n                fetchinfo = nil\n            end\n        end\n    end\n    -- we can disable to fallback fetch if on_fetch return false\n    if fetchinfo == nil then\n        self._find_tool = self._find_tool or sandbox_module.import(\"lib.detect.find_tool\", {anonymous = true})\n        if opt.system then\n            local fetchnames = {}\n            if not self:is_thirdparty() then\n                table.join2(fetchnames, self:extsources())\n            end\n            table.insert(fetchnames, self:name())\n            for _, fetchname in ipairs(fetchnames) do\n                fetchinfo = self:find_tool(fetchname, opt)\n                if fetchinfo then\n                    break\n                end\n            end\n        else\n            fetchinfo = self:find_tool(self:name(), {require_version = opt.require_version,\n                                                     cachekey = \"fetch_package_xmake\",\n                                                     norun = true, -- we don't need to run it to check for xmake/packages, @see https://github.com/xmake-io/xmake-repo/issues/66\n                                                     system = false, -- we only find it from xmake/packages, @see https://github.com/xmake-io/xmake-repo/pull/2085\n                                                     force = opt.force})\n\n            -- may be toolset, not single tool\n            if not fetchinfo then\n                fetchinfo = self:manifest_load()\n            end\n        end\n    end\n    return fetchinfo or nil\nend\n\n-- do fetch library\n--\n-- @param opt   the options, e.g. {force, system, external, require_version}\n--\nfunction _instance:_fetch_library(opt)\n    opt = opt or {}\n    local fetchinfo\n    local on_fetch = self:script(\"fetch\")\n    if on_fetch then\n        -- we cannot fetch it from system if it's cross-compilation package\n        if not opt.system or (opt.system and not self:is_cross()) then\n            fetchinfo = on_fetch(self, {force = opt.force,\n                                        system = opt.system,\n                                        external = opt.external,\n                                        require_version = opt.require_version})\n        end\n        if fetchinfo and opt.require_version and opt.require_version:find(\".\", 1, true) then\n            local version = fetchinfo.version\n            if not (version and (version == opt.require_version or semver.satisfies(version, opt.require_version))) then\n                fetchinfo = nil\n            end\n        end\n        if fetchinfo then\n            local components_base = fetchinfo.components and fetchinfo.components.__base\n            if opt.external then\n                fetchinfo.sysincludedirs = fetchinfo.sysincludedirs or fetchinfo.includedirs\n                fetchinfo.includedirs = nil\n                if components_base then\n                    components_base.sysincludedirs = components_base.sysincludedirs or components_base.includedirs\n                    components_base.includedirs = nil\n                end\n            else\n                fetchinfo.includedirs = fetchinfo.includedirs or fetchinfo.sysincludedirs\n                fetchinfo.sysincludedirs = nil\n                if components_base then\n                    components_base.includedirs = components_base.includedirs or components_base.sysincludedirs\n                    components_base.sysincludedirs = nil\n                end\n            end\n            local package_utils = sandbox_module.import(\"private.utils.package\", {anonymous = true})\n            package_utils.fetchinfo_set_concat(fetchinfo)\n        end\n        if fetchinfo and option.get(\"verbose\") then\n            local reponame = self:repo() and self:repo():name() or \"\"\n            utils.cprint(\"checking for %s::%s ... ${color.success}%s %s\", reponame, self:name(), self:name(), fetchinfo.version and fetchinfo.version or \"\")\n        end\n    end\n    if fetchinfo == nil then\n        if opt.system then\n            local fetchnames = {}\n            if not self:is_thirdparty() then\n                table.join2(fetchnames, self:extsources())\n            end\n            table.insert(fetchnames, self:name())\n            for _, fetchname in ipairs(fetchnames) do\n                local components_extsources = {}\n                for name, comp in pairs(self:components()) do\n                    for _, extsource in ipairs(table.wrap(comp:get(\"extsources\"))) do\n                        local extsource_info = extsource:split(\"::\")\n                        if fetchname:split(\"::\")[1] == extsource_info[1] then\n                            components_extsources[name] = extsource_info[2]\n                            break\n                        end\n                    end\n                end\n                fetchinfo = self:find_package(fetchname, table.join(opt, {components_extsources = components_extsources}))\n                if fetchinfo then\n                    break\n                end\n            end\n        else\n            fetchinfo = self:find_package(\"xmake::\" .. self:name(), {\n                                           require_version = opt.require_version,\n                                           cachekey = \"fetch_package_xmake\",\n                                           external = opt.external,\n                                           force = opt.force})\n        end\n    end\n    return fetchinfo or nil\nend\n\n-- find tool\nfunction _instance:find_tool(name, opt)\n    opt = opt or {}\n    self._find_tool = self._find_tool or sandbox_module.import(\"lib.detect.find_tool\", {anonymous = true})\n    return self._find_tool(name, {cachekey = opt.cachekey or \"fetch_package_system\",\n                                  installdir = self:installdir({readonly = true}),\n                                  bindirs = self:get(\"bindirs\"),\n                                  version = true, -- we alway check version\n                                  require_version = opt.require_version,\n                                  check = opt.check,\n                                  command = opt.command,\n                                  parse = opt.parse,\n                                  norun = opt.norun,\n                                  system = opt.system,\n                                  force = opt.force})\nend\n\n-- find package\nfunction _instance:find_package(name, opt)\n    opt = opt or {}\n    self._find_package = self._find_package or sandbox_module.import(\"lib.detect.find_package\", {anonymous = true})\n    local system = opt.system\n    if system == nil and not name:startswith(\"xmake::\") then\n        system = true -- find system package by default\n    end\n    local configs = table.clone(self:configs()) or {}\n    if opt.configs then\n        table.join2(configs, opt.configs)\n    end\n    if configs.runtimes then\n        configs.runtimes = self:runtimes()\n    end\n    return self._find_package(name, {\n                              force = opt.force,\n                              installdir = self:installdir({readonly = true}),\n                              bindirs = self:get(\"bindirs\"),\n                              version = true, -- we alway check version\n                              require_version = opt.require_version,\n                              mode = self:mode(),\n                              plat = self:plat(),\n                              arch = self:arch(),\n                              configs = configs,\n                              components = self:components_orderlist(),\n                              components_extsources = opt.components_extsources,\n                              buildhash = self:buildhash(), -- for xmake package or 3rd package manager, e.g. go:: ..\n                              cachekey = opt.cachekey or \"fetch_package_system\",\n                              external = opt.external,\n                              system = system,\n                              -- the following options is only for system::find_package\n                              sourcekind = opt.sourcekind,\n                              package = self,\n                              funcs = opt.funcs,\n                              snippets = opt.snippets,\n                              includes = opt.includes})\nend\n\n-- fetch the local package info\n--\n-- @param opt   the fetch option, e.g. {force = true, external = false, system = true}\n--\n-- @return {packageinfo}, fetchfrom (e.g. xmake/system)\n--\nfunction _instance:fetch(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- attempt to get it from cache\n    local fetchinfo = self._FETCHINFO\n    local usecache = opt.external == nil and opt.system == nil\n    if not opt.force and usecache and fetchinfo then\n        return fetchinfo\n    end\n\n    -- fetch the require version\n    local require_ver = opt.version or self:requireinfo().version\n    if not self:is_thirdparty() and not require_ver:find('.', 1, true) then\n        -- strip branch version only system package\n        require_ver = nil\n    end\n\n    -- nil: find xmake or system packages\n    -- true: only find system package\n    -- false: only find xmake packages\n    local system = opt.system\n    if system == nil then\n        system = self:requireinfo().system\n    end\n    if self:is_thirdparty() then\n        -- we need ignore `{system = true/false}` argument if be 3rd package\n        -- @see https://github.com/xmake-io/xmake/issues/726\n        system = nil\n    end\n\n    -- install only?\n    local project = package._project()\n    if project and project.policy(\"package.install_only\") then\n        system = false\n    end\n\n    -- use sysincludedirs/-isystem instead of -I?\n    local external\n    if opt.external ~= nil then\n        external = opt.external\n    else\n        external = self:use_external_includes()\n    end\n\n    -- always install to the local project directory?\n    -- @see https://github.com/xmake-io/xmake/pull/4376\n    local install_locally\n    if project and project.policy(\"package.install_locally\") then\n        install_locally = true\n    end\n    if install_locally == nil and self:policy(\"package.install_locally\") then\n        install_locally = true\n    end\n    if not self:is_local() and install_locally and system ~= true then\n        local has_global = os.isfile(self:manifest_file())\n        self:_mark_as_local(true)\n        if has_global and not os.isfile(self:manifest_file()) then\n            self:_mark_as_local(false)\n        end\n    end\n\n    -- fetch binary tool?\n    fetchinfo = nil\n    local is_system = nil\n    if self:is_binary() then\n\n        -- only fetch it from the xmake repository first\n        if not fetchinfo and system ~= true and not self:is_thirdparty() then\n            fetchinfo = self:_fetch_tool({require_version = self:version_str(), force = opt.force})\n            if fetchinfo then\n                is_system = self._is_system\n            end\n        end\n\n        -- fetch it from the system directories (disabled for cross-compilation)\n        if not fetchinfo and system ~= false and not self:is_cross() then\n            fetchinfo = self:_fetch_tool({system = true, require_version = require_ver, force = opt.force})\n            if fetchinfo then\n                is_system = true\n            end\n        end\n    else\n\n        -- only fetch it from the xmake repository first\n        if not fetchinfo and system ~= true and not self:is_thirdparty() then\n            fetchinfo = self:_fetch_library({require_version = self:version_str(), external = external, force = opt.force})\n            if fetchinfo then\n                is_system = self._is_system\n            end\n        end\n\n        -- fetch it from the system and external package sources\n        if not fetchinfo and system ~= false then\n            fetchinfo = self:_fetch_library({system = true, require_version = require_ver, external = external, force = opt.force})\n            if fetchinfo then\n                is_system = true\n            end\n        end\n    end\n\n    -- save to cache\n    if usecache then\n        self._FETCHINFO = fetchinfo\n    end\n\n    -- we need to update the real version if it's system package\n    -- @see https://github.com/xmake-io/xmake/issues/3333\n    if is_system and fetchinfo and fetchinfo.version then\n        local fetch_version = semver.new(fetchinfo.version)\n        if fetch_version then\n            self._VERSION = fetch_version\n            self._VERSION_STR = fetchinfo.version\n        end\n    end\n\n    -- mark as system package?\n    if is_system ~= nil then\n        self._is_system = is_system\n    end\n    return fetchinfo\nend\n\n-- exists this package?\nfunction _instance:exists()\n    return self._FETCHINFO ~= nil\nend\n\n-- fetch library dependencies\nfunction _instance:fetch_librarydeps()\n    local fetchinfo = self:fetch()\n    if not fetchinfo then\n        return\n    end\n    fetchinfo = table.clone(fetchinfo, 3) -- avoid the cached fetchinfo be modified\n    local librarydeps = self:librarydeps()\n    if librarydeps then\n        for _, dep in ipairs(librarydeps) do\n            local depinfo = dep:fetch()\n            if depinfo then\n                for name, values in pairs(depinfo) do\n                    if name ~= \"license\" and name ~= \"version\" then\n                        fetchinfo[name] = table.wrap(fetchinfo[name])\n                        table.join2(fetchinfo[name], values)\n                    end\n                end\n            end\n        end\n    end\n    if fetchinfo then\n        for name, values in pairs(fetchinfo) do\n            if name == \"links\" or name == \"syslinks\" or name == \"frameworks\" then\n                fetchinfo[name] = table.unwrap(table.reverse_unique(table.wrap(values)))\n            else\n                fetchinfo[name] = table.unwrap(table.unique(table.wrap(values)))\n            end\n        end\n    end\n    return fetchinfo\nend\n\n-- get the patches of the current version\n--\n-- @code\n-- add_patches(\"6.7.6\", \"https://cdn.kernel.org/pub/linux/kernel/v6.x/patch-6.7.6.xz\",\n--    \"a394326aa325f8a930a4ce33c69ba7b8b454aef1107a4d3c2a8ae12908615fc4\", {reverse = true})\n-- @endcode\n--\nfunction _instance:patches()\n    return self:current_scheme():patches()\nend\n\n-- get the resources of the current version\nfunction _instance:resources()\n    return self:current_scheme():resources()\nend\n\n-- get the the given resource\nfunction _instance:resource(name)\n    local resources = self:resources()\n    return resources and resources[name] or nil\nend\n\n-- get the the given resource file\nfunction _instance:resourcefile(name)\n    local resource = self:resource(name)\n    if resource and resource.url then\n        return path.join(self:cachedir(), \"resources\", name, (path.filename(resource.url):gsub(\"%?.+$\", \"\")))\n    end\nend\n\n-- get the the given resource directory\nfunction _instance:resourcedir(name)\n    local resource = self:resource(name)\n    if resource and resource.url then\n        local resourceurl = resource.url\n        local resourcedir = path.join(self:cachedir(), \"resources\", name, (path.filename(resourceurl):gsub(\"%?.+$\", \"\")))\n        if not resourceurl:startswith(\"git://\") and not resourceurl:endswith(\".git\") then\n            resourcedir = resourcedir .. \".dir\"\n        end\n        return resourcedir\n    end\nend\n\n-- get the given package component\nfunction _instance:component(name)\n    return self:components()[name]\nend\n\n-- get package components\n--\n-- .e.g. add_components(\"graphics\", \"windows\")\n--\nfunction _instance:components()\n    local components = self._COMPONENTS\n    if not components then\n        components = {}\n        for _, name in ipairs(table.wrap(self:get(\"components\"))) do\n            components[name] = component.new(name, {package = self})\n        end\n        self._COMPONENTS = components\n    end\n    return components\nend\n\n-- get package dependencies of components\n--\n-- @see https://github.com/xmake-io/xmake/issues/2636#issuecomment-1284787681\n--\n-- @code\n-- add_components(\"graphics\", {deps = \"window\"})\n-- @endcode\n--\n-- or\n--\n-- @code\n-- on_component(function (package, component))\n--     component:add(\"deps\", \"window\")\n-- end)\n-- @endcode\n--\nfunction _instance:components_deps()\n    local components_deps = self._COMPONENTS_DEPS\n    if not components_deps then\n        components_deps = {}\n        for _, name in ipairs(table.wrap(self:get(\"components\"))) do\n            components_deps[name] = self:extraconf(\"components\", name, \"deps\") or self:component(name):get(\"deps\")\n        end\n        self._COMPONENTS_DEPS = components_deps\n    end\n    return components_deps\nend\n\n-- get default components\n--\n-- @see https://github.com/xmake-io/xmake/issues/3164\n--\n-- @code\n-- add_components(\"graphics\", {default = true})\n-- @endcode\n--\n-- or\n--\n-- @code\n-- on_component(function (package, component))\n--     component:set(\"default\", true)\n-- end)\n-- @endcode\n--\nfunction _instance:components_default()\n    local components_default = self._COMPONENTS_DEFAULT\n    if not components_default then\n        for _, name in ipairs(table.wrap(self:get(\"components\"))) do\n            if self:extraconf(\"components\", name, \"default\") or self:component(name):get(\"default\") then\n                components_default = components_default or {}\n                table.insert(components_default, name)\n            end\n        end\n        self._COMPONENTS_DEFAULT = components_default or false\n    end\n    return components_default or nil\nend\n\n-- get package components list with dependencies order\nfunction _instance:components_orderlist()\n    local components_orderlist = self._COMPONENTS_ORDERLIST\n    if not components_orderlist then\n        components_orderlist = {}\n        for _, name in ipairs(table.wrap(self:get(\"components\"))) do\n            table.insert(components_orderlist, name)\n            table.join2(components_orderlist, self:_sort_componentdeps(name))\n        end\n        components_orderlist = table.reverse_unique(components_orderlist)\n        self._COMPONENTS_ORDERLIST = components_orderlist\n    end\n    return components_orderlist\nend\n\n-- sort component deps\nfunction _instance:_sort_componentdeps(name)\n    local orderdeps = {}\n    local plaindeps = self:components_deps() and self:components_deps()[name]\n    for _, dep in ipairs(table.wrap(plaindeps)) do\n        table.insert(orderdeps, dep)\n        table.join2(orderdeps, self:_sort_componentdeps(dep))\n    end\n    return orderdeps\nend\n\n-- get the given package scheme\nfunction _instance:scheme(name)\n    if not name then\n        os.raise(\"scheme name is required\")\n    end\n    local scheme = self:schemes()[name]\n    if not scheme then\n        os.raise(\"scheme %s not found\", name)\n    end\n    return scheme\nend\n\n-- set current scheme\nfunction _instance:current_scheme_set(scheme)\n    self._CURRENT_SCHEME = scheme\nend\n\n-- get current scheme\nfunction _instance:current_scheme()\n    if self._CURRENT_SCHEME == nil then\n        local schemes_orderlist = self:schemes_orderlist()\n        if #schemes_orderlist > 0 then\n            self._CURRENT_SCHEME = schemes_orderlist[1]\n        end\n    end\n    return self._CURRENT_SCHEME\nend\n\n-- get package schemes\n--\n-- .e.g. add_schemes(\"binary\", \"source\")\n--\nfunction _instance:schemes()\n    local schemes = self._SCHEMES\n    if not schemes then\n        schemes = {}\n        for _, scheme in ipairs(self:schemes_orderlist()) do\n            schemes[scheme:name()] = scheme\n        end\n        self._SCHEMES = schemes\n    end\n    return schemes\nend\n\n-- get package schemes list (ordered)\nfunction _instance:schemes_orderlist()\n    local schemes_orderlist = self._SCHEMES_ORDERLIST\n    if not schemes_orderlist then\n        schemes_orderlist = {}\n        local scheme_names = table.wrap(self:get(\"schemes\"))\n        if #scheme_names == 0 then\n            scheme_names = {\"__default__\"}\n        end\n        for _, name in ipairs(scheme_names) do\n            table.insert(schemes_orderlist, scheme.new(name, {package = self}))\n        end\n        self._SCHEMES_ORDERLIST = schemes_orderlist\n    end\n    return schemes_orderlist\nend\n\n-- prepare to install the given scheme\nfunction _instance:prepare_install_scheme(scheme)\n    self:current_scheme_set(scheme)\n\n    -- reset manifest to trigger reinstalling\n    self._MANIFEST = nil\nend\n\n-- generate lto configs\nfunction _instance:_generate_lto_configs(sourcekind)\n\n    -- add cflags\n    local configs = {}\n    if sourcekind then\n        local _, cc = self:tool(sourcekind)\n        local cflag = sourcekind == \"cxx\" and \"cxxflags\" or \"cflags\"\n        if cc == \"cl\" then\n            configs[cflag] = \"-GL\"\n        elseif cc == \"clang\" or cc == \"clangxx\" or cc == \"clang_cl\" then\n            configs[cflag] = \"-flto=thin\"\n        elseif cc == \"gcc\" or cc == \"gxx\" then\n            configs[cflag] = \"-flto\"\n        end\n    end\n\n    -- add ldflags and shflags\n    local _, ld = self:tool(\"ld\")\n    if ld == \"link\" then\n        configs.ldflags = \"-LTCG\"\n        configs.shflags = \"-LTCG\"\n    elseif ld == \"clang\" or ld == \"clangxx\" then\n        configs.ldflags = \"-flto=thin\"\n        configs.shflags = \"-flto=thin\"\n    elseif ld == \"gcc\" or ld == \"gxx\" then\n        configs.ldflags = \"-flto\"\n        configs.shflags = \"-flto\"\n    end\n    return configs\nend\n\n-- generate sanitizer configs\nfunction _instance:_generate_sanitizer_configs(checkmode, sourcekind)\n    local toolchain_utils = sandbox_module.import(\"private.utils.toolchain\", {anonymous = true})\n    return toolchain_utils.get_sanitizer_flags(self, {checkmode = checkmode, sourcekind = sourcekind})\nend\n\n-- generate building configs for has_xxx/check_xxx\nfunction _instance:_generate_build_configs(configs, opt)\n    opt = opt or {}\n    configs = table.join(self:fetch_librarydeps() or {}, configs)\n    -- since we are ignoring the runtimes of the headeronly library,\n    -- we can only get the runtimes from the dependency library to detect the link.\n    local runtimes = self:runtimes()\n    if self:is_headeronly() and not runtimes and self:librarydeps() then\n        for _, dep in ipairs(self:librarydeps()) do\n            if dep:is_plat(\"windows\") and dep:runtimes() then\n                runtimes = dep:runtimes()\n                break\n            end\n        end\n    end\n    if runtimes then\n        -- @note we need to patch package:sourcekinds(), because it wiil be called nf_runtime for gcc/clang\n        local sourcekind = opt.sourcekind or \"cxx\"\n        self.sourcekinds = function (self)\n            return sourcekind\n        end\n        local compiler = self:compiler(sourcekind)\n        local cxflags = compiler:map_flags(\"runtime\", runtimes, {target = self})\n        configs.cxflags = table.wrap(configs.cxflags)\n        table.insert(configs.cxflags, cxflags)\n\n        local ldflags = self:linker(\"binary\", sourcekind):map_flags(\"runtime\", runtimes, {target = self})\n        configs.ldflags = table.wrap(configs.ldflags)\n        table.insert(configs.ldflags, ldflags)\n\n        local shflags = self:linker(\"shared\", sourcekind):map_flags(\"runtime\", runtimes, {target = self})\n        configs.shflags = table.wrap(configs.shflags)\n        table.insert(configs.shflags, shflags)\n        self.sourcekinds = nil\n    end\n    if self:config(\"lto\") then\n        local configs_lto = self:_generate_lto_configs(opt.sourcekind or \"cxx\")\n        if configs_lto then\n            for k, v in pairs(configs_lto) do\n                configs[k] = table.wrap(configs[k] or {})\n                table.join2(configs[k], v)\n            end\n        end\n    end\n    if self:config(\"asan\") then\n        local configs_asan = self:_generate_sanitizer_configs(\"address\", opt.sourcekind or \"cxx\")\n        if configs_asan then\n            for k, v in pairs(configs_asan) do\n                configs[k] = table.wrap(configs[k] or {})\n                table.join2(configs[k], v)\n            end\n        end\n    end\n    -- enable exceptions for msvc by default\n    if opt.sourcekind == \"cxx\" and configs.exceptions == nil and self:has_tool(\"cxx\", \"cl\") then\n        configs.exceptions = \"cxx\"\n    end\n\n    -- pass user flags to on_test, because some flags need be passed to ldflags in on_test\n    -- e.g. add_requireconfs(\"**\", {configs = {cxflags = \"/fsanitize=address\", ldflags = \"/fsanitize=address\"}})\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/4046\n    --\n    for name, flags in pairs(self:configs()) do\n        if name:endswith(\"flags\") and self:extraconf(\"configs\", name, \"builtin\") then\n            configs[name] = table.wrap(configs[name] or {})\n            table.join2(configs[name], flags)\n        end\n    end\n\n    if configs and (configs.ldflags or configs.shflags) then\n        configs.force = {ldflags = configs.ldflags, shflags = configs.shflags}\n        configs.ldflags = nil\n        configs.shflags = nil\n    end\n\n    -- check links for library\n    if self:is_library() and not self:is_headeronly() and not self:is_moduleonly()\n        and self:exists() then -- we need to skip it if it's in on_check, @see https://github.com/xmake-io/xmake-repo/pull/4834\n        local links = table.wrap(configs.links)\n        local ldflags = table.wrap(configs.ldflags)\n        local frameworks = table.wrap(configs.frameworks)\n        if #links == 0 and #ldflags == 0 and #frameworks == 0 then\n            os.raise(\"package(%s): links not found!\", self:name())\n        end\n    end\n    return configs\nend\n\n-- has the given c funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cfuncs(funcs, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cc\"})\n    return sandbox_module.import(\"lib.detect.has_cfuncs\", {anonymous = true})(funcs, opt)\nend\n\n-- has the given c++ funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxfuncs(funcs, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cxx\"})\n    return sandbox_module.import(\"lib.detect.has_cxxfuncs\", {anonymous = true})(funcs, opt)\nend\n\n-- has the given c types?\n--\n-- @param types     the types\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_ctypes(types, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cc\"})\n    return sandbox_module.import(\"lib.detect.has_ctypes\", {anonymous = true})(types, opt)\nend\n\n-- has the given c++ types?\n--\n-- @param types     the types\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxtypes(types, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cxx\"})\n    return sandbox_module.import(\"lib.detect.has_cxxtypes\", {anonymous = true})(types, opt)\nend\n\n-- has the given c includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cincludes(includes, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cc\"})\n    return sandbox_module.import(\"lib.detect.has_cincludes\", {anonymous = true})(includes, opt)\nend\n\n-- has the given c++ includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxincludes(includes, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cxx\"})\n    return sandbox_module.import(\"lib.detect.has_cxxincludes\", {anonymous = true})(includes, opt)\nend\n\n-- has the given c flags?\n--\n-- @param flags     the flags\n-- @param opt       the argument options, e.g. { flagskey = \"xxx\" }\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cflags(flags, opt)\n    local compinst = self:compiler(\"cc\")\n    return compinst:has_flags(flags, \"cflags\", opt)\nend\n\n-- has the given c++ flags?\n--\n-- @param flags     the flags\n-- @param opt       the argument options, e.g. { flagskey = \"xxx\" }\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxflags(flags, opt)\n    local compinst = self:compiler(\"cxx\")\n    return compinst:has_flags(flags, \"cxxflags\", opt)\nend\n\n-- has the given features?\n--\n-- @param features  the features, e.g. {\"c_static_assert\", \"cxx_constexpr\"}\n-- @param opt       the argument options, e.g. {flags = \"\"}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_features(features, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"core.tool.compiler\", {anonymous = true}).has_features(features, opt)\nend\n\n-- check the size of type\n--\n-- @param typename  the typename\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          the type size\n--\nfunction _instance:check_sizeof(typename, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.check_sizeof\", {anonymous = true})(typename, opt)\nend\n\n-- check the given c snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_csnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cc\"})\n    return sandbox_module.import(\"lib.detect.check_csnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given c++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_cxxsnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"cxx\"})\n    return sandbox_module.import(\"lib.detect.check_cxxsnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given objc snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_msnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"mm\"})\n    return sandbox_module.import(\"lib.detect.check_msnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given objc++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_mxxsnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"mxx\"})\n    return sandbox_module.import(\"lib.detect.check_mxxsnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given fortran snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}, linkerkind = \"fc\", \"cxx\" ...}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_fcsnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    opt.configs = self:_generate_build_configs(opt.configs, {sourcekind = \"fc\"})\n    return sandbox_module.import(\"lib.detect.check_fcsnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given importfiles?\n--\n-- @param names     the import filenames (without .pc/.cmake extension), e.g. pkgconfig::libxml-2.0, cmake::CURL\n-- @param opt       the argument options\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_importfiles(names, opt)\n    opt = opt or {}\n    if opt.PKG_CONFIG_PATH == nil then\n        local PKG_CONFIG_PATH = {}\n        local linkdirs = table.wrap(self:get(\"linkdirs\") or \"lib\")\n        local installdir = self:installdir()\n        for _, linkdir in ipairs(linkdirs) do\n            table.insert(PKG_CONFIG_PATH, path.join(installdir, linkdir, \"pkgconfig\"))\n        end\n        opt.PKG_CONFIG_PATH = PKG_CONFIG_PATH\n    end\n    if opt.CMAKE_PREFIX_PATH == nil then\n        opt.CMAKE_PREFIX_PATH = self:installdir()\n    end\n    return sandbox_module.import(\"lib.detect.check_importfiles\", {anonymous = true})(names or (\"pkgconfig::\" .. self:name()), opt)\nend\n\n-- the current mode is belong to the given modes?\nfunction package._api_is_mode(interp, ...)\n    return config.is_mode(...)\nend\n\n-- the current platform is belong to the given platforms?\nfunction package._api_is_plat(interp, ...)\n    local plat = package.targetplat()\n    for _, v in ipairs(table.join(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current platform is belong to the given architectures?\nfunction package._api_is_arch(interp, ...)\n    local arch = package.targetarch()\n    for _, v in ipairs(table.join(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- the current host is belong to the given hosts?\nfunction package._api_is_host(interp, ...)\n    return os.is_host(...)\nend\n\n-- the interpreter\nfunction package._interpreter()\n    local interp = package._INTERPRETER\n    if not interp then\n        interp = interpreter.new()\n        interp:api_define(package.apis())\n        interp:api_define(language.apis())\n        package._INTERPRETER = interp\n    end\n    return interp\nend\n\n-- get package memcache\nfunction package._memcache()\n    return memcache.cache(\"core.base.package\")\nend\n\n-- get project\nfunction package._project()\n    local project = package._PROJECT\n    if not project then\n        if os.isfile(os.projectfile()) then\n            project = require(\"project/project\")\n        end\n    end\n    return project\nend\n\n-- get global target platform of package\nfunction package.targetplat()\n    local plat = package._memcache():get(\"target_plat\")\n    if plat == nil then\n        if not plat and package._project() then\n            local targetplat_root = package._project().get(\"target.plat\")\n            if targetplat_root then\n                plat = targetplat_root\n            end\n        end\n        if not plat then\n            plat = config.get(\"plat\") or os.subhost()\n        end\n        package._memcache():set(\"target_plat\", plat)\n    end\n    return plat\nend\n\n-- get global target architecture of package\nfunction package.targetarch()\n    local arch = package._memcache():get(\"target_arch\")\n    if arch == nil then\n        if not arch and package._project() then\n            local targetarch_root = package._project().get(\"target.arch\")\n            if targetarch_root then\n                arch = targetarch_root\n            end\n        end\n        if not arch then\n            arch = config.get(\"arch\") or os.subarch()\n        end\n        package._memcache():set(\"target_arch\", arch)\n    end\n    return arch\nend\n\n-- get package apis\nfunction package.apis()\n\n    return\n    {\n        values =\n        {\n            -- package.set_xxx\n            \"package.set_urls\"\n        ,   \"package.set_kind\"\n        ,   \"package.set_plat\" -- deprecated\n        ,   \"package.set_arch\" -- deprecated\n        ,   \"package.set_base\"\n        ,   \"package.set_license\"\n        ,   \"package.set_installtips\"\n        ,   \"package.set_homepage\"\n        ,   \"package.set_description\"\n        ,   \"package.set_parallelize\"\n        ,   \"package.set_sourcedir\"\n        ,   \"package.set_cachedir\"\n        ,   \"package.set_installdir\"\n        ,   \"package.add_bindirs\"\n        ,   \"package.add_schemes\"\n            -- package.add_xxx\n        ,   \"package.add_deps\"\n        ,   \"package.add_urls\"\n        ,   \"package.add_imports\"\n        ,   \"package.add_configs\"\n        ,   \"package.add_extsources\"\n        ,   \"package.add_components\"\n        }\n    ,   script =\n        {\n            -- package.on_xxx\n            \"package.on_source\"\n        ,   \"package.on_load\"\n        ,   \"package.on_fetch\"\n        ,   \"package.on_check\"\n        ,   \"package.on_download\"\n        ,   \"package.on_install\"\n        ,   \"package.on_test\"\n        ,   \"package.on_component\"\n        }\n    ,   keyvalues =\n        {\n            -- package.set_xxx\n            \"package.set_policy\"\n            -- package.add_xxx\n        ,   \"package.add_patches\"\n        ,   \"package.add_resources\"\n        }\n    ,   paths =\n        {\n            -- package.add_xxx\n            \"package.add_versionfiles\"\n        }\n    ,   dictionary =\n        {\n            -- package.add_xxx\n            \"package.add_versions\"\n        }\n    ,   custom =\n        {\n            -- is_xxx\n            { \"is_host\", package._api_is_host }\n        ,   { \"is_mode\", package._api_is_mode }\n        ,   { \"is_plat\", package._api_is_plat }\n        ,   { \"is_arch\", package._api_is_arch }\n        }\n    }\nend\n\n-- the cache directory\nfunction package.cachedir(opt)\n    opt = opt or {}\n    local cachedir = package._CACHEDIR\n    if not cachedir then\n        cachedir = os.getenv(\"XMAKE_PKG_CACHEDIR\") or global.get(\"pkg_cachedir\") or path.join(global.cachedir(), \"packages\")\n        package._CACHEDIR = cachedir\n    end\n    if opt.rootonly then\n        return cachedir\n    end\n    return path.join(cachedir, os.date(\"%y%m\"))\nend\n\n-- the install directory\nfunction package.installdir()\n    local installdir = package._INSTALLDIR\n    if not installdir then\n        installdir = os.getenv(\"XMAKE_PKG_INSTALLDIR\") or global.get(\"pkg_installdir\") or path.join(global.directory(), \"packages\")\n        package._INSTALLDIR = installdir\n    end\n    return installdir\nend\n\n-- the search directories\nfunction package.searchdirs()\n    local searchdirs = global.get(\"pkg_searchdirs\")\n    if searchdirs then\n        return path.splitenv(searchdirs)\n    end\nend\n\n-- load the package from the system directories\nfunction package.load_from_system(packagename)\n\n    -- get it directly from cache first\n    local instance = package._memcache():get2(\"packages\", packagename)\n    if instance then\n        return instance\n    end\n\n    -- get package info\n    local packageinfo = {}\n    local is_thirdparty = false\n    if packagename:find(\"::\", 1, true) then\n\n        -- get interpreter\n        local interp = package._interpreter()\n\n        -- on install script\n        local on_install = function (pkg)\n            local opt = {}\n            local configs       = table.clone(pkg:configs()) or {}\n            opt.configs         = configs\n            opt.mode            = pkg:is_debug() and \"debug\" or \"release\"\n            opt.plat            = pkg:plat()\n            opt.arch            = pkg:arch()\n            opt.require_version = pkg:version_str()\n            opt.buildhash       = pkg:buildhash()\n            opt.cachedir        = pkg:cachedir()\n            opt.installdir      = pkg:installdir()\n            if configs.runtimes then\n                configs.runtimes = pkg:runtimes()\n            end\n            import(\"package.manager.install_package\")(pkg:name(), opt)\n        end\n\n        -- make sandbox instance with the given script\n        instance, errors = sandbox.new(on_install, {filter = interp:filter(), namespace = interp:namespace()})\n        if not instance then\n            return nil, errors\n        end\n\n        -- save the install script\n        packageinfo.install = instance:script()\n\n        -- is third-party package?\n        if not packagename:startswith(\"xmake::\") then\n            is_thirdparty = true\n        end\n    end\n\n    -- new an instance\n    instance = _instance.new(packagename, scopeinfo.new(\"package\", packageinfo))\n\n    -- mark as system or 3rd package\n    instance._is_system = true\n    instance._is_thirdparty = is_thirdparty\n\n    if is_thirdparty then\n        -- add configurations for the 3rd package\n        local configurations = sandbox_module.import(\"package.manager.\" .. packagename:split(\"::\")[1]:lower() .. \".configurations\", {try = true, anonymous = true})\n        if configurations then\n            for name, conf in pairs(configurations()) do\n                instance:add(\"configs\", name, conf)\n            end\n        end\n\n        -- disable parallelize for installation\n        instance:set(\"parallelize\", false)\n    end\n\n    -- save instance to the cache\n    package._memcache():set2(\"packages\", instance)\n    return instance\nend\n\n-- load the package from the project file\nfunction package.load_from_project(packagename, project)\n\n    -- get it directly from cache first\n    local instance = package._memcache():get2(\"packages\", packagename)\n    if instance then\n        return instance\n    end\n\n    -- load packages (with cache)\n    local packages, errors = project.packages()\n    if not packages then\n        return nil, errors\n    end\n\n    -- get package info\n    local packageinfo = packages[packagename]\n    if packageinfo == nil and project.namespaces() then\n        for _, namespace in ipairs(project.namespaces()) do\n            packageinfo = packages[namespace .. \"::\" .. packagename]\n            if packageinfo then\n                packagename = namespace .. \"::\" .. packagename\n                break\n            end\n        end\n    end\n    if packageinfo == nil then\n        return\n    end\n\n    -- new an instance\n    instance = _instance.new(packagename, packageinfo, {scriptdir = os.projectdir()})\n    package._memcache():set2(\"packages\", instance)\n    return instance\nend\n\n-- load the package from the package directory or package description file\nfunction package.load_from_repository(packagename, packagedir, opt)\n\n    -- get it directly from cache first\n    opt = opt or {}\n    local instance = package._memcache():get2(\"packages\", packagename)\n    if instance then\n        return instance\n    end\n\n\n    -- find the package script path\n    local scriptpath = opt.packagefile\n    if not opt.packagefile and packagedir then\n        scriptpath = path.join(packagedir, \"xmake.lua\")\n    end\n    if not scriptpath or not os.isfile(scriptpath) then\n        return nil, string.format(\"package %s not found!\", packagename)\n    end\n\n    -- get interpreter\n    local interp = package._interpreter()\n\n    -- we need to modify plat/arch in description scope at same time\n    -- if plat/arch are passed to add_requires.\n    --\n    -- @see https://github.com/orgs/xmake-io/discussions/3439\n    --\n    -- e.g. add_requires(\"zlib~mingw\", {plat = \"mingw\", arch = \"x86_64\"})\n    --\n    if opt.plat then\n        package._memcache():set(\"target_plat\", opt.plat)\n    end\n    if opt.arch then\n        package._memcache():set(\"target_arch\", opt.arch)\n    end\n\n    -- load script\n    local ok, errors = interp:load(scriptpath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load package and disable filter, we will process filter after a while\n    local results, errors = interp:make(\"package\", true, false)\n    if not results then\n        return nil, errors\n    end\n\n    -- get package info\n    local packageinfo = results[packagename]\n    if not packageinfo then\n        return nil, string.format(\"%s: package(%s) not found!\", scriptpath, packagename)\n    end\n\n    -- new an instance\n    instance = _instance.new(packagename, packageinfo, {scriptdir = path.directory(scriptpath), repo = opt.repo})\n\n    -- reset plat/arch\n    if opt.plat then\n        package._memcache():set(\"target_plat\", nil)\n    end\n    if opt.arch then\n        package._memcache():set(\"target_arch\", nil)\n    end\n\n    -- save instance to the cache\n    package._memcache():set2(\"packages\", instance)\n    return instance\nend\n\n-- new a package instance\nfunction package.new(...)\n    return _instance.new(...)\nend\n\n\n-- return module\nreturn package\n"
  },
  {
    "path": "xmake/core/package/repository.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        repository.lua\n--\n\n-- define module\nlocal repository = repository or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal utils       = require(\"base/utils\")\nlocal string      = require(\"base/string\")\nlocal global      = require(\"base/global\")\nlocal config      = require(\"project/config\")\nlocal interpreter = require(\"base/interpreter\")\nlocal localcache  = require(\"cache/localcache\")\nlocal globalcache = require(\"cache/globalcache\")\n\n-- new an instance\nfunction _instance.new(name, url, branch, directory, is_global)\n\n    -- new an instance\n    local instance = table.inherit(_instance)\n\n    -- init instance\n    instance._NAME      = name\n    instance._URL       = url\n    instance._BRANCH    = branch\n    instance._DIRECTORY = directory\n    instance._IS_GLOBAL = is_global\n    return instance\nend\n\n\n-- get the repository name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the repository url\nfunction _instance:url()\n    return self._URL\nend\n\n-- get the repository branch\nfunction _instance:branch()\n    return self._BRANCH\nend\n\n-- get the current commit\nfunction _instance:commit()\n    return self._COMMIT\nend\n\n-- set the commit\nfunction _instance:commit_set(commit)\n    self._COMMIT = commit\nend\n\n-- is global repository?\nfunction _instance:is_global()\n    return self._IS_GLOBAL\nend\n\n-- get the repository directory\nfunction _instance:directory()\n    return self._DIRECTORY\nend\n\n\n-- get cache\nfunction repository._cache(is_global)\n    if is_global then\n        return globalcache.cache(\"repository\")\n    else\n        return localcache.cache(\"repository\")\n    end\nend\n\n-- the interpreter\nfunction repository._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if repository._INTERPRETER then\n        return repository._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(repository.apis())\n\n    -- save interpreter\n    repository._INTERPRETER = interp\n    return interp\nend\n\n-- get repository apis\nfunction repository.apis()\n\n    return\n    {\n        values =\n        {\n            -- set_xxx\n            \"set_description\"\n        }\n    }\nend\n\n-- get the local or global repository directory\nfunction repository.directory(is_global)\n\n    -- get directory\n    if is_global then\n        return path.join(global.directory(), \"repositories\")\n    else\n        return path.join(config.directory(), \"repositories\")\n    end\nend\n\n-- load the repository\nfunction repository.load(name, url, branch, is_global)\n\n    -- check url\n    if not url then\n        return nil, string.format(\"invalid repo(%s): url not found!\", name)\n    end\n\n    -- get it directly from cache first\n    repository._REPOS = repository._REPOS or {}\n    if repository._REPOS[name] then\n        return repository._REPOS[name]\n    end\n\n    -- the repository directory\n    local repodir = os.isdir(url) and path.absolute(url) or path.join(repository.directory(is_global), name)\n\n    -- new an instance\n    local instance, errors = _instance.new(name, url, branch, repodir, is_global)\n    if not instance then\n        return nil, errors\n    end\n\n    -- save instance to the cache\n    repository._REPOS[name] = instance\n    return instance\nend\n\n-- get repository url from the given name\nfunction repository.get(name, is_global)\n\n    -- get it\n    local repositories = repository.repositories(is_global)\n    if repositories then\n        local repoinfo = repositories[name]\n        if type(repoinfo) == \"table\" then\n            return repoinfo[1], repoinfo[2]\n        else\n            return repoinfo\n        end\n    end\nend\n\n-- add repository url to the given name\nfunction repository.add(name, url, branch, is_global)\n\n    -- no name?\n    if not name then\n        return false, string.format(\"please set name to repository: %s\", url)\n    end\n\n    -- get repositories\n    local repositories = repository.repositories(is_global) or {}\n\n    -- set it\n    repositories[name] = {url, branch}\n\n    -- save repositories\n    repository._cache(is_global):set(\"repositories\", repositories)\n    repository._cache(is_global):save()\n    return true\nend\n\n-- remove repository from gobal or local directory\nfunction repository.remove(name, is_global)\n\n    -- get repositories\n    local repositories = repository.repositories(is_global) or {}\n    if not repositories[name] then\n        return false, string.format(\"repository(%s): not found!\", name)\n    end\n\n    -- remove it\n    repositories[name] = nil\n\n    -- save repositories\n    repository._cache(is_global):set(\"repositories\", repositories)\n    repository._cache(is_global):save()\n    return true\nend\n\n-- clear all repositories\nfunction repository.clear(is_global)\n    repository._cache(is_global):set(\"repositories\", {})\n    repository._cache(is_global):save()\n    return true\nend\n\n\n-- get all repositories from global or local directory\nfunction repository.repositories(is_global)\n    return repository._cache(is_global):get(\"repositories\")\nend\n\n-- return module\nreturn repository\n"
  },
  {
    "path": "xmake/core/package/scheme.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scheme.lua\n--\n\n-- @ref         https://github.com/xmake-io/xmake/issues/7184\n-- @note        This module provides scheme management for packages,\n--              allowing custom download schemes and configurations\n--              to be defined and applied to package management.\n\n-- define module\nlocal scheme = scheme or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal io             = require(\"base/io\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal option         = require(\"base/option\")\nlocal hashset        = require(\"base/hashset\")\nlocal scopeinfo      = require(\"base/scopeinfo\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal language       = require(\"language/language\")\nlocal sandbox        = require(\"sandbox/sandbox\")\n\n-- new an instance\nfunction _instance.new(name, opt)\n    opt = opt or {}\n    local instance = table.inherit(_instance)\n    instance._NAME    = name\n    instance._INFO    = scopeinfo.new(\"scheme\", {}, {interpreter = scheme._interpreter()})\n    instance._PACKAGE = opt.package\n    return instance\nend\n\n-- get the scheme name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the type: scheme\nfunction _instance:type()\n    return \"scheme\"\nend\n\n-- is default scheme?\nfunction _instance:is_default()\n    return self:name() == \"__default__\"\nend\n\n-- is precompiled scheme?\nfunction _instance:is_precompiled()\n    return self:name() == \"__precompiled__\"\nend\n\n-- get the it's package\nfunction _instance:package()\n    return self._PACKAGE\nend\n\n-- get the scheme configuration\nfunction _instance:get(name)\n    local value = self._INFO:get(name)\n    if value == nil and self:is_default() and self:package() then\n        value = self:package():get(name)\n    end\n    return value\nend\n\n-- set the value to scheme info\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\nend\n\n-- add the value to scheme info\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    local value = self._INFO:extraconf(name, item, key)\n    if value == nil and self:is_default() and self:package() then\n        value = self:package():extraconf(name, item, key)\n    end\n    return value\nend\n\n-- set the extra configuration\nfunction _instance:extraconf_set(name, item, key, value)\n    return self._INFO:extraconf_set(name, item, key, value)\nend\n\n-- get urls\nfunction _instance:urls()\n    local urls = self._URLS\n    if urls == nil then\n        urls = table.wrap(self:get(\"urls\"))\n        if #urls == 1 and urls[1] == \"\" then\n            urls = {}\n        end\n    end\n    return urls\nend\n\n-- set urls\nfunction _instance:urls_set(urls)\n    self._URLS = urls\nend\n\n-- get the alias of url, @note need raw url\nfunction _instance:url_alias(url)\n    return self:extraconf(\"urls\", url, \"alias\")\nend\n\n-- get the version filter of url, @note need raw url\nfunction _instance:url_version(url)\n    return self:extraconf(\"urls\", url, \"version\")\nend\n\n-- get the excludes paths of url\n-- @note it supports the path pattern, but it only supports for archiver.\nfunction _instance:url_excludes(url)\n    return self:extraconf(\"urls\", url, \"excludes\")\nend\n\n-- get the includes paths of url\n-- @note it does not support the path pattern, and it only supports for git url now.\n-- @see https://github.com/xmake-io/xmake/issues/6071\nfunction _instance:url_includes(url)\n    return self:extraconf(\"urls\", url, \"includes\")\nend\n\n-- get the http headers of url, @note need raw url\nfunction _instance:url_http_headers(url)\n    return self:extraconf(\"urls\", url, \"http_headers\")\nend\n\n-- get the script directory\nfunction _instance:scriptdir()\n    local scriptdir = self._SCRIPTDIR\n    if not scriptdir then\n        if self:package() then\n            scriptdir = self:package():scriptdir()\n        end\n        self._SCRIPTDIR = scriptdir\n    end\n    return scriptdir\nend\n\n-- get versions\nfunction _instance:versions()\n    if self._VERSIONS == nil then\n        -- we need to sort the build number in semver list\n        -- https://github.com/xmake-io/xmake/issues/6953\n        local versions = {}\n        for version, _ in table.orderpairs(self:_versions_list()) do\n            -- remove the url alias prefix if exists\n            local pos = version:find(':', 1, true)\n            if pos then\n                version = version:sub(pos + 1, -1)\n            end\n            table.insert(versions, version)\n        end\n        self._VERSIONS = table.unique(versions)\n    end\n    return self._VERSIONS\nend\n\n-- get versions list\nfunction _instance:_versions_list()\n    if self._VERSIONS_LIST == nil then\n        local versions = table.wrap(self:get(\"versions\"))\n        local versionfiles = self:get(\"versionfiles\")\n        if versionfiles then\n            for _, versionfile in ipairs(table.wrap(versionfiles)) do\n                if not path.is_absolute(versionfile) then\n                    local subpath = versionfile\n                    versionfile = path.join(self:scriptdir(), subpath)\n                    if not os.isfile(versionfile) and self:package() and self:package():base() then\n                        versionfile = path.join(self:package():base():scriptdir(), subpath)\n                    end\n                end\n                if os.isfile(versionfile) then\n                    local list = io.readfile(versionfile)\n                    for _, line in ipairs(list:split(\"\\n\")) do\n                        local splitinfo = line:split(\"%s+\")\n                        if #splitinfo == 2 then\n                            local version = splitinfo[1]\n                            local shasum = splitinfo[2]\n                            versions[version] = shasum\n                        end\n                    end\n                end\n            end\n        end\n        self._VERSIONS_LIST = versions\n    end\n    return self._VERSIONS_LIST\nend\n\n-- set versions list\nfunction _instance:_versions_list_set(versions_list)\n    self._VERSIONS_LIST = versions_list\nend\n\n-- get version\nfunction _instance:version()\n    return self._VERSION\nend\n\n-- get version string\nfunction _instance:version_str()\n    local package = self:package()\n    if package and package:is_thirdparty() then\n        local requireinfo = package:requireinfo()\n        if requireinfo then\n            return requireinfo.version\n        end\n    end\n    return self._VERSION_STR\nend\n\n-- set version\nfunction _instance:version_set(version, source)\n\n    -- save the semver version\n    local sv = semver.new(version)\n    if sv then\n        self._VERSION = sv\n    end\n\n    -- save branch and tag\n    if source == \"branch\" then\n        self._BRANCH = version\n    elseif source == \"tag\" then\n        self._TAG = version\n    elseif source == \"commit\" then\n        self._COMMIT = version\n    end\n\n    -- save version string\n    if source == \"commit\" then\n        -- we strip it to avoid long paths\n        self._VERSION_STR = version:sub(1, 8)\n    else\n        self._VERSION_STR = version\n    end\nend\n\n-- get branch version\nfunction _instance:branch()\n    return self._BRANCH\nend\n\n-- get tag version\nfunction _instance:tag()\n    return self._TAG\nend\n\n-- get commit version\nfunction _instance:commit()\n    return self._COMMIT\nend\n\n-- is git ref?\nfunction _instance:gitref()\n    return self:branch() or self:tag() or self:commit()\nend\n\n-- get hash of the source package for the url_alias@version_str\nfunction _instance:sourcehash(url_alias)\n    local versions    = self:_versions_list()\n    local version_str = self:version_str()\n    if versions and version_str then\n        local sourcehash = nil\n        if url_alias then\n            sourcehash = versions[url_alias .. \":\" ..version_str]\n        end\n        if not sourcehash then\n            sourcehash = versions[version_str]\n        end\n        if sourcehash and #sourcehash == 40 then\n            sourcehash = sourcehash:lower()\n        end\n        return sourcehash\n    end\nend\n\n-- get revision(commit, tag, branch) of the url_alias@version_str, only for git url\nfunction _instance:revision(url_alias)\n    local revision = self:sourcehash(url_alias)\n    if revision and #revision <= 40 then\n        -- it will be sha256 of tar/gz file, not commit number if longer than 40 characters\n        return revision\n    end\nend\n\n-- get the patches of the current version\n--\n-- @code\n-- add_patches(\"6.7.6\", \"https://cdn.kernel.org/pub/linux/kernel/v6.x/patch-6.7.6.xz\",\n--    \"a394326aa325f8a930a4ce33c69ba7b8b454aef1107a4d3c2a8ae12908615fc4\", {reverse = true})\n-- @endcode\n--\nfunction _instance:patches()\n    local patches = self._PATCHES\n    if patches == nil then\n        local patchinfos = self:get(\"patches\")\n        if patchinfos then\n            local version_str = self:version_str()\n            local patchinfo = patchinfos[version_str]\n            if patchinfo then\n                patches = {}\n                patchinfo = table.wrap(patchinfo)\n                for idx = 1, #patchinfo, 2 do\n                    local extra = self:extraconf(\"patches.\" .. version_str, patchinfo[idx])\n                    table.insert(patches , {url = patchinfo[idx], sha256 = patchinfo[idx + 1], extra = extra})\n                end\n            else\n                -- match semver, e.g add_patches(\">=1.0.0\", url, sha256)\n                for range, patchinfo in pairs(patchinfos) do\n                    if semver.satisfies(version_str, range) then\n                        patches = patches or {}\n                        patchinfo = table.wrap(patchinfo)\n                        for idx = 1, #patchinfo, 2 do\n                            local extra = self:extraconf(\"patches.\" .. range, patchinfo[idx])\n                            table.insert(patches , {url = patchinfo[idx], sha256 = patchinfo[idx + 1], extra = extra})\n                        end\n                    end\n                end\n            end\n        end\n        self._PATCHES = patches or false\n    end\n    return patches and patches or nil\nend\n\n-- get the resources of the current version\nfunction _instance:resources()\n    local resources = self._RESOURCES\n    if resources == nil then\n        local resourceinfos = self:get(\"resources\")\n        if resourceinfos then\n            local version_str = self:version_str()\n            local resourceinfo = resourceinfos[version_str]\n            if resourceinfo then\n                resources = {}\n                resourceinfo = table.wrap(resourceinfo)\n                for idx = 1, #resourceinfo, 3 do\n                    local name = resourceinfo[idx]\n                    resources[name] = {url = resourceinfo[idx + 1], sha256 = resourceinfo[idx + 2]}\n                end\n            else\n                -- match semver, e.g add_resources(\">=1.0.0\", name, url, sha256)\n                for range, resourceinfo in pairs(resourceinfos) do\n                    if semver.satisfies(version_str, range) then\n                        resources = resources or {}\n                        resourceinfo = table.wrap(resourceinfo)\n                        for idx = 1, #resourceinfo, 3 do\n                            local name = resourceinfo[idx]\n                            resources[name] = {url = resourceinfo[idx + 1], sha256 = resourceinfo[idx + 2]}\n                        end\n                    end\n                end\n            end\n        end\n        self._RESOURCES = resources or false\n    end\n    return resources and resources or nil\nend\n\n-- interpreter\nfunction scheme._interpreter()\n    local interp = scheme._INTERPRETER\n    if not interp then\n        interp = interpreter.new()\n        interp:api_define(scheme.apis())\n        scheme._INTERPRETER = interp\n    end\n    return interp\nend\n\n-- get scheme apis\nfunction scheme.apis()\n    return {\n        values = {\n            -- scheme.set_xxx\n            \"scheme.set_urls\",\n            -- scheme.add_xxx\n            \"scheme.add_urls\"\n        },\n        script = {\n            -- scheme.on_xxx\n            \"scheme.on_download\"\n        ,   \"scheme.on_install\"\n        ,   \"scheme.on_test\"\n        },\n        keyvalues = {\n            -- scheme.add_xxx\n            \"scheme.add_patches\"\n        ,   \"scheme.add_resources\"\n        },\n        paths = {\n            -- scheme.add_xxx\n            \"scheme.add_versionfiles\"\n        },\n        dictionary = {\n            -- scheme.add_xxx\n            \"scheme.add_versions\"\n        }\n    }\nend\n\n-- new scheme\nfunction scheme.new(name, opt)\n    return _instance.new(name, opt)\nend\n\n-- return module\nreturn scheme\n"
  },
  {
    "path": "xmake/core/platform/environment.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        environment.lua\n--\n\n-- define module\nlocal environment = environment or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal table         = require(\"base/table\")\nlocal global        = require(\"base/global\")\nlocal sandbox       = require(\"sandbox/sandbox\")\nlocal package       = require(\"package/package\")\nlocal import        = require(\"sandbox/modules/import\")\n\n-- enter the toolchains environment\nfunction environment._enter_toolchains()\n    return true\nend\n\n-- leave the toolchains environment\nfunction environment._leave_toolchains()\n    return true\nend\n\n-- enter the environment for the current platform\nfunction environment.enter(name)\n\n    -- need enter?\n    local entered = environment._ENTERED or {}\n    environment._ENTERED = entered\n    if entered[name] then\n        entered[name] = entered[name] + 1\n        return true\n    else\n        entered[name] = 1\n    end\n\n    -- do enter\n    local maps = {toolchains = environment._enter_toolchains}\n    local func = maps[name]\n    if func then\n        local ok, errors = func()\n        if not ok then\n            return false, errors\n        end\n    end\n    return true\nend\n\n-- leave the environment for the current platform\nfunction environment.leave(name)\n\n    -- need leave?\n    local entered = environment._ENTERED or {}\n    if entered[name] then\n        entered[name] = entered[name] - 1\n    end\n    if entered[name] == 0 then\n        entered[name] = nil\n    else\n        return true\n    end\n\n    -- do leave\n    local maps = {toolchains = environment._leave_toolchains}\n    local func = maps[name]\n    if func then\n        local ok, errors = func()\n        if not ok then\n            return false, errors\n        end\n    end\n    return true\nend\n\n-- return module\nreturn environment\n"
  },
  {
    "path": "xmake/core/platform/menu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menu.lua\n--\n\n-- define module\nlocal menu          = menu or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal config         = require(\"project/config\")\nlocal platform       = require(\"platform/platform\")\n\n-- the remote build client is connected?\n--\n-- this implementation is from remote_build_client.is_connected(), but we can not call it by module/import\n--\n-- @see https://github.com/xmake-io/xmake/issues/3187\nfunction _remote_build_is_connected()\n    -- the current process is in service? we cannot enable it\n    if os.getenv(\"XMAKE_IN_SERVICE\") then\n        return false\n    end\n    local projectdir = os.projectdir()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) and projectdir then\n        local workdir = path.join(config.directory(), \"remote_build\")\n        local statusfile = path.join(workdir, \"status.txt\")\n        if os.isfile(statusfile) then\n            local status = io.load(statusfile)\n            if status and status.connected then\n                return true\n            end\n        end\n    end\nend\n\n-- get the option menu for action: xmake config or global\nfunction menu.options(action)\n    assert(action)\n\n    -- get all platforms\n    local plats = platform.plats()\n    assert(plats)\n\n    -- load and merge all platform options\n    local exist     = {}\n    local results   = {}\n    for _, plat in ipairs(plats) do\n\n        -- load platform\n        local instance, errors = platform.load(plat)\n        if not instance then\n            return nil, errors\n        end\n\n        -- get menu of the supported platform on the current host\n        local menu = instance:menu()\n        if menu and (os.is_host(table.unpack(table.wrap(instance:hosts()))) or _remote_build_is_connected()) then\n\n            -- get the options for this action\n            local options = menu[action]\n            if options then\n\n                -- get the language option\n                for _, option in ipairs(options) do\n\n                    -- merge it and remove repeat\n                    local name = option[2]\n                    if name then\n                        if not exist[name] then\n                            table.insert(results, option)\n                            exist[name] = true\n                        end\n                    else\n                        table.insert(results, option)\n                    end\n                end\n            end\n        end\n    end\n    return results\nend\n\n-- return module\nreturn menu\n"
  },
  {
    "path": "xmake/core/platform/platform.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        platform.lua\n--\n\n-- define module\nlocal platform      = platform or {}\nlocal _instance     = _instance or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal global         = require(\"base/global\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal toolchain      = require(\"tool/toolchain\")\nlocal memcache       = require(\"cache/memcache\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal config         = require(\"project/config\")\nlocal scheduler      = require(\"sandbox/modules/import/core/base/scheduler\")\n\n-- new an instance\nfunction _instance.new(name, info, opt)\n    opt = opt or{}\n    local instance    = table.inherit(_instance)\n    instance._NAME    = name\n    instance._INFO    = info\n    instance._ARCH    = opt.arch\n    instance._IS_HOST = opt.host or false\n    return instance\nend\n\n-- get memcache\nfunction _instance:_memcache()\n    local cache = self._MEMCACHE\n    if not cache then\n        cache = memcache.cache(\"core.platform.platform.\" .. tostring(self))\n        self._MEMCACHE = cache\n    end\n    return cache\nend\n\n-- the toolchains cache key for names\nfunction _instance:_toolchains_key()\n    return \"__toolchains_\" .. self:name() .. \"_\" .. self:arch() .. (self:is_host() and \"_host\" or \"\")\nend\n\n-- get platform name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get platform architecture\nfunction _instance:arch()\n    return self._ARCH or config.get(\"arch\")\nend\n\n-- set platform architecture\nfunction _instance:arch_set(arch)\n    if self:arch() ~= arch then\n        -- we need to clean the dirty cache if architecture has been changed\n        platform._PLATFORMS[self:name() .. \"_\" .. self:arch()] = nil\n        platform._PLATFORMS[self:name() .. \"_\" .. arch] = self\n        self._ARCH = arch\n    end\nend\n\n-- is host platform, it will use the host toolchain\nfunction _instance:is_host()\n    return self._IS_HOST\nend\n\n-- set the value to the platform configuration\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\nend\n\n-- add the value to the platform configuration\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\nend\n\n-- get the platform configuration\nfunction _instance:get(name)\n\n    -- attempt to get the static configure value\n    local value = self._INFO:get(name)\n    if value ~= nil then\n        return value\n    end\n\n    -- lazy loading platform if get other configuration\n    if not self._LOADED and not self:_is_builtin_conf(name) then\n        local on_load = self._INFO:get(\"load\")\n        if on_load then\n            local ok, errors = sandbox.load(on_load, self)\n            if not ok then\n                os.raise(errors)\n            end\n        end\n        self._LOADED = true\n    end\n\n    -- get other platform info\n    return self._INFO:get(name)\nend\n\n-- get the platform os\nfunction _instance:os()\n    return self._INFO:get(\"os\")\nend\n\n-- get the platform menu\nfunction _instance:menu()\n    -- @note do not use self:get(\"menu\") to avoid loading platform early\n    return self._INFO:get(\"menu\")\nend\n\n-- get the platform hosts\nfunction _instance:hosts()\n    return self._INFO:get(\"hosts\")\nend\n\n-- get the platform archs\nfunction _instance:archs()\n    return self._INFO:get(\"archs\")\nend\n\n-- get runenvs of toolchains\nfunction _instance:runenvs()\n    local runenvs = self._RUNENVS\n    if not runenvs then\n        runenvs = {}\n        for _, toolchain_inst in ipairs(self:toolchains()) do\n            local toolchain_runenvs = toolchain_inst:get(\"runenvs\")\n            if toolchain_runenvs then\n                for name, values in pairs(toolchain_runenvs) do\n                    runenvs[name] = table.join2(table.wrap(runenvs[name]), values)\n                end\n            end\n        end\n        self._RUNENVS = runenvs\n    end\n    return runenvs\nend\n\n-- get the toolchains\nfunction _instance:toolchains(opt)\n    local toolchains = self:_memcache():get(\"toolchains\")\n    if not toolchains then\n\n        -- get current valid toolchains from configuration cache\n        local names = nil\n        toolchains = {}\n        if not (opt and opt.all) then\n            names = config.get(self:_toolchains_key())\n        end\n        if not names then\n            -- get the given toolchain\n            local toolchain_given = config.get(self:is_host() and \"toolchain_host\" or \"toolchain\")\n            if toolchain_given then\n                local toolchain_inst, errors = toolchain.load(toolchain_given, {\n                    plat = self:name(), arch = self:arch()})\n                -- attempt to load toolchain from project\n                if not toolchain_inst and platform._project() then\n                    toolchain_inst = platform._project().toolchain(toolchain_given)\n                end\n                if not toolchain_inst then\n                    os.raise(errors)\n                end\n                table.insert(toolchains, toolchain_inst)\n                toolchain_given = toolchain_inst\n            end\n\n            -- get the platform toolchains\n            if (not toolchain_given or not toolchain_given:is_standalone()) and self._INFO:get(\"toolchains\") then\n                names = self._INFO:get(\"toolchains\")\n            end\n        end\n        if names then\n            for _, name in ipairs(table.wrap(names)) do\n                local toolchain_inst, errors = toolchain.load(name, {\n                    plat = self:name(), arch = self:arch()})\n                -- attempt to load toolchain from project\n                if not toolchain_inst and platform._project() then\n                    toolchain_inst = platform._project().toolchain(name)\n                end\n                if not toolchain_inst then\n                    os.raise(errors)\n                end\n                -- ignore cross toolchains for the host platform\n                if (self:is_host() and not toolchain_inst:is_cross_toolchain()) or not self:is_host() then\n                    table.insert(toolchains, toolchain_inst)\n                end\n            end\n        end\n        self:_memcache():set(\"toolchains\", toolchains)\n    end\n    return toolchains\nend\n\n-- get the program and name of the given tool kind\nfunction _instance:tool(toolkind)\n    return toolchain.tool(self:toolchains(), toolkind, {cachekey = \"platform\", plat = self:name(), arch = self:arch(),\n                          before_get = function ()\n        return config.get(toolkind)\n    end})\nend\n\n-- get tool configuration from the toolchains\nfunction _instance:toolconfig(name)\n    return toolchain.toolconfig(self:toolchains(), name, {cachekey = \"platform\", plat = self:name(), arch = self:arch()})\nend\n\n-- get the platform script\nfunction _instance:script(name)\n    return self._INFO:get(name)\nend\n\n-- get user private data\nfunction _instance:data(name)\n    return self._DATA and self._DATA[name] or nil\nend\n\n-- set user private data\nfunction _instance:data_set(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = data\nend\n\n-- add user private data\nfunction _instance:data_add(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = table.unwrap(table.join(self._DATA[name] or {}, data))\nend\n\n-- do check\nfunction _instance:check()\n    -- @see https://github.com/xmake-io/xmake/issues/4645#issuecomment-2201036943\n    -- @note avoid check it in the same time leading to deadlock if running in the coroutine\n    local lockname = tostring(self)\n    scheduler.co_lock(lockname)\n\n    -- this platform has been check?\n    local checked = self:_memcache():get(\"checked\")\n    if checked ~= nil then\n        scheduler.co_unlock(lockname)\n        return checked\n    end\n\n    -- check toolchains\n    local toolchains = self:toolchains({all = true})\n    local idx = 1\n    local num = #toolchains\n    local standalone = false\n    local toolchains_valid = {}\n    while idx <= num do\n        local toolchain = toolchains[idx]\n        -- we need to remove other standalone toolchains if standalone toolchain found\n        if (standalone and toolchain:is_standalone()) or not toolchain:check() then\n            table.remove(toolchains, idx)\n            num = num - 1\n        else\n            if toolchain:is_standalone() then\n                standalone = true\n            end\n            idx = idx + 1\n            table.insert(toolchains_valid, toolchain:fullname())\n        end\n    end\n    if #toolchains == 0 then\n        self:_memcache():set(\"checked\", false)\n        scheduler.co_unlock(lockname)\n        return false, \"toolchains not found!\"\n    end\n\n    -- save valid toolchains\n    config.set(self:_toolchains_key(), toolchains_valid)\n    self:_memcache():set(\"checked\", true)\n    scheduler.co_unlock(lockname)\n    return true\nend\n\n-- get formats\nfunction _instance:formats()\n    local formats = self._FORMATS\n    if not formats then\n        for _, toolchain_inst in ipairs(self:toolchains()) do\n            -- @note we can only get formats from set_formats in toolchain description.\n            formats = toolchain_inst:get(\"formats\", {load = false})\n            if formats then\n                break\n            end\n        end\n        if not formats then\n            formats = self._INFO:get(\"formats\")\n        end\n        self._FORMATS = formats\n    end\n    return formats\nend\n\n-- is builtin configuration?\nfunction _instance:_is_builtin_conf(name)\n\n    local builtin_configs = self._BUILTIN_CONFIGS\n    if not builtin_configs then\n        builtin_configs = {}\n        for apiname, _ in pairs(platform._interpreter():apis(\"platform\")) do\n            local pos = apiname:find('_', 1, true)\n            if pos then\n                builtin_configs[apiname:sub(pos + 1)] = true\n            end\n        end\n        self._BUILTIN_CONFIGS = builtin_configs\n    end\n    return builtin_configs[name]\nend\n\n-- the interpreter\nfunction platform._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if platform._INTERPRETER then\n        return platform._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(platform._apis())\n\n    -- save interpreter\n    platform._INTERPRETER = interp\n\n    -- ok?\n    return interp\nend\n\n-- get project\nfunction platform._project()\n    return platform._PROJECT\nend\n\n-- get platform apis\nfunction platform._apis()\n    return\n    {\n        values =\n        {\n            -- platform.set_xxx\n            \"platform.set_os\"\n        ,   \"platform.set_hosts\"\n        ,   \"platform.set_archs\"\n        ,   \"platform.set_installdir\"\n        ,   \"platform.set_toolchains\"\n        }\n    ,   script =\n        {\n            -- platform.on_xxx\n            \"platform.on_load\"\n        }\n    ,   keyvalues =\n        {\n            \"platform.set_formats\"\n        }\n    ,   dictionary =\n        {\n            -- platform.set_xxx\n            \"platform.set_menu\"\n        }\n    }\nend\n\n-- get memcache\nfunction platform._memcache()\n    return memcache.cache(\"core.platform.platform\")\nend\n\n-- get platform directories\nfunction platform.directories()\n    local dirs = platform._DIRS or  {   path.join(global.directory(), \"platforms\")\n                                    ,   path.join(os.programdir(), \"platforms\")\n                                    }\n    platform._DIRS = dirs\n    return dirs\nend\n\n-- add platform directories\nfunction platform.add_directories(...)\n    local dirs = platform.directories()\n    for _, dir in ipairs({...}) do\n        table.insert(dirs, 1, dir)\n    end\n    platform._DIRS = table.unique(dirs)\nend\n\n-- load the given platform\nfunction platform.load(plat, arch, opt)\n    opt = opt or {}\n    plat = plat or config.get(\"plat\") or os.host()\n    arch = arch or config.get(\"arch\") or os.arch()\n\n    -- get cache key\n    local cachekey = plat .. \"_\" .. arch\n    if opt.host then\n        cachekey = cachekey .. \"_host\"\n    end\n\n    -- get it directly from cache dirst\n    platform._PLATFORMS = platform._PLATFORMS or {}\n    if platform._PLATFORMS[cachekey] then\n        return platform._PLATFORMS[cachekey]\n    end\n\n    -- find the platform script path\n    local scriptpath = nil\n    for _, dir in ipairs(platform.directories()) do\n        scriptpath = path.join(dir, plat, \"xmake.lua\")\n        if os.isfile(scriptpath) then\n            break\n        end\n    end\n\n    -- unknown platform? switch to cross compilation platform\n    local cross = false\n    if not scriptpath or not os.isfile(scriptpath) then\n        scriptpath = path.join(os.programdir(), \"platforms\", \"cross\", \"xmake.lua\")\n        cross = true\n    end\n\n    -- not exists?\n    if not scriptpath or not os.isfile(scriptpath) then\n        return nil, string.format(\"the platform %s not found!\", plat)\n    end\n\n    -- get interpreter\n    local interp = platform._interpreter()\n\n    -- load script\n    local ok, errors = interp:load(scriptpath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load platform\n    local results, errors = interp:make(\"platform\", true, false)\n    if not results and os.isfile(scriptpath) then\n        return nil, errors\n    end\n\n    -- get result\n    local result = cross and results[\"cross\"] or results[plat]\n\n    -- check the platform name\n    if not result then\n        return nil, string.format(\"the platform %s not found!\", plat)\n    end\n\n    -- save instance to the cache\n    local instance = _instance.new(plat, result, {arch = arch, host = opt.host})\n    platform._PLATFORMS[cachekey] = instance\n    return instance\nend\n\n-- get the given platform configuration\nfunction platform.get(name, plat, arch, opt)\n    local instance, errors = platform.load(plat, arch, opt)\n    if instance then\n        return instance:get(name)\n    else\n        os.raise(errors)\n    end\nend\n\n-- get the platform tool from the kind\n--\n-- e.g. cc, cxx, mm, mxx, as, ar, ld, sh, ..\n--\nfunction platform.tool(toolkind, plat, arch, opt)\n    local instance, errors = platform.load(plat, arch, opt)\n    if instance then\n        return instance:tool(toolkind)\n    else\n        os.raise(errors)\n    end\nend\n\n-- get the given tool configuration\nfunction platform.toolconfig(name, plat, arch, opt)\n    local instance, errors = platform.load(plat, arch, opt)\n    if instance then\n        return instance:toolconfig(name)\n    else\n        os.raise(errors)\n    end\nend\n\n-- get the all platforms\nfunction platform.plats()\n\n    -- return it directly if exists\n    if platform._PLATS then\n        return platform._PLATS\n    end\n\n    -- get all platforms\n    local plats = {}\n    local dirs  = platform.directories()\n    for _, dir in ipairs(dirs) do\n        local platpathes = os.dirs(path.join(dir, \"*\"))\n        if platpathes then\n            for _, platpath in ipairs(platpathes) do\n                if os.isfile(path.join(platpath, \"xmake.lua\")) then\n                    table.insert(plats, path.basename(platpath))\n                end\n            end\n        end\n    end\n    platform._PLATS = plats\n    return plats\nend\n\n-- get the all toolchains\nfunction platform.toolchains()\n    local toolchains = platform._memcache():get(\"toolchains\")\n    if not toolchains then\n        toolchains = {}\n        local dirs  = toolchain.directories()\n        for _, dir in ipairs(dirs) do\n            local dirs = os.dirs(path.join(dir, \"*\"))\n            if dirs then\n                for _, dir in ipairs(dirs) do\n                    if os.isfile(path.join(dir, \"xmake.lua\")) then\n                        table.insert(toolchains, path.filename(dir))\n                    end\n                end\n            end\n        end\n        platform._memcache():set(\"toolchains\", toolchains)\n    end\n    return toolchains\nend\n\n-- get the platform os\nfunction platform.os(plat, arch)\n    return platform.get(\"os\", plat, arch) or config.get(\"target_os\")\nend\n\n-- get the platform archs\nfunction platform.archs(plat, arch)\n    return platform.get(\"archs\", plat, arch)\nend\n\n-- get the format of the given kind for platform\nfunction platform.format(kind, plat, arch)\n\n    -- get platform instance\n    local instance, errors = platform.load(plat, arch)\n    if not instance then\n        os.raise(errors)\n    end\n\n    -- get formats\n    local formats = instance:formats()\n    if formats then\n        return formats[kind]\n    end\nend\n\n\n-- return module\nreturn platform\n"
  },
  {
    "path": "xmake/core/project/cache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cache.lua\n--\n\n-- define module\nlocal cache = cache or {}\n\n-- load modules\nlocal io            = require(\"base/io\")\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal table         = require(\"base/table\")\nlocal utils         = require(\"base/utils\")\nlocal config        = require(\"project/config\")\nlocal global        = require(\"base/global\")\n\n-- the cache instance\n--\n-- @param scopename     local.xxxx\n--                      global.xxxx\n--\nfunction cache._instance(scopename)\n\n    -- check\n    assert(scopename)\n\n    -- init instances\n    cache._INSTANCES = cache._INSTANCES or {}\n    local instances = cache._INSTANCES\n\n    -- this instance has been initialized?\n    if instances[scopename] then\n        return instances[scopename]\n    end\n\n    -- init instance\n    local instance = table.inherit(cache)\n\n    -- memory cache?\n    if scopename:startswith(\"memory.\") then\n        instance._CACHEDATA = instance._CACHEDATA or {__version = xmake._VERSION_SHORT}\n        instances[scopename] = instance\n        return instance\n    end\n\n    -- check scopename\n    if not scopename:find(\"local%.\") and not scopename:find(\"global%.\") then\n        os.raise(\"invalid cache scope: %s\", scopename)\n    end\n\n    -- make the cache path\n    local cachepath = (scopename:gsub(\"%.\", \"/\"))\n    cachepath = (cachepath:gsub(\"^local%/\", path.join(config.directory(), \"cache\") .. \"/\"))\n    cachepath = (cachepath:gsub(\"^global%/\", path.join(global.cachedir()) .. \"/\"))\n\n    -- save the cache path\n    instance._CACHEPATH = cachepath\n\n    -- load the cache data\n    local results = io.load(cachepath)\n    if results then\n        instance._CACHEDATA = results\n    end\n    instance._CACHEDATA = instance._CACHEDATA or {__version = xmake._VERSION_SHORT}\n\n    -- save instance\n    instances[scopename] = instance\n\n    -- ok\n    return instance\nend\n\n-- get the value\nfunction cache:get(name)\n    return self._CACHEDATA[name]\nend\n\n-- set the value\nfunction cache:set(name, value)\n    self._CACHEDATA[name] = value\nend\n\n-- clear all\nfunction cache:clear()\n    self._CACHEDATA = {__version = xmake._VERSION_SHORT}\nend\n\n-- flush to cache file\nfunction cache:flush()\n\n    -- flush the version\n    self._CACHEDATA.__version = xmake._VERSION_SHORT\n\n    -- memory cache? ignore it directly\n    if not self._CACHEPATH then\n        return\n    end\n\n    -- save to file\n    local ok, errors = io.save(self._CACHEPATH, self._CACHEDATA)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- return module\nreturn cache._instance\n"
  },
  {
    "path": "xmake/core/project/config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        config.lua\n--\n\n-- define module\nlocal config = config or {}\n\n-- load modules\nlocal io            = require(\"base/io\")\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal table         = require(\"base/table\")\nlocal utils         = require(\"base/utils\")\nlocal option        = require(\"base/option\")\nlocal is_cross      = require(\"base/private/is_cross\")\n\n-- always use workingdir?\n--\n-- If the -P/-F parameter is specified, we use workingdir as the configuration root\n--\n-- But we cannot call `option.get(\"project\")`, because the menu script\n-- will also fetch the configdir, but at this point,\n-- the option has not yet finished parsing.\nfunction config._use_workingdir()\n    local use_workingdir = config._USE_WORKINGDIR\n    if use_workingdir == nil then\n        for _, arg in ipairs(xmake._ARGV) do\n            if arg == \"-P\" or arg == \"-F\" or\n                arg:startswith(\"--project=\") or arg:startswith(\"--file=\") then\n                use_workingdir = true\n            end\n        end\n        use_workingdir = use_workingdir or false\n        config._USE_WORKINGDIR = use_workingdir\n    end\n    return use_workingdir\nend\n\n-- the current config is belong to the given config values?\nfunction config._is_value(value, ...)\n    if value == nil then\n        return false\n    end\n\n    value = tostring(value)\n    for _, v in ipairs(table.pack(...)) do\n        -- escape '-'\n        v = tostring(v)\n        if value == v or value:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\n    return false\nend\n\n-- get the current given configuration\nfunction config.get(name)\n    local value = nil\n    if config._CONFIGS then\n        value = config._CONFIGS[name]\n        if type(value) == \"string\" and value == \"auto\" then\n            value = nil\n        end\n    end\n    return value\nend\n\n-- this config name is readonly?\nfunction config.readonly(name)\n    return config._MODES and config._MODES[\"__readonly_\" .. name]\nend\n\n-- set the given configure to the current\n--\n-- @param name  the name\n-- @param value the value\n-- @param opt   the argument options, e.g. {readonly = false, force = false}\n--\nfunction config.set(name, value, opt)\n    opt = opt or {}\n    assert(name)\n    assert(opt.force or not config.readonly(name), \"cannot set readonly config: \" .. name)\n\n    config._CONFIGS = config._CONFIGS or {}\n    config._CONFIGS[name] = value\n    if opt.readonly then\n        config._MODES = config._MODES or {}\n        config._MODES[\"__readonly_\" .. name] = true\n    end\nend\n\n-- get the current platform\nfunction config.plat()\n    return config.get(\"plat\")\nend\n\n-- get the current architecture\nfunction config.arch()\n    return config.get(\"arch\")\nend\n\n-- get the current mode\nfunction config.mode()\n    return config.get(\"mode\")\nend\n\n-- get the current host\nfunction config.host()\n    return config.get(\"host\")\nend\n\n-- get all options\nfunction config.options()\n\n    -- remove values with \"auto\" and private item\n    local configs = {}\n    if config._CONFIGS then\n        for name, value in pairs(config._CONFIGS) do\n            if not name:find(\"^_%u+\") and (type(value) ~= \"string\" or value ~= \"auto\") then\n                configs[name] = value\n            end\n        end\n    end\n    return configs\nend\n\n-- get the builddir\n-- we can use `{absolute = true}` to force to get absolute path\nfunction config.builddir(opt)\n\n    -- get the absolute path first\n    opt = opt or {}\n    local rootdir\n    -- we always switch to independent working directory if `-P/-F` is set\n    -- @see https://github.com/xmake-io/xmake/issues/3342\n    if not rootdir and config._use_workingdir() then\n        rootdir = os.workingdir()\n    end\n    -- we switch to independent working directory if .xmake exists\n    -- @see https://github.com/xmake-io/xmake/issues/820\n    if not rootdir and os.isdir(path.join(os.workingdir(), \".\" .. xmake._NAME)) then\n        rootdir = os.workingdir()\n    end\n    if not rootdir then\n        rootdir = os.projectdir()\n    end\n    local builddir = config.get(\"builddir\") or config.get(\"buildir\") or \"build\"\n    if not path.is_absolute(builddir) then\n        builddir = path.absolute(builddir, rootdir)\n    end\n\n    -- adjust path for the current directory\n    if not opt.absolute then\n        builddir = path.relative(builddir, os.curdir())\n    end\n    return builddir\nend\n\n-- get build directory (deprecated)\nfunction config.buildir(opt)\n    utils.warning(\"config.buildir() has been deprecated, please use config.builddir()\")\n    return config.builddir(opt)\nend\n\n-- get the configure file\nfunction config.filepath()\n    return path.join(config.directory(), xmake._NAME .. \".conf\")\nend\n\n-- get the local cache directory\nfunction config.cachedir()\n    return path.join(config.directory(), \"cache\")\nend\n\n-- get the configure directory on the current host/arch platform\nfunction config.directory()\n    if config._DIRECTORY == nil then\n        local rootdir = os.getenv(\"XMAKE_CONFIGDIR\")\n        -- we always switch to independent working directory if `-P/-F` is set\n        -- @see https://github.com/xmake-io/xmake/issues/3342\n        if not rootdir and config._use_workingdir() then\n            rootdir = os.workingdir()\n        end\n        -- we switch to independent working directory if .xmake exists\n        -- @see https://github.com/xmake-io/xmake/issues/820\n        if not rootdir and os.isdir(path.join(os.workingdir(), \".\" .. xmake._NAME)) then\n            rootdir = os.workingdir()\n        end\n        if not rootdir then\n            rootdir = os.projectdir()\n        end\n        config._DIRECTORY = path.join(rootdir, \".\" .. xmake._NAME, os.host(), os.arch())\n    end\n    return config._DIRECTORY\nend\n\n-- load the project configuration\n--\n-- @param opt   {readonly = true, force = true}\n--\nfunction config.load(filepath, opt)\n    opt = opt or {}\n    local configs, errors\n    filepath = filepath or config.filepath()\n    if os.isfile(filepath) then\n        configs, errors = io.load(filepath)\n        if not configs then\n            utils.error(errors)\n            return false\n        end\n    end\n    -- merge into the current configuration\n    local ok = false\n    if configs then\n        for name, value in pairs(configs) do\n            if config.get(name) == nil or opt.force then\n                config.set(name, value, opt)\n                ok = true\n            end\n        end\n    end\n    return ok\nend\n\n-- save the project configuration\n--\n-- @note we pass only_changed to avoid frequent changes to the file's mtime,\n-- because some plugins(vscode, compile_commands.autoupdate) depend on it's mtime.\n--\nfunction config.save(filepath, opt)\n    opt = opt or {}\n    filepath = filepath or config.filepath()\n    if opt.public then\n        local configs = {}\n        for name, value in pairs(config.options()) do\n            if not name:startswith(\"__\") then\n                configs[name] = value\n            end\n        end\n        return io.save(filepath, configs, {orderkeys = true, only_changed = true})\n    else\n        return io.save(filepath, config.options(), {orderkeys = true, only_changed = true})\n    end\nend\n\n-- read value from the configuration file directly\nfunction config.read(name)\n    local configs\n    if os.isfile(config.filepath()) then\n        configs = io.load(config.filepath())\n    end\n    local value = nil\n    if configs then\n        value = configs[name]\n        if type(value) == \"string\" and value == \"auto\" then\n            value = nil\n        end\n    end\n    return value\nend\n\n-- clear config\nfunction config.clear()\n    config._MODES = nil\n    config._CONFIGS = nil\nend\n\n-- the current mode is belong to the given modes?\nfunction config.is_mode(...)\n    return config._is_value(config.get(\"mode\"), ...)\nend\n\n-- the current platform is belong to the given platforms?\nfunction config.is_plat(...)\n    return config._is_value(config.get(\"plat\"), ...)\nend\n\n-- the current architecture is belong to the given architectures?\nfunction config.is_arch(...)\n    return config._is_value(config.get(\"arch\"), ...)\nend\n\n-- is cross-compilation?\nfunction config.is_cross()\n    return is_cross(config.plat(), config.arch())\nend\n\n-- dump the configure\nfunction config.dump()\n    if not option.get(\"quiet\") then\n        utils.print(\"configure\")\n        utils.print(\"{\")\n        for name, value in pairs(config.options()) do\n            if not name:startswith(\"__\") then\n                utils.print(\"    %s = %s\", name, value)\n            end\n        end\n        utils.print(\"}\")\n    end\nend\n\n-- return module\nreturn config\n"
  },
  {
    "path": "xmake/core/project/deprecated/project.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        deprecated_project.lua\n--\n\n-- define module: deprecated_project\nlocal deprecated_project = deprecated_project or {}\n\n-- load modules\nlocal os                        = require(\"base/os\")\nlocal path                      = require(\"base/path\")\nlocal utils                     = require(\"base/utils\")\nlocal table                     = require(\"base/table\")\nlocal string                    = require(\"base/string\")\nlocal rule                      = require(\"project/rule\")\nlocal config                    = require(\"project/config\")\nlocal platform                  = require(\"platform/platform\")\nlocal deprecated                = require(\"base/deprecated\")\n\n-- register api\nfunction deprecated_project.api_register(interp)\nend\n\n-- return module: deprecated_project\nreturn deprecated_project\n"
  },
  {
    "path": "xmake/core/project/option.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        option.lua\n--\n\n-- define module\nlocal option    = {}\nlocal _instance = {}\n\n-- load modules\nlocal io             = require(\"base/io\")\nlocal os             = require(\"base/os\")\nlocal path           = require(\"base/path\")\nlocal table          = require(\"base/table\")\nlocal utils          = require(\"base/utils\")\nlocal baseoption     = require(\"base/option\")\nlocal global         = require(\"base/global\")\nlocal scopeinfo      = require(\"base/scopeinfo\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal config         = require(\"project/config\")\nlocal localcache     = require(\"cache/localcache\")\nlocal linker         = require(\"tool/linker\")\nlocal compiler       = require(\"tool/compiler\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal language       = require(\"language/language\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal sandbox_os     = require(\"sandbox/modules/os\")\nlocal sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- new an instance\nfunction _instance.new(name, info)\n    local instance = table.inherit(_instance)\n    if name then\n        local parts = name:split(\"::\", {plain = true})\n        instance._NAME = parts[#parts]\n        table.remove(parts)\n        if #parts > 0 then\n            instance._NAMESPACE = table.concat(parts, \"::\")\n        end\n    end\n    instance._INFO = info\n    instance._CACHEID = 1\n    return instance\nend\n\n-- save the option info to the cache\nfunction _instance:_save()\n\n    -- clear scripts for caching to file\n    local check = self:get(\"check\")\n    local check_after = self:get(\"check_after\")\n    local check_before = self:get(\"check_before\")\n    self:set(\"check\", nil)\n    self:set(\"check_after\", nil)\n    self:set(\"check_before\", nil)\n\n    -- save option\n    option._cache():set(self:fullname(), self:info())\n\n    -- restore scripts\n    self:set(\"check\", check)\n    self:set(\"check_after\", check_after)\n    self:set(\"check_before\", check_before)\nend\n\n-- clear the option info for cache\nfunction _instance:_clear()\n    option._cache():set(self:fullname(), nil)\nend\n\n-- check snippets\nfunction _instance:_do_check_cxsnippets(snippets)\n\n    -- import check_cxsnippets()\n    self._check_cxsnippets = self._check_cxsnippets or sandbox_module.import(\"lib.detect.check_cxsnippets\", {anonymous = true})\n\n    -- check for c and c++\n    local passed = 0\n    local result_output\n    for _, kind in ipairs({\"c\", \"cxx\"}) do\n\n        -- get conditions\n        local links              = self:get(\"links\")\n        local snippets           = self:get(kind .. \"snippets\")\n        local types              = self:get(kind .. \"types\")\n        local funcs              = self:get(kind .. \"funcs\")\n        local includes           = self:get(kind .. \"includes\")\n\n        -- TODO it is deprecated\n        local snippet  = self:get(kind .. \"snippet\")\n        if snippet then\n            snippets = table.join(snippets or {}, snippet)\n        end\n\n        -- need check it?\n        if snippets or types or funcs or links or includes then\n\n            -- init source kind\n            local sourcekind = kind\n            if kind == \"c\" then\n                sourcekind = \"cc\"\n            end\n\n            -- split snippets\n            local snippets_build = {}\n            local snippets_tryrun = {}\n            local snippets_output = {}\n            local snippets_binary_match = {}\n            local snippet_binary_match = nil\n            if snippets then\n                for name, snippet in pairs(snippets) do\n                    if self:extraconf(kind .. \"snippets\", name, \"output\") then\n                        snippets_output[name] = snippet\n                    elseif self:extraconf(kind .. \"snippets\", name, \"tryrun\") then\n                        snippets_tryrun[name] = snippet\n                    elseif self:extraconf(kind .. \"snippets\", name, \"binary_match\") then\n                        snippets_binary_match[name] = snippet\n                        snippet_binary_match = self:extraconf(kind .. \"snippets\", name, \"binary_match\")\n                    else\n                        snippets_build[name] = snippet\n                    end\n                end\n                if #table.keys(snippets_output) > 1 then\n                    return false, -1, string.format(\"option(%s): only support for only one snippet with output!\", self:fullname())\n                end\n            end\n\n            -- check snippets (run with output)\n            if #table.keys(snippets_output) > 0 then\n                local ok, results_or_errors, output = sandbox.load(self._check_cxsnippets, snippets_output, {\n                                                            target = self,\n                                                            sourcekind = sourcekind,\n                                                            types = types,\n                                                            funcs = funcs,\n                                                            includes = includes,\n                                                            tryrun = true, output = true})\n                if not ok then\n                    return false, -1, results_or_errors\n                end\n\n                -- passed or no passed?\n                if results_or_errors then\n                    passed = 1\n                    result_output = output\n                else\n                    passed = -1\n                    break\n                end\n            end\n\n            -- check snippets (run only)\n            if passed == 0 and #table.keys(snippets_tryrun) > 0 then\n                local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_tryrun, {\n                                                            target = self,\n                                                            sourcekind = sourcekind,\n                                                            types = types,\n                                                            funcs = funcs,\n                                                            includes = includes,\n                                                            tryrun = true})\n                if not ok then\n                    return false, -1, results_or_errors\n                end\n\n                -- passed or no passed?\n                if results_or_errors then\n                    passed = 1\n                else\n                    passed = -1\n                    break\n                end\n            end\n\n            -- check snippets (run with binary_match)\n            if #table.keys(snippets_binary_match) > 0 then\n                local ok, results_or_errors, output = sandbox.load(self._check_cxsnippets, snippets_binary_match, {\n                                                            target = self,\n                                                            sourcekind = sourcekind,\n                                                            types = types,\n                                                            funcs = funcs,\n                                                            includes = includes,\n                                                            binary_match = snippet_binary_match})\n                if not ok then\n                    return false, -1, results_or_errors\n                end\n                -- passed or no passed?\n                if results_or_errors then\n                    passed = 1\n                    result_output = output\n                else\n                    passed = -1\n                    break\n                end\n            end\n\n            -- check snippets (build only)\n            if passed == 0 or #table.keys(snippets_build) > 0 then\n                local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_build, {\n                                                            target = self,\n                                                            sourcekind = sourcekind,\n                                                            types = types,\n                                                            funcs = funcs,\n                                                            includes = includes})\n                if not ok then\n                    return false, -1, results_or_errors\n                end\n\n                -- passed or no passed?\n                if results_or_errors then\n                    passed = 1\n                else\n                    passed = -1\n                    break\n                end\n            end\n        end\n    end\n    return true, passed, result_output\nend\n\n-- check features\nfunction _instance:_do_check_features()\n    local passed = 0\n    local features = self:get(\"features\")\n    if features then\n\n        -- import core.tool.compiler\n        self._core_tool_compiler = self._core_tool_compiler or sandbox_module.import(\"core.tool.compiler\", {anonymous = true})\n\n        -- all features are supported?\n        features = table.wrap(features)\n        if self._core_tool_compiler.has_features(features, {target = self}) then\n            passed = 1\n        end\n\n        -- trace\n        if baseoption.get(\"verbose\") or baseoption.get(\"diagnosis\") then\n            for _, feature in ipairs(features) do\n                utils.cprint(\"${dim}checking for feature(%s) ... %s\", feature, passed > 0 and \"${color.success}${text.success}\" or \"${color.nothing}${text.nothing}\")\n            end\n        end\n    end\n    return true, passed\nend\n\n-- check option conditions\nfunction _instance:_do_check()\n\n    -- check snippets\n    local ok, passed, errors = self:_do_check_cxsnippets()\n    if not ok then\n        return false, errors\n    end\n\n    -- get snippet output\n    local output\n    if passed then\n        output = errors\n    end\n\n    -- check features\n    if passed == 0 then\n        ok, passed, errors = self:_do_check_features()\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- enable this option if be passed\n    if passed > 0 then\n        self:enable(true)\n        if output then\n            self:set_value(output)\n        end\n    end\n    return true\nend\n\n-- on check\nfunction _instance:_on_check()\n\n    -- get check script\n    local check = self:script(\"check\")\n    if check then\n        return sandbox.load(check, self)\n    else\n        return self:_do_check()\n    end\nend\n\n-- check option\nfunction _instance:_check()\n\n    -- disable this option first\n    self:enable(false)\n\n    -- check it\n    local ok, errors = self:_on_check()\n\n    -- get name\n    local name = self:name()\n    if name:startswith(\"__\") then\n        name = name:sub(3)\n    end\n    local namespace = self:namespace()\n    if namespace then\n        name = namespace .. \"::\" .. name\n    end\n\n    -- trace\n    local result\n    if self:enabled() then\n        local value = self:value()\n        result = \"${color.success}\" .. (type(value) == \"boolean\" and \"${text.success}\" or tostring(value))\n    else\n        result = \"${color.nothing}${text.nothing}\"\n    end\n    utils.cprint(\"checking for %s ... %s\", name, result)\n    if not ok then\n        os.raise(errors)\n    end\n\n    -- flush io buffer to update progress info\n    io.flush()\nend\n\n-- invalidate the previous cache key\nfunction _instance:_invalidate()\n    self._CACHEID = self._CACHEID + 1\nend\n\n-- attempt to check option\nfunction _instance:check()\n\n    -- the option name\n    local name = self:fullname()\n\n    -- get default value, TODO: enable will be deprecated\n    local default = self:get(\"default\")\n    if default == nil then\n        default = self:get(\"enable\")\n    end\n\n    -- before and after check\n    local check_before = self:script(\"check_before\")\n    local check_after  = self:script(\"check_after\")\n    if check_before then\n        check_before(self)\n    end\n\n    -- need check? (only force to check the automatical option without the default value)\n    if config.get(name) == nil or default == nil then\n\n        -- use it directly if the default value exists\n        if default ~= nil then\n            self:set_value(default)\n        -- check option as boolean switch automatically if the default value not exists\n        elseif default == nil then\n            self:_check()\n        -- disable this option in other case\n        else\n            self:enable(false)\n        end\n\n    -- need not check? only save this option to configuration directly\n    elseif config.get(name) then\n        self:_save()\n    end\n\n    -- after check\n    if check_after then\n        check_after(self)\n    end\nend\n\n-- get the option value\nfunction _instance:value()\n    return config.get(self:fullname())\nend\n\n-- set the option value\nfunction _instance:set_value(value)\n    config.set(self:fullname(), value)\n    self:_save()\nend\n\n-- clear the option status and need recheck it\nfunction _instance:clear()\n    config.set(self:fullname(), nil)\n    self:_clear()\nend\n\n-- this option is enabled?\nfunction _instance:enabled()\n    return config.get(self:fullname())\nend\n\n-- enable or disable this option\n--\n-- @param enabled   enable option?\n-- @param opt       the argument options, e.g. {readonly = true, force = false}\n--\nfunction _instance:enable(enabled, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- enable or disable this option?\n    if not config.readonly(self:fullname()) or opt.force then\n        config.set(self:fullname(), enabled, opt)\n    end\n\n    -- save or clear this option in cache\n    if self:enabled() then\n        self:_save()\n    else\n        self:_clear()\n    end\nend\n\n-- get the option info\nfunction _instance:info()\n    return self._INFO:info()\nend\n\n-- get the type: option\nfunction _instance:type()\n    return \"option\"\nend\n\n-- get the option info\nfunction _instance:get(name)\n    return self._INFO:get(name)\nend\n\n-- set the value to the option info\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\n    self:_invalidate()\nend\n\n-- add the value to the option info\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\n    self:_invalidate()\nend\n\n-- remove the value to the option info (deprecated)\nfunction _instance:del(name, ...)\n    self._INFO:apival_del(name, ...)\n    self:_invalidate()\nend\n\n-- remove the value to the option info\nfunction _instance:remove(name, ...)\n    self._INFO:apival_remove(name, ...)\n    self:_invalidate()\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    return self._INFO:extraconf(name, item, key)\nend\n\n-- get configuration source information of the given api item\nfunction _instance:sourceinfo(name, item)\n    return self._INFO:sourceinfo(name, item)\nend\n\n-- get the given dependent option\nfunction _instance:dep(name)\n    local deps = self:deps()\n    if deps then\n        local dep = deps[name]\n        if dep == nil then\n            local namespace = self:namespace()\n            if namespace then\n                dep = deps[namespace .. \"::\" .. name]\n            end\n        end\n        return dep\n    end\nend\n\n-- get option deps\nfunction _instance:deps()\n    return self._DEPS\nend\n\n-- get option order deps\nfunction _instance:orderdeps()\n    return self._ORDERDEPS\nend\n\n-- get the option name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get the option description\nfunction _instance:description()\n    return self:get(\"description\") or (\"The \" .. self:fullname() .. \" option\")\nend\n\n-- get the cache key\nfunction _instance:cachekey()\n    return string.format(\"%s_%d\", tostring(self), self._CACHEID)\nend\n\n-- get xxx_script\nfunction _instance:script(name)\n\n    -- imports some modules first\n    local script = self:get(name)\n    if script then\n        local scope = getfenv(script)\n        if scope then\n            for _, modulename in ipairs(table.wrap(self:get(\"imports\"))) do\n                scope[sandbox_module.name(modulename)] = sandbox_module.import(modulename, {anonymous = true})\n            end\n        end\n    end\n    return script\nend\n\n-- show menu?\nfunction _instance:showmenu()\n    local showmenu = self:get(\"showmenu\")\n    if showmenu == nil then\n        -- auto check mode? we hidden menu by default\n        if self:get(\"ctypes\") or self:get(\"cxxtypes\") or\n            self:get(\"cfuncs\") or self:get(\"cxxfuncs\") or\n            self:get(\"cincludes\") or self:get(\"cxxincludes\") or\n            self:get(\"links\") or self:get(\"syslinks\") or\n            self:get(\"csnippets\") or self:get(\"cxxsnippets\") or\n            self:get(\"features\") then\n            showmenu = false\n        end\n    end\n    return showmenu\nend\n\n-- get cache\nfunction option._cache()\n    return localcache.cache(\"option\")\nend\n\n-- get option apis\nfunction option.apis()\n\n    return\n    {\n        values =\n        {\n            -- option.set_xxx\n            \"option.set_values\"\n        ,   \"option.set_default\"\n        ,   \"option.set_showmenu\"\n        ,   \"option.set_category\"\n        ,   \"option.set_warnings\"\n        ,   \"option.set_optimize\"\n        ,   \"option.set_languages\"\n        ,   \"option.set_description\"\n            -- option.add_xxx\n        ,   \"option.add_deps\"\n        ,   \"option.add_imports\"\n        ,   \"option.add_vectorexts\"\n        ,   \"option.add_features\"\n        }\n    ,   keyvalues =\n        {\n            -- option.set_xxx\n            \"option.set_configvar\"\n        }\n    ,   script =\n        {\n            -- option.before_xxx\n            \"option.before_check\"\n            -- option.on_xxx\n        ,   \"option.on_check\"\n            -- option.after_xxx\n        ,   \"option.after_check\"\n        }\n    }\nend\n\n-- get interpreter\nfunction option.interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if option._INTERPRETER then\n        return option._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n\n    -- define apis for option\n    interp:api_define(option.apis())\n\n    -- define apis for language\n    interp:api_define(language.apis())\n\n    -- we need to be able to precisely control the direction of deduplication of different types of values.\n    -- the default is to de-duplicate from left to right, but like links/syslinks need to be de-duplicated from right to left.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/1903\n    --\n    interp:deduplication_policy_set(\"links\", \"toleft\")\n    interp:deduplication_policy_set(\"syslinks\", \"toleft\")\n    interp:deduplication_policy_set(\"frameworks\", \"toleft\")\n\n    -- register filter handler\n    interp:filter():register(\"option\", function (variable)\n\n        -- init maps\n        local maps =\n        {\n            arch       = function() return config.get(\"arch\") or os.arch() end\n        ,   plat       = function() return config.get(\"plat\") or os.host() end\n        ,   mode       = function() return config.get(\"mode\") or \"release\" end\n        ,   host       = os.host()\n        ,   subhost    = os.subhost()\n        ,   scriptdir  = function () return interp:pending() and interp:scriptdir() or sandbox_os.scriptdir() end\n        ,   globaldir  = global.directory()\n        ,   configdir  = config.directory()\n        ,   projectdir = os.projectdir()\n        ,   programdir = os.programdir()\n        }\n\n        -- map it\n        local result = maps[variable]\n        if type(result) == \"function\" then\n            result = result()\n        end\n        return result\n    end)\n\n    -- save interpreter\n    option._INTERPRETER = interp\n\n    -- ok?\n    return interp\nend\n\n-- new an option instance\nfunction option.new(name, info)\n    return _instance.new(name, info)\nend\n\n-- load the option info from the cache\nfunction option.load(name, opt)\n    opt = opt or {}\n    local info = option._cache():get(name)\n    if info == nil and opt.namespace then\n        info = option._cache():get(opt.namespace .. \"::\" .. name)\n    end\n    if info == nil then\n        return\n    end\n    return option.new(name, scopeinfo.new(\"option\", info))\nend\n\n-- save all options to the cache file\nfunction option.save()\n    option._cache():save()\nend\n\n-- return module\nreturn option\n"
  },
  {
    "path": "xmake/core/project/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- define module\nlocal package = {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal io            = require(\"base/io\")\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal table         = require(\"base/table\")\nlocal utils         = require(\"base/utils\")\nlocal semver        = require(\"base/semver\")\nlocal rule          = require(\"project/rule\")\nlocal config        = require(\"project/config\")\nlocal sandbox       = require(\"sandbox/sandbox\")\nlocal localcache    = require(\"cache/localcache\")\nlocal instance_deps = require(\"base/private/instance_deps\")\n\n-- save the requires info to the cache\nfunction _instance:save()\n    package._cache():set(self:name(), self._INFO)\n    package._cache():save()\nend\n\n-- clear the package\nfunction _instance:clear()\n    local info = self._INFO\n    if info then\n        for k, v in pairs(info) do\n            if not k:startswith(\"__\") then\n                info[k] = nil\n            end\n        end\n    end\n    self._COMPONENT_DEPS = nil\nend\n\n-- dump this package\nfunction _instance:dump()\n    utils.dump(self._INFO)\nend\n\n-- get the require info\nfunction _instance:get(infoname)\n    return self._INFO[infoname]\nend\n\n-- get the package name (with alias name)\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the full name\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get the package version\nfunction _instance:version()\n\n    -- get it from cache first\n    if self._VERSION ~= nil then\n        return self._VERSION\n    end\n\n    -- get version\n    local version = nil\n    local verstr = self:get(\"version\")\n    if verstr then\n        version = semver.new(verstr)\n    end\n    self._VERSION = version or false\n    return version\nend\n\n-- get the package license\nfunction _instance:license()\n    return self:get(\"license\")\nend\n\n-- has static libraries?\nfunction _instance:has_static()\n    return self:get(\"static\")\nend\n\n-- has shared libraries?\nfunction _instance:has_shared()\n    return self:get(\"shared\")\nend\n\n-- get the require string\nfunction _instance:requirestr()\n    return self:get(\"__requirestr\")\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self:get(\"__namespace\")\nend\n\n-- get the require configuration from the given name\n--\n-- e.g.\n--\n-- add_requires(\"xxx\", {system = true, configs = {shared = true}})\n--\n-- local configs = pkg:requireconf()\n-- local system = pkg:requireconf(\"system\")\n-- local shared = pkg:requireconf(\"configs\", \"shared\")\n--\nfunction _instance:requireconf(name, key)\n    local requireconfs = self:get(\"__requireconfs\")\n    local value = requireconfs\n    if name then\n        value = requireconfs and requireconfs[name] or nil\n        if value and key then\n            value = value[key]\n        end\n    end\n    return value\nend\n\n-- get the install directory\n-- @see https://github.com/xmake-io/xmake/issues/3106\nfunction _instance:installdir()\n    return self:get(\"installdir\")\n        or self:get(\"__installdir\") -- deprecated\nend\n\n-- get library files\nfunction _instance:libraryfiles()\n    return self:get(\"libfiles\")\nend\n\n-- get components\nfunction _instance:components()\n    return self:get(\"components\")\nend\n\n-- get default components\nfunction _instance:components_default()\n    return self:get(\"__components_default\")\nend\n\n-- get components list with link order\nfunction _instance:components_orderlist()\n    return self:get(\"__components_orderlist\")\nend\n\n-- get the dependencies of components\nfunction _instance:components_deps()\n    return self:get(\"__components_deps\")\nend\n\n-- get user extra configuration from package/on_fetch\n-- @see https://github.com/xmake-io/xmake/issues/3106#issuecomment-1330143922\n--\n-- e.g.\n--\n-- @code\n-- package(\"xxx\")\n--     on_fetch(function (package)\n--         return {includedirs = \"\", links = \"\", extras = {foo = \"\"}}\n--     end)\n--\n-- @endcode\n--\n-- we can also get extra configuration from package/add_xxx\n--\n-- e.g.\n--\n-- @code\n-- package(\"xxx\")\n--     add_linkgroups(\"foo\", {group = true})\n--\n-- target:pkg(\"xxx\"):extraconf(\"linkgroups\", \"foo\", \"group\")\n-- @endcode\n--\n-- extras = {\n--     linkgroups = {\n--         z = {\n--             group = true\n--         }\n--     }\n-- }\n--\nfunction _instance:extraconf(name, item, key)\n    local extraconfs = self:get(\"extras\")\n    if not extraconfs then\n        return\n    end\n\n    -- get configuration\n    local extraconf = extraconfs[name]\n\n    -- get configuration value\n    local value = extraconf\n    if item then\n        value = extraconf and extraconf[item] or nil\n        if value == nil and extraconf and type(item) == \"table\" then\n            value = extraconf[table.concat(item, \"_\")]\n        end\n        if value and key then\n            value = value[key]\n        end\n    end\n    return value\nend\n\n-- add extra configuration\nfunction _instance:extraconf_add(name, item)\n    local extraconfs = self:get(\"extras\")\n    if not extraconfs then\n        extraconfs = {}\n    end\n\n    local extraconf = extraconfs[name]\n    if extraconf ~= nil then\n        extraconf = table.wrap(extraconf)\n        table.join2(extraconf, item)\n    else\n        extraconf = item\n    end\n    extraconfs[name] = extraconf\n    self:set(\"extras\", extraconfs)\nend\n\n-- get order dependencies of the given component\nfunction _instance:component_orderdeps(name)\n    local component_orderdeps = self._COMPONENT_ORDERDEPS\n    if not component_orderdeps then\n        component_orderdeps = {}\n        self._COMPONENT_ORDERDEPS = component_orderdeps\n    end\n\n    -- expand dependencies\n    local orderdeps = component_orderdeps[name]\n    if not orderdeps then\n        orderdeps = table.reverse_unique(self:_sort_componentdeps(name))\n        component_orderdeps[name] = orderdeps\n    end\n    return orderdeps\nend\n\n-- set the value to the requires info\nfunction _instance:set(name_or_info, ...)\n    if type(name_or_info) == \"string\" then\n        local args = ...\n        if args ~= nil then\n            self._INFO[name_or_info] = table.unwrap(table.unique(table.join(...)))\n        else\n            self._INFO[name_or_info] = nil\n        end\n    elseif table.is_dictionary(name_or_info) then\n        for name, info in pairs(table.join(name_or_info, ...)) do\n            self:set(name, info)\n        end\n    end\nend\n\n-- add the value to the requires info\nfunction _instance:add(name_or_info, ...)\n    if type(name_or_info) == \"string\" then\n        local name = name_or_info\n        if name == \"extras\" then\n            for _, extraconf in ipairs({...}) do\n                for k, v in pairs(extraconf) do\n                    self:extraconf_add(k, v)\n                end\n            end\n        else\n            local info = table.wrap(self._INFO[name])\n            self._INFO[name] = table.unwrap(table.unique(table.join(info, ...)))\n        end\n    elseif table.is_dictionary(name_or_info) then\n        for name, info in pairs(table.join(name_or_info, ...)) do\n            self:add(name, info)\n        end\n    end\nend\n\n-- this require info is enabled?\nfunction _instance:enabled()\n    return self:get(\"__enabled\")\nend\n\n-- enable or disable this require info\nfunction _instance:enable(enabled)\n    self:set(\"__enabled\", enabled)\nend\n\n-- get environments\nfunction _instance:envs()\n    return self:get(\"envs\")\nend\n\n-- get the given rule\nfunction _instance:rule(name)\n    return self:rules()[name]\nend\n\n-- get package rules\n-- @see https://github.com/xmake-io/xmake/issues/2374\nfunction _instance:rules()\n    local rules = self._RULES\n    if rules == nil then\n        local ruleinfos = {}\n        local installdir = self:installdir()\n        local rulesdir = path.join(installdir, \"rules\")\n        if os.isdir(rulesdir) then\n            local files = os.filedirs(path.join(rulesdir, \"*\"))\n            if files then\n                for _, filepath in ipairs(files) do\n                    local results, errors\n                    if filepath:endswith(\".lua\") then\n                        results, errors = rule._load(filepath)\n                    elseif os.isdir(filepath) and os.isfile(path.join(filepath, \"xmake.lua\")) then\n                        results, errors = rule._load(path.join(filepath, \"xmake.lua\"))\n                    else\n                        os.raise(\"unknown rule %s: %s\", os.isdir(filepath) and \"directory\" or \"file\", filepath)\n                    end\n                    if results then\n                        table.join2(ruleinfos, results)\n                    else\n                        os.raise(errors)\n                    end\n                end\n            end\n        end\n\n        -- make rule instances\n        rules = {}\n        for rulename, ruleinfo in pairs(ruleinfos) do\n            rulename = \"@\" .. self:name() .. \"/\" .. rulename\n            local instance = rule.new(rulename, ruleinfo, {package = self})\n            if instance:script(\"load\") then\n                utils.warning(\"we cannot add `on_load()` in package rule(%s), please use `on_config()` instead of it!\", rulename)\n            end\n            if instance:script(\"load_after\") then\n                utils.warning(\"we cannot add `after_load()` in package rule(%s), please use `on_config()` instead of it!\", rulename)\n            end\n            rules[rulename] = instance\n        end\n        self._RULES = rules\n    end\n    return rules\nend\n\n-- sort component deps\nfunction _instance:_sort_componentdeps(name)\n    local orderdeps = {}\n    local plaindeps = self:components_deps() and self:components_deps()[name]\n    for _, dep in ipairs(table.wrap(plaindeps)) do\n        table.insert(orderdeps, dep)\n        table.join2(orderdeps, self:_sort_componentdeps(dep))\n    end\n    return orderdeps\nend\n\n-- we need to sort package set keys by this string\n-- @see https://github.com/xmake-io/xmake/pull/2971#issuecomment-1290052169\nfunction _instance:__tostring()\n    return \"<package: \" .. self:fullname() .. \">\"\nend\n\n-- get cache\nfunction package._cache()\n    return localcache.cache(\"package\")\nend\n\n-- load the package from the cache\nfunction package.load(name)\n    local info = package._cache():get(name)\n    if info == nil then\n        return\n    end\n    return package.load_withinfo(name, info)\nend\n\n-- load package from the give package info\nfunction package.load_withinfo(name, info)\n    local instance = table.inherit(_instance)\n    instance._INFO = info\n    instance._NAME = name\n    return instance\nend\n\n-- return module\nreturn package\n"
  },
  {
    "path": "xmake/core/project/policy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        policy.lua\n--\n\n-- define module: policy\nlocal policy  = policy or {}\n\n-- load modules\nlocal os      = require(\"base/os\")\nlocal io      = require(\"base/io\")\nlocal path    = require(\"base/path\")\nlocal table   = require(\"base/table\")\nlocal utils   = require(\"base/utils\")\nlocal string  = require(\"base/string\")\n\n-- get all defined policies\nfunction policy.policies()\n    local policies = policy._POLICIES\n    if not policies then\n        policies = {\n            -- We will check and ignore all unsupported flags by default, but we can also pass `{force = true}` to force to set flags, e.g. add_ldflags(\"-static\", {force = true})\n            [\"check.auto_ignore_flags\"]           = {description = \"Enable check and ignore unsupported flags automatically.\", default = true, type = \"boolean\"},\n            -- We will map gcc flags to the current compiler and linker by default.\n            [\"check.auto_map_flags\"]              = {description = \"Enable map gcc flags to the current compiler and linker automatically.\", default = true, type = \"boolean\"},\n            -- We will check the compatibility of target and package licenses\n            [\"check.target_package_licenses\"]     = {description = \"Enable check the compatibility of target and package licenses.\", default = true, type = \"boolean\"},\n            -- Generate intermediate build directory\n            [\"build.intermediate_directory\"]      = {description = \"Generate intermediate build directory.\", default = true, type = \"boolean\"},\n            -- Provide a way to block all targets build that depends on self\n            [\"build.fence\"]                       = {description = \"Block all targets build that depends on self.\", default = false, type = \"boolean\"},\n            -- We can compile the source files for each target in parallel\n            [\"build.across_targets_in_parallel\"]  = {description = \"Enable compile the source files for each target in parallel.\", default = true, type = \"boolean\"},\n            -- Merge archive intead of linking for all dependent targets\n            [\"build.merge_archive\"]               = {description = \"Enable merge archive intead of linking for all dependent targets.\", default = false, type = \"boolean\"},\n            -- C/C++ build cache\n            [\"build.ccache\"]                      = {description = \"Enable C/C++ build cache.\", type = \"boolean\"},\n            -- Use global storage if build.ccache is enabled\n            [\"build.ccache.global_storage\"]       = {description = \"Use global storge if build.ccache is enabled.\", type = \"boolean\"},\n            -- Always update configfiles when building\n            [\"build.always_update_configfiles\"]   = {description = \"Always update configfiles when building.\", type = \"boolean\"},\n            -- Enable build warning output, it's enabled by default.\n            [\"build.warning\"]                     = {description = \"Enable build warning output.\", default = true, type = \"boolean\"},\n            -- Enable LTO linker-time optimization for c/c++ building.\n            [\"build.optimization.lto\"]            = {description = \"Enable LTO linker-time optimization for c/c++ building.\", type = \"boolean\"},\n            -- Enable address sanitizer for c/c++ building.\n            [\"build.sanitizer.address\"]           = {description = \"Enable address sanitizer for c/c++ building.\", type = \"boolean\"},\n            -- Enable thread sanitizer for c/c++ building.\n            [\"build.sanitizer.thread\"]            = {description = \"Enable thread sanitizer for c/c++ building.\", type = \"boolean\"},\n            -- Enable memort sanitizer for c/c++ building.\n            [\"build.sanitizer.memory\"]            = {description = \"Enable memory sanitizer for c/c++ building.\", type = \"boolean\"},\n            -- Enable leak sanitizer for c/c++ building.\n            [\"build.sanitizer.leak\"]              = {description = \"Enable leak sanitizer for c/c++ building.\", type = \"boolean\"},\n            -- Enable undefined sanitizer for c/c++ building.\n            [\"build.sanitizer.undefined\"]         = {description = \"Enable undefined sanitizer for c/c++ building.\", type = \"boolean\"},\n            -- Enable build rpath\n            [\"build.rpath\"]                       = {description = \"Enable build rpath.\", default = true, type = \"boolean\"},\n            -- Strip symbols by default in release mode (mode.release)\n            [\"build.release.strip\"]               = {description = \"Strip symbols by default in release mode.\", default = true, type = \"boolean\"},\n            -- Enable C++ modules for C++ building, even if no .mpp is involved in the compilation\n            [\"build.c++.modules\"]                 = {description = \"Enable C++ modules for C++ building.\", type = \"boolean\"},\n            -- Enable non cascading changes (experimental)\n            [\"build.c++.modules.non_cascading_changes\"] = {description = \"Enable non cascading changes when supported (experimental).\", default = false, type = \"boolean\"},\n            -- Hide C++ required files to reduce noise (may reduce build performance)\n            [\"build.c++.modules.hide_dependencies\"] = {description = \"Hide dependencies from the commandline when build C++ modules.\", default = false, type = \"boolean\"},\n            -- Enable two phase compilation for C++ modules if supported by the compiler\n            [\"build.c++.modules.two_phases\"]      = {description = \"Enable two phase compilation if supported.\", default = true, type = \"boolean\"},\n            -- Enable std module\n            [\"build.c++.modules.std\"]             = {description = \"Enable std modules.\", default = true, type = \"boolean\"},\n            -- Enable unreferenced and non-public named module culling\n            [\"build.c++.modules.culling\"]         = {description = \"Enable unrefereced and non-public named module culling.\", default = true, type = \"boolean\"},\n            -- Always reuse compiled module bmi file\n            [\"build.c++.modules.reuse\"]           = {description = \"Reuse compiled module artifacts if possible.\", default = true, type = \"boolean\"},\n            [\"build.c++.modules.tryreuse\"]        = {description = \"Try to reuse compiled module if possible. (deprecated)\", default = false, type = \"boolean\"},\n            -- Disabled flag check when reusing modules\n            [\"build.c++.modules.reuse.nocheck\"]   = {description = \"Disable flag compatibility check when reusing modules.\", default = false, type = \"boolean\"},\n            -- If target will not reuse modules from target deps if defines are different\n            [\"build.c++.modules.reuse.strict\"]          = {description = \"Enable strict defines comparison when trying to reuse module.\", default = false, type = \"boolean\"},\n            [\"build.c++.modules.tryreuse.discriminate_on_defines\"] = {description = \"Enable defines module reuse discrimination.\", default = false, type = \"boolean\"},\n            -- Force C++ modules fallback dependency scanner for all compilers\n            [\"build.c++.modules.fallbackscanner\"]       = {description = \"Force fallback module dependency scanner.\", default = false, type = \"boolean\"},\n            -- Force C++ modules fallback dependency scanner for clang\n            [\"build.c++.modules.clang.fallbackscanner\"] = {description = \"Force clang fallback module dependency scanner.\", default = false, type = \"boolean\"},\n            [\"build.c++.clang.fallbackscanner\"]         = {description = \"Force clang fallback module dependency scanner. (deprecated)\", default = false, type = \"boolean\"},\n            -- Force C++ modules fallback dependency scanner for msvc\n            [\"build.c++.modules.msvc.fallbackscanner\"]  = {description = \"Force msvc fallback module dependency scanner.\", default = false, type = \"boolean\"},\n            [\"build.c++.msvc.fallbackscanner\"]          = {description = \"Force msvc fallback module dependency scanner. (deprecated)\", default = false, type = \"boolean\"},\n            -- Force C++ modules fallback dependency scanner for gcc\n            [\"build.c++.modules.gcc.fallbackscanner\"]   = {description = \"Force gcc fallback module dependency scanner.\", default = false, type = \"boolean\"},\n            [\"build.c++.gcc.fallbackscanner\"]           = {description = \"Force gcc fallback module dependency scanner. (deprecated)\", default = false, type = \"boolean\"},\n            -- Force to enable new cxx11 abi in C++ modules for gcc\n            -- If in the future, gcc can support it well, we'll turn it on by default\n            -- https://github.com/xmake-io/xmake/issues/3855\n            [\"build.c++.modules.gcc.cxx11abi\"]    = {description = \"Force to enable new cxx11 abi in C++ modules for gcc.\", type = \"boolean\"},\n            [\"build.c++.gcc.modules.cxx11abi\"]    = {description = \"Force to enable new cxx11 abi in C++ modules for gcc. (deprecated)\", type = \"boolean\"},\n            -- Set the default vs runtime, e.g. MT, MD\n            [\"build.c++.msvc.runtime\"]            = {description = \"Set the default vs runtime.\", type = \"string\", values = {\"MT\", \"MD\"}},\n            -- Enable C++ Dynamic Debugging for MSVC (requires MSVC toolset 14.44+, x64 only, incompatible with LTCG/PGO/OPT-ICF).\n            [\"build.c++.dynamic_debugging\"]       = {description = \"Enable C++ Dynamic Debugging for MSVC (requires MSVC toolset 14.44+, x64 only, incompatible with LTCG/PGO/OPT-ICF).\", type = \"boolean\"},\n            -- Enable cuda device link\n            [\"build.cuda.devlink\"]                = {description = \"Enable Cuda devlink.\", type = \"boolean\"},\n            -- Enable linker output, e.g. show -Wl,--print-memory-usage output for gcc/g++\n            -- @see https://github.com/xmake-io/xmake/discussions/6772\n            [\"build.linker.output\"]               = {description = \"Enable linker output.\", type = \"boolean\"},\n            -- Enable build jobgraph\n            [\"build.jobgraph\"]                    = {description = \"Enable build jobgraph.\", default = true, type = \"boolean\"},\n            -- Enable build on only remote machines\n            [\"build.distcc.remote_only\"]          = {description = \"Enable build on only remote machines.\", default = false, type = \"boolean\"},\n            -- Set the build progress output style, e.g. scroll (default), singlerow, multirow\n            [\"build.progress_style\"]              = {description = \"Set the build progress output style.\", type = \"string\", values = {\"scroll\", \"singlerow\", \"multirow\"}},\n            -- Show target name in build progress output\n            [\"build.progress_show_target\"]        = {description = \"Show target name in build progress output.\", default = true, type = \"boolean\"},\n            -- Enable windows UAC and set level, e.g. invoker, admin, highest\n            [\"windows.manifest.uac\"]              = {description = \"Enable windows manifest UAC.\", type = \"string\"},\n            -- Enable ui access for windows UAC\n            [\"windows.manifest.uac.ui\"]           = {description = \"Enable ui access for windows UAC.\", type = \"boolean\"},\n            -- Automatically build before running\n            [\"run.autobuild\"]                     = {description = \"Automatically build before running.\", type = \"boolean\"},\n            -- Enable/Disable Windows Error Reporting Dialogs\n            [\"run.windows_error_dialog\"]          = {description = \"Enable Windows Error Reporting Dialogs during execution.\", default = false, type = \"boolean\"},\n            -- Enable install rpath\n            [\"install.rpath\"]                     = {description = \"Enable install rpath.\", default = true, type = \"boolean\"},\n            -- Strip package libraries for installation\n            [\"install.strip_packagelibs\"]         = {description = \"Strip package libraries for installation.\", default = true, type = \"boolean\"},\n            -- Preprocessor configuration for ccache/distcc, we can disable linemarkers to speed up preprocess\n            [\"preprocessor.linemarkers\"]          = {description = \"Enable linemarkers for preprocessor.\", default = true, type = \"boolean\"},\n            -- Preprocessor configuration for ccache/distcc, we can disable it to avoid cache object file with __DATE__, __TIME__\n            [\"preprocessor.gcc.directives_only\"]  = {description = \"Enable -fdirectives-only for gcc preprocessor.\", type = \"boolean\"},\n            -- We need to enable longpaths when building target or installing package\n            [\"platform.longpaths\"]                = {description = \"Enable long paths when building target or installing package on windows.\", default = false, type = \"boolean\"},\n            -- Lock required packages\n            [\"package.requires_lock\"]             = {description = \"Enable xmake-requires.lock to lock required packages.\", default = false, type = \"boolean\"},\n            -- Enable the precompiled packages, it will be enabled by default\n            [\"package.precompiled\"]               = {description = \"Enable precompiled packages.\", default = true, type = \"boolean\"},\n            -- Only fetch packages on system\n            [\"package.fetch_only\"]                = {description = \"Only fetch packages on system.\", type = \"boolean\"},\n            -- Only install packages from remote\n            [\"package.install_only\"]              = {description = \"Only install packages from remote.\", type = \"boolean\"},\n            -- Always install packages every time\n            [\"package.install_always\"]            = {description = \"Always install packages every time.\", type = \"boolean\"},\n            -- Install packages in the local project folder\n            [\"package.install_locally\"]           = {description = \"Install packages in the local project folder.\", default = false, type = \"boolean\"},\n            -- Keep package source code after installing (disable source dir cleanup)\n            [\"package.keep_source\"]               = {description = \"Keep package source code after installing.\", default = false, type = \"boolean\"},\n            -- Set custom headers when downloading package\n            [\"package.download.http_headers\"]     = {description = \"Set the custom http headers when downloading package.\", type = \"table\"},\n            -- Use includes as external header files? e.g. -isystem ..\n            [\"package.include_external_headers\"]  = {description = \"Use includes as external headers.\", type = \"boolean\"},\n            -- Inherit the configs from the external command arguments, e.g. toolchains, `xmake f --toolchain=`\n            [\"package.inherit_external_configs\"]  = {description = \"Inherit the configs from the external command arguments.\", default = true, type = \"boolean\"},\n            -- Set strict compatibility for package and it's all child packages. we can just set it in package().\n            -- if true, then any updates to this package, such as buildhash changes due to version changes,\n            -- will force all installed child packages to be recompiled and installed, @see https://github.com/xmake-io/xmake/issues/2719\n            [\"package.strict_compatibility\"]      = {description = \"Set strict compatibility for package and it's all child packages.\", type = \"boolean\"},\n            -- Set strict compatibility for package and it's all library dependencies. we can set it in package() and user project configuration.\n            -- if true, then any updates to library dependencies, such as buildhash changes due to version changes,\n            -- will force the installed packages to be recompiled and installed. @see https://github.com/xmake-io/xmake/issues/2719\n            [\"package.librarydeps.strict_compatibility\"] = {description = \"Set strict compatibility for package and it's all library dependencies.\", type = \"boolean\"},\n            -- Resolve package dependencies conflict automatically\n            -- @see https://github.com/xmake-io/xmake/issues/5745\n            [\"package.resolve_depconflict\"]       = {description = \"Automatically resolve package dependencies conflict.\", default = true, type = \"boolean\"},\n            -- Synchronize add_requires configuration in toplevel to all package dependencies for this package\n            -- @see https://github.com/xmake-io/xmake/issues/5745\n            [\"package.sync_requires_to_deps\"]     = {description = \"Synchronize requires configuration to all package dependencies.\", default = false, type = \"boolean\"},\n            -- Automatically passes dependency configuration for inner xmake package\n            -- @see https://github.com/xmake-io/xmake/issues/3952\n            [\"package.xmake.pass_depconfs\"]       = {description = \"Automatically passes dependency configuration for inner xmake package\", default = true, type = \"boolean\"},\n            -- It will force cmake package use ninja for build\n            [\"package.cmake_generator.ninja\"]     = {description = \"Set cmake package use ninja for build\", type = \"boolean\"},\n            -- Enable msbuild MultiToolTask\n            [\"package.msbuild.multi_tool_task\"]   = {description = \"Enable msbuild MultiToolTask.\", default = false, type = \"boolean\"},\n            -- Merge all static libraries after installing package\n            -- @see https://github.com/xmake-io/xmake/issues/5894\n            [\"package.merge_staticlibs\"]          = {description = \"Merge all static libraries after installing package\", type = \"boolean\"},\n            -- C/C++ build cache\n            [\"package.build.ccache\"]              = {description = \"Enable C/C++ package build cache.\", default = false, type = \"boolean\"},\n            -- Stop to test on the first failure\n            [\"test.stop_on_first_failure\"]        = {description = \"Stop to test on the first failure\", default = false, type = \"boolean\"},\n            -- Return zero as exit code on failure\n            [\"test.return_zero_on_failure\"]       = {description = \"Return zero as the exit code on failure\", default = false, type = \"boolean\"},\n            -- Show diagnosis info for checking build dependencies\n            [\"diagnosis.check_build_deps\"]        = {description = \"Show diagnosis info for checking build dependencies\", default = false, type = \"boolean\"},\n            -- Set the network mode, e.g. public/private\n            --   private: it will disable fetch remote package repositories\n            [\"network.mode\"]                      = {description = \"Set the network mode\", type = \"string\"},\n            -- Set the compatibility version, e.g. 2.0, 3.0\n            [\"compatibility.version\"]             = {description = \"Set the compatibility version\", type = \"string\", default = \"3.0\", values = {\"2.0\", \"3.0\"}},\n            -- Enable compile_commands\n            [\"generator.compile_commands\"]        = {description = \"Enable compile_commands.\", default = true, type = \"boolean\"},\n            -- Generate the solution file in root output directory\n            -- @see https://github.com/xmake-io/xmake/issues/6519\n            [\"generator.vsxmake.root_sln\"]        = {description = \"Generate the solution file in root output directory\", default = false, type = \"boolean\"}\n        }\n        policy._POLICIES = policies\n    end\n    return policies\nend\n\n-- set policy default value\nfunction policy.set_default(name, value)\n    local defined_policy = policy.policies()[name]\n    if defined_policy then\n        defined_policy.default = value\n    else\n        os.raise(\"unknown policy(%s)!\", name)\n    end\nend\n\n-- check policy value\nfunction policy.check(name, value)\n    local defined_policy = policy.policies()[name]\n    if defined_policy then\n        if value == nil then\n            value = defined_policy.default\n        else\n            local valtype = type(value)\n            if valtype ~= defined_policy.type then\n                utils.warning(\"policy(%s): invalid value type(%s), it shound be '%s'!\",\n                    name, valtype, defined_policy.type)\n            end\n            if defined_policy.values then\n                local found = false\n                for _, policy_value in ipairs(defined_policy.values) do\n                    if tostring(value) == tostring(policy_value) then\n                        found = true\n                        break\n                    end\n                end\n                if not found then\n                    local values = {}\n                    for _, policy_value in ipairs(defined_policy.values) do\n                        table.insert(values, tostring(policy_value))\n                    end\n                    utils.warning(\"policy(%s): invalid value(%s), please set value from {%s}.\",\n                        name, value, table.concat(values, \", \"))\n                end\n            end\n        end\n        return value\n    else\n        os.raise(\"unknown policy(%s)!\", name)\n    end\nend\n\n-- return module: policy\nreturn policy\n"
  },
  {
    "path": "xmake/core/project/project.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        project.lua\n--\n\n-- define module: project\nlocal project = project or {}\n\n-- load modules\nlocal os                    = require(\"base/os\")\nlocal io                    = require(\"base/io\")\nlocal path                  = require(\"base/path\")\nlocal hash                  = require(\"base/hash\")\nlocal task                  = require(\"base/task\")\nlocal utils                 = require(\"base/utils\")\nlocal table                 = require(\"base/table\")\nlocal global                = require(\"base/global\")\nlocal process               = require(\"base/process\")\nlocal hashset               = require(\"base/hashset\")\nlocal baseoption            = require(\"base/option\")\nlocal semver                = require(\"base/semver\")\nlocal deprecated            = require(\"base/deprecated\")\nlocal interpreter           = require(\"base/interpreter\")\nlocal instance_deps         = require(\"base/private/instance_deps\")\nlocal memcache              = require(\"cache/memcache\")\nlocal rule                  = require(\"project/rule\")\nlocal target                = require(\"project/target\")\nlocal config                = require(\"project/config\")\nlocal option                = require(\"project/option\")\nlocal policy                = require(\"project/policy\")\nlocal project_package       = require(\"project/package\")\nlocal deprecated_project    = require(\"project/deprecated/project\")\nlocal package               = require(\"package/package\")\nlocal platform              = require(\"platform/platform\")\nlocal toolchain             = require(\"tool/toolchain\")\nlocal language              = require(\"language/language\")\nlocal sandbox_os            = require(\"sandbox/modules/os\")\nlocal sandbox_module        = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- register project to platform, rule and target\nplatform._PROJECT = project\ntarget._PROJECT = project\nrule._PROJECT = project\n\n-- the current os is belong to the given os?\nfunction project._api_is_os(interp, ...)\n\n    -- get the current os\n    local os = platform.os()\n    if not os then return false end\n\n    -- exists this os?\n    for _, o in ipairs(table.join(...)) do\n        if o and type(o) == \"string\" and o == os then\n            return true\n        end\n    end\nend\n\n-- the current mode is belong to the given modes?\nfunction project._api_is_mode(interp, ...)\n    return config.is_mode(...)\nend\n\n-- the current platform is belong to the given platforms?\nfunction project._api_is_plat(interp, ...)\n    return config.is_plat(...)\nend\n\n-- the current platform is belong to the given architectures?\nfunction project._api_is_arch(interp, ...)\n    return config.is_arch(...)\nend\n\n-- the current platform and architecture is cross-complation?\nfunction project._api_is_cross(interp)\n    return config.is_cross()\nend\n\n-- the current kind is belong to the given kinds?\nfunction project._api_is_kind(interp, ...)\n\n    -- get the current kind\n    local kind = config.get(\"kind\")\n    if not kind then return false end\n\n    -- exists this kind?\n    for _, k in ipairs(table.pack(...)) do\n        if k and type(k) == \"string\" and k == kind then\n            return true\n        end\n    end\nend\n\n-- the current config is belong to the given config values?\nfunction project._api_is_config(interp, name, ...)\n    local value = config.get(name)\n    local namespace = interp:namespace()\n    if value == nil and namespace then\n        value = config.get(namespace .. \"::\" .. name)\n    end\n    return config._is_value(value, ...)\nend\n\n-- some configs are enabled?\nfunction project._api_has_config(interp, ...)\n    local names = table.pack(...)\n    local namespace = interp:namespace()\n    for _, name in ipairs(names) do\n        local value = config.get(name)\n        if value == nil and namespace then\n            value = config.get(namespace .. \"::\" .. name)\n        end\n        if value then\n            return true\n        end\n    end\n    return false\nend\n\n-- some packages are enabled?\nfunction project._api_has_package(interp, ...)\n    -- only for loading targets\n    local requires = project._memcache():get(\"requires\")\n    if requires then\n        for _, packagename in ipairs(table.pack(...)) do\n            local pkg = requires[packagename]\n            -- attempt to get package with namespace\n            if pkg == nil and packagename:find(\"::\", 1, true) then\n                local parts = packagename:split(\"::\", {plain = true})\n                local namespace_pkg = requires[parts[#parts]]\n                if namespace_pkg and namespace_pkg:namespace() then\n                    local fullname = namespace_pkg:fullname()\n                    if fullname:endswith(packagename) then\n                        pkg = namespace_pkg\n                    end\n                end\n            end\n            if pkg and pkg:enabled() then\n                return true\n            end\n        end\n    end\nend\n\n-- get config from the given name\nfunction project._api_get_config(interp, name)\n    local value = config.get(name)\n    local namespace = interp:namespace()\n    if value == nil and namespace then\n        value = config.get(namespace .. \"::\" .. name)\n    end\n    return value\nend\n\n-- add module directories\nfunction project._api_add_moduledirs(interp, ...)\n    local scriptdir = project.interpreter():scriptdir()\n    for _, dir in ipairs({...}) do\n        if not path.is_absolute(dir) then\n            dir = path.absolute(dir, scriptdir)\n        end\n        sandbox_module.add_directories(dir)\n    end\nend\n\n-- add plugin directories load all plugins from the given directories\nfunction project._api_add_plugindirs(interp, ...)\n    local scriptdir = project.interpreter():scriptdir()\n    local plugindirs = {}\n    for _, dir in ipairs({...}) do\n        if not path.is_absolute(dir) then\n            dir = path.absolute(dir, scriptdir)\n        end\n        table.insert(plugindirs, dir .. \"/*\")\n    end\n    interp:api_builtin_includes(plugindirs)\nend\n\n-- add platform directories\nfunction project._api_add_platformdirs(interp, ...)\n    local scriptdir = project.interpreter():scriptdir()\n    for _, dir in ipairs({...}) do\n        if not path.is_absolute(dir) then\n            dir = path.absolute(dir, scriptdir)\n        end\n        platform.add_directories(dir)\n    end\nend\n\n-- add toolchain directories\nfunction project._api_add_toolchaindirs(interp, ...)\n    local scriptdir = project.interpreter():scriptdir()\n    for _, dir in ipairs({...}) do\n        if not path.is_absolute(dir) then\n            dir = path.absolute(dir, scriptdir)\n        end\n        toolchain.add_directories(dir)\n    end\nend\n\n-- load the project file\nfunction project._load(force, disable_filter)\n\n    -- has already been loaded?\n    if project._memcache():get(\"rootinfo\") and not force then\n        return true\n    end\n\n    -- enter the project directory\n    local oldir, errors = os.cd(os.projectdir())\n    if not oldir then\n        return false, errors\n    end\n\n    -- get interpreter\n    local interp = project.interpreter()\n\n    -- load script\n    local ok, errors = interp:load(project.rootfile(), {on_load_data = function (data)\n            for _, xmakerc_file in ipairs(project.rcfiles()) do\n                if xmakerc_file and os.isfile(xmakerc_file) then\n                    local rcdata = io.readfile(xmakerc_file)\n                    if rcdata then\n                        data = rcdata .. \"\\n\" .. data\n                    end\n                end\n            end\n            return data\n        end})\n    if not ok then\n        return false, (errors or \"load project file failed!\")\n    end\n\n    -- load the root info of the project\n    local rootinfo, errors = project._load_scope(\"root\", true, not disable_filter)\n    if not rootinfo then\n        return false, errors\n    end\n\n    -- load the root info of the target\n    local rootinfo_target, errors = project._load_scope(\"root.target\", true, not disable_filter)\n    if not rootinfo_target then\n        return false, errors\n    end\n\n    -- save the root info\n    project._memcache():set(\"rootinfo\", rootinfo)\n    project._memcache():set(\"rootinfo_target\", rootinfo_target)\n\n    -- leave the project directory\n    oldir, errors = os.cd(oldir)\n    if not oldir then\n        return false, errors\n    end\n    return true\nend\n\n-- load scope from the project file\nfunction project._load_scope(scope_kind, deduplicate, enable_filter)\n\n    -- enter the project directory\n    local oldir, errors = os.cd(os.projectdir())\n    if not oldir then\n        return nil, errors\n    end\n\n    -- get interpreter\n    local interp = project.interpreter()\n\n    -- load scope\n    local results, errors = interp:make(scope_kind, deduplicate, enable_filter)\n    if not results then\n        return nil, errors\n    end\n\n    -- leave the project directory\n    oldir, errors = os.cd(oldir)\n    if not oldir then\n        return nil, errors\n    end\n    return results\nend\n\n-- load tasks\nfunction project._load_tasks()\n\n    -- the project file is not found?\n    if not os.isfile(project.rootfile()) then\n        return {}, nil\n    end\n\n    -- load the project file first and disable filter\n    local ok, errors = project._load(true, true)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load the tasks from the the project file\n    local results, errors = project._load_scope(\"task\", true, true)\n    if not results then\n       return nil, errors or \"load project tasks failed!\"\n    end\n\n    -- bind tasks for menu with an sandbox instance\n    local ok, errors = task._bind(results, project.interpreter())\n    if not ok then\n        return nil, errors\n    end\n\n    -- make task instances\n    local tasks = {}\n    for taskname, taskinfo in pairs(results) do\n        tasks[taskname] = task.new(taskname, taskinfo)\n    end\n    return tasks\nend\n\n-- load rules\nfunction project._load_rules()\n\n    -- load the project file first if has not been loaded?\n    local ok, errors = project._load()\n    if not ok then\n        return nil, errors\n    end\n\n    -- load the rules from the the project file\n    local results, errors = project._load_scope(\"rule\", true, true)\n    if not results then\n        return nil, errors\n    end\n\n    -- make rule instances\n    local rules = {}\n    for rulename, ruleinfo in pairs(results) do\n        rules[rulename] = rule.new(rulename, ruleinfo)\n    end\n    return rules\nend\n\n-- load toolchains\nfunction project._load_toolchains()\n\n    -- load the project file first if has not been loaded?\n    local ok, errors = project._load()\n    if not ok then\n        return nil, errors\n    end\n\n    -- load the toolchain from the the project file\n    local results, errors = project._load_scope(\"toolchain\", true, true)\n    if not results then\n        return nil, errors\n    end\n\n    -- make toolchain instances\n    local toolchains = {}\n    for toolchain_name, toolchain_info in pairs(results) do\n        toolchains[toolchain_name] = toolchain_info\n    end\n    return toolchains\nend\n\n-- load targets\nfunction project._load_targets()\n\n    -- mark targets have been loaded even if it may fail to load.\n    -- because once loaded, there will be some cached state, such as options,\n    -- so if we load it a second time, there will be some hidden state inconsistencies.\n    project._memcache():set(\"targets_loaded\", true)\n\n    -- load all requires first and reload the project file to ensure has_package() works for targets\n    local requires = project.required_packages()\n    local ok, errors = project._load(true)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load targets\n    local results, errors = project._load_scope(\"target\", true, true)\n    if not results then\n        return nil, errors\n    end\n\n    -- make targets\n    local targets = {}\n    for targetname, targetinfo in pairs(results) do\n        local t = target.new(targetname, targetinfo)\n        if t and (t:get(\"enabled\") == nil or t:get(\"enabled\") == true) then\n            targets[targetname] = t\n        end\n    end\n\n    -- load and attach target deps, rules and packages\n    for _, t in pairs(targets) do\n\n        -- load rules from target and language\n        t._RULES = t._RULES or {}\n        local rulenames = {}\n        local extensions = {}\n        table.join2(rulenames, t:get(\"rules\"))\n        for _, sourcefile in ipairs(table.wrap(t:get(\"files\"))) do\n            local extension = path.extension((sourcefile:gsub(\"|.*$\", \"\")))\n            if not extensions[extension] then\n                local sourcekind = t:extraconf(\"files\", sourcefile, \"sourcekind\")\n                local lang = sourcekind and language.load_sk(sourcekind) or language.load_ex(extension)\n                if lang and lang:rules() then\n                    table.join2(rulenames, lang:rules())\n                end\n                extensions[extension] = true\n            end\n        end\n        rulenames = table.unique(rulenames)\n        for _, rulename in ipairs(rulenames) do\n            local r = project.rule(rulename, {namespace = t:namespace()}) or rule.rule(rulename)\n            if r then\n                -- only add target rules\n                if r:kind() == \"target\" then\n                    t._RULES[rulename] = r\n                    for _, deprule in ipairs(r:orderdeps()) do\n                        t._RULES[deprule:name()] = deprule\n                    end\n                end\n            -- we need to ignore `@package/rulename`, it will be loaded later\n            elseif not rulename:match(\"@.-/\") then\n                return nil, string.format(\"unknown rule(%s) in target(%s)!\", rulename, t:name())\n            end\n        end\n\n        -- @note it's deprecated, please use on_load instead of before_load\n        ok, errors = t:_load_before()\n        if not ok then\n            return nil, errors\n        end\n\n        -- we need to call on_load() before building deps/rules,\n        -- so we can use `target:add(\"deps\", \"xxx\")` to add deps in on_load\n        ok, errors = t:_load()\n        if not ok then\n            return nil, errors\n        end\n    end\n    return targets\nend\n\n-- load options\nfunction project._load_options(disable_filter)\n\n    -- the project file is not found?\n    if not os.isfile(project.rootfile()) then\n        return {}, nil\n    end\n\n    -- reload the project file to ensure `if is_plat() then add_packagedirs() end` works\n    local ok, errors = project._load(true, disable_filter)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load the options from the the project file\n    local results, errors = project._load_scope(\"option\", true, not disable_filter)\n    if not results then\n        return nil, errors\n    end\n\n    -- load the options from the package directories, e.g. packagedir/*.pkg\n    for _, packagedir in ipairs(table.wrap(project.get(\"packagedirs\"))) do\n        local packagefiles = os.files(path.join(packagedir, \"*.pkg\", \"xmake.lua\"))\n        if packagefiles then\n            for _, packagefile in ipairs(packagefiles) do\n\n                -- load the package file\n                local interp = option.interpreter()\n                local ok, errors = interp:load(packagefile)\n                if not ok then\n                    return nil, errors\n                end\n\n                -- load the package options from the the package file\n                local packageinfos, errors = interp:make(\"option\", true, not disable_filter)\n                if not packageinfos then\n                    return nil, errors\n                end\n\n                -- transform includedirs and linkdirs\n                local rootdir = path.directory(packagefile)\n                for _, packageinfo in pairs(packageinfos) do\n                    local linkdirs = {}\n                    local includedirs = {}\n                    for _, linkdir in ipairs(table.wrap(packageinfo:get(\"linkdirs\"))) do\n                        table.insert(linkdirs, path.is_absolute(linkdir) and linkdir or path.join(rootdir, linkdir))\n                    end\n                    for _, includedir in ipairs(table.wrap(packageinfo:get(\"includedirs\"))) do\n                        table.insert(includedirs, path.is_absolute(includedir) and includedir or path.join(rootdir, includedir))\n                    end\n                    if #linkdirs > 0 then\n                        packageinfo:set(\"linkdirs\", linkdirs)\n                    end\n                    if #includedirs > 0 then\n                        packageinfo:set(\"includedirs\", includedirs)\n                    end\n                end\n                table.join2(results, packageinfos)\n            end\n        end\n    end\n\n    -- check options\n    local options = {}\n    for optionname, optioninfo in pairs(results) do\n        local instance = option.new(optionname, optioninfo)\n        options[optionname] = instance\n    end\n\n    -- load and attach options deps\n    for _, opt in pairs(options) do\n        opt._DEPS      = opt._DEPS or {}\n        opt._ORDERDEPS = opt._ORDERDEPS or {}\n        instance_deps.load_deps(opt, options, opt._DEPS, opt._ORDERDEPS, {opt:name()})\n    end\n    return options\nend\n\n-- load requires\nfunction project._load_requires()\n\n    -- parse requires\n    local requires = {}\n    local requires_str, requires_extra = project.requires_str()\n    requires_extra = requires_extra or {}\n    for _, requirestr in ipairs(table.wrap(requires_str)) do\n\n        -- get the package name, e.g. packagename[foo,bar] >1.0\n        local packagename = requirestr:split(\"%s\")[1]\n        local packagename_raw, _ = packagename:match(\"(.-)%[(.*)%]\")\n        if packagename_raw and not packagename:find(\"::\", 1, true) then\n            packagename = packagename_raw\n        end\n\n        -- get alias and requireconfs\n        local alias = nil\n        local requireconfs = requires_extra[requirestr]\n        if requireconfs then\n            alias = requireconfs.alias\n        end\n\n        -- load it from cache first\n        local name = alias or packagename\n        local instance = project_package.load(name)\n        if not instance then\n            local info = {__requirestr = requirestr, __requireconfs = requireconfs}\n            instance = project_package.load_withinfo(name, info)\n        end\n\n        -- add require info\n        requires[name] = instance\n    end\n    return requires\nend\n\n-- load the packages from the the project file and disable filter, we will process filter after a while\nfunction project._load_packages()\n\n    -- load the project file first if has not been loaded?\n    local ok, errors = project._load()\n    if not ok then\n        return nil, errors\n    end\n\n    -- load packages\n    return project._load_scope(\"package\", true, false)\nend\n\n-- get project memcache\nfunction project._memcache()\n    return memcache.cache(\"core.project.project\")\nend\n\n-- get project toolchain infos (@note only with toolchain info)\nfunction project._toolchains()\n    local toolchains = project._memcache():get(\"toolchains\")\n    if not toolchains then\n        local errors\n        toolchains, errors = project._load_toolchains()\n        if not toolchains then\n            os.raise(errors)\n        end\n        -- load toolchains from data file from \"package.tools.xmake\" module\n        local toolchain_datafiles = os.getenv(\"XMAKE_TOOLCHAIN_DATAFILES\")\n        if toolchain_datafiles then\n            toolchain_datafiles = path.splitenv(toolchain_datafiles)\n            if toolchain_datafiles and #toolchain_datafiles > 0 then\n                for _, toolchain_datafile in ipairs(toolchain_datafiles) do\n                    local toolchain_inst, errors = toolchain.load_fromfile(toolchain_datafile)\n                    if toolchain_inst then\n                        -- @note we use this passed toolchain configuration first if this toolchain has been defined in current project\n                        toolchains[toolchain_inst:name()] = toolchain_inst\n                    else\n                        os.raise(errors)\n                    end\n                end\n            end\n        end\n        project._memcache():set(\"toolchains\", toolchains)\n    end\n    return toolchains\nend\n\n-- get project apis\nfunction project.apis()\n\n    return\n    {\n        values =\n        {\n            -- set_xxx\n            \"set_project\"\n        ,   \"set_description\"\n        ,   \"set_allowedmodes\"\n        ,   \"set_allowedplats\"\n        ,   \"set_allowedarchs\"\n        ,   \"set_defaultmode\"\n        ,   \"set_defaultplat\"\n        ,   \"set_defaultarchs\"\n            -- add_xxx\n        ,   \"add_requires\"\n        ,   \"add_requireconfs\"\n        ,   \"add_repositories\"\n        }\n    ,   paths =\n        {\n            -- add_xxx\n            \"add_packagedirs\"\n        }\n    ,   keyvalues =\n        {\n            \"set_config\"\n        }\n    ,   custom =\n        {\n            -- is_xxx\n            {\"is_os\",                   project._api_is_os             }\n        ,   {\"is_kind\",                 project._api_is_kind           }\n        ,   {\"is_arch\",                 project._api_is_arch           }\n        ,   {\"is_mode\",                 project._api_is_mode           }\n        ,   {\"is_plat\",                 project._api_is_plat           }\n        ,   {\"is_cross\",                project._api_is_cross          }\n        ,   {\"is_config\",               project._api_is_config         }\n            -- get_xxx\n        ,   {\"get_config\",              project._api_get_config        }\n            -- has_xxx\n        ,   {\"has_config\",              project._api_has_config        }\n        ,   {\"has_package\",             project._api_has_package       }\n            -- add_xxx\n        ,   {\"add_moduledirs\",          project._api_add_moduledirs    }\n        ,   {\"add_plugindirs\",          project._api_add_plugindirs    }\n        ,   {\"add_platformdirs\",        project._api_add_platformdirs  }\n        ,   {\"add_toolchaindirs\",       project._api_add_toolchaindirs }\n        }\n    }\nend\n\n-- get interpreter\nfunction project.interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if project._INTERPRETER then\n        return project._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- set root directory\n    interp:rootdir_set(project.directory())\n\n    -- set root scope\n    interp:rootscope_set(\"target\")\n\n    -- define apis for rule\n    interp:api_define(rule.apis())\n\n    -- define apis for task\n    interp:api_define(task.apis())\n\n    -- define apis for target\n    interp:api_define(target.apis())\n\n    -- define apis for option\n    interp:api_define(option.apis())\n\n    -- define apis for package\n    interp:api_define(package.apis())\n\n    -- define apis for language\n    interp:api_define(language.apis())\n\n    -- define apis for toolchain\n    interp:api_define(toolchain.apis())\n\n    -- define apis for project\n    interp:api_define(project.apis())\n\n    -- we need to be able to precisely control the direction of deduplication of different types of values.\n    -- the default is to de-duplicate from left to right, but like links/syslinks need to be de-duplicated from right to left.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/1903\n    --\n    interp:deduplication_policy_set(\"links\", \"toleft\")\n    interp:deduplication_policy_set(\"syslinks\", \"toleft\")\n    interp:deduplication_policy_set(\"frameworks\", \"toleft\")\n\n    -- register api: deprecated\n    deprecated_project.api_register(interp)\n\n    -- set filter\n    interp:filter():register(\"project\", function (variable)\n\n        -- check\n        assert(variable)\n\n        -- hack builddir first\n        if variable == \"builddir\" or variable == \"buildir\" then\n            if variable == \"buildir\" then\n                utils.warning(\"$(buildir) has been deprecated, please use $(builddir)\")\n            end\n            return config.builddir()\n        end\n\n        -- attempt to get it directly from the configure\n        local result = config.get(variable)\n        if not result or type(result) ~= \"string\" then\n\n            -- init maps\n            local maps =\n            {\n                os          = platform.os()\n            ,   host        = os.host()\n            ,   subhost     = os.subhost()\n            ,   tmpdir      = function () return os.tmpdir() end\n            ,   curdir      = function () return os.curdir() end\n            ,   scriptdir   = function () return interp:pending() and interp:scriptdir() or sandbox_os.scriptdir() end\n            ,   globaldir   = global.directory()\n            ,   configdir   = config.directory()\n            ,   projectdir  = project.directory()\n            ,   programdir  = os.programdir()\n            }\n\n            -- map it\n            result = maps[variable]\n            if type(result) == \"function\" then\n                result = result()\n            end\n        end\n        return result\n    end)\n\n    -- save interpreter\n    project._INTERPRETER = interp\n\n    -- ok?\n    return interp\nend\n\n-- get the root project file\nfunction project.rootfile()\n    return os.projectfile()\nend\n\n-- get all loaded project files with subfiles (xmake.lua)\nfunction project.allfiles()\n    local files = {}\n    table.join2(files, project.interpreter():scriptfiles())\n    for _, rcfile in ipairs(project.rcfiles()) do\n        if rcfile and os.isfile(rcfile) then\n            table.insert(files, rcfile)\n        end\n    end\n    return files\nend\n\n-- get the global rcfiles: ~/.xmakerc.lua\nfunction project.rcfiles()\n    local rcfiles = project._XMAKE_RCFILES\n    if rcfiles == nil then\n        rcfiles = {}\n        local rcpaths = {}\n        local rcpaths_env = os.getenv(\"XMAKE_RCFILES\")\n        if rcpaths_env then\n            table.join2(rcpaths, path.splitenv(rcpaths_env))\n        end\n        table.join2(rcpaths, {\"/etc/xmakerc.lua\", \"~/.xmakerc.lua\", path.join(global.directory(), \"xmakerc.lua\")})\n        for _, rcfile in ipairs(rcpaths) do\n            if os.isfile(rcfile) then\n                table.insert(rcfiles, rcfile)\n            end\n        end\n        project._XMAKE_RCFILES = rcfiles\n    end\n    return rcfiles\nend\n\n-- get the project directory\nfunction project.directory()\n    return os.projectdir()\nend\n\n-- get the filelock of the whole project directory\nfunction project.filelock()\n    local errors\n    local filelock = project._FILELOCK\n    if filelock == nil then\n        filelock, errors = io.openlock(path.join(config.directory(), \"project.lock\"))\n        project._FILELOCK = filelock\n    end\n    return filelock, errors\nend\n\n-- get the root configuration\n--\n-- get root values in project, e.g project.get(\"name\")\n-- get root values in target, e.g. project.get(\"target.name\")\n-- get root values in specific namespace, e.g. project.get(\"ns1::ns2::name\"), project.get(\"target.ns1::ns2::name\")\nfunction project.get(name)\n    local rootinfo\n    if name and name:startswith(\"target.\") then\n        name = name:sub(8)\n        rootinfo = project._memcache():get(\"rootinfo_target\")\n    else\n        rootinfo = project._memcache():get(\"rootinfo\")\n    end\n    return rootinfo and rootinfo:get(name) or nil\nend\n\n-- get the root extra configuration\nfunction project.extraconf(name, item, key)\n    local rootinfo\n    if name and name:startswith(\"target.\") then\n        name = name:sub(8)\n        rootinfo = project._memcache():get(\"rootinfo_target\")\n    else\n        rootinfo = project._memcache():get(\"rootinfo\")\n    end\n    return rootinfo and rootinfo:extraconf(name, item, key) or nil\nend\n\n-- get the project name\nfunction project.name()\n    local name = project.get(\"project\")\n    -- TODO multi project names? we only get the first name now.\n    -- and we need to improve it in the future.\n    if type(name) == \"table\" then\n        name = name[1]\n    end\n    return name\nend\n\n-- get the project version, the root version of the target scope\nfunction project.version()\n    return project.get(\"target.version\")\nend\n\n-- get the project namespaces\nfunction project.namespaces()\n    return project.interpreter():namespaces()\nend\n\n-- init default policies\n-- @see https://github.com/xmake-io/xmake/issues/5527\nfunction project._init_default_policies()\n    local compatibility_version = project.policy(\"compatibility.version\")\n    if compatibility_version then\n        if semver.compare(compatibility_version, \"3.0\") >= 0 then\n            policy.set_default(\"package.cmake_generator.ninja\", true)\n            policy.set_default(\"build.c++.msvc.runtime\", \"MD\")\n            policy.set_default(\"run.autobuild\", true)\n        else\n            policy.set_default(\"package.cmake_generator.ninja\", false)\n            policy.set_default(\"build.c++.msvc.runtime\", \"MT\")\n        end\n    end\nend\n\n-- get the project policy, the root policy of the target scope\nfunction project.policy(name)\n    local policies = project._memcache():get(\"policies\")\n    if not policies then\n\n        -- init default policies\n        if name ~= \"compatibility.version\" then\n            if not project._DEFAULT_POLICIES_INITED then\n                project._init_default_policies()\n                project._DEFAULT_POLICIES_INITED = true\n            end\n        end\n\n        -- get policies from project, e.g. set_policy(\"xxx\", true)\n        policies = project.get(\"target.policy\")\n\n        -- get policies from config, e.g. xmake f --policies=package.precompiled:n,package.install_only\n        -- @see https://github.com/xmake-io/xmake/issues/2318\n        local policies_config = config.get(\"policies\")\n        if policies_config then\n            for _, policy in ipairs(policies_config:split(\",\", {plain = true})) do\n                local splitinfo = policy:split(\":\", {limit = 2})\n                local name = splitinfo[1]\n                if #splitinfo > 1 then\n                    policies = policies or {}\n                    policies[name] = baseoption.boolean(splitinfo[2])\n                else\n                    policies = policies or {}\n                    policies[name] = true\n                end\n            end\n        end\n\n        -- get policies from global, e.g. xmake g --policies=run.autobuild\n        local policies_config_global = global.get(\"policies\")\n        if policies_config_global then\n            for _, policy in ipairs(policies_config_global:split(\",\", {plain = true})) do\n                local splitinfo = policy:split(\":\", {limit = 2})\n                local name = splitinfo[1]\n                if #splitinfo > 1 then\n                    policies = policies or {}\n                    if policies[name] == nil then\n                        policies[name] = baseoption.boolean(splitinfo[2])\n                    end\n                else\n                    policies = policies or {}\n                    if policies[name] == nil then\n                        policies[name] = true\n                    end\n                end\n            end\n        end\n\n        project._memcache():set(\"policies\", policies)\n        if policies then\n            local defined_policies = policy.policies()\n            for name, _ in pairs(policies) do\n                if not defined_policies[name] then\n                    utils.warning(\"unknown policy(%s), please run `xmake l core.project.policy.policies` if you want to all policies\", name)\n                end\n            end\n        end\n    end\n    return policy.check(name, policies and policies[name])\nend\n\n-- set the project policy in memory\nfunction project.policy_set(name, value)\n    -- get current policies from cache or initialize\n    local policies = project._memcache():get(\"policies\")\n    if not policies then\n        -- force initialization by calling policy() once\n        project.policy(name)\n        policies = project._memcache():get(\"policies\")\n    end\n    policies = policies or {}\n    \n    -- set the policy value\n    policies[name] = value\n    \n    -- update cache\n    project._memcache():set(\"policies\", policies)\nend\n\n-- project has been loaded?\nfunction project.is_loaded()\n    return project._memcache():get(\"targets_loaded\")\nend\n\n-- get the given target\nfunction project.target(name, opt)\n    opt = opt or {}\n    local targets = project.targets()\n    if targets then\n        local t = targets[name]\n        if not t and opt.namespace then\n            t = targets[opt.namespace .. \"::\" .. name]\n        end\n        return t\n    end\nend\n\n-- add the given target, @note if the target name is the same, it will be replaced\nfunction project.target_add(t)\n    local targets = project.targets()\n    if targets then\n        targets[t:name()] = t\n        project._memcache():set(\"ordertargets\", nil)\n    end\nend\n\n-- get targets\nfunction project.targets()\n    local loading = false\n    local targets = project._memcache():get(\"targets\")\n    if not targets then\n        local errors\n        targets, errors = project._load_targets()\n        if errors then\n            os.raise(errors)\n        end\n        project._memcache():set(\"targets\", targets)\n        loading = true\n    end\n    if loading then\n        -- do after_load() for targets\n        -- @note we must call it after finishing to cache targets\n        -- because we maybe will call project.targets() in after_load, we need avoid dead recursion loop\n        for _, t in ipairs(project.ordertargets()) do\n            local ok, errors = t:_load_after()\n            if not ok then\n                os.raise(errors or string.format(\"load target %s failed\", t:name()))\n            end\n        end\n    end\n    return targets\nend\n\n-- get order targets\nfunction project.ordertargets()\n    local ordertargets = project._memcache():get(\"ordertargets\")\n    if not ordertargets then\n        ordertargets = instance_deps.sort(project.targets())\n        project._memcache():set(\"ordertargets\", ordertargets)\n    end\n    return ordertargets\nend\n\n-- get the given option\nfunction project.option(name, opt)\n    opt = opt or {}\n    local options = project.options()\n    if options then\n        local o = options[name]\n        if not o and opt.namespace then\n            o = options[opt.namespace .. \"::\" .. name]\n        end\n        return o\n    end\nend\n\n-- get options\nfunction project.options()\n    local options = project._memcache():get(\"options\")\n    if not options then\n        local errors\n        options, errors = project._load_options()\n        if not options then\n            os.raise(errors)\n        end\n        project._memcache():set(\"options\", options)\n    end\n    return options\nend\n\n-- get the given required package\nfunction project.required_package(name)\n    return project.required_packages()[name]\nend\n\n-- get required packages\nfunction project.required_packages()\n    local requires = project._memcache():get(\"requires\")\n    if not requires then\n        local errors\n        requires, errors = project._load_requires()\n        if not requires then\n            os.raise(errors)\n        end\n        project._memcache():set(\"requires\", requires)\n    end\n    return requires\nend\n\n-- get string requires\nfunction project.requires_str()\n    local requires_str   = project._memcache():get(\"requires_str\")\n    local requires_extra = project._memcache():get(\"requires_extra\")\n    if not requires_str then\n\n        -- reload the project file to handle `has_config()`\n        local ok, errors = project._load(true)\n        if not ok then\n            os.raise(errors)\n        end\n\n        -- get raw requires\n        requires_str, requires_extra = project.get(\"requires\"), project.get(\"__extra_requires\")\n        local namespaces = project.namespaces()\n        if namespaces then\n            for _, namespace in ipairs(namespaces) do\n                local ns_requires_str, ns_requires_extra = project.get(namespace .. \"::requires\"), project.get(namespace .. \"::__extra_requires\")\n                if ns_requires_str then\n                    requires_str = table.wrap(requires_str)\n                    table.join2(requires_str, ns_requires_str)\n                end\n                if ns_requires_extra then\n                    requires_extra = table.wrap(requires_extra)\n                    table.join2(requires_extra, ns_requires_extra)\n                end\n            end\n        end\n        project._memcache():set(\"requires_str\", requires_str or false)\n        project._memcache():set(\"requires_extra\", requires_extra)\n\n        -- get raw requireconfs\n        local requireconfs_str, requireconfs_extra = project.get(\"requireconfs\"), project.get(\"__extra_requireconfs\")\n        if namespaces then\n            for _, namespace in ipairs(project.namespaces()) do\n                local ns_requireconfs_str, ns_requireconfs_extra = project.get(namespace .. \"::requireconfs\"), project.get(namespace .. \"::__extra_requireconfs\")\n                if ns_requireconfs_str then\n                    requireconfs_str = table.wrap(requireconfs_str)\n                    table.join2(requireconfs_str, ns_requireconfs_str)\n                end\n                if ns_requireconfs_extra then\n                    requireconfs_extra = table.wrap(requireconfs_extra)\n                    table.join2(requireconfs_extra, ns_requireconfs_extra)\n                end\n            end\n        end\n        project._memcache():set(\"requireconfs_str\", requireconfs_str or false)\n        project._memcache():set(\"requireconfs_extra\", requireconfs_extra)\n    end\n    return requires_str or nil, requires_extra\nend\n\n-- get string requireconfs\nfunction project.requireconfs_str()\n    project.requires_str()\n    local requireconfs_str   = project._memcache():get(\"requireconfs_str\")\n    local requireconfs_extra = project._memcache():get(\"requireconfs_extra\")\n    -- synchronize requires configuration to all package dependencies.\n    -- @see https://github.com/xmake-io/xmake/issues/5745#issuecomment-2513951471\n    if project.policy(\"package.sync_requires_to_deps\") then\n        local requires_str   = project._memcache():get(\"requires_str\")\n        local requires_extra = project._memcache():get(\"requires_extra\")\n        local sync_requires_to_deps = project._memcache():get(\"package.sync_requires_to_deps\")\n        if requires_str and not sync_requires_to_deps then\n            local package_utils = project._package_utils\n            if package_utils == nil then\n                package_utils = sandbox_module.import(\"private.utils.package\", {anonymous = true})\n                project._package_utils = package_utils\n            end\n            requires_extra = requires_extra and table.wrap(requires_extra) or {}\n            requireconfs_str = requireconfs_str and table.wrap(requireconfs_str) or {}\n            requireconfs_extra = requireconfs_extra and table.wrap(requireconfs_extra) or {}\n            for _, require_str in ipairs(table.wrap(requires_str)) do\n                if not require_str:find(\"::\", 1, true) then\n                    local packagename, packageversion = package_utils.parse_requirestr(require_str)\n                    local requireconf_str = \"**.\" .. packagename\n                    local requireconf_extra = table.clone(requires_extra[require_str])\n                    if requireconf_extra then\n                        requireconf_extra.configs = table.clone(requireconf_extra.configs) or {}\n                    end\n                    if packageversion then\n                        requireconf_extra = requireconf_extra or {configs = {}}\n                        requireconf_extra.version = packageversion\n                    end\n                    if requireconf_extra then\n                        requireconf_extra.override = true\n                        table.insert(requireconfs_str, requireconf_str)\n                        requireconfs_extra[requireconf_str] = requireconf_extra\n                    end\n                end\n            end\n            project._memcache():set(\"requireconfs_str\", requireconfs_str)\n            project._memcache():set(\"requireconfs_extra\", requireconfs_extra)\n            project._memcache():set(\"package.sync_requires_to_deps\", true)\n        end\n    end\n    return requireconfs_str, requireconfs_extra\nend\n\n-- get requires lockfile\nfunction project.requireslock()\n    return path.join(project.directory(), \"xmake-requires.lock\")\nend\n\n-- get the format version of requires lockfile\nfunction project.requireslock_version()\n    return \"1.0\"\nend\n\n-- get the given rule\nfunction project.rule(name, opt)\n    opt = opt or {}\n    local r = project.rules()[name]\n    if r == nil and opt.namespace then\n        r = project.rules()[opt.namespace .. \"::\" .. name]\n    end\n    return r\nend\n\n-- get project rules\nfunction project.rules()\n    local rules = project._memcache():get(\"rules\")\n    if not rules then\n        local errors\n        rules, errors = project._load_rules()\n        if not rules then\n            os.raise(errors)\n        end\n        project._memcache():set(\"rules\", rules)\n    end\n    return rules\nend\n\n-- get the given toolchain\nfunction project.toolchain(name, opt)\n    opt = opt or {}\n    local parseinfo = toolchain.parsename(name) -- we need to ignore `@packagename`\n    local toolchain_name = parseinfo.name\n    local info = project._toolchains()[toolchain_name]\n    if info == nil and opt.namespace then\n        local requirestr = parseinfo.requirestr\n        if requirestr then\n            toolchain_name = toolchain_name .. \"[\" .. requirestr .. \"]\"\n        end\n        info = project._toolchains()[opt.namespace .. \"::\" .. toolchain_name]\n    end\n    if info then\n        return toolchain.load_withinfo(name, info, opt)\n    end\nend\n\n-- get project toolchains list\nfunction project.toolchains()\n    return table.keys(project._toolchains())\nend\n\n-- get the given task\nfunction project.task(name)\n    return project.tasks()[name]\nend\n\n-- get tasks\nfunction project.tasks()\n    local tasks = project._memcache():get(\"tasks\")\n    if not tasks then\n        local errors\n        tasks, errors = project._load_tasks()\n        if not tasks then\n            os.raise(errors)\n        end\n        project._memcache():set(\"tasks\", tasks)\n    end\n    return tasks\nend\n\n-- get packages\nfunction project.packages()\n    local packages = project._memcache():get(\"packages\")\n    if not packages then\n        local errors\n        packages, errors = project._load_packages()\n        if not packages then\n            return nil, errors\n        end\n        project._memcache():set(\"packages\", packages)\n    end\n    return packages\nend\n\n-- get the mtimes\nfunction project.mtimes()\n    local mtimes = project._MTIMES\n    if not mtimes then\n        mtimes = project.interpreter():mtimes()\n        for _, rcfile in ipairs(project.rcfiles()) do\n            mtimes[rcfile] = os.mtime(rcfile)\n        end\n        project._MTIMES = mtimes\n    end\n    return mtimes\nend\n\n-- get the project menu\nfunction project.menu()\n\n    -- we cannot only get it in main thread\n    if not xmake.in_main_thread() then\n        return {}\n    end\n\n    -- attempt to load options from the project file\n    local options = nil\n    local errors = nil\n    if os.isfile(project.rootfile()) then\n        options, errors = project._load_options(true)\n    end\n\n    -- failed?\n    if not options then\n        if errors then utils.error(errors) end\n        return {}\n    end\n\n    -- arrange options by category\n    local options_by_category = {}\n    for _, opt in pairs(options) do\n\n        -- make the category\n        local category = \"default\"\n        if opt:get(\"category\") then category = table.unwrap(opt:get(\"category\")) end\n        options_by_category[category] = options_by_category[category] or {}\n\n        -- append option to the current category\n        options_by_category[category][opt:fullname()] = opt\n    end\n\n    -- make menu by category\n    local menu = {}\n    for k, opts in pairs(options_by_category) do\n\n        -- insert options\n        local first = true\n        for name, opt in pairs(opts) do\n\n            -- show menu?\n            if opt:showmenu() ~= false then\n\n                -- the default value\n                local default = \"auto\"\n                if opt:get(\"default\") ~= nil then\n                    default = opt:get(\"default\")\n                end\n\n                -- is first?\n                if first then\n\n                    -- insert a separator\n                    table.insert(menu, {})\n\n                    -- not first\n                    first = false\n                end\n\n                -- append it\n                local longname = name\n                local description = opt:description()\n                if description then\n\n                    -- define menu option\n                    local menu_options = {nil, longname, \"kv\", default, description}\n\n                    -- handle set_description(\"xx\", \"xx\")\n                    if type(description) == \"table\" then\n                        for i, description in ipairs(description) do\n                            menu_options[4 + i] = description\n                        end\n                    end\n\n                    -- insert option into menu\n                    table.insert(menu, menu_options)\n                else\n                    table.insert(menu, {nil, longname, \"kv\", default, nil})\n                end\n            end\n        end\n    end\n    return menu\nend\n\n-- get the temporary directory of project\nfunction project.tmpdir(opt)\n\n    local tmpdir = project._TMPDIR\n    if not tmpdir then\n        if os.isdir(config.directory()) then\n            local tmpdir_root = path.join(config.directory(), \"tmp\")\n            tmpdir = path.join(tmpdir_root, os.date(\"%y%m%d\"))\n            if not os.isdir(tmpdir) then\n                os.mkdir(tmpdir)\n            end\n        else\n            tmpdir = os.tmpdir()\n        end\n    end\n    return tmpdir\nend\n\n-- generate the temporary file path of project\n--\n-- e.g.\n-- project.tmpfile(\"key\")\n-- project.tmpfile({key = \"xxx\"})\n--\nfunction project.tmpfile(opt_or_key)\n    local opt\n    local key = opt_or_key\n    if type(key) == \"table\" then\n        key = opt_or_key.key\n        opt = opt_or_key\n    end\n    local filename = \"_\" .. (key and hash.strhash128(key) or (hash.rand128()))\n    return path.join(project.tmpdir(opt), \"_\" .. filename)\nend\n\n-- get all modes\nfunction project.modes()\n    local modes\n    local allowed_modes = project.allowed_modes()\n    if allowed_modes then\n        modes = allowed_modes:to_array()\n    else\n        modes = {}\n        for _, target in table.orderpairs(table.wrap(project.targets())) do\n            for _, rule in ipairs(target:orderules()) do\n                local name = rule:name()\n                if name:startswith(\"mode.\") then\n                    table.insert(modes, name:sub(6))\n                end\n            end\n        end\n        modes = table.unique(modes)\n    end\n    return modes\nend\n\n-- get default architectures from the given platform\n--\n-- set_defaultarchs(\"linux|x86_64\", \"iphoneos|arm64\")\n--\nfunction project.default_arch(plat)\n    local default_archs = project._memcache():get(\"defaultarchs\")\n    if not default_archs then\n        default_archs = {}\n        for _, defaultarch in ipairs(table.wrap(project.get(\"defaultarchs\"))) do\n            local splitinfo = defaultarch:split('|')\n            if #splitinfo == 2 then\n                default_archs[splitinfo[1]] = splitinfo[2]\n            elseif #splitinfo == 1 and not default_archs.default then\n                default_archs.default = defaultarch\n            end\n        end\n        project._memcache():set(\"defaultarchs\", default_archs or false)\n    end\n    return default_archs[plat or \"default\"] or default_archs[\"default\"]\nend\n\n-- get allowed modes\n--\n-- set_allowedmodes(\"releasedbg\", \"debug\")\n--\nfunction project.allowed_modes()\n    local allowed_modes_set = project._memcache():get(\"allowedmodes\")\n    if not allowed_modes_set then\n        local allowed_modes = table.wrap(project.get(\"allowedmodes\"))\n        if #allowed_modes > 0 then\n            allowed_modes_set = hashset.from(allowed_modes)\n        end\n        project._memcache():set(\"allowedmodes\", allowed_modes_set or false)\n    end\n    return allowed_modes_set or nil\nend\n\n-- get allowed platforms\n--\n-- set_allowedplats(\"windows\", \"mingw\", \"linux\", \"macosx\")\n--\nfunction project.allowed_plats()\n    local allowed_plats_set = project._memcache():get(\"allowedplats\")\n    if not allowed_plats_set then\n        local allowed_plats = table.wrap(project.get(\"allowedplats\"))\n        if #allowed_plats > 0 then\n            allowed_plats_set = hashset.from(allowed_plats)\n        end\n        project._memcache():set(\"allowedplats\", allowed_plats_set or false)\n    end\n    return allowed_plats_set or nil\nend\n\n-- get allowed architectures\n--\n-- set_allowedarchs(\"macosx|arm64\", \"macosx|x86_64\", \"linux|i386\")\n--\nfunction project.allowed_archs(plat)\n    plat = plat or \"\"\n    local allowed_archs_set = project._memcache():get2(\"allowedarchs\", plat)\n    if not allowed_archs_set then\n        local allowed_archs = table.wrap(project.get(\"allowedarchs\"))\n        if #allowed_archs > 0 then\n            for _, allowed_arch in ipairs(allowed_archs) do\n                local splitinfo = allowed_arch:split('|')\n                local splitplat, splitarch\n                if #splitinfo == 2 then\n                    splitplat = splitinfo[1]\n                    splitarch = splitinfo[2]\n                elseif #splitinfo == 1 then\n                    splitarch = allowed_arch\n                end\n                if plat == splitplat or splitplat == nil then\n                    if not allowed_archs_set then\n                        allowed_archs_set = hashset.new()\n                    end\n                    allowed_archs_set:insert(splitarch)\n                end\n            end\n        end\n        project._memcache():set2(\"allowedarchs\", plat, allowed_archs_set or false)\n    end\n    return allowed_archs_set or nil\nend\n\n-- return module: project\nreturn project\n"
  },
  {
    "path": "xmake/core/project/rule.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rule.lua\n--\n\n-- define module\nlocal rule = rule or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal global         = require(\"base/global\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal instance_deps  = require(\"base/private/instance_deps\")\nlocal select_script  = require(\"base/private/select_script\")\nlocal config         = require(\"project/config\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal sandbox_os     = require(\"sandbox/modules/os\")\nlocal sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- get package\nfunction _instance:_package()\n    return self._PACKAGE\nend\n\n-- invalidate the previous cache\nfunction _instance:_invalidate(name)\n    if name == \"deps\" then\n        self._DEPS = nil\n        self._ORDERDEPS = nil\n    end\nend\n\n-- build deps\nfunction _instance:_build_deps()\n    local instances = table.clone(rule.rules())\n    if rule._project() then\n        table.join2(instances, rule._project().rules())\n    end\n    if self:_package() then\n        table.join2(instances, self:_package():rules())\n    end\n    self._DEPS      = self._DEPS or {}\n    self._ORDERDEPS = self._ORDERDEPS or {}\n    instance_deps.load_deps(self, instances, self._DEPS, self._ORDERDEPS, {self:fullname()})\n\n    -- compatible with `add_deps(\"foo\", {order = true})`\n    local plaindeps = self:get(\"deps\")\n    if plaindeps then\n        for _, depname in ipairs(table.wrap(plaindeps)) do\n            if self:extraconf(\"deps\", depname, \"order\") then\n                self:add(\"orders\", depname, self:name())\n                utils.warning(\"add_deps(%s, {order = true}) has been deprecated, please use `add_orders(%s, %s) instead of it`\",\n                    depname, depname, self:name())\n            end\n        end\n    end\nend\n\n-- clone rule\nfunction _instance:clone()\n    local instance = rule.new(self:fullname(), self._INFO:clone())\n    instance._DEPS = self._DEPS\n    instance._ORDERDEPS = self._ORDERDEPS\n    instance._PACKAGE = self._PACKAGE\n    return instance\nend\n\n-- get the rule info\nfunction _instance:get(name)\n    return self._INFO:get(name)\nend\n\n-- set the value to the rule info\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\n    self:_invalidate(name)\nend\n\n-- add the value to the rule info\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\n    self:_invalidate(name)\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    return self._INFO:extraconf(name, item, key)\nend\n\n-- set the extra configuration\nfunction _instance:extraconf_set(name, item, key, value)\n    return self._INFO:extraconf_set(name, item, key, value)\nend\n\n-- get the rule name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- set the rule name\nfunction _instance:name_set(name)\n    local parts = name:split(\"::\", {plain = true})\n    self._NAME = parts[#parts]\n    table.remove(parts)\n    if #parts > 0 then\n        self._NAMESPACE = table.concat(parts, \"::\")\n    end\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get the rule kind\n--\n-- current supported kind:\n--  - target: default, only for each target\n--  - project: global rule, for whole project\n--\nfunction _instance:kind()\n    return self:get(\"kind\") or \"target\"\nend\n\n-- get the given dependent rule\nfunction _instance:dep(name)\n    local deps = self:deps()\n    if deps then\n        return deps[name]\n    end\nend\n\n-- get rule deps\nfunction _instance:deps()\n    if self._DEPS == nil then\n        self:_build_deps()\n    end\n    return self._DEPS\nend\n\n-- get rule order deps\nfunction _instance:orderdeps()\n    if self._DEPS == nil then\n        self:_build_deps()\n    end\n    return self._ORDERDEPS\nend\n\n-- get xxx_script\nfunction _instance:script(name, generic)\n\n    -- get script\n    local script = self:get(name)\n    local result = select_script(script, {plat = config.get(\"plat\"), arch = config.get(\"arch\")}) or generic\n\n    -- imports some modules first\n    if result and result ~= generic then\n        local scope = getfenv(result)\n        if scope then\n            for _, modulename in ipairs(table.wrap(self:get(\"imports\"))) do\n                scope[sandbox_module.name(modulename)] = sandbox_module.import(modulename, {anonymous = true})\n            end\n        end\n    end\n    return result\nend\n\n-- the directories of rule\nfunction rule._directories()\n    return  {   path.join(global.directory(), \"rules\")\n            ,   path.join(os.programdir(), \"rules\")\n            }\nend\n\n-- the interpreter\nfunction rule._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if rule._INTERPRETER then\n        return rule._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(rule.apis())\n\n    -- set filter\n    interp:filter():register(\"rule\", function (variable)\n\n        -- check\n        assert(variable)\n\n        -- attempt to get it directly from the configure\n        local result = config.get(variable)\n        if not result or type(result) ~= \"string\" then\n\n            -- init maps\n            local maps =\n            {\n                host        = os.host()\n            ,   tmpdir      = function () return os.tmpdir() end\n            ,   curdir      = function () return os.curdir() end\n            ,   scriptdir   = function () return sandbox_os.scriptdir() end\n            ,   globaldir   = global.directory()\n            ,   configdir   = config.directory()\n            ,   projectdir  = os.projectdir()\n            ,   programdir  = os.programdir()\n            }\n\n            -- map it\n            result = maps[variable]\n            if type(result) == \"function\" then\n                result = result()\n            end\n        end\n\n        -- ok?\n        return result\n    end)\n\n    -- save interpreter\n    rule._INTERPRETER = interp\n    return interp\nend\n\n-- get project\nfunction rule._project()\n    return rule._PROJECT\nend\n\n-- load rule\nfunction rule._load(filepath)\n\n    -- get interpreter\n    local interp = rule._interpreter()\n    assert(interp)\n\n    -- load script\n    local ok, errors = interp:load(filepath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load rules\n    local results, errors = interp:make(\"rule\", true, true)\n    if not results then\n        return nil, errors\n    end\n    return results\nend\n\n-- get rule apis\nfunction rule.apis()\n\n    return\n    {\n        values =\n        {\n            -- rule.set_xxx\n            \"rule.set_extensions\"\n        ,   \"rule.set_sourcekinds\"\n        ,   \"rule.set_kind\"\n            -- rule.add_xxx\n        ,   \"rule.add_deps\"\n        ,   \"rule.add_imports\"\n        }\n    ,   groups =\n        {\n            -- rule.add_xxx\n           \"rule.add_orders\"\n        }\n    ,   script =\n        {\n            -- rule.on_xxx\n            \"rule.on_run\"\n        ,   \"rule.on_test\"\n        ,   \"rule.on_load\"\n        ,   \"rule.on_config\"\n        ,   \"rule.on_prepare\"\n        ,   \"rule.on_prepare_file\"\n        ,   \"rule.on_prepare_files\"\n        ,   \"rule.on_link\"\n        ,   \"rule.on_build\"\n        ,   \"rule.on_build_file\"\n        ,   \"rule.on_build_files\"\n        ,   \"rule.on_clean\"\n        ,   \"rule.on_package\"\n        ,   \"rule.on_install\"\n        ,   \"rule.on_uninstall\"\n        ,   \"rule.on_preparecmd\"\n        ,   \"rule.on_preparecmd_file\"\n        ,   \"rule.on_preparecmd_files\"\n        ,   \"rule.on_linkcmd\"\n        ,   \"rule.on_buildcmd\"\n        ,   \"rule.on_buildcmd_file\"\n        ,   \"rule.on_buildcmd_files\"\n        ,   \"rule.on_installcmd\"\n        ,   \"rule.on_uninstallcmd\"\n            -- rule.before_xxx\n        ,   \"rule.before_run\"\n        ,   \"rule.before_test\"\n        ,   \"rule.before_load\"\n        ,   \"rule.before_config\"\n        ,   \"rule.before_prepare\"\n        ,   \"rule.before_prepare_file\"\n        ,   \"rule.before_prepare_files\"\n        ,   \"rule.before_link\"\n        ,   \"rule.before_build\"\n        ,   \"rule.before_build_file\"\n        ,   \"rule.before_build_files\"\n        ,   \"rule.before_clean\"\n        ,   \"rule.before_package\"\n        ,   \"rule.before_install\"\n        ,   \"rule.before_uninstall\"\n        ,   \"rule.before_preparecmd\"\n        ,   \"rule.before_preparecmd_file\"\n        ,   \"rule.before_preparecmd_files\"\n        ,   \"rule.before_linkcmd\"\n        ,   \"rule.before_buildcmd\"\n        ,   \"rule.before_buildcmd_file\"\n        ,   \"rule.before_buildcmd_files\"\n        ,   \"rule.before_installcmd\"\n        ,   \"rule.before_uninstallcmd\"\n            -- rule.after_xxx\n        ,   \"rule.after_run\"\n        ,   \"rule.after_test\"\n        ,   \"rule.after_load\"\n        ,   \"rule.after_config\"\n        ,   \"rule.after_prepare\"\n        ,   \"rule.after_prepare_file\"\n        ,   \"rule.after_prepare_files\"\n        ,   \"rule.after_link\"\n        ,   \"rule.after_build\"\n        ,   \"rule.after_build_file\"\n        ,   \"rule.after_build_files\"\n        ,   \"rule.after_clean\"\n        ,   \"rule.after_package\"\n        ,   \"rule.after_install\"\n        ,   \"rule.after_uninstall\"\n        ,   \"rule.after_preparecmd\"\n        ,   \"rule.after_preparecmd_file\"\n        ,   \"rule.after_preparecmd_files\"\n        ,   \"rule.after_linkcmd\"\n        ,   \"rule.after_buildcmd\"\n        ,   \"rule.after_buildcmd_file\"\n        ,   \"rule.after_buildcmd_files\"\n        ,   \"rule.after_installcmd\"\n        ,   \"rule.after_uninstallcmd\"\n        }\n    }\nend\n\n-- new a rule instance\nfunction rule.new(name, info, opt)\n    opt = opt or {}\n    local instance = table.inherit(_instance)\n    if name then\n        instance:name_set(name)\n    end\n    instance._INFO = info\n    instance._PACKAGE = opt.package\n    if opt.package then\n        -- replace deps in package, @bar -> @zlib/bar\n        -- @see https://github.com/xmake-io/xmake/issues/2374\n        --\n        -- packages/z/zlib/rules/foo.lua\n        -- @code\n        -- rule(\"foo\")\n        --     add_deps(\"@bar\")\n        -- @endcode\n        --\n        -- package/z/zlib/rules/foo.lua\n        -- @code\n        -- rule(\"bar\")\n        --     ...\n        -- @endcode\n        --\n        local deps = {}\n        for _, depname in ipairs(table.wrap(instance:get(\"deps\"))) do\n            -- @xxx -> @package/xxx\n            if depname:startswith(\"@\") and not depname:find(\"/\", 1, true) then\n                depname = \"@\" .. opt.package:name() .. \"/\" .. depname:sub(2)\n            end\n            table.insert(deps, depname)\n        end\n        deps = table.unwrap(deps)\n        if deps and #deps > 0 then\n            instance:set(\"deps\", deps)\n        end\n        for depname, extraconf in pairs(table.wrap(instance:extraconf(\"deps\"))) do\n            if depname:startswith(\"@\") and not depname:find(\"/\", 1, true) then\n                depname = \"@\" .. opt.package:name() .. \"/\" .. depname:sub(2)\n                instance:extraconf_set(\"deps\", depname, extraconf)\n            end\n        end\n    end\n    return instance\nend\n\n-- get the given global rule\nfunction rule.rule(name)\n    return rule.rules()[name]\nend\n\n-- get global rules\nfunction rule.rules()\n    local rules = rule._RULES\n    if rules == nil then\n        local ruleinfos = {}\n        local dirs = rule._directories()\n        for _, dir in ipairs(dirs) do\n            local files = os.files(path.join(dir, \"**/xmake.lua\"))\n            if files then\n                for _, filepath in ipairs(files) do\n                    local results, errors = rule._load(filepath)\n                    if results then\n                        table.join2(ruleinfos, results)\n                    else\n                        os.raise(errors)\n                    end\n                end\n            end\n        end\n\n        -- make rule instances\n        rules = {}\n        for rulename, ruleinfo in pairs(ruleinfos) do\n            local instance = rule.new(rulename, ruleinfo)\n            rules[rulename] = instance\n        end\n        rule._RULES = rules\n    end\n    return rules\nend\n\n-- return module\nreturn rule\n"
  },
  {
    "path": "xmake/core/project/target.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target.lua\n--\n\n-- define module\nlocal target    = target or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal bit             = require(\"base/bit\")\nlocal os              = require(\"base/os\")\nlocal path            = require(\"base/path\")\nlocal hash            = require(\"base/hash\")\nlocal utils           = require(\"base/utils\")\nlocal table           = require(\"base/table\")\nlocal baseoption      = require(\"base/option\")\nlocal hashset         = require(\"base/hashset\")\nlocal deprecated      = require(\"base/deprecated\")\nlocal select_script   = require(\"base/private/select_script\")\nlocal match_copyfiles = require(\"base/private/match_copyfiles\")\nlocal instance_deps   = require(\"base/private/instance_deps\")\nlocal is_cross        = require(\"base/private/is_cross\")\nlocal memcache        = require(\"cache/memcache\")\nlocal rule            = require(\"project/rule\")\nlocal option          = require(\"project/option\")\nlocal config          = require(\"project/config\")\nlocal policy          = require(\"project/policy\")\nlocal project_package = require(\"project/package\")\nlocal tool            = require(\"tool/tool\")\nlocal linker          = require(\"tool/linker\")\nlocal compiler        = require(\"tool/compiler\")\nlocal toolchain       = require(\"tool/toolchain\")\nlocal platform        = require(\"platform/platform\")\nlocal environment     = require(\"platform/environment\")\nlocal language        = require(\"language/language\")\nlocal sandbox         = require(\"sandbox/sandbox\")\nlocal sandbox_module  = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- new a target instance\nfunction _instance.new(name, info)\n    local instance     = table.inherit(_instance)\n    instance._INFO     = info\n    instance._CACHEID  = 1\n    if name then\n        instance:name_set(name)\n    end\n    return instance\nend\n\n-- get memcache\nfunction _instance:memcache()\n    local cache = self._MEMCACHE\n    if not cache then\n        cache = memcache.cache(\"core.project.target.\" .. tostring(self))\n        self._MEMCACHE = cache\n    end\n    return cache\nend\n\n-- load rule, move cache to target\nfunction _instance:_load_rule(ruleinst, suffix)\n\n    -- init cache\n    local key = ruleinst:fullname() .. (suffix and (\"_\" .. suffix) or \"\")\n    local cache = self._RULES_LOADED or {}\n\n    -- do load\n    if cache[key] == nil then\n        local on_load = ruleinst:script(\"load\" .. (suffix and (\"_\" .. suffix) or \"\"))\n        if on_load then\n            local ok, errors = sandbox.load(on_load, self)\n            cache[key] = {ok, errors}\n        else\n            cache[key] = {true}\n        end\n\n        -- before_load has been deprecated\n        if on_load and suffix == \"before\" then\n            deprecated.add(ruleinst:fullname() .. \".on_load\", ruleinst:fullname() .. \".before_load\")\n        end\n    end\n\n    -- save cache\n    self._RULES_LOADED = cache\n\n    -- return results\n    local results = cache[key]\n    if results then\n        return results[1], results[2]\n    end\nend\n\n-- load rules\nfunction _instance:_load_rules(suffix)\n    for _, r in ipairs(self:orderules()) do\n        local ok, errors = self:_load_rule(r, suffix)\n        if not ok then\n            return false, errors\n        end\n    end\n    return true\nend\n\n-- do load target and rules\nfunction _instance:_load()\n\n    -- do load with target rules\n    local ok, errors = self:_load_rules()\n    if not ok then\n        return false, errors\n    end\n\n    -- do load for target\n    local on_load = self:script(\"load\")\n    if on_load then\n        ok, errors = sandbox.load(on_load, self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- mark as loaded\n    self._LOADED = true\n    return true\nend\n\n-- do before_load for rules\n-- @note it's deprecated, please use on_load instead of before_load\nfunction _instance:_load_before()\n    local ok, errors = self:_load_rules(\"before\")\n    if not ok then\n        return false, errors\n    end\n    return true\nend\n\n-- do after_load target and rules\nfunction _instance:_load_after()\n\n    -- enter the environments of the target packages\n    local oldenvs = os.addenvs(self:pkgenvs())\n\n    -- do load for target\n    local after_load = self:script(\"load_after\")\n    if after_load then\n        local ok, errors = sandbox.load(after_load, self)\n        if not ok then\n            return false, errors\n        end\n    end\n\n    -- do after_load with target rules\n    local ok, errors = self:_load_rules(\"after\")\n    if not ok then\n        return false, errors\n    end\n\n    -- leave the environments of the target packages\n    os.setenvs(oldenvs)\n    self._LOADED_AFTER = true\n    return true\nend\n\n-- get the visibility, private: 1, interface: 2, public: 3 = 1 | 2\nfunction _instance:_visibility(opt)\n    local visibility = 1\n    if opt then\n        if opt.interface then\n            visibility = 2\n        elseif opt.public then\n            visibility = 3\n        end\n    end\n    return visibility\nend\n\n-- update file rules\n--\n-- if we add files in on_load() dynamically, we need to update file rules,\n-- otherwise it will cause: unknown source file: ...\n--\nfunction _instance:_update_filerules()\n    local rulenames = {}\n    local extensions = {}\n    for _, sourcefile in ipairs(table.wrap(self:get(\"files\"))) do\n        local extension = path.extension((sourcefile:gsub(\"|.*$\", \"\")))\n        if not extensions[extension] then\n            local sourcekind = self:extraconf(\"files\", sourcefile, \"sourcekind\")\n            local lang = sourcekind and language.load_sk(sourcekind) or language.load_ex(extension)\n            if lang and lang:rules() then\n                table.join2(rulenames, lang:rules())\n            end\n            extensions[extension] = true\n        end\n    end\n    rulenames = table.unique(rulenames)\n    for _, rulename in ipairs(rulenames) do\n        local r = target._project() and target._project().rule(rulename, {namespace = self:namespace()}) or rule.rule(rulename)\n        if r then\n            -- only add target rules\n            if r:kind() == \"target\" then\n                if not self:rule(rulename) then\n                    self:rule_add(r)\n                    for _, deprule in ipairs(r:orderdeps()) do\n                        if not self:rule(deprule:name()) then\n                            self:rule_add(deprule)\n                        end\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- invalidate the previous cache\nfunction _instance:_invalidate(name)\n    self._CACHEID = self._CACHEID + 1\n    self._POLICIES = nil\n    self:memcache():clear()\n    -- we need to flush the source files cache if target/files are modified, e.g. `target:add(\"files\", \"xxx.c\")`\n    if name == \"files\" then\n        self._SOURCEFILES = nil\n        self._OBJECTFILES = nil\n        self._SOURCEBATCHES = nil\n        self:_update_filerules()\n    elseif name == \"deps\" then\n        self._DEPS = nil\n        self._ORDERDEPS = nil\n        self._INHERITDEPS = nil\n    end\n    if self._FILESCONFIG then\n        self._FILESCONFIG[name] = nil\n    end\nend\n\n-- build deps\nfunction _instance:_build_deps()\n    if target._project() then\n        local instances   = target._project().targets()\n        self._DEPS        = self._DEPS or {}\n        self._ORDERDEPS   = self._ORDERDEPS or {}\n        self._INHERITDEPS = self._INHERITDEPS or {}\n        instance_deps.load_deps(self, instances, self._DEPS, self._ORDERDEPS, {self:fullname()})\n        -- @see https://github.com/xmake-io/xmake/issues/4689\n        instance_deps.load_deps(self, instances, {}, self._INHERITDEPS, {self:fullname()}, function (t, dep)\n            local depinherit = t:extraconf(\"deps\", dep:name(), \"inherit\")\n            if depinherit == nil then\n                depinherit = t:extraconf(\"deps\", dep:fullname(), \"inherit\")\n            end\n            return depinherit == nil or depinherit\n        end)\n    end\nend\n\n-- is loaded?\nfunction _instance:_is_loaded()\n    return self._LOADED\nend\n\n-- get values from target deps with {interface|public = ...}\nfunction _instance:_get_from_deps(name, result_values, result_sources, opt)\n    local orderdeps = self:orderdeps({inherit = true})\n    local total = #orderdeps\n    for idx, _ in ipairs(orderdeps) do\n        local dep = orderdeps[total + 1 - idx]\n        -- We can inherit some configuration from dependencies.\n        -- e.g. disable to inherit links, add_deps(\"foo\", {links = false})\n        -- @see https://github.com/xmake-io/xmake/issues/6925\n        local inherit = self:extraconf(\"deps\", dep:name(), name)\n        if inherit ~= false then\n            local values = dep:get(name, opt)\n            if values ~= nil then\n                table.insert(result_values, values)\n                table.insert(result_sources, \"dep::\" .. dep:name())\n            end\n            local dep_values = {}\n            local dep_sources = {}\n            dep:_get_from_options(name, dep_values, dep_sources, opt)\n            dep:_get_from_packages(name, dep_values, dep_sources, opt)\n            for idx, values in ipairs(dep_values) do\n                local dep_source = dep_sources[idx]\n                table.insert(result_values, values)\n                table.insert(result_sources, \"dep::\" .. dep:name() .. \"/\" .. dep_source)\n            end\n        end\n    end\nend\n\n-- get values from target options with {interface|public = ...}\nfunction _instance:_get_from_options(name, result_values, result_sources, opt)\n    for _, opt_ in ipairs(self:orderopts(opt)) do\n        local values = opt_:get(name)\n        if values ~= nil then\n            table.insert(result_values, values)\n            table.insert(result_sources, \"option::\" .. opt_:name())\n        end\n    end\nend\n\n-- get values from target packages with {interface|public = ...}\nfunction _instance:_get_from_packages(name, result_values, result_sources, opt)\n    local function _filter_libfiles(libfiles)\n        local result = {}\n        for _, libfile in ipairs(table.wrap(libfiles)) do\n            if not libfile:endswith(\".dll\") then\n                table.insert(result, libfile)\n            end\n        end\n        return table.unwrap(result)\n    end\n    for _, pkg in ipairs(self:orderpkgs(opt)) do\n        local configinfo = self:pkgconfig(pkg:name())\n        -- get values from package components\n        -- e.g. `add_packages(\"sfml\", {components = {\"graphics\", \"window\"}})`\n        local selected_components = configinfo and configinfo.components or pkg:components_default()\n        if selected_components and pkg:components() then\n            local components_enabled = hashset.new()\n            for _, comp in ipairs(table.wrap(selected_components)) do\n                components_enabled:insert(comp)\n                for _, dep in ipairs(table.wrap(pkg:component_orderdeps(comp))) do\n                    components_enabled:insert(dep)\n                end\n            end\n            components_enabled:insert(\"__base\")\n            -- if we can't find the values from the component, we need to fall back to __base to find them.\n            -- it contains some common values of all components\n            local values = {}\n            local components = table.wrap(pkg:components())\n            for _, component_name in ipairs(table.join(pkg:components_orderlist(), \"__base\")) do\n                if components_enabled:has(component_name) then\n                    local info = components[component_name]\n                    if info then\n                        local compvalues = info[name]\n                        -- use full link path instead of links\n                        -- @see https://github.com/xmake-io/xmake/issues/5066\n                        if configinfo and configinfo.linkpath then\n                            local libfiles = info.libfiles\n                            if name == \"links\" then\n                                if libfiles then\n                                    compvalues = _filter_libfiles(libfiles)\n                                end\n                            elseif name == \"linkdirs\" then\n                                if libfiles then\n                                    compvalues = nil\n                                end\n                            end\n                        end\n                        table.join2(values, compvalues)\n                    else\n                        local components_str = table.concat(table.wrap(configinfo.components), \", \")\n                        utils.warning(\"unknown component(%s) in add_packages(%s, {components = {%s}})\", component_name, pkg:name(), components_str)\n                    end\n                end\n            end\n            if #values > 0 then\n                table.insert(result_values, values)\n                table.insert(result_sources, \"package::\" .. pkg:name())\n            end\n        -- get values instead of the builtin configs if exists extra package config\n        -- e.g. `add_packages(\"xxx\", {links = \"xxx\"})`\n        elseif configinfo and configinfo[name] then\n             local values = configinfo[name]\n             if values ~= nil then\n                table.insert(result_values, values)\n                table.insert(result_sources, \"package::\" .. pkg:name())\n            end\n        else\n            -- get values from the builtin package configs\n            local values = pkg:get(name)\n            -- use full link path instead of links\n            -- @see https://github.com/xmake-io/xmake/issues/5066\n            if configinfo and configinfo.linkpath then\n                local libfiles = pkg:libraryfiles()\n                if name == \"links\" then\n                    if libfiles then\n                        values = _filter_libfiles(libfiles)\n                    end\n                elseif name == \"linkdirs\" then\n                    if libfiles then\n                        values = nil\n                    end\n                end\n            end\n            if values ~= nil then\n                table.insert(result_values, values)\n                table.insert(result_sources, \"package::\" .. pkg:name())\n            end\n        end\n    end\nend\n\n-- get values from the given source\nfunction _instance:_get_from_source(name, source, result_values, result_sources, opt)\n    if source == \"self\" then\n        local values = self:get(name, opt)\n        if values ~= nil then\n            table.insert(result_values, values)\n            table.insert(result_sources, \"self\")\n        end\n    elseif source:startswith(\"dep::\") then\n        local depname = source:split(\"::\", {plain = true, limit = 2})[2]\n        if depname == \"*\" then\n            self:_get_from_deps(name, result_values, result_sources, opt)\n        else\n            local depsource\n            local splitinfo = depname:split(\"/\", {plain = true})\n            if #splitinfo == 2 then\n                depname = splitinfo[1]\n                depsource = splitinfo[2]\n            end\n            local dep = self:dep(depname)\n            if dep then\n                -- e.g.\n                -- dep::foo/option::bar\n                -- dep::foo/package::bar\n                if depsource then\n                    local dep_values = {}\n                    local dep_sources = {}\n                    dep:_get_from_source(name, depsource, dep_values, dep_sources, opt)\n                    for idx, values in ipairs(dep_values) do\n                        local dep_source = dep_sources[idx]\n                        table.insert(result_values, values)\n                        table.insert(result_sources, \"dep::\" .. depname .. \"/\" .. dep_source)\n                    end\n                else\n                    -- dep::foo\n                    local values = dep:get(name, opt)\n                    if values ~= nil then\n                        table.insert(result_values, values)\n                        table.insert(result_sources, source)\n                    end\n                end\n            end\n        end\n    elseif source:startswith(\"option::\") then\n        local optname = source:split(\"::\", {plain = true, limit = 2})[2]\n        if optname == \"*\" then\n            self:_get_from_options(name, result_values, result_sources, opt)\n        else\n            local opt_ = self:opt(optname, opt)\n            if opt_ then\n                local values = opt_:get(name)\n                if values ~= nil then\n                    table.insert(result_values, values)\n                    table.insert(result_sources, source)\n                end\n            end\n        end\n    elseif source:startswith(\"package::\") then\n        local pkgname = source:split(\"::\", {plain = true, limit = 2})[2]\n        if pkgname == \"*\" then\n            self:_get_from_packages(name, result_values, result_sources, opt)\n        else\n            local pkg = self:pkg(pkgname, opt)\n            if pkg then\n                local values = pkg:get(name)\n                if values ~= nil then\n                    table.insert(result_values, values)\n                    table.insert(result_sources, source)\n                end\n            end\n        end\n    elseif source == \"*\" then\n        self:_get_from_source(name, \"self\", result_values, result_sources, opt)\n        self:_get_from_source(name, \"option::*\", result_values, result_sources, opt)\n        self:_get_from_source(name, \"package::*\", result_values, result_sources, opt)\n        self:_get_from_source(name, \"dep::*\", result_values, result_sources, {interface = true})\n    else\n        os.raise(\"target:get_from(): unknown source %s\", source)\n    end\nend\n\n-- get the checked target, it's only for target:check_xxx api.\n--\n-- we should not inherit links from deps/packages when checking snippets in on_config,\n-- because the target deps has been not built.\n--\n-- @see https://github.com/xmake-io/xmake/issues/4491\n--\nfunction _instance:_checked_target()\n    local checked_target = self._CHECKED_TARGET\n    if checked_target == nil then\n        checked_target = self:clone()\n        -- we need update target:cachekey(), because target flags may be cached in builder\n        checked_target:_invalidate()\n        checked_target.get_from = function (target, name, sources, opt)\n            if (name == \"links\" or name == \"linkdirs\") and sources == \"*\" then\n                sources = \"self\"\n            end\n            return _instance.get_from(target, name, sources, opt)\n        end\n        self._CHECKED_TARGET = checked_target\n    end\n    return checked_target\nend\n\n-- get format\nfunction _instance:_format(kind)\n    local formats = self._FORMATS\n    if not formats then\n        for _, toolchain_inst in ipairs(self:toolchains()) do\n            formats = toolchain_inst:formats()\n            if formats then\n                break\n            end\n        end\n        self._FORMATS = formats\n    end\n    if formats then\n        return formats[kind or self:kind()]\n    end\nend\n\n-- clone target, @note we can just call it in after_load()\nfunction _instance:clone()\n    if not self:_is_loaded() then\n        os.raise(\"please call target:clone() in after_load().\", self:fullname())\n    end\n    local instance = target.new(self:fullname(), self._INFO:clone())\n    if self._DEPS then\n        instance._DEPS = table.clone(self._DEPS)\n    end\n    if self._ORDERDEPS then\n        instance._ORDERDEPS = table.clone(self._ORDERDEPS)\n    end\n    if self._INHERITDEPS then\n        instance._INHERITDEPS = table.clone(self._INHERITDEPS)\n    end\n    if self._RULES then\n        instance._RULES = table.clone(self._RULES)\n    end\n    if self._ORDERULES then\n        instance._ORDERULES = table.clone(self._ORDERULES)\n    end\n    if self._DATA then\n        instance._DATA = table.clone(self._DATA)\n    end\n    if self._SOURCEFILES then\n        instance._SOURCEFILES = table.clone(self._SOURCEFILES)\n    end\n    if self._OBJECTFILES then\n        instance._OBJECTFILES = table.clone(self._OBJECTFILES)\n    end\n    if self._SOURCEBATCHES then\n        instance._SOURCEBATCHES = table.clone(self._SOURCEBATCHES, 3)\n    end\n    instance._LOADED = self._LOADED\n    instance._LOADED_AFTER = true\n    return instance\nend\n\n-- get the target info\n--\n-- e.g.\n--\n-- default: get private\n--  - target:get(\"cflags\")\n--  - target:get(\"cflags\", {private = true})\n--\n-- get private and interface\n--  - target:get(\"cflags\", {public = true})\n--\n-- get interface\n--  - target:get(\"cflags\", {interface = true})\n--\n-- get raw reference of values\n--  - target:get(\"cflags\", {rawref = true})\n--\nfunction _instance:get(name, opt)\n\n    -- get values\n    local values = self._INFO:get(name)\n\n    -- get thr required visibility\n    local vs_private   = 1\n    local vs_interface = 2\n    local vs_public    = 3 -- all\n    local vs_required  = self:_visibility(opt)\n\n    -- get all values? (private and interface)\n    if vs_required == vs_public or (opt and opt.rawref) then\n        return values\n    end\n\n    -- get the extra configuration\n    local extraconf = self:extraconf(name)\n    if extraconf then\n        -- filter values for public, private or interface if be not dictionary\n        if not table.is_dictionary(values) then\n            local results = {}\n            for _, value in ipairs(table.wrap(values)) do\n                -- we always call self:extraconf() to handle group value\n                local extra = self:extraconf(name, value)\n                local vs_conf = self:_visibility(extra)\n                if bit.band(vs_required, vs_conf) ~= 0 then\n                    table.insert(results, value)\n                end\n            end\n            if #results > 0 then\n                return table.unwrap(results)\n            end\n        else\n            return values\n        end\n    else\n        -- only get the private values\n        if bit.band(vs_required, vs_private) ~= 0 then\n            return values\n        end\n    end\nend\n\n-- deprecated: get values from target dependencies\nfunction _instance:get_from_deps(name, opt)\n    deprecated.add(\"target:get_from(%s, \\\"dep:*\\\")\", \"target:get_from_deps(%s)\", name)\n    local result = {}\n    local values = self:get_from(name, \"dep::*\", opt)\n    if values then\n        for _, v in ipairs(values) do\n            table.join2(result, v)\n        end\n    end\n    return result\nend\n\n-- deprecated: get values from target options with {interface|public = ...}\nfunction _instance:get_from_opts(name, opt)\n    deprecated.add(\"target:get_from(%s, \\\"option::*\\\")\", \"target:get_from_opts(%s)\", name)\n    local result = {}\n    local values = self:get_from(name, \"option::*\", opt)\n    if values then\n        for _, v in ipairs(values) do\n            table.join2(result, v)\n        end\n    end\n    return result\nend\n\n-- deprecated: get values from target packages with {interface|public = ...}\nfunction _instance:get_from_pkgs(name, opt)\n    deprecated.add(\"target:get_from(%s, \\\"package::*\\\")\", \"target:get_from_pkgs(%s)\", name)\n    local result = {}\n    local values = self:get_from(name, \"package::*\", opt)\n    if values then\n        for _, v in ipairs(values) do\n            table.join2(result, v)\n        end\n    end\n    return result\nend\n\n-- get values from the given sources\n--\n-- e.g.\n--\n-- only from the current target:\n--      target:get_from(\"links\")\n--      target:get_from(\"links\", \"self\")\n--\n-- from the given dep:\n--      target:get_from(\"links\", \"dep::foo\")\n--      target:get_from(\"links\", \"dep::foo\", {interface = true})\n--      target:get_from(\"links\", \"dep::*\")\n--\n-- from the given option:\n--      target:get_from(\"links\", \"option::foo\")\n--      target:get_from(\"links\", \"option::*\")\n--\n-- from the given package:\n--      target:get_from(\"links\", \"package::foo\")\n--      target:get_from(\"links\", \"package::*\")\n--\n-- from the given dep/option, dep/package\n--      target:get_from(\"links\", \"dep::foo/option::bar\")\n--      target:get_from(\"links\", \"dep::foo/option::*\")\n--      target:get_from(\"links\", \"dep::foo/package::bar\")\n--      target:get_from(\"links\", \"dep::foo/package::*\")\n--\n-- from the multiple sources:\n--      target:get_from(\"links\", {\"self\", \"option::foo\", \"dep::bar\", \"package::zoo\"})\n--      target:get_from(\"links\", {\"self\", \"option::*\", \"dep::*\", \"package::*\"})\n--\n-- from all:\n--      target:get_from(\"links\", \"*\")\n--\n-- return:\n--      local values, sources = target:get_from(\"links\", \"*\")\n--      for idx, value in ipairs(values) do\n--          local source = sources[idx]\n--      end\n--\nfunction _instance:get_from(name, sources, opt)\n    local result_values = {}\n    local result_sources = {}\n    sources = sources or \"self\"\n    for _, source in ipairs(table.wrap(sources)) do\n        self:_get_from_source(name, source, result_values, result_sources, opt)\n    end\n    if #result_values > 0 then\n        return result_values, result_sources\n    end\nend\n\n-- set the value to the target info\nfunction _instance:set(name, ...)\n    self._INFO:apival_set(name, ...)\n    self:_invalidate(name)\nend\n\n-- add the value to the target info\nfunction _instance:add(name, ...)\n    self._INFO:apival_add(name, ...)\n    self:_invalidate(name)\nend\n\n-- remove the value to the target info (deprecated)\nfunction _instance:del(name, ...)\n    self._INFO:apival_del(name, ...)\n    self:_invalidate(name)\nend\n\n-- remove the value to the target info\nfunction _instance:remove(name, ...)\n    self._INFO:apival_remove(name, ...)\n    self:_invalidate(name)\nend\n\n-- get the extra configuration\nfunction _instance:extraconf(name, item, key)\n    return self._INFO:extraconf(name, item, key)\nend\n\n-- set the extra configuration\nfunction _instance:extraconf_set(name, item, key, value)\n    self._INFO:extraconf_set(name, item, key, value)\nend\n\n-- get the extra configuration from the given source\n--\n-- e.g.\n--\n-- only from the current target:\n--      target:extraconf_from(\"links\")\n--      target:extraconf_from(\"links\", \"self\")\n--\n-- from the given dep:\n--      target:extraconf_from(\"links\", \"dep::foo\")\n--\n-- from the given option:\n--      target:extraconf_from(\"links\", \"option::foo\")\n--\n-- from the given package:\n--      target:extraconf_from(\"links\", \"package::foo\")\n--\n-- from the given dep/option, dep/package\n--      target:extraconf_from(\"links\", \"dep::foo/option::bar\")\n--      target:extraconf_from(\"links\", \"dep::foo/package::bar\")\n--\nfunction _instance:extraconf_from(name, source)\n    if name:find(\"::\") then\n        local tmp = name\n        name = source\n        source = tmp\n        utils.warning(\"please use target:extraconf_from(%s, %s) intead of target:extraconf_from(%s, %s)\", name, source, source, name)\n    end\n    source = source or \"self\"\n    if source == \"self\" then\n        return self:extraconf(name)\n    elseif source:startswith(\"dep::\") then\n        local depname = source:split(\"::\", {plain = true, limit = 2})[2]\n        local depsource\n        local splitinfo = depname:split(\"/\", {plain = true})\n        if #splitinfo == 2 then\n            depname = splitinfo[1]\n            depsource = splitinfo[2]\n        end\n        local dep = self:dep(depname)\n        if dep then\n            -- e.g.\n            -- dep::foo/option::bar\n            -- dep::foo/package::bar\n            if depsource then\n                return dep:extraconf_from(name, dep_source)\n            else\n                -- dep::foo\n                return dep:extraconf(name)\n            end\n        end\n    elseif source:startswith(\"option::\") then\n        local optname = source:split(\"::\", {plain = true, limit = 2})[2]\n        local opt_ = self:opt(optname, opt)\n        if opt_ then\n            return opt_:extraconf(name)\n        end\n    elseif source:startswith(\"package::\") then\n        local pkgname = source:split(\"::\", {plain = true, limit = 2})[2]\n        local pkg = self:pkg(pkgname, opt)\n        if pkg then\n            return pkg:extraconf(name)\n        end\n    else\n        os.raise(\"target:extraconf_from(): unknown source %s\", source)\n    end\nend\n\n-- get configuration source information of the given api item\nfunction _instance:sourceinfo(name, item)\n    return self._INFO:sourceinfo(name, item)\nend\n\n-- get user private data\nfunction _instance:data(name)\n    return self._DATA and self._DATA[name]\nend\n\n-- set user private data\nfunction _instance:data_set(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = data\nend\n\n-- add user private data\nfunction _instance:data_add(name, data)\n    self._DATA = self._DATA or {}\n    self._DATA[name] = table.unwrap(table.join(self._DATA[name] or {}, data))\nend\n\n-- get values\nfunction _instance:values(name, sourcefile)\n\n    -- get values from the source file first\n    local values = {}\n    if sourcefile then\n        local fileconfig = self:fileconfig(sourcefile)\n        if fileconfig then\n            local filevalues = fileconfig.values\n            if filevalues then\n                -- we use '_' to simplify setting, for example:\n                --\n                -- add_files(\"xxx.mof\", {values = {wdk_mof_header = \"xxx.h\"}})\n                -- add_files(\"xxx.mof\", {values = {[\"wdk.mof.header\"] = \"xxx.h\"}})\n                --\n                table.join2(values, filevalues[name] or filevalues[name:gsub(\"%.\", \"_\")])\n            end\n        end\n    end\n\n    -- get values from target\n    table.join2(values, self:get(\"values.\" .. name))\n    if #values > 0 then\n        values = table.unwrap(values)\n    else\n        values = nil\n    end\n    return values\nend\n\n-- set values\nfunction _instance:values_set(name, ...)\n    self:set(\"values.\" .. name, ...)\nend\n\n-- add values\nfunction _instance:values_add(name, ...)\n    self:add(\"values.\" .. name, ...)\nend\n\n-- get the target info\nfunction _instance:info()\n    return self._INFO:info()\nend\n\n-- get the type: target\nfunction _instance:type()\n    return \"target\"\nend\n\n-- get the target name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- set the target name\nfunction _instance:name_set(name)\n    local parts = name:split(\"::\", {plain = true})\n    self._NAME = parts[#parts]\n    table.remove(parts)\n    if #parts > 0 then\n        self._NAMESPACE = table.concat(parts, \"::\")\n    end\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get the target kind\nfunction _instance:kind()\n    return self:get(\"kind\") or \"binary\"\nend\n\n-- get the target kind (deprecated)\nfunction _instance:targetkind()\n    return self:kind()\nend\n\n-- get the platform of this target\nfunction _instance:plat()\n    return self:get(\"plat\") or config.get(\"plat\") or os.host()\nend\n\n-- get the architecture of this target\nfunction _instance:arch()\n    return self:get(\"arch\") or config.get(\"arch\") or os.arch()\nend\n\n-- the current target is belong to the given platforms?\nfunction _instance:is_plat(...)\n    local plat = self:plat()\n    for _, v in ipairs(table.pack(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current target is belong to the given architectures?\nfunction _instance:is_arch(...)\n    local arch = self:arch()\n    for _, v in ipairs(table.pack(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- is 64bits architecture?\nfunction _instance:is_arch64()\n    return self:is_arch(\".+64.*\")\nend\n\n-- get the platform instance\nfunction _instance:platform()\n    local platform_inst = self._PLATFORM\n    if platform_inst == nil then\n        platform_inst, errors = platform.load(self:plat(), self:arch())\n        if not platform_inst then\n            os.raise(errors)\n        end\n        self._PLATFORM = platform_inst\n    end\n    return platform_inst\nend\n\n-- get the cache key\nfunction _instance:cachekey()\n    return string.format(\"%s_%d\", tostring(self), self._CACHEID)\nend\n\n-- get the target version\nfunction _instance:version()\n    local version = self:get(\"version\")\n    local version_build\n    if version then\n        version_build = self:extraconf(\"version\", version, \"build\")\n        if type(version_build) == \"string\" then\n            version_build = os.date(version_build, os.time())\n        end\n    end\n    return version, version_build\nend\n\n-- get the target soname\n-- @see https://github.com/tboox/tbox/issues/214\n--\n-- set_version(\"1.0.1\", {soname = \"1.0\"}) -> libfoo.so.1.0, libfoo.1.0.dylib\n-- set_version(\"1.0.1\", {soname = \"1\"}) -> libfoo.so.1, libfoo.1.dylib\n-- set_version(\"1.0.1\", {soname = true}) -> libfoo.so.1, libfoo.1.dylib\n-- set_version(\"1.0.1\", {soname = \"\"}) -> libfoo.so, libfoo.dylib\nfunction _instance:soname()\n    if not self:is_shared() then\n        return\n    end\n    if self:is_plat(\"windows\", \"mingw\", \"cygwin\", \"msys\") then\n        return\n    end\n    local version = self:get(\"version\")\n    local version_soname\n    if version then\n        version_soname = self:extraconf(\"version\", version, \"soname\")\n        if version_soname == true then\n            version_soname = version:split(\".\", {plain = true})[1]\n        end\n    end\n    if not version_soname then\n        return\n    end\n    local soname = self:filename()\n    if type(version_soname) == \"string\" and #version_soname > 0 then\n        local extension = path.extension(soname)\n        if extension == \".dylib\" then\n            soname = path.basename(soname) .. \".\" .. version_soname .. extension\n        else\n            soname = soname .. \".\" .. version_soname\n        end\n    end\n    return soname\nend\n\n-- get the target license\nfunction _instance:license()\n    return self:get(\"license\")\nend\n\n-- get the target policy\nfunction _instance:policy(name)\n    local policies = self._POLICIES\n    if not policies then\n        policies = self:get(\"policy\")\n        self._POLICIES = policies\n        if policies then\n            local defined_policies = policy.policies()\n            for name, _ in pairs(policies) do\n                if not defined_policies[name] then\n                    utils.warning(\"unknown policy(%s), please run `xmake l core.project.policy.policies` if you want to all policies\", name)\n                end\n            end\n        end\n    end\n    local value\n    if policies then\n        value = policies[name]\n    end\n    if value == nil and target._project() then\n        value = target._project().policy(name)\n    end\n    return policy.check(name, value)\nend\n\n-- get the base name of target file\nfunction _instance:basename()\n    local filename = self:get(\"filename\")\n    if filename then\n        return path.basename(filename)\n    end\n    return self:get(\"basename\") or self:name()\nend\n\n-- get the target compiler\nfunction _instance:compiler(sourcekind)\n    if not sourcekind then\n        os.raise(\"please pass sourcekind to the first argument of target:compiler(), e.g. cc, cxx, as\")\n    end\n    local compilerinst = self:memcache():get(\"compiler_\" .. sourcekind)\n    if not compilerinst then\n        local instance, errors = compiler.load(sourcekind, self)\n        if not instance then\n            os.raise(errors)\n        end\n        compilerinst = instance\n        self:memcache():set(\"compiler_\" .. sourcekind, compilerinst)\n    end\n    return compilerinst\nend\n\n-- get the target linker\nfunction _instance:linker()\n    local linkerinst = self:memcache():get(\"linker\")\n    if not linkerinst then\n        local instance, errors = linker.load(self:kind(), self:sourcekinds(), self)\n        if not instance then\n            os.raise(errors)\n        end\n        linkerinst = instance\n        self:memcache():set(\"linker\", linkerinst)\n    end\n    return linkerinst\nend\n\n-- make linking command for this target\nfunction _instance:linkcmd(objectfiles)\n    return self:linker():linkcmd(objectfiles or self:objectfiles(), self:targetfile(), {target = self})\nend\n\n-- make linking arguments for this target\nfunction _instance:linkargv(objectfiles)\n    return self:linker():linkargv(objectfiles or self:objectfiles(), self:targetfile(), {target = self})\nend\n\n-- make link flags for the given target\nfunction _instance:linkflags()\n    return self:linker():linkflags({target = self})\nend\n\n-- get the given dependent target\nfunction _instance:dep(name)\n    local deps = self:deps()\n    if deps then\n        local dep = deps[name]\n        if dep == nil then\n            local namespace = self:namespace()\n            if namespace then\n                dep = deps[namespace .. \"::\" .. name]\n            end\n        end\n        return dep\n    end\nend\n\n-- get target deps\nfunction _instance:deps()\n    if not self:_is_loaded() then\n        os.raise(\"please call target:deps() or target:dep() in after_load()!\")\n    end\n    if self._DEPS == nil then\n        self:_build_deps()\n    end\n    return self._DEPS\nend\n\n-- get target ordered deps\nfunction _instance:orderdeps(opt)\n    opt = opt or {}\n    if not self:_is_loaded() then\n        os.raise(\"please call target:orderdeps() in after_load()!\")\n    end\n    if self._DEPS == nil then\n        self:_build_deps()\n    end\n    return opt.inherit and self._INHERITDEPS or self._ORDERDEPS\nend\n\n-- get target rules\nfunction _instance:rules()\n    return self._RULES\nend\n\n-- get target ordered rules\nfunction _instance:orderules()\n    local rules = self._RULES\n    local orderules = self._ORDERULES\n    if orderules == nil and rules then\n        orderules = instance_deps.sort(rules)\n        self._ORDERULES = orderules\n    end\n    return orderules\nend\n\n-- get target rule from the given rule name\nfunction _instance:rule(name)\n    if self._RULES then\n        local r = self._RULES[name]\n        if r == nil and self:namespace() then\n            r = self._RULES[self:namespace() .. \"::\" .. name]\n        end\n        return r\n    end\nend\n\n-- add rule\n--\n-- @note If a rule has the same name as a built-in rule,\n-- it will be replaced in the target:rules() and target:orderules(), but will be not replaced globally in the project.rules()\nfunction _instance:rule_add(r)\n    self._RULES = self._RULES or {}\n    self._RULES[r:fullname()] = r\n    self._ORDERULES = nil\nend\n\n-- enable or disable rule\nfunction _instance:rule_enable(name, enabled)\n    local ruleinst = self:rule(name)\n    if ruleinst then\n        self:data_set(\"__rule_enabled.\" .. name, enabled)\n    else\n        utils.warning(\"target(%s): rule(%s) not found\", self:name(), name)\n    end\nend\n\n-- the given rule is enabled or disabled?\nfunction _instance:rule_is_enabled(name)\n    local enabled = self:data(\"__rule_enabled.\" .. name)\n    return enabled ~= false\nend\n\n-- is phony target?\nfunction _instance:is_phony()\n    local targetkind = self:kind()\n    return not targetkind or targetkind == \"phony\"\nend\n\n-- is binary target?\nfunction _instance:is_binary()\n    return self:kind() == \"binary\"\nend\n\n-- is shared library target?\nfunction _instance:is_shared()\n    return self:kind() == \"shared\"\nend\n\n-- is static library target?\nfunction _instance:is_static()\n    return self:kind() == \"static\"\nend\n\n-- is object files target?\nfunction _instance:is_object()\n    return self:kind() == \"object\"\nend\n\n-- is headeronly target?\nfunction _instance:is_headeronly()\n    return self:kind() == \"headeronly\"\nend\n\n-- is moduleonly target?\nfunction _instance:is_moduleonly()\n    return self:kind() == \"moduleonly\"\nend\n\n-- is library target?\nfunction _instance:is_library()\n    return self:is_static() or self:is_shared() or self:is_headeronly() or self:is_moduleonly()\nend\n\n-- is default target?\nfunction _instance:is_default()\n    local default = self:get(\"default\")\n    return default == nil or default == true\nend\n\n-- is enabled?\nfunction _instance:is_enabled()\n    return self:get(\"enabled\") ~= false\nend\n\n-- is rebuilt?\nfunction _instance:is_rebuilt()\n    return self:data(\"rebuilt\")\nend\n\n-- is cross-compilation?\nfunction _instance:is_cross()\n    return is_cross(self:plat(), self:arch())\nend\n\n-- get the enabled option\nfunction _instance:opt(name, opt)\n    return self:opts(opt)[name]\nend\n\n-- get the enabled options\nfunction _instance:opts(opt)\n    opt = opt or {}\n    local cachekey = \"opts\"\n    if opt.public then\n        cachekey = cachekey .. \"_public\"\n    elseif opt.interface then\n        cachekey = cachekey .. \"_interface\"\n    end\n    local opts = self:memcache():get(cachekey)\n    if not opts then\n        opts = {}\n        for _, opt_ in ipairs(self:orderopts(opt)) do\n            opts[opt_:name()] = opt_\n        end\n        self:memcache():set(cachekey, opts)\n    end\n    return opts\nend\n\n-- get the enabled ordered options with {public|interface = ...}\nfunction _instance:orderopts(opt)\n    opt = opt or {}\n    local cachekey = \"orderopts\"\n    if opt.public then\n        cachekey = cachekey .. \"_public\"\n    elseif opt.interface then\n        cachekey = cachekey .. \"_interface\"\n    end\n    local orderopts = self:memcache():get(cachekey)\n    if not orderopts then\n        orderopts = {}\n        for _, name in ipairs(table.wrap(self:get(\"options\", opt))) do\n            local opt_ = nil\n            local enabled = config.get(name)\n            if enabled == nil and self:namespace() then\n                enabled = config.get(self:namespace() .. \"::\" .. name)\n            end\n            if enabled then\n                opt_ = option.load(name, {namespace = self:namespace()})\n            end\n            if opt_ then\n                table.insert(orderopts, opt_)\n            end\n        end\n        self:memcache():set(cachekey, orderopts)\n    end\n    return orderopts\nend\n\n-- get the enabled package\nfunction _instance:pkg(name, opt)\n    return self:pkgs(opt)[name]\nend\n\n-- get the enabled packages\nfunction _instance:pkgs(opt)\n    opt = opt or {}\n    local cachekey = \"pkgs\"\n    if opt.public then\n        cachekey = cachekey .. \"_public\"\n    elseif opt.interface then\n        cachekey = cachekey .. \"_interface\"\n    end\n    local packages = self:memcache():get(cachekey)\n    if not packages then\n        packages = {}\n        for _, pkg in ipairs(self:orderpkgs(opt)) do\n            packages[pkg:name()] = pkg\n        end\n        self:memcache():set(cachekey, packages)\n    end\n    return packages\nend\n\n-- get the required packages with {interface|public = ..}\nfunction _instance:orderpkgs(opt)\n    opt = opt or {}\n    local cachekey = \"orderpkgs\"\n    if opt.public then\n        cachekey = cachekey .. \"_public\"\n    elseif opt.interface then\n        cachekey = cachekey .. \"_interface\"\n    end\n    local packages = self:memcache():get(cachekey)\n    if not packages then\n        packages = {}\n        local requires = target._project().required_packages()\n        if requires then\n            for _, packagename in ipairs(table.wrap(self:get(\"packages\", opt))) do\n                local pkg = requires[packagename]\n                -- attempt to get package with namespace\n                if pkg == nil and packagename:find(\"::\", 1, true) then\n                    local parts = packagename:split(\"::\", {plain = true})\n                    local namespace_pkg = requires[parts[#parts]]\n                    if namespace_pkg and namespace_pkg:namespace() then\n                        local fullname = namespace_pkg:fullname()\n                        if fullname:endswith(packagename) then\n                            pkg = namespace_pkg\n                        end\n                    end\n                end\n                if pkg and pkg:enabled() then\n                    table.insert(packages, pkg)\n                end\n            end\n        end\n        self:memcache():set(cachekey, packages)\n    end\n    return packages\nend\n\n-- get the environments of packages\nfunction _instance:pkgenvs()\n    local pkgenvs = self._PKGENVS\n    if pkgenvs == nil then\n        local pkgs = hashset.new()\n        for _, pkgname in ipairs(table.wrap(self:get(\"packages\"))) do\n            local pkg = self:pkg(pkgname)\n            if pkg then\n                pkgs:insert(pkg)\n            end\n        end\n        -- we can also get package envs from deps (public package)\n        -- @see https://github.com/xmake-io/xmake/issues/2729\n        for _, dep in ipairs(self:orderdeps()) do\n            for _, pkgname in ipairs(table.wrap(dep:get(\"packages\", {interface = true}))) do\n                local pkg = dep:pkg(pkgname)\n                if pkg then\n                    pkgs:insert(pkg)\n                end\n            end\n        end\n        for _, pkg in pkgs:orderkeys() do\n            local envs = pkg:envs()\n            if envs then\n                for name, values in table.orderpairs(envs) do\n                    if type(values) == \"table\" then\n                        values = path.joinenv(values)\n                    end\n                    pkgenvs = pkgenvs or {}\n                    if pkgenvs[name] then\n                        pkgenvs[name] = pkgenvs[name] .. path.envsep() .. values\n                    else\n                        pkgenvs[name] = values\n                    end\n                end\n            end\n        end\n        self._PKGENVS = pkgenvs or false\n    end\n    return pkgenvs or nil\nend\n\n-- get the config info of the given package\nfunction _instance:pkgconfig(pkgname)\n    local extra_packages = self:extraconf(\"packages\")\n    if extra_packages then\n        return extra_packages[pkgname]\n    end\nend\n\n-- get the object files directory\nfunction _instance:objectdir(opt)\n\n    -- the object directory\n    local objectdir = self:get(\"objectdir\")\n    if not objectdir then\n        objectdir = path.join(config.builddir(), \".objs\")\n    end\n    local namespace = self:namespace()\n    if namespace then\n        objectdir = path.join(objectdir, (namespace:replace(\"::\", path.sep())), self:name())\n    else\n        objectdir = path.join(objectdir, self:name())\n    end\n\n    -- get root directory of target\n    local intermediate_directory = self:policy(\"build.intermediate_directory\")\n    if (opt and opt.root) or intermediate_directory == false then\n        return objectdir\n    end\n\n    -- generate intermediate directory\n    local plat = self:plat()\n    if plat then\n        objectdir = path.join(objectdir, plat)\n    end\n    local arch = self:arch()\n    if arch then\n        objectdir = path.join(objectdir, arch)\n    end\n    local mode = config.mode()\n    if mode then\n        objectdir = path.join(objectdir, mode)\n    end\n    return objectdir\nend\n\n-- get the dependent files directory\nfunction _instance:dependir(opt)\n\n    -- init the dependent directory\n    local dependir = self:get(\"dependir\")\n    if not dependir then\n        dependir = path.join(config.builddir(), \".deps\")\n    end\n    local namespace = self:namespace()\n    if namespace then\n        dependir = path.join(dependir, (namespace:replace(\"::\", path.sep())), self:name())\n    else\n        dependir = path.join(dependir, self:name())\n    end\n\n    -- get root directory of target\n    local intermediate_directory = self:policy(\"build.intermediate_directory\")\n    if (opt and opt.root) or intermediate_directory == false then\n        return dependir\n    end\n\n    -- generate intermediate directory\n    local plat = self:plat()\n    if plat then\n        dependir = path.join(dependir, plat)\n    end\n    local arch = self:arch()\n    if arch then\n        dependir = path.join(dependir, arch)\n    end\n    local mode = config.mode()\n    if mode then\n        dependir = path.join(dependir, mode)\n    end\n    return dependir\nend\n\n-- get the autogen files directory\nfunction _instance:autogendir(opt)\n\n    -- init the autogen directory\n    local autogendir = self:get(\"autogendir\")\n    if not autogendir then\n        autogendir = path.join(config.builddir(), \".gens\")\n    end\n    local namespace = self:namespace()\n    if namespace then\n        autogendir = path.join(autogendir, (namespace:replace(\"::\", path.sep())), self:name())\n    else\n        autogendir = path.join(autogendir, self:name())\n    end\n\n    -- get root directory of target\n    local intermediate_directory = self:policy(\"build.intermediate_directory\")\n    if (opt and opt.root) or intermediate_directory == false then\n        return autogendir\n    end\n\n    -- generate intermediate directory\n    local plat = self:plat()\n    if plat then\n        autogendir = path.join(autogendir, plat)\n    end\n    local arch = self:arch()\n    if arch then\n        autogendir = path.join(autogendir, arch)\n    end\n    local mode = config.mode()\n    if mode then\n        autogendir = path.join(autogendir, mode)\n    end\n    return autogendir\nend\n\n-- get the autogen file path from the given source file path\nfunction _instance:autogenfile(sourcefile, opt)\n\n    -- get relative directory in the autogen directory\n    local relativedir = nil\n    local origindir  = path.directory(path.absolute(sourcefile))\n    local autogendir = path.absolute(self:autogendir())\n    if origindir:startswith(autogendir) then\n        relativedir = path.join(\"gens\", path.relative(origindir, autogendir))\n    end\n\n    -- get relative directory in the source directory\n    if not relativedir then\n        relativedir = path.directory(sourcefile)\n    end\n\n    -- translate path\n    --\n    -- e.g.\n    --\n    -- src/xxx.c\n    --      project/xmake.lua\n    --          build/.objs\n    --          build/.gens\n    --\n    -- objectfile: project/build/.objs/xxxx/../../xxx.c will be out of range for objectdir\n    -- autogenfile: project/build/.gens/xxxx/../../xxx.c will be out of range for autogendir\n    --\n    -- we need to replace '..' with '__' in this case\n    --\n    if path.is_absolute(relativedir) and os.host() == \"windows\" then\n        -- remove C:\\\\ and whitespaces and fix long path issue\n        -- e.g. C:\\\\Program Files (x64)\\\\xxx\\Windows.h\n        --\n        -- @see\n        -- https://github.com/xmake-io/xmake/issues/3021\n        -- https://github.com/xmake-io/xmake/issues/3715\n        relativedir = hash.strhash128(relativedir)\n    end\n    relativedir = relativedir:gsub(\"%.%.\", \"__\")\n    local rootdir = (opt and opt.rootdir) and opt.rootdir or self:autogendir()\n    if relativedir ~= \".\" then\n        rootdir = path.join(rootdir, relativedir)\n    end\n    return path.join(rootdir, (opt and opt.filename) and opt.filename or path.filename(sourcefile))\nend\n\n-- get the default target directory\nfunction _instance:_default_targetdir()\n    local targetdir = config.builddir()\n\n    -- get root directory of target\n    local intermediate_directory = self:policy(\"build.intermediate_directory\")\n    if intermediate_directory == false then\n        return targetdir\n    end\n\n    -- generate intermediate directory\n    local plat = self:plat()\n    if plat then\n        targetdir = path.join(targetdir, plat)\n    end\n    local arch = self:arch()\n    if arch then\n        targetdir = path.join(targetdir, arch)\n    end\n    local mode = config.mode()\n    if mode then\n        targetdir = path.join(targetdir, mode)\n    end\n    local namespace = self:namespace()\n    if namespace then\n        targetdir = path.join(targetdir, (namespace:replace(\"::\", path.sep())))\n    end\n    return targetdir\nend\n\n-- get the target directory\nfunction _instance:targetdir()\n    local targetdir = self:get(\"targetdir\")\n    if not targetdir then\n        return self:_default_targetdir()\n    end\n\n    -- we can use `set_targetdir(\"xxx\", {bindir = \"\", libdir = \"\"})` to set sub-directory\n    local subdir_kind\n    if self:is_binary() or (self:is_shared() and self:is_plat(\"windows\", \"mingw\")) then\n        subdir_kind = \"bindir\"\n    elseif self:is_static() or self:is_shared() then\n        subdir_kind = \"libdir\"\n    end\n    return self:_artifactdir(subdir_kind)\nend\n\n-- get the build artifact output directory,\n--\n-- @param subdir_kind  the sub-directory kind, e.g. libdir, bindir, includedir\n--\nfunction _instance:_artifactdir(subdir_kind)\n    local targetdir = self:get(\"targetdir\")\n    if not targetdir then\n        return self:_default_targetdir()\n    end\n\n    if subdir_kind then\n        local subdir = self:extraconf(\"targetdir\", targetdir, subdir_kind)\n        if subdir then\n            return path.join(targetdir, subdir)\n        end\n    end\n    return targetdir\nend\n\n-- get the extra build artifact file\n--\n-- supported artifact kinds:\n--    1. implib: windows DLL/EXE implib(.lib, .dll.a)\n--\n-- otherwise returns nil\n--\nfunction _instance:artifactfile(kind)\n    if kind == \"implib\" then\n        if (self:is_shared() or self:is_binary()) and self:is_plat(\"windows\", \"mingw\") then\n            return path.join(self:_artifactdir(\"libdir\"), path.basename(self:filename()) .. (self:is_plat(\"mingw\") and \".dll.a\" or \".lib\"))\n        end\n    end\nend\n\n-- get the target file name\nfunction _instance:filename()\n\n    -- no target file?\n    if self:is_object() or self:is_phony() or self:is_headeronly() or self:is_moduleonly() then\n        return\n    end\n\n    -- make the target file name and attempt to use the format of linker first\n    local targetkind = self:targetkind()\n    local filename = self:get(\"filename\")\n    if not filename then\n        local prefixname = self:get(\"prefixname\")\n        local suffixname = self:get(\"suffixname\")\n        local extension  = self:get(\"extension\")\n        filename = target.filename(self:basename(), targetkind, {\n            format = self:_format(),\n            plat = self:plat(), arch = self:arch(),\n            prefixname = prefixname,\n            suffixname = suffixname,\n            extension = extension})\n    end\n    return filename\nend\n\n-- get the link name only for static/shared library\nfunction _instance:linkname()\n    if self:is_static() or self:is_shared() then\n        local filename = self:get(\"filename\")\n        if filename then\n            return target.linkname(filename)\n        else\n            local linkname = self:basename()\n            local suffixname = self:get(\"suffixname\")\n            if suffixname then\n                linkname = linkname .. suffixname\n            end\n            return linkname\n        end\n    end\nend\n\n-- get the target file\nfunction _instance:targetfile()\n    local filename = self:filename()\n    if filename then\n        return path.join(self:targetdir(), filename)\n    end\nend\n\n-- get the symbol file\nfunction _instance:symbolfile()\n\n    -- the target directory\n    local targetdir = self:targetdir()\n    assert(targetdir and type(targetdir) == \"string\")\n\n    -- the symbol file name\n    local prefixname = self:get(\"prefixname\")\n    local suffixname = self:get(\"suffixname\")\n    local filename = target.filename(self:basename(), \"symbol\", {\n        plat = self:plat(), arch = self:arch(),\n        format = self:_format(\"symbol\"),\n        prefixname = prefixname,\n        suffixname = suffixname})\n    assert(filename)\n\n    -- make the symbol file path\n    return path.join(targetdir, filename)\nend\n\n-- get the script directory of xmake.lua\nfunction _instance:scriptdir()\n    return self:get(\"__scriptdir\")\nend\n\n-- get configuration output directory\nfunction _instance:configdir()\n    return self:get(\"configdir\") or config.builddir()\nend\n\n-- get run directory\nfunction _instance:rundir()\n    return baseoption.get(\"workdir\") or self:get(\"rundir\") or path.directory(self:targetfile())\nend\n\n-- get prefix directory\nfunction _instance:prefixdir()\n    return self:get(\"prefixdir\")\nend\n\n-- get the installed binary directory\nfunction _instance:bindir()\n    local bindir = baseoption.get(\"bindir\")\n    if bindir then\n        return path.is_absolute(bindir) and path.normalize(bindir) or self:installdir(bindir)\n    end\n    bindir = self:extraconf(\"prefixdir\", self:prefixdir(), \"bindir\")\n    if bindir == nil then\n        bindir = \"bin\"\n    end\n    return self:installdir(bindir)\nend\n\n-- get the installed library directory\nfunction _instance:libdir()\n    local libdir = baseoption.get(\"libdir\")\n    if libdir then\n        return path.is_absolute(libdir) and path.normalize(libdir) or self:installdir(libdir)\n    end\n    libdir = self:extraconf(\"prefixdir\", self:prefixdir(), \"libdir\")\n    if libdir == nil then\n        libdir = \"lib\"\n    end\n    return self:installdir(libdir)\nend\n\n-- get the installed include directory\nfunction _instance:includedir()\n    local includedir = baseoption.get(\"includedir\")\n    if includedir then\n        return path.is_absolute(includedir) and path.normalize(includedir) or self:installdir(includedir)\n    end\n    includedir = self:extraconf(\"prefixdir\", self:prefixdir(), \"includedir\")\n    if includedir == nil then\n        includedir = \"include\"\n    end\n    return self:installdir(includedir)\nend\n\n-- get install directory\nfunction _instance:installdir(...)\n    opt = opt or {}\n    local installdir = baseoption.get(\"installdir\")\n    if not installdir then\n        -- DESTDIR: be compatible with https://www.gnu.org/prep/standards/html_node/DESTDIR.html\n        installdir = self:get(\"installdir\") or os.getenv(\"INSTALLDIR\") or os.getenv(\"PREFIX\") or os.getenv(\"DESTDIR\") or platform.get(\"installdir\")\n        if installdir then\n            installdir = installdir:trim()\n        end\n    end\n    if installdir then\n        local prefixdir = self:prefixdir()\n        if prefixdir then\n            installdir = path.join(installdir, prefixdir)\n        end\n        return path.normalize(path.join(installdir, ...))\n    end\nend\n\n-- get package directory\nfunction _instance:packagedir()\n    -- get the output directory\n    local outputdir   = baseoption.get(\"outputdir\") or config.builddir()\n    local packagename = self:name():lower()\n    if #packagename > 1 and bit.band(packagename:byte(2), 0xc0) == 0x80 then\n        utils.warning(\"package(%s): cannot generate package, becauese it contains unicode characters!\", packagename)\n        return\n    end\n    return path.join(outputdir, \"packages\", packagename:sub(1, 1), packagename)\nend\n\n-- get rules of the source file\nfunction _instance:filerules(sourcefile)\n\n    -- add rules from file config\n    local rules = {}\n    local override = false\n    local fileconfig = self:fileconfig(sourcefile)\n    if fileconfig then\n        local filerules = fileconfig.rules or fileconfig.rule\n        if filerules then\n            override = filerules.override\n            for _, rulename in ipairs(table.wrap(filerules)) do\n                local r = target._project().rule(rulename, {namespace = self:namespace()}) or\n                            rule.rule(rulename) or self:rule(rulename)\n                if r then\n                    table.insert(rules, r)\n                end\n            end\n        end\n    end\n    -- override? e.g. add_files(\"src/*.c\", {rules = {\"xxx\", override = true}})\n    if override then\n        return rules, true\n    end\n\n    -- load all rules for this target with sourcekinds and extensions\n    local key2rules = self:memcache():get(\"key2rules\")\n    if not key2rules then\n        key2rules = {}\n        for _, r in pairs(table.wrap(self:rules())) do\n            -- we can also get sourcekinds from add_rules(\"xxx\", {sourcekinds = \"cxx\"})\n            local rule_sourcekinds = self:extraconf(\"rules\", r:name(), \"sourcekinds\") or r:get(\"sourcekinds\")\n            for _, sourcekind in ipairs(table.wrap(rule_sourcekinds)) do\n                key2rules[sourcekind] = key2rules[sourcekind] or {}\n                table.insert(key2rules[sourcekind], r)\n            end\n            -- we can also get extensions from add_rules(\"xxx\", {extensions = \".cpp\"})\n            local rule_extensions = self:extraconf(\"rules\", r:name(), \"extensions\") or r:get(\"extensions\")\n            for _, extension in ipairs(table.wrap(rule_extensions)) do\n                extension = extension:lower()\n                key2rules[extension] = key2rules[extension] or {}\n                table.insert(key2rules[extension], r)\n            end\n        end\n        self:memcache():set(\"key2rules\", key2rules)\n    end\n\n    -- get target rules from the given sourcekind or extension\n    --\n    -- @note we prefer to use rules with extension because we need to be able to\n    -- override the language code rules set by set_sourcekinds\n    --\n    -- e.g. set_extensions(\".bpf.c\") will override c++ rules\n    --\n    local rules_override = {}\n    local filename = path.filename(sourcefile):lower()\n    for _, r in ipairs(table.wrap(key2rules[path.extension(filename, 2)] or\n                                  key2rules[path.extension(filename)] or\n                                  key2rules[self:sourcekind_of(filename)] or\n                                  key2rules[fileconfig and fileconfig.sourcekind])) do -- add_files(\"*.nasm\", {sourcekind = \"asm\"})\n        if self:extraconf(\"rules\", r:name(), \"override\") then\n            table.insert(rules_override, r)\n        else\n            table.insert(rules, r)\n        end\n    end\n\n    -- we will use overrided rules first, e.g. add_rules(\"xxx\", {override = true})\n    return #rules_override > 0 and rules_override or rules\nend\n\n-- get the config info of the given source file\nfunction _instance:fileconfig(sourcefile, opt)\n    opt = opt or {}\n    local filetype = opt.filetype or \"files\"\n\n    -- get configs from user, e.g. target:fileconfig_set/add\n    -- it has contained all original configs\n    if self._FILESCONFIG_USER then\n        local filesconfig = self._FILESCONFIG_USER[filetype]\n        if filesconfig and filesconfig[sourcefile] then\n            return filesconfig[sourcefile]\n        end\n    end\n\n    -- get orignal configs from `add_xxxfiles()`\n    self._FILESCONFIG = self._FILESCONFIG or {}\n    local filesconfig = self._FILESCONFIG[filetype]\n    if not filesconfig then\n        filesconfig = {}\n        for filepath, fileconfig in pairs(table.wrap(self:extraconf(filetype))) do\n            local results = os.match(filepath)\n            if #results > 0 then\n                for _, file in ipairs(results) do\n                    if path.is_absolute(file) then\n                        file = path.relative(file, os.projectdir())\n                    end\n                    filesconfig[file] = fileconfig\n                end\n            else\n                -- we also need support always_added, @see https://github.com/xmake-io/xmake/issues/1634\n                if fileconfig.always_added then\n                    filesconfig[filepath] = fileconfig\n                end\n            end\n        end\n        self._FILESCONFIG[filetype] = filesconfig\n    end\n    return filesconfig[sourcefile]\nend\n\n-- set the config info to the given source file\nfunction _instance:fileconfig_set(sourcefile, info, opt)\n    opt = opt or {}\n    self._FILESCONFIG_USER = self._FILESCONFIG_USER or {}\n    local filetype = opt.filetype or \"files\"\n    local filesconfig = self._FILESCONFIG_USER[filetype]\n    if not filesconfig then\n        filesconfig = {}\n        self._FILESCONFIG_USER[filetype] = filesconfig\n    end\n    filesconfig[sourcefile] = info\nend\n\n-- add the config info to the given source file\nfunction _instance:fileconfig_add(sourcefile, info, opt)\n    opt = opt or {}\n    self._FILESCONFIG_USER = self._FILESCONFIG_USER or {}\n    local filetype = opt.filetype or \"files\"\n    local filesconfig = self._FILESCONFIG_USER[filetype]\n    if not filesconfig then\n        filesconfig = {}\n        self._FILESCONFIG_USER[filetype] = filesconfig\n    end\n\n    -- we fetch orignal configs first if no user configs\n    local fileconfig = filesconfig[sourcefile]\n    if not fileconfig then\n        fileconfig = table.clone(self:fileconfig(sourcefile, opt))\n        filesconfig[sourcefile] = fileconfig\n    end\n    if fileconfig then\n        for k, v in pairs(info) do\n            if k == \"force\" then\n                -- fileconfig_add(\"xxx.c\", {force = {cxxflags = \"\"}})\n                local force = fileconfig[k] or {}\n                for k2, v2 in pairs(v) do\n                    if force[k2] then\n                        force[k2] = table.join(force[k2], v2)\n                    else\n                        force[k2] = v2\n                    end\n                end\n                fileconfig[k] = force\n            else\n                -- fileconfig_add(\"xxx.c\", {cxxflags = \"\"})\n                if fileconfig[k] then\n                    fileconfig[k] = table.join(fileconfig[k], v)\n                else\n                    fileconfig[k] = v\n                end\n            end\n        end\n    else\n        filesconfig[sourcefile] = info\n    end\nend\n\n-- get the source files\nfunction _instance:sourcefiles()\n\n    -- cached? return it directly\n    if self._SOURCEFILES then\n        return self._SOURCEFILES, false\n    end\n\n    -- get files\n    local files = self:get(\"files\")\n    if not files then\n        return {}, false\n    end\n\n    -- match files\n    local i = 1\n    local count = 0\n    local sourcefiles = {}\n    local sourcefiles_removed = {}\n    local sourcefiles_inserted = {}\n    local removed_count = 0\n    local targetcache = memcache.cache(\"core.project.target\")\n    for _, file in ipairs(table.wrap(files)) do\n\n        -- mark as removed files?\n        local removed = false\n        local prefix = \"__remove_\"\n        if file:startswith(prefix) then\n            file = file:sub(#prefix + 1)\n            removed = true\n        end\n\n        local results\n        if removed then\n            results = {file}\n        else\n            -- find source files and try to cache the matching results of os.match across targets\n            -- @see https://github.com/xmake-io/xmake/issues/1353\n            results = targetcache:get2(\"sourcefiles\", file)\n            if results == nil then\n                results = os.files(file)\n                if #results == 0 then\n                    -- attempt to find source directories if maybe compile it as directory with the custom rules\n                    if #self:filerules(file) > 0 then\n                        results = os.dirs(file)\n                    end\n                end\n\n                -- Even if the current source file does not exist yet, we always add it.\n                -- This is usually used for some rules that automatically generate code files,\n                -- because they ensure that the code files have been generated before compilation.\n                --\n                -- @see https://github.com/xmake-io/xmake/issues/1540\n                --\n                -- e.g. add_files(\"src/test.c\", {always_added = true})\n                --\n                if #results == 0 and self:extraconf(\"files\", file, \"always_added\") then\n                    results = {file}\n                end\n            end\n            targetcache:set2(\"sourcefiles\", file, results)\n        end\n        if #results == 0 then\n            local sourceinfo = self:sourceinfo(\"files\", file) or {}\n            utils.warning(\"%s:%d${clear}: cannot match %s_files(\\\"%s\\\") in %s(%s)\",\n                sourceinfo.file or \"\", sourceinfo.line or -1, (removed and \"remove\" or \"add\"), file, self:type(), self:fullname())\n        end\n\n        -- process source files\n        for _, sourcefile in ipairs(results) do\n\n            -- convert to the relative path\n            if path.is_absolute(sourcefile) then\n                sourcefile = path.relative(sourcefile, os.projectdir())\n            end\n\n            -- add or remove it\n            if removed then\n                removed_count = removed_count + 1\n                table.insert(sourcefiles_removed, sourcefile)\n            elseif not sourcefiles_inserted[sourcefile] then\n                table.insert(sourcefiles, sourcefile)\n                sourcefiles_inserted[sourcefile] = true\n            end\n        end\n    end\n\n    -- remove all source files which need be removed\n    if removed_count > 0 then\n        table.remove_if(sourcefiles, function (i, sourcefile)\n            for _, removed_file in ipairs(sourcefiles_removed) do\n                local pattern = path.translate((removed_file:gsub(\"|.*$\", \"\")))\n                if pattern:sub(1, 2):find('%.[/\\\\]') then\n                    pattern = pattern:sub(3)\n                end\n                pattern = path.pattern(pattern)\n                -- we need to match whole pattern, https://github.com/xmake-io/xmake/issues/3523\n                if sourcefile:match(\"^\" .. pattern .. \"$\") then\n                    return true\n                end\n            end\n        end)\n    end\n    self._SOURCEFILES = sourcefiles\n\n    -- ok and sourcefiles are modified\n    return sourcefiles, true\nend\n\n-- get object file from source file\nfunction _instance:objectfile(sourcefile)\n    return self:autogenfile(sourcefile, {rootdir = self:objectdir(),\n        filename = target.filename(path.filename(sourcefile), \"object\", {\n            plat = self:plat(),\n            arch = self:arch(),\n            format = self:_format(\"object\")})})\nend\n\n-- get the object files\nfunction _instance:objectfiles()\n\n    -- get source batches\n    local sourcebatches, modified = self:sourcebatches()\n\n    -- cached? return it directly\n    if self._OBJECTFILES and not modified then\n        return self._OBJECTFILES\n    end\n\n    -- get object files from source batches\n    local objectfiles = {}\n    local batchcount = 0\n    local orderkeys = table.keys(sourcebatches)\n    table.sort(orderkeys) -- @note we need to guarantee the order of objectfiles for depend.is_changed() and etc.\n    for _, k in ipairs(orderkeys) do\n        local sourcebatch = sourcebatches[k]\n        table.join2(objectfiles, sourcebatch.objectfiles)\n        batchcount = batchcount + 1\n    end\n\n    -- some object files may be repeat and appear link errors if multi-batches exists, so we need to remove all repeat object files\n    -- e.g. add_files(\"src/*.c\", {rules = {\"rule1\", \"rule2\"}})\n    local deduplicate = batchcount > 1\n\n    -- get object files from all dependent targets (object kind)\n    -- @note we only merge objects in plain deps, e.g. binary -> (static -> object, object ...)\n    local plaindeps = self:get(\"deps\")\n    if plaindeps and (self:is_binary() or self:is_shared() or self:is_static()) then\n        local function _get_all_objectfiles_of_object_dep (t)\n            local _objectfiles = {}\n            table.join2(_objectfiles, t:objectfiles())\n            local _plaindeps = t:get(\"deps\")\n            if _plaindeps then\n                for _, depname in ipairs(table.wrap(_plaindeps)) do\n                    local dep = t:dep(depname)\n                    if dep and dep:is_object() then\n                        table.join2(_objectfiles, _get_all_objectfiles_of_object_dep(dep))\n                    end\n                end\n            end\n            return _objectfiles\n        end\n        for _, depname in ipairs(table.wrap(plaindeps)) do\n            local dep = self:dep(depname)\n            if dep and dep:is_object() then\n                table.join2(objectfiles, _get_all_objectfiles_of_object_dep(dep))\n                deduplicate = true\n            end\n        end\n    end\n\n    -- remove repeat object files\n    if deduplicate then\n        objectfiles = table.unique(objectfiles)\n    end\n\n    -- cache it\n    self._OBJECTFILES = objectfiles\n    return objectfiles\nend\n\n-- get the header files\nfunction _instance:headerfiles(outputdir, opt)\n    opt = opt or {}\n    local headerfiles = self:get(\"headerfiles\", opt) or {}\n    -- add_headerfiles(\"src/*.h\", {install = false})\n    -- @see https://github.com/xmake-io/xmake/issues/2577\n    if opt.installonly then\n       local installfiles = {}\n       for _, headerfile in ipairs(table.wrap(headerfiles)) do\n           if self:extraconf(\"headerfiles\", headerfile, \"install\") ~= false then\n               table.insert(installfiles, headerfile)\n           end\n       end\n       headerfiles = installfiles\n    end\n    if not headerfiles then\n        return\n    end\n\n    if not outputdir then\n        if self:includedir() then\n            outputdir = self:includedir()\n        end\n    end\n    return match_copyfiles(self, \"headerfiles\", outputdir, {copyfiles = headerfiles})\nend\n\n-- get the configuration files\nfunction _instance:configfiles(outputdir)\n    return match_copyfiles(self, \"configfiles\", outputdir or self:configdir(), {pathfilter = function (dstpath, fileinfo)\n            if dstpath:endswith(\".in\") then\n                dstpath = dstpath:sub(1, -4)\n            end\n            return dstpath\n        end})\nend\n\n-- get the install files\nfunction _instance:installfiles(outputdir, opt)\n    local installfiles = self:get(\"installfiles\", opt) or {}\n    return match_copyfiles(self, \"installfiles\", outputdir or self:installdir(), {copyfiles = installfiles})\nend\n\n-- get the extra files\nfunction _instance:extrafiles(outputdir)\n    return match_copyfiles(self, \"extrafiles\", outputdir)\nend\n\n-- get depend file from object file\nfunction _instance:dependfile(objectfile)\n\n    -- get the dependent original file and directory, @note relative to the root directory\n    local originfile = path.absolute(objectfile and objectfile or self:targetfile())\n    local origindir  = path.directory(originfile)\n\n    -- get relative directory in the object directory\n    local relativedir = nil\n    local objectdir = path.absolute(self:objectdir())\n    if origindir:startswith(objectdir) then\n        relativedir = path.relative(origindir, objectdir)\n    end\n\n    -- get relative directory in the target directory\n    if not relativedir then\n        local targetdir = path.absolute(self:targetdir())\n        if origindir:startswith(targetdir) then\n            relativedir = path.relative(origindir, targetdir)\n        end\n    end\n\n    -- get relative directory in the autogen directory\n    if not relativedir then\n        local autogendir = path.absolute(self:autogendir())\n        if origindir:startswith(autogendir) then\n            relativedir = path.join(\"gens\", path.relative(origindir, autogendir))\n        end\n    end\n\n    -- get relative directory in the build directory\n    if not relativedir then\n        local builddir = path.absolute(config.builddir())\n        if origindir:startswith(builddir) then\n            relativedir = path.join(\"build\", path.relative(origindir, builddir))\n        end\n    end\n\n    -- get relative directory in the project directory\n    if not relativedir then\n        local projectdir = os.projectdir()\n        if origindir:startswith(projectdir) then\n            relativedir = path.relative(origindir, projectdir)\n        end\n    end\n\n    -- get the relative directory from the origin file\n    if not relativedir then\n        relativedir = origindir\n    end\n    if path.is_absolute(relativedir) and os.host() == \"windows\" then\n        -- remove C:\\\\ and whitespaces and fix long path issue\n        -- e.g. C:\\\\Program Files (x64)\\\\xxx\\Windows.h\n        --\n        -- @see\n        -- https://github.com/xmake-io/xmake/issues/3021\n        -- https://github.com/xmake-io/xmake/issues/3715\n        relativedir = hash.strhash128(relativedir)\n    end\n\n    -- originfile: project/build/.objs/xxxx/../../xxx.c will be out of range for objectdir\n    --\n    -- we need to replace '..' to '__' in this case\n    --\n    relativedir = relativedir:gsub(\"%.%.\", \"__\")\n\n    -- make dependent file\n    -- full file name(not base) to avoid name-clash of original file\n    return path.join(self:dependir(), relativedir, path.filename(originfile) .. \".d\")\nend\n\n-- get the dependent include files\nfunction _instance:dependfiles()\n    local sourcebatches, modified = self:sourcebatches()\n    if self._DEPENDFILES and not modified then\n        return self._DEPENDFILES\n    end\n    local dependfiles = {}\n    for _, sourcebatch in pairs(self:sourcebatches()) do\n        table.join2(dependfiles, sourcebatch.dependfiles)\n    end\n    self._DEPENDFILES = dependfiles\n    return dependfiles\nend\n\n-- get the sourcekind for the given source file\nfunction _instance:sourcekind_of(sourcefile)\n\n    -- get the sourcekind of this source file\n    local sourcekind = language.sourcekind_of(sourcefile)\n    local fileconfig = self:fileconfig(sourcefile)\n    if fileconfig and fileconfig.sourcekind then\n        -- we can override the sourcekind, e.g. add_files(\"*.c\", {sourcekind = \"cxx\"})\n        sourcekind = fileconfig.sourcekind\n    end\n    return sourcekind\nend\n\n-- get the kinds of sourcefiles\n--\n-- e.g. cc cxx mm mxx as ...\n--\nfunction _instance:sourcekinds()\n    local sourcekinds = self._SOURCEKINDS\n    if not sourcekinds then\n        sourcekinds = {}\n        local sourcebatches = self:sourcebatches()\n        for _, sourcebatch in table.orderpairs(sourcebatches) do\n            local sourcekind = sourcebatch.sourcekind\n            if sourcekind then\n                table.insert(sourcekinds, sourcekind)\n            end\n        end\n        -- if the source file is added dynamically, we may not be able to get the sourcekinds,\n        -- so we can only continue to get it from the rule\n        -- https://github.com/xmake-io/xmake/issues/1622#issuecomment-927726697\n        for _, ruleinst in ipairs(self:orderules()) do\n            local rule_sourcekinds = ruleinst:get(\"sourcekinds\")\n            if rule_sourcekinds then\n                table.insert(sourcekinds, rule_sourcekinds)\n            end\n        end\n        sourcekinds = table.unique(sourcekinds)\n        self._SOURCEKINDS = sourcekinds\n    end\n    return sourcekinds\nend\n\n-- get source count\nfunction _instance:sourcecount()\n    return #self:sourcefiles()\nend\n\n-- get source batches\nfunction _instance:sourcebatches()\n\n    -- get source files\n    local sourcefiles, modified = self:sourcefiles()\n\n    -- cached? return it directly\n    if self._SOURCEBATCHES and not modified then\n        return self._SOURCEBATCHES, false\n    end\n\n    -- make source batches for each source kinds\n    local sourcebatches = {}\n    for _, sourcefile in ipairs(sourcefiles) do\n\n        -- get file rules\n        local filerules, override = self:filerules(sourcefile)\n        if #filerules == 0 then\n            os.raise(\"unknown source file: %s\", sourcefile)\n        end\n\n        -- add source batch for the file rules\n        for _, filerule in ipairs(filerules) do\n\n            -- get rule name\n            local rulename = filerule:name()\n\n            -- make this batch\n            local sourcebatch = sourcebatches[rulename] or {sourcefiles = {}}\n            sourcebatches[rulename] = sourcebatch\n\n            -- save the rule name\n            sourcebatch.rulename = rulename\n\n            -- add source file to this batch\n            table.insert(sourcebatch.sourcefiles, sourcefile)\n\n            -- attempt to get source kind from the builtin languages\n            local sourcekind = self:sourcekind_of(sourcefile)\n            if sourcekind and filerule:get(\"sourcekinds\") and not override then\n\n                -- save source kind\n                sourcebatch.sourcekind = sourcekind\n\n                -- insert object files to source batches\n                -- and we need to avoid duplication with object files, which may cause some conflicts.\n                -- e.g. c++.build, c++ module and unity_build rules\n                -- @see https://github.com/xmake-io/xmake/issues/6420\n                if filerule:extraconf(\"sourcekinds\", sourcekind, \"objectfiles\") ~= false then\n                    sourcebatch.objectfiles = sourcebatch.objectfiles or {}\n                    sourcebatch.dependfiles = sourcebatch.dependfiles or {}\n                    local objectfile = self:objectfile(sourcefile)\n                    table.insert(sourcebatch.objectfiles, objectfile)\n                    table.insert(sourcebatch.dependfiles, self:dependfile(objectfile))\n                end\n            end\n        end\n    end\n    self._SOURCEBATCHES = sourcebatches\n    return sourcebatches, modified\nend\n\n-- get xxx_script\nfunction _instance:script(name, generic)\n\n    -- get script\n    local script = self:get(name)\n    local result = select_script(script, {plat = self:plat(), arch = self:arch()}) or generic\n\n    -- imports some modules first\n    if result and result ~= generic then\n        local scope = getfenv(result)\n        if scope then\n            for _, modulename in ipairs(table.wrap(self:get(\"imports\"))) do\n                scope[sandbox_module.name(modulename)] = sandbox_module.import(modulename, {anonymous = true})\n            end\n        end\n    end\n    return result\nend\n\n-- get the precompiled header file (xxx.[h|hpp|inl])\n--\n-- @param langkind  c/cxx\n--\nfunction _instance:pcheaderfile(langkind)\n    local pcheaderfile = self:get(\"p\" .. langkind .. \"header\")\n    if table.empty(pcheaderfile) then\n        pcheaderfile = nil\n    end\n    return pcheaderfile\nend\n\n-- set the precompiled header file\nfunction _instance:pcheaderfile_set(langkind, headerfile)\n    self:set(\"p\" .. langkind .. \"header\", headerfile)\n    self._PCOUTPUTFILES = nil\nend\n\n-- get the output of precompiled header file (xxx.h.pch)\n--\n-- @param langkind  c/cxx\n--\nfunction _instance:pcoutputfile(langkind)\n    self._PCOUTPUTFILES = self._PCOUTPUTFILES or {}\n    local pcoutputfile = self._PCOUTPUTFILES[langkind]\n    if pcoutputfile then\n        return pcoutputfile\n    end\n\n    -- get the precompiled header file in the object directory\n    local pcheaderfile = self:pcheaderfile(langkind)\n    if pcheaderfile then\n        local is_gcc = false\n        local is_msvc = false\n        local sourcekinds = {c = \"cc\", cxx = \"cxx\", m = \"mm\", mxx = \"mxx\"}\n        local sourcekind = assert(sourcekinds[langkind], \"unknown language kind: \" .. langkind)\n        local _, toolname = self:tool(sourcekind)\n        if toolname then\n            if toolname == \"gcc\" or toolname == \"gxx\" then\n                is_gcc = true\n            elseif toolname == \"cl\" then\n                is_msvc = true\n            end\n        end\n\n        -- make precompiled output file\n        --\n        -- @note gcc has not -include-pch option to set the pch file path\n        --\n        pcoutputfile = self:objectfile(pcheaderfile)\n        local pcoutputfilename = path.basename(pcoutputfile)\n        if is_gcc then\n            pcoutputfilename = pcoutputfilename .. \".gch\"\n        else\n            -- different vs versions of pch files are not backward compatible,\n            -- so we need to distinguish between them.\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/5413\n            local msvc = self:toolchain(\"msvc\")\n            if is_msvc and msvc then\n                local vs_toolset = msvc:config(\"vs_toolset\")\n                if vs_toolset then\n                    vs_toolset = sandbox_module.import(\"private.utils.toolchain\", {anonymous = true}).get_vs_toolset_ver(vs_toolset)\n                end\n                if vs_toolset then\n                    pcoutputfilename = pcoutputfilename .. \"_\" .. vs_toolset\n                end\n            end\n            pcoutputfilename = pcoutputfilename .. \".pch\"\n        end\n        pcoutputfile = path.join(path.directory(pcoutputfile), sourcekind, pcoutputfilename)\n        self._PCOUTPUTFILES[langkind] = pcoutputfile\n        return pcoutputfile\n    end\nend\n\n-- get runtimes\nfunction _instance:runtimes()\n    local runtimes = self:memcache():get(\"runtimes\")\n    if runtimes == nil then\n        runtimes = self:get(\"runtimes\")\n        if runtimes then\n            local runtimes_supported = hashset.new()\n            local toolchains = self:toolchains() or platform.load(self:plat(), self:arch()):toolchains()\n            if toolchains then\n                for _, toolchain_inst in ipairs(toolchains) do\n                    if toolchain_inst:is_standalone() and toolchain_inst:get(\"runtimes\") then\n                        for _, runtime in ipairs(table.wrap(toolchain_inst:get(\"runtimes\"))) do\n                            runtimes_supported:insert(runtime)\n                        end\n                    end\n                end\n            end\n            local runtimes_current = {}\n            for _, runtime in ipairs(table.wrap(runtimes)) do\n                if runtimes_supported:has(runtime) then\n                    table.insert(runtimes_current, runtime)\n                end\n            end\n            runtimes = table.unwrap(runtimes_current)\n        end\n        runtimes = runtimes or false\n        self:memcache():set(\"runtimes\", runtimes)\n    end\n    return runtimes or nil\nend\n\n-- has the given runtime for the current toolchains?\nfunction _instance:has_runtime(...)\n    local runtimes_set = self:memcache():get(\"runtimes_set\")\n    if runtimes_set == nil then\n        runtimes_set = hashset.from(table.wrap(self:runtimes()))\n        self:memcache():set(\"runtimes_set\", runtimes_set)\n    end\n    for _, v in ipairs(table.pack(...)) do\n        if runtimes_set:has(v) then\n            return true\n        end\n    end\nend\n\n-- get the given toolchain\nfunction _instance:toolchain(name)\n    local toolchains_map = self:memcache():get(\"toolchains_map\")\n    if toolchains_map == nil then\n        toolchains_map = {}\n        for _, toolchain_inst in ipairs(self:toolchains()) do\n            toolchains_map[toolchain_inst:name()] = toolchain_inst\n        end\n        self:memcache():set(\"toolchains_map\", toolchains_map)\n    end\n    return toolchains_map[name]\nend\n\n-- get the toolchains\nfunction _instance:toolchains()\n    local toolchains = self:memcache():get(\"toolchains\")\n    if toolchains == nil then\n\n        -- load target toolchains first\n        local has_standalone = false\n        local target_toolchains = self:get(\"toolchains\")\n        if target_toolchains then\n            toolchains = {}\n            for _, name in ipairs(table.wrap(target_toolchains)) do\n                local toolchain_opt = table.copy(self:extraconf(\"toolchains\", name))\n                toolchain_opt.arch = self:arch()\n                toolchain_opt.plat = self:plat()\n                toolchain_opt.namespace = self:namespace()\n                local toolchain_inst, errors = toolchain.load(name, toolchain_opt)\n                -- attempt to load toolchain from project\n                if not toolchain_inst and target._project() then\n                    toolchain_inst = target._project().toolchain(name, toolchain_opt)\n                end\n                if not toolchain_inst then\n                    os.raise(errors)\n                end\n                if toolchain_inst:is_standalone() then\n                    has_standalone = true\n                end\n                table.insert(toolchains, toolchain_inst)\n            end\n\n            -- we always need a standalone toolchain\n            -- because we maybe only set partial toolchains in target, e.g. nasm toolchain\n            --\n            -- @note platform has been checked in config/_check_target_toolchains\n            if not has_standalone then\n                for _, toolchain_inst in ipairs(self:platform():toolchains()) do\n                    if toolchain_inst:is_standalone() then\n                        table.insert(toolchains, toolchain_inst)\n                        has_standalone = true\n                        break\n                    end\n                end\n            end\n        else\n            toolchains = self:platform():toolchains()\n        end\n\n        self:memcache():set(\"toolchains\", toolchains)\n    end\n    return toolchains\nend\n\n-- get the program and name of the given tool kind\nfunction _instance:tool(toolkind)\n    -- we cannot get tool in on_load, because target:toolchains() has been not checked in configuration stage.\n    if not self._LOADED_AFTER then\n        os.raise(\"we cannot get tool(%s) before target(%s) is loaded, maybe it is called on_load(), please call it in on_config().\", toolkind, self:fullname())\n    end\n    return toolchain.tool(self:toolchains(), toolkind, {cachekey = \"target_\" .. self:fullname(), plat = self:plat(), arch = self:arch(),\n                                                        before_get = function()\n        -- get program from set_toolset\n        local program = self:get(\"toolset.\" .. toolkind)\n\n        -- get program from `xmake f --cc`\n        if not program and not self:get(\"toolchains\") then\n            program = config.get(toolkind)\n        end\n\n        -- contain toolname? parse it, e.g. 'gcc@xxxx.exe'\n        -- https://github.com/xmake-io/xmake/issues/1361\n        local toolname\n        if program then\n            local pos = program:find('@', 1, true)\n            if pos then\n                -- we need to ignore valid path with `@`, e.g. /usr/local/opt/go@1.17/bin/go\n                -- https://github.com/xmake-io/xmake/issues/2853\n                local prefix = program:sub(1, pos - 1)\n                if prefix and not prefix:find(\"[/\\\\]\") then\n                    toolname = prefix\n                    program = program:sub(pos + 1)\n                end\n            end\n        end\n\n        -- find toolname\n        if program and not toolname then\n            local find_toolname = sandbox_module.import(\"lib.detect.find_toolname\", {anonymous = true})\n            toolname = find_toolname(program)\n        end\n        return program, toolname\n    end})\nend\n\n-- get tool configuration from the toolchains\nfunction _instance:toolconfig(name)\n    return toolchain.toolconfig(self:toolchains(), name, {cachekey = \"target_\" .. self:fullname(), plat = self:plat(), arch = self:arch(),\n                                                          after_get = function(toolchain_inst)\n        -- get flags from target.on_xxflags()\n        local script = toolchain_inst:get(\"target.on_\" .. name)\n        if type(script) == \"function\" then\n            local ok, result_or_errors = utils.trycall(script, nil, self)\n            if ok then\n                return result_or_errors\n            else\n                os.raise(result_or_errors)\n            end\n        end\n    end})\nend\n\n-- has source files with the given source kind?\nfunction _instance:has_sourcekind(...)\n    local sourcekinds_set = self._SOURCEKINDS_SET\n    if sourcekinds_set == nil then\n        sourcekinds_set = hashset.from(self:sourcekinds())\n        self._SOURCEKINDS_SET = sourcekinds_set\n    end\n    for _, v in ipairs(table.pack(...)) do\n        if sourcekinds_set:has(v) then\n            return true\n        end\n    end\nend\n\n-- has the given tool for the current target?\n--\n-- e.g.\n--\n-- if target:has_tool(\"cc\", \"clang\", \"gcc\") then\n--    ...\n-- end\nfunction _instance:has_tool(toolkind, ...)\n    local target_utils = target._target_utils\n    if target_utils == nil then\n        target_utils = sandbox_module.import(\"private.utils.target\", {anonymous = true})\n        target._target_utils = target_utils\n    end\n    local _, toolname = self:tool(toolkind)\n    return target_utils.has_tool(toolname, table.pack(...))\nend\n\n-- has the given c funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cfuncs(funcs, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_cfuncs\", {anonymous = true})(funcs, opt)\nend\n\n-- has the given c++ funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxfuncs(funcs, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_cxxfuncs\", {anonymous = true})(funcs, opt)\nend\n\n-- has the given c types?\n--\n-- @param types     the types\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_ctypes(types, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_ctypes\", {anonymous = true})(types, opt)\nend\n\n-- has the given c++ types?\n--\n-- @param types     the types\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxtypes(types, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_cxxtypes\", {anonymous = true})(types, opt)\nend\n\n-- has the given c includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cincludes(includes, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_cincludes\", {anonymous = true})(includes, opt)\nend\n\n-- has the given c++ includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options, e.g. {configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxincludes(includes, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.has_cxxincludes\", {anonymous = true})(includes, opt)\nend\n\n-- has the given c flags?\n--\n-- @param flags     the flags\n-- @param opt       the argument options, e.g. { flagskey = \"xxx\" }\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cflags(flags, opt)\n    local compinst = self:compiler(\"cc\")\n    return compinst:has_flags(flags, \"cflags\", opt)\nend\n\n-- has the given c++ flags?\n--\n-- @param flags     the flags\n-- @param opt       the argument options, e.g. { flagskey = \"xxx\" }\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_cxxflags(flags, opt)\n    local compinst = self:compiler(\"cxx\")\n    return compinst:has_flags(flags, \"cxxflags\", opt)\nend\n\n-- has the given features?\n--\n-- @param features  the features, e.g. {\"c_static_assert\", \"cxx_constexpr\"}\n-- @param opt       the argument options, e.g. {flags = \"\"}\n--\n-- @return          true or false, errors\n--\nfunction _instance:has_features(features, opt)\n    opt = opt or {}\n    opt.target = self:_checked_target()\n    return sandbox_module.import(\"core.tool.compiler\", {anonymous = true}).has_features(features, opt)\nend\n\n-- check the size of type\n--\n-- @param typename  the typename\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          the type size\n--\nfunction _instance:check_sizeof(typename, opt)\n    opt = opt or {}\n    opt.target = self:_checked_target()\n    return sandbox_module.import(\"lib.detect.check_sizeof\", {anonymous = true})(typename, opt)\nend\n\n-- check the endianness of compiler\n--\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          the type size\n--\nfunction _instance:check_bigendian(opt)\n  opt = opt or {}\n  opt.target = self:_checked_target()\n  return sandbox_module.import(\"lib.detect.check_bigendian\", {anonymous = true})(opt)\nend\n\n-- check the given c snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_csnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self:_checked_target()\n    return sandbox_module.import(\"lib.detect.check_csnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given c++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_cxxsnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self\n    return sandbox_module.import(\"lib.detect.check_cxxsnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given objc snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_msnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self:_checked_target()\n    return sandbox_module.import(\"lib.detect.check_msnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- check the given objc++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options, e.g. {includes = \"xxx.h\", configs = {defines = \"\"}}\n--\n-- @return          true or false, errors\n--\nfunction _instance:check_mxxsnippets(snippets, opt)\n    opt = opt or {}\n    opt.target = self:_checked_target()\n    return sandbox_module.import(\"lib.detect.check_mxxsnippets\", {anonymous = true})(snippets, opt)\nend\n\n-- get project\nfunction target._project()\n    return target._PROJECT\nend\n\n-- get target apis\nfunction target.apis()\n\n    return\n    {\n        values =\n        {\n            -- target.set_xxx\n            \"target.set_kind\"\n        ,   \"target.set_plat\"\n        ,   \"target.set_arch\"\n        ,   \"target.set_strip\"\n        ,   \"target.set_rules\"\n        ,   \"target.set_group\"\n        ,   \"target.add_filegroups\"\n        ,   \"target.set_version\"\n        ,   \"target.set_license\"\n        ,   \"target.set_enabled\"\n        ,   \"target.set_default\"\n        ,   \"target.set_options\"\n        ,   \"target.set_symbols\"\n        ,   \"target.set_filename\"\n        ,   \"target.set_basename\"\n        ,   \"target.set_extension\"\n        ,   \"target.set_prefixname\"\n        ,   \"target.set_suffixname\"\n        ,   \"target.set_warnings\"\n        ,   \"target.set_fpmodels\"\n        ,   \"target.set_optimize\"\n        ,   \"target.set_runtimes\"\n        ,   \"target.set_languages\"\n        ,   \"target.set_toolchains\"\n        ,   \"target.set_runargs\"\n        ,   \"target.set_exceptions\"\n        ,   \"target.set_encodings\"\n        ,   \"target.set_prefixdir\"\n            -- target.add_xxx\n        ,   \"target.add_deps\"\n        ,   \"target.add_rules\"\n        ,   \"target.add_options\"\n        ,   \"target.add_packages\"\n        ,   \"target.add_imports\"\n        ,   \"target.add_languages\"\n        ,   \"target.add_vectorexts\"\n        ,   \"target.add_toolchains\"\n        ,   \"target.add_tests\"\n        }\n    ,   keyvalues =\n        {\n            -- target.set_xxx\n            \"target.set_values\"\n        ,   \"target.set_configvar\"\n        ,   \"target.set_runenv\"\n        ,   \"target.set_toolset\"\n        ,   \"target.set_policy\"\n            -- target.add_xxx\n        ,   \"target.add_values\"\n        ,   \"target.add_runenvs\"\n        }\n    ,   paths =\n        {\n            -- target.set_xxx\n            \"target.set_targetdir\"\n        ,   \"target.set_objectdir\"\n        ,   \"target.set_dependir\"\n        ,   \"target.set_autogendir\"\n        ,   \"target.set_configdir\"\n        ,   \"target.set_installdir\"\n        ,   \"target.set_rundir\"\n            -- target.add_xxx\n        ,   \"target.add_files\"\n        ,   \"target.add_cleanfiles\"\n        ,   \"target.add_configfiles\"\n        ,   \"target.add_installfiles\"\n        ,   \"target.add_extrafiles\"\n            -- target.del_xxx (deprecated)\n        ,   \"target.del_files\"\n            -- target.remove_xxx\n        ,   \"target.remove_files\"\n        ,   \"target.remove_headerfiles\"\n        ,   \"target.remove_configfiles\"\n        ,   \"target.remove_installfiles\"\n        ,   \"target.remove_extrafiles\"\n        }\n    ,   script =\n        {\n            -- target.on_xxx\n            \"target.on_run\"\n        ,   \"target.on_test\"\n        ,   \"target.on_load\"\n        ,   \"target.on_config\"\n        ,   \"target.on_prepare\"\n        ,   \"target.on_prepare_file\"\n        ,   \"target.on_prepare_files\"\n        ,   \"target.on_link\"\n        ,   \"target.on_build\"\n        ,   \"target.on_build_file\"\n        ,   \"target.on_build_files\"\n        ,   \"target.on_clean\"\n        ,   \"target.on_package\"\n        ,   \"target.on_install\"\n        ,   \"target.on_uninstall\"\n        ,   \"target.on_preparecmd\"\n        ,   \"target.on_preparecmd_file\"\n        ,   \"target.on_preparecmd_files\"\n        ,   \"target.on_linkcmd\"\n        ,   \"target.on_buildcmd\"\n        ,   \"target.on_buildcmd_file\"\n        ,   \"target.on_buildcmd_files\"\n        ,   \"target.on_installcmd\"\n        ,   \"target.on_uninstallcmd\"\n            -- target.before_xxx\n        ,   \"target.before_run\"\n        ,   \"target.before_test\"\n        ,   \"target.before_config\"\n        ,   \"target.before_prepare\"\n        ,   \"target.before_prepare_file\"\n        ,   \"target.before_prepare_files\"\n        ,   \"target.before_link\"\n        ,   \"target.before_build\"\n        ,   \"target.before_build_file\"\n        ,   \"target.before_build_files\"\n        ,   \"target.before_clean\"\n        ,   \"target.before_package\"\n        ,   \"target.before_install\"\n        ,   \"target.before_uninstall\"\n        ,   \"target.before_preparecmd\"\n        ,   \"target.before_preparecmd_file\"\n        ,   \"target.before_preparecmd_files\"\n        ,   \"target.before_linkcmd\"\n        ,   \"target.before_buildcmd\"\n        ,   \"target.before_buildcmd_file\"\n        ,   \"target.before_buildcmd_files\"\n        ,   \"target.before_installcmd\"\n        ,   \"target.before_uninstallcmd\"\n            -- target.after_xxx\n        ,   \"target.after_run\"\n        ,   \"target.after_test\"\n        ,   \"target.after_load\"\n        ,   \"target.after_config\"\n        ,   \"target.after_prepare\"\n        ,   \"target.after_prepare_file\"\n        ,   \"target.after_prepare_files\"\n        ,   \"target.after_link\"\n        ,   \"target.after_build\"\n        ,   \"target.after_build_file\"\n        ,   \"target.after_build_files\"\n        ,   \"target.after_clean\"\n        ,   \"target.after_package\"\n        ,   \"target.after_install\"\n        ,   \"target.after_uninstall\"\n        ,   \"target.after_preparecmd\"\n        ,   \"target.after_preparecmd_file\"\n        ,   \"target.after_preparecmd_files\"\n        ,   \"target.after_linkcmd\"\n        ,   \"target.after_buildcmd\"\n        ,   \"target.after_buildcmd_file\"\n        ,   \"target.after_buildcmd_files\"\n        ,   \"target.after_installcmd\"\n        ,   \"target.after_uninstallcmd\"\n        }\n    }\nend\n\n-- get the filename from the given target name and kind\nfunction target.filename(targetname, targetkind, opt)\n    opt = opt or {}\n    assert(targetname and targetkind)\n\n    -- make filename by format\n    local filename = targetname\n    local format = opt.format or platform.format(targetkind, opt.plat, opt.arch) or \"$(name)\"\n    if format then\n        local splitinfo = format:split(\"$(name)\", {plain = true, strict = true})\n        local prefixname = splitinfo[1] or \"\"\n        local suffixname = \"\"\n        local extension = splitinfo[2] or \"\"\n        splitinfo = extension:split('.', {plain = true, limit = 2, strict = true})\n        if #splitinfo == 2 and splitinfo[1] ~= \"\" then\n            suffixname = splitinfo[1]\n            extension  = \".\" .. splitinfo[2]\n        end\n        if opt.prefixname then\n            prefixname = opt.prefixname\n        end\n        if opt.suffixname then\n            suffixname = opt.suffixname\n        end\n        if opt.extension then\n            extension = opt.extension\n        end\n        filename = prefixname .. targetname .. suffixname .. extension\n    end\n    return filename\nend\n\n-- get the link name of the target file\nfunction target.linkname(filename, opt)\n    -- for implib/mingw, e.g. libxxx.dll.a\n    opt = opt or {}\n    if filename:startswith(\"lib\") and filename:endswith(\".dll.a\") then\n        return filename:sub(4, #filename - 6)\n    end\n    -- for macOS, libxxx.tbd\n    if filename:startswith(\"lib\") and filename:endswith(\".tbd\") then\n        return filename:sub(4, #filename - 4)\n    end\n    local linkname, count = filename:gsub(target.filename(\"__pattern__\", \"static\", {plat = opt.plat}):gsub(\"%.\", \"%%.\"):gsub(\"__pattern__\", \"(.+)\") .. \"$\", \"%1\")\n    if count == 0 then\n        linkname, count = filename:gsub(target.filename(\"__pattern__\", \"shared\", {plat = opt.plat}):gsub(\"%.\", \"%%.\"):gsub(\"__pattern__\", \"(.+)\") .. \"$\", \"%1\")\n    end\n    -- in order to be compatible with mingw/windows library with .lib\n    if count == 0 and opt.plat == \"mingw\" then\n        linkname, count = filename:gsub(target.filename(\"__pattern__\", \"static\", {plat = \"windows\"}):gsub(\"%.\", \"%%.\"):gsub(\"__pattern__\", \"(.+)\") .. \"$\", \"%1\")\n    end\n    if count > 0 and linkname then\n        return linkname\n    end\n    -- fallback to the generic unix library name, libxxx.a, libxxx.so, ..\n    if filename:startswith(\"lib\") then\n        if filename:endswith(\".a\") or filename:endswith(\".so\") then\n            return path.basename(filename:sub(4))\n        end\n    elseif filename:endswith(\".so\") or filename:endswith(\".dylib\") then\n        -- for custom shared libraries name, xxx.so, xxx.dylib\n        return filename\n    end\n    return nil\nend\n\n-- new a target instance\nfunction target.new(...)\n    return _instance.new(...)\nend\n\n-- return module\nreturn target\n"
  },
  {
    "path": "xmake/core/sandbox/modules/assert.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        assert.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").assert\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/catch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        catch.lua\n--\n\n-- catch\nfunction sandbox_catch(block)\n\n    -- get the catch block function\n    return {catch = block[1]}\nend\n\n-- return module\nreturn sandbox_catch\n"
  },
  {
    "path": "xmake/core/sandbox/modules/coroutine.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        coroutine.lua\n--\n\n-- define module\nlocal sandbox_coroutine = sandbox_coroutine or {}\n\n-- load modules\nlocal option    = require(\"base/option\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_coroutine.create    = coroutine.create\nsandbox_coroutine.wrap      = coroutine.wrap\nsandbox_coroutine.yield     = coroutine.yield\nsandbox_coroutine.status    = coroutine.status\nsandbox_coroutine.running   = coroutine.running\n\n-- resume coroutine\nfunction sandbox_coroutine.resume(co, ...)\n    local ok, results = coroutine.resume(co, ...)\n    if not ok then\n\n        -- get errors\n        local errors = results\n        if option.get(\"diagnosis\") then\n            errors = debug.traceback(co, results)\n        elseif type(results) == \"string\" then\n            -- remove the prefix info\n            local _, pos = results:find(\":%d+: \")\n            if pos then\n                errors = results:sub(pos + 1)\n            end\n        end\n\n        -- raise it\n        raise(errors)\n    end\n    return results\nend\n\n-- load module\nreturn sandbox_coroutine\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/cprint.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cprint.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").cprint\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/cprintf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cprintf.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").cprintf\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/debug.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        debug.lua\n--\n\n-- load modules\nlocal table = require(\"base/table\")\n\n-- define module\nlocal sandbox_debug = sandbox_debug or table.join(debug)\n\nsandbox_debug.rawget         = rawget\nsandbox_debug.rawset         = rawset\nsandbox_debug.rawequal       = rawequal\nsandbox_debug.rawlen         = rawlen\nsandbox_debug.require        = require\nsandbox_debug.collectgarbage = collectgarbage\n\nfunction sandbox_debug.global(key)\n    if key == nil then\n        return _G\n    end\n    return _G[key]\nend\n\n-- return module\nreturn sandbox_debug\n"
  },
  {
    "path": "xmake/core/sandbox/modules/dprint.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dprint.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").dprint\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/dprintf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dprintf.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").dprintf\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/finally.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        finally.lua\n--\n\n-- finally\nfunction sandbox_finally(block)\n\n    -- get the finally block function\n    return {finally = block[1]}\nend\n\n-- return module\nreturn sandbox_finally\n"
  },
  {
    "path": "xmake/core/sandbox/modules/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- return module\nreturn function (name, opt)\n    local find_package = require(\"sandbox/modules/import/core/sandbox/module\").import(\"lib.detect.find_package\", {anonymous = true})\n    return find_package(name, opt)\nend\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/find_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_packages.lua\n--\n\n-- return module\nreturn function (...)\n\n    -- get find_package\n    local find_package = require(\"sandbox/modules/import/core/sandbox/module\").import(\"lib.detect.find_package\", {anonymous = true})\n\n    -- get packages and options\n    local pkgs = {...}\n    local opts = pkgs[#pkgs]\n    if type(opts) == \"table\" then\n        pkgs = table.slice(pkgs, 1, #pkgs - 1)\n    else\n        opts = {}\n    end\n\n    -- find all packages\n    local packages = {}\n    for _, pkgname in ipairs(pkgs) do\n        local pkg = find_package(pkgname, opts)\n        if pkg then\n            table.insert(packages, pkg)\n        end\n    end\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/format.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        format.lua\n--\n\n-- return module\nreturn require(\"sandbox/modules/string\").format\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/get_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        get_config.lua\n--\n\nlocal config  = require(\"project/config\")\nlocal sandbox = require(\"sandbox/sandbox\")\n\nreturn function (name)\n    local namespace\n    local instance = sandbox.instance()\n    if instance then\n        namespace = instance:namespace()\n    end\n    local value = config.get(name)\n    if value == nil and namespace then\n        value = config.get(namespace .. \"::\" .. name)\n    end\n    return value\nend\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/has_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_config.lua\n--\n\nlocal config  = require(\"project/config\")\nlocal sandbox = require(\"sandbox/sandbox\")\n\nreturn function (...)\n    local namespace\n    local instance = sandbox.instance()\n    if instance then\n        namespace = instance:namespace()\n    end\n    local names = table.pack(...)\n    for _, name in ipairs(names) do\n        local value = config.get(name)\n        if value == nil and namespace then\n            value = config.get(namespace .. \"::\" .. name)\n        end\n        if value then\n            return true\n        end\n    end\n    return false\nend\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/has_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_package.lua\n--\n\n-- return module\nreturn function (...)\n    require(\"sandbox/modules/import/core/sandbox/module\").import(\"core.project.project\")\n    local requires = project.required_packages()\n    if requires then\n        for _, packagename in ipairs(table.join(...)) do\n            local pkg = requires[packagename]\n            -- attempt to get package with namespace\n            if pkg == nil and packagename:find(\"::\", 1, true) then\n                local parts = packagename:split(\"::\", {plain = true})\n                local namespace_pkg = requires[parts[#parts]]\n                if namespace_pkg and namespace_pkg:namespace() then\n                    local fullname = namespace_pkg:fullname()\n                    if fullname:endswith(packagename) then\n                        pkg = namespace_pkg\n                    end\n                end\n            end\n            if pkg and pkg:enabled() then\n                return true\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/core/sandbox/modules/hash.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        hash.lua\n--\n\n-- load modules\nlocal hash  = require(\"base/hash\")\nlocal raise = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_hash = sandbox_hash or {}\n\n-- generate a new uuid\nfunction sandbox_hash.uuid(str)\n    local uuid = hash.uuid(str)\n    if not uuid then\n        raise(\"cannot generate uuid %s\", str)\n    end\n    return uuid\nend\n\n-- generate a new uuid v4\nfunction sandbox_hash.uuid4(str)\n    local uuid = hash.uuid4(str)\n    if not uuid then\n        raise(\"cannot generate uuid4 %s\", str)\n    end\n    return uuid\nend\n\n-- generate sha1 from the given file or data\nfunction sandbox_hash.sha1(file_or_data)\n    local sha1, errors = hash.sha1(file_or_data)\n    if not sha1 then\n        raise(\"cannot generate sha1, %s\", errors or \"unknown errors\")\n    end\n    return sha1\nend\n\n-- generate sha256 from the given file or data\nfunction sandbox_hash.sha256(file_or_data)\n    local sha256, errors = hash.sha256(file_or_data)\n    if not sha256 then\n        raise(\"cannot generate sha256, %s\", errors or \"unknown errors\")\n    end\n    return sha256\nend\n\n-- generate md5 from the given file or data\nfunction sandbox_hash.md5(file_or_data)\n    local md5, errors = hash.md5(file_or_data)\n    if not md5 then\n        raise(\"cannot generate md5, %s\", errors or \"unknown errors\")\n    end\n    return md5\nend\n\n-- generate xxhash32 from the given file or data\nfunction sandbox_hash.xxhash32(file_or_data)\n    local result, errors = hash.xxhash32(file_or_data)\n    if not result then\n        raise(\"cannot generate xxhash32, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate xxhash64 from the given file or data\nfunction sandbox_hash.xxhash64(file_or_data)\n    local result, errors = hash.xxhash64(file_or_data)\n    if not result then\n        raise(\"cannot generate xxhash64, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate xxhash128 from the given file or data\nfunction sandbox_hash.xxhash128(file_or_data)\n    local result, errors = hash.xxhash128(file_or_data)\n    if not result then\n        raise(\"cannot generate xxhash128, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate hash32 from string\nfunction sandbox_hash.strhash32(str)\n    local result, errors = hash.strhash32(str)\n    if not result then\n        raise(\"cannot generate hash32 for %s, %s\", str, errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate hash64 from string\nfunction sandbox_hash.strhash64(str)\n    local result, errors = hash.strhash64(str)\n    if not result then\n        raise(\"cannot generate hash32 for %s, %s\", str, errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate hash128 from string\nfunction sandbox_hash.strhash128(str)\n    local result, errors = hash.strhash128(str)\n    if not result then\n        raise(\"cannot generate hash128 for %s, %s\", str, errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate random32\nfunction sandbox_hash.rand32()\n    local result, errors = hash.rand32()\n    if not result then\n        raise(\"cannot generate random32, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate random64\nfunction sandbox_hash.rand64()\n    local result, errors = hash.rand64()\n    if not result then\n        raise(\"cannot generate random64, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- generate random128\nfunction sandbox_hash.rand128()\n    local result, errors = hash.rand128()\n    if not result then\n        raise(\"cannot generate random128, %s\", errors or \"unknown errors\")\n    end\n    return result\nend\n\n-- return module\nreturn sandbox_hash\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/base64.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        base64.lua\n--\n\n-- define module\nlocal sandbox_core_base_base64 = sandbox_core_base_base64 or {}\n\n-- load modules\nlocal base64    = require(\"base/base64\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- decode the base64 string to the data\nfunction sandbox_core_base_base64.decode(base64str, opt)\n    local data, errors = base64.decode(base64str, opt)\n    if not data and errors then\n        raise(errors)\n    end\n    return data\nend\n\n-- encode the data to the base64 string\nfunction sandbox_core_base_base64.encode(data, opt)\n    local base64str, errors = base64.encode(data, opt)\n    if not base64str and errors then\n        raise(errors)\n    end\n    return base64str\nend\n\n-- return module\nreturn sandbox_core_base_base64\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/binutils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        binutils.lua\n--\n\n-- define module\nlocal sandbox_core_base_binutils = sandbox_core_base_binutils or {}\n\n-- load modules\nlocal binutils = require(\"base/binutils\")\nlocal raise    = require(\"sandbox/modules/raise\")\n\n-- generate c/c++ code from the binary file\nfunction sandbox_core_base_binutils.bin2c(binaryfile, outputfile, opt)\n    local ok, errors = binutils.bin2c(binaryfile, outputfile, opt)\n    if not ok then\n        raise(\"bin2c: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- generate object file from the binary file\nfunction sandbox_core_base_binutils.bin2obj(binaryfile, outputfile, opt)\n    local ok, errors = binutils.bin2obj(binaryfile, outputfile, opt)\n    if not ok then\n        raise(\"bin2obj: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- get binary file format (auto-detect format: coff, elf, macho, ar, pe, unknown)\nfunction sandbox_core_base_binutils.format(binaryfile)\n    local format, errors = binutils.format(binaryfile)\n    if format then\n        return format\n    else\n        raise(\"format: %s\", errors or \"unknown errors\")\n    end\nend\n\n\n-- read symbols from object file (auto-detect format: ELF, COFF, Mach-O)\nfunction sandbox_core_base_binutils.readsyms(binaryfile)\n    local symbols, errors = binutils.readsyms(binaryfile)\n    if symbols then\n        return symbols\n    else\n        raise(\"readsyms: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- get dependent libraries from binary file (auto-detect format: ELF, COFF, Mach-O)\nfunction sandbox_core_base_binutils.deplibs(binaryfile)\n    local libs, errors = binutils.deplibs(binaryfile)\n    if libs then\n        return libs\n    else\n        raise(\"deplibs: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- get rpath list from binary file (auto-detect format: ELF or Mach-O)\nfunction sandbox_core_base_binutils.rpath_list(binaryfile)\n    local rpaths, errors = binutils.rpath_list(binaryfile)\n    if rpaths then\n        return rpaths\n    else\n        raise(\"rpath_list: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- clean rpaths from binary file (auto-detect format: ELF or Mach-O)\nfunction sandbox_core_base_binutils.rpath_clean(binaryfile)\n    local ok, errors = binutils.rpath_clean(binaryfile)\n    if not ok then\n        raise(\"rpath_clean: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- extract static library to directory\nfunction sandbox_core_base_binutils.extractlib(libraryfile, outputdir, opt)\n    local ok, errors = binutils.extractlib(libraryfile, outputdir, opt)\n    if not ok then\n        raise(\"extractlib: %s\", errors or \"unknown errors\")\n    end\nend\n\n-- return module\nreturn sandbox_core_base_binutils\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/bit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bit.lua\n--\n\n-- load modules\nreturn require(\"base/bit\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/bloom_filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bloom_filter.lua\n--\n\n-- load modules\nlocal utils        = require(\"base/utils\")\nlocal bloom_filter = require(\"base/bloom_filter\")\nlocal string       = require(\"base/string\")\nlocal raise        = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_core_base_bloom_filter            = sandbox_core_base_bloom_filter or {}\nlocal sandbox_core_base_bloom_filter_instance   = sandbox_core_base_bloom_filter_instance or {}\n\n-- wrap bloom_filter\nfunction _bloom_filter_wrap(filter)\n\n    -- hook bloom_filter interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_bloom_filter_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = filter[\"_\" .. name] or filter[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        filter[name] = func\n    end\n    return filter\nend\n\n-- get bloom filter data\nfunction sandbox_core_base_bloom_filter_instance.data(filter)\n    local data, errors = filter:_data()\n    if not data and errors then\n        raise(errors)\n    end\n    return data\nend\n\n-- set bloom filter data\nfunction sandbox_core_base_bloom_filter_instance.data_set(filter, data)\n    local ok, errors = filter:_data_set(data)\n    if not ok and errors then\n        raise(errors)\n    end\nend\n\n-- set bloom filter item\nfunction sandbox_core_base_bloom_filter_instance.set(filter, item)\n    local ok, result_or_errors = filter:_set(item)\n    if not ok then\n        raise(result_or_errors)\n    end\n    return result_or_errors\nend\n\n-- get bloom filter item\nfunction sandbox_core_base_bloom_filter_instance.get(filter, item)\n    local ok, result_or_errors = filter:_get(item)\n    if not ok then\n        raise(result_or_errors)\n    end\n    return result_or_errors\nend\n\n-- clear bloom filter data\nfunction sandbox_core_base_bloom_filter_instance.clear(filter)\n    local ok, errors = filter:_clear()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- close bloom filter\nfunction sandbox_core_base_bloom_filter_instance.close(filter)\n    local ok, errors = filter:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- new bloom filter\nfunction sandbox_core_base_bloom_filter.new(opt)\n    local filter, errors = bloom_filter.new(opt)\n    if not filter then\n        raise(errors)\n    end\n    return _bloom_filter_wrap(filter)\nend\n\n-- return module\nreturn sandbox_core_base_bloom_filter\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/bytes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bytes.lua\n--\n\n-- load modules\nreturn require(\"base/bytes\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/cli.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        cli.lua\n--\n\n-- load modules\nlocal cli = require(\"base/cli\")\n\n\n-- define module\nlocal sandbox_cli = sandbox_cli or {}\n\n-- inherit some builtin interfaces\nfor key, value in pairs(cli) do\n    if not key:startswith(\"_\") then\n        sandbox_cli[key] = value\n    end\nend\n\n-- return module\nreturn sandbox_cli\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/colors.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        colors.lua\n--\n\n-- return module\nreturn require(\"base/colors\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/cpu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cpu.lua\n--\n\n-- load modules\nreturn require(\"base/cpu\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/dlist.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dlist.lua\n--\n\n-- return module\nreturn require(\"base/list\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        filter.lua\n--\n\n-- define module\nlocal sandbox_core_base_filter = sandbox_core_base_filter or {}\n\n-- load modules\nlocal filter    = require(\"base/filter\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- new filter instance\nfunction sandbox_core_base_filter.new()\n    return filter.new()\nend\n\n-- return module\nreturn sandbox_core_base_filter\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/fwatcher.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fwatcher.lua\n--\n\n-- define module\nlocal sandbox_core_base_fwatcher = sandbox_core_base_fwatcher or {}\n\n-- load modules\nlocal fwatcher = require(\"base/fwatcher\")\nlocal raise    = require(\"sandbox/modules/raise\")\n\n-- the fwatcher event type\nsandbox_core_base_fwatcher.ET_MODIFY = fwatcher.ET_MODIFY\nsandbox_core_base_fwatcher.ET_CREATE = fwatcher.ET_CREATE\nsandbox_core_base_fwatcher.ET_DELETE = fwatcher.ET_DELETE\n\n-- add watch directory\nfunction sandbox_core_base_fwatcher.add(watchdir, opt)\n    local ok, errors = fwatcher.add(watchdir, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- remove watch directory\nfunction sandbox_core_base_fwatcher.remove(watchdir)\n    local ok, errors = fwatcher.remove(watchdir)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- wait event\nfunction sandbox_core_base_fwatcher.wait(timeout)\n    local ok, event_or_errors = fwatcher.wait(timeout)\n    if ok < 0 and event_or_errors then\n        raise(event_or_errors)\n    end\n    return ok, event_or_errors\nend\n\n-- watch watchdirs\nfunction sandbox_core_base_fwatcher.watchdirs(watchdirs, callback, opt)\n    local ok, errors = fwatcher.watchdirs(watchdirs, callback, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- watch created file path\nfunction sandbox_core_base_fwatcher.on_created(watchdirs, callback, opt)\n    local ok, errors = fwatcher.on_created(watchdirs, callback, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- watch modified file path\nfunction sandbox_core_base_fwatcher.on_modified(watchdirs, callback, opt)\n    local ok, errors = fwatcher.on_modified(watchdirs, callback, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- watch deleted file path\nfunction sandbox_core_base_fwatcher.on_deleted(watchdirs, callback, opt)\n    local ok, errors = fwatcher.on_deleted(watchdirs, callback, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- return module\nreturn sandbox_core_base_fwatcher\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/global.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        global.lua\n--\n\n-- define module\nlocal sandbox_core_base_global = sandbox_core_base_global or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal table     = require(\"base/table\")\nlocal global    = require(\"base/global\")\nlocal platform  = require(\"platform/platform\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- export some readonly interfaces\nsandbox_core_base_global.get       = global.get\nsandbox_core_base_global.set       = global.set\nsandbox_core_base_global.readonly  = global.readonly\nsandbox_core_base_global.dump      = global.dump\nsandbox_core_base_global.clear     = global.clear\nsandbox_core_base_global.options   = global.options\nsandbox_core_base_global.filepath  = global.filepath\nsandbox_core_base_global.directory = global.directory\nsandbox_core_base_global.cachedir  = global.cachedir\n\n-- save the configure\nfunction sandbox_core_base_global.save()\n    local ok, errors = global.save()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- return module\nreturn sandbox_core_base_global\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/graph.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        graph.lua\n--\n\n-- return module\nreturn require(\"base/graph\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/hashset.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        hashset.lua\n--\n\n-- load modules\nlocal hashset = require(\"base/hashset\")\n\n\n-- define module\nlocal sandbox_hashset = sandbox_hashset or {}\n\n-- inherit some builtin interfaces\nfor key, value in pairs(hashset) do\n    if not key:startswith(\"_\") then\n        sandbox_hashset[key] = value\n    end\nend\n\n-- return module\nreturn sandbox_hashset\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/heap.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        heap.lua\n--\n\n-- return module\nreturn require(\"base/heap\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/interpreter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        interpreter.lua\n--\n\n-- load modules\nlocal interpreter = require(\"base/interpreter\")\n\n-- define module\nlocal sandbox_core_base_interpreter = sandbox_core_base_interpreter or {}\n\n-- inherit some builtin interfaces\nsandbox_core_base_interpreter.instance        = interpreter.instance\nsandbox_core_base_interpreter.builtin_modules = interpreter.builtin_modules\n\n-- return module\nreturn sandbox_core_base_interpreter\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/json.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        json.lua\n--\n\n-- define module\nlocal sandbox_core_base_json = sandbox_core_base_json or {}\n\n-- load modules\nlocal json      = require(\"base/json\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_base_json.null               = json.null\nsandbox_core_base_json.purenull           = json.purenull\nsandbox_core_base_json.mark_as_array      = json.mark_as_array\nsandbox_core_base_json.is_marked_as_array = json.is_marked_as_array\n\n-- decode the json string to the lua table\nfunction sandbox_core_base_json.decode(jsonstr, opt)\n    local luatable, errors = json.decode(jsonstr, opt)\n    if not luatable then\n        raise(errors)\n    end\n    return luatable\nend\n\n-- encode the lua table to the json string\nfunction sandbox_core_base_json.encode(luatable, opt)\n    local jsonstr, errors = json.encode(luatable, opt)\n    if not jsonstr then\n        raise(errors)\n    end\n    return jsonstr\nend\n\n-- load json file to the lua table\nfunction sandbox_core_base_json.loadfile(filepath, opt)\n    local luatable, errors = json.loadfile(filepath, opt)\n    if not luatable then\n        raise(errors)\n    end\n    return luatable\nend\n\n-- save lua table to the json file\nfunction sandbox_core_base_json.savefile(filepath, luatable, opt)\n    local ok, errors = json.savefile(filepath, luatable, opt)\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- return module\nreturn sandbox_core_base_json\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/libc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        libc.lua\n--\n\n-- load modules\nreturn require(\"base/libc\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/list.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        list.lua\n--\n\n-- return module\nreturn require(\"base/list\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/memory.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        memory.lua\n--\n\n-- load modules\nreturn require(\"base/memory\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/object.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        object.lua\n--\n\n-- return module\nreturn require(\"base/object\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/option.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        option.lua\n--\n\n-- load modules\nlocal table  = require(\"base/table\")\nlocal option = require(\"base/option\")\nlocal raise  = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_core_base_option = sandbox_core_base_option or {}\n\n-- inherit some builtin interfaces\nsandbox_core_base_option.get      = option.get\nsandbox_core_base_option.set      = option.set\nsandbox_core_base_option.default  = option.default\nsandbox_core_base_option.save     = option.save\nsandbox_core_base_option.restore  = option.restore\nsandbox_core_base_option.boolean  = option.boolean\nsandbox_core_base_option.taskname = option.taskname\nsandbox_core_base_option.taskmenu = option.taskmenu\n\n-- get the options\nfunction sandbox_core_base_option.options()\n    return assert(option.options())\nend\n\n-- get the defaults\nfunction sandbox_core_base_option.defaults()\n    return option.defaults() or {}\nend\n\n-- show logo\nfunction sandbox_core_base_option.show_logo(logo, opt)\n    option.show_logo(logo, opt)\nend\n\n-- show options\nfunction sandbox_core_base_option.show_options(options, taskname)\n    option.show_options(options, taskname)\nend\n\n-- parse arguments with the given options\nfunction sandbox_core_base_option.raw_parse(argv, options, opt)\n    assert(argv and options)\n\n    -- parse it\n    local results, errors = option.parse(argv, options, opt)\n    if not results then\n        raise(errors)\n    end\n    return results\nend\n\n-- parse arguments with the given options\nfunction sandbox_core_base_option.parse(argv, options, ...)\n    assert(argv and options)\n\n    -- add common options\n    table.insert(options, 1, {})\n    table.insert(options, 2, {'h', \"help\",      \"k\",  nil, \"Print this help message and exit.\" })\n    table.insert(options, 3, {})\n\n    -- show help\n    local descriptions = {...}\n    local function show_help()\n        for _, description in ipairs(descriptions) do\n            print(description)\n        end\n        option.show_options(options)\n    end\n\n    -- parse it\n    local results, errors = option.parse(argv, options)\n    if not results then\n        show_help()\n        raise(errors)\n    end\n\n    -- help?\n    if results.help then\n        show_help()\n        os.exit()\n    else\n        results.help = show_help\n    end\n    return results\nend\n\n-- return module\nreturn sandbox_core_base_option\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/pipe.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pipe.lua\n--\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal pipe      = require(\"base/pipe\")\nlocal string    = require(\"base/string\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_core_base_pipe            = sandbox_core_base_pipe or {}\nlocal sandbox_core_base_pipe_instance   = sandbox_core_base_pipe_instance or {}\n\n-- export the pipe events\nsandbox_core_base_pipe.EV_READ  = pipe.EV_READ\nsandbox_core_base_pipe.EV_WRITE = pipe.EV_WRITE\nsandbox_core_base_pipe.EV_CONN  = pipe.EV_CONN\n\n-- wrap pipe file\nfunction _pipefile_wrap(pipefile)\n\n    -- hook pipe interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_pipe_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = pipefile[\"_\" .. name] or pipefile[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        pipefile[name] = func\n    end\n    return pipefile\nend\n\n-- wait pipe events\nfunction sandbox_core_base_pipe_instance.wait(pipefile, events, timeout)\n    local events, errors = pipefile:_wait(events, timeout)\n    if events < 0 and errors then\n        raise(errors)\n    end\n    return events\nend\n\n-- connect pipe, only for named pipe (server-side)\nfunction sandbox_core_base_pipe_instance.connect(pipefile, opt)\n    local ok, errors = pipefile:_connect(opt)\n    if ok < 0 and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- write data to pipe file\nfunction sandbox_core_base_pipe_instance.write(pipefile, data, opt)\n    local real, errors = pipefile:_write(data, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- read data from pipe file\nfunction sandbox_core_base_pipe_instance.read(pipefile, buff, size, opt)\n    local real, data_or_errors = pipefile:_read(buff, size, opt)\n    if real < 0 and data_or_errors then\n        raise(data_or_errors)\n    end\n    return real, data_or_errors\nend\n\n-- close pipe file\nfunction sandbox_core_base_pipe_instance.close(pipefile)\n    local ok, errors = pipefile:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- open a named pipe file\nfunction sandbox_core_base_pipe.open(name, mode, buffsize)\n    local pipefile, errors = pipe.open(name, mode, buffsize)\n    if not pipefile then\n        raise(errors)\n    end\n    return _pipefile_wrap(pipefile)\nend\n\n-- open a anonymous pipe pair\nfunction sandbox_core_base_pipe.openpair(mode, buffsize)\n    local rpipefile, wpipefile, errors = pipe.openpair(mode, buffsize)\n    if not rpipefile or not wpipefile then\n        raise(errors)\n    end\n    return _pipefile_wrap(rpipefile), _pipefile_wrap(wpipefile)\nend\n\n-- return module\nreturn sandbox_core_base_pipe\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/privilege.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      TitanSnow\n-- @file        privilege.lua\n--\n\n-- return module\nreturn require(\"base/privilege\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/process.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        process.lua\n--\n\n-- load modules\nlocal process   = require(\"base/process\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal raise     = require(\"sandbox/modules/raise\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\n\n-- define module\nlocal sandbox_core_base_process       = sandbox_core_base_process or {}\nlocal sandbox_core_base_instance      = sandbox_core_base_instance or {}\nsandbox_core_base_process._subprocess = sandbox_core_base_process._subprocess or process._subprocess\n\n-- wait subprocess\nfunction sandbox_core_base_instance.wait(proc, timeout)\n    local ok, status_or_errors = proc:_wait(timeout)\n    if ok < 0 and status_or_errors then\n        raise(status_or_errors)\n    end\n    return ok, status_or_errors\nend\n\n-- kill subprocess\nfunction sandbox_core_base_instance.kill(proc)\n    local ok, errors = proc:_kill()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- close subprocess\nfunction sandbox_core_base_instance.close(proc)\n    local ok, errors = proc:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- open process\n---\n-- @param command   the command\n-- @param opt       the arguments option, {outpath = \"\", errpath = \"\", envs = {\"PATH=xxx\", \"XXX=yyy\"}\n--\nfunction sandbox_core_base_process.open(command, opt)\n\n    -- check\n    assert(command)\n\n    -- format command first\n    command = vformat(command)\n\n    -- open process\n    local proc, errors = process.open(command, opt)\n    if not proc then\n        raise(errors)\n    end\n\n    -- hook subprocess interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = proc[\"_\" .. name] or proc[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        proc[name] = func\n    end\n    return proc\nend\n\n-- open process with arguments\n--\n-- @param filename  the command/file name\n-- @param argv      the command arguments\n-- @param opt       the arguments option, {outpath = \"\", errpath = \"\", envs = {\"PATH=xxx\", \"XXX=yyy\"}\n--\nfunction sandbox_core_base_process.openv(filename, argv, opt)\n\n    -- check\n    assert(argv)\n\n    -- format filename first\n    filename = vformat(filename)\n\n    -- open process\n    local proc, errors = process.openv(filename, argv, opt)\n    if not proc then\n        raise(errors)\n    end\n\n    -- hook subprocess interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = proc[\"_\" .. name] or proc[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        proc[name] = func\n    end\n    return proc\nend\n\n-- return module\nreturn sandbox_core_base_process\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/profiler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        profiler.lua\n--\n\n-- define module\nlocal sandbox_core_base_profiler = sandbox_core_base_profiler or {}\n\n-- load modules\nlocal profiler = require(\"base/profiler\")\nlocal raise    = require(\"sandbox/modules/raise\")\n\n-- enter tag\nfunction sandbox_core_base_profiler.enter(name, ...)\n    profiler:enter(name, ...)\nend\n\n-- leave tag\nfunction sandbox_core_base_profiler.leave(name, ...)\n    profiler:leave(name, ...)\nend\n\n-- return module\nreturn sandbox_core_base_profiler\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/queue.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        queue.lua\n--\n\n-- return module\nreturn require(\"base/queue\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/scheduler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scheduler.lua\n--\n\n-- define module\nlocal sandbox_core_base_scheduler = sandbox_core_base_scheduler or {}\nlocal sandbox_core_base_scheduler_semaphore = sandbox_core_base_scheduler_semaphore or {}\n\n-- load modules\nlocal poller    = require(\"base/poller\")\nlocal scheduler = require(\"base/scheduler\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- the poller object type\nsandbox_core_base_scheduler.OT_SOCK = poller.OT_SOCK\nsandbox_core_base_scheduler.OT_PIPE = poller.OT_PIPE\nsandbox_core_base_scheduler.OT_PROC = poller.OT_PROC\n\n-- wrap semaphore\nfunction _semaphore_wrap(semaphore)\n\n    -- hook semaphore interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_scheduler_semaphore) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = semaphore[\"_\" .. name] or semaphore[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        semaphore[name] = func\n    end\n    return semaphore\nend\n\n-- post semaphore\nfunction sandbox_core_base_scheduler_semaphore.post(semaphore, value)\n    local result, errors = semaphore:_post(value)\n    if result < 0 and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- wait semaphore\nfunction sandbox_core_base_scheduler_semaphore.wait(semaphore, timeout)\n    local ok, errors = semaphore:_wait(timeout)\n    if ok < 0 and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- start a new coroutine task\nfunction sandbox_core_base_scheduler.co_start(cotask, ...)\n    local co, errors = scheduler:co_start(cotask, ...)\n    if not co then\n        raise(errors)\n    end\n    return co\nend\n\n-- start a new named coroutine task\nfunction sandbox_core_base_scheduler.co_start_named(coname, cotask, ...)\n    local co, errors = scheduler:co_start_named(coname, cotask, ...)\n    if not co then\n        raise(errors)\n    end\n    return co\nend\n\n-- start a new coroutine task with options\nfunction sandbox_core_base_scheduler.co_start_withopt(opt, cotask, ...)\n    local co, errors = scheduler:co_start_withopt(opt, cotask, ...)\n    if not co then\n        raise(errors)\n    end\n    return co\nend\n\n-- resume the given coroutine\nfunction sandbox_core_base_scheduler.co_resume(co, ...)\n    return scheduler:resume(co:thread(), ...)\nend\n\n-- suspend the current coroutine\nfunction sandbox_core_base_scheduler.co_suspend(...)\n    return scheduler:co_suspend(...)\nend\n\n-- yield the current coroutine\nfunction sandbox_core_base_scheduler.co_yield()\n    local ok, errors = scheduler:co_yield()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- sleep some times (ms)\nfunction sandbox_core_base_scheduler.co_sleep(ms)\n    local ok, errors = scheduler:co_sleep(ms)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- lock the current coroutine\nfunction sandbox_core_base_scheduler.co_lock(lockname)\n    local ok, errors = scheduler:co_lock(lockname)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- unlock the current coroutine\nfunction sandbox_core_base_scheduler.co_unlock(lockname)\n    local ok, errors = scheduler:co_unlock(lockname)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get coroutine group with the given name\nfunction sandbox_core_base_scheduler.co_group(name)\n    return scheduler:co_group(name)\nend\n\n-- begin coroutine group with the given name\nfunction sandbox_core_base_scheduler.co_group_begin(name, scopefunc)\n    local ok, errors = scheduler:co_group_begin(name, scopefunc)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- wait for finishing the given coroutine group\nfunction sandbox_core_base_scheduler.co_group_wait(name, opt)\n    local ok, errors = scheduler:co_group_wait(name, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get the waiting poller objects of the given coroutine group\nfunction sandbox_core_base_scheduler.co_group_waitobjs(name)\n    return scheduler:co_group_waitobjs(name)\nend\n\n-- get the current running coroutine\nfunction sandbox_core_base_scheduler.co_running()\n    return scheduler:co_running()\nend\n\n-- get the all coroutine task count\nfunction sandbox_core_base_scheduler.co_count()\n    return scheduler:co_count()\nend\n\n-- new a coroutine semaphore\nfunction sandbox_core_base_scheduler.co_semaphore(name, value)\n    local semaphore = scheduler:co_semaphore(name, value)\n    return _semaphore_wrap(semaphore)\nend\n\n-- return module\nreturn sandbox_core_base_scheduler\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/semver.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        semver.lua\n--\n\n-- define module\nlocal sandbox_core_base_semver = sandbox_core_base_semver or {}\n\n-- load modules\nlocal table  = require(\"base/table\")\nlocal semver = require(\"base/semver\")\nlocal raise  = require(\"sandbox/modules/raise\")\n\n-- new a version instance\nfunction sandbox_core_base_semver.new(version)\n    local result, errors = semver.new(version)\n    if errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- try parsing the given version string to semver instance\nfunction sandbox_core_base_semver.try_parse(version)\n    return semver.new(version)\nend\n\n-- match a valid version from the string\n--\n-- semver.match('xxx 1.2.3 xxx') => { major = 1, minor = 2, patch = 3, ... }\n-- semver.match('a.b.c') => nil\n--\nfunction sandbox_core_base_semver.match(str, pos, pattern)\n    return semver.match(str, pos, pattern)\nend\n\n-- is valid version?\nfunction sandbox_core_base_semver.is_valid(version)\n    return semver.parse(version) ~= nil\nend\n\n-- is valid version range?\nfunction sandbox_core_base_semver.is_valid_range(range)\n    local ok = semver.satisfies(\"1.0\", range)\n    return ok ~= nil\nend\n\n-- compare two version strings\n--\n-- semver.compare('1.2.3', '1.3.0') > 0?\n--\nfunction sandbox_core_base_semver.compare(version1, version2)\n    local result, errors = semver.compare(version1, version2)\n    if errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- this version satisfies in the given version range\n--\n-- semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true\n--\nfunction sandbox_core_base_semver.satisfies(version, range)\n    local result, errors = semver.satisfies(version, range)\n    if errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- select required version from versions, tags and branches\n--\n-- e.g.\n--\n-- local version, source = semver.select(\">=1.5.0 <1.6\", {\"1.5.0\", \"1.5.1\"}, {\"v1.5.0\", ..}, {\"master\", \"dev\"})\n--\n-- @version     the selected version number\n-- @source      the version source, e.g. version, tag, branch\n--\nfunction sandbox_core_base_semver.select(range, versions, tags, branches)\n    local verinfo, errors = semver.select(range, table.wrap(versions), table.wrap(tags), table.wrap(branches))\n    if not verinfo then\n        raise(errors)\n    end\n    return verinfo.version, verinfo.source\nend\n\n-- return module\nreturn sandbox_core_base_semver\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/signal.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        signal.lua\n--\n\n-- load modules\nreturn require(\"base/signal\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/singleton.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        singleton.lua\n--\n\n-- return module\nreturn require(\"base/singleton\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/socket.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        socket.lua\n--\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal socket    = require(\"base/socket\")\nlocal string    = require(\"base/string\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_core_base_socket            = sandbox_core_base_socket or {}\nlocal sandbox_core_base_socket_instance   = sandbox_core_base_socket_instance or {}\n\n-- export the socket types\nsandbox_core_base_socket.TCP     = socket.TCP\nsandbox_core_base_socket.UDP     = socket.UDP\nsandbox_core_base_socket.ICMP    = socket.ICMP\n\n-- export the socket families\nsandbox_core_base_socket.IPV4    = socket.IPV4\nsandbox_core_base_socket.IPV6    = socket.IPV6\n\n-- export the socket events\nsandbox_core_base_socket.EV_RECV = socket.EV_RECV\nsandbox_core_base_socket.EV_SEND = socket.EV_SEND\nsandbox_core_base_socket.EV_CONN = socket.EV_CONN\nsandbox_core_base_socket.EV_ACPT = socket.EV_ACPT\n\n-- export the socket control code\nsandbox_core_base_socket.CTRL_SET_RECVBUFF = socket.CTRL_SET_RECVBUFF\nsandbox_core_base_socket.CTRL_SET_SENDBUFF = socket.CTRL_SET_SENDBUFF\n\n-- wrap socket\nfunction _socket_wrap(sock)\n\n    -- hook socket interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_socket_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = sock[\"_\" .. name] or sock[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        sock[name] = func\n    end\n    return sock\nend\n\n-- wait socket events\nfunction sandbox_core_base_socket_instance.wait(sock, events, timeout)\n    local events, errors = sock:_wait(events, timeout)\n    if events < 0 and errors then\n        raise(errors)\n    end\n    return events\nend\n\n-- control socket\nfunction sandbox_core_base_socket_instance.ctrl(sock, code, value)\n    local ok, errors = sock:_ctrl(code, value)\n    if not ok and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- get peer address\nfunction sandbox_core_base_socket_instance.peeraddr(sock)\n    local result, errors = sock:_peeraddr(data, opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- bind socket\nfunction sandbox_core_base_socket_instance.bind(sock, addr, port)\n    local ok, errors = sock:_bind(addr, port)\n    if not ok and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- listen socket\nfunction sandbox_core_base_socket_instance.listen(sock, backlog)\n    local ok, errors = sock:_listen(backlog)\n    if not ok and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- accept socket\nfunction sandbox_core_base_socket_instance.accept(sock, opt)\n    local client_sock, errors = sock:_accept(opt)\n    if not client_sock and errors then\n        raise(errors)\n    end\n    return client_sock and _socket_wrap(client_sock) or nil\nend\n\n-- connect socket\nfunction sandbox_core_base_socket_instance.connect(sock, addr, port, opt)\n    local ok, errors = sock:_connect(addr, port, opt)\n    if ok < 0 and errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- send data to socket\nfunction sandbox_core_base_socket_instance.send(sock, data, opt)\n    local real, errors = sock:_send(data, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- send file to socket\nfunction sandbox_core_base_socket_instance.sendfile(sock, file, opt)\n    local real, errors = sock:_sendfile(file, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- recv data from socket\nfunction sandbox_core_base_socket_instance.recv(sock, buff, size, opt)\n    local real, data_or_errors = sock:_recv(buff, size, opt)\n    if real < 0 and data_or_errors then\n        raise(data_or_errors)\n    end\n    return real, data_or_errors\nend\n\n-- send udp data to peer\nfunction sandbox_core_base_socket_instance.sendto(sock, data, addr, port, opt)\n    local real, errors = sock:_sendto(data, addr, port, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- recv udp data from peer\nfunction sandbox_core_base_socket_instance.recvfrom(sock, buff, size, opt)\n    local real, data_or_errors, addr, port = sock:_recvfrom(buff, size, opt)\n    if real < 0 and data_or_errors then\n        raise(data_or_errors)\n    end\n    return real, data_or_errors, addr, port\nend\n\n-- get socket rawfd\nfunction sandbox_core_base_socket_instance.rawfd(sock)\n    local result, errors = sock:_rawfd()\n    if not result then\n        raise(errors)\n    end\n    return result\nend\n\n-- close socket\nfunction sandbox_core_base_socket_instance.close(sock)\n    local ok, errors = sock:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- open socket\nfunction sandbox_core_base_socket.open(socktype, family)\n    local sock, errors = socket.open(socktype, family)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open tcp socket\nfunction sandbox_core_base_socket.tcp(opt)\n    local sock, errors = socket.tcp(opt)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open udp socket\nfunction sandbox_core_base_socket.udp(opt)\n    local sock, errors = socket.udp(opt)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open unix socket\nfunction sandbox_core_base_socket.unix(opt)\n    local sock, errors = socket.unix(opt)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open and bind tcp socket\nfunction sandbox_core_base_socket.bind(addr, port, opt)\n    local sock, errors = socket.bind(addr, port, opt)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open and bind tcp socket from the unix socket\nfunction sandbox_core_base_socket.bind_unix(addr, opt)\n    local sock, errors = socket.bind_unix(addr, opt)\n    if not sock then\n        raise(errors)\n    end\n    return _socket_wrap(sock)\nend\n\n-- open and connect tcp socket\nfunction sandbox_core_base_socket.connect(addr, port, opt)\n    local sock, errors = socket.connect(addr, port, opt)\n    if not sock and errors then\n        raise(errors)\n    end\n    return sock and _socket_wrap(sock) or nil\nend\n\n-- open and connect tcp socket from the unix socket\nfunction sandbox_core_base_socket.connect_unix(addr, opt)\n    local sock, errors = socket.connect_unix(addr, opt)\n    if not sock and errors then\n        raise(errors)\n    end\n    return sock and _socket_wrap(sock) or nil\nend\n\n-- return module\nreturn sandbox_core_base_socket\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/task.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        task.lua\n--\n\n-- define module\nlocal sandbox_core_base_task = sandbox_core_base_task or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal io        = require(\"base/io\")\nlocal table     = require(\"base/table\")\nlocal option    = require(\"base/option\")\nlocal string    = require(\"base/string\")\nlocal task      = require(\"base/task\")\nlocal project   = require(\"project/project\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- run the given task\nfunction sandbox_core_base_task.run(taskname, options, ...)\n\n    -- init options\n    options = table.wrap(options)\n\n    -- inherit some parent options\n    for _, name in ipairs({\"file\", \"project\", \"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\", \"root\"}) do\n        if options[name] == nil and option.get(name) ~= nil then\n            options[name] = option.get(name)\n        end\n    end\n\n    -- save the current option and push a new option context\n    option.save(taskname)\n\n    -- init the new options\n    for name, value in pairs(options) do\n        option.set(name, value)\n    end\n\n    -- get task instance\n    local taskname = option.taskname() or \"build\"\n    local taskinst = task.task(taskname) or project.task(taskname)\n    if not taskinst then\n        raise(\"do unknown task(%s)!\", taskname)\n    end\n\n    -- run the task\n    local ok, errors = taskinst:run(...)\n    if not ok then\n        raise(errors)\n    end\n\n    -- restore the previous option context\n    option.restore()\nend\n\n\nfunction sandbox_core_base_task.names()\n    local default_tasks = table.keys(task.tasks())\n    local project_tasks = table.keys(project.tasks())\n    return table.join(default_tasks, project_tasks)\nend\n\n-- return module\nreturn sandbox_core_base_task\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/text.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        text.lua\n--\n\n-- load modules\nlocal text = require(\"base/text\")\n\n\n-- define module\nlocal sandbox_text = sandbox_text or {}\n\n-- inherit some builtin interfaces\nfor key, value in pairs(text) do\n    if not key:startswith(\"_\") then\n        sandbox_text[key] = value\n    end\nend\n\n-- return module\nreturn sandbox_text\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/thread.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        thread.lua\n--\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal thread    = require(\"base/thread\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_core_base_thread           = sandbox_core_base_thread or {}\nlocal sandbox_core_base_thread_instance  = sandbox_core_base_thread_instance or {}\nlocal sandbox_core_base_thread_mutex     = sandbox_core_base_thread_mutex or {}\nlocal sandbox_core_base_thread_event     = sandbox_core_base_thread_event or {}\nlocal sandbox_core_base_thread_semaphore = sandbox_core_base_thread_semaphore or {}\nlocal sandbox_core_base_thread_queue     = sandbox_core_base_thread_queue or {}\nlocal sandbox_core_base_thread_sharedata = sandbox_core_base_thread_sharedata or {}\n\n-- export the thread status\nsandbox_core_base_thread.STATUS_READY     = thread.STATUS_READY\nsandbox_core_base_thread.STATUS_RUNNING   = thread.STATUS_RUNNING\nsandbox_core_base_thread.STATUS_SUSPENDED = thread.STATUS_SUSPENDED\nsandbox_core_base_thread.STATUS_DEAD      = thread.STATUS_DEAD\n\n-- wrap thread\nfunction _thread_wrap(instance)\n\n    -- hook thread interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_instance) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = instance[\"_\" .. name] or instance[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        instance[name] = func\n    end\n    return instance\nend\n\n-- start thread\nfunction sandbox_core_base_thread_instance.start(instance)\n    local ok, errors = instance:_start()\n    if not ok then\n        raise(errors)\n    end\n    return instance\nend\n\n-- suspend thread\nfunction sandbox_core_base_thread_instance.suspend(instance)\n    local ok, errors = instance:_suspend()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- resume thread\nfunction sandbox_core_base_thread_instance.resume(instance)\n    local ok, errors = instance:_resume()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- wait thread\nfunction sandbox_core_base_thread_instance.wait(instance, timeout)\n    local ok, errors = instance:_wait(timeout)\n    if ok < 0 then\n        raise(errors)\n    end\nend\n\n-- lock mutex\nfunction sandbox_core_base_thread_mutex.lock(mutex)\n    local ok, errors = mutex:_lock()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- unlock mutex\nfunction sandbox_core_base_thread_mutex.unlock(mutex)\n    local ok, errors = mutex:_unlock()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- close mutex\nfunction sandbox_core_base_thread_mutex.close(mutex)\n    local ok, errors = mutex:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- post event\nfunction sandbox_core_base_thread_event.post(event)\n    local ok, errors = event:_post()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- wait event\nfunction sandbox_core_base_thread_event.wait(event, timeout)\n    local ok, errors = event:_wait(timeout)\n    if ok < 0 then\n        raise(errors)\n    end\n    return ok\nend\n\n-- close event\nfunction sandbox_core_base_thread_event.close(event)\n    local ok, errors = event:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- post semaphore\nfunction sandbox_core_base_thread_semaphore.post(semaphore, value)\n    local ok, errors = semaphore:_post(value)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- wait semaphore\nfunction sandbox_core_base_thread_semaphore.wait(semaphore, timeout)\n    local ok, errors = semaphore:_wait(timeout)\n    if ok < 0 then\n        raise(errors)\n    end\n    return ok\nend\n\n-- close semaphore\nfunction sandbox_core_base_thread_semaphore.close(semaphore)\n    local ok, errors = semaphore:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get queue size\nfunction sandbox_core_base_thread_queue.size(queue)\n    local size, errors = queue:_size()\n    if not size then\n        raise(errors)\n    end\n    return size\nend\n\n-- is empty queue?\nfunction sandbox_core_base_thread_queue.empty(queue)\n    local ok, errors = queue:_empty()\n    if ok == nil then\n        raise(errors)\n    end\n    return ok\nend\n\n-- clear queue\nfunction sandbox_core_base_thread_queue.clear(queue)\n    local ok, errors = queue:_clear()\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- push queue item\nfunction sandbox_core_base_thread_queue.push(queue, value)\n    local ok, errors = queue:_push(value)\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- pop queue item\nfunction sandbox_core_base_thread_queue.pop(queue)\n    local value, errors = queue:_pop()\n    if value == nil and errors then\n        raise(errors)\n    end\n    return value\nend\n\n-- close queue\nfunction sandbox_core_base_thread_queue.close(queue)\n    local ok, errors = queue:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- clear sharedata\nfunction sandbox_core_base_thread_sharedata.clear(sharedata)\n    local ok, errors = sharedata:_clear()\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- set sharedata\nfunction sandbox_core_base_thread_sharedata.set(sharedata, value)\n    local ok, errors = sharedata:_set(value)\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- get sharedata\nfunction sandbox_core_base_thread_sharedata.get(sharedata)\n    local value, errors = sharedata:_get()\n    if value == nil and errors then\n        raise(errors)\n    end\n    return value\nend\n\n-- close sharedata\nfunction sandbox_core_base_thread_sharedata.close(sharedata)\n    local ok, errors = sharedata:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- new thread\nfunction sandbox_core_base_thread.new(callback, opt)\n    local instance, errors = thread.new(callback, opt)\n    if not instance then\n        raise(errors)\n    end\n    return _thread_wrap(instance)\nend\n\n-- start a thread\nfunction sandbox_core_base_thread.start(callback, ...)\n    return sandbox_core_base_thread.start_withopt(callback, {argv = table.pack(...)})\nend\n\n-- start a named thread\nfunction sandbox_core_base_thread.start_named(name, callback, ...)\n    return sandbox_core_base_thread.start_withopt(callback, {name = name, argv = table.pack(...)})\nend\n\n-- start a thread with options\nfunction sandbox_core_base_thread.start_withopt(callback, opt)\n    return sandbox_core_base_thread.new(callback, opt):start()\nend\n\n-- get the running thread\nfunction sandbox_core_base_thread.running()\n    local instance, errors = thread.running()\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- open a mutex\nfunction sandbox_core_base_thread.mutex(name)\n    local mutex, errors = thread.mutex(name)\n    if not mutex then\n        raise(errors)\n    end\n\n    -- hook filemutex interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_mutex) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = mutex[\"_\" .. name] or mutex[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        mutex[name] = func\n    end\n    return mutex\nend\n\n-- open a event\nfunction sandbox_core_base_thread.event(name)\n    local event, errors = thread.event(name)\n    if not event then\n        raise(errors)\n    end\n\n    -- hook fileevent interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_event) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = event[\"_\" .. name] or event[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        event[name] = func\n    end\n    return event\nend\n\n-- open a semaphore\nfunction sandbox_core_base_thread.semaphore(name, value)\n    local semaphore, errors = thread.semaphore(name, value)\n    if not semaphore then\n        raise(errors)\n    end\n\n    -- hook filesemaphore interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_semaphore) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = semaphore[\"_\" .. name] or semaphore[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        semaphore[name] = func\n    end\n    return semaphore\nend\n\n-- open a queue\nfunction sandbox_core_base_thread.queue(name)\n    local queue, errors = thread.queue(name)\n    if not queue then\n        raise(errors)\n    end\n\n    -- hook filequeue interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_queue) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = queue[\"_\" .. name] or queue[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        queue[name] = func\n    end\n    return queue\nend\n\n-- open a sharedata\nfunction sandbox_core_base_thread.sharedata(name)\n    local sharedata, errors = thread.sharedata(name)\n    if not sharedata then\n        raise(errors)\n    end\n\n    -- hook filesharedata interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_core_base_thread_sharedata) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = sharedata[\"_\" .. name] or sharedata[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        sharedata[name] = func\n    end\n    return sharedata\nend\n\n-- return module\nreturn sandbox_core_base_thread\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/tty.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tty.lua\n--\n\n-- load modules\nreturn require(\"base/tty\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/base/xml.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xml.lua\n--\n\n-- define module\nlocal sandbox_core_base_xml = sandbox_core_base_xml or {}\n\n-- load modules\nlocal xml       = require(\"base/xml\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_base_xml.encode   = xml.encode\nsandbox_core_base_xml.find     = xml.find\nsandbox_core_base_xml.text_of  = xml.text_of\nsandbox_core_base_xml.text     = xml.text\nsandbox_core_base_xml.new      = xml.new\nsandbox_core_base_xml.empty    = xml.empty\nsandbox_core_base_xml.comment  = xml.comment\nsandbox_core_base_xml.cdata    = xml.cdata\nsandbox_core_base_xml.doctype  = xml.doctype\n\n-- decode xml data\nfunction sandbox_core_base_xml.decode(data, opt)\n    local node, errors = xml.decode(data, opt)\n    if not node then\n        raise(errors)\n    end\n    return node\nend\n\n-- stream parse xml data\nfunction sandbox_core_base_xml.scan(data, callback, opt)\n    local ok, errors = xml.scan(data, callback, opt)\n    if ok == nil then\n        raise(errors)\n    end\n    return ok\nend\n\n-- load xml file to the lua table\nfunction sandbox_core_base_xml.loadfile(filepath, opt)\n    local node, errors = xml.loadfile(filepath, opt)\n    if not node then\n        raise(errors)\n    end\n    return node\nend\n\n-- save xml node to the file\nfunction sandbox_core_base_xml.savefile(filepath, node, opt)\n    local ok, errors = xml.savefile(filepath, node, opt)\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- return module\nreturn sandbox_core_base_xml\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/cache/detectcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        detectcache.lua\n--\n\n-- return module\nreturn require(\"cache/detectcache\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/cache/global_detectcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        global_detectcache.lua\n--\n\n-- return module\nreturn require(\"cache/global_detectcache\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/cache/globalcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        globalcache.lua\n--\n\n-- return module\nreturn require(\"cache/globalcache\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/cache/localcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        localcache.lua\n--\n\n-- return module\nreturn require(\"cache/localcache\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/cache/memcache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        memcache.lua\n--\n\n-- return module\nreturn require(\"cache/memcache\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/compress/lz4.lua",
    "content": "--!A cross-platform build utility compressd on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lz4.lua\n--\n\n-- define module\nlocal sandbox_core_compress_lz4 = sandbox_core_compress_lz4 or {}\nlocal sandbox_core_compress_lz4_cstream = sandbox_core_compress_lz4_cstream or {}\nlocal sandbox_core_compress_lz4_dstream = sandbox_core_compress_lz4_dstream or {}\n\n-- load modules\nlocal lz4   = require(\"compress/lz4\")\nlocal raise = require(\"sandbox/modules/raise\")\n\n-- wrap compress stream\nfunction _cstream_wrap(instance)\n    local hooked = {}\n    for name, func in pairs(sandbox_core_compress_lz4_cstream) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = instance[\"_\" .. name] or instance[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        instance[name] = func\n    end\n    return instance\nend\n\n-- wrap decompress stream\nfunction _dstream_wrap(instance)\n    local hooked = {}\n    for name, func in pairs(sandbox_core_compress_lz4_dstream) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = instance[\"_\" .. name] or instance[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        instance[name] = func\n    end\n    return instance\nend\n\n-- read data from stream\nfunction sandbox_core_compress_lz4_cstream.read(stream, buff, size, opt)\n    local real, data_or_errors = stream:_read(buff, size, opt)\n    if real < 0 and data_or_errors then\n        raise(data_or_errors)\n    end\n    return real, data_or_errors\nend\n\n-- write data to stream\nfunction sandbox_core_compress_lz4_cstream.write(stream, data, opt)\n    local real, errors = stream:_write(data, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- read data from stream\nfunction sandbox_core_compress_lz4_dstream.read(stream, buff, size, opt)\n    local real, data_or_errors = stream:_read(buff, size, opt)\n    if real < 0 and data_or_errors then\n        raise(data_or_errors)\n    end\n    return real, data_or_errors\nend\n\n-- write data to stream\nfunction sandbox_core_compress_lz4_dstream.write(stream, data, opt)\n    local real, errors = stream:_write(data, opt)\n    if real < 0 and errors then\n        raise(errors)\n    end\n    return real\nend\n\n-- compress frame data\nfunction sandbox_core_compress_lz4.compress(data, opt)\n    local result, errors = lz4.compress(data, opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- decompress frame data\nfunction sandbox_core_compress_lz4.decompress(data, opt)\n    local result, errors = lz4.decompress(data, opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- compress file data\nfunction sandbox_core_compress_lz4.compress_file(srcpath, dstpath, opt)\n    local result, errors = lz4.compress_file(srcpath, dstpath, opt)\n    if not result and errors then\n        raise(errors)\n    end\nend\n\n-- decompress file data\nfunction sandbox_core_compress_lz4.decompress_file(srcpath, dstpath, opt)\n    local result, errors = lz4.decompress_file(srcpath, dstpath, opt)\n    if not result and errors then\n        raise(errors)\n    end\nend\n\n-- compress block data\nfunction sandbox_core_compress_lz4.block_compress(data, opt)\n    local result, errors = lz4.block_compress(data, opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- decompress block data\nfunction sandbox_core_compress_lz4.block_decompress(data, realsize, opt)\n    local result, errors = lz4.block_decompress(data, realsize, opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- new compress stream\nfunction sandbox_core_compress_lz4.compress_stream(opt)\n    local result, errors = lz4.compress_stream(opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return _cstream_wrap(result)\nend\n\n-- new a decompress stream\nfunction sandbox_core_compress_lz4.decompress_stream(opt)\n    local result, errors = lz4.decompress_stream(opt)\n    if not result and errors then\n        raise(errors)\n    end\n    return _dstream_wrap(result)\nend\n\n-- return module\nreturn sandbox_core_compress_lz4\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/language/language.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        language.lua\n--\n\n-- define module\nlocal sandbox_core_language = sandbox_core_language or {}\n\n-- load modules\nlocal language  = require(\"language/language\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- get the apis\nfunction sandbox_core_language.apis()\n    return language.apis()\nend\n\n-- get the source extensions of all languages\nfunction sandbox_core_language.extensions()\n    return language.extensions()\nend\n\n-- get the target kinds of all languages\nfunction sandbox_core_language.targetkinds()\n    return language.targetkinds()\nend\n\n-- get the source kinds of all languages\nfunction sandbox_core_language.sourcekinds()\n    return language.sourcekinds()\nend\n\n-- get the source flags of all languages\nfunction sandbox_core_language.sourceflags()\n    return language.sourceflags()\nend\n\n-- get the linker kinds of all languages\nfunction sandbox_core_language.linkerkinds()\n    return language.linkerkinds()\nend\n\n-- get the language kinds of all languages\nfunction sandbox_core_language.langkinds()\n    return language.langkinds()\nend\n\n-- load the language from the given name (c++, objc++, swift, golang, asm, ...)\nfunction sandbox_core_language.load(name)\n    local instance, errors = language.load(name)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- load the language from the given source kind: cc, cxx, mm, mxx, sc, go, as ..\nfunction sandbox_core_language.load_sk(sourcekind)\n    local instance, errors = language.load_sk(sourcekind)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- load the language from the given source extension: .c, .cpp, .m, .mm, .swift, .go, .s ..\nfunction sandbox_core_language.load_ex(extension)\n    local instance, errors = language.load_ex(extension)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- get source kind of the source file name\nfunction sandbox_core_language.sourcekind_of(sourcefile)\n    local sourcekind, errors = language.sourcekind_of(sourcefile)\n    if not sourcekind then\n        raise(errors)\n    end\n    return sourcekind\nend\n\n-- get extension of the source kind\nfunction sandbox_core_language.extension_of(sourcekind)\n    local extension, errors = language.extension_of(sourcekind)\n    if not extension then\n        raise(errors)\n    end\n    return extension\nend\n\n-- get linker info (kind and flag) of the source kinds\nfunction sandbox_core_language.linkerinfos_of(targetkind, sourcekinds)\n    local linkerinfo, errors = language.linkerinfos_of(targetkind, sourcekinds)\n    if not linkerinfo then\n        raise(errors)\n    end\n    return linkerinfo\nend\n\n-- return module\nreturn sandbox_core_language\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/language/menu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menu.lua\n--\n\n-- define module\nlocal sandbox_core_language_menu = sandbox_core_language_menu or {}\n\n-- load modules\nlocal menu      = require(\"language/menu\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- get the language menu options for the given action: config or global\nfunction sandbox_core_language_menu.options(action)\n\n    -- get it\n    local options, errors = menu.options(action)\n    if not options then\n        raise(errors)\n    end\n\n    -- ok?\n    return options\nend\n\n\n-- return module\nreturn sandbox_core_language_menu\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/package/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- define module\nlocal sandbox_core_package_package = sandbox_core_package_package or {}\n\n-- load modules\nlocal project    = require(\"project/project\")\nlocal package    = require(\"package/package\")\nlocal raise      = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_package_package.cachedir   = package.cachedir\nsandbox_core_package_package.installdir = package.installdir\nsandbox_core_package_package.searchdirs = package.searchdirs\nsandbox_core_package_package.targetplat = package.targetplat\nsandbox_core_package_package.targetarch = package.targetarch\nsandbox_core_package_package.apis       = package.apis\nsandbox_core_package_package.new        = package.new\n\n-- load the package from the project file\nfunction sandbox_core_package_package.load_from_project(packagename)\n    local instance, errors = package.load_from_project(packagename, project)\n    if errors then\n        raise(errors)\n    end\n    return instance\nend\n\n-- load the package from the system\nfunction sandbox_core_package_package.load_from_system(packagename)\n    local instance, errors = package.load_from_system(packagename)\n    if errors then\n        raise(errors)\n    end\n    return instance\nend\n\n-- load the package from repositories\nfunction sandbox_core_package_package.load_from_repository(packagename, packagedir, opt)\n    local instance, errors = package.load_from_repository(packagename, packagedir, opt)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- return module\nreturn sandbox_core_package_package\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/package/repository.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        repository.lua\n--\n\n-- define module\nlocal sandbox_core_package_repository = sandbox_core_package_repository or {}\n\n-- load modules\nlocal global        = require(\"base/global\")\nlocal project       = require(\"project/project\")\nlocal localcache    = require(\"cache/localcache\")\nlocal repository    = require(\"package/repository\")\nlocal os            = require(\"base/os\")\nlocal raise         = require(\"sandbox/modules/raise\")\nlocal import        = require(\"sandbox/modules/import\")\n\n-- inherit some builtin interfaces\nsandbox_core_package_repository.directory = repository.directory\nsandbox_core_package_repository.get       = repository.get\nsandbox_core_package_repository.load      = repository.load\n\n-- add repository url to the given name\nfunction sandbox_core_package_repository.add(name, url, branch, is_global)\n    local ok, errors = repository.add(name, url, branch, is_global)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- remove repository from gobal or local directory\nfunction sandbox_core_package_repository.remove(name, is_global)\n    local ok, errors = repository.remove(name, is_global)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- clear all repositories from global or local directory\nfunction sandbox_core_package_repository.clear(is_global)\n    local ok, errors = repository.clear(is_global)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get all repositories from global or local directory\n--\n-- opt:\n--   - global  = true: load global repositories\n--   - network = false: do not access network resources (skip fasturl sorting)\nfunction sandbox_core_package_repository.repositories(opt)\n    opt = opt or {}\n    local is_global = opt.global\n\n    -- load repositories from repository cache\n    local repositories = {}\n    for name, repoinfo in pairs(table.wrap(repository.repositories(is_global))) do\n        local url = repoinfo\n        local branch = nil\n        if type(repoinfo) == \"table\" then\n            url = repoinfo[1]\n            branch = repoinfo[2]\n        end\n        local repo = repository.load(name, url, branch, is_global)\n        if repo then\n            table.insert(repositories, repo)\n        end\n    end\n\n    -- load repositories from project file\n    --\n    -- in project xmake.lua:\n    --\n    --     add_repositories(\"other-repo https://github.com/other/other-repo.git dev\")\n    --     add_repositories(\"other-repo dirname\", {rootdir = os.scriptdir()})\n    --\n    if not is_global then\n        for _, repo in ipairs(table.wrap(project.get(\"repositories\"))) do\n            local repoinfo = repo:split('%s')\n            if #repoinfo <= 3 then\n                local name    = repoinfo[1]\n                local url     = repoinfo[2]\n                local branch  = repoinfo[3]\n                local rootdir = project.extraconf(\"repositories\", repo, \"rootdir\")\n                if url and rootdir and not path.is_absolute(url) and not url:find(\":\", 1, true) then\n                    url = path.join(rootdir, url)\n                end\n                local repo = repository.load(name, url, branch, is_global)\n                if repo then\n                    table.insert(repositories, repo)\n                end\n            else\n                raise(\"invalid repository: %s\", repo)\n            end\n        end\n    end\n\n    -- add global xmake repositories\n    if is_global then\n\n        -- get the network mode\n        local network = project.policy(\"network.mode\")\n        if network == nil then\n            network = global.get(\"network\")\n        end\n        if opt.network == false then\n            network = \"private\"\n        end\n\n        -- add artifacts urls (only on Windows)\n        if os.is_host(\"windows\") then\n            local artifacts_urls = os.getenv(\"XMAKE_BINARY_REPO\")\n            if artifacts_urls then\n                artifacts_urls = {artifacts_urls}\n            else\n                artifacts_urls = localcache.cache(\"repository\"):get(\"artifacts_urls\")\n                if not artifacts_urls then\n                    artifacts_urls = {\"https://github.com/xmake-mirror/build-artifacts.git\",\n                                      \"https://gitlab.com/xmake-mirror/build-artifacts.git\",\n                                      \"https://gitee.com/xmake-mirror/build-artifacts.git\"}\n                    if network ~= \"private\" then\n                        import(\"net.fasturl\")\n                        fasturl.add(artifacts_urls)\n                        artifacts_urls = fasturl.sort(artifacts_urls)\n                        localcache.cache(\"repository\"):set(\"artifacts_urls\", artifacts_urls)\n                        localcache.cache(\"repository\"):save()\n                    end\n                end\n            end\n            if #artifacts_urls > 0 then\n                local repo = repository.load(\"build-artifacts\", artifacts_urls[1], \"main\", true)\n                if repo then\n                    table.insert(repositories, repo)\n                end\n            end\n        end\n\n        -- add main urls\n        local mainurls = os.getenv(\"XMAKE_MAIN_REPO\")\n        if mainurls then\n            mainurls = {mainurls}\n        else\n            mainurls = localcache.cache(\"repository\"):get(\"mainurls\")\n            if not mainurls then\n                mainurls = {\"https://github.com/xmake-io/xmake-repo.git\",\n                            \"https://gitlab.com/tboox/xmake-repo.git\",\n                            \"https://gitcode.com/xmake-io/xmake-repo.git\",\n                            \"https://gitee.com/tboox/xmake-repo.git\"}\n                if network ~= \"private\" then\n                    import(\"net.fasturl\")\n                    fasturl.add(mainurls)\n                    mainurls = fasturl.sort(mainurls)\n                    localcache.cache(\"repository\"):set(\"mainurls\", mainurls)\n                    localcache.cache(\"repository\"):save()\n                end\n            end\n        end\n        if #mainurls > 0 then\n            local repo = repository.load(\"xmake-repo\", mainurls[1], \"master\", true)\n            if repo then\n                table.insert(repositories, repo)\n            end\n        end\n    end\n\n    -- load repository from builtin program directory\n    if is_global then\n        local repo = repository.load(\"builtin-repo\", path.join(os.programdir(), \"repository\"), nil, true)\n        if repo then\n            table.insert(repositories, repo)\n        end\n    end\n\n    -- get the repositories\n    return repositories\nend\n\n-- return module\nreturn sandbox_core_package_repository\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/platform/menu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menu.lua\n--\n\n-- define module\nlocal sandbox_core_platform_menu = sandbox_core_platform_menu or {}\n\n-- load modules\nlocal menu      = require(\"platform/menu\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- get the platform menu options for the given action: config or global\nfunction sandbox_core_platform_menu.options(action)\n\n    -- get it\n    local options, errors = menu.options(action)\n    if not options then\n        raise(errors)\n    end\n\n    -- ok?\n    return options\nend\n\n\n-- return module\nreturn sandbox_core_platform_menu\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/platform/platform.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        platform.lua\n--\n\n-- define module\nlocal sandbox_core_platform = sandbox_core_platform or {}\n\n-- load modules\nlocal platform  = require(\"platform/platform\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- load the current platform\nfunction sandbox_core_platform.load(plat, arch, opt)\n    local instance, errors = platform.load(plat, arch, opt)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- get the platform os\nfunction sandbox_core_platform.os(plat, arch)\n    return platform.os(plat, arch)\nend\n\n-- get the all platforms\nfunction sandbox_core_platform.plats()\n    return assert(platform.plats())\nend\n\n-- get the all toolchains\nfunction sandbox_core_platform.toolchains()\n    return assert(platform.toolchains())\nend\n\n-- get the all architectures for the given platform\nfunction sandbox_core_platform.archs(plat, arch)\n    return platform.archs(plat, arch)\nend\n\n-- get the current platform configuration\nfunction sandbox_core_platform.get(name, plat, arch, opt)\n    return platform.get(name, plat, arch, opt)\nend\n\n-- get the platform tool from the kind\n--\n-- e.g. cc, cxx, mm, mxx, as, ar, ld, sh, ..\n--\nfunction sandbox_core_platform.tool(toolkind, plat, arch, opt)\n    return platform.tool(toolkind, plat, arch, opt)\nend\n\n-- get the current platform tool configuration\nfunction sandbox_core_platform.toolconfig(name, plat, arch, opt)\n    return platform.toolconfig(name, plat, arch, opt)\nend\n\n-- return module\nreturn sandbox_core_platform\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        config.lua\n--\n\n-- define module\nlocal sandbox_core_project_config = sandbox_core_project_config or {}\n\n-- load modules\nlocal config    = require(\"project/config\")\nlocal project   = require(\"project/project\")\nlocal platform  = require(\"platform/platform\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_project_config.builddir  = config.builddir\nsandbox_core_project_config.buildir   = config.buildir -- deprecated\nsandbox_core_project_config.plat      = config.plat\nsandbox_core_project_config.arch      = config.arch\nsandbox_core_project_config.mode      = config.mode\nsandbox_core_project_config.host      = config.host\nsandbox_core_project_config.get       = config.get\nsandbox_core_project_config.set       = config.set\nsandbox_core_project_config.directory = config.directory\nsandbox_core_project_config.filepath  = config.filepath\nsandbox_core_project_config.readonly  = config.readonly\nsandbox_core_project_config.load      = config.load\nsandbox_core_project_config.read      = config.read\nsandbox_core_project_config.clear     = config.clear\nsandbox_core_project_config.dump      = config.dump\n\n-- save the configuration\nfunction sandbox_core_project_config.save(filepath, opt)\n    local ok, errors = config.save(filepath, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- return module\nreturn sandbox_core_project_config\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/menu.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menu.lua\n--\n\n-- define module\nlocal sandbox_core_project_menu = sandbox_core_project_menu or {}\n\n-- load modules\nlocal config    = require(\"project/config\")\nlocal project   = require(\"project/project\")\n\n-- get the menu options\nfunction sandbox_core_project_menu.options()\n\n    -- get it\n    return project.menu()\nend\n\n-- return module\nreturn sandbox_core_project_menu\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/option.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        option.lua\n--\n\n-- define module\nlocal sandbox_core_project_option = sandbox_core_project_option or {}\n\n-- load modules\nlocal option = require(\"project/option\")\nlocal raise  = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_project_option.interpreter = option.interpreter\nsandbox_core_project_option.new         = option.new\nsandbox_core_project_option.apis        = option.apis\n\n-- return module\nreturn sandbox_core_project_option\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/policy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        policy.lua\n--\n\n-- define module\nlocal sandbox_core_project_policy = sandbox_core_project_policy or {}\n\n-- load modules\nlocal table       = require(\"base/table\")\nlocal global      = require(\"base/global\")\nlocal option      = require(\"base/option\")\nlocal utils       = require(\"base/utils\")\nlocal policy      = require(\"project/policy\")\nlocal project     = require(\"project/project\")\nlocal raise       = require(\"sandbox/modules/raise\")\n\n-- export some readonly interfaces\nsandbox_core_project_policy.policies = policy.policies\n\n-- has build warnings?\nfunction sandbox_core_project_policy.build_warnings(opt)\n    opt = opt or {}\n    if opt.build_warnings == false and not option.get(\"diagnosis\") then\n        return false\n    end\n    local warnings = sandbox_core_project_policy._BUILD_WARNINGS\n    if warnings == nil then\n        if option.get(\"warning\") then\n            utils.warning(\"\\\"xmake build -w\\\" option has been deprecated, the warning output has been enabled by default.\")\n        end\n        warnings = option.get(\"diagnosis\")\n        if warnings == nil and os.isfile(os.projectfile()) and project.policy(\"build.warning\") ~= nil then\n            warnings = project.policy(\"build.warning\")\n        end\n        sandbox_core_project_policy._BUILD_WARNINGS = warnings or false\n    end\n    return warnings\nend\n\n-- return module\nreturn sandbox_core_project_policy\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/project.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        project.lua\n--\n\n-- define module\nlocal sandbox_core_project = sandbox_core_project or {}\n\n-- load modules\nlocal table       = require(\"base/table\")\nlocal deprecated  = require(\"base/deprecated\")\nlocal utils       = require(\"base/utils\")\nlocal baseoption  = require(\"base/option\")\nlocal config      = require(\"project/config\")\nlocal option      = require(\"project/option\")\nlocal project     = require(\"project/project\")\nlocal sandbox     = require(\"sandbox/sandbox\")\nlocal raise       = require(\"sandbox/modules/raise\")\nlocal environment = require(\"platform/environment\")\nlocal package     = require(\"package/package\")\nlocal import      = require(\"sandbox/modules/import\")\n\n-- export some readonly interfaces\nsandbox_core_project.get                  = project.get\nsandbox_core_project.extraconf            = project.extraconf\nsandbox_core_project.rule                 = project.rule\nsandbox_core_project.rules                = project.rules\nsandbox_core_project.toolchain            = project.toolchain\nsandbox_core_project.toolchains           = project.toolchains\nsandbox_core_project.target               = project.target\nsandbox_core_project.target_add           = project.target_add\nsandbox_core_project.targets              = project.targets\nsandbox_core_project.ordertargets         = project.ordertargets\nsandbox_core_project.option               = project.option\nsandbox_core_project.options              = project.options\nsandbox_core_project.rootfile             = project.rootfile\nsandbox_core_project.allfiles             = project.allfiles\nsandbox_core_project.rcfiles              = project.rcfiles\nsandbox_core_project.directory            = project.directory\nsandbox_core_project.name                 = project.name\nsandbox_core_project.modes                = project.modes\nsandbox_core_project.default_arch         = project.default_arch\nsandbox_core_project.allowed_modes        = project.allowed_modes\nsandbox_core_project.allowed_plats        = project.allowed_plats\nsandbox_core_project.allowed_archs        = project.allowed_archs\nsandbox_core_project.mtimes               = project.mtimes\nsandbox_core_project.version              = project.version\nsandbox_core_project.required_package     = project.required_package\nsandbox_core_project.required_packages    = project.required_packages\nsandbox_core_project.requires_str         = project.requires_str\nsandbox_core_project.requireconfs_str     = project.requireconfs_str\nsandbox_core_project.requireslock         = project.requireslock\nsandbox_core_project.requireslock_version = project.requireslock_version\nsandbox_core_project.policy               = project.policy\nsandbox_core_project.policy_set           = project.policy_set\nsandbox_core_project.tmpdir               = project.tmpdir\nsandbox_core_project.tmpfile              = project.tmpfile\nsandbox_core_project.is_loaded            = project.is_loaded\nsandbox_core_project.apis                 = project.apis\nsandbox_core_project.namespaces           = project.namespaces\n\n-- check project options\nfunction sandbox_core_project.check_options()\n\n    -- get project options\n    local options = {}\n    for _, opt in pairs(project.options()) do\n        table.insert(options, opt)\n    end\n\n    -- get sandbox instance\n    local instance = sandbox.instance()\n    assert(instance)\n\n    -- enter the project directory\n    local oldir, errors = os.cd(os.projectdir())\n    if not oldir then\n        raise(errors)\n    end\n\n    -- init check task\n    local checked   = {}\n    local checktask = function (index)\n        local opt = options[index]\n        if opt then\n            -- check deps of this option first\n            for _, dep in ipairs(opt:orderdeps()) do\n                if not checked[dep:fullname()] then\n                    dep:check()\n                    checked[dep:fullname()] = true\n                end\n            end\n            -- check this option\n            if not checked[opt:fullname()] then\n                opt:check()\n                checked[opt:fullname()] = true\n            end\n        end\n    end\n\n    -- check all options\n    local jobs = baseoption.get(\"jobs\") or os.default_njob()\n    import(\"async.runjobs\", {anonymous = true})(\"check_options\", instance:fork(checktask):script(), {total = #options, comax = jobs})\n\n    -- save all options to the cache file\n    option.save()\n\n    -- leave the project directory\n    local ok, errors = os.cd(oldir)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- config targets\nfunction sandbox_core_project._config_targets(opt)\n    import(\"private.utils.target\", {alias = \"target_utils\"})\n    target_utils.config_targets(opt)\nend\n\n-- config targets\n--\n-- @param opt   the extra option, e.g. {recheck = false}\n--\n-- on_config(target, opt)\n--    -- @see https://github.com/xmake-io/xmake/issues/4173#issuecomment-1712843956\n--    if opt.recheck then\n--        target:has_cfuncs(...)\n--    end\n-- end\n-- TODO we need to optimize jobgraph\n-- https://github.com/xmake-io/xmake/issues/6775\n--[[\nfunction sandbox_core_project._config_targets(opt)\n    import(\"private.action.build.target\", {alias = \"target_buildutils\"})\n\n    -- we need to config all targets (contains non-default targets)\n    --\n    -- @note Currently, many configurations still depend on the order of rules/add_deps (e.g. qt rules),\n    -- so we can only execute single tasks for now (jobs = 1).\n    local targets_root = target_buildutils.get_root_targets(nil, {all = true})\n    target_buildutils.run_targetjobs(targets_root, {job_kind = \"config\", target_fence = true, jobs = 1, job_opt = opt})\nend]]\n\n-- load rules in the required packages for target\nfunction sandbox_core_project._load_package_rules_for_target(target)\n    for _, rulename in ipairs(table.wrap(target:get(\"rules\"))) do\n        local packagename = rulename:match(\"@(.-)/\")\n        if packagename then\n            local ruleinst\n            local pkginfo = project.required_package(packagename)\n            if pkginfo then\n                ruleinst = pkginfo:rule(rulename)\n                if ruleinst then\n                    target:rule_add(ruleinst)\n                    for _, dep in pairs(table.wrap(ruleinst:deps())) do\n                        target:rule_add(dep)\n                    end\n                end\n            end\n            if not ruleinst then\n                raise(\"target(\\\"%s\\\"): unknown package rule in add_rules(\\\"%s\\\")\", target:fullname(), rulename)\n            end\n        end\n    end\nend\n\n-- load rules in the required packages for targets\n-- @see https://github.com/xmake-io/xmake/issues/2374\n--\n-- @code\n-- add_requires(\"zlib\", {system = false})\n-- target(\"test\")\n--    set_kind(\"binary\")\n--    add_files(\"src/*.cpp\")\n--    add_packages(\"zlib\")\n--    add_rules(\"@zlib/test\")\n-- @endcode\n--\nfunction sandbox_core_project._load_package_rules_for_targets()\n    for _, target in ipairs(table.wrap(project.ordertargets())) do\n        if target:is_enabled() then\n            sandbox_core_project._load_package_rules_for_target(target)\n        end\n    end\nend\n\n-- load project targets\nfunction sandbox_core_project.load_targets(opt)\n    sandbox_core_project._load_package_rules_for_targets()\n    sandbox_core_project._config_targets(opt)\nend\n\n-- get the filelock of the whole project directory\nfunction sandbox_core_project.filelock()\n    local filelock, errors = project.filelock()\n    if not filelock then\n        raise(\"cannot create the project lock, %s!\", errors or \"unknown errors\")\n    end\n    return filelock\nend\n\n-- lock the whole project\nfunction sandbox_core_project.lock(opt)\n    if sandbox_core_project.trylock(opt) then\n        return true\n    elseif baseoption.get(\"diagnosis\") then\n        utils.cprint(\"${color.warning}the current project is being accessed by other processes, please wait!\")\n        io.flush()\n    end\n    local ok, errors = sandbox_core_project.filelock():lock(opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- trylock the whole project\nfunction sandbox_core_project.trylock(opt)\n    return sandbox_core_project.filelock():trylock(opt)\nend\n\n-- unlock the whole project\nfunction sandbox_core_project.unlock()\n    local ok, errors = sandbox_core_project.filelock():unlock()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- change project file and directory (xmake.lua)\nfunction sandbox_core_project.chdir(projectdir, projectfile)\n    if not projectfile then\n        projectfile = path.join(projectdir, \"xmake.lua\")\n    end\n    xmake._PROJECT_FILE = projectfile\n    xmake._PROJECT_DIR = path.directory(projectfile)\n    xmake._WORKING_DIR = xmake._PROJECT_DIR\n    config._DIRECTORY = nil\nend\n\n-- get scope\nfunction sandbox_core_project.scope(scopename)\n    local cachekey = \"scope.\" .. scopename\n    local scope = project._memcache():get(cachekey)\n    if not scope then\n\n        -- load the project file first if has not been loaded?\n        local ok, errors = project._load()\n        if not ok then\n            raise(\"load project failed, %s\", errors or \"unknown\")\n        end\n\n        -- load scope\n        scope, errors = project._load_scope(scopename, true, false)\n        if not scope then\n            raise(\"load scope(%s) failed, %s\", scopename, errors or \"unknown\")\n        end\n        project._memcache():set(cachekey, scope)\n    end\n    return scope\nend\n\n-- return module\nreturn sandbox_core_project\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/rule.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rule.lua\n--\n\n-- define module\nlocal sandbox_core_project_rule = sandbox_core_project_rule or {}\n\n-- load modules\nlocal table     = require(\"base/table\")\nlocal rule      = require(\"project/rule\")\nlocal project   = require(\"project/project\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_project_rule.rule  = rule.rule\nsandbox_core_project_rule.rules = rule.rules\nsandbox_core_project_rule.new   = rule.new\nsandbox_core_project_rule.apis  = rule.apis\n\n-- return module\nreturn sandbox_core_project_rule\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/target.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target.lua\n--\n\n-- define module\nlocal sandbox_core_project_target = sandbox_core_project_target or {}\n\n-- load modules\nlocal target    = require(\"project/target\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_project_target.filename = target.filename\nsandbox_core_project_target.linkname = target.linkname\nsandbox_core_project_target.new      = target.new\nsandbox_core_project_target.apis     = target.apis\n\n-- return module\nreturn sandbox_core_project_target\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/project/task.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        task.lua\n--\n\n-- deprecatd: return module\nreturn require(\"sandbox/modules/import/core/base/task\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/sandbox/module.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        module.lua\n--\n\n-- define module\nlocal core_sandbox_module = core_sandbox_module or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal hash      = require(\"base/hash\")\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal option    = require(\"base/option\")\nlocal global    = require(\"base/global\")\nlocal config    = require(\"project/config\")\nlocal memcache  = require(\"cache/memcache\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- the module kinds\nlocal MODULE_KIND_LUAFILE = 1\nlocal MODULE_KIND_LUADIR  = 2\nlocal MODULE_KIND_BINARY  = 3\nlocal MODULE_KIND_SHARED  = 4\n\n-- get module path from name\nfunction core_sandbox_module._modulepath(name)\n\n    -- translate module path\n    --\n    -- \"package.module\" => \"package/module\"\n    -- \"..package.module\" => \"../../package/module\"\n    --\n    local startdots = true\n    local modulepath = name:gsub(\".\", function(c)\n        if c == '.' then\n            if startdots then\n                return \"..\" .. path.sep()\n            else\n                return path.sep()\n            end\n        else\n            startdots = false\n            return c\n        end\n    end)\n\n    -- return module path\n    return modulepath\nend\n\n-- load module from file\nfunction core_sandbox_module._loadfile(filepath, instance)\n    assert(filepath)\n\n    -- load module script\n    local script, errors = loadfile(filepath)\n    if not script then\n        return nil, errors\n    end\n\n    -- with sandbox?\n    if instance then\n\n        -- fork a new sandbox for this script\n        instance, errors = instance:fork(script, path.directory(filepath))\n        if not instance then\n            return nil, errors\n        end\n\n        -- load module\n        local result, errors = instance:module()\n        if not result then\n            return nil, errors\n        end\n        return result, instance:script()\n    end\n\n    -- load module without sandbox\n    local ok, result = utils.trycall(script)\n    if not ok then\n        return nil, result\n    end\n    return result, script\nend\n\n-- find module\nfunction core_sandbox_module._find(dir, name)\n    assert(dir and name)\n\n    -- get module subpath\n    local module_subpath = core_sandbox_module._modulepath(name)\n    assert(module_subpath)\n\n    -- get module full path\n    local module_fullpath = path.join(dir, module_subpath)\n\n    -- single lua module?\n    local modulekey = path.normalize(path.absolute(module_fullpath))\n    if os.isfile(module_fullpath .. \".lua\") then\n        return modulekey, MODULE_KIND_LUAFILE\n    elseif os.isdir(module_fullpath) then\n        local module_projectfile = path.join(module_fullpath, \"xmake.lua\")\n        if os.isfile(module_projectfile) then -- native module? e.g. binary/shared modules\n            local content = io.readfile(module_projectfile)\n            local kind = content:match(\"add_rules%(\\\"module.(.-)\\\"%)\")\n            if kind == \"binary\" then\n                return modulekey, MODULE_KIND_BINARY\n            elseif kind == \"shared\" then\n                return modulekey, MODULE_KIND_SHARED\n            end\n        else\n            -- module directory\n            return modulekey, MODULE_KIND_LUADIR\n        end\n    end\nend\n\n-- load module from the single script file\nfunction core_sandbox_module._load_from_scriptfile(module_fullpath, opt)\n    assert(not opt.module)\n    return core_sandbox_module._loadfile(module_fullpath .. \".lua\", opt.instance)\nend\n\n-- load module from the script directory\nfunction core_sandbox_module._load_from_scriptdir(module_fullpath, opt)\n    local script\n    local module = opt.module\n    local modulefiles = os.files(path.join(module_fullpath, \"**.lua\"))\n    if modulefiles then\n        for _, modulefile in ipairs(modulefiles) do\n            local result, errors = core_sandbox_module._loadfile(modulefile, opt.instance)\n            if not result then\n                return nil, errors\n            end\n\n            -- bind main entry\n            if type(result) == \"table\" and result.main then\n                setmetatable(result, { __call = function (_, ...) return result.main(...) end})\n            end\n\n            -- get the module path\n            local modulepath = path.relative(modulefile, module_fullpath)\n            if not modulepath then\n                return nil, string.format(\"cannot get the path for module: %s\", module_subpath)\n            end\n            module = module or {}\n            script = errors\n\n            -- save module\n            local scope = module\n            for _, modulename in ipairs(path.split(modulepath)) do\n                local pos = modulename:find(\".lua\", 1, true)\n                if pos then\n                    modulename = modulename:sub(1, pos - 1)\n                    assert(modulename)\n                    scope[modulename] = result\n                else\n                    -- enter submodule\n                    scope[modulename] = scope[modulename] or {}\n                    scope = scope[modulename]\n                end\n            end\n        end\n    end\n    return module, script\nend\n\n-- add some builtin global options from the parent xmake\nfunction core_sandbox_module._add_builtin_argv(argv, projectdir)\n    table.insert(argv, \"-P\")\n    table.insert(argv, projectdir)\n    for _, name in ipairs({\"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\", \"root\"}) do\n        local value = option.get(name)\n        if type(value) == \"boolean\" then\n            table.insert(argv, \"--\" .. name)\n        elseif value ~= nil then\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        end\n    end\nend\n\n-- get the native module info\nfunction core_sandbox_module._native_moduleinfo(module_fullpath, modulekind)\n    local projectdir = path.normalize(path.absolute(module_fullpath))\n    local programdir = path.normalize(os.programdir())\n    local modulename = path.basename(module_fullpath)\n    local modulehash = hash.strhash64(projectdir)\n    local builddir\n    local is_global = false\n    local modulepath\n    if projectdir:startswith(programdir) then\n        is_global = true\n        builddir = path.join(global.directory(), \"cache\", \"modules\", modulehash)\n        modulepath = path.join(\"@programdir\", path.relative(projectdir, programdir))\n    elseif os.isfile(os.projectfile()) then\n        builddir = path.join(config.directory(), \"cache\", \"modules\", modulehash)\n        modulepath = path.relative(projectdir, os.projectdir())\n    else\n        builddir = path.join(projectdir, \"cache\", \"modules\", modulehash)\n        modulepath = projectdir\n    end\n    return {builddir = builddir, projectdir = projectdir, is_global = is_global, modulename = modulename, modulekind = modulekind, modulepath = modulepath}\nend\n\n-- build module\nfunction core_sandbox_module._build_module(moduleinfo)\n    local modulekind_str\n    if moduleinfo.modulekind == MODULE_KIND_BINARY then\n        modulekind_str = \"binary\"\n    elseif moduleinfo.modulekind == MODULE_KIND_SHARED then\n        modulekind_str = \"shared\"\n    else\n        return nil, \"unknown module kind!\"\n    end\n    utils.cprint(\"${color.build.target}building native %s module(%s) in %s ...\", modulekind_str, moduleinfo.modulename, moduleinfo.modulepath)\n    local builddir = moduleinfo.builddir\n    local projectdir = moduleinfo.projectdir\n    local envs = {XMAKE_CONFIGDIR = builddir}\n    local argv = {\"config\", \"-o\", builddir, \"-a\", xmake.arch()}\n    core_sandbox_module._add_builtin_argv(argv, projectdir)\n    local ok, errors = os.execv(os.programfile(), argv, {envs = envs, curdir = projectdir})\n    if ok ~= 0 then\n        return nil, errors\n    end\n    argv = {}\n    core_sandbox_module._add_builtin_argv(argv, projectdir)\n    ok, errors = os.execv(os.programfile(), argv, {envs = envs, curdir = projectdir})\n    if ok ~= 0 then\n        return nil, errors\n    end\n    return true\nend\n\n-- load module from the binary module\nfunction core_sandbox_module._load_from_binary(module_fullpath, opt)\n    opt = opt or {}\n    local moduleinfo = core_sandbox_module._native_moduleinfo(module_fullpath, MODULE_KIND_BINARY)\n    local binaryfiles = os.files(path.join(moduleinfo.builddir, \"module_*\"))\n    if #binaryfiles == 0 or (not moduleinfo.is_global and opt.always_build) then\n        local ok, errors = core_sandbox_module._build_module(moduleinfo)\n        if not ok then\n            return nil, errors\n        end\n        binaryfiles = {}\n    end\n    local module\n    if #binaryfiles == 0 then\n        binaryfiles = os.files(path.join(moduleinfo.builddir, \"module_*\"))\n    end\n    if #binaryfiles > 0 then\n        module = {}\n        for _, binaryfile in ipairs(binaryfiles) do\n            local modulename = path.basename(binaryfile):sub(8)\n            module[modulename] = function (...)\n                local argv = {}\n                for _, arg in ipairs(table.pack(...)) do\n                    table.insert(argv, tostring(arg))\n                end\n                local ok, outdata, errdata, errors = os.iorunv(binaryfile, argv)\n                if ok then\n                    return outdata\n                else\n                    if not errors then\n                        errors = errdata or \"\"\n                        if #errors:trim() == 0 then\n                            errors = outdata or \"\"\n                        end\n                    end\n                    os.raise({errors = errors, stderr = errdata, stdout = outdata})\n                end\n            end\n        end\n    end\n    return module\nend\n\n-- load module from the shared module\nfunction core_sandbox_module._load_from_shared(module_fullpath, opt)\n    opt = opt or {}\n    local moduleinfo = core_sandbox_module._native_moduleinfo(module_fullpath, MODULE_KIND_SHARED)\n    local libraryfiles = os.files(path.join(moduleinfo.builddir, \"*module_*\"))\n    if #libraryfiles == 0 or (not moduleinfo.is_global and opt.always_build) then\n        local ok, errors = core_sandbox_module._build_module(moduleinfo)\n        if not ok then\n            return nil, errors\n        end\n        libraryfiles = {}\n    end\n    local module\n    if #libraryfiles == 0 then\n        libraryfiles = os.files(path.join(moduleinfo.builddir, \"*module_*\"))\n    end\n    if #libraryfiles > 0 then\n        local script, errors1, errors2\n        for _, libraryfile in ipairs(libraryfiles) do\n            local modulename = path.basename(libraryfile):match(\"module_(.+)\")\n            if modulename then\n                if package.loadxmi then\n                    script, errors1 = package.loadxmi(libraryfile, \"xmiopen_\" .. modulename)\n                end\n                if not script then\n                    script, errors2 = package.loadlib(libraryfile, \"luaopen_\" .. modulename)\n                end\n                if script then\n                    module = script()\n                else\n                    return nil, errors1 or errors2 or string.format(\"xmiopen_%s and luaopen_%s not found!\", modulename, modulename)\n                end\n                break\n            end\n        end\n    end\n    return module, script\nend\n\n-- load module\nfunction core_sandbox_module._load(dir, name, opt)\n    opt = opt or {}\n    assert(dir and name)\n\n    -- get module subpath\n    local module_subpath = core_sandbox_module._modulepath(name)\n    assert(module_subpath)\n\n    -- get module full path\n    local module_fullpath = path.join(dir, module_subpath)\n\n    -- load module\n    local script\n    local module\n    local modulekind = opt.modulekind\n    if modulekind == MODULE_KIND_LUAFILE then\n        module, script = core_sandbox_module._load_from_scriptfile(module_fullpath, opt)\n    elseif modulekind == MODULE_KIND_LUADIR then\n        module, script = core_sandbox_module._load_from_scriptdir(module_fullpath, opt)\n    elseif modulekind == MODULE_KIND_BINARY then\n        module, script = core_sandbox_module._load_from_binary(module_fullpath, opt)\n    elseif modulekind == MODULE_KIND_SHARED then\n        module, script = core_sandbox_module._load_from_shared(module_fullpath, opt)\n    end\n    if not module then\n        local errors = script\n        return nil, errors or string.format(\"module: %s not found!\", name)\n    end\n    return module, script\nend\n\n-- find and load module\nfunction core_sandbox_module._find_and_load(name, opt)\n    opt = opt or {}\n    local found = false\n    local errors = nil\n    local module = nil\n    local modulekey = nil\n    local modulekind = MODULE_KIND_LUAFILE\n    local modules = opt.modules\n    local modules_directories = opt.modules_directories\n    local always_build = opt.always_build\n    local loadnext = false\n    for idx, moduledir in ipairs(modules_directories) do\n        modulekey, modulekind = core_sandbox_module._find(moduledir, name)\n        if modulekey then\n            local moduleinfo = modules[modulekey]\n            if moduleinfo and not opt.nocache and not opt.inherit then\n                module = moduleinfo[1]\n                errors = moduleinfo[2]\n            else\n                module, errors = core_sandbox_module._load(moduledir, name, {\n                                                           instance = idx < #modules_directories and opt.instance or nil,  -- last modules need not fork sandbox\n                                                           module = module,\n                                                           always_build = always_build,\n                                                           modulekind = modulekind})\n                if not opt.nocache then\n                    modules[modulekey] = {module, errors}\n                end\n            end\n            if module and modulekind == MODULE_KIND_LUADIR then\n                loadnext = true\n            end\n            found = true\n            if not loadnext then\n                break\n            end\n        end\n    end\n    return found, module, errors\nend\n\n-- get module name\nfunction core_sandbox_module.name(name)\n    local i = name:lastof(\".\", true)\n    if i then\n        name = name:sub(i + 1)\n    end\n    return name\nend\n\n-- get module directories\nfunction core_sandbox_module.directories()\n    local moduledirs = memcache.get(\"core_sandbox_module\", \"moduledirs\")\n    if not moduledirs then\n        moduledirs = { path.join(global.directory(), \"modules\"),\n                       path.join(os.programdir(), \"modules\"),\n                       path.join(os.programdir(), \"core/sandbox/modules/import\")}\n        local modulesdir = os.getenv(\"XMAKE_MODULES_DIR\")\n        if modulesdir and os.isdir(modulesdir) then\n            table.insert(moduledirs, 1, modulesdir)\n        end\n        memcache.set(\"core_sandbox_module\", \"moduledirs\", moduledirs)\n    end\n    return moduledirs\nend\n\n-- add module directories\nfunction core_sandbox_module.add_directories(...)\n    local moduledirs = core_sandbox_module.directories()\n    for _, dir in ipairs({...}) do\n        table.insert(moduledirs, 1, dir)\n    end\n    memcache.set(\"core_sandbox_module\", \"moduledirs\", table.unique(moduledirs))\nend\n\n-- find module\nfunction core_sandbox_module.find(name)\n    for _, moduledir in ipairs(core_sandbox_module.directories()) do\n        if (core_sandbox_module._find(moduledir, name)) then\n            return true\n        end\n    end\nend\n\n-- import module\n--\n-- @param name      the module name, e.g. core.platform\n-- @param opt       the argument options, e.g. {alias = \"\", nolocal = true, rootdir = \"\", try = false, inherit = false, anonymous = false, nocache = false}\n--\n-- @return          the module instance\n--\n-- e.g.\n--\n-- import(\"core.platform\")\n-- => platform\n--\n-- import(\"core.platform\", {alias = \"p\"})\n-- => p\n--\n-- import(\"core\")\n-- => core\n-- => core.platform\n---\n-- import(\"core\", {rootdir = \"/scripts\"})\n-- => core\n-- => core.platform\n--\n-- import(\"core.platform\", {inherit = true})\n-- => inherit the all interfaces of core.platform to the current scope\n--\n-- local test = import(\"test\", {rootdir = \"/tmp/xxx\", anonymous = true})\n-- => only return imported module\n--\n-- import(\"core.project.config\", {try = true})\n-- => cannot raise errors if the imported module not found\n--\n-- import(\"native.module\", {always_build = true})\n-- => always build module when calling import\n--\n-- @note the polymiorphism is not supported for import.inherit mode now.\n--\nfunction core_sandbox_module.import(name, opt)\n    assert(name)\n    opt = opt or {}\n\n    -- init module cache\n    core_sandbox_module._MODULES = core_sandbox_module._MODULES or {}\n    local modules = core_sandbox_module._MODULES\n\n    -- get the parent scope\n    local scope_parent = getfenv(2)\n    assert(scope_parent)\n\n    -- get module name\n    local modulename = core_sandbox_module.name(name)\n    if not modulename then\n        raise(\"cannot get module name for %s\", name)\n    end\n\n    -- the imported name\n    local imported_name = opt.alias or modulename\n\n    -- get the current sandbox instance\n    local instance = sandbox.instance()\n    assert(instance)\n\n    -- the root directory for this sandbox script\n    local rootdir = opt.rootdir or instance:rootdir()\n\n    -- init module directories (disable local packages?)\n    local modules_directories = (opt.nolocal or not rootdir) and core_sandbox_module.directories() or table.join(rootdir, core_sandbox_module.directories())\n\n    -- load module\n    local loadopt = table.clone(opt) or {}\n    loadopt.instance = instance\n    loadopt.modules = modules\n    loadopt.modules_directories = modules_directories\n    local found, module, errors = core_sandbox_module._find_and_load(name, loadopt)\n\n    -- not found? attempt to load module.interface\n    if not found and not opt.inherit then\n        -- get module name\n        local found2 = false\n        local errors2 = nil\n        local module2_name = nil\n        local interface_name = nil\n        local pos = name:lastof('.', true)\n        if pos then\n            module2_name = name:sub(1, pos - 1)\n            interface_name = name:sub(pos + 1)\n        end\n\n        -- load module.interface\n        if module2_name and interface_name then\n            found2, module2, errors2 = core_sandbox_module._find_and_load(module2_name, loadopt)\n            if found2 and module2 and module2[interface_name] then\n                module = module2[interface_name]\n                found = true\n                errors = nil\n            else\n                errors = errors2\n            end\n        end\n    end\n\n    -- not found?\n    if not found then\n        if opt.try then\n            return nil\n        else\n            raise(\"cannot import module: %s, not found!\", name)\n        end\n    end\n\n    -- check\n    if not module then\n        raise(\"cannot import module: %s, %s\", name, errors)\n    end\n\n    -- get module script\n    local script = errors\n\n    -- inherit?\n    if opt.inherit then\n\n        -- inherit this module into the parent scope\n        table.inherit2(scope_parent, module)\n\n        -- import as super module\n        imported_name = \"_super\"\n\n        -- public the script scope for the super module\n        --\n        -- we can access the all scope members of _super in the child module\n        --\n        -- e.g.\n        --\n        -- import(\"core.platform.xxx\", {inherit = true})\n        --\n        -- print(_super._g)\n        --\n        if script ~= nil then\n            setmetatable(module, {  __index = function (tbl, key)\n                                        local val = rawget(tbl, key)\n                                        if val == nil then\n                                            val = rawget(getfenv(script), key)\n                                        end\n                                        return val\n                                    end})\n\n        end\n\n    end\n\n    -- bind main entry\n    if type(module) == \"table\" and module.main then\n        setmetatable(module, { __call = function (_, ...) return module.main(...) end})\n    end\n\n    -- import this module into the parent scope\n    if not opt.anonymous then\n        scope_parent[imported_name] = module\n    end\n\n    -- return it\n    return module\nend\n\n-- inherit module\n--\n-- we can access all super interfaces by _super\n--\n-- @note the polymiorphism is not supported for import.inherit mode now.\n--\nfunction core_sandbox_module.inherit(name, opt)\n    opt = opt or {}\n    opt.inherit = true\n    return core_sandbox_module.import(name, opt)\nend\n\n-- get the public object in the current module\nfunction core_sandbox_module.get(name)\n\n    -- is private object?\n    if name:startswith('_') then\n        return\n    end\n\n    -- get the parent scope\n    local scope_parent = getfenv(2)\n    assert(scope_parent)\n\n    -- get it\n    return scope_parent[name]\nend\n\n-- load module\nreturn core_sandbox_module\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sandbox.lua\n--\n\n-- define module\nlocal sandbox_core_sandbox = sandbox_core_sandbox or {}\n\n-- load modules\nlocal sandbox     = require(\"sandbox/sandbox\")\nlocal raise       = require(\"sandbox/modules/raise\")\nlocal try         = require(\"sandbox/modules/try\")\nlocal catch       = require(\"sandbox/modules/catch\")\nlocal utils       = require(\"base/utils\")\nlocal table       = require(\"base/table\")\nlocal colors      = require(\"base/colors\")\nlocal dump        = require(\"base/dump\")\nlocal option      = require(\"base/option\")\nlocal scheduler   = require(\"base/scheduler\")\nlocal globalcache = require(\"cache/globalcache\")\n\n-- print variables for interactive mode\nfunction sandbox_core_sandbox._interactive_dump(...)\n    local diagnosis = option.get(\"diagnosis\")\n    local values = table.pack(...)\n    -- do not use #values since nil might be included\n    local n = values.n\n    if n <= 1 then\n        dump(values[1], \"< \", diagnosis)\n    else\n        local fmt = \"< %d: \"\n        if n >= 1000 then\n            -- try `unpack({}, 1, 5000)`, wish you happy!\n            fmt = \"< %4d: \"\n        elseif n >= 100 then\n            fmt = \"< %3d: \"\n        elseif n >= 10 then\n            fmt = \"< %2d: \"\n        end\n        for i = 1, n do\n            dump(values[i], string.format(fmt, i), diagnosis)\n        end\n    end\nend\n\n-- enter interactive mode\nfunction sandbox_core_sandbox.interactive()\n\n    -- get the current sandbox instance\n    local instance = sandbox.instance()\n    if not instance then\n        raise(\"cannot get sandbox instance!\")\n    end\n\n    -- fork a new sandbox\n    local errors\n    instance, errors = instance:fork()\n    if not instance then\n        raise(errors)\n    end\n\n    -- load repl history\n    local replhistory = nil\n    if readline then\n\n        -- clear history\n        readline.clear_history()\n\n        -- load history\n        replhistory = table.wrap(globalcache.get(\"history\", \"replhistory\"))\n        for _, ln in ipairs(replhistory) do\n            readline.add_history(ln)\n        end\n    end\n\n    -- register dump function for interactive mode\n    local public_scope = instance._PUBLIC\n    public_scope[\"$interactive_dump\"] = sandbox_core_sandbox._interactive_dump\n    public_scope[\"$interactive_prompt\"] = colors.translate(\"${color.interactive.prompt}${text.interactive.prompt} \")\n    public_scope[\"$interactive_prompt2\"] = colors.translate(\"${color.interactive.prompt2}${text.interactive.prompt2} \")\n    public_scope[\"$interactive_setfenv\"] = setfenv\n\n    -- disable scheduler\n    scheduler:enable(false)\n\n    -- enter interactive mode with this new sandbox\n    sandbox.interactive(public_scope)\n\n    -- enable scheduler\n    scheduler:enable(true)\n\n    -- save repl history if readline is enabled\n    if readline then\n\n        -- save to history\n        local entries = readline.history_list()\n        if #entries > #replhistory then\n            for i = #replhistory + 1, #entries do\n                if #replhistory > 64 then\n                    table.remove(replhistory, 1)\n                end\n                table.insert(replhistory, entries[i].line)\n                globalcache.set(\"history\", \"replhistory\", replhistory)\n            end\n            globalcache.save(\"history\")\n        end\n\n        -- clear history\n        readline.clear_history()\n    end\nend\n\n-- get the filter of the current sandbox for the given script\nfunction sandbox_core_sandbox.filter(script)\n    local instance = sandbox.instance(script)\n    if not instance then\n        raise(\"cannot get sandbox instance!\")\n    end\n    return instance:filter()\nend\n\n-- get all builtin modules\nfunction sandbox_core_sandbox.builtin_modules()\n    return sandbox.builtin_modules()\nend\n\n-- return module\nreturn sandbox_core_sandbox\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/theme/theme.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        theme.lua\n--\n\n-- define module\nlocal sandbox_core_theme = sandbox_core_theme or {}\n\n-- load modules\nlocal theme     = require(\"theme/theme\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- get the current theme instance\nfunction sandbox_core_theme.instance()\n    local instance = theme.instance()\n    if instance ~= nil then\n        return instance\n    else\n        raise(\"cannot get the current theme\")\n    end\nend\n\n-- load the given theme\nfunction sandbox_core_theme.load(name)\n    local instance, errors = theme.load(name)\n    if not instance then\n        raise(\"load theme(%s) failed, %s\", name, errors)\n    end\n    return instance\nend\n\n-- get the theme configuration\nfunction sandbox_core_theme.get(name)\n    local value = theme.get(name)\n    if value ~= nil then\n        return value\n    else\n        local instance = theme.instance()\n        raise(\"cannot get %s from the current theme(%s)\", name, instance and instance:name() or \"unknown\")\n    end\nend\n\n-- find all themes\nfunction sandbox_core_theme.names()\n    return theme.names()\nend\n\n-- return module\nreturn sandbox_core_theme\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/tool/compiler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        compiler.lua\n--\n\n-- define module\nlocal sandbox_core_tool_compiler = sandbox_core_tool_compiler or {}\n\n-- load modules\nlocal platform = require(\"platform/platform\")\nlocal language = require(\"language/language\")\nlocal compiler = require(\"tool/compiler\")\nlocal raise    = require(\"sandbox/modules/raise\")\nlocal assert   = require(\"sandbox/modules/assert\")\nlocal import   = require(\"sandbox/modules/import\")\nlocal sandbox  = require(\"sandbox/sandbox\")\n\n-- load the compiler from the given source kind\nfunction sandbox_core_tool_compiler.load(sourcekind, opt)\n    local instance, errors = compiler.load(sourcekind, opt and opt.target or nil)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- make command for compiling source file\nfunction sandbox_core_tool_compiler.compcmd(sourcefiles, objectfile, opt)\n    return os.args(table.join(sandbox_core_tool_compiler.compargv(sourcefiles, objectfile, opt)))\nend\n\n-- make arguments list for compiling source file\nfunction sandbox_core_tool_compiler.compargv(sourcefiles, objectfile, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get source kind if only one source file\n    local sourcekind = opt.sourcekind\n    if not sourcekind and type(sourcefiles) == \"string\" then\n        sourcekind = language.sourcekind_of(sourcefiles)\n    end\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- make arguments list\n    return instance:compargv(sourcefiles, objectfile, opt)\nend\n\n-- compile source files\nfunction sandbox_core_tool_compiler.compile(sourcefiles, objectfile, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get source kind if only one source file\n    local sourcekind = opt.sourcekind\n    if not sourcekind and type(sourcefiles) == \"string\" then\n        sourcekind = language.sourcekind_of(sourcefiles)\n    end\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- compile it\n    local ok, errors = instance:compile(sourcefiles, objectfile, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- make compiling flags\n--\n-- @param sourcefiles   the source files\n-- @param opt           the argument options (contain all the compiler attributes of target),\n--                      e.g. {target = ..., targetkind = \"static\", configs = {cxflags = \"\", defines = \"\", includedirs = \"\", ...}}\n--\n-- @return              the flags list\n--\nfunction sandbox_core_tool_compiler.compflags(sourcefiles, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- patch sourcefile to get flags of the given source file\n    if type(sourcefiles) == \"string\" then\n        opt.sourcefile = sourcefiles\n    end\n\n    -- get source kind if only one source file\n    local sourcekind = opt.sourcekind\n    if not sourcekind and type(sourcefiles) == \"string\" then\n        sourcekind = language.sourcekind_of(sourcefiles)\n    end\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- make flags\n    return instance:compflags(opt)\nend\n\n-- make command for building source file\nfunction sandbox_core_tool_compiler.buildcmd(sourcefiles, targetfile, opt)\n    return os.args(table.join(sandbox_core_tool_compiler.buildargv(sourcefiles, targetfile, opt)))\nend\n\n-- make arguments list for building source file\nfunction sandbox_core_tool_compiler.buildargv(sourcefiles, targetfile, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get source kind if only one source file\n    local sourcekind = opt.sourcekind\n    if not sourcekind and type(sourcefiles) == \"string\" then\n        sourcekind = language.sourcekind_of(sourcefiles)\n    end\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- make arguments list\n    return instance:buildargv(sourcefiles, targetfile, opt)\nend\n\n-- build source files\nfunction sandbox_core_tool_compiler.build(sourcefiles, targetfile, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get source kind if only one source file\n    local sourcekind = opt.sourcekind\n    if not sourcekind and type(sourcefiles) == \"string\" then\n        sourcekind = language.sourcekind_of(sourcefiles)\n    end\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- build it\n    local ok, errors = instance:build(sourcefiles, targetfile, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get the current compiler name of given language kind\n--\n-- @param langkind      the language kind, e.g. c, cxx, mm, mxx, swift, go, rust, d, as\n--\n-- @return              the compiler name\n--\nfunction sandbox_core_tool_compiler.name(langkind, opt)\n\n    -- get sourcekind from the language kind\n    local sourcekind = language.langkinds()[langkind]\n    assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n    return instance:name()\nend\n\n-- get all compiler features\n--\n-- @param langkind      the language kind, e.g. c, cxx, mm, mxx, swift, go, rust, d, as\n-- @param opt           the argument options (contain all the compiler attributes of target),\n--                      e.g. {target = ..., targetkind = \"static\", cxflags = \"\", defines = \"\", includedirs = \"\", ...}\n--\n-- @return              the features\n--\nfunction sandbox_core_tool_compiler.features(langkind, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get sourcekind from the language kind\n    local sourcekind = language.langkinds()[langkind]\n    assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- import \"lib.detect.features\"\n    sandbox_core_tool_compiler._features = sandbox_core_tool_compiler._features or import(\"lib.detect.features\")\n    if sandbox_core_tool_compiler._features then\n\n        -- get flags\n        local flags = instance:compflags(opt)\n\n        -- get features\n        local ok, results_or_errors = sandbox.load(sandbox_core_tool_compiler._features, instance:name(), {flags = flags, program = instance:program(), envs = instance:runenvs()})\n        if not ok then\n            raise(results_or_errors)\n        end\n\n        -- return features\n        return results_or_errors\n    end\n\n    -- no features\n    return {}\nend\n\n-- has the given features?\n--\n-- @param features      the features, e.g. {\"c_static_assert\", \"cxx_constexpr\"}\n-- @param opt           the argument options (contain all the compiler attributes of target),\n--                      e.g. {target = ..., targetkind = \"static\", cxflags = \"\", defines = \"\", includedirs = \"\", ...}\n--\n-- @return              the true or false\n--\nfunction sandbox_core_tool_compiler.has_features(features, opt)\n\n    -- import \"lib.detect.has_features\"\n    sandbox_core_tool_compiler._has_features = sandbox_core_tool_compiler._has_features or import(\"lib.detect.has_features\")\n    if not sandbox_core_tool_compiler._has_features then\n        return\n    end\n\n    -- classify features by the source kind\n    opt = opt or {}\n    local features_by_kind = {}\n    local langkinds = language.langkinds()\n    for _, feature in ipairs(table.wrap(features)) do\n\n        -- get language kind\n        local langkind = feature:match(\"^(%w-)_\")\n        assert(langkind, \"unknown language kind for the feature: %s\", feature)\n\n        -- get the sourcekind from the language kind\n        local sourcekind = langkinds[langkind]\n        assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n        -- add feature\n        features_by_kind[sourcekind] = features_by_kind[sourcekind] or {}\n        table.insert(features_by_kind[sourcekind], feature)\n    end\n\n    -- has features for each compiler?\n    for sourcekind, features in pairs(features_by_kind) do\n        local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n        local flags = instance:compflags(opt)\n        local ok, results_or_errors = sandbox.load(sandbox_core_tool_compiler._has_features, instance:name(), features, {flags = flags, program = instance:program(), envs = instance:runenvs()})\n        if not ok then\n            raise(results_or_errors)\n        end\n        if not results_or_errors then\n            return false\n        end\n    end\n    return true\nend\n\n-- has the given flags?\n--\n-- @param langkind      the language kind, e.g. c, cxx, mm, mxx, swift, go, rust, d, as\n-- @param flags         the flags\n-- @param opt           the options\n--\n-- @return              the supported flags or nil\n--\nfunction sandbox_core_tool_compiler.has_flags(langkind, flags, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get sourcekind from the language kind\n    local sourcekind = language.langkinds()[langkind]\n    assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- has flags?\n    return instance:has_flags(flags)\nend\n\n-- map flags from name and values\n--\n-- @param langkind      the language kind, e.g. c, cxx, mm, mxx, swift, go, rust, d, as\n-- @param name          the name, e.g. includedirs, defines, links\n-- @param values        the values\n-- @param opt           the options\n--\n-- @return              flags or nil\n--\nfunction sandbox_core_tool_compiler.map_flags(langkind, name, values, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get sourcekind from the language kind\n    local sourcekind = language.langkinds()[langkind]\n    assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n    -- get the compiler instance\n    local instance = sandbox_core_tool_compiler.load(sourcekind, opt)\n\n    -- map flags\n    return instance:map_flags(name, values, opt)\nend\n\n-- return module\nreturn sandbox_core_tool_compiler\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/tool/linker.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linker.lua\n--\n\n-- define module\nlocal sandbox_core_tool_linker = sandbox_core_tool_linker or {}\n\n-- load modules\nlocal platform  = require(\"platform/platform\")\nlocal linker    = require(\"tool/linker\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- load the linker from the given target kind\nfunction sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n    local instance, errors = linker.load(targetkind, sourcekinds, opt and opt.target or nil)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- make command for linking target file\nfunction sandbox_core_tool_linker.linkcmd(targetkind, sourcekinds, objectfiles, targetfile, opt)\n    return os.args(table.join(sandbox_core_tool_linker.linkargv(targetkind, sourcekinds, objectfiles, targetfile, opt)))\nend\n\n-- make arguments list for linking target file\nfunction sandbox_core_tool_linker.linkargv(targetkind, sourcekinds, objectfiles, targetfile, opt)\n    opt = opt or {}\n    local instance = sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n    return instance:linkargv(objectfiles, targetfile, opt)\nend\n\n-- make link flags for the given target\n--\n-- @param targetkind    the target kind\n-- @param sourcekinds   the source kinds\n-- @param opt           the argument options (contain all the linker attributes of target),\n--                      e.g. {target = ..., targetkind = \"static\", config = {cxflags = \"\", defines = \"\", includedirs = \"\", ...}}\n--\nfunction sandbox_core_tool_linker.linkflags(targetkind, sourcekinds, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get the linker instance\n    local instance = sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n\n    -- make flags\n    return instance:linkflags(opt)\nend\n\n-- link target file\nfunction sandbox_core_tool_linker.link(targetkind, sourcekinds, objectfiles, targetfile, opt)\n    opt = opt or {}\n    local instance = sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n    local ok, errors = instance:link(objectfiles, targetfile, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- has the given flags?\n--\n-- @param targetkind    the target kind\n-- @param sourcekinds   the source kinds\n-- @param flags         the flags\n-- @param opt           the options\n--\n-- @return              the supported flags or nil\n--\nfunction sandbox_core_tool_linker.has_flags(targetkind, sourcekinds, flags, opt)\n    opt = opt or {}\n    local instance = sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n    return instance:has_flags(flags)\nend\n\n-- map flags from name and values\n--\n-- @param targetkind    the target kind\n-- @param sourcekinds   the source kinds\n-- @param values        the values\n-- @param opt           the options\n--\n-- @return              flags or nil\n--\nfunction sandbox_core_tool_linker.map_flags(targetkind, sourcekinds, name, values, opt)\n    opt = opt or {}\n    local instance = sandbox_core_tool_linker.load(targetkind, sourcekinds, opt)\n    return instance:map_flags(name, values, opt)\nend\n\n-- return module\nreturn sandbox_core_tool_linker\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/tool/toolchain.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        toolchain.lua\n--\n\n-- define module\nlocal sandbox_core_tool_toolchain = sandbox_core_tool_toolchain or {}\n\n-- load modules\nlocal platform  = require(\"platform/platform\")\nlocal toolchain = require(\"tool/toolchain\")\nlocal project   = require(\"project/project\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- inherit some builtin interfaces\nsandbox_core_tool_toolchain.apis        = toolchain.apis\nsandbox_core_tool_toolchain.directories = toolchain.directories\nsandbox_core_tool_toolchain.save        = toolchain.save\n\n-- get all toolchains list\nfunction sandbox_core_tool_toolchain.list()\n    local names = table.copy(platform.toolchains())\n    if os.isfile(os.projectfile()) then\n        for _, name in ipairs(project.toolchains()) do\n            table.insert(names, name)\n        end\n    end\n    return names\nend\n\n-- load the toolchain from the given name\nfunction sandbox_core_tool_toolchain.load(name, opt)\n    local instance, errors = toolchain.load(name, opt)\n    if not instance then\n        raise(errors)\n    end\n    return instance\nend\n\n-- return module\nreturn sandbox_core_tool_toolchain\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/action.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        action.lua\n--\n\n-- return module: action\nreturn require(\"ui/action\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/application.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, TBOOX Open Source application.\n--\n-- @author      ruki\n-- @file        application.lua\n--\n\n-- load module: application\nreturn require(\"ui/application\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/border.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        border.lua\n--\n\n-- return module: border\nreturn require(\"ui/border\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/boxdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        boxdialog.lua\n--\n\n-- return module: boxdialog\nreturn require(\"ui/boxdialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/button.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        button.lua\n--\n\n-- return module: button\nreturn require(\"ui/button\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/canvas.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        canvas.lua\n--\n\n-- load modules\nreturn require(\"ui/canvas\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/choicebox.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        choicebox.lua\n--\n\n-- return module: choicebox\nreturn require(\"ui/choicebox\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/choicedialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        choicedialog.lua\n--\n\n-- return module: choicedialog\nreturn require(\"ui/choicedialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/curses.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        curses.lua\n--\n\n-- return module: curses\nreturn require(\"ui/curses\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/desktop.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        desktop.lua\n--\n\n-- return module: desktop\nreturn require(\"ui/desktop\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/dialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dialog.lua\n--\n\n-- return module: dialog\nreturn require(\"ui/dialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/event.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        event.lua\n--\n\n-- return module: event\nreturn require(\"ui/event\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/inputdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        inputdialog.lua\n--\n\n-- return module: inputdialog\nreturn require(\"ui/inputdialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/label.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        label.lua\n--\n\n-- return module: label\nreturn require(\"ui/label\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/log.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        log.lua\n--\n\n-- return module: log\nreturn require(\"ui/log\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/mconfdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mconfdialog.lua\n--\n\n-- return module: mconfdialog\nreturn require(\"ui/mconfdialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/menubar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menubar.lua\n--\n\n-- return module: menubar\nreturn require(\"ui/menubar\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/menuconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menuconf.lua\n--\n\n-- return module: menuconf\nreturn require(\"ui/menuconf\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/object.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        object.lua\n--\n\n-- return module: object\nreturn require(\"ui/object\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/panel.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        panel.lua\n--\n\n-- return module: panel\nreturn require(\"ui/panel\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/point.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        point.lua\n--\n\n-- return module: point\nreturn require(\"ui/point\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/program.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, TBOOX Open Source program.\n--\n-- @author      ruki\n-- @file        program.lua\n--\n\n-- return module: program\nreturn require(\"ui/program\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/rect.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rect.lua\n--\n\n-- return module: rect\nreturn require(\"ui/rect\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/statusbar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        statusbar.lua\n--\n\n-- return module: statusbar\nreturn require(\"ui/statusbar\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/textarea.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textarea.lua\n--\n\n-- return module: textarea\nreturn require(\"ui/textarea\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/textdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textdialog.lua\n--\n\n-- return module: textdialog\nreturn require(\"ui/textdialog\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/textedit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textedit.lua\n--\n\n-- return module: textedit\nreturn require(\"ui/textedit\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/view.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        view.lua\n--\n\n-- return module: view\nreturn require(\"ui/view\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/core/ui/window.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        window.lua\n--\n\n-- return module: window\nreturn require(\"ui/window\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_directory.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_directory.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_directory = sandbox_lib_detect_find_directory or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal raise     = require(\"sandbox/modules/raise\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\nlocal xmake     = require(\"base/xmake\")\n\n-- expand search paths\nfunction sandbox_lib_detect_find_directory._expand_paths(paths)\n    local results = {}\n    for _, _path in ipairs(table.wrap(paths)) do\n        if type(_path) == \"function\" then\n            local ok, result_or_errors = sandbox.load(_path)\n            if ok then\n                _path = result_or_errors or \"\"\n            else\n                raise(result_or_errors)\n            end\n        else\n            _path = vformat(_path)\n        end\n        for _, _s_path in ipairs(table.wrap(_path)) do\n            _s_path = tostring(_s_path)\n            if #_s_path > 0 then\n                table.insert(results, _s_path)\n            end\n        end\n    end\n    return results\nend\n\n-- normalize suffixes\nfunction sandbox_lib_detect_find_directory._normalize_suffixes(suffixes)\n    local results = {}\n    for _, suffix in ipairs(table.wrap(suffixes)) do\n        suffix = tostring(suffix)\n        if #suffix > 0 then\n            table.insert(results, suffix)\n        end\n    end\n    return results\nend\n\n-- find directory from directories list\nfunction sandbox_lib_detect_find_directory._find_from_directories(name, directories, suffixes)\n    directories = table.wrap(directories)\n    suffixes = table.wrap(suffixes)\n    if #suffixes > 0 then\n        for _, directory in ipairs(directories) do\n            for _, suffix in ipairs(suffixes) do\n                local results = os.dirs(path.join(directory, suffix, name), function (file, isdir) return false end)\n                if results and #results > 0 then\n                    return results[1]\n                end\n            end\n        end\n    else\n        for _, directory in ipairs(directories) do\n            local results = os.dirs(path.join(directory, name), function (file, isdir) return false end)\n            if results and #results > 0 then\n                return results[1]\n            end\n        end\n    end\nend\n\n-- find directory\n--\n-- @param name      the directory name\n-- @param paths     the search paths (e.g. dirs, paths, winreg paths)\n-- @param opt       the options, e.g. {suffixes = {\"/aa\", \"/bb\"}}\n--\n-- @return          the directory path\n--\n-- @code\n--\n-- local dir = find_directory(\"bin\", { \"/usr\", \"/usr/local\"})\n-- local dir = find_directory(\"xxx/test\", { \"/usr/include\", \"/usr/local/include/**\"})\n-- local dir = find_directory(\"xxx/test\", { \"$(env PATH)\", \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name)\"})\n-- local dir = find_directory(\"xxx/test/dir*\", { \"$(env PATH)\", function () return val(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name\"):match(\"\\\"(.-)\\\"\") end})\n--\n-- @endcode\n--\nfunction sandbox_lib_detect_find_directory.main(name, paths, opt)\n\n    -- init options\n    opt = opt or {}\n\n    local suffixes = sandbox_lib_detect_find_directory._normalize_suffixes(opt.suffixes)\n    local directories = sandbox_lib_detect_find_directory._expand_paths(paths)\n\n    if opt.async and xmake.in_main_thread() then\n        local result, _ = os._async_task().find_directory(name, directories, {suffixes = suffixes})\n        return result\n    end\n\n    return sandbox_lib_detect_find_directory._find_from_directories(name, directories, suffixes)\nend\n\n-- return module\nreturn sandbox_lib_detect_find_directory\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_file.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_file.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_file = sandbox_lib_detect_find_file or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal profiler  = require(\"base/profiler\")\nlocal raise     = require(\"sandbox/modules/raise\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\nlocal xmake     = require(\"base/xmake\")\n\n-- expand search paths\nfunction sandbox_lib_detect_find_file._expand_paths(paths)\n    local results = {}\n    for _, _path in ipairs(table.wrap(paths)) do\n        if type(_path) == \"function\" then\n            local ok, result_or_errors = sandbox.load(_path)\n            if ok then\n                _path = result_or_errors or \"\"\n            else\n                raise(result_or_errors)\n            end\n        elseif type(_path) == \"string\" then\n            if _path:match(\"^%$%(env .+%)$\") then\n                _path = path.splitenv(vformat(_path))\n            else\n                _path = vformat(_path)\n            end\n        end\n        for _, _s_path in ipairs(table.wrap(_path)) do\n            _s_path = tostring(_s_path)\n            if #_s_path > 0 then\n                table.insert(results, _s_path)\n            end\n        end\n    end\n    return results\nend\n\n-- normalize suffixes\nfunction sandbox_lib_detect_find_file._normalize_suffixes(suffixes)\n    local results = {}\n    for _, suffix in ipairs(table.wrap(suffixes)) do\n        suffix = tostring(suffix)\n        if #suffix > 0 then\n            table.insert(results, suffix)\n        end\n    end\n    return results\nend\n\n-- find from directories list\nfunction sandbox_lib_detect_find_file._find_from_directories(name, directories, suffixes)\n    local results\n    suffixes = table.wrap(suffixes)\n    directories = table.wrap(directories)\n    if #suffixes > 0 then\n        for _, directory in ipairs(directories) do\n            for _, suffix in ipairs(suffixes) do\n                local filedir = path.join(directory, suffix)\n                results = sandbox_lib_detect_find_file._find(filedir, name)\n                if results then\n                    return results\n                end\n            end\n        end\n    else\n        for _, directory in ipairs(directories) do\n            results = sandbox_lib_detect_find_file._find(directory, name)\n            if results then\n                return results\n            end\n        end\n    end\nend\n\n-- find the given file path or directory\nfunction sandbox_lib_detect_find_file._find(filedir, name)\n\n    -- get file path\n    local filepath = nil\n    if os.isfile(filedir) then\n        filepath = filedir\n    else\n        filepath = path.join(filedir, name)\n    end\n\n    -- find the first file\n    local results = os.files(filepath, function (file, isdir) return false end)\n    if results and #results > 0 then\n        return results[1]\n    end\nend\n\n-- find file\n--\n-- @param name      the file name\n-- @param paths     the search paths (e.g. dirs, paths, winreg paths)\n-- @param opt       the options, e.g. {suffixes = {\"/aa\", \"/bb\"}}\n--\n-- @return          the file path\n--\n-- @code\n--\n-- local file = find_file(\"ccache\", { \"/usr/bin\", \"/usr/local/bin\"})\n-- local file = find_file(\"test.h\", { \"/usr/include\", \"/usr/local/include/**\"})\n-- local file = find_file(\"xxx.h\", { \"$(env PATH)\", \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name)\"})\n-- local file = find_file(\"xxx.h\", { \"$(env PATH)\", function () return val(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name\"):match(\"\\\"(.-)\\\"\") end})\n--\n-- @endcode\n--\nfunction sandbox_lib_detect_find_file.main(name, paths, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find file\n    profiler:enter(\"find_file\", name)\n    local suffixes = sandbox_lib_detect_find_file._normalize_suffixes(opt.suffixes)\n    local directories = sandbox_lib_detect_find_file._expand_paths(paths)\n\n    -- run in async task?\n    if opt.async and xmake.in_main_thread() then\n        local result, _ = os._async_task().find_file(name, directories, {suffixes = suffixes})\n        profiler:leave(\"find_file\", name)\n        return result\n    end\n\n    local results = sandbox_lib_detect_find_file._find_from_directories(name, directories, suffixes)\n    profiler:leave(\"find_file\", name)\n    return results\nend\n\n-- return module\nreturn sandbox_lib_detect_find_file\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_library.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_library.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_library = sandbox_lib_detect_find_library or {}\n\n-- load modules\nlocal os                = require(\"base/os\")\nlocal path              = require(\"base/path\")\nlocal utils             = require(\"base/utils\")\nlocal table             = require(\"base/table\")\nlocal config            = require(\"project/config\")\nlocal target            = require(\"project/target\")\nlocal raise             = require(\"sandbox/modules/raise\")\nlocal import            = require(\"sandbox/modules/import\")\nlocal xmake             = require(\"base/xmake\")\nlocal find_file         = import(\"lib.detect.find_file\")\n\n-- find library from directories list\nfunction sandbox_lib_detect_find_library._find_from_directories(names, directories, kinds, suffixes, opt)\n    names = table.wrap(names)\n    directories = table.wrap(directories)\n    kinds = table.wrap(kinds)\n    suffixes = table.wrap(suffixes)\n    if #kinds == 0 then\n        kinds = {\"static\", \"shared\"}\n    end\n    opt = opt or {}\n    local plat = opt.plat\n    for _, name in ipairs(names) do\n        for _, kind in ipairs(kinds) do\n            local filename = target.filename(name, kind, {plat = plat})\n            local filepath = find_file._find_from_directories(filename, directories, suffixes)\n            if plat == \"mingw\" then\n                if not filepath and kind == \"shared\" then\n                    filepath = find_file._find_from_directories(filename .. \".a\", directories, suffixes)\n                end\n                if not filepath then\n                    filepath = find_file._find_from_directories(target.filename(name, kind, {plat = \"windows\"}), directories, suffixes)\n                end\n            end\n            if filepath then\n                local linkname = target.linkname(path.filename(filepath), {plat = plat})\n                return {kind = kind, filename = path.filename(filepath), linkdir = path.directory(filepath), link = linkname}\n            end\n        end\n    end\nend\n\n-- find library\n--\n-- @param names     the library names\n-- @param paths     the search paths\n-- @param opt       the options, e.g. {kind = \"static/shared\", suffixes = {\"/aa\", \"/bb\"}}\n--\n-- @return          {kind = \"static\", link = \"crypto\", linkdir = \"/usr/local/lib\", filename = \"libcrypto.a\", plat = ..}\n--\n-- @code\n--\n-- local library = find_library({\"crypto\", \"cryp*\"}, {\"/usr/lib\", \"/usr/local/lib\"})\n-- local library = find_library(\"crypto\", {\"/usr/lib\", \"/usr/local/lib\"}, {kind = \"static\"})\n--\n-- @endcode\n--\nfunction sandbox_lib_detect_find_library.main(names, paths, opt)\n\n    -- no paths?\n    if not paths or #paths == 0 then\n        return\n    end\n\n    -- find library file from the given paths\n    opt = opt or {}\n    local directories = find_file._expand_paths(paths)\n    local suffixes = find_file._normalize_suffixes(opt.suffixes)\n    local kinds = table.wrap(opt.kind or {\"static\", \"shared\"})\n\n    if opt.async and xmake.in_main_thread() then\n        local result, _ = os._async_task().find_library(names, directories, kinds, {suffixes = suffixes, plat = opt.plat})\n        return result\n    end\n\n    return sandbox_lib_detect_find_library._find_from_directories(names, directories, kinds, suffixes, {plat = opt.plat})\nend\n\n-- return module\nreturn sandbox_lib_detect_find_library\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_path.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_path.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_path = sandbox_lib_detect_find_path or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal table     = require(\"base/table\")\nlocal profiler  = require(\"base/profiler\")\nlocal raise     = require(\"sandbox/modules/raise\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\nlocal xmake     = require(\"base/xmake\")\n\n-- expand search paths\nfunction sandbox_lib_detect_find_path._expand_paths(paths)\n    local results = {}\n    for _, _path in ipairs(table.wrap(paths)) do\n        if type(_path) == \"function\" then\n            local ok, result_or_errors = sandbox.load(_path)\n            if ok then\n                _path = result_or_errors or \"\"\n            else\n                raise(result_or_errors)\n            end\n        else\n            _path = vformat(_path)\n        end\n        for _, _s_path in ipairs(table.wrap(_path)) do\n            _s_path = tostring(_s_path)\n            if #_s_path > 0 then\n                table.insert(results, _s_path)\n            end\n        end\n    end\n    return results\nend\n\n-- normalize suffixes\nfunction sandbox_lib_detect_find_path._normalize_suffixes(suffixes)\n    local results = {}\n    for _, suffix in ipairs(table.wrap(suffixes)) do\n        suffix = tostring(suffix)\n        if #suffix > 0 then\n            table.insert(results, suffix)\n        end\n    end\n    return results\nend\n\n-- find the given file path or directory\nfunction sandbox_lib_detect_find_path._find(filedir, name)\n\n    -- find the first path\n    local results = os.filedirs(path.join(filedir, name), function (file, isdir) return false end)\n    if results and #results > 0 then\n        local filepath = results[1]\n        if filepath then\n            -- we need to translate name first, https://github.com/xmake-io/xmake-repo/issues/1315\n\t    local p = filepath:lastof(path.pattern(path.translate(name)))\n            if p then\n                filepath = path.translate(filepath:sub(1, p - 1))\n                if os.isdir(filepath) then\n                    return filepath\n                else\n                    return path.directory(filepath)\n                end\n            end\n        end\n\n    end\nend\n\n-- find from directories list\nfunction sandbox_lib_detect_find_path._find_from_directories(name, directories, suffixes)\n    local results\n    suffixes = table.wrap(suffixes)\n    directories = table.wrap(directories)\n    if #suffixes > 0 then\n        for _, directory in ipairs(directories) do\n            for _, suffix in ipairs(suffixes) do\n                local filedir = path.join(directory, suffix)\n                results = sandbox_lib_detect_find_path._find(filedir, name)\n                if results then\n                    return results\n                end\n            end\n        end\n    else\n        for _, directory in ipairs(directories) do\n            results = sandbox_lib_detect_find_path._find(directory, name)\n            if results then\n                return results\n            end\n        end\n    end\nend\n\n-- find path\n--\n-- @param name      the path name\n-- @param paths     the search paths (e.g. dirs, paths, winreg paths)\n-- @param opt       the options, e.g. {suffixes = {\"/aa\", \"/bb\"}}\n--\n-- @return          the path\n--\n-- @code\n--\n-- local p = find_path(\"include/test.h\", { \"/usr\", \"/usr/local\"})\n--  -> /usr/local (\"/usr/local/include/test.h\")\n--\n-- local p = find_path(\"include/*.h\", { \"/usr\", \"/usr/local/**\"})\n-- local p = find_path(\"lib/xxx\", { \"$(env PATH)\", \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name)\"})\n-- local p = find_path(\"lib/xxx\", { \"$(env PATH)\", function () return val(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name\"):match(\"\\\"(.-)\\\"\") end})\n--\n-- @endcode\n--\nfunction sandbox_lib_detect_find_path.main(name, paths, opt)\n\n    -- init options\n    opt = opt or {}\n\n    profiler:enter(\"find_path\", name)\n    local suffixes = sandbox_lib_detect_find_path._normalize_suffixes(opt.suffixes)\n    local directories = sandbox_lib_detect_find_path._expand_paths(paths)\n\n    if opt.async and xmake.in_main_thread() then\n        local result, _ = os._async_task().find_path(name, directories, {suffixes = suffixes})\n        profiler:leave(\"find_path\", name)\n        return result\n    end\n\n    local results = sandbox_lib_detect_find_path._find_from_directories(name, directories, suffixes)\n    profiler:leave(\"find_path\", name)\n    return results\nend\n\n-- return module\nreturn sandbox_lib_detect_find_path\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_program.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_program.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_program = sandbox_lib_detect_find_program or {}\n\n-- load modules\nlocal os          = require(\"base/os\")\nlocal path        = require(\"base/path\")\nlocal winos       = require(\"base/winos\")\nlocal table       = require(\"base/table\")\nlocal utils       = require(\"base/utils\")\nlocal option      = require(\"base/option\")\nlocal profiler    = require(\"base/profiler\")\nlocal project     = require(\"project/project\")\nlocal detectcache = require(\"cache/detectcache\")\nlocal sandbox     = require(\"sandbox/sandbox\")\nlocal package     = require(\"package/package\")\nlocal raise       = require(\"sandbox/modules/raise\")\nlocal vformat     = require(\"sandbox/modules/vformat\")\nlocal scheduler   = require(\"sandbox/modules/import/core/base/scheduler\")\n\n-- do check\nfunction sandbox_lib_detect_find_program._do_check(program, opt)\n\n    -- do not attempt to run program? check it fastly\n    if opt.norun then\n        return os.isfile(program)\n    elseif opt.norunfile and path.is_absolute(program) and os.isfile(program) then\n        return true\n    end\n\n    -- no check script? attempt to run it directly\n    if not opt.check then\n        local ok, errors = os.runv(program, {\"--version\"}, {envs = opt.envs, shell = opt.shell})\n        if not ok and option.get(\"verbose\") and option.get(\"diagnosis\") then\n            utils.cprint(\"${color.warning}checkinfo: ${clear dim}\" .. errors)\n        end\n        return ok\n    end\n\n    -- check it\n    local ok = false\n    local errors = nil\n    if type(opt.check) == \"string\" then\n        ok, errors = os.runv(program, {opt.check}, {envs = opt.envs, shell = opt.shell})\n    elseif type(opt.check) == \"table\" then\n        ok, errors = os.runv(program, opt.check, {envs = opt.envs, shell = opt.shell})\n    else\n        ok, errors = sandbox.load(opt.check, program)\n    end\n\n    -- check failed? print verbose error info\n    if not ok and option.get(\"verbose\") and option.get(\"diagnosis\") then\n        utils.cprint(\"${color.warning}checkinfo: ${clear dim}\" .. errors)\n    end\n    return ok\nend\n\n-- check program\nfunction sandbox_lib_detect_find_program._check(program, opt)\n    opt = opt or {}\n    local findname = program\n    if os.subhost() == \"windows\" then\n        local ext = path.extension(program):lower()\n        if not opt.shell and ext ~= \".exe\" and ext ~= \".cmd\" and ext ~= \".bat\" then\n            findname = program .. \".exe\"\n        end\n    elseif os.subhost() == \"msys\" and os.isfile(program) and os.filesize(program) < 256 then\n        -- only a sh script on msys2? e.g. c:/msys64/usr/bin/7z\n        -- we need to use sh to wrap it, otherwise os.exec cannot run it\n        local ext = path.extension(program):lower()\n        if ext ~= \".exe\" and ext ~= \".cmd\" and ext ~= \".bat\" then\n            program = \"sh \" .. program\n        end\n        findname = program\n    end\n    if sandbox_lib_detect_find_program._do_check(findname, opt) then\n        return program\n    -- check \"zig c++\" without \".exe\"\n    -- https://github.com/xmake-io/xmake/issues/2232\n    elseif findname ~= program and path.filename(program):find(\" \", 1, true) and\n        sandbox_lib_detect_find_program._do_check(program, opt) then\n        return program\n    end\nend\n\n-- find program from the given paths\nfunction sandbox_lib_detect_find_program._find_from_paths(name, paths, opt)\n\n    -- attempt to check it from the given directories\n    if not path.is_absolute(name) then\n        for _, _path in ipairs(table.wrap(paths)) do\n\n            -- format path for builtin variables\n            if type(_path) == \"function\" then\n                local ok, results = sandbox.load(_path)\n                if ok then\n                    _path = results or \"\"\n                else\n                    raise(results)\n                end\n            elseif type(_path) == \"string\" then\n                if _path:match(\"^%$%(env .+%)$\") then\n                    _path = path.splitenv(vformat(_path))\n                else\n                    _path = vformat(_path)\n                end\n            end\n\n            for _, _s_path in ipairs(table.wrap(_path)) do\n\n                -- get program path\n                local program_path = nil\n                if os.isfile(_s_path) then\n                    program_path = _s_path\n                elseif os.isdir(_s_path) then\n                    program_path = path.join(_s_path, name)\n                end\n\n                -- the program path\n                if program_path and (os.isexec(program_path) or os.isexec(program_path:split(\"%s\")[1])) then\n                    local program_path_real = sandbox_lib_detect_find_program._check(program_path, opt)\n                    if program_path_real then\n                        return program_path_real\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- find program from the xmake packages\nfunction sandbox_lib_detect_find_program._find_from_packages(name, opt)\n\n    -- get the manifest file of package, e.g. ~/.xmake/packages/g/git/1.1.12/ed41d5327fad3fc06fe376b4a94f62ef/manifest.txt\n    opt = opt or {}\n    local installdir = opt.installdir or path.join(package.installdir(), name:sub(1, 1), name, opt.require_version, opt.buildhash)\n    local manifest_file = path.join(installdir, \"manifest.txt\")\n    if not os.isfile(manifest_file) then\n        return\n    end\n\n    -- get install directory of this package\n    local installdir = path.directory(manifest_file)\n\n    -- init paths\n    local paths = {}\n    local manifest = io.load(manifest_file)\n    if manifest and manifest.envs then\n        local pathenvs = manifest.envs.PATH\n        if pathenvs then\n            for _, pathenv in ipairs(pathenvs) do\n                table.insert(paths, path.join(installdir, pathenv))\n            end\n        end\n    end\n\n    -- find it\n    return sandbox_lib_detect_find_program._find_from_paths(name, paths, opt)\nend\n\n-- find program\nfunction sandbox_lib_detect_find_program._find(name, paths, opt)\n\n    -- attempt to find it from the given directories\n    local program_path = sandbox_lib_detect_find_program._find_from_paths(name, paths, opt)\n    if program_path and opt.system ~= false then\n        return program_path\n    end\n\n    -- attempt to find it from the xmake packages\n    if opt.require_version and opt.buildhash and opt.system ~= true then\n        return sandbox_lib_detect_find_program._find_from_packages(name, opt)\n    end\n\n    -- we will not continue to find system program\n    if opt.system == false then\n        return\n    end\n\n    -- attempt to find it from regists\n    if os.host() == \"windows\" then\n        local program_name = name:lower()\n        if not program_name:endswith(\".exe\") then\n            program_name = program_name .. \".exe\"\n        end\n        if path.is_absolute(program_name) and os.isfile(program_name) then\n            program_path = program_name\n        else\n            program_path = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths\\\\\" .. program_name)\n        end\n        if program_path then\n            program_path = program_path:trim()\n            if os.isexec(program_path) then\n                local program_path_real = sandbox_lib_detect_find_program._check(program_path, opt)\n                if program_path_real then\n                    return program_path_real\n                end\n            end\n        end\n    else\n        if path.is_absolute(name) and os.isfile(name) then\n            program_path = name\n        else\n            -- attempt to find it use `which program` command\n            local ok, result = os.iorunv(\"which\", {name})\n            if ok and result then\n                program_path = result:trim()\n            else\n                program_path = nil\n            end\n        end\n\n        if program_path then\n            local program_path_real = sandbox_lib_detect_find_program._check(program_path, opt)\n            if program_path_real then\n                return program_path_real\n            end\n        end\n    end\n\n    -- attempt to find it from the some default $PATH and system directories\n    local syspaths = {}\n    --[[\n    local envpaths = os.getenv(\"PATH\")\n    if envpaths then\n        table.join2(syspaths, path.splitenv(envpaths))\n    end]]\n    if os.host() ~= \"windows\" or os.is_subhost(\"msys\", \"cygwin\") then\n        table.insert(syspaths, \"/usr/local/bin\")\n        table.insert(syspaths, \"/usr/bin\")\n    end\n    if #syspaths > 0 then\n        program_path = sandbox_lib_detect_find_program._find_from_paths(name, syspaths, opt)\n        if program_path then\n            return program_path\n        end\n    end\n\n    -- attempt to find it use `where.exe program.exe` command\n    -- and we need to add `.exe` suffix to avoid find some incorrect programs. e.g. pkg-config.bat\n    --\n    -- it will return the absolute path, so we call it first\n    -- https://github.com/xmake-io/xmake/discussions/6223#discussioncomment-12537122\n    --\n    if os.host() == \"windows\" then\n        local program_name = name:lower()\n        if not program_name:endswith(\".exe\") then\n            program_name = program_name .. \".exe\"\n        end\n        local ok, wherepaths = os.iorunv(\"where.exe\", {program_name})\n        if ok and wherepaths then\n            for _, program_path in ipairs(wherepaths:split(\"\\n\")) do\n                program_path = program_path:trim()\n                if #program_path > 0 then\n                    local program_path_real = sandbox_lib_detect_find_program._check(program_path, opt)\n                    if program_path_real then\n                        return program_path_real\n                    end\n                end\n            end\n        end\n    end\n\n    -- attempt to find it directly in current environment\n    --\n    -- @note must be detected at the end, because full path is more accurate\n    --\n    local program_path_real = sandbox_lib_detect_find_program._check(name, opt)\n    if program_path_real then\n        return program_path_real\n    end\nend\n\n-- find program\n--\n-- @param name      the program name\n-- @param opt       the options, e.g. {paths = {\"/usr/bin\"}, check = function (program) os.run(\"%s -h\", program) end, verbose = true, force = true, cachekey = \"xxx\"}\n--                    - opt.paths     the program paths (e.g. dirs, paths, winreg paths, script paths)\n--                    - opt.check     the check script or command\n--                    - opt.norun     do not attempt to run program to check program fastly\n--                    - opt.norunfile do not attempt to run program to check program if it's valid file path.\n--                    - opt.system    true: only find it from system, false: only find it from xmake/packages\n--\n-- @return          the program name or path\n--\n-- @code\n--\n-- local program = find_program(\"ccache\")\n-- local program = find_program(\"ccache\", {paths = {\"/usr/bin\", \"/usr/local/bin\"}})\n-- local program = find_program(\"ccache\", {paths = {\"/usr/bin\", \"/usr/local/bin\"}, check = \"--help\"}) -- simple check command: ccache --help\n-- local program = find_program(\"ccache\", {paths = {\"/usr/bin\", \"/usr/local/bin\"}, check = function (program) os.run(\"%s -h\", program) end})\n-- local program = find_program(\"ccache\", {paths = {\"$(env PATH)\", \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger)\"}})\n-- local program = find_program(\"ccache\", {paths = {\"$(env PATH)\", function () return \"/usr/local/bin\" end}})\n-- local program = find_program(\"ccache\", {envs = {PATH = \"xxx\"}})\n--\n-- @endcode\n--\nfunction sandbox_lib_detect_find_program.main(name, opt)\n    opt = opt or {}\n\n    -- init cachekey\n    local cachekey = \"find_program\"\n    if opt.cachekey then\n        cachekey = cachekey .. \"_\" .. opt.cachekey\n    end\n\n    -- @see https://github.com/xmake-io/xmake/issues/4645\n    -- @note avoid detect the same program in the same time leading to deadlock if running in the coroutine (e.g. ccache)\n    local lockname = cachekey .. name\n    scheduler.co_lock(lockname)\n\n    -- attempt to get result from cache first\n    local result = detectcache:get2(cachekey, name)\n    if result ~= nil and not opt.force then\n        scheduler.co_unlock(lockname)\n        return result and result or nil\n    end\n\n    -- get paths from the opt.envs.PATH\n    -- @note the wrong `pathes` word will be discarded, but the interface parameters will still be compatible\n    local envs = opt.envs\n    local paths = opt.paths or opt.pathes\n    if envs and (envs.PATH or envs.path) then\n        local pathenv = envs.PATH or envs.path\n        if type(pathenv) == \"string\" then\n            pathenv = path.splitenv(pathenv)\n        end\n        paths = table.join(table.wrap(opt.paths or opt.pathes), pathenv)\n    end\n\n    -- find executable program\n    profiler:enter(\"find_program\", name)\n    result = sandbox_lib_detect_find_program._find(name, paths, opt)\n    profiler:leave(\"find_program\", name)\n\n    -- cache result\n    detectcache:set2(cachekey, name, result and result or false)\n\n    -- trace\n    if option.get(\"verbose\") or opt.verbose then\n        if result then\n            utils.cprint(\"checking for %s ... ${color.success}%s\", name, (name == result and \"${text.success}\" or result))\n        else\n            utils.cprint(\"checking for %s ... ${color.nothing}${text.nothing}\", name)\n        end\n    end\n    scheduler.co_unlock(lockname)\n    return result\nend\n\n-- return module\nreturn sandbox_lib_detect_find_program\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/detect/find_programver.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_programver.lua\n--\n\n-- define module\nlocal sandbox_lib_detect_find_programver = sandbox_lib_detect_find_programver or {}\n\n-- load modules\nlocal os          = require(\"base/os\")\nlocal path        = require(\"base/path\")\nlocal table       = require(\"base/table\")\nlocal utils       = require(\"base/utils\")\nlocal option      = require(\"base/option\")\nlocal semver      = require(\"base/semver\")\nlocal profiler    = require(\"base/profiler\")\nlocal project     = require(\"project/project\")\nlocal detectcache = require(\"cache/detectcache\")\nlocal sandbox     = require(\"sandbox/sandbox\")\nlocal raise       = require(\"sandbox/modules/raise\")\nlocal scheduler   = require(\"sandbox/modules/import/core/base/scheduler\")\n\n-- find program version\n--\n-- @param program   the program\n-- @param opt       the options, e.g. {command = \"--version\", parse = \"(%d+%.?%d*%.?%d*.-)%s\", verbose = true, force = true, cachekey = \"xxx\"}\n--                    - opt.command   the version command string or script, default: --version\n--                    - opt.parse     the version parse script or lua match pattern\n--\n-- @return          the version string\n--\n-- @code\n-- local version = find_programver(\"ccache\")\n-- local version = find_programver(\"ccache\", {command = \"-v\"})\n-- local version = find_programver(\"ccache\", {command = \"--version\", parse = \"(%d+%.?%d*%.?%d*.-)%s\"})\n-- local version = find_programver(\"ccache\", {command = \"--version\", parse = function (output) return output:match(\"(%d+%.?%d*%.?%d*.-)%s\") end})\n-- local version = find_programver(\"ccache\", {command = function () return os.iorun(\"ccache --version\") end})\n-- @endcode\n--\nfunction sandbox_lib_detect_find_programver.main(program, opt)\n    opt = opt or {}\n\n    -- init cachekey\n    local cachekey = \"find_programver\"\n    if opt.cachekey then\n        cachekey = cachekey .. \"_\" .. opt.cachekey\n    end\n\n    -- @see https://github.com/xmake-io/xmake/issues/4645\n    -- @note avoid detect the same program in the same time leading to deadlock if running in the coroutine (e.g. ccache)\n    local lockname = cachekey .. program\n    scheduler.co_lock(lockname)\n\n    -- attempt to get result from cache first\n    local result = detectcache:get2(cachekey, program)\n    if result ~= nil and not opt.force then\n        scheduler.co_unlock(lockname)\n        return result and result or nil\n    end\n\n    -- attempt to get version output info\n    profiler:enter(\"find_programver\", program)\n    local ok = false\n    local outdata = nil\n    local command = opt.command\n    if type(command) == \"function\" then\n        ok, outdata = sandbox.load(command)\n        if not ok and outdata and option.get(\"diagnosis\") then\n            utils.cprint(\"${color.warning}checkinfo: ${clear dim}\" .. outdata)\n        end\n    elseif type(command) == \"table\" then\n        ok, outdata = os.iorunv(program, command, {envs = opt.envs})\n    else\n        ok, outdata = os.iorunv(program, {command or \"--version\"}, {envs = opt.envs})\n    end\n    profiler:leave(\"find_programver\", program)\n\n    -- find version info\n    if ok and outdata and #outdata > 0 then\n        local parse = opt.parse\n        if type(parse) == \"function\" then\n            ok, result = sandbox.load(parse, outdata)\n            if not ok and result and option.get(\"diagnosis\") then\n                utils.cprint(\"${color.warning}checkinfo: ${clear dim}\" .. result)\n                result = nil\n            end\n        elseif parse == nil or type(parse) == \"string\" then\n            result = semver.match(outdata, 1, parse)\n            if result then\n                result = result:rawstr()\n            end\n        end\n    end\n\n    -- save result\n    detectcache:set2(cachekey, program, result and result or false)\n    scheduler.co_unlock(lockname)\n    return result\nend\n\n-- return module\nreturn sandbox_lib_detect_find_programver\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/lni.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lni.lua\n--\n\n-- return module\nreturn _lni or {}\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/lua/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- load modules\nlocal string    = require(\"base/string\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_lib_lua_package = sandbox_lib_lua_package or {}\n\n-- load lua module from the dynamic library\n--\n-- @param libfile       the lib file, e.g. foo.dll, libfoo.so\n-- @param symbol        the export symbol name, e.g. luaopen_xxx\n--\nfunction sandbox_lib_lua_package.loadlib(libfile, symbol)\n    local script, errors = package.loadlib(libfile, symbol)\n    if not script then\n        raise(errors)\n    end\n    return script\nend\n\nreturn sandbox_lib_lua_package\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/luajit/bcsave.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bcsave.lua\n--\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal string    = require(\"base/string\")\nlocal raise     = require(\"sandbox/modules/raise\")\n\nif not xmake._LUAJIT then\n    print(debug.traceback())\n    return\nend\n\n-- save lua file to bitcode file\n--\n-- @param luafile       the lua file\n-- @param bcfile        the bitcode file\n-- @param opt           the arguments option, e.g. {strip = true, displaypath = \"/xxx/a.lua\", nocache = true}\n--\nfunction main(luafile, bcfile, opt)\n    opt = opt or {}\n    local result, errors = loadfile(luafile, \"bt\", {displaypath = opt.displaypath, nocache = opt.nocache})\n    if not result then\n        raise(errors)\n    end\n    result, errors = string._dump(result, opt.strip)\n    if not result then\n        raise(errors)\n    end\n    result, errors = io.writefile(bcfile, result)\n    if not result then\n        raise(errors)\n    end\nend\n\nreturn main\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/luajit/bit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bit.lua\n--\n\nif xmake._LUAJIT then\n    return require(\"bit\")\nend\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/luajit/ffi.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ffi.lua\n--\n\nif xmake._LUAJIT then\n    return require(\"ffi\")\nend\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/lib/luajit/jit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        jit.lua\n--\n\nif xmake._LUAJIT then\n    return require(\"jit\")\nend\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/private/core/base/is_cross.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_cross.lua\n--\n\nreturn require(\"base/private/is_cross\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/private/core/base/match_copyfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        match_copyfiles.lua\n--\n\nreturn require(\"base/private/match_copyfiles\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import/private/core/base/select_script.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        select_script.lua\n--\n\nreturn require(\"base/private/select_script\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/import.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        import.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/import/core/sandbox/module\").import\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/inherit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        inherit.lua\n--\n\n-- load modules\nreturn require(\"sandbox/modules/import/core/sandbox/module\").inherit\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/format.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        format.lua\n--\n\n-- return module\nreturn string.format\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/getenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        getenv.lua\n--\n\n-- return module\nreturn require(\"sandbox/modules/os\").getenv\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/hash.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        hash.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/hash\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/ipairs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ipairs.lua\n--\n\n-- load modules\nreturn require(\"sandbox/modules/ipairs\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/is_host.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_host.lua\n--\n\n-- return module\nreturn require(\"base/os\").is_host\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/is_subhost.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_subhost.lua\n--\n\n-- return module\nreturn require(\"base/os\").is_subhost\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/linuxos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linuxos.lua\n--\n\n-- load modules\nlocal linuxos = require(\"base/linuxos\")\n\n-- define module\nlocal sandbox_linuxos = sandbox_linuxos or {}\n\n-- export some readonly interfaces\nsandbox_linuxos.name      = linuxos.name\nsandbox_linuxos.version   = linuxos.version\nsandbox_linuxos.kernelver = linuxos.kernelver\n\n-- return module\nreturn sandbox_linuxos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/macos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        macos.lua\n--\n\n-- load modules\nlocal macos = require(\"base/macos\")\n\n-- define module\nlocal sandbox_macos = sandbox_macos or {}\n\n-- export some readonly interfaces\nsandbox_macos.version = macos.version\n\n-- return module\nreturn sandbox_macos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/math.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        math.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/math\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/os.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        os.lua\n--\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal string        = require(\"base/string\")\nlocal interpreter   = require(\"base/interpreter\")\n\n-- define module\nlocal sandbox_os = sandbox_os or {}\n\n-- export some readonly interfaces\nsandbox_os.term         = os.term\nsandbox_os.host         = os.host\nsandbox_os.arch         = os.arch\nsandbox_os.subhost      = os.subhost\nsandbox_os.subarch      = os.subarch\nsandbox_os.date         = os.date\nsandbox_os.time         = os.time\nsandbox_os.mtime        = os.mtime\nsandbox_os.mclock       = os.mclock\nsandbox_os.getenv       = os.getenv\nsandbox_os.isdir        = os.isdir\nsandbox_os.isfile       = os.isfile\nsandbox_os.exists       = os.exists\nsandbox_os.curdir       = os.curdir\nsandbox_os.tmpdir       = os.tmpdir\nsandbox_os.cpuinfo      = os.cpuinfo\nsandbox_os.default_njob = os.default_njob\nsandbox_os.filesize     = os.filesize\nsandbox_os.programdir   = os.programdir\nsandbox_os.programfile  = os.programfile\nsandbox_os.projectdir   = os.projectdir\nsandbox_os.projectfile  = os.projectfile\n\n-- match files\nfunction sandbox_os.files(pattern, ...)\n    return os.files(string.format(pattern, ...))\nend\n\n-- match directories\nfunction sandbox_os.dirs(pattern, ...)\n    return os.dirs(string.format(pattern, ...))\nend\n\n-- match file and directories\nfunction sandbox_os.filedirs(pattern, ...)\n    return os.filedirs(string.format(pattern, ...))\nend\n\n-- get the script directory\nfunction sandbox_os.scriptdir()\n    local instance = interpreter.instance()\n    assert(instance)\n    return instance:scriptdir()\nend\n\n-- return module\nreturn sandbox_os\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/pairs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pairs.lua\n--\n\n-- load modules\nreturn require(\"sandbox/modules/pairs\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/path.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        path.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/path\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/print.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        print.lua\n--\n\n-- load modules\nlocal table     = require(\"base/table\")\nlocal try       = require(\"sandbox/modules/try\")\nlocal catch     = require(\"sandbox/modules/catch\")\n\n-- print format string\nfunction _print(format, ...)\n\n    -- print format string\n    if type(format) == \"string\" and format:find(\"%\", 1, true) then\n\n        local args = {...}\n        try\n        {\n            function ()\n                -- attempt to print format string first\n                io.write(string.format(format, table.unpack(args)) .. \"\\n\")\n            end,\n            catch\n            {\n                function ()\n                    -- print multi-variables with raw lua action\n                    print(format, table.unpack(args))\n                end\n            }\n        }\n\n    else\n        -- print multi-variables with raw lua action\n        print(format, ...)\n    end\nend\n\n-- load module\nreturn _print\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/printf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        printf.lua\n--\n\n-- printf format string without newline\nfunction _printf(format, ...)\n\n    -- done\n    io.write(string.format(format, ...))\nend\n\n-- load module\nreturn _printf\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/string.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        string.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/string\")\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/table.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        table.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/table\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/tonumber.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tonumber.lua\n--\n\n-- load module\nreturn tonumber\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/tostring.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tostring.lua\n--\n\n-- load module\nreturn tostring\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/type.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        type.lua\n--\n\n-- load module\nreturn type\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/unpack.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        table.unpack.lua\n--\n\n-- load module\nreturn require(\"base/table\").unpack\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/utf8.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utf8.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utf8\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/winos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        winos.lua\n--\n\n-- load modules\nlocal winos = require(\"base/winos\")\n\n-- define module\nlocal sandbox_winos = sandbox_winos or {}\n\n-- export some readonly interfaces\nsandbox_winos.registry_query  = winos.registry_query\nsandbox_winos.registry_keys   = winos.registry_keys\nsandbox_winos.registry_values = winos.registry_values\nsandbox_winos.logical_drives  = winos.logical_drives\nsandbox_winos.version         = winos.version\n\n-- return module\nreturn sandbox_winos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/interpreter/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- load modules\nlocal xmake   = require(\"base/xmake\")\n\n-- define module\nlocal sandbox_xmake = sandbox_xmake or {}\n\n-- inherit some builtin interfaces\nsandbox_xmake.version     = xmake.version\nsandbox_xmake.programdir  = xmake.programdir\nsandbox_xmake.programfile = xmake.programfile\nsandbox_xmake.luajit      = xmake.luajit\n\n-- return module\nreturn sandbox_xmake\n"
  },
  {
    "path": "xmake/core/sandbox/modules/io.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        io.lua\n--\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal raise     = require(\"sandbox/modules/raise\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\n\n-- define module\nlocal sandbox_io          = sandbox_io or {}\nlocal sandbox_io_file     = sandbox_io_file or {}\nlocal sandbox_io_filelock = sandbox_io_filelock or {}\nsandbox_io.lines          = io.lines\n\n-- get file size\nfunction sandbox_io_file.size(file)\n    local result, errors = file:_size()\n    if not result then\n        raise(errors)\n    end\n    return result\nend\n\n-- get file rawfd\nfunction sandbox_io_file.rawfd(file)\n    local result, errors = file:_rawfd()\n    if not result then\n        raise(errors)\n    end\n    return result\nend\n\n-- close file\nfunction sandbox_io_file.close(file)\n    local ok, errors = file:_close()\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- flush file\nfunction sandbox_io_file.flush(file)\n    local ok, errors = file:_flush()\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- this file is a tty?\nfunction sandbox_io_file.isatty(file)\n    local ok, errors = file:_isatty()\n    if ok == nil then\n        raise(errors)\n    end\n    return ok\nend\n\n-- seek offset at file\nfunction sandbox_io_file.seek(file, whence, offset)\n    local result, errors = file:_seek(whence, offset)\n    if not result then\n        raise(errors)\n    end\n    return result\nend\n\n-- read data from file\nfunction sandbox_io_file.read(file, fmt, opt)\n    local result, errors = file:_read(fmt, opt)\n    if errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- readable for file\nfunction sandbox_io_file.readable(file)\n    local ok, errors = file:_readable()\n    if errors then\n        raise(errors)\n    end\n    return ok\nend\n\n-- write data to file\nfunction sandbox_io_file.write(file, ...)\n    local ok, errors = file:_write(...)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- print file\nfunction sandbox_io_file.print(file, ...)\n    sandbox_io_file.write(file, vformat(...), \"\\n\")\nend\n\n-- printf file\nfunction sandbox_io_file.printf(file, ...)\n    sandbox_io_file.write(file, vformat(...))\nend\n\n-- writef file (without value filter)\nfunction sandbox_io_file.writef(file, ...)\n    sandbox_io_file.write(file, string.format(...))\nend\n\n-- load object from file\nfunction sandbox_io_file.load(file)\n    local result, errors = file:_load()\n    if errors then\n        raise(errors)\n    end\n    return result\nend\n\n-- save object to file\nfunction sandbox_io_file.save(file, object, opt)\n    local ok, errors = file:_save(object, opt)\n    if not ok then\n        raise(errors)\n    end\n    return ok\nend\n\n-- lock filelock\nfunction sandbox_io_filelock.lock(lock, opt)\n    local ok, errors = lock:_lock(opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- unlock filelock\nfunction sandbox_io_filelock.unlock(lock)\n    local ok, errors = lock:_unlock()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- close filelock\nfunction sandbox_io_filelock.close(lock)\n    local ok, errors = lock:_close()\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- gsub the given file and return replaced data\nfunction sandbox_io.gsub(filepath, pattern, replace, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local data, count, errors = io.gsub(filepath, pattern, replace, opt)\n    if not data then\n        raise(errors)\n    end\n    return data, count\nend\n\n-- replace text of the given file and return new data\nfunction sandbox_io.replace(filepath, pattern, replace, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local data, count, errors = io.replace(filepath, pattern, replace, opt)\n    if not data then\n        raise(errors)\n    end\n    return data, count\nend\n\n-- insert text before line number in the given file and return new data\nfunction sandbox_io.insert(filepath, lineidx, text, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local data, errors = io.insert(filepath, lineidx, text, opt)\n    if not data then\n        raise(errors)\n    end\n    return data\nend\n\n-- convert file encoding\nfunction sandbox_io.convert(inputfile, outputfile, opt)\n    assert(inputfile and outputfile)\n    inputfile = vformat(inputfile)\n    outputfile = vformat(outputfile)\n    local ok, errors = io.convert(inputfile, outputfile, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- get std file\nfunction sandbox_io.stdfile(filepath)\n    assert(filepath)\n    local file, errors = io.stdfile(filepath)\n    if not file then\n        raise(errors)\n    end\n\n    -- hook file interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_io_file) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = file[\"_\" .. name] or file[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        file[name] = func\n    end\n    return file\nend\n\n-- open file\nfunction sandbox_io.open(filepath, mode, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local file, errors = io.open(filepath, mode, opt)\n    if not file then\n        raise(errors)\n    end\n\n    -- hook file interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_io_file) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = file[\"_\" .. name] or file[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        file[name] = func\n    end\n    return file\nend\n\n-- open file lock\nfunction sandbox_io.openlock(filepath)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local lock, errors = io.openlock(filepath)\n    if not lock then\n        raise(errors)\n    end\n\n    -- hook filelock interfaces\n    local hooked = {}\n    for name, func in pairs(sandbox_io_filelock) do\n        if not name:startswith(\"_\") and type(func) == \"function\" then\n            hooked[\"_\" .. name] = lock[\"_\" .. name] or lock[name]\n            hooked[name] = func\n        end\n    end\n    for name, func in pairs(hooked) do\n        lock[name] = func\n    end\n    return lock\nend\n\n-- load object from the given file\nfunction sandbox_io.load(filepath, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local result, errors = io.load(filepath, opt)\n    if errors ~= nil then\n        raise(errors)\n    end\n    return result\nend\n\n-- save object the the given filepath\nfunction sandbox_io.save(filepath, object, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local ok, errors = io.save(filepath, object, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- read all data from file\nfunction sandbox_io.readfile(filepath, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local result, errors = io.readfile(filepath, opt)\n    if not result then\n        raise(errors)\n    end\n    return result\nend\n\n-- direct read from stdin\nfunction sandbox_io.read(fmt, opt)\n    return sandbox_io.stdin:read(fmt, opt)\nend\n\n-- has readable for stdin?\nfunction sandbox_io.readable()\n    return sandbox_io.stdin:readable()\nend\n\n-- direct write to stdout\nfunction sandbox_io.write(...)\n    sandbox_io.stdout:write(...)\nend\n\n--- flush file\nfunction sandbox_io.flush(file)\n    return (file or sandbox_io.stdout):flush()\nend\n\n-- isatty\nfunction sandbox_io.isatty(file)\n    file = file or sandbox_io.stdout\n    return file:isatty()\nend\n\n-- write all data to file\nfunction sandbox_io.writefile(filepath, data, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    local ok, errors = io.writefile(filepath, data, opt)\n    if not ok then\n        raise(errors)\n    end\nend\n\n-- print line to file\nfunction sandbox_io.print(filepath, ...)\n    sandbox_io.writefile(filepath, vformat(...) .. \"\\n\")\nend\n\n-- print string to file\nfunction sandbox_io.printf(filepath, ...)\n    sandbox_io.writefile(filepath, vformat(...))\nend\n\n-- cat the given file\nfunction sandbox_io.cat(filepath, linecount, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    io.cat(filepath, linecount, opt)\nend\n\n-- tail the given file\nfunction sandbox_io.tail(filepath, linecount, opt)\n    assert(filepath)\n    filepath = vformat(filepath)\n    io.tail(filepath, linecount, opt)\nend\n\n-- lazy loading stdfile\nsetmetatable(sandbox_io, { __index = function (tbl, key)\n        local val = rawget(tbl, key)\n        if val == nil and (key == \"stdin\" or key == \"stdout\" or key == \"stderr\") then\n            val = sandbox_io.stdfile(\"/dev/\" .. key)\n            if val ~= nil then\n                rawset(tbl, key, val)\n            end\n        end\n        return val\n    end})\n\n-- return module\nreturn sandbox_io\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/ipairs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ipairs.lua\n--\n\n-- load modules\nlocal table = require(\"base/table\")\n\n-- improve ipairs, wrap nil and single value\nfunction sandbox_ipairs(t)\n\n    -- exists the custom ipairs?\n    local is_table = type(t) == \"table\"\n    if is_table and t.ipairs then\n        return t:ipairs()\n    end\n\n    -- wrap table and return iterator\n    if not is_table then\n        t = t ~= nil and {t} or {}\n    end\n    return function (t, i)\n        i = i + 1\n        local v = t[i]\n        if v ~= nil then\n            return i, v\n        end\n    end, t, 0\nend\n\n-- load module\nreturn sandbox_ipairs\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/irpairs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        irpairs.lua\n--\n\n-- load modules\nlocal table = require(\"base/table\")\n\n-- irpairs\n--\n-- e.g.\n--\n-- @code\n--\n-- for idx, val in irpairs({\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}) do\n--      print(\"%d %s\", idx, val)\n-- end\n--\n-- for idx, val in irpairs({\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}, function (v) return v:upper() end) do\n--      print(\"%d %s\", idx, val)\n-- end\n--\n-- for idx, val in irpairs({\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}, function (v, a, b) return v:upper() .. a .. b end, \"a\", \"b\") do\n--      print(\"%d %s\", idx, val)\n-- end\n--\n-- @endcode\nfunction sandbox_irpairs(t, filter, ...)\n\n    -- has filter?\n    local has_filter = type(filter) == \"function\"\n\n    -- init iterator\n    local args = table.pack(...)\n    local iter = function (t, i)\n        i = i - 1\n        local v = t[i]\n        if v ~= nil then\n            if has_filter then\n                v = filter(v, table.unpack(args, 1, args.n))\n            end\n            return i, v\n        end\n    end\n\n    -- return iterator and initialized state\n    t = table.wrap(t)\n    return iter, t, table.getn(t) + 1\nend\n\n-- load module\nreturn sandbox_irpairs\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_arch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_arch.lua\n--\n\n-- return module\nreturn require(\"project/config\").is_arch\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_config.lua\n--\n\nlocal config  = require(\"project/config\")\nlocal sandbox = require(\"sandbox/sandbox\")\n\nreturn function (name, ...)\n    local namespace\n    local instance = sandbox.instance()\n    if instance then\n        namespace = instance:namespace()\n    end\n    local value = config.get(name)\n    if value == nil and namespace then\n        value = config.get(namespace .. \"::\" .. name)\n    end\n    return config._is_value(value, ...)\nend\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_host.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_host.lua\n--\n\n-- return module\nreturn require(\"base/os\").is_host\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_mode.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_mode.lua\n--\n\n-- return module\nreturn require(\"project/config\").is_mode\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_plat.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_plat.lua\n--\n\n-- return module\nreturn require(\"project/config\").is_plat\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/is_subhost.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_subhost.lua\n--\n\n-- return module\nreturn require(\"base/os\").is_subhost\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/linuxos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linuxos.lua\n--\n\n-- load modules\nlocal linuxos = require(\"base/linuxos\")\nlocal raise   = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_linuxos = sandbox_linuxos or {}\n\n-- get linux system name\nfunction sandbox_linuxos.name()\n    local name = linuxos.name()\n    if not name then\n        raise(\"cannot get the system name of the current linux!\")\n    end\n    return name\nend\n\n-- get linux system version\nfunction sandbox_linuxos.version()\n    local linuxver = linuxos.version()\n    if not linuxver then\n        raise(\"cannot get the system version of the current linux!\")\n    end\n    return linuxver\nend\n\n-- get linux kernel version\nfunction sandbox_linuxos.kernelver()\n    local kernelver = linuxos.kernelver()\n    if not kernelver then\n        raise(\"cannot get the kernel version of the current linux!\")\n    end\n    return kernelver\nend\n\n-- return module\nreturn sandbox_linuxos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/macos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        macos.lua\n--\n\n-- load modules\nlocal macos = require(\"base/macos\")\nlocal raise = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_macos = sandbox_macos or {}\n\n-- get system version\nfunction sandbox_macos.version()\n    local winver = macos.version()\n    if not winver then\n        raise(\"cannot get the version of the current macos!\")\n    end\n    return winver\nend\n\n-- return module\nreturn sandbox_macos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/math.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        math.lua\n--\n\n-- load module\nreturn require(\"base/math\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/os.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        os.lua\n--\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal os        = require(\"base/os\")\nlocal utils     = require(\"base/utils\")\nlocal xmake     = require(\"base/xmake\")\nlocal option    = require(\"base/option\")\nlocal semver    = require(\"base/semver\")\nlocal scheduler = require(\"base/scheduler\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal vformat   = require(\"sandbox/modules/vformat\")\n\n-- define module\nlocal sandbox_os = sandbox_os or {}\n\n-- inherit some builtin interfaces\nsandbox_os.shell        = os.shell\nsandbox_os.term         = os.term\nsandbox_os.host         = os.host\nsandbox_os.arch         = os.arch\nsandbox_os.subhost      = os.subhost\nsandbox_os.subarch      = os.subarch\nsandbox_os.is_host      = os.is_host\nsandbox_os.is_arch      = os.is_arch\nsandbox_os.is_subhost   = os.is_subhost\nsandbox_os.is_subarch   = os.is_subarch\nsandbox_os.syserror     = os.syserror\nsandbox_os.strerror     = os.strerror\nsandbox_os.exit         = os.exit\nsandbox_os.atexit       = os.atexit\nsandbox_os.date         = os.date\nsandbox_os.time         = os.time\nsandbox_os.args         = os.args\nsandbox_os.args         = os.args\nsandbox_os.argv         = os.argv\nsandbox_os.mtime        = os.mtime\nsandbox_os.raise        = os.raise\nsandbox_os.fscase       = os.fscase\nsandbox_os.isroot       = os.isroot\nsandbox_os.mclock       = os.mclock\nsandbox_os.nuldev       = os.nuldev\nsandbox_os.getenv       = os.getenv\nsandbox_os.setenv       = os.setenv\nsandbox_os.addenv       = os.addenv\nsandbox_os.setenvp      = os.setenvp\nsandbox_os.addenvp      = os.addenvp\nsandbox_os.getenvs      = os.getenvs\nsandbox_os.setenvs      = os.setenvs\nsandbox_os.addenvs      = os.addenvs\nsandbox_os.joinenvs     = os.joinenvs\nsandbox_os.pbpaste      = os.pbpaste\nsandbox_os.pbcopy       = os.pbcopy\nsandbox_os.cpuinfo      = os.cpuinfo\nsandbox_os.meminfo      = os.meminfo\nsandbox_os.default_njob = os.default_njob\nsandbox_os.emptydir     = os.emptydir\nsandbox_os.filesize     = os.filesize\nsandbox_os.features     = os.features\nsandbox_os.workingdir   = os.workingdir\nsandbox_os.programdir   = os.programdir\nsandbox_os.programfile  = os.programfile\nsandbox_os.projectdir   = os.projectdir\nsandbox_os.projectfile  = os.projectfile\nsandbox_os.getwinsize   = os.getwinsize\nsandbox_os.getpid       = os.getpid\n\n-- syserror code\nsandbox_os.SYSERR_UNKNOWN     = os.SYSERR_UNKNOWN\nsandbox_os.SYSERR_NONE        = os.SYSERR_NONE\nsandbox_os.SYSERR_NOT_PERM    = os.SYSERR_NOT_PERM\nsandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR\nsandbox_os.SYSERR_NOT_ACCESS  = os.SYSERR_NOT_ACCESS\n\n-- copy file or directory\nfunction sandbox_os.cp(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- move file or directory\nfunction sandbox_os.mv(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- remove files or directories\nfunction sandbox_os.rm(filepath, opt)\n    assert(filepath)\n    filepath = tostring(filepath)\n    local ok, errors = os.rm(vformat(filepath), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- link file or directory to the new symfile\nfunction sandbox_os.ln(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    srcpath = tostring(srcpath)\n    dstpath = tostring(dstpath)\n    local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- copy file or directory with the verbose info\nfunction sandbox_os.vcp(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    if option.get(\"verbose\") then\n        utils.cprint(\"${dim}> copy %s to %s\", srcpath, dstpath)\n    end\n    return sandbox_os.cp(srcpath, dstpath, opt)\nend\n\n-- move file or directory with the verbose info\nfunction sandbox_os.vmv(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    if option.get(\"verbose\") then\n        utils.cprint(\"${dim}> move %s to %s\", srcpath, dstpath)\n    end\n    return sandbox_os.mv(srcpath, dstpath, opt)\nend\n\n-- remove file or directory with the verbose info\nfunction sandbox_os.vrm(filepath, opt)\n    assert(filepath)\n    if option.get(\"verbose\") then\n        utils.cprint(\"${dim}> remove %s\", filepath)\n    end\n    return sandbox_os.rm(filepath, opt)\nend\n\n-- link file or directory with the verbose info\nfunction sandbox_os.vln(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    if option.get(\"verbose\") then\n        utils.cprint(\"${dim}> link %s to %s\", srcpath, dstpath)\n    end\n    return sandbox_os.ln(srcpath, dstpath, opt)\nend\n\n-- try to copy file or directory\nfunction sandbox_os.trycp(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    return os.cp(vformat(srcpath), vformat(dstpath), opt)\nend\n\n-- try to move file or directory\nfunction sandbox_os.trymv(srcpath, dstpath, opt)\n    assert(srcpath and dstpath)\n    return os.mv(vformat(srcpath), vformat(dstpath), opt)\nend\n\n-- try to remove files or directories\nfunction sandbox_os.tryrm(filepath, opt)\n    assert(filepath)\n    return os.rm(vformat(filepath), opt)\nend\n\n-- change to directory\nfunction sandbox_os.cd(dir)\n\n    -- check\n    assert(dir)\n\n    -- format it first\n    dir = vformat(dir)\n\n    -- enter this directory\n    local oldir, errors = os.cd(dir)\n    if not oldir then\n        os.raise(errors)\n    end\n\n    -- ok\n    return oldir\nend\n\n-- touch file or directory\nfunction sandbox_os.touch(filepath, opt)\n    assert(filepath)\n    local ok, errors = os.touch(vformat(filepath), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- create directories\nfunction sandbox_os.mkdir(dir)\n    assert(dir)\n    local ok, errors = os.mkdir(vformat(dir))\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- remove directories\nfunction sandbox_os.rmdir(dir, opt)\n    assert(dir)\n    local ok, errors = os.rmdir(vformat(dir), opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- get the current directory\nfunction sandbox_os.curdir()\n    return assert(os.curdir())\nend\n\n-- get the temporary directory\nfunction sandbox_os.tmpdir(opt)\n    return assert(os.tmpdir(opt))\nend\n\n-- get the temporary file\nfunction sandbox_os.tmpfile(key, opt)\n    return assert(os.tmpfile(key, opt))\nend\n\n-- get the script directory\nfunction sandbox_os.scriptdir()\n    local instance = sandbox.instance()\n    local rootdir = instance:rootdir()\n    assert(rootdir)\n    return rootdir\nend\n\n-- quietly run command\nfunction sandbox_os.run(cmd, ...)\n    cmd = vformat(cmd, ...)\n    local ok, errors = os.run(cmd)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- quietly run command with arguments list\nfunction sandbox_os.runv(program, argv, opt)\n    program = vformat(program)\n    local ok, errors = os.runv(program, argv, opt)\n    if not ok then\n        os.raise(errors)\n    end\nend\n\n-- quietly run command and echo verbose info if [-v|--verbose] option is enabled\nfunction sandbox_os.vrun(cmd, ...)\n    if option.get(\"verbose\") then\n        print(vformat(cmd, ...))\n    end\n    (option.get(\"verbose\") and sandbox_os.exec or sandbox_os.run)(cmd, ...)\nend\n\n-- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled\nfunction sandbox_os.vrunv(program, argv, opt)\n    if option.get(\"verbose\") then\n        print(vformat(program) .. \" \" .. sandbox_os.args(argv or {}))\n    end\n    if not (opt and opt.dryrun) then\n        (option.get(\"verbose\") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt)\n    end\nend\n\n-- run command and return output and error data\nfunction sandbox_os.iorun(cmd, ...)\n    cmd = vformat(cmd, ...)\n    local ok, outdata, errdata, errors = os.iorun(cmd)\n    if not ok then\n        if not errors then\n            errors = errdata or \"\"\n            if #errors:trim() == 0 then\n                errors = outdata or \"\"\n            end\n        end\n        os.raise({errors = errors, stderr = errdata, stdout = outdata})\n    end\n    return outdata, errdata\nend\n\n-- run command and return output and error data\nfunction sandbox_os.iorunv(program, argv, opt)\n    program = vformat(program)\n    local ok, outdata, errdata, errors = os.iorunv(program, argv, opt)\n    if not ok then\n        if not errors then\n            errors = errdata or \"\"\n            if #errors:trim() == 0 then\n                errors = outdata or \"\"\n            end\n        end\n        os.raise({errors = errors, stderr = errdata, stdout = outdata})\n    end\n    return outdata, errdata\nend\n\n-- execute command\nfunction sandbox_os.exec(cmd, ...)\n    cmd = vformat(cmd, ...)\n    local ok, errors = os.exec(cmd)\n    if ok ~= 0 then\n        if ok ~= nil then\n            errors = string.format(\"exec(%s) failed(%d), %s\", cmd, ok, errors or \"unknown reason\")\n        else\n            errors = string.format(\"cannot exec(%s), %s\", cmd, errors or \"unknown reason\")\n        end\n        os.raise(errors)\n    end\nend\n\n-- execute command with arguments list\nfunction sandbox_os.execv(program, argv, opt)\n\n    -- make program\n    program = vformat(program)\n\n    -- flush io buffer first for fixing redirect io output order\n    --\n    -- e.g.\n    --\n    -- xmake run > /tmp/a\n    --   print(\"xxx1\")\n    --   os.exec(\"echo xxx2\")\n    --\n    -- cat /tmp/a\n    --   xxx2\n    --   xxx1\n    --\n    io.flush()\n\n    -- run it\n    opt = opt or {}\n    local ok, errors = os.execv(program, argv, opt)\n    if ok ~= 0 and not opt.try then\n\n        -- get command\n        local cmd = program\n        if argv then\n            cmd = cmd .. \" \" .. os.args(argv)\n        end\n\n        -- get errors\n        if ok ~= nil then\n            errors = string.format(\"execv(%s) failed(%d), %s\", cmd, ok, errors or \"unknown reason\")\n        else\n            errors = string.format(\"cannot execv(%s), %s\", cmd, errors or \"unknown reason\")\n        end\n        os.raise(errors)\n    end\n\n    -- we need return results if opt.try is enabled\n    return ok, errors\nend\n\n-- execute command and echo verbose info if [-v|--verbose] option is enabled\nfunction sandbox_os.vexec(cmd, ...)\n\n    -- echo command\n    if option.get(\"verbose\") then\n        utils.cprint(\"${color.dump.string}\" .. vformat(cmd, ...))\n    end\n\n    -- run it\n    sandbox_os.exec(cmd, ...)\nend\n\n-- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled\nfunction sandbox_os.vexecv(program, argv, opt)\n\n    -- echo command\n    if option.get(\"verbose\") then\n        utils.cprint(\"${color.dump.string}\" .. vformat(program) .. \" \" .. sandbox_os.args(argv))\n    end\n\n    -- run it\n    if not (opt and opt.dryrun) then\n        return sandbox_os.execv(program, argv, opt)\n    else\n        return 0\n    end\nend\n\n-- match files or directories\nfunction sandbox_os.match(pattern, mode, opt)\n    return os.match(vformat(tostring(pattern)), mode, opt)\nend\n\n-- match directories\nfunction sandbox_os.dirs(pattern, opt)\n    return os.dirs(vformat(tostring(pattern)), opt)\nend\n\n-- match files\nfunction sandbox_os.files(pattern, opt)\n    return os.files(vformat(tostring(pattern)), opt)\nend\n\n-- match files and directories\nfunction sandbox_os.filedirs(pattern, opt)\n    return os.filedirs(vformat(tostring(pattern)), opt)\nend\n\n-- is directory?\nfunction sandbox_os.isdir(dirpath)\n    assert(dirpath)\n    dirpath = tostring(dirpath)\n    return os.isdir(vformat(dirpath))\nend\n\n-- is file?\nfunction sandbox_os.isfile(filepath)\n    assert(filepath)\n    filepath = tostring(filepath)\n    return os.isfile(vformat(filepath))\nend\n\n-- is symlink?\nfunction sandbox_os.islink(filepath)\n    assert(filepath)\n    filepath = tostring(filepath)\n    return os.islink(vformat(filepath))\nend\n\n-- is execute program?\nfunction sandbox_os.isexec(filepath)\n    assert(filepath)\n    filepath = tostring(filepath)\n    return os.isexec(vformat(filepath))\nend\n\n-- exists file or directory?\nfunction sandbox_os.exists(filedir)\n    assert(filedir)\n    filedir = tostring(filedir)\n    return os.exists(vformat(filedir))\nend\n\n-- read the content of symlink\nfunction sandbox_os.readlink(symlink)\n    local result = os.readlink(tostring(symlink))\n    if not result then\n        os.raise(\"cannot read link(%s)\", symlink)\n    end\n    return result\nend\n\n-- sleep (support in coroutine)\nfunction sandbox_os.sleep(ms)\n    if scheduler:co_running() then\n        local ok, errors = scheduler:co_sleep(ms)\n        if not ok then\n            raise(errors)\n        end\n    else\n        os.sleep(ms)\n    end\nend\n\n-- get xmake version\nfunction sandbox_os.xmakever()\n\n    -- fill cache\n    if sandbox_os._XMAKEVER == nil then\n        -- get xmakever\n        local xmakever = semver.new(xmake._VERSION_SHORT)\n        -- save to cache\n        sandbox_os._XMAKEVER = xmakever or false\n    end\n\n    -- done\n    return sandbox_os._XMAKEVER or nil\nend\n\n-- return module\nreturn sandbox_os\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/pairs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pairs.lua\n--\n\n-- load modules\nlocal table = require(\"base/table\")\n\n-- improve pairs, wrap nil/single value\nfunction sandbox_pairs(t)\n\n    -- exists the custom ipairs?\n    local is_table = type(t) == \"table\"\n    if is_table and t.pairs then\n        return t:pairs()\n    end\n\n    -- wrap table and return iterator\n    if not is_table then\n        t = t ~= nil and {t} or {}\n    end\n    return function (t, i)\n        return next(t, i)\n    end, t, nil\nend\n\n-- load module\nreturn sandbox_pairs\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/path.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        path.lua\n--\n\n-- load module\nreturn require(\"base/path\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/print.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        print.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").print\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/printf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        printf.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").printf\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/raise.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        raise.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/os\").raise\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/string.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        string.lua\n--\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal sandbox   = require(\"sandbox/sandbox\")\n\n-- define module\nlocal sandbox_string = sandbox_string or {}\n\n-- inherit the public interfaces of string\nfor k, v in pairs(string) do\n    if not k:startswith(\"_\") and type(v) == \"function\" then\n        sandbox_string[k] = v\n    end\nend\n\n-- format string with the builtin variables\nfunction sandbox_string.vformat(format, ...)\n\n    -- check\n    assert(format)\n\n    -- get the current sandbox instance\n    local instance = sandbox.instance()\n    assert(instance)\n\n    -- format string if exists arguments\n    local result = format\n    if #{...} > 0 then\n\n        -- escape \"%$\", \"%(\", \"%)\", \"%%\" to '$', '(', ')', '%%'\n        format = format:gsub(\"%%([%$%(%)%%])\", function (ch) return ch ~= \"%\" and (\"%%\" .. ch) or \"%%%%\" end)\n\n        -- try to format it\n        result = string.format(format, ...)\n    end\n    assert(result)\n\n    -- get filter from the current sandbox\n    local filter = instance:filter()\n    if filter then\n        result = filter:handle(result)\n    end\n\n    -- ok?\n    return result\nend\n\n-- return module\nreturn sandbox_string\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/table.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        table.lua\n--\n\n-- load module\nreturn require(\"base/table\")\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/todisplay.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        todisplay.lua\n--\n\n-- load module\nreturn require(\"base/todisplay\").print\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/tonumber.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tonumber.lua\n--\n\n-- load module\nreturn tonumber\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/tostring.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tostring.lua\n--\n\n-- load module\nreturn tostring\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/try.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        try.lua\n--\n\n-- load modules\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal option    = require(\"base/option\")\n\n-- define module\nlocal sandbox_try = sandbox_try or {}\n\n-- traceback\nfunction sandbox_try._traceback(errors)\n\n    -- no diagnosis info?\n    if not option.get(\"diagnosis\") then\n        if errors then\n            -- remove the prefix info\n            local _, pos = errors:find(\":%d+: \")\n            if pos then\n                errors = errors:sub(pos + 1)\n            end\n        end\n        return errors\n    end\n\n    -- traceback exists?\n    if errors and errors:find(\"stack traceback:\", 1, true) then\n        return errors\n    end\n\n    -- init results\n    local results = \"\"\n    if errors then\n        results = errors .. \"\\n\"\n    end\n    results = results .. \"stack traceback:\\n\"\n\n    -- make results\n    local level = 2\n    while true do\n\n        -- get debug info\n        local info = debug.getinfo(level, \"Sln\")\n\n        -- end?\n        if not info or (info.name and info.name == \"xpcall\") then\n            break\n        end\n\n        -- function?\n        if info.what == \"C\" then\n            results = results .. string.format(\"    [C]: in function '%s'\\n\", info.name)\n        elseif info.name then\n            results = results .. string.format(\"    [%s:%d]: in function '%s'\\n\", info.short_src, info.currentline, info.name)\n        elseif info.what == \"main\" then\n            results = results .. string.format(\"    [%s:%d]: in main chunk\\n\", info.short_src, info.currentline)\n            break\n        else\n            results = results .. string.format(\"    [%s:%d]:\\n\", info.short_src, info.currentline)\n        end\n        level = level + 1\n    end\n    return results\nend\n\n-- local ok = try\n-- {\n--   function ()\n--      raise(\"errors\")\n--      raise({errors = \"xxx\", xxx = \"\", yyy = \"\"})\n--      return true\n--   end,\n--   catch\n--   {\n--      function (errors)\n--          print(errors)\n--          if errors then\n--              print(errors.xxx)\n--          end\n--      end\n--   },\n--   finally\n--   {\n--      function (ok, result_or_errors)\n--      end\n--   }\n-- }\nfunction sandbox_try.try(block)\n\n    -- get the try function\n    local try = block[1]\n    assert(try)\n\n    -- get catch and finally functions\n    local funcs = table.join(block[2] or {}, block[3] or {})\n\n    -- try to call it\n    local results = table.pack(utils.trycall(try, sandbox_try._traceback))\n    local ok = results[1]\n    if not ok then\n\n        -- run the catch function\n        if funcs and funcs.catch then\n            funcs.catch(results[2])\n        end\n    end\n\n    -- run the finally function\n    if funcs and funcs.finally then\n        funcs.finally(ok, table.unpack(results, 2, results.n))\n    end\n\n    if ok then\n        return table.unpack(results, 2, results.n)\n    end\nend\n\n-- return module\nreturn sandbox_try.try\n"
  },
  {
    "path": "xmake/core/sandbox/modules/type.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        type.lua\n--\n\n-- load module\nreturn type\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/unpack.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        table.unpack.lua\n--\n\n-- load module\nreturn require(\"base/table\").unpack\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/utf8.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utf8.lua\n--\n\nreturn require(\"base/utf8\")\n"
  },
  {
    "path": "xmake/core/sandbox/modules/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- load modules\nlocal io         = require(\"base/io\")\nlocal os         = require(\"base/os\")\nlocal utils      = require(\"base/utils\")\nlocal colors     = require(\"base/colors\")\nlocal option     = require(\"base/option\")\nlocal log        = require(\"base/log\")\nlocal deprecated = require(\"base/deprecated\")\nlocal binutils   = require(\"base/binutils\")\nlocal try        = require(\"sandbox/modules/try\")\nlocal catch      = require(\"sandbox/modules/catch\")\nlocal vformat    = require(\"sandbox/modules/vformat\")\n\n-- define module\nlocal sandbox_utils = sandbox_utils or {}\n\n-- inherit some builtin interfaces\nsandbox_utils.dump    = utils.dump -- do not change to a function call to utils.dump since debug.getinfo is called in utils.dump to get caller info\nsandbox_utils.confirm = utils.confirm\nsandbox_utils.error   = utils.error\nsandbox_utils.warning = utils.warning\nsandbox_utils.trycall = utils.trycall\n\n-- print each arguments\nfunction sandbox_utils._print(...)\n    local args = {}\n    for _, arg in ipairs({...}) do\n        if type(arg) == \"string\" then\n            table.insert(args, vformat(arg))\n        else\n            table.insert(args, arg)\n        end\n    end\n    utils._print(table.unpack(args))\n    log:printv(table.unpack(args))\nend\n\n-- print format string with newline\n-- print builtin-variables with $(var)\n-- print multi-variables with raw lua action\n--\nfunction sandbox_utils.print(format, ...)\n    if type(format) == \"string\" and format:find(\"%\", 1, true) then\n        local args = {...}\n        try {\n            function ()\n                local message = vformat(format, table.unpack(args))\n                utils._print(message)\n                log:printv(message)\n            end,\n            catch {\n                function (errors)\n                    sandbox_utils._print(format, table.unpack(args))\n                end\n            }\n        }\n    else\n        sandbox_utils._print(format, ...)\n    end\nend\n\n-- print format string and the builtin variables without newline\nfunction sandbox_utils.printf(format, ...)\n    local message = vformat(format, ...)\n    utils._iowrite(message)\n    log:write(message)\nend\n\n-- print format string, the builtin variables and colors with newline\nfunction sandbox_utils.cprint(format, ...)\n    local message = vformat(format, ...)\n    utils._print(colors.translate(message))\n    if log:file() then\n        log:printv(colors.ignore(message))\n    end\nend\n\n-- print format string, the builtin variables and colors without newline\nfunction sandbox_utils.cprintf(format, ...)\n    local message = vformat(format, ...)\n    utils._iowrite(colors.translate(message))\n    if log:file() then\n        log:write(colors.ignore(message))\n    end\nend\n\n-- print the verbose information\nfunction sandbox_utils.vprint(format, ...)\n    if option.get(\"verbose\") then\n        sandbox_utils.print(format, ...)\n    end\nend\n\n-- print the verbose information without newline\nfunction sandbox_utils.vprintf(format, ...)\n    if option.get(\"verbose\") then\n        sandbox_utils.printf(format, ...)\n    end\nend\n\n-- print the diagnosis information\nfunction sandbox_utils.dprint(format, ...)\n    if option.get(\"diagnosis\") then\n        sandbox_utils.print(format, ...)\n    end\nend\n\n-- print the diagnosis information without newline\nfunction sandbox_utils.dprintf(format, ...)\n    if option.get(\"diagnosis\") then\n        sandbox_utils.printf(format, ...)\n    end\nend\n\n-- print the warning information\nfunction sandbox_utils.wprint(format, ...)\n    utils.warning(vformat(format, ...))\nend\n\n-- assert\nfunction sandbox_utils.assert(value, format, ...)\n    if not value then\n        if format ~= nil then\n            os.raiselevel(2, format, ...)\n        else\n            os.raiselevel(2, \"assertion failed!\")\n        end\n    end\n    return value\nend\n\n-- generate c/c++ code from the binary file (deprecated, use binutils.bin2c instead)\nfunction sandbox_utils.bin2c(binaryfile, outputfile, opt)\n    deprecated.add(\"binutils.bin2c\", \"utils.bin2c\")\n    return binutils.bin2c(binaryfile, outputfile, opt)\nend\n\n-- return module\nreturn sandbox_utils\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/val.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        val.lua\n--\n\n-- load modules\nlocal sandbox = require(\"sandbox/sandbox\")\n\n-- get the variable value of filter\n--\n-- e.g.\n--\n-- local value = val(\"host\")\n-- local value = val(\"env PATH\")\n-- local value = val(\"shell echo hello xmake!\")\n-- local value = val(\"reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\XXXX;Name\")\n--\nfunction val(name)\n\n    -- get the current sandbox instance\n    local instance = sandbox.instance()\n    assert(instance)\n\n    -- get filter from the current sandbox\n    local filter = instance:filter()\n    if filter then\n        return filter:get(name) or \"\"\n    end\n\n    -- no this variable\n    return \"\"\nend\n\n-- return module\nreturn val\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/vformat.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vformat.lua\n--\n\n-- return module\nreturn require(\"sandbox/modules/string\").vformat\n\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/vprint.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vprint.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").vprint\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/vprintf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vprintf.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").vprintf\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/winos.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        winos.lua\n--\n\n-- load modules\nlocal winos = require(\"base/winos\")\nlocal raise = require(\"sandbox/modules/raise\")\n\n-- define module\nlocal sandbox_winos = sandbox_winos or {}\n\n-- inherit some builtin interfaces\nsandbox_winos.oem_cp                  = winos.oem_cp\nsandbox_winos.ansi_cp                 = winos.ansi_cp\nsandbox_winos.cp_info                 = winos.cp_info\nsandbox_winos.console_cp              = winos.console_cp\nsandbox_winos.console_output_cp       = winos.console_output_cp\nsandbox_winos.logical_drives          = winos.logical_drives\nsandbox_winos.cmdargv                 = winos.cmdargv\nsandbox_winos.processes               = winos.processes\nsandbox_winos.inherit_handles_safely  = winos.inherit_handles_safely\nsandbox_winos.set_error_mode          = winos.set_error_mode\nsandbox_winos.file_signature          = winos.file_signature\n\n-- get windows system version\nfunction sandbox_winos.version()\n    local winver = winos.version()\n    if not winver then\n        raise(\"cannot get the version of the current winos!\")\n    end\n    return winver\nend\n\n-- query registry value\nfunction sandbox_winos.registry_query(keypath)\n    local value, errors = winos.registry_query(keypath)\n    if not value then\n        raise(errors)\n    end\n    return value\nend\n\n-- get registry keys\nfunction sandbox_winos.registry_keys(keypath)\n    local keys, errors = winos.registry_keys(keypath)\n    if not keys then\n        raise(errors)\n    end\n    return keys\nend\n\n-- get registry values\nfunction sandbox_winos.registry_values(keypath)\n    local values, errors = winos.registry_values(keypath)\n    if not values then\n        raise(errors)\n    end\n    return values\nend\n\n-- get short path\nfunction sandbox_winos.short_path(long_path)\n    local short_path, errors = winos.short_path(long_path)\n    if not short_path then\n        raise(errors)\n    end\n    return short_path\nend\n\n-- return module\nreturn sandbox_winos\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/wprint.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        wprint.lua\n--\n\n-- load module\nreturn require(\"sandbox/modules/utils\").wprint\n\n"
  },
  {
    "path": "xmake/core/sandbox/modules/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- load modules\nlocal xmake   = require(\"base/xmake\")\n\n-- define module\nlocal sandbox_xmake = sandbox_xmake or {}\n\n-- inherit some builtin interfaces\nsandbox_xmake.arch           = xmake.arch\nsandbox_xmake.version        = xmake.version\nsandbox_xmake.branch         = xmake.branch\nsandbox_xmake.programdir     = xmake.programdir\nsandbox_xmake.programfile    = xmake.programfile\nsandbox_xmake.luajit         = xmake.luajit\nsandbox_xmake.is_embed       = xmake.is_embed\nsandbox_xmake.in_main_thread = xmake.in_main_thread\nsandbox_xmake.argv           = xmake.argv\n\n-- return module\nreturn sandbox_xmake\n"
  },
  {
    "path": "xmake/core/sandbox/sandbox.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sandbox.lua\n--\n\n-- define module\nlocal sandbox = sandbox or {}\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal path      = require(\"base/path\")\nlocal table     = require(\"base/table\")\nlocal utils     = require(\"base/utils\")\nlocal string    = require(\"base/string\")\nlocal option    = require(\"base/option\")\n\n-- traceback\nfunction sandbox._traceback(errors)\n\n    -- no diagnosis info?\n    if not option.get(\"diagnosis\") then\n        if errors then\n            -- remove the prefix info\n            local _, pos = errors:find(\":%d+: \")\n            if pos then\n                errors = errors:sub(pos + 1)\n            end\n        end\n        return errors\n    end\n\n    -- traceback exists?\n    if errors and errors:find(\"stack traceback:\", 1, true) then\n        return errors\n    end\n\n    -- init results\n    local results = \"\"\n    if errors then\n        results = errors .. \"\\n\"\n    end\n    results = results .. \"stack traceback:\\n\"\n\n    -- make results\n    local level = 2\n    while true do\n\n        -- get debug info\n        local info = debug.getinfo(level, \"Sln\")\n\n        -- end?\n        if not info then\n            break\n        end\n\n        -- function?\n        if info.what == \"C\" then\n            results = results .. string.format(\"    [C]: in function '%s'\\n\", info.name)\n        elseif info.name then\n            results = results .. string.format(\"    [%s:%d]: in function '%s'\\n\", info.short_src, info.currentline, info.name)\n        elseif info.what == \"main\" then\n            results = results .. string.format(\"    [%s:%d]: in main chunk\\n\", info.short_src, info.currentline)\n            break\n        else\n            results = results .. string.format(\"    [%s:%d]:\\n\", info.short_src, info.currentline)\n        end\n        level = level + 1\n    end\n    return results\nend\n\n-- register api for builtin\nfunction sandbox._api_register_builtin(self, name, func)\n    assert(self and self._PUBLIC and func)\n    self._PUBLIC[name] = func\nend\n\n-- new a sandbox instance\nfunction sandbox._new()\n\n    -- init an sandbox instance\n    local instance = {_PUBLIC = {}, _PRIVATE = {}}\n\n    -- inherit the interfaces of sandbox\n    table.inherit2(instance, sandbox)\n\n    -- register the builtin modules\n    instance:_api_register_builtin(\"_g\", {})\n    for module_name, module in pairs(sandbox.builtin_modules()) do\n        instance:_api_register_builtin(module_name, module)\n    end\n\n    -- bind instance to the public script envirnoment\n    instance:bind(instance._PUBLIC)\n    return instance\nend\n\n-- new a sandbox instance with the given script\nfunction sandbox.new(script, opt)\n    opt = opt or {}\n\n    -- new instance\n    local self = sandbox._new()\n    assert(self and self._PUBLIC and self._PRIVATE)\n\n    self._PRIVATE._FILTER = opt.filter\n    self._PRIVATE._ROOTDIR = opt.rootdir\n    self._PRIVATE._NAMESPACE = opt.namespace\n\n    -- invalid script?\n    if type(script) ~= \"function\" then\n        return nil, \"invalid script!\"\n    end\n\n    -- bind public scope\n    setfenv(script, self._PUBLIC)\n\n    -- save script\n    self._PRIVATE._SCRIPT = script\n    return self\nend\n\n-- load script in the sandbox\nfunction sandbox.load(script, ...)\n    return utils.trycall(script, sandbox._traceback, ...)\nend\n\n-- bind self instance to the given script or envirnoment\nfunction sandbox:bind(script_or_env)\n\n    -- get envirnoment\n    local env = script_or_env\n    if type(script_or_env) == \"function\" then\n        env = getfenv(script_or_env)\n    end\n\n    -- bind instance to the script envirnoment\n    setmetatable(env, {     __index = function (tbl, key)\n                                if type(key) == \"string\" and key == \"_SANDBOX\" and rawget(tbl, \"_SANDBOX_READABLE\") then\n                                    return self\n                                end\n                                return rawget(tbl, key)\n                            end\n                        ,   __newindex = function (tbl, key, val)\n                                if type(key) == \"string\" and (key == \"_SANDBOX\" or key == \"_SANDBOX_READABLE\") then\n                                    return\n                                end\n                                rawset(tbl, key, val)\n                            end})\n\n    -- ok\n    return script_or_env\nend\n\n-- fork a new sandbox from the self sandbox\nfunction sandbox:fork(script, rootdir)\n\n    -- invalid script?\n    if script ~= nil and type(script) ~= \"function\" then\n        return nil, \"invalid script!\"\n    end\n\n    -- init a new sandbox instance\n    local instance = sandbox._new()\n    assert(instance and instance._PUBLIC and instance._PRIVATE)\n\n    instance._PRIVATE._FILTER = self:filter()\n    instance._PRIVATE._ROOTDIR = rootdir or self:rootdir()\n    instance._PRIVATE._NAMESPACE = self:namespace()\n\n    -- bind public scope\n    if script then\n        setfenv(script, instance._PUBLIC)\n        instance._PRIVATE._SCRIPT = script\n    end\n    return instance\nend\n\n-- load script and module\nfunction sandbox:module()\n\n    -- this module has been loaded?\n    if self._PRIVATE._MODULE then\n        return self._PRIVATE._MODULE\n    end\n\n    -- backup the scope variables first\n    local scope_public = getfenv(self:script())\n    local scope_backup = {}\n    table.copy2(scope_backup, scope_public)\n\n    -- load module with sandbox\n    local ok, errors = sandbox.load(self:script())\n    if not ok then\n        return nil, errors\n    end\n\n    -- only export new public functions\n    local module = {}\n    for k, v in pairs(scope_public) do\n        if type(v) == \"function\" and not k:startswith(\"_\") and scope_backup[k] == nil then\n            module[k] = v\n        end\n    end\n    self._PRIVATE._MODULE = module\n    return module\nend\n\n-- get script from the given sandbox\nfunction sandbox:script()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._SCRIPT\nend\n\n-- get filter from the given sandbox\nfunction sandbox:filter()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._FILTER\nend\n\n-- get root directory from the given sandbox\nfunction sandbox:rootdir()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._ROOTDIR\nend\n\n-- get current namespace\nfunction sandbox:namespace()\n    assert(self and self._PRIVATE)\n    return self._PRIVATE._NAMESPACE\nend\n\n-- register api for builtin\nfunction sandbox:api_register_builtin(name, func)\n    sandbox._api_register_builtin(self, name, func)\nend\n\n-- get current instance in the sandbox modules\nfunction sandbox.instance(script)\n\n    -- get the sandbox instance from the given script\n    local instance = nil\n    if script then\n        local scope = getfenv(script)\n        if scope then\n\n            -- enable to read _SANDBOX\n            rawset(scope, \"_SANDBOX_READABLE\", true)\n\n            -- attempt to get it\n            instance = scope._SANDBOX\n\n            -- disable to read _SANDBOX\n            rawset(scope, \"_SANDBOX_READABLE\", nil)\n        end\n        if instance then return instance end\n    end\n\n    -- find self instance for the current sandbox\n    local level = 2\n    while level < 32 do\n\n        -- get scope\n        local ok, scope = pcall(getfenv, level)\n        if not ok then\n            break;\n        end\n        if scope then\n\n            -- enable to read _SANDBOX\n            rawset(scope, \"_SANDBOX_READABLE\", true)\n\n            -- attempt to get it\n            instance = scope._SANDBOX\n\n            -- disable to read _SANDBOX\n            rawset(scope, \"_SANDBOX_READABLE\", nil)\n        end\n\n        -- found?\n        if instance then\n            break\n        end\n\n        -- next\n        level = level + 1\n    end\n    return instance\nend\n\n-- get builtin modules\nfunction sandbox.builtin_modules()\n    local builtin_modules = sandbox._BUILTIN_MODULES\n    if builtin_modules == nil then\n        builtin_modules = {}\n        local builtin_module_files = os.files(path.join(os.programdir(), \"core/sandbox/modules/*.lua\"))\n        if builtin_module_files then\n            for _, builtin_module_file in ipairs(builtin_module_files) do\n                local module_name = path.basename(builtin_module_file)\n                assert(module_name)\n\n                local script, errors = loadfile(builtin_module_file)\n                if script then\n                    local ok, results = utils.trycall(script)\n                    if not ok then\n                        os.raise(results)\n                    end\n                    builtin_modules[module_name] = results\n                else\n                    os.raise(errors)\n                end\n            end\n        end\n        sandbox._BUILTIN_MODULES = builtin_modules\n    end\n    return builtin_modules\nend\n\n\n-- return module\nreturn sandbox\n"
  },
  {
    "path": "xmake/core/theme/theme.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        theme.lua\n--\n\n-- define module\nlocal theme         = theme or {}\nlocal _instance     = _instance or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal table         = require(\"base/table\")\nlocal interpreter   = require(\"base/interpreter\")\nlocal global        = require(\"base/global\")\n\n-- new an instance\nfunction _instance.new(name, info, rootdir)\n    local instance    = table.inherit(_instance)\n    instance._NAME    = name\n    instance._INFO    = info\n    instance._ROOTDIR = rootdir\n    return instance\nend\n\n-- get theme name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the theme configuration\nfunction _instance:get(name)\n    return self._INFO:get(name)\nend\n\n-- the interpreter\nfunction theme._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if theme._INTERPRETER then\n        return theme._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(theme._apis())\n\n    -- the spinner should be able to have the same character occur several times\n    -- cf. https://github.com/xmake-io/xmake/pull/6543#issuecomment-2970305842\n    interp:deduplication_policy_set(\"text.spinner.chars\", false)\n\n    -- save interpreter\n    theme._INTERPRETER = interp\n\n    -- ok?\n    return interp\nend\n\n-- get theme apis\nfunction theme._apis()\n    return\n    {\n        keyvalues =\n        {\n            -- theme.set_xxx\n            \"theme.set_color\"\n        ,   \"theme.set_text\"\n        }\n    }\nend\n\n-- get theme directories\nfunction theme.directories()\n\n    -- init directories\n    local dirs = theme._DIRS or {   path.join(global.directory(), \"themes\")\n                                ,   path.join(os.programdir(), \"themes\")\n                                }\n\n    -- save directories to cache\n    theme._DIRS = dirs\n    return dirs\nend\n\n-- find all themes\nfunction theme.names()\n\n    local paths = {}\n    for _, dir in ipairs(theme.directories()) do\n        table.join2(paths, (os.files(path.join(dir, \"*\", \"xmake.lua\"))))\n    end\n    for i, v in ipairs(paths) do\n        local value = path.split(v)\n        paths[i] = value[#value - 1]\n    end\n    return paths\nend\n\n-- load the given theme\nfunction theme.load(name)\n\n    -- find the theme script path\n    local scriptpath = nil\n    if name then\n        for _, dir in ipairs(theme.directories()) do\n            scriptpath = path.join(dir, name, \"xmake.lua\")\n            if os.isfile(scriptpath) then\n                break\n            end\n        end\n    end\n\n    -- not exists? uses the default theme\n    if not scriptpath or not os.isfile(scriptpath) then\n        scriptpath = path.join(os.programdir(), \"themes\", \"default\", \"xmake.lua\")\n    end\n\n    -- get interpreter\n    local interp = theme._interpreter()\n\n    -- load script\n    local ok, errors = interp:load(scriptpath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load theme\n    local results, errors = interp:make(\"theme\", true, false)\n    if not results and os.isfile(scriptpath) then\n        return nil, errors\n    end\n\n    -- get result\n    local result = results[name]\n    if not result then\n        return nil, string.format(\"the theme %s not found!\", name)\n    end\n\n    -- new an instance\n    local instance, errors = _instance.new(name, result, interp:rootdir())\n    if not instance then\n        return nil, errors\n    end\n\n    -- save the current theme instance\n    theme._THEME = instance\n    return instance\nend\n\n-- get the current theme instance\nfunction theme.instance()\n    return theme._THEME\nend\n\n-- get the given theme configuration\nfunction theme.get(name)\n    local instance = theme._THEME\n    if instance then\n        return instance:get(name)\n    end\nend\n\n-- return module\nreturn theme\n"
  },
  {
    "path": "xmake/core/tool/builder.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        builder.lua\n--\n\n-- define module\nlocal builder = builder or {}\n\n-- load modules\nlocal io             = require(\"base/io\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal string         = require(\"base/string\")\nlocal option         = require(\"base/option\")\nlocal hashset        = require(\"base/hashset\")\nlocal graph          = require(\"base/graph\")\nlocal tool           = require(\"tool/tool\")\nlocal config         = require(\"project/config\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal language       = require(\"language/language\")\nlocal platform       = require(\"platform/platform\")\nlocal sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\nlocal target_utils   = nil -- lazy import(\"private.utils.target\")\n\n-- get the tool of builder\nfunction builder:_tool()\n    return self._TOOL\nend\n\n-- get the name flags\nfunction builder:_nameflags()\n    return self._NAMEFLAGS\nend\n\n-- get the target kind\nfunction builder:_targetkind()\n    return self._TARGETKIND\nend\n\n-- map flag implementation\nfunction builder:_mapflag_impl(flag, flagkind, mapflags, auto_ignore_flags)\n\n    -- attempt to map it directly\n    local flag_mapped = mapflags[flag]\n    if flag_mapped then\n        return flag_mapped\n    end\n\n    -- find and replace it using pattern, maybe flag is table, e.g. {\"-I\", \"/xxx\"}\n    if type(flag) == \"string\" then\n        for k, v in pairs(mapflags) do\n            local flag_mapped, count = flag:gsub(\"^\" .. k .. \"$\", function (w) return v end)\n            if flag_mapped and count ~= 0 then\n                return #flag_mapped ~= 0 and flag_mapped\n            end\n        end\n    end\n\n    -- has this flag?\n    if auto_ignore_flags == false or self:has_flags(flag, flagkind) then\n        return flag\n    else\n        utils.warning(\"add_%s(\\\"%s\\\") is ignored, please pass `{force = true}` or call `set_policy(\\\"check.auto_ignore_flags\\\", false)` if you want to set it.\", flagkind, os.args(flag))\n    end\nend\n\n-- map flag\nfunction builder:_mapflag(flag, flagkind, target)\n    local mapflags = self:get(\"mapflags\")\n    local auto_map_flags = target and target.policy and target:policy(\"check.auto_map_flags\")\n    local auto_ignore_flags = target and target.policy and target:policy(\"check.auto_ignore_flags\")\n    if mapflags and (auto_map_flags ~= false) then\n        return self:_mapflag_impl(flag, flagkind, mapflags, auto_ignore_flags)\n    else\n        if auto_ignore_flags == false or self:has_flags(flag, flagkind) then\n            return flag\n        else\n            utils.warning(\"add_%s(\\\"%s\\\") is ignored, please pass `{force = true}` or call `set_policy(\\\"check.auto_ignore_flags\\\", false)` if you want to set it.\", flagkind, flag)\n        end\n    end\nend\n\n-- map flags\nfunction builder:_mapflags(flags, flagkind, target)\n    local results = {}\n    local mapflags = self:get(\"mapflags\")\n    local auto_map_flags = target and target.policy and target:policy(\"check.auto_map_flags\")\n    local auto_ignore_flags = target and target.policy and target:policy(\"check.auto_ignore_flags\")\n    flags = table.wrap(flags)\n    if mapflags and (auto_map_flags ~= false) then\n        for _, flag in pairs(flags) do\n            local flag_mapped = self:_mapflag_impl(flag, flagkind, mapflags, auto_ignore_flags)\n            if flag_mapped then\n                table.insert(results, flag_mapped)\n            end\n        end\n    else\n        for _, flag in pairs(flags) do\n            if auto_ignore_flags == false or self:has_flags(flag, flagkind) then\n                table.insert(results, flag)\n            else\n                utils.warning(\"add_%s(\\\"%s\\\") is ignored, please pass `{force = true}` or call `set_policy(\\\"check.auto_ignore_flags\\\", false)` if you want to set it.\", flagkind, flag)\n            end\n        end\n    end\n    return results\nend\n\n-- get the flag kinds\nfunction builder:_flagkinds()\n    return self._FLAGKINDS\nend\n\n-- get the extra configuration from value\nfunction builder:_extraconf(extras, value)\n    local extra = extras\n    if extra then\n        if type(value) == \"table\" then\n            extra = extra[table.concat(value, \"_\")]\n        else\n            extra = extra[value]\n        end\n    end\n    return extra\nend\n\n-- inherit flags (only for public/interface) from target deps\n--\n-- e.g.\n-- add_cflags(\"\", {public = true})\n-- add_cflags(\"\", {interface = true})\n--\nfunction builder:_inherit_flags_from_targetdeps(flags, target)\n    local orderdeps = target:orderdeps({inherit = true})\n    local total = #orderdeps\n    for idx, _ in ipairs(orderdeps) do\n        local dep = orderdeps[total + 1 - idx]\n        for _, flagkind in ipairs(self:_flagkinds()) do\n            self:_add_flags_from_flagkind(flags, dep, flagkind, {interface = true})\n        end\n    end\nend\n\n-- add flags from the flagkind\nfunction builder:_add_flags_from_flagkind(flags, target, flagkind, opt)\n    if target_utils == nil then\n        target_utils = sandbox_module.import(\"private.utils.target\", {anonymous = true})\n    end\n    local targetflags = target:get(flagkind, opt)\n    local extraconf   = target:extraconf(flagkind)\n    for _, flag in ipairs(table.wrap(targetflags)) do\n        flag = target_utils.flag_belong_to_tool(flag, self, extraconf)\n        if flag then\n            if extraconf then\n                local flagconf = extraconf[flag]\n                -- @note we need join the single flag with shallow mode, aboid expand table values\n                -- e.g. add_cflags({\"-I\", \"/tmp/xxx foo\"}, {force = true, expand = false})\n                if flagconf and flagconf.force then\n                    table.shallow_join2(flags, flag)\n                else\n                    table.shallow_join2(flags, self:_mapflag(flag, flagkind, target))\n                end\n            else\n                table.shallow_join2(flags, self:_mapflag(flag, flagkind, target))\n            end\n        end\n    end\nend\n\n-- add flags from the configure\nfunction builder:_add_flags_from_config(flags)\n    for _, flagkind in ipairs(self:_flagkinds()) do\n        local values = config.get(flagkind)\n        if values then\n            table.join2(flags, os.argv(values))\n        end\n    end\nend\n\n-- add flags from the target options\nfunction builder:_add_flags_from_targetopts(flags, target)\n    for _, flagkind in ipairs(self:_flagkinds()) do\n        local result = target:get_from(flagkind, \"option::*\")\n        if result then\n            for _, values in ipairs(table.wrap(result)) do\n                table.join2(flags, self:_mapflags(values, flagkind, target))\n            end\n        end\n    end\nend\n\n-- add flags from the target packages\nfunction builder:_add_flags_from_targetpkgs(flags, target)\n    local kind = self:kind()\n    for _, flagkind in ipairs(self:_flagkinds()) do\n        -- attempt to add special lanugage flags from package first, e.g. gcldflags, dcarflags\n        -- @see https://github.com/xmake-io/xmake-repo/issues/5255\n        local result\n        if kind:endswith(\"ld\") or kind:endswith(\"sh\") then\n            result = target:get_from(kind .. \"flags\", \"package::*\")\n        end\n        if not result then\n            result = target:get_from(flagkind, \"package::*\")\n        end\n        if result then\n            for _, values in ipairs(table.wrap(result)) do\n                table.join2(flags, self:_mapflags(values, flagkind, target))\n            end\n        end\n    end\nend\n\n-- add flags from the target\nfunction builder:_add_flags_from_target(flags, target)\n\n    -- no target?\n    if not target then\n        return\n    end\n\n    -- only for target and option\n    local target_type = target:type()\n    if target_type ~= \"target\" and target_type ~= \"option\" then\n        return\n    end\n\n    -- init cache\n    self._TARGETFLAGS = self._TARGETFLAGS or {}\n    local cache = self._TARGETFLAGS\n\n    -- get flags from cache first\n    local key = target:cachekey()\n    local targetflags = cache[key]\n    if not targetflags then\n\n        -- add flags from language\n        targetflags = {}\n        self:_add_flags_from_language(targetflags, {target = target})\n\n        -- add flags for the target\n        if target_type == \"target\" then\n\n            -- add flags from options\n            self:_add_flags_from_targetopts(targetflags, target)\n\n            -- add flags from packages\n            self:_add_flags_from_targetpkgs(targetflags, target)\n\n            -- inherit flags (public/interface) from all dependent targets\n            self:_inherit_flags_from_targetdeps(targetflags, target)\n        end\n\n        -- add the target flags\n        for _, flagkind in ipairs(self:_flagkinds()) do\n            self:_add_flags_from_flagkind(targetflags, target, flagkind)\n        end\n        cache[key] = targetflags\n    end\n    table.join2(flags, targetflags)\nend\n\n-- add flags from the argument option\nfunction builder:_add_flags_from_argument(flags, target, args)\n\n    -- add flags from the flag kinds (cxflags, ..)\n    for _, flagkind in ipairs(self:_flagkinds()) do\n        table.join2(flags, self:_mapflags(args[flagkind], flagkind, target))\n        local original_flags = (args.force or {})[flagkind]\n        if original_flags then\n            table.join2(flags, original_flags)\n        end\n    end\n\n    -- add flags (named) from the language\n    self:_add_flags_from_language(flags, {linkorders = args.linkorders, linkgroups = args.linkgroups, getters = {\n        target = function (name)\n            -- we need also to get extra from arguments\n            -- @see https://github.com/xmake-io/xmake/issues/4274\n            --\n            -- e.g.\n            -- package/add_linkgroups(\"xxx\", {group = true})\n            -- {linkgroups = , extras = {\n            --     linkgroups = {z = {group = true}}\n            -- }}\n            local values = args[name]\n            local extras = args.extras and args.extras[name]\n            return values, extras\n        end,\n        toolchain = function (name)\n            if target and target.toolconfig then\n                return target:toolconfig(name)\n            end\n            local plat, arch\n            if target and target.plat then\n                plat = target:plat()\n            end\n            if target and target.arch then\n                arch = target:arch()\n            end\n            return platform.toolconfig(name, plat, arch)\n        end}})\nend\n\n-- add items from getter\nfunction builder:_add_items_from_getter(items, name, opt)\n    local values, extras = opt.getter(name)\n    if values then\n        table.insert(items, {\n            name = name,\n            values = table.wrap(values),\n            check = opt.check,\n            multival = opt.multival,\n            mapper = opt.mapper,\n            extras = extras})\n    end\nend\n\n-- add items from config\nfunction builder:_add_items_from_config(items, name, opt)\n    local values = config.get(name)\n    if values and name:endswith(\"dirs\") then\n        values = path.splitenv(values)\n    end\n    if values then\n        table.insert(items, {\n            name = name,\n            values = table.wrap(values),\n            check = opt.check,\n            multival = opt.multival,\n            mapper = opt.mapper})\n    end\nend\n\n-- add items from toolchain\nfunction builder:_add_items_from_toolchain(items, name, opt)\n    local values\n    local target = opt.target\n    if target and target:type() == \"target\" then\n        values = target:toolconfig(name)\n    else\n        values = platform.toolconfig(name)\n    end\n    if values then\n        table.insert(items, {\n            name = name,\n            values = table.wrap(values),\n            check = opt.check,\n            multival = opt.multival,\n            mapper = opt.mapper})\n    end\nend\n\n-- add items from option\nfunction builder:_add_items_from_option(items, name, opt)\n    local values\n    local target = opt.target\n    if target then\n        values = target:get(name)\n    end\n    if values then\n        table.insert(items, {\n            name = name,\n            values = table.wrap(values),\n            check = opt.check,\n            multival = opt.multival,\n            mapper = opt.mapper})\n    end\nend\n\n-- add items from target\nfunction builder:_add_items_from_target(items, name, opt)\n    local target = opt.target\n    if target then\n        local result, sources = target:get_from(name, \"*\")\n        if result then\n            for idx, values in ipairs(result) do\n                local source = sources[idx]\n                local extras = target:extraconf_from(name, source)\n                values = table.wrap(values)\n                if values and #values > 0 then\n                    table.insert(items, {\n                        name = name,\n                        values = values,\n                        extras = extras,\n                        check = opt.check,\n                        multival = opt.multival,\n                        mapper = opt.mapper})\n                end\n            end\n        end\n    end\nend\n\n-- add flags from the language\nfunction builder:_add_flags_from_language(flags, opt)\n    opt = opt or {}\n\n    -- get order named items\n    local items = {}\n    local target = opt.target\n    for _, flaginfo in ipairs(self:_nameflags()) do\n\n        -- get flag info\n        local flagscope     = flaginfo[1]\n        local flagname      = flaginfo[2]\n        local checkstate    = flaginfo[3]\n        if checkstate then\n            local auto_ignore_flags = target and target.policy and target:policy(\"check.auto_ignore_flags\")\n            if auto_ignore_flags == false then\n                checkstate = false\n            end\n        end\n\n        -- get api name of tool\n        local apiname  = flagname:gsub(\"^nf_\", \"\")\n\n        -- use multiple values mapper if be defined in tool module\n        local multival = false\n        if apiname:endswith(\"s\") then\n            if self:_tool()[\"nf_\" .. apiname] then\n                multival = true\n            else\n                apiname = apiname:sub(1, #apiname - 1)\n            end\n        end\n\n        -- map named flags to real flags\n        local mapper = self:_tool()[\"nf_\" .. apiname]\n        if mapper then\n            local opt_ = {target = target, check = checkstate, multival = multival, mapper = mapper}\n            if opt.getters then\n                local getter = opt.getters[flagscope]\n                if getter then\n                    opt_.getter = getter\n                    self:_add_items_from_getter(items, flagname, opt_)\n                end\n            elseif flagscope == \"target\" and target and target:type() == \"target\" then\n                self:_add_items_from_target(items, flagname, opt_)\n            elseif flagscope == \"target\" and target and target:type() == \"option\" then\n                self:_add_items_from_option(items, flagname, opt_)\n            elseif flagscope == \"config\" then\n                self:_add_items_from_config(items, flagname, opt_)\n            elseif flagscope == \"toolchain\" then\n                self:_add_items_from_toolchain(items, flagname, opt_)\n            end\n        end\n\n    end\n\n    -- sort links\n    local kind = self:kind()\n    if kind == \"ld\" or kind == \"sh\" then\n        local linkorders = table.wrap(opt.linkorders)\n        local linkgroups = table.wrap(opt.linkgroups)\n        if target and target:type() == \"target\" then\n            local values = target:get_from(\"linkorders\", \"*\")\n            if values then\n                for _, value in ipairs(values) do\n                    table.join2(linkorders, value)\n                end\n            end\n            values = target:get_from(\"linkgroups\", \"*\")\n            if values then\n                for _, value in ipairs(values) do\n                    table.join2(linkgroups, value)\n                end\n            end\n        end\n        if #linkorders > 0 or #linkgroups > 0 then\n            self:_sort_links_of_items(items, {linkorders = linkorders, linkgroups = linkgroups})\n        end\n    end\n\n    -- get flags from the items\n    for _, item in ipairs(items) do\n        local check = item.check\n        local mapper = item.mapper\n        local extras = item.extras\n        if item.multival then\n            local extra = self:_extraconf(extras, item.values)\n            local results = mapper(self:_tool(), item.values, {target = target, targetkind = self:_targetkind(), extra = extra})\n            for _, flag in ipairs(table.wrap(results)) do\n                if flag and flag ~= \"\" and (not check or self:has_flags(flag)) then\n                    table.insert(flags, flag)\n                end\n            end\n        else\n            for _, flagvalue in ipairs(item.values) do\n                local extra = self:_extraconf(extras, flagvalue)\n                local flag = mapper(self:_tool(), flagvalue, {target = target, targetkind = self:_targetkind(), extra = extra})\n                if flag and flag ~= \"\" and (not check or self:has_flags(flag)) then\n                    table.insert(flags, flag)\n                end\n            end\n        end\n    end\nend\n\n-- sort links of items\nfunction builder:_sort_links_of_items(items, opt)\n    opt = opt or {}\n    local sortlinks = false\n    local makegroups = false\n    local linkorders = table.wrap(opt.linkorders)\n    if #linkorders > 0 then\n        sortlinks = true\n    end\n    local linkgroups = table.wrap(opt.linkgroups)\n    local linkgroups_set = hashset.new()\n    if #linkgroups > 0 then\n        makegroups = true\n        for _, linkgroup in ipairs(linkgroups) do\n            for _, link in ipairs(linkgroup) do\n                linkgroups_set:insert(link)\n            end\n        end\n    end\n\n    -- get all links\n    local links = {}\n    local linkgroups_map = {}\n    local extras_map = {}\n    local link_mapper\n    local framework_mapper\n    local linkgroup_mapper\n    if sortlinks or makegroups then\n        local linkitems = {}\n        table.remove_if(items, function (_, item)\n            local name = item.name\n            local removed = false\n            if name == \"links\" or name == \"syslinks\" then\n                link_mapper = item.mapper\n                removed = true\n                table.insert(linkitems, item)\n            elseif name == \"frameworks\" then\n                framework_mapper = item.mapper\n                removed = true\n                table.insert(linkitems, item)\n            elseif name == \"linkgroups\" then\n                linkgroup_mapper = item.mapper\n                removed = true\n                table.insert(linkitems, item)\n            end\n            return removed\n        end)\n\n        -- @note table.remove_if will traverse backwards,\n        -- we need to fix the initial link order first to make sure the syslinks are in the correct order\n        linkitems = table.reverse(linkitems)\n        for _, item in ipairs(linkitems) do\n            local name = item.name\n            for _, value in ipairs(item.values) do\n                if name == \"links\" or name == \"syslinks\" then\n                    if not linkgroups_set:has(value) then\n                        table.insert(links, value)\n                    end\n                elseif name == \"frameworks\" then\n                    table.insert(links, \"framework::\" .. value)\n                elseif name == \"linkgroups\" then\n                    local extras = item.extras\n                    local extra = self:_extraconf(extras, value)\n                    local key = extra and extra.name or tostring(value)\n                    table.insert(links, \"linkgroup::\" .. key)\n                    extras_map[key] = extras\n                    local oldvalue = linkgroups_map[key]\n                    if oldvalue == nil then\n                        linkgroups_map[key] = value\n                    else\n                        -- merge linkgroups if multiple groups have same group name\n                        -- @see https://github.com/xmake-io/xmake/issues/5806\n                        local oldvalue_wrap_unlock = table.clone(oldvalue)\n                        table.wrap_unlock(oldvalue_wrap_unlock)\n                        local value_wrap_unlock = table.clone(value)\n                        table.wrap_unlock(value_wrap_unlock)\n                        local newvalue = table.join(oldvalue_wrap_unlock, value_wrap_unlock)\n                        table.wrap_lock(newvalue)\n                        linkgroups_map[key] = newvalue\n\n                        -- merge linkgroups extras\n                        local extra_merged = {}\n                        local group_name = extra.name\n                        for k, v in pairs(extras) do\n                            if v.name == group_name then\n                                table.join2(extra_merged, v)\n                            end\n                        end\n                        local newgroup_name = table.concat(newvalue, \"_\")\n                        extras[newgroup_name] = extra_merged\n                    end\n                end\n            end\n        end\n        links = table.reverse_unique(links)\n    end\n\n    -- sort sublinks\n    if sortlinks then\n        local gh = graph.new(true)\n        local from\n        local original_deps = {}\n        for _, link in ipairs(links) do\n            local to = link\n            if from and to then\n                original_deps[from] = to\n            end\n            from = to\n        end\n        -- we need remove cycle in original links\n        -- e.g.\n        --\n        -- case1:\n        -- original_deps: a -> b -> c -> d -> e\n        -- new deps: e -> b\n        -- graph: a -> b -> c -> d    e  (remove d -> e, add d -> nil)\n        --            /|\\             |\n        --              --------------\n        --\n        -- case2:\n        -- original_deps: a -> b -> c -> d -> e\n        -- new deps: b -> a\n        --\n        --         ---------\n        --        |        \\|/\n        -- graph: a    b -> c -> d -> e  (remove a -> b, add a -> c)\n        --       /|\\   |\n        --         ----\n        --\n        local function remove_cycle_in_original_deps(f, t)\n            local k\n            local v = t\n            while v ~= f do\n                k = v\n                v = original_deps[v]\n                if v == nil then\n                    break\n                end\n            end\n            if v == f and k ~= nil then\n                -- break the original from node, link to next node\n                -- e.g.\n                -- case1: d -x-> e, d -> nil, k: d, f: e\n                -- case2: a -x-> b, a -> c, k: a, f: b\n                original_deps[k] = original_deps[f]\n            end\n        end\n        local links_set = hashset.from(links)\n        for _, linkorder in ipairs(linkorders) do\n            local from\n            for _, link in ipairs(linkorder) do\n                if links_set:has(link) then\n                    local to = link\n                    if from and to then\n                        remove_cycle_in_original_deps(from, to)\n                        gh:add_edge(from, to)\n                    end\n                    from = to\n                end\n            end\n        end\n        for k, v in pairs(original_deps) do\n            gh:add_edge(k, v)\n        end\n        if not gh:empty() then\n            local has_cycle\n            links, has_cycle = gh:topo_sort()\n            if has_cycle then\n                local cycle = gh:find_cycle()\n                if cycle then\n                    utils.warning(\"cycle links found in add_linkorders(): %s\", table.concat(cycle, \" -> \"))\n                end\n            end\n        end\n    end\n\n    -- re-generate links to items list\n    if sortlinks or makegroups then\n        for _, link in ipairs(links) do\n            if link:startswith(\"framework::\") then\n                link = link:sub(12)\n                table.insert(items, {name = \"frameworks\", values = table.wrap(link), check = false, multival = false, mapper = framework_mapper})\n            elseif link:startswith(\"linkgroup::\") then\n                local key = link:sub(12)\n                local values = linkgroups_map[key]\n                local extras = extras_map[key]\n                table.insert(items, {name = \"linkgroups\", values = table.wrap(values), extras = extras, check = false, multival = false, mapper = linkgroup_mapper})\n            else\n                table.insert(items, {name = \"links\", values = table.wrap(link), check = false, multival = false, mapper = link_mapper})\n            end\n        end\n    end\nend\n\n-- preprocess flags\nfunction builder:_preprocess_flags(flags)\n\n    -- remove repeat by right direction, because we need to consider links/deps order\n    -- @note https://github.com/xmake-io/xmake/issues/1240\n    local unique = {}\n    local count = #flags\n    if count > 1 then\n        local flags_new = {}\n        for idx = count, 1, -1 do\n            local flag = flags[idx]\n            local flagkey = type(flag) == \"table\" and table.concat(flag, \"\") or flag\n            if flag and not unique[flagkey] then\n                table.insert(flags_new, flag)\n                unique[flagkey] = true\n            end\n        end\n        flags = flags_new\n        count = #flags_new\n    end\n\n    -- remove repeat first and split flags group, e.g. \"-I /xxx\" => {\"-I\", \"/xxx\"}\n    local results = {}\n    if count > 0 then\n        for idx = count, 1, -1 do\n            local flag = flags[idx]\n            if type(flag) == \"string\" then\n                flag = flag:trim()\n                if #flag > 0 then\n                    if flag:find(\" \", 1, true) then\n                        table.join2(results, os.argv(flag, {splitonly = true}))\n                    else\n                        table.insert(results, flag)\n                    end\n                end\n            else\n                -- may be a table group? e.g. {\"-I\", \"/xxx\"}\n                if #flag > 0 then\n                    table.wrap_unlock(flag)\n                    table.join2(results, flag)\n                end\n            end\n        end\n    end\n    return results\nend\n\n-- get the target\nfunction builder:target()\n    return self._TARGET\nend\n\n-- get tool name\nfunction builder:name()\n    return self:_tool():name()\nend\n\n-- get tool kind\nfunction builder:kind()\n    return self:_tool():kind()\nend\n\n-- get tool program\nfunction builder:program()\n    return self:_tool():program()\nend\n\n-- get toolchain of this tool\nfunction builder:toolchain()\n    return self:_tool():toolchain()\nend\n\n-- get the run environments\nfunction builder:runenvs()\n    return self:_tool():runenvs()\nend\n\n-- get properties of the tool\nfunction builder:get(name)\n    return self:_tool():get(name)\nend\n\n-- has flags?\nfunction builder:has_flags(flags, flagkind, opt)\n    return self:_tool():has_flags(flags, flagkind, opt)\nend\n\n-- map flags from name and values, e.g. linkdirs, links, defines\nfunction builder:map_flags(name, values, opt)\n    local flags  = {}\n    local mapper = self:_tool()[\"nf_\" .. name]\n    local multival = false\n    if name:endswith(\"s\") then\n        multival = true\n    elseif not mapper then\n        mapper = self:_tool()[\"nf_\" .. name .. \"s\"]\n        if mapper then\n            multival = true\n        end\n    end\n    if mapper then\n        opt = opt or {}\n        if multival then\n            local extra = self:_extraconf(opt.extras, values)\n            local results = mapper(self:_tool(), values, {target = opt.target, targetkind = opt.targetkind, extra = extra})\n            for _, flag in ipairs(table.wrap(results)) do\n                if flag and flag ~= \"\" and (not opt.check or self:has_flags(flag)) then\n                    table.insert(flags, flag)\n                end\n            end\n        else\n            for _, value in ipairs(table.wrap(values)) do\n                local extra = self:_extraconf(opt.extras, value)\n                local flag = mapper(self:_tool(), value, {target = opt.target, targetkind = opt.targetkind, extra = extra})\n                if flag and flag ~= \"\" and (not opt.check or self:has_flags(flag)) then\n                    table.join2(flags, flag)\n                end\n            end\n        end\n    end\n    if #flags > 0 then\n        return flags\n    end\nend\n\n-- return module\nreturn builder\n"
  },
  {
    "path": "xmake/core/tool/compiler.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        compiler.lua\n--\n\n-- define module\nlocal compiler = compiler or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal path      = require(\"base/path\")\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal option    = require(\"base/option\")\nlocal profiler  = require(\"base/profiler\")\nlocal tool      = require(\"tool/tool\")\nlocal builder   = require(\"tool/builder\")\nlocal config    = require(\"project/config\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal language  = require(\"language/language\")\nlocal platform  = require(\"platform/platform\")\n\n-- get the language of compiler\nfunction compiler:_language()\n    return self._LANGUAGE\nend\n\n-- add flags from the toolchains\nfunction compiler:_add_flags_from_toolchains(flags, targetkind, target)\n\n    -- add flags for platform with the given target kind, e.g. binary.gcc.cxflags or binary.cxflags\n    if targetkind then\n        local toolname = self:name()\n        if target and target.toolconfig then\n            for _, flagkind in ipairs(self:_flagkinds()) do\n                local toolflags = target:toolconfig(targetkind .. '.' .. toolname .. '.' .. flagkind)\n                table.join2(flags, toolflags or target:toolconfig(targetkind .. '.' .. flagkind))\n            end\n        else\n            for _, flagkind in ipairs(self:_flagkinds()) do\n                local toolflags = platform.toolconfig(targetkind .. '.' .. toolname .. '.' .. flagkind)\n                table.join2(flags, toolflags or platform.toolconfig(targetkind .. '.' .. flagkind))\n            end\n        end\n    end\nend\n\n-- add flags from the compiler\nfunction compiler:_add_flags_from_compiler(flags, targetkind)\n    for _, flagkind in ipairs(self:_flagkinds()) do\n\n        -- add compiler, e.g. cxflags\n        table.join2(flags, self:get(flagkind))\n\n        -- add compiler, e.g. targetkind.cxflags\n        if targetkind then\n            table.join2(flags, self:get(targetkind .. '.' .. flagkind))\n        end\n    end\nend\n\n-- add flags from the sourcefile config\nfunction compiler:_add_flags_from_fileconfig(flags, target, sourcefile, fileconfig)\n\n    -- add flags from the current compiler\n    local add_sourceflags = self:_tool().add_sourceflags\n    if add_sourceflags then\n        local flag = add_sourceflags(self:_tool(), sourcefile, fileconfig, target, self:_targetkind())\n        if flag and flag ~= \"\" then\n            table.join2(flags, flag)\n        end\n    end\n\n    -- add flags from the common argument option\n    self:_add_flags_from_argument(flags, target, fileconfig)\nend\n\n-- load compiler tool\nfunction compiler._load_tool(sourcekind, target)\n    local program, toolname, toolchain_info\n    if target and target.tool then\n        program, toolname, toolchain_info = target:tool(sourcekind)\n    end\n\n    -- is host?\n    local is_host\n    if target and target.is_host then\n        is_host = target:is_host()\n    end\n\n    -- load the compiler tool from the source kind\n    local result, errors = tool.load(sourcekind, {\n        host = is_host,\n        program = program,\n        toolname = toolname,\n        toolchain_info = toolchain_info})\n    if not result then\n        return nil, errors\n    end\n    return result, program\nend\n\n-- load the compiler from the given source kind\nfunction compiler.load(sourcekind, target)\n    if not sourcekind then\n        return nil, \"unknown source kind!\"\n    end\n\n    -- init cache key\n    -- @note we need plat/arch,\n    -- because it is possible for the compiler to do cross-compilation with the -target parameter\n    local plat = config.plat() or os.host()\n    local arch = config.arch() or os.arch()\n    if target and target.tool then\n        local _, _, toolchain_info = target:tool(sourcekind)\n        if toolchain_info then\n            plat = toolchain_info.plat\n            arch = toolchain_info.arch\n        end\n    end\n    local cachekey = sourcekind .. (program_or_errors or \"\") .. plat .. arch\n    if target then\n        cachekey = cachekey .. tostring(target)\n    end\n\n    -- get it directly from cache dirst\n    compiler._INSTANCES = compiler._INSTANCES or {}\n    local instance = compiler._INSTANCES[cachekey]\n    if not instance then\n        instance = table.inherit(compiler, builder)\n\n        -- load compiler tool\n        -- @NOTE We cannot cache the tool, otherwise it may cause duplicate toolchain flags to be added\n        local compiler_tool, program_or_errors = compiler._load_tool(sourcekind, target)\n        if not compiler_tool then\n            return nil, program_or_errors\n        end\n        instance._TOOL = compiler_tool\n\n        -- load the compiler language from the source kind\n        local result, errors = language.load_sk(sourcekind)\n        if not result then\n            return nil, errors\n        end\n        instance._LANGUAGE = result\n\n        -- init target (optional)\n        instance._TARGET = target\n\n        -- init target kind\n        instance._TARGETKIND = \"object\"\n\n        -- init name flags\n        instance._NAMEFLAGS = result:nameflags()[instance:_targetkind()]\n\n        -- init flag kinds\n        instance._FLAGKINDS = table.wrap(result:sourceflags()[sourcekind])\n\n        -- add toolchains flags to the compiler tool, e.g. gcc.cxflags or cxflags\n        local toolname = compiler_tool:name()\n        if target and target.toolconfig then\n            for _, flagkind in ipairs(instance:_flagkinds()) do\n                compiler_tool:add(flagkind, target:toolconfig(toolname .. '.' .. flagkind) or target:toolconfig(flagkind))\n            end\n        else\n            for _, flagkind in ipairs(instance:_flagkinds()) do\n                compiler_tool:add(flagkind, platform.toolconfig(toolname .. '.' .. flagkind) or platform.toolconfig(flagkind))\n            end\n        end\n\n        -- @note we can't call _load_once before caching the instance,\n        -- it may call has_flags to trigger the concurrent scheduling.\n        --\n        -- this will result in more compiler/linker instances being created at the same time,\n        -- and they will access the same tool instance at the same time.\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/3429\n        compiler._INSTANCES[cachekey] = instance\n    end\n\n    -- we need to load it at the end because in tool.load().\n    -- because we may need to call has_flags, which requires the full platform toolchain flags\n    local ok, errors = instance:_tool():_load_once()\n    if not ok then\n        return nil, errors\n    end\n    return instance\nend\n\n-- build the source files (compile and link)\nfunction compiler:build(sourcefiles, targetfile, opt)\n    opt = opt or {}\n\n    -- get compile flags\n    local compflags = opt.compflags\n    if not compflags then\n        -- patch sourcefile to get flags of the given source file\n        if type(sourcefiles) == \"string\" then\n            opt.sourcefile = sourcefiles\n        end\n        compflags = self:compflags(opt)\n    end\n\n    -- make flags\n    local flags = compflags\n    if opt.target then\n        flags = table.join(flags, opt.target:linkflags())\n    end\n\n    -- get target kind\n    local targetkind = opt.targetkind\n    if not targetkind and opt.target and opt.target.targetkind then\n        targetkind = opt.target:kind()\n    end\n    return sandbox.load(self:_tool().build, self:_tool(), sourcefiles, targetkind or \"binary\", targetfile, flags, opt)\nend\n\n-- get the build arguments list (compile and link)\nfunction compiler:buildargv(sourcefiles, targetfile, opt)\n    opt = opt or {}\n\n    -- get compile flags\n    local compflags = opt.compflags\n    if not compflags then\n        -- patch sourcefile to get flags of the given source file\n        if type(sourcefiles) == \"string\" then\n            opt.sourcefile = sourcefiles\n        end\n        compflags = self:compflags(opt)\n    end\n\n    -- make flags\n    local flags = compflags\n    if opt.target then\n        flags = table.join(flags, opt.target:linkflags())\n    end\n\n    -- get target kind\n    local targetkind = opt.targetkind\n    if not targetkind and opt.target and opt.target.targetkind then\n        targetkind = opt.target:kind()\n    end\n    return self:_tool():buildargv(sourcefiles, targetkind or \"binary\", targetfile, flags, opt)\nend\n\n-- get the build command\nfunction compiler:buildcmd(sourcefiles, targetfile, opt)\n    return os.args(table.join(self:buildargv(sourcefiles, targetfile, opt)))\nend\n\n-- compile the source files\nfunction compiler:compile(sourcefiles, objectfile, opt)\n    opt = opt or {}\n\n    -- get compile flags\n    local compflags = opt.compflags\n    if not compflags then\n        -- patch sourcefile to get flags of the given source file\n        if type(sourcefiles) == \"string\" then\n            opt.sourcefile = sourcefiles\n        end\n        compflags = self:compflags(opt)\n    end\n\n    -- compile it\n    opt = table.copy(opt)\n    opt.target = self:target()\n    profiler:enter(self:name(), \"compile\", sourcefiles)\n    local ok, errors = sandbox.load(self:_tool().compile, self:_tool(), sourcefiles, objectfile, opt.dependinfo, compflags, opt)\n    profiler:leave(self:name(), \"compile\", sourcefiles)\n    return ok, errors\nend\n\n-- get the compile arguments list\nfunction compiler:compargv(sourcefiles, objectfile, opt)\n    opt = opt or {}\n\n    -- get compile flags\n    local compflags = opt.compflags\n    if not compflags then\n        -- patch sourcefile to get flags of the given source file\n        if type(sourcefiles) == \"string\" then\n            opt.sourcefile = sourcefiles\n        end\n        compflags = self:compflags(opt)\n    end\n    return self:_tool():compargv(sourcefiles, objectfile, compflags, opt)\nend\n\n-- get the compile command\nfunction compiler:compcmd(sourcefiles, objectfile, opt)\n    return os.args(table.join(self:compargv(sourcefiles, objectfile, opt)))\nend\n\n-- get the compling flags\n--\n-- @param opt   the argument options (contain all the compiler attributes of target),\n--              e.g.\n--              {target = ..., targetkind = \"static\", configs = {defines = \"\", cxflags = \"\", includedirs = \"\"}}\n--\n-- @return      flags list\n--\nfunction compiler:compflags(opt)\n    opt = opt or {}\n\n    -- get target\n    local target = opt.target or self:target()\n    local targetkind = opt.targetkind\n    if not targetkind and target and target:type() == \"target\" then\n        targetkind = target:kind()\n    end\n\n    -- add flags from compiler/toolchains\n    --\n    -- we need to add toolchain flags at the beginning to allow users to override them.\n    -- but includedirs/links/syslinks/linkdirs will still be placed last, they are in the order defined in languages/xmake.lua\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/978\n    --\n    local flags = {}\n    self:_add_flags_from_compiler(flags, targetkind)\n    self:_add_flags_from_toolchains(flags, targetkind, target)\n\n    -- add flags from target\n    self:_add_flags_from_target(flags, target)\n\n    -- add flags from source file configuration\n    if opt.sourcefile and target and target.fileconfig then\n        local fileconfig = target:fileconfig(opt.sourcefile)\n        if fileconfig then\n            self:_add_flags_from_fileconfig(flags, target, opt.sourcefile, fileconfig)\n        end\n    end\n\n    -- add flags from argument\n    local configs = opt.configs or opt.config\n    if configs then\n        self:_add_flags_from_argument(flags, target, configs)\n    end\n\n    -- add flags from user configuration\n    self:_add_flags_from_config(flags)\n\n    -- preprocess flags\n    return self:_preprocess_flags(flags)\nend\n\n-- return module\nreturn compiler\n"
  },
  {
    "path": "xmake/core/tool/linker.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linker.lua\n--\n\n-- define module\nlocal linker = linker or {}\n\n-- load modules\nlocal io        = require(\"base/io\")\nlocal path      = require(\"base/path\")\nlocal utils     = require(\"base/utils\")\nlocal table     = require(\"base/table\")\nlocal string    = require(\"base/string\")\nlocal option    = require(\"base/option\")\nlocal profiler  = require(\"base/profiler\")\nlocal config    = require(\"project/config\")\nlocal sandbox   = require(\"sandbox/sandbox\")\nlocal language  = require(\"language/language\")\nlocal platform  = require(\"platform/platform\")\nlocal tool      = require(\"tool/tool\")\nlocal builder   = require(\"tool/builder\")\nlocal compiler  = require(\"tool/compiler\")\n\n-- add flags from the toolchains\nfunction linker:_add_flags_from_toolchains(flags, targetkind, target)\n\n    -- attempt to add special lanugage flags first for target kind, e.g. binary.go.gcldflags, static.dcarflags\n    if targetkind then\n        local toolkind = self:kind()\n        local toolname = self:name()\n        if target and target.toolconfig then\n            for _, flagkind in ipairs(self:_flagkinds()) do\n                local toolflags = target:toolconfig(targetkind .. '.' .. toolname .. '.' .. toolkind .. 'flags') or target:toolconfig(targetkind .. '.' .. toolname .. '.' .. flagkind)\n                table.join2(flags, toolflags or target:toolconfig(targetkind .. '.' .. toolkind .. 'flags') or target:toolconfig(targetkind .. '.' .. flagkind))\n            end\n        else\n            for _, flagkind in ipairs(self:_flagkinds()) do\n                local toolflags = platform.toolconfig(targetkind .. '.' .. toolname .. '.' .. toolkind .. 'flags') or platform.toolconfig(targetkind .. '.' .. toolname .. '.' .. flagkind)\n                table.join2(flags, toolflags or platform.toolconfig(targetkind .. '.' .. toolkind .. 'flags') or platform.toolconfig(targetkind .. '.' .. flagkind))\n            end\n        end\n    end\nend\n\n-- add flags from the linker\nfunction linker:_add_flags_from_linker(flags)\n    local toolkind = self:kind()\n    for _, flagkind in ipairs(self:_flagkinds()) do\n        -- attempt to add special lanugage flags first, e.g. gcldflags, dcarflags\n        table.join2(flags, self:get(toolkind .. \"flags\") or self:get(flagkind))\n    end\nend\n\n-- load tool\nfunction linker._load_tool(targetkind, sourcekinds, target)\n\n    -- get the linker infos\n    local linkerinfos, errors = language.linkerinfos_of(targetkind, sourcekinds)\n    if not linkerinfos then\n        return nil, errors\n    end\n\n    -- select the linker\n    local linkerinfo = nil\n    local linkertool = nil\n    local firsterror = nil\n    for _, _linkerinfo in ipairs(linkerinfos) do\n\n        -- get program from target\n        local program, toolname, toolchain_info\n        if target and target.tool then\n            program, toolname, toolchain_info = target:tool(_linkerinfo.linkerkind)\n        end\n\n        -- is host?\n        local is_host\n        if target and target.is_host then\n            is_host = target:is_host()\n        end\n\n        -- load the linker tool from the linker kind (with cache)\n        linkertool, errors = tool.load(_linkerinfo.linkerkind, {\n            host = is_host,\n            program = program,\n            toolname = toolname,\n            toolchain_info = toolchain_info})\n        if linkertool then\n            linkerinfo = _linkerinfo\n            linkerinfo.program = program\n            break\n        else\n            firsterror = firsterror or errors\n        end\n    end\n    if not linkerinfo then\n        return nil, firsterror\n    end\n    return linkertool, linkerinfo\nend\n\n-- load the linker from the given target kind\nfunction linker.load(targetkind, sourcekinds, target)\n    assert(sourcekinds)\n\n    -- wrap sourcekinds first\n    sourcekinds = table.wrap(sourcekinds)\n    if #sourcekinds == 0 then\n        -- we need to detect the sourcekinds of all deps if the current target has not any source files\n        for _, dep in ipairs(target:orderdeps()) do\n            table.join2(sourcekinds, dep:sourcekinds())\n        end\n        if #sourcekinds > 0 then\n            sourcekinds = table.unique(sourcekinds)\n        end\n    end\n\n    -- load linker tool first, we need to get the correct plat/arch\n    -- @NOTE We cannot cache the tool, otherwise it may cause duplicate toolchain flags to be added\n    local linkertool, linkerinfo_or_errors = linker._load_tool(targetkind, sourcekinds, target)\n    if not linkertool then\n        return nil, linkerinfo_or_errors\n    end\n\n    -- get linker info\n    local linkerinfo = linkerinfo_or_errors\n\n    -- init cache key\n    local plat = linkertool:plat() or config.plat() or os.host()\n    local arch = linkertool:arch() or config.arch() or os.arch()\n    local cachekey = targetkind .. \"_\" .. linkerinfo.linkerkind .. (linkerinfo.program or \"\") .. plat .. arch\n    cachekey = cachekey .. table.concat(sourcekinds, \"\") -- @see https://github.com/xmake-io/xmake/issues/5360\n    if target then\n        cachekey = cachekey .. tostring(target)\n    end\n\n    -- get it directly from cache dirst\n    builder._INSTANCES = builder._INSTANCES or {}\n    local instance = builder._INSTANCES[cachekey]\n    if not instance then\n\n        -- new instance\n        instance = table.inherit(linker, builder)\n\n        -- save linker tool\n        instance._TOOL = linkertool\n\n        -- load the name flags of archiver\n        local nameflags = {}\n        local nameflags_exists = {}\n        for _, sourcekind in ipairs(sourcekinds) do\n\n            -- load language\n            local result, errors = language.load_sk(sourcekind)\n            if not result then\n                return nil, errors\n            end\n\n            -- merge name flags\n            for _, flaginfo in ipairs(table.wrap(result:nameflags()[targetkind])) do\n                local key = flaginfo[1] .. flaginfo[2]\n                if not nameflags_exists[key] then\n                    table.insert(nameflags, flaginfo)\n                    nameflags_exists[key] = flaginfo\n                end\n            end\n        end\n        instance._NAMEFLAGS = nameflags\n\n        -- init target (optional)\n        instance._TARGET = target\n\n        -- init target kind\n        instance._TARGETKIND = targetkind\n\n        -- init flag kinds\n        instance._FLAGKINDS = {linkerinfo.linkerflag}\n\n        -- add toolchains flags to the linker tool\n        -- add special lanugage flags first, e.g. go.gcldflags or gcc.ldflags or gcldflags or ldflags\n        local toolkind = linkertool:kind()\n        local toolname = linkertool:name()\n        if target and target.toolconfig then\n            for _, flagkind in ipairs(instance:_flagkinds()) do\n                linkertool:add(toolkind .. 'flags', target:toolconfig(toolname .. '.' .. toolkind .. 'flags') or target:toolconfig(toolkind .. 'flags'))\n                linkertool:add(flagkind, target:toolconfig(toolname .. '.' .. flagkind) or target:toolconfig(flagkind))\n            end\n        else\n            for _, flagkind in ipairs(instance:_flagkinds()) do\n                linkertool:add(toolkind .. 'flags', platform.toolconfig(toolname .. '.' .. toolkind .. 'flags') or platform.toolconfig(toolkind .. 'flags'))\n                linkertool:add(flagkind, platform.toolconfig(toolname .. '.' .. flagkind) or platform.toolconfig(flagkind))\n            end\n        end\n\n        -- @note we can't call _load_once before caching the instance,\n        -- it may call has_flags to trigger the concurrent scheduling.\n        --\n        -- this will result in more compiler/linker instances being created at the same time,\n        -- and they will access the same tool instance at the same time.\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/3429\n        builder._INSTANCES[cachekey] = instance\n    end\n\n    -- we need to load it at the end because in tool.load().\n    -- because we may need to call has_flags, which requires the full platform toolchain flags\n    local ok, errors = instance:_tool():_load_once()\n    if not ok then\n        return nil, errors\n    end\n    return instance\nend\n\n-- link the target file\nfunction linker:link(objectfiles, targetfile, opt)\n    opt = opt or {}\n    local linkflags = opt.linkflags or self:linkflags(opt)\n    profiler:enter(self:name(), \"link\", targetfile)\n    local ok, errors = sandbox.load(self:_tool().link, self:_tool(),\n        table.wrap(objectfiles), self:_targetkind(), targetfile, linkflags,\n        table.join(opt, {target = self:target()}))\n    profiler:leave(self:name(), \"link\", targetfile)\n    return ok, errors\nend\n\n-- get the link arguments list\nfunction linker:linkargv(objectfiles, targetfile, opt)\n    opt = opt or {}\n    return self:_tool():linkargv(table.wrap(objectfiles),\n        self:_targetkind(), targetfile, opt.linkflags or self:linkflags(opt),\n        table.join(opt, {target = self:target()}))\nend\n\n-- get the link command\nfunction linker:linkcmd(objectfiles, targetfile, opt)\n    return os.args(table.join(self:linkargv(objectfiles, targetfile, opt)))\nend\n\n-- get the link flags\n--\n-- @param opt   the argument options (contain all the linker attributes of target),\n--              e.g. {target = ..., targetkind = \"static\", configs = {ldflags = \"\", links = \"\", linkdirs = \"\", ...}}\n--\nfunction linker:linkflags(opt)\n    opt = opt or {}\n\n    -- get target\n    local target = opt.target or self:target()\n    local targetkind = opt.targetkind\n    if not targetkind and target and target:type() == \"target\" then\n        targetkind = target:kind()\n    end\n\n    -- add flags from linker/toolchains\n    --\n    -- we need to add toolchain flags at the beginning to allow users to override them.\n    -- but includedirs/links/syslinks/linkdirs will still be placed last, they are in the order defined in languages/xmake.lua\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/978\n    --\n    local flags = {}\n    self:_add_flags_from_linker(flags)\n    self:_add_flags_from_toolchains(flags, targetkind, target)\n\n    -- add flags from target\n    self:_add_flags_from_target(flags, target)\n\n    -- add flags from argument\n    local configs = opt.configs or opt.config\n    if configs then\n        self:_add_flags_from_argument(flags, target, configs)\n    end\n\n    -- add flags from user configuration\n    self:_add_flags_from_config(flags)\n\n    -- preprocess flags\n    return self:_preprocess_flags(flags)\nend\n\n-- return module\nreturn linker\n"
  },
  {
    "path": "xmake/core/tool/tool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific tool governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tool.lua\n--\n\n-- define module\nlocal tool      = tool or {}\nlocal _instance = _instance or {}\n\n-- load modules\nlocal os            = require(\"base/os\")\nlocal path          = require(\"base/path\")\nlocal utils         = require(\"base/utils\")\nlocal table         = require(\"base/table\")\nlocal string        = require(\"base/string\")\nlocal config        = require(\"project/config\")\nlocal sandbox       = require(\"sandbox/sandbox\")\nlocal toolchain     = require(\"tool/toolchain\")\nlocal platform      = require(\"platform/platform\")\nlocal language      = require(\"language/language\")\nlocal is_cross      = require(\"base/private/is_cross\")\nlocal import        = require(\"sandbox/modules/import\")\n\n-- new an instance\nfunction _instance.new(kind, name, program, plat, arch, toolchain_inst)\n\n    -- import \"core.tools.xxx\"\n    -- @note we need to create a tool instance with unique toolclass context (_g)\n    local toolclass = import(\"core.tools.\" .. name, {try = true, nocache = true})\n\n    -- not found?\n    if not toolclass then\n        return nil, string.format(\"cannot import \\\"core.tools.%s\\\" module!\", name)\n    end\n\n    -- new an instance\n    local instance = table.inherit(_instance, toolclass)\n\n    -- save name, kind and program\n    instance._NAME      = name\n    instance._KIND      = kind\n    instance._PROGRAM   = program\n    instance._PLAT      = plat\n    instance._ARCH      = arch\n    instance._TOOLCHAIN = toolchain_inst\n    instance._INFO      = {}\n\n    -- init instance\n    if instance.init then\n        local ok, errors = sandbox.load(instance.init, instance)\n        if not ok then\n            return nil, errors\n        end\n    end\n    return instance\nend\n\n-- get the tool name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the tool kind\nfunction _instance:kind()\n    return self._KIND\nend\n\n-- get the tool platform\nfunction _instance:plat()\n    return self._PLAT\nend\n\n-- get the tool architecture\nfunction _instance:arch()\n    return self._ARCH\nend\n\n-- the current target is belong to the given platforms?\nfunction _instance:is_plat(...)\n    local plat = self:plat()\n    for _, v in ipairs(table.join(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current target is belong to the given architectures?\nfunction _instance:is_arch(...)\n    local arch = self:arch()\n    for _, v in ipairs(table.join(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- is cross-compilation?\nfunction _instance:is_cross()\n    return is_cross(self:plat(), self:arch())\nend\n\n-- get the tool program\nfunction _instance:program()\n    return self._PROGRAM\nend\n\n-- get the toolchain of this tool\nfunction _instance:toolchain()\n    return self._TOOLCHAIN\nend\n\n-- get run environments\nfunction _instance:runenvs()\n    return self:toolchain() and self:toolchain():runenvs()\nend\n\n-- set the value to the platform info\nfunction _instance:set(name, ...)\n    self._INFO[name] = table.unwrap({...})\nend\n\n-- add the value to the platform info\nfunction _instance:add(name, ...)\n    local info = table.wrap(self._INFO[name])\n    self._INFO[name] = table.unwrap(table.join(info, ...))\nend\n\n-- get the platform configure\nfunction _instance:get(name)\n    if self._super_get then\n        local value = self:_super_get(name)\n        if value ~= nil then\n            return value\n        end\n    end\n    return self._INFO[name]\nend\n\n-- has the given flag?\nfunction _instance:has_flags(flags, flagkind, opt)\n\n    -- init options\n    opt = opt or {}\n    opt.program = opt.program or self:program()\n    opt.toolkind = opt.toolkind or self:kind()\n    opt.flagkind = opt.flagkind or flagkind\n    opt.sysflags = opt.sysflags or self:_sysflags(opt.toolkind, opt.flagkind)\n\n    -- import has_flags()\n    self._has_flags = self._has_flags or import(\"lib.detect.has_flags\", {anonymous = true})\n\n    -- bind the run environments\n    opt.envs = self:runenvs()\n\n    -- has flags?\n    return self._has_flags(self:name(), flags, opt)\nend\n\n-- load tool only once\nfunction _instance:_load_once()\n    if not self._LOADED then\n        if self.load then\n            local ok, errors = sandbox.load(self.load, self)\n            if not ok then\n                return false, errors\n            end\n        end\n        self._LOADED = true\n    end\n    return true\nend\n\n-- get system flags from toolchains\n-- @see https://github.com/xmake-io/xmake/issues/3429\nfunction _instance:_sysflags(toolkind, flagkind)\n    local sysflags = {}\n    local sourceflags = language.sourceflags()[toolkind]\n    if not sourceflags and flagkind then\n        sourceflags = {}\n        if flagkind == \"cflags\" or flagkind == \"cxxflags\" then\n            table.insert(sourceflags, flagkind)\n            table.insert(sourceflags, \"cxflags\")\n        elseif flagkind == \"cxflags\" then\n            table.insert(sourceflags, flagkind)\n            table.insert(sourceflags, \"cxxflags\")\n        elseif flagkind == \"mflags\" or flagkind == \"mxxflags\" then\n            table.insert(sourceflags, flagkind)\n            table.insert(sourceflags, \"mxflags\")\n        elseif flagkind == \"mxflags\" then\n            table.insert(sourceflags, flagkind)\n            table.insert(sourceflags, \"mxxflags\")\n        else\n            -- flagkind may be ldflags, we need to ignore it\n            -- and we should use more precise flagkind, e.g. rcldflags instead of ldflags\n        end\n    end\n    if sourceflags then\n        for _, flagname in ipairs(table.wrap(sourceflags)) do\n            local flags = self:get(flagname)\n            if flags then\n                table.join2(sysflags, flags)\n            end\n        end\n    end\n    -- maybe it's linker flags, ld -> ldflags, dcld -> dcldflags\n    if #sysflags == 0 then\n        table.join2(sysflags, self:get(toolkind .. \"flags\"))\n    end\n    if #sysflags > 0 then\n        return sysflags\n    end\nend\n\n-- load the given tool from the given kind\n--\n-- @param kind                the tool kind e.g. cc, cxx, mm, mxx, as, ar, ld, sh, ..\n-- @param opt.program         the tool program, e.g. /xxx/arm-linux-gcc, gcc@mipscc.exe, (optional)\n-- @param opt.toolname        gcc, clang, .. (optional)\n-- @param opt.toolchain_info  the toolchain info (optional)\n--\nfunction tool.load(kind, opt)\n    opt = opt or {}\n    local program = opt.program\n    local toolname = opt.toolname\n    local toolchain_info = opt.toolchain_info or {}\n\n    -- get platform and architecture\n    local plat = toolchain_info.plat or config.plat() or os.host()\n    local arch = toolchain_info.arch or config.arch() or os.arch()\n\n    -- contain toolname? parse it, e.g. 'gcc@xxxx.exe'\n    if program then\n        local pos = program:find('@', 1, true)\n        if pos then\n            -- we need to ignore valid path with `@`, e.g. /usr/local/opt/go@1.17/bin/go\n            -- https://github.com/xmake-io/xmake/issues/2853\n            local prefix = program:sub(1, pos - 1)\n            if prefix and not prefix:find(\"[/\\\\]\") then\n                toolname = prefix\n                program = program:sub(pos + 1)\n            end\n        end\n    end\n\n    -- get the tool program and name\n    if not program then\n        program, toolname, toolchain_info = platform.tool(kind, plat, arch, {host = opt.host})\n        if toolchain_info then\n            assert(toolchain_info.plat == plat)\n            assert(toolchain_info.arch == arch)\n        end\n    end\n    if not program then\n        return nil, string.format(\"cannot get program for %s\", kind)\n    end\n\n    -- import find_toolname()\n    tool._find_toolname = tool._find_toolname or import(\"lib.detect.find_toolname\")\n\n    -- get the tool name from the program\n    local ok, name_or_errors = sandbox.load(tool._find_toolname, toolname or program, {program = program})\n    if not ok then\n        return nil, name_or_errors\n    end\n\n    -- get name\n    local name = name_or_errors\n    if not name then\n        return nil, string.format(\"cannot find known tool script for %s\", toolname or program)\n    end\n\n    -- load toolchain instance\n    local toolchain_inst\n    if toolchain_info and toolchain_info.name then\n        toolchain_inst = toolchain.load(toolchain_info.name, {plat = plat, arch = arch, cachekey = toolchain_info.cachekey})\n    end\n\n    -- new an instance\n    local instance, errors = _instance.new(kind, name, program, plat, arch, toolchain_inst)\n    if not instance then\n        return nil, errors\n    end\n    return instance\nend\n\n-- return module\nreturn tool\n"
  },
  {
    "path": "xmake/core/tool/toolchain.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        toolchain.lua\n--\n\n-- define module\nlocal toolchain      = toolchain or {}\nlocal _instance     = _instance or {}\n\n-- load modules\nlocal os             = require(\"base/os\")\nlocal path           = require(\"base/path\")\nlocal utils          = require(\"base/utils\")\nlocal table          = require(\"base/table\")\nlocal global         = require(\"base/global\")\nlocal option         = require(\"base/option\")\nlocal hashset        = require(\"base/hashset\")\nlocal scopeinfo      = require(\"base/scopeinfo\")\nlocal interpreter    = require(\"base/interpreter\")\nlocal is_cross       = require(\"base/private/is_cross\")\nlocal config         = require(\"project/config\")\nlocal memcache       = require(\"cache/memcache\")\nlocal localcache     = require(\"cache/localcache\")\nlocal language       = require(\"language/language\")\nlocal sandbox        = require(\"sandbox/sandbox\")\nlocal sandbox_module = require(\"sandbox/modules/import/core/sandbox/module\")\n\n-- new an instance\nfunction _instance.new(name, info, opt)\n    opt = opt or {}\n    local cachekey = opt.cachekey\n    local configs = opt.configs\n    local instance = table.inherit(_instance)\n    local parts = name:split(\"::\", {plain = true})\n    instance._NAME = parts[#parts]\n    table.remove(parts)\n    if #parts > 0 then\n        instance._NAMESPACE = table.concat(parts, \"::\")\n    end\n    instance._INFO          = info\n    instance._REQUIRESTR    = opt.requirestr\n    instance._IS_BUILTIN    = opt.is_builtin\n    instance._CACHE         = toolchain._localcache()\n    instance._CACHEKEY      = cachekey\n    local toolchain_configs = instance._CACHE:get(cachekey)\n    if toolchain_configs == nil then\n        toolchain_configs = {}\n        instance._CACHE:set(cachekey, toolchain_configs)\n    end\n    instance._CONFIGS = toolchain_configs\n    for k, v in pairs(configs) do\n        toolchain_configs[k] = v\n    end\n    -- is global toolchain for the whole platform?\n    configs.plat = nil\n    configs.arch = nil\n    configs.cachekey = nil\n    local plat = config.get(\"plat\") or os.host()\n    local arch = config.get(\"arch\") or os.arch()\n    if instance:is_plat(plat) and instance:is_arch(arch) and #table.keys(configs) == 0 then\n        toolchain_configs.__global = true\n    end\n    return instance\nend\n\n-- get toolchain name\nfunction _instance:name()\n    return self._NAME\nend\n\n-- get the namespace\nfunction _instance:namespace()\n    return self._NAMESPACE\nend\n\n-- get the full name\nfunction _instance:fullname()\n    local namespace = self:namespace()\n    local name = self:name()\n    local requirestr = self._REQUIRESTR\n    if requirestr then\n        name = name .. \"[\" .. requirestr .. \"]\"\n    end\n    return namespace and namespace .. \"::\" .. name or name\nend\n\n-- get memcache\nfunction _instance:memcache()\n    local cache = self._MEMCACHE\n    if not cache then\n        cache = memcache.cache(\"core.tool.toolchain.\" .. self:cachekey())\n        self._MEMCACHE = cache\n    end\n    return cache\nend\n\n-- get toolchain platform\nfunction _instance:plat()\n    return self._PLAT or self:config(\"plat\")\nend\n\n-- set toolchain platform\nfunction _instance:plat_set(plat)\n    self._PLAT = plat\nend\n\n-- get toolchain architecture\nfunction _instance:arch()\n    return self._ARCH or self:config(\"arch\")\nend\n\n-- set toolchain architecture\nfunction _instance:arch_set(arch)\n    self._ARCH = arch\nend\n\n-- the current platform is belong to the given platforms?\nfunction _instance:is_plat(...)\n    local plat = self:plat()\n    for _, v in ipairs(table.join(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current architecture is belong to the given architectures?\nfunction _instance:is_arch(...)\n    local arch = self:arch()\n    for _, v in ipairs(table.join(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- get toolchain info\nfunction _instance:info()\n    local arch = self:arch()\n    local infos = self._INFOS\n    if not infos then\n        infos = {}\n        self._INFOS = infos\n    end\n    local info = infos[arch]\n    if not info then\n        -- we need multiple info objects for different architectures\n        info = self._INFO:clone()\n        infos[arch] = info\n    end\n    return info\nend\n\n-- set the value to the toolchain configuration\nfunction _instance:set(name, ...)\n    self:info():apival_set(name, ...)\nend\n\n-- add the value to the toolchain configuration\nfunction _instance:add(name, ...)\n    self:info():apival_add(name, ...)\nend\n\n-- get the toolchain configuration\nfunction _instance:get(name, opt)\n    opt = opt or {}\n\n    -- attempt to get the static configure value\n    local value = self:info():get(name)\n    if value ~= nil then\n        return value\n    end\n\n    -- lazy loading toolchain\n    if opt.load ~= false then\n        self:_load()\n        return self:info():get(name)\n    end\nend\n\n-- get toolchain kind\nfunction _instance:kind()\n    return self:info():get(\"kind\")\nend\n\n-- get toolchain formats, we must set it in description scope\n-- @see https://github.com/xmake-io/xmake/issues/4769\nfunction _instance:formats()\n    return self:info():get(\"formats\")\nend\n\n-- is cross-compilation?\nfunction _instance:is_cross()\n    return is_cross(self:plat(), self:arch()) or self:is_cross_toolchain()\nend\n\n-- is cross-compilation toolchain?\nfunction _instance:is_cross_toolchain()\n    if self:kind() == \"cross\" then\n        return true\n    elseif self:kind() == \"standalone\" and (self:cross() or self:config(\"sdkdir\") or self:info():get(\"sdkdir\")) then\n        return true\n    end\nend\n\n-- is standalone toolchain?\nfunction _instance:is_standalone()\n    return self:kind() == \"standalone\" or self:kind() == \"cross\"\nend\n\n-- is global toolchain for whole platform\nfunction _instance:is_global()\n    return self:config(\"__global\")\nend\n\n-- is builtin toolchain? it's not from local project\nfunction _instance:is_builtin()\n    return self._IS_BUILTIN\nend\n\n-- get the run environments\nfunction _instance:runenvs()\n    local runenvs = self._RUNENVS\n    if runenvs == nil then\n        local toolchain_runenvs = self:get(\"runenvs\")\n        if toolchain_runenvs then\n            runenvs = {}\n            for name, values in pairs(toolchain_runenvs) do\n                if type(values) == \"table\" then\n                    values = path.joinenv(values)\n                end\n                runenvs[name] = values\n            end\n        end\n        runenvs = runenvs or false\n        self._RUNENVS = runenvs\n    end\n    return runenvs or nil\nend\n\n-- get the program and name of the given tool kind\nfunction _instance:tool(toolkind)\n    if not self:_is_checked() then\n        utils.warning(\"we cannot get tool(%s) in toolchain(%s) with %s/%s, because it has been not checked yet!\", toolkind, self:name(), self:plat(), self:arch())\n    end\n    -- ensure to do load for initializing toolset first\n    -- @note we cannot call self:check() here, because it can only be called on config\n    self:_load()\n    local toolpaths = self:get(\"toolset.\" .. toolkind)\n    if toolpaths then\n        for _, toolpath in ipairs(table.wrap(toolpaths)) do\n            local program, toolname = self:_checktool(toolkind, toolpath)\n            if program then\n                return program, toolname\n            end\n        end\n    end\nend\n\n-- get the toolchain script\nfunction _instance:script(name)\n    return self:info():get(name)\nend\n\n-- get the cross\nfunction _instance:cross()\n    return self:config(\"cross\") or config.get(\"cross\") or self:info():get(\"cross\")\nend\n\n-- get the bin directory\nfunction _instance:bindir()\n    local bindir = self:config(\"bindir\") or config.get(\"bin\") or self:info():get(\"bindir\")\n    if not bindir and self:sdkdir() and os.isdir(path.join(self:sdkdir(), \"bin\")) then\n        bindir = path.join(self:sdkdir(), \"bin\")\n    end\n    return bindir\nend\n\n-- get the sdk directory\nfunction _instance:sdkdir()\n    return self:config(\"sdkdir\") or config.get(\"sdk\") or self:info():get(\"sdkdir\")\nend\n\n-- get cachekey\nfunction _instance:cachekey()\n    return self._CACHEKEY\nend\n\n-- get user config from `set_toolchains(\"\", {configs = {vs = \"2018\"}})`\nfunction _instance:config(name)\n    return self._CONFIGS[name]\nend\n\n-- set user config\nfunction _instance:config_set(name, data)\n    self._CONFIGS[name] = data\nend\n\n-- save user config (deprecated)\nfunction _instance:configs_save()\n    utils.warning(\"toolchain:configs_save() is deprecated, please remove it.\")\nend\n\n-- do check, we only check it once for all architectures\nfunction _instance:check()\n    local checked = self:config(\"__checked\")\n    if checked == nil then\n        local on_check = self:_on_check()\n        if on_check then\n            local ok, results_or_errors = sandbox.load(on_check, self)\n            if ok then\n                checked = results_or_errors\n            else\n                os.raise(results_or_errors)\n            end\n        else\n            checked = true\n        end\n        -- we need to persist this state\n        checked = checked or false\n        self:config_set(\"__checked\", checked)\n    end\n    return checked\nend\n\n-- do load manually, it will call on_load()\nfunction _instance:load()\n    self:_load()\nend\n\n-- check cross toolchain\nfunction _instance:check_cross_toolchain()\n    return sandbox_module.import(\"toolchains.cross.check\", {rootdir = os.programdir(), anonymous = true})(self)\nend\n\n-- load cross toolchain\nfunction _instance:load_cross_toolchain()\n    return sandbox_module.import(\"toolchains.cross.load\", {rootdir = os.programdir(), anonymous = true})(self)\nend\n\n-- get packages\nfunction _instance:packages()\n    local packages = self._PACKAGES\n    if packages == nil then\n        local project = require(\"project/project\")\n        -- we will get packages from `set_toolchains(\"foo\", {packages})` or `set_toolchains(\"foo@packages\")`\n        for _, pkgname in ipairs(table.wrap(self:config(\"packages\"))) do\n            local requires = project.required_packages()\n            if requires then\n                local pkginfo = requires[pkgname]\n                if pkginfo then\n                    packages = packages or {}\n                    table.insert(packages, pkginfo)\n                end\n            end\n        end\n        self._PACKAGES = packages or false\n    end\n    return packages or nil\nend\n\n-- save toolchain to file\nfunction _instance:savefile(filepath)\n    if not self:_is_loaded() then\n        os.raise(\"we can only save toolchain(%s) after it has been loaded!\", self:name())\n    end\n    -- we strip on_load/on_check scripts to solve some issues\n    -- @see https://github.com/xmake-io/xmake/issues/3774\n    local info = table.clone(self:info():info())\n    info.load = nil\n    info.check = nil\n    return io.save(filepath, {name = self:name(), info = info, cachekey = self:cachekey(), configs = self._CONFIGS})\nend\n\n-- on check (builtin)\nfunction _instance:_on_check()\n    local on_check = self:info():get(\"check\")\n    if not on_check and self:is_cross() then\n        on_check = self.check_cross_toolchain\n    end\n    return on_check\nend\n\n-- on load (builtin)\nfunction _instance:_on_load()\n    local on_load = self:info():get(\"load\")\n    if not on_load and self:is_cross() then\n        on_load = self.load_cross_toolchain\n    end\n    return on_load\nend\n\n-- do load, @note we need to load it repeatly for each architectures\nfunction _instance:_load()\n    if not self:_is_checked() then\n        utils.warning(\"we cannot load toolchain(%s), because it has been not checked yet!\", self:name(), self:plat(), self:arch())\n    end\n    local info = self:info()\n    if not info:get(\"__loaded\") and not info:get(\"__loading\") then\n        local on_load = self:_on_load()\n        if on_load then\n            info:set(\"__loading\", true)\n            local ok, errors = sandbox.load(on_load, self)\n            info:set(\"__loading\", false)\n            if not ok then\n                os.raise(errors)\n            end\n        end\n        info:set(\"__loaded\", true)\n    end\nend\n\n-- is loaded?\nfunction _instance:_is_loaded()\n    return self:info():get(\"__loaded\")\nend\n\n-- is checked?\nfunction _instance:_is_checked()\n    return self:config(\"__checked\") ~= nil or self:_on_check() == nil\nend\n\n-- get the tool description from the tool kind\nfunction _instance:_description(toolkind)\n    local descriptions = self._DESCRIPTIONS\n    if not descriptions then\n        descriptions =\n        {\n            cc         = \"the c compiler\",\n            cxx        = \"the c++ compiler\",\n            cpp        = \"the c/c++ preprocessor\",\n            ld         = \"the linker\",\n            sh         = \"the shared library linker\",\n            ar         = \"the static library archiver\",\n            mrc        = \"the windows resource compiler\",\n            strip      = \"the symbols stripper\",\n            ranlib     = \"the archive index generator\",\n            objcopy    = \"the GNU objcopy utility\",\n            dsymutil   = \"the symbols generator\",\n            mm         = \"the objc compiler\",\n            mxx        = \"the objc++ compiler\",\n            as         = \"the assember\",\n            sc         = \"the swift compiler\",\n            scld       = \"the swift linker\",\n            scsh       = \"the swift shared library linker\",\n            scar       = \"the swift static library archiver\",\n            gc         = \"the golang compiler\",\n            gcld       = \"the golang linker\",\n            gcar       = \"the golang static library archiver\",\n            dc         = \"the dlang compiler\",\n            dcld       = \"the dlang linker\",\n            dcsh       = \"the dlang shared library linker\",\n            dcar       = \"the dlang static library archiver\",\n            rc         = \"the rust compiler\",\n            rcld       = \"the rust linker\",\n            rcsh       = \"the rust shared library linker\",\n            rcar       = \"the rust static library archiver\",\n            fc         = \"the fortran compiler\",\n            fcld       = \"the fortran linker\",\n            fcsh       = \"the fortran shared library linker\",\n            zc         = \"the zig compiler\",\n            zcld       = \"the zig linker\",\n            zcsh       = \"the zig shared library linker\",\n            zcar       = \"the zig static library archiver\",\n            cu         = \"the cuda compiler\",\n            culd       = \"the cuda linker\",\n            cuccbin    = \"the cuda host c++ compiler\",\n            nc         = \"the nim compiler\",\n            ncld       = \"the nim linker\",\n            ncsh       = \"the nim shared library linker\",\n            ncar       = \"the nim static library archiver\",\n            kc         = \"the kotlin native compiler\",\n            kcld       = \"the kotlin native linker\",\n            kcsh       = \"the kotlin native shared library linker\",\n            kcar       = \"the kotlin native static library archiver\",\n        }\n        self._DESCRIPTIONS = descriptions\n    end\n    return descriptions[toolkind]\nend\n\n-- check the given tool path\nfunction _instance:_checktool(toolkind, toolpath)\n\n    -- get result from cache first\n    local result = self:memcache():get2(\"checktool_\" .. toolkind, toolpath)\n    if result then\n        return result[1], result[2]\n    end\n\n    -- get find_tool\n    local find_tool = self._find_tool\n    if not find_tool then\n        find_tool = sandbox_module.import(\"lib.detect.find_tool\", {anonymous = true})\n        self._find_tool = find_tool\n    end\n\n    -- do filter for toolpath variables, e.g. set_toolset(\"cc\", \"$(env CC)\")\n    local sandbox_inst = sandbox.instance()\n    if sandbox_inst then\n        local filter = sandbox_inst:filter()\n        if filter then\n            local value = filter:handle(toolpath)\n            if value and value:trim() ~= \"\" then\n                toolpath = value\n            else\n                return\n            end\n        end\n    end\n\n    -- contain toolname? parse it, e.g. 'gcc@xxxx.exe'\n    -- https://github.com/xmake-io/xmake/issues/1361\n    local program, toolname\n    if toolpath then\n        local pos = toolpath:find('@', 1, true)\n        if pos then\n            -- we need to ignore valid path with `@`, e.g. /usr/local/opt/go@1.17/bin/go\n            -- https://github.com/xmake-io/xmake/issues/2853\n            local prefix = toolpath:sub(1, pos - 1)\n            if prefix and not prefix:find(\"[/\\\\]\") then\n                toolname = prefix\n                program = toolpath:sub(pos + 1)\n            end\n        end\n    end\n\n    -- find tool program\n    local cachekey = self:cachekey() .. \"_checktool\" .. toolkind\n    local tool = find_tool(toolpath, {toolchain = self,\n        cachekey = cachekey,\n        program = program or toolpath,\n        paths = self:bindir(),\n        envs = self:get(\"runenvs\")})\n    if tool then\n        program = tool.program\n        toolname = toolname or tool.name\n    else\n        -- we need reset result if not found\n        -- https://github.com/xmake-io/xmake/discussions/6415#discussioncomment-13099816\n        program = nil\n        toolname = nil\n    end\n\n    -- get tool description from the tool kind\n    local description = self:_description(toolkind) or (\"unknown toolkind \" .. toolkind)\n\n    -- trace\n    if option.get(\"verbose\") then\n        if program then\n            utils.cprint(\"${dim}checking for %s (%s) ... ${color.success}%s\", description, toolkind, path.filename(program))\n        else\n            utils.cprint(\"${dim}checking for %s (%s: ${bright}%s${clear}) ... ${color.nothing}${text.nothing}\", description, toolkind, toolpath)\n        end\n    end\n    self:memcache():set2(\"checktool_\" .. toolkind, toolpath, {program, toolname})\n    return program, toolname\nend\n\n-- get memcache\nfunction toolchain._memcache()\n    return memcache.cache(\"core.tool.toolchain\")\nend\n\n-- get local cache\nfunction toolchain._localcache()\n    return localcache.cache(\"toolchain\")\nend\n\n-- the interpreter\nfunction toolchain._interpreter()\n\n    -- the interpreter has been initialized? return it directly\n    if toolchain._INTERPRETER then\n        return toolchain._INTERPRETER\n    end\n\n    -- init interpreter\n    local interp = interpreter.new()\n    assert(interp)\n\n    -- define apis\n    interp:api_define(toolchain.apis())\n\n    -- define apis for language\n    interp:api_define(language.apis())\n\n    -- save interpreter\n    toolchain._INTERPRETER = interp\n    return interp\nend\n\n-- get cache key\nfunction toolchain._cachekey(name, opt)\n    local cachekey = opt.cachekey\n    if not cachekey then\n        cachekey = name\n        for _, k in ipairs(table.orderkeys(opt)) do\n            local v = opt[k]\n            cachekey = cachekey .. \"_\" .. k .. \"_\" .. tostring(v)\n        end\n    end\n    return cachekey\nend\n\n-- parse toolchain, configs and package name\n--\n-- formats:\n--\n-- 1. only toolchain name\n-- e.g. clang, gcc\n--\n-- 2. toolchain@package\n-- e.g. \"clang@llvm-10\", \"@muslcc\", zig\n--\n-- 3. toolchain[configs]@package\n-- e.g. \"mingw[clang]@llvm-mingw\", \"msvc[vs=2025,..]\"\n--\nfunction toolchain.parsename(name)\n    local splitinfo = name:split('@', {plain = true, strict = true})\n    local toolchain_name = splitinfo[1]\n    if toolchain_name == \"\" then\n        toolchain_name = nil\n    end\n    local packages = splitinfo[2]\n    if packages == \"\" then\n        packages = nil\n    end\n    local requireconfs, requirestr\n    if toolchain_name then\n        local toolchain_name_raw, configs_str = toolchain_name:match(\"(.-)%[(.*)%]\")\n        if toolchain_name_raw and configs_str then\n            configs_str = configs_str:gsub(\"%[(.*)%]\", function (w)\n                return w:replace(\",\", \":\")\n            end)\n            requirestr = configs_str\n            toolchain_name = toolchain_name_raw\n            local splitinfo = configs_str:split(\",\", {plain = true})\n            for _, v in ipairs(splitinfo) do\n                local parts = v:split(\"=\", {plain = true})\n                local k = parts[1]\n                v = parts[2]\n                requireconfs = requireconfs or {}\n                if v then\n                    if v:find(\":\", 1 ,true) then\n                        requireconfs[k] = v:split(\":\", {plain = true})\n                    else\n                        requireconfs[k] = option.boolean(v)\n                    end\n                else\n                    requireconfs[k] = true\n                end\n            end\n        end\n    end\n    return {name = toolchain_name or packages, packages = packages, requireconfs = requireconfs, requirestr = requirestr}\nend\n\n-- get toolchain apis\nfunction toolchain.apis()\n    return\n    {\n        values =\n        {\n            \"toolchain.set_kind\"\n        ,   \"toolchain.set_cross\"\n        ,   \"toolchain.set_bindir\"\n        ,   \"toolchain.set_sdkdir\"\n        ,   \"toolchain.set_archs\"\n        ,   \"toolchain.set_runtimes\"\n        ,   \"toolchain.set_homepage\"\n        ,   \"toolchain.set_description\"\n        }\n    ,   keyvalues =\n        {\n            -- toolchain.set_xxx\n            \"toolchain.set_formats\"\n        ,   \"toolchain.set_toolset\"\n        ,   \"toolchain.add_toolset\"\n            -- toolchain.add_xxx\n        ,   \"toolchain.add_runenvs\"\n        }\n    ,   script =\n        {\n            -- toolchain.on_xxx\n            \"toolchain.on_load\"\n        ,   \"toolchain.on_check\"\n        }\n    }\nend\n\n-- get toolchain directories\nfunction toolchain.directories()\n    local dirs = toolchain._DIRS or {   path.join(global.directory(), \"toolchains\")\n                                    ,   path.join(os.programdir(), \"toolchains\")\n                                    }\n    toolchain._DIRS = dirs\n    return dirs\nend\n\n-- add toolchain directories\nfunction toolchain.add_directories(...)\n    local dirs = toolchain.directories()\n    for _, dir in ipairs({...}) do\n        table.insert(dirs, 1, dir)\n    end\n    toolchain._DIRS = table.unique(dirs)\nend\n\n-- load toolchain\nfunction toolchain.load(name, opt)\n    opt = opt or {}\n\n    -- parse toolchain name\n    local parseinfo = toolchain.parsename(name)\n    name = parseinfo.name\n\n    -- init configs\n    local configs = parseinfo.requireconfs or {}\n    table.join2(configs, opt)\n    configs.packages = opt.packages or parseinfo.packages\n    configs.plat = opt.plat or config.get(\"plat\") or os.host()\n    configs.arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- get cache\n    local cache = toolchain._memcache()\n    local cachekey = toolchain._cachekey(name, configs)\n\n    -- get it directly from cache dirst\n    local instance = cache:get(cachekey)\n    if instance then\n        return instance\n    end\n\n    -- find the toolchain script path\n    local scriptpath = nil\n    for _, dir in ipairs(toolchain.directories()) do\n        scriptpath = path.join(dir, name, \"xmake.lua\")\n        if os.isfile(scriptpath) then\n            break\n        end\n    end\n    if not scriptpath or not os.isfile(scriptpath) then\n        return nil, string.format(\"the toolchain %s not found!\", name)\n    end\n\n    -- get interpreter\n    local interp = toolchain._interpreter()\n\n    -- load script\n    local ok, errors = interp:load(scriptpath)\n    if not ok then\n        return nil, errors\n    end\n\n    -- load toolchain\n    local results, errors = interp:make(\"toolchain\", true, false)\n    if not results and os.isfile(scriptpath) then\n        return nil, errors\n    end\n\n    -- get toolchain info\n    local info = results[name]\n    if not info then\n        return nil, string.format(\"the toolchain %s not found!\", name)\n    end\n\n    -- save instance to the cache\n    instance = _instance.new(name, info, {cachekey = cachekey,\n        is_builtin = true, configs = configs, requirestr = parseinfo.requirestr})\n    cache:set(cachekey, instance)\n    return instance\nend\n\n-- load toolchain from the give toolchain info\nfunction toolchain.load_withinfo(name, info, opt)\n    opt = opt or {}\n\n    -- parse toolchain name\n    local parseinfo = toolchain.parsename(name)\n    name = parseinfo.name\n\n    -- init configs\n    local configs = parseinfo.requireconfs or {}\n    table.join2(configs, opt)\n    configs.packages = opt.packages or parseinfo.packages\n    configs.plat = opt.plat or config.get(\"plat\") or os.host()\n    configs.arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- get cache key\n    local cache = toolchain._memcache()\n    local cachekey = toolchain._cachekey(name, configs)\n\n    -- get it directly from cache dirst\n    local instance = cache:get(cachekey)\n    if instance then\n        return instance\n    end\n\n    -- save instance to the cache\n    instance = _instance.new(name, info, {cachekey = cachekey,\n        is_builtin = false, configs = configs, requirestr = parseinfo.requirestr})\n    cache:set(cachekey, instance)\n    return instance\nend\n\n-- load toolchain from file\nfunction toolchain.load_fromfile(filepath, opt)\n    local fileinfo, errors = io.load(filepath)\n    if not fileinfo then\n        return nil, errors\n    end\n    if not fileinfo.name or not fileinfo.info then\n        return nil, string.format(\"%s is invalid toolchain info file!\", filepath)\n    end\n    opt = table.join(opt or {}, fileinfo.configs)\n    opt.cachekey = fileinfo.cachekey\n    local scope_opt = {interpreter = toolchain._interpreter(), deduplicate = true, enable_filter = true}\n    local info = scopeinfo.new(\"toolchain\", fileinfo.info, scope_opt)\n    local instance = toolchain.load_withinfo(fileinfo.name, info, opt)\n    return instance\nend\n\n\n-- get the program and name of the given tool kind\nfunction toolchain.tool(toolchains, toolkind, opt)\n\n    -- get plat and arch\n    opt = opt or {}\n    local plat = opt.plat or config.get(\"plat\") or os.host()\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- get cache and cachekey\n    local cache = toolchain._localcache()\n    local cachekey = \"tool_\" .. (opt.cachekey or \"\") .. \"_\" .. plat .. \"_\" .. arch .. \"_\" .. toolkind\n    local updatecache = false\n\n    -- get program from before_script\n    local program, toolname, toolchain_info\n    local before_get = opt.before_get\n    if before_get then\n        program, toolname, toolchain_info = before_get(toolkind)\n        if program then\n            updatecache = true\n        end\n    end\n\n    -- get program from local cache\n    if not program then\n        program = cache:get2(cachekey, \"program\")\n        toolname = cache:get2(cachekey, \"toolname\")\n        toolchain_info = cache:get2(cachekey, \"toolchain_info\")\n    end\n\n    -- get program from toolchains\n    if not program then\n        for idx, toolchain_inst in ipairs(toolchains) do\n            program, toolname = toolchain_inst:tool(toolkind)\n            if program then\n                toolchain_info = {name = toolchain_inst:name(),\n                                  plat = toolchain_inst:plat(),\n                                  arch = toolchain_inst:arch(),\n                                  cachekey = toolchain_inst:cachekey()}\n                updatecache = true\n                break\n            end\n        end\n    end\n\n    -- contain toolname? parse it, e.g. 'gcc@xxxx.exe'\n    if program and type(program) == \"string\" then\n        local pos = program:find('@', 1, true)\n        if pos then\n            -- we need to ignore valid path with `@`, e.g. /usr/local/opt/go@1.17/bin/go\n            -- https://github.com/xmake-io/xmake/issues/2853\n            local prefix = program:sub(1, pos - 1)\n            if prefix and not prefix:find(\"[/\\\\]\") then\n                toolname = prefix\n                program = program:sub(pos + 1)\n            end\n            updatecache = true\n        end\n    end\n\n    -- update cache\n    if program and updatecache then\n        cache:set2(cachekey, \"program\", program)\n        cache:set2(cachekey, \"toolname\", toolname)\n        cache:set2(cachekey, \"toolchain_info\", toolchain_info)\n    end\n    return program, toolname, toolchain_info\nend\n\n-- get tool configuration from the toolchains\nfunction toolchain.toolconfig(toolchains, name, opt)\n\n    -- get plat and arch\n    opt = opt or {}\n    local plat = opt.plat or config.get(\"plat\") or os.host()\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- get cache and cachekey\n    local cache = toolchain._memcache()\n    local cachekey = \"toolconfig_\" .. (opt.cachekey or \"\") .. \"_\" .. plat .. \"_\" .. arch\n\n    -- get configuration\n    local toolconfig = cache:get2(cachekey, name)\n    if toolconfig == nil then\n        for _, toolchain_inst in ipairs(toolchains) do\n            if not toolchain_inst:_is_checked() then\n                utils.warning(\"we cannot get toolconfig(%s) in toolchain(%s) with %s/%s, because it has been not checked yet!\", name, toolchain_inst:name(), toolchain_inst:plat(), toolchain_inst:arch())\n            end\n            local values = toolchain_inst:get(name)\n            if values then\n                toolconfig = toolconfig or {}\n                table.join2(toolconfig, values)\n            end\n            local after_get = opt.after_get\n            if after_get then\n                values = after_get(toolchain_inst, name)\n                if values then\n                    toolconfig = toolconfig or {}\n                    table.join2(toolconfig, values)\n                end\n            end\n        end\n        cache:set2(cachekey, name, toolconfig or false)\n    end\n    return toolconfig or nil\nend\n\n-- save all configs to the local cache\n--\n-- @see flushing localcache for each test is too slow,\n-- so we only flush the toolchain configuration cache once after the configuration is completed.\nfunction toolchain.save()\n    toolchain._localcache():save()\nend\n\n-- return module\nreturn toolchain\n"
  },
  {
    "path": "xmake/core/ui/action.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        action.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal object = require(\"ui/object\")\n\n-- define module\nlocal action = action or object { }\n\n-- register action types\nfunction action:register(tag, ...)\n    local base = self[tag] or 0\n    local enums = {...}\n    local n = #enums\n    for i = 1, n do\n        self[enums[i]] = i + base\n    end\n    self[tag] = base + n\nend\n\n-- register action enums\naction:register(\"ac_max\",\n                \"ac_on_text_changed\",\n                \"ac_on_selected\",\n                \"ac_on_clicked\",\n                \"ac_on_resized\",\n                \"ac_on_scrolled\",\n                \"ac_on_enter\",\n                \"ac_on_load\",\n                \"ac_on_save\",\n                \"ac_on_exit\")\n\n-- return module\nreturn action\n"
  },
  {
    "path": "xmake/core/ui/application.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        application.lua\n--\n\n-- load modules\nlocal os        = require(\"base/os\")\nlocal utils     = require(\"base/utils\")\nlocal log       = require(\"ui/log\")\nlocal rect      = require(\"ui/rect\")\nlocal event     = require(\"ui/event\")\nlocal curses    = require(\"ui/curses\")\nlocal program   = require(\"ui/program\")\nlocal desktop   = require(\"ui/desktop\")\nlocal menubar   = require(\"ui/menubar\")\nlocal statusbar = require(\"ui/statusbar\")\n\n-- define module\nlocal application = application or program()\n\n-- init application\nfunction application:init(name, argv)\n\n    -- init log\n    log:clear()\n--    log:enable(false)\n\n    -- trace\n    log:print(\"<application: %s>: init ..\", name)\n\n    -- init program\n    program.init(self, name, argv)\n\n    -- trace\n    log:print(\"<application: %s>: init ok\", name)\nend\n\n-- exit application\nfunction application:exit()\n\n    -- exit program\n    program.exit(self)\n\n    -- flush log\n    log:flush()\nend\n\n-- get menubar\nfunction application:menubar()\n    if not self._MENUBAR then\n        self._MENUBAR = menubar:new(\"menubar\", rect{0, 0, self:width(), 1})\n    end\n    return self._MENUBAR\nend\n\n-- get desktop\nfunction application:desktop()\n    if not self._DESKTOP then\n        self._DESKTOP = desktop:new(\"desktop\", rect{0, 1, self:width(), self:height() - 1})\n    end\n    return self._DESKTOP\nend\n\n-- get statusbar\nfunction application:statusbar()\n    if not self._STATUSBAR then\n        self._STATUSBAR = statusbar:new(\"statusbar\", rect{0, self:height() - 1, self:width(), self:height()})\n    end\n    return self._STATUSBAR\nend\n\n-- on event\nfunction application:on_event(e)\n    program.on_event(self, e)\nend\n\n-- on resize\nfunction application:on_resize()\n    self:menubar():bounds_set(rect{0, 0, self:width(), 1})\n    self:desktop():bounds_set(rect{0, 1, self:width(), self:height() - 1})\n    self:statusbar():bounds_set(rect{0, self:height() - 1, self:width(), self:height()})\n    program.on_resize(self)\nend\n\n-- run application\nfunction application:run(...)\n    assert(curses.done, \"ncurses not found, please install it first.\")\n\n    -- init runner\n    local argv = {...}\n    local runner = function ()\n\n        -- new an application\n        local app = self:new(argv)\n        if app then\n            app:loop()\n            app:exit()\n        end\n    end\n\n    -- run application\n    local ok, errors = utils.trycall(runner)\n\n    -- exit curses\n    if not ok then\n        if not curses.isdone() then\n            curses.done()\n        end\n        log:flush()\n        os.raise(errors)\n    end\nend\n\n-- return module\nreturn application\n"
  },
  {
    "path": "xmake/core/ui/border.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        border.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal view   = require(\"ui/view\")\nlocal label  = require(\"ui/label\")\nlocal curses = require(\"ui/curses\")\n\n-- define module\nlocal border = border or view()\n\n-- init border\nfunction border:init(name, bounds)\n\n    -- init view\n    view.init(self, name, bounds)\n\n    -- check bounds\n    assert(self:width() > 2 and self:height() > 2, string.format(\"%s: too small!\", tostring(self)))\nend\n\n-- draw border\nfunction border:on_draw(transparent)\n\n    -- draw background (transparent)\n    view.on_draw(self, true)\n\n    -- get corner attribute\n    local cornerattr = self:cornerattr()\n\n    -- the left-upper attribute\n    local attr_ul = curses.color_pair(cornerattr[1], self:background())\n    if self:background() == cornerattr[1] then\n        attr_ul = {attr_ul, \"bold\"}\n    end\n\n    -- the right-lower attribute\n    local attr_rl = curses.color_pair(cornerattr[2], self:background())\n    if self:background() == cornerattr[2] then\n        attr_rl = {attr_rl, \"bold\"}\n    end\n\n    -- the border characters\n    -- @note acs character will use 2 width on borders (pdcurses), so we use acsii characters instead of them.\n    local iswin = os.host() == \"windows\"\n    local hline = iswin and '-' or \"hline\"\n    local vline = iswin and '|' or \"vline\"\n    local ulcorner = iswin and ' ' or \"ulcorner\"\n    local llcorner = iswin and ' ' or \"llcorner\"\n    local urcorner = iswin and ' ' or \"urcorner\"\n    local lrcorner = iswin and ' ' or \"lrcorner\"\n\n    -- draw left and top border\n    self:canvas():attr(attr_ul)\n    self:canvas():move(0, 0):putchar(hline, self:width())\n    self:canvas():move(0, 0):putchar(ulcorner)\n    self:canvas():move(0, 1):putchar(vline, self:height() - 1, true)\n    self:canvas():move(0, self:height() - 1):putchar(llcorner)\n\n    -- draw bottom and right border\n    self:canvas():attr(attr_rl)\n    self:canvas():move(1, self:height() - 1):putchar(hline, self:width() - 1)\n    self:canvas():move(self:width() - 1, 0):putchar(urcorner)\n    self:canvas():move(self:width() - 1, 1):putchar(vline, self:height() - 1, true)\n    self:canvas():move(self:width() - 1, self:height() - 1):putchar(lrcorner)\nend\n\n-- get border corner attribute\nfunction border:cornerattr()\n    return self._CORNERATTR or {\"white\", \"black\"}\nend\n\n-- set border corner attribute\nfunction border:cornerattr_set(attr_ul, attr_rl)\n    self._CORNERATTR = {attr_ul or \"white\", attr_rl or attr_ul or \"black\"}\n    self:invalidate()\nend\n\n-- swap border corner attribute\nfunction border:cornerattr_swap()\n    local cornerattr = self:cornerattr()\n    self:cornerattr_set(cornerattr[2], cornerattr[1])\nend\n\n-- return module\nreturn border\n"
  },
  {
    "path": "xmake/core/ui/boxdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        boxdialog.lua\n--\n\n-- load modules\nlocal log        = require(\"ui/log\")\nlocal rect       = require(\"ui/rect\")\nlocal action     = require(\"ui/action\")\nlocal curses     = require(\"ui/curses\")\nlocal window     = require(\"ui/window\")\nlocal textdialog = require(\"ui/textdialog\")\n\n-- define module\nlocal boxdialog = boxdialog or textdialog()\n\n-- init dialog\nfunction boxdialog:init(name, bounds, title)\n\n    -- init window\n    textdialog.init(self, name, bounds, title)\n\n    -- resize text\n    self._TEXT_EY = 3\n    self:text():bounds().ey = self._TEXT_EY\n    self:text():invalidate(true)\n    self:text():option_set(\"selectable\", false)\n\n    -- insert box\n    self:panel():insert(self:box())\n\n    -- text changed\n    self:text():action_set(action.ac_on_text_changed, function (v)\n        if v:text() then\n            local lines = #self:text():splitext(v:text())\n            if lines > 0 and lines < self:height() then\n                self._TEXT_EY = lines\n                self:panel():invalidate(true)\n            end\n        end\n    end)\n\n    -- select buttons by default\n    self:panel():select(self:buttons())\n\n    -- on resize for panel\n    self:panel():action_add(action.ac_on_resized, function (v)\n        self:text():bounds().ey = self._TEXT_EY\n        self:box():bounds_set(rect{0, self._TEXT_EY, v:width(), v:height() - 1})\n    end)\n\n    -- on click for frame\n    self:frame():action_set(action.ac_on_clicked, function (v, x, y)\n\n        -- get relative coordinates\n        x, y  = x - v:bounds().sx, y - v:bounds().sy\n        local panel, box = v:parent():panel(), v:parent():box()\n        local px, py  = x - panel:bounds().sx, y - panel:bounds().sy\n\n        -- if coordinates don't match any view try box\n        if panel:option(\"mouseable\") then\n            if panel:action_on(action.ac_on_clicked, x, y) then\n                return true\n            elseif box:option(\"mouseable\") and not box:option(\"selectable\") and box:bounds():contains(px, py) then\n                return box:action_on(action.ac_on_clicked, px, py)\n            end\n        end\n    end)\nend\n\n-- get box\nfunction boxdialog:box()\n    if not self._BOX then\n        self._BOX = window:new(\"boxdialog.box\", rect{0, self._TEXT_EY, self:panel():width(), self:panel():height() - 1})\n        self._BOX:border():cornerattr_set(\"black\", \"white\")\n    end\n    return self._BOX\nend\n\n-- on resize\nfunction boxdialog:on_resize()\n    self:text():text_set(self:text():text())\n    textdialog.on_resize(self)\nend\n\n-- return module\nreturn boxdialog\n"
  },
  {
    "path": "xmake/core/ui/button.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        button.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal event     = require(\"ui/event\")\nlocal label     = require(\"ui/label\")\nlocal action    = require(\"ui/action\")\nlocal curses    = require(\"ui/curses\")\n\n-- define module\nlocal button = button or label()\n\n-- init button\nfunction button:init(name, bounds, text, on_action)\n\n    -- init label\n    label.init(self, name, bounds, text)\n\n    -- mark as selectable\n    self:option_set(\"selectable\", true)\n\n    -- show cursor\n    self:cursor_show(true)\n\n    -- init actions\n    self:option_set(\"mouseable\", true)\n    self:action_set(action.ac_on_enter, on_action)\n    self:action_set(action.ac_on_clicked, function (v)\n        v:action_on(action.ac_on_enter)\n        return true\n    end)\nend\n\n-- draw button\nfunction button:on_draw(transparent)\n\n    -- draw background\n    view.on_draw(self, transparent)\n\n    -- strip text string\n    local str = self:text()\n    if str and #str > 0 then\n        str = string.sub(str, 1, self:width())\n    end\n    if not str or #str == 0 then\n        return\n    end\n\n    -- get the text attribute value\n    local textattr = self:textattr_val()\n\n    -- selected?\n    if self:state(\"selected\") and self:state(\"focused\") then\n        textattr = {textattr, \"reverse\"}\n    end\n\n    -- draw text\n    self:canvas():attr(textattr):move(0, 0):putstr(str)\nend\n\n-- on event\nfunction button:on_event(e)\n\n    -- selected?\n    if not self:state(\"selected\") then\n        return\n    end\n\n    -- enter this button?\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Enter\" then\n            self:action_on(action.ac_on_enter)\n            return true\n        end\n    end\nend\n\n-- set state\nfunction button:state_set(name, enable)\n    if name == \"focused\" and self:state(name) ~= enable then\n        self:invalidate()\n    end\n    return view.state_set(self, name, enable)\nend\n\n-- return module\nreturn button\n"
  },
  {
    "path": "xmake/core/ui/canvas.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        canvas.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal point  = require(\"ui/point\")\nlocal object = require(\"ui/object\")\nlocal curses = require(\"ui/curses\")\n\n-- define module\nlocal line   = line or object()\nlocal canvas = canvas or object()\n\n-- new canvas instance\nfunction canvas:new(view, window)\n\n    -- create instance\n    self = self()\n\n    -- save view and window\n    self._view = view\n    self._window = window\n    assert(view and window, \"cannot new canvas instance without view and window!\")\n\n    -- set the default attributes\n    self:attr()\n\n    -- done\n    return self\nend\n\n-- clear canvas\nfunction canvas:clear()\n    self._window:clear()\n    return self\nend\n\n-- move canvas to the given position\nfunction canvas:move(x, y)\n    self._window:move(y, x)\n    return self\nend\n\n-- get the current position\nfunction canvas:pos()\n    local y, x = self._window:getyx()\n    return x, y\nend\n\n-- get the canvas size\nfunction canvas:size()\n    local y, x = self._window:getmaxyx()\n    return point {x + 1, y + 1}\nend\n\n-- get the canvas width\nfunction canvas:width()\n    local _, x = self._window:getmaxyx()\n    return x + 1\nend\n\n-- get the canvas height\nfunction canvas:height()\n    local y, _ = self._window:getmaxyx()\n    return y + 1\nend\n\n-- put character to canvas\nfunction canvas:putchar(ch, n, vertical)\n\n    -- acs character?\n    if type(ch) == \"string\" and #ch > 1 then\n        ch = curses.acs(ch)\n    end\n\n    -- draw characters\n    n = n or 1\n    if vertical then\n        local x, y = self:pos()\n        while n > 0 do\n            self:move(x, y)\n            self._window:addch(ch)\n            n = n - 1\n            y = y + 1\n        end\n    else\n        while n > 0 do\n            self._window:addch(ch)\n            n = n - 1\n        end\n    end\n    return self\nend\n\n-- put a string to canvas\nfunction canvas:putstr(str)\n    self._window:addstr(str)\n    return self\nend\n\n-- put strings to canvas\nfunction canvas:putstrs(strs, startline)\n\n    -- draw strings\n    local sy, sx = self._window:getyx()\n    local ey, _ = self._window:getmaxyx()\n    for idx = startline or 1, #strs do\n        local _, y = self:pos()\n        self._window:addstr(strs[idx])\n        if y + 1 < ey and idx < #strs then\n            self:move(sx, y + 1)\n        else\n            break\n        end\n    end\n    return self\nend\n\n-- set canvas attributes\n--\n-- set attr:    canvas:attr(\"bold\")\n-- add attr:    canvas:attr(\"bold\", true)\n-- remove attr: canvas:attr(\"bold\", false)\n--\nfunction canvas:attr(attrs, modify)\n\n    -- calculate the attributes\n    local attr = curses.calc_attr(attrs)\n    if modify == nil then\n        self._window:attrset(attr)\n    elseif modify == false then\n        self._window:attroff(attr)\n    else\n        self._window:attron(attr)\n    end\n    return self\nend\n\n-- return module\nreturn canvas\n"
  },
  {
    "path": "xmake/core/ui/choicebox.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        choicebox.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal rect      = require(\"ui/rect\")\nlocal panel     = require(\"ui/panel\")\nlocal event     = require(\"ui/event\")\nlocal action    = require(\"ui/action\")\nlocal curses    = require(\"ui/curses\")\nlocal button    = require(\"ui/button\")\nlocal object    = require(\"ui/object\")\n\n-- define module\nlocal choicebox = choicebox or panel()\n\n-- init choicebox\nfunction choicebox:init(name, bounds)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- init items\n    self._ITEMS = {}\n\n    -- init start index\n    self._STARTINDEX = 1\nend\n\n-- load values\nfunction choicebox:load(values, selected)\n\n    -- clear the views first\n    self:clear()\n\n    -- reset start index\n    self._STARTINDEX = 1\n\n    -- load items\n    local items = {}\n    for idx, value in ipairs(values) do\n        table.insert(items, self:_load_item(value, idx, idx == selected))\n    end\n    self._ITEMS = items\n\n    -- insert top-n items\n    local startindex = self._STARTINDEX\n    for idx = startindex, startindex + self:height() - 1 do\n        local item = items[idx]\n        if item then\n            self:insert(item)\n        else\n            break\n        end\n    end\n\n    -- select the first item\n    self:select(self:first())\n\n    -- on loaded\n    self:action_on(action.ac_on_load)\n\n    -- invalidate\n    self:invalidate()\nend\n\n-- is scrollable?\nfunction choicebox:scrollable()\n    return #self:_items() > self:height()\nend\n\n-- scroll\nfunction choicebox:scroll(count)\n    if self:scrollable() then\n        local items = self:_items()\n        local totalcount = #items\n        local startindex = self._STARTINDEX + count\n        if startindex > totalcount then\n            return\n        elseif startindex < 1 then\n            startindex = 1\n        end\n        self._STARTINDEX = startindex\n        self:clear()\n        for idx = startindex, startindex + self:height() - 1 do\n            local item = items[idx]\n            if item then\n                item:bounds():move2(0, idx - startindex)\n                self:insert(item)\n            else\n                break\n            end\n        end\n        if count > 0 then\n            self:select(self:first())\n        else\n            self:select(self:last())\n        end\n        self:invalidate()\n    end\nend\n\n-- on resize\nfunction choicebox:on_resize()\n    local items = self:_items()\n    local totalcount = #items\n    local startindex = self._STARTINDEX\n    for idx = 1, totalcount do\n        local item = items[idx]\n        if item then\n            if idx >= startindex and idx < startindex + self:height() then\n                if not self:view(item:name()) then\n                    item:bounds():move2(0, idx - startindex)\n                    self:insert(item)\n                end\n            else\n                if self:view(item:name()) then\n                    self:remove(item)\n                end\n            end\n        end\n    end\n    panel.on_resize(self)\nend\n\n-- on event\nfunction choicebox:on_event(e)\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Down\" then\n            if self:current() == self:last() then\n                self:scroll(self:height())\n            else\n                self:select_next()\n            end\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"Up\" then\n            if self:current() == self:first() then\n                self:scroll(-self:height())\n            else\n                self:select_prev()\n            end\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"PageDown\" or e.key_name == \"PageUp\" then\n            local direction = e.key_name == \"PageDown\" and 1 or -1\n            self:scroll(self:height() * direction)\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"Enter\" or e.key_name == \" \" then\n            self:_do_select()\n            return true\n        end\n    elseif e.type == event.ev_command and e.command == \"cm_enter\" then\n        self:_do_select()\n        return true\n    end\nend\n\n-- load a item with value\nfunction choicebox:_load_item(value, index, selected)\n\n    -- init text\n    local text = (selected and \"(X) \" or \"( ) \") .. tostring(value)\n\n    -- init a value item view\n    local item = button:new(\"choicebox.value.\" .. index,\n                    rect:new(0, index - 1, self:width(), 1),\n                    text,\n                    function (v, e)\n                        self:_do_select()\n                    end)\n\n    -- attach index and value\n    item:extra_set(\"index\", index)\n    item:extra_set(\"value\", value)\n    return item\nend\n\n-- notify scrolled\nfunction choicebox:_notify_scrolled()\n    local totalcount = #self:_items()\n    local startindex = self:current():extra(\"index\")\n    self:action_on(action.ac_on_scrolled, startindex / totalcount)\nend\n\n-- get all items\nfunction choicebox:_items()\n    return self._ITEMS\nend\n\n-- do select the current config\nfunction choicebox:_do_select()\n\n    -- clear selected text\n    for v in self:views() do\n        local text = v:text()\n        if text and text:startswith(\"(X) \") then\n            local t = v:extra(\"value\")\n            v:text_set(\"( ) \" .. tostring(t))\n        end\n    end\n\n    -- get the current item\n    local item = self:current()\n\n    -- do action: on selected\n    local index = item:extra(\"index\")\n    local value = item:extra(\"value\")\n    self:action_on(action.ac_on_selected, index, value)\n\n    -- update text\n    item:text_set(\"(X) \" .. tostring(value))\nend\n\n-- return module\nreturn choicebox\n"
  },
  {
    "path": "xmake/core/ui/choicedialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        choicedialog.lua\n--\n\n-- load modules\nlocal log         = require(\"ui/log\")\nlocal rect        = require(\"ui/rect\")\nlocal event       = require(\"ui/event\")\nlocal action      = require(\"ui/action\")\nlocal curses      = require(\"ui/curses\")\nlocal window      = require(\"ui/window\")\nlocal scrollbar   = require(\"ui/scrollbar\")\nlocal choicebox   = require(\"ui/choicebox\")\nlocal boxdialog   = require(\"ui/boxdialog\")\n\n-- define module\nlocal choicedialog = choicedialog or boxdialog()\n\n-- init dialog\nfunction choicedialog:init(name, bounds, title)\n\n    -- init window\n    boxdialog.init(self, name, bounds, title)\n\n    -- init text\n    self:text():text_set(\"Use the arrow keys to navigate this window or press the hotkey of the item you wish to select followed by the <SPACEBAR>. Press <?> for additional information about this\")\n\n    -- init buttons\n    self:button_add(\"select\", \"< Select >\", function (v, e)\n        self:choicebox():on_event(event.command {\"cm_enter\"})\n        self:quit()\n    end)\n    self:button_add(\"cancel\", \"< Cancel >\", function (v, e)\n        self:quit()\n    end)\n    self:buttons():select(self:button(\"select\"))\n\n    -- insert scrollbar\n    self:box():panel():insert(self:scrollbar_box())\n\n    -- insert choice box\n    self:box():panel():insert(self:choicebox())\n\n    -- disable to select to box (disable Tab switch and only response to buttons)\n    self:box():option_set(\"selectable\", false)\n\n    -- on resize for panel\n    self:box():panel():action_add(action.ac_on_resized, function (v)\n        self:choicebox():bounds_set(rect:new(0, 0, v:width() - 1, v:height()))\n        self:scrollbar_box():bounds_set(rect:new(v:width() - 1, 0, 1, v:height()))\n        if self:choicebox():scrollable() then\n            self:scrollbar_box():show(true)\n        else\n            self:scrollbar_box():show(false)\n        end\n    end)\n\n    -- show scrollbar?\n    self:choicebox():action_add(action.ac_on_load, function (v)\n        if v:scrollable() then\n            self:scrollbar_box():show(true)\n        else\n            self:scrollbar_box():show(false)\n        end\n    end)\n\n    -- on scroll\n    self:choicebox():action_add(action.ac_on_scrolled, function (v, progress)\n        if self:scrollbar_box():state(\"visible\") then\n            self:scrollbar_box():progress_set(progress)\n        end\n    end)\nend\n\n-- get choice box\nfunction choicedialog:choicebox()\n    if not self._CHOICEBOX then\n        local bounds = self:box():panel():bounds()\n        self._CHOICEBOX = choicebox:new(\"choicedialog.choicebox\", rect:new(0, 0, bounds:width() - 1, bounds:height()))\n        self._CHOICEBOX:state_set(\"focused\", true) -- we can select and highlight selected item\n    end\n    return self._CHOICEBOX\nend\n\n-- get box scrollbar\nfunction choicedialog:scrollbar_box()\n    if not self._SCROLLBAR_BOX then\n        local bounds = self:box():panel():bounds()\n        self._SCROLLBAR_BOX = scrollbar:new(\"choicedialog.scrollbar\", rect:new(bounds:width() - 1, 0, 1, bounds:height()))\n        self._SCROLLBAR_BOX:show(false)\n    end\n    return self._SCROLLBAR_BOX\nend\n\n-- on event\nfunction choicedialog:on_event(e)\n\n    -- load values first\n    if e.type == event.ev_idle then\n        if not self._LOADED then\n            self:action_on(action.ac_on_load)\n            self._LOADED = true\n        end\n    -- select value\n    elseif e.type == event.ev_keyboard then\n        if e.key_name == \"Down\" or e.key_name == \"Up\" or e.key_name == \" \" then\n            return self:choicebox():on_event(e)\n        end\n    end\n    return boxdialog.on_event(self, e)\nend\n\n-- return module\nreturn choicedialog\n"
  },
  {
    "path": "xmake/core/ui/curses.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        curses.lua\n--\n\n-- define module: curses\nlocal curses = curses or {}\n\n-- load modules\nlocal os  = require(\"base/os\")\nlocal log = require(\"ui/log\")\n\n-- get color from the given name\nfunction curses.color(name)\n        if name == 'black' then     return curses.COLOR_BLACK\n    elseif name == 'red' then       return curses.COLOR_RED\n    elseif name == 'green' then     return curses.COLOR_GREEN\n    elseif name == 'yellow' then    return curses.COLOR_YELLOW\n    elseif name == 'blue' then      return curses.COLOR_BLUE\n    elseif name == 'magenta' then   return curses.COLOR_MAGENTA\n    elseif name == 'cyan' then      return curses.COLOR_CYAN\n    elseif name == 'white' then     return curses.COLOR_WHITE\n    else                            return curses.COLOR_BLACK\n    end\nend\n\n-- is color?\nlocal colors = {black = true, red = true, green = true, yellow = true, blue = true, magenta = true, cyan = true, white = true}\nfunction curses.iscolor(name)\n    return colors[name] or colors[name:sub(3) or \"\"]\nend\n\n-- get attr from the given name\nfunction curses.attr(name)\n        if name == 'normal' then    return curses.A_NORMAL\n    elseif name == 'standout' then  return curses.A_STANDOUT\n    elseif name == 'underline' then return curses.A_UNDERLINE\n    elseif name == 'reverse' then   return curses.A_REVERSE\n    elseif name == 'blink' then     return curses.A_BLINK\n    elseif name == 'dim' then       return curses.A_DIM\n    elseif name == 'bold' then      return curses.A_BOLD\n    elseif name == 'protect' then   return curses.A_PROTECT\n    elseif name == 'invis' then     return curses.A_INVIS\n    elseif name == 'alt' then       return curses.A_ALTCHARSET\n    else                            return curses.A_NORMAL\n    end\nend\n\n-- get acs character from the given name\nfunction curses.acs(name)\n        if name == 'block' then     return curses.ACS_BLOCK\n    elseif name == 'board' then     return curses.ACS_BOARD\n    elseif name == 'btee' then      return curses.ACS_BTEE\n    elseif name == 'bullet' then    return curses.ACS_BULLET\n    elseif name == 'ckboard' then   return curses.ACS_CKBOARD\n    elseif name == 'darrow' then    return curses.ACS_DARROW\n    elseif name == 'degree' then    return curses.ACS_DEGREE\n    elseif name == 'diamond' then   return curses.ACS_DIAMOND\n    elseif name == 'gequal' then    return curses.ACS_GEQUAL\n    elseif name == 'hline' then     return curses.ACS_HLINE\n    elseif name == 'lantern' then   return curses.ACS_LANTERN\n    elseif name == 'larrow' then    return curses.ACS_LARROW\n    elseif name == 'lequal' then    return curses.ACS_LEQUAL\n    elseif name == 'llcorner' then  return curses.ACS_LLCORNER\n    elseif name == 'lrcorner' then  return curses.ACS_LRCORNER\n    elseif name == 'ltee' then      return curses.ACS_LTEE\n    elseif name == 'nequal' then    return curses.ACS_NEQUAL\n    elseif name == 'pi' then        return curses.ACS_PI\n    elseif name == 'plminus' then   return curses.ACS_PLMINUS\n    elseif name == 'plus' then      return curses.ACS_PLUS\n    elseif name == 'rarrow' then    return curses.ACS_RARROW\n    elseif name == 'rtee' then      return curses.ACS_RTEE\n    elseif name == 's1' then        return curses.ACS_S1\n    elseif name == 's3' then        return curses.ACS_S3\n    elseif name == 's7' then        return curses.ACS_S7\n    elseif name == 's9' then        return curses.ACS_S9\n    elseif name == 'sterling' then  return curses.ACS_STERLING\n    elseif name == 'ttee' then      return curses.ACS_TTEE\n    elseif name == 'uarrow' then    return curses.ACS_UARROW\n    elseif name == 'ulcorner' then  return curses.ACS_ULCORNER\n    elseif name == 'urcorner' then  return curses.ACS_URCORNER\n    elseif name == 'vline' then     return curses.ACS_VLINE\n    elseif type(name) == 'string' and #name == 1 then\n        return name\n    else\n        return ' '\n    end\nend\n\n-- calculate attr from the attributes list\n--\n-- local attr = curses.calc_attr(\"bold\")\n-- local attr = curses.calc_attr(\"yellow\")\n-- local attr = curses.calc_attr{ \"yellow\", \"ongreen\" }\n-- local attr = curses.calc_attr{ \"yellow\", \"ongreen\", \"bold\" }\n-- local attr = curses.calc_attr{ curses.color_pair(\"yellow\", \"green\"), \"bold\" }\n--\nfunction curses.calc_attr(attrs)\n\n    -- curses.calc_attr(curses.A_BOLD)\n    -- curses.calc_attr(curses.color_pair(\"yellow\", \"green\"))\n    local atype = type(attrs)\n    if atype == \"number\" then\n        return attrs\n    -- curses.calc_attr(\"bold\")\n    -- curses.calc_attr(\"yellow\")\n    elseif atype == \"string\" then\n        if curses.iscolor(attrs) then\n            local color = attrs\n            if color:startswith(\"on\") then\n                color = color:sub(3)\n            end\n            return curses.color_pair(color, color)\n        end\n        return curses.attr(attrs)\n    -- curses.calc_attr{ \"yellow\", \"ongreen\", \"bold\" }\n    -- curses.calc_attr{ curses.color_pair(\"yellow\", \"green\"), \"bold\" }\n    elseif atype == \"table\" then\n        local v = 0\n        local set = {}\n        local fg = nil\n        local bg = nil\n        for _, a in ipairs(attrs) do\n            if not set[a] and a then\n                set[a] = true\n                if type(a) == \"number\" then\n                    v = v + a\n                elseif curses.iscolor(a) then\n                    if a:startswith(\"on\") then\n                        bg = a:sub(3)\n                    else\n                        fg = a\n                    end\n                else\n                    v = v + curses.attr(a)\n                end\n            end\n        end\n        if fg or bg then\n            v = v + curses.color_pair(fg or bg, bg or fg)\n        end\n        return v\n    else\n        return 0\n    end\nend\n\n-- get attr from the color pair\ncurses._color_pair = curses._color_pair or curses.color_pair\nfunction curses.color_pair(fg, bg)\n\n    -- get foreground and backround color\n    fg = curses.color(fg)\n    bg = curses.color(bg)\n\n    -- attempt to get color from the cache first\n    local key = fg .. ':' .. bg\n    local colors = curses._COLORS or {}\n    if colors[key] then\n        return colors[key]\n    end\n\n    -- no colors?\n    if not curses.has_colors() then\n        return 0\n    end\n\n    -- update the colors count\n    curses._NCOLORS = (curses._NCOLORS or 0) + 1\n\n    -- init the color pair\n    if not curses.init_pair(curses._NCOLORS, fg, bg) then\n        os.raise(\"failed to initialize color pair (%d, %s, %s)\", curses._NCOLORS, fg, bg)\n    end\n\n    -- get the color attr\n    local attr = curses._color_pair(curses._NCOLORS)\n\n    -- save to cache\n    colors[key] = attr\n    curses._COLORS = colors\n\n    -- ok\n    return attr\nend\n\n-- set cursor state\ncurses._cursor_set = curses._cursor_set or curses.cursor_set\nfunction curses.cursor_set(state)\n    if curses._CURSOR_STATE ~= state then\n        curses._CURSOR_STATE = state\n        curses._cursor_set(state)\n    end\nend\n\n-- has mouse?\nfunction curses.has_mouse()\n    return curses.KEY_MOUSE and true or false\nend\n\n-- return module: curses\nreturn curses\n"
  },
  {
    "path": "xmake/core/ui/desktop.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        desktop.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal view   = require(\"ui/view\")\nlocal panel  = require(\"ui/panel\")\nlocal curses = require(\"ui/curses\")\n\n-- define module\nlocal desktop = desktop or panel()\n\n-- init desktop\nfunction desktop:init(name, bounds)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- init background\n    self:background_set(\"blue\")\nend\n\n-- return module\nreturn desktop\n"
  },
  {
    "path": "xmake/core/ui/dialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dialog.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal event  = require(\"ui/event\")\nlocal label  = require(\"ui/label\")\nlocal panel  = require(\"ui/panel\")\nlocal action = require(\"ui/action\")\nlocal button = require(\"ui/button\")\nlocal window = require(\"ui/window\")\nlocal curses = require(\"ui/curses\")\n\n-- define module\nlocal dialog = dialog or window()\n\n-- update the position of all buttons\nfunction dialog:_update_buttons_layout()\n\n    -- update the position of all buttons\n    local index = 1\n    local width = self:buttons():width()\n    local count = self:buttons():count()\n    local padding = math.floor(width / 8)\n    for v in self:buttons():views() do\n        local x = padding + index * math.floor((width - padding * 2) / (count + 1)) - math.floor(v:width() / 2)\n        if x + v:width() > width then\n            x = math.max(0, width - v:width())\n        end\n        v:bounds():move2(x, 0)\n        v:invalidate(true)\n        index = index + 1\n    end\nend\n\n-- init dialog\nfunction dialog:init(name, bounds, title)\n\n    -- init window\n    window.init(self, name, bounds, title, true)\n\n    -- insert buttons\n    self:panel():insert(self:buttons())\n    self:panel():action_add(action.ac_on_resized, function (v)\n        self:buttons():bounds_set(rect:new(0, v:height() - 1, v:width(), 1))\n        self:_update_buttons_layout()\n    end)\n\n    -- mark as block mouse\n    self:option_set(\"blockmouse\", true)\nend\n\n-- get buttons\nfunction dialog:buttons()\n    if not self._BUTTONS then\n        self._BUTTONS = panel:new(\"dialog.buttons\", rect:new(0, self:panel():height() - 1, self:panel():width(), 1))\n    end\n    return self._BUTTONS\nend\n\n-- get button from the given button name\nfunction dialog:button(name)\n    return self:buttons():view(name)\nend\n\n-- add button\nfunction dialog:button_add(name, text, command)\n\n    -- init button\n    local btn = button:new(name, rect:new(0, 0, #text, 1), text, command)\n\n    -- insert button\n    self:buttons():insert(btn)\n\n    -- update the position of all buttons\n    self:_update_buttons_layout()\n\n    -- invalidate\n    self:invalidate()\n\n    -- ok\n    return btn\nend\n\n-- select button from the given button name\nfunction dialog:button_select(name)\n    self:buttons():select(self:button(name))\n    return self\nend\n\n-- quit dialog\nfunction dialog:quit()\n    local parent = self:parent()\n    if parent then\n        self:action_on(action.ac_on_exit)\n        parent:remove(self)\n    end\nend\n\n-- on event\nfunction dialog:on_event(e)\n    if e.type == event.ev_keyboard and e.key_name == \"Esc\" then\n        self:quit()\n        return true\n    end\n    return window.on_event(self, e)\nend\n\n-- return module\nreturn dialog\n"
  },
  {
    "path": "xmake/core/ui/event.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        event.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal object = require(\"ui/object\")\n\n-- define module\nlocal event = event or object { _init = {\"type\", \"command\", \"extra\"} }\n\n-- register event types\nfunction event:register(tag, ...)\n    local base = self[tag] or 0\n    local enums = {...}\n    local n = #enums\n    for i = 1, n do\n        self[enums[i]] = i + base\n    end\n    self[tag] = base + n\nend\n\n-- is key?\nfunction event:is_key(key_name)\n    return self.type == event.ev_keyboard and self.key_name == key_name\nend\n\n-- is command event: cm_xxx?\nfunction event:is_command(command)\n    return self.type == event.ev_command and self.command == command\nend\n\n-- dump event\nfunction event:dump()\n    if self.type == event.ev_keyboard then\n        log:print(\"event(key): %s %s ..\", self.key_name, self.key_code)\n    elseif self.type == event.ev_command then\n        log:print(\"event(cmd): %s ..\", self.command)\n    else\n        log:print(\"event(%s): ..\", self.type)\n    end\nend\n\n-- register event types, event.ev_keyboard = 1, event.ev_mouse = 2, ... , event.ev_idle = 5, event.ev_max = 5\nevent:register(\"ev_max\", \"ev_keyboard\", \"ev_mouse\", \"ev_command\", \"ev_text\", \"ev_idle\")\n\n-- register command event types (ev_command)\nevent:register(\"cm_max\", \"cm_quit\", \"cm_exit\", \"cm_enter\")\n\n-- define keyboard event\n--\n-- keyname = key name\n-- keycode = key code\n-- keymeta = ALT key was pressed\n--\nevent.keyboard = object {_init = { \"key_code\", \"key_name\", \"key_meta\" }, type = event.ev_keyboard}\n\n-- define mouse event\n--\n-- btn_name = button number and event type\n-- btn_code = mouse event code\n-- x, y = coordinates\n--\nevent.mouse = object {_init = { \"btn_code\", \"x\", \"y\", \"btn_name\" }, type = event.ev_mouse}\n\n-- define command event\nevent.command = object {_init = { \"command\", \"extra\" }, type = event.ev_command}\n\n-- define idle event\nevent.idle = object {_init = {}, type = event.ev_idle}\n\n-- return module\nreturn event\n"
  },
  {
    "path": "xmake/core/ui/inputdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        inputdialog.lua\n--\n\n-- load modules\nlocal log        = require(\"ui/log\")\nlocal rect       = require(\"ui/rect\")\nlocal view       = require(\"ui/view\")\nlocal event      = require(\"ui/event\")\nlocal action     = require(\"ui/action\")\nlocal curses     = require(\"ui/curses\")\nlocal window     = require(\"ui/window\")\nlocal textedit   = require(\"ui/textedit\")\nlocal textdialog = require(\"ui/textdialog\")\n\n-- define module\nlocal inputdialog = inputdialog or textdialog()\n\n-- init dialog\nfunction inputdialog:init(name, bounds, title)\n\n    -- init window\n    textdialog.init(self, name, bounds, title)\n\n    -- insert textedit\n    self:panel():insert(self:textedit())\n\n    -- resize text\n    self:text():bounds().ey = 1\n    self:text():invalidate(true)\n    self:text():option_set(\"selectable\", false)\n\n    -- text changed\n    self:text():action_set(action.ac_on_text_changed, function (v)\n        if v:text() then\n            local lines = #self:text():splitext(v:text()) + 1\n            if lines > 0 and lines < self:height() then\n                self:text():bounds().ey = lines\n                self:textedit():bounds().sy = lines\n                self:text():invalidate(true)\n                self:textedit():invalidate(true)\n            end\n        end\n    end)\n\n    -- on resize for panel\n    self:panel():action_add(action.ac_on_resized, function (v)\n        self:textedit():bounds_set(rect{0, 1, v:width(), v:height() - 1})\n    end)\nend\n\n-- get textedit\nfunction inputdialog:textedit()\n    if not self._TEXTEDIT then\n        self._TEXTEDIT = textedit:new(\"inputdialog.textedit\", rect{0, 1, self:panel():width(), self:panel():height() - 1})\n    end\n    return self._TEXTEDIT\nend\n\n-- return module\nreturn inputdialog\n"
  },
  {
    "path": "xmake/core/ui/label.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        label.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal event     = require(\"ui/event\")\nlocal action    = require(\"ui/action\")\nlocal curses    = require(\"ui/curses\")\nlocal bit       = require(\"base/bit\")\n\n-- define module\nlocal label = label or view()\n\n-- init label\nfunction label:init(name, bounds, text)\n\n    -- init view\n    view.init(self, name, bounds)\n\n    -- init text\n    self:text_set(text)\n\n    -- init text attribute\n    self:textattr_set(\"black\")\nend\n\n-- draw view\nfunction label:on_draw(transparent)\n\n    -- draw background\n    view.on_draw(self, transparent)\n\n    -- get the text attribute value\n    local textattr = self:textattr_val()\n\n    -- draw text string\n    local str = self:text()\n    if str and #str > 0 and textattr then\n        self:canvas():attr(textattr):move(0, 0):putstrs(self:splitext(str))\n    end\nend\n\n-- get text\nfunction label:text()\n    return self._TEXT\nend\n\n-- set text\nfunction label:text_set(text)\n\n    -- set text\n    text = text or \"\"\n    local changed = self._TEXT ~= text\n    self._TEXT = text\n\n    -- do action\n    if changed then\n        self:action_on(action.ac_on_text_changed)\n    end\n    self:invalidate()\n    return self\nend\n\n-- get text attribute\nfunction label:textattr()\n    return self:attr(\"textattr\")\nend\n\n-- set text attribute, e.g. textattr_set(\"yellow onblue bold\")\nfunction label:textattr_set(attr)\n    return self:attr_set(\"textattr\", attr)\nend\n\n-- get the current text attribute value\nfunction label:textattr_val()\n\n    -- get text attribute\n    local textattr = self:textattr()\n    if not textattr then\n        return\n    end\n\n    -- no text background? use view's background\n    if self:background() and not textattr:find(\"on\") then\n        textattr = textattr .. \" on\" .. self:background()\n    end\n\n    -- attempt to get the attribute value from the cache first\n    self._TEXTATTR = self._TEXTATTR or {}\n    local value = self._TEXTATTR[textattr]\n    if value then\n        return value\n    end\n\n    -- update the cache\n    value = curses.calc_attr(textattr:split(\"%s\"))\n    self._TEXTATTR[textattr] = value\n    return value\nend\n\n-- split text by width\nfunction label:splitext(text, width)\n\n    -- get width\n    width = width or self:width()\n\n    -- split text first\n    local result = {}\n    local lines = text:split('\\n', {strict = true})\n    for idx = 1, #lines do\n        local line = lines[idx]\n        while #line > width do\n            local size = 0\n            local split_idx = 0\n            for p, c in utf8.codes(line) do\n                local w = utf8.width(c)\n                size = size + w\n                if size > width then\n                    split_idx = p\n                    break\n                end\n            end\n\n            if split_idx > 0 then\n                table.insert(result, line:sub(1, split_idx - 1))\n                line = line:sub(split_idx)\n            else\n                break\n            end\n        end\n        table.insert(result, line)\n    end\n    return result\nend\n\n-- return module\nreturn label\n"
  },
  {
    "path": "xmake/core/ui/log.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        log.lua\n--\n\n-- get log\nlocal log = log or (function ()\n\n    -- load modules\n    local os    = require(\"base/os\")\n    local path  = require(\"base/path\")\n    local table = require(\"base/table\")\n\n    -- get log directory\n    local logdir = nil\n    if os.isfile(os.projectfile()) then\n        logdir = path.join(os.projectdir(), \".\" .. xmake._NAME)\n    else\n        logdir = os.tmpdir()\n    end\n\n    -- return module: log\n    local instance = table.inherit(require(\"base/log\"))\n    if instance then\n        instance._FILE = nil\n        instance._LOGFILE = path.join(logdir, \"ui.log\")\n    end\n    return instance\nend)()\nreturn log\n"
  },
  {
    "path": "xmake/core/ui/mconfdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mconfdialog.lua\n--\n\n-- load modules\nlocal table        = require(\"base/table\")\nlocal log          = require(\"ui/log\")\nlocal rect         = require(\"ui/rect\")\nlocal event        = require(\"ui/event\")\nlocal action       = require(\"ui/action\")\nlocal curses       = require(\"ui/curses\")\nlocal window       = require(\"ui/window\")\nlocal scrollbar    = require(\"ui/scrollbar\")\nlocal menuconf     = require(\"ui/menuconf\")\nlocal boxdialog    = require(\"ui/boxdialog\")\nlocal textdialog   = require(\"ui/textdialog\")\nlocal inputdialog  = require(\"ui/inputdialog\")\nlocal choicedialog = require(\"ui/choicedialog\")\n\n-- define module\nlocal mconfdialog = mconfdialog or boxdialog()\n\n-- init dialog\nfunction mconfdialog:init(name, bounds, title)\n\n    -- init window\n    boxdialog.init(self, name, bounds, title)\n\n    -- init text\n    self:text():text_set([[Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty submenus ----).\nPressing <Y> includes, <N> excludes. Enter <Esc> or <Back> to go back, <?> for Help, </> for Search. Legend: [*] built-in  [ ] excluded\n]])\n\n    -- init buttons\n    self:button_add(\"select\", \"< Select >\", function (v, e) self:menuconf():on_event(event.command {\"cm_enter\"}) end)\n    self:button_add(\"back\", \"< Back >\", function (v, e)\n        self:menuconf():on_event(event.command {\"cm_back\"})\n        self:buttons():select(self:button(\"select\"))\n    end)\n    self:button_add(\"exit\", \"< Exit >\", function (v, e)\n        self:show_exit([[Did you wish to save your new configuration?\n(Pressing <Esc> to continue your configuration.)]])\n    end)\n    self:button_add(\"help\", \"< Help >\", function (v, e) self:show_help() end)\n    self:button_add(\"save\", \"< Save >\", function (v, e) self:action_on(action.ac_on_save) end)\n    self:buttons():select(self:button(\"select\"))\n\n    -- insert scrollbar\n    self:box():panel():insert(self:scrollbar_menuconf())\n\n    -- insert menu config\n    self:box():panel():insert(self:menuconf())\n    self:box():panel():action_add(action.ac_on_resized, function (v)\n        local bounds = self:box():panel():bounds()\n        self:menuconf():bounds_set(rect:new(0, 0, bounds:width(), bounds:height()))\n    end)\n\n    -- disable to select to box (disable Tab switch and only response to buttons)\n    self:box():option_set(\"selectable\", false)\n\n    -- on resize for panel\n    self:box():panel():action_add(action.ac_on_resized, function (v)\n        self:menuconf():bounds_set(rect:new(0, 0, v:width() - 1, v:height()))\n        self:scrollbar_menuconf():bounds_set(rect:new(v:width() - 1, 0, 1, v:height()))\n        if self:menuconf():scrollable() then\n            self:scrollbar_menuconf():show(true)\n        else\n            self:scrollbar_menuconf():show(false)\n        end\n    end)\n\n    -- on selected\n    self:menuconf():action_set(action.ac_on_selected, function (v, config)\n\n        -- show input dialog\n        if config.kind == \"string\" or config.kind == \"number\" then\n            local dialog_input = self:inputdialog()\n            dialog_input:extra_set(\"config\", config)\n            dialog_input:title():text_set(config:prompt())\n            dialog_input:textedit():text_set(tostring(config.value))\n            dialog_input:panel():select(dialog_input:textedit())\n            if config.kind == \"string\" then\n                dialog_input:text():text_set(\"Please enter a string value. Use the <TAB> key to move from the input fields to buttons below it.\")\n            else\n                dialog_input:text():text_set(\"Please enter a decimal value. Fractions will not be accepted.  Use the <TAB> key to move from the input field to the buttons below it.\")\n            end\n            self:insert(dialog_input, {centerx = true, centery = true})\n            return true\n\n        -- show choice dialog\n        elseif config.kind == \"choice\" and config.values and #config.values > 0 then\n            local dialog_choice = self:choicedialog()\n            dialog_choice:title():text_set(config:prompt())\n            dialog_choice:choicebox():load(config.values, config.value)\n            dialog_choice:choicebox():action_set(action.ac_on_selected, function (v, index, value)\n                config.value = index\n            end)\n            self:insert(dialog_choice, {centerx = true, centery = true})\n            return true\n        end\n    end)\n\n    -- show scrollbar?\n    self:menuconf():action_add(action.ac_on_load, function (v)\n        if v:scrollable() then\n            self:scrollbar_menuconf():show(true)\n        else\n            self:scrollbar_menuconf():show(false)\n        end\n    end)\n\n    -- on scroll\n    self:menuconf():action_add(action.ac_on_scrolled, function (v, progress)\n        if self:scrollbar_menuconf():state(\"visible\") then\n            self:scrollbar_menuconf():progress_set(progress)\n        end\n    end)\nend\n\n-- load configs\nfunction mconfdialog:load(configs)\n    self._CONFIGS = configs\n    return self:menuconf():load(configs)\nend\n\n-- get configs\nfunction mconfdialog:configs()\n    return self._CONFIGS\nend\n\n-- get menu config\nfunction mconfdialog:menuconf()\n    if not self._MENUCONF then\n        local bounds = self:box():panel():bounds()\n        self._MENUCONF = menuconf:new(\"mconfdialog.menuconf\", rect:new(0, 0, bounds:width() - 1, bounds:height()))\n        self._MENUCONF:state_set(\"focused\", true) -- we can select and highlight selected item\n    end\n    return self._MENUCONF\nend\n\n-- get menu scrollbar\nfunction mconfdialog:scrollbar_menuconf()\n    if not self._SCROLLBAR_MENUCONF then\n        local bounds = self:box():panel():bounds()\n        self._SCROLLBAR_MENUCONF = scrollbar:new(\"mconfdialog.scrollbar\", rect:new(bounds:width() - 1, 0, 1, bounds:height()))\n        self._SCROLLBAR_MENUCONF:show(false)\n    end\n    return self._SCROLLBAR_MENUCONF\nend\n\n-- get help dialog\nfunction mconfdialog:helpdialog()\n    if not self._HELPDIALOG then\n        local helpdialog = textdialog:new(\"mconfdialog.help\", self:bounds(), \"help\")\n        helpdialog:button_add(\"exit\", \"< Exit >\", function (v) helpdialog:quit() end)\n        helpdialog:option_set(\"scrollable\", true)\n        self._HELPDIALOG = helpdialog\n    end\n    return self._HELPDIALOG\nend\n\n-- get result dialog\nfunction mconfdialog:resultdialog()\n    if not self._RESULTDIALOG then\n        local resultdialog = textdialog:new(\"mconfdialog.result\", self:bounds(), \"result\")\n        resultdialog:button_add(\"exit\", \"< Exit >\", function (v) resultdialog:quit() end)\n        resultdialog:option_set(\"scrollable\", true)\n        self._RESULTDIALOG = resultdialog\n    end\n    return self._RESULTDIALOG\nend\n\n-- get input dialog\nfunction mconfdialog:inputdialog()\n    if not self._INPUTDIALOG then\n        local dialog_input = inputdialog:new(\"mconfdialog.input\", rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, \"input dialog\")\n        dialog_input:background_set(self:frame():background())\n        dialog_input:frame():background_set(\"cyan\")\n        dialog_input:textedit():option_set(\"multiline\", false)\n        dialog_input:button_add(\"ok\", \"< Ok >\", function (v)\n            local config = dialog_input:extra(\"config\")\n            if config.kind == \"string\" then\n                config.value = dialog_input:textedit():text()\n            elseif config.kind == \"number\" then\n                local value = tonumber(dialog_input:textedit():text())\n                if value ~= nil then\n                    config.value = value\n                end\n            end\n            dialog_input:quit()\n        end)\n        dialog_input:button_add(\"cancel\", \"< Cancel >\", function (v)\n            dialog_input:quit()\n        end)\n        dialog_input:button_select(\"ok\")\n        self._INPUTDIALOG = dialog_input\n    end\n    return self._INPUTDIALOG\nend\n\n-- get choice dialog\nfunction mconfdialog:choicedialog()\n    if not self._CHOICEDIALOG then\n        local dialog_choice = choicedialog:new(\"mconfdialog.choice\", rect{0, 0, math.min(80, self:width() - 8), math.min(20, self:height())}, \"input dialog\")\n        dialog_choice:background_set(self:frame():background())\n        dialog_choice:frame():background_set(\"cyan\")\n        dialog_choice:box():frame():background_set(\"cyan\")\n        self._CHOICEDIALOG = dialog_choice\n    end\n    return self._CHOICEDIALOG\nend\n\n-- get search dialog\nfunction mconfdialog:searchdialog()\n    if not self._SEARCHDIALOG then\n        local dialog_search = inputdialog:new(\"mconfdialog.input\", rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())}, \"Search Configuration Parameter\")\n        dialog_search:background_set(self:frame():background())\n        dialog_search:frame():background_set(\"cyan\")\n        dialog_search:textedit():option_set(\"multiline\", false)\n        dialog_search:text():text_set(\"Enter (sub)string or lua pattern string to search for configuration\")\n        dialog_search:button_add(\"ok\", \"< Ok >\", function (v)\n            local configs = self:search(self:configs(), dialog_search:textedit():text())\n            local results = \"Search('\" .. dialog_search:textedit():text() .. \"') results:\"\n            for _, config in ipairs(configs) do\n                results = results .. \"\\n\" .. config:prompt()\n                if config.kind then\n                    results = results .. \"\\nkind: \" .. config.kind\n                end\n                if config.default then\n                    results = results .. \"\\ndefault: \" .. tostring(config.default)\n                end\n                if config.path then\n                    results = results .. \"\\npath: \" .. config.path\n                end\n                if config.sourceinfo then\n                    results = results .. \"\\nposition: \" .. (config.sourceinfo.file or \"\") .. \":\" .. (config.sourceinfo.line or \"-1\")\n                end\n                results = results .. \"\\n\"\n            end\n            self:show_result(results)\n            dialog_search:quit()\n        end)\n        dialog_search:button_add(\"cancel\", \"< Cancel >\", function (v)\n            dialog_search:quit()\n        end)\n        dialog_search:button_select(\"ok\")\n        self._SEARCHDIALOG = dialog_search\n    end\n    return self._SEARCHDIALOG\nend\n\n-- get exit dialog\nfunction mconfdialog:exitdialog()\n    if not self._EXITDIALOG then\n        local exitdialog = textdialog:new(\"mconfdialog.exit\", rect{0, 0, math.min(60, self:width() - 8), math.min(7, self:height())}, \"\")\n        exitdialog:background_set(self:frame():background())\n        exitdialog:frame():background_set(\"cyan\")\n        exitdialog:button_add(\"Yes\", \"< Yes >\", function (v)\n            self:action_on(action.ac_on_save)\n        end)\n        exitdialog:button_add(\"No\", \"< No >\", function (v) self:quit() end)\n        exitdialog:option_set(\"scrollable\", false)\n        exitdialog:button_select(\"Yes\")\n        self._EXITDIALOG = exitdialog\n    end\n    return self._EXITDIALOG\nend\n\n-- search configs via the given text\nfunction mconfdialog:search(configs, text)\n    local results = {}\n    for _, config in ipairs(configs) do\n        local prompt = config:prompt()\n        if prompt and prompt:find(text) then\n            table.insert(results, config)\n        end\n        if config.kind == \"menu\" then\n            table.join2(results, self:search(config.configs, text))\n        end\n    end\n    return results\nend\n\n-- show help dialog\nfunction mconfdialog:show_help()\n    if self:parent() then\n\n        -- get the current config item\n        local item = self:menuconf():current()\n\n        -- get the current config\n        local config = item:extra(\"config\")\n\n        -- set help title\n        self:helpdialog():title():text_set(config:prompt())\n\n        -- set help text\n        local text = config.description\n        if type(text) == \"table\" then\n            text = table.concat(text, '\\n')\n        end\n        if config.kind then\n            text = text .. \"\\ntype: \" .. config.kind\n        end\n        if config.kind == \"choice\" then\n            if config.default and config.values[config.default] then\n                text = text .. \"\\ndefault: \" .. config.values[config.default]\n            end\n            text = text .. \"\\nvalues: \"\n            for _, value in ipairs(config.values) do\n                text = text .. \"\\n    - \" .. value\n            end\n        elseif config.default then\n            text = text .. \"\\ndefault: \" .. tostring(config.default)\n        end\n        if config.path then\n            text = text .. \"\\npath: \" .. config.path\n        end\n        if config.sourceinfo then\n            text = text .. \"\\nposition: \" .. (config.sourceinfo.file or \"\") .. \":\" .. (config.sourceinfo.line or \"-1\")\n        end\n        self:helpdialog():text():text_set(text)\n\n        -- show help\n        self:parent():insert(self:helpdialog())\n    end\nend\n\n-- show search dialog\nfunction mconfdialog:show_search()\n    local dialog_search = self:searchdialog()\n    dialog_search:panel():select(dialog_search:textedit())\n    self:insert(dialog_search, {centerx = true, centery = true})\nend\n\n-- show result dialog\nfunction mconfdialog:show_result(text)\n    local dialog_result = self:resultdialog()\n    dialog_result:text():text_set(text)\n    if not self:view(\"mconfdialog.result\") then\n        self:insert(dialog_result, {centerx = true, centery = true})\n    else\n        self:select(dialog_result)\n    end\nend\n\n-- show exit dialog\nfunction mconfdialog:show_exit(text)\n    local dialog_exit = self:exitdialog()\n    dialog_exit:text():text_set(text)\n    if not self:view(\"mconfdialog.exit\") then\n        self:insert(dialog_exit, {centerx = true, centery = true})\n    else\n        self:select(dialog_exit)\n    end\nend\n\n-- on event\nfunction mconfdialog:on_event(e)\n\n    -- select config\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Down\" or e.key_name == \"Up\" or e.key_name == \" \" or e.key_name == \"Esc\" or e.key_name:lower() == \"y\" or e.key_name:lower() == \"n\" then\n            return self:menuconf():on_event(e)\n        elseif e.key_name == \"?\" then\n            self:show_help()\n            return true\n        elseif e.key_name == \"/\" then\n            self:show_search()\n            return true\n        end\n    end\n    return boxdialog.on_event(self, e)\nend\n\n-- on resize\nfunction mconfdialog:on_resize()\n    if self._HELPDIALOG then\n        self:helpdialog():bounds_set(self:bounds())\n    end\n    if self._RESULTDIALOG then\n        self:resultdialog():bounds_set(self:bounds())\n        self:center(self:resultdialog(), {centerx = true, centery = true})\n    end\n    if self._INPUTDIALOG then\n        self:inputdialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())})\n        self:center(self:inputdialog(), {centerx = true, centery = true})\n    end\n    if self._CHOICEDIALOG then\n        self:choicedialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(20, self:height())})\n        self:center(self:choicedialog(), {centerx = true, centery = true})\n    end\n    if self._SEARCHDIALOG then\n        self:searchdialog():bounds_set(rect{0, 0, math.min(80, self:width() - 8), math.min(8, self:height())})\n        self:center(self:searchdialog(), {centerx = true, centery = true})\n    end\n    boxdialog.on_resize(self)\nend\n\n-- return module\nreturn mconfdialog\n"
  },
  {
    "path": "xmake/core/ui/menubar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menubar.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal rect      = require(\"ui/rect\")\nlocal label     = require(\"ui/label\")\nlocal panel     = require(\"ui/panel\")\nlocal curses    = require(\"ui/curses\")\n\n-- define module\nlocal menubar = menubar or panel()\n\n-- init menubar\nfunction menubar:init(name, bounds)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- init title\n    self._TITLE = label:new(\"menubar.title\", rect{0, 0, self:width(), self:height()}, \"Menu Bar\")\n    self:insert(self:title())\n    self:title():textattr_set(\"red\")\n\n    -- init background\n    self:background_set(\"white\")\nend\n\n-- get title\nfunction menubar:title()\n    return self._TITLE\nend\n\n-- return module\nreturn menubar\n"
  },
  {
    "path": "xmake/core/ui/menuconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        menuconf.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal rect      = require(\"ui/rect\")\nlocal panel     = require(\"ui/panel\")\nlocal event     = require(\"ui/event\")\nlocal action    = require(\"ui/action\")\nlocal curses    = require(\"ui/curses\")\nlocal button    = require(\"ui/button\")\nlocal object    = require(\"ui/object\")\n\n-- define module\nlocal menuconf = menuconf or panel()\n\n-- init menuconf\nfunction menuconf:init(name, bounds)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- init configs\n    self._CONFIGS = {}\n\n    -- init items\n    self._ITEMS = {}\n\n    -- init start index\n    self._STARTINDEX = 1\nend\n\n-- load configs\nfunction menuconf:load(configs)\n\n    -- clear the views first\n    self:clear()\n\n    -- reset start index\n    self._STARTINDEX = 1\n\n    -- detach the previous config and view\n    local configs_prev = self._CONFIGS._PREV\n    if configs_prev then\n        for _, config in ipairs(configs_prev) do\n            config._view = nil\n        end\n    end\n\n    -- save configs\n    self._CONFIGS = configs\n\n    -- load items\n    local items = {}\n    for idx, config in ipairs(configs) do\n        table.insert(items, self:_load_item(config, idx))\n    end\n    self._ITEMS = items\n\n    -- insert top-n items\n    local startindex = self._STARTINDEX\n    for idx = startindex, startindex + self:height() - 1 do\n        local item = items[idx]\n        if item then\n            self:insert(item)\n        else\n            break\n        end\n    end\n\n    -- select the first item\n    self:select(self:first())\n\n    -- on loaded\n    self:action_on(action.ac_on_load)\n\n    -- invalidate\n    self:invalidate()\nend\n\n-- is scrollable?\nfunction menuconf:scrollable()\n    return #self:_items() > self:height()\nend\n\n-- scroll\nfunction menuconf:scroll(count)\n    if self:scrollable() then\n        local items = self:_items()\n        local totalcount = #items\n        local startindex = self._STARTINDEX + count\n        if startindex > totalcount then\n            return\n        elseif startindex < 1 then\n            startindex = 1\n        end\n        self._STARTINDEX = startindex\n        self:clear()\n        for idx = startindex, startindex + self:height() - 1 do\n            local item = items[idx]\n            if item then\n                item:bounds():move2(0, idx - startindex)\n                self:insert(item)\n            else\n                break\n            end\n        end\n        if count > 0 then\n            self:select(self:first())\n        else\n            self:select(self:last())\n        end\n        self:invalidate()\n    end\nend\n\n-- on resize\nfunction menuconf:on_resize()\n    local items = self:_items()\n    local totalcount = #items\n    local startindex = self._STARTINDEX\n    for idx = 1, totalcount do\n        local item = items[idx]\n        if item then\n            if idx >= startindex and idx < startindex + self:height() then\n                if not self:view(item:name()) then\n                    item:bounds():move2(0, idx - startindex)\n                    self:insert(item)\n                end\n            else\n                if self:view(item:name()) then\n                    self:remove(item)\n                end\n            end\n        end\n    end\n    panel.on_resize(self)\nend\n\n-- on event\nfunction menuconf:on_event(e)\n    local back = false\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Down\" then\n            if self:current() == self:last() then\n                self:scroll(self:height())\n            else\n                self:select_next()\n            end\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"Up\" then\n            if self:current() == self:first() then\n                self:scroll(-self:height())\n            else\n                self:select_prev()\n            end\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"PageDown\" or e.key_name == \"PageUp\" then\n            local direction = e.key_name == \"PageDown\" and 1 or -1\n            self:scroll(self:height() * direction)\n            self:_notify_scrolled()\n            return true\n        elseif e.key_name == \"Enter\" or e.key_name == \" \" then\n            self:_do_select()\n            return true\n        elseif e.key_name:lower() == \"y\" then\n            self:_do_include(true)\n            return true\n        elseif e.key_name:lower() == \"n\" then\n            self:_do_include(false)\n            return true\n        elseif e.key_name == \"Esc\" then\n            back = true\n        end\n    elseif e.type == event.ev_command then\n        if e.command == \"cm_enter\" then\n            self:_do_select()\n            return true\n        elseif e.command == \"cm_back\" then\n            back = true\n        end\n    end\n\n    -- back?\n    if back then\n        -- load the previous menu configs\n        local configs_prev = self._CONFIGS._PREV\n        if configs_prev then\n            self._CONFIGS._PREV = configs_prev._PREV\n            self:load(configs_prev)\n            return true\n        end\n    end\nend\n\n-- load a config item\nfunction menuconf:_load_item(config, index)\n\n    -- init a config item view\n    local item = button:new(\"menuconf.config.\" .. index,\n                    rect:new(0, index - 1, self:width(), 1),\n                    tostring(config),\n                    function (v, e)\n                        self:_do_select()\n                    end)\n\n    -- attach this index and config\n    item:extra_set(\"index\", index)\n    item:extra_set(\"config\", config)\n\n    -- attach this view\n    config._view = item\n    return item\nend\n\n-- notify scrolled\nfunction menuconf:_notify_scrolled()\n    local totalcount = #self:_items()\n    local startindex = self:current():extra(\"index\")\n    self:action_on(action.ac_on_scrolled, startindex / totalcount)\nend\n\n-- get all items\nfunction menuconf:_items()\n    return self._ITEMS\nend\n\n-- do select the current config\nfunction menuconf:_do_select()\n\n    -- get the current item\n    local item = self:current()\n\n    -- get the current config\n    local config = item:extra(\"config\")\n\n    -- clear new state\n    config.new = false\n\n    -- do action: on selected\n    if self:action_on(action.ac_on_selected, config) then\n        return\n    end\n\n    -- select the boolean config\n    if config.kind == \"boolean\" then\n        config.value = not config.value\n    -- show sub-menu configs\n    elseif config.kind == \"menu\" and config.configs and #config.configs > 0 then\n        local configs_prev = self._CONFIGS\n        self:load(config.configs)\n        self._CONFIGS._PREV = configs_prev\n    end\nend\n\n-- do include\nfunction menuconf:_do_include(enabled)\n\n    -- get the current item\n    local item = self:current()\n\n    -- get the current config\n    local config = item:extra(\"config\")\n\n    -- clear new state\n    config.new = false\n\n    -- select the boolean config\n    if config.kind == \"boolean\" then\n        config.value = enabled\n    end\nend\n\n-- init config object\n--\n-- kind\n--  - {kind = \"number/boolean/string/choice/menu\"}\n--\n-- description\n--  - {description = \"config item description\"}\n--  - {description = {\"config item description\", \"line2\", \"line3\", \"more description ...\"}}\n--\n-- boolean config\n--  - {name = \"...\", kind = \"boolean\", value = true, default = true, description = \"boolean config item\", new = true/false}\n--\n-- number config\n--  - {name = \"...\", kind = \"number\", value = 10, default = 0, description = \"number config item\", new = true/false}\n--\n-- string config\n--  - {name = \"...\", kind = \"string\", value = \"xmake\", default = \"\", description = \"string config item\", new = true/false}\n--\n-- choice config (value is index)\n--  - {name = \"...\", kind = \"choice\", value = 1, default = 1, description = \"choice config item\", values = {2, 2, 3, 4, 5}}\n--\n-- menu config\n--  - {name = \"...\", kind = \"menu\", description = \"menu config item\", configs = {...}}\n--\nlocal config = config or object{new = true,\n                                __index = function (tbl, key)\n                                    if key == \"value\" then\n                                        local val = rawget(tbl, \"_value\")\n                                        if val == nil then\n                                            val = rawget(tbl, \"default\")\n                                        end\n                                        return val\n                                    end\n                                    return rawget(tbl, key)\n                                end,\n                                __newindex = function (tbl, key, val)\n                                    if key == \"value\" then\n                                        key = \"_value\"\n                                    end\n                                    rawset(tbl, key, val)\n                                    if key == \"_value\" then\n                                        local v = rawget(tbl, \"_view\") -- update the config item text in view\n                                        if v then\n                                            v:text_set(tostring(tbl))\n                                        end\n                                    end\n                                end}\n\n-- the prompt info\nfunction config:prompt()\n\n    -- get text (first line in description)\n    local text = self.description or \"\"\n    if type(text) == \"table\" then\n        text = text[1] or \"\"\n    end\n    return text\nend\n\n-- to string\nfunction config:__tostring()\n\n    -- get text (first line in description)\n    local text = self:prompt()\n\n    -- get value\n    local value = self.value\n\n    -- update text\n    if self.kind == \"boolean\" or (not self.kind and type(value) == \"boolean\") then -- boolean config?\n        text = (value and \"[*] \" or \"[ ] \") .. text\n    elseif self.kind == \"number\" or (not self.kind and type(value) == \"number\") then -- number config?\n        text = \"    \" .. text .. \" (\" .. tostring(value or 0) .. \")\"\n    elseif self.kind == \"string\" or (not self.kind and type(value) == \"string\") then -- string config?\n        text = \"    \" .. text .. \" (\" .. tostring(value or \"\") .. \")\"\n    elseif self.kind == \"choice\" then -- choice config?\n        if self.values and #self.values > 0 then\n            text = \"    \" .. text .. \" (\" .. tostring(self.values[value or 1]) .. \")\" .. \"  --->\"\n        else\n            text = \"    \" .. text .. \" ()  ----\"\n        end\n    elseif self.kind == \"menu\" then -- menu config?\n        text = \"    \" .. text .. (self.configs and #self.configs > 0 and \"  --->\" or \"  ----\")\n    end\n\n    -- new config?\n    if self.new and self.kind ~= \"choice\" and self.kind ~= \"menu\" then\n        text = text .. \" (NEW)\"\n    end\n\n    -- ok\n    return text\nend\n\n-- save config objects\nmenuconf.config  = menuconf.config or config\nmenuconf.menu    = menuconf.menu or config { kind = \"menu\", configs = {} }\nmenuconf.number  = menuconf.number or config { kind = \"number\", default = 0 }\nmenuconf.string  = menuconf.string or config { kind = \"string\", default = \"\" }\nmenuconf.choice  = menuconf.choice or config { kind = \"choice\", default = 1, values = {} }\nmenuconf.boolean = menuconf.boolean or config { kind = \"boolean\", default = false }\n\n-- return module\nreturn menuconf\n"
  },
  {
    "path": "xmake/core/ui/object.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        object.lua\n--\n\n-- return module: object\nreturn require(\"base/object\")\n"
  },
  {
    "path": "xmake/core/ui/panel.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        panel.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal view   = require(\"ui/view\")\nlocal rect   = require(\"ui/rect\")\nlocal event  = require(\"ui/event\")\nlocal point  = require(\"ui/point\")\nlocal curses = require(\"ui/curses\")\nlocal action = require(\"ui/action\")\nlocal list   = require(\"base/list\")\n\n-- define module\nlocal panel = panel or view()\n\n-- init panel\nfunction panel:init(name, bounds)\n\n    -- init view\n    view.init(self, name, bounds)\n\n    -- mark as panel\n    self:type_set(\"panel\")\n\n    -- mark as selectable\n    self:option_set(\"selectable\", true)\n\n    -- init child views\n    self._VIEWS = list.new()\n\n    -- init views cache\n    self._VIEWS_CACHE = {}\n\n    -- on click action\n    self:option_set(\"mouseable\", true)\n    self:action_set(action.ac_on_clicked, function (v, x, y)\n\n        -- get relative coordinates\n        x, y = x - v:bounds().sx, y - v:bounds().sy\n\n        -- try focused first\n        local current = v:current()\n        if current and current:option(\"mouseable\") and (current:option(\"blockmouse\") or current:bounds():contains(x, y)) then\n            return current:action_on(action.ac_on_clicked, x, y)\n        end\n\n        local p = v:last()\n        while p do\n            if p:option(\"selectable\") and p:bounds():contains(x, y) then\n                if p:option(\"mouseable\") then\n                    v:select(p)\n                    return p:action_on(action.ac_on_clicked, x, y)\n                end\n                return true\n            end\n            p = v:prev(p)\n        end\n    end)\nend\n\n-- get all child views\nfunction panel:views()\n    return self._VIEWS:items()\nend\n\n-- get views count\nfunction panel:count()\n    return self._VIEWS:size()\nend\n\n-- is empty?\nfunction panel:empty()\n    return self._VIEWS:empty()\nend\n\n-- get the first view\nfunction panel:first()\n    return self._VIEWS:first()\nend\n\n-- get the last view\nfunction panel:last()\n    return self._VIEWS:last()\nend\n\n-- get the next view\nfunction panel:next(v)\n    return self._VIEWS:next(v)\nend\n\n-- get the previous view\nfunction panel:prev(v)\n    return self._VIEWS:prev(v)\nend\n\n-- get the current selected child view\nfunction panel:current()\n    return self._CURRENT\nend\n\n-- get view from the given name\nfunction panel:view(name)\n    return self._VIEWS_CACHE[name]\nend\n\n-- center view\nfunction panel:center(v, opt)\n\n    -- center this view if centerx or centery are set\n    local bounds = v:bounds()\n    local center = false\n    local org = point {bounds.sx, bounds.sy}\n    if opt and opt.centerx then\n        org.x = math.floor((self:width() - v:width()) / 2)\n        center = true\n    end\n    if opt and opt.centery then\n        org.y = math.floor((self:height() - v:height()) / 2)\n        center = true\n    end\n    if center then\n        bounds:move(org.x - bounds.sx, org.y - bounds.sy)\n        v:invalidate(true)\n    end\nend\n\n-- insert view\nfunction panel:insert(v, opt)\n\n    -- check\n    assert(not v:parent() or v:parent() == self)\n    assert(not self:view(v:name()), v:name() .. \" has been in this panel!\")\n\n    -- this view has been inserted into this panel? remove it first\n    if v:parent() == self then\n        self:remove(v)\n    end\n\n    -- center this view if centerx or centery are set\n    self:center(v, opt)\n\n    -- insert this view\n    self._VIEWS:push(v)\n\n    -- cache this view\n    self._VIEWS_CACHE[v:name()] = v\n\n    -- set it's parent view\n    v:parent_set(self)\n\n    -- select this view\n    if v:option(\"selectable\") then\n        self:select(v)\n    end\n\n    -- invalidate it\n    self:invalidate()\nend\n\n-- remove view\nfunction panel:remove(v, opt)\n\n    -- check\n    assert(v:parent() == self)\n\n    -- remove view\n    self._VIEWS:remove(v)\n    self._VIEWS_CACHE[v:name()] = nil\n\n    -- clear parent\n    v:parent_set(nil)\n\n    -- select next view\n    if self:current() == v then\n        if opt and opt.select_prev then\n            self:select_prev(nil, true)\n        else\n            self:select_next(nil, true)\n        end\n    end\n\n    -- invalidate it\n    self:invalidate()\nend\n\n-- clear views\nfunction panel:clear()\n\n    -- clear parents\n    for v in self:views() do\n        v:parent_set(nil)\n    end\n\n    -- clear views and cache\n    self._VIEWS:clear()\n    self._VIEWS_CACHE = {}\n\n    -- reset the current view\n    self._CURRENT = nil\n\n    -- invalidate\n    self:invalidate()\nend\n\n-- select the child view\nfunction panel:select(v)\n\n    -- check\n    assert(v == nil or (v:parent() == self and v:option(\"selectable\")))\n\n    -- get the current selected view\n    local current = self:current()\n    if v == current then\n        return\n    end\n\n    -- undo the previous selected view\n    if current then\n\n        -- undo the current view first\n        if self:state(\"focused\") then\n            current:state_set(\"focused\", false)\n        end\n        current:state_set(\"selected\", false)\n    end\n\n    -- update the current selected view\n    self._CURRENT = v\n\n    -- update the new selected view\n    if v then\n\n        -- select and focus this view\n        v:state_set(\"selected\", true)\n        if self:state(\"focused\") then\n            v:state_set(\"focused\", true)\n        end\n    end\n\n    -- ok\n    return v\nend\n\n-- select the next view\nfunction panel:select_next(start, reset)\n\n    -- is empty?\n    if self:empty() then\n        return\n    end\n\n    -- reset?\n    if reset then\n        self._CURRENT = nil\n    end\n\n    -- get current view\n    local current = start or self:current()\n\n    -- select the next view\n    local next = self:next(current)\n    while next ~= current do\n        if next and next:option(\"selectable\") and next:state(\"visible\") then\n            return self:select(next)\n        end\n        next = self:next(next)\n    end\nend\n\n-- select the previous view\nfunction panel:select_prev(start, reset)\n\n    -- is empty?\n    if self:empty() then\n        return\n    end\n\n    -- reset?\n    if reset then\n        self._CURRENT = nil\n    end\n\n    -- get current view\n    local current = start or self:current()\n\n    -- select the previous view\n    local prev = self:prev(current)\n    while prev ~= current do\n        if prev and prev:option(\"selectable\") and prev:state(\"visible\") then\n            return self:select(prev)\n        end\n        prev = self:prev(prev)\n    end\nend\n\n-- on event\nfunction panel:on_event(e)\n\n    -- select view?\n    if e.type == event.ev_keyboard then\n        -- @note we also use '-' to switch them on termux without right/left and\n        -- we cannot use tab, because we still need swith views on windows. e.g. inputdialog\n        -- @see https://github.com/tboox/ltui/issues/11\n        if e.key_name == \"Right\" or e.key_name == \"-\" then\n            return self:select_next()\n        elseif e.key_name == \"Left\" then\n            return self:select_prev()\n        end\n    end\nend\n\n-- set state\nfunction panel:state_set(name, enable)\n    view.state_set(self, name, enable)\n    if name == \"focused\" and self:current() then\n        self:current():state_set(name, enable)\n    end\n    return self\nend\n\n-- draw panel\nfunction panel:on_draw(transparent)\n\n    -- redraw panel?\n    local redraw = self:state(\"redraw\")\n\n    -- draw panel background first\n    if redraw then\n        view.on_draw(self, transparent)\n    end\n\n    -- draw all child views\n    for v in self:views() do\n        if redraw then\n            v:state_set(\"redraw\", true)\n        end\n        if v:state(\"visible\") and (v:state(\"redraw\") or v:type() == \"panel\") then\n            v:on_draw(transparent)\n        end\n    end\nend\n\n-- resize panel\nfunction panel:on_resize()\n\n    -- resize panel\n    view.on_resize(self)\n\n    -- resize all child views\n    for v in self:views() do\n        v:state_set(\"resize\", true)\n        if v:state(\"visible\") then\n            v:on_resize()\n        end\n    end\nend\n\n-- refresh panel\nfunction panel:on_refresh()\n\n    -- need not refresh? do not refresh it\n    if not self:state(\"refresh\") or not self:state(\"visible\") then\n        return\n    end\n\n    -- refresh all child views\n    for v in self:views() do\n        if v:state(\"refresh\") then\n            v:on_refresh()\n            v:state_set(\"refresh\", false)\n        end\n    end\n\n    -- refresh it\n    view.on_refresh(self)\n\n    -- clear mark\n    self:state_set(\"refresh\", false)\nend\n\n-- dump all views\nfunction panel:dump()\n    log:print(\"%s\", self:_tostring(1))\nend\n\n-- tostring(panel, level)\nfunction panel:_tostring(level)\n    local str = \"\"\n    if self.views then\n        str = str .. string.format(\"<%s %s>\", self:name(), tostring(self:bounds()))\n        if not self:empty() then\n            str = str .. \"\\n\"\n        end\n        for v in self:views() do\n            for l = 1, level do\n                str = str .. \"    \"\n            end\n            str = str .. panel._tostring(v, level + 1) .. \"\\n\"\n        end\n    else\n        str = tostring(self)\n    end\n    return str\nend\n\n-- tostring(panel)\nfunction panel:__tostring()\n    return string.format(\"<panel(%s) %s>\", self:name(), tostring(self:bounds()))\nend\n\n\n-- return module\nreturn panel\n"
  },
  {
    "path": "xmake/core/ui/point.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        point.lua\n--\n\n-- load modules\nlocal object = require(\"ui/object\")\n\n-- define module\nlocal point = point or object { _init = {\"x\", \"y\"} }\n\n-- add delta x and y\nfunction point:addxy(dx, dy)\n    self.x = self.x + dx\n    self.y = self.y + dy\n    return self\nend\n\n-- add point\nfunction point:add(p)\n    return self:addxy(p.x, p.y)\nend\n\n-- sub delta x and y\nfunction point:subxy(dx, dy)\n    return self:addxy(-dx, -dy)\nend\n\n-- sub point\nfunction point:sub(p)\n    return self:addxy(-p.x, -p.y)\nend\n\n-- p1 + p2\nfunction point:__add(p)\n    local np = self()\n    np.x = np.x + p.x\n    np.y = np.y + p.y\n    return np\nend\n\n-- p1 - p2\nfunction point:__sub(p)\n    local np = self()\n    np.x = np.x - p.x\n    np.y = np.y - p.y\n    return np\nend\n\n-- -p\nfunction point:__unm()\n    local p = self()\n    p.x = -p.x\n    p.y = -p.y\n    return p\nend\n\n-- p1 == p2?\nfunction point:__eq(p)\n    return self.x == p.x and self.y == p.y\nend\n\n-- tostring(p)\nfunction point:__tostring()\n    return '(' .. self.x .. ', ' .. self.y .. ')'\nend\n\n-- p1 .. p2\nfunction point.__concat(op1, op2)\n    if type(op1) == 'string' then\n        return op1 .. op2:__tostring()\n    elseif type(op2) == 'string' then\n        return op1:__tostring() .. op2\n    else\n        return op1:__tostring() .. op2:__tostring()\n    end\nend\n\n-- return module\nreturn point\n"
  },
  {
    "path": "xmake/core/ui/program.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        program.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal point  = require(\"ui/point\")\nlocal panel  = require(\"ui/panel\")\nlocal event  = require(\"ui/event\")\nlocal curses = require(\"ui/curses\")\nlocal action = require(\"ui/action\")\n\n-- define module\nlocal program = program or panel()\n\n-- init program\nfunction program:init(name, argv)\n\n    -- init main window\n    local main_window = self:main_window()\n\n    -- disable echo\n    curses.echo(false)\n\n    -- disable input cache\n    curses.cbreak(true)\n\n    -- disable newline\n    curses.nl(false)\n\n    -- init mouse support\n    if curses.has_mouse() then\n        -- curses.ALL_MOUSE_EVENTS may be set to mask unused events\n        curses.mousemask(curses.ALL_MOUSE_EVENTS)\n    end\n\n    -- init colors\n    if (curses.has_colors()) then\n        curses.start_color()\n    end\n\n    -- disable main window cursor\n    main_window:leaveok(false)\n\n    -- enable special key map\n    main_window:keypad(true)\n\n    -- non-block for getch()\n    main_window:nodelay(true)\n\n    -- get 8-bits character for getch()\n    main_window:meta(true)\n\n    -- save the current arguments\n    self._ARGV = argv\n\n    -- init panel\n    panel.init(self, name, rect {0, 0, curses.columns(), curses.lines()})\n\n    -- init state\n    self:state_set(\"focused\", true)\n    self:state_set(\"selected\", true)\nend\n\n-- exit program\nfunction program:exit()\n\n    -- exit panel\n    panel.exit(self)\n\n    -- (attempt to) make sure the screen will be cleared\n    -- if not restored by the curses driver\n    self:main_window():clear()\n    self:main_window():noutrefresh()\n    curses.doupdate()\n\n    -- exit curses\n    assert(not curses.isdone())\n    curses.done()\nend\n\n-- get the main window\nfunction program:main_window()\n\n    -- init main window if not exists\n    local main_window = self._MAIN_WINDOW\n    if not main_window then\n\n        -- init main window\n        main_window = curses.init()\n        assert(main_window, \"cannot init main window!\")\n\n        -- save main window\n        self._MAIN_WINDOW = main_window\n    end\n    return main_window\nend\n\n-- get the command arguments\nfunction program:argv()\n    return self._ARGV\nend\n\n-- get the current event\nfunction program:event()\n\n    -- get event from the event queue first\n    local event_queue = self._EVENT_QUEUE\n    if event_queue then\n        local e = event_queue[1]\n        if e then\n            table.remove(event_queue, 1)\n            return e\n        end\n    end\n\n    -- get input key\n    local key_code, key_name, key_meta = self:_input_key()\n    if key_code then\n        if curses.KEY_MOUSE and key_code == curses.KEY_MOUSE then\n            local code, x, y = curses.getmouse()\n            local name = self:_mouse_map()[code]\n            return event.mouse{code, x, y, name}\n        end\n        return event.keyboard{key_code, key_name, key_meta}\n    end\nend\n\n-- on event\nfunction program:on_event(e)\n\n    -- get the top focused view\n    local focused_view = self\n    while focused_view:type() == \"panel\" and focused_view:current() do\n        focused_view = focused_view:current()\n    end\n\n    -- do event for focused views\n    while focused_view and focused_view ~= self do\n        local parent = focused_view:parent()\n        if focused_view:on_event(e) then\n            return true\n        end\n        focused_view = parent\n    end\n\n    -- do event\n    if e.type == event.ev_keyboard then\n        -- resize?\n        if e.key_name == \"Resize\" then\n            self:bounds_set(rect {0, 0, curses.columns(), curses.lines()})\n            return true\n        -- refresh?\n        elseif e.key_name == \"Refresh\" then\n            self:invalidate()\n            return true\n        -- ctrl+c? quit program\n        elseif e.key_name == \"CtrlC\" then\n            self:send(\"cm_exit\")\n            return true\n        end\n    -- quit program?\n    elseif event.is_command(e, \"cm_exit\") then\n        self:quit()\n        return true\n    -- mouse events\n    elseif e.type == event.ev_mouse and curses.has_mouse() and self:option(\"mouseable\") then\n        if e.btn_name == \"BUTTON1_CLICKED\" or e.btn_name == \"BUTTON1_DOUBLE_CLICKED\" then\n            self:action_on(action.ac_on_clicked, e.x, e.y)\n        end\n    end\nend\n\n-- put an event to view\nfunction program:put_event(e)\n\n    -- init event queue\n    self._EVENT_QUEUE = self._EVENT_QUEUE or {}\n\n    -- put event to queue\n    table.insert(self._EVENT_QUEUE, e)\nend\n\n-- send command\nfunction program:send(command, extra)\n    self:put_event(event.command {command, extra})\nend\n\n-- quit program\nfunction program:quit()\n    self:send(\"cm_quit\")\nend\n\n-- run program loop\nfunction program:loop(argv)\n\n    -- do message loop\n    local e = nil\n    local sleep = true\n    while true do\n\n        -- get the current event\n        e = self:event()\n\n        -- do event\n        if e then\n            event.dump(e)\n            self:on_event(e)\n            sleep = false\n        else\n            -- do idle event\n            self:on_event(event.idle())\n            sleep = true\n        end\n\n        -- quit?\n        if e and event.is_command(e, \"cm_quit\") then\n            break\n        end\n\n        -- resize views\n        if self:state(\"resize\") then\n            self:on_resize()\n        end\n\n        -- draw views\n        self:on_draw()\n\n        -- refresh views\n        if self:state(\"refresh\") then\n            self:on_refresh()\n        end\n\n        -- wait some time, 50ms\n        if sleep then\n            curses.napms(50)\n        end\n    end\nend\n\n-- refresh program\nfunction program:on_refresh()\n\n    -- refresh views\n    panel.on_refresh(self)\n\n    -- trace\n    log:print(\"%s: refresh ..\", self)\n\n    -- get main window\n    local main_window = curses.main_window()\n\n    -- refresh main window\n    self:window():copy(main_window, 0, 0, 0, 0, self:height() - 1, self:width() - 1)\n\n    -- refresh cursor\n    self:_refresh_cursor()\n\n    -- mark as refresh\n    main_window:noutrefresh()\n\n    -- do update\n    curses.doupdate()\nend\n\n-- get key map\nfunction program:_key_map()\n    if not self._KEYMAP then\n        self._KEYMAP =\n        {\n            [ 1] = \"CtrlA\", [ 2] = \"CtrlB\", [ 3] = \"CtrlC\",\n            [ 4] = \"CtrlD\", [ 5] = \"CtrlE\", [ 6] = \"CtrlF\",\n            [ 7] = \"CtrlG\", [ 8] = \"CtrlH\", [ 9] = \"CtrlI\",\n            [10] = \"CtrlJ\", [11] = \"CtrlK\", [12] = \"CtrlL\",\n            [13] = \"CtrlM\", [14] = \"CtrlN\", [15] = \"CtrlO\",\n            [16] = \"CtrlP\", [17] = \"CtrlQ\", [18] = \"CtrlR\",\n            [19] = \"CtrlS\", [20] = \"CtrlT\", [21] = \"CtrlU\",\n            [22] = \"CtrlV\", [23] = \"CtrlW\", [24] = \"CtrlX\",\n            [25] = \"CtrlY\", [26] = \"CtrlZ\",\n\n            [  8] = \"Backspace\",\n            [  9] = \"Tab\",\n            [ 10] = \"Enter\",\n            [ 13] = \"Enter\",\n            [ 27] = \"Esc\",\n            [ 31] = \"CtrlBackspace\",\n            [127] = \"Backspace\",\n\n            [curses.KEY_DOWN        ] = \"Down\",\n            [curses.KEY_UP          ] = \"Up\",\n            [curses.KEY_LEFT        ] = \"Left\",\n            [curses.KEY_RIGHT       ] = \"Right\",\n            [curses.KEY_HOME        ] = \"Home\",\n            [curses.KEY_END         ] = \"End\",\n            [curses.KEY_NPAGE       ] = \"PageDown\",\n            [curses.KEY_PPAGE       ] = \"PageUp\",\n            [curses.KEY_IC          ] = \"Insert\",\n            [curses.KEY_DC          ] = \"Delete\",\n            [curses.KEY_BACKSPACE   ] = \"Backspace\",\n            [curses.KEY_F1          ] = \"F1\",\n            [curses.KEY_F2          ] = \"F2\",\n            [curses.KEY_F3          ] = \"F3\",\n            [curses.KEY_F4          ] = \"F4\",\n            [curses.KEY_F5          ] = \"F5\",\n            [curses.KEY_F6          ] = \"F6\",\n            [curses.KEY_F7          ] = \"F7\",\n            [curses.KEY_F8          ] = \"F8\",\n            [curses.KEY_F9          ] = \"F9\",\n            [curses.KEY_F10         ] = \"F10\",\n            [curses.KEY_F11         ] = \"F11\",\n            [curses.KEY_F12         ] = \"F12\",\n\n            [curses.KEY_RESIZE      ] = \"Resize\",\n            [curses.KEY_REFRESH     ] = \"Refresh\",\n\n            [curses.KEY_BTAB        ] = \"ShiftTab\",\n            [curses.KEY_SDC         ] = \"ShiftDelete\",\n            [curses.KEY_SIC         ] = \"ShiftInsert\",\n            [curses.KEY_SEND        ] = \"ShiftEnd\",\n            [curses.KEY_SHOME       ] = \"ShiftHome\",\n            [curses.KEY_SLEFT       ] = \"ShiftLeft\",\n            [curses.KEY_SRIGHT      ] = \"ShiftRight\",\n\n            -- register virtual keys\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/1610\n            -- https://github.com/wmcbrine/PDCurses/blob/HEAD/curses.h#L766-L774\n            [curses.KEY_C2 or -1    ] = \"Down\",\n            [curses.KEY_A2 or -1    ] = \"Up\",\n            [curses.KEY_B1 or -1    ] = \"Left\",\n            [curses.KEY_B3 or -1    ] = \"Right\"\n        }\n    end\n    return self._KEYMAP\nend\n\n-- get mouse map\nfunction program:_mouse_map()\n    if not self._MOUSEMAP then\n        -- must be defined dynamically since it depends\n        -- on curses implementation\n        self._MOUSEMAP = {}\n        for n, v in pairs(curses) do\n            if (n:match('MOUSE') and n ~= 'KEY_MOUSE') or n:match('BUTTON') then\n                self._MOUSEMAP[v] = n\n            end\n        end\n    end\n    return self._MOUSEMAP\nend\n\n-- get input key\nfunction program:_input_key()\n\n    -- get main window\n    local main_window = self:main_window()\n\n    -- get input character\n    local ch = main_window:getch()\n    if not ch then\n        return\n    end\n\n    -- this is the time limit in ms within Esc-key sequences are detected as\n    -- Alt-letter sequences. useful when we can't generate Alt-letter sequences\n    -- directly. sometimes this pause may be longer than expected since the\n    -- curses driver may also pause waiting for another key (ncurses-5.3)\n    local esc_delay = 400\n\n    -- get key map\n    local key_map = self:_key_map()\n\n    -- is alt?\n    local alt = ch == 27\n    if alt then\n\n        -- get the next input character\n        ch = main_window:getch()\n        if not ch then\n\n            -- since there is no way to know the time with millisecond precision\n            -- we pause the the program until we get a key or the time limit\n            -- is reached\n            local t = 0\n            while true do\n                ch = main_window:getch()\n                if ch or t >= esc_delay then\n                    break\n                end\n\n                -- wait some time, 50ms\n                curses.napms(50)\n                t = t + 50\n            end\n\n            -- nothing was typed... return Esc\n            if not ch then\n                return 27, \"Esc\", false\n            end\n        end\n        if ch > 96 and ch < 123 then\n            ch = ch - 32\n        end\n    end\n\n    -- map character to key\n    local key = key_map[ch]\n    local key_name = nil\n    if key then\n        key_name = alt and \"Alt\".. key or key\n    elseif (ch < 256) then\n        key_name = alt and \"Alt\".. string.char(ch) or string.char(ch)\n    else\n        return ch, '(noname)', alt\n    end\n\n    -- return key info\n    return ch, key_name, alt\nend\n\n-- refresh cursor\nfunction program:_refresh_cursor()\n\n    -- get the top focused view\n    local focused_view = self\n    while focused_view:type() == \"panel\" and focused_view:current() do\n        focused_view = focused_view:current()\n    end\n\n    -- get the cursor state of the top focused view\n    local cursor_state = 0\n    if focused_view and focused_view:state(\"cursor_visible\") then\n        cursor_state = focused_view:state(\"block_cursor\") and 2 or 1\n    end\n\n    -- get the cursor position\n    local cursor = focused_view and focused_view:cursor()() or point{0, 0}\n    if cursor_state ~= 0 then\n        local v = focused_view\n        while v:parent() do\n\n            -- update the cursor position\n            cursor:addxy(v:bounds().sx, v:bounds().sy)\n\n            -- is cursor visible?\n            if cursor.x < 0 or cursor.y < 0 or cursor.x >= v:parent():width() or cursor.y >= v:parent():height() then\n                cursor_state = 0\n                break\n            end\n\n            -- get the parent view\n            v = v:parent()\n        end\n    end\n\n    -- update the cursor state\n    curses.cursor_set(cursor_state)\n\n    -- get main window\n    local main_window = curses.main_window()\n\n    -- trace\n    log:print(\"cursor(%s): %s, %d\", focused_view, cursor, cursor_state)\n\n    -- move cursor position\n    if cursor_state ~= 0 then\n        main_window:move(cursor.y, cursor.x)\n    else\n        main_window:move(self:height() - 1, self:width() - 1)\n    end\nend\n\n-- return module\nreturn program\n"
  },
  {
    "path": "xmake/core/ui/rect.lua",
    "content": "\n--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rect.lua\n--\n\n-- load modules\nlocal point  = require(\"ui/point\")\nlocal object = require(\"ui/object\")\n\n-- define module\nlocal rect = rect or object { _init = {\"sx\", \"sy\", \"ex\", \"ey\"} }\n\n-- make rect\nfunction rect:new(x, y, w, h)\n    return rect { x, y, x + w, y + h }\nend\n\n-- get rect size\nfunction rect:size()\n    return point { self.ex - self.sx, self.ey - self.sy }\nend\n\n-- get width\nfunction rect:width()\n    return self.ex - self.sx\nend\n\n-- get height\nfunction rect:height()\n    return self.ey - self.sy\nend\n\n-- resize rect\nfunction rect:resize(w, h)\n    self.ex = self.sx + w\n    self.ey = self.sy + h\nend\n\n-- move rect\nfunction rect:move(dx, dy)\n    self.sx = self.sx + dx\n    self.sy = self.sy + dy\n    self.ex = self.ex + dx\n    self.ey = self.ey + dy\n    return self\nend\n\n-- move rect to the given position\nfunction rect:move2(x, y)\n    local w = self.ex - self.sx\n    local h = self.ey - self.sy\n    self.sx = x\n    self.sy = y\n    self.ex = x + w\n    self.ey = y + h\n    return self\nend\n\n-- move top right corner of the rect\nfunction rect:moves(dx, dy)\n    self.sx = self.sx + dx\n    self.sy = self.sy + dy\n    return self\nend\n\n-- move bottom left corner of the rect\nfunction rect:movee(dx, dy)\n    self.ex = self.ex + dx\n    self.ey = self.ey + dy\n    return self\nend\n\n-- expand rect area\nfunction rect:grow(dx, dy)\n    self.sx = self.sx - dx\n    self.sy = self.sy - dy\n    self.ex = self.ex + dx\n    self.ey = self.ey + dy\n    return self\nend\n\n-- is intersect?\nfunction rect:is_intersect(r)\n    return not self():intersect(r):empty()\nend\n\n-- set rect with shared area between this rect and a given rect\nfunction rect:intersect(r)\n    self.sx = math.max(self.sx, r.sx)\n    self.sy = math.max(self.sy, r.sy)\n    self.ex = math.min(self.ex, r.ex)\n    self.ey = math.min(self.ey, r.ey)\n    return self\nend\n\n-- get rect with shared area between two rects: local rect_new = r1 / r2\nfunction rect:__div(r)\n    return self():intersect(r)\nend\n\n-- set union rect\nfunction rect:union(r)\n    self.sx = math.min(self.sx, r.sx)\n    self.sy = math.min(self.sy, r.sy)\n    self.ex = math.max(self.ex, r.ex)\n    self.ey = math.max(self.ey, r.ey)\n    return self\nend\n\n-- get union rect: local rect_new = r1 + r2\nfunction rect:__add(r)\n    return self():union(r)\nend\n\n-- r1 == r1?\nfunction rect:__eq(r)\n    return\n        self.sx == r.sx and\n        self.sy == r.sy and\n        self.ex == r.ex and\n        self.ey == r.ey\nend\n\n-- contains the given point in rect?\nfunction rect:contains(x, y)\n    return x >= self.sx and x < self.ex and y >= self.sy and y < self.ey\nend\n\n-- empty rect?\nfunction rect:empty()\n    return self.sx >= self.ex or self.sy >= self.ey\nend\n\n-- tostring(r)\nfunction rect:__tostring()\n    if self:empty() then\n        return '[]'\n    end\n    return string.format(\"[%d, %d, %d, %d]\", self.sx, self.sy, self.ex, self.ey)\nend\n\n-- r1 .. r2\nfunction rect.__concat(op1, op2)\n    if type(op1) == 'string' then\n        return op1 .. op2:__tostring()\n    elseif type(op2) == 'string' then\n        return op1:__tostring() .. op2\n    else\n        return op1:__tostring() .. op2:__tostring()\n    end\nend\n\n-- return module\nreturn rect\n"
  },
  {
    "path": "xmake/core/ui/scrollbar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scrollbar.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal event     = require(\"ui/event\")\nlocal curses    = require(\"ui/curses\")\nlocal action    = require(\"ui/action\")\n\n-- define module\nlocal scrollbar = scrollbar or view()\n\n-- init scrollbar\nfunction scrollbar:init(name, bounds, vertical)\n\n    -- init view\n    view.init(self, name, bounds)\n\n    -- init bar attribute\n    self:charattr_set(\"black on black\")\n\n    -- init bar vertical\n    self:vertical_set(vertical)\n\n    -- init progress\n    self:progress_set(0)\n\n    -- init character\n    self:char_set(' ')\nend\n\n-- get bar attribute\nfunction scrollbar:charattr()\n    return self:attr(\"charattr\")\nend\n\n-- set bar attribute, .e.g charattr_set(\"yellow onblue bold\")\nfunction scrollbar:charattr_set(attr)\n    return self:attr_set(\"charattr\", attr)\nend\n\n-- get the current char attribute value\nfunction scrollbar:charattr_val()\n\n    -- get text attribute\n    local charattr = self:charattr()\n    if not charattr then\n        return\n    end\n\n    -- no text background? use view's background\n    if self:background() and not charattr:find(\"on\") then\n        charattr = charattr .. \" on\" .. self:background()\n    end\n\n    -- attempt to get the attribute value from the cache first\n    self._charattr = self._charattr or {}\n    local value = self._charattr[charattr]\n    if value then\n        return value\n    end\n\n    -- update the cache\n    value = curses.calc_attr(charattr:split(\"%s+\"))\n    self._charattr[charattr] = value\n    return value\nend\n\n-- get bar character\nfunction scrollbar:char()\n    return self:attr(\"char\") or ' '\nend\n\n-- set bar character\nfunction scrollbar:char_set(char)\n    if char ~= self:char() then\n        self:invalidate()\n    end\n    return self:attr_set(\"char\", char)\nend\n\n-- is vertical bar?\nfunction scrollbar:vertical()\n    return self:attr(\"vertical\") or true\nend\n\n-- set bar vertical\nfunction scrollbar:vertical_set(vertical)\n    return self:attr_set(\"vertical\", vertical)\nend\n\n-- get bar progress\nfunction scrollbar:progress()\n    return self:attr(\"progress\") or 0\nend\n\n-- set bar progress, [0, 1]\nfunction scrollbar:progress_set(progress)\n    if progress > 1 then\n        progress = 1\n    elseif progress < 0 then\n        progress = 0\n    end\n    if progress ~= self:progress() then\n        self:invalidate()\n    end\n    return self:attr_set(\"progress\", progress)\nend\n\n-- get bar step width\nfunction scrollbar:stepwidth()\n    return self:attr(\"stepwidth\") or 0.1\nend\n\n-- set bar step width, [0, 1]\nfunction scrollbar:stepwidth_set(stepwidth)\n    if stepwidth > 1 then\n        stepwidth = 1\n    elseif stepwidth < 0 then\n        stepwidth = 0\n    end\n    if stepwidth ~= self:stepwidth() then\n        self:invalidate()\n    end\n    return self:attr_set(\"stepwidth\", stepwidth)\nend\n\n-- draw scrollbar\nfunction scrollbar:on_draw(transparent)\n\n    -- draw background\n    view.on_draw(self, transparent)\n\n    -- draw bar\n    local char      = self:char()\n    local charattr  = self:charattr_val()\n    if self:vertical() then\n        local sn = math.ceil(self:height() * self:stepwidth())\n        local sb = math.floor(self:height() * self:progress())\n        local se = sb + sn\n        if se > self:height() then\n            sb = self:height() - sn\n            se = self:height()\n        end\n        if se > sb and se - sb <= self:height() then\n            for x = 0, self:width() - 1 do\n                self:canvas():attr(charattr):move(x, sb):putchar(char, se - sb, true)\n            end\n        end\n    else\n        local sn = math.ceil(self:width() * self:stepwidth())\n        local sb = math.floor(self:width() * self:progress())\n        local se = sb + sn\n        if se > self:width() then\n            sb = self:width() - sn\n            se = self:width()\n        end\n        if se > sb and se - sb <= self:width() then\n            for y = 0, self:height() - 1 do\n                self:canvas():attr(charattr):move(sb, y):putchar(char, se - sb)\n            end\n        end\n    end\nend\n\n-- scroll bar, e.g. -1 * 0.1, 1 * 0.1\nfunction scrollbar:scroll(steps)\n    steps = steps or 1\n    self:progress_set(self:progress() + steps * self:stepwidth())\n    self:action_on(action.ac_on_scrolled, self:progress())\nend\n\n-- on event\nfunction scrollbar:on_event(e)\n    if e.type == event.ev_keyboard then\n        if self:vertical() then\n            if e.key_name == \"Up\" then\n                self:scroll(-1)\n                return true\n            elseif e.key_name == \"Down\" then\n                self:scroll(1)\n                return true\n            end\n        else\n            if e.key_name == \"Left\" then\n                self:scroll(-1)\n                return true\n            elseif e.key_name == \"Right\" then\n                self:scroll(1)\n                return true\n            end\n        end\n    end\nend\n\n-- return module\nreturn scrollbar\n"
  },
  {
    "path": "xmake/core/ui/statusbar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        statusbar.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal rect      = require(\"ui/rect\")\nlocal panel     = require(\"ui/panel\")\nlocal label     = require(\"ui/label\")\nlocal event     = require(\"ui/event\")\nlocal curses    = require(\"ui/curses\")\n\n-- define module\nlocal statusbar = statusbar or panel()\n\n-- init statusbar\nfunction statusbar:init(name, bounds)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- init info\n    self._INFO = label:new(\"statusbar.info\", rect{0, 0, self:width(), self:height()})\n    self:insert(self:info())\n    self:info():text_set(\"Status Bar\")\n    self:info():textattr_set(\"blue\")\n\n    -- init background\n    self:background_set(\"white\")\nend\n\n-- get status info\nfunction statusbar:info()\n    return self._INFO\nend\n\n-- return module\nreturn statusbar\n"
  },
  {
    "path": "xmake/core/ui/textarea.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textarea.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal label     = require(\"ui/label\")\nlocal event     = require(\"ui/event\")\nlocal curses    = require(\"ui/curses\")\nlocal action    = require(\"ui/action\")\n\n-- define module\nlocal textarea = textarea or label()\n\n-- init textarea\nfunction textarea:init(name, bounds, text)\n\n    -- init label\n    label.init(self, name, bounds, text)\n\n    -- mark as selectable\n    self:option_set(\"selectable\", true)\n\n    -- init start line\n    self._STARTLINE = 0\n    self._LINECOUNT = 0\nend\n\n-- draw textarea\nfunction textarea:on_draw(transparent)\n\n    -- draw background\n    view.on_draw(self, transparent)\n\n    -- get the text attribute value\n    local textattr = self:textattr_val()\n\n    -- draw text string\n    local strs = self._SPLITTEXT\n    if strs and #strs > 0 and textattr then\n        self:canvas():attr(textattr):move(0, 0):putstrs(strs, self._STARTLINE + 1)\n    end\nend\n\n-- set text\nfunction textarea:text_set(text)\n    self._STARTLINE = 0\n    self._SPLITTEXT = text and self:splitext(text) or {}\n    self._LINECOUNT = #self._SPLITTEXT\n    return label.text_set(self, text)\nend\n\n-- is scrollable?\nfunction textarea:scrollable()\n    return self._LINECOUNT > self:height()\nend\n\n-- scroll\nfunction textarea:scroll(lines)\n    if self:scrollable() then\n        self._STARTLINE = self._STARTLINE + lines\n        if self._STARTLINE < 0 then\n            self._STARTLINE = 0\n        end\n        local startline_end = self._LINECOUNT > self:height() and self._LINECOUNT - self:height() or self._LINECOUNT\n        if self._STARTLINE > startline_end then\n            self._STARTLINE = startline_end\n        end\n        self:action_on(action.ac_on_scrolled, self._STARTLINE / startline_end)\n        self:invalidate()\n    end\nend\n\n-- scroll to end\nfunction textarea:scroll_to_end()\n    if self:scrollable() then\n        local startline_end = self._LINECOUNT > self:height() and self._LINECOUNT - self:height() or self._LINECOUNT\n        self._STARTLINE = startline_end\n        self:action_on(action.ac_on_scrolled, self._STARTLINE / startline_end)\n        self:invalidate()\n    end\nend\n\n-- on event\nfunction textarea:on_event(e)\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Up\" then\n            self:scroll(-5)\n            return true\n        elseif e.key_name == \"Down\" then\n            self:scroll(5)\n            return true\n        end\n    end\nend\n\n-- return module\nreturn textarea\n"
  },
  {
    "path": "xmake/core/ui/textdialog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textdialog.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal rect      = require(\"ui/rect\")\nlocal event     = require(\"ui/event\")\nlocal dialog    = require(\"ui/dialog\")\nlocal curses    = require(\"ui/curses\")\nlocal textarea  = require(\"ui/textarea\")\nlocal scrollbar = require(\"ui/scrollbar\")\nlocal action    = require(\"ui/action\")\n\n-- define module\nlocal textdialog = textdialog or dialog()\n\n-- init dialog\nfunction textdialog:init(name, bounds, title)\n\n    -- init window\n    dialog.init(self, name, bounds, title)\n\n    -- mark as scrollable, disabled by default\n    self:option_set(\"scrollable\", false)\n\n    -- insert text\n    self:panel():insert(self:text())\n\n    -- insert scrollbar\n    self:panel():insert(self:scrollbar())\n\n    -- select buttons by default\n    self:panel():select(self:buttons())\n\n    -- on resize for panel\n    self:panel():action_add(action.ac_on_resized, function (v)\n        if self:option(\"scrollable\") then\n            self:text():bounds_set(rect:new(0, 0, v:width() - 1, v:height() - 1))\n            self:scrollbar():bounds_set(rect:new(v:width() - 1, 0, 1, v:height() - 1))\n        else\n            self:text():bounds_set(rect:new(0, 0, v:width(), v:height() - 1))\n        end\n    end)\n\n    -- show scrollbar?\n    self:text():action_add(action.ac_on_text_changed, function (v)\n        if self:option(\"scrollable\") then\n            if v:scrollable() then\n                self:scrollbar():show(true)\n            else\n                self:scrollbar():show(false)\n            end\n        end\n    end)\n\n    -- on scroll for text and scrollbar\n    self:text():action_add(action.ac_on_scrolled, function (v, progress)\n        if self:scrollbar():state(\"visible\") then\n            self:scrollbar():progress_set(progress)\n        end\n    end)\nend\n\n-- enable or disable scrollbar\nfunction textdialog:option_set(name, value)\n    if name == \"scrollable\" then\n        local oldvalue = self:option(name)\n        if value ~= oldvalue then\n            if value then\n                self:text():bounds():resize(self:panel():width() - 1, self:panel():height() - 1)\n            else\n                self:text():bounds():resize(self:panel():width(), self:panel():height() - 1)\n            end\n        end\n    end\n    dialog.option_set(self, name, value)\nend\n\n-- get text\nfunction textdialog:text()\n    if not self._TEXT then\n        self._TEXT = textarea:new(\"textdialog.text\", rect:new(0, 0, self:panel():width(), self:panel():height() - 1))\n    end\n    return self._TEXT\nend\n\n-- get scrollbar\nfunction textdialog:scrollbar()\n    if not self._SCROLLBAR then\n        self._SCROLLBAR = scrollbar:new(\"textdialog.scrollbar\", rect:new(self:panel():width() - 1, 0, 1, self:panel():height() - 1))\n        self._SCROLLBAR:show(false)\n    end\n    return self._SCROLLBAR\nend\n\n-- on event\nfunction textdialog:on_event(e)\n\n    -- pass event to dialog\n    if dialog.on_event(self, e) then\n        return true\n    end\n\n    -- pass keyboard event to text area to scroll\n    if e.type == event.ev_keyboard then\n        return self:text():on_event(e)\n    end\nend\n\n-- return module\nreturn textdialog\n"
  },
  {
    "path": "xmake/core/ui/textedit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        textedit.lua\n--\n\n-- load modules\nlocal log       = require(\"ui/log\")\nlocal view      = require(\"ui/view\")\nlocal label     = require(\"ui/label\")\nlocal event     = require(\"ui/event\")\nlocal border    = require(\"ui/border\")\nlocal curses    = require(\"ui/curses\")\nlocal textarea  = require(\"ui/textarea\")\nlocal action    = require(\"ui/action\")\nlocal bit       = require(\"base/bit\")\n\n-- define module\nlocal textedit = textedit or textarea()\n\n-- init textedit\nfunction textedit:init(name, bounds, text)\n\n    -- init label\n    textarea.init(self, name, bounds, text)\n\n    -- show cursor\n    self:cursor_show(true)\n\n    -- mark as selectable\n    self:option_set(\"selectable\", true)\n\n    -- mark as mouseable\n    self:option_set(\"mouseable\", true)\n    self:action_set(action.ac_on_clicked, function () return true end)\n\n    -- enable multiple line\n    self:option_set(\"multiline\", true)\nend\n\n-- draw textedit\nfunction textedit:on_draw(transparent)\n\n    -- draw label\n    textarea.on_draw(self, transparent)\n\n    -- move cursor\n    if not self:text() or #self:text() == 0 then\n        self:cursor_move(0, 0)\n    else\n        self:cursor_move(self:canvas():pos())\n    end\nend\n\n-- set text\nfunction textedit:text_set(text)\n    textarea.text_set(self, text)\n    self:scroll_to_end()\n    return self\nend\n\n-- on event\nfunction textedit:on_event(e)\n\n    -- update text\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Enter\" and self:option(\"multiline\") then\n            self:text_set(self:text() .. '\\n')\n            return true\n        elseif e.key_name == \"Backspace\" then\n            local text = self:text()\n            if #text > 0 then\n                local size = 1\n                -- while continuation byte\n                while bit.band(text:byte(#text - size + 1), 0xc0) == 0x80 do\n                    size = size + 1\n                end\n                self:text_set(text:sub(1, #text - size))\n            end\n            return true\n        elseif e.key_name == \"CtrlV\" then\n            local pastetext = os.pbpaste()\n            if pastetext then\n                self:text_set(self:text() .. pastetext)\n            end\n            return true\n        elseif e.key_code > 0x1f and e.key_code < 0xf8 then\n            self:text_set(self:text() .. string.char(e.key_code))\n            return true\n        end\n    end\n\n    -- do textarea event\n    return textarea.on_event(self, e)\nend\n\n-- return module\nreturn textedit\n"
  },
  {
    "path": "xmake/core/ui/view.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        view.lua\n--\n\n-- load modules\nlocal table  = require(\"base/table\")\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal point  = require(\"ui/point\")\nlocal object = require(\"ui/object\")\nlocal canvas = require(\"ui/canvas\")\nlocal curses = require(\"ui/curses\")\nlocal action = require(\"ui/action\")\n\n-- define module\nlocal view = view or object()\n\n-- new view instance\nfunction view:new(name, bounds, ...)\n\n    -- create instance\n    self = self()\n\n    -- init view\n    self:init(name, bounds, ...)\n\n    -- done\n    return self\nend\n\n-- init view\nfunction view:init(name, bounds)\n\n    -- check\n    assert(name and type(bounds) == 'table')\n\n    -- init type\n    self._TYPE           = \"view\"\n\n    -- init state\n    local state          = object()\n    state.visible        = true      -- view visibility\n    state.cursor_visible = false     -- cursor visibility\n    state.block_cursor   = false     -- block cursor\n    state.selected       = false     -- is selected?\n    state.focused        = false     -- is focused?\n    state.redraw         = true      -- need redraw\n    state.on_refresh     = true      -- need refresh\n    state.on_resize      = true      -- need resize\n    self._STATE          = state\n\n    -- init options\n    local options        = object()\n    options.selectable   = false     -- true if window can be selected\n    options.mouseable    = false     -- false by default\n    self._OPTIONS        = options\n\n    -- init attributes\n    self._ATTRS          = object()\n\n    -- init actions\n    self._ACTIONS        = object()\n\n    -- init extras\n    self._EXTRAS         = object()\n\n    -- init name\n    self._NAME           = name\n\n    -- init cursor\n    self._CURSOR         = point{0, 0}\n\n    -- init bounds and window\n    self:bounds_set(bounds)\nend\n\n-- exit view\nfunction view:exit()\n\n    -- close window\n    if self._WINDOW then\n        self._WINDOW:close()\n        self._WINDOW = nil\n    end\nend\n\n-- get view name\nfunction view:name()\n    return self._NAME\nend\n\n-- get view bounds\nfunction view:bounds()\n    return self._BOUNDS\nend\n\n-- set window bounds\nfunction view:bounds_set(bounds)\n    if bounds and self:bounds() ~= bounds then\n        self._BOUNDS = bounds()\n        self:invalidate(true)\n    end\nend\n\n-- get view width\nfunction view:width()\n    return self:bounds():width()\nend\n\n-- get view height\nfunction view:height()\n    return self:bounds():height()\nend\n\n-- get view size\nfunction view:size()\n    return self:bounds():size()\nend\n\n-- get the parent view\nfunction view:parent()\n    return self._PARENT\nend\n\n-- set the parent view\nfunction view:parent_set(parent)\n    self._PARENT = parent\nend\n\n-- get the application\nfunction view:application()\n    if not self._APPLICATION then\n        local app = self\n        while app:parent() do\n            app = app:parent()\n        end\n        self._APPLICATION = app\n    end\n    return self._APPLICATION\nend\n\n-- get the view window\nfunction view:window()\n    if not self._WINDOW then\n\n        -- create window\n        self._WINDOW = curses.new_pad(self:height() > 0 and self:height() or 1, self:width() > 0 and self:width() or 1)\n        assert(self._WINDOW, \"cannot create window!\")\n\n        -- disable cursor\n        self._WINDOW:leaveok(true)\n    end\n    return self._WINDOW\nend\n\n-- get the view canvas\nfunction view:canvas()\n    if not self._CANVAS then\n        self._CANVAS = canvas:new(self, self:window())\n    end\n    return self._CANVAS\nend\n\n-- draw view\nfunction view:on_draw(transparent)\n\n    -- trace\n    log:print(\"%s: draw (transparent: %s) ..\", self, tostring(transparent))\n\n    -- draw background\n    if not transparent then\n        local background = self:background()\n        if background then\n            background = curses.color_pair(background, background)\n            self:canvas():attr(background):move(0, 0):putchar(' ', self:width() * self:height())\n        else\n            self:canvas():clear()\n        end\n    end\n\n    -- clear mark\n    self:state_set(\"redraw\", false)\n    self:_mark_refresh()\nend\n\n-- refresh view\nfunction view:on_refresh()\n\n    -- refresh to the parent view\n    local parent = self:parent()\n    if parent and self:state(\"visible\") then\n\n        -- clip bounds with the parent view\n        local bounds = self:bounds()\n        local r = bounds():intersect(rect{0, 0, parent:width(), parent:height()})\n        if not r:empty() then\n\n            -- trace\n            log:print(\"%s: refresh to %s(%d, %d, %d, %d) ..\", self, parent:name(), r.sx, r.sy, r.ex, r.ey)\n\n            -- copy this view to parent view\n            self:window():copy(parent:window(), 0, 0, r.sy, r.sx, r.ey - 1, r.ex - 1)\n        end\n    end\nend\n\n-- resize bounds of inner child views (abstract)\nfunction view:on_resize()\n\n    -- trace\n    log:print(\"%s: resize ..\", self)\n\n    -- close the previous windows first\n    if self._WINDOW then\n        self._WINDOW:close()\n        self._WINDOW = nil\n    end\n\n    -- need renew canvas\n    self._CANVAS = nil\n\n    -- clear mark\n    self:state_set(\"resize\", false)\n\n    -- do action\n    self:action_on(action.ac_on_resized)\nend\n\n-- show view?\n--\n-- .e.g\n-- v:show(false)\n-- v:show(true, {focused = true})\n--\nfunction view:show(visible, opt)\n    if self:state(\"visible\") ~= visible then\n        local parent = self:parent()\n        if parent and parent:current() == self and not visible then\n            parent:select_next(nil, true)\n        elseif parent and visible and opt and opt.focused then\n            parent:select(self)\n        end\n        self:state_set(\"visible\", visible)\n        self:invalidate()\n    end\nend\n\n-- invalidate view to redraw it\nfunction view:invalidate(bounds)\n    if bounds then\n        self:_mark_resize()\n    end\n    self:_mark_redraw()\nend\n\n-- on event (abstract)\n--\n-- @return true: done and break dispatching, false/nil: continous to dispatch to other views\n--\nfunction view:on_event(e)\nend\n\n-- get the current event\nfunction view:event()\n    return self:parent() and self:parent():event()\nend\n\n-- put an event to view\nfunction view:put_event(e)\n    return self:parent() and self:parent():put_event(e)\nend\n\n-- get type\nfunction view:type()\n    return self._TYPE\nend\n\n-- set type\nfunction view:type_set(t)\n    self._TYPE = t or \"view\"\n    return self\nend\n\n-- get state\nfunction view:state(name)\n    return self._STATE[name]\nend\n\n-- set state\nfunction view:state_set(name, enable)\n\n    -- state not changed?\n    enable = enable or false\n    if self:state(name) == enable then\n        return self\n    end\n\n    -- change state\n    self._STATE[name] = enable\n    return self\nend\n\n-- get option\nfunction view:option(name)\n    return self._OPTIONS[name]\nend\n\n-- set option\nfunction view:option_set(name, enable)\n\n    -- state not changed?\n    enable = enable or false\n    if self:option(name) == enable then\n        return\n    end\n\n    -- set option\n    self._OPTIONS[name] = enable\nend\n\n-- get attribute\nfunction view:attr(name)\n    return self._ATTRS[name]\nend\n\n-- set attribute\nfunction view:attr_set(name, value)\n    self._ATTRS[name] = value\n    self:invalidate()\n    return self\nend\n\n-- get extra data\nfunction view:extra(name)\n    return self._EXTRAS[name]\nend\n\n-- set extra data\nfunction view:extra_set(name, value)\n    self._EXTRAS[name] = value\n    return self\nend\n\n-- set action\nfunction view:action_set(name, on_action)\n    self._ACTIONS[name] = on_action\n    return self\nend\n\n-- add action\nfunction view:action_add(name, on_action)\n    self._ACTIONS[name] = table.join(table.wrap(self._ACTIONS[name]), on_action)\n    return self\nend\n\n-- do action\nfunction view:action_on(name, ...)\n    local on_action = self._ACTIONS[name]\n    if on_action then\n        if type(on_action) == \"string\" then\n            -- send command\n            if self:application() then\n                self:application():send(on_action)\n            end\n        elseif type(on_action) == \"function\" then\n            -- do action script\n            return on_action(self, ...)\n        elseif type(on_action) == \"table\" then\n            for _, on_action_val in ipairs(on_action) do\n                -- we cannot uses the return value of action for multi-actions\n                if type(on_action_val) == \"function\" then\n                    on_action_val(self, ...)\n                end\n            end\n        end\n    end\nend\n\n-- get cursor position\nfunction view:cursor()\n    return self._CURSOR\nend\n\n-- move cursor to the given position\nfunction view:cursor_move(x, y)\n    self._CURSOR = point{ self:_limit(x, 0, self:width() - 1), self:_limit(y, 0, self:height() - 1) }\n    return self\nend\n\n-- show cursor?\nfunction view:cursor_show(visible)\n    if self:state(\"cursor_visible\") ~= visible then\n        self:state_set(\"cursor_visible\", visible)\n    end\n    return self\nend\n\n-- get background\nfunction view:background()\n    local background = self:attr(\"background\")\n    if not background and self:parent() then\n        background = self:parent():background()\n    end\n    return background\nend\n\n-- set background, .e.g background_set(\"blue\")\nfunction view:background_set(color)\n    return self:attr_set(\"background\", color)\nend\n\n-- limit value range\nfunction view:_limit(value, minval, maxval)\n    return math.min(maxval, math.max(value, minval))\nend\n\n-- need resize view\nfunction view:_mark_resize()\n\n    -- have been marked?\n    if self:state(\"resize\") then\n        return\n    end\n\n    -- trace\n    log:print(\"%s: mark as resize\", self)\n\n    -- need resize it\n    self:state_set(\"resize\", true)\n\n    -- @note we need to trigger on_resize() of the root view and pass it to this subview\n    if self:parent() then\n        self:parent():invalidate(true)\n    end\nend\n\n-- need redraw view\nfunction view:_mark_redraw()\n\n    -- have been marked?\n    if self:state(\"redraw\") then\n        return\n    end\n\n    -- trace\n    log:print(\"%s: mark as redraw\", self)\n\n    -- need redraw it\n    self:state_set(\"redraw\", true)\n\n    -- need redraw it's parent view if this view is invisible\n    if not self:state(\"visible\") and self:parent() then\n        self:parent():_mark_redraw()\n    end\nend\n\n-- need refresh view\nfunction view:_mark_refresh()\n\n    -- have been marked?\n    if self:state(\"refresh\") then\n        return\n    end\n\n    -- need refresh it\n    if self:state(\"visible\") then\n        self:state_set(\"refresh\", true)\n    end\n\n    -- need refresh it's parent view\n    if self:parent() then\n        self:parent():_mark_refresh()\n    end\nend\n\n-- tostring(view)\nfunction view:__tostring()\n    return string.format(\"<view(%s) %s>\", self:name(), tostring(self:bounds()))\nend\n\n-- return module\nreturn view\n"
  },
  {
    "path": "xmake/core/ui/window.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        window.lua\n--\n\n-- load modules\nlocal log    = require(\"ui/log\")\nlocal rect   = require(\"ui/rect\")\nlocal view   = require(\"ui/view\")\nlocal label  = require(\"ui/label\")\nlocal panel  = require(\"ui/panel\")\nlocal event  = require(\"ui/event\")\nlocal border = require(\"ui/border\")\nlocal curses = require(\"ui/curses\")\nlocal action = require(\"ui/action\")\n\n-- define module\nlocal window = window or panel()\n\n-- init window\nfunction window:init(name, bounds, title, shadow)\n\n    -- init panel\n    panel.init(self, name, bounds)\n\n    -- check bounds\n    assert(self:width() > 4 and self:height() > 3, string.format(\"%s: too small!\", tostring(self)))\n\n    -- insert shadow\n    if shadow then\n        self._SHADOW = view:new(\"window.shadow\", rect{2, 1, self:width(), self:height()}):background_set(\"black\")\n        self:insert(self:shadow())\n        self:frame():bounds():movee(-2, -1)\n        self:frame():invalidate(true)\n    end\n\n    -- insert border\n    self:frame():insert(self:border())\n\n    -- insert title\n    if title then\n        self._TITLE = label:new(\"window.title\", rect{0, 0, #title, 1}, title)\n        self:title():textattr_set(\"blue bold\")\n        self:title():action_set(action.ac_on_text_changed, function (v)\n            if v:text() then\n                local bounds = v:bounds()\n                v:bounds():resize(#v:text(), v:height())\n                bounds:move2(math.max(0, math.floor((self:frame():width() - v:width()) / 2)), bounds.sy)\n                v:invalidate(true)\n            end\n        end)\n        self:frame():insert(self:title(), {centerx = true})\n    end\n\n    -- insert panel\n    self:frame():insert(self:panel())\n\n    -- insert frame\n    self:insert(self:frame())\nend\n\n-- get frame\nfunction window:frame()\n    if not self._FRAME then\n        self._FRAME = panel:new(\"window.frame\", rect{0, 0, self:width(), self:height()}):background_set(\"white\")\n    end\n    return self._FRAME\nend\n\n-- get panel\nfunction window:panel()\n    if not self._PANEL then\n        self._PANEL = panel:new(\"window.panel\", self:frame():bounds())\n        self._PANEL:bounds():grow(-1, -1)\n        self._PANEL:invalidate(true)\n    end\n    return self._PANEL\nend\n\n-- get title\nfunction window:title()\n    return self._TITLE\nend\n\n-- get shadow\nfunction window:shadow()\n    return self._SHADOW\nend\n\n-- get border\nfunction window:border()\n    if not self._BORDER then\n        self._BORDER = border:new(\"window.border\", self:frame():bounds())\n    end\n    return self._BORDER\nend\n\n-- on event\nfunction window:on_event(e)\n\n    -- select panel?\n    if e.type == event.ev_keyboard then\n        if e.key_name == \"Tab\" then\n            return self:panel():select_next()\n        end\n    end\nend\n\n-- on resize\nfunction window:on_resize()\n    self:frame():bounds_set(rect{0, 0, self:width(), self:height()})\n    if self:shadow() then\n        self:shadow():bounds_set(rect{2, 1, self:width(), self:height()})\n        self:frame():bounds():movee(-2, -1)\n    end\n    self:border():bounds_set(self:frame():bounds())\n    if self:title() then\n        self:frame():center(self:title(), {centerx = true})\n    end\n    self:panel():bounds_set(self:frame():bounds())\n    self:panel():bounds():grow(-1, -1)\n    panel.on_resize(self)\nend\n\n-- return module\nreturn window\n"
  },
  {
    "path": "xmake/includes/check/check_bigendian.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2024, Xmake Open Source Community.\n--\n-- @author      CarbeneHu\n-- @file        check_bigendian.lua\n--\n\n-- check compiler byteorder(big-endian/little-endian) add to macro definition\n--\n-- from https://github.com/xmake-io/xmake/issues/4843\n--\n-- e.g.\n--\n-- check_bigendian(\"IS_BIG_ENDIAN\") => IS_BIG_ENDIAN=0\n--\n-- configvar_check_bigendian(\"IS_BIG_ENDIAN\") => #define IS_BIG_ENDIAN 0\n--\n\nlocal check_bigendian_template = [[\n#include <inttypes.h>\n/* A 16 bit integer is required. */\ntypedef uint16_t byteorder_int16_t;\n\n/* On a little endian machine, these 16bit ints will give \"THIS IS LITTLE ENDIAN.\"\n    On a big endian machine the characters will be exchanged pairwise. */\nconst byteorder_int16_t info_little[] =  {0x4854, 0x5349, 0x4920, 0x2053, 0x494c, 0x5454, 0x454c, 0x4520, 0x444e, 0x4149, 0x2e4e, 0x0000};\n\n/* on a big endian machine, these 16bit ints will give \"THIS IS BIG ENDIAN.\"\n    On a little endian machine the characters will be exchanged pairwise. */\nconst byteorder_int16_t info_big[] =     {0x5448, 0x4953, 0x2049, 0x5320, 0x4249, 0x4720, 0x454e, 0x4449, 0x414e, 0x2e2e, 0x0000};\n\nint main(int argc, char *argv[])\n{\n  int require = 0;\n  require += info_little[argc];\n  require += info_big[argc];\n  (void)argv;\n  return require;\n}]]\n\nlocal function _byteorder_binary_match(content)\n  local match = content:match(\"THIS IS BIG ENDIAN\")\n  return match and true or false\nend\n\nfunction check_bigendian(definition, opt)\n  opt = opt or {}\n  local optname = opt.name or (\"__\" .. definition)\n  interp_save_scope()\n  option(optname)\n      set_showmenu(false)\n      add_cxxsnippets(definition, check_bigendian_template, {binary_match = _byteorder_binary_match})\n      if opt.links then\n          add_links(opt.links)\n      end\n      if opt.includes then\n          add_cxxincludes(opt.includes)\n      end\n      if opt.languages then\n          set_languages(opt.languages)\n      end\n      if opt.cflags then\n          add_cflags(opt.cflags)\n      end\n      if opt.cxflags then\n          add_cxflags(opt.cxflags)\n      end\n      if opt.defines then\n          add_defines(opt.defines)\n      end\n      if opt.warnings then\n          set_warnings(opt.warnings)\n      end\n      after_check(function(option)\n          option:add(\"defines\", definition .. \"=\" .. (option:value() and 1 or 0))\n      end)\n  option_end()\n  interp_restore_scope()\n  add_options(optname)\nend\n\nfunction configvar_check_bigendian(definition, opt)\n  opt = opt or {}\n  local optname = opt.name or (\"__\" .. definition)\n  local defname, defval = table.unpack(definition:split('='))\n  interp_save_scope()\n  option(optname)\n      set_showmenu(false)\n      add_cxxsnippets(definition, check_bigendian_template, {binary_match = _byteorder_binary_match})\n      if opt.default == nil then\n          set_configvar(defname, defval or 1, { quote = false })\n      end\n      if opt.links then\n          add_links(opt.links)\n      end\n      if opt.includes then\n          add_cxxincludes(opt.includes)\n      end\n      if opt.languages then\n          set_languages(opt.languages)\n      end\n      if opt.cflags then\n          add_cflags(opt.cflags)\n      end\n      if opt.cxflags then\n          add_cxflags(opt.cxflags)\n      end\n      if opt.defines then\n          add_defines(opt.defines)\n      end\n      if opt.warnings then\n          set_warnings(opt.warnings)\n      end\n      after_check(function(option)\n          option:set(\"configvar\", defname, option:value() and 1 or 0, { quote = false })\n      end)\n  option_end()\n  interp_restore_scope()\n  if opt.default == nil then\n      add_options(optname)\n  else\n      set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, { quote = false })\n  end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cflags.lua\n--\n\n-- check c flags and add macro definition\n--\n-- e.g.\n--\n-- check_cflags(\"HAS_SSE2\", \"-msse2\")\n-- check_cflags(\"HAS_SSE2\", {\"-msse\", \"-msse2\"})\n--\nfunction check_cflags(definition, flags, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_defines(definition)\n        on_check(function (option)\n            import(\"core.tool.compiler\")\n            if compiler.has_flags(\"c\", flags, opt) then\n                option:enable(true)\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c flags and add macro definition to the configuration flags\n--\n-- e.g.\n--\n-- configvar_check_cflags(\"HAS_SSE2\", \"-msse2\")\n-- configvar_check_cflags(\"HAS_SSE2\", {\"-msse\", \"-msse2\"})\n-- configvar_check_cflags(\"HAS_SSE2\", \"-msse2\", {default = 0})\n-- configvar_check_cflags(\"SSE_STR=2\", \"-msse2\")\n-- configvar_check_cflags(\"SSE=2\", \"-msse2\", {quote = false})\n--\nfunction configvar_check_cflags(definition, flags, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        on_check(function (option)\n            import(\"core.tool.compiler\")\n            if compiler.has_flags(\"c\", flags, opt) then\n                option:enable(true)\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cfuncs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cfuncs.lua\n--\n\n-- check c funcs and add macro definition\n--\n-- the function syntax\n--  - sigsetjmp\n--  - sigsetjmp((void*)0, 0)\n--  - sigsetjmp{sigsetjmp((void*)0, 0);}\n--  - sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- e.g.\n--\n-- check_cfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"signal.h\", \"setjmp.h\"}, links = {}})\n-- check_cfuncs(\"HAS_SETJMP\", {\"setjmp\", \"sigsetjmp{sigsetjmp((void*)0, 0);}\"})\n--\nfunction check_cfuncs(definition, funcs, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cfuncs(funcs)\n        add_defines(definition)\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c funcs and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_cfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"signal.h\", \"setjmp.h\"}, links = {}})\n-- configvar_check_cfuncs(\"HAS_SETJMP\", {\"setjmp\", \"sigsetjmp{sigsetjmp((void*)0, 0);}\"})\n-- configvar_check_cfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"setjmp.h\"}, default = 0})\n-- configvar_check_cfuncs(\"CUSTOM_SETJMP=setjmp\", \"setjmp\", {includes = {\"setjmp.h\"}, default = \"\", quote = false})\n--\nfunction configvar_check_cfuncs(definition, funcs, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cfuncs(funcs)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cincludes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cincludes.lua\n--\n\n-- check include c files and add macro definition\n--\n-- e.g.\n--\n-- check_cincludes(\"HAS_STRING_H\", \"string.h\")\n-- check_cincludes(\"HAS_STRING_AND_STDIO_H\", {\"string.h\", \"stdio.h\"})\n--\nfunction check_cincludes(definition, includes, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cincludes(includes)\n        if opt.includedirs then\n            add_includedirs(opt.includedirs)\n        end\n        add_defines(definition)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check include c files and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_cincludes(\"HAS_STRING_H\", \"string.h\")\n-- configvar_check_cincludes(\"HAS_STRING_H\", \"string.h\", {default = 0})\n-- configvar_check_cincludes(\"HAS_STRING_AND_STDIO_H\", {\"string.h\", \"stdio.h\"})\n--\nfunction configvar_check_cincludes(definition, includes, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cincludes(includes)\n        if opt.includedirs then\n            add_includedirs(opt.includedirs)\n        end\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_csnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_csnippets.lua\n--\n\n-- check c snippets and add macro definition\n--\n-- e.g.\n--\n-- check_csnippets(\"HAS_STATIC_ASSERT\", \"_Static_assert(1, \\\"\\\");\", {includes = \"stdio.h\"})\n-- check_csnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true})\n-- check_csnippets(\"PTR_SIZE\", 'printf(\"%d\", sizeof(void*)); return 0;', {output = true, number = true})\n--\nfunction check_csnippets(definition, snippets, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_csnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})\n        if not opt.output then\n            add_defines(definition)\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        if opt.output then\n            after_check(function (option)\n                if option:value() then\n                    if opt.number then\n                        option:add(\"defines\", definition .. \"=\" .. tonumber(option:value()))\n                    elseif opt.quote == false then\n                        option:add(\"defines\", definition .. \"=\" .. option:value())\n                    else\n                        option:add(\"defines\", definition .. \"=\\\"\" .. option:value() .. \"\\\"\")\n                    end\n                end\n            end)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c snippets and add macro definition to the configuration snippets\n--\n-- e.g.\n--\n-- configvar_check_csnippets(\"HAS_STATIC_ASSERT\", \"_Static_assert(1, \\\"\\\");\", {includes = \"stdio.h\"})\n-- configvar_check_csnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true})\n-- configvar_check_csnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true, default = 0})\n-- configvar_check_csnippets(\"LONG_SIZE=8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true, quote = false})\n-- configvar_check_csnippets(\"PTR_SIZE\", 'printf(\"%d\", sizeof(void*)); return 0;', {output = true, number = true})\n--\nfunction configvar_check_csnippets(definition, snippets, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_csnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        if opt.output then\n            after_check(function (option)\n                if option:value() then\n                    option:set(\"configvar\", defname, opt.number and tonumber(option:value()) or option:value(), {quote = opt.quote})\n                end\n            end)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_ctypes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_ctypes.lua\n--\n\n-- check c types and add macro definition\n--\n-- e.g.\n--\n-- check_ctypes(\"HAS_WCHAR\", \"wchar_t\")\n-- check_ctypes(\"HAS_WCHAR_AND_FLOAT\", {\"wchar_t\", \"float\"})\n--\nfunction check_ctypes(definition, types, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_ctypes(types)\n        add_defines(definition)\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c types and add macro definition to the configuration types\n--\n-- e.g.\n--\n-- configvar_check_ctypes(\"HAS_WCHAR\", \"wchar_t\")\n-- configvar_check_ctypes(\"HAS_WCHAR\", \"wchar_t\", {default = 0})\n-- configvar_check_ctypes(\"CUSTOM_WCHAR=wchar_t\", \"wchar_t\", {default = \"\", quote = false})\n-- configvar_check_ctypes(\"HAS_WCHAR_AND_FLOAT\", {\"wchar_t\", \"float\"})\n--\nfunction configvar_check_ctypes(definition, types, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_ctypes(types)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.includes then\n            add_cincludes(opt.includes)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cxxflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxflags.lua\n--\n\n-- check c++ flags and add macro definition\n--\n-- e.g.\n--\n-- check_cxxflags(\"HAS_SSE2\", \"-msse2\")\n-- check_cxxflags(\"HAS_SSE2\", {\"-msse\", \"-msse2\"})\n--\nfunction check_cxxflags(definition, flags, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_defines(definition)\n        on_check(function (option)\n            import(\"core.tool.compiler\")\n            if compiler.has_flags(\"cxx\", flags, opt) then\n                option:enable(true)\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c++ flags and add macro definition to the configuration flags\n--\n-- e.g.\n--\n-- configvar_check_cxxflags(\"HAS_SSE2\", \"-msse2\")\n-- configvar_check_cxxflags(\"HAS_SSE2\", {\"-msse\", \"-msse2\"})\n-- configvar_check_cxxflags(\"HAS_SSE2\", \"-msse2\", {default = 0})\n-- configvar_check_cxxflags(\"SSE_STR=2\", \"-msse2\")\n-- configvar_check_cxxflags(\"SSE=2\", \"-msse2\", {quote = false})\n--\nfunction configvar_check_cxxflags(definition, flags, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        on_check(function (option)\n            import(\"core.tool.compiler\")\n            if compiler.has_flags(\"cxx\", flags, opt) then\n                option:enable(true)\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cxxfuncs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxfuncs.lua\n--\n\n-- check c++ funcs and add macro definition\n--\n-- the function syntax\n--  - sigsetjmp\n--  - sigsetjmp((void*)0, 0)\n--  - sigsetjmp{sigsetjmp((void*)0, 0);}\n--  - sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- e.g.\n--\n-- check_cxxfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"signal.h\", \"setjmp.h\"}, links = {}})\n-- check_cxxfuncs(\"HAS_SETJMP\", {\"setjmp\", \"sigsetjmp{sigsetjmp((void*)0, 0);}\"})\n--\nfunction check_cxxfuncs(definition, funcs, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxfuncs(funcs)\n        add_defines(definition)\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c++ funcs and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_cxxfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"signal.h\", \"setjmp.h\"}, links = {}})\n-- configvar_check_cxxfuncs(\"HAS_SETJMP\", {\"setjmp\", \"sigsetjmp{sigsetjmp((void*)0, 0);}\"})\n-- configvar_check_cxxfuncs(\"HAS_SETJMP\", \"setjmp\", {includes = {\"setjmp.h\"}, default = 0})\n-- configvar_check_cxxfuncs(\"CUSTOM_SETJMP=setjmp\", \"setjmp\", {includes = {\"setjmp.h\"}, default = \"\", quote = false})\n--\nfunction configvar_check_cxxfuncs(definition, funcs, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxfuncs(funcs)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cxxincludes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxincludes.lua\n--\n\n-- check include c++ files and add macro definition\n--\n-- e.g.\n--\n-- check_cxxincludes(\"HAS_STRING_H\", \"string.h\")\n-- check_cxxincludes(\"HAS_STRING_AND_STDIO_H\", {\"string.h\", \"stdio.h\"})\n--\nfunction check_cxxincludes(definition, includes, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxincludes(includes)\n        add_defines(definition)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check include c++ files and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_cxxincludes(\"HAS_STRING_H\", \"string.h\")\n-- configvar_check_cxxincludes(\"HAS_STRING_H\", \"string.h\", {default = 0})\n-- configvar_check_cxxincludes(\"HAS_STRING_AND_STDIO_H\", {\"string.h\", \"stdio.h\"})\n--\nfunction configvar_check_cxxincludes(definition, includes, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxincludes(includes)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cxxsnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxsnippets.lua\n--\n\n-- check c++ snippets and add macro definition\n--\n-- e.g.\n--\n-- check_cxxsnippets(\"HAS_STATIC_ASSERT\", \"static_assert(1, \\\"\\\");\")\n-- check_csnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true})\n-- check_csnippets(\"PTR_SIZE\", 'printf(\"%d\", sizeof(void*)); return 0;', {output = true, number = true})\n--\nfunction check_cxxsnippets(definition, snippets, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxsnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})\n        if not opt.output then\n            add_defines(definition)\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        if opt.output then\n            after_check(function (option)\n                if option:value() then\n                    if opt.number then\n                        option:add(\"defines\", definition .. \"=\" .. tonumber(option:value()))\n                    elseif opt.quote == false then\n                        option:add(\"defines\", definition .. \"=\" .. option:value())\n                    else\n                        option:add(\"defines\", definition .. \"=\\\"\" .. option:value() .. \"\\\"\")\n                    end\n                end\n            end)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c++ snippets and add macro definition to the configuration snippets\n--\n-- e.g.\n--\n-- configvar_check_cxxsnippets(\"HAS_STATIC_ASSERT\", \"static_assert(1, \\\"\\\");\")\n-- configvar_check_cxxsnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true})\n-- configvar_check_cxxsnippets(\"HAS_LONG_8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true, default = 0})\n-- configvar_check_cxxsnippets(\"LONG_SIZE=8\", \"return (sizeof(long) == 8)? 0 : -1;\", {tryrun = true, quote = false})\n-- configvar_check_cxxsnippets(\"PTR_SIZE\", 'printf(\"%d\", sizeof(void*)); return 0;', {output = true, number = true})\n--\nfunction configvar_check_cxxsnippets(definition, snippets, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxsnippets(definition, snippets, {tryrun = opt.tryrun, output = opt.output})\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        if opt.output then\n            after_check(function (option)\n                if option:value() then\n                    option:set(\"configvar\", defname, opt.number and tonumber(option:value()) or option:value(), {quote = opt.quote})\n                end\n            end)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_cxxtypes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxtypes.lua\n--\n\n-- check c++ types and add macro definition\n--\n-- e.g.\n--\n-- check_cxxtypes(\"HAS_WCHAR\", \"wchar_t\")\n-- check_cxxtypes(\"HAS_WCHAR_AND_FLOAT\", {\"wchar_t\", \"float\"})\n--\nfunction check_cxxtypes(definition, types, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxtypes(types)\n        add_defines(definition)\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check c++ types and add macro definition to the configuration types\n--\n-- e.g.\n--\n-- configvar_check_cxxtypes(\"HAS_WCHAR\", \"wchar_t\")\n-- configvar_check_cxxtypes(\"HAS_WCHAR\", \"wchar_t\", {default = 0})\n-- configvar_check_cxxtypes(\"CUSTOM_WCHAR=wchar_t\", \"wchar_t\", {default = \"\", quote = false})\n-- configvar_check_cxxtypes(\"HAS_WCHAR_AND_FLOAT\", {\"wchar_t\", \"float\"})\n--\nfunction configvar_check_cxxtypes(definition, types, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxtypes(types)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_features.lua\n--\n\n-- check features and add macro definition\n--\n-- e.g.\n--\n-- check_features(\"HAS_CONSTEXPR\", \"cxx_constexpr\")\n-- check_features(\"HAS_CONSEXPR_AND_STATIC_ASSERT\", {\"cxx_constexpr\", \"c_static_assert\"}, {cxflags = \"\", languages = \"c++11\"})\n--\nfunction check_features(definition, features, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_features(features)\n        add_defines(definition)\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check features and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_features(\"HAS_CONSTEXPR\", \"cxx_constexpr\")\n-- configvar_check_features(\"HAS_CONSTEXPR\", \"cxx_constexpr\", {default = 0})\n-- configvar_check_features(\"HAS_CONSEXPR_AND_STATIC_ASSERT\", {\"cxx_constexpr\", \"c_static_assert\"}, {languages = \"c++11\"})\n--\nfunction configvar_check_features(definition, features, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_features(features)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_links.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_links.lua\n--\n\n-- check links and add macro definition\n--\n-- e.g.\n--\n-- check_links(\"HAS_PTHREAD\", \"pthread\")\n-- check_links(\"HAS_PTHREAD\", {\"pthread\", \"m\", \"dl\"})\n--\nfunction check_links(definition, links, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_links(links)\n        add_defines(definition)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check links and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_links(\"HAS_PTHREAD\", \"pthread\")\n-- configvar_check_links(\"HAS_PTHREAD\", \"pthread\", {default = 0})\n-- configvar_check_links(\"HAS_PTHREAD\", {\"pthread\", \"m\", \"dl\"})\n--\nfunction configvar_check_links(definition, links, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_links(links)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_macros.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_macros.lua\n--\n\n-- check macros and add macro definition\n--\n-- e.g.\n--\n--  check_macros(\"HAS_GCC\", \"__GNUC__\")\n--  check_macros(\"NO_GCC\", \"__GNUC__\", {defined = false})\n--  check_macros(\"HAS_CXX20\", \"__cplusplus >= 202002L\", {languages = \"c++20\"})\n--\nfunction check_macros(definition, macros, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local snippets = {}\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        for _, macro in ipairs(macros) do\n            if macro:find(' ', 1, true) then\n                table.insert(snippets, ([[\n                #if %s\n                #else\n                    #error %s is not satisfied!\n                #endif\n                ]]):format(macro, macro))\n            else\n                table.insert(snippets, ([[\n                #if%s %s\n                #else\n                    #error %s is not defined!\n                #endif\n                ]]):format(opt.defined ~= false and \"def\" or \"ndef\", macro, macro))\n            end\n        end\n        if opt.languages and opt.languages:startswith(\"c++\") then\n            add_cxxsnippets(definition, table.concat(snippets, \"\\n\"))\n        else\n            add_csnippets(definition, table.concat(snippets, \"\\n\"))\n        end\n        add_defines(definition)\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.languages and opt.languages:startswith(\"c++\") then\n            add_cxxincludes(opt.includes)\n        else\n            add_cincludes(opt.includes)\n        end\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check macros and add macro definition to the configuration files\n--\n-- e.g.\n--  configvar_check_macros(\"HAS_GCC\", \"__GNUC__\")\n--  configvar_check_macros(\"NO_GCC\", \"__GNUC__\", {defined = false})\n--  configvar_check_macros(\"HAS_CXX20\", \"__cplusplus >= 202002L\", {languages = \"c++20\"})\nfunction configvar_check_macros(definition, macros, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    local snippets = {}\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        for _, macro in ipairs(macros) do\n            if macro:find(' ', 1, true) then\n                table.insert(snippets, ([[\n                #if %s\n                #else\n                    #error %s is not satisfied!\n                #endif\n                ]]):format(macro, macro))\n            else\n                table.insert(snippets, ([[\n                #if%s %s\n                #else\n                    #error %s is not defined!\n                #endif\n                ]]):format(opt.defined ~= false and \"def\" or \"ndef\", macro, macro))\n            end\n        end\n        if opt.languages and opt.languages:startswith(\"c++\") then\n            add_cxxsnippets(definition, table.concat(snippets, \"\\n\"))\n        else\n            add_csnippets(definition, table.concat(snippets, \"\\n\"))\n        end\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.cxxflags then\n            add_cxxflags(opt.cxxflags)\n        end\n        if opt.includes then\n            if opt.languages and opt.languages:startswith(\"c++\") then\n                add_cxxincludes(opt.includes)\n            else\n                add_cincludes(opt.includes)\n            end\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/check_sizeof.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2023, Xmake Open Source Community.\n--\n-- @author      zeromake\n-- @file        check_sizeof.lua\n--\n\n-- check c sizeof(type) add to macro definition support cross compile\n--\n-- from https://github.com/xmake-io/xmake/issues/4345\n--\n-- e.g.\n--\n-- check_sizeof(\"SIZEOF_LONG\", \"long\") => SIZEOF_LONG=4\n--\n-- configvar_check_sizeof(\"SIZEOF_LONG\", \"long\") => #define SIZEOF_LONG 4\n--\nlocal binary_match_pattern = 'INFO:size%[(%d+)%]'\n\nlocal check_sizeof_template = [[\n#define SIZE (sizeof(${TYPE}))\nstatic char info_size[] =  {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',\n  ('0' + ((SIZE / 10000)%10)),\n  ('0' + ((SIZE / 1000)%10)),\n  ('0' + ((SIZE / 100)%10)),\n  ('0' + ((SIZE / 10)%10)),\n  ('0' +  (SIZE    % 10)),\n  ']',\n  '\\0'};\n\nint main(int argc, char *argv[]) {\n  int require = 0;\n  require += info_size[argc];\n  (void)argv;\n  return require;\n}]]\n\nfunction _binary_match(content)\n    local match = content:match(binary_match_pattern)\n    if match then\n        return match:ltrim(\"0\")\n    end\nend\n\nfunction check_sizeof(definition, typename, opt)\n    opt = opt or {}\n    if opt.number == nil then\n        opt.number = true\n    end\n    local optname = opt.name or (\"__\" .. definition)\n    local snippet = opt.snippet or \"\"\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxsnippets(definition, check_sizeof_template:gsub('${TYPE}', typename), {binary_match = _binary_match})\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        after_check(function (option)\n            if option:value() then\n                if opt.number then\n                    option:add(\"defines\", definition .. \"=\" .. tonumber(option:value()))\n                elseif opt.quote == false then\n                    option:add(\"defines\", definition .. \"=\" .. option:value())\n                else\n                    option:add(\"defines\", definition .. \"=\\\"\" .. option:value() .. \"\\\"\")\n                end\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n\nfunction configvar_check_sizeof(definition, typename, opt)\n    opt = opt or {}\n    if opt.number == nil then\n        opt.number = true\n    end\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_cxxsnippets(definition, check_sizeof_template:gsub('${TYPE}', typename), {binary_match = _binary_match})\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n        if opt.links then\n            add_links(opt.links)\n        end\n        if opt.includes then\n            add_cxxincludes(opt.includes)\n        end\n        if opt.languages then\n            set_languages(opt.languages)\n        end\n        if opt.cflags then\n            add_cflags(opt.cflags)\n        end\n        if opt.cxflags then\n            add_cxflags(opt.cxflags)\n        end\n        if opt.defines then\n            add_defines(opt.defines)\n        end\n        if opt.warnings then\n            set_warnings(opt.warnings)\n        end\n        after_check(function (option)\n            if option:value() then\n                option:set(\"configvar\", defname, opt.number and tonumber(option:value()) or option:value(), {quote = opt.quote})\n            end\n        end)\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = true})\n    end\nend\n\n"
  },
  {
    "path": "xmake/includes/check/check_syslinks.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_syslinks.lua\n--\n\n-- check links and add macro definition\n--\n-- e.g.\n--\n-- check_syslinks(\"HAS_PTHREAD\", \"pthread\")\n-- check_syslinks(\"HAS_PTHREAD\", {\"pthread\", \"m\", \"dl\"})\n--\nfunction check_syslinks(definition, links, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_syslinks(links)\n        add_defines(definition)\n    option_end()\n    interp_restore_scope()\n    add_options(optname)\nend\n\n-- check links and add macro definition to the configuration files\n--\n-- e.g.\n--\n-- configvar_check_syslinks(\"HAS_PTHREAD\", \"pthread\")\n-- configvar_check_syslinks(\"HAS_PTHREAD\", \"pthread\", {default = 0})\n-- configvar_check_syslinks(\"HAS_PTHREAD\", {\"pthread\", \"m\", \"dl\"})\n--\nfunction configvar_check_syslinks(definition, links, opt)\n    opt = opt or {}\n    local optname = opt.name or (\"__\" .. definition)\n    local defname, defval = table.unpack(definition:split('='))\n    interp_save_scope()\n    option(optname)\n        set_showmenu(false)\n        add_syslinks(links)\n        if opt.default == nil then\n            set_configvar(defname, defval or 1, {quote = opt.quote})\n        end\n    option_end()\n    interp_restore_scope()\n    if opt.default == nil then\n        add_options(optname)\n    else\n        set_configvar(defname, has_config(optname) and (defval or 1) or opt.default, {quote = opt.quote})\n    end\nend\n"
  },
  {
    "path": "xmake/includes/check/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nincludes(\"@builtin/check/check_cflags.lua\")\nincludes(\"@builtin/check/check_cfuncs.lua\")\nincludes(\"@builtin/check/check_cincludes.lua\")\nincludes(\"@builtin/check/check_csnippets.lua\")\nincludes(\"@builtin/check/check_ctypes.lua\")\nincludes(\"@builtin/check/check_cxxflags.lua\")\nincludes(\"@builtin/check/check_cxxfuncs.lua\")\nincludes(\"@builtin/check/check_cxxincludes.lua\")\nincludes(\"@builtin/check/check_cxxsnippets.lua\")\nincludes(\"@builtin/check/check_cxxtypes.lua\")\nincludes(\"@builtin/check/check_features.lua\")\nincludes(\"@builtin/check/check_links.lua\")\nincludes(\"@builtin/check/check_macros.lua\")\nincludes(\"@builtin/check/check_syslinks.lua\")\nincludes(\"@builtin/check/check_sizeof.lua\")\nincludes(\"@builtin/check/check_bigendian.lua\")\n"
  },
  {
    "path": "xmake/includes/qt/qt_add_static_plugins.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        qt_add_static_plugins.lua\n--\n\n-- add static plugins for qt rules\n--\n-- e.g.\n--\n-- @code\n-- includes(\"qt_add_static_plugins.lua\")\n-- target(\"test\")\n--     add_rules(\"qt.quickapp\")\n--     add_files(\"src/*.c\")\n--     qt_add_static_plugins(\"QSvgPlugin\", {linkdirs = \"plugins/imageformats\", links = {\"qsvg\"}})\n-- @endcode\n--\nfunction qt_add_static_plugins(plugin, opt)\n    opt = opt or {}\n    add_values(\"qt.plugins\", plugin)\n    if opt.links then\n        add_values(\"qt.links\", table.unpack(table.wrap(opt.links)))\n    end\n    if opt.linkdirs then\n        add_values(\"qt.linkdirs\", table.unpack(table.wrap(opt.linkdirs)))\n    end\nend\n\n"
  },
  {
    "path": "xmake/includes/qt/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nincludes(\"@builtin/qt/qt_add_static_plugins.lua\")\n"
  },
  {
    "path": "xmake/includes/xpack/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- Define xpack interfaces to generate installation package. e.g. nsis, deb, rpm, ...\n--\n-- And we can call `xmake pack` plugin to pack them.\n--\n-- @see https://github.com/xmake-io/xmake/issues/1433\n--\n\n-- define apis\nlocal apis = {\n    values = {\n        -- set package version,  we will also get it from project/target\n        \"xpack.set_version\",\n        -- set package homepage url\n        \"xpack.set_homepage\",\n        -- set package title\n        \"xpack.set_title\",\n        -- set author\n        \"xpack.set_author\",\n        -- set maintainer,\n        \"xpack.set_maintainer\",\n        -- set package description\n        \"xpack.set_description\",\n        -- set input kind, e.g. binary, source\n        \"xpack.set_inputkind\",\n        -- set package copyright\n        \"xpack.set_copyright\",\n        -- set company name\n        \"xpack.set_company\",\n        -- set package formats, e.g. nsis, deb, srpm, rpm, targz, zip, srctargz, srczip, runself, ...\n        -- we can also add custom formats\n        \"xpack.set_formats\",\n        -- set the base name of the output file\n        \"xpack.set_basename\",\n        -- set the extension of the output file\n        \"xpack.set_extension\",\n        -- add targets to be packaged\n        \"xpack.add_targets\",\n        -- add package components\n        \"xpack.add_components\",\n        -- set installed binary directory, e.g. bin\n        \"xpack.set_bindir\",\n        -- set installed library directory, e.g. lib\n        \"xpack.set_libdir\",\n        -- set installed include directory, e.g. include\n        \"xpack.set_includedir\",\n        -- set prefix directory, e.g. prefixdir/bin, prefixdir/lib ..\n        \"xpack.set_prefixdir\",\n        -- add build requires for source inputkind\n        \"xpack.add_buildrequires\",\n        -- set nsis display icon\n        \"xpack.set_nsis_displayicon\",\n        -- set package component title\n        \"xpack_component.set_title\",\n        -- set package component description\n        \"xpack_component.set_description\",\n        -- enable/disable this component by default\n        \"xpack_component.set_default\"\n    },\n    paths = {\n        -- set the spec file path, support the custom variable pattern, e.g. set_specfile(\"\", {pattern = \"%${([^\\n]-)}\"})\n        \"xpack.set_specfile\",\n        -- set icon file path, e.g foo.ico\n        \"xpack.set_iconfile\",\n        -- set package license\n        \"xpack.set_license\",\n        -- set package license file, we will also get them from target\n        \"xpack.set_licensefile\",\n        -- add source files\n        \"xpack.add_sourcefiles\",\n        -- add install files, we will also get them from target\n        \"xpack.add_installfiles\",\n        -- add source files for component\n        \"xpack_component.add_sourcefiles\",\n        -- add install files for component\n        \"xpack_component.add_installfiles\"\n    },\n    script = {\n        -- add custom load script\n        \"xpack.on_load\",\n        -- add custom package script before packing package\n        \"xpack.before_package\",\n        -- rewrite custom package script\n        \"xpack.on_package\",\n        -- add custom package script after packing package\n        \"xpack.after_package\",\n        -- add custom build commands script before building, it's only for source inputkind\n        \"xpack.before_buildcmd\",\n        -- add custom build commands script, it's only for source inputkind\n        \"xpack.on_buildcmd\",\n        -- add custom build commands script after building, it's only for source inputkind\n        \"xpack.after_buildcmd\",\n        -- add custom commands script before installing\n        \"xpack.before_installcmd\",\n        -- add custom commands script before uninstalling\n        \"xpack.before_uninstallcmd\",\n        -- rewrite custom install commands script, we will also get it from target/rules\n        \"xpack.on_installcmd\",\n        -- rewrite custom uninstall commands script, we will also get it from target/rules\n        \"xpack.on_uninstallcmd\",\n        -- add custom commands script after installing\n        \"xpack.after_installcmd\",\n        -- add custom commands script after uninstalling\n        \"xpack.after_uninstallcmd\",\n        -- add custom load script in component\n        \"xpack_component.on_load\",\n        -- add custom commands script before installing in component\n        \"xpack_component.before_installcmd\",\n        -- add custom commands script before uninstalling in component\n        \"xpack_component.before_uninstallcmd\",\n        -- rewrite custom install commands script in component, we will also get it from target/rules\n        \"xpack_component.on_installcmd\",\n        -- rewrite custom uninstall commands script in component, we will also get it from target/rules\n        \"xpack_component.on_uninstallcmd\",\n        -- add custom commands script after installing in component\n        \"xpack_component.after_installcmd\",\n        -- add custom commands script after uninstalling in component\n        \"xpack_component.after_uninstallcmd\"\n    },\n    keyvalues = {\n        -- set the spec variable\n        \"xpack.set_specvar\"\n    }\n}\ninterp_add_scopeapis(apis)\n"
  },
  {
    "path": "xmake/includes/xrepo/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- add envs for `xrepo env`\n-- @see https://github.com/xmake-io/xmake/issues/5580\n--\n-- @code\n-- includes(\"@builtin/xrepo\")\n--\n-- xrepo_addenvs(function (package)\n--     package:addenv(\"FOO\", \"FOO\")\n-- end)\n--\n-- xrepo_addenvs({BAR = \"BAR\"})\n-- @endcode\n--\nfunction xrepo_addenvs(envs)\n    local packagename = \"__xrepo_addenvs_\" .. hash.strhash32(string.serialize(envs))\n    package(packagename)\n        on_load(function (package)\n            if type(envs) == \"function\" then\n                envs(package)\n            elseif type(envs) == \"table\" then\n                for k, v in pairs(envs) do\n                    package:addenv(k, v)\n                end\n            end\n        end)\n        on_fetch(function (package, opt)\n            return {}\n        end)\n    package_end()\n    add_requires(packagename)\nend\n\n-- add env for `xrepo env`\n-- @see https://github.com/xmake-io/xmake/issues/5580\n--\n-- @code\n-- includes(\"@builtin/xrepo\")\n--\n-- xrepo_addenv(\"ZOO\", ...)\n-- @endcode\n--\nfunction xrepo_addenv(name, ...)\n    local args = table.pack(...)\n    local packagename = \"__xrepo_addenv_\" .. name .. hash.strhash32(table.concat(args))\n    package(packagename)\n        on_load(function (package)\n            package:addenv(name, table.unpack(args))\n        end)\n        on_fetch(function (package, opt)\n            return {}\n        end)\n    package_end()\n    add_requires(packagename)\nend\n"
  },
  {
    "path": "xmake/languages/asm/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_asflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_asflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_asflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\"\n    ,   \"package.add_sysincludedirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_asflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    }\n    apis.groups = {\n        -- target.add_xxx\n        \"target.add_linkorders\"\n    ,   \"target.add_linkgroups\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_headerfiles\"\n    ,   \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/asm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"asm\")\n    add_rules(\"asm\")\n    set_sourcekinds {as = {\".s\", \".S\", \".asm\"}}\n    set_sourceflags {as = \"asflags\"}\n    set_targetkinds {binary = \"ld\", static = \"ar\", shared = \"sh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {as = \"as\"}\n    set_mixingkinds(\"as\")\n\n    on_load(\"load\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.runtimes\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"       }\n                ,   {nil, \"as\",         \"kv\", nil,          \"The Assembler\"                   }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"         }\n                ,   {nil, \"ar\",         \"kv\", nil,          \"The Static Library Linker\"       }\n                ,   {nil, \"ld\",         \"kv\", nil,          \"The Linker\"                      }\n                ,   {nil, \"sh\",         \"kv\", nil,          \"The Shared Library Linker\"       }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\" }\n                ,   {nil, \"asflags\",    \"kv\", nil,          \"The Assembler Flags\"             }\n\n                ,   {category = \"Cross Complation Configuration/Linker Flags Configuration\"   }\n                ,   {nil, \"ldflags\",    \"kv\", nil,          \"The Binary Linker Flags\"         }\n                ,   {nil, \"arflags\",    \"kv\", nil,          \"The Static Library Linker Flags\" }\n                ,   {nil, \"shflags\",    \"kv\", nil,          \"The Shared Library Linker Flags\" }\n\n                ,   {category = \"Cross Complation Configuration/Builin Flags Configuration\"   }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"              }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"       }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"     }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"  }\n                }\n            }\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/languages/c/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find int main(int argc, char** argv) {}\n    if sourcecode:find(\"%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/c/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- get apis\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_cflags\"\n    ,   \"target.add_cxflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n    ,   \"target.add_forceincludes\"\n        -- option.add_xxx\n    ,   \"option.add_cincludes\"\n    ,   \"option.add_cfuncs\"\n    ,   \"option.add_ctypes\"\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_cflags\"\n    ,   \"option.add_cxflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n    ,   \"option.add_frameworks\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_cflags\"\n    ,   \"package.add_cxflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n    ,   \"package.add_frameworks\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\" --@note we need not uses paths for package, see https://github.com/xmake-io/xmake/issues/717\n    ,   \"package.add_sysincludedirs\"\n    ,   \"package.add_frameworkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_cflags\"\n    ,   \"toolchain.add_cxflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    ,   \"toolchain.add_frameworks\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    ,   \"toolchain.add_frameworkdirs\"\n    }\n    apis.groups = {\n        -- target.add_xxx\n        \"target.add_linkorders\"\n    ,   \"target.add_linkgroups\"\n        -- package.add_xxx\n    ,   \"package.add_linkorders\"\n    ,   \"package.add_linkgroups\"\n    }\n    apis.paths = {\n        -- target.set_xxx\n        \"target.set_pcheader\"\n        -- target.add_xxx\n    ,   \"target.add_headerfiles\"\n    ,   \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n    ,   \"target.add_frameworkdirs\"\n    ,   \"target.add_embeddirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    ,   \"option.add_frameworkdirs\"\n    }\n    apis.dictionary = {\n        -- option.add_xxx\n        \"option.add_csnippets\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/c/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"c\")\n    add_rules(\"c\")\n    set_sourcekinds {cc = \".c\"}\n    set_sourceflags {cc = {\"cflags\", \"cxflags\"}}\n    set_targetkinds {binary = \"ld\", static = \"ar\", shared = \"sh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {c = \"cc\"}\n    set_mixingkinds(\"cc\", \"cxx\", \"as\", \"mrc\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.runtimes\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.fpmodels\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.pcheader\"\n        ,   \"target.includedirs\"\n        ,   \"target.embeddirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"target.exceptions\"\n        ,   \"target.encodings\"\n        ,   \"target.forceincludes\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.linkgroups\" -- we must move it before target.links, because we need sort correct order for package and its deps\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"                             }\n                ,   {nil, \"cc\",            \"kv\", nil,          \"The C Compiler\"                                     }\n                ,   {nil, \"cpp\",           \"kv\", nil,          \"The C/C++ Preprocessor\"                             }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"                               }\n                ,   {nil, \"ld\",            \"kv\", nil,          \"The Linker\"                                         }\n                ,   {nil, \"ar\",            \"kv\", nil,          \"The Static Library Linker\"                          }\n                ,   {nil, \"sh\",            \"kv\", nil,          \"The Shared Library Linker\"                          }\n                ,   {nil, \"ranlib\",        \"kv\", nil,          \"The Static Library Index Generator\"                 }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\"                       }\n                ,   {nil, \"cflags\",        \"kv\", nil,          \"The C Compiler Flags\"                               }\n                ,   {nil, \"cxflags\",       \"kv\", nil,          \"The C/C++ compiler Flags\"                           }\n\n                ,   {category = \"Cross Complation Configuration/Linker Flags Configuration\"                         }\n                ,   {nil, \"ldflags\",       \"kv\", nil,          \"The Binary Linker Flags\"                            }\n                ,   {nil, \"arflags\",       \"kv\", nil,          \"The Static Library Linker Flags\"                    }\n                ,   {nil, \"shflags\",       \"kv\", nil,          \"The Shared Library Linker Flags\"                    }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"                        }\n                ,   {nil, \"links\",         \"kv\", nil,          \"The Link Libraries\"                                 }\n                ,   {nil, \"syslinks\",      \"kv\", nil,          \"The System Link Libraries\"                          }\n                ,   {nil, \"linkdirs\",      \"kv\", nil,          \"The Link Search Directories\"                        }\n                ,   {nil, \"includedirs\",   \"kv\", nil,          \"The Include Search Directories\"                     }\n                ,   {nil, \"frameworks\",    \"kv\", nil,          \"The Frameworks\"                                     }\n                ,   {nil, \"frameworkdirs\", \"kv\", nil,          \"The Frameworks Search Directories\"                  }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/languages/c++/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find int main(int argc, char** argv) {}\n    if sourcecode:find(\"%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/c++/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- get apis\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_cxflags\"\n    ,   \"target.add_cxxflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n    ,   \"target.add_forceincludes\"\n        -- option.add_xxx\n    ,   \"option.add_cxxincludes\"\n    ,   \"option.add_cxxfuncs\"\n    ,   \"option.add_cxxtypes\"\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_cxflags\"\n    ,   \"option.add_cxxflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n    ,   \"option.add_frameworks\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_cxflags\"\n    ,   \"package.add_cxxflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n    ,   \"package.add_frameworks\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\" --@note we need not uses paths for package, see https://github.com/xmake-io/xmake/issues/717\n    ,   \"package.add_sysincludedirs\"\n    ,   \"package.add_frameworkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_cxflags\"\n    ,   \"toolchain.add_cxxflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    ,   \"toolchain.add_frameworks\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    ,   \"toolchain.add_frameworkdirs\"\n    }\n    apis.groups = {\n        -- target.add_xxx\n        \"target.add_linkorders\"\n    ,   \"target.add_linkgroups\"\n        -- package.add_xxx\n    ,   \"package.add_linkorders\"\n    ,   \"package.add_linkgroups\"\n    }\n    apis.paths = {\n        -- target.set_xxx\n        \"target.set_pcxxheader\"\n        -- target.add_xxx\n    ,   \"target.add_headerfiles\"\n    ,   \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n    ,   \"target.add_frameworkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    ,   \"option.add_frameworkdirs\"\n    }\n    apis.dictionary = {\n        -- option.add_xxx\n        \"option.add_cxxsnippets\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/c++/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"c++\")\n    add_rules(\"c++\")\n    set_sourcekinds {cxx = {\".cpp\", \".cc\", \".cxx\", \".c++\", \".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\"}}\n    set_sourceflags {cxx = {\"cxxflags\", \"cxflags\"}}\n    set_targetkinds {binary = \"ld\", static = \"ar\", shared = \"sh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {cxx = \"cxx\"}\n    set_mixingkinds(\"cc\", \"cxx\", \"as\", \"mrc\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.runtimes\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.fpmodels\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.pcxxheader\"\n        ,   \"target.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"target.exceptions\"\n        ,   \"target.encodings\"\n        ,   \"target.forceincludes\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.linkgroups\" -- we must move it before target.links, because we need sort correct order for package and its deps\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"                             }\n                ,   {nil, \"cxx\",           \"kv\", nil,          \"The C++ Compiler\"                                   }\n                ,   {nil, \"cpp\",           \"kv\", nil,          \"The C/C++ Preprocessor\"                             }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"                               }\n                ,   {nil, \"ld\",            \"kv\", nil,          \"The Linker\"                                         }\n                ,   {nil, \"ar\",            \"kv\", nil,          \"The Static Library Linker\"                          }\n                ,   {nil, \"sh\",            \"kv\", nil,          \"The Shared Library Linker\"                          }\n                ,   {nil, \"ranlib\",        \"kv\", nil,          \"The Static Library Index Generator\"                 }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\"                       }\n                ,   {nil, \"cxflags\",       \"kv\", nil,          \"The C/C++ compiler Flags\"                           }\n                ,   {nil, \"cxxflags\",      \"kv\", nil,          \"The C++ Compiler Flags\"                             }\n\n                ,   {category = \"Cross Complation Configuration/Linker Flags Configuration\"                         }\n                ,   {nil, \"ldflags\",       \"kv\", nil,          \"The Binary Linker Flags\"                            }\n                ,   {nil, \"arflags\",       \"kv\", nil,          \"The Static Library Linker Flags\"                    }\n                ,   {nil, \"shflags\",       \"kv\", nil,          \"The Shared Library Linker Flags\"                    }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"                        }\n                ,   {nil, \"links\",         \"kv\", nil,          \"The Link Libraries\"                                 }\n                ,   {nil, \"syslinks\",      \"kv\", nil,          \"The System Link Libraries\"                          }\n                ,   {nil, \"linkdirs\",      \"kv\", nil,          \"The Link Search Directories\"                        }\n                ,   {nil, \"includedirs\",   \"kv\", nil,          \"The Include Search Directories\"                     }\n                ,   {nil, \"frameworks\",    \"kv\", nil,          \"The Frameworks\"                                     }\n                ,   {nil, \"frameworkdirs\", \"kv\", nil,          \"The Frameworks Search Directories\"                  }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/languages/csharp/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JassJam\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_csflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_shflags\"\n        -- option.add_xxx\n    ,   \"option.add_csflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_shflags\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_csflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_shflags\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n"
  },
  {
    "path": "xmake/languages/csharp/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JassJam\n-- @file        xmake.lua\n--\n\nlanguage(\"csharp\")\n    add_rules(\"csharp\")\n    set_sourcekinds {cs = \".cs\"}\n    set_sourceflags {cs = \"csflags\"}\n    set_targetkinds {binary = \"cs\", shared = \"cs\"}\n    set_targetflags {binary = \"ldflags\", shared = \"shflags\"}\n    set_langkinds {csharp = \"cs\"}\n    set_mixingkinds(\"cs\")\n\n    on_load(\"load\")\n\n    set_nameflags {\n        object = {\n            \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"       }\n                ,   {nil, \"cs\",         \"kv\", nil,          \"The C# Compiler\"                 }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"         }\n                ,   {nil, \"ld\",         \"kv\", nil,          \"The Linker\"                      }\n                ,   {nil, \"sh\",         \"kv\", nil,          \"The Shared Library Linker\"       }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\" }\n                ,   {nil, \"csflags\",    \"kv\", nil,          \"The C# Compiler Flags\"           }\n\n                ,   {category = \"Cross Complation Configuration/Linker Flags Configuration\"   }\n                ,   {nil, \"ldflags\",    \"kv\", nil,          \"The Binary Linker Flags\"         }\n                ,   {nil, \"shflags\",    \"kv\", nil,          \"The Shared Library Linker Flags\" }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/cuda/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find int main(int argc, char** argv) {}\n    if sourcecode:find(\"%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/cuda/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_cugencodes\"\n    ,   \"target.add_cuflags\"\n    ,   \"target.add_culdflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_cugencodes\"\n    ,   \"option.add_cuflags\"\n    ,   \"option.add_culdflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_cuflags\"\n    ,   \"package.add_culdflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n    ,   \"package.add_rpathdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_cugencodes\"\n    ,   \"toolchain.add_cuflags\"\n    ,   \"toolchain.add_culdflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    ,   \"toolchain.add_rpathdirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/cuda/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"cuda\")\n    add_rules(\"cuda\")\n    set_sourcekinds {cu = \".cu\"}\n    set_sourceflags {cu = \"cuflags\"}\n    set_targetkinds {gpucode = \"culd\", binary = \"ld\", static = \"ar\", shared = \"sh\"}\n    set_targetflags {gpucode = \"culdflags\", binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds {cu = \"cu\"}\n    set_mixingkinds(\"cu\", \"cc\", \"cxx\", \"as\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.runtimes\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.includedirs\"\n        ,   \"target.languages\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    ,   gpucode = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"         }\n                ,   {nil, \"cu\",         \"kv\", nil,          \"The Cuda Compiler\"                 }\n                ,   {nil, \"cu-ccbin\",   \"kv\", nil,          \"The Cuda Host C++ Compiler\"        }\n                ,   {nil, \"culd\",      \"kv\", nil,          \"The Cuda Linker\"                   }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\"   }\n                ,   {nil, \"cuflags\",    \"kv\", nil,          \"The Cuda Compiler Flags\"           }\n                ,   {nil, \"culdflags\",  \"kv\", nil,          \"The Cuda Linker Flags\"             }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"    }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"                }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"         }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"       }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"    }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/dlang/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"/%+.-%+/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find func main() {\n    if sourcecode:find(\"void%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/dlang/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_dcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_dcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_frameworks\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_dcflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_frameworks\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\"\n    ,   \"package.add_sysincludedirs\"\n    ,   \"package.add_frameworkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_dcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_frameworks\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    ,   \"toolchain.add_frameworkdirs\"\n    }\n    apis.groups = {\n        -- target.add_xxx\n        \"target.add_linkorders\"\n    ,   \"target.add_linkgroups\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/dlang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"dlang\")\n    add_rules(\"dlang\")\n    set_sourcekinds {dc = \".d\"}\n    set_sourceflags {dc = \"dcflags\"}\n    set_targetkinds {binary = \"dcld\", static = \"dcar\", shared = \"dcsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {d = \"dc\"}\n    set_mixingkinds(\"dc\", \"cc\", \"cxx\", \"as\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.includedirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.includedirs\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"         }\n                ,   {nil, \"dc\",         \"kv\", nil,          \"The Dlang Compiler\"                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"           }\n                ,   {nil, \"dcld\",      \"kv\", nil,          \"The Dlang Linker\"                  }\n                ,   {nil, \"dcar\",      \"kv\", nil,          \"The Dlang Static Library Archiver\" }\n                ,   {nil, \"dcsh\",      \"kv\", nil,          \"The Dlang Shared Library Linker\"   }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"    }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"                }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"         }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"       }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"    }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/fortran/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"!.-\\n\", \"\\n\")\n\n    -- find 'program xxx'\n    if sourcecode:find(\"program%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/fortran/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_fcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_fcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_fcflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\"\n    ,   \"package.add_sysincludedirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_fcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/fortran/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"fortran\")\n    add_rules(\"fortran\")\n    set_sourcekinds {fc = {\".f03\", \".f90\", \".f95\", \".for\", \".f\"}}\n    set_sourceflags {fc = \"fcflags\"}\n    set_targetkinds {binary = \"fcld\", static = \"ar\", shared = \"fcsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {fortran = \"fc\"}\n    set_mixingkinds(\"fc\", \"cc\", \"cxx\", \"as\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.includedirs\"\n        ,   \"toolchain.includedirs\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"          }\n                ,   {nil, \"fc\",         \"kv\", nil,          \"The Fortran Compiler\"               }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"            }\n                ,   {nil, \"fcld\",       \"kv\", nil,          \"The Fortran Linker\"                 }\n                ,   {nil, \"fcsh\",       \"kv\", nil,          \"The Fortran Shared Library Linker\"  }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"     }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"                 }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"          }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"        }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"     }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/golang/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find func main() {\n    if sourcecode:find(\"func%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/golang/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_gcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_gcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_gcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/golang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"golang\")\n    add_rules(\"go\")\n    set_sourcekinds {gc = \".go\"}\n    set_sourceflags {gc = \"gcflags\"}\n    set_targetkinds {binary = \"gcld\", static = \"gcar\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\"}\n    set_langkinds   {go = \"gc\"}\n    set_mixingkinds(\"gc\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.includedirs\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"        }\n                ,   {nil, \"go\",         \"kv\", nil,          \"The Golang Compiler\"              }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"          }\n                ,   {nil, \"gcld\",      \"kv\", nil,          \"The Golang Linker\"                }\n                ,   {nil, \"go-ar\",      \"kv\", nil,          \"The Golang Static Library Linker\" }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"   }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"               }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"        }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"      }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"   }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/kotlin/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find fun main() {\n    if sourcecode:find(\"fun%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/kotlin/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_kcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_links\"\n        -- option.add_xxx\n    ,   \"option.add_kcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_links\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_kcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_links\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/kotlin/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"kotlin\")\n    add_rules(\"kotlin-native\")\n    set_sourcekinds {kc = \".kt\"}\n    set_sourceflags {kc = \"kcflags\"}\n    set_targetkinds {binary = \"kcld\", static = \"kcar\", shared = \"kcsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds {kotlin = \"kc\"}\n    set_mixingkinds(\"kc\", \"cc\", \"cxx\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"       }\n                ,   {nil, \"kc\",         \"kv\", nil,         \"The Rust Compiler\"                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"         }\n                ,   {nil, \"kcld\",      \"kv\", nil,          \"The Rust Linker\"                  }\n                ,   {nil, \"kcar\",      \"kv\", nil,          \"The Rust Static Library Archiver\" }\n                ,   {nil, \"kcsh\",      \"kv\", nil,          \"The Rust Shared Library Linker\"   }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"  }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,         \"The Link Search Directories\"      }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/msrc/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_mrcflags\"\n        -- option.add_xxx\n    ,   \"option.add_mrcflags\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_mrcflags\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n        -- option.add_xxx\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/msrc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"msrc\")\n    add_rules(\"win.sdk.resource\")\n    set_sourcekinds {mrc = {\".rc\", \".rc2\"}}\n    set_sourceflags {mrc = \"mrcflags\"}\n    set_langkinds   {msrc = \"mrc\"}\n    set_mixingkinds(\"mrc\")\n\n    on_load(\"load\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.includedirs\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"       }\n                ,   {nil, \"mrc\",        \"kv\", nil,          \"The Microsoft Resource Compiler\" }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\" }\n                ,   {nil, \"mrcflags\",   \"kv\", nil,          \"The Microsoft Resource Flags\"    }\n\n                ,   {category = \"Cross Complation Configuration/Builti Flags Configuration\"   }\n                ,   {nil, \"includedirs\",\"kv\", nil,          \"The Include Search Directories\"  }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/nim/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_ncflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_ncflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_rpathdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_ncflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_rpathdirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/nim/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"nim\")\n    add_rules(\"nim\")\n    set_sourcekinds {nc = \".nim\"}\n    set_sourceflags {nc = \"ncflags\"}\n    set_targetkinds {binary = \"ncld\", static = \"ncar\", shared = \"ncsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds {nim = \"nc\"}\n    set_mixingkinds(\"nc\")\n\n    on_load(\"load\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.includedirs\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.includedirs\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"target.includedirs\"\n        ,   \"target.sysincludedirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"target.includedirs\"\n        ,   \"target.sysincludedirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.includedirs\"\n        ,   \"target.sysincludedirs\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"      }\n                ,   {nil, \"nc\",         \"kv\", nil,         \"The Nim Compiler\"                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"        }\n                ,   {nil, \"ncld\",      \"kv\", nil,          \"The Nim Linker\"                  }\n                ,   {nil, \"ncar\",      \"kv\", nil,          \"The Nim Static Library Archiver\" }\n                ,   {nil, \"ncsh\",      \"kv\", nil,          \"The Nim Shared Library Linker\"   }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\" }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,         \"The Link Search Directories\"     }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/objc++/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find int main(int argc, char** argv) {}\n    if sourcecode:find(\"%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/objc++/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_mflags\"\n    ,   \"target.add_mxflags\"\n    ,   \"target.add_mxxflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n    ,   \"target.add_forceincludes\"\n        -- option.add_xxx\n    ,   \"option.add_cincludes\"\n    ,   \"option.add_cxxincludes\"\n    ,   \"option.add_cfuncs\"\n    ,   \"option.add_cxxfuncs\"\n    ,   \"option.add_ctypes\"\n    ,   \"option.add_cxxtypes\"\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_mflags\"\n    ,   \"option.add_mxflags\"\n    ,   \"option.add_mxxflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n    ,   \"option.add_frameworks\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_mflags\"\n    ,   \"package.add_mxflags\"\n    ,   \"package.add_mxxflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n    ,   \"package.add_frameworks\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\" --@note we don't need to use paths for package, see https://github.com/xmake-io/xmake/issues/717\n    ,   \"package.add_sysincludedirs\"\n    ,   \"package.add_frameworkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_mflags\"\n    ,   \"toolchain.add_mxflags\"\n    ,   \"toolchain.add_mxxflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    ,   \"toolchain.add_frameworks\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_sysincludedirs\"\n    ,   \"toolchain.add_frameworkdirs\"\n    }\n    apis.groups = {\n        -- target.add_xxx\n        \"target.add_linkorders\"\n    ,   \"target.add_linkgroups\"\n    }\n    apis.paths = {\n        -- target.set_xxx\n        \"target.set_pmheader\"\n    ,   \"target.set_pmxxheader\"\n        -- target.add_xxx\n    ,   \"target.add_headerfiles\"\n    ,   \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n    ,   \"target.add_frameworkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    ,   \"option.add_frameworkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/objc++/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define language\nlanguage(\"objc++\")\n\n    -- set source file kinds\n    set_sourcekinds {mm = \".m\", mxx = \".mm\"}\n\n    -- set source file flags\n    set_sourceflags {mm = {\"mflags\", \"mxflags\"}, mxx = {\"mxxflags\", \"mxflags\"}}\n\n    -- set target kinds\n    set_targetkinds {binary = \"ld\", static = \"ar\", shared = \"sh\"}\n\n    -- set target flags\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n\n    -- set language kinds\n    set_langkinds {m = \"mm\", mxx = \"mxx\"}\n\n    -- set mixing kinds\n    set_mixingkinds(\"mm\", \"mxx\", \"cc\", \"cxx\", \"as\")\n\n    -- add rules\n    add_rules(\"objc++\")\n\n    -- on load\n    on_load(\"load\")\n\n    -- on check_main\n    on_check_main(\"check_main\")\n\n    -- set name flags\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.runtimes\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.pmheader\"\n        ,   \"target.pmxxheader\"\n        ,   \"target.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"target.exceptions\"\n        ,   \"target.encodings\"\n        ,   \"target.forceincludes\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        ,   \"target.sysincludedirs\"\n        ,   \"toolchain.sysincludedirs\"\n        }\n    ,   binary = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"target.runtimes\"\n        ,   \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"target.linkgroups\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    -- set menu\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"                             }\n                ,   {nil, \"mm\",            \"kv\", nil,          \"The Objc Compiler\"                                  }\n                ,   {nil, \"mxx\",           \"kv\", nil,          \"The Objc++ Compiler\"                                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"                               }\n                ,   {nil, \"ld\",            \"kv\", nil,          \"The Linker\"                                         }\n                ,   {nil, \"ar\",            \"kv\", nil,          \"The Static Library Linker\"                          }\n                ,   {nil, \"sh\",            \"kv\", nil,          \"The Shared Library Linker\"                          }\n\n                ,   {category = \"Cross Complation Configuration/Compiler Flags Configuration\"                       }\n                ,   {nil, \"mflags\",        \"kv\", nil,          \"The Objc Compiler Flags\"                            }\n                ,   {nil, \"mxflags\",       \"kv\", nil,          \"The Objc/c++ Compiler Flags\"                        }\n                ,   {nil, \"mxxflags\",      \"kv\", nil,          \"The Objc++ Compiler Flags\"                          }\n\n                ,   {category = \"Cross Complation Configuration/Linker Flags Configuration\"                         }\n                ,   {nil, \"ldflags\",       \"kv\", nil,          \"The Binary Linker Flags\"                            }\n                ,   {nil, \"arflags\",       \"kv\", nil,          \"The Static Library Linker Flags\"                    }\n                ,   {nil, \"shflags\",       \"kv\", nil,          \"The Shared Library Linker Flags\"                    }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"                        }\n                ,   {nil, \"links\",         \"kv\", nil,          \"The Link Libraries\"                                 }\n                ,   {nil, \"syslinks\",      \"kv\", nil,          \"The System Link Libraries\"                          }\n                ,   {nil, \"linkdirs\",      \"kv\", nil,          \"The Link Search Directories\"                        }\n                ,   {nil, \"includedirs\",   \"kv\", nil,          \"The Include Search Directories\"                     }\n                ,   {nil, \"frameworks\",    \"kv\", nil,          \"The Frameworks\"                                     }\n                ,   {nil, \"frameworkdirs\", \"kv\", nil,          \"The Frameworks Search Directories\"                  }\n                }\n            }\n\n\n\n\n"
  },
  {
    "path": "xmake/languages/pascal/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"{%*.-%*}\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find 'program xxx'\n    if sourcecode:find(\"program%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/pascal/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_pcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n    ,   \"target.add_defines\"\n    ,   \"target.add_undefines\"\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_pcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_rpathdirs\"\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_defines\"\n    ,   \"option.add_undefines\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_pcflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n    ,   \"package.add_includedirs\"\n    ,   \"package.add_defines\"\n    ,   \"package.add_undefines\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_pcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    ,   \"toolchain.add_includedirs\"\n    ,   \"toolchain.add_defines\"\n    ,   \"toolchain.add_undefines\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n    ,   \"target.add_includedirs\"\n    ,   \"target.add_frameworkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n"
  },
  {
    "path": "xmake/languages/pascal/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"pascal\")\n    add_rules(\"pascal\")\n    set_sourcekinds {pc = {\".pas\", \".pp\", \".ppu\", \".lpr\"}}\n    set_sourceflags {pc = \"pcflags\"}\n    set_targetkinds {binary = \"pcld\", shared = \"pcsh\"}\n    set_targetflags {binary = \"ldflags\", shared = \"shflags\"}\n    set_langkinds   {pascal = \"pc\"}\n    set_mixingkinds(\"pc\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.fpmodels\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"target.exceptions\"\n        ,   \"target.encodings\"\n        ,   \"target.forceincludes\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        ,   \"toolchain.exceptions\"\n        ,   \"toolchain.languages\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"config.rpathdirs\"\n        ,   \"config.syslinks\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"config.rpathdirs\"\n        ,   \"config.syslinks\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"target.optimize:check\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"          }\n                ,   {nil, \"pc\",         \"kv\", nil,          \"The Pascal Compiler\"                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"            }\n                ,   {nil, \"pcld\",       \"kv\", nil,          \"The Pascal Linker\"                  }\n                ,   {nil, \"pcsh\",       \"kv\", nil,          \"The Pascal Shared Library Linker\"   }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"     }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"                 }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"          }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"        }\n                }\n            }\n"
  },
  {
    "path": "xmake/languages/rust/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find func main() {\n    if sourcecode:find(\"fn%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/rust/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_rcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_rcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_rpathdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_rcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_rpathdirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/rust/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"rust\")\n    add_rules(\"rust\")\n    set_sourcekinds {rc = \".rs\"}\n    set_sourceflags {rc = \"rcflags\"}\n    set_targetkinds {binary = \"rcld\", static = \"rcar\", shared = \"rcsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds {rust = \"rc\"}\n    set_mixingkinds(\"rc\", \"cc\", \"cxx\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"        }\n                ,   {nil, \"rc\",         \"kv\", nil,          \"The Rust Compiler\"                }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"          }\n                ,   {nil, \"rcld\",      \"kv\", nil,          \"The Rust Linker\"                  }\n                ,   {nil, \"rcar\",      \"kv\", nil,          \"The Rust Static Library Archiver\" }\n                ,   {nil, \"rcsh\",      \"kv\", nil,          \"The Rust Shared Library Linker\"   }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"   }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"      }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/languages/swift/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_scflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_frameworks\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_scflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_frameworks\"\n    ,   \"option.add_rpathdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_scflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_frameworks\"\n    ,   \"toolchain.add_rpathdirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_includedirs\"\n    ,   \"target.add_sysincludedirs\"\n    ,   \"target.add_linkdirs\"\n    ,   \"target.add_frameworkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_includedirs\"\n    ,   \"option.add_sysincludedirs\"\n    ,   \"option.add_linkdirs\"\n    ,   \"option.add_frameworkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/swift/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"swift\")\n    add_rules(\"swift\")\n    set_sourcekinds {sc = \".swift\"}\n    set_sourceflags {sc = \"scflags\"}\n    set_targetkinds {binary = \"scld\", static = \"scar\", shared = \"scsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"scarflags\", shared = \"shflags\"}\n    set_langkinds   {swift = \"sc\"}\n    set_mixingkinds(\"sc\", \"mm\", \"mxx\", \"cc\", \"cxx\")\n\n    on_load(\"load\")\n\n    set_nameflags {\n        object = {\n            \"config.includedirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"config.Frameworks\"\n        ,   \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        ,   \"target.languages\"\n        ,   \"target.includedirs\"\n        ,   \"target.defines\"\n        ,   \"target.undefines\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.includedirs\"\n        ,   \"toolchain.defines\"\n        ,   \"toolchain.undefines\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"toolchain.frameworks\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"config.frameworkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.frameworkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.frameworkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.frameworks\"\n        ,   \"target.frameworks\"\n        ,   \"toolchain.frameworks\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"                              }\n                ,   { nil, \"sc\",            \"kv\", nil,          \"The Swift Compiler\"                                 }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"                                }\n                ,   { nil, \"scld\",         \"kv\", nil,          \"The Swift Linker\"                                   }\n                ,   { nil, \"scsh\",         \"kv\", nil,          \"The Swift Shared Library Linker\"                    }\n                ,   { nil, \"scar\",         \"kv\", nil,          \"The Swift Static Library Archiver\"                  }\n\n                ,   { category = \"Cross Complation Configuration/Builtin Flags Configuration\"                        }\n                ,   { nil, \"links\",         \"kv\", nil,          \"The Link Libraries\"                                 }\n                ,   { nil, \"syslinks\",      \"kv\", nil,          \"The System Link Libraries\"                          }\n                ,   { nil, \"linkdirs\",      \"kv\", nil,          \"The Link Search Directories\"                        }\n                ,   { nil, \"includedirs\",   \"kv\", nil,          \"The Include Search Directories\"                     }\n                ,   { nil, \"frameworks\",    \"kv\", nil,          \"The Frameworks\"                                     }\n                ,   { nil, \"frameworkdirs\", \"kv\", nil,          \"The Frameworks Search Directories\"                  }\n                }\n            }\n\n\n\n\n"
  },
  {
    "path": "xmake/languages/zig/check_main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_main.lua\n--\n\n-- check it\nfunction main(sourcefile)\n\n    -- load source code\n    local sourcecode = io.readfile(sourcefile)\n\n    -- remove comment first\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n\n    -- find func main() {\n    if sourcecode:find(\"pub%s+fn%s+main%s*%(.-%)\") then\n        return true\n    end\n\n    -- no main function\n    return false\nend\n\n\n"
  },
  {
    "path": "xmake/languages/zig/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\nfunction _get_apis()\n    local apis = {}\n    apis.values = {\n        -- target.add_xxx\n        \"target.add_links\"\n    ,   \"target.add_syslinks\"\n    ,   \"target.add_zcflags\"\n    ,   \"target.add_ldflags\"\n    ,   \"target.add_arflags\"\n    ,   \"target.add_shflags\"\n    ,   \"target.add_rpathdirs\"  -- @note do not translate path, it's usually an absolute path or contains $ORIGIN/@loader_path\n        -- option.add_xxx\n    ,   \"option.add_links\"\n    ,   \"option.add_syslinks\"\n    ,   \"option.add_zcflags\"\n    ,   \"option.add_ldflags\"\n    ,   \"option.add_arflags\"\n    ,   \"option.add_shflags\"\n    ,   \"option.add_rpathdirs\"\n        -- package.add_xxx\n    ,   \"package.add_links\"\n    ,   \"package.add_syslinks\"\n    ,   \"package.add_zcflags\"\n    ,   \"package.add_ldflags\"\n    ,   \"package.add_arflags\"\n    ,   \"package.add_shflags\"\n    ,   \"package.add_rpathdirs\"\n    ,   \"package.add_linkdirs\"\n        -- toolchain.add_xxx\n    ,   \"toolchain.add_links\"\n    ,   \"toolchain.add_syslinks\"\n    ,   \"toolchain.add_zcflags\"\n    ,   \"toolchain.add_ldflags\"\n    ,   \"toolchain.add_arflags\"\n    ,   \"toolchain.add_shflags\"\n    ,   \"toolchain.add_rpathdirs\"\n    ,   \"toolchain.add_linkdirs\"\n    }\n    apis.paths = {\n        -- target.add_xxx\n        \"target.add_linkdirs\"\n        -- option.add_xxx\n    ,   \"option.add_linkdirs\"\n    }\n    return apis\nend\n\nfunction main()\n    return {apis = _get_apis()}\nend\n\n\n"
  },
  {
    "path": "xmake/languages/zig/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nlanguage(\"zig\")\n    add_rules(\"zig\")\n    set_sourcekinds {zc = \".zig\"}\n    set_sourceflags {zc = \"zcflags\"}\n    set_targetkinds {binary = \"zcld\", static = \"zcar\", shared = \"zcsh\"}\n    set_targetflags {binary = \"ldflags\", static = \"arflags\", shared = \"shflags\"}\n    set_langkinds   {zig = \"zc\"}\n    set_mixingkinds(\"zc\", \"cc\", \"cxx\", \"as\")\n\n    on_load(\"load\")\n    on_check_main(\"check_main\")\n\n    set_nameflags {\n        object = {\n            \"target.symbols\"\n        ,   \"target.warnings\"\n        ,   \"target.optimize:check\"\n        ,   \"target.vectorexts:check\"\n        }\n    ,   binary = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.rpathdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"toolchain.rpathdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   shared = {\n            \"config.linkdirs\"\n        ,   \"target.linkdirs\"\n        ,   \"target.strip\"\n        ,   \"target.symbols\"\n        ,   \"toolchain.linkdirs\"\n        ,   \"config.links\"\n        ,   \"target.links\"\n        ,   \"toolchain.links\"\n        ,   \"config.syslinks\"\n        ,   \"target.syslinks\"\n        ,   \"toolchain.syslinks\"\n        }\n    ,   static = {\n            \"target.strip\"\n        ,   \"target.symbols\"\n        }\n    }\n\n    set_menu {\n                config = {\n                    {category = \"Cross Complation Configuration/Compiler Configuration\"          }\n                ,   {nil, \"zc\",         \"kv\", nil,          \"The Zig Compiler\"                   }\n\n                ,   {category = \"Cross Complation Configuration/Linker Configuration\"            }\n                ,   {nil, \"zcld\",       \"kv\", nil,          \"The Zig Linker\"                     }\n                ,   {nil, \"zcar\",       \"kv\", nil,          \"The Zig Static Library Archiver\"    }\n                ,   {nil, \"zcsh\",       \"kv\", nil,          \"The Zig Shared Library Linker\"      }\n\n                ,   {category = \"Cross Complation Configuration/Builtin Flags Configuration\"     }\n                ,   {nil, \"links\",      \"kv\", nil,          \"The Link Libraries\"                 }\n                ,   {nil, \"syslinks\",   \"kv\", nil,          \"The System Link Libraries\"          }\n                ,   {nil, \"linkdirs\",   \"kv\", nil,          \"The Link Search Directories\"        }\n                }\n            }\n\n"
  },
  {
    "path": "xmake/modules/async/jobgraph.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        jobgraph.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.list\")\nimport(\"core.base.graph\")\nimport(\"core.base.hashset\")\n\n-- define module\nlocal jobqueue = jobqueue or object {_init = {\"_jobgraph\", \"_dag\"}}\nlocal jobgraph = jobgraph or object {_init = {\"_name\", \"_jobs\", \"_size\", \"_dag\", \"_groups\", \"_bridge_nodes\", \"_bridge_from\", \"_bridge_to\"}}\n\n-- attach a job to existing bridge nodes of its group (if any)\nfunction jobgraph:_attach_job_to_bridges(job, group_name)\n    local outbound = self._bridge_from[group_name]\n    local inbound = self._bridge_to[group_name]\n    if not outbound and not inbound then\n        return\n    end\n    if outbound then\n        for _, bridge in ipairs(outbound) do\n            self._dag:add_edge(job, bridge)\n        end\n    end\n    if inbound then\n        for _, bridge in ipairs(inbound) do\n            self._dag:add_edge(bridge, job)\n        end\n    end\nend\n\n-- ensure a reusable bridge node exists between two groups\nfunction jobgraph:_ensure_bridge(from_group, to_group)\n    local key = from_group .. \"->\" .. to_group\n    local bridge = self._bridge_nodes[key]\n    if bridge then\n        return bridge\n    end\n    bridge = {from_group = from_group, to_group = to_group}\n    self._bridge_nodes[key] = bridge\n    self._dag:add_vertex(bridge)\n    local from_members = self._groups[from_group] or {}\n    for _, member in ipairs(from_members) do\n        self._dag:add_edge(member, bridge)\n    end\n    local to_members = self._groups[to_group] or {}\n    for _, member in ipairs(to_members) do\n        self._dag:add_edge(bridge, member)\n    end\n    self._bridge_from[from_group] = self._bridge_from[from_group] or {}\n    table.insert(self._bridge_from[from_group], bridge)\n    self._bridge_to[to_group] = self._bridge_to[to_group] or {}\n    table.insert(self._bridge_to[to_group], bridge)\n    return bridge\nend\n\n-- remove the finished job\nfunction jobqueue:remove(job)\n    local dag = self._dag\n    dag:partial_topo_sort_remove(job)\nend\n\n-- get a free job from the job queue\nfunction jobqueue:getfree()\n    local dag = self._dag\n::continue::\n    local freejob, has_cycle = dag:partial_topo_sort_next()\n    if has_cycle then\n        local names = {}\n        local cycle = dag:find_cycle()\n        if cycle then\n            for _, job in ipairs(cycle) do\n                table.insert(names, job.name)\n            end\n            table.insert(names, names[1])\n        end\n        raise(\"%s: circular job dependency detected!\\n%s\", self._jobgraph, table.concat(names, \"\\n   -> \"))\n    end\n    -- if it's a fake job, we need to skip it and continue to get the next job\n    if freejob and not freejob.run then\n        dag:partial_topo_sort_remove(freejob)\n        goto continue\n    end\n    return freejob\nend\n\n-- add a job to the jobgraph\n--\n-- e.g.\n-- jobgraph:add(\"xxx\", function (index, total, opt)\n-- end)\n--\n-- @param name      the job name\n-- @param run       the job run command/script\n-- @param opt       the job options, e.g. {groups = {\"xxx\"}}\n--\nfunction jobgraph:add(name, run, opt)\n    opt = opt or {}\n    local dag = self._dag\n    local jobs = self._jobs\n    if not jobs[name] then\n        local job = {name = name, run = run, distcc = opt.distcc}\n        jobs[name] = job\n        dag:add_vertex(job)\n        self._size = self._size + 1\n\n        if self._current_groups or opt.groups then\n            local seen\n            local job_groups\n            local function add_group(group_name)\n                if not group_name then\n                    return\n                end\n                seen = seen or {}\n                if seen[group_name] then\n                    return\n                end\n                seen[group_name] = true\n                job_groups = job_groups or {}\n                table.insert(job_groups, group_name)\n                local groups = self._groups[group_name]\n                if not groups then\n                    groups = {}\n                    self._groups[group_name] = groups\n                end\n                table.insert(groups, job)\n                -- ensure bridges (if any) are updated for new members\n                self:_attach_job_to_bridges(job, group_name)\n            end\n            for _, group_name in ipairs(self._current_groups or {}) do\n                add_group(group_name)\n            end\n            if opt.groups then\n                for _, group_name in ipairs(opt.groups) do\n                    add_group(group_name)\n                end\n            end\n            job._groups = job_groups\n        end\n    else\n        wprint(\"job(%s): has already been added!\", name)\n    end\nend\n\n-- remove a given job\nfunction jobgraph:remove(name)\n    local dag = self._dag\n    local jobs = self._jobs\n    local job = jobs[name]\n    if job then\n        assert(self._size > 0)\n        jobs[name] = nil\n        dag:remove_vertex(job)\n        if job._groups then\n            for _, group_name in ipairs(job._groups) do\n                local members = self._groups[group_name]\n                if members then\n                    table.remove_if(members, function (_, item) return item == job end)\n                    if #members == 0 then\n                        self._groups[group_name] = nil\n                    end\n                end\n            end\n        end\n        self._size = self._size - 1\n    end\nend\n\n-- has the given job or group?\nfunction jobgraph:has(name)\n    return (self._jobs[name] or self._groups[name]) ~= nil\nend\n\n-- enter group to add jobs\n--\n-- e.g.\n-- jobgraph:group(\"foo\", function ()\n--     jobgraph:add(\"job1\", function (index, total, opt)\n--         TODO\n--     end)\n--     jobgraph:add(\"job2\", function (index, total, opt)\n--         TODO\n--     end)\n-- end)\nfunction jobgraph:group(name, callback)\n    local current_groups = self._current_groups\n    if current_groups == nil then\n        current_groups = {}\n        self._current_groups = current_groups\n    end\n    table.insert(current_groups, name)\n    callback()\n    table.remove(current_groups)\nend\n\n-- add job orders, e.g. add_orders(a, b, c, ...): a -> b -> c, ...\n--\n-- and it supports nil, e.g add_orders(\"foo\", nil, \"bar\", ...)\n-- and it also supports to add orders list, e.g. add_orders(orders)\n--\nfunction jobgraph:add_orders(...)\n    local prev\n    local prev_is_group\n    local prev_name\n    local dag = self._dag\n    local jobs = self._jobs\n    local groups = self._groups\n    local orders = table.pack(...)\n    local count = orders.n\n    if count == 1 and type(orders[1]) == \"table\" then\n        orders = orders[1]\n        count = #orders\n    end\n    for i = 1, count do\n        local name = orders[i]\n        if name then\n            local curr_is_group = false\n            local curr = jobs[name]\n            if not curr then\n                curr = groups[name]\n                curr_is_group = true\n            end\n            assert(curr, \"job(%s) not found in jobgraph(%s)\", name, self)\n            if prev then\n                if prev_is_group and curr_is_group then\n                    -- we use (and reuse) a bridge job as a node to bridge the two groups.\n                    self:_ensure_bridge(prev_name, name)\n                elseif curr_is_group then\n                    for _, job in ipairs(curr) do\n                        dag:add_edge(prev, job)\n                    end\n                elseif prev_is_group then\n                    for _, job in ipairs(prev) do\n                        dag:add_edge(job, curr)\n                    end\n                else\n                    dag:add_edge(prev, curr)\n                end\n            end\n            prev = curr\n            prev_is_group = curr_is_group\n            prev_name = name\n        end\n    end\nend\n\n-- build a job queue\nfunction jobgraph:build()\n    local dag = self._dag\n    dag:partial_topo_sort_reset()\n    return jobqueue {self, dag}\nend\n\n-- get jobs\nfunction jobgraph:jobs()\n    return self._jobs\nend\n\n-- get jobgraph name\nfunction jobgraph:name()\n    return self._name\nend\n\n-- get job size\nfunction jobgraph:size()\n    return self._size\nend\n\n-- is empty?\nfunction jobgraph:empty()\n    return self:size() == 0\nend\n\n-- dump jobgraph\nfunction jobgraph:dump()\n    print(\"================================ %s ================================\", self)\n    for _, node in ipairs(self._dag:vertices()) do\n        debug.setmetatable(node, {__tostring = function (v)\n            if v.from_group and v.to_group then\n                return string.format(\"${dim}bridge<%s, %s>${clear}\", v.from_group, v.to_group)\n            end\n            return string.format(\"${color.dump.string_quote}%s${clear}\", v.name)\n        end})\n    end\n    self._dag:dump()\n\n    print(\"\")\n    print(\"groups:\")\n    for name, jobs in pairs(self._groups) do\n        print(\"  group(%s):\", name)\n        for _, job in ipairs(jobs) do\n            cprint(\"    %s\", job)\n        end\n    end\n    print(\"\")\nend\n\n-- tostring\nfunction jobgraph:__tostring()\n    return string.format(\"<jobgraph:%s/%d>\", self:name() or \"anonymous\", self:size())\nend\n\n-- new a jobgraph\nfunction new(name)\n    return jobgraph {name, {}, 0, graph.new(true), {}, {}, {}, {}}\nend\n"
  },
  {
    "path": "xmake/modules/async/runjobs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        runjobs.lua\n--\n\n-- imports\nimport(\"core.base.scheduler\")\nimport(\"utils.progress\")\nimport(\"utils.waiting_indicator\")\n\n-- print back characters\nfunction _print_backchars(backnum)\n    if backnum > 0 then\n        local str = ('\\b'):rep(backnum) .. (' '):rep(backnum) .. ('\\b'):rep(backnum)\n        if #str > 0 then\n            printf(str)\n        end\n    end\nend\n\n-- init waiting indicator\nfunction _init_waiting_indicator(state, opt)\n    opt = opt or {}\n\n    -- init waiting indicator helper\n    -- we need to hide wait characters if is not a tty\n    local waiting_indicator_opt = opt.waiting_indicator\n\n    -- compatibility: support deprecated opt.progress parameter\n    if opt.progress ~= nil and waiting_indicator_opt == nil then\n        waiting_indicator_opt = opt.progress\n        wprint(\"opt.progress is deprecated in runjobs, use opt.waiting_indicator instead\")\n    end\n\n    state.show_waiting_indicator = io.isatty() and (waiting_indicator_opt or type(waiting_indicator_opt) == \"table\")\n    state.backnum = 0\n    if state.show_waiting_indicator then\n        local indicator_opt = nil\n        if type(waiting_indicator_opt) == \"table\" then\n            indicator_opt = waiting_indicator_opt\n        end\n        state.waiting_indicator_helper = waiting_indicator.new(nil, indicator_opt)\n    end\nend\n\n-- init progress\nfunction _init_progress(state, opt)\n    opt = opt or {}\n\n    -- init progress wrapper\n    state.progress_finished_count = 0\n    state.progress_factor = opt.progress_factor or 1.0\n    local progress_wrapper = {}\n    local progress_wrapper_data = {}\n    progress_wrapper.current = function ()\n        return state.progress_finished_count\n    end\n    progress_wrapper.total = function ()\n        return state.total\n    end\n    progress_wrapper.percent = function ()\n        local total = state.total\n        if total and total > 0 then\n            return math.floor((state.progress_finished_count * state.progress_factor * 100) / total)\n        else\n            return 0\n        end\n    end\n    progress_wrapper.set = function (_, key, value)\n        local running = scheduler.co_running()\n        if running then\n            local co_data = progress_wrapper_data[running]\n            if not co_data then\n                co_data = {}\n                progress_wrapper_data[running] = co_data\n            end\n            co_data[key] = value\n        end\n    end\n    progress_wrapper.get = function (_, key)\n        local running = scheduler.co_running()\n        if running then\n            local co_data = progress_wrapper_data[running]\n            if co_data then\n                return co_data[key]\n            end\n        end\n    end\n    debug.setmetatable(progress_wrapper, {\n        __tostring = function ()\n            return string.format(\"%d%%\", progress_wrapper.percent())\n        end\n    })\n    state.progress_wrapper = progress_wrapper\n\nend\n\n-- start timer (on_timer callback)\nfunction _start_timer(state, name, opt)\n    if opt.on_timer then\n        state.on_timer = opt.on_timer\n        state.group_timer = state.group_name .. \"/timer\"\n        -- create semaphore for timer loop to wait with timeout for quick exit\n        state.timer_semaphore = scheduler.co_semaphore(state.group_name .. \"/timer\", 0)\n        scheduler.co_group_begin(state.group_timer, function (co_group)\n            scheduler.co_start_withopt({name = name .. \"/timer\", isolate = opt.isolate}, _timer_loop, state)\n        end)\n    end\nend\n\n-- start waiting indicator timer\nfunction _start_waiting_indicator_timer(state, name, opt)\n    if state.show_waiting_indicator then\n        state.group_waiting_indicator_timer = state.group_name .. \"/waiting_indicator\"\n        -- create semaphore for waiting indicator loop to wait with timeout for quick exit\n        state.waiting_indicator_semaphore = scheduler.co_semaphore(state.group_name .. \"/waiting_indicator\", 0)\n        scheduler.co_group_begin(state.group_waiting_indicator_timer, function (co_group)\n            scheduler.co_start_withopt({name = name .. \"/waiting_indicator\", isolate = opt.isolate}, _waiting_indicator_loop, state)\n        end)\n    end\nend\n\n-- start progress refresh timer for multirow progress\nfunction _start_progress_refresh_timer(state, name, opt)\n    if opt.progress_refresh and progress.is_multirow() then\n        state.group_progress_refresh_timer = state.group_name .. \"/progress_refresh\"\n        state.all_tasks_started = false\n        -- create semaphore for refresh loop\n        state.progress_refresh_semaphore = scheduler.co_semaphore(state.group_name .. \"/progress_refresh\", 0)\n        -- start progress refresh loop\n        scheduler.co_group_begin(state.group_progress_refresh_timer, function (co_group)\n            scheduler.co_start_withopt({name = name .. \"/progress_refresh\", isolate = opt.isolate}, _progress_refresh_loop, state)\n        end)\n    end\nend\n\n-- start all timers\nfunction _start_timers(state, name, opt)\n    _start_timer(state, name, opt)\n    _start_waiting_indicator_timer(state, name, opt)\n    _start_progress_refresh_timer(state, name, opt)\nend\n\n-- stop all timers and notify them to exit\nfunction _stop_timers(state)\n    -- signal all timer loops to exit quickly\n    if state.timer_semaphore then\n        state.timer_semaphore:post(1)\n    end\n    if state.waiting_indicator_semaphore then\n        state.waiting_indicator_semaphore:post(1)\n    end\n    if state.progress_refresh_semaphore then\n        state.progress_refresh_semaphore:post(1)\n    end\nend\n\n-- wait all timer jobs exited\nfunction _wait_timers(state)\n    if state.group_timer then\n        scheduler.co_group_wait(state.group_timer)\n    end\n    if state.group_waiting_indicator_timer then\n        scheduler.co_group_wait(state.group_waiting_indicator_timer)\n    end\n    if state.group_progress_refresh_timer then\n        scheduler.co_group_wait(state.group_progress_refresh_timer)\n    end\nend\n\n-- exit waiting indicator\nfunction _exit_waiting_indicator(state)\n    if state.show_waiting_indicator then\n        _print_backchars(state.backnum)\n        state.waiting_indicator_helper:stop()\n    end\nend\n\n-- exit progress\nfunction _exit_progress(state)\n    progress.show_abort()\nend\n\n-- isolate environments\nfunction _isolate_environments(state, opt)\n    local co_running = scheduler.co_running()\n    if co_running and opt.isolate then\n        local is_isolated = co_running:is_isolated()\n        co_running:isolate(true)\n        state.isolated_running = co_running\n        state.is_isolated = is_isolated\n    end\nend\n\n-- restore isolated environments\nfunction _restore_isolated_environments(state, opt)\n    if state.isolated_running and opt.isolate and state.is_isolated ~= nil then\n        state.isolated_running:isolate(state.is_isolated)\n    end\nend\n\n-- run jobs and wait for completion\nfunction _run_jobs(state, name, opt)\n    local distcc = opt.distcc\n    state.abort = false\n    state.abort_errors = nil\n    state.finished_count = 0\n    state.curdir = opt.curdir\n    state.waiting_count = 0\n    state.distcc_waiting_count = 0\n    scheduler.co_group_begin(state.group_name, function (co_group)\n        state.semaphore = scheduler.co_semaphore(state.group_name, 0)\n        if distcc then\n            state.distcc_semaphore = scheduler.co_semaphore(state.group_name .. \"/distcc\", 0)\n        end\n        -- @note we can set `remote_only = true` to run all jobs in remote only\n        local local_comax = 0\n        if not opt.remote_only then\n            local_comax = math.min(state.total, state.comax)\n            for id = 1, local_comax do\n                scheduler.co_start_withopt({name = name .. '/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, false)\n            end\n        end\n        if distcc then\n            local left_comax = state.total - local_comax\n            local remote_comax = math.min(distcc:freejobs(), left_comax)\n            for id = 1, remote_comax do\n                scheduler.co_start_withopt({name = name .. '/distcc/' .. tostring(id), isolate = opt.isolate}, _consume_jobs_loop, state, true)\n            end\n        end\n    end)\n\n    -- wait all jobs exited\n    scheduler.co_group_wait(state.group_name)\n    state.stop = true\n\n    -- stop all timers and notify them to exit\n    _stop_timers(state)\n\n    -- wait all timer jobs exited\n    _wait_timers(state)\nend\n\n-- cleanup and handle errors after jobs completion\nfunction _cleanup_jobs(state, opt)\n    -- restore isolated environments\n    _restore_isolated_environments(state, opt)\n\n    -- exit progress\n    _exit_progress(state)\n\n    -- exit waiting indicator\n    _exit_waiting_indicator(state)\n\n    -- do exit callback\n    if opt.on_exit then\n        opt.on_exit(state.abort_errors)\n    end\n\n    -- re-throw abort errors\n    --\n    -- @note we cannot throw it in coroutine,\n    -- because his causes a direct exit from the entire runloop and\n    -- a quick escape from nested try-catch blocks and coroutines groups.\n    -- so we can not catch runjobs errors, e.g. build fails\n    if state.abort then\n        raise(state.abort_errors)\n    end\nend\n\n-- the timer loop\nfunction _timer_loop(state)\n    local timeout = state.timeout\n    while not state.stop do\n        -- wait for timeout, allows quick exit when state.stop is set via post\n        state.timer_semaphore:wait(timeout)\n        if not state.stop then\n            local indices\n            if state.running_jobs_indices then\n                indices = table.keys(state.running_jobs_indices)\n            end\n            state.on_timer(indices)\n        end\n    end\n\n    -- we cannot post semaphore in a dead coroutine\n    state.timer_semaphore = nil\nend\n\n-- the refresh loop for multirow progress (independent timer with its own timeout)\nfunction _progress_refresh_loop(state)\n    -- wait until all tasks have been started using semaphore\n    if state.progress_refresh_semaphore and not state.stop then\n        state.progress_refresh_semaphore:wait(-1)\n    else\n        return\n    end\n\n    -- start refreshing progress using semaphore wait with timeout for quick exit\n    while not state.stop do\n        -- wait for refresh timeout, allows quick exit when state.stop is set via post\n        state.progress_refresh_semaphore:wait(state.timeout)\n\n        -- refresh progress if not stopped\n        if not state.stop then\n            progress.refresh()\n        end\n    end\n\n    -- we cannot post semaphore in a dead coroutine\n    state.progress_refresh_semaphore = nil\nend\n\n-- the waiting indicator loop\nfunction _waiting_indicator_loop(state)\n    local timeout = state.timeout\n    local waiting_indicator_helper = state.waiting_indicator_helper\n    while not state.stop do\n        -- wait for timeout, allows quick exit when state.stop is set via post\n        state.waiting_indicator_semaphore:wait(timeout)\n        if not state.stop then\n\n            -- show waitchars\n            local tips = nil\n            local waitobjs = scheduler.co_group_waitobjs(state.group_name)\n            if waitobjs:size() > 0 then\n                local names = {}\n                for _, obj in waitobjs:keys() do\n                    if obj:otype() == scheduler.OT_PROC then\n                        table.insert(names, obj:name())\n                    elseif obj:otype() == scheduler.OT_SOCK then\n                        table.insert(names, \"sock\")\n                    elseif obj:otype() == scheduler.OT_PIPE then\n                        table.insert(names, \"pipe\")\n                    end\n                end\n                names = table.unique(names)\n                if #names > 0 then\n                    names = table.concat(names, \",\")\n                    if #names > 16 then\n                        names = names:sub(1, 16) .. \"..\"\n                    end\n                    tips = string.format(\"(%d/%s)\", waitobjs:size(), names)\n                end\n            end\n\n            -- print back characters\n            waiting_indicator_helper:clear()\n            _print_backchars(state.backnum)\n\n            if tips then\n                cprintf(\"${dim}%s${clear} \", tips)\n                state.backnum = #tips + 1\n            end\n            waiting_indicator_helper:write()\n        end\n    end\n\n    -- we cannot post semaphore in a dead coroutine\n    state.waiting_indicator_semaphore = nil\nend\n\n-- consume jobs\nfunction _consume_jobs_loop(state, run_in_remote)\n    local jobs = state.jobs\n    local jobs_cb = state.jobs_cb\n    local total = state.total\n    local curdir = state.curdir\n    local semaphore = state.semaphore\n    local distcc_semaphore = state.distcc_semaphore\n    local co_running = scheduler.co_running()\n    while state.finished_count < total and not state.stop do\n\n        -- get free job\n        local job\n        local job_func = jobs_cb\n        local job_distcc = false\n        if not job_func then\n            job = jobs:getfree()\n            if job then\n                if job.distcc then\n                    job_distcc = true\n                end\n                job_func = job.run\n                -- notify other coroutines to consume jobs\n                if run_in_remote then\n                    if state.distcc_waiting_count > 0 then\n                        local left_count = total - state.finished_count\n                        local post_count = math.min(left_count, state.distcc_waiting_count)\n                        distcc_semaphore:post(post_count)\n                    end\n                else\n                    if state.waiting_count > 0 then\n                        local left_count = total - state.finished_count\n                        local post_count = math.min(left_count, state.waiting_count)\n                        semaphore:post(post_count)\n                    end\n                end\n            elseif state.finished_count < total then\n                -- no free jobs now, wait other coroutines\n                if run_in_remote then\n                    state.distcc_waiting_count = state.distcc_waiting_count + 1\n                    distcc_semaphore:wait(-1)\n                    state.distcc_waiting_count = state.distcc_waiting_count - 1\n                else\n                    state.waiting_count = state.waiting_count + 1\n                    semaphore:wait(-1)\n                    state.waiting_count = state.waiting_count - 1\n                end\n            else\n                break\n            end\n        end\n\n        try\n        {\n            function ()\n\n                -- mark the current coroutine to run remote job\n                if run_in_remote and co_running then\n                    co_running:data_set(\"distcc.distccjob\", job_distcc)\n                end\n\n                -- run job\n                co_running:data_set(\"runjobs.running\", true)\n                local job_index = state.finished_count + 1\n                state.running_jobs_indices[job_index] = job_index\n                if job_func then\n                    if curdir then\n                        os.cd(curdir)\n                    end\n\n                    -- to avoid running the same task repeatedly,\n                    -- we need to update the completion count in advance.\n                    state.finished_count = state.finished_count + 1\n\n                    -- check if all tasks have been started (all consumed, but may still be running)\n                    if state.finished_count >= total and not state.all_tasks_started then\n                        state.all_tasks_started = true\n                        -- notify refresh loop that all tasks have been started\n                        if state.progress_refresh_semaphore then\n                            state.progress_refresh_semaphore:post(1)\n                        end\n                    end\n\n                    -- run job\n                    job_func(job_index, total, {progress = state.progress_wrapper})\n\n                    -- update progress\n                    state.progress_finished_count = state.progress_finished_count + 1\n                end\n                state.running_jobs_indices[job_index] = nil\n                co_running:data_set(\"runjobs.running\", false)\n            end,\n            catch\n            {\n                function (errors)\n                    -- stop timer and disable show waitchars first\n                    state.stop = true\n\n                    -- stop progress and waiting indicator\n                    _exit_progress(state)\n                    _exit_waiting_indicator(state)\n\n                    -- we need re-throw this errors outside scheduler\n                    state.abort = true\n                    if state.abort_errors == nil then\n                        state.abort_errors = errors\n                    end\n\n                    -- kill all waited objects in this group\n                    local waitobjs = scheduler.co_group_waitobjs(state.group_name)\n                    if waitobjs:size() > 0 then\n                        for _, obj in waitobjs:keys() do\n                            -- TODO, kill pipe is not supported now\n                            if obj.kill then\n                                obj:kill()\n                            end\n                        end\n                    end\n                end\n            },\n            finally\n            {\n                function ()\n                    if job then\n                        jobs:remove(job)\n                    end\n                end\n            }\n        }\n    end\n\n    -- notify left waiting coroutines\n    if state.distcc_waiting_count > 0 then\n        distcc_semaphore:post(state.distcc_waiting_count)\n    end\n    if state.waiting_count > 0 then\n        semaphore:post(state.waiting_count)\n    end\nend\n\n-- asynchronous run jobs\n--\n-- e.g.\n-- runjobs(\"test\", function (index) print(\"hello\") end, {total = 100, comax = 6, timeout = 1000, on_timer = function (running_jobs_indices) end})\n-- runjobs(\"test\", function () os.sleep(10000) end, { waiting_indicator = true })\n-- runjobs(\"test\", function () os.sleep(10000) end, { waiting_indicator = { chars = {'/','\\'} } }) -- see module utils.waiting_indicator\n-- runjobs(\"test\", function () os.sleep(10000) end, { waiting_indicator = true, progress_refresh = true }) -- enable progress refresh timer for multirow progress\n--\n-- local jobs = jobpool.new()\n-- local root = jobs:addjob(\"job/root\", function (index, total, opt)\n--   print(index, total, opt.progress)\n-- end)\n-- for i = 1, 3 do\n--     local job = jobs:addjob(\"job/\" .. i, function (index, total, opt)\n--         print(index, total, opt.progress)\n--     end, {rootjob = root})\n-- end\n-- runjobs(\"test\", jobs, {comax = 6, timeout = 1000, on_timer = function (running_jobs_indices) end})\n--\n-- distributed build:\n-- runjobs(\"test\", jobs, {comax = 6, distcc = distcc_build_client.singleton()}\n--\nfunction main(name, jobs, opt)\n    opt = opt or {}\n\n    -- init state\n    local state = {}\n    state.total = opt.total or (type(jobs) == \"table\" and jobs:size()) or 1\n    state.comax = opt.comax and tonumber(opt.comax) or math.min(state.total, 4)\n    state.timeout = opt.timeout or 500\n    state.group_name = name\n    state.jobs_cb = type(jobs) == \"function\" and jobs or nil\n    state.stop = false\n    state.running_jobs_indices = {}\n    assert(state.timeout < 60000, \"runjobs: invalid timeout!\")\n\n    -- build jobs queue\n    if type(jobs) == \"table\" and jobs.build then\n        jobs = jobs:build()\n    end\n    assert(jobs, \"runjobs: no jobs!\")\n    state.jobs = jobs\n\n    -- init waiting indicator\n    _init_waiting_indicator(state, opt)\n\n    -- init progress\n    _init_progress(state, opt)\n\n    -- isolate environments\n    _isolate_environments(state, opt)\n\n    -- start all timers\n    _start_timers(state, name, opt)\n\n    -- run jobs and wait for completion\n    _run_jobs(state, name, opt)\n\n    -- cleanup and handle errors\n    _cleanup_jobs(state, opt)\nend\n"
  },
  {
    "path": "xmake/modules/cli/amalgamate.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        amalgamate.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.graph\")\nimport(\"core.project.config\")\nimport(\"core.project.task\")\nimport(\"core.project.project\")\nimport(\"private.detect.check_targetname\")\n\n-- the options\nlocal options =\n{\n    {'u', \"uniqueid\",  \"kv\", nil, \"Set the unique id.\"       },\n    {'o', \"outputdir\", \"kv\", nil, \"Set the output directory.\"},\n    {nil, \"target\",    \"v\",  nil, \"The target name.\"         }\n}\n\n-- get include files\nfunction _get_include_files(target, filepath)\n    local includes = {}\n    local sourcecode = io.readfile(filepath)\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n    sourcecode:gsub(\"#include%s+\\\"(.-)\\\"\", function (include)\n        table.insert(includes, include)\n    end)\n    includes = table.unique(includes)\n\n    local includefiles = {}\n    local filedir = path.directory(filepath)\n    local includedirs = table.join(filedir, target:get(\"includedirs\"))\n    for _, include in ipairs(includes) do\n        local result\n        for _, includedir in ipairs(includedirs) do\n            local includefile = path.join(includedir, include)\n            if os.isfile(includefile) then\n                includefile = path.normalize(path.absolute(includefile, os.projectdir()))\n                result = includefile\n                break\n            end\n        end\n        if result then\n            table.insert(includefiles, result)\n        else\n            wprint(\"#include \\\"%s\\\" not found in %s\", include, filepath)\n        end\n    end\n    return includefiles\nend\n\n-- generate include graph\nfunction _generate_include_graph(target, inputpaths, gh, marked)\n    for _, inputpath in ipairs(inputpaths) do\n        if not marked[inputpath] then\n            marked[inputpath] = true\n            local includefiles = _get_include_files(target, inputpath)\n            for _, includefile in ipairs(includefiles) do\n                gh:add_edge(inputpath, includefile)\n            end\n            if includefiles and #includefiles > 0 then\n                _generate_include_graph(target, includefiles, gh, marked)\n            end\n        end\n    end\nend\n\n-- generate file\nfunction _generate_file(target, inputpaths, outputpath, uniqueid)\n\n    -- generate include graph\n    local gh = graph.new(true)\n    for idx, inputpath in ipairs(inputpaths) do\n        inputpath = path.normalize(path.absolute(inputpath, os.projectdir()))\n        inputpaths[idx] = inputpath\n        gh:add_edge(\"__root__\", inputpath)\n    end\n    _generate_include_graph(target, inputpaths, gh, {})\n\n    -- sort file paths and remove root path\n    local filepaths = gh:topo_sort()\n    table.remove(filepaths, 1)\n\n    -- generate amalgamate file\n    local outputfile = io.open(outputpath, \"w\")\n    for _, filepath in irpairs(filepaths) do\n        cprint(\"  ${color.dump.reference}+${clear} %s\", filepath)\n        if uniqueid then\n            outputfile:print(\"#define %s %s\", uniqueid, \"unity_\" .. hash.uuid():split(\"-\", {plain = true})[1])\n        end\n        outputfile:write(io.readfile(filepath))\n        if uniqueid then\n            outputfile:print(\"#undef %s\", uniqueid)\n        end\n    end\n    outputfile:close()\n    cprint(\"${bright}%s generated!\", outputpath)\nend\n\n-- generate code\nfunction _generate_amalgamate_code(target, opt)\n\n    -- only for library/binary\n    if not target:is_library() and not target:is_binary() then\n        return\n    end\n\n    -- generate source code\n    local outputdir = opt.outputdir\n    local uniqueid = opt.uniqueid\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        local rulename = sourcebatch.rulename\n        if rulename == \"c.build\" or rulename == \"c++.build\" then\n            local outputpath = path.join(outputdir, target:name() .. (sourcekind == \"cxx\" and \".cpp\" or \".c\"))\n            _generate_file(target, sourcebatch.sourcefiles, outputpath, uniqueid)\n        end\n    end\n\n    -- generate header file\n    local srcheaders = target:headerfiles(includedir)\n    if srcheaders and #srcheaders > 0 then\n        local outputpath = path.join(outputdir, target:name() .. \".h\")\n        _generate_file(target, srcheaders, outputpath, uniqueid)\n    end\nend\n\n-- generate amalgamate code\n--\n-- https://github.com/xmake-io/xmake/issues/1438\n--\nfunction main(...)\n\n    -- parse arguments\n    local argv = table.pack(...)\n    local args = option.parse(argv, options, \"Generate amalgamate code.\",\n                                             \"\",\n                                             \"Usage: xmake l cli.amalgamate [options]\")\n\n    -- config first\n    task.run(\"config\")\n\n    -- generate amalgamate code\n    args.outputdir = args.outputdir or config.builddir()\n    if args.target then\n        local target = assert(check_targetname(args.target))\n        _generate_amalgamate_code(target, args)\n    else\n        for _, target in ipairs(project.ordertargets()) do\n            _generate_amalgamate_code(target, args)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/cli/archive.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        archive.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"utils.archive.archive\")\n\n-- the options\nlocal options = {\n    {nil, \"compress\",   \"kv\",  nil, \"Set the compress algorithm.\", values = {\"fastest\", \"faster\", \"default\", \"better\", \"best\"}},\n    {'r', \"recurse\",    \"k\",   nil, \"Enable recursive pattern.\"},\n    {'w', \"workdir\",    \"kv\",  nil, \"Set the working directory.\"},\n    {nil, \"excludes\",   \"kv\",  nil, \"Set the excludes patterns.\",\n                                    \"e.g.\",\n                                    \"    - xmake l cli.archive --excludes=\\\"*/dir/*|dir/*\\\" -o archivefile inputfiles\"},\n    {'o', \"archivefile\",\"kv\",  nil, \"The output archive file.\"},\n    {nil, \"inputfiles\", \"vs\",  nil, \"The input files.\"}\n}\n\nfunction main(...)\n    local argv = table.pack(...)\n    local args = option.parse(argv, options, \"Archive file.\",\n                                             \"\",\n                                             \"Usage: xmake l cli.archive [options]\")\n    local archivefile = assert(args.archivefile, \"please set output file!\")\n    local inputfiles = assert(args.inputfiles, \"please set input files!\")\n\n    local opt = {}\n    opt.recurse = args.recurse\n    opt.compress = args.compress\n    opt.curdir = args.workdir\n    if args.excludes then\n        opt.excludes = args.excludes:split(\"|\")\n    end\n    archive(archivefile, inputfiles, opt)\nend\n"
  },
  {
    "path": "xmake/modules/cli/binutils/bin2c.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bin2c.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"utils.binary.bin2c\")\n\nlocal options = {\n    {'w', \"linewidth\",  \"kv\", nil,   \"Set the line width\"},\n    {nil, \"nozeroend\",  \"k\",  false, \"Disable to patch zero terminating character\"},\n    {'i', \"binarypath\", \"kv\", nil,   \"Set the binary file path.\"},\n    {'o', \"outputpath\", \"kv\", nil,   \"Set the output file path.\"}\n}\n\nfunction main(...)\n\n    -- parse arguments\n    local argv = {...}\n    local opt  = option.parse(argv, options, \"Print c/c++ code files from the given binary file.\"\n                                           , \"\"\n                                           , \"Usage: xmake l cli.binutils.bin2c [options]\")\n\n    -- check arguments\n    if not opt.binarypath or not opt.outputpath then\n        cprint(\"${bright}Usage: $${clear}xmake l cli.binutils.bin2c [options]\")\n        option.show_options(options, \"bin2c\")\n        return\n    end\n\n    -- do bin2c\n    bin2c.main(opt.binarypath, opt.outputpath, opt)\nend\n"
  },
  {
    "path": "xmake/modules/cli/binutils/bin2obj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bin2obj.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"utils.binary.bin2obj\")\n\nlocal options = {\n    {'i', \"binarypath\",    \"kv\", nil,   \"Set the binary file path.\"},\n    {'o', \"outputpath\",    \"kv\", nil,   \"Set the output object file path.\"},\n    {'f', \"format\",        \"kv\", nil,   \"Set the object file format (coff, elf, macho).\"},\n    {nil, \"symbol_prefix\", \"kv\", nil,   \"Set the symbol prefix (default: _binary_).\"},\n    {'a', \"arch\",          \"kv\", nil,   \"Set the target architecture.\"},\n    {'p', \"plat\",          \"kv\", nil,   \"Set the target platform (macosx, iphoneos, etc.).\"},\n    {nil, \"target_minver\", \"kv\", nil,   \"Set the target minimum version (e.g., 10.0, 18.2).\"},\n    {nil, \"xcode_sdkver\",  \"kv\", nil,   \"Set the Xcode SDK version (e.g., 10.0, 18.2).\"},\n    {nil, \"zeroend\",       \"k\",  nil,   \"Append a null terminator ('\\\\0') at the end of data.\"},\n    {nil, \"cosmocc\",       \"k\",  nil,   \"Enable cosmocc support (generate concomitant object file).\"}\n}\n\nfunction main(...)\n\n    -- parse arguments\n    local argv = {...}\n    local opt  = option.parse(argv, options, \"Convert binary file to object file for direct linking.\"\n                                                   , \"\"\n                                                   , \"Usage: xmake l cli.binutils.bin2obj [options]\")\n\n    -- check arguments\n    if not opt.binarypath or not opt.outputpath then\n        cprint(\"${bright}Usage: $${clear}xmake l cli.binutils.bin2obj [options]\")\n        option.show_options(options, \"bin2obj\")\n        return\n    end\n\n    -- do bin2obj\n    bin2obj.main(opt.binarypath, opt.outputpath, opt)\nend\n"
  },
  {
    "path": "xmake/modules/cli/bisect.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bisect.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- the options\nlocal options = {\n    {'g', \"good\",     \"kv\",  nil, \"Set the good commit.\"},\n    {'b', \"bad\",      \"kv\",  nil, \"Set the bad commit.\"},\n    {nil, \"gitdir\",   \"kv\",  nil, \"Set the git root directory.\"},\n    {'c', \"commands\", \"kv\" , nil, \"Run the multiple commands instead of the default build command.\",\n                                  \"e.g.\",\n                                  \"    $ xmake l cli.bisect -c 'xmake -rv' -g good -b bad\",\n                                  \"    $ xmake l cli.bisect -c 'xmake -vD; xmake run hello' -g good -b bad\"},\n    {'s', \"script\"  , \"kv\" , nil, \"Run the given lua script file.\",\n                                  \"e.g.\",\n                                  \"    $ xmake l cli.bisect -s /tmp/test.lua -g good -b bad\"},\n    {'-', \"arbitrary\", \"vs\", nil, \"Run an arbitrary command.\",\n                                  \"e.g.\",\n                                  \"    $ xmake l cli.bisect -g 90846dd -b ddb86e4 -- xmake -rv\"}\n}\n\n-- run command\nfunction _run_command(opt)\n    opt = opt or {}\n    local ok = try\n    {\n        function ()\n            local commands = opt.commands\n            local scriptfile = opt.script\n            local arbitrary = opt.arbitrary\n            if commands then\n                for _, command in ipairs(commands:split(\";\")) do\n                    os.exec(command:trim())\n                end\n            elseif arbitrary then\n                local program = arbitrary[1]\n                local argv = #arbitrary > 1 and table.slice(arbitrary, 2) or {}\n                os.execv(program, argv)\n            elseif scriptfile and os.isfile(scriptfile) and path.extension(scriptfile) == \".lua\" then\n                local script = import(path.basename(scriptfile),\n                    {rootdir = path.directory(scriptfile), anonymous = true})\n                script(events)\n            end\n            return true\n        end,\n        catch\n        {\n            function (errors)\n                cprint(tostring(errors))\n            end\n        }\n    }\n    return ok\nend\n\n\n-- use `git bisect` to analyze problem\nfunction main(...)\n    local argv = table.pack(...)\n    local args = option.parse(argv, options, \"Analyze problem using `git bisect`.\",\n                                             \"\",\n                                             \"Usage: xmake l cli.bisect [options]\")\n\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n    local good = assert(args.good, \"please set `--good commit`\")\n    local bad = assert(args.bad, \"please set `--bad commit`\")\n    local gitdir = args.gitdir or os.curdir()\n    os.execv(git.program, {\"bisect\", \"start\"}, {curdir = gitdir})\n    os.execv(git.program, {\"bisect\", \"good\", good}, {curdir = gitdir})\n    os.execv(git.program, {\"bisect\", \"bad\", bad}, {curdir = gitdir})\n    while true do\n        local output\n        if _run_command(args) then\n            output = os.iorunv(git.program, {\"bisect\", \"good\"}, {curdir = gitdir})\n        else\n            output = os.iorunv(git.program, {\"bisect\", \"bad\"}, {curdir = gitdir})\n        end\n        if output then\n            print(output)\n            if output:find(\"is the first bad commit\", 1, true) then\n                break\n            end\n        end\n    end\n    os.execv(git.program, {\"bisect\", \"reset\"}, {curdir = gitdir})\nend\n"
  },
  {
    "path": "xmake/modules/cli/extract.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        extract.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"utils.archive.extract\")\n\n-- the options\nlocal options = {\n    {'w', \"workdir\",    \"kv\",  nil, \"Set the working directory.\"},\n    {nil, \"excludes\",   \"kv\",  nil, \"Set the excludes patterns.\",\n                                    \"e.g.\",\n                                    \"    - xmake l cli.extract --excludes=\\\"*/dir/*|dir/*\\\" -o outputdir archivefile\"},\n    {'o', \"outputdir\",  \"kv\", nil,  \"The output directory.\"},\n    {nil, \"archivefile\",\"v\",  nil,  \"The archive file.\"}\n}\n\nfunction main(...)\n    local argv = table.pack(...)\n    local args = option.parse(argv, options, \"Extract file.\",\n                                             \"\",\n                                             \"Usage: xmake l cli.extract [options]\")\n    local archivefile = assert(args.archivefile, \"please set archive file!\")\n    local outputdir = assert(args.outputdir, \"please set output directory!\")\n\n    local opt = {}\n    opt.recurse = args.recurse\n    opt.curdir = args.workdir\n    if args.excludes then\n        opt.excludes = args.excludes:split(\"|\")\n    end\n    extract(archivefile, outputdir, opt)\nend\n"
  },
  {
    "path": "xmake/modules/cli/iconv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        iconv.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- supported encodings\nlocal encodings = {\"ansi\", \"ascii\", \"gb2312\", \"gbk\", \"iso8859\", \"ucs2\", \"ucs4\", \"utf16\", \"utf16be\", \"utf16bom\", \"utf16le\", \"utf16lebom\", \"utf32\", \"utf32be\", \"utf32le\", \"utf8\", \"utf8bom\"}\n\n-- the options\nlocal options = {\n    {'f', \"from\",       \"kv\", \"utf8\", \"The source encoding.\", values = encodings},\n    {'t', \"to\",         \"kv\", \"utf8\", \"The target encoding.\", values = encodings},\n    {'l', \"list\",       \"k\",  nil,    \"List supported encodings.\"},\n    {'o', \"outputfile\", \"kv\", nil,    \"The output file.\"},\n    {nil, \"inputfile\",  \"v\",  nil,    \"The input file.\"}\n}\n\n-- main entry\nfunction main(...)\n\n    -- parse arguments\n    local argv = table.pack(...)\n    local args = option.parse(argv, options, \"Convert encoding of a file.\",\n                                             \"\",\n                                             \"Usage: xmake l cli.iconv [options] [inputfile]\")\n\n    -- list encodings\n    if args.list then\n        print(table.concat(encodings, \" \"))\n        return\n    end\n\n    -- get arguments\n    local input_file = assert(args.inputfile, \"input file required!\")\n    local output_file = args.outputfile\n    local from_code = args.from\n    local to_code = args.to\n\n    -- convert encoding\n    if output_file then\n        io.convert(input_file, output_file, {from = from_code, to = to_code})\n    else\n        local tmpfile = os.tmpfile()\n        io.convert(input_file, tmpfile, {from = from_code, to = to_code})\n        local data = io.readfile(tmpfile, {encoding = \"binary\"})\n        if data then\n            io.write(data)\n        end\n        os.rm(tmpfile)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/core/base/license.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        license.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.hashset\")\n\n-- get licenses\nfunction _licenses()\n    local licenses = _g.licenses\n    if not licenses then\n        licenses = hashset.from({\"Apache-1.1\", \"Apache-2.0\",\n                                 \"MIT\",\n                                 \"Zlib\",\n                                 \"Public Domain\",\n                                 \"CC0\",\n                                 \"LLVM\",\n                                 \"AFL-3.0\",\n                                 \"AGPL-3.0\",\n                                 \"LGPL-2.0\", \"LGPL-2.1\", \"LGPL-3.0\",\n                                 \"GPL-2.0\", \"GPL-3.0\",\n                                 \"BSD-2-Clause\", \"BSD-3-Clause\",\n                                 \"BSL-1.0\",\n                                 \"MPL-2.0\",\n                                 \"libpng-2.0\",\n                                 \"Python-2.0\"})\n        _g.licenses = licenses\n    end\n    return licenses\nend\n\n-- get all licenses list\nfunction list()\n    return _licenses():to_array()\nend\n\n-- normalize license\nfunction normalize(license)\n    -- TODO parse and convert license strings in other formats\n    return license\nend\n\n-- check if the license is compatible\n-- @see https://github.com/xmake-io/xmake/issues/1016\n--\nfunction compatible(target_license, library_license, opt)\n    opt = opt or {}\n    library_license = normalize(library_license)\n    if library_license then\n        target_license = normalize(target_license)\n        if library_license:startswith(\"GPL-\") then\n            return target_license and target_license:startswith(\"GPL-\")\n        elseif library_license:startswith(\"LGPL-\") then\n            if target_license and target_license:startswith(\"LGPL-\") then\n                return true\n            elseif opt.library_kind and opt.library_kind == \"shared\" then\n                -- we can only use shared library with LGPL-x\n                return true\n            else\n                return false, string.format(\"we can use shared libraries with %s or use set_license()/set_policy() to modify/disable license\", library_license)\n            end\n        else\n            -- TODO maybe we need handle more licenses\n        end\n    end\n    return true\nend\n"
  },
  {
    "path": "xmake/modules/core/project/depend.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        depend.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\n\n-- load depfiles\nfunction _load_depfiles(parser, dependinfo, depfiles, opt)\n    depfiles = parser(depfiles, opt)\n    if depfiles then\n        if dependinfo.files then\n            table.join2(dependinfo.files, depfiles)\n        else\n            dependinfo.files = depfiles\n        end\n    end\nend\n\n-- get depfiles parser\nfunction _get_depfiles_parser(depfiles_format)\n    assert(depfiles_format, \"no depfiles format\")\n    local depfiles_parsers = _g._depfiles_parsers\n    if depfiles_parsers == nil then\n        depfiles_parsers = {}\n        _g._depfiles_parsers = depfiles_parsers\n    end\n    local parser = depfiles_parsers[depfiles_format]\n    if parser == nil then\n        parser = import(\"core.tools.\" .. depfiles_format .. \".parse_deps\", {anonymous = true})\n        depfiles_parsers[depfiles_format] = parser or false\n    end\n    return parser or nil\nend\n\n-- load dependent info from the given file (.d)\nfunction load(dependfile, opt)\n    if os.isfile(dependfile) then\n        -- may be the depend file has been incomplete when if the compilation process is abnormally interrupted\n        local dependinfo = try { function() return io.load(dependfile) end }\n        if dependinfo then\n            -- attempt to load depfiles from the compilers\n            local depfiles = dependinfo.depfiles\n            if depfiles then\n                local depfiles_parser = _get_depfiles_parser(dependinfo.depfiles_format)\n                _load_depfiles(depfiles_parser, dependinfo, depfiles, opt)\n                dependinfo.depfiles = nil\n            end\n            return dependinfo\n        end\n    end\nend\n\n-- show diagnosis info?\nfunction _is_show_diagnosis_info()\n    local show = _g.is_show_diagnosis_info\n    if show == nil then\n        if project.policy(\"diagnosis.check_build_deps\") then\n            show = true\n        else\n            show = false\n        end\n        _g.is_show_diagnosis_info = show\n    end\n    return show\nend\n\n-- save dependent info to file\nfunction save(dependinfo, dependfile)\n    io.save(dependfile, dependinfo)\nend\n\n-- Is the dependent info changed?\n--\n-- if not depend.is_changed(dependinfo, {filemtime = os.mtime(objectfile), values = {...}}) then\n--      return\n-- end\n--\nfunction is_changed(dependinfo, opt)\n\n    -- empty depend info? always be changed\n    local files = table.wrap(dependinfo.files)\n    local values = table.wrap(dependinfo.values)\n    if #files == 0 and #values == 0 then\n        return true\n    end\n\n    -- check whether the dependent files are changed\n    local timecache = opt.timecache\n    local lastmtime = opt.lastmtime or 0\n    _g.files_mtime = _g.files_mtime or {}\n    local files_mtime = _g.files_mtime\n    for _, file in ipairs(files) do\n\n        -- get and cache the file mtime\n        local mtime\n        if timecache then\n            mtime = files_mtime[file]\n            if mtime == nil then\n                mtime = os.mtime(file)\n                files_mtime[file] = mtime\n            end\n        else\n            mtime = os.mtime(file)\n        end\n\n        -- source and header files have been changed or not exists?\n        if mtime == 0 or mtime > lastmtime then\n            if _is_show_diagnosis_info() then\n                cprint(\"${color.warning}[check_build_deps]: file %s is changed, mtime: %s, lastmtime: %s\", file, mtime, lastmtime)\n            end\n            return true\n        end\n    end\n\n    -- check whether the dependent values are changed\n    local depvalues = values\n    local optvalues = table.wrap(opt.values)\n    if #depvalues ~= #optvalues then\n        return true\n    end\n    for idx, depvalue in ipairs(depvalues) do\n        local optvalue = optvalues[idx]\n        local deptype = type(depvalue)\n        local opttype = type(optvalue)\n        if deptype ~= opttype then\n            return true\n        elseif deptype == \"string\" and depvalue ~= optvalue then\n            if _is_show_diagnosis_info() then\n                cprint(\"${color.warning}[check_build_deps]: value %s != %s\", depvalue, optvalue)\n            end\n            return true\n        elseif deptype == \"table\" then\n            for subidx, subvalue in ipairs(depvalue) do\n                if subvalue ~= optvalue[subidx] then\n                    if _is_show_diagnosis_info() then\n                        cprint(\"${color.warning}[check_build_deps]: value %s != %s at index %d\", subvalue, optvalue[subidx], subidx)\n                    end\n                    return true\n                end\n            end\n        end\n    end\n\n    -- check whether the dependent files list are changed\n    if opt.files then\n        local optfiles = table.wrap(opt.files)\n        if #files ~= #optfiles then\n            return true\n        end\n        for idx, file in ipairs(files) do\n            if file ~= optfiles[idx] then\n                if _is_show_diagnosis_info() then\n                    cprint(\"${color.warning}[check_build_deps]: file %s != %s at index %d\", file, optfiles[idx], idx)\n                end\n                return true\n            end\n        end\n    end\nend\n\n-- on changed for the dependent files and values\n--\n-- e.g.\n--\n-- depend.on_changed(function ()\n--     -- do some thing\n--     -- ..\n--\n--     -- maybe need update dependent files\n--     dependinfo.files = {\"\"}\n--\n--     -- return new dependinfo (optional)\n--     return {files = {}, ..}\n--\n-- end, {dependfile = \"/xx/xx\",\n--       values = {compinst:program(), compflags},\n--       files = {sourcefile, ...}})\n--\nfunction on_changed(callback, opt)\n    opt = opt or {}\n\n    -- dry run? we only do callback directly and do not change any status\n    if opt.dryrun then\n        return callback()\n    end\n\n    -- get files\n    assert(opt.files, \"depend.on_changed(): please set files list!\")\n\n    -- get dependfile\n    local dependfile = opt.dependfile\n    if not dependfile then\n        dependfile = project.tmpfile(table.concat(table.wrap(opt.files), \"\"))\n    end\n\n    -- load dependent info\n    local dependinfo = opt.changed and {} or (load(dependfile) or {})\n\n    -- @note we use mtime(dependfile) instead of mtime(objectfile) to ensure the object file is is fully compiled.\n    -- @see https://github.com/xmake-io/xmake/issues/748\n    if not is_changed(dependinfo, {\n            timecache = opt.timecache,\n            lastmtime = opt.lastmtime or os.mtime(dependfile),\n            values = opt.values, files = opt.files}) then\n        return\n    end\n\n    -- do callback if changed and maybe files and values will be updated\n    dependinfo = callback() or {}\n\n    -- update files and values to the dependent file\n    dependinfo.files = dependinfo.files or {}\n    table.join2(dependinfo.files, opt.files)\n    if opt.values then\n        dependinfo.values = dependinfo.values or {}\n        table.join2(dependinfo.values, opt.values)\n    end\n    save(dependinfo, dependfile)\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/ar/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.ar.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = nil\n        try\n        {\n            function () os.runv(opt.program, {\"--help\"}) end,\n            catch\n            {\n                function (errors) arglist = errors end\n            }\n        }\n        if arglist then\n            local found = false\n            for arg in arglist:gmatch(\"%-r %[%-(%a+)%]\") do\n                arg:gsub(\"%a\", function (ch) allflags[\"-\" .. ch] = true; allflags[\"-r\" .. ch] = true; allflags[\"-\" .. ch .. \"r\"] = true end)\n                found = true\n            end\n            if found then\n                allflags[\"-r\"] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n    return _check_from_arglist(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ar.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n    self:set(\"arflags\", \"-cr\")\n    self:set(\"dcarflags\", \"-cr\") -- for dlang/gdc, e.g. x86_64-unknown-linux-gnu-gcc-ar\nend\n\n-- make the strip flag\nfunction strip(self, level)\n    local maps = {\n        debug = \"-S\"\n    ,   all   = \"-s\"\n    }\n    return maps[level]\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local argv = table.join(flags, targetfile, objectfiles)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the library file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n\n    -- @note remove the previous archived file first to force recreating a new file\n    os.tryrm(targetfile)\n\n    -- link it\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    os.runv(program, argv, {envs = self:runenvs(), shell = opt.shell})\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ar2000.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ar2000.lua\n--\n\ninherit(\"ar\")\n\n-- init it\nfunction init(self)\n    self:set(\"arflags\", \"-r\")\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ar6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ar6x.lua\n--\n\ninherit(\"ar\")\n\n-- init it\nfunction init(self)\n    self:set(\"arflags\", \"-r\")\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armar.lua\n--\n\ninherit(\"ar\")\n\nfunction init(self)\n    _super.init(self)\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local argv = table.join(flags, targetfile, objectfiles)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n        if #argv > 0 and argv[1] and argv[1]:startswith(\"@\") then\n            argv[1] = argv[1]:replace(\"@\", \"\", {plain = true})\n            table.insert(argv, 1, \"--via\")\n        end\n    end\n    return self:program(), argv\nend\n\n-- link the library file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n\n    -- @note remove the previous archived file first to force recreating a new file\n    os.tryrm(targetfile)\n\n    -- link it\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n    os.runv(program, argv, {envs = self:runenvs()})\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/armasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armasm.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime == \"microlib\" then\n        return {\"--pd\", \"__MICROLIB SETA 1\"}\n    end\nend\n\n-- make the define flag\n-- eg.\n-- add_defines(\"MACRO\") -> --pd \"MACRO  SETA 1\n-- add_defines(\"MACRO=3\") -> --pd \"MACRO SETA 3\"\nfunction nf_define(self, macro)\n    local def = macro:split(\"=\")\n    local key = def[1]:trim()\n    local value = \"1\"\n    if #def == 2 then\n        value = def[2]:trim()\n    end\n    return {\"--pd\", key .. \" SETA \" .. value}\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armasm64_msvc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.armasm_msvc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armasm64_msvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armasm64_msvc.lua\n--\n\n-- imports\ninherit(\"armasm_msvc\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armasm_msvc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.armasm.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-?\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\")] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]:gsub(\"/\", \"-\")]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"armasm_has_flags.asm\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, [[\nEND]])\n    end\n\n    -- check it\n    local errors = nil\n    return try  {   function ()\n                        local _, errs = os.iorunv(opt.program, table.join(flags, \"-o\", os.nuldev(), sourcefile), {envs = opt.envs})\n                        if errs and #errs:trim() > 0 then\n                            return false, errs\n                        end\n                        return true\n                    end,\n                    catch { function (errs) errors = errs end }\n                }, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armasm_msvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armasm_msvc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n    self:add(\"asflags\", \"-nologo\")\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make the define flag\n-- eg.\n-- add_defines(\"MACRO\") -> --pd \"MACRO  SETA 1\n-- add_defines(\"MACRO=3\") -> --pd \"MACRO SETA 3\"\nfunction nf_define(self, macro)\n    local def = macro:split(\"=\")\n    local key = def[1]:trim()\n    local value = \"1\"\n    if #def == 2 then\n        value = def[2]:trim()\n    end\n    return {\"-pd\", key .. \" SETA \" .. value}\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-i\", dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armcc/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      smalli\n-- @file        parse_deps_armcc.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\n\n-- a placeholder for spaces in path\nlocal space_placeholder = \"\\001\"\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        return dep\n    end\nend\n\n-- parse depsfiles from string\n--\n-- parse_deps(io.readfile(depfile, {continuation = \"\\\\\"}))\n--\n-- eg.\n-- build\\\\.objs\\\\apps\\\\cross\\\\cortex-m3\\\\release\\\\APPS\\\\main.c.o: APPS\\\\main.c\\\n-- build\\\\.objs\\\\apps\\\\cross\\\\cortex-m3\\\\release\\\\APPS\\\\main.c.o: D:\\\\Keil533\\\\ARM\\\\ARMCC\\\\bin\\\\..\\\\include\\\\stdarg.h\\\n-- build\\\\.objs\\\\apps\\\\cross\\\\cortex-m3\\\\release\\\\APPS\\\\main.c.o: D:\\\\Keil533\\\\ARM\\\\ARMCC\\\\bin\\\\..\\\\include\\\\stdio.h\\\n-- build\\\\.objs\\\\apps\\\\cross\\\\cortex-m3\\\\release\\\\APPS\\\\main.c.o: D:\\\\Keil533\\\\ARM\\\\ARMCC\\\\bin\\\\..\\\\include\\\\string.h\\\n-- build\\\\.objs\\\\apps\\\\cross\\\\cortex-m3\\\\release\\\\APPS\\\\main.c.o: APPS\\\\main.h\\\n--\n--\nfunction main(depsdata)\n    local block = 0\n    local results = hashset.new()\n    local projectdir = os.projectdir()\n    local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first\n    local plain = {plain = true}\n    line = line:replace(\"\\\\ \", space_placeholder, plain)\n    for _, includefile in ipairs(line:split('\\n', plain)) do\n        if is_host(\"windows\") and includefile:match(\"^%w\\\\:\") then\n            includefile = includefile:replace(\"\\\\:\", \":\", plain)\n        end\n        includefile = includefile:replace(space_placeholder, ' ', plain)\n        local splitinfo = includefile:split(\".o:\", {plain = true})\n        if #splitinfo < 2 then\n            splitinfo = includefile:split(\".obj:\", {plain = true})\n        end\n        includefile = splitinfo[2]\n        if includefile then\n            includefile = includefile:replace(' ', '', plain)\n            if #includefile > 0 then\n                includefile = _normailize_dep(includefile, projectdir)\n                if includefile then\n                    results:insert(includefile)\n                end\n            end\n        end\n    end\n    return results:to_array()\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/armcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armcc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime == \"microlib\" then\n        return \"-D__MICROLIB\"\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-Os\"\n    ,   aggressive = \"-Ofast\"\n    }\n    return maps[level]\nend\n\n-- make the language flag\nfunction nf_language(self, stdname)\n\n    -- the stdc maps\n    if _g.cmaps == nil then\n        _g.cmaps =\n        {\n            ansi        = \"-c89\"\n        ,   c89         = \"-c89\"\n        ,   gnu89       = \"-c89\"\n        ,   c99         = \"-c99\"\n        ,   gnu99       = \"-c99\"\n        ,   c11         = \"-c11\"\n        ,   gnu11       = \"-c11\"\n        ,   clatest     = {\"-c11\", \"-c99\", \"-c89\"}\n        ,   gnulatest   = {\"-c11\", \"-c99\", \"-c89\"}\n        }\n    end\n    local maps = _g.cmaps\n    local result = maps[stdname]\n    if type(result) == \"table\" then\n        for _, v in ipairs(result) do\n            if self:has_flags(v, \"cxflags\") then\n                result = v\n                maps[stdname] = result\n                return result\n            end\n        end\n    else\n        return result\n    end\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"--depend\", depfile)\n            end\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"armcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armclang/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    local has_target\n    for _, v in ipairs(argv) do\n        if v:startswith(\"-target=\") then\n            has_target = true\n            break\n        end\n    end\n    if not has_target then\n        table.insert(argv, 1, \"-mcpu=cortex-m3\")\n        table.insert(argv, 1, \"-target=arm-arm-none-eabi\")\n    end\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.armclang.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {islinker and \"-Wl,--help\" or \"--help\"}, {envs = opt.envs}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    if islinker and flag then\n        if flag:startswith(\"-Wl,\") then\n            flag = flag:match(\"-Wl,(.-),\") or flag:sub(5)\n        end\n    end\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"armclang_has_flags\" .. _get_extension(opt))\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-c\", \"-o\", tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun and _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armclang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armclang.lua\n--\n\ninherit(\"gcc\")\nimport(\"core.language.language\")\n\nfunction init(self)\n    _super.init(self)\nend\n\n-- make runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime == \"microlib\" then\n        return \"-D__MICROLIB\"\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none       = \"-O0\"\n        ,   fast       = \"-O1\"\n        ,   faster     = \"-O2\"\n        ,   fastest    = \"-O3\"\n        ,   smallest   = \"-Oz\" -- smaller than -Os\n        ,   aggressive = \"-Ofast\"\n        }\n        return maps[level]\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/armlink.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        armlink.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"utils.progress\")\n\nfunction init(self)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"lib\" .. lib .. \".a\"\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"--userlibpath\", dir}\nend\n\n-- make runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime == \"microlib\" then\n        return \"--library_type=microlib\"\n    end\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n        if #argv > 0 and argv[1] and argv[1]:startswith(\"@\") then\n            argv[1] = argv[1]:replace(\"@\", \"\", {plain = true})\n            table.insert(argv, 1, \"--via\")\n        end\n    end\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    try\n    {\n        function ()\n            os.mkdir(path.directory(targetfile))\n            local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n            return os.iorunv(program, argv)\n        end,\n        catch\n        {\n            function (errors)\n\n                -- parse and strip errors\n                local lines = errors and tostring(errors):split('\\n', {plain = true}) or {}\n                if not option.get(\"verbose\") then\n\n                    -- find the start line of error\n                    local start = 0\n                    for index, line in ipairs(lines) do\n                        if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                            start = index\n                            break\n                        end\n                    end\n\n                    -- get 16 lines of errors\n                    if start > 0 then\n                        lines = table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start)))\n                    end\n                end\n\n                -- raise errors\n                local results = #lines > 0 and table.concat(lines, \"\\n\") or \"\"\n                raise(results)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n\n                -- show warnings?\n                if ok and errdata and #errdata > 0 and policy.build_warnings(opt) then\n                    local lines = errdata:split('\\n', {plain = true})\n                    if #lines > 0 then\n                        if not option.get(\"diagnosis\") then\n                            lines = table.slice(lines, 1, (#lines > 16 and 16 or #lines))\n                        end\n                        local warnings = table.concat(lines, \"\\n\")\n                        progress.show_output(\"${color.warning}%s\", warnings)\n                    end\n                end\n\n                -- show echo output? e.g. --map data\n                -- @see https://github.com/xmake-io/xmake/issues/4420\n                if ok and outdata and #outdata > 0 and option.get(\"diagnosis\") then\n                    print(outdata)\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/bl51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        bl51.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"utils.progress\")\n\nfunction init(self)\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    return self:program(), table.join(table.concat(objectfiles, \",\"), \"TO\", targetfile, flags)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/c51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        c51.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\nimport(\"core.project.policy\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = {\n            fast       = \"OT(8,SPEED)\"\n        ,   faster     = \"OT(9,SPEED)\"\n        ,   fastest    = \"OT(10,SPEED)\"\n        ,   smallest   = \"OT(10,SIZE)\"\n        ,   aggressive = \"OT(11,SPEED)\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the includedir flag\nfunction nf_includedirs(self, dirs)\n    local paths = {}\n    for _, dir in ipairs(dirs) do\n        table.insert(paths, path.translate(dir))\n    end\n    if #paths > 0 then\n        return {\"INCDIR(\" .. table.concat(paths, \";\") .. \")\"}\n    end\nend\n\n-- make the define flag\nfunction nf_defines(self, defines)\n    if defines and #defines > 0 then\n        return {\"DEFINE(\" .. table.concat(defines, \",\") .. \")\"}\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    local lstfile = objectfile:gsub(\"%.c%.obj\", \".lst\")\n    lstfile = lstfile:gsub(\"%.c%.o$\", \".lst\")\n    return self:program(), table.join(sourcefile, \"OBJECT(\" .. objectfile .. \")\", \"PRINT(\" .. lstfile .. \")\", flags)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                -- show warnings?\n                if ok and outdata and #outdata > 0 and policy.build_warnings(opt) then\n                    local warnings_count = outdata:match(\"(%d-) WARNING\")\n                    if warnings_count and tonumber(warnings_count) > 0 then\n                        local lines = outdata:split('\\n', {plain = true})\n                        if #lines > 0 then\n                            if not option.get(\"diagnosis\") then\n                                lines = table.slice(lines, 1, (#lines > 16 and 16 or #lines))\n                            end\n                            local warnings = table.concat(lines, \"\\n\")\n                            progress.show_output(\"${color.warning}%s\", warnings)\n                        end\n                    end\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cc.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/circle/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/circle.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        circle.lua\n--\n\ninherit(\"gcc\")\n\nfunction init(self)\n    _super.init(self)\nend\n\nfunction nf_strip(self, level)\n    local maps =\n    {\n        debug = \"-Wl,-S\"\n    ,   all   = \"-Wl,-s\"\n    }\n    return maps[level]\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/cfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cfeatures.lua\n--\n\n-- set features\nfunction _set(feature, condition)\n    _g.features = _g.features or {}\n    _g.features[feature] = condition\nend\n\n-- get features\nfunction main()\n\n    -- init conditions\n    local msvc_minver = \"_MSC_VER >= 1200\"\n    local msvc_2005   = \"_MSC_VER >= 1400\"\n    local msvc_2010   = \"_MSC_VER >= 1600\"\n    local msvc_2019   = \"_MSC_VER >= 1920\"\n\n    -- set language standard supports\n    _set(\"c_std_89\", msvc_2005)\n    _set(\"c_std_99\", msvc_2019)\n\n    -- set features\n    _set(\"c_static_assert\",       msvc_2010)\n    _set(\"c_restrict\",            msvc_2005)\n    _set(\"c_variadic_macros\",     msvc_2005)\n    _set(\"c_function_prototypes\", msvc_minver)\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/cxxfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxfeatures.lua\n--\n\n-- set features\nfunction _set(feature, condition)\n    _g.features = _g.features or {}\n    _g.features[feature] = condition\nend\n\n-- get features\n--\n-- Reference: http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx\n-- http://blogs.msdn.com/b/vcblog/archive/2013/06/28/c-11-14-stl-features-fixes-and-breaking-changes-in-vs-2013.aspx\n-- http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx\n-- http://www.visualstudio.com/en-us/news/vs2015-preview-vs.aspx\n-- http://blogs.msdn.com/b/vcblog/archive/2015/04/29/c-11-14-17-features-in-vs-2015-rc.aspx\n-- http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx\n-- https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-160\n--\n-- porting from Modules/Compiler/MSVC-CXX-FeatureTests.cmake\n--\nfunction main()\n\n    -- init conditions\n    local msvc_minver = \"_MSC_VER >= 1200\"\n    local msvc_60     = \"_MSC_VER >= 1200\"\n    local msvc_70     = \"_MSC_VER >= 1300\"\n    local msvc_71     = \"_MSC_VER >= 1310\"\n    local msvc_2005   = \"_MSC_VER >= 1400\"\n    local msvc_2008   = \"_MSC_VER >= 1500\"\n    local msvc_2010   = \"_MSC_VER >= 1600\"\n    local msvc_2012   = \"_MSC_VER >= 1700\"\n    local msvc_2013   = \"_MSC_VER >= 1800\"\n    local msvc_2015   = \"_MSC_VER >= 1900\"\n    local msvc_2017   = \"_MSC_VER >= 1910\"\n    local msvc_2019   = \"_MSC_VER >= 1920\"\n    local msvc_2022   = \"_MSC_VER >= 1930\"\n\n    -- set language standard supports\n    _set(\"cxx_std_98\", msvc_2005)\n    _set(\"cxx_std_11\", msvc_2015)\n    _set(\"cxx_std_14\", msvc_2017)\n    _set(\"cxx_std_17\", msvc_2019)\n    _set(\"cxx_std_20\", msvc_2022)\n\n    -- VS version 15 (not 2015) introduces support for aggregate initializers.\n    _set(\"cxx_aggregate_default_initializers\", \"_MSC_FULL_VER >= 190024406\")\n\n    -- VS 2015 Update 2 introduces support for variable templates.\n    -- https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx\n    _set(\"cxx_variable_templates\", \"_MSC_FULL_VER >= 190023918\")\n\n    _set(\"cxx_alignas\",                       msvc_2015)\n    _set(\"cxx_alignof\",                       msvc_2015)\n    _set(\"cxx_attributes\",                    msvc_2015)\n    _set(\"cxx_attribute_deprecated\",          msvc_2015)\n    _set(\"cxx_binary_literals\",               msvc_2015)\n    _set(\"cxx_constexpr\",                     msvc_2015)\n    _set(\"cxx_decltype_auto\",                 msvc_2015)\n    _set(\"cxx_digit_separators\",              msvc_2015)\n    _set(\"cxx_func_identifier\",               msvc_2015)\n    _set(\"cxx_nonstatic_member_init\",         msvc_2015)\n    _set(\"cxx_defaulted_move_initializers\",   msvc_2015)\n    _set(\"cxx_generic_lambdas\",               msvc_2015)\n    _set(\"cxx_inheriting_constructors\",       msvc_2015)\n    _set(\"cxx_inline_namespaces\",             msvc_2015)\n    _set(\"cxx_lambda_init_captures\",          msvc_2015)\n    _set(\"cxx_noexcept\",                      msvc_2015)\n    _set(\"cxx_return_type_deduction\",         msvc_2015)\n    _set(\"cxx_sizeof_member\",                 msvc_2015)\n    _set(\"cxx_thread_local\",                  msvc_2015)\n    _set(\"cxx_unicode_literals\",              msvc_2015)\n    _set(\"cxx_unrestricted_unions\",           msvc_2015)\n    _set(\"cxx_user_literals\",                 msvc_2015)\n    _set(\"cxx_reference_qualified_functions\", msvc_2015)\n\n    -- \"The copies and moves don't interact precisely like the Standard says they\n    -- should. For example, deletion of moves is specified to also suppress\n    -- copies, but Visual C++ in Visual Studio 2013 does not.\"\n    -- http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx\n    -- lists this as 'partial' in 2013\n    _set(\"cxx_deleted_functions\", msvc_2015)\n\n    -- http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx\n    -- Note 1. While previous version of VisualStudio said they supported these\n    -- they silently produced bad code, and are now marked as having partial\n    -- support in previous versions. The footnote says the support will be complete\n    -- in msvc 2015, so support the feature for that version, assuming that is true.\n    -- The blog post also says that VS 2013 Update 3 generates an error in cases\n    -- that previously produced bad code.\n    _set(\"cxx_generalized_initializers\", \"_MSC_FULL_VER >= 180030723\")\n\n    -- Microsoft now states they support contextual conversions in 2013 and above.\n    -- See footnote 6 at:\n    -- http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features-in-vs-2015-preview.aspx\n    _set(\"cxx_contextual_conversions\",         msvc_2013)\n    _set(\"cxx_default_function_template_args\", msvc_2013)\n    _set(\"cxx_defaulted_functions\",            msvc_2013)\n    _set(\"cxx_delegating_constructors\",        msvc_2013)\n    _set(\"cxx_explicit_conversions\",           msvc_2013)\n    _set(\"cxx_raw_string_literals\",            msvc_2013)\n    _set(\"cxx_uniform_initialization\",         msvc_2013)\n    _set(\"cxx_alias_templates\",                msvc_2013)\n\n    -- Support is documented, but possibly partly broken:\n    -- https://msdn.microsoft.com/en-us/library/hh567368.aspx\n    -- http://thread.gmane.org/gmane.comp.lib.boost.devel/244986/focus=245333\n    _set(\"cxx_variadic_templates\",           msvc_2013)\n\n    _set(\"cxx_enum_forward_declarations\",    msvc_2012)\n    _set(\"cxx_final\",                        msvc_2012)\n    _set(\"cxx_range_for\",                    msvc_2012)\n    _set(\"cxx_strong_enums\",                 msvc_2012)\n\n    _set(\"cxx_auto_type\",                    msvc_2010)\n    _set(\"cxx_decltype\",                     msvc_2010)\n    _set(\"cxx_extended_friend_declarations\", msvc_2010)\n    _set(\"cxx_extern_templates\",             msvc_2010)\n    _set(\"cxx_lambdas\",                      msvc_2010)\n    _set(\"cxx_local_type_template_args\",     msvc_2010)\n    _set(\"cxx_long_long_type\",               msvc_2010)\n    _set(\"cxx_nullptr\",                      msvc_2010)\n    _set(\"cxx_override\",                     msvc_2010)\n    _set(\"cxx_right_angle_brackets\",         msvc_2010)\n    _set(\"cxx_rvalue_references\",            msvc_2010)\n    _set(\"cxx_static_assert\",                msvc_2010)\n    _set(\"cxx_template_template_parameters\", msvc_2010)\n    _set(\"cxx_trailing_return_types\",        msvc_2010)\n    _set(\"cxx_variadic_macros\",              msvc_2010)\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\nimport(\"cfeatures\")\nimport(\"cxxfeatures\")\n\n-- get macro defines\nfunction _get_macro_defines(snippets, extension, opt)\n\n    -- make an stub source file\n    local sourcefile = os.tmpfile() .. extension\n    local objectfile = sourcefile .. \".obj\"\n    local binaryfile = sourcefile .. \".exe\"\n    io.writefile(sourcefile, \"#include <stdio.h>\\n\\nint main(int argc, char** argv)\\n{\\n\" .. table.concat(table.wrap(snippets), \"\\n\") .. \"\\nreturn 0;\\n}\\n\")\n\n    -- get defines\n    local results = {}\n    local defines = try\n    {\n        function ()\n            os.runv(opt.program, table.join(opt.flags or {}, {\"-nologo\", \"-Fo\" .. objectfile, sourcefile, \"-link\", \"-out:\" .. binaryfile}), {envs = opt.envs})\n            return os.iorunv(binaryfile, {}, {envs = opt.envs})\n        end\n    }\n    if defines then\n        for _, define in ipairs(defines:split(\"\\n\")) do\n            results[define] = true\n        end\n    end\n\n    -- remove files\n    os.tryrm(sourcefile)\n    os.tryrm(objectfile)\n    os.tryrm(binaryfile)\n    return results\nend\n\n-- set feature with condition\nfunction _set_feature(feature, condition)\n\n    -- init features\n    _g.features = _g.features or {}\n\n    -- get feature kind\n    local kind = feature:match(\"^(%w-)_\")\n    assert(kind, \"unknown kind for the feature: %s\", feature)\n\n    -- init language extensions\n    _g.extensions = _g.extensions or {c = \".c\", cxx = \".cpp\", objc = \".m\", objcxx = \".mm\"}\n\n    -- get extension\n    local extension = _g.extensions[kind]\n    assert(extension, \"not supported kind for the feature: %s\", feature)\n\n    -- make snippet\n    local snippet = format([[\n#if (%s)\n    printf(\"%s\\n\");\n#endif]], condition, feature)\n\n    -- init features with the given extension\n    local features = _g.features[extension] or {}\n    _g.features[extension] = features\n\n    -- set feature and snippet\n    features[feature] = snippet\nend\n\n-- set features\nfunction set_features(features)\n    for feature, condition in pairs(features) do\n        _set_feature(feature, condition)\n    end\nend\n\n-- check features\nfunction check_features(opt)\n\n    -- check features with all extensions\n    opt = opt or {}\n    local results = {}\n    for extension, features in pairs(_g.features) do\n\n        -- make snippets\n        local snippets = {}\n        for _, snippet in pairs(features) do\n            table.insert(snippets, snippet)\n        end\n\n        -- get defines\n        local defines = _get_macro_defines(snippets, extension, opt)\n\n        -- check features\n        for feature, _ in pairs(features) do\n            if defines[feature] then\n                results[feature] = true\n            end\n        end\n    end\n\n    -- ok?\n    return results\nend\n\n-- get features\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", flags = {}}\n--\n-- @return      the features\n--\nfunction main(opt)\n\n    -- set features for c\n    set_features(cfeatures())\n\n    -- set features for c++\n    set_features(cxxfeatures())\n\n    -- check features\n    return check_features(opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.language.language\")\nimport(\"core.cache.global_detectcache\")\nimport(\"core.base.hashset\")\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt)\n    local flag = flags[1]:gsub(\"/\", \"-\")\n    local known_flags = _g.known_flags\n    if known_flags == nil then\n        known_flags = hashset.from({\"-Ox\", \"-O1\", \"-O2\", \"-Od\", \"-MT\", \"-MD\", \"-MTd\", \"-MDd\", \"-EHsc\"})\n        _g.known_flags = known_flags\n    end\n    if known_flags:has(flag) then\n        return true\n    end\n    if flag:startswith(\"-D\") or\n       flag:startswith(\"-U\") or\n       flag:startswith(\"-I\") then\n        return true\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n    local key = \"core.tools.cl.has_flags\"\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = global_detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-?\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\")] = true\n            end\n        end\n        global_detectcache:set2(key, flagskey, allflags)\n        global_detectcache:save()\n    end\n    local flag = flags[1]:gsub(\"/\", \"-\")\n    if flag:startswith(\"-D\") or flag:startswith(\"-I\") then\n        return true\n    end\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    return opt.flagkind == \"cxxflags\" and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"cl_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    -- check it\n    local errors = nil\n    return try  {   function ()\n                        local tmpdir = os.tmpdir()\n                        local nuldev = os.nuldev()\n                        local tmpfile\n                        if not is_host(\"windows\") then\n                            tmpfile = os.tmpfile()\n                            nuldev = tmpfile\n                        end\n                        local _, errs = os.iorunv(opt.program, table.join(\"-c\", \"-nologo\", flags, \"-Fo\" .. nuldev, sourcefile),\n                                            {envs = opt.envs, curdir = tmpdir}) -- we need to switch to tmpdir to avoid generating some tmp files, e.g. /Zi -> vc140.pdb\n                        if tmpfile then\n                            os.tryrm(tmpfile)\n                        end\n                        if errs and #errs:trim() > 0 then\n                            return false, errs\n                        end\n                        return true\n                    end,\n                    catch { function (errs) errors = errs end }\n                }, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    opt = opt or {}\n    if not opt.tryrun then\n        if _check_from_knownargs(flags, opt) then\n            return true\n        end\n        if _check_from_arglist(flags, opt) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\nimport(\"parse_include\")\nimport(\"core.tool.toolchain\")\n\n-- get $VCInstallDir\nfunction _VCInstallDir()\n    local VCInstallDir = _g.VCInstallDir\n    if not VCInstallDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.VCInstallDir then\n                VCInstallDir = vcvars.VCInstallDir\n                _g.VCInstallDir = VCInstallDir\n            end\n        end\n    end\n    return VCInstallDir\nend\n\n-- get $WindowsSdkDir\nfunction _WindowsSdkDir()\n    local WindowsSdkDir = _g.WindowsSdkDir\n    if not WindowsSdkDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.WindowsSdkDir then\n                WindowsSdkDir = vcvars.WindowsSdkDir\n                _g.WindowsSdkDir = WindowsSdkDir\n            end\n        end\n    end\n    return WindowsSdkDir\nend\n\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    local VCInstallDir = _VCInstallDir()\n    local WindowsSdkDir = _WindowsSdkDir()\n    if (VCInstallDir and dep:startswith(VCInstallDir)) or (WindowsSdkDir and dep:startswith(WindowsSdkDir)) then\n        -- we ignore headerfiles in vc install directory\n        return\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- parse depsfiles from string\nfunction main(depsdata)\n    local results = hashset.new()\n    for _, line in ipairs(depsdata:split(\"\\n\", {plain = true})) do\n        local includefile = parse_include(line:trim())\n        if includefile then\n            includefile = _normailize_dep(includefile, os.projectdir())\n            if includefile then\n                results:insert(includefile)\n            end\n        end\n    end\n    return results:to_array()\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/parse_deps_json.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps_json.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\nimport(\"core.base.json\")\nimport(\"core.tool.toolchain\")\n\n-- get $VCInstallDir\nfunction _VCInstallDir()\n    local VCInstallDir = _g.VCInstallDir\n    if not VCInstallDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.VCInstallDir then\n                VCInstallDir = vcvars.VCInstallDir:lower() -- @note we need lower case for json/deps\n                _g.VCInstallDir = VCInstallDir\n            end\n        end\n    end\n    return VCInstallDir\nend\n\n-- get $WindowsSdkDir\nfunction _WindowsSdkDir()\n    local WindowsSdkDir = _g.WindowsSdkDir\n    if not WindowsSdkDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.WindowsSdkDir then\n                WindowsSdkDir = vcvars.WindowsSdkDir:lower() -- @note we need lower case for json/deps\n                _g.WindowsSdkDir = WindowsSdkDir\n            end\n        end\n    end\n    return WindowsSdkDir\nend\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    dep = dep:lower()\n    local VCInstallDir = _VCInstallDir()\n    local WindowsSdkDir = _WindowsSdkDir()\n    if (VCInstallDir and dep:startswith(VCInstallDir)) or (WindowsSdkDir and dep:startswith(WindowsSdkDir)) then\n        -- we ignore headerfiles in vc install directory\n        return\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- parse depsfiles from string\n--\n--[[\n{\n    \"Version\": \"1.2\",\n    \"Data\": {\n        \"Source\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\main.cpp\",\n        \"ProvidedModule\": \"\",\n        \"Includes\": [],\n        \"ImportedModules\": [\n            {\n                \"Name\": \"hello\",\n                \"BMI\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\hello.ifc\"\n            }\n        ],\n        \"ImportedHeaderUnits\": [\n            {\n                \"Header\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\header.hpp\",\n                \"BMI\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\header.hpp.ifc\"\n            }\n        ]\n    }\n}]]\nfunction main(depsdata)\n\n    -- decode json data first\n    depsdata = json.decode(depsdata)\n\n    -- get includes\n    local data\n    if depsdata then\n        data = depsdata.Data\n    end\n    if data then\n        includes = data.Includes\n        for _, item in ipairs(data.ImportedModules) do\n            local bmifile = item.BMI\n            if bmifile then\n                includes = includes or {}\n                table.insert(includes, bmifile)\n            end\n        end\n        for _, item in ipairs(data.ImportedHeaderUnits) do\n            local bmifile = item.BMI\n            if bmifile then\n                includes = includes or {}\n                table.insert(includes, bmifile)\n            end\n        end\n    end\n\n    -- translate it\n    local results = hashset.new()\n    local projectdir = os.projectdir():lower() -- we need to generate lower string, because json values are all lower\n    for _, includefile in ipairs(includes) do\n        includefile = _normailize_dep(includefile, projectdir)\n        if includefile then\n            results:insert(includefile)\n        end\n    end\n    return results:to_array()\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl/parse_include.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_include.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.tools.vstool\")\n\n-- probe include note prefix from cl\nfunction probe_include_note_from_cl()\n    local key = \"cldeps.parse_include.note\"\n    local note = detectcache:get(key)\n    if not note then\n        local runenvs = toolchain.load(\"msvc\"):runenvs()\n        local cl = find_tool(\"cl\", {envs = runenvs})\n        if cl then\n            local projectdir = os.tmpfile() .. \".cldeps\"\n            local sourcefile = path.join(projectdir, \"main.c\")\n            local headerfile = path.join(projectdir, \"foo.h\")\n            local objectfile = sourcefile .. \".obj\"\n            local outdata = try { function()\n                local argv = {\"-nologo\", \"-showIncludes\", \"-c\", \"-Fo\" .. objectfile, sourcefile}\n                io.writefile(headerfile, \"\\n\")\n                io.writefile(sourcefile, [[\n                    #include \"foo.h\"\n                    int main (int argc, char** argv) {\n                        return 0;\n                    }\n                ]])\n                return vstool.iorunv(cl.program, argv, {envs = runenvs, curdir = projectdir})\n            end}\n            if outdata then\n                for _, line in ipairs(outdata:split('\\n', {plain = true})) do\n                    note = line:match(\"^(.-:.-: )\")\n                    if note then\n                        break\n                    end\n                end\n            end\n            os.tryrm(projectdir)\n        end\n        detectcache:set(key, note)\n    end\n    return note\nend\n\n-- get include notes prefix, e.g. \"Note: including file: \"\n--\n-- @note we cannot get better solution to distinguish between `includes` and `error infos`\n--\nfunction get_include_notes()\n    local notes = _g.notes\n    if not notes then\n        notes = {}\n        local note = probe_include_note_from_cl()\n        if note then\n            table.insert(notes, note)\n        end\n        table.join2(notes, {\n            \"Note: including file: \", -- en\n            \"注意: 包含文件: \", -- zh\n            \"Remarque : inclusion du fichier : \", -- fr\n            \"メモ: インクルード ファイル: \" -- jp\n        })\n        _g.notes = notes\n    end\n    return notes\nend\n\n-- has include note?\nfunction has_include_note(line)\n    local note = _g.note\n    if note and line:startswith(note) then\n        return note\n    end\n\n    local notes = get_include_notes()\n    for idx, note in ipairs(notes) do\n        if line:startswith(note) then\n            _g.note = note\n            return note\n        end\n    end\nend\n\n-- parse note includes\nfunction main(line)\n    local note = has_include_note(line)\n    if note then\n        return line:sub(#note):trim()\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cl.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.hashset\")\nimport(\"core.cache.memcache\")\nimport(\"core.project.project\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\nimport(\"private.tools.vstool\")\nimport(\"core.tools.cl.parse_include\")\nimport(\"private.cache.build_cache\")\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init cxflags\n    self:set(\"cxflags\", \"-nologo\")\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- optimize\n        [\"-O0\"]                     = \"-Od\"\n    ,   [\"-Os\"]                     = \"-O1\"\n    ,   [\"-O3\"]                     = \"-Ox\"\n    ,   [\"-Ofast\"]                  = \"-Ox -fp:fast\"\n    ,   [\"-fomit-frame-pointer\"]    = \"-Oy\"\n\n        -- symbols\n    ,   [\"-g\"]                      = \"-Z7\"\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-Weverything\"]            = \"-Wall\"\n    ,   [\"-Wextra\"]                 = \"-W4\"\n    ,   [\"-Wall\"]                   = \"-W3\" -- = \"-Wall\" will enable too more warnings\n    ,   [\"-W1\"]                     = \"-W1\"\n    ,   [\"-W2\"]                     = \"-W2\"\n    ,   [\"-W3\"]                     = \"-W3\"\n    ,   [\"-Werror\"]                 = \"-WX\"\n    ,   [\"-Wswitch\"]                = \"-we4062\"\n    ,   [\"-Wswitch-enum\"]           = \"-we4061\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n    ,   [\"%-fno%-.*\"]               = \"\"\n\n        -- vectorexts\n    ,   [\"-mmmx\"]                   = \"-arch:MMX\"\n    ,   [\"-msse\"]                   = \"-arch:SSE\"\n    ,   [\"-msse2\"]                  = \"-arch:SSE2\"\n    ,   [\"-msse3\"]                  = \"-arch:SSE3\"\n    ,   [\"-mssse3\"]                 = \"-arch:SSSE3\"\n    ,   [\"-mavx\"]                   = \"-arch:AVX\"\n    ,   [\"-mavx2\"]                  = \"-arch:AVX2\"\n    ,   [\"-mfpu=.*\"]                = \"\"\n\n        -- language\n    ,   [\"-ansi\"]                   = \"\"\n    ,   [\"-std=c99\"]                = \"-TP\" -- compile as c++ files because msvc doesn't support c99\n    ,   [\"-std=c11\"]                = \"-std:c11\"\n    ,   [\"-std=c17\"]                = \"-std:c17\"\n    ,   [\"-std=c2x\"]                = \"-std:clatest\"\n    ,   [\"-std=c23\"]                = \"-std:clatest\"\n    ,   [\"-std=gnu99\"]              = \"-TP\" -- compile as c++ files because msvc doesn't support c99\n    ,   [\"-std=gnu11\"]              = \"-std:c11\"\n    ,   [\"-std=gnu17\"]              = \"-std:c17\"\n    ,   [\"-std=gnu2x\"]              = \"-std:clatest\"\n    ,   [\"-std=gnu23\"]              = \"-std:clatest\"\n    ,   [\"-std=.*\"]                 = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    })\nend\n\n-- is syntax check enabled?\nfunction _is_syntax_check()\n    return memcache.get(\"syntax_check\", \"enabled\") or false\nend\n\n-- make the symbol flags\nfunction nf_symbols(self, levels, opt)\n    local flags = nil\n    local values = hashset.from(levels)\n    if values:has(\"debug\") then\n        flags = {}\n        if values:has(\"edit\") then\n            table.insert(flags, \"-ZI\")\n        elseif values:has(\"embed\") then\n            table.insert(flags, \"-Z7\")\n        else\n            table.insert(flags, \"-Zi\")\n        end\n\n        -- generate *.pdb file\n        local symbolfile = nil\n        local target = opt.target\n        if target and target.symbolfile and not values:has(\"embed\") then\n            symbolfile = target:symbolfile()\n        end\n        if symbolfile then\n\n            -- ensure the object directory\n            local symboldir = path.directory(symbolfile)\n            if not os.isdir(symboldir) then\n                os.mkdir(symboldir)\n            end\n\n            -- check and add symbol output file\n            --\n            -- @note we need to use `{}` to wrap it to avoid expand it\n            -- https://github.com/xmake-io/xmake/issues/2061#issuecomment-1042590085\n            local pdbflags = {\"-Fd\" .. (target:is_static() and symbolfile or path.join(symboldir, \"compile.\" .. path.filename(symbolfile)))}\n            if self:has_flags({\"-FS\", \"-Fd\" .. os.nuldev() .. \".pdb\"}, \"cxflags\", { flagskey = \"-FS -Fd\" }) then\n                table.insert(pdbflags, 1, \"-FS\")\n            end\n            table.insert(flags, pdbflags)\n        end\n    end\n    return flags\nend\n\n-- make the fp-model flag\nfunction nf_fpmodel(self, level)\n    local maps = {\n        precise    = \"-fp:precise\" -- default\n    ,   fast       = \"-fp:fast\"\n    ,   strict     = \"-fp:strict\"\n    ,   except     = \"-fp:except\"\n    ,   noexcept   = \"-fp:except-\"\n    }\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warnings(self, levels)\n    local flags = {}\n    local values = hashset.from(levels)\n    if values:has(\"all\") and values:has(\"extra\") then\n        table.insert(flags, \"-W4\")\n        values:remove(\"all\")\n        values:remove(\"extra\")\n    end\n\n    local maps = {\n        none       = \"-w\"\n    ,   less       = \"-W1\"\n    ,   more       = \"-W3\"\n    ,   all        = \"-W3\" -- = \"-Wall\" will enable too more warnings\n    ,   allextra   = \"-W4\"\n    ,   everything = \"-Wall\"\n    ,   error      = \"-WX\"\n    }\n    for _, level in values:orderkeys() do\n        local flag = maps[level]\n        if flag then\n            table.insert(flags, flag)\n        end\n    end\n    if #flags > 0 then\n        return flags\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none        = \"-Od\"\n    ,   faster      = \"-Ox\"\n    ,   fastest     = \"-O2\"\n    ,   smallest    = \"-O1 -GL\" -- /GL and (/OPT:REF is on by default in linker), we need to enable /ltcg\n    ,   aggressive  = \"-O2\"\n    }\n    return maps[level]\nend\n\n-- make the runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime then\n        local maps = {\n            MT = \"-MT\",\n            MD = \"-MD\",\n            MTd = \"-MTd\",\n            MDd = \"-MDd\"\n        }\n        return maps[runtime]\n    end\nend\n\n-- make the vector extension flag\nfunction nf_vectorext(self, extension)\n    local maps =\n    {\n        sse        = \"-arch:SSE\"\n    ,   sse2       = \"-arch:SSE2\"\n    ,   [\"sse4.2\"] = \"/d2archSSE42\" -- the only undocumented way works, @see https://github.com/xmake-io/xmake/issues/3786\n    ,   avx        = \"-arch:AVX\"\n    ,   avx2       = \"-arch:AVX2\"\n    ,   avx512     = \"-arch:AVX512\" -- for msvc 2019+ avx512 support\n    ,   fma        = \"-arch:AVX2\"\n    ,   all        = {\"-arch:SSE\", \"-arch:SSE2\", \"/d2archSSE42\", \"-arch:AVX\", \"-arch:AVX2\", \"-arch:AVX512\"}\n    }\n    local flags = maps[extension]\n    if flags then\n        -- @see https://github.com/xmake-io/xmake/issues/5499\n        if type(flags) == \"string\" then\n            return flags\n        else\n            local result = {}\n            for _, flag in ipairs(flags) do\n                if self:has_flags(flag, \"cxflags\") then\n                    table.insert(result, flag)\n                end\n            end\n            if #result > 0 then\n                return table.unwrap(result)\n            end\n        end\n    end\nend\n\n-- make the language flag\n-- clang-cl should also use it, @see https://github.com/xmake-io/xmake/issues/2211#issuecomment-1083322178\nfunction nf_language(self, stdname)\n\n    -- the stdc maps\n    if _g.cmaps == nil then\n        _g.cmaps =\n        {\n            -- stdc\n            c99       = \"-TP\" -- compile as c++ files because older msvc only support c89\n        ,   gnu99     = \"-TP\"\n        ,   c11       = {\"-std:c11\", \"-std:clatest\", \"-TP\"}\n        ,   gnu11     = {\"-std:c11\", \"-std:clatest\", \"-TP\"}\n        ,   c17       = {\"-std:c17\", \"-std:clatest\", \"-TP\"}\n        ,   gnu17     = {\"-std:c17\", \"-std:clatest\", \"-TP\"}\n        ,   c2x       = {\"-std:c23\", \"-std:clatest\", \"-TP\"}\n        ,   gnu2x     = {\"-std:c23\", \"-std:clatest\", \"-TP\"}\n        ,   c23       = {\"-std:c23\", \"-std:clatest\", \"-TP\"}\n        ,   gnu23     = {\"-std:c23\", \"-std:clatest\", \"-TP\"}\n        ,   clatest   = {\"-std:clatest\", \"-std:c23\", \"-std:c17\", \"-std:c11\", \"-TP\"}\n        ,   gnulatest   = {\"-std:clatest\", \"-std:c23\", \"-std:c17\", \"-std:c11\", \"-TP\"}\n        }\n    end\n\n    -- the stdc++ maps\n    if _g.cxxmaps == nil then\n        -- clang-cl with c++23preview does not work for c++ modules\n        -- https://github.com/xmake-io/xmake/issues/7169\n        local cxx23 = {\"-std:c++23\", \"-std:c++23preview\", \"-std:c++latest\"}\n        if self:name() == \"clang_cl\" then\n            cxx23 = {\"-std:c++23\", \"-std:c++latest\"}\n        end\n        local cxx2b = cxx23\n        _g.cxxmaps =\n        {\n            cxx11       = \"-std:c++11\"\n        ,   gnuxx11     = \"-std:c++11\"\n        ,   cxx14       = \"-std:c++14\"\n        ,   gnuxx14     = \"-std:c++14\"\n        ,   cxx17       = \"-std:c++17\"\n        ,   gnuxx17     = \"-std:c++17\"\n        ,   cxx1z       = \"-std:c++17\"\n        ,   gnuxx1z     = \"-std:c++17\"\n        ,   cxx20       = {\"-std:c++20\", \"-std:c++latest\"}\n        ,   gnuxx20     = {\"-std:c++20\", \"-std:c++latest\"}\n        ,   cxx2a       = {\"-std:c++20\", \"-std:c++latest\"}\n        ,   gnuxx2a     = {\"-std:c++20\", \"-std:c++latest\"}\n        ,   cxx23       = cxx23\n        ,   gnuxx23     = cxx23\n        ,   cxx2b       = cxx2b\n        ,   gnuxx2b     = cxx2b\n        ,   cxx26       = {\"-std:c++26\", \"-std:c++latest\"}\n        ,   gnuxx26     = {\"-std:c++26\", \"-std:c++latest\"}\n        ,   cxxlatest   = \"-std:c++latest\"\n        ,   gnuxxlatest = \"-std:c++latest\"\n        }\n        local cxxmaps2 = {}\n        for k, v in pairs(_g.cxxmaps) do\n            cxxmaps2[k:gsub(\"xx\", \"++\")] = v\n        end\n        table.join2(_g.cxxmaps, cxxmaps2)\n    end\n\n    -- select maps\n    local maps = _g.cmaps\n    if self:kind() == \"cxx\" or self:kind() == \"mxx\" then\n        maps = _g.cxxmaps\n    end\n\n    -- map it\n    local result = maps[stdname]\n    if type(result) == \"table\" then\n        for _, v in ipairs(result) do\n            if self:has_flags(v, \"cxflags\") then\n                result = v\n                maps[stdname] = result\n                return result\n            end\n        end\n    else\n        return result\n    end\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. path.translate(dir)}\nend\n\n-- make the force include flag\nfunction nf_forceinclude(self, headerfile, opt)\n    local target = opt.target\n    local sourcekinds = target and target:extraconf(\"forceincludes\", headerfile, \"sourcekinds\")\n    if not sourcekinds or table.contains(table.wrap(sourcekinds), self:kind()) then\n        return {\"-FI\", headerfile}\n    end\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    local has_external_includedir = _g._HAS_EXTERNAL_INCLUDEDIR\n    if has_external_includedir == nil then\n        if self:has_flags({\"-external:W0\", \"-external:I\" .. os.args(path.translate(dir))}, \"cxflags\", {flagskey = \"cl_external_includedir\"}) then\n            has_external_includedir = 2 -- full support\n        elseif self:has_flags({\"-experimental:external\", \"-external:W0\", \"-external:I\" .. os.args(path.translate(dir))}, \"cxflags\", {flagskey = \"cl_external_includedir_experimental\"}) then\n            has_external_includedir = 1 -- experimental support\n        end\n        has_external_includedir = has_external_includedir or 0\n        _g._HAS_EXTERNAL_INCLUDEDIR = has_external_includedir\n    end\n    if has_external_includedir >= 2 then\n        return {\"-external:W0\", \"-external:I\" .. path.translate(dir)}\n    elseif has_external_includedir >= 1 then\n        return {\"-experimental:external\", \"-external:W0\", \"-external:I\" .. path.translate(dir)}\n    else\n        return nf_includedir(self, dir)\n    end\nend\n\n-- make the exception flag\n--\n-- e.g.\n-- set_exceptions(\"cxx\")\n-- set_exceptions(\"no-cxx\")\nfunction nf_exception(self, exp)\n    local maps = {\n        cxx = \"/EHsc\",\n        [\"no-cxx\"] = \"/EHsc-\"\n    }\n    return maps[exp]\nend\n\n-- make the encoding flag\n-- @see https://github.com/xmake-io/xmake/issues/2471\n--\n-- e.g.\n-- set_encodings(\"utf-8\")\n-- set_encodings(\"source:utf-8\", \"target:utf-8\")\nfunction nf_encoding(self, encoding)\n    local kind\n    local charset\n    local splitinfo = encoding:split(\":\")\n    if #splitinfo > 1 then\n        kind = splitinfo[1]\n        charset = splitinfo[2]\n    else\n        charset = encoding\n    end\n    local charsets = {\n        [\"utf-8\"] = \"utf-8\",\n        utf8 = \"utf-8\",\n        gb2312 = \"gb2312\"\n    }\n    local flags = {}\n    charset = charsets[charset:lower()]\n    if charset then\n        if not kind and charset == \"utf-8\" then\n            table.insert(flags, \"/utf-8\")\n        else\n            if kind == \"source\" or not kind then\n                table.insert(flags, \"-source-charset:\" .. charset)\n            end\n            if kind == \"target\" or not kind then\n                table.insert(flags, \"-execution-charset:\" .. charset)\n            end\n        end\n    end\n    if #flags > 0 then\n        return flags\n    end\nend\n\n-- make the c precompiled header flag\nfunction nf_pcheader(self, pcheaderfile, opt)\n    if self:kind() == \"cc\" then\n        local target = opt.target\n        local objectfiles = target:objectfiles()\n        if objectfiles then\n            table.insert(objectfiles, target:pcoutputfile(\"c\") .. \".obj\")\n        end\n        return {\"-Yu\" .. path.absolute(pcheaderfile), \"-FI\" .. path.absolute(pcheaderfile), \"-Fp\" .. target:pcoutputfile(\"c\")}\n    end\nend\n\n-- make the c++ precompiled header flag\nfunction nf_pcxxheader(self, pcheaderfile, opt)\n    if self:kind() == \"cxx\" then\n        local target = opt.target\n        local objectfiles = target:objectfiles()\n        if objectfiles then\n            table.insert(objectfiles, target:pcoutputfile(\"cxx\") .. \".obj\")\n        end\n        return {\"-Yu\" .. path.absolute(pcheaderfile), \"-FI\" .. path.absolute(pcheaderfile), \"-Fp\" .. target:pcoutputfile(\"cxx\")}\n    end\nend\n\n-- add the special flags for the given source file of target\n--\n-- @note only it called when fileconfig is set\n--\nfunction add_sourceflags(self, sourcefile, fileconfig, target, targetkind)\n\n    -- add language type flags explicitly if the sourcekind is changed.\n    --\n    -- because compiler maybe compile `.c` as c++.\n    -- e.g.\n    --   add_files(\"*.c\", {sourcekind = \"cxx\"})\n    --\n    local sourcekind = fileconfig.sourcekind\n    if sourcekind then\n        local maps = {cc = \"-TC\", cxx = \"-TP\"}\n        return maps[sourcekind]\n    end\nend\n\n-- make the compile arguments list for the precompiled header\nfunction _compargv_pch(self, pcheaderfile, pcoutputfile, flags)\n\n    -- remove \"-Yuxxx.h\" and \"-Fpxxx.pch\"\n    local pchflags = {}\n    for _, flag in ipairs(flags) do\n        if not flag:find(\"-Yu\", 1, true) and not flag:find(\"-Fp\", 1, true) then\n            table.insert(pchflags, flag)\n        end\n    end\n\n    -- compile as c/c++ source file\n    if self:kind() == \"cc\" then\n        table.insert(pchflags, \"-TC\")\n    elseif self:kind() == \"cxx\" then\n        table.insert(pchflags, \"-TP\")\n    end\n\n    -- make the compile arguments list\n    return self:program(), table.join(\"-c\", \"-Yc\", pchflags, \"-Fp\" .. pcoutputfile, \"-Fo\" .. pcoutputfile .. \".obj\", pcheaderfile)\nend\n\n-- has /sourceDependencies xxx.json @see https://github.com/xmake-io/xmake/issues/868?\nfunction _has_source_dependencies(self)\n    local has_source_dependencies = _g._HAS_SOURCE_DEPENDENCIES\n    if has_source_dependencies == nil then\n        local source_dependencies_jsonfile = os.tmpfile() .. \".json\"\n        if self:has_flags(\"/sourceDependencies \" .. source_dependencies_jsonfile, \"cxflags\", {flagskey = \"cl_sourceDependencies\",\n                on_check = function (ok, errors)\n                    -- even if cl does not support /sourceDependencies, it will not interrupt compilation\n                    if ok and not os.isfile(source_dependencies_jsonfile) then\n                        ok = false\n                    end\n                    return ok, errors\n                end}) then\n            has_source_dependencies = true\n        end\n        has_source_dependencies = has_source_dependencies or false\n        _g._HAS_SOURCE_DEPENDENCIES = has_source_dependencies\n    end\n    return has_source_dependencies\nend\n\nfunction _is_in_vstudio()\n    local is_in_vstudio = _g._IS_IN_VSTUDIO\n    if is_in_vstudio == nil then\n        is_in_vstudio = os.getenv(\"XMAKE_IN_VSTUDIO\") or false\n        _g._IS_IN_VSTUDIO = is_in_vstudio\n    end\n    return is_in_vstudio\nend\n\n-- get preprocess file path\nfunction _get_cppfile(sourcefile, objectfile)\n    return path.join(path.directory(objectfile), \"__cpp_\" .. path.basename(objectfile) .. path.extension(sourcefile))\nend\n\n-- do preprocess\nfunction _preprocess(program, argv, opt)\n\n    -- get flags and source file\n    local flags = {}\n    local cppflags = {}\n    local skipped = 0\n    local objectfile\n    local pdbfile\n    local sourcefile = argv[#argv]\n    local extension = path.extension(sourcefile)\n    for _, flag in ipairs(argv) do\n        if flag:startswith(\"-Fo\") or flag:startswith(\"/Fo\") then\n            objectfile = flag:sub(4)\n            break\n        end\n\n        -- get preprocessor flags\n        -- TODO fix precompiled header bug for /P + /FI\n        local target = opt.target\n        if target and (flag:startswith(\"-FI\") or flag:startswith(\"/FI\")) then\n            local pcheaderfile = target:get(\"pcheader\") or target:get(\"pcxxheader\")\n            if pcheaderfile then\n                flag = \"-FI\" .. path.absolute(pcheaderfile)\n            end\n        end\n        table.insert(cppflags, flag)\n\n        -- get compiler flags\n        if flag == \"-showIncludes\" or flag == \"/showIncludes\" or\n           (flag:startswith(\"-I\") and #flag > 2) or (flag:startswith(\"/I\") and #flag > 2) or\n           flag:startswith(\"-external:\") or flag:startswith(\"/external:\") then\n            skipped = 1\n        -- @note we cannot ignore precompiled flags when compiling pch, @see https://github.com/xmake-io/xmake/issues/2885\n        elseif not toolchain_utils.is_cxx_headerext(extension) and (\n           flag:startswith(\"-Yu\") or flag:startswith(\"/Yu\") or\n           flag:startswith(\"-FI\") or flag:startswith(\"/FI\") or\n           flag:startswith(\"-Fp\") or flag:startswith(\"/Fp\")) then\n            skipped = 1\n        elseif flag == \"-I\" or flag == \"-sourceDependencies\" or flag == \"/sourceDependencies\" then\n            skipped = 2\n        elseif opt.remote and flag:startswith(\"-Fd\") or flag:startswith(\"/Fd\") then\n            skipped = 1\n            pdbfile = flag:sub(4) --TODO handle remote pdb\n        end\n        if skipped > 0 then\n            skipped = skipped - 1\n        else\n            table.insert(flags, flag)\n        end\n    end\n    assert(objectfile and sourcefile, \"%s: iorunv(%s): invalid arguments!\", self, program)\n\n    -- is precompiled header?\n    if objectfile:endswith(\".pch\") then\n        return false\n    end\n\n    -- disable linemarkers?\n    local linemarkers = _g.linemarkers\n    if linemarkers == nil then\n        if os.isfile(os.projectfile()) and project.policy(\"preprocessor.linemarkers\") == false then\n            linemarkers = false\n        else\n            linemarkers = true\n        end\n        _g.linemarkers = linemarkers\n    end\n\n    -- do preprocess\n    local cppfile = _get_cppfile(sourcefile, objectfile)\n    local cppfiledir = path.directory(cppfile)\n    if not os.isdir(cppfiledir) then\n        os.mkdir(cppfiledir)\n    end\n    if linemarkers == false then\n        table.insert(cppflags, \"-EP\")\n    else\n        -- we cannot use `/P`, @see https://github.com/xmake-io/xmake/issues/2445\n        table.insert(cppflags, \"-E\")\n    end\n    table.insert(cppflags, sourcefile)\n    return try{ function()\n        -- https://github.com/xmake-io/xmake/issues/2902#issuecomment-1326934902\n        local outfile = cppfile\n        local errfile = os.tmpfile() .. \".i.err\"\n        local inherit_handles_safely = true\n        if not winos.inherit_handles_safely() then\n            outfile = os.tmpfile() .. \".i.out\"\n            inherit_handles_safely = false\n        end\n        os.execv(program, winos.cmdargv(cppflags), table.join(opt, {stdout = outfile, stderr = errfile}))\n        local errdata\n        if os.isfile(errfile) then\n            errdata = io.readfile(errfile)\n        end\n        os.tryrm(errfile)\n        if not inherit_handles_safely then\n            os.cp(outfile, cppfile)\n            os.tryrm(outfile)\n        end\n        -- includes information will be output to stderr instead of stdout now\n        return {outdata = errdata, errdata = errdata,\n                sourcefile = sourcefile, objectfile = objectfile, cppfile = cppfile, cppflags = flags,\n                pdbfile = pdbfile}\n    end}\nend\n\n-- compile preprocessed file\nfunction _compile_preprocessed_file(program, cppinfo, opt)\n    local outdata, errdata = vstool.iorunv(program, winos.cmdargv(table.join(cppinfo.cppflags, \"-Fo\" .. cppinfo.objectfile, cppinfo.cppfile)), opt)\n    -- we need to get warning information from output\n    cppinfo.outdata = outdata\n    cppinfo.errdata = errdata\nend\n\n-- do compile\nfunction _compile(self, sourcefile, objectfile, compflags, opt)\n    opt = opt or {}\n    local function _compile_fallback()\n        local program, argv = compargv(self, sourcefile, objectfile, compflags, opt)\n        return vstool.iorunv(program, argv, {envs = self:runenvs()})\n    end\n    local cppinfo\n    if distcc_build_client.is_distccjob() and distcc_build_client.singleton():has_freejobs() then\n        local program, argv = compargv(self, sourcefile, objectfile, compflags, table.join(opt, {rawargs = true}))\n        cppinfo = distcc_build_client.singleton():compile(program, argv, {envs = self:runenvs(),\n            preprocess = _preprocess, compile = _compile_preprocessed_file, compile_fallback = _compile_fallback,\n            target = opt.target, tool = self, remote = true})\n    elseif build_cache.is_enabled(opt.target) and build_cache.is_supported(self:kind()) then\n        local program, argv = compargv(self, sourcefile, objectfile, compflags, table.join(opt, {rawargs = true}))\n        cppinfo = build_cache.build(program, argv, {envs = self:runenvs(),\n            preprocess = _preprocess, compile = _compile_preprocessed_file, compile_fallback = _compile_fallback,\n            target = opt.target, tool = self})\n    end\n    if cppinfo then\n        return cppinfo.outdata, cppinfo.errdata\n    else\n        return _compile_fallback()\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags, opt)\n    opt = opt or {}\n\n    -- precompiled header?\n    local extension = path.extension(sourcefile)\n    if toolchain_utils.is_cxx_headerext(extension) then\n        return _compargv_pch(self, sourcefile, objectfile, flags)\n    end\n\n    -- if syntax-only, add /Zs and skip -c and -Fo\n    if _is_syntax_check() then\n        table.insert(flags, \"/Zs\")\n        local argv = table.join(flags, sourcefile)\n        return self:program(), (opt and opt.rawargs) and argv or winos.cmdargv(argv)\n    end\n\n    -- suppress clang-cl warnings\n    -- clang-cl: warning: argument unused during compilation: '-c' [-Wunused-command-line-argument]\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/7049\n    local argv = {}\n    if not (self:name() == \"clang_cl\" and objectfile:endswith(\".pcm\")) then\n        table.insert(argv, \"-c\")\n    end\n\n    -- make the compile arguments list\n    table.join2(argv, flags, \"-Fo\" .. objectfile, sourcefile)\n    return self:program(), (opt and opt.rawargs) and argv or winos.cmdargv(argv)\nend\n\n-- show warnings\nfunction _show_warnings(self, output, sourcefile)\n    local lines = {}\n    local has_warnings = false\n    local has_source_dependencies = _has_source_dependencies(self)\n    for _, line in ipairs(output:split(\"\\n\", {plain = true})) do\n        line = line:rtrim()\n        if #line > 0 then\n            local skip = false\n\n            -- filter includes notes: \"Note: including file: xxx.h\"\n            if not has_source_dependencies and parse_include.has_include_note(line) then\n                skip = true\n            end\n\n            -- filter source filename echo\n            --\n            -- e.g.\n            -- main.cpp     <-- skip it\n            -- src\\main.cpp(2): warning C5295: #warning xxx\n            --\n            if not skip then\n                -- we don't need use isfile() to check it, because it's too slow\n                if sourcefile:endswith(line) and not line:find(\":\", 1, true) then\n                    skip = true\n                end\n            end\n\n            if not skip then\n                table.insert(lines, line)\n                if line:find(\"warning\", 1, true) then\n                    has_warnings = true\n                end\n            end\n        end\n    end\n\n    if has_warnings and #lines > 0 then\n        if not option.get(\"diagnosis\") then\n            lines = table.slice(lines, 1, (#lines > 16 and 16 or #lines))\n        end\n        local warnings = table.concat(lines, \"\\r\\n\")\n        progress.show_output(\"${color.warning}%s\", warnings)\n    end\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    local objectdir = path.directory(objectfile)\n    if not os.isdir(objectdir) then\n        os.mkdir(objectdir)\n    end\n\n    -- compile it\n    local depfile = nil\n    local outdata = try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if dependinfo then\n                if _has_source_dependencies(self) then\n                    depfile = os.tmpfile() .. \".json\"\n                    compflags = table.join(flags, \"/sourceDependencies\", depfile)\n                else\n                    compflags = table.join(flags, \"-showIncludes\")\n                end\n            end\n\n            -- we need to show full file path to goto error position if xmake is called in vstudio\n            -- https://github.com/xmake-io/xmake/issues/1049\n            if _is_in_vstudio() then\n                if compflags == flags then\n                    compflags = table.join(flags, \"-FC\")\n                else\n                    table.join2(compflags, \"-FC\")\n                end\n            end\n\n            -- do compile\n            return _compile(self, sourcefile, objectfile, compflags, opt)\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- remove preprocess file\n                local cppfile = _get_cppfile(sourcefile, objectfile)\n                os.tryrm(cppfile)\n\n                -- use cl/stdout as errors first from vstool.iorunv()\n                if type(errors) == \"table\" then\n                    local errs = errors.stdout or \"\"\n                    errs = errs .. (errors.stderr or \"\")\n                    errors = errs\n                end\n\n                local results = \"\"\n                if depfile then\n                    results = tostring(errors)\n                else\n                    -- filter includes notes: \"Note: including file: xxx.h\", @note maybe not english language\n                    for _, line in ipairs(tostring(errors):split(\"\\n\", {plain = true})) do\n                        line = line:rtrim()\n                        if not parse_include.has_include_note(line) then\n                            results = results .. line .. \"\\r\\n\"\n                        end\n                    end\n                end\n                if not option.get(\"verbose\") then\n                    results = results .. \"\\n  ${yellow}> in ${bright}\" .. sourcefile\n                end\n                raise(results)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                if ok and policy.build_warnings(opt) then\n                    local output = outdata or \"\"\n                    if #output:trim() == 0 then\n                        output = errdata or \"\"\n                    end\n                    if #output > 0 then\n                        _show_warnings(self, output, sourcefile)\n                    end\n                end\n            end\n        }\n    }\n\n    -- generate the dependent includes\n    if dependinfo then\n        if depfile and os.isfile(depfile) then\n            dependinfo.depfiles_format = \"cl_json\"\n            dependinfo.depfiles = io.readfile(depfile)\n            os.tryrm(depfile)\n        elseif outdata then\n            dependinfo.depfiles_format = \"cl\"\n            dependinfo.depfiles = outdata\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl2000/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.cl6x.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl2000/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\ninherit(\"core.tools.cl6x.parse_deps\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl2000.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cl2000.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-m3\"\n    ,   aggressive = \"-O3\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if not lib:endswith(\".a\") and not lib:endswith(\".so\") then\n         lib = \"lib\" .. lib .. \".a\"\n    end\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-i\" .. path.translate(dir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir, opt)\n    opt = opt or {}\n    local extra = opt.extra\n    if extra and extra.installonly then\n        return\n    end\n    dir = path.translate(dir)\n    return {\"-rpath=\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    local argv = table.join(\"-z\", \"--output_file=\" .. targetfile, objectfiles, flags)\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n    if option.get(\"verbose\") then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", \"--preproc_with_compile\", flags, \"--output_file=\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-ppd=\" .. depfile)\n            end\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"cl2000\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl6x/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt, islinker)\n    local flag = flags[1]\n    if not islinker then\n        if flag:startswith(\"-D\") or\n           flag:startswith(\"-U\") or\n           flag:startswith(\"-I\") then\n            return true\n        end\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.cl6x.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"cl6x_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-z\", \"--output_file=\" .. tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-c\", \"--output_file=\" .. tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun then\n        if _check_from_arglist(flags, opt, islinker) then\n            return true\n        end\n        if _check_from_knownargs(flags, opt, islinker) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl6x/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    -- escape characters, e.g. \\#Qt.Widget_pch.h -> #Qt.Widget_pch.h\n    -- @see https://github.com/xmake-io/xmake/issues/4134\n    -- https://github.com/xmake-io/xmake/issues/4273\n    if not is_host(\"windows\") then\n        dep = dep:gsub(\"\\\\(.)\", \"%1\")\n    end\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- parse depsfiles from string\n--\n-- parse_deps(io.readfile(depfile, {continuation = \"\\\\\"}))\n--\n-- eg.\n--\n-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.c\n-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.h\n--\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/main.c\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/foo.h\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/bar.h\n-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/zoo.h\n--\nfunction main(depsdata, opt)\n    local results = hashset.new()\n    local projectdir = os.projectdir()\n    local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first\n    local plain = {plain = true}\n    for _, includefile in ipairs(line:split('\\n', plain)) do -- it will trim all internal spaces without `{strict = true}`\n        includefile = includefile:split(\": \", plain)[2]\n        if includefile and #includefile > 0 then\n            includefile = _normailize_dep(includefile, projectdir)\n            if includefile then\n                results:insert(includefile)\n            end\n        end\n    end\n    return results:to_array()\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/cl6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cl6x.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-m3\"\n    ,   aggressive = \"-O3\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if not lib:endswith(\".a\") and not lib:endswith(\".so\") then\n         lib = \"lib\" .. lib .. \".a\"\n    end\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-i\" .. path.translate(dir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir, opt)\n    opt = opt or {}\n    local extra = opt.extra\n    if extra and extra.installonly then\n        return\n    end\n    dir = path.translate(dir)\n    return {\"-rpath=\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    local argv = table.join(\"-z\", \"--output_file=\" .. targetfile, objectfiles, flags)\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n    if option.get(\"verbose\") then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", \"--preproc_with_compile\", flags, \"--output_file=\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-ppd=\" .. depfile)\n            end\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"cl6x\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cl_json/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\nimport(\"core.base.json\")\nimport(\"core.tool.toolchain\")\n\n-- get $VCInstallDir\nfunction _VCInstallDir()\n    local VCInstallDir = _g.VCInstallDir\n    if not VCInstallDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.VCInstallDir then\n                VCInstallDir = vcvars.VCInstallDir:lower() -- @note we need lower case for json/deps\n                _g.VCInstallDir = VCInstallDir\n            end\n        end\n    end\n    return VCInstallDir\nend\n\n-- get $WindowsSdkDir\nfunction _WindowsSdkDir()\n    local WindowsSdkDir = _g.WindowsSdkDir\n    if not WindowsSdkDir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.WindowsSdkDir then\n                WindowsSdkDir = vcvars.WindowsSdkDir:lower() -- @note we need lower case for json/deps\n                _g.WindowsSdkDir = WindowsSdkDir\n            end\n        end\n    end\n    return WindowsSdkDir\nend\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    dep = dep:lower()\n    local VCInstallDir = _VCInstallDir()\n    local WindowsSdkDir = _WindowsSdkDir()\n    if (VCInstallDir and dep:startswith(VCInstallDir)) or (WindowsSdkDir and dep:startswith(WindowsSdkDir)) then\n        -- we ignore headerfiles in vc install directory\n        return\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- parse depsfiles from string\n--\n--[[\n{\n    \"Version\": \"1.2\",\n    \"Data\": {\n        \"Source\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\main.cpp\",\n        \"ProvidedModule\": \"\",\n        \"Includes\": [],\n        \"ImportedModules\": [\n            {\n                \"Name\": \"hello\",\n                \"BMI\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\hello.ifc\"\n            }\n        ],\n        \"ImportedHeaderUnits\": [\n            {\n                \"Header\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\header.hpp\",\n                \"BMI\": \"c:\\users\\ruki\\desktop\\user_headerunit\\src\\header.hpp.ifc\"\n            }\n        ]\n    }\n}]]\nfunction main(depsdata)\n\n    -- decode json data first\n    depsdata = json.decode(depsdata)\n\n    -- get includes\n    local data\n    if depsdata then\n        data = depsdata.Data\n    end\n    if data then\n        includes = data.Includes\n        for _, item in ipairs(data.ImportedModules) do\n            local bmifile = item.BMI\n            if bmifile then\n                includes = includes or {}\n                table.insert(includes, bmifile)\n            end\n        end\n        for _, item in ipairs(data.ImportedHeaderUnits) do\n            local bmifile = item.BMI\n            if bmifile then\n                includes = includes or {}\n                table.insert(includes, bmifile)\n            end\n        end\n    end\n\n    -- translate it\n    local results = hashset.new()\n    local projectdir = os.projectdir():lower() -- we need to generate lower string, because json values are all lower\n    for _, includefile in ipairs(includes) do\n        includefile = _normailize_dep(includefile, projectdir)\n        if includefile then\n            results:insert(includefile)\n        end\n    end\n    return results:to_array()\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang/cfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.gcc.cfeatures\")\n\n-- set features\nfunction _set(feature, condition)\n    _g.features[feature] = condition\nend\n\n-- get features\nfunction main()\n\n    -- init features\n    _g.features = cfeatures()\n\n    -- init conditions\n    -- clang -std=c11 -dM -E - < /dev/null | grep __STDC_VERSION__\n    local clang_minver = \"((__clang_major__ * 100) + __clang_minor__) >= 304\"\n    local c17          = clang_minver .. \" && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L\"\n    local c11          = clang_minver .. \" && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L\"\n    local c99          = clang_minver .. \" && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\"\n    local c90          = clang_minver\n\n    -- set language standard supports\n    _set(\"c_std_89\", c90)\n    _set(\"c_std_99\", c99)\n    _set(\"c_std_11\", c11)\n    _set(\"c_std_17\", c17)\n\n    -- set features\n    _set(\"c_static_assert\",       c11)\n    _set(\"c_restrict\",            c99)\n    _set(\"c_variadic_macros\",     c99)\n    _set(\"c_function_prototypes\", c90)\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang/cxxfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.gcc.cxxfeatures\")\n\n-- set features\nfunction _set(feature, condition)\n    _g.features[feature] = condition\nend\n\n-- get features\n--\n-- @see http://clang.llvm.org/cxx_status.html\n--\n-- porting from Modules/Compiler/Clang-CXX-FeatureTests.cmake\n--\nfunction main()\n\n    -- init features\n    _g.features = cxxfeatures()\n\n    -- init conditions\n    -- clang -x c++ -std=c++20 -dM -E - < /dev/null | grep __cplusplus\n    local clang_minver  = \"((__clang_major__ * 100) + __clang_minor__) >= 301\"\n    local clang80_cxx20 = \"((__clang_major__ * 100) + __clang_minor__) >= 800 && __cplusplus >= 202002L\"\n    local clang50_cxx17 = \"((__clang_major__ * 100) + __clang_minor__) >= 500 && __cplusplus >= 201703L\"\n    local clang34_cxx14 = \"((__clang_major__ * 100) + __clang_minor__) >= 304 && __cplusplus > 201103L\"\n    local clang31_cxx11 = clang_minver .. \" && __cplusplus >= 201103L\"\n    local clang29_cxx11 = clang_minver .. \" && __cplusplus >= 201103L\"\n    local clang_cxx98   = clang_minver .. \" && __cplusplus >= 199711L\"\n\n    -- set language standard supports\n    _set(\"cxx_std_98\", clang_cxx98)\n    _set(\"cxx_std_11\", clang29_cxx11)\n    _set(\"cxx_std_14\", clang34_cxx14)\n    _set(\"cxx_std_17\", clang50_cxx17)\n    _set(\"cxx_std_20\", clang80_cxx20)\n\n    -- set features for __has_feature()\n    local features_of_has_feature =\n    {\n         \"cxx_alias_templates\"\n    ,    \"cxx_alignas\"\n    ,    \"cxx_attributes\"\n    ,    \"cxx_auto_type\"\n    ,    \"cxx_binary_literals\"\n    ,    \"cxx_constexpr\"\n    ,    \"cxx_contextual_conversions\"\n    ,    \"cxx_decltype\"\n    ,    \"cxx_default_function_template_args\"\n    ,    \"cxx_defaulted_functions\"\n    ,    \"cxx_delegating_constructors\"\n    ,    \"cxx_deleted_functions\"\n    ,    \"cxx_explicit_conversions\"\n    ,    \"cxx_generalized_initializers\"\n    ,    \"cxx_inheriting_constructors\"\n    ,    \"cxx_lambdas\"\n    ,    \"cxx_local_type_template_args\"\n    ,    \"cxx_noexcept\"\n    ,    \"cxx_nonstatic_member_init\"\n    ,    \"cxx_nullptr\"\n    ,    \"cxx_range_for\"\n    ,    \"cxx_raw_string_literals\"\n    ,    \"cxx_reference_qualified_functions\"\n    ,    \"cxx_relaxed_constexpr\"\n    ,    \"cxx_return_type_deduction\"\n    ,    \"cxx_rvalue_references\"\n    ,    \"cxx_static_assert\"\n    ,    \"cxx_strong_enums\"\n    ,    \"cxx_thread_local\"\n    ,    \"cxx_unicode_literals\"\n    ,    \"cxx_unrestricted_unions\"\n    ,    \"cxx_user_literals\"\n    ,    \"cxx_variable_templates\"\n    ,    \"cxx_variadic_templates\"\n    ,   {\"cxx_aggregate_default_initializers\", \"cxx_aggregate_nsdmi\"          }\n    ,   {\"cxx_trailing_return_types\",          \"cxx_trailing_return\"          }\n    ,   {\"cxx_alignof\",                        \"cxx_alignas\"                  }\n    ,   {\"cxx_final\",                          \"cxx_override_control\"         }\n    ,   {\"cxx_override\",                       \"cxx_override_control\"         }\n    ,   {\"cxx_uniform_initialization\",         \"cxx_generalized_initializers\" }\n    ,   {\"cxx_defaulted_move_initializers\",    \"cxx_defaulted_functions\"      }\n    ,   {\"cxx_lambda_init_captures\",           \"cxx_init_captures\"            }\n    }\n    for _, feature in ipairs(features_of_has_feature) do\n        local name = feature\n        local test = feature\n        if type(feature) == \"table\" then\n            name = feature[1]\n            test = feature[2]\n        end\n        _set(name, clang_minver .. \" && __has_feature(\" .. test .. \")\")\n    end\n\n    -- set features\n    _set(\"cxx_attribute_deprecated\",         clang34_cxx14) -- http://llvm.org/bugs/show_bug.cgi?id=19242\n    _set(\"cxx_decltype_auto\",                clang34_cxx14) -- http://llvm.org/bugs/show_bug.cgi?id=19698\n    _set(\"cxx_digit_separators\",             clang34_cxx14)\n    _set(\"cxx_generic_lambdas\",              clang34_cxx14) -- http://llvm.org/bugs/show_bug.cgi?id=19674\n    _set(\"cxx_enum_forward_declarations\",    clang31_cxx11)\n    _set(\"cxx_sizeof_member\",                clang31_cxx11)\n    _set(\"cxx_extended_friend_declarations\", clang29_cxx11)\n    _set(\"cxx_extern_templates\",             clang29_cxx11)\n    _set(\"cxx_func_identifier\",              clang29_cxx11)\n    _set(\"cxx_inline_namespaces\",            clang29_cxx11)\n    _set(\"cxx_long_long_type\",               clang29_cxx11)\n    _set(\"cxx_right_angle_brackets\",         clang29_cxx11)\n    _set(\"cxx_variadic_macros\",              clang29_cxx11)\n    _set(\"cxx_template_template_parameters\", clang_cxx98)\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\nimport(\"cfeatures\")\nimport(\"cxxfeatures\")\n\n-- get features\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", flags = {}}\n--\n-- @return      the features\n--\nfunction main(opt)\n\n    -- set features for c\n    set_features(cfeatures())\n\n    -- set features for c++\n    set_features(cxxfeatures())\n\n    -- check features\n    return check_features(opt)\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clang.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\nimport(\"core.language.language\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- init it\nfunction init(self)\n\n    -- init super\n    _super.init(self)\n\n    -- add cuflags\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"shared.cuflags\", \"-fPIC\")\n    end\n\n    -- suppress warning\n    self:add(\"cxflags\", \"-Qunused-arguments\")\n    self:add(\"cuflags\", \"-Qunused-arguments\")\n    self:add(\"mxflags\", \"-Qunused-arguments\")\n    self:add(\"asflags\", \"-Qunused-arguments\")\n\n    -- add cuda path\n    local cuda = get_config(\"cuda\")\n    if cuda then\n        local cuda_path = \"--cuda-path=\" .. os.args(path.translate(cuda))\n        self:add(\"cuflags\", cuda_path)\n    end\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- warnings\n        [\"-W1\"] = \"-Wall\"\n    ,   [\"-W2\"] = \"-Wall\"\n    ,   [\"-W3\"] = \"-Wall\"\n    ,   [\"-W4\"] = \"-Wall -Wextra\"\n\n         -- strip\n    ,   [\"-s\"]  = \"-s\"\n    ,   [\"-S\"]  = \"-S\"\n\n        -- rdc\n    ,   [\"-rdc=true\"] = \"-fcuda-rdc\"\n    ,   [\"-rdc true\"] = \"-fcuda-rdc\"\n    ,   [\"--relocatable-device-code=true\"] = \"-fcuda-rdc\"\n    ,   [\"--relocatable-device-code true\"] = \"-fcuda-rdc\"\n    ,   [\"-rdc=false\"] = \"\"\n    ,   [\"-rdc false\"] = \"\"\n    ,   [\"--relocatable-device-code=false\"] = \"\"\n    ,   [\"--relocatable-device-code false\"] = \"\"\n    })\n\nend\n\n-- make the fp-model flag\nfunction nf_fpmodel(self, level)\n    local maps\n    if self:has_flags(\"-ffp-model=fast\") then\n        maps =\n        {\n            precise    = \"-ffp-model=precise\"\n        ,   fast       = \"-ffp-model=fast\"\n        ,   strict     = \"-ffp-model=strict\"\n        ,   except     = \"-ftrapping-math\"\n        ,   noexcept   = \"-fno-trapping-math\"\n        }\n    else\n        maps =\n        {\n            precise    = \"\" -- default\n        ,   fast       = \"-ffast-math\"\n        ,   strict     = {\"-frounding-math\", \"-ftrapping-math\"}\n        ,   except     = \"-ftrapping-math\"\n        ,   noexcept   = \"-fno-trapping-math\"\n        }\n    end\n    return maps[level]\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none       = \"-O0\"\n        ,   fast       = \"-O1\"\n        ,   faster     = \"-O2\"\n        ,   fastest    = \"-O3\"\n        ,   smallest   = \"-Oz\" -- smaller than -Os\n        ,   aggressive = \"-Ofast\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none       = \"-w\"\n    ,   less       = \"-Wall\"\n    ,   more       = \"-Wall\"\n    ,   all        = \"-Wall\"\n    ,   allextra   = {\"-Wall\", \"-Wextra\"}\n    ,   extra      = \"-Wextra\"\n    ,   pedantic   = \"-Wpedantic\"\n    ,   everything = \"-Weverything\"\n    ,   error      = \"-Werror\"\n    }\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if kind == \"ld\" or kind == \"sh\" then\n        -- clang/windows need add `-g` to linker to generate pdb symbol file\n        if self:is_plat(\"windows\") and level == \"debug\" then\n            return \"-g\"\n        end\n    else\n        return _super.nf_symbol(self, level)\n    end\nend\n\n-- make the exception flag\n--\n-- e.g.\n-- set_exceptions(\"cxx\")\n-- set_exceptions(\"objc\")\n-- set_exceptions(\"no-cxx\")\n-- set_exceptions(\"no-objc\")\n-- set_exceptions(\"cxx\", \"objc\")\nfunction nf_exception(self, exp)\n    local maps = {\n        cxx = \"-fcxx-exceptions\",\n        [\"no-cxx\"] = \"-fno-cxx-exceptions\",\n        objc = \"-fobjc-exceptions\",\n        [\"no-objc\"] = \"-fno-objc-exceptions\"\n    }\n    local value = maps[exp]\n    if value then\n        return {exp:startswith(\"no-\") and \"-fno-exceptions\" or \"-fexceptions\", value}\n    end\nend\n\n-- has -fms-runtime-lib?\nfunction _has_ms_runtime_lib(self)\n    local has_ms_runtime_lib = _g._HAS_MS_RUNTIME_LIB\n    if has_ms_runtime_lib == nil then\n        if self:has_flags(\"-fms-runtime-lib=dll\", \"cxflags\", {flagskey = \"clang_ms_runtime_lib\"}) then\n            has_ms_runtime_lib = true\n        end\n        has_ms_runtime_lib = has_ms_runtime_lib or false\n        _g._HAS_MS_RUNTIME_LIB = has_ms_runtime_lib\n    end\n    return has_ms_runtime_lib\nend\n\n-- has -static-libstdc++?\nfunction _has_static_libstdcxx(self)\n    local has_static_libstdcxx = _g._HAS_STATIC_LIBSTDCXX\n    if has_static_libstdcxx == nil then\n        if self:has_flags(\"-static-libstdc++ -Werror\", \"ldflags\", {flagskey = \"clang_static_libstdcxx\"}) then\n            has_static_libstdcxx = true\n        end\n        has_static_libstdcxx = has_static_libstdcxx or false\n        _g._HAS_STATIC_LIBSTDCXX = has_static_libstdcxx\n    end\n    return has_static_libstdcxx\nend\n\n-- make the runtime flag\n-- @see https://github.com/xmake-io/xmake/issues/3546\nfunction nf_runtime(self, runtime, opt)\n    opt = opt or {}\n    local maps\n    -- if a sdk dir is defined, we should redirect include / library path to have the correct includes / libc++ link\n    local kind = self:kind()\n    if self:is_plat(\"windows\") and runtime then\n        if not _has_ms_runtime_lib(self) then\n            if runtime:startswith(\"MD\") then\n                wprint(\"%s runtime is not available for the current Clang compiler.\", runtime)\n            end\n            return\n        end\n        if language.sourcekinds()[kind] then\n            maps = {\n                MT  = \"-fms-runtime-lib=static\",\n                MTd = \"-fms-runtime-lib=static_dbg\",\n                MD  = \"-fms-runtime-lib=dll\",\n                MDd = \"-fms-runtime-lib=dll_dbg\"\n            }\n        elseif kind == \"ld\" or kind == \"sh\" then\n            maps = {\n                MT  = \"-nostdlib\",\n                MTd = \"-nostdlib\",\n                MD  = \"-nostdlib\",\n                MDd = \"-nostdlib\"\n            }\n        end\n    end\n    -- llvm on windows still doesn't support autolinking of libc++ and compiler-rt builtins\n    -- @see https://discourse.llvm.org/t/improve-autolinking-of-compiler-rt-and-libc-on-windows-with-lld-link/71392/10\n    -- and need manual setting of libc++ headerdirectory\n    -- @see https://github.com/llvm/llvm-project/issues/79647\n    local target = opt.target or opt\n    local llvm_dirs = toolchain_utils.get_llvm_dirs(self:toolchain())\n    -- we will set runtimes in android ndk toolchain\n    if not self:is_plat(\"android\") then\n        maps = maps or {}\n        if kind == \"cxx\" or kind == \"ld\" or kind == \"sh\" then\n            maps[\"c++_static\"]    = \"-stdlib=libc++\"\n            maps[\"c++_shared\"]    = \"-stdlib=libc++\"\n            maps[\"stdc++_static\"] = \"-stdlib=libstdc++\"\n            maps[\"stdc++_shared\"] = \"-stdlib=libstdc++\"\n            if kind == \"cxx\" then\n                -- force the toolchain libc++ headers to prevent clang picking the systems one\n                -- @see https://github.com/llvm/llvm-project/issues/79647\n                if llvm_dirs.cxxincludedir then\n                    maps[\"c++_static\"] = table.join(maps[\"c++_static\"], \"-cxx-isystem\" .. llvm_dirs.cxxincludedir)\n                    maps[\"c++_shared\"] = table.join(maps[\"c++_shared\"], \"-cxx-isystem\" .. llvm_dirs.cxxincludedir)\n                end\n            end\n        end\n\n        if self:is_plat(\"windows\") and language.sourcekinds()[kind] then\n              -- on windows force link to compiler_rt builtins\n            if llvm_dirs.rtdir and llvm_dirs.rtlink then\n                for name, _ in pairs(maps) do\n                    maps[name] = table.join({\"-Xclang\", \"--dependent-lib=\" .. llvm_dirs.rtlink}, maps[name])\n                end\n            end\n        end\n        if kind == \"ld\" or kind == \"sh\" then\n            if self:is_plat(\"windows\") and llvm_dirs.rtdir then\n                  -- on windows force add compiler_rt link directories\n                for name, _ in pairs(maps) do\n                    maps[name] = table.join(nf_linkdir(self, llvm_dirs.rtdir), maps[name])\n                    maps[name] = table.join(\"-resource-dir=\" .. llvm_dirs.resourcedir, maps[name])\n                end\n            end\n            local is_cxx = target and (target.sourcekinds and table.contains(table.wrap(target:sourcekinds()), \"cxx\"))\n            if is_cxx then\n                if llvm_dirs.libdir then\n                    maps[\"c++_static\"] = table.join(maps[\"c++_static\"], nf_linkdir(self, llvm_dirs.libdir))\n                    maps[\"c++_shared\"] = table.join(maps[\"c++_shared\"], nf_linkdir(self, llvm_dirs.libdir))\n\n                    -- sometimes llvm c++ runtimes are located in c++ subfolder (e.g homebrew llvm)\n                    if llvm_dirs.cxxlibdir then\n                        maps[\"c++_static\"] = table.join(maps[\"c++_static\"], nf_linkdir(self, llvm_dirs.cxxlibdir))\n                        maps[\"c++_shared\"] = table.join(maps[\"c++_shared\"], nf_linkdir(self, llvm_dirs.cxxlibdir))\n                    end\n\n                    -- add rpath to avoid the user need to set (DY)LD_LIBRARY_PATH by hand\n                    if not self:is_plat(\"windows\", \"mingw\") then\n                        if llvm_dirs.libdir then\n                            maps[\"c++_shared\"] = table.join(maps[\"c++_shared\"], nf_rpathdir(self, llvm_dirs.libdir))\n                        end\n                        if llvm_dirs.cxxlibdir then\n                            maps[\"c++_shared\"] = table.join(maps[\"c++_shared\"], nf_rpathdir(self, llvm_dirs.cxxlibdir))\n                        end\n                    end\n                end\n                if runtime:endswith(\"_static\") and _has_static_libstdcxx(self) then\n                    maps[\"c++_static\"] = table.join(maps[\"c++_static\"], \"-static-libstdc++\")\n                    maps[\"stdc++_static\"] = table.join(maps[\"stdc++_static\"], \"-static-libstdc++\")\n                end\n            end\n        end\n    end\n    return maps and maps[runtime]\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/clang_cl/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.clang_cl.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-?\"})\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\")] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]:gsub(\"/\", \"-\")]\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- get extension\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    local extension = opt.program:endswith(\"++\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"clang_cl_has_flags\" .. extension)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(\"-Werror=unused-command-line-argument\", flags, \"-c\", \"-o\", os.tmpfile(), sourcefile))\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clang_cl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clang_cl.lua\n--\n\n-- inherit cl\ninherit(\"cl\")\nimport(\"core.base.option\")\nimport(\"core.base.tty\")\nimport(\"core.base.colors\")\nimport(\"core.project.policy\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- warnings\n        [\"-W1\"] = \"-Wall\"\n    ,   [\"-W2\"] = \"-Wall\"\n    ,   [\"-W3\"] = \"-Wall\"\n    ,   [\"-W4\"] = \"-Wall -Wextra\"\n    ,   [\"-Weverything\"] = \"-Wall -Wextra -Weffc++\"\n\n        -- language\n    ,   [\"-ansi\"]                   = \"-Xclang -ansi\"\n    ,   [\"-std=c89\"]                = \"-Xclang -std=c89\"\n    ,   [\"-std=c99\"]                = \"-Xclang -std=c99\"\n    ,   [\"-std=c11\"]                = \"-Xclang -std=c11\"\n    ,   [\"-std=gnu89\"]              = \"-Xclang -std=gnu89\"\n    ,   [\"-std=gnu99\"]              = \"-Xclang -std=gnu99\"\n    ,   [\"-std=gnu11\"]              = \"-Xclang -std=gnu11\"\n    ,   [\"-std=c++98\"]              = \"-Xclang -std=c++98\"\n    ,   [\"-std=c++11\"]              = \"-Xclang -std=c++11\"\n    ,   [\"-std=c++14\"]              = \"-Xclang -std=c++14\"\n    ,   [\"-std=c++17\"]              = \"-Xclang -std=c++17\"\n    ,   [\"-std=c++1z\"]              = \"-Xclang -std=c++1z\"\n    ,   [\"-std=c++1a\"]              = \"-Xclang -std=c++1a\"\n    ,   [\"-std=c++20\"]              = \"-Xclang -std=c++20\"\n    ,   [\"-std=c++2a\"]              = \"-Xclang -std=c++2a\"\n    ,   [\"-std=c++23\"]              = \"-Xclang -std=c++23\"\n    ,   [\"-std=c++2b\"]              = \"-Xclang -std=c++2b\"\n    ,   [\"-std=gnu++98\"]            = \"-Xclang -std=gnu++98\"\n    ,   [\"-std=gnu++11\"]            = \"-Xclang -std=gnu++11\"\n    ,   [\"-std=gnu++14\"]            = \"-Xclang -std=gnu++14\"\n    ,   [\"-std=gnu++17\"]            = \"-Xclang -std=gnu++17\"\n    ,   [\"-std=gnu++1z\"]            = \"-Xclang -std=gnu++1z\"\n    ,   [\"-std=gnu++1a\"]            = \"-Xclang -std=gnu++1a\"\n    ,   [\"-std=gnu++20\"]            = \"-Xclang -std=gnu++20\"\n    ,   [\"-std=gnu++2a\"]            = \"-Xclang -std=gnu++2a\"\n    ,   [\"-std=gnu++23\"]            = \"-Xclang -std=gnu++23\"\n    ,   [\"-std=gnu++2b\"]            = \"-Xclang -std=gnu++2b\"\n    })\nend\n\n-- has color diagnostics?\nfunction _has_color_diagnostics(self)\n    local colors_diagnostics = _g._HAS_COLOR_DIAGNOSTICS\n    if colors_diagnostics == nil then\n        if io.isatty() and (tty.has_color8() or tty.has_color256()) then\n            local theme = colors.theme()\n            if theme and theme:name() ~= \"plain\" then\n                -- for clang\n                if self:has_flags(\"-fcolor-diagnostics\", \"cxflags\") then\n                    colors_diagnostics = \"-fcolor-diagnostics\"\n                -- for gcc\n                elseif self:has_flags(\"-fdiagnostics-color=always\", \"cxflags\") then\n                    colors_diagnostics = \"-fdiagnostics-color=always\"\n                end\n\n                -- enable color output for windows, @see https://github.com/xmake-io/xmake-vscode/discussions/260\n                if colors_diagnostics and\n                    self:has_flags(\"-fansi-escape-codes\", \"cxflags\") then\n                    colors_diagnostics = table.join(colors_diagnostics, \"-fansi-escape-codes\")\n                end\n            end\n        end\n        colors_diagnostics = colors_diagnostics or false\n        _g._HAS_COLOR_DIAGNOSTICS = colors_diagnostics\n    end\n    return colors_diagnostics\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none        = \"-Od\"\n    ,   faster      = \"-Ox\"\n    ,   fastest     = \"-O2\"\n    ,   smallest    = \"-O1\"\n    ,   aggressive  = \"-O2\"\n    }\n    return maps[level]\nend\n\n-- make the c precompiled header flag\nfunction nf_pcheader(self, pcheaderfile, opt)\n    local target = opt.target\n    if self:kind() == \"cc\" then\n        local objectfiles = target:objectfiles()\n        if objectfiles then\n            table.insert(objectfiles, target:pcoutputfile(\"c\") .. \".obj\")\n        end\n        return {\"-Yu\" .. path.filename(pcheaderfile),\n                \"-FI\" .. path.filename(pcheaderfile),\n                \"-I\" .. path.directory(pcheaderfile),\n                \"-Fp\" .. target:pcoutputfile(\"c\")}\n    end\nend\n\n-- make the c++ precompiled header flag\nfunction nf_pcxxheader(self, pcheaderfile, opt)\n    local target = opt.target\n    if self:kind() == \"cxx\" then\n        local objectfiles = target:objectfiles()\n        if objectfiles then\n            table.insert(objectfiles, target:pcoutputfile(\"cxx\") .. \".obj\")\n        end\n        -- https://github.com/xmake-io/xmake/issues/3905\n        -- clang-cl need extra include search path\n        return {\"-Yu\" .. path.filename(pcheaderfile),\n                \"-FI\" .. path.filename(pcheaderfile),\n                \"-I\" .. path.directory(pcheaderfile),\n                \"-Fp\" .. target:pcoutputfile(\"cxx\")}\n    end\nend\n\n-- has /clang:-MMD -MF depfile?\nfunction _has_clang_mmd(self)\n    local has_clang_mmd = _g._HAS_CLANG_MMD\n    if has_clang_mmd == nil then\n        local depfile = os.tmpfile()\n        if self:has_flags({\"/clang:-MMD\", \"/clang:-MF\", \"/clang:\" .. depfile}, \"cxflags\", {flagskey = \"clang_mmd\"}) then\n            has_clang_mmd = true\n        end\n        has_clang_mmd = has_clang_mmd or false\n        _g._HAS_CLANG_MMD = has_clang_mmd\n        os.tryrm(depfile)\n    end\n    return has_clang_mmd\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    local depfile\n    local depfile_format\n    local outdata = try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if dependinfo then\n                if _has_clang_mmd(self) then\n                    depfile = os.tmpfile()\n                    compflags = table.join(flags, \"/clang:-MMD\", \"/clang:-MF\", \"/clang:\" .. depfile)\n                    depfile_format = \"gcc\"\n                else\n                    compflags = table.join(flags, \"-showIncludes\")\n                    depfile_format = \"cl\"\n                end\n            end\n\n            -- has color diagnostics? enable it\n            local colors_diagnostics = _has_color_diagnostics(self)\n            if colors_diagnostics then\n                compflags = table.join(compflags, colors_diagnostics)\n            end\n\n            -- do compile\n            local program, argv = compargv(self, sourcefile, objectfile, compflags)\n            return os.iorunv(program, argv, {envs = self:runenvs()})\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n                if depfile then\n                    os.tryrm(depfile)\n                end\n\n                -- parse and strip errors\n                local lines = errors and tostring(errors):split('\\n', {plain = true}) or {}\n                if not option.get(\"verbose\") then\n\n                    -- find the start line of error\n                    local start = 0\n                    for index, line in ipairs(lines) do\n                        if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                            start = index\n                            break\n                        end\n                    end\n\n                    -- get 16 lines of errors\n                    if start > 0 then\n                        lines = table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start)))\n                    end\n                end\n\n                -- raise compiling errors\n                raise(#lines > 0 and table.concat(lines, \"\\n\") or \"\")\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                -- show warnings?\n                if ok and errdata and #errdata > 0 and policy.build_warnings(opt) then\n                    local lines = errdata:split('\\n', {plain = true})\n                    if #lines > 0 then\n                        local warnings = table.concat(table.slice(lines, 1, (#lines > 8 and 8 or #lines)), \"\\n\")\n                        progress.show_output(\"${color.warning}%s\", warnings)\n                    end\n                end\n            end\n        }\n    }\n\n    -- generate the dependent includes\n    if dependinfo and outdata then\n        if depfile then\n            if os.isfile(depfile) then\n                dependinfo.depfiles_format = depfile_format\n                dependinfo.depfiles = io.readfile(depfile)\n                os.tryrm(depfile)\n            end\n        elseif depfile_format == \"cl\" then\n            dependinfo.depfiles_format = \"cl\"\n            dependinfo.depfiles = outdata\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/clangxx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clangxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/clangxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clangxx.lua\n--\n\n-- inherit clang\ninherit(\"clang\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cosmoar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cosmoar.lua\n--\n\ninherit(\"ar\")\n\nfunction init(self)\n    _super.init(self)\nend\n\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        targetfile = targetfile:gsub(\"\\\\\", \"/\")\n        local objectfiles_new = {}\n        for idx, objectfile in ipairs(objectfiles) do\n            objectfiles_new[idx] = objectfiles[idx]:gsub(\"\\\\\", \"/\")\n        end\n        objectfiles = objectfiles_new\n    end\n    return _super.link(self, objectfiles, targetkind, targetfile, flags, table.join(opt, {shell = true}))\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/cosmocc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try {\n        function () os.runv(program, argv, table.join(opt or {}, {shell = true}))\n            return true\n        end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt, islinker)\n    local flag = flags[1]\n    if not islinker then\n        if flag:startswith(\"-D\") or\n           flag:startswith(\"-U\") or\n           flag:startswith(\"-I\") then\n            return true\n        end\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.cosmocc.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {islinker and \"-Wl,--help\" or \"--help\"}, {envs = opt.envs, shell = true}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    if islinker and flag then\n        if flag:startswith(\"-Wl,\") then\n            flag = flag:match(\"-Wl,(.-),\") or flag:sub(5)\n        end\n    end\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"cosmocc_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n    if is_host(\"windows\") then\n        sourcefile = sourcefile:gsub(\"\\\\\", \"/\")\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if is_host(\"windows\") then\n        tmpfile = tmpfile:gsub(\"\\\\\", \"/\")\n    end\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-o\", tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun then\n        if _check_from_arglist(flags, opt, islinker) then\n            return true\n        end\n        if _check_from_knownargs(flags, opt, islinker) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cosmocc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cosmocc.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n-- init it\nfunction init(self)\n    _super.init(self)\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        targetfile = targetfile:gsub(\"\\\\\", \"/\")\n        local objectfiles_new = {}\n        for idx, objectfile in ipairs(objectfiles) do\n            objectfiles_new[idx] = objectfiles[idx]:gsub(\"\\\\\", \"/\")\n        end\n        objectfiles = objectfiles_new\n    end\n    return _super.link(self, objectfiles, targetkind, targetfile, flags, table.join(opt, {shell = true}))\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        sourcefile = sourcefile:gsub(\"\\\\\", \"/\")\n        objectfile = objectfile:gsub(\"\\\\\", \"/\")\n        local target = opt.target\n        if target then\n            target:set(\"policy\", \"build.ccache\", false)\n        end\n    end\n    return _super.compile(self, sourcefile, objectfile, dependinfo, flags, table.join(opt, {shell = true}))\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/cosmocxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.cosmocc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cosmocxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cosmocxx.lua\n--\n\n-- inherit cosmocc\ninherit(\"cosmocc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cparser.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cparser.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init mxflags\n    self:set(\"mxflags\", \"-fmessage-length=0\"\n                      , \"-pipe\"\n                      , \"-DIBOutlet=__attribute__((iboutlet))\"\n                      , \"-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))\"\n                      , \"-DIBAction=void)__attribute__((ibaction)\")\n\n    -- init shflags\n    self:set(\"shflags\", \"-shared\", \"-fPIC\")\n\n    -- init cxflags for the kind: shared\n    self:set(\"shared.cxflags\", \"-fPIC\")\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- warnings\n        [\"-W1\"]          = \"-Wall\"\n    ,   [\"-W2\"]          = \"-Wall\"\n    ,   [\"-W3\"]          = \"-Wall\"\n    ,   [\"-W4\"]          = \"-Wall -Wextra\"\n    ,   [\"-Weverything\"] = \"-Wall -Wextra\"\n\n         -- strip\n    ,   [\"-s\"]  = \"-s\"\n    ,   [\"-S\"]  = \"-S\"\n    })\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n\n    -- the maps\n    local maps =\n    {\n        debug = \"-S\"\n    ,   all   = \"-s\"\n    }\n\n    -- make it\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n\n    -- the maps\n    local maps =\n    {\n        debug  = \"-g\"\n    ,   hidden = \"-fvisibility=hidden\"\n    }\n\n    -- make it\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n\n    -- the maps\n    local maps =\n    {\n        none       = \"-w\"\n    ,   less       = \"-Wall\"\n    ,   more       = \"-Wall\"\n    ,   all        = \"-Wall\"\n    ,   everything = \"-Wextra -Wall\"\n    ,   error      = \"-Werror\"\n    }\n\n    -- make it\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    return self:program(), table.join(\"-o\", targetfile, objectfiles, flags)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/cxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxx.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/dmd/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-L=<arg>\" or \"-L<arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-L=\") or flags_str:startswith(\"-L-\") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.dmd.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"dmd_has_flags.d\")\n    local objectfile = path.join(os.tmpdir(), \"detect\", \"dmd_has_flags.o\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"void main() {\\n}\")\n    end\n\n    -- init argv\n    local argv = table.join(flags, \"-of\" .. objectfile, sourcefile)\n    if not islinker then\n        table.insert(argv, 1, \"-c\")\n    end\n\n    -- check it\n    return _try_running(opt.program, argv)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/dmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dmd.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init arflags\n    self:set(\"dcarflags\", \"-lib\")\n\n    -- init shflags\n    self:set(\"dcshflags\", \"-shared\")\n\n    -- add -fPIC for shared\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"dcshflags\", \"-fPIC\")\n        self:add(\"shared.dcflags\", \"-fPIC\")\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            fast        = \"-O\"\n        ,   faster      = {\"-O\", \"-release\"}\n        ,   fastest     = {\"-O\", \"-release\", \"-inline\", \"-boundscheck=off\"}\n        ,   smallest    = {\"-O\", \"-release\", \"-boundscheck=off\"}\n        ,   aggressive  = {\"-O\", \"-release\", \"-inline\", \"-boundscheck=off\"}\n        }\n        return maps[level]\n    end\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    if not self:is_plat(\"windows\") then\n        local maps = {\n            debug = \"-L-S\",\n            all   = \"-L-s\"\n        }\n        if self:is_plat(\"macosx\", \"iphoneos\") then\n            maps.all = {\"-L-x\", \"-L-dead_strip\"}\n        end\n        return maps[level]\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps = {\n                debug  = {\"-g\", \"-debug\"}\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    elseif (kind == \"dcld\" or kind == \"dcsh\") and self:is_plat(\"windows\") and level == \"debug\" then\n        return \"-g\"\n    end\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none        = \"-d\",\n        less        = \"-w\",\n        more        = \"-w -wi\",\n        all         = \"-w -wi\",\n        everything  = \"-w -wi\",\n        error       = \"-de\"\n    }\n    return maps[level]\nend\n\n-- make the vector extension flag\nfunction nf_vectorext(self, extension)\n    local maps = {\n        avx  = \"-mcpu=avx\",\n        avx2 = \"-mcpu=avx\"\n    }\n    return maps[extension]\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if self:is_plat(\"windows\") then\n        return \"-L\" .. lib .. \".lib\"\n    else\n        return \"-L-l\" .. lib\n    end\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    if self:is_plat(\"windows\") then\n        return {\"-L-libpath:\" .. dir}\n    else\n        return {\"-L-L\" .. dir}\n    end\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    if self:is_plat(\"macosx\") then\n        return {\"-L-framework\", \"-L\" .. framework}\n    end\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    if self:is_plat(\"macosx\") then\n        return {\"-L-F\" .. path.translate(frameworkdir)}\n    end\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\n    if not self:is_plat(\"windows\") then\n        dir = path.translate(dir)\n        if self:has_flags(\"-L-rpath=\" .. dir, \"ldflags\") then\n            return {\"-L-rpath=\" .. (dir:gsub(\"@[%w_]+\", function (name)\n                local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n                return maps[name]\n            end))}\n        elseif self:has_flags(\"-L-rpath -L\" .. dir, \"ldflags\") then\n            return {\"-L-rpath\", \"-L\" .. (dir:gsub(\"%$ORIGIN\", \"@loader_path\"))}\n        end\n    end\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- add rpath for dylib (macho), e.g. -install_name @rpath/file.dylib\n    local flags_extra = {}\n    if targetkind == \"shared\" and self:is_plat(\"macosx\") then\n        table.insert(flags_extra, \"-L-install_name\")\n        table.insert(flags_extra, \"-L@rpath/\" .. path.filename(targetfile))\n    end\n\n    -- init arguments\n    local argv = table.join(flags, flags_extra, \"-of\" .. targetfile, objectfiles)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-of\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    opt = opt or {}\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-makedeps=\" .. depfile)\n            end\n\n            -- do compile\n            local program, argv = compargv(self, sourcefile, objectfile, compflags)\n            os.iorunv(program, argv, {envs = self:runenvs()})\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- parse and strip errors\n                local lines = errors and tostring(errors):split('\\n', {plain = true}) or {}\n                if not option.get(\"verbose\") then\n\n                    -- find the start line of error\n                    local start = 0\n                    for index, line in ipairs(lines) do\n                        if line:find(\"Error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                            start = index\n                            break\n                        end\n                    end\n\n                    -- get 16 lines of errors\n                    if start > 0 then\n                        lines = table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start)))\n                    end\n                end\n\n                -- raise compiling errors\n                local results = #lines > 0 and table.concat(lines, \"\\n\") or \"\"\n                if not option.get(\"verbose\") then\n                    results = results .. \"\\n  ${yellow}> in ${bright}\" .. sourcefile\n                end\n                raise(results)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        -- it use makefile/gcc compatiable format\n                        dependinfo.depfiles_format = \"gcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/dotnet/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt)\n    local flag = flags[1]\n    -- dotnet MSBuild properties\n    if flag:startswith(\"-p:\") or flag:startswith(\"/p:\") then\n        return true\n    end\n    -- dotnet CLI options\n    if flag:startswith(\"--\") then\n        return true\n    end\n    -- common csflags patterns\n    if flag:startswith(\"-\") or flag:startswith(\"/\") then\n        return true\n    end\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cs|csld|cssh]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n    opt = opt or {}\n    if _check_from_knownargs(flags, opt) then\n        return true\n    end\n    return false\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/dotnet.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dotnet.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-p:DefineConstants=\" .. macro}\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps = {\n        none       = \"-p:Optimize=false\"\n    ,   fast       = \"-p:Optimize=true\"\n    ,   faster     = \"-p:Optimize=true\"\n    ,   fastest    = \"-p:Optimize=true\"\n    ,   smallest   = \"-p:Optimize=true\"\n    ,   aggressive = \"-p:Optimize=true\"\n    }\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps = {\n        debug = {\"-p:DebugType=full\", \"-p:DebugSymbols=true\"}\n    }\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none       = \"-p:WarningLevel=0\"\n    ,   less       = \"-p:WarningLevel=1\"\n    ,   more       = \"-p:WarningLevel=3\"\n    ,   all        = \"-p:WarningLevel=5\"\n    ,   allextra   = \"-p:WarningLevel=9999\"\n    ,   error      = {\"-p:WarningLevel=5\", \"-p:TreatWarningsAsErrors=true\"}\n    }\n    return maps[level]\nend\n\n-- get the .csproj file from source files\nfunction _get_csprojfile(opt)\n    local target = opt and opt.target\n    if target then\n        local csprojfile = target:data(\"csharp.csproj\")\n        if csprojfile then\n            return csprojfile\n        end\n    end\nend\n\n-- get dotnet verbosity level\nfunction _get_verbosity()\n    if option.get(\"diagnosis\") then\n        return \"diagnostic\"\n    end\n    return \"quiet\"\nend\n\n-- get build configuration from mode\nfunction _get_configuration()\n    local mode = config.mode() or \"release\"\n    if mode:lower() == \"debug\" then\n        return \"Debug\"\n    end\n    return \"Release\"\nend\n\n-- make the build arguments list\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)\n    local argv = {\"build\"}\n\n    -- add .csproj file\n    local csprojfile = _get_csprojfile(opt)\n    if csprojfile then\n        table.insert(argv, csprojfile)\n    end\n\n    -- add common options\n    table.join2(argv, {\"--nologo\", \"--configuration\", _get_configuration(), \"--verbosity\", _get_verbosity()})\n\n    -- add output directory\n    table.join2(argv, {\"--output\", path.directory(targetfile)})\n\n    -- add flags\n    if flags then\n        table.join2(argv, flags)\n    end\n    return self:program(), argv\nend\n\n-- build the target file\nfunction build(self, sourcefiles, targetkind, targetfile, flags, opt)\n    os.mkdir(path.directory(targetfile))\n    local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)\n    os.runv(program, argv, {envs = self:runenvs()})\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/dpcpp/cfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.clang.cfeatures\")\n"
  },
  {
    "path": "xmake/modules/core/tools/dpcpp/cxxfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.clang.cxxfeatures\")\n"
  },
  {
    "path": "xmake/modules/core/tools/dpcpp/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.features\")\n"
  },
  {
    "path": "xmake/modules/core/tools/dpcpp/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/dpcpp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icpc.lua\n--\n\n-- inherit icc\ninherit(\"icx\")\n"
  },
  {
    "path": "xmake/modules/core/tools/emar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        emar.lua\n--\n\n-- inherit ar\ninherit(\"ar\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/emcc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/emcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        emcc.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n-- make the optimize flag\n--\n-- same options must be used at compile and link, @see https://github.com/xmake-io/xmake/issues/2455\n-- https://emscripten.org/docs/compiling/Building-Projects.html?highlight=optimization#building-projects-optimizations\nfunction nf_optimize(self, level)\n    local maps = {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-Os\"\n    ,   aggressive = \"-O3\"\n    }\n    return maps[level]\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if kind == \"ld\" or kind == \"sh\" then\n        -- emscripten requires -g when linking to map JS/wasm code back to original source\n        if level == \"debug\" then\n            return \"-g\"\n        end\n    end\n\n    return _super.nf_symbol(self, level)\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n\n    -- init arguments\n    opt = opt or {}\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/emxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.emcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/emxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        em++.lua\n--\n\n-- inherit emcc\ninherit(\"emcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/fasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fasm.lua\n--\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- symbols\n        [\"-g\"]                      = \"\"\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-Wall\"]                   = \"\" -- = \"-Wall\" will enable too more warnings\n    ,   [\"-W1\"]                     = \"\"\n    ,   [\"-W2\"]                     = \"\"\n    ,   [\"-W3\"]                     = \"\"\n    ,   [\"-Werror\"]                 = \"\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-d\" .. macro}\nend\n\n-- make the compile arguments list\nfunction _compargv1(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, sourcefile, objectfile)\nend\n\n-- compile the source file\nfunction _compile1(self, sourcefile, objectfile, dependinfo, flags)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    os.runv(_compargv1(self, sourcefile, objectfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefiles, objectfile, flags)\n\n    -- only support single source file now\n    assert(type(sourcefiles) ~= \"table\", \"'object:sources' not support!\")\n\n    -- for only single source file\n    return _compargv1(self, sourcefiles, objectfile, flags)\nend\n\n-- compile the source file\nfunction compile(self, sourcefiles, objectfile, dependinfo, flags)\n\n    -- only support single source file now\n    assert(type(sourcefiles) ~= \"table\", \"'object:sources' not support!\")\n\n    -- for only single source file\n    _compile1(self, sourcefiles, objectfile, dependinfo, flags)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/flang/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"-ld\") or toolkind:endswith(\"-sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.flang.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"flang_has_flags.f90\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"program hello\\n  print *, \\\"Hello World!\\\"\\nend program hello\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", os.tmpfile(), sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-S\", \"-o\", os.tmpfile(), sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[fc|fcld|fcsh]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/flang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        flang.lua\n--\n\n-- inherit clang (flang is part of LLVM)\ninherit(\"clang\")\nimport(\"core.base.option\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init super\n    _super.init(self)\n\n    -- init shflags\n    self:set(\"fcshflags\", \"-shared\")\n\n    -- add -fPIC for shared\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"fcshflags\", \"-fPIC\")\n        self:add(\"shared.fcflags\", \"-fPIC\")\n    end\n\n    -- init flags map to filter unsupported C/C++ flags\n    self:set(\"mapflags\",\n    {\n        -- visibility flags (not supported by Fortran)\n        [\"-fvisibility=.*\"] = \"\",\n        -- strip flags (not supported by flang, use nf_strip instead)\n        [\"^-s$\"] = \"\"\n    })\nend\n\n-- make the strip flag\n-- flang doesn't support -s directly, use -Wl,-s for linker\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"-Wl,-S\"\n    ,   all   = \"-Wl,-s\"\n    }\n    if self:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\", \"applexros\") then\n        maps.all = {\"-Wl,-x\", \"-Wl,-dead_strip\"}\n    elseif self:is_plat(\"windows\") then\n        -- flang doesn't support strip on windows\n        maps = {}\n    end\n    return maps[level]\nend\n\n-- make the symbol flag\n-- Fortran doesn't support visibility flags, only debug symbols\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = {\n            debug = \"-g\"\n        }\n        return maps[level]\n    elseif kind == \"ld\" or kind == \"sh\" then\n        -- we need to add `-g` to linker to generate pdb symbol file for clang on windows\n        if level == \"debug\" and self:is_plat(\"windows\") then\n            return \"-g\"\n        end\n    end\nend\n\n-- make the link arguments list\n-- flang needs to pass install_name through -Wl, for macOS shared libraries\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- add install_name for macOS shared libraries\n    local flags_extra = {}\n    if targetkind == \"shared\" and self:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n        table.insert(flags_extra, \"-Wl,-install_name\")\n        table.insert(flags_extra, \"-Wl,@rpath/\" .. path.filename(targetfile))\n    end\n\n    -- init arguments\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags, flags_extra)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- enable linker output?\n    local target = opt.target\n    local linker_output = option.get(\"verbose\")\n    if linker_output == nil and target and target.policy and target:policy(\"build.linker.output\") then\n        linker_output = true\n    end\n\n    os.mkdir(path.directory(targetfile))\n\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    if linker_output then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/fpc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.fpc.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-h\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"fpc_has_flags.pas\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"program Hello;\\nbegin\\nend.\")\n    end\n\n    -- check it\n    local binaryfile = os.tmpfile()\n    local ok, errors = _try_running(opt.program, table.join(flags, \"-o\" .. binaryfile, sourcefile))\n    os.tryrm(binaryfile)\n    return ok, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/fpc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fpc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"shared.pcflags\", \"-Cg\")\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none       = \"-O-\"\n        ,   fast       = \"-O1\"\n        ,   fastest    = \"-O3\"\n        ,   smallest   = \"-O2\"\n        ,   aggressive = \"-O4\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    if level == \"all\" then\n        return \"-Xs\"\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    if level == \"debug\" and self:kind() == \"pc\" then\n        if self:is_plat(\"windows\") then\n            return {\"-gw3\", \"-WN\"}\n        else\n            return \"-gw3\"\n        end\n    end\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-k-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-k-L\" .. dir}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\n    dir = path.translate(dir)\n    if self:has_flags(\"-k-rpath=\" .. dir, \"ldflags\") then\n        return {\"-k-rpath=\" .. (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n            return maps[name]\n        end))}\n    end\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    return {\"-k-framework\", framework}\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-k-F\", path.translate(frameworkdir)}\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, includedir)\n    return {\"-Fi\" .. path.translate(includedir)}\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-d\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return {\"-u\" .. macro}\nend\n\n-- make the language flag\nfunction nf_language(self, language)\n    local mode = {\n        pascal = \"-Mfpc\",\n        fpc = \"-Mfpc\",\n        objfpc = \"-Mobjfpc\",\n        delphi = \"-Mdelphi\",\n        macpas = \"-Mmacpas\",\n        isopas = \"-Miso\",\n        extendedpascal = \"-Mextendedpascal\",\n        delphiunicode = \"-Mdelphiunicode\",\n    }\n    return mode[language:lower()]\nend\n\n-- make the exception flag\n-- considering this applies to all dialects,\n-- make this only accept on/off\nfunction nf_exception(self, exp)\n    return {exp == \"off\" and \"-Sx-\" or \"-Sx\"}\nend\n\n-- make the build arguments list\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local extraflags = {}\n    local objectdir = opt.target and opt.target:objectdir()\n    if objectdir then\n        table.insert(extraflags, \"-FU\" .. path.translate(objectdir))\n    end\n    return self:program(), table.join(flags, extraflags, \"-o\" .. targetfile, sourcefiles)\nend\n\n-- build the target file\nfunction build(self, sourcefiles, targetkind, targetfile, flags, opt)\n    os.mkdir(path.directory(targetfile))\n    os.runv(buildargv(self, sourcefiles, targetkind, targetfile, flags, opt))\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc/cfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cfeatures.lua\n--\n\n-- set features\nfunction _set(feature, condition)\n    _g.features = _g.features or {}\n    _g.features[feature] = condition\nend\n\n-- get features\nfunction main()\n\n    -- init conditions\n    local gcc_minver = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 304\"\n    local gcc10_c17  = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 1000 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L\"\n    local gcc46_c11  = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201000L\"\n    local gcc34_c99  = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 304 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\"\n    local gcc_c90    = gcc_minver\n\n    -- set language standard supports\n    _set(\"c_std_89\", gcc46_c90)\n    _set(\"c_std_99\", gcc34_c99)\n    _set(\"c_std_11\", gcc46_c11)\n    _set(\"c_std_17\", gcc46_c17)\n\n    -- set features\n    _set(\"c_static_assert\",       gcc46_c11) -- GNU 4.7 correctly sets __STDC_VERSION__ to 201112L, but GNU 4.6 sets it to 201000L\n    _set(\"c_restrict\",            gcc34_c99)\n    _set(\"c_variadic_macros\",     gcc34_c99)\n    _set(\"c_function_prototypes\", gcc_c90)\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc/cxxfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxfeatures.lua\n--\n\n-- set features\nfunction _set(feature, condition)\n    _g.features = _g.features or {}\n    _g.features[feature] = condition\nend\n\n-- get features\n--\n-- http://gcc.gnu.org/projects/cxx0x.html\n-- http://gcc.gnu.org/projects/cxx1y.html\n-- https://gcc.gnu.org/projects/cxx-status.html\n--\n-- porting from Modules/Compiler/GNU-CXX-FeatureTests.cmake\n--\nfunction main()\n\n    -- init conditions\n    -- gcc -x c++ -std=c++20 -dM -E - < /dev/null | grep __cplusplus\n    local gcc_minver        = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 404\"\n    local gcc90_cxx20       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 900 && __cplusplus >= 202002L\"\n    local gcc70_cxx17       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 700 && __cplusplus >= 201703L\"\n    local gcc50_cxx14       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 500 && __cplusplus >= 201402L\"\n    local gcc49_cxx14       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && __cplusplus > 201103L\"\n    local gcc481_cxx11      = \"((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40801) && __cplusplus >= 201103L\"\n    local gcc48_cxx11       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L\"\n    local gcc47_cxx11       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && __cplusplus >= 201103L\"\n    local gcc_cxx0x_defined = \"(__cplusplus >= 201103L || (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__))\"\n    local gcc46_cxx11       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && \" .. gcc_cxx0x_defined\n    local gcc45_cxx11       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 405 && \" .. gcc_cxx0x_defined\n    local gcc44_cxx11       = \"(__GNUC__ * 100 + __GNUC_MINOR__) >= 404 && \" .. gcc_cxx0x_defined\n    local gcc43_cxx11       = gcc_minver .. \" && \" .. gcc_cxx0x_defined\n\n    -- set language standard supports\n    _set(\"cxx_std_98\", gcc_minver)\n    _set(\"cxx_std_11\", gcc43_cxx11)\n    _set(\"cxx_std_14\", gcc49_cxx14)\n    _set(\"cxx_std_17\", gcc70_cxx17)\n    _set(\"cxx_std_20\", gcc90_cxx20)\n\n    -- set features\n    _set(\"cxx_variable_templates\",             gcc50_cxx14)\n    _set(\"cxx_relaxed_constexpr\",              gcc50_cxx14)\n    _set(\"cxx_aggregate_default_initializers\", gcc50_cxx14)\n\n    -- GNU 4.9 in c++14 mode sets __cplusplus to 201300L, so don't test for the\n    -- correct value of it below.\n    -- https://patchwork.ozlabs.org/patch/382470/\n    _set(\"cxx_contextual_conversions\", gcc49_cxx14)\n    _set(\"cxx_attribute_deprecated\",   gcc49_cxx14)\n    _set(\"cxx_decltype_auto\",          gcc49_cxx14)\n    _set(\"cxx_digit_separators\",       gcc49_cxx14)\n    _set(\"cxx_generic_lambdas\",        gcc49_cxx14)\n    _set(\"cxx_lambda_init_captures\",   gcc49_cxx14)\n\n    -- GNU 4.3 supports binary literals as an extension, but may warn about\n    -- use of extensions prior to GNU 4.9\n    -- http://stackoverflow.com/questions/16334024/difference-between-gcc-binary-literals-and-c14-ones\n    _set(\"cxx_binary_literals\", gcc49_cxx14)\n\n    -- The feature below is documented as available in GNU 4.8 (by implementing an\n    -- earlier draft of the standard paper), but that version of the compiler\n    -- does not set __cplusplus to a value greater than 201103L until GNU 4.9:\n    -- http://gcc.gnu.org/onlinedocs/gcc-4.8.2/cpp/Standard-Predefined-Macros.html#Standard-Predefined-Macros\n    -- http://gcc.gnu.org/onlinedocs/gcc-4.9.0/cpp/Standard-Predefined-Macros.html#Standard-Predefined-Macros\n    -- So, CMake only reports availability for it with GNU 4.9 or later.\n    _set(\"cxx_return_type_deduction\", gcc49_cxx14)\n\n    -- Introduced in GCC 4.8.1\n    _set(\"cxx_decltype_incomplete_return_types\", gcc481_cxx11)\n    _set(\"cxx_reference_qualified_functions\",    gcc481_cxx11)\n\n    -- The alignof feature works with GNU 4.7 and -std=c++11, but it is documented\n    -- as available with GNU 4.8, so treat that as true.\n    _set(\"cxx_alignas\",                 gcc48_cxx11)\n    _set(\"cxx_alignof\",                 gcc48_cxx11)\n    _set(\"cxx_attributes\",              gcc48_cxx11)\n    _set(\"cxx_inheriting_constructors\", gcc48_cxx11)\n    _set(\"cxx_thread_local\",            gcc48_cxx11)\n\n    _set(\"cxx_alias_templates\",              gcc47_cxx11)\n    _set(\"cxx_delegating_constructors\",      gcc47_cxx11)\n    _set(\"cxx_extended_friend_declarations\", gcc47_cxx11)\n    _set(\"cxx_final\",                        gcc47_cxx11)\n    _set(\"cxx_nonstatic_member_init\",        gcc47_cxx11)\n    _set(\"cxx_override\",                     gcc47_cxx11)\n    _set(\"cxx_user_literals\",                gcc47_cxx11)\n\n    -- NOTE: C++11 was ratified in September 2011. GNU 4.7 is the first minor\n    -- release following that (March 2012), and the first minor release to\n    -- support -std=c++11. Prior to that, support for C++11 features is technically\n    -- experiemental and possibly incomplete (see for example the note below about\n    -- cxx_variadic_template_template_parameters)\n    -- GNU does not define __cplusplus correctly before version 4.7.\n    -- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773\n    -- __GXX_EXPERIMENTAL_CXX0X__ is defined in prior versions, but may not be\n    -- defined in the future.\n    _set(\"cxx_constexpr\",                   gcc46_cxx11)\n    _set(\"cxx_defaulted_move_initializers\", gcc46_cxx11)\n    _set(\"cxx_enum_forward_declarations\",   gcc46_cxx11)\n    _set(\"cxx_noexcept\",                    gcc46_cxx11)\n    _set(\"cxx_nullptr\",                     gcc46_cxx11)\n    _set(\"cxx_range_for\",                   gcc46_cxx11)\n    _set(\"cxx_unrestricted_unions\",         gcc46_cxx11)\n\n    _set(\"cxx_explicit_conversions\",     gcc45_cxx11)\n    _set(\"cxx_lambdas\",                  gcc45_cxx11)\n    _set(\"cxx_local_type_template_args\", gcc45_cxx11)\n    _set(\"cxx_raw_string_literals\",      gcc45_cxx11)\n\n    _set(\"cxx_auto_type\",                gcc44_cxx11)\n    _set(\"cxx_defaulted_functions\",      gcc44_cxx11)\n    _set(\"cxx_deleted_functions\",        gcc44_cxx11)\n    _set(\"cxx_generalized_initializers\", gcc44_cxx11)\n    _set(\"cxx_inline_namespaces\",        gcc44_cxx11)\n    _set(\"cxx_sizeof_member\",            gcc44_cxx11)\n    _set(\"cxx_strong_enums\",             gcc44_cxx11)\n    _set(\"cxx_trailing_return_types\",    gcc44_cxx11)\n    _set(\"cxx_unicode_literals\",         gcc44_cxx11)\n    _set(\"cxx_uniform_initialization\",   gcc44_cxx11)\n    _set(\"cxx_variadic_templates\",       gcc44_cxx11)\n\n    -- TODO: If features are ever recorded for GNU 4.3, there should possibly\n    -- be a new feature added like cxx_variadic_template_template_parameters,\n    -- which is implemented by GNU 4.4, but not 4.3. cxx_variadic_templates is\n    -- actually implemented by GNU 4.3, but variadic template template parameters\n    -- 'completes' it, so that is the version we record as having the variadic\n    -- templates capability in CMake. See\n    -- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf\n    -- TODO: Should be supported by GNU 4.3\n    _set(\"cxx_decltype\",                       gcc43_cxx11)\n    _set(\"cxx_default_function_template_args\", gcc43_cxx11)\n    _set(\"cxx_long_long_type\",                 gcc43_cxx11)\n    _set(\"cxx_right_angle_brackets\",           gcc43_cxx11)\n    _set(\"cxx_rvalue_references\",              gcc43_cxx11)\n    _set(\"cxx_static_assert\",                  gcc43_cxx11)\n\n    -- TODO: Should be supported since GNU 3.4?\n    _set(\"cxx_extern_templates\", gcc_minver .. \" && \" .. gcc_cxx0x_defined)\n\n    -- TODO: Should be supported forever?\n    _set(\"cxx_func_identifier\", gcc_minver .. \" && \" .. gcc_cxx0x_defined)\n    _set(\"cxx_variadic_macros\", gcc_minver .. \" && \" .. gcc_cxx0x_defined)\n    _set(\"cxx_template_template_parameters\", gcc_minver .. \" && __cplusplus\")\n\n    -- c++17 language features with predefined macros\n    -- https://en.cppreference.com/w/cpp/feature_test\n    local features_cxx17 = {\n        \"__cpp_aggregate_bases\",\n        \"__cpp_aligned_new\",\n        \"__cpp_capture_star_this\",\n        \"__cpp_constexpr\",\n        \"__cpp_deduction_guides\",\n        \"__cpp_enumerator_attributes\",\n        \"__cpp_fold_expressions\",\n        \"__cpp_guaranteed_copy_elision\",\n        \"__cpp_hex_float\",\n        \"__cpp_if_constexpr\",\n        \"__cpp_inheriting_constructors\",\n        \"__cpp_inline_variables\",\n        \"__cpp_namespace_attributes\",\n        \"__cpp_noexcept_function_type\",\n        \"__cpp_nontype_template_args\",\n        \"__cpp_nontype_template_parameter_auto\",\n        \"__cpp_range_based_for\",\n        \"__cpp_static_assert\",\n        \"__cpp_structured_bindings\",\n        \"__cpp_template_template_args\",\n        \"__cpp_variadic_using\"}\n    for _, feature in ipairs(features_cxx17) do\n        _set((feature:gsub(\"__cpp\", \"cxx\")), \"__cplusplus && defined(\" .. feature .. \")\")\n    end\n\n    -- c++20 language features with predefined macros\n    -- https://en.cppreference.com/w/cpp/feature_test\n    local features_cxx20 = {\n        \"__cpp_aggregate_paren_init\",\n        \"__cpp_char8_t\",\n        \"__cpp_concepts\",\n        \"__cpp_conditional_explicit\",\n        \"__cpp_consteval\",\n        \"__cpp_constexpr\",\n        \"__cpp_constexpr_dynamic_alloc\",\n        \"__cpp_constexpr_in_decltype\",\n        \"__cpp_constinit\",\n        \"__cpp_deduction_guides\",\n        \"__cpp_designated_initializers\",\n        \"__cpp_generic_lambdas\",\n        \"__cpp_impl_coroutine\",\n        \"__cpp_impl_destroying_delete\",\n        \"__cpp_impl_three_way_comparison\",\n        \"__cpp_init_captures\",\n        \"__cpp_modules\",\n        \"__cpp_nontype_template_args\",\n        \"__cpp_using_enum\"}\n    for _, feature in ipairs(features_cxx20) do\n        _set((feature:gsub(\"__cpp\", \"cxx\")), \"__cplusplus && defined(\" .. feature .. \")\")\n    end\n\n    -- get features\n    return _g.features\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\nimport(\"cfeatures\")\nimport(\"cxxfeatures\")\nimport(\"core.language.language\")\n\n-- get macro defines\nfunction _get_macro_defines(snippets, extension, opt)\n\n    -- make an stub source file\n    local sourcefile = os.tmpfile() .. extension\n    io.writefile(sourcefile, table.concat(table.wrap(snippets), \"\\n\"))\n\n    -- get defines\n    local results = {}\n    local defines = try { function () return os.iorunv(opt.program, table.join(opt.flags or {}, {\"-dM\", \"-E\", sourcefile}), {envs = opt.envs}) end }\n    if defines then\n        for _, define in ipairs(defines:split(\"\\n\")) do\n            local name = define:match(\"#define%s+(.-)%s+\")\n            if name then\n                results[name] = true\n            end\n        end\n    end\n    os.tryrm(sourcefile)\n    return results\nend\n\n-- set feature with condition\nfunction _set_feature(feature, condition)\n\n    -- init features\n    _g.features = _g.features or {}\n\n    -- get language kind\n    local langkind = feature:match(\"^(%w-)_\")\n    assert(langkind, \"unknown language kind for the feature: %s\", feature)\n\n    -- get source kind from the language kind\n    local sourcekind = language.langkinds()[langkind]\n    assert(sourcekind, \"unknown language kind: \" .. langkind)\n\n    -- get extension\n    local extension = table.wrap(language.sourcekinds()[sourcekind])[1]\n    assert(extension, \"not supported kind for the feature: %s\", feature)\n\n    -- make snippet\n    local snippet = format([[\n#if (%s)\n#   define %s 1\n#endif]], condition, feature)\n\n    -- init features with the given extension\n    local features = _g.features[extension] or {}\n    _g.features[extension] = features\n\n    -- set feature and snippet\n    features[feature] = snippet\nend\n\n-- set features\nfunction set_features(features)\n    for feature, condition in pairs(features) do\n        _set_feature(feature, condition)\n    end\nend\n\n-- check features\nfunction check_features(opt)\n\n    -- check features with all extensions\n    local results = {}\n    for extension, features in pairs(_g.features) do\n\n        -- make snippets\n        local snippets = {}\n        for _, snippet in pairs(features) do\n            table.insert(snippets, snippet)\n        end\n\n        -- get defines\n        local defines = _get_macro_defines(snippets, extension, opt)\n\n        -- check features\n        for feature, _ in pairs(features) do\n            if defines[feature] then\n                results[feature] = true\n            end\n        end\n    end\n    return results\nend\n\n-- get features\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", flags = {}}\n--\n-- @return      the features\n--\nfunction main(opt)\n\n    -- set features for c\n    set_features(cfeatures())\n\n    -- set features for c++\n    set_features(cxxfeatures())\n\n    -- check features\n    return check_features(opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\nimport(\"core.base.hashset\")\nimport(\"core.base.semver\")\nimport(\"detect.sdks.find_cuda\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt, islinker)\n    local flag = flags[1]\n    local known_flags = _g.known_flags\n    if known_flags == nil then\n        known_flags = hashset.from({\"-O\", \"-O0\", \"-O1\", \"-O2\", \"-O3\", \"-Os\", \"-g\"})\n        _g.known_flags = known_flags\n    end\n    if known_flags:has(flag) then\n        return true\n    end\n    if not islinker then\n        if flag:startswith(\"-D\") or\n           flag:startswith(\"-U\") or\n           flag:startswith(\"-I\") then\n            return true\n        end\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.gcc.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {islinker and \"-Wl,--help\" or \"--help\"}, {envs = opt.envs}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    if islinker and flag then\n        if flag:startswith(\"-Wl,\") then\n            flag = flag:match(\"-Wl,(.-),\") or flag:sub(5)\n        end\n    end\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"gcc_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for clang cuda compiler\n    if opt.toolkind == \"cu\" then\n        local cuda_gpu_flags = false\n        for _, flag in ipairs(flags) do\n            if flag:startswith(\"--cuda-gpu-arch=\") then\n                cuda_gpu_flags = true\n                break\n            end\n        end\n\n        local args = table.join(flags, \"-c\", \"-o\", tmpfile, sourcefile)\n        if not cuda_gpu_flags then\n            local cuda = get_config(\"cuda\")\n            local cuda_sdk = find_cuda(cuda)\n            local cuda_sdkver = cuda_sdk and cuda_sdk.version or \"7.0\"\n            if cuda_sdkver and semver.compare(cuda_sdkver, \"12.0\") >= 0 then\n                table.insert(args, 1, \"--cuda-gpu-arch=sm_80\")\n            end\n        end\n\n        return _try_running(opt.program, args, opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-S\", \"-o\", tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun then\n        if _check_from_knownargs(flags, opt, islinker) then\n            return true\n        end\n        if _check_from_arglist(flags, opt, islinker) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\n\n-- a placeholder for spaces in path\nlocal space_placeholder = \"\\001\"\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    -- escape characters, e.g. \\#Qt.Widget_pch.h -> #Qt.Widget_pch.h\n    -- @see https://github.com/xmake-io/xmake/issues/4134\n    -- https://github.com/xmake-io/xmake/issues/4273\n    if not is_host(\"windows\") then\n        dep = dep:gsub(\"\\\\(.)\", \"%1\")\n    end\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        -- we also need to check header files outside project\n        -- https://github.com/xmake-io/xmake/issues/1154\n        return dep\n    end\nend\n\n-- load module mapper\nfunction _load_module_mapper(target)\n    local mapper = {}\n    local mapperfile = path.join(config.builddir(), target:name(), \"mapper.txt\")\n    for line in io.lines(mapperfile) do\n        local moduleinfo = line:split(\" \", {plain = true})\n        if #moduleinfo == 2 then\n            mapper[moduleinfo[1]] = moduleinfo[2]\n        end\n    end\n    return mapper\nend\n\n-- parse depsfiles from string\n--\n-- parse_deps(io.readfile(depfile, {continuation = \"\\\\\"}))\n--\n-- eg.\n-- strcpy.o: src/tbox/libc/string/strcpy.c src/tbox/libc/string/string.h \\\n--  src/tbox/libc/string/prefix.h src/tbox/libc/string/../prefix.h \\\n--  src/tbox/libc/string/../../prefix.h \\\n--  src/tbox/libc/string/../../prefix/prefix.h \\\n--  src/tbox/libc/string/../../prefix/config.h \\\n--  src/tbox/libc/string/../../prefix/../config.h \\\n--  build/iphoneos/x86_64/release/tbox.config.h \\\n--\n-- with c++ modules (gcc):\n-- build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o: src/foo.mpp\\\n-- build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o  gcm.cache/foo.gcm: bar.c++m cat.c++m\\\n-- foo.c++m: gcm.cache/foo.gcm\\\n-- .PHONY: foo.c++m\\\n-- gcm.cache/foo.gcm:|  build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o\\\n-- CXX_IMPORTS += bar.c++m cat.c++m\\\n--\nfunction main(depsdata, opt)\n\n    -- we assume there is only one valid line\n    local block = 0\n    local results = hashset.new()\n    local projectdir = os.projectdir()\n    local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first\n    local plain = {plain = true}\n    line = line:replace(\"\\\\ \", space_placeholder, plain)\n    for _, includefile in ipairs(line:split(' ', plain)) do -- it will trim all internal spaces without `{strict = true}`\n        -- some gcc toolchains will some invalid paths (e.g. `d\\:\\xxx`), we need to fix it\n        -- https://github.com/xmake-io/xmake/issues/1196\n        if is_host(\"windows\") and includefile:match(\"^%w\\\\:\") then\n            includefile = includefile:replace(\"\\\\:\", \":\", plain)\n        end\n        if includefile:endswith(\":\") then -- ignore \"xxx.o:\" prefix\n            block = block + 1\n            if block > 1 then\n                -- skip other `xxx.o:` block\n                break\n            end\n        else\n            includefile = includefile:replace(space_placeholder, ' ', plain)\n            includefile = includefile:split(\"\\n\", plain)[1]\n            if #includefile > 0 then\n                includefile = _normailize_dep(includefile, projectdir)\n                if includefile then\n                    results:insert(includefile)\n                end\n            end\n        end\n    end\n\n    -- translate .c++m module file path\n    -- with c++ modules (gcc):\n    -- CXX_IMPORTS += bar.c++m cat.c++m\\\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/3000\n    -- https://github.com/xmake-io/xmake/issues/4215\n    local target = opt and opt.target\n    if target and line:find(\"CXX_IMPORTS += \", 1, true) then\n        local mapper = _load_module_mapper(target)\n        local modulefiles = line:split(\"CXX_IMPORTS += \", plain)[2]\n        if modulefiles then\n            for _, modulefile in ipairs(modulefiles:split(' ', plain)) do\n                if modulefile:endswith(\".c++m\") then\n                    local modulekey = modulefile:sub(1, #modulefile - 5)\n                    local modulepath = mapper[modulekey]\n                    if modulepath then\n                        modulepath = _normailize_dep(modulepath, projectdir)\n                        results:insert(modulepath)\n                    end\n                end\n            end\n        end\n    end\n\n    return results:to_array()\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gcc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.tty\")\nimport(\"core.base.colors\")\nimport(\"core.base.global\")\nimport(\"core.cache.memcache\")\nimport(\"core.project.config\")\nimport(\"core.project.policy\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\nimport(\"private.cache.build_cache\")\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\nimport(\"rules.c++.modules.support\", {rootdir = os.programdir()})\n\n-- has -static-libstdc++?\nfunction _has_static_libstdcxx(self)\n    local has_static_libstdcxx = _g._HAS_STATIC_LIBSTDCXX\n    if has_static_libstdcxx == nil then\n        if self:has_flags(\"-static-libstdc++ -Werror\", \"ldflags\", {flagskey = \"gcc_static_libstdcxx\"}) then\n            has_static_libstdcxx = true\n        end\n        has_static_libstdcxx = has_static_libstdcxx or false\n        _g._HAS_STATIC_LIBSTDCXX = has_static_libstdcxx\n    end\n    return has_static_libstdcxx\nend\n\n-- get implib file\nfunction _get_implibfile(self, targetkind, targetfile, opt)\n    if targetkind == \"shared\" and self:is_plat(\"mingw\") then\n        local target = opt and opt.target\n        local implibfile\n        if target and target:type() == \"target\" then\n            implibfile = target:artifactfile(\"implib\")\n        end\n        if not implibfile then\n            implibfile = path.join(path.directory(targetfile), path.basename(targetfile) .. \".a\")\n        end\n        return implibfile\n    end\nend\n\n-- is cosmocc?\nfunction _is_cosmocc(self)\n    local is_cosmocc = _g._IS_COSMOCC\n    if is_cosmocc == nil then\n        if self:name():startswith(\"cosmoc\") then\n            is_cosmocc = true\n        end\n        _g._IS_COSMOCC = is_cosmocc or false\n    end\n    return is_cosmocc\nend\n\n-- is syntax check enabled?\nfunction _is_syntax_check()\n    return memcache.get(\"syntax_check\", \"enabled\") or false\nend\n\n-- get `-MMD -MF depfile.d` flags, some old gcc does not support it at same time\nfunction _get_depfile_flags(self)\n    local depfile_flags = _g._DEPFILE_FLAGS\n    if depfile_flags == nil then\n        local nuldev = os.nuldev()\n        if _is_cosmocc(self) then\n            nuldev = path.unix(os.tmpfile())\n        end\n        if self:has_flags({\"-MMD\", \"-MF\", nuldev}, \"cxflags\", { flagskey = \"-MMD -MF\" }) then\n            depfile_flags = {\"-MMD\", \"-MF\"}\n        end\n        _g._DEPFILE_FLAGS = depfile_flags or false\n    end\n    return depfile_flags\nend\n\n-- get color diagnostics flag\nfunction _get_color_diagnostics_flag(self)\n    local colors_diagnostics = _g._COLOR_DIAGNOSTICS\n    if colors_diagnostics == nil then\n        if io.isatty() and (tty.has_color8() or tty.has_color256()) then\n            local theme = colors.theme()\n            if theme and theme:name() ~= \"plain\" then\n                -- for gcc\n                if self:has_flags(\"-fdiagnostics-color=always\", \"cxflags\") then\n                    colors_diagnostics = \"-fdiagnostics-color=always\"\n                -- for clang\n                elseif self:has_flags(\"-fcolor-diagnostics\", \"cxflags\") then\n                    colors_diagnostics = \"-fcolor-diagnostics\"\n                end\n\n                -- enable color output for windows, @see https://github.com/xmake-io/xmake-vscode/discussions/260\n                if colors_diagnostics and self:name() == \"clang\" and is_host(\"windows\") and\n                    self:has_flags(\"-fansi-escape-codes\", \"cxflags\") then\n                    colors_diagnostics = table.join(colors_diagnostics, \"-fansi-escape-codes\")\n                end\n            end\n        end\n        colors_diagnostics = colors_diagnostics or false\n        _g._COLOR_DIAGNOSTICS = colors_diagnostics\n    end\n    return colors_diagnostics\nend\n\n-- has gnu-line-marker flag?\nfunction _has_gnu_line_marker_flag(self)\n    local gnu_line_marker = _g._HAS_GNU_LINE_MARKER\n    if gnu_line_marker == nil then\n        if self:has_flags({\"-Wno-gnu-line-marker\", \"-Werror\"}, \"cxflags\") then\n            gnu_line_marker = true\n        end\n        gnu_line_marker = gnu_line_marker or false\n        _g._HAS_GNU_LINE_MARKER = gnu_line_marker\n    end\n    return gnu_line_marker\nend\n\n-- get preprocess file path\nfunction _get_cppfile(sourcefile, objectfile)\n    return path.join(path.directory(objectfile), \"__cpp_\" .. path.basename(objectfile) .. path.extension(sourcefile))\nend\n\n-- do preprocess\nfunction _preprocess(program, argv, opt)\n\n    -- is gcc or clang?\n    local tool = opt.tool\n    local is_gcc = false\n    local is_clang = false\n    if tool then\n        if tool:name() == \"gcc\" or tool:name() == \"gxx\" then\n            is_gcc = true\n        elseif tool:name():startswith(\"clang\") then\n            is_clang = true\n        elseif tool:name() == \"circle\" then\n            return\n        end\n    end\n\n    -- enable \"-fdirectives-only\"? we need to enable it manually\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/2603\n    -- https://github.com/xmake-io/xmake/issues/2425\n    local directives_only\n    if is_gcc then\n        local cachekey = \"core.tools.\" .. tool:name()\n        directives_only = memcache.get(cachekey, \"directives_only\")\n        if directives_only == nil then\n            if os.isfile(os.projectfile()) and project.policy(\"preprocessor.gcc.directives_only\") then\n                directives_only = true\n            end\n            memcache.set(cachekey, \"directives_only\", directives_only)\n        end\n    end\n\n    -- get flags and source file\n    local flags = {}\n    local cppflags = {}\n    local skipped = program:endswith(\"cache\") and 1 or 0\n    for _, flag in ipairs(argv) do\n        if flag == \"-o\" then\n            break\n        end\n\n        -- get preprocessor flags\n        table.insert(cppflags, flag)\n\n        -- for c++ modules, we cannot support it for clang now\n        if is_clang and flag:startswith(\"-fmodules\") then\n            return\n        end\n\n        -- we cannot enable \"-fdirectives-only\"\n        if directives_only and (flag:startswith(\"-D__TIME__=\") or\n                flag:startswith(\"-D__DATE__=\") or flag:startswith(\"-D__TIMESTAMP__=\")) then\n            directives_only = false\n        end\n\n        -- get compiler flags\n        if flag == \"-MMD\" or (flag:startswith(\"-I\") and #flag > 2) or flag:startswith(\"--sysroot=\") then\n            skipped = 1\n        elseif flag == \"-MF\" or\n            flag == \"-I\" or flag == \"-isystem\" or flag == \"-include\" or flag == \"-include-pch\" or\n            flag == \"-isysroot\" or flag == \"-gcc-toolchain\" then\n            skipped = 2\n        elseif flag:endswith(\"xcrun\") then\n            skipped = 4\n        end\n        if skipped > 0 then\n            skipped = skipped - 1\n        else\n            table.insert(flags, flag)\n        end\n    end\n    local objectfile = argv[#argv - 1]\n    local sourcefile = argv[#argv]\n    assert(objectfile and sourcefile, \"%s: iorunv(%s): invalid arguments!\", self, program)\n\n    -- is precompiled header?\n    if objectfile:endswith(\".gch\") or objectfile:endswith(\".pch\") then\n        return\n    end\n\n    -- disable linemarkers?\n    local linemarkers = _g.linemarkers\n    if linemarkers == nil then\n        if os.isfile(os.projectfile()) and project.policy(\"preprocessor.linemarkers\") == false then\n            linemarkers = false\n        else\n            linemarkers = true\n        end\n        _g.linemarkers = linemarkers\n    end\n\n    -- do preprocess\n    local cppfile = _get_cppfile(sourcefile, objectfile)\n    local cppfiledir = path.directory(cppfile)\n    if not os.isdir(cppfiledir) then\n        os.mkdir(cppfiledir)\n    end\n    table.insert(cppflags, \"-E\")\n    -- it will be faster for preprocessing\n    -- when preprocessing, handle directives, but do not expand macros.\n    if directives_only then\n        table.insert(cppflags, \"-fdirectives-only\")\n    end\n    if linemarkers == false then\n        table.insert(cppflags, \"-P\")\n    end\n    -- if we want to support pch for gcc, we need to enable this flag\n    -- and clang need not this flag, it will use '-include-pch' to include and preprocess header files\n    -- but it will be slower than non-ccache mode.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/5858\n    -- https://musescore.org/en/node/182331\n    if is_gcc then\n        table.insert(cppflags, \"-fpch-preprocess\")\n    end\n    table.insert(cppflags, \"-o\")\n    table.insert(cppflags, cppfile)\n    table.insert(cppflags, sourcefile)\n\n    -- we need to mark as it when compiling the preprocessed source file\n    -- it will indicate to the preprocessor that the input file has already been preprocessed.\n    if is_gcc then\n        table.insert(flags, \"-fpreprocessed\")\n    end\n    -- with -fpreprocessed, predefinition of command line and most builtin macros is disabled.\n    if directives_only then\n        table.insert(flags, \"-fdirectives-only\")\n    end\n\n    -- suppress -Wgnu-line-marker warnings\n    -- @see https://github.com/xmake-io/xmake/issues/5737\n    if (is_gcc or is_clang) and _has_gnu_line_marker_flag(tool) then\n        table.insert(flags, \"-Wno-gnu-line-marker\")\n    end\n\n    -- do preprocess\n    local cppinfo = try {function ()\n        if is_host(\"windows\") then\n            cppflags = winos.cmdargv(cppflags, {escape = true})\n        end\n        local outdata, errdata = os.iorunv(program, cppflags, opt)\n        return {outdata = outdata, errdata = errdata,\n                sourcefile = sourcefile, objectfile = objectfile, cppfile = cppfile, cppflags = flags}\n    end}\n    if not cppinfo then\n        if is_gcc then\n            local cachekey = \"core.tools.\" .. tool:name()\n            memcache.set(cachekey, \"directives_only\", false)\n        end\n    end\n    return cppinfo\nend\n\n-- compile preprocessed file\nfunction _compile_preprocessed_file(program, cppinfo, opt)\n    local argv = table.join(cppinfo.cppflags, \"-o\", cppinfo.objectfile, cppinfo.cppfile)\n    if is_host(\"windows\") then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    local outdata, errdata = os.iorunv(program, argv, opt)\n    -- we need to get warning information from output\n    -- and we need to reserve warnings output from preprocessing\n    -- @see https://github.com/xmake-io/xmake/issues/5858\n    if outdata then\n        cppinfo.outdata = (cppinfo.outdata or \"\") .. outdata\n    end\n    if errdata then\n        cppinfo.errdata = (cppinfo.errdata or \"\") .. errdata\n    end\nend\n\n-- do compile\nfunction _compile(self, sourcefile, objectfile, compflags, opt)\n    opt = opt or {}\n    local program, argv = compargv(self, sourcefile, objectfile, compflags, opt)\n    local function _compile_fallback()\n        local runargv = argv\n        if is_host(\"windows\") then\n            runargv = winos.cmdargv(argv, {escape = true})\n        end\n        return os.iorunv(program, runargv, {envs = self:runenvs(), shell = opt.shell})\n    end\n    local cppinfo\n    if distcc_build_client.is_distccjob() and distcc_build_client.singleton():has_freejobs() then\n        cppinfo = distcc_build_client.singleton():compile(program, argv, {envs = self:runenvs(),\n            preprocess = _preprocess, compile = _compile_preprocessed_file, compile_fallback = _compile_fallback,\n            tool = self, remote = true, shell = opt.shell})\n    elseif build_cache.is_enabled(opt.target) and build_cache.is_supported(self:kind()) then\n        cppinfo = build_cache.build(program, argv, {envs = self:runenvs(),\n            preprocess = _preprocess, compile = _compile_preprocessed_file, compile_fallback = _compile_fallback,\n            tool = self, shell = opt.shell})\n    end\n    if cppinfo then\n        return cppinfo.outdata, cppinfo.errdata\n    else\n        return _compile_fallback()\n    end\nend\n\n-- remove \"-include xxx.h\" and \"-include-pch xxx.pch\"\nfunction _remove_flags_for_pch(self, flags, opt)\n    opt = opt or {}\n    local result = {}\n    local include = false\n    local pchfile = opt.pchfile\n    for _, flag in ipairs(flags) do\n        local inserted = false\n        if not flag:startswith(\"-include\") then\n            if not include then\n                inserted = true\n            end\n            include = false\n        else\n            include = true\n        end\n        if pchfile and flag:startswith(\"-fmodules\") then\n            inserted = false\n        end\n        if inserted then\n            table.insert(result, flag)\n        end\n    end\n    return result\nend\n\n-- make the compile arguments list for the precompiled header\nfunction _translate_flags_for_pch(self, flags)\n    local pchflags = _remove_flags_for_pch(self, flags, {pchfile = true})\n    if self:kind() == \"cxx\" then\n        table.insert(pchflags, \"-x\")\n        table.insert(pchflags, \"c++-header\")\n    elseif self:kind() == \"cc\" then\n        table.insert(pchflags, \"-x\")\n        table.insert(pchflags, \"c-header\")\n    elseif self:kind() == \"mxx\" then\n        table.insert(pchflags, \"-x\")\n        table.insert(pchflags, \"objective-c++-header\")\n    elseif self:kind() == \"mm\" then\n        table.insert(pchflags, \"-x\")\n        table.insert(pchflags, \"objective-c-header\")\n    end\n    return pchflags\nend\n\n-- remove the force includes for c++modules\n-- @see https://github.com/xmake-io/xmake/issues/4051#issuecomment-2795707800\nfunction _translate_flags_for_mpp(self, flags)\n    return _remove_flags_for_pch(self, flags)\nend\n\n-- init it\nfunction init(self)\n\n    -- init mxflags\n    self:set(\"mxflags\", \"-pipe\"\n                      , \"-DIBOutlet=__attribute__((iboutlet))\"\n                      , \"-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))\"\n                      , \"-DIBAction=void)__attribute__((ibaction)\")\n\n    -- init shflags\n    self:set(\"shflags\", \"-shared\")\n\n    -- init flags map\n    self:set(\"mapflags\", {\n        -- warnings\n        [\"-W1\"] = \"-Wall\"\n    ,   [\"-W2\"] = \"-Wall\"\n    ,   [\"-W3\"] = \"-Wall\"\n    ,   [\"-W4\"] = \"-Wall -Wextra\"\n    ,   [\"-Weverything\"] = \"-Wall -Wextra -Weffc++\"\n\n         -- strip\n    ,   [\"-s\"]  = \"-s\"\n    ,   [\"-S\"]  = \"-Wl,-S\"\n    })\n\n    -- for macho target\n    if self:is_plat(\"macosx\", \"iphoneos\") then\n        self:add(\"mapflags\", {\n            [\"-s\"] = \"-Wl,-x\"\n        })\n    end\nend\n\n-- we can only call has_flags in load(),\n-- as it requires the full platform toolchain flags.\n--\nfunction load(self)\n    -- add -fPIC for shared\n    --\n    -- we need check it for clang/gcc with window target\n    -- @see https://github.com/xmake-io/xmake/issues/1392\n    --\n    if not self:is_plat(\"windows\", \"mingw\") and self:has_flags(\"-fPIC\") then\n        self:add(\"shflags\", \"-fPIC\")\n        self:add(\"shared.cxflags\", \"-fPIC\")\n    end\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"-Wl,-S\"\n    ,   all   = \"-s\"\n    }\n    if self:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\", \"applexros\") then\n        maps.all = {\"-Wl,-x\", \"-Wl,-dead_strip\"}\n    elseif self:is_plat(\"windows\") then\n        -- clang does not it on windows, TODO maybe we need test it for gcc\n        maps = {}\n    end\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps = {\n                debug  = \"-g\"\n            ,   hidden = \"-fvisibility=hidden\"\n            }\n            if kind == \"cxx\" and self:has_flags(\"-fvisibility-inlines-hidden\", \"cxflags\") then\n                maps.hidden_cxx = {\"-fvisibility=hidden\", \"-fvisibility-inlines-hidden\"}\n            end\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    elseif kind == \"ld\" or kind == \"sh\" then\n        -- we need to add `-g` to linker to generate pdb symbol file for mingw-gcc, llvm-clang on windows\n        local plat = self:plat()\n        if level == \"debug\" and (plat == \"windows\" or (plat == \"mingw\" and is_host(\"windows\"))) then\n            return \"-g\"\n        end\n    end\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none       = \"-w\"\n    ,   less       = \"-Wall\"\n    ,   more       = \"-Wall\"\n    ,   all        = \"-Wall\"\n    ,   allextra   = {\"-Wall\", \"-Wextra\"}\n    ,   extra      = \"-Wextra\"\n    ,   pedantic   = \"-Wpedantic\"\n    ,   everything = self:kind() == \"cxx\" and {\"-Wall\", \"-Wextra\", \"-Weffc++\"} or {\"-Wall\", \"-Wextra\"}\n    ,   error      = \"-Werror\"\n    }\n    return maps[level]\nend\n\n-- make the fp-model flag\nfunction nf_fpmodel(self, level)\n    local maps = {\n        precise    = \"\" --default\n    ,   fast       = \"-ffast-math\"\n    ,   strict     = {\"-frounding-math\", \"-ftrapping-math\"}\n    ,   except     = \"-ftrapping-math\"\n    ,   noexcept   = \"-fno-trapping-math\"\n    }\n    return maps[level]\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = {\n            none       = \"-O0\"\n        ,   fast       = \"-O1\"\n        ,   faster     = \"-O2\"\n        ,   fastest    = \"-O3\"\n        ,   smallest   = \"-Os\"\n        ,   aggressive = \"-Ofast\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the vector extension flag\n-- @see https://github.com/xmake-io/xmake/issues/1613\nfunction nf_vectorext(self, extension)\n    local maps = {\n        mmx        = \"-mmmx\"\n    ,   sse        = \"-msse\"\n    ,   sse2       = \"-msse2\"\n    ,   sse3       = \"-msse3\"\n    ,   ssse3      = \"-mssse3\"\n    ,   [\"sse4.2\"] = \"-msse4.2\"\n    ,   avx        = \"-mavx\"\n    ,   avx2       = \"-mavx2\"\n    ,   avx512     = {\"-mavx512f\", \"-mavx512dq\", \"-mavx512bw\", \"-mavx512vl\"}\n    ,   fma        = \"-mfma\"\n    ,   neon       = \"-mfpu=neon\"\n    ,   all        = \"-march=native\"\n    }\n    if extension == \"all\" and self:is_cross() then\n        -- https://github.com/xmake-io/xmake-repo/pull/4040#discussion_r1605121207\n        maps[extension] = nil\n    end\n    return maps[extension]\nend\n\n-- make the runtime flag\nfunction nf_runtime(self, runtime, opt)\n    opt = opt or {}\n    local maps\n    local kind = self:kind()\n    if not self:is_plat(\"android\") then -- we will set runtimes in android ndk toolchain\n        maps = maps or {}\n        if kind == \"ld\" or kind == \"sh\" then\n            local target = opt.target\n            if target and target.sourcekinds and table.contains(table.wrap(target:sourcekinds()), \"cxx\") then\n                if runtime:endswith(\"_static\") and _has_static_libstdcxx(self) then\n                    maps[\"stdc++_static\"] = \"-static-libstdc++\"\n                end\n            end\n        end\n    end\n    return maps and maps[runtime]\nend\n\n-- make the language flag\nfunction nf_language(self, stdname)\n\n    -- the stdc maps\n    if _g.cmaps == nil then\n        _g.cmaps = {\n            -- stdc\n            ansi        = \"-ansi\"\n        ,   c89         = \"-std=c89\"\n        ,   gnu89       = \"-std=gnu89\"\n        ,   c90         = \"-std=c90\"\n        ,   gnu90       = \"-std=gnu90\"\n        ,   c99         = \"-std=c99\"\n        ,   gnu99       = \"-std=gnu99\"\n        ,   c11         = \"-std=c11\"\n        ,   gnu11       = \"-std=gnu11\"\n        ,   c17         = \"-std=c17\"\n        ,   gnu17       = \"-std=gnu17\"\n        ,   c23         = {\"-std=c23\", \"-std=c2x\"}\n        ,   gnu23       = {\"-std=gnu23\", \"-std=gnu2x\"}\n        ,   clatest     = {\"-std=c23\", \"-std=c2x\", \"-std=c17\", \"-std=c11\", \"-std=c99\", \"-std=c89\", \"-ansi\"}\n        ,   gnulatest   = {\"-std=gnu23\", \"-std=gnu2x\", \"-std=gnu17\", \"-std=gnu11\", \"-std=gnu99\", \"-std=gnu89\", \"-ansi\"}\n        }\n    end\n\n    -- the stdc++ maps\n    if _g.cxxmaps == nil then\n        _g.cxxmaps = {\n            cxx98        = \"-std=c++98\"\n        ,   gnuxx98      = \"-std=gnu++98\"\n        ,   cxx03        = \"-std=c++03\"\n        ,   gnuxx03      = \"-std=gnu++03\"\n        ,   cxx11        = \"-std=c++11\"\n        ,   gnuxx11      = \"-std=gnu++11\"\n        ,   cxx14        = \"-std=c++14\"\n        ,   gnuxx14      = \"-std=gnu++14\"\n        ,   cxx17        = \"-std=c++17\"\n        ,   gnuxx17      = \"-std=gnu++17\"\n        ,   cxx1z        = \"-std=c++1z\"\n        ,   gnuxx1z      = \"-std=gnu++1z\"\n        ,   cxx20        = {\"-std=c++20\", \"-std=c++2a\"}\n        ,   gnuxx20      = {\"-std=gnu++20\", \"-std=c++2a\"}\n        ,   cxx2a        = \"-std=c++2a\"\n        ,   gnuxx2a      = \"-std=gnu++2a\"\n        ,   cxx23        = {\"-std=c++23\", \"-std=c++2b\"}\n        ,   gnuxx23      = {\"-std=gnu++23\", \"-std=c++2b\"}\n        ,   cxx2b        = \"-std=c++2b\"\n        ,   gnuxx2b      = \"-std=gnu++2b\"\n        ,   cxx2c        = \"-std=c++2c\"\n        ,   gnuxx2c      = \"-std=gnu++2c\"\n        ,   cxx26        = {\"-std=c++26\", \"-std=c++2c\"}\n        ,   gnuxx26      = {\"-std=gnu++26\", \"-std=gnu++2c\"}\n        ,   cxxlatest    = {\"-std=c++26\", \"-std=c++2c\", \"-std=c++23\", \"-std=c++2b\", \"-std=c++20\", \"-std=c++2a\", \"-std=c++17\", \"-std=c++14\", \"-std=c++11\", \"-std=c++1z\", \"-std=c++98\"}\n        ,   gnuxxlatest  = {\"-std=gnu++26\", \"-std=gnu++2c\", \"-std=gnu++23\", \"-std=gnu++2\", \"-std=gnu++20\", \"-std=gnu++2a\", \"-std=gnu++17\", \"-std=gnu++14\", \"-std=gnu++11\", \"-std=c++1z\", \"-std=gnu++98\"}\n        }\n        local cxxmaps2 = {}\n        for k, v in pairs(_g.cxxmaps) do\n            cxxmaps2[k:gsub(\"xx\", \"++\")] = v\n        end\n        table.join2(_g.cxxmaps, cxxmaps2)\n    end\n\n    -- select maps\n    local maps = _g.cmaps\n    if self:kind() == \"cxx\" or self:kind() == \"mxx\" then\n        maps = _g.cxxmaps\n    elseif self:kind() == \"sc\" then\n        maps = {}\n    end\n    local result = maps[stdname]\n    if type(result) == \"table\" then\n        for _, v in ipairs(result) do\n            if self:has_flags(v, \"cxflags\") then\n                result = v\n                maps[stdname] = result\n                return result\n            end\n        end\n    else\n        return result\n    end\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. path.translate(dir)}\nend\n\n-- make the embeddir flag\nfunction nf_embeddir(self, dir)\n    return {\"--embed-dir=\" .. path.translate(dir)}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return {\"-isystem\", path.translate(dir)}\nend\n\n-- make the force include flag\nfunction nf_forceinclude(self, headerfile, opt)\n    local target = opt.target\n    local sourcekinds = target and target:extraconf(\"forceincludes\", headerfile, \"sourcekinds\")\n    if not sourcekinds or table.contains(table.wrap(sourcekinds), self:kind()) then\n        return {\"-include\", headerfile}\n    end\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if self:is_plat(\"linux\") and (lib:endswith(\".a\") or lib:endswith(\".so\")) and not lib:find(path.sep(), 1, true) then\n        return \"-l:\" .. lib\n    elseif lib:endswith(\".a\") or lib:endswith(\".so\") or lib:endswith(\".dylib\") or lib:endswith(\".lib\") then\n        return lib\n    else\n        return \"-l\" .. lib\n    end\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the link group flag\nfunction nf_linkgroup(self, linkgroup, opt)\n    local linkflags = {}\n    for _, lib in ipairs(linkgroup) do\n        table.insert(linkflags, nf_link(self, lib))\n    end\n    local flags = {}\n    local extra = opt.extra\n    if extra and not self:is_plat(\"macosx\", \"windows\", \"mingw\") then\n        local as_needed = extra.as_needed\n        local whole = extra.whole\n        local group = extra.group\n        local static = extra.static\n        local prefix_flags = {}\n        local suffix_flags = {}\n        if static then\n            table.insert(prefix_flags, \"-Wl,-Bstatic\")\n            table.insert(suffix_flags, 1, \"-Wl,-Bdynamic\")\n        end\n        -- https://github.com/xmake-io/xmake/issues/5621\n        if as_needed then\n            table.insert(prefix_flags, \"-Wl,--as-needed\")\n            table.insert(suffix_flags, 1, \"-Wl,--no-as-needed\")\n        elseif as_needed == false then\n            table.insert(prefix_flags, \"-Wl,--no-as-needed\")\n            table.insert(suffix_flags, 1, \"-Wl,--as-needed\")\n        end\n        if whole then\n            table.insert(prefix_flags, \"-Wl,--whole-archive\")\n            table.insert(suffix_flags, 1, \"-Wl,--no-whole-archive\")\n        end\n        if group then\n            table.insert(prefix_flags, \"-Wl,--start-group\")\n            table.insert(suffix_flags, 1, \"-Wl,--end-group\")\n        end\n        table.join2(flags, prefix_flags, linkflags, suffix_flags)\n    end\n    if #flags == 0 then\n        flags = linkflags\n    end\n    return flags\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. path.translate(dir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir, opt)\n    if self:is_plat(\"windows\", \"mingw\") then\n        return\n    end\n    opt = opt or {}\n    local extra = opt.extra\n    if extra and extra.installonly then\n        return\n    end\n    dir = path.translate(dir)\n    if self:has_flags(\"-Wl,-rpath=\" .. dir, \"ldflags\") then\n        local flags = {\"-Wl,-rpath=\" .. (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n            return maps[name]\n        end))}\n        -- add_rpathdirs(\"...\", {runpath = false})\n        -- https://github.com/xmake-io/xmake/issues/5109\n        if extra then\n            if extra.runpath == false and self:has_flags(\"-Wl,-rpath=\" .. dir .. \",--disable-new-dtags\", \"ldflags\") then\n                flags[1] = flags[1] .. \",--disable-new-dtags\"\n            elseif extra.runpath == true and self:has_flags(\"-Wl,-rpath=\" .. dir .. \",--enable-new-dtags\", \"ldflags\") then\n                flags[1] = flags[1] .. \",--enable-new-dtags\"\n            end\n        end\n        if self:is_plat(\"bsd\") then\n            -- FreeBSD ld must have \"-zorigin\" with \"-rpath\".  Otherwise, $ORIGIN is not translated and it is literal.\n            table.insert(flags, 1, \"-Wl,-zorigin\")\n        end\n        return flags\n    elseif self:has_flags(\"-Xlinker -rpath -Xlinker \" .. dir, \"ldflags\") then\n        return {\"-Xlinker\", \"-rpath\", \"-Xlinker\", (dir:gsub(\"%$ORIGIN\", \"@loader_path\"))}\n    end\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    return {\"-framework\", framework}\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-F\" .. path.translate(frameworkdir)}\nend\n\n-- make the exception flag\n--\n-- e.g.\n-- set_exceptions(\"cxx\")\n-- set_exceptions(\"objc\")\n-- set_exceptions(\"no-cxx\")\n-- set_exceptions(\"no-objc\")\n-- set_exceptions(\"cxx\", \"objc\")\nfunction nf_exception(self, exp)\n    return exp:startswith(\"no-\") and \"-fno-exceptions\" or \"-fexceptions\"\nend\n\n-- make the encoding flag\n-- @see https://github.com/xmake-io/xmake/issues/2471\n--\n-- e.g.\n-- set_encodings(\"utf-8\")\n-- set_encodings(\"source:utf-8\", \"target:utf-8\")\nfunction nf_encoding(self, encoding)\n    local kind\n    local charset\n    local splitinfo = encoding:split(\":\")\n    if #splitinfo > 1 then\n        kind = splitinfo[1]\n        charset = splitinfo[2]\n    else\n        charset = encoding\n    end\n    local charsets = {\n        [\"utf-8\"] = \"UTF-8\",\n        utf8 = \"UTF-8\"\n    }\n    local flags = {}\n    charset = charsets[charset:lower()]\n    if charset then\n        if kind == \"source\" or not kind then\n            table.insert(flags, \"-finput-charset=\" .. charset)\n        end\n        if kind == \"target\" or not kind then\n            table.insert(flags, \"-fexec-charset=\" .. charset)\n        end\n    end\n    if #flags > 0 then\n        return flags\n    end\nend\n\n-- make the c precompiled header flag\nfunction nf_pcheader(self, pcheaderfile, opt)\n    if self:kind() == \"cc\" then\n        local target = opt.target\n        local pcoutputfile = target:pcoutputfile(\"c\")\n        if self:name():startswith(\"clang\") then\n            return {\"-include\", pcheaderfile, \"-include-pch\", pcoutputfile}\n        else\n            return {\"-I\", path.directory(pcoutputfile), \"-include\", path.filename(pcheaderfile)}\n        end\n    end\nend\n\n-- make the c++ precompiled header flag\nfunction nf_pcxxheader(self, pcheaderfile, opt)\n    if self:kind() == \"cxx\" then\n        local target = opt.target\n        local pcoutputfile = target:pcoutputfile(\"cxx\")\n        if self:name():startswith(\"clang\") then\n            return {\"-include\", pcheaderfile, \"-include-pch\", pcoutputfile}\n        else\n            return {\"-I\", path.directory(pcoutputfile), \"-include\", path.filename(pcheaderfile)}\n        end\n    end\nend\n\n-- make the objc precompiled header flag\nfunction nf_pmheader(self, pcheaderfile, opt)\n    if self:kind() == \"mm\" then\n        local target = opt.target\n        local pcoutputfile = target:pcoutputfile(\"m\")\n        if self:name():startswith(\"clang\") then\n            return {\"-include\", pcheaderfile, \"-include-pch\", pcoutputfile}\n        else\n            return {\"-I\", path.directory(pcoutputfile), \"-include\", path.filename(pcheaderfile)}\n        end\n    end\nend\n\n-- make the objc++ precompiled header flag\nfunction nf_pmxxheader(self, pcheaderfile, opt)\n    if self:kind() == \"mxx\" then\n        local target = opt.target\n        local pcoutputfile = target:pcoutputfile(\"mxx\")\n        if self:name():startswith(\"clang\") then\n            return {\"-include\", pcheaderfile, \"-include-pch\", pcoutputfile}\n        else\n            return {\"-I\", path.directory(pcoutputfile), \"-include\", path.filename(pcheaderfile)}\n        end\n    end\nend\n\n-- add the special flags for the given source file of target\n--\n-- @note only it called when fileconfig is set\n--\nfunction add_sourceflags(self, sourcefile, fileconfig, target, targetkind)\n\n    -- add language type flags explicitly if the sourcekind is changed.\n    --\n    -- because compiler maybe compile `.c` as c++.\n    -- e.g.\n    --   add_files(\"*.c\", {sourcekind = \"cxx\"})\n    --\n    local sourcekind = fileconfig.sourcekind\n    if sourcekind then\n        local maps = {cc = \"-x c\", cxx = \"-x c++\"}\n        return maps[sourcekind]\n    end\nend\n\n-- show warnings\nfunction _show_warnings(self, output)\n    local lines = output:split('\\n', {plain = true})\n    if #lines > 0 then\n        if not option.get(\"diagnosis\") then\n            lines = table.slice(lines, 1, (#lines > 16 and 16 or #lines))\n        end\n        local warnings = table.concat(lines, \"\\n\")\n        progress.show_output(\"${color.warning}%s\", warnings)\n    end\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n\n    -- add rpath for dylib (macho), e.g. -install_name @rpath/file.dylib\n    local flags_extra = {}\n    if targetkind == \"shared\" and self:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n        if not table.contains(flags, \"-install_name\") then\n            table.insert(flags_extra, \"-install_name\")\n            table.insert(flags_extra, \"@rpath/\" .. path.filename(targetfile))\n        end\n    end\n\n    -- add `-Wl,--out-implib,outputdir/libxxx.a` for xxx.dll on mingw/gcc\n    local implibfile = _get_implibfile(self, targetkind, targetfile, opt)\n    if implibfile then\n        table.insert(flags_extra, \"-Wl,--out-implib,\" .. implibfile)\n    end\n\n    -- init arguments\n    opt = opt or {}\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags, flags_extra)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- enable linker output?\n    local target = opt.target\n    local linker_output = option.get(\"verbose\")\n    if linker_output == nil and target and target.policy and target:policy(\"build.linker.output\") then\n        linker_output = true\n    end\n\n    os.mkdir(path.directory(targetfile))\n    local implibfile = _get_implibfile(self, targetkind, targetfile, opt)\n    if implibfile then\n        os.mkdir(path.directory(implibfile))\n    end\n\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    if linker_output then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags, opt)\n    opt = opt or {}\n\n    -- is precompiled header or module files? remove the force includes.\n    local extension = path.extension(sourcefile)\n    if toolchain_utils.is_cxx_headerext(extension) then\n        flags = _translate_flags_for_pch(self, flags)\n    elseif support.has_module_extension(sourcefile, {extension = extension}) then\n        flags = _translate_flags_for_mpp(self, flags)\n    end\n\n    -- if syntax-only, add -fsyntax-only and skip -c and -o\n    if _is_syntax_check() then\n        table.insert(flags, \"-fsyntax-only\")\n        return self:program(), table.join(flags, sourcefile)\n    end\n\n    local argv = table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\n    return self:program(), argv\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(objectfile))\n\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if depfile then\n                if _is_cosmocc(self) then\n                    depfile = path.unix(depfile)\n                end\n                local depfile_flags = _get_depfile_flags(self)\n                if depfile_flags then\n                    compflags = table.join(compflags, depfile_flags, depfile)\n                end\n            end\n\n            -- attempt to enable color diagnostics\n            local colors_diagnostics = _get_color_diagnostics_flag(self)\n            if colors_diagnostics then\n                compflags = table.join(compflags, colors_diagnostics)\n            end\n\n            -- do compile\n            return _compile(self, sourcefile, objectfile, compflags, opt)\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- remove preprocess file\n                local cppfile = _get_cppfile(sourcefile, objectfile)\n                os.tryrm(cppfile)\n\n                -- parse and strip errors\n                local lines = errors and tostring(errors):split('\\n', {plain = true}) or {}\n                if not option.get(\"verbose\") then\n\n                    -- find the start line of error\n                    local start = 0\n                    for index, line in ipairs(lines) do\n                        if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                            start = index\n                            break\n                        end\n                    end\n\n                    -- get 16 lines of errors\n                    if start > 0 then\n                        lines = table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start)))\n                    end\n                end\n\n                -- raise compiling errors\n                local results = #lines > 0 and table.concat(lines, \"\\n\") or \"\"\n                if not option.get(\"verbose\") then\n                    results = results .. \"\\n  ${yellow}> in ${bright}\" .. sourcefile\n                end\n                raise(results)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                -- show warnings?\n                if ok and errdata and #errdata > 0 and policy.build_warnings(opt) then\n                    _show_warnings(self, errdata)\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"gcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/gcc_ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gcc_ar.lua\n--\n\ninherit(\"ar\")\nimport(\"lib.detect.find_file\")\n\n-- replace gcc-ar\nfunction _replace_gcc_ar(program, name)\n    local dir = path.directory(program)\n    local filename = path.filename(program)\n    filename = filename:gsub(\"gcc%-ar\", name)\n    if dir and dir ~= \".\" then\n        program = path.join(dir, filename)\n    else\n        program = filename\n    end\n    return program\nend\n\n-- get liblto_plugin.so path for gcc\nfunction _get_gcc_liblto_plugin_path(self, program)\n    local plugin_path = _g.LTO_PLUGIN_PATH\n    if plugin_path == nil then\n        local gcc = _replace_gcc_ar(program, \"gcc\")\n        local outdata = try { function() return os.iorunv(gcc, {\"-print-prog-name=lto-wrapper\"}) end }\n        if outdata then\n            local lto_plugindir = path.directory(outdata:trim())\n            if os.isdir(lto_plugindir) then\n                if is_host(\"windows\") then\n                    plugin_path = find_file(\"liblto_plugin*.dll\", lto_plugindir)\n                else\n                    plugin_path = find_file(\"liblto_plugin.so\", lto_plugindir)\n                end\n            end\n        end\n        plugin_path = plugin_path or false\n        _g.LTO_PLUGIN_PATH = plugin_path\n    end\n    return plugin_path or nil\nend\n\n-- link the library file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n\n    -- @note remove the previous archived file first to force recreating a new file\n    os.tryrm(targetfile)\n\n    -- generate link arguments\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    if is_host(\"windows\") and argv and #argv > 0 and argv[1]:startswith(\"@\") then\n        -- gcc-ar.exe does not support `@file`, so we need use ar.exe to instead of it.\n        -- @see https://github.com/xmake-io/xmake/issues/5051\n        --\n        -- but ar.exe does not support lto, we need also add lto_plugin-0.dll path in `@file` for gcc\n        -- @see https://github.com/xmake-io/xmake/issues/5015\n        --\n        -- gcc-ar is the wrapper of `ar --plugin lto_plugin.so ...`\n        --\n        local _, rawargv = linkargv(self, objectfiles, targetkind, targetfile, flags, table.join(opt, {rawargs = true}))\n        local plugin_path = _get_gcc_liblto_plugin_path(self, program)\n        if plugin_path then\n            argv = winos.cmdargv(table.join({\"--plugin\", plugin_path}, rawargv), {escape = true})\n        end\n        program = _replace_gcc_ar(program, \"ar\")\n    end\n\n    -- link it\n    os.runv(program, argv, {envs = self:runenvs(), shell = opt.shell})\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gccgo/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gccgo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gccgo.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gdc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"dcld\" or toolkind == \"dcsh\"\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.gdc.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"gdc_has_flags.d\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"void main()\\n{}\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", os.tmpfile(), sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-S\", \"-o\", os.tmpfile(), sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gdc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, BarrOff\n-- @file        gdc.lua\n--\n\n-- imports\ninherit(\"gcc\")\n\n-- init it\nfunction init(self)\n\n    -- init arflags\n    self:set(\"dcarflags\", \"-cr\")\n\n    -- init shflags\n    self:set(\"dcshflags\", \"-shared\", \"-fPIC\")\n\n    -- init dcflags for the kind: shared\n    self:set(\"shared.dcflags\", \"-fPIC\")\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        fast        = \"-O\"\n    ,   faster      = \"-O -frelease\"\n    ,   fastest     = \"-O -frelease -fbounds-check=off\"\n    ,   smallest    = \"-O -frelease -fbounds-check=off\"\n    ,   aggressive  = \"-O -frelease -fbounds-check=off\"\n    }\n    return maps[level]\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gfortran/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"-ld\") or toolkind:endswith(\"-sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.gfortran.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"gfortran_has_flags.f90\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"program hello\\n  print *, \\\"Hello World!\\\"\\nend program hello\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", os.tmpfile(), sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-S\", \"-o\", os.tmpfile(), sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gfortran.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gfortran.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n-- init it\nfunction init(self)\n\n    -- init super\n    _super.init(self)\n\n    -- init shflags\n    self:set(\"fcshflags\", \"-shared\")\n\n    -- add -fPIC for shared\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"fcshflags\", \"-fPIC\")\n        self:add(\"shared.fcflags\", \"-fPIC\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/go/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    -- the tool kind is gcld or gcsh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    local ok = try { \n        function () \n            os.runv(program, argv, opt)\n            return true \n        end, \n        catch { \n            function (errs) \n                errors = (errs or \"\"):trim() \n            end \n        }\n    }\n    return ok, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    -- only for compiler and single flag\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.go.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        \n        -- try to get help from \"go help build\"\n        local help_output = try { \n            function () \n                return os.iorunv(opt.program, {\"help\", \"build\"}, {envs = opt.envs}) \n            end \n        }\n        \n        if help_output then\n            -- parse flags from help output\n            for flag in help_output:gmatch(\"%s+(%-[%-%a%d=]+)%s+\") do\n                allflags[flag] = true\n            end\n        end\n        \n        -- also try \"go build -h\" for more detailed flags\n        local build_help = try { \n            function () \n                return os.iorunv(opt.program, {\"build\", \"-h\"}, {envs = opt.envs}) \n            end \n        }\n        \n        if build_help then\n            for flag in build_help:gmatch(\"%s+(%-[%-%a%d=]+)%s+\") do\n                allflags[flag] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    \n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"go_has_flags.go\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"package main\\n\\nfunc main() {\\n}\\n\")\n    end\n\n    -- check flags for linker or compiler\n    -- Modern Go uses \"go build\" for both compilation and linking\n    local argv = {\"build\", \"-o\", os.tmpfile()}\n    table.join2(argv, flags)\n    table.insert(argv, sourcefile)\n    \n    local ok, errors = _try_running(opt.program, argv, {envs = opt.envs})\n    return ok == true\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[gc|gcld|gcar]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/go.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        go.lua\n--\n\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n    self:set(\"gcarflags\", \"\")\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps = {\n        none = \"-gcflags=-N\"\n    }\n    return maps[level]\nend\n\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = {\"-ldflags\", \"-s\"}\n    ,   all   = {\"-ldflags\", \"-s -w\"}\n    }\n    return maps[level]\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-ldflags\", \"-L \" .. dir}\nend\n\n-- make the build arguments list\n-- Modern Go uses \"go build\" command for both compilation and linking\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    local argv = {\"build\"}\n    if flags then\n        table.join2(argv, flags)\n    end\n    table.insert(argv, \"-o\")\n    table.insert(argv, targetfile)\n\n    -- for static library, use buildmode=archive\n    if targetkind == \"static\" then\n        table.insert(argv, \"-buildmode=archive\")\n    end\n\n    -- add source files (Go supports building from source file list)\n    table.join2(argv, sourcefiles)\n\n    return self:program(), argv\nend\n\n-- build the target file (compile and link in one step)\nfunction build(self, sourcefiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    os.runv(program, argv, {envs = self:runenvs()})\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/gxx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/gxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gxx.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/iarchive.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        iarchive.lua\n--\n\ninherit(\"ar\")\n\nfunction init(self)\n    self:set(\"arflags\", \"--create\")\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/icc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icc.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n-- init it\nfunction init(self)\n    _super.init(self)\nend\n\n-- make the fp-model flag\nfunction nf_fpmodel(self, level)\n    local maps =\n    {\n        precise    = \"-fp-model=precise\"\n    ,   fast       = \"-fp-model=fast\"  --default\n    ,   strict     = \"-fp-model=strict\"\n    ,   except     = \"-fp-model=except\"\n    ,   noexcept   = \"-fp-model=no-except\"\n    }\n    return maps[level]\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/iccarm/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from known flags\nfunction _check_from_knownargs(flags, opt, islinker)\n    local flag = flags[1]\n    if not islinker then\n        if flag:startswith(\"-D\") or\n           flag:startswith(\"-U\") or\n           flag:startswith(\"-I\") then\n            return true\n        end\n    end\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n    local key = \"core.tools.iccarm.\" .. (islinker and \"has_ldflags\" or \"has_cflags\")\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = try {function () return os.iorunv(opt.program, {\"--help\"}, {envs = opt.envs}) end}\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n        detectcache:set2(key, flagskey, allflags)\n    end\n    local flag = flags[1]\n    return allflags[flag]\nend\n\n-- get extension\nfunction _get_extension(opt)\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    return (opt.program:endswith(\"++\") or opt.flagkind == \"cxxflags\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"iccarm_has_flags:\" .. snippet) .. _get_extension(opt)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    -- check flags for linker\n    local tmpfile = os.tmpfile()\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", tmpfile, sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-c\", \"-o\", tmpfile, sourcefile), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    opt = opt or {}\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if not opt.tryrun then\n        if _check_from_arglist(flags, opt, islinker) then\n            return true\n        end\n        if _check_from_knownargs(flags, opt, islinker) then\n            return true\n        end\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/iccarm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        iccarm.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps =\n            {\n                debug  = \"--debug\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-On\"\n    ,   fast       = \"-Ol\"\n    ,   faster     = \"-Om\"\n    ,   fastest    = \"-Oh\"\n    ,   smallest   = \"-Ohz\"\n    ,   aggressive = \"-Ohs\"\n    }\n    return maps[level]\nend\n\n-- make the vector extension flag\nfunction nf_vectorext(self, extension)\n    local maps = {\n        all = \"--vectorize\"\n    }\n    return maps[extension]\nend\n\n-- make the language flag\nfunction nf_language(self, stdname)\n    if _g.cmaps == nil then\n        _g.cmaps = {\n            c89 = \"--c89\"\n        }\n    end\n    return _g.cmaps[stdname]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return \"-D\" .. macro\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n    try\n    {\n        function ()\n            local compflags = flags\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and not warnings:find(\"Warnings: none\", 1, true) and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icl/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.cl.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icl.lua\n--\n\n-- inherit cl\ninherit(\"cl\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icpc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gxx.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icpc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icpc.lua\n--\n\n-- inherit icc\ninherit(\"icc\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icpx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icpx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icpx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icpc.lua\n--\n\n-- inherit icc\ninherit(\"icx\")\n"
  },
  {
    "path": "xmake/modules/core/tools/icx/cfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.clang.cfeatures\")\n"
  },
  {
    "path": "xmake/modules/core/tools/icx/cxxfeatures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxfeatures.lua\n--\n\n-- imports\nimport(\"core.tools.clang.cxxfeatures\")\n"
  },
  {
    "path": "xmake/modules/core/tools/icx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.features\")\n"
  },
  {
    "path": "xmake/modules/core/tools/icx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.clang.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/icx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        icc.lua\n--\n\n-- inherit gcc\ninherit(\"clang\")\n"
  },
  {
    "path": "xmake/modules/core/tools/ifort/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nif is_host(\"windows\") then\n    inherit(\"core.tools.cl.has_flags\")\nelse\n    inherit(\"core.tools.gfortran.has_flags\")\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ifort.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ifort.lua\n--\n\nif is_host(\"windows\") then\n\n    -- imports\n    inherit(\"cl\")\n    inherit(\"link\")\n    import(\"private.tools.vstool\")\n\n    -- init it\n    function init(self)\n        self:set(\"fcflags\", \"-nologo\")\n        self:set(\"fcldflags\", \"-nologo\", \"-dynamicbase\", \"-nxcompat\")\n        self:set(\"fcshflags\", \"-nologo\")\n    end\n\n    -- get the property\n    function get(self, name)\n        local values = self._INFO[name]\n        if name == \"fcldflags\" or name == \"fcarflags\" or name == \"fcshflags\" then\n            -- switch architecture, @note does cache it in init() for generating vs201x project\n            values = table.join(values, \"-machine:\" .. (self:arch() or \"x86\"))\n        end\n        return values\n    end\n\n    -- make the link arguments list\n    function linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n        opt = opt or {}\n        local argv = table.join(\"-o\", targetfile, objectfiles, \"/link\", flags)\n        if not opt.rawargs then\n            argv = winos.cmdargv(argv, {escape = true})\n        end\n        -- @note we cannot put -dll to @args.txt\n        if targetkind == \"shared\" then\n            table.insert(argv, 1, \"-dll\")\n        end\n        return self:program(), argv\n    end\n\n    -- link the target file\n    function link(self, objectfiles, targetkind, targetfile, flags, opt)\n\n        -- ensure the target directory\n        os.mkdir(path.directory(targetfile))\n\n        try\n        {\n            function ()\n\n                -- use vstool to link and enable vs_unicode_output @see https://github.com/xmake-io/xmake/issues/528\n                local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n                vstool.runv(program, argv, {envs = self:runenvs()})\n            end,\n            catch\n            {\n                function (errors)\n\n                    -- use link/stdout as errors first from vstool.iorunv()\n                    if type(errors) == \"table\" then\n                        local errs = errors.stdout or \"\"\n                        if #errs:trim() == 0 then\n                            errs = errors.stderr or \"\"\n                        end\n                        errors = errs\n                    end\n                    os.raise(tostring(errors))\n                end\n            }\n        }\n    end\nelse\n    inherit(\"gfortran\")\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/ifx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.ifort.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ifx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ifx.lua\n--\n\ninherit(\"ifort\")\n"
  },
  {
    "path": "xmake/modules/core/tools/ilinkarm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ilinkarm.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"--strip\"\n    ,   all   = \"--strip\"\n    }\n    return maps[level]\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. path.translate(dir)}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags)\n    return self:program(), argv\nend\n\n-- link the target file\n--\n-- maybe we need to use os.vrunv() to show link output when enable verbose information\n-- @see https://github.com/xmake-io/xmake/discussions/2916\n--\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(targetfile))\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags)\n    if option.get(\"verbose\") then\n        os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    else\n        os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell})\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/kotlinc_native/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.kotlinc_native.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"kotlinc_native_has_flags.kt\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"fun main() {\\n}\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(flags, sourcefile, \"-o\", os.tmpfile()), opt)\n    end\n\n    -- check flags for compiler\n    local libraryfile = os.tmpfile()\n    local ok, errors = _try_running(opt.program, table.join(\"-produce\", \"static\", flags, sourcefile, \"-o\", libraryfile))\n    os.tryrm(libraryfile)\n    return ok, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/kotlinc_native.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        kotlinc_native.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return {\"-l\", lib}\nend\n\n-- make the build arguments list\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)\n    return self:program(), table.join(flags, sourcefiles, \"-o\", targetfile)\nend\n\n-- build the target file\nfunction build(self, sourcefiles, targetkind, targetfile, flags, opt)\n    os.mkdir(path.directory(targetfile))\n    local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    os.runv(program, argv, {envs = self:runenvs()})\n    if targetkind == \"binary\" then\n        local targetfile_real = targetfile .. (self:is_plat(\"windows\") and \".exe\" or \".kexe\")\n        if os.isfile(targetfile_real) then\n            os.mv(targetfile_real, targetfile)\n            if self:is_plat(\"macosx\", \"iphoneos\") then\n                local symbolfile_real = targetfile_real .. \".dSYM\"\n                local symbolfile = targetfile .. \".dSYM\"\n                if os.isdir(symbolfile_real) then\n                    os.mv(symbolfile_real, symbolfile)\n                end\n            end\n        end\n    elseif targetkind == \"static\" and self:is_plat(\"windows\") then\n        local headerfile_real = targetfile .. \"_api.h\"\n        local headerfile = path.join(path.directory(targetfile), \"lib\" .. path.basename(targetfile) .. \"_api.h\")\n        if os.isfile(headerfile_real) then\n            os.mv(headerfile_real, headerfile)\n        end\n\n        local targetfile_real = path.join(path.directory(targetfile), \"lib\" .. path.basename(targetfile) .. \".lib.a\")\n        if os.isfile(targetfile_real) then\n            os.mv(targetfile_real, targetfile)\n        end\n    elseif targetkind == \"shared\" and self:is_plat(\"windows\") then\n        local headerfile_real = path.join(path.directory(targetfile), path.basename(targetfile) .. \"_api.h\")\n        local headerfile = path.join(path.directory(targetfile), \"lib\" .. path.basename(targetfile) .. \"_api.h\")\n        if os.isfile(headerfile_real) then\n            os.mv(headerfile_real, headerfile)\n        end\n        local deffile = path.join(path.directory(targetfile), path.basename(targetfile) .. \".def\")\n        local libfile = path.join(path.directory(targetfile), path.basename(targetfile) .. \".lib\")\n        if os.isfile(deffile) then\n            local msvc = toolchain.load(\"msvc\", {plat = self:plat(), arch = self:arch()})\n            if msvc:check() then\n                local lib = find_tool(\"lib\", {envs = msvc:runenvs()})\n                if lib then\n                    os.runv(lib.program, {\"/def:\" .. deffile, \"/out:\" .. libfile}, {envs = msvc:runenvs()})\n                end\n            end\n        end\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ld.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init shflags\n    self:set(\"shflags\", \"-shared\")\n\n    -- add -fPIC for shared\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:add(\"shflags\", \"-fPIC\")\n        self:add(\"shared.cxflags\", \"-fPIC\")\n    end\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"-S\"\n    ,   all   = \"-s\"\n    }\n    if self:is_plat(\"macosx\", \"iphoneos\") then\n        maps.all   = \"-Wl,-x\"\n        maps.debug = \"-Wl,-S\"\n    end\n    return maps[level]\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\", path.translate(dir)}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local argv = table.join(\"-o\", targetfile, objectfiles, flags)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ld64_lld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ld64_lld.lua\n--\n\n-- imports\ninherit(\"ld\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ld_lld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ld_lld.lua\n--\n\n-- imports\ninherit(\"ld\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ldc2/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.dmd.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ldc2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, BarrOff\n-- @file        ldc2.lua\n--\n\n-- imports\ninherit(\"dmd\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init arflags\n    self:set(\"dcarflags\", \"-lib\")\n\n    -- init shflags\n    self:set(\"dcshflags\", \"-shared\", \"--relocation-model=pic\")\n\n    -- init dcflags for the kind: shared\n    self:set(\"shared.dcflags\", \"--relocation-model=pic\")\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps = {\n        none        = \"--O0\"\n    ,   fast        = \"--O1\"\n    ,   faster      = {\"--O2\", \"--release\"}\n    ,   fastest     = {\"--O3\", \"--release\", \"--boundscheck=off\"}\n    ,   smallest    = {\"--Oz\", \"--release\", \"--boundscheck=off\"}\n    ,   aggressive  = {\"--O4\", \"--release\", \"--boundscheck=off\"}\n    }\n    return maps[level]\nend\n\n-- make the linkdir flag\n-- ldc2 on windows uses msvc link.exe which requires /libpath: (not -libpath:)\nfunction nf_linkdir(self, dir)\n    if self:is_plat(\"windows\") then\n        return {\"-L/libpath:\" .. dir}\n    else\n        return {\"-L-L\" .. dir}\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps = {\n                debug  = {\"-g\", \"--d-debug\"}\n            ,   hidden = \"-fvisibility=hidden\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    elseif (kind == \"dcld\" or kind == \"dcsh\") and self:is_plat(\"windows\") and level == \"debug\" then\n        return \"-g\"\n    end\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/link/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.global_detectcache\")\nimport(\"lib.detect.find_tool\")\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n    local key = \"core.tools.link.has_flags\"\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n    local allflags = global_detectcache:get2(key, flagskey)\n    if not allflags then\n        allflags = {}\n        local arglist = nil\n        try {\n            function () os.runv(opt.program, {\"-?\"}, {envs = opt.envs}) end,\n            catch {\n                function (errors) arglist = errors end\n            }\n        }\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\"):lower()] = true\n            end\n        end\n        global_detectcache:set2(key, flagskey, allflags)\n        global_detectcache:save()\n    end\n    local flag = flags[1]:gsub(\"/\", \"-\"):lower()\n    return allflags[flag]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local flags_str = table.concat(flags, \" \"):lower()\n    local winmain = flags_str:find(\"subsystem:windows\")\n    local sourcefile = path.join(os.tmpdir(), \"detect\", (winmain and \"winmain_\" or \"\") .. \"link_has_flags.c\")\n    if not os.isfile(sourcefile) then\n        if winmain then\n            io.writefile(sourcefile, \"int WinMain(void* instance, void* previnst, char** argv, int argc)\\n{return 0;}\\n\")\n        else\n            io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n        end\n    end\n\n    -- compile the source file\n    local objectfile = os.tmpfile() .. \".obj\"\n    local binaryfile = os.tmpfile() .. \".exe\"\n    local cl = find_tool(\"cl\", {envs = opt.envs})\n    if cl then\n        os.runv(cl.program, {\"-c\", \"-nologo\", \"-Fo\" .. objectfile, sourcefile}, {envs = opt.envs})\n    end\n\n    -- try link it\n    local ok, errors = _try_running(opt.program, table.join(flags, \"-nologo\", \"-out:\" .. binaryfile, objectfile), {envs = opt.envs})\n    os.tryrm(objectfile)\n    os.tryrm(binaryfile)\n    return ok, errors\nend\n\n-- ignore some flags\nfunction _ignore_flags(flags)\n    local results = {}\n    for _, flag in ipairs(flags) do\n        flag = flag:lower()\n        if not flag:find(\"[%-/]def:.+%.def\") and not flag:find(\"[%-/]export:\") then\n            table.insert(results, flag)\n        end\n    end\n    return results\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- ignore some flags\n    flags = _ignore_flags(flags)\n    if #flags == 0 then\n        return true\n    end\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/link.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        link.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"private.tools.vstool\")\n\n-- get implib file\nfunction _get_implibfile(self, opt)\n    local target = opt and opt.target\n    if target and target:type() == \"target\" then\n        return target:artifactfile(\"implib\")\n    end\nend\n\n-- init it\nfunction init(self)\n\n    -- init ldflags\n    self:set(\"ldflags\", \"-nologo\", \"-dynamicbase\", \"-nxcompat\")\n\n    -- init arflags\n    self:set(\"arflags\", \"-nologo\")\n\n    -- init shflags\n    self:set(\"shflags\", \"-nologo\")\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- strip\n        [\"-s\"]                  = \"\"\n    ,   [\"-S\"]                  = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]             = \"\"\n    ,   [\"-fsanitize=address\"]  = \"\"\n    })\nend\n\n-- get the property\nfunction get(self, name)\n    local values = self._INFO[name]\n    if name == \"ldflags\" or name == \"arflags\" or name == \"shflags\" then\n        -- switch architecture, @note does cache it in init() for generating vs201x project\n        values = table.join(values, \"-machine:\" .. (self:arch() or \"x86\"))\n    end\n    return values\nend\n\n-- make the strip flag\nfunction nf_strip(self, level, opt)\n\n    -- link.exe/arm64 does not support /opt:ref, /opt:icf\n    local target = opt.target\n    if target and target:is_arch(\"arm64\") then\n        return\n    end\n\n    -- @note we explicitly strip some useless code, because `/debug` may keep them\n    -- @see https://github.com/xmake-io/xmake/issues/907\n    if level == \"all\" then\n        -- we enable /ltcg for optimize/smallest:/Gl\n        local flags = {\"/opt:ref\", \"/opt:icf\"}\n        if target and target:get(\"optimize\") == \"smallest\" then\n            table.insert(flags, \"/ltcg\")\n        end\n        return flags\n    elseif level == \"debug\" then\n        return {\"/opt:ref\", \"/opt:icf\"}\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level, opt)\n\n    -- debug? generate *.pdb file\n    local flags = nil\n    local target = opt.target\n    if target then\n        if target:type() == \"target\" then\n            if level == \"debug\" and (target:is_binary() or target:is_shared()) then\n                flags = {\"-debug\", \"-pdb:\" .. target:symbolfile()}\n            end\n        else -- for option\n            if level == \"debug\" then\n                flags = \"-debug\"\n            end\n        end\n    end\n    return flags\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if not lib:endswith(\".lib\") and not lib:endswith(\".obj\") then\n        lib = lib .. \".lib\"\n    end\n    return lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the runtime flag\nfunction nf_runtime(self, runtime)\n    if runtime and runtime:startswith(\"MT\") then\n        return \"-nodefaultlib:msvcrt.lib\"\n    end\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-libpath:\" .. path.translate(dir)}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n    local argv = table.join(flags, \"-out:\" .. targetfile, objectfiles)\n    if not opt.rawargs then\n        argv = winos.cmdargv(argv)\n    end\n    -- @note we cannot put -lib/-dll to @args.txt\n    local implib = false\n    if targetkind == \"static\" then\n        table.insert(argv, 1, \"-lib\")\n    elseif targetkind == \"shared\" then\n        table.insert(argv, 1, \"-dll\")\n        implib = true\n    elseif targetkind == \"binary\" then\n        implib = true\n    end\n    if implib then\n        local implibfile = _get_implibfile(self, opt)\n        if implibfile then\n            table.insert(argv, \"/implib:\" .. implibfile)\n        end\n    end\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- ensure the target file directory exists\n    os.mkdir(path.directory(targetfile))\n    local implibfile = _get_implibfile(self, opt)\n    if implibfile then\n        os.mkdir(path.directory(implibfile))\n    end\n\n    try\n    {\n        function ()\n\n            local toolchain = self:toolchain()\n            local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n\n            if toolchain and toolchain:name() == \"masm32\" then\n                os.iorunv(program, argv, {envs = self:runenvs()})\n            else\n                -- use vstool to link and enable vs_unicode_output @see https://github.com/xmake-io/xmake/issues/528\n                vstool.runv(program, argv, {envs = self:runenvs()})\n            end\n        end,\n        catch\n        {\n            function (errors)\n\n                -- use link/stdout as errors first from vstool.iorunv()\n                if type(errors) == \"table\" then\n                    local errs = errors.stdout or \"\"\n                    if #errs:trim() == 0 then\n                        errs = errors.stderr or \"\"\n                    end\n                    errors = errs\n                end\n                os.raise(tostring(errors))\n            end\n        }\n    }\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/lld_link.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lld_link.lua\n--\n\n-- imports\ninherit(\"link\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/llvm_ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        llvm_ar.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\n\n-- init it\nfunction init(self)\n    self:set(\"arflags\", \"cr\")\nend\n\n-- make the strip flag\nfunction strip(self, level)\n    local maps = {\n        debug = \"S\"\n    ,   all   = \"S\"\n    }\n    return maps[level]\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    assert(targetkind == \"static\")\n    opt = opt or {}\n    local argv = table.join(flags, targetfile, objectfiles)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n    return self:program(), argv\nend\n\n-- link the library file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    assert(targetkind == \"static\", \"the target kind: %s is not support for ar\", targetkind)\n    os.mkdir(path.directory(targetfile))\n    -- @note remove the previous archived file first to force recreating a new file\n    os.tryrm(targetfile)\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/llvm_rc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        llvm_rc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.project.project\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"/D\", macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return {\"/U\", macro}\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"/I\", dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"/FO\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- compiling errors\n                os.raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ml/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.ml.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-?\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\")] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]:gsub(\"/\", \"-\")]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"ml_has_flags.asm\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, [[\nifndef X64\n.686p\n.model flat, C\nendif\n.code\nend]])\n    end\n\n    -- check it\n    local errors = nil\n    return try  {   function ()\n                        if opt.program:find(\"ml64\", 1, true) then\n                            table.insert(flags, \"-DX64\")\n                        end\n                        local _, errs = os.iorunv(opt.program, table.join(\"-c\", \"-nologo\", flags, \"-Fo\" .. os.nuldev(), sourcefile), {envs = opt.envs})\n                        if errs and #errs:trim() > 0 then\n                            return false, errs\n                        end\n                        return true\n                    end,\n                    catch { function (errs) errors = errs end }\n                }, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ml.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ml.lua\n--\n\n-- imports\nimport(\"private.tools.vstool\")\nimport(\"core.base.hashset\")\n\n-- init it\n--\n-- @see https://docs.microsoft.com/en-us/cpp/assembler/masm/ml-and-ml64-command-line-reference\n--\nfunction init(self)\n\n    -- init asflags\n    self:set(\"asflags\", \"-nologo\")\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- symbols\n        [\"-g\"]                      = \"-Z7\"\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-W1\"]                     = \"-W1\"\n    ,   [\"-W2\"]                     = \"-W2\"\n    ,   [\"-W3\"]                     = \"-W3\"\n    ,   [\"-Wall\"]                   = \"-W3\" -- /W level \tSets the warning level, where level = 0, 1, 2, or 3.\n    ,   [\"-Wextra\"]                 = \"-W3\"\n    ,   [\"-Weverything\"]            = \"-W3\"\n    ,   [\"-Werror\"]                 = \"-WX\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the symbol flags\nfunction nf_symbols(self, levels)\n    local flags = nil\n    local values = hashset.from(levels)\n    if values:has(\"debug\") then\n        flags = {}\n        if values:has(\"edit\") then\n            table.insert(flags, \"-ZI\")\n        elseif values:has(\"embed\") then\n            table.insert(flags, \"-Z7\")\n        else\n            table.insert(flags, \"-Zi\")\n        end\n    end\n    return flags\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps =\n    {\n        none         = \"-w\"\n    ,   less         = \"-W1\"\n    ,   more         = \"-W3\"\n    ,   all          = \"-W3\"\n    ,   everything   = \"-W3\"\n    ,   error        = \"-WX\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    -- we need to set the default -Gd option for the x86 architecture,\n    -- if the other calling convention flags are not set\n    --\n    -- we can't directly remove -Gd. This is not only for backward compatibility,\n    -- but also to simplify mixed compilation with c programs.\n    --\n    -- although this may affect some performance,\n    -- it only takes effect under x86 asm, so there will be no major performance issues.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/1779\n    --\n    if not self:program():find(\"64\", 1, true) and\n        not table.contains(flags, \"-Gc\", \"/Gc\", \"-GZ\", \"/GZ\") then\n        table.insert(flags, \"-Gd\")\n    end\n    return self:program(), table.join(\"-c\", flags, \"-Fo\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    try\n    {\n        function ()\n            -- @note we don't need to use vstool.runv to enable unicode output for ml.exe\n            local program, argv = compargv(self, sourcefile, objectfile, flags)\n            os.runv(program, argv, {envs = self:runenvs()})\n        end,\n        catch\n        {\n            function (errors)\n\n                -- use link/stdout as errors first from vstool.iorunv()\n                if type(errors) == \"table\" then\n                    local errs = errors.stdout or \"\"\n                    if #errs:trim() == 0 then\n                        errs = errors.stderr or \"\"\n                    end\n                    errors = errs\n                end\n                raise(tostring(errors))\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ml64/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.ml.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/ml64.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ml64.lua\n--\n\n-- inherit ml\ninherit(\"ml\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/mold.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mold.lua\n--\n\n-- imports\ninherit(\"ld\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nasm.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- symbols\n        [\"-g\"]                      = \"\"\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-Wall\"]                   = \"\" -- = \"-Wall\" will enable too more warnings\n    ,   [\"-W1\"]                     = \"\"\n    ,   [\"-W2\"]                     = \"\"\n    ,   [\"-W3\"]                     = \"\"\n    ,   [\"-Werror\"]                 = \"\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = {\n            debug  = \"-g\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none  = \"-w\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\", dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    local outdata, errdata = try\n    {\n        function ()\n            return os.iorunv(compargv(self, sourcefile, objectfile, flags))\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- raise compiling errors\n                raise(tostring(errors))\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n\n                -- show warnings?\n                if ok and errdata and policy.build_warnings(opt) then\n                    errdata = errdata:trim()\n                    if #errdata > 0 then\n                        progress.show_output(\"${color.warning}%s\", errdata)\n                    end\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nim/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.nim.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"nim_has_flags.nim\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"echo \\\"hello\\\"\")\n    end\n\n    -- check it\n    local cachedir = os.tmpfile() .. \".dir\"\n    local ok, errors = _try_running(opt.program, table.join(\"c\", \"-c\", flags, \"--nimcache:\" .. cachedir, sourcefile))\n    os.tryrm(cachedir)\n    return ok, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nim.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nim.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\n--\n-- @see https://nim-lang.org/docs/nimc.html\nfunction init(self)\n\n    -- init arflags\n    self:set(\"ncarflags\", \"--app:staticlib\", \"--noMain\")\n\n    -- init shflags\n    self:set(\"ncshflags\", \"--app:lib\", \"--noMain\")\n\n    -- init arch flags\n    local arch = self:arch()\n    if arch then\n        if self:is_arch(\"x86\", \"i386\") then\n            self:add(\"ncflags\", \"--cpu:i386\", \"--define:bit32\")\n            if self:is_plat(\"linux\", \"macosx\", \"bsd\", \"mingw\") then\n                self:add(\"ncflags\", '--passC:\"-m32\"', '--passL:\"-m32\"')\n            end\n        elseif self:is_arch(\"x64\", \"x86_64\") then\n            self:add(\"ncflags\", \"--cpu:amd64\", \"--define:bit64\")\n        elseif self:is_arch(\"arm64.*\") then\n            self:add(\"ncflags\", \"--cpu:arm64\", \"--define:bit64\")\n        elseif self:is_arch(\"arm.*\") then\n            self:add(\"ncflags\", \"--cpu:arm\", \"--define:bit32\")\n        end\n    end\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps =\n    {\n        none       = \"--warning:X:off\"\n    ,   less       = \"--warning:X:on\"\n    ,   more       = \"--warning:X:on\"\n    ,   all        = \"--warning:X:on\"\n    ,   allextra   = \"--warning:X:on\"\n    ,   everything = \"--warning:X:on\"\n    ,   error      = \"--warningAsError:X:on\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"--define:\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"--undef:\" .. macro\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none        = \"--opt:none\"\n        ,   fast        = \"-d:release\"\n        ,   faster      = \"-d:release\"\n        ,   fastest     = \"-d:release\"\n        ,   smallest    = {\"-d:release\", \"--opt:size\"}\n        ,   aggressive  = \"-d:danger\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps =\n    {\n        debug = \"--debugger:native\"\n    }\n    return maps[level]\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    if self:is_plat(\"linux\", \"macosx\", \"bsd\") then\n        if level == \"debug\" or level == \"all\" then\n            return '--passL:\"-s\"'\n        end\n    end\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {string.format('--passC:\"-I%s\"', path.translate(dir))}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if self:is_plat(\"windows\") then\n        return string.format('--passL:\"%s.lib\"', lib)\n    else\n        return string.format('--passL:\"-l%s\"', lib)\n    end\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    if self:is_plat(\"windows\") then\n        return string.format('--passL:\"%s.lib\"', lib)\n    else\n        if lib == \"pthread\" then\n            return {\"--threads:on\", string.format('--passL:\"-l%s\"', lib), '--dynlibOverride:\"pthread\"'}\n        else\n            return string.format('--passL:\"-l%s\"', lib)\n        end\n    end\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    if self:is_plat(\"windows\") then\n        return {string.format('--passL:\"-libpath:%s\"', path.translate(dir))}\n    else\n        return {string.format('--passL:\"-L%s\"', path.translate(dir))}\n    end\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir, opt)\n    if self:is_plat(\"windows\") then\n        return\n    end\n    opt = opt or {}\n    local extra = opt.extra\n    if extra and extra.installonly then\n        return\n    end\n    dir = path.translate(dir)\n\n    -- Use --passL:\"-Wl,-rpath=<dir>\" to pass rpath to the linker\n    -- We use standard -Wl,-rpath for gcc/clang on linux/macosx/bsd without check mainly.\n    if self:is_plat(\"macosx\", \"iphoneos\") then\n         dir = dir:gsub(\"([@$][%w_]+)\", function (name)\n            if name == \"$ORIGIN\" then\n                return \"@loader_path\"\n            end\n            return name\n         end)\n        local rpath = string.format(\"-Wl,-rpath,%s\", dir)\n        return {string.format('--passL:\"%s\"', rpath)}\n    elseif self:is_plat(\"linux\", \"bsd\", \"android\") then\n         dir = dir:gsub(\"([@$][%w_]+)\", function (name)\n            if name == \"@loader_path\" or name == \"@executable_path\" then\n                return \"\\\\$ORIGIN\"\n            elseif name == \"$ORIGIN\" then\n                return \"\\\\$ORIGIN\"\n            end\n            return name\n         end)\n        local rpath = string.format(\"-Wl,-rpath=%s\", dir)\n        local flags = {string.format('--passL:\"%s\"', rpath)}\n        if extra then\n            if extra.runpath == false and self:has_flags(string.format('--passL:\"%s,--disable-new-dtags\"', rpath), \"ldflags\") then\n                flags[1] = string.format('--passL:\"%s,--disable-new-dtags\"', rpath)\n            elseif extra.runpath == true and self:has_flags(string.format('--passL:\"%s,--enable-new-dtags\"', rpath), \"ldflags\") then\n                flags[1] = string.format('--passL:\"%s,--enable-new-dtags\"', rpath)\n            end\n        end\n        return flags\n    end\n\n    -- fallback\n    if self:has_flags(string.format('--passL:\"-Wl,-rpath=%s\"', dir), \"ldflags\") then\n        local flags = {string.format('--passL:\"-Wl,-rpath=%s\"', (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = { [\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\" }\n            return maps[name]\n        end)))}\n        -- add_rpathdirs(\"...\", {runpath = false})\n        if extra then\n            if extra.runpath == false and self:has_flags(string.format('--passL:\"-Wl,-rpath=%s,--disable-new-dtags\"', dir), \"ldflags\") then\n                flags[1] = string.format('--passL:\"-Wl,-rpath=%s,--disable-new-dtags\"', dir)\n            elseif extra.runpath == true and self:has_flags(string.format('--passL:\"-Wl,-rpath=%s,--enable-new-dtags\"', dir), \"ldflags\") then\n                flags[1] = string.format('--passL:\"-Wl,-rpath=%s,--enable-new-dtags\"', dir)\n            end\n        end\n        return flags\n    elseif self:has_flags('--passL:\"-Xlinker\" --passL:\"-rpath\" --passL:\"-Xlinker\" ' .. string.format('--passL:\"%s\"', dir), \"ldflags\") then\n        return {'--passL:\"-Xlinker\"', '--passL:\"-rpath\"', '--passL:\"-Xlinker\"', string.format('--passL:\"%s\"', (dir:gsub(\"%$ORIGIN\", \"@loader_path\")))}\n    end\nend\n\n-- make the build arguments list\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    local flags_extra = {}\n    if targetkind ~= \"static\" and self:is_plat(\"windows\") then\n        -- fix link flags for windows\n        -- @see https://github.com/nim-lang/Nim/issues/19033\n        local flags_new = {}\n        local flags_link = {}\n        for _, flag in ipairs(flags) do\n            if flag:find(\"passL:\", 1, true) then\n                table.insert(flags_link, flag)\n            else\n                table.insert(flags_new, flag)\n            end\n        end\n        if #flags_link > 0 then\n            table.insert(flags_new, \"--passL:-link\")\n            table.join2(flags_new, flags_link)\n        end\n        flags = flags_new\n    end\n    if targetkind == \"static\" then\n        local targetname = path.basename(targetkind)\n        table.insert(flags_extra, \"--nimMainPrefix:lib\" .. targetname)\n    end\n    return self:program(), table.join(\"c\", flags, flags_extra, \"-o:\" .. targetfile, sourcefiles)\nend\n\n-- build the target file\nfunction build(self, sourcefiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    os.runv(program, argv, {envs = self:runenvs()})\nend\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvc/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nvc.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvcc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\" or \"-Xlinker <arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") or flags_str:startswith(\"-Xlinker \") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"-ld\") or toolkind:endswith(\"-sh\")\nend\n\n-- try running\nfunction _try_running(program, argv, opt)\n    local errors = nil\n    return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- check for the builtin flags\n    local builtin_flags = {[\"-code\"] = true,\n                           [\"--gpu-code\"] = true,\n                           [\"-gencode\"] = true,\n                           [\"--generate-code\"] = true,\n                           [\"-arch\"] = true,\n                           [\"--gpu-architecture\"] = true,\n                           [\"-cudart=none\"] = true,\n                           [\"--cudart=none\"] = true}\n    if builtin_flags[flags[1]] then\n        return true\n    end\n\n    -- check for the builtin flag=value\n    local cudart_flags = {none = true, shared = true, static = true}\n    local builtin_flags_pair = {[\"-cudart\"] = cudart_flags,\n                                [\"--cudart\"] = cudart_flags}\n    if #flags > 1 and builtin_flags_pair[flags[1]] and builtin_flags_pair[flags[1]][flags[2]] then\n        return true\n    end\n\n    -- check from the `--help` menu, only for linker\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.nvcc.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local snippet = opt.snippet or \"int main(int argc, char** argv)\\n{return 0;}\\n\"\n    local sourcefile = os.tmpfile(\"nvcc_has_flags:\" .. snippet) .. \".cu\"\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, snippet)\n    end\n\n    local args = table.join(\"-o\", os.nuldev(), sourcefile)\n    if not islinker then\n        table.insert(args, 1, \"-c\")\n    end\n\n    -- avoid recursion\n    if flags[1] ~= \"-allow-unsupported-compiler\" then\n        -- add -allow-unsupported-compiler if supported to suppress error of unsupported compiler,\n        -- which caused all checks failed.\n        local allow_unsupported_compiler = _has_flags({\"-allow-unsupported-compiler\"}, opt)\n        if allow_unsupported_compiler then\n            table.insert(args, 1, \"-allow-unsupported-compiler\")\n        end\n    end\n\n    -- add architecture flags if cross compiling\n    if not is_arch(os.arch()) then\n        if is_arch(\".+64.*\") then\n            table.insert(args, 1, \"-m64\")\n        else\n            table.insert(args, 1, \"-m32\")\n        end\n    end\n\n    -- check flags\n    return _try_running(opt.program, table.join(flags, args), opt)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"cu\"}\n--\n-- @return      true or false\n--\nfunction _has_flags(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\nfunction main(...)\n    return _has_flags(...)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nvcc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.language.language\")\nimport(\"core.project.policy\")\nimport(\"utils.progress\")\n\n-- get implib file\nfunction _get_implibfile(self, targetkind, targetfile, opt)\n    if targetkind == \"shared\" and self:is_plat(\"mingw\") then\n        local target = opt and opt.target\n        local implibfile\n        if target and target:type() == \"target\" then\n            implibfile = target:artifactfile(\"implib\")\n        end\n        if not implibfile then\n            implibfile = path.join(path.directory(targetfile), path.basename(targetfile) .. \".a\")\n        end\n        return implibfile\n    end\nend\n\n-- init it\nfunction init(self)\n\n    -- init cuflags\n    if not self:is_plat(\"windows\", \"mingw\") then\n        self:set(\"shared.cuflags\", \"-Xcompiler -fPIC\")\n        self:set(\"binary.cuflags\", \"-Xcompiler -fPIE\")\n    end\n\n    -- init flags map\n    self:set(\"mapflags\", {\n        -- warnings\n        [\"-W4\"]            = \"-Wreorder --Wno-deprecated-gpu-targets --Wno-deprecated-declarations\"\n    ,   [\"-Wextra\"]        = \"-Wreorder --Wno-deprecated-gpu-targets --Wno-deprecated-declarations\"\n    ,   [\"-Weverything\"]   = \"-Wreorder --Wno-deprecated-gpu-targets --Wno-deprecated-declarations\"\n    })\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level, opt)\n\n    -- debug? generate *.pdb file\n    local flags = nil\n    if level == \"debug\" then\n        -- #5777: '--device-debug (-G)' overrides '--generate-line-info (-lineinfo)' in nvcc\n        -- remove '-G' and '-lineinfo' and add them in mode.debug and mode.profile respectively\n        flags = {\"-g\"}\n        if self:is_plat(\"windows\") then\n            local host_flags = nil\n            local symbolfile = nil\n            local target = opt.target\n            if target and target.symbolfile then\n                symbolfile = target:symbolfile()\n            end\n            if symbolfile then\n\n                -- ensure the object directory\n                local symboldir = path.directory(symbolfile)\n                if not os.isdir(symboldir) then\n                    os.mkdir(symboldir)\n                end\n\n                -- check and add symbol output file\n                host_flags = \"-Zi -Fd\" .. path.join(symboldir, \"compile.\" .. path.filename(symbolfile))\n                if self:has_flags({'-Xcompiler \"-Zi -FS -Fd' .. os.nuldev() .. '.pdb\"'}, \"cuflags\", { flagskey = '-Xcompiler \"-Zi -FS -Fd\"' }) then\n                    host_flags = \"-FS \" .. host_flags\n                end\n            else\n                host_flags = \"-Zi\"\n            end\n            table.insert(flags, \"-Xcompiler\")\n            table.insert(flags, host_flags)\n        end\n    end\n    return flags\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n\n    -- the maps\n    local maps =\n    {\n        none       = \"-w\"\n    ,   everything = { \"-Wreorder\", \"--Wno-deprecated-gpu-targets\", \"--Wno-deprecated-declarations\" }\n    ,   error      = { \"-Werror\", \"cross-execution-space-call,reorder,deprecated-declarations\" }\n    }\n\n    -- for cl.exe on windows\n    local cl_maps =\n    {\n        none       = \"-W0\"\n    ,   less       = \"-W1\"\n    ,   more       = \"-W3\"\n    ,   all        = \"-W3\" -- = \"-Wall\" will enable too more warnings\n    ,   allextra   = \"-W4\"\n    ,   everything = \"-Wall\"\n    ,   error      = \"-WX\"\n    }\n\n    -- for gcc & clang on linux, may be work for other gnu compatible compilers such as icc\n    --\n    -- gcc dosen't support `-Weverything`, use `-Wall -Wextra -Weffc++` for it\n    -- no warning will emit for unsupoorted `-W` flags by clang/gcc\n    --\n    local gcc_clang_maps =\n    {\n        none       = \"-w\"\n    ,   less       = \"-Wall\"\n    ,   more       = \"-Wall\"\n    ,   all        = \"-Wall\"\n    ,   allextra   = \"-Wall -Wextra\"\n    ,   everything = \"-Weverything -Wall -Wextra -Weffc++\"\n    ,   error      = \"-Werror\"\n    }\n\n    -- get warning for nvcc\n    local warning = maps[level]\n\n    -- add host warning\n    --\n    -- for cl.exe on windows, it is the only supported host compiler on the platform\n    -- for gcc/clang, or any gnu compatible compiler on *nix\n    --\n    local host_warning = nil\n    if self:is_plat(\"windows\") then\n        host_warning = cl_maps[level]\n    else\n        host_warning = gcc_clang_maps[level]\n    end\n    if host_warning then\n        warning = table.wrap(warning)\n        table.insert(warning, '-Xcompiler')\n        table.insert(warning, host_warning)\n    end\n    return warning\n\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none       = \"-O0\"\n        ,   fast       = \"-O1\"\n        ,   faster     = \"-O2\"\n        ,   fastest    = \"-O3\"\n        ,   smallest   = \"-Os\"\n        ,   aggressive = \"-Ofast\"\n        }\n        return maps[level]\n    end\nend\n\n-- make vs runtime flag\nfunction nf_runtime(self, runtime)\n    if self:is_plat(\"windows\") and runtime then\n        local maps = {\n            MT = '-Xcompiler \"-MT\"',\n            MD = '-Xcompiler \"-MD\"',\n            MTd = '-Xcompiler \"-MTd\"',\n            MDd = '-Xcompiler \"-MDd\"'\n        }\n        return maps[runtime]\n    end\nend\n\n-- make the language flag\nfunction nf_language(self, stdname)\n\n    -- the stdc++ maps\n    if _g.cxxmaps == nil then\n        _g.cxxmaps =\n        {\n            cxx03       = \"--std c++03\"\n        ,   cxx11       = \"--std c++11\"\n        ,   cxx14       = \"--std c++14\"\n        ,   cxx17       = \"--std c++17\"\n        ,   cxx20       = \"--std c++20\"\n        ,   cxxlatest   = {\"--std c++20\", \"--std c++17\", \"--std c++14\", \"--std c++11\", \"--std c++03\"}\n        }\n        local cxxmaps2 = {}\n        for k, v in pairs(_g.cxxmaps) do\n            cxxmaps2[k:gsub(\"xx\", \"++\")] = v\n        end\n        table.join2(_g.cxxmaps, cxxmaps2)\n    end\n    local maps = _g.cxxmaps\n    local result = maps[stdname]\n    if type(result) == \"table\" then\n        for _, v in ipairs(result) do\n            if self:has_flags(v, \"cxflags\") then\n                result = v\n                maps[stdname] = result\n                break\n            end\n        end\n    end\n    return result\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. path.translate(dir)}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    if lib:endswith(\".a\") or lib:endswith(\".so\") or lib:endswith(\".dylib\") or lib:endswith(\".lib\") then\n        return lib\n    else\n        return \"-l\" .. lib\n    end\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. path.translate(dir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\n    if self:has_flags(\"-Wl,-rpath=\" .. dir, \"ldflags\") then\n        return {\"-Wl,-rpath=\" .. (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n            return maps[name]\n        end))}\n    elseif self:has_flags(\"-Xlinker -rpath -Xlinker \" .. dir, \"ldflags\") then\n        return {\"-Xlinker\", \"-rpath\", \"-Xlinker\", (dir:gsub(\"%$ORIGIN\", \"@loader_path\"))}\n    end\nend\n\n-- make the c precompiled header flag\nfunction nf_pcheader(self, pcheaderfile)\n    return {\"-include\", pcheaderfile}\nend\n\n-- make the c++ precompiled header flag\nfunction nf_pcxxheader(self, pcheaderfile)\n    return {\"-include\", pcheaderfile}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    -- add rpath for dylib (macho), e.g. -install_name @rpath/file.dylib\n    local flags_extra = {}\n    if targetkind == \"shared\" and targetfile:endswith(\".dylib\") then\n        table.insert(flags_extra, \"-Xlinker\")\n        table.insert(flags_extra, \"-install_name\")\n        table.insert(flags_extra, \"-Xlinker\")\n        table.insert(flags_extra, \"@rpath/\" .. path.filename(targetfile))\n    end\n\n    -- add `-Wl,--out-implib,outputdir/libxxx.a` for xxx.dll on mingw/gcc\n    local implibfile = _get_implibfile(self, targetkind, targetfile, opt)\n    if implibfile then\n        table.insert(flags_extra, \"-Xlinker\")\n        table.insert(flags_extra, \"-Wl,--out-implib,\" .. implibfile)\n    end\n\n    -- make link args\n    return self:program(), table.join(\"-o\", targetfile, objectfiles, flags, flags_extra)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags, opt)\n    opt = opt or {}\n\n    os.mkdir(path.directory(targetfile))\n    local implibfile = _get_implibfile(self, targetkind, targetfile, opt)\n    if implibfile then\n        os.mkdir(path.directory(implibfile))\n    end\n\n    local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n    os.runv(program, argv, {envs = self:runenvs()})\nend\n\n-- show warnings\nfunction _show_warnings(self, output)\n    local lines = output:split('\\n', {plain = true})\n    if #lines > 0 then\n        if not option.get(\"diagnosis\") then\n            lines = table.slice(lines, 1, (#lines > 16 and 16 or #lines))\n        end\n        local warnings = table.concat(lines, \"\\n\")\n        progress.show_output(\"${color.warning}%s\", warnings)\n    end\nend\n\n-- support `-MD -MF depfile.d`?\nfunction _has_flags_md_mf(self)\n    local has_md_mf = _g._HAS_MD_MF\n    if has_md_mf == nil then\n       has_md_mf = self:has_flags({\"-MD\", \"-MF\", os.nuldev()}, \"cuflags\", { flagskey = \"-MD -MF\" }) or false\n        _g._HAS_MD_MF = has_md_mf\n    end\n    return has_md_mf\nend\n\n-- support `-MMD -MF depfile.d`? some old gcc does not support it at same time\nfunction _has_flags_mmd_mf(self)\n    local has_mmd_mf = _g._HAS_MMD_MF\n    if has_mmd_mf == nil and not is_host(\"windows\") then\n       has_mmd_mf = self:has_flags({\"-MMD\", \"-MF\", os.nuldev()}, \"cuflags\", { flagskey = \"-MMD -MF\" }) or false\n        _g._HAS_MMD_MF = has_mmd_mf\n    end\n    return has_mmd_mf\nend\n\n-- support `-M -o depfile.d`?\nfunction _has_flags_m(self)\n    local has_m = _g._HAS_M\n    if not has_md_mf and has_m == nil then\n        has_m = self:has_flags(\"-M\", \"cuflags\", { flagskey = \"-M\" }) or false\n        _g._HAS_M = has_m\n    end\n    return has_m\nend\n\n-- support `-MM -o depfile.d`?\nfunction _has_flags_mm(self)\n    local has_mm = _g._HAS_MM\n    if not has_mmd_mf and has_mm == nil and not is_host(\"windows\") then\n        has_mm = self:has_flags(\"-MM\", \"cuflags\", { flagskey = \"-MM\" }) or false\n        _g._HAS_MM = has_mm\n    end\n    return has_mm\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if depfile then\n                if _has_flags_mmd_mf(self) then\n                    compflags = table.join(compflags, \"-MMD\", \"-MF\", depfile)\n                elseif _has_flags_mm(self) then\n                    -- since -MMD is not supported, run nvcc twice\n                    local program, argv = compargv(self, sourcefile, depfile, table.join(flags, \"-MM\"))\n                    os.runv(program, argv, {envs = self:runenvs()})\n                elseif _has_flags_md_mf(self) then\n                    -- on windows only -MD and -M are supported\n                    compflags = table.join(compflags, \"-MD\", \"-MF\", depfile)\n                elseif _has_flags_m(self) then\n                    -- since -MD is not supported, run nvcc twice\n                    local program, argv = compargv(self, sourcefile, depfile, table.join(flags, \"-M\"))\n                    os.runv(program, argv, {envs = self:runenvs()})\n                end\n            end\n\n            -- do compile\n            local program, argv = compargv(self, sourcefile, objectfile, compflags)\n            local outdata, errdata = os.iorunv(program, argv, {envs = self:runenvs()})\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- use nvcc/stdout as errors first from os.iorunv()\n                if type(errors) == \"table\" then\n                    errors = (errors.stdout or \"\") .. (errors.stderr or \"\")\n                else\n                    errors = tostring(errors)\n                end\n\n                -- find the start line of error\n                local lines = errors:split(\"\\n\", {plain = true})\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:match(\"[eE]rror:\", 1, true) or line:find(\"错误：\", 1, true) or line:match(\"ptxas fatal%s*:\") or line:match(\"error %a+[0-9]+%s*:\") then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n                if not option.get(\"verbose\") then\n                    errors = errors .. \"\\n  ${yellow}> in ${bright}\" .. sourcefile\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                -- show warnings?\n                if ok and policy.build_warnings(opt) then\n                    local output = (outdata or \"\") .. (errdata or \"\")\n                    if #output > 0 then\n                        _show_warnings(self, output)\n                    end\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        -- nvcc uses gcc-style depfiles\n                        dependinfo.depfiles_format = \"gcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvcxx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvcxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvcxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nvcxx.lua\n--\n\n-- inherit gcc\ninherit(\"gcc\")\n\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvfortran/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gfortran.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/nvfortran.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nvfortran.lua\n--\n\ninherit(\"gfortran\")\nimport(\"core.language.language\")\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = _g.symbol_maps\n        if not maps then\n            maps = {\n                debug  = \"-g\"\n            }\n            _g.symbol_maps = maps\n        end\n        return maps[level .. '_' .. kind] or maps[level]\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/rc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.rc.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"-?\"}, {envs = opt.envs})\n        if arglist then\n            for arg in arglist:gmatch(\"(/[%-%a%d]+)%s+\") do\n                allflags[arg:gsub(\"/\", \"-\")] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]:gsub(\"/\", \"-\")]\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n    return _check_from_arglist(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/rc/parse_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        parse_deps.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        return deps\n    end\nend\n\n-- parse depsfiles from string\nfunction main(depsdata)\n    local results = hashset.new()\n    local projectdir = os.projectdir()\n    for _, includefile in ipairs(depsdata:split('\\n', {plain = true})) do\n        if #includefile > 0 then\n            includefile = _normailize_dep(includefile, projectdir)\n            if includefile then\n                results:insert(includefile)\n            end\n        end\n    end\n    return results:to_array()\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/rc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.project\")\nimport(\"core.project.policy\")\nimport(\"private.tools.vstool\")\nimport(\"utils.progress\")\n\n-- normailize path of a dependecy\nfunction _normailize_dep(dep, projectdir)\n    if path.is_absolute(dep) then\n        dep = path.translate(dep)\n    else\n        dep = path.absolute(dep, projectdir)\n    end\n    if dep:startswith(projectdir) then\n        return path.relative(dep, projectdir)\n    else\n        return deps\n    end\nend\n\n-- parse include file\nfunction _parse_includefile(line)\n    if line:startswith(\"#line\") then\n        return line:match(\"#line %d+ \\\"(.+)\\\"\")\n    elseif line:find(\"ICON\", 1, true) and line:find(\".ico\", 1, true) then\n        -- 101 ICON \"xxx.ico\"\n        return line:match(\"ICON%s+\\\"(.+.ico)\\\"\")\n    elseif line:find(\"BITMAP\", 1, true) and line:find(\".bmp\", 1, true) then\n        return line:match(\"BITMAP%s+\\\"(.+.bmp)\\\"\")\n    end\nend\n\n-- init it\nfunction init(self)\n    if self:has_flags(\"-nologo\", \"mrcflags\") then\n        -- fix vs2008 on xp, e.g. fatal error RC1106: invalid option: -ologo\n        self:set(\"mrcflags\", \"-nologo\")\n    end\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags, opt)\n    return self:program(), table.join(flags, \"-Fo\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(objectfile))\n\n    try\n    {\n        function ()\n            -- @note we don't need to use vstool.iorunv to enable unicode output for rc.exe\n            local program, argv = compargv(self, sourcefile, objectfile, flags, opt)\n            local outdata, errdata = os.iorunv(program, argv, {envs = self:runenvs()})\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n                -- use stdout as errors first from vstool.iorunv()\n                if type(errors) == \"table\" then\n                    local errs = errors.stdout or \"\"\n                    if #errs:trim() == 0 then\n                        errs = errors.stderr or \"\"\n                    end\n                    errors = errs\n                end\n                os.raise(tostring(errors))\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\n\n    -- try to use cl.exe to parse includes, but cl.exe maybe not exists in masm32 sdk\n    -- @see https://github.com/xmake-io/xmake/issues/2562\n    local cl\n    if opt.target then\n        cl = opt.target:tool(\"cxx\")\n    elseif self:toolchain() then\n        cl = self:toolchain():tool(\"cxx\")\n    end\n    if cl then\n        local outfile = os.tmpfile() .. \".rc.out\"\n        local errfile = os.tmpfile() .. \".rc.err\"\n        local includeflags = {}\n        for _, flag in ipairs(flags) do\n            if flag:match(\"^[-/]I\") then\n                table.insert(includeflags, flag)\n            end\n        end\n        local ok = try {function () os.execv(cl, table.join(\"-E\", includeflags, sourcefile), {stdout = outfile, stderr = errfile, envs = self:runenvs()}); return true end}\n        if ok and os.isfile(outfile) then\n            local depfiles_rc\n            local includeset = hashset.new()\n            local file = io.open(outfile)\n            local projectdir = os.projectdir()\n            for line in file:lines() do\n                local includefile = _parse_includefile(line)\n                if includefile then\n                    includefile = _normailize_dep(includefile, projectdir)\n                    if includefile and not includeset:has(includefile)\n                        and path.absolute(includefile) ~= path.absolute(sourcefile)\n                        and os.isfile(includefile) then\n                        depfiles_rc = (depfiles_rc or \"\") .. \"\\n\" .. includefile\n                        includeset:insert(includefile)\n                    end\n                end\n            end\n            file:close()\n            if dependinfo then\n                dependinfo.depfiles_format = \"rc\"\n                dependinfo.depfiles = depfiles_rc\n            end\n        end\n        os.tryrm(outfile)\n        os.tryrm(errfile)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/rustc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-C linkarg=\") then\n        return true\n    end\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.rustc.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"rustc_has_flags.rs\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"fn main() {\\n}\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(\"--crate-type=bin\", flags, \"-o\", os.tmpfile(), sourcefile), opt)\n    end\n\n    -- check flags for compiler\n    local objectfile = os.tmpfile() .. \".o\"\n    local ok, errors = _try_running(opt.program, table.join(\"--emit\", \"obj\", flags, \"-o\", objectfile, sourcefile))\n    os.tryrm(objectfile)\n    return ok, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/rustc/target_triple.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      SirLynix\n-- @file        target_triple.lua\n--\n\n-- get arch part\nfunction _translate_arch(arch, opt)\n    local maps =\n    {\n        [\"aarch64\"]     = \"aarch64\"\n    ,   [\"arm\"]         = \"arm\"\n    ,   [\"armv5te\"]     = \"arm\"\n    ,   [\"armeabi\"]     = \"arm\"\n    ,   [\"armeabi-v7a\"] = \"armv7\"\n    ,   [\"armv7-a\"]     = \"armv7\"\n    ,   [\"arm64\"]       = \"aarch64\"\n    ,   [\"arm64-v8a\"]   = \"aarch64\"\n    ,   [\"i386\"]        = \"i686\"\n    ,   [\"i686\"]        = \"i686\"\n    ,   [\"x86\"]         = \"i686\"\n    ,   [\"x86_64\"]      = \"x86_64\"\n    ,   [\"x64\"]         = \"x86_64\"\n    ,   [\"wasm32\"]      = \"wasm32\"\n    ,   [\"wasm64\"]      = \"wasm64\"\n    }\n    return maps[arch] or arch\nend\n\n-- get platform part\nfunction _translate_plat(plat, arch, opt)\n    if plat == \"windows\" then\n        return \"-pc-windows-msvc\"\n    elseif plat == \"mingw\" or plat == \"msys\" then\n        return \"-pc-windows-gnu\"\n    elseif plat == \"linux\" then\n        return \"-unknown-linux-gnu\"\n    elseif plat == \"macosx\" then\n        return \"-apple-darwin\"\n    elseif plat == \"android\" then\n        if arch == \"armeabi-v7a\" or arch == \"armeabi\" or arch == \"armv7-a\" or arch == \"armv5te\" then\n            return \"-linux-androideabi\"\n        else\n            return \"-linux-android\"\n        end\n    elseif plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n        local suffix = opt and opt.apple_sim and \"-sim\" or \"\"\n        if plat == \"iphoneos\" then\n            return \"-apple-ios\" .. suffix\n        elseif plat == \"appletvos\" then\n            return \"-apple-tvos\" .. suffix\n        elseif plat == \"watchos\" then\n            return \"-apple-watchos\" .. suffix\n        end\n    elseif plat == \"bsd\" then\n        return \"-unknown-freebsd\"\n    elseif plat == \"wasm\" then\n        return \"-unknown-unknown\"\n    end\nend\n\n-- gets the rustc compatible target triple (e.g. x86_64-pc-windows-msvc) for a set plat/arch\n--\n-- @param plat      the target plat, e.g. windows, android, macosx, ...\n-- @param arch      the target name, e.g. arm64, x86_64, wasm64, ...\n-- @param opt       the options, e.g. {apple_sim = true)\n--\n-- @return          a valid rustc triple if plat and arch are recognized, nil otherwise\nfunction main(plat, arch, opt)\n\n    -- is triple? return it directly\n    -- @see https://github.com/xmake-io/xmake/issues/6574\n    if arch:match(\"%w+%-%w+%-%w+\") then\n        return arch\n    end\n\n    local target_arch = _translate_arch(arch, opt)\n    if not target_arch then\n        return\n    end\n\n    local target_plat = _translate_plat(plat, arch, opt)\n    if not target_plat then\n        return\n    end\n\n    return target_arch .. target_plat\nend\n"
  },
  {
    "path": "xmake/modules/core/tools/rustc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rustc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none        = \"-C opt-level=0\"\n        ,   fast        = \"-C opt-level=1\"\n        ,   faster      = \"-C opt-level=2\"\n        ,   fastest     = \"-C opt-level=3\"\n        ,   smallest    = \"-C opt-level=s\"\n        ,   aggressive  = \"-C opt-level=z\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps =\n    {\n        debug = \"-C debuginfo=2\"\n    }\n    return maps[level]\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. dir}\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the frameworkdir flag, crate module dependency directories\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-L\", \"dependency=\" .. frameworkdir}\nend\n\n-- make the framework flag, crate module\nfunction nf_framework(self, framework)\n    local basename = path.basename(framework)\n    -- return \"mycrate\" from libmycrate-f882feaebb8ba0ca.rlib or libmycrate.rlib\n    local cratename = basename:match(\"lib(.-)%-.-\") or basename:match(\"lib(.+)\")\n    if not cratename and framework:endswith(\".dll\") then\n        -- @see https://github.com/xmake-io/xmake/issues/5156#issuecomment-2143978086\n        -- mycrate-f882feaebb8ba0ca.dll or mycrate.dll\n        cratename = basename:split(\"-\", {plain = true})[1]\n    end\n    if cratename then\n        return {\"--extern\", cratename .. \"=\" .. framework}\n    end\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\n    dir = path.translate(dir)\n    if self:has_flags({\"-C\", \"link-arg=-Wl,-rpath=$ORIGIN\"}, \"ldflags\") then\n        return {\"-C\", \"link-arg=-Wl,-rpath=\" .. (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n            return maps[name]\n        end))}\n    elseif self:has_flags({\"-C\", \"link-arg=-Xlinker\", \"-C\", \"link-arg=-rpath\", \"-C\", \"link-arg=-Xlinker\", \"-C\", \"link-arg=@loader_path\"}, \"ldflags\") then\n        return {\"-C\", \"link-arg=-Xlinker\",\n                \"-C\", \"link-arg=-rpath\",\n                \"-C\", \"link-arg=-Xlinker\",\n                \"-C\", \"link-arg=\" .. (dir:gsub(\"%$ORIGIN\", \"@loader_path\"))}\n    end\nend\n\n-- make the build arguments list\nfunction buildargv(self, sourcefiles, targetkind, targetfile, flags)\n    -- add rpath for dylib (macho), e.g. -install_name @rpath/file.dylib\n    local flags_extra = {}\n    if targetkind == \"shared\" and self:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n        table.insert(flags_extra, \"-C\")\n        table.insert(flags_extra, \"link-arg=-Xlinker\")\n        table.insert(flags_extra, \"-C\")\n        table.insert(flags_extra, \"link-arg=-install_name\")\n        table.insert(flags_extra, \"-C\")\n        table.insert(flags_extra, \"link-arg=-Xlinker\")\n        table.insert(flags_extra, \"-C\")\n        table.insert(flags_extra, \"link-arg=@rpath/\" .. path.filename(targetfile))\n    end\n    return self:program(), table.join(flags, flags_extra, \"-o\", targetfile, sourcefiles)\nend\n\n-- build the target file\nfunction build(self, sourcefiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(buildargv(self, sourcefiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefiles, objectfile, flags)\n    return self:program(), table.join(\"--emit\", \"obj\", flags, \"-o\", objectfile, sourcefiles)\nend\n\n-- compile the source file\nfunction compile(self, sourcefiles, objectfile, dependinfo, flags)\n    os.mkdir(path.directory(objectfile))\n    os.runv(compargv(self, sourcefiles, objectfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/sdar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sdar.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\n\n-- init it\nfunction init(self)\n\n    -- init flags\n    self:set(\"arflags\", \"-cr\")\nend\n\n-- make the strip flag\nfunction strip(self, level)\n\n    -- the maps\n    local maps =\n    {\n        debug = \"-S\"\n    ,   all   = \"-s\"\n    }\n\n    -- make it\n    return maps[level]\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags, opt)\n\n    -- check\n    assert(targetkind == \"static\")\n\n    -- init arguments\n    opt = opt or {}\n    local argv = table.join(flags, targetfile, objectfiles)\n    if is_host(\"windows\") and not opt.rawargs then\n        argv = winos.cmdargv(argv, {escape = true})\n    end\n\n    -- make it\n    return self:program(), argv\nend\n\n-- link the library file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n\n    -- check\n    assert(targetkind == \"static\", \"the target kind: %s is not support for ar\", targetkind)\n\n    -- ensure the target directory\n    os.mkdir(path.directory(targetfile))\n\n    -- @note remove the previous archived file first to force recreating a new file\n    os.tryrm(targetfile)\n\n    -- link it\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/sdasstm8.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sdasstm8.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/sdcc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"core.language.language\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the flags is \"-Wl,<arg>\"?\n    local flags_str = table.concat(flags, \" \")\n    if flags_str:startswith(\"-Wl,\") then\n        return true\n    end\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\"\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.sdcc.has_flags\"\n\n    -- make flags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all flags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- get extension\n    -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]\n    local extension = opt.program:endswith(\"++\") and \".cpp\" or (table.wrap(language.sourcekinds()[opt.toolkind or \"cc\"])[1] or \".c\")\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"sdcc_has_flags\" .. extension)\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n    end\n\n    -- check flags for linker\n    if islinker then\n        return _try_running(opt.program, table.join(flags, \"-o\", os.tmpfile(), sourcefile))\n    end\n\n    -- check flags for compiler\n    -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage\n    return _try_running(opt.program, table.join(flags, \"-S\", \"-o\", os.tmpfile(), sourcefile))\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/sdcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sdcc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- optimize\n        [\"-O0\"]                     = \"\"\n    ,   [\"-Os\"]                     = \"--opt-code-speed\"\n    ,   [\"-O3\"]                     = \"--opt-code-size\"\n    ,   [\"-Ofast\"]                  = \"--opt-code-speed\"\n\n        -- symbols\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-Weverything\"]            = \"\"\n    ,   [\"-Wextra\"]                 = \"\"\n    ,   [\"-Wall\"]                   = \"\"\n    ,   [\"-W1\"]                     = \"--less-pedantic\"\n    ,   [\"-W2\"]                     = \"--less-pedantic\"\n    ,   [\"-W3\"]                     = \"\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n    ,   [\"%-fno%-.*\"]               = \"\"\n\n        -- language\n    ,   [\"-ansi\"]                   = \"--std-c89\"\n    ,   [\"-std=c89\"]                = \"--std-c89\"\n    ,   [\"-std=c99\"]                = \"--std-c99\"\n    ,   [\"-std=c11\"]                = \"--std-c11\"\n    ,   [\"-std=c20\"]                = \"--std-c2x\"\n    ,   [\"-std=gnu89\"]              = \"--std-sdcc89\"\n    ,   [\"-std=gnu99\"]              = \"--std-sdcc99\"\n    ,   [\"-std=gnu11\"]              = \"--std-sdcc11\"\n    ,   [\"-std=gnu20\"]              = \"--std-sdcc2x\"\n    ,   [\"-std=.*\"]                 = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps =\n    {\n        none       = \"--less-pedantic\"\n    ,   less       = \"--less-pedantic\"\n    ,   error      = \"-Werror\"\n    }\n    return maps[level]\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none       = \"\"\n        ,   fast       = \"--opt-code-speed\"\n        ,   faster     = \"--opt-code-speed\"\n        ,   fastest    = \"--opt-code-speed\"\n        ,   smallest   = \"--opt-code-size\"\n        ,   aggressive = \"--opt-code-speed\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the language flag\nfunction nf_language(self, stdname)\n    if _g.cmaps == nil then\n        _g.cmaps =\n        {\n            ansi        = \"--std-c89\"\n        ,   c89         = \"--std-c89\"\n        ,   gnu89       = \"--std-sdcc89\"\n        ,   c99         = \"--std-c99\"\n        ,   gnu99       = \"--std-sdcc99\"\n        ,   c11         = \"--std-c11\"\n        ,   gnu11       = \"--std-sdcc11\"\n        ,   c20         = \"--std-c2x\"\n        ,   gnu20       = \"--std-sdcc2x\"\n        ,   clatest     = {\"--std-c2x\", \"--std-c11\", \"--std-c99\", \"--std-c89\"}\n        ,   gnulatest   = {\"--std-sdcc2x\", \"--std-sdcc11\", \"--std-sdcc99\", \"--std-sdcc89\"}\n        }\n    end\n    local maps = _g.cmaps\n    local result = maps[stdname]\n    if type(result) == \"table\" then\n        for _, v in ipairs(result) do\n            if self:has_flags(v, \"cxflags\") then\n                result = v\n                maps[stdname] = result\n                return result\n            end\n        end\n    else\n        return result\n    end\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    return self:program(), table.join(\"-o\", targetfile, objectfiles, flags)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(objectfile))\n\n    local depfile = dependinfo and os.tmpfile() .. \".rel\" or nil\n    try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-M\")\n            end\n            os.iorunv(compargv(self, sourcefile, depfile, compflags))\n\n            -- do compile\n            outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, flags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- show warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"gcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/swift_frontend/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.swiftc.has_flags\")\n"
  },
  {
    "path": "xmake/modules/core/tools/swift_frontend.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        swift_frontend.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\", {\n\n        -- symbols\n        [\"-fvisibility=hidden\"]     = \"\"\n\n        -- warnings\n    ,   [\"-w\"]                      = \"-suppress-warnings\"\n    ,   [\"-W%d*\"]                   = \"-warn-swift3-objc-inference-minimal\"\n    ,   [\"-Wall\"]                   = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Wextra\"]                 = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Weverything\"]            = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Werror\"]                 = \"-warnings-as-errors\"\n\n        -- optimize\n    ,   [\"-O0\"]                     = \"-Onone\"\n    ,   [\"-Ofast\"]                  = \"-Ounchecked\"\n    ,   [\"-O.*\"]                    = \"-O\"\n\n        -- vectorexts\n    ,   [\"-m.*\"]                    = \"\"\n\n        -- strip\n    ,   [\"-s\"]                      = \"\"\n    ,   [\"-S\"]                      = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps = {\n        debug = \"-g\"\n    }\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none       = \"-suppress-warnings\"\n    ,   less       = \"-warn-swift3-objc-inference-minimal\"\n    ,   more       = \"-warn-swift3-objc-inference-minimal\"\n    ,   all        = \"-warn-swift3-objc-inference-complete\"\n    ,   everything = \"-warn-swift3-objc-inference-complete\"\n    ,   error      = \"-warnings-as-errors\"\n    }\n    return maps[level]\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps = {\n            none        = \"-Onone\"\n        ,   fast        = \"-O\"\n        ,   faster      = \"-O\"\n        ,   fastest     = \"-O\"\n        ,   smallest    = \"-O\"\n        ,   aggressive  = \"-Ounchecked\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the vector extension flag\nfunction nf_vectorext(self, extension)\n    local maps = {\n        mmx   = \"-mmmx\"\n    ,   sse   = \"-msse\"\n    ,   sse2  = \"-msse2\"\n    ,   sse3  = \"-msse3\"\n    ,   ssse3 = \"-mssse3\"\n    ,   avx   = \"-mavx\"\n    ,   avx2  = \"-mavx2\"\n    ,   neon  = \"-mfpu=neon\"\n    }\n    return maps[extension]\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, includedir)\n    return \"-I\" .. includedir\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-Xcc\", \"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return {\"-Xcc\", \"-U\" .. macro}\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    return {\"-framework\", framework}\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-F\", frameworkdir}\nend\n\n-- make the compile arguments list\n-- @see https://github.com/xmake-io/xmake/issues/3916\nfunction compargv(self, sourcefile, objectfile, flags)\n    local flags_new = {}\n    for _, flag in ipairs(flags) do\n        -- we need remove primary file in swift.build rule\n        if flag ~= sourcefile then\n            table.insert(flags_new, flag)\n        end\n    end\n    return self:program(), table.join(\"-c\", flags_new, \"-o\", objectfile, \"-primary-file\", sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags)\n    os.mkdir(path.directory(objectfile))\n    os.runv(compargv(self, sourcefile, objectfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/swiftc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- try running\nfunction _try_running(...)\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt)\n\n    -- only one flag?\n    if #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.swiftc.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"swiftc_has_flags.swift\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"\")\n    end\n\n    -- check it\n    local objectfile = os.tmpfile() .. \".o\"\n    local ok, errors = _try_running(opt.program, table.join(flags, \"-o\", objectfile, sourcefile))\n    if errors and not errors:match(\"unknown argument\") then\n        ok = true\n        errors = nil\n    end\n\n    -- remove files\n    os.tryrm(objectfile)\n\n    -- ok?\n    return ok, errors\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/swiftc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        swiftc.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.language.language\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\", {\n\n        -- symbols\n        [\"-fvisibility=hidden\"]     = \"\"\n\n        -- warnings\n    ,   [\"-w\"]                      = \"-suppress-warnings\"\n    ,   [\"-W%d*\"]                   = \"-warn-swift3-objc-inference-minimal\"\n    ,   [\"-Wall\"]                   = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Wextra\"]                 = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Weverything\"]            = \"-warn-swift3-objc-inference-complete\"\n    ,   [\"-Werror\"]                 = \"-warnings-as-errors\"\n\n        -- optimize\n    ,   [\"-O0\"]                     = \"-Onone\"\n    ,   [\"-Ofast\"]                  = \"-Ounchecked\"\n    ,   [\"-O.*\"]                    = \"-O\"\n\n        -- vectorexts\n    ,   [\"-m.*\"]                    = \"\"\n\n        -- strip\n    ,   [\"-s\"]                      = \"\"\n    ,   [\"-S\"]                      = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"-Xlinker -S\"\n    ,   all   = \"-Xlinker -s\"\n    }\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps = {\n        debug = \"-g\"\n    }\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none       = \"-suppress-warnings\"\n    ,   less       = \"-warn-swift3-objc-inference-minimal\"\n    ,   more       = \"-warn-swift3-objc-inference-minimal\"\n    ,   all        = \"-warn-swift3-objc-inference-complete\"\n    ,   everything = \"-warn-swift3-objc-inference-complete\"\n    ,   error      = \"-warnings-as-errors\"\n    }\n    return maps[level]\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    -- only for source kind\n    local kind = self:kind()\n    if language.sourcekinds()[kind] then\n        local maps =\n        {\n            none        = \"-Onone\"\n        ,   fast        = \"-O\"\n        ,   faster      = \"-O\"\n        ,   fastest     = \"-O\"\n        ,   smallest    = \"-O\"\n        ,   aggressive  = \"-Ounchecked\"\n        }\n        return maps[level]\n    end\nend\n\n-- make the vector extension flag\nfunction nf_vectorext(self, extension)\n    local maps = {\n        mmx   = \"-mmmx\"\n    ,   sse   = \"-msse\"\n    ,   sse2  = \"-msse2\"\n    ,   sse3  = \"-msse3\"\n    ,   ssse3 = \"-mssse3\"\n    ,   avx   = \"-mavx\"\n    ,   avx2  = \"-mavx2\"\n    ,   neon  = \"-mfpu=neon\"\n    }\n    return maps[extension]\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, includedir)\n    return \"-I\" .. includedir\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-Xcc\", \"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return {\"-Xcc\", \"-U\" .. macro}\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    return {\"-framework\", framework}\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-F\", frameworkdir}\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\", dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    return self:program(), table.join(\"-o\", targetfile, objectfiles, flags)\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags)\n    os.mkdir(path.directory(objectfile))\n    os.runv(compargv(self, sourcefile, objectfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/tcc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/tcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tcc.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init shflags\n    self:set(\"shflags\", \"-shared\", \"-rdynamic\")\n\n    -- init cxflags for the kind: shared\n    self:set(\"shared.cxflags\", \"-fPIC\")\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- warnings\n        [\"-W1\"] = \"-Wall\"\n    ,   [\"-W2\"] = \"-Wall\"\n    ,   [\"-W3\"] = \"-Wall\"\n    ,   [\"-W4\"] = \"-Wall -Wunsupported\"\n\n         -- strip\n    ,   [\"-s\"]  = \"-s\"\n    ,   [\"-S\"]  = \"-S\"\n    })\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps =\n    {\n        debug = \"-S\"\n    ,   all   = \"-s\"\n    }\n    return maps[level]\nend\n\n-- make the symbol flag\nfunction nf_symbol(self, level)\n    local maps =\n    {\n        debug  = \"-g\"\n    ,   hidden = \"-fvisibility=hidden\"\n    }\n    return maps[level]\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps =\n    {\n        none       = \"-w\"\n    ,   less       = \"-W1\"\n    ,   more       = \"-W3\"\n    ,   all        = \"-Wall\"\n    ,   allextra   = \"-Wall -Wunsupported -Wwrite-strings -Wimplicit-function-declaration\"\n    ,   everything = \"-Wall -Wunsupported -Wwrite-strings -Wimplicit-function-declaration\"\n    ,   error      = \"-Werror\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\" .. dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\" .. dir}\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    local argv\n    if targetkind == \"static\" then\n        argv = table.join(\"-ar\", \"cr\", targetfile, objectfiles)\n    else\n        argv = table.join(\"-o\", targetfile, objectfiles, flags)\n    end\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"-c\", flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    opt = opt or {}\n    os.mkdir(path.directory(objectfile))\n\n    local depfile = dependinfo and os.tmpfile() or nil\n    try\n    {\n        function ()\n\n            -- generate includes file\n            local compflags = flags\n            if depfile then\n                compflags = table.join(compflags, \"-MD\", \"-MF\", depfile)\n            end\n\n            -- do compile\n            local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags))\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- find the start line of error\n                local lines = tostring(errors):split(\"\\n\")\n                local start = 0\n                for index, line in ipairs(lines) do\n                    if line:find(\"error:\", 1, true) or line:find(\"错误：\", 1, true) then\n                        start = index\n                        break\n                    end\n                end\n\n                -- get 16 lines of errors\n                if start > 0 or not option.get(\"verbose\") then\n                    if start == 0 then start = 1 end\n                    errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), \"\\n\")\n                end\n\n                -- raise compiling errors\n                raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n\n                -- print some warnings\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n\n                -- generate the dependent includes\n                if depfile and os.isfile(depfile) then\n                    if dependinfo then\n                        dependinfo.depfiles_format = \"gcc\"\n                        dependinfo.depfiles = io.readfile(depfile, {continuation = \"\\\\\"})\n                    end\n\n                    -- remove the temporary dependent file\n                    os.tryrm(depfile)\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/windres.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        windres.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.policy\")\nimport(\"core.project.project\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n    self:add(\"mrcflags\", \"--use-temp-file\", \"-O\", \"coff\")\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\", dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, sourcefile, objectfile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n    os.mkdir(path.directory(objectfile))\n    try\n    {\n        function ()\n            local program, argv = compargv(self, sourcefile, objectfile, flags)\n            local outdata, errdata = os.iorunv(program, argv, {envs = self:runenvs()})\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n                os.raise(errors)\n            end\n        },\n        finally\n        {\n            function (ok, warnings)\n                if warnings and #warnings > 0 and policy.build_warnings(opt) then\n                    progress.show_output(\"${color.warning}%s\", table.concat(table.slice(warnings:split('\\n'), 1, 8), '\\n'))\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/yasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        yasm.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.policy\")\nimport(\"core.language.language\")\nimport(\"utils.progress\")\n\n-- init it\nfunction init(self)\n\n    -- init flags map\n    self:set(\"mapflags\",\n    {\n        -- symbols\n        [\"-g\"]                      = \"\"\n    ,   [\"-fvisibility=.*\"]         = \"\"\n\n        -- warnings\n    ,   [\"-Wall\"]                   = \"\" -- = \"-Wall\" will enable too more warnings\n    ,   [\"-W1\"]                     = \"\"\n    ,   [\"-W2\"]                     = \"\"\n    ,   [\"-W3\"]                     = \"\"\n    ,   [\"-Werror\"]                 = \"\"\n    ,   [\"%-Wno%-error=.*\"]         = \"\"\n\n        -- others\n    ,   [\"-ftrapv\"]                 = \"\"\n    ,   [\"-fsanitize=address\"]      = \"\"\n    })\nend\n\n-- make the warning flag\nfunction nf_warning(self, level)\n    local maps = {\n        none  = \"-w\"\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the undefine flag\nfunction nf_undefine(self, macro)\n    return \"-U\" .. macro\nend\n\n-- make the includedir flag\nfunction nf_includedir(self, dir)\n    return {\"-I\", dir}\nend\n\n-- make the sysincludedir flag\nfunction nf_sysincludedir(self, dir)\n    return nf_includedir(self, dir)\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(flags, \"-o\", objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags, opt)\n\n    -- ensure the object directory\n    os.mkdir(path.directory(objectfile))\n\n    -- compile it\n    local outdata, errdata = try\n    {\n        function ()\n            return os.iorunv(compargv(self, sourcefile, objectfile, flags))\n        end,\n        catch\n        {\n            function (errors)\n\n                -- try removing the old object file for forcing to rebuild this source file\n                os.tryrm(objectfile)\n\n                -- raise compiling errors\n                raise(tostring(errors))\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n\n                -- show warnings?\n                if ok and errdata and policy.build_warnings(opt) then\n                    errdata = errdata:trim()\n                    if #errdata > 0 then\n                        progress.show_output(\"${color.warning}%s\", errdata)\n                    end\n                end\n            end\n        }\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\n\n-- is linker?\nfunction _islinker(flags, opt)\n\n    -- the tool kind is ld or sh?\n    local toolkind = opt.toolkind or \"\"\n    return toolkind == \"ld\" or toolkind == \"sh\" or toolkind:endswith(\"ld\") or toolkind:endswith(\"sh\")\nend\n\n-- try running\nfunction _try_running(...)\n\n    local argv = {...}\n    local errors = nil\n    return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or \"\"):trim() end }}, errors\nend\n\n-- attempt to check it from the argument list\nfunction _check_from_arglist(flags, opt, islinker)\n\n    -- only for compiler\n    if islinker or #flags > 1 then\n        return\n    end\n\n    -- make cache key\n    local key = \"core.tools.zig.has_flags\"\n\n    -- make allflags key\n    local flagskey = opt.program .. \"_\" .. (opt.programver or \"\")\n\n    -- get all allflags from argument list\n    local allflags = detectcache:get2(key, flagskey)\n    if not allflags then\n\n        -- get argument list\n        allflags = {}\n        local arglist = os.iorunv(opt.program, {\"build-obj\", \"--help\"})\n        if arglist then\n            for arg in arglist:gmatch(\"%s+(%-[%-%a%d]+)%s+\") do\n                allflags[arg] = true\n            end\n        end\n\n        -- save cache\n        detectcache:set2(key, flagskey, allflags)\n    end\n    return allflags[flags[1]]\nend\n\n-- try running to check flags\nfunction _check_try_running(flags, opt, islinker)\n\n    -- make an stub source file\n    local sourcefile = path.join(os.tmpdir(), \"detect\", \"zig_has_flags.zig\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, \"pub fn main() !void {}\")\n    end\n\n    -- init argv\n    local argv = table.join(flags, \"-femit-bin=\" .. os.tmpfile(), sourcefile)\n    if islinker then\n        table.insert(argv, 1, \"build-exe\")\n    else\n        table.insert(argv, 1, \"build-obj\")\n    end\n\n    -- check it\n    return _try_running(opt.program, argv)\nend\n\n-- has_flags(flags)?\n--\n-- @param opt   the argument options, e.g. {toolname = \"\", program = \"\", programver = \"\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\"}\n--\n-- @return      true or false\n--\nfunction main(flags, opt)\n\n    -- is linker?\n    local islinker = _islinker(flags, opt)\n\n    -- attempt to check it from the argument list\n    if _check_from_arglist(flags, opt, islinker) then\n        return true\n    end\n\n    -- try running to check it\n    return _check_try_running(flags, opt, islinker)\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        zig.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.project.target\")\n\n-- init it\nfunction init(self)\n\n    -- init shflags\n    self:set(\"zcshflags\", \"-dynamic\", \"-fPIC\")\n\n    -- init zcflags for the kind: shared\n    self:set(\"shared.zcflags\", \"-fPIC\")\nend\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug  = \"-fstrip\"\n    ,   all    = {\"-fstrip\", \"-dead_strip\"}\n    }\n    return maps[level]\nend\n\n-- make the define flag\nfunction nf_define(self, macro)\n    return {\"-D\" .. macro}\nend\n\n-- make the optimize flag\nfunction nf_optimize(self, level)\n    local maps =\n    {\n        none       = \"-O Debug\"\n    ,   fast       = \"-O ReleaseSafe\"\n    ,   fastest    = \"-O ReleaseFast\"\n    ,   smallest   = \"-O ReleaseSmall\"\n    ,   aggressive = \"-O ReleaseFast\"\n    }\n    return maps[level]\nend\n\n-- make the link flag\nfunction nf_link(self, lib)\n    return \"-l\" .. lib\nend\n\n-- make the syslink flag\nfunction nf_syslink(self, lib)\n    return nf_link(self, lib)\nend\n\n-- make the linkdir flag\nfunction nf_linkdir(self, dir)\n    return {\"-L\", dir}\nend\n\n-- make the framework flag\nfunction nf_framework(self, framework)\n    return {\"-framework\", framework}\nend\n\n-- make the frameworkdir flag\nfunction nf_frameworkdir(self, frameworkdir)\n    return {\"-F\", path.translate(frameworkdir)}\nend\n\n-- make the rpathdir flag\nfunction nf_rpathdir(self, dir)\n    dir = path.translate(dir)\n    if self:is_plat(\"macosx\") then\n        return {\"-rpath\", (dir:gsub(\"%$ORIGIN\", \"@loader_path\"))}\n    else\n        return {\"-rpath\", (dir:gsub(\"@[%w_]+\", function (name)\n            local maps = {[\"@loader_path\"] = \"$ORIGIN\", [\"@executable_path\"] = \"$ORIGIN\"}\n            return maps[name]\n        end))}\n    end\nend\n\n-- make the link arguments list\nfunction linkargv(self, objectfiles, targetkind, targetfile, flags)\n    local argv = {}\n    if targetkind == \"binary\" then\n        table.insert(argv, \"build-exe\")\n    elseif targetkind == \"static\" or targetkind == \"shared\" then\n        table.insert(argv, \"build-lib\")\n    else\n        raise(\"unknown target kind(%s)!\", targetkind)\n    end\n    table.join2(argv, flags, \"-femit-bin=\" .. targetfile, objectfiles)\n    return self:program(), argv\nend\n\n-- link the target file\nfunction link(self, objectfiles, targetkind, targetfile, flags)\n    os.mkdir(path.directory(targetfile))\n    os.runv(linkargv(self, objectfiles, targetkind, targetfile, flags))\nend\n\n-- make the compile arguments list\nfunction compargv(self, sourcefile, objectfile, flags)\n    return self:program(), table.join(\"build-obj\", flags, \"-femit-bin=\" .. objectfile, sourcefile)\nend\n\n-- compile the source file\nfunction compile(self, sourcefile, objectfile, dependinfo, flags)\n    os.mkdir(path.directory(objectfile))\n    os.runv(compargv(self, sourcefile, objectfile, flags))\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cc/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cc/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        zig_cc.lua\n--\n\n-- inherit clang\ninherit(\"clang\")\n\n-- make the strip flag\nfunction nf_strip(self, level)\n    local maps = {\n        debug = \"-Wl,-S\"\n    ,   all   = \"-s\"\n    }\n    return maps[level]\nend\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cxx/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.features\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cxx/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\ninherit(\"core.tools.gcc.has_flags\")\n\n"
  },
  {
    "path": "xmake/modules/core/tools/zig_cxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        zig_cxx.lua\n--\n\ninherit(\"zig_cc\")\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_libxml2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_libxml2.lua\n--\n\n-- imports\nimport(\"package.manager.find_package\")\n\n-- find libxml2\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- find package by the builtin script\n    local result = opt.find_package(\"libxml2\", opt)\n\n    -- find package from the homebrew package manager\n    if not result and opt.plat == os.host() and opt.arch == os.arch() then\n        result = find_package(\"brew::libxml2/libxml-2.0\", opt)\n    end\n\n    -- patch \"include/libxml2\"\n    if result then\n        local includedirs = {}\n        for _, includedir in ipairs(result.includedirs) do\n            if includedir:endswith(\"include\") then\n                table.insert(includedirs, path.join(includedir, \"libxml2\"))\n            else\n                table.insert(includedirs, includedir)\n            end\n        end\n        result.includedirs = includedirs\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_mbedtls.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_mbedtls.lua\n--\n\n-- imports\nimport(\"package.manager.find_package\")\n\n-- find mbedtls\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n    opt.links = {\"mbedtls\", \"mbedcrypto\", \"mbedx509\"}\n    return opt.find_package(\"mbedtls\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_mkl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_mkl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\nimport(\"lib.detect.find_package\")\n\n-- find mkl\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- for windows platform\n    if opt.plat == \"windows\" then\n\n        -- init bits\n        local rdir = (opt.arch == \"x64\" and \"intel64\" or \"ia32\")\n\n        -- init search paths\n        local paths = {\n            \"$(env ONEAPI_ROOT)\\\\mkl\\\\latest\"\n        }\n\n        -- find library\n        local result = {links = {}, linkdirs = {}, includedirs = {}, threading = \"\"}\n        local linkinfo = find_library(\"mkl_core\", paths, {suffixes = path.join(\"lib\", rdir)})\n        if not linkinfo then\n            return\n        end\n        table.insert(result.linkdirs, linkinfo.linkdir)\n        if rdir == \"intel64\" then\n            table.insert(result.links, \"mkl_intel_ilp64\")\n        else\n            table.insert(result.links, \"mkl_intel_c\")\n        end\n\n        -- use tbb if available\n        local tbb_res = find_package(\"tbb\")\n        if tbb_res then\n            table.join2(result.linkdirs, tbb_res.linkdirs)\n            table.join2(result.links, {\"mkl_tbb_thread\", \"mkl_core\", \"tbb\"})\n            result.threading = \"tbb\"\n        else\n            table.join2(result.links, {\"mkl_sequential\", \"mkl_core\"})\n            result.threading = \"seq\"\n        end\n\n        -- find include\n        table.insert(result.includedirs, find_path(\"mkl.h\", paths, {suffixes = \"include\"}))\n        return result\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_mysql.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_mysql.lua\n--\n\n-- imports\nimport(\"package.manager.find_package\")\n\n-- find mysql\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- find package by the builtin script\n    local result = opt.find_package(\"mysql\", opt)\n\n    -- find package from the homebrew package manager\n    if not result and opt.plat == os.host() and opt.arch == os.arch() then\n        result = find_package(\"brew::mysqlclient\", opt)\n    end\n    return result\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_nvtx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_nvtx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\nimport(\"detect.sdks.find_cuda\")\n\n-- find nvtx\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n    if opt.plat == \"windows\" then\n\n        -- init bits\n        local rdir = (opt.arch == \"x64\" and \"x64\" or \"Win32\")\n        local libname = (opt.arch == \"x64\" and \"nvToolsExt64_1\" or \"nvToolsExt32_1\")\n\n        -- init search paths\n        local paths =\n        {\n            \"$(env NVTOOLSEXT_PATH)\",\n            \"$(env PROGRAMFILES)/NVIDIA Corporation/NvToolsExt\"\n        }\n\n        -- find library\n        local result = {links = {}, linkdirs = {}, includedirs = {}, libfiles = {}}\n        local linkinfo = find_library(libname, paths, {suffixes = path.join(\"lib\", rdir)})\n        if linkinfo then\n            local nvtx_dir = path.directory(path.directory(linkinfo.linkdir))\n            table.insert(result.linkdirs, linkinfo.linkdir)\n            table.insert(result.links, libname)\n            table.insert(result.libfiles, path.join(nvtx_dir, \"bin\", rdir, libname .. \".dll\"))\n            table.insert(result.libfiles, path.join(nvtx_dir, \"lib\", rdir, libname .. \".lib\"))\n        else\n            -- not found?\n            return\n        end\n\n        -- find include\n        table.insert(result.includedirs, find_path(\"nvToolsExt.h\", paths, {suffixes = \"include\"}))\n        return result\n    else\n        local cuda = find_cuda()\n        if cuda then\n            local result = {links = {}, linkdirs = {}, includedirs = {}}\n\n            -- find library\n            local linkinfo = find_library(\"nvToolsExt\", cuda.linkdirs)\n            if linkinfo then\n                table.insert(result.links, \"nvToolsExt\")\n                table.insert(result.linkdirs, linkinfo.linkdir)\n            else\n                return\n            end\n            table.join2(result.includedirs, cuda.includedirs)\n            return result\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_openssl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_openssl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\n\n-- find openssl\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- for windows platform\n    --\n    -- http://www.slproweb.com/products/Win32OpenSSL.html\n    --\n    if opt.plat == \"windows\" then\n\n        -- init bits\n        local bits = (opt.arch == \"x64\" and \"64\" or \"32\")\n\n        -- init search paths\n        local paths = {\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\OpenSSL %(\" .. bits .. \"-bit%)_is1;Inno Setup: App Path)\",\n                        \"$(env PROGRAMFILES)/OpenSSL\",\n                        \"$(env PROGRAMFILES)/OpenSSL-Win\" .. bits,\n                        \"C:/OpenSSL\",\n                        \"C:/OpenSSL-Win\" .. bits}\n\n        -- find library\n        local result = {links = {}, linkdirs = {}, includedirs = {}}\n        for _, name in ipairs({\"libssl\", \"libcrypto\"}) do\n            local linkinfo = find_library(name, paths, {suffixes = \"lib\"})\n            if linkinfo then\n                table.insert(result.links, linkinfo.link)\n                table.insert(result.linkdirs, linkinfo.linkdir)\n            end\n        end\n\n        -- not found?\n        if #result.links ~= 2 then\n            return\n        end\n\n        -- find include\n        table.insert(result.includedirs, find_path(\"openssl/ssl.h\", paths, {suffixes = \"include\"}))\n\n        -- ok\n        return result\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_pcre.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_pcre.lua\n--\n\n-- imports\nimport(\"package.manager.find_package\")\n\n-- find pcre\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- find package by the builtin script\n    local result = opt.find_package(\"pcre\", opt)\n\n    -- find package from the homebrew package manager\n    if not result and opt.plat == os.host() and opt.arch == os.arch() then\n        for _, width in ipairs({\"\", \"16\", \"32\"}) do\n            result = find_package(\"brew::pcre/libpcre\" .. width, opt)\n            if result then\n                break\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_pcre2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_pcre2.lua\n--\n\n-- imports\nimport(\"package.manager.find_package\")\n\n-- find pcre2\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- find package by the builtin script\n    local result = opt.find_package(\"pcre2\", opt)\n\n    -- find package from the homebrew package manager\n    if not result and opt.plat == os.host() and opt.arch == os.arch() then\n        for _, width in ipairs({\"8\", \"16\", \"32\"}) do\n            result = find_package(\"brew::pcre2/libpcre2-\" .. width, opt)\n            if result then\n                break\n            end\n        end\n    end\n\n    -- patch PCRE2_CODE_UNIT_WIDTH\n    if result and not result.defines then\n        local links = {}\n        for _, link in ipairs(result.links) do\n            links[link] = true\n        end\n        for _, width in ipairs({\"8\", \"16\", \"32\"}) do\n            if links[\"pcre2-\" .. width] then\n                result.links   = {\"pcre2-\" .. width}\n                result.defines = {\"PCRE2_CODE_UNIT_WIDTH=\" .. width}\n                break\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_tbb.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_tbb.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\n\n-- find tbb\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- for windows platform\n    if opt.plat == \"windows\" then\n\n        -- init bits\n        local rdir = (opt.arch == \"x64\" and \"intel64\" or \"ia32\")\n\n        -- init search paths\n        local paths = {\n            \"$(env ONEAPI_ROOT)\\\\tbb\\\\latest\"\n        }\n\n        -- find library\n        local result = {links = {}, linkdirs = {}, includedirs = {}}\n        local linkinfo = find_library(\"tbb\", paths, {suffixes = path.join(\"lib\", rdir, \"vc14\")})\n        if linkinfo then\n            table.insert(result.linkdirs, linkinfo.linkdir)\n            table.join2(result.links, {\"tbb\", \"tbb_malloc\"})\n        else\n            -- not found?\n            return\n        end\n\n        -- find include\n        table.insert(result.includedirs, find_path(path.join(\"tbb\", \"tbb.h\"), paths, {suffixes = \"include\"}))\n\n        -- ok\n        return result\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_vulkansdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_vulkansdk.lua\n--\n\n-- imports\nimport(\"detect.sdks.find_vulkansdk\")\n\n-- find vulkansdk\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n    opt = opt or {}\n    return find_vulkansdk({arch = opt.arch})\nend\n"
  },
  {
    "path": "xmake/modules/detect/packages/find_zlib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_zlib.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\nimport(\"package.manager.find_package\")\n\n-- find zlib\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n\n    -- for windows platform\n    --\n    -- http://gnuwin32.sourceforge.net/packages/zlib.html\n    --\n    if opt.plat == \"windows\" then\n\n        -- init search paths\n        local paths = {\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\GnuWin32\\\\Zlib;InstallPath)\",\n                        \"$(env PROGRAMFILES)/GnuWin32\",\n                        \"$(env PROGRAMFILES)/zlib\"}\n\n        -- find library\n        local result = {links = {}, linkdirs = {}, includedirs = {}}\n        local linkinfo = find_library(\"zlib\", paths, {suffixes = \"lib\"})\n        if not linkinfo then\n            return\n        end\n\n        -- save link and directory\n        table.insert(result.links, linkinfo.link)\n        table.insert(result.linkdirs, linkinfo.linkdir)\n\n        -- find include\n        local includedir = find_path(\"zlib.h\", paths, {suffixes = \"include\"})\n        if includedir then\n\n            -- save include directory\n            table.insert(result.includedirs, includedir)\n\n            -- get version\n            local zlib_h = io.readfile(path.join(includedir, \"zlib.h\"))\n            if zlib_h then\n                local version = zlib_h:match(\"#define ZLIB_VERSION \\\"(%d+%.?%d+%.?%d+)\\\"\")\n                if version then\n                    result.version = version\n                end\n            end\n        end\n        return result\n    end\n\n    -- find it by the builtin script first\n    local result = opt.find_package(\"zlib\", opt)\n    if not result then\n        -- find it from the link name: z\n        result = find_package(\"system::z\", opt)\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_android_sdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_android_sdk.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_directory\")\n\n-- find sdk directory\nfunction _find_android_sdkdir(sdkdir)\n\n    -- get sdk directory\n    if not sdkdir then\n        sdkdir = os.getenv(\"ANDROID_SDK_HOME\") or os.getenv(\"ANDROID_SDK_ROOT\")\n        if not sdkdir and is_host(\"macosx\") then\n            sdkdir = \"~/Library/Android/sdk\"\n        end\n    end\n\n    -- get sdk directory\n    if sdkdir and os.isdir(sdkdir) then\n        return sdkdir\n    end\nend\n\n-- find the build-tools version of sdk\nfunction _find_sdk_build_toolver(sdkdir)\n\n    -- find the max version\n    local toolver_max = \"0\"\n    for _, dir in ipairs(os.dirs(path.join(sdkdir, \"build-tools\", \"*\"))) do\n        local toolver = path.filename(dir)\n        if semver.is_valid(toolver) and semver.compare(toolver, toolver_max) > 0 then\n            toolver_max = toolver\n        end\n    end\n\n    -- get the max sdk version\n    return toolver_max ~= \"0\" and tostring(toolver_max) or nil\nend\n\n-- find the android sdk\nfunction _find_android_sdk(sdkdir, build_toolver)\n\n    -- find sdk root directory\n    sdkdir = _find_android_sdkdir(sdkdir)\n    if not sdkdir then\n        return {}\n    end\n\n    -- find the build-tools version of sdk\n    build_toolver = build_toolver or _find_sdk_build_toolver(sdkdir)\n\n    -- ok?\n    return {sdkdir = sdkdir, build_toolver = build_toolver}\nend\n\n-- find android sdk directory\n--\n-- @param sdkdir    the android sdk directory\n-- @param opt       the argument options, e.g. {force = true, build_toolver = \"28.0.3\"}\n--\n-- @return          the sdk toolchains. e.g. {sdkdir = .., build_toolver = \"28.0.3\"}\n--\n-- @code\n--\n-- local sdk = find_android_sdk(\"~/Library/Android/sdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_android_sdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.sdk and cacheinfo.sdk.sdkdir and os.isdir(cacheinfo.sdk.sdkdir) then\n        return cacheinfo.sdk\n    end\n\n    -- find sdk\n    local sdk = _find_android_sdk(sdkdir or config.get(\"android_sdk\") or global.get(\"android_sdk\"), opt.build_toolver or config.get(\"build_toolver\"))\n    if sdk and sdk.sdkdir then\n\n        -- save to config\n        config.set(\"android_sdk\", sdk.sdkdir, {force = true, readonly = true})\n        config.set(\"build_toolver\", sdk.build_toolver, {force = true, readonly = true})\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            local extra = \"\"\n            if sdk.build_toolver then\n                extra = \" (buildtools: \" .. sdk.build_toolver .. \")\"\n            end\n            cprint(\"checking for Android SDK ... ${color.success}%s%s\", sdk.sdkdir, extra)\n        end\n    else\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Android SDK ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.sdk = sdk or false\n    detectcache:set(key, cacheinfo)\n    return sdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_c51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n-- Based On template file xmake\\modules\\detect\\sdks\\find_mdk.lua\n--\n-- @author      DawnMagnet\n-- @file        find_c51.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find C51 directory\nfunction _find_sdkdir(sdkdir)\n    local paths = {\n        \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Keil\\\\Products\\\\C51;Path)\"\n    }\n    if sdkdir then\n        table.insert(paths, 1, sdkdir)\n    end\n    local result = find_path(\"..\\\\C51\", paths)\n    if not result then\n        -- find it from some logical drives paths\n        paths = {}\n        for _, logical_drive in ipairs(winos.logical_drives()) do\n            table.insert(paths, path.join(logical_drive, \"Keil_v5\", \"C51\", \"BIN\"))\n        end\n        result = find_path(\"C51.exe\", paths)\n    end\n    return result\nend\n\n-- find C51 toolchains\nfunction _find_c51(sdkdir)\n    -- find C51 directory\n    sdkdir = _find_sdkdir(sdkdir)\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n    local result = {sdkdir = sdkdir}\n\n    -- get sdk version\n    local sdkver = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Keil\\\\Products\\\\C51;Version\")\n    if sdkver then\n        sdkver = semver.match(sdkver, 1, \"V%d+%.%d+\")\n        if sdkver then\n            result.sdkver = sdkver:rawstr()\n        end\n    end\n\n    -- c51(exe) sdk directory\n    if os.isfile(path.join(sdkdir, \"bin\", \"c51.exe\")) then\n        result.sdkdir_c51 = sdkdir\n    end\n\n    -- a51(exe) sdk directory\n    if os.isfile(path.join(sdkdir, \"bin\", \"a51.exe\")) then\n        result.sdkdir_a51 = sdkdir\n    end\n    return result\nend\n\n-- find c51 toolchains\n--\n-- @param sdkdir    the C51 directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false}\n--\n-- @return          the C51 toolchains. e.g. {sdkver = ..., sdkdir, sdkdir_armcc, sdkdir_armclang, sdkdir_c51}\n--\n-- @code\n--\n-- local toolchains = find_c51(\"~/c51\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_c51\"\n\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.c51 and cacheinfo.c51.sdkdir and os.isdir(cacheinfo.c51.sdkdir) then\n        return cacheinfo.c51\n    end\n\n    -- find c51\n    local c51 = _find_c51(sdkdir or config.get(\"sdk\"))\n    if c51 then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for c51 directory ... ${color.success}%s\", c51.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for c51 directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.c51 = c51 or false\n    detectcache:set(key, cacheinfo)\n    return c51\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_cross_toolchain.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cross_toolchain.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\n\n-- find bin directory and cross\nfunction _find_bindir(sdkdir, opt)\n\n    -- init bin directories\n    local bindirs = {}\n    if opt.bindir then\n        table.insert(bindirs, opt.bindir)\n    end\n    table.insert(bindirs, path.join(sdkdir, \"bin\"))\n\n    -- attempt to find *-[gcc|clang|ld]\n    for _, toolname in ipairs({\"gcc\", \"clang\", \"ld\"}) do\n        if is_host(\"windows\") then\n            toolname = toolname .. \".exe\"\n        end\n        local toolpath = find_file((opt.cross or '*-') .. toolname, bindirs)\n        if toolpath then\n            return path.directory(toolpath), path.filename(toolpath):sub(1, -(#toolname + 1))\n        end\n\n        -- find tool path\n        if not opt.cross then\n            toolpath = find_file(toolname, bindirs)\n            if toolpath then\n                return path.directory(toolpath), \"\"\n            end\n        end\n    end\n\n    -- attempt to use the bin directory\n    local bindir = opt.bindir or path.join(sdkdir, \"bin\")\n    if os.isdir(bindir) and not opt.cross then\n        return bindir\n    end\nend\n\n-- find cross toolchain\n--\n-- @param sdkdir   the root sdk directory of cross toolchain\n-- @param opt      the argument options\n--                 e.g. {bindir = .., cross = ..}\n--\n-- @return          the toolchain e.g. {sdkdir = .., bindir = .., cross = ..}\n--\n-- @code\n--\n-- local toolchain = find_cross_toolchain(\"/xxx/android-cross-r10e\")\n-- local toolchain = find_cross_toolchain(\"/xxx/android-cross-r10e\", {cross = \"arm-linux-androideabi-\"})\n-- local toolchain = find_cross_toolchain(\"/xxx/android-cross-r10e\", {cross = \"arm-linux-androideabi-\", bindir = ..})\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- get sdk directories\n    local sdkdirs = {}\n    if sdkdir then\n        table.insert(sdkdirs, sdkdir)\n    elseif opt.cross and not is_subhost(\"windows\") then\n        -- we attempt to find cross toolchain from /usr, e.g. /usr/bin/aarch64-linux-gnu-gcc\n        table.insert(sdkdirs, \"/usr/\")\n        table.insert(sdkdirs, \"/usr/local\")\n    end\n\n    -- find bin directory and cross\n    local result\n    for _, _sdkdir in ipairs(sdkdirs) do\n        if os.isdir(_sdkdir) then\n            local bindir, cross = _find_bindir(_sdkdir, opt)\n            if bindir then\n                result = {sdkdir = _sdkdir, bindir = bindir, cross = cross}\n                break\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_cuda.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cuda.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find cuda sdk directory\nfunction _find_sdkdir(version, sdkdir)\n\n    -- init the search directories\n    local paths = {}\n    if sdkdir then\n        version = version or \"*\"\n        table.insert(paths, path.join(sdkdir, \"bin\"))\n        if is_host(\"macosx\") then\n            table.insert(paths, path.join(sdkdir, format(\"CUDA-%s/bin\", version)))\n        elseif is_host(\"windows\") then\n            table.insert(paths, path.join(sdkdir, format(\"v%s\\\\bin\", version)))\n        else\n            table.insert(paths, path.join(sdkdir, format(\"cuda-%s/bin\", version)))\n        end\n    elseif version then\n        if is_host(\"macosx\") then\n            table.insert(paths, format(\"/Developer/NVIDIA/CUDA-%s/bin\", version))\n        elseif is_host(\"windows\") then\n            table.insert(paths, format(\"$(env CUDA_PATH_V%s)/bin\", version:gsub(\"%.\", \"_\")))\n            table.insert(paths, format(\"C:\\\\Program Files\\\\NVIDIA GPU Computing Toolkit\\\\CUDA\\\\v%s\\\\bin\", version))\n        else\n            table.insert(paths, format(\"/usr/local/cuda-%s/bin\", version))\n        end\n    else\n        if is_host(\"macosx\") then\n            table.insert(paths, \"/Developer/NVIDIA/CUDA/bin\")\n            table.insert(paths, \"/Developer/NVIDIA/CUDA*/bin\")\n        elseif is_host(\"windows\") then\n            table.insert(paths, \"$(env CUDA_PATH)/bin\")\n            table.insert(paths, \"C:\\\\Program Files\\\\NVIDIA GPU Computing Toolkit\\\\CUDA\\\\*\\\\bin\")\n        else\n            -- find from default symbol link dir\n            table.insert(paths, \"/usr/local/cuda/bin\")\n            table.insert(paths, \"/usr/local/cuda*/bin\")\n        end\n        table.insert(paths, \"$(env PATH)\")\n    end\n\n    -- attempt to find nvcc\n    local nvcc = find_file(is_host(\"windows\") and \"nvcc.exe\" or \"nvcc\", paths)\n    if nvcc then\n        return path.directory(path.directory(nvcc))\n    end\nend\n\n-- find cuda msbuild extensions\nfunction _find_msbuildextensionsdir(sdkdir)\n    local props = find_file(\"CUDA *.props\", {path.join(sdkdir, \"extras\", \"visual_studio_integration\", \"MSBuildExtensions\")})\n    if props then\n        return path.directory(props)\n    end\nend\n\n-- find cuda sdk toolchains\nfunction _find_cuda(sdkdir, sdkver)\n\n    -- handle sdkdir as version\n    if sdkdir and sdkdir:match(\"^[%d*]+%.[%d*]+$\") then\n        sdkver = sdkdir\n        sdkdir = nil\n    end\n\n    -- check sdkdir\n    if sdkdir and not os.isdir(sdkdir) then\n        raise(\"invalid cuda location: \" .. sdkdir)\n    end\n\n    -- check sdkver\n    if sdkver and not sdkver:match(\"^[%d*]+%.[%d*]+$\") then\n        raise(\"invalid cuda version: \" .. sdkver)\n    end\n\n    -- find cuda directory\n    sdkdir = _find_sdkdir(sdkver, sdkdir)\n    if not sdkdir and sdkver then\n        raise(\"cuda version %s not found!\", sdkver)\n    end\n\n    -- not found?\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n\n    -- get the bin directory\n    local bindir = path.join(sdkdir, \"bin\")\n    if not os.isexec(path.join(bindir, \"nvcc\")) then\n        return nil\n    end\n\n    -- get linkdirs\n    local linkdirs = {}\n    if is_host(\"windows\") then\n        local subdir = is_arch(\"x64\") and \"x64\" or \"Win32\"\n        table.insert(linkdirs, path.join(sdkdir, \"lib\", subdir))\n    elseif is_host(\"linux\") and is_arch(\"x86_64\", \"arm64\") then\n        table.insert(linkdirs, path.join(sdkdir, \"lib64\"))\n    else\n        table.insert(linkdirs, path.join(sdkdir, \"lib\"))\n    end\n\n    -- get includedirs\n    local includedirs = {path.join(sdkdir, \"include\")}\n\n    -- get version\n    local version = find_programver(path.join(bindir, \"nvcc\"), {parse = \"release (%d+%.%d+),\"})\n\n    -- find msbuildextensionsdir on windows\n    local msbuildextensionsdir\n    if is_host(\"windows\") then\n        msbuildextensionsdir = _find_msbuildextensionsdir(sdkdir)\n    end\n\n    -- get toolchains\n    return {sdkdir = sdkdir, bindir = bindir, version = version, linkdirs = linkdirs, includedirs = includedirs, msbuildextensionsdir = msbuildextensionsdir}\nend\n\n-- find cuda sdk toolchains\n--\n-- @param sdkdir    the cuda sdk directory or version\n-- @param opt       the argument options\n--\n-- @return          the cuda sdk toolchains. e.g. {sdkdir = ..., bindir = .., linkdirs = ..., includedirs = ..., .. }\n--\n-- @code\n--\n-- local toolchains = find_cuda(\"/Developer/NVIDIA/CUDA-9.1\")\n-- local toolchains = find_cuda(\"9.1\")\n-- local toolchains = find_cuda(\"9.*\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_cuda\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.cuda and cacheinfo.cuda.sdkdir and os.isdir(cacheinfo.cuda.sdkdir) then\n        return cacheinfo.cuda\n    end\n\n    -- find cuda\n    local cuda = _find_cuda(sdkdir or config.get(\"cuda\") or global.get(\"cuda\") or config.get(\"sdk\"), opt.version or config.get(\"cuda_sdkver\"))\n    if cuda then\n\n        -- save to config\n        config.set(\"cuda\", cuda.sdkdir, {force = true, readonly = true})\n        config.set(\"cuda_sdkver\", cuda.version, {force = true, readonly = true})\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Cuda SDK directory ... ${color.success}%s\", cuda.sdkdir)\n        end\n    else\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Cuda SDK directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.cuda = cuda or false\n    detectcache:set(key, cacheinfo)\n    return cuda\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_dia_sdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      redbeanw\n-- @file        find_dia_sdk.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.base.option\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.detectcache\")\nimport(\"detect.sdks.find_vstudio\")\n\nfunction _is_sdkdir_valid(sdkdir)\n    return os.isfile(path.join(sdkdir, \"lib\", \"diaguids.lib\"))\nend\n\nfunction _find_sdkdir(sdkdir, opt)\n    if not sdkdir then\n        local vsdir = os.getenv(\"VSInstallDir\")\n        if not vsdir then\n            if opt.toolchain then\n                vcvars = opt.toolchain:config(\"vcvars\")\n                if vcvars then\n                    vsdir = vcvars[\"VSInstallDir\"]\n                end\n            end\n        end\n        if not vsdir then\n            local msvc = toolchain.load(\"msvc\", {plat = opt.plat or config.get(\"plat\"), arch = opt.arch or config.get(\"arch\")})\n            if msvc and msvc:check() then\n                local vcvars = msvc:config(\"vcvars\")\n                if vcvars then\n                    vsdir = vcvars[\"VSInstallDir\"]\n                end\n            end\n        end\n        if vsdir then\n            sdkdir = path.join(vsdir, \"DIA SDK\")\n        else\n            return\n        end\n    end\n\n    if not _is_sdkdir_valid(sdkdir) then\n        sdkdir = path.join(sdkdir, \"DIA SDK\")\n    end\n\n    return _is_sdkdir_valid(sdkdir) and sdkdir or nil\nend\n\nfunction _find_dia_sdk(sdkdir, opt)\n    -- get sdkdir\n    sdkdir = _find_sdkdir(sdkdir, opt)\n    if not sdkdir then\n        return\n    end\n\n    -- get arch\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n    if arch then\n        local supported_arch = {\n            x64 = \"amd64\",\n            arm = \"arm\",\n            arm64 = \"arm64\"\n        }\n        arch = supported_arch[arch]\n    end\n    if not arch then\n        return\n    end\n\n    return {\n        sdkdir = sdkdir,\n        linkdirs = {\n            path.join(sdkdir, \"lib\", arch),\n            path.join(sdkdir, \"bin\", arch)\n        },\n        includedirs = {\n            path.join(sdkdir, \"include\", arch)\n        }\n    }\nend\n\n-- find DIA SDK\n--\n-- @param sdkdir    the DIA SDK directory\n-- @param opt       the argument options, e.g. {toolchain = ..., plat = ..., arch = ..., force = false, verbose = false}\n--\n-- @return          the DIA SDK. e.g. {sdkdir = ..., linkdirs = ..., includedirs = ...}\n--\n-- @code\n--\n-- local toolchains = find_dia_sdk(\"/opt/msvc/DIA SDK\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_dia_sdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.dia_sdk and os.isdir(cacheinfo.dia_sdk.sdkdir) then\n        return cacheinfo.dia_sdk\n    end\n\n    -- find dia sdk\n    local dia_sdk = _find_dia_sdk(sdkdir, opt)\n    if not dia_sdk then\n        local vstudio = find_vstudio()\n        if vstudio then\n            for vsver, value in pairs(vstudio) do\n                if value.vcvarsall then\n                    for arch, vcvarsall_value in pairs(value.vcvarsall) do\n                        local VSInstallDir = vcvarsall_value.VSInstallDir\n                        if VSInstallDir then\n                            dia_sdk = _find_dia_sdk(VSInstallDir, opt)\n                            if dia_sdk then\n                                goto found\n                            end\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n::found::\n\n    if dia_sdk then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for DIA SDK directory ... ${color.success}%s\", dia_sdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for DIA SDK directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.dia_sdk = dia_sdk or false\n    detectcache:set(key, cacheinfo)\n    return dia_sdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_dotnet.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dotnet.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.tool.toolchain\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find dotnet sdk info from dotnet cli\nfunction _find_dotnet_cli(sdkdir)\n\n    -- find dotnet program\n    local paths = {}\n    if sdkdir then\n        table.insert(paths, path.join(sdkdir, \"bin\"))\n        table.insert(paths, sdkdir)\n    end\n    local dotnet = find_tool(\"dotnet\", {version = true, paths = #paths > 0 and paths or nil})\n    if not dotnet then\n        return nil\n    end\n\n    local bindir = path.directory(dotnet.program)\n    local result = {bindir = bindir, version = dotnet.version}\n\n    -- get sdk list, e.g. \"8.0.100 [/usr/share/dotnet/sdk]\"\n    local sdklist = try { function () return os.iorunv(dotnet.program, {\"--list-sdks\"}) end }\n    if sdklist then\n        local sdks = {}\n        for _, line in ipairs(sdklist:split(\"\\n\", {plain = true})) do\n            line = line:trim()\n            local ver, dir = line:match(\"^(%S+)%s+%[(.-)%]\")\n            if ver and dir then\n                table.insert(sdks, {version = ver, directory = path.join(dir, ver)})\n            end\n        end\n        if #sdks > 0 then\n            result.sdks = sdks\n            result.sdkdir = sdks[#sdks].directory\n            result.sdkver = sdks[#sdks].version\n        end\n    end\n\n    -- set sdkdir from bindir if not found from sdk list\n    if not result.sdkdir then\n        result.sdkdir = sdkdir or path.directory(bindir)\n    end\n\n    -- get runtime list, e.g. \"Microsoft.NETCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]\"\n    local runtimelist = try { function () return os.iorunv(dotnet.program, {\"--list-runtimes\"}) end }\n    if runtimelist then\n        local runtimes = {}\n        for _, line in ipairs(runtimelist:split(\"\\n\", {plain = true})) do\n            line = line:trim()\n            local name, ver = line:match(\"^(%S+)%s+(%S+)%s+%[\")\n            if name and ver then\n                table.insert(runtimes, {name = name, version = ver})\n            end\n        end\n        if #runtimes > 0 then\n            result.runtimes = runtimes\n        end\n    end\n    return result\nend\n\n-- find .NET Framework SDK directory from MSVC (Windows only)\nfunction _find_netfxsdk(sdkdir)\n    if not sdkdir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc and msvc:check() then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars then\n                sdkdir = vcvars.WindowsSdkDir\n                if sdkdir then\n                    sdkdir = path.join(path.directory(path.translate(sdkdir)), \"NETFXSDK\")\n                end\n            end\n        end\n    end\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n\n    -- get sdk version\n    local sdkver\n    local vers = {}\n    for _, dir in ipairs(os.dirs(path.join(sdkdir, \"*\", \"Include\"))) do\n        table.insert(vers, path.filename(path.directory(dir)))\n    end\n    for _, ver in ipairs(vers) do\n        if os.isdir(path.join(sdkdir, ver, \"Lib\", \"um\")) and os.isdir(path.join(sdkdir, ver, \"Include\", \"um\")) then\n            sdkver = ver\n            break\n        end\n    end\n    if not sdkver then\n        return nil\n    end\n    return {sdkdir = sdkdir, sdkver = sdkver,\n        libdir = path.join(sdkdir, sdkver, \"Lib\"),\n        includedir = path.join(sdkdir, sdkver, \"Include\")}\nend\n\n-- find dotnet sdk\n--\n-- @param sdkdir    the dotnet directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false}\n--\n-- @return          the dotnet sdk info, e.g. {program = ..., version = ..., sdkver = ..., sdkdir = ..., sdks = {...}, runtimes = {...}}\n--\n-- @code\n--\n-- local dotnet = find_dotnet()\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_dotnet\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.dotnet and cacheinfo.dotnet.sdkdir and os.isdir(cacheinfo.dotnet.sdkdir) then\n        return cacheinfo.dotnet\n    end\n\n    -- find dotnet cli sdk\n    local dotnet = _find_dotnet_cli(sdkdir or config.get(\"dotnet\") or global.get(\"dotnet\"))\n\n    -- find .NET Framework SDK on Windows\n    if is_host(\"windows\") then\n        local netfxsdk = _find_netfxsdk(sdkdir or config.get(\"dotnet\") or global.get(\"dotnet\"))\n        if netfxsdk then\n            if dotnet then\n                dotnet.netfxsdk = netfxsdk\n            else\n                dotnet = netfxsdk\n            end\n        end\n    end\n\n    if dotnet then\n\n        -- save to config\n        if dotnet.sdkdir then\n            config.set(\"dotnet\", dotnet.sdkdir, {force = true, readonly = true})\n        end\n        if dotnet.sdkver then\n            config.set(\"dotnet_sdkver\", dotnet.sdkver, {force = true, readonly = true})\n        end\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            if dotnet.version then\n                cprint(\"checking for .NET SDK version ... ${color.success}%s\", dotnet.version)\n            end\n            if dotnet.sdkdir then\n                cprint(\"checking for .NET SDK directory ... ${color.success}%s\", dotnet.sdkdir)\n            end\n        end\n    else\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for .NET SDK directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.dotnet = dotnet or false\n    detectcache:set(key, cacheinfo)\n    return dotnet\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_emsdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      SirLynix\n-- @file        find_emsdk.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_file\")\n\n-- find sdk directory\nfunction _find_emsdkdir(sdkdir)\n    local paths = {}\n    if sdkdir then\n        table.insert(paths, sdkdir)\n    end\n    table.insert(paths, \"$(env EMSDK)\")\n    if is_host(\"linux\") then\n        table.join2(paths, {\"/usr/share/emscripten/\", \"/usr/lib/emscripten/\"})\n    end\n    local emsdk = find_file(\"emsdk.py\", paths, {suffixes = subdirs})\n    if emsdk then\n        return path.directory(emsdk)\n    end\n    local emcc_py = find_file(\"emcc.py\", paths, {suffixes = subdirs})\n    if emcc_py then\n        return path.directory(emcc_py)\n    end\nend\n\n-- find emsdk\nfunction _find_emsdk(sdkdir)\n\n    -- find sdk root directory\n    sdkdir = _find_emsdkdir(sdkdir)\n    if not sdkdir then\n        return {}\n    end\n\n    -- find emscripten toolchain directory\n    local emscripten\n    local subdirs = {}\n    table.insert(subdirs, path.join(\"*\", \"emscripten\"))\n    local emcc = find_file(\"emcc\", sdkdir, {suffixes = subdirs})\n    emcc = emcc or find_file(\"emcc.py\", sdkdir, {suffixes = subdirs})\n    if emcc then\n        emscripten = path.directory(emcc)\n    end\n    return {sdkdir = sdkdir, emscripten = emscripten}\n\nend\n\n-- find emsdk directory\n--\n-- @param sdkdir    the emsdk directory\n-- @param opt       the argument options, e.g. {force = true}\n--\n-- @return          the sdk toolchains. e.g. {sdkdir = ..}\n--\n-- @code\n--\n-- local sdk = find_emsdk(\"~/emsdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_emsdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.sdk and cacheinfo.sdk.sdkdir and os.isdir(cacheinfo.sdk.sdkdir) then\n        return cacheinfo.sdk\n    end\n\n    -- find sdk\n    local sdk = _find_emsdk(sdkdir or config.get(\"emsdk\") or global.get(\"emsdk\"))\n    if sdk and sdk.sdkdir then\n        config.set(\"emsdk\", sdk.sdkdir, {force = true, readonly = true})\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for emsdk directory ... ${color.success}%s\", sdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for emsdk directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.sdk = sdk or false\n    detectcache:set(key, cacheinfo)\n    return sdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_hdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_hdk.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_directory\")\n\n-- find hdk directory\nfunction _find_hdkdir(sdkdir)\n\n    -- get hdk directory\n    if not sdkdir then\n        if not sdkdir then\n            if is_host(\"macosx\") then\n                local paths = {\n                    \"/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony\",\n                    \"~/Library/OpenHarmony/Sdk/*\",\n                    \"~/Library/Huawei/Sdk/*/*\" -- for old version, deprecated\n                }\n                sdkdir = find_directory(\"native\", paths)\n            elseif is_host(\"windows\") then\n                sdkdir = find_directory(\"native\", \"~/Huawei/Sdk/*/*\")\n            end\n        end\n    end\n\n    -- get hdk directory\n    if sdkdir and os.isdir(sdkdir) then\n        return path.translate(sdkdir)\n    end\nend\n\n-- find the hdk toolchain\nfunction _find_hdk(sdkdir)\n\n    -- find hdk root directory\n    sdkdir = _find_hdkdir(sdkdir)\n    if not sdkdir then\n        return\n    end\n\n    -- get the binary directory\n    local bindir = path.join(sdkdir, \"llvm\", \"bin\")\n    if not os.isdir(bindir) then\n        return\n    end\n\n    local sysroot = path.join(sdkdir, \"sysroot\")\n    return {sdkdir = sdkdir,\n            bindir = bindir,\n            sysroot = sysroot}\nend\n\n-- find hdk toolchains\n--\n-- @param sdkdir    the hdk directory\n-- @param opt       the argument options\n--                  e.g. {verbose = true, force = false}\n--\n-- @return          the hdk toolchains. e.g. {bindir = .., cross = ..}\n--\n-- @code\n--\n-- local toolchain = find_hdk(\"/xxx/android-hdk-r10e\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_hdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.hdk and cacheinfo.hdk.sdkdir and os.isdir(cacheinfo.hdk.sdkdir) then\n        return cacheinfo.hdk\n    end\n\n    -- find hdk\n    local hdk = _find_hdk(sdkdir or config.get(\"sdk\") or global.get(\"sdk\"))\n    if hdk and hdk.sdkdir then\n        config.set(\"hdk\", hdk.sdkdir, {force = true, readonly = true})\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Harmony SDK ... ${color.success}%s\", hdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Harmony SDK ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.hdk = hdk or false\n    detectcache:set(key, cacheinfo)\n    return hdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_iarsdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iarsdk.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find IAR sdk directory\nfunction _find_sdkdir(sdkdir)\n    local paths = {\n        \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\IAR Systems\\\\Embedded Workbench\\\\5.0;LastInstallPath)/arm/bin\"\n    }\n    if sdkdir then\n        table.insert(paths, 1, sdkdir)\n    end\n    local bindir = find_path(\"iccarm.exe\", paths)\n    if bindir then\n        return path.directory(bindir)\n    end\nend\n\n-- find IAR sdk toolchains\nfunction _find_iarsdk(sdkdir)\n\n    -- find iarsdk directory\n    sdkdir = _find_sdkdir(sdkdir)\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n    return {sdkdir = sdkdir}\nend\n\n-- find IAR sdk toolchains\n--\n-- @param sdkdir    the IAR sdk directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false}\n--\n-- @return          the IAR sdk toolchains. e.g. {sdkver = ..., sdkdir}\n--\n-- @code\n--\n-- local toolchains = find_iarsdk(\"~/iarsdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_iarsdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.iarsdk and cacheinfo.iarsdk.sdkdir and os.isdir(cacheinfo.iarsdk.sdkdir) then\n        return cacheinfo.iarsdk\n    end\n\n    -- find iarsdk\n    local iarsdk = _find_iarsdk(sdkdir or config.get(\"sdk\"))\n    if iarsdk then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for IAR Embedded Workbench directory ... ${color.success}%s\", iarsdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for IAR Embedded Workbench directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.iarsdk = iarsdk or false\n    detectcache:set(key, cacheinfo)\n    return iarsdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_iccenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iccenv.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- init icl variables\nlocal iclvars = {\"path\",\n                 \"lib\",\n                 \"libpath\",\n                 \"include\",\n                 \"DevEnvdir\",\n                 \"VSInstallDir\",\n                 \"VCInstallDir\",\n                 \"WindowsSdkDir\",\n                 \"WindowsLibPath\",\n                 \"WindowsSDKVersion\",\n                 \"WindowsSdkBinPath\",\n                 \"UniversalCRTSdkDir\",\n                 \"UCRTVersion\"}\n\n-- load iclvars_bat environment variables\nfunction _load_iclvars(iclvars_bat, arch, opt)\n\n    -- make the geniclvars.bat\n    opt = opt or {}\n    local geniclvars_bat = os.tmpfile() .. \"_geniclvars.bat\"\n    local geniclvars_dat = os.tmpfile() .. \"_geniclvars.txt\"\n    local file = io.open(geniclvars_bat, \"w\")\n    file:print(\"@echo off\")\n    file:print(\"call \\\"%s\\\" -arch %s > nul\", iclvars_bat, arch)\n    for idx, var in ipairs(iclvars) do\n        file:print(\"echo \" .. var .. \" = %%\" .. var .. \"%% %s %s\", idx == 1 and \">\" or \">>\", geniclvars_dat)\n    end\n    file:close()\n\n    -- run geniclvars.bat\n    os.run(geniclvars_bat)\n\n    -- load all envirnoment variables\n    local variables = {}\n    for _, line in ipairs((io.readfile(geniclvars_dat) or \"\"):split(\"\\n\")) do\n        local p = line:find('=', 1, true)\n        if p then\n            local name = line:sub(1, p - 1):trim()\n            local value = line:sub(p + 1):trim()\n            variables[name] = value\n        end\n    end\n    if not variables.path then\n        return\n    end\n\n    -- remove some empty entries\n    for _, name in ipairs(iclvars) do\n        if variables[name] and #variables[name]:trim() == 0 then\n            variables[name] = nil\n        end\n    end\n\n    -- fix bin path for ia32\n    if variables.path and arch == \"ia32\" then\n        variables.path = variables.path:gsub(\"windows\\\\bin\\\\intel64;\", \"windows\\\\bin\\\\intel64_ia32;\")\n    end\n\n    -- convert path/lib/include to PATH/LIB/INCLUDE\n    variables.PATH    = variables.path\n    variables.LIB     = variables.lib\n    variables.LIBPATH = variables.libpath\n    variables.INCLUDE = variables.include\n    variables.path    = nil\n    variables.lib     = nil\n    variables.include = nil\n    variables.libpath = nil\n    return variables\nend\n\n-- find intel c/c++ envirnoment on windows\nfunction _find_intel_on_windows(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find iclvars_bat.bat\n    local paths = {\"$(env ICPP_COMPILER20)\"}\n    local iclvars_bat = find_file(\"bin/iclvars.bat\", paths)\n    -- look for setvars.bat which is new in 2021\n    if not iclvars_bat then\n        -- find setvars.bat in intel oneapi toolkits rootdir\n        paths = {\"$(env ONEAPI_ROOT)\"}\n        iclvars_bat = find_file(\"setvars.bat\", paths)\n    end\n    if not iclvars_bat then\n        -- find setvars.bat using ICPP_COMPILER.*\n        paths = {\n            \"$(env ICPP_COMPILER21)\",\n            \"$(env ICPP_COMPILER22)\",\n            \"$(env ICPP_COMPILER23)\"\n        }\n        iclvars_bat = find_file(\"../../../setvars.bat\", paths)\n        if not iclvars_bat then\n            paths = {\n                \"$(env ICPP_COMPILER24)\"\n            }\n            iclvars_bat = find_file(\"../../setvars.bat\", paths)\n        end\n    end\n    if iclvars_bat then\n\n        -- load iclvars_bat\n        local iclvars_x86 = _load_iclvars(iclvars_bat, \"ia32\", opt)\n        local iclvars_x64 = _load_iclvars(iclvars_bat, \"intel64\", opt)\n\n        -- save results\n        return {iclvars_bat = iclvars_bat, iclvars = {x86 = iclvars_x86, x64 = iclvars_x64}}\n     end\nend\n\n-- find intel c/c++ envirnoment on linux\nfunction _find_intel_on_linux(opt)\n\n    -- attempt to find the sdk directory\n    local paths = {\"/opt/intel/bin\", \"/usr/local/bin\", \"/usr/bin\"}\n    local icc = find_file(\"icc\", paths)\n    if icc then\n        local sdkdir = path.directory(path.directory(icc))\n        return {sdkdir = sdkdir, bindir = path.directory(icc), path.join(sdkdir, \"include\"), libdir = path.join(sdkdir, \"lib\")}\n    end\n\n    -- find it from oneapi sdk directory\n    local oneapi_rootdirs = {\"~/intel/oneapi/compiler\", \"/opt/intel/oneapi/compiler\"}\n    local arch = os.arch() == \"x86_64\" and \"intel64\" or \"ia32\"\n    paths = {}\n    for _, rootdir in ipairs(oneapi_rootdirs) do\n        table.insert(paths, path.join(rootdir, \"*\", is_host(\"macosx\") and \"mac\" or \"linux\", \"bin\", arch))\n    end\n    if #paths > 0 then\n        local icc = find_file(\"icc\", paths)\n        if icc then\n            local bindir = path.directory(icc)\n            local sdkdir = path.directory(path.directory(bindir))\n            return {sdkdir = sdkdir, bindir = bindir, libdir = path.join(sdkdir, \"compiler\", \"lib\", arch)}\n        end\n    end\nend\n\n-- find intel c/c++ environment\nfunction main(opt)\n    if is_host(\"windows\") then\n        return _find_intel_on_windows(opt)\n    else\n        return _find_intel_on_linux(opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_icxenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icxenv.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- init icx variables\nlocal icxvars = {\"path\",\n                 \"lib\",\n                 \"libpath\",\n                 \"include\",\n                 \"DevEnvdir\",\n                 \"VSInstallDir\",\n                 \"VCInstallDir\",\n                 \"WindowsSdkDir\",\n                 \"WindowsLibPath\",\n                 \"WindowsSDKVersion\",\n                 \"WindowsSdkBinPath\",\n                 \"UniversalCRTSdkDir\",\n                 \"UCRTVersion\"}\n\n-- load icxvars_bat environment variables\nfunction _load_icxvars(icxvars_bat, arch, opt)\n\n    -- make the genicxvars.bat\n    opt = opt or {}\n    local genicxvars_bat = os.tmpfile() .. \"_genicxvars.bat\"\n    local genicxvars_dat = os.tmpfile() .. \"_genicxvars.txt\"\n    local file = io.open(genicxvars_bat, \"w\")\n    file:print(\"@echo off\")\n    file:print(\"call \\\"%s\\\" -arch %s > nul\", icxvars_bat, arch)\n    for idx, var in ipairs(icxvars) do\n        file:print(\"echo \" .. var .. \" = %%\" .. var .. \"%% %s %s\", idx == 1 and \">\" or \">>\", genicxvars_dat)\n    end\n    file:close()\n\n    -- run genicxvars.bat\n    os.run(genicxvars_bat)\n\n    -- load all envirnoment variables\n    local variables = {}\n    for _, line in ipairs((io.readfile(genicxvars_dat) or \"\"):split(\"\\n\")) do\n        local p = line:find('=', 1, true)\n        if p then\n            local name = line:sub(1, p - 1):trim()\n            local value = line:sub(p + 1):trim()\n            variables[name] = value\n        end\n    end\n    if not variables.path then\n        return\n    end\n\n    -- remove some empty entries\n    for _, name in ipairs(icxvars) do\n        if variables[name] and #variables[name]:trim() == 0 then\n            variables[name] = nil\n        end\n    end\n\n    -- fix bin path for ia32\n    if variables.path and arch == \"ia32\" then\n        variables.path = variables.path:gsub(\"windows\\\\bin\\\\intel64;\", \"windows\\\\bin\\\\intel64_ia32;\")\n    end\n\n    -- convert path/lib/include to PATH/LIB/INCLUDE\n    variables.PATH    = variables.path\n    variables.LIB     = variables.lib\n    variables.LIBPATH = variables.libpath\n    variables.INCLUDE = variables.include\n    variables.path    = nil\n    variables.lib     = nil\n    variables.include = nil\n    variables.libpath = nil\n    return variables\nend\n\n-- find intel llvm c/c++ envirnoment on windows\nfunction _find_intel_on_windows(opt)\n    opt = opt or {}\n\n    -- find icxvars_bat.bat\n    local paths = {\"$(env ONEAPI_ROOT)\"}\n    local icxvars_bat = find_file(\"setvars.bat\", paths)\n    if not icxvars_bat then\n        paths = {}\n        local keys = winos.registry_keys(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\Intel\\\\DPCPPSuites\\\\**\\\\DPC++\")\n        for _, key in ipairs(keys) do\n            table.insert(paths, format(\"$(reg %s;ProductDir)\", key))\n        end\n        icxvars_bat = find_file(\"../../setvars.bat\", paths)\n    end\n    if icxvars_bat then\n        local icxvars_x86 = _load_icxvars(icxvars_bat, \"ia32\", opt)\n        local icxvars_x64 = _load_icxvars(icxvars_bat, \"intel64\", opt)\n        return {icxvars_bat = icxvars_bat, icxvars = {x86 = icxvars_x86, x64 = icxvars_x64}}\n     end\nend\n\n-- find intel llvm c/c++ envirnoment on linux\nfunction _find_intel_on_linux(opt)\n\n    -- attempt to find the sdk directory\n    local oneapi_rootdirs = {\"~/intel/oneapi/compiler\", \"/opt/intel/oneapi/compiler\"}\n    paths = {}\n    for _, rootdir in ipairs(oneapi_rootdirs) do\n        table.insert(paths, path.join(rootdir, \"*\", is_host(\"macosx\") and \"mac\" or \"linux\", \"bin\"))\n        table.insert(paths, path.join(rootdir, \"*\", \"bin\"))\n    end\n    if #paths > 0 then\n        local icx = find_file(\"icx\", paths)\n        if icx then\n            local bindir = path.directory(icx)\n            local sdkdir = path.directory(path.directory(bindir))\n            return {sdkdir = sdkdir, bindir = bindir}\n        end\n    end\nend\n\n-- find intel c/c++ environment\nfunction main(opt)\n    if is_host(\"windows\") then\n        return _find_intel_on_windows(opt)\n    else\n        return _find_intel_on_linux(opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_ifortenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ifortenv.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- init ifort variables\nlocal ifortvars = {\"path\",\n                   \"lib\",\n                   \"libpath\",\n                   \"include\",\n                   \"DevEnvdir\",\n                   \"VSInstallDir\",\n                   \"VCInstallDir\",\n                   \"WindowsSdkDir\",\n                   \"WindowsLibPath\",\n                   \"WindowsSDKVersion\",\n                   \"WindowsSdkBinPath\",\n                   \"UniversalCRTSdkDir\",\n                   \"UCRTVersion\"}\n\n-- load ifortvars_bat environment variables\nfunction _load_ifortvars(ifortvars_bat, arch, opt)\n\n    -- make the genifortvars.bat\n    opt = opt or {}\n    local genifortvars_bat = os.tmpfile() .. \"_genifortvars.bat\"\n    local genifortvars_dat = os.tmpfile() .. \"_genifortvars.txt\"\n    local file = io.open(genifortvars_bat, \"w\")\n    file:print(\"@echo off\")\n    file:print(\"call \\\"%s\\\" -arch %s > nul\", ifortvars_bat, arch)\n    for idx, var in ipairs(ifortvars) do\n        file:print(\"echo \" .. var .. \" = %%\" .. var .. \"%% %s %s\", idx == 1 and \">\" or \">>\", genifortvars_dat)\n    end\n    file:close()\n\n    -- run genifortvars.bat\n    os.run(genifortvars_bat)\n\n    -- load all envirnoment variables\n    local variables = {}\n    for _, line in ipairs((io.readfile(genifortvars_dat) or \"\"):split(\"\\n\")) do\n        local p = line:find('=', 1, true)\n        if p then\n            local name = line:sub(1, p - 1):trim()\n            local value = line:sub(p + 1):trim()\n            variables[name] = value\n        end\n    end\n    if not variables.path then\n        return\n    end\n\n    -- remove some empty entries\n    for _, name in ipairs(ifortvars) do\n        if variables[name] and #variables[name]:trim() == 0 then\n            variables[name] = nil\n        end\n    end\n\n    -- fix bin path for ia32\n    if variables.path and arch == \"ia32\" then\n        variables.path = variables.path:gsub(\"windows\\\\bin\\\\intel64;\", \"windows\\\\bin\\\\intel64_ia32;\")\n    end\n\n    -- convert path/lib/include to PATH/LIB/INCLUDE\n    variables.PATH    = variables.path\n    variables.LIB     = variables.lib\n    variables.LIBPATH = variables.libpath\n    variables.INCLUDE = variables.include\n    variables.path    = nil\n    variables.lib     = nil\n    variables.include = nil\n    variables.libpath = nil\n    return variables\nend\n\n-- find intel fortran envirnoment on windows\nfunction _find_intel_on_windows(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find ifortvars_bat.bat\n    local paths = {\"$(env IFORT_COMPILER20)\"}\n    local ifortvars_bat = find_file(\"bin/ifortvars.bat\", paths)\n    -- look for setvars.bat which is new in 2021\n    if not ifortvars_bat then\n        -- find setvars.bat in intel oneapi toolkits rootdir\n        paths = {\"$(env ONEAPI_ROOT)\"}\n        ifortvars_bat = find_file(\"setvars.bat\", paths)\n    end\n    if not ifortvars_bat then\n        -- find setvars.bat use IFORT_COMPILER.*\n        paths = {\n            \"$(env IFORT_COMPILER21)\",\n            \"$(env IFORT_COMPILER22)\",\n            \"$(env IFORT_COMPILER23)\"\n        }\n        ifortvars_bat = find_file(\"../../../setvars.bat\", paths)\n        if not ifortvars_bat then\n            paths = {\n                \"$(env IFORT_COMPILER24)\"\n            }\n            ifortvars_bat = find_file(\"../../setvars.bat\", paths)\n        end\n    end\n\n    if ifortvars_bat then\n\n        -- load ifortvars_bat\n        local ifortvars_x86 = _load_ifortvars(ifortvars_bat, \"ia32\", opt)\n        local ifortvars_x64 = _load_ifortvars(ifortvars_bat, \"intel64\", opt)\n\n        -- save results\n        return {ifortvars_bat = ifortvars_bat, ifortvars = {x86 = ifortvars_x86, x64 = ifortvars_x64}}\n     end\nend\n\n-- find intel fortran envirnoment on linux\nfunction _find_intel_on_linux(opt)\n\n    local paths = {\"/opt/intel/bin\", \"/usr/local/bin\", \"/usr/bin\"}\n    local ifort = find_file(\"ifort\", paths)\n    if ifort then\n        local bindir = path.directory(ifort)\n        local sdkdir = path.directory(bindir)\n        return {sdkdir = sdkdir, bindir = bindir, libdir = path.join(sdkdir, \"lib\")}\n    end\n\n    -- find it from oneapi sdk directory\n    local oneapi_rootdirs = {\"~/intel/oneapi/compiler\", \"/opt/intel/oneapi/compiler\"}\n    local arch = os.arch() == \"x86_64\" and \"intel64\" or \"ia32\"\n    paths = {}\n    for _, rootdir in ipairs(oneapi_rootdirs) do\n        table.insert(paths, path.join(rootdir, \"*\", is_host(\"macosx\") and \"mac\" or \"linux\", \"bin\", arch))\n    end\n    if #paths > 0 then\n        local ifort = find_file(\"ifort\", paths)\n        if ifort then\n            local bindir = path.directory(ifort)\n            local sdkdir = path.directory(path.directory(bindir))\n            return {sdkdir = sdkdir, bindir = bindir, libdir = path.join(sdkdir, \"compiler\", \"lib\", arch)}\n        end\n    end\nend\n\n-- find intel fortran environment\nfunction main(opt)\n    if is_host(\"windows\") then\n        return _find_intel_on_windows(opt)\n    else\n        return _find_intel_on_linux(opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_ifxenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ifxenv.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- init ifx variables\nlocal ifxvars = {\"path\",\n                 \"lib\",\n                 \"libpath\",\n                 \"include\",\n                 \"DevEnvdir\",\n                 \"VSInstallDir\",\n                 \"VCInstallDir\",\n                 \"WindowsSdkDir\",\n                 \"WindowsLibPath\",\n                 \"WindowsSDKVersion\",\n                 \"WindowsSdkBinPath\",\n                 \"UniversalCRTSdkDir\",\n                 \"UCRTVersion\"}\n\n-- load ifxvars_bat environment variables\nfunction _load_ifxvars(ifxvars_bat, arch, opt)\n\n    -- make the genifxvars.bat\n    opt = opt or {}\n    local genifxvars_bat = os.tmpfile() .. \"_genifxvars.bat\"\n    local genifxvars_dat = os.tmpfile() .. \"_genifxvars.txt\"\n    local file = io.open(genifxvars_bat, \"w\")\n    file:print(\"@echo off\")\n    file:print(\"call \\\"%s\\\" -arch %s > nul\", ifxvars_bat, arch)\n    for idx, var in ipairs(ifxvars) do\n        file:print(\"echo \" .. var .. \" = %%\" .. var .. \"%% %s %s\", idx == 1 and \">\" or \">>\", genifxvars_dat)\n    end\n    file:close()\n\n    -- run genifxvars.bat\n    os.run(genifxvars_bat)\n\n    -- load all envirnoment variables\n    local variables = {}\n    for _, line in ipairs((io.readfile(genifxvars_dat) or \"\"):split(\"\\n\")) do\n        local p = line:find('=', 1, true)\n        if p then\n            local name = line:sub(1, p - 1):trim()\n            local value = line:sub(p + 1):trim()\n            variables[name] = value\n        end\n    end\n    if not variables.path then\n        return\n    end\n\n    -- remove some empty entries\n    for _, name in ipairs(ifxvars) do\n        if variables[name] and #variables[name]:trim() == 0 then\n            variables[name] = nil\n        end\n    end\n\n    -- fix bin path for ia32\n    if variables.path and arch == \"ia32\" then\n        variables.path = variables.path:gsub(\"windows\\\\bin\\\\intel64;\", \"windows\\\\bin\\\\intel64_ia32;\")\n    end\n\n    -- convert path/lib/include to PATH/LIB/INCLUDE\n    variables.PATH    = variables.path\n    variables.LIB     = variables.lib\n    variables.LIBPATH = variables.libpath\n    variables.INCLUDE = variables.include\n    variables.path    = nil\n    variables.lib     = nil\n    variables.include = nil\n    variables.libpath = nil\n    return variables\nend\n\n-- find intel llvm fortran envirnoment on windows\nfunction _find_intel_on_windows(opt)\n    opt = opt or {}\n\n    -- find ifxvars_bat.bat\n    local paths = {\"$(env ONEAPI_ROOT)\"}\n    local ifxvars_bat = find_file(\"setvars.bat\", paths)\n    if not ifxvars_bat then\n        paths = {}\n        local keys = winos.registry_keys(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\Intel\\\\Compilers\\\\Fortran\\\\**\")\n        for _, key in ipairs(keys) do\n            table.insert(paths, format(\"$(reg %s;ProductDir)\", key))\n        end\n        ifxvars_bat = find_file(\"../../setvars.bat\", paths)\n    end\n    if ifxvars_bat then\n        local ifxvars_x86 = _load_ifxvars(ifxvars_bat, \"ia32\", opt)\n        local ifxvars_x64 = _load_ifxvars(ifxvars_bat, \"intel64\", opt)\n        return {ifxvars_bat = ifxvars_bat, ifxvars = {x86 = ifxvars_x86, x64 = ifxvars_x64}}\n     end\nend\n\n-- find intel llvm fortran envirnoment on linux\nfunction _find_intel_on_linux(opt)\n\n    -- attempt to find the sdk directory\n    local oneapi_rootdirs = {\"~/intel/oneapi/compiler\", \"/opt/intel/oneapi/compiler\"}\n    paths = {}\n    for _, rootdir in ipairs(oneapi_rootdirs) do\n        table.insert(paths, path.join(rootdir, \"*\", is_host(\"macosx\") and \"mac\" or \"linux\", \"bin\"))\n        table.insert(paths, path.join(rootdir, \"*\", \"bin\"))\n    end\n    if #paths > 0 then\n        local ifx = find_file(\"ifx\", paths)\n        if ifx then\n            local bindir = path.directory(ifx)\n            local sdkdir = path.directory(path.directory(bindir))\n            return {sdkdir = sdkdir, bindir = bindir}\n        end\n    end\nend\n\n-- find intel fortran environment\nfunction main(opt)\n    if is_host(\"windows\") then\n        return _find_intel_on_windows(opt)\n    else\n        return _find_intel_on_linux(opt)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_masm32.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_masm32.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find masm32 directory\nfunction _find_sdkdir(sdkdir)\n    local paths = {}\n    if sdkdir then\n        table.insert(paths, path.join(sdkdir, \"bin\"))\n    else\n        for _, logical_drive in ipairs(winos.logical_drives()) do\n            table.insert(paths, path.join(logical_drive, \"masm32\", \"bin\"))\n        end\n    end\n    local bindir = find_path(\"ml.exe\", paths)\n    if bindir then\n        return path.directory(bindir)\n    end\nend\n\n-- find masm32 toolchains\nfunction _find_masm32(sdkdir)\n    sdkdir = _find_sdkdir(sdkdir)\n    if not sdkdir or not os.isdir(sdkdir) then\n        return\n    end\n    return {sdkdir = sdkdir, bindir = path.join(sdkdir, \"bin\"), includedir = path.join(sdkdir, \"include\"), libdir = path.join(sdkdir, \"lib\")}\nend\n\n-- find masm32 toolchains\n--\n-- @param sdkdir    the masm32 directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false}\n--\n-- @return          the masm32 toolchains. e.g. {sdkver = ..., sdkdir, sdkdir_armcc, sdkdir_armclang}\n--\n-- @code\n--\n-- local toolchains = find_masm32(\"~/masm32\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_masm32\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.masm32 and cacheinfo.masm32.sdkdir and os.isdir(cacheinfo.masm32.sdkdir) then\n        return cacheinfo.masm32\n    end\n\n    -- find masm32\n    local masm32 = _find_masm32(sdkdir or config.get(\"sdk\"))\n    if masm32 then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for masm32 directory ... ${color.success}%s\", masm32.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for masm32 directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.masm32 = masm32 or false\n    detectcache:set(key, cacheinfo)\n    return masm32\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_matlab.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      jacklin\n-- @file        find_matlab.lua\n--\n\n-- imports\nimport(\"detect.sdks.matlab\")\n\n-- find matlab sdk toolchains\n--\n-- @return          the matlab sdk toolchains. e.g. {sdkdir = ..., includedirs = ..., linkdirs = ..., .. }\n--\n-- @code\n--\n-- local toolchains = find_matlab(opt)\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local version = opt.require_version and tostring(opt.require_version) or nil\n    local result = {sdkdir = \"\", includedirs = {}, linkdirs = {}, links = {}}\n    if is_host(\"windows\") then\n        local matlabkey = \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\MathWorks\\\\MATLAB\"\n        local valuekeys = winos.registry_keys(matlabkey)\n        if #valuekeys == 0 then\n            return\n        end\n\n        local itemkey\n        if version == nil then\n            itemkey = valuekeys[1] .. \";MATLABROOT\"\n        else\n            local versionname = matlab.versions()[version]\n            if versionname ~= nil then\n                itemkey = matlabkey .. \"\\\\\" .. version .. \";MATLABROOT\"\n            else\n                local versionvalue = matlab.versions_names()[version:lower()]\n                if versionvalue ~= nil then\n                    itemkey = matlabkey .. \"\\\\\" .. versionvalue .. \";MATLABROOT\"\n                else\n                    print(\"allowed values are:\")\n                    for k, v in pairs(matlab.versions()) do\n                        print(\"    \", k, v)\n                    end\n                    raise(\"MATLAB Runtime version does not exist: \" .. version)\n                end\n            end\n        end\n\n        local sdkdir = try {function () return winos.registry_query(itemkey) end}\n        if not sdkdir then\n            return\n        end\n        result.sdkdir = sdkdir\n        result.includedirs = path.join(sdkdir, \"extern\", \"include\")\n        for _, value in ipairs(os.dirs(path.join(sdkdir, \"extern\", \"lib\", \"**\"))) do\n            local dirbasename = path.basename(value)\n            if not dirbasename:startswith(\"win\") then\n                result.linkdirs[dirbasename] = value\n            end\n        end\n        for _, value in pairs(result.linkdirs) do\n            local dirbasename = path.basename(value)\n            result.links[dirbasename] = {}\n            for _, filepath in ipairs(os.files(value..\"/*.lib\")) do\n                table.insert(result.links[dirbasename], path.basename(filepath))\n            end\n            result.links[dirbasename] = table.unique(result.links[dirbasename])\n        end\n    end\n    return result\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_matlab_runtime.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      WubiCookie\n-- @file        find_matlab_runtime.lua\n--\n\n-- imports\nimport(\"detect.sdks.matlab\")\n\n-- find matlab runtime sdk\n--\n-- @return          the matlab runtime sdk. e.g. {sdkdir = ..., includedirs = ..., linkdirs = ..., .. }\n--\n-- @code\n--\n-- local sdk = find_matlab_runtime(opt)\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local version = opt.require_version and tostring(opt.require_version) or nil\n    local result = {sdkdir = \"\", includedirs = {}, linkdirs = {}, links = {}, bindirs = {}}\n    if is_host(\"windows\") then\n        local matlabkey = \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\MathWorks\\\\MATLAB Runtime\"\n        local valuekeys = winos.registry_keys(matlabkey)\n        if #valuekeys == 0 then\n            return\n        end\n\n        local itemkey\n        local versionname\n        local versionvalue\n        if version == nil then\n            local splitvaluekeys = valuekeys[1]:split(\"\\\\\")\n            versionvalue = splitvaluekeys[#splitvaluekeys]\n            versionname = matlab.versions()[versionvalue]\n            itemkey = valuekeys[1] .. \";MATLABROOT\"\n        else\n            versionname = matlab.versions()[version]\n            if versionname ~= nil then\n                versionvalue = matlab.versions_names()[versionname:lower()]\n                itemkey = matlabkey .. \"\\\\\" .. version .. \";MATLABROOT\"\n            else\n                versionvalue = matlab.versions_names()[version:lower()]\n                versionname = matlab.versions()[versionvalue]\n                if versionvalue ~= nil then\n                    itemkey = matlabkey .. \"\\\\\" .. versionvalue .. \";MATLABROOT\"\n                else\n                    print(\"allowed values are:\")\n                    for k, v in pairs(matlab.versions()) do\n                        print(\"    \", k, v)\n                    end\n                    raise(\"MATLAB Runtime version does not exist: \" .. version)\n                end\n            end\n        end\n\n        local sdkdir = try {function () return winos.registry_query(itemkey) end}\n        if not sdkdir then\n            return\n        end\n        sdkdir = sdkdir .. \"\\\\v\" .. versionvalue:gsub(\"%.\", \"\")\n        result.sdkdir = sdkdir\n        result.includedirs = path.join(sdkdir, \"extern\", \"include\")\n        result.bindirs = {\n            path.join(sdkdir, \"bin\", \"win64\"),\n            path.join(sdkdir, \"runtime\", \"win64\"),\n        }\n        for _, value in ipairs(os.dirs(path.join(sdkdir, \"extern\", \"lib\", \"**\"))) do\n            local dirbasename = path.basename(value)\n            if not dirbasename:startswith(\"win\") then\n                result.linkdirs[dirbasename] = value\n            end\n        end\n        for _, value in pairs(result.linkdirs) do\n            local dirbasename = path.basename(value)\n            result.links[dirbasename] = {}\n            for _, filepath in ipairs(os.files(value..\"/*.lib\")) do\n                table.insert(result.links[dirbasename], path.basename(filepath))\n            end\n            result.links[dirbasename] = table.unique(result.links[dirbasename])\n        end\n    end\n    return result\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_mdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_mdk.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find MDK directory\nfunction _find_sdkdir(sdkdir)\n    local paths = {\n        \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Keil\\\\Products\\\\MDK;Path)\"\n    }\n    if sdkdir then\n        table.insert(paths, 1, sdkdir)\n    end\n    local result = find_path(\"armcc\", paths) or find_path(\"armclang\", paths)\n    if not result then\n        -- find it from some logical drives paths\n        paths = {}\n        for _, logical_drive in ipairs(winos.logical_drives()) do\n            table.insert(paths, path.join(logical_drive, \"Keil_v5\", \"ARM\"))\n        end\n        result = find_path(\"armcc\", paths) or find_path(\"armclang\", paths)\n    end\n    return result\nend\n\n-- find MDK toolchains\nfunction _find_mdk(sdkdir)\n\n    -- find mdk directory\n    sdkdir = _find_sdkdir(sdkdir)\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n    local result = {sdkdir = sdkdir}\n\n    -- get sdk version\n    local sdkver = winos.registry_query(\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Keil\\\\Products\\\\MDK;Version\")\n    if sdkver then\n        sdkver = semver.match(sdkver, 1, \"V%d+%.%d+\")\n        if sdkver then\n            result.sdkver = sdkver:rawstr()\n        end\n    end\n\n    -- armcc sdk directory\n    local sdkdir_armcc = path.join(sdkdir, \"armcc\")\n    if os.isdir(sdkdir_armcc) and os.isfile(path.join(sdkdir_armcc, \"bin\", \"armcc.exe\")) then\n        result.sdkdir_armcc = sdkdir_armcc\n    end\n\n    -- armclang sdk directory\n    local sdkdir_armclang = path.join(sdkdir, \"armclang\")\n    if os.isdir(sdkdir_armclang) and os.isfile(path.join(sdkdir_armclang, \"bin\", \"armclang.exe\")) then\n        result.sdkdir_armclang = sdkdir_armclang\n    end\n    return result\nend\n\n-- find MDK toolchains\n--\n-- @param sdkdir    the MDK directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false}\n--\n-- @return          the MDK toolchains. e.g. {sdkver = ..., sdkdir, sdkdir_armcc, sdkdir_armclang}\n--\n-- @code\n--\n-- local toolchains = find_mdk(\"~/mdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_mdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.mdk and cacheinfo.mdk.sdkdir and os.isdir(cacheinfo.mdk.sdkdir) then\n        return cacheinfo.mdk\n    end\n\n    -- find mdk\n    local mdk = _find_mdk(sdkdir or config.get(\"sdk\"))\n    if mdk then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for MDK directory ... ${color.success}%s\", mdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for MDK directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.mdk = mdk or false\n    detectcache:set(key, cacheinfo)\n    return mdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_mingw.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_mingw.lua\n--\n\n-- imports\nimport(\"lib.detect.find_path\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\n-- find mingw directory\nfunction _find_mingwdir(sdkdir, msystem)\n    if not sdkdir then\n        if is_host(\"macosx\", \"linux\") and os.isdir(\"/opt/llvm-mingw\") then\n            sdkdir = \"/opt/llvm-mingw\"\n        elseif is_host(\"macosx\") and os.isdir(\"/usr/local/opt/mingw-w64\") then\n            -- for macOS Intel\n            sdkdir = \"/usr/local/opt/mingw-w64\"\n        elseif is_host(\"macosx\") and os.isdir(\"/opt/homebrew/opt/mingw-w64\") then\n            -- for Apple Silicon\n            sdkdir = \"/opt/homebrew/opt/mingw-w64\"\n        elseif is_host(\"linux\") then\n            sdkdir = \"/usr\"\n        else\n            local mingw_prefix = is_subhost(\"msys\") and os.getenv(\"MINGW_PREFIX\") or os.getenv(\"LLVM_MINGW_DIR\") or os.getenv(\"LLVM_MINGW_ROOT\")\n            if mingw_prefix and os.isdir(mingw_prefix) then\n                sdkdir = mingw_prefix\n            end\n        end\n        -- attempt to get it from $PATH\n        -- @see https://github.com/xmake-io/xmake/issues/977\n        if not sdkdir then\n            local pathenv = os.getenv(\"PATH\")\n            if pathenv then\n                local buildhash_pattern = string.rep('%x', 32)\n                local match_pattern = \"[\\\\/]packages[\\\\/]%w[\\\\/].*mingw.*[\\\\/][^\\\\/]+[\\\\/]\" .. buildhash_pattern .. \"[\\\\/]bin\"\n                for _, p in ipairs(path.splitenv(pathenv)) do\n                    if (p:find(match_pattern) or p:find(string.ipattern(\"mingw[%w%-%_%+]*[\\\\/]bin\"))) and\n                        path.filename(p) == \"bin\" and os.isdir(p) then\n                        sdkdir = path.directory(p)\n                        break\n                    end\n                end\n            end\n        end\n    end\n\n    if is_subhost(\"msys\") and sdkdir and msystem and not sdkdir:find(msystem, 1, true) then\n        sdkdir = path.unix(path.join(path.directory(sdkdir), msystem))\n    end\n\n    -- attempt to find mingw directory from the qt sdk\n    local qt = config.get(\"qt\")\n    if not sdkdir and qt then\n        sdkdir = find_path(\"bin\", path.join(qt, \"Tools\", \"mingw*_\" .. (is_arch(\"x86_64\") and \"64\" or \"32\")))\n    end\n\n    -- get mingw directory\n    if sdkdir and os.isdir(sdkdir) then\n        return sdkdir\n    end\nend\n\n-- find the mingw toolchain\nfunction _find_mingw(sdkdir, opt)\n    opt = opt or {}\n    local bindir = opt.bindir\n    local cross = opt.cross\n    local msystem = opt.msystem\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- find mingw root directory\n    sdkdir = _find_mingwdir(sdkdir, msystem)\n    if not sdkdir then\n        return\n    end\n\n    -- select cross on macOS, e.g x86_64-w64-mingw32- or i686-w64-mingw32-\n    if not cross then\n        if arch == \"i386\" or arch == \"x86\" or arch == \"i686\" then\n            cross = \"i686-w64-mingw32-\"\n        elseif arch == \"arm64\" or arch == \"aarch64\" then\n            cross = \"aarch64-w64-mingw32-\" -- for llvm-mingw\n        elseif arch:startswith(\"arm\") then\n            cross = \"armv7-w64-mingw32-\"   -- for llvm-mingw\n        else\n            cross = \"x86_64-w64-mingw32-\"\n        end\n    end\n\n    -- find cross toolchain\n    local toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir, cross = cross})\n    if not toolchain then -- fallback, e.g. gcc.exe without cross\n        toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir})\n    end\n    if toolchain then\n        return {sdkdir = toolchain.sdkdir, bindir = toolchain.bindir, cross = toolchain.cross, msystem = msystem}\n    end\nend\n\n-- find mingw toolchains\n--\n-- @param sdkdir    the mingw directory\n-- @param opt       the argument options\n--                  e.g. {verbose = true, force = false, bindir = .., cross = ..., arch = ...}\n--\n-- @return          the mingw toolchains. e.g. {sdkdir = .., bindir = .., cross = ..}\n--\n-- @code\n--\n-- local toolchain = find_mingw(\"/xxx/android-mingw-r10e\")\n-- local toolchain = find_mingw(\"/xxx/android-mingw-r10e\", {force = true, verbose = true})\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_mingw\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.mingw and cacheinfo.mingw.sdkdir and os.isdir(cacheinfo.mingw.sdkdir)\n        and cacheinfo.mingw.msystem == opt.msystem then\n        return cacheinfo.mingw\n    end\n\n    -- find mingw\n    local mingw = _find_mingw(sdkdir or config.get(\"mingw\") or global.get(\"mingw\") or config.get(\"sdk\"), {\n        bindir = opt.bindir or config.get(\"bin\"),\n        cross = opt.cross or config.get(\"cross\"),\n        msystem = opt.msystem,\n        arch = opt.arch\n    })\n    if mingw and mingw.sdkdir then\n        config.set(\"mingw\", mingw.sdkdir, {force = true, readonly = true})\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Mingw SDK ... ${color.success}%s (%s)\", mingw.sdkdir, mingw.cross)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Mingw SDK ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.mingw = mingw or false\n    detectcache:set(key, cacheinfo)\n    return mingw\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_ndk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ndk.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_directory\")\n\n-- get triple\nfunction _get_triple(arch)\n    local triples =\n    {\n        [\"armv5te\"]     = \"arm-linux-androideabi\"   -- deprecated\n    ,   [\"armv7-a\"]     = \"arm-linux-androideabi\"   -- deprecated\n    ,   [\"armeabi\"]     = \"arm-linux-androideabi\"   -- removed in ndk r17\n    ,   [\"armeabi-v7a\"] = \"arm-linux-androideabi\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-linux-android\"\n    ,   [\"riscv64\"]     = \"riscv64-linux-android\"\n    ,   i386            = \"i686-linux-android\"      -- deprecated\n    ,   x86             = \"i686-linux-android\"\n    ,   x86_64          = \"x86_64-linux-android\"\n    ,   mips            = \"mips-linux-android\"      -- removed in ndk r17\n    ,   mips64          = \"mips64-linux-android\"    -- removed in ndk r17\n    }\n    return triples[arch]\nend\n\n-- find ndk directory\nfunction _find_ndkdir(sdkdir)\n\n    -- get ndk directory\n    if not sdkdir then\n        sdkdir = os.getenv(\"ANDROID_NDK_HOME\") or os.getenv(\"ANDROID_NDK_ROOT\")\n        if not sdkdir and config.get(\"android_sdk\") then\n            local ndkbundle = path.join(config.get(\"android_sdk\"), \"ndk-bundle\")\n            if os.isdir(ndkbundle) then\n                sdkdir = ndkbundle\n            end\n        end\n        if not sdkdir and is_host(\"macosx\") then\n            sdkdir = find_directory(\"NDK\", \"/Applications/AndroidNDK*.app/Contents\")\n            if not sdkdir then\n                sdkdir = find_directory(\"*\", \"~/Library/Android/sdk/ndk\")\n            end\n            if not sdkdir then\n                sdkdir = \"~/Library/Android/sdk/ndk-bundle\"\n            end\n        end\n    end\n\n    -- get ndk directory\n    if sdkdir and os.isdir(sdkdir) then\n        return path.translate(sdkdir)\n    end\nend\n\n-- find the sdk version of ndk\nfunction _find_ndk_sdkver(sdkdir, bindir, sysroot, arch)\n\n    -- uses llvm stl?\n    local use_llvm = false\n    local ndk_cxxstl = config.get(\"ndk_cxxstl\")\n    if ndk_cxxstl then\n        -- we uses c++_static/c++_shared instead of llvmstl_static/llvmstl_shared\n        if ndk_cxxstl:startswith(\"c++\") or ndk_cxxstl:startswith(\"llvmstl\") then\n            use_llvm = true\n        end\n    elseif bindir and bindir:find(\"llvm\", 1, true) then\n        use_llvm = true\n    end\n\n    -- get triple\n    local triple = _get_triple(arch)\n    assert(triple, \"no triple found for arch %s (wrong arch?)\", arch)\n\n    -- try to select the best compatible version\n    local sdkver = \"16\"\n    if use_llvm or arch == \"arm64-v8a\" or arch == \"riscv64\" then\n        sdkver = (arch == \"riscv64\") and \"35\" or \"21\"\n    end\n    if sysroot then\n        if os.isdir(path.join(sysroot, \"usr\", \"lib\", triple, sdkver)) then\n            return sdkver\n        end\n    end\n    if os.isdir(path.join(sdkdir, \"platforms\", \"android-\" .. sdkver)) then\n        return sdkver\n    end\n\n    -- find the max version\n    local sdkver_max = 0\n    local sdkver_dir_pattern\n    if sysroot and os.isdir(path.join(sysroot, \"usr\", \"lib\")) then\n        sdkver_dir_pattern = path.join(sysroot, \"usr\", \"lib\", triple, \"*\")\n    else\n        sdkver_dir_pattern = path.join(sdkdir, \"platforms\", \"android-*\")\n    end\n    for _, sdkdir in ipairs(os.dirs(sdkver_dir_pattern)) do\n\n        -- get version\n        local filename = path.filename(sdkdir)\n        local version, count = filename:gsub(\"android%-\", \"\")\n        if count > 0 then\n\n            -- get the max version\n            local sdkver_now = tonumber(version)\n            if sdkver_now > sdkver_max then\n                sdkver_max = sdkver_now\n            end\n        end\n    end\n\n    -- get the max sdk version\n    return sdkver_max > 0 and tostring(sdkver_max) or nil\nend\n\n-- find the toolchains version of ndk\nfunction _find_ndk_toolchains_ver(bindir)\n    return bindir:match(\"%-(%d*%.%d*)[/\\\\]\")\nend\n\n-- find sysroot directory\nfunction _find_ndk_sysroot(sdkdir)\n\n    -- get sysroot above ndk r22\n    -- @see https://github.com/android/ndk/wiki/Changelog-r22\n    local prebuilt = (is_host(\"macosx\") and \"darwin\" or os.host()) .. \"-x86_64\"\n    local sysroot_r22 = path.join(sdkdir, \"toolchains\", \"llvm\", \"prebuilt\", prebuilt, \"sysroot\")\n    if os.isdir(sysroot_r22) then\n        return sysroot_r22\n    end\n\n    -- get sysroot above ndk r14\n    -- @see https://android.googlesource.com/platform/ndk/+/master/docs/UnifiedHeaders.md\n    local sysroot_r14 = path.join(sdkdir, \"sysroot\")\n    if os.isdir(sysroot_r14) then\n        return sysroot_r14\n    end\nend\n\n-- find the ndk toolchain\nfunction _find_ndk(opt)\n    opt = opt or {}\n    local arch = opt.arch\n    local sdkdir = opt.sdkdir\n    local ndk_sdkver = opt.ndk_sdkver\n    local ndk_toolchains_ver = opt.ndk_toolchains_ver\n    local compiler = opt.compiler\n\n    -- find ndk root directory\n    sdkdir = _find_ndkdir(sdkdir)\n    if not sdkdir then\n        return\n    end\n\n    -- get cross\n    local crosses =\n    {\n        [\"armv5te\"]     = \"arm-linux-androideabi-\" -- deprecated\n    ,   [\"armv7-a\"]     = \"arm-linux-androideabi-\" -- deprecated\n    ,   [\"armeabi\"]     = \"arm-linux-androideabi-\" -- removed in ndk r17\n    ,   [\"armeabi-v7a\"] = \"arm-linux-androideabi-\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-linux-android-\"\n    ,   [\"riscv64\"]     = \"riscv64-linux-android-\"\n    ,   i386            = \"i686-linux-android-\"    -- deprecated\n    ,   x86             = \"i686-linux-android-\"\n    ,   x86_64          = \"x86_64-linux-android-\"\n    ,   mips            = \"mips-linux-android-\"    -- removed in ndk r17\n    ,   mips64          = \"mips64-linux-android-\"  -- removed in ndk r17\n    }\n    local cross = crosses[arch]\n\n    -- get gcc toolchain sub-directory\n    local gcc_toolchain_subdirs =\n    {\n        [\"armv5te\"]     = \"arm-linux-androideabi-*\"\n    ,   [\"armv7-a\"]     = \"arm-linux-androideabi-*\"\n    ,   [\"armeabi\"]     = \"arm-linux-androideabi-*\"\n    ,   [\"armeabi-v7a\"] = \"arm-linux-androideabi-*\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-linux-android-*\"\n    ,   [\"riscv64\"]     = \"riscv64-linux-android-*\"\n    ,   i386            = \"x86-*\"\n    ,   x86             = \"x86-*\"\n    ,   x86_64          = \"x86_64-*\"\n    ,   mips            = \"mipsel-linux-android-*\"\n    ,   mips64          = \"mips64el-linux-android-*\"\n    }\n    local gcc_toolchain_subdir = gcc_toolchain_subdirs[arch] or \"arm-linux-androideabi-*\"\n\n    -- find the binary directory\n    local llvm_toolchain\n    local prebuilt = (is_host(\"macosx\") and \"darwin\" or os.host()) .. \"-x86_64\"\n    local bindir = find_directory(\"bin\", path.join(sdkdir, \"toolchains\", \"llvm\", \"prebuilt\", prebuilt)) -- larger than ndk r16\n    if bindir and compiler ~= \"gcc\" then\n        llvm_toolchain = path.directory(bindir)\n    else\n        bindir = find_directory(\"bin\", path.join(sdkdir, \"toolchains\", gcc_toolchain_subdir, \"prebuilt\", \"*\"))\n    end\n    if not bindir then\n        return\n    end\n\n    -- find the gcc toolchain\n    local gcc_toolchain = find_directory(\"bin\", path.join(sdkdir, \"toolchains\", gcc_toolchain_subdir, \"prebuilt\", \"*\"))\n    if gcc_toolchain then\n        gcc_toolchain = path.directory(gcc_toolchain)\n    end\n\n    -- find the toolchains version\n    local toolchains_ver = ndk_toolchains_ver or _find_ndk_toolchains_ver(gcc_toolchain or bindir)\n\n    -- find sysroot directory\n    local sysroot = _find_ndk_sysroot(sdkdir)\n\n    -- find the sdk version\n    local sdkver = ndk_sdkver or _find_ndk_sdkver(sdkdir, bindir, sysroot, arch)\n\n    -- get ndk version, e.g. r16b, ..\n    local ndkver = nil\n    if sysroot then\n        local ndk_version_header = path.join(sysroot, \"usr/include/android/ndk-version.h\")\n        if os.isfile(ndk_version_header) then\n            local ndk_version_info = io.readfile(ndk_version_header)\n            if ndk_version_info then\n                ndk_version_info = ndk_version_info:match(\"#define __NDK_MAJOR__ (%d+)\")\n                if ndk_version_info then\n                    ndkver = tonumber(ndk_version_info)\n                end\n            end\n        end\n    end\n\n    return {ndkver = ndkver,\n            sdkdir = sdkdir,\n            bindir = bindir,\n            cross = cross,\n            sdkver = sdkver,\n            llvm_toolchain = llvm_toolchain, -- >= ndk r22\n            gcc_toolchain = gcc_toolchain,\n            toolchains_ver = toolchains_ver,\n            sysroot = sysroot}\nend\n\n-- find ndk toolchains\n--\n-- @param sdkdir    the ndk directory\n-- @param opt       the argument options\n--                  e.g. {arch = \"[armeabi|armeabi-v7a|arm64-v8a]\", verbose = true, force = false, sdkver = 19, toolchains_ver = \"4.9\"}\n--\n-- @return          the ndk toolchains. e.g. {bindir = .., cross = ..}\n--\n-- @code\n--\n-- local toolchain = find_ndk(\"/xxx/android-ndk-r10e\")\n-- local toolchain = find_ndk(\"/xxx/android-ndk-r10e\", {arch = \"arm64-v8a\"})\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_ndk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.ndk and cacheinfo.ndk.sdkdir and os.isdir(cacheinfo.ndk.sdkdir) then\n        return cacheinfo.ndk\n    end\n\n    -- get arch\n    local arch = opt.arch or config.get(\"arch\") or \"armeabi-v7a\"\n\n    -- find ndk\n    local ndk = _find_ndk({sdkdir = sdkdir or config.get(\"ndk\") or global.get(\"ndk\"),\n            arch = arch,\n            ndk_sdkver = opt.sdkver or config.get(\"ndk_sdkver\"),\n            ndk_toolchains_ver = opt.toolchains_ver or config.get(\"ndk_toolchains_ver\"),\n            compiler = opt.compiler})\n    if ndk and ndk.sdkdir then\n        config.set(\"ndk\", ndk.sdkdir, {force = true, readonly = true})\n        config.set(\"ndkver\", ndk.ndkver, {force = true, readonly = true})\n        config.set(\"ndk_sdkver\", ndk.sdkver, {force = true, readonly = true})\n        config.set(\"ndk_toolchains_ver\", ndk.toolchains_ver, {force = true, readonly = true})\n        if opt.verbose or option.get(\"verbose\") then\n            local extra = \"\"\n            if ndk.sdkver then\n                extra = \" (sdk: \" .. ndk.sdkver .. \")\"\n            end\n            cprint(\"checking for Android NDK ... ${color.success}%s%s\", ndk.sdkdir, extra)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Android NDK ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.ndk = ndk or false\n    detectcache:set(key, cacheinfo)\n    return ndk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_qt.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_qt.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\n\n-- find qt sdk directory\nfunction _find_sdkdir(sdkdir, sdkver)\n\n    -- append target sub-directory\n    local subdirs = {}\n    if is_plat(\"linux\") then\n        table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x86_64\") and \"gcc_64\" or \"gcc_32\", \"bin\"))\n        table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x86_64\") and \"clang_64\" or \"clang_32\", \"bin\"))\n    elseif is_plat(\"macosx\") then\n        table.insert(subdirs, path.join(sdkver or \"*\", \"macos\", \"bin\")) -- for Qt 6.2\n        table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x86_64\") and \"clang_64\" or \"clang_32\", \"bin\"))\n    elseif is_plat(\"iphoneos\") then\n        table.insert(subdirs, path.join(sdkver or \"*\", \"ios\", \"bin\"))\n    elseif is_plat(\"windows\") then\n        local vs = config.get(\"vs\")\n        if vs then\n            table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x64\") and \"msvc\" .. vs .. \"_64\" or \"msvc\" .. vs .. \"_32\", \"bin\"))\n            table.insert(subdirs, path.join(sdkver or \"*\", \"msvc\" .. vs, \"bin\"))\n        end\n        table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x64\") and \"msvc*_64\" or \"msvc*_32\", \"bin\"))\n        table.insert(subdirs, path.join(sdkver or \"*\", \"msvc*\", \"bin\"))\n    elseif is_plat(\"mingw\") then\n        table.insert(subdirs, path.join(sdkver or \"*\", is_arch(\"x86_64\") and \"mingw*_64\" or \"mingw*_32\", \"bin\"))\n    elseif is_plat(\"android\") then\n        local subdir\n        if is_arch(\"arm64-v8a\") then\n            subdir = \"android_arm64_v8a\"\n        elseif is_arch(\"armeabi-v7a\", \"armeabi\", \"armv7-a\", \"armv5te\") then -- armv7-a/armv5te are deprecated\n            subdir = \"android_armv7\"\n        elseif is_arch(\"x86\", \"i386\") then -- i386 is deprecated\n            subdir = \"android_x86\"\n        elseif is_arch(\"x86_64\") then\n            subdir = \"android_x86_64\"\n        end\n        if subdir then\n            table.insert(subdirs, path.join(sdkver or \"*\", subdir, \"bin\"))\n        end\n        table.insert(subdirs, path.join(sdkver or \"*\", \"android\", \"bin\"))\n    elseif is_plat(\"wasm\") then\n        table.insert(subdirs, path.join(sdkver or \"*\", \"wasm_*\", \"bin\"))\n    else\n        table.insert(subdirs, path.join(sdkver or \"*\", \"*\", \"bin\"))\n    end\n    table.insert(subdirs, path.join(\"*\", \"bin\"))\n    table.insert(subdirs, \"bin\")\n\n    -- init the search directories\n    local paths = {}\n    if sdkdir then\n        table.insert(paths, sdkdir)\n    end\n    if is_host(\"windows\") then\n\n        -- we find it from /mingw64 first\n        if is_subhost(\"msys\") then\n            local mingw_prefix = os.getenv(\"MINGW_PREFIX\")\n            if mingw_prefix and os.isdir(mingw_prefix) then\n                table.insert(paths, mingw_prefix)\n            end\n        end\n\n        -- add paths from registry\n        local regs =\n        {\n            \"HKEY_CLASSES_ROOT\\\\Applications\\\\QtProject.QtCreator.c\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CLASSES_ROOT\\\\Applications\\\\QtProject.QtCreator.cpp\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CLASSES_ROOT\\\\Applications\\\\QtProject.QtCreator.pro\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Classes\\\\Applications\\\\QtProject.QtCreator.c\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Classes\\\\Applications\\\\QtProject.QtCreator.cpp\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Classes\\\\Applications\\\\QtProject.QtCreator.pro\\\\shell\\\\Open\\\\Command\"\n        }\n        for _, reg in ipairs(regs) do\n            table.insert(paths, function ()\n                local value = val(\"reg \" .. reg)\n                if value then\n                    local p = value:find(\"\\\\Tools\\\\QtCreator\", 1, true)\n                    if p then\n                        return path.translate(value:sub(1, p - 1))\n                    end\n                end\n            end)\n        end\n\n        -- add root logical drive pates, e.g. C:/Qt/Qtx.x.x, D:/Qtx.x.x ..\n        for idx, drive in ipairs(winos.logical_drives()) do\n            if idx < 5 then\n                table.insert(paths, path.join(drive, \"Qt\", \"Qt*\"))\n            else\n                break\n            end\n        end\n    else\n        for _, dir in ipairs(os.dirs(\"~/Qt*\")) do\n            table.insert(paths, dir)\n        end\n    end\n\n    -- special case for android on windows, where qmake is a .bat from version 6.3\n    -- this case also applys to wasm\n    if is_host(\"windows\") and is_plat(\"android\", \"wasm\") then\n        local qmake = find_file(\"qmake.bat\", paths, {suffixes = subdirs})\n        if qmake then\n            return path.directory(path.directory(qmake)), qmake\n        end\n    end\n\n    -- attempt to find qmake\n    local qmake\n    if is_host(\"windows\") then\n        qmake = find_file(\"qmake.exe\", paths, {suffixes = subdirs})\n    else\n        -- @see https://github.com/xmake-io/xmake/issues/4881\n        if sdkver then\n            local major = sdkver:sub(1, 1)\n            local suffixes = {major, \"-\" .. major, \"-qt\" .. major, \"\"}\n            for _, suffix in ipairs(suffixes) do\n                qmake = find_file(\"qmake\" .. suffix, paths, {suffixes = subdirs})\n                if qmake then\n                    break\n                end\n            end\n        end\n        if not qmake then\n            qmake = find_file(\"qmake\", paths, {suffixes = subdirs})\n        end\n    end\n    if qmake then\n        return path.directory(path.directory(qmake)), qmake\n    end\nend\n\n-- find qmake\nfunction _find_qmake(sdkdir, sdkver)\n\n    -- we attempt to find qmake from qt sdkdir first\n    local sdkdir, qmakefile = _find_sdkdir(sdkdir, sdkver)\n    if qmakefile then\n        return qmakefile\n    end\n\n    -- try finding qmake with the specific version, e.g. /usr/bin/qmake6\n    -- https://github.com/xmake-io/xmake/pull/3555\n    local qmake\n    if sdkver then\n        sdkver = semver.try_parse(sdkver)\n        if sdkver then\n            local major = sdkver:major()\n            local suffixes = {major, \"-\" .. major, \"-qt\" .. major}\n            for _, suffix in ipairs(suffixes) do\n                local cachekey = \"qmake\" .. suffix\n                qmake = find_tool(\"qmake\", {program = cachekey, cachekey = cachekey, paths = sdkdir and path.join(sdkdir, \"bin\")})\n                if qmake then\n                    break\n                end\n            end\n        end\n    end\n\n    -- we need to find the default qmake in current system\n    -- maybe we only installed qmake6\n    if not qmake then\n        local suffixes = {\"\", \"6\", \"-6\", \"-qt6\", \"5\", \"-5\", \"-qt5\"}\n        for _, suffix in ipairs(suffixes) do\n            local cachekey = \"qmake\" .. suffix\n            qmake = find_tool(\"qmake\", {program = cachekey, cachekey = cachekey, paths = sdkdir and path.join(sdkdir, \"bin\")})\n            if qmake then\n                break\n            end\n        end\n    end\n    if qmake then\n        return qmake.program\n    end\nend\n\n-- get qt environment\nfunction _get_qtenvs(qmake, sdkdir)\n    local envs = {}\n    local results\n\n    -- Try with -qtconf first if sdkdir is provided\n    if sdkdir then\n        local conf_paths = {path.join(sdkdir, \"bin\", \"target_qt.conf\"), path.join(sdkdir, \"bin\", \"qt.conf\")}\n        for _, conf_path in ipairs(conf_paths) do\n            if os.isfile(conf_path) then\n                results = try {function () return os.iorunv(qmake, {\"-query\", \"-qtconf\", conf_path}) end}\n                break\n            end\n        end\n    end\n\n    -- Fallback to normal query if sdkdir is not specified or -qtconf not applicable\n    results = results or try {\n        function ()\n            return os.iorunv(qmake, {\"-query\"})\n        end,\n        catch {\n            function (errors)\n                if errors then\n                    dprint(tostring(errors))\n                end\n            end\n        }\n    }\n    if results then\n        for _, qtenv in ipairs(results:split('\\n', {plain = true})) do\n            local kv = qtenv:split(':', {plain = true, limit = 2}) -- @note set limit = 2 for supporting value with win-style path, e.g. `key:C:\\xxx`\n            if #kv == 2 then\n                envs[kv[1]] = kv[2]:trim()\n            end\n        end\n        return envs\n    end\nend\n\n-- Verify and correct the Qt SDK version for cross-compiling.\n-- qmake reports its own version (QT_VERSION), not the version specified in the SDK's configuration files.\nfunction _tryfix_sdkver_for_cross(sdkdir, sdkver)\n    local qconfig_path = sdkdir and path.join(sdkdir, \"mkspecs\", \"qconfig.pri\")\n    if not sdkver or not os.isfile(qconfig_path) then\n        return sdkver\n    end\n    -- Extract the actual SDK version from qconfig.pri\n    local qconfig = io.readfile(qconfig_path)\n    local actual_sdkver = qconfig and qconfig:match(\"QT_VERSION%s*=%s*(%S+)\") -- Expected format: QT_VERSION = x.y.z\n    if not actual_sdkver then\n        return sdkver\n    end\n    if sdkver ~= actual_sdkver then\n        wprint(\"Host Qt SDK version (%s) differs from Target Qt SDK version (%s). To prevent build issues, please ensure both use the same version.\", sdkver, actual_sdkver);\n    end\n    return actual_sdkver\nend\n\n-- find qt sdk toolchains\nfunction _find_qt(sdkdir, sdkver, sdkdir_host)\n\n    -- find qmake\n    local qmake = _find_qmake(sdkdir_host or sdkdir, sdkver)\n    if not qmake then\n        return\n    end\n\n    -- get qt environments\n    local located_sdkdir = sdkdir and _find_sdkdir(sdkdir, sdkver)\n    local qtenvs = _get_qtenvs(qmake, located_sdkdir or sdkdir)\n    if not qtenvs then\n        return\n    end\n\n    -- get qt toolchains\n    sdkdir = qtenvs.QT_INSTALL_PREFIX\n    local sdkver = _tryfix_sdkver_for_cross(sdkdir, qtenvs.QT_VERSION)\n    local bindir = qtenvs.QT_INSTALL_BINS\n    local libexecdir = qtenvs.QT_INSTALL_LIBEXECS\n    local qmldir = qtenvs.QT_INSTALL_QML\n    local libdir = qtenvs.QT_INSTALL_LIBS\n    local pluginsdir = qtenvs.QT_INSTALL_PLUGINS\n    local includedir = qtenvs.QT_INSTALL_HEADERS\n    local mkspecsdir = qtenvs.QMAKE_MKSPECS or path.join(qtenvs.QT_HOST_DATA, \"mkspecs\")\n    local mkspec = qtenvs.QMAKE_XSPEC or qtenvs.QMAKE_SPEC\n    -- for 6.2\n    local bindir_host = qtenvs.QT_HOST_BINS\n    if not bindir_host and libexecdir and is_plat(\"android\", \"iphoneos\") then\n        local rootdir = path.directory(path.directory(bindir))\n        if is_host(\"macosx\") then\n            bindir_host = path.join(rootdir, \"macos\", \"bin\")\n        else\n            -- TODO\n        end\n    end\n    local libexecdir_host = qtenvs.QT_HOST_LIBEXECS\n    if not libexecdir_host and libexecdir and is_plat(\"android\", \"iphoneos\") then\n        local rootdir = path.directory(path.directory(libexecdir))\n        if is_host(\"macosx\") then\n            libexecdir_host = path.join(rootdir, \"macos\", \"libexec\")\n        else\n            -- TODO\n        end\n    end\n\n    if sdkdir_host then\n        local located_sdkdir_host = _find_sdkdir(sdkdir_host, sdkver)\n        local qtenvs_host = _get_qtenvs(qmake, located_sdkdir_host or sdkdir_host)\n        if qtenvs_host then\n            bindir_host = qtenvs_host.QT_HOST_BINS or qtenvs_host.QT_INSTALL_BINS or bindir_host\n            libexecdir_host = qtenvs_host.QT_HOST_LIBEXECS or qtenvs_host.QT_INSTALL_LIBEXECS or libexecdir_host\n        end\n    end\n\n    return {sdkdir = sdkdir, bindir = bindir, bindir_host = bindir_host, libexecdir = libexecdir, libexecdir_host = libexecdir_host, libdir = libdir, includedir = includedir, qmldir = qmldir, pluginsdir = pluginsdir, mkspecsdir = mkspecsdir, mkspec = mkspec, sdkver = sdkver}\nend\n\n-- find qt sdk toolchains\n--\n-- @param sdkdir    the qt sdk directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false, version = \"5.9.1\"}\n--\n-- @return          the qt sdk toolchains. e.g. {sdkver = ..., sdkdir = ..., bindir = .., linkdirs = ..., includedirs = ..., .. }\n--\n-- @code\n--\n-- local toolchains = find_qt(\"~/Qt\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_qt\"\n    local cacheinfo = (sdkdir and detectcache:get2(key, sdkdir)) or detectcache:get(key) or {}\n    if not opt.force and cacheinfo.qt and cacheinfo.qt.sdkdir and os.isdir(cacheinfo.qt.sdkdir) then\n        return cacheinfo.qt\n    end\n\n    -- find qt\n    local sdkdir = sdkdir or config.get(\"qt\") or global.get(\"qt\") or config.get(\"sdk\")\n    local sdkver = opt.version or config.get(\"qt_sdkver\")\n    local sdkdir_host = opt.sdkdir_host or config.get(\"qt_host\") or global.get(\"qt_host\")\n    local qt = _find_qt(sdkdir, sdkver, sdkdir_host)\n    if qt then\n        config.set(\"qt\", qt.sdkdir, {force = true, readonly = true})\n        config.set(\"qt_sdkver\", qt.sdkver, {force = true, readonly = true})\n\n        if opt.verbose or option.get(\"verbose\") then\n            local extra = \"\"\n            if qt.sdkver then\n                extra = \" (\" .. qt.sdkver .. \")\"\n            end\n            cprint(\"checking for Qt SDK ... ${color.success}%s%s\", qt.sdkdir, extra)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for Qt SDK ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.qt = qt or false\n    if sdkdir then\n        detectcache:set2(key, sdkdir, cacheinfo)\n    else\n        detectcache:set(key, cacheinfo)\n    end\n    return qt\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_sdasstm8.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_sdasstm8.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find sdasstm8\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local sdasstm8 = find_sdasstm8()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n\n    -- add search paths\n    local paths  = {}\n    local bindir = get_config(\"bin\")\n    if bindir and os.isdir(bindir) then\n        table.insert(paths, bindir)\n    end\n    if is_host(\"windows\") then\n        table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\SDCC)\\\\bin\")\n    end\n    if #paths > 0 then\n        opt.paths = paths\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"sdasstm8\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_vcpkgdir.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vcpkgdir.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_tool\")\n\n-- find vcpkgdir\nfunction main()\n    local vcpkgdir = detectcache:get(\"detect.sdks.find_vcpkgdir\")\n    if vcpkgdir == nil then\n        if not vcpkgdir then\n            vcpkgdir = config.get(\"vcpkg\") or global.get(\"vcpkg\")\n            if vcpkgdir then\n                if os.isfile(vcpkgdir) then\n                    vcpkgdir = path.directory(vcpkgdir)\n                end\n            end\n        end\n        if not vcpkgdir then\n            vcpkgdir = os.getenv(\"VCPKG_ROOT\") or os.getenv(\"VCPKG_INSTALLATION_ROOT\")\n        end\n        if not vcpkgdir and is_host(\"macosx\", \"linux\") then\n            local brew = find_tool(\"brew\")\n            if brew then\n                dir = try\n                {\n                    function ()\n                        return os.iorunv(brew.program, {\"--prefix\", \"vcpkg\"})\n                    end\n                }\n            end\n            if dir then\n                dir = path.join(dir:trim(), \"libexec\")\n                if os.isdir(path.join(dir, \"installed\")) then\n                    vcpkgdir = dir\n                end\n            end\n        end\n        if not vcpkgdir and is_host(\"windows\") then\n            -- attempt to read path info after running `vcpkg integrate install`\n            local pathfile = \"~/../Local/vcpkg/vcpkg.path.txt\"\n            if os.isfile(pathfile) then\n                local dir = io.readfile(pathfile):trim()\n                if os.isdir(dir) then\n                    vcpkgdir = dir\n                end\n            end\n        end\n        detectcache:set(\"detect.sdks.find_vcpkgdir\", vcpkgdir or false)\n    end\n    return vcpkgdir or nil\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_vstudio.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vstudio.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_directory\")\nimport(\"core.cache.global_detectcache\")\n\n-- init vsvers\nlocal vsvers = {\n    [\"18.0\"] = \"2026\"\n,   [\"17.0\"] = \"2022\"\n,   [\"16.0\"] = \"2019\"\n,   [\"15.0\"] = \"2017\"\n,   [\"14.0\"] = \"2015\"\n,   [\"12.0\"] = \"2013\"\n,   [\"11.0\"] = \"2012\"\n,   [\"10.0\"] = \"2010\"\n,   [\"9.0\"]  = \"2008\"\n,   [\"8.0\"]  = \"2005\"\n,   [\"7.1\"]  = \"2003\"\n,   [\"7.0\"]  = \"7.0\"\n,   [\"6.0\"]  = \"6.0\"\n,   [\"5.0\"]  = \"5.0\"\n,   [\"4.2\"]  = \"4.2\"\n}\n\n-- init vsenvs\nlocal vsenvs = {\n    [\"18.0\"] = \"VS180COMNTOOLS\"\n,   [\"17.0\"] = \"VS170COMNTOOLS\"\n,   [\"16.0\"] = \"VS160COMNTOOLS\"\n,   [\"15.0\"] = \"VS150COMNTOOLS\"\n,   [\"14.0\"] = \"VS140COMNTOOLS\"\n,   [\"12.0\"] = \"VS120COMNTOOLS\"\n,   [\"11.0\"] = \"VS110COMNTOOLS\"\n,   [\"10.0\"] = \"VS100COMNTOOLS\"\n,   [\"9.0\"]  = \"VS90COMNTOOLS\"\n,   [\"8.0\"]  = \"VS80COMNTOOLS\"\n,   [\"7.1\"]  = \"VS71COMNTOOLS\"\n,   [\"7.0\"]  = \"VS70COMNTOOLS\"\n,   [\"6.0\"]  = \"VS60COMNTOOLS\"\n,   [\"5.0\"]  = \"VS50COMNTOOLS\"\n,   [\"4.2\"]  = \"VS42COMNTOOLS\"\n}\n\n-- the original environment variables\nlocal _env_orgs = {}\n\n-- get all known Visual Studio environment variables\nfunction get_vcvars()\n    local vcvars = {\n        \"PATH\",\n        \"LIB\",\n        \"LIBPATH\",\n        \"INCLUDE\",\n        \"DevEnvdir\",\n        \"VSInstallDir\",\n        \"VCInstallDir\",\n        \"WindowsSdkDir\",\n        \"WindowsLibPath\",\n        \"WindowsSDKVersion\",\n        \"WindowsSdkBinPath\",\n        \"WindowsSdkVerBinPath\",\n        \"ExtensionSdkDir\",\n        \"UniversalCRTSdkDir\",\n        \"UCRTVersion\",\n        \"VCToolsVersion\",\n        \"VCIDEInstallDir\",\n        \"VCToolsInstallDir\",\n        \"VCToolsRedistDir\",\n        \"VisualStudioVersion\",\n        \"VSCMD_VER\",\n        \"VSCMD_ARG_app_plat\",\n        \"VSCMD_ARG_HOST_ARCH\",\n        \"VSCMD_ARG_TGT_ARCH\"}\n\n    local realvcvars = vcvars\n    for _, v in pairs(vsenvs) do\n        table.insert(realvcvars, v)\n    end\n    return realvcvars\nend\n\nfunction find_build_tools(opt)\n    opt = opt or {}\n\n    local sdkdir = opt.sdkdir\n    if not sdkdir or not os.isdir(sdkdir) then\n        return\n    end\n\n    local variables = {}\n    local VCInstallDir = path.join(sdkdir, \"VC\")\n    local VCToolsVersion = opt.vs_toolset\n    if not VCToolsVersion or not os.isdir(path.join(VCInstallDir, \"Tools/MSVC\", VCToolsVersion)) then\n        -- https://github.com/xmake-io/xmake/issues/6159\n        local latest_toolset\n        for _, dir in ipairs(os.dirs(path.join(sdkdir, \"VC/Tools/MSVC/*\"))) do\n            local toolset = path.filename(dir)\n            if not latest_toolset or semver.compare(toolset, latest_toolset) > 0 then\n                latest_toolset = toolset\n            end\n        end\n        if latest_toolset then\n            VCToolsVersion = latest_toolset\n        else\n            return\n        end\n    end\n    variables.VCInstallDir = VCInstallDir\n    variables.VCToolsVersion = VCToolsVersion\n    variables.VCToolsInstallDir = path.join(VCInstallDir, \"Tools/MSVC\", VCToolsVersion)\n\n    local WindowsSDKVersion\n    local vs_sdkver = opt.vs_sdkver\n    if vs_sdkver and os.isdir(path.join(sdkdir, \"Windows Kits/10/Lib\", vs_sdkver)) then\n        WindowsSDKVersion = vs_sdkver\n    else\n        local dir = find_directory(\"10*\", path.join(sdkdir, \"Windows Kits/10/Lib\"))\n        if dir then\n            WindowsSDKVersion = path.filename(dir)\n        else\n            return\n        end\n    end\n    variables.WindowsSDKVersion = WindowsSDKVersion\n    variables.WindowsSdkDir = path.join(sdkdir, \"Windows Kits/10\")\n    variables.WindowsSdkBinPath = path.join(variables.WindowsSdkDir, \"bin\")\n    variables.WindowsSdkVerBinPath = path.join(variables.WindowsSdkBinPath, WindowsSDKVersion)\n    variables.ExtensionSdkDir = path.join(variables.WindowsSdkDir, \"ExtensionSdkDir\")\n    variables.UCRTVersion = WindowsSDKVersion\n    variables.UniversalCRTSdkDir = variables.WindowsSdkDir\n\n    local includedirs = {\n        path.join(variables.VCToolsInstallDir, \"include\"),\n        path.join(variables.VCToolsInstallDir, \"atlmfc\", \"include\"),\n        path.join(variables.WindowsSdkDir, \"Include\", WindowsSDKVersion, \"ucrt\"),\n        path.join(variables.WindowsSdkDir, \"Include\", WindowsSDKVersion, \"shared\"),\n        path.join(variables.WindowsSdkDir, \"Include\", WindowsSDKVersion, \"um\"),\n        path.join(variables.WindowsSdkDir, \"Include\", WindowsSDKVersion, \"winrt\"),\n        path.join(variables.WindowsSdkDir, \"Include\", WindowsSDKVersion, \"cppwinrt\"),\n    }\n\n    local linkdirs = {\n        path.join(variables.VCToolsInstallDir, \"lib\"),\n        path.join(variables.VCToolsInstallDir, \"atlmfc\", \"lib\"),\n        path.join(variables.WindowsSdkDir, \"Lib\", WindowsSDKVersion, \"ucrt\"),\n        path.join(variables.WindowsSdkDir, \"Lib\", WindowsSDKVersion, \"um\"),\n        path.join(variables.WindowsSdkDir, \"Lib\", WindowsSDKVersion, \"km\"),\n    }\n\n    local archs = {\n        \"x86\",\n        \"x64\",\n        \"arm\",\n        \"arm64\",\n    }\n\n    local vcvarsall = {}\n    for _, target_arch in ipairs(archs) do\n        local lib = {}\n        for _, lib_dir in ipairs(linkdirs) do\n            local dir = path.join(lib_dir, target_arch)\n            if os.isdir(dir) then\n                table.insert(lib, dir)\n            end\n        end\n\n        if #lib ~= 0 then\n            local vcvars = {\n                BUILD_TOOLS_ROOT = sdkdir,\n                VSInstallDir = sdkdir,\n\n                -- vs runs in a windows ctx, so the envsep is always \";\"\n                INCLUDE = path.joinenv(includedirs, ';'),\n                LIB = path.joinenv(lib, ';'),\n\n                VSCMD_ARG_HOST_ARCH = \"x64\",\n\n                VCInstallDir = variables.VCInstallDir,\n                VCToolsVersion = variables.VCToolsVersion,\n                VCToolsInstallDir = variables.VCToolsInstallDir,\n\n                WindowsSDKVersion = variables.WindowsSDKVersion,\n                WindowsSdkDir = variables.WindowsSdkDir,\n                WindowsSdkBinPath = variables.WindowsSdkBinPath,\n                WindowsSdkVerBinPath = variables.WindowsSdkVerBinPath,\n                ExtensionSdkDir = variables.ExtensionSdkDir,\n                UCRTVersion = variables.UCRTVersion,\n                UniversalCRTSdkDir = variables.UniversalCRTSdkDir,\n            }\n\n            local build_tools_bin = {}\n            local host_dir = \"Host\" .. vcvars.VSCMD_ARG_HOST_ARCH\n            if is_host(\"windows\") then\n                table.insert(build_tools_bin, path.join(vcvars.VCToolsInstallDir, \"bin\", host_dir, target_arch))\n                table.insert(build_tools_bin, path.join(vcvars.WindowsSdkDir, \"bin\", WindowsSDKVersion))\n                table.insert(build_tools_bin, path.join(vcvars.WindowsSdkDir, \"bin\", WindowsSDKVersion, \"ucrt\"))\n            elseif is_host(\"linux\") then\n                -- for msvc-wine\n                table.insert(build_tools_bin, path.join(sdkdir, \"bin\", target_arch))\n            end\n\n            vcvars.VSCMD_ARG_TGT_ARCH = target_arch\n            vcvars.BUILD_TOOLS_BIN = path.joinenv(build_tools_bin)\n\n            local PATH = build_tools_bin\n            table.join2(PATH, path.splitenv(os.getenv(\"PATH\")))\n            vcvars.PATH = path.joinenv(PATH)\n\n            vcvarsall[target_arch] = vcvars\n        end\n    end\n\n    return vcvarsall\nend\n\n-- load vcvarsall environment variables\nfunction _load_vcvarsall_impl(vcvarsall, vsver, arch, opt)\n    opt = opt or {}\n\n    -- is VsDevCmd.bat?\n    local is_vsdevcmd = path.basename(vcvarsall):lower() == \"vsdevcmd\"\n\n    -- make the genvcvars.bat\n    local genvcvars_bat = os.tmpfile() .. \"_genvcvars.bat\"\n    local file = io.open(genvcvars_bat, \"w\")\n    file:print(\"@echo off\")\n    -- @note we need to get utf8 output from cmd.exe\n    -- because some %PATH% and other envs maybe contains unicode characters\n\tif winos.version():gt(\"winxp\") then\n    \tfile:print(\"chcp 65001\")\n\tend\n    -- fix error caused by the new vsDevCmd.bat of vs2019\n    -- @see https://github.com/xmake-io/xmake/issues/549\n    if vsver and tonumber(vsver) >= 16 then\n        file:print(\"set VSCMD_SKIP_SENDTELEMETRY=yes\")\n    end\n    local host_arch = os.arch()\n    if is_vsdevcmd then\n        if vsver and tonumber(vsver) >= 16 then\n            if opt.toolset then\n                file:print(\"call \\\"%s\\\" -host_arch=%s -arch=%s -winsdk=%s -vcvars_ver=%s > nul\", vcvarsall, host_arch, arch, opt.sdkver or \"\", opt.toolset or \"\")\n            else\n                file:print(\"call \\\"%s\\\" -host_arch=%s -arch=%s -winsdk=%s > nul\", vcvarsall, host_arch, arch, opt.sdkver or \"\")\n            end\n        else\n            if opt.toolset then\n                file:print(\"call \\\"%s\\\" -arch=%s -winsdk=%s -vcvars_ver=%s > nul\", vcvarsall, arch, opt.sdkver or \"\", opt.toolset or \"\")\n            else\n                file:print(\"call \\\"%s\\\" -arch=%s -winsdk=%s > nul\", vcvarsall, arch, opt.sdkver or \"\")\n            end\n        end\n    else\n        -- @see https://github.com/xmake-io/xmake/issues/5077\n        if vsver and tonumber(vsver) >= 16 and host_arch ~= arch then\n            if host_arch == \"x64\" then\n                host_arch = \"amd64\"\n            end\n            arch = host_arch .. \"_\" .. arch\n        end\n        if opt.toolset then\n            file:print(\"call \\\"%s\\\" %s %s -vcvars_ver=%s > nul\", vcvarsall, arch, opt.sdkver or \"\", opt.toolset or \"\")\n        else\n            file:print(\"call \\\"%s\\\" %s %s > nul\", vcvarsall, arch, opt.sdkver or \"\")\n        end\n    end\n    for idx, var in ipairs(get_vcvars()) do\n        file:print(\"echo \" .. var .. \" = %%\" .. var .. \"%%\")\n    end\n    file:close()\n\n    -- run genvcvars.bat\n    local outdata, errdata = try {function () return os.iorun(genvcvars_bat) end}\n    if errdata and #errdata > 0 and option.get(\"verbose\") and option.get(\"diagnosis\") then\n        cprint(\"${color.warning}checkinfo: ${clear dim}get vcvars error: %s\", errdata)\n    end\n    if not outdata then\n        return\n    end\n\n    -- load all envirnoment variables\n    local variables = {}\n    for _, line in ipairs(outdata:split(\"\\n\")) do\n        local p = line:find('=', 1, true)\n        if p then\n            local name = line:sub(1, p - 1):trim()\n            if #name > 0 then\n                local value = line:sub(p + 1):trim()\n                if #value > 0 then\n                    variables[name] = value\n                end\n            end\n        end\n    end\n\n    -- check if the environment variables are truncated\n    _check_vcvarsall_env(variables)\n    if not variables.PATH then\n        return\n    end\n\n    -- fix WindowsSDKVersion\n    local WindowsSDKVersion = variables.WindowsSDKVersion\n    if WindowsSDKVersion then\n        WindowsSDKVersion = WindowsSDKVersion:gsub(\"\\\\\", \"\"):trim()\n        if WindowsSDKVersion ~= \"\" then\n            variables.WindowsSDKVersion = WindowsSDKVersion\n        end\n    else\n        -- sometimes the variable `WindowsSDKVersion` is not available\n        -- then parse it from `WindowsSdkBinPath`, such as: `C:\\\\Program Files (x86)\\\\Windows Kits\\\\8.1\\\\bin`\n        local WindowsSdkBinPath = variables.WindowsSdkBinPath\n        if WindowsSdkBinPath then\n            WindowsSDKVersion = string.match(WindowsSdkBinPath, \"\\\\(%d+%.%d+)\\\\bin$\")\n            if WindowsSDKVersion then\n                variables.WindowsSDKVersion = WindowsSDKVersion\n            end\n        end\n    end\n\n    -- fix UCRTVersion\n    --\n    -- @note vcvarsall.bat maybe detect error if install WDK and SDK at same time (multi-sdk version exists in include directory).\n    --\n    local UCRTVersion = variables.UCRTVersion\n    if UCRTVersion and WindowsSDKVersion and UCRTVersion ~= WindowsSDKVersion and WindowsSDKVersion ~= \"\" then\n        local lib = variables.LIB\n        if lib then\n            lib = lib:gsub(UCRTVersion, WindowsSDKVersion)\n            variables.LIB = lib\n        end\n        local include = variables.INCLUDE\n        if include then\n            include = include:gsub(UCRTVersion, WindowsSDKVersion)\n            variables.INCLUDE = include\n        end\n        UCRTVersion = WindowsSDKVersion\n        variables.UCRTVersion = UCRTVersion\n    end\n    return variables\nend\n\n-- strip toolset version, e.g. 14.16.27023 -> 14.16\nfunction _strip_toolset_ver(vs_toolset)\n    local version = semver.new(vs_toolset)\n    if version then\n        return version:major() .. \".\" .. version:minor()\n    end\n    return vs_toolset\nend\n\n-- check if the environment variables are truncated\n-- https://github.com/xmake-io/xmake/issues/7281\nfunction _check_vcvarsall_env(vars)\n    if not option.get(\"diagnosis\") then\n        return\n    end\n    local check_vars = {\"PATH\", \"INCLUDE\", \"LIB\", \"LIBPATH\"}\n    for _, name in ipairs(check_vars) do\n        local value_org = _env_orgs[name]\n        if value_org == nil then\n            local value_str = os.getenv(name)\n            if value_str then\n                _env_orgs[name] = path.splitenv(value_str)\n            else\n                _env_orgs[name] = false\n            end\n            value_org = _env_orgs[name]\n        end\n        local value_new = vars[name]\n        if value_org and value_new and #value_org > 0 then\n            local values_new = hashset.from(path.splitenv(value_new))\n            for _, p in ipairs(value_org) do\n                if not values_new:has(p) then\n                    if #p > 256 then\n                        p = p:sub(1, 256) .. \"...\"\n                    end\n                    wprint(\"%%%s%% is too long and truncated, msvc detection may fail, please clear some unused variables!\\n  > %s\", name, p)\n                    break\n                end\n            end\n        end\n    end\nend\n\nfunction _load_vcvarsall(vcvarsall, vsver, arch, opt)\n    opt = opt or {}\n    local vs_toolset = opt.toolset or opt.vcvars_ver\n    if vs_toolset then\n        opt.toolset = _strip_toolset_ver(vs_toolset)\n    end\n    local result = _load_vcvarsall_impl(vcvarsall, vsver, arch, opt)\n    if result and not vs_toolset then\n        -- if no vs toolset version is specified, we default to the latest version.\n        -- https://github.com/xmake-io/xmake/issues/6159\n        local latest_toolset\n        local VCToolsVersion = result.VCToolsVersion\n        local VCInstallDir = result.VCInstallDir\n        if VCToolsVersion and VCInstallDir then\n            for _, dir in ipairs(os.dirs(path.join(VCInstallDir, \"Tools/MSVC/*\"))) do\n                local toolset = path.filename(dir)\n                if not latest_toolset or semver.compare(toolset, latest_toolset) > 0 then\n                    latest_toolset = toolset\n                end\n            end\n        end\n        if latest_toolset and VCToolsVersion and semver.compare(latest_toolset, VCToolsVersion) > 0 then\n            opt.toolset = _strip_toolset_ver(latest_toolset)\n            result = _load_vcvarsall_impl(vcvarsall, vsver, arch, opt)\n        end\n    end\n    return result\nend\n\n-- find vstudio for msvc\nfunction _find_vstudio(opt)\n    opt = opt or {}\n\n    -- clear local cache of environment variables\n    _env_orgs = {}\n\n    -- find the single current MSVC/VS from environment variables\n    local VCInstallDir = os.getenv(\"VCInstallDir\")\n    if VCInstallDir and (VCInstallDir ~= \"\") then\n        local VisualStudioVersion = os.getenv(\"VisualStudioVersion\")\n        if not VisualStudioVersion or (VisualStudioVersion == \"\") then\n\n            -- heuristic for VisualStudioVersion value (early MSVC/VS versions don't set VisualStudioVersion)\n            local VSInstallDir = os.getenv(\"VSInstallDir\") or \"\"\n            VisualStudioVersion = VSInstallDir:match('(%d+[.]?%d*)\\\\?%s*$')\n            if not VisualStudioVersion then VisualStudioVersion = VCInstallDir:match('(%d+[.]?%d*)\\\\VC\\\\?%s*$') end\n            if not VisualStudioVersion then VisualStudioVersion = \"0\" end\n            if not VisualStudioVersion:match('[.]') then VisualStudioVersion = VisualStudioVersion .. '.0' end\n\n            -- find highest known version which is less than or equal to VisualStudioVersion\n            if not vsvers[VisualStudioVersion] then\n                local versions = {}\n                local count = 0\n                for k in pairs(vsvers) do\n                    table.insert(versions, tonumber(k))\n                    count = count + 1\n                end\n                table.sort(versions)\n                local i = 0\n                local v = tonumber(VisualStudioVersion)\n                while ((i < count) and (versions[i + 1] <= v)) do\n                    i = i + 1\n                end\n                VisualStudioVersion = versions[i] or \"0\"\n            end\n        end\n\n        -- find vcvarsall.bat or vcvars32.bat\n        local paths =\n        {\n            path.join(VCInstallDir, \"Auxiliary\", \"Build\"),\n            path.join(VCInstallDir, \"bin\"),\n            VCInstallDir\n        }\n        local vcvarsall = find_file(\"vcvarsall.bat\", paths) or find_file(\"vcvars32.bat\", paths)\n        if vcvarsall and os.isfile(vcvarsall) and vsvers[VisualStudioVersion] then\n\n            -- load vcvarsall\n            local vcvarsall_x86     = _load_vcvarsall(vcvarsall, VisualStudioVersion, \"x86\", opt)\n            local vcvarsall_x64     = _load_vcvarsall(vcvarsall, VisualStudioVersion, \"x64\", opt)\n            local vcvarsall_arm     = _load_vcvarsall(vcvarsall, VisualStudioVersion, \"arm\", opt)\n            local vcvarsall_arm64   = _load_vcvarsall(vcvarsall, VisualStudioVersion, \"arm64\", opt)\n            local vcvarsall_arm64ec = vcvarsall_arm64\n\n            -- save results\n            local results = {}\n            results[vsvers[VisualStudioVersion]] = {\n                version = VisualStudioVersion,\n                vcvarsall_bat = vcvarsall,\n                vcvarsall = {\n                    x86 = vcvarsall_x86,\n                    x64 = vcvarsall_x64,\n                    arm = vcvarsall_arm,\n                    arm64 = vcvarsall_arm64,\n                    arm64ec = vcvarsall_arm64ec\n                }\n            }\n            return results\n        end\n    end\n\n    -- find vswhere\n    local vswhere = find_tool(\"vswhere\")\n\n    -- sort vs versions\n    local order_vsvers = table.keys(vsvers)\n    table.sort(order_vsvers, function (a, b) return tonumber(a) > tonumber(b) end)\n\n    -- find vs2017 -> vs4.2\n    local results = {}\n    for _, version in ipairs(order_vsvers) do\n\n        -- find VC install path (and aux build path) using `vswhere` (for version >= 15.0)\n        -- * version > 15.0 eschews registry entries; but `vswhere` (included with version >= 15.2) can be used to find VC install path\n        -- ref: https://github.com/Microsoft/vswhere/blob/master/README.md @@ https://archive.is/mEmdu\n        local vswhere_VCAuxiliaryBuildDir = {}\n        local vswhere_Common7ToolsDir = {}\n        if (tonumber(version) >= 15) and vswhere then\n            local vswhere_vrange = format(\"%s,%s)\", version, (version + 1))\n            -- build tools: https://github.com/microsoft/vswhere/issues/22 @@ https://aka.ms/vs/workloads\n            local result = os.iorunv(vswhere.program, {\"-products\", \"*\", \"-prerelease\", \"-property\", \"installationpath\", \"-version\", vswhere_vrange})\n            if result then\n                for _, vc_path in ipairs(result:split(\"\\n\")) do\n                    table.insert(vswhere_VCAuxiliaryBuildDir, path.join(vc_path:trim(), \"VC\", \"Auxiliary\", \"Build\"))\n                    table.insert(vswhere_Common7ToolsDir, path.join(vc_path:trim(), \"Common7\", \"Tools\"))\n                end\n            end\n        end\n\n        -- init paths\n        local paths = {\n            format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\VC\", version),\n            format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\VC7\\\\bin\", version),\n            format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\VC\", version),\n            format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\VC\\\\Auxiliary\\\\Build\", version),\n            format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\VC\\\\Auxiliary\\\\Build\", version)\n        }\n        if vsenvs[version] then\n            table.insert(paths, format(\"$(env %s)\\\\..\\\\..\\\\VC\", vsenvs[version]))\n        end\n\n        if vswhere_VCAuxiliaryBuildDir then\n            for _, vc_path in ipairs(vswhere_VCAuxiliaryBuildDir) do\n                if os.isdir(vc_path) then\n                    table.insert(paths, 1, vc_path)\n                end\n            end\n        end\n        if version == \"6.0\" and os.arch() == \"x64\" then\n            table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\Microsoft\\\\DevStudio\\\\6.0\\\\Products\\\\Microsoft Visual C++;ProductDir)\\\\Bin\")\n            table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\Microsoft\\\\VisualStudio\\\\6.0\\\\Setup\\\\Microsoft Visual C++;ProductDir)\\\\Bin\")\n        end\n\n        -- find vcvarsall.bat, vcvars32.bat for vs7.1\n        local vcvarsall = find_file(\"vcvarsall.bat\", paths) or find_file(\"vcvars32.bat\", paths)\n        if not vcvarsall then\n            -- find vs from some logical drives paths\n            paths = {}\n            local logical_drives = winos.logical_drives()\n            -- we attempt to find vs from wdk directory\n            -- wdk: E:\\Program Files\\Windows Kits\\10\n            -- vcvarsall: E:\\Program Files\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Auxiliary\\Build\n            local wdk = config.get(\"wdk\")\n            if wdk and os.isdir(wdk) then\n                local p = wdk:find(\"Program Files\")\n                if p then\n                    table.insert(logical_drives, wdk:sub(1, p - 1))\n                end\n            end\n            for _, logical_drive in ipairs(logical_drives) do\n                if os.isdir(path.join(logical_drive, \"Program Files (x86)\")) then\n                    table.insert(paths, path.join(logical_drive, \"Program Files (x86)\", \"Microsoft Visual Studio\", vsvers[version], \"*\", \"VC\", \"Auxiliary\", \"Build\"))\n                    table.insert(paths, path.join(logical_drive, \"Program Files (x86)\", \"Microsoft Visual Studio \" .. version, \"VC\"))\n                end\n                table.insert(paths, path.join(logical_drive, \"Program Files\", \"Microsoft Visual Studio\", vsvers[version], \"*\", \"VC\", \"Auxiliary\", \"Build\"))\n                table.insert(paths, path.join(logical_drive, \"Program Files\", \"Microsoft Visual Studio \" .. version, \"VC\"))\n                if version == \"6.0\" then\n                    table.insert(paths, path.join(logical_drive, \"Program Files\", \"Microsoft Visual Studio\", \"VC98\", \"Bin\"))\n                    table.insert(paths, path.join(logical_drive, \"Program Files (x86)\", \"Microsoft Visual Studio\", \"VC98\", \"Bin\"))\n                end\n            end\n            vcvarsall = find_file(\"vcvarsall.bat\", paths) or find_file(\"vcvars32.bat\", paths)\n        end\n        if not vcvarsall then\n            local paths = {\n                format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\Common7\\\\Tools\", version),\n                format(\"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;%s)\\\\Common7\\\\Tools\", version)\n            }\n            if vswhere_Common7ToolsDir then\n                for _, vc_path in ipairs(vswhere_Common7ToolsDir) do\n                    if os.isdir(vc_path) then\n                        table.insert(paths, 1, vc_path)\n                    end\n                end\n            end\n            vcvarsall = find_file(\"VsDevCmd.bat\", paths)\n        end\n        if vcvarsall then\n\n            -- load vcvarsall\n            local vcvarsall_x86     = _load_vcvarsall(vcvarsall, version, \"x86\", opt)\n            local vcvarsall_x64     = _load_vcvarsall(vcvarsall, version, \"x64\", opt)\n            local vcvarsall_arm     = _load_vcvarsall(vcvarsall, version, \"arm\", opt)\n            local vcvarsall_arm64   = _load_vcvarsall(vcvarsall, version, \"arm64\", opt)\n            local vcvarsall_arm64ec = vcvarsall_arm64\n\n            -- save results\n            results[vsvers[version]] = {\n                version = version,\n                vcvarsall_bat = vcvarsall,\n                vcvarsall = {\n                    x86 = vcvarsall_x86,\n                    x64 = vcvarsall_x64,\n                    arm = vcvarsall_arm,\n                    arm64 = vcvarsall_arm64,\n                    arm64ec = vcvarsall_arm64ec\n                }\n            }\n        end\n    end\n    return results\nend\n\n-- get last mtime of msvc\n-- @see https://github.com/xmake-io/xmake/issues/3652\nfunction _get_last_mtime_of_msvc(msvc)\n    local mtime = -1\n    for arch, envs in pairs(msvc.vcvarsall) do\n        if envs.PATH then\n            local pathenv = path.splitenv(envs.PATH)\n            for _, dir in ipairs(pathenv) do\n                local cl = path.join(dir, \"cl.exe\")\n                if os.isfile(cl) then\n                    local t = os.mtime(cl)\n                    if t > mtime then\n                        mtime = t\n                    end\n                end\n            end\n        end\n        local winsdk = envs.WindowsSdkDir\n        if winsdk and os.isdir(winsdk) then\n            local t = os.mtime(winsdk)\n            if t > mtime then\n                mtime = t\n            end\n        end\n    end\n    return mtime\nend\n\n-- get last mtime of vstudio\nfunction _get_last_mtime(vstudio)\n    local mtime = -1\n    for _, msvc in pairs(vstudio) do\n        local vcvarsall_bat = msvc.vcvarsall_bat\n        if vcvarsall_bat and os.isfile(vcvarsall_bat) then\n            local t = os.mtime(vcvarsall_bat)\n            if t > mtime then\n                mtime = t\n            end\n            t = _get_last_mtime_of_msvc(msvc)\n            if t > mtime then\n                mtime = t\n            end\n        else\n            mtime = -1\n            break\n        end\n    end\n    return mtime\nend\n\nfunction _show_vstudio_diagnosis_result(vstudio)\n    local found = {}\n    for vsver, msvc in pairs(vstudio) do\n        if type(msvc) == \"table\" and msvc.version then\n            local toolset\n            local vcvarsall = msvc.vcvarsall\n            if type(vcvarsall) == \"table\" then\n                for _, envs in pairs(vcvarsall) do\n                    if type(envs) == \"table\" and envs.VCToolsVersion then\n                        toolset = _strip_toolset_ver(envs.VCToolsVersion)\n                        break\n                    end\n                end\n            end\n            if toolset then\n                table.insert(found, tostring(vsver) .. \"(\" .. tostring(msvc.version) .. \", toolset:\" .. tostring(toolset) .. \")\")\n            else\n                table.insert(found, tostring(vsver) .. \"(\" .. tostring(msvc.version) .. \")\")\n            end\n        else\n            table.insert(found, tostring(vsver))\n        end\n    end\n    table.sort(found, function (a, b) return a > b end)\n    cprint(\"${dim}detecting vstudio environment ... ${color.success}%s\", table.concat(found, \", \"))\nend\n\n-- find vstudio environment\n--\n-- @param opt   the options, e.g. {toolset = 14.0, sdkver = \"10.0.15063.0\"}\n--\n-- @return      { 2008 = {version = \"9.0\", vcvarsall = {x86 = {path = .., lib = .., include = ..}}}\n--              , 2017 = {version = \"15.0\", vcvarsall = {x64 = {path = .., lib = ..}}}}\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- only for windows\n    if not is_host(\"windows\") then\n        return\n    end\n\n    local key = \"vstudio\"\n    if opt.toolset then\n        key = key .. opt.toolset\n    end\n    if opt.sdkver then\n        key = key .. opt.sdkver\n    end\n\n    -- attempt to get it from the global cache first\n    local vstudio = global_detectcache:get2(key, \"msvc\")\n    if vstudio then\n        local mtime = _get_last_mtime(vstudio)\n        local mtimeprev = global_detectcache:get2(key, \"mtime\")\n        if mtime and mtimeprev and mtime > 0 and mtimeprev > 0 and mtime == mtimeprev then\n            return vstudio\n        end\n    end\n\n    -- find and cache result\n    cprint(\"${color.warning}Detecting Visual Studio environment (cached); run `xmake global --clean` first if vs updated.\")\n    vstudio = _find_vstudio(opt)\n    if vstudio then\n        local mtime = _get_last_mtime(vstudio)\n        global_detectcache:set2(key, \"msvc\", vstudio)\n        global_detectcache:set2(key, \"mtime\", mtime)\n        global_detectcache:save()\n    end\n    if option.get(\"diagnosis\") then\n        if vstudio and not table.empty(vstudio) then\n            _show_vstudio_diagnosis_result(vstudio)\n        else\n            cprint(\"${dim}detecting vstudio environment ...${color.failure}${text.failure}\")\n        end\n    end\n    return vstudio\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_vulkansdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_vulkansdk.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_library\")\nimport(\"lib.detect.find_programver\")\nimport(\"lib.detect.find_package\")\n\n-- find vulkan from paths\nfunction _find_vulkan_from_paths(paths, opt)\n    opt = opt or {}\n    local arch = opt.arch or config.arch() or os.arch()\n    local plat = opt.plat or config.plat() or os.host()\n    local binsuffix = ((is_host(\"windows\") and arch == \"x86\") and \"bin32\" or \"bin\")\n    local libname = (is_host(\"windows\") and \"vulkan-1\" or \"vulkan\")\n    local libsuffix = ((is_host(\"windows\") and arch == \"x86\") and \"lib32\" or \"lib\")\n\n    -- find library\n    local result = {links = {}, linkdirs = {}, includedirs = {}}\n    local linkinfo = find_library(libname, paths, {suffixes = {libsuffix}, plat = plat})\n    if linkinfo then\n        result.sdkdir = path.directory(linkinfo.linkdir)\n        result.bindir = path.join(result.sdkdir, binsuffix)\n        table.insert(result.linkdirs, linkinfo.linkdir)\n        table.insert(result.links, libname)\n    else\n        -- not found?\n        return\n    end\n\n    -- find headers\n    local incdir = find_path(path.join(\"vulkan\", \"vulkan.h\"), paths, {suffixes = {\"include\"}})\n    if incdir then\n        table.insert(result.includedirs, incdir)\n    else\n        -- not found?\n        return\n    end\n\n    -- find api version\n    local vkinfo\n    if is_host(\"windows\") then\n        if arch == \"x86\" then\n            vkinfo = find_file(\"vulkaninfoSDK.exe\", paths, {suffixes = {\"bin32\"}})\n        else\n            vkinfo = find_file(\"vulkaninfoSDK.exe\", paths, {suffixes = {\"bin\"}})\n        end\n    elseif is_host(\"linux\") then\n        vkinfo = find_file(\"vulkaninfo\", paths, {suffixes = {\"bin\"}})\n    end\n    if vkinfo then\n        local apiver = find_programver(vkinfo, {command = \"--summary\", parse = \"Vulkan Instance Version: (%d+%.%d+%.%d+)\"})\n        result.apiversion = apiver\n    end\n    return result\nend\n\n-- find vulkan from system\nfunction _find_vulkan_from_system(opt)\n    local result = find_package(\"pkgconfig::vulkan\", table.join({version = true}, opt))\n    if result then\n        result.apiversion = result.version\n        result.version = nil\n        if not result.apiversion then\n            local apiver = find_programver(\"vulkaninfo\", {command = \"--summary\", parse = \"Vulkan Instance Version: (%d+%.%d+%.%d+)\"})\n            result.apiversion = apiver\n        end\n    end\n    return result\nend\n\n-- find vulkansdk\n--\n-- @param opt   the package options. e.g. see the options of find_package()\n--\n-- @return      see the return value of find_package()\n--\nfunction main(opt)\n    local paths = {\n        \"$(env VK_SDK_PATH)\",\n        \"$(env VULKAN_SDK)\"\n    }\n    local result = _find_vulkan_from_paths(paths, opt)\n    if not result then\n        result = _find_vulkan_from_system(opt)\n    end\n    if not result and is_host(\"linux\") then\n        -- we attempt to find vulkan from /usr, e.g. /usr/include/vulkan/vulkan.h\n        paths = {\"/usr\", \"/usr/local\"}\n        result = _find_vulkan_from_paths(paths, opt)\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_wasisdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      vkensou\n-- @file        find_wasisdk.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_file\")\n\n-- find wasm-ld directory\nfunction _find_wasm_ld(sdkdir)\n    local subdirs = {}\n    table.insert(subdirs, \"bin\")\n\n    local paths = {}\n    if sdkdir then\n        table.insert(paths, sdkdir)\n    end\n    table.insert(paths, \"$(env WASI_SDK_PATH)\")\n\n    local wasm_ldname = (is_host(\"windows\") and \"wasm-ld.exe\" or \"wasm-ld\")\n    local wasm_ld = find_file(wasm_ldname, paths, {suffixes = subdirs})\n    if wasm_ld then\n        return path.directory(wasm_ld)\n    end\nend\n\n-- find wasi-sdk\nfunction _find_wasisdk(sdkdir)\n\n    -- find bin directory\n    local bindir = _find_wasm_ld(sdkdir)\n    if not bindir or path.filename(bindir) ~= \"bin\" then\n        return {}\n    end\n\n    -- find sdk root directory\n    sdkdir = path.directory(bindir)\n    if not sdkdir then\n        return {}\n    end\n\n    return {sdkdir = sdkdir, bindir = bindir}\nend\n\n-- find wasi-sdk directory\n--\n-- @param sdkdir    the wasi-sdk directory\n-- @param opt       the argument options, e.g. {force = true}\n--\n-- @return          the sdk toolchains. e.g. {sdkdir = ..}\n--\n-- @code\n--\n-- local sdk = find_wasisdk(\"~/wasi-sdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_wasisdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.sdk and cacheinfo.sdk.sdkdir and os.isdir(cacheinfo.sdk.sdkdir) then\n        return cacheinfo.sdk\n    end\n\n    -- find sdk\n    local sdk = _find_wasisdk(sdkdir)\n    if sdk and sdk.sdkdir and sdk.bindir then\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for wasi-sdk directory ... ${color.success}%s\", sdk.sdkdir)\n        end\n    else\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for wasi-sdk directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.sdk = sdk or false\n    detectcache:set(key, cacheinfo)\n    return sdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_wdk.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_wdk.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.detectcache\")\nimport(\"detect.sdks.find_vstudio\")\n\n-- find WDK directory\nfunction _find_sdkdir(sdkdir)\n\n    -- get sdk directory from the environment variables first\n    if not sdkdir then\n        sdkdir = os.getenv(\"WindowsSdkDir\")\n    end\n\n    -- get sdk directory from vcvars\n    if not sdkdir then\n        local msvc = toolchain.load(\"msvc\")\n        if msvc and msvc:check() then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars then\n                sdkdir = vcvars.WindowsSdkDir\n            end\n        end\n    end\n    return sdkdir\nend\n\n-- find umdf version\nfunction _find_umdfver(libdir, includedir)\n\n    -- find versions\n    local versions = {}\n    for _, p in ipairs(os.files(path.join(includedir, \"wdf\", \"umdf\", \"*\", \"wdf.h\"))) do\n        table.insert(versions, path.filename(path.directory(p)))\n    end\n\n    -- find version\n    local arch = config.arch() or os.arch()\n    if arch then\n        for _, ver in ipairs(versions) do\n            if os.isfile(path.join(libdir, \"wdf\", \"umdf\", arch, ver, \"WdfDriverStubUm.lib\")) then\n                return ver\n            end\n        end\n    end\nend\n\n-- find kmdf version\nfunction _find_kmdfver(libdir, includedir)\n\n    -- find versions\n    local versions = {}\n    for _, p in ipairs(os.files(path.join(includedir, \"wdf\", \"kmdf\", \"*\", \"wdf.h\"))) do\n        table.insert(versions, path.filename(path.directory(p)))\n    end\n\n    -- find version\n    local arch = config.arch() or os.arch()\n    if arch then\n        for _, ver in ipairs(versions) do\n            if os.isfile(path.join(libdir, \"wdf\", \"kmdf\", arch, ver, \"wdfdriverentry.lib\")) then\n                return ver\n            end\n        end\n    end\nend\n\n-- find WDK toolchains\nfunction _find_wdk(sdkdir, sdkver)\n\n    -- find wdk directory\n    sdkdir = _find_sdkdir(sdkdir)\n    if not sdkdir or not os.isdir(sdkdir) then\n        return nil\n    end\n\n    -- get sdk version\n    if not sdkver then\n        local vers = {}\n        for _, dir in ipairs(os.dirs(path.join(sdkdir, \"Include\", \"*\", \"km\"))) do\n            table.insert(vers, path.filename(path.directory(dir)))\n        end\n        for _, ver in ipairs(vers) do\n            if os.isdir(path.join(sdkdir, \"Lib\", ver, \"km\")) and os.isdir(path.join(sdkdir, \"Lib\", ver, \"um\")) and os.isdir(path.join(sdkdir, \"Include\", ver, \"um\"))  then\n                sdkver = ver\n                break\n            end\n        end\n    end\n    if not sdkver then\n        return nil\n    end\n\n    -- get the bin directory\n    local bindir = path.join(sdkdir, \"bin\")\n\n    -- get the lib directory\n    local libdir = path.join(sdkdir, \"Lib\")\n\n    -- get the include directory\n    local includedir = path.join(sdkdir, \"Include\")\n\n    -- get umdf version\n    local umdfver = _find_umdfver(libdir, includedir)\n\n    -- get kmdf version\n    local kmdfver = _find_kmdfver(libdir, includedir)\n\n    -- get toolchains\n    return {sdkdir = sdkdir, bindir = bindir, libdir = libdir, includedir = includedir, sdkver = sdkver, umdfver = umdfver, kmdfver = kmdfver}\nend\n\n-- find WDK toolchains\n--\n-- @param sdkdir    the WDK directory\n-- @param opt       the argument options, e.g. {verbose = true, force = false, version = \"5.9.1\"}\n--\n-- @return          the WDK toolchains. e.g. {sdkver = ..., sdkdir = ..., bindir = .., libdir = ..., includedir = ..., .. }\n--\n-- @code\n--\n-- local toolchains = find_wdk(\"~/wdk\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_wdk\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.wdk and cacheinfo.wdk.sdkdir and os.isdir(cacheinfo.wdk.sdkdir) then\n        return cacheinfo.wdk\n    end\n\n    -- find wdk\n    local wdk = _find_wdk(sdkdir or config.get(\"wdk\") or global.get(\"wdk\") or config.get(\"sdk\"), opt.version or config.get(\"wdk_sdkver\"))\n    if wdk then\n\n        -- save to config\n        config.set(\"wdk\", wdk.sdkdir, {force = true, readonly = true})\n        config.set(\"wdk_sdkver\", wdk.sdkver, {force = true, readonly = true})\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for WDK directory ... ${color.success}%s\", wdk.sdkdir)\n            cprint(\"checking for WDK version ... ${color.success}%s\", wdk.sdkver)\n        end\n    else\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            cprint(\"checking for WDK directory ... ${color.nothing}${text.nothing}\")\n        end\n    end\n\n    -- save to cache\n    cacheinfo.wdk = wdk or false\n    detectcache:set(key, cacheinfo)\n    return wdk\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/find_xcode.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_xcode.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_directory\")\nimport(\"private.tools.codesign\")\n\n-- find xcode directory\nfunction _find_sdkdir(sdkdir, opt)\n    if sdkdir and os.isdir(sdkdir) then\n        return sdkdir\n    end\n    return find_directory(\"Xcode.app\", {\"/Applications\"}) or find_directory(\"Xcode*.app\", {\"/Applications\"})\nend\n\n-- find the sdk version of xcode\nfunction _find_xcode_sdkver(sdkdir, opt)\n\n    -- select platform sdkdir\n    local plat = opt.plat\n    local arch = opt.arch\n    local platsdkdir = nil\n    if plat == \"iphoneos\" then\n        if arch == \"i386\" or arch == \"x86_64\" then\n            platsdkdir = \"Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator*.*.sdk\"\n        else\n            platsdkdir = \"Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.*.sdk\"\n        end\n    elseif plat == \"watchos\" then\n        if arch == \"i386\" or arch == \"x86_64\" then\n            platsdkdir = \"Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator*.*.sdk\"\n        else\n            platsdkdir = \"Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS*.*.sdk\"\n        end\n    elseif plat == \"appletvos\" then\n        if arch == \"i386\" or arch == \"x86_64\" then\n            platsdkdir = \"Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator*.*.sdk\"\n        else\n            platsdkdir = \"Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS*.*.sdk\"\n        end\n    elseif plat == \"applexros\" then\n        if arch == \"i386\" or arch == \"x86_64\" then\n            platsdkdir = \"Contents/Developer/Platforms/XRSimulator.platform/Developer/SDKs/XRSimulator*.*.sdk\"\n        else\n            platsdkdir = \"Contents/Developer/Platforms/XROS.platform/Developer/SDKs/XROS*.*.sdk\"\n        end\n    else\n        platsdkdir = \"Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.*.sdk\"\n    end\n\n    -- attempt to find the platform directory and get sdk version\n    if platsdkdir then\n\t    local dir = find_directory(platsdkdir, sdkdir)\n        if dir then\n            local basename = path.basename(dir)\n            return basename:match(\"%d+%.%d+\")\n        end\n    end\nend\n\n-- find the target minver\nfunction _find_target_minver(sdkdir, sdkver, opt)\n    opt = opt or {}\n    local target_minver = sdkver\n    if opt.plat == \"macosx\" then\n        if opt.appledev == \"catalyst\" then\n            local platsdkdir = \"Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.*.sdk\"\n            local dir = find_directory(platsdkdir, sdkdir)\n            if dir then\n                local basename = path.basename(dir)\n                target_minver = basename:match(\"%d+%.%d+\")\n            else\n                target_minver = \"13.1\"\n            end\n        else\n            local macos_ver = macos.version()\n            if macos_ver and (not sdkver or macos_ver:le(sdkver)) then\n                target_minver = macos_ver:major() .. \".\" .. macos_ver:minor()\n            end\n        end\n    end\n    return target_minver\nend\n\n-- find the xcode toolchain\nfunction _find_xcode(sdkdir, opt)\n\n    -- find xcode root directory\n    sdkdir = _find_sdkdir(sdkdir, opt)\n    if not sdkdir then\n        return {}\n    end\n\n    -- find the sdk version\n    local sdkver = opt.sdkver or _find_xcode_sdkver(sdkdir, opt)\n    if not sdkver then\n        return {}\n    end\n\n    -- find the target minver\n    local target_minver = _find_target_minver(sdkdir, sdkver, opt)\n    return {sdkdir = sdkdir, sdkver = sdkver, target_minver = target_minver}\nend\n\n-- find xcode toolchain\n--\n-- @param sdkdir    the xcode directory\n-- @param opt       the argument options\n--                  e.g. {verbose = true, force = false, sdkver = 19, find_codesign = true}\n--\n-- @return          the xcode toolchain. e.g. {bindir = .., cross = ..}\n--\n-- @code\n--\n-- local toolchain = find_xcode(\"/Applications/Xcode.app\")\n--\n-- @endcode\n--\nfunction main(sdkdir, opt)\n\n    -- init arguments\n    opt = opt or {}\n\n    -- attempt to load cache first\n    local key = \"detect.sdks.find_xcode\"\n    local cacheinfo = detectcache:get(key) or {}\n    if not opt.force and cacheinfo.xcode and cacheinfo.xcode.sdkdir and os.isdir(cacheinfo.xcode.sdkdir) then\n        return cacheinfo.xcode\n    end\n\n    -- get plat and arch\n    local plat = opt.plat or config.get(\"plat\") or os.host()\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- find xcode\n    local xcode = _find_xcode(sdkdir or config.get(\"xcode\") or global.get(\"xcode\"), opt)\n\n    -- save to cache\n    cacheinfo.xcode = xcode or false\n    detectcache:set(key, cacheinfo)\n    return xcode\nend\n"
  },
  {
    "path": "xmake/modules/detect/sdks/matlab.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      WubiCookie\n-- @file        matlab.lua\n--\n\n-- get matlab versions\nfunction versions()\n\n    -- see https://www.mathworks.com/products/compiler/matlab-runtime.html\n    return\n    {\n        [\"9.12\"]  = \"R2022a\"\n    ,   [\"9.11\"]  = \"R2021b\"\n    ,   [\"9.10\"]  = \"R2021a\"\n    ,   [\"9.9\"]   = \"R2020b\"\n    ,   [\"9.8\"]   = \"R2020a\"\n    ,   [\"9.7\"]   = \"R2019b\"\n    ,   [\"9.6\"]   = \"R2019a\"\n    ,   [\"9.5\"]   = \"R2018b\"\n    ,   [\"9.4\"]   = \"R2018a\"\n    ,   [\"9.3\"]   = \"R2017b\"\n    ,   [\"9.2\"]   = \"R2017a\"\n    ,   [\"9.1\"]   = \"R2016b\"\n    ,   [\"9.0.1\"] = \"R2016a\"\n    ,   [\"9.0\"]   = \"R2015b\"\n    ,   [\"8.5.1\"] = \"R2015aSP1\"\n    ,   [\"8.5\"]   = \"R2015a\"\n    ,   [\"8.4\"]   = \"R2014b\"\n    ,   [\"8.3\"]   = \"R2014a\"\n    ,   [\"8.2\"]   = \"R2013b\"\n    ,   [\"8.1\"]   = \"R2013a\"\n    ,   [\"8.0\"]   = \"R2012b\"\n    ,   [\"7.17\"]  = \"R2012a\"\n    }\nend\n\n-- get matlab versions names\nfunction versions_names()\n\n    return\n    {\n        r2022a    = \"9.12\"\n    ,   r2021b    = \"9.11\"\n    ,   r2021a    = \"9.10\"\n    ,   r2020b    = \"9.9\"\n    ,   r2020a    = \"9.8\"\n    ,   r2019b    = \"9.7\"\n    ,   r2019a    = \"9.6\"\n    ,   r2018b    = \"9.5\"\n    ,   r2018a    = \"9.4\"\n    ,   r2017b    = \"9.3\"\n    ,   r2017a    = \"9.2\"\n    ,   r2016b    = \"9.1\"\n    ,   r2016a    = \"9.0.1\"\n    ,   r2015b    = \"9.0\"\n    ,   r2015asp1 = \"8.5.1\"\n    ,   r2015a    = \"8.5\"\n    ,   r2014b    = \"8.4\"\n    ,   r2014a    = \"8.3\"\n    ,   r2013b    = \"8.2\"\n    ,   r2013a    = \"8.1\"\n    ,   r2012b    = \"8.0\"\n    ,   r2012a    = \"7.17\"\n    }\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_7z.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_7z.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find 7z\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local 7z = find_7z()\n-- local 7z, version = find_7z({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"--help\"\n    opt.command = opt.command or \"--help\"\n    opt.parse   = \"(%d+%.?%d*)%s\"\n\n    -- find 7z from builtin xmake/winenv\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        table.insert(opt.paths, path.join(os.programdir(), \"winenv\", \"bin\"))\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"7z\", opt)\n    if not program and not opt.program then\n        program = find_program(\"7za\", opt)\n    end\n\n    -- find it from msys/mingw, it is only a shell script\n    if not program and is_subhost(\"msys\") then\n        program = find_program(\"sh 7z\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_appimagetool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_appimagetool.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find appimagetool\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local appimagetool = find_appimagetool()\n-- local appimagetool, version = find_appimagetool({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- only for linux\n    if not is_host(\"linux\") then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n    opt.envs = opt.envs or {}\n    opt.envs.APPIMAGE_EXTRACT_AND_RUN = \"1\"\n\n    -- find program\n    local program = find_program(opt.program or \"appimagetool\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_apt.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_apt.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find apt\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local apt = find_apt()\n-- local apt, version = find_apt({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"apt\", opt)\n    if not program and not opt.program then\n        program = find_program(\"apt-get\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_aqt.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_aqt.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find aqt\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local aqt = find_aqt()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.check = opt.check or \"version\"\n\n    -- find program\n    local program = find_program(opt.program or \"aqt\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or function () local _, info = os.iorunv(program, {\"version\"}, {envs = opt.envs}); return info end\n        opt.parse   = opt.parse or \"aqt%S*%s+v*(%S+)\"\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- check\nfunction _check(program)\n\n    -- make a stub object file\n    local libraryfile = os.tmpfile() .. \".a\"\n    local objectfile  = os.tmpfile() .. \".o\"\n    io.writefile(objectfile, \"\")\n\n    -- archive it\n    os.runv(program, {\"-cr\", libraryfile, objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(libraryfile)\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ar()\n-- local ar, version = find_ar({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = opt.check or _check\n    opt.norunfile = true\n    return find_program(opt.program or \"ar\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ar2000.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ar2000.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- check\nfunction _check(program)\n\n    -- make a stub object file\n    local libraryfile = os.tmpfile() .. \".a\"\n    local objectfile  = os.tmpfile() .. \".o\"\n    io.writefile(objectfile, \"\")\n\n    -- archive it\n    os.execv(program, {\"-r\", libraryfile, objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(libraryfile)\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ar2000()\n-- local ar, version = find_ar2000({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt       = opt or {}\n    opt.check = opt.check or _check\n    return find_program(opt.program or \"ar2000\", opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ar6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ar6x.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- check\nfunction _check(program)\n\n    -- make a stub object file\n    local libraryfile = os.tmpfile() .. \".a\"\n    local objectfile  = os.tmpfile() .. \".o\"\n    io.writefile(objectfile, \"\")\n\n    -- archive it\n    os.execv(program, {\"-r\", libraryfile, objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(libraryfile)\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ar6x()\n-- local ar, version = find_ar6x({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt       = opt or {}\n    opt.check = opt.check or _check\n    return find_program(opt.program or \"ar6x\", opt)\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armar = find_armar()\n-- local armar, version = find_armar({program = \"armar\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armar.exe\", opt)\n    if not program then\n        local mdk = find_mdk()\n        if mdk then\n            if mdk.sdkdir_armcc then\n                program = find_program(path.join(mdk.sdkdir_armcc, \"bin\", \"armar.exe\"), opt)\n            end\n            if not program and mdk.sdkdir_armclang then\n                program = find_program(path.join(mdk.sdkdir_armclang, \"bin\", \"armar.exe\"), opt)\n            end\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armasm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armasm = find_armasm()\n-- local armasm, version = find_armasm({program = \"armasm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armasm.exe\", opt)\n    if not program then\n        local mdk = find_mdk()\n        if mdk then\n            if mdk.sdkdir_armcc then\n                program = find_program(path.join(mdk.sdkdir_armcc, \"bin\", \"armasm.exe\"), opt)\n            end\n            if not program and mdk.sdkdir_armclang then\n                program = find_program(path.join(mdk.sdkdir_armclang, \"bin\", \"armasm.exe\"), opt)\n            end\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armasm64_msvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armasm64_msvc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armasm = find_armasm64_msvc()\n-- local armasm, version = find_armasm64_msvc({program = \"armasm64\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armasm64.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armasm_msvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armasm_msvc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armasm = find_armasm_msvc()\n-- local armasm, version = find_armasm_msvc({program = \"armasm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armasm.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armcc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armcc = find_armcc()\n-- local armcc, version = find_armcc({program = \"armcc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armcc.exe\", opt)\n    if not program then\n        local mdk = find_mdk()\n        if mdk and mdk.sdkdir_armcc then\n            program = find_program(path.join(mdk.sdkdir_armcc, \"bin\", \"armcc.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armclang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armclang.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armclang\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armclang = find_armclang()\n-- local armclang, version = find_armclang({program = \"armclang\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.parse   = opt.parse or function (output) return output:match(\"Arm Compiler for Embedded (%d+%.?%d+%.?%d+)%s\") end\n\n    -- find program\n    local program = find_program(opt.program or \"armclang.exe\", opt)\n    if not program then\n        local mdk = find_mdk()\n        if mdk and mdk.sdkdir_armclang then\n            program = find_program(path.join(mdk.sdkdir_armclang, \"bin\", \"armclang.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_armlink.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_armlink.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_mdk\")\n\n-- find armlink\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local armlink = find_armlink()\n-- local armlink, version = find_armlink({program = \"armlink\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"armlink.exe\", opt)\n    if not program then\n        local mdk = find_mdk()\n        if mdk then\n            if mdk.sdkdir_armcc then\n                program = find_program(path.join(mdk.sdkdir_armcc, \"bin\", \"armlink.exe\"), opt)\n            end\n            if not program and mdk.sdkdir_armclang then\n                program = find_program(path.join(mdk.sdkdir_armclang, \"bin\", \"armlink.exe\"), opt)\n            end\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_asm6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_asm6x.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find asm6x\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local asm6x = find_asm6x()\n-- local asm6x, version = find_asm6x({program = \"asm6x\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = \"--help\"\n    opt.command = \"--help\"\n    local program = find_program(opt.program or \"asm6x\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_asn1c.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_asn1c.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find asn1c\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local asn1c = find_asn1c()\n-- local asn1c, version = find_asn1c({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"asn1c\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_bash.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_bash.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find bash\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local bash = find_bash()\n-- local bash, version = find_bash({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find bash from git for windows\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        table.insert(opt.paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\GitForWindows;InstallPath)\\\\bin\")\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"bash\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_bazel.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_bazel.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find bazel\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local bazel = find_bazel()\n-- local bazel, version = find_bazel({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"bazel\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_bison.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_bison.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find bison\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local bison = find_bison()\n-- local bison, version = find_bison({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"bison\", opt)\n    if not program and not opt.program and is_host(\"windows\") then\n        program = find_program(\"win_bison\", opt)\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_bl51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        find_bl51.lua\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_c51\")\nimport(\"lib.detect.find_tool\")\n\nfunction _check(program)\n    local c51 = assert(find_tool(\"c51\"), \"c51 not found\")\n\n    -- make temp source file\n    local tmpdir = os.tmpfile() .. \".dir\"\n    local cfile = path.join(tmpdir, \"test.c\")\n    local objfile = path.join(tmpdir, \"test.obj\")\n    local binfile = path.join(tmpdir, \"test\")\n\n    -- write test code\n    io.writefile(cfile, \"void main() {}\")\n\n    -- archive it\n    os.runv(c51.program, {\"test.c\"}, {curdir = tmpdir})\n    os.runv(program, {objfile, \"TO\", binfile})\n\n    -- remove files\n    os.rmdir(tmpdir)\nend\n-- find bl51\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local bl51 = find_bl51()\n-- local bl51, version = find_bl51()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or _check\n    local program = find_program(opt.program or \"bl51.exe\", opt)\n    if not program then\n        local c51 = find_c51()\n        if c51 then\n            if c51.sdkdir_c51 then\n                program = find_program(path.join(c51.sdkdir_c51, \"bin\", \"bl51.exe\"), opt)\n            end\n            if not program and c51.sdkdir_a51 then\n                program = find_program(path.join(c51.sdkdir_a51, \"bin\", \"bl51.exe\"), opt)\n            end\n        end\n    end\n    return program, nil\nend"
  },
  {
    "path": "xmake/modules/detect/tools/find_brew.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_brew.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find brew\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local brew = find_brew()\n-- local brew, version = find_brew({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- we do not attempt to run brew and only find the brew program path\n    -- because the `brew --version` and `brew help` commands are too slow. (~1.5s)\n    opt.norun = true\n\n    -- find program\n    local program = find_program(opt.program or \"brew\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_bzip2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_bzip2.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find bzip2\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local bzip2 = find_bzip2()\n-- local bzip2, version = find_bzip2({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"--help\"\n    opt.command = opt.command or \"--help\"\n    opt.parse   = \"(%d+%.?%d*)%s\"\n\n    -- find program\n    local program = find_program(opt.program or \"bzip2\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_c51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        find_c51.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_c51\")\n\nfunction _check(program)\n    -- make temp source file\n    local tmpdir = os.tmpfile() .. \".dir\"\n    local cfile = path.join(tmpdir, \"test.c\")\n\n    -- write test code\n    io.writefile(cfile, \"void main() {}\")\n    -- archive it\n    os.runv(program, {\"test.c\"}, {curdir = tmpdir})\n    -- remove files\n    os.rmdir(tmpdir)\nend\n-- find c51\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local c51 = find_c51()\n-- local c51, version = find_c51()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or _check\n    local program = find_program(opt.program or \"c51\", opt)\n    if not program then\n        local c51 = find_c51()\n        if c51 then\n            if c51.sdkdir_c51 then\n                program = find_program(path.join(c51.sdkdir_c51, \"bin\", \"c51\"), opt)\n            end\n            if not program and c51.sdkdir_a51 then\n                program = find_program(path.join(c51.sdkdir_a51, \"bin\", \"c51\"), opt)\n            end\n        end\n    end\n    return program, nil\nend"
  },
  {
    "path": "xmake/modules/detect/tools/find_cargo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cargo.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nim\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nim = find_cargo()\n-- local nim, version = find_cargo({program = \"cargo\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"cargo\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.tools.find_gcc\")\n\n-- find c++\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cc = find_cc()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    local version = nil\n    local program = find_program(opt.program or \"cc\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- is clang++ or c++\n    local is_clang = false\n    if program then\n        is_clang = find_gcc.check_clang(program, opt)\n    end\n    return program, version, (is_clang and \"clang\" or \"cc\")\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ccache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ccache.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ccache\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ccache = find_ccache()\n-- local ccache, version = find_ccache({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"ccache\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_circle.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_circle.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find circle\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local circle = find_circle()\n-- local circle, version = find_circle({program = \"circle\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"circle\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cl = find_cl()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    opt.check = opt.check or function (program)\n        local ok = try { function () os.runv(program, {}, {envs = opt.envs}); return true end }\n        if not ok then\n            -- @see https://github.com/xmake-io/xmake/issues/3057\n            local objectfile = os.tmpfile() .. \".obj\"\n            local sourcefile = os.tmpfile() .. \".c\"\n            io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n            os.runv(program, {\"-c\", \"-Fo\" .. objectfile, sourcefile}, {envs = opt.envs})\n            os.rm(objectfile)\n            os.rm(sourcefile)\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"cl.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or function ()\n            local _, info = os.iorunv(program, {}, {envs = opt.envs})\n            return info\n        end\n        opt.parse = opt.parse or function (output)\n            -- we only keep the first three digits of the version number, making sure to provide a valid semver string.\n            -- @see https://github.com/xmake-io/xmake/issues/6474\n            return output:match(\"%s(%d+%.%d+%.%d+)\")\n        end\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cl2000.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cl2000.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cl2000\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cl2000 = find_cl2000()\n-- local cl2000, version = find_cl2000({program = \"cl2000\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = \"--help\"\n    opt.command = \"--help\"\n    local program = find_program(opt.program or \"cl2000\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cl6x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cl6x.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cl6x\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cl6x = find_cl6x()\n-- local cl6x, version = find_cl6x({program = \"cl6x\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = \"--help\"\n    opt.command = \"--help\"\n    local program = find_program(opt.program or \"cl6x\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clang.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clang = find_clang()\n-- local clang, version = find_clang({program = \"xcrun -sdk macosx clang\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    local program = find_program(opt.program or \"clang\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clang_cl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clang_cl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang_cl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clang_cl = find_clang_cl()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    local version = nil\n    local program = find_program(opt.program or \"clang-cl.exe\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clang_format.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clang_format.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang-format\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clang_format = find_clang_format()\n-- local clang_format, version = find_clang_format({program = \"clang-format\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"clang-format\", opt)\n    if not program and is_host(\"macosx\") then\n        local llvm = try {function () return os.iorunv(\"brew\", {\"--prefix\", \"llvm\"}) end}\n        if llvm then\n            opt.paths = table.wrap(opt.paths)\n            opt.force = true\n            table.insert(opt.paths, path.join(llvm:trim(), \"bin\"))\n            program = find_program(opt.program or \"clang-format\", opt)\n        end\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clang_scan_deps.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clang_scan_deps.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang-scan-deps\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clang_scan_deps = find_clang_scan_deps()\n-- local clang_scan_deps, version = find_clang_scan_deps({program = \"clang-scan-deps\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"clang-scan-deps\", opt)\n    if not program and is_host(\"macosx\") then\n        local llvm = try {function () return os.iorunv(\"brew\", {\"--prefix\", \"llvm\"}) end}\n        if llvm then\n            opt.paths = table.wrap(opt.paths)\n            opt.force = true\n            table.insert(opt.paths, path.join(llvm:trim(), \"bin\"))\n            program = find_program(opt.program or \"clang-scan-deps\", opt)\n        end\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clang_tidy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clang_tidy.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang-tidy\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clang_tidy = find_clang_tidy()\n-- local clang_tidy, version = find_clang_tidy({program = \"clang-tidy\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"clang-tidy\", opt)\n    if not program and is_host(\"macosx\") then\n        local llvm = try {function () return os.iorunv(\"brew\", {\"--prefix\", \"llvm\"}) end}\n        if llvm then\n            opt.paths = table.wrap(opt.paths)\n            opt.force = true\n            table.insert(opt.paths, path.join(llvm:trim(), \"bin\"))\n            program = find_program(opt.program or \"clang-tidy\", opt)\n        end\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clangxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_clangxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clang++\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clangxx = find_clangxx()\n-- local clangxx, version = find_clangxx({program = \"xcrun -sdk macosx clang++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    local program = find_program(opt.program or \"clang++\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_clib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Adel Vilkov (aka RaZeR-RBI)\n-- @file        find_clib.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find clib\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local clib = find_clib()\n-- local clib, version = find_clib({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"clib\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cmake.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.tool.toolchain\")\n\n-- find cmake\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cmake = find_cmake()\n-- local cmake, version = find_cmake({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.norunfile = true\n    if is_host(\"windows\") then\n        opt.paths = \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Kitware\\\\CMake;InstallDir)\\\\bin\"\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"cmake\", opt)\n    if not program and is_host(\"windows\") then\n        -- we always use host/arch to avoid windows/arm64, because we are building packages for cross-compilation\n        local msvc = toolchain.load(\"msvc\", {plat = os.host(), arch = os.arch()})\n        if msvc:check() then\n            opt.envs = msvc:runenvs() -- we attempt to find it from vstudio environments\n            opt.force = true\n            program = find_program(opt.program or \"cmake\", opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_codesign.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_codesign.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find codesign\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local codesign = find_codesign()\n-- local codesign, version = find_codesign({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- only for macosx\n    if not is_host(\"macosx\") then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n    opt.check = function (program)\n        os.runv(program, {\"-d\", \"/bin/echo\"})\n    end\n\n    -- find program\n    return find_program(opt.program or \"codesign\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_conan.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_conan.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find conan\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local conan = find_conan()\n-- local conan, version = find_conan({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"conan\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_conda.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_conda.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find conda\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local conda = find_conda()\n-- local conda, version = find_conda({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    if is_host(\"windows\") then\n        opt.paths = {\"$(env CONDA_BAT)\",\n                     \"$(env USERPROFILE)/miniconda3/condabin\"}\n    end\n    local program = find_program(opt.program or (is_host(\"windows\") and \"conda.bat\" or \"conda\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cosmoar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cosmoar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_cosmoar()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.shell = true\n    opt.envs  = opt.envs or {PATH = os.getenv(\"PATH\")}\n    local program = find_program(opt.program or \"cosmoar\", opt)\n    if program and is_host(\"windows\") then\n        program = program:gsub(\"\\\\\", \"/\")\n    end\n    return program\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cosmocc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cosmocc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cosmocc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cosmocc = find_cosmocc()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.shell = true\n    opt.envs  = opt.envs or {PATH = os.getenv(\"PATH\")}\n    local program = find_program(opt.program or \"cosmocc\", opt)\n    if program and is_host(\"windows\") then\n        program = program:gsub(\"\\\\\", \"/\")\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cosmocxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cosmocxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cosmocxx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cosmocxx = find_cosmocxx()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.shell = true\n    opt.envs  = opt.envs or {PATH = os.getenv(\"PATH\")}\n    local program = find_program(opt.program or \"cosmoc++\", opt)\n    if program and is_host(\"windows\") then\n        program = program:gsub(\"\\\\\", \"/\")\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cparser.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cparser.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cparser\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cparser = find_cparser()\n-- local cparser, version = find_cparser({program = \"cparser\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"cparser\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cpp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cpp.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find cpp\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cpp = find_cpp()\n-- local cpp, version = find_cpp({program = \"xcrun -sdk macosx cpp\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local version = nil\n    local program = find_program(opt.program or \"cpp\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cudagdb.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        find_cudagdb.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find cudagdb\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cudagdb = find_cudagdb()\n-- local cudagdb, version = find_cudagdb({program = \"cuda-gdb\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"cuda-gdb\", \"(%d+%.?%d*%.?%d*.-)%s+release\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cudamemcheck.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        find_cudamemcheck.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find cudamemcheck\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cudamemcheck = find_cudamemcheck()\n-- local cudamemcheck, version = find_cudamemcheck({program = \"cuda-memcheck\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"cuda-memcheck\", \"version (%d+%.?%d*%.?%d*.-)\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_curl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_curl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find curl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local curl = find_curl()\n-- local curl, version = find_curl({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find curl from builtin xmake/winenv\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        table.insert(opt.paths, path.join(os.programdir(), \"winenv\", \"bin\"))\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"curl\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.tools.find_gcc\")\n\n-- find c++\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local cxx = find_cxx()\n-- local cxx, version, hintname = find_cxx({program = \"xcrun -sdk macosx c++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    local version = nil\n    local program = find_program(opt.program or \"c++\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- is clang++ or c++\n    local is_clang = false\n    if program then\n        is_clang = find_gcc.check_clang(program, opt)\n    end\n    return program, version, (is_clang and \"clangxx\" or \"cxx\")\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_cxxbridge.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_cxxbridge.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nim\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nim = find_cxxbridge()\n-- local nim, version = find_cxxbridge({program = \"cxxbridge\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"cxxbridge\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_debuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_debuild.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find debuild\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local debuild = find_debuild()\n-- local debuild, version = find_debuild({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"debuild\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_devenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_devenv.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\n\n-- find devenv\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local devenv = find_devenv()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if not is_host(\"windows\") then\n        return\n    end\n\n    -- disable to check version\n    opt         = opt or {}\n    opt.command = function () end\n\n    -- find it from %DevEnvdir%\n    -- e.g. C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\IDE\n    --\n    local program = nil\n    local msvc = toolchain.load(\"msvc\", {plat = os.host(), arch = os.arch()})\n    if msvc then\n        local vcvars = msvc:config(\"vcvars\")\n        if vcvars then\n            if vcvars.DevEnvdir and os.isexec(path.join(vcvars.DevEnvdir, \"devenv.exe\")) then\n                program = path.join(vcvars.DevEnvdir, \"devenv.exe\")\n            end\n        end\n    end\n    return program\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dmd.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dmd\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dmd = find_dmd()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n\n    -- find program\n    local program = find_program(opt.program or \"dmd\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dotnet.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dotnet.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dotnet\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dotnet = find_dotnet()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"--version\"\n    opt.command = opt.command or \"--version\"\n\n    -- find program\n    local program = find_program(opt.program or \"dotnet\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_doxygen.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_doxygen.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find doxygen\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local doxygen = find_doxygen()\n-- local doxygen, version = find_doxygen({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"doxygen\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dpcpp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icpc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icpc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icpc = find_icpc()\n-- local icpc, version, hintname = find_icpc({program = \"icpc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"dpcpp\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dsymutil.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dsymutil.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dsymutil\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dsymutil = find_dsymutil()\n-- local dsymutil, version = find_dsymutil({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"dsymutil\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dub.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dub.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dub\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dub = find_dub()\n-- local dub, version = find_dub({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"dub\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dumpbin.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dumpbin.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dumpbin\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dumpbin = find_dumpbin()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or function (program) os.runv(program, {\"/symbols\"}, {envs = opt.envs}) end\n\n    -- find program\n    local program = find_program(opt.program or \"dumpbin.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or function () local info = os.iorunv(program, {\"/symbols\"}, {envs = opt.envs}); return info end\n        opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n        version     = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_dxc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_dxc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dxc\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\dxc.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dxc = find_dxc()\n-- local dxc, version = find_dxc({version = true})\n-- local dxc, version = find_dxc({version = true, program = \"c:\\xxx\\dxc.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.paths = opt.paths or {\n        \"$(env VULKAN_SDK)/Bin\",\n        \"$(env VK_SDK_PATH)/Bin\",\n        \"$(env PATH)\"\n    }\n    opt.paths = table.wrap(opt.paths)\n    local program = find_program(opt.program or \"dxc.exe\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_emar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_emar.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_emsdk\")\n\n-- check\nfunction _check(program)\n\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_emar()\n-- local ar, version = find_emar({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.check = opt.check or function (program)\n        local bindir = path.directory(program)\n        local filename = path.filename(program)\n        filename = filename:gsub(\"emar\", \"emcc\")\n        local emcc_program = filename\n        if bindir and bindir ~= \".\" then\n            emcc_program = path.join(bindir, filename)\n        end\n        local emcc = assert(find_tool(\"emcc\", {program = emcc_program, envs = opt.envs}), \"emcc not found!\")\n\n        -- make an stub source file\n        local libraryfile   = os.tmpfile() .. \".a\"\n        local objectfile    = os.tmpfile() .. \".o\"\n        local sourcefile    = os.tmpfile() .. \".c\"\n        io.writefile(sourcefile, \"int test(void)\\n{return 0;}\\n\")\n\n        -- compile it\n        os.runv(emcc.program, {\"-c\", \"-o\" .. objectfile, sourcefile}, {envs = opt.envs})\n\n        -- archive it\n        os.runv(program, {\"-cr\", libraryfile, objectfile}, {envs = opt.envs})\n\n        -- remove files\n        os.rm(objectfile)\n        os.rm(sourcefile)\n        os.rm(libraryfile)\n    end\n\n    -- init the search directories\n    local emsdk = find_emsdk()\n    if emsdk and emsdk.emscripten then\n        local paths = {}\n        table.insert(paths, emsdk.emscripten)\n        opt.paths = paths\n    end\n\n    -- find program\n    return find_program(opt.program or (is_host(\"windows\") and \"emar.bat\" or \"emar\"), opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_emcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_emcc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_emsdk\")\n\n-- find emcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local emcc = find_emcc()\n-- local emcc, version = find_emcc({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init the search directories\n    local emsdk = find_emsdk()\n    if emsdk and emsdk.emscripten then\n        local paths = {}\n        table.insert(paths, emsdk.emscripten)\n        opt.paths = paths\n    end\n\n    -- find program\n    local program = find_program(opt.program or (is_host(\"windows\") and \"emcc.bat\" or \"emcc\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_emrun.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      jinke18\n-- @file        find_emrun.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_emsdk\")\n\n-- find emrun\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local emrun = find_emrun()\n-- local emrun, version = find_emrun({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or function (program)\n        os.runv(program, {\"--help\"}, {envs = opt.envs})\n    end\n\n    -- init the search directories\n    local emsdk = find_emsdk()\n    if emsdk and emsdk.emscripten then\n        local paths = {}\n        table.insert(paths, emsdk.emscripten)\n        opt.paths = paths\n    end\n    \n    -- find program\n    local program = find_program(opt.program or (is_host(\"windows\") and \"emrun.bat\" or \"emrun\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_emxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_emxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_emsdk\")\n\n-- find emxx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local emxx = find_emxx()\n-- local emxx, version = find_emxx({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init the search directories\n    local emsdk = find_emsdk()\n    if emsdk and emsdk.emscripten then\n        local paths = {}\n        table.insert(paths, emsdk.emscripten)\n        opt.paths = paths\n    end\n\n    -- find program\n    local program = find_program(opt.program or (is_host(\"windows\") and \"em++.bat\" or \"em++\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_fasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_fasm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find fasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local fasm = find_fasm()\n-- local fasm, version = find_fasm({program = \"fasm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.norun = true\n\n    -- find program\n    local program = find_program(opt.program or \"fasm\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_flang.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_flang.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find flang\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local flang = find_flang()\n-- local flang, version = find_flang({program = \"flang\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"flang\", opt)\n    if not program and is_host(\"linux\") then\n        -- on Linux, flang might be named as flang-new\n        program = find_program(\"flang-new\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_flex.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_flex.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find flex\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local flex = find_flex()\n-- local flex, version = find_flex({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"flex\", opt)\n    if not program and not opt.program and is_host(\"windows\") then\n        program = find_program(\"win_flex\", opt)\n    end\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_fpc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_fpc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find fpc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local fpc = find_fpc()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-h\"\n\n    -- find program\n    local program = find_program(opt.program or \"fpc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gcc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.cache.detectcache\")\n\n-- check gcc/gigabyte signature\nfunction check_gcc_gigabyte(program)\n    if os.isfile(program) then\n        local signer = nil\n        if winos.file_signature then\n            signer = winos.file_signature(program)\n        end\n        if signer and signer.signer_name then\n            local signer_name = signer.signer_name:upper()\n            if signer_name:find(\"GIGA-BYTE\", 1, true) then\n                return true\n            end\n        end\n    end\nend\n\n-- check gigabyte gcc\n-- avoid gcc.exe signed by GIGA-BYTE\n-- @see https://github.com/xmake-io/xmake/issues/5629\nfunction _check_gcc_on_windows(program, opt)\n    opt = opt or {}\n    if check_gcc_gigabyte(program) then\n        raise(\"gcc.exe signed by GIGA-BYTE is not allowed!\")\n    end\n    return os.runv(program, {\"--version\"}, {envs = opt.envs, shell = opt.shell})\nend\n\n-- detect whether the current gcc compiler is clang\nfunction check_clang(program, opt)\n    local is_clang = false\n    local cachekey = \"find_gcc_versioninfo_\" .. program\n    local versioninfo = detectcache:get(cachekey)\n    if versioninfo == nil then\n        versioninfo = os.iorunv(program, {\"--version\"}, {envs = opt.envs})\n        detectcache:set(cachekey, versioninfo)\n    end\n    if versioninfo and versioninfo:find(\"clang\", 1, true) then\n        is_clang = true\n    end\n    return is_clang\nend\n\n-- find gcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gcc = find_gcc()\n-- local gcc, version, hintname = find_gcc({program = \"xcrun -sdk macosx gcc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        opt.check = _check_gcc_on_windows\n    else\n        opt.norunfile = true\n    end\n    local program = find_program(opt.program or \"gcc\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    local is_clang = false\n    if program and is_host(\"macosx\") then\n        is_clang = check_clang(program, opt)\n    end\n    return program, version, (is_clang and \"clang\" or \"gcc\")\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gcc_ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gcc_ar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- check\nfunction _check(program)\n\n    -- make a stub object file\n    local libraryfile = os.tmpfile() .. \".a\"\n    local objectfile  = os.tmpfile() .. \".o\"\n    io.writefile(objectfile, \"\")\n\n    -- archive it\n    os.runv(program, {\"-cr\", libraryfile, objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(libraryfile)\nend\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_gcc_ar()\n-- local ar, version = find_ar({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt       = opt or {}\n    opt.check = opt.check or _check\n    return find_program(opt.program or \"gcc-ar\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gccgo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gogccgo.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gccgo\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gccgo = find_gccgo()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n    opt.parse   = opt.parse or function (output) return output:match(\"%s(%d+%.?%d+%.?%d+)%s\") end\n\n    -- find program\n    local program = find_program(opt.program or \"gccgo\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gdb.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gdb.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gdb\n--\n-- @param opt   the argument options, e.g. {version = true, program=\"/usr/bin/gdb\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gdb = find_gdb()\n-- local gdb, version = find_gdb({version = true})\n-- local gdb, version = find_gdb({version = true, program = \"/usr/bin/gdb\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"gdb\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gdc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gdc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gdc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gdc = find_gdc()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n    opt.parse   = opt.parse or function (output) return output:match(\"%s(%d+%.?%d+%.?%d+)%s\") end\n\n    -- find program\n    local program = find_program(opt.program or \"gdc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gfortran.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gfortran.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gfortran\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gfortran = find_gfortran()\n-- local gfortran, version = find_gfortran({program = \"g95\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"gfortran\", opt)\n    if not program then\n        program = find_program(\"g95\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_git.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_git.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find git\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local git = find_git()\n-- local git, version = find_git({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"git\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_glslangValidator.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_glslangValidator.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find glslangValidator\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local glslangValidator = find_glslangValidator()\n-- local glslangValidator, version = find_glslangValidator({program = \"glslangValidator\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"glslangValidator\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_glslc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_glslc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.tool.toolchain\")\n\n-- find glslc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local glslc = find_glslc()\n-- local glslc, version = find_glslc({program = \"glslc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"glslc\", opt)\n    if not program and is_plat(\"android\") then\n        local ndk = toolchain.load(\"ndk\"):config(\"ndk\")\n        if ndk then\n            local prebuilt = (is_host(\"macosx\") and \"darwin\" or os.host()) .. \"-x86_64\"\n            opt.paths = path.join(ndk, \"shader-tools\", prebuilt)\n            program = find_program(opt.program or \"glslc\", opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gn.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gn.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gn\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gn = find_gn()\n-- local gn, version = find_gn({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"gn\", opt)\n    if not program and is_host(\"windows\") then\n        program = find_program(\"gn.bat\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_go.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_go.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find go\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local go = find_go()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"version\"\n    opt.command = opt.command or \"version\"\n\n    -- find program\n    local program = find_program(opt.program or \"go\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.tools.find_gcc\")\n\n-- find g++\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gxx = find_gxx()\n-- local gxx, version, hintname = find_gxx({program = \"xcrun -sdk macosx g++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    local program = find_program(opt.program or \"g++\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- is clang++ or g++\n    local is_clang = false\n    if program and is_host(\"macosx\") then\n        is_clang = find_gcc.check_clang(program, opt)\n    end\n    return program, version, (is_clang and \"clangxx\" or \"gxx\")\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_gzip.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_gzip.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find gzip\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local gzip = find_gzip()\n-- local gzip, version = find_gzip({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"gzip\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or function()\n            local outdata, errdata = os.iorunv(program, {\"--version\"})\n            return (outdata or \"\") .. (errdata or \"\")\n        end\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_hdiutil.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_hdiutil.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find hdiutil\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local hdiutil = find_hdiutil()\n-- local hdiutil, version = find_hdiutil({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- only for macosx\n    if not is_host(\"macosx\") then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or \"help\"\n\n    -- find program\n    local program = find_program(opt.program or \"hdiutil\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or \"info\"\n        opt.parse = opt.parse or function (output)\n            -- extract version from \"framework : 671.140.2\" or \"driver : 671.140.2\"\n            return output:match(\"framework%s*:%s*(%d+%.%d+%.%d+)\") or output:match(\"driver%s*:%s*(%d+%.%d+%.%d+)\")\n        end\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_iarchive.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iarchive.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_iarsdk\")\n\n-- find iarchive\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local iarchive = find_iarchive()\n-- local iarchive, version = find_iarchive({program = \"iarchive\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"iarchive.exe\", opt)\n    if not program then\n        local iarsdk = find_iarsdk()\n        if iarsdk and iarsdk.sdkdir then\n            program = find_program(path.join(iarsdk.sdkdir, \"bin\", \"iarchive.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_iasmarm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iasmarm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_iarsdk\")\n\n-- find iasmarm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local iasmarm = find_iasmarm()\n-- local iasmarm, version = find_iasmarm({program = \"iasmarm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"iasmarm.exe\", opt)\n    if not program then\n        local iarsdk = find_iarsdk()\n        if iarsdk and iarsdk.sdkdir then\n            program = find_program(path.join(iarsdk.sdkdir, \"bin\", \"iasmarm.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_icc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icc = find_icc()\n-- local icc, version, hintname = find_icc({program = \"icc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"icc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_iccarm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iccarm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_iarsdk\")\n\n-- find iccarm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local iccarm = find_iccarm()\n-- local iccarm, version = find_iccarm({program = \"iccarm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"iccarm.exe\", opt)\n    if not program then\n        local iarsdk = find_iarsdk()\n        if iarsdk and iarsdk.sdkdir then\n            program = find_program(path.join(iarsdk.sdkdir, \"bin\", \"iccarm.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_icl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icl = find_icl()\n-- local icl, version, hintname = find_icl({program = \"icl\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or function (program) os.runv(program, {\"/help\"}, {envs = opt.envs}) end\n\n    -- find program\n    local program = find_program(opt.program or \"icl.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or function () local _, info = os.iorunv(program, {\"/help\"}, {envs = opt.envs}); return info end\n        opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n        version     = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_icpc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icpc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icpc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icpc = find_icpc()\n-- local icpc, version, hintname = find_icpc({program = \"icpc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"icpc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_icpx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icpc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icpc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icpc = find_icpc()\n-- local icpc, version, hintname = find_icpc({program = \"icpc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"icpx\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_icx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_icx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find icx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local icx = find_icx()\n-- local icx, version, hintname = find_icx({program = \"icx\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"icx\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ideviceinstaller.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ideviceinstaller.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ideviceinstaller\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ideviceinstaller = find_ideviceinstaller()\n-- local ideviceinstaller, version = find_ideviceinstaller({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- only for macosx\n    if not is_host(\"macosx\") then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-h\"\n\n    -- find program\n    return find_program(opt.program or \"ideviceinstaller\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ifort.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ifort.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ifort\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ifort = find_ifort()\n-- local ifort, version, hintname = find_ifort({program = \"ifort\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        -- find program\n        opt.check = opt.check or function (program) os.runv(program, {\"/help\"}, {envs = opt.envs}) end\n        local program = find_program(opt.program or \"ifort.exe\", opt)\n\n        -- find program version\n        local version = nil\n        if program and opt and opt.version then\n            opt.command = opt.command or function () local _, info = os.iorunv(program, {\"/help\"}, {envs = opt.envs}); return info end\n            opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n            version     = find_programver(program, opt)\n        end\n        return program, version\n    else\n        -- find program\n        local program = find_program(opt.program or \"ifort\", opt)\n\n        -- find program version\n        local version = nil\n        if program and opt.version then\n            version = find_programver(program, opt)\n        end\n        return program, version\n    end\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ifx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ifx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ifx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ifx = find_ifx()\n-- local ifx, version, hintname = find_ifx({program = \"ifx\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    if is_host(\"windows\") then\n        -- find program\n        opt.check = opt.check or function (program) os.runv(program, {\"/help\"}, {envs = opt.envs}) end\n        local program = find_program(opt.program or \"ifx.exe\", opt)\n\n        -- find program version\n        local version = nil\n        if program and opt and opt.version then\n            opt.command = opt.command or function () local _, info = os.iorunv(program, {\"/help\"}, {envs = opt.envs}); return info end\n            opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n            version     = find_programver(program, opt)\n        end\n        return program, version\n    else\n        -- find program\n        local program = find_program(opt.program or \"ifx\", opt)\n\n        -- find program version\n        local version = nil\n        if program and opt.version then\n            version = find_programver(program, opt)\n        end\n        return program, version\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ilinkarm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ilinkarm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_iarsdk\")\n\n-- find ilinkarm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ilinkarm = find_ilinkarm()\n-- local ilinkarm, version = find_ilinkarm({program = \"ilinkarm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"ilinkarm.exe\", opt)\n    if not program then\n        local iarsdk = find_iarsdk()\n        if iarsdk and iarsdk.sdkdir then\n            program = find_program(path.join(iarsdk.sdkdir, \"bin\", \"ilinkarm.exe\"), opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_iverilog.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_iverilog.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find iverilog\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local iverilog = find_iverilog()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-V\"\n    opt.command = opt.command or \"-V\"\n\n    -- find it from some logical drives paths\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        for _, logical_drive in ipairs(winos.logical_drives()) do\n            table.insert(opt.paths, path.join(logical_drive, \"iverilog\", \"bin\"))\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"iverilog\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_java.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_java.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find java\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local java = find_java()\n-- local java, version = find_java({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.check   = opt.check or \"-version\"\n    opt.command = opt.command or \"-version\"\n\n    local program = find_program(opt.program or \"java\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_jom.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_jom.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find jom\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local jom = find_jom()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = \"/?\"\n\n    -- find program\n    local program = find_program(opt.program or \"jom.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_kotlinc_native.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_kotlinc_native.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find kotlinc_native\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local kotlinc_native = find_kotlinc_native()\n-- local kotlinc_native, version = find_kotlinc_native({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.check   = opt.check or \"-version\"\n    opt.command = opt.command or \"-version\"\n\n    local program = opt.program or \"kotlinc-native\"\n    if is_host(\"windows\") then\n        program = program .. \".bat\"\n    elseif is_host(\"linux\") then\n        opt.shell = true\n    end\n    program = find_program(program, opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ld.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ld()\n-- local ar, version = find_ld({program = \"ld\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norun = true\n    return find_program(opt.program or \"ld\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ld64_lld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ld64_lld.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ld64_lld()\n-- local ar, version = find_ld64_lld({program = \"ld64.lld\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"ld64.lld\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ld_lld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ld_lld.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_ld_lld()\n-- local ar, version = find_ld_lld({program = \"ld.lld\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"ld.lld\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ldc2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ldc2.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ldc2\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ldc2 = find_ldc2()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n    opt.parse   = opt.parse or function (output) return output:match(\"%((%d+%.?%d*%.?%d*.-)%)\") end\n\n    local version = nil\n    local program = find_program(opt.program or \"ldc2\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lex.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lex.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lex\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lex = find_lex()\n-- local lex, version = find_lex({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"lex\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lib.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"lib.detect.find_tool\")\n\n-- find lib\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lib = find_lib()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init version info first\n    local verinfo = nil\n\n    -- init options\n    opt       = opt or {}\n    opt.check = opt.check or function (program)\n\n        -- make an stub source file\n        local libraryfile = os.tmpfile() .. \".lib\"\n        local objectfile  = os.tmpfile() .. \".obj\"\n        local sourcefile  = os.tmpfile() .. \".c\"\n        io.writefile(sourcefile, \"int test(void)\\n{return 0;}\\n\")\n\n        -- check it\n        local cl = assert(find_tool(\"cl\", {envs = opt.envs}))\n        local link = assert(find_tool(\"link\", {envs = opt.envs}))\n        os.runv(cl.program, {\"-c\", \"-Fo\" .. objectfile, sourcefile}, {envs = opt.envs})\n        os.runv(link.program, {\"-lib\", \"-out:\" .. libraryfile, objectfile}, {envs = opt.envs})\n        verinfo = os.iorunv(program, {\"-list\", libraryfile}, {envs = opt.envs})\n\n        -- remove files\n        os.rm(objectfile)\n        os.rm(sourcefile)\n        os.rm(libraryfile)\n    end\n    opt.command = opt.command or function () return verinfo end\n    opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n\n    -- find program\n    local program = find_program(opt.program or \"lib.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_link.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_link.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"lib.detect.find_tool\")\n\n-- find link\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local link = find_link()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init version info first\n    local version = nil\n    local verinfo = nil\n\n    -- init options\n    opt = opt or {}\n    opt.norunfile = true\n    opt.check = opt.check or function (program)\n        local toolchain = opt.toolchain\n        if toolchain and toolchain:name() == \"masm32\" then\n            -- if this link.exe is from masm32 sdk, we just pass it fastly\n            -- because it does not contain cl.exe\n            --\n            -- TODO maybe we can use ml to improve it\n        else\n            local is_clang_cl = toolchain and toolchain:name() == \"clang-cl\"\n            local cl = assert(find_tool(is_clang_cl and \"clang-cl\" or \"cl\", {envs = opt.envs}))\n\n            -- make an stub source file\n            local binaryfile = os.tmpfile() .. \".exe\"\n            local objectfile = os.tmpfile() .. \".obj\"\n            local sourcefile = os.tmpfile() .. \".c\"\n\n            -- compile sourcefile first\n            io.writefile(sourcefile, \"int main(int argc, char** argv)\\n{return 0;}\\n\")\n            os.runv(cl.program, {\"-c\", \"-Fo\" .. objectfile, sourcefile}, {envs = opt.envs})\n\n            -- do link\n            verinfo = os.iorunv(program, {\"-lib\", \"-out:\" .. binaryfile, objectfile}, {envs = opt.envs})\n\n            -- remove files\n            os.rm(objectfile)\n            os.rm(sourcefile)\n            os.rm(binaryfile)\n        end\n    end\n    opt.command = opt.command or function () return verinfo end\n    opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n\n    -- find program\n    local program = find_program(opt.program or \"link.exe\", opt)\n\n    -- find program version\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lipo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lipo.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lipo\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lipo = find_lipo()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.check = opt.check or function (program) os.run(\"%s -info %s\", program, os.programfile()) end\n\n    -- find program\n    return find_program(opt.program or \"lipo\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lld_link.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lld_link.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_lld_link()\n-- local ar, version = find_lld_link({program = \"lld.link\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"lld-link\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lldb.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lldb.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lldb\n--\n-- @param opt   the argument options, e.g. {version = true, program=\"/usr/bin/lldb\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lldb = find_lldb()\n-- local lldb, version = find_lldb({version = true})\n-- local lldb, version = find_lldb({version = true, program = \"/usr/bin/lldb\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"lldb\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_llvm_ar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_llvm_ar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find llvm-ar\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\llvm_ar.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local llvm_ar = find_llvm_ar()\n-- local llvm_ar, version = find_llvm_ar({version = true})\n-- local llvm_ar, version = find_llvm_ar({version = true, program = \"c:\\xxx\\llvm_ar.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    opt.check = opt.check or \"-h\"\n    opt.command = opt.command or \"--version\"\n\n    local version = nil\n    local program = find_program(opt.program or \"llvm-ar\", opt)\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_llvm_as.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_llvm_as.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find llvm-ar\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\llvm-as.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local llvm_as = find_llvm_as()\n-- local llvm_as, version = find_llvm_as({version = true})\n-- local llvm_as, version = find_llvm_as({version = true, program = \"c:\\xxx\\llvm-as.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or \"-version\"\n    opt.command = opt.command or \"-version\"\n\n    -- find program\n    local program = find_program(opt.program or \"llvm-as\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_llvm_dlltool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_llvm_dlltool.lua\n--\n\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find llvm-dlltool\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dlltool = find_llvm_dlltool()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    -- return with non-zero code\n    opt.norun = true\n\n    -- find program\n    local program = find_program(opt.program or \"llvm-dlltool\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_llvm_rc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_llvm_rc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find llvm-rc\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\llvm_rc.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local llvm_rc = find_llvm_rc()\n-- local llvm_rc, version = find_llvm_rc({version = true})\n-- local llvm_rc, version = find_llvm_rc({version = true, program = \"c:\\xxx\\llvm_rc.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    opt.check = opt.check or \"/?\"\n    return find_program(opt.program or \"llvm-rc\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_lua.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_lua.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lua\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lua = find_lua()\n-- local lua, version = find_lua({program = \"lua\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"lua\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_luajit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_luajit.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lua\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lua = find_luajit()\n-- local lua, version = find_luajit({program = \"luajit\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"luajit\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_make.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_make.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find make\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local make = find_make()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    local program = find_program(opt.program or (is_host(\"bsd\") and \"gmake\" or \"make\"), opt)\n    if not program and not opt.program and is_subhost(\"msys\", \"cygwin\") then\n        program = find_program(\"mingw32-make.exe\", opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_meson.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_meson.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find meson\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local meson = find_meson()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"meson\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_metal.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_metal.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find metal\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local metal = find_metal()\n-- local metal, version = find_metal({program = \"xcrun -sdk macosx metal\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    local program = find_program(opt.program or \"xcrun -sdk macosx metal\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_metallib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_metallib.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find metallib\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local metallib = find_metallib()\n-- local metallib, version = find_metallib({program = \"xcrun -sdk macosx metallib\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    local program = find_program(opt.program or \"xcrun -sdk macosx metallib\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_midl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_midl.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find midl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n-- local midl = find_midl()\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.check   = opt.check or \"/confirm\"\n    opt.command = opt.command or \"/confirm\"\n    opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.%d+%.%d+)%s\") end\n\n    -- https://github.com/xmake-io/xmake/issues/7192\n    opt.norunfile = true\n\n    local envs = opt.envs\n    if envs and envs.WindowsSdkDir and envs.WindowsSDKVersion then\n        local toolchain = opt.toolchain\n        local arch = toolchain and toolchain:arch() or config.arch()\n        local bindir = path.join(envs.WindowsSdkDir, \"bin\", envs.WindowsSDKVersion, arch)\n        if os.isdir(bindir) then\n            opt.paths = table.wrap(opt.paths)\n            table.insert(opt.paths, bindir)\n        end\n    end\n\n    local version = nil\n    local program = find_program(opt.program or \"midl\", opt)\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ml.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ml.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ml\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ml = find_ml()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    opt.check = opt.check or function (program)\n        os.runv(program, {}, {envs = opt.envs})\n    end\n\n    local version = nil\n    local program = find_program(opt.program or \"ml.exe\", opt)\n    if program and opt and opt.version then\n        opt.command = opt.command or function () local _, info = os.iorunv(program, {}, {envs = opt.envs}); return info end\n        opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ml64.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ml64.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ml64\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ml64 = find_ml64()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.norunfile = true\n    opt.check = opt.check or function (program)\n        os.runv(program, {}, {envs = opt.envs})\n    end\n\n    local version = nil\n    local program = find_program(opt.program or \"ml64.exe\", opt)\n    if program and opt and opt.version then\n        opt.command = opt.command or function () local _, info = os.iorunv(program, {}, {envs = opt.envs}); return info end\n        opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_mold.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_mold.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_mold()\n-- local ar, version = find_mold({program = \"mold\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"mold\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_msbuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_msbuild.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find msbuild\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local msbuild = find_msbuild()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = \"/version\"\n\n    -- find program\n    local program = find_program(opt.program or \"msbuild.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nasm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nasm = find_nasm()\n-- local nasm, version = find_nasm({program = \"nasm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"nasm\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nim.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nim.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nim\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nim = find_nim()\n-- local nim, version = find_nim({program = \"nim\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"nim\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nimble.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nimble.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nim\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nim = find_nimble()\n-- local nim, version = find_nimble({program = \"nimble\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"nimble\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ninja.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ninja.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.tool.toolchain\")\n\n-- find ninja\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ninja = find_ninja()\n-- local ninja, version = find_ninja({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    opt.norunfile = true\n    local program = find_program(opt.program or \"ninja\", opt)\n    if not program and is_host(\"windows\") then\n        local msvc = toolchain.load(\"msvc\", {plat = os.host(), arch = os.arch()})\n        if msvc:check() then\n            opt.envs = msvc:runenvs() -- we attempt to find it from vstudio environments\n            opt.force = true\n            program = find_program(opt.program or \"ninja\", opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nix.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nix.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nix\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nix = find_nix()\n-- local nix, version = find_nix({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    -- init options\n    opt = opt or {}\n    \n    -- add common nix installation paths if no specific program is given\n    if not opt.program then\n        opt.paths = opt.paths or {}\n        local nix_paths = {\n            \"/nix/var/nix/profiles/default/bin\", -- multi-user installation\n            \"/home/\" .. (os.getenv(\"USER\") or \"user\") .. \"/.nix-profile/bin\", -- single user installation\n            \"/usr/local/bin\", -- default path of nix when compiling nix from source\n        }\n\n        -- NixOS-specific paths\n        if linuxos.name() == \"nixos\" then\n            table.insert(nix_paths, \"/run/current-system/sw/bin\")\n        end\n        \n        opt.paths = table.wrap(opt.paths)\n        for _, nixpath in ipairs(nix_paths) do\n            table.insert(opt.paths, nixpath)\n        end\n    end\n    \n    -- find program\n    local program = find_program(opt.program or \"nix\", opt)\n    \n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt, function (output)\n            -- parse version from \"nix (Nix) 2.18.1\" format\n            return output:match(\"nix %(Nix%) ([%d%.]+)\")\n        end)\n    end\n    \n    return program, version\nend"
  },
  {
    "path": "xmake/modules/detect/tools/find_nmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nmake.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nmake\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nmake = find_nmake()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = \"/?\"\n\n    -- find program\n    local program = find_program(opt.program or \"nmake.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nmap.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nmap.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- find nmap\n--\n--\n-- @param opt   the argument options\n--\n-- @return      program\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    return find_program(opt.program or \"nmap\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nnd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        find_nnd.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find nnd\n--\n-- @param opt   the argument options, e.g. {version = true, program=\"/usr/bin/nnd\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nnd = find_nnd()\n-- local nnd, version = find_nnd({version = true})\n-- local nnd, version = find_nnd({version = true, program = \"/usr/bin/nnd\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"nnd\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nvc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nvc.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find nvc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nvc = find_nvc()\n-- local nvc, version = find_nvc({program = \"nvc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"nvc\", \"V(%d+%.?%d*%.?%d*.-)%s\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nvcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nvcc.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find nvcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nvcc = find_nvcc()\n-- local nvcc, version = find_nvcc({program = \"nvcc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"nvcc\", \"V(%d+%.?%d*%.?%d*.-)%s\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nvcxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nvcxx.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find nvcxx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nvcxx = find_nvcxx()\n-- local nvcxx, version = find_nvcxx({program = \"nvcxx\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"nvc++\", \"V(%d+%.?%d*%.?%d*.-)%s\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_nvfortran.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_nvfortran.lua\n--\n\n-- imports\nimport(\"private.detect.find_cudatool\")\n\n-- find nvfortran\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nvfortran = find_nvfortran()\n-- local nvfortran, version = find_nvfortran({program = \"nvfortran\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    return find_cudatool(\"nvfortran\", \"V(%d+%.?%d*%.?%d*.-)%s\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_objcopy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_objcopy.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find objcopy\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local objcopy = find_objcopy()\n-- local objcopy, version = find_objcopy({program = \"xcrun -sdk macosx objcopy\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"objcopy\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_oh51.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        find_oh51.lua\n-- OBJECT TO HEX FILE CONVERTER OH51\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_c51\")\nimport(\"lib.detect.find_tool\")\n\nfunction _check(program)\n    local c51 = assert(find_tool(\"c51\"), \"c51 not found\")\n    local bl51 = assert(find_tool(\"bl51\"), \"bl51 not found\")\n\n    -- make temp source file\n    local tmpdir = os.tmpfile() .. \".dir\"\n    os.mkdir(tmpdir)\n    local cfile = path.join(tmpdir, \"test.c\")\n    local objfile = path.join(tmpdir, \"test.obj\")\n    local binfile = path.join(tmpdir, \"test\")\n\n    -- write test code\n    io.writefile(cfile, \"void main() {}\")\n\n    -- archive it\n    os.runv(c51.program, {\"test.c\"}, {curdir = tmpdir})\n    os.runv(bl51.program, {objfile, \"TO\", binfile})\n    os.runv(program, {binfile})\n\n    -- remove files\n    os.rmdir(tmpdir)\nend\n-- find oh51\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local oh51 = find_oh51()\n-- local oh51, version = find_oh51()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or _check\n    local program = find_program(opt.program or \"oh51.exe\", opt)\n    if not program then\n        local c51 = find_c51()\n        if c51 then\n            if c51.sdkdir_c51 then\n                program = find_program(path.join(c51.sdkdir_c51, \"bin\", \"oh51.exe\"), opt)\n            end\n            if not program and c51.sdkdir_a51 then\n                program = find_program(path.join(c51.sdkdir_a51, \"bin\", \"oh51.exe\"), opt)\n            end\n        end\n    end\n    return program, nil\nend"
  },
  {
    "path": "xmake/modules/detect/tools/find_ollydbg.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ollydbg.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ollydbg\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\ollydbg.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ollydbg = find_ollydbg()\n-- local ollydbg, version = find_ollydbg({version = true})\n-- local ollydbg, version = find_ollydbg({version = true, program = \"c:\\xxx\\ollydbg.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if os.host() ~= \"windows\" then\n        return\n    end\n\n    -- init options\n    opt        = opt or {}\n    opt.paths = opt.paths or function ()\n        for _, reg in ipairs({\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\", \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\"}) do\n            return (val(\"reg \" .. reg) or \"\"):match(\"\\\"(.-)\\\"\")\n        end\n    end\n    opt.paths = table.wrap(opt.paths)\n    opt.check  = opt.check or function (program) if not os.isfile(program) then raise() end end\n\n    -- find program\n    return find_program(opt.program or \"ollydbg\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_pacman.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_pacman.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find pacman\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local pacman = find_pacman()\n-- local pacman, version = find_pacman({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"pacman\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_patch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_patch.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find lua\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local lua = find_patch()\n-- local lua, version = find_patch({program = \"patch\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"patch\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_perl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_perl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find perl\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local perl = find_perl()\n-- local perl, version = find_perl({program = \"perl\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init the search directories\n    local paths = {}\n    if is_host(\"windows\") then\n        table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\GitForWindows;InstallPath)\\\\usr\\\\bin\")\n    end\n    opt.paths = paths\n\n    -- find program\n    local program = find_program(opt.program or \"perl\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ping.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ping.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- find ping\n--\n--\n-- @param opt   the argument options\n--\n-- @return      program\n--\nfunction main(opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.check = opt.check or function (program)\n        if is_host(\"windows\") then\n            os.run(\"%s -n 1 -w 500 127.0.0.1\", program)\n        elseif is_host(\"macosx\") then\n            os.run(\"%s -c 1 -t 1 127.0.0.1\", program)\n        else\n            os.run(\"%s -c 1 -W 1 127.0.0.1\", program)\n        end\n    end\n\n    -- find program\n    return find_program(opt.program or \"ping\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_pkg_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_pkg_config.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find pkg_config\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local pkg_config = find_pkg_config()\n-- local pkg_config, version = find_pkg_config({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"pkg-config\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_pkgconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_pkgconf.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find pkgconf\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local pkgconf = find_pkgconf()\n-- local pkgconf, version = find_pkgconf({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"pkgconf\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_powershell.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_powershell.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find powershell\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local powershell = find_powershell()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.check   = opt.check or {\"-c\", \"$PSVersionTable\"}\n    local program = find_program(opt.program or \"powershell\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or {\"-c\", \"$PSVersionTable\"}\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_pwsh.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        find_pwsh.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find pwsh\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local pwsh = find_pwsh()\n--\n-- @endcode\n--\nfunction main(opt)\n    opt         = opt or {}\n    opt.check   = opt.check or {\"-c\", \"$PSVersionTable\"}\n    local program = find_program(opt.program or \"pwsh\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        opt.command = opt.command or {\"-c\", \"$PSVersionTable\"}\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_python.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_python.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.tools.find_python2\")\nimport(\"detect.tools.find_python3\")\n\n-- find python\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return     program, version\n--\n-- @code\n--\n-- local python = find_python()\n-- local python, version = find_python({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"python\", opt)\n    if not program then\n        local opt2 = table.clone(opt)\n        opt2.program = nil\n        program = find_python3(opt2) or find_python2(opt2)\n    end\n\n    local version = nil\n    if program and opt.version then\n        opt.command = function ()\n            local outs, errs = os.iorunv(program, {\"--version\"})\n            return ((outs or \"\") .. (errs or \"\")):trim()\n        end\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_python2.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_python2.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find python\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return     program, version\n--\n-- @code\n--\n-- local python = find_python2()\n-- local python, version = find_python2({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"python2\", opt)\n    if not program then\n        opt.force = true\n        program = find_program(\"python\", opt)\n        opt.version = true\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        opt.command = function ()\n            local outs, errs = os.iorunv(program, {\"--version\"})\n            return ((outs or \"\") .. (errs or \"\")):trim()\n        end\n        version = find_programver(program, opt)\n    end\n\n    -- check version\n    if version and not version:startswith(\"2.\") then\n        return\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_python3.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_python3.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find python\n--\n-- @param opt  the arguments, e.g. {version = true}\n--\n-- @return     program, version\n--\n-- @code\n--\n-- local python = find_python3()\n-- local python, version = find_python3({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        local keys = winos.registry_keys(\"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\3.*\\\\InstallPath\")\n        for _, key in ipairs(keys) do\n            local value = try {function () return winos.registry_query(key .. \";ExecutablePath\") end}\n            if value and os.isfile(value) then\n                table.insert(opt.paths, value)\n            end\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"python3\", opt)\n    if not program then\n        opt.force = true\n        program = find_program(\"python\", opt)\n        opt.version = true\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        opt.command = function ()\n            local outs, errs = os.iorunv(program, {\"--version\"})\n            return ((outs or \"\") .. (errs or \"\")):trim()\n        end\n        version = find_programver(program, opt)\n    end\n\n    -- check version\n    if version and not version:startswith(\"3.\") then\n        return\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_qmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_qmake.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find qmake\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local qmake = find_qmake()\n-- local qmake, version = find_qmake({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"qmake\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_raddbg.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, gaweringo\n-- @file        find_raddbg.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find raddbg\n--\n-- @param opt   the argument options, e.g. {version = true, program=\"raddbg\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local raddbg = find_raddbg()\n-- local raddbg, version = find_raddbg({version = true})\n-- local raddbg, version = find_raddbg({version = true, program = \"raddbg\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"raddbg\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_ranlib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_ranlib.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find ranlib\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ranlib = find_ranlib()\n-- local ranlib, version = find_ranlib({program = \"xcrun -sdk macosx ranlib\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"ranlib\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_rc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_rc.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find rc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local rc = find_rc()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if not is_host(\"windows\") then\n        return\n    end\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-?\"\n    opt.command = opt.command or \"-?\"\n    opt.parse   = opt.parse or function (output) return output:match(\"Version (%d+%.?%d*%.?%d*.-)%s\") end\n\n    -- fix rc.exe missing issues\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/225\n    -- https://stackoverflow.com/questions/43847542/rc-exe-no-longer-found-in-vs-2015-command-prompt/45319119\n    --\n    -- patch sdk bin directory to path environment\n    --\n    -- e.g. C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.17134.0\\x64\n    --\n    local envs = opt.envs\n    if envs and envs.WindowsSdkDir and envs.WindowsSDKVersion then\n        local toolchain = opt.toolchain\n        local arch = toolchain and toolchain:arch() or config.arch()\n        local bindir = path.join(envs.WindowsSdkDir, \"bin\", envs.WindowsSDKVersion, arch)\n        if os.isdir(bindir) then\n            opt.paths = table.wrap(opt.paths)\n            table.insert(opt.paths, bindir)\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"rc.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_renderdoc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, SirLynix\n-- @file        find_renderdoc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find qmake\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local qmake = find_renderdoc()\n-- local qmake, version = find_renderdoc({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n\n        -- add paths from registry\n        local regs =\n        {\n            \"HKEY_CLASSES_ROOT\\\\Applications\\\\qrenderdoc.exe\\\\shell\\\\Open\\\\Command\",\n            \"HKEY_CURRENT_USER\\\\SOFTWARE\\\\Classes\\\\Applications\\\\qrenderdoc.exe\\\\shell\\\\Open\\\\Command\",\n        }\n        for _, reg in ipairs(regs) do\n            table.insert(opt.paths, function ()\n                local value = val(\"reg \" .. reg)\n                if value then\n                    local p = value:split(\"\\\"\") \n                    if p and p[1] then\n                        return path.translate(p[1])\n                    end\n                end\n            end)\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"qrenderdoc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_rpm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Lingfeng Fu\n-- @file        find_rpm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find rpm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local rpm = find_rpm()\n-- local rpm, version = find_rpm({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"rpm\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_rustc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_rustc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find rustc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local rustc = find_rustc()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"rustc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_scons.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_scons.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find scons\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local scons = find_scons()\n-- local scons, version = find_scons({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"scons\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_sdar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_sdar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find dmd\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local dmd = find_sdar()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n\n    -- add search paths\n    local paths = {}\n    local bindir = get_config(\"bin\")\n    if bindir and os.isdir(bindir) then\n        table.insert(paths, bindir)\n    end\n    if is_host(\"windows\") then\n        table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\SDCC)\\\\bin\")\n    end\n    if #paths > 0 then\n        opt.paths = paths\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"sdar\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_sdcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_sdcc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find sdcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local sdcc = find_sdcc()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.command = opt.command or \"--version\"\n\n    -- add search paths\n    local paths  = {}\n    local bindir = get_config(\"bin\")\n    if bindir and os.isdir(bindir) then\n        table.insert(paths, bindir)\n    end\n    if is_host(\"windows\") then\n        table.insert(paths, \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\WOW6432Node\\\\SDCC)\\\\bin\")\n    end\n    if #paths > 0 then\n        opt.paths = paths\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"sdcc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_strip.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_strip.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\n\n-- check strip of xcode\nfunction _check_strip_of_xcode(program)\n\n    -- make an stub source file\n    local objectfile    = os.tmpfile() .. \".o\"\n    local sourcefile    = os.tmpfile() .. \".c\"\n    io.writefile(sourcefile, \"int test(void)\\n{return 0;}\\n\")\n\n    -- compile it\n    compiler.compile(sourcefile, objectfile)\n\n    -- archive it\n    os.runv(program, {\"-S\", objectfile})\n\n    -- remove files\n    os.rm(objectfile)\n    os.rm(sourcefile)\nend\n\n-- find strip\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local strip = find_strip()\n-- local strip, version = find_strip({program = \"xcrun -sdk macosx strip\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- attempt to find gnu strip first with `--version`\n    local program = find_program(opt.program or \"strip\", opt)\n    if not program then\n        -- find strip of xcode without `--version`\n        if is_plat(\"macosx\", \"iphoneos\", \"watchos\") or is_host(\"macosx\") then\n            opt.force = true\n            opt.check = _check_strip_of_xcode\n            program = find_program(opt.program or \"strip\", opt)\n        end\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_sudo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_sudo.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find sudo\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local sudo = find_sudo()\n-- local sudo, version = find_sudo({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-h\"\n    opt.command = opt.command or \"-V\"\n\n    -- find program\n    local program = find_program(opt.program or \"sudo\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_swift_frontend.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_swift_frontend.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find swift_frontend\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local swift_frontend = find_swift_frontend()\n-- local swift_frontend, version = find_swift_frontend({program = \"xcrun -sdk macosx swift-frontend\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"swift-frontend\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_swiftc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_swiftc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find swiftc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local swiftc = find_swiftc()\n-- local swiftc, version = find_swiftc({program = \"xcrun -sdk macosx swiftc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"swiftc\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_swig.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_swig.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find swig\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local swig = find_swig()\n-- local swig, version = find_swig({program = \"swig\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n    opt.check = opt.check or \"-version\"\n\n    -- find program\n    local program = find_program(opt.program or \"swig\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_tar.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_tar.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find tar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local tar = find_tar()\n-- local tar, version = find_tar({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"tar\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_tcc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_tcc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find tcc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local tcc = find_tcc()\n-- local tcc, version = find_tcc({program = \"xcrun -sdk macosx tcc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"tcc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_tclsh.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_tclsh.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find tclsh\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local tclsh = find_tclsh()\n-- local tclsh, version = find_tclsh({program = \"tclsh\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check   = opt.check or function (program)\n        local infile = os.tmpfile()\n        local outfile = os.tmpfile()\n        io.writefile(infile, \"puts hello\\n\")\n        local outdata = os.iorunv(program, {infile})\n        assert(outdata == \"hello\\n\")\n        os.rm(infile)\n        os.rm(outfile)\n    end\n    return find_program(opt.program or \"tclsh\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_unzip.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_unzip.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find unzip\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local unzip = find_unzip()\n-- local unzip, version = find_unzip({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"unzip\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_valac.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_valac.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find valac\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local valac = find_valac()\n-- local valac, version, hintname = find_valac({program = \"valac\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"valac\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_vcpkg.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vcpkg.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_vcpkgdir\")\n\n-- find vcpkg\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local vcpkg = find_vcpkg()\n-- local vcpkg, version = find_vcpkg({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"version\"\n    opt.command = opt.command or \"version\"\n\n    -- init the search directories\n    local paths = {}\n    local vcpkgdir = find_vcpkgdir()\n    if vcpkgdir then\n        table.insert(paths, vcpkgdir)\n    end\n\n    -- find program\n    opt.paths = paths\n    opt.envs  = {PATH = os.getenv(\"PATH\")}\n    local program = find_program(opt.program or (is_host(\"windows\") and \"vcpkg.exe\" or \"vcpkg\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_verilator.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_verilator.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find verilator\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local verilator = find_verilator()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find program\n    opt = opt or {}\n    local program = find_program(opt.program or \"verilator\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_vsjitdebugger.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vsjitdebugger.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find vsjitdebugger\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\vsjitdebugger.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local vsjitdebugger = find_vsjitdebugger()\n-- local vsjitdebugger, version = find_vsjitdebugger({version = true})\n-- local vsjitdebugger, version = find_vsjitdebugger({version = true, program = \"c:\\xxx\\vsjitdebugger.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if not is_host(\"windows\") then\n        return\n    end\n\n    -- init options\n    opt        = opt or {}\n    opt.paths  = opt.paths or function ()\n        for _, reg in ipairs({\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\", \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\"}) do\n            return (val(\"reg \" .. reg) or \"\"):match(\"\\\"(.-)\\\"\")\n        end\n    end\n    opt.paths = table.wrap(opt.paths)\n    opt.check  = opt.check or function (program) if not os.isfile(program) then raise() end end\n\n    -- find program\n    return find_program(opt.program or \"vsjitdebugger\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_vswhere.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vswhere.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find vswhere\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\vswhere.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local vswhere = find_vswhere()\n-- local vswhere, version = find_vswhere({version = true})\n-- local vswhere, version = find_vswhere({version = true, program = \"c:\\xxx\\vswhere.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if not is_host(\"windows\") then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    opt.check   = opt.check or \"-?\"\n    opt.command = opt.command or \"-?\"\n    opt.paths   = opt.paths or\n    {\n        \"$(env VSINSTALLERDIR)\",\n        \"$(env ProgramFiles%(x86%))\\\\Microsoft Visual Studio\\\\Installer\",\n        \"$(env ProgramFiles)\\\\Microsoft Visual Studio\\\\Installer\"\n    }\n    opt.paths = table.wrap(opt.paths)\n    local program = find_program(opt.program or \"vswhere.exe\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_vvp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_vvp.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find vvp\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local vvp = find_vvp()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-V\"\n    opt.command = opt.command or \"-V\"\n\n    -- find it from some logical drives paths\n    if is_host(\"windows\") then\n        opt.paths = table.wrap(opt.paths)\n        for _, logical_drive in ipairs(winos.logical_drives()) do\n            table.insert(opt.paths, path.join(logical_drive, \"iverilog\", \"bin\"))\n        end\n    end\n\n    -- find program\n    local program = find_program(opt.program or \"vvp\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_wasm_ld.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_wasm_ld.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_program\")\n\n-- find ar\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local ar = find_wasm_ld()\n-- local ar, version = find_wasm_ld({program = \"wasm.ld\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"wasm.ld\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_wget.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_wget.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find wget\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local wget = find_wget()\n-- local wget, version = find_wget({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"wget\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_where.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_where.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- find where\n--\n-- @code\n-- local where = find_where()\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = \"/?\"\n    local program\n    if is_host(\"windows\") then\n        program = find_program(opt.program or \"where.exe\", opt)\n    end\n    return program\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_windbg.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_windbg.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find windbg\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\windbg.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local windbg = find_windbg()\n-- local windbg, version = find_windbg({version = true})\n-- local windbg, version = find_windbg({version = true, program = \"c:\\xxx\\windbg.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if os.host() ~= \"windows\" then\n        return\n    end\n\n    -- init options\n    opt        = opt or {}\n    opt.paths  = opt.paths or function ()\n        for _, reg in ipairs({\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\", \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\"}) do\n            return (val(\"reg \" .. reg) or \"\"):match(\"\\\"(.-)\\\"\")\n        end\n    end\n    opt.paths = table.wrap(opt.paths)\n    opt.check  = opt.check or function (program) if not os.isfile(program) then raise() end end\n\n    -- find program\n    local program = find_program(opt.program or \"windbg\", opt)\n    if not program then\n        program = find_program(\"windbgx\", opt)\n    end\n    return program\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_windres.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_windres.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\n\n-- we cannot run `windres --version` to check it, because llvm-mingw/windres always return non-zero\nfunction _check(program, opt)\n    local objectfile = os.tmpfile() .. \".o\"\n    local resourcefile  = os.tmpfile() .. \".rc\"\n    io.writefile(resourcefile, [[\n#include <winresrc.h>\n\nVS_VERSION_INFO VERSIONINFO\nFILEFLAGSMASK VS_FFI_FILEFLAGSMASK\nFILEFLAGS 0x0L\nFILEOS VOS_NT_WINDOWS32\nFILETYPE VFT_APP\nFILESUBTYPE VFT2_UNKNOWN\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"000004B0\"\n        BEGIN\n            VALUE \"ProductName\", \"xmake\"\n        END\n    END\nEND\n    ]])\n\n    os.runv(program, {\"-i\", resourcefile, \"-o\", objectfile}, {envs = opt.envs})\n    os.rm(resourcefile)\n    os.rm(objectfile)\nend\n\n-- find windres\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local windres = find_windres()\n-- local windres, version = find_windres({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    opt.check = function (program)\n        _check(program, opt)\n    end\n    return find_program(opt.program or \"windres\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_wine.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_wine.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find wine\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local wine = find_wine()\n-- local wine, version = find_wine({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"wine\", opt)\n\n    local version = nil\n    if program and opt and opt.version then\n        opt.parse = opt.parse or \"wine%-(%d+%.%d+%.%d+)\"\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_x64dbg.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_x64dbg.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find x64dbg\n--\n-- @param opt   the argument options, e.g. {version = true, program = \"c:\\xxx\\x64dbg.exe\"}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local x64dbg = find_x64dbg()\n-- local x64dbg, version = find_x64dbg({version = true})\n-- local x64dbg, version = find_x64dbg({version = true, program = \"c:\\xxx\\x64dbg.exe\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- not on windows?\n    if os.host() ~= \"windows\" then\n        return\n    end\n\n    -- init options\n    opt        = opt or {}\n    opt.paths  = opt.paths or function ()\n        for _, reg in ipairs({\"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\", \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger\"}) do\n            return (val(\"reg \" .. reg) or \"\"):match(\"\\\"(.-)\\\"\")\n        end\n    end\n    opt.paths = table.wrap(opt.paths)\n    opt.check  = opt.check or function (program) if not os.isfile(program) then raise() end end\n\n    -- find program\n    return find_program(opt.program or \"x64dbg\", opt)\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_xrepo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_xrepo.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find xz\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local xz = find_xrepo()\n-- local xz, version = find_xrepo({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or (is_host(\"windows\") and \"xrepo.bat\" or \"xrepo\"), opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_xz.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_xz.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find xz\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local xz = find_xz()\n-- local xz, version = find_xz({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"xz\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_yacc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_yacc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find yacc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local yacc = find_yacc()\n-- local yacc, version = find_yacc({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"yacc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_yasm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_yasm.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find yasm\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local yasm = find_yasm()\n-- local yasm, version = find_yasm({program = \"yasm\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"yasm\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_yum.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_yum.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find yum\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local yum = find_yum()\n-- local yum, version = find_yum({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"yum\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zig.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_zig.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zig\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zig = find_zig()\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"version\"\n    opt.command = opt.command or \"version\"\n\n    -- find program\n    local program = find_program(opt.program or \"zig\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zig_cc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_zig_cc.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zig_cc\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zig_cc = find_zig_cc()\n-- local zig_cc, version, hintname = find_zig_cc({program = \"zig cc\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"zig cc\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zig_cxx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_zig_cxx.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zig_cxx\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zig_cxx = find_zig_cxx()\n-- local zig_cxx, version, hintname = find_zig_cxx({program = \"zig c++\", version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"zig c++\", opt)\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zip.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_zip.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zip\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zip = find_zip()\n-- local zip, version = find_zip({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt         = opt or {}\n    opt.check   = opt.check or \"-v\"\n    opt.command = opt.command or \"-v\"\n\n    -- find program\n    local program = find_program(opt.program or \"zip\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zstd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      24bit-xjkp\n-- @file        find_xz.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zstd\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zstd = find_zstd()\n-- local zstd, version = find_zstd({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find program\n    local program = find_program(opt.program or \"zstd\", opt)\n\n    -- find program version\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n\n    -- ok?\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/detect/tools/find_zypper.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Lingfeng Fu\n-- @file        find_zypper.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\n\n-- find zypper\n--\n-- @param opt   the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local zypper = find_zypper()\n-- local zypper, version = find_zypper({version = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local program = find_program(opt.program or \"zypper\", opt)\n    local version = nil\n    if program and opt and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/devel/debugger/run.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        run.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.executable_path\")\nimport(\"private.action.run.runenvs\")\n\n-- run gdb\nfunction _run_gdb(program, argv, opt)\n    opt = opt or {}\n    local gdb = find_tool(\"gdb\", {program = config.get(\"debugger\")})\n    if not gdb then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n    table.insert(argv, 1, \"--args\")\n\n    -- run it\n    os.execv(gdb.program, argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run cuda-gdb\nfunction _run_cudagdb(program, argv, opt)\n    opt = opt or {}\n    local gdb = find_tool(\"cudagdb\", {program = config.get(\"debugger\")})\n    if not gdb then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n    table.insert(argv, 1, \"--args\")\n\n    -- run it\n    os.execv(gdb.program, argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run lldb\nfunction _run_lldb(program, argv, opt)\n    opt = opt or {}\n    local lldb = find_tool(\"lldb\", {program = config.get(\"debugger\")})\n    if not lldb then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, \"--\")\n    table.insert(argv, 1, program)\n    table.insert(argv, 1, \"-f\")\n\n    -- run it\n    os.execv(executable_path(lldb.program), argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run windbg\nfunction _run_windbg(program, argv, opt)\n    local windbg = find_tool(\"windbg\", {program = config.get(\"debugger\")})\n    if not windbg then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(windbg.program, argv, opt)\n    return true\nend\n\n-- run cuda-memcheck\nfunction _run_cudamemcheck(program, argv, opt)\n    local cudamemcheck = find_tool(\"cudamemcheck\", {program = config.get(\"debugger\")})\n    if not cudamemcheck then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    os.execv(cudamemcheck.program, argv, opt)\n    return true\nend\n\n-- run x64dbg\nfunction _run_x64dbg(program, argv, opt)\n    local x64dbg = find_tool(\"x64dbg\", {program = config.get(\"debugger\")})\n    if not x64dbg then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(x64dbg.program, argv, opt)\n    return true\nend\n\n-- run ollydbg\nfunction _run_ollydbg(program, argv, opt)\n    local ollydbg = find_tool(\"ollydbg\", {program = config.get(\"debugger\")})\n    if not ollydbg then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(ollydbg.program, argv, opt)\n    return true\nend\n\n-- run vsjitdebugger\nfunction _run_vsjitdebugger(program, argv, opt)\n    local vsjitdebugger = find_tool(\"vsjitdebugger\", {program = config.get(\"debugger\")})\n    if not vsjitdebugger then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(vsjitdebugger.program, argv, opt)\n    return true\nend\n\n-- run devenv\nfunction _run_devenv(program, argv, opt)\n    local devenv = find_tool(\"devenv\", {program = config.get(\"debugger\")})\n    if not devenv then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, \"/DebugExe\")\n    table.insert(argv, 2, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(devenv.program, argv, opt)\n    return true\nend\n\n-- run renderdoc\nfunction _run_renderdoc(program, argv, opt)\n    local renderdoc = find_tool(\"renderdoc\", {program = config.get(\"debugger\")})\n    if not renderdoc then\n        return false\n    end\n\n    -- build capture settings\n    local environment = {}\n    if opt.addenvs then\n        for name, values in pairs(opt.addenvs) do\n            table.insert(environment, {\n                separator = \"Platform style\",\n                type = \"Append\",\n                value = path.joinenv(values),\n                variable = name\n            })\n        end\n    end\n\n    if opt.setenvs then\n        for name, values in pairs(opt.setenvs) do\n            table.insert(environment, {\n                separator = \"Platform style\",\n                type = \"Set\",\n                value = path.joinenv(values),\n                variable = name\n            })\n        end\n    end\n\n    local settings = {\n        rdocCaptureSettings = 1,\n        settings = {\n            autoStart = false,\n            commandLine = table.concat(table.wrap(argv), \" \"),\n            environment = json.mark_as_array(environment),\n            executable = program,\n            inject = false,\n            numQueuedFrames = 0,\n            queuedFrameCap = 0,\n            workingDir = opt.curdir and path.absolute(opt.curdir) or \"\",\n            options = {\n                allowFullscreen = true,\n                allowVSync = true,\n                apiValidation = false,\n                captureAllCmdLists = false,\n                captureCallstacks = false,\n                captureCallstacksOnlyDraws = false,\n                debugOutputMute = true,\n                delayForDebugger = 0,\n                hookIntoChildren = false,\n                refAllResources = false,\n                verifyBufferAccess = false\n            }\n        }\n    }\n\n    -- save to temporary file\n    local capturefile = os.tmpfile() .. \".cap\"\n    json.savefile(capturefile, settings)\n\n    -- run renderdoc\n    opt.detach = true\n    opt.addenvs = nil\n    opt.setenvs = nil\n    os.execv(renderdoc.program, { capturefile }, opt)\n    return true\nend\n\n-- run gede\nfunction _run_gede(program, argv, opt)\n    opt = opt or {}\n\n    -- 'gede --version' return with non-zero code\n    local gede = find_tool(\"gede\", {program = config.get(\"debugger\"), norun = true})\n    if not gede then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n    table.insert(argv, 1, \"--args\")\n    table.insert(argv, 1, \"--no-show-config\")\n\n    -- run it\n    os.execv(gede.program, argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run seergdb\nfunction _run_seergdb(program, argv, opt)\n    opt = opt or {}\n    local seergdb = find_tool(\"seergdb\", {program = config.get(\"debugger\")})\n    if not seergdb then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n    table.insert(argv, 1, \"--start\")\n\n    -- run it\n    os.execv(seergdb.program, argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run rad debugger\nfunction _run_raddbg(program, argv, opt)\n    opt = opt or {}\n    local raddbg = find_tool(\"raddbg\", {program = config.get(\"debugger\")})\n    if not raddbg then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    opt.detach = true\n    os.execv(raddbg.program, argv, opt)\n    return true\nend\n\n-- run nnd\nfunction _run_nnd(program, argv, opt)\n    opt = opt or {}\n    local nnd = find_tool(\"nnd\", {program = config.get(\"debugger\")})\n    if not nnd then\n        return false\n    end\n\n    -- patch arguments\n    argv = argv or {}\n    table.insert(argv, 1, program)\n\n    -- run it\n    os.execv(nnd.program, argv, table.join(opt, {exclusive = true}))\n    return true\nend\n\n-- run program with debugger\n--\n-- @param program   the program name\n-- @param argv      the program rguments\n--\n-- @code\n--\n-- import(\"devel.debugger\")\n--\n-- debugger.run(\"test\")\n-- debugger.run(\"echo\", {\"hello xmake!\"})\n--\n-- @endcode\n--\nfunction main(program, argv, opt)\n\n    -- init debuggers\n    local debuggers =\n    {\n        {\"lldb\"        , _run_lldb}\n    ,   {\"gdb\"         , _run_gdb}\n    ,   {\"cudagdb\"     , _run_cudagdb}\n    ,   {\"cudamemcheck\", _run_cudamemcheck}\n    ,   {\"renderdoc\"   , _run_renderdoc}\n    ,   {\"gede\"        , _run_gede}\n    ,   {\"seergdb\"     , _run_seergdb}\n    }\n\n    -- for windows target or on windows?\n    local plat = config.plat() or os.host()\n    if plat == \"windows\" then\n        table.insert(debuggers, 1, {\"windbg\",           _run_windbg})\n        table.insert(debuggers, 1, {\"ollydbg\",          _run_ollydbg})\n        table.insert(debuggers, 1, {\"x64dbg\",           _run_x64dbg})\n        table.insert(debuggers, 1, {\"vsjitdebugger\",    _run_vsjitdebugger})\n        table.insert(debuggers, 1, {\"devenv\",           _run_devenv})\n        table.insert(debuggers, 1, {\"raddbg\",           _run_raddbg})\n    elseif plat == \"linux\" then\n        table.insert(debuggers, {\"nnd\", _run_nnd})\n    end\n\n    -- get debugger from configuration\n    opt = opt or {}\n    local debugger = config.get(\"debugger\")\n    if debugger then\n\n        -- try exactmatch first\n        debugger = debugger:lower()\n        local debuggername = path.basename(debugger)\n        for _, _debugger in ipairs(debuggers) do\n            if debuggername:startswith(_debugger[1]) then\n                if _debugger[2](program, argv, opt) then\n                    return\n                end\n            end\n        end\n\n        for _, _debugger in ipairs(debuggers) do\n            if debugger:find(_debugger[1]) then\n                if _debugger[2](program, argv, opt) then\n                    return\n                end\n            end\n        end\n    else\n        -- run debugger\n        for _, _debugger in ipairs(debuggers) do\n            if _debugger[2](program, argv, opt) then\n                return\n            end\n        end\n    end\n\n    -- no debugger\n    raise(\"debugger%s not found!\", debugger and (\"(\" .. debugger .. \")\") or \"\")\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/apply.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        apply.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- apply remote commits\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.apply(\"xxx.patch\")\n-- git.apply(\"xxx.diff\")\n--\n-- @endcode\n--\nfunction main(patchfile, opt)\n    opt = opt or {}\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n    local argv = {\"apply\", \"--reject\", \"--ignore-whitespace\"}\n    if opt.reverse then\n        table.insert(argv, \"-R\")\n    end\n    if opt.gitdir then\n        table.insert(argv, 1, \"--git-dir=\" .. opt.gitdir)\n    end\n    table.insert(argv, patchfile)\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/asgiturl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        asgiturl.lua\n--\n\n-- imports\nimport(\"checkurl\")\n\nlocal custom_protocol =\n{\n    [\"github:\"]     = \"https://github.com\"\n,   [\"gitlab:\"]     = \"https://gitlab.com\"\n,   [\"gitee:\"]      = \"https://gitee.com\"\n,   [\"bitbucket:\"]  = \"https://bitbucket.org\"\n}\n\n-- try to parse given url as a git url\n--\n-- @param url   url can be transformed to a git url\n--\n-- @return      a git url or nil, if failed\n--\n\nfunction main(url)\n\n    -- check\n    url = url:trim()\n    assert(#url > 0, \"provided URL is empty!\")\n\n    -- safe because all custom_protocol supports https\n    local lower = url:lower()\n    local n_url = url\n    if lower:startswith(\"http://\") then\n        n_url = \"https\" .. url:sub(#\"http\" + 1)\n        lower = n_url:lower()\n    end\n\n    for k, v in pairs(custom_protocol) do\n        if lower:startswith(k) then\n            local data = n_url:sub(#k + 1):split(\"/\")\n            if #data ~= 2 then return nil end\n            return v .. \"/\" .. data[1] .. \"/\" .. data[2] .. \".git\"\n        elseif lower:startswith(v) then\n            local data = n_url:sub(#v + 1):split(\"/\")\n            if #data ~= 2 then return nil end\n            return v .. \"/\" .. data[1] .. \"/\" .. (data[2]:endswith(\".git\") and data[2] or (data[2] .. \".git\"))\n        end\n    end\n\n    if checkurl(url) then\n        return url\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/devel/git/branch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        branch.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- get current branch\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local branch = git.branch()\n-- local branch = git.branch({repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init arguments\n    local argv = {\"branch\", \"--show-current\"}\n\n    -- trace\n    if option.get(\"verbose\") then\n        print(\"%s %s\", git.program, os.args(argv))\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- get current branch\n    local branch = os.iorunv(git.program, argv, {envs = envs, curdir = opt.repodir})\n    if branch then\n        branch = branch:trim()\n    end\n    return branch\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/branches.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        branches.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"ls_remote\")\n\n-- get all branches from url\n--\n-- @param url       the remote url, optional\n--\n-- @return          the branches\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local branches = git.branches(url)\n--\n-- @endcode\n--\nfunction main(url)\n    return ls_remote(\"heads\", url)\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/checkout.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        checkout.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"devel.git.support\")\nimport(\"lib.detect.find_tool\")\n\n-- checkout to given branch, tag or commit\n--\n-- @param commit    the commit, tag or branch\n-- @param opt       the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.checkout(\"master\", {repodir = \"/tmp/xmake\"})\n-- git.checkout(\"v1.0.1\", {repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction main(commit, opt)\n    opt = opt or {}\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n\n    -- @see https://github.com/xmake-io/xmake/issues/6071\n    -- https://github.blog/open-source/git/bring-your-monorepo-down-to-size-with-sparse-checkout/\n    if opt.includes and support.can_sparse_checkout() then\n        os.vrunv(git.program, {\"sparse-checkout\", \"init\", \"--cone\"}, {curdir = opt.repodir})\n        os.vrunv(git.program, table.join({\"sparse-checkout\", \"set\"}, opt.includes), {curdir = opt.repodir})\n    end\n\n    table.insert(argv, \"checkout\")\n    table.insert(argv, commit)\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/checkurl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        checkurl.lua\n--\n\n-- check git url\n--\n-- @param url   is git url?\n--\n-- @return      true or false\n--\nfunction main(url)\n    return url:endswith(\".git\") or url:startswith(\"git://\") or os.isdir(url .. \".git\")\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/clean.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clean.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- clean files\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.clean()\n-- git.clean({repodir = \"/tmp/xmake\", force = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n    table.insert(argv, \"clean\")\n    table.insert(argv, \"-d\")\n\n    -- verbose?\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n\n    -- force?\n    if opt.force then\n        table.insert(argv, \"-f\")\n    end\n\n    -- remove all files and does not use the standard ignore rules\n    if opt.all then\n        table.insert(argv, \"-x\")\n    end\n\n    -- clean it\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/clone.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clone.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\nimport(\"devel.git.support\")\n\n-- clone url\n--\n-- @param url   the git url\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.clone(\"git@github.com:xmake-io/xmake.git\")\n-- git.clone(\"git@github.com:xmake-io/xmake.git\", {depth = 1, treeless = true, branch = \"master\", outputdir = \"/tmp/xmake\", longpaths = true})\n--\n-- @endcode\n--\nfunction main(url, opt)\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {\"clone\", url}\n\n    -- set branch\n    opt = opt or {}\n    if opt.branch then\n        table.insert(argv, \"-b\")\n        table.insert(argv, opt.branch)\n    end\n\n    -- set depth\n    if opt.depth then\n        table.insert(argv, \"--depth\")\n        table.insert(argv, type(opt.depth) == \"number\" and tostring(opt.depth) or opt.depth)\n    end\n\n    -- treeless?\n    -- @see https://github.com/xmake-io/xmake/issues/5507\n    if opt.treeless and support.can_treeless() then\n        table.insert(argv, \"--filter=tree:0\")\n    end\n\n    -- no checkout\n    if opt.checkout == false then\n        table.insert(argv, \"--no-checkout\")\n    end\n\n    -- recursive?\n    if opt.recursive then\n        table.insert(argv, \"--recursive\")\n    end\n\n    -- clone for submodules\n    if opt.recurse_submodules then\n        table.insert(argv, \"--recurse-submodules\")\n    end\n    if opt.shallow_submodules and support.can_shallow_submodules() then\n        table.insert(argv, \"--shallow-submodules\")\n    end\n\n    -- use longpaths, we need it on windows\n    if opt.longpaths then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.longpaths=true\")\n    end\n\n    -- set fsmonitor\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n\n    -- set core.autocrlf\n    if opt.autocrlf then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.autocrlf=true\")\n    elseif opt.autocrlf == false then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.autocrlf=false\")\n    end\n\n    -- set outputdir\n    if opt.outputdir then\n        table.insert(argv, path.translate(opt.outputdir))\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- clone it\n    if opt.verbose then\n        os.execv(git.program, argv, {envs = envs})\n    else\n        os.vrunv(git.program, argv, {envs = envs})\n    end\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/init.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        init.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- init project\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.init()\n-- git.init({repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {\"init\"}\n\n    -- verbose?\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n\n    -- init it\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/lastcommit.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lastcommit.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- get last commit in git repository\n--\n-- @param opt       the options, e.g. {repodir = ..}\n--\n-- @return          the last commit\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local lastcommit = git.lastcommit({repodir = ..})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init arguments\n    local argv = {\"rev-parse\", \"HEAD\"}\n\n    -- trace\n    if option.get(\"verbose\") then\n        print(\"%s %s\", git.program, os.args(argv))\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- get last commit\n    local lastcommit = os.iorunv(git.program, argv, {envs = envs, curdir = opt.repodir})\n    if lastcommit then\n        lastcommit = lastcommit:trim()\n    end\n    return lastcommit\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/ls_remote.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ls_remote.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- ls_remote to given branch, tag or commit\n--\n-- @param reftype   the reference type, \"tags\", \"heads\" and \"refs\"\n-- @param url       the remote url, optional\n--\n-- @return          the tags, heads or refs\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local tags   = git.ls_remote(\"tags\", url)\n-- local heads  = git.ls_remote(\"heads\", url)\n-- local refs   = git.ls_remote(\"refs\")\n--\n-- @endcode\n--\nfunction main(reftype, url)\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init reference type\n    reftype = reftype or \"refs\"\n\n    -- init arguments\n    local argv = {\"ls-remote\", \"--\" .. reftype, url or \".\"}\n\n    -- trace\n    if option.get(\"verbose\") then\n        print(\"%s %s\", git.program, os.args(argv))\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- get refs\n    local data = os.iorunv(git.program, argv, {envs = envs})\n\n    -- get commmits and tags\n    local refs = {}\n    for _, line in ipairs(data:split('\\n')) do\n\n        -- parse commit and ref\n        local refinfo = line:split('%s')\n\n        -- get commit\n        local commit = refinfo[1]\n\n        -- get ref\n        local ref = refinfo[2]\n\n        -- save this ref\n        local prefix = reftype == \"refs\" and \"refs/\" or (\"refs/\" .. reftype .. \"/\")\n        if ref and ref:startswith(prefix) and commit and #commit == 40 then\n            table.insert(refs, ref:sub(#prefix + 1))\n        end\n    end\n\n    -- ok\n    return refs\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/pull.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pull.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"devel.git.remote\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- pull remote commits\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.pull()\n-- git.pull({remote = \"origin\", tags = true, branch = \"master\", repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n    table.insert(argv, \"pull\")\n\n    -- set remote\n    table.insert(argv, opt.remote or \"origin\")\n\n    -- set branch\n    if opt.branch then\n        table.insert(argv, opt.branch)\n    end\n\n    -- set tags\n    if opt.tags then\n        table.insert(argv, \"--tags\")\n    end\n\n    if opt.force then\n        table.insert(argv, \"-f\")\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config()\n    if proxy_conf then\n        -- get proxy configuration from the current remote url\n        local url = remote.get_url({remote = opt.remote or \"origin\", repodir = opt.repodir})\n        if url then\n            proxy_conf = proxy.config(url)\n        end\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- pull it\n    os.vrunv(git.program, argv, {envs = envs, curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/push.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        push.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"devel.git.remote\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\nimport(\"branch\", {alias = \"git_branch\"})\n\n-- push to given remote url and branch\n--\n-- @param url the remote url\n-- @param opt the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.push(url, {branch = \"master, remote_branch = \"xxx\", force = true, \"repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction main(url, opt)\n    opt = opt or {}\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n    table.insert(argv, \"push\")\n    table.insert(argv, url)\n    if opt.force then\n        table.insert(argv, \"--force\")\n    end\n    local branch = opt.branch or git_branch(opt)\n    assert(branch, \"git branch not found!\")\n    if opt.remote_branch then\n        branch = branch .. \":\" .. opt.remote_branch\n    end\n    table.insert(argv, branch)\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config()\n    if proxy_conf then\n        -- get proxy configuration from the remote url\n        -- if url is a remote name, get its URL; otherwise use url directly\n        local remote_url = url\n        if not url:find(\"://\") and not url:find(\"@\") then\n            -- looks like a remote name, get its URL\n            remote_url = remote.get_url({remote = url, repodir = opt.repodir})\n        end\n        if remote_url then\n            proxy_conf = proxy.config(remote_url)\n        end\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    if opt.verbose then\n        os.execv(git.program, argv, {envs = envs, curdir = opt.repodir})\n    else\n        os.vrunv(git.program, argv, {envs = envs, curdir = opt.repodir})\n    end\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/refs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        refs.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"ls_remote\")\n\n-- get all refs from url, contains tags and branchs\n--\n-- @param url       the remote url, optional\n--\n-- @return          the tags, branches\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local tags, branches = git.refs(url)\n--\n-- @endcode\n--\nfunction main(url)\n\n    -- get refs\n    local refs = ls_remote(\"refs\", url)\n    if not refs or #refs == 0 then\n        return {}, {}\n    end\n\n    -- get tags and branches\n    local tags = {}\n    local branches = {}\n    for _, ref in ipairs(refs) do\n        if ref:startswith(\"tags/\") then\n            table.insert(tags, ref:sub(6))\n        elseif ref:startswith(\"heads/\") then\n            table.insert(branches, ref:sub(7))\n        end\n    end\n\n    -- ok\n    return tags, branches\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/remote.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        remote.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- get remote url\n--\n-- @param opt   the argument options\n--              - remote: the remote name, default is \"origin\"\n--              - repodir: the repository directory\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local url = git.remote.get_url()\n-- local url = git.remote.get_url({remote = \"origin\", repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction get_url(opt)\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init arguments\n    local argv = {\"remote\", \"get-url\", opt.remote or \"origin\"}\n\n    -- trace\n    if option.get(\"verbose\") then\n        print(\"%s %s\", git.program, os.args(argv))\n    end\n\n    -- get remote url\n    local url = try { function() return os.iorunv(git.program, argv, {curdir = opt.repodir}) end }\n    if url then\n        url = url:trim()\n    end\n    return url\nend\n\n-- set remote url\n--\n-- @param url   the remote url\n-- @param opt   the argument options\n--              - remote: the remote name, default is \"origin\"\n--              - repodir: the repository directory\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.remote.set_url(\"https://github.com/xmake-io/xmake-repo.git\")\n-- git.remote.set_url(\"https://github.com/xmake-io/xmake-repo.git\", {remote = \"origin\", repodir = \"/tmp/xmake\"})\n--\n-- @endcode\n--\nfunction set_url(url, opt)\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init arguments\n    local argv = {\"remote\", \"set-url\", opt.remote or \"origin\", url}\n\n    -- set remote url\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n\n"
  },
  {
    "path": "xmake/modules/devel/git/reset.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        reset.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- reset files\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.reset()\n-- git.reset({repodir = \"/tmp/xmake\", force = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n    table.insert(argv, \"reset\")\n\n    -- verbose?\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n\n    -- hard?\n    if opt.hard then\n        table.insert(argv, \"--hard\")\n    end\n\n    -- soft?\n    if opt.soft then\n        table.insert(argv, \"--soft\")\n    end\n\n    -- keep?\n    if opt.keep then\n        table.insert(argv, \"--keep\")\n    end\n\n    -- reset to the given commit\n    if opt.commit then\n        table.insert(argv, opt.commit)\n    end\n\n    -- reset it\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/submodule/clean.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clean.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- clean files\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.clean()\n-- git.clean({repodir = \"/tmp/xmake\", force = true})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find git\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n    table.join2(argv, \"submodule\", \"foreach\", \"--recursive\", \"git\", \"clean\", \"-d\")\n\n    -- verbose?\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n\n    -- force?\n    if opt.force then\n        table.insert(argv, \"-f\")\n    end\n\n    -- remove all files and does not use the standard ignore rules\n    if opt.all then\n        table.insert(argv, \"-x\")\n    end\n\n    -- clean it\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/submodule/reset.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        reset.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- reset files\n--\n-- @param opt   the argument options\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- git.reset()\n-- git.reset({repodir = \"/tmp/xmake\", force = true})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n\n    -- use longpaths, we need it on windows\n    if opt.longpaths then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.longpaths=true\")\n    end\n    table.join2(argv, \"submodule\", \"foreach\", \"--recursive\", \"git\", \"reset\")\n\n    -- verbose?\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n\n    -- hard?\n    if opt.hard then\n        table.insert(argv, \"--hard\")\n    end\n\n    -- soft?\n    if opt.soft then\n        table.insert(argv, \"--soft\")\n    end\n\n    -- keep?\n    if opt.keep then\n        table.insert(argv, \"--keep\")\n    end\n\n    -- reset to the given commit\n    if opt.commit then\n        table.insert(argv, opt.commit)\n    end\n\n    -- reset it\n    os.vrunv(git.program, argv, {curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/submodule/update.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        update.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"devel.git.remote\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- update submodule\n--\n-- @param opt       the argument options, e.g. repodir, init, remote, force, checkout, merge, rebase, recursive, reference, paths\n--\n-- @code\n--\n-- import(\"devel.git.submodule\")\n--\n-- submodule.update({repodir = \"/tmp/xmake\", init = true, remote = true})\n-- submodule.update({repodir = \"/tmp/xmake\", recursive = true, longpaths = true, reference = \"xxx\", paths = \"xxx\"})\n--\n-- @endcode\n--\nfunction main(opt)\n    opt = opt or {}\n    local git = assert(find_tool(\"git\"), \"git not found!\")\n\n    -- init argv\n    local argv = {}\n    if opt.fsmonitor then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=true\")\n    else\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.fsmonitor=false\")\n    end\n\n    -- use longpaths, we need it on windows\n    if opt.longpaths then\n        table.insert(argv, \"-c\")\n        table.insert(argv, \"core.longpaths=true\")\n    end\n\n    table.insert(argv, \"submodule\")\n    table.insert(argv, \"update\")\n    for _, name in ipairs({\"init\", \"remote\", \"force\", \"checkout\", \"merge\", \"rebase\", \"recursive\"}) do\n        if opt[name] then\n            table.insert(argv, \"--\" .. name)\n        end\n    end\n    if opt.reference then\n        table.insert(argv, \"--reference\")\n        table.insert(argv, opt.reference)\n    end\n    if opt.paths then\n        table.join2(argv, opt.paths)\n    end\n\n    -- use proxy?\n    local envs\n    local proxy_conf = proxy.config()\n    if proxy_conf then\n        -- get proxy configuration from the current remote url\n        local url = remote.get_url({remote = opt.remote or \"origin\", repodir = opt.repodir})\n        if url then\n            proxy_conf = proxy.config(url)\n        end\n        envs = {ALL_PROXY = proxy_conf}\n    end\n\n    -- update it\n    os.vrunv(git.program, argv, {envs = envs, curdir = opt.repodir})\nend\n"
  },
  {
    "path": "xmake/modules/devel/git/support.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        support.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\n\n-- get git version\nfunction _git_version()\n    local git_version = _g.git_version\n    if git_version == nil then\n        local git = assert(find_tool(\"git\", {version = true}), \"git not found!\")\n        if git.version then\n            git_version = git.version\n        end\n        _g.git_version = git_version or false\n    end\n    return git_version or nil\nend\n\n-- can clone tag?\n-- @see https://github.com/xmake-io/xmake/issues/4151\nfunction can_clone_tag()\n    local can = _g.can_clone_tag\n    if can == nil then\n        local git_version = _git_version()\n        if git_version and semver.compare(git_version, \"1.7.10\") >= 0 then\n            can = true\n        end\n        _g.can_clone_tag = can or false\n    end\n    return can or false\nend\n\n-- can clone with --shallow-submodules?\n-- @see https://github.com/xmake-io/xmake/issues/4151\nfunction can_shallow_submodules()\n    local can = _g.can_shallow_submodules\n    if can == nil then\n        local git_version = _git_version()\n        if git_version and semver.compare(git_version, \"2.9.0\") >= 0 then\n            can = true\n        end\n        _g.can_shallow_submodules = can or false\n    end\n    return can or false\nend\n\n-- can clone with --filter=tree:0?\n-- @see https://github.com/xmake-io/xmake/issues/6246\nfunction can_treeless()\n    local can = _g.can_treeless\n    if can == nil then\n        local git_version = _git_version()\n        if git_version and semver.compare(git_version, \"2.16.0\") >= 0 then\n            can = true\n        end\n        _g.can_treeless = can or false\n    end\n    return can or false\nend\n\n-- can sparse checkout?\n-- @see https://github.com/xmake-io/xmake/issues/6071\n-- https://github.blog/open-source/git/bring-your-monorepo-down-to-size-with-sparse-checkout/\nfunction can_sparse_checkout()\n    local can = _g.can_sparse_checkout\n    if can == nil then\n        local git_version = _git_version()\n        if git_version and semver.compare(git_version, \"2.25.0\") >= 0 then\n            can = true\n        end\n        _g.can_sparse_checkout = can or false\n    end\n    return can or false\nend\n\n"
  },
  {
    "path": "xmake/modules/devel/git/tags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tags.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"ls_remote\")\n\n-- get all tags from url\n--\n-- @param url       the remote url, optional\n--\n-- @return          the tags\n--\n-- @code\n--\n-- import(\"devel.git\")\n--\n-- local tags = git.tags(url)\n--\n-- @endcode\n--\nfunction main(url)\n    return ls_remote(\"tags\", url)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_bigendian.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      CarbeneHu\n-- @file        check_bigendian.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxxsnippets\")\n\nlocal check_bigendian_template = [[\n#include <inttypes.h>\n/* A 16 bit integer is required. */\ntypedef uint16_t byteorder_int16_t;\n\n/* On a little endian machine, these 16bit ints will give \"THIS IS LITTLE ENDIAN.\"\n    On a big endian machine the characters will be exchanged pairwise. */\nconst byteorder_int16_t info_little[] =  {0x4854, 0x5349, 0x4920, 0x2053, 0x494c, 0x5454, 0x454c, 0x4520, 0x444e, 0x4149, 0x2e4e, 0x0000};\n\n/* on a big endian machine, these 16bit ints will give \"THIS IS BIG ENDIAN.\"\n    On a little endian machine the characters will be exchanged pairwise. */\nconst byteorder_int16_t info_big[] =     {0x5448, 0x4953, 0x2049, 0x5320, 0x4249, 0x4720, 0x454e, 0x4449, 0x414e, 0x2e2e, 0x0000};\n\nint main(int argc, char *argv[])\n{\n  int require = 0;\n  require += info_little[argc];\n  require += info_big[argc];\n  (void)argv;\n  return require;\n}]]\n\nlocal function _byteorder_binary_match(content)\n  local match = content:match(\"THIS IS BIG ENDIAN\")\n  return match and true or false\nend\n\n-- check the endianness of the compiler\n--\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = \"stdio.h\"\n--                  , configs = {defines = \"xx\", cxflags = \"\"}}\n--\n-- @return          Boolean value whether the compiler is big-endian\n--\n-- @code\n-- local is_bigendian = check_bigendian()\n-- @endcode\n--\nfunction main(opt)\n    local snippets = check_bigendian_template\n    local ok, is_bigendian = check_cxxsnippets(snippets, table.join(table.wrap(opt), {binary_match = _byteorder_binary_match}))\n    if ok then\n        return is_bigendian\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_csnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_csnippets.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- check the given c snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option]\n--                  , types = {\"wchar_t\", \"char*\"}, includes = \"stdio.h\", funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"}\n--                  , configs = {defines = \"xx\", cxflags = \"\"}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = check_csnippets(\"void test() {}\")\n-- local ok = check_csnippets({\"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok = check_csnippets({snippet_name = \"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(snippets, opt)\n    return check_cxsnippets(snippets, table.join(table.wrap(opt), {sourcekind = \"cc\"}))\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_cxsnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxsnippets.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.language.language\")\n\n-- get function name\n--\n-- sigsetjmp\n-- sigsetjmp((void*)0, 0)\n-- sigsetjmp{sigsetjmp((void*)0, 0);}\n-- sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\nfunction _funcname(funcinfo)\n\n    -- parse function name\n    local name = string.match(funcinfo, \"(.+){.+}\")\n    if name == nil then\n        local pos = funcinfo:find(\"%(\")\n        if pos then\n            name = funcinfo:sub(1, pos - 1)\n        else\n            name = funcinfo\n        end\n    end\n\n    -- ok\n    return name:trim()\nend\n\n-- get function code\n--\n-- sigsetjmp\n-- sigsetjmp((void*)0, 0)\n-- sigsetjmp{sigsetjmp((void*)0, 0);}\n-- sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\nfunction _funccode(funcinfo)\n    local code = string.match(funcinfo, \".+{(.+)}\")\n    if code == nil then\n        local pos = funcinfo:find(\"%(\")\n        if pos then\n            code = funcinfo\n        else\n            code = string.format(\"volatile void* p%s = (void*)&%s; if (p%s) {}\", funcinfo, funcinfo, funcinfo)\n        end\n    end\n    return code\nend\n\n-- make source code\nfunction _sourcecode(snippets, opt)\n\n    -- has main()?\n    local has_main = false\n    for _, snippet in pairs(snippets) do\n        -- find int main(int argc, char** argv) {}\n        if snippet:find(\"int%s+main%s*%(.-%)%s*{\") then\n            has_main = true\n            break\n        end\n    end\n\n    -- add includes\n    local sourcecode = \"\"\n    local includes = table.wrap(opt.includes)\n    if not has_main and opt.tryrun and opt.output then\n        table.insert(includes, \"stdio.h\")\n    end\n    for _, include in ipairs(includes) do\n        sourcecode = format(\"%s\\n#include <%s>\", sourcecode, include)\n    end\n    sourcecode = sourcecode .. \"\\n\"\n\n    -- add types\n    for _, typename in ipairs(opt.types) do\n        sourcecode = format(\"%s\\ntypedef %s __type_%s;\", sourcecode, typename, typename:gsub(\"[^%a]\", \"_\"))\n    end\n    sourcecode = sourcecode .. \"\\n\"\n\n    -- we just add all snippets if has main function\n    -- @see https://github.com/xmake-io/xmake/issues/3527\n    if has_main then\n        for _, snippet in pairs(snippets) do\n            sourcecode = sourcecode .. \"\\n\" .. snippet\n        end\n        sourcecode = sourcecode .. \"\\n\"\n        return sourcecode\n    end\n\n    -- add snippets (build only)\n    if not opt.tryrun then\n        for _, snippet in pairs(snippets) do\n            sourcecode = sourcecode .. \"\\n\" .. snippet\n        end\n        sourcecode = sourcecode .. \"\\n\"\n    end\n\n    -- enter main function\n    sourcecode = sourcecode .. \"int main(int argc, char** argv)\\n{\\n\"\n\n    -- add funcs\n    for _, funcinfo in ipairs(opt.funcs) do\n        sourcecode = format(\"%s\\n    %s;\", sourcecode, _funccode(funcinfo))\n    end\n\n    -- add snippets (tryrun)\n    if opt.tryrun then\n        for _, snippet in pairs(snippets) do\n            sourcecode = sourcecode .. \"\\n\" .. snippet\n        end\n        if opt.output then\n            sourcecode = sourcecode .. \"\\nfflush(stdout);\\n\"\n        end\n        sourcecode = sourcecode .. \"\\n}\\n\" -- we need return exit code in snippet\n    else\n        -- leave main function\n        sourcecode = sourcecode .. \"\\n    return 0;\\n}\\n\"\n    end\n    return sourcecode\nend\n\n-- check the given c/c++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], sourcekind = \"[cc|cxx|mm|mxx]\"\n--                  , types = {\"wchar_t\", \"char*\"}, includes = \"stdio.h\", funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"}\n--                  , configs = {defines = \"xx\", cxflags = \"\"}\n--                  , tryrun = true, output = true}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok, output_or_errors = check_cxsnippets(\"void test() {}\")\n-- local ok, output_or_errors = check_cxsnippets({\"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok, output_or_errors = check_cxsnippets({snippet_name = \"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok, output_or_errors = check_cxsnippets([[\n--  int test() {\n--      return (sizeof(int) == 4)? 0 : -1;\n--  }\n--  int main(int argc, char** argv) {\n--      return test();\n--  }]], {tryrun = true})\n-- @endcode\n--\nfunction main(snippets, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init snippets\n    snippets = snippets or {}\n\n    -- get configs\n    local configs = opt.configs or opt.config\n\n    -- get links\n    local links = {}\n    local target = opt.target\n    if configs and configs.links then\n        table.join2(links, configs.links)\n    end\n    if target and target:type() ~= \"package\" then\n        table.join2(links, target:get(\"links\"))\n    end\n    if configs and configs.syslinks then\n        table.join2(links, configs.syslinks)\n    end\n    if target and target:type() ~= \"package\" then\n        table.join2(links, opt.target:get(\"syslinks\"))\n    end\n\n    -- get types\n    local types = table.wrap(opt.types)\n\n    -- get includes\n    local includes = table.wrap(opt.includes)\n\n    -- get funcs\n    local funcs = {}\n    for _, funcinfo in ipairs(opt.funcs) do\n        table.insert(funcs, _funcname(funcinfo))\n    end\n\n    -- make source code\n    local sourcecode = _sourcecode(snippets, opt)\n\n    -- get c/c++ extension\n    local extension = \".c\"\n    local sourcekind = opt.sourcekind\n    if sourcekind then\n        extension = table.wrap(language.sourcekinds()[sourcekind])[1] or \".c\"\n    end\n\n    -- make the source file\n    -- @note we use fixed temporary filenames in order to better cache the compilation results for build_cache.\n    local tmpfile = os.tmpfile(sourcecode)\n    local sourcefile = tmpfile .. extension\n    local objectfile = os.tmpfile() .. \".o\"\n    local binaryfile = objectfile:gsub(\"%.o$\", \".b\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, sourcecode)\n    end\n\n    -- @note cannot cache result, all conditions will be changed\n    -- attempt to compile it\n    local errors = nil\n    local ok, output = try\n    {\n        function ()\n            if option.get(\"diagnosis\") then\n                cprint(\"${dim}> %s\", compiler.compcmd(sourcefile, objectfile, opt))\n            end\n            opt = table.clone(opt)\n            opt.build_warnings = false\n            compiler.compile(sourcefile, objectfile, opt)\n            if #links > 0 or opt.tryrun or opt.binary_match then\n                if option.get(\"diagnosis\") then\n                    cprint(\"${dim}> %s\", linker.linkcmd(\"binary\", {\"cc\", \"cxx\"}, objectfile, binaryfile, opt))\n                end\n                linker.link(\"binary\", {\"cc\", \"cxx\"}, objectfile, binaryfile, opt)\n            end\n            if opt.tryrun then\n                if opt.output then\n                    local output = os.iorun(binaryfile)\n                    if output then\n                        output = output:trim()\n                    end\n                    return true, output\n                else\n                    os.vrun(binaryfile)\n                end\n            end\n            local binary_match = opt.binary_match\n            if binary_match then\n                local content = io.readfile(binaryfile, {encoding = \"binary\"})\n                local match = type(binary_match) == \"function\" and binary_match(content) or content:match(binary_match)\n                if match ~= nil then\n                    return true, match\n                end\n            end\n            return true\n        end,\n        catch { function (errs) errors = errs end }\n    }\n\n    -- remove some files\n    os.tryrm(objectfile)\n    os.tryrm(binaryfile)\n\n    -- trace\n    if opt.verbose or option.get(\"verbose\") or option.get(\"diagnosis\") then\n        local kind = \"c\"\n        if sourcekind == \"cxx\" then\n            kind = \"c++\"\n        elseif sourcekind == \"mxx\" then\n            kind = \"objc++\"\n        elseif sourcekind == \"cc\" then\n            kind = \"c\"\n        elseif sourcekind == \"mm\" then\n            kind = \"objc\"\n        end\n        if #includes > 0 then\n            cprint(\"${dim}> checking for %s includes(%s)\", kind, table.concat(includes, \", \"))\n        end\n        if #types > 0 then\n            cprint(\"${dim}> checking for %s types(%s)\", kind, table.concat(types, \", \"))\n        end\n        if #funcs > 0 then\n            cprint(\"${dim}> checking for %s funcs(%s)\", kind, table.concat(funcs, \", \"))\n        end\n        if #links > 0 then\n            cprint(\"${dim}> checking for %s links(%s)\", kind, table.concat(links, \", \"))\n        end\n        for idx_or_name, snippet in pairs(snippets) do\n            local name = idx_or_name\n            if type(name) == \"number\" then\n                name = snippet:sub(1, 16)\n            end\n            cprint(\"${dim}> checking for %s snippet(%s)\", kind, name)\n        end\n    end\n    if errors and option.get(\"diagnosis\") and #tostring(errors) > 0 then\n        cprint(\"${color.warning}checkinfo:${clear dim} %s\", errors)\n    end\n    return ok, ok and output or errors\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_cxxsnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_cxxsnippets.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- check the given c++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option]\n--                  , types = {\"wchar_t\", \"char*\"}, includes = \"stdio.h\", funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"}\n--                  , configs = {defines = \"xx\", cxflags = \"\"}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = check_cxxsnippets(\"void test() {}\")\n-- local ok = check_cxxsnippets({\"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok = check_cxxsnippets({snippet_name = \"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(snippets, opt)\n    return check_cxsnippets(snippets, table.join(table.wrap(opt), {sourcekind = \"cxx\"}))\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_fcsnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_fcsnippets.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\n\n-- make source code\nfunction _sourcecode(snippets, opt)\n    local sourcecode = \"\"\n    for _, snippet in pairs(snippets) do\n        sourcecode = sourcecode .. \"\\n\" .. snippet\n    end\n    sourcecode = sourcecode .. \"\\n\"\n    return sourcecode\nend\n\n-- check the given fortran snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], linkerkind = \"fc\", \"cxx\"\n--                  , configs = {defines = \"xx\", fcflags = \"\"}\n--                  , tryrun = true, output = true}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok, output_or_errors = check_fcsnippets([[\n-- program hello\n--  print *, \"Hello World!\"\n-- end program hello\n--  ]], {tryrun = true})\n-- @endcode\n--\nfunction main(snippets, opt)\n    opt = opt or {}\n    snippets = snippets or {}\n\n    -- get configs\n    local configs = opt.configs or opt.config\n\n    -- get links\n    local links = {}\n    local target = opt.target\n    if configs and configs.links then\n        table.join2(links, configs.links)\n    end\n    if target and target:type() ~= \"package\" then\n        table.join2(links, target:get(\"links\"))\n    end\n    if configs and configs.syslinks then\n        table.join2(links, configs.syslinks)\n    end\n    if target and target:type() ~= \"package\" then\n        table.join2(links, opt.target:get(\"syslinks\"))\n    end\n\n    -- make source code\n    local sourcecode = _sourcecode(snippets, opt)\n\n    -- make the source file\n    -- @note we use fixed temporary filenames in order to better cache the compilation results for build_cache.\n    local tmpfile = os.tmpfile(sourcecode)\n    local sourcefile = tmpfile .. \".f90\"\n    local objectfile = os.tmpfile() .. \".o\"\n    local binaryfile = objectfile:gsub(\"%.o$\", \".b\")\n    if not os.isfile(sourcefile) then\n        io.writefile(sourcefile, sourcecode)\n    end\n\n    -- @note cannot cache result, all conditions will be changed\n    -- attempt to compile it\n    local errors = nil\n    local ok, output = try\n    {\n        function ()\n            if option.get(\"diagnosis\") then\n                cprint(\"${dim}> %s\", compiler.compcmd(sourcefile, objectfile, opt))\n            end\n            opt = table.clone(opt)\n            opt.build_warnings = false\n            compiler.compile(sourcefile, objectfile, opt)\n            local linkerkind = opt.linkerkind or \"fc\"\n            if #links > 0 or opt.tryrun or opt.binary_match then\n                if option.get(\"diagnosis\") then\n                    cprint(\"${dim}> %s\", linker.linkcmd(\"binary\", linkerkind, objectfile, binaryfile, opt))\n                end\n                linker.link(\"binary\", linkerkind, objectfile, binaryfile, opt)\n            end\n            if opt.tryrun then\n                if opt.output then\n                    local output = os.iorun(binaryfile)\n                    if output then\n                        output = output:trim()\n                    end\n                    return true, output\n                else\n                    os.vrun(binaryfile)\n                end\n            end\n            local binary_match = opt.binary_match\n            if binary_match then\n                local content = io.readfile(binaryfile, {encoding = \"binary\"})\n                local match = type(binary_match) == \"function\" and binary_match(content) or content:match(binary_match)\n                if match ~= nil then\n                    return true, match\n                end\n            end\n            return true\n        end,\n        catch { function (errs) errors = errs end }\n    }\n\n    -- remove some files\n    os.tryrm(objectfile)\n    os.tryrm(binaryfile)\n\n    -- trace\n    if opt.verbose or option.get(\"verbose\") or option.get(\"diagnosis\") then\n        if #links > 0 then\n            cprint(\"${dim}> checking for fortran links(%s)\", table.concat(links, \", \"))\n        end\n        for idx_or_name, snippet in pairs(snippets) do\n            local name = idx_or_name\n            if type(name) == \"number\" then\n                name = snippet:sub(1, 16)\n            end\n            cprint(\"${dim}> checking for fortran snippet(%s)\", name)\n        end\n    end\n    if errors and option.get(\"diagnosis\") and #tostring(errors) > 0 then\n        cprint(\"${color.warning}checkinfo:${clear dim} %s\", errors)\n    end\n    return ok, ok and output or errors\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_importfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_importfiles.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.pkgconfig\")\nimport(\"package.manager.cmake.find_package\", {alias = \"cmake_find_package\"})\n\n-- check the given importfiles for pkgconfig/cmake\n--\n-- @param names the import filenames (without .pc/.cmake suffix), e.g. pkgconfig::libxml-2.0, cmake::CURL\n-- @param opt   the argument options, e.g. { verbose = true, configdirs = {\"lib\"}}\n--\nfunction main(names, opt)\n    local verbose\n    if opt.verbose or option.get(\"verbose\") or option.get(\"diagnosis\") then\n        verbose = true\n    end\n    for _, name in ipairs(names) do\n        local kind\n        local parts = name:split(\"::\")\n        if #parts == 2 then\n            kind = parts[1]\n            name = parts[2]\n        end\n        if kind == nil then\n            kind = \"pkgconfig\"\n        end\n        if verbose then\n            cprint(\"${dim}> checking for %s/%s\", kind, name)\n        end\n        if kind == \"pkgconfig\" then\n            opt.configdirs = opt.PKG_CONFIG_PATH\n            local result = pkgconfig.libinfo(name, opt)\n            if verbose and result then\n                print(result)\n            end\n            if not result then\n                return false, string.format(\"pkgconfig/%s.pc not found!\", name)\n            end\n        elseif kind == \"cmake\" then\n            if opt.CMAKE_PREFIX_PATH then\n                opt.configs = opt.configs or {}\n                opt.configs.envs = opt.configs.envs or {}\n                opt.configs.envs.CMAKE_PREFIX_PATH = path.joinenv(table.wrap(opt.CMAKE_PREFIX_PATH))\n            end\n            local result = cmake_find_package(name, opt)\n            if verbose and result then\n                print(result)\n            end\n            if not result then\n                return false, string.format(\"cmake/%s.cmake not found!\", name)\n            end\n        end\n    end\n    return true\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_msnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_msnippets.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- check the given c snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option]\n--                  , types = {\"wchar_t\", \"char*\"}, includes = \"stdio.h\", funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"}\n--                  , configs = {defines = \"xx\", mxflags = \"\"}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = check_msnippets(\"void test() {}\")\n-- local ok = check_msnippets({\"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok = check_msnippets({snippet_name = \"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(snippets, opt)\n    return check_cxsnippets(snippets, table.join(table.wrap(opt), {sourcekind = \"mm\"}))\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_mxxsnippets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_mxxsnippets.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- check the given c++ snippets?\n--\n-- @param snippets  the snippets\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option]\n--                  , types = {\"wchar_t\", \"char*\"}, includes = \"stdio.h\", funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"}\n--                  , configs = {defines = \"xx\", mxflags = \"\"}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = check_mxxsnippets(\"void test() {}\")\n-- local ok = check_mxxsnippets({\"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- local ok = check_mxxsnippets({snippet_name = \"void test(){}\", \"#define TEST 1\"}, {types = \"wchar_t\", includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(snippets, opt)\n    return check_cxsnippets(snippets, table.join(table.wrap(opt), {sourcekind = \"mxx\"}))\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/check_sizeof.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_sizeof.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxxsnippets\")\n\nlocal binary_match_pattern = 'INFO:size%[(%d+)%]'\n\nlocal check_sizeof_template = [[\n#define SIZE (sizeof(${TYPE}))\nstatic char info_size[] =  {'I', 'N', 'F', 'O', ':', 's','i','z','e','[',\n  ('0' + ((SIZE / 10000)%10)),\n  ('0' + ((SIZE / 1000)%10)),\n  ('0' + ((SIZE / 100)%10)),\n  ('0' + ((SIZE / 10)%10)),\n  ('0' +  (SIZE    % 10)),\n  ']',\n  '\\0'};\n\nint main(int argc, char *argv[]) {\n  int require = 0;\n  require += info_size[argc];\n  (void)argv;\n  return require;\n}]]\n\nfunction _binary_match(content)\n    local match = content:match(binary_match_pattern)\n    if match then\n        return match:ltrim(\"0\")\n    end\nend\n\n-- check the size of type\n--\n-- @param typename  the typename\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = \"stdio.h\"\n--                  , configs = {defines = \"xx\", cxflags = \"\"}}\n--\n-- @return          the type size\n--\n-- @code\n-- local size = check_sizeof(\"long\")\n-- local size = check_sizeof(\"std::string\", {includes = \"string\"})\n-- @endcode\n--\nfunction main(typename, opt)\n    local snippets = check_sizeof_template:gsub('${TYPE}', typename)\n    local ok, size = check_cxxsnippets(snippets, table.join(table.wrap(opt), {binary_match = _binary_match}))\n    if ok then\n        return size\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        features.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.scheduler\")\n\n-- get all features of the current tool\n--\n-- @param name      the tool name\n-- @param opt       the argument options, e.g. {program = \"\", flags = {}}\n--\n-- @return          the features dictionary\n--\n-- @code\n-- local features = features(\"clang\")\n-- local features = features(\"clang\", {flags = \"-O0\", program = \"xcrun -sdk macosx clang\"})\n-- local features = features(\"clang\", {flags = {\"-g\", \"-O0\"}, envs = {PATH = \"\"}})\n-- @endcode\n--\nfunction main(name, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find tool program and version first\n    opt.version = true\n    local tool = find_tool(name, opt)\n    if not tool then\n        return {}\n    end\n\n    -- init tool\n    opt.toolname   = tool.name\n    opt.program    = tool.program\n    opt.programver = tool.version\n\n    -- init cache and key\n    local key     = tool.program .. \"_\" .. (tool.version or \"\") .. \"_\" .. table.concat(table.wrap(opt.flags), \",\")\n    _g._RESULTS = _g._RESULTS or {}\n    local results = _g._RESULTS\n\n    -- @see https://github.com/xmake-io/xmake/issues/4645\n    -- @note avoid detect the same program in the same time leading to deadlock if running in the coroutine (e.g. ccache)\n    scheduler.co_lock(key)\n\n    -- get result from the cache first\n    local result = results[key]\n    if result ~= nil then\n        scheduler.co_unlock(key)\n        return result\n    end\n\n    -- core.tools.xxx.features(opt)?\n    local features = import(\"core.tools.\" .. tool.name .. \".features\", {try = true})\n    if features then\n        result = features(opt)\n    end\n\n    result = result or {}\n    results[key] = result\n    scheduler.co_unlock(key)\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/find_cudadevices.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        find_cudadevices.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.platform.platform\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_tool\")\n\n-- a magic string to filter output\nlocal _PRINT_SUFFIX = \"<find_cudadevices>\"\n\n-- filter stdout and stderr with _PRINT_SUFFIX\nfunction _get_lines(str)\n    local result = {}\n    for _, l in ipairs(str:split(\"\\n\")) do\n        if l:startswith(_PRINT_SUFFIX) then\n            table.insert(result, l:sub(#_PRINT_SUFFIX + 1))\n        end\n    end\n    return result\nend\n\n-- parse a single value\n--\n-- format:\n-- 1. a number:     `2048`\n-- 2. an array:     `(65536, 2048, 2048)`\n-- 3. bool value:   `true` or `false`\n-- 4. string:       `\"string\"`\n--\nfunction _parse_value(value)\n    local num = tonumber(value)\n    if num then return num end\n\n    if value:lower() == \"true\" then return true end\n    if value:lower() == \"false\" then return false end\n    if value:startswith('\"') and value:endswith('\"') then\n        return value:sub(2, -2)\n    end\n\n    if value:startswith(\"(\") and value:endswith(\")\") then\n        local values = value:sub(2, -2):split(\",\")\n        local result = {}\n        for _, v in ipairs(values) do\n            table.insert(result, _parse_value(v:trim()))\n        end\n        return result\n    end\n\n    raise(\"don't know how to parse value: %s\", value)\nend\n\n\n-- parse single line\n--\n-- format:\n--     key = value\n--\nfunction _parse_line(line, device)\n    local key = line:match(\"%s+(%g+) = .+\")\n    local value = line:match(\"%s+%g+ = (.+)\")\n    if key and value then\n        key = key:trim()\n        value = value:trim()\n        assert(not device[key], \"duplicate key: \" .. key)\n        device[key] = _parse_value(value)\n    end\nend\n\n-- parse filtered lines\nfunction _parse_result(lines, verbose)\n\n    if #lines == 0 then\n        -- not a failure, returns {} rather than nil\n        utils.warning(\"no cuda devices was found\")\n        return {}\n    end\n\n    local devices = {}\n    local currentDevice = nil\n    for _, l in ipairs(lines) do\n        if verbose then\n            cprint(\"${dim}> %s\", l)\n        end\n        local devId = tonumber(l:match(\"%s*DEVICE #(%d+)\"))\n        if devId then\n            currentDevice = { [\"$id\"] = devId }\n            table.insert(devices, currentDevice)\n        elseif currentDevice then\n            _parse_line(l, currentDevice)\n        end\n    end\n    return devices\nend\n\n-- find devices\nfunction _find_devices(verbose, opt)\n\n    -- find nvcc\n    local nvcc = assert(find_tool(\"nvcc\"), \"nvcc not found\")\n\n    -- trace\n    if verbose then\n        cprint(\"${dim}checking for cuda devices\")\n    end\n\n    -- get cuda devices\n    local sourcefile = path.join(os.programdir(), \"scripts\", \"find_cudadevices.cpp\")\n    local outfile = os.tmpfile({ramdisk = false}) -- no execution permision in docker's /shm\n    local compile_errors = nil\n    local results, errors = try\n    {\n        function ()\n            local args = { sourcefile, \"-run\", \"-lcuda\", \"-o\", outfile , '-DPRINT_SUFFIX=\"' .. _PRINT_SUFFIX .. '\"' }\n            if opt.arch == \"x86\" then\n                table.insert(args, \"-m32\")\n            elseif opt.arch == \"x64\" or opt.arch == \"x86_64\" then\n                table.insert(args, \"-m64\")\n            end\n            return os.iorunv(nvcc.program, args, {envs = opt.envs})\n        end,\n        catch\n        {\n            function (errs)\n                compile_errors = tostring(errs)\n            end\n        }\n    }\n\n    if compile_errors then\n        if not option.get(\"diagnosis\") then\n            compile_errors = compile_errors:split('\\n')[1]\n        end\n        utils.warning(\"failed to find cuda devices: \" .. compile_errors)\n        return nil\n    end\n\n    -- clean up\n    os.tryrm(outfile)\n    os.tryrm(outfile .. \".*\")\n\n    -- get results\n    local results_lines = _get_lines(results)\n    local errors_lines = _get_lines(errors)\n    if #errors_lines ~= 0 then\n        utils.warning(\"failed to find cuda devices: \" .. table.concat(errors_lines, \"\\n\"))\n        return nil\n    end\n\n    -- print raw result only with -D flags\n    local devices = _parse_result(results_lines, option.get(\"diagnosis\"))\n    if verbose then\n        for _, v in ipairs(devices) do\n            cprint(\"${dim}> found device #%d: ${green bright}%s${reset dim} with compute ${bright}%d.%d${reset dim} capability\", v[\"$id\"], v.name, v.major, v.minor)\n        end\n    end\n    return devices\nend\n\n-- get devices array form cache or via _find_devices\nfunction _get_devices(opt)\n\n    -- init cachekey\n    local cachekey = \"find_cudadevices\"\n    if opt.cachekey then\n        cachekey = cachekey .. \"_\" .. opt.cachekey\n    end\n\n    -- check cache\n    local cachedata = detectcache:get(cachekey) or {}\n    if cachedata.succeed and not opt.force then\n        return cachedata.data\n    end\n\n    local verbose = opt.verbose or option.get(\"verbose\") or option.get(\"diagnosis\")\n    local devices = _find_devices(verbose, opt)\n    if devices then\n        cachedata = { succeed = true, data = devices }\n    else\n        cachedata = { succeed = false }\n        devices = {}\n    end\n\n    -- fill cache\n    detectcache:set(cachekey, cachedata)\n    return devices\nend\n\nfunction _skip_compute_mode_prohibited(devices)\n    local results = {}\n    local cuda_compute_mode_prohibited = 2\n    for _, dev in ipairs(devices) do\n        if dev.computeMode ~= cuda_compute_mode_prohibited then\n            table.insert(results, dev)\n        end\n    end\n    return results\nend\n\nfunction _min_sm_arch(devices, min_sm_arch)\n    local results = {}\n    for _, dev in ipairs(devices) do\n        if dev.major * 10 + dev.minor >= min_sm_arch then\n            table.insert(results, dev)\n        end\n    end\n    return results\nend\n\nfunction _order_by_flops(devices)\n\n    -- See https://github.com/NVIDIA/cuda-samples/blob/master/Common/helper_cuda_drvapi.h#L100\n    local ngpu_arch_cores_per_sm =\n    {\n        [30] =    192\n    ,   [32] =    192\n    ,   [35] =    192\n    ,   [37] =    192\n    ,   [50] =    128\n    ,   [52] =    128\n    ,   [53] =    128\n    ,   [60] =     64\n    ,   [61] =    128\n    ,   [62] =    128\n    ,   [70] =     64\n    ,   [72] =     64\n    ,   [75] =     64\n    ,   [80] =     64\n    ,   [86] =    128\n    ,   [87] =    128\n    ,   [89] =    128\n    ,   [90] =    128\n    ,   [100] =   128\n    ,   [103] =   128\n    ,   [110] =   128\n    ,   [120] =   128\n    ,   [121] =   128\n    }\n\n    for _, dev in ipairs(devices) do\n        local sm_per_multiproc = 0\n        if dev.major == 9999 and dev.minor == 9999 then\n            sm_per_multiproc = 1\n        else\n            sm_per_multiproc = ngpu_arch_cores_per_sm[dev.major * 10 + dev.minor] or 128;\n        end\n        dev[\"$flops\"] = dev.multiProcessorCount * sm_per_multiproc * dev.clockRate\n    end\n\n    table.sort(devices, function (a,b) return a[\"$flops\"] > b[\"$flops\"] end)\n    return devices\nend\n\n-- find cuda devices of the host\n--\n-- @param opt   the options\n--              e.g. { verbose = false, force = false, cachekey = \"xxxx\", min_sm_arch = 35, skip_compute_mode_prohibited = false, order_by_flops = true }\n--\n-- @return      { { [\"$id\"] = 0, name = \"GeForce GTX 960M\", major = 5, minor = 0, ... }, ... }\n--              for all keys, see https://docs.nvidia.com/cuda/cuda-runtime-api/structcudaDeviceProp.html#structcudaDeviceProp\n--              keys might be differ as your cuda version varies\n--\nfunction main(opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get devices\n    local devices = _get_devices(opt)\n\n    -- apply filters\n    if opt.min_sm_arch then\n        devices = _min_sm_arch(devices, opt.min_sm_arch)\n    end\n    if opt.skip_compute_mode_prohibited then\n        devices = _skip_compute_mode_prohibited(devices)\n    end\n    if opt.order_by_flops then\n        devices = _order_by_flops(devices)\n    end\n\n    return devices\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"package.manager.find_package\")\nimport(\"private.utils.package\", {alias = \"package_utils\"})\n\n-- find package using the package manager\n--\n-- @param name  the package name\n--              e.g. zlib 1.12.x (try all), xmake::zlib 1.12.x, brew::zlib, brew::pcre/libpcre16, vcpkg::zlib, conan::OpenSSL/1.0.2n@conan/stable\n-- @param opt   the options\n--              e.g. { verbose = false, force = false, plat = \"iphoneos\", arch = \"arm64\", mode = \"debug\", require_version = \"1.0.x\", version = true,\n--                     external = true, -- we use sysincludedirs instead of includedirs as results\n--                     linkdirs = {\"/usr/lib\"}, includedirs = \"/usr/include\", links = {\"ssl\"}, includes = {\"ssl.h\"}\n--                     packagedirs = {\"/tmp/packages\"}, system = true, cachekey = \"xxxx\"\n--                     pkgconfigs = {..}}\n--\n-- @return      {links = {\"ssl\", \"crypto\", \"z\"}, linkdirs = {\"/usr/local/lib\"}, includedirs = {\"/usr/local/include\"}}\n--\n-- @code\n--\n-- local package = find_package(\"openssl\")\n-- local package = find_package(\"openssl\", {require_version = \"1.0.*\", version = true})\n-- local package = find_package(\"openssl\", {plat = \"iphoneos\"})\n-- local package = find_package(\"openssl\", {linkdirs = {\"/usr/lib\", \"/usr/local/lib\"}, includedirs = \"/usr/local/include\", version = \"1.0.1\"})\n-- local package = find_package(\"openssl\", {linkdirs = {\"/usr/lib\", \"/usr/local/lib\", links = {\"ssl\", \"crypto\"}, includes = {\"ssl.h\"}})\n--\n-- @endcode\n--\nfunction main(name, opt)\n\n    -- get the copied options\n    opt = table.copy(opt)\n    opt.plat = opt.plat or config.get(\"plat\") or os.host()\n    opt.arch = opt.arch or config.get(\"arch\") or os.arch()\n    opt.mode = opt.mode or config.mode() or \"release\"\n\n    -- init cache key\n    local cachekey = \"find_package_\" .. opt.plat .. \"_\" .. opt.arch\n    if opt.cachekey then\n        cachekey = cachekey .. \"_\" .. opt.cachekey\n    end\n\n    -- init package key\n    local packagekey = name\n    if opt.buildhash then\n        packagekey = packagekey .. \"_\" .. opt.buildhash\n    end\n    if opt.mode then\n        packagekey = packagekey .. \"_\" .. opt.mode\n    end\n    if opt.require_version then\n        packagekey = packagekey .. \"_\" .. opt.require_version\n    end\n    if opt.external then\n        packagekey = packagekey .. \"_external\"\n    end\n\n    -- attempt to get result from cache first\n    local result = detectcache:get2(cachekey, packagekey)\n    if result == nil or opt.force then\n\n        -- find package\n        local found_manager_name, package_name\n        result, found_manager_name, package_name = find_package(name, opt)\n\n        -- use isystem?\n        if result and result.includedirs and opt.external then\n            result.sysincludedirs = result.includedirs\n            result.includedirs = nil\n            local components_base = result.components and result.components.__base\n            if components_base then\n                components_base.sysincludedirs = components_base.includedirs\n                components_base.includedirs = nil\n            end\n        end\n\n        -- cache result\n        detectcache:set2(cachekey, packagekey, result and result or false)\n\n        -- trace\n        if opt.verbose or option.get(\"verbose\") then\n            if result then\n\n                -- only display manager of found package if the package we searched for\n                -- did not specify a package manager\n                local display_manager = name:find(\"::\", 1, true) and \"\" or (found_manager_name or \"\") .. \"::\"\n                local display_name = display_manager .. package_name\n                cprint(\"checking for %s ... ${color.success}%s %s\", name, display_name, result.version and result.version or \"\")\n            else\n                cprint(\"checking for %s ... ${color.nothing}${text.nothing}\", name)\n            end\n        end\n    end\n\n    -- does not show version (default)? strip it\n    if not opt.version and result then\n        result.version = nil\n    end\n\n    -- register concat\n    if result then\n        package_utils.fetchinfo_set_concat(result)\n    end\n    return result and result or nil\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/find_tool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_tool.lua\n--\n\n-- imports\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"lib.detect.find_toolname\")\nimport(\"core.base.semver\")\nimport(\"core.tool.toolchain\")\n\n-- find tool from modules\nfunction _find_from_modules(name, opt)\n    local find_tool = import(\"detect.tools.find_\" .. name, {try = true})\n    if find_tool then\n        local program, version, toolname = find_tool(opt)\n        if program then\n            return {name = toolname or name, program = program, version = version}\n        end\n        return false\n    end\n    return nil\nend\n\n-- find tool\nfunction _find_tool(name, opt)\n    local toolname = find_toolname(name or opt.program)\n    if toolname then\n        local result = _find_from_modules(toolname, opt)\n        if result then\n            return result\n        elseif result == false then\n            -- find_xxx.lua exists, but program not found\n            return\n        end\n    end\n\n    opt.program = opt.program or name\n    local program = find_program(opt.program, opt)\n    if not program then\n        return\n    end\n\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return {name = toolname, program = program, version = version}\nend\n\n-- find tool\n--\n-- @param name      the tool name\n-- @param opt       the options, e.g. {program = \"xcrun -sdk macosx clang\", paths = {\"/usr/bin\"},\n--                                     check = function (tool) os.run(\"%s -h\", tool) end, version = true\n--                                     force = true, cachekey = \"xxx\", envs = {PATH = \"xxx\"}, system = false}\n--\n-- @return          {name = \"\", program = \"\", version = \"\"} or nil\n--\n-- @code\n--\n-- local tool = find_tool(\"clang\")\n-- local tool = find_tool(\"clang\", {program = \"xcrun -sdk macosx clang\"})\n-- local tool = find_tool(\"clang\", {paths = {\"/usr/bin\", \"/usr/local/bin\"}})\n-- local tool = find_tool(\"clang\", {check = \"--help\"}) -- simple check command: ccache --help\n-- local tool = find_tool(\"clang\", {check = function (tool) os.run(\"%s -h\", tool) end})\n-- local tool = find_tool(\"clang\", {paths = {\"$(env PATH)\", \"$(reg HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\AeDebug;Debugger)\"}})\n-- local tool = find_tool(\"clang\", {paths = {\"$(env PATH)\", function () return \"/usr/bin\"end}})\n-- local tool = find_tool(\"ccache\", {version = true})\n--\n-- @endcode\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if opt.require_version then\n        opt.version = true\n    end\n    local result = _find_tool(name, opt)\n    if opt.require_version and opt.require_version:find('.', 1, true) and result then\n        if not (result.version and (result.version == opt.require_version or semver.satisfies(result.version, opt.require_version))) then\n            result = nil\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/find_toolname.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_toolname.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.sandbox.module\")\n\n-- remove some suffix\n--\n-- we just remove some known extension, because we need to reverse others, e.g. ld.lld, ld64.lld\n--\nfunction _remove_suffix(name)\n    local exts = hashset.of(\"exe\", \"bat\", \"sh\", \"ps1\", \"ps\")\n    name = name:gsub(\"%.(%w+)\", function (ext)\n        ext = ext:lower()\n        if exts:has(ext) then\n            return \"\"\n        end\n    end)\n    return name\nend\n\n-- find the the whole name\nfunction _find_with_whole_name(program)\n\n    -- attempt to find it directly first\n    if module.find(\"detect.tools.find_\" .. program) then\n        return program\n    end\n\n    -- find the the whole name with spaces, e.g. \"zig cc\" -> zig_cc\n    local partnames = {}\n    local names = path.filename(program):lower():split(\"%s\")\n    for _, name in ipairs(names) do\n        -- remove suffix: \".exe\", e.g. \"zig.exe cc\"\n        name = _remove_suffix(name)\n        -- \"zig c++\" -> zig_cxx\n        name = name:gsub(\"%+\", \"x\")\n        -- skip -arguments\n        if not name:startswith(\"-\") then\n            table.insert(partnames, name)\n        end\n    end\n    local toolname = table.concat(partnames, \"_\")\n    if module.find(\"detect.tools.find_\" .. toolname) then\n        return toolname\n    end\nend\n\n-- find tool name from the given program\nfunction _find(program)\n\n    -- find whole name first\n    local toolname = _find_with_whole_name(program)\n    if toolname then\n        return toolname\n    end\n\n    -- get file name first\n    local name = path.filename(program):lower()\n\n    -- remove arguments: \" -xxx\" or \" --xxx\"\n    name = name:gsub(\"%s%-+%w+\", \" \")\n\n    -- try the last name by ' ': xxx xxx toolname\n    local names = name:split(\"%s\")\n    if #names > 0 then\n        name = names[#names]\n    end\n\n    -- remove suffix: \".xxx\"\n    name = _remove_suffix(name)\n    toolname = name:gsub(\"[%+%-%.]\", function (ch) return (ch == \"+\" and \"x\" or \"_\") end)\n    if module.find(\"detect.tools.find_\" .. toolname) then\n        return toolname\n    end\n\n    -- try last valid name: xxx-xxx-toolname-5\n    --\n    -- e.g.\n    -- arm-none-eabi-gcc-ar -> gcc_ar\n    -- arm-none-eabi-gcc -> gcc\n    local partnames = {}\n    for partname in name:gmatch(\"([%a%+]+)\") do\n        table.insert(partnames, partname)\n    end\n    while #partnames > 0 do\n        name = table.concat(partnames, \"_\")\n        table.remove(partnames, 1)\n        toolname = name:gsub(\"%+\", \"x\")\n        if module.find(\"detect.tools.find_\" .. toolname) then\n            return toolname\n        end\n    end\nend\n\n-- find tool name\n--\n-- e.g.\n-- \"xcrun -sdk macosx clang\":   clang\n-- \"zig cc\":                    zig_cc\n-- \"zig.exe c++\":               zig_c++\n-- \"/usr/bin/arm-linux-gcc\":    gcc\n-- \"link.exe -lib\":             link\n-- \"gcc-5\":                     gcc\n-- \"arm-android-clang++\":       clangxx\n-- \"pkg-config\":                pkg_config\n--\n-- @param program   the program path or name\n--\n-- @return          the tool name\n--\nfunction main(program)\n\n    -- init cache\n    local toolnames = _g._TOOLNAMES or {}\n\n    -- get it from the cache first\n    local toolname = toolnames[program]\n    if toolname ~= nil then\n        return toolname and toolname or nil\n    end\n\n    -- find the tool name\n    toolname = _find(program)\n\n    -- save result to cache\n    toolnames[program] = toolname and toolname or false\n    _g._TOOLNAMES = toolnames\n    return toolname\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_cfuncs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_cfuncs.lua\n--\n\n-- imports\nimport(\"lib.detect.check_csnippets\")\n\n-- has the given c funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = \"\", configs = {linkdirs = .., links = .., defines = .., ..}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_cfuncs(\"setjmp\")\n-- local ok = has_cfuncs({\"sigsetjmp((void*)0, 0)\", \"setjmp\"}, {includes = \"setjmp.h\"})\n-- @endcode\n--\nfunction main(funcs, opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.funcs = funcs\n\n    -- has funcs?\n    local name = opt.name or \"has_cfuncs\"\n    return check_csnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_cincludes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_cincludes.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- has the given c includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], configs = {defines = \"..\", .. }}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_cincludes(\"stdio.h\")\n-- local ok = has_cincludes({\"stdio.h\", \"stdlib.h\"}, {target = target})\n-- @endcode\n--\nfunction main(includes, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init includes\n    opt.sourcekind = \"cc\"\n    opt.includes   = includes\n\n    -- has includes?\n    local name = opt.name or \"has_cincludes\"\n    return check_cxsnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_ctypes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_ctypes.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- has the given c types?\n--\n-- @param types     the types\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = .., configs = {defines = .., ..}}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_ctypes(\"wchar_t\")\n-- local ok = has_ctypes({\"char*\", \"wchar_t\"}, {includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(types, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init types\n    opt.sourcekind = \"cc\"\n    opt.types      = types\n\n    -- has types?\n    local name = opt.name or \"has_ctypes\"\n    return check_cxsnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_cxxfuncs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_cxxfuncs.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxxsnippets\")\n\n-- has the given c++ funcs?\n--\n-- @param funcs     the funcs\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = \"\", configs = {linkdirs = .., links = .., defines = .., ..}}\n--\n-- funcs:\n--      sigsetjmp\n--      sigsetjmp((void*)0, 0)\n--      sigsetjmp{sigsetjmp((void*)0, 0);}\n--      sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_cxxfuncs(\"setjmp\")\n-- local ok = has_cxxfuncs({\"sigsetjmp((void*)0, 0)\", \"setjmp\"}, {includes = \"setjmp.h\"})\n-- @endcode\n--\nfunction main(funcs, opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.funcs = funcs\n\n    -- has funcs?\n    local name = opt.name or \"has_cxxfuncs\"\n    return check_cxxsnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_cxxincludes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_cxxincludes.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- has the given c++ includes?\n--\n-- @param includes  the includes\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], configs = {defines = \"..\", .. }}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_cxxincludes(\"stdio.h\")\n-- local ok = has_cxxincludes({\"stdio.h\", \"stdlib.h\"}, {target = target})\n-- @endcode\n--\nfunction main(includes, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init includes\n    opt.sourcekind = \"cxx\"\n    opt.includes   = includes\n\n    -- has includes?\n    local name = opt.name or \"has_cxxincludes\"\n    return check_cxsnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_cxxtypes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_cxxtypes.lua\n--\n\n-- imports\nimport(\"lib.detect.check_cxsnippets\")\n\n-- has the given c++ types?\n--\n-- @param types     the types\n-- @param opt       the argument options\n--                  e.g.\n--                  { verbose = false, target = [target|option], includes = .., configs = {defines = .., ..}}\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_cxxtypes(\"wchar_t\")\n-- local ok = has_cxxtypes({\"char*\", \"wchar_t\"}, {includes = \"stdio.h\"})\n-- @endcode\n--\nfunction main(types, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- init types\n    opt.sourcekind = \"cxx\"\n    opt.types      = types\n\n    -- has types?\n    local name = opt.name or \"has_cxxtypes\"\n    return check_cxsnippets({[name] = \"\"}, opt)\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_features.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_features.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.features\", {alias = \"get_features\"})\n\n-- has the given features for the current tool?\n--\n-- @param name      the tool name\n-- @param features  the features\n-- @param opt       the argument options, e.g. {verbose = false, flags = {}, program = \"\"}}\n--\n-- @return          true or false\n--\n-- @code\n-- local features = has_features(\"clang\", \"cxx_constexpr\")\n-- local features = has_features(\"clang\", {\"cxx_constexpr\", \"c_static_assert\"}, {flags = {\"-g\", \"-O0\"}, program = \"xcrun -sdk macosx clang\"})\n-- local features = has_features(\"clang\", {\"cxx_constexpr\", \"c_static_assert\"}, {flags = \"-g\"})\n-- @endcode\n--\nfunction main(name, features, opt)\n    opt = opt or {}\n    local allfeatures = get_features(name, opt) or {}\n    local passed = 0\n    features = table.wrap(features)\n    for _, feature in ipairs(features) do\n        if allfeatures[feature] then\n            passed = passed + 1\n        end\n    end\n    return passed == #features\nend\n"
  },
  {
    "path": "xmake/modules/lib/detect/has_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        has_flags.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"core.base.profiler\")\nimport(\"core.project.config\")\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_tool\")\n\n-- has the given flags for the current tool?\n--\n-- @param name      the tool name\n-- @param flags     the flags\n-- @param opt       the argument options, e.g. {force = true, verbose = false, program = \"\", sysflags = {}, flagkind = \"cxflag\", toolkind = \"[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]\", flagskey = \"custom key\" }\n--\n-- @return          true or false\n--\n-- @code\n-- local ok = has_flags(\"clang\", \"-g\")\n-- local ok = has_flags(\"clang\", {\"-g\", \"-O0\"}, {program = \"xcrun -sdk macosx clang\"})\n-- local ok = has_flags(\"clang\", \"-g\", {toolkind = \"cxx\"})\n-- local ok = has_flags(\"clang\", \"-g\", {on_check = function (ok, errors) return ok, errors end})\n-- @endcode\n--\nfunction main(name, flags, opt)\n\n    -- wrap flags first\n    flags = table.clone(flags)\n    table.wrap_unlock(flags)\n    flags = table.wrap(flags)\n\n    -- init options\n    opt = opt or {}\n    opt.flagskey = opt.flagskey or table.concat(flags, \" \")\n    opt.sysflags = table.wrap(opt.sysflags)\n\n    -- @note avoid running additional `program --version` processes\n    --opt.version = true\n\n    -- find tool program and version first\n    local tool = find_tool(name, opt)\n    if not tool then\n        return false\n    end\n\n    -- init tool\n    opt.toolname   = tool.name\n    opt.program    = tool.program\n    --opt.programver = tool.version\n\n    -- get tool platform\n    local plat = opt.plat or config.get(\"plat\") or os.host()\n\n    -- get tool architecture\n    --\n    -- some tools select arch by path environment, not be flags, e.g. cl.exe of msvc)\n    -- so, it will affect the cache result\n    --\n    local arch = opt.arch or config.get(\"arch\") or os.arch()\n\n    -- init cache key\n    local key = plat .. \"_\" .. arch .. \"_\" .. tool.program .. \"_\"\n              .. (tool.version or \"\") .. \"_\" .. (opt.toolkind or \"\")\n              .. \"_\" .. (opt.flagkind or \"\") .. \"_\" .. table.concat(opt.sysflags, \" \") .. \"_\" .. opt.flagskey\n\n    -- @see https://github.com/xmake-io/xmake/issues/4645\n    -- @note avoid detect the same program in the same time leading to deadlock if running in the coroutine (e.g. ccache)\n    scheduler.co_lock(key)\n\n    -- attempt to get result from cache first\n    local cacheinfo = detectcache:get(\"lib.detect.has_flags\")\n    if not cacheinfo then\n        -- since has_flags may be switched to other concurrent processes during cache saving,\n        -- we need to commit the initialized cache to avoid multiple cache objects overwriting it.\n        cacheinfo = {}\n        detectcache:set(\"lib.detect.has_flags\", cacheinfo)\n    end\n    local result = cacheinfo[key]\n    if result ~= nil and not opt.force then\n        scheduler.co_unlock(key)\n        return result\n    end\n\n    -- generate all checked flags\n    local checkflags = table.join(flags, opt.sysflags)\n\n    -- split flag group, e.g. \"-I /xxx\" => {\"-I\", \"/xxx\"}\n    local results = {}\n    for _, flag in ipairs(checkflags) do\n        flag = flag:trim()\n        if #flag > 0 then\n            if flag:find(\" \", 1, true) then\n                table.join2(results, os.argv(flag))\n            else\n                table.insert(results, flag)\n            end\n        end\n    end\n    checkflags = results\n\n    -- start profile\n    profiler.enter(\"has_flags\", tool.name, checkflags[1])\n\n    -- core.tools.xxx.has_flags(flags, opt)?\n    local hasflags = import(\"core.tools.\" .. tool.name .. \".has_flags\", {try = true})\n    local errors = nil\n    if hasflags then\n        result, errors = hasflags(checkflags, opt)\n    else\n        result = try { function () os.runv(tool.program, checkflags, {envs = opt.envs}); return true end, catch { function (errs) errors = errs end }}\n    end\n    if opt.on_check then\n        result, errors = opt.on_check(result, errors)\n    end\n    result = result or false\n\n    -- stop profile\n    profiler.leave(\"has_flags\", tool.name, checkflags[1])\n\n    -- trace\n    if option.get(\"verbose\") or option.get(\"diagnosis\") or opt.verbose then\n        cprint(\"${dim}checking for flags (%s) ... %s\", opt.flagskey, result and \"${color.success}${text.success}\" or \"${color.nothing}${text.nothing}\")\n        if option.get(\"diagnosis\") then\n            cprint(\"${dim}> %s \\\"%s\\\"\", path.filename(tool.program), table.concat(checkflags, \"\\\" \\\"\"))\n            if errors and #tostring(errors) > 0 then\n                cprint(\"${color.warning}checkinfo:${clear dim} %s\", tostring(errors):trim())\n            end\n        end\n    end\n\n    -- save result to cache\n    cacheinfo[key] = result\n    detectcache:set(\"lib.detect.has_flags\", cacheinfo)\n    scheduler.co_unlock(key)\n    return result\nend\n\n"
  },
  {
    "path": "xmake/modules/lib/detect/pkgconfig.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pkgconfig.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"core.project.target\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_library\")\nimport(\"lib.detect.find_tool\")\n\n-- get pkgconfig\nfunction _get_pkgconfig()\n    local pkgconfig = find_tool(\"pkg-config\") or find_tool(\"pkgconf\")\n    if pkgconfig then\n        return pkgconfig.program\n    end\nend\n\n-- get version\n--\n-- @param name      the package name\n-- @param opt       the argument options, {configdirs = {\"/xxxx/pkgconfig/\"}}\n--\nfunction version(name, opt)\n\n    -- attempt to add search paths from pkg-config\n    local pkgconfig = _get_pkgconfig()\n    if not pkgconfig then\n        return\n    end\n\n    -- init options\n    opt = opt or {}\n\n    -- init PKG_CONFIG_PATH\n    local configdirs_old = os.getenv(\"PKG_CONFIG_PATH\")\n    local configdirs = table.wrap(opt.configdirs)\n    if #configdirs > 0 then\n        os.setenv(\"PKG_CONFIG_PATH\", table.unpack(configdirs))\n    end\n\n    -- get version\n    local version = try { function() return os.iorunv(pkgconfig, {\"--modversion\", name}) end }\n    if version then\n        version = version:trim()\n    end\n\n    -- restore PKG_CONFIG_PATH\n    if configdirs_old then\n        os.setenv(\"PKG_CONFIG_PATH\", configdirs_old)\n    end\n\n    -- ok?\n    return version\nend\n\n-- get variables\n--\n-- @param name      the package name\n-- @param variables the variables\n-- @param opt       the argument options, {configdirs = {\"/xxxx/pkgconfig/\"}}\n--\nfunction variables(name, variables, opt)\n    opt = opt or {}\n    local pkgconfig = _get_pkgconfig()\n    if not pkgconfig then\n        return\n    end\n\n    local result = nil\n    local envs = {PKG_CONFIG_PATH = opt.configdirs}\n    if variables then\n        for _, variable in ipairs(table.wrap(variables)) do\n            local value = try { function ()\n                return os.iorunv(pkgconfig, {\"--variable=\" .. variable, name}, {envs = envs})\n            end }\n            if value ~= nil then\n                result = result or {}\n                result[variable] = value:trim()\n            end\n        end\n    end\n    return result\nend\n\n-- get pcfile path\n--\n-- @param name      the package name\n-- @param opt       the argument options, {configdirs = {\"/xxxx/pkgconfig/\"}}\n--\nfunction pcfile(name, opt)\n    opt = opt or {}\n    local pkgconfig = _get_pkgconfig()\n    if not pkgconfig then\n        return\n    end\n\n    local envs = {PKG_CONFIG_PATH = opt.configdirs}\n    local result = try { function ()\n        return os.iorunv(pkgconfig, {\"--path\", name}, {envs = envs})\n    end }\n    if result then\n        result = result:trim()\n    end\n    return result\nend\n\n-- get library info\n--\n-- @param name  the package name\n-- @param opt   the argument options, {version = true, variables = \"includedir\", configdirs = {\"/xxxx/pkgconfig/\"}}\n--\n-- @return      {links = {\"ssl\", \"crypto\", \"z\"}, linkdirs = {\"\"}, includedirs = {\"\"}, version = \"\"}\n--\n-- @code\n--\n-- local libinfo = pkgconfig.libinfo(\"openssl\")\n--\n-- @endcode\n--\nfunction libinfo(name, opt)\n    opt = opt or {}\n    local pkgconfig = _get_pkgconfig()\n    if not pkgconfig then\n        return\n    end\n\n    -- get cflags\n    local found\n    local result = {}\n    local envs = {PKG_CONFIG_PATH = opt.configdirs}\n    local cflags = try {function ()\n        return os.iorunv(pkgconfig, {\"--cflags\", name}, {envs = envs})\n    end, catch {function (errs)\n        found = false\n    end}}\n    if cflags then\n        for _, flag in ipairs(os.argv(cflags)) do\n            if flag:startswith(\"-I\") and #flag > 2 then\n                local includedir = flag:sub(3)\n                if includedir and os.isdir(includedir) then\n                    result.includedirs = result.includedirs or {}\n                    table.insert(result.includedirs, includedir)\n                end\n            elseif flag:startswith(\"-D\") and #flag > 2 then\n                local define = flag:sub(3)\n                result.defines = result.defines or {}\n                table.insert(result.defines, define)\n            elseif flag:startswith(\"-\") and #flag > 1 then\n                result.cxflags = result.cxflags or {}\n                table.insert(result.cxflags, flag)\n            end\n        end\n    end\n\n    -- libinfo may be empty body, but it's also valid\n    -- @see https://github.com/xmake-io/xmake/issues/3777#issuecomment-1568453316\n    if found == false then\n        return\n    end\n\n    -- get libs and ldflags\n    local ldflags = try { function () return os.iorunv(pkgconfig, {\"--libs\", name}, {envs = envs}) end }\n    if ldflags then\n        for _, flag in ipairs(os.argv(ldflags)) do\n            if flag:startswith(\"-L\") and #flag > 2 then\n                local linkdir = flag:sub(3)\n                if linkdir and os.isdir(linkdir) then\n                    result.linkdirs = result.linkdirs or {}\n                    table.insert(result.linkdirs, linkdir)\n                end\n            elseif flag:startswith(\"-l\") and #flag > 2 then\n                -- https://github.com/xmake-io/xmake/issues/4292\n                local link = flag:startswith(\"-l:\") and flag:sub(4) or flag:sub(3)\n                result.links = result.links or {}\n                table.insert(result.links, link)\n            elseif flag:startswith(\"-\") and #flag > 1 then\n                result.ldflags = result.ldflags or {}\n                result.shflags = result.shflags or {}\n                table.insert(result.ldflags, flag)\n                table.insert(result.shflags, flag)\n            end\n        end\n    end\n\n    -- get version\n    local version = try { function() return os.iorunv(pkgconfig, {\"--modversion\", name}, {envs = envs}) end }\n    if version then\n        result.version = version:trim()\n    end\n    return result\nend\n\n"
  },
  {
    "path": "xmake/modules/net/fasturl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fasturl.lua\n--\n\n-- imports\nimport(\"ping\")\n\n-- http[s]://xxx.com[:1234]/.. or git@git.xxx.com:xxx/xxx.git\nfunction _parse_host(url)\n    _g._URLHOSTS = _g._URLHOSTS or {}\n    local host = _g._URLHOSTS[url] or url:match(\"://([^/:]+)\") or url:match(\"@(.-):\")\n    _g._URLHOSTS[url] = host\n    return host\nend\n\nfunction add(urls)\n    local pinginfo = _g._PINGINFO or {}\n    _g._PINGHOSTS = _g._PINGHOSTS or {}\n    for _, url in ipairs(urls) do\n        local host = _parse_host(url)\n        if host and not pinginfo[host] then\n            table.insert(_g._PINGHOSTS, host)\n        end\n    end\nend\n\nfunction sort(urls)\n\n    -- ping hosts\n    local pinghosts = table.unique(_g._PINGHOSTS or {})\n    if pinghosts and #pinghosts > 0 then\n        local pinginfo = ping(pinghosts)\n        _g._PINGINFO = table.join(_g._PINGINFO or {}, pinginfo)\n    end\n\n    -- sort urls by the ping info\n    local pinginfo = _g._PINGINFO or {}\n    table.sort(urls, function(a, b)\n        a = pinginfo[_parse_host(a) or \"\"] or 65536\n        b = pinginfo[_parse_host(b) or \"\"] or 65536\n        return a < b\n    end)\n\n    _g._PINGHOSTS = {}\n    return urls\nend\n\n"
  },
  {
    "path": "xmake/modules/net/http/download.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"net.proxy\")\n\n-- get user agent\nfunction _get_user_agent()\n\n    -- init user agent\n    if _g._USER_AGENT == nil then\n\n        -- init systems\n        local systems = {macosx = \"Macintosh\", linux = \"Linux\", windows = \"Windows\", msys = \"MSYS\", cygwin = \"Cygwin\"}\n\n        -- os user agent\n        local os_user_agent = \"\"\n        if is_host(\"macosx\") then\n            local osver = try { function() return os.iorun(\"/usr/bin/sw_vers -productVersion\") end }\n            if osver then\n                os_user_agent = (\"Intel Mac OS X \" .. (osver or \"\")):trim()\n            end\n        elseif is_subhost(\"linux\", \"msys\", \"cygwin\") then\n            local osver = try { function () return os.iorun(\"uname -r\") end }\n            if osver then\n                os_user_agent = (os_user_agent .. \" \" .. (osver or \"\")):trim()\n            end\n        end\n\n        -- make user agent\n        _g._USER_AGENT = string.format(\"Xmake/%s (%s;%s)\", xmake.version(), systems[os.subhost()] or os.subhost(), os_user_agent)\n    end\n    return _g._USER_AGENT\nend\n\n-- download url using curl\nfunction _curl_download(tool, url, outputfile, opt)\n\n    -- set basic arguments\n    local argv = {}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"-SL\")\n    else\n        table.insert(argv, \"-fsSL\")\n    end\n\n    -- use proxy?\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        table.insert(argv, \"-x\")\n        table.insert(argv, proxy_conf)\n    end\n\n    -- set user-agent\n    local user_agent = _get_user_agent()\n    if user_agent then\n        if tool.version then\n            user_agent = user_agent .. \" curl/\" .. tool.version\n        end\n        table.insert(argv, \"-A\")\n        table.insert(argv, user_agent)\n    end\n\n    -- ignore to check ssl certificates\n    if opt.insecure then\n        table.insert(argv, \"-k\")\n    end\n\n    -- add custom headers\n    if opt.headers then\n        for _, header in ipairs(opt.headers) do\n            table.insert(argv, \"-H\")\n            table.insert(argv, header)\n        end\n    end\n\n    -- continue to download?\n    if opt.continue then\n        table.insert(argv, \"-C\")\n        table.insert(argv, \"-\")\n    end\n\n    -- set timeout\n    if opt.timeout then\n        table.insert(argv, \"--max-time\")\n        table.insert(argv, tostring(opt.timeout))\n    end\n\n    -- set read timeout\n    if opt.read_timeout then\n        table.insert(argv, \"--speed-limit\")\n        table.insert(argv, \"0\")\n        table.insert(argv, \"--speed-time\")\n        table.insert(argv, tostring(opt.read_timeout))\n    end\n\n    -- set url\n    table.insert(argv, url)\n\n    -- ensure output directory\n    local outputdir = path.directory(outputfile)\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- set outputfile\n    table.insert(argv, \"-o\")\n    table.insert(argv, outputfile)\n\n    -- download it\n    os.vrunv(tool.program, argv)\nend\n\n-- download url using wget\nfunction _wget_download(tool, url, outputfile, opt)\n\n    -- ensure output directory\n    local argv = {url}\n    local outputdir = path.directory(outputfile)\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- use proxy?\n    local proxy_conf = proxy.config(url)\n    if proxy_conf then\n        table.insert(argv, \"-e\")\n        table.insert(argv, \"use_proxy=yes\")\n        table.insert(argv, \"-e\")\n        if url:startswith(\"http://\") then\n            table.insert(argv, \"http_proxy=\" .. proxy_conf)\n        elseif url:startswith(\"https://\") then\n            table.insert(argv, \"https_proxy=\" .. proxy_conf)\n        elseif url:startswith(\"ftp://\") then\n            table.insert(argv, \"ftp_proxy=\" .. proxy_conf)\n        else\n            table.insert(argv, \"http_proxy=\" .. proxy_conf)\n        end\n    end\n\n    -- set user-agent\n    local user_agent = _get_user_agent()\n    if user_agent then\n        if tool.version then\n            user_agent = user_agent .. \" wget/\" .. tool.version\n        end\n        table.insert(argv, \"-U\")\n        table.insert(argv, user_agent)\n    end\n\n    -- ignore to check ssl certificates\n    if opt.insecure then\n        table.insert(argv, \"--no-check-certificate\")\n    end\n\n    -- add custom headers\n    if opt.headers then\n        for _, header in ipairs(opt.headers) do\n            table.insert(argv, \"--header=\" .. header)\n        end\n    end\n\n    -- continue to download?\n    if opt.continue then\n        table.insert(argv, \"-c\")\n    end\n\n    -- set timeout\n    if opt.timeout then\n        table.insert(argv, \"--timeout=\" .. tostring(opt.timeout))\n    end\n\n    -- set read timeout\n    if opt.read_timeout then\n        table.insert(argv, \"--read-timeout=\" .. tostring(opt.read_timeout))\n    end\n\n    -- set outputfile\n    table.insert(argv, \"-O\")\n    table.insert(argv, outputfile)\n\n    -- download it\n    os.vrunv(tool.program, argv)\nend\n\n-- download url using powershell\n-- e.g.\n-- powershell -ExecutionPolicy Bypass -File \"D:\\scripts\\download.ps1\" \"url\" \"outputfile\"\nfunction _powershell_download(tool, url, outputfile, opt)\n\n    -- get the script file\n    local scriptfile = path.join(os.programdir(), \"scripts\", \"download.ps1\")\n\n    -- ensure output directory\n    local outputdir = path.directory(outputfile)\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- download it\n    local argv = {\"-ExecutionPolicy\", \"Bypass\", \"-File\", scriptfile, url, outputfile}\n    os.vrunv(tool.program, argv)\nend\n\n-- download url\n--\n-- @param url           the input url\n-- @param outputfile    the output file\n-- @param opt           the option, {continue = true}\n--\n--\nfunction main(url, outputfile, opt)\n\n    -- init output file\n    opt = opt or {}\n    outputfile = outputfile or path.filename(url):gsub(\"%?.+$\", \"\")\n\n    -- attempt to download url using curl first\n    local tool = find_tool(\"curl\", {version = true})\n    if tool then\n        return _curl_download(tool, url, outputfile, opt)\n    end\n\n    -- download url using wget\n    tool = find_tool(\"wget\", {version = true})\n    if tool then\n        return _wget_download(tool, url, outputfile, opt)\n    end\n\n    -- download url using powershell\n    if is_host(\"windows\") then\n        tool = find_tool(\"pwsh\") or find_tool(\"powershell\")\n        if tool then\n            return _powershell_download(tool, url, outputfile, opt)\n        end\n    end\n\n    assert(tool, \"curl or wget not found!\")\nend\n"
  },
  {
    "path": "xmake/modules/net/ping.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ping.lua\n--\n\n-- imports\nimport(\"core.cache.detectcache\")\nimport(\"lib.detect.find_tool\")\nimport(\"async.runjobs\")\n\n-- using ping to ping host\nfunction _ping_via_ping(ping, host)\n    local data = nil\n    if is_host(\"windows\") then\n        data = try { function () return os.iorun(\"%s -n 1 -w 1000 %s\", ping.program, host) end }\n    elseif is_host(\"macosx\") then\n        data = try { function () return os.iorun(\"%s -c 1 -t 1 %s\", ping.program, host) end }\n    else\n        -- @see https://github.com/xmake-io/xmake/issues/4470#issuecomment-1840338777\n        data = try { function () return os.iorun(\"%s -c 1 -W 1 -n %s\", ping.program, host) end }\n        if not data then\n            data = try { function () return os.iorun(\"%s -c 1 -W 1 %s\", ping.program, host) end }\n        end\n    end\n    local timeval = \"65535\"\n    if data then\n        timeval = data:match(\"= [^/]+/([^/]+)/\", 1, true) or data:match(\"[=<]([%d%s%.]-)ms TTL\", 1, true) or \"65535\"\n    end\n    if timeval then\n        timeval = tonumber(timeval:trim())\n    end\n    return timeval\nend\n\n-- using curl to ping host\nfunction _ping_via_curl(curl, host)\n    local data, dt = try { function ()\n        local t = os.mclock()\n        local tmpfile = os.tmpfile()\n        local outdata = os.iorunv(curl.program, {\"-o\", tmpfile, \"-s\", \"-w\", \"%{time_total}\", \"--max-time\", \"1\", host})\n        t = os.mclock() - t\n        os.tryrm(tmpfile)\n        return outdata, t\n    end }\n    local timeval = 65535\n    if data then\n        local t = tonumber(data:trim())\n        if t then\n            timeval = t * 1000\n        else\n            timeval = dt\n        end\n    end\n    return timeval\nend\n\n-- using wget to ping host\nfunction _ping_via_wget(wget, host)\n    local data = try { function ()\n        local t = os.mclock()\n        os.runv(wget.program, {\"-O\", os.nuldev(), \"--tries=1\", \"--timeout=1\", host})\n        t = os.mclock() - t\n        return t\n    end }\n    local timeval = 65535\n    if data then\n        timeval = data\n    end\n    return timeval\nend\n\n-- ping host\n-- @see https://github.com/xmake-io/xmake/issues/6579\nfunction _ping(ping, host)\n    local routers = {\n        ping = _ping_via_ping,\n        curl = _ping_via_curl,\n        wget = _ping_via_wget\n    }\n    local router = routers[ping.name] or _ping_via_ping\n    if router then\n        return router(ping, host)\n    end\nend\n\n-- send ping to hosts\n--\n-- @param hosts     the hosts\n-- @param opt       the options\n--\n-- @return          the time or -1\n--\nfunction main(hosts, opt)\n    opt = opt or {}\n\n    local ping = find_tool(\"curl\", opt) or find_tool(\"wget\") or find_tool(\"ping\", opt)\n    if not ping then\n        return {}\n    end\n\n    local cacheinfo = nil\n    if not opt.force then\n        cacheinfo = detectcache:get(\"net.ping\")\n    end\n\n    local results = {}\n    hosts = table.wrap(hosts)\n    runjobs(\"ping\", function (index)\n        local host = hosts[index]\n        if host then\n            local timeval = nil\n            if cacheinfo then\n                timeval = cacheinfo[host]\n            end\n            if timeval then\n                results[host] = timeval\n            else\n                timeval = _ping(ping, host)\n                results[host] = timeval\n                if cacheinfo then\n                    cacheinfo[host] = timeval\n                end\n                vprint(\"pinging the host(%s) ... %d ms\", host, math.floor(timeval))\n            end\n        end\n    end, {total = #hosts})\n\n    if cacheinfo then\n        detectcache:set(\"net.ping\", cacheinfo)\n    end\n    return results\nend\n\n"
  },
  {
    "path": "xmake/modules/net/proxy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        proxy.lua\n--\n\n-- imports\nimport(\"core.base.global\")\n\n-- get proxy hosts\nfunction _proxy_hosts()\n    local proxy_hosts = _g._PROXY_HOSTS\n    if proxy_hosts == nil then\n        proxy_hosts = global.get(\"proxy_hosts\")\n        if proxy_hosts then\n            proxy_hosts = proxy_hosts:split(',', {plain = true})\n        end\n        _g._PROXY_HOSTS = proxy_hosts or false\n    end\n    return proxy_hosts or nil\nend\n\n-- get proxy pac file\n--\n-- pac.lua\n--\n-- @code\n-- function mirror(url)\n--     return url:gsub(\"github.com\", \"hub.fastgit.org\")\n-- end\n-- function main(url, host)\n--    if host:find(\"bintray.com\") then\n--        return true\n--    end\n-- end\n-- @endcode\n--\nfunction _proxy_pac()\n    local proxy_pac = _g._PROXY_PAC\n    if proxy_pac == nil then\n        local pac = global.get(\"proxy_pac\")\n        local pacfile\n        if pac and pac:endswith(\".lua\") then\n            if os.isfile(pac) then\n                pacfile = pac\n            end\n            if not pacfile and not path.is_absolute(pac) then\n                pacfile = path.join(global.directory(), pac)\n                if not os.isfile(pacfile) and os.isfile(path.join(os.programdir(), \"scripts\", \"pac\", pac)) then\n                    pacfile = path.join(os.programdir(), \"scripts\", \"pac\", pac)\n                end\n            end\n        end\n        if pacfile and os.isfile(pacfile) then\n            proxy_pac = import(path.basename(pacfile), {rootdir = path.directory(pacfile), try = true, anonymous = true})\n        end\n        _g._PROXY_PAC = proxy_pac or false\n    end\n    return proxy_pac or nil\nend\n\n-- convert host pattern to a lua pattern\nfunction _host_pattern(pattern)\n    pattern = pattern:gsub(\"([%+%.%-%^%$%(%)%%])\", \"%%%1\")\n    pattern = pattern:gsub(\"%*\", \"\\001\")\n    pattern = pattern:gsub(\"\\001\", \".*\")\n    return pattern\nend\n\n-- has main entry? it will be callable directly\nfunction _is_callable(func)\n    if type(func) == \"function\" then\n        return true\n    elseif type(func) == \"table\" then\n        local meta = debug.getmetatable(func)\n        if meta and meta.__call then\n            return true\n        end\n    end\nend\n\n-- get proxy mirror url\nfunction mirror(url)\n    local proxy_pac = _proxy_pac()\n    if proxy_pac and proxy_pac.mirror then\n        return proxy_pac.mirror(url)\n    end\n    return url\nend\n\n-- get system proxy\nfunction _system_proxy()\n    local proxy = os.getenv(\"ALL_PROXY\") or os.getenv(\"HTTP_PROXY\") or os.getenv(\"HTTPS_PROXY\")\n    if proxy then\n        return proxy\n    end\n\n    if is_host(\"windows\") then\n        -- Check whether system proxy is enabled\n        local proxy_enable = winos.registry_query('HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings;ProxyEnable')\n        --  Verify that the proxy is enabled (0x1 means enabled)\n        if not proxy_enable or proxy_enable ~= \"1\" then\n            return nil\n        end\n\n        -- Extract the proxy server address\n        local proxy_server = winos.registry_query(\"HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings;ProxyServer\")\n        if not proxy_server then\n            return nil\n        end\n\n        -- Prepend the protocol if not present\n        if not proxy_server:match(\"://(.-)\") then\n            proxy_server = \"http://\" .. proxy_server\n        end\n        return proxy_server\n    end\n\n    return nil\nend\n\n-- translate global proxy\nfunction _global_proxy()\n    local proxy = global.get(\"proxy\")\n    if proxy and proxy:lower() == \"system\" then\n        return _system_proxy()\n    end\n    return proxy\nend\n\n-- get proxy configuration from the given url, [protocol://]host[:port]\n--\n-- @see https://github.com/xmake-io/xmake/issues/854\n--\nfunction config(url)\n\n    -- enable proxy for the given url and configuration pattern\n    if url then\n\n        -- filter proxy host from the given hosts pattern\n        local host = url:match(\"://(.-)/\") or url:match(\"@(.-):\")\n        local proxy_hosts = _proxy_hosts()\n        if host and proxy_hosts then\n            host = host:lower()\n            for _, proxy_host in ipairs(proxy_hosts) do\n                proxy_host = proxy_host:lower()\n                if host == proxy_hosts or host:match(_host_pattern(proxy_host)) then\n                    return _global_proxy()\n                end\n            end\n        end\n\n        -- filter proxy host from the pac file\n        local proxy_pac = _proxy_pac()\n        if proxy_pac and host and _is_callable(proxy_pac) and proxy_pac(url, host) then\n            return _global_proxy()\n        end\n\n        -- use global proxy\n        if not proxy_pac and not proxy_hosts then\n            return _global_proxy()\n        end\n        return\n    end\n\n    -- enable global proxy\n    return _global_proxy()\nend\n"
  },
  {
    "path": "xmake/modules/os/winver.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        winver.lua\n--\n\n-- get WINVER from name\n--\n-- reference: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx\n--\nfunction version(name)\n\n    -- init values\n    _g.values = _g.values or\n    {\n        nt4      = \"0x0400\"\n    ,   win2k    = \"0x0500\"\n    ,   winxp    = \"0x0501\"\n    ,   ws03     = \"0x0502\"\n    ,   win6     = \"0x0600\"\n    ,   vista    = \"0x0600\"\n    ,   ws08     = \"0x0600\"\n    ,   longhorn = \"0x0600\"\n    ,   win7     = \"0x0601\"\n    ,   win8     = \"0x0602\"\n    ,   winblue  = \"0x0603\"\n    ,   win81    = \"0x0603\"\n    ,   win10    = \"0x0A00\"\n    }\n\n    -- ignore the subname with '_xxx'\n    name = name:split('_')[1]\n\n    -- get value\n    return _g.values[name]\nend\n\n-- get NTDDI_VERSION from name\nfunction ntddi_version(name)\n\n    -- init subvalues\n    _g.subvalues = _g.subvalues or\n    {\n        sp1    = \"0100\"\n    ,   sp2    = \"0200\"\n    ,   sp3    = \"0300\"\n    ,   sp4    = \"0400\"\n    ,   th2    = \"0001\"\n    ,   rs1    = \"0002\"\n    ,   rs2    = \"0003\"\n    ,   rs3    = \"0004\"\n    ,   rs4    = \"0005\"\n    ,   rs5    = \"0006\"\n    ,   h1     = \"0007\"\n    ,   vb     = \"0008\"\n    ,   nm     = \"0009\"\n    ,   fe     = \"000A\"\n    ,   co     = \"000B\"\n    ,   ni     = \"000C\"\n    }\n\n    -- get subvalue\n    local subvalue = nil\n    local subname = name:split('_')[2]\n    if subname then\n        subvalue = _g.subvalues[subname]\n    end\n\n    -- get value\n    local val = version(name)\n    if val then\n        val = val .. (subvalue or \"0000\")\n    end\n    return val\nend\n\n-- get _WIN32_WINNT from name\nfunction winnt_version(name)\n    return version(name)\nend\n\n-- get _NT_TARGET_VERSION from name\nfunction target_version(name)\n    return version(name)\nend\n\n-- get subsystem version from name\nfunction subsystem(name)\n\n    -- ignore the subname with '_xxx'\n    name = (name or \"\"):split('_')[1]\n\n    -- make defined values\n    local defvals =\n    {\n        nt4      = \"4.00\"\n    ,   win2k    = \"5.00\"\n    ,   winxp    = \"5.01\"\n    ,   ws03     = \"5.02\"\n    ,   win6     = \"6.00\"\n    ,   vista    = \"6.00\"\n    ,   ws08     = \"6.00\"\n    ,   longhorn = \"6.00\"\n    ,   win7     = \"6.01\"\n    ,   win8     = \"6.02\"\n    ,   winblue  = \"6.03\"\n    ,   win81    = \"6.03\"\n    ,   win10    = \"10.00\"\n    }\n    return defvals[name] or \"10.00\"\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/apt/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.pkgconfig.find_package\", {alias = \"find_package_from_pkgconfig\"})\n\n-- find package\nfunction _find_package(dpkg, name, opt)\n    local result = nil\n    local pkgconfig_files = {}\n    local listinfo = try {function () return os.iorunv(dpkg.program, {\"--listfiles\", name}) end}\n    if listinfo then\n        for _, line in ipairs(listinfo:split('\\n', {plain = true})) do\n            line = line:trim()\n\n            -- get includedirs\n            local pos = line:find(\"include/\", 1, true)\n            if pos then\n                -- we don't need to add includedirs, gcc/clang will use /usr/ as default sysroot\n                result = result or {}\n            end\n\n            -- get pc files\n            if line:find(\"/pkgconfig/\", 1, true) and line:endswith(\".pc\") then\n                table.insert(pkgconfig_files, line)\n            end\n\n            -- get linkdirs and links\n            if line:endswith(\".a\") or line:endswith(\".so\") then\n                result = result or {}\n                result.links = result.links or {}\n                result.linkdirs = result.linkdirs or {}\n                result.libfiles = result.libfiles or {}\n                if line:endswith(\".a\") then\n                    result.static = true\n                else\n                    result.shared = true\n                end\n                table.insert(result.linkdirs, path.directory(line))\n                table.insert(result.links, target.linkname(path.filename(line), {plat = opt.plat}))\n                table.insert(result.libfiles, path.join(path.directory(line), path.filename(line)))\n            end\n        end\n    end\n\n    -- we iterate over each pkgconfig file to extract the required data\n    local foundpc = false\n    local pcresult = {includedirs = {}, linkdirs = {}, links = {}, libfiles = {}}\n    for _, pkgconfig_file in ipairs(pkgconfig_files) do\n        local pkgconfig_dir = path.directory(pkgconfig_file)\n        local pkgconfig_name = path.basename(pkgconfig_file)\n        local pcinfo = find_package_from_pkgconfig(pkgconfig_name, {configdirs = pkgconfig_dir, linkdirs = linkdirs})\n\n        -- the pkgconfig file has been parse successfully\n        if pcinfo then\n            for _, includedir in ipairs(pcinfo.includedirs) do\n                table.insert(pcresult.includedirs, includedir)\n            end\n            for _, linkdir in ipairs(pcinfo.linkdirs) do\n                table.insert(pcresult.linkdirs, linkdir)\n            end\n            for _, link in ipairs(pcinfo.links) do\n                table.insert(pcresult.links, link)\n            end\n            if not result or not result.libfiles then\n                for _, libfile in ipairs(pcinfo.libfiles) do\n                    table.insert(pcresult.libfiles, libfile)\n                end\n                pcresult.static = pcinfo.static\n                pcresult.shared = pcinfo.shared\n            end\n            -- version should be the same if a pacman package contains multiples .pc\n            pcresult.version = pcinfo.version\n            foundpc = true\n        end\n    end\n    if foundpc == true then\n        pcresult.includedirs = table.unique(pcresult.includedirs)\n        pcresult.linkdirs = table.unique(pcresult.linkdirs)\n        pcresult.libfiles = table.unique(pcresult.libfiles)\n        pcresult.links = table.reverse_unique(pcresult.links)\n        result = pcresult\n    end\n\n    -- meta/alias package? e.g. libboost-dev -> libboost1.74-dev\n    -- @see https://github.com/xmake-io/xmake/issues/1786\n    if not result then\n        local statusinfo = try {function () return os.iorunv(dpkg.program, {\"--status\", name}) end}\n        if statusinfo then\n            for _, line in ipairs(statusinfo:split(\"\\n\", {plain = true})) do\n                -- parse depends, e.g. Depends: libboost1.74-dev, libomp-14-dev (>= 14~)\n                if line:startswith(\"Depends:\") then\n                    local depends = line:sub(9):gsub(\"%(.-%)\", \"\"):split(\"%s+\")\n                    if #depends == 1 then\n                        return _find_package(dpkg, depends[1], opt)\n                    end\n                    break\n                end\n            end\n        end\n    end\n\n    if result then\n        if result.links then\n            result.links = table.unique(result.links)\n            if #result.links == 0 then\n                result.links = nil\n            end\n        end\n        if result.linkdirs then\n            result.linkdirs = table.unique(result.linkdirs)\n            if #result.linkdirs == 0 then\n                result.linkdirs = nil\n            end\n        end\n        if result.includedirs then\n            result.includedirs = table.unique(result.includedirs)\n            if #result.includedirs == 0 then\n                result.includedirs = nil\n            end\n        end\n        if result.libfiles then\n            result.libfiles = table.unique(result.libfiles)\n            if #result.libfiles == 0 then\n                result.libfiles = nil\n            end\n        end\n    end\n    return result\nend\n\n-- find package using the dpkg package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.0\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    local dpkg = find_tool(\"dpkg\")\n    if not dpkg then\n        return\n    end\n    return _find_package(dpkg, name, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/apt/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"privilege.sudo\")\n\n-- install package\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, apt = \"the package name\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find apt\n    local apt = find_tool(\"apt\")\n    if not apt then\n        raise(\"apt not found!\")\n    end\n\n    -- init argv\n    local argv = {\"install\", \"-y\", opt.apt or name}\n\n    -- install package directly if the current user is root\n    if os.isroot() then\n        os.vrunv(apt.program, argv)\n    -- install with administrator permission?\n    elseif sudo.has() then\n\n        -- install it if be confirmed\n        local description = format(\"try installing %s with administrator permission\", name)\n        local confirm = utils.confirm({default = true, description = description})\n        if confirm then\n            sudo.vrunv(apt.program, argv)\n        end\n    else\n        raise(\"cannot get administrator permission!\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/apt/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search package using the apt package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n\n    -- find apt\n    local apt = find_tool(\"apt\")\n    if not apt then\n        raise(\"apt not found!\")\n    end\n\n    -- search packages\n    --\n    -- libzopfli1/groovy 1.0.3-1build1 amd64\n    --  zlib (gzip, deflate) compatible compressor - shared library\n    --\n    -- lua-zlib/groovy 1.2-2 amd64\n    --  zlib library for the Lua language\n    --\n    local results = {}\n    local searchdata = os.iorunv(apt.program, {\"search\", name})\n    local packagename\n    for _, line in ipairs(searchdata:split(\"\\n\", {plain = true})) do\n        if line:find(\"/\", 1, true) then\n            local splitinfo = line:split(\"%s+\", {limit = 3})\n            packagename = splitinfo[1]\n            if packagename then\n                packagename = packagename:split('/')[1]\n            end\n        elseif line:trim() ~= \"\" and packagename then\n            local description = line:trim()\n            if packagename:find(name, 1, true) then\n                table.insert(results, {name = \"apt::\" .. packagename, version = version, description = description})\n            end\n            packagename = nil\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/brew/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.pkgconfig\")\nimport(\"core.project.target\")\nimport(\"package.manager.find_package\")\nimport(\"private.core.base.is_cross\")\n\n-- get the root directory of the brew packages\nfunction _brew_pkg_rootdir()\n    local brew_pkg_rootdir = _g.brew_pkg_rootdir\n    if brew_pkg_rootdir == nil then\n        local brew = find_tool(\"brew\")\n        if brew then\n            brew_pkg_rootdir = try\n            {\n                function ()\n                    return os.iorunv(brew.program, {\"--prefix\"})\n                end\n            } or \"/usr/local\"\n        end\n        if brew_pkg_rootdir then\n            brew_pkg_rootdir = brew_pkg_rootdir:trim()\n        end\n        _g.brew_pkg_rootdir = brew_pkg_rootdir or false\n    end\n    return brew_pkg_rootdir or nil\nend\n\n-- find package from pkg-config\nfunction _find_package_from_pkgconfig(name, opt)\n    opt = opt or {}\n    local brew_pkg_rootdir = opt.brew_pkg_rootdir\n\n    -- parse name, e.g. pcre/libpcre16\n    local nameinfo = name:split('/')\n    local pcname   = nameinfo[2] or nameinfo[1]\n\n    -- find package from pkg-config/*.pc,\n    -- but we cannot find it from `brew --prefix`/package, because `brew --prefix` is too slow (> 3s) when it's not found.\n    local result = nil\n    local paths = {}\n    table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], \"lib/pkgconfig\"))\n    table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], \"share/pkgconfig\"))\n    if opt.require_version then\n        table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], opt.require_version, \"lib/pkgconfig\"))\n        table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], opt.require_version, \"share/pkgconfig\"))\n    else\n        table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], \"*/lib/pkgconfig\"))\n        table.insert(paths, path.join(brew_pkg_rootdir, nameinfo[1], \"*/share/pkgconfig\"))\n    end\n    local pcfile = find_file(pcname .. \".pc\", paths)\n    if pcfile then\n        opt.configdirs = path.directory(pcfile)\n        result = find_package(\"pkgconfig::\" .. pcname, opt)\n        if not result or not result.includedirs then\n            -- attempt to get includedir variable from pkg-config/xx.pc\n            local varinfo = pkgconfig.variables(pcname, \"includedir\", opt)\n            if varinfo and varinfo.includedir then\n                result = result or {}\n                result.version = pkgconfig.version(pcname, opt)\n                result.includedirs = varinfo.includedir\n            end\n        end\n    end\n    return result\nend\n\n-- find package from the brew package manager\n--\n-- @param name  the package name, e.g. zlib, pcre/libpcre16\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    -- find the prefix directory of brew\n    local brew_pkg_rootdir = _brew_pkg_rootdir()\n    if not brew_pkg_rootdir then\n        return\n    end\n    brew_pkg_rootdir = path.join(brew_pkg_rootdir, opt.plat == \"macosx\" and \"Cellar\" or \"opt\")\n\n    -- find package from pkg-config\n    local result = _find_package_from_pkgconfig(name,\n        table.join(opt, {brew_pkg_rootdir = brew_pkg_rootdir}))\n\n    -- find components\n    local components\n    local components_extsources = opt.components_extsources\n    for _, comp in ipairs(opt.components) do\n        local extsource = components_extsources and components_extsources[comp]\n        if extsource then\n            local component_result = _find_package_from_pkgconfig(extsource,\n                table.join(opt, {brew_pkg_rootdir = brew_pkg_rootdir}))\n            if component_result then\n                components = components or {}\n                components[comp] = component_result\n            end\n        end\n    end\n    if components then\n        result = result or {}\n        result.components = components\n        components.__base = {}\n    end\n\n    -- find package from xxx/lib, xxx/include\n    if not result then\n        local nameinfo = name:split('/')\n        local pkgdir\n        if is_host(\"linux\") then\n            -- /home/linuxbrew/.linuxbrew/opt/llvm\n            pkgdir = find_path(\"lib\", path.join(brew_pkg_rootdir, nameinfo[1]))\n        else\n            -- /usr/local/Cellar/llvm/16.0.6\n            pkgdir = find_path(\"lib\", path.join(brew_pkg_rootdir, nameinfo[1], \"*\"))\n        end\n        if pkgdir then\n            local links = {}\n            for _, libfile in ipairs(os.files(path.join(pkgdir, \"lib\", \"*.a\"))) do\n                table.insert(links, target.linkname(path.filename(libfile), {plat = opt.plat}))\n            end\n            for _, libfile in ipairs(os.files(path.join(pkgdir, \"lib\", opt.plat == \"macosx\" and \"*.dylib\" or \"*.so\"))) do\n                if not os.islink(libfile) then\n                    table.insert(links, target.linkname(path.filename(libfile), {plat = opt.plat}))\n                end\n            end\n            opt.links       = links\n            opt.linkdirs    = path.join(pkgdir, \"lib\")\n            opt.includedirs = path.join(pkgdir, \"include\")\n            result = find_package(\"system::\" .. name, opt)\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/brew/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n--\n-- @param name  the package name, e.g. pcre2, pcre2/libpcre2-8\n-- @param opt   the options, e.g. {verbose = true}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- find brew\n    local brew = find_tool(\"brew\")\n    if not brew then\n        raise(\"brew not found!\")\n    end\n\n    -- check architecture\n    if opt.arch ~= os.arch() then\n        raise(\"cannot install package(%s) for arch(%s)!\", name, opt.arch)\n    end\n\n    -- init argv\n    local argv = {\"install\", name:split('/')[1]}\n    if opt.verbose or option.get(\"verbose\") then\n        table.insert(argv, \"--verbose\")\n    end\n\n    -- install package\n    os.vrunv(brew.program, argv)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/cargo/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get configurations\nfunction main()\n    return\n    {\n        features         = {description = \"Set the features of dependency.\"},\n        default_features = {description = \"Enable or disable any defaults provided by the dependency.\", default = true},\n        std              = {description = \"Enable or disable std module.\"},\n        main             = {description = \"Enable or disable main entry function.\"},\n        cargo_toml       = {description = \"Set Cargo.toml file path\"}\n    }\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/cargo/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.base.json\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\"private.tools.rust.check_target\")\n\n-- get cargo registry directory\nfunction _get_cargo_registrydir()\n    return path.join(is_host(\"windows\") and os.getenv(\"USERPROFILE\") or \"~\", \".cargo\", \"registry\")\nend\n\n-- get the Cargo.toml of package\n-- e.g. ~/.cargo/registry/src/github.com-1ecc6299db9ec823/obj-rs-0.6.4/Cargo.toml\nfunction _get_package_toml(name)\n    local registrydir = _get_cargo_registrydir()\n    local registrysrc = path.join(registrydir, \"src\")\n    if os.isdir(registrysrc) then\n        local files = os.files(path.join(registrysrc, \"*\", name .. \"-*\", \"Cargo.toml\"))\n        for _, file in ipairs(files) do\n            local dir = path.directory(file)\n            local basename = path.filename(dir)\n            if basename:startswith(name) then\n                basename = basename:sub(#name + 1)\n                if basename:match(\"^%-[%d%.]+$\") then\n                    return file\n                end\n            end\n        end\n    end\nend\n\n-- get rust library name\n--\n-- e.g.\n-- sdl2 -> libsdl2\n-- future-util -> libfuture_util\nfunction _get_libname(name)\n    -- we attempt to parse libname from Cargo.toml/[lib]\n    -- @see https://github.com/xmake-io/xmake/issues/3452\n    -- e.g. obj-rs -> libobj\n    local tomlfile = _get_package_toml(name)\n    if tomlfile then\n        local libinfo = false\n        local tomldata = io.readfile(tomlfile)\n        for _, line in ipairs(tomldata:split(\"\\n\")) do\n            if line:find(\"[lib]\", 1, true) then\n                libinfo = true\n            elseif line:find(\"[\", 1, true) then\n                libinfo = false\n            elseif libinfo then\n                local name = line:match(\"name%s+=%s+\\\"(.+)\\\"\")\n                if name then\n                    return \"lib\" .. name\n                end\n            end\n        end\n    end\n    return \"lib\" .. name:gsub(\"-\", \"_\")\nend\n\n-- get the name set of libraries\nfunction _get_names_of_libraries(name, opt)\n    local configs = opt.configs or {}\n    local names = hashset.new()\n    local metadata_file = path.join(opt.installdir, \"metadata.txt\")\n    if configs.cargo_toml and os.isfile(metadata_file) then\n        local fileinfo = io.load(metadata_file)\n        local metadata = json.decode(fileinfo.metadata)\n        local metadata_without_deps = json.decode(fileinfo.metadata_without_deps)\n\n        -- FIXME: should consider the case of multiple packages in a workspace!\n        local direct_deps = metadata_without_deps.packages[1].dependencies\n\n        -- get the intersection of the direct dependencies and all dependencies for the target platform\n        for _, dep in ipairs(direct_deps) do\n            local dep_metadata\n            for _, pkg in ipairs(metadata.packages) do\n                if pkg.name == dep.name then\n                    dep_metadata = pkg\n                    break\n                end\n            end\n            if dep_metadata then\n                names:insert(_get_libname(dep.name))\n            end\n        end\n    else\n        names:insert(_get_libname(name))\n    end\n    return names\nend\n\n-- find package using the cargo package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, require_version = \"1.12.x\")\n--\nfunction main(name, opt)\n\n    -- get configs\n    opt = opt or {}\n    local configs = opt.configs or {}\n\n    -- get names of libraries\n    local names = _get_names_of_libraries(name, opt)\n    assert(not names:empty())\n\n    local frameworkdirs\n    local frameworks\n    local librarydir = path.join(opt.installdir, \"lib\")\n    local librarydir_host = path.join(opt.installdir, \"lib\", \"host\")\n    local libfiles = os.files(path.join(librarydir, \"*.rlib\"))\n\n    local frameworkdirs = {}\n    table.insert(frameworkdirs, librarydir)\n    if os.isdir(librarydir_host) then\n        table.insert(frameworkdirs, librarydir_host)\n    end\n\n    -- @see https://github.com/xmake-io/xmake/issues/4228\n    local libfiles_native\n    local plat = opt.plat\n    if plat == \"macosx\" then\n        libfiles_native = os.files(path.join(librarydir, \"*.dylib\"))\n    elseif plat == \"windows\" or plat == \"mingw\" then\n        libfiles_native = os.files(path.join(librarydir, \"*.lib\"))\n    else\n        libfiles_native = os.files(path.join(librarydir, \"*.so\"))\n    end\n    -- @see https://github.com/xmake-io/xmake/issues/5156\n    local libfiles_native_host\n    if is_host(\"macosx\") then\n        libfiles_native_host = os.files(path.join(librarydir_host, \"*.dylib\"))\n    elseif is_host(\"windows\") then\n        libfiles_native_host = os.files(path.join(librarydir_host, \"*.lib|*.dll.lib\"))\n        table.join2(libfiles_native_host, os.files(path.join(librarydir_host, \"*.dll\")))\n    else\n        libfiles_native_host = os.files(path.join(librarydir_host, \"*.so\"))\n    end\n    local libraries_set = {}\n    for _, libraryfile in ipairs(table.join(libfiles or {}, libfiles_native or {}, libfiles_native_host)) do\n        local filename = path.filename(libraryfile)\n        local libraryname = filename:split('-', {plain = true})[1]\n        -- https://github.com/xmake-io/xmake/issues/5156#issuecomment-2143509207\n        if not libraryname:startswith(\"lib\") then\n            libraryname = \"lib\" .. libraryname\n        end\n        if names:has(libraryname) and not libraries_set[libraryname] then\n            frameworks = frameworks or {}\n            table.insert(frameworks, libraryfile)\n            libraries_set[libraryname] = true\n        end\n    end\n    local result\n    if frameworks and frameworkdirs then\n        result = result or {}\n        result.libfiles = libfiles\n        result.frameworkdirs = frameworkdirs\n        result.frameworks = frameworks\n        result.version = opt.require_version\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/cargo/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tools.rustc.target_triple\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.tools.rust.check_target\")\n\n-- translate local path in dependencies\n-- @see https://github.com/xmake-io/xmake/issues/4222\n-- https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html\n--\n-- e.g.\n-- [dependencies]\n-- hello_utils = { path = \"./hello_utils\", version = \"0.1.0\" }\n--\n-- [dependencies.my_lib]\n-- path = \"../my_lib\"\nfunction _translate_local_path_in_deps(cargotoml, rootdir)\n    local content = io.readfile(cargotoml)\n    content = content:gsub(\"path%s+=%s+\\\"(.-)\\\"\", function (localpath)\n        if not path.is_absolute(localpath) then\n            localpath = path.absolute(localpath, rootdir)\n        end\n        localpath = localpath:gsub(\"\\\\\", \"/\")\n        return \"path = \\\"\" .. localpath .. \"\\\"\"\n    end)\n    io.writefile(cargotoml, content)\nend\n\n-- install package\n--\n-- e.g.\n-- add_requires(\"cargo::base64\")\n-- add_requires(\"cargo::base64 0.13.0\")\n-- add_requires(\"cargo::flate2 1.0.17\", {configs = {features = {\"zlib\"}, [\"default-features\"] = false}})\n-- add_requires(\"cargo::xxx\", {configs = {cargo_toml = path.join(os.projectdir(), \"Cargo.toml\")}})\n--\n-- @param name  the package name, e.g. cargo::base64\n-- @param opt   the options, e.g. { verbose = true, mode = \"release\", plat = , arch = , require_version = \"x.x.x\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- find cargo\n    local cargo = find_tool(\"cargo\")\n    if not cargo then\n        raise(\"cargo not found!\")\n    end\n\n    -- get required version\n    opt = opt or {}\n    local configs = opt.configs or {}\n    local require_version = opt.require_version\n    if not require_version or require_version == \"latest\" then\n        require_version = \"*\"\n    end\n\n    -- get target\n    -- e.g. x86_64-pc-windows-msvc, aarch64-unknown-none\n    -- @see https://github.com/xmake-io/xmake/issues/4049\n    local target = #opt.arch:split(\"%-\") >= 2 and check_target(opt.arch, true) and opt.arch\n    if not target then\n        target = target_triple(opt.plat, opt.arch)\n    end\n\n    -- generate Cargo.toml\n    local sourcedir = path.join(opt.cachedir, \"source\")\n    local cargotoml = path.join(sourcedir, \"Cargo.toml\")\n    os.tryrm(sourcedir)\n    if configs.cargo_toml then\n        assert(os.isfile(configs.cargo_toml), \"%s not found!\", configs.cargo_toml)\n        os.cp(configs.cargo_toml, cargotoml)\n        _translate_local_path_in_deps(cargotoml, path.directory(configs.cargo_toml))\n        -- we need add `[workspace]` to prevent cargo from searching up for a parent.\n        -- https://github.com/rust-lang/cargo/issues/10534#issuecomment-1087631050\n        local tomlfile = io.open(cargotoml, \"a\")\n        tomlfile:print(\"\")\n        tomlfile:print(\"[lib]\")\n        tomlfile:print(\"crate-type = [\\\"staticlib\\\"]\")\n        tomlfile:print(\"\")\n        tomlfile:print(\"[workspace]\")\n        tomlfile:print(\"\")\n        tomlfile:close()\n    else\n        local tomlfile = io.open(cargotoml, \"w\")\n        tomlfile:print(\"[lib]\")\n        tomlfile:print(\"crate-type = [\\\"staticlib\\\"]\")\n        tomlfile:print(\"\")\n        tomlfile:print(\"[package]\")\n        tomlfile:print(\"name = \\\"cargodeps\\\"\")\n        tomlfile:print(\"version = \\\"0.1.0\\\"\")\n        tomlfile:print(\"edition = \\\"2018\\\"\")\n        tomlfile:print(\"\")\n        tomlfile:print(\"[dependencies]\")\n\n        local features = configs.features\n        if features then\n            features = table.wrap(features)\n            tomlfile:print(\"%s = {version = \\\"%s\\\", features = [\\\"%s\\\"], default-features = %s}\", name, require_version, table.concat(features, \"\\\", \\\"\"), configs.default_features)\n        else\n            tomlfile:print(\"%s = \\\"%s\\\"\", name, require_version)\n        end\n        tomlfile:print(\"\")\n        tomlfile:close()\n    end\n\n    -- generate .cargo/config.toml\n    local configtoml = path.join(sourcedir, \".cargo\", \"config.toml\")\n    if target then\n        io.writefile(configtoml, format([[\n[build]\ntarget = \"%s\"\n]], target))\n    end\n\n    -- generate main.rs\n    local file = io.open(path.join(sourcedir, \"src\", \"lib.rs\"), \"w\")\n    if configs.main == false then\n        file:print(\"#![no_main]\")\n    end\n    if configs.std == false then\n        file:print(\"#![no_std]\")\n    end\n    if configs.main == false then\n        file:print([[\n    use core::panic::PanicInfo;\n\n    #[panic_handler]\n    fn panic(_panic: &PanicInfo<'_>) -> ! {\n        loop {}\n    }]])\n    else\n        file:print([[\n    fn main() {\n        println!(\"Hello, world!\");\n    }]])\n    end\n    file:close()\n\n    -- do build\n    local argv = {\"build\"}\n    if opt.mode ~= \"debug\" then\n        table.insert(argv, \"--release\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(argv, option.get(\"diagnosis\") and \"-vv\" or \"-v\")\n    end\n    os.vrunv(cargo.program, argv, {curdir = sourcedir})\n\n    -- do install\n    local installdir = opt.installdir\n    local librarydir = path.join(installdir, \"lib\")\n    local librarydir_host = path.join(installdir, \"lib\", \"host\")\n    os.tryrm(librarydir)\n    if target then\n        os.vcp(path.join(sourcedir, \"target\", target, opt.mode == \"debug\" and \"debug\" or \"release\", \"deps\"), librarydir)\n        -- @see https://github.com/xmake-io/xmake/issues/5156#issuecomment-2142566862\n        os.vcp(path.join(sourcedir, \"target\", opt.mode == \"debug\" and \"debug\" or \"release\", \"deps\"), librarydir_host)\n    else\n        os.vcp(path.join(sourcedir, \"target\", opt.mode == \"debug\" and \"debug\" or \"release\", \"deps\"), librarydir)\n    end\n\n    -- install metadata\n    argv = {\"metadata\", \"--format-version\", \"1\", \"--manifest-path\", cargotoml, \"--color\", \"never\"}\n    if target then\n        table.insert(argv, \"--filter-platform\")\n        table.insert(argv, target)\n    end\n\n    local metadata = os.iorunv(cargo.program, argv, {curdir = sourcedir})\n\n    -- fetch the direct dependencies list regradless of the target platform\n    table.insert(argv, \"--no-deps\")\n    local metadata_without_deps = os.iorunv(cargo.program, argv, {curdir = sourcedir})\n\n    io.save(path.join(installdir, \"metadata.txt\"), {metadata = metadata, metadata_without_deps = metadata_without_deps})\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/clib/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Adel Vilkov (aka RaZeR-RBI)\n-- @file        configurations.lua\n--\n\n-- get configurations\nfunction main()\n    return\n    {\n        save = {description = \"save dependency in project's package.json\", default = false, type = \"boolean\"},\n        save_dev = {description = \"save as development dependency in project's package.json\", default = false, type = \"boolean\"},\n        outputdir = {description = \"package installation directory relative to project root\", default = \"clib\"},\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/clib/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Adel Vilkov (aka RaZeR-RBI)\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\n\nfunction main(name, opt)\n    -- check if a package marker file with install directory exists\n    local cache_dir = path.join(config.directory(), \"clib\", \"cache\", \"packages\")\n    local marker_filename = string.gsub(name, \"%/\", \"=\")\n    local marker_path = path.join(cache_dir, marker_filename)\n    dprint(\"looking for marker file for %s at %s\", name, marker_path)\n\n    if not os.isfile(marker_path) then\n        dprint(\"no marker file found for %s\", name)\n        return\n    end\n\n    dprint(\"found marker file for %s\", name)\n    return io.load(marker_path)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/clib/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Adel Vilkov (aka RaZeR-RBI)\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n-- @param name  the package name, e.g. clib::clibs/bytes@0.4.0\n-- @param opt   the options, e.g. { verbose = true,\n--                                  configs = {outputdir = \"clib\", save = false, save_dev = false}}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- find clib\n    local clib = find_tool(\"clib\")\n    if not clib then\n        raise(\"clib not found!\")\n    end\n\n    opt = opt or {}\n    local configs = opt.configs or {}\n    local argv = {\"install\", name}\n    local abs_out = path.join(os.projectdir(), configs.outputdir)\n    dprint(\"installing %s to %s\", name, abs_out)\n    table.insert(argv, \"-o \" .. abs_out)\n\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    if configs.save then\n        table.insert(argv, \"--save\")\n    end\n    if configs.save_dev then\n        table.insert(argv, \"--save-dev\")\n    end\n\n    -- save previous directory and cd to project directory\n    local old_dir = os.curdir()\n    os.cd(os.projectdir())\n\n    -- do install\n    os.vrunv(clib.program, argv)\n\n    -- restore old directory\n    os.cd(old_dir)\n\n    -- add a package marker file with install directory\n    local cache_dir = path.join(config.directory(), \"clib\", \"cache\", \"packages\")\n    local marker_filename = string.gsub(name, \"%/\", \"=\")\n    local marker_path = path.join(cache_dir, marker_filename)\n    dprint(\"writing clib marker file for %s to %s\", name, marker_path)\n    io.save(marker_path, {includedirs = { abs_out }})\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/cmake/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get configurations\nfunction main()\n    return\n    {\n        link_libraries      = {description = \"Set the cmake package dependencies, e.g. {\\\"abc::lib1\\\", \\\"abc::lib2\\\"}\"},\n        include_directories = {description = \"Set the cmake package include directories, e.g. {\\\"${ZLIB_INCLUDE_DIRS}\\\"}\"},\n        search_mode         = {description = \"Set the cmake package search mode, e.g. {\\\"config\\\", \\\"module\\\"}\"},\n        components          = {description = \"Set the cmake package components, e.g. {\\\"regex\\\", \\\"system\\\"}\"},\n        moduledirs          = {description = \"Set the cmake modules directories.\"},\n        presets             = {description = \"Set the preset values, e.g. {Boost_USE_STATIC_LIB = true}\"},\n        envs                = {description = \"Set the run environments of cmake, e.g. {CMAKE_PREFIX_PATH = \\\"xxx\\\"}\"},\n        allow_empty_package = {description = \"Accept package even if it doesn't have any include directories or linked libraries\"},\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/cmake/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\n\n-- exclude cmake internal definitions https://github.com/xmake-io/xmake/issues/5217\nfunction _should_exclude(define)\n    local name = define:split(\"=\")[1]\n    return table.contains({\"CMAKE_INTDIR\", \"_DEBUG\", \"NDEBUG\"}, name)\nend\n\n-- map xmake mode to cmake mode\nfunction _cmake_mode(mode)\n    if mode == \"debug\" then return \"Debug\"\n    elseif mode == \"releasedbg\" then return \"RelWithDebInfo\"\n    elseif mode == \"minsizerel\" then return \"MinSizeRel\"\n    else return \"Release\"\n    end\nend\n\n-- find package\nfunction _find_package(cmake, name, opt)\n\n    -- get work directory\n    local workdir = os.tmpfile() .. \".dir\"\n    os.tryrm(workdir)\n    os.mkdir(workdir)\n    io.writefile(path.join(workdir, \"test.cpp\"), \"\")\n\n    -- generate CMakeLists.txt\n    local filepath = path.join(workdir, \"CMakeLists.txt\")\n    local cmakefile = io.open(filepath, \"w\")\n    if cmake.version then\n        cmakefile:print(\"cmake_minimum_required(VERSION %s)\", cmake.version)\n    end\n    cmakefile:print(\"project(find_package)\")\n\n    -- e.g. OpenCV 4.1.1, Boost COMPONENTS regex system\n    local requirestr = name\n    local configs = opt.configs or {}\n    if opt.require_version and opt.require_version ~= \"latest\" then\n        requirestr = requirestr .. \" \" .. opt.require_version\n    end\n    -- set search mode, e.g. config, module\n    -- it will be both mode if do not set this config.\n    -- e.g. https://cmake.org/cmake/help/latest/command/find_package.html#id4\n    if configs.search_mode then\n        requirestr = requirestr .. \" \" .. configs.search_mode:upper()\n    end\n    -- use opt.components is for backward compatibility\n    local componentstr = \"\"\n    local components = configs.components or opt.components\n    if components and #components > 0 then\n        componentstr = \"COMPONENTS\"\n        for _, component in ipairs(components) do\n            componentstr = componentstr .. \" \" .. component\n        end\n    end\n    local moduledirs = configs.moduledirs or opt.moduledirs\n    if moduledirs then\n        for _, moduledir in ipairs(moduledirs) do\n            cmakefile:print(\"list(APPEND CMAKE_MODULE_PATH \\\"%s\\\")\", (moduledir:gsub(\"\\\\\", \"/\")))\n        end\n    end\n    -- https://github.com/xmake-io/xmake/issues/6296\n    local prefixdirs = configs.prefixdirs or opt.prefixdirs\n    if prefixdirs then\n        for _, prefixdir in ipairs(prefixdirs) do\n            cmakefile:print(\"list(APPEND CMAKE_PREFIX_PATH \\\"%s\\\")\", (prefixdir:gsub(\"\\\\\", \"/\")))\n        end\n    end\n\n    -- e.g. set(Boost_USE_STATIC_LIB ON)\n    local presets = configs.presets or opt.presets\n    if presets then\n        for k, v in pairs(presets) do\n            if type(v) == \"boolean\" then\n                cmakefile:print(\"set(%s %s)\", k, v and \"ON\" or \"OFF\")\n            else\n                cmakefile:print(\"set(%s %s)\", k, tostring(v))\n            end\n        end\n    end\n    local testname = \"test_\" .. name\n    cmakefile:print(\"find_package(%s REQUIRED %s)\", requirestr, componentstr)\n    cmakefile:print(\"add_executable(%s test.cpp)\", testname)\n    -- setup include directories\n    local includedirs = \"\"\n    if configs.include_directories then\n        includedirs = table.concat(table.wrap(configs.include_directories), \" \")\n    else\n        includedirs = (\"${%s_INCLUDE_DIR} ${%s_INCLUDE_DIRS}\"):format(name, name)\n        includedirs = includedirs .. (\" ${%s_INCLUDE_DIR} ${%s_INCLUDE_DIRS}\"):format(name:upper(), name:upper())\n    end\n    cmakefile:print(\"target_include_directories(%s PRIVATE %s)\", testname, includedirs)\n    -- reserved for backword compatibility\n    cmakefile:print(\"target_include_directories(%s PRIVATE ${%s_CXX_INCLUDE_DIRS})\",\n        testname, name)\n    -- setup link library/target\n    local linklibs = \"\"\n    if configs.link_libraries then\n        linklibs = table.concat(table.wrap(configs.link_libraries), \" \")\n    else\n        linklibs = (\"${%s_LIBRARY} ${%s_LIBRARIES} ${%s_LIBS}\"):format(name, name, name)\n        linklibs = linklibs .. (\" ${%s_LIBRARY} ${%s_LIBRARIES} ${%s_LIBS}\"):format(name:upper(), name:upper(), name:upper())\n    end\n    cmakefile:print(\"target_link_libraries(%s PRIVATE %s)\", testname, linklibs)\n    cmakefile:close()\n    if option.get(\"diagnosis\") then\n        local cmakedata = io.readfile(filepath)\n        cprint(\"finding it from the generated CMakeLists.txt:\")\n        io.write(cmakedata .. \"\\n\")\n    end\n\n    -- run cmake\n    local envs = configs.envs or opt.envs or {}\n    envs.CMAKE_BUILD_TYPE = envs.CMAKE_BUILD_TYPE or _cmake_mode(opt.mode or \"release\")\n    -- If the generated CMakeLists.txt fails to find the REQUIRED package, CMake will exit\n    -- with code 1, os.vrunv will raise an error and the try{} block will return nil.\n    local ok = try {function()\n        os.vrunv(cmake.program, {workdir}, {curdir = workdir, envs = envs})\n        return true\n    end}\n    if not ok then\n        return\n    end\n\n    -- parse defines and includedirs for macosx/linux\n    local links\n    local linkdirs\n    local libfiles\n    local defines\n    local includedirs\n    local ldflags\n    local flagsfile = path.join(workdir, \"CMakeFiles\", testname .. \".dir\", \"flags.make\")\n    if os.isfile(flagsfile) then\n        local flagsdata = io.readfile(flagsfile)\n        if flagsdata then\n            if option.get(\"diagnosis\") then\n                cprint(\"finding includes from %s\", flagsfile)\n                io.write(flagsdata .. \"\\n\")\n            end\n            for _, line in ipairs(flagsdata:split(\"\\n\", {plain = true})) do\n                if line:find(\"CXX_INCLUDES =\", 1, true) then\n                    local has_include = false\n                    local flags = os.argv(line:split(\"=\", {plain = true})[2]:trim())\n                    for _, flag in ipairs(flags) do\n                        if has_include or (flag:startswith(\"-I\") and #flag > 2) then\n                            local includedir = has_include and flag or flag:sub(3)\n                            if includedir and os.isdir(includedir) then\n                                includedirs = includedirs or {}\n                                table.insert(includedirs, includedir)\n                            end\n                            has_include = false\n                        elseif flag == \"-isystem\" or flag == \"-I\" then\n                            has_include = true\n                        end\n                    end\n                elseif line:find(\"CXX_DEFINES =\", 1, true) then\n                    defines = defines or {}\n                    local flags = os.argv(line:split(\"=\", {plain = true})[2]:trim())\n                    for _, flag in ipairs(flags) do\n                        if flag:startswith(\"-D\") and #flag > 2 then\n                            local define = flag:sub(3)\n                            if define and not _should_exclude(define) then\n                                table.insert(defines, define)\n                            end\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- parse links and linkdirs for macosx/linux\n    local linkfile = path.join(workdir, \"CMakeFiles\", testname .. \".dir\", \"link.txt\")\n    if os.isfile(linkfile) then\n        local linkdata = io.readfile(linkfile)\n        if linkdata then\n            if option.get(\"diagnosis\") then\n                cprint(\"finding links from %s\", linkfile)\n                io.write(linkdata .. \"\\n\")\n            end\n            for _, line in ipairs(os.argv(linkdata)) do\n                local is_ldflags = false\n                local is_library = false\n                for _, suffix in ipairs({\".so\", \".dylib\", \".dylib\", \".tbd\", \".lib\"}) do\n                    if line:startswith(\"-Wl,\") then\n                        is_ldflags = true\n                        break\n                    elseif line:find(suffix, 1, true) then\n                        is_library = true\n                        break\n                    end\n                end\n                if is_ldflags then\n                    ldflags = ldflags or {}\n                    table.insert(ldflags, line)\n                elseif is_library then\n                    -- strip library version suffix, e.g. libxxx.so.1.1 -> libxxx.so\n                    if line:find(\".so\", 1, true) then\n                        line = line:gsub(\"lib(.-)%.so%..+$\", \"lib%1.so\")\n                    end\n\n                    -- get libfiles\n                    if os.isfile(line) then\n                        libfiles = libfiles or {}\n                        table.insert(libfiles, line)\n                    end\n\n                    -- get links and linkdirs\n                    local linkdir = path.directory(line)\n                    if linkdir ~= \".\" then\n                        linkdirs = linkdirs or {}\n                        table.insert(linkdirs, linkdir)\n                    end\n                    local link = target.linkname(path.filename(line))\n                    if link then\n                        links = links or {}\n                        table.insert(links, link)\n                    end\n                -- is link? e.g. -lxxx\n                elseif line:startswith(\"-l\") then\n                    local link = line:sub(3):trim()\n                    links = links or {}\n                    table.insert(links, link)\n                end\n            end\n        end\n    end\n\n    -- pares includedirs and links/linkdirs for windows\n    local vcprojfile = path.join(workdir, testname .. \".vcxproj\")\n    if os.isfile(vcprojfile) then\n        local vcprojdata = io.readfile(vcprojfile)\n        local vs_mode = envs.CMAKE_BUILD_TYPE or _cmake_mode(opt.mode or \"release\")\n        vcprojdata = vcprojdata:match(\"<ItemDefinitionGroup Condition=\\\"'$%(Configuration%)|$%(Platform%)'=='\" .. vs_mode .. \"|.->(.-)</ItemDefinitionGroup>\")\n\n        if vcprojdata then\n            for _, line in ipairs(vcprojdata:split(\"\\n\", {plain = true})) do\n                local values = line:match(\"<AdditionalIncludeDirectories>(.+);%%%(AdditionalIncludeDirectories%)</AdditionalIncludeDirectories>\")\n                if values then\n                    includedirs = includedirs or {}\n                    table.join2(includedirs, path.splitenv(values))\n                end\n\n                values = line:match(\"<AdditionalDependencies>(.+)</AdditionalDependencies>\")\n                if values then\n                    for _, library in ipairs(path.splitenv(values)) do\n                        -- get libfiles\n                        if os.isfile(library) then\n                            libfiles = libfiles or {}\n                            table.insert(libfiles, library)\n                        end\n\n                        -- get links and linkdirs\n                        local linkdir = path.directory(library)\n                        linkdir = path.translate(linkdir)\n                        if linkdir ~= \".\" and not linkdir:startswith(workdir) then\n                            linkdirs = linkdirs or {}\n                            table.insert(linkdirs, linkdir)\n                            local link = target.linkname(path.filename(library))\n                            if link then\n                                links = links or {}\n                                table.insert(links, link)\n                            end\n                        end\n                    end\n                end\n\n                values = line:match(\"<PreprocessorDefinitions>%%%(PreprocessorDefinitions%);(.+)</PreprocessorDefinitions>\")\n                if values then\n                    defines = defines or {}\n                    values = path.splitenv(values)\n                    for _, value in ipairs(values) do\n                        if not _should_exclude(value) then\n                            table.insert(defines, value)\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- remove work directory\n    os.tryrm(workdir)\n\n    -- get results\n    if configs.allow_empty_package or links or includedirs then\n        local results = {}\n        results.links       = table.reverse_unique(links)\n        results.ldflags     = table.reverse_unique(ldflags)\n        results.linkdirs    = table.unique(linkdirs)\n        results.defines     = table.unique(defines)\n        results.libfiles    = table.unique(libfiles)\n        results.includedirs = table.unique(includedirs)\n        return results\n    end\nend\n\n-- find package using the cmake package manager\n--\n-- e.g.\n--\n-- find_package(\"cmake::ZLIB\")\n-- find_package(\"cmake::OpenCV\", {require_version = \"4.1.1\"})\n-- find_package(\"cmake::Boost\", {configs = {components = {\"regex\", \"system\"}, presets = {Boost_USE_STATIC_LIB = true}}})\n-- find_package(\"cmake::Foo\", {configs = {moduledirs = \"xxx\"}})\n--\n-- we can use add_requires with {system = true}\n--\n-- add_requires(\"cmake::ZLIB\", {system = true})\n-- add_requires(\"cmake::OpenCV 4.1.1\", {system = true})\n-- add_requires(\"cmake::Boost\", {configs = {components = {\"regex\", \"system\"}, presets = {Boost_USE_STATIC_LIB = true}}})\n-- add_requires(\"cmake::Foo\", {configs = {moduledirs = \"xxx\"}})\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, require_version = \"1.0\",\n--                                 configs = {\n--                                      components = {\"regex\", \"system\"},\n--                                      moduledirs = \"xxx\",\n--                                      presets = {Boost_USE_STATIC_LIB = true},\n--                                      envs = {CMAKE_PREFIX_PATH = \"xxx\"}})\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local cmake = find_tool(\"cmake\", {version = true})\n    if not cmake then\n        return\n    end\n    return _find_package(cmake, name, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get arch for conan\nfunction arch(arch)\n    local map = {x86_64          = \"x86_64\",\n                 x64             = \"x86_64\",\n                 i386            = \"x86\",\n                 x86             = \"x86\",\n                 armv7           = \"armv7\",\n                 [\"armv7-a\"]     = \"armv7\",  -- for android, deprecated\n                 [\"armeabi\"]     = \"armv7\",  -- for android, removed in ndk r17\n                 [\"armeabi-v7a\"] = \"armv7\",  -- for android\n                 armv7s          = \"armv7s\", -- for iphoneos\n                 arm64           = \"armv8\",  -- for iphoneos\n                 [\"arm64-v8a\"]   = \"armv8\",  -- for android\n                 mips            = \"mips\",\n                 mips64          = \"mips64\",\n                 wasm32          = \"wasm\"}\n    return assert(map[arch], \"unknown arch(%s)!\", arch)\nend\n\n-- get os platform for conan\nfunction plat(plat)\n    local map = {macosx   = \"Macos\",\n                 windows  = \"Windows\",\n                 mingw    = \"Windows\",\n                 linux    = \"Linux\",\n                 cross    = \"Linux\",\n                 iphoneos = \"iOS\",\n                 android  = \"Android\",\n                 wasm     = \"Emscripten\"}\n    return assert(map[plat], \"unknown plat(%s)!\", plat)\nend\n\n-- get build type\nfunction build_type(mode)\n    if mode == \"debug\" then\n        return \"Debug\"\n    else\n        return \"Release\"\n    end\nend\n\n-- get configurations\nfunction main()\n    return\n    {\n        build           = {description = \"Use it to choose if you want to build from sources.\", default = \"missing\", values = {\"all\", \"never\", \"missing\", \"outdated\"}},\n        remote          = {description = \"Set the conan remote server.\"},\n        options         = {description = \"Set the options values, e.g. shared=True\"},\n        settings        = {description = \"Set the host settings for conan.\"},\n        settings_host   = {description = \"Set the host settings for conan.\"},\n        settings_build  = {description = \"Set the build settings for conan.\"},\n        imports         = {description = \"Set the imports for conan 1.x, it has been deprecated in conan 2.x.\"},\n        build_requires  = {description = \"Set the build requires for conan.\"},\n        conf            = {description = \"Set the host configurations for conan, e.g. tools.microsoft.bash:subsystem=msys2\"},\n        conf_host       = {description = \"Set the host configurations for conan, e.g. tools.microsoft.bash:subsystem=msys2\"},\n        conf_build      = {description = \"Set the build configurations for conan, e.g. tools.microsoft.bash:subsystem=msys2\"},\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"package.manager.conan.configurations\")\n\n-- get build info file\nfunction _conan_get_buildinfo_file(name, dep_name)\n    local filename = \"conanbuildinfo.xmake.lua\"\n    if dep_name then\n        filename = \"conanbuildinfo_\" .. dep_name .. \".xmake.lua\"\n    end\n    return path.absolute(path.join(config.builddir() or os.tmpdir(), \".conan\", name, filename))\nend\n\n-- get info key\nfunction _conan_get_infokey(opt)\n    opt = opt or {}\n    local plat = configurations.plat(opt.plat)\n    local arch = configurations.arch(opt.arch)\n    local mode = configurations.build_type(opt.mode)\n    if plat and arch and mode then\n        return plat .. \"_\" .. arch .. \"_\" .. mode\n    end\nend\n\n-- get build info\nfunction _conan_get_buildinfo(name, opt)\n    opt = opt or {}\n    local buildinfo_file = _conan_get_buildinfo_file(name, opt.dep_name)\n    if not os.isfile(buildinfo_file) then\n        return\n    end\n\n    -- load build info\n    local infokey = _conan_get_infokey(opt)\n    if not infokey then\n        return\n    end\n    local buildinfo = io.load(buildinfo_file)\n    if buildinfo then\n        buildinfo = buildinfo[infokey]\n    end\n\n    -- get the package info of the given platform, architecture and mode\n    local found = false\n    local result = {}\n    local dep_names\n    for k, v in pairs(buildinfo) do\n        if not k:startswith(\"__\") then\n            if #table.wrap(v) > 0 then\n                result[k] = v\n                found = true\n            end\n        end\n    end\n\n    -- remove unused frameworks for linux\n    -- @see https://github.com/xmake-io/xmake/issues/5358\n    local plat = opt.plat\n    if found and result and plat ~= \"macosx\" and plat ~= \"iphoneos\" then\n        result.frameworks = nil\n        result.frameworkdirs = nil\n    end\n\n    if found then\n        return buildinfo, result\n    end\nend\n\n-- find conan library\nfunction _conan_find_library(name, opt)\n    opt = opt or {}\n    local buildinfo, result = _conan_get_buildinfo(name, opt)\n    if result then\n        local libfiles = {}\n        for _, linkdir in ipairs(result.linkdirs) do\n            for _, file in ipairs(os.files(path.join(linkdir, \"*\"))) do\n                if file:endswith(\".lib\") or file:endswith(\".a\") then\n                    result.static = true\n                    table.insert(libfiles, file)\n                elseif file:endswith(\".so\") or file:match(\".+%.so%..+$\") or file:endswith(\".dylib\") or file:endswith(\".dll\") then -- maybe symlink to libxxx.so.1\n                    result.shared = true\n                    table.insert(libfiles, file)\n                end\n            end\n        end\n        if opt.plat == \"windows\" or opt.plat == \"mingw\" then\n            for _, bindir in ipairs(buildinfo.__bindirs) do\n                for _, file in ipairs(os.files(path.join(bindir, \"*.dll\"))) do\n                    result.shared = true\n                    table.insert(libfiles, file)\n                end\n            end\n        end\n        for _, includedir in ipairs(result.includedirs) do\n            if not os.isdir(includedir) then\n                return\n            end\n        end\n        local require_version = opt.require_version\n        if require_version ~= nil and require_version ~= \"latest\" then\n            result.version = opt.require_version\n        end\n        result.libfiles = table.unique(libfiles)\n        return result, buildinfo.__dep_names\n    end\nend\n\n-- find package using the conan package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true)\n--\nfunction main(name, opt)\n    local result, dep_names = _conan_find_library(name, opt)\n    if result and dep_names then\n        for _, dep_name in ipairs(dep_names) do\n            local depinfo = _conan_find_library(name, table.join(opt, {dep_name = dep_name}))\n            for k, v in pairs(depinfo) do\n                result[k] = table.join(result[k] or {}, v)\n            end\n        end\n        for k, v in pairs(result) do\n            if k == \"links\" or k == \"syslinks\" or k == \"frameworks\" then\n                result[k] = table.unwrap(table.reverse_unique(v))\n            else\n                result[k] = table.unwrap(table.unique(v))\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n--\n-- @param name  the package name, e.g. conan::OpenSSL 1.0.2n\n-- @param opt   the options, e.g. { verbose = true, mode = \"release\", plat = , arch = ,\n--                                  configs = {\n--                                      remote = \"\", build = \"all\", options = {}, imports = {}, build_requires = {},\n--                                      settings = {\"compiler=msvc\", \"compiler.version=10\", \"compiler.runtime=MD\"}}}\n--\nfunction main(name, opt)\n    local conan = find_tool(\"conan\", {version = true})\n    if not conan then\n        raise(\"conan not found!\")\n    end\n    if conan.version and semver.compare(conan.version, \"2.0.5\") >= 0 then\n        -- https://github.com/conan-io/conan/issues/13709\n        import(\"package.manager.conan.v2.install_package\")(conan, name, opt)\n    elseif conan.version and semver.compare(conan.version, \"2.0.0\") < 0 then\n        import(\"package.manager.conan.v1.install_package\")(conan, name, opt)\n    else\n        -- conan 2.0.0-2.0.4 does not supported\n        raise(\"conan %s is not supported, please use conan 1.x\", conan.version)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search package using the conan package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n\n    -- find conan\n    local conan = find_tool(\"conan\")\n    if not conan then\n        raise(\"conan not found!\")\n    end\n\n    -- search packages\n    local results = {}\n    local searchdata = os.iorunv(conan.program, {\"search\", name})\n    for _, line in ipairs(searchdata:split(\"\\n\", {plain = true})) do\n        local packagename = line:trim()\n        if packagename:find(name, 1, true) then\n            table.insert(results, {name = \"conan::\" .. packagename})\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/v1/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_tool\")\nimport(\"devel.git\")\nimport(\"net.fasturl\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get build env\nfunction _conan_get_build_env(name, plat)\n    local value = config.get(name)\n    if value == nil then\n        value = platform.toolconfig(name, plat)\n    end\n    if value == nil then\n        value = platform.tool(name, plat)\n    end\n    value = table.unique(table.wrap(value))\n    if #value > 0 then\n        value = table.unwrap(value)\n        return value\n    end\nend\n\n-- get build directory\nfunction _conan_get_build_directory(name)\n    return path.absolute(path.join(config.builddir() or os.tmpdir(), \".conan\", name))\nend\n\n-- generate conanfile.txt\nfunction _conan_generate_conanfile(name, configs, opt)\n\n    -- trace\n    dprint(\"generate %s ..\", path.join(_conan_get_build_directory(name), \"conanfile.txt\"))\n\n    -- get conan options, imports and build_requires\n    local options        = table.wrap(configs.options)\n    local imports        = table.wrap(configs.imports)\n    local build_requires = table.wrap(configs.build_requires or \"xmake_generator/0.1.0@bincrafters/testing\")\n\n    -- @see https://docs.conan.io/en/latest/systems_cross_building/cross_building.html\n    -- generate it\n    local conanfile = io.open(\"conanfile.txt\", \"w\")\n    if conanfile then\n        conanfile:print(\"[generators]\")\n        conanfile:print(\"xmake\")\n        conanfile:print(\"[requires]\")\n        local require_version = opt.require_version\n        if require_version ~= nil and require_version ~= \"latest\" then\n            conanfile:print(\"%s/%s\", name, require_version)\n        else\n            conanfile:print(\"%s\", name)\n        end\n        if #options > 0 then\n            conanfile:print(\"[options]\")\n            for _, item in ipairs(options) do\n                if not item:find(\":\", 1, true) then\n                    item = name .. \":\" .. item\n                end\n                conanfile:print(\"%s\", item)\n            end\n        end\n        if #imports > 0 then\n            conanfile:print(\"[imports]\")\n            conanfile:print(\"%s\", table.concat(imports, \"\\n\"))\n        end\n        if #build_requires > 0 then\n            conanfile:print(\"[build_requires]\")\n            conanfile:print(\"%s\", table.concat(build_requires, \"\\n\"))\n        end\n        conanfile:close()\n    end\nend\n\n-- install xmake generator\nfunction _conan_install_xmake_generator(conan)\n    local xmake_generator_localdir = path.join(config.directory(), \"conan\", \"xmake_generator\")\n    if not os.isdir(xmake_generator_localdir) then\n\n        -- sort main urls\n        local mainurls = {\"https://github.com/xmake-io/conan-xmake_generator.git\",\n                          \"https://gitlab.com/xmake-io/conan-xmake_generator.git\",\n                          \"https://gitee.com/xmake-io/conan-xmake_generator.git\"}\n        fasturl.add(mainurls)\n        mainurls = fasturl.sort(mainurls)\n\n        -- clone xmake generator repository\n        local ok = false\n        for _, url in ipairs(mainurls) do\n            ok = try { function () git.clone(url, {depth = 1, branch = \"0.1.0/testing\", outputdir = xmake_generator_localdir}); return true end }\n            if ok then\n                break\n            end\n        end\n        if ok then\n            os.vrunv(conan.program, {\"export\", xmake_generator_localdir, \"bincrafters/testing\"})\n        end\n    end\nend\n\n-- install package\nfunction main(conan, name, opt)\n\n    -- get configs\n    opt = opt or {}\n    local configs = opt.configs or {}\n\n    -- get build directory\n    local builddir = _conan_get_build_directory(name)\n\n    -- clean the build directory\n    os.tryrm(builddir)\n    if not os.isdir(builddir) then\n        os.mkdir(builddir)\n    end\n\n    -- enter build directory\n    local oldir = os.cd(builddir)\n\n    -- install xmake generator\n    _conan_install_xmake_generator(conan)\n\n    -- generate conanfile.txt\n    _conan_generate_conanfile(name, configs, opt)\n\n    -- install package\n    local argv = {\"install\", \".\"}\n    if configs.build then\n        if configs.build == \"all\" then\n            table.insert(argv, \"--build\")\n        else\n            table.insert(argv, \"--build=\" .. configs.build)\n        end\n    end\n\n    -- set platform\n    local plats = {macosx = \"Macos\", windows = \"Windows\", mingw = \"Windows\", linux = \"Linux\", cross = \"Linux\", iphoneos = \"iOS\", android = \"Android\"}\n    table.insert(argv, \"-s\")\n    local plat = plats[opt.plat]\n    if plat then\n        table.insert(argv, \"os=\" .. plat)\n    else\n        raise(\"cannot install package(%s) on platform(%s)!\", name, opt.plat)\n    end\n\n    -- set architecture\n    local archs = {x86_64          = \"x86_64\",\n                   x64             = \"x86_64\",\n                   i386            = \"x86\",\n                   x86             = \"x86\",\n                   armv7           = \"armv7\",\n                   [\"armv7-a\"]     = \"armv7\",  -- for android, deprecated\n                   [\"armeabi\"]     = \"armv7\",  -- for android, removed in ndk r17\n                   [\"armeabi-v7a\"] = \"armv7\",  -- for android\n                   armv7s          = \"armv7s\", -- for iphoneos\n                   arm64           = \"armv8\",  -- for iphoneos\n                   [\"arm64-v8a\"]   = \"armv8\",  -- for android\n                   mips            = \"mips\",\n                   mips64          = \"mips64\"}\n    table.insert(argv, \"-s\")\n    local arch = archs[opt.arch]\n    if arch then\n        table.insert(argv, \"arch=\" .. arch)\n    else\n        raise(\"cannot install package(%s) for arch(%s)!\", name, opt.arch)\n    end\n\n    -- set build mode\n    table.insert(argv, \"-s\")\n    if opt.mode == \"debug\" then\n        table.insert(argv, \"build_type=Debug\")\n    else\n        table.insert(argv, \"build_type=Release\")\n    end\n\n    -- set compiler settings\n    if opt.plat == \"windows\" then\n        local vs = assert(config.get(\"vs\"), \"vs not found!\")\n        table.insert(argv, \"-s\")\n        table.insert(argv, \"compiler=Visual Studio\")\n        table.insert(argv, \"-s\")\n        table.insert(argv, \"compiler.version=\" .. toolchain_utils.get_vsver(vs))\n        if configs.runtimes then\n            table.insert(argv, \"-s\")\n            table.insert(argv, \"compiler.runtime=\" .. configs.runtimes)\n        end\n    elseif opt.plat == \"iphoneos\" then\n        local target_minver = nil\n        local toolchain_xcode = toolchain.load(\"xcode\", {plat = opt.plat, arch = opt.arch})\n        if toolchain_xcode then\n            target_minver = toolchain_xcode:config(\"target_minver\")\n        end\n        if target_minver and tonumber(target_minver) > 10 and (arch == \"armv7\" or arch == \"armv7s\" or arch == \"x86\") then\n            target_minver = \"10\" -- iOS 10 is the maximum deployment target for 32-bit targets\n        end\n        if target_minver then\n            table.insert(argv, \"-s\")\n            table.insert(argv, \"os.version=\" .. target_minver)\n        end\n    elseif opt.plat == \"android\" then\n        local ndk_sdkver = config.get(\"ndk_sdkver\")\n        if ndk_sdkver then\n            table.insert(argv, \"-s\")\n            table.insert(argv, \"os.api_level=\" .. ndk_sdkver)\n        end\n    end\n\n    -- set custom settings\n    for _, setting in ipairs(configs.settings) do\n        table.insert(argv, \"-s\")\n        table.insert(argv, setting)\n    end\n\n    -- set remote\n    if configs.remote then\n        table.insert(argv, \"-r\")\n        table.insert(argv, configs.remote)\n    end\n\n    -- TODO set environments\n    if opt.plat == \"android\" then\n        local envs = {}\n        local cflags   = table.join(table.wrap(_conan_get_build_env(\"cxflags\", opt.plat)), _conan_get_build_env(\"cflags\", opt.plat))\n        local cxxflags = table.join(table.wrap(_conan_get_build_env(\"cxflags\", opt.plat)), _conan_get_build_env(\"cxxflags\", opt.plat))\n        envs.CC        = _conan_get_build_env(\"cc\", opt.plat)\n        envs.CXX       = _conan_get_build_env(\"cxx\", opt.plat)\n        envs.AS        = _conan_get_build_env(\"as\", opt.plat)\n        envs.AR        = _conan_get_build_env(\"ar\", opt.plat)\n        envs.LD        = _conan_get_build_env(\"ld\", opt.plat)\n        envs.LDSHARED  = _conan_get_build_env(\"sh\", opt.plat)\n        envs.CPP       = _conan_get_build_env(\"cpp\", opt.plat)\n        envs.RANLIB    = _conan_get_build_env(\"ranlib\", opt.plat)\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(table.wrap(_conan_get_build_env(\"asflags\", opt.plat)), ' ')\n        envs.ARFLAGS   = table.concat(table.wrap(_conan_get_build_env(\"arflags\", opt.plat)), ' ')\n        envs.LDFLAGS   = table.concat(table.wrap(_conan_get_build_env(\"ldflags\", opt.plat)), ' ')\n        envs.SHFLAGS   = table.concat(table.wrap(_conan_get_build_env(\"shflags\", opt.plat)), ' ')\n        local toolchain_ndk = toolchain.load(\"ndk\", {plat = opt.plat, arch = opt.arch})\n        local ndk_sysroot = toolchain_ndk:config(\"ndk_sysroot\")\n        if ndk_sysroot then\n            table.insert(argv, \"-e\")\n            table.insert(argv, \"CONAN_CMAKE_FIND_ROOT_PATH=\" .. ndk_sysroot)\n        end\n        for k, v in pairs(envs) do\n            table.insert(argv, \"-e\")\n            table.insert(argv, k .. \"=\" .. v)\n        end\n    end\n\n    -- do install\n    os.vrunv(conan.program, argv)\n\n    -- leave build directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conan/v2/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\"detect.sdks.find_emsdk\")\nimport(\"devel.git\")\nimport(\"net.fasturl\")\nimport(\"package.manager.conan.configurations\")\n\n-- get build env\nfunction _conan_get_build_env(name, plat)\n    local value = config.get(name)\n    if value == nil then\n        value = platform.toolconfig(name, plat)\n    end\n    if value == nil then\n        value = platform.tool(name, plat)\n    end\n    value = table.unique(table.wrap(value))\n    if #value > 0 then\n        value = table.unwrap(value)\n        return value\n    end\nend\n\n-- get build directory\nfunction _conan_get_build_directory(name)\n    return path.absolute(path.join(config.builddir() or os.tmpdir(), \".conan\", name))\nend\n\n-- generate conanfile.txt\nfunction _conan_generate_conanfile(name, configs, opt)\n\n    -- trace\n    dprint(\"generate %s ..\", path.join(_conan_get_build_directory(name), \"conanfile.txt\"))\n\n    -- get conan options, imports and build_requires\n    local options        = table.wrap(configs.options)\n    local build_requires = table.wrap(configs.build_requires)\n\n    -- @see https://docs.conan.io/1/migrating_to_2.0/recipes.html\n    -- https://docs.conan.io/en/latest/systems_cross_building/cross_building.html\n    -- generate it\n    local conanfile = io.open(\"conanfile.txt\", \"w\")\n    if conanfile then\n        conanfile:print(\"[requires]\")\n        local require_version = opt.require_version\n        if require_version ~= nil and require_version ~= \"latest\" then\n            conanfile:print(\"%s/%s\", name, require_version)\n        else\n            conanfile:print(\"%s\", name)\n        end\n        if #options > 0 then\n            conanfile:print(\"[options]\")\n            for _, item in ipairs(options) do\n                if not item:find(\":\", 1, true) then\n                    item = name .. \"/*:\" .. item\n                end\n                conanfile:print(\"%s\", item)\n            end\n        end\n        if #build_requires > 0 then\n            conanfile:print(\"[tool_requires]\")\n            conanfile:print(\"%s\", table.concat(build_requires, \"\\n\"))\n        end\n        conanfile:close()\n    end\nend\n\n-- get conan home directory\nfunction _conan_get_homedir(conan)\n    local homedir = _g.homedir\n    if homedir == nil then\n        homedir = try {function () return os.iorunv(conan.program, {\"config\", \"home\"}) end}\n        _g.homedir = homedir\n    end\n    return homedir\nend\n\n-- install xmake generator\n-- @see https://github.com/conan-io/conan/pull/13718\n--\nfunction _conan_install_xmake_generator(conan)\n    local homedir = assert(_conan_get_homedir(conan), \"cannot get conan home\")\n    local scriptfile_now = path.join(os.programdir(), \"scripts\", \"conan\", \"extensions\", \"generators\", \"xmake_generator.py\")\n    local scriptfile_installed = path.join(homedir, \"extensions\", \"generators\", \"xmake_generator.py\")\n    if not os.isfile(scriptfile_installed) or os.mtime(scriptfile_now) > os.mtime(scriptfile_installed) then\n        os.vrunv(conan.program, {\"config\", \"install\", path.join(os.programdir(), \"scripts\", \"conan\")})\n    end\nend\n\n-- get compiler version\n--\n-- https://github.com/conan-io/conan/blob/353c63b16c31c90d370305b5cbb5dc175cf8a443/conan/tools/microsoft/visual.py#L13\n-- https://github.com/xmake-io/xmake/issues/5338\nfunction _conan_get_compiler_version(name, opt)\n    opt = opt or {}\n    local version\n    local result = find_tool(name, {program = opt.program, version = true, envs = opt.envs})\n    if result and result.version then\n        local v = semver.try_parse(result.version)\n        if v then\n            if name == \"cl\" then\n                version = tostring(v:major()) .. tostring(v:minor()):sub(1, 1)\n            else\n                version = tostring(v:major())\n            end\n        end\n    end\n    return version\nend\n\n-- generate compiler profile\nfunction _conan_generate_compiler_profile(profile, configs, opt)\n    local conf\n    local plat = opt.plat\n    local arch = opt.arch\n    local runtimes = configs.runtimes\n    if plat == \"windows\" then\n        local msvc = toolchain.load(\"msvc\", {plat = plat, arch = arch})\n        assert(msvc:check(), \"vs not found!\")\n        local vs = assert(msvc:config(\"vs\"), \"vs not found!\")\n        profile:print(\"compiler=msvc\")\n        local version = _conan_get_compiler_version(\"cl\", {envs = msvc:runenvs()})\n        if version then\n            profile:print(\"compiler.version=\" .. version)\n        end\n        -- @see https://github.com/conan-io/conan/issues/12387\n        if tonumber(vs) >= 2015 then\n            profile:print(\"compiler.cppstd=14\")\n        end\n        if runtimes then\n            profile:print(\"compiler.runtime=\" .. (runtimes:startswith(\"MD\") and \"dynamic\" or \"static\"))\n            profile:print(\"compiler.runtime_type=\" .. (runtimes:endswith(\"d\") and \"Debug\" or \"Release\"))\n        end\n    elseif plat == \"iphoneos\" then\n        local target_minver = nil\n        local xcode = toolchain.load(\"xcode\", {plat = plat, arch = arch})\n        if xcode then\n            target_minver = xcode:config(\"target_minver\")\n        end\n        if target_minver and tonumber(target_minver) > 10 and (arch == \"armv7\" or arch == \"armv7s\" or arch == \"x86\") then\n            target_minver = \"10\" -- iOS 10 is the maximum deployment target for 32-bit targets\n        end\n        if target_minver then\n            profile:print(\"os.version=\" .. target_minver)\n        end\n        local simulator = xcode:config(\"appledev\") == \"simulator\"\n        profile:print(\"os.sdk=\" .. (simulator and \"iphonesimulator\" or \"iphoneos\"))\n        profile:print(\"compiler=clang\")\n        local version = _conan_get_compiler_version(\"clang\")\n        if version then\n            profile:print(\"compiler.version=\" .. version)\n        end\n    elseif plat == \"android\" then\n        local ndk = toolchain.load(\"ndk\", {plat = plat, arch = arch})\n        local ndk_sdkver = ndk:config(\"ndk_sdkver\")\n        if ndk_sdkver then\n            profile:print(\"os.api_level=\" .. ndk_sdkver)\n        end\n        if runtimes then\n            profile:print(\"compiler.libcxx=\" .. runtimes)\n        end\n        local program, toolname = ndk:tool(\"cc\")\n        local version = _conan_get_compiler_version(toolname, {program = program})\n        profile:print(\"compiler=\" .. toolname)\n        if version then\n            profile:print(\"compiler.version=\" .. version)\n        end\n        conf = {}\n        conf[\"tools.android:ndk_path\"] = ndk:config(\"ndk\")\n    elseif plat == \"wasm\" then\n        local emsdk = find_emsdk()\n        assert(emsdk and emsdk.emscripten, \"emscripten not found!\")\n        local emscripten_cmakefile = find_file(\"Emscripten.cmake\", path.join(emsdk.emscripten, \"cmake/Modules/Platform\"))\n        assert(emscripten_cmakefile, \"Emscripten.cmake not found!\")\n\n        profile:print(\"compiler=gcc\")\n        profile:print(\"compiler.cppstd=gnu17\")\n        profile:print(\"compiler.libcxx=libstdc++11\")\n        profile:print(\"compiler.version=12\")\n\n        conf = {}\n        conf[\"tools.build:compiler_executables\"] = \"{'c':'emcc', 'cpp':'em++', 'ar':'emar', 'ranlib':'emranlib'}\"\n        conf[\"tools.cmake.cmaketoolchain:user_toolchain\"] = \"['\" ..emscripten_cmakefile .. \"']\"\n    else\n        local program, toolname = platform.tool(\"cc\", plat, arch)\n        if toolname == \"gcc\" or toolname == \"clang\" then\n            profile:print(\"compiler=\" .. toolname)\n            profile:print(\"compiler.cppstd=gnu17\")\n            local libcxx = \"libstdc++11\"\n            if runtimes and table.contains(table.wrap(runtimes), \"c++_static\", \"c++_shared\") then\n                libcxx = \"libc++\"\n            elseif not runtimes and toolname == \"clang\" then\n                libcxx = \"libc++\"\n            end\n            profile:print(\"compiler.libcxx=\" .. libcxx)\n            local version = _conan_get_compiler_version(toolname, {program = program})\n            if version then\n                profile:print(\"compiler.version=\" .. version)\n            end\n        end\n    end\n\n    if conf then\n        profile:print(\"\")\n        profile:print(\"[conf]\")\n        for k, v in pairs(conf) do\n            profile:print(\"%s=%s\", k, v)\n        end\n    end\nend\n\n-- generate build profile\nfunction _conan_generate_build_profile(configs, opt)\n    local profile = io.open(\"profile_build.txt\", \"w\")\n    profile:print(\"[settings]\")\n    profile:print(\"arch=%s\", configurations.arch(os.arch()))\n    profile:print(\"build_type=%s\", configurations.build_type(opt.mode))\n    profile:print(\"os=%s\", configurations.plat(os.host()))\n    _conan_generate_compiler_profile(profile, configs, {plat = os.host(), arch = os.arch()})\n    profile:close()\nend\n\n-- generate host profile\nfunction _conan_generate_host_profile(configs, opt)\n    local profile = io.open(\"profile_host.txt\", \"w\")\n    profile:print(\"[settings]\")\n    profile:print(\"arch=%s\", configurations.arch(opt.arch))\n    profile:print(\"build_type=%s\", configurations.build_type(opt.mode))\n    profile:print(\"os=%s\", configurations.plat(opt.plat))\n    _conan_generate_compiler_profile(profile, configs, opt)\n    profile:close()\nend\n\n-- install package\nfunction main(conan, name, opt)\n\n    -- get configs\n    opt = opt or {}\n    local configs = opt.configs or {}\n\n    -- get build directory\n    local builddir = _conan_get_build_directory(name)\n\n    -- clean the build directory\n    os.tryrm(builddir)\n    if not os.isdir(builddir) then\n        os.mkdir(builddir)\n    end\n\n    -- enter build directory\n    local oldir = os.cd(builddir)\n\n    -- install xmake generator\n    _conan_install_xmake_generator(conan)\n\n    -- generate conanfile.txt\n    _conan_generate_conanfile(name, configs, opt)\n\n    -- generate host profile\n    _conan_generate_host_profile(configs, opt)\n\n    -- generate build profile\n    _conan_generate_build_profile(configs, opt)\n\n    -- install package\n    local argv = {\"install\", \".\", \"-g\", \"XmakeGenerator\",\n        \"--profile:build=profile_build.txt\", \"--profile:host=profile_host.txt\"}\n    if configs.build then\n        if configs.build == \"all\" then\n            table.insert(argv, \"--build\")\n        else\n            table.insert(argv, \"--build=\" .. configs.build)\n        end\n    end\n\n    -- set custom host settings\n    for _, setting in ipairs(configs.settings or configs.settings_host) do\n        table.insert(argv, \"-s\")\n        table.insert(argv, setting)\n    end\n\n    -- set custom build settings\n    for _, setting in ipairs(configs.settings_build) do\n        table.insert(argv, \"-s:b\")\n        table.insert(argv, setting)\n    end\n\n    -- set custom host configurations\n    for _, conf in ipairs(configs.conf or configs.conf_host) do\n        table.insert(argv, \"-c\")\n        table.insert(argv, conf)\n    end\n\n    -- set custom build configurations\n    for _, conf in ipairs(configs.conf_build) do\n        table.insert(argv, \"-c:b\")\n        table.insert(argv, conf)\n    end\n\n    -- set remote\n    if configs.remote then\n        table.insert(argv, \"-r\")\n        table.insert(argv, configs.remote)\n    end\n\n    -- do install\n    os.vrunv(conan.program, argv)\n\n    -- leave build directory\n    os.cd(oldir)\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/conda/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\n\n-- get conda prefix directory\nfunction _conda_prefixdir(conda)\n    local prefixdir = _g.prefixdir\n    if prefixdir == nil then\n        prefixdir = os.getenv(\"CONDA_PREFIX\")\n        if not prefixdir then\n            local info = try {function () return os.iorunv(conda.program, {\"info\"}) end}\n            if info then\n                for _, line in ipairs(info:split('\\n', {plain = true})) do\n                    if line:find(\"base environment\") then\n                        prefixdir = line:match(\"ase environment : (.-) %(writable%)\")\n                        if prefixdir then\n                            prefixdir = prefixdir:trim()\n                        end\n                        break\n                    end\n                end\n            end\n        end\n        _g.prefixdir = prefixdir\n    end\n    return prefixdir\nend\n\n-- find package using the conda package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, require_version = \"1.12.0\")\n--\nfunction main(name, opt)\n\n    -- check\n    opt = opt or {}\n    if not is_host(opt.plat) or os.arch() ~= opt.arch then\n        return\n    end\n\n    -- find conda\n    local conda = find_tool(\"conda\")\n    if not conda then\n        return\n    end\n\n    -- find package\n    local version, build\n    local listinfo = try {function () return os.iorunv(conda.program, {\"list\", name}) end}\n    if listinfo then\n        for _, line in ipairs(listinfo:split('\\n', {plain = true})) do\n            if line:startswith(name) then\n                version, build = listinfo:match(name .. \"%s-([%w%.%d%-%+]+)%s-([%w%d_]+)\")\n                if version and build then\n                    break\n                end\n            end\n        end\n    end\n    if not version or not build then\n        return\n    end\n    if opt.require_version and opt.require_version:find('.', 1, true) and opt.require_version ~= version then\n        return\n    end\n\n    -- get meta info of package\n    -- e.g. ~/miniconda2/conda-meta/libpng-1.6.37-ha441bb4_0.json\n    local prefixdir = _conda_prefixdir(conda)\n    if not prefixdir then\n        return\n    end\n    local metafile = path.join(prefixdir, \"conda-meta\", name .. \"-\" .. version .. \"-\" .. build .. \".json\")\n    if not os.isfile(metafile) then\n        return\n    end\n    local metainfo = json.loadfile(metafile)\n    if not metainfo or not metainfo.extracted_package_dir then\n        return\n    end\n\n    -- save includedirs, linkdirs and links\n    local result = nil\n    local packagedir = metainfo.extracted_package_dir\n    for _, line in ipairs(metainfo.files) do\n        line = line:trim()\n\n        -- get includedirs\n        local pos = line:find(\"include/\", 1, true)\n        if pos then\n            result = result or {}\n            result.includedirs = result.includedirs or {}\n            table.insert(result.includedirs, path.join(packagedir, line:sub(1, pos + 7)))\n        end\n\n        -- get linkdirs and links\n        if line:endswith(\".lib\") or line:endswith(\".a\") or line:endswith(\".so\") or line:endswith(\".dylib\") then\n            result = result or {}\n            result.links = result.links or {}\n            result.linkdirs = result.linkdirs or {}\n            result.libfiles = result.libfiles or {}\n            table.insert(result.linkdirs, path.join(packagedir, path.directory(line)))\n            table.insert(result.links, target.linkname(path.filename(line), {plat = opt.plat}))\n            table.insert(result.libfiles, path.join(packagedir, path.directory(line), path.filename(line)))\n        end\n\n        -- add shared library directory (/bin/) to linkdirs for running with PATH on windows\n        if opt.plat == \"windows\" and line:endswith(\".dll\") then\n            result = result or {}\n            result.linkdirs = result.linkdirs or {}\n            result.libfiles = result.libfiles or {}\n            table.insert(result.linkdirs, path.join(packagedir, path.directory(line)))\n            table.insert(result.libfiles, path.join(packagedir, path.directory(line), path.filename(line)))\n        end\n    end\n\n    -- save version\n    if result then\n        result.version = metainfo.version or version\n    end\n\n    -- remove repeat\n    if result then\n        if result.links then\n            result.links = table.unique(result.links)\n        end\n        if result.linkdirs then\n            result.linkdirs = table.unique(result.linkdirs)\n        end\n        if result.includedirs then\n            result.includedirs = table.unique(result.includedirs)\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conda/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n--\n-- @param name  the package name, e.g. conda::libpng 1.6.37\n-- @param opt   the options, e.g. { verbose = true }\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- check\n    opt = opt or {}\n    assert(is_host(opt.plat) and os.arch() == opt.arch, \"conda cannot install %s for %s/%s\", name, opt.plat, opt.arch)\n\n    -- find conda\n    local conda = find_tool(\"conda\")\n    if not conda then\n        raise(\"conda not found!\")\n    end\n\n    -- install package\n    local argv = {\"install\", \"-y\"}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"-v\")\n    end\n    if opt.require_version and opt.require_version:find('.', 1, true) then\n        name = name .. \"=\" .. opt.require_version\n    end\n    table.insert(argv, name)\n    os.vrunv(conda.program, argv)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/conda/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search package using the conda package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n\n    -- find conda\n    local conda = find_tool(\"conda\")\n    if not conda then\n        raise(\"conda not found!\")\n    end\n\n    -- search packages\n    local results = {}\n    local searchdata = os.iorunv(conda.program, {\"search\", \"-q\", name})\n    for _, line in ipairs(searchdata:split(\"\\n\", {plain = true})) do\n        local splitinfo = line:split(\"%s+\", {limit = 3})\n        local packagename = splitinfo[1]\n        local version = splitinfo[2]\n        local description = splitinfo[3]\n        if packagename:find(name, 1, true) then\n            table.insert(results, {name = \"conda::\" .. packagename, version = version, description = description})\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/dub/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.json\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\n\n-- find package using the dub package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, require_version = \"1.12.x\")\n--\nfunction main(name, opt)\n\n    -- find dub\n    local dub = find_tool(\"dub\")\n    if not dub then\n        raise(\"dub not found!\")\n    end\n\n    -- get the library pattern\n    local libpattern = (opt.plat == \"windows\") and \"**.lib\" or \"**.a\"\n\n    -- find package\n    local result\n    local pkglist = os.iorunv(dub.program, {\"list\"})\n    if pkglist then\n        local pkgdir\n        for _, line in ipairs(pkglist:split('\\n', {plain = true})) do\n            local pkginfo = line:split(': ', {plain = true})\n            if #pkginfo == 2 then\n                local pkgkey  = pkginfo[1]:trim():split(' ', {plain = true})\n                local pkgpath = pkginfo[2]:trim()\n                if #pkgkey == 2 then\n                    local pkgname    = pkgkey[1]:trim()\n                    local pkgversion = pkgkey[2]:trim()\n                    if pkgname == name and find_file(libpattern, pkgpath) and\n                        (not opt.require_version or opt.require_version == \"latest\" or opt.require_version == \"master\" or semver.satisfies(pkgversion, opt.require_version)) then\n                        pkgdir = pkgpath\n                        break\n                    end\n                end\n            end\n        end\n        if pkgdir then\n            local links = {}\n            local linkdirs = {}\n            for _, libraryfile in ipairs(os.files(path.join(pkgdir, libpattern))) do\n                table.insert(links, target.linkname(path.filename(libraryfile), {plat = opt.plat}))\n                table.insert(linkdirs, path.directory(libraryfile))\n            end\n            linkdirs = table.unique(linkdirs)\n            local includedirs = {}\n            local dubjson = path.join(pkgdir, \"dub.json\")\n            if os.isfile(dubjson) then\n                dubjson = json.loadfile(dubjson)\n                if dubjson and dubjson.importPaths then\n                    for _, importPath in ipairs(dubjson.importPaths) do\n                        table.insert(includedirs, path.join(pkgdir, importPath))\n                    end\n                end\n            end\n            if #includedirs > 0 and #links > 0 then\n                result = {version = opt.require_version, links = links, linkdirs = linkdirs, includedirs = includedirs}\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/dub/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n--\n-- @param name  the package name, e.g. dub::log\n-- @param opt   the options, e.g. { verbose = true, mode = \"release\", plat = , arch = , require_version = \"x.x.x\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- find dub\n    local dub = find_tool(\"dub\")\n    if not dub then\n        raise(\"dub not found!\")\n    end\n\n    -- fetch the given package\n    local argv = {\"fetch\", name}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"-v\")\n    end\n    if opt.require_version and opt.require_version ~= \"latest\" and opt.require_version ~= \"master\" then\n        table.insert(argv, \"--version=\" .. opt.require_version)\n    end\n    os.vrunv(dub.program, argv)\n\n    -- build the given package\n    argv = {\"build\", name, \"-y\"}\n    if opt.mode == \"debug\" then\n        table.insert(argv, \"--build=debug\")\n    else\n        table.insert(argv, \"--build=release\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(argv, \"-v\")\n    end\n    local archs = {x86_64          = \"x86_64\",\n                   x64             = \"x86_64\",\n                   i386            = \"x86\",\n                   x86             = \"x86\"}\n    local arch = archs[opt.arch]\n    if arch then\n        table.insert(argv, \"--arch=\" .. arch)\n    else\n        raise(\"cannot install package(%s) for arch(%s)!\", name, opt.arch)\n    end\n    os.vrunv(dub.program, argv)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\n\n-- Is the current version matched?\nfunction _is_match_version(current_version, require_version)\n    if current_version then\n        if current_version == require_version then\n            return true\n        end\n        if semver.is_valid(current_version) and semver.satisfies(current_version, require_version) then\n            return true\n        end\n    end\nend\n\n-- find package with the builtin rule\n--\n-- opt.system:\n--   nil: find local or system packages\n--   true: only find system package\n--   false: only find local packages\n--\nfunction _find_package_with_builtin_rule(package_name, opt)\n\n    -- we cannot find it from xmake repo and package directories if only find system packages\n    local managers = {}\n    if opt.system ~= true then\n        table.insert(managers, \"xmake\")\n    end\n\n    -- find system package if be not disabled\n    if opt.system ~= false then\n        local plat = opt.plat\n        local arch = opt.arch\n        local find_from_host = not is_cross(plat, arch)\n        if find_from_host and not is_host(\"windows\") then\n            table.insert(managers, \"brew\")\n        end\n        -- vcpkg/conan support multi-platforms/architectures\n        table.insert(managers, \"vcpkg\")\n        table.insert(managers, \"conan\")\n        if find_from_host then\n            if not is_subhost(\"windows\") then\n                table.insert(managers, \"pkgconfig\")\n            end\n            if is_subhost(\"linux\", \"msys\") and plat ~= \"windows\" and find_tool(\"pacman\") then\n                table.insert(managers, \"pacman\")\n            end\n            if is_subhost(\"linux\", \"msys\") and plat ~= \"windows\" and find_tool(\"emerge\") then\n                table.insert(managers, \"portage\")\n            end\n            table.insert(managers, \"system\")\n        end\n    end\n\n    -- find package from the given package manager\n    local result = nil\n    local found_manager_name = nil\n    opt = table.join({try = true}, opt)\n    for _, manager_name in ipairs(managers) do\n        dprint(\"finding %s from %s ..\", package_name, manager_name)\n        result = import(\"package.manager.\" .. manager_name .. \".find_package\", {anonymous = true})(package_name, opt)\n        if result then\n            found_manager_name = manager_name\n            break\n        end\n    end\n    return result, found_manager_name\nend\n\n-- find package\nfunction _find_package(manager_name, package_name, opt)\n\n    -- find package from the given package manager\n    local result = nil\n    if manager_name then\n\n        -- trace\n        dprint(\"finding %s from %s ..\", package_name, manager_name)\n\n        -- TODO compatible with the previous version: pkg_config (deprecated)\n        if manager_name == \"pkg_config\" then\n            manager_name = \"pkgconfig\"\n            wprint(\"please use find_package(\\\"pkgconfig::%s\\\") instead of `pkg_config::%s`\", package_name, package_name)\n        end\n\n        -- find it\n        result = import(\"package.manager.\" .. manager_name .. \".find_package\", {anonymous = true})(package_name, opt)\n    else\n\n        -- find package from the given custom \"detect.packages.find_xxx\" script\n        local builtin = false\n        local find_package = import(\"detect.packages.find_\" .. package_name, {anonymous = true, try = true})\n        if find_package then\n\n            -- trace\n            dprint(\"finding %s from find_%s ..\", package_name, package_name)\n\n            -- find it\n            result = find_package(table.join(opt, { find_package = function (...)\n                                                        builtin = true\n                                                        return _find_package_with_builtin_rule(...)\n                                                    end}))\n        end\n\n        -- find package with the builtin rule\n        if not result and not builtin then\n            result, manager_name = _find_package_with_builtin_rule(package_name, opt)\n        end\n    end\n\n    -- found?\n    if result then\n\n        -- remove repeat\n        result.linkdirs    = table.unique(result.linkdirs)\n        result.includedirs = table.unique(result.includedirs)\n    end\n\n    -- ok?\n    return result, manager_name\nend\n\n-- find package using the package manager\n--\n-- @param name  the package name\n--              e.g. zlib 1.12.x (try all), xmake::zlib 1.12.x, brew::zlib, brew::pcre/libpcre16, vcpkg::zlib, conan::OpenSSL/1.0.2n@conan/stable\n-- @param opt   the options\n--              e.g. { verbose = false, force = false, plat = \"iphoneos\", arch = \"arm64\", mode = \"debug\", version = \"1.0.x\",\n--                     linkdirs = {\"/usr/lib\"}, includedirs = \"/usr/include\", links = {\"ssl\"}, includes = {\"ssl.h\"}\n--                     packagedirs = {\"/tmp/packages\"}, system = true}\n--\n-- @return      {links = {\"ssl\", \"crypto\", \"z\"}, linkdirs = {\"/usr/local/lib\"}, includedirs = {\"/usr/local/include\"}},\n--              manager_name, package_name\n--\n-- @code\n--\n-- local package = find_package(\"openssl\")\n-- local package = find_package(\"openssl\", {require_version = \"1.0.*\"})\n-- local package = find_package(\"openssl\", {plat = \"iphoneos\"})\n-- local package = find_package(\"openssl\", {linkdirs = {\"/usr/lib\", \"/usr/local/lib\"}, includedirs = \"/usr/local/include\", require_version = \"1.0.1\"})\n-- local package = find_package(\"openssl\", {linkdirs = {\"/usr/lib\", \"/usr/local/lib\", links = {\"ssl\", \"crypto\"}, includes = {\"ssl.h\"}})\n-- local package, manager_name, package_name = find_package(\"openssl\")\n--\n-- @endcode\n--\n\nfunction main(name, opt)\n\n    -- get the copied options\n    opt = table.copy(opt)\n    opt.plat = opt.plat or config.get(\"plat\") or os.host()\n    opt.arch = opt.arch or config.get(\"arch\") or os.arch()\n    opt.mode = opt.mode or config.mode() or \"release\"\n\n    -- get package manager name\n    local manager_name, package_name = table.unpack(name:split(\"::\", {plain = true, strict = true}))\n    if package_name == nil then\n        package_name = manager_name\n        manager_name = nil\n    else\n        manager_name = manager_name:lower():trim()\n    end\n\n    -- get package name and require version\n    local require_version = nil\n    package_name, require_version = table.unpack(package_name:trim():split(\"%s\"))\n    opt.require_version = require_version or opt.require_version\n\n    -- find package\n    local found_manager_name = nil\n    result, found_manager_name = _find_package(manager_name, package_name, opt)\n\n    -- match version?\n    if opt.require_version and opt.require_version:find('.', 1, true) and result then\n        if not _is_match_version(result.version, opt.require_version) then\n            result = nil\n        end\n    end\n    return result, found_manager_name, package_name\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.project.config\")\n\n-- install package\nfunction _install_package(manager_name, package_name, opt)\n\n    -- get managers\n    if manager_name then\n        dprint(\"installing %s from %s ..\", package_name, manager_name)\n        return import(\"package.manager.\" .. manager_name .. \".install_package\", {anonymous = true})(package_name, opt)\n    end\n\n    -- get suitable package managers\n    local managers = {}\n    if is_host(\"windows\") then\n        table.insert(managers, \"pacman\") -- msys/mingw\n    elseif is_host(\"linux\") then\n        table.insert(managers, \"apt\")\n        table.insert(managers, \"yum\")\n        table.insert(managers, \"pacman\")\n        table.insert(managers, \"portage\")\n        table.insert(managers, \"brew\")\n        table.insert(managers, \"zypper\")\n        table.insert(managers, \"nix\")\n    elseif is_host(\"macosx\") then\n        table.insert(managers, \"vcpkg\")\n        table.insert(managers, \"brew\")\n        table.insert(managers, \"nix\")\n    end\n    assert(#managers > 0, \"no suitable package manager!\")\n\n    -- install package from the given package managers\n    local errors = nil\n    for _, manager in ipairs(managers) do\n\n        -- trace\n        dprint(\"installing %s from %s ..\", package_name, manager)\n\n        -- try to install it\n        local ok = try\n        {\n            function ()\n                import(\"package.manager.\" .. manager .. \".install_package\", {anonymous = true})(package_name, opt)\n                return true\n            end,\n            catch\n            {\n                function (errs)\n                    errors = errs\n                end\n            }\n        }\n\n        -- install ok?\n        if ok then\n            dprint(\"install %s ok from %s\", package_name, manager)\n            return\n        end\n    end\n\n    -- install failed\n    raise(\"install %s failed! %s\", package_name, errors or \"\")\nend\n\n-- install package using the package manager\n--\n-- @param name  the package name, e.g. zlib 1.12.x (try all), XMAKE::zlib 1.12.x, BREW::zlib, VCPKG::zlib, CONAN::OpenSSL/1.0.2n@conan/stable\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n--\nfunction main(name, opt)\n\n    -- get the copied options\n    opt = table.copy(opt)\n    opt.plat = opt.plat or config.get(\"plat\") or os.host()\n    opt.arch = opt.arch or config.get(\"arch\") or os.arch()\n    opt.mode = opt.mode or config.mode() or \"release\"\n\n    -- get package manager name\n    local manager_name, package_name = table.unpack(name:split(\"::\", {plain = true, strict = true}))\n    if package_name == nil then\n        package_name = manager_name\n        manager_name = nil\n    else\n        manager_name = manager_name:lower():trim()\n    end\n\n    -- get package name and require version\n    local require_version = nil\n    package_name, require_version = table.unpack(package_name:trim():split(\"%s\"))\n    opt.require_version = require_version or opt.require_version\n\n    -- do install package\n    _install_package(manager_name, package_name, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/kotlin-native/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get architecture for kotlin-native\nfunction arch(arch)\n    local archs = {\n        x86_64          = \"x64\",\n        i386            = \"x86\",\n        [\"armeabi-v7a\"] = \"arm32\",\n        [\"arm64-v8a\"]   = \"arm64\",\n        armv7           = \"arm32\",\n        armv7s          = \"arm32\"\n    }\n    return archs[arch] or arch\nend\n\n-- get platform for kotlin-native\nfunction plat(plat)\n    local plats = {\n        macosx          = \"macos\",\n        iphoneos        = \"ios\",\n        appletvos       = \"tvos\",\n        windows         = \"mingw\"\n    }\n    return plats[plat] or plat\nend\n\n-- get triplet\nfunction triplet(plat, arch)\n    return plat .. arch\nend\n\n-- get configurations\nfunction main()\n    return {\n        repositories = {description = \"set the maven repositories\", default = {\n            \"https://repo.maven.apache.org/maven2\"\n        }}\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/kotlin-native/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"package.manager.kotlin-native.configurations\")\n\n-- find package from the kotlin-native package manager\n--\n-- @param name  the package name, e.g. org.jetbrains.kotlinx:kotlinx-serialization-json 1.8.0\n-- @param opt   the options, e.g. {verbose = true)\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local result = {}\n    local installdir = assert(opt.installdir, \"installdir not found!\")\n    local manifest_file = path.join(installdir, \"installed_manifest.txt\")\n    if os.isfile(manifest_file) then\n        return io.load(manifest_file)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/kotlin-native/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\nimport(\"package.manager.kotlin-native.configurations\")\nimport(\"net.http\")\nimport(\"core.base.semver\")\n\n-- select package version\n-- e.g. https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/kotlinx-serialization-json-iosarm64/maven-metadata.xml\nfunction _select_package_version(name, opt)\n    local installdir = opt.installdir\n    local require_version = opt.require_version\n    local metadata_file = path.join(installdir, \"maven-metadata.xml\")\n    for _, repository in ipairs(opt.repositories) do\n        local metadata_url = (\"%s/%s-%s/maven-metadata.xml\"):format(repository, (name:gsub(\"%.\", \"/\"):gsub(\":\", \"/\")), opt.triplet)\n        local ok = try {\n            function()\n                http.download(metadata_url, metadata_file, {\n                    insecure = global.get(\"insecure-ssl\")})\n                return true\n            end\n        }\n        if ok and os.isfile(metadata_file) then\n            local metadata = io.readfile(metadata_file)\n            local versions = {}\n            for _, line in ipairs(metadata:split(\"\\n\")) do\n                local v = line:match(\"<version>(.*)</version>\")\n                if v then\n                    table.insert(versions, v)\n                end\n            end\n            local version = semver.select(require_version, versions)\n            if version then\n                return version, repository\n            end\n        end\n    end\nend\n\n-- install package\n-- e.g. https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/kotlinx-serialization-json-iosarm64/1.8.0/kotlinx-serialization-json-iosarm64-1.8.0.klib\nfunction _install_package(name, opt)\n    local installdir = opt.installdir\n    local basename = name:split(\":\")[2] .. \"-\" .. opt.triplet\n    local library_file = path.join(installdir, \"klib\", \"platform\", opt.plat .. \"_\" .. opt.arch, basename .. \".klib\")\n    local library_url = (\"%s/%s-%s/%s/%s-%s.klib\"):format(opt.repository, (name:gsub(\"%.\", \"/\"):gsub(\":\", \"/\")), opt.triplet, opt.version, basename, opt.version)\n    http.download(library_url, library_file, {\n        insecure = global.get(\"insecure-ssl\")})\n\n    local manifest_file = path.join(installdir, \"installed_manifest.txt\")\n    io.save(manifest_file, {\n        links = library_file,\n        libfiles = library_file,\n        version = opt.version})\nend\n\n-- install package\n--\n-- @param name  the package name, e.g. org.jetbrains.kotlinx:kotlinx-serialization-json 1.8.0\n-- @param opt   the options, e.g. {verbose = true}\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local configs = opt.configs or {}\n    local repositories = configs.repositories\n\n    -- init triplet\n    local arch = opt.arch\n    local plat = opt.plat\n    plat = configurations.plat(plat)\n    arch = configurations.arch(arch)\n    local triplet = configurations.triplet(plat, arch)\n\n    -- select version\n    local installdir = assert(opt.installdir, \"installdir not found!\")\n    local require_version = opt.require_version\n    local version, repository = _select_package_version(name, {\n        triplet = triplet,\n        installdir = installdir,\n        require_version = require_version,\n        repositories = repositories})\n    assert(version and repository, \"package(%s): %s not found for %s!\", name, require_version, triplet)\n\n    -- do install\n    _install_package(name, {\n        plat = plat,\n        arch = arch,\n        triplet = triplet,\n        installdir = installdir,\n        version = version,\n        repository = repository})\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/nimble/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\n\n-- parse package name and version (with old version)\n--\n-- e.g.\n-- zip  [0.3.1]\n-- zip  [(version: 0.3.1, checksum: 747aab3c43ecb7b50671cdd0ec3b2edc2c83494c)]\n--\nfunction _parse_packageinfo_v1(line)\n    local splitinfo = line:split(\"%s+\", {limit = 2})\n    local package_name = splitinfo[1]\n    local version_str = splitinfo[2]\n    if version_str then\n        local version = semver.match(version_str)\n        if version then\n            package_version = version:rawstr()\n        end\n    end\n    return package_name, package_version\nend\n\n-- parse package name and version (with new version)\n--\n-- e.g.\n-- bearssl\n-- └── @0.2.5 (550e6f9321b85de53bba9c0ffab9c95ffbe12ab3) (C:\\Users\\V\\.nimble\\pkgs2\\bearssl-0.2.5-550e6f9321b85de53bba9c0ffab9c95ffbe12ab3)\n-- imguin\n-- ├── @1.92.3.0 (9b1400a393d47e0b7a7301115abd04b11a735b06) (C:\\Users\\V\\.nimble\\pkgs2\\imguin-1.92.3.0-9b1400a393d47e0b7a7301115abd04b11a735b06)\n-- └── @1.92.4.0 (fe2a7f25cfc17144dfb4f34c80655827bbe80fcb) (C:\\Users\\V\\.nimble\\pkgs2\\imguin-1.92.4.0-fe2a7f25cfc17144dfb4f34c80655827bbe80fcb)\n--\nfunction _parse_packageinfo_v2(line)\n    -- match package name (top-level entries only, not indented)\n    local package_name = line:match(\"^(%S+)$\")\n    if package_name then\n        return package_name, nil\n    end\n\n    -- match version lines like: └── @1.92.4.0 (...) or ├── @0.2.5 (...)\n    local version_str = line:match(\"^[├└].-@([%d%.]+)\")\n    if version_str then\n        local version = semver.match(version_str)\n        if version then\n            return nil, version:rawstr()\n        end\n    end\n\n    return nil, nil\nend\n\n-- find package with new format\nfunction _find_package_v2(name, list, opt)\n    local result\n    local current_package\n    for _, line in ipairs(list:split(\"\\n\", { plain = true })) do\n        local package_name, package_version = _parse_packageinfo_v2(line)\n        if package_name then\n            current_package = package_name\n        elseif package_version and current_package == name then\n            if opt.require_version then\n                if package_version and (opt.require_version == \"latest\" or semver.satisfies(package_version, opt.require_version)) then\n                    result = { version = package_version }\n                    break\n                end\n            else\n                result = {}\n                break\n            end\n        end\n    end\n    return result\nend\n\n-- find package with old format\nfunction _find_package_v1(name, list, opt)\n    local result\n    for _, line in ipairs(list:split(\"\\n\", {plain = true})) do\n        local package_name, package_version = _parse_packageinfo_v1(line)\n        if package_name == name then\n            if opt.require_version then\n                if package_version and (opt.require_version == \"latest\" or semver.satisfies(package_version, opt.require_version)) then\n                    result = {version = package_version}\n                    break\n                end\n            else\n                result = {}\n                break\n            end\n        end\n    end\n    return result\nend\n\n-- find package using the nimble package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, require_version = \"1.12.x\")\n--\nfunction main(name, opt)\n\n    -- find nimble\n    local nimble = find_tool(\"nimble\")\n    if not nimble then\n        raise(\"nimble not found!\")\n    end\n\n    -- find it from all installed package list\n    local list = os.iorunv(nimble.program, {\"list\", \"-i\", \"--ver\"})\n    if not list then\n        return\n    end\n\n    -- new format?\n    local result\n    if list:find(\"Package list format:\", 1, true) then\n        result = _find_package_v2(name, list, opt)\n    else\n        result = _find_package_v1(name, list, opt)\n    end\n\n    -- @note we don't need return links and includedirs information,\n    -- because it's nim source code package and nim will find them automatically\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/nimble/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\n\n-- install package\n--\n-- e.g.\n-- add_requires(\"nimble::zip\")\n-- add_requires(\"nimble::zip >0.3\")\n-- add_requires(\"nimble::zip 0.3.1\")\n--\n-- @param name  the package name, e.g. nimble::zip\n-- @param opt   the options, e.g. { verbose = true, mode = \"release\", plat = , arch = , require_version = \"x.x.x\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- find nimble\n    local nimble = find_tool(\"nimble\")\n    if not nimble then\n        raise(\"nimble not found!\")\n    end\n\n    -- install the given package\n    local argv = {\"install\", \"-y\"}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"--verbose\")\n    end\n    local require_str = name\n    if opt.require_version and opt.require_version ~= \"latest\" and opt.require_version ~= \"master\" then\n        name = name .. \"@\"\n        name = name .. opt.require_version\n    end\n    table.insert(argv, name)\n    os.vrunv(nimble.program, argv)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/nix/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ZZBaron\n-- @file        find_package.lua\n--\n\n--imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.pkgconfig.find_package\", {alias = \"find_package_from_pkgconfig\"})\nimport(\"core.cache.globalcache\")\nimport(\"core.cache.memcache\")\nimport(\"core.base.json\")\nimport(\"core.base.object\")\nimport(\"core.base.semver\")\n\n-- cache keys\nlocal STORE_PATHS_CACHE = \"nix_store_paths\"\nlocal PACKAGE_INFO_CACHE = \"nix_package_info\"\nlocal PROPAGATED_CACHE = \"nix_propagated\"\nlocal PKGCONFIG_CACHE = \"nix_pkgconfig\"\nlocal DERIVATION_CACHE = \"nix_derivation_info\"\n\n-- get nix cache instance\nlocal function get_nix_cache()\n    return globalcache.cache(\"nix_packages\")\nend\n\n-- get memory cache for current session\nlocal function get_memory_cache()\n    return memcache.cache(\"nix_session\")\nend\n\n-- check if we're in a nix shell\nlocal function is_in_nix_shell()\n    local in_nix_shell = os.getenv(\"IN_NIX_SHELL\")\n    return in_nix_shell == \"pure\" or in_nix_shell == \"impure\"\nend\n\n-- generate cache key for environment state\nlocal function generate_env_cache_key()\n    local env_vars = {\n        \"buildInputs\",\n        \"nativeBuildInputs\", \n        \"propagatedBuildInputs\",\n        \"propagatedNativeBuildInputs\"\n    }\n    \n    local env_data = {}\n    for _, var in ipairs(env_vars) do\n        env_data[var] = os.getenv(var) or \"\"\n    end\n    \n    -- Include nix shell state and user\n    env_data.in_nix_shell = tostring(is_in_nix_shell())\n    env_data.user = os.getenv(\"USER\") or \"unknown\"\n    \n    -- Create a hash-like key from the environment\n    local key_parts = {}\n    for k, v in table.orderpairs(env_data) do\n        table.insert(key_parts, k .. \"=\" .. v)\n    end\n    return table.concat(key_parts, \"|\")\nend\n\n-- extract package information from store path using derivation data\nlocal function extract_package_info_from_path(store_path, opt)\n    local cache = get_nix_cache()\n    local memory_cache = get_memory_cache()\n    \n    -- Check caches first\n    local cached = memory_cache:get2(DERIVATION_CACHE, store_path)\n    if cached then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Using session cached derivation info for: \" .. store_path)\n        end\n\n        return cached.name, cached.version, cached.outputs, cached.current_output\n    end\n    \n    cached = cache:get2(DERIVATION_CACHE, store_path)\n    if cached then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Using persistent cached derivation info for: \" .. store_path)\n        end\n\n        memory_cache:set2(DERIVATION_CACHE, store_path, cached)\n        return cached.name, cached.version, cached.outputs, cached.current_output\n    end\n    \n    -- Find required tools\n    local nix_store = find_tool(\"nix-store\")\n    local nix = find_tool(\"nix\")\n\n    if not nix_store or not nix then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            local missing = {}\n            if not nix_store then table.insert(missing, \"nix-store\") end\n            if not nix then table.insert(missing, \"nix\") end\n            if opt and (opt.verbose or option.get(\"verbose\")) then\n                print(\"Nix: Required tools not found: \" .. table.concat(missing, \", \"))\n            end\n        end\n        return nil\n    end\n\n    -- Get the derivation path\n    local drv_output = try {function()\n        local outdata = os.iorunv(nix_store.program, {\"--query\", \"--valid-derivers\", store_path}) -- not \"--deriver\" because:\n        -- The returned deriver is not guaranteed to exist in the local store, for example when paths were substituted from a binary cache.\n        -- Ref: https://nix.dev/manual/nix/latest/command-ref/nix-store/query.html\n        if outdata then\n            return outdata:trim()\n        end\n        return outdata\n    end}\n    \n    if not drv_output or drv_output == \"\" then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Could not get derivation for: \" .. store_path)\n        end\n        return nil\n    end\n\n    -- drv_output is a list of derivations\n    local derivations = {}\n    for drv_path in drv_output:gmatch(\"(%S+)\") do\n        if drv_path:match(\"%.drv$\") then\n            table.insert(derivations, drv_path)\n        end\n    end\n    \n    if #derivations == 0 then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: No valid derivation paths found for: \" .. store_path)\n        end\n        return nil\n    end\n    \n    -- Try each derivation until we find one that works\n    local derivation_json = nil\n    for _, drv_path in ipairs(derivations) do\n        derivation_json = try {function()\n            local outdata = os.iorunv(nix.program, {\n                \"derivation\", \"show\", \n                drv_path,\n                \"--extra-experimental-features\", \"nix-command flakes\"\n            })\n            if outdata then\n                return outdata:trim()\n            end\n            return outdata\n        end}\n        \n        if derivation_json and derivation_json ~= \"\" then\n            if opt and (opt.verbose or option.get(\"verbose\")) then\n                print(\"Nix: Using derivation: \" .. drv_path)\n            end\n            break\n        end\n    end\n    \n    if not derivation_json or derivation_json == \"\" then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Could not show derivation for: \" .. drv_output)\n        end\n        return nil\n    end\n    \n    -- Parse the JSON output\n    local derivation_data = json.decode(derivation_json)\n    if not derivation_data then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Failed to parse derivation JSON\")\n        end\n        return nil\n    end\n    \n    -- Extract the derivation info (should be a single key-value pair)\n    local drv_info = nil\n    for _, info in pairs(derivation_data) do\n        drv_info = info\n        break\n    end\n    \n    if not drv_info and opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: No derivation info found in JSON\")\n    end\n    \n    -- Extract package information\n    -- structureAttrs vs env:\n    -- not every nix package has structureAttrs, so we fallback to env\n    -- Ref: https://nix.dev/manual/nix/latest/language/advanced-attributes.html\n    local package_name = (drv_info.structuredAttrs and drv_info.structuredAttrs.pname) or (drv_info.env and drv_info.env.pname) or nil \n    -- not just \"name\" as that includes version\n    local version = (drv_info.structuredAttrs and drv_info.structuredAttrs.version) or (drv_info.env and drv_info.env.version) or nil \n    local outputs = drv_info.outputs or {}\n    \n    if not package_name then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: No pname found in derivation: \" .. drv_output)\n        end\n        return nil\n    end\n    \n    -- Create outputs map (output_name -> store_path)\n    local output_paths = {}\n    for output_name, output_info in pairs(outputs) do\n        if output_info.path then\n            output_paths[output_name] = output_info.path\n        end\n    end\n    \n    -- Determine which output this store_path represents\n    local current_output = nil\n    for output_name, output_path in pairs(output_paths) do\n        if output_path == store_path then\n            current_output = output_name\n            break\n        end\n    end\n    \n    -- Cache the result\n    local result = {\n        name = package_name,\n        version = version,\n        outputs = output_paths,\n        current_output = current_output\n    }\n    \n    cache:set2(DERIVATION_CACHE, store_path, result)\n    memory_cache:set2(DERIVATION_CACHE, store_path, result)\n    \n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Extracted derivation info for \" .. package_name .. \" (version: \" .. (version or \"unknown\") .. \")\")\n    end\n    return package_name, version, output_paths, current_output\nend\n\n-- package info data\nlocal package_info = object {_init = {\"name\", \"version\"}}\n\nfunction package_info:new(name, version)\n    self._name = name\n    self._version = version\n    self._includedirs = {}\n    self._bindirs = {}\n    self._linkdirs = {}\n    self._links = {}\n    self._libfiles = {}\n    self._store_paths = {}\n    self._outputs = {}\n    self._pkgconfig_available = false\n    return package_info {self, name, version}\nend\n\nfunction package_info:add_store_path(p, output_name)\n    table.insert(self._store_paths, p)\n    if output_name then\n        self._outputs[output_name] = p\n    end\nend\n\nfunction package_info:add_includedir(d)\n    table.insert(self._includedirs, d)\nend\n\nfunction package_info:add_bindir(d)\n    table.insert(self._bindirs, d)\nend\n\nfunction package_info:add_linkdir(d)\n    table.insert(self._linkdirs, d)\nend\n\nfunction package_info:add_link(l)\n    table.insert(self._links, l)\nend\n\nfunction package_info:add_libfile(f)\n    table.insert(self._libfiles, f)\nend\n\nfunction package_info:set_pkgconfig_available()\n    self._pkgconfig_available = true\nend\n\nfunction package_info:finalize()\n    -- remove duplicates\n    self._includedirs = table.unique(self._includedirs)\n    self._bindirs = table.unique(self._bindirs)\n    self._linkdirs = table.unique(self._linkdirs)\n    self._links = table.unique(self._links)\n    self._libfiles = table.unique(self._libfiles)\n    self._store_paths = table.unique(self._store_paths)\n   \n    -- return plain table (so cache stores normal table)\n    return {\n        name = self._name,\n        includedirs = self._includedirs,\n        bindirs = self._bindirs,\n        linkdirs = self._linkdirs,\n        links = self._links,\n        libfiles = self._libfiles,\n        store_paths = self._store_paths,\n        outputs = self._outputs,\n        version = self._version,\n        pkgconfig_available = self._pkgconfig_available\n    }\nend\n\n-- follow propagated build inputs recursively with caching\nlocal function follow_propagated_inputs(store_paths, opt)\n    local cache = get_nix_cache()\n    local visited = {}\n    \n    -- Add initial paths\n    local all_paths = table.unique(store_paths)\n    \n    local i = 1\n    while i <= #all_paths do\n        local store_path = all_paths[i]\n        if not visited[store_path] then\n            visited[store_path] = true\n            \n            -- Check cache first\n            local cached_props = cache:get2(PROPAGATED_CACHE, store_path)\n            local prop_paths\n            \n            if cached_props then\n                prop_paths = cached_props\n                if opt and (opt.verbose or option.get(\"verbose\")) then\n                    print(\"Nix: Using cached propagated inputs for: \" .. store_path)\n                end\n            else\n                -- Read from filesystem\n                prop_paths = {}\n                local prop_file = path.join(store_path, \"nix-support\", \"propagated-build-inputs\")\n                if os.isfile(prop_file) then\n                    local content = try {function()\n                        return io.readfile(prop_file):trim()\n                    end}\n                    if content and content ~= \"\" then\n                        for prop_path in content:gmatch(\"%S+\") do\n                            if prop_path:startswith(\"/nix/store/\") then\n                                table.insert(prop_paths, prop_path)\n                            end\n                        end\n                    end\n                end\n                \n                -- Cache the result\n                cache:set2(PROPAGATED_CACHE, store_path, prop_paths)\n                if opt and (opt.verbose or option.get(\"verbose\")) then\n                    print(\"Nix: Cached propagated inputs for: \" .. store_path)\n                end\n            end\n            \n            -- Add new paths\n            for _, prop_path in ipairs(prop_paths) do\n                table.insert(all_paths, prop_path)\n                if opt and (opt.verbose or option.get(\"verbose\")) then\n                    print(\"Nix: Added propagated: \" .. prop_path)\n                end\n            end\n        end\n        i = i + 1\n    end\n    \n    return table.unique(all_paths)\nend\n\n-- get store paths from nix command output\nlocal function get_store_paths_from_command(command, args, opt)\n    local output = try {function()\n        local outdata = os.iorunv(command, args)\n        if outdata then\n            return outdata:trim()\n        end\n        return outdata\n    end}\n    \n    if not output then\n        return {}\n    end\n    \n    local store_paths = {}\n    for line in output:gmatch(\"[^\\n]+\") do\n        local store_path = line:match(\"(/nix/store/[^%s]+)\")\n        if store_path then\n            table.insert(store_paths, store_path)\n        end\n    end\n    \n    return follow_propagated_inputs(store_paths, opt)\nend\n\n-- parse store paths from environment variables with caching\nlocal function parse_store_paths_from_env(env_vars, opt)\n    local cache_key = generate_env_cache_key()\n    local memory_cache = get_memory_cache()\n    \n    -- Check memory cache first (session cache)\n    local cached_paths = memory_cache:get2(STORE_PATHS_CACHE, cache_key)\n    if cached_paths then\n        return cached_paths\n    end\n    \n    -- Check persistent cache\n    local cache = get_nix_cache()\n    cached_paths = cache:get2(STORE_PATHS_CACHE, cache_key)\n    if cached_paths then\n        -- Also cache in memory for faster access\n        memory_cache:set2(STORE_PATHS_CACHE, cache_key, cached_paths)\n        memory_cache:set(\"last_env_key\", cache_key)\n        return cached_paths\n    end\n    \n    -- Parse from environment\n    local paths = {}\n    local seen = {}\n    \n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Parsing store paths from environment variables\")\n    end\n    \n    for _, var_name in ipairs(env_vars) do\n        local env_value = os.getenv(var_name) or \"\"\n        if env_value ~= \"\" then\n            for item in env_value:gmatch(\"[^%s:]+\") do\n                if item:startswith(\"/nix/store/\") then\n                    local store_path = item:match(\"(/nix/store/[^/]+)\")\n                    if store_path and not seen[store_path] then\n                        seen[store_path] = true\n                        table.insert(paths, store_path)\n                        if opt and (opt.verbose or option.get(\"verbose\")) then\n                            print(\"Nix: Found store path: \" .. store_path)\n                        end\n                    end\n                end\n            end\n        end\n    end\n    \n    -- Follow propagated inputs\n    paths = follow_propagated_inputs(paths, opt)\n    \n    -- Cache the result\n    cache:set2(STORE_PATHS_CACHE, cache_key, paths)\n    memory_cache:set2(STORE_PATHS_CACHE, cache_key, paths)\n    memory_cache:set(\"last_env_key\", cache_key)\n    cache:save()\n    \n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Cached \" .. #paths .. \" store paths\")\n    end\n    \n    return paths\nend\n\n-- STORE PATH EXTRACTION FUNCTIONS\n\n-- extract store paths from nix shell\nlocal function get_store_paths_nix_shell(opt)\n    if not is_in_nix_shell() then\n        return {}\n    end\n    \n    local build_env_vars = {\n        \"buildInputs\",\n        \"nativeBuildInputs\",\n        \"propagatedBuildInputs\",\n        \"propagatedNativeBuildInputs\"\n    }\n    \n    return parse_store_paths_from_env(build_env_vars, opt)\nend\n\n-- Find package from current user's nix profile, includes nix-env installed packages\n-- Note: nix-env only lists one output in the profile list\n-- $ nix-env -iA nixpkgs.<package> # installs multiple outputs, but only one is listed in the profile\n-- this can cause issues if the main output does not contain the necessary files\n-- Example: zlib.dev contains the headers, but zlib only contains the library\n-- there does not seem to be an straight-forward way to find all outputs...\n-- It is better to use nix profile like:\n-- $ nix profile install 'nixpkgs#zlib^*'' # installs all outputs\n-- $ nix profile install 'nixpkgs#zlib^dev' # installs only the dev output\nlocal function get_store_paths_nix_profile(opt)\n    local nix = find_tool(\"nix\")\n    if not nix then\n        return {}\n    end\n    \n    return get_store_paths_from_command(\n        nix.program, \n        {\"profile\", \"list\", \"--extra-experimental-features\", \"nix-command flakes\"},\n        opt\n    )\nend\n\n-- Popular nix-community tool to declaratively manage user environments (NixOS and non-NixOS)\nlocal function get_store_paths_home_manager_tool(opt)\n    local home_manager = find_tool(\"home-manager\")\n    if not home_manager then\n        return {}\n    end\n    \n    return get_store_paths_from_command(\n        home_manager.program,\n        {\"packages\"},\n        opt\n    )\nend\n\n-- Home manager can be installed as a module in nixos, in which case the home-manager tool is missing.\nlocal function get_store_paths_home_manager_profile(opt)\n    local nix_store = find_tool(\"nix-store\")\n    if not nix_store then\n        return {}\n    end\n    \n    local user = os.getenv(\"USER\") or \"unknown\"\n    local user_profile = \"/etc/profiles/per-user/\" .. user\n    if not os.isdir(user_profile) then\n        return {}\n    end\n    \n    return get_store_paths_from_command(\n        nix_store.program,\n        {\"--query\", \"--requisites\", user_profile},\n        opt\n    )\nend\n\n-- nixos-option is not always configured properly, but if it is, we can find user/system packages\nlocal function get_store_paths_nixos_user_packages(opt)\n    local nixos_option = find_tool(\"nixos-option\")\n    if not nixos_option then\n        return {}\n    end\n    \n    local user = os.getenv(\"USER\") or \"unknown\"\n    local output = try {function()\n        local outdata = os.iorunv(nixos_option.program, {\"users.users.\" .. user .. \".packages\"})\n        if outdata then\n            return outdata:trim()\n        end\n        return outdata\n    end}\n    \n    if output then\n        local store_paths = {}\n        for store_path in output:gmatch('(/nix/store/[^\"\\'%s]+)') do\n            table.insert(store_paths, store_path)\n        end\n        \n        return follow_propagated_inputs(store_paths, opt)\n    end\n    return {}\nend\n\n-- extract store paths from nixos system packages\nlocal function get_store_paths_nixos_system_packages(opt)\n    local nixos_option = find_tool(\"nixos-option\")\n    if not nixos_option then\n        return {}\n    end\n    \n    local output = try {function()\n        local outdata = os.iorunv(nixos_option.program, {\"environment.systemPackages\"})\n        if outdata then\n            return outdata:trim()\n        end\n        return outdata\n    end}\n    \n    if output then\n        local store_paths = {}\n        for store_path in output:gmatch('(/nix/store/[^\"\\'%s]+)') do\n            table.insert(store_paths, store_path)\n        end\n        \n        return follow_propagated_inputs(store_paths, opt)\n    end\n    return {}\nend\n\n-- Includes all system/user/home-manager packages\nlocal function get_store_paths_nixos_current_system(opt)\n    local nix_store = find_tool(\"nix-store\")\n    if not nix_store then\n        return {}\n    end\n    \n    if not os.isdir(\"/run/current-system\") then\n        return {}\n    end\n    \n    return get_store_paths_from_command(\n        nix_store.program,\n        {\"--query\", \"--requisites\", \"/run/current-system\"},\n        opt\n    )\nend\n\n-- get all store paths from all nix environments with caching\nlocal function get_all_store_paths(opt)\n    local cache = get_nix_cache()\n    local memory_cache = get_memory_cache()\n    local cache_key = \"all_environments:\" .. generate_env_cache_key()\n    \n    -- Check memory cache first\n    local cached_paths = memory_cache:get2(STORE_PATHS_CACHE, cache_key)\n    if cached_paths then\n        return cached_paths\n    end\n    \n    -- Check persistent cache\n    cached_paths = cache:get2(STORE_PATHS_CACHE, cache_key)\n    if cached_paths then\n        memory_cache:set2(STORE_PATHS_CACHE, cache_key, cached_paths)\n        return cached_paths\n    end\n    \n    -- Extract from all sources\n    local all_paths = {}\n    local seen = {}\n    \n    local get_store_path_functions = {\n        get_store_paths_nix_shell,\n        get_store_paths_nix_profile,\n        get_store_paths_home_manager_tool,\n        get_store_paths_home_manager_profile,\n        get_store_paths_nixos_user_packages,\n        get_store_paths_nixos_system_packages,\n        get_store_paths_nixos_current_system\n    }\n    \n    for _, func in ipairs(get_store_path_functions) do\n        local paths = func(opt)\n        for _, store_path in ipairs(paths) do\n            if not seen[store_path] then\n                seen[store_path] = true\n                table.insert(all_paths, store_path)\n            end\n        end\n    end\n    \n    -- Cache the result\n    cache:set2(STORE_PATHS_CACHE, cache_key, all_paths)\n    memory_cache:set2(STORE_PATHS_CACHE, cache_key, all_paths)\n    cache:save()\n    \n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Found \" .. #all_paths .. \" total store paths across all environments\")\n    end\n    \n    return all_paths\nend\n\n-- check if store path has the package name (substring search)\nlocal function path_matches_package(store_path, package_name)\n    local path_name_lower = path.basename(store_path):lower()\n    local package_name_lower = package_name:lower()\n    \n    return path_name_lower:find(package_name_lower, 1, true) ~= nil\nend\n\nlocal function group_paths_by_version(store_paths, package_name, opt)\n    local version_groups = {}  -- { \"package:version\" -> [store_paths] }\n    \n    for _, store_path in ipairs(store_paths) do\n        if not store_path or store_path == \"\" then goto continue end\n        \n        -- Extract package info\n        local parsed_name, parsed_version, output_paths, current_output = extract_package_info_from_path(store_path, opt)\n        \n        if not parsed_name then\n            goto continue\n        end\n        \n        -- Only include matching package names (if filtering)\n        if package_name then\n            local name_matches = parsed_name:lower() == package_name:lower()\n            if not name_matches then\n                goto continue\n            end\n        end\n        \n        -- Create version key\n        local version_key = parsed_name .. \":\" .. (parsed_version or \"unknown\")\n        \n        if not version_groups[version_key] then\n            version_groups[version_key] = {\n                name = parsed_name,\n                version = parsed_version,\n                paths = {}\n            }\n        end\n        \n        table.insert(version_groups[version_key].paths, {\n            path = store_path,\n            outputs = output_paths,\n            current_output = current_output\n        })\n        \n        ::continue::\n    end\n    \n    return version_groups\nend\n\n-- extract package information from store paths with caching\nlocal function extract_package_info(store_paths, package_name, opt)\n    opt = opt or {}\n    local cache = get_nix_cache()\n    local memory_cache = get_memory_cache()\n    local paths_key = table.concat(store_paths or {}, \";\")\n    local cache_key = \"package_info:\" .. (package_name or \"all\") .. \":\" .. paths_key\n    \n    -- Check memory cache first\n    local cached = memory_cache:get2(PACKAGE_INFO_CACHE, cache_key)\n    if cached ~= nil then\n        return cached\n    end\n    \n    -- Check persistent cache\n    cached = cache:get2(PACKAGE_INFO_CACHE, cache_key)\n    if cached ~= nil then\n        memory_cache:set2(PACKAGE_INFO_CACHE, cache_key, cached)\n        return cached\n    end\n\n    if not store_paths or #store_paths == 0 then\n        local empty = {}\n        cache:set2(PACKAGE_INFO_CACHE, cache_key, empty)\n        memory_cache:set2(PACKAGE_INFO_CACHE, cache_key, empty)\n        return empty\n    end\n\n    -- Filter store paths if package_name is provided\n    local filtered_paths = store_paths\n    if package_name then\n        filtered_paths = {}\n        local seen = {}\n        \n        -- First, find direct matches\n        for _, store_path in ipairs(store_paths) do\n            if path_matches_package(store_path, package_name) and not seen[store_path] then\n                seen[store_path] = true\n                table.insert(filtered_paths, store_path)\n            end\n        end\n        \n        -- Then find their dependencies\n        local all_deps = follow_propagated_inputs(filtered_paths, opt)\n        filtered_paths = table.unique(all_deps)\n        \n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Filtered to \" .. #filtered_paths .. \" relevant store paths for package: \" .. package_name)\n        end\n    end\n\n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Extracting package info for \" .. #filtered_paths .. \" store paths\")\n    end\n\n    local version_groups = group_paths_by_version(filtered_paths, package_name, opt)\n\n    local packages = {} -- map: \"package_name:version\" -> package_info\n\n    for version_key, version_data in pairs(version_groups) do\n        local pkg_name = version_data.name\n        local pkg_version = version_data.version\n        local pkg = package_info:new(pkg_name, pkg_version)\n        \n        -- Process all store paths for this version only\n        for _, path_data in ipairs(version_data.paths) do\n            local store_path = path_data.path\n            local output_paths = path_data.outputs\n            local current_output = path_data.current_output\n            \n            pkg:add_store_path(store_path, current_output)\n            \n            -- Add all output paths to the package\n            if output_paths then\n                for output_name, output_path in pairs(output_paths) do\n                    pkg._outputs[output_name] = output_path\n                end\n            end\n\n            -- include directories (and their subdirs)\n            local includedir = path.join(store_path, \"include\")\n            if os.isdir(includedir) then\n                pkg:add_includedir(includedir)\n                local subdirs = try { function() return os.dirs(path.join(includedir, \"*\")) end } or {}\n                for _, subdir in ipairs(subdirs) do\n                    if os.isdir(subdir) then\n                        pkg:add_includedir(subdir)\n                    end\n                end\n            end\n\n            -- bin\n            local bindir = path.join(store_path, \"bin\")\n            if os.isdir(bindir) then\n                pkg:add_bindir(bindir)\n            end\n\n            -- lib and libs\n            local libdir = path.join(store_path, \"lib\")\n            if os.isdir(libdir) then\n                local libfiles = try { function()\n                    local files = {}\n                    local patterns = {\"*.so*\", \"*.a\", \"*.dylib*\"}\n                    for _, pattern in ipairs(patterns) do\n                        for _, f in ipairs(os.files(path.join(libdir, pattern)) or {}) do\n                            table.insert(files, f)\n                        end\n                    end\n                    return files\n                end } or {}\n\n                if #libfiles > 0 then\n                    pkg:add_linkdir(libdir)\n                    for _, libfile in ipairs(libfiles) do\n                        local filename = path.filename(libfile)\n                        local linkname = filename:match(\"^lib(.+)%.so\") or\n                                         filename:match(\"^lib(.+)%.a\") or\n                                         filename:match(\"^lib(.+)%.dylib\")\n                        if linkname then\n                            pkg:add_link(linkname)\n                            pkg:add_libfile(libfile)\n                        end\n                    end\n                else\n                    -- if no libs, see if cmake/pkgconfig dirs exist and add linkdir\n                    local has_cmake = os.isdir(path.join(libdir, \"cmake\"))\n                    local has_pkgconfig = os.isdir(path.join(libdir, \"pkgconfig\"))\n                    if has_cmake or has_pkgconfig then\n                        pkg:add_linkdir(libdir)\n                    end\n                end\n            end\n        end\n    \n        packages[version_key] = pkg\n    end\n\n    -- finalize all package_info instances into plain tables\n    local result = {}\n    for version_key, pkgobj in pairs(packages) do\n        local plain = pkgobj:finalize()\n        result[version_key] = plain\n    end\n\n    -- cache result\n    cache:set2(PACKAGE_INFO_CACHE, cache_key, result)\n    memory_cache:set2(PACKAGE_INFO_CACHE, cache_key, result)\n    cache:save()\n\n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        local keys = table.keys(result)\n        print(\"Nix: Extracted \" .. #keys .. \" package versions from store paths\")\n    end\n\n    return result\nend\n\nlocal function find_all_with_pkgconfig(package_name, store_paths, opt)\n    local cache = get_nix_cache()\n    local memory_cache = get_memory_cache()\n\n    -- prefer the normalized env key stored in session memcache\n    local env_key = memory_cache:get(\"last_env_key\")\n    local cache_key = package_name .. \":all:\" .. (env_key or table.concat(store_paths, \";\"))\n\n    -- Check session memory cache first\n    local memo = memory_cache:get2(PKGCONFIG_CACHE, cache_key)\n    if memo ~= nil then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            local status = (type(memo) == \"table\" and #memo > 0) and \"found\" or \"not found\"\n            print(\"Nix: Using session cached pkg-config results (\" .. status .. \") for: \" .. package_name)\n        end\n        return (type(memo) == \"table\") and memo or {}\n    end\n\n    -- Check persistent cache\n    local cached_result = cache:get2(PKGCONFIG_CACHE, cache_key)\n    if cached_result ~= nil then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            local status = (type(cached_result) == \"table\" and #cached_result > 0) and \"found\" or \"not found\"\n            print(\"Nix: Using persistent cached pkg-config results (\" .. status .. \") for: \" .. package_name)\n        end\n        local result_table = (type(cached_result) == \"table\") and cached_result or {}\n        memory_cache:set2(PKGCONFIG_CACHE, cache_key, result_table)\n        return result_table\n    end\n\n    -- Filter store paths to only relevant ones\n    local filtered_paths = {}\n    local seen = {}\n    \n    for _, store_path in ipairs(store_paths) do\n        if path_matches_package(store_path, package_name) and not seen[store_path] then\n            seen[store_path] = true\n            table.insert(filtered_paths, store_path)\n        end\n    end\n    \n    -- Add dependencies of matching packages\n    filtered_paths = follow_propagated_inputs(filtered_paths, opt)\n\n    local all_results = {}\n    for _, store_path in ipairs(filtered_paths) do\n        local pkgconfig_dirs = {\n            path.join(store_path, \"lib\", \"pkgconfig\"),\n            path.join(store_path, \"share\", \"pkgconfig\")\n        }\n\n        for _, pcdir in ipairs(pkgconfig_dirs) do\n            if os.isdir(pcdir) then\n                local result = find_package_from_pkgconfig(package_name, {configdirs = pcdir})\n                if result and result.version then\n                    table.insert(all_results, result)\n                    if opt and (opt.verbose or option.get(\"verbose\")) then\n                        print(\"Nix: Found pkg-config version: \" .. package_name .. \" \" .. result.version)\n                    end\n                end\n            end\n        end\n    end\n\n    memory_cache:set2(PKGCONFIG_CACHE, cache_key, all_results)\n    cache:set2(PKGCONFIG_CACHE, cache_key, all_results)\n    \n    return all_results\nend\n\nlocal function select_best_version(packages, package_name, require_version, opt)\n    -- Collect all versions of the target package\n    local candidates = {}\n    local name_lower = package_name:lower()\n    \n    for version_key, pkg_data in pairs(packages) do\n        local pkg_name = pkg_data.name or \"\"\n        if pkg_name:lower() == name_lower then\n            table.insert(candidates, pkg_data)\n        end\n    end\n    \n    -- Handle empty candidates\n    if not candidates or #candidates == 0 then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: No versions found for package: \" .. package_name)\n        end\n        return nil\n    end\n    \n    -- If only one candidate, return it\n    if #candidates == 1 then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            local ver = candidates[1].version or \"unknown\"\n            print(\"Nix: Found single version: \" .. package_name .. \" \" .. ver)\n        end\n        return candidates[1]\n    end\n    \n    -- Multiple candidates - select best one\n    local best_match = nil\n    local best_version = nil\n    \n    for _, candidate in ipairs(candidates) do\n        local pkg_version = candidate.version\n        \n        if not pkg_version then\n            -- No version info, use as fallback if nothing better found\n            if not best_match then\n                best_match = candidate\n            end\n            goto continue\n        end\n        \n        -- Check if version satisfies constraints\n        local satisfies = false\n        if not require_version or require_version == \"latest\" then\n            satisfies = true\n        else\n            satisfies = try {\n                function()\n                    return semver.satisfies(pkg_version, require_version)\n                end,\n                catch = function()\n                    -- If semver parsing fails, try exact match\n                    return (pkg_version == require_version)\n                end\n            }\n        end\n        \n        if satisfies then\n            -- Try to parse version for comparison\n            local current_ver = try {\n                function()\n                    return semver.new(pkg_version)\n                end,\n                catch = function()\n                    return nil\n                end\n            }\n            \n            -- Select highest version among satisfying candidates\n            if not best_version then\n                best_match = candidate\n                best_version = current_ver\n            elseif current_ver and best_version then\n                -- Both versions are valid semver, compare them\n                if current_ver:gt(best_version) then\n                    best_match = candidate\n                    best_version = current_ver\n                end\n            elseif current_ver and not best_version then\n                -- Current has valid semver but previous didn't, prefer current\n                best_match = candidate\n                best_version = current_ver\n            end\n        end\n        \n        ::continue::\n    end\n    \n    -- Log results if verbose\n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        if best_match then\n            local ver = best_match.version or \"unknown\"\n            local constraint_msg = (require_version and require_version ~= \"\") \n                and (\" matching constraint: \" .. require_version) or \"\"\n            print(\"Nix: Selected version: \" .. package_name .. \" \" .. ver .. constraint_msg)\n        else\n            local constraint_msg = (require_version and require_version ~= \"\") \n                and (\" matching constraint: \" .. require_version) or \"\"\n            print(\"Nix: No version found for: \" .. package_name .. constraint_msg)\n        end\n    end\n    \n    return best_match\nend\n\nlocal function nonempty_string(v)\n    return type(v) == \"string\" and v ~= \"\" and v\nend\n\n-- find package using the nix package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n\nfunction main(name, opt)\n    opt = opt or {}\n\n    -- ensure a stable env cache key is available for the whole run\n    local memory_cache = get_memory_cache()\n    memory_cache:set(\"last_env_key\", generate_env_cache_key())\n\n    local require_version = nonempty_string(opt.require_version) or nonempty_string(opt.version)\n\n    -- Skip cross-compilation scenarios\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n    \n    -- Get all store paths from all nix environments (cached)\n    local store_paths = get_all_store_paths(opt)\n    if #store_paths == 0 then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: No store paths found in any nix environment\")\n        end\n        return nil\n    end\n    \n    -- Extract all package info (cached)\n    local packages = extract_package_info(store_paths, name, opt)\n    local keys = table.keys(packages)\n    if not packages or #keys == 0 then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: No packages extracted from store paths\")\n        end\n        return nil\n    end\n    \n    -- Find best version from extracted packages\n    local found_package = select_best_version(packages, name, require_version, opt)\n    \n    if not found_package then\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Package \" .. name .. \" not found or no matching version\")\n        end\n        return nil\n    end\n\n    local pkgconfig_results = find_all_with_pkgconfig(name, store_paths, opt)\n    local pkgconfig_result =  select_best_version(pkgconfig_results, name, require_version, opt)\n    \n    -- Decide which result to use - prefer whichever has the highest version\n    local use_pkgconfig = false\n    if pkgconfig_result then\n        if not found_package.version then\n            -- found_package has no version, prefer pkg-config\n            use_pkgconfig = true\n        elseif not pkgconfig_result.version then\n            -- pkg-config has no version, prefer found_package\n            use_pkgconfig = false\n        else\n            -- Both have versions, compare them\n            local pkg_ver = try {\n                function() return semver.new(found_package.version) end\n            }\n            local pkgconfig_ver = try {\n                function() return semver.new(pkgconfig_result.version) end\n            }\n            \n            if pkg_ver and pkgconfig_ver then\n                -- Prefer whichever is higher\n                if pkgconfig_ver:gt(pkg_ver) then\n                    use_pkgconfig = true\n                end\n            elseif pkgconfig_ver then\n                -- Only pkg-config has valid semver\n                use_pkgconfig = true\n            end\n            -- else: only pkg_ver is valid or neither is valid, use found_package\n        end\n    end\n    \n    if use_pkgconfig and pkgconfig_result then\n        local ver = pkgconfig_result.version or \"unknown\"\n        if opt and (opt.verbose or option.get(\"verbose\")) then\n            print(\"Nix: Returning pkg-config package: \" .. name .. \" (\" .. ver .. \")\")\n        end\n        return pkgconfig_result\n    end\n    \n    -- Return the selected version from extracted packages\n    local ver = found_package.version or \"unknown\"\n    if opt and (opt.verbose or option.get(\"verbose\")) then\n        print(\"Nix: Returning package: \" .. name .. \" (\" .. ver .. \")\")\n    end\n    \n    local result = {\n        name = found_package.name,\n        version = found_package.version\n    }\n    \n    local fields_to_copy = {\"includedirs\", \"linkdirs\", \"links\", \"libfiles\", \"bindirs\"}\n    -- Add directories and links if they exist\n    for _, field in ipairs(fields_to_copy) do\n        if found_package[field] and #found_package[field] > 0 then\n            result[field] = found_package[field]\n        end\n    end\n    \n    return result\nend"
  },
  {
    "path": "xmake/modules/package/manager/nix/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ZZBaron\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\n\n-- install package\n--\n-- @param name  the package name, e.g. zlib\n-- @param opt   the options, e.g. {verbose = true}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n    \n    -- find nix tools (try modern first, then legacy)\n    local nix = find_tool(\"nix\")\n    local nix_env = find_tool(\"nix-env\")\n    \n    if not nix and not nix_env then\n        raise(\"nix not found!\")\n    end\n    \n    -- check architecture \n    if is_cross(opt.plat, opt.arch) then\n        raise(\"cannot install package(%s) for cross compilation!\", name)\n    end\n    \n    local success = false\n    \n    -- try modern nix first\n    if nix then\n        local argv = {\"profile\", \"install\", \"nixpkgs#\" .. name}\n        if opt.verbose or option.get(\"verbose\") then\n            table.insert(argv, \"--verbose\")\n        end\n        \n        success = try {function()\n            os.vrunv(nix.program, argv)\n            return true\n        end}\n    end\n    \n    -- fallback to nix-env\n    if not success and nix_env then\n        local argv = {\"-iA\", \"nixpkgs.\" .. name}\n        if opt.verbose or option.get(\"verbose\") then\n            table.insert(argv, \"--verbose\")\n        end\n        \n        os.vrunv(nix_env.program, argv)\n    end\nend"
  },
  {
    "path": "xmake/modules/package/manager/nix/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ZZBaron\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search packages using modern nix search\nfunction _search_with_flakes(nix, name)\n    local results = {}\n    \n    -- use nix search to find packages\n    local searchdata = try {function ()\n        return os.iorunv(nix.program, {\"search\", \"nixpkgs\", name, \"--json\"})\n    end}\n    \n    if searchdata then\n        -- parse JSON output\n        local ok, data = try {function ()\n            return json.decode(searchdata)\n        end}\n        \n        if ok and data then\n            for pkgname, pkginfo in pairs(data) do\n                -- extract package name from the full path (e.g., \"legacyPackages.x86_64-linux.cmake\" -> \"cmake\")\n                local simplename = pkgname:match(\"([^%.]+)$\")\n                if simplename and simplename:find(name, 1, true) then\n                    table.insert(results, {\n                        name = \"nix::\" .. simplename,\n                        version = pkginfo.version or \"unknown\",\n                        description = pkginfo.description or \"\"\n                    })\n                end\n            end\n        end\n    end\n    \n    return results\nend\n\n-- search packages using legacy nix-env\nfunction _search_with_env(name)\n    local results = {}\n    local nixenv = find_tool(\"nix-env\")\n    if not nixenv then\n        return results\n    end\n    \n    -- use nix-env to search for packages\n    local searchdata = try {function ()\n        return os.iorunv(nixenv.program, {\"-qaP\", \"*\" .. name .. \"*\"})\n    end}\n    \n    if searchdata then\n        -- parse nix-env output format:\n        -- nixpkgs.cmake                                cmake-3.27.7\n        -- nixpkgs.cmake-cursor                         cmake-cursor-0.2.1\n        -- nixpkgs.cmakeWithGui                         cmake-3.27.7\n        \n        for _, line in ipairs(searchdata:split(\"\\n\", {plain = true})) do\n            line = line:trim()\n            if line ~= \"\" then\n                local parts = line:split(\"%s+\", {limit = 2})\n                if #parts >= 2 then\n                    local fullname = parts[1]\n                    local version_desc = parts[2]\n                    \n                    -- extract simple package name\n                    local pkgname = fullname:match(\"nixpkgs%.(.+)\")\n                    if pkgname and pkgname:find(name, 1, true) then\n                        -- try to separate version from description\n                        local version = version_desc:match(\"^([%d%.%-]+)\")\n                        local description = version_desc:gsub(\"^[%d%.%-]+%s*\", \"\")\n                        \n                        table.insert(results, {\n                            name = \"nix::\" .. pkgname,\n                            version = version or \"unknown\",\n                            description = description or \"\"\n                        })\n                    end\n                end\n            end\n        end\n    end\n    \n    return results\nend\n\n-- search package using the nix package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n    -- find nix\n    local nix = find_tool(\"nix\")\n    if not nix then\n        raise(\"nix not found!\")\n    end\n    \n    -- check if we have flakes enabled (modern nix)\n    local hasflakes = try {function ()\n        return os.iorunv(nix.program, {\"search\", \"--help\"}, {stdout = os.nuldev()})\n    end}\n    \n    local results = {}\n    \n    -- try modern search first\n    if hasflakes then\n        results = try {function ()\n            return _search_with_flakes(nix, name)\n        end} or {}\n    end\n    \n    -- fallback to legacy search if modern search failed or returned no results\n    if #results == 0 then\n        results = try {function ()\n            return _search_with_env(name)\n        end} or {}\n    end\n    \n    -- remove duplicates and sort\n    local seen = {}\n    local unique_results = {}\n    for _, result in ipairs(results) do\n        local key = result.name\n        if not seen[key] then\n            seen[key] = true\n            table.insert(unique_results, result)\n        end\n    end\n    \n    -- sort by package name\n    table.sort(unique_results, function(a, b)\n        return a.name < b.name\n    end)\n    \n    return unique_results\nend"
  },
  {
    "path": "xmake/modules/package/manager/nuget/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.option\")\nimport(\"core.base.json\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _find_target_root(targets, name)\n    local namelower = name:lower()\n    for targetname in pairs(targets or {}) do\n        local targetpkg = targetname:match(\"^([^/]+)\") or targetname\n        local targetpkglower = targetpkg:lower()\n        local targetnamelower = targetname:lower()\n        local normalized_targetpkg = targetpkglower:gsub(\"[._%-]\", \"\")\n        local normalized_name = namelower:gsub(\"[._%-]\", \"\")\n        if targetnamelower == namelower\n           or targetnamelower:startswith(namelower .. \"/\")\n           or targetpkglower == namelower\n           or normalized_targetpkg == normalized_name then\n            return targetname\n        end\n    end\nend\n\nfunction _find_library_root(libraries, name)\n    local namelower = name:lower()\n    for libraryname in pairs(libraries or {}) do\n        local librarypkg = libraryname:match(\"^([^/]+)\") or libraryname\n        local librarypkglower = librarypkg:lower()\n        local librarynamelower = libraryname:lower()\n        local normalized_librarypkg = librarypkglower:gsub(\"[._%-]\", \"\")\n        local normalized_name = namelower:gsub(\"[._%-]\", \"\")\n        if librarynamelower == namelower\n           or librarynamelower:startswith(namelower .. \"/\")\n           or librarypkglower == namelower\n           or normalized_librarypkg == normalized_name then\n            return libraryname\n        end\n    end\nend\n\nfunction _find_version_in_project_dependencies(manifest, name)\n    local namelower = name:lower()\n    local normalized_name = namelower:gsub(\"[._%-]\", \"\")\n    if manifest.project and manifest.project.frameworks then\n        for _, framework in pairs(manifest.project.frameworks) do\n            local dependencies = framework.dependencies or {}\n            for depname, depver in pairs(dependencies) do\n                local deplower = depname:lower()\n                local normalized_depname = deplower:gsub(\"[._%-]\", \"\")\n                if deplower == namelower or normalized_depname == normalized_name then\n                    return tostring(depver)\n                end\n            end\n        end\n    end\nend\n\nfunction _get_packagesdir_from_manifest(manifest)\n    if manifest.project and manifest.project.restore and manifest.project.restore.packagesPath then\n        return manifest.project.restore.packagesPath\n    end\n    if manifest.packageFolders then\n        for folder in pairs(manifest.packageFolders) do\n            return folder\n        end\n    end\n    local packagesdir = os.getenv(\"NUGET_PACKAGES\")\n    if packagesdir and #packagesdir > 0 then\n        return packagesdir\n    end\n    local homedir = os.homedir and os.homedir()\n    if homedir and #homedir > 0 then\n        return path.join(homedir, \".nuget\", \"packages\")\n    end\nend\n\nlocal function _extract_version_from_root(rootname)\n    if rootname then\n        return rootname:match(\"/(.+)$\")\n    end\nend\n\n-- check if pattern matches as a complete path component\n-- e.g. \"x86\" should match \"/x86/\" but not \"/x86_64/\"\nfunction _match_path_component(file_lower, pattern)\n    local s, e = file_lower:find(pattern, 1, true)\n    while s do\n        -- check boundary: start of string or path separator before\n        local before_ok = (s == 1) or file_lower:sub(s - 1, s - 1):match(\"[/\\\\]\")\n        -- check boundary: end of string or path separator after\n        local after_ok = (e == #file_lower) or file_lower:sub(e + 1, e + 1):match(\"[/\\\\]\")\n        if before_ok and after_ok then\n            return true\n        end\n        -- continue searching from next position\n        s, e = file_lower:find(pattern, e + 1, true)\n    end\n    return false\nend\n\n-- match library file by analyzing path components\n-- returns match score (higher is better), 0 means no match\nfunction _match_libfile(file, libarch, toolset, libmode, runtime)\n    -- architecture aliases for matching\n    local arch_patterns = {\n        x64 = {\"x64\", \"amd64\", \"x86_64\"},\n        Win32 = {\"win32\", \"x86\", \"i386\", \"i686\"},\n        arm64 = {\"arm64\", \"aarch64\"},\n    }\n    local target_archs = arch_patterns[libarch] or {libarch:lower()}\n\n    -- check if file path contains target architecture\n    local file_lower = file:lower()\n    local has_arch = false\n    for _, arch_name in ipairs(target_archs) do\n        if _match_path_component(file_lower, arch_name) then\n            has_arch = true\n            break\n        end\n    end\n\n    -- check if file contains other architecture (should exclude)\n    for arch, patterns in pairs(arch_patterns) do\n        if arch ~= libarch then\n            for _, p in ipairs(patterns) do\n                if _match_path_component(file_lower, p) then\n                    return 0 -- contains wrong architecture\n                end\n            end\n        end\n    end\n\n    -- calculate match score based on path components\n    local score = has_arch and 10 or 1\n    if toolset and file_lower:find(toolset:lower(), 1, true) then\n        score = score + 4\n    end\n    if file_lower:find(libmode:lower(), 1, true) then\n        score = score + 2\n    end\n    if runtime and file_lower:find(runtime:lower(), 1, true) then\n        score = score + 1\n    end\n    return score\nend\n\n-- find native package files\nfunction _find_package(name, result, opt)\n    local arch = opt.arch\n    local plat = opt.plat\n    local configs = opt.configs or {}\n    local libinfo = opt.libraries[name]\n    if libinfo then\n        local libarchs = {x64 = \"x64\", x86 = \"Win32\", arm64 = \"arm64\"}\n        local runtimes = {\n            MT = \"MultiThreaded\",\n            MTd = \"MultiThreadedDebug\",\n            MD = \"MultiThreadedDLL\",\n            MDd = \"MultiThreadedDebugDLL\"}\n        local runtime = runtimes[configs.runtimes]\n        local installdir = path.join(opt.packagesdir, name)\n        local msvc = toolchain.load(\"msvc\", {plat = plat, arch = arch})\n        local toolset = msvc and toolchain_utils.get_vs_toolset_ver(msvc:config(\"vs_toolset\") or config.get(\"vs_toolset\")) or nil\n        local libarch = libarchs[arch] or \"x64\"\n        local libmode = configs.debug and \"Debug\" or \"Release\"\n        for _, file in ipairs(libinfo.files) do\n            local filepath = path.join(installdir, file)\n            file = file:trim()\n\n            -- get includedirs\n            -- support multiple include directory patterns:\n            -- e.g. build/native/include/*.h, build/native/include-winrt/*.h\n            if file:endswith(\".h\") or file:endswith(\".hpp\") or file:endswith(\".hxx\") then\n                local dir = path.directory(file)\n                if dir and (dir:find(\"include\", 1, true) or dir:find(\"inc\", 1, true)) then\n                    result.includedirs = result.includedirs or {}\n                    table.insert(result.includedirs, path.join(installdir, dir))\n                end\n            end\n\n            -- get linkdirs and links\n            -- use score-based matching to support various directory structures\n            if file:endswith(\".lib\") then\n                local score = _match_libfile(file, libarch, toolset, libmode, runtime)\n                if score > 0 then\n                    local libname = path.filename(filepath)\n                    -- check if we already have this lib with a better match\n                    result._libscores = result._libscores or {}\n                    local existing_score = result._libscores[libname] or 0\n                    if score > existing_score then\n                        -- remove old entry if exists\n                        if existing_score > 0 then\n                            for i, v in ipairs(result.links or {}) do\n                                if target.linkname(libname, {plat = plat}) == v then\n                                    table.remove(result.links, i)\n                                    table.remove(result.linkdirs, i)\n                                    table.remove(result.libfiles, i)\n                                    break\n                                end\n                            end\n                        end\n                        result.links = result.links or {}\n                        result.linkdirs = result.linkdirs or {}\n                        result.libfiles = result.libfiles or {}\n                        table.insert(result.linkdirs, path.directory(filepath))\n                        table.insert(result.links, target.linkname(libname, {plat = plat}))\n                        table.insert(result.libfiles, filepath)\n                        result._libscores[libname] = score\n                    end\n                end\n            end\n        end\n    end\n    local targetinfo = opt.targets[name]\n    if targetinfo then\n        local dependencies = targetinfo.dependencies\n        if dependencies then\n            for k, v in pairs(dependencies) do\n                _find_package(k .. \"/\" .. v, result, opt)\n            end\n        end\n    end\nend\n\nfunction _cleanup_result(result, version)\n    result._libscores = nil\n    if version and not result.version then\n        result.version = version\n    end\n    if result.links or result.includedirs then\n        if result.includedirs then\n            result.includedirs = table.unique(result.includedirs)\n        end\n        if result.linkdirs then\n            result.linkdirs = table.unique(result.linkdirs)\n        end\n    end\n    return result\nend\n\n-- find package from the nuget package manager\n--\n-- @param name  the package name, e.g. zlib, pcre\n-- @param opt   the options, e.g. {verbose = true)\n--\nfunction main(name, opt)\n    opt = opt or {}\n\n    -- load manifest info\n    local installdir = assert(opt.installdir, \"installdir not found!\")\n    local stubdir = path.join(installdir, \"stub\")\n    local manifestfile = path.join(stubdir, \"obj\", \"project.assets.json\")\n    if not os.isfile(manifestfile) then\n        return\n    end\n    local manifest = json.loadfile(manifestfile)\n    local packagesdir = _get_packagesdir_from_manifest(manifest)\n    if not manifest.libraries then\n        return\n    end\n\n    if manifest.targets and packagesdir then\n        for _, targets in pairs(manifest.targets) do\n            local target_root = _find_target_root(targets, name)\n            if target_root then\n                local metainfo = {}\n                metainfo.plat = opt.plat\n                metainfo.arch = opt.arch\n                metainfo.mode = opt.mode\n                metainfo.configs = opt.configs\n                metainfo.targets = targets\n                metainfo.libraries = manifest.libraries\n                metainfo.packagesdir = packagesdir\n                local result = {}\n                _find_package(target_root, result, metainfo)\n                return _cleanup_result(result, _extract_version_from_root(target_root))\n            end\n        end\n    end\n\n    local library_root = _find_library_root(manifest.libraries, name)\n    if library_root then\n        if packagesdir then\n            local metainfo = {}\n            metainfo.plat = opt.plat\n            metainfo.arch = opt.arch\n            metainfo.mode = opt.mode\n            metainfo.configs = opt.configs\n            metainfo.targets = {}\n            metainfo.libraries = manifest.libraries\n            metainfo.packagesdir = packagesdir\n            local result = {}\n            _find_package(library_root, result, metainfo)\n            return _cleanup_result(result, _extract_version_from_root(library_root))\n        end\n        -- package exists in manifest but package root cannot be determined,\n        -- treat managed-only package as found.\n        return {version = _extract_version_from_root(library_root)}\n    end\n\n    -- fallback for managed package references if target/library keys are not aligned\n    -- with the requested package name format.\n    local depver = _find_version_in_project_dependencies(manifest, name)\n    if depver then\n        return {version = depver}\n    end\n    if opt.require_version then\n        return {version = tostring(opt.require_version)}\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/nuget/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\n\n-- dotnet add package libpapki --version 1.0.147\nfunction _install(dotnet, name, opt)\n\n    -- init argv\n    local argv = {\"add\", \"package\", name}\n    local require_version = opt.require_version\n    if require_version == \"latest\" then\n        require_version = nil\n    end\n    if require_version then\n        table.insert(argv, \"--version\")\n        table.insert(argv, require_version)\n    end\n\n    local installdir = assert(opt.installdir, \"installdir not found!\")\n    if not os.isdir(installdir) then\n        os.mkdir(installdir)\n    end\n    local stubdir = path.join(installdir, \"stub\")\n    if not os.isdir(stubdir) then\n        os.vrunv(dotnet, {\"new\", \"console\", \"-n\", \"stub\"}, {curdir = installdir})\n    end\n\n    -- install package\n    os.vrunv(dotnet, argv, {curdir = stubdir})\nend\n\n-- install package\n--\n-- @param name  the package name, e.g. pcre2\n-- @param opt   the options, e.g. {verbose = true}\n--\nfunction main(name, opt)\n    local dotnet = find_tool(\"dotnet\")\n    if not dotnet then\n        raise(\"dotnet not found!\")\n    end\n    _install(dotnet.program, name, opt or {})\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/pacman/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get configurations\nfunction main()\n    return {\n        msystem = {description = \"Install pacman packages from the given msystem on msys2.\", values = {\"msys\", \"ucrt\", \"clang\", \"mingw\"}}\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/pacman/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.pkgconfig.find_package\", {alias = \"find_package_from_pkgconfig\"})\nimport(\"get_package_name\")\n\n-- find package from list of file inside pacman package\nfunction _find_package_from_list(list, name, pacman, opt)\n\n    -- mingw + pacman = cygpath available\n    local cygpath = nil\n    local pathtomsys = nil\n    local msystem = nil\n    if is_subhost(\"msys\") and opt.plat == \"mingw\" then\n        cygpath = find_tool(\"cygpath\")\n        if not cygpath then\n            return\n        end\n        pathtomsys = os.iorunv(cygpath.program, {\"--windows\", \"/\"})\n        pathtomsys = pathtomsys:trim()\n        msystem = os.getenv(\"MSYSTEM\")\n        if msystem then\n            msystem = msystem:lower()\n        end\n    end\n\n    -- iterate over each file path inside the pacman package\n    local result = {}\n    for _, line in ipairs(list:split('\\n', {plain = true})) do -- on msys cygpath should be used to convert local path to windows path\n        line = line:trim():split('%s+')[2]\n        if line:find(\"/include/\", 1, true) and (line:endswith(\".h\") or line:endswith(\".hpp\")) then\n            if not line:startswith(\"/usr/include/\") then\n                if not (msystem and line:startswith(\"/\" .. msystem .. \"/include/\")) then\n                    result.includedirs = result.includedirs or {}\n                    local hpath = line\n                    if is_subhost(\"msys\") and opt.plat == \"mingw\" then\n                        hpath = path.join(pathtomsys, line)\n                        local basehpath = path.join(pathtomsys, msystem .. \"/include\")\n                        table.insert(result.includedirs, basehpath)\n                    end\n                    table.insert(result.includedirs, path.directory(hpath))\n                end\n            end\n        -- remove lib and .a, .dll.a and .so to have the links\n        elseif line:endswith(\".dll.a\") then -- only for mingw\n            local apath = path.join(pathtomsys, line)\n            apath = apath:trim()\n            result.linkdirs = result.linkdirs or {}\n            result.links = result.links or {}\n            table.insert(result.linkdirs, path.directory(apath))\n            table.insert(result.links, target.linkname(path.filename(apath), {plat = opt.plat}))\n        elseif line:endswith(\".so\") then\n            result.linkdirs = result.linkdirs or {}\n            result.links = result.links or {}\n            table.insert(result.linkdirs, path.directory(line))\n            table.insert(result.links, target.linkname(path.filename(line), {plat = opt.plat}))\n        elseif line:endswith(\".a\") then\n            result.linkdirs = result.linkdirs or {}\n            result.links = result.links or {}\n            local apath = line\n            if is_subhost(\"msys\") and opt.plat == \"mingw\" then\n                apath = path.join(pathtomsys, line)\n                apath = apath:trim()\n            end\n            table.insert(result.linkdirs, path.directory(apath))\n            table.insert(result.links, target.linkname(path.filename(apath), {plat = opt.plat}))\n        end\n    end\n    if result.includedirs then\n        result.includedirs = table.unique(result.includedirs)\n    end\n    if result.linkdirs then\n        result.linkdirs = table.unique(result.linkdirs)\n    end\n    if result.links then\n        result.links = table.reverse_unique(result.links)\n    end\n\n    -- use pacman package version as version\n    local version = try { function() return os.iorunv(pacman.program, {\"-Q\", name}) end }\n    if version then\n        version = version:trim():split('%s+')[2]\n        -- we need strip \"1:\" prefix, @see https://github.com/xmake-io/xmake/issues/2020\n        -- e.g. vulkan-headers 1:1.3.204-1\n        if version:startswith(\"1:\") then\n            version = version:split(':')[2]\n        end\n        result.version = version:split('-')[1]\n    else\n        result = nil\n    end\n    return result\nend\n\n-- find libfiles from list of file inside pacman package\nfunction _find_libfiles_from_list(list, name, pacman, opt)\n\n    -- mingw + pacman = cygpath available\n    local cygpath = nil\n    local pathtomsys = nil\n    if is_subhost(\"msys\") and opt.plat == \"mingw\" then\n        cygpath = find_tool(\"cygpath\")\n        if not cygpath then\n            return\n        end\n        pathtomsys = os.iorunv(cygpath.program, {\"--windows\", \"/\"})\n        pathtomsys = pathtomsys:trim()\n    end\n\n    -- iterate over each file path inside the pacman package\n    local libfiles\n    for _, line in ipairs(list:split('\\n', {plain = true})) do -- on msys cygpath should be used to convert local path to windows path\n        line = line:trim():split('%s+')[2]\n        if line:endswith(\".dll.a\") then -- only for mingw\n            local apath = path.join(pathtomsys, line)\n            apath = apath:trim()\n            libfiles = libfiles or {}\n            table.insert(libfiles, apath)\n        elseif line:endswith(\".so\") then\n            libfiles = libfiles or {}\n            table.insert(libfiles, line)\n        elseif line:endswith(\".a\") then\n            local apath = line\n            if is_subhost(\"msys\") and opt.plat == \"mingw\" then\n                apath = path.join(pathtomsys, line)\n                apath = apath:trim()\n            end\n            libfiles = libfiles or {}\n            table.insert(libfiles, apath)\n        end\n    end\n    return libfiles\nend\n\n-- find package from the system directories\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    -- find pacman\n    local pacman = find_tool(\"pacman\")\n    if not pacman then\n        return\n    end\n\n    -- get package name\n    name = get_package_name(name, opt)\n\n    -- get package files list\n    local list = name and try { function() return os.iorunv(pacman.program, {\"-Q\", \"-l\", name}) end }\n    if not list then\n        return\n    end\n\n    -- parse package files list\n    local linkdirs = {}\n    local pkgconfig_files = {}\n    for _, line in ipairs(list:split('\\n', {plain = true})) do\n        line = line:trim():split('%s+')[2]\n        if line:find(\"/pkgconfig/\", 1, true) and line:endswith(\".pc\") then\n            table.insert(pkgconfig_files, line)\n        end\n        if line:endswith(\".so\") or line:endswith(\".a\") or line:endswith(\".lib\") then\n            table.insert(linkdirs, path.directory(line))\n        end\n    end\n    linkdirs = table.unique(linkdirs)\n\n    -- we iterate over each pkgconfig file to extract the required data\n    local result\n    for _, pkgconfig_file in ipairs(pkgconfig_files) do\n        local pkgconfig_dir = path.directory(pkgconfig_file)\n        local pkgconfig_name = path.basename(pkgconfig_file)\n        local pcresult = find_package_from_pkgconfig(pkgconfig_name, {configdirs = pkgconfig_dir, linkdirs = linkdirs})\n        if pcresult then\n            result = result or {}\n            for _, includedir in ipairs(pcresult.includedirs) do\n                result.includedirs = result.includedirs or {}\n                table.insert(result.includedirs, includedir)\n            end\n            for _, linkdir in ipairs(pcresult.linkdirs) do\n                result.linkdirs = result.linkdirs or {}\n                table.insert(result.linkdirs, linkdir)\n            end\n            for _, link in ipairs(pcresult.links) do\n                result.links = result.links or {}\n                table.insert(result.links, link)\n            end\n            for _, libfile in ipairs(pcresult.libfiles) do\n                result.libfiles = result.libfiles or {}\n                table.insert(result.libfiles, libfile)\n            end\n            result.shared = pcresult.shared\n            result.static = pcresult.static\n        end\n    end\n\n    if result then\n        if result.includedirs then\n            result.includedirs = table.unique(result.includedirs)\n        end\n        if result.linkdirs then\n            result.linkdirs = table.unique(result.linkdirs)\n        end\n        if result.libfiles then\n            result.libfiles = table.unique(result.libfiles)\n        end\n        if result.links then\n            result.links = table.reverse_unique(result.links)\n        end\n\n        -- We should get version from pacman, because if a pacman package contains multiples .pc we may get a wrong version\n        local verstr = try { function() return os.iorunv(pacman.program, {\"-Q\", name}) end }\n        if verstr then\n            local version = semver.match(verstr)\n            if version then\n                result.version = version:rawstr():split('-')[1]\n            end\n        end\n    else\n        -- if there is no .pc, we parse the package content to obtain the data we want\n        result = _find_package_from_list(list, name, pacman, opt)\n    end\n    if result then\n        -- we give priority to libfiles in the list\n        local libfiles = _find_libfiles_from_list(list, name, pacman, opt)\n        if libfiles then\n            result.shared = nil\n            result.static = nil\n            result.libfiles = libfiles\n            for _, libfile in ipairs(libfiles) do\n                if libfile:endswith(\".so\") then\n                    result.shared = true\n                elseif libfile:endswith(\".a\") then\n                    result.static = true\n                end\n            end\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/pacman/get_package_name.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        get_package_name.lua\n--\n\nfunction main(name, opt)\n    opt = opt or {}\n    local configs = opt.configs or {}\n\n    -- https://www.msys2.org/docs/package-naming/\n    if is_subhost(\"msys\") then\n        local msystem = configs.msystem\n        if not msystem and opt.plat == \"mingw\" then\n            msystem = \"mingw\"\n        end\n        if msystem == \"mingw\" or msystem == \"ucrt\" or msystem == \"clang\" then\n            local prefix = \"mingw-w64-\"\n            local arch = opt.arch\n            if arch == \"x86\" or arch == \"i386\" then\n                arch = \"i686\"\n            elseif arch == \"x64\" then\n                arch = \"x86_64\"\n            elseif arch == \"arm64\" then\n                arch = \"aarch64\"\n            end\n            if msystem ~= \"mingw\" then\n                name = prefix .. msystem .. \"-\" .. arch .. \"-\" .. name\n            else\n                name = prefix .. arch .. \"-\" .. name\n            end\n        else\n            -- msys packages, no prefix\n        end\n    end\n    return name\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/pacman/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"privilege.sudo\")\nimport(\"get_package_name\")\n\n-- install package\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, pacman = \"the package name\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local pacman = find_tool(\"pacman\")\n    if not pacman then\n        raise(\"pacman not found!\")\n    end\n\n    -- get package name\n    name = get_package_name(name, opt)\n\n    -- init argv\n    local argv = {\"-Sy\", \"--noconfirm\", \"--needed\", \"--disable-download-timeout\", name}\n    if opt.verbose or option.get(\"verbose\") then\n        table.insert(argv, \"--verbose\")\n    end\n\n    -- install package directly if the current user is root\n    if is_host(\"windows\") or os.isroot() then\n        os.vrunv(pacman.program, argv)\n    -- install with administrator permission?\n    elseif sudo.has() then\n\n        -- install it if be confirmed\n        local description = format(\"try installing %s with administrator permission\", name)\n        local confirm = utils.confirm({default = true, description = description})\n        if confirm then\n            sudo.vrunv(pacman.program, argv)\n        end\n    else\n        raise(\"cannot get administrator permission!\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/pkgconfig/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"lib.detect.pkgconfig\")\nimport(\"lib.detect.find_library\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.system.find_package\", {alias = \"find_package_from_system\"})\n\n-- find package from the pkg-config package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    -- get library info\n    local libinfo = pkgconfig.libinfo(name, opt)\n    if not libinfo and name:startswith(\"lib\") then\n        -- libxxx? attempt to find xxx without `lib` prefix\n        libinfo = pkgconfig.libinfo(name:sub(4), opt)\n    end\n    if not libinfo then\n        return\n    end\n\n    -- no linkdirs in pkg-config? attempt to find it from system directories\n    if libinfo.links and not libinfo.linkdirs then\n        local libinfo_sys = find_package_from_system(name, table.join(opt, {links = libinfo.links}))\n        if libinfo_sys then\n            libinfo.linkdirs = libinfo_sys.linkdirs\n        end\n    end\n\n    -- get result, libinfo may be empty body, but it's also valid\n    -- @see https://github.com/xmake-io/xmake/issues/3777#issuecomment-1568453316\n    local result = nil\n    if libinfo then\n        result             = result or {}\n        result.includedirs = libinfo.includedirs\n        result.linkdirs    = libinfo.linkdirs\n        result.links       = libinfo.links\n        result.defines     = libinfo.defines\n        result.cxflags     = libinfo.cxflags\n        result.ldflags     = libinfo.ldflags\n        result.shflags     = libinfo.shflags\n        result.version     = libinfo.version\n    end\n\n    -- find libfiles\n    if result and libinfo then\n        local libdirs = libinfo.linkdirs\n        if not libdirs then\n            local pcfile = pkgconfig.pcfile(name, opt)\n            if not pcfile and name:startswith(\"lib\") then\n                pcfile = pkgconfig.pcfile(name:sub(4), opt)\n            end\n            if pcfile then\n                libdirs = path.directory(pcfile)\n                if path.filename(libdirs) == \"pkgconfig\" then\n                    libdirs = path.directory(libdirs)\n                end\n            end\n        end\n        if libdirs and libinfo.links then\n            for _, link in ipairs(libinfo.links) do\n                local info = find_library(link, libdirs, {plat = opt.plat})\n                if info and info.linkdir and info.filename then\n                    result.libfiles = result.libfiles or {}\n                    table.insert(result.libfiles, path.join(info.linkdir, info.filename))\n                    if info.kind then\n                        result[info.kind] = true\n                    end\n                end\n            end\n        end\n        if result.libfiles then\n            result.libfiles = table.unique(result.libfiles)\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/portage/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.pkgconfig.find_package\", {alias = \"find_package_from_pkgconfig\"})\n\n-- find package from the system directories\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    -- for msys2/mingw? mingw-w64-[i686|x86_64]-xxx\n    if opt.plat == \"mingw\" then\n        name = \"mingw64-runtime\" -- there is only one package for mingw\n    end\n\n    -- get package contents file\n    local file = find_file(\"CONTENTS\", \"/var/db/pkg/*/\" .. name .. \"-*\")\n    if not file then\n        return\n    end\n\n    -- get package files list\n    local list = {}\n    local file_contents = io.readfile(file)\n    for _, entry in pairs(file_contents:split(\"\\n\")) do\n        -- the file path is the second element after being delimited by spaces\n        local split_entry = entry:split(\" \")[2]\n        if split_entry then\n            table.insert(list, split_entry)\n        end\n    end\n\n    -- parse package files list\n    local linkdirs = {}\n    local has_includes = false\n    local pkgconfig_files = {}\n    for _, line in ipairs(list) do\n        line = line:trim():split('%s+')[1]\n        if line:find(\"/pkgconfig/\", 1, true) and line:endswith(\".pc\") then\n            pkgconfig_files[path.basename(line)] = line\n        end\n        if line:endswith(\".so\") or line:endswith(\".a\") or line:endswith(\".lib\") then\n            table.insert(linkdirs, path.directory(line))\n        elseif line:find(\"/include/\", 1, true) and (line:endswith(\".h\") or line:endswith(\".hpp\")) then\n            has_includes = true\n        end\n    end\n\n    -- get pkgconfig file\n    local pkgconfig_file = pkgconfig_files[name]\n    if not pkgconfig_file then\n        for _, file in pairs(pkgconfig_files) do\n            pkgconfig_file = file\n            break\n        end\n    end\n\n    -- find package\n    local result = nil\n    if pkgconfig_file then\n        local pkgconfig_dir = path.directory(pkgconfig_file)\n        local pkgconfig_name = path.basename(pkgconfig_file)\n        linkdirs = table.unique(linkdirs)\n        includedirs = table.unique(includedirs)\n        result = find_package_from_pkgconfig(pkgconfig_name, {configdirs = pkgconfig_dir, linkdirs = linkdirs})\n        if not result and has_includes then\n            -- header only and hidden /usr/include? we only need to return empty {}\n            result = {}\n        end\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/portage/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"privilege.sudo\")\n\n-- install package\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, emerge = \"the package name\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find emerge\n    local emerge = find_tool(\"emerge\")\n    if not emerge then\n        raise(\"emerge not found!\")\n    end\n\n    -- for msys2/mingw? mingw-w64-[i686|x86_64]-xxx\n    if opt.plat == \"mingw\" then\n        name = \"mingw64-runtime\"\n    end\n\n    -- init argv\n    -- ask for confirmation, view tree of packages, verbose\n    -- it is set this way because Portage compiles from source\n    -- therefore it's better to have more info and ask for confirmation\n    -- that way the user can ensure they installed the package with the correct USE flags\n    local argv = {\"-a\", \"-t\", \"-v\", opt.emerge or name}\n    if opt.verbose or option.get(\"verbose\") then\n        table.insert(argv, \"-v\")\n    end\n\n    -- install package directly if the current user is root\n    if is_subhost(\"msys\") or os.isroot() then\n        os.vrunv(emerge.program, argv)\n    -- install with administrator permission?\n    elseif sudo.has() then\n\n        -- install it if be confirmed\n        local description = format(\"try installing %s with administrator permission\", name)\n        local confirm = utils.confirm({default = true, description = description})\n        if confirm then\n            sudo.vrunv(emerge.program, argv)\n        end\n    else\n        raise(\"cannot get administrator permission!\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/system/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.language.language\")\nimport(\"core.platform.platform\")\nimport(\"private.core.base.is_cross\")\nimport(\"lib.detect.check_cxsnippets\")\n\n-- get package items\nfunction _get_package_items()\n    local items = {}\n    for _, apiname in ipairs(table.join(language.apis().values, language.apis().paths)) do\n        if apiname:startswith(\"target.\") then\n            local valuename = apiname:split('.add_', {plain = true})[2]\n            if valuename then\n                table.insert(items, valuename)\n            end\n        end\n    end\n    return items\nend\n\n-- find package from system and compiler\n-- @see https://github.com/xmake-io/xmake/issues/4596\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, package = <package instance>, includes = \"\", sourcekind = \"[cc|cxx|mm|mxx]\",\n--              funcs = {\"sigsetjmp\", \"sigsetjmp((void*)0, 0)\"},\n--              configs = {defines = \"\", links = \"\", cflags = \"\"}}\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n\n    local configs = opt.configs or {}\n    local items = _get_package_items()\n    local snippet_configs = {}\n    for _, name in ipairs(items) do\n        snippet_configs[name] = configs[name]\n    end\n    snippet_configs.links = snippet_configs.links or name\n\n    local snippet_opt = {\n        verbose = opt.verbose,\n        target = opt.package,\n        funcs = opt.funcs,\n        sourcekind = opt.sourcekind,\n        includes = opt.includes,\n        configs = snippet_configs}\n\n    local snippetname = \"find_package/\" .. name\n    local snippets = opt.snippets or {[snippetname] = \"\"}\n    if check_cxsnippets(snippets, snippet_opt) then\n        local result = snippet_configs\n        if not table.empty(result) then\n            return result\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/vcpkg/configurations.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configurations.lua\n--\n\n-- get architecture for vcpkg\nfunction arch(arch)\n    local archs = {\n        x86_64          = \"x64\",\n        i386            = \"x86\",\n\n        -- android: armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mip64\n        -- Offers a doc: https://github.com/microsoft/vcpkg/tree/master/triplets\n        [\"armeabi-v7a\"] = \"arm-neon\",\n        [\"arm64-v8a\"]   = \"arm64\",\n\n        -- ios: arm64 armv7 armv7s i386\n        armv7           = \"arm\",\n        armv7s          = \"arm\",\n        arm64           = \"arm64\",\n    }\n    return archs[arch] or arch\nend\n\n-- get platform for vcpkg\nfunction plat(plat)\n    local plats = {\n        macosx          = \"osx\",\n        iphoneos        = \"ios\",\n        bsd             = \"freebsd\",\n    }\n    return plats[plat] or plat\nend\n\n-- get triplet\nfunction triplet(configs, plat, arch)\n    configs = configs or {}\n    local triplet = arch .. \"-\" .. plat\n    if plat == \"windows\" and configs.shared ~= true then\n        triplet = triplet .. \"-static\"\n        if configs.runtimes and configs.runtimes:startswith(\"MD\") then\n            triplet = triplet .. \"-md\"\n        end\n    elseif plat == \"linux\" then\n        -- x64-linux-dynamic\n        if arch == \"x64\" and configs.shared then\n            triplet = triplet .. \"-dynamic\"\n        end\n    elseif plat == \"osx\" then\n        -- x64-osx-dynamic\n        -- arm64-osx-dynamic\n        if (arch == \"x64\" or arch == \"arm64\") and configs.shared then\n            triplet = triplet .. \"-dynamic\"\n        end\n    elseif plat == \"mingw\" then\n        triplet = triplet .. (configs.shared ~= true and \"-static\" or \"-dynamic\")\n    end\n    return triplet\nend\n\n-- get configurations\nfunction main()\n    return {\n        baseline           = {description = \"set the builtin baseline.\"},\n        features           = {description = \"set the features of dependency.\"},\n        default_features   = {description = \"enables or disables any defaults provided by the dependency.\", default = true},\n        registries         = {description = \"set the registries in vcpkg-configuration.json\"},\n        default_registries = {description = \"set the default registries in vcpkg-configuration.json\"}\n    }\nend\n\n"
  },
  {
    "path": "xmake/modules/package/manager/vcpkg/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"detect.sdks.find_vcpkgdir\")\nimport(\"package.manager.vcpkg.configurations\")\nimport(\"package.manager.vcpkg.utils\", {alias = \"vcpkg_utils\"})\nimport(\"package.manager.pkgconfig.find_package\", {alias = \"find_package_from_pkgconfig\"})\n\n-- extract required features from both package name and configs.features.\nfunction _required_features(name, configs)\n    local features = {}\n    local features_str = name:match(\"%[(.-)%]\")\n    if features_str then\n        for _, feature in ipairs(features_str:split(\",\", {plain = true})) do\n            feature = feature:trim()\n            if #feature > 0 then\n                table.insert(features, feature)\n            end\n        end\n    end\n    for _, feature in ipairs(table.wrap(configs and configs.features)) do\n        feature = tostring(feature):trim()\n        if #feature > 0 then\n            table.insert(features, feature)\n        end\n    end\n    features = table.unique(features)\n    if #features > 0 then\n        return features\n    end\nend\n\n-- we iterate over each pkgconfig file to extract the required data\nfunction _find_package_from_pkgconfig(pkgconfig_files, opt)\n    opt = opt or {}\n    local foundpc = false\n    local result = {includedirs = {}, linkdirs = {}, links = {}}\n    for _, pkgconfig_file in ipairs(pkgconfig_files) do\n        local pkgconfig_dir = path.join(opt.installdir, path.directory(pkgconfig_file))\n        local pkgconfig_name = path.basename(pkgconfig_file)\n        local pcresult = find_package_from_pkgconfig(pkgconfig_name, {configdirs = pkgconfig_dir, linkdirs = opt.linkdirs})\n\n        -- the pkgconfig file has been parse successfully\n        if pcresult then\n            for _, includedir in ipairs(pcresult.includedirs) do\n                table.insert(result.includedirs, includedir)\n            end\n            for _, linkdir in ipairs(pcresult.linkdirs) do\n                table.insert(result.linkdirs, linkdir)\n            end\n            for _, link in ipairs(pcresult.links) do\n                table.insert(result.links, link)\n            end\n            -- version should be the same if a pacman package contains multiples .pc\n            result.version = pcresult.version\n            foundpc = true\n        end\n    end\n\n    if foundpc == true then\n        result.includedirs = table.unique(result.includedirs)\n        result.linkdirs = table.unique(result.linkdirs)\n        result.links = table.reverse_unique(result.links)\n        return result\n    end\nend\n\nfunction _get_package_info(name, triplet, infodirs, arch, plat, mode)\n    -- find the package info file, e.g. zlib_1.2.11-3_x86-windows[-static].list\n    local infofile = find_file(format(\"%s_*_%s.list\", name, triplet), infodirs)\n    if not infofile then\n        return\n    end\n    local installdir = path.directory(path.directory(path.directory(infofile)))\n\n    -- save includedirs, linkdirs and links\n    local result = nil\n    local pkgconfig_files = {}\n    local info = io.readfile(infofile)\n    if info then\n        for _, line in ipairs(info:split('\\n')) do\n            line = line:trim()\n            if plat == \"windows\" then\n                line = line:lower()\n            end\n\n            -- get pkgconfig files\n            if line:find(triplet .. (mode == \"debug\" and \"/debug\" or \"\") .. \"/lib/pkgconfig/\", 1, true) and line:endswith(\".pc\") then\n                table.insert(pkgconfig_files, line)\n            end\n\n            -- get includedirs\n            if line:endswith(\"/include/\") then\n                result = result or {}\n                result.includedirs = result.includedirs or {}\n                table.insert(result.includedirs, path.join(installdir, line))\n            end\n\n            -- get linkdirs and links\n            if (plat == \"windows\" and line:endswith(\".lib\")) or line:endswith(\".a\") or line:endswith(\".so\") then\n                if line:find(triplet .. (mode == \"debug\" and \"/debug\" or \"\") .. \"/lib/\", 1, true) then\n                    result = result or {}\n                    result.links = result.links or {}\n                    result.linkdirs = result.linkdirs or {}\n                    result.libfiles = result.libfiles or {}\n                    table.insert(result.linkdirs, path.join(installdir, path.directory(line)))\n                    table.insert(result.links, target.linkname(path.filename(line), {plat = plat}))\n                    table.insert(result.libfiles, path.join(installdir, path.directory(line), path.filename(line)))\n                end\n            end\n\n            -- add shared library directory (/bin/) to linkdirs for running with PATH on windows\n            if plat == \"windows\" and line:endswith(\".dll\") then\n                if line:find(plat .. (mode == \"debug\" and \"/debug\" or \"\") .. \"/bin/\", 1, true) then\n                    result = result or {}\n                    result.linkdirs = result.linkdirs or {}\n                    result.libfiles = result.libfiles or {}\n                    table.insert(result.linkdirs, path.join(installdir, path.directory(line)))\n                    table.insert(result.libfiles, path.join(installdir, path.directory(line), path.filename(line)))\n                end\n            end\n        end\n    end\n\n    -- find result from pkgconfig first\n    if #pkgconfig_files > 0 then\n        local pkgconfig_result = _find_package_from_pkgconfig(pkgconfig_files, {installdir = installdir, linkdirs = result and result.linkdirs})\n        if pkgconfig_result then\n            result = pkgconfig_result\n        end\n    end\n\n    return result\nend\n\nfunction _find_package(vcpkg, vcpkgdir, name, opt)\n\n    -- get configs\n    local configs = opt.configs or {}\n\n    -- is need manifest mode?\n    local manifest_mode = vcpkg_utils.need_manifest(opt)\n\n    -- manifest mode requires installdir to run vcpkg commands in the context of the manifest\n    if manifest_mode and not opt.installdir then\n        raise(\"installdir is required for manifest mode!\")\n    end\n\n    -- extract required features from both package name and configs.features.\n    local required_features = _required_features(name, configs)\n\n    -- fix name, e.g. ffmpeg[x264] as ffmpeg\n    -- @see https://github.com/xmake-io/xmake/issues/925\n    name = name:gsub(\"%[.-%]\", \"\")\n\n    -- init triplet\n    local arch = opt.arch\n    local plat = opt.plat\n    local mode = opt.mode\n    plat = configurations.plat(plat)\n    arch = configurations.arch(arch)\n    local triplet = configurations.triplet(configs, plat, arch)\n\n    -- get the vcpkg info directories\n    local infodirs = {}\n\tif manifest_mode then\n        table.join2(infodirs, path.join(opt.installdir, \"vcpkg_installed\", \"vcpkg\", \"info\"))\n    else\n        table.join2(infodirs, path.join(vcpkgdir, \"installed\", \"vcpkg\", \"info\"))\n\tend\n\n    -- find the package info file, e.g. zlib_1.2.11-3_x86-windows[-static].list\n    local infofile = find_file(format(\"%s_*_%s.list\", name, triplet), infodirs)\n    if not infofile then\n        return\n    end\n\n    -- check that required features are installed\n    -- @see https://github.com/xmake-io/xmake/issues/7388\n    if required_features and not vcpkg_utils.has_installed_features(vcpkg, name, triplet, required_features, opt) then\n        return\n    end\n\n    -- find dependency package\n    -- pass features to depend-info to get the complete dependency tree\n    -- e.g. curl[mbedtls] needs mbedtls libraries\n    -- @see https://github.com/xmake-io/xmake/issues/7388\n    local depend_name = name\n    if required_features then\n        depend_name = name .. \"[\" .. table.concat(required_features, \",\") .. \"]\"\n    end\n    local result = nil\n    local argv = {\"depend-info\", depend_name, \"--sort=reverse\", \"--triplet=\" .. triplet}\n\n    -- pass feature flags to depend-info when in manifest mode, otherwise depend-info will not show the complete dependency tree with features\n    if manifest_mode then\n        table.insert(argv, 1, \"--feature-flags=versions\")\n    end\n\n    local _, dependinfo = try { function () return os.iorunv(vcpkg, argv, manifest_mode and {curdir = opt.installdir} or nil) end }\n    if dependinfo then\n        for _, line in ipairs(dependinfo:split(\"\\n\", {plain = true})) do\n            if not line:startswith(\"vcpkg-\") then\n                local packagename = line:match(\"^([^%[:]+)[^:]*:\")\n                if packagename then\n                    local dependencyresult = _get_package_info(packagename, triplet, infodirs, arch, plat, mode)\n                    if dependencyresult then\n                        result = result or {}\n                        for key, dependencylist in pairs(dependencyresult) do\n                            result[key] = result[key] or {}\n                            table.join2(result[key], dependencylist)\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- save version\n    if result then\n        local infoname = path.basename(infofile)\n        local prefix = name\n        -- name maybe contains lua pattern characters, we need escape it. e.g. `-`\n        prefix = prefix:gsub(\"([%+%.%-%^%$%(%)%%])\", \"%%%1\")\n        result.version = infoname:match(prefix .. \"_(%d+%.?%d*%.?%d*.-)_\" .. arch)\n        if not result.version then\n            result.version = infoname:match(prefix .. \"_(%d+%.?%d*%.-)_\" .. arch)\n        end\n    end\n\n    -- remove repeat\n    if result then\n        for k, v in pairs(result) do\n            if k == \"links\" or k == \"syslinks\" or k == \"frameworks\" then\n                result[k] = table.unwrap(table.reverse_unique(v))\n            else\n                result[k] = table.unwrap(table.unique(v))\n            end\n        end\n    end\n    return result\nend\n\n-- find package from the vcpkg package manager\n--\n-- @param name  the package name, e.g. zlib, pcre\n-- @param opt   the options, e.g. {verbose = true)\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local vcpkgdir = find_vcpkgdir()\n    if not vcpkgdir then\n\n        -- we need show warning if we do not try finding package and vcpkg root directory not found.\n        if not opt.try then\n            wprint(\"vcpkg root directory not found, maybe you need set $VCPKG_ROOT!\")\n        end\n        return\n    end\n\n    -- attempt to find vcpkg\n    local vcpkg = find_tool(\"vcpkg\")\n    if not vcpkg then\n        raise(\"vcpkg not found!\")\n    end\n\n    -- do find package\n    return _find_package(vcpkg.program, vcpkgdir, name, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/vcpkg/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\nimport(\"package.manager.vcpkg.configurations\")\nimport(\"package.manager.vcpkg.utils\", {alias = \"vcpkg_utils\"})\n\n-- install for classic mode\nfunction _install_for_classic(vcpkg, name, opt)\n\n    -- get configs\n    local configs = opt.configs or {}\n\n    -- init triplet\n    local arch = opt.arch\n    local plat = opt.plat\n    plat = configurations.plat(plat)\n    arch = configurations.arch(arch)\n    local triplet = configurations.triplet(configs, plat, arch)\n\n    -- init argv\n    local argv = {\"install\", name .. \":\" .. triplet}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"--debug\")\n    end\n\n    -- check if the base package is already installed with different features,\n    -- if so, prompt user before rebuilding with --recurse\n    -- @see https://github.com/xmake-io/xmake/issues/7388\n    local basename = name:gsub(\"%[.-%]\", \"\")\n    if basename ~= name then\n        if not vcpkg_utils.is_installed(vcpkg, name, triplet, opt) then\n            if vcpkg_utils.is_installed(vcpkg, basename, triplet, opt) then\n                local confirm = utils.confirm({default = true,\n                    description = format(\"%s:%s is already installed (possibly with different features). Installing %s will require a rebuild of it and its dependencies. Continue?\", basename, triplet, name)})\n                if confirm then\n                    table.insert(argv, \"--recurse\")\n                else\n                    raise(\"install %s:%s cancelled!\", name, triplet)\n                end\n            end\n        end\n    end\n\n    -- install package\n    os.vrunv(vcpkg, argv)\nend\n\n-- install for manifest mode\nfunction _install_for_manifest(vcpkg, name, opt)\n\n    -- get configs\n    local configs = opt.configs or {}\n\n    -- init triplet\n    local arch = opt.arch\n    local plat = opt.plat\n    plat = configurations.plat(plat)\n    arch = configurations.arch(arch)\n    local triplet = configurations.triplet(configs, plat, arch)\n\n    -- init argv\n    local argv = {\"--feature-flags=\\\"versions\\\"\", \"install\", \"--x-wait-for-lock\", \"--triplet\", triplet}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"--debug\")\n    end\n\n    -- generate platform\n    local platform = plat .. \" & \" .. arch\n\n    -- generate dependencies\n    local require_version = opt.require_version\n    if require_version == \"latest\" then\n        require_version = nil\n    end\n    local minversion = require_version\n    if minversion and minversion:startswith(\">=\") then\n        minversion = minversion:sub(3)\n    end\n    local dependencies = {}\n    table.insert(dependencies, {\n        name = name,\n        [\"version>=\"] = minversion,\n        platform = platform,\n        features = configs.features,\n        [\"default-features\"] = configs.default_features})\n\n    -- generate overrides to use fixed version\n    local overrides\n    if require_version and semver.is_valid(require_version) then\n        overrides = {{name = name, version = require_version}}\n    end\n\n    -- generate manifest, vcpkg.json\n    local baseline = configs.baseline or \"2e6fcc44573d091af0321f99c89b212997a76f1f\" -- 2025.09.27\n    local manifest = {\n        name = \"stub\",\n        version = \"1.0\",\n        dependencies = dependencies,\n        [\"builtin-baseline\"] = baseline,\n        overrides = overrides}\n    local installdir = assert(opt.installdir, \"installdir not found!\")\n    json.savefile(path.join(installdir, \"vcpkg.json\"), manifest)\n    if not os.isdir(installdir) then\n        os.mkdir(installdir)\n    end\n    if option.get(\"diagnosis\") then\n        vprint(path.join(installdir, \"vcpkg.json\"))\n        vprint(manifest)\n    end\n\n    -- generate vcpkg-configuration.json\n    -- @see https://github.com/xmake-io/xmake/issues/2469\n    if configs.registries or configs.default_registries then\n        local configuration = {registries = configs.registries, [\"default-registries\"] = configs.default_registries}\n        json.savefile(path.join(installdir, \"vcpkg-configuration.json\"), configuration)\n    end\n\n    -- install package\n    os.vrunv(vcpkg, argv, {curdir = installdir})\nend\n\n-- install package\n--\n-- @param name  the package name, e.g. pcre2, pcre2/libpcre2-8\n-- @param opt   the options, e.g. {verbose = true}\n--\nfunction main(name, opt)\n\n    -- attempt to find vcpkg\n    local vcpkg = find_tool(\"vcpkg\")\n    if not vcpkg then\n        raise(\"vcpkg not found!\")\n    end\n\n    -- do install\n    opt = opt or {}\n    if vcpkg_utils.need_manifest(opt) then\n        _install_for_manifest(vcpkg.program, name, opt)\n    else\n        _install_for_classic(vcpkg.program, name, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/vcpkg/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search package using the vcpkg package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n\n    -- attempt to find vcpkg\n    local vcpkg = find_tool(\"vcpkg\")\n    if not vcpkg then\n        raise(\"vcpkg not found!\")\n    end\n\n    -- search packages\n    local results = {}\n    local searchdata = os.iorunv(vcpkg.program, {\"search\", name})\n    for _, line in ipairs(searchdata:split(\"\\n\", {plain = true})) do\n        local version\n        local splitinfo = line:split(\"%s+\", {limit = 2})\n        local packagename = splitinfo[1]\n        local description = splitinfo[2]\n        if description then\n            splitinfo = description:split(\"%s+\", {limit = 2})\n            if #splitinfo == 2 and splitinfo[1]:find('.', 1, true) then\n                version = splitinfo[1]\n                description = splitinfo[2]\n            end\n        end\n        if packagename:find(name) and not packagename:find('%[.*' .. name .. '.*%]') then\n            table.insert(results, {name = \"vcpkg::\" .. packagename, version = version, description = description})\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/vcpkg/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- check if a package (with optional features) is installed for the given triplet\n-- e.g. is_installed(vcpkg, \"curl\", \"x64-windows-static-md\", opt)\n--      is_installed(vcpkg, \"curl[mbedtls]\", \"x64-windows-static-md\", opt)\n--\n-- @see https://github.com/xmake-io/xmake/issues/7388\n--\n\nfunction need_manifest(opt)\n    local require_version = opt.require_version\n    if require_version ~= nil and require_version ~= \"latest\" then\n        return true\n    end\n    local configs = opt.configs\n    if configs and (configs.features or configs.default_features == false or configs.baseline) then\n        return true\n    end\nend\n\nfunction is_installed(vcpkg, name, triplet, opt)\n    local argv = {\"list\", name .. \":\" .. triplet, \"--x-full-desc\"}\n    local manifest_mode = need_manifest(opt)\n\n    -- pass feature flags to depend-info when in manifest mode, otherwise depend-info will not show the complete dependency tree with features\n    if manifest_mode then\n        table.insert(argv, 1, \"--feature-flags=versions\")\n    end\n\n    local listinfo = try { function ()\n        return os.iorunv(vcpkg, argv, manifest_mode and {curdir = opt.installdir} or nil)\n    end}\n    if listinfo then\n        local exact_prefix = name .. \":\" .. triplet\n        for _, line in ipairs(listinfo:split(\"\\n\", {plain = true})) do\n            local first = line:split(\"%s\")[1]\n            if first == exact_prefix then\n                return true\n            end\n        end\n    end\n    return false\nend\n\n-- check if all required features are installed\n-- e.g. has_installed_features(vcpkg, \"curl\", \"x64-windows-static-md\", {\"openssl\", \"mbedtls\"})\n--\n-- @see https://github.com/xmake-io/xmake/issues/7388\n--\nfunction has_installed_features(vcpkg, name, triplet, required_features, opt)\n    for _, feature in ipairs(required_features) do\n        if not is_installed(vcpkg, name .. \"[\" .. feature .. \"]\", triplet, opt) then\n            return false\n        end\n    end\n    return true\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/xmake/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.option\")\nimport(\"core.project.target\")\nimport(\"core.package.package\")\nimport(\"core.language.language\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_library\")\n\n-- deduplicate values\nfunction _deduplicate_values(values)\n    for _, k in ipairs(table.keys(values)) do\n        local v = values[k]\n        if type(v) == \"table\" then\n            if k == \"links\" or k == \"syslinks\" or k == \"frameworks\" then\n                values[k] = table.reverse_unique(v)\n            else\n                values[k] = table.unique(v)\n            end\n        end\n    end\nend\n\n-- find package from the repository (maybe only include and no links)\nfunction _find_package_from_repo(name, opt)\n\n    -- check options\n    if not opt.require_version or not opt.buildhash then\n        return\n    end\n\n    -- find the manifest file of package, e.g. ~/.xmake/packages/z/zlib/1.1.12/ed41d5327fad3fc06fe376b4a94f62ef/manifest.txt\n    local packagedirs = {}\n    if opt.installdir then\n        table.insert(packagedirs, opt.installdir)\n    else\n        table.insert(packagedirs, path.join(package.installdir(), name:lower():sub(1, 1), name:lower(), opt.require_version, opt.buildhash))\n    end\n    local manifest_file = find_file(\"manifest.txt\", packagedirs)\n    if not manifest_file then\n        return\n    end\n\n    -- load manifest info\n    local manifest = io.load(manifest_file)\n    if not manifest then\n        return\n    end\n\n    -- get manifest variables\n    local vars = manifest.vars or {}\n\n    -- get install directory of this package\n    local installdir = path.directory(manifest_file)\n\n    -- save includedirs to result (maybe only include and no links)\n    local result = {}\n    local includedirs = {}\n    for _, includedir in ipairs(vars.includedirs) do\n        table.insert(includedirs, path.join(installdir, includedir))\n    end\n    if #includedirs == 0 and os.isdir(path.join(installdir, \"include\")) then\n        table.insert(includedirs, path.join(installdir, \"include\"))\n    end\n    if #includedirs > 0 then\n        result.includedirs = table.unique(includedirs)\n    end\n\n    -- get links and link directories\n    local links = {}\n    local linkdirs = {}\n    local components = opt.components\n    if vars.links then\n        table.join2(links, vars.links)\n    elseif components and manifest.components then\n        -- get links from components\n        local vars = manifest.components.vars\n        if vars then\n            for _, component_name in ipairs(components) do\n                local component_vars = vars[component_name]\n                if component_vars and component_vars.links then\n                    table.join2(links, component_vars.links)\n                end\n            end\n        end\n        links = table.reverse_unique(links)\n    else\n        -- we scan links automatically\n        local symrefs = {}\n        local libfiles = {}\n        for _, libdir in ipairs(vars.linkdirs or \"lib\") do\n            for _, file in ipairs(os.files(path.join(installdir, libdir, \"*\"))) do\n                table.insert(libfiles, file)\n                if os.islink(file) then\n                    local reallink = os.readlink(file)\n                    if reallink then\n                        symrefs[reallink] = file\n                    end\n                end\n            end\n        end\n        local found = false\n        for _, file in ipairs(libfiles) do\n            if file:endswith(\".lib\") or file:endswith(\".a\") then\n                found = true\n                table.insert(links, target.linkname(path.filename(file), {plat = opt.plat}))\n            end\n        end\n        if not found then\n            for _, file in ipairs(libfiles) do\n                -- if this library file has been referenced (libfoo.so.1), e.g. libfoo.so -> libfoo.so.1,\n                -- we need ignore it and only use -lfoo\n                local filename = path.filename(file)\n                if not symrefs[filename] then\n                    if file:endswith(\".so\") or file:match(\".+%.so%..+$\") or file:endswith(\".dylib\") then\n                        table.insert(links, target.linkname(path.filename(file), {plat = opt.plat}))\n                    end\n                end\n            end\n        end\n    end\n    if #links > 0 then\n        for _, libdir in ipairs(vars.linkdirs or \"lib\") do\n            table.insert(linkdirs, path.join(installdir, libdir))\n        end\n    end\n\n    -- get libfiles\n    local libfiles = {}\n    for _, libdir in ipairs(vars.linkdirs or \"lib\") do\n        for _, file in ipairs(os.files(path.join(installdir, libdir, \"*\"))) do\n            if file:endswith(\".lib\") or file:endswith(\".a\") then\n                result.static = true\n                table.insert(libfiles, file)\n            end\n        end\n        for _, file in ipairs(os.files(path.join(installdir, libdir, \"*\"))) do\n            if file:endswith(\".so\") or file:match(\".+%.so%..+$\") or file:endswith(\".dylib\") or file:endswith(\"*.dll\") then\n                result.shared = true\n                table.insert(libfiles, file)\n            end\n        end\n    end\n    if opt.plat == \"windows\" or opt.plat == \"mingw\" then\n        local bindirs = opt.bindirs or \"bin\"\n        for _, bindir in ipairs(bindirs) do\n            for _, file in ipairs(os.files(path.join(installdir, bindir, \"*.dll\"))) do\n                result.shared = true\n                table.insert(libfiles, file)\n            end\n        end\n        -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242513463\n        if not result.shared then\n            for _, file in ipairs(os.files(path.join(installdir, \"**.dll\"))) do\n                result.shared = true\n                table.insert(libfiles, file)\n            end\n        end\n    end\n\n    -- add root link directories\n    if #linkdirs == 0 then\n        table.insert(linkdirs, path.join(installdir, \"lib\"))\n    end\n\n    -- uses name as links directly e.g. libname.a\n    if #links == 0 then\n        links = table.wrap(name)\n    end\n\n    -- find library\n    for _, link in ipairs(links) do\n        local libinfo = find_library(link, linkdirs, {plat = opt.plat})\n        if libinfo then\n            if libinfo.kind == \"shared\" then\n                result.shared = true\n            end\n            if libinfo.kind == \"static\" then\n                result.static = true\n            end\n            result.links    = table.join(result.links or {}, libinfo.link)\n            result.linkdirs = table.join(result.linkdirs or {}, libinfo.linkdir)\n            result.libfiles = table.join(result.libfiles or {}, path.join(libinfo.linkdir, libinfo.filename))\n        end\n    end\n    if result.libfiles then\n        result.libfiles = table.join(result.libfiles, libfiles)\n    end\n\n    -- inherit the other prefix variables\n    local components_base = {includedirs = table.clone(result.includedirs), linkdirs = table.clone(result.linkdirs)}\n    for name, values in pairs(vars) do\n        if name ~= \"links\" and name ~= \"linkdirs\" and name ~= \"includedirs\" then\n            result[name] = values\n            components_base[name] = table.clone(values)\n        end\n    end\n\n    -- get component values\n    if components and manifest.components then\n        local vars = manifest.components.vars\n        if vars then\n            _deduplicate_values(components_base)\n            result.components = result.components or {}\n            result.components.__base = components_base\n            for _, component_name in ipairs(components) do\n                local comp = vars[component_name]\n                if comp then\n                    result.components[component_name] = comp\n\n                    -- merge component values to root\n                    for k, v in pairs(comp) do\n                        if k ~= \"links\" then\n                            result[k] = table.join(result[k] or {}, v)\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- deduplicate result\n    _deduplicate_values(result)\n\n    -- update the project references file\n    local projectdir = os.projectdir()\n    if projectdir and os.isdir(projectdir) then\n        local references_file = path.join(installdir, \"references.txt\")\n        local references = os.isfile(references_file) and io.load(references_file) or {}\n        references[projectdir] = os.date(\"%y%m%d\")\n        io.save(references_file, references)\n    end\n\n    -- get version and license\n    result.version = manifest.version or path.filename(path.directory(path.directory(manifest_file)))\n    result.license = manifest.license\n    result.extras  = manifest.extras\n    return result\nend\n\n-- find package from the package directories\nfunction _find_package_from_packagedirs(name, opt)\n\n    -- get package path (e.g. name.pkg) in the package directories\n    local packagepath = nil\n    for _, dir in ipairs(table.wrap(opt.packagedirs)) do\n        local p = path.join(dir, name .. \".pkg\")\n        if os.isdir(p) then\n            packagepath = p\n            break\n        end\n    end\n    if not packagepath then\n        return\n    end\n\n    -- get package file (e.g. name.pkg/xmake.lua)\n    local packagefile = path.join(packagepath, \"xmake.lua\")\n    if not os.isfile(packagefile) then\n        return\n    end\n\n    -- init interpreter\n    local interp = option.interpreter()\n\n    -- register filter handler\n    interp:filter():register(\"find_package\", function (variable)\n        local maps = {\n            arch = opt.arch\n        ,   plat = opt.plat\n        ,   mode = opt.mode\n        }\n        return maps[variable]\n    end)\n\n    -- load script\n    local ok, errors = interp:load(packagefile)\n    if not ok then\n        raise(errors)\n    end\n\n    -- load the package from the the package file\n    local packageinfos, errors = interp:make(\"option\", true, true)\n    if not packageinfos then\n        raise(errors)\n    end\n\n    -- unregister filter handler\n    interp:filter():register(\"find_package\", nil)\n\n    -- get package info\n    local packageinfo = packageinfos[name]\n    if not packageinfo then\n        return\n    end\n\n    -- get linkdirs\n    local linkdirs = {}\n    for _, linkdir in ipairs(packageinfo:get(\"linkdirs\")) do\n        table.insert(linkdirs, path.join(packagepath, linkdir))\n    end\n    if #linkdirs == 0 then\n        return\n    end\n\n    -- find library\n    local result = nil\n    for _, link in ipairs(packageinfo:get(\"links\")) do\n        local libinfo = find_library(link, linkdirs, {plat = opt.plat})\n        if libinfo then\n            result          = result or {}\n            result.links    = table.join(result.links or {}, libinfo.link)\n            result.linkdirs = table.join(result.linkdirs or {}, libinfo.linkdir)\n            result.libfiles = table.join(result.libfiles or {}, path.join(libinfo.linkdir, libinfo.filename))\n        end\n    end\n\n    -- inherit other package info\n    if result then\n        result.includedirs = {}\n        for _, includedir in ipairs(packageinfo:get(\"includedirs\")) do\n            table.insert(result.includedirs, path.join(packagepath, includedir))\n        end\n        for _, infoname in ipairs({\"defines\", \"languages\", \"warnings\"}) do\n            result[infoname] = packageinfo:get(infoname)\n        end\n    end\n    return result\nend\n\n-- find package using the xmake package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.x\", buildhash = \"xxxxxx\")\n--\nfunction main(name, opt)\n\n    -- find package from repository\n    local result = _find_package_from_repo(name, opt)\n\n    -- find package from the given package directories, e.g. packagedir/xxx.pkg\n    if not result and opt.packagedirs then\n        result = _find_package_from_packagedirs(name, opt)\n    end\n\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/xmake/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"private.xrepo.quick_search.cache\")\n\nfunction _search_package(packages, name, opt)\n    for _, packageinfo in ipairs(cache.find(name, {description = opt.description ~= false})) do\n        local packagename = packageinfo.name\n        local packagedata = packageinfo.data\n\n        local version\n        local versions = packagedata.versions\n        if versions then\n            versions = table.copy(versions)\n            table.sort(versions, function (a, b) return semver.compare(a, b) > 0 end)\n            if opt.require_version then\n                for _, ver in ipairs(versions) do\n                    if semver.satisfies(ver, opt.require_version) then\n                        version = ver\n                    end\n                end\n            else\n                version = versions[1]\n            end\n        end\n\n        local description = packagedata.description\n        if description then\n            description = description:gsub(string.ipattern(name), function (w)\n                return \"${bright}\" .. w .. \"${clear}\"\n            end)\n        end\n\n        if not opt.require_version or version then\n            packages[packagename] = {name = packagename, version = version, description = description, reponame = packagedata.reponame}\n        end\n    end\nend\n\n-- search package using the xmake package manager\n--\n-- @param name  the package name with pattern\n-- @param opt   the options, e.g. {require_version = \"1.x\"}\n--\nfunction main(name, opt)\n    opt = opt or {}\n    local packages = {}\n    _search_package(packages, name, opt)\n\n    local results = {}\n    for name, info in table.orderpairs(packages) do\n        table.insert(results, info)\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/yum/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"privilege.sudo\")\n\n-- install package\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, yum = \"the package name\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- find yum\n    local yum = find_tool(\"yum\")\n    if not yum then\n        raise(\"yum not found!\")\n    end\n\n    -- init argv\n    local argv = {\"install\", \"-y\", opt.yum or name}\n\n    -- install package directly if the current user is root\n    if os.isroot() then\n        os.vrunv(yum.program, argv)\n    -- install with administrator permission?\n    elseif sudo.has() then\n\n        -- install it if be confirmed\n        local description = format(\"try installing %s with administrator permission\", name)\n        local confirm = utils.confirm({default = true, description = description})\n        if confirm then\n            sudo.vrunv(yum.program, argv)\n        end\n    else\n        raise(\"cannot get administrator permission!\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/zypper/find_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Lingfeng Fu\n-- @file        find_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.target\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.core.base.is_cross\")\nimport(\"package.manager.pkgconfig.find_package\", { alias = \"find_package_from_pkgconfig\" })\n\n-- find package\nfunction _find_package(rpm, name, opt)\n    if opt.require_version and opt.require_version ~= \"latest\" then\n        name = name .. '-' .. opt.require_version:gsub('%.', '_')\n    end\n    local result = nil\n    local pkgconfig_files = {}\n    local listinfo = try { function()\n        return os.iorunv(rpm.program, { \"-ql\", name })\n    end }\n    if listinfo then\n        for _, line in ipairs(listinfo:split('\\n', { plain = true })) do\n            line = line:trim()\n\n            -- get includedirs\n            local pos = line:find(\"include/\", 1, true)\n            if pos then\n                -- we don't need to add includedirs, gcc/clang will use /usr/ as default sysroot\n                result = result or {}\n            end\n\n            -- get pc files\n            if line:find(\"/pkgconfig/\", 1, true) and line:endswith(\".pc\") then\n                table.insert(pkgconfig_files, line)\n            end\n\n            -- get linkdirs and links\n            if line:endswith(\".a\") or line:endswith(\".so\") then\n                result = result or {}\n                result.links = result.links or {}\n                result.linkdirs = result.linkdirs or {}\n                result.libfiles = result.libfiles or {}\n                table.insert(result.linkdirs, path.directory(line))\n                table.insert(result.links, target.linkname(path.filename(line), { plat = opt.plat }))\n                table.insert(result.libfiles, path.join(path.directory(line), path.filename(line)))\n            end\n        end\n    end\n\n    -- we iterate over each pkgconfig file to extract the required data\n    local foundpc = false\n    local pcresult = { includedirs = {}, linkdirs = {}, links = {} }\n    for _, pkgconfig_file in ipairs(pkgconfig_files) do\n        local pkgconfig_dir = path.directory(pkgconfig_file)\n        local pkgconfig_name = path.basename(pkgconfig_file)\n        local pcinfo = find_package_from_pkgconfig(pkgconfig_name, { configdirs = pkgconfig_dir, linkdirs = linkdirs })\n\n        -- the pkgconfig file has been parse successfully\n        if pcinfo then\n            for _, includedir in ipairs(pcinfo.includedirs) do\n                table.insert(pcresult.includedirs, includedir)\n            end\n            for _, linkdir in ipairs(pcinfo.linkdirs) do\n                table.insert(pcresult.linkdirs, linkdir)\n            end\n            for _, link in ipairs(pcinfo.links) do\n                table.insert(pcresult.links, link)\n            end\n            -- version should be the same if a pacman package contains multiples .pc\n            pcresult.version = pcinfo.version\n            foundpc = true\n        end\n    end\n    if foundpc then\n        pcresult.includedirs = table.unique(pcresult.includedirs)\n        pcresult.linkdirs = table.unique(pcresult.linkdirs)\n        pcresult.links = table.reverse_unique(pcresult.links)\n        result = pcresult\n    end\n\n    -- meta/alias package? e.g. libboost_headers-devel -> libboost_headers1_82_0-devel\n    -- @see https://github.com/xmake-io/xmake/issues/1786\n    if not result then\n        local statusinfo = try { function()\n            return os.iorunv(rpm.program, { \"-qR\", name })\n        end }\n        if statusinfo then\n            for _, line in ipairs(statusinfo:split(\"\\n\", { plain = true })) do\n                -- parse depends, e.g. Depends: libboost1.74-dev\n                if not line:startswith(\"rpmlib(\") then\n                    local depends = line\n                    result = _find_package(rpm, depends, opt)\n                    if result then\n                        return result\n                    end\n                end\n            end\n        end\n    end\n\n    -- remove repeat\n    if result then\n        if result.links then\n            result.links = table.unique(result.links)\n        end\n        if result.linkdirs then\n            result.linkdirs = table.unique(result.linkdirs)\n        end\n        if result.includedirs then\n            result.includedirs = table.unique(result.includedirs)\n        end\n    end\n    return result\nend\n\n-- find package using the rpm package manager\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, version = \"1.12.0\")\n--\nfunction main(name, opt)\n    opt = opt or {}\n    if is_cross(opt.plat, opt.arch) then\n        return\n    end\n    local rpm = find_tool(\"rpm\")\n    if not rpm then\n        return\n    end\n    return _find_package(rpm, name, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/zypper/install_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Lingfeng Fu\n-- @file        install_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"privilege.sudo\")\n\n-- install package\n--\n-- @param name  the package name\n-- @param opt   the options, e.g. {verbose = true, apt = \"the package name\"}\n--\n-- @return      true or false\n--\nfunction main(name, opt)\n\n    -- init options\n    opt = opt or {}\n    if opt.require_version and opt.require_version ~= \"latest\" then\n        name = name .. '-' .. opt.require_version:gsub('%.', '_')\n    end\n\n    -- find apt\n    local zypper = find_tool(\"zypper\")\n    if not zypper then\n        raise(\"apt not found!\")\n    end\n\n    -- init argv\n    local argv = { \"install\", \"-y\", opt.zypper or name }\n\n    -- install package directly if the current user is root\n    if os.isroot() then\n        os.vrunv(zypper.program, argv)\n        -- install with administrator permission?\n    elseif sudo.has() then\n\n        -- install it if be confirmed\n        local description = format(\"try installing %s with administrator permission\", name)\n        local confirm = utils.confirm({ default = true, description = description })\n        if confirm then\n            sudo.vrunv(zypper.program, argv)\n        end\n    else\n        raise(\"cannot get administrator permission!\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/manager/zypper/search_package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Lingfeng Fu\n-- @file        search_package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- search package using the zypper package manager\n--\n-- @param name  the package name with pattern\n--\nfunction main(name)\n\n    -- find zypper\n    local zypper = find_tool(\"zypper\")\n    if not zypper then\n        raise(\"zypper not found!\")\n    end\n\n    -- search packages\n    --\n    --    | libboost_wave-devel     | Development headers for Boost.Wave library  | package\n    --\n    -- i  | libboost_wave-devel     | Development headers for Boost.Wave library  | package\n    --\n    -- i+ | libboost_headers-devel  | Development headers for Boost               | package\n    --\n    local results = {}\n    local searchdata = os.iorunv(zypper.program, { \"search\", name })\n    for _, line in ipairs(searchdata:split(\"\\n\", { plain = true })) do\n        if line:endswith(\"package\") then\n            local splitinfo = line:split(\"%s+|%s+\", { limit = 4 })\n            if not line:startswith(\" \") then\n                table.remove(splitinfo, 1)\n            end\n            local packagename = splitinfo[1]\n            local description = splitinfo[2]\n            table.insert(results, { name = \"zypper::\" .. packagename, version = version, description = description })\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/autoconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        autoconf.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.memcache\")\nimport(\"lib.detect.find_tool\")\nimport(\"devel.git\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- translate paths\nfunction _translate_paths(paths)\n    if paths and is_host(\"windows\") then\n        if type(paths) == \"string\" then\n            return path.unix(paths)\n        elseif type(paths) == \"table\" then\n            local result = {}\n            for _, p in ipairs(paths) do\n                table.insert(result, path.unix(p))\n            end\n            return result\n        end\n    end\n    return paths\nend\n\n-- translate cygwin paths\nfunction _translate_cygwin_paths(paths)\n    if type(paths) == \"string\" then\n        return path.cygwin(paths)\n    elseif type(paths) == \"table\" then\n        local result = {}\n        for _, p in ipairs(paths) do\n            table.insert(result, path.cygwin(p))\n        end\n        return result\n    end\n    return paths\nend\n\n-- translate windows bin path\nfunction _translate_windows_bin_path(bin_path)\n    if bin_path then\n        local argv = os.argv(bin_path)\n        argv[1] = path.unix(argv[1])\n        local path_lower = argv[1]:lower()\n        if not path_lower:endswith(\".exe\") and not path_lower:endswith(\".cmd\") and not path_lower:endswith(\".bat\") then\n            argv[1] = argv[1] .. \".exe\"\n        end\n        return os.args(argv)\n    end\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get msvc run environments\nfunction _get_msvc_runenvs(package)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- get memcache\nfunction _memcache()\n    return memcache.cache(\"package.tools.autoconf\")\nend\n\n-- has flag ?\nfunction _has_flag(package, flag)\n    local flag_name = flag:gsub(\"-\", \"\")\n    local has_flag = _memcache():get2(tostring(package), flag_name)\n    if has_flag == nil then\n        local result = try {function() return os.iorunv(\"./configure\", {\"--help\"}, {shell = true}) end}\n        if result and result:find(flag, 1, true) then\n            has_flag = true\n        end\n        has_flag = has_flag or false\n        _memcache():set2(tostring(package), flag_name, has_flag)\n    end\n    return has_flag\nend\n\n\n-- has `--with-pic`?\nfunction _has_with_pic(package)\n    return _has_flag(package, \"--with-pic\")\nend\n\n-- has `--enable-debug`?\nfunction _has_enable_debug(package)\n    return _has_flag(package, \"--enable-debug\")\nend\n\n-- has `--enable-static` and `--enable-shared`?\nfunction _has_enable_kind(package)\n    return _has_flag(package, \"--enable-static\") and _has_flag(package, \"--enable-shared\")\nend\n\n-- has `--disable-static` and `--disable-shared`?\nfunction _has_disable_kind(package)\n    return _has_flag(package, \"--disable-static\") and _has_flag(package, \"--disable-shared\")\nend\n\n-- get configs\nfunction _get_configs(package, configs)\n    local configs = configs or {}\n    table.insert(configs, \"--prefix=\" .. _translate_paths(package:installdir()))\n\n    if not configs.host then\n        if package:is_plat(\"iphoneos\", \"macosx\") and package:is_cross() then\n            local triples =\n            {\n                arm64  = \"aarch64-apple-darwin\",\n                arm64e = \"aarch64-apple-darwin\",\n                armv7  = \"armv7-apple-darwin\",\n                armv7s = \"armv7s-apple-darwin\",\n                i386   = \"i386-apple-darwin\",\n                x86_64 = \"x86_64-apple-darwin\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[package:arch()] or triples.arm64))\n        elseif package:is_plat(\"android\") then\n            -- @see https://developer.android.com/ndk/guides/other_build_systems#autoconf\n            local triples =\n            {\n                [\"armv5te\"]     = \"arm-linux-androideabi\",  -- deprecated\n                [\"armv7-a\"]     = \"arm-linux-androideabi\",  -- deprecated\n                [\"armeabi\"]     = \"arm-linux-androideabi\",  -- removed in ndk r17\n                [\"armeabi-v7a\"] = \"arm-linux-androideabi\",\n                [\"arm64-v8a\"]   = \"aarch64-linux-android\",\n                i386            = \"i686-linux-android\",     -- deprecated\n                x86             = \"i686-linux-android\",\n                x86_64          = \"x86_64-linux-android\",\n                mips            = \"mips-linux-android\",     -- removed in ndk r17\n                mips64          = \"mips64-linux-android\"    -- removed in ndk r17\n            }\n            table.insert(configs, \"--host=\" .. (triples[package:arch()] or triples[\"armeabi-v7a\"]))\n        elseif package:is_plat(\"mingw\") then -- we always add host for mingw\n            local triples =\n            {\n                i386   = \"i686-w64-mingw32\",\n                x86_64 = \"x86_64-w64-mingw32\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[package:arch()] or triples.i386))\n        elseif package:is_plat(\"linux\") and package:is_cross() then\n            local triples =\n            {\n                [\"arm64-v8a\"] = \"aarch64-linux-gnu\",\n                arm64 = \"aarch64-linux-gnu\",\n                i386   = \"i686-linux-gnu\",\n                x86_64 = \"x86_64-linux-gnu\",\n                armv7 = \"arm-linux-gnueabihf\",\n                mips = \"mips-linux-gnu\",\n                mips64 = \"mips64-linux-gnu\",\n                mipsel = \"mipsel-linux-gnu\",\n                mips64el = \"mips64el-linux-gnu\",\n                loong64 = \"loongarch64-linux-gnu\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[package:arch()] or triples.i386))\n        elseif package:is_plat(\"cross\") and package:targetos() then\n            local host = package:arch()\n            if package:is_arch(\"arm64\") then\n                host = \"aarch64\"\n            elseif package:is_arch(\"arm.*\") then\n                host = \"arm\"\n            end\n            host = host .. \"-\" .. package:targetos()\n            table.insert(configs, \"--host=\" .. host)\n        end\n    end\n    if not package:is_plat(\"windows\", \"mingw\") and\n        package:config(\"pic\") ~= false and _has_with_pic(package) then\n        table.insert(configs, \"--with-pic\")\n    end\n    if package:is_debug() and _has_enable_debug(package) then\n        table.insert(configs, \"--enable-debug\")\n    end\n    if package:is_library() then\n        if _has_enable_kind(package) then\n            table.insert(configs, \"--enable-shared=\" .. (package:config(\"shared\") and \"yes\" or \"no\"))\n            table.insert(configs, \"--enable-static=\" .. (package:config(\"shared\") and \"no\" or \"yes\"))\n        elseif _has_disable_kind(package) then\n            if package:config(\"shared\") then\n                table.insert(configs, \"--disable-static\")\n            else\n                table.insert(configs, \"--disable-shared\")\n            end\n        end\n    end\n    return configs\nend\n\n-- get cflags from package deps\nfunction _get_cflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    -- @see https://github.com/xmake-io/xmake-repo/pull/4973#issuecomment-2295890196\n    local result = {}\n    if values then\n        if values.defines then\n            table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"define\", values.defines))\n        end\n        if values.includedirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_compflags_for_package(package, \"cxx\", \"includedir\", values.includedirs)))\n        end\n        if values.sysincludedirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_compflags_for_package(package, \"cxx\", \"sysincludedir\", values.sysincludedirs)))\n        end\n    end\n    return result\nend\n\n-- get ldflags from package deps\nfunction _get_ldflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    local result = {}\n    if values then\n        if values.linkdirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"linkdir\", values.linkdirs)))\n        end\n        if values.links then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"link\", values.links))\n        end\n        if values.syslinks then\n            table.join2(result, _translate_paths(toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"syslink\", values.syslinks)))\n        end\n        if values.frameworks then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"framework\", values.frameworks))\n        end\n    end\n    return result\nend\n\n-- @see https://github.com/xmake-io/xmake/pull/6963\nfunction _apply_libtool_patch_for_cross(package, opt)\n    if not package:is_cross() or not os.isfile(\"libtool\") then\n        return\n    end\n\n    -- this patch is only needed for clang-based toolchains\n    if not package:has_tool(\"cxx\", \"clang\", \"clangxx\", \"zig_cc\") then\n        return\n    end\n\n    -- detect the version of generated libtool script\n    local libtool = io.readfile(\"libtool\")\n    local libtool_version = libtool:match(\"macro_version=(%d+%.%d+%.%d+)\")\n    if option.get(\"verbose\") then\n        if libtool_version then\n            cprint(\"${dim}> checking for generated libtool version ... ${color.success} %s\", libtool_version)\n        else\n            wprint(\"generated libtool version cannot be detected, the patch for cross-compilation cannot be applied.\")\n        end\n    end\n    if libtool_version then\n        libtool_version = semver.new(libtool_version)\n    else\n        return\n    end\n\n    if not libtool_version:at(\"2.4.3\", \"2.6.0\") then\n        return\n    end\n\n    -- load and parse patch list\n    local patch_dir = path.join(os.programdir(), \"scripts\", \"patches\", \"libtool\")\n    local loaded_patch_versions = {}\n    for _, patch_file in ipairs(os.files(path.join(patch_dir, \"*.patch\"))) do\n        local patch_version = path.filename(patch_file):rtrim(\".patch\")\n        table.insert(loaded_patch_versions, semver.new(patch_version))\n    end\n    table.sort(loaded_patch_versions)\n\n    -- select the suitable patch\n    local suitable_patch_versions = {}\n    local last_patch_version = nil\n    for _, patch_version in ipairs(loaded_patch_versions) do\n        if last_patch_version then\n            if libtool_version:at(last_patch_version, patch_version) then\n                -- some distributions (such as archlinux) may package the dev\n                -- version of libtool, in which case the next version of the \n                -- patch may be applicable.\n                table.insert(suitable_patch_versions, last_patch_version)\n                table.insert(suitable_patch_versions, patch_version)\n                break\n            end\n        else\n            if #loaded_patch_versions == 1 then\n                if libtool_version:ge(patch_version) then\n                    table.insert(suitable_patch_versions, patch_version)\n                end\n            end\n        end\n        last_patch_version = patch_version\n    end\n\n    -- try to apply the suitable patch\n    local succeed = false\n    for _, patch_version in ipairs(suitable_patch_versions) do\n        if option.get(\"verbose\") then\n            cprint(\"${dim}> try applying the patch ... ${color.success} >= %s\", patch_version)\n        end\n        local patch_file = path.join(patch_dir, patch_version:shortstr() .. \".patch\")\n        local result = try {\n            function ()\n                os.cp(\"libtool\", \"__xmake_patched_libtool\")\n                git.apply(patch_file)\n                os.mv(\"__xmake_patched_libtool\", \"libtool\")\n                return true\n            end\n        }\n        if result then\n            succeed = true\n            break\n        end\n    end\n\n    if option.get(\"verbose\") then\n        if succeed then\n            cprint(\"${dim}> libtool patch for cross-compilation applied successfully\")\n        else\n            wprint(\"unable to apply libtool cross-compilation patches, your build files were not modified.\")\n        end\n    end\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    opt = opt or {}\n    local envs = {}\n    local cross = false\n    local cflags, cxxflags, cppflags, asflags, ldflags, shflags, arflags\n    if not package:is_cross() and not package:config(\"toolchains\") then\n        cppflags = {}\n        cflags   = table.join(table.wrap(package:config(\"cxflags\")), package:config(\"cflags\"))\n        cxxflags = table.join(table.wrap(package:config(\"cxflags\")), package:config(\"cxxflags\"))\n        asflags  = table.copy(table.wrap(package:config(\"asflags\")))\n        ldflags  = table.copy(table.wrap(package:config(\"ldflags\")))\n        shflags  = table.copy(table.wrap(package:config(\"shflags\")))\n        if package:is_plat(\"linux\") and package:is_arch(\"i386\") then\n            table.insert(cflags,   \"-m32\")\n            table.insert(cxxflags, \"-m32\")\n            table.insert(asflags,  \"-m32\")\n            table.insert(ldflags,  \"-m32\")\n            table.insert(shflags,  \"-m32\")\n        end\n        table.join2(cflags,   opt.cflags)\n        table.join2(cflags,   opt.cxflags)\n        table.join2(cxxflags, opt.cxxflags)\n        table.join2(cxxflags, opt.cxflags)\n        table.join2(cppflags, opt.cppflags) -- @see https://github.com/xmake-io/xmake/issues/1688\n        table.join2(asflags,  opt.asflags)\n        table.join2(ldflags,  opt.ldflags)\n        table.join2(shflags,  opt.shflags)\n        table.join2(cflags,   _get_cflags_from_packagedeps(package, opt))\n        table.join2(cxxflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(cppflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(ldflags,  _get_ldflags_from_packagedeps(package, opt))\n        table.join2(shflags,  _get_ldflags_from_packagedeps(package, opt))\n    else\n        cross = true\n        cppflags = {}\n        cflags   = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cflags\"))\n        cxxflags = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cxxflags\"))\n        asflags  = table.copy(table.wrap(package:build_getenv(\"asflags\")))\n        ldflags  = table.copy(table.wrap(package:build_getenv(\"ldflags\")))\n        shflags  = table.copy(table.wrap(package:build_getenv(\"shflags\")))\n        arflags  = table.copy(table.wrap(package:build_getenv(\"arflags\")))\n        local defines        = package:build_getenv(\"defines\")\n        local includedirs    = package:build_getenv(\"includedirs\")\n        local sysincludedirs = package:build_getenv(\"sysincludedirs\")\n        local links          = package:build_getenv(\"links\")\n        local syslinks       = package:build_getenv(\"syslinks\")\n        local linkdirs       = package:build_getenv(\"linkdirs\")\n        table.join2(cflags,   opt.cflags)\n        table.join2(cflags,   opt.cxflags)\n        table.join2(cxxflags, opt.cxxflags)\n        table.join2(cxxflags, opt.cxflags)\n        table.join2(cppflags, opt.cppflags) -- @see https://github.com/xmake-io/xmake/issues/1688\n        table.join2(asflags,  opt.asflags)\n        table.join2(ldflags,  opt.ldflags)\n        table.join2(shflags,  opt.shflags)\n        table.join2(arflags,  opt.arflags)\n        table.join2(cflags,   _get_cflags_from_packagedeps(package, opt))\n        table.join2(cxxflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(cppflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(ldflags,  _get_ldflags_from_packagedeps(package, opt))\n        table.join2(cflags,   toolchain_utils.map_compflags_for_package(package, \"c\", \"define\", defines))\n        table.join2(cflags,   toolchain_utils.map_compflags_for_package(package, \"c\", \"includedir\", includedirs))\n        table.join2(cflags,   toolchain_utils.map_compflags_for_package(package, \"c\", \"sysincludedir\", sysincludedirs))\n        table.join2(asflags,  toolchain_utils.map_compflags_for_package(package, \"as\", \"define\", defines))\n        table.join2(asflags,  toolchain_utils.map_compflags_for_package(package, \"as\", \"includedir\", includedirs))\n        table.join2(asflags,  toolchain_utils.map_compflags_for_package(package, \"as\", \"sysincludedir\", sysincludedirs))\n        table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"define\", defines))\n        table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"includedir\", includedirs))\n        table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"sysincludedir\", sysincludedirs))\n        table.join2(ldflags,  toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"link\", links))\n        table.join2(ldflags,  toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"syslink\", syslinks))\n        table.join2(ldflags,  toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"linkdir\", linkdirs))\n        table.join2(shflags,  toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"link\", links))\n        table.join2(shflags,  toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"syslink\", syslinks))\n        table.join2(shflags,  toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"linkdir\", linkdirs))\n        envs.CC        = package:build_getenv(\"cc\")\n        envs.AS        = package:build_getenv(\"as\")\n        envs.AR        = package:build_getenv(\"ar\")\n        envs.LD        = package:build_getenv(\"ld\")\n        envs.LDSHARED  = package:build_getenv(\"sh\")\n        envs.CPP       = package:build_getenv(\"cpp\")\n        envs.RANLIB    = package:build_getenv(\"ranlib\")\n    end\n    if not package:is_plat(\"windows\", \"mingw\") and\n        package:config(\"pic\") ~= false and not _has_with_pic(package) then\n        table.insert(cflags, \"-fPIC\")\n        table.insert(cxxflags, \"-fPIC\")\n    end\n    if package:config(\"lto\") then\n        table.join2(cflags, package:_generate_lto_configs(\"cc\").cflags)\n        table.join2(cxxflags, package:_generate_lto_configs(\"cxx\").cxxflags)\n        table.join2(ldflags, package:_generate_lto_configs().ldflags)\n    end\n    local runtimes = package:runtimes()\n    if runtimes then\n        table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"runtime\", runtimes))\n        table.join2(ldflags, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"runtime\", runtimes))\n        table.join2(shflags, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"runtime\", runtimes))\n    end\n    if package:config(\"asan\") then\n        table.join2(cflags, package:_generate_sanitizer_configs(\"address\", \"cc\").cflags)\n        table.join2(cxxflags, package:_generate_sanitizer_configs(\"address\", \"cxx\").cxxflags)\n        table.join2(ldflags, package:_generate_sanitizer_configs(\"address\").ldflags)\n        table.join2(shflags, package:_generate_sanitizer_configs(\"address\").shflags)\n    end\n    if cflags then\n        envs.CFLAGS    = table.concat(_translate_paths(cflags), ' ')\n    end\n    if cxxflags then\n        envs.CXXFLAGS  = table.concat(_translate_paths(cxxflags), ' ')\n    end\n    if cppflags then\n        envs.CPPFLAGS  = table.concat(_translate_paths(cppflags), ' ')\n    end\n    if asflags then\n        envs.ASFLAGS   = table.concat(_translate_paths(asflags), ' ')\n    end\n    if arflags then\n        envs.ARFLAGS   = table.concat(_translate_paths(arflags), ' ')\n    end\n    if ldflags or shflags then\n        -- autoconf does not use SHFLAGS\n        envs.LDFLAGS   = table.concat(table.reverse_unique(_translate_paths(table.join(ldflags or {}, shflags))), ' ')\n    end\n\n    -- cross-compilation? pass the full build environments\n    if cross then\n        if package:is_plat(\"mingw\") then\n            -- fix linker error, @see https://github.com/xmake-io/xmake/issues/574\n            -- libtool: line 1855: lib: command not found\n            envs.ARFLAGS = nil\n            local ld = envs.LD\n            if ld then\n                if ld:endswith(\"x86_64-w64-mingw32-g++\") then\n                    envs.LD = path.join(path.directory(ld), is_host(\"windows\") and \"ld\" or \"x86_64-w64-mingw32-ld\")\n                elseif ld:endswith(\"i686-w64-mingw32-g++\") then\n                    envs.LD = path.join(path.directory(ld), is_host(\"windows\") and \"ld\" or \"i686-w64-mingw32-ld\")\n                end\n            end\n        else\n            if package:is_plat(\"macosx\") then\n                -- force to apply shflags on macosx https://gmplib.org/manual/Known-Build-Problems\n                envs.CC = envs.CC .. \" -arch \" .. package:arch()\n            end\n            -- android r27 will use llmv-ar instead of ar, https://github.com/xmake-io/xmake/issues/6206\n            if package:is_plat(\"cross\") or package:has_tool(\"ar\", \"ar\", \"emar\", \"llvm_ar\") then\n                -- only for cross-toolchain\n                envs.CXX = package:build_getenv(\"cxx\")\n                if not envs.ARFLAGS or envs.ARFLAGS == \"\" then\n                    envs.ARFLAGS = \"-cr\"\n                end\n            end\n        end\n\n        -- we should use ld as linker\n        --\n        -- @see\n        -- https://github.com/xmake-io/xmake-repo/pull/1043\n        -- https://github.com/libexpat/libexpat/issues/312\n        -- https://github.com/xmake-io/xmake/issues/2195\n        local ld = envs.LD\n        if ld and package:has_tool(\"ld\", \"clang\", \"clangxx\", \"gcc\", \"gxx\") then\n            local dir = path.directory(ld)\n            local name = path.filename(ld)\n            name = name:gsub(\"clang%+%+$\", \"ld\")\n            name = name:gsub(\"clang%+%+%-%d+\", \"ld\")\n            name = name:gsub(\"clang$\", \"ld\")\n            name = name:gsub(\"clang%-%d+\", \"ld\")\n            name = name:gsub(\"gcc$\", \"ld\")\n            name = name:gsub(\"gcc%-%d+$\", \"ld\")\n            name = name:gsub(\"g%+%+$\", \"ld\")\n            name = name:gsub(\"g%+%+%-%d+$\", \"ld\")\n            if dir and os.isfile(path.join(dir, name)) then\n                envs.LD = path.join(dir, name)\n            else\n                local ld = find_tool(\"ld\")\n                if ld and path.filename(ld.program) == name then\n                    envs.LD = ld.program\n                end\n            end\n        end\n        if ld and package:has_tool(\"ld\", \"zig_cc\") then\n            envs.LD = package:build_getenv(\"ld.lld\")\n        end\n        -- we need use clang++ as cxx, autoconf will use it as linker\n        -- https://github.com/xmake-io/xmake/issues/2170\n        local cxx = envs.CXX\n        if cxx and package:has_tool(\"cxx\", \"clang\", \"gcc\") then\n            local dir = path.directory(cxx)\n            local name = path.filename(cxx)\n            name = name:gsub(\"clang$\", \"clang++\")\n            name = name:gsub(\"clang%-\", \"clang++-\")\n            name = name:gsub(\"gcc$\", \"g++\")\n            name = name:gsub(\"gcc%-\", \"g++-\")\n            envs.CXX = dir and path.join(dir, name) or name\n        end\n    end\n    if package:is_plat(\"windows\") and not package:config(\"toolchains\") then\n        envs.PATH = os.getenv(\"PATH\") -- we need to reserve PATH on msys2\n        envs = os.joinenvs(envs, _get_msvc(package):runenvs())\n    end\n\n    if is_host(\"windows\") then\n        envs.CC       = _translate_windows_bin_path(envs.CC)\n        envs.CXX      = _translate_windows_bin_path(envs.CXX)\n        envs.AS       = _translate_windows_bin_path(envs.AS)\n        envs.AR       = _translate_windows_bin_path(envs.AR)\n        envs.LD       = _translate_windows_bin_path(envs.LD)\n        envs.LDSHARED = _translate_windows_bin_path(envs.LDSHARED)\n        envs.CPP      = _translate_windows_bin_path(envs.CPP)\n        envs.RANLIB   = _translate_windows_bin_path(envs.RANLIB)\n    end\n    local ACLOCAL_PATH = {}\n    local PKG_CONFIG_PATH = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n    end\n    -- some binary packages contain it too. e.g. libtool\n    for _, dep in ipairs(package:orderdeps()) do\n        local aclocal = path.join(dep:installdir(), \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            table.insert(ACLOCAL_PATH, aclocal)\n        end\n    end\n    envs.ACLOCAL_PATH = path.joinenv(ACLOCAL_PATH)\n    -- fix PKG_CONFIG_PATH for windows/msys2\n    -- @see https://github.com/xmake-io/xmake-repo/issues/3442\n    if package:is_plat(\"windows\") then\n        -- pkg-config can only support for unix path and env seperator on msys/cygwin\n        PKG_CONFIG_PATH = _translate_cygwin_paths(PKG_CONFIG_PATH)\n        envs.PKG_CONFIG_PATH = path.joinenv(PKG_CONFIG_PATH, \":\")\n    else\n        envs.PKG_CONFIG_PATH = path.joinenv(PKG_CONFIG_PATH)\n    end\n    return envs\nend\n\n-- get the autogen environments\nfunction autogen_envs(package, opt)\n    opt = opt or {}\n    local envs = {NOCONFIGURE = \"yes\"}\n    local ACLOCAL_PATH = {}\n    local PKG_CONFIG_PATH = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n    end\n    -- some binary packages contain it too. e.g. libtool\n    for _, dep in ipairs(package:orderdeps()) do\n        local aclocal = path.join(dep:installdir(), \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            table.insert(ACLOCAL_PATH, aclocal)\n        end\n    end\n    envs.ACLOCAL_PATH    = path.joinenv(ACLOCAL_PATH)\n    envs.PKG_CONFIG_PATH = path.joinenv(PKG_CONFIG_PATH)\n    return envs\nend\n\n-- configure package\nfunction configure(package, configs, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- generate configure file\n    if not os.isfile(\"configure\") then\n        if os.isfile(\"autogen.sh\") then\n            os.vrunv(\"./autogen.sh\", {}, {shell = true, envs = autogen_envs(package, opt)})\n        elseif os.isfile(\"configure.ac\") or os.isfile(\"configure.in\") then\n            local autoreconf = find_tool(\"autoreconf\")\n            assert(autoreconf, \"autoreconf not found!\")\n            os.vrunv(autoreconf.program, {\"--install\", \"--symlink\"}, {shell = true, envs = autogen_envs(package, opt)})\n        end\n    end\n\n    -- get envs\n    local envs = opt.envs or buildenvs(package, opt)\n\n    -- pass configurations\n    local argv = {}\n    for name, value in pairs(_get_configs(package, configs)) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, \"--\" .. name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- do configure\n    os.vrunv(\"./configure\", argv, {shell = true, envs = envs})\n\n    _apply_libtool_patch_for_cross(package, opt)\nend\n\n-- do make\nfunction make(package, argv, opt)\n    opt = opt or {}\n    local program\n    if package:is_plat(\"mingw\") and is_subhost(\"windows\") then\n        local mingw = assert(package:build_getenv(\"mingw\") or package:build_getenv(\"sdk\"), \"mingw not found!\")\n        program = path.join(mingw, \"bin\", \"mingw32-make.exe\")\n    else\n        local tool = find_tool(\"make\")\n        if tool then\n            program = tool.program\n        end\n    end\n    assert(program, \"make not found!\")\n\n    if package:is_plat(\"windows\") then\n        local envs = opt.envs or buildenvs(package, opt)\n        os.vrunv(program, argv, {envs = envs})\n    else\n        os.vrunv(program, argv)\n    end\nend\n\n-- build package\nfunction build(package, configs, opt)\n\n    -- do configure\n    configure(package, configs, opt)\n\n    -- do make and install\n    opt = opt or {}\n    local njob = opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\n    local argv = {\"-j\" .. njob}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"V=1\")\n    end\n    if opt.makeconfigs then\n        for name, value in pairs(opt.makeconfigs) do\n            value = tostring(value):trim()\n            if value ~= \"\" then\n                if type(name) == \"number\" then\n                    table.insert(argv, value)\n                else\n                    table.insert(argv, name .. \"=\" .. value)\n                end\n            end\n        end\n    end\n    make(package, argv, opt)\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- do build\n    opt = opt or {}\n    build(package, configs, opt)\n\n    -- do install\n    local argv = {\"install\"}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"V=1\")\n    end\n    if opt.makeconfigs then\n        for name, value in pairs(opt.makeconfigs) do\n            value = tostring(value):trim()\n            if value ~= \"\" then\n                if type(name) == \"number\" then\n                    table.insert(argv, value)\n                else\n                    table.insert(argv, name .. \"=\" .. value)\n                end\n            end\n        end\n    end\n    make(package, argv, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/bazel.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bazel.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- get configs\nfunction _get_configs(package, configs)\n    local configs = configs or {}\n    return configs\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local bazel = assert(find_tool(\"bazel\"), \"bazel not found!\")\n    local argv = {\"build\"}\n    configs = _get_configs(package, configs)\n    if configs then\n        table.join2(argv, configs)\n    end\n    os.vrunv(bazel.program, argv, {envs = opt.envs or buildenvs(package, opt)})\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/cmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cmake.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"package.tools.ninja\")\nimport(\"package.tools.msbuild\")\nimport(\"detect.sdks.find_emsdk\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get the number of parallel jobs\nfunction _get_parallel_njobs(opt)\n    return opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\nend\n\n-- translate paths\nfunction _translate_paths(paths)\n    if is_host(\"windows\") then\n        if type(paths) == \"string\" then\n            return (paths:gsub(\"\\\\\", \"/\"))\n        elseif type(paths) == \"table\" then\n            local result = {}\n            for _, p in ipairs(paths) do\n                table.insert(result, (p:gsub(\"\\\\\", \"/\")))\n            end\n            return result\n        end\n    end\n    return paths\nend\n\n-- translate bin path\nfunction _translate_bin_path(bin_path)\n    if is_host(\"windows\") and bin_path then\n        bin_path = bin_path:gsub(\"\\\\\", \"/\")\n        if not os.isfile(bin_path) and\n           not bin_path:find(string.ipattern(\"%.exe$\")) and\n           not bin_path:find(string.ipattern(\"%.cmd$\")) and\n           not bin_path:find(string.ipattern(\"%.bat$\")) then\n            bin_path = bin_path .. \".exe\"\n        end\n    end\n    return bin_path\nend\n\n-- get pkg-config, we need force to find it, because package install environments will be changed\nfunction _get_pkgconfig(package)\n    -- meson need fullpath pkgconfig\n    -- @see https://github.com/xmake-io/xmake/issues/5474\n    local dep = package:dep(\"pkgconf\") or package:dep(\"pkg-config\")\n    if dep then\n        local suffix = dep:is_plat(\"windows\", \"mingw\") and \".exe\" or \"\"\n        local pkgconf = path.join(dep:installdir(\"bin\"), \"pkgconf\" .. suffix)\n        if os.isfile(pkgconf) then\n            return pkgconf\n        end\n        local pkgconfig = path.join(dep:installdir(\"bin\"), \"pkg-config\" .. suffix)\n        if os.isfile(pkgconfig) then\n            return pkgconfig\n        end\n    end\n    if package:is_plat(\"windows\") then\n        local pkgconf = find_tool(\"pkgconf\", {force = true})\n        if pkgconf then\n            return pkgconf.program\n        end\n    end\n    local pkgconfig = find_tool(\"pkg-config\", {force = true})\n    if pkgconfig then\n        return pkgconfig.program\n    end\nend\n\n-- is the toolchain compatible with the host?\nfunction _is_toolchain_compatible_with_host(package)\n    for _, name in ipairs(package:config(\"toolchains\")) do\n        if toolchain_utils.is_compatible_with_host(name) then\n            return true\n        end\n    end\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get msvc run environments\nfunction _get_msvc_runenvs(package)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- get cflags from package deps\nfunction _get_cflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    -- @see https://github.com/xmake-io/xmake-repo/pull/4973#issuecomment-2295890196\n    local result = {}\n    if values then\n        if values.defines then\n            table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"define\", values.defines))\n        end\n        if values.includedirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_compflags_for_package(package, \"cxx\", \"includedir\", values.includedirs)))\n        end\n        if values.sysincludedirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_compflags_for_package(package, \"cxx\", \"sysincludedir\", values.sysincludedirs)))\n        end\n    end\n    return result\nend\n\n-- get ldflags from package deps\nfunction _get_ldflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    local result = {}\n    if values then\n        if values.linkdirs then\n            table.join2(result, _translate_paths(toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"linkdir\", values.linkdirs)))\n        end\n        if values.links then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"link\", values.links))\n        end\n        if values.syslinks then\n            table.join2(result, _translate_paths(toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"syslink\", values.syslinks)))\n        end\n        if values.frameworks then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"framework\", values.frameworks))\n        end\n    end\n    return result\nend\n\n-- get cflags\nfunction _get_cflags(package, opt)\n    opt = opt or {}\n    local result = {}\n    if opt.cross then\n        table.join2(result, package:build_getenv(\"cflags\"))\n        table.join2(result, package:build_getenv(\"cxflags\"))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"c\", \"define\", package:build_getenv(\"defines\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"c\", \"includedir\", package:build_getenv(\"includedirs\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"c\", \"sysincludedir\", package:build_getenv(\"sysincludedirs\")))\n    end\n    table.join2(result, package:config(\"cflags\"))\n    table.join2(result, package:config(\"cxflags\"))\n    if opt.cflags then\n        table.join2(result, opt.cflags)\n    end\n    if opt.cxflags then\n        table.join2(result, opt.cxflags)\n    end\n    if package:config(\"lto\") then\n        table.join2(result, package:_generate_lto_configs(\"cc\").cflags)\n    end\n    if package:config(\"asan\") then\n        table.join2(result, package:_generate_sanitizer_configs(\"address\", \"cc\").cflags)\n    end\n    table.join2(result, _get_cflags_from_packagedeps(package, opt))\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n\n-- get cxxflags\nfunction _get_cxxflags(package, opt)\n    opt = opt or {}\n    local result = {}\n    if opt.cross then\n        table.join2(result, package:build_getenv(\"cxxflags\"))\n        table.join2(result, package:build_getenv(\"cxflags\"))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"define\", package:build_getenv(\"defines\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"includedir\", package:build_getenv(\"includedirs\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"sysincludedir\", package:build_getenv(\"sysincludedirs\")))\n    end\n    table.join2(result, package:config(\"cxxflags\"))\n    table.join2(result, package:config(\"cxflags\"))\n    if opt.cxxflags then\n        table.join2(result, opt.cxxflags)\n    end\n    if opt.cxflags then\n        table.join2(result, opt.cxflags)\n    end\n    if package:config(\"lto\") then\n        table.join2(result, package:_generate_lto_configs(\"cxx\").cxxflags)\n    end\n    if package:config(\"asan\") then\n        table.join2(result, package:_generate_sanitizer_configs(\"address\", \"cxx\").cxxflags)\n    end\n    table.join2(result, _get_cflags_from_packagedeps(package, opt))\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n\n-- get asflags\nfunction _get_asflags(package, opt)\n    opt = opt or {}\n    local result = {}\n    if opt.cross then\n        table.join2(result, package:build_getenv(\"asflags\"))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"as\", \"define\", package:build_getenv(\"defines\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"as\", \"includedir\", package:build_getenv(\"includedirs\")))\n        table.join2(result, toolchain_utils.map_compflags_for_package(package, \"as\", \"sysincludedir\", package:build_getenv(\"sysincludedirs\")))\n    end\n    table.join2(result, package:config(\"asflags\"))\n    if opt.asflags then\n        table.join2(result, opt.asflags)\n    end\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n\n-- get ldflags\nfunction _get_ldflags(package, opt)\n    opt = opt or {}\n    local result = {}\n    if opt.cross then\n        table.join2(result, package:build_getenv(\"ldflags\"))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"link\", package:build_getenv(\"links\")))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"syslink\", package:build_getenv(\"syslinks\")))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"linkdir\", package:build_getenv(\"linkdirs\")))\n    end\n    table.join2(result, package:config(\"ldflags\"))\n    if package:config(\"lto\") then\n        table.join2(result, package:_generate_lto_configs().ldflags)\n    end\n    if package:config(\"asan\") then\n        table.join2(result, package:_generate_sanitizer_configs(\"address\").ldflags)\n    end\n    table.join2(result, _get_ldflags_from_packagedeps(package, opt))\n    if opt.ldflags then\n        table.join2(result, opt.ldflags)\n    end\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n\n-- get shflags\nfunction _get_shflags(package, opt)\n    opt = opt or {}\n    local result = {}\n    if opt.cross then\n        table.join2(result, package:build_getenv(\"shflags\"))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"link\", package:build_getenv(\"links\")))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"syslink\", package:build_getenv(\"syslinks\")))\n        table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"linkdir\", package:build_getenv(\"linkdirs\")))\n    end\n    table.join2(result, package:config(\"shflags\"))\n    if package:config(\"lto\") then\n        table.join2(result, package:_generate_lto_configs().shflags)\n    end\n    if package:config(\"asan\") then\n        table.join2(result, package:_generate_sanitizer_configs(\"address\").shflags)\n    end\n    table.join2(result, _get_ldflags_from_packagedeps(package, opt))\n    if opt.shflags then\n        table.join2(result, opt.shflags)\n    end\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n\n-- get arflags\nfunction _get_arflags(package, opt)\n    local result = table.wrap(package:build_getenv(\"arflags\"))\n    if #result > 0 then\n        return os.args(_translate_paths(result))\n    end\nend\n-- get cmake version\nfunction _get_cmake_version()\n    local cmake_version = _g.cmake_version\n    if not cmake_version then\n        local cmake = find_tool(\"cmake\", {version = true})\n        if cmake and cmake.version then\n            cmake_version = semver.new(cmake.version)\n        end\n        _g.cmake_version = cmake_version\n    end\n    return cmake_version\nend\n\nfunction _get_cmake_system_processor(package)\n    -- on Windows, CMAKE_SYSTEM_PROCESSOR comes from PROCESSOR_ARCHITECTURE\n    -- on other systems it's the output of uname -m\n    if package:is_plat(\"windows\") then\n        local archs = {\n            x86 = \"x86\",\n            x64 = \"AMD64\",\n            x86_64 = \"AMD64\",\n            arm = \"ARM\",\n            arm64 = \"ARM64\",\n            arm64ec = \"ARM64EC\"\n        }\n        return archs[package:arch()] or package:arch()\n    end\n    return package:arch()\nend\n\n-- get mingw32 make\nfunction _get_mingw32_make(package)\n    local mingw = package:build_getenv(\"mingw\") or package:build_getenv(\"sdk\")\n    if mingw then\n        local mingw_make = _translate_bin_path(path.join(mingw, \"bin\", \"mingw32-make.exe\"))\n        if os.isfile(mingw_make) then\n            return mingw_make\n        end\n    end\nend\n\n-- get ninja\nfunction _get_ninja(package)\n    local ninja = find_tool(\"ninja\")\n    if ninja then\n        return ninja.program\n    end\nend\n\n-- https://github.com/xmake-io/xmake-repo/pull/1096\nfunction _fix_cxx_compiler_cmake(package, envs)\n    local cxx = envs.CMAKE_CXX_COMPILER\n    if cxx and package:has_tool(\"cxx\", \"clang\", \"gcc\") then\n        local dir = path.directory(cxx)\n        local name = path.filename(cxx)\n        name = name:gsub(\"clang$\", \"clang++\")\n        name = name:gsub(\"clang%-\", \"clang++-\")\n        name = name:gsub(\"clang%.\", \"clang++.\")\n        name = name:gsub(\"gcc$\", \"g++\")\n        name = name:gsub(\"gcc%-\", \"g++-\")\n        name = name:gsub(\"gcc%.\", \"g++.\")\n        if dir and dir ~= \".\" then\n            cxx = path.join(dir, name)\n        else\n            cxx = name\n        end\n        envs.CMAKE_CXX_COMPILER = _translate_bin_path(cxx)\n    end\nend\n\n-- @see https://github.com/ziglang/zig/issues/22213\nfunction _fix_zigcc_linker_cmake(package, envs)\n    if package:has_tool(\"cc\", \"zig_cc\") then\n        envs.CMAKE_C_LINKER_DEPFILE_SUPPORTED = \"FALSE\"\n        envs.CMAKE_CXX_LINKER_DEPFILE_SUPPORTED = \"FALSE\"\n    end\nend\n\n-- insert configs from envs\nfunction _insert_configs_from_envs(configs, envs, opt)\n    opt = opt or {}\n    local configs_str = opt._configs_str\n    for k, v in pairs(envs) do\n        if configs_str and configs_str:find(\"-D\" .. k .. \"=\", 1, true) then\n            -- use user custom configuration\n        else\n            table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n        end\n    end\nend\n\n-- get configs for generic\nfunction _get_configs_for_generic(package, configs, opt)\n    local envs = {}\n    if not package:is_plat(\"windows\", \"mingw\") and package:config(\"pic\") ~= false then\n        envs.CMAKE_POSITION_INDEPENDENT_CODE = \"ON\"\n    end\n    if not package:use_external_includes() then\n        envs.CMAKE_NO_SYSTEM_FROM_IMPORTED = \"ON\"\n    end\n    envs.CMAKE_BUILD_TYPE = package:is_debug() and \"Debug\" or \"Release\"\n    if package:is_library() then\n        envs.BUILD_SHARED_LIBS = package:config(\"shared\") and \"ON\" or \"OFF\"\n    end\n    if package:has_source() then\n        envs.CMAKE_EXPORT_COMPILE_COMMANDS = \"ON\"\n    end\n    -- https://cmake.org/cmake/help/latest/variable/CMAKE_LINKER_TYPE.html\n    if package:has_tool(\"ld\", \"link\") then\n        envs.CMAKE_LINKER_TYPE = \"MSVC\"\n    end\n    _fix_zigcc_linker_cmake(package, envs)\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for windows\nfunction _get_configs_for_windows(package, configs, opt)\n    local envs = {}\n    local cmake_generator = opt.cmake_generator\n    if not cmake_generator or cmake_generator:find(\"Visual Studio\", 1, true) then\n        table.insert(configs, \"-A\")\n        if package:is_arch(\"x86\", \"i386\") then\n            table.insert(configs, \"Win32\")\n        elseif package:is_arch(\"arm64\") then\n            table.insert(configs, \"ARM64\")\n        elseif package:is_arch(\"arm64ec\") then\n            table.insert(configs, \"ARM64EC\")\n        elseif package:is_arch(\"arm.*\") then\n            table.insert(configs, \"ARM\")\n        else\n            table.insert(configs, \"x64\")\n        end\n        local vs_toolset = toolchain_utils.get_vs_toolset_ver(_get_msvc(package):config(\"vs_toolset\") or config.get(\"vs_toolset\"))\n        if vs_toolset then\n            envs.CMAKE_GENERATOR_TOOLSET = vs_toolset\n        end\n    end\n\n    -- use clang-cl or clang, and we need pass --target=xxx flags\n    if package:has_tool(\"cc\", \"clang\", \"clang_cl\") then\n        envs.CMAKE_C_COMPILER = _translate_bin_path(package:build_getenv(\"cc\"))\n    end\n    if package:has_tool(\"cxx\", \"clang\", \"clang_cl\") then\n        envs.CMAKE_CXX_COMPILER = _translate_bin_path(package:build_getenv(\"cxx\"))\n    end\n\n    -- we maybe need patch `cmake_policy(SET CMP0091 NEW)` to enable this argument for some packages\n    -- @see https://cmake.org/cmake/help/latest/policy/CMP0091.html#policy:CMP0091\n    -- https://github.com/xmake-io/xmake-repo/pull/303\n    if package:has_runtime(\"MT\") then\n        envs.CMAKE_MSVC_RUNTIME_LIBRARY = \"MultiThreaded\"\n    elseif package:has_runtime(\"MTd\") then\n        envs.CMAKE_MSVC_RUNTIME_LIBRARY = \"MultiThreadedDebug\"\n    elseif package:has_runtime(\"MD\") then\n        envs.CMAKE_MSVC_RUNTIME_LIBRARY = \"MultiThreadedDLL\"\n    elseif package:has_runtime(\"MDd\") then\n        envs.CMAKE_MSVC_RUNTIME_LIBRARY = \"MultiThreadedDebugDLL\"\n    end\n\n    local pdb_dir = path.unix(path.join(os.curdir(), \"pdb\"))\n    envs.CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY = pdb_dir\n    envs.CMAKE_PDB_OUTPUT_DIRECTORY = pdb_dir\n    _insert_configs_from_envs(configs, envs, opt)\n\n    if package:is_cross() then\n        _get_configs_for_cross(package, configs, opt)\n    end\nend\n\n-- get configs for android\n-- https://developer.android.google.cn/ndk/guides/cmake\nfunction _get_configs_for_android(package, configs, opt)\n    opt = opt or {}\n    local ndk = get_config(\"ndk\")\n    if ndk and os.isdir(ndk) then\n        local ndk_sdkver = get_config(\"ndk_sdkver\")\n        table.insert(configs, \"-DCMAKE_TOOLCHAIN_FILE=\" .. path.join(ndk, \"build/cmake/android.toolchain.cmake\"))\n        table.insert(configs, \"-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF\")\n        table.insert(configs, \"-DANDROID_ABI=\" .. package:arch())\n        if ndk_sdkver then\n            table.insert(configs, \"-DANDROID_PLATFORM=android-\" .. ndk_sdkver)\n            table.insert(configs, \"-DANDROID_NATIVE_API_LEVEL=\" .. ndk_sdkver)\n        end\n        -- https://cmake.org/cmake/help/latest/variable/CMAKE_ANDROID_STL_TYPE.html\n        local runtime = package:runtimes()\n        if runtime then\n            table.insert(configs, \"-DCMAKE_ANDROID_STL_TYPE=\" .. runtime)\n        end\n        if is_host(\"windows\") and opt.cmake_generator ~= \"Ninja\" then\n            local make = path.join(ndk, \"prebuilt\", \"windows-x86_64\", \"bin\", \"make.exe\")\n            if os.isfile(make) then\n                table.insert(configs, \"-DCMAKE_MAKE_PROGRAM=\" .. make)\n            end\n        end\n\n        -- avoid find and add system include/library path\n        -- @see https://github.com/xmake-io/xmake/issues/2037\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER\")\n    end\nend\n\n-- get configs for appleos\nfunction _get_configs_for_appleos(package, configs, opt)\n    opt = opt or {}\n    local envs                     = {}\n    opt.cross                      = true\n    -- https://cmake.org/cmake/help/v3.17/manual/cmake-toolchains.7.html#id25\n    if package:is_plat(\"watchos\") then\n        envs.CMAKE_SYSTEM_NAME = \"watchOS\"\n        if package:is_arch(\"x86_64\", \"i386\") then\n            envs.CMAKE_OSX_SYSROOT = \"watchsimulator\"\n        end\n    elseif package:is_plat(\"iphoneos\") then\n        envs.CMAKE_SYSTEM_NAME = \"iOS\"\n        if package:is_arch(\"x86_64\", \"i386\") then\n            envs.CMAKE_OSX_SYSROOT = \"iphonesimulator\"\n        end\n    elseif package:is_cross() then\n        envs.CMAKE_SYSTEM_NAME = \"Darwin\"\n        envs.CMAKE_SYSTEM_PROCESSOR = _get_cmake_system_processor(package)\n    end\n    envs.CMAKE_OSX_ARCHITECTURES = package:arch()\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE   = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY   = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE   = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_FRAMEWORK = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM   = \"NEVER\"\n    -- avoid install bundle targets\n    envs.CMAKE_MACOSX_BUNDLE       = \"NO\"\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for mingw\nfunction _get_configs_for_mingw(package, configs, opt)\n    opt = opt or {}\n    opt.cross                      = true\n    local envs                     = {}\n    local sdkdir                   = package:build_getenv(\"mingw\") or package:build_getenv(\"sdk\")\n    envs.CMAKE_C_COMPILER          = _translate_bin_path(package:build_getenv(\"cc\"))\n    envs.CMAKE_CXX_COMPILER        = _translate_bin_path(package:build_getenv(\"cxx\"))\n    envs.CMAKE_ASM_COMPILER        = _translate_bin_path(package:build_getenv(\"as\"))\n    envs.CMAKE_AR                  = _translate_bin_path(package:build_getenv(\"ar\"))\n    envs.CMAKE_RANLIB              = _translate_bin_path(package:build_getenv(\"ranlib\"))\n    envs.CMAKE_RC_COMPILER         = _translate_bin_path(package:build_getenv(\"mrc\"))\n    -- @see https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html\n    -- https://github.com/xmake-io/xmake/pull/5888\n    if not is_host(\"windows\") then\n        envs.CMAKE_SYSTEM_NAME = \"Windows\"\n    end\n    envs.CMAKE_SYSTEM_PROCESSOR    = _get_cmake_system_processor(package)\n    -- avoid find and add system include/library path\n    -- @see https://github.com/xmake-io/xmake/issues/2037\n    -- https://github.com/xmake-io/xmake/issues/6660\n    if sdkdir and sdkdir ~= \"/usr\" then\n        envs.CMAKE_FIND_ROOT_PATH = sdkdir\n    end\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = \"NEVER\"\n    -- avoid add -isysroot on macOS\n    envs.CMAKE_OSX_SYSROOT = \"\"\n    -- Avoid cmake to add the flags -search_paths_first and -headerpad_max_install_names on macOS\n    envs.HAVE_FLAG_SEARCH_PATHS_FIRST = \"0\"\n    -- CMAKE_MAKE_PROGRAM may be required for some CMakeLists.txt (libcurl)\n    if is_subhost(\"windows\") and opt.cmake_generator ~= \"Ninja\" then\n        envs.CMAKE_MAKE_PROGRAM = _get_mingw32_make(package)\n    end\n    _fix_cxx_compiler_cmake(package, envs)\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for wasm\nfunction _get_configs_for_wasm(package, configs, opt)\n    opt = opt or {}\n    local envs = {}\n    local emsdk = find_emsdk()\n    assert(emsdk and emsdk.emscripten, \"emscripten not found!\")\n    local emscripten_cmakefile = find_file(\"Emscripten.cmake\", path.join(emsdk.emscripten, \"cmake/Modules/Platform\"))\n    assert(emscripten_cmakefile, \"Emscripten.cmake not found!\")\n    table.insert(configs, \"-DCMAKE_TOOLCHAIN_FILE=\" .. emscripten_cmakefile)\n    if is_subhost(\"windows\") then\n        if opt.cmake_generator ~= \"Ninja\" then\n            local mingw_make = _get_mingw32_make(package)\n            if mingw_make then\n                table.insert(configs, \"-DCMAKE_MAKE_PROGRAM=\" .. mingw_make)\n            end\n        end\n    end\n\n    -- avoid find and add system include/library path\n    -- @see https://github.com/xmake-io/xmake/issues/5577\n    -- https://github.com/emscripten-core/emscripten/issues/13310\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = \"NEVER\"\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for cross\nfunction _get_configs_for_cross(package, configs, opt)\n    opt = opt or {}\n    opt.cross                      = true\n    local envs                     = {}\n    local sdkdir                   = _translate_paths(package:build_getenv(\"sdk\"))\n    envs.CMAKE_C_COMPILER          = _translate_bin_path(package:build_getenv(\"cc\"))\n    envs.CMAKE_CXX_COMPILER        = _translate_bin_path(package:build_getenv(\"cxx\"))\n    envs.CMAKE_ASM_COMPILER        = _translate_bin_path(package:build_getenv(\"as\"))\n    envs.CMAKE_AR                  = _translate_bin_path(package:build_getenv(\"ar\"))\n    if package:is_plat(\"windows\") then\n        envs.CMAKE_RC_COMPILER = _translate_bin_path(package:build_getenv(\"mrc\"))\n        if package:has_tool(\"cxx\", \"cl\") then\n            envs.CMAKE_AR = path.join(path.directory(envs.CMAKE_CXX_COMPILER), \"lib.exe\")\n        end\n    end\n    _fix_cxx_compiler_cmake(package, envs)\n    -- @note The link command line is set in Modules/CMake{C,CXX,Fortran}Information.cmake and defaults to using the compiler, not CMAKE_LINKER,\n    -- so we need to set CMAKE_CXX_LINK_EXECUTABLE to use CMAKE_LINKER as linker.\n    --\n    -- https://github.com/xmake-io/xmake-repo/pull/1039\n    -- https://stackoverflow.com/questions/1867745/cmake-use-a-custom-linker/25274328#25274328\n    -- https://github.com/xmake-io/xmake-repo/pull/2134#issuecomment-1573195810\n    local ld = _translate_bin_path(package:build_getenv(\"ld\"))\n    if package:has_tool(\"ld\", \"gxx\", \"clangxx\") then\n        envs.CMAKE_CXX_LINK_EXECUTABLE = ld .. \" <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>\"\n    end\n    envs.CMAKE_RANLIB = _translate_bin_path(package:build_getenv(\"ranlib\"))\n    -- we don't need to set it as cross compilation if we just pass toolchain\n    -- https://github.com/xmake-io/xmake/issues/2170\n    if package:is_cross() then\n        local system_name = package:targetos() or \"Linux\"\n        if system_name == \"linux\" then\n            system_name = \"Linux\"\n        elseif system_name == \"windows\" then\n            system_name = \"Windows\"\n        end\n        envs.CMAKE_SYSTEM_NAME = system_name\n        envs.CMAKE_SYSTEM_PROCESSOR = _get_cmake_system_processor(package)\n    end\n    -- avoid find and add system include/library path\n    -- @see https://github.com/xmake-io/xmake/issues/2037\n    -- https://github.com/xmake-io/xmake/issues/6660\n    if sdkdir and sdkdir ~= \"/usr\" then\n        envs.CMAKE_FIND_ROOT_PATH = sdkdir\n    end\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = \"NEVER\"\n    -- avoid add -isysroot on macOS\n    envs.CMAKE_OSX_SYSROOT = \"\"\n    -- avoid cmake to add the flags -search_paths_first and -headerpad_max_install_names on macOS\n    envs.HAVE_FLAG_SEARCH_PATHS_FIRST = \"0\"\n    -- avoids finding host include/library path\n    envs.CMAKE_FIND_USE_CMAKE_SYSTEM_PATH = \"0\"\n    envs.CMAKE_FIND_USE_INSTALL_PREFIX = \"0\"\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for host toolchain\nfunction _get_configs_for_host_toolchain(package, configs, opt)\n    opt = opt or {}\n    opt.cross                      = true\n    local envs                     = {}\n    envs.CMAKE_C_COMPILER          = _translate_bin_path(package:build_getenv(\"cc\"))\n    envs.CMAKE_CXX_COMPILER        = _translate_bin_path(package:build_getenv(\"cxx\"))\n    envs.CMAKE_ASM_COMPILER        = _translate_bin_path(package:build_getenv(\"as\"))\n    envs.CMAKE_RC_COMPILER         = _translate_bin_path(package:build_getenv(\"mrc\"))\n    envs.CMAKE_AR                  = _translate_bin_path(package:build_getenv(\"ar\"))\n    _fix_cxx_compiler_cmake(package, envs)\n    -- @note The link command line is set in Modules/CMake{C,CXX,Fortran}Information.cmake and defaults to using the compiler, not CMAKE_LINKER,\n    -- so we need set CMAKE_CXX_LINK_EXECUTABLE to use CMAKE_LINKER as linker.\n    --\n    -- https://github.com/xmake-io/xmake-repo/pull/1039\n    -- https://stackoverflow.com/questions/1867745/cmake-use-a-custom-linker/25274328#25274328\n    -- https://github.com/xmake-io/xmake-repo/pull/2134#issuecomment-1573195810\n    local ld = _translate_bin_path(package:build_getenv(\"ld\"))\n    if package:has_tool(\"ld\", \"gxx\", \"clangxx\") then\n        envs.CMAKE_CXX_LINK_EXECUTABLE = ld .. \" <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>\"\n    end\n    envs.CMAKE_RANLIB = _translate_bin_path(package:build_getenv(\"ranlib\"))\n    -- we don't need to set it as cross compilation if we just pass toolchain\n    -- https://github.com/xmake-io/xmake/issues/2170\n    if package:is_cross() then\n        envs.CMAKE_SYSTEM_NAME     = \"Linux\"\n    end\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get cmake generator for msvc\nfunction _get_cmake_generator_for_msvc(package)\n    local vs = _get_msvc(package):config(\"vs\") or config.get(\"vs\")\n    return \"Visual Studio \" .. toolchain_utils.get_vsver(vs) .. \" \" .. vs\nend\n\n-- get configs for cmake generator\nfunction _get_configs_for_generator(package, configs, opt)\n    opt     = opt or {}\n    configs = configs or {}\n    local cmake_generator = opt.cmake_generator\n    if cmake_generator then\n        if cmake_generator:find(\"Visual Studio\", 1, true) then\n            cmake_generator = _get_cmake_generator_for_msvc(package)\n        end\n        table.insert(configs, \"-G\")\n        table.insert(configs, cmake_generator)\n        if cmake_generator:find(\"Ninja\", 1, true) then\n            local jobs = _get_parallel_njobs(opt)\n            local linkjobs = opt.linkjobs or option.get(\"linkjobs\")\n            if linkjobs then\n                table.insert(configs, \"-DCMAKE_JOB_POOL_COMPILE:STRING=compile\")\n                table.insert(configs, \"-DCMAKE_JOB_POOL_LINK:STRING=link\")\n                table.insert(configs, (\"-DCMAKE_JOB_POOLS:STRING=compile=%s;link=%s\"):format(jobs, linkjobs))\n            end\n            local ninja = _get_ninja(package)\n            if ninja then\n                table.insert(configs, \"-DCMAKE_MAKE_PROGRAM=\" .. ninja)\n            end\n        end\n    elseif package:is_plat(\"mingw\") and is_subhost(\"msys\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MSYS Makefiles\")\n    elseif package:is_plat(\"mingw\") and is_subhost(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MinGW Makefiles\")\n    elseif package:is_plat(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, _get_cmake_generator_for_msvc(package))\n    elseif package:is_plat(\"wasm\") and is_subhost(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MinGW Makefiles\")\n    else\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"Unix Makefiles\")\n    end\nend\n\n-- get configs for installation\nfunction _get_configs_for_install(package, configs, opt)\n    -- @see https://cmake.org/cmake/help/v3.14/module/GNUInstallDirs.html\n    -- LIBDIR: object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)\n    --\n    table.insert(configs, \"-DCMAKE_INSTALL_PREFIX=\" .. package:installdir())\n    if not opt._configs_str:find(\"CMAKE_INSTALL_LIBDIR\") then\n        table.insert(configs, \"-DCMAKE_INSTALL_LIBDIR:PATH=lib\")\n    end\nend\n\nfunction _get_default_flags(package, configs, buildtype, opt)\n    -- The default flags are different for different platforms\n    -- @see https://github.com/xmake-io/xmake-repo/pull/4038#issuecomment-2116489448\n    local cc = package:build_getenv(\"cc\")\n    local cxx = package:build_getenv(\"cxx\")\n    local cachekey = buildtype .. package:plat() .. package:arch() .. (cc or \"\") .. (cxx or \"\")\n    local cmake_default_flags = _g.cmake_default_flags and _g.cmake_default_flags[cachekey]\n    if not cmake_default_flags then\n        local tmpdir = path.join(os.tmpfile() .. \".dir\", package:displayname(), package:mode())\n        local dummy_cmakelist = path.join(tmpdir, \"CMakeLists.txt\")\n\n        local cflags\n        if cc then\n            cflags = \"-DCMAKE_C_COMPILER=\" .. _translate_bin_path(cc)\n        end\n        local cxxflags\n        if cxx then\n            cxxflags = \"-DCMAKE_CXX_COMPILER=\" .. _translate_bin_path(cxx)\n        end\n\n        -- About the minimum cmake version requirement\n        -- @see https://github.com/xmake-io/xmake/pull/6032\n        io.writefile(dummy_cmakelist, format([[\n    cmake_minimum_required(VERSION 3.15)\n    project(XMakeDummyProject)\n\n    message(STATUS \"CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}\")\n    message(STATUS \"CMAKE_C_FLAGS_%s is ${CMAKE_C_FLAGS_%s}\")\n\n    message(STATUS \"CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}\")\n    message(STATUS \"CMAKE_CXX_FLAGS_%s is ${CMAKE_CXX_FLAGS_%s}\")\n\n    message(STATUS \"CMAKE_EXE_LINKER_FLAGS is ${CMAKE_EXE_LINKER_FLAGS}\")\n    message(STATUS \"CMAKE_EXE_LINKER_FLAGS_%s is ${CMAKE_EXE_LINKER_FLAGS_%s}\")\n\n    message(STATUS \"CMAKE_SHARED_LINKER_FLAGS is ${CMAKE_SHARED_LINKER_FLAGS}\")\n    message(STATUS \"CMAKE_SHARED_LINKER_FLAGS_%s is ${CMAKE_SHARED_LINKER_FLAGS_%s}\")\n\n    message(STATUS \"CMAKE_STATIC_LINKER_FLAGS is ${CMAKE_STATIC_LINKER_FLAGS}\")\n    message(STATUS \"CMAKE_STATIC_LINKER_FLAGS_%s is ${CMAKE_STATIC_LINKER_FLAGS_%s}\")\n        ]], buildtype, buildtype, buildtype, buildtype, buildtype, buildtype, buildtype, buildtype, buildtype, buildtype))\n\n        local runenvs = opt.envs or buildenvs(package)\n        local cmake = find_tool(\"cmake\")\n        local _configs = table.join(configs, \"-S\", path.directory(dummy_cmakelist), \"-B\", tmpdir, cflags or {}, cxxflags)\n        local outdata = try{ function() return os.iorunv(cmake.program, _configs, {envs = runenvs}) end}\n        if outdata and outdata ~= \"\" then\n            cmake_default_flags = {}\n            cmake_default_flags.CMAKE_C_FLAGS = outdata:match(\"CMAKE_C_FLAGS is (.-)\\n\")\n            cmake_default_flags[\"CMAKE_C_FLAGS_\" .. buildtype] = outdata:match(format(\"CMAKE_C_FLAGS_%s is (.-)\\n\", buildtype))\n            cmake_default_flags.CMAKE_CXX_FLAGS = outdata:match(\"CMAKE_CXX_FLAGS is (.-)\\n\")\n            cmake_default_flags[\"CMAKE_CXX_FLAGS_\" .. buildtype] = outdata:match(format(\"CMAKE_CXX_FLAGS_%s is (.-)\\n\", buildtype))\n            cmake_default_flags.CMAKE_CXX_FLAGS = outdata:match(\"CMAKE_CXX_FLAGS is (.-)\\n\")\n            cmake_default_flags[\"CMAKE_EXE_LINKER_FLAGS_\" .. buildtype] = outdata:match(format(\"CMAKE_EXE_LINKER_FLAGS_%s is (.-)\\n\", buildtype))\n            cmake_default_flags.CMAKE_SHARED_LINKER_FLAGS = outdata:match(\"CMAKE_SHARED_LINKER_FLAGS is (.-)\\n\")\n            cmake_default_flags[\"CMAKE_SHARED_LINKER_FLAGS_\" .. buildtype] = outdata:match(format(\"CMAKE_SHARED_LINKER_FLAGS_%s is (.-)\\n\", buildtype))\n            cmake_default_flags.CMAKE_STATIC_LINKER_FLAGS = outdata:match(\"CMAKE_STATIC_LINKER_FLAGS is (.-)\\n\")\n            cmake_default_flags[\"CMAKE_STATIC_LINKER_FLAGS_\" .. buildtype] = outdata:match(format(\"CMAKE_STATIC_LINKER_FLAGS_%s is (.-)\\n\", buildtype))\n            for k, v in ipairs(cmake_default_flags) do\n                cmake_default_flags[k] = v:replace(\"/M[DT]d\", \"\"):replace(\"/M[DT]\", \"\")\n            end\n            _g.cmake_default_flags = _g.cmake_default_flags or {}\n            _g.cmake_default_flags[cachekey] = cmake_default_flags\n        end\n        os.rm(tmpdir)\n    end\n    return cmake_default_flags\nend\n\nfunction _get_cmake_buildtype(package)\n    local cmake_buildtype_map = {\n        debug = \"DEBUG\",\n        release = \"RELEASE\",\n        releasedbg = \"RELWITHDEBINFO\"\n    }\n    local buildtype = package:mode()\n    return cmake_buildtype_map[buildtype] or \"RELEASE\"\nend\n\nfunction _get_envs_for_default_flags(package, configs, opt)\n    local buildtype = _get_cmake_buildtype(package)\n    return table.clone(_get_default_flags(package, configs, buildtype, opt)) or {}\nend\n\nfunction _get_envs_for_runtime_flags(package, opt)\n    local buildtype = _get_cmake_buildtype(package)\n    local envs = {}\n    local runtimes = package:runtimes()\n    if runtimes then\n        envs[format(\"CMAKE_C_FLAGS_%s\", buildtype)]             = toolchain_utils.map_compflags_for_package(package, \"c\", \"runtime\", runtimes)\n        envs[format(\"CMAKE_CXX_FLAGS_%s\", buildtype)]           = toolchain_utils.map_compflags_for_package(package, \"cxx\", \"runtime\", runtimes)\n        envs[format(\"CMAKE_EXE_LINKER_FLAGS_%s\", buildtype)]    = toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"runtime\", runtimes)\n        envs[format(\"CMAKE_STATIC_LINKER_FLAGS_%s\", buildtype)] = toolchain_utils.map_linkflags_for_package(package, \"static\", {\"cxx\"}, \"runtime\", runtimes)\n        envs[format(\"CMAKE_SHARED_LINKER_FLAGS_%s\", buildtype)] = toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"runtime\", runtimes)\n        envs[format(\"CMAKE_MODULE_LINKER_FLAGS_%s\", buildtype)] = toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"runtime\", runtimes)\n    end\n    return envs\nend\n\nfunction _get_envs_for_flags(package, configs, opt)\n    -- get the default envs\n    local envs = _get_envs_for_default_flags(package, configs, opt)\n    local runtime_envs = _get_envs_for_runtime_flags(package, opt)\n    if runtime_envs then\n        for name, value in pairs(runtime_envs) do\n            envs[name] = (envs[name] or \" \") .. \" \" .. table.concat(value, \" \")\n        end\n    end\n\n    -- get the platform/toolchain envs\n    local platform_envs = {}\n    if package:is_plat(\"windows\") then\n        -- use clang-cl or clang, and we need pass --target=xxx flags\n        if package:has_tool(\"cc\", \"clang\", \"clang_cl\") then\n            -- @see https://github.com/xmake-io/xmake-repo/issues/7662\n            platform_envs.CMAKE_C_FLAGS = _get_cflags(package, table.join({cross = true}, opt))\n        end\n        if package:has_tool(\"cxx\", \"clang\", \"clang_cl\") then\n            platform_envs.CMAKE_CXX_FLAGS = _get_cxxflags(package, table.join({cross = true}, opt))\n        end\n    elseif package:is_plat(\"wasm\") then\n        -- pass toolchain flags cross-compilation\n        -- @see https://github.com/xmake-io/xmake/issues/6690\n        opt.cross = true\n    end\n    platform_envs.CMAKE_C_FLAGS             = platform_envs.CMAKE_C_FLAGS or _get_cflags(package, opt)\n    platform_envs.CMAKE_CXX_FLAGS           = platform_envs.CMAKE_CXX_FLAGS or _get_cxxflags(package, opt)\n    platform_envs.CMAKE_ASM_FLAGS           = _get_asflags(package, opt)\n    platform_envs.CMAKE_EXE_LINKER_FLAGS    = _get_ldflags(package, opt)\n    platform_envs.CMAKE_SHARED_LINKER_FLAGS = _get_shflags(package, opt)\n    platform_envs.CMAKE_MODULE_LINKER_FLAGS = _get_shflags(package, opt)\n    platform_envs.CMAKE_STATIC_LINKER_FLAGS = _get_arflags(package, opt)\n    for name, value in pairs(platform_envs) do\n        envs[name] = (envs[name] or \" \") .. \" \" .. value\n    end\n    return envs\nend\n\nfunction _get_configs(package, configs, opt)\n    configs = configs or {}\n    opt._configs_str = string.serialize(configs, {indent = false, strip = true})\n    _get_configs_for_install(package, configs, opt)\n    _get_configs_for_generator(package, configs, opt)\n    _get_configs_for_generic(package, configs, opt)\n\n    if package:is_plat(\"windows\") then\n        _get_configs_for_windows(package, configs, opt)\n    elseif package:is_plat(\"android\") then\n        _get_configs_for_android(package, configs, opt)\n    elseif package:is_plat(\"iphoneos\", \"watchos\") or\n        -- for cross-compilation on macOS, @see https://github.com/xmake-io/xmake/issues/2804\n        (package:is_plat(\"macosx\") and (get_config(\"appledev\") or not package:is_arch(os.subarch()))) then\n        _get_configs_for_appleos(package, configs, opt)\n    elseif package:is_plat(\"mingw\") then\n        _get_configs_for_mingw(package, configs, opt)\n    elseif package:is_plat(\"wasm\") then\n        _get_configs_for_wasm(package, configs, opt)\n    elseif package:is_cross() then\n        _get_configs_for_cross(package, configs, opt)\n    elseif package:config(\"toolchains\") then\n        -- we still need find system libraries,\n        -- it just pass toolchain environments if the toolchain is compatible with host\n        if _is_toolchain_compatible_with_host(package) then\n            _get_configs_for_host_toolchain(package, configs, opt)\n        else\n            _get_configs_for_cross(package, configs, opt)\n        end\n    end\n\n    -- fix error for cmake 4.x\n    -- e.g. Compatibility with CMake < 3.5 has been removed from CMake.\n    if _get_cmake_version() and _get_cmake_version():ge(\"4.0\") then\n        table.insert(configs, \"-DCMAKE_POLICY_VERSION_MINIMUM=3.5\")\n    end\n\n    -- insert flags to configs\n    --\n    -- @note We need to rely on configs to get the exact default flags\n    -- @see https://github.com/xmake-io/xmake/issues/6781\n    local envs = _get_envs_for_flags(package, configs, opt)\n    _insert_configs_from_envs(configs, envs, opt)\n\n    -- enable ccache?\n    local ccache = package:data(\"ccache\")\n    if ccache then\n        table.insert(configs, \"-DCMAKE_C_COMPILER_LAUNCHER=\" .. ccache)\n        table.insert(configs, \"-DCMAKE_CXX_COMPILER_LAUNCHER=\" .. ccache)\n    end\n    return configs\nend\n\n-- Fix pdb issue, if multiple CL.EXE write to the same .PDB file, please use /FS\n-- @see https://github.com/xmake-io/xmake/issues/5353\nfunction _fix_pdbdir_for_ninja(package)\n    if package:is_plat(\"windows\") and package:has_tool(\"cxx\", \"cl\") then\n        local pdbdir = \"pdb\"\n        if not os.isdir(pdbdir) then\n            os.mkdir(pdbdir)\n        end\n    end\nend\n\n-- enter build directory\nfunction _enter_builddir(package, opt)\n    local builddir = opt.builddir or opt.buildir or package:builddir()\n    if opt.buildir then\n        wprint(\"{buildir = } has been deprecated, please use {builddir = } in cmake.install\")\n    end\n    os.mkdir(path.join(builddir, \"install\"))\n    return os.cd(builddir)\nend\n\n-- get build environments\nfunction buildenvs(package, opt)\n\n    -- we need to bind msvc environments manually\n    -- @see https://github.com/xmake-io/xmake/issues/1057\n    opt = opt or {}\n    local envs = {}\n    if package:is_plat(\"windows\") then\n        envs = _get_msvc_runenvs(package)\n    end\n\n    -- we need to pass pkgconf for windows/mingw without msys2/cygwin\n    if package:is_plat(\"windows\", \"mingw\") and is_subhost(\"windows\") then\n        local pkgconf = _get_pkgconfig(package)\n        if pkgconf then\n            envs.PKG_CONFIG = pkgconf\n        end\n    end\n\n    -- add environments for cmake/find_packages\n    -- and we need also find them from private libraries,\n    -- @see https://github.com/xmake-io/xmake-repo/pull/2553\n    local CMAKE_LIBRARY_PATH = {}\n    local CMAKE_INCLUDE_PATH = {}\n    local CMAKE_PREFIX_PATH  = {}\n    local PKG_CONFIG_PATH = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        if dep:is_system() then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                table.join2(CMAKE_LIBRARY_PATH, fetchinfo.linkdirs)\n                table.join2(CMAKE_INCLUDE_PATH, fetchinfo.includedirs)\n                table.join2(CMAKE_INCLUDE_PATH, fetchinfo.sysincludedirs)\n            end\n        else\n            table.join2(CMAKE_PREFIX_PATH, dep:installdir())\n            local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n            if os.isdir(pkgconfig) then\n                table.insert(PKG_CONFIG_PATH, pkgconfig)\n            end\n            pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n            if os.isdir(pkgconfig) then\n                table.insert(PKG_CONFIG_PATH, pkgconfig)\n            end\n        end\n    end\n    envs.CMAKE_LIBRARY_PATH = path.joinenv(CMAKE_LIBRARY_PATH)\n    envs.CMAKE_INCLUDE_PATH = path.joinenv(CMAKE_INCLUDE_PATH)\n    envs.CMAKE_PREFIX_PATH  = path.joinenv(CMAKE_PREFIX_PATH)\n    envs.PKG_CONFIG_PATH    = path.joinenv(PKG_CONFIG_PATH)\n    return envs\nend\n\n-- do build for msvc\nfunction _build_for_msvc(package, configs, opt)\n    local allbuild = os.isfile(\"ALL_BUILD.vcxproj\") and \"ALL_BUILD.vcxproj\" or \"ALL_BUILD.vcproj\"\n    assert(os.isfile(allbuild), \"ALL_BUILD project not found!\")\n    msbuild.build(package, {allbuild, \"-t:Rebuild\"}, opt)\nend\n\n-- do build for make\nfunction _build_for_make(package, configs, opt)\n    local argv = {}\n    local targets = table.wrap(opt.targets or opt.target)\n    if #targets ~= 0 then\n        table.join2(argv, targets)\n    end\n    local jobs = _get_parallel_njobs(opt)\n    table.insert(argv, \"-j\" .. jobs)\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    if is_host(\"bsd\") then\n        os.vrunv(\"gmake\", argv)\n    elseif is_subhost(\"windows\") and package:is_plat(\"mingw\") then\n        local mingw_make = assert(_get_mingw32_make(package), \"mingw32-make.exe not found!\")\n        os.vrunv(mingw_make, argv)\n    elseif package:is_plat(\"android\") and is_host(\"windows\") then\n        local make\n        local ndk = get_config(\"ndk\")\n        if ndk then\n            make = path.join(ndk, \"prebuilt\", \"windows-x86_64\", \"bin\", \"make.exe\")\n        end\n        if not make or not os.isfile(make) then\n            make = \"make\"\n        end\n        os.vrunv(make, argv)\n    else\n        os.vrunv(\"make\", argv)\n    end\nend\n\n-- do build for ninja\nfunction _build_for_ninja(package, configs, opt)\n    opt = opt or {}\n    _fix_pdbdir_for_ninja(package)\n    ninja.build(package, {}, {envs = opt.envs or buildenvs(package, opt),\n        jobs = opt.jobs,\n        targets = opt.targets or opt.target})\nend\n\n-- do build for cmake/build\nfunction _build_for_cmakebuild(package, configs, opt)\n    local cmake = assert(find_tool(\"cmake\"), \"cmake not found!\")\n    local argv = {\"--build\", os.curdir()}\n    if opt.config then\n        table.insert(argv, \"--config\")\n        table.insert(argv, opt.config)\n    end\n    local targets = table.wrap(opt.targets or opt.target)\n    if #targets ~= 0 then\n        table.insert(argv, \"--target\")\n        if #targets > 1 then\n            -- https://stackoverflow.com/questions/47553569/how-can-i-build-multiple-targets-using-cmake-build\n            if _get_cmake_version() and _get_cmake_version():ge(\"3.15\") then\n                table.join2(argv, targets)\n            else\n                raise(\"Build multiple targets need cmake >=3.15\")\n            end\n        else\n            table.insert(argv, targets[1])\n        end\n    end\n    os.vrunv(cmake.program, argv, {envs = opt.envs or buildenvs(package)})\nend\n\n-- do install for msvc\nfunction _install_for_msvc(package, configs, opt)\n    local allbuild = os.isfile(\"ALL_BUILD.vcxproj\") and \"ALL_BUILD.vcxproj\" or \"ALL_BUILD.vcproj\"\n    assert(os.isfile(allbuild), \"ALL_BUILD project not found!\")\n    msbuild.build(package, {allbuild, \"-t:Rebuild\", \"/nr:false\"}, opt)\n    local projfile = os.isfile(\"INSTALL.vcxproj\") and \"INSTALL.vcxproj\" or \"INSTALL.vcproj\"\n    if os.isfile(projfile) then\n        msbuild.build(package, {projfile}, opt)\n        os.trycp(\"install/bin\", package:installdir())\n        os.trycp(\"install/lib\", package:installdir()) -- perhaps only headers library\n        os.trycp(\"install/share\", package:installdir())\n        os.trycp(\"install/include\", package:installdir())\n    else\n        os.trycp(\"**.dll\", package:installdir(\"bin\"))\n        os.trycp(\"**.lib\", package:installdir(\"lib\"))\n        os.trycp(\"**.exp\", package:installdir(\"lib\"))\n        if package:config(\"shared\") or not package:is_library() then\n            os.trycp(\"**.pdb\", package:installdir(\"bin\"))\n        else\n            os.trycp(\"**.pdb\", package:installdir(\"lib\"))\n        end\n    end\nend\n\n-- do install for make\nfunction _install_for_make(package, configs, opt)\n    local jobs = _get_parallel_njobs(opt)\n    local argv = {\"-j\" .. jobs}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    if is_host(\"bsd\") then\n        os.vrunv(\"gmake\", argv)\n        os.vrunv(\"gmake\", {\"install\"})\n    elseif is_subhost(\"windows\") and package:is_plat(\"mingw\", \"wasm\") then\n        local mingw_make = assert(_get_mingw32_make(package), \"mingw32-make.exe not found!\")\n        os.vrunv(mingw_make, argv)\n        os.vrunv(mingw_make, {\"install\"})\n    elseif package:is_plat(\"android\") and is_host(\"windows\") then\n        local make\n        local ndk = get_config(\"ndk\")\n        if ndk then\n            make = path.join(ndk, \"prebuilt\", \"windows-x86_64\", \"bin\", \"make.exe\")\n        end\n        if not make or not os.isfile(make) then\n            make = \"make\"\n        end\n        os.vrunv(make, argv)\n        os.vrunv(make, {\"install\"})\n    else\n        os.vrunv(\"make\", argv)\n        os.vrunv(\"make\", {\"install\"})\n    end\nend\n\n-- do install for ninja\nfunction _install_for_ninja(package, configs, opt)\n    opt = opt or {}\n    _fix_pdbdir_for_ninja(package)\n    ninja.install(package, {}, {envs = opt.envs or buildenvs(package, opt),\n        jobs = opt.jobs,\n        targets = opt.targets or opt.target})\nend\n\n-- do install for cmake/build\nfunction _install_for_cmakebuild(package, configs, opt)\n    opt = opt or {}\n    local cmake = assert(find_tool(\"cmake\"), \"cmake not found!\")\n    local argv = {\"--build\", os.curdir()}\n    local install_argv = {\"--install\", os.curdir()}\n    if opt.config then\n        table.insert(argv, \"--config\")\n        table.insert(argv, opt.config)\n        table.insert(install_argv, \"--config\")\n        table.insert(install_argv, opt.config)\n    end\n    os.vrunv(cmake.program, argv, {envs = opt.envs or buildenvs(package)})\n    os.vrunv(cmake.program, install_argv)\nend\n\n-- get cmake generator\nfunction _get_cmake_generator(package, opt)\n    opt = opt or {}\n    local cmake_generator = opt.cmake_generator\n    if not cmake_generator then\n        local use_ninja = package:policy(\"package.cmake_generator.ninja\")\n        if use_ninja == nil then\n            use_ninja = project.policy(\"package.cmake_generator.ninja\")\n        end\n        if use_ninja then\n            cmake_generator = \"Ninja\"\n        end\n        if not cmake_generator then\n            if package:has_tool(\"cc\", \"clang_cl\") or package:has_tool(\"cxx\", \"clang_cl\") then\n                cmake_generator = \"Ninja\"\n            elseif (is_subhost(\"windows\") and package:is_plat(\"mingw\", \"wasm\"))\n                or (package:is_plat(\"windows\") and is_host(\"linux\")) then\n                local ninja = _get_ninja(package)\n                if ninja then\n                    cmake_generator = \"Ninja\"\n                end\n            end\n        end\n        local cmake_generator_env = os.getenv(\"CMAKE_GENERATOR\")\n        if not cmake_generator and cmake_generator_env then\n            cmake_generator = cmake_generator_env\n        end\n        if cmake_generator then\n            opt.cmake_generator = cmake_generator\n        end\n    end\n    return cmake_generator\nend\n\n-- shrink cmake arguments, fix too long arguments\n-- @see https://github.com/xmake-io/xmake-repo/pull/5247#discussion_r1780302212\nfunction _shrink_cmake_arguments(argv, oldir, opt)\n    local cmake_argv = {}\n    local long_options = hashset.of(\n        \"CMAKE_C_FLAGS\",\n        \"CMAKE_CXX_FLAGS\",\n        \"CMAKE_ASM_FLAGS\",\n        \"CMAKE_EXE_LINKER_FLAGS\",\n        \"CMAKE_SHARED_LINKER_FLAGS\",\n        \"CMAKE_MODULE_LINKER_FLAGS\",\n        \"CMAKE_C_FLAGS_RELEASE\",\n        \"CMAKE_CXX_FLAGS_RELEASE\",\n        \"CMAKE_ASM_FLAGS_RELEASE\",\n        \"CMAKE_EXE_LINKER_FLAGS_RELEASE\",\n        \"CMAKE_SHARED_LINKER_FLAGS_RELEASE\",\n        \"CMAKE_MODULE_LINKER_FLAGS_RELEASE\",\n        \"CMAKE_C_FLAGS_DEBUG\",\n        \"CMAKE_CXX_FLAGS_DEBUG\",\n        \"CMAKE_ASM_FLAGS_DEBUG\",\n        \"CMAKE_EXE_LINKER_FLAGS_DEBUG\",\n        \"CMAKE_SHARED_LINKER_FLAGS_DEBUG\",\n        \"CMAKE_MODULE_LINKER_FLAGS_DEBUG\")\n    local shrink = false\n    local add_compile_options = false\n    local add_link_options = false\n    if _get_cmake_version() and _get_cmake_version():ge(\"3.13\") then\n        add_compile_options = true\n        add_link_options = true\n    end\n    local buildtypes_map = {\n        RELEASE = \"Release\",\n        DEBUG = \"Debug\",\n        RELWITHDEBINFO = \"RelWithDebInfo\"\n    }\n    table.remove_if(argv, function (idx, value)\n        local k, v = value:match(\"%-D(.*)=(.*)\")\n        if k and v and long_options:has(k) then\n            local kind, mode = k:match(\"CMAKE_(.+)_FLAGS_(.+)\")\n            if not kind then\n                kind = k:match(\"CMAKE_(.+)_FLAGS\")\n            end\n            -- improve cmake flags\n            -- @see https://github.com/xmake-io/xmake/issues/5826\n            --[[\n            local build_type = mode and buildtypes_map[mode] or nil\n            if #v > 0 and add_compile_options and (kind == \"C\" or kind == \"CXX\" or kind == \"ASM\") then\n                if build_type then\n                    table.insert(cmake_argv, (\"if(CMAKE_BUILD_TYPE STREQUAL \\\"%s\\\")\"):format(build_type))\n                end\n                local flags = v:replace(\"\\\"\", \"\\\\\\\"\")\n                table.insert(cmake_argv, (\"set(COMP_%s_FLAGS \\\"%s\\\")\"):format(kind, flags))\n                table.insert(cmake_argv, (\"add_compile_options($<$<COMPILE_LANGUAGE:%s>:${COMP_%s_FLAGS}>)\"):format(kind, kind))\n                if build_type then\n                    table.insert(cmake_argv, \"endif()\")\n                end\n                shrink = true\n                return true\n            end]]\n            -- shrink long arguments\n            if #v > 128 then\n                local flags = v:replace(\"\\\"\", \"\\\\\\\"\")\n                table.insert(cmake_argv, (\"set(%s \\\"%s\\\")\"):format(k, flags))\n                shrink = true\n                return true\n            end\n        end\n    end)\n    if shrink then\n        local cmakefile = path.join(opt.curdir and opt.curdir or oldir, \"CMakeLists.txt\")\n        io.insert(cmakefile, 1, table.concat(cmake_argv, \"\\n\"))\n    end\nend\n\nfunction configure(package, configs, opt)\n    opt = opt or {}\n    local oldir = _enter_builddir(package, opt)\n\n    -- pass configurations\n    local argv = {}\n    for name, value in pairs(_get_configs(package, configs, opt)) do\n        value = tostring(value):trim()\n        if type(name) == \"number\" then\n            if value ~= \"\" then\n                table.insert(argv, value)\n            end\n        else\n            table.insert(argv, \"-D\" .. name .. \"=\" .. value)\n        end\n    end\n    -- shrink cmake arguments, fix too long arguments\n    -- @see https://github.com/xmake-io/xmake-repo/pull/5247#discussion_r1780302212\n    _shrink_cmake_arguments(argv, oldir, opt)\n    table.insert(argv, oldir)\n\n    -- do configure\n    local cmake = assert(find_tool(\"cmake\"), \"cmake not found!\")\n    os.vrunv(cmake.program, argv, {envs = opt.envs or buildenvs(package, opt)})\n    os.cd(oldir)\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local cmake_generator = _get_cmake_generator(package, opt)\n\n    -- do configure\n    configure(package, configs, opt)\n\n    -- do build\n    local oldir = _enter_builddir(package, opt)\n    if opt.cmake_build then\n        _build_for_cmakebuild(package, configs, opt)\n    elseif cmake_generator then\n        if cmake_generator:find(\"Visual Studio\", 1, true) then\n            _build_for_msvc(package, configs, opt)\n        elseif cmake_generator == \"Ninja\" then\n            _build_for_ninja(package, configs, opt)\n        elseif cmake_generator:find(\"Makefiles\", 1, true) then\n            _build_for_make(package, configs, opt)\n        else\n            raise(\"unknown cmake generator(%s)!\", cmake_generator)\n        end\n    else\n        if package:is_plat(\"windows\") then\n            _build_for_msvc(package, configs, opt)\n        else\n            _build_for_make(package, configs, opt)\n        end\n    end\n    os.cd(oldir)\nend\n\n-- install package\nfunction install(package, configs, opt)\n    opt = opt or {}\n    local cmake_generator = _get_cmake_generator(package, opt)\n\n    -- do configure\n    configure(package, configs, opt)\n\n    -- do build and install\n    local oldir = _enter_builddir(package, opt)\n    if opt.cmake_build then\n        _install_for_cmakebuild(package, configs, opt)\n    elseif cmake_generator then\n        if cmake_generator:find(\"Visual Studio\", 1, true) then\n            _install_for_msvc(package, configs, opt)\n        elseif cmake_generator == \"Ninja\" then\n            _install_for_ninja(package, configs, opt)\n        elseif cmake_generator:find(\"Makefiles\", 1, true) then\n            _install_for_make(package, configs, opt)\n        else\n            raise(\"unknown cmake generator(%s)!\", cmake_generator)\n        end\n    else\n        if package:is_plat(\"windows\") then\n            _install_for_msvc(package, configs, opt)\n        else\n            _install_for_make(package, configs, opt)\n        end\n    end\n    if package:is_plat(\"windows\") and os.isdir(\"pdb\") then\n        if package:config(\"shared\") or not package:is_library() then\n            os.trycp(\"pdb/**.pdb\", package:installdir(\"bin\"))\n        else\n            os.trycp(\"pdb/**.pdb\", package:installdir(\"lib\"))\n        end\n    end\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/gn.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gn.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\nimport(\"package.tools.ninja\")\n\n-- get build directory\nfunction _get_builddir(opt)\n    if opt and (opt.builddir or opt.buildir) then\n        if opt.buildir then\n            wprint(\"{buildir = } has been deprecated, please use {builddir = } in gn.install\")\n        end\n        return opt.builddir or opt.buildir\n    else\n        _g.builddir = _g.builddir or (\"build_\" .. hash.uuid4():split('%-')[1])\n        return _g.builddir\n    end\nend\n\n-- get configs\nfunction _get_configs(package, configs, opt)\n    configs = configs or {}\n    if not package:is_plat(\"windows\") then\n        configs.cc  = package:build_getenv(\"cc\")\n        configs.cxx = package:build_getenv(\"cxx\")\n    end\n    if package:is_plat(\"macosx\") then\n        configs.extra_ldflags = {\"-lstdc++\"}\n        local xcode = toolchain.load(\"xcode\", {plat = package:plat(), arch = package:arch()})\n        configs.xcode_sysroot = xcode:config(\"xcode_sysroot\")\n    end\n    if package:is_plat(\"linux\") then\n        configs.target_os = \"linux\"\n    elseif package:is_plat(\"macosx\") then\n        configs.target_os = \"mac\"\n    elseif package:is_plat(\"windows\") then\n        configs.target_os = \"win\"\n    elseif package:is_plat(\"iphoneos\") then\n        configs.target_os = \"ios\"\n    elseif package:is_plat(\"android\") then\n        configs.target_os = \"android\"\n    end\n    if package:is_arch(\"x86\", \"i386\") then\n        configs.target_cpu = \"x86\"\n    elseif package:is_arch(\"x64\", \"x86_64\") then\n        configs.target_cpu = \"x64\"\n    elseif package:is_arch(\"arm64\", \"arm64-v8a\") then\n        configs.target_cpu = \"arm64\"\n    elseif package:is_arch(\"arm.*\") then\n        configs.target_cpu = \"arm\"\n    end\n    if configs.is_debug == nil then\n        configs.is_debug = package:is_debug() and true or false\n    end\n    return configs\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    local envs = {}\n    if package:is_plat(\"windows\") then\n        envs = os.joinenvs(_get_msvc(package):runenvs())\n    end\n    return envs\nend\n\n-- generate build files for ninja\nfunction generate(package, configs, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- pass configurations\n    local argv = {}\n    local args = {}\n    table.insert(argv, \"gen\")\n    table.insert(argv, _get_builddir(opt))\n    for name, value in pairs(_get_configs(package, configs, opt)) do\n        if type(value) == \"string\" then\n            table.insert(args, name .. \"=\\\"\" .. value .. \"\\\"\")\n        elseif type(value) == \"table\" then\n            table.insert(args, name .. \"=[\\\"\" .. table.concat(value, \"\\\",\\\"\") .. \"\\\"]\")\n        else\n            table.insert(args, name .. \"=\" .. tostring(value))\n        end\n    end\n    table.insert(argv, \"--args=\" .. table.concat(args, ' '))\n\n    -- do configure\n    local gn = assert(find_tool(\"gn\"), \"gn not found!\")\n    os.vrunv(gn.program, argv, {envs = opt.envs or buildenvs(package)})\nend\n\n-- build package\nfunction build(package, configs, opt)\n\n    -- generate build files\n    opt = opt or {}\n    generate(package, configs, opt)\n\n    -- do build\n    local builddir = _get_builddir(opt)\n    local targets = table.wrap(opt.targets or opt.target)\n    ninja.build(package, targets, {builddir = builddir, envs = opt.envs or buildenvs(package, opt)})\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- generate build files\n    opt = opt or {}\n    generate(package, configs, opt)\n\n    -- do build and install\n    local builddir = _get_builddir(opt)\n    local targets = table.wrap(opt.targets or opt.target)\n    ninja.install(package, targets, {builddir = builddir, envs = opt.envs or buildenvs(package, opt)})\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/jom.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        jom.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- get the number of parallel jobs\nfunction _get_parallel_njobs(opt)\n    return opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- do make\nfunction make(package, argv, opt)\n    opt = opt or {}\n    local program\n    local runenvs = opt.envs or buildenvs(package)\n    local tool = find_tool(\"jom\", {envs = runenvs})\n    if tool then\n        program = tool.program\n    end\n    assert(program, \"jom not found!\")\n    os.vrunv(program, argv or {}, {envs = runenvs, curdir = opt.curdir})\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local argv = {}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    local jobs = _get_parallel_njobs(opt)\n    local jom_argv = {\"/K\"}\n    if jobs then\n        table.insert(jom_argv, \"/J\")\n        table.insert(jom_argv, tostring(jobs))\n    end\n    configs = table.join(jom_argv, configs)\n    for name, value in pairs(configs) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- do build\n    make(package, argv, opt)\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- do build\n    opt = opt or {}\n    build(package, configs, opt)\n\n    -- do install\n    local argv = {\"install\"}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n        table.insert(argv, \"V=1\")\n    end\n    make(package, argv, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/make.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        make.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- translate bin path\nfunction _translate_bin_path(bin_path)\n    if is_host(\"windows\") and bin_path then\n        bin_path = bin_path:gsub(\"\\\\\", \"/\")\n        local bin_path_lower = bin_path:lower()\n        if not bin_path_lower:endswith(\".exe\") and not bin_path_lower:endswith(\".cmd\") and not bin_path_lower:endswith(\".bat\") then\n            bin_path = bin_path .. \".exe\"\n        end\n        return bin_path\n    end\n    return bin_path\nend\n\n-- get the build environments\nfunction buildenvs(package)\n    local envs = {}\n    local cflags   = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cflags\"))\n    local cxxflags = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cxxflags\"))\n    local asflags  = table.copy(table.wrap(package:config(\"asflags\")))\n    local ldflags  = table.copy(table.wrap(package:config(\"ldflags\")))\n    local shflags  = table.copy(table.wrap(package:config(\"shflags\")))\n    local runtimes = package:runtimes()\n    if runtimes then\n        table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"runtime\", runtimes))\n        table.join2(ldflags, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"runtime\", runtimes))\n        table.join2(shflags, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"runtime\", runtimes))\n    end\n    if package:is_plat(os.host()) then\n        if package:is_plat(\"linux\") and package:is_arch(\"i386\") then\n            table.insert(cflags,   \"-m32\")\n            table.insert(cxxflags, \"-m32\")\n            table.insert(asflags,  \"-m32\")\n            table.insert(ldflags,  \"-m32\")\n        end\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(asflags, ' ')\n        envs.LDFLAGS   = table.concat(ldflags, ' ')\n        envs.SHFLAGS   = table.concat(shflags, ' ')\n    else\n        envs.CC        = _translate_bin_path(package:build_getenv(\"cc\"))\n        envs.CXX       = _translate_bin_path(package:build_getenv(\"cxx\"))\n        envs.AS        = _translate_bin_path(package:build_getenv(\"as\"))\n        envs.AR        = _translate_bin_path(package:build_getenv(\"ar\"))\n        envs.LD        = _translate_bin_path(package:build_getenv(\"ld\"))\n        envs.LDSHARED  = _translate_bin_path(package:build_getenv(\"sh\"))\n        envs.CPP       = _translate_bin_path(package:build_getenv(\"cpp\"))\n        envs.RANLIB    = _translate_bin_path(package:build_getenv(\"ranlib\"))\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(asflags, ' ')\n        envs.ARFLAGS   = table.concat(table.wrap(package:build_getenv(\"arflags\")), ' ')\n        envs.LDFLAGS   = table.concat(ldflags, ' ')\n        envs.SHFLAGS   = table.concat(shflags, ' ')\n    end\n    local ACLOCAL_PATH = {}\n    local PKG_CONFIG_PATH = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n    end\n    -- some binary packages contain it too. e.g. libtool\n    for _, dep in ipairs(package:orderdeps()) do\n        local aclocal = path.join(dep:installdir(), \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            table.insert(ACLOCAL_PATH, aclocal)\n        end\n    end\n    envs.ACLOCAL_PATH    = path.joinenv(ACLOCAL_PATH)\n    envs.PKG_CONFIG_PATH = path.joinenv(PKG_CONFIG_PATH)\n    -- some Makefile use ComSpec to detect Windows (e.g. Makefiles generated by Premake) and require this env\n    if is_subhost(\"windows\") then\n        envs.ComSpec = os.getenv(\"ComSpec\")\n    end\n\n    return envs\nend\n\n-- do make\nfunction make(package, argv, opt)\n    opt = opt or {}\n    local program\n    local runenvs = opt.envs or buildenvs(package)\n    if package:is_plat(\"mingw\") and is_subhost(\"windows\") then\n        local mingw = assert(package:build_getenv(\"mingw\") or package:build_getenv(\"sdk\"), \"mingw not found!\")\n        program = path.join(mingw, \"bin\", \"mingw32-make.exe\")\n    else\n        local tool = find_tool(\"make\", {envs = runenvs})\n        if tool then\n            program = tool.program\n        end\n    end\n    assert(program, \"make not found!\")\n    os.vrunv(program, argv or {}, {envs = runenvs, curdir = opt.curdir})\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n\n    -- pass configurations\n    local njob = opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\n    local argv = {\"-j\" .. njob}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n        table.insert(argv, \"V=1\")\n    end\n    for name, value in pairs(configs) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- do build\n    make(package, argv, opt)\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- do build\n    opt = opt or {}\n    build(package, configs, opt)\n\n    -- do install\n    local argv = {\"install\"}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n        table.insert(argv, \"V=1\")\n    end\n    make(package, argv, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/meson.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        meson.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.executable_path\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get build directory\nfunction _get_builddir(package, opt)\n    if opt and (opt.builddir or opt.buildir) then\n        if opt.buildir then\n            wprint(\"{buildir = } has been deprecated, please use {builddir = } in meson.install\")\n        end\n        return opt.builddir or opt.buildir\n    else\n        _g.builddir = _g.builddir or package:builddir()\n        return _g.builddir\n    end\nend\n\n-- get pkg-config, we need force to find it, because package install environments will be changed\nfunction _get_pkgconfig(package)\n    -- meson need fullpath pkgconfig\n    -- @see https://github.com/xmake-io/xmake/issues/5474\n    local dep = package:dep(\"pkgconf\") or package:dep(\"pkg-config\")\n    if dep then\n        local suffix = dep:is_plat(\"windows\", \"mingw\") and \".exe\" or \"\"\n        local pkgconf = path.join(dep:installdir(\"bin\"), \"pkgconf\" .. suffix)\n        if os.isfile(pkgconf) then\n            return pkgconf\n        end\n        local pkgconfig = path.join(dep:installdir(\"bin\"), \"pkg-config\" .. suffix)\n        if os.isfile(pkgconfig) then\n            return pkgconfig\n        end\n    end\n    if package:is_plat(\"windows\") then\n        local pkgconf = find_tool(\"pkgconf\", {force = true})\n        if pkgconf then\n            return pkgconf.program\n        end\n    end\n    local pkgconfig = find_tool(\"pkg-config\", {force = true})\n    if pkgconfig then\n        return pkgconfig.program\n    end\nend\n\n-- translate flags\nfunction _translate_flags(package, flags)\n    if package:is_plat(\"android\") then\n        local flags_new = {}\n        for _, flag in ipairs(flags) do\n            if flag:startswith(\"--gcc-toolchain=\") or flag:startswith(\"--target=\") or flag:startswith(\"-isystem \") then\n                table.join2(flags_new, flag:split(\" \", {limit = 2}))\n            else\n                table.insert(flags_new, flag)\n            end\n        end\n        flags = flags_new\n    elseif package:is_plat(\"windows\") then\n        for idx, flag in ipairs(flags) do\n            -- @see https://github.com/xmake-io/xmake/issues/4407\n            if flag:startswith(\"-libpath:\") then\n                flags[idx] = flag:gsub(\"%-libpath:\", \"/libpath:\")\n            end\n        end\n    end\n    return flags\nend\n\nfunction _insert_cross_configs(package, file, opt)\n    -- host machine\n    file:print(\"[host_machine]\")\n    if opt.host_machine then\n        file:print(\"%s\", opt.host_machine)\n    elseif package:is_plat(\"iphoneos\", \"macosx\") then\n        local cpu\n        local cpu_family\n        if package:is_arch(\"arm64\") then\n            cpu = \"aarch64\"\n            cpu_family = \"aarch64\"\n        elseif package:is_arch(\"armv7\") then\n            cpu = \"arm\"\n            cpu_family = \"arm\"\n        elseif package:is_arch(\"x64\", \"x86_64\") then\n            cpu = \"x86_64\"\n            cpu_family = \"x86_64\"\n        elseif package:is_arch(\"x86\", \"i386\") then\n            cpu = \"i686\"\n            cpu_family = \"x86\"\n        else\n            raise(\"unsupported arch(%s)\", package:arch())\n        end\n        file:print(\"system = 'darwin'\")\n        file:print(\"cpu_family = '%s'\", cpu_family)\n        file:print(\"cpu = '%s'\", cpu)\n        file:print(\"endian = 'little'\")\n    elseif package:is_plat(\"android\") then\n        local cpu\n        local cpu_family\n        if package:is_arch(\"arm64-v8a\") then\n            cpu = \"aarch64\"\n            cpu_family = \"aarch64\"\n        elseif package:is_arch(\"armeabi-v7a\") then\n            cpu = \"arm\"\n            cpu_family = \"arm\"\n        elseif package:is_arch(\"x64\", \"x86_64\") then\n            cpu = \"x86_64\"\n            cpu_family = \"x86_64\"\n        elseif package:is_arch(\"x86\", \"i386\") then\n            cpu = \"i686\"\n            cpu_family = \"x86\"\n        else\n            raise(\"unsupported arch(%s)\", package:arch())\n        end\n        file:print(\"system = 'android'\")\n        file:print(\"cpu_family = '%s'\", cpu_family)\n        file:print(\"cpu = '%s'\", cpu)\n        file:print(\"endian = 'little'\")\n    elseif package:is_plat(\"mingw\") then\n        local cpu\n        local cpu_family\n        if package:is_arch(\"x64\", \"x86_64\") then\n            cpu = \"x86_64\"\n            cpu_family = \"x86_64\"\n        elseif package:is_arch(\"x86\", \"i386\") then\n            cpu = \"i686\"\n            cpu_family = \"x86\"\n        else\n            raise(\"unsupported arch(%s)\", package:arch())\n        end\n        file:print(\"system = 'windows'\")\n        file:print(\"cpu_family = '%s'\", cpu_family)\n        file:print(\"cpu = '%s'\", cpu)\n        file:print(\"endian = 'little'\")\n    elseif package:is_plat(\"windows\") then\n        local cpu\n        local cpu_family\n        if package:is_arch(\"arm64\", \"arm64ec\") then\n            cpu = \"aarch64\"\n            cpu_family = \"aarch64\"\n        elseif package:is_arch(\"x86\") then\n            cpu = \"x86\"\n            cpu_family = \"x86\"\n        elseif package:is_arch(\"x64\") then\n            cpu = \"x86_64\"\n            cpu_family = \"x86_64\"\n        else\n            raise(\"unsupported arch(%s)\", package:arch())\n        end\n        file:print(\"system = 'windows'\")\n        file:print(\"cpu_family = '%s'\", cpu_family)\n        file:print(\"cpu = '%s'\", cpu)\n        file:print(\"endian = 'little'\")\n    elseif package:is_plat(\"wasm\") then\n        file:print(\"system = 'emscripten'\")\n        file:print(\"cpu_family = '%s'\", package:arch())\n        file:print(\"cpu = '%s'\", package:arch())\n        file:print(\"endian = 'little'\")\n    else\n        local cpu = package:arch()\n        if package:is_arch(\"arm64\") or package:is_arch(\"aarch64\") then\n            cpu = \"aarch64\"\n        elseif package:is_arch(\"arm.*\") then\n            cpu = \"arm\"\n        end\n        local cpu_family = cpu\n        file:print(\"system = '%s'\", package:targetos() or \"linux\")\n        file:print(\"cpu_family = '%s'\", cpu_family)\n        file:print(\"cpu = '%s'\", cpu)\n        file:print(\"endian = 'little'\")\n    end\nend\n\n-- is the toolchain compatible with the host?\nfunction _is_toolchain_compatible_with_host(package)\n    for _, name in ipairs(package:config(\"toolchains\")) do\n        if toolchain_utils.is_compatible_with_host(name) then\n            return true\n        end\n    end\nend\n\n-- get cross file\nfunction _get_configs_file(package, opt)\n    opt = opt or {}\n    local configsfile = path.join(_get_builddir(package, opt), \"configs_file.txt\")\n    if not os.isfile(configsfile) then\n        local file = io.open(configsfile, \"w\")\n        -- binaries\n        file:print(\"[binaries]\")\n        local cc = package:build_getenv(\"cc\")\n        if cc then\n            file:print(\"c=['%s']\", executable_path(cc))\n        end\n\n        local cxx = package:build_getenv(\"cxx\")\n        if cxx then\n            -- https://github.com/xmake-io/xmake/discussions/4979\n            if package:has_tool(\"cxx\", \"clang\", \"gcc\") then\n                local dir = path.directory(cxx)\n                local name = path.filename(cxx)\n                name = name:gsub(\"clang$\", \"clang++\")\n                name = name:gsub(\"clang%-\", \"clang++-\") -- clang-xx\n                name = name:gsub(\"clang%.\", \"clang++.\") -- clang.exe\n                name = name:gsub(\"gcc$\", \"g++\")\n                name = name:gsub(\"gcc%-\", \"g++-\")\n                name = name:gsub(\"gcc%.\", \"g++.\")\n                if dir and dir ~= \".\" then\n                    cxx = path.join(dir, name)\n                else\n                    cxx = name\n                end\n            end\n            file:print(\"cpp=['%s']\", executable_path(cxx))\n        end\n\n        local ld = package:build_getenv(\"ld\")\n        if ld then\n            file:print(\"ld=['%s']\", executable_path(ld))\n        end\n        -- we cannot pass link.exe to ar for msvc, it will raise `unknown linker`\n        if not package:is_plat(\"windows\") then\n            local ar = package:build_getenv(\"ar\")\n            if ar then\n                file:print(\"ar=['%s']\", executable_path(ar))\n            end\n        end\n        local strip = package:build_getenv(\"strip\")\n        if strip then\n            file:print(\"strip=['%s']\", executable_path(strip))\n        end\n        local ranlib = package:build_getenv(\"ranlib\")\n        if ranlib then\n            file:print(\"ranlib=['%s']\", executable_path(ranlib))\n        end\n        if package:is_plat(\"mingw\", \"msys\", \"windows\") then\n            local mrc = package:build_getenv(\"mrc\")\n            if mrc then\n                file:print(\"windres=['%s']\", executable_path(mrc))\n            end\n            local dlltool = package:build_getenv(\"dlltool\")\n            if dlltool then\n                file:print(\"dlltool=['%s']\", executable_path(dlltool))\n            end\n        end\n        local cmake = find_tool(\"cmake\")\n        if cmake then\n            file:print(\"cmake=['%s']\", executable_path(cmake.program))\n        end\n        local pkgconfig = _get_pkgconfig(package)\n        if pkgconfig then\n            file:print(\"pkgconfig=['%s']\", executable_path(pkgconfig))\n        end\n        file:print(\"\")\n\n        -- built-in options\n        file:print(\"[built-in options]\")\n        local cflags   = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cflags\"))\n        local cxxflags = table.join(table.wrap(package:build_getenv(\"cxflags\")), package:build_getenv(\"cxxflags\"))\n        local asflags  = table.wrap(package:build_getenv(\"asflags\"))\n        local arflags  = table.wrap(package:build_getenv(\"arflags\"))\n        local ldflags  = table.wrap(package:build_getenv(\"ldflags\"))\n        local shflags  = table.wrap(package:build_getenv(\"shflags\"))\n        table.join2(cflags,   opt.cflags)\n        table.join2(cflags,   opt.cxflags)\n        table.join2(cxxflags, opt.cxxflags)\n        table.join2(cxxflags, opt.cxflags)\n        table.join2(asflags,  opt.asflags)\n        table.join2(ldflags,  opt.ldflags)\n        table.join2(shflags,  opt.shflags)\n        table.join2(cflags,   _get_cflags_from_packagedeps(package, opt))\n        table.join2(cxxflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(ldflags,  _get_ldflags_from_packagedeps(package, opt))\n        table.join2(shflags,  _get_ldflags_from_packagedeps(package, opt))\n        -- add runtimes flags\n        for _, runtime in ipairs(package:runtimes()) do\n            if not runtime:startswith(\"M\") then\n                table.join2(cxxflags, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"runtime\", {runtime}))\n                table.join2(ldflags, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"runtime\", {runtime}))\n                table.join2(shflags, toolchain_utils.map_linkflags_for_package(package, \"shared\", {\"cxx\"}, \"runtime\", {runtime}))\n            end\n        end\n        if #cflags > 0 then\n            file:print(\"c_args=['%s']\", table.concat(cflags, \"', '\"))\n        end\n        if #cxxflags > 0 then\n            file:print(\"cpp_args=['%s']\", table.concat(cxxflags, \"', '\"))\n        end\n        local linkflags = table.join(ldflags or {}, shflags)\n        if #linkflags > 0 then\n            file:print(\"c_link_args=['%s']\", table.concat(linkflags, \"', '\"))\n            file:print(\"cpp_link_args=['%s']\", table.concat(linkflags, \"', '\"))\n        end\n\n        if package:is_cross() or opt.cross then\n            file:print(\"\")\n            _insert_cross_configs(package, file, opt)\n            file:print(\"\")\n        end\n        file:close()\n    end\n    return configsfile\nend\n\n-- get configs\nfunction _get_configs(package, configs, opt)\n\n    -- add prefix\n    configs = configs or {}\n    opt._configs_str = string.serialize(configs, {indent = false, strip = true})\n    table.insert(configs, \"--prefix=\" .. (opt.prefix or package:installdir()))\n    table.insert(configs, \"--libdir=lib\")\n\n    -- set build type\n    table.insert(configs, \"-Dbuildtype=\" .. (package:debug() and \"debug\" or \"release\"))\n\n    -- add -fpic\n    if package:is_plat(\"linux\") and package:config(\"pic\") ~= false then\n        table.insert(configs, \"-Db_staticpic=true\")\n    end\n\n    -- add lto\n    if package:config(\"lto\") then\n        table.insert(configs, \"-Db_lto=true\")\n    end\n\n    -- add asan\n    if package:config(\"asan\") then\n        table.insert(configs, \"-Db_sanitize=address\")\n    end\n\n    -- add library kind\n    if package:is_library() then\n        local has_already_libflag = opt._configs_str and opt._configs_str:find(\"default_library\", 1, true)\n        if not has_already_libflag then\n            table.insert(configs, \"-Ddefault_library=\".. (package:config(\"shared\") and \"shared\" or \"static\"))\n        end\n    end\n\n    -- add vs runtimes flags\n    if package:is_plat(\"windows\") then\n        table.insert(configs, \"--vsenv\")\n        if package:has_runtime(\"MT\") then\n            table.insert(configs, \"-Db_vscrt=mt\")\n        elseif package:has_runtime(\"MTd\") then\n            table.insert(configs, \"-Db_vscrt=mtd\")\n        elseif package:has_runtime(\"MD\") then\n            table.insert(configs, \"-Db_vscrt=md\")\n        elseif package:has_runtime(\"MDd\") then\n            table.insert(configs, \"-Db_vscrt=mdd\")\n        end\n    end\n\n    -- add cross file\n    if package:is_cross() or package:is_plat(\"mingw\") then\n        table.insert(configs, \"--cross-file=\" .. _get_configs_file(package, opt))\n    elseif package:config(\"toolchains\") then\n        if _is_toolchain_compatible_with_host(package) then\n            table.insert(configs, \"--native-file=\" .. _get_configs_file(package, opt))\n        else\n            table.insert(configs, \"--cross-file=\" .. _get_configs_file(package, table.join2(opt, {cross = true})))\n        end\n    end\n\n    -- add build directory\n    table.insert(configs, _get_builddir(package, opt))\n    return configs\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get msvc run environments\nfunction _get_msvc_runenvs(package)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- fix libname on windows\nfunction _fix_libname_on_windows(package)\n    for _, lib in ipairs(os.files(path.join(package:installdir(\"lib\"), \"lib*.a\"))) do\n        os.mv(lib, (lib:gsub(\"(.+)\\\\lib(.-)%.a\", \"%1\\\\%2.lib\")))\n    end\nend\n\n-- get cflags from package deps\nfunction _get_cflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    -- @see https://github.com/xmake-io/xmake-repo/pull/4973#issuecomment-2295890196\n    local result = {}\n    if values then\n        if values.defines then\n            table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"define\", values.defines))\n        end\n        if values.includedirs then\n            table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"includedir\", values.includedirs))\n        end\n        if values.sysincludedirs then\n            table.join2(result, toolchain_utils.map_compflags_for_package(package, \"cxx\", \"sysincludedir\", values.sysincludedirs))\n        end\n    end\n    return _translate_flags(package, result)\nend\n\n-- get ldflags from package deps\nfunction _get_ldflags_from_packagedeps(package, opt)\n    local values\n    for _, depname in ipairs(opt.packagedeps) do\n        local dep = type(depname) ~= \"string\" and depname or package:librarydep(depname)\n        if dep then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                if values then\n                    values = values .. fetchinfo\n                else\n                    values = fetchinfo\n                end\n            end\n        end\n    end\n    local result = {}\n    if values then\n        if values.linkdirs then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"linkdir\", values.linkdirs))\n        end\n        if values.links then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"link\", values.links))\n        end\n        if values.syslinks then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"syslink\", values.syslinks))\n        end\n        if values.frameworks then\n            table.join2(result, toolchain_utils.map_linkflags_for_package(package, \"binary\", {\"cxx\"}, \"framework\", values.frameworks))\n        end\n    end\n    return _translate_flags(package, result)\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    local envs = {}\n    if not is_host(\"windows\") and package:is_plat(\"windows\") then\n        local msvc = package:toolchain(\"msvc\") or package:toolchain(\"clang\") or package:toolchain(\"clang-cl\")\n        assert(msvc:check(), \"msvc envs not found!\") -- we need to check vs envs if it has been not checked yet\n        envs = os.joinenvs(msvc:runenvs())\n    end\n\n    opt = opt or {}\n    if package:is_plat(os.host()) then\n        local cflags   = table.join(table.wrap(package:config(\"cxflags\")), package:config(\"cflags\"))\n        local cxxflags = table.join(table.wrap(package:config(\"cxflags\")), package:config(\"cxxflags\"))\n        local asflags  = table.wrap(package:config(\"asflags\"))\n        local ldflags  = table.wrap(package:config(\"ldflags\"))\n        local shflags  = table.wrap(package:config(\"shflags\"))\n        table.join2(cflags,   opt.cflags)\n        table.join2(cflags,   opt.cxflags)\n        table.join2(cxxflags, opt.cxxflags)\n        table.join2(cxxflags, opt.cxflags)\n        table.join2(asflags,  opt.asflags)\n        table.join2(ldflags,  opt.ldflags)\n        table.join2(shflags,  opt.shflags)\n        table.join2(cflags,   _get_cflags_from_packagedeps(package, opt))\n        table.join2(cxxflags, _get_cflags_from_packagedeps(package, opt))\n        table.join2(ldflags,  _get_ldflags_from_packagedeps(package, opt))\n        table.join2(shflags,  _get_ldflags_from_packagedeps(package, opt))\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(asflags, ' ')\n        envs.LDFLAGS   = table.concat(ldflags, ' ')\n        envs.SHFLAGS   = table.concat(shflags, ' ')\n        if package:is_plat(\"windows\") then\n            envs = os.joinenvs(envs, _get_msvc_runenvs(package))\n            local pkgconf = _get_pkgconfig(package)\n            if pkgconf then\n                envs.PKG_CONFIG = pkgconf\n            end\n        end\n    end\n    local ACLOCAL_PATH = {}\n    local PKG_CONFIG_PATH = {}\n    local CMAKE_LIBRARY_PATH = {}\n    local CMAKE_INCLUDE_PATH = {}\n    local CMAKE_PREFIX_PATH  = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        -- meson may also use cmake to find dependencies\n        if dep:is_system() then\n            local fetchinfo = dep:fetch()\n            if fetchinfo then\n                table.join2(CMAKE_LIBRARY_PATH, fetchinfo.linkdirs)\n                table.join2(CMAKE_INCLUDE_PATH, fetchinfo.includedirs)\n                table.join2(CMAKE_INCLUDE_PATH, fetchinfo.sysincludedirs)\n            end\n        else\n            table.join2(CMAKE_PREFIX_PATH, dep:installdir())\n        end\n    end\n    -- some binary packages contain it too. e.g. libtool\n    for _, dep in ipairs(package:orderdeps()) do\n        local aclocal = path.join(dep:installdir(), \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            table.insert(ACLOCAL_PATH, aclocal)\n        end\n    end\n    envs.ACLOCAL_PATH       = path.joinenv(ACLOCAL_PATH)\n    envs.CMAKE_LIBRARY_PATH = path.joinenv(CMAKE_LIBRARY_PATH)\n    envs.CMAKE_INCLUDE_PATH = path.joinenv(CMAKE_INCLUDE_PATH)\n    envs.CMAKE_PREFIX_PATH  = path.joinenv(CMAKE_PREFIX_PATH)\n    envs.PKG_CONFIG_PATH    = path.joinenv(PKG_CONFIG_PATH)\n    return envs\nend\n\n-- generate build files for ninja\nfunction generate(package, configs, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- pass configurations\n    -- TODO: support more backends https://mesonbuild.com/Commands.html#setup\n    local argv = {\"setup\"}\n    for name, value in pairs(_get_configs(package, configs, opt)) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, \"--\" .. name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- do configure\n    local meson = assert(find_tool(\"meson\"), \"meson not found!\")\n    os.vrunv(meson.program, argv, {envs = opt.envs or buildenvs(package, opt)})\nend\n\n-- build package\nfunction build(package, configs, opt)\n\n    -- generate build files\n    opt = opt or {}\n    generate(package, configs, opt)\n\n    -- configurate build\n    local builddir = _get_builddir(package, opt)\n    local njob = opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\n    local argv = {\"compile\", \"-C\", builddir}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"-v\")\n    end\n    table.insert(argv, \"-j\")\n    table.insert(argv, njob)\n\n    -- do build\n    local meson = assert(find_tool(\"meson\"), \"meson not found!\")\n    os.vrunv(meson.program, argv, {envs = opt.envs or buildenvs(package, opt)})\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- do build\n    opt = opt or {}\n    build(package, configs, opt)\n\n    -- configure install\n    local builddir = _get_builddir(package, opt)\n    local argv = {\"install\", \"-C\", builddir}\n\n    -- do install\n    local meson = assert(find_tool(\"meson\"), \"meson not found!\")\n    os.vrunv(meson.program, argv, {envs = opt.envs or buildenvs(package, opt)})\n\n    -- fix static libname on windows\n    if package:is_plat(\"windows\") and not package:config(\"shared\") then\n        _fix_libname_on_windows(package)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/msbuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        msbuild.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.upgrade_vsproj\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get the number of parallel jobs\nfunction _get_parallel_njobs(opt)\n    return opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\nend\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get msvc run environments\nfunction _get_msvc_runenvs(package)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- get vs arch\nfunction _get_vsarch(package)\n    local arch = package:arch()\n    if arch == 'x86' or arch == 'i386' then return \"Win32\" end\n    if arch == 'x86_64' then return \"x64\" end\n    if arch:startswith('arm64') then return \"ARM64\" end\n    if arch:startswith('arm') then return \"ARM\" end\n    return arch\nend\n\n-- get configs\nfunction _get_configs(package, configs, opt)\n    local jobs = _get_parallel_njobs(opt)\n    configs = configs or {}\n    local configs_str = string.serialize(configs, {indent = false, strip = true})\n    table.insert(configs, \"-nologo\")\n    table.insert(configs, (jobs ~= nil and format(\"-m:%d\", jobs) or \"-m\"))\n    if not configs_str:find(\"p:Configuration=\", 1, true) then\n        table.insert(configs, \"-p:Configuration=\" .. (package:is_debug() and \"Debug\" or \"Release\"))\n    end\n    if not configs_str:find(\"p:Platform=\", 1, true) then\n        table.insert(configs, \"-p:Platform=\" .. _get_vsarch(package))\n    end\n    if not configs_str:find(\"p:PlatformToolset=\", 1, true) then\n        local vs_toolset = toolchain_utils.get_vs_toolset_ver(_get_msvc(package):config(\"vs_toolset\") or config.get(\"vs_toolset\"))\n        if vs_toolset then\n            table.insert(configs, \"/p:PlatformToolset=\" .. vs_toolset)\n        end\n    end\n    if project.policy(\"package.msbuild.multi_tool_task\") or package:policy(\"package.msbuild.multi_tool_task\") then\n        table.insert(configs, \"/p:UseMultiToolTask=true\")\n        table.insert(configs, \"/p:EnforceProcessCountAcrossBuilds=true\")\n        if jobs then\n            table.insert(configs, format(\"/p:MultiProcMaxCount=%d\", jobs))\n        end\n    end\n    return configs\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    return _get_msvc_runenvs(package)\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n\n    -- pass configurations\n    local argv = {}\n    for name, value in pairs(_get_configs(package, configs, opt)) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- upgrade vs solution file?\n    -- @see https://github.com/xmake-io/xmake/issues/3871\n    if opt.upgrade then\n        local msvc = _get_msvc(package)\n        for _, value in ipairs(opt.upgrade) do\n            upgrade_vsproj.upgrade(value, table.join(opt, {msvc = msvc}))\n        end\n    end\n\n    -- do build\n    local envs = opt.envs or buildenvs(package, opt)\n    local msbuild = find_tool(\"msbuild\", {envs = envs})\n    os.vrunv(msbuild.program, argv, {envs = envs})\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/ninja.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ninja.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\nfunction _default_argv(package, configs, opt)\n    opt = opt or {}\n    local builddir = opt.builddir or opt.buildir or os.curdir()\n    local njob = opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\n    if opt.buildir then\n        wprint(\"{buildir = } has been deprecated, please use {builddir = } in ninja.install\")\n    end\n\n    local argv = {}\n    local targets = table.wrap(opt.targets or opt.target)\n    if #targets ~= 0 then\n        table.join2(argv, targets)\n    end\n    table.insert(argv, \"-C\")\n    table.insert(argv, builddir)\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"-v\")\n    end\n    table.insert(argv, \"-j\")\n    table.insert(argv, njob)\n    if configs then\n        table.join2(argv, configs)\n    end\n\n    return argv\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local argv = {}\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    table.join2(argv, _default_argv(package, configs, opt))\n    os.vrunv(ninja.program, argv, {envs = opt.envs})\nend\n\n-- install package\nfunction install(package, configs, opt)\n    opt = opt or {}\n    local argv = {\"install\"}\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    table.join2(argv, _default_argv(package, configs, opt))\n    os.vrunv(ninja.program, argv, {envs = opt.envs})\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/nmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        nmake.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- get msvc\nfunction _get_msvc(package)\n    local msvc = package:toolchain(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    return os.joinenvs(_get_msvc(package):runenvs())\nend\n\n-- do make\nfunction make(package, argv, opt)\n    opt = opt or {}\n    local program\n    local runenvs = opt.envs or buildenvs(package)\n    local tool = find_tool(\"nmake\", {envs = runenvs})\n    if tool then\n        program = tool.program\n    end\n    assert(program, \"nmake not found!\")\n    os.vrunv(program, argv or {}, {envs = runenvs, curdir = opt.curdir})\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local argv = {}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    for name, value in pairs(configs) do\n        value = tostring(value):trim()\n        if value ~= \"\" then\n            if type(name) == \"number\" then\n                table.insert(argv, value)\n            else\n                table.insert(argv, name .. \"=\" .. value)\n            end\n        end\n    end\n\n    -- do build\n    make(package, argv, opt)\nend\n\n-- install package\nfunction install(package, configs, opt)\n\n    -- do build\n    opt = opt or {}\n    build(package, configs, opt)\n\n    -- do install\n    local argv = {\"install\"}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n        table.insert(argv, \"V=1\")\n    end\n    make(package, argv, opt)\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/scons.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      PucklaMotzer09\n-- @file        scons.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- get configs\nfunction _get_configs(package, configs)\n    local configs = configs or {}\n    local items = hashset.new()\n    for _, item in ipairs(configs) do\n        local name = item:split(\"=\")[1]\n        items:insert(name)\n    end\n    if not items:has(\"target\") then\n        table.insert(configs, \"target=\" .. (package:is_debug() and \"debug\" or \"release\"))\n    end\n    if not items:has(\"use_mingw\") then\n        table.insert(configs, \"use_mingw=\" .. (package:is_plat(\"mingw\", \"cygwin\", \"msys\") and \"yes\" or \"no\"))\n    end\n    if not items:has(\"platform\") then\n        if package:is_plat(\"android\") then\n            local scons_android_arch = \"armv7\"\n            if package:is_arch(\"arm64-v8a\") then\n                scons_android_arch = \"arm64v8\"\n            end\n            table.insert(configs, \"platform=android\")\n            table.insert(configs, \"android_arch=\" .. scons_android_arch)\n        elseif package:is_plat(\"iphoneos\") then\n            table.insert(configs, \"platform=ios\")\n            table.insert(configs, \"ios_arch=\" .. package:arch())\n        elseif package:is_plat(\"macosx\") then\n            table.insert(configs, \"platform=osx\")\n        elseif package:is_plat(\"windows\", \"mingw\", \"cygwin\", \"msys\") then\n            table.insert(configs, \"platform=windows\")\n        elseif package:is_plat(\"linux\") then\n            table.insert(configs, \"platform=linux\")\n        elseif package:is_plat(\"bsd\") then\n            table.insert(configs, \"platform=freebsd\")\n        end\n    end\n    if not items:has(\"bits\") and package:is_plat(\"x86_64\", \"x86\", \"i386\", \"x64\") then\n        table.insert(\"bits=\" .. (package:is_arch(\"x86\", \"i386\") and \"32\" or \"64\"))\n    end\n    return configs\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    opt = opt or {}\n    local envs = {}\n    if package:is_plat(\"android\") then\n        local ndk = toolchain.load(\"ndk\", {plat = package:plat(), arch = package:arch()})\n        envs.ANDROID_NDK_ROOT = ndk:config(\"ndk\")\n    end\n    local ACLOCAL_PATH = {}\n    local PKG_CONFIG_PATH = {}\n    for _, dep in ipairs(package:librarydeps({private = true})) do\n        local pkgconfig = path.join(dep:installdir(), \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n        pkgconfig = path.join(dep:installdir(), \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            table.insert(PKG_CONFIG_PATH, pkgconfig)\n        end\n    end\n    -- some binary packages contain it too. e.g. libtool\n    for _, dep in ipairs(package:orderdeps()) do\n        local aclocal = path.join(dep:installdir(), \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            table.insert(ACLOCAL_PATH, aclocal)\n        end\n    end\n    envs.ACLOCAL_PATH    = path.joinenv(ACLOCAL_PATH)\n    envs.PKG_CONFIG_PATH = path.joinenv(PKG_CONFIG_PATH)\n    return envs\nend\n\n-- build package\nfunction build(package, configs, opt)\n    opt = opt or {}\n    local builddir = opt.builddir or opt.buildir or os.curdir()\n    if opt.buildir then\n        wprint(\"{buildir = } has been deprecated, please use {builddir = } in scons.install\")\n    end\n    local njob = opt.jobs or option.get(\"jobs\") or tostring(os.default_njob())\n    local scons = assert(find_tool(\"scons\"), \"scons not found!\")\n    local argv = {\"-C\", builddir, \"-j\", njob}\n    configs = _get_configs(package, configs)\n    if configs then\n        table.join2(argv, configs)\n    end\n    os.vrunv(scons.program, argv, {envs = opt.envs or buildenvs(package, opt)})\nend\n"
  },
  {
    "path": "xmake/modules/package/tools/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.project\")\nimport(\"core.package.repository\")\nimport(\"private.action.require.impl.package\", {alias = \"require_package\"})\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get config from toolchains\nfunction _get_config_from_toolchains(package, name)\n    for _, toolchain_inst in ipairs(package:toolchains()) do\n        local value = toolchain_inst:config(name)\n        if value ~= nil then\n            return value\n        end\n    end\nend\n\n-- is the toolchain compatible with the host?\nfunction _is_toolchain_compatible_with_host(package)\n    for _, name in ipairs(package:config(\"toolchains\")) do\n        if toolchain_utils.is_compatible_with_host(name) then\n            return true\n        end\n    end\nend\n\n-- get configs for qt\nfunction _get_configs_for_qt(package, configs, opt)\n    local names = {\"qt\", \"qt_sdkver\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\nend\n\n-- get configs for vcpkg\nfunction _get_configs_for_vcpkg(package, configs, opt)\n    local names = {\"vcpkg\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\nend\n\n-- get configs for windows\nfunction _get_configs_for_windows(package, configs, opt)\n    local names = {\"vs\", \"vs_toolset\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\n    -- pass runtimes from package configs\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\n\n    -- we can switch some toolchains, e.g. llvm/clang\n    if package:config(\"toolchains\") and _is_toolchain_compatible_with_host(package) then\n        _get_configs_for_host_toolchain(package, configs, opt)\n    end\n\n    if not is_host(\"windows\") then\n        local sdkdir = _get_config_from_toolchains(package, \"sdkdir\") or get_config(\"sdk\")\n        if sdkdir and #sdkdir > 0 then\n            table.insert(configs, \"--sdk=\" .. sdkdir)\n        end\n    end\nend\n\n-- get configs for appleos\nfunction _get_configs_for_appleos(package, configs, opt)\n    local xcode = get_config(\"xcode\")\n    if xcode then\n        table.insert(configs, \"--xcode=\" .. xcode)\n    end\n    local xcode_sdkver = get_config(\"xcode_sdkver\")\n    if xcode_sdkver then\n        table.insert(configs, \"--xcode_sdkver=\" .. xcode_sdkver)\n    end\n    local target_minver = get_config(\"target_minver\")\n    if target_minver then\n        table.insert(configs, \"--target_minver=\" .. target_minver)\n    end\n    local appledev = get_config(\"appledev\")\n    if appledev then\n        table.insert(configs, \"--appledev=\" .. appledev)\n    end\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\nend\n\n-- get configs for android\nfunction _get_configs_for_android(package, configs, opt)\n    local names = {\"ndk\", \"ndk_sdkver\", \"ndk_stdcxx\", \"ndk_cxxstl\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\nend\n\n-- get configs for mingw\nfunction _get_configs_for_mingw(package, configs, opt)\n    local names = {\"mingw\", \"sdk\", \"ld\", \"sh\", \"ar\", \"cc\", \"cxx\", \"mm\", \"mxx\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\nend\n\n-- get configs for generic, e.g. linux, macosx, bsd host platforms\nfunction _get_configs_for_generic(package, configs, opt)\n    local names = {\"ld\", \"sh\", \"ar\", \"cc\", \"cxx\", \"mm\", \"mxx\"}\n    if package:is_plat(\"macosx\") then\n        table.join2(names, \"xcode\", \"xcode_sdkver\", \"target_minver\", \"appledev\")\n    end\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\nend\n\n-- get configs for host toolchain\nfunction _get_configs_for_host_toolchain(package, configs, opt)\n    local bindir = _get_config_from_toolchains(package, \"bindir\") or get_config(\"bin\")\n    if bindir then\n        table.insert(configs, \"--bin=\" .. bindir)\n    end\n    local sdkdir = _get_config_from_toolchains(package, \"sdkdir\") or get_config(\"sdk\")\n    if sdkdir then\n        table.insert(configs, \"--sdk=\" .. sdkdir)\n    end\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    local toolchain_name = get_config(\"toolchain\")\n    if toolchain_name then\n        table.insert(configs, \"--toolchain=\" .. toolchain_name)\n    end\n    _get_configs_for_qt(package, configs, opt)\n    _get_configs_for_vcpkg(package, configs, opt)\nend\n\n-- get configs for cross\nfunction _get_configs_for_cross(package, configs, opt)\n    local cross = _get_config_from_toolchains(package, \"cross\") or get_config(\"cross\")\n    if cross then\n        table.insert(configs, \"--cross=\" .. cross)\n    end\n    local bindir = _get_config_from_toolchains(package, \"bindir\") or get_config(\"bin\")\n    if bindir then\n        table.insert(configs, \"--bin=\" .. bindir)\n    end\n    local sdkdir = _get_config_from_toolchains(package, \"sdkdir\") or get_config(\"sdk\")\n    if sdkdir then\n        table.insert(configs, \"--sdk=\" .. sdkdir)\n    end\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        table.insert(configs, \"--runtimes=\" .. runtimes)\n    end\n    local toolchain_name = get_config(\"toolchain\")\n    if toolchain_name then\n        table.insert(configs, \"--toolchain=\" .. toolchain_name)\n    end\n    local names = {\"ld\", \"sh\", \"ar\", \"cc\", \"cxx\", \"mm\", \"mxx\"}\n    for _, name in ipairs(names) do\n        local value = get_config(name)\n        if value ~= nil then\n            table.insert(configs, \"--\" .. name .. \"=\" .. tostring(value))\n        end\n    end\nend\n\n-- get configs\nfunction _get_configs(package, configs, opt)\n    opt = opt or {}\n    local configs  = configs or {}\n    local cflags   = table.join(table.wrap(package:config(\"cflags\")),   get_config(\"cflags\"))\n    local cxflags  = table.join(table.wrap(package:config(\"cxflags\")),  get_config(\"cxflags\"))\n    local cxxflags = table.join(table.wrap(package:config(\"cxxflags\")), get_config(\"cxxflags\"))\n    local asflags  = table.join(table.wrap(package:config(\"asflags\")),  get_config(\"asflags\"))\n    local ldflags  = table.join(table.wrap(package:config(\"ldflags\")),  get_config(\"ldflags\"))\n    local shflags  = table.join(table.wrap(package:config(\"shflags\")),  get_config(\"shflags\"))\n    table.insert(configs, \"--plat=\" .. package:plat())\n    table.insert(configs, \"--arch=\" .. package:arch())\n    if configs.mode == nil then\n        table.insert(configs, \"--mode=\" .. (package:is_debug() and \"debug\" or \"release\"))\n    end\n    if configs.kind == nil then\n        table.insert(configs, \"--kind=\" .. (package:config(\"shared\") and \"shared\" or \"static\"))\n    end\n    if package:is_plat(\"windows\") then\n        _get_configs_for_windows(package, configs, opt)\n    elseif package:is_plat(\"android\") then\n        _get_configs_for_android(package, configs, opt)\n    elseif package:is_plat(\"iphoneos\", \"watchos\", \"appletvos\") or\n        -- for cross-compilation on macOS, @see https://github.com/xmake-io/xmake/issues/2804\n        (package:is_plat(\"macosx\") and (get_config(\"appledev\") or not package:is_arch(os.subarch()))) then\n        _get_configs_for_appleos(package, configs, opt)\n    elseif package:is_plat(\"mingw\") then\n        _get_configs_for_mingw(package, configs, opt)\n    elseif package:is_cross() then\n        _get_configs_for_cross(package, configs, opt)\n    elseif package:config(\"toolchains\") then\n        -- we still need find system libraries,\n        -- it just pass toolchain environments if the toolchain is compatible with host\n        if _is_toolchain_compatible_with_host(package) then\n            _get_configs_for_host_toolchain(package, configs, opt)\n        else\n            _get_configs_for_cross(package, configs, opt)\n        end\n    else\n        _get_configs_for_generic(package, configs, opt)\n    end\n\n    local policies = get_config(\"policies\")\n    local policies_list = policies and policies:split(\",\") or {}\n    if package:config(\"lto\") and (not policies or not policies:find(\"build.optimization.lto\", 1, true)) then\n        table.insert(policies_list, \"build.optimization.lto\")\n    end\n    if package:config(\"asan\") and (not policies or not policies:find(\"build.sanitizer.address\", 1, true)) then\n        table.insert(policies_list, \"build.sanitizer.address\")\n    end\n    if not package:use_external_includes() and (not policies or not policies:find(\"package.include_external_headers\", 1, true)) then\n        table.insert(policies_list, \"package.include_external_headers:n\")\n    end\n    if policies and policies:find(\"package.build.ccache\", 1, true) then\n        table.insert(configs, \"--ccachedir=\" .. path.join(path.directory(package:cachedir()), \"build_cache\"))\n        table.insert(policies_list, \"build.ccache\")\n    end\n    if #policies_list > 0 then\n        table.insert(configs, \"--policies=\" .. table.concat(policies_list, \",\"))\n    end\n\n    if not package:is_plat(\"windows\", \"mingw\") and package:config(\"pic\") ~= false then\n        table.insert(cxflags, \"-fPIC\")\n    end\n    if cflags and #cflags > 0 then\n        table.insert(configs, \"--cflags=\" .. table.concat(cflags, ' '))\n    end\n    if cxflags and #cxflags > 0 then\n        table.insert(configs, \"--cxflags=\" .. table.concat(cxflags, ' '))\n    end\n    if cxxflags and #cxxflags > 0 then\n        table.insert(configs, \"--cxxflags=\" .. table.concat(cxxflags, ' '))\n    end\n    if asflags and #asflags > 0 then\n        table.insert(configs, \"--asflags=\" .. table.concat(asflags, ' '))\n    end\n    if ldflags and #ldflags > 0 then\n        table.insert(configs, \"--ldflags=\" .. table.concat(ldflags, ' '))\n    end\n    if shflags and #shflags > 0 then\n        table.insert(configs, \"--shflags=\" .. table.concat(shflags, ' '))\n    end\n    local builddir = opt.builddir or opt.buildir or package:builddir()\n    if builddir then\n        table.insert(configs, \"--builddir=\" .. builddir)\n    end\n    if opt.buildir then\n        wprint(\"{buildir = } has been deprecated, please use {builddir = } in xmake.install\")\n    end\n    return configs\nend\n\n-- maybe in project?\n-- @see https://github.com/xmake-io/xmake/issues/3720\nfunction _maybe_in_project(package)\n    local dir = package:sourcedir() or package:cachedir()\n    local parentdir = path.directory(dir)\n    while parentdir and os.isdir(parentdir) do\n        if os.isfile(path.join(parentdir, \"xmake.lua\")) then\n            return true\n        end\n        parentdir = path.directory(parentdir)\n    end\nend\n\n-- set some builtin global options from the parent xmake\nfunction _set_builtin_argv(package, argv)\n    -- if the package cache directory is modified,\n    -- we need to force the project directory to be specified to avoid interference by the upper level xmake.lua.\n    -- and we also need to put `-P` in the first argument to avoid option.parse() parsing errors\n    if _maybe_in_project(package) then\n        table.insert(argv, \"-P\")\n        table.insert(argv, os.curdir())\n    end\n    for _, name in ipairs({\"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\", \"root\"}) do\n        local value = option.get(name)\n        if type(value) == \"boolean\" then\n            table.insert(argv, \"--\" .. name)\n        elseif value ~= nil then\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        end\n    end\nend\n\n-- get require info of package\nfunction _get_package_requireinfo(packagename)\n    if os.isfile(os.projectfile()) then\n        local requires_str, requires_extra = project.requires_str()\n        local requireitems = require_package.load_requires(requires_str, requires_extra)\n        for _, requireitem in ipairs(requireitems) do\n            local requireinfo = requireitem.info or {}\n            local requirename = requireinfo.alias or requireitem.name\n            if requirename == packagename then\n                return requireinfo\n            end\n        end\n    end\nend\n\n-- get package toolchains envs\nfunction _get_package_toolchains_envs(envs, package, opt)\n    opt = opt or {}\n    local toolchains = package:config(\"toolchains\")\n    if toolchains then\n\n        -- pass toolchains name and their package configurations\n        local toolchain_packages = {}\n        local toolchains_custom = {}\n        for _, name in ipairs(toolchains) do\n            local toolchain_inst = toolchain.load(name, {plat = package:plat(), arch = package:arch()})\n            if toolchain_inst then\n                table.join2(toolchain_packages, toolchain_inst:config(\"packages\"))\n                if not toolchain_inst:is_builtin() then\n                    table.insert(toolchains_custom, toolchain_inst)\n                end\n            end\n        end\n        local rcfile_path = os.tmpfile() .. \".lua\"\n        local rcfile = io.open(rcfile_path, 'w')\n        if #toolchain_packages > 0 then\n            for _, packagename in ipairs(toolchain_packages) do\n                local requireinfo = _get_package_requireinfo(packagename)\n                if requireinfo then\n                    requireinfo.originstr = nil\n                    rcfile:print(\"add_requires(\\\"%s\\\", %s)\", packagename, string.serialize(requireinfo, {strip = true, indent = false}))\n                else\n                    rcfile:print(\"add_requires(\\\"%s\\\")\", packagename)\n                end\n            end\n        end\n        rcfile:print(\"add_toolchains(\\\"%s\\\")\", table.concat(table.wrap(toolchains), '\", \"'))\n        rcfile:close()\n        table.insert(envs.XMAKE_RCFILES, rcfile_path)\n\n        -- pass custom toolchains definition in project\n        for _, toolchain_inst in ipairs(toolchains_custom) do\n            -- we must load it first\n            -- @see https://github.com/xmake-io/xmake/issues/3774\n            if toolchain_inst:check() then\n                toolchain_inst:load()\n                local toolchains_file = os.tmpfile()\n                dprint(\"passing toolchain(%s) to %s\", toolchain_inst:name(), toolchains_file)\n                local ok, errors = toolchain_inst:savefile(toolchains_file)\n                if not ok then\n                    raise(\"save toolchain failed, %s\", errors or \"unknown\")\n                end\n                envs.XMAKE_TOOLCHAIN_DATAFILES = envs.XMAKE_TOOLCHAIN_DATAFILES or {}\n                table.insert(envs.XMAKE_TOOLCHAIN_DATAFILES, toolchains_file)\n            end\n        end\n    end\nend\n\n-- get require paths\nfunction _get_package_requirepaths(requirepaths, package, dep, rootpath)\n    for _, plaindep in ipairs(package:plaindeps()) do\n        local subpath = table.join(rootpath, plaindep:name())\n        if plaindep == dep then\n            table.insert(requirepaths, table.concat(subpath, \".\"))\n        else\n            _get_package_requirepaths(requirepaths, plaindep, dep, subpath)\n        end\n    end\nend\n\n-- get package depconfs envs\n-- @see https://github.com/xmake-io/xmake/issues/3952\nfunction _get_package_depconfs_envs(envs, package, opt)\n    local policy = package:policy(\"package.xmake.pass_depconfs\")\n    if policy == nil then\n        policy = project.policy(\"package.xmake.pass_depconfs\")\n    end\n    if policy == false then\n        return\n    end\n    local requireconfs = {}\n    for _, dep in ipairs(package:librarydeps()) do\n        local requireinfo = dep:requireinfo()\n        -- {\n        --  requirekey = \"imgui#8b6c4fbd\",\n        --  originstr = \"imgui\",\n        --  configs = { },\n        --  resolvedinfo = {\n        --    version = \"v1.91.1\",\n        --    configs = { }\n        --  },\n        --  version = \"v1.91.1\"\n        --}\n        local passed_requireinfo\n        if requireinfo then\n            local resolvedinfo = requireinfo.resolvedinfo\n            if resolvedinfo then\n                requireinfo = resolvedinfo\n            end\n        end\n        if requireinfo then\n            if requireinfo.version and requireinfo.version ~= \"latest\" then\n                passed_requireinfo = passed_requireinfo or {}\n                passed_requireinfo.version = requireinfo.version\n                passed_requireinfo.override = true\n            end\n            if requireinfo.configs and not table.empty(requireinfo.configs) then\n                passed_requireinfo = passed_requireinfo or {}\n                passed_requireinfo.configs = requireinfo.configs\n                passed_requireinfo.override = true\n            end\n        end\n        if passed_requireinfo then\n            local requirepaths = {}\n            _get_package_requirepaths(requirepaths, package, dep, {})\n            if #requirepaths > 0 then\n                table.insert(requireconfs, {requirepaths = requirepaths, requireinfo = passed_requireinfo})\n            end\n        end\n    end\n    if #requireconfs > 0 then\n        local rcfile_path = os.tmpfile() .. \".lua\"\n        local rcfile = io.open(rcfile_path, 'w')\n        for _, requireconf in ipairs(requireconfs) do\n            for _, requirepath in ipairs(requireconf.requirepaths) do\n                rcfile:print(\"add_requireconfs(\\\"%s\\\", %s)\", requirepath, string.serialize(requireconf.requireinfo, {strip = true, indent = false}))\n            end\n        end\n        rcfile:close()\n        table.insert(envs.XMAKE_RCFILES, rcfile_path)\n    end\nend\n\n-- get the build environments\nfunction buildenvs(package, opt)\n    local envs = {XMAKE_RCFILES = {}}\n    table.join2(envs.XMAKE_RCFILES, os.getenv(\"XMAKE_RCFILES\"))\n    _get_package_toolchains_envs(envs, package, opt)\n    _get_package_depconfs_envs(envs, package, opt)\n    -- we should avoid using $XMAKE_CONFIGDIR outside to cause conflicts\n    envs.XMAKE_CONFIGDIR = os.curdir()\n    envs.XMAKE_IN_XREPO  = \"1\"\n    envs.XMAKE_IN_PROJECT_GENERATOR = \"\"\n    return envs\nend\n\n-- install package\nfunction install(package, configs, opt)\n    opt = opt or {}\n\n    -- copy the ported xmake.lua in the default position if it's missing\n    local xmakefile = path.join(opt.curdir or os.curdir(), \"xmake.lua\")\n    if not os.isfile(xmakefile) and package:repo() ~= nil then\n        local xmakefile_port = path.join(package:scriptdir(), \"port\", \"xmake.lua\")\n        if os.isfile(xmakefile_port) then\n            os.cp(xmakefile_port, xmakefile)\n        end\n    end\n\n    -- get build environments\n    local envs = opt.envs or buildenvs(package)\n\n    -- pass local repositories\n    for _, repo in ipairs(repository.repositories()) do\n        local repo_argv = {\"repo\"}\n        _set_builtin_argv(package, repo_argv)\n        table.join2(repo_argv, {\"--add\", repo:name(), repo:directory()})\n        os.vrunv(os.programfile(), repo_argv, {envs = envs, curdir = opt.curdir})\n    end\n\n    -- pass configurations\n    -- we need to put `-P` in the first argument of _set_builtin_argv() to avoid option.parse() parsing errors\n    local argv = {\"f\"}\n    _set_builtin_argv(package, argv)\n    table.insert(argv, \"-y\")\n    table.insert(argv, \"-c\")\n    for name, value in pairs(_get_configs(package, configs, opt)) do\n        value = tostring(value):trim()\n        if type(name) == \"number\" then\n            if value ~= \"\" then\n                table.insert(argv, value)\n            end\n        else\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        end\n    end\n\n    -- do configure\n    os.vrunv(os.programfile(), argv, {envs = envs, curdir = opt.curdir})\n\n    -- do build\n    argv = {\"build\"}\n    _set_builtin_argv(package, argv)\n    local njob = opt.jobs or option.get(\"jobs\")\n    if njob then\n        table.insert(argv, \"--jobs=\" .. njob)\n    end\n    local targets = table.wrap(opt.targets or opt.target)\n    if #targets ~= 0 then\n        table.join2(argv, targets)\n    end\n    os.vrunv(os.programfile(), argv, {envs = envs, curdir = opt.curdir})\n\n    -- do install\n    argv = {\"install\", \"-y\", \"--packages=n\", \"-o\", package:installdir()}\n    _set_builtin_argv(package, argv)\n    local targets = table.wrap(opt.targets or opt.target)\n    if #targets ~= 0 then\n        table.join2(argv, targets)\n    end\n    os.vrunv(os.programfile(), argv, {envs = envs, curdir = opt.curdir})\nend\n"
  },
  {
    "path": "xmake/modules/private/action/clean/remove_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        remove_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- remove the given files or (empty) directories\nfunction main(filedirs, opt)\n    opt = opt or {}\n    for _, filedir in ipairs(filedirs) do\n        -- os.exists will return false if symlink -> not found, but we need still remove this symlink\n        if os.exists(filedir) or os.islink(filedir) then\n            -- we cannot use os.tryrm, because we need raise exception if remove failed with `uninstall --admin`\n            os.rm(filedir, {emptydirs = option.get(\"all\") or opt.emptydir})\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/check.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.json\")\nimport(\"core.project.project\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.utils.get_requires\")\nimport(\"private.action.require.impl.actions.check\", {alias = \"action_check\"})\n\n-- check the given package info\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- check the given packages\n    for _, instance in irpairs(package.load_packages(requires, {requires_extra = requires_extra, nodeps = true})) do\n        action_check(instance)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/clean.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clean.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.package.package\")\nimport(\"core.cache.localcache\")\nimport(\"private.action.require.impl.remove_packages\")\n\n-- clean the given or all package caches\nfunction main(package_names)\n\n    local clean_modes = option.get(\"clean_modes\")\n    if clean_modes then\n        clean_modes = hashset.from(clean_modes:split(\",\"))\n    else\n        clean_modes = hashset.of(\"cache\", \"package\")\n    end\n\n    -- clear cache directory\n    if clean_modes:has(\"cache\") then\n        print(\"clearing caches ..\")\n        os.rm(package.cachedir())\n\n        -- clear require cache\n        local require_cache = localcache.cache(\"package\")\n        require_cache:clear()\n        require_cache:save()\n    end\n\n    -- clear all unused packages\n    if clean_modes:has(\"package\") then\n        print(\"clearing packages ..\")\n        remove_packages(package_names, {clean = true})\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/download.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.download_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- download packages\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- find git\n    environment.enter()\n    local git = find_tool(\"git\")\n    environment.leave()\n\n    -- pull all repositories first if not exists\n    --\n    -- attempt to download git from the builtin-packages first if git not found\n    --\n    if git and (not repository.pulled() or option.get(\"upgrade\")) then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- download packages\n    environment.enter()\n    download_packages(requires, {requires_extra = requires_extra, nodeps = option.get(\"shallow\")})\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/export.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        export.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.export_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- export the given packages\nfunction main(requires_raw)\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- export packages\n    local packagedir = option.get(\"packagedir\")\n    local nodeps     = option.get(\"shallow\") and true or false\n    local packages   = export_packages(requires, {requires_extra = requires_extra, packagedir = packagedir, nodeps = nodeps})\n    if not packages or #packages == 0 then\n        if requires_raw then\n            cprint(\"${bright}packages(%s) not found, maybe they don’t exactly match the configuration \", table.concat(requires_raw, \", \"))\n            if os.getenv(\"XREPO_WORKING\") then\n                print(\"please attempt to export them with `-f/--configs=` option, e.g.\")\n                print(\"    - xrepo export -f \\\"name=value, ...\\\" package\")\n                print(\"    - xrepo export -m debug -k shared -f \\\"name=value, ...\\\" package\")\n            else\n                print(\"please attempt to export them with `--extra=` option, e.g.\")\n                print(\"    - xmake require --export --extra=\\\"{configs={...}}\\\" package\")\n                print(\"    - xmake require --export --extra=\\\"{debug=true,configs={shared=true}}\\\" package\")\n            end\n        end\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/fetch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fetch.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.json\")\nimport(\"core.project.project\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- fetch the given package info\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- get the fetching modes\n    local fetchmodes = option.get(\"fetch_modes\")\n    if fetchmodes then\n        fetchmodes = hashset.from(fetchmodes:split(',', {plain = true}))\n    end\n\n    -- fetch all packages\n    local fetchinfos = {}\n    local nodeps = not (fetchmodes and fetchmodes:has(\"deps\"))\n    for _, instance in irpairs(package.load_packages(requires, {requires_extra = requires_extra, nodeps = nodeps})) do\n        local fetchinfo = instance:fetch({external = (fetchmodes and fetchmodes:has(\"external\") or false)})\n        if fetchinfo then\n            table.insert(fetchinfos, fetchinfo)\n        end\n    end\n\n    -- show results\n    if #fetchinfos > 0 then\n        local flags = {}\n        if fetchmodes and fetchmodes:has(\"cflags\") then\n            for _, fetchinfo in ipairs(fetchinfos) do\n                table.join2(flags, compiler.map_flags(\"cxx\", \"define\", fetchinfo.defines))\n                table.join2(flags, compiler.map_flags(\"cxx\", \"includedir\", fetchinfo.includedirs))\n                table.join2(flags, compiler.map_flags(\"cxx\", \"sysincludedir\", fetchinfo.sysincludedirs))\n                for _, cflag in ipairs(fetchinfo.cflags) do\n                    table.insert(flags, cflag)\n                end\n                for _, cxflag in ipairs(fetchinfo.cxflags) do\n                    table.insert(flags, cxflag)\n                end\n                for _, cxxflag in ipairs(fetchinfo.cxxflags) do\n                    table.insert(flags, cxxflag)\n                end\n            end\n        end\n        if fetchmodes and fetchmodes:has(\"ldflags\") then\n            for _, fetchinfo in ipairs(fetchinfos) do\n                table.join2(flags, linker.map_flags(\"binary\", {\"cxx\"}, \"linkdir\", fetchinfo.linkdirs))\n                table.join2(flags, linker.map_flags(\"binary\", {\"cxx\"}, \"link\", fetchinfo.links))\n                table.join2(flags, linker.map_flags(\"binary\", {\"cxx\"}, \"syslink\", fetchinfo.syslinks))\n                for _, ldflag in ipairs(fetchinfo.ldflags) do\n                    table.insert(flags, ldflags)\n                end\n            end\n        end\n        if #flags > 0 then\n            print(os.args(flags))\n        elseif fetchmodes and fetchmodes:has(\"json\") then\n            print(json.encode(fetchinfos))\n        else\n            print(fetchinfos)\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/check.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\n\n-- check the given package\nfunction main(package, opt)\n    opt = opt or {}\n\n    -- we need not check it if this package is precompiled now\n    if package:is_precompiled() then\n        return\n    end\n\n    -- do check\n    local script = package:script(\"check\")\n    if script then\n        script(package)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/download.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.tty\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_directory\")\nimport(\"private.action.require.impl.check_api\")\nimport(\"private.action.require.impl.utils.filter\")\nimport(\"private.action.require.impl.utils.url_filename\")\nimport(\"net.http\")\nimport(\"net.proxy\")\nimport(\"devel.git\")\nimport(\"utils.archive\")\n\n-- get url extension\nfunction _url_extension(url)\n    local extension = archive.extension(url)\n    if extension == \"\" then\n        -- maybe non-archive file, e.g. .exe, .sh, ..\n        local urlpath = url:split('?', {plain = true})[1]\n        extension = path.extension(urlpath)\n    end\n    return extension\nend\n\n-- checkout codes from git\nfunction _checkout(package, url, sourcedir, opt)\n    opt = opt or {}\n    local filename = opt.url_filename or url_filename(url)\n    local sparse_includes = opt.url_includes\n    local clone_submodules = opt.url_submodules ~= false\n\n    -- we need to enable longpaths on windows\n    local longpaths = package:policy(\"platform.longpaths\")\n\n    -- use previous source directory if exists\n    local packagedir = path.join(sourcedir, package:name())\n    if os.isdir(path.join(packagedir, \".git\")) and\n        not (option.get(\"force\") and package:branch()) then -- we need disable cache if we force to clone from the given branch\n\n        -- clean the previous build files\n        git.clean({repodir = packagedir, force = true, all = true})\n        -- reset the previous modified files\n        git.reset({repodir = packagedir, hard = true})\n        -- clean and reset submodules\n        if os.isfile(path.join(packagedir, \".gitmodules\")) then\n            git.submodule.clean({repodir = packagedir, force = true, all = true})\n            git.submodule.reset({repodir = packagedir, hard = true, longpaths = longpaths})\n        end\n        tty.erase_line_to_start().cr()\n        return\n    end\n\n    -- we can use local package from the search directories directly if network is too slow\n    local localdir\n    local searchnames = {package:name() .. archive.extension(url),\n                         path.basename(filename)}\n    for _, searchname in ipairs(searchnames) do\n        localdir = find_directory(searchname, core_package.searchdirs())\n        if localdir then\n            break\n        end\n    end\n    if localdir and os.isdir(path.join(localdir, \".git\")) then\n        git.clean({repodir = localdir, force = true, all = true})\n        git.reset({repodir = localdir, hard = true})\n        if os.isfile(path.join(localdir, \".gitmodules\")) then\n            git.submodule.clean({repodir = localdir, force = true, all = true})\n            git.submodule.reset({repodir = localdir, hard = true, longpaths = longpaths})\n        end\n        os.cp(localdir, packagedir)\n        tty.erase_line_to_start().cr()\n        return\n    end\n\n    -- remove temporary directory\n    os.rm(sourcedir .. \".tmp\")\n\n    -- download package from branches?\n    packagedir = path.join(sourcedir .. \".tmp\", package:name())\n    local branch = package:branch()\n    if branch then\n\n        -- we need to select the correct default branch\n        -- @see https://github.com/xmake-io/xmake/issues/3248\n        if branch == \"@default\" then\n            branch = nil\n        end\n\n        -- only shallow clone this branch\n        git.clone(url, {depth = 1, recursive = clone_submodules, shallow_submodules = clone_submodules, longpaths = longpaths, branch = branch, outputdir = packagedir})\n\n    -- download package from revision or tag?\n    else\n\n        -- get tag and revision?\n        local tag\n        local revision = package:revision(opt.url_alias)\n        if revision and (#revision ~= 40 or not revision:match(\"%w+\")) then\n            tag = revision\n        end\n        if not tag then\n            tag = package:tag()\n        end\n        if not revision then\n            revision = tag or package:commit() or package:version_str()\n        end\n\n        -- only shallow clone this tag\n        -- @see https://github.com/xmake-io/xmake/issues/4151\n        if tag and git.support.can_clone_tag() and not sparse_includes then\n            git.clone(url, {depth = 1, recursive = clone_submodules, shallow_submodules = clone_submodules, longpaths = longpaths, branch = tag, outputdir = packagedir})\n        else\n\n            -- clone whole history and tags\n            -- @see https://github.com/xmake-io/xmake/issues/5507\n            git.clone(url, {treeless = true, checkout = false, longpaths = longpaths, outputdir = packagedir})\n\n            -- attempt to checkout the given version\n            git.checkout(revision, {repodir = packagedir, includes = sparse_includes})\n\n            -- update all submodules\n            if os.isfile(path.join(packagedir, \".gitmodules\")) and clone_submodules then\n                git.submodule.update({init = true, recursive = true, longpaths = longpaths, repodir = packagedir})\n            end\n        end\n    end\n\n    -- move to source directory\n    os.rm(sourcedir)\n    os.mv(sourcedir .. \".tmp\", sourcedir)\n\n    -- trace\n    tty.erase_line_to_start().cr()\n    cprint(\"${yellow}  => ${clear}clone %s %s .. ${color.success}${text.success}\", url, package:version_str())\nend\n\n-- download codes from ftp/http/https\nfunction _download(package, url, sourcedir, opt)\n    opt = opt or {}\n\n    -- get package file\n    local packagefile = opt.url_filename\n    if not packagefile then\n        packagefile = url_filename(url)\n        if not os.isfile(packagefile) then -- we need to be compatible with the old file names\n            packagefile = package:name() .. \"-\" .. package:version_str() .. _url_extension(packagefile)\n        end\n    end\n\n    -- get sourcehash from the given url\n    --\n    -- we don't need sourcehash and skip checksum to try download it directly if no version list in package()\n    -- @see https://github.com/xmake-io/xmake/issues/930\n    -- https://github.com/xmake-io/xmake/issues/1009\n    --\n    local sourcehash = package:sourcehash(opt.url_alias)\n    assert(not package:is_verify() or not package:get(\"versions\") or sourcehash, \"cannot get source hash of %s in package(%s)\", url, package:name())\n\n    -- the package file have been downloaded?\n    local cached = true\n    if not os.isfile(packagefile) or sourcehash ~= hash.sha256(packagefile) then\n\n        -- no cached\n        cached = false\n\n        -- attempt to remove package file first\n        os.tryrm(packagefile)\n\n        -- download or copy package file\n        if os.isfile(url) then\n            os.cp(url, packagefile)\n        else\n            local localfile\n            local searchnames = {package:name() .. \"-\" .. package:version_str() .. _url_extension(url),\n                                 packagefile}\n\n            -- match github name mangling https://github.com/xmake-io/xmake/issues/1343\n            local github_name = url_filename.github_filename(url)\n            if github_name then\n                table.insert(searchnames, github_name)\n            end\n\n            for _, searchname in ipairs(searchnames) do\n                localfile = find_file(searchname, core_package.searchdirs())\n                if localfile then\n                    break\n                end\n            end\n            if localfile and os.isfile(localfile) then\n                -- we can use local package from the search directories directly if network is too slow\n                os.cp(localfile, packagefile)\n            else\n                http.download(url, packagefile, {\n                    insecure = global.get(\"insecure-ssl\"),\n                    headers = opt.url_http_headers or package:policy(\"package.download.http_headers\")})\n            end\n        end\n\n        -- check hash\n        if sourcehash and sourcehash ~= hash.sha256(packagefile) then\n            if package:is_precompiled() then\n                wprint(\"perhaps the local binary repository is not up to date, please run `xrepo update-repo` to update it and try again!\")\n            end\n            raise(\"unmatched checksum, current hash(%s) != original hash(%s)\", hash.sha256(packagefile):sub(1, 8), sourcehash:sub(1, 8))\n        end\n    end\n\n    -- we do not extract it if we download only it.\n    if opt.download_only then\n        tty.erase_line_to_start().cr()\n        if cached then\n            cprint(\"${yellow}  => ${clear}download %s .. ${color.success}cached\", url)\n        else\n            cprint(\"${yellow}  => ${clear}download %s .. ${color.success}${text.success}\", url)\n        end\n        return\n    end\n\n    -- extract package file\n    local sourcedir_tmp = sourcedir .. \".tmp\"\n    os.rm(sourcedir_tmp)\n    local extension = archive.extension(packagefile)\n    local errors\n    local ok = try {\n        function()\n            archive.extract(packagefile, sourcedir_tmp, {excludes = opt.url_excludes})\n            return true\n        end,\n        catch {\n            function (errs)\n                if errs then\n                    errors = tostring(errs)\n                end\n            end\n        }\n    }\n    if ok then\n        -- move to source directory and we skip it to avoid long path issues on windows if only one root directory\n        os.rm(sourcedir)\n        local filedirs = os.filedirs(path.join(sourcedir_tmp, \"*\"))\n        if #filedirs == 1 and os.isdir(filedirs[1]) then\n            os.mv(filedirs[1], sourcedir)\n            -- we need to anchor it to avoid expand it when installing package\n            io.writefile(path.join(sourcedir, \"__sourceroot_anchor__.txt\"), \"\")\n            os.rm(sourcedir_tmp)\n        else\n            os.mv(sourcedir_tmp, sourcedir)\n        end\n        -- mark this sourcedir as cleanable\n        if not package:has_source() then\n            package:data_set(\"cleanable_sourcedir\", path.absolute(sourcedir))\n        end\n    elseif extension and extension ~= \"\" then\n        -- create an empty source directory if do not extract package file\n        os.tryrm(sourcedir)\n        os.mkdir(sourcedir)\n        raise(errors or string.format(\"cannot extract %s, maybe missing extractor or invalid package file!\", packagefile))\n    else\n        -- if it is not archive file, we only need to create empty source directory and use package:originfile()\n        -- e.g. .exe, .sh\n        os.tryrm(sourcedir)\n        os.mkdir(sourcedir)\n    end\n\n    -- save original file path\n    package:originfile_set(path.absolute(packagefile))\n\n    -- trace\n    tty.erase_line_to_start().cr()\n    if not cached then\n        cprint(\"${yellow}  => ${clear}download %s .. ${color.success}${text.success}\", url)\n    end\nend\n\n-- download codes from script\nfunction _download_from_script(package, script, opt)\n    script(package, opt)\n    tty.erase_line_to_start().cr()\n    cprint(\"${yellow}  => ${clear}download %s .. ${color.success}${text.success}\", opt.url)\nend\n\n-- get sorted urls\nfunction _urls(package)\n\n    -- sort urls from the version source\n    local urls = {{}, {}}\n    for _, url in ipairs(package:urls()) do\n        if git.checkurl(url) then\n            table.insert(urls[1], url)\n        elseif not package:is_verify() or not package:get(\"versions\") or package:sourcehash(package:url_alias(url)) then\n            table.insert(urls[2], url)\n        end\n    end\n    if package:gitref() then\n        return table.join(urls[1], urls[2])\n    else\n        return table.join(urls[2], urls[1])\n    end\nend\n\n-- download the given package\nfunction main(package, opt)\n    opt = opt or {}\n\n    -- get working directory of this package\n    local workdir = opt.outputdir or package:cachedir()\n\n    -- ensure the working directory first\n    os.mkdir(workdir)\n\n    -- enter the working directory\n    local oldir = os.cd(workdir)\n\n    -- lock this package\n    package:lock()\n\n    -- get urls\n    local urls = _urls(package)\n    assert(#urls > 0, \"cannot get url of package(%s)\", package:name())\n\n    -- download package from urls\n    local ok = false\n    local urls_failed = {}\n    for idx, url in ipairs(urls) do\n        local url_alias = package:url_alias(url)\n        local url_excludes = package:url_excludes(url)\n        local url_includes = package:url_includes(url)\n        local url_http_headers = package:url_http_headers(url)\n        local url_submodules = package:extraconf(\"urls\", url, \"submodules\")\n        local url_filename_custom = package:extraconf(\"urls\", url, \"filename\")\n\n        -- filter url\n        url = filter.handle(url, package)\n\n        -- use proxy url?\n        if not os.isfile(url) then\n            url = proxy.mirror(url) or url\n        end\n\n        -- download url\n        local allerrors = {}\n        ok = try\n        {\n            function ()\n\n                -- use debug source directory directly?\n                local debugdir = package:is_toplevel() and option.get(\"debugdir\") or nil\n                if debugdir then\n                    package:set(\"sourcedir\", debugdir)\n                    tty.erase_line_to_start().cr()\n                    return true\n                end\n\n                -- download package\n                local sourcedir = \"source\"\n                local script = package:script(\"download\")\n                if script then\n                    _download_from_script(package, script, {\n                        download_only = opt.download_only,\n                        sourcedir = sourcedir,\n                        url = url,\n                        url_alias = url_alias,\n                        url_excludes = url_excludes,\n                        url_includes = url_includes,\n                        url_submodules = url_submodules,\n                        url_filename = url_filename_custom})\n                elseif git.checkurl(url) then\n                    _checkout(package, url, sourcedir, {\n                        url_alias = url_alias,\n                        url_includes = url_includes,\n                        url_submodules = url_submodules,\n                        url_filename = url_filename_custom})\n                else\n                    _download(package, url, sourcedir, {\n                        download_only = opt.download_only,\n                        url_alias = url_alias,\n                        url_excludes = url_excludes,\n                        url_includes = url_includes,\n                        url_http_headers = url_http_headers,\n                        url_filename = url_filename_custom})\n                end\n                return true\n            end,\n            catch\n            {\n                function (errors)\n\n                    check_api(package, {download_failure = true})\n\n                    -- show or save the last errors\n                    if errors then\n                        if (option.get(\"verbose\") or option.get(\"diagnosis\")) then\n                            cprint(\"${dim color.error}error: ${clear}%s\", errors)\n                        else\n                            table.insert(allerrors, errors)\n                        end\n                    end\n\n                    -- trace\n                    tty.erase_line_to_start().cr()\n                    if git.checkurl(url) then\n                        cprint(\"${yellow}  => ${clear}clone %s %s .. ${color.failure}${text.failure}\", url, package:version_str())\n                    else\n                        cprint(\"${yellow}  => ${clear}download %s .. ${color.failure}${text.failure}\", url)\n                    end\n                    table.insert(urls_failed, url)\n\n                    -- failed? break it\n                    if idx == #urls and not package:is_optional() then\n                        if #urls_failed > 0 then\n                            print(\"\")\n                            print(\"we can also download these packages manually:\")\n                            local searchnames = hashset.new()\n                            for _, url_failed in ipairs(urls_failed) do\n                                cprint(\"  ${yellow}- %s\", url_failed)\n                                if git.checkurl(url_failed) then\n                                    searchnames:insert(package:name() .. archive.extension(url_failed))\n                                    searchnames:insert(path.basename(url_filename(url_failed)))\n                                else\n                                    local extension = _url_extension(url_failed)\n                                    if extension then\n                                        searchnames:insert(package:name() .. \"-\" .. package:version_str() .. extension)\n                                    end\n                                    searchnames:insert(url_filename(url_failed))\n                                end\n                            end\n                            cprint(\"to the local search directories: ${bright}%s\", table.concat(table.wrap(core_package.searchdirs()), path.envsep()))\n                            cprint(\"  ${bright}- %s\", table.concat(searchnames:to_array(), \", \"))\n                            cprint(\"and we can run `xmake g --pkg_searchdirs=/xxx` to set the search directories.\")\n                        end\n                        if #allerrors then\n                            raise(table.concat(allerrors, \"\\n\"))\n                        else\n                            raise(\"download failed!\")\n                        end\n                    end\n                end\n            }\n        }\n\n        if ok then\n            break\n        end\n    end\n\n    -- unlock this package\n    package:unlock()\n\n    -- leave working directory\n    os.cd(oldir)\n    return ok\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/download_resources.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download_resources.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_directory\")\nimport(\"net.http\")\nimport(\"net.proxy\")\nimport(\"devel.git\")\nimport(\"utils.archive\")\n\n-- checkout resources\nfunction _checkout(package, resource_name, resource_url, resource_revision)\n\n    -- trace\n    resource_url = proxy.mirror(resource_url) or resource_url\n    vprint(\"cloning resource(%s: %s) to %s-%s ..\", resource_name, resource_revision, package:name(), package:version_str())\n\n    -- get the resource directory\n    local resourcedir = assert(package:resourcefile(resource_name), \"invalid resource directory!\")\n\n    -- use previous resource directory if exists\n    if os.isdir(resourcedir) and not option.get(\"force\") then\n        -- clean the previous build files\n        git.clean({repodir = resourcedir, force = true, all = true})\n        -- reset the previous modified files\n        git.reset({repodir = resourcedir, hard = true})\n        if os.isfile(path.join(resourcedir, \".gitmodules\")) then\n            git.submodule.clean({repodir = resourcedir, force = true, all = true})\n            git.submodule.reset({repodir = resourcedir, hard = true})\n        end\n        return\n    end\n\n    -- we can use local package from the search directories directly if network is too slow\n    local localdir = find_directory(path.filename(resourcedir), core_package.searchdirs())\n    if localdir and os.isdir(localdir) then\n        git.clean({repodir = localdir, force = true, all = true})\n        git.reset({repodir = localdir, hard = true})\n        if os.isfile(path.join(localdir, \".gitmodules\")) then\n            git.submodule.clean({repodir = localdir, force = true, all = true})\n            git.submodule.reset({repodir = localdir, hard = true})\n        end\n        os.cp(localdir, resourcedir)\n        return\n    end\n\n    -- remove temporary directory\n    os.rm(resourcedir)\n\n    -- we need to enable longpaths on windows\n    local longpaths = package:policy(\"platform.longpaths\")\n\n    -- clone whole history and tags\n    git.clone(resource_url, {treeless = true, checkout = false, longpaths = longpaths, outputdir = resourcedir})\n\n    -- attempt to checkout the given version\n    git.checkout(resource_revision, {repodir = resourcedir})\n\n    -- update all submodules\n    if os.isfile(path.join(resourcedir, \".gitmodules\")) then\n        git.submodule.update({init = true, recursive = true, longpaths = longpaths, repodir = resourcedir})\n    end\nend\n\n-- download resources\nfunction _download(package, resource_name, resource_url, resource_hash)\n\n    -- trace\n    resource_url = proxy.mirror(resource_url) or resource_url\n    vprint(\"downloading resource(%s: %s) to %s-%s ..\", resource_name, resource_url, package:name(), package:version_str())\n\n    -- get the resource file\n    local resource_file = assert(package:resourcefile(resource_name), \"invalid resource file!\")\n\n    -- ensure lower hash\n    if resource_hash then\n        resource_hash = resource_hash:lower()\n    end\n\n    -- the package file have been downloaded?\n    local cached = true\n    if not os.isfile(resource_file) or resource_hash ~= hash.sha256(resource_file) then\n\n        -- no cached\n        cached = false\n\n        -- attempt to remove the previous file first\n        os.tryrm(resource_file)\n\n        -- download or copy the resource file\n        local localfile = find_file(path.filename(resource_file), core_package.searchdirs())\n        if localfile and os.isfile(localfile) then\n            -- we can use local resource from the search directories directly if network is too slow\n            os.cp(localfile, resource_file)\n        elseif os.isfile(resource_url) then\n            os.cp(resource_url, resource_file)\n        elseif resource_url:find(string.ipattern(\"https-://\")) or resource_url:find(string.ipattern(\"ftps-://\")) then\n            http.download(resource_url, resource_file, {\n                insecure = global.get(\"insecure-ssl\"),\n                headers = package:policy(\"package.download.http_headers\")})\n        else\n            raise(\"invalid resource url(%s)\", resource_url)\n        end\n\n        -- check hash\n        if resource_hash and resource_hash ~= hash.sha256(resource_file) then\n            raise(\"resource(%s): unmatched checksum, current hash(%s) != original hash(%s)\", resource_url,\n                hash.sha256(resource_file):sub(1, 8), resource_hash:sub(1, 8))\n        end\n    end\n\n    -- extract the resource file\n    local resourcedir = package:resourcedir(resource_name)\n    local resourcedir_tmp = resourcedir .. \".tmp\"\n    os.tryrm(resourcedir_tmp)\n    local extension = archive.extension(resource_file)\n    local errors\n    local ok = try {\n        function ()\n            archive.extract(resource_file, resourcedir_tmp)\n            return true\n        end,\n        catch {\n            function (errs)\n                if errs then\n                    errors = tostring(errs)\n                end\n            end\n        }\n    }\n    if ok then\n        os.tryrm(resourcedir)\n        os.mv(resourcedir_tmp, resourcedir)\n    elseif extension and extension ~= \"\" then\n        os.tryrm(resourcedir_tmp)\n        os.tryrm(resourcedir)\n        raise(errors or string.format(\"cannot extract %s\", resource_file))\n    else\n        -- if it is not archive file, we only need to create empty resource directory and use package:resourcefile(resource_name)\n        os.tryrm(resourcedir)\n        os.mkdir(resourcedir)\n    end\nend\n\n-- download all resources of the given package\nfunction main(package)\n\n    -- we don't need to download it if we use the precompiled artifacts to install package\n    if package:is_precompiled() then\n        return\n    end\n\n    -- no resources?\n    local resources = package:resources()\n    if not resources then\n        return\n    end\n\n    -- download all resources\n    for name, resourceinfo in pairs(resources) do\n        if git.checkurl(resourceinfo.url) then\n            _checkout(package, name, resourceinfo.url, resourceinfo.sha256)\n        else\n            _download(package, name, resourceinfo.url, resourceinfo.sha256)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.tty\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"core.project.target\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_file\")\nimport(\"utils.archive.merge_staticlib\")\nimport(\"private.tools.ccache\")\nimport(\"private.action.require.impl.actions.test\")\nimport(\"private.action.require.impl.actions.patch_sources\")\nimport(\"private.action.require.impl.actions.download_resources\")\nimport(\"private.action.require.impl.utils.filter\")\n\n-- patch pkgconfig if not exists\nfunction _patch_pkgconfig(package)\n\n    -- only binary? need not pkgconfig\n    if not package:is_library() then\n        return\n    end\n\n    local installdir = path.unix(path.normalize(package:installdir()))\n\n    -- get lib/pkgconfig/*.pc or share/pkgconfig/*.pc file\n    local libpkgconfigdir = path.join(package:installdir(), \"lib\", \"pkgconfig\")\n    local sharepkgconfigdir = path.join(package:installdir(), \"share\", \"pkgconfig\")\n    local pcfiles = {}\n    table.join2(pcfiles, os.isdir(libpkgconfigdir) and os.files(path.join(libpkgconfigdir, \"*.pc\")) or {})\n    table.join2(pcfiles, os.isdir(sharepkgconfigdir) and os.files(path.join(sharepkgconfigdir, \"*.pc\")) or {})\n    if #pcfiles > 0 then\n        for _, pcfile in ipairs(pcfiles) do\n            local pcfile_content = io.readfile(pcfile)\n            if pcfile_content then\n                local pcfile_content, count = pcfile_content:replace(installdir, \"${installdir}\", {plain = true})\n                if count > 0 then\n                    local line_ending = pcfile_content:find(\"\\r\\n\") and \"\\r\\n\" or \"\\n\"\n                    pcfile_content = \"# Modified by Xmake: Using relative paths to make package relocatable\" .. line_ending\n                                      .. \"installdir=${pcfiledir}/\" .. path.unix(path.relative(installdir, path.directory(pcfile))) .. line_ending\n                                      .. pcfile_content\n                    io.writefile(pcfile, pcfile_content)\n                end\n            end\n        end\n        return\n    end\n\n    -- trace\n    local pcfile = path.join(libpkgconfigdir, package:name() .. \".pc\")\n    vprint(\"patching %s ..\", pcfile)\n\n    -- fetch package\n    local fetchinfo = package:fetch_librarydeps()\n    if not fetchinfo then\n        return\n    end\n\n    -- get libs\n    local libs = \"\"\n    for _, linkdir in ipairs(fetchinfo.linkdirs) do\n        linkdir = path.unix(path.normalize(linkdir)):replace(installdir, \"${exec_prefix}\", {plain = true})\n        if linkdir ~= \"${exec_prefix}/lib\" then\n            libs = libs .. \" -L\" .. linkdir\n        end\n    end\n    libs = libs .. \" -L${libdir}\"\n    for _, link in ipairs(fetchinfo.links) do\n        libs = libs .. \" -l\" .. link\n    end\n    for _, link in ipairs(fetchinfo.syslinks) do\n        libs = libs .. \" -l\" .. link\n    end\n\n    -- cflags\n    local cflags = \"\"\n    for _, includedir in ipairs(fetchinfo.includedirs or fetchinfo.sysincludedirs) do\n        includedir = path.unix(path.normalize(includedir)):replace(installdir, \"${prefix}\", {plain = true})\n        if includedir ~= \"${prefix}/include\" then\n            cflags = cflags .. \" -I\" .. includedir\n        end\n    end\n    cflags = cflags .. \" -I${includedir}\"\n    for _, define in ipairs(fetchinfo.defines) do\n        cflags = cflags .. \" -D\" .. define\n    end\n\n    -- patch a *.pc file\n    local file = io.open(pcfile, 'w')\n    if file then\n        -- @see https://github.com/xmake-io/xmake-repo/pull/8165#discussion_r2366249416\n        local version = package:version_str():ltrim(\"v\")\n        file:print(\"# Generated by Xmake\")\n        file:print(\"prefix=%s\", \"${pcfiledir}/\" .. path.unix(path.relative(installdir, path.directory(pcfile))))\n        file:print(\"exec_prefix=${prefix}\")\n        file:print(\"libdir=${exec_prefix}/lib\")\n        file:print(\"includedir=${prefix}/include\")\n        file:print(\"\")\n        file:print(\"Name: %s\", package:name())\n        file:print(\"Description: %s\", package:description())\n        file:print(\"Version: %s\", version)\n        file:print(\"Libs: %s\", libs)\n        file:print(\"Libs.private: \")\n        file:print(\"Cflags: %s\", cflags)\n        file:close()\n    end\nend\n\n-- Match to path like (string insides brackets is matched):\n--     /home/user/.xmake/packages[/f/foo/v0.1.0/9adc96bd69124211aad7dd58a36f02ce]/lib\nlocal _PACKAGE_VERSION_BUILDHASH_PATTERN = \"[\\\\/]%w[\\\\/][^\\\\/]+[\\\\/][^\\\\/]+[\\\\/]\" .. string.rep('%x', 32)\n\nfunction _fix_path_for_file(file, search_pattern)\n    -- Replace path string before package pattern with local package install\n    -- directory.\n    -- Note: It's possible that package A references files in package B, thus we\n    -- need to match against all possible package install paths.\n    --\n    -- search_pattern should contain a whole and a sub capture.\n    -- The sub capture will be replaced with local install path.\n    -- The whole capture is to make the search more precise and less likely to\n    -- match non package path.\n    local prefix = core_package.installdir()\n\n    io.gsub(file, search_pattern, function(whole_value, value)\n        local mat = value:match(_PACKAGE_VERSION_BUILDHASH_PATTERN)\n        if not mat then\n            return nil\n        end\n\n        local result\n        local splitinfo = value:split(mat, {plain = true})\n        if #splitinfo == 2 then\n            -- /home/user/packages[/f/foo/buildhash]/v1.0\n            result = path.join(prefix, mat, splitinfo[2])\n        elseif #splitinfo == 1 then\n            if value:startswith(mat) then\n                -- path begins with matched pattern: [/f/foo/buildhash]/v1.0\n                result = path.join(prefix, value)\n            else\n                -- path ends with matched pattern: /home/user/packages[/f/foo/buildhash]\n                result = path.join(prefix, mat)\n            end\n        else\n            vprint(\"fix path split got more than 2 parts, something wrong?\", whole_value)\n        end\n        if result then\n            result = result:gsub(\"\\\\\", \"/\")\n            vprint(\"fix path: %s in %s\", whole_value, file)\n            return whole_value:replace(value, result, {plain = true})\n        end\n    end)\nend\n\n-- fix paths for the precompiled package\n-- @see https://github.com/xmake-io/xmake/issues/1671\nfunction _fix_paths_for_precompiled_package(package)\n    local patterns = {\n        {\n            -- Fix path for cmake files.\n            -- \"|include/**\" means exclude all files under include directory.\n            -- Their are quite a few search paths used by cmake, so just look\n            -- for all \".cmake\" files for most reliable result.\n            -- https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure\n            file_pattern = {\"**.cmake|include/**\"},\n            search_pattern = {'(\"(.-)\")'},\n        },\n        {\n            -- Fix path for pkg-config .pc files.\n            -- 1. `varname=value` defines a variable, which may contain path.\n            -- 2. A package may reference another package with absolute path.\n            --    For example: glog.pc with gflags and unwind enabled contains something like following:\n            --        Libs: -L/absolute/path/to/gflags/lib -L /absolute/path/to/libunwind/lib ...\n            --    So searching for only prefix is not enough.\n            -- 3. If path contains spaces, it should be double quoted.\n            --    If not quoted, spaces should be backslash escaped, which we do\n            --    not fix for now.\n            --    For pkg-config behavior for spaces in path, refer to\n            --    https://github.com/golang/go/issues/16455#issuecomment-255900404\n            file_pattern = {\"lib/pkgconfig/**.pc\", \"share/pkgconfig/**.pc\"},\n            search_pattern = {\"([%w_]+%s*=%s*(.-)\\n)\", \"(%-[I|L]%s*(%S+))\", '(\"(.-)\")'},\n        },\n    }\n\n    -- If artifact contains installdir where it's built (remotedir), extract\n    -- path prefix and do plain replace with local install dir.\n    local remotedir\n    local manifest = package:manifest_load()\n    if manifest and manifest.artifacts then\n        remotedir = manifest.artifacts.remotedir\n    end\n\n    local remote_prefix\n    local local_prefix\n    if remotedir then\n        local idx = remotedir:find(_PACKAGE_VERSION_BUILDHASH_PATTERN)\n        if idx then\n            remote_prefix = remotedir:sub(1, idx)\n            local_prefix = core_package.installdir()\n            if not local_prefix:endswith(path.sep()) then\n                local_prefix = local_prefix .. path.sep()\n            end\n        else\n            wprint(\"no package buildhash pattern found in artifacts remotedir: %s\", remotedir)\n        end\n    end\n\n    for _, pat in ipairs(patterns) do\n        for _, filepat in ipairs(pat.file_pattern) do\n            local filepattern = path.join(package:installdir(), filepat)\n            for _, file in ipairs(os.files(filepattern)) do\n                if remote_prefix then\n                    local _, count = io.replace(file, remote_prefix, local_prefix, {plain = true})\n                    -- maybe we need to translate path seperator\n                    -- @see https://github.com/xmake-io/xmake/discussions/3008\n                    if count == 0 and is_host(\"windows\") then\n                        io.replace(file, (remote_prefix:gsub(\"\\\\\", \"/\")), local_prefix:gsub(\"\\\\\", \"/\"), {plain = true})\n                    end\n                else\n                    for _, search_pattern in ipairs(pat.search_pattern) do\n                        _fix_path_for_file(file, search_pattern)\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- merge static libraries\n-- @see https://github.com/xmake-io/xmake/issues/5894\nfunction _merge_staticlibs(package)\n    local merge_staticlibs = project.policy(\"package.merge_staticlibs\")\n    if merge_staticlibs == nil then\n        merge_staticlibs = package:policy(\"package.merge_staticlibs\")\n    end\n    if merge_staticlibs and package:is_library()\n        and not package:config(\"shared\") and not package:is_headeronly() and not package:is_moduleonly() then\n        local installdir = package:installdir()\n        local linkdirs = table.wrap(package:get(\"linkdirs\") or \"lib\")\n        local libfiles = {}\n        for _, linkdir in ipairs(linkdirs) do\n            for _, libfile in ipairs(os.files(path.join(installdir, linkdir, \"*\"))) do\n                if libfile:endswith(\".lib\") or libfile:endswith(\".a\") then\n                    table.insert(libfiles, libfile)\n                end\n            end\n        end\n        if #libfiles > 0 then\n            local linkdir = linkdirs[1]\n            local linkname = package:name()\n            local opt = {plat = package:plat(), arch = package:arch()}\n            local libfile_new = path.join(installdir, linkdir, target.filename(linkname, \"static\", opt))\n\n            merge_staticlib(package, libfile_new, libfiles)\n            package:set(\"links\", linkname)\n            for _, libfile in ipairs(libfiles) do\n                if libfile ~= libfile_new then\n                    os.rm(libfile)\n                end\n            end\n        end\n    end\nend\n\n-- get failed install directory\nfunction _get_installdir_failed(package)\n    return path.join(package:cachedir(), \"installdir.failed\")\nend\n\n-- clear install directory\nfunction _clear_installdir(package)\n    os.tryrm(package:installdir())\n    os.tryrm(_get_installdir_failed(package))\nend\n\n-- clear source directory\nfunction _clear_sourcedir(package)\n    local sourcedir = package:data(\"cleanable_sourcedir\")\n    if sourcedir then\n        os.tryrm(sourcedir)\n    end\nend\n\n-- enter working directory\nfunction _enter_workdir(package)\n\n    -- get working directory of this package\n    local workdir = package:cachedir()\n\n    -- lock this package\n    package:lock()\n\n    -- enter directory\n    local oldir = nil\n    local sourcedir = package:sourcedir()\n    if sourcedir then\n        oldir = os.cd(sourcedir)\n    elseif #package:urls() > 0 then\n        -- only one root directory? skip it\n        local anchorfile = path.join(workdir, \"source\", \"__sourceroot_anchor__.txt\")\n        local filedirs = os.filedirs(path.join(workdir, \"source\", \"*\"))\n        if not os.isfile(anchorfile) and #filedirs == 1 and os.isdir(filedirs[1]) then\n            oldir = os.cd(filedirs[1])\n        else\n            oldir = os.cd(path.join(workdir, \"source\"))\n        end\n    end\n    if not oldir then\n        os.mkdir(workdir)\n        oldir = os.cd(workdir)\n    end\n\n    -- we need to copy source codes to the working directory with short path on windows\n    --\n    -- Because the target name and source file path of this project are too long,\n    -- it's absolute path exceeds the windows path length limit.\n    --\n    if is_host(\"windows\") and package:policy(\"platform.longpaths\") then\n        local sourcedir_tmp = os.tmpdir() .. \".dir\"\n        os.tryrm(sourcedir_tmp)\n        os.cp(os.curdir(), sourcedir_tmp)\n        os.cd(sourcedir_tmp)\n    end\n\n    return oldir\nend\n\n-- leave working directory\nfunction _leave_workdir(package, oldir)\n\n    -- clean the empty package directory\n    local installdir = package:installdir()\n    if os.emptydir(installdir) then\n        os.tryrm(installdir)\n    end\n\n    -- unlock this package\n    package:unlock()\n\n    -- leave source codes directory\n    if oldir then\n        os.cd(oldir)\n    end\n\n    -- clean source directory if it is no longer needed\n    _clear_sourcedir(package)\nend\n\n-- enter package install environments\nfunction _enter_package_installenvs(package)\n    for _, dep in ipairs(package:orderdeps()) do\n        dep:envs_enter()\n    end\nend\n\n-- enter package test environments\nfunction _enter_package_testenvs(package)\n\n    -- add compiler runtime library directory to $PATH\n    -- @see https://github.com/xmake-io/xmake-repo/pull/3606\n    if is_host(\"windows\") and package:is_plat(\"windows\", \"mingw\") then -- bin/*.dll for windows\n        local toolchains = package:toolchains()\n        if not toolchains then\n            local platform_inst = platform.load(package:plat(), package:arch())\n            toolchains = platform_inst:toolchains()\n            for _, toolchain_inst in ipairs(toolchains) do\n                if toolchain_inst:check() then\n                    local runenvs = toolchain_inst:runenvs()\n                    if runenvs and runenvs.PATH then\n                        local envs = {PATH = runenvs.PATH}\n                        os.addenvs(envs)\n                    end\n                end\n            end\n        end\n    end\n\n    -- enter package environments\n    for _, dep in ipairs(package:orderdeps()) do\n        dep:envs_enter()\n    end\n    package:envs_enter()\nend\n\nfunction _enable_ccache(package)\n    if package:is_local() then\n        return\n    end\n\n    if not project.policy(\"package.build.ccache\") then\n        return\n    end\n\n    local ccache = ccache.get()\n    if ccache then\n        local name = path.basename(ccache.program)\n        package:data_set(\"ccache\", name)\n        local ccache_dir = path.join(path.directory(package:cachedir()), name)\n        os.setenv(name:upper() .. \"_DIR\", ccache_dir)\n    end\nend\n\nfunction _get_package_tipname(package)\n    local package_tipname = package:displayname()\n    local current_scheme = package:current_scheme()\n    if package:version_str() then\n        package_tipname = package_tipname .. \" \" .. package:version_str()\n    end\n    if current_scheme and not current_scheme:is_default() then\n        local scheme_name = current_scheme:name()\n        if current_scheme:is_precompiled() then\n            scheme_name = \"precompiled\"\n        end\n        package_tipname = package_tipname .. \" ${dim}(\" .. scheme_name .. \")${clear}\"\n    end\n    return package_tipname\nend\n\nfunction main(package)\n    local oldir = _enter_workdir(package)\n\n    -- install it\n    local ok = true\n    local oldenvs = os.getenvs()\n    local package_tipname = _get_package_tipname(package)\n    try\n    {\n        function ()\n\n            -- install the third-party package directly, e.g. brew::pcre2/libpcre2-8, conan::OpenSSL/1.0.2n@conan/stable\n            local installed_now = false\n            local script = package:script(\"install\")\n            if package:is_thirdparty() then\n                if script ~= nil then\n                    filter.call(script, package)\n                end\n            else\n\n                -- build and install package to the install directory\n                local force_reinstall = package:policy(\"package.install_always\") or package:data(\"force_reinstall\") or option.get(\"force\")\n                if force_reinstall or not package:manifest_load() then\n\n                    -- clear install directory\n                    _clear_installdir(package)\n\n                    -- download package resources\n                    download_resources(package)\n\n                    -- patch source codes of package\n                    patch_sources(package)\n\n                    -- enter the environments of all package dependencies\n                    _enter_package_installenvs(package)\n\n                    -- set package ccache dir\n                    _enable_ccache(package)\n\n                    -- do install\n                    if script ~= nil then\n                        filter.call(script, package, {oldenvs = oldenvs})\n                    end\n\n                    -- install rules\n                    local rulesdir = package:rulesdir()\n                    if rulesdir and os.isdir(rulesdir) then\n                        os.cp(rulesdir, package:installdir())\n                    end\n\n                    -- merge static libraries\n                    _merge_staticlibs(package)\n\n                    -- leave the environments of all package dependencies\n                    os.setenvs(oldenvs)\n\n                    -- save the package info to the manifest file\n                    package:manifest_save()\n                    installed_now = true\n                end\n            end\n\n            -- enter the package environments\n            _enter_package_testenvs(package)\n\n            -- fetch package and force to flush the cache\n            local fetchinfo = package:fetch({force = true})\n            if option.get(\"verbose\") or option.get(\"diagnosis\") then\n                print(fetchinfo)\n            end\n            assert(fetchinfo, \"fetch %s failed!\", package_tipname)\n\n            -- this package is installed now\n            if installed_now then\n\n                -- fix paths for the precompiled package\n                if package:is_precompiled() and not package:is_system() then\n                    _fix_paths_for_precompiled_package(package)\n                end\n\n                -- patch pkg-config files for package\n                _patch_pkgconfig(package)\n\n                -- test it\n                test(package)\n            end\n\n            -- leave the package environments\n            os.setenvs(oldenvs)\n\n            -- trace\n            tty.erase_line_to_start().cr()\n            cprint(\"${yellow}  => ${clear}install %s .. ${color.success}${text.success}\", package_tipname)\n        end,\n\n        catch\n        {\n            function (errors)\n\n                -- show or save the last errors\n                local errorfile = path.join(package:installdir(\"logs\"), \"install.txt\")\n                if errors then\n                    if (option.get(\"verbose\") or option.get(\"diagnosis\")) then\n                        cprint(\"${dim color.error}error: ${clear}%s\", errors)\n                    else\n                        io.writefile(errorfile, errors .. \"\\n\")\n                    end\n                end\n\n                -- trace\n                tty.erase_line_to_start().cr()\n                cprint(\"${yellow}  => ${clear}install %s .. ${color.failure}${text.failure}\", package_tipname)\n\n                -- leave the package environments\n                os.setenvs(oldenvs)\n\n                -- copy the invalid package directory to cache\n                local installdir = package:installdir()\n                if os.isdir(installdir) then\n                    local installdir_failed = _get_installdir_failed(package)\n                    if not os.isdir(installdir_failed) then\n                        os.cp(installdir, installdir_failed)\n                    end\n                    errorfile = path.join(installdir_failed, \"logs\", \"install.txt\")\n                end\n                os.tryrm(installdir)\n\n                -- is not last scheme? we can fallback to next scheme and try reinstall it again\n                local current_scheme = package:current_scheme()\n                local schemes_orderlist = package:schemes_orderlist()\n                local last_scheme = schemes_orderlist[#schemes_orderlist]\n                if current_scheme ~= last_scheme then\n                    ok = false\n                else\n                    -- failed\n                    if not package:requireinfo().optional then\n                        if os.isfile(errorfile) then\n                            if errors and option.get(\"diagnosis\") then\n                                print(tostring(errors))\n                            else\n                                if errors then\n                                    print(\"\")\n                                    for idx, line in ipairs(errors:split(\"\\n\")) do\n                                        print(line)\n                                        if idx > 16 then\n                                            break\n                                        end\n                                    end\n                                end\n                                cprint(\"if you want to get more verbose errors, please see:\")\n                                cprint(\"  -> ${bright}%s\", errorfile)\n                            end\n                        end\n                        raise(\"install failed!\")\n                    end\n                end\n            end\n        }\n    }\n\n    _leave_workdir(package, oldir)\n    return ok\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/patch_sources.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        patch_sources.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"net.http\")\nimport(\"net.proxy\")\nimport(\"devel.git\")\nimport(\"utils.archive\")\n\n-- check sha256\nfunction _check_sha256(patch_hash, patch_file)\n    local ok = (patch_hash == hash.sha256(patch_file))\n    if not ok then\n        -- `git pull` maybe will replace lf to crlf in the patch text automatically on windows.\n        -- so we need to attempt to fix this sha256\n        --\n        -- @see\n        -- https://github.com/xmake-io/xmake-repo/pull/67\n        -- https://stackoverflow.com/questions/1967370/git-replacing-lf-with-crlf\n        --\n        local tmpfile = os.tmpfile(patch_file)\n        os.cp(patch_file, tmpfile)\n        local content = io.readfile(tmpfile, {encoding = \"binary\"})\n        content = content:gsub('\\r\\n', '\\n')\n        io.writefile(tmpfile, content, {encoding = \"binary\"})\n        ok = (patch_hash == hash.sha256(tmpfile))\n        os.rm(tmpfile)\n    end\n    return ok\nend\n\n-- do patch\nfunction _patch(package, patchinfo)\n    local patch_url = patchinfo.url\n    local patch_hash = patchinfo.sha256\n    local patch_extra = patchinfo.extra or {}\n\n    -- trace\n    patch_url = proxy.mirror(patch_url) or patch_url\n    vprint(\"patching %s to %s-%s ..\", patch_url, package:name(), package:version_str())\n\n    -- get the patch file\n    local patch_file = path.join(os.tmpdir(), \"patches\", package:name(), package:version_str(), (path.filename(patch_url):gsub(\"%?.+$\", \"\")))\n\n    -- ensure lower hash\n    if patch_hash then\n        patch_hash = patch_hash:lower()\n    end\n\n    -- the package file have been downloaded?\n    local cached = true\n    if not os.isfile(patch_file) or not _check_sha256(patch_hash, patch_file) then\n\n        -- no cached\n        cached = false\n\n        -- attempt to remove the previous file first\n        os.tryrm(patch_file)\n\n        -- download the patch file\n        if patch_url:find(string.ipattern(\"https-://\")) or patch_url:find(string.ipattern(\"ftps-://\")) then\n            http.download(patch_url, patch_file, {\n                insecure = global.get(\"insecure-ssl\"),\n                headers = package:policy(\"package.download.http_headers\")})\n        else\n            -- copy the patch file\n            if os.isfile(patch_url) then\n                os.cp(patch_url, patch_file)\n            else\n                local scriptdir = package:scriptdir()\n                if scriptdir and os.isfile(path.join(scriptdir, patch_url)) then\n                    os.cp(path.join(scriptdir, patch_url), patch_file)\n                else\n                    raise(\"patch(%s): not found!\", patch_url)\n                end\n            end\n        end\n\n        -- check hash\n        if patch_hash and not _check_sha256(patch_hash, patch_file) then\n            raise(\"patch(%s): unmatched checksum!\", patch_url)\n        end\n    end\n\n    -- is archive file? we need extract it first\n    local extension = archive.extension(patch_file)\n    if extension and #extension > 0 then\n        local patchdir = patch_file .. \".dir\"\n        local patchdir_tmp = patchdir .. \".tmp\"\n        os.tryrm(patchdir_tmp)\n        local errors\n        local ok = try {\n            function()\n                archive.extract(patch_file, patchdir_tmp)\n                return true\n            end,\n            catch {\n                function (errs)\n                    if errs then\n                        errors = tostring(errs)\n                    end\n                end\n            }\n        }\n        if ok then\n            os.tryrm(patchdir)\n            os.mv(patchdir_tmp, patchdir)\n        else\n            os.tryrm(patchdir_tmp)\n            os.tryrm(patchdir)\n            raise(errors or string.format(\"cannot extract %s\", patch_file))\n        end\n\n        -- apply patch files\n        for _, file in ipairs(os.files(path.join(patchdir, \"**\"))) do\n            vprint(\"applying patch %s\", file)\n            git.apply(file, {reverse = patch_extra.reverse})\n        end\n    else\n        -- apply single plain patch file\n        vprint(\"applying patch %s\", patch_file)\n        git.apply(patch_file, {reverse = patch_extra.reverse})\n    end\nend\n\n-- patch the given package\nfunction main(package)\n\n    -- we don't need to patch it if we use the precompiled artifacts to install package\n    if package:is_precompiled() then\n        return\n    end\n\n    -- no patches?\n    local patches = package:patches()\n    if not patches then\n        return\n    end\n\n    -- do all patches\n    for _, patchinfo in ipairs(patches) do\n        _patch(package, patchinfo)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/actions/test.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        test.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.utils.filter\")\n\n-- test the given package\nfunction main(package)\n\n    -- enter the test directory\n    local testdir = path.join(os.tmpdir(), \"pkgtest\", package:name(), package:version_str() or \"latest\")\n    if os.isdir(testdir) then\n        os.tryrm(testdir)\n    end\n    if not os.isdir(testdir) then\n        os.mkdir(testdir)\n    end\n    local oldir = os.cd(testdir)\n\n    -- test it\n    local script = package:script(\"test\")\n    if script ~= nil then\n        filter.call(script, package)\n    end\n\n    -- restore the current directory\n    os.cd(oldir)\n\n    -- remove the test directory\n    os.tryrm(testdir)\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/check_api.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        check_api.lua\n--\n\nimport(\"private.check.checker\")\nimport(\"private.check.show\")\n\nfunction main(package, opt)\n    opt = opt or {}\n\n    local checkers = checker.checkers()\n    for name, info in table.orderpairs(checkers) do\n        if (info.load and opt.load) or (info.download_failure and opt.download_failure) then\n            local check = import(\"private.check.checkers.\" .. name, {anonymous = true})\n            check({package = package, show = show.wshow})\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/download_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download_packages.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"core.project.project\")\nimport(\"core.base.tty\")\nimport(\"async.runjobs\")\nimport(\"utils.waiting_indicator\", {alias = \"waiting_indicator\"})\nimport(\"net.fasturl\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.register_packages\")\nimport(\"private.action.require.impl.actions.download\", {alias = \"action_download\"})\n\n-- sort packages urls\nfunction _sort_packages_urls(packages)\n\n    -- add all urls to fasturl and prepare to sort them together\n    for _, instance in pairs(packages) do\n        fasturl.add(instance:urls())\n    end\n\n    -- sort and update urls\n    for _, instance in pairs(packages) do\n        instance:urls_set(fasturl.sort(instance:urls()))\n    end\nend\n\n-- get user confirm\nfunction _get_confirm(packages)\n\n    -- no confirmed packages?\n    if #packages == 0 then\n        return true\n    end\n\n    local result\n    local packages_modified\n    while result == nil do\n        -- get confirm result\n        result = utils.confirm({default = true, description = function ()\n\n            -- get packages for each repositories\n            local packages_repo = {}\n            for _, instance in ipairs(packages) do\n                -- achive packages by repository\n                local reponame = instance:repo() and instance:repo():name() or (instance:is_system() and \"system\" or \"\")\n                if instance:is_thirdparty() then\n                    reponame = instance:name():lower():split(\"::\")[1]\n                end\n                packages_repo[reponame] = packages_repo[reponame] or {}\n                table.insert(packages_repo[reponame], instance)\n            end\n\n            -- show tips\n            cprint(\"${bright color.warning}note: ${clear}download these packages (pass -y to skip confirm)?\")\n            for reponame, packages in pairs(packages_repo) do\n                if reponame ~= \"\" then\n                    print(\"in %s:\", reponame)\n                end\n                local packages_showed = {}\n                for _, instance in ipairs(packages) do\n                    if not packages_showed[tostring(instance)] then\n                        cprint(\"  ${yellow}->${clear} %s %s ${dim}%s\", instance:displayname(), instance:version_str() or \"\", package.get_configs_str(instance))\n                        packages_showed[tostring(instance)] = true\n                    end\n                end\n            end\n        end, answer = function ()\n            cprint(\"please input: ${bright}y${clear} (y/n)\")\n            io.flush()\n            return (io.read() or \"false\"):trim()\n        end})\n\n        -- get confirm result\n        result = option.boolean(result)\n        if type(result) ~= \"boolean\" then\n            result = true\n        end\n    end\n    return result, packages_modified\nend\n\n-- should download package?\nfunction _should_download_package(instance)\n    _g.package_status_cache = _g.package_status_cache or {}\n    local result = _g.package_status_cache[tostring(instance)]\n    if result == nil then\n        result = package.should_install(instance) or false\n        _g.package_status_cache[tostring(instance)] = result\n    end\n    return result\nend\n\n-- download packages\nfunction _download_packages(packages_download)\n\n    -- we need to hide wait characters if is not a tty\n    local show_wait = io.isatty()\n\n    -- init downloaded packages\n    local packages_downloaded = {}\n    for _, instance in ipairs(packages_download) do\n        packages_downloaded[tostring(instance)] = false\n    end\n\n    -- save terminal mode for stdout, @see https://github.com/xmake-io/xmake/issues/1924\n    local term_mode_stdout = tty.term_mode(\"stdout\")\n\n    -- do download\n    local waiting_indicator_helper = show_wait and waiting_indicator.new() or nil\n    local packages_downloading = {}\n    local packages_pending = table.copy(packages_download)\n    local working_count = 0\n    local downloading_count = 0\n    runjobs(\"download_packages\", function (index)\n\n        -- fetch a new package\n        local instance = nil\n        while instance == nil and #packages_pending > 0 do\n            instance = packages_pending[1]\n            table.remove(packages_pending, 1)\n        end\n        if instance then\n            working_count = working_count + 1\n            downloading_count = downloading_count + 1\n            packages_downloading[index] = instance\n\n            -- download this package\n            action_download(instance, {outputdir = option.get(\"packagedir\"), download_only = true})\n\n            -- reset package status cache\n            _g.package_status_cache = nil\n\n            -- next\n            downloading_count = downloading_count - 1\n            packages_downloading[index] = nil\n            packages_downloaded[tostring(instance)] = true\n\n            -- update working count\n            working_count = working_count - 1\n        end\n\n    end, {total = #packages_download,\n          comax = (option.get(\"verbose\") or option.get(\"diagnosis\")) and 1 or 4,\n          isolate = true,\n          on_timer = function (running_jobs_indices)\n\n        -- do not print progress info if be verbose\n        if option.get(\"verbose\") or not show_wait then\n            return\n        end\n\n        -- make downloading packages list\n        local downloading = {}\n        for _, index in ipairs(running_jobs_indices) do\n            local instance = packages_downloading[index]\n            if instance then\n                table.insert(downloading, instance:displayname())\n            end\n        end\n        -- we just return it directly if no thing is waited\n        -- @see https://github.com/xmake-io/xmake/issues/3535\n        if #downloading == 0 and #downloading == 0 then\n            return\n        end\n\n        -- get waitobjs tips\n        local tips = nil\n        local waitobjs = scheduler.co_group_waitobjs(\"download_packages\")\n        if waitobjs:size() > 0 then\n            local names = {}\n            for _, obj in waitobjs:keys() do\n                if obj:otype() == scheduler.OT_PROC then\n                    table.insert(names, obj:name())\n                elseif obj:otype() == scheduler.OT_SOCK then\n                    table.insert(names, \"sock\")\n                elseif obj:otype() == scheduler.OT_PIPE then\n                    table.insert(names, \"pipe\")\n                end\n            end\n            names = table.unique(names)\n            if #names > 0 then\n                names = table.concat(names, \",\")\n                if #names > 16 then\n                    names = names:sub(1, 16) .. \"..\"\n                end\n                tips = string.format(\"(%d/%s)\", waitobjs:size(), names)\n            end\n        end\n\n        -- fix terminal mode to avoid some subprocess to change it\n        -- @see https://github.com/xmake-io/xmake/issues/1924\n        if term_mode_stdout ~= tty.term_mode(\"stdout\") then\n            tty.term_mode(\"stdout\", term_mode_stdout)\n        end\n\n        -- trace\n        waiting_indicator_helper:clear()\n        tty.erase_line_to_start().cr()\n        cprintf(\"${yellow}  => \")\n        if #downloading > 0 then\n            cprintf(\"downloading ${color.dump.string}%s\", table.concat(downloading, \", \"))\n        end\n        cprintf(\" .. %s\", tips and (\"${dim}\" .. tips .. \"${clear} \") or \"\")\n        waiting_indicator_helper:write()\n    end, exit = function(errors)\n        if errors then\n            tty.erase_line_to_start().cr()\n            io.flush()\n        end\n    end})\nend\n\n-- download packages\nfunction main(requires, opt)\n    opt = opt or {}\n\n    -- load packages\n    local packages = package.load_packages(requires, opt)\n\n    -- save terminal mode for stdout\n    local term_mode_stdout = tty.term_mode(\"stdout\")\n\n    -- filter packages\n    local packages_download = {}\n    local packages_unsupported = {}\n    local packages_unknown = {}\n    for _, instance in ipairs(packages) do\n        if _should_download_package(instance) then\n            if instance:is_supported() then\n                if #instance:urls() > 0 then\n                    packages_download[tostring(instance)] = instance\n                end\n                table.insert(packages_download, instance)\n            elseif not instance:is_optional() then\n                if not instance:exists() and instance:is_system() then\n                    table.insert(packages_unknown, instance)\n                else\n                    table.insert(packages_unsupported, instance)\n                end\n            end\n        end\n    end\n\n    -- exists unknown packages?\n    local has_errors = false\n    if #packages_unknown > 0 then\n        cprint(\"${bright color.warning}note: ${clear}the following packages were not found in any repository (check if they are spelled correctly):\")\n        for _, instance in ipairs(packages_unknown) do\n            print(\"  -> %s\", instance:displayname())\n        end\n        has_errors = true\n    end\n\n    -- exists unsupported packages?\n    if #packages_unsupported > 0 then\n        cprint(\"${bright color.warning}note: ${clear}the following packages are unsupported on $(plat)/$(arch):\")\n        for _, instance in ipairs(packages_unsupported) do\n            print(\"  -> %s %s\", instance:displayname(), instance:version_str() or \"\")\n        end\n        has_errors = true\n    end\n\n    if has_errors then\n        raise()\n    end\n\n    -- get user confirm\n    local confirm = _get_confirm(packages_download)\n    if not confirm then\n        return\n    end\n\n    -- sort package urls\n    _sort_packages_urls(packages_download)\n\n    -- download all required packages from repositories\n    _download_packages(packages_download)\n    cprint(\"outputdir: ${bright}%s\", option.get(\"packagedir\"))\n    cprint(\"${color.success}download packages ok\")\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/environment.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        environment.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\n\n-- enter environment\n--\n-- ensure that we can find some basic tools: git, unzip, ...\n--\n-- If these tools not exist, we will install it first.\n--\nfunction enter()\n\n    -- enter the environments of git\n    _g._OLDENVS = packagenv.enter(\"git\")\n\n    -- git not found? install it first\n    local packages = {}\n    local git = find_tool(\"git\")\n    if not git then\n        table.join2(packages, install_packages(\"git\"))\n    end\n\n    -- missing the necessary unarchivers for *.gz, *.7z? install them first, e.g. gzip, 7z, tar ..\n    local zip = (find_tool(\"gzip\") and find_tool(\"tar\")) or find_tool(\"7z\")\n    if not zip then\n        table.join2(packages, install_packages(\"7z\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force to detect and flush detect cache after loading all environments\n    if not git then\n        find_tool(\"git\", {force = true})\n    end\n    if not zip then\n        find_tool(\"7z\", {force = true})\n    end\nend\n\n-- leave environment\nfunction leave()\n    local oldenvs = _g._OLDENVS\n    if oldenvs then\n        os.setenvs(oldenvs)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/export_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        export_packages.lua\n--\n\n-- imports\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"private.action.require.impl.package\")\n\n-- export packages\nfunction main(requires, opt)\n    opt = opt or {}\n    local packages = {}\n    local packagedir = assert(opt.packagedir)\n    for _, instance in ipairs(package.load_packages(requires, opt)) do\n\n        -- get export path\n        local installdir = instance:installdir()\n        local rootdir = core_package.installdir()\n        local exportpath, count = installdir:replace(rootdir, packagedir, {plain = true})\n        if count == 0 and instance:is_binary_embed() then\n            -- maybe local binary embed package\n            -- @see https://github.com/xmake-io/xmake/issues/3470\n            local name = instance:name()\n            installdir = instance:scriptdir()\n            if installdir:endswith(path.join(name:sub(1, 1), name)) then\n                rootdir = path.directory(path.directory(installdir))\n                exportpath, count = installdir:replace(rootdir, packagedir, {plain = true})\n            end\n        end\n\n        -- export this package\n        if exportpath and count == 1 and instance:fetch({force = true}) then\n            print(\"exporting %s-%s %s\", instance:displayname(), instance:version_str(), package.get_configs_str(instance))\n            cprint(\"  ${yellow}->${clear} %s\", exportpath)\n            os.cp(installdir, exportpath, {symlink = true})\n            os.tryrm(path.join(exportpath, \"references.txt\"))\n            table.insert(packages, instance)\n        end\n    end\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/import_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        import_packages.lua\n--\n\n-- imports\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"private.action.require.impl.package\")\n\n-- import packages\nfunction main(requires, opt)\n    opt = opt or {}\n    local packages = {}\n    local packagedir = assert(opt.packagedir)\n    for _, instance in ipairs(package.load_packages(requires, opt)) do\n\n        -- get import path\n        local installdir = instance:installdir()\n        local rootdir = core_package.installdir()\n        local importpath, count = installdir:replace(rootdir, packagedir, {plain = true})\n\n        -- import this package\n        if importpath and count == 1 then\n            print(\"importing %s-%s %s\", instance:displayname(), instance:version_str(), package.get_configs_str(instance))\n            cprint(\"  ${yellow}<-${clear} %s\", importpath)\n            os.tryrm(installdir)\n            os.cp(importpath, installdir, {symlink = true})\n            table.insert(packages, instance)\n        end\n    end\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/install_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install_packages.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"core.project.project\")\nimport(\"core.base.tty\")\nimport(\"async.runjobs\")\nimport(\"utils.waiting_indicator\", {alias = \"waiting_indicator\"})\nimport(\"net.fasturl\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.lock_packages\")\nimport(\"private.action.require.impl.register_packages\")\nimport(\"private.action.require.impl.actions.check\", {alias = \"action_check\"})\nimport(\"private.action.require.impl.actions.install\", {alias = \"action_install\"})\nimport(\"private.action.require.impl.actions.download\", {alias = \"action_download\"})\n\n-- sort packages urls\nfunction _sort_packages_urls(packages)\n\n    -- add all urls to fasturl and prepare to sort them together\n    for _, instance in pairs(packages) do\n        fasturl.add(instance:urls())\n    end\n\n    -- sort and update urls\n    for _, instance in pairs(packages) do\n        instance:urls_set(fasturl.sort(instance:urls()))\n    end\nend\n\n-- replace modified package\nfunction _replace_package(packages, instance, extinstance)\n    for idx, rawinstance in ipairs(packages) do\n        if rawinstance == instance then\n            packages[idx] = extinstance\n        end\n        local deps = rawinstance._DEPS\n        for name, dep in pairs(deps) do\n            if dep == instance then\n                deps[name] = nil\n                deps[extinstance:name()] = extinstance\n                break\n            end\n        end\n        local parents = rawinstance._PARENTS\n        for name, parent in pairs(parents) do\n            if parent == instance then\n                parents[name] = nil\n                parents[extinstance:name()] = extinstance\n                break\n            end\n        end\n        local orderdeps = rawinstance._ORDERDEPS\n        for depidx, dep in ipairs(orderdeps) do\n            if dep == instance then\n                orderdeps[depidx] = extinstance\n                break\n            end\n        end\n        local librarydeps = rawinstance._LIBRARYDEPS\n        for depidx, dep in ipairs(librarydeps) do\n            if dep == instance then\n                librarydeps[depidx] = extinstance\n                break\n            end\n        end\n        local plaindeps = rawinstance._PLAINDEPS\n        for depidx, dep in ipairs(rawinstance._PLAINDEPS) do\n            if dep == instance then\n                plaindeps[depidx] = extinstance\n                break\n            end\n        end\n    end\nend\n\n-- replace modified packages\nfunction _replace_packages(packages, packages_modified)\n    for _, package_modified in ipairs(packages_modified) do\n        local instance = package_modified.instance\n        local extinstance = package_modified.extinstance\n        _replace_package(packages, instance, extinstance)\n    end\nend\n\n-- get user confirm from 3rd package sources\n-- @see https://github.com/xmake-io/xmake/issues/1140\nfunction _get_confirm_from_3rd(packages)\n\n    -- get extpackages list\n    local extpackages_list = _g.extpackages_list\n    if not extpackages_list then\n        extpackages_list = {}\n        for _, instance in ipairs(packages) do\n            local extsources = instance:get(\"extsources\")\n            local extsources_extra = instance:extraconf(\"extsources\")\n            if extsources then\n                local extpackages = package.load_packages(extsources, extsources_extra)\n                for _, extinstance in ipairs(extpackages) do\n                    table.insert(extpackages_list, {instance = instance, extinstance = extinstance})\n                end\n            end\n        end\n        _g.extpackages_list = extpackages_list\n    end\n\n    -- no extpackages?\n    if #extpackages_list == 0 then\n        print(\"no more packages!\")\n        return\n    end\n\n    -- get confirm result\n    local result = utils.confirm({description = function ()\n        cprint(\"${bright color.warning}note: ${clear}select the following 3rd packages\")\n        for idx, extinstance in ipairs(extpackages_list) do\n            local instance = extinstance.instance\n            local extinstance = extinstance.extinstance\n            cprint(\"  ${yellow}%d.${clear} %s ${yellow}->${clear} %s %s ${dim}%s\",\n                idx, extinstance:name(),\n                instance:displayname(),\n                instance:version_str() or \"\",\n                package.get_configs_str(instance))\n        end\n    end, answer = function ()\n        cprint(\"please input number list: ${bright}n${clear} (1,2,..)\")\n        io.flush()\n        return (io.read() or \"n\"):trim()\n    end})\n\n    -- get confirmed extpackages\n    local confirmed_extpackages = {}\n    if result and result ~= \"n\" then\n        for _, idx in ipairs(result:split(',')) do\n            idx = tonumber(idx)\n            if extpackages_list[idx] then\n                table.insert(confirmed_extpackages, extpackages_list[idx])\n            end\n        end\n    end\n\n    -- modify packages\n    if #confirmed_extpackages > 0 then\n        _replace_packages(packages, confirmed_extpackages)\n        return confirmed_extpackages\n    end\nend\n\n-- get user confirm\nfunction _get_confirm(packages, opt)\n    opt = opt or {}\n\n    -- no confirmed packages?\n    if #packages == 0 then\n        return true\n    end\n\n    local result\n    local packages_modified\n    while result == nil do\n        -- get confirm result\n        result = utils.confirm({default = true, description = function ()\n\n            -- get packages for each repositories\n            local packages_repo = {}\n            local packages_group = {}\n            for _, instance in ipairs(packages) do\n                -- achive packages by repository\n                local reponame = instance:repo() and instance:repo():name() or (instance:is_system() and \"system\" or \"\")\n                if instance:is_thirdparty() then\n                    reponame = instance:name():lower():split(\"::\")[1]\n                end\n                packages_repo[reponame] = packages_repo[reponame] or {}\n                table.insert(packages_repo[reponame], instance)\n\n                -- achive packages by group\n                local group = instance:group()\n                if group then\n                    packages_group[group] = packages_group[group] or {}\n                    table.insert(packages_group[group], instance)\n                end\n            end\n\n            -- show tips\n            if opt.toolchain then\n                cprint(\"${bright color.warning}note: ${clear}install or modify (m) these ${bright}toolchain${clear} packages first (pass -y to skip confirm)?\")\n            else\n                cprint(\"${bright color.warning}note: ${clear}install or modify (m) these packages (pass -y to skip confirm)?\")\n            end\n            for reponame, packages in pairs(packages_repo) do\n                if reponame ~= \"\" then\n                    print(\"in %s:\", reponame)\n                end\n                local packages_showed = {}\n                for _, instance in ipairs(packages) do\n                    if not packages_showed[tostring(instance)] then\n                        local group = instance:group()\n                        if group and packages_group[group] and #packages_group[group] > 1 then\n                            for idx, package_in_group in ipairs(packages_group[group]) do\n                                cprint(\"  ${yellow}%s${clear} %s %s ${dim}%s\", idx == 1 and \"->\" or \"   or\",\n                                    package_in_group:displayname(), package_in_group:version_str() or \"\",\n                                    package.get_configs_str(package_in_group))\n                                for _, tip in ipairs(package_in_group:get(\"installtips\")) do\n                                    if idx == 1 then\n                                        cprint(\"     ${yellow}*${clear} %s\", tip)\n                                    else\n                                        cprint(\"        ${yellow}*${clear} %s\", tip)\n                                    end\n                                end\n                                packages_showed[tostring(package_in_group)] = true\n                            end\n                            packages_group[group] = nil\n                        else\n                            cprint(\"  ${yellow}->${clear} %s %s ${dim}%s\",\n                                instance:displayname(), instance:version_str() or \"\",\n                                package.get_configs_str(instance))\n                            for _, tip in ipairs(instance:get(\"installtips\")) do\n                                cprint(\"     ${yellow}*${clear} %s\", tip)\n                            end\n                            packages_showed[tostring(instance)] = true\n                        end\n                    end\n                end\n            end\n        end, answer = function ()\n            cprint(\"please input: ${bright}y${clear} (y/n/m)\")\n            io.flush()\n            return (io.read() or \"false\"):trim()\n        end})\n\n        -- modify to select 3rd packages?\n        if result == \"m\" then\n            packages_modified = _get_confirm_from_3rd(packages)\n            result = nil\n        else\n            -- get confirm result\n            result = option.boolean(result)\n            if type(result) ~= \"boolean\" then\n                result = true\n            end\n        end\n    end\n    return result, packages_modified\nend\n\n-- show upgraded packages\nfunction _show_upgraded_packages(packages)\n    local upgraded_count = 0\n    for _, instance in ipairs(packages) do\n        local locked_requireinfo = package.get_locked_requireinfo(instance:requireinfo(), {force = true})\n        if locked_requireinfo and locked_requireinfo.version and instance:version() and instance:version():gt(locked_requireinfo.version) then\n            cprint(\"  ${color.dump.string}%s${clear}: %s -> ${color.success}%s\", instance:displayname(), locked_requireinfo.version, instance:version_str())\n            upgraded_count = upgraded_count + 1\n        end\n    end\n    cprint(\"${bright}%d packages are upgraded!\", upgraded_count)\nend\n\n-- fetch packages\nfunction _fetch_packages(packages_fetch, installdeps)\n\n    -- init installed packages\n    local packages_fetched = {}\n    for _, instance in ipairs(packages_fetch) do\n        packages_fetched[tostring(instance)] = false\n    end\n\n    -- save terminal mode for stdout, @see https://github.com/xmake-io/xmake/issues/1924\n    local term_mode_stdout = tty.term_mode(\"stdout\")\n\n    -- do fetch\n    local packages_fetching = {}\n    local packages_pending = table.copy(packages_fetch)\n    local working_count = 0\n    local fetching_count = 0\n    local parallelize = true\n    runjobs(\"fetch_packages\", function (index)\n\n        -- fetch a new package\n        local instance = nil\n        while instance == nil and #packages_pending > 0 do\n            for idx, pkg in ipairs(packages_pending) do\n\n                -- all dependencies has been fetched? we fetch it now\n                local ready = true\n                local dep_not_ready = nil\n                for _, dep in pairs(installdeps[tostring(pkg)]) do\n                    local fetched = packages_fetched[tostring(dep)]\n                    if fetched == false then\n                        ready = false\n                        dep_not_ready = dep\n                        break\n                    end\n                end\n\n                -- get a package with the ready status\n                if ready then\n                    instance = pkg\n                    table.remove(packages_pending, idx)\n                    break\n                elseif working_count == 0 then\n                    if #packages_pending == 1 and dep_not_ready then\n                        raise(\"package(%s): cannot be fetched, there are dependencies(%s) that cannot be fetched!\", pkg:displayname(), dep_not_ready:displayname())\n                    elseif #packages_pending == 1 then\n                        raise(\"package(%s): cannot be fetched!\", pkg:displayname())\n                    end\n                end\n            end\n            if instance == nil and #packages_pending > 0 then\n                os.sleep(100)\n            end\n        end\n        if instance then\n\n            -- update working count\n            working_count = working_count + 1\n\n            -- disable parallelize?\n            if not instance:is_parallelize() then\n                parallelize = false\n            end\n            if not parallelize then\n                while fetching_count > 0 do\n                    os.sleep(100)\n                end\n            end\n            fetching_count = fetching_count + 1\n\n            -- fetch this package\n            packages_fetching[index] = instance\n            local oldenvs = os.getenvs()\n            instance:envs_enter()\n            instance:lock()\n            instance:fetch()\n            instance:unlock()\n            os.setenvs(oldenvs)\n\n            -- fix terminal mode to avoid some subprocess to change it\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/1924\n            -- https://github.com/xmake-io/xmake/issues/2329\n            if term_mode_stdout ~= tty.term_mode(\"stdout\") then\n                tty.term_mode(\"stdout\", term_mode_stdout)\n            end\n\n            -- next\n            parallelize = true\n            fetching_count = fetching_count - 1\n            packages_fetching[index] = nil\n            packages_fetched[tostring(instance)] = true\n\n            -- update working count\n            working_count = working_count - 1\n        end\n        packages_fetching[index] = nil\n\n    end, {total = #packages_fetch,\n          comax = (option.get(\"verbose\") or option.get(\"diagnosis\")) and 1 or 4,\n          isolate = true})\nend\n\n-- should fetch package?\nfunction _should_fetch_package(instance)\n    if instance:is_fetchonly() or not option.get(\"force\") or\n        (option.get(\"shallow\") and not instance:is_toplevel()) then\n        return true\n    end\nend\n\n-- should install package?\nfunction _should_install_package(instance)\n    _g.package_status_cache = _g.package_status_cache or {}\n    local result = _g.package_status_cache[tostring(instance)]\n    if result == nil then\n        result = package.should_install(instance) or false\n        _g.package_status_cache[tostring(instance)] = result\n    end\n    return result\nend\n\n-- do install packages\nfunction _do_install_packages(packages_install, packages_download, installdeps)\n\n    -- we need to hide wait characters if is not a tty\n    local show_wait = io.isatty()\n\n    -- init installed packages\n    local packages_installed = {}\n    for _, instance in ipairs(packages_install) do\n        packages_installed[tostring(instance)] = false\n    end\n\n    -- save terminal mode for stdout, @see https://github.com/xmake-io/xmake/issues/1924\n    local term_mode_stdout = tty.term_mode(\"stdout\")\n\n    -- do install\n    local waiting_indicator_helper = show_wait and waiting_indicator.new() or nil\n    local packages_installing = {}\n    local packages_downloading = {}\n    local packages_pending = table.copy(packages_install)\n    local packages_in_group = {}\n    local working_count = 0\n    local installing_count = 0\n    local parallelize = true\n    runjobs(\"install_packages\", function (index)\n\n        -- fetch a new package\n        local instance = nil\n        while instance == nil and #packages_pending > 0 do\n            for idx, pkg in ipairs(packages_pending) do\n\n                -- all dependencies has been installed? we install it now\n                local ready = true\n                local dep_not_found = nil\n                for _, dep in pairs(installdeps[tostring(pkg)]) do\n                    local installed = packages_installed[tostring(dep)]\n                    if installed == false or (installed == nil and _should_install_package(dep) and not dep:is_optional()) then\n                        ready = false\n                        dep_not_found = dep\n                        break\n                    end\n                end\n                local group = pkg:group()\n                if ready and group then\n                    -- this group has been installed? skip it\n                    local group_status = packages_in_group[group]\n                    if group_status == 1 then\n                        table.remove(packages_pending, idx)\n                        break\n                    -- this group is installing? wait it\n                    elseif group_status == 0 then\n                        ready = false\n                    end\n                end\n\n                -- get a package with the ready status\n                if ready then\n                    instance = pkg\n                    table.remove(packages_pending, idx)\n                    break\n                elseif working_count == 0 then\n                    if #packages_pending == 1 and dep_not_found then\n                        raise(\"package(%s): cannot be installed, there are dependencies(%s) that cannot be installed!\", pkg:displayname(), dep_not_found:displayname())\n                    elseif #packages_pending == 1 then\n                        raise(\"package(%s): cannot be installed!\", pkg:displayname())\n                    end\n                end\n            end\n            if instance == nil and #packages_pending > 0 then\n                os.sleep(100)\n            end\n        end\n        if instance then\n\n            -- update working count\n            working_count = working_count + 1\n\n            -- only install the first package in same group\n            local group = instance:group()\n            if not group or not packages_in_group[group] then\n\n                -- disable parallelize?\n                if not instance:is_parallelize() then\n                    parallelize = false\n                end\n                if not parallelize then\n                    while installing_count > 0 do\n                        os.sleep(100)\n                    end\n                end\n                installing_count = installing_count + 1\n\n                -- mark this group as 'installing'\n                if group then\n                    packages_in_group[group] = 0\n                end\n\n                -- install package from the multiple schemes\n                for _, scheme in ipairs(instance:schemes_orderlist()) do\n                    instance:prepare_install_scheme(scheme)\n\n                    -- download this package first\n                    local downloaded = true\n                    if packages_download[tostring(instance)] then\n                        packages_downloading[index] = instance\n                        packages_installing[index] = nil\n                        action_check(instance)\n                        downloaded = action_download(instance)\n                        packages_downloading[index] = nil\n                    end\n\n                    packages_installing[index] = instance\n                    if downloaded then\n                        if action_install(instance) then\n                            -- install ok\n                            break\n                        end\n                    end\n                end\n\n                -- reset package status cache\n                _g.package_status_cache = nil\n\n                -- register it to local cache if it is root required package\n                --\n                -- @note we need to register the package in time,\n                -- because other packages may be used, e.g. toolchain/packages\n                if instance:is_toplevel() then\n                    register_packages({instance})\n                end\n\n                -- mark this group as 'installed' or 'failed'\n                if group then\n                    packages_in_group[group] = instance:exists() and 1 or -1\n                end\n\n                -- next\n                parallelize = true\n                installing_count = installing_count - 1\n                packages_installing[index] = nil\n                packages_installed[tostring(instance)] = true\n            end\n\n            -- update working count\n            working_count = working_count - 1\n        end\n        packages_installing[index] = nil\n        packages_downloading[index] = nil\n\n    end, {total = #packages_install,\n          comax = (option.get(\"verbose\") or option.get(\"diagnosis\")) and 1 or 4,\n          isolate = true,\n          on_timer = function (running_jobs_indices)\n\n        -- do not print progress info if be verbose\n        if option.get(\"verbose\") or not show_wait then\n            return\n        end\n\n        -- make installing and downloading packages list\n        local installing = {}\n        local downloading = {}\n        for _, index in ipairs(running_jobs_indices) do\n            local instance = packages_installing[index]\n            if instance then\n                table.insert(installing, instance:displayname())\n            end\n            local instance = packages_downloading[index]\n            if instance then\n                table.insert(downloading, instance:displayname())\n            end\n        end\n        -- we just return it directly if no thing is waited\n        -- @see https://github.com/xmake-io/xmake/issues/3535\n        if #installing == 0 and #downloading == 0 then\n            return\n        end\n\n        -- get waitobjs tips\n        local tips = nil\n        local waitobjs = scheduler.co_group_waitobjs(\"install_packages\")\n        if waitobjs:size() > 0 then\n            local names = {}\n            for _, obj in waitobjs:keys() do\n                if obj:otype() == scheduler.OT_PROC then\n                    table.insert(names, obj:name())\n                elseif obj:otype() == scheduler.OT_SOCK then\n                    table.insert(names, \"sock\")\n                elseif obj:otype() == scheduler.OT_PIPE then\n                    table.insert(names, \"pipe\")\n                end\n            end\n            names = table.unique(names)\n            if #names > 0 then\n                names = table.concat(names, \",\")\n                if #names > 16 then\n                    names = names:sub(1, 16) .. \"..\"\n                end\n                tips = string.format(\"(%d/%s)\", waitobjs:size(), names)\n            end\n        end\n\n        -- fix terminal mode to avoid some subprocess to change it\n        -- @see https://github.com/xmake-io/xmake/issues/1924\n        if term_mode_stdout ~= tty.term_mode(\"stdout\") then\n            tty.term_mode(\"stdout\", term_mode_stdout)\n        end\n\n        -- trace\n        waiting_indicator_helper:clear()\n        tty.erase_line_to_start().cr()\n        cprintf(\"${yellow}  => \")\n        if #downloading > 0 then\n            cprintf(\"downloading ${color.dump.string}%s\", table.concat(downloading, \", \"))\n        end\n        if #installing > 0 then\n            cprintf(\"%sinstalling ${color.dump.string}%s\", #downloading > 0 and \", \" or \"\", table.concat(installing, \", \"))\n        end\n        cprintf(\" .. %s\", tips and (\"${dim}\" .. tips .. \"${clear} \") or \"\")\n        waiting_indicator_helper:write()\n    end, exit = function(errors)\n        if errors then\n            tty.erase_line_to_start().cr()\n            io.flush()\n        end\n    end})\nend\n\n-- only enable the first package in same group and root packages\nfunction _disable_other_packages_in_group(packages)\n    local registered_in_group = {}\n    for _, instance in ipairs(packages) do\n        local group = instance:group()\n        if instance:is_toplevel() and group then\n            local required_package = project.required_package(instance:alias() or instance:name())\n            if required_package then\n                if not registered_in_group[group] and required_package:enabled() then\n                    registered_in_group[group] = true\n                elseif required_package:enabled() then\n                    required_package:enable(false)\n                    required_package:save()\n                end\n            end\n        end\n    end\nend\n\n-- sort packages for installation dependencies\nfunction _sort_packages_for_installdeps(packages, installdeps, order_packages)\n    for _, instance in ipairs(packages) do\n        local deps = installdeps[tostring(instance)]\n        if deps then\n            _sort_packages_for_installdeps(deps, installdeps, order_packages)\n        end\n        table.insert(order_packages, instance)\n    end\nend\n\n-- get package installation dependencies\nfunction _get_package_installdeps(packages)\n    local installdeps = {}\n    local packagesmap = {}\n    for _, instance in ipairs(packages) do\n        -- we need to use alias name first for toolchain/packages\n        packagesmap[instance:alias() or instance:name()] = instance\n    end\n    for _, instance in ipairs(packages) do\n        local deps = {}\n        if instance:orderdeps() then\n            deps = table.copy(instance:orderdeps())\n        end\n        -- patch toolchain/packages to installdeps, because we need to install toolchain package first\n        for _, toolchain in ipairs(instance:toolchains()) do\n            for _, packagename in ipairs(toolchain:config(\"packages\")) do\n                if packagesmap[packagename] ~= instance then -- avoid loop recursion\n                    table.insert(deps, packagesmap[packagename])\n                end\n            end\n        end\n        installdeps[tostring(instance)] = deps\n    end\n    return installdeps\nend\n\n-- install packages\nfunction _install_packages(requires, opt)\n    opt = opt or {}\n\n    -- load packages\n    local packages = package.load_packages(requires, opt)\n\n    -- get package installation dependencies\n    local installdeps = _get_package_installdeps(packages)\n\n    -- sort packages for installdeps\n    local order_packages = {}\n    _sort_packages_for_installdeps(packages, installdeps, order_packages)\n    packages = table.unique(order_packages)\n\n    -- save terminal mode for stdout\n    local term_mode_stdout = tty.term_mode(\"stdout\")\n\n    -- fetch and register packages (with system) from local first\n    local packages_fetch = {}\n    for _, instance in ipairs(packages) do\n        if _should_fetch_package(instance) then\n            table.insert(packages_fetch, instance)\n        end\n    end\n    _fetch_packages(packages_fetch, installdeps)\n\n    -- register all installed root packages to local cache\n    register_packages(packages)\n\n    -- filter packages\n    local packages_install = {}\n    local packages_download = {}\n    local packages_unsupported = {}\n    local packages_not_found = {}\n    local packages_unknown = {}\n    for _, instance in ipairs(packages) do\n        if _should_install_package(instance) then\n            if instance:is_supported() then\n                if #instance:urls() > 0 then\n                    packages_download[tostring(instance)] = instance\n                end\n                table.insert(packages_install, instance)\n            elseif not instance:is_optional() then\n                if not instance:exists() and instance:is_system() then\n                    table.insert(packages_unknown, instance)\n                else\n                    table.insert(packages_unsupported, instance)\n                end\n            end\n        -- @see https://github.com/xmake-io/xmake/issues/2050\n        elseif not instance:exists() and not instance:is_optional() then\n            local requireinfo = instance:requireinfo()\n            if requireinfo and requireinfo.system then\n                table.insert(packages_not_found, instance)\n            end\n        end\n    end\n\n    -- exists unknown packages?\n    local has_errors = false\n    if #packages_unknown > 0 then\n        cprint(\"${bright color.warning}note: ${clear}the following packages were not found in any repository (check if they are spelled correctly):\")\n        for _, instance in ipairs(packages_unknown) do\n            local tips\n            local possible_package = package.get_possible_package(instance:name())\n            if possible_package then\n                tips = string.format(\", maybe ${bright}%s %s${clear} in %s\", possible_package.name, possible_package.version, possible_package.reponame)\n            end\n            cprint(\"  -> %s%s\", instance:displayname(), tips or \"\")\n        end\n        has_errors = true\n    end\n\n    -- exists unsupported packages?\n    if #packages_unsupported > 0 then\n        local packages_unsupported_maps = {}\n        for _, instance in ipairs(packages_unsupported) do\n            local key = instance:plat() .. \"/\" .. instance:arch()\n            packages_unsupported_maps[key] = packages_unsupported_maps[key] or {}\n            table.insert(packages_unsupported_maps[key], instance)\n        end\n        for key, instances in pairs(packages_unsupported_maps) do\n            cprint(\"${bright color.warning}note: ${clear}the following packages are unsupported on %s,\", key)\n            cprint(\"${clear}you can try running ${bright}`xrepo update-repo`${clear} to update repositories or open a pr to improve these packages:\")\n            for _, instance in ipairs(instances) do\n                cprint(\"  ${yellow}->${clear} %s %s ${dim}%s\",\n                    instance:displayname(), instance:version_str() or \"\", package.get_configs_str(instance))\n            end\n        end\n        has_errors = true\n    end\n\n    -- exists not found packages?\n    if #packages_not_found > 0 then\n        if packages_not_found[1]:is_cross() then\n            cprint(\"${bright color.warning}note: ${clear}system package is not supported for cross-compilation currently, the following system packages cannot be found:\")\n        else\n            cprint(\"${bright color.warning}note: ${clear}the following packages were not found on your system, try again after installing them:\")\n        end\n        for _, instance in ipairs(packages_not_found) do\n            print(\"  -> %s %s\", instance:displayname(), instance:version_str() or \"\")\n        end\n        has_errors = true\n    end\n\n    if has_errors then\n        raise()\n    end\n\n    -- get user confirm\n    local confirm, packages_modified = _get_confirm(packages_install, opt)\n    if not confirm then\n        local packages_must = {}\n        for _, instance in ipairs(packages_install) do\n            if not instance:is_optional() then\n                table.insert(packages_must, instance:displayname())\n            end\n        end\n        if #packages_must > 0 then\n            raise(\"packages(%s): must be installed!\", table.concat(packages_must, \", \"))\n        else\n            -- continue other actions\n            return\n        end\n    end\n\n    -- show upgraded information\n    if option.get(\"upgrade\") then\n        print(\"upgrading packages ..\")\n    end\n\n    -- some packages are modified? we need to fix packages list and all deps\n    if packages_modified then\n        order_packages = {}\n        _replace_packages(packages, packages_modified)\n        installdeps = _get_package_installdeps(packages)\n        _sort_packages_for_installdeps(packages, installdeps, order_packages)\n        packages = table.unique(order_packages)\n     end\n\n    -- sort package urls\n    _sort_packages_urls(packages_download)\n\n    -- install all required packages from repositories\n    _do_install_packages(packages_install, packages_download, installdeps)\n\n    -- disable other packages in same group\n    _disable_other_packages_in_group(packages)\n\n    -- re-register and refresh all root packages to local cache,\n    -- because there may be some missing optional dependencies reinstalled\n    register_packages(packages)\n\n    -- show upgraded packages\n    if option.get(\"upgrade\") then\n        _show_upgraded_packages(packages)\n    end\n    return packages\nend\n\nfunction main(requires, opt)\n    -- we need to install toolchain packages first,\n    -- because we will call compiler-specific api in package.on_load,\n    -- and we will check package toolchains before calling package.on_load\n    --\n    -- @see https://github.com/xmake-io/xmake/pull/5466\n    local packages = {}\n    table.join2(packages, _install_packages(requires, table.join(opt or {}, {toolchain = true})))\n    table.join2(packages, _install_packages(requires, opt))\n\n    -- lock packages\n    lock_packages(packages)\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/lock_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lock_packages.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.project.config\")\nimport(\"devel.git\")\nimport(\"private.action.require.impl.utils.filter\")\nimport(\"private.action.require.impl.utils.requirekey\")\n\n-- get locked package key\nfunction _get_packagelock_key(instance)\n    local requireinfo = instance:requireinfo()\n    return requireinfo and requireinfo.requirekey\nend\n\n-- lock package\nfunction _lock_package(instance)\n    local result      = {}\n    local repo        = instance:repo()\n    result.version    = instance:version_str()\n    result.branch     = instance:branch()\n    result.tag        = instance:tag()\n    if repo then\n        -- Even when locking pre-compiled packages,\n        -- we always use the repo and commit info in the current repository (instead of precompiled-artifacts manifest)\n        -- to ensure that the repo information remains stable when reverting to source code installation.\n        result.repo   = {url = repo:url(), commit = repo:commit(), branch = repo:branch()}\n    end\n    return result\nend\n\n-- lock all required packages\nfunction main(packages)\n    if project.policy(\"package.requires_lock\") then\n        local plat = config.plat() or os.subhost()\n        local arch = config.arch() or os.subarch()\n        local key = plat .. \"|\" .. arch\n        local results = os.isfile(project.requireslock()) and io.load(project.requireslock()) or {}\n        results.__meta__ = results.__meta__ or {}\n        results.__meta__.version = project.requireslock_version()\n        results[key] = {}\n        for _, instance in ipairs(packages) do\n            local packagelock_key = _get_packagelock_key(instance)\n            results[key][packagelock_key] = _lock_package(instance)\n        end\n        -- write to temporary file first, then copy if content is different\n        local lockfile = project.requireslock()\n        local content = string.serialize(results, {orderkeys = true})\n        local tmpfile = os.tmpfile()\n\n        -- write to temporary file\n        io.writefile(tmpfile, content, {encoding = \"binary\"})\n\n        -- copy to target file only if content is different\n        os.cp(tmpfile, lockfile, {copy_if_different = true})\n        os.rm(tmpfile)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.hashset\")\nimport(\"utils.progress\")\nimport(\"core.cache.memcache\")\nimport(\"core.project.project\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.platform.platform\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"devel.git\")\nimport(\"private.action.require.impl.check_api\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.search_packages\")\nimport(\"private.action.require.impl.utils.requirekey\", {alias = \"_get_requirekey\"})\nimport(\"private.utils.package\", {alias = \"package_utils\"})\n\n-- get memcache\nfunction _memcache()\n    return memcache.cache(\"require.impl.package\")\nend\n\n-- load require info\nfunction _load_require(require_str, requires_extra, opt)\n    opt = opt or {}\n\n    -- parse require\n    local packagename, version, reponame = package_utils.parse_requirestr(require_str)\n\n    -- get require extra\n    local require_extra = {}\n    if requires_extra then\n        require_extra = requires_extra[require_str] or {}\n    end\n\n    -- parse configs from package name, and we need to ignore 3rd package name, e.g. vcpkg::boost[core], ...\n    -- @see https://github.com/xmake-io/xmake/issues/5727#issuecomment-2421040107\n    --\n    -- e.g.\n    --   add_requires(\"boost[iostreams,system,thread,key=value] >=1.78.0\")\n    --   add_requires(\"libplist[shared,debug,codecs=[foo,bar,zoo]]\")\n    --\n    local packagename_raw, configs_str = packagename:match(\"(.-)%[(.*)%]\")\n    if packagename_raw and configs_str and not packagename:find(\"::\", 1, true) then\n        configs_str = configs_str:gsub(\"%[(.*)%]\", function (w)\n            return w:replace(\",\", \":\")\n        end)\n        packagename = packagename_raw\n        local splitinfo = configs_str:split(\",\", {plain = true})\n        for _, v in ipairs(splitinfo) do\n            local parts = v:split(\"=\", {plain = true})\n            local k = parts[1]\n            v = parts[2]\n            require_extra.configs = require_extra.configs or {}\n            local configs = require_extra.configs\n            if v then\n                if v:find(\":\", 1 ,true) then\n                    configs[k] = v:split(\":\", {plain = true})\n                else\n                    configs[k] = option.boolean(v)\n                end\n            else\n                configs[k] = true\n            end\n        end\n    end\n\n    -- resolve require info\n    local resolvedinfo = opt.resolvedinfo\n    local requirepath = opt.requirepath\n    if requirepath then\n        requirepath = requirepath .. \".\" .. packagename\n    else\n        requirepath = packagename\n    end\n    resolvedinfo = resolvedinfo and resolvedinfo[requirepath]\n    if resolvedinfo then\n        -- resolve the conflict package version\n        if resolvedinfo.version then\n            version = resolvedinfo.version\n        end\n        -- resolve the conflict package configs\n        if resolvedinfo.configs then\n            require_extra.configs = resolvedinfo.configs\n        end\n    end\n\n    -- get required building configurations\n    -- we need to clone a new configs object, because the whole requireinfo will be modified later.\n    -- @see https://github.com/xmake-io/xmake-repo/pull/2067\n    local require_build_configs = table.clone(require_extra.configs or require_extra.config)\n    if require_extra.debug then\n        require_build_configs = require_build_configs or {}\n        require_build_configs.debug = true\n    end\n\n    -- vs_runtime is deprecated, we should use runtimes\n    if require_build_configs and require_build_configs.vs_runtime then\n        require_build_configs.runtimes = require_build_configs.vs_runtime\n        require_build_configs.vs_runtime = nil\n        wprint(\"add_requires(%s): vs_runtime is deprecated, please use runtimes!\", require_str)\n    end\n\n    -- check require options\n    local extra_options = hashset.of(\"plat\", \"arch\", \"kind\", \"host\", \"targetos\",\n    \"alias\", \"group\", \"system\", \"option\", \"default\", \"optional\", \"debug\",\n    \"verify\", \"external\", \"private\", \"build\", \"configs\", \"version\", \"public\")\n    for name, value in pairs(require_extra) do\n        if not extra_options:has(name) then\n            wprint(\"add_requires(\\\"%s\\\") has unknown option: {%s=%s}!\", require_str, name, tostring(value))\n        end\n    end\n\n    -- we always use xmake package, `add_requires(\"xmake::zlib\")`,\n    -- it is equivalent to `add_requires(\"zlib\", {system = false})`\n    if packagename:startswith(\"xmake::\") then\n        packagename = packagename:sub(8)\n        require_extra.system = false\n    end\n\n    -- init required item\n    local required = {}\n    local parentinfo = opt.parentinfo\n    parentinfo = parentinfo or {}\n    required.packagename = packagename\n    required.requireinfo =\n    {\n        originstr        = require_str,\n        reponame         = reponame,\n        version          = require_extra.version or version,\n        host             = require_extra.host,      -- this package is only for host machine\n        plat             = require_extra.plat,      -- require package in the given platform\n        arch             = require_extra.arch,      -- require package in the given architecture\n        targetos         = require_extra.targetos,  -- require package in the given target os\n        kind             = require_extra.kind,      -- default: library, set package kind, e.g. binary, library, we can set `kind = \"binary\"` to only detect binary program and ignore library.\n        alias            = require_extra.alias,     -- set package alias name\n        group            = require_extra.group,     -- only uses the first package in same group\n        system           = require_extra.system,    -- default: true, we can set it to disable system package manually\n        option           = require_extra.option,    -- set and attach option\n        configs          = require_build_configs,   -- the required building configurations\n        default          = require_extra.default,   -- default: true, we can set it to disable package manually\n        optional         = parentinfo.optional or require_extra.optional, -- default: false, inherit parentinfo.optional\n        verify           = require_extra.verify,    -- default: true, we can set false to ignore sha256sum and select any version\n        external         = require_extra.external,  -- default: true, we use sysincludedirs/-isystem instead of -I/xxx\n        private          = require_extra.private,   -- default: false, private package, only for installation, do not export any links/includes and environments\n        build            = require_extra.build,     -- default: false, always build packages, we do not use the precompiled artifacts\n        resolvedinfo     = resolvedinfo             -- the resolved info for the conflict version/configs\n    }\n    return required.packagename, required.requireinfo\nend\n\n-- load package package from system\nfunction _load_package_from_system(packagename)\n    return core_package.load_from_system(packagename)\nend\n\n-- load package package from project\nfunction _load_package_from_project(packagename)\n    return core_package.load_from_project(packagename)\nend\n\n-- load package package from repositories\nfunction _load_package_from_repository(packagename, opt)\n    opt = opt or {}\n    local packagedir, repo = repository.packagedir(packagename, opt)\n    if packagedir then\n        return core_package.load_from_repository(packagename, packagedir, {plat = opt.plat, arch = opt.arch, repo = repo})\n    end\nend\n\n-- load package package from base\nfunction _load_package_from_base(package, basename, opt)\n    local package_base = _load_package_from_project(basename)\n    if not package_base then\n        package_base = _load_package_from_repository(basename, opt)\n    end\n    if package_base then\n        package._BASE = package_base\n    end\nend\n\n-- has locked requires?\nfunction _has_locked_requires(opt)\n    opt = opt or {}\n    if not option.get(\"upgrade\") or opt.force then\n        return project.policy(\"package.requires_lock\") and os.isfile(project.requireslock())\n    end\nend\n\n-- get locked requires\nfunction _get_locked_requires(requirekey, opt)\n    opt = opt or {}\n    local requireslock = _memcache():get(\"requireslock\")\n    if requireslock == nil or opt.force then\n        if _has_locked_requires(opt) then\n            requireslock = io.load(project.requireslock())\n        end\n        _memcache():set(\"requireslock\", requireslock or false)\n    end\n    if requireslock then\n        local plat = config.plat() or os.subhost()\n        local arch = config.arch() or os.subarch()\n        local key = plat .. \"|\" .. arch\n        if requireslock[key] then\n            return requireslock[key][requirekey], requireslock.__meta__.version\n        end\n    end\nend\n\n-- sort package deps\n--\n-- e.g.\n--\n-- a.deps = b\n-- b.deps = c\n--\n-- orderdeps: c -> b -> a\n--\nfunction _sort_packagedeps(package)\n    -- we must use native deps list instead of package:deps() to generate correct librarydeps\n    local orderdeps = {}\n    for _, dep in ipairs(package:plaindeps()) do\n        if dep then\n            table.join2(orderdeps, _sort_packagedeps(dep))\n            table.insert(orderdeps, dep)\n        end\n    end\n    return orderdeps\nend\n\n-- sort library deps and generate correct link order\n--\n-- e.g.\n--\n-- a.deps = b\n-- b.deps = c\n--\n-- orderdeps: a -> b -> c\n--\nfunction _sort_librarydeps(package, opt)\n    -- we must use native deps list instead of package:deps() to generate correct link order\n    local orderdeps = {}\n    for _, dep in ipairs(package:plaindeps()) do\n        if dep and dep:is_library() and (opt and opt.private or not dep:is_private()) then\n            table.insert(orderdeps, dep)\n            table.join2(orderdeps, _sort_librarydeps(dep, opt))\n        end\n    end\n    return orderdeps\nend\n\n-- get builtin configuration default values\nfunction _get_default_config_value_of(name)\n    local defaults = {\n        debug = false,\n        shared = false,\n        pic = true,\n        lto = false,\n        asan = false\n    }\n    return defaults[name]\nend\n\n-- add some builtin configurations to package\nfunction _add_package_configurations(package)\n    -- we can define configs to override it and it's default value in package()\n    if package:extraconf(\"configs\", \"debug\", \"default\") == nil then\n        local default = _get_default_config_value_of(\"debug\")\n        package:add(\"configs\", \"debug\", {builtin = true, description = \"Enable debug symbols.\", default = default, type = \"boolean\"})\n    end\n    if package:extraconf(\"configs\", \"shared\", \"default\") == nil then\n        -- we always use static library if it's for wasm platform\n        local readonly\n        if package:is_plat(\"wasm\") then\n            readonly = true\n        end\n        local default = _get_default_config_value_of(\"shared\")\n        package:add(\"configs\", \"shared\", {builtin = true, description = \"Build shared library.\", default = default, readonly = readonly, type = \"boolean\"})\n    end\n    if package:extraconf(\"configs\", \"pic\", \"default\") == nil then\n        local default = _get_default_config_value_of(\"pic\")\n        package:add(\"configs\", \"pic\", {builtin = true, description = \"Enable the position independent code.\", default = default, type = \"boolean\"})\n    end\n    if package:extraconf(\"configs\", \"lto\", \"default\") == nil then\n        package:add(\"configs\", \"lto\", {builtin = true, description = \"Enable the link-time build optimization.\", type = \"boolean\"})\n    end\n    if package:extraconf(\"configs\", \"asan\", \"default\") == nil then\n        package:add(\"configs\", \"asan\", {builtin = true, description = \"Enable the address sanitizer.\", type = \"boolean\"})\n    end\n    if package:extraconf(\"configs\", \"runtimes\", \"default\") == nil then\n        local values = {\"MT\", \"MTd\", \"MD\", \"MDd\",\n                        \"c++_static\", \"c++_shared\", \"stdc++_static\", \"stdc++_shared\"}\n        package:add(\"configs\", \"runtimes\", {builtin = true, description = \"Set the compiler runtimes.\", type = \"string\", values = values, restrict = function (value)\n            local values_set = hashset.from(values)\n            if type(value) ~= \"string\" then\n                return false\n            end\n            if value then\n                for _, item in ipairs(value:split(\",\", {plain = true})) do\n                    if not values_set:has(item) then\n                        return false\n                    end\n                end\n            end\n            return true\n        end})\n    end\n    -- deprecated, please use runtimes\n    if package:extraconf(\"configs\", \"vs_runtime\", \"default\") == nil then\n        package:add(\"configs\", \"vs_runtime\", {builtin = true, description = \"Set vs compiler runtime.\", values = {\"MT\", \"MTd\", \"MD\", \"MDd\"}})\n    end\n    if package:extraconf(\"configs\", \"toolchains\", \"default\") == nil then\n        package:add(\"configs\", \"toolchains\", {builtin = true, description = \"Set package toolchains only for cross-compilation.\"})\n    end\n    package:add(\"configs\", \"cflags\", {builtin = true, description = \"Set the C compiler flags.\"})\n    package:add(\"configs\", \"cxflags\", {builtin = true, description = \"Set the C/C++ compiler flags.\"})\n    package:add(\"configs\", \"cxxflags\", {builtin = true, description = \"Set the C++ compiler flags.\"})\n    package:add(\"configs\", \"asflags\", {builtin = true, description = \"Set the assembler flags.\"})\n    package:add(\"configs\", \"ldflags\", {builtin = true, description = \"Set the binary linker flags.\"})\n    package:add(\"configs\", \"shflags\", {builtin = true, description = \"Set the shared library linker flags.\"})\nend\n\n-- select version from scheme\nfunction _select_version_from_scheme(scheme, requireinfo)\n\n    -- check urls\n    local urls = scheme:urls()\n    local has_giturl = false\n    for _, url in ipairs(urls) do\n        if git.checkurl(url) then\n            has_giturl = true\n            break\n        end\n    end\n\n    -- select package version\n    local source = nil\n    local version = nil\n    local require_version = requireinfo.version\n    local require_verify  = requireinfo.verify\n    local is_system = requireinfo.system\n    local has_versionlist = scheme:get(\"versions\") or scheme:get(\"versionfiles\")\n    -- We need to strictly limit the number of valid URLs to filter out schemes that don't have any URLs, prioritizing them.\n    if #urls > 0 and (not has_versionlist or require_verify == false)\n        and (semver.is_valid(require_version) or semver.is_valid_range(require_version)) then\n        -- no version list in package() or need not verify sha256sum? try selecting this version directly\n        -- @see\n        -- https://github.com/xmake-io/xmake/issues/930\n        -- https://github.com/xmake-io/xmake/issues/1009\n        -- https://github.com/xmake-io/xmake/issues/3551\n        version = require_version\n        source = \"version\"\n    elseif #scheme:versions() > 0 then -- select version?\n        version, source = try { function () return semver.select(require_version, scheme:versions()) end }\n    end\n    if not version and has_giturl then -- select branch?\n        if require_version and #require_version == 40 and require_version:match(\"%w+\") then\n            version, source = require_version, \"commit\"\n        else\n            version, source = require_version ~= \"latest\" and require_version or \"@default\", \"branch\"\n        end\n    end\n    -- local source package? we use a phony version\n    if not version and require_version == \"latest\" and #urls == 0 then\n        version = \"latest\"\n        source = \"version\"\n    end\n    return version, source\nend\n\n-- select package version\nfunction _select_package_version(package, requireinfo, locked_requireinfo)\n\n    -- get it from the locked requireinfo\n    if locked_requireinfo then\n        local version = locked_requireinfo.version\n        local source = \"version\"\n        if locked_requireinfo.branch then\n            source = \"branch\"\n        elseif locked_requireinfo.tag then\n            source = \"tag\"\n        end\n        package:version_set(version, source)\n        return version, source\n    end\n\n    -- select version from schemes\n    local version, source\n    local version_latest, source_latest\n    local scheme_version_map = {}\n    for _, scheme in ipairs(package:schemes_orderlist()) do\n        local scheme_version, scheme_source = _select_version_from_scheme(scheme, requireinfo)\n        if scheme_version then\n            scheme_version_map[scheme] = scheme_version\n            scheme:version_set(scheme_version, scheme_source)\n            if not version and scheme_version ~= \"latest\" then\n                version = scheme_version\n                source = scheme_source\n            end\n            if not version_latest and scheme_version == \"latest\" then\n                version_latest = scheme_version\n                source_latest = scheme_source\n            end\n        end\n    end\n    if not version then\n        -- If no version is available for any scheme and no URLs are available, we will use the specified version by default.\n        -- https://github.com/xmake-io/xmake/issues/7265\n        local require_version = requireinfo.version\n        local require_verify  = requireinfo.verify\n        local current_scheme = package:current_scheme()\n        local has_versionlist = current_scheme:get(\"versions\") or current_scheme:get(\"versionfiles\")\n        if (not has_versionlist or require_verify == false)\n            and (semver.is_valid(require_version) or semver.is_valid_range(require_version)) then\n            local scheme_version = require_version\n            local scheme_source = \"version\"\n            scheme_version_map[current_scheme] = scheme_version\n            current_scheme:version_set(scheme_version, scheme_source)\n            version = scheme_version\n            source = scheme_source\n        end\n    end\n    if not version then\n        version = version_latest\n        source = source_latest\n    end\n\n    -- remove these invalid schemes if version is not matched\n    table.remove_if(package:schemes_orderlist(), function (_, scheme)\n        local scheme_version = scheme_version_map[scheme]\n        if not scheme_version or (version and scheme_version ~= version) then\n            package:schemes()[scheme:name()] = nil\n            -- reset current scheme cache, we need to resolve new current scheme\n            package:current_scheme_set(nil)\n            return true\n        end\n    end)\n    assert(#package:schemes_orderlist() > 0, \"package(%s): no available schemes with urls and versions\", package:name())\n\n    local is_system = requireinfo.system\n    if not version and not package:is_thirdparty() and is_system ~= true then\n        local require_version = requireinfo.version\n        raise(\"package(%s): version(%s) not found!\", package:name(), require_version)\n    end\n    return version, source\nend\n\n-- check the configurations of packages\n--\n-- package(\"pcre2\")\n--      add_configs(\"bitwidth\", {description = \"Set the code unit width.\", default = \"8\", values = {\"8\", \"16\", \"32\"}})\n--      add_configs(\"bitwidth\", {type = \"number\", values = {8, 16, 32}})\n--      add_configs(\"bitwidth\", {restrict = function(value) if tonumber(value) < 100 then return true end})\n--\nfunction _check_package_configurations(package)\n    local configs_defined = {}\n    for _, name in ipairs(package:get(\"configs\")) do\n        configs_defined[name] = package:extraconf(\"configs\", name) or {}\n    end\n    for name, value in pairs(package:configs()) do\n        local conf = configs_defined[name]\n        if conf then\n            local config_type = conf.type\n            if config_type ~= nil and type(value) ~= config_type then\n                raise(\"package(%s %s): invalid type(%s) for config(%s), need type(%s)!\", package:displayname(), package:version_str(), type(value), name, config_type)\n            end\n            if conf.restrict then\n                if not conf.restrict(value) then\n                    raise(\"package(%s %s): invalid value(%s) for config(%s)!\", package:displayname(), package:version_str(), string.serialize(value, {indent = false}), name)\n                end\n            elseif conf.values then\n                local found = false\n                for _, config_value in ipairs(conf.values) do\n                    if tostring(value) == tostring(config_value) then\n                        found = true\n                        break\n                    end\n                end\n                if not found then\n                    raise(\"package(%s %s): invalid value(%s) for config(%s), please run `xmake require --info %s` to get all valid values!\", package:displayname(), package:version_str(), value, name, package:name())\n                end\n            end\n        else\n            raise(\"package(%s %s): invalid config(%s), please run `xmake require --info %s` to get all configurations!\", package:displayname(), package:version_str(), name, package:name())\n        end\n    end\nend\n\n-- check package toolchains\nfunction _check_package_toolchains(package)\n    if package:toolchains() then\n        for _, toolchain_inst in pairs(package:toolchains()) do\n            if not toolchain_inst:check() then\n                raise(\"toolchain(\\\"%s\\\"): not found!\", toolchain_inst:name())\n            end\n        end\n    else\n        -- maybe this package is host package, it's platform and toolchain has been not checked yet.\n        local platform_inst = platform.load(package:plat(), package:arch(), {host = package:is_host()})\n        if not platform_inst:check() then\n            raise(\"no any matched platform for this package(%s)!\", package:name())\n        end\n    end\nend\n\n-- match require path\nfunction _match_requirepath(requirepath, requireconf)\n\n    -- get pattern\n    local function _get_pattern(pattern)\n        pattern = pattern:gsub(\"([%+%.%-%^%$%(%)%%])\", \"%%%1\")\n        pattern = pattern:gsub(\"%*%*\", \"\\001\")\n        pattern = pattern:gsub(\"%*\", \"\\002\")\n        pattern = pattern:gsub(\"\\001\", \".*\")\n        pattern = pattern:gsub(\"\\002\", \"[^.]*\")\n        pattern = string.ipattern(pattern, true)\n        return pattern\n    end\n\n    -- get the excludes\n    local excludes = requireconf:match(\"|.*$\")\n    if excludes then excludes = excludes:split(\"|\", {plain = true}) end\n\n    -- do match\n    local pattern = requireconf:gsub(\"|.*$\", \"\")\n    pattern = _get_pattern(pattern)\n    if (requirepath:match('^' .. pattern .. '$')) then\n        -- exclude sub-deps, e.g. \"libwebp.**|cmake|autoconf\"\n        local splitinfo = requirepath:split(\".\", {plain = true})\n        if #splitinfo > 0 then\n            local name = splitinfo[#splitinfo]\n            for _, exclude in ipairs(excludes) do\n                pattern = _get_pattern(exclude)\n                if (name:match('^' .. pattern .. '$')) then\n                    return false\n                end\n            end\n        end\n        return true\n    end\nend\n\n-- init requireinfo\nfunction _init_requireinfo(requireinfo, package, opt)\n    -- pass root configs to top library package\n    requireinfo.configs = requireinfo.configs or {}\n    if opt.is_toplevel then\n        requireinfo.is_toplevel = true\n\n        -- we always pass some configurations from toplevel even it's headeronly, because it's library deps need inherit them\n        -- @see https://github.com/xmake-io/xmake/issues/2688\n        if package:is_library() then\n            requireinfo.configs.toolchains = requireinfo.configs.toolchains or project.get(\"target.toolchains\")\n            if project.policy(\"package.inherit_external_configs\") then\n                requireinfo.configs.toolchains = requireinfo.configs.toolchains or get_config(\"toolchain\")\n            end\n        end\n        requireinfo.configs.runtimes = requireinfo.configs.runtimes or project.get(\"target.runtimes\")\n        if project.policy(\"package.inherit_external_configs\") then\n            requireinfo.configs.runtimes = requireinfo.configs.runtimes or get_config(\"runtimes\") or get_config(\"vs_runtime\")\n        end\n        if type(requireinfo.configs.runtimes) == \"table\" then\n            requireinfo.configs.runtimes = table.concat(requireinfo.configs.runtimes, \",\")\n        end\n        if requireinfo.configs.lto == nil then\n            requireinfo.configs.lto = project.policy(\"build.optimization.lto\")\n        end\n        if requireinfo.configs.asan == nil then\n            requireinfo.configs.asan = project.policy(\"build.sanitizer.address\")\n        end\n    end\n    -- but we will ignore some configs for buildhash in the headeronly, moduleonly and host/binary package\n    -- @note on_test still need these configs, @see https://github.com/xmake-io/xmake/issues/4124\n    if package:is_headeronly() or package:is_moduleonly() or (package:is_binary() and not package:is_cross()) then\n        requireinfo.ignored_configs_for_buildhash = {\"runtimes\", \"toolchains\", \"lto\", \"asan\", \"pic\"}\n    end\nend\n\n-- finish requireinfo\nfunction _finish_requireinfo(requireinfo, package)\n    requireinfo.configs = requireinfo.configs or {}\n    if package:is_plat(\"windows\") then\n        -- @see https://github.com/xmake-io/xmake/issues/4477#issuecomment-1913249489\n        -- @note its buildhash will be ignored for headeronly\n        local runtimes = requireinfo.configs.runtimes\n        if runtimes then\n            runtimes = runtimes:split(\",\")\n        else\n            runtimes = {}\n        end\n        -- we should not set default runtimes if runtimes has been set, e.g. `xmake f --toolchain=clang --runtimes=c++_shared`\n        if #runtimes == 0 then\n            local vs_runtime_default = project.policy(\"build.c++.msvc.runtime\")\n            if vs_runtime_default and is_mode(\"debug\") then\n                vs_runtime_default = vs_runtime_default .. \"d\"\n            end\n            table.insert(runtimes, vs_runtime_default or \"MT\")\n        end\n        requireinfo.configs.runtimes = table.concat(runtimes, \",\")\n    end\n    -- we need to ensure readonly configs\n    for _, name in ipairs(table.keys(requireinfo.configs)) do\n        local current = requireinfo.configs[name]\n        local default = package:extraconf(\"configs\", name, \"default\")\n        local readonly = package:extraconf(\"configs\", name, \"readonly\")\n        if name == \"runtimes\" then\n            -- vs_runtime is deprecated, but we need also support it now.\n            if default == nil then\n                default = package:extraconf(\"configs\", \"vs_runtime\", \"default\")\n            end\n            if readonly == nil then\n                readonly = package:extraconf(\"configs\", \"vs_runtime\", \"readonly\")\n            end\n            if default ~= nil or readonly ~= nil then\n                wprint(\"please use add_configs(\\\"runtimes\\\") instead of add_configs(\\\"vs_runtime\\\").\")\n            end\n        end\n        if readonly and current ~= default then\n            wprint(\"configs.%s is readonly in package(%s), it's always %s\", name, package:name(), default)\n            -- package:config() will use default value after loading package\n            requireinfo.configs[name] = nil\n        end\n    end\n    -- sync default value to prevent cache mismatch (buildhash)\n    -- @see https://github.com/xmake-io/xmake/pull/4324\n    for k, v in pairs(requireinfo.configs) do\n        local default = _get_default_config_value_of(k)\n        if v == default then\n            requireinfo.configs[k] = nil\n        end\n    end\n\n    -- all binary packages are host package\n    -- we need to synchronize the setup to requireinfo so that all its dependent packages inherit from it.\n    if package:is_binary() then\n        requireinfo.host = true\n    end\nend\n\n-- merge requireinfo from `add_requireconfs()`\n--\n-- add_requireconfs(\"*\",                         {system = false, configs = {runtimes = \"MD\"}})\n-- add_requireconfs(\"lib*\",                      {system = false, configs = {runtimes = \"MD\"}})\n-- add_requireconfs(\"libwebp\",                   {system = false, configs = {runtimes = \"MD\"}})\n-- add_requireconfs(\"libpng.zlib\",               {system = false, override = true, configs = {cxflags = \"-DTEST1\"}, version = \"1.2.10\"})\n-- add_requireconfs(\"libtiff.*\",                 {system = false, configs = {cxflags = \"-DTEST2\"}})\n-- add_requireconfs(\"libwebp.**|cmake|autoconf\", {system = false, configs = {cxflags = \"-DTEST3\"}}) -- recursive deps\n--\nfunction _merge_requireinfo(requireinfo, requirepath)\n\n    -- only for project\n    if not os.isfile(os.projectfile()) then\n        return\n    end\n\n    -- find requireconf from the given requirepath\n    local requireconf_result = {}\n    local requireconfs, requireconfs_extra = project.requireconfs_str()\n    if requireconfs then\n        for _, requireconf in ipairs(requireconfs) do\n            if _match_requirepath(requirepath, requireconf) then\n                local requireconf_extra = requireconfs_extra[requireconf]\n                table.insert(requireconf_result, {requireconf = requireconf, requireconf_extra = requireconf_extra})\n            end\n        end\n    end\n\n    -- Append requireconf_extra into requireinfo\n    -- and the configs of add_requires have a higher priority than add_requireconfs.\n    --\n    -- e.g.\n    -- add_requireconfs(\"*\", {configs = {debug = false}})\n    -- add_requires(\"foo\", \"bar\", {configs = {debug = true}})\n    --\n    -- foo and bar will be debug mode\n    --\n    -- We can also override the configs of add_requires\n    --\n    -- e.g.\n    -- add_requires(\"zlib 1.2.11\")\n    -- add_requireconfs(\"zlib\", {override = true, version = \"1.2.10\"})\n    --\n    -- We override the version of zlib to 1.2.10\n    --\n    -- If the same dependency is matched to multiple configurations,\n    -- the configurations are merged by default,\n    -- and if override is set, then it rewrites the previous configurations.\n    --\n    for _, item in ipairs(requireconf_result) do\n        local requireconf_extra = item.requireconf_extra\n        if requireconf_extra then\n            -- preprocess requireconf_extra, (debug, override ..)\n            local override = requireconf_extra.override\n            if requireconf_extra.debug then\n                requireconf_extra.configs = requireconf_extra.configs or {}\n                requireconf_extra.configs.debug = true\n                requireconf_extra.debug = nil\n            end\n            -- append or override configs and extra options\n            for k, v in pairs(requireconf_extra.configs) do\n                requireinfo.configs = requireinfo.configs or {}\n                if override or requireinfo.configs[k] == nil then\n                    requireinfo.configs[k] = v\n                end\n            end\n            for k, v in pairs(requireconf_extra) do\n                if k ~= \"configs\" then\n                    if override or requireinfo[k] == nil then\n                        requireinfo[k] = v\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- get package key\nfunction _get_packagekey(packagename, requireinfo, version)\n    return _get_requirekey(requireinfo, {name = packagename,\n                                         host = requireinfo.host,\n                                         plat = requireinfo.plat,\n                                         arch = requireinfo.arch,\n                                         kind = requireinfo.kind,\n                                         version = version or requireinfo.version})\nend\n\n-- get locked package key\nfunction _get_packagelock_key(requireinfo)\n    local requirestr  = requireinfo.originstr\n    local key         = _get_requirekey(requireinfo, {hash = true})\n    return string.format(\"%s#%s\", requirestr, key)\nend\n\n-- inherit some builtin configs of parent package if these config values are not default value\n-- e.g. add_requires(\"libpng\", {configs = {runtimes = \"MD\", pic = false}})\n--\nfunction _inherit_parent_configs(requireinfo, package, parentinfo)\n    if package:is_library() then\n        local requireinfo_configs = requireinfo.configs or {}\n        local parentinfo_configs  = parentinfo.configs or {}\n        if not requireinfo_configs.shared then\n            if requireinfo_configs.runtimes == nil then\n                requireinfo_configs.runtimes = parentinfo_configs.runtimes\n            end\n            if requireinfo_configs.pic == nil then\n                requireinfo_configs.pic = parentinfo_configs.pic\n            end\n        end\n        if parentinfo.plat then\n            requireinfo.plat = parentinfo.plat\n        end\n        if parentinfo.arch then\n            requireinfo.arch = parentinfo.arch\n        end\n        if parentinfo.host then\n            requireinfo.host = parentinfo.host\n        end\n        requireinfo_configs.toolchains = requireinfo_configs.toolchains or parentinfo_configs.toolchains\n        requireinfo_configs.runtimes = requireinfo_configs.runtimes or parentinfo_configs.runtimes\n        requireinfo_configs.lto = requireinfo_configs.lto or parentinfo_configs.lto\n        requireinfo_configs.asan = requireinfo_configs.asan or parentinfo_configs.asan\n        requireinfo.configs = requireinfo_configs\n    end\nend\n\n-- select artifacts for msvc\nfunction _select_artifacts_for_msvc(package, artifacts_manifest)\n    local msvc\n    for _, instance in ipairs(package:toolchains()) do\n        if instance:name() == \"msvc\" then\n            msvc = instance\n            break\n        end\n    end\n    if not msvc then\n        msvc = toolchain.load(\"msvc\", {plat = package:plat(), arch = package:arch()})\n    end\n    local vcvars = msvc:config(\"vcvars\")\n    if vcvars then\n        local vs_toolset = vcvars.VCToolsVersion\n        if vs_toolset and semver.is_valid(vs_toolset) then\n            local artifacts_infos = {}\n            for key, artifacts_info in pairs(artifacts_manifest) do\n                if key:startswith(package:plat() .. \"-\" .. package:arch() .. \"-vc\") and key:endswith(\"-\" .. package:buildhash()) then\n                    table.insert(artifacts_infos, artifacts_info)\n                end\n            end\n            -- we sort them to select a newest toolset to get better optimzed performance\n            table.sort(artifacts_infos, function (a, b)\n                if a.toolset and b.toolset then\n                    return semver.compare(a.toolset, b.toolset) > 0\n                else\n                    return false\n                end\n            end)\n            if package:config(\"shared\") or package:is_binary() then\n                -- executable programs and dynamic libraries only need to select the latest toolset\n                return artifacts_infos[1]\n            else\n                -- static libraries need to consider toolset compatibility\n                for _, artifacts_info in ipairs(artifacts_infos) do\n                    -- toolset is backwards compatible\n                    --\n                    -- @see https://github.com/xmake-io/xmake/issues/1513\n                    -- https://docs.microsoft.com/en-us/cpp/porting/binary-compat-2015-2017?view=msvc-160\n                    if artifacts_info.toolset and semver.compare(vs_toolset, artifacts_info.toolset) >= 0 then\n                        return artifacts_info\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- select artifacts for generic\nfunction _select_artifacts_for_generic(package, artifacts_manifest)\n    local buildid = package:plat() .. \"-\" .. package:arch() .. \"-\" .. package:buildhash()\n    return artifacts_manifest[buildid]\nend\n\n-- select to use precompiled artifacts?\nfunction _select_artifacts(package, artifacts_manifest)\n    -- the precompile policy is disabled in package?\n    if package:policy(\"package.precompiled\") == false then\n        return\n    end\n    -- the precompile policy is disabled in project?\n    if os.isfile(os.projectfile()) and project.policy(\"package.precompiled\") == false then\n        return\n    end\n    local artifacts_info\n    if package:is_plat(\"windows\") then -- for msvc\n        artifacts_info = _select_artifacts_for_msvc(package, artifacts_manifest)\n    else\n        artifacts_info = _select_artifacts_for_generic(package, artifacts_manifest)\n    end\n    if artifacts_info then\n        package:use_precompiled_artifacts(artifacts_info)\n    end\nend\n\n-- select package runtimes\nfunction _select_package_runtimes(package)\n    local runtimes = package:config(\"runtimes\")\n    if runtimes then\n        local runtimes_supported = hashset.new()\n        local toolchains = package:toolchains() or\n            platform.load(package:plat(), package:arch(), {host = package:is_host()}):toolchains()\n        if toolchains then\n            for _, toolchain_inst in ipairs(toolchains) do\n                if toolchain_inst:is_standalone() and toolchain_inst:get(\"runtimes\") then\n                    for _, runtime in ipairs(table.wrap(toolchain_inst:get(\"runtimes\"))) do\n                        runtimes_supported:insert(runtime)\n                    end\n                end\n            end\n        end\n        local runtimes_current = {}\n        for _, runtime in ipairs(table.wrap(runtimes:split(\",\", {plain = true}))) do\n            if runtimes_supported:has(runtime) then\n                table.insert(runtimes_current, runtime)\n            end\n        end\n        -- we need update runtimes for buildhash, configs ...\n        --\n        -- we use configs_overrided to override configs in configs and buildhash,\n        -- but we shouldn't modify requireinfo.configs directly as it affects the package cache key\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/4477#issuecomment-1913185727\n        local requireinfo = package:requireinfo()\n        if requireinfo then\n            requireinfo.configs_overrided = requireinfo.configs_overrided or {}\n            requireinfo.configs_overrided.runtimes = #runtimes_current > 0 and table.concat(runtimes_current, \",\") or nil\n            package:_invalidate_configs()\n        end\n    end\nend\n\n-- load required packages\nfunction _load_package(packagename, requireinfo, opt)\n\n    -- check circular dependency\n    opt = opt or {}\n    if opt.requirepath then\n        local splitinfo = opt.requirepath:split(\".\", {plain = true})\n        if #splitinfo > 3 and\n            splitinfo[1] == splitinfo[#splitinfo - 1] and\n            splitinfo[2] == splitinfo[#splitinfo] then\n            raise(\"circular dependency(%s) detected in package(%s)!\", opt.requirepath, splitinfo[1])\n        end\n    end\n\n    -- strip trailing ~tag, e.g. zlib~debug\n    local displayname\n    if packagename:find('~', 1, true) then\n        displayname = packagename\n        local splitinfo = packagename:split('~', {plain = true, limit = 2})\n        packagename = splitinfo[1]\n        requireinfo.alias = requireinfo.alias or displayname\n        requireinfo.label = splitinfo[2]\n    end\n\n    -- save requirekey\n    local requirekey = _get_packagelock_key(requireinfo)\n    requireinfo.requirekey = requirekey\n\n    -- get locked requireinfo\n    local locked_requireinfo = get_locked_requireinfo(requireinfo)\n\n    -- load package from project first\n    local package\n    if os.isfile(os.projectfile()) then\n        package = _load_package_from_project(packagename)\n        if package and package:namespace() then\n            packagename = package:namespace() .. \"::\" .. packagename\n            if displayname then\n                displayname = package:namespace() .. \"::\" .. displayname\n            end\n        end\n    end\n\n    -- load package from repositories\n    local from_repo = false\n    if not package then\n        package = _load_package_from_repository(packagename, {\n            plat = requireinfo.plat,\n            arch = requireinfo.arch,\n            name = requireinfo.reponame,\n            locked_repo = locked_requireinfo and locked_requireinfo.repo})\n        if package then\n            from_repo = true\n        end\n    end\n\n    -- load base package\n    if package and package:get(\"base\") then\n        _load_package_from_base(package, package:get(\"base\", {\n            name = requireinfo.reponame, locked_repo = locked_requireinfo and locked_requireinfo.repo}))\n    end\n\n    -- load package from system\n    local system = requireinfo.system\n    if system == nil then\n        system = opt.system\n    end\n    if not package and (system ~= false or packagename:find(\"::\", 1, true)) then\n        package = _load_package_from_system(packagename)\n    end\n\n    -- check unknown package\n    if not package then\n        cprint(\"${bright color.warning}note: ${clear}the following packages were not found in any repository (check if they are spelled correctly):\")\n        local tips\n        local possible_package = get_possible_package(packagename)\n        if possible_package then\n            local possible_name = possible_package.name\n            if possible_package.version then\n                possible_name = possible_name .. \" \" .. possible_package.version\n            end\n            tips = string.format(\", maybe ${bright}%s${clear} in %s\", possible_name, possible_package.reponame)\n        end\n        cprint(\"  -> %s%s\", packagename, tips or \"\")\n        raise(\"package(%s) not found!\", packagename)\n    end\n\n    -- init requireinfo\n    _init_requireinfo(requireinfo, package, {is_toplevel = not opt.parentinfo})\n\n    -- merge requireinfo from `add_requireconfs()`\n    _merge_requireinfo(requireinfo, opt.requirepath)\n\n    -- inherit some builtin configs of parent package, e.g. runtimes, pic\n    if opt.parentinfo then\n        _inherit_parent_configs(requireinfo, package, opt.parentinfo)\n    end\n\n    -- finish requireinfo\n    _finish_requireinfo(requireinfo, package)\n\n    -- save require info\n    package:requireinfo_set(requireinfo)\n\n    -- only load toolchain package and its deps\n    if opt.toolchain then\n        if package:is_toplevel() and not package:is_toolchain()then\n            return\n        end\n    end\n\n    -- init urls source\n    package:_init_source()\n\n    -- select package version\n    local version, source = _select_package_version(package, requireinfo, locked_requireinfo)\n    if version then\n        package:data_set(\"__locked_requireinfo\", locked_requireinfo)\n    end\n\n    -- get package key\n    local packagekey = _get_packagekey(packagename, requireinfo, version)\n\n    -- get package from cache first\n    local package_cached = _memcache():get2(\"packages\", packagekey)\n    if package_cached then\n        -- since toplevel is not part of packagekey, we need to ensure it's part of the cached package table too\n        if requireinfo.is_toplevel and not package_cached:is_toplevel() then\n            package_cached:requireinfo().is_toplevel = true\n        end\n        -- mark this cached package.requireinfo as override\n        -- @see https://github.com/xmake-io/xmake/issues/4078\n        if requireinfo.override then\n            package_cached:requireinfo().override = true\n        end\n        return package_cached\n    end\n\n    -- save display name\n    if not displayname then\n        local packageid = _memcache():get2(\"packageids\", packagename)\n        displayname = packagename\n        if packageid then\n            displayname = displayname .. \"#\" .. tostring(packageid)\n        end\n        _memcache():set2(\"packageids\", packagename, (packageid or 0) + 1)\n    end\n    package:displayname_set(displayname)\n\n    -- disable parallelize if the package cache directory conflicts\n    local cachedirs = _memcache():get2(\"cachedirs\", package:cachedir())\n    if cachedirs then\n        package:set(\"parallelize\", false)\n    end\n    _memcache():set2(\"cachedirs\", package:cachedir(), true)\n\n    -- add some builtin configurations to package\n    _add_package_configurations(package)\n\n    -- check package configurations\n    _check_package_configurations(package)\n\n    -- we need to check package toolchains before on_load and select runtimes,\n    -- because we will call compiler-specific apis in on_load/on_fetch/find_package ..\n    --\n    -- @see https://github.com/xmake-io/xmake/pull/5466\n    -- https://github.com/xmake-io/xmake/issues/4596#issuecomment-2014528801\n    _check_package_toolchains(package)\n\n    -- we need to select package runtimes before computing buildhash\n    -- @see https://github.com/xmake-io/xmake/pull/4630#issuecomment-1910216561\n    _select_package_runtimes(package)\n\n    -- pre-compute the package buildhash\n    package:_compute_buildhash()\n\n    -- save artifacts info, we need to add it at last before buildhash need depend on package configurations\n    -- it will switch to install precompiled binary package from xmake-mirror/build-artifacts\n    if from_repo and not option.get(\"build\") and not requireinfo.build and requireinfo.system ~= true then\n        local artifacts_manifest = repository.artifacts_manifest(packagename, version)\n        if artifacts_manifest then\n            _select_artifacts(package, artifacts_manifest)\n        end\n    end\n\n    -- we need to check package toolchains before on_load,\n    -- because we will call compiler-specific apis in on_load/on_fetch/find_package ..\n    --\n    -- @see https://github.com/xmake-io/xmake/pull/5466\n    -- https://github.com/xmake-io/xmake/issues/4596#issuecomment-2014528801\n    _check_package_toolchains(package)\n\n    -- do load\n    package:_load()\n\n    -- check api\n    check_api(package, {load = true})\n\n    -- save this package package to cache\n    _memcache():set2(\"packages\", packagekey, package)\n\n    -- load ok\n    package:_mark_as_loaded()\n    return package\nend\n\n-- load all required packages\nfunction _load_packages(requires, opt)\n\n    -- no requires?\n    if not requires or #requires == 0 then\n        return {}\n    end\n\n    -- load packages\n    local packages = {}\n    local packages_nodeps = {}\n    for _, requireitem in ipairs(load_requires(requires, opt.requires_extra, opt)) do\n\n        -- load package\n        local requireinfo = requireitem.info\n        local requirepath = opt.requirepath and (opt.requirepath .. \".\" .. requireitem.name) or requireitem.name\n        local package = _load_package(requireitem.name, requireinfo, table.join(opt, {requirepath = requirepath}))\n\n        -- maybe package not found and optional\n        if package then\n\n            -- load dependent packages and save them first of this package\n            if not package._DEPS then\n                if package:get(\"deps\") and opt.nodeps ~= true then\n\n                    -- load dependent packages and do not load system/3rd packages for package/deps()\n                    local _, plaindeps = _load_packages(package:get(\"deps\"), {requirepath = requirepath,\n                                                        requires_extra = package:extraconf(\"deps\") or {},\n                                                        parentinfo = requireinfo,\n                                                        nodeps = opt.nodeps,\n                                                        resolvedinfo = opt.resolvedinfo,\n                                                        system = false})\n                    for _, dep in ipairs(plaindeps) do\n                        dep:parents_add(package)\n                    end\n                    package._PLAINDEPS = plaindeps\n                    package._ORDERDEPS = table.unique(_sort_packagedeps(package))\n                    package._LIBRARYDEPS = table.reverse_unique(_sort_librarydeps(package))\n                    package._LIBRARYDEPS_WITH_PRIVATE = table.reverse_unique(_sort_librarydeps(package, {private = true}))\n                    -- we always need load dependencies everytime\n                    -- @see https://github.com/xmake-io/xmake/issues/4522\n                    local packagedeps = {}\n                    for _, dep in ipairs(package._ORDERDEPS) do\n                        table.insert(packages, dep)\n                        packagedeps[dep:name()] = dep\n                    end\n                    package._DEPS = packagedeps\n                end\n            end\n\n            -- save this package\n            table.insert(packages, package)\n            table.insert(packages_nodeps, package)\n        end\n    end\n    return packages, packages_nodeps\nend\n\n-- get package parents string\nfunction _get_parents_str(package)\n    local parents = package:parents()\n    if parents then\n        local parentnames = {}\n        for _, parent in ipairs(parents) do\n            table.insert(parentnames, parent:displayname())\n        end\n        if #parentnames == 0 then\n            return\n        end\n        return table.concat(parentnames, \",\")\n    end\nend\n\n-- get require paths\nfunction _get_requirepaths(package)\n    local requirepaths = {}\n    local parents = package:parents()\n    if parents and #parents > 0 then\n        for _, parent in ipairs(parents) do\n            for _, requirepath in ipairs(_get_requirepaths(parent)) do\n                table.insert(requirepaths, requirepath .. \".\" .. package:name())\n            end\n        end\n        -- we also need to resolve requires conflict in toplevel, if `package.sync_requires_to_deps` policy is enabled.\n        -- @see https://github.com/xmake-io/xmake/issues/5745#issuecomment-2513951471\n        if project.policy(\"package.sync_requires_to_deps\") then\n            table.insert(requirepaths, package:name())\n        end\n    else\n        table.insert(requirepaths, package:name())\n    end\n    return requirepaths\nend\n\n-- get compatibility key\nfunction _get_package_compatkey(dep)\n    local key = dep:plat() .. \"/\" .. dep:arch() .. \"/\" .. (dep:kind() or \"\")\n    if dep:is_system() then\n        key = key .. \"/system\"\n    end\n    local resolve_depconflict = project.policy(\"package.resolve_depconflict\")\n    if resolve_depconflict == nil then\n        resolve_depconflict = dep:policy(\"package.resolve_depconflict\")\n    end\n    if resolve_depconflict == false then\n        if dep:version_str() then\n            key = key .. \"/\" .. dep:version_str()\n        end\n        local configs = dep:requireinfo().configs\n        if configs then\n            local configs_order = {}\n            for k, v in pairs(configs) do\n                if type(v) == \"table\" then\n                    v = string.serialize(v, {strip = true, indent = false, orderkeys = true})\n                end\n                table.insert(configs_order, k .. \"=\" .. tostring(v))\n            end\n            table.sort(configs_order)\n            key = key .. \":\" .. string.serialize(configs_order, true)\n        end\n    end\n    return key\nend\n\n-- get package compatibility info\nfunction _get_package_compatinfo(package)\n    local compatinfo = {name = package:name()}\n    if package:data(\"__locked_requireinfo\") then\n        compatinfo.locked = true\n        compatinfo.versions = hashset.from(table.wrap(package:version_str()))\n        return compatinfo\n    end\n\n    -- get compatible version range\n    local requireinfo = package:requireinfo()\n    local require_version = requireinfo.version\n    if require_version then\n        compatinfo.require_version = require_version\n        if semver.is_valid(require_version) or semver.is_valid_range(require_version) then\n            local versions = hashset.new()\n            for _, version in ipairs(package:versions()) do\n                if semver.satisfies(version, require_version) then\n                    versions:insert(version)\n                end\n            end\n            compatinfo.versions = versions\n        elseif require_version == \"latest\" then\n            compatinfo.versions = hashset.from(table.wrap(package:versions()))\n        else\n            compatinfo.versions = hashset.from(table.wrap(require_version))\n        end\n    else\n        compatinfo.versions = hashset.from(table.wrap(package:versions()))\n    end\n    return compatinfo\nend\n\n-- check and resolve package conflicts\nfunction _check_and_resolve_package_depconflicts_impl(package, name, deps, resolvedinfo)\n\n    -- check version compatibility\n    local versions\n    for _, dep in ipairs(deps) do\n        local compatinfo = _get_package_compatinfo(dep)\n        assert(compatinfo.versions)\n\n        if versions then\n            for version in versions:items() do\n                if not compatinfo.versions:has(version) then\n                    versions:remove(version)\n                end\n            end\n        else\n            versions = compatinfo.versions\n        end\n    end\n\n    if not versions or versions:empty() then\n        print(\"package(%s): add_deps(%s, ...)\", package:name(), name)\n        for idx, dep in ipairs(deps) do\n            cprint(\"  ${color.warning}->${clear} %s %s ${dim}%s\",\n                dep:displayname(), dep:version_str() or \"\", get_configs_str(dep))\n        end\n        print(\"we can use add_requireconfs(\\\"**.%s\\\", {override = true, version = \\\"x.x.x\\\"}) to override version.\", name)\n        raise(\"package(%s): conflict version dependencies!\", name)\n    end\n\n    -- check configs compatibility\n    local prevkey\n    local configs\n    local configs_conflict = false\n    for _, dep in ipairs(deps) do\n        local key = _get_package_compatkey(dep)\n        if prevkey then\n            if prevkey ~= key then\n                configs_conflict = true\n                break\n            end\n        else\n            prevkey = key\n        end\n        local depconfigs = dep:requireinfo().configs\n        if configs and depconfigs then\n            for k, v in pairs(depconfigs) do\n                local oldv = configs[k]\n                if oldv ~= nil then\n                    local v_key = tostring(v)\n                    local oldv_key = tostring(oldv)\n                    if type(v) == \"table\" then\n                        v_key = string.serialize(v, {strip = true, indent = false, orderkeys = true})\n                    end\n                    if type(oldv) == \"table\" then\n                        oldv_key = string.serialize(oldv, {strip = true, indent = false, orderkeys = true})\n                    end\n                    if v_key ~= oldv_key then\n                        configs_conflict = true\n                        break\n                    end\n                else\n                    configs[k] = v\n                end\n            end\n        else\n            configs = depconfigs\n        end\n    end\n    if configs_conflict then\n        print(\"package(%s): add_deps(%s, ...)\", package:name(), name)\n        for idx, dep in ipairs(deps) do\n            cprint(\"  ${color.warning}->${clear} %s %s ${dim}%s\",\n                dep:displayname(), dep:version_str() or \"\", get_configs_str(dep))\n        end\n        print(\"we can use add_requireconfs(\\\"**.%s\\\", {override = true, configs = {}}) to override configs.\", name)\n        raise(\"package(%s): conflict configs dependencies!\", name)\n    end\n\n    -- resolve compatible version for all deps\n    if versions and not versions:empty() then\n        local version_best\n        for version in versions:items() do\n            if version_best == nil or semver.compare(version, version_best) > 0 then\n                version_best = version\n            end\n        end\n        if version_best then\n            for _, dep in ipairs(deps) do\n                for _, requirepath in ipairs(_get_requirepaths(dep)) do\n                    resolvedinfo[requirepath] = {version = version_best}\n                end\n            end\n        end\n    end\n\n    -- resolve configs\n    if configs then\n        for _, dep in ipairs(deps) do\n            for _, requirepath in ipairs(_get_requirepaths(dep)) do\n                resolvedinfo[requirepath] = resolvedinfo[requirepath] or {}\n                resolvedinfo[requirepath].configs = configs\n            end\n        end\n    end\nend\n\n-- check and resolve dependencies conflicts\n--\n-- It exists conflict for dependent packages for each root packages? resolve it first\n-- e.g.\n-- add_requires(\"foo\") -> bar -> zlib 1.2.10\n--                     -> xyz -> zlib 1.2.11 or other configs\n--\n-- add_requires(\"ddd\") -> zlib\n--\n-- We assume that there is no conflict between `foo` and `ddd`.\n--\n-- Of course, conflicts caused by `add_packages(\"foo\", \"ddd\")`\n-- cannot be detected at present and can only be resolved by the user\n--\nfunction _check_and_resolve_package_depconflicts(package, resolvedinfo)\n    local some_packagedeps = {}\n    for _, dep in ipairs(package:librarydeps()) do\n        local deps = some_packagedeps[dep:name()]\n        if deps == nil then\n            deps = {}\n            some_packagedeps[dep:name()] = deps\n        end\n        table.insert(deps, dep)\n    end\n    for name, deps in pairs(some_packagedeps) do\n        if #deps > 1 then\n            _check_and_resolve_package_depconflicts_impl(package, name, deps, resolvedinfo)\n        end\n    end\nend\n\n-- must depend on the given package?\nfunction _must_depend_on(package, dep)\n    local manifest = package:manifest_load()\n    if manifest and manifest.librarydeps then\n        local librarydeps = hashset.from(manifest.librarydeps)\n        return librarydeps:has(dep:name())\n    end\n    -- If we mark it as public, even if binary package is already installed,\n    -- we need also to install it's public dep and export the it's envs.\n    --\n    -- @see https://github.com/xmake-io/xmake-repo/pull/6207\n    -- https://github.com/xmake-io/xmake/pull/6101\n    if package:is_binary() and package:extraconf(\"deps\", dep:name(), \"public\") then\n        return true\n    end\nend\n\n-- compatible with all previous link dependencies?\n-- @see https://github.com/xmake-io/xmake/issues/2719\nfunction _compatible_with_previous_librarydeps(package, opt)\n\n    -- skip to check compatibility if installation has been finished\n    opt = opt or {}\n    if opt.install_finished then\n        return true\n    end\n\n    -- check strict compatibility for librarydeps?\n    local strict_compatibility = project.policy(\"package.librarydeps.strict_compatibility\")\n    if strict_compatibility == nil then\n        strict_compatibility = package:policy(\"package.librarydeps.strict_compatibility\")\n    end\n    -- and we can disable it manually, @see https://github.com/xmake-io/xmake/pull/3738\n    if strict_compatibility == false then\n       return true\n    end\n\n    -- compute the buildhash for current librarydeps\n    local depnames = hashset.new()\n    local depinfos_curr = {}\n    for _, dep in ipairs(package:librarydeps()) do\n        if strict_compatibility or dep:policy(\"package.strict_compatibility\") then\n            depinfos_curr[dep:name()] = {\n                version = dep:version_str(),\n                buildhash = dep:buildhash()\n            }\n            depnames:insert(dep:name())\n        end\n    end\n\n    -- compute the buildhash for previous librarydeps\n    local depinfos_prev = {}\n    local manifest = package:manifest_load()\n    if manifest and manifest.librarydeps then\n        local deps = manifest.deps or {}\n        for _, depname in ipairs(manifest.librarydeps) do\n            if strict_compatibility or (package:dep(depname) and package:dep(depname):policy(\"package.strict_compatibility\")) or depinfos_curr[depname] then\n                local depinfo = deps[depname]\n                if depinfo and depinfo.buildhash then\n                    depinfos_prev[depname] = depinfo\n                    depnames:insert(depname)\n                end\n            end\n        end\n    end\n\n    -- no any dependencies\n    if depnames:empty() then\n        return true\n    end\n\n    -- is compatible?\n    local is_compatible = true\n    local compatible_tips = {}\n    for _, depname in depnames:keys() do\n        local depinfo_prev = depinfos_prev[depname]\n        local depinfo_curr = depinfos_curr[depname]\n        if depinfo_prev and depinfo_curr then\n            if depinfo_prev.buildhash ~= depinfo_curr.buildhash then\n                is_compatible = false\n                table.insert(compatible_tips, (\"*%s\"):format(depname))\n            end\n        elseif depinfo_prev then\n            is_compatible = false\n            table.insert(compatible_tips, (\"-%s\"):format(depname))\n        elseif depinfo_curr then\n            is_compatible = false\n            table.insert(compatible_tips, (\"+%s\"):format(depname))\n        end\n    end\n    if not is_compatible and #compatible_tips > 0 then\n        package:data_set(\"librarydeps.compatible_tips\", compatible_tips)\n    end\n    if not is_compatible then\n        package:data_set(\"force_reinstall\", true)\n    end\n    return is_compatible\nend\n\n-- get possible package\nfunction get_possible_package(packagename)\n    local packages_possible = search_packages(\"*\", {description = false})\n    if packages_possible then\n        packages_possible = packages_possible[\"*\"]\n    end\n    local result\n    local distance_min\n    for name, info in pairs(packages_possible) do\n        local distance = packagename:levenshtein(info.name)\n        if (distance_min == nil or distance < distance_min) and distance < 5 then\n            distance_min = distance\n            result = info\n        end\n    end\n    return result\nend\n\n-- the cache directory\nfunction cachedir()\n    return path.join(global.directory(), \"cache\", \"packages\")\nend\n\n-- this package should be install?\nfunction should_install(package, opt)\n    opt = opt or {}\n    if package:is_template() then\n        return false\n    end\n    if not opt.install_finished and package:policy(\"package.install_always\") then\n        return true\n    end\n    if package:exists() and _compatible_with_previous_librarydeps(package, opt) then\n        return false\n    end\n    -- we don't need to install it if this package only need to be fetched\n    if package:is_fetchonly() then\n        return false\n    end\n    -- only get system package? e.g. add_requires(\"xxx\", {system = true})\n    local requireinfo = package:requireinfo()\n    if requireinfo and requireinfo.system then\n        return false\n    end\n    if package:parents() then\n        -- if all the packages that depend on it already exist, then there is no need to install it\n        for _, parent in ipairs(package:parents()) do\n            if should_install(parent, opt) and not parent:exists() then\n                return true\n            end\n\n            -- if the existing parent package is already using it,\n            -- then even if it is an optional package, you must make sure to install it\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/1460\n            --\n            if parent:exists() and not option.get(\"force\") and _must_depend_on(parent, package) then\n                -- mark this package as non-optional because parent package need it\n                local requireinfo = package:requireinfo()\n                if requireinfo.optional then\n                    requireinfo.optional = nil\n                end\n                return true\n            end\n        end\n    else\n        return true\n    end\nend\n\n-- get package configs string\nfunction get_configs_str(package)\n    local configs = {}\n    if package:is_optional() then\n        table.insert(configs, \"optional\")\n    end\n    if package:is_private() then\n        table.insert(configs, \"private\")\n    end\n    if package:is_host() then\n        table.insert(configs, \"host\")\n    end\n    local requireinfo = package:requireinfo()\n    if requireinfo then\n        if requireinfo.plat then\n            table.insert(configs, requireinfo.plat)\n        end\n        if requireinfo.arch then\n            table.insert(configs, requireinfo.arch)\n        end\n        if requireinfo.kind then\n            table.insert(configs, requireinfo.kind)\n        end\n        local ignored_configs_for_buildhash = hashset.from(requireinfo.ignored_configs_for_buildhash or {})\n        local configs_overrided = requireinfo.configs_overrided or {}\n        for k, v in pairs(requireinfo.configs) do\n            if not ignored_configs_for_buildhash:has(k) then\n                v = configs_overrided[k] or v\n                if type(v) == \"boolean\" then\n                    table.insert(configs, k .. \":\" .. (v and \"y\" or \"n\"))\n                else\n                    table.insert(configs, k .. \":\" .. string.serialize(v, {strip = true, indent = false}))\n                end\n            end\n        end\n    end\n    local compatible_tips = package:data(\"librarydeps.compatible_tips\")\n    if compatible_tips then\n        table.insert(configs, \"deps:\" .. table.concat(compatible_tips, \",\"))\n    end\n    local parents_str = _get_parents_str(package)\n    if parents_str then\n        table.insert(configs, \"from:\" .. parents_str)\n    end\n    local license = package:get(\"license\")\n    if license then\n        table.insert(configs, \"license:\" .. license)\n    end\n    local configs_str = #configs > 0 and \"[\" .. table.concat(configs, \", \") .. \"]\" or \"\"\n    local limitwidth = math.floor(os.getwinsize().width * 2 / 3)\n    if #configs_str > limitwidth then\n        configs_str = configs_str:sub(1, limitwidth) .. \" ..)\"\n    end\n    local resolvedinfo = requireinfo.resolvedinfo\n    if resolvedinfo then\n        configs_str = configs_str .. \" \" .. \"${color.warning}(conflict resolved)${clear}\"\n    end\n    return configs_str\nend\n\n-- get locked requireinfo\nfunction get_locked_requireinfo(requireinfo, opt)\n    local requirekey = requireinfo.requirekey\n    local locked_requireinfo, requireslock_version\n    if _has_locked_requires(opt) and requirekey then\n        locked_requireinfo, requireslock_version = _get_locked_requires(requirekey, opt)\n        if requireslock_version and semver.compare(project.requireslock_version(), requireslock_version) < 0 then\n            locked_requireinfo = nil\n        end\n    end\n    return locked_requireinfo, requireslock_version\nend\n\n-- load requires\nfunction load_requires(requires, requires_extra, opt)\n    opt = opt or {}\n    local requireitems = {}\n    for _, require_str in ipairs(requires) do\n        local packagename, requireinfo = _load_require(require_str, requires_extra, opt)\n        table.insert(requireitems, {name = packagename, info = requireinfo})\n    end\n    return requireitems\nend\n\n-- load all required packages\nfunction load_packages(requires, opt)\n    opt = opt or {}\n    local unique = {}\n    local packages = {}\n    local resolvedinfo = {}\n    for _, package in ipairs((_load_packages(requires, table.clone(opt)))) do\n        if package:is_toplevel() then\n            _check_and_resolve_package_depconflicts(package, resolvedinfo)\n        end\n        local key = _get_packagekey(package:name(), package:requireinfo())\n        if not unique[key] then\n            table.insert(packages, package)\n            unique[key] = true\n        end\n    end\n\n    -- we need to reload packages with new resolved deps if there are some dep conflicts\n    if not table.empty(resolvedinfo) then\n        for _, package in ipairs(packages) do\n            local installdir = package:installdir({readonly = true})\n            if os.isdir(installdir) and os.emptydir(installdir) then\n                os.tryrm(installdir, {emptydirs = true})\n            end\n        end\n        unique = {}\n        packages = {}\n        _memcache():clear()\n        opt = table.join(opt, {resolvedinfo = resolvedinfo})\n        for _, package in ipairs((_load_packages(requires, opt))) do\n            local key = _get_packagekey(package:name(), package:requireinfo())\n            if not unique[key] then\n                table.insert(packages, package)\n                unique[key] = true\n            end\n        end\n    end\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/packagenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        packagenv.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.package.package\", {alias = \"core_package\"})\n\n-- enter the package environments\nfunction _enter_package(package_name, envs, pathenvs, installdir)\n    if pathenvs then\n        pathenvs = hashset.from(pathenvs)\n    end\n    for name, values in pairs(envs) do\n        if pathenvs and pathenvs:has(name) then\n            for _, value in ipairs(values) do\n                if path.is_absolute(value) then\n                    os.addenv(name, value)\n                else\n                    os.addenv(name, path.normalize(path.join(installdir, value)))\n                end\n            end\n        else\n            os.addenv(name, table.unpack(table.wrap(values)))\n        end\n    end\nend\n\n-- enter environment of the given binary packages, git, 7z, ..\nfunction enter(...)\n    local oldenvs = os.getenvs()\n    for _, name in ipairs({...}) do\n        for _, manifest_file in ipairs(os.files(path.join(core_package.installdir(), name:sub(1, 1), name, \"*\", \"*\", \"manifest.txt\"))) do\n            local manifest = io.load(manifest_file)\n            if manifest and manifest.plat == os.host() and manifest.arch == os.arch() then\n                _enter_package(name, manifest.envs, manifest.pathenvs, path.directory(manifest_file))\n            end\n        end\n    end\n    return oldenvs\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/register_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        register_packages.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.cache.localcache\")\n\n-- register required package environments\n-- envs: bin path for *.dll, program ..\nfunction _register_required_package_envs(instance, envs)\n    for name, values in table.orderpairs(instance:envs()) do\n        envs[name] = envs[name] or {}\n        table.join2(envs[name], values)\n    end\nend\n\n-- register required package libraries\n-- libs: includedirs, links, linkdirs ...\nfunction _register_required_package_libs(instance, required_package, is_deps)\n    if instance:is_library() then\n        local fetchinfo = table.clone(instance:fetch())\n        if fetchinfo then\n            fetchinfo.name = nil\n            if is_deps then\n                -- we only need reserve license for root package\n                --\n                -- @note the license compatibility between the root package and\n                -- its dependent packages is guaranteed by the root package itself\n                --\n                fetchinfo.license = nil\n\n                -- we only need some infos for root package\n                fetchinfo.version = nil\n                fetchinfo.static  = nil\n                fetchinfo.shared  = nil\n                fetchinfo.installdir = nil\n                fetchinfo.components = nil\n            end\n\n            -- merge into the root values\n            local components = fetchinfo.components\n            fetchinfo.components = nil\n            required_package:add(fetchinfo)\n\n            -- save components list and dependencies\n            if components then\n                required_package:set(\"__components_deps\", instance:components_deps())\n                required_package:set(\"__components_default\", instance:components_default())\n                required_package:set(\"__components_orderlist\", instance:components_orderlist())\n            end\n\n            -- save namespace\n            if instance:namespace() then\n                required_package:set(\"__namespace\", instance:namespace())\n            end\n\n            -- merge into the components values\n            local required_components = required_package:get(\"components\")\n            if required_components then\n                fetchinfo.libfiles = nil\n                local components_base = required_components.__base or {}\n                for k, v in table.orderpairs(fetchinfo) do\n                    local values = table.wrap(components_base[k])\n                    components_base[k] = table.unwrap(table.unique(table.join(values, v)))\n                end\n                required_components.__base = components_base\n            else\n                required_package:set(\"components\", components)\n            end\n        end\n    end\nend\n\n-- register the base info of required package\nfunction _register_required_package_base(instance, required_package)\n    if not instance:is_system() and not instance:is_thirdparty() then\n        required_package:set(\"installdir\", instance:installdir())\n    end\nend\n\n-- register the required local package\nfunction _register_required_package(instance, required_package)\n\n    -- disable it if this package is missing\n    if not instance:exists() then\n        required_package:enable(false)\n    else\n        -- clear require info first\n        required_package:clear()\n\n        -- add packages info with all dependencies\n        local envs = {}\n        _register_required_package_base(instance, required_package)\n        _register_required_package_libs(instance, required_package)\n        _register_required_package_envs(instance, envs)\n        for _, dep in ipairs(instance:librarydeps()) do\n            if instance:is_library() then\n                _register_required_package_libs(dep, required_package, true)\n            end\n        end\n        for _, dep in ipairs(instance:orderdeps()) do\n            if not dep:is_private() then\n                _register_required_package_envs(dep, envs)\n            end\n        end\n        if #table.keys(envs) > 0 then\n            required_package:add({envs = envs})\n        end\n\n        -- enable this require info\n        required_package:enable(true)\n    end\n\n    -- save this require info and flush the whole cache file\n    required_package:save()\nend\n\n-- register all required root packages to local cache\nfunction main(packages)\n\n    -- register to package cache for add_packages()\n    for _, instance in ipairs(packages) do\n        if instance:is_toplevel() then\n            local required_packagename = instance:alias() or instance:name()\n            local required_package = project.required_package(required_packagename)\n            if required_package then\n                _register_required_package(instance, required_package)\n            end\n        end\n    end\n\n    -- register references for `xrepo clean`\n    -- and we use glocal memory cache to save all packages from multiple arch/mode, e.g. `xmake project -m \"debug,release\" -k vsxmake`\n    -- @see https://github.com/xmake-io/xmake/issues/3679\n    local references = _g.references or {}\n    _g.references = references\n    for _, instance in ipairs(packages) do\n        if not instance:is_system() and not instance:is_thirdparty() then\n            local installdir = instance:installdir({readonly = true})\n            if os.isdir(installdir) then\n                table.insert(references, installdir)\n            end\n        end\n    end\n    localcache.set(\"references\", \"packages\", table.unique(references))\n    localcache.save(\"references\")\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/remove_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        remove_packages.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.package.package\")\nimport(\"core.cache.localcache\")\n\n-- get package configs string\nfunction _get_package_configs_str(manifest_file)\n    local manifest = os.isfile(manifest_file) and io.load(manifest_file)\n    if manifest then\n        local configs = {}\n        for k, v in pairs(manifest.configs) do\n            if type(v) == \"boolean\" then\n                table.insert(configs, k .. \":\" .. (v and \"y\" or \"n\"))\n            else\n                table.insert(configs, k .. \":\" .. string.serialize(v, {strip = true, indent = false}))\n            end\n        end\n        local configs_str = #configs > 0 and \"[\" .. table.concat(configs, \", \") .. \"]\" or \"\"\n        local limitwidth = math.floor(os.getwinsize().width * 2 / 3)\n        if #configs_str > limitwidth then\n            configs_str = configs_str:sub(1, limitwidth) .. \" ..)\"\n        end\n        return configs_str\n    end\nend\n\n-- has reference from project?\n-- @see https://github.com/xmake-io/xmake/issues/3679\nfunction _has_reference_from_project(projectdir, packagedir)\n    local project_references_file = path.join(projectdir, \".xmake\", os.host(), os.arch(), \"cache\", \"references\")\n    if os.isfile(project_references_file) then\n        local references = io.load(project_references_file)\n        if references and references.packages then\n            local packages = hashset.from(references.packages)\n            if packages:has(packagedir) then\n                return true\n            end\n        end\n    end\nend\n\n-- remove package directories\nfunction _remove_packagedirs(packagedir, opt)\n\n    -- clear them\n    local package_name = path.filename(packagedir)\n    for _, versiondir in ipairs(os.dirs(path.join(packagedir, \"*\"))) do\n        local version = path.filename(versiondir)\n        for _, hashdir in ipairs(os.dirs(path.join(versiondir, \"*\"))) do\n            local hash = path.filename(hashdir)\n            local references_file = path.join(hashdir, \"references.txt\")\n            local referenced = false\n            local references = os.isfile(references_file) and io.load(references_file) or nil\n            if references then\n                for projectdir, refdate in pairs(references) do\n                    if os.isdir(projectdir) and _has_reference_from_project(projectdir, hashdir) then\n                        referenced = true\n                        break\n                    end\n                end\n            end\n            local manifest_file = path.join(hashdir, \"manifest.txt\")\n            local status = nil\n            if os.emptydir(hashdir) then\n                status = \"empty\"\n            elseif not referenced then\n                status = \"unused\"\n            elseif not os.isfile(manifest_file) then\n                status = \"invalid\"\n            end\n            if not opt.clean or status then\n                local configs_str = _get_package_configs_str(manifest_file) or \"[]\"\n                local description = string.format(\"remove ${color.dump.string}%s-%s${clear}/${yellow}%s${clear}\\n  -> ${dim}%s${clear} (${red}%s${clear})\", package_name, version, hash, configs_str, status and status or \"used\")\n                local confirm = utils.confirm({default = true, description = description})\n                if confirm then\n                    os.rm(hashdir)\n                end\n            end\n        end\n        if os.emptydir(versiondir) then\n            os.rm(versiondir)\n        end\n    end\n    if os.emptydir(packagedir) then\n        os.rm(packagedir)\n    end\nend\n\n-- remove the given or all packages\n--\n-- @param package_names     the package names list, support lua pattern\n-- @param opt               the options, only clean unused packages if pass `{clean = true}`\n--\nfunction main(package_names, opt)\n    opt = opt or {}\n    local installdir = package.installdir()\n    if package_names then\n        for _, package_name in ipairs(package_names) do\n            for _, packagedir in ipairs(os.dirs(path.join(installdir, package_name:sub(1, 1), package_name))) do\n                _remove_packagedirs(packagedir, opt)\n            end\n        end\n    else\n        for _, packagedir in ipairs(os.dirs(path.join(installdir, \"*\", \"*\"))) do\n            _remove_packagedirs(packagedir, opt)\n        end\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/repository.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        repository.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.package.repository\")\nimport(\"devel.git\")\nimport(\"net.proxy\")\n\n-- get package directory from the locked repository\nfunction _get_packagedir_from_locked_repo(packagename, locked_repo)\n\n    -- find global repository directory\n    local repo_global\n    for _, repo in ipairs(repositories()) do\n        if locked_repo.url == repo:url() and locked_repo.branch == repo:branch() then\n            repo_global = repo\n            break\n        end\n    end\n    local reponame = hash.strhash128(locked_repo.url .. (locked_repo.commit or \"\")) .. \".lock\"\n\n    -- get local repodir\n    local repodir_local\n    if os.isdir(locked_repo.url) then\n        repodir_local = locked_repo.url\n    elseif not locked_repo.commit and repo_global then\n        repodir_local = repo_global:directory()\n    else\n        repodir_local = path.join(config.directory(), \"repositories\", reponame)\n    end\n\n    -- get the network mode?\n    local network = project.policy(\"network.mode\")\n    if network == nil then\n        network = global.get(\"network\")\n    end\n\n    -- clone repository to local\n    local lastcommit\n    if not os.isdir(repodir_local) then\n        if repo_global then\n            git.clone(repo_global:directory(), {treeless = true, checkout = false, verbose = option.get(\"verbose\"), outputdir = repodir_local, autocrlf = false})\n            lastcommit = repo_global:commit()\n        elseif network ~= \"private\" then\n            local remoteurl = proxy.mirror(locked_repo.url) or locked_repo.url\n            git.clone(remoteurl, {verbose = option.get(\"verbose\"), branch = locked_repo.branch, outputdir = repodir_local, autocrlf = false})\n        else\n            wprint(\"we cannot lock repository(%s) in private network mode!\", locked_repo.url)\n            return\n        end\n    end\n\n    -- lock commit\n    local ok\n    if locked_repo.commit and os.isdir(path.join(repodir_local, \".git\")) then\n        lastcommit = lastcommit or try {function()\n            return git.lastcommit({repodir = repodir_local})\n        end}\n        if locked_repo.commit ~= lastcommit then\n            -- try checkout to the given commit\n            ok = try {function () git.checkout(locked_repo.commit, {verbose = option.get(\"verbose\"), repodir = repodir_local}); return true end}\n            if not ok then\n                if network ~= \"private\" then\n                    -- pull the latest commit\n                    local remoteurl = proxy.mirror(locked_repo.url) or locked_repo.url\n                    git.reset({verbose = option.get(\"verbose\"), repodir = repodir_local, hard = true})\n                    git.pull({verbose = option.get(\"verbose\"), remote = remoteurl, branch = locked_repo.branch, repodir = repodir_local, force = true})\n                    -- re-checkout to the given commit\n                    ok = try {function () git.checkout(locked_repo.commit, {verbose = option.get(\"verbose\"), repodir = repodir_local}); return true end}\n                else\n                    wprint(\"we cannot lock repository(%s) in private network mode!\", locked_repo.url)\n                    return\n                end\n            end\n        else\n            ok = true\n        end\n    end\n\n    -- find package directory\n    local foundir\n    if ok then\n        local dir = path.join(repodir_local, \"packages\", packagename:sub(1, 1), packagename)\n        if os.isdir(dir) and os.isfile(path.join(dir, \"xmake.lua\")) then\n            local repo = repository.load(reponame, locked_repo.url, locked_repo.branch, false)\n            foundir = {dir, repo}\n            vprint(\"lock package(%s) in %s from repository(%s)/%s\", packagename, dir, locked_repo.url, locked_repo.commit)\n        end\n    end\n    return foundir\nend\n\n-- get all repositories\nfunction repositories()\n    if _g._REPOSITORIES then\n        return _g._REPOSITORIES\n    end\n    -- get all repositories (local first)\n    local repos = table.join(repository.repositories({global = false}), repository.repositories({global = true}))\n    _g._REPOSITORIES = repos\n    return repos\nend\n\n-- the remote repositories have been pulled?\nfunction pulled()\n\n    local network = project.policy(\"network.mode\")\n    if network == nil then\n        network = global.get(\"network\")\n    end\n\n    if network ~= \"private\" then\n        for _, repo in ipairs(repositories()) do\n            if not os.isdir(repo:url()) then\n                -- repository not found? or xmake has been re-installed\n                local repodir = repo:directory()\n                local updatefile = path.join(repodir, \"updated\")\n                if not os.isfile(updatefile) or (os.isfile(updatefile) and os.mtime(os.programfile()) > os.mtime(updatefile)) then\n                    -- fix broken empty directory\n                    -- @see https://github.com/xmake-io/xmake/issues/2159\n                    if os.isdir(repodir) and os.emptydir(repodir) then\n                        os.tryrm(repodir)\n                    end\n                    return false\n                end\n            end\n        end\n    end\n    return true\nend\n\n-- get package directory from repositories\nfunction packagedir(packagename, opt)\n\n    -- strip trailing ~tag, e.g. zlib~debug\n    opt = opt or {}\n    packagename = packagename:lower()\n    if packagename:find('~', 1, true) then\n        packagename = packagename:gsub(\"~.+$\", \"\")\n    end\n\n    -- get cache key\n    local reponame = opt.name\n    local cachekey = packagename\n    local locked_repo = opt.locked_repo\n    if locked_repo then\n        cachekey = cachekey .. locked_repo.url .. (locked_repo.commit or \"\") .. (locked_repo.branch or \"\")\n    end\n    local packagedirs = _g._PACKAGEDIRS\n    if not packagedirs then\n        packagedirs = {}\n        _g._PACKAGEDIRS = packagedirs\n    end\n\n    -- get the package directory\n    local foundir = packagedirs[cachekey]\n    if not foundir then\n\n        -- find the package directory from the locked repository\n        if locked_repo then\n            foundir = _get_packagedir_from_locked_repo(packagename, locked_repo)\n        end\n\n        -- find the package directory from repositories\n        if not foundir then\n            for _, repo in ipairs(repositories()) do\n                local dir = path.join(repo:directory(), \"packages\", packagename:sub(1, 1), packagename)\n                if os.isdir(dir) and os.isfile(path.join(dir, \"xmake.lua\")) and (not reponame or reponame == repo:name()) then\n                    foundir = {dir, repo}\n                    break\n                end\n            end\n        end\n        foundir = foundir or {}\n        packagedirs[cachekey] = foundir\n    end\n\n    -- save the current commit\n    local dir  = foundir[1]\n    local repo = foundir[2]\n    if repo and not repo:commit() then\n        local lastcommit = try {function()\n            if os.isdir(path.join(repo:directory(), \".git\")) then\n                return git.lastcommit({repodir = repo:directory()})\n            end\n        end}\n        repo:commit_set(lastcommit)\n    end\n    return dir, repo\nend\n\n-- get artifacts manifest from repositories\nfunction artifacts_manifest(packagename, version)\n    packagename = packagename:lower()\n    for _, repo in ipairs(repositories()) do\n        local manifestfile = path.join(repo:directory(), \"packages\", packagename:sub(1, 1), packagename, version, \"manifest.txt\")\n        if os.isfile(manifestfile) then\n            return io.load(manifestfile)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/search_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search_packages.lua\n--\n\n-- search packages from repositories\nfunction _search_packages(name, opt)\n\n    -- get package manager name\n    local manager_name, package_name = table.unpack(name:split(\"::\", {plain = true, strict = true}))\n    if package_name == nil then\n        package_name = manager_name\n        manager_name = \"xmake\"\n    else\n        manager_name = manager_name:lower():trim()\n    end\n\n    -- search packages\n    local packages = {}\n    local result = import(\"package.manager.\" .. manager_name .. \".search_package\", {anonymous = true})(package_name, opt)\n    if result then\n        table.join2(packages, result)\n    end\n    return packages\nend\n\n-- search packages\nfunction main(names, opt)\n    local results = {}\n    for _, name in ipairs(names) do\n        local packages = _search_packages(name, opt)\n        if packages then\n            table.sort(packages, function (a, b)\n                return name:levenshtein(a.name) < name:levenshtein(b.name)\n            end)\n            results[name] = packages\n        end\n    end\n    return results\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/uninstall_packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall_packages.lua\n--\n\n-- imports\nimport(\"core.cache.localcache\")\nimport(\"private.action.require.impl.package\")\n\n-- uninstall packages\nfunction main(requires, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- do not remove dependent packages\n    opt.nodeps = true\n\n    -- clear the local cache\n    localcache.clear()\n\n    -- remove all packages\n    local packages = {}\n    for _, instance in ipairs(package.load_packages(requires, opt)) do\n        if os.isfile(instance:manifest_file()) then\n            table.insert(packages, instance)\n        end\n        os.tryrm(instance:installdir())\n    end\n    return packages\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/utils/filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        filter.lua\n--\n\n-- imports\nimport(\"core.base.filter\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.sandbox.sandbox\")\n\n-- get filter\nfunction _filter()\n    if _g.filter == nil then\n        _g.filter = filter.new()\n        _g.filter:register(\"common\", function (variable)\n\n            -- attempt to get it directly from the configure\n            local result = config.get(variable)\n            if result == nil then\n\n                -- init maps\n                _g.common_maps = _g.common_maps or\n                {\n                    host        = os.host()\n                ,   subhost     = os.subhost()\n                ,   tmpdir      = function () return os.tmpdir() end\n                ,   curdir      = function () return os.curdir() end\n                ,   scriptdir   = function () return os.scriptdir() end\n                ,   globaldir   = global.directory()\n                ,   configdir   = config.directory()\n                ,   projectdir  = project.directory()\n                ,   programdir  = os.programdir()\n                }\n\n                -- map it\n                result = _g.common_maps[variable]\n            end\n\n            -- is script? call it\n            if type(result) == \"function\" then\n                result = result()\n            end\n            return result\n        end)\n    end\n    return _g.filter\nend\n\n-- the package handler\nfunction _handler(package, strval)\n\n    -- @note cannot cache it, because the package instance will be changed\n    return function (variable)\n        local maps = {\n            version = function ()\n                if strval then\n                    -- set_urls(\"https://sqlite.org/2018/sqlite-autoconf-$(version)000.tar.gz\",\n                    --          {version = function (version) return version:gsub(\"%.\", \"\") end})\n                    local version_filter = package:url_version(strval)\n                    if version_filter then\n                        local v = version_filter(package:version())\n                        if v ~= nil then\n                            -- may be semver version object\n                            v = tostring(v)\n                        end\n                        return v\n                    end\n                end\n                return package:version_str()\n            end\n        }\n\n        -- get value\n        local result = maps[variable]\n        if type(result) == \"function\" then\n            result = result()\n        end\n        return result\n    end\nend\n\n-- attach filter to the given script and call it\nfunction call(script, package, opt)\n\n    -- get sandbox filter and handlers of the given script\n    local sandbox_filter   = sandbox.filter(script)\n    local sandbox_handlers = sandbox_filter:handlers()\n\n    -- switch to the handlers of the current filter\n    sandbox_filter:set_handlers(_filter():handlers())\n\n    -- register package handler\n    sandbox_filter:register(\"package\", _handler(package))\n\n    -- call it\n    script(package, opt)\n\n    -- restore handlers\n    sandbox_filter:set_handlers(sandbox_handlers)\nend\n\n-- handle the string value of package\nfunction handle(strval, package)\n\n    -- register filter handler\n    _filter():register(\"package\", _handler(package, strval))\n\n    -- handle string value\n    strval = _filter():handle(strval)\n\n    -- register filter handler\n    _filter():register(\"package\", nil)\n\n    -- ok\n    return strval\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/utils/get_requires.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        get_requires.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\n\n-- get requires and extra config\nfunction main(requires)\n\n    -- init requires\n    local requires_extra = nil\n    if not requires then\n        requires, requires_extra = project.requires_str()\n    end\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- get extra info\n    local extra =  option.get(\"extra\")\n    local extrainfo = nil\n    if extra then\n        local v, err = string.deserialize(extra)\n        if err then\n            raise(err)\n        else\n            extrainfo = v\n        end\n    end\n\n    -- force to use the given requires extra info\n    if extrainfo then\n        requires_extra = requires_extra or {}\n        for _, require_str in ipairs(requires) do\n            requires_extra[require_str] = extrainfo\n        end\n    end\n    return requires, requires_extra\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/utils/requirekey.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        requirekey.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.package.package\", {alias = \"core_package\"})\n\n-- get require key from requireinfo\nfunction main(requireinfo, opt)\n    opt = opt or {}\n    local key = \"\"\n    if opt.name then\n        key = key .. \"/\" .. opt.name\n    end\n    if opt.plat then\n        key = key .. \"/\" .. opt.plat\n    end\n    if opt.arch then\n        key = key .. \"/\" .. opt.arch\n    end\n    if opt.kind then\n        key = key .. \"/\" .. opt.kind\n    end\n    if opt.version then\n        key = key .. \"/\" .. opt.version\n    end\n    if requireinfo.label then\n        key = key .. \"/\" .. requireinfo.label\n    end\n    if requireinfo.host then\n        if is_subhost(core_package.targetplat()) and os.subarch() == core_package.targetarch() then\n            -- we need to pass plat/arch to avoid repeat installation\n            -- @see https://github.com/xmake-io/xmake/issues/1579\n        else\n            key = key .. \"/host\"\n        end\n    end\n    if requireinfo.system then\n        key = key .. \"/system\"\n    end\n    -- @see https://github.com/xmake-io/xmake/issues/4934\n    if requireinfo.private then\n        key = key .. \"/private\"\n    end\n    if key:startswith(\"/\") then\n        key = key:sub(2)\n    end\n    local configs = requireinfo.configs\n    if configs then\n        local configs_order = {}\n        for k, v in pairs(configs) do\n            if type(v) == \"table\" then\n                v = string.serialize(v, {strip = true, indent = false, orderkeys = true})\n            end\n            table.insert(configs_order, k .. \"=\" .. tostring(v))\n        end\n        table.sort(configs_order)\n        key = key .. \":\" .. string.serialize(configs_order, true)\n    end\n    if opt.hash then\n        if key == \"\" then\n            key = \"_\" -- we need to generate a fixed hash value\n        end\n        return hash.strhash32(key)\n    else\n        return key\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/impl/utils/url_filename.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        url_filename.lua\n--\n\n-- get raw filename\nfunction raw_filename(url)\n    local urlpath = url:split('?', {plain = true})[1]\n    return path.filename(urlpath)\nend\n\n-- get filename from github name mangling\nfunction github_filename(url)\n    local reponame = url:match(\"^https://github.com/[^/]-/([^/]-)/archive/\")\n    if reponame then\n        local filename = raw_filename(url)\n        if filename:find(\"^v%d\") then\n            filename = filename:match(\"^v(.+)\")\n        end\n        return reponame .. \"-\" .. filename\n    end\nend\n\n-- get filename from url\nfunction main(url)\n    return raw_filename(url)\nend\n"
  },
  {
    "path": "xmake/modules/private/action/require/import.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        import.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.import_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- import the given packages\nfunction main(requires_raw)\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- import packages\n    local packagedir = option.get(\"packagedir\")\n    local packages  = import_packages(requires, {requires_extra = requires_extra, packagedir = packagedir})\n    if not packages or #packages == 0 then\n        if requires_raw then\n            cprint(\"${bright}packages(%s) cannot be imported, maybe they don’t exactly match the configuration.\", table.concat(requires_raw, \", \"))\n            if os.getenv(\"XREPO_WORKING\") then\n                print(\"please attempt to import them with `-f/--configs=` option, e.g.\")\n                print(\"    - xrepo import -f \\\"name=value, ...\\\" package\")\n                print(\"    - xrepo import -m debug -k shared -f \\\"name=value, ...\\\" package\")\n            else\n                print(\"please attempt to import them with `--extra=` option, e.g.\")\n                print(\"    - xmake require --import --extra=\\\"{configs={...}}\\\" package\")\n                print(\"    - xmake require --import --extra=\\\"{debug=true,configs={shared=true}}\\\" package\")\n            end\n        end\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/info.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        info.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.project\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"devel.git\")\nimport(\"utils.archive\")\nimport(\"private.action.require.impl.utils.filter\")\nimport(\"private.action.require.impl.utils.url_filename\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- from xmake/system/remote?\nfunction _from(instance)\n    local fetchinfo = instance:fetch()\n    if fetchinfo then\n        if instance:is_thirdparty() then\n            return \", ${green}3rd${clear}\"\n        elseif instance:is_system() then\n            return \", ${green}system${clear}\"\n        else\n            return \"\"\n        end\n    elseif #instance:urls() > 0 then\n        local repo = instance:repo()\n        local reponame = repo and repo:name() or \"unknown\"\n        return instance:is_supported() and format(\", ${yellow}remote${clear}(in %s)\", reponame) or format(\", ${yellow}remote${clear}(${red}unsupported${clear} in %s)\", reponame)\n    elseif instance:is_system() then\n        return \", ${red}missing${clear}\"\n    else\n        return \"\"\n    end\nend\n\n-- get package info\nfunction _info(instance)\n    local info = instance:version_str() and instance:version_str() or \"no version\"\n    info = info .. _from(instance)\n    info = info .. (instance:is_optional() and \", ${yellow}optional${clear}\" or \"\")\n    return info\nend\n\n-- show the given package info\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- show title\n    print(\"The package info of project:\")\n\n    -- list all packages\n    for _, instance in ipairs(package.load_packages(requires, {requires_extra = requires_extra})) do\n\n        -- show package name\n        local requireinfo = instance:requireinfo() or {}\n        cprint(\"    ${color.dump.string_quote}require${clear}(%s): \", requireinfo.originstr)\n\n        -- show description\n        local description = instance:get(\"description\")\n        if description then\n            cprint(\"      -> ${color.dump.string_quote}description${clear}: %s\", description)\n        end\n\n        -- show version\n        local version = instance:version_str()\n        if version then\n            cprint(\"      -> ${color.dump.string_quote}version${clear}: %s\", version)\n        end\n\n        -- show license\n        local license = instance:get(\"license\")\n        if license then\n            cprint(\"      -> ${color.dump.string_quote}license${clear}: %s\", license)\n        end\n\n        -- show urls\n        local urls = instance:urls()\n        if urls and #urls > 0 then\n            cprint(\"      -> ${color.dump.string_quote}urls${clear}:\")\n            local schemes = instance:schemes_orderlist()\n            if schemes then\n                for _, scheme in ipairs(schemes) do\n                    if not scheme:is_precompiled() then\n                        local urls = scheme:urls()\n                        if urls and #urls > 0 then\n                            local scheme_name = scheme:is_default() and \"default\" or scheme:name()\n                            cprint(\"         -> ${magenta}%s${clear}:\", scheme_name)\n                            for _, url in ipairs(urls) do\n                                print(\"            -> %s\", filter.handle(url, instance))\n                                if git.asgiturl(url) then\n                                    local url_alias = scheme:url_alias(url)\n                                    cprint(\"               -> ${yellow}%s\", scheme:revision(url_alias) or scheme:tag() or scheme:version_str())\n                                else\n                                    local sourcehash = scheme:sourcehash(scheme:url_alias(url))\n                                    if sourcehash then\n                                        cprint(\"               -> ${yellow}%s\", sourcehash)\n                                    end\n                                end\n                            end\n                        end\n                    end\n                end\n            end\n        end\n\n        -- show repository\n        local repo = instance:repo()\n        if repo then\n            cprint(\"      -> ${color.dump.string_quote}repo${clear}: %s %s %s\", repo:name(), repo:url(), repo:branch() or \"\")\n        end\n\n        -- show deps\n        local deps = instance:orderdeps()\n        if deps and #deps > 0 then\n            cprint(\"      -> ${color.dump.string_quote}deps${clear}:\")\n            for _, dep in ipairs(deps) do\n                requireinfo = dep:requireinfo() or {}\n                cprint(\"         -> %s\", requireinfo.originstr)\n            end\n        end\n\n        -- show cache directory\n        cprint(\"      -> ${color.dump.string_quote}cachedir${clear}: %s\", instance:cachedir())\n\n        -- show install directory\n        cprint(\"      -> ${color.dump.string_quote}installdir${clear}: %s\", instance:installdir())\n\n        -- show search directories and search names\n        cprint(\"      -> ${color.dump.string_quote}searchdirs${clear}: %s\", table.concat(table.wrap(core_package.searchdirs()), path.envsep()))\n        local searchnames = hashset.new()\n        for _, url in ipairs(urls) do\n            url = filter.handle(url, instance)\n            if git.checkurl(url) then\n                searchnames:insert(instance:name() .. archive.extension(url) .. \" ${dim}(git)${clear}\")\n                searchnames:insert(path.basename(url_filename(url)) .. \" ${dim}(git)${clear}\")\n            else\n                local extension = archive.extension(url)\n                if extension then\n                    searchnames:insert(instance:name() .. \"-\" .. instance:version_str() .. extension)\n                end\n                searchnames:insert(url_filename(url))\n\n                -- match github name mangling https://github.com/xmake-io/xmake/issues/1343\n                local github_name = url_filename.github_filename(url)\n                if github_name then\n                    searchnames:insert(github_name)\n                end\n            end\n        end\n        cprint(\"      -> ${color.dump.string_quote}searchnames${clear}:\")\n        for _, searchname in searchnames:keys() do\n            cprint(\"         -> %s\", searchname)\n        end\n\n        -- show fetch info\n        cprint(\"      -> ${color.dump.string_quote}fetchinfo${clear}: %s\", _info(instance))\n        local fetchinfo = instance:fetch()\n        if fetchinfo then\n            for name, info in pairs(fetchinfo) do\n                info = table.unwrap(info)\n                if type(info) ~= \"table\" then\n                    info = tostring(info)\n                end\n                cprint(\"          -> ${color.dump.string_quote}%s${clear}: %s\", name, table.concat(table.wrap(info), \" \"))\n            end\n        end\n\n        -- show supported platforms\n        local platforms = {}\n        local on_install = instance:get(\"install\")\n        if type(on_install) == \"table\" then\n            for plat, _ in pairs(on_install) do\n                table.insert(platforms, plat)\n            end\n        else\n            table.insert(platforms, \"all\")\n        end\n        cprint(\"      -> ${color.dump.string_quote}platforms${clear}: %s\", table.concat(platforms, \", \"))\n\n        -- show requires\n        cprint(\"      -> ${color.dump.string_quote}requires${clear}:\")\n        cprint(\"         -> ${cyan}plat${clear}: %s\", instance:plat())\n        cprint(\"         -> ${cyan}arch${clear}: %s\", instance:arch())\n        local configs_required = instance:configs()\n        if configs_required then\n            cprint(\"         -> ${cyan}configs${clear}:\")\n            for name, value in pairs(configs_required) do\n                cprint(\"            -> %s: %s\", name, value)\n            end\n        end\n\n        -- show user configs\n        local configs_defined = instance:get(\"configs\")\n        if configs_defined then\n            cprint(\"      -> ${color.dump.string_quote}configs${clear}:\")\n            for _, conf in ipairs(configs_defined) do\n                local configs_extra = instance:extraconf(\"configs\", conf)\n                if configs_extra and not configs_extra.builtin then\n                    cprintf(\"         -> ${cyan}%s${clear}: \", conf)\n                    if configs_extra.description then\n                        printf(configs_extra.description)\n                    end\n                    if configs_extra.default ~= nil then\n                        printf(\" (default: %s)\", configs_extra.default)\n                    elseif configs_extra.type ~= nil and configs_extra.type ~= \"string\" then\n                        printf(\" (type: %s)\", configs_extra.type)\n                    end\n                    if configs_extra.readonly then\n                        printf(\" (readonly)\")\n                    end\n                    print(\"\")\n                    if configs_extra.values then\n                        cprint(\"            -> values: %s\", string.serialize(configs_extra.values, true))\n                    end\n                end\n            end\n        end\n\n        -- show builtin configs\n        local configs_defined = instance:get(\"configs\")\n        if configs_defined then\n            cprint(\"      -> ${color.dump.string_quote}configs (builtin)${clear}:\")\n            for _, conf in ipairs(configs_defined) do\n                local configs_extra = instance:extraconf(\"configs\", conf)\n                if configs_extra and configs_extra.builtin then\n                    cprintf(\"         -> ${cyan}%s${clear}: \", conf)\n                    if configs_extra.description then\n                        printf(configs_extra.description)\n                    end\n                    if configs_extra.default ~= nil then\n                        printf(\" (default: %s)\", configs_extra.default)\n                    elseif configs_extra.type ~= nil and configs_extra.type ~= \"string\" then\n                        printf(\" (type: %s)\", configs_extra.type)\n                    end\n                    print(\"\")\n                    if configs_extra.values then\n                        cprint(\"            -> values: %s\", string.serialize(configs_extra.values, true))\n                    end\n                end\n            end\n        end\n\n        -- show components\n        local components = instance:get(\"components\")\n        if components then\n            cprint(\"      -> ${color.dump.string_quote}components${clear}: \")\n            for _, comp in ipairs(components) do\n                cprintf(\"         -> ${cyan}%s${clear}: \", comp)\n                local plaindeps = instance:extraconf(\"components\", comp, \"deps\")\n                if plaindeps then\n                    print(\"%s\", table.concat(table.wrap(plaindeps), \", \"))\n                else\n                    print(\"\")\n                end\n            end\n        end\n\n        -- show references\n        local references = instance:references()\n        if references then\n            cprint(\"      -> ${color.dump.string_quote}references${clear}:\")\n            for projectdir, refdate in pairs(references) do\n                cprint(\"         -> %s: %s%s\", refdate, projectdir, os.isdir(projectdir) and \"\" or \" ${red}(not found)${clear}\")\n            end\n        end\n\n        -- end\n        print(\"\")\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- check missing packages\nfunction _check_missing_packages(packages)\n\n    -- get all missing packages\n    local packages_missing = {}\n    local optional_missing = {}\n    for _, instance in ipairs(packages) do\n        if package.should_install(instance, {install_finished = true}) or (instance:is_fetchonly() and not instance:exists()) then\n            if instance:is_optional() then\n                optional_missing[instance:name()] = instance\n            else\n                table.insert(packages_missing, instance:name())\n            end\n        end\n    end\n\n    -- raise tips\n    if #packages_missing > 0 then\n        local cmd = \"xmake repo -u\"\n        if os.getenv(\"XREPO_WORKING\") then\n            cmd = \"xrepo update-repo\"\n        end\n        raise(\"The packages(%s) not found, please run `%s` first!\", table.concat(packages_missing, \", \"), cmd)\n    end\n\n    -- save the optional missing packages\n    _g.optional_missing = optional_missing\nend\n\n-- install packages\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- find git\n    environment.enter()\n    local git = find_tool(\"git\")\n    environment.leave()\n\n    -- pull all repositories first if not exists\n    --\n    -- attempt to install git from the builtin-packages first if git not found\n    --\n    if git and (not repository.pulled() or option.get(\"upgrade\")) then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- install packages\n    environment.enter()\n    local packages = install_packages(requires, {requires_extra = requires_extra})\n    if packages then\n        _check_missing_packages(packages)\n    end\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/list.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        list.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.task\")\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\n\n-- from xmake/system/remote?\nfunction _from(instance)\n    local fetchinfo = instance:fetch()\n    if fetchinfo then\n        if instance:is_thirdparty() then\n            return \", ${green}3rd${clear}\"\n        elseif instance:is_system() then\n            return \", ${green}system${clear}\"\n        else\n            return \"\"\n        end\n    elseif #instance:urls() > 0 then\n        return instance:is_supported() and format(\", ${yellow}remote${clear}(in %s)\", instance:repo():name()) or format(\", ${yellow}remote${clear}(${red}unsupported${clear} in %s)\", instance:repo():name())\n    elseif instance:is_system() then\n        return \", ${red}missing${clear}\"\n    else\n        return \"\"\n    end\nend\n\n-- get package info\nfunction _info(instance)\n    local info = instance:version_str() and instance:version_str() or \"no version\"\n    info = info .. _from(instance)\n    info = info .. (instance:is_optional() and \", ${yellow}optional${clear}\" or \"\")\n    return info\nend\n\nfunction _get_status(instance)\n    local fetchinfo = instance:fetch()\n    if fetchinfo then\n        if instance:is_thirdparty() then\n            return \"3rd\"\n        elseif instance:is_system() then\n            return \"system\"\n        else\n            return \"installed\"\n        end\n    elseif #instance:urls() > 0 then\n        return \"remote\"\n    elseif instance:is_system() then\n        return \"missing\"\n    end\n    return \"unknown\"\nend\n\nfunction _make_info_json(instance)\n    local info = {}\n    info.name = instance:name()\n    info.requirestr = instance:requireinfo().originstr\n    info.version = instance:version_str()\n    info.status = _get_status(instance)\n\n    if info.status == \"remote\" then\n         if instance:repo() then\n            info.repo = instance:repo():name()\n         end\n         if not instance:is_supported() then\n            info.supported = false\n         end\n    end\n\n    if instance:is_optional() then\n        info.optional = true\n    end\n\n    local fetchinfo = instance:fetch()\n    if fetchinfo then\n        info.fetchinfo = fetchinfo\n    end\n\n    local deps = {}\n    for _, dep in ipairs(instance:orderdeps()) do\n        table.insert(deps, _make_info_json(dep))\n    end\n    if #deps > 0 then\n        info.deps = deps\n    end\n    return info\nend\n\n-- list packages\nfunction main()\n\n    -- get requires\n    local requires, requires_extra = project.requires_str()\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    if option.get(\"json\") then\n        local list = {}\n        for _, instance in ipairs(package.load_packages(requires, {requires_extra = requires_extra})) do\n             table.insert(list, _make_info_json(instance))\n        end\n        print(json.encode(list))\n        environment.leave()\n        return\n    end\n\n    -- list all required packages\n    print(\"The package dependencies of project:\")\n\n    -- list all required packages\n    for _, instance in ipairs(package.load_packages(requires, {requires_extra = requires_extra})) do\n        cprint(\"    ${color.dump.string_quote}require${clear}(%s): %s\", instance:requireinfo().originstr, _info(instance))\n        for _, dep in ipairs(instance:orderdeps()) do\n            cprint(\"      -> ${color.dump.string_quote}dep${clear}(%s): %s\", dep:requireinfo().originstr, _info(dep))\n        end\n        local fetchinfo = instance:fetch()\n        if fetchinfo then\n            for name, info in pairs(fetchinfo) do\n                if type(info) == \"table\" then\n                    cprint(\"      -> ${color.dump.string_quote}%s${clear}: %s\", name, table.concat(info, \" \"))\n                else\n                    cprint(\"      -> ${color.dump.string_quote}%s${clear}: %s\", name, tostring(info))\n                end\n            end\n        end\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/register.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        register.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"lib.detect.find_tool\")\nimport(\"async.runjobs\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.register_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- register packages\nfunction main(requires_raw)\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- find git\n    environment.enter()\n    local git = find_tool(\"git\")\n    environment.leave()\n\n    -- pull all repositories first if not exists\n    --\n    -- attempt to install git from the builtin-packages first if git not found\n    --\n    if git and (not repository.pulled() or option.get(\"upgrade\")) then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- register packages\n    local packages = package.load_packages(requires, {requires_extra = requires_extra})\n    if packages then\n\n        -- fetch and register packages (with system) from local first\n        runjobs(\"fetch_packages\", function (index)\n            local instance = packages[index]\n            if instance and (not option.get(\"force\") or (option.get(\"shallow\") and not instance:is_toplevel())) then\n                local oldenvs = os.getenvs()\n                instance:envs_enter()\n                instance:fetch()\n                os.setenvs(oldenvs)\n            end\n        end, {total = #packages, isolate = true})\n\n        -- register all required root packages to local cache\n        register_packages(packages)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/scan.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional scanrmation\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scan.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.package.package\")\n\n-- scan local package\nfunction _scan_package(packagedir)\n\n    -- show packages\n    local package_name = path.filename(packagedir)\n    for _, versiondir in ipairs(os.dirs(path.join(packagedir, \"*\"))) do\n        local version = path.filename(versiondir)\n        cprint(\"${color.dump.string}%s-%s${clear}:\", package_name, version)\n\n        -- show package hash\n        for _, hashdir in ipairs(os.dirs(path.join(versiondir, \"*\"))) do\n            local hash = path.filename(hashdir)\n            local references_file = path.join(hashdir, \"references.txt\")\n            local referenced = false\n            local references = os.isfile(references_file) and io.load(references_file) or nil\n            if references then\n                for projectdir, refdate in pairs(references) do\n                    if os.isdir(projectdir) then\n                        referenced = true\n                        break\n                    end\n                end\n            end\n            local manifest_file = path.join(hashdir, \"manifest.txt\")\n            local manifest = os.isfile(manifest_file) and io.load(manifest_file) or nil\n            cprintf(\"  -> ${yellow}%s${clear}: ${green}%s, %s\", hash, manifest and manifest.plat or \"\", manifest and manifest.arch or \"\")\n            if os.emptydir(hashdir) then\n                cprintf(\", ${red}empty\")\n            elseif not referenced then\n                cprintf(\", ${red}unused\")\n            elseif not manifest then\n                cprintf(\", ${red}invalid\")\n            end\n            print(\"\")\n            if manifest and manifest.configs then\n                print(\"    -> %s\", string.serialize(manifest.configs, {orderkeys = true, indent = false, strip = true}))\n            end\n        end\n    end\nend\n\n-- scan local packages\nfunction main(package_names)\n\n    -- trace\n    print(\"scanning packages ..\")\n\n    -- scan packages\n    local installdir = package.installdir()\n    if package_names then\n        for _, package_name in ipairs(package_names) do\n            for _, packagedir in ipairs(os.dirs(path.join(installdir, package_name:sub(1, 1), package_name))) do\n                _scan_package(packagedir)\n            end\n        end\n    else\n        for _, packagedir in ipairs(os.dirs(path.join(installdir, \"*\", \"*\"))) do\n            _scan_package(packagedir)\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/search.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"private.action.require.impl.utils.filter\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.search_packages\")\n\n-- search the given packages\nfunction main(names)\n\n    -- no names?\n    if not names then\n        return\n    end\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- show title\n    print(\"The package names:\")\n\n    -- search packages\n    for name, packages in pairs(search_packages(names)) do\n        if #packages > 0 then\n\n            -- show name\n            print(\"    %s: \", name)\n\n            -- show packages\n            for _, result in ipairs(packages) do\n                local name = result.name\n                local version = result.version\n                local reponame = result.reponame\n                local description = result.description\n                cprint(\"      -> ${color.dump.string}%s%s${clear}: %s %s\", name,\n                    version and (\"-\" .. version) or \"\",\n                    description or \"\",\n                    reponame and (\"(in \" .. reponame .. \")\") or \"\")\n            end\n        end\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/require/uninstall.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.repository\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.action.require.impl.uninstall_packages\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- uninstall the given packages\nfunction main(requires_raw)\n\n    -- enter environment\n    environment.enter()\n\n    -- pull all repositories first if not exists\n    if not repository.pulled() then\n        task.run(\"repo\", {update = true})\n    end\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- uninstall packages\n    local packages = uninstall_packages(requires, {requires_extra = requires_extra})\n    for _, instance in ipairs(packages) do\n        print(\"uninstall: %s%s ok!\", instance:name(), instance:version_str() and (\"-\" .. instance:version_str()) or \"\")\n    end\n    if not packages or #packages == 0 then\n        cprint(\"${bright}packages(%s) not found, maybe they don’t exactly match the configuration\"\n            , requires_raw and table.concat(requires_raw, \", \") or \"\")\n        if os.getenv(\"XREPO_WORKING\") then\n            print(\"please attempt to remove them with `-f/--configs=` option, e.g.\")\n            print(\"    - xrepo remove -f \\\"name=value, ...\\\" package\")\n            print(\"    - xrepo remove -m debug -k shared -f \\\"name=value, ...\\\" package\")\n        else\n            print(\"please attempt to uninstall them with `--extra=` option, e.g.\")\n            print(\"    - xmake require --uninstall --extra=\\\"{configs={...}}\\\" package\")\n            print(\"    - xmake require --uninstall --extra=\\\"{debug=true,configs={shared=true}}\\\" package\")\n        end\n    end\n\n    -- leave environment\n    environment.leave()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/run/runenvs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, OpportunityLiu, SirLynix\n-- @file        runenvs.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\n\n-- add search directories for all dependent shared libraries on windows\nfunction _make_runpath_on_windows(target)\n    local pathenv = {}\n    local searchdirs = hashset.new()\n    local function insert(dir)\n        if not path.is_absolute(dir) then\n            dir = path.absolute(dir, os.projectdir())\n        end\n        if searchdirs:insert(dir) then\n            table.insert(pathenv, dir)\n        end\n    end\n\n    -- recursively add targets and dep targets linkdirs\n    local seentargets = hashset.new()\n    local function insert_target(target)\n        if seentargets:insert(target) then\n            for _, linkdir in ipairs(target:get(\"linkdirs\")) do\n                insert(linkdir)\n            end\n            for _, opt in ipairs(target:orderopts()) do\n                for _, linkdir in ipairs(opt:get(\"linkdirs\")) do\n                    insert(linkdir)\n                end\n            end\n            for _, pkg in ipairs(target:orderpkgs()) do\n                for _, linkdir in ipairs(pkg:get(\"linkdirs\")) do\n                    insert(linkdir)\n                end\n            end\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:kind() == \"shared\" then\n                    insert(dep:targetdir())\n                end\n                insert_target(dep)\n            end\n            for _, toolchain in ipairs(target:toolchains()) do\n                local runenvs = toolchain:runenvs()\n                if runenvs and runenvs.PATH then\n                    for _, env in ipairs(path.splitenv(runenvs.PATH)) do\n                        insert(env)\n                    end\n                end\n            end\n        end\n    end\n    insert_target(target)\n    return pathenv\nend\n\n-- flatten envs ({PATH = {\"A\", \"B\"}} => {PATH = \"A;B\"})\nfunction _flatten_envs(envs)\n    local flatten_envs = {}\n    for name, values in pairs(envs) do\n        flatten_envs[name] = path.joinenv(values)\n    end\n    return flatten_envs\nend\n\n-- join addenvs and setenvs in a common envs table\nfunction join(addenvs, setenvs)\n    local envs = os.joinenvs(addenvs and _flatten_envs(addenvs) or {})\n    if setenvs then\n        envs = os.joinenvs(envs, _flatten_envs(setenvs))\n    end\n    return envs\nend\n\n-- recursively add package envs\nfunction _add_target_pkgenvs(addenvs, target, targets_added)\n    if targets_added[target:name()] then\n        return\n    end\n    targets_added[target:name()] = true\n    local pkgenvs = target:pkgenvs()\n    if pkgenvs then\n        for name, values in pairs(pkgenvs) do\n            values = path.splitenv(values)\n            local oldenvs = addenvs[name]\n            if oldenvs then\n                table.join2(oldenvs, values)\n            else\n                addenvs[name] = values\n            end\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        _add_target_pkgenvs(addenvs, dep, targets_added)\n    end\nend\n\n-- deduplicate envs\n-- @see https://github.com/xmake-io/xmake/issues/5184\nfunction _dedup_envs(envs)\n    local envs_new = {}\n    for k, v in pairs(envs) do\n        if type(v) == \"table\" then\n            envs_new[k] = table.unique(v)\n        else\n            envs_new[k] = v\n        end\n    end\n    return envs_new\nend\n\nfunction make(target)\n\n    -- add run environments\n    local setenvs = {}\n    local addenvs = {}\n    local runenvs = target:get(\"runenvs\")\n    if runenvs then\n        for name, values in pairs(runenvs) do\n            addenvs[name] = table.wrap(values)\n        end\n    end\n    local runenv = target:get(\"runenv\")\n    if runenv then\n        for name, value in pairs(runenv) do\n            setenvs[name] = table.wrap(value)\n            if addenvs[name] then\n                utils.warning(format(\"both add_runenvs and set_runenv called on environment variable \\\"%s\\\", the former one will be ignored.\", name))\n                addenvs[name] = nil\n            end\n        end\n    end\n\n    -- add package run environments\n    _add_target_pkgenvs(addenvs, target, {})\n\n    -- add search directories for all dependent shared libraries on windows\n    if target:is_plat(\"windows\") or (target:is_plat(\"mingw\") and is_host(\"windows\")) then\n        local pathenv = addenvs[\"PATH\"] or setenvs[\"PATH\"]\n        local runpath = _make_runpath_on_windows(target)\n        if pathenv == nil then\n            addenvs[\"PATH\"] = runpath\n        else\n            table.join2(pathenv, runpath)\n        end\n    end\n\n    -- deduplicate envs\n    if addenvs then\n        addenvs = _dedup_envs(addenvs)\n    end\n    if setenvs then\n        setenvs = _dedup_envs(setenvs)\n    end\n    return addenvs, setenvs\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/autoconf.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        autoconf.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- translate path\nfunction _translate_path(p)\n    if p and is_host(\"windows\") and is_plat(\"mingw\") then\n        p = p:gsub(\"\\\\\", \"/\")\n    end\n    return p\nend\n\n-- translate windows bin path\nfunction _translate_windows_bin_path(bin_path)\n    if bin_path then\n        local argv = os.argv(bin_path)\n        argv[1] = argv[1]:gsub(\"\\\\\", \"/\") .. \".exe\"\n        return os.args(argv)\n    end\nend\n\n-- get build directory\nfunction _get_buildir()\n    return config.builddir() or \"build\"\nend\n\n-- get artifacts directory\nfunction _get_artifacts_dir()\n    return path.absolute(path.join(_get_buildir(), \"artifacts\"))\nend\n\n-- get the build environment\nfunction _get_buildenv(key)\n    local value = config.get(key)\n    if value == nil then\n        value = platform.toolconfig(key, config.plat())\n    end\n    if value == nil then\n        value = platform.tool(key, config.plat())\n    end\n    return value\nend\n\n-- is cross compilation?\nfunction _is_cross_compilation()\n    if not is_plat(os.subhost()) then\n        return true\n    end\n    if is_plat(\"macosx\") and not is_arch(os.subarch()) then\n        return true\n    end\n    return false\nend\n\n-- get the build environments\nfunction _get_buildenvs()\n    local envs = {}\n    local cross = false\n    if not _is_cross_compilation() then\n        local cflags   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n        local cxxflags = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n        local asflags  = table.copy(table.wrap(_get_buildenv(\"asflags\")))\n        local ldflags  = table.copy(table.wrap(_get_buildenv(\"ldflags\")))\n        if is_plat(\"linux\") and is_arch(\"i386\") then\n            table.insert(cflags,   \"-m32\")\n            table.insert(cxxflags, \"-m32\")\n            table.insert(asflags,  \"-m32\")\n            table.insert(ldflags,  \"-m32\")\n        end\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(asflags, ' ')\n        envs.LDFLAGS   = table.concat(ldflags, ' ')\n    else\n        cross = true\n        local cflags   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n        local cxxflags = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n        envs.CC        = _get_buildenv(\"cc\")\n        envs.AS        = _get_buildenv(\"as\")\n        envs.AR        = _get_buildenv(\"ar\")\n        envs.LD        = _get_buildenv(\"ld\")\n        envs.LDSHARED  = _get_buildenv(\"sh\")\n        envs.CPP       = _get_buildenv(\"cpp\")\n        envs.RANLIB    = _get_buildenv(\"ranlib\")\n        envs.CFLAGS    = table.concat(cflags, ' ')\n        envs.CXXFLAGS  = table.concat(cxxflags, ' ')\n        envs.ASFLAGS   = table.concat(table.wrap(_get_buildenv(\"asflags\")), ' ')\n        envs.ARFLAGS   = table.concat(table.wrap(_get_buildenv(\"arflags\")), ' ')\n        envs.LDFLAGS   = table.concat(table.wrap(_get_buildenv(\"ldflags\")), ' ')\n        envs.SHFLAGS   = table.concat(table.wrap(_get_buildenv(\"shflags\")), ' ')\n    end\n\n    -- cross-compilation? pass the full build environments\n    if cross then\n        local ar = envs.AR\n        if is_plat(\"mingw\") then\n            -- fix linker error, @see https://github.com/xmake-io/xmake/issues/574\n            -- libtool: line 1855: lib: command not found\n            envs.ARFLAGS = nil\n            local ld = envs.LD\n            if ld then\n                if ld:endswith(\"x86_64-w64-mingw32-g++\") then\n                    envs.LD = path.join(path.directory(ld), is_host(\"windows\") and \"ld\" or \"x86_64-w64-mingw32-ld\")\n                elseif ld:endswith(\"i686-w64-mingw32-g++\") then\n                    envs.LD = path.join(path.directory(ld), is_host(\"windows\") and \"ld\" or \"i686-w64-mingw32-ld\")\n                end\n            end\n            if is_host(\"windows\") then\n                envs.CC       = _translate_windows_bin_path(envs.CC)\n                envs.AS       = _translate_windows_bin_path(envs.AS)\n                envs.AR       = _translate_windows_bin_path(envs.AR)\n                envs.LD       = _translate_windows_bin_path(envs.LD)\n                envs.LDSHARED = _translate_windows_bin_path(envs.LDSHARED)\n                envs.CPP      = _translate_windows_bin_path(envs.CPP)\n                envs.RANLIB   = _translate_windows_bin_path(envs.RANLIB)\n            end\n        elseif is_plat(\"cross\") or (ar and ar:find(\"ar\")) then\n            -- only for cross-toolchain\n            envs.CXX = _get_buildenv(\"cxx\")\n            if not envs.ARFLAGS or envs.ARFLAGS == \"\" then\n                envs.ARFLAGS = \"-cr\"\n            end\n        end\n\n        -- we should use ld as linker\n        --\n        -- @see\n        -- https://github.com/xmake-io/xmake-repo/pull/1043\n        -- https://github.com/libexpat/libexpat/issues/312\n        -- https://github.com/xmake-io/xmake/issues/2195\n        local ld = envs.LD\n        if ld then\n            local dir = path.directory(ld)\n            local name = path.filename(ld)\n            name = name:gsub(\"clang%+%+$\", \"ld\")\n            name = name:gsub(\"clang%+%+%-%d+\", \"ld\")\n            name = name:gsub(\"clang$\", \"ld\")\n            name = name:gsub(\"clang%-%d+\", \"ld\")\n            name = name:gsub(\"gcc$\", \"ld\")\n            name = name:gsub(\"gcc-%d+\", \"ld\")\n            name = name:gsub(\"g%+%+$\", \"ld\")\n            name = name:gsub(\"g%+%+%-%d+\", \"ld\")\n            envs.LD = dir and path.join(dir, name) or name\n        end\n        -- we need to use clang++ as cxx, autoconf will use it as linker\n        -- https://github.com/xmake-io/xmake/issues/2170\n        local cxx = envs.CXX\n        if cxx then\n            local dir = path.directory(cxx)\n            local name = path.filename(cxx)\n            name = name:gsub(\"clang$\", \"clang++\")\n            name = name:gsub(\"clang%-\", \"clang++-\")\n            name = name:gsub(\"gcc$\", \"g++\")\n            name = name:gsub(\"gcc%-\", \"g++-\")\n            envs.CXX = dir and path.join(dir, name) or name\n        end\n    end\n\n    if option.get(\"verbose\") then\n        print(envs)\n    end\n    return envs\nend\n\n-- get configs\nfunction _get_configs(artifacts_dir)\n\n    -- add prefix\n    local configs = {}\n    table.insert(configs, \"--prefix=\" .. _translate_path(artifacts_dir))\n\n    -- add extra user configs\n    local tryconfigs = config.get(\"tryconfigs\")\n    if tryconfigs then\n        for _, opt in ipairs(os.argv(tryconfigs)) do\n            table.insert(configs, tostring(opt))\n        end\n    end\n\n    -- add host for cross-complation\n    if _is_cross_compilation() then\n        if is_plat(\"iphoneos\", \"macosx\") then\n            local triples =\n            {\n                arm64  = \"aarch64-apple-darwin\",\n                arm64e = \"aarch64-apple-darwin\",\n                armv7  = \"armv7-apple-darwin\",\n                armv7s = \"armv7s-apple-darwin\",\n                i386   = \"i386-apple-darwin\",\n                x86_64 = \"x86_64-apple-darwin\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[config.arch()] or triples.arm64))\n        elseif is_plat(\"android\") then\n            -- @see https://developer.android.com/ndk/guides/other_build_systems#autoconf\n            local triples =\n            {\n                [\"armv5te\"]     = \"arm-linux-androideabi\",  -- deprecated\n                [\"armv7-a\"]     = \"arm-linux-androideabi\",  -- deprecated\n                [\"armeabi\"]     = \"arm-linux-androideabi\",  -- removed in ndk r17\n                [\"armeabi-v7a\"] = \"arm-linux-androideabi\",\n                [\"arm64-v8a\"]   = \"aarch64-linux-android\",\n                i386            = \"i686-linux-android\",     -- deprecated\n                x86             = \"i686-linux-android\",\n                x86_64          = \"x86_64-linux-android\",\n                mips            = \"mips-linux-android\",     -- removed in ndk r17\n                mips64          = \"mips64-linux-android\"    -- removed in ndk r17\n            }\n            table.insert(configs, \"--host=\" .. (triples[config.arch()] or triples[\"armeabi-v7a\"]))\n        elseif is_plat(\"mingw\") then\n            local triples =\n            {\n                i386   = \"i686-w64-mingw32\",\n                x86_64 = \"x86_64-w64-mingw32\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[config.arch()] or triples.i386))\n        elseif is_plat(\"linux\") then\n            local triples =\n            {\n                [\"arm64-v8a\"] = \"aarch64-linux-gnu\",\n                arm64 = \"aarch64-linux-gnu\",\n                i386   = \"i686-linux-gnu\",\n                x86_64 = \"x86_64-linux-gnu\",\n                armv7 = \"arm-linux-gnueabihf\",\n                mips = \"mips-linux-gnu\",\n                mips64 = \"mips64-linux-gnu\",\n                mipsel = \"mipsel-linux-gnu\",\n                mips64el = \"mips64el-linux-gnu\",\n                loong64 = \"loongarch64-linux-gnu\"\n            }\n            table.insert(configs, \"--host=\" .. (triples[config.arch()] or triples.i386))\n        elseif is_plat(\"cross\") then\n            local host = config.arch()\n            if is_arch(\"arm64\") then\n                host = \"aarch64\"\n            elseif is_arch(\"arm.*\") then\n                host = \"arm\"\n            end\n            host = host .. \"-\" .. (get_config(\"target_os\") or \"linux\")\n            table.insert(configs, \"--host=\" .. host)\n        else\n            raise(\"autoconf: unknown platform(%s)!\", config.plat())\n        end\n    end\n    return configs\nend\n\n-- detect build-system and configuration file\nfunction detect()\n    if not is_subhost(\"windows\") then\n        return find_file(\"configure\", os.curdir()) or\n               find_file(\"configure.ac\", os.curdir()) or\n               find_file(\"autogen.sh\", os.curdir())\n    end\nend\n\n-- do clean\nfunction clean()\n    if find_file(\"[mM]akefile\", os.curdir()) then\n        if option.get(\"all\") then\n            os.vexec(\"make distclean\")\n            os.tryrm(_get_artifacts_dir())\n        else\n            os.vexec(\"make clean\")\n        end\n    end\nend\n\n-- do build\nfunction build()\n\n    -- get artifacts directory\n    local artifacts_dir = _get_artifacts_dir()\n    if not os.isdir(artifacts_dir) then\n        os.mkdir(artifacts_dir)\n    end\n\n    -- generate configure\n    if not os.isfile(\"configure\") then\n        if os.isfile(\"autogen.sh\") then\n            os.vexecv(\"./autogen.sh\", {}, {shell = true})\n        elseif os.isfile(\"configure.ac\") or os.isfile(\"configure.in\") then\n            local autoreconf = find_tool(\"autoreconf\")\n            assert(autoreconf, \"autoreconf not found!\")\n            os.vexecv(autoreconf.program, {\"--install\", \"--symlink\"}, {shell = true})\n        end\n    end\n\n    -- do configure\n    local configfile = find_file(\"[mM]akefile\", os.curdir())\n    if not configfile or os.mtime(config.filepath()) > os.mtime(configfile) then\n        os.vexecv(\"./configure\", _get_configs(artifacts_dir), {shell = true, envs = _get_buildenvs()})\n    end\n\n    -- do build\n    local argv = {\"-j\" .. option.get(\"jobs\")}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"V=1\")\n    end\n    if is_host(\"bsd\") then\n        os.vexecv(\"gmake\", argv)\n        os.vexec(\"gmake install\")\n    else\n        os.vexecv(\"make\", argv)\n        os.vexec(\"make install\")\n    end\n    cprint(\"output to ${bright}%s\", artifacts_dir)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/bazel.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bazel.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"BUILD\", os.curdir()) or find_file(\"BUILD.bazel\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    local bazel = assert(find_tool(\"bazel\"), \"bazel not found!\")\n    os.vexecv(bazel.program, {\"clean\"})\nend\n\n-- do build\nfunction build()\n\n    -- only support the current subsystem host platform now!\n    assert(is_subhost(config.plat()), \"bazel: %s not supported!\", config.plat())\n\n    -- do build\n    local bazel = assert(find_tool(\"bazel\"), \"bazel not found!\")\n    os.vexecv(bazel.program, {\"build\"})\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/cmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cmake.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- get build directory\nfunction _get_builddir()\n    return config.builddir() or \"build\"\nend\n\n-- get artifacts directory\nfunction _get_artifacts_dir()\n    return path.absolute(path.join(_get_builddir(), \"artifacts\"))\nend\n\n-- get the build environment\nfunction _get_buildenv(key)\n    local value = config.get(key)\n    if value == nil then\n        value = platform.toolconfig(key, config.plat())\n    end\n    if value == nil then\n        value = platform.tool(key, config.plat())\n    end\n    return value\nend\n\n-- get vs arch\nfunction _get_vsarch()\n    local arch = get_config(\"arch\") or os.arch()\n    if arch == \"x86\" or arch == \"i386\" then return \"Win32\" end\n    if arch == \"x86_64\" then return \"x64\" end\n    if arch == \"arm64ec\" then return \"ARM64EC\" end\n    if arch:startswith(\"arm64\") then return \"ARM64\" end\n    if arch:startswith(\"arm\") then return \"ARM\" end\n    return arch\nend\n\n-- get msvc\nfunction _get_msvc()\n    local msvc = toolchain.load(\"msvc\")\n    assert(msvc:check(), \"vs not found!\") -- we need to check vs envs if it has been not checked yet\n    return msvc\nend\n\n-- get msvc run environments\nfunction _get_msvc_runenvs()\n    return os.joinenvs(_get_msvc():runenvs())\nend\n\n-- translate paths\nfunction _translate_paths(paths)\n    if is_host(\"windows\") then\n        if type(paths) == \"string\" then\n            return (paths:gsub(\"\\\\\", \"/\"))\n        elseif type(paths) == \"table\" then\n            local result = {}\n            for _, p in ipairs(paths) do\n                table.insert(result, (p:gsub(\"\\\\\", \"/\")))\n            end\n            return result\n        end\n    end\n    return paths\nend\n\n-- translate bin path\nfunction _translate_bin_path(bin_path)\n    if is_host(\"windows\") and bin_path then\n        bin_path = bin_path:gsub(\"\\\\\", \"/\")\n        if not bin_path:find(string.ipattern(\"%.exe$\")) and\n           not bin_path:find(string.ipattern(\"%.cmd$\")) and\n           not bin_path:find(string.ipattern(\"%.bat$\")) then\n            bin_path = bin_path .. \".exe\"\n        end\n    end\n    return bin_path\nend\n\n-- is cross compilation?\nfunction _is_cross_compilation()\n    if not is_plat(os.subhost()) then\n        return true\n    end\n    if is_plat(\"macosx\") and not is_arch(os.subarch()) then\n        return true\n    end\n    return false\nend\n\nfunction _get_cmake_system_processor()\n    -- on Windows, CMAKE_SYSTEM_PROCESSOR comes from PROCESSOR_ARCHITECTURE\n    -- on other systems it's the output of uname -m\n    if is_plat(\"windows\") then\n        local archs = {\n            x86 = \"x86\",\n            x64 = \"AMD64\",\n            x86_64 = \"AMD64\",\n            arm = \"ARM\",\n            arm64 = \"ARM64\",\n            arm64ec = \"ARM64EC\"\n        }\n        return archs[os.subarch()] or os.subarch()\n    end\n    return os.subarch()\nend\n\n-- insert configs from envs\nfunction _insert_configs_from_envs(configs, envs, opt)\n    opt = opt or {}\n    for k, v in pairs(envs) do\n        table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n    end\nend\n\n-- get configs for windows\nfunction _get_configs_for_windows(configs, opt)\n    local envs = {}\n    opt = opt or {}\n    local cmake_generator = opt.cmake_generator\n    if not cmake_generator or cmake_generator:find(\"Visual Studio\", 1, true) then\n        table.insert(configs, \"-A\")\n        if is_arch(\"x86\", \"i386\") then\n            table.insert(configs, \"Win32\")\n        elseif is_arch(\"arm64\") then\n            table.insert(configs, \"ARM64\")\n        elseif is_arch(\"arm64ec\") then\n            table.insert(configs, \"ARM64EC\")\n        elseif is_arch(\"arm.*\") then\n            table.insert(configs, \"ARM\")\n        else\n            table.insert(configs, \"x64\")\n        end\n\n        local vs_toolset = config.get(\"vs_toolset\")\n        if vs_toolset then\n            vs_toolset = toolchain_utils.get_vs_toolset_ver(vs_toolset)\n            if vs_toolset then\n                envs.CMAKE_GENERATOR_TOOLSET = vs_toolset\n            end\n        end\n    end\n\n    -- use clang/clang-cl\n    local cc = _get_buildenv(\"cc\")\n    if cc and path.basename(cc):find(\"clang\", 1, true) then\n        envs.CMAKE_C_COMPILER = _translate_bin_path(cc)\n    end\n    local cxx = _get_buildenv(\"cxx\")\n    if cxx and path.basename(cxx):find(\"clang\", 1, true) then\n        envs.CMAKE_CXX_COMPILER = _translate_bin_path(cxx)\n    end\n\n    _insert_configs_from_envs(configs, envs, opt)\nend\n\n-- get configs for android\nfunction _get_configs_for_android(configs)\n    -- https://developer.android.google.cn/ndk/guides/cmake\n    local ndk = config.get(\"ndk\")\n    if ndk and os.isdir(ndk) then\n        local arch = config.arch()\n        local ndk_sdkver = config.get(\"ndk_sdkver\")\n        local ndk_cxxstl = config.get(\"ndk_cxxstl\")\n        table.insert(configs, \"-DCMAKE_TOOLCHAIN_FILE=\" .. path.join(ndk, \"build/cmake/android.toolchain.cmake\"))\n        if arch then\n            table.insert(configs, \"-DANDROID_ABI=\" .. arch)\n        end\n        if ndk_sdkver then\n            table.insert(configs,  \"-DANDROID_NATIVE_API_LEVEL=\" .. ndk_sdkver)\n        end\n        if ndk_cxxstl then\n            table.insert(configs, \"-DANDROID_STL=\" .. ndk_cxxstl)\n        end\n\n        -- avoid find and add system include/library path\n        -- @see https://github.com/xmake-io/xmake/issues/2037\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH\")\n        table.insert(configs, \"-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER\")\n    end\nend\n\n-- get configs for appleos\nfunction _get_configs_for_appleos(configs)\n    local envs                     = {}\n    local cflags                   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n    local cxxflags                 = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n    envs.CMAKE_C_FLAGS             = table.concat(cflags, ' ')\n    envs.CMAKE_CXX_FLAGS           = table.concat(cxxflags, ' ')\n    envs.CMAKE_ASM_FLAGS           = table.concat(table.wrap(_get_buildenv(\"asflags\")), ' ')\n    envs.CMAKE_STATIC_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"arflags\")), ' ')\n    envs.CMAKE_EXE_LINKER_FLAGS    = table.concat(table.wrap(_get_buildenv(\"ldflags\")), ' ')\n    envs.CMAKE_SHARED_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"shflags\")), ' ')\n    -- https://cmake.org/cmake/help/v3.17/manual/cmake-toolchains.7.html#id25\n    if is_plat(\"watchos\") then\n        envs.CMAKE_SYSTEM_NAME = \"watchOS\"\n        if is_arch(\"x86_64\", \"i386\") then\n            envs.CMAKE_OSX_SYSROOT = \"watchsimulator\"\n        end\n    elseif is_plat(\"iphoneos\") then\n        envs.CMAKE_SYSTEM_NAME = \"iOS\"\n        if is_arch(\"x86_64\", \"i386\") then\n            envs.CMAKE_OSX_SYSROOT = \"iphonesimulator\"\n        end\n    elseif _is_cross_compilation() then\n        envs.CMAKE_SYSTEM_NAME = \"Darwin\"\n        envs.CMAKE_SYSTEM_PROCESSOR = _get_cmake_system_processor()\n    end\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY   = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE   = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_FRAMEWORK = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM   = \"NEVER\"\n    -- avoid install bundle targets\n    envs.CMAKE_MACOSX_BUNDLE       = \"NO\"\n    for k, v in pairs(envs) do\n        table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n    end\nend\n\n-- get configs for mingw\nfunction _get_configs_for_mingw(configs)\n    local envs                     = {}\n    local cflags                   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n    local cxxflags                 = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n    local sdkdir                   = _get_buildenv(\"mingw\") or _get_buildenv(\"sdk\")\n    envs.CMAKE_C_COMPILER          = _get_buildenv(\"cc\")\n    envs.CMAKE_CXX_COMPILER        = _get_buildenv(\"cxx\")\n    envs.CMAKE_ASM_COMPILER        = _get_buildenv(\"as\")\n    envs.CMAKE_AR                  = _get_buildenv(\"ar\")\n    envs.CMAKE_LINKER              = _get_buildenv(\"ld\")\n    envs.CMAKE_RANLIB              = _get_buildenv(\"ranlib\")\n    envs.CMAKE_C_FLAGS             = table.concat(cflags, ' ')\n    envs.CMAKE_CXX_FLAGS           = table.concat(cxxflags, ' ')\n    envs.CMAKE_ASM_FLAGS           = table.concat(table.wrap(_get_buildenv(\"asflags\")), ' ')\n    envs.CMAKE_STATIC_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"arflags\")), ' ')\n    envs.CMAKE_EXE_LINKER_FLAGS    = table.concat(table.wrap(_get_buildenv(\"ldflags\")), ' ')\n    envs.CMAKE_SHARED_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"shflags\")), ' ')\n    envs.CMAKE_SYSTEM_NAME         = \"Windows\"\n    envs.CMAKE_SYSTEM_PROCESSOR    = _get_cmake_system_processor()\n    -- avoid find and add system include/library path\n    envs.CMAKE_FIND_ROOT_PATH      = sdkdir\n    envs.CMAKE_SYSROOT             = sdkdir\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = \"NEVER\"\n    -- avoid add -isysroot on macOS\n    envs.CMAKE_OSX_SYSROOT = \"\"\n    -- Avoid cmake to add the flags -search_paths_first and -headerpad_max_install_names on macOS\n    envs.HAVE_FLAG_SEARCH_PATHS_FIRST = \"0\"\n    for k, v in pairs(envs) do\n        table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n    end\nend\n\n-- get configs for wasm\nfunction _get_configs_for_wasm(configs)\n    if config.get(\"toolchain\") == \"wasi\" then\n        _get_configs_for_cross(configs)\n        return\n    end\n    local emsdk = find_emsdk()\n    assert(emsdk and emsdk.emscripten, \"emscripten not found!\")\n    local emscripten_cmakefile = find_file(\"Emscripten.cmake\", path.join(emsdk.emscripten, \"cmake/Modules/Platform\"))\n    assert(emscripten_cmakefile, \"Emscripten.cmake not found!\")\n    table.insert(configs, \"-DCMAKE_TOOLCHAIN_FILE=\" .. emscripten_cmakefile)\n    assert(emscripten_cmakefile, \"Emscripten.cmake not found!\")\n    _get_configs_for_generic(configs)\nend\n\n-- get configs for cross\nfunction _get_configs_for_cross(configs)\n    local envs                     = {}\n    local cflags                   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n    local cxxflags                 = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n    local sdkdir                   = _translate_paths(_get_buildenv(\"sdk\"))\n    envs.CMAKE_C_COMPILER          = _translate_bin_path(_get_buildenv(\"cc\"))\n    envs.CMAKE_CXX_COMPILER        = _translate_bin_path(_get_buildenv(\"cxx\"))\n    envs.CMAKE_ASM_COMPILER        = _translate_bin_path(_get_buildenv(\"as\"))\n    envs.CMAKE_AR                  = _translate_bin_path(_get_buildenv(\"ar\"))\n    -- https://github.com/xmake-io/xmake-repo/pull/1096\n    local cxx = envs.CMAKE_CXX_COMPILER\n    if cxx and (cxx:find(\"clang\", 1, true) or cxx:find(\"gcc\", 1, true)) then\n        local dir = path.directory(cxx)\n        local name = path.filename(cxx)\n        name = name:gsub(\"clang$\", \"clang++\")\n        name = name:gsub(\"clang%-\", \"clang++-\")\n        name = name:gsub(\"gcc$\", \"g++\")\n        name = name:gsub(\"gcc%-\", \"g++-\")\n        envs.CMAKE_CXX_COMPILER = _translate_bin_path(dir and path.join(dir, name) or name)\n    end\n    -- @note The link command line is set in Modules/CMake{C,CXX,Fortran}Information.cmake and defaults to using the compiler, not CMAKE_LINKER,\n    -- so we need to set CMAKE_CXX_LINK_EXECUTABLE to use CMAKE_LINKER as linker.\n    --\n    -- https://github.com/xmake-io/xmake-repo/pull/1039\n    -- https://stackoverflow.com/questions/1867745/cmake-use-a-custom-linker/25274328#25274328\n    envs.CMAKE_LINKER              = _translate_bin_path(_get_buildenv(\"ld\"))\n    local ld = envs.CMAKE_LINKER\n    if ld and (ld:find(\"g++\", 1, true) or ld:find(\"clang++\", 1, true)) then\n        envs.CMAKE_CXX_LINK_EXECUTABLE = \"<CMAKE_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>\"\n    end\n    envs.CMAKE_RANLIB              = _translate_bin_path(_get_buildenv(\"ranlib\"))\n    envs.CMAKE_C_FLAGS             = table.concat(cflags, ' ')\n    envs.CMAKE_CXX_FLAGS           = table.concat(cxxflags, ' ')\n    envs.CMAKE_ASM_FLAGS           = table.concat(table.wrap(_get_buildenv(\"asflags\")), ' ')\n    envs.CMAKE_STATIC_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"arflags\")), ' ')\n    envs.CMAKE_EXE_LINKER_FLAGS    = table.concat(table.wrap(_get_buildenv(\"ldflags\")), ' ')\n    envs.CMAKE_SHARED_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"shflags\")), ' ')\n    envs.CMAKE_SYSTEM_NAME         = \"Linux\"\n    -- avoid find and add system include/library path\n    envs.CMAKE_FIND_ROOT_PATH      = sdkdir\n    envs.CMAKE_SYSROOT             = sdkdir\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = \"BOTH\"\n    envs.CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = \"NEVER\"\n    -- avoid add -isysroot on macOS\n    envs.CMAKE_OSX_SYSROOT = \"\"\n    -- Avoid cmake to add the flags -search_paths_first and -headerpad_max_install_names on macOS\n    envs.HAVE_FLAG_SEARCH_PATHS_FIRST = \"0\"\n    for k, v in pairs(envs) do\n        table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n    end\nend\n\n-- get configs for host toolchain\nfunction _get_configs_for_host_toolchain(configs)\n    local envs                     = {}\n    local cflags                   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n    local cxxflags                 = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n    local sdkdir                   = _translate_paths(_get_buildenv(\"sdk\"))\n    envs.CMAKE_C_COMPILER          = _translate_bin_path(_get_buildenv(\"cc\"))\n    envs.CMAKE_CXX_COMPILER        = _translate_bin_path(_get_buildenv(\"cxx\"))\n    envs.CMAKE_ASM_COMPILER        = _translate_bin_path(_get_buildenv(\"as\"))\n    envs.CMAKE_AR                  = _translate_bin_path(_get_buildenv(\"ar\"))\n    -- https://github.com/xmake-io/xmake-repo/pull/1096\n    local cxx = envs.CMAKE_CXX_COMPILER\n    if cxx and (cxx:find(\"clang\", 1, true) or cxx:find(\"gcc\", 1, true)) then\n        local dir = path.directory(cxx)\n        local name = path.filename(cxx)\n        name = name:gsub(\"clang$\", \"clang++\")\n        name = name:gsub(\"clang%-\", \"clang++-\")\n        name = name:gsub(\"gcc$\", \"g++\")\n        name = name:gsub(\"gcc%-\", \"g++-\")\n        envs.CMAKE_CXX_COMPILER = _translate_bin_path(dir and path.join(dir, name) or name)\n    end\n    -- @note The link command line is set in Modules/CMake{C,CXX,Fortran}Information.cmake and defaults to using the compiler, not CMAKE_LINKER,\n    -- so we need to set CMAKE_CXX_LINK_EXECUTABLE to use CMAKE_LINKER as linker.\n    --\n    -- https://github.com/xmake-io/xmake-repo/pull/1039\n    -- https://stackoverflow.com/questions/1867745/cmake-use-a-custom-linker/25274328#25274328\n    envs.CMAKE_LINKER              = _translate_bin_path(_get_buildenv(\"ld\"))\n    local ld = envs.CMAKE_LINKER\n    if ld and (ld:find(\"g++\", 1, true) or ld:find(\"clang++\", 1, true)) then\n        envs.CMAKE_CXX_LINK_EXECUTABLE = \"<CMAKE_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>\"\n    end\n    envs.CMAKE_RANLIB              = _translate_bin_path(_get_buildenv(\"ranlib\"))\n    envs.CMAKE_C_FLAGS             = table.concat(cflags, ' ')\n    envs.CMAKE_CXX_FLAGS           = table.concat(cxxflags, ' ')\n    envs.CMAKE_ASM_FLAGS           = table.concat(table.wrap(_get_buildenv(\"asflags\")), ' ')\n    envs.CMAKE_STATIC_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"arflags\")), ' ')\n    envs.CMAKE_EXE_LINKER_FLAGS    = table.concat(table.wrap(_get_buildenv(\"ldflags\")), ' ')\n    envs.CMAKE_SHARED_LINKER_FLAGS = table.concat(table.wrap(_get_buildenv(\"shflags\")), ' ')\n    -- we don't need to set it as cross compilation if we just pass toolchain\n    -- https://github.com/xmake-io/xmake/issues/2170\n    if _is_cross_compilation() then\n        envs.CMAKE_SYSTEM_NAME = \"Linux\"\n    end\n    for k, v in pairs(envs) do\n        table.insert(configs, \"-D\" .. k .. \"=\" .. v)\n    end\nend\n\n-- get cmake generator for msvc\nfunction _get_cmake_generator_for_msvc()\n    local vs = _get_msvc():config(\"vs\") or config.get(\"vs\")\n    return \"Visual Studio \" .. toolchain_utils.get_vsver(vs) .. \" \" .. vs\nend\n\n-- get configs for cmake generator\nfunction _get_configs_for_generator(configs, opt)\n    opt     = opt or {}\n    configs = configs or {}\n    local cmake_generator = opt.cmake_generator\n    if cmake_generator then\n        if cmake_generator:find(\"Visual Studio\", 1, true) then\n            cmake_generator = _get_cmake_generator_for_msvc()\n        end\n        table.insert(configs, \"-G\")\n        table.insert(configs, cmake_generator)\n    elseif is_plat(\"mingw\") and is_subhost(\"msys\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MSYS Makefiles\")\n    elseif is_plat(\"mingw\") and is_subhost(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MinGW Makefiles\")\n    elseif is_plat(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, _get_cmake_generator_for_msvc())\n    elseif is_plat(\"wasm\") and is_subhost(\"windows\") then\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"MinGW Makefiles\")\n    else\n        table.insert(configs, \"-G\")\n        table.insert(configs, \"Unix Makefiles\")\n    end\nend\n\n-- get configs for installation\nfunction _get_configs_for_install(configs, opt)\n    -- @see https://cmake.org/cmake/help/v3.14/module/GNUInstallDirs.html\n    -- LIBDIR: object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)\n    --\n    table.insert(configs, \"-DCMAKE_INSTALL_PREFIX=\" .. opt.artifacts_dir)\n    table.insert(configs, \"-DCMAKE_INSTALL_LIBDIR:PATH=lib\")\nend\n\n-- get configs\nfunction _get_configs(opt)\n    local configs = {}\n    _get_configs_for_install(configs, opt)\n    _get_configs_for_generator(configs, opt)\n    if is_plat(\"windows\") then\n        _get_configs_for_windows(configs, opt)\n    elseif is_plat(\"android\") then\n        _get_configs_for_android(configs)\n    elseif is_plat(\"iphoneos\", \"watchos\") or\n        -- for cross-compilation on macOS, @see https://github.com/xmake-io/xmake/issues/2804\n        (is_plat(\"macosx\") and (get_config(\"appledev\") or not is_arch(os.subarch()))) then\n        _get_configs_for_appleos(configs)\n    elseif is_plat(\"mingw\") then\n        _get_configs_for_mingw(configs)\n    elseif is_plat(\"wasm\") then\n        _get_configs_for_wasm(configs)\n    elseif _is_cross_compilation() then\n        _get_configs_for_cross(configs)\n    elseif config.get(\"toolchain\") then\n        -- we still need find system libraries,\n        -- it just pass toolchain environments if the toolchain is compatible with host\n        if toolchain_utils.is_compatible_with_host(config.get(\"toolchain\")) then\n            _get_configs_for_host_toolchain(configs)\n        else\n            _get_configs_for_cross(configs)\n        end\n    end\n\n    -- enable verbose?\n    if option.get(\"verbose\") then\n        table.insert(configs, \"-DCMAKE_VERBOSE_MAKEFILE=ON\")\n    end\n\n    -- add extra user configs\n    local tryconfigs = config.get(\"tryconfigs\")\n    if tryconfigs then\n        for _, item in ipairs(os.argv(tryconfigs)) do\n            table.insert(configs, tostring(item))\n        end\n    end\n\n    -- add build directory\n    table.insert(configs, '..')\n    return configs\nend\n\n-- build for msvc\nfunction _build_for_msvc(opt)\n    local runenvs = _get_msvc_runenvs()\n    local msbuild = find_tool(\"msbuild\", {envs = runenvs})\n    local slnfile = assert(find_file(\"*.sln\", os.curdir()) or find_file(\"*.slnx\", os.curdir()), \"*.sln/slnx file not found!\")\n    os.vexecv(msbuild.program, {slnfile, \"-nologo\", \"-t:Build\", \"-m\",\n        \"-p:Configuration=\" .. (is_mode(\"debug\") and \"Debug\" or \"Release\"),\n        \"-p:Platform=\" .. _get_vsarch()}, {envs = runenvs})\n    local projfile = os.isfile(\"INSTALL.vcxproj\") and \"INSTALL.vcxproj\" or \"INSTALL.vcproj\"\n    if os.isfile(projfile) then\n        os.vexecv(msbuild.program, {projfile, \"/property:configuration=\" .. (is_mode(\"debug\") and \"Debug\" or \"Release\")}, {envs = runenvs})\n    end\nend\n\n-- build for make\nfunction _build_for_make(opt)\n    local argv = {\"-j\" .. option.get(\"jobs\")}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    if is_host(\"bsd\") then\n        os.vexecv(\"gmake\", argv)\n        os.vexecv(\"gmake\", {\"install\"})\n    else\n        os.vexecv(\"make\", argv)\n        os.vexecv(\"make\", {\"install\"})\n    end\nend\n\n-- build for ninja\nfunction _build_for_ninja(opt)\n    local njob = option.get(\"jobs\") or tostring(os.default_njob())\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    local argv = {}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"-v\")\n    end\n    table.insert(argv, \"-j\")\n    table.insert(argv, njob)\n    local envs\n    if is_plat(\"windows\") then\n        envs = _get_msvc_runenvs()\n    end\n    os.vexecv(ninja.program, argv, {envs = envs})\nend\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"CMakeLists.txt\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    local builddir = _get_builddir()\n    if os.isdir(builddir) then\n        local configfile = find_file(\"[mM]akefile\", builddir) or (is_plat(\"windows\") and find_file(\"*.sln\", builddir))\n        if configfile then\n            local oldir = os.cd(builddir)\n            if is_plat(\"windows\") then\n                local runenvs = _get_msvc_runenvs()\n                local msbuild = find_tool(\"msbuild\", {envs = runenvs})\n                os.vexecv(msbuild.program, {configfile, \"-nologo\", \"-t:Clean\", \"-p:Configuration=\" .. (is_mode(\"debug\") and \"Debug\" or \"Release\"), \"-p:Platform=\" .. (is_arch(\"x64\") and \"x64\" or \"Win32\")}, {envs = runenvs})\n            else\n                os.vexec(\"make clean\")\n            end\n            os.cd(oldir)\n        end\n    end\nend\n\n-- do build\nfunction build()\n\n    -- get cmake\n    local cmake = assert(find_tool(\"cmake\"), \"cmake not found!\")\n\n    -- get artifacts directory\n    local opt = {}\n    local artifacts_dir = _get_artifacts_dir()\n    if not os.isdir(artifacts_dir) then\n        os.mkdir(artifacts_dir)\n    end\n    os.cd(_get_builddir())\n    opt.artifacts_dir = artifacts_dir\n\n    -- exists $CMAKE_GENERATOR? use it\n    opt.cmake_generator = os.getenv(\"CMAKE_GENERATOR\")\n\n    -- do configure\n    os.vexecv(cmake.program, _get_configs(opt))\n\n    -- do build\n    local cmake_generator = opt.cmake_generator\n    if cmake_generator then\n        if cmake_generator:find(\"Visual Studio\", 1, true) then\n            _build_for_msvc(opt)\n        elseif cmake_generator == \"Ninja\" then\n            _build_for_ninja(opt)\n        elseif cmake_generator:find(\"Makefiles\", 1, true) then\n            _build_for_make(opt)\n        else\n            raise(\"unknown cmake generator(%s)!\", cmake_generator)\n        end\n    else\n        if is_plat(\"windows\") then\n            _build_for_msvc(opt)\n        else\n            _build_for_make(opt)\n        end\n    end\n\n    cprint(\"output to ${bright}%s\", artifacts_dir)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/make.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        make.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"[mM]akefile\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    if is_subhost(\"windows\") then\n        os.vexec(\"nmake clean\")\n    else\n        os.vexec(\"make clean\")\n    end\nend\n\n-- do build\nfunction build()\n    assert(is_subhost(config.plat()), \"make: %s not supported!\", config.plat())\n    local argv = {}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"VERBOSE=1\")\n    end\n    if is_subhost(\"windows\") then\n        os.vexecv(\"nmake\", argv)\n    else\n        table.insert(argv, \"-j\" .. option.get(\"jobs\"))\n        if is_host(\"bsd\") then\n            os.vexecv(\"gmake\", argv)\n        else\n            os.vexecv(\"make\", argv)\n        end\n    end\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/meson.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        meson.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- get build directory\nfunction _get_builddir()\n    return config.builddir() or \"build\"\nend\n\n-- get artifacts directory\nfunction _get_artifacts_dir()\n    return path.absolute(path.join(_get_builddir(), \"artifacts\"))\nend\n\n-- is cross compilation?\nfunction _is_cross_compilation()\n    if not is_plat(os.subhost()) then\n        return true\n    end\n    if is_plat(\"macosx\") and not is_arch(os.subarch()) then\n        return true\n    end\n    return false\nend\n\n-- get pkg-config\nfunction _get_pkgconfig()\n    if is_plat(\"windows\") then\n        local pkgconf = find_tool(\"pkgconf\")\n        if pkgconf then\n            return pkgconf.program\n        end\n    end\n    local pkgconfig = find_tool(\"pkg-config\")\n    if pkgconfig then\n        return pkgconfig.program\n    end\nend\n\n-- get the build environment\nfunction _get_buildenv(key)\n    local value = config.get(key)\n    if value == nil then\n        value = platform.toolconfig(key, config.plat())\n    end\n    if value == nil then\n        value = platform.tool(key, config.plat())\n    end\n    return value\nend\n\n-- get cross file\nfunction _get_cross_file(builddir)\n    local crossfile = path.join(builddir, \"cross_file.txt\")\n    if not os.isfile(crossfile) then\n        local file = io.open(crossfile, \"w\")\n        -- binaries\n        file:print(\"[binaries]\")\n        local cc = _get_buildenv(\"cc\")\n        if cc then\n            -- we need to split it, maybe is `xcrun -sdk iphoneos clang`\n            file:print(\"c=['%s']\", table.concat(os.argv(cc), \"', '\"))\n        end\n        local cxx = _get_buildenv(\"cxx\")\n        if cxx then\n            file:print(\"cpp=['%s']\", table.concat(os.argv(cxx), \"', '\"))\n        end\n        local ld = _get_buildenv(\"ld\")\n        if ld then\n            file:print(\"ld=['%s']\", table.concat(os.argv(ld), \"', '\"))\n        end\n        local ar = _get_buildenv(\"ar\")\n        if ar then\n            file:print(\"ar=['%s']\", table.concat(os.argv(ar), \"', '\"))\n        end\n        local strip = _get_buildenv(\"strip\")\n        if strip then\n            file:print(\"strip='%s'\", strip)\n        end\n        local ranlib = _get_buildenv(\"ranlib\")\n        if ranlib then\n            file:print(\"ranlib='%s'\", ranlib)\n        end\n        if is_plat(\"mingw\") then\n            local mrc = _get_buildenv(\"mrc\")\n            if mrc then\n                file:print(\"windres='%s'\", mrc)\n            end\n        end\n        local cmake = find_tool(\"cmake\")\n        if cmake then\n            file:print(\"cmake='%s'\", cmake.program)\n        end\n        local pkgconfig = _get_pkgconfig()\n        if pkgconfig then\n            file:print(\"pkgconfig='%s'\", pkgconfig)\n        end\n        file:print(\"\")\n\n        -- built-in options\n        file:print(\"[built-in options]\")\n        local cflags   = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cflags\"))\n        local cxxflags = table.join(table.wrap(_get_buildenv(\"cxflags\")), _get_buildenv(\"cxxflags\"))\n        local asflags  = table.wrap(_get_buildenv(\"asflags\"))\n        local arflags  = table.wrap(_get_buildenv(\"arflags\"))\n        local ldflags  = table.wrap(_get_buildenv(\"ldflags\"))\n        local shflags  = table.wrap(_get_buildenv(\"shflags\"))\n        if #cflags > 0 then\n            file:print(\"c_args=['%s']\", table.concat(cflags, \"', '\"))\n        end\n        if #cxxflags > 0 then\n            file:print(\"cpp_args=['%s']\", table.concat(cxxflags, \"', '\"))\n        end\n        local linkflags = table.join(ldflags or {}, shflags)\n        if #linkflags > 0 then\n            file:print(\"c_link_args=['%s']\", table.concat(linkflags, \"', '\"))\n            file:print(\"cpp_link_args=['%s']\", table.concat(linkflags, \"', '\"))\n        end\n        file:print(\"\")\n\n        -- host machine\n        file:print(\"[host_machine]\")\n        if is_plat(\"iphoneos\", \"macosx\") then\n            local cpu\n            local cpu_family\n            if is_arch(\"arm64\") then\n                cpu = \"aarch64\"\n                cpu_family = \"aarch64\"\n            elseif is_arch(\"armv7\") then\n                cpu = \"arm\"\n                cpu_family = \"arm\"\n            elseif is_arch(\"x64\", \"x86_64\") then\n                cpu = \"x86_64\"\n                cpu_family = \"x86_64\"\n            elseif is_arch(\"x86\", \"i386\") then\n                cpu = \"i686\"\n                cpu_family = \"x86\"\n            else\n                raise(\"unsupported arch(%s)\", config.arch())\n            end\n            file:print(\"system = 'darwin'\")\n            file:print(\"cpu_family = '%s'\", cpu_family)\n            file:print(\"cpu = '%s'\", cpu)\n            file:print(\"endian = 'little'\")\n        elseif is_plat(\"android\") then\n            -- TODO\n            raise(\"android has been not supported now!\")\n        elseif is_plat(\"mingw\") then\n            local cpu\n            local cpu_family\n            if is_arch(\"x64\", \"x86_64\") then\n                cpu = \"x86_64\"\n                cpu_family = \"x86_64\"\n            elseif is_arch(\"x86\", \"i386\") then\n                cpu = \"i686\"\n                cpu_family = \"x86\"\n            else\n                raise(\"unsupported arch(%s)\", config.arch())\n            end\n            file:print(\"system = 'windows'\")\n            file:print(\"cpu_family = '%s'\", cpu_family)\n            file:print(\"cpu = '%s'\", cpu)\n            file:print(\"endian = 'little'\")\n        elseif is_plat(\"wasm\") then\n            file:print(\"system = 'emscripten'\")\n            file:print(\"cpu_family = 'wasm32'\")\n            file:print(\"cpu = 'wasm32'\")\n            file:print(\"endian = 'little'\")\n        elseif is_plat(\"cross\") then\n            local cpu = config.arch()\n            if is_arch(\"arm64\") then\n                cpu = \"aarch64\"\n            elseif is_arch(\"arm.*\") then\n                cpu = \"arm\"\n            end\n            local cpu_family = cpu\n            file:print(\"system = '%s'\", get_config(\"target_os\") or \"linux\")\n            file:print(\"cpu_family = '%s'\", cpu_family)\n            file:print(\"cpu = '%s'\", cpu)\n            file:print(\"endian = 'little'\")\n        end\n        file:print(\"\")\n        file:close()\n    end\n    return crossfile\nend\n\n-- get configs\nfunction _get_configs(artifacts_dir, builddir)\n\n    -- add prefix\n    local configs = {\"--prefix=\" .. artifacts_dir}\n    if configfile then\n        table.insert(configs, \"--reconfigure\")\n    end\n\n    -- add extra user configs\n    local tryconfigs = config.get(\"tryconfigs\")\n    if tryconfigs then\n        for _, opt in ipairs(os.argv(tryconfigs)) do\n            table.insert(configs, tostring(opt))\n        end\n    end\n\n    -- add cross file\n    if _is_cross_compilation() then\n        table.insert(configs, \"--cross-file=\" .. _get_cross_file(builddir))\n    end\n\n    -- add build directory\n    table.insert(configs, builddir)\n    return configs\nend\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"meson.build\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    local builddir = _get_builddir()\n    if os.isdir(builddir) then\n        local configfile = find_file(\"build.ninja\", builddir)\n        if configfile then\n            local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n            local ninja_argv = {\"-C\", builddir}\n            if option.get(\"verbose\") or option.get(\"diagnosis\") then\n                table.insert(ninja_argv, \"-v\")\n            end\n            table.insert(ninja_argv, \"-t\")\n            table.insert(ninja_argv, \"clean\")\n            os.vexecv(ninja.program, ninja_argv)\n            if option.get(\"all\") then\n                os.tryrm(builddir)\n            end\n        end\n    end\nend\n\n-- do build\nfunction build()\n\n    -- get artifacts directory\n    local artifacts_dir = _get_artifacts_dir()\n    if not os.isdir(artifacts_dir) then\n        os.mkdir(artifacts_dir)\n    end\n\n    -- generate makefile\n    local builddir = _get_builddir()\n    local meson = assert(find_tool(\"meson\"), \"meson not found!\")\n    local configfile = find_file(\"build.ninja\", builddir)\n    if not configfile or os.mtime(config.filepath()) > os.mtime(configfile) then\n        os.vexecv(meson.program, _get_configs(artifacts_dir, builddir))\n    end\n\n    -- do build\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    local ninja_argv = {\"-C\", builddir}\n    if option.get(\"verbose\") then\n        table.insert(ninja_argv, \"-v\")\n    end\n    table.insert(ninja_argv, \"-j\")\n    table.insert(ninja_argv, option.get(\"jobs\"))\n    os.vexecv(ninja.program, ninja_argv)\n    os.vexecv(ninja.program, table.join(\"install\", ninja_argv))\n    cprint(\"output to ${bright}%s\", artifacts_dir)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/msbuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        msbuild.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- find project file\nfunction _find_projectfile()\n    return find_file(\"*.sln\", os.curdir()) or find_file(\"*.slnx\", os.curdir())\nend\n\n-- detect build-system and configuration file\nfunction detect()\n    if is_subhost(\"windows\") then\n        return _find_projectfile()\n    end\nend\n\n-- do clean\nfunction clean()\n    local projectfile = _find_projectfile()\n    local runenvs = toolchain.load(\"msvc\"):runenvs()\n    local msbuild = find_tool(\"msbuild\", {envs = runenvs})\n    local projectdata = io.readfile(projectfile)\n    if projectdata and projectdata:find(\"Any CPU\", 1, true) then\n        platform = \"Any CPU\"\n    end\n    os.vexecv(msbuild.program, {projectfile, \"-nologo\", \"-t:Clean\", \"-p:Configuration=Release\", \"-p:Platform=\" .. platform}, {envs = runenvs})\nend\n\n-- do build\nfunction build()\n\n    -- only support the current subsystem host platform now!\n    assert(is_subhost(config.plat()), \"msbuild: %s not supported!\", config.plat())\n\n    -- do build\n    local projectfile = _find_projectfile()\n    local runenvs = toolchain.load(\"msvc\"):runenvs()\n    local msbuild = find_tool(\"msbuild\", {envs = runenvs})\n    local platform = is_arch(\"x64\") and \"x64\" or \"Win32\"\n    local projectdata = io.readfile(projectfile)\n    if projectdata and projectdata:find(\"Any CPU\", 1, true) then\n        platform = \"Any CPU\"\n    end\n    os.vexecv(msbuild.program, {projectfile, \"-nologo\", \"-t:Build\", \"-p:Configuration=Release\", \"-p:Platform=\" .. platform}, {envs = runenvs})\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/ndkbuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ndkbuild.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\n\n-- get ndk directory\nfunction _get_ndkdir()\n    local ndk = assert(config.get(\"ndk\"), \"ndkbuild: please uses `xmake f --ndk=` to set the ndk path!\")\n    return path.absolute(ndk)\nend\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"Android.mk\", path.join(os.curdir(), \"jni\"))\nend\n\n-- do clean\nfunction clean()\n\n    -- get the ndk root directory\n    local ndk = _get_ndkdir()\n    assert(os.isdir(ndk), \"%s not found!\", ndk)\n\n    -- do clean\n    os.vexecv(path.join(ndk, \"ndk-build\"), {\"clean\"}, {envs = {NDK_ROOT = ndk}})\nend\n\n-- do build\nfunction build()\n\n    -- only support the android platform now!\n    assert(is_plat(\"android\"), \"ndkbuild: please uses `xmake f -p android --trybuild=ndkbuild` to switch to android platform!\")\n\n    -- get the ndk root directory\n    local ndk = _get_ndkdir()\n    assert(os.isdir(ndk), \"%s not found!\", ndk)\n\n    -- do build\n    local argv = {}\n    if option.get(\"verbose\") then\n        table.insert(argv, \"V=1\")\n    end\n    local ndkbuild = path.join(ndk, \"ndk-build\")\n    if is_host(\"windows\") then\n        ndkbuild = ndkbuild .. \".cmd\"\n    end\n    os.vexecv(ndkbuild, argv, {envs = {NDK_ROOT = ndk}})\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/ninja.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ninja.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"build.ninja\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    local ninja_argv = {\"-C\", os.curdir()}\n    if option.get(\"verbose\") or option.get(\"diagnosis\") then\n        table.insert(ninja_argv, \"-v\")\n    end\n    table.insert(ninja_argv, \"-t\")\n    table.insert(ninja_argv, \"clean\")\n    os.vexecv(ninja.program, ninja_argv)\nend\n\n-- do build\nfunction build()\n    local ninja = assert(find_tool(\"ninja\"), \"ninja not found!\")\n    local ninja_argv = {\"-C\", os.curdir()}\n    if option.get(\"verbose\") then\n        table.insert(ninja_argv, \"-v\")\n    end\n    table.insert(ninja_argv, \"-j\")\n    table.insert(ninja_argv, option.get(\"jobs\"))\n    os.vexecv(ninja.program, ninja_argv)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/scons.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scons.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\n\n-- detect build-system and configuration file\nfunction detect()\n    return find_file(\"SConstruct\", os.curdir())\nend\n\n-- do clean\nfunction clean()\n    local scons = assert(find_tool(\"scons\"), \"scons not found!\")\n    os.vexecv(scons.program, {\"-c\"})\nend\n\n-- do build\nfunction build()\n\n    -- only support the current subsystem host platform now!\n    assert(is_subhost(config.plat()), \"scons: %s not supported!\", config.plat())\n\n    -- do build\n    local scons = assert(find_tool(\"scons\"), \"scons not found!\")\n    os.vexec(scons.program)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/xcodebuild.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xcodebuild.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_directory\")\n\n-- detect build-system and configuration file\nfunction detect()\n    if is_subhost(\"macosx\") then\n        return find_directory(\"*.xcworkspace\", os.curdir()) or find_directory(\"*.xcodeproj\", os.curdir())\n    end\nend\n\n-- do clean\nfunction clean()\n    os.exec(\"xcodebuild clean CODE_SIGN_IDENTITY=\\\"\\\" CODE_SIGNING_REQUIRED=NO\")\nend\n\n-- do build\nfunction build()\n\n    -- only support the current subsystem host platform now!\n    assert(is_subhost(config.plat()), \"xcodebuild: %s not supported!\", config.plat())\n\n    -- do build\n    os.exec(\"xcodebuild build CODE_SIGN_IDENTITY=\\\"\\\" CODE_SIGNING_REQUIRED=NO\")\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/trybuild/xrepo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xrepo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.search_packages\")\n\n-- get build directory\nfunction _get_buildir()\n    return config.builddir() or \"build\"\nend\n\n-- get artifacts directory\nfunction _get_artifacts_dir()\n    return path.absolute(path.join(_get_buildir(), \"artifacts\"))\nend\n\n-- detect build-system and configuration file\nfunction detect()\n\n    -- we need xrepo\n    local xrepo = find_tool(\"xrepo\")\n    if not xrepo then\n        return\n    end\n\n    -- get package name and version\n    local dirname = path.filename(os.curdir())\n    local packagename = dirname\n    local version = semver.match(dirname)\n    if version then\n        local pos = dirname:find(\"v\" .. version:rawstr(), 1, true) or dirname:find(version:rawstr(), 1, true)\n        if pos then\n            packagename = dirname:sub(1, pos - 1)\n            if packagename:endswith(\"-\") or packagename:endswith(\"_\") then\n                packagename = packagename:sub(1, #packagename - 1):lower()\n            end\n        end\n    end\n    packagename = packagename:trim()\n    if #packagename == 0 then\n        return\n    end\n\n    -- search packages\n    local result\n    local packages_found = search_packages(packagename, {description = false, require_version = version and version:rawstr() or nil})\n    for name, packages in pairs(packages_found) do\n        for _, package in ipairs(packages) do\n            if package.name == packagename or packagename:levenshtein(package.name) < 3 then\n                result = package\n                break\n            end\n        end\n    end\n    if result then\n        _g.package = result\n        if result.version then\n            return (\"%s %s in %s\"):format(result.name, result.version, result.reponame)\n        else\n            return (\"%s in %s\"):format(result.name, result.reponame)\n        end\n    end\nend\n\n-- get common configs\nfunction _get_common_configs(argv)\n    table.insert(argv, \"-y\")\n    table.insert(argv, \"--shallow\")\n    table.insert(argv, \"-v\")\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"-D\")\n    end\n    if config.get(\"plat\") then\n        table.insert(argv, \"-p\")\n        table.insert(argv, config.get(\"plat\"))\n    end\n    if config.get(\"arch\") then\n        table.insert(argv, \"-a\")\n        table.insert(argv, config.get(\"arch\"))\n    end\n    if config.get(\"mode\") then\n        table.insert(argv, \"-m\")\n        table.insert(argv, config.get(\"mode\"))\n    end\n    if config.get(\"kind\") then\n        table.insert(argv, \"-k\")\n        table.insert(argv, config.get(\"kind\"))\n    end\n    if config.get(\"toolchain\") then\n        table.insert(argv, \"--toolchain=\" .. config.get(\"toolchain\"))\n    end\n    local runtimes = config.get(\"runtimes\") or config.get(\"vs_runtime\")\n    if runtimes then\n        table.insert(argv, \"-f\")\n        table.insert(argv, \"runtimes='\" .. runtimes .. \"'\")\n    end\nend\n\n-- get install configs\nfunction _get_install_configs(argv)\n\n    -- pass jobs\n    if option.get(\"jobs\") then\n        table.insert(argv, \"-j\")\n        table.insert(argv, option.get(\"jobs\"))\n    end\n\n    -- cross compilation\n    if config.get(\"sdk\") then\n        table.insert(argv, \"--sdk=\" .. config.get(\"sdk\"))\n    end\n\n    -- android\n    if config.get(\"ndk\") then\n        table.insert(argv, \"--ndk=\" .. config.get(\"ndk\"))\n    end\n    if option.get(\"ndk_sdkver\") then\n        table.insert(argv, \"--ndk_sdkver=\" .. option.get(\"ndk_sdkver\"))\n    end\n    if option.get(\"android_sdk\") then\n        table.insert(argv, \"--android_sdk=\" .. option.get(\"android_sdk\"))\n    end\n    if option.get(\"build_toolver\") then\n        table.insert(argv, \"--build_toolver=\" .. option.get(\"build_toolver\"))\n    end\n    if option.get(\"ndk_stdcxx\") then\n        table.insert(argv, \"--ndk_stdcxx=\" .. option.get(\"ndk_stdcxx\"))\n    end\n    if option.get(\"ndk_cxxstl\") then\n        table.insert(argv, \"--ndk_cxxstl=\" .. option.get(\"ndk_cxxstl\"))\n    end\n\n    -- mingw\n    if config.get(\"mingw\") then\n        table.insert(argv, \"--mingw=\" .. config.get(\"mingw\"))\n    end\n\n    -- msvc\n    if config.get(\"vs\") then\n        table.insert(argv, \"--vs=\" .. config.get(\"vs\"))\n    end\n    if config.get(\"vs_toolset\") then\n        table.insert(argv, \"--vs_toolset=\" .. config.get(\"vs_toolset\"))\n    end\n    if config.get(\"vs_sdkver\") then\n        table.insert(argv, \"--vs_sdkver=\" .. config.get(\"vs_sdkver\"))\n    end\n\n    -- xcode\n    if config.get(\"xcode\") then\n        table.insert(argv, \"--xcode=\" .. config.get(\"xcode\"))\n    end\n    if config.get(\"xcode_sdkver\") then\n        table.insert(argv, \"--xcode_sdkver=\" .. config.get(\"xcode_sdkver\"))\n    end\n    if config.get(\"target_minver\") then\n        table.insert(argv, \"--target_minver=\" .. config.get(\"target_minver\"))\n    end\n    if config.get(\"appledev\") then\n        table.insert(argv, \"--appledev=\" .. config.get(\"appledev\"))\n    end\nend\n\n-- do clean\nfunction clean()\nend\n\n-- do build\nfunction build()\n\n    -- get xrepo\n    local xrepo = assert(find_tool(\"xrepo\"), \"xrepo not found!\")\n\n    -- get package info\n    local package = assert(_g.package, \"package not found!\")\n\n    -- do install for building\n    local argv = {\"install\"}\n    _get_common_configs(argv)\n    _get_install_configs(argv)\n    table.insert(argv, \"-d\")\n    table.insert(argv, \".\")\n    if package.version then\n        table.insert(argv, package.name .. \" \" .. package.version)\n    else\n        table.insert(argv, package.name)\n    end\n    os.vexecv(xrepo.program, argv)\n\n    -- do export\n    local artifacts_dir = _get_artifacts_dir()\n    local argv = {\"export\"}\n    _get_common_configs(argv)\n    table.insert(argv, \"-o\")\n    table.insert(argv, artifacts_dir)\n    if package.version then\n        table.insert(argv, package.name .. \" \" .. package.version)\n    else\n        table.insert(argv, package.name)\n    end\n    os.vexecv(xrepo.program, argv)\n    cprint(\"output to ${bright}%s\", artifacts_dir)\n    cprint(\"${color.success}build ok!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/action/update/fetch_version.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu, ruki\n-- @file        fetch_version.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"net.http\")\nimport(\"devel.git\")\nimport(\"net.fasturl\")\n\n-- the official git sources for xmake\nlocal official_sources =\n{\n    \"https://github.com/xmake-io/xmake.git\",\n    \"git@github.com:xmake-io/xmake.git\",\n    \"https://gitlab.com/tboox/xmake.git\",\n    \"https://gitcode.com/xmake-io/xmake.git\",\n    \"https://gitee.com/tboox/xmake.git\"\n}\n\n-- get version and url of provided xmakever\nfunction main(xmakever)\n\n    -- init xmakever\n    xmakever = xmakever or \"latest\"\n\n    -- parse url and commit\n    local commitish = nil\n    local custom_url = nil\n    local seg = xmakever:split('#', { plain = true, limit = 2, strict = true })\n    if #seg == 2 then\n        if #seg[1] ~= 0 then\n            custom_url = seg[1]\n        end\n        commitish = seg[2]\n    else\n        if xmakever:find(':', 1, true) then\n            custom_url = xmakever\n        else\n            commitish = xmakever\n        end\n    end\n\n    local urls = nil\n    if custom_url then\n        urls = { git.asgiturl(custom_url) or custom_url }\n        vprint(\"using custom source: %s ..\", urls[1] )\n    else\n        urls = official_sources\n    end\n    commitish = (commitish and #commitish > 0) and commitish or \"latest\"\n\n    -- sort urls\n    if #urls > 1 then\n        fasturl.add(urls)\n        urls = fasturl.sort(urls)\n    end\n\n    -- get version\n    local version = nil\n    local tags, branches\n    for _, url in ipairs(urls) do\n        tags, branches = git.refs(url)\n        if tags or branches then\n            version = semver.select(commitish, tags or {}, tags or {}, branches or {})\n            break\n        end\n    end\n    return {is_official = (urls == official_sources), urls = urls, version = (version or \"master\"), tags = tags, branches = branches}\nend\n\n"
  },
  {
    "path": "xmake/modules/private/action/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get target name and group pattern from option\nfunction get_target_and_group()\n    local targetname\n    local group_pattern = option.get(\"group\")\n    if group_pattern then\n        group_pattern = \"^\" .. path.pattern(group_pattern) .. \"$\"\n    else\n        targetname = option.get(\"target\")\n    end\n    return targetname, group_pattern\nend\n"
  },
  {
    "path": "xmake/modules/private/async/buildjobs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        buildjobs.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\n\n-- build jobs for node dependencies\nfunction _build_jobs_for_nodedeps(nodes, jobs, rootjob, jobrefs, nodeinfo)\n    local targetjob_ref = jobrefs[nodeinfo.name]\n    if targetjob_ref then\n        jobs:add(targetjob_ref, rootjob)\n    else\n        local nodejob = jobs:add(nodeinfo.job, rootjob)\n        if nodejob then\n            jobrefs[nodeinfo.name] = nodejob\n            for _, depname in ipairs(nodeinfo.deps) do\n                local dep = nodes[depname]\n                if dep then\n                    _build_jobs_for_nodedeps(nodes, jobs, nodejob, jobrefs, dep)\n                end\n            end\n        end\n    end\nend\n\n-- build jobs\n--\n-- @param nodes     the node graph dependencies\n-- @param jobs      the jobpool object\n-- @param rootjob   the root job\n--\n-- @code\n--[[\n    nodes[\"node1\"] = {\n        name = \"node1\",\n        deps = {\"node2\", \"node3\"},\n        job = batchjobs:newjob(\"/job/node1\", function(index, total, opt)\n        end)\n    }\n--]]\nfunction main(nodes, jobs, rootjob)\n    local depset = hashset.new()\n    for _, nodeinfo in pairs(nodes) do\n        assert(nodeinfo.job)\n        for _, depname in ipairs(nodeinfo.deps) do\n            depset:insert(depname)\n        end\n    end\n    local nodes_root = {}\n    for _, nodeinfo in pairs(nodes) do\n        if not depset:has(nodeinfo.name) then\n            table.insert(nodes_root, nodeinfo)\n        end\n    end\n    local jobrefs = {}\n    for _, nodeinfo in pairs(nodes_root) do\n        _build_jobs_for_nodedeps(nodes, jobs, rootjob, jobrefs, nodeinfo)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/async/jobpool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        jobpool.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.list\")\nimport(\"core.base.hashset\")\n\n-- define module\nlocal jobpool = jobpool or object {_init = {\"_size\", \"_rootjob\", \"_leafjobs\"}}\n\n-- the job status\nlocal JOB_STATUS_FREE     = 1\nlocal JOB_STATUS_PENDING  = 2\nlocal JOB_STATUS_FINISHED = 3\n\n-- get jobs size\nfunction jobpool:size()\n    return self._size\nend\n\n-- get root job\nfunction jobpool:rootjob()\n    return self._rootjob\nend\n\n-- new run job\n--\n-- e.g.\n-- local job = jobpool:newjob(\"xxx\", function (index, total) end)\n-- jobpool:add(job, rootjob1)\n-- jobpool:add(job, rootjob2)\n-- jobpool:add(job, rootjob3)\n--\nfunction jobpool:newjob(name, run, opt)\n    opt = opt or {}\n    return {name = name, run = run, distcc = opt.distcc, status = JOB_STATUS_FREE}\nend\n\n-- add run job to the given job node\n--\n-- e.g.\n-- local job = jobpool:addjob(\"xxx\", function (index, total) end, {rootjob = rootjob})\n--\n-- @param name      the job name\n-- @param run       the run command/script\n-- @param opt       the options (rootjob, distcc)\n--                  we can support distcc build if distcc is true\n--\nfunction jobpool:addjob(name, run, opt)\n    opt = opt or {}\n    return self:add({name = name, run = run, distcc = opt.distcc, status = JOB_STATUS_FREE}, opt.rootjob)\nend\n\n-- add job to the given job node\n--\n-- @param job       the job\n-- @param rootjob   the root job node (optional)\n--\nfunction jobpool:add(job, rootjob)\n\n    -- add job to the root job\n    rootjob = rootjob or self:rootjob()\n    rootjob._deps = rootjob._deps or hashset.new()\n    rootjob._deps:insert(job)\n\n    -- attach parents node\n    local parents = job._parents\n    if not parents then\n        parents = {}\n        job._parents = parents\n        self._size = self._size + 1 -- @note only update number for new job without parents\n    end\n    table.insert(parents, rootjob)\n\n    -- in group? attach the group node\n    local group = self._group\n    if group then\n        job._deps = job._deps or hashset.new()\n        job._deps:insert(group)\n        group._parents = group._parents or {}\n        table.insert(group._parents, job)\n    end\n    return job\nend\n\n-- get a free job from the leaf jobs\nfunction jobpool:getfree()\n    if self:size() == 0 then\n        return\n    end\n\n    -- get a free job from the leaf jobs\n    local leafjobs = self:_getleafjobs()\n    if not leafjobs:empty() then\n        -- try to get next free job fastly\n        if self._nextfree then\n            local job = self._nextfree\n            local nextfree = leafjobs:prev(job)\n            if nextfree ~= job and self:_isfree(nextfree) then\n                self._nextfree = nextfree\n            else\n                self._nextfree = nil\n            end\n            job.status = JOB_STATUS_PENDING\n            return job\n        end\n        -- find the next free job\n        local removed_jobs = {}\n        for job in leafjobs:ritems() do\n            if self:_isfree(job) then\n                local nextfree = leafjobs:prev(job)\n                if nextfree ~= job and self:_isfree(nextfree) then\n                    self._nextfree = nextfree\n                end\n                job.status = JOB_STATUS_PENDING\n                return job\n            elseif job.group or job.status == JOB_STATUS_FINISHED then\n                table.insert(removed_jobs, job)\n            end\n        end\n        -- not found? if remove group and referenced node exist,\n        -- we try to remove them and find the next free job again\n        if #removed_jobs > 0 then\n            for _, job in ipairs(removed_jobs) do\n                self:remove(job)\n            end\n            for job in leafjobs:ritems() do\n                if self:_isfree(job) then\n                    local nextfree = leafjobs:prev(job)\n                    if nextfree ~= job and self:_isfree(nextfree) then\n                        self._nextfree = nextfree\n                    end\n                    job.status = JOB_STATUS_PENDING\n                    return job\n                end\n            end\n        end\n    end\nend\n\n-- remove the given job from the leaf jobs\nfunction jobpool:remove(job)\n    assert(self:size() > 0)\n    local leafjobs = self:_getleafjobs()\n    if not leafjobs:empty() then\n        assert(job ~= self._nextfree)\n\n        -- remove this job from leaf jobs\n        job.status = JOB_STATUS_FINISHED\n        leafjobs:remove(job)\n\n        -- get parents node\n        local parents = assert(job._parents, \"invalid job without parents node!\")\n\n        -- update all parents nodes\n        for _, p in ipairs(parents) do\n            -- we need to avoid adding it to leafjobs repeatly, it will cause dead-loop when poping group job\n            -- @see https://github.com/xmake-io/xmake/issues/2740\n            if not p._leaf then\n                p._deps:remove(job)\n                if p._deps:empty() and self._size > 0 then\n                    p._leaf = true\n                    leafjobs:insert_first(p)\n                end\n            end\n        end\n    end\nend\n\n-- enter group\n--\n-- @param name      the group name\n-- @param opt       the options, e.g. {rootjob = ..}\n--\nfunction jobpool:group_enter(name, opt)\n    opt = opt or {}\n    assert(not self._group, \"jobpool: cannot enter group(%s)!\", name)\n    self._group = {name = name, group = true, rootjob = opt.rootjob}\nend\n\n-- leave group\n--\n-- @return          the group node\n--\nfunction jobpool:group_leave()\n    local group = self._group\n    self._group = nil\n    if group then\n        if group._parents then\n            return group\n        else\n            -- we just return the rootjob if there is not any jobs in this group\n            return group.rootjob\n        end\n    end\nend\n\n-- is free job?\n-- we need to ignore group node (empty job) and referenced node (finished job)\nfunction jobpool:_isfree(job)\n    if job and job.status == JOB_STATUS_FREE and not job.group then\n        return true\n    end\nend\n\n-- get leaf jobs\nfunction jobpool:_getleafjobs()\n    local leafjobs = self._leafjobs\n    if leafjobs == nil then\n        leafjobs = list.new()\n        local refs = {}\n        self:_genleafjobs(self:rootjob(), leafjobs, refs)\n        self._leafjobs = leafjobs\n    end\n    return leafjobs\nend\n\n-- generate all leaf jobs from the given job\nfunction jobpool:_genleafjobs(job, leafjobs, refs)\n    local deps = job._deps\n    if deps and not deps:empty() then\n        for _, dep in deps:keys() do\n            local depkey = tostring(dep)\n            if not refs[depkey] then\n                refs[depkey] = true\n                self:_genleafjobs(dep, leafjobs, refs)\n            end\n        end\n    else\n        job._leaf = true\n        leafjobs:insert_last(job)\n    end\nend\n\n-- generate jobs tree for the given job\nfunction jobpool:_gentree(job, refs)\n    local tree = {job.group and (\"group(\" .. job.name .. \")\") or job.name}\n    local deps = job._deps\n    if deps and not deps:empty() then\n        for _, dep in deps:keys() do\n            local depkey = tostring(dep)\n            if refs[depkey] then\n                local depname = dep.group and (\"group(\" .. dep.name .. \")\") or dep.name\n                table.insert(tree, \"ref(\" .. depname .. \")\")\n            else\n                refs[depkey] = true\n                table.insert(tree, self:_gentree(dep, refs))\n            end\n        end\n    end\n    -- strip tree\n    local smalltree = hashset.new()\n    for _, item in ipairs(tree) do\n        item = table.unwrap(item)\n        if smalltree:size() < 16 or type(item) == \"table\" then\n            smalltree:insert(item)\n        else\n            smalltree:insert(\"...\")\n        end\n    end\n    return smalltree:to_array()\nend\n\n-- tostring\nfunction jobpool:__tostring()\n    local refs = {}\n    return string.serialize(self:_gentree(self:rootjob(), refs), {indent = 2, orderkeys = true})\nend\n\n-- new a jobpool\nfunction new()\n    return jobpool {0, {name = \"root\"}, nil}\nend\n"
  },
  {
    "path": "xmake/modules/private/async/runjobs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        runjobs.lua\n--\n\n-- imports\nimport(\"async.runjobs\")\n\n-- asynchronous run jobs\nfunction main(name, jobs, opt)\n    runjobs(name, jobs, opt)\n    wprint(\"please use import(\\\"async.runjobs\\\") instead of private.async.runjobs!\")\nend\n"
  },
  {
    "path": "xmake/modules/private/cache/build_cache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_cache.lua\n--\n\n-- imports\nimport(\"core.base.bytes\")\nimport(\"core.base.hashset\")\nimport(\"core.base.global\")\nimport(\"core.cache.memcache\")\nimport(\"core.project.config\")\nimport(\"core.project.policy\")\nimport(\"core.project.project\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\nimport(\"private.service.client_config\")\nimport(\"private.service.remote_cache.client\", {alias = \"remote_cache_client\"})\n\n-- get memcache\nfunction _memcache()\n    local cache = _g.memcache\n    if not cache then\n        cache = memcache.cache(\"build_cache\")\n        _g.memcache = cache\n    end\n    return cache\nend\n\n-- get exist info\nfunction _get_existinfo()\n    local existinfo = _g.existinfo\n    if existinfo == nil then\n        existinfo = remote_cache_client.singleton():existinfo()\n        _g.existinfo = existinfo\n    end\n    return existinfo\nend\n\n-- is enabled?\nfunction is_enabled(target)\n    local key = tostring(target or \"all\")\n    local result = _memcache():get2(\"enabled\", key)\n    if result == nil then\n        -- target may be option instance\n        if result == nil and target and target.policy then\n            result = target:policy(\"build.ccache\")\n        end\n        if result == nil and os.isfile(os.projectfile()) then\n            local policy = project.policy(\"build.ccache\")\n            if policy ~= nil then\n                result = policy\n            end\n        end\n        -- disable ccache on ci\n        if result == nil and ci_is_running() then\n            local action_build_cache = _g._ACTION_BUILD_CACHE\n            if action_build_cache == nil then\n                action_build_cache = os.getenv(\"XMAKE_ACTION_BUILD_CACHE\")\n                _g._ACTION_BUILD_CACHE = action_build_cache or false\n            end\n            -- we cannot disable it if github-action-setup-xmake/build-cache is enabled\n            if not action_build_cache then\n                result = false\n            end\n        end\n        -- disable ccache for msvc, because cl.exe preprocessor is too slower\n        -- @see https://github.com/xmake-io/xmake/issues/3532\n        if result == nil and is_host(\"windows\") and\n            target and target.has_tool and target:has_tool(\"cxx\", \"cl\") then\n            result = false\n        end\n        if result == nil then\n            result = config.get(\"ccache\")\n        end\n        result = result or false\n        _memcache():set2(\"enabled\", key)\n    end\n    return result\nend\n\n-- is supported?\nfunction is_supported(sourcekind)\n    local sourcekinds = _g.sourcekinds\n    if sourcekinds == nil then\n        sourcekinds = hashset.of(\"cc\", \"cxx\", \"mm\", \"mxx\")\n        _g.sourcekinds = sourcekinds\n    end\n    return sourcekinds:has(sourcekind)\nend\n\n-- get cache key\nfunction cachekey(program, cppinfo, envs)\n    local cppfile = cppinfo.cppfile\n    local cppflags = cppinfo.cppflags\n    local items = {program}\n    for _, cppflag in ipairs(cppflags) do\n        if cppflag:startswith(\"-D\") or cppflag:startswith(\"/D\") then\n            -- ignore `-Dxx` to improve the cache hit rate, as some source files may not use the defined macros.\n            -- @see https://github.com/xmake-io/xmake/issues/2425\n        else\n            table.insert(items, cppflag)\n        end\n    end\n    table.insert(items, hash.xxhash128(cppfile))\n    if envs then\n        local basename = path.basename(program)\n        if basename == \"cl\" then\n            for _, name in ipairs({\"WindowsSDKVersion\", \"VCToolsVersion\", \"LIB\"}) do\n                local val = envs[name]\n                if val then\n                    table.insert(items, val)\n                end\n            end\n        end\n    end\n    return hash.strhash128(table.concat(items, \"\"))\nend\n\n-- get cache root directory\nfunction rootdir()\n    local cachedir = _g.cachedir\n    if not cachedir then\n        cachedir = config.get(\"ccachedir\")\n        if not cachedir and project.policy(\"build.ccache.global_storage\") then\n            cachedir = path.join(global.directory(), \".build_cache\")\n        end\n        if not cachedir then\n            cachedir = path.join(config.builddir(), \".build_cache\")\n        end\n        _g.cachedir = path.absolute(cachedir)\n    end\n    return cachedir\nend\n\n-- clean cached files\nfunction clean()\n    os.rm(rootdir())\n    if remote_cache_client.is_connected() then\n        client_config.load()\n        remote_cache_client.singleton():clean()\n    end\nend\n\n-- get hit rate\nfunction hitrate()\n    local cache_hit_count = (_g.cache_hit_count or 0)\n    local total_count = (_g.total_count or 0)\n    if total_count > 0 then\n        return math.floor(cache_hit_count * 100 / total_count)\n    end\n    return 0\nend\n\n-- dump stats\nfunction dump_stats()\n    local total_count = (_g.total_count or 0)\n    local cache_hit_count = (_g.cache_hit_count or 0)\n    local cache_miss_count = total_count - cache_hit_count\n    local newfiles_count = (_g.newfiles_count or 0)\n    local remote_hit_count = (_g.remote_hit_count or 0)\n    local remote_newfiles_count = (_g.remote_newfiles_count or 0)\n    local preprocess_error_count = (_g.preprocess_error_count or 0)\n    local compile_fallback_count = (_g.compile_fallback_count or 0)\n    local compile_total_time = (_g.compile_total_time or 0)\n    local cache_hit_total_time = (_g.cache_hit_total_time or 0)\n    local cache_miss_total_time = (_g.cache_miss_total_time or 0)\n    vprint(\"\")\n    vprint(\"build cache stats:\")\n    vprint(\"cache directory: %s\", rootdir())\n    vprint(\"cache hit rate: %d%%\", hitrate())\n    vprint(\"cache hit: %d\", cache_hit_count)\n    vprint(\"cache hit total time: %0.3fs\", cache_hit_total_time / 1000.0)\n    vprint(\"cache miss: %d\", cache_miss_count)\n    vprint(\"cache miss total time: %0.3fs\", cache_miss_total_time / 1000.0)\n    vprint(\"new cached files: %d\", newfiles_count)\n    vprint(\"remote cache hit: %d\", remote_hit_count)\n    vprint(\"remote new cached files: %d\", remote_newfiles_count)\n    vprint(\"preprocess failed: %d\", preprocess_error_count)\n    vprint(\"compile fallback count: %d\", compile_fallback_count)\n    vprint(\"compile total time: %0.3fs\", compile_total_time / 1000.0)\n    vprint(\"\")\nend\n\n-- get object file\nfunction get(cachekey)\n    _g.total_count = (_g.total_count or 0) + 1\n    local objectfile_cached = path.join(rootdir(), cachekey:sub(1, 2):lower(), cachekey)\n    local objectfile_infofile = objectfile_cached .. \".txt\"\n    if os.isfile(objectfile_cached) then\n        _g.cache_hit_count = (_g.cache_hit_count or 0) + 1\n        return objectfile_cached, objectfile_infofile\n    elseif remote_cache_client.is_connected() then\n        return try\n        {\n            function ()\n                if not remote_cache_client.singleton():unreachable() then\n                    local exists, extrainfo = remote_cache_client.singleton():pull(cachekey, objectfile_cached)\n                    if exists and os.isfile(objectfile_cached) then\n                        _g.cache_hit_count = (_g.cache_hit_count or 0) + 1\n                        _g.remote_hit_count = (_g.remote_hit_count or 0) + 1\n                        if extrainfo then\n                            io.save(objectfile_infofile, extrainfo)\n                        end\n                        return objectfile_cached, objectfile_infofile\n                    end\n                end\n            end,\n            catch\n            {\n                function (errors)\n                    if errors and policy.build_warnings() then\n                        cprint(\"${color.warning}fallback to the local cache, %s\", tostring(errors))\n                    end\n                end\n            }\n        }\n    end\nend\n\n-- put object file\nfunction put(cachekey, objectfile, extrainfo)\n    local objectfile_cached = path.join(rootdir(), cachekey:sub(1, 2):lower(), cachekey)\n    local objectfile_infofile = objectfile_cached .. \".txt\"\n    os.cp(objectfile, objectfile_cached)\n    if extrainfo then\n        io.save(objectfile_infofile, extrainfo)\n    end\n    _g.newfiles_count = (_g.newfiles_count or 0) + 1\n    if remote_cache_client.is_connected() then\n        try\n        {\n            function ()\n                if not remote_cache_client.singleton():unreachable() then\n                    -- this file does not exist in remote server? push it to server\n                    --\n                    -- we use the bloom filter to approximate whether it exists or not,\n                    -- which may result in a few less files being uploaded, but that's fine.\n                    local existinfo = _get_existinfo()\n                    if not existinfo or not existinfo:get(cachekey) then\n                        -- existinfo is just an initial snapshot, we need to go further and determine if the current file exists\n                        local cacheinfo = remote_cache_client.singleton():cacheinfo(cachekey)\n                        if not cacheinfo or not cacheinfo.exists then\n                            _g.remote_newfiles_count = (_g.remote_newfiles_count or 0) + 1\n                            remote_cache_client.singleton():push(cachekey, objectfile, extrainfo)\n                        end\n                    end\n                end\n            end,\n            catch\n            {\n                function (errors)\n                    if errors and policy.build_warnings() then\n                        cprint(\"${color.warning}fallback to the local cache, %s\", tostring(errors))\n                    end\n                end\n            }\n        }\n    end\nend\n\n-- build with cache\nfunction build(program, argv, opt)\n\n    -- do preprocess\n    opt = opt or {}\n    local preprocess = assert(opt.preprocess, \"preprocessor not found!\")\n    local compile = assert(opt.compile, \"compiler not found!\")\n    local cppinfo = preprocess(program, argv, opt)\n    if cppinfo then\n        local cachekey = cachekey(program, cppinfo, opt.envs)\n        local cache_hit_start_time = os.mclock()\n        local objectfile_cached, objectfile_infofile = get(cachekey)\n        if objectfile_cached then\n            os.cp(objectfile_cached, cppinfo.objectfile)\n            -- we need to update mtime for incremental compilation\n            -- @see https://github.com/xmake-io/xmake/issues/2620\n            os.touch(cppinfo.objectfile, {mtime = os.time()})\n            -- we need to get outdata/errdata to show warnings,\n            -- @see https://github.com/xmake-io/xmake/issues/2452\n            if objectfile_infofile and os.isfile(objectfile_infofile) then\n                local extrainfo = io.load(objectfile_infofile)\n                cppinfo.outdata = extrainfo.outdata\n                cppinfo.errdata = extrainfo.errdata\n            end\n            _g.cache_hit_total_time = (_g.cache_hit_total_time or 0) + (os.mclock() - cache_hit_start_time)\n        else\n            -- do compile\n            local preprocess_outdata = cppinfo.outdata\n            local preprocess_errdata = cppinfo.errdata\n            local compile_start_time = os.mclock()\n            local compile_fallback = opt.compile_fallback\n            if compile_fallback then\n                local ok = try {function () compile(program, cppinfo, opt); return true end}\n                if not ok then\n                    -- we fallback to compile original source file if compiling preprocessed file fails.\n                    -- https://github.com/xmake-io/xmake/issues/2467\n                    local outdata, errdata = compile_fallback()\n                    cppinfo.outdata = outdata\n                    cppinfo.errdata = errdata\n                    _g.compile_fallback_count = (_g.compile_fallback_count or 0) + 1\n                end\n            else\n                compile(program, cppinfo, opt)\n            end\n            -- if no compiler output, we need use preprocessor output, because it maybe contains warning output\n            if not cppinfo.outdata or #cppinfo.outdata == 0 then\n                cppinfo.outdata = preprocess_outdata\n            end\n            if not cppinfo.errdata or #cppinfo.errdata == 0 then\n                cppinfo.errdata = preprocess_errdata\n            end\n            _g.compile_total_time = (_g.compile_total_time or 0) + (os.mclock() - compile_start_time)\n            if cachekey then\n                local extrainfo\n                if cppinfo.outdata and #cppinfo.outdata ~= 0 then\n                    extrainfo = extrainfo or {}\n                    extrainfo.outdata = cppinfo.outdata\n                end\n                if cppinfo.errdata and #cppinfo.errdata ~= 0 then\n                    extrainfo = extrainfo or {}\n                    extrainfo.errdata = cppinfo.errdata\n                end\n                local cache_miss_start_time = os.mclock()\n                put(cachekey, cppinfo.objectfile, extrainfo)\n                _g.cache_miss_total_time = (_g.cache_miss_total_time or 0) + (os.mclock() - cache_miss_start_time)\n            end\n        end\n        os.tryrm(cppinfo.cppfile)\n    else\n        _g.preprocess_error_count = (_g.preprocess_error_count or 0) + 1\n    end\n    return cppinfo\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checker.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        checker.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get all checkers\nfunction checkers()\n    local checkers = _g._CHECKERS\n    if not checkers then\n        checkers = {\n            -- package api checkers\n            [\"api.package.kind\"]         = {description = \"Check kind configuration in package.\", load = true},\n            [\"api.package.versionfiles\"] = {description = \"Check versionfiles configuration in package.\", download_failure = true},\n            -- target api checkers\n            [\"api.target.version\"]       = {description = \"Check version configuration in target.\"},\n            [\"api.target.kind\"]          = {description = \"Check kind configuration in target.\", build = true},\n            [\"api.target.strip\"]         = {description = \"Check strip configuration in target.\", build = true},\n            [\"api.target.optimize\"]      = {description = \"Check optimize configuration in target.\", build = true},\n            [\"api.target.symbols\"]       = {description = \"Check symbols configuration in target.\", build = true},\n            [\"api.target.fpmodels\"]      = {description = \"Check fpmodels configuration in target.\", build = true},\n            [\"api.target.warnings\"]      = {description = \"Check warnings configuration in target.\", build = true},\n            [\"api.target.languages\"]     = {description = \"Check languages configuration in target.\", build = true},\n            [\"api.target.vectorexts\"]    = {description = \"Check vectorexts configuration in target.\", build = true},\n            [\"api.target.exceptions\"]    = {description = \"Check exceptions configuration in target.\", build = true},\n            [\"api.target.encodings\"]     = {description = \"Check encodings configuration in target.\", build = true},\n            [\"api.target.packages\"]      = {description = \"Check packages configuration in target.\"},\n            [\"api.target.files\"]         = {description = \"Check files configuration in target.\"},\n            [\"api.target.headerfiles\"]   = {description = \"Check header files configuration in target.\"},\n            [\"api.target.installfiles\"]  = {description = \"Check install files configuration in target.\"},\n            [\"api.target.configfiles\"]   = {description = \"Check config files configuration in target.\"},\n            [\"api.target.linkdirs\"]      = {description = \"Check linkdirs configuration in target.\", build = true},\n            [\"api.target.includedirs\"]   = {description = \"Check includedirs configuration in target.\", build = true},\n            [\"api.target.frameworkdirs\"] = {description = \"Check frameworkdirs configuration in target.\", build = true},\n            [\"api.target.cflags\"]        = {description = \"Check c compiler flags configuration in target.\"},\n            [\"api.target.cxflags\"]       = {description = \"Check c/c++ compiler flags configuration in target.\"},\n            [\"api.target.cxxflags\"]      = {description = \"Check c++ compiler flags configuration in target.\"},\n            [\"api.target.asflags\"]       = {description = \"Check assembler flags configuration in target.\"},\n            [\"api.target.ldflags\"]       = {description = \"Check binary linker flags configuration in target.\"},\n            [\"api.target.shflags\"]       = {description = \"Check shared library linker flags configuration in target.\"},\n            [\"api.target.license\"]       = {description = \"Check license in target and packages.\", build = true},\n            -- cuda checkers\n            [\"cuda.devlink\"]             = {description = \"Check devlink for targets.\", build_failure = true},\n            -- clang tidy checker\n            [\"clang.tidy\"]               = {description = \"Check project code using clang-tidy.\", showstats = false},\n            -- syntax checker\n            [\"syntax\"]                   = {description = \"Check the project sourcecode syntax without linking.\", showstats = false}\n        }\n        _g._CHECKERS = checkers\n    end\n    return checkers\nend\n\n-- complete checkers\nfunction complete(complete, opt)\n    return try\n    {\n        function ()\n            local list = {}\n            local groupstats = {}\n            for name, _ in table.orderpairs(checkers()) do\n                local groupname = name:split(\".\", {plain = true})[1]\n                groupstats[groupname] = (groupstats[groupname] or 0) + 1\n                if not complete then\n                    local limit = 16\n                    if groupstats[groupname] < limit then\n                        table.insert(list, name)\n                    elseif groupstats[groupname] == limit then\n                        table.insert(list, \"...\")\n                    end\n                elseif name:startswith(complete) then\n                    table.insert(list, name)\n                end\n            end\n            return list\n        end\n    }\nend\n\n-- update stats\nfunction update_stats(level, count)\n    local stats = _g.stats\n    if not stats then\n        stats = {}\n        _g.stats = stats\n    end\n    count = count or 1\n    stats[level] = (stats[level] or 0) + count\nend\n\n-- show stats\nfunction show_stats()\n    local stats = _g.stats or {}\n    cprint(\"${bright}%d${clear} notes, ${color.warning}%d${clear} warnings, ${color.error}%d${clear} errors\", stats.note or 0, stats.warning or 0, stats.error or 0)\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/api_checker.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        api_checker.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.package.package\")\nimport(\"core.project.project\")\nimport(\"private.check.checker\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\nfunction _get_project_packages()\n    local project_packages = _g.project_packages\n    if not project_packages then\n        project_packages = {}\n        for name, _ in pairs(project.required_packages()) do\n            local pkg, errors = package.load_from_project(name)\n            if pkg then\n                table.insert(project_packages, pkg)\n            elseif errors then\n                raise(errors)\n            end\n        end\n        _g.project_packages = project_packages\n    end\n    return project_packages\nend\n\n-- get the most probable value\nfunction _get_most_probable_value(value, valueset)\n    local result\n    local mindist\n    for v in valueset:keys() do\n        local dist = value:levenshtein(v)\n        if not mindist or dist < mindist then\n            mindist = dist\n            result = v\n        end\n    end\n    return result\nend\n\nfunction _do_show(str, opt)\n    _g.showed = _g.showed or {}\n    local showed = _g.showed\n    local infostr\n    if str then\n        infostr = string.format(\"%s: %s: %s\", opt.sourcetips, opt.level_tips, str)\n    else\n        infostr = string.format(\"%s: %s: unknown %s value '%s'\", opt.sourcetips, opt.level_tips, opt.apiname, opt.value)\n    end\n    if opt.probable_value then\n        infostr = string.format(\"%s, it may be '%s'\", infostr, opt.probable_value)\n    end\n    if not showed[infostr] then\n        cprint(infostr)\n        showed[infostr] = true\n        return true\n    end\nend\n\n-- show result\nfunction _show(apiname, value, instance, opt)\n    opt = opt or {}\n\n    -- match level? verbose: note/warning/error, default: warning/error\n    local level = opt.level\n    if not option.get(\"verbose\") and level == \"note\" then\n        return\n    end\n\n    -- get source information\n    local sourceinfo = instance:sourceinfo(apiname, value) or {}\n    local sourcetips = sourceinfo.file or \"\"\n    if sourceinfo.line then\n        sourcetips = sourcetips .. \":\" .. (sourceinfo.line or -1)\n    end\n    if #sourcetips == 0 then\n        sourcetips = string.format(\"%s(%s)\", instance:type(), instance:name())\n    end\n\n    -- get level tips\n    local level_tips = \"note\"\n    if level == \"warning\" then\n        level_tips = \"${color.warning}${text.warning}${clear}\"\n    elseif level == \"error\" then\n        level_tips = \"${color.error}${text.error}${clear}\"\n    end\n\n    -- get probable value\n    local probable_value\n    if opt.valueset then\n        probable_value = _get_most_probable_value(value, opt.valueset)\n    end\n\n    if apiname:endswith(\"s\") then\n        apiname = apiname:sub(1, #apiname - 1)\n    end\n\n    -- do show\n    return (opt.show or _do_show)(opt.showstr, {\n        apiname = apiname,\n        sourcetips = sourcetips,\n        level_tips = level_tips,\n        value = value,\n        probable_value = probable_value})\nend\n\n-- check instance\nfunction _check_instance(instance, apiname, valueset, level, opt)\n    local instance_valueset = valueset\n    if type(opt.values) == \"function\" then\n        local instance_values = opt.values(instance)\n        if instance_values then\n            instance_valueset = hashset.from(instance_values)\n        end\n    end\n    local values = instance:get(apiname)\n    for _, value in ipairs(values) do\n        if opt.check then\n            local ok, errors = opt.check(instance, value)\n            if not ok then\n                local reported = _show(apiname, value, instance, {\n                    show = opt.show,\n                    showstr = errors,\n                    level = level})\n                if reported then\n                    checker.update_stats(level)\n                end\n            end\n        elseif not instance_valueset:has(value) then\n            local reported = _show(apiname, value, instance, {\n                show = opt.show,\n                valueset = instance_valueset,\n                level = level})\n            if reported then\n                checker.update_stats(level)\n            end\n        end\n    end\nend\n\n-- check api configuration in instances\nfunction _check_instances(apiname, instance, instances_func, opt)\n    local level = opt.level or \"warning\"\n    local valueset\n    if opt.values and type(opt.values) ~= \"function\" then\n        valueset = hashset.from(opt.values)\n    else\n        valueset = hashset.new()\n    end\n    if instance then\n        _check_instance(instance, apiname, valueset, level, opt)\n    else\n        for _, instance in pairs(instances_func()) do\n            _check_instance(instance, apiname, valueset, level, opt)\n        end\n    end\nend\n\n-- check flag\n-- @see https://github.com/xmake-io/xmake/issues/3594\nfunction check_flag(target, toolinst, flagkind, flag)\n    local extraconf = target:extraconf(flagkind)\n    flag = target_utils.flag_belong_to_tool(flag, toolinst, extraconf)\n    if flag then\n        extraconf = extraconf and extraconf[flag]\n        if not extraconf or not extraconf.force then\n            return toolinst:has_flags(flag)\n        end\n    end\n    return true\nend\n\n-- check api configuration in targets\nfunction check_targets(apiname, opt)\n    opt = opt or {}\n    _check_instances(apiname, opt.target, project.targets, opt)\nend\n\n-- check api configuration in packages\nfunction check_packages(apiname, opt)\n    opt = opt or {}\n    _check_instances(apiname, opt.package, _get_project_packages, opt)\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/package/kind.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        kind.lua\n--\n\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_packages(\"kind\", table.join(opt, {check = function(package, value)\n        if value == \"library\" then\n            local extraconf = package:extraconf(\"kind\", \"library\")\n            if extraconf then\n                if extraconf.headeronly and extraconf.moduleonly then\n                    return false, \"a library package cannot be set as both 'headeronly' and 'moduleonly'\"\n                end\n                for key, _ in pairs(extraconf) do\n                    if key ~= \"headeronly\" and key ~= \"moduleonly\" then\n                        return false, string.format(\"unknown kind configuration '%s'\", key)\n                    end\n                end\n            end\n            return true\n        end\n        return value == \"binary\" or value == \"toolchain\" or value == \"template\"\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/package/versionfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        versionfiles.lua\n--\n\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_packages(\"versionfiles\", table.join(opt, {check = function(package, value)\n        local versionfile_path = value\n        if not path.is_absolute(versionfile_path) then\n            local subpath = versionfile_path\n            versionfile_path = path.join(package:scriptdir(), subpath)\n            if not os.isfile(versionfile_path) and package:base() then\n                versionfile_path = path.join(package:base():scriptdir(), subpath)\n            end\n        end\n        if not os.isfile(versionfile_path) then\n            return false, string.format(\"versionfile '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/asflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        asflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"asflags\", table.join(opt, {check = function(target, value)\n        local compinst = target:compiler(\"as\")\n        if not api_checker.check_flag(target, compinst, \"asflags\", value) then\n            return false, string.format(\"%s: unknown assembler flag '%s'\", compinst:name(), value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/cflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"cflags\", table.join(opt, {check = function(target, value)\n        local compinst = target:compiler(\"cc\")\n        if not api_checker.check_flag(target, compinst, \"cflags\", value) then\n            return false, string.format(\"%s: unknown c compiler flag '%s'\", compinst:name(), value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/configfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        configfiles.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"configfiles\", table.join(opt, {check = function(target, value)\n        value = value:gsub(\"[()]\", \"\")\n        local configfiles = os.files(value)\n        if not configfiles or #configfiles == 0 then\n            return false, string.format(\"configfiles '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/cxflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"cxflags\", table.join(opt, {check = function(target, value)\n        local compinst = target:compiler(\"cxx\")\n        if not api_checker.check_flag(target, compinst, \"cxflags\", value) then\n            return false, string.format(\"%s: unknown c/c++ compiler flag '%s'\", compinst:name(), value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/cxxflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cxxflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"cxxflags\", table.join(opt, {check = function(target, value)\n        local compinst = target:compiler(\"cxx\")\n        if not api_checker.check_flag(target, compinst, \"cxxflags\", value) then\n            return false, string.format(\"%s: unknown c++ compiler flag '%s'\", compinst:name(), value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/encodings.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        encodings.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"encodings\", table.join(opt, {values = {\n        \"none\", \"utf-8\", \"source:utf-8\", \"target:utf-8\", \"source:gb2312\", \"target:gb2312\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/exceptions.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        exceptions.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"exceptions\", table.join(opt, {values = {\"none\", \"cxx\", \"objc\", \"no-cxx\", \"no-objc\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        files.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"files\", table.join(opt, {check = function(target, value)\n        local files = os.files(value)\n        if not files or #files == 0 then\n            return false, string.format(\"files '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/fpmodels.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fpmodels.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"fpmodels\", table.join(opt, {values = {\"none\", \"precise\", \"fast\", \"strict\", \"except\", \"noexcept\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/frameworkdirs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        frameworkdirs.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"frameworkdirs\", table.join(opt, {check = function(target, value)\n        if not os.isdir(value) then\n            return false, string.format(\"frameworkdir '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/headerfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        headerfiles.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"headerfiles\", table.join(opt, {check = function(target, value)\n        value = value:gsub(\"[()]\", \"\")\n        local headerfiles = os.files(value)\n        if not headerfiles or #headerfiles == 0 then\n            return false, string.format(\"headerfiles '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/includedirs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        includedirs.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"includedirs\", table.join(opt, {check = function(target, value)\n        if not os.isdir(value) then\n            return false, string.format(\"includedir '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/installfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        installfiles.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"installfiles\", table.join(opt, {check = function(target, value)\n        value = value:gsub(\"[()]\", \"\")\n        local installfiles = os.files(value)\n        if not installfiles or #installfiles == 0 then\n            return false, string.format(\"installfiles '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/kind.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        kind.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"kind\", table.join(opt, {values = {\"object\", \"binary\", \"static\", \"shared\", \"headeronly\", \"moduleonly\", \"phony\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/languages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        languages.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    local values = {\n        \"ansi\", \"c89\", \"c90\", \"c99\", \"c11\", \"c17\", \"c23\", \"clatest\",\n        \"cxx98\", \"cxx03\", \"cxx11\", \"cxx14\", \"cxx17\", \"cxx1z\", \"cxx20\", \"cxx2a\", \"cxx23\", \"cxx2b\", \"cxx2c\", \"cxx26\", \"cxxlatest\"\n    }\n    local languages = {}\n    for _, value in ipairs(values) do\n        table.insert(languages, value)\n        if value:find(\"xx\", 1, true) then\n            table.insert(languages, (value:gsub(\"xx\", \"++\")))\n        end\n        if value:startswith(\"c\") then\n            table.insert(languages, \"gnu\" .. value:sub(2))\n        end\n    end\n    api_checker.check_targets(\"languages\", table.join(opt, {values = languages}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/ldflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ldflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"ldflags\", table.join(opt, {check = function(target, value)\n        if target:is_binary() then\n            local linker = target:linker()\n            if not api_checker.check_flag(target, linker, \"ldflags\", value) then\n                return false, string.format(\"%s: unknown linker flag '%s'\", linker:name(), value)\n            end\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/license.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check_licenses.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.license\")\nimport(\"private.check.checker\")\n\n-- show info\nfunction _show(str)\n    cprint(\"${color.warning}${text.warning}${clear}: %s\", str)\nend\n\n-- check licenses\nfunction _check_licenses_for_package(target, package, opt)\n    opt = opt or {}\n    local target_license  = target:license()\n    local package_license = package:license()\n    local package_kind    = package:has_shared() and \"shared\"\n    local ok, errors = license.compatible(target_license, package_license, {library_kind = package_kind})\n    if not ok then\n        errors = errors or \"you can use set_license()/set_policy() to modify/disable license\"\n        if target_license then\n            errors = string.format(\"license(%s) of target(%s) is not compatible with license(%s) of package(%s)\\n%s!\", target_license, target:name(), package_license, package:name(), errors)\n        else\n            errors = string.format(\"target(%s) maybe is not compatible with license(%s) of package(%s), \\n%s!\", target:name(), package_license, package:name(), errors)\n        end\n        (opt.show or _show)(errors)\n        checker.update_stats(\"warning\")\n    end\nend\n\n-- check licenses for all dependent packages\n--\n-- @see https://github.com/xmake-io/xmake/issues/1016\n--\nfunction _check_licenses_for_target(target, opt)\n    if target:policy(\"check.target_package_licenses\") then\n        for _, pkg in ipairs(target:orderpkgs()) do\n            if pkg:license() then\n                _check_licenses_for_package(target, pkg, opt)\n            end\n        end\n    end\nend\n\nfunction main(opt)\n    opt = opt or {}\n    local target = opt.target\n    if target then\n        _check_licenses_for_target(target, opt)\n    else\n        for _, target in pairs(project.targets()) do\n            _check_licenses_for_target(target, opt)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/linkdirs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        linkdirs.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"linkdirs\", table.join(opt, {check = function(target, value)\n        if not os.isdir(value) then\n            return false, string.format(\"linkdir '%s' not found\", value)\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/optimize.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        optimize.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"optimize\", table.join(opt, {values = {\"none\", \"fast\", \"faster\", \"fastest\", \"smallest\", \"aggressive\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        packages.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    local packages = {}\n    local requires = project.required_packages()\n    if requires then\n        table.join2(packages, table.orderkeys(requires))\n    end\n    api_checker.check_targets(\"packages\", table.join(opt, {values = packages, level = \"note\"}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/shflags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        shflags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"shflags\", table.join(opt, {check = function(target, value)\n        if target:is_shared() then\n            local linker = target:linker()\n            if not api_checker.check_flag(target, linker, \"shflags\", value) then\n                return false, string.format(\"%s: unknown linker flag '%s'\", linker:name(), value)\n            end\n        end\n        return true\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/strip.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        strip.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"strip\", table.join(opt, {values = {\"none\", \"debug\", \"all\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/symbols.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        symbols.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"symbols\", table.join(opt, {values = function (target)\n        local values = {\"none\", \"debug\", \"hidden\", \"hidden_cxx\"}\n        if target:is_plat(\"windows\") and (target:has_tool(\"cc\", \"cl\") or target:has_tool(\"cxx\", \"cl\")) then\n            table.insert(values, \"edit\")\n            table.insert(values, \"embed\")\n        end\n        return values\n    end}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/vectorexts.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vectorexts.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"vectorexts\", table.join(opt, {values = {\n        \"none\", \"all\", \"sse\", \"sse2\", \"sse3\", \"ssse3\", \"sse4.2\", \"avx\", \"avx2\", \"avx512\", \"fma\", \"neon\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/version.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        version.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"version\", table.join(opt, {check = function(target, value)\n        local errors\n        local ok = try {\n            function()\n                semver.new(value)\n                return true\n            end,\n            catch {\n                function (errs)\n                    errors = errs\n                end\n            }\n        }\n        return ok, errors\n    end, level = \"error\"}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/api/target/warnings.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        warnings.lua\n--\n\n-- imports\nimport(\".api_checker\")\n\nfunction main(opt)\n    opt = opt or {}\n    api_checker.check_targets(\"warnings\", table.join(opt, {values = {\n        \"none\", \"less\", \"more\", \"extra\", \"all\", \"allextra\", \"everything\", \"pedantic\", \"error\"}}))\nend\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/clang/tidy.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        tidy.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"lib.detect.find_tool\")\nimport(\"async.runjobs\")\nimport(\"utils.progress\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\n\n-- the clang.tidy options\nlocal options = {\n    {\"l\", \"list\",       \"k\",  nil,  \"Show the clang-tidy checks list.\"},\n    {\"j\", \"jobs\",       \"kv\", tostring(os.default_njob()),\n                                    \"Set the number of parallel check jobs.\"},\n    {\"q\", \"quiet\",      \"k\",  nil,  \"Run clang-tidy in quiet mode.\"},\n    {\"v\", \"verbose\",    \"k\",  nil,  \"Print lots of verbose information for users.\"},\n    {\"D\", \"diagnosis\",  \"k\",  nil,  \"Print lots of diagnosis information (backtrace, check info ..) only for developers.\"},\n    {nil, \"fix\",        \"k\",  nil,  \"Apply suggested fixes.\"},\n    {nil, \"fix_errors\", \"k\",  nil,  \"Apply suggested errors fixes.\"},\n    {nil, \"fix_notes\",  \"k\",  nil,  \"Apply suggested notes fixes.\"},\n    {nil, \"create\",     \"k\",  nil,  \"Create a .clang-tidy file.\"},\n    {nil, \"configfile\", \"kv\", nil,  \"Specify the path of .clang-tidy or custom config file.\"},\n    {nil, \"compdb\",     \"kv\", nil,  \"Specify the path of the compile_commands.json file or the directory containing the file.\"},\n    {nil, \"checks\",     \"kv\", nil,  \"Set the given checks.\",\n                                    \"e.g.\",\n                                    \"    - xmake check clang.tidy --checks=\\\"*\\\"\"},\n    {\"f\", \"files\",      \"kv\", nil,  \"Set files path with pattern\",\n                                    \"e.g.\",\n                                    \"    - xmake check clang.tidy -f src/main.c\",\n                                    \"    - xmake check clang.tidy -f 'src/*.c\" .. path.envsep() .. \"src/**.cpp'\"},\n    {nil, \"targets\",    \"vs\",  nil,  \"Check the sourcefiles of the given target.\",\n                                    \".e.g\",\n                                    \"    - xmake check clang.tidy\",\n                                    \"    - xmake check clang.tidy [targets]\"}\n}\n\n-- show checks list\nfunction _show_list(clang_tidy)\n    os.execv(clang_tidy, {\"--list-checks\"})\nend\n\n-- create .clang-tidy config file\nfunction _create_config(clang_tidy, opt)\n    local projectdir = project.directory()\n    local argv = {\"--dump-config\"}\n    if opt.checks then\n        table.insert(argv, \"--checks=\" .. opt.checks)\n    end\n    os.execv(clang_tidy, argv, {stdout = path.join(projectdir, \".clang-tidy\"), curdir = projectdir})\nend\n\n-- add sourcefiles in target\nfunction _add_target_files(sourcefiles, target)\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        -- we can only use rulename to filter them because sourcekind may be bound to multiple rules\n        local rulename = sourcebatch.rulename\n        if rulename == \"c.build\" or rulename == \"c++.build\"\n            or rulename == \"objc.build\" or rulename == \"objc++.build\"\n            or rulename == \"cuda.build\" or rulename == \"c++.build.modules\" then\n            table.join2(sourcefiles, sourcebatch.sourcefiles)\n        end\n    end\nend\n\n-- get clang-tidy\nfunction _get_clang_tidy()\n    local clang_tidy = find_tool(\"clang-tidy\")\n    if clang_tidy then\n        return clang_tidy\n    end\n\n    -- enter the environments of llvm\n    local oldenvs = packagenv.enter(\"llvm\")\n\n    -- find clang-tidy\n    local packages = {}\n    local clang_tidy = find_tool(\"clang-tidy\")\n    if not clang_tidy then\n        table.join2(packages, install_packages(\"llvm\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not clang_tidy then\n        clang_tidy = find_tool(\"clang-tidy\", {force = true})\n    end\n\n    os.setenvs(oldenvs)\n    return clang_tidy\nend\n\n-- get compile_commands.json file\nfunction _get_compdb_file(opt)\n    local db_path = opt.compdb\n    if not db_path then\n        -- @see https://github.com/xmake-io/xmake/issues/5583#issuecomment-2337696628\n        local outputdir\n        local extraconf = project.extraconf(\"target.rules\", \"plugin.compile_commands.autoupdate\")\n        if extraconf then\n            outputdir = extraconf.outputdir\n        end\n        if outputdir then\n            db_path = path.join(outputdir, \"compile_commands.json\")\n        end\n    end\n    if not db_path then\n        db_path = \"compile_commands.json\"\n    end\n    if os.isdir(db_path) then\n        local db_file_path = path.join(db_path, \"compile_commands.json\")\n        if os.isfile(db_file_path) then\n            db_path = db_file_path\n        end\n    end\n    if not os.isfile(db_path) then\n        local outputdir = os.tmpfile() .. \".dir\"\n        local filename = path.filename(db_path)\n        db_path = outputdir and path.join(outputdir, filename) or filename\n        task.run(\"project\", {quiet = true, kind = \"compile_commands\", lsp = \"clangd\", outputdir = outputdir})\n    end\n    return path.absolute(db_path)\nend\n\n-- check a single sourcefile\nfunction _check_sourcefile(clang_tidy, sourcefile, opt)\n    progress.show(opt.progress, \"clang-tidy.analyzing %s\", sourcefile)\n    try\n    {\n        function ()\n            local outdata, errdata = os.iorunv(clang_tidy.program, opt.tidy_argv, {curdir = opt.projectdir})\n            return (outdata or \"\") .. (errdata or \"\")\n        end,\n        catch\n        {\n            function (errors)\n                -- execution failed or returned non-zero\n                local error_text = \"\"\n                if type(errors) == \"table\" then\n                    error_text = (errors.stdout or \"\") .. (errors.stderr or \"\")\n                    if #error_text:trim() == 0 then\n                        error_text = errors.errors or \"check failed\"\n                    end\n                else\n                    error_text = tostring(errors)\n                end\n                progress.show_output(\"${color.error}%s:\\n%s\", sourcefile, error_text)\n                progress.show_abort()\n                raise(error_text)\n            end\n        },\n        finally\n        {\n            function (ok, outdata, errdata)\n                -- show output if any\n                if ok then\n                    local output = (outdata or \"\") .. (errdata or \"\")\n                    if output and #output:trim() > 0 then\n                        progress.show_output(\"${color.warning}%s:\\n%s\", sourcefile, output)\n                    end\n                end\n            end\n        }\n    }\nend\n\n-- check sourcefiles\nfunction _check_sourcefiles(clang_tidy, sourcefiles, opt)\n    opt = opt or {}\n    local projectdir = project.directory()\n    local argv = {}\n    if opt.checks then\n        table.insert(argv, \"--checks=\" .. opt.checks)\n    end\n    if opt.fix then\n        table.insert(argv, \"--fix\")\n    end\n    if opt.fix_errors then\n        table.insert(argv, \"--fix-errors\")\n    end\n    if opt.fix_notes then\n        table.insert(argv, \"--fix-notes\")\n    end\n    if opt.compdbfile then\n        table.insert(argv, \"-p\")\n        table.insert(argv, opt.compdbfile)\n    end\n    if opt.configfile then\n        table.insert(argv, \"--config-file=\" .. opt.configfile)\n    end\n    if opt.quiet then\n        table.insert(argv, \"--quiet\")\n    end\n\n    -- run clang-tidy\n    local analyze_time = os.mclock()\n    local runjobs_opt = {\n        total = #sourcefiles,\n        comax = opt.jobs or os.default_njob(),\n        showtips = false,\n        progress_refresh = true\n    }\n    runjobs(\"checker.tidy\", function (index, total, job_opt)\n        local sourcefile = sourcefiles[index]\n        local tidy_argv = table.join(argv, {sourcefile})\n        _check_sourcefile(clang_tidy, sourcefile, {\n            tidy_argv = tidy_argv,\n            projectdir = projectdir,\n            progress = job_opt.progress\n        })\n    end, runjobs_opt)\n    analyze_time = os.mclock() - analyze_time\n    progress.show(100, \"${color.success}clang-tidy analyzed %d files, spent %.3fs\", #sourcefiles, analyze_time / 1000)\nend\n\n-- do check\nfunction _check(clang_tidy, opt)\n    opt = opt or {}\n\n    -- generate compile_commands.json first\n    opt.compdbfile = _get_compdb_file(opt)\n\n    -- save option context\n    option.save()\n\n    -- set verbose and diagnosis if specified\n    if opt.verbose then\n        option.set(\"verbose\", true)\n    end\n    if opt.diagnosis then\n        option.set(\"diagnosis\", true)\n    end\n\n    -- get sourcefiles\n    local sourcefiles = {}\n    if opt.files then\n        local files = path.splitenv(opt.files)\n        for _, file in ipairs(files) do\n            for _, filepath in ipairs(os.files(file)) do\n                table.insert(sourcefiles, filepath)\n            end\n        end\n    else\n        local targetnames = opt.targets\n        if targetnames then\n            for _, targetname in ipairs(targetnames) do\n                local target = assert(project.target(targetname), \"unknown target(%s)\", targetname)\n                _add_target_files(sourcefiles, target)\n            end\n        else\n            for _, target in ipairs(project.ordertargets()) do\n                _add_target_files(sourcefiles, target)\n            end\n        end\n    end\n\n    -- check files\n    _check_sourcefiles(clang_tidy, sourcefiles, opt)\n\n    -- restore option context\n    option.restore()\nend\n\nfunction main(argv)\n\n    -- parse arguments\n    local args = option.parse(argv or {}, options, \"Use clang-tidy to check project code.\"\n                                           , \"\"\n                                           , \"Usage: xmake check clang.tidy [options]\")\n\n    -- find clang-tidy\n    local clang_tidy = _get_clang_tidy()\n    assert(clang_tidy, \"clang-tidy not found!\")\n\n    -- list checks\n    if args.list then\n        _show_list(clang_tidy.program)\n    elseif args.create then\n        _create_config(clang_tidy.program, args)\n    else\n        _check(clang_tidy, args)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/cuda/devlink.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        devlink.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\n\n-- https://github.com/xmake-io/xmake/issues/1976#issuecomment-1427378799\nfunction _check_target(target, opt)\n    if target:is_binary() then\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches and not sourcebatches[\"cuda.build\"] then\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:is_static() then\n                    sourcebatches = dep:sourcebatches()\n                    if sourcebatches and sourcebatches[\"cuda.build\"] then\n                        local devlink = dep:policy(\"build.cuda.devlink\") or dep:values(\"cuda.build.devlink\")\n                        if not devlink then\n                            wprint('target(%s)${clear}: cuda device link is not performed! specify set_policy(\"build.cuda.devlink\", true) to enable it', dep:name())\n                        end\n                    end\n                end\n            end\n        end\n    end\nend\n\nfunction main(opt)\n    if opt.target then\n        _check_target(opt.target, opt)\n    else\n        for _, target in pairs(project.targets()) do\n            _check_target(target, opt)\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/check/checkers/syntax.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        syntax.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.cache.memcache\")\nimport(\"core.project.project\")\nimport(\"actions.build.build_files\", {rootdir = os.programdir(), alias = \"build_files\"})\nimport(\"actions.build.build\", {rootdir = os.programdir(), alias = \"build\"})\nimport(\"utils.progress\")\n\n-- the syntax check options\nlocal options = {\n    {'f', \"files\",      \"kv\", nil,   \"Check the given source files.\",\n                                    \"e.g.\",\n                                    \"    - xmake check syntax -f src/foo.cpp\",\n                                    \"    - xmake check syntax -f 'src/*.cpp'\"},\n    {\"j\", \"jobs\",       \"kv\", tostring(os.default_njob()),\n                                    \"Set the number of parallel check jobs.\"},\n    {\"v\", \"verbose\",    \"k\",  nil,   \"Print lots of verbose information for users.\"},\n    {\"D\", \"diagnosis\",  \"k\",  nil,   \"Print lots of diagnosis information (backtrace, check info ..) only for developers.\"},\n    {nil, \"targets\",    \"vs\", nil,   \"Check the sourcefiles of the given target.\",\n                                    \"e.g.\",\n                                    \"    - xmake check syntax\",\n                                    \"    - xmake check syntax [targets]\"}\n}\n\n-- check if target has C++ rules\nfunction _has_cpp_rules(target)\n    for _, ruleinst in ipairs(target:orderules()) do\n        local rulename = ruleinst:name()\n        if rulename == \"c++.build\" or rulename == \"c.build\" or\n           rulename == \"objc++.build\" or rulename == \"objc.build\" then\n            return true\n        end\n    end\n    return false\nend\n\n-- check if compiler supports syntax-only check\nfunction _check_compiler_support(target)\n    local has_support = false\n    if target:has_tool(\"cc\", \"gcc\", \"clang\") or target:has_tool(\"cxx\", \"gxx\", \"clangxx\") then\n        -- gcc/clang: -fsyntax-only\n        has_support = true\n    elseif target:has_tool(\"cc\", \"cl\") or target:has_tool(\"cxx\", \"cl\") then\n        -- MSVC: /Zs\n        has_support = true\n    end\n    return has_support\nend\n\n-- validate targets and enable syntax-only\nfunction _validate_and_enable_targets(opt)\n    opt = opt or {}\n    local targets = {}\n    if opt.targets then\n        for _, targetname in ipairs(opt.targets) do\n            local target = project.target(targetname)\n            if target then\n                table.insert(targets, target)\n            end\n        end\n    else\n        for _, target in pairs(project.targets()) do\n            if target:is_enabled() and (target:is_default() or option.get(\"all\")) then\n                table.insert(targets, target)\n            end\n        end\n    end\n\n    -- check if any target has C++ rules and enable syntax-only\n    local cpp_targets = {}\n    for _, target in ipairs(targets) do\n        if _has_cpp_rules(target) then\n            -- check if compiler supports syntax-only check\n            if not _check_compiler_support(target) then\n                wprint(\"target(%s): current compiler does not support syntax-only check\", target:name())\n            else\n                table.insert(cpp_targets, target)\n            end\n        else\n            wprint(\"target(%s): syntax check currently only supports C/C++ targets\", target:name())\n        end\n    end\n\n    -- enable syntax-only via memcache\n    if #cpp_targets > 0 then\n        memcache.set(\"syntax_check\", \"enabled\", true)\n    end\n\n    -- if no C++ target found, return false to skip checking\n    if #cpp_targets == 0 then\n        return false\n    end\n    return true\nend\n\n-- do check\nfunction _check(opt)\n    opt = opt or {}\n\n    local sourcefiles = opt.files\n    local targetnames = opt.targets\n    local jobs = opt.jobs and tonumber(opt.jobs) or nil\n\n    local check_time = os.mclock()\n    local build_opt = {linkjobs = false}\n    if jobs then\n        build_opt.jobs = jobs\n    end\n    if sourcefiles then\n        build_opt.sourcefiles = sourcefiles\n        build_files(targetnames, build_opt)\n    else\n        build(targetnames, build_opt)\n    end\n    check_time = os.mclock() - check_time\n    progress.show(100, \"${color.success}syntax check ok, spent %.3fs\", check_time / 1000)\nend\n\nfunction main(argv)\n    -- parse arguments\n    local args = option.parse(argv or {}, options, \"Check the project sourcecode syntax without linking.\"\n                                           , \"\"\n                                           , \"Usage: xmake check syntax [options]\")\n\n    -- save option context\n    option.save()\n\n    -- set verbose and diagnosis if specified\n    if args.verbose then\n        option.set(\"verbose\", true)\n    end\n    if args.diagnosis then\n        option.set(\"diagnosis\", true)\n    end\n\n    -- lock the whole project\n    project.lock()\n\n    -- disable ccache after config\n    project.policy_set(\"build.ccache\", false)\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- it will call on_config to add some missing flags in rules\n    project.load_targets()\n\n    -- validate targets and enable syntax-only\n    if _validate_and_enable_targets(args) then\n        _check(args)\n    end\n\n    -- leave project directory\n    os.cd(oldir)\n\n    -- unlock the whole project\n    project.unlock()\n\n    -- restore option context\n    option.restore()\nend\n\n"
  },
  {
    "path": "xmake/modules/private/check/show.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        show.lua\n--\n\nfunction wshow(str, opt)\n    opt = opt or {}\n    _g.showed = _g.showed or {}\n    local showed = _g.showed\n    local infostr\n    if str and opt.sourcetips then\n        infostr = string.format(\"%s${clear}: %s\", opt.sourcetips, str)\n    elseif opt.sourcetips and opt.apiname and opt.value ~= nil then\n        infostr = string.format(\"%s${clear}: unknown %s value '%s'\", opt.sourcetips, opt.apiname, opt.value)\n    elseif str then\n        infostr = string.format(\"${clear}: %s\", str)\n    end\n    if opt.probable_value then\n        infostr = string.format(\"%s, it may be '%s'\", infostr, opt.probable_value)\n    end\n    if not showed[infostr] then\n        wprint(infostr)\n        showed[infostr] = true\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/detect/check_targetname.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        check_targetname.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"private.detect.find_similar_targetnames\")\n\n-- check if a target name is valid\n--\n-- @param targetname the target name to check for\n-- @param opt        the argument options, e.g. {find_similar = false, max_similar = 5}\n-- @return           target or nil, errors\n--\n-- @code\n--\n-- local target, errors = check_targetname(\"mytarget\")\n-- local target, errors = check_targetname(\"mytarget\", {find_similar = false})\n--\n-- @endcode\n--\nfunction main(targetname, opt)\n    opt = opt or {}\n\n    local target = project.target(targetname)\n    if target then\n        return target\n    end\n\n    local errors = \"'\" .. targetname .. \"' is not a valid target name for this project.\"\n    if opt.find_similar ~= false then\n        local matching_targetnames = find_similar_targetnames(targetname)\n        if #matching_targetnames > 0 then\n            local max_index = math.min(#matching_targetnames, opt.max_similar or 14)\n            errors = errors .. \"\\nValid target names closest to input:\\n - \"\n                    .. table.concat(matching_targetnames, '\\n - ', 1, max_index)\n        end\n    end\n    return nil, errors\nend\n"
  },
  {
    "path": "xmake/modules/private/detect/find_cudatool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        find_cudatool.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_program\")\nimport(\"lib.detect.find_programver\")\nimport(\"detect.sdks.find_cuda\")\n\n-- find cuda tool\n--\n-- @param       toolname   name of cuda tool, e.g. \"nvcc\"\n--              parse      default pattern for version string\n--              opt        the argument options, e.g. {version = true}\n--\n-- @return      program, version\n--\n-- @code\n--\n-- local nvcc = find_cudatool(\"nvcc\", \"V(%d+%.?%d*%.?%d*.-)%s\")\n-- local nvcc, version = find_cudatool(\"nvcc\", \"V(%d+%.?%d*%.?%d*.-)%s\", {program = \"nvcc\", version = true})\n--\n-- @endcode\n--\nfunction main(toolname, parse, opt)\n\n    -- init options\n    opt       = opt or {}\n    opt.parse = opt.parse or parse\n\n    -- always keep consistency with cuda cache\n    local program\n    local toolchains = find_cuda()\n    if toolchains and toolchains.bindir then\n        local opt2 = table.clone(opt)\n        opt2.paths = opt2.paths or {}\n        table.insert(opt2.paths, toolchains.bindir)\n        program = find_program(opt2.program or toolname, opt2)\n    end\n\n    -- not found? attempt to find program only\n    if not program then\n        program = find_program(opt.program or toolname, opt)\n    end\n\n    -- find program version\n    local version = nil\n    if program and opt.version then\n        version = find_programver(program, opt)\n    end\n    return program, version\nend\n"
  },
  {
    "path": "xmake/modules/private/detect/find_platform.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        find_platform.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\n-- find platform\nfunction _find_plat(plat)\n    plat = plat or config.get(\"plat\")\n    if not plat then\n        if not plat then\n            plat = project.get(\"defaultplat\")\n        end\n        if not plat then\n            plat = os.subhost()\n        end\n        if plat == \"msys\" then\n            local msystem = os.getenv(\"MSYSTEM\")\n            if msystem and msystem:lower():find(\"mingw\", 1, true) then\n                plat = \"mingw\"\n            end\n        end\n    end\n    return plat\nend\n\n-- find architecture for cross platform\nfunction _find_arch_from_cross()\n    local cross  = config.get(\"cross\")\n    if not cross then\n        local cross_toolchain = find_cross_toolchain(config.get(\"sdk\"), {bindir = config.get(\"bin\")})\n        if cross_toolchain then\n            cross = cross_toolchain.cross\n        end\n    end\n    local arch = \"none\"\n    if cross then\n        if cross:find(\"aarch64\", 1, true) then\n            arch = \"arm64\"\n        elseif cross:find(\"arm\", 1, true) then\n            arch = \"arm\"\n        elseif cross:find(\"mips64\", 1, true) then\n            arch = \"mips64\"\n        elseif cross:find(\"mips\", 1, true) then\n            arch = \"mips\"\n        elseif cross:find(\"riscv64\", 1, true) then\n            arch = \"riscv64\"\n        elseif cross:find(\"riscv\", 1, true) then\n            arch = \"riscv\"\n        elseif cross:find(\"loong64\", 1, true) then\n            arch = \"loong64\"\n        elseif cross:find(\"s390x\", 1, true) then\n            arch = \"s390x\"\n        elseif cross:find(\"powerpc64\", 1, true) then\n            arch = \"ppc64\"\n        elseif cross:find(\"powerpc\", 1, true) then\n            arch = \"ppc\"\n        elseif cross:find(\"sh4\", 1, true) then\n            arch = \"sh4\"\n        elseif cross:find(\"x86_64\", 1, true) then\n            arch = \"x86_64\"\n        elseif cross:find(\"i386\", 1, true) or cross:find(\"i686\", 1, true) then\n            arch = \"i386\"\n        end\n    end\n    return arch\nend\n\n-- find architecture\nfunction _find_arch(plat, arch)\n    arch = arch or config.get(\"arch\")\n    if not arch then\n        if not arch then\n            arch = project.default_arch(plat)\n        end\n        if not arch then\n            local appledev = config.get(\"appledev\")\n            if plat == \"android\" then\n                arch = \"armeabi-v7a\"\n            elseif plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"applexros\" then\n                arch = appledev == \"simulator\" and os.arch() or \"arm64\"\n            elseif plat == \"watchos\" then\n                arch = appledev == \"simulator\" and os.arch() or \"armv7k\"\n            elseif plat == \"wasm\" then\n                arch = \"wasm32\"\n            elseif plat == \"mingw\" then\n                local mingw_chost = nil\n                if is_subhost(\"msys\") then\n                    mingw_chost = os.getenv(\"MINGW_CHOST\")\n                end\n                if mingw_chost == \"i686-w64-mingw32\" then\n                    arch = \"i386\"\n                else\n                    arch = \"x86_64\"\n                end\n            elseif plat == \"harmony\" then\n                arch = \"arm64-v8a\"\n            elseif plat == \"cross\" then\n                arch = _find_arch_from_cross()\n            else\n                arch = os.subarch()\n            end\n        end\n    end\n    return arch\nend\n\n-- find default platform and architecture\n--\n-- @param   opt the argument options, e.g. {plat = \"\", arch = \"\", global = true}\n--\n-- @return  plat, arch\n--\n-- @code\n--\n-- find the default platform:\n--   local result = find_platform()\n--\n-- find the default architecture from the given platform:\n--   local result = find_platform({plat = \"iphoneos\"})\n--\n-- @endcode\n--\nfunction main(opt)\n\n    -- find platform\n    opt = opt or {}\n    local plat = _find_plat(opt.plat)\n    local will_set_plat = false\n    if opt.global then\n        if not opt.plat and not config.get(\"plat\") then\n            will_set_plat = true\n            config.set(\"plat\", plat)\n        end\n    end\n\n    -- find architecture\n    local arch = _find_arch(plat, opt.arch)\n    local will_set_arch = false\n    if opt.global then\n        if not opt.arch and not config.get(\"arch\") then\n            will_set_arch = true\n            config.set(\"arch\", arch)\n        end\n    end\n    if opt.global then\n        if will_set_plat or will_set_arch then\n            cprint(\"checking for platform ... ${color.success}%s (%s)\", plat, arch)\n        end\n    end\n    return plat, arch\nend\n"
  },
  {
    "path": "xmake/modules/private/detect/find_similar_targetnames.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Shiffted\n-- @file        find_similar_targetnames.lua\n--\n\n-- imports\nimport(\"core.project.project\")\n\n-- find targets with a similar name\n--\n-- @param targetname the target name to check against\n-- @return           table of matching target names\n--\n-- @code\n--\n-- local tool = find_similar_targetnames(\"mytarget\")\n--\n-- @endcode\n--\nfunction main(targetname)\n    local targetname_lower = targetname:lower()\n    local matching_targetnames = {}\n    local matching_levenshtein = {}\n\n    for _, target in ipairs(project.ordertargets()) do\n        local name = target:name()\n        if name:lower():find(targetname_lower, 1, true) then\n            table.insert(matching_targetnames, name)\n        else\n            local distance = targetname:levenshtein(name, {sub = 2})\n            if distance < 5 then\n                matching_levenshtein[name] = distance\n            end\n        end\n    end\n\n    table.sort(matching_targetnames, function(a, b)\n        if #a == #b then\n            return a < b\n        end\n        return #a < #b\n    end)\n\n    local levenshtein_keys = table.keys(matching_levenshtein)\n    table.sort(levenshtein_keys, function(a, b)\n        local a_distance = matching_levenshtein[a]\n        local b_distance = matching_levenshtein[b]\n        if a_distance == b_distance then\n            return a < b\n        end\n        return a_distance < b_distance\n    end)\n\n    table.join2(matching_targetnames, levenshtein_keys)\n    return matching_targetnames\nend\n"
  },
  {
    "path": "xmake/modules/private/service/add_user.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        add_user.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.base64\")\nimport(\"core.base.bytes\")\nimport(\"core.base.hashset\")\nimport(\"private.service.service\")\nimport(\"private.service.server_config\", {alias = \"config\"})\n\nfunction main(user)\n    assert(user, \"empty user name!\")\n\n    -- get user password\n    cprint(\"Please input user ${bright}%s${clear} password:\", user)\n    io.flush()\n    local pass = (io.read() or \"\"):trim()\n    assert(pass ~= \"\", \"password is empty!\")\n\n    -- compute user authorization\n    local token = base64.encode(user .. \":\" .. pass)\n    token = hash.md5(bytes(token))\n\n    -- save to configs\n    local configs = assert(config.configs(), \"configs not found!\")\n    configs.tokens = configs.tokens or {}\n    if not hashset.from(configs.tokens):has(token) then\n        table.insert(configs.tokens, token)\n    else\n        cprint(\"User ${bright}%s${clear} has been added!\", user)\n        return\n    end\n    config.save(configs)\n    cprint(\"Add user ${bright}%s${clear} ok!\", user)\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/clean_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clean_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\nimport(\"private.service.remote_cache.client\", {alias = \"remote_cache_client\"})\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\n\nfunction _clean_remote_build_server(...)\n    remote_build_client(...):clean()\nend\n\nfunction _clean_remote_cache_server(...)\n    remote_cache_client(...):clean()\nend\n\nfunction _clean_distcc_build_server(...)\n    distcc_build_client(...):clean()\nend\n\nfunction main(...)\n    local cleaners = {}\n    local default = true\n    if option.get(\"remote\") then\n        table.insert(cleaners, _clean_remote_build_server)\n        default = false\n    end\n    if option.get(\"distcc\") then\n        table.insert(cleaners, _clean_distcc_build_server)\n        default = false\n    end\n    if option.get(\"ccache\") then\n        table.insert(cleaners, _clean_remote_cache_server)\n        default = false\n    end\n    if default then\n        if config.get(\"remote_build\") then\n            table.insert(cleaners, _clean_remote_build_server)\n        end\n    end\n    for _, clean_server in ipairs(cleaners) do\n        scheduler.co_start(clean_server, ...)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/service/client.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.client_config\", {alias = \"config\"})\n\n-- define module\nlocal client = client or object()\n\n-- init client\nfunction client:init()\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"recv_timeout\") or -1\n    self._CONNECT_TIMEOUT = config.get(\"connect_timeout\") or -1\nend\n\n-- get send timeout\nfunction client:send_timeout()\n    return self._SEND_TIMEOUT\nend\n\n-- get recv timeout\nfunction client:recv_timeout()\n    return self._RECV_TIMEOUT\nend\n\n-- get connect timeout\nfunction client:connect_timeout()\n    return self._CONNECT_TIMEOUT\nend\n\n-- parse host address\nfunction client:address_parse(address)\n    local addr, port, user\n    local splitinfo = address:split(':', {plain = true})\n    if #splitinfo == 2 then\n        addr = splitinfo[1]\n        port = splitinfo[2]\n    else\n        addr = \"127.0.0.1\"\n        port = splitinfo[1]\n    end\n    if addr and addr:find(\"@\", 1, true) then\n        splitinfo = addr:split('@', {plain = true})\n        if #splitinfo == 2 then\n            user = splitinfo[1]\n            addr = splitinfo[2]\n        end\n    end\n    assert(addr and port, \"invalid client address!\")\n    return addr, port, user\nend\n\n-- get class\nfunction client:class()\n    return client\nend\n\n-- get working directory\nfunction client:workdir()\n    return os.tmpfile(tostring(self)) .. \".dir\"\nend\n\nfunction client:__tostring()\n    return \"<client>\"\nend\n\nfunction main()\n    local instance = client()\n    instance:init()\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/client_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client_config.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"core.base.base64\")\nimport(\"core.base.bytes\")\nimport(\"core.project.config\")\nimport(\"private.service.server_config\")\n\n-- get a local server token\nfunction _get_local_server_token()\n    local tokens = server_config.get(\"tokens\")\n    if tokens then\n        return tokens[1]\n    end\nend\n\n-- generate a default config file\nfunction _generate_configfile()\n    local filepath = configfile()\n    assert(not _g.configs and not os.isfile(filepath))\n    local token = _get_local_server_token()\n    print(\"generating config file to %s ..\", filepath)\n    local configs = {\n        send_timeout = -1,\n        recv_timeout = -1,\n        connect_timeout = 10000,\n        remote_build = {\n            hosts = {\n                {\n                    name = \"local\",\n                    connect = \"127.0.0.1:9691\",\n                    token = token\n                }\n            }\n        },\n        remote_cache = {\n            connect = \"127.0.0.1:9692\",\n            token = token\n        },\n        distcc_build = {\n            hosts = {\n                -- optional configs\n                --\n                -- njob: max jobs\n                {connect = \"127.0.0.1:9693\", token = token}\n            }\n        }\n    }\n    save(configs)\nend\n\n-- get config file path\nfunction configfile()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) then\n        local localconf = path.join(config.directory(), \"service\", \"client.conf\")\n        if os.isfile(localconf) then\n            return localconf\n        end\n    end\n    return path.join(global.directory(), \"service\", \"client.conf\")\nend\n\n-- get all configs\nfunction configs()\n    return _g.configs\nend\n\n-- get the given config, e.g. client_config.get(\"remote_build.connect\")\nfunction get(name)\n    local value = configs()\n    for _, key in ipairs(name:split('.', {plain = true})) do\n        if type(value) == \"table\" then\n            value = value[key]\n        else\n            value = nil\n            break\n        end\n    end\n    return value\nend\n\n-- load configs\nfunction load()\n    if _g.configs == nil then\n        local filepath = configfile()\n        if not os.isfile(filepath) then\n            _generate_configfile()\n        end\n        assert(os.isfile(filepath), \"%s not found!\", filepath)\n        _g.configs = io.load(filepath)\n    end\nend\n\n-- save configs\nfunction save(configs)\n    local filepath = configfile()\n    io.save(filepath, configs, {orderkeys = true})\nend\n"
  },
  {
    "path": "xmake/modules/private/service/connect_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        connect_service.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\nimport(\"private.service.remote_cache.client\", {alias = \"remote_cache_client\"})\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\n\nfunction _connect_remote_build_server(...)\n    remote_build_client(...):connect()\nend\n\nfunction _connect_remote_cache_server(...)\n    remote_cache_client(...):connect()\nend\n\nfunction _connect_distcc_build_server(...)\n    distcc_build_client(...):connect()\nend\n\nfunction main(...)\n    local connectors = {}\n    local default = true\n    if option.get(\"remote\") then\n        table.insert(connectors, _connect_remote_build_server)\n        default = false\n    end\n    if option.get(\"distcc\") then\n        table.insert(connectors, _connect_distcc_build_server)\n        default = false\n    end\n    if option.get(\"ccache\") then\n        table.insert(connectors, _connect_remote_cache_server)\n        default = false\n    end\n    if default then\n        if config.get(\"remote_build\") then\n            table.insert(connectors, _connect_remote_build_server)\n        end\n    end\n    for _, connect_server in ipairs(connectors) do\n        scheduler.co_start(connect_server, ...)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/disconnect_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        disconnect_service.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\nimport(\"private.service.distcc_build.client\", {alias = \"distcc_build_client\"})\nimport(\"private.service.remote_cache.client\", {alias = \"remote_cache_client\"})\n\nfunction _disconnect_remote_build_server(...)\n    remote_build_client(...):disconnect()\nend\n\nfunction _disconnect_remote_cache_server(...)\n    remote_cache_client(...):disconnect()\nend\n\nfunction _disconnect_distcc_build_server(...)\n    distcc_build_client(...):disconnect()\nend\n\nfunction main(...)\n    local disconnectors = {}\n    local default = true\n    if option.get(\"remote\") then\n        table.insert(disconnectors, _disconnect_remote_build_server)\n        default = false\n    end\n    if option.get(\"distcc\") then\n        table.insert(disconnectors, _disconnect_distcc_build_server)\n        default = false\n    end\n    if option.get(\"ccache\") then\n        table.insert(disconnectors, _disconnect_remote_cache_server)\n        default = false\n    end\n    if default then\n        if config.get(\"remote_build\") then\n            table.insert(disconnectors, _disconnect_remote_build_server)\n        end\n    end\n    for _, disconnect_server in ipairs(disconnectors) do\n        scheduler.co_start(disconnect_server, ...)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/service/distcc_build/client.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client.lua\n--\n\n-- imports\nimport(\"core.base.bytes\")\nimport(\"core.base.base64\")\nimport(\"core.base.socket\")\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"core.project.policy\")\nimport(\"core.project.project\")\nimport(\"core.project.config\", {alias = \"project_config\"})\nimport(\"lib.detect.find_tool\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.client\")\nimport(\"private.cache.build_cache\")\nimport(\"private.service.distcc_build.client_session\")\nimport(\"private.service.stream\", {alias = \"socket_stream\"})\n\n-- define module\nlocal distcc_build_client = distcc_build_client or client()\nlocal super = distcc_build_client:class()\n\n-- init client\nfunction distcc_build_client:init()\n    super.init(self)\n\n    -- init hosts\n    local hosts = assert(config.get(\"distcc_build.hosts\"), \"config(distcc_build.hosts): not found!\")\n    self:hosts_set(hosts)\n\n    -- get project directory\n    local projectdir = os.projectdir()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) and projectdir then\n        self._PROJECTDIR = projectdir\n        self._WORKDIR = path.join(project_config.directory(), \"service\", \"distcc_build\")\n    else\n        raise(\"we need to enter a project directory with xmake.lua first!\")\n    end\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"distcc_build.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"distcc_build.recv_timeout\") or config.get(\"recv_timeout\") or -1\n    self._CONNECT_TIMEOUT = config.get(\"distcc_build.connect_timeout\") or config.get(\"connect_timeout\") or 10000\nend\n\n-- get class\nfunction distcc_build_client:class()\n    return distcc_build_client\nend\n\n-- get the client hosts\nfunction distcc_build_client:hosts()\n    return self._HOSTS\nend\n\n-- set the client hosts\nfunction distcc_build_client:hosts_set(hosts)\n    local hostinfos = {}\n    for _, host in ipairs(hosts) do\n        local hostinfo = {}\n        local address = assert(host.connect, \"connect address not found in hosts configuration!\")\n        local addr, port, user = self:address_parse(address)\n        if addr and port then\n            hostinfo.addr = addr\n            hostinfo.port = port\n            hostinfo.user = user\n            hostinfo.token = host.token\n            hostinfo.njob = host.njob\n            table.insert(hostinfos, hostinfo)\n        end\n    end\n    self._HOSTS = hostinfos\nend\n\n-- get the status of client hosts\nfunction distcc_build_client:hosts_status()\n    local hosts_status = self._HOSTS_STATUS\n    if hosts_status == nil then\n        hosts_status = table.copy(self:status().hosts)\n        for _, host_status in pairs(hosts_status) do\n            self:_host_status_update(host_status)\n        end\n        self._HOSTS_STATUS = hosts_status\n    end\n    return hosts_status\nend\n\n-- connect to the distcc server\nfunction distcc_build_client:connect()\n    if self:is_connected() then\n        print(\"%s: has been connected!\", self)\n        return\n    end\n\n    -- do connect\n    local hosts = self:hosts()\n    assert(hosts and #hosts > 0, \"hosts not found!\")\n    local group_name = tostring(self) .. \"/connect\"\n    scheduler.co_group_begin(group_name, function ()\n        for _, host in ipairs(hosts) do\n            scheduler.co_start(self._connect_host, self, host)\n        end\n    end)\n    scheduler.co_group_wait(group_name)\n\n    -- all hosts are connected?\n    local connected = true\n    for _, host in ipairs(hosts) do\n        if not self:_is_connected(host.addr, host.port) then\n            connected = false\n        end\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = connected\n    self:status_save()\nend\n\n-- disconnect server\nfunction distcc_build_client:disconnect()\n    if not self:is_connected() then\n        print(\"%s: has been disconnected!\", self)\n        return\n    end\n\n    -- do disconnect\n    local hosts = self:hosts()\n    assert(hosts and #hosts > 0, \"hosts not found!\")\n    for _, host in ipairs(hosts) do\n        self:_disconnect_host(host)\n    end\n\n    -- all hosts are connected?\n    local connected = true\n    for _, host in ipairs(hosts) do\n        if not self:_is_connected(host.addr, host.port) then\n            connected = false\n        end\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = connected\n    self:status_save()\nend\n\n-- is connected?\nfunction distcc_build_client:is_connected()\n    return self:status().connected\nend\n\n-- get max jobs count\nfunction distcc_build_client:maxjobs()\n    local maxjobs = self._MAXJOBS\n    if maxjobs == nil then\n        maxjobs = 0\n        for _, host in pairs(self:status().hosts) do\n            maxjobs = maxjobs + (host.njob or 4)\n        end\n        self._MAXJOBS = maxjobs\n    end\n    return maxjobs or 0\nend\n\n-- get free jobs count\nfunction distcc_build_client:freejobs()\n    local maxjobs = self:maxjobs()\n    if maxjobs > 0 then\n        local running = (self._RUNNING or 0)\n        if running > maxjobs then\n            running = maxjobs\n        end\n        return maxjobs - running\n    end\n    return 0\nend\n\n-- has free jobs?\nfunction distcc_build_client:has_freejobs()\n    return self:freejobs() > 0\nend\n\n-- clean server files\nfunction distcc_build_client:clean()\n    if not self:is_connected() then\n        print(\"%s: has been disconnected!\", self)\n        return\n    end\n\n    -- do disconnect\n    local hosts = self:hosts()\n    assert(hosts and #hosts > 0, \"hosts not found!\")\n    local group_name = tostring(self) .. \"/clean\"\n    scheduler.co_group_begin(group_name, function ()\n        for _, host in ipairs(hosts) do\n            scheduler.co_start(self._clean_host, self, host)\n        end\n    end)\n    scheduler.co_group_wait(group_name)\nend\n\n-- run compilation job\nfunction distcc_build_client:compile(program, argv, opt)\n\n    -- get free host\n    local host = assert(self:_get_freehost(), \"free host not found!\")\n\n    -- lock this host\n    self:_host_status_lock(host)\n\n    -- open the host session\n    local session = assert(self:_host_status_session_open(host), \"open session failed!\")\n\n    -- do preprocess\n    opt = opt or {}\n    local preprocess = assert(opt.preprocess, \"preprocessor not found!\")\n    local cppinfo = preprocess(program, argv, opt)\n    local build_in_local = false\n    if cppinfo then\n        -- get objectfile from the build cache first\n        local cached = false\n        local cachekey\n        if build_cache.is_enabled(opt.target) then\n            cachekey = build_cache.cachekey(program, cppinfo, opt.envs)\n            local objectfile_cached, objectfile_infofile = build_cache.get(cachekey)\n            if objectfile_cached then\n                os.cp(objectfile_cached, cppinfo.objectfile)\n                -- we need to update mtime for incremental compilation\n                -- @see https://github.com/xmake-io/xmake/issues/2620\n                os.touch(cppinfo.objectfile, {mtime = os.time()})\n                -- we need to get outdata/errdata to show warnings,\n                -- @see https://github.com/xmake-io/xmake/issues/2452\n                if objectfile_infofile and os.isfile(objectfile_infofile) then\n                    local extrainfo = io.load(objectfile_infofile)\n                    cppinfo.outdata = extrainfo.outdata\n                    cppinfo.errdata = extrainfo.errdata\n                end\n                cached = true\n            end\n        end\n\n        -- do distcc compilation\n        if not cached then\n            -- we just compile the large preprocessed file in remote\n            if (self:remote_only() or os.filesize(cppinfo.cppfile) > 4096) and not session:is_unreachable() then\n                local compile_fallback = opt.compile_fallback\n                if compile_fallback then\n                    local ok = try\n                    {\n                        function ()\n                            local outdata, errdata = session:compile(cppinfo.sourcefile, cppinfo.objectfile, cppinfo.cppfile, cppinfo.cppflags,\n                                table.join(opt, {cachekey = cachekey}))\n                            cppinfo.outdata = outdata\n                            cppinfo.errdata = errdata\n                            return true\n                        end,\n                        catch\n                        {\n                            function (errors)\n                                if errors and policy.build_warnings() then\n                                    cprint(\"${color.warning}fallback to the local compiler, %s\", tostring(errors))\n                                end\n                            end\n                        }\n                    }\n                    if not ok then\n                        -- we fallback to compile original source file if compiling preprocessed file fails.\n                        -- https://github.com/xmake-io/xmake/issues/2467\n                        local outdata, errdata = compile_fallback()\n                        cppinfo.outdata = outdata\n                        cppinfo.errdata = errdata\n                    end\n                else\n                    local outdata, errdata = session:compile(cppinfo.sourcefile, cppinfo.objectfile, cppinfo.cppfile, cppinfo.cppflags,\n                        table.join(opt, {cachekey = cachekey}))\n                    cppinfo.outdata = outdata\n                    cppinfo.errdata = errdata\n                end\n                if cachekey then\n                    local extrainfo\n                    if cppinfo.outdata and #cppinfo.outdata ~= 0 then\n                        extrainfo = extrainfo or {}\n                        extrainfo.outdata = cppinfo.outdata\n                    end\n                    if cppinfo.errdata and #cppinfo.errdata ~= 0 then\n                        extrainfo = extrainfo or {}\n                        extrainfo.errdata = cppinfo.errdata\n                    end\n                    build_cache.put(cachekey, cppinfo.objectfile, extrainfo)\n                end\n            else\n                build_in_local = true\n            end\n        end\n    end\n\n    -- close session\n    self:_host_status_session_close(host, session)\n\n    -- unlock this host\n    self:_host_status_unlock(host)\n\n    -- build in local\n    if build_in_local then\n        if cppinfo and build_in_local then\n            local compile = assert(opt.compile, \"compiler not found!\")\n            local compile_fallback = opt.compile_fallback\n            if compile_fallback then\n                local ok = try {function () compile(program, cppinfo, opt); return true end}\n                if not ok then\n                    -- we fallback to compile original source file if compiling preprocessed file fails.\n                    -- https://github.com/xmake-io/xmake/issues/2467\n                    local outdata, errdata = compile_fallback()\n                    cppinfo.outdata = outdata\n                    cppinfo.errdata = errdata\n                end\n            else\n                compile(program, cppinfo, opt)\n            end\n            if build_cache.is_enabled(opt.target) then\n                local cachekey = build_cache.cachekey(program, cppinfo, opt.envs)\n                if cachekey then\n                    local extrainfo\n                    if cppinfo.outdata and #cppinfo.outdata ~= 0 then\n                        extrainfo = extrainfo or {}\n                        extrainfo.outdata = cppinfo.outdata\n                    end\n                    if cppinfo.errdata and #cppinfo.errdata ~= 0 then\n                        extrainfo = extrainfo or {}\n                        extrainfo.errdata = cppinfo.errdata\n                    end\n                    build_cache.put(cachekey, cppinfo.objectfile, extrainfo)\n                end\n            end\n        end\n    end\n    return cppinfo\nend\n\n-- get the status\nfunction distcc_build_client:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction distcc_build_client:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get the status file\nfunction distcc_build_client:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get the project directory\nfunction distcc_build_client:projectdir()\n    return self._PROJECTDIR\nend\n\n-- get working directory\nfunction distcc_build_client:workdir()\n    return self._WORKDIR\nend\n\n-- build on only remote machines\nfunction distcc_build_client:remote_only()\n    return project.policy(\"build.distcc.remote_only\") == true\nend\n\n-- get free host\nfunction distcc_build_client:_get_freehost()\n    local max_weight = -1\n    local host\n    if self:has_freejobs() then\n        for _, host_status in pairs(self:hosts_status()) do\n            if host_status.freejobs > 0 and host_status.weight > max_weight then\n                max_weight = host_status.weight\n                host = host_status\n            end\n        end\n    end\n    return host\nend\n\n-- update the host status\nfunction distcc_build_client:_host_status_update(host_status)\n    local running  = host_status.running or 0\n    if running > host_status.njob then\n        running = host_status.njob\n    end\n    if running < 0 then\n        running = 0\n    end\n    host_status.running  = running\n    host_status.freejobs = host_status.njob - host_status.running\n    host_status.weight   = host_status.freejobs * (1.0 - (host_status.cpurate or 0))\n    if host_status.memrate and host_status.memrate > 0.9 then\n        host_status.weight = host_status.weight * (1.0 - (host_status.memrate or 0))\n    end\nend\n\n-- lock host status\nfunction distcc_build_client:_host_status_lock(host_status)\n\n    -- update the host status\n    host_status.running = host_status.running + 1\n    self:_host_status_update(host_status)\n\n    -- update the total running status\n    local running = (self._RUNNING or 0) + 1\n    if running > self:maxjobs() then\n        running = self:maxjobs()\n    end\n    self._RUNNING = running\nend\n\n-- unlock host status\nfunction distcc_build_client:_host_status_unlock(host_status)\n\n    -- update the host status\n    host_status.running = host_status.running - 1\n    self:_host_status_update(host_status)\n\n    -- update the total running status\n    local running = self._RUNNING - 1\n    if running < 0 then\n        running = 0\n    end\n    self._RUNNING = running\nend\n\n-- open host session\nfunction distcc_build_client:_host_status_session_open(host_status)\n    host_status.sessions  = host_status.sessions or {}\n    host_status.free_sessions = host_status.free_sessions or {}\n    local sessions = host_status.sessions\n    local free_sessions = host_status.free_sessions\n    if #free_sessions > 0 then\n        local session = free_sessions[#free_sessions]\n        if session and not session:is_opened() then\n            table.remove(free_sessions)\n            session:open(host_status)\n            return session\n        end\n    end\n    local njob = host_status.njob\n    for i = 1, njob do\n        local session = host_status.sessions[i]\n        if not session then\n            session = client_session(self, host_status.session_id, host_status.token, host_status.addr, host_status.port,\n                {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout(), connect_timeout = self:connect_timeout()})\n            host_status.sessions[i] = session\n            session:open(host_status)\n            return session\n        elseif not session:is_opened() then\n            session:open(host_status)\n            return session\n        end\n    end\nend\n\n-- close session\nfunction distcc_build_client:_host_status_session_close(host_status, session)\n    host_status.free_sessions = host_status.free_sessions or {}\n    session:close()\n    table.insert(host_status.free_sessions, session)\nend\n\n-- get the session id, only for unique project\nfunction distcc_build_client:_session_id(addr, port)\n    local hosts = self:status().hosts\n    if hosts then\n        local host = hosts[addr .. \":\" .. port]\n        if host then\n            return host.session_id\n        end\n    end\n    return hash.uuid(option.get(\"session\")):split(\"-\", {plain = true})[1]:lower()\nend\n\n-- is connected for the given host\nfunction distcc_build_client:_is_connected(addr, port)\n    local hosts = self:status().hosts\n    if hosts then\n        local host = hosts[addr .. \":\" .. port]\n        if host then\n            return host.connected\n        end\n    end\nend\n\n-- connect to the host\nfunction distcc_build_client:_connect_host(host)\n    local addr = host.addr\n    local port = host.port\n    if self:_is_connected(addr, port) then\n        print(\"%s: %s:%d has been connected!\", self, addr, port)\n        return\n    end\n\n    -- Do we need user authorization?\n    local user = host.user\n    local token = host.token\n    if not token and user then\n\n        -- get user password\n        cprint(\"Please input user ${bright}%s${clear} password to connect <%s:%d>:\", user, addr, port)\n        io.flush()\n        local pass = (io.read() or \"\"):trim()\n        assert(pass ~= \"\", \"password is empty!\")\n\n        -- compute user authorization\n        token = base64.encode(self:user() .. \":\" .. pass)\n        token = hash.md5(bytes(token))\n    end\n\n    -- do connect\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:_session_id(addr, port)\n    local ok = false\n    local errors\n    local ncpu, njob\n    print(\"%s: connect %s:%d ..\", self, addr, port)\n    if sock then\n        local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        if stream:send_msg(message.new_connect(session_id, {token = token})) and stream:flush() then\n            local msg = stream:recv_msg()\n            if msg then\n                local body = msg:body()\n                vprint(body)\n                if msg:success() then\n                    ncpu = body.ncpu\n                    njob = body.njob\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        end\n    end\n    if ok then\n        print(\"%s: %s:%d connected!\", self, addr, port)\n    else\n        print(\"%s: connect %s:%d failed, %s\", self, addr, port, errors or \"unknown\")\n    end\n\n    -- update status\n    if ok then\n        local status = self:status()\n        status.hosts = status.hosts or {}\n        status.hosts[addr .. \":\" .. port] = {\n            addr = addr, port = port, token = token,\n            connected = ok, session_id = session_id,\n            ncpu = ncpu, njob = njob}\n        self:status_save()\n    end\nend\n\n-- disconnect from the host\nfunction distcc_build_client:_disconnect_host(host)\n    local addr = host.addr\n    local port = host.port\n    if not self:_is_connected(addr, port) then\n        print(\"%s: %s:%d has been disconnected!\", self, addr, port)\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.hosts = status.hosts or {}\n    local host_status = status.hosts[addr .. \":\" .. port]\n    if host_status then\n        host_status.token = nil\n        host_status.connected = false\n    end\n    self:status_save()\n    print(\"%s: %s:%d disconnected!\", self, addr, port)\nend\n\n-- clean file for the host\nfunction distcc_build_client:_clean_host(host)\n    local addr = host.addr\n    local port = host.port\n    if not self:_is_connected(addr, port) then\n        print(\"%s: %s:%d has been disconnected!\", self, addr, port)\n        return\n    end\n\n    -- do clean\n    local token = host.token\n    local sock = socket.connect(addr, port, {timeout = self:connect_timeout()})\n    local session_id = self:_session_id(addr, port)\n    local errors\n    local ok = false\n    print(\"%s: clean files in %s:%d ..\", self, addr, port)\n    if sock then\n        local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        if stream:send_msg(message.new_clean(session_id, {token = token})) and stream:flush() then\n            local msg = stream:recv_msg()\n            if msg then\n                vprint(msg:body())\n                if msg:success() then\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        end\n    else\n        -- server unreachable, but we still disconnect it.\n        wprint(\"%s: server unreachable!\", self)\n        ok = true\n    end\n    if ok then\n        print(\"%s: %s:%d clean files ok!\", self, addr, port)\n    else\n        print(\"%s: clean files %s:%d failed, %s\", self, addr, port, errors or \"unknown\")\n    end\nend\n\n-- is connected? we cannot depend on client:init when run action\nfunction is_connected()\n    local connected = _g.connected\n    if connected == nil then\n        -- the current process is in service? we cannot enable it\n        if os.getenv(\"XMAKE_IN_SERVICE\") then\n            connected = false\n        end\n        if connected == nil then\n            local projectdir = os.projectdir()\n            local projectfile = os.projectfile()\n            if projectfile and os.isfile(projectfile) and projectdir then\n                local workdir = path.join(project_config.directory(), \"service\", \"distcc_build\")\n                local statusfile = path.join(workdir, \"status.txt\")\n                if os.isfile(statusfile) then\n                    local status = io.load(statusfile)\n                    if status and status.connected then\n                        connected = true\n                    end\n                end\n            end\n        end\n        connected = connected or false\n        _g.connected = connected\n    end\n    return connected\nend\n\n-- we can run distcc job?\nfunction is_distccjob()\n    if is_connected() then\n        local co_running = scheduler.co_running()\n        if co_running then\n            return co_running:data(\"distcc.distccjob\")\n        end\n    end\nend\n\n-- new a client instance\nfunction new()\n    local instance = distcc_build_client()\n    instance:init()\n    return instance\nend\n\n-- get the singleton\nfunction singleton()\n    local instance = _g.singleton\n    if not instance then\n        config.load()\n        instance = new()\n        _g.singleton = instance\n    end\n    return instance\nend\n\nfunction main()\n    return new()\nend\n"
  },
  {
    "path": "xmake/modules/private/service/distcc_build/client_session.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client_session.lua\n--\n\n-- imports\nimport(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.object\")\nimport(\"core.base.global\")\nimport(\"core.base.option\")\nimport(\"core.base.socket\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.stream\", {alias = \"socket_stream\"})\n\n-- define module\nlocal client_session = client_session or object()\n\n-- init client session\nfunction client_session:init(client, session_id, token, addr, port, opt)\n    opt = opt or {}\n    self._ID = session_id\n    self._ADDR = addr\n    self._PORT = port\n    self._TOKEN = token\n    self._CLIENT = client\n    self._SEND_TIMEOUT = opt.send_timeout and opt.send_timeout or -1\n    self._RECV_TIMEOUT = opt.recv_timeout and opt.recv_timeout or -1\n    self._CONNECT_TIMEOUT = opt.connect_timeout and opt.connect_timeout or -1\nend\n\n-- get client session id\nfunction client_session:id()\n    return self._ID\nend\n\n-- get token\nfunction client_session:token()\n    return self._TOKEN\nend\n\n-- get client\nfunction client_session:client()\n    return self._CLIENT\nend\n\n-- get send timeout\nfunction client_session:send_timeout()\n    return self._SEND_TIMEOUT\nend\n\n-- get recv timeout\nfunction client_session:recv_timeout()\n    return self._RECV_TIMEOUT\nend\n\n-- get connect timeout\nfunction client_session:connect_timeout()\n    return self._CONNECT_TIMEOUT\nend\n\n-- server unreachable?\nfunction client_session:is_unreachable()\n    return self._UNREACHABLE\nend\n\n-- get stream\nfunction client_session:stream()\n    local stream = self._STREAM\n    if stream == nil then\n        local addr = self._ADDR\n        local port = self._PORT\n        local sock = socket.connect(addr, port, {timeout = self:connect_timeout()})\n        if not sock then\n            self._UNREACHABLE = true\n            raise(\"%s: server unreachable!\", self)\n        end\n        stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        self._STREAM = stream\n    end\n    return stream\nend\n\n-- open session\nfunction client_session:open(host_status)\n    assert(not self:is_opened(), \"%s: has been opened!\", self)\n    self._OPENED = true\n    self._HOST_STATUS = host_status\nend\n\n-- close session\nfunction client_session:close()\n    self._OPENED = false\nend\n\n-- is opened?\nfunction client_session:is_opened()\n    return self._OPENED\nend\n\n-- get host status\nfunction client_session:host_status()\n    return self._HOST_STATUS\nend\n\n\n\n-- run compilation job\nfunction client_session:compile(sourcefile, objectfile, cppfile, cppflags, opt)\n    assert(self:is_opened(), \"%s: has been not opened!\", self)\n    local ok = false\n    local errors\n    local tool = opt.tool\n    local toolname = tool:name()\n    local toolkind = tool:kind()\n    local plat = tool:plat()\n    local arch = tool:arch()\n    local cachekey = opt.cachekey\n    local toolchain = tool:toolchain():name()\n    local stream = self:stream()\n    local host_status = self:host_status()\n    local outdata, errdata\n    if stream:send_msg(message.new_compile(self:id(), toolname, toolkind, plat, arch, toolchain,\n            cppflags, path.filename(sourcefile), {token = self:token(), cachekey = cachekey})) and\n        stream:send_file(cppfile, {compress = os.filesize(cppfile) > 4096}) and stream:flush() then\n        local recv = stream:recv_file(objectfile, {timeout = -1})\n        if recv ~= nil then\n            local msg = stream:recv_msg()\n            if msg then\n                if msg:success() then\n                    local body = msg:body()\n                    outdata = body.outdata\n                    errdata = body.errdata\n                    host_status.cpurate = body.cpurate\n                    host_status.memrate = body.memrate\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        else\n            errors = \"recv object file failed!\"\n        end\n    end\n    os.tryrm(cppfile)\n    assert(ok, \"%s: %s\", self, errors or \"unknown errors!\")\n    return outdata, errdata\nend\n\n-- get work directory\nfunction client_session:workdir()\n    return path.join(self:server():workdir(), \"sessions\", self:id())\nend\n\nfunction client_session:__tostring()\n    return string.format(\"<session %s: %s>\", self:id(), self._ADDR)\nend\n\nfunction main(client, session_id, token, addr, port, opt)\n    local instance = client_session()\n    instance:init(client, session_id, token, addr, port, opt)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/distcc_build/server.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.server\")\nimport(\"private.service.distcc_build.server_session\")\nimport(\"lib.detect.find_tool\")\n\n-- define module\nlocal distcc_build_server = distcc_build_server or server()\nlocal super = distcc_build_server:class()\n\n-- init server\nfunction distcc_build_server:init(daemon)\n    super.init(self, daemon)\n\n    -- init address\n    local address = assert(config.get(\"distcc_build.listen\"), \"config(distcc_build.listen): not found!\")\n    super.address_set(self, address)\n\n    -- init handler\n    super.handler_set(self, self._on_handle)\n\n    -- init sessions\n    self._SESSIONS = {}\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"distcc_build.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"distcc_build.recv_timeout\") or config.get(\"recv_timeout\") or -1\nend\n\n-- get class\nfunction distcc_build_server:class()\n    return distcc_build_server\nend\n\n-- get work directory\nfunction distcc_build_server:workdir()\n    local workdir = config.get(\"distcc_build.workdir\")\n    if not workdir then\n        workdir = path.join(global.directory(), \"service\", \"server\", \"distcc_build\")\n    end\n    return workdir\nend\n\n-- on handle message\nfunction distcc_build_server:_on_handle(stream, msg)\n    local session_id = msg:session_id()\n    local session = self:_session(session_id)\n    vprint(\"%s: %s: <session %s>: on handle message(%d)\", self, stream:sock(), session_id, msg:code())\n    vprint(msg:body())\n    session:stream_set(stream)\n    local respmsg = msg:clone()\n    local session_errs\n    local session_ok = try\n    {\n        function()\n            if self:need_verfiy() then\n                local ok, errors = self:verify_user(msg:token(), stream:sock():peeraddr())\n                if not ok then\n                    session_errs = errors\n                    return false\n                end\n            end\n            if msg:is_connect() then\n                session:open(respmsg)\n            else\n                assert(session:is_connected(), \"session has not been connected!\")\n                if msg:is_compile() then\n                    local ok, errors = session:compile(respmsg)\n                    if not ok then\n                        session_errs = errors\n                        return false\n                    end\n                elseif msg:is_clean() then\n                    session:clean()\n                end\n            end\n            return true\n        end,\n        catch\n        {\n            function (errors)\n                if errors then\n                    session_errs = tostring(errors)\n                end\n            end\n        }\n    }\n    respmsg:status_set(session_ok)\n    if not session_ok and session_errs then\n        respmsg:errors_set(session_errs)\n        vprint(session_errs)\n    end\n    local ok = stream:send_msg(respmsg) and stream:flush()\n    vprint(\"%s: %s: <session %s>: send %s\", self, stream:sock(), session_id, ok and \"ok\" or \"failed\")\nend\n\n-- get session\nfunction distcc_build_server:_session(session_id)\n    local session = self._SESSIONS[session_id]\n    if not session then\n        session = server_session(self, session_id)\n        self._SESSIONS[session_id] = session\n    end\n    return session\nend\n\n-- close session\nfunction distcc_build_server:_session_close(session_id)\n    self._SESSIONS[session_id] = nil\nend\n\nfunction distcc_build_server:__tostring()\n    return \"<distcc_build_server>\"\nend\n\nfunction main(daemon)\n    local instance = distcc_build_server()\n    instance:init(daemon ~= nil)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/distcc_build/server_session.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server_session.lua\n--\n\n-- imports\nimport(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.object\")\nimport(\"core.base.global\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.memcache\")\nimport(\"private.tools.vstool\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\n\n-- define module\nlocal server_session = server_session or object()\n\n-- init server session\nfunction server_session:init(server, session_id)\n    self._ID = session_id\n    self._SERVER = server\nend\n\n-- get server session id\nfunction server_session:id()\n    return self._ID\nend\n\n-- get server\nfunction server_session:server()\n    return self._SERVER\nend\n\n-- open server session\nfunction server_session:open(respmsg)\n    local body = respmsg:body()\n    body.ncpu = os.cpuinfo().ncpu\n    body.njob = os.default_njob()\n    if not self:is_connected() then\n        local status = self:status()\n        status.connected = true\n        status.session_id = self:id()\n        self:status_save()\n    end\nend\n\n-- close server session\nfunction server_session:close()\n    if not self:is_connected() then\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = false\n    status.session_id = self:id()\n    self:status_save()\nend\n\n-- do clean\nfunction server_session:clean()\n    vprint(\"%s: clean files in %s ..\", self, self:workdir())\n    os.tryrm(self:builddir())\n    os.tryrm(self:cachedir())\n    vprint(\"%s: clean files ok\", self)\nend\n\n-- do compile\nfunction server_session:compile(respmsg)\n\n    -- recv source file\n    local body = respmsg:body()\n    local stream = self:stream()\n    local cachekey = body.cachekey\n    local sourcename = body.sourcename\n    local sourcedir = path.join(self:builddir(), (hash.uuid4():gsub(\"-\", \"\")))\n    local sourcefile = path.join(sourcedir, sourcename)\n    local objectfile = (cachekey and path.join(self:cachedir(), cachekey:sub(1, 2), cachekey) or sourcefile) .. \".o\"\n    local objectfile_infofile = objectfile .. \".txt\"\n    if not stream:recv_file(sourcefile) then\n        raise(\"recv %s failed!\", sourcename)\n    end\n\n    -- do compile\n    local errors\n    local ok\n    local outdata, errdata\n    if not (cachekey and os.isfile(objectfile)) then -- no cached object file?\n        ok = try\n        {\n            function ()\n                local flags = body.flags\n                local toolname = body.toolname\n                local compile = assert(self[\"_\" .. toolname .. \"_compile\"], \"%s: compiler(%s) is not supported!\", self, toolname)\n                local objectdir = path.directory(objectfile)\n                if not os.isdir(objectdir) then\n                    os.mkdir(objectdir)\n                end\n                outdata, errdata = compile(self, toolname, flags, sourcefile, objectfile, body)\n                local extrainfo\n                if outdata and #outdata ~= 0 then\n                    extrainfo = extrainfo or {}\n                    extrainfo.outdata = outdata\n                end\n                if errdata and #errdata ~= 0 then\n                    extrainfo = extrainfo or {}\n                    extrainfo.errdata = errdata\n                end\n                if extrainfo then\n                    io.save(objectfile_infofile, extrainfo)\n                end\n                return os.isfile(objectfile)\n            end,\n            catch\n            {\n                function (errs)\n                    errors = tostring(errs)\n                end\n            }\n        }\n        if ok then\n            vprint(\"send compiled object file %s ..\", objectfile)\n        end\n    else\n        vprint(\"send cached object file %s ..\", objectfile)\n        if os.isfile(objectfile_infofile) then\n            local extrainfo = io.load(objectfile_infofile)\n            outdata = extrainfo.outdata\n            errdata = extrainfo.errdata\n        end\n        ok = true\n    end\n\n    -- send object file\n    if ok then\n        if not stream:send_file(objectfile, {compress = os.filesize(objectfile) > 4096}) then\n            raise(\"send %s failed!\", objectfile)\n        end\n        body.outdata = outdata\n        body.errdata = errdata\n    else\n        if not stream:send_emptydata() then\n            raise(\"send empty data failed!\")\n        end\n    end\n\n    -- send current server status\n    body.cpurate = os.cpuinfo(\"usagerate\")\n    body.memrate = os.meminfo(\"usagerate\")\n\n    -- remove files\n    os.tryrm(sourcefile)\n    if not cachekey then\n        os.tryrm(objectfile)\n    end\n    return ok, errors\nend\n\n-- set stream\nfunction server_session:stream_set(stream)\n    self._STREAM = stream\nend\n\n-- get stream\nfunction server_session:stream()\n    return self._STREAM\nend\n\n-- get work directory\nfunction server_session:workdir()\n    return path.join(self:server():workdir(), \"sessions\", self:id())\nend\n\n-- get build directory\nfunction server_session:builddir()\n    return path.join(self:workdir(), \"build\")\nend\n\n-- get cache directory\nfunction server_session:cachedir()\n    return path.join(self:workdir(), \"cache\")\nend\n\n-- is connected?\nfunction server_session:is_connected()\n    return self:status().connected\nend\n\n-- get the status\nfunction server_session:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction server_session:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get status file\nfunction server_session:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get cache\nfunction server_session:_cache()\n    return memcache.cache(\"distcc_build_server.session\")\nend\n\n-- get tool\nfunction server_session:_tool(name, opt)\n    opt = opt or {}\n    local plat = opt.plat\n    local arch = opt.arch\n    local toolkind = opt.toolkind\n    local cachekey = name .. (plat or \"\") .. (arch or \"\") .. toolkind\n    local cacheinfo = self:_cache():get(cachekey)\n    if not cacheinfo then\n        local toolchain_configs = (config.get(\"distcc_build.toolchains\") or {})[name]\n        local toolchain_inst = toolchain.load(name, table.join({plat = plat, arch = arch}, toolchain_configs))\n        if toolchain_inst:check() then\n            local program, toolname = toolchain_inst:tool(toolkind)\n            assert(program, \"%s/%s not found!\", name, toolkind)\n            cacheinfo = {program, toolname, toolchain_inst:runenvs()}\n            self:_cache():set(cachekey, cacheinfo)\n        else\n            raise(\"toolchain(%s) not found!\", name)\n        end\n    end\n    return cacheinfo[1], cacheinfo[2], cacheinfo[3]\nend\n\n-- do compile job for gcc\nfunction server_session:_gcc_compile(toolname, flags, sourcefile, objectfile, opt)\n    local program, toolname_real, runenvs = self:_tool(opt.toolchain, opt)\n    assert(toolname_real == toolname, \"toolname is not matched, %s != %s\", toolname, toolname_real)\n    return os.iorunv(program, table.join(flags, \"-o\", objectfile, sourcefile), {envs = runenvs})\nend\n\n-- do compile job for g++\nfunction server_session:_gxx_compile(toolname, flags, sourcefile, objectfile, opt)\n    return self:_gcc_compile(toolname, flags, sourcefile, objectfile, opt)\nend\n\n-- do compile job for clang\nfunction server_session:_clang_compile(toolname, flags, sourcefile, objectfile, opt)\n    return self:_gcc_compile(toolname, flags, sourcefile, objectfile, opt)\nend\n\n-- do compile job for clang++\nfunction server_session:_clangxx_compile(toolname, flags, sourcefile, objectfile, opt)\n    return self:_gcc_compile(toolname, flags, sourcefile, objectfile, opt)\nend\n\n-- do compile job for cl\nfunction server_session:_cl_compile(toolname, flags, sourcefile, objectfile, opt)\n    local program, toolname_real, runenvs = self:_tool(opt.toolchain, opt)\n    assert(toolname_real == toolname, \"toolname is not matched, %s != %s\", toolname, toolname_real)\n    return vstool.iorunv(program, winos.cmdargv(table.join(flags, \"-Fo\" .. objectfile, sourcefile)), {envs = runenvs})\nend\n\nfunction server_session:__tostring()\n    return string.format(\"<session %s>\", self:id())\nend\n\nfunction main(server, session_id)\n    local instance = server_session()\n    instance:init(server, session_id)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/gen_token.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gen_token.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.base64\")\nimport(\"core.base.bytes\")\nimport(\"core.base.hashset\")\nimport(\"private.service.service\")\nimport(\"private.service.server_config\", {alias = \"config\"})\n\n-- generate a token\nfunction _generate_token()\n    return hash.md5(bytes(base64.encode(hash.uuid())))\nend\n\nfunction main()\n\n    -- generate token\n    local token = _generate_token()\n\n    -- save to configs\n    local configs = assert(config.configs(), \"configs not found!\")\n    configs.tokens = configs.tokens or {}\n    if not hashset.from(configs.tokens):has(token) then\n        table.insert(configs.tokens, token)\n    else\n        cprint(\"Token ${yellow bright}%s${clear} has been added!\", token)\n        return\n    end\n    config.save(configs)\n    cprint(\"New token ${yellow bright}%s${clear} is generated!\", token)\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/message.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        message.lua\n--\n\n-- imports\nimport(\"core.base.object\")\n\n-- define module\nlocal message = message or object()\n\n-- the common message code\nmessage.CODE_CONNECT        = 1  -- connect server\nmessage.CODE_DISCONNECT     = 2  -- disconnect server\nmessage.CODE_CLEAN          = 3  -- clean all cached files in server\nmessage.CODE_DATA           = 4  -- send data\nmessage.CODE_RUNCMD         = 5  -- run the given command in server\nmessage.CODE_DIFF           = 6  -- diff files between server and client\nmessage.CODE_SYNC           = 7  -- sync files between server and client\nmessage.CODE_COMPILE        = 8  -- compile the given file from client in server\nmessage.CODE_PULL           = 9  -- pull the given file from server\nmessage.CODE_PUSH           = 10 -- push the given file to server\nmessage.CODE_FILEINFO       = 11 -- get the given file info in server\nmessage.CODE_EXISTINFO      = 12 -- get exists info in server (use bloom filter)\nmessage.CODE_END            = 13 -- end\n\n-- init message\nfunction message:init(body)\n    self._BODY = body\nend\n\n-- get message code\nfunction message:code()\n    return self:body().code\nend\n\n-- get session id\nfunction message:session_id()\n    return self:body().session_id\nend\n\n-- is connect message?\nfunction message:is_connect()\n    return self:code() == message.CODE_CONNECT\nend\n\n-- is disconnect message?\nfunction message:is_disconnect()\n    return self:code() == message.CODE_DISCONNECT\nend\n\n-- is diff message?\nfunction message:is_diff()\n    return self:code() == message.CODE_DIFF\nend\n\n-- is sync message?\nfunction message:is_sync()\n    return self:code() == message.CODE_SYNC\nend\n\n-- is compile message?\nfunction message:is_compile()\n    return self:code() == message.CODE_COMPILE\nend\n\n-- is clean message?\nfunction message:is_clean()\n    return self:code() == message.CODE_CLEAN\nend\n\n-- is run command message?\nfunction message:is_runcmd()\n    return self:code() == message.CODE_RUNCMD\nend\n\n-- is data message?\nfunction message:is_data()\n    return self:code() == message.CODE_DATA\nend\n\n-- is pull message?\nfunction message:is_pull()\n    return self:code() == message.CODE_PULL\nend\n\n-- is push message?\nfunction message:is_push()\n    return self:code() == message.CODE_PUSH\nend\n\n-- is fileinfo message?\nfunction message:is_fileinfo()\n    return self:code() == message.CODE_FILEINFO\nend\n\n-- is existinfo message?\nfunction message:is_existinfo()\n    return self:code() == message.CODE_EXISTINFO\nend\n\n-- is end message?\nfunction message:is_end()\n    return self:code() == message.CODE_END\nend\n\n-- get user authorization\nfunction message:token()\n    return self:body().token\nend\n\n-- is success?\nfunction message:success()\n    return self:body().status == true\nend\n\n-- set status, ok or failed\nfunction message:status_set(ok)\n    self:body().status = ok\nend\n\n-- get message body\nfunction message:body()\n    return self._BODY\nend\n\n-- get message errors\nfunction message:errors()\n    return self:body().errors\nend\n\n-- set message errors\nfunction message:errors_set(errors)\n    self:body().errors = errors\nend\n\n-- clone a message\nfunction message:clone()\n    local body = table.copy(self:body())\n    return _new(body)\nend\n\n-- dump message\nfunction message:dump()\n    print(self:body())\nend\n\n-- new message\nfunction _new(body)\n    local instance = message()\n    instance:init(body)\n    return instance\nend\n\n-- new connect message\nfunction new_connect(session_id, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_CONNECT,\n        session_id = session_id,\n        token = opt.token,\n        xmakever = xmake.version():shortstr()\n    })\nend\n\n-- new disconnect message\nfunction new_disconnect(session_id, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_DISCONNECT,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\n-- new diff message, e.g manifest = {[\"src/main.c\"] = {sha256 = \"\", mtime = \"\"}}\nfunction new_diff(session_id, manifest, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_DIFF,\n        session_id = session_id,\n        token = opt.token,\n        manifest = manifest,\n        xmakesrc = opt.xmakesrc\n    })\nend\n\n-- new sync message, e.g. manifest = {modified = {\"src/main.c\"}, inserted = {}, removed = {}}\nfunction new_sync(session_id, manifest, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_SYNC,\n        session_id = session_id,\n        token = opt.token,\n        manifest = manifest,\n        xmakesrc = opt.xmakesrc\n    })\nend\n\n-- new clean message\nfunction new_clean(session_id, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_CLEAN,\n        session_id = session_id,\n        token = opt.token,\n        all = opt.all\n    })\nend\n\n-- new run command message\nfunction new_runcmd(session_id, program, argv, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_RUNCMD,\n        session_id = session_id,\n        token = opt.token,\n        program = program,\n        argv = argv\n    })\nend\n\n-- new data message\nfunction new_data(session_id, size, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_DATA,\n        size = size,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\n-- new compile command message\nfunction new_compile(session_id, toolname, toolkind, plat, arch, toolchain, flags, sourcename, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_COMPILE,\n        session_id = session_id,\n        token = opt.token,\n        toolname = toolname,\n        toolkind = toolkind,\n        cachekey = opt.cachekey,\n        plat = plat,\n        arch = arch,\n        toolchain = toolchain,\n        flags = flags,\n        sourcename = sourcename\n    })\nend\n\n-- new pull message\nfunction new_pull(session_id, filename, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_PULL,\n        filename = filename,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\n-- new push message\nfunction new_push(session_id, filename, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_PUSH,\n        filename = filename,\n        session_id = session_id,\n        token = opt.token,\n        extrainfo = opt.extrainfo\n    })\nend\n\n-- new fileinfo message\nfunction new_fileinfo(session_id, filename, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_FILEINFO,\n        filename = filename,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\n-- new existinfo message\nfunction new_existinfo(session_id, name, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_EXISTINFO,\n        name = name,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\n-- new end message\nfunction new_end(session_id, opt)\n    opt = opt or {}\n    return _new({\n        code = message.CODE_END,\n        session_id = session_id,\n        token = opt.token\n    })\nend\n\nfunction main(body)\n    return _new(body)\nend\n"
  },
  {
    "path": "xmake/modules/private/service/pull_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pull_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\n\nfunction main(filepattern, outputdir)\n    remote_build_client():pull(filepattern, outputdir)\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/service/reconnect_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        reconnect_service.lua\n--\n\n-- imports\nimport(\"private.service.connect_service\")\nimport(\"private.service.disconnect_service\")\n\nfunction main()\n    disconnect_service();\n    connect_service();\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/remote_build/action.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        action.lua\n--\n\n-- imports\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\n\n-- is enabled?\nfunction enabled()\n    return remote_build_client.is_connected()\nend\n\nfunction main()\n    config.load()\n    remote_build_client.singleton():runcmd(\"xmake\", xmake.argv())\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_build/client.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client.lua\n--\n\n-- imports\nimport(\"core.base.tty\")\nimport(\"core.base.bytes\")\nimport(\"core.base.base64\")\nimport(\"core.base.socket\")\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"core.project.config\", {alias = \"project_config\"})\nimport(\"lib.detect.find_tool\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.client\")\nimport(\"private.service.stream\", {alias = \"socket_stream\"})\nimport(\"private.service.remote_build.filesync\", {alias = \"new_filesync\"})\n\n-- define module\nlocal remote_build_client = remote_build_client or client()\nlocal super = remote_build_client:class()\n\n-- init client\nfunction remote_build_client:init()\n    super.init(self)\n\n    -- get project directory\n    local projectdir = os.projectdir()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) and projectdir then\n        self._PROJECTDIR = projectdir\n        self._WORKDIR = path.join(project_config.directory(), \"service\", \"remote_build\")\n    else\n        raise(\"we need to enter a project directory with xmake.lua first!\")\n    end\n\n    -- init host\n    self:_init_host()\n\n    -- init filesync\n    local filesync = new_filesync(self:projectdir(), path.join(self:workdir(), \"manifest.txt\"))\n    filesync:ignorefiles_add(\".git/**\")\n    filesync:ignorefiles_add(\".xmake/**\")\n    self._FILESYNC = filesync\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"remote_build.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"remote_build.recv_timeout\") or config.get(\"recv_timeout\") or -1\n    self._CONNECT_TIMEOUT = config.get(\"remote_build.connect_timeout\") or config.get(\"connect_timeout\") or 10000\nend\n\n-- get class\nfunction remote_build_client:class()\n    return remote_build_client\nend\n\n-- connect to the remote server\nfunction remote_build_client:connect()\n    if self:is_connected() then\n        print(\"%s: has been connected!\", self)\n        return\n    end\n\n    -- Do we need user authorization?\n    local user = self:user()\n    local token = self:token()\n    if not token and user then\n\n        -- get user password\n        cprint(\"Please input user ${bright}%s${clear} password to connect <%s:%d>:\", user, self:addr(), self:port())\n        io.flush()\n        local pass = (io.read() or \"\"):trim()\n        assert(pass ~= \"\", \"password is empty!\")\n\n        -- compute user authorization\n        token = base64.encode(user .. \":\" .. pass)\n        token = hash.md5(bytes(token))\n\n        -- update the computed token\n        self:token_set(token)\n    end\n\n    -- do connect\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local ok = false\n    local errors\n    cprint(\"${dim}%s: connect %s:%d ..\", self, addr, port)\n    if sock then\n        local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        if stream:send_msg(message.new_connect(session_id, {token = token})) and stream:flush() then\n            local msg = stream:recv_msg()\n            if msg then\n                vprint(msg:body())\n                if msg:success() then\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        end\n    end\n    if ok then\n        cprint(\"${dim}%s: connected!\", self)\n    else\n        cprint(\"${dim}%s: connect %s:%d failed, %s\", self, addr, port, errors or \"unknown\")\n    end\n\n    -- update status\n    local status = self:status()\n    status.addr = addr\n    status.port = port\n    status.token = token\n    status.user = user\n    status.connected = ok\n    status.session_id = session_id\n    self:status_save()\n\n    -- sync files\n    if ok then\n        self:sync()\n    end\nend\n\n-- disconnect server\nfunction remote_build_client:disconnect()\n    if not self:is_connected() then\n        print(\"%s: has been disconnected!\", self)\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.token = nil\n    status.connected = false\n    self:status_save()\n    cprint(\"${dim}%s: disconnected!\", self)\nend\n\n-- sync server files\nfunction remote_build_client:sync()\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    local diff_files\n    local xmakesrc = option.get(\"xmakesrc\")\n    cprint(\"${dim}%s: sync files in %s:%d ..\", self, addr, port)\n    while sock do\n\n        -- diff files\n        local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        diff_files, errors = self:_diff_files(stream, {xmakesrc = xmakesrc})\n        if not diff_files then\n            break\n        end\n        if not diff_files.changed then\n            ok = true\n            break\n        end\n\n        -- do sync\n        cprint(\"Uploading files ..\")\n        local send_ok = false\n        if stream:send_msg(message.new_sync(session_id, diff_files,\n                {token = self:token(), xmakesrc = xmakesrc and true or false}), {compress = true}) and stream:flush() then\n            if self:_send_diff_files(stream, diff_files, {rootdir = xmakesrc}) then\n                send_ok = true\n            end\n        end\n        if not send_ok then\n            errors = \"send files failed\"\n            break\n        end\n\n        -- sync ok\n        local msg = stream:recv_msg({timeout = -1})\n        if msg and msg:success() then\n            vprint(msg:body())\n            ok = true\n        elseif msg then\n            errors = msg:errors()\n        end\n        break\n    end\n    if ok then\n        cprint(\"${dim}%s: sync files ok!\", self)\n    else\n        cprint(\"${dim}%s: sync files failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\nend\n\n-- pull server files\nfunction remote_build_client:pull(filepattern, outputdir)\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    if not filepattern:find(\"*\", 1, true) and os.isdir(filepattern) then\n        filepattern = path.join(filepattern, \"**\")\n    end\n    if not outputdir then\n        outputdir = os.curdir()\n    end\n    cprint(\"${dim}%s: pull %s in %s:%d ..\", self, filepattern, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_pull(session_id, filepattern, {token = self:token()})) and stream:flush() then\n        local fileitems\n        local msg = stream:recv_msg({timeout = -1})\n        if msg then\n            dprint(msg:body())\n            if msg:success() then\n                fileitems = msg:body().fileitems\n            else\n                errors = msg:errors()\n            end\n        end\n        if fileitems then\n            for _, fileitem in ipairs(fileitems) do\n                print(\"recving %s ..\", fileitem)\n                if not stream:recv_file(path.normalize(path.join(outputdir, fileitem))) then\n                    errors = string.format(\"recv %s failed\", fileitem)\n                    break\n                end\n            end\n            msg = stream:recv_msg({timeout = -1})\n            if msg then\n                dprint(msg:body())\n                if msg:success() then\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        end\n    end\n    if ok then\n        cprint(\"${dim}%s: pull files to %s!\", self, outputdir)\n    else\n        cprint(\"${dim}%s: pull files failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\nend\n\n-- clean server files\nfunction remote_build_client:clean()\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    cprint(\"${dim}%s: clean files in %s:%d ..\", self, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_clean(session_id, {token = self:token(), all = option.get(\"all\")})) and stream:flush() then\n        local msg = stream:recv_msg({timeout = -1})\n        if msg then\n            vprint(msg:body())\n            if msg:success() then\n                ok = true\n            else\n                errors = msg:errors()\n            end\n        end\n    end\n    if ok then\n        cprint(\"${dim}%s: clean files ok!\", self)\n    else\n        cprint(\"${dim}%s: clean files failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\nend\n\n-- run command\nfunction remote_build_client:runcmd(program, argv)\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    local buff = bytes(8192)\n    local command = os.args(table.join(program, argv))\n    local leftstr = \"\"\n    cprint(\"${dim}%s: run '%s' in %s:%d ..\", self, command, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_runcmd(session_id, program, argv, {token = self:token()})) and stream:flush() then\n        local stdin_opt = {stop = false}\n        local group_name = \"remote_build/runcmd\"\n        scheduler.co_group_begin(group_name, function (co_group)\n            scheduler.co_start(self._read_stdin, self, stream, stdin_opt)\n        end)\n        while true do\n            local msg = stream:recv_msg({timeout = -1})\n            if msg then\n                if msg:is_data() then\n                    local data = stream:recv(buff, msg:body().size)\n                    if data then\n                        leftstr = leftstr .. data:str()\n                        local pos = leftstr:lastof(\"\\n\", true)\n                        if pos then\n                            cprint(leftstr:sub(1, pos - 1))\n                            leftstr = leftstr:sub(pos + 1)\n                        end\n                    else\n                        errors = string.format(\"recv output data(%d) failed!\", msg:body().size)\n                        break\n                    end\n                elseif msg:is_end() then\n                    ok = true\n                    break\n                else\n                    if msg:success() then\n                        ok = true\n                    else\n                        errors = msg:errors()\n                    end\n                    break\n                end\n            else\n                break\n            end\n        end\n        stdin_opt.stop = true\n        scheduler.co_group_wait(group_name)\n    end\n    if #leftstr > 0 then\n        cprint(leftstr)\n    end\n    if ok then\n        cprint(\"${dim}%s: run command ok!\", self)\n    else\n        cprint(\"${dim}%s: run command failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\n    io.flush()\nend\n\n-- is connected?\nfunction remote_build_client:is_connected()\n    return self:status().connected\nend\n\n-- get the status\nfunction remote_build_client:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction remote_build_client:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get the status file\nfunction remote_build_client:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get the project directory\nfunction remote_build_client:projectdir()\n    return self._PROJECTDIR\nend\n\n-- get working directory\nfunction remote_build_client:workdir()\n    return self._WORKDIR\nend\n\n-- get user token\nfunction remote_build_client:token()\n    return self._TOKEN or self:status().token\nend\n\n-- set user token\nfunction remote_build_client:token_set(token)\n    self._TOKEN = token\nend\n\n-- get the session id, only for unique project\nfunction remote_build_client:session_id()\n    return self:status().session_id or hash.uuid(option.get(\"session\")):split(\"-\", {plain = true})[1]:lower()\nend\n\n-- init host address and token\n--\n-- Supported configuration formats:\n--\n-- New format (multiple hosts):\n--   remote_build = {\n--       hosts = {\n--           {\n--               name = \"windows\",\n--               connect = \"10.5.139.8:9691\",\n--               token = \"0e052f8c7153a6111d5a418e514020ee\"\n--           },\n--           {\n--               name = \"linux\",\n--               connect = \"192.168.1.100:9691\",\n--               token = \"abc123def456\"\n--           }\n--       }\n--   }\n--\n-- Old format (single host, backward compatible):\n--   remote_build = {\n--       connect = \"10.5.139.8:9691\",\n--       token = \"0e052f8c7153a6111d5a418e514020ee\"\n--   }\n--\n-- Usage:\n--   xmake service --connect --host=windows    # connect by name\n--   xmake service --connect --host=10.5.139.8:9691  # connect by address\n--   xmake service --connect                 # use default host\nfunction remote_build_client:_init_host()\n    local remote_build_config = config.get(\"remote_build\") or {}\n    local address\n    local token\n\n    -- if already connected, use status first\n    if self:is_connected() then\n        local status = self:status()\n        if status.addr and status.port then\n            address = status.addr .. \":\" .. status.port\n            token = status.token\n            self:address_set(address)\n            if token then\n                self:token_set(token)\n            end\n            return\n        end\n    end\n\n    -- support new hosts format\n    if remote_build_config.hosts then\n        local host_name = option.get(\"host\")\n        if host_name then\n            -- find host by name or address\n            for _, host in ipairs(remote_build_config.hosts) do\n                local host_ip, _ = host.connect:split(\":\", {plain = true})\n                if host.name == host_name or\n                   host.connect == host_name or\n                   (host_ip == host_name and not host_name:find(\":\", 1, true)) then\n                    address = host.connect\n                    token = host.token\n                    break\n                end\n            end\n            if not address then\n                raise(\"host '%s' not found in configuration!\", host_name)\n            end\n        else\n            -- use first host as default\n            if #remote_build_config.hosts > 0 then\n                address = remote_build_config.hosts[1].connect\n                token = remote_build_config.hosts[1].token\n            end\n        end\n    -- support old format for backward compatibility\n    elseif remote_build_config.connect then\n        address = remote_build_config.connect\n        token = remote_build_config.token\n    end\n\n    if not address then\n        raise(\"config(remote_build.connect) or config(remote_build.hosts) not found!\")\n    end\n\n    self:address_set(address)\n    if token then\n        self:token_set(token)\n    end\nend\n\n-- set the given client address\nfunction remote_build_client:address_set(address)\n    local addr, port, user = self:address_parse(address)\n    self._ADDR = addr\n    self._PORT = port\n    self._USER = user\nend\n\n-- get user name\nfunction remote_build_client:user()\n    return self._USER or self:status().user\nend\n\n-- get the ip address\nfunction remote_build_client:addr()\n    return self._ADDR or self:status().addr\nend\n\n-- get the address port\nfunction remote_build_client:port()\n    return self._PORT or self:status().port\nend\n\n-- get filesync\nfunction remote_build_client:_filesync()\n    return self._FILESYNC\nend\n\n-- diff server files\nfunction remote_build_client:_diff_files(stream, opt)\n    opt = opt or {}\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    print(\"Scanning files ..\")\n    local filesync = self:_filesync()\n    if opt.xmakesrc then\n        assert(os.isdir(opt.xmakesrc), \"%s: %s not found!\", opt.xmakesrc)\n        filesync = new_filesync(opt.xmakesrc, path.join(self:workdir(), \"xmakesrc_manifest.txt\"))\n        filesync:ignorefiles_add(\".git/**\")\n    end\n    local manifest, filecount = filesync:snapshot()\n    local session_id = self:session_id()\n    local count = 0\n    local result, errors\n    cprint(\"Comparing ${bright}%d${clear} files ..\", filecount)\n    if stream:send_msg(message.new_diff(session_id, manifest,\n            {token = self:token(), xmakesrc = opt.xmakesrc and true or false}),\n                {compress = true}) and stream:flush() then\n        local msg = stream:recv_msg({timeout = -1})\n        if msg and msg:success() then\n            result = msg:body().manifest\n            if result then\n                for _, fileitem in ipairs(result.inserted) do\n                    if count < 8 then\n                        cprint(\"    ${green}[+]: ${clear}%s\", fileitem)\n                    end\n                    count = count + 1\n                end\n                for _, fileitem in ipairs(result.modified) do\n                    if count < 8 then\n                        cprint(\"    ${yellow}[*]: ${clear}%s\", fileitem)\n                    end\n                    count = count + 1\n                end\n                for _, fileitem in ipairs(result.removed) do\n                    if count < 8 then\n                        cprint(\"    ${red}[-]: ${clear}%s\", fileitem)\n                    end\n                    count = count + 1\n                end\n                if count >= 8 then\n                    print(\"    ...\")\n                end\n            end\n        elseif msg then\n            errors = msg:errors()\n        end\n    end\n    cprint(\"${bright}%d${clear} files has been changed!\", count)\n    return result, errors\nend\n\n-- send diff files\nfunction remote_build_client:_send_diff_files(stream, diff_files, opt)\n    opt = opt or {}\n    local count = 0\n    local totalsize = 0\n    local compressed_size = 0\n    local totalcount = #(diff_files.inserted or {}) + #(diff_files.modified or {})\n    local time = os.mclock()\n    local startime = time\n    for _, fileitem in ipairs(diff_files.inserted) do\n        local filepath = fileitem\n        if opt.rootdir and not path.is_absolute(fileitem) then\n            filepath = path.absolute(fileitem, opt.rootdir)\n        end\n        local filesize = os.filesize(filepath)\n        if os.mclock() - time > 1000 then\n            cprint(\"Uploading ${bright}%d%%${clear} ..\", math.floor(count * 100 / totalcount))\n            time = os.mclock()\n        end\n        vprint(\"uploading %s, %d bytes ..\", fileitem, filesize)\n        local sent, compressed_real = stream:send_file(filepath, {compress = filesize > 4096})\n        if not sent then\n            return false\n        end\n        count = count + 1\n        totalsize = totalsize + filesize\n        compressed_size = compressed_size + compressed_real\n    end\n    for _, fileitem in ipairs(diff_files.modified) do\n        local filepath = fileitem\n        if opt.rootdir and not path.is_absolute(fileitem) then\n            filepath = path.absolute(fileitem, opt.rootdir)\n        end\n        local filesize = os.filesize(filepath)\n        if os.mclock() - time > 1000 then\n            cprint(\"Uploading ${bright}%d%%${clear} ..\", math.floor(count * 100 / totalcount))\n            time = os.mclock()\n        end\n        vprint(\"uploading %s, %d bytes ..\", fileitem, filesize)\n        local sent, compressed_real = stream:send_file(filepath, {compress = filesize > 4096})\n        if not sent then\n            return false\n        end\n        count = count + 1\n        totalsize = totalsize + filesize\n        compressed_size = compressed_size + compressed_real\n    end\n    cprint(\"Uploading ${bright}%s%%${clear} ..\", totalcount > 0 and math.floor(count * 100 / totalcount) or 0)\n    cprint(\"${bright}%s${clear} files, ${bright}%s (%s%%)${clear} bytes are uploaded, spent ${bright}%s${clear} ms.\",\n        totalcount, compressed_size, totalsize > 0 and math.floor(compressed_size * 100 / totalsize) or 0, os.mclock() - startime)\n    return stream:flush()\nend\n\n-- read stdin data\nfunction remote_build_client:_read_stdin(stream, opt)\n    local term = tty.term()\n    if term == \"msys2\" or term == \"cygwin\" then\n        wprint(\"we cannot capture stdin on %s, please pass `-y` option to xmake command or use cmd/powershell terminal!\", term)\n    end\n    while not opt.stop do\n        -- FIXME, io.readable is invalid on msys2/cygwin, it always return false\n        -- @see https://github.com/xmake-io/xmake/issues/2504\n        if io.readable() then\n            local line = io.read(\"L\") -- with crlf\n            if line and #line > 0 then\n                local ok = false\n                local data = bytes(line)\n                if stream:send_msg(message.new_data(0, data:size(), {token = self:token()})) then\n                    if stream:send(data) and stream:flush() then\n                        ok = true\n                    end\n                end\n                if not ok then\n                    break\n                end\n            else\n                -- we need to avoid always reading stdin\n                -- https://github.com/xmake-io/xmake/issues/3422\n                os.sleep(1)\n            end\n        else\n            os.sleep(500)\n        end\n    end\n    -- say bye\n    if stream:send_msg(message.new_end(self:session_id(), {token = self:token()})) then\n        stream:flush()\n    end\nend\n\nfunction remote_build_client:__tostring()\n    return \"<remote_build_client>\"\nend\n\n-- is connected? we cannot depend on client:init when run action\nfunction is_connected()\n    -- the current process is in service? we cannot enable it\n    if os.getenv(\"XMAKE_IN_SERVICE\") then\n        return false\n    end\n    local projectdir = os.projectdir()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) and projectdir then\n        local workdir = path.join(project_config.directory(), \"service\", \"remote_build\")\n        local statusfile = path.join(workdir, \"status.txt\")\n        if os.isfile(statusfile) then\n            local status = io.load(statusfile)\n            if status and status.connected then\n                return true\n            end\n        end\n    end\nend\n\n-- new a client instance\nfunction new()\n    local instance = remote_build_client()\n    instance:init()\n    return instance\nend\n\n-- get the singleton\nfunction singleton()\n    local instance = _g.singleton\n    if not instance then\n        config.load()\n        instance = new()\n        _g.singleton = instance\n    end\n    return instance\nend\n\nfunction main()\n    return new()\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_build/filesync.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        filesync.lua\n--\n\n-- imports\nimport(\"core.base.object\")\n\n-- define module\nlocal filesync = filesync or object()\n\n-- init filesync\nfunction filesync:init(rootdir, manifest_file)\n    self._ROOTDIR = rootdir\n    self._MANIFEST_FILE = manifest_file\nend\n\n-- get root directory\nfunction filesync:rootdir()\n    return self._ROOTDIR\nend\n\n-- get ignore files\nfunction filesync:ignorefiles()\n    local ignorefiles = self._IGNOREFILES\n    if not ignorefiles then\n        ignorefiles = {}\n        self:_ignorefiles_load(ignorefiles)\n        self._IGNOREFILES = ignorefiles\n    end\n    return ignorefiles\nend\n\n-- add ignore files\nfunction filesync:ignorefiles_add(...)\n    table.join2(self:ignorefiles(), ...)\nend\n\n-- get manifest\nfunction filesync:manifest()\n    local manifest = self._MANIFEST\n    if not manifest then\n        local manifest_file = self:manifest_file()\n        if manifest_file and os.isfile(manifest_file) then\n            manifest = io.load(manifest_file)\n        end\n        manifest = manifest or {}\n        self._MANIFEST = manifest\n    end\n    return manifest\nend\n\n-- save manifest file\nfunction filesync:manifest_save()\n    local manifest_file = self:manifest_file()\n    if manifest_file then\n        io.save(manifest_file, self:manifest())\n    end\nend\n\n-- get manifest file\nfunction filesync:manifest_file()\n    return self._MANIFEST_FILE\nend\n\n-- do snapshot, it will re-scan all and update to manifest file\nfunction filesync:snapshot()\n    local rootdir = self:rootdir()\n    assert(rootdir and os.isdir(rootdir), \"get snapshot %s failed, rootdir not found!\", rootdir)\n    local manifest = {}\n    local manifest_old = self:manifest()\n    local ignorefiles = self:ignorefiles()\n    if ignorefiles then\n        ignorefiles = \"|\" .. table.concat(ignorefiles, \"|\")\n    end\n    local count = 0\n    for _, filepath in ipairs(os.files(path.join(rootdir, \"**\" .. ignorefiles))) do\n        local fileitem = path.relative(filepath, rootdir)\n        if fileitem then\n            -- we should always use '/' in path key for supporting linux & windows\n            -- https://github.com/xmake-io/xmake/issues/2488\n            if is_host(\"windows\") then\n                fileitem = fileitem:gsub(\"\\\\\", \"/\")\n            end\n            local manifest_info = manifest_old[fileitem]\n            local mtime = os.mtime(filepath)\n            if not manifest_info or not manifest_info.mtime or mtime > manifest_info.mtime then\n                manifest[fileitem] = {sha256 = hash.sha256(filepath), mtime = mtime}\n            else\n                manifest[fileitem] = manifest_info\n            end\n            count = count + 1\n        end\n    end\n    self._MANIFEST = manifest\n    self:manifest_save()\n    return manifest, count\nend\n\n-- update file\nfunction filesync:update(fileitem, filepath, sha256)\n    local mtime = os.mtime(filepath)\n    local manifest = self:manifest()\n    sha256 = sha256 or hash.sha256(filepath)\n    manifest[fileitem] = {sha256 = sha256, mtime = mtime}\nend\n\n-- remove file\nfunction filesync:remove(fileitem)\n    local manifest = self:manifest()\n    manifest[fileitem] = nil\nend\n\n-- load ignore files from .gitignore files\nfunction filesync:_ignorefiles_load(ignorefiles)\n    local rootdir = self:rootdir()\n    local gitignore_files = os.files(path.join(rootdir, \"**\", \".gitignore\"))\n    if os.isfile(path.join(rootdir, \".gitignore\")) then\n        table.insert(gitignore_files, path.join(rootdir, \".gitignore\"))\n    end\n    for _, gitignore_file in ipairs(gitignore_files) do\n        local gitroot = path.directory(gitignore_file)\n        local gitignore = io.open(gitignore_file, \"r\")\n        for line in gitignore:lines() do\n            line = line:trim()\n            if #line > 0 and not line:startswith(\"#\") then\n                local filepath = path.join(gitroot, line)\n                local pattern = path.relative(filepath, rootdir)\n                if pattern then\n                    if line:endswith(path.sep()) or os.isdir(line) then\n                        table.insert(ignorefiles, path.join(pattern, \"**\"))\n                    elseif os.isfile(line) then\n                        table.insert(ignorefiles, pattern)\n                    elseif line:find(\"*.\", 1, true) then\n                        table.insert(ignorefiles, (pattern:gsub(\"%*%.\", \"**.\")))\n                    else\n                        table.insert(ignorefiles, pattern)\n                        table.insert(ignorefiles, path.join(pattern, \"**\"))\n                    end\n                end\n            end\n        end\n        gitignore:close()\n    end\nend\n\nfunction main(rootdir, manifest_file)\n    local instance = filesync()\n    instance:init(rootdir, manifest_file)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_build/server.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.server\")\nimport(\"private.service.remote_build.server_session\")\nimport(\"private.service.remote_build.filesync\", {alias = \"new_filesync\"})\nimport(\"lib.detect.find_tool\")\n\n-- define module\nlocal remote_build_server = remote_build_server or server()\nlocal super = remote_build_server:class()\n\n-- init server\nfunction remote_build_server:init(daemon)\n    super.init(self, daemon)\n\n    -- init address\n    local address = assert(config.get(\"remote_build.listen\"), \"config(remote_build.listen): not found!\")\n    super.address_set(self, address)\n\n    -- init handler\n    super.handler_set(self, self._on_handle)\n\n    -- init sessions\n    self._SESSIONS = {}\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"remote_build.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"remote_build.recv_timeout\") or config.get(\"recv_timeout\") or -1\n\n    -- init xmake filesync\n    local xmake_filesync = new_filesync(self:xmake_sourcedir(), path.join(self:workdir(), \"xmakesrc_manifest.txt\"))\n    xmake_filesync:ignorefiles_add(\".git/**\")\n    self._XMAKE_FILESYNC = xmake_filesync\nend\n\n-- get class\nfunction remote_build_server:class()\n    return remote_build_server\nend\n\n-- get work directory\nfunction remote_build_server:workdir()\n    local workdir = config.get(\"remote_build.workdir\")\n    if not workdir then\n        workdir = path.join(global.directory(), \"service\", \"server\", \"remote_build\")\n    end\n    return workdir\nend\n\n-- get xmake sourcedir directory\nfunction remote_build_server:xmake_sourcedir()\n    return path.join(self:workdir(), \"xmake_source\")\nend\n\n-- get filesync for xmakesrc\nfunction remote_build_server:_xmake_filesync()\n    return self._XMAKE_FILESYNC\nend\n\n-- on handle message\nfunction remote_build_server:_on_handle(stream, msg)\n    local session_id = msg:session_id()\n    local session = self:_session(session_id)\n    vprint(\"%s: %s: <session %s>: on handle message(%d)\", self, stream:sock(), session_id, msg:code())\n    vprint(msg:body())\n    session:stream_set(stream)\n    local respmsg = msg:clone()\n    local session_errs\n    local session_ok = try\n    {\n        function()\n            if self:need_verfiy() then\n                local ok, errors = self:verify_user(msg:token(), stream:sock():peeraddr())\n                if not ok then\n                    session_errs = errors\n                    return false\n                end\n            end\n            if msg:is_connect() then\n                session:open()\n            else\n                assert(session:is_connected(), \"session has not been connected!\")\n                if msg:is_diff() then\n                    session:diff(respmsg)\n                elseif msg:is_sync() then\n                    session:sync(respmsg)\n                elseif msg:is_pull() then\n                    session:pull(respmsg)\n                elseif msg:is_clean() then\n                    session:clean(respmsg)\n                elseif msg:is_runcmd() then\n                    session:runcmd(respmsg)\n                end\n            end\n            return true\n        end,\n        catch\n        {\n            function (errors)\n                if errors then\n                    session_errs = tostring(errors)\n                    vprint(session_errs)\n                end\n            end\n        }\n    }\n    respmsg:status_set(session_ok)\n    if not session_ok and session_errs then\n        respmsg:errors_set(session_errs)\n    end\n    local ok = stream:send_msg(respmsg) and stream:flush()\n    vprint(\"%s: %s: <session %s>: send %s\", self, stream:sock(), session_id, ok and \"ok\" or \"failed\")\nend\n\n-- get session\nfunction remote_build_server:_session(session_id)\n    local session = self._SESSIONS[session_id]\n    if not session then\n        session = server_session(self, session_id)\n        self._SESSIONS[session_id] = session\n    end\n    return session\nend\n\n-- close session\nfunction remote_build_server:_session_close(session_id)\n    self._SESSIONS[session_id] = nil\nend\n\nfunction remote_build_server:__tostring()\n    return \"<remote_build_server>\"\nend\n\nfunction main(daemon)\n    local instance = remote_build_server()\n    instance:init(daemon ~= nil)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_build/server_session.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server_session.lua\n--\n\n-- imports\nimport(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.object\")\nimport(\"core.base.global\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.remote_build.filesync\", {alias = \"new_filesync\"})\n\n-- define module\nlocal server_session = server_session or object()\n\n-- init server session\nfunction server_session:init(server, session_id)\n    self._ID = session_id\n    self._SERVER = server\n    local filesync = new_filesync(self:sourcedir(), path.join(self:workdir(), \"manifest.txt\"))\n    filesync:ignorefiles_add(\".git/**\")\n    filesync:ignorefiles_add(\".xmake/**\")\n    self._FILESYNC = filesync\nend\n\n-- get server session id\nfunction server_session:id()\n    return self._ID\nend\n\n-- get server\nfunction server_session:server()\n    return self._SERVER\nend\n\n-- open server session\nfunction server_session:open()\n    if self:is_connected() then\n        return\n    end\n\n    -- ensure source directory\n    self:_ensure_sourcedir()\n\n    -- update status\n    local status = self:status()\n    status.connected = true\n    status.session_id = self:id()\n    self:status_save()\nend\n\n-- close server session\nfunction server_session:close()\n    if not self:is_connected() then\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = false\n    status.session_id = self:id()\n    self:status_save()\nend\n\n-- set stream\nfunction server_session:stream_set(stream)\n    self._STREAM = stream\nend\n\n-- get stream\nfunction server_session:stream()\n    return self._STREAM\nend\n\n-- diff files\nfunction server_session:diff(respmsg)\n    local body = respmsg:body()\n\n    -- ensure sourcedir\n    self:_ensure_sourcedir()\n\n    -- do snapshot\n    local filesync = body.xmakesrc and self:_xmake_filesync() or self:_filesync()\n    local manifest_server = assert(filesync:snapshot(), \"server manifest not found!\")\n    local manifest_client = assert(body.manifest, \"client manifest not found!\")\n    vprint(\"%s: diff files in %s ..\", self, filesync:rootdir())\n\n    -- get all files\n    local fileitems = hashset.new()\n    for fileitem, _ in pairs(manifest_client) do\n        fileitems:insert(fileitem)\n    end\n    for fileitem, _ in pairs(manifest_server) do\n        fileitems:insert(fileitem)\n    end\n\n    -- do diff\n    local removed = {}\n    local modified = {}\n    local inserted = {}\n    local changed = false\n    for _, fileitem in fileitems:keys() do\n        local manifest_info_client = manifest_client[fileitem]\n        local manifest_info_server = manifest_server[fileitem]\n        if manifest_info_client and manifest_info_server\n            and manifest_info_client.sha256 ~= manifest_info_server.sha256 then\n            table.insert(modified, fileitem)\n            changed = true\n            vprint(\"[*]: %s\", fileitem)\n        elseif not manifest_info_server and manifest_info_client then\n            table.insert(inserted, fileitem)\n            changed = true\n            vprint(\"[+]: %s\", fileitem)\n        elseif manifest_info_server and not manifest_info_client then\n            table.insert(removed, fileitem)\n            changed = true\n            vprint(\"[-]: %s\", fileitem)\n        end\n    end\n    body.manifest = {changed = changed, removed = removed, inserted = inserted, modified = modified}\n    vprint(\"%s: diff files ok\", self)\nend\n\n-- sync files\nfunction server_session:sync(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local manifest = assert(body.manifest, \"manifest not found!\")\n    local filesync = body.xmakesrc and self:_xmake_filesync() or self:_filesync()\n    local sourcedir = body.xmakesrc and self:xmake_sourcedir() or self:sourcedir()\n    local archivedir = os.tmpfile() .. \".dir\"\n    vprint(\"%s: sync files in %s ..\", self, sourcedir)\n    if self:_recv_syncfiles(manifest, archivedir) then\n\n        -- do sync\n        for _, fileitem in ipairs(manifest.inserted) do\n            vprint(\"[+]: %s\", fileitem)\n            local filepath_server = path.join(sourcedir, fileitem)\n            local filepath_client = path.join(archivedir, fileitem)\n            os.cp(filepath_client, filepath_server)\n            filesync:update(fileitem, filepath_server)\n        end\n        for _, fileitem in ipairs(manifest.modified) do\n            vprint(\"[*]: %s\", fileitem)\n            local filepath_server = path.join(sourcedir, fileitem)\n            local filepath_client = path.join(archivedir, fileitem)\n            os.cp(filepath_client, filepath_server)\n            filesync:update(fileitem, filepath_server)\n        end\n        for _, fileitem in ipairs(manifest.removed) do\n            vprint(\"[-]: %s\", fileitem)\n            local filepath_server = path.join(sourcedir, fileitem)\n            os.rm(filepath_server)\n            filesync:remove(fileitem)\n        end\n        filesync:manifest_save()\n    else\n        raise(\"receive files failed!\")\n    end\n    os.tryrm(archivedir)\n    vprint(\"%s: sync files ok\", self)\nend\n\n-- pull file\nfunction server_session:pull(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local filepattern = body.filename\n    vprint(\"pull %s ..\", filepattern)\n\n    -- get files\n    local filepaths = os.files(path.join(self:sourcedir(), filepattern))\n    local fileitems = {}\n    for _, filepath in ipairs(filepaths) do\n        local fileitem = path.relative(filepath, self:sourcedir())\n        if is_host(\"windows\") then\n            fileitem = fileitem:gsub(\"\\\\\", \"/\")\n        end\n        if fileitem:startswith(\"./\") then\n            fileitem = fileitem:sub(3)\n        end\n        table.insert(fileitems, fileitem)\n    end\n    vprint(fileitems)\n\n    -- send files\n    body.fileitems = fileitems\n    respmsg:status_set(true)\n    if stream:send_msg(respmsg) then\n        for _, fileitem in ipairs(fileitems) do\n            local filepath = path.join(self:sourcedir(), fileitem)\n            vprint(\"sending %s ..\", filepath)\n            if not stream:send_file(filepath, {compress = os.filesize(filepath) > 4096}) then\n                raise(\"send %s failed!\", filepath)\n            end\n        end\n    end\nend\n\n-- clean files\nfunction server_session:clean(respmsg)\n    local body = respmsg:body()\n    vprint(\"%s: clean files in %s ..\", self, self:workdir())\n    os.tryrm(self:sourcedir())\n    os.tryrm(path.join(self:workdir(), \"manifest.txt\"))\n    if body.all then\n        for _, sessiondir in ipairs(os.dirs(path.join(self:server():workdir(), \"sessions\", \"*\"))) do\n            os.tryrm(path.join(sessiondir, \"source\"))\n            os.tryrm(path.join(sessiondir, \"manifest.txt\"))\n        end\n        os.tryrm(self:xmake_sourcedir())\n        os.tryrm(path.join(self:server():workdir(), \"xmakesrc_manifest.txt\"))\n    end\n    vprint(\"%s: clean files ok\", self)\nend\n\n-- run command\nfunction server_session:runcmd(respmsg)\n    local body = respmsg:body()\n    local program = body.program\n    local argv = body.argv\n    vprint(\"%s: run command(%s) ..\", self, os.args(table.join(program, argv)))\n\n    -- init pipes\n    local stdin_rpipe, stdin_wpipe = pipe.openpair(\"BA\") -- rpipe (block)\n    local stdin_wpipeopt = {wpipe = stdin_wpipe, stop = false}\n    local stdout_rpipe, stdout_wpipe = pipe.openpair()\n    local stdout_rpipeopt = {rpipe = stdout_rpipe, stop = false}\n\n    -- read and write pipe\n    local group_name = \"remote_build/runcmd\"\n    scheduler.co_group_begin(group_name, function (co_group)\n        scheduler.co_start(self._write_pipe, self, stdin_wpipeopt)\n        scheduler.co_start(self._read_pipe, self, stdout_rpipeopt)\n    end)\n\n    -- run program\n    local xmakesrc\n    if os.isfile(path.join(self:xmake_sourcedir(), \"core\", \"main.lua\")) then\n        xmakesrc = self:xmake_sourcedir()\n    end\n    try { function ()\n        os.execv(program, argv, {curdir = self:sourcedir(),\n            stdout = stdout_wpipe, stderr = stdout_wpipe, stdin = stdin_rpipe,\n            envs = {XMAKE_IN_SERVICE = \"true\", XMAKE_PROGRAM_DIR = xmakesrc}})\n    end}\n    stdin_rpipe:close()\n    stdout_wpipe:close()\n\n    -- stop it\n    stdin_wpipeopt.stop = true\n    stdout_rpipeopt.stop = true\n\n    -- wait pipes exits\n    scheduler.co_group_wait(group_name)\n    vprint(\"%s: run command ok\", self)\nend\n\n-- get work directory\nfunction server_session:workdir()\n    return path.join(self:server():workdir(), \"sessions\", self:id())\nend\n\n-- is connected?\nfunction server_session:is_connected()\n    return self:status().connected\nend\n\n-- get the status\nfunction server_session:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction server_session:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get status file\nfunction server_session:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get sourcedir directory\nfunction server_session:sourcedir()\n    return path.join(self:workdir(), \"source\")\nend\n\n-- get xmake sourcedir directory\nfunction server_session:xmake_sourcedir()\n    return self:server():xmake_sourcedir()\nend\n\n-- get filesync\nfunction server_session:_filesync()\n    return self._FILESYNC\nend\n\n-- get xmake filesync\nfunction server_session:_xmake_filesync()\n    return self:server():_xmake_filesync()\nend\n\n-- ensure source directory\nfunction server_session:_ensure_sourcedir()\n    local sourcedir = self:sourcedir()\n    if not os.isdir(sourcedir) then\n        os.mkdir(sourcedir)\n    end\n    local xmake_sourcedir = self:xmake_sourcedir()\n    if not os.isdir(xmake_sourcedir) then\n        os.mkdir(xmake_sourcedir)\n    end\nend\n\n-- write data to pipe\nfunction server_session:_write_pipe(opt)\n    local buff = bytes(256)\n    local wpipe = opt.wpipe\n    vprint(\"%s: %s: writing data ..\", self, wpipe)\n    while not opt.stop do\n        local data = self:_recv_data(buff)\n        if data then\n            local real = wpipe:write(data, {block = true})\n            vprint(\"%s: %s: write bytes(%d)\", self, wpipe, real)\n            if real < 0 then\n                break\n            end\n        else\n            break\n        end\n    end\n    wpipe:close()\n    vprint(\"%s: %s: write data end\", self, wpipe)\nend\n\n-- read data from pipe\nfunction server_session:_read_pipe(opt)\n    local buff = bytes(256)\n    local rpipe = opt.rpipe\n    local verbose = option.get(\"verbose\")\n    vprint(\"%s: %s: reading data ..\", self, rpipe)\n    local leftstr = \"\"\n    while not opt.stop do\n        local real, data = rpipe:read(buff)\n        if real > 0 then\n            if verbose then\n                leftstr = leftstr .. data:str()\n                local pos = leftstr:lastof(\"\\n\", true)\n                if pos then\n                    cprint(leftstr:sub(1, pos - 1))\n                    leftstr = leftstr:sub(pos + 1)\n                end\n            end\n            if not self:_send_data(data) then\n                break\n            end\n        elseif real == 0 then\n            if rpipe:wait(pipe.EV_READ, -1) < 0 then\n                break\n            end\n        else\n            break\n        end\n    end\n    rpipe:close()\n    if #leftstr > 0 then\n        cprint(leftstr)\n    end\n    -- say end to client\n    self:_send_end()\n    vprint(\"%s: %s: read data end\", self, rpipe)\nend\n\n-- recv data from stream\nfunction server_session:_recv_data(buff)\n    local stream = self:stream()\n    local msg = stream:recv_msg({timeout = -1})\n    if msg and msg:is_data() then\n        return stream:recv(buff, msg:body().size)\n    end\nend\n\n-- send data to stream\nfunction server_session:_send_data(data)\n    local stream = self:stream()\n    if stream:send_msg(message.new_data(self:id(), data:size())) then\n        if stream:send(data) then\n            return stream:flush()\n        end\n    end\nend\n\n-- send end to stream\nfunction server_session:_send_end()\n    local stream = self:stream()\n    if stream:send_msg(message.new_end(self:id())) then\n        return stream:flush()\n    end\nend\n\n-- recv syncfiles\nfunction server_session:_recv_syncfiles(manifest, outputdir)\n    local stream = self:stream()\n    for _, fileitem in ipairs(manifest.inserted) do\n        local filepath = path.join(outputdir, fileitem)\n        if not stream:recv_file(filepath) then\n            dprint(\"%s: recv %s failed!\", self, filepath)\n            return false\n        end\n    end\n    for _, fileitem in ipairs(manifest.modified) do\n        local filepath = path.join(outputdir, fileitem)\n        if not stream:recv_file(filepath) then\n            dprint(\"%s: recv %s failed!\", self, filepath)\n            return false\n        end\n    end\n    return true\nend\n\nfunction server_session:__tostring()\n    return string.format(\"<session %s>\", self:id())\nend\n\nfunction main(server, session_id)\n    local instance = server_session()\n    instance:init(server, session_id)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_cache/client.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        client.lua\n--\n\n-- imports\nimport(\"core.base.bytes\")\nimport(\"core.base.base64\")\nimport(\"core.base.socket\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"core.base.bloom_filter\")\nimport(\"core.project.config\", {alias = \"project_config\"})\nimport(\"lib.detect.find_tool\")\nimport(\"private.service.client_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.client\")\nimport(\"private.service.stream\", {alias = \"socket_stream\"})\n\n-- define module\nlocal remote_cache_client = remote_cache_client or client()\nlocal super = remote_cache_client:class()\n\n-- init client\nfunction remote_cache_client:init()\n    super.init(self)\n\n    -- init address\n    local address = assert(config.get(\"remote_cache.connect\"), \"config(remote_cache.connect): not found!\")\n    self:address_set(address)\n\n    -- get project directory\n    local projectdir = os.projectdir()\n    local projectfile = os.projectfile()\n    if projectfile and os.isfile(projectfile) and projectdir then\n        self._PROJECTDIR = projectdir\n        self._WORKDIR = path.join(project_config.directory(), \"service\", \"remote_cache\")\n    else\n        raise(\"we need to enter a project directory with xmake.lua first!\")\n    end\n\n    -- init sockets\n    self._FREESOCKS = {}\n    self._OPENSOCKS = hashset.new()\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"remote_cache.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"remote_cache.recv_timeout\") or config.get(\"recv_timeout\") or -1\n    self._CONNECT_TIMEOUT = config.get(\"remote_cache.connect_timeout\") or config.get(\"connect_timeout\") or 10000\nend\n\n-- get class\nfunction remote_cache_client:class()\n    return remote_cache_client\nend\n\n-- connect to the remote server\nfunction remote_cache_client:connect()\n    if self:is_connected() then\n        print(\"%s: has been connected!\", self)\n        return\n    end\n\n    -- Do we need user authorization?\n    local token = config.get(\"remote_cache.token\")\n    if not token and self:user() then\n\n        -- get user password\n        cprint(\"Please input user ${bright}%s${clear} password to connect <%s:%d>:\", self:user(), self:addr(), self:port())\n        io.flush()\n        local pass = (io.read() or \"\"):trim()\n        assert(pass ~= \"\", \"password is empty!\")\n\n        -- compute user authorization\n        token = base64.encode(self:user() .. \":\" .. pass)\n        token = hash.md5(bytes(token))\n    end\n\n    -- do connect\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(socket.connect(addr, port, {timeout = self:connect_timeout()}), \"%s: server unreachable!\", self)\n    local session_id = self:session_id()\n    local ok = false\n    local errors\n    print(\"%s: connect %s:%d ..\", self, addr, port)\n    if sock then\n        local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n        if stream:send_msg(message.new_connect(session_id, {token = token})) and stream:flush() then\n            local msg = stream:recv_msg()\n            if msg then\n                vprint(msg:body())\n                if msg:success() then\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        end\n    end\n    if ok then\n        print(\"%s: connected!\", self)\n    else\n        print(\"%s: connect %s:%d failed, %s\", self, addr, port, errors or \"unknown\")\n    end\n\n    -- update status\n    local status = self:status()\n    status.addr = addr\n    status.port = port\n    status.token = token\n    status.connected = ok\n    status.session_id = session_id\n    self:status_save()\nend\n\n-- disconnect server\nfunction remote_cache_client:disconnect()\n    if not self:is_connected() then\n        print(\"%s: has been disconnected!\", self)\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.token = nil\n    status.connected = false\n    self:status_save()\n    print(\"%s: disconnected!\", self)\nend\n\n-- pull cache file\nfunction remote_cache_client:pull(cachekey, cachefile)\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(self:_sock_open(), \"open socket failed!\")\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    local exists = false\n    local extrainfo\n    dprint(\"%s: pull cache(%s) in %s:%d ..\", self, cachekey, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_pull(session_id, cachekey, {token = self:token()})) and stream:flush() then\n        if stream:recv_file(cachefile) then\n            local msg = stream:recv_msg()\n            if msg then\n                dprint(msg:body())\n                if msg:success() then\n                    ok = true\n                    exists = msg:body().exists\n                    extrainfo = msg:body().extrainfo\n                else\n                    errors = msg:errors()\n                end\n            end\n        else\n            errors = \"recv cache file failed\"\n        end\n    end\n    self:_sock_close(sock)\n    if ok then\n        dprint(\"%s: pull cache(%s) ok!\", self, cachekey)\n    else\n        dprint(\"%s: pull cache(%s) failed in %s:%d, %s\", self, cachekey, addr, port, errors or \"unknown\")\n    end\n    return exists, extrainfo\nend\n\n-- push cache file\nfunction remote_cache_client:push(cachekey, cachefile, extrainfo)\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(self:_sock_open(), \"open socket failed!\")\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    dprint(\"%s: push cache(%s) in %s:%d ..\", self, cachekey, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_push(session_id, cachekey, {token = self:token(), extrainfo = extrainfo})) and stream:flush() then\n        if stream:send_file(cachefile, {compress = os.filesize(cachefile) > 4096}) then\n            local msg = stream:recv_msg()\n            if msg then\n                dprint(msg:body())\n                if msg:success() then\n                    ok = true\n                else\n                    errors = msg:errors()\n                end\n            end\n        else\n            errors = \"send cache file failed\"\n        end\n    end\n    self:_sock_close(sock)\n    if ok then\n        dprint(\"%s: push cache(%s) ok!\", self, cachekey)\n    else\n        dprint(\"%s: push cache(%s) failed in %s:%d, %s\", self, cachekey, addr, port, errors or \"unknown\")\n    end\nend\n\n-- get cache file info\nfunction remote_cache_client:cacheinfo(cachekey)\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(self:_sock_open(), \"open socket failed!\")\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    local cacheinfo\n    dprint(\"%s: get cacheinfo(%s) in %s:%d ..\", self, cachekey, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_fileinfo(session_id, cachekey, {token = self:token()})) and stream:flush() then\n        local msg = stream:recv_msg()\n        if msg then\n            dprint(msg:body())\n            if msg:success() then\n                cacheinfo = msg:body().fileinfo\n                ok = true\n            else\n                errors = msg:errors()\n            end\n        end\n    end\n    self:_sock_close(sock)\n    if ok then\n        dprint(\"%s: get cacheinfo(%s) ok!\", self, cachekey)\n    else\n        dprint(\"%s: get cacheinfo(%s) failed in %s:%d, %s\", self, cachekey, addr, port, errors or \"unknown\")\n    end\n    return cacheinfo\nend\n\n-- get the exist info of cache in server\nfunction remote_cache_client:existinfo()\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(self:_sock_open(), \"open socket failed!\")\n    local session_id = self:session_id()\n    local errors\n    local existinfo\n    dprint(\"%s: get exist info in %s:%d ..\", self, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_existinfo(session_id, \"objectfiles\", {token = self:token()})) and stream:flush() then\n        local data = stream:recv_data()\n        if data then\n            local msg = stream:recv_msg()\n            if msg then\n                dprint(msg:body())\n                if msg:success() then\n                    local count = msg:body().count\n                    if count and count > 0 then\n                        local filter = bloom_filter.new()\n                        filter:data_set(data)\n                        existinfo = filter\n                    end\n                else\n                    errors = msg:errors()\n                end\n            end\n        else\n            errors = \"recv exist info failed\"\n        end\n    end\n    self:_sock_close(sock)\n    if existinfo then\n        dprint(\"%s: get exist info ok!\", self)\n    else\n        dprint(\"%s: get exist info failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\n    return existinfo\nend\n\n-- clean server files\nfunction remote_cache_client:clean()\n    assert(self:is_connected(), \"%s: has been not connected!\", self)\n    local addr = self:addr()\n    local port = self:port()\n    local sock = assert(self:_sock_open(), \"open socket failed!\")\n    local session_id = self:session_id()\n    local errors\n    local ok = false\n    print(\"%s: clean files in %s:%d ..\", self, addr, port)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    if stream:send_msg(message.new_clean(session_id, {token = self:token()})) and stream:flush() then\n        local msg = stream:recv_msg()\n        if msg then\n            vprint(msg:body())\n            if msg:success() then\n                ok = true\n            else\n                errors = msg:errors()\n            end\n        end\n    end\n    self:_sock_close(sock)\n    if ok then\n        print(\"%s: clean files ok!\", self)\n    else\n        print(\"%s: clean files failed in %s:%d, %s\", self, addr, port, errors or \"unknown\")\n    end\nend\n\n-- is connected?\nfunction remote_cache_client:is_connected()\n    return self:status().connected\nend\n\n-- get the status\nfunction remote_cache_client:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction remote_cache_client:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get the status file\nfunction remote_cache_client:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get the project directory\nfunction remote_cache_client:projectdir()\n    return self._PROJECTDIR\nend\n\n-- get working directory\nfunction remote_cache_client:workdir()\n    return self._WORKDIR\nend\n\n-- get user token\nfunction remote_cache_client:token()\n    return self:status().token\nend\n\n-- get the session id, only for unique project\nfunction remote_cache_client:session_id()\n    return self:status().session_id or hash.uuid(option.get(\"session\")):split(\"-\", {plain = true})[1]:lower()\nend\n\n-- set the given client address\nfunction remote_cache_client:address_set(address)\n    local addr, port, user = self:address_parse(address)\n    self._ADDR = addr\n    self._PORT = port\n    self._USER = user\nend\n\n-- get user name\nfunction remote_cache_client:user()\n    return self._USER\nend\n\n-- get the ip address\nfunction remote_cache_client:addr()\n    return self._ADDR\nend\n\n-- get the address port\nfunction remote_cache_client:port()\n    return self._PORT\nend\n\n-- is server unreachable?\nfunction remote_cache_client:unreachable()\n    return self._UNREACHABLE\nend\n\n-- open a free socket\nfunction remote_cache_client:_sock_open()\n    local freesocks = self._FREESOCKS\n    local opensocks = self._OPENSOCKS\n    if #freesocks > 0 then\n        local sock = freesocks[#freesocks]\n        table.remove(freesocks)\n        opensocks:insert(sock)\n        return sock\n    end\n\n    local addr = self:addr()\n    local port = self:port()\n    local sock = socket.connect(addr, port, {timeout = self:connect_timeout()})\n    if not sock then\n        self._UNREACHABLE = true\n        raise(\"%s: server unreachable!\", self)\n    end\n    opensocks:insert(sock)\n    return sock\nend\n\n-- close a socket\nfunction remote_cache_client:_sock_close(sock)\n    local freesocks = self._FREESOCKS\n    local opensocks = self._OPENSOCKS\n    table.insert(freesocks, sock)\n    opensocks:remove(sock)\nend\n\nfunction remote_cache_client:__gc()\n    local freesocks = self._FREESOCKS\n    local opensocks = self._OPENSOCKS\n    for _, sock in ipairs(freesocks) do\n        sock:close()\n    end\n    for _, sock in ipairs(opensocks:keys()) do\n        sock:close()\n    end\n    self._FREESOCKS = {}\n    self._OPENSOCKS = {}\nend\n\nfunction remote_cache_client:__tostring()\n    return \"<remote_cache_client>\"\nend\n\n-- is connected? we cannot depend on client:init when run action\nfunction is_connected()\n    local connected = _g.connected\n    if connected == nil then\n        -- the current process is in service? we cannot enable it\n        if os.getenv(\"XMAKE_IN_SERVICE\") then\n            connected = false\n        end\n        if connected == nil then\n            local projectdir = os.projectdir()\n            local projectfile = os.projectfile()\n            if projectfile and os.isfile(projectfile) and projectdir then\n                local workdir = path.join(project_config.directory(), \"service\", \"remote_cache\")\n                local statusfile = path.join(workdir, \"status.txt\")\n                if os.isfile(statusfile) then\n                    local status = io.load(statusfile)\n                    if status and status.connected then\n                        connected = true\n                    end\n                end\n            end\n        end\n        connected = connected or false\n        _g.connected = connected\n    end\n    return connected\nend\n\n-- new a client instance\nfunction new()\n    local instance = remote_cache_client()\n    instance:init()\n    return instance\nend\n\n-- get the singleton\nfunction singleton()\n    local instance = _g.singleton\n    if not instance then\n        config.load()\n        instance = new()\n        _g.singleton = instance\n    end\n    return instance\nend\n\nfunction main()\n    return new()\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_cache/server.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.server\")\nimport(\"private.service.remote_cache.server_session\")\nimport(\"lib.detect.find_tool\")\n\n-- define module\nlocal remote_cache_server = remote_cache_server or server()\nlocal super = remote_cache_server:class()\n\n-- init server\nfunction remote_cache_server:init(daemon)\n    super.init(self, daemon)\n\n    -- init address\n    local address = assert(config.get(\"remote_cache.listen\"), \"config(remote_cache.listen): not found!\")\n    super.address_set(self, address)\n\n    -- init handler\n    super.handler_set(self, self._on_handle)\n\n    -- init sessions\n    self._SESSIONS = {}\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"remote_cache.send_timeout\") or config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"remote_cache.recv_timeout\") or config.get(\"recv_timeout\") or -1\nend\n\n-- get class\nfunction remote_cache_server:class()\n    return remote_cache_server\nend\n\n-- get work directory\nfunction remote_cache_server:workdir()\n    local workdir = config.get(\"remote_cache.workdir\")\n    if not workdir then\n        workdir = path.join(global.directory(), \"service\", \"server\", \"remote_cache\")\n    end\n    return workdir\nend\n\n-- on handle message\nfunction remote_cache_server:_on_handle(stream, msg)\n    local session_id = msg:session_id()\n    local session = self:_session(session_id)\n    vprint(\"%s: %s: <session %s>: on handle message(%d)\", self, stream:sock(), session_id, msg:code())\n    vprint(msg:body())\n    session:stream_set(stream)\n    local respmsg = msg:clone()\n    local session_errs\n    local session_ok = try\n    {\n        function()\n            if self:need_verfiy() then\n                local ok, errors = self:verify_user(msg:token(), stream:sock():peeraddr())\n                if not ok then\n                    session_errs = errors\n                    return false\n                end\n            end\n            if msg:is_connect() then\n                session:open()\n            else\n                assert(session:is_connected(), \"session has not been connected!\")\n                if msg:is_push() then\n                    session:push(respmsg)\n                elseif msg:is_pull() then\n                    session:pull(respmsg)\n                elseif msg:is_fileinfo() then\n                    session:fileinfo(respmsg)\n                elseif msg:is_existinfo() then\n                    session:existinfo(respmsg)\n                elseif msg:is_clean() then\n                    session:clean()\n                end\n            end\n            return true\n        end,\n        catch\n        {\n            function (errors)\n                if errors then\n                    session_errs = tostring(errors)\n                    vprint(session_errs)\n                end\n            end\n        }\n    }\n    respmsg:status_set(session_ok)\n    if not session_ok and session_errs then\n        respmsg:errors_set(session_errs)\n    end\n    local ok = stream:send_msg(respmsg) and stream:flush()\n    vprint(\"%s: %s: <session %s>: send %s\", self, stream:sock(), session_id, ok and \"ok\" or \"failed\")\nend\n\n-- get session\nfunction remote_cache_server:_session(session_id)\n    local session = self._SESSIONS[session_id]\n    if not session then\n        session = server_session(self, session_id)\n        self._SESSIONS[session_id] = session\n    end\n    return session\nend\n\n-- close session\nfunction remote_cache_server:_session_close(session_id)\n    self._SESSIONS[session_id] = nil\nend\n\nfunction remote_cache_server:__tostring()\n    return \"<remote_cache_server>\"\nend\n\nfunction main(daemon)\n    local instance = remote_cache_server()\n    instance:init(daemon ~= nil)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/remote_cache/server_session.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server_session.lua\n--\n\n-- imports\nimport(\"core.base.pipe\")\nimport(\"core.base.bytes\")\nimport(\"core.base.object\")\nimport(\"core.base.global\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.scheduler\")\nimport(\"core.base.bloom_filter\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\n\n-- define module\nlocal server_session = server_session or object()\n\n-- init server session\nfunction server_session:init(server, session_id)\n    self._ID = session_id\n    self._SERVER = server\nend\n\n-- get server session id\nfunction server_session:id()\n    return self._ID\nend\n\n-- get server\nfunction server_session:server()\n    return self._SERVER\nend\n\n-- open server session\nfunction server_session:open()\n    if self:is_connected() then\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = true\n    status.session_id = self:id()\n    self:status_save()\nend\n\n-- close server session\nfunction server_session:close()\n    if not self:is_connected() then\n        return\n    end\n\n    -- update status\n    local status = self:status()\n    status.connected = false\n    status.session_id = self:id()\n    self:status_save()\nend\n\n-- pull file\nfunction server_session:pull(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local cachekey = body.filename\n    local cachefile = path.join(self:cachedir(), cachekey:sub(1, 2), cachekey)\n    local cacheinfofile = cachefile .. \".txt\"\n    vprint(\"pull cachefile(%s) ..\", cachekey)\n\n    -- send cache file\n    if os.isfile(cachefile) then\n        body.exists = true\n        if os.isfile(cacheinfofile) then\n            body.extrainfo = io.load(cacheinfofile)\n        end\n        if not stream:send_file(cachefile, {compress = os.filesize(cachefile) > 4096}) then\n            raise(\"send %s failed!\", cachefile)\n        end\n    else\n        body.exists = false\n        if not stream:send_emptydata() then\n            raise(\"send empty data failed!\")\n        end\n    end\nend\n\n-- push file\nfunction server_session:push(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local cachekey = body.filename\n    local cachefile = path.join(self:cachedir(), cachekey:sub(1, 2), cachekey)\n    local cacheinfofile = cachefile .. \".txt\"\n    vprint(\"push cachefile(%s) ..\", cachekey)\n    if not stream:recv_file(cachefile) then\n        raise(\"recv %s failed!\", cachefile)\n    end\n    if body.extrainfo then\n        io.save(cacheinfofile, body.extrainfo)\n    end\nend\n\n-- get file info\nfunction server_session:fileinfo(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local cachekey = body.filename\n    local cachefile = path.join(self:cachedir(), cachekey:sub(1, 2), cachekey)\n    body.fileinfo = {filesize = os.filesize(cachefile), exists = os.isfile(cachefile)}\n    vprint(\"get cacheinfo(%s)\", cachekey)\nend\n\n-- get exist info\nfunction server_session:existinfo(respmsg)\n    local body = respmsg:body()\n    local stream = self:stream()\n    local cachedir = self:cachedir()\n    local filter = bloom_filter.new()\n    local count = 0\n    vprint(\"get existinfo(%s) ..\", body.name)\n    for _, objectfile in ipairs(os.files(path.join(cachedir, \"*\", \"*\"))) do\n        local cachekey = path.basename(objectfile)\n        if cachekey then\n            filter:set(cachekey)\n            count = count + 1\n        end\n    end\n    if count > 0 then\n        if not stream:send_data(filter:data(), {compress = true}) then\n            raise(\"send data failed!\")\n        end\n    else\n        if not stream:send_emptydata() then\n            raise(\"send empty data failed!\")\n        end\n    end\n    body.count = count\n    vprint(\"get existinfo(%s): %d ok\", body.name, count)\nend\n\n-- clean files\nfunction server_session:clean()\n    vprint(\"%s: clean files in %s ..\", self, self:cachedir())\n    os.tryrm(self:cachedir())\n    vprint(\"%s: clean files ok\", self)\nend\n\n-- set stream\nfunction server_session:stream_set(stream)\n    self._STREAM = stream\nend\n\n-- get stream\nfunction server_session:stream()\n    return self._STREAM\nend\n\n-- get work directory\nfunction server_session:workdir()\n    return path.join(self:server():workdir(), \"sessions\", self:id())\nend\n\n-- is connected?\nfunction server_session:is_connected()\n    return self:status().connected\nend\n\n-- get the status\nfunction server_session:status()\n    local status = self._STATUS\n    local statusfile = self:statusfile()\n    if not status then\n        if os.isfile(statusfile) then\n            status = io.load(statusfile)\n        end\n        status = status or {}\n        self._STATUS = status\n    end\n    return status\nend\n\n-- save status\nfunction server_session:status_save()\n    io.save(self:statusfile(), self:status())\nend\n\n-- get status file\nfunction server_session:statusfile()\n    return path.join(self:workdir(), \"status.txt\")\nend\n\n-- get cache directory\nfunction server_session:cachedir()\n    return path.join(self:workdir(), \"cache\")\nend\n\nfunction server_session:__tostring()\n    return string.format(\"<session %s>\", self:id())\nend\n\nfunction main(server, session_id)\n    local instance = server_session()\n    instance:init(server, session_id)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/restart_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        restart_service.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.stop_service\")\nimport(\"private.service.start_service\")\n\nfunction main()\n    stop_service();\n    start_service({daemon = true});\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/rm_user.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rm_user.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.base64\")\nimport(\"core.base.bytes\")\nimport(\"core.base.hashset\")\nimport(\"private.service.service\")\nimport(\"private.service.server_config\", {alias = \"config\"})\n\nfunction main(user)\n    assert(user, \"empty user name!\")\n\n    -- get user password\n    cprint(\"Please input user ${bright}%s${clear} password:\", user)\n    io.flush()\n    local pass = (io.read() or \"\"):trim()\n    assert(pass ~= \"\", \"password is empty!\")\n\n    -- compute user authorization\n    local token = base64.encode(user .. \":\" .. pass)\n    token = hash.md5(bytes(token))\n\n    -- save to configs\n    local configs = assert(config.configs(), \"configs not found!\")\n    configs.tokens = configs.tokens or {}\n    local tokenset = hashset.from(configs.tokens)\n    if tokenset:has(token) then\n        tokenset:remove(token)\n        configs.tokens = tokenset:to_array()\n    else\n        cprint(\"User ${bright}%s${clear} not found!\", user)\n        return\n    end\n    config.save(configs)\n    cprint(\"Remove user ${bright}%s${clear} ok!\", user)\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/service/server.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.bytes\")\nimport(\"core.base.base64\")\nimport(\"core.base.hashset\")\nimport(\"core.base.socket\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.message\")\nimport(\"private.service.stream\", {alias = \"socket_stream\"})\n\n-- define module\nlocal server = server or object()\n\n-- init server\nfunction server:init(daemon)\n    self._DAEMON = daemon\n\n    -- init authorizations\n    local tokens = config.get(\"tokens\")\n    self:tokens_set(tokens)\n\n    -- init known hosts\n    local known_hosts = config.get(\"known_hosts\")\n    self:known_hosts_set(known_hosts)\n\n    -- init timeout\n    self._SEND_TIMEOUT = config.get(\"send_timeout\") or -1\n    self._RECV_TIMEOUT = config.get(\"recv_timeout\") or -1\nend\n\n-- is daemon?\nfunction server:daemon()\n    return self._DAEMON\nend\n\n-- set handler\nfunction server:handler_set(handler)\n    self._HANDLER = handler\nend\n\n-- set the given listen address\nfunction server:address_set(address)\n    local splitinfo = address:split(':', {plain = true})\n    if #splitinfo == 2 then\n        self._ADDR = splitinfo[1]\n        self._PORT = splitinfo[2]\n    else\n        self._ADDR = \"127.0.0.1\"\n        self._PORT = splitinfo[1]\n    end\n    assert(self._ADDR and self._PORT, \"invalid listen address!\")\nend\n\n-- get the listen address\nfunction server:addr()\n    return self._ADDR\nend\n\n-- get the listen port\nfunction server:port()\n    return self._PORT\nend\n\n-- get send timeout\nfunction server:send_timeout()\n    return self._SEND_TIMEOUT\nend\n\n-- get recv timeout\nfunction server:recv_timeout()\n    return self._RECV_TIMEOUT\nend\n\n-- get tokens\nfunction server:tokens()\n    return self._TOKENS\nend\n\n-- set tokens\nfunction server:tokens_set(tokens)\n    self._TOKENS = tokens and hashset.from(tokens) or hashset.new()\nend\n\n-- get known hosts\nfunction server:known_hosts()\n    return self._KNOWN_HOSTS\nend\n\n-- set known hosts\nfunction server:known_hosts_set(hosts)\n    self._KNOWN_HOSTS = hosts and hashset.from(hosts) or hashset.new()\nend\n\n-- we need to verify user\nfunction server:need_verfiy()\n    return not self:tokens():empty()\nend\n\n-- verify user\nfunction server:verify_user(token, peeraddr)\n    if not token then\n        return false, \"client has no authorization, we need to add username to connect address or token!\"\n    end\n\n    -- check authorization\n    if not self:tokens():has(token) then\n        return false, \"user and password are incorrect!\"\n    end\n\n    -- check known_hosts\n    if not self:known_hosts():empty() and peeraddr then\n        local addrinfo = peeraddr:split(\":\")\n        if addrinfo and #addrinfo == 2 then\n            local addr = addrinfo[1]\n            if not self:known_hosts():has(addr) then\n                return false, \"your host address is unknown in server!\"\n            end\n        end\n    end\n    return true\nend\n\n-- run main loop\nfunction server:runloop()\n    assert(self._HANDLER, \"no handler found!\")\n\n    -- ensure only one server process\n    local lock = io.openlock(self:lockfile())\n    if not lock:trylock() then\n        raise(\"%s: has been started!\", self)\n    end\n\n    -- save the current pid for stopping service\n    io.writefile(self:pidfile(), os.getpid())\n\n    -- run loop\n    local sock = socket.bind(self:addr(), self:port())\n    sock:listen(100)\n    print(\"%s: listening %s:%d ..\", self, self:addr(), self:port())\n    io.flush()\n    while true do\n        local sock_client = sock:accept()\n        if sock_client then\n            scheduler.co_start(function (sock)\n                self:_handle_session(sock)\n                sock:close()\n            end, sock_client)\n        end\n    end\n    io.flush()\n    sock:close()\nend\n\n-- get class\nfunction server:class()\n    return server\nend\n\n-- get pid file\nfunction server:pidfile()\n    return path.join(self:workdir(), \"server.pid\")\nend\n\n-- get lock file\nfunction server:lockfile()\n    return path.join(self:workdir(), \"server.lock\")\nend\n\n-- get working directory\nfunction server:workdir()\n    return os.tmpfile(tostring(self)) .. \".dir\"\nend\n\n-- handle session\nfunction server:_handle_session(sock)\n    print(\"%s: %s: session connected\", self, sock)\n    local stream = socket_stream(sock, {send_timeout = self:send_timeout(), recv_timeout = self:recv_timeout()})\n    while true do\n        local msg = stream:recv_object({timeout = -1})\n        if msg then\n            local ok = try\n            {\n                function ()\n                    self:_HANDLER(stream, message(msg))\n                    return true\n                end,\n                catch\n                {\n                    function (errors)\n                        vprint(errors)\n                    end\n                }\n            }\n            if not ok then\n                break\n            end\n        else\n            break\n        end\n    end\n    print(\"%s: %s: session end\", self, sock)\nend\n\nfunction server:__tostring()\n    return \"<server>\"\nend\n\nfunction main()\n    local instance = server()\n    instance:init()\n    return instance\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/server_config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        server_config.lua\n--\n\n-- imports\nimport(\"core.base.global\")\nimport(\"core.base.base64\")\nimport(\"core.base.bytes\")\n\n-- generate a token\nfunction _generate_token()\n    return hash.md5(bytes(base64.encode(hash.uuid())))\nend\n\n-- generate a default config file\nfunction _generate_configfile()\n    local filepath = configfile()\n    assert(not _g.configs and not os.isfile(filepath))\n    local servicedir = path.join(global.directory(), \"service\", \"server\")\n    local token = _generate_token()\n    print(\"generating the config file to %s ..\", filepath)\n    cprint(\"an token(${bright yellow}%s${clear}) is generated, we can use this token to connect service.\", token)\n    local configs = {\n        logfile = path.join(servicedir, \"logs.txt\"),\n        known_hosts = {\n        --    \"127.0.0.1\"\n        },\n        tokens = {\n            token\n        },\n        send_timeout = -1,\n        recv_timeout = -1,\n        remote_build = {\n            listen = \"0.0.0.0:9691\",\n            workdir = path.join(servicedir, \"remote_build\"),\n        },\n        remote_cache = {\n            listen = \"0.0.0.0:9692\",\n            workdir = path.join(servicedir, \"remote_cache\"),\n        },\n        distcc_build = {\n            listen = \"0.0.0.0:9693\",\n            workdir = path.join(servicedir, \"distcc_build\"),\n            toolchains = {\n                ndk = {\n                }\n            }\n        }\n    }\n    save(configs)\nend\n\n-- get config file path\nfunction configfile()\n    return path.join(global.directory(), \"service\", \"server.conf\")\nend\n\n-- get all configs\nfunction configs()\n    return _g.configs\nend\n\n-- get the given config, e.g. server_config.get(\"remote_build.listen\")\nfunction get(name)\n    local value = configs()\n    for _, key in ipairs(name:split('.', {plain = true})) do\n        if type(value) == \"table\" then\n            value = value[key]\n        else\n            value = nil\n            break\n        end\n    end\n    return value\nend\n\n-- load configs\nfunction load()\n    if _g.configs == nil then\n        local filepath = configfile()\n        if not os.isfile(filepath) then\n            _generate_configfile()\n        end\n        assert(os.isfile(filepath), \"%s not found!\", filepath)\n        _g.configs = io.load(filepath)\n    end\nend\n\n-- save configs\nfunction save(configs)\n    local filepath = configfile()\n    io.save(filepath, configs, {orderkeys = true})\nend\n"
  },
  {
    "path": "xmake/modules/private/service/service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.scheduler\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.remote_build.server\", {alias = \"remote_build_server\"})\nimport(\"private.service.remote_cache.server\", {alias = \"remote_cache_server\"})\nimport(\"private.service.distcc_build.server\", {alias = \"distcc_build_server\"})\n\nfunction _start_remote_build_server(...)\n    remote_build_server(...):runloop()\nend\n\nfunction _start_remote_cache_server(...)\n    remote_cache_server(...):runloop()\nend\n\nfunction _start_distcc_build_server(...)\n    distcc_build_server(...):runloop()\nend\n\nfunction main(daemon, ...)\n    if daemon then\n        config.load()\n    end\n    local starters = {}\n    if option.get(\"remote\") then\n        table.insert(starters, _start_remote_build_server)\n    elseif option.get(\"distcc\") then\n        table.insert(starters, _start_distcc_build_server)\n    elseif option.get(\"ccache\") then\n        table.insert(starters, _start_remote_cache_server)\n    else\n        if config.get(\"remote_build\") then\n            table.insert(starters, _start_remote_build_server)\n        end\n        if config.get(\"remote_cache\") then\n            table.insert(starters, _start_remote_cache_server)\n        end\n        if config.get(\"distcc_build\") then\n            table.insert(starters, _start_distcc_build_server)\n        end\n    end\n    for _, start_server in ipairs(starters) do\n        scheduler.co_start(start_server, daemon, ...)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/show_logs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        show_logs.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.server_config\", {alias = \"config\"})\n\nfunction main()\n    local log\n    local logfile = config.get(\"logfile\")\n    while not log do\n        if os.isfile(logfile) then\n            log = io.open(logfile, \"r\")\n            break\n        end\n        os.sleep(1000)\n    end\n    while true do\n        local line = log:read(\"l\")\n        if line and #line > 0 then\n            print(line)\n        else\n            os.sleep(500)\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/show_status.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        show_status.lua\n--\n\n-- imports\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\n\nfunction main()\n    local client = remote_build_client()\n    local status = client:status()\n    if status then\n        print(\"%s: connected\", client)\n        print(status)\n    else\n        print(\"%s: disconnected\", client)\n    end\nend\n\n\n\n"
  },
  {
    "path": "xmake/modules/private/service/start_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        start_service.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.project\")\nimport(\"private.service.server_config\", {alias = \"config\"})\nimport(\"private.service.service\")\n\nfunction main(opt)\n\n    -- start service\n    opt = opt or {}\n    if opt.daemon then\n        local argv = {\"lua\"}\n        if option.get(\"verbose\") then\n            table.insert(argv, \"-v\")\n        end\n        if option.get(\"diagnosis\") then\n            table.insert(argv, \"-D\")\n        end\n        table.insert(argv, \"private.service.service\")\n        table.insert(argv, \"--daemon\")\n        local logfile = config.get(\"logfile\")\n        if logfile then\n            local logdir = path.directory(logfile)\n            if not os.isdir(logdir) then\n                os.mkdir(logdir)\n            end\n        end\n        local tmpdir = os.tmpfile() .. \".dir\"\n        if not os.isdir(tmpdir) then\n            os.mkdir(tmpdir)\n        end\n        try\n        {\n            function()\n                os.execv(os.programfile(), argv, {detach = true, curdir = tmpdir, stdout = logfile, stderr = logfile})\n            end,\n            catch\n            {\n                function (errors)\n                    io.cat(logfile)\n                    raise(errors)\n                end\n            }\n        }\n    else\n        service()\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/stop_service.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        stop_service.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.remote_build.server\", {alias = \"remote_build_server\"})\nimport(\"private.service.remote_cache.server\", {alias = \"remote_cache_server\"})\nimport(\"private.service.distcc_build.server\", {alias = \"distcc_build_server\"})\n\nfunction _stop_remote_build_server(...)\n    local pidfile = remote_build_server(...):pidfile()\n    if pidfile and os.isfile(pidfile) then\n        local pid = io.readfile(pidfile)\n        if pid then\n            pid = pid:trim()\n            try { function ()\n                if is_host(\"windows\") then\n                    os.run(\"taskkill /f /t /pid %s\", pid)\n                else\n                    os.run(\"kill -9 %s\", pid)\n                end\n                print(\"service[%s]: stopped\", pid)\n            end}\n        end\n        os.rm(pidfile)\n    end\nend\n\nfunction _stop_remote_cache_server(...)\n    local pidfile = remote_cache_server(...):pidfile()\n    if pidfile and os.isfile(pidfile) then\n        local pid = io.readfile(pidfile)\n        if pid then\n            pid = pid:trim()\n            try { function ()\n                if is_host(\"windows\") then\n                    os.run(\"taskkill /f /t /pid %s\", pid)\n                else\n                    os.run(\"kill -9 %s\", pid)\n                end\n                print(\"service[%s]: stopped\", pid)\n            end}\n        end\n        os.rm(pidfile)\n    end\nend\n\nfunction _stop_distcc_build_server(...)\n    local pidfile = distcc_build_server(...):pidfile()\n    if pidfile and os.isfile(pidfile) then\n        local pid = io.readfile(pidfile)\n        if pid then\n            pid = pid:trim()\n            try { function ()\n                if is_host(\"windows\") then\n                    os.run(\"taskkill /f /t /pid %s\", pid)\n                else\n                    os.run(\"kill -9 %s\", pid)\n                end\n                print(\"service[%s]: stopped\", pid)\n            end}\n        end\n        os.rm(pidfile)\n    end\nend\n\nfunction main(...)\n    local stoppers = {_stop_remote_build_server, _stop_remote_cache_server, _stop_distcc_build_server}\n    for _, stop_server in ipairs(stoppers) do\n        stop_server(...)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/service/stream.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        stream.lua\n--\n\n-- imports\nimport(\"core.base.bit\")\nimport(\"core.base.object\")\nimport(\"core.base.socket\")\nimport(\"core.base.bytes\")\nimport(\"core.compress.lz4\")\nimport(\"private.service.message\")\n\n-- define module\nlocal stream = stream or object()\n\n-- max data buffer size\nlocal STREAM_DATA_MAXN = 10 * 1024 * 1024\n\n-- the header flags\nlocal HEADER_FLAG_COMPRESS_LZ4 = 1\n\n-- init stream\nfunction stream:init(sock, opt)\n    opt = opt or {}\n    self._SOCK = sock\n    self._BUFF = bytes(65536)\n    self._RCACHE = bytes(8192)\n    self._RCACHE_SIZE = 0\n    self._WCACHE = bytes(8192)\n    self._WCACHE_SIZE = 0\n    self._SEND_TIMEOUT = opt.send_timeout and opt.send_timeout or -1\n    self._RECV_TIMEOUT = opt.recv_timeout and opt.recv_timeout or -1\nend\n\n-- get socket\nfunction stream:sock()\n    return self._SOCK\nend\n\n-- get send timeout\nfunction stream:send_timeout()\n    return self._SEND_TIMEOUT\nend\n\n-- get send timeout\nfunction stream:recv_timeout()\n    return self._RECV_TIMEOUT\nend\n\n-- flush data\nfunction stream:flush(opt)\n    opt = opt or {}\n    local cache = self._WCACHE\n    local cache_size = self._WCACHE_SIZE\n    if cache_size > 0 then\n        local sock = self._SOCK\n        local real = sock:send(cache, {block = true, last = cache_size, timeout = opt.timeout or self:send_timeout()})\n        if real > 0 then\n            self._WCACHE_SIZE = 0\n            return true\n        end\n    else\n        return true\n    end\nend\n\n-- send the given bytes (small data)\nfunction stream:send(data, start, last, opt)\n    opt = opt or {}\n    start = start or 1\n    last = last or data:size()\n    local size = last + 1 - start\n    assert(size <= data:size())\n\n    -- write data to cache first\n    local cache = self._WCACHE\n    local cache_size = self._WCACHE_SIZE\n    local cache_maxn = cache:size()\n    local cache_left = cache_maxn - cache_size\n    if size <= cache_left then\n        cache:copy2(cache_size + 1, data, start, last)\n        cache_size = cache_size + size\n        self._WCACHE_SIZE = cache_size\n        return true\n    elseif cache_left > 0 then\n        cache:copy2(cache_size + 1, data, start, start + cache_left - 1)\n        cache_size = cache_size + cache_left\n        start = start + cache_left\n        size = last + 1 - start\n    end\n    assert(cache_size == cache_maxn)\n\n    -- send data to socket\n    local sock = self._SOCK\n    local real = sock:send(cache, {block = true, timeout = opt.timeout or self:send_timeout()})\n    if real > 0 then\n        -- copy left data to cache\n        assert(size <= cache_maxn)\n        cache:copy2(1, data, start, last)\n        self._WCACHE_SIZE = size\n        return true\n    end\nend\n\n-- send message\nfunction stream:send_msg(msg, opt)\n    return self:send_object(msg:body(), opt)\nend\n\n-- send object\nfunction stream:send_object(obj, opt)\n    local str, errors = string.serialize(obj, {strip = true, indent = false})\n    if errors then\n        raise(errors)\n    end\n    if str then\n        return self:send_string(str, opt)\n    end\nend\n\n-- send data header\nfunction stream:send_header(size, flags, opt)\n    local buff = self._BUFF\n    buff:u32be_set(1, size)\n    buff:u8_set(5, flags or 0)\n    return self:send(buff, 1, 5, opt)\nend\n\n-- send data\nfunction stream:send_data(data, opt)\n    opt = opt or {}\n    local flags = 0\n    if opt.compress then\n        flags = bit.bor(flags, HEADER_FLAG_COMPRESS_LZ4)\n        data = lz4.compress(data)\n    end\n    local size = data:size()\n    assert(size < STREAM_DATA_MAXN, \"too large data size(%d)\", size)\n    if self:send_header(size, flags, opt) then\n        local send = 0\n        local cache = self._WCACHE\n        local cache_maxn = cache:size()\n        while send < size do\n            local left = math.min(cache_maxn, size - send)\n            if self:send(data, send + 1, send + left, opt) then\n                send = send + left\n            else\n                break\n            end\n        end\n        if send == size then\n            return true\n        end\n    end\nend\n\n-- send string\nfunction stream:send_string(str, opt)\n    return self:send_data(bytes(str), opt)\nend\n\n-- send empty data\nfunction stream:send_emptydata(opt)\n    return self:send_header(0, opt)\nend\n\n-- send file\nfunction stream:send_file(filepath, opt)\n\n    -- send header\n    opt = opt or {}\n    local flags = 0\n    local tmpfile\n    local originsize = os.filesize(filepath)\n    if opt.compress and originsize > 0 then\n        flags = bit.bor(flags, HEADER_FLAG_COMPRESS_LZ4)\n        tmpfile = os.tmpfile()\n        lz4.compress_file(filepath, tmpfile)\n        filepath = tmpfile\n    end\n\n    -- send header\n    local size = os.filesize(filepath)\n    if not self:send_header(size, flags) then\n        return\n    end\n\n    -- empty file?\n    if size == 0 then\n        return 0, 0\n    end\n\n    -- flush cache data first\n    if not self:flush() then\n        return\n    end\n\n    -- send file\n    local ok = false\n    local sock = self._SOCK\n    local file = io.open(filepath, 'rb')\n    if file then\n        local send = sock:sendfile(file, {block = true, timeout = opt.timeout or self:send_timeout()})\n        if send > 0 then\n            ok = true\n        end\n        file:close()\n    end\n    if tmpfile then\n        os.tryrm(tmpfile)\n    end\n    if ok then\n        return originsize, size\n    end\nend\n\n-- send files\nfunction stream:send_files(filepaths, opt)\n    local size\n    local compressed_size\n    for _, filepath in ipairs(filepaths) do\n        local real, compressed_real = self:send_file(filepath, opt)\n        if real then\n            size = (size or 0) + real\n            compressed_size = (compressed_size or 0) + compressed_real\n        else\n            return\n        end\n    end\n    return size, compressed_size\nend\n\n-- recv the given bytes\nfunction stream:recv(buff, size, opt)\n    opt = opt or {}\n    assert(size <= buff:size(), \"too large size(%d)\", size)\n\n    -- read data from cache first\n    local buffsize = 0\n    local cache = self._RCACHE\n    local cache_size = self._RCACHE_SIZE\n    local cache_maxn = cache:size()\n    if size <= cache_size then\n        buff:copy(cache, 1, size)\n        cache:move(size + 1, cache_size)\n        cache_size = cache_size - size\n        self._RCACHE_SIZE = cache_size\n        return buff:slice(1, size)\n    elseif cache_size > 0 then\n        buff:copy(cache, 1, cache_size)\n        buffsize = cache_size\n        cache_size = 0\n    end\n    assert(cache_size == 0)\n\n    -- recv data from socket\n    local real = 0\n    local data = nil\n    local wait = false\n    local sock = self._SOCK\n    while buffsize < size do\n        real, data = sock:recv(cache)\n        if real > 0 then\n            -- append data to buffer\n            local leftsize = size - buffsize\n            if real < leftsize then\n                buff:copy2(buffsize + 1, data)\n                buffsize = buffsize + real\n            else\n                buff:copy2(buffsize + 1, data, 1, leftsize)\n                buffsize = buffsize + leftsize\n\n                -- move left cache to head\n                cache_size = real - leftsize\n                if cache_size > 0 then\n                    cache:move(leftsize + 1, real)\n                end\n                self._RCACHE_SIZE = cache_size\n                return buff:slice(1, buffsize)\n            end\n            wait = false\n        elseif real == 0 and not wait then\n            local ok = sock:wait(socket.EV_RECV, opt.timeout or self:recv_timeout())\n            if ok == socket.EV_RECV then\n                wait = true\n            else\n                assert(ok ~= 0, \"%s: recv timeout!\", self)\n                break\n            end\n        else\n            break\n        end\n    end\nend\n\n-- recv message\nfunction stream:recv_msg(opt)\n    local body = self:recv_object(opt)\n    if body then\n        return message(body)\n    end\nend\n\n-- recv object\nfunction stream:recv_object(opt)\n    local str = self:recv_string(opt)\n    if str then\n        local obj, errors = str:deserialize()\n        if errors then\n            raise(errors)\n        end\n        return obj\n    end\nend\n\n-- recv header\nfunction stream:recv_header(opt)\n    local data = self:recv(self._BUFF, 5, opt)\n    if data then\n        local size = data:u32be(1)\n        local flags = data:u8(5)\n        return size, flags\n    end\nend\n\n-- recv data\nfunction stream:recv_data(opt)\n    local size, flags = self:recv_header(opt)\n    if size then\n        local recv = 0\n        assert(size < STREAM_DATA_MAXN, \"too large data size(%d)\", size)\n        local buff = bytes(size)\n        while recv < size do\n            local data = self:recv(buff:slice(recv + 1), size - recv, opt)\n            if data then\n                recv = recv + data:size()\n            else\n                break\n            end\n        end\n        if recv == size then\n            if bit.band(flags, HEADER_FLAG_COMPRESS_LZ4) == HEADER_FLAG_COMPRESS_LZ4 then\n                buff = lz4.decompress(buff)\n            end\n            return buff\n        end\n    end\nend\n\n-- recv string\nfunction stream:recv_string(opt)\n    local data = self:recv_data(opt)\n    if data then\n        return data:str()\n    end\nend\n\n-- recv file\nfunction stream:recv_file(filepath, opt)\n    local size, flags = self:recv_header(opt)\n    if size then\n        -- empty file? we just create an empty file\n        if size == 0 then\n            local file = io.open(filepath, \"wb\")\n            file:close()\n            return size\n        end\n        local result\n        local tmpfile = os.tmpfile({ramdisk = false})\n        if bit.band(flags, HEADER_FLAG_COMPRESS_LZ4) == HEADER_FLAG_COMPRESS_LZ4 then\n            result = self:_recv_compressed_file(lz4.decompress_stream(), tmpfile, size, opt)\n        else\n            local buff = self._BUFF\n            local recv = 0\n            local file = io.open(tmpfile, \"wb\")\n            while recv < size do\n                local data = self:recv(buff, math.min(buff:size(), size - recv), opt)\n                if data then\n                    file:write(data)\n                    recv = recv + data:size()\n                end\n            end\n            file:close()\n            if recv == size then\n                result = recv\n            end\n        end\n        if result then\n            os.cp(tmpfile, filepath)\n        end\n        os.tryrm(tmpfile)\n        return result\n    end\nend\n\n-- recv files\nfunction stream:recv_files(filepaths, opt)\n    local size, decompressed_size\n    for _, filepath in ipairs(filepaths) do\n        local real, decompressed_real = self:recv_file(filepath, opt)\n        if real then\n            size = (size or 0) + real\n            decompressed_size = (decompressed_size or 0) + decompressed_real\n        else\n            return\n        end\n    end\n    return size, decompressed_size\nend\n\n-- recv compressed file\nfunction stream:_recv_compressed_file(lz4_stream, filepath, size, opt)\n    local buff = self._BUFF\n    local recv = 0\n    local file = io.open(filepath, \"wb\")\n    local decompressed_size = 0\n    while recv < size do\n        local data = self:recv(buff, math.min(buff:size(), size - recv), opt)\n        if data then\n            local write = 0\n            local writesize = data:size()\n            while write < writesize do\n                local blocksize = math.min(writesize - write, 8192)\n                local real = lz4_stream:write(data, {start = write + 1, last = write + blocksize})\n                if real > 0 then\n                    while true do\n                        local decompressed_real, decompressed_data = lz4_stream:read(buff, 8192)\n                        if decompressed_real > 0 and decompressed_data then\n                            file:write(decompressed_data)\n                            decompressed_size = decompressed_size + decompressed_real\n                        else\n                            break\n                        end\n                    end\n                end\n                write = write + blocksize\n            end\n            recv = recv + data:size()\n        end\n    end\n    file:close()\n    if recv == size then\n        return recv, decompressed_size\n    end\nend\n\nfunction stream:__tostring()\n    return string.format(\"<stream: %s>\", self:sock())\nend\n\nfunction main(sock, opt)\n    local instance = stream()\n    instance:init(sock, opt)\n    return instance\nend\n"
  },
  {
    "path": "xmake/modules/private/service/sync_files.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sync_files.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.service.remote_build.client\", {alias = \"remote_build_client\"})\n\nfunction main()\n    remote_build_client():sync()\nend\n\n\n"
  },
  {
    "path": "xmake/modules/private/tools/ccache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        ccache.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\n\n-- get ccache tool\nfunction get()\n    local ccache = _g.ccache\n    if ccache == nil and config.get(\"ccache\") then\n        ccache = find_tool(\"ccache\")\n        if not ccache then\n            ccache = find_tool(\"sccache\")\n        end\n        _g.ccache = ccache or false\n    end\n    return ccache or nil\nend\n\nfunction exists()\n    return get() ~= nil\nend\n\n-- uses ccache to wrap the program and arguments\n--\n-- e.g. ccache program argv\n--\nfunction cmdargv(program, argv)\n\n    -- uses ccache?\n    local ccache = get()\n    if ccache then\n\n        -- parse the filename and arguments, e.g. \"xcrun -sdk macosx clang\"\n        if not os.isexec(program) then\n            argv = table.join(program:split(\"%s\"), argv)\n        else\n            table.insert(argv, 1, program)\n        end\n        return ccache.program, argv\n    end\n    return program, argv\nend\n"
  },
  {
    "path": "xmake/modules/private/tools/codesign.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        codesign.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.cache.global_detectcache\")\n\n-- get mobile provision name\nfunction _get_mobile_provision_name(provision)\n    local p = provision:find(\"<key>Name</key>\", 1, true)\n    if p then\n        local e = provision:find(\"</string>\", p, true)\n        if e then\n            return provision:sub(p, e + 9):match(\"<string>(.*)</string>\")\n        end\n    end\nend\n\n-- get mobile provision entitlements\nfunction _get_mobile_provision_entitlements(provision)\n    local p = provision:find(\"<key>Entitlements</key>\", 1, true)\n    if p then\n        local e = provision:find(\"</dict>\", p, true)\n        if e then\n            return provision:sub(p, e + 7):match(\"(<dict>.*</dict>)\")\n        end\n    end\nend\n\n-- get codesign identities\nfunction codesign_identities()\n    local identities = global_detectcache:get2(\"codesign\", \"identities\")\n    local lastime = global_detectcache:get2(\"codesign\", \"lastime\")\n    if type(lastime) == \"number\" and os.time() - lastime > 3 * 24 * 3600 then -- > 3 days\n        identities = nil\n    end\n    if identities == nil then\n        identities = {}\n        local results = try { function() return os.iorun(\"/usr/bin/security find-identity\") end }\n        if results then\n            local splitinfo = results:split(\"Valid identities only\", {plain = true})\n            if splitinfo and #splitinfo > 1 then\n                results = splitinfo[2]\n            end\n        end\n        if not results then\n            -- it may be slower\n            results = try { function() return os.iorun(\"/usr/bin/security find-identity -v -p codesigning\") end }\n        end\n        if results then\n            for _, line in ipairs(results:split('\\n', {plain = true})) do\n                local sign, identity = line:match(\"%) (%w+) \\\"(.+)\\\"\")\n                if sign and identity then\n                    identities[identity] = sign\n                end\n            end\n        end\n        global_detectcache:set2(\"codesign\", \"identities\", identities or false)\n        global_detectcache:set2(\"codesign\", \"lastime\", os.time())\n        global_detectcache:save()\n    end\n    return identities or nil\nend\n\n-- get provision profiles only for mobile\nfunction mobile_provisions()\n    local mobile_provisions = global_detectcache:get2(\"codesign\", \"mobile_provisions\")\n    local lastime = global_detectcache:get2(\"codesign\", \"lastime\")\n    if type(lastime) == \"number\" and os.time() - lastime > 3 * 24 * 3600 then -- > 3 days\n        mobile_provisions = nil\n    end\n    if mobile_provisions == nil then\n        mobile_provisions = {}\n        local files = os.files(\"~/Library/MobileDevice/Provisioning Profiles/*.mobileprovision\")\n        for _, file in ipairs(files) do\n            local results = try { function() return os.iorunv(\"/usr/bin/security\", {\"cms\", \"-D\", \"-i\", file}) end }\n            if results then\n                local name = _get_mobile_provision_name(results)\n                if name then\n                    mobile_provisions[name] = results\n                end\n            end\n        end\n        global_detectcache:set2(\"codesign\", \"mobile_provisions\", mobile_provisions or false)\n        global_detectcache:set2(\"codesign\", \"lastime\", os.time())\n        global_detectcache:save()\n    end\n    return mobile_provisions or nil\nend\n\n-- dump all information of codesign\nfunction dump()\n\n    -- only for macosx\n    assert(is_host(\"macosx\"), \"codesign: only support for macOS!\")\n\n    -- do dump\n    print(\"==================================== codesign identities ====================================\")\n    print(codesign_identities())\n    print(\"===================================== mobile provisions =====================================\")\n    print(mobile_provisions())\nend\n\n-- remove signature\nfunction unsign(programdir)\n\n    -- only for macosx\n    assert(is_host(\"macosx\"), \"codesign: only support for macOS!\")\n\n    -- get codesign\n    local codesign = find_tool(\"codesign\")\n    if not codesign then\n        return\n    end\n\n    -- remove signature\n    os.vrunv(codesign.program, {\"--remove-signature\", programdir})\nend\n\n-- get the current codesign identity of xcode\nfunction xcode_codesign_identity()\n    local codesign_identity = config.get(\"xcode_codesign_identity\")\n    if codesign_identity == nil then -- we will disable codesign_identity if be false\n        codesign_identity = global.get(\"xcode_codesign_identity\")\n    end\n    if codesign_identity == nil then\n        local identities = codesign_identities()\n        if identities then\n            for identity, _ in pairs(identities) do\n                codesign_identity = identity\n                break\n            end\n        end\n    end\n    return codesign_identity\nend\n\n-- get the current mobile provision of xcode\nfunction xcode_mobile_provision()\n    local mobile_provision = config.get(\"xcode_mobile_provision\")\n    if mobile_provision == nil then -- we will disable mobile_provision if be false\n        mobile_provision = global.get(\"xcode_mobile_provision\")\n    end\n\n    local provisions = mobile_provisions()\n    if provisions then\n        if mobile_provision == nil then\n            for provision, _ in pairs(provisions) do\n                mobile_provision = provision\n                break\n            end\n        -- valid mobile provision not found? reset it\n        elseif not provisions[mobile_provision] then\n            mobile_provision = nil\n        end\n    end\n    return mobile_provision\nend\n\nfunction main(programdir, codesign_identity, mobile_provision, opt)\n\n    -- only for macosx\n    opt = opt or {}\n    assert(is_host(\"macosx\"), \"codesign: only support for macOS!\")\n\n    -- get codesign\n    local codesign = find_tool(\"codesign\")\n    if not codesign then\n        return\n    end\n\n    -- get codesign_allocate\n    local codesign_allocate\n    local xcode_sdkdir = get_config(\"xcode\")\n    if xcode_sdkdir then\n        codesign_allocate = path.join(xcode_sdkdir, \"Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate\")\n    end\n\n    -- get codesign\n    local sign = \"-\"\n    if codesign_identity then -- we will uses sign/'-' if be false for `xmake f --xcode_codesign_identity=n`\n        local identities = codesign_identities()\n        if identities then\n            sign = identities[codesign_identity]\n            assert(sign, \"codesign: invalid sign identity(%s)!\", codesign_identity)\n        end\n    end\n\n    -- get entitlements for mobile\n    local entitlements\n    if codesign_identity and mobile_provision then\n        local provisions = mobile_provisions()\n        if provisions then\n            mobile_provision = provisions[mobile_provision]\n            if mobile_provision then\n                local entitlements_data = _get_mobile_provision_entitlements(mobile_provision)\n                if entitlements_data then\n                    entitlements = os.tmpfile() .. \".plist\"\n                    io.writefile(entitlements, string.format([[<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n%s\n</plist>\n]], entitlements_data))\n                end\n            end\n        end\n    end\n\n    -- do sign\n    local argv = {\"--force\", \"--timestamp=none\"}\n    if opt.deep then\n        table.insert(argv, \"--deep\")\n    end\n    table.insert(argv, \"--sign\")\n    table.insert(argv, sign)\n    if entitlements then\n        table.insert(argv, \"--entitlements\")\n        table.insert(argv, entitlements)\n    end\n    table.insert(argv, programdir)\n    os.vrunv(codesign.program, argv, {envs = {CODESIGN_ALLOCATE = codesign_allocate}})\n    if entitlements then\n        os.tryrm(entitlements)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/tools/go/goenv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        goenv.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\n\n-- Map xmake platform to Go OS\nfunction GOOS(plat)\n    local goos_map = {\n        windows = \"windows\",\n        mingw = \"windows\",\n        msys = \"windows\",\n        cygwin = \"windows\",\n        linux = \"linux\",\n        macosx = \"darwin\",\n        android = \"android\",\n        ios = \"ios\",\n        freebsd = \"freebsd\",\n        netbsd = \"netbsd\",\n        openbsd = \"openbsd\",\n        dragonfly = \"dragonfly\",\n        solaris = \"solaris\",\n        aix = \"aix\",\n        plan9 = \"plan9\"\n    }\n    return goos_map[plat]\nend\n\n-- Map xmake architecture to Go architecture\nfunction GOARCH(arch)\n    local goarch_map = {\n        x86 = \"386\",\n        i386 = \"386\",\n        x64 = \"amd64\",\n        x86_64 = \"amd64\",\n        amd64 = \"amd64\",\n        arm = \"arm\",\n        armv7 = \"arm\",\n        armv7s = \"arm\",\n        arm64 = \"arm64\",\n        aarch64 = \"arm64\",\n        mips = \"mips\",\n        mips64 = \"mips64\",\n        mips64le = \"mips64le\",\n        mipsle = \"mipsle\",\n        ppc = \"ppc\",\n        ppc64 = \"ppc64\",\n        ppc64le = \"ppc64le\",\n        riscv64 = \"riscv64\",\n        s390x = \"s390x\",\n        wasm = \"wasm\"\n    }\n    \n    -- try direct match first\n    if goarch_map[arch] then\n        return goarch_map[arch]\n    end\n    \n    -- try pattern matching for arm variants\n    if arch:match(\"^arm\") then\n        if arch:match(\"64\") or arch:match(\"aarch64\") then\n            return \"arm64\"\n        else\n            return \"arm\"\n        end\n    end\n    \n    -- try pattern matching for x86 variants\n    if arch:match(\"^x86\") or arch:match(\"^i386\") or arch:match(\"^i686\") then\n        return \"386\"\n    end\n    \n    if arch:match(\"^x64\") or arch:match(\"^amd64\") or arch:match(\"^x86_64\") then\n        return \"amd64\"\n    end\n    \n    return nil\nend\n\n-- Get GOROOT from Go installation\nfunction GOROOT(toolchain)\n    local go = find_tool(\"go\")\n    if go then\n        local gorootdir = try { \n            function() \n                return os.iorunv(go.program, {\"env\", \"GOROOT\"}, {envs = toolchain and toolchain:get(\"runenvs\") or nil}) \n            end \n        }\n        if gorootdir then\n            return gorootdir:trim()\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/tools/rust/check_target.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      w568w\n-- @file        check_target.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\n\n-- get rustc supported targets\n--\n-- @return          the supported target list. If rustc not found, return nil\nfunction _get_rustc_supported_target()\n    local rustc = find_tool(\"rustc\")\n    if not rustc then\n        return nil\n    end\n    local output = os.iorunv(rustc.program, {\"--print\", \"target-list\"})\n    return output:split('\\n')\nend\n\n-- check whether the target is supported by rustc\n--\n-- @param arch      the target name, e.g. x86_64-unknown-linux-gnu\n-- @param precise   whether to check the target precisely (i.e. check by rustc), otherwise only by syntax\n--\n-- @return          true if arch != nil and the target is supported by rustc, otherwise false\nfunction main(arch, precise)\n\n    if not arch then\n        return false\n    end\n\n    -- 1: check by syntax\n    local result = false\n    local archs = arch:split(\"%-\")\n    if #archs >= 2 then\n        result = true\n    else\n        wprint(\"the arch \\\"%s\\\" is NOT a valid target triple, will be IGNORED and may cause compilation errors, please check it again\", arch)\n    end\n\n    -- 2: check by rustc\n    if not precise then\n        return result\n    end\n    result = false\n    local rustc_supported_target = _get_rustc_supported_target()\n    if rustc_supported_target then\n        for _, v in ipairs(rustc_supported_target) do\n            if v == arch then\n                result = true\n                break\n            end\n        end\n        if not result then\n            wprint(\"the arch \\\"%s\\\" is NOT supported by rustc, will be IGNORED and may cause compilation errors, please check it again\", arch)\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "xmake/modules/private/tools/vstool.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vstool.lua\n--\n\n-- quietly run command with arguments list\nfunction runv(program, argv, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- if has VS_BINARY_OUTPUT dont enable unicode output\n    local envs = opt.envs or {}\n    if envs.VS_BINARY_OUTPUT then\n        return os.runv(program, argv, opt)\n    end\n\n    -- make temporary output and error file\n    local outpath = os.tmpfile()\n    local errpath = os.tmpfile()\n    local outfile = io.open(outpath, 'w')\n\n    -- enable unicode output for vs toolchains, e.g. cl.exe, link.exe and etc.\n    -- @see https://github.com/xmake-io/xmake/issues/528\n    if is_host(\"windows\") then\n        opt.envs = table.join(envs, {VS_UNICODE_OUTPUT = outfile:rawfd()})\n    end\n\n    -- execute it\n    local ok, syserrors = os.execv(program, argv, table.join(opt, {try = true, stdout = outfile, stderr = errpath}))\n\n    -- close outfile first\n    outfile:close()\n\n    -- failed?\n    if ok ~= 0 then\n\n        -- read errors\n        local encoding = is_host(\"windows\") and \"utf16le\" or nil\n        local outdata = os.isfile(outpath) and io.readfile(outpath, {encoding = encoding}) or nil\n        local errdata = os.isfile(errpath) and io.readfile(errpath) or nil\n        local errors = errdata or \"\"\n        if #errors:trim() == 0 then\n            errors = outdata or \"\"\n        end\n\n        -- make the default errors\n        if not errors or #errors == 0 then\n\n            -- get command\n            local cmd = program\n            if argv then\n                cmd = cmd .. \" \" .. os.args(argv)\n            end\n\n            -- get errors\n            if ok ~= nil then\n                errors = string.format(\"vstool.runv(%s) failed(%d)\", cmd, ok)\n            else\n                errors = string.format(\"vstool.runv(%s), %s\", cmd, syserrors and syserrors or \"unknown reason\")\n            end\n        end\n\n        -- remove the files\n        os.tryrm(outpath)\n        os.tryrm(errpath)\n\n        -- raise errors\n        os.raise({errors = errors, stderr = errdata, stdout = outdata})\n    end\n\n    -- remove the files\n    os.tryrm(outpath)\n    os.tryrm(errpath)\nend\n\n-- run command and return output and error data\nfunction iorunv(program, argv, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- if has VS_BINARY_OUTPUT dont enable unicode output\n    local envs = opt.envs or {}\n    if envs.VS_BINARY_OUTPUT then\n        return os.runv(program, argv, opt)\n    end\n\n    -- make temporary output and error file\n    local outpath = os.tmpfile()\n    local errpath = os.tmpfile()\n    local outfile = io.open(outpath, 'w')\n\n    -- enable unicode output for vs toolchains, e.g. cl.exe, link.exe and etc.\n    -- @see https://github.com/xmake-io/xmake/issues/528\n    if is_host(\"windows\") then\n        opt.envs = table.join(envs, {VS_UNICODE_OUTPUT = outfile:rawfd()})\n    end\n\n    -- run command\n    local ok, syserrors = os.execv(program, argv, table.join(opt, {try = true, stdout = outfile, stderr = errpath}))\n\n    -- get output and error data\n    outfile:close()\n    local encoding = is_host(\"windows\") and \"utf16le\" or nil\n    local outdata = os.isfile(outpath) and io.readfile(outpath, {encoding = encoding}) or nil\n    local errdata = os.isfile(errpath) and io.readfile(errpath) or nil\n\n    -- remove the temporary output and error file\n    os.tryrm(outpath)\n    os.tryrm(errpath)\n\n    -- failed?\n    if ok ~= 0 then\n\n        -- get errors\n        local errors = errdata or \"\"\n        if #errors:trim() == 0 then\n            errors = outdata or \"\"\n        end\n\n        -- make the default errors\n        if not errors or #errors == 0 then\n\n            -- get command\n            local cmd = program\n            if argv then\n                cmd = cmd .. \" \" .. os.args(argv)\n            end\n\n            -- get errors\n            if ok ~= nil then\n                errors = string.format(\"vstool.iorunv(%s) failed(%d)\", cmd, ok)\n            else\n                errors = string.format(\"vstool.iorunv(%s), %s\", cmd, syserrors and syserrors or \"unknown reason\")\n            end\n        end\n\n        -- raise errors\n        os.raise({errors = errors, stderr = errdata, stdout = outdata})\n    end\n    return outdata, errdata\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/batchcmds.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        batchcmds.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.object\")\nimport(\"core.base.tty\")\nimport(\"core.base.colors\")\nimport(\"core.project.depend\")\nimport(\"core.theme.theme\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.language.language\")\nimport(\"utils.run_script\")\nimport(\"utils.progress\", {alias = \"progress_utils\"})\nimport(\"utils.binary.rpath\", {alias = \"rpath_utils\"})\n\n-- define module\nlocal batchcmds = batchcmds or object { _init = {\"_TARGET\", \"_CMDS\", \"_DEPINFO\", \"_tip\"}}\n\n-- run command: show\nfunction _runcmd_show(cmd, opt)\n    local format = cmd.format\n    if format then\n        cprint(format, table.unpack(cmd.argv))\n    end\nend\n\n-- run command: show_progress\nfunction _runcmd_show_progress(cmd, opt)\n    local format = cmd.format\n    local progress = cmd.progress\n    if format and progress then\n        progress_utils.show(progress, format, table.unpack(cmd.argv))\n    end\nend\n\n-- run command: os.runv\nfunction _runcmd_runv(cmd, opt)\n    if cmd.program then\n        if not opt.dryrun then\n            os.runv(cmd.program, cmd.argv, cmd.opt)\n        end\n    end\nend\n\n-- run command: os.vrunv\nfunction _runcmd_vrunv(cmd, opt)\n    if cmd.program then\n        if opt.dryrun then\n            vprint(os.args(table.join(cmd.program, cmd.argv)))\n        else\n            os.vrunv(cmd.program, cmd.argv, cmd.opt)\n        end\n    end\nend\n\n-- run command: os.execv\nfunction _runcmd_execv(cmd, opt)\n    if cmd.program then\n        if not opt.dryrun then\n            os.execv(cmd.program, cmd.argv, cmd.opt)\n        end\n    end\nend\n\n-- run command: os.vexecv\nfunction _runcmd_vexecv(cmd, opt)\n    if cmd.program then\n        if opt.dryrun then\n            vprint(os.args(table.join(cmd.program, cmd.argv)))\n        else\n            os.vexecv(cmd.program, cmd.argv, cmd.opt)\n        end\n    end\nend\n\n-- run command: lua\nfunction _runcmd_lua(cmd, opt)\n    if cmd.script then\n        if not opt.dryrun then\n            local runopt = table.clone(cmd.opt) or {}\n            runopt.arguments = cmd.argv\n            runopt.quiet = true\n            -- it will run in a separate native thread, which will not block other coroutine jobs\n            runopt.thread = true\n            run_script(cmd.script, runopt)\n        end\n    end\nend\n\n-- run command: vlua\nfunction _runcmd_vlua(cmd, opt)\n    if cmd.script then\n        vprint(os.args(table.join(\"xmake\", \"lua\", cmd.script, cmd.argv)))\n        if not opt.dryrun then\n            local runopt = table.clone(cmd.opt) or {}\n            runopt.arguments = cmd.argv\n            if option.get(\"diagnosis\") then\n                runopt.verbose = true\n                runopt.diagnosis = true\n            else\n                runopt.quiet = not option.get(\"verbose\")\n            end\n            -- it will run in a separate native thread, which will not block other coroutine jobs\n            runopt.thread = true\n            run_script(cmd.script, runopt)\n        end\n    end\nend\n\n-- run command: os.mkdir\nfunction _runcmd_mkdir(cmd, opt)\n    local dir = cmd.dir\n    if not opt.dryrun and not os.isdir(dir) then\n        os.mkdir(dir)\n    end\nend\n\n-- run command: os.cd\nfunction _runcmd_cd(cmd, opt)\n    local dir = cmd.dir\n    if not opt.dryrun then\n        os.cd(dir)\n    end\nend\n\n-- run command: os.rm\nfunction _runcmd_rm(cmd, opt)\n    local filepath = cmd.filepath\n    if not opt.dryrun then\n        os.tryrm(filepath, opt)\n    end\nend\n\n-- run command: os.rmdir\nfunction _runcmd_rmdir(cmd, opt)\n    local dir = cmd.dir\n    if not opt.dryrun and os.isdir(dir) then\n        os.tryrm(dir, opt)\n    end\nend\n\n-- run command: os.cp\nfunction _runcmd_cp(cmd, opt)\n    if not opt.dryrun then\n        os.cp(cmd.srcpath, cmd.dstpath, cmd.opt)\n    end\nend\n\n-- run command: os.mv\nfunction _runcmd_mv(cmd, opt)\n    if not opt.dryrun then\n        os.mv(cmd.srcpath, cmd.dstpath, cmd.opt)\n    end\nend\n\n-- run command: os.ln\nfunction _runcmd_ln(cmd, opt)\n    if not opt.dryrun then\n        os.ln(cmd.srcpath, cmd.dstpath, cmd.opt)\n    end\nend\n\n-- run command: clean rpath\nfunction _runcmd_clean_rpath(cmd, opt)\n    if not opt.dryrun then\n        rpath_utils.clean(cmd.filepath, cmd.opt)\n    end\nend\n\n-- run command: insert rpath\nfunction _runcmd_insert_rpath(cmd, opt)\n    if not opt.dryrun then\n        rpath_utils.insert(cmd.filepath, cmd.rpath, cmd.opt)\n    end\nend\n\n-- run command: remove rpath\nfunction _runcmd_remove_rpath(cmd, opt)\n    if not opt.dryrun then\n        rpath_utils.remove(cmd.filepath, cmd.rpath, cmd.opt)\n    end\nend\n\n-- run command: change rpath\nfunction _runcmd_change_rpath(cmd, opt)\n    if not opt.dryrun then\n        rpath_utils.change(cmd.filepath, cmd.rpath_old, cmd.rpath_new, cmd.opt)\n    end\nend\n\n-- run command\nfunction _runcmd(cmd, opt)\n    local kind = cmd.kind\n    local maps = _g.maps\n    if not maps then\n        maps =\n        {\n            show          = _runcmd_show,\n            show_progress = _runcmd_show_progress,\n            runv          = _runcmd_runv,\n            vrunv         = _runcmd_vrunv,\n            execv         = _runcmd_execv,\n            vexecv        = _runcmd_vexecv,\n            lua           = _runcmd_lua,\n            vlua          = _runcmd_vlua,\n            mkdir         = _runcmd_mkdir,\n            rmdir         = _runcmd_rmdir,\n            cd            = _runcmd_cd,\n            rm            = _runcmd_rm,\n            cp            = _runcmd_cp,\n            mv            = _runcmd_mv,\n            ln            = _runcmd_ln,\n            clean_rpath   = _runcmd_clean_rpath,\n            insert_rpath  = _runcmd_insert_rpath,\n            remove_rpath  = _runcmd_remove_rpath,\n            change_rpath  = _runcmd_change_rpath\n        }\n        _g.maps = maps\n    end\n    local script = maps[kind]\n    if script then\n        script(cmd, opt)\n    end\nend\n\n-- run commands\nfunction _runcmds(cmds, opt)\n    for _, cmd in ipairs(cmds) do\n        _runcmd(cmd, opt)\n    end\nend\n\n-- is empty? no commands\nfunction batchcmds:empty()\n    return #self:cmds() == 0\nend\n\n-- get commands\nfunction batchcmds:cmds()\n    return self._CMDS\nend\n\n-- add command: os.runv\nfunction batchcmds:runv(program, argv, opt)\n    table.insert(self:cmds(), {kind = \"runv\", program = program, argv = argv, opt = opt})\nend\n\n-- add command: os.vrunv\nfunction batchcmds:vrunv(program, argv, opt)\n    table.insert(self:cmds(), {kind = \"vrunv\", program = program, argv = argv, opt = opt})\nend\n\n-- add command: os.execv\nfunction batchcmds:execv(program, argv, opt)\n    table.insert(self:cmds(), {kind = \"execv\", program = program, argv = argv, opt = opt})\nend\n\n-- add command: os.vexecv\nfunction batchcmds:vexecv(program, argv, opt)\n    table.insert(self:cmds(), {kind = \"vexecv\", program = program, argv = argv, opt = opt})\nend\n\n-- add command: run lua script file, command or module\nfunction batchcmds:lua(script, argv, opt)\n    table.insert(self:cmds(), {kind = \"lua\", script = script, argv = argv, opt = opt})\nend\n\n-- add command: run lua script file, command or module\nfunction batchcmds:vlua(script, argv, opt)\n    table.insert(self:cmds(), {kind = \"vlua\", script = script, argv = argv, opt = opt})\nend\n\n-- add command: compiler.compile\nfunction batchcmds:compile(sourcefiles, objectfile, opt)\n\n    -- bind target if exists\n    opt = opt or {}\n    opt.target = self._TARGET\n\n    -- wrap path for sourcefiles, because we need to translate path for project generator\n    if not path.instance_of(sourcefiles) then\n        if type(sourcefiles) == \"table\"  then\n            local sourcefiles_wrap = {}\n            for _, sourcefile in ipairs(sourcefiles) do\n                table.insert(sourcefiles_wrap, path(sourcefile))\n            end\n            sourcefiles = sourcefiles_wrap\n        else\n            sourcefiles = path(sourcefiles)\n        end\n    end\n\n    -- load compiler and get compilation command\n    local sourcekind = opt.sourcekind\n    if not sourcekind and (type(sourcefiles) == \"string\" or path.instance_of(sourcefiles)) then\n        sourcekind = language.sourcekind_of(tostring(sourcefiles))\n    end\n    local compiler_inst = compiler.load(sourcekind, opt)\n    local _, argv = compiler_inst:compargv(sourcefiles, path(objectfile), opt)\n\n    -- add compilation command and bind run environments of compiler\n    self:mkdir(path.directory(objectfile))\n    self:compilev(argv, table.join({sourcekind = sourcekind, compiler = compiler_inst}, opt))\nend\n\n-- add command: compiler.compilev\nfunction batchcmds:compilev(argv, opt)\n\n    -- bind target if exists\n    opt = opt or {}\n    opt.target = self._TARGET\n    opt.verbose = (opt.verbose == nil) and true or opt.verbose\n\n    -- load compiler and get compilation command\n    local compiler_inst = opt.compiler\n    if not compiler_inst then\n        local sourcekind = opt.sourcekind\n        compiler_inst = compiler.load(sourcekind, opt)\n    end\n\n    -- we need to translate path for the project generator\n    local patterns = {\"^([%-/]external:I)(.*)\",\n                      \"^([%-/]I)(.*)\",\n                      \"^([%-/]Fp)(.*)\",\n                      \"^([%-/]Fd)(.*)\",\n                      \"^([%-/]Yu)(.*)\",\n                      \"^([%-/]FI)(.*)\"}\n    for idx, item in ipairs(argv) do\n        if type(item) == \"string\" then\n            for _, pattern in ipairs(patterns) do\n                local _, count = item:gsub(pattern, function (prefix, value)\n                    argv[idx] = path(value, function (p) return prefix .. p end)\n                end)\n                if count > 0 then\n                    break\n                end\n            end\n        end\n    end\n\n    -- add compilation command and bind run environments of compiler\n    if opt.verbose then\n        self:vrunv(compiler_inst:program(), argv, {envs = table.join(compiler_inst:runenvs(), opt.envs)})\n    else\n        self:runv(compiler_inst:program(), argv, {envs = table.join(compiler_inst:runenvs(), opt.envs)})\n    end\nend\n\n-- add command: linker.link\nfunction batchcmds:link(objectfiles, targetfile, opt)\n\n    -- bind target if exists\n    local target = self._TARGET\n    opt = opt or {}\n    opt.target = target\n\n    -- wrap path for objectfiles, because we need to translate path for project generator\n    local objectfiles_wrap = {}\n    for _, objectfile in ipairs(objectfiles) do\n        table.insert(objectfiles_wrap, path(objectfile))\n    end\n    objectfiles = objectfiles_wrap\n\n    -- load linker and get link command\n    local linker_inst = target and target:linker() or linker.load(opt.targetkind, opt.sourcekinds, opt)\n    local program, argv = linker_inst:linkargv(objectfiles, path(targetfile), opt)\n\n    -- we need to translate path for the project generator\n    local patterns = {\"^([%-/]L)(.*)\",\n                      \"^([%-/]F)(.*)\",\n                      \"^([%-/]libpath:)(.*)\"}\n    for idx, item in ipairs(argv) do\n        if type(item) == \"string\" then\n            for _, pattern in ipairs(patterns) do\n                local _, count = item:gsub(pattern, function (prefix, value)\n                    argv[idx] = path(value, function (p) return prefix .. p end)\n                end)\n                if count > 0 then\n                    break\n                end\n            end\n        end\n    end\n\n    -- add link command and bind run environments of linker\n    self:mkdir(path.directory(targetfile))\n    self:vrunv(program, argv, {envs = table.join(linker_inst:runenvs(), opt.envs)})\nend\n\n-- add command: os.mkdir\nfunction batchcmds:mkdir(dir)\n    table.insert(self:cmds(), {kind = \"mkdir\", dir = dir})\nend\n\n-- add command: os.rmdir\nfunction batchcmds:rmdir(dir, opt)\n    table.insert(self:cmds(), {kind = \"rmdir\", dir = dir, opt = opt})\nend\n\n-- add command: os.rm\nfunction batchcmds:rm(filepath, opt)\n    table.insert(self:cmds(), {kind = \"rm\", filepath = filepath, opt = opt})\nend\n\n-- add command: os.cp\nfunction batchcmds:cp(srcpath, dstpath, opt)\n    table.insert(self:cmds(), {kind = \"cp\", srcpath = srcpath, dstpath = dstpath, opt = opt})\nend\n\n-- add command: os.mv\nfunction batchcmds:mv(srcpath, dstpath, opt)\n    table.insert(self:cmds(), {kind = \"mv\", srcpath = srcpath, dstpath = dstpath, opt = opt})\nend\n\n-- add command: os.ln\nfunction batchcmds:ln(srcpath, dstpath, opt)\n    table.insert(self:cmds(), {kind = \"ln\", srcpath = srcpath, dstpath = dstpath, opt = opt})\nend\n\n-- add command: os.cd\nfunction batchcmds:cd(dir, opt)\n    table.insert(self:cmds(), {kind = \"cd\", dir = dir, opt = opt})\nend\n\n-- add command: show\nfunction batchcmds:show(format, ...)\n    table.insert(self:cmds(), {kind = \"show\", format = format, argv = table.pack(...)})\nend\n\n-- add command: show progress\nfunction batchcmds:show_progress(progress, format, ...)\n    table.insert(self:cmds(), {kind = \"show_progress\", progress = progress, format = format, argv = table.pack(...)})\nend\n\n-- add command: clean rpath\nfunction batchcmds:clean_rpath(filepath, opt)\n    table.insert(self:cmds(), {kind = \"clean_rpath\", filepath = filepath, opt = opt})\nend\n\n-- add command: insert rpath\nfunction batchcmds:insert_rpath(filepath, rpath, opt)\n    table.insert(self:cmds(), {kind = \"insert_rpath\", filepath = filepath, rpath = rpath, opt = opt})\nend\n\n-- add command: remove rpath\nfunction batchcmds:remove_rpath(filepath, rpath, opt)\n    table.insert(self:cmds(), {kind = \"remove_rpath\", filepath = filepath, rpath = rpath, opt = opt})\nend\n\n-- add command: change rpath\nfunction batchcmds:change_rpath(filepath, rpath_old, rpath_new, opt)\n    table.insert(self:cmds(), {kind = \"change_rpath\", filepath = filepath, rpath_old = rpath_old, rpath_new = rpath_new, opt = opt})\nend\n\n-- add raw command for the specific generator or xpack format\nfunction batchcmds:rawcmd(kind, rawstr)\n    table.insert(self:cmds(), {kind = kind, rawstr = rawstr})\nend\n\n-- get depinfo\nfunction batchcmds:depinfo()\n    return self._DEPINFO\nend\n\n-- add dependent files\nfunction batchcmds:add_depfiles(...)\n    local depinfo = self._DEPINFO or {}\n    depinfo.files = depinfo.files or {}\n    table.join2(depinfo.files, ...)\n    self._DEPINFO = depinfo\nend\n\n-- add dependent values\nfunction batchcmds:add_depvalues(...)\n    local depinfo = self._DEPINFO or {}\n    depinfo.values = depinfo.values or {}\n    table.join2(depinfo.values, ...)\n    self._DEPINFO = depinfo\nend\n\n-- set the last mtime of dependent files and values\nfunction batchcmds:set_depmtime(lastmtime)\n    local depinfo = self._DEPINFO or {}\n    depinfo.lastmtime = lastmtime\n    self._DEPINFO = depinfo\nend\n\n-- set cache file of depend info\nfunction batchcmds:set_depcache(cachefile)\n    local depinfo = self._DEPINFO or {}\n    depinfo.dependfile = cachefile\n    self._DEPINFO = depinfo\nend\n\n-- run cmds\nfunction batchcmds:runcmds(opt)\n    opt = opt or {}\n    if self:empty() then\n        return\n    end\n    local depinfo = self:depinfo()\n    if depinfo and depinfo.files then\n        depend.on_changed(function ()\n            _runcmds(self:cmds(), opt)\n        end, table.join(depinfo, {dryrun = opt.dryrun, changed = opt.changed}))\n    else\n        _runcmds(self:cmds(), opt)\n    end\nend\n\n-- new a batch commands for rule/xx_xxcmd_xxx()\n--\n-- @params opt      options, e.g. {target = ..}\n--\nfunction new(opt)\n    opt = opt or {}\n    return batchcmds {_TARGET = opt.target, _CMDS = {}}\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/bcsave.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bcsave.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.luajit.bcsave\")\n\n-- the options\nlocal options =\n{\n    {'s', \"strip\",       \"k\",  false,            \"Strip the debug info.\"                      }\n,   {nil, \"rootname\",    \"kv\", nil,              \"Set the display root path name.\"            }\n,   {'o', \"outputdir\",   \"kv\", nil,              \"Set the output directory of bitcode files.\" }\n,   {'x', \"excludedirs\", \"kv\", nil,              \"Set the excluded directories.\"              }\n,   {nil, \"sourcedir\",   \"v\",  os.programdir(),  \"Set the directory of lua source files.\"     }\n}\n\n-- save lua files to bitcode files in the given directory\nfunction save(sourcedir, outputdir, opt)\n\n    -- init source directory and options\n    opt = opt or {}\n    sourcedir = path.absolute(sourcedir or os.programdir())\n    outputdir = outputdir and path.absolute(outputdir) or sourcedir\n    assert(os.isdir(sourcedir), \"%s not found!\", sourcedir)\n\n    -- trace\n    print(\"generating bitcode files from %s ..\", sourcedir)\n\n    -- save all lua files to bitcode files\n    local total_lua = 0\n    local total_bc  = 0\n    local pattern = path.join(sourcedir, \"**.lua\")\n    if opt.excludedirs then\n        pattern = pattern .. \"|\" .. opt.excludedirs\n    end\n    local override = (outputdir == sourcedir)\n    for _, luafile in ipairs(os.files(pattern)) do\n\n        -- get relative lua file path\n        local relativepath = path.relative(luafile, sourcedir)\n\n        -- get display path\n        local displaypath = opt.rootname and path.join(opt.rootname, relativepath) or relativepath\n\n        -- get bitcode file path\n        local bcfile = override and os.tmpfile() or path.join(outputdir, relativepath)\n\n        -- generate bitcode file\n        -- @note we disable cache to ensure all display paths are correct\n        bcsave(luafile, bcfile, {strip = opt.strip, displaypath = displaypath, nocache = true})\n\n        -- trace\n        local luasize = os.filesize(luafile)\n        local bcsize  = os.filesize(bcfile)\n        total_lua = total_lua + luasize\n        total_bc  = total_bc + bcsize\n        vprint(\"generating %s (%d => %d) ..\", displaypath, luasize, bcsize)\n\n        -- override?\n        if override then\n            os.cp(bcfile, luafile)\n        end\n    end\n\n    -- trace\n    cprint(\"${bright}bitcode files have been generated in %s, size: %d => %d\", outputdir, total_lua, total_bc)\nend\n\n-- main entry\nfunction main(...)\n\n    -- parse arguments\n    local argv = {...}\n    local opt  = option.parse(argv, options, \"Save all lua files to bitcode files.\"\n                                           , \"\"\n                                           , \"Usage: xmake l private.utils.bcsave [options]\")\n\n    -- save bitcode files\n    save(opt.sourcedir, opt.outputdir, opt)\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/complete.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu, glcraft\n-- @file        complete.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"private.utils.completer\")\n\nfunction main(pos, config, ...)\n\n    local comp = completer.new(pos, config, {...})\n\n    local word = table.concat(comp:words(), \" \") or \"\"\n    position = tonumber(pos) or 0\n\n    local has_space = word:endswith(\" \") or position > #word\n    word = word:trim()\n\n    local argv = os.argv(word)\n\n    if argv[1] then\n\n        -- normailize word to remove \"xmake\"\n        if is_host(\"windows\") and argv[1]:lower() == \"xmake.exe\" then\n            argv[1] = \"xmake\"\n        end\n        if argv[1] == \"xmake\" then\n            table.remove(argv, 1)\n        end\n    end\n\n    local items = {}\n    local tasks = task.names()\n    for _, name in ipairs(tasks) do\n        items[name] = option.taskmenu(name)\n    end\n\n    if has_space then\n        comp:complete(items, argv, \"\")\n    else\n        local completing = table.remove(argv)\n        comp:complete(items, argv, completing or \"\")\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/complete_helper.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        complete_helper.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.project.config\")\n\n-- get targets\nfunction targets()\n    return try\n    {\n        function ()\n            config.load()\n            return table.orderkeys(project.targets())\n        end\n    }\nend\n\n-- get runnable targets\nfunction runable_targets(complete, opt)\n    return try\n    {\n        function ()\n            config.load()\n            local targets = project.targets()\n            local runable = {}\n            for k, v in table.orderpairs(targets) do\n                if (v:script(\"run\") or v:is_binary()) and (not complete or k:startswith(complete)) then\n                    table.insert(runable, k)\n                end\n            end\n            return runable\n        end\n    }\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/completer.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu, glcraft\n-- @file        complete.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.cli\")\n\nlocal completer = {}\n\n\nfunction completer.new(pos, config, words)\n    local instance = table.inherit(completer)\n    instance._POSITION = 0\n    instance._CONFIG = {}\n    instance._WORDS = {}\n    instance._DEFAULT_COMMAND = \"\"\n    instance:set_config(config)\n    instance:set_position(pos)\n    instance:set_words(words)\n    return instance\nend\n\nfunction completer:_print_candidate(candidate)\n    if candidate.value and #candidate.value ~= 0 then\n        printf(candidate.value)\n        if not self:config(\"nospace\") and candidate.is_complete then\n            print(\" \")\n        else\n            print(\"\")\n        end\n    end\nend\n\nfunction completer:_print_candidates(candidates)\n    if self:config(\"json\") then\n        import(\"core.base.json\")\n        print(json.encode(candidates))\n    else\n        for _, v in ipairs(candidates) do\n            self:_print_candidate(v)\n        end\n    end\nend\n\nfunction completer:_find_candidates(candidates, find)\n\n    if type(candidates) ~= 'table' then\n        return {}\n    end\n\n    local has_candidate = false\n    local results = table.new(#candidates, 0)\n\n    -- find candidate starts with find str\n    for _, v in ipairs(candidates) do\n        if tostring(v):startswith(find) then\n            table.insert(results, v)\n            has_candidate = true\n        end\n    end\n\n    -- stop searching if found any\n    if has_candidate then\n        return results\n    end\n\n    -- find candidate contains find str\n    for _, v in ipairs(candidates) do\n        if tostring(v):find(find, 1, true) then\n            table.insert(results, v)\n        end\n    end\n\n    return results\nend\n\nfunction completer:_complete_item(items, name)\n    local found_candidates = {}\n    for _, v in ipairs(self:_find_candidates(table.keys(items), name)) do\n        table.insert(found_candidates, { value = v, is_complete = true, description = items[v].description })\n    end\n    self:_print_candidates(found_candidates)\n    return #found_candidates > 0\nend\n\n-- complete values of kv\nfunction completer:_complete_option_kv_v(options, current, completing, name, value)\n\n    -- find completion option\n    local opt\n    for _, v in ipairs(options) do\n        if v[3] == \"kv\" and (v[1] == name or v[2] == name) then\n            opt = v\n            break\n        end\n    end\n    if not opt then\n        return false\n    end\n\n    -- show candidates of values\n    local values = opt.values\n    if type(values) == \"function\" then\n        values = values(value, current)\n    end\n    if values == nil and type(opt[4]) == \"boolean\" then\n        values = { \"yes\", \"no\" }\n        -- ignore existing input\n        value = \"\"\n    end\n\n    -- match values starts with value first\n    local found_candidates = {}\n    local nokey = self:config(\"nokey\")\n    for _, v in ipairs(self:_find_candidates(values, value)) do\n        if nokey then\n            table.insert(found_candidates, { value = v, is_complete = true })\n        else\n            table.insert(found_candidates, { value = format(\"--%s=%s\", name, v), is_complete = true })\n        end\n    end\n    self:_print_candidates(found_candidates)\n\n    -- whether any candidates has been found, finish complete since we don't have more info\n    return true\nend\n\n-- complete keys of kv\nfunction completer:_complete_option_kv_k(options, current, completing, name)\n\n    local opcandi = table.new(0, 10)\n    for _, opt in ipairs(options) do\n        if opt[2] and current[opt[2]] == nil and (opt[3] == \"kv\" or opt[3] == \"k\") then\n            opcandi[opt[2]] = opt\n        end\n    end\n    local found_candidates = {}\n    for _, k in ipairs(self:_find_candidates((table.keys(opcandi)), name)) do\n        local opt = opcandi[k]\n        local name = format((opt[3] == \"k\") and \"--%s\" or \"--%s=\", opt[2])\n        table.insert(found_candidates, { value = name, description = opt[5], is_complete = (opt[3] == \"k\") })\n    end\n    self:_print_candidates(found_candidates)\n\n    return true\nend\n\nfunction completer:_complete_option_kv(options, current, completing)\n\n    local name, value\n    if completing == \"-\" or completing == \"--\" then\n        name = \"\"\n    elseif completing:startswith(\"--\") then\n        local parg = cli.parsev({completing})[1]\n        if parg.type == \"option\" then\n            name, value = parg.key, parg.value\n        elseif parg.type == \"flag\" then\n            name = parg.key\n        end\n    elseif completing:startswith(\"-\") then\n        -- search full names only\n        return true\n    end\n\n    if value then\n        -- complete values\n        return self:_complete_option_kv_v(options, current, completing, name, value)\n    else\n        -- complete keys\n        return self:_complete_option_kv_k(options, current, completing, name)\n    end\nend\n\n-- complete options v and vs\nfunction completer:_complete_option_v(options, current, completing)\n    -- find completion option\n    local opt\n    local optvs\n    for _, v in ipairs(options) do\n        if v[3] == \"v\" and current[v[2] or v[1]] == nil then\n            opt = v\n        end\n        if v[3] == \"vs\" and not optvs then\n            optvs = v\n        end\n    end\n    -- transform values array to candidates array\n    local function _transform_values(values)\n        local candidates = {}\n        if #values > 0 and type(values[1]) == \"string\" then\n            for _, v in ipairs(values) do\n                if v:startswith(completing) then\n                    table.insert(candidates, { value = v, is_complete = true })\n                end\n            end\n        else\n            for _, v in ipairs(values) do\n                v.is_complete = true\n                table.insert(candidates, v)\n            end\n        end\n        return candidates\n    end\n    -- filter candidates with completing\n    local function _filter_candidates(candidates)\n        local found_candidates = {}\n        for _, v in ipairs(candidates) do\n            if v.value:find(completing, 1, true) then\n                v.is_complete = true\n                table.insert(found_candidates, v)\n            end\n        end\n        return found_candidates\n    end\n    -- get completion candidates from values option\n    local function _values_into_candidates(values)\n        if values == nil then\n            return {}\n        elseif type(values) == \"function\" then\n            -- no need to filter result of values() as we consider values() already filter candidates\n            return _transform_values(values(completing, current))\n        else\n            return _filter_candidates(_transform_values(values))\n        end\n    end\n\n    -- get candidates from values option\n    local found_candidates = {}\n    if opt then\n        found_candidates = _values_into_candidates(opt.values)\n    end\n\n    -- get candidates from values option\n    if optvs and #found_candidates == 0 then\n        found_candidates = _values_into_candidates(optvs.values)\n    end\n    self:_print_candidates(found_candidates)\n    return #found_candidates > 0\nend\n\nfunction completer:_complete_option(options, segs, completing)\n    local current_options = try {\n        function()\n            return option.raw_parse(segs, options, { populate_defaults = false, allow_unknown = true })\n        end\n    }\n\n    -- current options is invalid\n    if not current_options then return false end\n\n    -- current context is wrong\n    if not self:config(\"reenter\") and (current_options.file or current_options.project) then\n        local args = {\"lua\", \"private.utils.complete\", tostring(position), table.concat(self._CONFIG, \"-\") .. \"-reenter\", table.unpack(raw_words) }\n        if current_options.file then\n            table.insert(args, 2, \"--file=\" .. current_options.file)\n        end\n        if current_options.project then\n            table.insert(args, 2, \"--project=\" .. current_options.project)\n        end\n        os.execv(os.programfile(), args)\n        return true\n    end\n\n    if completing:startswith(\"-\") then\n        return self:_complete_option_kv(options, current_options, completing)\n    else\n        return self:_complete_option_v(options, current_options, completing)\n    end\nend\n\nfunction completer:complete(items, argv, completing)\n\n    local shortnames = table.new(0, 10)\n    for v, menu in pairs(items) do\n        if menu.shortname then\n            shortnames[menu.shortname] = v\n        end\n    end\n\n    if #argv == 0 then\n        if self:_complete_item(items, completing) then return end\n    end\n\n    local item_name = self:default_command()\n    if argv[1] and not argv[1]:startswith(\"-\") then\n        item_name = table.remove(argv, 1)\n    end\n\n    if shortnames[item_name] then\n        item_name = shortnames[item_name]\n    end\n\n    local options\n    if items[item_name] then\n        options = items[item_name].options\n    end\n    if options then\n        self:_complete_option(options, argv, completing)\n    end\nend\n\nfunction completer:set_words(raw_words)\n    self._WORDS = raw_words\nend\n\nfunction completer:words()\n    return self._WORDS\nend\n\nfunction completer:set_position(pos)\n    self._POSITION = pos\nend\n\nfunction completer:position()\n    return self._POSITION\nend\n\nfunction completer:set_default_command(command)\n    self._DEFAULT_COMMAND = command\nend\n\nfunction completer:default_command()\n    return self._DEFAULT_COMMAND\nend\n\nfunction completer:set_config(config)\n    self._CONFIG = (config or \"\"):trim():split(\"-\")\nend\n\nfunction completer:config(key)\n    return table.find_first(self._CONFIG, key)\nend\n\nfunction new(...)\n    return completer.new(...)\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/executable_path.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        executable_path.lua\n--\n\n-- get executable file path\n--\n-- e.g.\n-- \"/usr/bin/xcrun -sdk macosx clang\" -> \"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang\"\n--\n-- @see\n-- https://github.com/xmake-io/xmake/issues/3159\n-- https://github.com/xmake-io/xmake/issues/3286\n-- https://github.com/xmake-io/xmake-repo/pull/1840#issuecomment-1434096993\nfunction main(program)\n    local program_map = _g.program_map\n    if program_map == nil then\n        program_map = {}\n        _g.program_map = program_map\n    end\n    local filepath = program_map[program]\n    if filepath then\n        return filepath\n    end\n    if is_host(\"macosx\") and program:find(\"xcrun -sdk\", 1, true) then\n        local cmd = program:gsub(\"xcrun %-sdk (%S+) (%S+)\", function (plat, cc)\n            return \"xcrun -sdk \" .. plat .. \" -f \" .. cc\n        end)\n        local splitinfo = cmd:split(\"%s\")\n        local result = try {function() return os.iorunv(splitinfo[1], table.slice(splitinfo, 2) or {}) end}\n        if result then\n            result = result:trim()\n            if #result > 0 then\n                filepath = result\n            end\n        end\n    end\n    -- patch .exe\n    -- @see https://github.com/xmake-io/xmake/discussions/4781\n    if is_host(\"windows\") and path.is_absolute(program) then\n        local program_exe = program .. \".exe\"\n        if os.isfile(program_exe) then\n            program = program_exe\n        end\n    end\n    if not filepath then\n        filepath = program\n    end\n    program_map[program] = filepath\n    return filepath\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- concat packages, TODO components\nfunction _concat_packages(a, b)\n    local result = table.copy(a)\n    for k, v in pairs(b) do\n        local o = result[k]\n        if o ~= nil then\n            v = table.join(o, v)\n        end\n        result[k] = v\n    end\n    for k, v in pairs(result) do\n        if k == \"links\" or k == \"syslinks\" or k == \"frameworks\" or k == \"ldflags\" or k == \"shflags\" then\n            if type(v) == \"table\" and #v > 1 then\n                -- we need to ensure link orders when removing repeat values\n                v = table.reverse_unique(v)\n            end\n        elseif k == \"static\" or k == \"shared\" then\n            v = table.unwrap(table.unique(v))\n            if type(v) == \"table\" then\n                -- conflict, {true, false}\n                v = true\n            end\n        else\n            v = table.unique(v)\n        end\n        result[k] = v\n    end\n    return result\nend\n\n-- set concat for find_package/fetch info\nfunction fetchinfo_set_concat(fetchinfo)\n    if fetchinfo and type(fetchinfo) == \"table\" then\n        debug.setmetatable(fetchinfo, {__concat = _concat_packages})\n    end\nend\n\n--\n-- parse require string\n--\n-- basic\n-- - add_requires(\"zlib\")\n--\n-- semver\n-- - add_requires(\"tbox >=1.5.1\", \"zlib >=1.2.11\")\n-- - add_requires(\"tbox\", {version = \">=1.5.1\"})\n--\n-- git branch/tag\n-- - add_requires(\"zlib master\")\n--\n-- with the given repository\n-- - add_requires(\"xmake-repo@tbox >=1.5.1\")\n--\n-- with the given configs\n-- - add_requires(\"aaa_bbb_ccc >=1.5.1 <1.6.0\", {optional = true, alias = \"mypkg\", debug = true})\n-- - add_requires(\"tbox\", {config = {coroutine = true, abc = \"xxx\"}})\n--\n-- with namespace and the 3rd package manager\n-- - add_requires(\"xmake::xmake-repo@tbox >=1.5.1\")\n-- - add_requires(\"vcpkg::ffmpeg\")\n-- - add_requires(\"conan::OpenSSL/1.0.2n@conan/stable\")\n-- - add_requires(\"conan::openssl/1.1.1g\") -- new\n-- - add_requires(\"brew::pcre2/libpcre2-8 10.x\", {alias = \"pcre2\"})\n--\n-- clone as a standalone package with the different configs\n-- we can install and use these three packages at the same time.\n-- - add_requires(\"zlib\")\n-- - add_requires(\"zlib~debug\", {debug = true})\n-- - add_requires(\"zlib~shared\", {configs = {shared = true}, alias = \"zlib_shared\"})\n--\n-- - add_requires(\"zlib~label1\")\n-- - add_requires(\"zlib\", {label = \"label2\"})\n--\n-- private package, only for installation, do not export any links/includes and environments to target\n-- - add_requires(\"zlib\", {private = true})\n--\n-- {system = nil/true/false}:\n--   nil: get remote or system packages\n--   true: only get system package\n--   false: only get remote packages\n--\n-- {build = true}: always build packages, we do not use the precompiled artifacts\n--\n-- simply configs as string:\n--   add_requires(\"boost[iostreams,system,thread,key=value] >=1.78.0\")\n--   add_requires(\"boost[iostreams,thread=n] >=1.78.0\")\n--   add_requires(\"libplist[shared,debug,codecs=[foo,bar,zoo]]\")\n--\nfunction parse_requirestr(require_str)\n\n    -- split package and version info\n    local splitinfo = require_str:split('%s+')\n    assert(splitinfo and #splitinfo > 0, \"require(\\\"%s\\\"): invalid!\", require_str)\n\n    -- get package info\n    local packageinfo = splitinfo[1]\n\n    -- get version\n    --\n    -- e.g.\n    --\n    -- latest\n    -- >=1.5.1 <1.6.0\n    -- master || >1.4\n    -- ~1.2.3\n    -- ^1.1\n    --\n    local version = \"latest\"\n    if #splitinfo > 1 then\n        version = table.concat(table.slice(splitinfo, 2), \" \")\n    end\n    assert(version, \"require(\\\"%s\\\"): unknown version!\", require_str)\n\n    -- require third-party packages? e.g. brew::pcre2/libpcre2-8\n    local reponame    = nil\n    local packagename = nil\n    if require_str:find(\"::\", 1, true) then\n        packagename = packageinfo\n    else\n\n        -- get repository name, package name and package url\n        local pos = packageinfo:lastof('@', true)\n        if pos then\n            packagename = packageinfo:sub(pos + 1)\n            reponame = packageinfo:sub(1, pos - 1)\n        else\n            packagename = packageinfo\n        end\n    end\n\n    -- check package name\n    assert(packagename, \"require(\\\"%s\\\"): the package name not found!\", require_str)\n    return packagename, version, reponame\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/rule.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rule.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\n-- get rule\n-- @note we need to get rule from target first, because we maybe will inject and replace builtin rule in target\nfunction get_rule(target, rulename)\n    local ruleinst = assert(target:rule(rulename) or project.rule(rulename, {namespace = target:namespace()}) or\n        rule.rule(rulename), \"unknown rule: %s\", rulename)\n    return ruleinst\nend\n\n-- build rules orders in jobgraph, we need to add rule job with groups\n--\n-- like this:\n-- @code\n--   local root_group = \"\"\n--   for _, ruleinst in ipairs(rules) do\n--        local script_group = root_group .. \"/\" .. ruleinst:fullname()\n--        jobgraph:group(script_group, function ()\n--            jobgraph:add(\"xxx\", function (index, total, opt)\n--                -- call rule script\n--            end)\n--        end)\n--    end\n--\nfunction build_orders_in_jobgraph(jobgraph, target, rules, opt)\n    opt = opt or {}\n    local root_group = assert(opt.root_group)\n    for _, ruleinst in ipairs(rules) do\n        local orders = table.wrap(ruleinst:get(\"orders\"))\n        if #orders > 0 then\n            for _, order in ipairs(orders) do\n                local joborders = {}\n                for _, rulename in ipairs(order) do\n                    -- we need to use fullname to support namespace\n                    local ruleinst = get_rule(target, rulename)\n                    local script_group = root_group .. \"/\" .. ruleinst:fullname()\n                    if jobgraph:has(script_group) then\n                        table.insert(joborders, script_group)\n                    end\n                end\n                if #joborders > 0 then\n                    jobgraph:add_orders(joborders)\n                end\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/statistics.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        statistics.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.process\")\nimport(\"core.project.config\")\nimport(\"core.platform.platform\")\nimport(\"utils.ci.is_running\", {alias = \"ci_is_running\"})\nimport(\"private.action.update.fetch_version\")\nimport(\"private.action.require.impl.packagenv\")\n\n-- statistics is enabled?\nfunction _is_enabled()\n\n    -- disable statistics? need not post it\n    local stats = (os.getenv(\"XMAKE_STATS\") or \"\"):lower()\n    if stats == \"false\" then\n        return false\n    end\n\n    -- is running on ci(travis/appveyor/...)? need not post it\n    if ci_is_running() then\n        os.setenv(\"XMAKE_STATS\", \"false\")\n        return false\n    end\n    return true\nend\n\n-- post statistics info and only post once everyday when building each project\n--\n-- clone the xmake-stats(only an empty repo) to update the traffic(git clones) info in github\n--\n-- the traffic info in github (just be approximate numbers):\n--\n-- Clones:          the number of projects which build using xmake everyday\n-- Unique cloners:  the number of users everyday\n--\nfunction post()\n\n    -- enter project directory\n    local oldir = os.cd(os.projectdir())\n\n    -- get the project directory name\n    local projectname = path.basename(os.projectdir())\n\n    -- has been posted today or statistics is disable?\n    local outputdir = path.join(os.tmpdir(), \"stats\", os.date(\"%y%m%d\"), projectname)\n    local markfile  = outputdir .. \".mark\"\n    if os.isdir(outputdir) or os.isfile(markfile) or not _is_enabled() then\n        return\n    end\n\n    -- mark as posted first, avoid posting it repeatly\n    io.writefile(markfile, \"ok\")\n\n    -- init argument list\n    local argv = {\"lua\", path.join(os.scriptdir(), \"statistics.lua\")}\n    for _, name in ipairs({\"root\", \"file\", \"project\", \"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\"}) do\n        local value = option.get(name)\n        if type(value) == \"string\" then\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        elseif value then\n            table.insert(argv, \"--\" .. name)\n        end\n    end\n\n    -- try to post it in background\n    try\n    {\n        function ()\n            process.openv(os.programfile(), argv, {stdout = path.join(os.tmpdir(), projectname .. \".stats.log\"), detach = true}):close()\n        end\n    }\n\n    -- leave project directory\n    os.cd(oldir)\nend\n\n-- the main function\nfunction main()\n\n    -- in project?\n    if not os.isfile(os.projectfile()) then\n        return\n    end\n\n    -- load config\n    config.load()\n\n    -- load platform\n    platform.load(config.plat())\n\n    -- enter the environments of git\n    local oldenvs = packagenv.enter(\"git\")\n\n    -- get the project directory name\n    local projectname = path.basename(os.projectdir())\n\n    -- clone the xmake-stats repo to update the traffic(git clones) info in github\n    local outputdir = path.join(os.tmpdir(), \"stats\", os.date(\"%y%m%d\"), projectname)\n    if not os.isdir(outputdir) then\n        try\n        {\n            function ()\n                import(\"devel.git.clone\")\n                clone(\"https://github.com/xmake-io/xmake-stats.git\", {depth = 1, branch = \"master\", outputdir = outputdir})\n                print(\"post to traffic ok!\")\n            end\n        }\n    end\n\n    -- fetch the latest version\n    local versionfile = path.join(os.tmpdir(), \"latest_version\")\n    if not os.isfile(versionfile) then\n        local fetchinfo = try { function () return fetch_version() end }\n        if fetchinfo then\n            io.save(versionfile, fetchinfo)\n        end\n    end\n\n    -- leave the environments of git\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/target.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"utils.binary.deplibs\", {alias = \"get_depend_libraries\"})\n\n-- Is this target has these tools?\nfunction has_tool(toolname, tools)\n    if toolname then\n        -- We need compatibility with gcc/g++, clang/clang++ for c++ compiler/linker\n        -- @see https://github.com/xmake-io/xmake/issues/6852\n        local trim_xx = false\n        if toolname == \"clangxx\" or toolname == \"gxx\" then\n            toolname = toolname:rtrim(\"xx\")\n            trim_xx = true\n        end\n        for _, v in ipairs(tools) do\n            if trim_xx then\n                v = v:rtrim(\"xx\")\n            end\n            if v and toolname:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n                return true\n            end\n        end\n    end\n    return false\nend\n\n-- does this flag belong to this tool?\n-- @see https://github.com/xmake-io/xmake/issues/3022\n--\n-- e.g.\n--\n-- for all: add_cxxflags(\"-g\")\n-- only for clang: add_cxxflags(\"clang::-stdlib=libc++\")\n-- only for clang and multiple flags: add_cxxflags(\"-stdlib=libc++\", \"-DFOO\", {tools = \"clang\"})\n--\nfunction flag_belong_to_tool(flag, toolinst, extraconf)\n    local for_this_tool = true\n    local flagconf = extraconf and extraconf[flag]\n    if type(flag) == \"string\" and flag:find(\"::\", 1, true) then\n        for_this_tool = false\n        local splitinfo = flag:split(\"::\", {plain = true})\n        local toolname = splitinfo[1]\n        local realname = toolinst:name()\n        -- We need compatibility with gcc/g++, clang/clang++ for c++ compiler/linker\n        -- @see https://github.com/xmake-io/xmake/issues/6852\n        if realname == \"clangxx\" or realname == \"gxx\" then\n            toolname = toolname:rtrim(\"xx\")\n            realname = realname:rtrim(\"xx\")\n        end\n        if toolname == realname then\n            flag = splitinfo[2]\n            for_this_tool = true\n        end\n    elseif flagconf and flagconf.tools then\n        for_this_tool = has_tool(toolinst:name(), flagconf.tools)\n    end\n    if for_this_tool then\n        return flag\n    end\nend\n\n-- translate flags in tool\nfunction translate_flags_in_tool(target, flagkind, flags)\n    local extraconf = target:extraconf(flagkind)\n    local sourcekind\n    local linkerkind\n    if flagkind == \"cflags\" then\n        sourcekind = \"cc\"\n    elseif flagkind == \"cxxflags\" or flagkind == \"cxflags\" then\n        sourcekind = \"cxx\"\n    elseif flagkind == \"asflags\" then\n        sourcekind = \"as\"\n    elseif flagkind == \"cuflags\" then\n        sourcekind = \"cu\"\n    elseif flagkind == \"ldflags\" or flagkind == \"shflags\" then\n        -- pass\n    else\n        raise(\"unknown flag kind %s\", flagkind)\n    end\n    local toolinst = sourcekind and target:compiler(sourcekind) or target:linker()\n\n    -- does this flag belong to this tool?\n    -- @see https://github.com/xmake-io/xmake/issues/3022\n    --\n    -- e.g.\n    --\n    -- for all: add_cxxflags(\"-g\")\n    -- only for clang: add_cxxflags(\"clang::-stdlib=libc++\")\n    -- only for clang and multiple flags: add_cxxflags(\"-stdlib=libc++\", \"-DFOO\", {tools = \"clang\"})\n    --\n    local result = {}\n    for _, flag in ipairs(flags) do\n        flag = flag_belong_to_tool(flag, toolinst, extraconf)\n        if flag then\n            table.insert(result, flag)\n        end\n    end\n    return result\nend\n\n-- get project targets\nfunction get_project_targets()\n    local selected_target = option.get(\"target\")\n    if selected_target then\n        -- return table.wrap(project.target(selected_target))\n        return { project.target(selected_target) }\n    end\n    return project.targets()\nend\n\n-- check target toolchains\nfunction check_target_toolchains()\n    -- check toolchains configuration for all target in the current project\n    -- @note we must check targets after loading options\n    for _, target in pairs(project.targets()) do\n        if target:is_enabled() and (target:get(\"toolchains\") or\n                                    not target:is_plat(config.get(\"plat\")) or\n                                    not target:is_arch(config.get(\"arch\"))) then\n\n            -- check platform toolchains first\n            -- `target/set_plat()` and target:toolchains() need it\n            target:platform():check()\n\n            -- check target toolchains next\n            local target_toolchains = target:get(\"toolchains\")\n            if target_toolchains then\n                target_toolchains = hashset.from(table.wrap(target_toolchains))\n                for _, toolchain_inst in pairs(target:toolchains()) do\n                    -- check toolchains for `target/set_toolchains()`\n                    if not toolchain_inst:check() and target_toolchains:has(toolchain_inst:name()) then\n                        raise(\"toolchain(\\\"%s\\\"): not found!\", toolchain_inst:name())\n                    end\n                end\n            end\n        elseif not target:get(\"toolset\") then\n            -- we only abort it when we know that toolchains of platform and target do not found\n            local toolchain_found\n            for _, toolchain_inst in pairs(target:toolchains()) do\n                if toolchain_inst:is_standalone() then\n                    toolchain_found = true\n                end\n            end\n            assert(toolchain_found, \"target(%s): toolchain not found!\", target:name())\n        end\n    end\nend\n\n-- config target\nfunction config_target(target, opt)\n    for _, rule in ipairs(table.wrap(target:orderules())) do\n        local before_config = rule:script(\"config_before\")\n        if before_config then\n            before_config(target, opt)\n        end\n    end\n\n    for _, rule in ipairs(table.wrap(target:orderules())) do\n        local on_config = rule:script(\"config\")\n        if on_config then\n            on_config(target, opt)\n        end\n    end\n    local on_config = target:script(\"config\")\n    if on_config then\n        on_config(target, opt)\n    end\n\n    for _, rule in ipairs(table.wrap(target:orderules())) do\n        local after_config = rule:script(\"config_after\")\n        if after_config then\n            after_config(target, opt)\n        end\n    end\nend\n\n-- config targets\nfunction config_targets(opt)\n    opt = opt or {}\n    for _, target in ipairs(table.wrap(project.ordertargets())) do\n        if target:is_enabled() then\n            config_target(target, opt)\n        end\n    end\nend\n\nfunction get_target_package_libfiles(target, opt)\n    opt = opt or {}\n    local libfiles = {}\n    for _, pkg in ipairs(target:orderpkgs(opt)) do\n        if pkg:enabled() and pkg:get(\"libfiles\") then\n            for _, libfile in ipairs(table.wrap(pkg:get(\"libfiles\"))) do\n                local filename = path.filename(libfile)\n                if filename:endswith(\".dll\") or filename:endswith(\".so\") or filename:find(\"%.so[%.%d+]+$\") or filename:endswith(\".dylib\") then\n                    table.insert(libfiles, libfile)\n                end\n            end\n        end\n    end\n    -- we can only reserve used libraries\n    if project.policy(\"install.strip_packagelibs\") then\n        if target:is_binary() or target:is_shared() or opt.binaryfile then\n            -- we need to get all deplibs, e.g. app -> libfoo.so -> libbar.so ...\n            -- @see https://github.com/xmake-io/xmake/issues/5325#issuecomment-2242597732\n            local deplibs = get_depend_libraries(opt.binaryfile or target:targetfile(), {\n                plat = target:plat(), arch = target:arch(),\n                recursive = true, resolve_path = true, resolve_hint_paths = libfiles})\n            if deplibs then\n                local depends = hashset.from(deplibs)\n                table.remove_if(libfiles, function (_, libfile) return not depends:has(libfile) end)\n            end\n        end\n    end\n    return libfiles\nend\n\n-- get target libraries\nfunction get_target_libfiles(target, libfiles, binaryfile, refs, opt)\n    if not refs[target] then\n        local plaindeps = target:get(\"deps\")\n        if plaindeps then\n            for _, depname in ipairs(plaindeps) do\n                local dep = target:dep(depname)\n                if dep then\n                    if dep:is_shared() then\n                        local depfile = dep:targetfile()\n                        if os.isfile(depfile) then\n                            table.insert(libfiles, depfile)\n                        end\n                        get_target_libfiles(dep, libfiles, dep:targetfile(), refs, opt)\n                    elseif dep:is_library() then\n                        get_target_libfiles(dep, libfiles, binaryfile, refs, opt)\n                    end\n                end\n            end\n        end\n        table.join2(libfiles, get_target_package_libfiles(target, table.join({binaryfile = binaryfile}, opt)))\n        refs[target] = true\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/utils/toolchain.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        toolchain.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.language.language\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_vstudio\")\n\n-- attempt to check vs environment\nfunction _check_vsenv(toolchain, check)\n\n    -- have been checked?\n    local vs = toolchain:config(\"vs\") or config.get(\"vs\")\n    if vs then\n        vs = tostring(vs)\n    end\n    local vcvars = toolchain:config(\"vcvars\")\n    if vs and vcvars then\n        return vs\n    end\n\n    -- find vstudio\n    local vs_toolset = toolchain:config(\"vs_toolset\") or config.get(\"vs_toolset\")\n    local vs_sdkver  = toolchain:config(\"vs_sdkver\") or config.get(\"vs_sdkver\")\n    local vstudio = find_vstudio({toolset = vs_toolset, sdkver = vs_sdkver})\n    if vstudio then\n\n        -- make order vsver\n        local vsvers = {}\n        for vsver, _ in pairs(vstudio) do\n            if not vs or vs ~= vsver then\n                table.insert(vsvers, vsver)\n            end\n        end\n        table.sort(vsvers, function (a, b) return tonumber(a) > tonumber(b) end)\n        if vs then\n            table.insert(vsvers, 1, vs)\n        end\n\n        -- get vcvarsall\n        for _, vsver in ipairs(vsvers) do\n            local vcvarsall = (vstudio[vsver] or {}).vcvarsall or {}\n            local vcvars = vcvarsall[toolchain:arch()]\n            if vcvars and vcvars.PATH and vcvars.INCLUDE and vcvars.LIB then\n                toolchain:config_set(\"vcvars\", vcvars)\n                toolchain:config_set(\"vcarchs\", table.orderkeys(vcvarsall))\n                toolchain:config_set(\"vs_toolset\", vcvars.VCToolsVersion)\n                toolchain:config_set(\"vs_sdkver\", vcvars.WindowsSDKVersion)\n                if check and check(toolchain, vcvars) then\n                    return vsver\n                end\n            end\n        end\n    end\nend\n\n-- check the visual studio\nfunction check_vstudio(toolchain, check)\n    local vs = _check_vsenv(toolchain, check)\n    if vs then\n        if toolchain:is_global() then\n            config.set(\"vs\", vs, {force = true, readonly = true})\n        end\n        toolchain:config_set(\"vs\", vs)\n        cprint(\"checking for Microsoft Visual Studio (%s) version ... ${color.success}%s\", toolchain:arch(), vs)\n    else\n        cprint(\"checking for Microsoft Visual Studio (%s) version ... ${color.nothing}${text.nothing}\", toolchain:arch())\n    end\n    return vs\nend\n\n-- add the given vs environment\nfunction _add_vsenv(toolchain, name, curenvs)\n\n    -- get vcvars\n    local vcvars = toolchain:config(\"vcvars\")\n    if not vcvars then\n        return\n    end\n\n    -- get the paths for the vs environment\n    local new = vcvars[name]\n    if new then\n        -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.\n        -- @see https://github.com/xmake-io/xmake/issues/4751\n        for k, c in pairs(curenvs) do\n            if name:lower() == k:lower() and name ~= k then\n                name = k\n                break\n            end\n        end\n        -- msvc-wine on linux\n        if (name == \"INCLUDE\" or name == \"LIB\") and not is_host(\"windows\") then\n            toolchain:add(\"runenvs\", name, path.joinenv(path.splitenv(new), \";\"))\n        else\n            for _, item in ipairs(path.splitenv(new)) do\n                toolchain:add(\"runenvs\", name, item)\n            end\n        end\n    end\nend\n\n-- get clang target\nfunction get_clang_target(toolchain)\n    local target\n    if toolchain:is_plat(\"windows\") then\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            target = \"x86_64-pc-windows-msvc\"\n        elseif toolchain:is_arch(\"i386\", \"x86\", \"i686\") then\n            target = \"i686-pc-windows-msvc\"\n        elseif toolchain:is_arch(\"arm64\", \"aarch64\") then\n            target = \"aarch64-pc-windows-msvc\"\n        elseif toolchain:is_arch(\"arm64ec\") then\n            target = \"arm64ec-pc-windows-msvc\"\n        elseif toolchain:is_arch(\"arm.*\") then\n            target = \"armv7-pc-windows-msvc\"\n        end\n    elseif toolchain:is_plat(\"mingw\") then\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            target = \"x86_64-w64-windows-gnu\"\n        elseif toolchain:is_arch(\"i386\", \"x86\", \"i686\") then\n            target = \"i686-w64-windows-gnu\"\n        elseif toolchain:is_arch(\"arm64\", \"aarch64\") then\n            target = \"aarch64-w64-windows-gnu\"\n        elseif toolchain:is_arch(\"arm.*\") then\n            target = \"armv7-w64-windows-gnu\"\n        end\n    elseif toolchain:is_plat(\"linux\") then\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            target = \"x86_64-linux-gnu\"\n        elseif toolchain:is_arch(\"i386\", \"x86\", \"i686\") then\n            target = \"i686-linux-gnu\"\n        elseif toolchain:is_arch(\"arm64\", \"aarch64\", \"arm64-v8a\") then\n            target = \"aarch64-linux-gnu\"\n        elseif toolchain:is_arch(\"arm.*\") then\n            target = \"armv7-linux-gnu\"\n        end\n    elseif toolchain:is_plat(\"cross\") then\n        target = toolchain:cross()\n        if target and target:endswith(\"-\") then\n            target = target:sub(1, -2)\n        end\n    end\n    return target\nend\n\n-- get clang target flags\n-- @see https://github.com/xmake-io/xmake/issues/7271\nfunction get_clang_target_flags(toolchain)\n    local target\n    if toolchain:is_cross() or toolchain:is_plat(\"windows\") then\n        target = get_clang_target(toolchain)\n        if target then\n            return \"--target=\" .. target\n        end\n    end\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        return \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        return \"-m32\"\n    end\nend\n\n-- get xcode/apple target triple for clang -target\n--\n-- e.g.\n-- - macosx: x86_64-apple-macos14.0\n-- - macosx(catalyst): arm64-apple-macos14.0-macabi\n-- - iphoneos: arm64-apple-ios18.2\n-- - iphoneos(simulator): x86_64-apple-ios18.2-simulator\n-- - appletvos: arm64-apple-tvos17.0\n-- - watchos: armv7k-apple-watchos10.0\n-- - applexros(simulator): x86_64-apple-xros1.0-simulator\n--\n-- configs:\n-- - appledev: simulator/catalyst\n-- - target_minver: deployment target version (ios 32-bit will be capped to 10)\nfunction get_xcode_target_triple(toolchain)\n    local arch = toolchain:arch()\n    local plat = toolchain:plat()\n    local platmap = {macosx = \"macos\", iphoneos = \"ios\", watchos = \"watchos\", appletvos = \"tvos\", applexros = \"xros\"}\n    plat = platmap[plat] or plat\n    local target_minver = toolchain:config(\"target_minver\") or config.get(\"target_minver\")\n    local appledev = toolchain:config(\"appledev\") or config.get(\"appledev\")\n    local target = format(\"%s-apple-%s\", arch, plat)\n    if target_minver then\n        if plat == \"ios\" and tonumber(target_minver) > 10 and (arch == \"armv7\" or arch == \"armv7s\" or arch == \"i386\") then\n            target_minver = \"10\"\n        end\n        target = target .. target_minver\n    end\n    if plat == \"macos\" then\n        if appledev == \"catalyst\" then\n            target = target .. \"-macabi\"\n        end\n    else\n        if appledev == \"simulator\" then\n            target = target .. \"-simulator\"\n        end\n    end\n    return target\nend\n\n-- add vs environments\nfunction add_vsenvs(toolchain, opt)\n    opt = opt or {}\n    local curenvs = os.getenvs()\n    local varnames = opt.varnames or {\"PATH\", \"LIB\", \"INCLUDE\", \"LIBPATH\"}\n    for _, name in ipairs(varnames) do\n        _add_vsenv(toolchain, name, curenvs)\n    end\n    for _, name in ipairs(find_vstudio.get_vcvars()) do\n        if not table.contains(varnames, name:upper()) then\n            _add_vsenv(toolchain, name, curenvs)\n        end\n    end\nend\n\n-- set llvm runtimes\nfunction set_llvm_runtimes(toolchain)\n    -- We should set them up uniformly here, because runtimes will be accessed early (in sanitizer),\n    -- which automatically triggers lazy loading of the toolchain.\n    -- However, if some runtime configurations are set in advance in the descriptor scope,\n    -- lazy loading will not be triggered when the runtimes are accessed, and some Windows runtimes may be lost.\n    --\n    -- @see https://github.com/xmake-io/xmake/pull/7146#issuecomment-3674402132\n    toolchain:set(\"runtimes\", \"c++_static\", \"c++_shared\", \"stdc++_static\", \"stdc++_shared\")\n    if toolchain:is_plat(\"windows\") then\n        toolchain:add(\"runtimes\", \"MT\", \"MTd\", \"MD\", \"MDd\")\n    end\nend\n\n-- check vc build tools sdk\nfunction check_vc_build_tools(toolchain, sdkdir, check)\n    local opt = {}\n    opt.sdkdir = sdkdir\n    opt.vs_toolset = toolchain:config(\"vs_toolset\") or config.get(\"vs_toolset\")\n    opt.vs_sdkver = toolchain:config(\"vs_sdkver\") or config.get(\"vs_sdkver\")\n\n    local vcvarsall = find_vstudio.find_build_tools(opt)\n    if not vcvarsall then\n        return\n    end\n\n    local vcvars = vcvarsall[toolchain:arch()]\n    if vcvars and vcvars.PATH and vcvars.INCLUDE and vcvars.LIB then\n        toolchain:config_set(\"vcvars\", vcvars)\n        toolchain:config_set(\"vcarchs\", table.orderkeys(vcvarsall))\n        toolchain:config_set(\"vs_toolset\", vcvars.VCToolsVersion)\n        toolchain:config_set(\"vs_sdkver\", vcvars.WindowsSDKVersion)\n        if check and check(toolchain, vcvars) then\n            return vcvars\n        end\n    end\nend\n\n-- is the compatible with the host?\nfunction is_compatible_with_host(name)\n    if is_host(\"linux\", \"macosx\", \"bsd\") then\n        if name:startswith(\"clang\") or name:startswith(\"gcc\") or name == \"llvm\" then\n            return true\n        end\n    elseif is_host(\"windows\") then\n        if name == \"msvc\" or name == \"llvm\" or name == \"clang-cl\" then\n            return true\n        end\n    end\nend\n\n-- get vs version\nfunction get_vsver(vs)\n    local vsvers = {[\"2026\"] = \"18\",\n                    [\"2022\"] = \"17\",\n                    [\"2019\"] = \"16\",\n                    [\"2017\"] = \"15\",\n                    [\"2015\"] = \"14\",\n                    [\"2013\"] = \"12\",\n                    [\"2012\"] = \"11\",\n                    [\"2010\"] = \"10\",\n                    [\"2008\"] = \"9\",\n                    [\"2005\"] = \"8\"}\n    return assert(vsvers[vs], \"unknown msvc version!\")\nend\n\n-- get vs toolset version, e.g. v143, v144, ..\nfunction get_vs_toolset_ver(vs_toolset)\n    local toolset_ver\n    if vs_toolset then\n        local verinfo = semver.new(vs_toolset)\n        toolset_ver = \"v\" .. verinfo:major() .. (tostring(verinfo:minor()):sub(1, 1) or \"0\")\n\n        -- @see https://github.com/xmake-io/xmake/pull/5176\n        if toolset_ver and toolset_ver == \"v144\" and verinfo:ge(\"14.40\") and verinfo:lt(\"14.50\") then\n            toolset_ver = \"v143\"\n        end\n    end\n    return toolset_ver\nend\n\n-- map compiler flags for package\nfunction map_compflags_for_package(package, langkind, name, values)\n    -- @note we need to patch package:sourcekinds(), because it wiil be called nf_runtime for gcc/clang\n    package.sourcekinds = function (self)\n        local sourcekind = language.langkinds()[langkind]\n        return sourcekind\n    end\n    local flags = compiler.map_flags(langkind, name, values, {target = package})\n    package.sourcekinds = nil\n    return flags\nend\n\n-- map linker flags for package\nfunction map_linkflags_for_package(package, targetkind, sourcekinds, name, values)\n    -- @note we need to patch package:sourcekinds(), because it wiil be called nf_runtime for gcc/clang\n    package.sourcekinds = function (self)\n        return sourcekinds\n    end\n    local flags = linker.map_flags(targetkind, sourcekinds, name, values, {target = package})\n    package.sourcekinds = nil\n    return flags\nend\n\n-- Check and cache llvm/clang driver info (e.g. -print-resource-dir/-print-target-triple) in toolchain:config().\n-- It must be collected during toolchain on_check so that toolchain on_load can use it without running clang again.\n-- @see https://github.com/xmake-io/xmake/issues/7337#issuecomment-3942499208\nfunction check_llvm_info(toolchain, clang, opt)\n    opt = opt or {}\n    if not clang then\n        return\n    end\n\n    local envs = opt.envs\n    local resourcedir = try {function () return os.iorunv(clang, {\"-print-resource-dir\"}, {envs = envs}) end}\n    if resourcedir then\n        resourcedir = path.normalize(resourcedir:trim())\n        dprint(\"checking for llvm resource dir ... %s\", resourcedir)\n        if #resourcedir > 0 and os.isdir(resourcedir) then\n            toolchain:config_set(\"llvm_resourcedir\", resourcedir)\n        end\n    end\n\n    local target_triple = try {function () return os.iorunv(clang, {\"-print-target-triple\"}, {envs = envs}) end}\n    if target_triple then\n        target_triple = target_triple:trim()\n        dprint(\"checking for llvm target triple ... %s\", target_triple)\n        if #target_triple > 0 then\n            toolchain:config_set(\"llvm_target_triple\", target_triple)\n        end\n    end\nend\n\n-- get llvm sdk resource directory\nfunction _get_llvm_resourcedir(toolchain)\n    return toolchain:config(\"llvm_resourcedir\") or nil\nend\n\n-- get llvm sdk root directory\nfunction _get_llvm_rootdir(toolchain)\n    local memcache = toolchain:memcache()\n    local cachekey = \"get_llvm_rootdir\"\n    local llvm_rootdir = memcache:get(cachekey)\n    if llvm_rootdir == nil then\n        local resourcedir = _get_llvm_resourcedir(toolchain)\n        if resourcedir then\n            llvm_rootdir = path.normalize(path.join(resourcedir, \"..\", \"..\", \"..\"))\n            if not os.isdir(llvm_rootdir) then\n                llvm_rootdir = nil\n            end\n        end\n        memcache:set(cachekey, llvm_rootdir or false)\n    end\n    return llvm_rootdir or nil\nend\n\n-- get compiler-rt info\nfunction _get_llvm_compiler_rtinfo(toolchain)\n    local memcache = toolchain:memcache()\n    local cachekey = \"get_llvm_compiler_rtinfo\"\n    local rtinfo = memcache:get(cachekey)\n    if rtinfo == nil then\n        local resourcedir = _get_llvm_resourcedir(toolchain)\n        if resourcedir  then\n            local res_libdir = path.join(resourcedir, \"lib\")\n            -- when -DLLVM_ENABLE_TARGET_RUNTIME_DIR=OFF rtdir is windows/ and rtlink is clang_rt.builtins_<arch>.lib\n            -- when ON rtdir is windows/<target-triple> and rtlink is clang_rt.builtins.lib\n            local target_triple = _get_llvm_target_triple(toolchain)\n            local arch = target_triple and target_triple:split(\"-\")[1]\n\n            local plat\n            if toolchain:is_plat(\"windows\", \"mingw\") then\n                plat = \"windows\"\n            elseif toolchain:is_plat(\"linux\") then\n                plat = \"linux\"\n            elseif toolchain:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\", \"applexros\") then\n                plat = \"darwin\"\n            end\n\n            local tripletdir = target_triple and path.join(res_libdir, \"windows\", target_triple)\n            tripletdir = os.isdir(tripletdir) or nil\n\n            local rtdir = tripletdir and path.join(plat, target_triple) or plat\n            rtinfo = {rtdir = res_libdir, rtlibdir = path.join(res_libdir, rtdir)}\n            if os.isdir(rtinfo.rtlibdir) and toolchain:is_plat(\"windows\", \"mingw\") then\n                local rtlink\n                if tripletdir then\n                    rtlink = \"clang_rt.builtins.lib\"\n                elseif arch then\n                    rtlink = \"clang_rt.builtins-\" .. arch .. \".lib\"\n                end\n                if rtlink and os.isfile(path.join(rtinfo.rtlibdir, rtlink)) then\n                    rtinfo.rtlink = path.join(rtdir, rtlink)\n                end\n            end\n        end\n        memcache:set(cachekey, rtinfo or false)\n    end\n    return rtinfo or nil\nend\n\n-- get llvm target triple\nfunction _get_llvm_target_triple(toolchain)\n    return toolchain:config(\"llvm_target_triple\") or nil\nend\n\n-- get llvm toolchain dirs\nfunction get_llvm_dirs(toolchain)\n    local memcache = toolchain:memcache()\n    local cachekey = \"get_llvm_dirs\"\n    local llvm_dirs = memcache:get(cachekey)\n    if llvm_dirs == nil then\n        local rootdir = toolchain:sdkdir()\n        if not rootdir and (toolchain:is_plat(\"windows\") or is_host(\"windows\")) then\n            rootdir = _get_llvm_rootdir(toolchain)\n        end\n\n        local bindir, libdir, cxxlibdir, includedir, cxxincludedir, resourcedir, rtdir, rtlink, rtlibdir\n        if rootdir then\n            bindir = path.join(rootdir, \"bin\")\n            bindir = os.isdir(bindir) and bindir or nil\n\n            libdir = path.join(rootdir, \"lib\")\n            libdir = os.isdir(libdir) and libdir or nil\n\n            if libdir then\n                cxxlibdir = path.join(libdir, \"c++\")\n                cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil\n                if not cxxlibdir then\n                    local target_triple = _get_llvm_target_triple(toolchain)\n                    if target_triple then\n                        cxxlibdir = path.join(libdir, target_triple)\n                        cxxlibdir = os.isdir(cxxlibdir) and cxxlibdir or nil\n                    end\n                end\n            end\n\n            includedir = path.join(rootdir, \"include\")\n            includedir = os.isdir(includedir) and includedir or nil\n\n            if includedir then\n                cxxincludedir = path.join(includedir, \"c++\", \"v1\")\n                cxxincludedir = os.isdir(cxxincludedir) and cxxincludedir or nil\n            end\n\n            resourcedir = _get_llvm_resourcedir(toolchain)\n            local rtinfo = _get_llvm_compiler_rtinfo(toolchain)\n            if rtinfo then\n                rtdir = rtinfo.rtdir\n                rtlink = rtinfo.rtlink\n                rtlibdir = rtinfo.rtlibdir\n            end\n        end\n\n        llvm_dirs = {rootdir = rootdir,\n                     bindir = bindir,\n                     libdir = libdir,\n                     cxxlibdir = cxxlibdir,\n                     includedir = includedir,\n                     cxxincludedir = cxxincludedir,\n                     resourcedir = resourcedir,\n                     rtdir = rtdir,\n                     rtlibdir = rtlibdir,\n                     rtlink = rtlink }\n        memcache:set(cachekey, llvm_dirs)\n      end\n      return llvm_dirs\nend\n\n-- add runenvs for llvm\nfunction add_llvm_runenvs(toolchain)\n    local dirs = get_llvm_dirs(toolchain)\n    if dirs then\n        if dirs.bindir and (toolchain:is_plat(\"windows\") or is_host(\"windows\")) then\n            toolchain:add(\"runenvs\", \"PATH\", dirs.bindir)\n        end\n        for _, dir in ipairs({dirs.libdir or false, dirs.cxxlibdir or false, dirs.rtlibdir or false}) do\n            if dir then\n                if toolchain:is_plat(\"windows\") or is_host(\"windows\") then\n                    toolchain:add(\"runenvs\", \"PATH\", dir)\n                elseif toolchain:is_plat(\"linux\", \"bsd\") then\n                    toolchain:add(\"runenvs\", \"LD_LIBRARY_PATH\", dir)\n                elseif toolchain:is_plat(\"macosx\") then\n                    -- using use DYLD_FALLBACK_LIBRARY_PATH instead of DYLD_LIBRARY_PATH to avoid symbols error when running homebrew llvm (which is linked to system libc++)\n                    -- e.g dyld[5195]: Symbol not found: __ZnwmSt19__type_descriptor_t\n                    -- Referenced from: <378C7CC2-7CD6-3B88-9C66-FE198E30462B> /usr/local/Cellar/llvm/21.1.5/bin/clang-21\n                    -- Expected as weak-def export from some loaded dylibSymbol not found: __ZnamSt19__type_descriptor_t\n                    toolchain:add(\"runenvs\", \"DYLD_FALLBACK_LIBRARY_PATH\", dir)\n                end\n            end\n        end\n    end\nend\n\n-- get sanitizer flags\n--\n-- @param target    the target or package\n-- @param opt       the options, e.g. {checkmode = \"address\", sourcekind = \"cxx\"}\n--\n-- @return          the sanitizer flags, e.g. {cflags = {}, ldflags = {}}\n--\nfunction get_sanitizer_flags(target, opt)\n    opt = opt or {}\n    local checkmode = opt.checkmode\n    local sourcekind = opt.sourcekind\n\n    -- add cflags\n    local result = {}\n    local flagnames = {\n        cc = \"cflags\",\n        cxx = \"cxxflags\",\n        mm = \"mflags\",\n        mxx = \"mxxflags\"\n    }\n    local flagname = flagnames[sourcekind]\n    if flagname and target:has_tool(sourcekind, \"cl\", \"clang\", \"clangxx\", \"clang_cl\", \"gcc\", \"gxx\") then\n        result[flagname] = \"-fsanitize=\" .. checkmode\n    end\n\n    -- add ldflags\n    local ldflags = {}\n    -- msvc does not have an fsanitize linker flag, so the 'link' tool is excluded\n    if target:has_tool(\"ld\", \"clang\", \"clangxx\", \"gcc\", \"gxx\") then\n        table.insert(ldflags, \"-fsanitize=\" .. checkmode)\n    end\n\n    -- add windows ldflags\n    if target:is_plat(\"windows\") and checkmode == \"address\" and not target:has_tool(\"cxx\", \"cl\") then\n        assert(target:has_runtime(\"MD\", \"MT\"), \"clang asan only support MD/MT runtime on windows\")\n        if target:has_tool(\"cxx\", \"clang\", \"clangxx\") then\n            if target:has_runtime(\"MT\") then\n                table.insert(ldflags, \"-D_MT\")\n            elseif target:has_runtime(\"MD\") then\n                table.join2(ldflags, {\"-D_MT\", \"-D_DLL\"})\n            end\n        elseif target:has_tool(\"cxx\", \"clang_cl\") then\n            -- TODO: This is hack, try to find a way to let cmake use clang++ for link\n            -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/26430\n            local toolchain = target:toolchain(\"clang-cl\") or target:toolchain(\"clang\")\n            local libdir = assert(get_llvm_dirs(toolchain).rtlibdir, \"clang resource directory not found\")\n\n            local kind\n            if target:has_runtime(\"MD\") then\n                kind = \"dynamic\"\n            elseif target:has_runtime(\"MT\") then\n                kind = \"static\"\n            end\n\n            local driver = target:has_tool(\"ld\", \"lld_link\", \"link\") and \"\" or \"-Wl,\"\n            local thunk = path.join(libdir, string.format(\"clang_rt.asan_%s_runtime_thunk-x86_64.lib\", kind))\n            table.join2(ldflags, {\n                path.unix(path.join(libdir, \"clang_rt.asan_dynamic-x86_64.lib\")),\n                driver .. \"/WHOLEARCHIVE:\" .. path.unix(thunk),\n                driver .. \"/INFERASANLIBS:NO\",\n            })\n        end\n    end\n\n    if #ldflags > 0 then\n        result.ldflags = ldflags\n        result.shflags = ldflags\n    end\n    return result\nend\n\n-- get zig target\nfunction get_zig_target(toolchain)\n    local zig_version = toolchain:config(\"zig_version\")\n\n    -- get target from cross only for cross-compilation\n    -- @see https://github.com/xmake-io/xmake/issues/7180\n    local target\n    if not target and toolchain:is_cross() then\n        target = toolchain:cross()\n    end\n\n    -- get target from arch\n    if not target then\n        local arch\n        if toolchain:is_arch(\"arm64\", \"arm64-v8a\") then\n            arch = \"aarch64\"\n        elseif toolchain:is_arch(\"arm\", \"armv7\") then\n            arch = \"arm\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            if zig_version and semver.compare(zig_version, \"0.11\") >= 0 then\n                arch = \"x86\"\n            else\n                arch = \"i386\"\n            end\n        elseif toolchain:is_arch(\"riscv64\") then\n            arch = \"riscv64\"\n        elseif toolchain:is_arch(\"loong64\") then\n            arch = \"loongarch64\"\n        elseif toolchain:is_arch(\"mips.*\") then\n            arch = toolchain:arch()\n        elseif toolchain:is_arch(\"ppc64\") then\n            arch = \"powerpc64\"\n        elseif toolchain:is_arch(\"ppc\") then\n            arch = \"powerpc\"\n        elseif toolchain:is_arch(\"s390x\") then\n            arch = \"s390x\"\n        else\n            arch = \"x86_64\"\n        end\n\n        if toolchain:is_plat(\"cross\") then\n            -- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64\n        elseif toolchain:is_plat(\"macosx\") then\n            --@see https://github.com/ziglang/zig/issues/14226\n            target = arch .. \"-macos-none\"\n        elseif toolchain:is_plat(\"linux\") then\n            if arch == \"arm\" then\n                target = \"arm-linux-gnueabi\"\n            elseif arch == \"mips64\" or arch == \"mips64el\" then\n                target = arch .. \"-linux-gnuabi64\"\n            else\n                target = arch .. \"-linux-gnu\"\n            end\n        elseif toolchain:is_plat(\"windows\") then\n            target = arch .. \"-windows-msvc\"\n        elseif toolchain:is_plat(\"mingw\") then\n            target = arch .. \"-windows-gnu\"\n        end\n    end\n    return target\nend\n\n-- check if the file is a c++ header file extension\nfunction is_cxx_headerext(extension)\n    -- prioritize .h* extensions to filter out most cases quickly\n    if extension:startswith(\".h\") then\n        return true\n    end\n\n    local headerexts = _g.headerexts\n    if not headerexts then\n        local other_header_extensions = {\n            \".inl\", \".ipp\", \".tcc\", \".tpl\", \".inc\"\n        }\n        headerexts = hashset.from(other_header_extensions)\n        _g.headerexts = headerexts\n    end\n    return headerexts:has(extension) or false\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/trim_trailing_spaces.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        trim_trailing_spaces.lua\n--\n\nfunction main(pattern)\n    for _, filepath in ipairs(os.files(pattern)) do\n        local filedata = io.readfile(filepath)\n        if filedata then\n            local filedata2 = {}\n            for _, line in ipairs(filedata:split('\\n', {strict = true})) do\n                line = line:rtrim()\n                table.insert(filedata2, line)\n            end\n            io.writefile(filepath, table.concat(filedata2, \"\\n\"))\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/utils/upgrade_vsproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        upgrade_vsproj.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.toolchain\")\nimport(\"plugins.project.vstudio.impl.vsinfo\", {rootdir = os.programdir()})\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- the options\nlocal options = {\n    {nil, \"vs\",              \"kv\", nil, \"Set the vs version. (default: latest).\"     }\n,   {nil, \"vs_toolset\",      \"kv\", nil, \"Set the vs toolset.\"                        }\n,   {nil, \"vs_sdkver\",       \"kv\", nil, \"Set the vs sdk version.\"                    }\n,   {nil, \"vs_projectfiles\", \"vs\", nil, \"Set the solution or project files.\"         }\n}\n\n-- upgrade *.sln\nfunction _upgrade_sln(projectfile, opt)\n    opt = opt or {}\n    local msvc = opt.msvc or import(\"core.tool.toolchain\").load(\"msvc\")\n    local vs_version = opt.vs or msvc:config(\"vs\")\n    local vs_info = assert(vsinfo(tonumber(vs_version)), \"unknown vs version!\")\n    io.gsub(projectfile, \"Microsoft Visual Studio Solution File, Format Version %d+%.%d+\",\n        \"Microsoft Visual Studio Solution File, Format Version \" .. vs_info.solution_version .. \".00\")\n    io.gsub(projectfile, \"# Visual Studio %d+\", \"# Visual Studio \" .. vs_version)\nend\n\n-- upgrade *.vcxproj\nfunction _upgrade_vcxproj(projectfile, opt)\n    opt = opt or {}\n    local msvc = opt.msvc or import(\"core.tool.toolchain\").load(\"msvc\")\n    local vs_version = opt.vs or msvc:config(\"vs\")\n    local vs_info = assert(vsinfo(tonumber(vs_version)), \"unknown vs version!\")\n    local vs_sdkver = opt.vs_sdkver or msvc:config(\"vs_sdkver\") or vs_info.sdk_version\n    local vs_toolset = toolchain_utils.get_vs_toolset_ver(opt.vs_toolset or msvc:config(\"vs_toolset\")) or vs_info.toolset_version\n    local vs_toolsver = vs_info.project_version\n    io.gsub(projectfile, \"<PlatformToolset>v%d+</PlatformToolset>\",\n        \"<PlatformToolset>\" .. vs_toolset .. \"</PlatformToolset>\")\n    io.gsub(projectfile, \"<WindowsTargetPlatformVersion>.*</WindowsTargetPlatformVersion>\",\n        \"<WindowsTargetPlatformVersion>\" .. vs_sdkver .. \"</WindowsTargetPlatformVersion>\")\n    if vs_toolsver then\n        io.gsub(projectfile, \"ToolsVersion=\\\".-\\\"\", \"ToolsVersion=\\\"\" .. vs_toolsver .. \"\\\"\")\n    end\nend\n\n-- upgrade vs project file\nfunction upgrade(projectfile, opt)\n    if projectfile:endswith(\".sln\") then\n        _upgrade_sln(projectfile, opt)\n    elseif projectfile:endswith(\".vcxproj\") or projectfile:endswith(\".props\") then\n        _upgrade_vcxproj(projectfile, opt)\n    end\nend\n\n-- https://github.com/xmake-io/xmake/issues/3871\nfunction main(...)\n    local argv = {...}\n    local opt  = option.parse(argv, options, \"Upgrade all the vs project files.\"\n                                           , \"\"\n                                           , \"Usage: xmake l private.utils.upgrade_vsproj [options]\")\n\n    for _, projectfile in ipairs(opt.vs_projectfiles) do\n        upgrade(projectfile, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/add-repo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        add-repo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Add the given remote repository url.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"name\",   \"v\", nil, \"The repository name.\"   },\n        {nil, \"url\",    \"v\", nil, \"The repository url\"     },\n        {nil, \"branch\", \"v\", nil, \"The repository branch\"  }\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo add-repo [options] name url [branch]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"add-repo\")\n    end\n    return options, show_options, description\nend\n\n-- add repository\nfunction _add_repository(name, url, branch)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- add it\n    local repo_argv = {\"repo\", \"--add\", \"--global\"}\n    if option.get(\"verbose\") then\n        table.insert(repo_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(repo_argv, \"-D\")\n    end\n    table.insert(repo_argv, name)\n    table.insert(repo_argv, url)\n    if branch then\n        table.insert(repo_argv, branch)\n    end\n    os.vexecv(os.programfile(), repo_argv)\nend\n\n-- main entry\nfunction main()\n    local name = option.get(\"name\")\n    local url  = option.get(\"url\")\n    if name and url then\n        _add_repository(name, url, option.get(\"branch\"))\n    else\n        raise(\"please specify the repository name and url to be added.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/clean.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        clean.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Clear all package caches and remove all not-referenced packages.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"cache\",      \"k\", nil,  \"Just clean packages cache.\"},\n        {nil, \"packages\",   \"vs\", nil, \"The packages list (support lua pattern).\",\n                                       \"e.g.\",\n                                       \"    - xrepo clean\",\n                                       \"    - xrepo clean zlib\",\n                                       \"    - xrepo clean zlib bo*\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo clean [options] [packages]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"clean\")\n    end\n    return options, show_options, description\nend\n\n-- clean packages\nfunction _clean_packages(packages)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    os.vrunv(os.programfile(), config_argv)\n\n    -- do clean\n    local require_argv = {\"require\", \"--clean\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    if option.get(\"cache\") then\n        table.insert(require_argv, \"--clean_modes=cache\")\n    end\n    if packages then\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- main entry\nfunction main()\n    _clean_packages(option.get(\"packages\"))\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/download.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        download.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Only download the given package source archive files.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",          \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}},\n        {'p', \"plat\",          \"kv\", nil, \"Set the given platform.\"                                                                                        },\n        {'a', \"arch\",          \"kv\", nil, \"Set the given architecture.\"                                                                                    },\n        {'m', \"mode\",          \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}},\n        {'f', \"configs\",       \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo download -f \\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo download -f \\\"regex=true,thread=true\\\" boost\"                                                          },\n        {'j', \"jobs\",          \"kv\", tostring(os.default_njob()),\n                                          \"Set the number of parallel download jobs.\"                                                                      },\n        {nil, \"toolchain\",      \"kv\", nil, \"Set the toolchain name.\"                                                                                       },\n        {nil, \"toolchain_host\", \"kv\", nil, \"Set the host toolchain name.\"                                                                                  },\n        {nil, \"includes\",      \"kv\", nil, \"Includes extra lua configuration files.\",\n                                       \"e.g.\",\n                                       \"    - xrepo download -p cross --toolchain=mytool --includes='toolchain1.lua\" .. path.envsep() .. \"toolchain2.lua'\" },\n        {category = \"Other Configuration\"                                                                                                                  },\n        {nil, \"force\",         \"k\",  nil, \"Force to redownload all packages.\"                                                                              },\n        {nil, \"shallow\",       \"k\",  nil, \"Does not download dependent packages.\"                                                                          },\n        {'o', \"outputdir\",     \"kv\", \"packages\",\"Set the packages download output directory.\"                                                              },\n        {                                                                                                                                                  },\n        {nil, \"packages\",      \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo download zlib boost\",\n                                       \"    - xrepo download /tmp/zlib.lua\",\n                                       \"    - xrepo download -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo download -p android [--ndk=/xxx] -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo download -p mingw [--mingw=/xxx] -k shared zlib\",\n                                       \"    - xrepo download conan::zlib/1.2.11 vcpkg::zlib\",\n                                        values = function (complete, opt) return import(\"private.xrepo.quick_search.completion\")(complete, opt) end        }\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo download [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"download\")\n    end\n    return options, show_options, description\nend\n\n-- download packages\nfunction _download_packages(packages)\n\n    -- is package configuration file? e.g. xrepo download xxx.lua\n    --\n    -- xxx.lua\n    --   add_requires(\"libpng\", {system = false})\n    --   add_requireconfs(\"libpng.*\", {configs = {shared = true}})\n    local packagefile\n    if type(packages) == \"string\" or #packages == 1 then\n        local filepath = table.unwrap(packages)\n        if type(filepath) == \"string\" and filepath:endswith(\".lua\") and os.isfile(filepath) then\n            packagefile = path.absolute(filepath)\n        end\n    end\n\n    -- add includes to rcfiles\n    local rcfiles = {}\n    local includes = option.get(\"includes\")\n    if includes then\n        for _, includefile in ipairs(path.splitenv(includes)) do\n            table.insert(rcfiles, path.absolute(includefile))\n        end\n    end\n\n    -- enter working project directory\n    local subdir = \"working\"\n    if packagefile then\n        subdir = subdir .. \"-\" .. hash.uuid(packagefile):split('-')[1]\n    end\n    local origindir = os.curdir()\n    local workdir = path.join(os.tmpdir(), \"xrepo\", subdir)\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n    if packagefile then\n        assert(os.isfile(\"xmake.lua\"), \"xmake.lua not found!\")\n        io.writefile(\"xmake.lua\", ('includes(\"%s\")\\ntarget(\"test\", {kind = \"phony\"})'):format((packagefile:gsub(\"\\\\\", \"/\"))))\n    end\n\n    -- disable xmake-stats\n    os.setenv(\"XMAKE_STATS\", \"false\")\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\", \"--require=n\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    if option.get(\"toolchain\") then\n        table.insert(config_argv, \"--toolchain=\" .. option.get(\"toolchain\"))\n    end\n    if option.get(\"toolchain_host\") then\n        table.insert(config_argv, \"--toolchain_host=\" .. option.get(\"toolchain_host\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    local envs = {}\n    if #rcfiles > 0 then\n        envs.XMAKE_RCFILES = path.joinenv(rcfiles)\n    end\n    os.vrunv(os.programfile(), config_argv, {envs = envs})\n\n    -- do download\n    local require_argv = {\"require\", \"--download\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    if option.get(\"jobs\") then\n        table.insert(require_argv, \"-j\")\n        table.insert(require_argv, option.get(\"jobs\"))\n    end\n    if option.get(\"force\") then\n        table.insert(require_argv, \"--force\")\n    end\n    if option.get(\"shallow\") then\n        table.insert(require_argv, \"--shallow\")\n    end\n    local outputdir = option.get(\"outputdir\")\n    if outputdir then\n        if not path.is_absolute(outputdir) then\n            outputdir = path.absolute(outputdir, os.workingdir())\n        end\n        table.insert(require_argv, \"--packagedir=\" .. outputdir)\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.system  = false\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if not packagefile then\n        -- avoid overriding extra configs in add_requires/xmake.lua\n        if extra then\n            local extra_str = string.serialize(extra, {indent = false, strip = true})\n            table.insert(require_argv, \"--extra=\" .. extra_str)\n        end\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv, {envs = envs})\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _download_packages(packages)\n    else\n        raise(\"please specify the packages to be downloaded.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/env.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        env.lua\n--\n\n-- imports\nimport(\"core.base.tty\")\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.base.hashset\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.run.runenvs\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Set environment and execute command, or print environment.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"show\",       \"k\",  nil, \"Only show environment information.\"  },\n        {nil, \"add\",        \"k\",  nil, \"Add global environment config.\",\n                                       \"e.g.\",\n                                       \"    - xrepo env --add base.lua\",\n                                       \"    - xrepo env --add myenv.lua\"},\n        {nil, \"remove\",     \"k\",  nil, \"Remove global environment config.\",\n                                       \"e.g.\",\n                                       \"    - xrepo env --remove base\",\n                                       \"    - xrepo env --remove myenv\"},\n        {\"l\", \"list\",       \"k\",  nil, \"List all global environment configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo env --list\"},\n        {'b', \"bind\",       \"kv\", nil, \"Bind the specified environment or package.\",\n                                       \"e.g.\",\n                                       \"    - xrepo env -b base shell\",\n                                       \"    - xrepo env -b myenv shell\",\n                                       \"    - xrepo env -b \\\"python 3.x\\\" shell\",\n                                       \"    - xrepo env -b \\\"cmake,ninja,python 3.x\\\" shell\",\n                                       \"    - xrepo env -b \\\"luajit 2.x\\\" luajit xx.lua\"},\n        {},\n        {nil, \"program\",    \"v\",  nil, \"Set the program name to be run.\",\n                                       \"e.g.\",\n                                       \"    - xrepo env\",\n                                       \"    - xrepo env bash\",\n                                       \"    - xrepo env shell (it will load bash/sh/cmd automatically)\",\n                                       \"    - xrepo env python\",\n                                       \"    - xrepo env luajit xx.lua\"},\n        {nil, \"arguments\",  \"vs\", nil, \"Set the program arguments to be run\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo env [options] [program] [arguments]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"env\")\n    end\n    return options, show_options, description\nend\n\n-- enter the working project\nfunction _enter_project()\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working-\" .. tty.session_id())\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n        os.rm(\"*\")\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    end\n    project.chdir(workdir)\nend\n\n-- remove repeat environment values\nfunction _deduplicate_pathenv(value)\n    if value then\n        local itemset = {}\n        local results = {}\n        for _, item in ipairs(path.splitenv(value)) do\n            if not itemset[item] then\n                table.insert(results, item)\n                itemset[item] = true\n            end\n        end\n        if #results > 0 then\n            value = path.joinenv(results)\n        end\n    end\n    return value\nend\n\n-- get environment directory\nfunction _get_envsdir()\n    return path.join(global.directory(), \"envs\")\nend\n\n-- get builtin environment directory\nfunction _get_envsdir_builtin()\n    return path.join(os.programdir(), \"scripts\", \"xrepo\", \"envs\")\nend\n\n-- get envfironment files\nfunction _get_envfiles()\n    local envfiles = {}\n    for _, envsdir in ipairs({_get_envsdir(), _get_envsdir_builtin()}) do\n        for _, envfile in ipairs(os.files(path.join(envsdir, \"*.lua\"))) do\n            envfiles[path.basename(envfile)] = envfile\n        end\n    end\n    return envfiles\nend\n\n-- get bound environment files or packages\nfunction _get_boundenvs(opt)\n    local packages = {}\n    local files = {}\n    local bind = (opt and opt.bind) or option.get(\"bind\")\n    if bind then\n        local envfiles = _get_envfiles()\n        for _, binditem in ipairs(bind:split(',', {plain = true})) do\n            binditem = binditem:trim()\n            if envfiles[binditem] then\n                table.insert(files, envfiles[binditem])\n            else\n                table.insert(packages, binditem)\n            end\n        end\n    else\n        local program = option.get(\"program\")\n        if program then\n            table.insert(packages, program)\n        end\n    end\n    return packages, files\nend\n\n-- add values to environment variable\nfunction _addenvs(envs, name, ...)\n    local values = {...}\n    if #values > 0 then\n        local oldenv = envs[name]\n        local appendenv = path.joinenv(values)\n        if oldenv == \"\" or oldenv == nil then\n            envs[name] = appendenv\n        else\n            envs[name] = appendenv .. path.envsep() .. oldenv\n        end\n    end\nend\n\n-- add package environments\nfunction _package_addenvs(envs, instance)\n\n    -- only for xmake::package\n    if instance:is_system() then\n        return\n    end\n\n    -- add run envs, e.g. PATH, LD_LIBRARY_PATH, DYLD_LIBRARY_PATH\n    local installdir = instance:installdir({readonly = true})\n    for name, values in pairs(instance:envs()) do\n        _addenvs(envs, name, table.unpack(table.wrap(values)))\n    end\n\n    -- add library envs, e.g. ACLOCAL_PATH, PKG_CONFIG_PATH, CMAKE_PREFIX_PATH\n    if instance:is_library() then\n        local pkgconfig = path.join(installdir, \"lib\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            _addenvs(envs, \"PKG_CONFIG_PATH\", pkgconfig)\n        end\n        pkgconfig = path.join(installdir, \"share\", \"pkgconfig\")\n        if os.isdir(pkgconfig) then\n            _addenvs(envs, \"PKG_CONFIG_PATH\", pkgconfig)\n        end\n        local aclocal = path.join(installdir, \"share\", \"aclocal\")\n        if os.isdir(aclocal) then\n            _addenvs(envs, \"ACLOCAL_PATH\", aclocal)\n        end\n        _addenvs(envs, \"CMAKE_PREFIX_PATH\", installdir)\n        if instance:is_plat(\"windows\") then\n            _addenvs(envs, \"INCLUDE\", path.join(installdir, \"include\"))\n            _addenvs(envs, \"LIBPATH\", path.join(installdir, \"lib\"))\n        else\n            _addenvs(envs, \"CPATH\", path.join(installdir, \"include\"))\n            _addenvs(envs, \"LIBRARY_PATH\", path.join(installdir, \"lib\"))\n        end\n    end\nend\n\n-- add toolchain environments\nfunction _toolchain_addenvs(envs)\n    for _, name in ipairs(project.get(\"target.toolchains\")) do\n        local toolchain_opt = project.extraconf(\"target.toolchains\", name)\n        local toolchain_inst = toolchain.load(name, toolchain_opt)\n        if toolchain_inst then\n            for k, v in pairs(toolchain_inst:runenvs()) do\n                _addenvs(envs, k, table.unpack(path.splitenv(v)))\n            end\n        end\n    end\nend\n\n-- add target environments\nfunction _target_addenvs(envs)\n    for _, target in ipairs(project.ordertargets()) do\n        if target:is_binary() then\n            _addenvs(envs, \"PATH\", target:targetdir())\n        elseif target:is_shared() then\n            if is_host(\"windows\") then\n                _addenvs(envs, \"PATH\", target:targetdir())\n            elseif is_host(\"macosx\") then\n                _addenvs(envs, \"DYLD_LIBRARY_PATH\", target:targetdir())\n            else\n                _addenvs(envs, \"LD_LIBRARY_PATH\", target:targetdir())\n            end\n        end\n        -- add run environments\n        local addrunenvs = runenvs.make(target)\n        for name, values in pairs(addrunenvs) do\n            _addenvs(envs, name, table.unpack(table.wrap(values)))\n        end\n    end\nend\n\n-- get package environments\nfunction _package_getenvs(opt)\n    local envs = os.getenvs()\n    local packages, envfiles = _get_boundenvs(opt)\n    local has_envfiles = #envfiles > 0\n    local has_packages = #packages > 0\n    local in_project = os.isfile(os.projectfile()) and not option.get(\"bind\")\n    local oldir = os.curdir()\n    if not in_project then\n        _enter_project()\n    end\n    if has_envfiles then\n        table.join2(project.rcfiles(), envfiles)\n    end\n    if has_packages then\n        local envfile = os.tmpfile() .. \".lua\"\n        local file = io.open(envfile, \"w\")\n        for _, requirename in ipairs(packages) do\n            file:print(\"add_requires(\\\"%s\\\")\", requirename)\n        end\n        file:close()\n        table.insert(project.rcfiles(), envfile)\n    end\n    if in_project or has_envfiles or has_packages then\n        task.run(\"config\", {}, {disable_dump = true})\n        if in_project or has_envfiles then\n            _toolchain_addenvs(envs)\n        end\n        local requires, requires_extra = get_requires()\n        for _, instance in ipairs(package.load_packages(requires, {requires_extra = requires_extra})) do\n            _package_addenvs(envs, instance)\n        end\n        if in_project then\n            _target_addenvs(envs)\n        end\n    end\n    local results = {}\n    for k, v in pairs(envs) do\n        results[k] = _deduplicate_pathenv(v)\n    end\n    os.cd(oldir)\n    return results\nend\n\n-- get environment setting script\nfunction _get_env_script(envs, shell, del)\n    local prefix = \"\"\n    local connector = \"=\"\n    local suffix = \"\"\n    local default = \"\"\n    if shell == \"powershell\" or shell == \"pwsh\" then\n        prefix = \"[Environment]::SetEnvironmentVariable('\"\n        connector = \"','\"\n        suffix = \"')\"\n        default = \"$Null\"\n    elseif shell == \"cmd\" then\n        prefix = \"@set \\\"\"\n        suffix = \"\\\"\"\n    elseif shell:endswith(\"sh\") then\n        if del then\n            prefix = \"unset '\"\n            connector = \"'\"\n        else\n            prefix = \"export '\"\n            connector = \"'='\"\n            suffix = \"'\"\n        end\n    end\n    local exceptions = hashset.of(\"_\", \"PS1\", \"PROMPT\", \"!;\", \"!EXITCODE\")\n    local ret = \"\"\n    if del then\n        for name, _ in pairs(envs) do\n            if not exceptions:has(name) then\n                ret = ret .. prefix .. name .. connector .. default .. suffix .. \"\\n\"\n            end\n        end\n    else\n        for name, value in pairs(envs) do\n            if not exceptions:has(name) then\n                ret = ret .. prefix .. name .. connector .. value .. suffix .. \"\\n\"\n            end\n        end\n    end\n    return ret\nend\n\n-- get prompt\nfunction _get_prompt(bnd)\n    bnd = bnd or option.get(\"bind\")\n    local prompt\n    local packages, envfiles = _get_boundenvs({bind = bnd})\n    if #packages > 0 or #envfiles > 0 then\n        if #packages == 0 and #envfiles == 1 then\n            prompt = path.basename(envfiles[1])\n        else\n            prompt = bnd:sub(1, math.min(#bnd, 16))\n            if bnd ~= prompt then\n                prompt = prompt .. \"..\"\n            end\n        end\n        prompt = \"[\" .. prompt .. \"]\"\n    elseif not bnd then\n        assert(os.isfile(os.projectfile()), \"xmake.lua not found!\")\n        prompt = path.filename(os.projectdir())\n        prompt = \"[\" .. prompt .. \"]\"\n    end\n    return prompt or \"\"\nend\n\n-- get information of current virtual environment\nfunction info(key, bnd)\n    if key == \"prompt\" then\n        local prompt = _get_prompt(bnd)\n        io.write(prompt)\n    elseif key == \"envfile\" then\n        print(os.tmpfile())\n    elseif key == \"config\" then\n        _package_getenvs({bind = bnd})\n    elseif key:startswith(\"script.\") then\n        local shell = key:match(\"script%.(.+)\")\n        io.write(_get_env_script(_package_getenvs({bind = bnd}), shell, false))\n    elseif key:startswith(\"backup.\") then\n        local shell = key:match(\"backup%.(.+)\")\n\n        -- remove current environment variables first\n        io.write(_get_env_script(_package_getenvs({bind = bnd}), shell, true))\n        io.write(_get_env_script(os.getenvs(), shell, false))\n    end\nend\n\n-- run shell\nfunction _run_shell(envs)\n    local shell = os.shell()\n    local args = table.wrap(option.get(\"arguments\"))\n    if shell == \"pwsh\" or shell == \"powershell\" then\n        os.execv(\"pwsh\", args, {envs = envs})\n    elseif shell == \"nu\" then\n        if #args ~= 0 then\n            table.insert(args, 1, \"-c\")\n        end\n        os.execv(\"nu\", args, {envs = envs})\n    elseif shell:endswith(\"sh\") then\n        local prompt = _get_prompt()\n        local ps1 = os.getenv(\"PS1\")\n        if ps1 then\n            prompt = prompt .. ps1\n        elseif is_host(\"macosx\") then\n            prompt = prompt .. \" \\\\W > \"\n        else\n            prompt = prompt .. \" > \"\n        end\n        os.execv(shell, args, {envs = table.join({PS1 = prompt}, envs)})\n    elseif shell == \"cmd\" or is_host(\"windows\") then\n        local prompt = _get_prompt()\n        prompt = prompt .. \" $P$G\"\n        local args = table.join({\"/k\", \"set PROMPT=\" .. prompt}, args)\n        os.execv(\"cmd\", args, {envs = envs})\n    else\n        assert(\"shell not found!\")\n    end\nend\n\nfunction main()\n    if option.get(\"list\") then\n        local envname = option.get(\"program\")\n        if envname then\n            for _, envsdir in ipairs({_get_envsdir(), _get_envsdir_builtin()}) do\n                local envfile = path.join(envsdir, envname .. \".lua\")\n                if os.isfile(envfile) then\n                    print(\"%s:\", envfile)\n                    io.cat(envfile)\n                end\n            end\n        else\n            print(\"%s (builtin):\", _get_envsdir_builtin())\n            local count = 0\n            for _, envfile in ipairs(os.files(path.join(_get_envsdir_builtin(), \"*.lua\"))) do\n                local envname = path.basename(envfile)\n                print(\"  - %s\", envname)\n                count = count + 1\n            end\n            print(\"%s:\", _get_envsdir())\n            for _, envfile in ipairs(os.files(path.join(_get_envsdir(), \"*.lua\"))) do\n                local envname = path.basename(envfile)\n                print(\"  - %s\", envname)\n                count = count + 1\n            end\n            print(\"envs(%d) found!\", count)\n        end\n    elseif option.get(\"add\") then\n        local envfile = assert(option.get(\"program\"), \"please set environment config file!\")\n        if os.isfile(envfile) then\n            os.vcp(envfile, path.join(_get_envsdir(), path.filename(envfile)))\n        end\n    elseif option.get(\"remove\") then\n        local envname = assert(option.get(\"program\"), \"please set environment config name!\")\n        os.rm(path.join(_get_envsdir(), envname .. \".lua\"))\n    else\n        local program = option.get(\"program\")\n        if program and program == \"shell\" and not is_subhost(\"windows\") then\n            wprint(\"The shell was not integrated with xmake. Some features might be missing. Please switch to your default shell, and run `xmake update --integrate` to integrate the shell.\")\n        end\n        local envs = _package_getenvs()\n        if program and not option.get(\"show\") then\n            if envs and envs.PATH then\n                os.setenv(\"PATH\", envs.PATH)\n            end\n            if program == \"shell\" then\n                _run_shell(envs)\n            else\n                os.execv(program, option.get(\"arguments\"), {envs = envs})\n            end\n        else\n            print(envs)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/export.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        export.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Export the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",           \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}                            },\n        {'p', \"plat\",           \"kv\", nil, \"Set the given platform.\"                            },\n        {'a', \"arch\",           \"kv\", nil, \"Set the given architecture.\"                        },\n        {'m', \"mode\",           \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}                            },\n        {'f', \"configs\",        \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo export -f \\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo export -f \\\"regex=true,thread=true\\\" boost\" },\n        {                                                                                       },\n        {nil, \"includes\",       \"kv\", nil, \"Includes extra lua configuration files.\"            },\n        {nil, \"toolchain\",      \"kv\", nil, \"Set the toolchain name.\"                            },\n        {nil, \"toolchain_host\", \"kv\", nil, \"Set the host toolchain name.\"                       },\n        {nil, \"shallow\",        \"k\",  nil, \"Does not export dependent packages.\"                },\n        {'o', \"packagedir\",     \"kv\", \"packages\",\"Set the exported packages directory.\"         },\n        {nil, \"packages\",       \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo export zlib boost\",\n                                       \"    - xrepo export -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo export -p android -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo export -p mingw -k shared zlib\",\n                                       \"    - xrepo export conan::zlib/1.2.11 vcpkg::zlib\"      }\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo export [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"export\")\n    end\n    return options, show_options, description\nend\n\n-- export packages\nfunction _export_packages(packages)\n\n    -- is package configuration file? e.g. xrepo export xxx.lua\n    --\n    -- xxx.lua\n    --   add_requires(\"libpng\", {system = false})\n    --   add_requireconfs(\"libpng.*\", {configs = {shared = true}})\n    local packagefile\n    if type(packages) == \"string\" or #packages == 1 then\n        local filepath = table.unwrap(packages)\n        if type(filepath) == \"string\" and filepath:endswith(\".lua\") and os.isfile(filepath) then\n            packagefile = path.absolute(filepath)\n        end\n    end\n\n    -- add includes to rcfiles\n    local rcfiles = {}\n    local includes = option.get(\"includes\")\n    if includes then\n        for _, includefile in ipairs(path.splitenv(includes)) do\n            table.insert(rcfiles, path.absolute(includefile))\n        end\n    end\n\n    -- enter working project directory\n    local oldir = os.curdir()\n    local subdir = \"working\"\n    if packagefile then\n        subdir = subdir .. \"-\" .. hash.uuid(packagefile):split('-')[1]\n    end\n    local workdir = path.join(os.tmpdir(), \"xrepo\", subdir)\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n    if packagefile then\n        assert(os.isfile(\"xmake.lua\"), \"xmake.lua not found!\")\n        io.writefile(\"xmake.lua\", ('includes(\"%s\")\\ntarget(\"test\", {kind = \"phony\"})'):format((packagefile:gsub(\"\\\\\", \"/\"))))\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\", \"--require=n\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    if option.get(\"toolchain\") then\n        table.insert(config_argv, \"--toolchain=\" .. option.get(\"toolchain\"))\n    end\n    if option.get(\"toolchain_host\") then\n        table.insert(config_argv, \"--toolchain_host=\" .. option.get(\"toolchain_host\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    local envs = {}\n    if #rcfiles > 0 then\n        envs.XMAKE_RCFILES = path.joinenv(rcfiles)\n    end\n    os.vrunv(os.programfile(), config_argv, {envs = envs})\n\n    -- do export\n    local require_argv = {\"require\", \"--export\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    if option.get(\"shallow\") then\n        table.insert(require_argv, \"--shallow\")\n    end\n    local packagedir = option.get(\"packagedir\")\n    if packagedir and not path.is_absolute(packagedir) then\n        packagedir = path.absolute(packagedir, oldir)\n    end\n    if packagedir then\n        table.insert(require_argv, \"--packagedir=\" .. packagedir)\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if not packagefile then\n        if extra then\n            local extra_str = string.serialize(extra, {indent = false, strip = true})\n            table.insert(require_argv, \"--extra=\" .. extra_str)\n        end\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv, {envs = envs})\nend\n\n-- export packages in current project\nfunction _export_current_packages(packages)\n\n    -- do export\n    local require_argv = {export = true}\n    if option.get(\"yes\") then\n        require_argv.yes = true\n    end\n    if option.get(\"verbose\") then\n        require_argv.verbose = true\n    end\n    if option.get(\"diagnosis\") then\n        require_argv.diagnosis = true\n    end\n    local packagedir = option.get(\"packagedir\")\n    if packagedir and not path.is_absolute(packagedir) then\n        packagedir = path.absolute(packagedir, oldir)\n    end\n    if packagedir then\n        require_argv.packagedir = packagedir\n    end\n    local extra = {system = false}\n    local mode  = option.get(\"mode\")\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    local kind = option.get(\"kind\")\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if extra then\n        local extra_str = string.serialize(extra, {indent = false, strip = true})\n        require_argv.extra = extra_str\n    end\n    task.run(\"require\", require_argv)\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _export_packages(packages)\n    elseif os.isfile(os.projectfile()) then\n        _export_current_packages()\n    else\n        raise(\"please specify the packages to be exported.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/fetch.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        fetch.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Fetch library information of the given installed packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",           \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"                                                                                     }},\n        {'p', \"plat\",           \"kv\", nil, \"Set the given platform.\"                                                                                    },\n        {'a', \"arch\",           \"kv\", nil, \"Set the given architecture.\"                                                                                },\n        {'m', \"mode\",           \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"                                                                                     }},\n        {'f', \"configs\",        \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo fetch --configs=\\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo fetch --configs=\\\"regex=true,thread=true\\\" boost\"                                                   },\n        {nil, \"system\",         \"k\", \"false\", \"Only fetch package on current system.\"                                                                   },\n        {category = \"Android NDK Configuration\"                                                                                                         },\n        {nil, \"ndk\",            \"kv\", nil, \"The NDK directory\"                                                                                          },\n        {category = \"Cross Compilation Configuration\"                                                                                                   },\n        {nil, \"sdk\",            \"kv\", nil, \"Set the SDK directory of cross toolchain.\"                                                                  },\n        {nil, \"toolchain\",      \"kv\", nil, \"Set the toolchain name.\"                                                                                    },\n        {nil, \"toolchain_host\", \"kv\", nil, \"Set the host toolchain name.\"                                                                               },\n        {category = \"Other Configuration\"                                                                                                               },\n        {nil, \"includes\",       \"kv\", nil, \"Includes extra lua configuration files.\",\n                                       \"e.g.\",\n                                       \"    - xrepo fetch -p cross --toolchain=mytool --includes='toolchain1.lua\" .. path.envsep() .. \"toolchain2.lua'\" },\n        {nil, \"deps\",           \"k\",  nil, \"Fetch packages with dependencies.\"                                                                          },\n        {nil, \"cflags\",         \"k\",  nil, \"Fetch cflags of the given packages.\"                                                                        },\n        {nil, \"ldflags\",        \"k\",  nil, \"Fetch ldflags of the given packages.\"                                                                       },\n        {'e', \"external\",       \"k\",  nil, \"Show cflags as external packages with -isystem.\"                                                            },\n        {nil, \"json\",           \"k\",  nil, \"Output package info as json format.\"                                                                        },\n        {                                                                                                                                               },\n        {nil, \"packages\",       \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo fetch zlib boost\",\n                                       \"    - xrepo fetch /tmp/zlib.lua\",\n                                       \"    - xrepo fetch -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo fetch -p android -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo fetch -p mingw -k shared zlib\",\n                                       \"    - xrepo fetch conan::zlib/1.2.11 vcpkg::zlib\",\n                                       \"    - xrepo fetch brew::zlib\",\n                                       \"    - xrepo fetch system::zlib (from pkgconfig, brew, /usr/lib ..)\",\n                                       \"    - xrepo fetch pkgconfig::zlib\"                                                                              }\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo fetch [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"fetch\")\n    end\n    return options, show_options, description\nend\n\n-- fetch packages\nfunction _fetch_packages(packages)\n\n    -- is package configuration file? e.g. xrepo install xxx.lua\n    --\n    -- xxx.lua\n    --   add_requires(\"libpng\", {system = false})\n    --   add_requireconfs(\"libpng.*\", {configs = {shared = true}})\n    local packagefile\n    if type(packages) == \"string\" or #packages == 1 then\n        local filepath = table.unwrap(packages)\n        if type(filepath) == \"string\" and filepath:endswith(\".lua\") and os.isfile(filepath) then\n            packagefile = path.absolute(filepath)\n        end\n    end\n\n    -- add includes to rcfiles\n    local rcfiles = {}\n    local includes = option.get(\"includes\")\n    if includes then\n        for _, includefile in ipairs(path.splitenv(includes)) do\n            table.insert(rcfiles, path.absolute(includefile))\n        end\n    end\n\n    -- enter working project directory\n    local subdir = \"working\"\n    if packagefile then\n        subdir = subdir .. \"-\" .. hash.uuid(packagefile):split('-')[1]\n    end\n    local workdir = path.join(os.tmpdir(), \"xrepo\", subdir)\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n    if packagefile then\n        assert(os.isfile(\"xmake.lua\"), \"xmake.lua not found!\")\n        io.writefile(\"xmake.lua\", ('includes(\"%s\")\\ntarget(\"test\", {kind = \"phony\"})'):format((packagefile:gsub(\"\\\\\", \"/\"))))\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\", \"--require=n\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    -- for android\n    if option.get(\"ndk\") then\n        table.insert(config_argv, \"--ndk=\" .. option.get(\"ndk\"))\n    end\n    -- for cross toolchain\n    if option.get(\"sdk\") then\n        table.insert(config_argv, \"--sdk=\" .. option.get(\"sdk\"))\n    end\n    if option.get(\"toolchain\") then\n        table.insert(config_argv, \"--toolchain=\" .. option.get(\"toolchain\"))\n    end\n    if option.get(\"toolchain_host\") then\n        table.insert(config_argv, \"--toolchain_host=\" .. option.get(\"toolchain_host\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    local envs = {}\n    if #rcfiles > 0 then\n        envs.XMAKE_RCFILES = path.joinenv(rcfiles)\n    end\n    os.vrunv(os.programfile(), config_argv, {envs = envs})\n\n    -- do fetch\n    local require_argv = {\"require\", \"--fetch\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    local fetchmodes = {}\n    if option.get(\"deps\") then\n        table.insert(fetchmodes, \"deps\")\n    end\n    if option.get(\"cflags\") then\n        table.insert(fetchmodes, \"cflags\")\n    end\n    if option.get(\"ldflags\") then\n        table.insert(fetchmodes, \"ldflags\")\n    end\n    if option.get(\"external\") then\n        table.insert(fetchmodes, \"external\")\n    end\n    if option.get(\"json\") then\n        table.insert(fetchmodes, \"json\")\n    end\n    if #fetchmodes > 0 then\n        table.insert(require_argv, \"--fetch_modes=\" .. table.concat(fetchmodes, ','))\n    end\n    local extra = {system = option.get(\"system\")}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if not packagefile then\n        -- avoid overriding extra configs in add_requires/xmake.lua\n        if extra then\n            local extra_str = string.serialize(extra, {indent = false, strip = true})\n            table.insert(require_argv, \"--extra=\" .. extra_str)\n        end\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv, {envs = envs})\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _fetch_packages(packages)\n    else\n        raise(\"please specify the package to be fetched.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/import.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        import.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Import the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",       \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}         },\n        {'p', \"plat\",       \"kv\", nil, \"Set the given platform.\"             },\n        {'a', \"arch\",       \"kv\", nil, \"Set the given architecture.\"         },\n        {'m', \"mode\",       \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}         },\n        {'f', \"configs\",    \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo import -f \\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo import -f \\\"regex=true,thread=true\\\" boost\"},\n        {},\n        {'i', \"packagedir\",  \"kv\", \"packages\",\"Set the imported packages directory.\"},\n        {nil, \"packages\",   \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo import zlib boost\",\n                                       \"    - xrepo import -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo import -p android -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo import -p mingw -k shared zlib\",\n                                       \"    - xrepo import conan::zlib/1.2.11 vcpkg::zlib\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo import [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"import\")\n    end\n    return options, show_options, description\nend\n\n-- import packages\nfunction _import_packages(packages)\n\n    -- enter working project directory\n    local oldir = os.curdir()\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    os.vrunv(os.programfile(), config_argv)\n\n    -- do import\n    local require_argv = {\"require\", \"--import\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    local packagedir = option.get(\"packagedir\")\n    if packagedir and not path.is_absolute(packagedir) then\n        packagedir = path.absolute(packagedir, oldir)\n    end\n    if packagedir then\n        table.insert(require_argv, \"--packagedir=\" .. packagedir)\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if extra then\n        local extra_str = string.serialize(extra, {indent = false, strip = true})\n        table.insert(require_argv, \"--extra=\" .. extra_str)\n    end\n    table.join2(require_argv, packages)\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- import packages in current project\nfunction _import_current_packages(packages)\n\n    -- do import\n    local require_argv = {import = true}\n    if option.get(\"yes\") then\n        require_argv.yes = true\n    end\n    if option.get(\"verbose\") then\n        require_argv.verbose = true\n    end\n    if option.get(\"diagnosis\") then\n        require_argv.diagnosis = true\n    end\n    local packagedir = option.get(\"packagedir\")\n    if packagedir and not path.is_absolute(packagedir) then\n        packagedir = path.absolute(packagedir, oldir)\n    end\n    if packagedir then\n        require_argv.packagedir = packagedir\n    end\n    local extra = {system = false}\n    local mode = option.get(\"mode\")\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    local kind = option.get(\"kind\")\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if extra then\n        local extra_str = string.serialize(extra, {indent = false, strip = true})\n        require_argv.extra = extra_str\n    end\n    task.run(\"require\", require_argv)\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _import_packages(packages)\n    elseif os.isfile(os.projectfile()) then\n        _import_current_packages()\n    else\n        raise(\"please specify the packages to be imported.\")\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/info.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        info.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Show information of the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",       \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}         },\n        {'p', \"plat\",       \"kv\", nil, \"Set the given platform.\"             },\n        {'a', \"arch\",       \"kv\", nil, \"Set the given architecture.\"         },\n        {'m', \"mode\",       \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}         },\n        {'f', \"configs\",    \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo fetch --configs=\\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo fetch --configs=\\\"regex=true,thread=true\\\" boost\"},\n        {},\n        {nil, \"packages\",   \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo info zlib boost\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo info [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"info\")\n    end\n    return options, show_options, description\nend\n\n-- info packages\nfunction _info_packages(packages)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    os.vrunv(os.programfile(), config_argv)\n\n    -- show info\n    local require_argv = {\"require\", \"--info\"}\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if extra then\n        local extra_str = string.serialize(extra, {indent = false, strip = true})\n        table.insert(require_argv, \"--extra=\" .. extra_str)\n    end\n    table.join2(require_argv, packages)\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _info_packages(packages)\n    else\n        raise(\"please specify the packages to be viewed.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Install the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",          \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}         },\n        {'p', \"plat\",          \"kv\", nil, \"Set the given platform.\"          },\n        {'a', \"arch\",          \"kv\", nil, \"Set the given architecture.\"      },\n        {'m', \"mode\",          \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}         },\n        {'f', \"configs\",       \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo install -f \\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo install -f \\\"regex=true,thread=true\\\" boost\"},\n        {'j', \"jobs\",          \"kv\", tostring(os.default_njob()),\n                                          \"Set the number of parallel compilation jobs.\"},\n        {nil, \"linkjobs\",      \"kv\", nil, \"Set the number of parallel link jobs.\"},\n        {nil, \"includes\",      \"kv\", nil, \"Includes extra lua configuration files.\",\n                                       \"e.g.\",\n                                       \"    - xrepo install -p cross --toolchain=mytool --includes='toolchain1.lua\" .. path.envsep() .. \"toolchain2.lua'\"},\n        {nil, \"policies\",      \"kv\", nil, \"Set the policies.\"                },\n        {category = \"Visual Studio SDK Configuration\"                        },\n        {nil, \"vs\",            \"kv\", nil, \"The Microsoft Visual Studio\"\n                                        , \"  e.g. --vs=2017\"                 },\n        {nil, \"vs_toolset\",    \"kv\", nil, \"The Microsoft Visual Studio Toolset Version\"\n                                        , \"  e.g. --vs_toolset=14.0\"         },\n        {nil, \"vs_sdkver\",     \"kv\", nil, \"The Windows SDK Version of Visual Studio\"\n                                        , \"  e.g. --vs_sdkver=10.0.15063.0\"  },\n        {category = \"Android NDK Configuration\"                              },\n        {nil, \"ndk\",           \"kv\", nil, \"The NDK directory\"                },\n        {nil, \"ndk_sdkver\",    \"kv\", nil, \"The SDK Version for NDK (default: auto)\" },\n        {nil, \"android_sdk\",   \"kv\", nil, \"The Android SDK Directory\"        },\n        {nil, \"build_toolver\", \"kv\", nil, \"The Build Tool Version of Android SDK\" },\n        {nil, \"ndk_stdcxx\",    \"kv\", nil, \"Use stdc++ library for NDK\"        },\n        {nil, \"ndk_cxxstl\",    \"kv\", nil, \"The stdc++ stl library for NDK\",\n                                          \"    - c++_static\",\n                                          \"    - c++_shared\",\n                                          \"    - gnustl_static\",\n                                          \"    - gnustl_shared\",\n                                          \"    - stlport_shared\",\n                                          \"    - stlport_static\"             },\n        {category = \"Cross Compilation Configuration\"                        },\n        {nil, \"sdk\",           \"kv\", nil, \"Set the SDK directory of cross toolchain.\" },\n        {nil, \"toolchain\",     \"kv\", nil, \"Set the toolchain name.\"          },\n        {nil, \"toolchain_host\",\"kv\", nil, \"Set the host toolchain name.\"     },\n        {category = \"MingW Configuration\"                                    },\n        {nil, \"mingw\",         \"kv\", nil, \"Set the MingW SDK directory.\"     },\n        {category = \"XCode SDK Configuration\"                                },\n        {nil, \"xcode\",         \"kv\", nil, \"The Xcode Application Directory\"  },\n        {nil, \"xcode_sdkver\",  \"kv\", nil, \"The SDK Version for Xcode\"        },\n        {nil, \"target_minver\", \"kv\", nil, \"The Target Minimal Version\"       },\n        {nil, \"appledev\",      \"kv\", nil, \"The Apple Device Type\", values = {\"simulator\", \"iphone\", \"watchtv\", \"appletv\", \"catalyst\"}},\n        {category = \"Debug Configuration\"                                    },\n        {'d', \"debugdir\",      \"kv\", nil, \"The source directory of the current package for debugging. It will enable --force/--shallow by default.\"},\n        {category = \"Other Configuration\"                                    },\n        {nil, \"force\",         \"k\",  nil, \"Force to reinstall all package dependencies.\"},\n        {nil, \"shallow\",       \"k\",  nil, \"Does not install dependent packages.\"},\n        {nil, \"build\",         \"k\",  nil, \"Always build and install packages from source.\"},\n        {},\n        {nil, \"packages\",      \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo install zlib boost\",\n                                       \"    - xrepo install /tmp/zlib.lua\",\n                                       \"    - xrepo install -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo install -p android [--ndk=/xxx] -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo install -p mingw [--mingw=/xxx] -k shared zlib\",\n                                       \"    - xrepo install conan::zlib/1.2.11 vcpkg::zlib\",\n                                        values = function (complete, opt) return import(\"private.xrepo.quick_search.completion\")(complete, opt) end}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo install [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"install\")\n    end\n    return options, show_options, description\nend\n\n-- install packages\nfunction _install_packages(packages)\n\n    -- is package configuration file? e.g. xrepo install xxx.lua\n    --\n    -- xxx.lua\n    --   add_requires(\"libpng\", {system = false})\n    --   add_requireconfs(\"libpng.*\", {configs = {shared = true}})\n    local packagefile\n    if type(packages) == \"string\" or #packages == 1 then\n        local filepath = table.unwrap(packages)\n        if type(filepath) == \"string\" and filepath:endswith(\".lua\") and os.isfile(filepath) then\n            packagefile = path.absolute(filepath)\n        end\n    end\n\n    -- add includes to rcfiles\n    local rcfiles = {}\n    local includes = option.get(\"includes\")\n    if includes then\n        for _, includefile in ipairs(path.splitenv(includes)) do\n            table.insert(rcfiles, path.absolute(includefile))\n        end\n    end\n\n    -- enter working project directory\n    local subdir = \"working\"\n    if packagefile then\n        subdir = subdir .. \"-\" .. hash.uuid(packagefile):split('-')[1]\n    end\n    local origindir = os.curdir()\n    local workdir = path.join(os.tmpdir(), \"xrepo\", subdir)\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n    if packagefile then\n        assert(os.isfile(\"xmake.lua\"), \"xmake.lua not found!\")\n        io.writefile(\"xmake.lua\", ('includes(\"%s\")\\ntarget(\"test\", {kind = \"phony\"})'):format((packagefile:gsub(\"\\\\\", \"/\"))))\n    end\n\n    -- disable xmake-stats\n    os.setenv(\"XMAKE_STATS\", \"false\")\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\", \"--require=n\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    local policies = option.get(\"policies\")\n    if policies then\n        table.insert(config_argv, \"--policies=\" .. policies)\n    end\n    -- for android\n    if option.get(\"ndk\") then\n        table.insert(config_argv, \"--ndk=\" .. option.get(\"ndk\"))\n    end\n    if option.get(\"ndk_sdkver\") then\n        table.insert(config_argv, \"--ndk_sdkver=\" .. option.get(\"ndk_sdkver\"))\n    end\n    if option.get(\"android_sdk\") then\n        table.insert(config_argv, \"--android_sdk=\" .. option.get(\"android_sdk\"))\n    end\n    if option.get(\"build_toolver\") then\n        table.insert(config_argv, \"--build_toolver=\" .. option.get(\"build_toolver\"))\n    end\n    if option.get(\"ndk_stdcxx\") then\n        table.insert(config_argv, \"--ndk_stdcxx=\" .. option.get(\"ndk_stdcxx\"))\n    end\n    if option.get(\"ndk_cxxstl\") then\n        table.insert(config_argv, \"--ndk_cxxstl=\" .. option.get(\"ndk_cxxstl\"))\n    end\n    -- for cross toolchain\n    if option.get(\"sdk\") then\n        table.insert(config_argv, \"--sdk=\" .. option.get(\"sdk\"))\n    end\n    if option.get(\"toolchain\") then\n        table.insert(config_argv, \"--toolchain=\" .. option.get(\"toolchain\"))\n    end\n    if option.get(\"toolchain_host\") then\n        table.insert(config_argv, \"--toolchain_host=\" .. option.get(\"toolchain_host\"))\n    end\n    -- for mingw\n    if option.get(\"mingw\") then\n        table.insert(config_argv, \"--mingw=\" .. option.get(\"mingw\"))\n    end\n    -- for vs\n    if option.get(\"vs\") then\n        table.insert(config_argv, \"--vs=\" .. option.get(\"vs\"))\n    end\n    if option.get(\"vs_toolset\") then\n        table.insert(config_argv, \"--vs_toolset=\" .. option.get(\"vs_toolset\"))\n    end\n    if option.get(\"vs_sdkver\") then\n        table.insert(config_argv, \"--vs_sdkver=\" .. option.get(\"vs_sdkver\"))\n    end\n    -- for xcode\n    if option.get(\"xcode\") then\n        table.insert(config_argv, \"--xcode=\" .. option.get(\"xcode\"))\n    end\n    if option.get(\"xcode_sdkver\") then\n        table.insert(config_argv, \"--xcode_sdkver=\" .. option.get(\"xcode_sdkver\"))\n    end\n    if option.get(\"target_minver\") then\n        table.insert(config_argv, \"--target_minver=\" .. option.get(\"target_minver\"))\n    end\n    if option.get(\"appledev\") then\n        table.insert(config_argv, \"--appledev=\" .. option.get(\"appledev\"))\n    end\n    local envs = {}\n    if #rcfiles > 0 then\n        envs.XMAKE_RCFILES = path.joinenv(rcfiles)\n    end\n    os.vrunv(os.programfile(), config_argv, {envs = envs})\n\n    -- do install\n    local require_argv = {\"require\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    if option.get(\"jobs\") then\n        table.insert(require_argv, \"-j\")\n        table.insert(require_argv, option.get(\"jobs\"))\n    end\n    if option.get(\"linkjobs\") then\n        table.insert(require_argv, \"--linkjobs=\" .. option.get(\"linkjobs\"))\n    end\n    local is_debug = false\n    local sourcedir = option.get(\"debugdir\")\n    if sourcedir then\n        is_debug = true\n        table.insert(require_argv, \"--debugdir=\" .. path.absolute(sourcedir, origindir))\n    end\n    if option.get(\"force\") or is_debug then\n        table.insert(require_argv, \"--force\")\n    end\n    if option.get(\"shallow\") or is_debug then\n        table.insert(require_argv, \"--shallow\")\n    end\n    if option.get(\"build\") or is_debug then\n        table.insert(require_argv, \"--build\")\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.system  = false\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if not packagefile then\n        -- avoid overriding extra configs in add_requires/xmake.lua\n        if extra then\n            local extra_str = string.serialize(extra, {indent = false, strip = true})\n            table.insert(require_argv, \"--extra=\" .. extra_str)\n        end\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv, {envs = envs})\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _install_packages(packages)\n    else\n        raise(\"please specify the packages to be installed.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/list-repo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        list-repo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"List all remote repositories.\"\n\n    -- menu options\n    local options = {}\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo list-repo [options]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"list-repo\")\n    end\n    return options, show_options, description\nend\n\n-- list repository\nfunction list_repository()\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- list it\n    local repo_argv = {\"repo\", \"--list\", \"--global\"}\n    if option.get(\"verbose\") then\n        table.insert(repo_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(repo_argv, \"-D\")\n    end\n    os.vexecv(os.programfile(), repo_argv)\nend\n\n-- main entry\nfunction main()\n    list_repository()\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/remove.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        remove.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.remove_packages\", {alias = \"remove_all_packages\"})\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Remove the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {'k', \"kind\",            \"kv\", nil, \"Enable static/shared library.\",\n                                       values = {\"static\", \"shared\"}                            },\n        {'p', \"plat\",            \"kv\", nil, \"Set the given platform.\"                           },\n        {'a', \"arch\",            \"kv\", nil, \"Set the given architecture.\"                       },\n        {'m', \"mode\",            \"kv\", nil, \"Set the given mode.\",\n                                       values = {\"release\", \"debug\"}                            },\n        {'f', \"configs\",         \"kv\", nil, \"Set the given extra package configs.\",\n                                       \"e.g.\",\n                                       \"    - xrepo remove -f \\\"runtimes='MD'\\\" zlib\",\n                                       \"    - xrepo remove -f \\\"regex=true,thread=true\\\" boost\" },\n        {nil, \"toolchain\",       \"kv\", nil, \"Set the toolchain name.\"                           },\n        {nil, \"toolchain_host\",  \"kv\", nil, \"Set the host toolchain name.\"                      },\n        {                                                                                       },\n        {nil, \"all\",             \"k\", nil,  \"Remove all packages and ignore extra package configs.\",\n                                       \"If `--all` is enabled, the package name parameter will support lua pattern\",\n                                       \"e.g.\",\n                                       \"    - xrepo remove --all\",\n                                       \"    - xrepo remove --all zlib boost\",\n                                       \"    - xrepo remove --all zl* boo*\"                      },\n        {nil, \"packages\",        \"vs\", nil, \"The packages list.\",\n                                       \"e.g.\",\n                                       \"    - xrepo remove zlib boost\",\n                                       \"    - xrepo remove -p iphoneos -a arm64 \\\"zlib >=1.2.0\\\"\",\n                                       \"    - xrepo remove -p android -m debug \\\"pcre2 10.x\\\"\",\n                                       \"    - xrepo remove -p mingw -k shared zlib\",\n                                       \"    - xrepo remove conan::zlib/1.2.11 vcpkg::zlib\"      }\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo remove [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"remove\")\n    end\n    return options, show_options, description\nend\n\n-- remove packages\nfunction _remove_packages(packages)\n\n    -- is package configuration file? e.g. xrepo install xxx.lua\n    --\n    -- xxx.lua\n    --   add_requires(\"libpng\", {system = false})\n    --   add_requireconfs(\"libpng.*\", {configs = {shared = true}})\n    local packagefile\n    if type(packages) == \"string\" or #packages == 1 then\n        local filepath = table.unwrap(packages)\n        if type(filepath) == \"string\" and filepath:endswith(\".lua\") and os.isfile(filepath) then\n            packagefile = path.absolute(filepath)\n        end\n    end\n\n    -- add includes to rcfiles\n    local rcfiles = {}\n    local includes = option.get(\"includes\")\n    if includes then\n        for _, includefile in ipairs(path.splitenv(includes)) do\n            table.insert(rcfiles, path.absolute(includefile))\n        end\n    end\n\n    -- enter working project directory\n    local subdir = \"working\"\n    if packagefile then\n        subdir = subdir .. \"-\" .. hash.uuid(packagefile):split('-')[1]\n    end\n    local workdir = path.join(os.tmpdir(), \"xrepo\", subdir)\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n    if packagefile then\n        assert(os.isfile(\"xmake.lua\"), \"xmake.lua not found!\")\n        io.writefile(\"xmake.lua\", ('includes(\"%s\")\\ntarget(\"test\", {kind = \"phony\"})'):format((packagefile:gsub(\"\\\\\", \"/\"))))\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\", \"--require=n\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    if option.get(\"plat\") then\n        table.insert(config_argv, \"-p\")\n        table.insert(config_argv, option.get(\"plat\"))\n    end\n    if option.get(\"arch\") then\n        table.insert(config_argv, \"-a\")\n        table.insert(config_argv, option.get(\"arch\"))\n    end\n    local mode  = option.get(\"mode\")\n    if mode then\n        table.insert(config_argv, \"-m\")\n        table.insert(config_argv, mode)\n    end\n    local kind  = option.get(\"kind\")\n    if kind then\n        table.insert(config_argv, \"-k\")\n        table.insert(config_argv, kind)\n    end\n    if option.get(\"toolchain\") then\n        table.insert(config_argv, \"--toolchain=\" .. option.get(\"toolchain\"))\n    end\n    if option.get(\"toolchain_host\") then\n        table.insert(config_argv, \"--toolchain_host=\" .. option.get(\"toolchain_host\"))\n    end\n    local envs = {}\n    if #rcfiles > 0 then\n        envs.XMAKE_RCFILES = path.joinenv(rcfiles)\n    end\n    os.vrunv(os.programfile(), config_argv, {envs = envs})\n\n    -- do remove\n    local require_argv = {\"require\", \"--uninstall\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    local extra = {system = false}\n    if mode == \"debug\" then\n        extra.debug = true\n    end\n    if kind then\n        extra.configs = extra.configs or {}\n        extra.configs.shared = kind == \"shared\"\n    end\n    local configs = option.get(\"configs\")\n    if configs then\n        extra.configs = extra.configs or {}\n        local extra_configs, errors = (\"{\" .. configs .. \"}\"):deserialize()\n        if extra_configs then\n            table.join2(extra.configs, extra_configs)\n        else\n            raise(errors)\n        end\n    end\n    if not packagefile then\n        -- avoid overriding extra configs in add_requires/xmake.lua\n        if extra then\n            local extra_str = string.serialize(extra, {indent = false, strip = true})\n            table.insert(require_argv, \"--extra=\" .. extra_str)\n        end\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if option.get(\"all\") then\n        remove_all_packages(packages)\n    elseif packages then\n        _remove_packages(packages)\n    else\n        raise(\"please specify the packages to be removed.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/rm-repo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rm-repo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Remove the given remote repository.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"all\",  \"k\", nil, \"Remove all added repositories.\"},\n        {nil, \"name\", \"v\", nil, \"The repository name.\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo rm-repo [options] [name]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"rm-repo\")\n    end\n    return options, show_options, description\nend\n\n-- remove repository\nfunction remove_repository(name)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- remove it\n    local repo_argv = {\"repo\", \"--remove\", \"--global\"}\n    if option.get(\"verbose\") then\n        table.insert(repo_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(repo_argv, \"-D\")\n    end\n    table.insert(repo_argv, name)\n    os.vexecv(os.programfile(), repo_argv)\nend\n\n-- clear repository\nfunction clear_repository()\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- clear all\n    local repo_argv = {\"repo\", \"--clear\", \"--global\"}\n    if option.get(\"verbose\") then\n        table.insert(repo_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(repo_argv, \"-D\")\n    end\n    os.vexecv(os.programfile(), repo_argv)\nend\n\n-- main entry\nfunction main()\n    local name = option.get(\"name\")\n    if name then\n        remove_repository(name)\n    elseif option.get(\"all\") then\n        clear_repository()\n    else\n        raise(\"please specify the repository name to be removed.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/scan.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        scan.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Scan the given or all installed packages.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"packages\",   \"vs\", nil, \"The packages list (support lua pattern).\",\n                                       \"e.g.\",\n                                       \"    - xrepo scan\",\n                                       \"    - xrepo scan zlib\",\n                                       \"    - xrepo scan zlib bo*\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo scan [options] [packages]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"scan\")\n    end\n    return options, show_options, description\nend\n\n-- scan packages\nfunction _scan_packages(packages)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    os.vrunv(os.programfile(), config_argv)\n\n    -- do scan\n    local require_argv = {\"require\", \"--scan\"}\n    if option.get(\"yes\") then\n        table.insert(require_argv, \"-y\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    if packages then\n        table.join2(require_argv, packages)\n    end\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- main entry\nfunction main()\n    _scan_packages(option.get(\"packages\"))\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/search.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        search.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Search the given packages.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"packages\",   \"vs\", nil, \"The packages list (support lua pattern).\",\n                                       \"e.g.\",\n                                       \"    - xrepo search zlib boost\",\n                                       \"    - xrepo search \\\"pcre*\\\"\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo search [options] packages\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"search\")\n    end\n    return options, show_options, description\nend\n\n-- search packages\nfunction _search_packages(packages)\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- do configure first\n    local config_argv = {\"f\", \"-c\"}\n    if option.get(\"diagnosis\") then\n        table.insert(config_argv, \"-vD\")\n    end\n    os.vrunv(os.programfile(), config_argv)\n\n    -- do search\n    local require_argv = {\"require\", \"--search\"}\n    if option.get(\"verbose\") then\n        table.insert(require_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(require_argv, \"-D\")\n    end\n    table.join2(require_argv, packages)\n    os.vexecv(os.programfile(), require_argv)\nend\n\n-- main entry\nfunction main()\n    local packages = option.get(\"packages\")\n    if packages then\n        _search_packages(packages)\n    else\n        raise(\"please specify the package to be searched.\")\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/action/update-repo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        update-repo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get menu options\nfunction menu_options()\n\n    -- description\n    local description = \"Update the local repositories from remote.\"\n\n    -- menu options\n    local options =\n    {\n        {nil, \"name\", \"v\", nil, \"The repository name.\"}\n    }\n\n    -- show menu options\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo update-repo [options]\")\n\n        -- show description\n        print(\"\")\n        print(description)\n\n        -- show options\n        option.show_options(options, \"update-repo\")\n    end\n    return options, show_options, description\nend\n\n-- update repository\nfunction update_repository()\n\n    -- enter working project directory\n    local workdir = path.join(os.tmpdir(), \"xrepo\", \"working\")\n    if not os.isdir(workdir) then\n        os.mkdir(workdir)\n        os.cd(workdir)\n        os.vrunv(os.programfile(), {\"create\", \"-P\", \".\"})\n    else\n        os.cd(workdir)\n    end\n\n    -- update it\n    local repo_argv = {\"repo\", \"--update\"}\n    if option.get(\"verbose\") then\n        table.insert(repo_argv, \"-v\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(repo_argv, \"-D\")\n    end\n    local name = option.get(\"name\")\n    if name then\n        table.insert(repo_argv, name)\n    end\n    os.vexecv(os.programfile(), repo_argv)\nend\n\nfunction main()\n    update_repository()\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/complete.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      glcraft\n-- @file        complete.lua\n--\n\nimport(\"private.utils.completer\")\n\nfunction main(pos, config, ...)\n\n    local comp = completer.new(pos, config, {...})\n\n    local word = table.concat(comp:words(), \" \") or \"\"\n    position = tonumber(pos) or 0\n\n    local has_space = word:endswith(\" \") or position > #word\n    word = word:trim()\n\n    local argv = os.argv(word)\n\n    if argv[1] then\n\n        -- normailize word to remove \"xrepo\"\n        if is_host(\"windows\") and argv[1]:lower() == \"xrepo.exe\" then\n            argv[1] = \"xrepo\"\n        end\n        if argv[1] == \"xrepo\" then\n            table.remove(argv, 1)\n        end\n    end\n\n    local items = {}\n    for _, scriptfile in ipairs(os.files(path.join(os.scriptdir(), \"action\", \"*.lua\"))) do\n        local action_name = path.basename(scriptfile)\n        local action = import(\"private.xrepo.action.\" .. action_name, {anonymous = true})\n        local options, _, description = action.menu_options()\n        items[action_name] = {\n            description = description,\n            options = options,\n        }\n    end\n\n    if has_space then\n        comp:complete(items, argv, \"\")\n    else\n        local completing = table.remove(argv)\n        comp:complete(items, argv, completing or \"\")\n    end\nend"
  },
  {
    "path": "xmake/modules/private/xrepo/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.text\")\nimport(\"core.base.option\")\n\n-- show version\nfunction _show_version()\n\n    -- show title\n    cprint(\"${bright}xRepo %s/xmake, A cross-platform C/C++ package manager based on Xmake.\", xmake.version())\n\n    -- show copyright\n    cprint(\"Copyright (C) 2015-present Ruki Wang, ${underline}https://xmake.io${clear}\")\n    print(\"\")\n\n    -- show logo\n    local logo = [[\n    __  ___ ___  ______ ____  _____\n    \\ \\/ / |  _ \\| ____|  _ \\/  _  |\n     >  <  | |_) |  _| | |_) | |_| |\n    /_/\\_\\_| \\___|_____|_|   |____/\n\n                         by ruki, xmake.io\n    ]]\n    option.show_logo(logo, {seed = 680})\nend\n\n-- get main menu options\nfunction _menu_options()\n\n    -- main menu options\n    local options = {}\n\n    -- show menu in narrow mode?\n    local function menu_isnarrow()\n        local width = os.getwinsize().width\n        return width > 0 and width < 60\n    end\n\n    -- show all actions\n    local function show_actions()\n        print(\"\")\n        cprint(\"${bright}Actions:\")\n\n        -- get action names\n        local repo_actions = {}\n        local package_actions = {}\n        for _, scriptfile in ipairs(os.files(path.join(os.scriptdir(), \"action\", \"*.lua\"))) do\n            local action_name = path.basename(scriptfile)\n            if action_name:endswith(\"-repo\") then\n                table.insert(repo_actions, action_name)\n            else\n                table.insert(package_actions, action_name)\n            end\n        end\n        table.sort(repo_actions)\n        table.sort(package_actions)\n\n        -- make action content\n        local tablecontent = {}\n        local narrow = menu_isnarrow()\n        for _, action_name in ipairs(table.join(package_actions, repo_actions)) do\n            local action = import(\"private.xrepo.action.\" .. action_name, {anonymous = true})\n            local _, _, description = action.menu_options()\n            local taskline = string.format(narrow and \"  %s\" or \"    %s\", action_name)\n            table.insert(tablecontent, {taskline, description})\n        end\n\n        -- set table styles\n        tablecontent.style = {\"${color.menu.main.task.name}\"}\n        tablecontent.width = {nil, \"auto\"}\n        tablecontent.sep = narrow and \"  \" or \"    \"\n\n        -- print table\n        io.write(text.table(tablecontent))\n    end\n\n    -- show options of main program\n    local function show_options()\n\n        -- show usage\n        cprint(\"${bright}Usage: $${clear cyan}xrepo [action] [options]\")\n\n        -- show actions\n        show_actions()\n\n        -- show options\n        option.show_options(options, \"main\")\n    end\n    return options, show_options\nend\n\n-- parse options\nfunction _parse_options(...)\n\n    -- get action and arguments\n    local argv = table.pack(...)\n    local action_name = nil\n    if #argv > 0 and not argv[1]:startswith('-') then\n        action_name = argv[1]\n        argv = table.slice(argv, 2)\n    end\n\n    -- get menu\n    local action, options, show_options\n    if action_name then\n        action = assert(import(\"private.xrepo.action.\" .. action_name, {anonymous = true, try = true}), \"xrepo: action %s not found!\", action_name)\n        options, show_options = action.menu_options()\n    else\n        options, show_options = _menu_options()\n    end\n\n    -- insert common options\n    local common_options =\n    {\n        {'q', \"quiet\",     \"k\", nil, \"Quiet operation.\"                            },\n        {'y', \"yes\",       \"k\", nil, \"Input yes by default if need user confirm.\"  },\n        {nil, \"root\",      \"k\", nil, \"Allow to run xrepo as root.\"                 },\n        {},\n        {'v', \"verbose\",   \"k\", nil, \"Print lots of verbose information for users.\"},\n        {'D', \"diagnosis\", \"k\", nil, \"Print lots of diagnosis information.\"        },\n        {nil, \"version\",   \"k\", nil, \"Print the version number and exit.\"          },\n        {'h', \"help\",      \"k\", nil, \"Print this help message and exit.\"           },\n        {category = action and \"action\" or nil},\n    }\n    for _, opt in irpairs(common_options) do\n        table.insert(options, 1, opt)\n    end\n\n    -- parse argument options\n    local menu = {}\n    local results, errors = option.raw_parse(argv, options)\n    if results then\n        menu.options = results\n    end\n    menu.action      = action\n    menu.action_name = action_name\n    menu.show_help   = function ()\n        _show_version()\n        show_options()\n    end\n    return menu, errors\nend\n\n-- main entry\nfunction main(...)\n\n    -- parse argument options\n    local menu, errors = _parse_options(...)\n    if errors then\n        menu.show_help()\n        raise(errors)\n    end\n\n    -- show help?\n    local options = menu.options\n    if not options or options.help then\n        return menu.show_help()\n    end\n\n    -- show version?\n    if options.version then\n        return _show_version()\n    end\n\n    -- init option\n    option.save()\n    for k, v in pairs(options) do\n        option.set(k, v)\n    end\n\n    -- tell xmake that xrepo is currently being used\n    os.setenv(\"XREPO_WORKING\", \"y\")\n\n    -- do action\n    if menu.action then\n        menu.action()\n    else\n        menu.show_help()\n    end\nend\n"
  },
  {
    "path": "xmake/modules/private/xrepo/quick_search/cache.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      glcraft\n-- @file        cache.lua\n--\n\nimport(\"core.base.json\")\nimport(\"core.cache.globalcache\")\nimport(\"core.package.package\", {alias = \"core_package\"})\nimport(\"private.action.require.impl.repository\")\n\nlocal cache = globalcache.cache(\"quick_search\")\n\n-- search package directories from repositories\nfunction _list_package_dirs()\n    -- find the package directories from all repositories\n    local unique = {}\n    local packageinfos = {}\n    for _, repo in ipairs(repository.repositories()) do\n        for _, file in ipairs(os.files(path.join(repo:directory(), \"packages\", \"*\", \"*\", \"xmake.lua\"))) do\n            local dir = path.directory(file)\n            local subdirname = path.basename(path.directory(dir))\n            if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua\n                local packagename = path.filename(dir)\n                if not unique[packagename] then\n                    table.insert(packageinfos, {name = packagename, repo = repo, packagedir = dir})\n                    unique[packagename] = true\n                end\n            end\n        end\n    end\n    return packageinfos\nend\n\n-- check cache content exists\nfunction _init()\n    if table.empty(cache:data()) then\n        update()\n    end\nend\n\n-- update the cache file\nfunction update()\n    for _, packageinfo in ipairs(_list_package_dirs()) do\n        local package = core_package.load_from_repository(packageinfo.name, packageinfo.packagedir, {repo = packageinfo.repo})\n        cache:set(packageinfo.name, {\n            reponame = package:repo() and package:repo():name(),\n            description = package:description(),\n            versions = package:versions(),\n        })\n    end\n    cache:save()\nend\n\n-- remove the cache file\nfunction clear()\n    cache:clear()\n    cache:save()\nend\n\n-- get the cache data\nfunction get()\n    _init()\n    return cache:data()\nend\n\n-- find package\nfunction find(name, opt)\n    _init()\n    opt = opt or {}\n    local list_result = {}\n    for packagename, packagedata in pairs(cache:data()) do\n        local found = false\n        if opt.prefix then\n            found = packagename:startswith(name)\n        else\n            found = packagename:find(path.pattern(name))\n        end\n        if not found and opt.description and packagedata.description and packagedata.description:find(name) then\n            found = true\n        end\n        if found then\n            table.insert(list_result, {name = packagename, data = packagedata})\n        end\n    end\n    return list_result\nend\n\n"
  },
  {
    "path": "xmake/modules/private/xrepo/quick_search/completion.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      glcraft\n-- @file        complete.lua\n--\n\nimport(\"private.xrepo.quick_search.cache\")\n\n-- complete xrepo packages\nfunction _xmake_package_complete(complete, opt)\n    local candidates = {}\n    local found = cache.find(complete, {prefix = true})\n    for _, candidate in ipairs(found) do\n        table.insert(candidates, {value = candidate.name, description = candidate.data.description})\n    end\n    return candidates\nend\n\nfunction main(complete, opt)\n    local prefix = \"\"\n\n    -- if help menu, do nothing\n    if opt.helpmenu then\n        return {}\n    end\n\n    -- check prefix if present\n    if complete:find(\"::\", 1, true) then\n        prefix = complete:sub(1, complete:find(\"::\", 1, true) - 1)\n        complete = complete:sub(complete:find(\"::\", 1, true) + 2)\n    end\n\n    local packages\n\n    -- complete xmake packages\n    if prefix == \"\" or prefix == \"xmake\" then\n        packages = _xmake_package_complete(complete, opt)\n    end\n\n    -- to prevent shell completion misunderstandings,\n    -- we put back the prefix\n    if packages and prefix ~= \"\" then\n        for _, package in ipairs(packages) do\n            package.value = prefix .. \"::\" .. package.value\n        end\n    end\n    return packages or {}\nend\n"
  },
  {
    "path": "xmake/modules/privilege/sudo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sudo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"detect.tools.find_sudo\")\n\n-- some inherited environment variables\nfunction _envars(escape)\n    local names  = {\"PATH\", \"XMAKE_STATS\", \"COLORTERM\"}\n    local envars = {\"env\"}\n    for _, name in ipairs(names) do\n        local value = os.getenv(name)\n        if escape and value then\n            value = \"\\\"\" .. (value:gsub(\"\\\"\", \"\\\\\\\"\")) .. \"\\\"\"\n        end\n        table.insert(envars, name .. \"=\" .. (value or \"\"))\n    end\n    return envars\nend\n\n-- sudo run command with administrator permission\n--\n-- e.g.\n-- _sudo(os.run, \"echo\", \"hello xmake!\")\n--\nfunction _sudo(runner, cmd, ...)\n\n    -- find sudo\n    local sudo = find_sudo()\n    assert(sudo, \"sudo not found!\")\n\n    -- run it with administrator permission and preserve parent environment\n    runner(sudo .. \" \" .. table.concat(_envars(true), \" \") .. \" \" .. cmd, ...)\nend\n\n-- sudo run command with administrator permission and arguments list\n--\n-- e.g.\n-- _sudov(os.runv, {\"echo\", \"hello xmake!\"})\n--\nfunction _sudov(runner, program, argv, opt)\n\n    -- find sudo\n    local sudo = find_sudo()\n    assert(sudo, \"sudo not found!\")\n\n    -- run it with administrator permission and preserve parent environment\n    runner(sudo, table.join(_envars(), program, argv), opt)\nend\n\n-- sudo run lua script with administrator permission and arguments list\n--\n-- e.g.\n-- _lua(os.runv, \"xxx.lua\", {\"arg1\", \"arg2\"})\n--\nfunction _lua(runner, luafile, luaargv)\n\n    -- init argv\n    local argv = {\"lua\", \"--root\"}\n    for _, name in ipairs({\"file\", \"project\", \"diagnosis\", \"verbose\", \"quiet\", \"yes\", \"confirm\"}) do\n        local value = option.get(name)\n        if type(value) == \"string\" then\n            table.insert(argv, \"--\" .. name .. \"=\" .. value)\n        elseif value then\n            table.insert(argv, \"--\" .. name)\n        end\n    end\n\n    -- run it with administrator permission\n    _sudov(runner, os.programfile(), table.join(argv, luafile, luaargv))\nend\n\n-- has sudo?\nfunction has()\n    return find_sudo() ~= nil\nend\n\n-- sudo run command\nfunction run(cmd, ...)\n    return _sudo(os.run, cmd, ...)\nend\n\n-- sudo run command with arguments list\nfunction runv(program, argv, opt)\n    return _sudov(os.run, program, argv, opt)\nend\n\n-- sudo quietly run command and echo verbose info if [-v|--verbose] option is enabled\nfunction vrun(cmd, ...)\n    return _sudo(os.vrun, cmd, ...)\nend\n\n-- sudo quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled\nfunction vrunv(program, argv, opt)\n    return _sudov(os.vrunv, program, argv, opt)\nend\n\n-- sudo run command and return output and error data\nfunction iorun(cmd, ...)\n    return _sudo(os.iorun, cmd, ...)\nend\n\n-- sudo run command and return output and error data\nfunction iorunv(program, argv, opt)\n    return _sudov(os.iorunv, program, argv, opt)\nend\n\n-- sudo execute command\nfunction exec(cmd, ...)\n    return _sudo(os.exec, cmd, ...)\nend\n\n-- sudo execute command with arguments list\nfunction execv(program, argv, opt)\n    return _sudov(os.execv, program, argv, opt)\nend\n\n-- sudo run lua script\nfunction runl(luafile, luaargv, opt)\n    return _lua(os.runv, luafile, luaargv, opt)\nend\n\n-- sudo quietly run lua script and echo verbose info if [-v|--verbose] option is enabled\nfunction vrunl(luafile, luaargv)\n    return _lua(os.vrunv, luafile, luaargv)\nend\n\n-- sudo run lua script and return output and error data\nfunction iorunl(luafile, luaargv)\n    return _lua(os.iorunv, luafile, luaargv)\nend\n\n-- sudo execute lua script\nfunction execl(luafile, luaargv)\n    return _lua(os.execv, luafile, luaargv)\nend\n"
  },
  {
    "path": "xmake/modules/target/action/clean/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.action.clean.remove_files\")\nimport(\"private.cache.build_cache\")\n\n-- the builtin clean main entry\nfunction main(target)\n\n    -- is phony?\n    if target:is_phony() then\n        return\n    end\n\n    -- remove the target file\n    local targetfile = target:targetfile()\n    remove_files(targetfile)\n\n    -- remove import library of the target file\n    -- @see https://github.com/xmake-io/xmake/issues/3052\n    if target:is_shared() then\n        if target:is_plat(\"windows\") then\n            local implibfile = target:artifactfile(\"implib\")\n            local expfile = path.join(path.directory(implibfile), path.basename(targetfile) .. \".exp\")\n            if os.isfile(implibfile) then\n                remove_files(implibfile)\n            end\n            if os.isfile(expfile) then\n                remove_files(expfile)\n            end\n        end\n\n        if target:is_plat(\"mingw\") then\n            local implibfile = target:artifactfile(\"implib\")\n            if os.isfile(implibfile) then\n                remove_files(implibfile)\n            end\n        end\n    end\n\n    -- remove the symbol file\n    remove_files(target:symbolfile())\n\n    -- remove the c/c++ precompiled header file\n    remove_files(target:pcoutputfile(\"c\"))\n    remove_files(target:pcoutputfile(\"cxx\"))\n\n    -- remove the clean files\n    remove_files(target:get(\"cleanfiles\"))\n\n    -- remove all?\n    if option.get(\"all\") then\n\n        -- remove config files\n        local _, configfiles = target:configfiles()\n        remove_files(configfiles)\n\n        -- remove all dependent files for each platform\n        remove_files(target:dependir({root = true}))\n\n        -- remove all object files for each platform\n        remove_files(target:objectdir({root = true}))\n\n        -- remove all autogen files for each platform\n        remove_files(target:autogendir({root = true}))\n\n        -- clean build cache\n        build_cache.clean()\n    else\n\n        -- remove dependent files for the current platform\n        remove_files(target:dependir())\n\n        -- remove object files for the current platform\n        remove_files(target:objectdir())\n\n        -- remove autogen files for the current platform\n        remove_files(target:autogendir())\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/target/action/install/cmake_importfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cmake_importfiles.lua\n--\n\n-- imports\nimport(\"core.project.project\")\n\n-- get install libdir\nfunction _get_install_libdir(target, installdir, opt)\n    opt = opt or {}\n    return path.normalize(opt.libdir and path.join(installdir, opt.libdir) or target:libdir())\nend\n\n-- get the lib file of the target\nfunction _get_libfilename(target, libdir)\n    local libfile = path.filename(target:targetfile())\n    if target:is_plat(\"windows\") then\n        libfile = libfile:gsub(\"%.dll$\", \".lib\")\n    elseif target:is_plat(\"mingw\") then\n        if os.isfile(path.join(libdir, libfile:gsub(\"%.dll$\", \".dll.a\"))) then\n            libfile = libfile:gsub(\"%.dll$\", \".dll.a\")\n        else\n            libfile = libfile:gsub(\"%.dll$\", \".lib\")\n        end\n    end\n    return libfile\nend\n\n-- get the builtin variables\nfunction _get_builtinvars(target, installdir, libdir)\n    local target_ptrbytes\n    if target:is_plat(\"cross\") then\n        target_ptrbytes = target:check_sizeof(\"void*\")\n    else\n        target_ptrbytes = target:is_arch64() and \"8\" or \"4\"\n    end\n    local libsubdir\n    if libdir:startswith(installdir) then\n        libsubdir = path.relative(libdir, installdir)\n    else\n        raise(\"target(%s): libdir(%s) is not in installdir(%s)\", target:name(), libdir, installdir)\n    end\n    return {LIBDIR          = libsubdir,\n            TARGETNAME      = target:name(),\n            PROJECTNAME     = project.name() or target:name(),\n            TARGETFILENAME  = target:targetfile() and _get_libfilename(target, libdir),\n            TARGETKIND      = target:is_headeronly() and \"INTERFACE\" or (target:is_shared() and \"SHARED\" or \"STATIC\"),\n            PACKAGE_VERSION = target:get(\"version\") or \"1.0.0\",\n            TARGET_PTRBYTES = target_ptrbytes}\nend\n\n-- install cmake config file\nfunction _install_cmake_configfile(target, installdir, filename, opt)\n\n    -- get import file path\n    local libdir = _get_install_libdir(target, installdir, opt)\n    local projectname = project.name() or target:name()\n    local importfile_src = path.join(os.programdir(), \"scripts\", \"cmake_importfiles\", filename)\n    local importfile_dst = path.join(libdir, \"cmake\", projectname, (filename:gsub(\"xxx\", projectname)))\n\n    -- trace\n    vprint(\"generating %s ..\", importfile_dst)\n\n    -- get the builtin variables\n    local builtinvars = _get_builtinvars(target, installdir, libdir)\n\n    -- copy and replace builtin variables\n    local content = io.readfile(importfile_src)\n    if content then\n        content = content:split(\"#######################+#\")[1]\n        content = content:gsub(\"(@(.-)@)\", function(_, variable)\n            variable = variable:trim()\n            local value = builtinvars[variable]\n            return type(value) == \"function\" and value() or value\n        end)\n        io.writefile(importfile_dst, content)\n    end\nend\n\n-- append target to cmake config file\nfunction _append_cmake_configfile(target, installdir, filename, opt)\n\n    -- get import file path\n    local libdir = _get_install_libdir(target, installdir, opt)\n    local projectname = project.name() or target:name()\n    local importfile_src = path.join(os.programdir(), \"scripts\", \"cmake_importfiles\", filename)\n    local importfile_dst = path.join(libdir, \"cmake\", projectname, (filename:gsub(\"xxx\", projectname)))\n\n    -- get the builtin variables\n    local builtinvars = _get_builtinvars(target, installdir, libdir)\n\n    -- generate the file if not exist / file is outdated\n    if target:is_headeronly() or not os.isfile(importfile_dst) or os.mtime(importfile_dst) < os.mtime(target:targetfile()) then\n        _install_cmake_configfile(target, installdir, filename, opt)\n    end\n\n    -- copy and replace builtin variables\n    local content = io.readfile(importfile_src)\n    local dst_content = io.readfile(importfile_dst)\n    if content then\n        content = content:split(\"#######################+#\")[2]\n        content = content:gsub(\"(@(.-)@)\", function(_, variable)\n            variable = variable:trim()\n            local value = builtinvars[variable]\n            return type(value) == \"function\" and value() or value\n        end)\n        content = content:trim()\n\n        -- check if the target already exists\n        if not dst_content:match(format(\"%sTargets.cmake\", target:name())) then\n            io.writefile(importfile_dst, dst_content:trim() .. \"\\n\\n\" .. content .. \"\\n\")\n        end\n    end\nend\n\n-- install cmake target file\nfunction _install_cmake_targetfile(target, installdir, filename, opt)\n\n    -- get import file path\n    local libdir = _get_install_libdir(target, installdir, opt)\n    local projectname = project.name() or target:name()\n    local importfile_src = path.join(os.programdir(), \"scripts\", \"cmake_importfiles\", filename)\n    local importfile_dst = path.join(libdir, \"cmake\", projectname, (filename:gsub(\"xxx\", target:name())))\n\n    -- trace\n    vprint(\"generating %s ..\", importfile_dst)\n\n    -- get the builtin variables\n    local builtinvars = _get_builtinvars(target, installdir, libdir)\n\n    -- copy and replace builtin variables\n    local content = io.readfile(importfile_src)\n    if content then\n        content = content:gsub(\"(@(.-)@)\", function(_, variable)\n            variable = variable:trim()\n            local value = builtinvars[variable]\n            return type(value) == \"function\" and value() or value\n        end)\n        local libfilename = path.filename(target:targetfile())\n        local postfix = is_mode(\"debug\") and \"DEBUG\" or \"RELEASE\"\n        if target:is_shared() and (_get_libfilename(target, libdir) ~= libfilename) then\n            -- On DLL platforms, the import library is named differently from the target file\n            content = content:gsub(\"# IMPORTED_IMPLIB_\" .. postfix, \"IMPORTED_IMPLIB_\" .. postfix)\n            content = content:gsub(\n                \"IMPORTED_LOCATION_\" .. postfix .. \" \\\"%${_IMPORT_PREFIX}/lib/.-\\\"\",\n                \"IMPORTED_LOCATION_\" .. postfix .. \" \\\"${_IMPORT_PREFIX}/bin/\" .. libfilename .. \"\\\"\"\n            )\n        end\n        io.writefile(importfile_dst, content)\n    end\nend\n\n-- install .cmake import files\nfunction main(target, opt)\n\n    -- check\n    opt = opt or {}\n    assert(target:is_library(), 'cmake_importfiles: only support for library target(%s)!', target:name())\n\n    -- get install directory\n    local installdir = target:installdir()\n    if not installdir then\n        return\n    end\n\n    -- do install\n    installdir = path.normalize(installdir)\n    _append_cmake_configfile(target, installdir, \"xxxConfig.cmake\", opt)\n    _install_cmake_configfile(target, installdir, \"xxxConfigVersion.cmake\", opt)\n    _install_cmake_targetfile(target, installdir, \"xxxTargets.cmake\", opt)\n    if not target:is_headeronly() then\n        if is_mode(\"debug\") then\n            _install_cmake_targetfile(target, installdir, \"xxxTargets-debug.cmake\", opt)\n        else\n            _install_cmake_targetfile(target, installdir, \"xxxTargets-release.cmake\", opt)\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/target/action/install/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.project.project\")\nimport(\"utils.binary.deplibs\", {alias = \"get_depend_libraries\"})\nimport(\"utils.binary.rpath\", {alias = \"rpath_utils\"})\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\nfunction _get_target_libdir(target, opt)\n    if not opt.installdir then\n        return target:libdir()\n    end\n    assert(opt.libdir, \"opt.libdir is missing\")\n    return path.join(opt.installdir, opt.libdir)\nend\n\nfunction _get_target_bindir(target, opt)\n    if not opt.installdir then\n        return target:bindir()\n    end\n    assert(opt.bindir, \"opt.bindir is missing\")\n    return path.join(opt.installdir, opt.bindir)\nend\n\nfunction _get_target_includedir(target, opt)\n    if not opt.installdir then\n        return target:includedir()\n    end\n    assert(opt.includedir, \"opt.includedir is missing\")\n    return path.join(opt.installdir, opt.includedir)\nend\n\n-- copy file with symlinks\nfunction _copy_file_with_symlinks(srcfile, outputdir)\n    if os.islink(srcfile) then\n        local srcfile_symlink = os.readlink(srcfile)\n        if not path.is_absolute(srcfile_symlink) then\n            srcfile_symlink = path.join(path.directory(srcfile), srcfile_symlink)\n        end\n        _copy_file_with_symlinks(srcfile_symlink, outputdir)\n        os.vcp(srcfile, path.join(outputdir, path.filename(srcfile)), {symlink = true, force = true})\n    else\n        os.vcp(srcfile, path.join(outputdir, path.filename(srcfile)))\n    end\nend\n\n-- install files\nfunction _install_files(target)\n    local srcfiles, dstfiles = target:installfiles()\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            os.vcp(srcfile, dstfiles[idx])\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcfiles, dstfiles = dep:installfiles(dep:installdir(), {interface = true})\n        if srcfiles and dstfiles then\n            for idx, srcfile in ipairs(srcfiles) do\n                os.vcp(srcfile, dstfiles[idx])\n            end\n        end\n    end\nend\n\n-- install headers\nfunction _install_headers(target, opt)\n    local srcheaders, dstheaders = target:headerfiles(_get_target_includedir(target, opt), {installonly = true})\n    if srcheaders and dstheaders then\n        for idx, srcheader in ipairs(srcheaders) do\n            os.vcp(srcheader, dstheaders[idx])\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcfiles, dstfiles = dep:headerfiles(_get_target_includedir(dep, opt), {installonly = true, interface = true})\n        if srcfiles and dstfiles then\n            for idx, srcfile in ipairs(srcfiles) do\n                os.vcp(srcfile, dstfiles[idx])\n            end\n        end\n    end\nend\n\n-- install shared libraries\nfunction _install_shared_libraries(target, opt)\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(target, opt) or _get_target_libdir(target, opt)\n\n    -- get all dependent shared libraries\n    local libfiles = {}\n    target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {}, opt)\n    libfiles = table.unique(libfiles)\n\n    -- do install\n    for _, libfile in ipairs(libfiles) do\n        local filename = path.filename(libfile)\n        local filepath = path.join(bindir, filename)\n        if os.isfile(filepath) and hash.sha256(filepath) ~= hash.sha256(libfile) then\n            wprint(\"'%s' already exists in install dir, we are copying '%s' to overwrite it.\", filepath, libfile)\n        end\n        _copy_file_with_symlinks(libfile, bindir)\n    end\nend\n\n-- update install rpath, we can only get and update rpathdirs with `{installonly = true}`\n-- e.g. add_rpathdirs(\"@loader_path/../lib\", {installonly = true})\nfunction _update_install_rpath(target, opt)\n    if target:is_plat(\"windows\", \"mingw\") then\n        return\n    end\n    local bindir = _get_target_bindir(target, opt)\n    local targetfile = path.join(bindir, target:filename())\n    if target:policy(\"install.rpath\") then\n        local result, sources = target:get_from(\"rpathdirs\", \"*\")\n        if result and sources then\n            for idx, rpathdirs in ipairs(result) do\n                local source = sources[idx]\n                local extraconf = target:extraconf_from(\"rpathdirs\", source)\n                for _, rpathdir in ipairs(rpathdirs) do\n                    local extra = extraconf and extraconf[rpathdir] or nil\n                    if extra and extra.installonly then\n                        rpath_utils.insert(targetfile, rpathdir, {plat = target:plat(), arch = target:arch()})\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- install binary\nfunction _install_binary(target, opt)\n    if opt.libraries then\n        _install_shared_libraries(target, opt)\n    end\n    if opt.binaries then\n        local bindir = _get_target_bindir(target, opt)\n        os.mkdir(bindir)\n        os.vcp(target:targetfile(), bindir)\n        os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))\n        _update_install_rpath(target, opt)\n    end\nend\n\n-- install shared library\nfunction _install_shared(target, opt)\n    if opt.libraries then\n        local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(target, opt) or _get_target_libdir(target, opt)\n        os.mkdir(bindir)\n        local targetfile = target:targetfile()\n\n        if target:is_plat(\"windows\", \"mingw\") then\n            -- install *.lib for shared/windows (*.dll) target\n            -- @see https://github.com/xmake-io/xmake/issues/714\n            os.vcp(target:targetfile(), bindir)\n            local libdir = _get_target_libdir(target, opt)\n            local implibfile = target:artifactfile(\"implib\")\n            if os.isfile(implibfile) then\n                os.mkdir(libdir)\n                os.vcp(implibfile, libdir)\n            end\n        else\n            -- install target with soname and symlink\n            _copy_file_with_symlinks(targetfile, bindir)\n        end\n        os.trycp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))\n        _install_shared_libraries(target, opt)\n    end\n    if opt.headers then\n        _install_headers(target, opt)\n    end\nend\n\n-- install static library\nfunction _install_static(target, opt)\n    if opt.libraries then\n        local libdir = _get_target_libdir(target, opt)\n        os.mkdir(libdir)\n        os.vcp(target:targetfile(), libdir)\n        os.trycp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile())))\n    end\n    if opt.headers then\n        _install_headers(target, opt)\n    end\nend\n\n-- install headeronly library\nfunction _install_headeronly(target, opt)\n    if opt.headers then\n        _install_headers(target, opt)\n    end\nend\n\n-- install moduleonly library\nfunction _install_moduleonly(target, opt)\n    if opt.headers then\n        _install_headers(target, opt)\n    end\nend\n\nfunction main(target, opt)\n    opt = opt or {}\n    if opt.headers == nil then\n        opt.headers = true\n    end\n    if opt.binaries == nil then\n        opt.binaries = true\n    end\n    if opt.libraries == nil then\n        opt.libraries = true\n    end\n    if opt.packages == nil then\n        opt.packages = true\n    end\n\n    local installdir = opt.installdir or target:installdir()\n    if not installdir then\n        wprint(\"please use `xmake install -o installdir` or `set_installdir` to set install directory.\")\n        return\n    end\n    print(\"installing %s to %s ..\", target:name(), installdir)\n\n    if target:is_binary() then\n        _install_binary(target, opt)\n    elseif target:is_shared() then\n        _install_shared(target, opt)\n    elseif target:is_static() then\n        _install_static(target, opt)\n    elseif target:is_headeronly() then\n        _install_headeronly(target, opt)\n    elseif target:is_moduleonly() then\n        _install_moduleonly(target, opt)\n    end\n\n    _install_files(target)\nend\n"
  },
  {
    "path": "xmake/modules/target/action/install/pkgconfig_importfiles.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pkgconfig_importfiles.lua\n--\n\n-- install pkgconfig/.pc import files\nfunction main(target, opt)\n\n    -- check\n    opt = opt or {}\n    assert(target:is_library(), 'pkgconfig_importfiles: only support for library target(%s)!', target:name())\n    local installdir = path.unix(path.normalize(target:installdir()))\n    if not installdir then\n        return\n    end\n\n    -- get pkgconfig/.pc file\n    local libdir = path.unix(path.normalize(opt.libdir and path.join(installdir, opt.libdir) or target:libdir()))\n    local pcfile = path.join(libdir, \"pkgconfig\", opt.filename or (target:basename() .. \".pc\"))\n    if not libdir:startswith(installdir) then\n        raise(\"target(%s): libdir(%s) is not in installdir(%s)\", target:name(), libdir, installdir)\n    end\n\n    -- get includedirs\n    local includedirs = opt.includedirs\n\n    -- get links and linkdirs\n    local links = opt.links or target:basename()\n    local linkdirs = opt.linkdirs\n\n    -- get libs\n    local libs = \"\"\n    for _, linkdir in ipairs(linkdirs) do\n        linkdir = path.unix(path.normalize(linkdir)):replace(installdir, \"${exec_prefix}\", {plain = true})\n        if linkdir ~= \"${exec_prefix}/lib\" then\n            libs = libs .. \" -L\" .. linkdir\n        end\n    end\n    libs = libs .. \" -L${libdir}\"\n    if not target:is_headeronly() then\n        for _, link in ipairs(links) do\n            libs = libs .. \" -l\" .. link\n        end\n    end\n    libs = libs:trim()\n\n    -- get cflags\n    local cflags = \"\"\n    for _, includedir in ipairs(includedirs) do\n        includedir = path.unix(path.normalize(includedir)):replace(installdir, \"${prefix}\", {plain = true})\n        if includedir ~= \"${prefix}/include\" then\n            cflags = cflags .. \" -I\" .. includedir\n        end\n    end\n    cflags = cflags .. \" -I${includedir}\"\n    cflags = cflags:trim()\n\n    -- trace\n    vprint(\"generating %s ..\", pcfile)\n\n    -- generate a *.pc file\n    local file = io.open(pcfile, 'w')\n    if file then\n        file:print(\"# Generated by Xmake\")\n        file:print(\"prefix=%s\", \"${pcfiledir}/\" .. path.unix(path.relative(installdir, path.directory(pcfile))))\n        file:print(\"exec_prefix=${prefix}\")\n        file:print(\"libdir=${exec_prefix}/lib\")\n        file:print(\"includedir=${prefix}/include\")\n        file:print(\"\")\n        file:print(\"Name: %s\", target:name())\n        file:print(\"Description: %s\", target:name())\n        local version = target:get(\"version\")\n        if version then\n            file:print(\"Version: %s\", version)\n        end\n        file:print(\"Libs: %s\", libs)\n        file:print(\"Cflags: %s\", cflags)\n        file:close()\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/target/action/uninstall/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.project\")\nimport(\"private.action.clean.remove_files\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\nfunction _get_target_libdir(target, opt)\n    if not opt.installdir then\n        return target:libdir()\n    end\n    assert(opt.libdir, \"opt.libdir is missing\")\n    return path.join(opt.installdir, opt.libdir)\nend\n\nfunction _get_target_bindir(target, opt)\n    if not opt.installdir then\n        return target:bindir()\n    end\n    assert(opt.bindir, \"opt.bindir is missing\")\n    return path.join(opt.installdir, opt.bindir)\nend\n\nfunction _get_target_includedir(target, opt)\n    if not opt.installdir then\n        return target:includedir()\n    end\n    assert(opt.includedir, \"opt.includedir is missing\")\n    return path.join(opt.installdir, opt.includedir)\nend\n\n\n\n-- remove file with symbols\nfunction _remove_file_with_symbols(filepath)\n    if os.islink(filepath) then\n        local filepath_symlink = os.readlink(filepath)\n        if not path.is_absolute(filepath_symlink) then\n            filepath_symlink = path.join(path.directory(filepath), filepath_symlink)\n        end\n        _remove_file_with_symbols(filepath_symlink)\n    end\n    remove_files(filepath, {emptydir = true})\nend\n\n-- uninstall files\nfunction _uninstall_files(target)\n    local _, dstfiles = target:installfiles()\n    for _, dstfile in ipairs(dstfiles) do\n        remove_files(dstfile, {emptydir = true})\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local _, dstfiles = dep:installfiles(dep:installdir(), {interface = true})\n        for _, dstfile in ipairs(dstfiles) do\n            remove_files(dstfile, {emptydir = true})\n        end\n    end\nend\n\n-- uninstall headers\nfunction _uninstall_headers(target, opt)\n    local _, dstheaders = target:headerfiles(_get_target_includedir(target, opt), {installonly = true})\n    for _, dstheader in ipairs(dstheaders) do\n        remove_files(dstheader, {emptydir = true})\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local _, dstfiles = dep:headerfiles(_get_target_includedir(dep, opt), {installonly = true, interface = true})\n        for _, dstfile in ipairs(dstfiles) do\n            remove_files(dstfile, {emptydir = true})\n        end\n    end\nend\n\n-- uninstall shared libraries\nfunction _uninstall_shared_libraries(target, opt)\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(target, opt) or _get_target_libdir(target, opt)\n\n    -- get all dependent shared libraries\n    local libfiles = {}\n    target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {})\n    libfiles = table.unique(libfiles)\n\n    -- do uninstall\n    for _, libfile in ipairs(libfiles) do\n        local filename = path.filename(libfile)\n        local filepath = path.join(bindir, filename)\n        _remove_file_with_symbols(filepath)\n    end\nend\n\n-- uninstall binary\nfunction _uninstall_binary(target, opt)\n    local bindir = _get_target_bindir(target, opt)\n    remove_files(path.join(bindir, path.filename(target:targetfile())), {emptydir = true})\n    remove_files(path.join(bindir, path.filename(target:symbolfile())), {emptydir = true})\n    _uninstall_shared_libraries(target, opt)\nend\n\n-- uninstall shared library\nfunction _uninstall_shared(target, opt)\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(target, opt) or _get_target_libdir(target, opt) \n    if target:is_plat(\"windows\", \"mingw\") then\n        -- uninstall *.lib for shared/windows (*.dll) target\n        -- @see https://github.com/xmake-io/xmake/issues/714\n        local libdir = _get_target_libdir(target, opt)\n        local targetfile = target:targetfile()\n        remove_files(path.join(bindir, path.filename(targetfile)), {emptydir = true})\n        remove_files(path.join(libdir, path.basename(targetfile) .. (target:is_plat(\"mingw\") and \".dll.a\" or \".lib\")), {emptydir = true})\n    else\n        local targetfile = path.join(bindir, path.filename(target:targetfile()))\n        _remove_file_with_symbols(targetfile)\n    end\n    remove_files(path.join(bindir, path.filename(target:symbolfile())), {emptydir = true})\n\n    _uninstall_headers(target, opt)\n    _uninstall_shared_libraries(target, opt)\nend\n\n-- uninstall static library\nfunction _uninstall_static(target, opt)\n    local libdir = _get_target_libdir(target, opt)\n    remove_files(path.join(libdir, path.filename(target:targetfile())), {emptydir = true})\n    remove_files(path.join(libdir, path.filename(target:symbolfile())), {emptydir = true})\n    _uninstall_headers(target, opt)\nend\n\n-- uninstall headeronly library\nfunction _uninstall_headeronly(target, opt)\n    _uninstall_headers(target, opt)\nend\n\n-- uninstall moduleonly library\nfunction _uninstall_moduleonly(target, opt)\n    _uninstall_headers(target, opt)\nend\n\nfunction main(target, opt)\n    opt = opt or {}\n    local installdir = opt.installdir or target:installdir()\n    if not installdir then\n        wprint(\"please use `xmake install -o installdir` or `set_installdir` to set install directory.\")\n        return\n    end\n    print(\"uninstalling %s to %s ..\", target:name(), installdir)\n\n    if target:is_binary() then\n        _uninstall_binary(target, opt)\n    elseif target:is_shared() then\n        _uninstall_shared(target, opt)\n    elseif target:is_static() then\n        _uninstall_static(target, opt)\n    elseif target:is_headeronly() then\n        _uninstall_headeronly(target, opt)\n    elseif target:is_moduleonly() then\n        _uninstall_moduleonly(target, opt)\n    end\n\n    _uninstall_files(target)\nend\n\n"
  },
  {
    "path": "xmake/modules/ui/app/showfile.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, showfile 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        showfile.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.event\")\nimport(\"core.ui.textdialog\")\nimport(\"core.ui.application\")\n\n-- the application\nlocal app = application()\n\n-- init app\nfunction app:init(argv)\n\n    -- init name\n    application.init(self, \"app\", argv)\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- get file\n    local file = argv[1]\n\n    -- read file content\n    local content = nil\n    if file then\n        content = os.isfile(file) and io.readfile(file) or nil\n    else\n        content = \"please input file path!\"\n    end\n\n    -- init main dialog\n    local dialog_main = textdialog:new(\"dialog.main\", rect {1, 1, self:width() - 1, self:height() - 1}, \"showfile: \" .. (file and path.filename(file) or \"\"))\n    dialog_main:text():text_set(content or string.format(\"cannot read file(%s)!\", file))\n    dialog_main:button_add(\"exit\", \"< Exit >\", function (v) self:quit() end)\n    self:insert(dialog_main)\nend\n\n-- main entry\nfunction main(...)\n    app:run(...)\nend\n"
  },
  {
    "path": "xmake/modules/ui/app/version.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        version.lua\n--\n\n-- imports\nimport(\"core.ui.log\")\nimport(\"core.ui.rect\")\nimport(\"core.ui.event\")\nimport(\"core.ui.textdialog\")\nimport(\"core.ui.application\")\n\n-- the application\nlocal app = application()\n\n-- init app\nfunction app:init()\n\n    -- init name\n    application.init(self, \"app\")\n\n    -- init background\n    self:background_set(\"blue\")\n\n    -- disable color code output\n    os.setenv(\"COLORTERM\", \"nocolor\")\n\n    -- get version info\n    local version = os.iorun(\"xmake --version\")\n\n    -- init main dialog\n    local dialog_main = textdialog:new(\"dialog.main\", rect {1, 1, self:width() - 1, self:height() - 1}, \"version info\")\n    dialog_main:text():text_set(version or \"unknown version!\")\n    dialog_main:button_add(\"exit\", \"< Exit >\", function (v) self:quit() end)\n    self:insert(dialog_main)\nend\n\n-- main entry\nfunction main(...)\n    app:run(...)\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/archive.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        archive.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"archive_xmz\")\nimport(\"extension\", {alias = \"get_archive_extension\"})\n\n-- archive archivefile using xmake compress module\nfunction _archive_using_xmz(archivefile, inputfiles, extension, opt)\n    archive_xmz(archivefile, inputfiles, opt)\n    return true\nend\n\n-- archive archivefile using zip\nfunction _archive_using_zip(archivefile, inputfiles, extension, opt)\n\n    -- find zip\n    local zip = find_tool(\"zip\")\n    if not zip then\n        return false\n    end\n\n    -- init argv\n    local argv = {archivefile}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    if opt.excludes then\n        table.insert(argv, \"-x\")\n        for _, exclude in ipairs(opt.excludes) do\n            table.insert(argv, exclude)\n        end\n    end\n    local compress = opt.compress\n    if compress then\n        if compress == \"faster\" or compress == \"fastest\" then\n            table.insert(argv, \"-1\")\n        elseif compress == \"better\" or compress == \"best\" then\n            table.insert(argv, \"-9\")\n        end\n    end\n    if opt.recurse then\n        table.insert(argv, \"-r\")\n    end\n    local inputlistfile = os.tmpfile()\n    if type(inputfiles) == \"table\" then\n        local file = io.open(inputlistfile, \"w\")\n        for _, inputfile in ipairs(inputfiles) do\n            file:print(inputfile)\n        end\n        file:close()\n        table.insert(argv, \"-@\")\n    else\n        table.insert(argv, inputfiles)\n    end\n\n    -- archive it\n    os.vrunv(zip.program, argv, {curdir = opt.curdir, stdin = inputlistfile})\n    if inputlistfile then\n        os.tryrm(inputlistfile)\n    end\n    return true\nend\n\n-- archive archivefile using 7z\nfunction _archive_using_7z(archivefile, inputfiles, extension, opt)\n\n    -- find 7z\n    local z7 = find_tool(\"7z\")\n    if not z7 then\n        return false\n    end\n\n    -- init argv\n    local argv = {\"a\"}\n    if extension == \".gz\" then\n        table.insert(argv, \"-tgzip\")\n    end\n    if extension == \".tar\" then\n        table.insert(argv, \"-ttar\")\n    end\n    if extension == \".xz\" then\n        table.insert(argv, \"-txz\")\n    end\n    table.insert(argv, archivefile)\n    table.insert(argv, \"-y\")\n    local excludesfile\n    if opt.excludes then\n        excludesfile = os.tmpfile()\n        io.writefile(excludesfile, table.concat(table.wrap(opt.excludes), '\\n'))\n        table.insert(argv, \"-xr@\" .. excludesfile)\n    end\n    local compress = opt.compress\n    if compress and extension ~= \".tar\" then\n        if compress == \"fastest\" then\n            table.insert(argv, \"-mx1\")\n        elseif compress == \"faster\" then\n            table.insert(argv, \"-mx3\")\n        elseif compress == \"better\" then\n            table.insert(argv, \"-mx7\")\n        elseif compress == \"best\" then\n            table.insert(argv, \"-mx9\")\n        end\n    end\n    if opt.recurse then\n        table.insert(argv, \"-r\")\n    end\n    local inputlistfile = os.tmpfile()\n    if type(inputfiles) == \"table\" then\n        local file = io.open(inputlistfile, \"w\")\n        for _, inputfile in ipairs(inputfiles) do\n            file:print(inputfile)\n        end\n        file:close()\n        table.insert(argv, \"-i@\" .. inputlistfile)\n    else\n        table.insert(argv, inputfiles)\n    end\n\n    -- archive it\n    os.vrunv(z7.program, argv, {curdir = opt.curdir})\n\n    -- remove the excludes files\n    if excludesfile then\n        os.tryrm(excludesfile)\n    end\n    if inputlistfile then\n        os.tryrm(inputlistfile)\n    end\n    return true\nend\n\n-- archive archivefile using xz\nfunction _archive_using_xz(archivefile, inputfiles, extension, opt)\n\n    -- find xz\n    local xz = find_tool(\"xz\")\n    if not xz then\n        return false\n    end\n\n    -- init argv\n    local argv = {\"-z\", \"-k\", \"-c\", archivefile}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    local compress = opt.compress\n    if compress then\n        if compress == \"fastest\" then\n            table.insert(argv, \"-1\")\n        elseif compress == \"faster\" then\n            table.insert(argv, \"-3\")\n        elseif compress == \"better\" then\n            table.insert(argv, \"-7\")\n        elseif compress == \"best\" then\n            table.insert(argv, \"-9\")\n        end\n    end\n    if type(inputfiles) == \"table\" then\n        for _, inputfile in ipairs(inputfiles) do\n            table.insert(argv, inputfile)\n        end\n    else\n        table.insert(argv, inputfiles)\n    end\n\n    -- archive it\n    os.vrunv(xz.program, argv, {stdout = archivefile, curdir = opt.curdir})\n    return true\nend\n\n-- archive archivefile using gzip\nfunction _archive_using_gzip(archivefile, inputfiles, extension, opt)\n\n    -- find gzip\n    local gzip = find_tool(\"gzip\")\n    if not gzip then\n        return false\n    end\n\n    -- init argv\n    local argv = {\"-c\", archivefile}\n    local keep = _g.gzip_keep\n    if keep == nil then\n        -- https://github.com/xmake-io/xmake/issues/7361\n        keep = try {function ()\n            local outdata, errdata = os.iorunv(gzip.program, {\"--help\"})\n            local result = (outdata or \"\") .. (errdata or \"\")\n            if result and (result:find(\" -k\", 1, true) or result:find(\"--keep\", 1, true)) then\n                return true\n            end\n        end}\n        _g.gzip_keep = keep or false\n    end\n    if keep then\n        table.insert(argv, 1, \"-k\")\n    end\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    local compress = opt.compress\n    if compress then\n        if compress == \"fastest\" then\n            table.insert(argv, \"-1\")\n        elseif compress == \"faster\" then\n            table.insert(argv, \"-3\")\n        elseif compress == \"better\" then\n            table.insert(argv, \"-7\")\n        elseif compress == \"best\" then\n            table.insert(argv, \"-9\")\n        end\n    end\n    if opt.recurse then\n        table.insert(argv, \"-r\")\n    end\n    if type(inputfiles) == \"table\" then\n        for _, inputfile in ipairs(inputfiles) do\n            table.insert(argv, inputfile)\n        end\n    else\n        table.insert(argv, inputfiles)\n    end\n\n    -- archive it\n    os.vrunv(gzip.program, argv, {stdout = archivefile, curdir = opt.curdir})\n    return true\nend\n\n-- archive archivefile using tar\nfunction _archive_using_tar(archivefile, inputfiles, extension, opt)\n\n    -- find tar\n    local tar = find_tool(\"tar\")\n    if not tar then\n        return false\n    end\n\n    -- with compress? e.g. .tar.xz\n    local compress = false\n    local archivefile_tar\n    if extension ~= \".tar\" then\n        compress = true\n        archivefile_tar = path.join(path.directory(archivefile), path.basename(archivefile))\n    end\n\n    -- init argv\n    local argv = {}\n    local program = tar.program\n    if is_host(\"windows\") then\n        local force_local = _g.force_local\n        if force_local == nil then\n            force_local = try {function ()\n                local outdata, errdata = os.iorunv(program, {\"--help\"})\n                local result = (outdata or \"\") .. (errdata or \"\")\n                if result and result:find(\"--force-local\", 1, true) then\n                    return true\n                end\n            end}\n            _g.force_local = force_local or false\n        end\n        if force_local then\n            table.insert(argv, \"--force-local\")\n        end\n    end\n    if compress and not is_host(\"windows\") then\n        table.insert(argv, \"-a\")\n    end\n    if option.get(\"verbose\") then\n        table.insert(argv, \"-cvf\")\n    else\n        table.insert(argv, \"-cf\")\n    end\n    table.insert(argv, archivefile_tar and archivefile_tar or archivefile)\n    if opt.excludes then\n        for _, exclude in ipairs(opt.excludes) do\n            table.insert(argv, \"--exclude=\")\n            table.insert(argv, exclude)\n        end\n    end\n    if not opt.recurse then\n        table.insert(argv, \"-n\")\n    end\n    local inputlistfile = os.tmpfile()\n    if type(inputfiles) == \"table\" then\n        local file = io.open(inputlistfile, \"w\")\n        for _, inputfile in ipairs(inputfiles) do\n            file:print(inputfile)\n        end\n        file:close()\n        table.insert(argv, \"-T\")\n        table.insert(argv, inputlistfile)\n    else\n        table.insert(argv, inputfiles)\n    end\n\n    -- archive it\n    os.vrunv(program, argv, {curdir = opt.curdir})\n    if inputlistfile then\n        os.tryrm(inputlistfile)\n    end\n    if archivefile_tar and os.isfile(archivefile_tar) then\n        try {\n            function ()\n                _archive_tarfile(archivefile, archivefile_tar, opt)\n                os.tryrm(archivefile_tar)\n                return true\n            end,\n            catch {\n                function (errs)\n                    os.tryrm(archivefile_tar)\n                    raise(errs)\n                end\n            }\n        }\n    end\n    return true\nend\n\n-- archive archive file using archivers\nfunction _archive(archivefile, inputfiles, extension, archivers, opt)\n    local errors\n    for _, archive in ipairs(archivers) do\n        local ok = try {\n            function ()\n                return archive(archivefile, inputfiles, extension, opt)\n            end,\n            catch {\n                function (errs)\n                    if errs then\n                        errors = tostring(errs)\n                    end\n                end\n            }\n        }\n        if ok then\n            return true\n        end\n    end\n    raise(\"cannot archive %s, %s!\", path.filename(archivefile), errors or \"no archiver(like zip, ...) found\")\nend\n\n-- only archive tar file\nfunction _archive_tarfile(archivefile, tarfile, opt)\n    local archivers = {\n        [\".xz\"]         = {_archive_using_xz, _archive_using_7z}\n    ,   [\".gz\"]         = {_archive_using_gzip, _archive_using_7z}\n    }\n    local extension = opt.extension or path.extension(archivefile)\n    return _archive(archivefile, tarfile, extension, archivers[extension], opt)\nend\n\n-- archive file\n--\n-- @param archivefile   the archive file. e.g. *.tar.gz, *.zip, *.7z, *.tar.bz2, ..\n-- @param inputfiles    the input file or directory or list\n-- @param options       the options, e.g.. {curdir = \"/tmp\", recurse = true, compress = \"fastest|faster|default|better|best\", excludes = {\"*/dir/*\", \"dir/*\"}}\n--\nfunction main(archivefile, inputfiles, opt)\n    opt = opt or {}\n    inputfiles = inputfiles or os.curdir()\n    if opt.recurse == nil then\n        opt.recurse = true\n    end\n\n    -- init archivers\n    local archivers = {\n        [\".zip\"]        = {_archive_using_zip, _archive_using_7z}\n    ,   [\".7z\"]         = {_archive_using_7z}\n    ,   [\".xz\"]         = {_archive_using_xz, _archive_using_7z}\n    ,   [\".gz\"]         = {_archive_using_gzip, _archive_using_7z}\n    ,   [\".tar\"]        = {_archive_using_tar, _archive_using_7z}\n    ,   [\".tar.gz\"]     = {_archive_using_tar}\n    ,   [\".tar.xz\"]     = {_archive_using_tar}\n    ,   [\".xmz\"]        = {_archive_using_xmz}\n    }\n\n    -- get extension\n    local extension = opt.extension or get_archive_extension(archivefile)\n\n    -- ensure output directory\n    local archivedir = path.directory(archivefile)\n    if not os.isdir(archivedir) then\n        os.mkdir(archivedir)\n    end\n\n    -- archive it\n    return _archive(archivefile, inputfiles, extension, archivers[extension], opt)\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/archive_xmz.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        archive_xmz.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.bytes\")\nimport(\"core.compress.lz4\")\n\n-- archive files\nfunction _archive_files(archivefile, inputfiles, opt)\n    local curdir = opt.curdir\n    local outputfile = io.open(archivefile, \"wb\")\n    for _, inputfile in ipairs(inputfiles) do\n        local filepath = inputfile\n        if curdir then\n            filepath = path.relative(filepath, curdir)\n        end\n        outputfile:write(bytes(2):u16be_set(1, #filepath))\n        outputfile:write(filepath)\n        local data = io.readfile(inputfile, {encoding = \"binary\"})\n        vprint(\"archiving %s, %d bytes\", inputfile, data and #data or 0)\n        outputfile:write(bytes(4):u32be_set(1, #data))\n        outputfile:write(data)\n    end\n    outputfile:close()\nend\n\n-- compress file\nfunction _compress_file(archivefile, outputfile, opt)\n    lz4.compress_file(archivefile, outputfile)\nend\n\n-- archive file\n--\n-- @param archivefile   the archive file. e.g. *.tar.gz, *.zip, *.7z, *.tar.bz2, ..\n-- @param inputfiles    the input file or directory or list\n-- @param options       the options, e.g.. {curdir = \"/tmp\", recurse = true, compress = \"fastest|faster|default|better|best\", excludes = {\"*/dir/*\", \"dir/*\"}}\n--\nfunction main(archivefile, inputfiles, opt)\n    opt = opt or {}\n    local files = {}\n    for _, inputfile in ipairs(inputfiles) do\n        if os.isdir(inputfile) then\n            table.join2(files, os.files(path.join(inputfile, opt.recurse and \"**\" or \"*\")))\n        elseif os.isfile(inputfile) then\n            table.insert(files, inputfile)\n        end\n    end\n    inputfiles = files\n\n    local archivefile_tmp = os.tmpfile({ramdisk = false})\n    _archive_files(archivefile_tmp, inputfiles, opt)\n    _compress_file(archivefile_tmp, archivefile, opt)\n    os.tryrm(archivefile_tmp)\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/extension.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        extension.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\n\n-- get the archive extension\nfunction main(url)\n    local urlpath = url:split('?', {plain = true})[1]\n    local extension = \"\"\n    local filename = path.filename(urlpath)\n    local extensionset = hashset.from({\n        \".xmz\", -- xmake compression format\n        \".zip\", \".7z\", \".gz\", \".xz\", \".zst\", \".tgz\",\n        \".bz2\", \".tar\", \".tar.gz\", \".tar.xz\",\n        \".tar.zst\", \".tar.bz2\", \".tar.Z\"})\n    local i = filename:lastof(\".\", true)\n    if i then\n        local p = filename:sub(1, i - 1):lastof(\".\", true)\n        if p and extensionset:has(filename:sub(p)) then i = p end\n        extension = filename:sub(i)\n    end\n    return extensionset:has(extension) and extension or \"\"\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/extract.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        extract.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_tool\")\nimport(\"extract_xmz\")\nimport(\"extension\", {alias = \"get_archive_extension\"})\n\n-- extract archivefile using xmake decompress module\nfunction _extract_using_xmz(archivefile, outputdir, extension, opt)\n    extract_xmz(archivefile, outputdir, opt)\n    return true\nend\n\n-- extract archivefile using tar\nfunction _extract_using_tar(archivefile, outputdir, extension, opt)\n\n    -- the tar on windows can only extract \"*.tar\", \"*.tar.gz\"\n    -- the tar on msys2 can extract more, like \"*.tar.bz2\", ..\n    if os.host() == \"windows\" and (extension ~= \".tar\" and extension ~= \".tar.gz\") then\n        return false\n    end\n\n    -- find tar\n    local tar = find_tool(\"tar\")\n    if not tar then\n        return false\n    end\n    local program = tar.program\n\n    -- init argv\n    local argv = {}\n    if is_host(\"windows\") then\n        -- force \"x:\\\\xx\" as local file\n        local force_local = _g.force_local\n        if force_local == nil then\n            force_local = try {function ()\n                local result = os.iorunv(program, {\"--help\"})\n                if result and result:find(\"--force-local\", 1, true) then\n                    return true\n                end\n            end}\n            _g.force_local = force_local or false\n        end\n        if force_local then\n            table.insert(argv, \"--force-local\")\n        end\n    end\n    table.insert(argv, \"-xf\")\n    table.insert(argv, path.absolute(archivefile))\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- set outputdir\n    if not is_host(\"windows\") then\n        table.insert(argv, \"-C\")\n        table.insert(argv, outputdir)\n    end\n\n    -- excludes files\n    if opt.excludes then\n        table.insert(argv, \"--exclude\")\n        for _, exclude in ipairs(opt.excludes) do\n            table.insert(argv, exclude)\n        end\n    end\n\n    -- extract it\n    if is_host(\"windows\") then\n        os.vrunv(program, argv, {curdir = outputdir})\n    else\n        os.vrunv(program, argv)\n    end\n\n    return true\nend\n\n-- extract archivefile using 7z\nfunction _extract_using_7z(archivefile, outputdir, extension, opt)\n\n    -- find 7z\n    local z7 = find_tool(\"7z\")\n    if not z7 then\n        return false\n    end\n    local program = z7.program\n\n    -- p7zip cannot extract other archive format on msys/cygwin, but it can extract .tgz\n    -- https://github.com/xmake-io/xmake/issues/1575#issuecomment-898205462\n    if is_subhost(\"msys\", \"cygwin\") and program:startswith(\"sh \") and\n        extension ~= \".7z\" and extension ~= \".tgz\" then\n        return false\n    end\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") or extension == \".tgz\" then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- on msys2/cygwin? we need to translate input path to cygwin-like path\n    if is_subhost(\"msys\", \"cygwin\") and program:gsub(\"\\\\\", \"/\"):find(\"/usr/bin\") then\n        archivefile = path.cygwin_path(archivefile)\n    end\n\n    -- init argv\n    local argv = {\"x\", \"-y\", archivefile}\n\n    -- disable to store symlinks on windows\n    if is_host(\"windows\") then\n        table.insert(argv, \"-snl-\")\n    end\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- set outputdir\n    table.insert(argv, \"-o\" .. outputdir)\n\n    -- excludes files\n    local excludesfile = nil\n    if opt.excludes and not outputdir_old then\n        excludesfile = os.tmpfile()\n        io.writefile(excludesfile, table.concat(table.wrap(opt.excludes), '\\n'))\n        table.insert(argv, \"-xr@\" .. excludesfile)\n    end\n\n    -- extract it\n    os.vrunv(program, argv)\n\n    -- remove the excludes file\n    if excludesfile then\n        os.tryrm(excludesfile)\n    end\n\n    -- remove unused pax_global_header file after extracting .tar file\n    if extension == \".tar\" then\n        os.tryrm(path.join(outputdir, \"pax_global_header\"))\n        os.tryrm(path.join(outputdir, \"PaxHeaders*\"))\n        os.tryrm(path.join(outputdir, \"@PaxHeader\"))\n        -- https://github.com/xmake-io/xmake-repo/pull/2673\n        os.tryrm(path.join(outputdir, \"*.paxheader\"))\n    end\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using gzip\nfunction _extract_using_gzip(archivefile, outputdir, extension, opt)\n\n    -- find gzip\n    local gzip = find_tool(\"gzip\")\n    if not gzip then\n        return false\n    end\n    local program = gzip.program\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- init temporary archivefile\n    local tmpfile = path.join(outputdir, path.filename(archivefile))\n\n    -- init argv\n    local argv = {\"-d\", \"-f\"}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    table.insert(argv, tmpfile)\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- copy archivefile to outputdir first\n    if path.absolute(archivefile) ~= path.absolute(tmpfile) then\n        os.cp(archivefile, tmpfile)\n    end\n\n    -- extract it\n    os.vrunv(program, argv, {curdir = outputdir})\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using xz\nfunction _extract_using_xz(archivefile, outputdir, extension, opt)\n\n    -- find xz\n    local xz = find_tool(\"xz\")\n    if not xz then\n        return false\n    end\n    local program = xz.program\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- init temporary archivefile\n    local tmpfile = path.join(outputdir, path.filename(archivefile))\n\n    -- init argv\n    local argv = {\"-d\", \"-f\"}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    table.insert(argv, tmpfile)\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- copy archivefile to outputdir first\n    if path.absolute(archivefile) ~= path.absolute(tmpfile) then\n        os.cp(archivefile, tmpfile)\n    end\n\n    -- extract it\n    os.vrunv(program, argv, {curdir = outputdir})\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using zstd\nfunction _extract_using_zstd(archivefile, outputdir, extension, opt)\n\n    -- find zstd\n    local zstd = find_tool(\"zstd\")\n    if not zstd then\n        return false\n    end\n    local program = zstd.program\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- init temporary archivefile\n    local tmpfile = path.join(outputdir, path.filename(archivefile))\n\n    -- init argv\n    local argv = {\"-d\"}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    table.insert(argv, tmpfile)\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- copy archivefile to outputdir first\n    if path.absolute(archivefile) ~= path.absolute(tmpfile) then\n        os.cp(archivefile, tmpfile)\n    end\n\n    -- extract it\n    os.vrunv(program, argv, {curdir = outputdir})\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using unzip\nfunction _extract_using_unzip(archivefile, outputdir, extension, opt)\n\n    -- find unzip\n    local unzip = find_tool(\"unzip\")\n    if not unzip then\n        return false\n    end\n    local program = unzip.program\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- init argv\n    local argv = {\"-o\"} -- overwrite existing files without prompting\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    table.insert(argv, archivefile)\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- extract to outputdir\n    table.insert(argv, \"-d\")\n    table.insert(argv, outputdir)\n\n    -- excludes files\n    if opt.excludes and not outputdir_old then\n        table.insert(argv, \"-x\")\n        for _, exclude in ipairs(opt.excludes) do\n            table.insert(argv, exclude)\n        end\n    end\n\n    -- extract it\n    os.vrunv(program, argv)\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using powershell\n-- powershell -ExecutionPolicy Bypass -File \"D:\\scripts\\unzip.ps1\" \"archivefile\" \"outputdir\"\nfunction _extract_using_powershell(archivefile, outputdir, extension, opt)\n\n    -- find powershell\n    local powershell = find_tool(\"pwsh\") or find_tool(\"powershell\")\n    if not powershell then\n        return false\n    end\n\n    -- get the script file\n    local scriptfile = path.join(os.programdir(), \"scripts\", \"unzip.ps1\")\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- extract it\n    local argv = {\"-ExecutionPolicy\", \"Bypass\", \"-File\", scriptfile, archivefile, outputdir}\n    os.vrunv(powershell.program, argv)\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract archivefile using bzip2\nfunction _extract_using_bzip2(archivefile, outputdir, extension, opt)\n\n    -- find bzip2\n    local bzip2 = find_tool(\"bzip2\")\n    if not bzip2 then\n        return false\n    end\n    local program = bzip2.program\n\n    -- extract to *.tar file first\n    local outputdir_old = nil\n    if extension:startswith(\".tar.\") then\n        outputdir_old = outputdir\n        outputdir = os.tmpfile({ramdisk = false}) .. \".tar\"\n    end\n\n    -- on msys2/cygwin? we need to translate input path to cygwin-like path\n    if is_subhost(\"msys\", \"cygwin\") and program:gsub(\"\\\\\", \"/\"):find(\"/usr/bin\") then\n        archivefile = path.cygwin_path(archivefile)\n    end\n\n    -- init temporary archivefile\n    local tmpfile = path.join(outputdir, path.filename(archivefile))\n\n    -- init argv\n    local argv = {\"-d\", \"-f\"}\n    if not option.get(\"verbose\") then\n        table.insert(argv, \"-q\")\n    end\n    table.insert(argv, tmpfile)\n\n    -- ensure output directory\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- copy archivefile to outputdir first\n    if path.absolute(archivefile) ~= path.absolute(tmpfile) then\n        os.cp(archivefile, tmpfile)\n    end\n\n    -- extract it\n    os.vrunv(program, argv, {curdir = outputdir})\n    return _extract_uncompressed_tar(outputdir_old, outputdir, opt)\nend\n\n-- extract *.tar after decompress\nfunction _extract_uncompressed_tar(outputdir_old, outputdir, opt)\n    if outputdir_old then\n        local tarfile = find_file(\"**.tar\", outputdir)\n        if tarfile and os.isfile(tarfile) then\n            local ok = _extract(tarfile, outputdir_old, \".tar\", {_extract_using_7z, _extract_using_tar}, opt)\n            -- remove the temporary tar file\n            -- @see https://github.com/xmake-io/xmake/issues/6311\n            os.rm(tarfile)\n            os.rm(outputdir, {emptydirs = true})\n            return ok\n        end\n    end\n    return true\nend\n\n-- extract archive file using extractors\nfunction _extract(archivefile, outputdir, extension, extractors, opt)\n    local errors\n    for _, extract in ipairs(extractors) do\n        local ok = try {\n            function ()\n                return extract(archivefile, outputdir, extension, opt)\n            end,\n            catch {\n                function (errs)\n                    if errs then\n                        errors = tostring(errs)\n                    end\n                end\n            }\n        }\n        if ok then\n            return true\n        end\n    end\n    raise(\"cannot extract %s, %s!\", path.filename(archivefile), errors or \"no extractor(like unzip, ...) found\")\nend\n\n-- extract file\n--\n-- @param archivefile   the archive file. e.g. *.tar.gz, *.zip, *.7z, *.tar.bz2, ..\n-- @param outputdir     the output directory\n-- @param options       the options, e.g.. {excludes = {\"*/dir/*\", \"dir/*\"}}\n--\nfunction main(archivefile, outputdir, opt)\n    opt = opt or {}\n    outputdir = outputdir or os.curdir()\n\n    -- init extractors\n    local extractors\n    if is_subhost(\"windows\") then\n        -- we use 7z first, becase xmake package has builtin 7z program on windows\n        -- tar/windows can not extract .bz2 ...\n        -- 7z doesn't support zstd by default\n        extractors =\n        {\n            [\".zip\"]        = {_extract_using_7z, _extract_using_unzip, _extract_using_tar, _extract_using_powershell}\n        ,   [\".7z\"]         = {_extract_using_7z}\n        ,   [\".gz\"]         = {_extract_using_7z, _extract_using_gzip, _extract_using_tar}\n        ,   [\".xz\"]         = {_extract_using_7z, _extract_using_xz, _extract_using_tar}\n        ,   [\".zst\"]        = {_extract_using_zstd, _extract_using_tar}\n        ,   [\".tgz\"]        = {_extract_using_7z, _extract_using_tar}\n        ,   [\".bz2\"]        = {_extract_using_7z, _extract_using_bzip2}\n        ,   [\".tar\"]        = {_extract_using_7z, _extract_using_tar}\n        -- @see https://github.com/xmake-io/xmake/issues/5538\n        ,   [\".tar.gz\"]     = {_extract_using_tar, _extract_using_7z, _extract_using_gzip}\n        ,   [\".tar.xz\"]     = {_extract_using_7z, _extract_using_xz}\n        ,   [\".tar.zst\"]    = {_extract_using_zstd}\n        ,   [\".tar.bz2\"]    = {_extract_using_7z, _extract_using_bzip2}\n        ,   [\".tar.lz\"]     = {_extract_using_7z}\n        ,   [\".tar.Z\"]      = {_extract_using_7z}\n        ,   [\".xmz\"]        = {_extract_using_xmz}\n        }\n    else\n        extractors =\n        {\n            -- tar supports .zip on macOS but does not on Linux\n            [\".zip\"]        = is_host(\"macosx\") and {_extract_using_unzip, _extract_using_tar, _extract_using_7z} or {_extract_using_unzip, _extract_using_7z}\n        ,   [\".7z\"]         = {_extract_using_7z}\n        ,   [\".gz\"]         = {_extract_using_gzip, _extract_using_tar, _extract_using_7z}\n        ,   [\".xz\"]         = {_extract_using_xz, _extract_using_tar, _extract_using_7z}\n        ,   [\".zst\"]        = {_extract_using_zstd, _extract_using_tar}\n        ,   [\".tgz\"]        = {_extract_using_tar, _extract_using_7z}\n        ,   [\".bz2\"]        = {_extract_using_bzip2, _extract_using_tar, _extract_using_7z}\n        ,   [\".tar\"]        = {_extract_using_tar, _extract_using_7z}\n        ,   [\".tar.gz\"]     = {_extract_using_tar, _extract_using_7z, _extract_using_gzip}\n        ,   [\".tar.xz\"]     = {_extract_using_tar, _extract_using_7z, _extract_using_xz}\n        ,   [\".tar.zst\"]     = {_extract_using_tar, _extract_using_zstd}\n        ,   [\".tar.bz2\"]    = {_extract_using_tar, _extract_using_7z, _extract_using_bzip2}\n        ,   [\".tar.lz\"]     = {_extract_using_tar, _extract_using_7z}\n        ,   [\".tar.Z\"]      = {_extract_using_tar, _extract_using_7z}\n        ,   [\".xmz\"]        = {_extract_using_xmz}\n        }\n    end\n\n    -- get extension\n    local extension = opt.extension or get_archive_extension(archivefile)\n\n    -- extract it\n    return _extract(archivefile, outputdir, extension, extractors[extension], opt)\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/extract_xmz.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        extract_xmz.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.bytes\")\nimport(\"core.compress.lz4\")\n\n-- extract files\nfunction _extract_files(archivefile, outputdir, opt)\n    local inputfile = io.open(archivefile, \"rb\")\n    local filesize = inputfile:size()\n    local readsize = 0\n    while readsize < filesize do\n        local data = inputfile:read(2)\n        local size = bytes(data):u16be(1)\n        local filepath\n        if size > 0 then\n            filepath = inputfile:read(size)\n        end\n        readsize = readsize + 2 + size\n        data = inputfile:read(4)\n        size = bytes(data):u32be(1)\n        local filedata\n        if size > 0 then\n            filedata = inputfile:read(size)\n        end\n        readsize = readsize + 4 + size\n        if filepath then\n            vprint(\"extracting %s, %d bytes\", filepath, filedata and #filedata or 0)\n            if filedata then\n                io.writefile(path.join(outputdir, filepath), filedata, {encoding = \"binary\"})\n            else\n                os.touch(filepath)\n            end\n        end\n    end\n    inputfile:close()\nend\n\n-- decompress file\nfunction _decompress_file(archivefile, outputfile, opt)\n    lz4.decompress_file(archivefile, outputfile)\nend\n\n-- extract file\n--\n-- @param archivefile   the archive file. e.g. *.tar.gz, *.zip, *.7z, *.tar.bz2, ..\n-- @param outputdir     the output directory\n-- @param options       the options, e.g.. {excludes = {\"*/dir/*\", \"dir/*\"}}\n--\nfunction main(archivefile, outputdir, opt)\n    opt = opt or {}\n\n    local archivefile_tmp = os.tmpfile({ramdisk = false})\n    _decompress_file(archivefile, archivefile_tmp, opt)\n    _extract_files(archivefile_tmp, outputdir, opt)\n    os.tryrm(archivefile_tmp)\nend\n"
  },
  {
    "path": "xmake/modules/utils/archive/merge_staticlib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        merge_staticlib.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.binutils\")\nimport(\"private.tools.vstool\")\n\n-- merge *.a archive libraries using libtool\nfunction _merge_for_ar_libtool(target, program, outputfile, libraryfiles, opt)\n    os.vrunv(\"libtool\", table.join(\"-static\", \"-o\", outputfile, libraryfiles))\nend\n\n-- merge *.a archive libraries using fallback method (extract and repack)\n-- Used for platforms where ar does not support -M option (e.g., Solaris)\nfunction _merge_for_ar_fallback(target, program, outputfile, libraryfiles, opt)\n\n    -- extract all archives to the temporary directory\n    local tmpdir = os.tmpfile() .. \".dir\"\n    os.mkdir(tmpdir)\n    for _, libraryfile in ipairs(libraryfiles) do\n        binutils.extractlib(libraryfile, tmpdir)\n    end\n\n    -- collect all object files\n    local objectfiles = {}\n    for _, objectfile in ipairs(os.files(path.join(tmpdir, \"*.o\"))) do\n        table.insert(objectfiles, path.filename(objectfile))\n    end\n\n    -- create new archive with all object files\n    if #objectfiles > 0 then\n        os.mkdir(path.directory(outputfile))\n        local outputfile_abs = path.absolute(outputfile)\n        -- remove output file if exists to avoid appending\n        os.tryrm(outputfile_abs)\n        -- create new archive with -c (create) and -r (replace/insert)\n        -- use relative paths for object files since curdir = tmpdir\n        os.vrunv(program, table.join(\"-cr\", outputfile_abs, objectfiles), {curdir = tmpdir})\n    end\n    os.rm(tmpdir)\nend\n\n-- merge *.a archive libraries for GNU ar (using -M interactive mode)\nfunction _merge_for_ar_gnu(target, program, outputfile, libraryfiles, opt)\n    -- we can't generate directly to outputfile,\n    -- because on windows/ndk, llvm-ar.exe may fail to write with no permission, even though it's a writable temp file.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/1973\n    local archivefile = target.autogenfile and target:autogenfile((hash.uuid(outputfile):gsub(\"%-\", \"\"))) .. \".a\" or (os.tmpfile() .. \".a\")\n    os.mkdir(path.directory(archivefile))\n    local tmpfile = os.tmpfile()\n    local mrifile = io.open(tmpfile, \"w\")\n    mrifile:print(\"create %s\", archivefile)\n    for _, libraryfile in ipairs(libraryfiles) do\n        mrifile:print(\"addlib %s\", libraryfile)\n    end\n    mrifile:print(\"save\")\n    mrifile:print(\"end\")\n    mrifile:close()\n    os.vrunv(program, {\"-M\"}, {stdin = tmpfile})\n    os.cp(archivefile, outputfile)\n    os.rm(tmpfile)\n    os.rm(archivefile)\nend\n\n-- merge *.a archive libraries for ar\nfunction _merge_for_ar(target, program, outputfile, libraryfiles, opt)\n    opt = opt or {}\n    if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n        _merge_for_ar_libtool(target, program, outputfile, libraryfiles, opt)\n    elseif target:is_plat(\"solaris\") then\n        _merge_for_ar_fallback(target, program, outputfile, libraryfiles, opt)\n    else\n        _merge_for_ar_gnu(target, program, outputfile, libraryfiles, opt)\n    end\nend\n\n-- merge *.a archive libraries for msvc/lib.exe\nfunction _merge_for_msvclib(target, program, outputfile, libraryfiles, opt)\n    opt = opt or {}\n    vstool.runv(program, table.join(\"-nologo\", \"-out:\" .. outputfile, libraryfiles), {envs = opt.runenvs})\nend\n\n-- merge *.a archive libraries, @note target may be package.\nfunction main(target, outputfile, libraryfiles)\n    local program, toolname = target:tool(\"ar\")\n    if program and toolname then\n        if toolname:find(\"ar\") then\n            _merge_for_ar(target, program, outputfile, libraryfiles)\n        elseif toolname == \"link\" and target:is_plat(\"windows\") then\n            local msvc\n            for _, toolchain_inst in ipairs(target:toolchains()) do\n                if toolchain_inst:name() == \"msvc\" then\n                    msvc = toolchain_inst\n                    break\n                end\n            end\n            _merge_for_msvclib(target, (program:gsub(\"link%.exe\", \"lib.exe\")), outputfile, libraryfiles, {runenvs = msvc and msvc:runenvs()})\n        else\n            raise(\"cannot merge (%s): unknown ar tool %s!\", table.concat(libraryfiles, \", \"), toolname)\n        end\n    else\n        raise(\"cannot merge (%s): ar not found!\", table.concat(libraryfiles, \", \"))\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/binary/bin2c.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bin2c.lua\n--\n\n-- imports\nimport(\"core.base.bytes\")\nimport(\"core.base.binutils\")\n\nfunction _do_dump(binarydata, outputfile, opt)\n    local i = 0\n    local n = 147\n    local p = 0\n    local e = binarydata:size()\n    local line = nil\n    local linewidth = opt.linewidth or 32\n    local first = true\n    while p < e do\n        line = \"\"\n        if p + linewidth <= e then\n            for i = 0, linewidth - 1 do\n                if first then\n                    first = false\n                    line = line .. \" \"\n                else\n                    line = line .. \",\"\n                end\n                line = line .. string.format(\" 0x%02X\", binarydata[p + i + 1])\n            end\n            outputfile:print(line)\n            p = p + linewidth\n        elseif p < e then\n            local left = e - p\n            for i = 0, left - 1 do\n                if first then\n                    first = false\n                    line = line .. \" \"\n                else\n                    line = line .. \",\"\n                end\n                line = line .. string.format(\" 0x%02X\", binarydata[p + i + 1])\n            end\n            outputfile:print(line)\n            p = p + left\n        else\n            break\n        end\n    end\nend\n\nfunction main(binarypath, outputpath, opt)\n\n    -- init source directory and options\n    opt = opt or {}\n    binarypath = path.absolute(binarypath)\n    outputpath = path.absolute(outputpath)\n    assert(os.isfile(binarypath), \"%s not found!\", binarypath)\n\n    -- trace\n    print(\"generating code data file from %s ..\", binarypath)\n\n    -- optimize the default linewidth for reading large file\n    if not opt.linewidth then\n        local filesize = os.filesize(binarypath)\n        if filesize > 1024 * 1024 * 1024 then\n            opt.linewidth = 512\n        elseif filesize > 100 * 1024 * 1024 then\n            opt.linewidth = 256\n        elseif filesize > 10 * 1024 * 1024 then\n            opt.linewidth = 128\n        elseif filesize > 1024 * 1024 then\n            opt.linewidth = 64\n        else\n            opt.linewidth = 32\n        end\n    end\n\n    -- do dump\n    if binutils.bin2c then\n        binutils.bin2c(binarypath, outputpath, opt)\n    else\n        local binarydata = bytes(io.readfile(binarypath, {encoding = \"binary\"}))\n        local outputfile = io.open(outputpath, 'w')\n        if outputfile then\n            if not opt.nozeroend then\n                binarydata = binarydata .. bytes('\\0')\n            end\n            _do_dump(binarydata, outputfile, opt)\n            outputfile:close()\n        end\n    end\n\n    -- trace\n    cprint(\"${bright}%s generated!\", outputpath)\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/binary/bin2obj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        bin2obj.lua\n--\n\n-- imports\nimport(\"core.base.binutils\")\n\nfunction main(binarypath, outputpath, opt)\n    -- init source directory and options\n    opt = opt or {}\n    binarypath = path.absolute(binarypath)\n    outputpath = path.absolute(outputpath)\n    assert(os.isfile(binarypath), \"%s not found!\", binarypath)\n\n    -- get filename from binary path (with extension, dots replaced with underscores)\n    local filename = path.filename(binarypath)\n    -- replace dots with underscores for symbol name (e.g., data.bin -> data_bin)\n    local basename = filename:gsub(\"%.\", \"_\")\n    opt.basename = basename\n\n    -- validate format\n    local format = opt.format\n    if format then\n        format = format:lower()\n        if format ~= \"coff\" and format ~= \"elf\" and format ~= \"macho\" then\n            raise(\"bin2obj: unsupported format '%s' (supported: coff, elf, macho)\", format)\n        end\n    end\n\n    -- trace\n    print(\"converting binary file %s to %s object file %s ..\", binarypath, format or \"coff\", outputpath)\n\n    -- do conversion\n    binutils.bin2obj(binarypath, outputpath, opt)\n\n    -- generate concomitant object file for cosmocc\n    if opt.cosmocc then\n        local arch = opt.arch or \"x86_64\"\n        local arch_concomitant\n        local objectfile_concomitant\n        if arch == \"x86_64\" or arch == \"x64\" then\n            arch_concomitant = \"aarch64\"\n            objectfile_concomitant = path.join(path.directory(outputpath), \".aarch64\", path.filename(outputpath))\n        elseif arch == \"aarch64\" or arch == \"arm64\" then\n            arch_concomitant = \"x86_64\"\n            objectfile_concomitant = path.join(path.directory(outputpath), \".x86_64\", path.filename(outputpath))\n        end\n\n        if arch_concomitant and objectfile_concomitant then\n\n            -- clone options for concomitant\n            local opt_concomitant = table.clone(opt)\n            opt_concomitant.arch = arch_concomitant\n            opt_concomitant.cosmocc = false\n\n            -- trace\n            print(\"converting binary file %s to %s object file %s ..\", binarypath, format or \"coff\", objectfile_concomitant)\n\n            -- do conversion\n            os.mkdir(path.directory(objectfile_concomitant))\n            binutils.bin2obj(binarypath, objectfile_concomitant, opt_concomitant)\n        end\n    end\n\n    -- trace\n    cprint(\"${bright}%s generated!\", outputpath)\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/binary/deplibs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        deplibs.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.graph\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\nimport(\"utils.binary.rpath\", {alias = \"rpath_utils\"})\nimport(\"core.base.binutils\")\n\nfunction _get_depends_by_binutils(binaryfile, opt)\n    return binutils.deplibs(binaryfile)\nend\n\nfunction _get_depends_by_dumpbin(binaryfile, opt)\n    local depends\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    local cachekey = \"utils.binary.deplibs\"\n    local msvc = toolchain.load(\"msvc\", {plat = plat, arch = arch})\n    if msvc:check() then\n        local dumpbin = find_tool(\"dumpbin\", {cachekey = cachekey, envs = msvc:runenvs()})\n        if dumpbin then\n            local binarydir = path.directory(binaryfile)\n            local result = try { function () return os.iorunv(dumpbin.program, {\"/dependents\", \"/nologo\", binaryfile}) end }\n            if result then\n                for _, line in ipairs(result:split(\"\\n\")) do\n                    line = line:trim()\n                    if not line:startswith(\"Dump of file\") and line:endswith(\".dll\") then\n                        depends = depends or {}\n                        table.insert(depends, line)\n                    end\n                end\n            end\n        end\n    end\n    return depends\nend\n\nfunction _get_depends_by_objdump(binaryfile, opt)\n    local depends\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    local cachekey = \"utils.binary.deplibs\"\n    local objdump = find_tool(\"llvm-objdump\", {cachekey = cachekey}) or find_tool(\"objdump\", {cachekey = cachekey})\n    if objdump then\n        local binarydir = path.directory(binaryfile)\n        local argv = {\"-p\", binaryfile}\n        if plat == \"macosx\" or plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n            argv = {\"--macho\", \"--dylibs-used\", binaryfile}\n        end\n        local result = try { function () return os.iorunv(objdump.program, argv) end }\n        if result then\n            for _, line in ipairs(result:split(\"\\n\")) do\n                line = line:trim()\n                if not line:endswith(\":\") then\n                    if plat == \"windows\" or plat == \"mingw\" then\n                        if line:startswith(\"DLL Name:\") then\n                            local filename = line:split(\":\")[2]:trim()\n                            if filename:endswith(\".dll\") then\n                                depends = depends or {}\n                                table.insert(depends, filename)\n                            end\n                        end\n                    elseif plat == \"macosx\" or plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n                        local filename = line:match(\".-%.dylib\") or line:match(\".-%.framework\")\n                        if filename then\n                            depends = depends or {}\n                            table.insert(depends, filename)\n                        end\n                    else\n                        if line:startswith(\"NEEDED\") then\n                            local filename = line:split(\"%s+\")[2]\n                            if filename and filename:endswith(\".so\") or filename:find(\"%.so[%.%d+]+$\") then\n                                depends = depends or {}\n                                table.insert(depends, filename)\n                            end\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return depends\nend\n\n-- $ldd ./build/linux/x86_64/release/test\n--\tlinux-vdso.so.1 (0x00007ffc51fdd000)\n--\tlibfoo.so => /mnt/xmake/tests/projects/c/shared_library/./build/linux/x86_64/release/libfoo.so (0x00007fe241233000)\n--\tlibstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fe240fca000)\n--\tlibm.so.6 => /lib64/libm.so.6 (0x00007fe240ee7000)\n--\tlibgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fe240eba000)\n--\tlibc.so.6 => /lib64/libc.so.6 (0x00007fe240ccd000)\n--\t/lib64/ld-linux-x86-64.so.2 (0x00007fe24123a000)\n--\nfunction _get_depends_by_ldd(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" then\n        return\n    end\n    local depends\n    local cachekey = \"utils.binary.deplibs\"\n    local ldd = find_tool(\"ldd\", {cachekey = cachekey})\n    if ldd then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(ldd.program, {binaryfile}) end }\n        if result then\n            for _, line in ipairs(result:split(\"\\n\")) do\n                local splitinfo = line:split(\"=>\")\n                line = splitinfo[2]\n                if not line or line:find(\"not found\", 1, true) then\n                    line = splitinfo[1]\n                end\n                line = line:gsub(\"%(.+%)\", \"\"):trim()\n                local filename = line:match(\".-%.so$\") or line:match(\".-%.so[%.%d+]+$\")\n                if filename then\n                    depends = depends or {}\n                    table.insert(depends, filename:trim())\n                end\n            end\n        end\n    end\n    return depends\nend\n\n-- $ readelf -d build/linux/x86_64/release/test\n--\n-- Dynamic section at offset 0x2db8 contains 29 entries:\n--  Tag        Type                         Name/Value\n-- 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]\n-- 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN]\nfunction _get_depends_by_readelf(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return\n    end\n    local depends\n    local cachekey = \"utils.binary.deplibs\"\n    local readelf = find_tool(\"readelf\", {cachekey = cachekey})\n    if readelf then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(readelf.program, {\"-d\", binaryfile}) end }\n        if result then\n            for _, line in ipairs(result:split(\"\\n\")) do\n                if line:find(\"NEEDED\", 1, true) then\n                    local filename = line:match(\"Shared library: %[(.-)%]\")\n                    if filename then\n                        depends = depends or {}\n                        table.insert(depends, filename:trim())\n                    end\n                end\n            end\n        end\n    end\n    return depends\nend\n\n-- $ otool -L build/iphoneos/arm64/release/test\n-- build/iphoneos/arm64/release/test:\n--        @rpath/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0)\n--        /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 2048.1.101)\n--        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)\n--        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1600.151.0)\n--        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0)\n--\nfunction _get_depends_by_otool(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"macosx\" and plat ~= \"iphoneos\" and plat ~= \"appletvos\" and plat ~= \"watchos\" then\n        return\n    end\n    local depends\n    local cachekey = \"utils.binary.deplibs\"\n    local otool = find_tool(\"otool\", {cachekey = cachekey})\n    if otool then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(otool.program, {\"-L\", binaryfile}) end }\n        if result then\n            for _, line in ipairs(result:split(\"\\n\")) do\n                line = line:trim()\n                if not line:endswith(\":\") then\n                    local filename = line:match(\".-%.dylib\") or line:match(\".-%.framework\")\n                    if filename then\n                        depends = depends or {}\n                        table.insert(depends, filename:trim())\n                    end\n                end\n            end\n        end\n    end\n    return depends\nend\n\nfunction _get_depends(binaryfile, opt)\n    opt = opt or {}\n    local ops = {\n        _get_depends_by_objdump,\n        _get_depends_by_readelf,\n        _get_depends_by_binutils\n    }\n    if is_host(\"windows\") then\n        table.insert(ops, 1, _get_depends_by_dumpbin)\n    elseif is_host(\"linux\", \"bsd\") then\n        table.insert(ops, 1, _get_depends_by_ldd)\n    elseif is_host(\"macosx\") then\n        table.insert(ops, 1, _get_depends_by_otool)\n    end\n    for _, op in ipairs(ops) do\n        local depends = op(binaryfile, opt)\n        if depends then\n            return depends\n        end\n    end\nend\n\n-- resolve file path with @rpath, @loader_path, and $ORIGIN\nfunction _resolve_filepath(binaryfile, dependfile, opt)\n    local loaderfile = opt._loaderfile\n    local resolve_hint_paths = opt.resolve_hint_paths\n    local resolve_search_paths = opt.resolve_search_paths\n    local resolved = false\n\n    -- resolve path from rpath\n    if not resolved and dependfile:startswith(\"@rpath/\") then\n        local rpathlist = opt._rpathlist\n        if rpathlist == nil then\n            rpathlist = rpath_utils.list(loaderfile)\n            opt._rpathlist = rpathlist or false\n        end\n        if rpathlist then\n            for _, rpath in ipairs(rpathlist) do\n                local filepath = dependfile:replace(\"@rpath/\", rpath .. \"/\", {plain = true})\n                if os.isfile(filepath) then\n                    dependfile = path.absolute(filepath)\n                    resolved = true\n                    break\n                elseif filepath:startswith(\"@loader_path/\") then\n                    filepath = filepath:replace(\"@loader_path/\", path.directory(loaderfile) .. \"/\", {plain = true})\n                    if os.isfile(filepath) then\n                        dependfile = path.absolute(filepath)\n                        resolved = true\n                        break\n                    end\n                elseif filepath:startswith(\"$ORIGIN/\") then\n                    filepath = filepath:replace(\"$ORIGIN/\", path.directory(loaderfile) .. \"/\", {plain = true})\n                    if os.isfile(filepath) then\n                        dependfile = path.absolute(filepath)\n                        resolved = true\n                        break\n                    end\n                end\n            end\n        end\n    end\n\n    if not path.is_absolute(dependfile) then\n\n        -- resolve absolute path\n        if not resolved and os.isfile(dependfile) then\n            dependfile = path.absolute(dependfile)\n            resolved = true\n        end\n\n        -- resolve path from the hint paths\n        if not resolved and resolve_hint_paths then\n            local filename = path.filename(dependfile)\n            for _, filepath in ipairs(resolve_hint_paths) do\n                if filename == path.filename(filepath) then\n                    dependfile = path.absolute(filepath)\n                    resolved = true\n                    break\n                end\n            end\n        end\n\n        -- resolve path from the current loader directory on windows\n        if not resolved and is_host(\"windows\") then\n            local loaderdir = path.directory(loaderfile)\n            local filepath = path.join(loaderdir, dependfile)\n            if os.isfile(filepath) then\n                dependfile = path.absolute(filepath)\n                resolved = true\n            end\n        end\n\n        -- resolve path from the searth paths\n        if resolve_search_paths then\n            for _, searchdir in ipairs(resolve_search_paths) do\n                local filepath = path.join(searchdir, dependfile)\n                if os.isfile(filepath) then\n                    dependfile = path.absolute(filepath)\n                    resolved = true\n                end\n            end\n        end\n\n        -- resolve path from LD_LIBRARY_PATH, ...\n        local library_paths = is_host(\"macosx\") and os.getenv(\"DYLD_LIBRARY_PATH\") or os.getenv(\"LD_LIBRARY_PATH\")\n        if library_paths then\n            for _, searchdir in ipairs(path.splitenv(library_paths)) do\n                local filepath = path.join(searchdir, dependfile)\n                if os.isfile(filepath) then\n                    dependfile = path.absolute(filepath)\n                    resolved = true\n                end\n            end\n        end\n    end\n\n    dependfile = path.normalize(dependfile)\n    if binaryfile ~= dependfile then\n        return dependfile\n    end\nend\n\nfunction _get_plain_depends(binaryfile, opt)\n    opt = opt or {}\n    local depends = _get_depends(binaryfile, opt)\n    if depends and opt.resolve_path then\n        local result = {}\n        for _, dependfile in ipairs(depends) do\n            dependfile = _resolve_filepath(binaryfile, dependfile, opt)\n            if dependfile then\n                table.insert(result, dependfile)\n            end\n        end\n        depends = result\n    end\n    return depends\nend\n\nfunction _get_recursive_depends(binaryfile, dag, depends, opt)\n    local dependfiles = _get_plain_depends(binaryfile, opt)\n    if dependfiles then\n        for _, dependfile in ipairs(dependfiles) do\n            dag:add_edge(binaryfile, dependfile)\n            if not depends:has(dependfile) then\n                depends:insert(dependfile)\n                if os.isfile(dependfile) then\n                    _get_recursive_depends(dependfile, dag, depends, opt)\n                end\n            end\n        end\n    end\nend\n\n-- get the library dependencies of the give binary files\n--\n-- @param binaryfile the binary file\n-- @param opt        the option, e.g. {recursive = false, resolve_path = true, resolve_hint_paths = {}}\n--                      - plat, arch: the platform and architecture\n--                      - recursive: recursively get all sub-dependencies, sorted by topology\n--                      - resolve_path: try to resolve the file full path, e.g. @rpath, @loader_path, $ORIGIN, relative path ..\n--                      - resolve_hint_paths: we can resolve and match path from them\n--                      - resolve_search_paths: the search library paths, like: LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, ...\n--                      - check_cycle: check cycle deps\n--\nfunction main(binaryfile, opt)\n    opt = opt or {}\n    if opt.resolve_path then\n        opt._loaderfile = binaryfile\n    end\n    binaryfile = path.normalize(path.absolute(binaryfile))\n    if opt.recursive then\n        local dag = graph.new(true)\n        _get_recursive_depends(binaryfile, dag, hashset.new(), opt)\n        local depends, has_cycle = dag:topo_sort()\n        if has_cycle and opt.check_cycle then\n            local files = {}\n            local cycle = dag:find_cycle()\n            if cycle then\n                for _, file in ipairs(cycle) do\n                    table.insert(files, file)\n                end\n                table.insert(files, binaryfile)\n            end\n            raise(\"deplibs(%s): circular library dependencies detected!\\n%s\", binaryfile, table.concat(files, \"\\n   -> \"))\n        end\n        if depends and #depends > 1 then\n            return table.slice(depends, 2)\n        end\n    else\n        return _get_plain_depends(binaryfile, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/utils/binary/extractlib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        extractlib.lua\n--\n\n-- imports\nimport(\"core.base.binutils\")\n\n-- extract static library to directory\n--\n-- @param libraryfile   the static library file path (.a or .lib)\n-- @param outputdir     the output directory to extract object files\n-- @param opt           the options (optional)\n--                        - plain: extract all object files to the same directory (default: true)\n--\nfunction main(libraryfile, outputdir, opt)\n    -- init paths\n    libraryfile = path.absolute(libraryfile)\n    outputdir = path.absolute(outputdir)\n    assert(os.isfile(libraryfile), \"%s not found!\", libraryfile)\n\n    -- ensure output directory exists\n    if not os.isdir(outputdir) then\n        os.mkdir(outputdir)\n    end\n\n    -- trace\n    print(\"extracting static library %s to %s ..\", libraryfile, outputdir)\n\n    -- do extraction\n    binutils.extractlib(libraryfile, outputdir, opt)\n\n    -- trace\n    cprint(\"${bright}extraction completed!\")\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/binary/readsyms.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        readsyms.lua\n--\n\n-- imports\nimport(\"core.base.binutils\")\n\n-- get symbols from binary file (auto-detect format: ELF, COFF, Mach-O)\n--\n-- @param binaryfile  the binary file path (required)\n-- @return            the symbols table\nfunction _get_symbols(binaryfile)\n    assert(binaryfile, \"usage: xmake l utils.binary.readsyms <binaryfile>\")\n\n    binaryfile = path.absolute(binaryfile)\n    assert(os.isfile(binaryfile), \"%s not found!\", binaryfile)\n\n    return binutils.readsyms(binaryfile)\nend\n\n-- dump symbols to console\n--\n-- @param binaryfile  the object file path (required)\nfunction dump(binaryfile)\n    local objects = _get_symbols(binaryfile)\n    if objects and #objects > 0 then\n        for _, obj in ipairs(objects) do\n            local symbols = obj.symbols\n            if symbols and #symbols > 0 then\n                -- print object file\n                print(\"\")\n                cprint(\"${bright}Object: %s\", obj.objectfile)\n                print(string.rep(\"-\", 80))\n\n                -- calculate column widths for alignment\n                local max_name_len = 0\n                local max_type_len = 0\n\n                for i, sym in ipairs(symbols) do\n                    if sym.name then\n                        max_name_len = math.max(max_name_len, #sym.name)\n                    end\n                    if sym.type then\n                        max_type_len = math.max(max_type_len, #sym.type)\n                    end\n                end\n\n                -- calculate column widths\n                local type_width = math.max(max_type_len, 4)\n                local name_width = math.max(max_name_len, 4)\n\n                -- print header\n                local header_format = \"  %-\" .. type_width .. \"s  %s\"\n                print(string.format(header_format, \"TYPE\", \"NAME\"))\n\n                -- print symbols\n                local format_str = \"  %-\" .. type_width .. \"s  %s\"\n\n                for i, sym in ipairs(symbols) do\n                    local type_str = sym.type or \"unknown\"\n                    local name_str = sym.name or \"\"\n\n                    print(string.format(format_str, type_str, name_str))\n                end\n                print(\"\")\n                cprint(\"${bright}%d symbols found!\", #symbols)\n            end\n        end\n    else\n        print(\"\")\n        cprint(\"${bright}No symbols found!\")\n    end\nend\n\n-- read symbols from object file (auto-detect format: ELF, COFF, Mach-O)\n--\n-- @param binaryfile  the object file path (required)\n-- @return            the symbols table\nfunction main(binaryfile)\n    assert(binaryfile, \"usage: xmake l utils.binary.readsyms <binaryfile>\")\n    return _get_symbols(binaryfile)\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/binary/rpath.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rpath.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.binutils\")\nimport(\"lib.detect.find_tool\")\n\nfunction _replace_rpath_vars(rpath, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat == \"macosx\" or plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n        rpath = rpath:gsub(\"%$ORIGIN\", \"@loader_path\")\n    else\n        rpath = rpath:gsub(\"@loader_path\", \"$ORIGIN\")\n        rpath = rpath:gsub(\"@executable_path\", \"$ORIGIN\")\n    end\n    return rpath\nend\n\nfunction _get_rpath_list_by_binutils(binaryfile, opt)\n    return binutils.rpath_list(binaryfile)\nend\n\nfunction _get_rpath_list_by_objdump(binaryfile, opt)\n    local list\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    local cachekey = \"utils.binary.rpath\"\n    local objdump = find_tool(\"llvm-objdump\", {cachekey = cachekey}) or find_tool(\"objdump\", {cachekey = cachekey})\n    if objdump then\n        local binarydir = path.directory(binaryfile)\n        local argv = {\"-x\", binaryfile}\n        if plat == \"macosx\" or plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n            argv = {\"--macho\", \"-x\", binaryfile}\n        end\n        local result = try { function () return os.iorunv(objdump.program, argv) end }\n        if result then\n            local cmd = false\n            for _, line in ipairs(result:split(\"\\n\")) do\n                line = line:trim()\n                if plat == \"macosx\" or plat == \"iphoneos\" or plat == \"appletvos\" or plat == \"watchos\" then\n                    if not cmd and line:find(\"cmd LC_RPATH\", 1, true) then\n                        cmd = true\n                    elseif cmd and (line:find(\"cmd \", 1, true) or line:find(\"Load command\", 1, true)) then\n                        cmd = false\n                    end\n                    if cmd then\n                        local p = line:match(\"path (.-) %(\")\n                        if p then\n                            list = list or {}\n                            table.insert(list, p:trim())\n                        end\n                    end\n                else\n                    if line:startswith(\"RUNPATH\") or line:startswith(\"RPATH\") then\n                        local p = line:split(\"%s+\")[2]\n                        if p then\n                            list = list or {}\n                            table.join2(list, path.splitenv(p:trim()))\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return list\nend\n\n-- $ readelf -d build/linux/x86_64/release/test\n--\n-- Dynamic section at offset 0x2db8 contains 29 entries:\n--  Tag        Type                         Name/Value\n-- 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]\n-- 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]\n-- 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN]\n-- ...\n-- 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN]\nfunction _get_rpath_list_by_readelf(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return\n    end\n    local list\n    local cachekey = \"utils.binary.rpath\"\n    local readelf = find_tool(\"readelf\", {cachekey = cachekey})\n    if readelf then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(readelf.program, {\"-d\", binaryfile}) end }\n        if result then\n            for _, line in ipairs(result:split(\"\\n\")) do\n                if line:find(\"RUNPATH\", 1, true) then\n                    local p = line:match(\"Library runpath: %[(.-)%]\")\n                    if p then\n                        list = list or {}\n                        table.join2(list, path.splitenv(p:trim()))\n                    end\n                elseif line:find(\"RPATH\", 1, true) then\n                    local p = line:match(\"Library rpath: %[(.-)%]\")\n                    if p then\n                        list = list or {}\n                        table.join2(list, path.splitenv(p:trim()))\n                    end\n                end\n            end\n        end\n    end\n    return list\nend\n\n-- $ patchelf --print-rpath ./build/linux/x86_64/release/app\n-- $ORIGIN:xxx:bar\nfunction _get_rpath_list_by_patchelf(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return\n    end\n    local list\n    local cachekey = \"utils.binary.rpath\"\n    local patchelf = find_tool(\"patchelf\", {cachekey = cachekey})\n    if patchelf then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(patchelf.program, {\"--print-rpath\", binaryfile}) end }\n        if result then\n            result = result:trim()\n            if #result > 0 then\n                list = path.splitenv(result)\n            end\n        end\n    end\n    return list\nend\n\n\n-- $ otool -l build/iphoneos/arm64/release/test\n-- build/iphoneos/arm64/release/test:\n--          cmd LC_RPATH\n--      cmdsize 32\n--         path @loader_path (offset 12)\n--\nfunction _get_rpath_list_by_otool(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"macosx\" and plat ~= \"iphoneos\" and plat ~= \"appletvos\" and plat ~= \"watchos\" then\n        return\n    end\n    local list\n    local cachekey = \"utils.binary.rpath\"\n    local otool = find_tool(\"otool\", {cachekey = cachekey})\n    if otool then\n        local binarydir = path.directory(binaryfile)\n        local result = try { function () return os.iorunv(otool.program, {\"-l\", binaryfile}) end }\n        if result then\n            local cmd = false\n            for _, line in ipairs(result:split(\"\\n\")) do\n                if not cmd and line:find(\"cmd LC_RPATH\", 1, true) then\n                    cmd = true\n                elseif cmd and (line:find(\"cmd \", 1, true) or line:find(\"Load command\", 1, true)) then\n                    cmd = false\n                end\n                if cmd then\n                    local p = line:match(\"path (.-) %(\")\n                    if p then\n                        list = list or {}\n                        table.insert(list, p:trim())\n                    end\n                end\n            end\n        end\n    end\n    return list\nend\n\n-- patchelf --add-rpath binaryfile\nfunction _insert_rpath_by_patchelf(binaryfile, rpath, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return false\n    end\n    local ok = try { function ()\n        os.runv(\"patchelf\", {\"--add-rpath\", rpath, binaryfile})\n        return true\n    end }\n    return ok\nend\n\n-- install_name_tool -add_rpath <rpath> binaryfile\nfunction _insert_rpath_by_install_name_tool(binaryfile, rpath, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"macosx\" and plat ~= \"iphoneos\" and plat ~= \"appletvos\" and plat ~= \"watchos\" then\n        return false\n    end\n    local ok = try { function ()\n        os.vrunv(\"install_name_tool\", {\"-add_rpath\", rpath, binaryfile})\n        return true\n    end }\n    return ok\nend\n\n-- install_name_tool -rpath <rpath_old> <rpath_new> binaryfile\nfunction _change_rpath_by_install_name_tool(binaryfile, rpath_old, rpath_new, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"macosx\" and plat ~= \"iphoneos\" and plat ~= \"appletvos\" and plat ~= \"watchos\" then\n        return false\n    end\n    local ok = try { function ()\n        os.vrunv(\"install_name_tool\", {\"-rpath\", rpath_old, rpath_new, binaryfile})\n        return true\n    end }\n    return ok\nend\n\n-- use patchelf to remove the given rpath\nfunction _remove_rpath_by_patchelf(binaryfile, rpath, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return false\n    end\n    local ok = try { function ()\n        local result = os.iorunv(\"patchelf\", {\"--print-rpath\", binaryfile})\n        if result then\n            local rpaths_new = {}\n            local removed = false\n            for _, p in ipairs(path.splitenv(result:trim())) do\n                if p ~= rpath then\n                    table.insert(rpaths_new, p)\n                else\n                    removed = true\n                end\n            end\n            if removed then\n                if #rpaths_new > 0 then\n                    os.runv(\"patchelf\", {\"--set-rpath\", path.joinenv(rpaths_new), binaryfile})\n                else\n                    os.runv(\"patchelf\", {\"--remove-rpath\", binaryfile})\n                end\n            end\n        end\n        return true\n    end }\n    return ok\nend\n\n-- install_name_tool -delete_rpath <rpath> binaryfile\nfunction _remove_rpath_by_install_name_tool(binaryfile, rpath, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"macosx\" and plat ~= \"iphoneos\" and plat ~= \"appletvos\" and plat ~= \"watchos\" then\n        return false\n    end\n    local ok = try { function ()\n        os.vrunv(\"install_name_tool\", {\"-delete_rpath\", rpath, binaryfile})\n        return true\n    end }\n    return ok\nend\n\n-- patchelf --remove-rpath binaryfile\nfunction _clean_rpath_by_patchelf(binaryfile, opt)\n    local plat = opt.plat or os.host()\n    local arch = opt.arch or os.arch()\n    if plat ~= \"linux\" and plat ~= \"bsd\" and plat ~= \"android\" and plat ~= \"cross\" then\n        return false\n    end\n    local ok = try { function ()\n        os.runv(\"patchelf\", {\"--remove-rpath\", binaryfile})\n        return true\n    end }\n    return ok\nend\n\n\nfunction _clean_rpath_by_binutils(binaryfile, opt)\n    return binutils.rpath_clean(binaryfile)\nend\n\n-- get rpath list\nfunction list(binaryfile, opt)\n    opt = opt or {}\n    local ops = {\n        _get_rpath_list_by_objdump,\n        _get_rpath_list_by_readelf,\n        _get_rpath_list_by_patchelf,\n        _get_rpath_list_by_binutils\n    }\n    if is_host(\"macosx\") then\n        table.insert(ops, 1, _get_rpath_list_by_otool)\n    end\n    for _, op in ipairs(ops) do\n        local result = op(binaryfile, opt)\n        if result then\n            return result\n        end\n    end\nend\n\n-- insert rpath\nfunction insert(binaryfile, rpath, opt)\n    opt = opt or {}\n    local ops = {\n        _insert_rpath_by_patchelf,\n    }\n    if is_host(\"macosx\") then\n        table.insert(ops, 1, _insert_rpath_by_install_name_tool)\n    end\n    rpath = _replace_rpath_vars(rpath, opt)\n    local done = false\n    for _, op in ipairs(ops) do\n        if op(binaryfile, rpath, opt) then\n            done = true\n            break\n        end\n    end\n    if not done then\n        wprint(\"cannot insert rpath to %s, no rpath utility available, maybe we need to install patchelf\", binaryfile)\n    end\nend\n\n-- remove rpath\nfunction remove(binaryfile, rpath, opt)\n    opt = opt or {}\n    local ops = {\n        _remove_rpath_by_patchelf,\n    }\n    if is_host(\"macosx\") then\n        table.insert(ops, 1, _remove_rpath_by_install_name_tool)\n    end\n    rpath = _replace_rpath_vars(rpath, opt)\n    for _, op in ipairs(ops) do\n        if op(binaryfile, rpath, opt) then\n            break\n        end\n    end\nend\n\n-- change rpath\nfunction change(binaryfile, rpath_old, rpath_new, opt)\n    local function _change_rpath_by_generic(binaryfile, rpath_old, rpath_new, opt)\n        remove(binaryfile, rpath_old, opt)\n        insert(binaryfile, rpath_new, opt)\n        return true\n    end\n\n    opt = opt or {}\n    local ops = {\n        _change_rpath_by_generic\n    }\n    if is_host(\"macosx\") then\n        table.insert(ops, 1, _change_rpath_by_install_name_tool)\n    end\n    rpath_old = _replace_rpath_vars(rpath_old, opt)\n    rpath_new = _replace_rpath_vars(rpath_new, opt)\n    local done = false\n    for _, op in ipairs(ops) do\n        if op(binaryfile, rpath_old, rpath_new, opt) then\n            done = true\n            break\n        end\n    end\n    if not done then\n        wprint(\"cannot change rpath to %s, no rpath utility available, maybe we need to install patchelf\", binaryfile)\n    end\nend\n\n-- clean rpath\nfunction clean(binaryfile, opt)\n    local function _clean_rpath_by_generic(binaryfile, opt)\n        for _, rpath in ipairs(list(binaryfile, opt)) do\n            remove(binaryfile, rpath, opt)\n        end\n        return true\n    end\n\n    opt = opt or {}\n    local ops = {\n        _clean_rpath_by_patchelf,\n        _clean_rpath_by_binutils,\n        _clean_rpath_by_generic\n    }\n    local done = false\n    for _, op in ipairs(ops) do\n        if op(binaryfile, opt) then\n            done = true\n            break\n        end\n    end\n    if not done then\n        wprint(\"cannot clean rpath %s, no rpath utility available, maybe we need to install patchelf\", binaryfile)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/utils/ci/is_running.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        is_running.lua\n--\n\n-- is running on ci(travis/appveyor/...)?\nfunction main()\n    local on_ci = _g._ON_CI\n    if on_ci == nil then\n        local ci = (os.getenv(\"CI\") or os.getenv(\"GITHUB_ACTIONS\") or \"\"):lower()\n        if ci == \"true\" or ci == \"1\" then\n            on_ci = true\n        else\n            on_ci = false\n        end\n        _g._ON_CI = on_ci\n    end\n    return on_ci\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/ci/packageskey.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        packageskey.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"private.action.require.impl.package\")\nimport(\"private.action.require.impl.utils.get_requires\")\n\n-- generate a hash key of all packages to cache packages on github/ci\n--\n-- on windows.yml\n--\n-- - name: Retrieve dependencies hash\n--   id: packageskey\n--   run: echo \"::set-output name=hash::$(xmake l utils.ci.packageskey)\"\n\n-- Cache xmake dependencies\n-- - name: Retrieve cached xmake dependencies\n--   uses: actions/cache@v2\n--   with:\n--     path: ${{env.APPLOCALDATA}}\\.xmake\\packages\n--     key: ${{ steps.packageskey.outputs.hash }}\n--\nfunction main(requires_raw)\n\n    -- suppress all logs\n    option.save()\n    option.set(\"quiet\", true, {force = true})\n\n    -- get requires and extra config\n    local requires_extra = nil\n    local requires, requires_extra = get_requires(requires_raw)\n    if not requires or #requires == 0 then\n        return\n    end\n\n    -- get keys\n    local keys = {}\n    for _, instance in ipairs(package.load_packages(requires, {requires_extra = requires_extra})) do\n        table.insert(keys, instance:installdir()) -- contain name/version/buildhash\n    end\n    table.sort(keys)\n    keys = table.concat(keys, \",\")\n\n    option.restore()\n    print(hash.strhash128(keys))\nend\n\n\n"
  },
  {
    "path": "xmake/modules/utils/ipa/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"utils.ipa.package\", {alias = \"ipagen\"})\nimport(\"lib.detect.find_tool\")\n\n-- main entry\nfunction main (ipafile)\n\n    -- check\n    assert(os.exists(ipafile), \"%s not found!\", ipafile)\n\n    -- find ideviceinstaller\n    local ideviceinstaller = assert(find_tool(\"ideviceinstaller\"), \"ideviceinstaller not found!\")\n\n    -- is *.app directory? package it first\n    local istmp = false\n    if os.isdir(ipafile) then\n        local appdir = ipafile\n        ipafile = os.tmpfile() .. \".ipa\"\n        ipagen(appdir, ipafile)\n        istmp = true\n    end\n\n    -- do install\n    os.vrunv(ideviceinstaller.program, {\"-i\", ipafile})\n    if istmp then\n        os.tryrm(ipafile)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/ipa/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\n\n-- main entry\nfunction main (appdir, ipafile, iconfile)\n\n    -- check\n    assert(appdir)\n    assert(os.isdir(appdir), \"%s not found!\", appdir)\n\n    -- find zip\n    local zip = find_tool(\"zip\")\n    assert(zip, \"zip not found!\")\n\n    -- get the .ipa file path\n    local appname = path.basename(appdir)\n    if not ipafile then\n        ipafile = path.join(path.directory(appdir), appname .. \".ipa\")\n    end\n    ipafile = path.absolute(ipafile)\n\n    -- remove the old ipafile first\n    os.tryrm(ipafile)\n\n    -- the temporary directory\n    local tmpdir = path.join(os.tmpdir(), \"ipagen\", appname)\n\n    -- clean the tmpdir first\n    os.rm(tmpdir)\n\n    -- make the payload directory\n    os.mkdir(path.join(tmpdir, \"Payload\"))\n\n    -- copy the .app directory into payload\n    os.vcp(appdir, path.join(tmpdir, \"Payload\"))\n\n    -- copy icon file to iTunesArtwork\n    if iconfile then\n        os.vcp(iconfile, path.join(tmpdir, \"iTunesArtwork\"))\n    end\n\n    -- generate .ipa file\n    local argv = {\"-r\", ipafile, \"Payload\"}\n    if iconfile then\n        table.insert(argv, \"iTunesArtwork\")\n    end\n    local oldir = os.cd(tmpdir)\n    os.vrunv(zip.program, argv)\n    os.cd(oldir)\n\n    -- remove the temporary directory\n    os.rm(tmpdir)\n\n    -- check\n    assert(os.isfile(ipafile), \"generate %s failed!\", ipafile)\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/ipa/resign.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        resign.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_directory\")\nimport(\"utils.archive.extract\")\nimport(\"private.tools.codesign\")\nimport(\"utils.ipa.package\", {alias = \"ipagen\"})\n\n-- resign *.app directory\nfunction _resign_app(appdir, codesign_identity, mobile_provision, bundle_identifier)\n\n    -- get default codesign identity\n    if not codesign_identity then\n        for identity, _ in pairs(codesign.codesign_identities()) do\n            codesign_identity = identity\n            break\n        end\n    end\n\n    -- get default mobile provision\n    if not mobile_provision then\n        for provision, _ in pairs(codesign.mobile_provisions()) do\n            mobile_provision = provision\n            break\n        end\n    end\n\n    -- generate embedded.mobileprovision to *.app/embedded.mobileprovision\n    local mobile_provision_embedded = path.join(appdir, \"embedded.mobileprovision\")\n    if mobile_provision then\n        os.tryrm(mobile_provision_embedded)\n        local provisions = codesign.mobile_provisions()\n        if provisions then\n            local mobile_provision_data = provisions[mobile_provision]\n            if mobile_provision_data then\n                io.writefile(mobile_provision_embedded, mobile_provision_data)\n            end\n        end\n    end\n\n    -- replace bundle identifier of Info.plist\n    if bundle_identifier then\n        local info_plist_file = path.join(appdir, \"Info.plist\")\n        if os.isfile(info_plist_file) then\n            local info_plist_data = io.readfile(info_plist_file)\n            if info_plist_data then\n                local p = info_plist_data:find(\"<key>CFBundleIdentifier</key>\", 1, true)\n                if p then\n                    local e = info_plist_data:find(\"</string>\", p, true)\n                    if e then\n                        local block = info_plist_data:sub(p, e + 9):match(\"<string>(.+)</string>\")\n                        if block then\n                            info_plist_data = info_plist_data:gsub(block, bundle_identifier)\n                            io.writefile(info_plist_file, info_plist_data)\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- do codesign\n    codesign(appdir, codesign_identity, mobile_provision)\nend\n\n-- resign *.ipa file\nfunction _resign_ipa(ipafile, codesign_identity, mobile_provision, bundle_identifier)\n\n    -- get resigned ipa file\n    local ipafile_resigned = path.join(path.directory(ipafile), path.basename(ipafile) .. \"_resign\" .. path.extension(ipafile))\n\n    -- extract *.ipa file\n    local appdir = os.tmpfile() .. \".app\"\n    extract(ipafile, appdir, {extension = \".zip\"})\n\n    -- find real *.app directory\n    local appdir_real = find_directory(\"**.app\", appdir)\n    if not appdir_real then\n        appdir_real = appdir\n    end\n\n    -- resign *.app directory\n    _resign_app(appdir_real, codesign_identity, mobile_provision, bundle_identifier)\n\n    -- re-generate *.ipa file\n    ipagen(appdir_real, ipafile_resigned)\n\n    -- remove tmp files\n    os.tryrm(appdir)\n\n    -- trace\n    cprint(\"output: ${bright}%s\", ipafile_resigned)\nend\n\n-- main entry\nfunction main (filepath, codesign_identity, mobile_provision, bundle_identifier)\n\n    -- check\n    assert(os.exists(filepath), \"%s not found!\", filepath)\n\n    -- resign *.ipa or *.app application\n    if os.isfile(filepath) then\n        _resign_ipa(filepath, codesign_identity, mobile_provision, bundle_identifier)\n    else\n        _resign_app(filepath, codesign_identity, mobile_provision, bundle_identifier)\n    end\n\n    -- ok\n    cprint(\"${color.success}resign ok!\")\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/platform/gnu2mslib.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        gnu2mslib.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_tool\")\n\n-- get .def file path from gnulib\nfunction _get_defpath_from_gnulib(gnulib, msvc)\n\n    -- check\n    assert(os.isfile(gnulib), \"%s not found!\", gnulib)\n\n    -- get dumpbin.exe\n    local dumpbin = assert(find_tool(\"dumpbin\", {envs = msvc:runenvs()}), \"gnu2mslib(): dumpbin.exe not found!\")\n\n    -- get symbols\n    local symbols_exported = hashset.new()\n    local symbols = try {function() return os.iorunv(dumpbin.program, {\"/linkermember\", gnulib}) end}\n    if symbols then\n        local symbols_count\n        local symbols_index = 0\n        for _, line in ipairs(symbols:split('\\n', {plain = true})) do\n            if symbols_count == nil then\n                symbols_count = line:match(\"(%d+) public symbols\")\n                if symbols_count then\n                    symbols_count = tonumber(symbols_count)\n                end\n            else\n                local symbol = line:match(\"%s+[%dABCDEF]+%s+(.+)\")\n                if symbol then\n                    if not symbol:startswith(\"__\") and not symbol:startswith(\"?\") then\n                        symbols_exported:insert(symbol)\n                    end\n                    symbols_index = symbols_index + 1\n                    if symbols_index >= symbols_count then\n                        break\n                    end\n                end\n            end\n        end\n    end\n\n    -- generate .def file\n    if symbols_exported:size() > 0 then\n        local defpath = os.tmpfile() .. \".def\"\n        local file = io.open(defpath, \"w\")\n        file:print(\"EXPORTS\")\n        for _, symbol in ipairs(symbols_exported) do\n            file:print(\"%s\", symbol)\n        end\n        file:close()\n        return defpath\n    end\nend\n\n-- convert mingw/gnu xxx.dll.a to msvc xxx.lib\n--\n-- gnu2mslib(mslib, gnulib_or_defpath, {arch = \"x64\", dllname = \"foo.dll\"}\n--\n-- @see https://github.com/xmake-io/xmake/issues/1181\n--\nfunction main(mslib, gnulib_or_defpath, opt)\n\n    -- check\n    opt = opt or {}\n    assert(is_host(\"windows\"), \"we can only run gnu2mslib() on windows!\")\n    assert(mslib and gnulib_or_defpath, \"invalid input parameters, usage: gnu2mslib(mslib, gnulib_or_defpath, {arch = \\\"x64\\\", dllname = \\\"foo.dll\\\"})\")\n\n    -- get msvc toolchain\n    local msvc = toolchain.load(\"msvc\", {plat = opt.plat, arch = opt.arch})\n    if not msvc:check() then\n        raise(\"we can not get msvc toolchain!\")\n    end\n\n    -- get lib.exe\n    local libtool = assert(find_tool(\"lib\", {envs = msvc:runenvs()}), \"gnu2mslib(): lib.exe not found!\")\n\n    -- get dll name\n    local dllname = opt.dllname or path.basename(mslib) .. \".dll\"\n\n    -- get def file path\n    local defpath = gnulib_or_defpath:endswith(\".def\") and gnulib_or_defpath or _get_defpath_from_gnulib(gnulib_or_defpath, msvc)\n    assert(defpath and os.isfile(defpath), \"gnu2mslib(): convert failed, cannot get .def file!\")\n\n    -- generate mslib from gnulib\n    os.vrunv(libtool.program, {\"/machine:\" .. opt.arch, \"/def:\" .. defpath, \"/name:\" .. path.filename(dllname), \"/out:\" .. mslib}, {envs = msvc:runenvs()})\n\n    -- remove temporary .def file\n    if not gnulib_or_defpath:endswith(\".def\") then\n        os.rm(defpath)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/utils/progress.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        progress.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.colors\")\nimport(\"core.base.tty\")\nimport(\"core.base.scheduler\")\nimport(\"core.theme.theme\")\nimport(\"core.project.project\")\n\n-- cache color strings\nlocal COLOR_SUPERSLOW = \"${color.build.progress_superslow}\"\nlocal COLOR_VERYSLOW = \"${color.build.progress_veryslow}\"\nlocal COLOR_SLOW = \"${color.build.progress_slow}\"\n\n-- is scroll output?\nfunction _is_scroll()\n    -- if style is forced, use it\n    if _g.forced_style then\n        return _g.forced_style == \"scroll\"\n    end\n    local is_scroll = _g.is_scroll\n    if is_scroll == nil then\n        local style = project.policy(\"build.progress_style\") or theme.get(\"text.build.progress_style\") or \"scroll\"\n        if style == \"scroll\" then\n            is_scroll = true\n        end\n        _g.is_scroll = is_scroll\n    end\n    return is_scroll\nend\n\n-- is multi-row refresh output?\nfunction _is_multirow_refresh()\n    -- if style is forced, use it\n    if _g.forced_style then\n        return _g.forced_style == \"multirow\"\n    end\n    local is_multirow_refresh = _g.is_multirow_refresh\n    if is_multirow_refresh == nil then\n        local style = project.policy(\"build.progress_style\") or theme.get(\"text.build.progress_style\")\n        if style == \"multirow\" and tty.has_vtansi() and io.isatty() then\n            is_multirow_refresh = true\n        end\n        _g.is_multirow_refresh = is_multirow_refresh\n    end\n    return is_multirow_refresh\nend\n\n-- is single-row refresh output?\nfunction _is_singlerow_refresh()\n    -- if style is forced, use it\n    if _g.forced_style then\n        return _g.forced_style == \"singlerow\"\n    end\n    local is_singlerow_refresh = _g.is_singlerow_refresh\n    if is_singlerow_refresh == nil then\n        local style = project.policy(\"build.progress_style\") or theme.get(\"text.build.progress_style\")\n        if style == \"singlerow\" and tty.has_vtansi() and io.isatty() then\n            is_singlerow_refresh = true\n        end\n        _g.is_singlerow_refresh = is_singlerow_refresh\n    end\n    return is_singlerow_refresh\nend\n\n-- set progress style (temporarily override the current style)\n-- @param style \"scroll\", \"singlerow\", or \"multirow\"\nfunction set_style(style)\n    -- save the original style if not already saved\n    if not _g.saved_style then\n        -- get current effective style\n        if _is_multirow_refresh() then\n            _g.saved_style = \"multirow\"\n        elseif _is_singlerow_refresh() then\n            _g.saved_style = \"singlerow\"\n        else\n            _g.saved_style = \"scroll\"\n        end\n    end\n    \n    -- set forced style\n    _g.forced_style = style\n    -- clear cached flags to force recalculation\n    _g.is_scroll = nil\n    _g.is_multirow_refresh = nil\n    _g.is_singlerow_refresh = nil\nend\n\n-- restore progress style (restore the original style from project policy)\nfunction restore_style()\n    _g.forced_style = nil\n    _g.saved_style = nil\n    -- clear cached flags to force recalculation\n    _g.is_scroll = nil\n    _g.is_multirow_refresh = nil\n    _g.is_singlerow_refresh = nil\nend\n\n-- get progress prefix\nfunction _get_progress_prefix()\n    if not _g.progress_prefix then\n        _g.progress_prefix = \"${color.build.progress}\" .. theme.get(\"text.build.progress_format\") .. \":${clear} \"\n    end\n    return _g.progress_prefix\nend\n\n-- strip progress line\nfunction _strip_progress_line(msg, maxwidth)\n    local msg_plain = colors.translate(msg, {plain = true})\n    if #msg_plain > maxwidth then\n        -- windows width is too small? strip the partial message in middle\n        local partlen = math.floor(maxwidth / 2) - 3\n        local sep = msg_plain:sub(partlen + 1, #msg_plain - partlen - 1)\n        local split = msg:split(sep, {plain = true, strict = true})\n        msg = table.concat(split, \"...\")\n    end\n    return msg\nend\n\n-- show progress with verbose information\nfunction _show_progress_with_verbose(progress, format, ...)\n    cprint(_get_progress_prefix() .. \"${dim}\" .. format, progress, ...)\nend\n\n-- show progress with scroll\nfunction _show_progress_with_scroll(progress, format, ...)\n    cprint(_get_progress_prefix() .. format, progress, ...)\nend\n\n-- build ordered subprocess line infos from progress_lineinfos (internal helper)\nfunction _build_ordered_subprocess_lineinfos(maxwidth, current_time)\n    local progress_lineinfos = _g.progress_lineinfos\n    if not progress_lineinfos then\n        return {}\n    end\n\n    local order_lineinfos = {}\n    for _, progress_lineinfo in pairs(progress_lineinfos) do\n        local progress_msg = progress_lineinfo.progress_msg\n        if progress_msg then\n            local spent_time = current_time - progress_lineinfo.start_time\n            local time_seconds = spent_time / 1000\n\n            -- determine color based on time (use cached color constants)\n            local timecolor\n            if spent_time > 30000 then\n                timecolor = COLOR_SUPERSLOW\n            elseif spent_time > 1000 then\n                timecolor = COLOR_VERYSLOW\n            elseif spent_time > 500 then\n                timecolor = COLOR_SLOW\n            else\n                timecolor = \"\"\n            end\n\n            progress_lineinfo.spent_time = spent_time\n            -- use string.format instead of vformat for better performance\n            local time_str = string.format(\"%s%0.02fs${clear} \", timecolor, time_seconds)\n            local subprogress_line = _strip_progress_line(\"  > \" .. time_str .. progress_msg, maxwidth)\n            progress_lineinfo.progress_line = subprogress_line\n            table.insert(order_lineinfos, progress_lineinfo)\n        else\n            progress_lineinfo.spent_time = 0\n            progress_lineinfo.progress_line = nil\n        end\n    end\n\n    table.sort(order_lineinfos, function (a, b) return a.spent_time > b.spent_time end)\n    return order_lineinfos\nend\n\n-- display subprocess progress lines (internal helper)\nfunction _display_subprocess_lines(order_lineinfos)\n    local linecount = 0\n    for _, lineinfo in ipairs(order_lineinfos) do\n        -- we need not show it if the progress job is idle in runjobs now\n        local progress_running = lineinfo.running\n        if progress_running and progress_running:data(\"runjobs.running\") == false then\n            lineinfo.progress_line = nil\n        end\n        if lineinfo.progress_line then\n            tty.erase_line().cr()\n            cprint(lineinfo.progress_line)\n            linecount = linecount + 1\n        end\n    end\n    -- clear the left lines\n    local left_linecount = #order_lineinfos - linecount\n    if left_linecount > 0 then\n        for i = 1, left_linecount do\n            tty.erase_line().cr()\n            print(\"\")\n        end\n        tty.cursor_move_up(left_linecount)\n    end\n    _g.linecount = linecount\nend\n\n-- redraw the multirow progress area (internal helper)\n-- @param maxwidth: window width\n-- @param current_time: optional current time (to avoid repeated os.mclock() calls)\nfunction _redraw_multirow_progress(maxwidth, current_time)\n    local last_total_progress = _g.last_total_progress\n    if not last_total_progress then\n        return\n    end\n\n    -- redraw the total progress line\n    tty.erase_line().cr()\n    cprint(last_total_progress)\n\n    -- build and display the subprocess lines\n    if not current_time then\n        current_time = os.mclock()\n    end\n    local order_lineinfos = _build_ordered_subprocess_lineinfos(maxwidth, current_time)\n    _display_subprocess_lines(order_lineinfos)\n    io.flush()\nend\n\n-- show progress with multi-row refresh\n-- @see https://github.com/xmake-io/xmake/issues/6805\nfunction _show_progress_with_multirow_refresh(progress, format, ...)\n    local running = scheduler.co_running()\n    if not running then\n        _show_progress_with_scroll(progress, format, ...)\n        return\n    end\n\n    -- get window size and time once\n    local maxwidth = os.getwinsize().width\n    local current_time = os.mclock()\n\n    -- get progress line\n    local is_first = false\n    local is_finished = math.floor(progress) == 100\n    local progress_msg = vformat(format, ...)\n    local progress_line = _strip_progress_line(string.format(_get_progress_prefix(), progress) .. progress_msg, maxwidth)\n\n    local progress_lineinfos = _g.progress_lineinfos\n    if progress_lineinfos == nil then\n        progress_lineinfos = {}\n        _g.progress_lineinfos = progress_lineinfos\n        is_first = true\n    end\n    if is_first then\n        tty.cursor_hide()\n        os.atexit(function (ok, errors)\n            tty.cursor_show()\n        end)\n    end\n\n    -- show the total progress line\n    local linecount = _g.linecount or 0\n    if not is_first and linecount > 0 then\n        tty.cursor_move_up(linecount + 1)\n    end\n    tty.erase_line().cr()\n    cprint(progress_line)\n\n    -- save the total progress line and progress value for potential redraw in show_output\n    _g.last_total_progress = progress_line\n    _g.last_total_progress_value = progress\n    _g.last_show_time = current_time\n\n    -- update the current progress info\n    local current_lineinfo = progress_lineinfos[running]\n    if current_lineinfo == nil then\n        current_lineinfo = {spent_time = 0, running = running}\n        progress_lineinfos[running] = current_lineinfo\n    end\n    if is_finished then\n        current_lineinfo.progress_msg = nil\n    else\n        current_lineinfo.progress_msg = progress_msg\n        current_lineinfo.start_time = current_time\n    end\n\n    -- build and display the subprocess lines\n    if not is_finished then\n        local order_lineinfos = _build_ordered_subprocess_lineinfos(maxwidth, current_time)\n        _display_subprocess_lines(order_lineinfos)\n        _g.refresh_mode = \"multirow\"\n    else\n        -- when finished, clear all subprocess lines without leaving empty lines\n        local old_linecount = _g.linecount or 0\n        if old_linecount > 0 then\n            tty.erase_down()\n        end\n        _g.refresh_mode = nil\n        _g.progress_lineinfos = nil\n        _g.last_total_progress = nil\n        _g.last_total_progress_value = nil\n        _g.linecount = 0\n        tty.cursor_show()\n    end\n    io.flush()\nend\n\n-- show progress with single-row refresh (ninja style)\nfunction _show_progress_with_singlerow_refresh(progress, format, ...)\n    local maxwidth = os.getwinsize().width\n    local is_finished = math.floor(progress) == 100\n    local progress_msg = vformat(format, ...)\n    local progress_line = _strip_progress_line(string.format(_get_progress_prefix(), progress) .. progress_msg, maxwidth)\n    tty.erase_line().cr()\n    cprintf(progress_line)\n    if is_finished then\n        print(\"\")\n        _g.refresh_mode = nil\n    else\n        _g.refresh_mode = \"singlerow\"\n    end\n    io.flush()\nend\n\n-- show the current coroutine's progress line (internal helper for multirow mode)\nfunction _show_current_coroutine_progress(maxwidth)\n    local progress_lineinfos = _g.progress_lineinfos\n    if progress_lineinfos then\n        local running = scheduler.co_running()\n        if running then\n            local current_lineinfo = progress_lineinfos[running]\n            if current_lineinfo and current_lineinfo.progress_msg then\n                local progress_value = _g.last_total_progress_value or 0\n                local progress_line = _strip_progress_line(string.format(_get_progress_prefix(), math.floor(progress_value)) .. current_lineinfo.progress_msg, maxwidth)\n                tty.erase_line_to_end()\n                cprint(progress_line)\n            end\n        end\n    end\nend\n\n-- is show target enabled?\nfunction _is_show_target_enabled()\n    local show_target = _g.show_target\n    if show_target == nil then\n        local policy_value = project.policy(\"build.progress_show_target\")\n        if policy_value == nil then\n            show_target = true\n        else\n            show_target = policy_value\n        end\n        _g.show_target = show_target\n    end\n    return show_target\nend\n\n-- get target name prefix from progress object\nfunction _get_target_name_prefix(progress)\n    if type(progress) == \"table\" and progress.get then\n        local target_name = progress:get(\"target_name\")\n        if target_name and _is_show_target_enabled() then\n            return \"${color.build.target}<\" .. target_name .. \">${clear} \"\n        end\n    end\nend\n\n-- set the associated target name for the progress object (coroutine-local)\n-- it's safe to call with non-table progress (e.g. number), it will be ignored\nfunction set_target(progress, target)\n    if _is_show_target_enabled() and type(progress) == \"table\" and progress.set then\n        progress:set(\"target_name\", target:fullname())\n    end\nend\n\n-- show the message with progress\nfunction show(progress, format, ...)\n    local target_prefix = _get_target_name_prefix(progress)\n    if target_prefix then\n        format = target_prefix .. format\n    end\n    progress = type(progress) == \"table\" and progress:percent() or math.floor(progress)\n    if option.get(\"verbose\") then\n        _show_progress_with_verbose(progress, format, ...)\n    elseif _is_scroll() then\n        _show_progress_with_scroll(progress, format, ...)\n    elseif _is_multirow_refresh() then\n        _show_progress_with_multirow_refresh(progress, format, ...)\n    elseif _is_singlerow_refresh() then\n        _show_progress_with_singlerow_refresh(progress, format, ...)\n    else\n        _show_progress_with_scroll(progress, format, ...)\n    end\nend\n\n-- print additional output logs with colors outside the progress log area, such as warning logs.\n-- it's used when the progress style is multirow/singlerow refresh.\nfunction show_output(format, ...)\n    local refresh_mode = _g.refresh_mode\n    if refresh_mode == \"singlerow\" then\n        print(\"\")\n        cprint(format, ...)\n    elseif refresh_mode == \"multirow\" then\n        -- get window size once and the number of fixed progress lines at the bottom\n        -- +1 for the total progress line\n        local maxwidth = os.getwinsize().width\n        local linecount = (_g.linecount or 0) + 1\n\n        -- move to the top of progress area and clear to bottom\n        tty.cursor_move_up(linecount)\n        tty.erase_down()\n        tty.cr()\n\n        -- show the current task's progress line before the log output\n        _show_current_coroutine_progress(maxwidth)\n\n        -- print the log output, which will scroll naturally\n        cprint(format, ...)\n\n        -- redraw the progress area immediately\n        _redraw_multirow_progress(maxwidth)\n    else\n        cprint(format, ...)\n    end\nend\n\n-- check if multirow refresh mode is enabled\nfunction is_multirow()\n    return _is_multirow_refresh()\nend\n\n-- refresh the multirow progress display to update elapsed time\n-- this is useful for long-running tasks to keep the elapsed time updated\nfunction refresh()\n    local refresh_mode = _g.refresh_mode\n    if refresh_mode == \"multirow\" then\n        -- get current time once and reuse it\n        local current_time = os.mclock()\n        \n        -- only refresh if more than 500ms has passed since last show\n        -- this avoids too frequent refreshes\n        local last_show_time = _g.last_show_time\n        if last_show_time then\n            local elapsed = current_time - last_show_time\n            if elapsed <= 500 then\n                return\n            end\n        end\n\n        -- move cursor back to the top of progress area to avoid scrolling\n        local linecount = _g.linecount or 0\n        if linecount > 0 then\n            tty.cursor_move_up(linecount + 1)\n        end\n\n        -- redraw the progress area immediately, passing current_time to avoid repeated calls\n        local maxwidth = os.getwinsize().width\n        _redraw_multirow_progress(maxwidth, current_time)\n    end\nend\n\n-- abort the progress display mode, used for error exit or early termination\n-- this function cleans up the progress display area and restores the terminal state\nfunction show_abort()\n    local refresh_mode = _g.refresh_mode\n    if refresh_mode == \"multirow\" then\n        -- move to the top of progress area and clear\n        local linecount = (_g.linecount or 0) + 1\n        if linecount > 0 then\n            tty.cursor_move_up(linecount)\n            tty.erase_down()\n            tty.cr()\n        end\n\n        -- show the current coroutine's progress line before abort\n        local maxwidth = os.getwinsize().width\n        _show_current_coroutine_progress(maxwidth)\n        tty.cursor_show()\n\n        -- reset all global states\n        _g.refresh_mode = nil\n        _g.progress_lineinfos = nil\n        _g.last_total_progress = nil\n        _g.last_total_progress_value = nil\n        _g.linecount = 0\n        io.flush()\n    elseif refresh_mode == \"singlerow\" then\n        -- clear the current progress line and move to next line\n        print(\"\")\n        _g.refresh_mode = nil\n        io.flush()\n    end\nend\n\n-- get the message text with progress\nfunction text(progress, format, ...)\n    local target_prefix = _get_target_name_prefix(progress)\n    if target_prefix then\n        format = target_prefix .. format\n    end\n    progress = type(progress) == \"table\" and progress:percent() or math.floor(progress)\n    local progress_prefix = _get_progress_prefix()\n    if option.get(\"verbose\") then\n        return string.format(progress_prefix .. \"${dim}\" .. format, progress, ...)\n    else\n        return string.format(progress_prefix .. format, progress, ...)\n    end\nend\n\n"
  },
  {
    "path": "xmake/modules/utils/run_script.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        run.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.thread\")\nimport(\"core.sandbox.module\")\n\n-- print verbose log\nfunction _print_vlog(script_type, script_name, args, opt)\n    if not opt.verbose then\n        return\n    end\n    cprintf(\"running %s ${underline}%s${reset}\", script_type, script_name)\n    if args.n > 0 then\n        print(\" with args:\")\n        if not opt.diagnosis then\n            for i = 1, args.n do\n                print(\"  - \" .. todisplay(args[i]))\n            end\n        else\n            utils.dump(table.unpack(args, 1, args.n))\n        end\n    else\n        print(\".\")\n    end\nend\n\nfunction _is_callable(func)\n    if type(func) == \"function\" then\n        return true\n    elseif type(func) == \"table\" then\n        local meta = debug.getmetatable(func)\n        if meta and meta.__call then\n            return true\n        end\n    end\nend\n\nfunction _run_script(script, args, opt)\n\n    local func\n    local printresult = false\n    local script_type, script_name\n\n    -- import and run script\n    if path.extension(script) == \".lua\" and os.isfile(script) then\n\n        -- run the given lua script file (xmake lua /tmp/script.lua)\n        script_type, script_name = \"given lua script file\", path.relative(script)\n        func = import(path.basename(script), {rootdir = path.directory(script), anonymous = true})\n    elseif os.isfile(path.join(os.programdir(), \"plugins\", \"lua\", \"scripts\", script .. \".lua\")) then\n\n        -- run builtin lua script (xmake lua echo \"hello xmake\")\n        script_type, script_name = \"builtin lua script\", script\n        func = import(\"scripts.\" .. script, {anonymous = true, rootdir = path.join(os.programdir(), \"plugins\", \"lua\")})\n    else\n\n        -- attempt to find the builtin module\n        local object = nil\n        for _, name in ipairs(script:split(\"%.\")) do\n            object = object and object[name] or module.get(name)\n            if not object then\n                break\n            end\n        end\n        if object then\n            -- run builtin modules (xmake lua core.xxx.xxx)\n            script_type, script_name = \"builtin module\", script\n            func = object\n        else\n            -- run imported modules (xmake lua core.xxx.xxx)\n            script_type, script_name = \"imported module\", script\n            func = import(script, {anonymous = true})\n        end\n        printresult = true\n    end\n\n    -- print verbose log\n    _print_vlog(script_type or \"script\", script_name or \"\", args, opt)\n\n    -- dump func() result\n    if _is_callable(func) then\n        local result = table.pack(func(table.unpack(args, 1, args.n)))\n        if printresult and result and result.n ~= 0 then\n            utils.dump(table.unpack(result, 1, result.n))\n        end\n    else\n        -- dump variables directly\n        utils.dump(func)\n    end\nend\n\nfunction _run_commanad(command, args, opt)\n    local tmpfile = os.tmpfile() .. \".lua\"\n    io.writefile(tmpfile, \"function main(...)\\n\" .. command .. \"\\nend\")\n    _run_script(tmpfile, args, opt)\nend\n\nfunction _get_args(opt)\n    opt = opt or {}\n\n    -- get arguments\n    local args = opt.arguments or {}\n    args.n = #args\n\n    -- get deserialize tag\n    local deserialize = opt.deserialize\n    if not deserialize then\n        return args\n    end\n    deserialize = tostring(deserialize)\n\n    -- deserialize prefixed arguments\n    for i, value in ipairs(args) do\n        if value:startswith(deserialize) then\n            local v, err = string.deserialize(value:sub(#deserialize + 1))\n            if err then\n                raise(err)\n            else\n                args[i] = v\n            end\n        end\n    end\n    return args\nend\n\nfunction _run(script, opt)\n    opt = opt or {}\n\n    if opt.quiet then\n        option.save()\n        option.set(\"quiet\", true, {force = true})\n    end\n\n    local oldir\n    if xmake.in_main_thread() then\n        local curdir = opt.curdir or os.workingdir()\n        oldir = os.cd(curdir)\n    end\n    if opt.command then\n        _run_commanad(script, _get_args(opt), opt)\n    else\n        _run_script(script, _get_args(opt), opt)\n    end\n    if oldir then\n        os.cd(oldir)\n    end\n\n    if opt.quiet then\n        option.restore()\n    end\nend\n\nfunction _run_in_thread(script, opt)\n    import(\"utils.run_script\", {anonymous = true})(script, opt)\nend\n\n-- run lua script\n--\n-- @param script      the script file or string or module name\n--                    e.g. /tmp/test.lua, \"print(\"hello\")\", \"utils.bin2c\"\n-- @param opt         the options\n--                     - curdir      the currect directory\n--                     - command     run script as command\n--                     - deserialize deserialize arguments starts with given prefix\n--                     - arguments   the script arguments\n--                     - thread      run script in a new native thread\n--                     - quiet       enable quiet output\n--                     - verbose     enable verbose output\n--                     - diagnosis   enable diagnosis output\nfunction main(script, opt)\n    opt = opt or {}\n    if opt.thread then\n        local argv\n        for _, arg in ipairs(opt.arguments) do\n            argv = argv or {}\n            if path.instance_of(arg) then\n                arg = tostring(arg)\n            end\n            table.insert(argv, arg)\n        end\n        local thread_opt = {\n            curdir = opt.curdir,\n            command = opt.command,\n            deserialize = opt.deserialize,\n            arguments = argv,\n            quiet = opt.quiet,\n            verbose = opt.verbose,\n            diagnosis = opt.diagnosis\n        }\n        local t = thread.start_named(\"utils.run_script\", _run_in_thread, script, thread_opt)\n        t:wait(-1)\n    else\n        _run(script, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/modules/utils/waiting_indicator.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        waiting_indicator.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.tty\")\nimport(\"core.theme.theme\")\n\n-- define module\nlocal waiting_indicator = waiting_indicator or object { _init = { \"_RUNNING\", \"_INDEX\", \"_STREAM\", \"_OPT\" } }\n\n-- stop the waiting indicator, clear written frames\nfunction waiting_indicator:stop()\n    if self._RUNNING ~= 0 then\n        self:clear()\n        self._RUNNING = 0\n        self._INDEX = 0\n    end\nend\n\nfunction waiting_indicator:_clear()\n    if self._RUNNING == 1 then\n        tty.erase_line_to_end()\n        self._RUNNING = 2\n        return true\n    end\nend\n\n-- clear previous frame of the waiting indicator\nfunction waiting_indicator:clear()\n    if self:_clear() then\n        self._STREAM:flush()\n    end\nend\n\n-- write next frame of the waiting indicator\nfunction waiting_indicator:write()\n    local chars = self._OPT.chars[self._INDEX % #self._OPT.chars + 1]\n    tty.cursor_and_attrs_save()\n    self._STREAM:write(chars)\n    self._STREAM:flush()\n    tty.cursor_and_attrs_restore()\n    self._INDEX = self._INDEX + 1\n    self._RUNNING = 1\nend\n\n-- check if the waiting indicator is running\nfunction waiting_indicator:running()\n    return self._RUNNING and true or false\nend\n\n-- build a waiting indicator\n-- @params stream - stream to write to, will use io.stdout if not provided\n-- @params opt - options\n--               - chars - an array of chars for waiting indicator\nfunction new(stream, opt)\n    stream = stream or io.stdout\n    opt = opt or {}\n    if opt.chars == nil or #opt.chars == 0 then\n        opt.chars = theme.get(\"text.spinner.chars\")\n    end\n    return waiting_indicator {_OPT = opt, _STREAM = stream, _RUNNING = 0, _INDEX = 0}\nend\n\nreturn {new = new}\n\n"
  },
  {
    "path": "xmake/modules/utils/wdk/testcert.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        testcert.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_wdk\")\n\n-- get tool\nfunction _get_tool(wdk, name)\n\n    -- init cache\n    _g.tools = _g.tools or {}\n\n    -- get it from the cache\n    local tool = _g.tools[name]\n    if not tool then\n\n        -- get arch\n        local arch = config.arch() or os.arch()\n\n        -- get tool\n        tool = path.join(wdk.bindir, arch, name .. \".exe\")\n        if not os.isexec(tool) then\n            tool = path.join(wdk.bindir, wdk.sdkver, arch, name .. \".exe\")\n        end\n        assert(os.isexec(tool), name .. \" not found!\")\n        _g.tools[name] = tool\n    end\n    return tool\nend\n\n-- install test certificate\nfunction _install(wdk)\n\n    -- get signtool\n    local signtool = _get_tool(wdk, \"signtool\")\n\n    -- check test certificate first\n    local ok = try\n    {\n        function ()\n            local tmpfile = os.tmpfile(os.programfile())\n            if not os.isfile(tmpfile) then\n                os.cp(os.programfile(), tmpfile)\n            end\n            os.vrunv(signtool, {\"sign\", \"/v\", \"/a\", \"/s\", \"PrivateCertStore\", \"/n\", \"xmake.io(test)\", tmpfile})\n            return true\n        end\n    }\n    if ok then\n        return\n    end\n\n    -- get makecert\n    local makecert = _get_tool(wdk, \"makecert\")\n\n    -- get certmgr\n    local certmgr = _get_tool(wdk, \"certmgr\")\n\n    -- get a test certificate\n    local testcer = path.join(global.directory(), \"sign\", \"test.cer\")\n    local company = \"xmake.io(test)\"\n\n    -- make a new test certificate @note need re-generate certificate when reinstalling\n    local signdir = path.directory(testcer)\n    if not os.isdir(signdir)  then\n        os.mkdir(signdir)\n    end\n    os.vrunv(makecert, {\"-r\", \"-pe\", \"-ss\", \"PrivateCertStore\", \"-n\", \"CN=\" .. company, testcer})\n\n    -- register this test certificate\n    try\n    {\n        function ()\n            os.vrunv(certmgr, {\"/add\", testcer, \"/s\", \"/r\", \"localMachine\", \"root\"})\n            os.vrunv(certmgr, {\"/add\", testcer, \"/s\", \"/r\", \"localMachine\", \"trustedpublisher\"})\n        end,\n        catch\n        {\n            function (errors)\n                os.tryrm(testcer)\n                raise(errors)\n            end\n        }\n    }\n\n    -- trace\n    print(\"install test certificate ok!\")\n    print(\"  - company: %s\", company)\n    print(\"  - cerfile: %s\", testcer)\nend\n\n-- entry function\nfunction main(action)\n\n    -- find wdk envirnoment first\n    local wdk = find_wdk()\n    assert(wdk, \"wdk not found!\")\n\n    -- install or uninstall test certificate\n    if action == \"install\" then\n        _install(wdk)\n    end\nend\n"
  },
  {
    "path": "xmake/platforms/android/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"android\")\n    set_os(\"android\")\n    set_hosts(\"macosx\", \"linux\", \"windows\")\n\n    -- set archs, we use the latest android abi provided in android ndk now.\n    -- we will continue to support the old abi architectures for old version ndk.\n    -- e.g. armv5te(armeabi), armv7-a(armeabi-v7a), mips, mips64, i386\n    --\n    -- @see https://developer.android.google.cn/ndk/guides/abis\n    -- @note The NDK previously supported ARMv5 (armeabi) and 32-bit and 64-bit MIPS, but this support has been removed in NDK r17.\n    --\n    set_archs(\"armeabi\", \"armeabi-v7a\", \"arm64-v8a\", \"riscv64\", \"x86\", \"x86_64\", \"mips\", \"mip64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolchains(\"envs\", \"ndk\", \"rust\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Android Configuration\"                                                 }\n                ,   {nil, \"ndk\",            \"kv\", nil,          \"The NDK Directory\"                     }\n                ,   {nil, \"ndk_sdkver\",     \"kv\", \"auto\",       \"The SDK Version for NDK\"               }\n                ,   {nil, \"android_sdk\",    \"kv\", nil,          \"The Android SDK Directory\"             }\n                ,   {nil, \"build_toolver\",  \"kv\", nil,          \"The Build Tool Version of Android SDK\" }\n                ,   {nil, \"ndk_stdcxx\",     \"kv\", true,         \"Use stdc++ library for NDK\"            }\n                ,   {nil, \"ndk_cxxstl\",     \"kv\", nil,          \"The stdc++ stl library for NDK, (deprecated, please use --runtimes)\",\n                                                                \"    - c++_static\",\n                                                                \"    - c++_shared\",\n                                                                \"    - gnustl_static\",\n                                                                \"    - gnustl_shared\",\n                                                                \"    - stlport_shared\",\n                                                                \"    - stlport_static\"                  }\n                }\n\n            ,   global =\n                {\n                    {category = \"Android Configuration\"                                                 }\n                ,   {nil, \"ndk\",            \"kv\", nil,          \"The NDK Directory\"                     }\n                ,   {nil, \"ndk_sdkver\",     \"kv\", \"auto\",       \"The SDK Version for NDK\"               }\n                ,   {nil, \"android_sdk\",    \"kv\", nil,          \"The Android SDK Directory\"             }\n                ,   {nil, \"build_toolver\",  \"kv\", nil,          \"The Build Tool Version of Android SDK\" }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/platforms/appletvos/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"appletvos\")\n    set_os(\"ios\")\n    set_hosts(\"macosx\")\n\n    if os.arch() == \"arm64\" then -- on apple m1 device\n        set_archs(\"arm64\", \"x86_64\")\n    else\n        set_archs(\"arm64\", \"armv7\", \"armv7s\", \"i386\", \"x86_64\")\n    end\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dylib\")\n    set_formats(\"symbol\", \"$(name).dSYM\")\n\n    set_toolchains(\"envs\", \"xcode\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_sdkver\",            \"kv\", \"auto\",       \"The SDK Version for Xcode\"         }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                ,   {nil, \"target_minver\",           \"kv\", \"auto\",       \"The Target Minimal Version\"        }\n                ,   {nil, \"appledev\",                \"kv\", nil,          \"The Apple Device Type\",\n                                                                         values = {\"simulator\", \"iphone\", \"watchtv\", \"appletv\"}}\n                }\n\n            ,   global =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/applexros/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"applexros\")\n    set_os(\"ios\")\n    set_hosts(\"macosx\")\n\n    if os.arch() == \"arm64\" then -- on apple m1 device\n        set_archs(\"arm64\", \"x86_64\")\n    else\n        set_archs(\"arm64\", \"armv7\", \"armv7s\", \"i386\", \"x86_64\")\n    end\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dylib\")\n    set_formats(\"symbol\", \"$(name).dSYM\")\n\n    set_toolchains(\"envs\", \"xcode\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_sdkver\",            \"kv\", \"auto\",       \"The SDK Version for Xcode\"         }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                ,   {nil, \"target_minver\",           \"kv\", \"auto\",       \"The Target Minimal Version\"        }\n                ,   {nil, \"appledev\",                \"kv\", nil,          \"The Apple Device Type\",\n                                                                         values = {\"simulator\", \"iphone\", \"watchtv\", \"applexr\"}}\n                }\n\n            ,   global =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/bsd/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"bsd\")\n    set_os(\"bsd\")\n    set_hosts(\"bsd\")\n    set_archs(\"i386\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_installdir(\"/usr/local\")\n\n    set_toolchains(\"envs\", \"gcc\", \"clang\", \"yasm\", \"nasm\", \"fasm\", \"cuda\", \"go\", \"rust\", \"gfortran\", \"zig\", \"dotnet\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {nil, \"cuda_sdkver\",    \"kv\", \"auto\",       \"The Cuda SDK Version\"              }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {nil, \"qt_sdkver\",      \"kv\", \"auto\",       \"The Qt SDK Version\"                }\n                }\n\n            ,   global =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                }\n            }\n\n\n"
  },
  {
    "path": "xmake/platforms/cross/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"cross\")\n    set_hosts(\"macosx\", \"linux\", \"windows\", \"bsd\")\n    set_archs(\"i386\", \"x86_64\", \"arm\", \"arm64\", \"mips\", \"mips64\", \"riscv\", \"riscv64\", \"loong64\", \"s390x\", \"ppc\", \"ppc64\", \"sh4\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolchains(\"envs\", \"cross\")\n\n\n"
  },
  {
    "path": "xmake/platforms/cygwin/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"cygwin\")\n    set_os(\"windows\")\n    set_hosts(\"windows\")\n    set_archs(\"i386\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"$(name).dll\")\n    set_formats(\"binary\", \"$(name).exe\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_installdir(\"/usr/local\")\n\n    set_toolchains(\"envs\", \"cross\", \"gcc\", \"clang\", \"yasm\", \"gfortran\")\n\n"
  },
  {
    "path": "xmake/platforms/haiku/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"haiku\")\n    set_os(\"haiku\")\n    set_hosts(\"haiku\")\n    set_archs(\"i386\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolchains(\"envs\", \"gcc\", \"clang\", \"yasm\", \"nasm\", \"fasm\", \"cuda\", \"go\", \"rust\", \"gfortran\", \"zig\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {nil, \"cuda_sdkver\",    \"kv\", \"auto\",       \"The Cuda SDK Version\"              }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {nil, \"qt_sdkver\",      \"kv\", \"auto\",       \"The Qt SDK Version\"                }\n                }\n\n            ,   global =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                }\n            }\n\n\n"
  },
  {
    "path": "xmake/platforms/harmony/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"harmony\")\n    set_os(\"harmony\")\n    set_hosts(\"macosx\", \"linux\", \"windows\")\n    set_archs(\"armeabi-v7a\", \"arm64-v8a\", \"x86\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolchains(\"envs\", \"hdk\")\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/iphoneos/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"iphoneos\")\n    set_os(\"ios\")\n    set_hosts(\"macosx\")\n    set_archs(\"arm64\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dylib\")\n    set_formats(\"symbol\", \"$(name).dSYM\")\n\n    set_toolchains(\"envs\", \"xcode\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_sdkver\",            \"kv\", \"auto\",       \"The SDK Version for Xcode\"         }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                ,   {nil, \"target_minver\",           \"kv\", \"auto\",       \"The Target Minimal Version\"        }\n                ,   {nil, \"appledev\",                \"kv\", nil,          \"The Apple Device Type\",\n                                                                         values = {\"simulator\", \"iphone\", \"watchtv\", \"appletv\", \"catalyst\"}}\n                }\n\n            ,   global =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/linux/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"linux\")\n    set_os(\"linux\")\n    set_hosts(\"macosx\", \"linux\", \"windows\", \"bsd\")\n    set_archs(\"i386\", \"x86_64\", \"armv7\", \"armv7s\", \"arm64\", \"mips\", \"mips64\", \"mipsel\", \"mips64el\", \"loong64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_installdir(\"/usr/local\")\n\n    -- The cross toolchain should be placed after the host toolchain.\n    -- otherwise, if the host toolchain is explicitly loaded in the target,\n    -- the cross toolchain will be selected incorrectly in toolchain.lua.\n    --\n    -- TODO Perhaps we should handle it better, or remove the cross toolchain.\n    set_toolchains(\"envs\", \"gcc\", \"clang\",\n        \"cross\", \"yasm\", \"nasm\", \"fasm\", \"cuda\", \"go\", \"rust\", \"swift\", \"gfortran\", \"zig\", \"fpc\", \"nim\", \"dotnet\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {nil, \"cuda_sdkver\",    \"kv\", \"auto\",       \"The Cuda SDK Version\"              }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {nil, \"qt_sdkver\",      \"kv\", \"auto\",       \"The Qt SDK Version\"                }\n                ,   {category = \"Vcpkg Configuration\"                                               }\n                ,   {nil, \"vcpkg\",          \"kv\", \"auto\",       \"The Vcpkg Directory\"               }\n                }\n\n            ,   global =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {category = \"Vcpkg Configuration\"                                               }\n                ,   {nil, \"vcpkg\",          \"kv\", \"auto\",       \"The Vcpkg Directory\"               }\n                }\n            }\n\n\n"
  },
  {
    "path": "xmake/platforms/macosx/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"macosx\")\n    set_os(\"macosx\")\n    set_hosts(\"macosx\")\n    set_archs(\"x86_64\", \"arm64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dylib\")\n    set_formats(\"symbol\", \"$(name).dSYM\")\n\n    set_installdir(\"/usr/local\")\n    set_toolchains(\"envs\", \"xcode\", \"clang\", \"gcc\", \"yasm\", \"nasm\", \"cuda\", \"rust\", \"go\", \"gfortran\", \"zig\", \"fpc\", \"nim\", \"dotnet\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_sdkver\",            \"kv\", \"auto\",       \"The SDK Version for Xcode\"         }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                ,   {nil, \"target_minver\",           \"kv\", \"auto\",       \"The Target Minimal Version\"        }\n                ,   {nil, \"appledev\",                \"kv\", nil,          \"The Apple Device Type\",\n                                                                         values = {\"simulator\", \"iphone\", \"watchtv\", \"appletv\", \"catalyst\"}}\n                ,   {category = \"Cuda SDK Configuration\"                                                     }\n                ,   {nil, \"cuda\",                    \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {nil, \"cuda_sdkver\",             \"kv\", \"auto\",       \"The Cuda SDK Version\"              }\n                ,   {category = \"Qt SDK Configuration\"                                                       }\n                ,   {nil, \"qt\",                      \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",                 \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {nil, \"qt_sdkver\",               \"kv\", \"auto\",       \"The Qt SDK Version\"                }\n                ,   {category = \"Vcpkg Configuration\"                                                        }\n                ,   {nil, \"vcpkg\",                   \"kv\", \"auto\",       \"The Vcpkg Directory\"               }\n                }\n\n            ,   global =\n                {\n                    {category = \"XCode SDK Configuration\"                                                    }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\"   }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\"   }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\"   }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"    }\n                ,   {category = \"Cuda SDK Configuration\"                                                     }\n                ,   {nil, \"cuda\",                    \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {category = \"Qt SDK Configuration\"                                                       }\n                ,   {nil, \"qt\",                      \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",                 \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {category = \"Vcpkg Configuration\"                                                        }\n                ,   {nil, \"vcpkg\",                   \"kv\", \"auto\",       \"The Vcpkg Directory\"               }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/mingw/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"mingw\")\n    set_os(\"windows\")\n    set_hosts(\"macosx\", \"linux\", \"windows\", \"bsd\")\n\n    -- set archs, arm/arm64 only for llvm-mingw\n    set_archs(\"i386\", \"x86_64\", \"arm\", \"arm64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).obj\")\n    set_formats(\"shared\", \"lib$(name).dll\")\n    set_formats(\"binary\", \"$(name).exe\")\n    set_formats(\"symbol\", \"$(name).pdb\")\n\n    set_toolchains(\"envs\", \"mingw\", \"yasm\", \"nasm\", \"fasm\", \"go\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"MingW Configuration\"                                     }\n                ,   {nil, \"mingw\",          \"kv\", nil,          \"The MingW SDK Directory\" }\n                }\n\n            ,   global =\n                {\n                    {category = \"MingW Configuration\"                                     }\n                ,   {nil, \"mingw\",          \"kv\", nil,          \"The MingW SDK Directory\" }\n                }\n            }\n"
  },
  {
    "path": "xmake/platforms/msys/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"msys\")\n    set_os(\"windows\")\n    set_hosts(\"windows\")\n    set_archs(\"i386\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dll\")\n    set_formats(\"binary\", \"$(name).exe\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_installdir(\"/usr/local\")\n\n    set_toolchains(\"envs\", \"cross\", \"gcc\", \"clang\", \"yasm\", \"go\", \"gfortran\")\n\n"
  },
  {
    "path": "xmake/platforms/solaris/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"solaris\")\n    set_os(\"solaris\")\n    set_hosts(\"solaris\")\n    set_archs(\"i386\", \"x86_64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_installdir(\"/usr/local\")\n\n    set_toolchains(\"envs\", \"gcc\", \"clang\", \"yasm\", \"nasm\", \"fasm\", \"cuda\", \"go\", \"rust\", \"gfortran\", \"zig\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {nil, \"cuda_sdkver\",    \"kv\", \"auto\",       \"The Cuda SDK Version\"              }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                ,   {nil, \"qt_sdkver\",      \"kv\", \"auto\",       \"The Qt SDK Version\"                }\n                }\n\n            ,   global =\n                {\n                    {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",           \"kv\", \"auto\",       \"The Cuda SDK Directory\"            }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",             \"kv\", \"auto\",       \"The Qt SDK Directory\"              }\n                ,   {nil, \"qt_host\",        \"kv\", \"auto\",       \"The Qt Host SDK Directory\"         }\n                }\n            }\n\n\n"
  },
  {
    "path": "xmake/platforms/wasm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"wasm\")\n    set_os(\"web\")\n    set_hosts(\"macosx\", \"linux\", \"windows\", \"bsd\")\n    set_archs(\"wasm32\", \"wasm64\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).so\")\n    set_formats(\"binary\", \"$(name).html\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolchains(\"emcc\")\n\n    set_menu {\n        config =\n        {\n            {category = \"Emscripten Configuration\"          }\n        ,   {nil, \"emsdk\", \"kv\", nil, \"The emsdk directory\" }\n        }\n    ,   global =\n        {\n            {category = \"Emscripten Configuration\"          }\n        ,   {nil, \"emsdk\", \"kv\", nil, \"The emsdk directory\" }\n        }\n    }\n\n\n"
  },
  {
    "path": "xmake/platforms/watchos/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"watchos\")\n    set_os(\"ios\")\n    set_hosts(\"macosx\")\n    set_archs(\"armv7k\", \"i386\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"shared\", \"lib$(name).dylib\")\n    set_formats(\"symbol\", \"$(name).dSYM\")\n\n    set_toolchains(\"envs\", \"xcode\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"XCode SDK Configuration\"                                                  }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\" }\n                ,   {nil, \"xcode_sdkver\",            \"kv\", \"auto\",       \"The SDK Version for Xcode\"       }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\" }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\" }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"  }\n                ,   {nil, \"target_minver\",           \"kv\", \"auto\",       \"The Target Minimal Version\"      }\n                ,   {nil, \"appledev\",                \"kv\", nil,          \"The Apple Device Type\",\n                                                                         values = {\"simulator\", \"iphone\", \"watchtv\", \"appletv\"}}\n                }\n\n            ,   global =\n                {\n                    {category = \"XCode SDK Configuration\"                                                  }\n                ,   {nil, \"xcode\",                   \"kv\", \"auto\",       \"The Xcode Application Directory\" }\n                ,   {nil, \"xcode_bundle_identifier\", \"kv\", \"auto\",       \"The Bundle Identifier for Xcode\" }\n                ,   {nil, \"xcode_codesign_identity\", \"kv\", \"auto\",       \"The Codesign Identity for Xcode\" }\n                ,   {nil, \"xcode_mobile_provision\",  \"kv\", \"auto\",       \"The Mobile Provision for Xcode\"  }\n                }\n            }\n\n\n\n\n\n\n"
  },
  {
    "path": "xmake/platforms/windows/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nplatform(\"windows\")\n    set_os(\"windows\")\n    set_hosts(\"windows\")\n    set_archs(\"x86\", \"x64\", \"arm\", \"arm64\", \"arm64ec\")\n\n    set_formats(\"static\", \"$(name).lib\")\n    set_formats(\"object\", \"$(name).obj\")\n    set_formats(\"shared\", \"$(name).dll\")\n    set_formats(\"binary\", \"$(name).exe\")\n    set_formats(\"symbol\", \"$(name).pdb\")\n\n    set_toolchains(\"msvc\", \"clang\", \"yasm\", \"nasm\", \"cuda\", \"rust\", \"swift\", \"go\", \"gfortran\", \"zig\", \"fpc\", \"nim\", \"dotnet\")\n\n    set_menu {\n                config =\n                {\n                    {category = \"Visual Studio SDK Configuration\"                                   }\n                ,   {nil, \"vs\",          \"kv\", \"auto\", \"The Microsoft Visual Studio\"\n                                                    , \"  e.g. --vs=2017\"                            }\n                ,   {nil, \"vs_toolset\",  \"kv\", nil,    \"The Microsoft Visual Studio Toolset Version\"\n                                                    , \"  e.g. --vs_toolset=14.0\"                    }\n                ,   {nil, \"vs_sdkver\",   \"kv\", nil,    \"The Windows SDK Version of Visual Studio\"\n                                                    , \"  e.g. --vs_sdkver=10.0.15063.0\"             }\n                ,   {nil, \"vs_runtime\",  \"kv\", nil,    \"The Runtime library of Visual Studio (deprecated, please use --runtimes)\"\n                                                    , values = {\"MT\", \"MTd\", \"MD\", \"MDd\"}           }\n                ,   {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",        \"kv\", \"auto\", \"The Cuda SDK Directory\"                     }\n                ,   {nil, \"cuda_sdkver\", \"kv\", \"auto\", \"The Cuda SDK Version\"                       }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",          \"kv\", \"auto\", \"The Qt SDK Directory\"                       }\n                ,   {nil, \"qt_host\",     \"kv\", \"auto\", \"The Qt Host SDK Directory\"                  }\n                ,   {nil, \"qt_sdkver\",   \"kv\", \"auto\", \"The Qt SDK Version\"                         }\n                ,   {category = \"WDK Configuration\"                                                 }\n                ,   {nil, \"wdk\",         \"kv\", \"auto\", \"The WDK Directory\"                          }\n                ,   {nil, \"wdk_sdkver\",  \"kv\", \"auto\", \"The WDK Version\"                            }\n                ,   {nil, \"wdk_winver\",  \"kv\", \"auto\", \"The WDK Windows Version\"\n                                                    , values = function (complete)\n                                                        if complete then\n                                                            return {\"win10_rs3\", \"win10\", \"win81\", \"win8\", \"win7_sp3\", \"win7_sp2\", \"win7_sp1\", \"win7\"}\n                                                        else\n                                                            return {\"win10[|_rs3]\", \"win81\", \"win8\", \"win7[|_sp1|_sp2|_sp3]\"}\n                                                        end\n                                                    end                                             }\n                ,   {category = \"Vcpkg Configuration\"                                               }\n                ,   {nil, \"vcpkg\",       \"kv\", \"auto\", \"The Vcpkg Directory\"                        }\n                }\n\n            ,   global =\n                {\n                    {category = \"Visual Studio SDK Configuration\"                                   }\n                ,   {nil, \"vs\",          \"kv\", \"auto\", \"The Microsoft Visual Studio\"                }\n                ,   {category = \"Cuda SDK Configuration\"                                            }\n                ,   {nil, \"cuda\",        \"kv\", \"auto\", \"The Cuda SDK Directory\"                     }\n                ,   {category = \"Qt SDK Configuration\"                                              }\n                ,   {nil, \"qt\",          \"kv\", \"auto\", \"The Qt SDK Directory\"                       }\n                ,   {nil, \"qt_host\",     \"kv\", \"auto\", \"The Qt Host SDK Directory\"                  }\n                ,   {category = \"WDK Configuration\"                                                 }\n                ,   {nil, \"wdk\",         \"kv\", \"auto\", \"The WDK Directory\"                          }\n                ,   {category = \"Vcpkg Configuration\"                                               }\n                ,   {nil, \"vcpkg\",       \"kv\", \"auto\", \"The Vcpkg Directory\"                        }\n                }\n            }\n\n\n"
  },
  {
    "path": "xmake/plugins/check/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.text\")\nimport(\"core.project.config\")\nimport(\"private.check.checker\")\n\n-- show checkers list\nfunction _show_list()\n    local tbl = {align = 'l', sep = \"    \"}\n    local checkers = checker.checkers()\n    local groups = {}\n    for name, info in table.orderpairs(checkers) do\n        local groupname = name:split(\".\", {plain = true})[1]\n        if not groups[groupname] then\n            table.insert(tbl, {})\n            table.insert(tbl, {groupname:sub(1, 1):upper() .. groupname:sub(2) .. \" checkers:\"})\n            groups[groupname] = true\n        end\n        table.insert(tbl, {{\"  \" .. name, style = \"${color.dump.string_quote}\"}, info.description})\n    end\n    cprint(text.table(tbl))\nend\n\n-- show checker information\nfunction _show_info(name)\n    local checkers = checker.checkers()\n    local info = checkers[name]\n    if info then\n        cprint(\"${color.dump.string}checker${clear}(%s):\", name)\n        cprint(\"  -> ${color.dump.string_quote}description${clear}: %s\", info.description)\n    else\n        raise(\"checker(%s) not found!\", name)\n    end\nend\n\n-- do check\nfunction _check(group_or_name, arguments)\n\n    -- load config\n    config.load()\n\n    -- get checkers\n    local checked_checkers = {}\n    local checkers = checker.checkers()\n    if checkers[group_or_name] then\n        table.insert(checked_checkers, group_or_name)\n    else\n        for name, _ in table.orderpairs(checkers) do\n            if name:startswith(group_or_name .. \".\") then\n                table.insert(checked_checkers, name)\n            end\n        end\n    end\n    assert(#checked_checkers > 0, \"checker(%s) not found!\", group_or_name)\n\n    -- do checkers\n    local showstats\n    for _, name in ipairs(checked_checkers) do\n        local info = checkers[name]\n        if showstats == nil and info and info.showstats ~= nil then\n            showstats = info.showstats\n        end\n        import(\"private.check.checkers.\" .. name, {anonymous = true})(arguments)\n    end\n    if showstats ~= false then\n        checker.show_stats()\n    end\nend\n\nfunction main()\n    if option.get(\"list\") then\n        _show_list()\n    elseif option.get(\"info\") then\n        _show_info(option.get(\"info\"))\n    elseif option.get(\"checkers\") then\n        _check(option.get(\"checkers\"), option.get(\"arguments\"))\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/check/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"check\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake check [options] [arguments]\",\n        description = \"Check the project sourcecode and configuration.\",\n        options = {\n            {'l', \"list\",      \"k\",  nil,   \"Show all supported checkers list.\"},\n            {nil, \"info\",      \"kv\", nil,   \"Show the given checker information.\"},\n            {nil, \"checkers\",  \"v\",  \"api\", \"Use the given checkers to check project.\",\n                                            \"e.g.\",\n                                            \"    - xmake check api\",\n                                            \"    - xmake check -v api.target\",\n                                            \"    - xmake check api.target.languages\",\n                                            \"\",\n                                            \"The supported checkers list:\",\n                values = function (complete, opt)\n                    return import(\"private.check.checker\").complete(complete, opt)\n                end},\n            {nil, \"arguments\", \"vs\", nil,   \"Set the checker arguments.\",\n                                            \"e.g.\",\n                                            \"    - xmake check clang.tidy [arguments]\"}\n        }\n    }\n\n"
  },
  {
    "path": "xmake/plugins/doxygen/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\n\n-- generate doxyfile\nfunction _generate_doxyfile(doxygen)\n\n    -- generate the default doxyfile\n    local doxyfile = path.join(project.directory(), \"doxyfile\")\n    os.vrunv(doxygen.program, {\"-g\", doxyfile})\n\n    -- enable recursive\n    --\n    -- RECURSIVE = YES\n    --\n    io.gsub(doxyfile, \"RECURSIVE%s-=%s-NO\", \"RECURSIVE = YES\")\n\n    -- set the source directory\n    --\n    -- INPUT = xxx\n    --\n    local srcdir = option.get(\"srcdir\")\n    if srcdir and os.isdir(srcdir) then\n        io.gsub(doxyfile, \"INPUT%s-=.-\\n\", format(\"INPUT = %s\\n\", srcdir))\n    end\n\n    -- set the output directory\n    --\n    -- OUTPUT_DIRECTORY =\n    --\n    local outputdir = option.get(\"outputdir\") or config.builddir()\n    if outputdir then\n        io.gsub(doxyfile, \"OUTPUT_DIRECTORY%s-=.-\\n\", format(\"OUTPUT_DIRECTORY = %s\\n\", outputdir))\n        os.mkdir(outputdir)\n    end\n\n    -- set the project name\n    --\n    -- PROJECT_NAME =\n    --\n    local name = project.name()\n    if name then\n        io.gsub(doxyfile, \"PROJECT_NAME%s-=.-\\n\", format(\"PROJECT_NAME = %s\\n\", name))\n    end\n    return doxyfile\nend\n\nfunction main()\n\n    -- load configuration\n    config.load()\n\n    -- enter the environments of doxygen\n    local oldenvs = packagenv.enter(\"doxygen\")\n\n    -- find doxygen\n    local packages = {}\n    local doxygen = find_tool(\"doxygen\")\n    if not doxygen then\n        table.join2(packages, install_packages(\"doxygen\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not doxygen then\n        doxygen = find_tool(\"doxygen\", {force = true})\n    end\n    assert(doxygen, \"doxygen not found!\")\n\n    -- get doxyfile first\n    local doxyfile = \"doxyfile\"\n    if not os.isfile(doxyfile) then\n        doxyfile = _generate_doxyfile(doxygen)\n    end\n    assert(os.isfile(doxyfile), \"%s not found!\", doxyfile)\n\n    -- set the project version\n    --\n    -- PROJECT_NUMBER =\n    --\n    local version = project.version()\n    if version then\n        io.gsub(doxyfile, \"PROJECT_NUMBER%s-=.-\\n\", format(\"PROJECT_NUMBER = %s\\n\", version))\n    end\n\n    -- generate document\n    cprint(\"generating ..\")\n    os.vrunv(doxygen.program, {doxyfile}, {curdir = project.directory()})\n\n    -- done\n    local outputdir = option.get(\"outputdir\") or config.builddir()\n    cprint(\"${bright green}result: ${default green}%s/html/index.html\", outputdir)\n    cprint(\"${color.success}doxygen ok!\")\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/doxygen/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        doxygen.lua\n--\n\n-- define task\ntask(\"doxygen\")\n\n    -- set category\n    set_category(\"plugin\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake doxygen [options] [arguments]\"\n\n                -- description\n            ,   description = \"Generate the doxygen document.\"\n\n                -- options\n            ,   options =\n                {\n                    {'o', \"outputdir\",  \"kv\", nil,      \"Set the output directory.\"         }\n                ,   {}\n                ,   {nil, \"srcdir\",     \"v\",  \"src\",    \"Set the source code directory.\"    }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/plugins/format/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"lib.detect.find_tool\")\nimport(\"async.runjobs\")\nimport(\"utils.progress\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\"private.action.utils\", {alias = \"action_utils\"})\n\n-- match source files\nfunction _match_sourcefiles(sourcefile, filepatterns)\n    for _, filepattern in ipairs(filepatterns) do\n        if sourcefile:match(filepattern.pattern) == sourcefile then\n            if filepattern.excludes then\n                if filepattern.rootdir and sourcefile:startswith(filepattern.rootdir) then\n                    sourcefile = sourcefile:sub(#filepattern.rootdir + 2)\n                end\n                for _, exclude in ipairs(filepattern.excludes) do\n                    if sourcefile:match(exclude) == sourcefile then\n                        return false\n                    end\n                end\n            end\n            return true\n        end\n    end\nend\n\n-- convert all sourcefiles to lua pattern\nfunction _get_file_patterns(sourcefiles)\n    local patterns = {}\n    for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do\n\n        -- get the excludes\n        local pattern  = sourcefile:trim()\n        local excludes = pattern:match(\"|.*$\")\n        if excludes then excludes = excludes:split(\"|\", {plain = true}) end\n\n        -- translate excludes\n        if excludes then\n            local _excludes = {}\n            for _, exclude in ipairs(excludes) do\n                exclude = path.translate(exclude)\n                exclude = path.pattern(exclude)\n                table.insert(_excludes, exclude)\n            end\n            excludes = _excludes\n        end\n\n        -- translate path and remove some repeat separators\n        pattern = path.translate((pattern:gsub(\"|.*$\", \"\")))\n\n        -- remove \"./\" or '.\\\\' prefix\n        if pattern:sub(1, 2):find('%.[/\\\\]') then\n            pattern = pattern:sub(3)\n        end\n\n        -- get the root directory\n        local rootdir = pattern\n        local startpos = pattern:find(\"*\", 1, true)\n        if startpos then\n            rootdir = rootdir:sub(1, startpos - 1)\n        end\n        rootdir = path.directory(rootdir)\n\n        -- convert to lua path pattern\n        pattern = path.pattern(pattern)\n        table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir})\n    end\n    return patterns\nend\n\n-- get all the targets that match the group or targetname\nfunction _get_targets(targetname, group_pattern)\n    local targets = {}\n    if targetname then\n        table.insert(targets, project.target(targetname))\n    else\n        for _, target in pairs(project.targets()) do\n            local group = target:get(\"group\")\n            if (target:is_default() and not group_pattern) or option.get(\"all\") or (group_pattern and group and group:match(group_pattern)) then\n                table.insert(targets, target)\n            end\n        end\n    end\n    return targets\nend\n\n-- tell if the source batch is a c/c++/objc/objc++/cuda source batch\nfunction _source_batch_should_format(sourcebatch)\n    local rulename = sourcebatch.rulename\n    local matched_rules = {\"c.build\", \"c++.build\", \"c++.build.modules\", \"cuda.build\", \"objc.build\", \"objc++.build\"}\n    return table.contains(matched_rules, rulename)\nend\n\n-- main\nfunction main()\n\n    -- load configuration\n    config.load()\n\n    -- enter the environments of llvm\n    local oldenvs = packagenv.enter(\"llvm\")\n\n    -- find clang-format\n    local packages = {}\n    local clang_format = find_tool(\"clang-format\")\n    if not clang_format then\n        table.join2(packages, install_packages(\"llvm\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not clang_format then\n        clang_format = find_tool(\"clang-format\", {force = true})\n    end\n    assert(clang_format, \"clang-format not found!\")\n\n    -- create style file\n    local argv = {}\n    local projectdir = project.directory()\n    if option.get(\"create\") then\n        table.insert(argv, \"--style=\" .. (option.get(\"style\") or \"Google\"))\n        table.insert(argv, \"--dump-config\")\n        os.execv(clang_format.program, argv, {stdout = path.join(projectdir, \".clang-format\"), curdir = projectdir})\n        return\n    end\n\n    -- set style file\n    if option.get(\"style\") then\n        table.insert(argv, \"--style=\" .. option.get(\"style\"))\n    end\n\n    if option.get(\"dry-run\") then\n        -- do not make any changes, just show the files that would be formatted\n        table.insert(argv, \"--dry-run\")\n    else\n        -- inplace flag\n        table.insert(argv, \"-i\")\n    end\n\n    -- changes formatting warnings to errors\n    if option.get(\"error\") then\n        table.insert(argv, \"--Werror\")\n    end\n\n    -- print verbose information\n    if option.get(\"verbose\") then\n        table.insert(argv, \"--verbose\")\n    end\n\n    -- collect sourcefiles\n    local sourcefiles = {}\n    local targetname, group_pattern = action_utils.get_target_and_group()\n    local targets = _get_targets(targetname, group_pattern)\n    if option.get(\"files\") then\n        local filepatterns = _get_file_patterns(option.get(\"files\"))\n        for _, target in ipairs(targets) do\n            for _, source in ipairs(target:sourcefiles()) do\n                if _match_sourcefiles(source, filepatterns) then\n                    table.insert(sourcefiles, path.join(projectdir, source))\n                end\n            end\n            for _, header in ipairs(target:headerfiles()) do\n                if _match_sourcefiles(header, filepatterns) then\n                    table.insert(sourcefiles, path.join(projectdir, header))\n                end\n            end\n        end\n    else\n        for _, target in ipairs(targets) do\n            for _, sourcebatch in pairs(target:sourcebatches()) do\n                if _source_batch_should_format(sourcebatch) then\n                    for _, source in ipairs(sourcebatch.sourcefiles) do\n                        table.insert(sourcefiles, path.join(projectdir, source))\n                    end\n                end\n            end\n            for _, header in ipairs(target:headerfiles()) do\n                table.insert(sourcefiles, path.join(projectdir, header))\n            end\n        end\n    end\n\n    -- format files in parallel\n    if #sourcefiles > 0 then\n        local jobs = tonumber(option.get(\"jobs\"))\n        if not jobs or jobs <= 0 then\n            jobs = os.default_njob()\n        end\n        local format_time = os.mclock()\n        local runjobs_opt = {\n            total = #sourcefiles,\n            comax = jobs,\n            showtips = false,\n            progress_refresh = true\n        }\n        runjobs(\"clang-format\", function (index, total, opt)\n            local sourcefile = sourcefiles[index]\n            local format_argv = table.join(argv, {sourcefile})\n            progress.show(opt.progress, \"clang-format.formatting %s\", sourcefile)\n            os.execv(clang_format.program, format_argv, {curdir = projectdir})\n        end, runjobs_opt)\n        format_time = os.mclock() - format_time\n        progress.show(100, \"${color.success}clang-format formatted %d files, spent %.3fs\", #sourcefiles, format_time / 1000)\n    end\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/format/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        format.lua\n--\n\ntask(\"format\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n                usage = \"xmake format [options] [arguments]\",\n                description = \"Format the current project.\",\n                options = {\n                    {'s', \"style\",   \"kv\",  nil,  \"Set the path of .clang-format file, a coding style\",\n                                                  values = {\"LLVM\", \"Google\", \"Chromium\", \"Mozilla\", \"WebKit\"}},\n                    {nil, \"create\",  \"k\",  nil,   \"Create a .clang-format file from a coding style\"},\n                    {'n', \"dry-run\", \"k\",  nil,   \"Do not make any changes, just show the files that would be formatted.\"},\n                    {'e', \"error\",   \"k\",  nil,   \"If set, changes formatting warnings to errors.\"},\n                    {'j', \"jobs\",    \"kv\", tostring(os.default_njob()),\n                                                  \"Set the number of parallel format jobs.\"},\n                    {'a', \"all\",     \"k\",  nil,   \"Format all targets.\"},\n                    {'g', \"group\",   \"kv\", nil,   \"Format all targets of the given group. It support path pattern matching.\",\n                                                  \"e.g.\",\n                                                  \"    xmake format -g test\",\n                                                  \"    xmake format -g test_*\",\n                                                  \"    xmake format --group=benchmark/*\"},\n                    {'f', \"files\",   \"kv\", nil,   \"Build the given source files.\",\n                                                  \"e.g.\",\n                                                  \"    - xmake format --files=src/main.c\",\n                                                  \"    - xmake format --files='src/*.c' [target]\",\n                                                  \"    - xmake format --files='src/**.c|excluded_file.c'\",\n                                                  \"    - xmake format --files='src/main.c\" .. path.envsep() .. \"src/test.c'\" },\n                                                  {},\n                    {nil, \"target\",  \"v\",  nil,   \"The target name. It will format all default targets if this parameter is not specified.\"\n                                                       , values = function (complete, opt) return import(\"private.utils.complete_helper.targets\")(complete, opt) end }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/plugins/lua/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.sandbox.module\")\nimport(\"core.sandbox.sandbox\")\nimport(\"core.project.project\")\nimport(\"utils.run_script\")\n\n-- get all lua scripts\nfunction scripts()\n    local names = {}\n    local oldir = os.cd(os.workingdir())\n    local files = os.files(path.join(os.scriptdir(), \"scripts/*.lua\"))\n    for _, file in ipairs(files) do\n        table.insert(names, path.basename(file))\n    end\n    os.cd(oldir)\n    return names\nend\n\n-- list all lua scripts\nfunction _list()\n    print(\"scripts:\")\n    for _, file in ipairs(scripts()) do\n        print(\"    \" .. file)\n    end\nend\n\n-- get script from stdin\nfunction _get_script_from_stdin()\n    local script_content = io.read(\"*a\")\n    if script_content then\n        -- remove utf8 bom\n        script_content = script_content:ltrim(utf8.bom)\n        if not script_content:find(\"function main\", 1, true) then\n            script_content = \"function main(...)\\n\" .. script_content .. \"\\nend\"\n        end\n\n        local script = os.tmpfile() .. \".lua\"\n        io.writefile(script, script_content)\n        return script\n    end\nend\n\nfunction main()\n\n    -- list builtin scripts\n    if option.get(\"list\") then\n        return _list()\n    end\n\n    -- run script\n    local script = option.get(\"script\")\n    local arguments = option.get(\"arguments\")\n    local from_stdin = option.get(\"stdin\")\n    if script or from_stdin then\n\n        -- run script from stdin?\n        local script_file_to_remove\n        if from_stdin then\n            local script_path = _get_script_from_stdin()\n            if script_path then\n                script = script_path\n                script_file_to_remove = script_path\n            end\n        end\n\n        if script then\n            run_script(script, {\n                curdir = os.workingdir(),\n                verbose = option.get(\"verbose\"),\n                diagnosis = option.get(\"diagnosis\"),\n                command = option.get(\"command\"),\n                arguments = arguments,\n                deserialize = option.get(\"deserialize\")})\n\n            if script_file_to_remove then\n                os.tryrm(script_file_to_remove)\n            end\n        end\n    else\n        -- enter interactive mode\n        sandbox.interactive()\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/cat.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cat.lua\n--\n\n-- main\nfunction main(...)\n    for _, v in ipairs(table.pack(...)) do\n        if os.isfile(v) then io.cat(v) end\n    end\n    print(\"\")\nend\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/cp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cp.lua\n--\n\n-- main\nfunction main(...)\n    os.cp(...)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/echo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        echo.lua\n--\n\n-- main\nfunction main(...)\n    for _, v in ipairs(table.pack(...)) do\n        printf(\"%s \", v)\n    end\n    print(\"\")\nend\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/lipo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        lipo.lua\n--\n\n-- imports\nimport(\"detect.tools.find_lipo\")\n\n-- main\n--\n-- e.g..\n--\n-- xmake l lipo \"-create -arch armv7 file -arch arm64 file -output file\"\nfunction main(...)\n\n    -- get arguments\n    local args = {...}\n    if not args or #args ~= 1 then\n        raise(\"invalid arguments!\")\n    end\n    args = args[1]\n\n    -- find the lipo\n    local lipo = find_lipo()\n    assert(lipo, \"lipo not found!\")\n\n    -- run it\n    os.run(\"%s %s\", lipo, args)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/mkdir.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mkdir.lua\n--\n\n-- main\nfunction main(...)\n    os.mkdir(...)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/mv.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        mv.lua\n--\n\n-- main\nfunction mv.main(...)\n    os.mv(...)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/rm.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rm.lua\n--\n\n-- main\nfunction main(...)\n    os.rm(...)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/rmdir.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rmdir.lua\n--\n\n-- main\nfunction main(...)\n    os.rmdir(...)\nend\n\n"
  },
  {
    "path": "xmake/plugins/lua/scripts/time.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        time.lua\n--\n\n-- main\nfunction main(...)\n    local argv = {...}\n    local program = argv[1]\n    if program then\n        local t = os.mclock()\n        os.execv(program, table.slice(argv, 2))\n        t = os.mclock() - t\n        print(\"time %0.3fs\", t / 1000.)\n    else\n        raise(\"program not found!\")\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/lua/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define task\ntask(\"lua\")\n\n    -- set category\n    set_category(\"plugin\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake lua|l [options] [script] [arguments]\"\n\n                -- description\n            ,   description = \"Run the lua script.\"\n\n                -- xmake l\n            ,   shortname = 'l'\n\n                -- options\n            ,   options =\n                {\n\n                    {'l', \"list\"        , \"k\"   , nil   ,   \"List all scripts.\"                                             }\n                ,   {'c', \"command\"     , \"k\"   , nil   ,   \"Run script as command\"                                         }\n                ,   {'d', \"deserialize\" , \"kv\"  , nil   ,   \"Deserialize arguments starts with given prefix\"                }\n                ,   {nil, \"stdin\"       , \"k\"   , nil   ,   \"Run script from stdin\",\n                                                            \"e.g.\",\n                                                            \"    - echo 'print(\\\"hello\\\")' | xmake lua --stdin\",\n                                                            \"    - cat script.lua | xmake lua --stdin\"\n                                                                                                                            }\n                ,   {nil, \"script\"      , \"v\"   , nil   ,   \"Run the given lua script name, file or module and enter interactive mode if no given script.\",\n                                                            \"e.g.\",\n                                                            \"    - xmake lua (enter interactive mode)\",\n                                                            \"    - xmake lua /tmp/script.lua\",\n                                                            \"    - xmake lua echo 'hello xmake'\",\n                                                            \"    - xmake lua core.xxx.xxx\",\n                                                            \"    - xmake lua -c 'print(...)' hello xmake!\"\n                                                        ,   values = function (complete, opt)\n                                                                if not complete or opt.command or opt.list then\n                                                                    return\n                                                                end\n                                                                local list = import(\"main.scripts\")()\n                                                                if list and complete then\n                                                                    local result = {}\n                                                                    for _, item in ipairs(list) do\n                                                                        if item:startswith(complete) then\n                                                                            table.insert(result, item)\n                                                                        end\n                                                                    end\n                                                                    if #result > 0 then\n                                                                        return result\n                                                                    end\n                                                                end\n                                                                -- we just return nil and fallback to system autocomplete\n                                                                -- it will complete file path, e.g. `xmake l scripts/test.lua`\n                                                            end                                                             }\n                ,   {nil, \"arguments\"   ,  \"vs\" , nil   ,   \"The script arguments, use '--deserialize' option to enable deserializing.\",\n                                                            \"e.g.\",\n                                                            \"    - xmake lua -d@ lib.detect.find_tool tar @{version=true}\"      }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/plugins/macro/macros/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\n\n-- the options\nlocal options =\n{\n    {'p', \"plat\",       \"kv\",  os.host(),   \"Set the platform.\"                                    }\n,   {'a', \"arch\",       \"kv\",  nil,         \"Set the architectures. e.g. 'armv7, arm64'\"           }\n,   {'f', \"config\",     \"kv\",  nil,         \"Pass the config arguments to \\\"xmake config\\\" ..\"     }\n,   {'o', \"outputdir\",  \"kv\",  nil,         \"Set the output directory of the package.\"             }\n,   {nil, \"target\",     \"v\",   nil,         \"The target name. It will package all default targets if this parameter is not specified.\"}\n}\n\n-- package all\n--\n-- e.g.\n-- xmake m package\n-- xmake m package -f \"-m debug\"\n-- xmake m package -p linux\n-- xmake m package -p iphoneos -f \"-m debug --xxx ...\" -o /tmp/xxx\n-- xmake m package -f \\\"--mode=debug\\\"\n--\nfunction main(argv)\n\n    -- parse arguments\n    local args = option.parse(argv, options, \"Package all architectures for the given the platform.\"\n                                           , \"\"\n                                           , \"Usage: xmake macro package [options]\")\n\n    -- package all archs\n    local plat = args.plat\n    local archs = args.arch and args.arch:split(',') or platform.archs(plat)\n    for _, arch in ipairs(archs) do\n        local argv = {\"f\", \"-cy\", \"-p\", plat, \"-a\", arch}\n        if args.config then\n            table.join2(argv, os.argv(args.config))\n        end\n        if option.get(\"verbose\") then\n            table.insert(argv, \"-v\")\n        end\n        if option.get(\"diagnosis\") then\n            table.insert(argv, \"-D\")\n        end\n        os.execv(os.programfile(), argv)\n        argv = {\"p\", \"-f\", \"oldpkg\"}\n        if args.outputdir then\n            table.insert(argv, \"-o\")\n            table.insert(argv, args.outputdir)\n        end\n        if option.get(\"verbose\") then\n            table.insert(argv, \"-v\")\n        end\n        if option.get(\"diagnosis\") then\n            table.insert(argv, \"-D\")\n        end\n        if option.get(\"target\") then\n            table.insert(argv, option.get(\"target\"))\n        end\n        os.execv(os.programfile(), argv)\n    end\n\n    -- package universal for iphoneos, watchos ...\n    if plat == \"iphoneos\" or plat == \"watchos\" or plat == \"macosx\" then\n\n        config.load()\n        os.cd(project.directory())\n\n        local outputdir = args.outputdir or config.builddir()\n        local targets = {}\n        if option.get(\"target\") then\n            local target = project.target(option.get(\"target\"))\n            if target then\n                table.insert(targets, target)\n            end\n        else\n            for _, target in pairs(project.targets()) do\n                table.insert(targets, target)\n            end\n        end\n        for _, target in ipairs(targets) do\n            local modes = {}\n            for _, modedir in ipairs(os.dirs(format(\"%s/%s.pkg/*/*/lib/*\", outputdir, target:name()))) do\n                table.insert(modes, path.basename(modedir))\n            end\n            for _, mode in ipairs(table.unique(modes)) do\n                local lipoargs = nil\n                for _, arch in ipairs(archs) do\n                    local archfile = format(\"%s/%s.pkg/%s/%s/lib/%s/%s\", outputdir, target:name(), plat, arch:trim(), mode, path.filename(target:targetfile()))\n                    if os.isfile(archfile) then\n                        lipoargs = format(\"%s -arch %s %s\", lipoargs or \"\", arch, archfile)\n                    end\n                end\n                if lipoargs then\n                    lipoargs = format(\"-create %s -output %s/%s.pkg/%s/universal/lib/%s/%s\", lipoargs, outputdir, target:name(), plat, mode, path.filename(target:targetfile()))\n                    os.mkdir(format(\"%s/%s.pkg/%s/universal/lib/%s\", outputdir, target:name(), plat, mode))\n                    os.execv(os.programfile(), {\"l\", \"lipo\", lipoargs})\n                end\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/macro/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.cache.localcache\")\n\n-- the macro directories\nfunction _directories()\n\n    return {    path.join(config.directory(), \"macros\")\n            ,   path.join(os.scriptdir(), \"macros\")}\nend\n\n-- the macro directory\nfunction _directory(macroname)\n\n    -- find macro directory\n    local macrodir = nil\n    for _, dir in ipairs(_directories()) do\n\n        -- found?\n        if os.isfile(path.join(dir, macroname .. \".lua\")) then\n            macrodir = dir\n            break\n        end\n    end\n\n    -- check\n    assert(macrodir, \"macro(%s) not found!\", macroname)\n    return macrodir\nend\n\n-- the readable macro file\nfunction _rfile(macroname)\n    if macroname == '.' then\n        macroname = \"anonymous\"\n    end\n    return path.join(_directory(macroname), macroname .. \".lua\")\nend\n\n-- the writable macro file\nfunction _wfile(macroname)\n    if macroname == '.' then\n        macroname = \"anonymous\"\n    end\n    return path.join(path.join(config.directory(), \"macros\"), macroname .. \".lua\")\nend\n\n-- get all macros\nfunction macros(anonymousname)\n\n    local results = {}\n    -- find all macros\n    for _, dir in ipairs(_directories()) do\n        local macrofiles = os.match(path.join(dir, \"*.lua\"))\n        for _, macrofile in ipairs(macrofiles) do\n\n            -- get macro name\n            local macroname = path.basename(macrofile)\n            if macroname == \"anonymous\" and anonymousname then\n                macroname = anonymousname\n            end\n            table.insert(results, macroname)\n        end\n    end\n    return results\nend\n\n-- list macros\nfunction _list()\n    cprint(\"${bright}macros:\")\n    for _, macroname in ipairs(macros(\".<anonymous>\")) do\n        print(\"    \" .. macroname)\n    end\nend\n\n-- show macro\nfunction _show(macroname)\n    local file = _rfile(macroname)\n    if os.isfile(file) then\n        io.cat(file)\n    else\n        raise(\"macro(%s) not found!\", macroname)\n    end\nend\n\n-- clear all macros\nfunction _clear()\n    os.rm(path.join(config.directory(), \"macros\"))\nend\n\n-- delete macro\nfunction _delete(macroname)\n\n    -- remove it\n    if os.isfile(_wfile(macroname)) then\n        os.rm(_wfile(macroname))\n    elseif os.isfile(_rfile(macroname)) then\n        raise(\"macro(%s) cannot be deleted!\", macroname)\n    else\n        raise(\"macro(%s) not found!\", macroname)\n    end\n\n    -- trace\n    cprint(\"${color.success}delete macro(%s) ok!\", macroname)\nend\n\n-- import macro\nfunction _import(macrofile, macroname)\n\n    -- import all macros\n    if os.isdir(macrofile) then\n\n        -- the macro directory\n        local macrodir = macrofile\n        local macrofiles = os.match(path.join(macrodir, \"*.lua\"))\n        for _, macrofile in ipairs(macrofiles) do\n\n            -- the macro name\n            macroname = path.basename(macrofile)\n\n            -- import it\n            os.cp(macrofile, _wfile(macroname))\n\n            -- trace\n            cprint(\"${color.success}import macro(%s) ok!\", macroname)\n        end\n    else\n\n        -- import it\n        os.cp(macrofile, _wfile(macroname))\n\n        -- trace\n        cprint(\"${color.success}import macro(%s) ok!\", macroname)\n    end\nend\n\n-- export macro\nfunction _export(macrofile, macroname)\n\n    -- export all macros\n    if os.isdir(macrofile) then\n\n        -- the output directory\n        local outputdir = macrofile\n\n        -- export all macros\n        for _, dir in ipairs(_directories()) do\n            local macrofiles = os.match(path.join(dir, \"*.lua\"))\n            for _, macrofile in ipairs(macrofiles) do\n\n                -- export it\n                os.cp(macrofile, outputdir)\n\n                -- trace\n                cprint(\"${color.success}export macro(%s) ok!\", path.basename(macrofile))\n            end\n        end\n    else\n        -- export it\n        os.cp(_rfile(macroname), macrofile)\n\n        -- trace\n        cprint(\"${color.success}export macro(%s) ok!\", macroname)\n    end\nend\n\n-- begin to record macro\nfunction _begin()\n    localcache.set(\"history\", \"cmdlines\", \"__macro_begin__\")\n    localcache.save(\"history\")\nend\n\n-- end to record macro\nfunction _end(macroname)\n\n    -- load the history: cmdlines\n    local cmdlines = table.wrap(localcache.get(\"history\", \"cmdlines\"))\n\n    -- get the last macro block\n    local begin = false\n    local block = {}\n    local total = #cmdlines\n    local index = total\n    while index ~= 0 do\n\n        -- the command line\n        local cmdline = cmdlines[index]\n\n        -- found begin? break it\n        if cmdline == \"__macro_begin__\" then\n            begin = true\n            break\n        end\n\n        -- found end? break it\n        if cmdline == \"__macro_end__\" then\n            break\n        end\n\n        -- ignore \"xmake m ..\" and \"xmake macro ..\"\n        if not cmdline:find(\"xmake%s+macro%s*\") and not cmdline:find(\"xmake%s+m%s*\") then\n\n            -- save this command line to block\n            table.insert(block, 1, cmdline)\n        end\n\n        -- the previous line\n        index = index - 1\n    end\n\n    -- the begin tag not found?\n    if not begin then\n        raise(\"please run: 'xmake macro --begin' first!\")\n    end\n\n    -- patch end tag to the history: cmdlines\n    table.insert(cmdlines, \"__macro_end__\")\n    localcache.set(\"history\", \"cmdlines\", cmdlines)\n    localcache.save(\"history\")\n\n    -- open the macro file\n    local file = io.open(_wfile(macroname), \"w\")\n\n    -- save the macro begin\n    file:print(\"function main(argv)\")\n\n    -- save the macro block\n    for _, cmdline in ipairs(block) do\n        file:print(\"    os.exec(\\\"%s\\\")\", (cmdline:gsub(\"[\\\\\\\"]\", function (w) return \"\\\\\" .. w end)))\n    end\n\n    -- save the macro end\n    file:print(\"end\")\n\n    -- exit the macro file\n    file:close()\n\n    -- show this macro\n    _show(macroname)\n\n    -- trace\n    cprint(\"${color.success}define macro(%s) ok!\", macroname)\nend\n\n-- run macro\nfunction _run(macroname)\n\n    -- run last command?\n    if macroname == \"..\" then\n\n        -- load the history: cmdlines\n        local cmdlines = localcache.get(\"history\", \"cmdlines\")\n\n        -- get the last command\n        local lastcmd = nil\n        if cmdlines then\n            local total = #cmdlines\n            local index = total\n            while index ~= 0 do\n\n                -- ignore \"xmake m ..\" and \"xmake macro ..\"\n                local cmdline = cmdlines[index]\n                if not cmdline:startswith(\"__macro_\") and not cmdline:find(\"xmake%s+macro%s*\") and not cmdline:find(\"xmake%s+m%s*\") then\n                    lastcmd = cmdline\n                    break\n                end\n\n                -- the previous line\n                index = index - 1\n            end\n        end\n\n        -- run the last command\n        if lastcmd then\n            os.exec(lastcmd)\n        end\n        return\n    end\n\n    -- is anonymous?\n    if macroname == '.' then\n        macroname = \"anonymous\"\n    end\n\n    -- run macro\n    import(macroname, {rootdir = _directory(macroname), anonymous = true})(option.get(\"arguments\") or {})\nend\n\n-- main\nfunction main()\n\n    -- list macros\n    if option.get(\"list\") then\n\n        _list()\n\n    -- show macro\n    elseif option.get(\"show\") then\n\n        _show(option.get(\"name\"))\n\n    -- clear macro\n    elseif option.get(\"clear\") then\n\n        _clear()\n\n    -- delete macro\n    elseif option.get(\"delete\") then\n\n        _delete(option.get(\"name\"))\n\n    -- import macro\n    elseif option.get(\"import\") then\n\n        _import(option.get(\"import\"), option.get(\"name\"))\n\n    -- export macro\n    elseif option.get(\"export\") then\n\n        _export(option.get(\"export\"), option.get(\"name\"))\n\n    -- begin to record macro\n    elseif option.get(\"begin\") then\n\n        _begin()\n\n    -- end to record macro\n    elseif option.get(\"end\") then\n\n        _end(option.get(\"name\"))\n\n    -- run macro\n    else\n        _run(option.get(\"name\"))\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/macro/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        macro.lua\n--\n\n-- define task\ntask(\"macro\")\n\n    -- set category\n    set_category(\"plugin\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake macro|m [options] [name] [arguments]\"\n\n                -- description\n            ,   description = \"Run the given macro.\"\n\n                -- xmake m\n            ,   shortname = 'm'\n\n                -- options\n            ,   options =\n                {\n                    {'b', \"begin\",      \"k\",  nil,  \"Start to record macro.\"\n                                                ,   \"e.g.\"\n                                                ,   \"Record macro with name: test\"\n                                                ,   \"    xmake macro --begin\"\n                                                ,   \"    xmake config --plat=macosx\"\n                                                ,   \"    xmake clean\"\n                                                ,   \"    xmake -r\"\n                                                ,   \"    xmake package\"\n                                                ,   \"    xmake macro --end test\"                    }\n                ,   {'e', \"end\",        \"k\",  nil,  \"Stop to record macro.\"                         }\n                ,   {}\n                ,   {nil, \"show\",       \"k\",  nil,  \"Show the content of the given macro.\"          }\n                ,   {'l', \"list\",       \"k\",  nil,  \"List all macros.\"                              }\n                ,   {'d', \"delete\",     \"k\",  nil,  \"Delete the given macro.\"                       }\n                ,   {'c', \"clear\",      \"k\",  nil,  \"Clear the all macros.\"                         }\n                ,   {}\n                ,   {nil, \"import\",     \"kv\", nil,  \"Import the given macro file or directory.\"\n                                                ,   \"e.g.\"\n                                                ,   \"    xmake macro --import=/xxx/macro.lua test\"\n                                                ,   \"    xmake macro --import=/xxx/macrodir\"        }\n                ,   {nil, \"export\",     \"kv\", nil,  \"Export the given macro to file or directory.\"\n                                                ,   \"e.g.\"\n                                                ,   \"    xmake macro --export=/xxx/macro.lua test\"\n                                                ,   \"    xmake macro --export=/xxx/macrodir\"        }\n                ,   {}\n                ,   {nil, \"name\",       \"v\",  \".\",  \"Set the macro name.\"\n                                                ,   \"e.g.\"\n                                                ,   \"   Run the given macro:     xmake macro test\"\n                                                ,   \"   Run the anonymous macro: xmake macro .\"\n                                                ,   \"   Run the last command:    xmake macro ..\"\n                                                ,   values = function (complete, opt)\n                                                        -- hide in help menu\n                                                        if not complete then return end\n                                                        -- don't need name\n                                                        if opt.begin or opt.list or opt.clear then return end\n                                                        -- name should be given by user\n                                                        if opt[\"end\"] or opt.import then return end\n\n                                                        return import(\"main.macros\")(\".\")\n                                                    end                                             }\n                ,   {nil, \"arguments\",  \"vs\", nil,  \"Set the macro arguments.\"                      }\n                }\n            }\n"
  },
  {
    "path": "xmake/plugins/pack/appimage/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\".batchcmds\")\n\n-- handle icon file\nfunction _handle_icon(package, appdir, appname)\n    local iconname = nil\n    local iconfile = package:get(\"iconfile\")\n    if iconfile then\n        local iconpath = path.absolute(iconfile)\n        if not os.isfile(iconpath) then\n            raise(\"icon file not found: %s\", iconfile)\n        end\n        local ext = path.extension(iconpath)\n        -- AppImage only supports .png, .svg, .xpm\n        if ext ~= \".png\" and ext ~= \".svg\" and ext ~= \".xpm\" then\n            raise(\"appimage format only supports .png, .svg, or .xpm icon files, but got: %s\", ext)\n        end\n        iconname = appname .. ext\n        -- copy to AppDir root (required for AppImage)\n        os.cp(iconpath, path.join(appdir, iconname))\n        -- also copy to standard location\n        local iconsdir = path.join(appdir, \"usr\", \"share\", \"icons\", \"hicolor\", \"256x256\", \"apps\")\n        os.mkdir(iconsdir)\n        os.cp(iconpath, path.join(iconsdir, iconname))\n    end\n    return iconname\nend\n\n-- create desktop file\nfunction _create_desktop_file(package, appdir, appname, apptitle, appdescription, main_executable, iconname)\n    local desktopfile = path.join(appdir, appname .. \".desktop\")\n    local icon_line = \"\"\n    if iconname then\n        icon_line = string.format(\"Icon=%s\\n\", appname)\n    end\n    local version_line = \"\"\n    local version = package:version()\n    if version then\n        version_line = string.format(\"X-AppImage-Version=%s\\n\", version)\n    end\n    local desktop_content = string.format([[\n[Desktop Entry]\nType=Application\nName=%s\nComment=%s\nExec=usr/bin/%s\n%s%sCategories=Utility;\n]], apptitle, appdescription, main_executable, icon_line, version_line)\n    io.writefile(desktopfile, desktop_content)\nend\n\n-- create AppRun script\nfunction _create_apprun_script(appdir, main_executable)\n    local apprun = path.join(appdir, \"AppRun\")\n    local apprun_content = string.format([[\n#!/bin/bash\nHERE=\"$(dirname \"$(readlink -f \"${0}\")\")\"\nexec \"${HERE}/usr/bin/%s\" \"$@\"\n]], main_executable)\n    io.writefile(apprun, apprun_content)\n    os.vrunv(\"chmod\", {\"+x\", apprun})\nend\n\n-- get the appimagetool\nfunction _get_appimagetool()\n\n    -- enter the environments of appimagetool\n    local oldenvs = packagenv.enter(\"appimagetool\")\n\n    -- find appimagetool\n    local packages = {}\n    local appimagetool = find_tool(\"appimagetool\")\n    if not appimagetool then\n        table.join2(packages, install_packages(\"appimagetool\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not appimagetool then\n        appimagetool = find_tool(\"appimagetool\", {force = true})\n    end\n    assert(appimagetool, \"appimagetool not found!\")\n    return appimagetool, oldenvs\nend\n\n-- get main executable from package\nfunction _get_main_executable(package, usrdir)\n    local main_executable = nil\n    local main_executable_path = nil\n    \n    -- try to find from targets first\n    for _, target in ipairs(package:targets()) do\n        if target:is_binary() then\n            main_executable = target:basename()\n            -- check if file exists in usr/bin\n            local exec_path = path.join(usrdir, \"bin\", main_executable)\n            if os.isfile(exec_path) then\n                main_executable_path = exec_path\n                break\n            end\n        end\n    end\n    \n    -- fallback: find in bindir\n    if not main_executable_path then\n        local bindir = package:bindir()\n        if bindir and os.isdir(bindir) then\n            -- find executable files in bindir using os.files callback\n            os.files(path.join(bindir, \"*\"), function (file, isdir)\n                if not isdir and os.isfile(file) and not os.islink(file) and os.isexec(file) then\n                    main_executable = path.filename(file)\n                    main_executable_path = path.join(usrdir, \"bin\", main_executable)\n                    if os.isfile(main_executable_path) then\n                        return false\n                    end\n                end\n                return true\n            end)\n        end\n    end\n    \n    return main_executable, main_executable_path\nend\n\n-- pack appimage package\nfunction _pack_appimage(package, appimagetool)\n\n    -- check platform\n    assert(package:is_plat(\"linux\"), \"appimage format only supports Linux platform!\")\n\n    -- archive binary files\n    batchcmds.get_installcmds(package):runcmds()\n    for _, component in table.orderpairs(package:components()) do\n        if component:get(\"default\") ~= false then\n            batchcmds.get_installcmds(component):runcmds()\n        end\n    end\n\n    -- get install root directory\n    local rootdir = package:install_rootdir()\n    assert(os.isdir(rootdir), \"install root directory not found: %s\", rootdir)\n\n    -- get output file\n    local outputfile = package:outputfile()\n    os.tryrm(outputfile)\n\n    -- create AppDir directory structure\n    local builddir = package:builddir()\n    local appdir = path.join(builddir, \"AppDir\")\n    os.tryrm(appdir)\n    os.mkdir(appdir)\n\n    -- copy files to AppDir/usr\n    local usrdir = path.join(appdir, \"usr\")\n    os.cp(rootdir, usrdir)\n\n    -- get main executable\n    local main_executable, main_executable_path = _get_main_executable(package, usrdir)\n    assert(main_executable and main_executable_path and os.isfile(main_executable_path), \n           \"main executable not found! Please ensure at least one binary target is added to xpack.\")\n\n    -- get application name and title\n    local appname = package:name()\n    local apptitle = package:title() or appname\n    local appdescription = package:description() or \"\"\n\n    -- handle icon file\n    local iconname = _handle_icon(package, appdir, appname)\n\n    -- create desktop file\n    _create_desktop_file(package, appdir, appname, apptitle, appdescription, main_executable, iconname)\n\n    -- create AppRun script\n    _create_apprun_script(appdir, main_executable)\n\n    -- create AppImage using appimagetool\n    os.vrunv(appimagetool, {appdir, outputfile}, {envs = {APPIMAGE_EXTRACT_AND_RUN = \"1\"}})\n\n    -- verify AppImage was created\n    assert(os.isfile(outputfile), \"generate %s failed!\", outputfile)\nend\n\nfunction main(package)\n\n    -- only for linux\n    if not is_host(\"linux\") then\n        return\n    end\n\n    cprint(\"packing %s .. \", package:outputfile())\n\n    -- get appimagetool\n    local appimagetool, oldenvs = _get_appimagetool()\n\n    -- pack appimage package\n    _pack_appimage(package, appimagetool.program)\n\n    -- done\n    os.setenvs(oldenvs)\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/archive.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        archive.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"utils.archive\")\nimport(\"batchcmds\")\n\n-- pack archive package\nfunction _pack_archive(package)\n\n    -- archive source files\n    if package:from_source() then\n        local srcfiles, dstfiles = package:sourcefiles()\n        for idx, srcfile in ipairs(srcfiles) do\n            os.vcp(srcfile, dstfiles[idx])\n        end\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                local srcfiles, dstfiles = component:sourcefiles()\n                for idx, srcfile in ipairs(srcfiles) do\n                    os.vcp(srcfile, dstfiles[idx])\n                end\n            end\n        end\n    else\n        -- archive binary files\n        batchcmds.get_installcmds(package):runcmds()\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                batchcmds.get_installcmds(component):runcmds()\n            end\n        end\n    end\n\n    -- archive install files\n    local rootdir = package:from_source() and package:source_rootdir() or package:install_rootdir()\n    local oldir = os.cd(rootdir)\n    local archivefiles = os.files(\"**\")\n    os.cd(oldir)\n    os.tryrm(package:outputfile())\n    archive.archive(path.absolute(package:outputfile()), archivefiles, {curdir = rootdir, compress = \"best\"})\nend\n\nfunction main(package)\n    cprint(\"packing %s .. \", package:outputfile())\n    _pack_archive(package)\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/batchcmds.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        batchcmds.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.project\")\nimport(\"utils.archive\")\nimport(\"utils.binary.deplibs\", {alias = \"get_depend_libraries\"})\nimport(\"private.utils.batchcmds\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- get target bindir\nfunction _get_target_bindir(package, target)\n    local bindir = package:bindir()\n    local prefixdir = target:prefixdir()\n    if prefixdir then\n        bindir = path.join(package:installdir(), prefixdir, target:extraconf(\"prefixdir\", prefixdir, \"bindir\") or \"bin\")\n    end\n    return path.normalize(bindir)\nend\n\n-- get target libdir\nfunction _get_target_libdir(package, target)\n    local libdir = package:libdir()\n    local prefixdir = target:prefixdir()\n    if prefixdir then\n        libdir = path.join(package:installdir(), prefixdir, target:extraconf(\"prefixdir\", prefixdir, \"libdir\") or \"lib\")\n    end\n    return path.normalize(libdir)\nend\n\n-- get target includedir\nfunction _get_target_includedir(package, target)\n    local includedir = package:includedir()\n    local prefixdir = target:prefixdir()\n    if prefixdir then\n        includedir = path.join(package:installdir(), prefixdir, target:extraconf(\"prefixdir\", prefixdir, \"includedir\") or \"include\")\n    end\n    return path.normalize(includedir)\nend\n\n-- get target installdir\nfunction _get_target_installdir(package, target)\n    local installdir = package:installdir()\n    local prefixdir = target:prefixdir()\n    if prefixdir then\n        installdir = path.join(package:installdir(), prefixdir)\n    end\n    return path.normalize(installdir)\nend\n\n\n\n\n\n-- copy file with symlinks\nfunction _copy_file_with_symlinks(batchcmds_, srcfile, outputdir)\n    if os.islink(srcfile) then\n        local srcfile_symlink = os.readlink(srcfile)\n        if not path.is_absolute(srcfile_symlink) then\n            srcfile_symlink = path.join(path.directory(srcfile), srcfile_symlink)\n        end\n        _copy_file_with_symlinks(batchcmds_, srcfile_symlink, outputdir)\n        batchcmds_:cp(srcfile, path.join(outputdir, path.filename(srcfile)), {symlink = true, force = true})\n    else\n        batchcmds_:cp(srcfile, path.join(outputdir, path.filename(srcfile)))\n    end\nend\n\n\n\n-- install target files\nfunction install_target_files(target, batchcmds_, opt)\n    local package = opt.package\n    local srcfiles, dstfiles = target:installfiles(_get_target_installdir(package, target))\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            batchcmds_:cp(srcfile, dstfiles[idx], {symlink = true})\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcfiles, dstfiles = dep:installfiles(_get_target_installdir(package, dep), {interface = true})\n        if srcfiles and dstfiles then\n            for idx, srcfile in ipairs(srcfiles) do\n                batchcmds_:cp(srcfile, dstfiles[idx], {symlink = true})\n            end\n        end\n    end\nend\n\n-- install target headers\nfunction _install_target_headers(target, batchcmds_, opt)\n    local package = opt.package\n    local srcheaders, dstheaders = target:headerfiles(_get_target_includedir(package, target), {installonly = true})\n    if srcheaders and dstheaders then\n        for idx, srcheader in ipairs(srcheaders) do\n            batchcmds_:cp(srcheader, dstheaders[idx])\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcheaders, dstheaders = dep:headerfiles(_get_target_includedir(package, dep), {installonly = true, interface = true})\n        if srcheaders and dstheaders then\n            for idx, srcheader in ipairs(srcheaders) do\n                batchcmds_:cp(srcheader, dstheaders[idx])\n            end\n        end\n    end\nend\n\n-- install target shared libraries\nfunction install_target_shared_libraries(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = opt.bindir or (target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(package, target) or _get_target_libdir(package, target))\n\n    -- get all dependent shared libraries\n    local libfiles = {}\n    target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {})\n    libfiles = table.unique(libfiles)\n\n    -- do install\n    for _, libfile in ipairs(libfiles) do\n        _copy_file_with_symlinks(batchcmds_, libfile, bindir)\n    end\nend\n\n-- uninstall target files\nfunction _uninstall_target_files(target, batchcmds_, opt)\n    local package = opt.package\n    local _, dstfiles = target:installfiles(_get_target_installdir(package, target))\n    for _, dstfile in ipairs(dstfiles) do\n        batchcmds_:rm(dstfile, {emptydirs = true})\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local _, dstfiles = dep:installfiles(_get_target_installdir(package, dep), {interface = true})\n        for _, dstfile in ipairs(dstfiles) do\n            batchcmds_:rm(dstfile, {emptydirs = true})\n        end\n    end\nend\n\n-- uninstall target headers\nfunction _uninstall_target_headers(target, batchcmds_, opt)\n    local package = opt.package\n    local _, dstheaders = target:headerfiles(_get_target_includedir(package, target), {installonly = true})\n    for _, dstheader in ipairs(dstheaders) do\n        batchcmds_:rm(dstheader, {emptydirs = true})\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local _, dstheaders = dep:headerfiles(_get_target_includedir(package, dep), {installonly = true, interface = true})\n        for _, dstheader in ipairs(dstheaders) do\n            batchcmds_:rm(dstheader, {emptydirs = true})\n        end\n    end\nend\n\n-- uninstall target shared libraries\nfunction _uninstall_target_shared_libraries(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(package, target) or _get_target_libdir(package, target)\n\n    -- get all dependent shared libraries\n    local libfiles = {}\n    target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {})\n    libfiles = table.unique(libfiles)\n\n    -- do uninstall\n    for _, libfile in ipairs(libfiles) do\n        local filename = path.filename(libfile)\n        batchcmds_:rm(path.join(bindir, filename), {emptydirs = true})\n    end\nend\n\n-- update install rpath, we can only get and update rpathdirs with `{installonly = true}`\n-- e.g. add_rpathdirs(\"@loader_path/../lib\", {installonly = true})\nfunction update_target_install_rpath(target, batchcmds, opt)\n    if target:is_plat(\"windows\", \"mingw\") then\n        return\n    end\n    local package = opt.package\n    local bindir = _get_target_bindir(package, target)\n    local targetfile = path.join(bindir, target:filename())\n    if target:policy(\"install.rpath\") then\n        batchcmds:clean_rpath(targetfile, {plat = target:plat(), arch = target:arch()})\n        local result, sources = target:get_from(\"rpathdirs\", \"*\")\n        if result and sources then\n            for idx, rpathdirs in ipairs(result) do\n                local source = sources[idx]\n                local extraconf = target:extraconf_from(\"rpathdirs\", source)\n                if extraconf then\n                    for _, rpathdir in ipairs(rpathdirs) do\n                        local extra = extraconf[rpathdir]\n                        if extra and extra.installonly then\n                            batchcmds:insert_rpath(targetfile, rpathdir, {plat = target:plat(), arch = target:arch()})\n                        end\n                    end\n                end\n            end\n        end\n    end\nend\n\n-- on install binary target command\nfunction _on_target_installcmd_binary(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = _get_target_bindir(package, target)\n    batchcmds_:cp(target:targetfile(), path.join(bindir, target:filename()))\n    if os.isfile(target:symbolfile()) then\n        batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))\n    end\n    install_target_shared_libraries(target, batchcmds_, opt)\n    update_target_install_rpath(target, batchcmds_, opt)\nend\n\n-- on install shared target command\nfunction _on_target_installcmd_shared(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(package, target) or _get_target_libdir(package, target)\n    local libdir = _get_target_libdir(package, target)\n\n    _copy_file_with_symlinks(batchcmds_, target:targetfile(), bindir)\n    if os.isfile(target:symbolfile()) then\n        batchcmds_:cp(target:symbolfile(), path.join(bindir, path.filename(target:symbolfile())))\n    end\n\n    -- install *.lib for shared/windows (*.dll) target\n    -- @see https://github.com/xmake-io/xmake/issues/714\n    local implibfile = target:artifactfile(\"implib\")\n    if implibfile and os.isfile(implibfile) then\n        batchcmds_:mkdir(libdir)\n        batchcmds_:cp(implibfile, path.join(libdir, path.filename(implibfile)))\n    end\n\n    _install_target_headers(target, batchcmds_, opt)\n    install_target_shared_libraries(target, batchcmds_, opt)\nend\n\n-- on install static target command\nfunction _on_target_installcmd_static(target, batchcmds_, opt)\n    local package = opt.package\n    local libdir = _get_target_libdir(package, target)\n\n    batchcmds_:cp(target:targetfile(), path.join(libdir, target:filename()))\n    if os.isfile(target:symbolfile()) then\n        batchcmds_:cp(target:symbolfile(), path.join(libdir, path.filename(target:symbolfile())))\n    end\n\n    _install_target_headers(target, batchcmds_, opt)\nend\n\n-- on install headeronly target command\nfunction _on_target_installcmd_headeronly(target, batchcmds_, opt)\n    _install_target_headers(target, batchcmds_, opt)\nend\n\n-- on install source target command\nfunction _on_target_installcmd_source(target, batchcmds_, opt)\n    local package = opt.package\n    batchcmds_:vrunv(\"xmake\", {\"install\", \"-P\", \".\", \"-y\", \"-o\", path(package:install_rootdir()), target:name()})\nend\n\n-- on build target command\nfunction _on_target_buildcmd(target, batchcmds_, opt)\n    local package = opt.package\n    batchcmds_:vrunv(\"xmake\", {\"build\", \"-P\", \".\",  \"-y\", target:name()})\nend\n\n-- on install target command\nfunction _on_target_installcmd(target, batchcmds_, opt)\n    local package = opt.package\n    if package:from_source() then\n        _on_target_installcmd_source(target, batchcmds_, opt)\n        return\n    end\n\n    -- check if target rules have on_installcmd, use rule's logic first\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_installcmd = r:script(\"installcmd\")\n        if on_installcmd then\n            on_installcmd(target, batchcmds_, opt)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- install target binaries\n    local scripts = {\n        binary     = _on_target_installcmd_binary,\n        shared     = _on_target_installcmd_shared,\n        static     = _on_target_installcmd_static,\n        headeronly = _on_target_installcmd_headeronly\n    }\n    local script = scripts[target:kind()]\n    if script then\n        script(target, batchcmds_, opt)\n    end\n\n    -- install target files\n    install_target_files(target, batchcmds_, opt)\nend\n\n-- on uninstall binary target command\nfunction _on_target_uninstallcmd_binary(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = _get_target_bindir(package, target)\n\n    -- uninstall target file\n    batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true})\n    batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true})\n\n    -- uninstall target shared libraries\n    _uninstall_target_shared_libraries(target, batchcmds_, opt)\nend\n\n-- on uninstall shared target command\nfunction _on_target_uninstallcmd_shared(target, batchcmds_, opt)\n    local package = opt.package\n    local bindir = target:is_plat(\"windows\", \"mingw\") and _get_target_bindir(package, target) or _get_target_libdir(package, target)\n    local libdir = _get_target_libdir(package, target)\n\n    -- uninstall target file\n    batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true})\n    batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true})\n\n    -- uninstall *.lib for shared/windows (*.dll) target\n    -- @see https://github.com/xmake-io/xmake/issues/714\n    local targetfile = target:targetfile()\n    batchcmds_:rm(path.join(libdir, path.basename(targetfile) .. (target:is_plat(\"mingw\") and \".dll.a\" or \".lib\")), {emptydirs = true})\n\n    -- uninstall target headers\n    _uninstall_target_headers(target, batchcmds_, opt)\n\n    -- uninstall target shared libraries\n    _uninstall_target_shared_libraries(target, batchcmds_, opt)\nend\n\n-- on uninstall static target command\nfunction _on_target_uninstallcmd_static(target, batchcmds_, opt)\n    local package = opt.package\n    local libdir = _get_target_libdir(package, target)\n\n    -- uninstall target file\n    batchcmds_:rm(path.join(libdir, target:filename()), {emptydirs = true})\n    batchcmds_:rm(path.join(libdir, path.filename(target:symbolfile())), {emptydirs = true})\n\n    -- remove headers from the include directory\n    _uninstall_target_headers(target, batchcmds_, opt)\nend\n\n-- on uninstall headeronly target command\nfunction _on_target_uninstallcmd_headeronly(target, batchcmds_, opt)\n    _uninstall_target_headers(target, batchcmds_, opt)\nend\n\n-- on uninstall source target command\nfunction _on_target_uninstallcmd_source(target, batchcmds_, opt)\n    -- TODO\nend\n\n-- on uninstall target command\nfunction _on_target_uninstallcmd(target, batchcmds_, opt)\n    local package = opt.package\n    if package:from_source() then\n        _on_target_uninstallcmd_source(target, batchcmds_, opt)\n        return\n    end\n\n    -- check if target rules have on_uninstallcmd, use rule's logic first\n    local done = false\n    for _, r in ipairs(target:orderules()) do\n        local on_uninstallcmd = r:script(\"uninstallcmd\")\n        if on_uninstallcmd then\n            on_uninstallcmd(target, batchcmds_, opt)\n            done = true\n        end\n    end\n    if done then return end\n\n    -- uninstall target binaries\n    local scripts = {\n        binary     = _on_target_uninstallcmd_binary,\n        shared     = _on_target_uninstallcmd_shared,\n        static     = _on_target_uninstallcmd_static,\n        headeronly = _on_target_uninstallcmd_headeronly\n    }\n    local script = scripts[target:kind()]\n    if script then\n        script(target, batchcmds_, opt)\n    end\n\n    -- uninstall target files\n    _uninstall_target_files(target, batchcmds_, opt)\nend\n\n-- get build commands from targets\nfunction _get_target_buildcmds(target, batchcmds_, opt)\n\n    -- call script to get build commands\n    local scripts = {\n        target:script(\"buildcmd_before\"), -- TODO unused\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_buildcmd = r:script(\"buildcmd_before\")\n                if before_buildcmd then\n                    before_buildcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"buildcmd\", _on_target_buildcmd), -- TODO unused\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_buildcmd = r:script(\"buildcmd_after\")\n                if after_buildcmd then\n                    after_buildcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"buildcmd_after\") -- TODO unused\n    }\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target, batchcmds_, opt)\n        end\n    end\nend\n\n-- get install commands from targets\nfunction _get_target_installcmds(target, batchcmds_, opt)\n\n    -- call script to get install commands\n    local scripts = {\n        target:script(\"installcmd_before\"),\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_installcmd = r:script(\"installcmd_before\")\n                if before_installcmd then\n                    before_installcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"installcmd\", _on_target_installcmd),\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_installcmd = r:script(\"installcmd_after\")\n                if after_installcmd then\n                    after_installcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"installcmd_after\")\n    }\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target, batchcmds_, opt)\n        end\n    end\nend\n\n-- get uninstall commands from targets\nfunction _get_target_uninstallcmds(target, batchcmds_, opt)\n\n    -- call script to get uninstall commands\n    local scripts = {\n        target:script(\"uninstallcmd_before\"),\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local before_uninstallcmd = r:script(\"uninstallcmd_before\")\n                if before_uninstallcmd then\n                    before_uninstallcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"uninstallcmd\", _on_target_uninstallcmd),\n        function (target)\n            for _, r in ipairs(target:orderules()) do\n                local after_uninstallcmd = r:script(\"uninstallcmd_after\")\n                if after_uninstallcmd then\n                    after_uninstallcmd(target, batchcmds_, opt)\n                end\n            end\n        end,\n        target:script(\"uninstallcmd_after\")\n    }\n    for i = 1, 5 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(target, batchcmds_, opt)\n        end\n    end\nend\n\n-- on build command\nfunction _on_buildcmd(package, batchcmds_)\n    if not package:from_source() then\n        return\n    end\n    for _, target in ipairs(package:targets()) do\n        _get_target_buildcmds(target, batchcmds_, {package = package})\n    end\nend\n\n-- on install command\nfunction _on_installcmd(package, batchcmds_)\n    local srcfiles, dstfiles = package:installfiles()\n    for idx, srcfile in ipairs(srcfiles) do\n        batchcmds_:cp(srcfile, dstfiles[idx], {symlink = true})\n    end\n    for _, target in ipairs(package:targets()) do\n        _get_target_installcmds(target, batchcmds_, {package = package})\n    end\nend\n\n-- on uninstall command\nfunction _on_uninstallcmd(package, batchcmds_)\n    local _, dstfiles = package:installfiles()\n    for _, dstfile in ipairs(dstfiles) do\n        batchcmds_:rm(dstfile, {emptydirs = true})\n    end\n    for _, target in ipairs(package:targets()) do\n        _get_target_uninstallcmds(target, batchcmds_, {package = package})\n    end\nend\n\n-- get build commands\nfunction get_buildcmds(package)\n    local batchcmds_ = batchcmds.new()\n\n    -- call script to get build commands\n    local scripts = {\n        package:script(\"buildcmd_before\"),\n        package:script(\"buildcmd\", _on_buildcmd),\n        package:script(\"buildcmd_after\")\n    }\n    for i = 1, 3 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(package, batchcmds_)\n        end\n    end\n    return batchcmds_\nend\n\n-- get install commands\nfunction get_installcmds(package)\n    local batchcmds_ = batchcmds.new()\n\n    -- call script to get install commands\n    local scripts = {\n        package:script(\"installcmd_before\"),\n        package:script(\"installcmd\", _on_installcmd),\n        package:script(\"installcmd_after\")\n    }\n    for i = 1, 3 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(package, batchcmds_)\n        end\n    end\n    return batchcmds_\nend\n\n-- get uninstall commands\nfunction get_uninstallcmds(package)\n    local batchcmds_ = batchcmds.new()\n\n    -- call script to get uninstall commands\n    local scripts = {\n        package:script(\"uninstallcmd_before\"),\n        package:script(\"uninstallcmd\", _on_uninstallcmd),\n        package:script(\"uninstallcmd_after\")\n    }\n    for i = 1, 3 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(package, batchcmds_)\n        end\n    end\n    return batchcmds_\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/deb/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\"utils.archive\")\nimport(\".batchcmds\")\n\n-- get the debuild\nfunction _get_debuild()\n    local debuild = find_tool(\"debuild\", {force = true})\n    assert(debuild, \"debuild not found, please run `sudo apt install devscripts` to install it!\")\n    return debuild\nend\n\n-- get archive file\nfunction _get_archivefile(package)\n    return path.absolute(path.join(path.directory(package:sourcedir()), package:name() .. \"_\" .. package:version() .. \".orig.tar.gz\"))\nend\n\n-- translate the file path\nfunction _translate_filepath(package, filepath)\n    return filepath:replace(package:install_rootdir(), \"$(PREFIX)\", {plain = true})\nend\n\n-- get install command\nfunction _get_customcmd(package, installcmds, cmd)\n    local opt = cmd.opt or {}\n    local kind = cmd.kind\n    if kind == \"cp\" then\n        local srcfiles = os.files(cmd.srcpath)\n        for _, srcfile in ipairs(srcfiles) do\n            -- the destination is directory? append the filename\n            local dstfile = _translate_filepath(package, cmd.dstpath)\n            if #srcfiles > 1 or path.islastsep(dstfile) then\n                if opt.rootdir then\n                    dstfile = path.join(dstfile, path.relative(srcfile, opt.rootdir))\n                else\n                    dstfile = path.join(dstfile, path.filename(srcfile))\n                end\n            end\n            table.insert(installcmds, string.format(\"install -Dpm0644 \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile))\n        end\n    elseif kind == \"rm\" then\n        local filepath = _translate_filepath(package, cmd.filepath)\n        table.insert(installcmds, string.format(\"rm -f \\\"%s\\\"\", filepath))\n    elseif kind == \"rmdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"rm -rf \\\"%s\\\"\", dir))\n    elseif kind == \"mv\" then\n        local srcpath = _translate_filepath(package, cmd.srcpath)\n        local dstpath = _translate_filepath(package, cmd.dstpath)\n        table.insert(installcmds, string.format(\"mv \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile))\n    elseif kind == \"cd\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"cd \\\"%s\\\"\", dir))\n    elseif kind == \"mkdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"mkdir -p \\\"%s\\\"\", dir))\n    elseif cmd.program then\n        local argv = {}\n        for _, arg in ipairs(cmd.argv) do\n            if path.instance_of(arg) then\n                arg = arg:clone():set(_translate_filepath(package, arg:rawstr())):str()\n            elseif path.is_absolute(arg) then\n                arg = _translate_filepath(package, arg)\n            end\n            table.insert(argv, arg)\n        end\n        table.insert(installcmds, string.format(\"%s\", os.args(table.join(cmd.program, argv))))\n    end\nend\n\n-- get build commands\nfunction _get_buildcmds(package, buildcmds, cmds)\n    for _, cmd in ipairs(cmds) do\n        _get_customcmd(package, buildcmds, cmd)\n    end\nend\n\n-- get install commands\nfunction _get_installcmds(package, installcmds, cmds)\n    for _, cmd in ipairs(cmds) do\n        _get_customcmd(package, installcmds, cmd)\n    end\nend\n\n-- get uninstall commands\nfunction _get_uninstallcmds(package, uninstallcmds, cmds)\n    for _, cmd in ipairs(cmds) do\n        _get_customcmd(package, uninstallcmds, cmd)\n    end\nend\n\n-- get specvars\nfunction _get_specvars(package)\n    local specvars = table.clone(package:specvars())\n    local datestr = os.iorunv(\"date\", {\"-u\", \"+%a, %d %b %Y %H:%M:%S +0000\"}, {envs = {LC_TIME = \"en_US\"}})\n    if datestr then\n        datestr = datestr:trim()\n    end\n    specvars.PACKAGE_DATE = datestr or \"\"\n    local author = package:get(\"author\") or \"unknown <unknown@unknown.com>\"\n    specvars.PACKAGE_COPYRIGHT = os.date(\"%Y\") .. \" \" .. author\n    specvars.PACKAGE_INSTALLCMDS = function ()\n        local prefixdir = package:get(\"prefixdir\")\n        package:set(\"prefixdir\", nil)\n        local installcmds = {}\n        _get_installcmds(package, installcmds, batchcmds.get_installcmds(package):cmds())\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                _get_installcmds(package, installcmds, batchcmds.get_installcmds(component):cmds())\n            end\n        end\n        package:set(\"prefixdir\", prefixdir)\n        return table.concat(installcmds, \"\\n\\t\")\n    end\n    specvars.PACKAGE_UNINSTALLCMDS = function ()\n        local uninstallcmds = {}\n        _get_uninstallcmds(package, uninstallcmds, batchcmds.get_uninstallcmds(package):cmds())\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                _get_uninstallcmds(package, uninstallcmds, batchcmds.get_uninstallcmds(component):cmds())\n            end\n        end\n        return table.concat(uninstallcmds, \"\\n\\t\")\n    end\n    specvars.PACKAGE_BUILDCMDS = function ()\n        local buildcmds = {}\n        _get_buildcmds(package, buildcmds, batchcmds.get_buildcmds(package):cmds())\n        return table.concat(buildcmds, \"\\n\\t\")\n    end\n    specvars.PACKAGE_BUILDREQUIRES = function ()\n        local requires = {}\n        local buildrequires = package:get(\"buildrequires\")\n        if buildrequires then\n            for _, buildrequire in ipairs(buildrequires) do\n                table.insert(requires, buildrequire)\n            end\n        else\n            local programs = hashset.new()\n            for _, cmd in ipairs(batchcmds.get_buildcmds(package):cmds()) do\n                local program = cmd.program\n                if program then\n                    programs:insert(program)\n                end\n            end\n            local map = {\n                xmake = \"xmake\",\n                cmake = \"cmake\",\n                make = \"make\"\n            }\n            for _, program in programs:keys() do\n                local requirename = map[program]\n                if requirename then\n                    table.insert(requires, requirename)\n                end\n            end\n        end\n        return table.concat(requires, \", \")\n    end\n    return specvars\nend\n\n-- pack deb package\nfunction _pack_deb(debuild, package)\n\n    -- install the initial debian directory\n    local sourcedir = package:sourcedir()\n    local debiandir = path.join(sourcedir, \"debian\")\n    if not os.isdir(debiandir) then\n        local debiandir_template = package:get(\"specfile\") or path.join(os.programdir(), \"scripts\", \"xpack\", \"deb\", \"debian\")\n        os.cp(debiandir_template, debiandir, {writeable = true})\n    end\n\n    -- replace variables in specfile\n    -- and we need to avoid `attempt to yield across a C-call boundary` in io.gsub\n    local specvars = _get_specvars(package)\n    local pattern = package:extraconf(\"specfile\", \"pattern\") or \"%${([^\\n]-)}\"\n    local specvars_names = {}\n    local specvars_values = {}\n    for _, specfile in ipairs(os.files(path.join(debiandir, \"**\"))) do\n        io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n            table.insert(specvars_names, name)\n        end)\n    end\n    for _, name in ipairs(specvars_names) do\n        name = name:trim()\n        if specvars_values[name] == nil then\n            local value = specvars[name]\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if value ~= nil then\n                dprint(\"[%s]:  > replace %s -> %s\", path.filename(specfile), name, value)\n            end\n            if type(value) == \"table\" then\n                dprint(\"invalid variable value\", value)\n            end\n            specvars_values[name] = value\n        end\n    end\n    for _, specfile in ipairs(os.files(path.join(debiandir, \"**\"))) do\n        io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n            name = name:trim()\n            return specvars_values[name]\n        end)\n    end\n\n    -- archive source files\n    local srcfiles, dstfiles = package:sourcefiles()\n    for idx, srcfile in ipairs(srcfiles) do\n        os.vcp(srcfile, dstfiles[idx])\n    end\n    for _, component in table.orderpairs(package:components()) do\n        if component:get(\"default\") ~= false then\n            local srcfiles, dstfiles = component:sourcefiles()\n            for idx, srcfile in ipairs(srcfiles) do\n                os.vcp(srcfile, dstfiles[idx])\n            end\n        end\n    end\n\n    -- archive install files\n    local rootdir = package:source_rootdir()\n    local oldir = os.cd(rootdir)\n    local archivefiles = os.files(\"**\")\n    os.cd(oldir)\n    local archivefile = _get_archivefile(package)\n    os.tryrm(archivefile)\n    archive.archive(archivefile, archivefiles, {curdir = rootdir, compress = \"best\"})\n\n    -- build package\n    os.vrunv(debuild, {\"-us\", \"-uc\"}, {curdir = sourcedir})\n\n    -- copy deb file\n    os.vcp(path.join(path.directory(sourcedir), \"*.deb\"), package:outputfile())\nend\n\nfunction main(package)\n    if not is_host(\"linux\") then\n        return\n    end\n\n    cprint(\"packing %s\", package:outputfile())\n\n    -- get debuild\n    local debuild = _get_debuild()\n\n    -- pack deb package\n    _pack_deb(debuild.program, package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/dmg/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\".batchcmds\")\n\n-- pack dmg package\nfunction _pack_dmg(package)\n\n    -- check platform\n    assert(package:is_plat(\"macosx\"), \"dmg format only supports macOS platform!\")\n\n    -- get hdiutil\n    local hdiutil = find_tool(\"hdiutil\")\n    assert(hdiutil, \"hdiutil not found! Please install Xcode Command Line Tools.\")\n\n    -- archive binary files\n    batchcmds.get_installcmds(package):runcmds()\n    for _, component in table.orderpairs(package:components()) do\n        if component:get(\"default\") ~= false then\n            batchcmds.get_installcmds(component):runcmds()\n        end\n    end\n\n    -- get install root directory\n    local rootdir = package:install_rootdir()\n    assert(os.isdir(rootdir), \"install root directory not found: %s\", rootdir)\n\n    -- get output file\n    local outputfile = package:outputfile()\n    os.tryrm(outputfile)\n\n    -- create directory for DMG in builddir\n    local builddir = package:builddir()\n    local dmgdir = path.join(builddir, \"dmg\")\n    os.tryrm(dmgdir)\n    os.mkdir(dmgdir)\n\n    -- copy files to DMG directory\n    local dmgname = path.basename(outputfile, \".dmg\")\n    local dmgcontentdir = path.join(dmgdir, dmgname)\n    os.cp(rootdir, dmgcontentdir)\n\n    -- create DMG using hdiutil\n    -- create a read-only DMG with UDZO format (compressed)\n    local argv = {\n        \"create\",\n        \"-volname\", package:title() or package:name() or dmgname,\n        \"-srcfolder\", dmgcontentdir,\n        \"-ov\",\n        \"-format\", \"UDZO\",\n        outputfile\n    }\n\n    -- run hdiutil\n    os.vrunv(hdiutil.program, argv)\n\n    -- verify DMG was created\n    assert(os.isfile(outputfile), \"generate %s failed!\", outputfile)\nend\n\nfunction main(package)\n    cprint(\"packing %s .. \", package:outputfile())\n    _pack_dmg(package)\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/filter.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        filter.lua\n--\n\n-- imports\nimport(\"core.base.filter\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.sandbox.sandbox\")\n\n-- get filter\nfunction _filter()\n    if _g.filter == nil then\n        _g.filter = filter.new()\n        _g.filter:register(\"common\", function (variable)\n\n            -- attempt to get it directly from the configure\n            local result = config.get(variable)\n            if result == nil then\n\n                -- init maps\n                _g.common_maps = _g.common_maps or\n                {\n                    host        = os.host()\n                ,   subhost     = os.subhost()\n                ,   tmpdir      = function () return os.tmpdir() end\n                ,   curdir      = function () return os.curdir() end\n                ,   scriptdir   = function () return os.scriptdir() end\n                ,   globaldir   = global.directory()\n                ,   configdir   = config.directory()\n                ,   projectdir  = project.directory()\n                ,   programdir  = os.programdir()\n                }\n\n                -- map it\n                result = _g.common_maps[variable]\n            end\n\n            -- is script? call it\n            if type(result) == \"function\" then\n                result = result()\n            end\n            return result\n        end)\n    end\n    return _g.filter\nend\n\n-- the package handler\nfunction _handler(package, strval)\n\n    -- @note cannot cache it, because the package instance will be changed\n    return function (variable)\n        local maps = {\n            arch = package:arch(),\n            plat = package:plat(),\n            version = package:version()\n        }\n\n        -- get value\n        local result = maps[variable]\n        if type(result) == \"function\" then\n            result = result()\n        end\n        return result\n    end\nend\n\n-- attach filter to the given script and call it\nfunction call(script, package, opt)\n\n    -- get sandbox filter and handlers of the given script\n    local sandbox_filter   = sandbox.filter(script)\n    local sandbox_handlers = sandbox_filter:handlers()\n\n    -- switch to the handlers of the current filter\n    sandbox_filter:set_handlers(_filter():handlers())\n\n    -- register package handler\n    sandbox_filter:register(\"package\", _handler(package))\n\n    -- call it\n    script(package, opt)\n\n    -- restore handlers\n    sandbox_filter:set_handlers(sandbox_handlers)\nend\n\n-- handle the string value of package\nfunction handle(strval, package)\n\n    -- register filter handler\n    _filter():register(\"package\", _handler(package, strval))\n\n    -- handle string value\n    strval = _filter():handle(strval)\n\n    -- register filter handler\n    _filter():register(\"package\", nil)\n    return strval\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"actions.build.main\", {rootdir = os.programdir(), alias = \"build_action\"})\nimport(\"xpack\")\nimport(\"async.runjobs\")\n\n-- get packages\nfunction _get_packages()\n\n    -- get need formats\n    local formats_need = option.get(\"formats\")\n    if formats_need then\n        formats_need = formats_need:split(\",\")\n        if formats_need[1] == \"all\" then\n            formats_need = nil\n        end\n    end\n\n    local packages = {}\n    for _, package in ipairs(xpack.packages()) do\n        if not formats_need or table.contains(formats_need, package:format()) then\n            table.insert(packages, package)\n        end\n    end\n    return packages\nend\n\n-- load package\nfunction _load_package(package)\n\n    -- ensure build and output directories\n    os.tryrm(package:builddir())\n    os.mkdir(package:outputdir())\n\n    -- load it\n    local script = package:script(\"load\")\n    if script then\n        script(package)\n    end\nend\n\n-- pack the given package\nfunction _on_package(package)\n    import(package:format())(package)\nend\n\nfunction _pack_package(package)\n\n    -- do pack\n    local scripts = {\n        package:script(\"package_before\"),\n        package:script(\"package\", _on_package),\n        package:script(\"package_after\")\n    }\n    _load_package(package)\n    for i = 1, 3 do\n        local script = scripts[i]\n        if script ~= nil then\n            script(package)\n        end\n    end\nend\n\nfunction _pack_packages()\n    local packages = _get_packages()\n    local jobs = option.get(\"jobs\")\n    if jobs then\n        jobs = tonumber(jobs)\n    end\n    runjobs(\"pack_packages\", function (index)\n        local package = packages[index]\n        if package then\n            _pack_package(package)\n        end\n    end, {total = #packages, comax = jobs or os.default_njob(), isolate = true})\nend\n\nfunction _build_targets()\n    local targetnames = {}\n    for _, package in ipairs(_get_packages()) do\n        if package:from_binary() then\n            local targets = package:get(\"targets\")\n            if targets then\n                table.join2(targetnames, targets)\n            end\n        end\n    end\n    if #targetnames > 0 then\n        build_action.build_targets(targetnames)\n    end\nend\n\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load config first\n    task.run(\"config\", {}, {disable_dump = true})\n\n    -- lock the whole project\n    project.lock()\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- build targets first\n    if option.get(\"autobuild\") then\n        _build_targets()\n    end\n\n    -- do pack\n    _pack_packages()\n\n    -- leave project directory\n    os.cd(oldir)\n\n    -- unlock the whole project\n    project.unlock()\n    cprint(\"${color.success}pack ok\")\nend\n"
  },
  {
    "path": "xmake/plugins/pack/nsis/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\".filter\")\nimport(\".batchcmds\")\n\n-- check makensis, we need check some plugins\nfunction _check_makensis(program)\n    local tmpdir = os.tmpfile() .. \".dir\"\n    io.writefile(path.join(tmpdir, \"test.nsis\"), [[\n        !include \"MUI2.nsh\"\n        !include \"WordFunc.nsh\"\n        !include \"WinMessages.nsh\"\n        !include \"FileFunc.nsh\"\n        !include \"UAC.nsh\"\n\n        Name \"test\"\n        OutFile \"test.exe\"\n\n        Function .onInit\n        FunctionEnd\n\n        Section \"test\" InstallExeutable\n        SectionEnd\n\n        Function un.onInit\n        FunctionEnd\n\n        Section \"Uninstall\"\n        SectionEnd]])\n    os.runv(program, {\"test.nsis\"}, {curdir = tmpdir})\n    os.tryrm(tmpdir)\nend\n\n-- get the makensis\nfunction _get_makensis()\n\n    -- enter the environments of nsis\n    local oldenvs = packagenv.enter(\"nsis\")\n\n    -- find makensis\n    local packages = {}\n    local makensis = find_tool(\"makensis\", {check = _check_makensis})\n    if not makensis then\n        table.join2(packages, install_packages(\"nsis\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not makensis then\n        makensis = find_tool(\"makensis\", {check = _check_makensis, force = true})\n    end\n    assert(makensis, \"makensis not found!\")\n    return makensis, oldenvs\nend\n\n-- translate the file path\nfunction _translate_filepath(package, filepath)\n    return filepath:replace(package:install_rootdir(), \"$InstDir\", {plain = true})\nend\n\n-- get command string\nfunction _get_command_strings(package, cmd, opt)\n    opt = table.join(cmd.opt or {}, opt)\n    local result = {}\n    local kind = cmd.kind\n    if kind == \"cp\" then\n        -- https://nsis.sourceforge.io/Reference/File\n        local srcpath = cmd.srcpath\n        local dstpath = _translate_filepath(package, cmd.dstpath)\n\n        -- match files and directories\n        local srcitems = os.filedirs(srcpath)\n        for _, srcitem in ipairs(srcitems) do\n            if os.isdir(srcitem) then\n                -- copy directory recursively\n                srcitem = path.normalize(srcitem)\n                local dstdir = dstpath\n                if opt.rootdir then\n                    dstdir = path.join(dstdir, path.relative(srcitem, opt.rootdir))\n                else\n                    dstdir = path.join(dstdir, path.filename(srcitem))\n                end\n                dstdir = path.normalize(dstdir)\n                table.insert(result, string.format(\"SetOutPath \\\"%s\\\"\", dstdir))\n                table.insert(result, string.format(\"File /r \\\"%s\\\\*\\\"\", srcitem))\n            else\n                -- copy file\n                local dstfile = dstpath\n                if #srcitems > 1 or path.islastsep(dstfile) then\n                    if opt.rootdir then\n                        dstfile = path.join(dstfile, path.relative(srcitem, opt.rootdir))\n                    else\n                        dstfile = path.join(dstfile, path.filename(srcitem))\n                    end\n                end\n                srcitem = path.normalize(srcitem)\n                local dstname = path.filename(dstfile)\n                local dstdir = path.normalize(path.directory(dstfile))\n                table.insert(result, string.format(\"SetOutPath \\\"%s\\\"\", dstdir))\n                table.insert(result, string.format(\"File \\\"/oname=%s\\\" \\\"%s\\\"\", dstname, srcitem))\n            end\n        end\n    elseif kind == \"rm\" then\n        local filepath = _translate_filepath(package, cmd.filepath)\n        table.insert(result, string.format(\"${%s} \\\"%s\\\"\", opt.install and \"RMFileIfExists\" or \"unRMFileIfExists\", filepath))\n        if opt.emptydirs then\n            table.insert(result, string.format(\"${%s} \\\"%s\\\"\", opt.install and \"RMEmptyParentDirs\" or \"unRMEmptyParentDirs\", filepath))\n        end\n    elseif kind == \"rmdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(result, string.format(\"${%s} \\\"%s\\\"\", opt.install and \"RMDirIfExists\" or \"unRMDirIfExists\", dir))\n        if opt.emptydirs then\n            table.insert(result, string.format(\"${%s} \\\"%s\\\"\", opt.install and \"RMEmptyParentDirs\" or \"unRMEmptyParentDirs\", dir))\n        end\n    elseif kind == \"mv\" then\n        local srcpath = _translate_filepath(package, cmd.srcpath)\n        local dstpath = _translate_filepath(package, cmd.dstpath)\n        table.insert(result, string.format(\"Rename \\\"%s\\\" \\\"%s\\\"\", srcpath, dstpath))\n    elseif kind == \"cd\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(result, string.format(\"SetOutPath \\\"%s\\\"\", dir))\n    elseif kind == \"mkdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(result, string.format(\"CreateDirectory \\\"%s\\\"\", dir))\n    elseif kind == \"nsis\" then\n        table.insert(result, cmd.rawstr)\n    end\n    return result\nend\n\n-- get commands string\nfunction _get_commands_string(package, cmds, opt)\n    local cmdstrs = {}\n    for _, cmd in ipairs(cmds) do\n        table.join2(cmdstrs, _get_command_strings(package, cmd, opt))\n    end\n    return table.concat(cmdstrs, \"\\n  \")\nend\n\n-- get install commands of component\nfunction _get_component_installcmds(component)\n    return _get_commands_string(component, batchcmds.get_installcmds(component):cmds(), {install = true})\nend\n\n-- get uninstall commands of component\nfunction _get_component_uninstallcmds(component)\n    return _get_commands_string(component, batchcmds.get_uninstallcmds(component):cmds(), {install = false})\nend\n\n-- get install commands\nfunction _get_installcmds(package)\n    return _get_commands_string(package, batchcmds.get_installcmds(package):cmds(), {install = true})\nend\n\n-- get uninstall commands\nfunction _get_uninstallcmds(package)\n    return _get_commands_string(package, batchcmds.get_uninstallcmds(package):cmds(), {install = false})\nend\n\n-- get value and filter it\nfunction _get_filter_value(package, name)\n    local value = package:get(name)\n    if type(value) == \"string\" then\n        value = filter.handle(value, package)\n    end\n    return value\nend\n\n-- get target file path\nfunction _get_target_filepath(package)\n    local targetfile\n    for _, target in ipairs(package:targets()) do\n        if target:is_binary() then\n            targetfile = target:targetfile()\n            break\n        end\n    end\n    if targetfile then\n        return _translate_filepath(package, path.join(package:bindir(), path.filename(targetfile)))\n    end\nend\n\n-- get specvars\nfunction _get_specvars(package)\n    local specvars = table.clone(package:specvars())\n    specvars.PACKAGE_WORKDIR = path.absolute(os.projectdir())\n    specvars.PACKAGE_BINDIR = _translate_filepath(package, package:bindir())\n    specvars.PACKAGE_OUTPUTFILE = path.absolute(package:outputfile())\n    if specvars.PACKAGE_VERSION_BUILD then\n        -- @see https://github.com/xmake-io/xmake/issues/5306\n        specvars.PACKAGE_VERSION_BUILD = specvars.PACKAGE_VERSION_BUILD:gsub(\" \", \"_\")\n    end\n    specvars.PACKAGE_INSTALLCMDS = function ()\n        return _get_installcmds(package)\n    end\n    specvars.PACKAGE_UNINSTALLCMDS = function ()\n        return _get_uninstallcmds(package)\n    end\n    specvars.PACKAGE_NSIS_DISPLAY_ICON = function ()\n        local iconpath = _get_filter_value(package, \"nsis_displayicon\")\n        if iconpath then\n            iconpath = path.join(package:installdir(), iconpath)\n        end\n        if not iconpath then\n            iconpath = _get_target_filepath(package) or \"\"\n        end\n        return _translate_filepath(package, iconpath)\n    end\n\n    -- install sections\n    local install_sections = {}\n    local install_descs = {}\n    local install_description_texts = {}\n    for name, component in table.orderpairs(package:components()) do\n        local installcmds = _get_component_installcmds(component)\n        if installcmds and #installcmds > 0 then\n            local tag = \"Install\" .. name\n            table.insert(install_sections, string.format('Section%s \"%s\" %s', component:get(\"default\") == false and \" /o\" or \"\", component:title(), tag))\n            table.insert(install_sections, installcmds)\n            table.insert(install_sections, \"SectionEnd\")\n            table.insert(install_descs, string.format('LangString DESC_%s ${LANG_ENGLISH} \"%s\"', tag, component:description() or \"\"))\n            table.insert(install_description_texts, string.format('!insertmacro MUI_DESCRIPTION_TEXT ${%s} $(DESC_%s)', tag, tag))\n        end\n        local uninstallcmds = _get_component_uninstallcmds(component)\n        if uninstallcmds and #uninstallcmds > 0 then\n            local tag = \"Uninstall\" .. name\n            table.insert(install_sections, string.format('Section \"un.%s\" %s', component:title(), tag))\n            table.insert(install_sections, uninstallcmds)\n            table.insert(install_sections, \"SectionEnd\")\n        end\n    end\n    specvars.PACKAGE_NSIS_INSTALL_SECTIONS = table.concat(install_sections, \"\\n  \")\n    specvars.PACKAGE_NSIS_INSTALL_DESCS = table.concat(install_descs, \"\\n  \")\n    specvars.PACKAGE_NSIS_INSTALL_DESCRIPTION_TEXTS = table.concat(install_description_texts, \"\\n  \")\n    return specvars\nend\n\n-- pack nsis package\nfunction _pack_nsis(makensis, package)\n\n    -- install the initial specfile\n    local specfile = path.join(package:builddir(), package:basename() .. \".nsi\")\n    if not os.isfile(specfile) then\n        local specfile_template = package:get(\"specfile\") or path.join(os.programdir(), \"scripts\", \"xpack\", \"nsis\", \"makensis.nsi\")\n        os.cp(specfile_template, specfile)\n    end\n\n    -- replace variables in specfile,\n    -- and we need to avoid `attempt to yield across a C-call boundary` in io.gsub\n    local specvars = _get_specvars(package)\n    local pattern = package:extraconf(\"specfile\", \"pattern\") or \"%${([^\\n]-)}\"\n    local specvars_names = {}\n    local specvars_values = {}\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        table.insert(specvars_names, name)\n    end, {encoding = \"ansi\"})\n    for _, name in ipairs(specvars_names) do\n        name = name:trim()\n        if specvars_values[name] == nil then\n            local value = specvars[name]\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if value ~= nil then\n                dprint(\"  > replace %s -> %s\", name, value)\n            end\n            if type(value) == \"table\" then\n                dprint(\"invalid variable value\", value)\n            end\n            specvars_values[name] = value\n        end\n    end\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        name = name:trim()\n        return specvars_values[name]\n    end, {encoding = \"ansi\"})\n\n    -- make package\n    os.vrunv(makensis, {specfile})\nend\n\nfunction main(package)\n\n    -- only for windows\n    if not is_host(\"windows\") then\n        return\n    end\n\n    cprint(\"packing %s\", package:outputfile())\n\n    -- get makensis\n    local makensis, oldenvs = _get_makensis()\n\n    -- pack nsis package\n    _pack_nsis(makensis.program, package)\n\n    -- done\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/rpm/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\".srpm\")\n\nfunction main(package)\n    srpm(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/runself/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\".batchcmds\")\n\n-- get the makeself\nfunction _get_makeself()\n\n    -- enter the environments of makeself\n    local oldenvs = packagenv.enter(\"makeself\")\n\n    -- find makeself\n    local packages = {}\n    local makeself = find_tool(\"makeself.sh\")\n    if not makeself then\n        table.join2(packages, install_packages(\"makeself\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not makeself then\n        makeself = find_tool(\"makeself.sh\", {force = true})\n    end\n    assert(makeself, \"makeself not found!\")\n    return makeself, oldenvs\nend\n\n-- get specvars\nfunction _get_specvars(package)\n    local specvars = table.clone(package:specvars())\n    return specvars\nend\n\n-- write install command\nfunction _write_installcmd(package, scriptfile, cmd)\n    local opt = cmd.opt or {}\n    local kind = cmd.kind\n    if kind == \"cp\" then\n        local srcfiles = os.files(cmd.srcpath)\n        for _, srcfile in ipairs(srcfiles) do\n            -- the destination is directory? append the filename\n            local dstfile = cmd.dstpath\n            if #srcfiles > 1 or path.islastsep(dstfile) then\n                if opt.rootdir then\n                    dstfile = path.join(dstfile, path.relative(srcfile, opt.rootdir))\n                else\n                    dstfile = path.join(dstfile, path.filename(srcfile))\n                end\n            end\n            scriptfile:print(\"cp -p \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile)\n        end\n    elseif kind == \"rm\" then\n        local filepath = cmd.filepath\n        scriptfile:print(\"rm -f \\\"%s\\\"\", filepath)\n    elseif kind == \"rmdir\" then\n        local dir = cmd.dir\n        scriptfile:print(\"rm -rf \\\"%s\\\"\", dir)\n    elseif kind == \"mv\" then\n        local srcpath = cmd.srcpath\n        local dstpath = cmd.dstpath\n        scriptfile:print(\"mv \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile)\n    elseif kind == \"cd\" then\n        local dir = cmd.dir\n        scriptfile:print(\"cd \\\"%s\\\"\", dir)\n    elseif kind == \"mkdir\" then\n        local dir = cmd.dir\n        scriptfile:print(\"mkdir -p \\\"%s\\\"\", dir)\n    elseif cmd.program then\n        scriptfile:print(\"%s\", os.args(table.join(cmd.program, cmd.argv)))\n    end\nend\n\n-- write install commands\nfunction _write_installcmds(package, scriptfile, cmds)\n    for _, cmd in ipairs(cmds) do\n        _write_installcmd(package, scriptfile, cmd)\n    end\nend\n\n-- pack runself package\nfunction _pack_runself(makeself, package)\n\n    -- install the initial specfile\n    local specfile = path.join(package:builddir(), package:basename() .. \".lsm\")\n    if not os.isfile(specfile) then\n        local specfile_template = package:get(\"specfile\") or path.join(os.programdir(), \"scripts\", \"xpack\", \"runself\", \"makeself.lsm\")\n        os.cp(specfile_template, specfile, {writeable = true})\n    end\n\n    -- replace variables in specfile\n    local specvars = _get_specvars(package)\n    local pattern = package:extraconf(\"specfile\", \"pattern\") or \"%${([^\\n]-)}\"\n    local specvars_names = {}\n    local specvars_values = {}\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        table.insert(specvars_names, name)\n    end)\n    for _, name in ipairs(specvars_names) do\n        name = name:trim()\n        if specvars_values[name] == nil then\n            local value = specvars[name]\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if value ~= nil then\n                dprint(\"  > replace %s -> %s\", name, value)\n            end\n            if type(value) == \"table\" then\n                dprint(\"invalid variable value\", value)\n            end\n            specvars_values[name] = value\n        end\n    end\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        name = name:trim()\n        return specvars_values[name]\n    end)\n\n    -- archive source files\n    local srcfiles, dstfiles = package:sourcefiles()\n    for idx, srcfile in ipairs(srcfiles) do\n        os.vcp(srcfile, dstfiles[idx])\n    end\n    for _, component in table.orderpairs(package:components()) do\n        if component:get(\"default\") ~= false then\n            local srcfiles, dstfiles = component:sourcefiles()\n            for idx, srcfile in ipairs(srcfiles) do\n                os.vcp(srcfile, dstfiles[idx])\n            end\n        end\n    end\n\n    -- generate the setup.sh script\n    local sourcedir = package:sourcedir()\n    local setupfile = path.join(sourcedir, \"__setup__.sh\")\n    os.cp(path.join(os.programdir(), \"scripts\", \"xpack\", \"runself\", \"setup.sh\"), setupfile)\n    local scriptfile = io.open(setupfile, \"a+\")\n    if scriptfile then\n        _write_installcmds(package, scriptfile, batchcmds.get_installcmds(package):cmds())\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                _write_installcmds(package, scriptfile, batchcmds.get_installcmds(component):cmds())\n            end\n        end\n        scriptfile:close()\n    end\n\n    -- make package\n    os.vrunv(makeself, {\"--gzip\", \"--sha256\", \"--lsm\", specfile,\n        sourcedir, package:outputfile(), package:basename(), \"./__setup__.sh\"})\nend\n\nfunction main(package)\n\n    if is_subhost(\"windows\") then\n        return\n    end\n\n    cprint(\"packing %s\", package:outputfile())\n\n    -- get makeself\n    local makeself, oldenvs = _get_makeself()\n\n    -- pack runself package\n    _pack_runself(makeself.program, package)\n\n    -- done\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/srctargz/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/srctarxz/main.lua",
    "content": "import(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/srczip/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/srpm/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\"utils.archive\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\".batchcmds\")\n\n-- get the rpmbuild\nfunction _get_rpmbuild()\n\n    -- enter the environments of rpmbuild\n    local oldenvs = packagenv.enter(\"rpm\")\n\n    -- find rpmbuild\n    local packages = {}\n    local rpmbuild = find_tool(\"rpmbuild\")\n    if not rpmbuild then\n        table.join2(packages, install_packages(\"rpm\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not rpmbuild then\n        rpmbuild = find_tool(\"rpmbuild\", {force = true})\n    end\n    assert(rpmbuild, \"rpmbuild not found!\")\n    return rpmbuild, oldenvs\nend\n\n-- get archive file\nfunction _get_archivefile(package)\n    return path.absolute(path.join(package:builddir(), package:basename() .. \".tar.gz\"))\nend\n\n-- translate the file path\nfunction _translate_filepath(package, filepath)\n    return filepath:replace(package:install_rootdir(), \"%{buildroot}/%{_exec_prefix}\", {plain = true})\nend\n\n-- get install command\nfunction _get_customcmd(package, installcmds, cmd)\n    local opt = cmd.opt or {}\n    local kind = cmd.kind\n    if kind == \"cp\" then\n        local srcfiles = os.files(cmd.srcpath)\n        for _, srcfile in ipairs(srcfiles) do\n            -- the destination is directory? append the filename\n            local dstfile = _translate_filepath(package, cmd.dstpath)\n            if #srcfiles > 1 or path.islastsep(dstfile) then\n                if opt.rootdir then\n                    dstfile = path.join(dstfile, path.relative(srcfile, opt.rootdir))\n                else\n                    dstfile = path.join(dstfile, path.filename(srcfile))\n                end\n            end\n            table.insert(installcmds, string.format(\"install -Dpm0644 \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile))\n        end\n    elseif kind == \"rm\" then\n        local filepath = _translate_filepath(package, cmd.filepath)\n        table.insert(installcmds, string.format(\"rm -f \\\"%s\\\"\", filepath))\n    elseif kind == \"rmdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"rm -rf \\\"%s\\\"\", dir))\n    elseif kind == \"mv\" then\n        local srcpath = _translate_filepath(package, cmd.srcpath)\n        local dstpath = _translate_filepath(package, cmd.dstpath)\n        table.insert(installcmds, string.format(\"mv \\\"%s\\\" \\\"%s\\\"\", srcfile, dstfile))\n    elseif kind == \"cd\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"cd \\\"%s\\\"\", dir))\n    elseif kind == \"mkdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        table.insert(installcmds, string.format(\"mkdir -p \\\"%s\\\"\", dir))\n    elseif cmd.program then\n        local argv = {}\n        for _, arg in ipairs(cmd.argv) do\n            if path.instance_of(arg) then\n                arg = arg:clone():set(_translate_filepath(package, arg:rawstr())):str()\n            elseif path.is_absolute(arg) then\n                arg = _translate_filepath(package, arg)\n            end\n            table.insert(argv, arg)\n        end\n        table.insert(installcmds, string.format(\"%s\", os.args(table.join(cmd.program, argv))))\n    end\nend\n\n-- get build commands\nfunction _get_buildcmds(package, buildcmds, cmds)\n    for _, cmd in ipairs(cmds) do\n        _get_customcmd(package, buildcmds, cmd)\n    end\nend\n\n-- get install commands\nfunction _get_installcmds(package, installcmds, cmds)\n    for _, cmd in ipairs(cmds) do\n        _get_customcmd(package, installcmds, cmd)\n    end\nend\n\n-- get specvars\nfunction _get_specvars(package)\n    local specvars = table.clone(package:specvars())\n    specvars.PACKAGE_ARCHIVEFILE = path.filename(_get_archivefile(package))\n    local datestr = os.iorunv(\"date\", {\"+%a %b %d %Y\"}, {envs = {LC_TIME = \"en_US\"}})\n    if datestr then\n        datestr = datestr:trim()\n    end\n    specvars.PACKAGE_PREFIXDIR = package:prefixdir() or \"\"\n    specvars.PACKAGE_DATE = datestr or \"\"\n    specvars.PACKAGE_INSTALLCMDS = function ()\n        local prefixdir = package:get(\"prefixdir\")\n        package:set(\"prefixdir\", nil)\n        local installcmds = {}\n        _get_installcmds(package, installcmds, batchcmds.get_installcmds(package):cmds())\n        for _, component in table.orderpairs(package:components()) do\n            if component:get(\"default\") ~= false then\n                _get_installcmds(package, installcmds, batchcmds.get_installcmds(component):cmds())\n            end\n        end\n        package:set(\"prefixdir\", prefixdir)\n        return table.concat(installcmds, \"\\n\")\n    end\n    specvars.PACKAGE_BUILDCMDS = function ()\n        local buildcmds = {}\n        _get_buildcmds(package, buildcmds, batchcmds.get_buildcmds(package):cmds())\n        return table.concat(buildcmds, \"\\n\")\n    end\n    specvars.PACKAGE_BUILDREQUIRES = function ()\n        local requires = {}\n        local buildrequires = package:get(\"buildrequires\")\n        if buildrequires then\n            for _, buildrequire in ipairs(buildrequires) do\n                table.insert(requires, \"BuildRequires: \" .. buildrequire)\n            end\n        else\n            local programs = hashset.new()\n            for _, cmd in ipairs(batchcmds.get_buildcmds(package):cmds()) do\n                local program = cmd.program\n                if program then\n                    programs:insert(program)\n                end\n            end\n            local map = {\n                xmake = \"xmake\",\n                cmake = \"cmake\",\n                make = \"make\"\n            }\n            for _, program in programs:keys() do\n                local requirename = map[program]\n                if requirename then\n                    table.insert(requires, \"BuildRequires: \" .. requirename)\n                end\n            end\n            if #requires > 0 then\n                table.insert(requires, \"BuildRequires: gcc\")\n                table.insert(requires, \"BuildRequires: gcc-c++\")\n            end\n        end\n        return table.concat(requires, \"\\n\")\n    end\n    return specvars\nend\n\n-- pack srpm package\nfunction _pack_srpm(rpmbuild, package)\n\n    -- ensure prefixdir\n    local prefixdir = package:get(\"prefixdir\")\n    if not prefixdir then\n        prefixdir = package:name() .. \"-\" .. package:version()\n        package:set(\"prefixdir\", prefixdir)\n    end\n\n    -- install the initial specfile\n    local specfile = path.join(package:builddir(), package:basename() .. \".spec\")\n    if not os.isfile(specfile) then\n        local specfile_template = package:get(\"specfile\") or path.join(os.programdir(), \"scripts\", \"xpack\", \"srpm\", \"srpm.spec\")\n        os.cp(specfile_template, specfile, {writeable = true})\n    end\n\n    -- replace variables in specfile\n    -- and we need to avoid `attempt to yield across a C-call boundary` in io.gsub\n    local specvars = _get_specvars(package)\n    local pattern = package:extraconf(\"specfile\", \"pattern\") or \"%${([^\\n]-)}\"\n    local specvars_names = {}\n    local specvars_values = {}\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        table.insert(specvars_names, name)\n    end)\n    for _, name in ipairs(specvars_names) do\n        name = name:trim()\n        if specvars_values[name] == nil then\n            local value = specvars[name]\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if value ~= nil then\n                dprint(\"  > replace %s -> %s\", name, value)\n            end\n            if type(value) == \"table\" then\n                dprint(\"invalid variable value\", value)\n            end\n            specvars_values[name] = value\n        end\n    end\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        name = name:trim()\n        return specvars_values[name]\n    end)\n\n    -- archive source files\n    local srcfiles, dstfiles = package:sourcefiles()\n    for idx, srcfile in ipairs(srcfiles) do\n        os.vcp(srcfile, dstfiles[idx])\n    end\n    for _, component in table.orderpairs(package:components()) do\n        if component:get(\"default\") ~= false then\n            local srcfiles, dstfiles = component:sourcefiles()\n            for idx, srcfile in ipairs(srcfiles) do\n                os.vcp(srcfile, dstfiles[idx])\n            end\n        end\n    end\n\n    -- archive install files\n    local rootdir = package:source_rootdir()\n    local oldir = os.cd(rootdir)\n    local archivefiles = os.files(\"**\")\n    os.cd(oldir)\n    local archivefile = _get_archivefile(package)\n    os.tryrm(archivefile)\n    archive.archive(archivefile, archivefiles, {curdir = rootdir, compress = \"best\"})\n\n    -- pack srpm package\n    os.vrunv(rpmbuild, {\"-bs\", specfile,\n        \"--define\", \"_topdir \" .. package:builddir(),\n        \"--define\", \"_sourcedir \" .. package:builddir(),\n        \"--define\", \"_srcrpmdir \" .. package:outputdir()})\n\n    -- pack rpm package\n    if package:format() == \"rpm\" then\n        local srpmfile = find_file(\"*.src.rpm\", package:outputdir())\n        if srpmfile then\n            os.vrunv(rpmbuild, {\"--rebuild\", srpmfile, \"--define\", \"_rpmdir \" .. package:outputdir()})\n        end\n    end\nend\n\nfunction main(package)\n\n    if not is_host(\"linux\") then\n        return\n    end\n\n    cprint(\"packing %s\", package:outputfile())\n\n    -- get rpmbuild\n    local rpmbuild, oldenvs = _get_rpmbuild()\n\n    -- pack srpm package\n    _pack_srpm(rpmbuild.program, package)\n\n    -- done\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/targz/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/tarxz/main.lua",
    "content": "import(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/wix/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      A2va\n-- @file        main.lua\n--\n\nimport(\"lib.detect.find_tool\")\nimport(\"private.action.require.impl.packagenv\")\nimport(\"private.action.require.impl.install_packages\")\nimport(\".batchcmds\")\n\n-- get the wixtoolset\nfunction _get_wix()\n\n    -- enter the environments of wix\n    local oldenvs = packagenv.enter(\"wixtoolset\")\n\n    -- find makensis\n    local packages = {}\n    local wix = find_tool(\"wix\")\n    if not wix then\n        table.join2(packages, install_packages(\"wixtoolset\"))\n    end\n\n    -- enter the environments of installed packages\n    for _, instance in ipairs(packages) do\n        instance:envs_enter()\n    end\n\n    -- we need to force detect and flush detect cache after loading all environments\n    if not wix then\n        wix = find_tool(\"wix\", {force = true})\n    end\n    assert(wix, \"wix not found (ensure that wix is up to date)!\")\n    return wix, oldenvs\nend\n\n-- translate the file path\nfunction _translate_filepath(package, filepath)\n    return path.relative(filepath, package:install_rootdir())\nend\n\nfunction _to_rtf_string(str)\n    if str == \"\" then\n        return str\n    end\n\n    local escape_text = str:gsub(\"\\\\\", \"\\\\\\\\\")\n    escape_text = escape_text:gsub(\"{\", \"\\\\{\")\n    escape_text = escape_text:gsub(\"}\", \"\\\\}\")\n\n    local rtf = \"{\\\\rtf1\\\\ansi{\\\\fonttbl\\\\f0\\\\fswiss Helvetica;}\\\\f0\\\\pard \";\n    rtf = rtf .. escape_text:gsub(\"\\r\\n\", \" \\\\par \") .. \"}\"\n    return rtf\nend\n\n-- get a table where the key is a directory and the value a list of files\n-- used to regroup all files that are placed in the same directory under the same component.\nfunction _get_cp_kind_table(package, cmds, opt)\n\n    local result = {}\n    for _, cmd in ipairs(cmds) do\n        if cmd.kind ~= \"cp\" then\n            goto continue\n        end\n\n        local option = table.join(cmd.opt or {}, opt)\n        -- match files and directories\n        local srcitems = os.filedirs(cmd.srcpath)\n        for _, srcitem in ipairs(srcitems) do\n            if os.isdir(srcitem) then\n                -- for directory, recursively collect all files in it\n                local rootdir = option.rootdir or srcitem\n                local files = os.files(path.join(srcitem, \"**\"))\n                for _, srcfile in ipairs(files) do\n                    -- the destination is directory? append the relative path\n                    local dstfile = cmd.dstpath\n                    if option.rootdir then\n                        dstfile = path.join(dstfile, path.relative(srcfile, option.rootdir))\n                    else\n                        dstfile = path.join(dstfile, path.relative(srcfile, rootdir))\n                    end\n                    srcfile = path.normalize(srcfile)\n                    local dstname = path.filename(dstfile)\n                    local dstdir = path.normalize(path.directory(dstfile))\n                    dstdir = _translate_filepath(package, dstdir)\n\n                    if result[dstdir] then\n                        table.insert(result[dstdir], {srcfile, dstname})\n                    else\n                        result[dstdir] = {{srcfile, dstname}}\n                    end\n                end\n            else\n                -- for file, use the original logic\n                local dstfile = cmd.dstpath\n                if #srcitems > 1 or path.islastsep(dstfile) then\n                    if option.rootdir then\n                        dstfile = path.join(dstfile, path.relative(srcitem, option.rootdir))\n                    else\n                        dstfile = path.join(dstfile, path.filename(srcitem))\n                    end\n                end\n                srcitem = path.normalize(srcitem)\n                local dstname = path.filename(dstfile)\n                local dstdir = path.normalize(path.directory(dstfile))\n                dstdir = _translate_filepath(package, dstdir)\n\n                if result[dstdir] then\n                    table.insert(result[dstdir], {srcitem, dstname})\n                else\n                    result[dstdir] = {{srcitem, dstname}}\n                end\n            end\n        end\n        ::continue::\n    end\n    return result\nend\n\n-- get id\nfunction _get_id(name)\n    return \"A\" .. hash.uuid(name):gsub(\"-\", \".\")\nend\n\n-- for each id/guid in the file wix want them to be unique\n-- so compute a hash for each directory based on the file that are inside\nfunction _get_dir_id(cp_table)\n    local hashes = {}\n    for dir, files in pairs(cp_table) do\n        local s = \"\"\n        for _, file in ipairs(files) do\n            s = s .. table.concat(file, \"\")\n        end\n        -- wix required id to start with a letter and without any hyphen\n        hashes[dir] = _get_id(s)\n    end\n    return hashes\nend\n\n-- get custom commands\nfunction _get_other_commands(package, cmd, opt)\n    opt = table.join(cmd.opt or {}, opt)\n    local result = \"\"\n    local kind = cmd.kind\n    local id = _get_id()\n    if kind == \"rm\" then\n        local subdirectory = _translate_filepath(package, path.directory(cmd.filepath))\n        subdirectory = subdirectory ~= \".\" and string.format([[Subdirectory=\"%s\"]], subdirectory) or \"\"\n        local on = opt.install and [[On=\"install\"]] or [[On=\"uninstall\"]]\n        local filename = path.filename(cmd.filepath)\n        result = string.format([[<RemoveFile Id=\"%s\" Directory=\"INSTALLFOLDER\" Name=\"%s\" %s %s/>]], id, filename, subdirectory, on)\n    elseif kind == \"rmdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        local subdirectory = dir ~= \".\" and string.format([[Subdirectory=\"%s\"]], dir) or \"\"\n        local on = opt.install and [[On=\"install\"]] or [[On=\"uninstall\"]]\n        result = string.format([[<RemoveFolder Id=\"%s\" Directory=\"INSTALLFOLDER\" %s %s/>]], id, subdirectory, on)\n    elseif kind == \"mkdir\" then\n        local dir = _translate_filepath(package, cmd.dir)\n        local subdirectory = dir ~= \".\" and string.format([[Subdirectory=\"%s\"]], dir) or \"\"\n        result = string.format([[<CreateFolder Id=\"%s\" Directory=\"INSTALLFOLDER\" %s/>]], id, subdirectory)\n    elseif kind == \"wix\" then\n        result = cmd.rawstr\n    end\n    return result\nend\n\n-- get the string of a wix feature\nfunction _get_feature_string(name, title, opt)\n    local level = opt.default and 1 or 2\n    local description = opt.description or \"\"\n    local allow_absent = opt.force and \"false\" or \"true\"\n    local allow_advertise = opt.force and \"false\" or \"true\"\n    local typical_default = [[TypicalDefault=\"install\"]]\n    local directory = opt.config_dir and [[ConfigurableDirectory=\"INSTALLFOLDER\"]] or \"\"\n    local feature = string.format([[<Feature Id=\"%s\" Title=\"%s\" Description=\"%s\" Level=\"%d\" AllowAdvertise=\"%s\" AllowAbsent=\"%s\" %s %s>]],\n        name:gsub(\"[ ()]\", \"\"), title, description, level, allow_advertise, allow_absent, typical_default, directory)\n    return feature\nend\n\nfunction _get_component_string(id, subdirectory)\n    local subdirectory = (subdirectory ~= \".\" and subdirectory ~= nil) and string.format([[Subdirectory=\"%s\"]], subdirectory) or \"\"\n    return string.format([[<Component Id=\"%s\" Guid=\"%s\" Directory=\"INSTALLFOLDER\" %s>]], id:gsub(\"[ ()]\", \"\"), hash.uuid(id), subdirectory)\nend\n\n-- build a feature from batchcmds\nfunction _build_feature(package, opt)\n    opt = opt or {}\n    local default = opt.default or package:get(\"default\")\n\n    local result = {}\n    local name = opt.name or package:title()\n    table.insert(result, _get_feature_string(name, package:title(), table.join(opt, {default = default, description = package:description()})))\n\n    local installcmds = batchcmds.get_installcmds(package):cmds()\n    local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds()\n\n    local cp_table = _get_cp_kind_table(package, installcmds, opt)\n    table.remove_if(installcmds, function (_, cmd) return cmd.kind == \"cp\" end)\n\n    local dir_id = _get_dir_id(cp_table)\n    for dir, files in pairs(cp_table) do\n        table.insert(result, _get_component_string(dir_id[dir], dir))\n        for _, file in ipairs(files) do\n            local srcfile = file[1]\n            local dstname = file[2]\n            table.insert(result, string.format([[<File Source=\"%s\" Name=\"%s\" Id=\"%s\"/>]], srcfile, dstname, _get_id()))\n        end\n        table.insert(result, \"</Component>\")\n    end\n\n    table.insert(result, _get_component_string(name .. \"Cmds\"))\n    for _, cmd in ipairs(installcmds) do\n        table.insert(result, _get_other_commands(package, cmd, {install = true}))\n    end\n    for _, cmd in ipairs(uninstallcmds) do\n        table.insert(result, _get_other_commands(package, cmd, {install = false}))\n    end\n\n    table.insert(result, \"</Component>\")\n    table.insert(result, \"</Feature>\")\n    return result\nend\n\n-- add to path feature\nfunction _add_to_path(package)\n    local result = {}\n    table.insert(result, _get_feature_string(\"PATH\", \"Add to PATH\", {default = false, force = false, description = \"Add to PATH\"}))\n    table.insert(result, _get_component_string(\"PATH\"))\n    table.insert(result, [[<Environment Id=\"PATH\" Name=\"PATH\"  Value=\"[INSTALLFOLDER]bin\" Permanent=\"false\" Part=\"last\" Action=\"set\" System=\"true\" />]])\n    table.insert(result, \"</Component>\")\n    table.insert(result, \"</Feature>\")\n    return result\nend\n\n-- get specvars\nfunction _get_specvars(package)\n    local installcmds = batchcmds.get_installcmds(package):cmds()\n    local specvars = table.clone(package:specvars())\n\n    local features = {}\n    table.join2(features, _build_feature(package, {default = true, force = true, config_dir = true}))\n    table.join2(features, _add_to_path(package))\n    for name, component in table.orderpairs(package:components()) do\n        table.join2(features, _build_feature(component, {name = \"Install \" .. name}))\n    end\n\n    specvars.PACKAGE_LICENSEFILE = function ()\n        local rtf_string = \"\"\n        local licensefile = package:get(\"licensefile\")\n        if licensefile then\n            rtf_string =  _to_rtf_string(io.readfile(licensefile))\n        end\n\n        local rtf_file = path.join(package:builddir(), \"license.rtf\")\n        io.writefile(rtf_file, rtf_string)\n        return rtf_file\n    end\n\n    specvars.PACKAGE_WIX_CMDS = table.concat(features, \"\\n  \")\n    specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name())\n\n    -- company cannot be empty with wix\n    if package:get(\"company\") == nil or package:get(\"company\") == \"\" then\n        specvars.PACKAGE_COMPANY = package:name()\n    end\n    return specvars\nend\n\nfunction _pack_wix(wix, package)\n\n    -- install the initial specfile\n    local specfile = path.join(package:builddir(), package:basename() .. \".wxs\")\n    if not os.isfile(specfile) then\n        local specfile_template = package:get(\"specfile\") or path.join(os.programdir(), \"scripts\", \"xpack\", \"wix\", \"msi.wxs\")\n        os.cp(specfile_template, specfile)\n    end\n\n    -- replace variables in specfile\n    -- and we need to avoid `attempt to yield across a C-call boundary` in io.gsub\n    local specvars = _get_specvars(package)\n    local pattern = package:extraconf(\"specfile\", \"pattern\") or \"%${([^\\n]-)}\"\n    local specvars_names = {}\n    local specvars_values = {}\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        table.insert(specvars_names, name)\n    end)\n    for _, name in ipairs(specvars_names) do\n        name = name:trim()\n        if specvars_values[name] == nil then\n            local value = specvars[name]\n            if type(value) == \"function\" then\n                value = value()\n            end\n            if value ~= nil then\n                dprint(\"  > replace %s -> %s\", name, value)\n            end\n            if type(value) == \"table\" then\n                dprint(\"invalid variable value\", value)\n            end\n            specvars_values[name] = value\n        end\n    end\n    io.gsub(specfile, \"(\" .. pattern .. \")\", function(_, name)\n        name = name:trim()\n        return specvars_values[name]\n    end)\n\n    local argv = {\"build\", specfile}\n    table.join2(argv, {\"-ext\", \"WixToolset.UI.wixext\"})\n    table.join2(argv, {\"-o\", package:outputfile()})\n\n    if package:arch() == \"x64\" then\n        table.join2(argv, {\"-arch\", \"x64\"})\n    elseif package:arch() == \"x86\" then\n        table.join2(argv, {\"-arch\", \"x86\"})\n    end\n\n    -- make package\n    os.vrunv(wix, argv)\nend\n\nfunction main(package)\n\n    -- only for windows\n    if not is_host(\"windows\") then\n        return\n    end\n\n    cprint(\"packing %s\", package:outputfile())\n\n    -- get wix\n    local wix, oldenvs = _get_wix()\n\n    -- pack nsis package\n    _pack_wix(wix.program, package)\n\n    -- done\n    os.setenvs(oldenvs)\nend\n"
  },
  {
    "path": "xmake/plugins/pack/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        pack.lua\n--\n\ntask(\"pack\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake pack [options] [names]\",\n        description = \"Pack binary installation packages.\",\n        options = {\n            {'o', \"outputdir\", \"kv\", nil,   \"Set the output directory. (default: build/xpack)\"},\n            {nil, \"basename\",  \"kv\", nil,   \"Set the basename of the output file.\"},\n            {nil, \"autobuild\", \"kv\", true,  \"Build targets automatically.\"},\n            {'j', \"jobs\",      \"kv\", tostring(os.default_njob()), \"Set the number of parallel compilation jobs.\"   },\n            {'f', \"formats\",   \"kv\", \"all\", \"Pack the given package formats.\",\n                                            \"e.g.\",\n                                            \"    - xmake pack -f nsis,deb,rpm\",\n                                            \"values:\",\n                                            values = {\"nsis\", \"wix\", \"deb\", \"srpm\", \"rpm\", \"runself\", \"targz\", \"tarxz\", \"zip\", \"srctargz\", \"srctarxz\", \"srczip\"}},\n            {},\n            {nil, \"packages\",  \"vs\", nil,   \"The package names.\"}\n        }\n    }\n"
  },
  {
    "path": "xmake/plugins/pack/xpack.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xpack.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.core.base.select_script\")\nimport(\"private.core.base.match_copyfiles\")\nimport(\"lib.detect.find_tool\")\nimport(\"filter\")\nimport(\"xpack_component\")\n\n-- define module\nlocal xpack = xpack or object {_init = {\"_name\", \"_info\", \"_namespace\"}}\n\n-- get name\nfunction xpack:name()\n    return self._name\nend\n\n-- get namespace\nfunction xpack:namespace()\n    return self._namespace\nend\n\n-- get fullname\nfunction xpack:fullname()\n    local namespace = self:namespace()\n    return namespace and namespace .. \"::\" .. self:name() or self:name()\nend\n\n-- get values\nfunction xpack:get(name)\n    if self._info then\n        return self._info:get(name)\n    end\nend\n\n-- set values\nfunction xpack:set(name, ...)\n    if self._info then\n        self._info:apival_set(name, ...)\n    end\nend\n\n-- add values\nfunction xpack:add(name, ...)\n    if self._info then\n        self._info:apival_add(name, ...)\n    end\nend\n\n-- get the extra configuration\nfunction xpack:extraconf(name, item, key)\n    if self._info then\n        return self._info:extraconf(name, item, key)\n    end\nend\n\n-- get the package license\nfunction xpack:license()\n    return self:get(\"license\")\nend\n\n-- get the package title\nfunction xpack:title()\n    local title = self:get(\"title\")\n    if title == nil then\n        title = self:name()\n    end\n    return filter.handle(title, self)\nend\n\n-- get the package description\nfunction xpack:description()\n    return self:get(\"description\")\nend\n\n-- get the platform of package\nfunction xpack:plat()\n    return config.get(\"plat\") or os.subhost()\nend\n\n-- get the architecture of package\nfunction xpack:arch()\n    return config.get(\"arch\") or os.subarch()\nend\n\n-- the current platform is belong to the given platforms?\nfunction xpack:is_plat(...)\n    local plat = self:plat()\n    for _, v in ipairs(table.pack(...)) do\n        if v and plat == v then\n            return true\n        end\n    end\nend\n\n-- the current architecture is belong to the given architectures?\nfunction xpack:is_arch(...)\n    local arch = self:arch()\n    for _, v in ipairs(table.pack(...)) do\n        if v and arch:find(\"^\" .. v:gsub(\"%-\", \"%%-\") .. \"$\") then\n            return true\n        end\n    end\nend\n\n-- get xxx_script\nfunction xpack:script(name, generic)\n    local script = self:get(name)\n    local result = select_script(script, {plat = self:plat(), arch = self:arch()}) or generic\n    return result\nend\n\n-- get targets\nfunction xpack:targets()\n    local targets = self._targets\n    if not targets then\n        targets = {}\n        local targetnames = self:get(\"targets\")\n        if targetnames then\n            for _, name in ipairs(targetnames) do\n                local target = project.target(name, {namespace = self:namespace()})\n                if target then\n                    table.insert(targets, target)\n                else\n                    raise(\"xpack(%s): target(%s) not found!\", self:name(), name)\n                end\n            end\n        end\n        self._targets = targets\n    end\n    return targets\nend\n\n-- get the given target\nfunction xpack:target(name)\n    local targetnames = self:get(\"targets\")\n    if targetnames and table.contains(table.wrap(targetnames), name) then\n        return project.target(name, {namespace = self:namespace()})\n    end\nend\n\n-- get formats\nfunction xpack:formats()\n    local formats = self._formats\n    if not formats then\n        formats = hashset.new()\n        for _, format in ipairs(self:get(\"formats\")) do\n            formats:insert(format)\n        end\n        self._formats = formats\n    end\n    return formats\nend\n\n-- has the given format?\nfunction xpack:format_has(...)\n    local formats = self:formats()\n    for _, v in ipairs(table.pack(...)) do\n        if v and formats:has(v) then\n            return true\n        end\n    end\nend\n\n-- set the current format\nfunction xpack:format_set(format)\n    self._FORMAT = format\nend\n\n-- get the current format\nfunction xpack:format()\n    return self._FORMAT\nend\n\n-- get the input kind\nfunction xpack:inputkind()\n    local inputkind = self:get(\"inputkind\")\n    if inputkind == nil then\n        local inputkinds = {\n            wix      = \"binary\",\n            nsis     = \"binary\",\n            zip      = \"binary\",\n            targz    = \"binary\",\n            tarxz    = \"binary\",\n            dmg      = \"binary\",\n            appimage = \"binary\",\n            srczip   = \"source\",\n            srctargz = \"source\",\n            srctarxz = \"source\",\n            runself  = \"source\",\n            deb      = \"source\",\n            srpm     = \"source\",\n            rpm      = \"source\"\n        }\n        inputkind = inputkinds[self:format()] or \"binary\"\n    end\n    return inputkind\nend\n\n-- get the output kind\nfunction xpack:outputkind()\n    local outputkinds = {\n        wix      = \"binary\",\n        nsis     = \"binary\",\n        zip      = \"binary\",\n        targz    = \"binary\",\n        tarxz    = \"binary\",\n        dmg      = \"binary\",\n        appimage = \"binary\",\n        srczip   = \"source\",\n        srctargz = \"source\",\n        srctarxz = \"source\",\n        runself  = \"source\",\n        deb      = \"binary\",\n        srpm     = \"source\",\n        rpm      = \"binary\"\n    }\n    local outputkind = outputkinds[self:format()] or \"binary\"\n    return outputkind\nend\n\n-- pack from source files?\nfunction xpack:from_source()\n    return self:inputkind() == \"source\"\nend\n\n-- pack from binary files?\nfunction xpack:from_binary()\n    return self:inputkind() == \"binary\"\nend\n\n-- pack with source files?\nfunction xpack:with_source()\n    return self:outputkind() == \"source\"\nend\n\n-- pack with binary files?\nfunction xpack:with_binary()\n    return self:outputkind() == \"binary\"\nend\n\n-- get the build directory\nfunction xpack:builddir()\n    local dir = path.join(config.builddir(), \".xpack\", self:name())\n    if self:format() then\n        dir = path.join(dir, self:format())\n    end\n    return dir\nend\n\n-- get the build directory (deprecated)\nfunction xpack:buildir()\n    wprint(\"xpack:buildir() has been deprecated, please use xpack:builddir()\")\n    return self:builddir()\nend\n\n-- get the output directory\nfunction xpack:outputdir()\n    local outputdir = option.get(\"outputdir\")\n    if outputdir == nil then\n        outputdir = path.join(config.builddir(), \"xpack\", self:name())\n    end\n    return outputdir\nend\n\n-- get the basename\nfunction xpack:basename()\n    local basename = option.get(\"basename\") or self:get(\"basename\")\n    if basename == nil then\n        basename = self:name()\n        if self:with_source() then\n            basename = basename .. \"-src\"\n        end\n        local version = self:version()\n        if version then\n            basename = basename .. \"-\" .. version\n        end\n    end\n    -- we need filter builtin variables, e.g. $(plat), $(arch), $(version) ...\n    return filter.handle(basename, self)\nend\n\n-- get the spec variables\nfunction xpack:specvars()\n    local specvars = self._specvars\n    if specvars == nil then\n        specvars = {\n            PACKAGE_ARCH        = self:arch(),\n            PACKAGE_PLAT        = self:plat(),\n            PACKAGE_NAME        = self:name(),\n            PACKAGE_TITLE       = self:title() or \"\",\n            PACKAGE_DESCRIPTION = self:description() or \"\",\n            PACKAGE_FILENAME    = self:filename(),\n            PACKAGE_AUTHOR      = self:get(\"author\") or \"\",\n            PACKAGE_MAINTAINER  = self:get(\"maintainer\") or self:get(\"author\") or \"\",\n            PACKAGE_HOMEPAGE    = self:get(\"homepage\") or \"\",\n            PACKAGE_COPYRIGHT   = self:get(\"copyright\") or \"\",\n            PACKAGE_COMPANY     = self:get(\"company\") or \"\",\n            PACKAGE_ICONFILE    = self:get(\"iconfile\") or \"\",\n            PACKAGE_LICENSE     = self:license() or \"\",\n            PACKAGE_LICENSEFILE = self:get(\"licensefile\") or \"\"\n        }\n\n        -- get version\n        local version, version_build = self:version()\n        if version then\n            specvars.PACKAGE_VERSION = version or \"0.0.0\"\n            try {function ()\n                local v = semver.new(version)\n                if v then\n                    specvars.PACKAGE_VERSION_MAJOR = v:major() or \"0\"\n                    specvars.PACKAGE_VERSION_MINOR = v:minor() or \"0\"\n                    specvars.PACKAGE_VERSION_ALTER = v:patch() or \"0\"\n                end\n            end}\n            specvars.PACKAGE_VERSION_BUILD = version_build or \"\"\n        end\n\n        -- get git information\n        local cmds =\n        {\n            GIT_TAG         = {\"describe\", \"--tags\"},\n            GIT_TAG_LONG    = {\"describe\", \"--tags\", \"--long\"},\n            GIT_BRANCH      = {\"rev-parse\", \"--abbrev-ref\", \"HEAD\"},\n            GIT_COMMIT      = {\"rev-parse\", \"--short\", \"HEAD\"},\n            GIT_COMMIT_LONG = {\"rev-parse\", \"HEAD\"},\n            GIT_COMMIT_DATE = {\"log\", \"-1\", \"--date=format:%Y%m%d%H%M%S\", \"--format=%ad\"}\n        }\n        for name, argv in pairs(cmds) do\n            specvars[name] = function ()\n                local result\n                local git = find_tool(\"git\")\n                if git then\n                    result = try {function ()\n                        return os.iorunv(git.program, argv)\n                    end}\n                end\n                if not result then\n                    result = \"none\"\n                end\n                return result:trim()\n            end\n        end\n\n        -- get user variables\n        local vars = self:get(\"specvar\")\n        if vars then\n            table.join2(specvars, vars)\n        end\n        self._specvars = specvars\n    end\n    return specvars\nend\n\n-- get the extension\nfunction xpack:extension()\n    local extension = self:get(\"extension\")\n    if extension == nil then\n        local extensions = {\n            wix      = \".msi\",\n            nsis     = \".exe\",\n            zip      = \".zip\",\n            targz    = \".tar.gz\",\n            tarxz    = \".tar.xz\",\n            dmg      = \".dmg\",\n            appimage = \".AppImage\",\n            srczip   = \".zip\",\n            srctargz = \".tar.gz\",\n            srctarxz = \".tar.xz\",\n            runself  = \".gz.run\",\n            deb      = \".deb\",\n            srpm     = \".src.rpm\",\n            rpm      = \".rpm\"\n        }\n        extension = extensions[self:format()] or \"\"\n    end\n    return extension\nend\n\n-- get the output filename\nfunction xpack:filename()\n    return self:basename() .. self:extension()\nend\n\n-- get the output file\nfunction xpack:outputfile()\n    return path.join(self:outputdir(), self:filename())\nend\n\n-- get the package version\nfunction xpack:version()\n    local version = self:get(\"version\")\n    local version_build\n    if version == nil then\n        for _, target in ipairs(self:targets()) do\n            version, version_build = target:version()\n            if version then\n                break\n            end\n        end\n        if version == nil then\n            version, version_build = project.version()\n        end\n    else\n        version_build = self:extraconf(\"version\", version, \"build\")\n        if type(version_build) == \"string\" then\n            version_build = os.date(version_build, os.time())\n        end\n    end\n    return version, version_build\nend\n\n-- get the install files\nfunction xpack:installfiles()\n    return match_copyfiles(self, \"installfiles\", self:installdir())\nend\n\n-- get the installed root directory, this is just a temporary sandbox installation path,\n-- we may replace it with the actual installation path in the specfile\nfunction xpack:install_rootdir()\n    return path.join(self:builddir(), \"installed\", self:format())\nend\n\n-- get the installed directory\nfunction xpack:installdir(...)\n    local installdir = self:install_rootdir()\n    local prefixdir = self:prefixdir()\n    if prefixdir then\n        installdir = path.join(installdir, prefixdir)\n    end\n    return path.normalize(path.join(installdir, ...))\nend\n\n-- get the source files\nfunction xpack:sourcefiles()\n    return match_copyfiles(self, \"sourcefiles\", self:sourcedir())\nend\n\n-- get the source root directory\nfunction xpack:source_rootdir()\n    return path.join(self:builddir(), \"source\", self:format())\nend\n\n-- get the source directory\nfunction xpack:sourcedir(...)\n    local sourcedir = self:source_rootdir()\n    local prefixdir = self:prefixdir()\n    if prefixdir then\n        sourcedir = path.join(sourcedir, prefixdir)\n    end\n    return path.normalize(path.join(sourcedir, ...))\nend\n\n-- get the prefixdir\nfunction xpack:prefixdir()\n    local prefixdir = self:get(\"prefixdir\")\n    if prefixdir then\n        return filter.handle(prefixdir, self)\n    end\n    return prefixdir\nend\n\n-- get the binary directory\nfunction xpack:bindir()\n    local bindir = self:get(\"bindir\") or self:extraconf(\"prefixdir\", self:prefixdir(), \"bindir\")\n    if bindir == nil then\n        bindir = \"bin\"\n    end\n    return self:installdir(bindir)\nend\n\n-- get the library directory\nfunction xpack:libdir()\n    local libdir = self:get(\"libdir\") or self:extraconf(\"prefixdir\", self:prefixdir(), \"libdir\")\n    if libdir == nil then\n        libdir = \"lib\"\n    end\n    return self:installdir(libdir)\nend\n\n-- get the include directory\nfunction xpack:includedir()\n    local includedir = self:get(\"includedir\") or self:extraconf(\"prefixdir\", self:prefixdir(), \"includedir\")\n    if includedir == nil then\n        includedir = \"include\"\n    end\n    return self:installdir(includedir)\nend\n\n-- get the components\nfunction xpack:components()\n    local components = _g.components\n    if components == nil then\n        components = {}\n        local xpack_component_scope = project.scope(\"xpack_component\")\n        for _, component_name in ipairs(self:get(\"components\")) do\n            local scope = xpack_component_scope[component_name]\n            if scope then\n                local instance = xpack_component.new(component_name, scope, self)\n                components[component_name] = instance\n            else\n                raise(\"unknown xpack component(%s) in xpack(%s)\", component_name, self:name())\n            end\n        end\n        _g.components = components\n    end\n    return components\nend\n\n-- get the given component\nfunction xpack:component(name)\n    return self:components()[name]\nend\n\n-- new a xpack, and we need to clone scope info,\n-- because two different format packages maybe have same scope\nfunction _new(name, info)\n    local parts = name:split(\"::\", {plain = true})\n    name = parts[#parts]\n    table.remove(parts)\n    local namespace\n    if #parts > 0 then\n        namespace = table.concat(parts, \"::\")\n    end\n    return xpack {name, info:clone(), namespace}\nend\n\n-- get xpack packages\nfunction packages()\n    local packages = _g.packages\n    if not packages then\n        packages = {}\n        local packages_need = option.get(\"packages\")\n        if packages_need then\n            packages_need = hashset.from(packages_need)\n        end\n        local xpack_scope = project.scope(\"xpack\")\n        for name, scope in pairs(xpack_scope) do\n            local need = false\n            if packages_need then\n                if packages_need:has(name) then\n                    need = true\n                end\n            else\n                need = true\n            end\n            if need then\n                local formats = scope:get(\"formats\")\n                if formats then\n                    for _, format in ipairs(formats) do\n                        local instance = _new(name, scope)\n                        instance:format_set(format)\n                        table.insert(packages, instance)\n                    end\n                else\n                    raise(\"xpack(%s): formats not found, please use `set_formats()` to set it.\", scope:get(\"name\"))\n                end\n            end\n        end\n        _g.packages = packages\n    end\n    return packages\nend\n"
  },
  {
    "path": "xmake/plugins/pack/xpack_component.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xpack_component.lua\n--\n\n-- imports\nimport(\"core.base.object\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.core.base.select_script\")\nimport(\"private.core.base.match_copyfiles\")\n\n-- define module\nlocal xpack_component = xpack_component or object {_init = {\"_name\", \"_info\", \"_package\"}}\n\n-- get name\nfunction xpack_component:name()\n    return self._name\nend\n\n-- get values\nfunction xpack_component:get(name)\n    if self._info then\n        return self._info:get(name)\n    end\nend\n\n-- set values\nfunction xpack_component:set(name, ...)\n    if self._info then\n        self._info:apival_set(name, ...)\n    end\nend\n\n-- add values\nfunction xpack_component:add(name, ...)\n    if self._info then\n        self._info:apival_add(name, ...)\n    end\nend\n\n-- get the extra configuration\nfunction xpack_component:extraconf(name, item, key)\n    if self._info then\n        return self._info:extraconf(name, item, key)\n    end\nend\n\n-- get the component title\nfunction xpack_component:title()\n    return self:get(\"title\") or self:name()\nend\n\n-- get the component description\nfunction xpack_component:description()\n    return self:get(\"description\")\nend\n\n-- get xxx_script\nfunction xpack_component:script(name, generic)\n    local script = self:get(name)\n    local result = select_script(script, {plat = self:package():plat(), arch = self:package():arch()}) or generic\n    return result\nend\n\n-- get targets\nfunction xpack_component:targets()\n    local targets = self._targets\n    if not targets then\n        targets = {}\n        local targetnames = self:get(\"targets\")\n        if targetnames then\n            for _, name in ipairs(targetnames) do\n                local target = project.target(name)\n                if target then\n                    table.insert(targets, target)\n                else\n                    raise(\"xpack_component(%s): target(%s) not found!\", self:name(), name)\n                end\n            end\n        end\n        self._targets = targets\n    end\n    return targets\nend\n\n-- get the given target\nfunction xpack_component:target(name)\n    local targetnames = self:get(\"targets\")\n    if targetnames and table.contains(table.wrap(targetnames), name) then\n        return project.target(name)\n    end\nend\n\n-- get the package\nfunction xpack_component:package()\n    return self._package\nend\n\n-- get the install files\nfunction xpack_component:installfiles()\n    return match_copyfiles(self, \"installfiles\", self:package():installdir())\nend\n\n-- get the installed root directory, this is just a temporary sandbox installation path,\n-- we may replace it with the actual installation path in the specfile\nfunction xpack_component:install_rootdir()\n    return self:package():install_rootdir()\nend\n\n-- get the installed directory\nfunction xpack_component:installdir(...)\n    return self:package():installdir(...)\nend\n\n-- get the source files\nfunction xpack_component:sourcefiles()\n    return match_copyfiles(self, \"sourcefiles\", self:package():sourcedir())\nend\n\n-- get the source root directory\nfunction xpack_component:source_rootdir()\n    return self:package():souece_rootdir()\nend\n\n-- get the source directory\nfunction xpack_component:sourcedir(...)\n    return self:package():sourcedir(...)\nend\n\n-- get the binary directory\nfunction xpack_component:bindir()\n    return self:package():bindir()\nend\n\n-- get the library directory\nfunction xpack_component:libdir()\n    return self:package():libdir()\nend\n\n-- get the include directory\nfunction xpack_component:includedir()\n    return self:package():includedir()\nend\n\n-- pack from source files?\nfunction xpack_component:from_source()\n    return self:package():from_source()\nend\n\n-- pack from binary files?\nfunction xpack_component:from_binary()\n    return self:package():from_binary()\nend\n\n-- new a xpack_component\nfunction new(name, info, package)\n    return xpack_component {name, info:clone(), package}\nend\n\n"
  },
  {
    "path": "xmake/plugins/pack/zip/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\".archive\")\n\nfunction main(package)\n    archive(package)\nend\n"
  },
  {
    "path": "xmake/plugins/plugin/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"devel.git\")\nimport(\"net.fasturl\")\nimport(\"private.action.require.impl.environment\")\n\n-- get plugin urls\nfunction _plugin_urls()\n    local urls = option.get(\"plugins\")\n    if urls then\n        local result = {}\n        for _, url in ipairs(urls) do\n            table.insert(result, git.asgiturl(url) or url)\n        end\n        urls = result\n    else\n        urls = {\n        \"https://github.com/xmake-io/xmake-plugins.git\",\n        \"https://gitlab.com/tboox/xmake-plugins.git\",\n        \"https://gitee.com/tboox/xmake-plugins.git\"}\n        urls = fasturl.add(urls)\n        urls = fasturl.sort(urls)\n    end\n    return urls\nend\n\n-- get manifest path\nfunction _manifest_path()\n    return path.join(global.directory(), \"plugins\", \"manifest.txt\")\nend\n\n-- load manifest\nfunction _load_manifest()\n    local manifest_path = _manifest_path()\n    if os.isfile(manifest_path) then\n        return io.load(manifest_path)\n    end\nend\n\n-- save manifest\nfunction _save_manifest(manifest)\n    io.save(_manifest_path(), manifest)\nend\n\n-- install plugins\nfunction _install()\n\n    -- enter environment\n    environment.enter()\n\n    try\n    {\n        function ()\n\n            -- do install\n            local urls = _plugin_urls()\n            local tmpdir = os.tmpfile() .. \".dir\"\n            local plugindir = path.join(global.directory(), \"plugins\")\n            local installed_url\n            for _, url in ipairs(urls) do\n                cprint(\"installing plugins from %s ..\", url)\n                git.clone(url, {verbose = option.get(\"verbose\"), outputdir = tmpdir})\n                installed_url = url\n                break\n            end\n            for _, filepath in ipairs(os.files(path.join(tmpdir, \"*\", \"xmake.lua\"))) do\n                local srcdir = path.directory(filepath)\n                local name = path.filename(srcdir)\n                local dstdir = path.join(plugindir, name)\n                assert(not os.isdir(dstdir), \"plugin(%s) already exists!\", name)\n                os.vcp(srcdir, dstdir)\n                cprint(\"  ${yellow}->${clear} %s\", name)\n            end\n            os.tryrm(tmpdir)\n\n            -- save manifest\n            if installed_url then\n                local manifest = _load_manifest() or {}\n                manifest.urls = manifest.urls or {}\n                table.join2(manifest.urls, installed_url)\n                _save_manifest(manifest)\n            end\n            cprint(\"${bright}all plugins have been installed in %s!\", plugindir)\n        end,\n        catch\n        {\n            function (errors)\n                raise(errors)\n            end\n        }\n    }\n\n    -- leave environment\n    environment.leave()\nend\n\n-- update plugins\nfunction _update()\n\n    -- enter environment\n    environment.enter()\n\n    try\n    {\n        function ()\n\n            -- do update\n            local manifest = _load_manifest()\n            assert(manifest and manifest.urls, \"3rd plugins not found!\")\n            local urls = manifest.urls\n            local plugindir = path.join(global.directory(), \"plugins\")\n            for _, url in ipairs(urls) do\n                cprint(\"updating plugins from %s ..\", url)\n                local tmpdir = os.tmpfile() .. \".dir\"\n                git.clone(url, {verbose = option.get(\"verbose\"), outputdir = tmpdir})\n                for _, filepath in ipairs(os.files(path.join(tmpdir, \"*\", \"xmake.lua\"))) do\n                    local srcdir = path.directory(filepath)\n                    local name = path.filename(srcdir)\n                    local dstdir = path.join(plugindir, name)\n                    os.tryrm(dstdir)\n                    os.vcp(srcdir, dstdir)\n                    cprint(\"  ${yellow}->${clear} %s\", name)\n                end\n                os.tryrm(tmpdir)\n            end\n            cprint(\"${bright}all plugins have been updated in %s!\", plugindir)\n        end,\n        catch\n        {\n            function (errors)\n                raise(errors)\n            end\n        }\n    }\n\n    -- leave environment\n    environment.leave()\nend\n\n-- clear all installed plugins\nfunction _clear()\n    local plugindir = path.join(global.directory(), \"plugins\")\n    if os.isdir(plugindir) then\n        os.rmdir(plugindir)\n    end\n    cprint(\"${color.success}clear all installed plugins ok!\")\nend\n\nfunction main()\n    if option.get(\"install\") then\n        _install()\n    elseif option.get(\"update\") then\n        _update()\n    elseif option.get(\"clear\") then\n        _clear()\n    end\nend\n\n"
  },
  {
    "path": "xmake/plugins/plugin/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        plugin.lua\n--\n\ntask(\"plugin\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake plugin [options]\",\n        description = \"Manage plugins of xmake.\",\n        options = {\n            {'i', \"install\", \"k\",  nil,      \"Install plugins.\"             },\n            {'u', \"update\",  \"k\",  nil,      \"Update plugins.\"              },\n            {'c', \"clear\",   \"k\",  nil,      \"Clear all installed plugins.\" },\n            {nil, \"plugins\", \"v\",  nil,      \"The plugins path or url.\",\n                                             \"e.g.\",\n                                             \"    $ xmake plugin --install https://github.com/xmake-io/xmake-plugins\",\n                                             \"    $ xmake plugin --update\"}\n        }\n    }\n"
  },
  {
    "path": "xmake/plugins/project/clang/compile_commands.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        compile_commands.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.rule\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"private.utils.batchcmds\")\nimport(\"private.utils.executable_path\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\nimport(\"actions.test.main\", {rootdir = os.programdir(), alias = \"test_action\"})\n\n-- escape path\nfunction _escape_path(p)\n    return os.args(p, {escape = true, nowrap = true})\nend\n\n-- this sourcebatch is built?\nfunction _sourcebatch_is_built(sourcebatch)\n    -- we can only use rulename to filter them because sourcekind may be bound to multiple rules\n    local rulename = sourcebatch.rulename\n    if rulename == \"c.build\" or rulename == \"c++.build\"\n        or rulename == \"asm.build\" or rulename == \"cuda.build\"\n        or rulename == \"objc.build\" or rulename == \"objc++.build\" then\n        return true\n    end\nend\n\n-- Is there other supported source file, which come from custom rules?\nfunction _is_other_sourcefile(sourcefile)\n    local extensions = _g._other_supported_exts\n    if extensions == nil then\n        extensions = hashset.from({\".v\", \".sv\"})\n        _g._other_supported_exts = extensions\n    end\n    return extensions:has(path.extension(sourcefile))\nend\n\n-- get LSP, clangd, ccls, ...\nfunction _get_lsp()\n    local lsp = option.get(\"lsp\")\n    if lsp == nil then\n        lsp = os.getenv(\"XMAKE_GENERATOR_COMPDB_LSP\")\n    end\n    return lsp\nend\n\n-- specify windows sdk verison\nfunction _get_windows_sdk_arguments(target)\n    local args = {}\n    local msvc = target:toolchain(\"msvc\")\n    if msvc then\n        local envs = msvc:runenvs()\n        if envs then\n            for _, dir in ipairs(path.splitenv(envs.INCLUDE)) do\n                table.insert(args, \"-imsvc\")\n                table.insert(args, dir)\n            end\n        end\n    end\n    return args\nend\n\n-- translate external/system include flags, because some tools (vscode) do not support them yet.\n-- https://github.com/xmake-io/xmake/issues/1050\nfunction _translate_arguments(arguments)\n    local args = {}\n    local cc = path.basename(arguments[1]):lower()\n    local is_include = false\n    local lsp = _get_lsp()\n    for idx, arg in ipairs(arguments) do\n        -- convert path to string, maybe we need to convert path, but not supported now.\n        arg = tostring(arg)\n\n        -- see https://github.com/xmake-io/xmake/issues/1721\n        if idx == 1 and is_host(\"windows\") and path.extension(arg) == \"\" then\n            arg = arg .. \".exe\"\n        end\n        if arg:startswith(\"-isystem-after\", 1, true) then\n            arg = \"-I\" .. arg:sub(15)\n        elseif arg:startswith(\"-isystem\", 1, true) then\n            -- clangd support `-isystem`, we don't need to translate it\n            -- @see https://github.com/xmake-io/xmake/issues/3020\n            if not lsp or lsp ~= \"clangd\" then\n                arg = \"-I\" .. arg:sub(9)\n            end\n        elseif arg:find(\"[%-/]external:I\") then\n            arg = arg:gsub(\"[%-/]external:I\", \"-I\")\n        elseif arg:find(\"[%-/]external:W\") or arg:find(\"[%-/]experimental:external\") then\n            arg = nil\n        end\n        -- @see use msvc-style flags for msvc to support language-server better\n        -- https://github.com/xmake-io/xmake/issues/1284\n        if cc == \"cl\" and arg and arg:startswith(\"-\") then\n            arg = arg:gsub(\"^%-\", \"/\")\n        elseif cc == \"nvcc\" and arg then\n            -- support -I path with spaces for nvcc\n            -- https://github.com/xmake-io/xmake/issues/1726\n            if is_include then\n                if arg and arg:find(' ', 1, true) then\n                    arg = \"\\\"\" .. arg .. \"\\\"\"\n                end\n                is_include = false\n            elseif arg:startswith(\"-I\") then\n                local f = arg:sub(1, 2)\n                local v = arg:sub(3)\n                if v and v:find(' ', 1, true) then\n                    arg = f .. \"\\\"\" .. v .. \"\\\"\"\n                end\n            elseif arg:startswith(\"-ccbin=\") then\n                -- @see https://github.com/xmake-io/xmake/issues/4716\n                local f = arg:sub(1, 7)\n                local v = arg:sub(8)\n                if v then\n                    arg = f .. v:gsub(\"\\\\\\\\\", \"\\\\\")\n                end\n            end\n        end\n        if arg and arg == \"-I\" then\n            is_include = true\n        end\n        -- ignore pch flags\n        -- https://github.com/xmake-io/xmake/issues/6710\n        if arg and (arg == \"-include-pch\" or arg:endswith(\".pch\")) then\n            arg = nil\n        end\n        if arg then\n            -- improve to support for \"/usr/bin/xcrun -sdk macosx clang\"\n            -- @see\n            -- https://github.com/xmake-io/xmake/issues/3159\n            -- https://github.com/xmake-io/xmake/issues/3286\n            if idx == 1 then\n                arg = executable_path(arg)\n            end\n            table.insert(args, arg)\n        end\n    end\n    return args\nend\n\n-- make command\nfunction _make_arguments(jsonfile, arguments, opt)\n\n    -- attempt to get source file from arguments\n    opt = opt or {}\n    local sourcefile = opt.sourcefile\n    if not sourcefile then\n        for _, arg in ipairs(arguments) do\n            local sourcekind = try {function () return language.sourcekind_of(path.filename(arg)) end}\n            if sourcekind and os.isfile(arg) then\n                sourcefile = tostring(arg)\n            elseif _is_other_sourcefile(arg) and os.isfile(arg) then\n                sourcefile = tostring(arg)\n            end\n            if sourcefile then\n                break\n            end\n        end\n        if not sourcefile then\n            return\n        end\n    end\n\n    -- translate some unsupported arguments\n    arguments = _translate_arguments(arguments)\n\n    -- https://github.com/xmake-io/xmake/issues/6058\n    local lsp = _get_lsp()\n    local target = opt.target\n    local cc = path.basename(arguments[1]):lower()\n    if lsp and lsp == \"clangd\" and target and target:is_plat(\"windows\") and cc ~= \"nvcc\" then\n        table.join2(arguments, _get_windows_sdk_arguments(target))\n    end\n\n    -- escape '\"', '\\'\n    local arguments_escape = {}\n    for _, arg in ipairs(arguments) do\n        table.insert(arguments_escape, _escape_path(arg))\n    end\n\n    -- remove repeat\n    -- this is because some rules will repeatedly bind the same sourcekind, e.g. `rule(\"c++.build.modules.builder\")`\n    local key = hash.uuid(os.args(arguments_escape) .. sourcefile)\n    local map = _g.map or {}\n    _g.map = map\n    if map[key] then\n        return\n    end\n\n    -- make body\n    jsonfile:printf(\n[[%s{\n  \"directory\": \"%s\",\n  \"arguments\": [\"%s\"],\n  \"file\": \"%s\"\n}]], (_g.firstline and \"\" or \",\\n\"), _escape_path(os.projectdir()), table.concat(arguments_escape, \"\\\", \\\"\"), _escape_path(sourcefile))\n\n    -- clear first line marks\n    _g.firstline = false\n    map[key] = true\nend\n\n-- add target custom commands\nfunction _add_target_custom_commands(jsonfile, target, suffix, cmds)\n    for _, cmd in ipairs(cmds) do\n        if cmd.program then\n            _make_arguments(jsonfile, table.join(cmd.program, cmd.argv), {target = target})\n        end\n    end\nend\n\n-- add target source commands\nfunction _add_target_source_commands(jsonfile, target)\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        local sourcekind = sourcebatch.sourcekind\n        if sourcekind and _sourcebatch_is_built(sourcebatch) then\n            for index, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local objectfile = sourcebatch.objectfiles[index]\n                local arguments = table.join(compiler.compargv(sourcefile, objectfile, {target = target, sourcekind = sourcekind, rawargs=true}))\n                _make_arguments(jsonfile, arguments, {sourcefile = sourcefile, target = target})\n            end\n        end\n    end\nend\n\n-- add target commands\nfunction _add_target_commands(jsonfile, target)\n\n    -- add before commands\n    -- we use irpairs(groups), because the last group that should be given the highest priority.\n    local cmds_before = target_cmds.get_target_buildcmds(target, {stages = {\"before\", \"on\"}})\n    _add_target_custom_commands(jsonfile, target, \"before\", cmds_before)\n\n    -- add target source commands\n    _add_target_source_commands(jsonfile, target)\n\n    -- add after commands\n    local cmds_after = target_cmds.get_target_buildcmds(target, {stages = {\"after\"}})\n    _add_target_custom_commands(jsonfile, target, \"after\", cmds_after)\nend\n\n-- add target\nfunction _add_target(jsonfile, target)\n\n    -- https://github.com/xmake-io/xmake/issues/2337\n    target:data_set(\"plugin.project.kind\", \"compile_commands\")\n\n    -- disable compile_commands?\n    if target:policy(\"generator.compile_commands\") == false then\n        return\n    end\n\n    -- enter package environments\n    local oldenvs = os.addenvs(target:pkgenvs())\n\n    -- add target commands\n    _add_target_commands(jsonfile, target)\n\n    -- restore package environments\n    os.setenvs(oldenvs)\nend\n\n-- get test targets\n-- https://github.com/xmake-io/xmake/issues/4750\nfunction _get_test_targets()\n    local test_targets = _g.test_targets\n    if test_targets == nil then\n        test_targets = {}\n        for _, test in pairs(test_action.get_tests()) do\n            local target = test.target\n            if not target:is_phony() then\n                table.insert(test_targets, target)\n            end\n        end\n        _g.test_targets = test_targets\n    end\n    return test_targets\nend\n\n-- add targets\nfunction _add_targets(jsonfile)\n    jsonfile:print(\"[\")\n    _g.firstline = true\n\n    local project_targets = target_utils.get_project_targets()\n    for _, target in pairs(project_targets) do\n        if not target:is_phony() then\n            _add_target(jsonfile, target)\n        end\n    end\n    -- https://github.com/xmake-io/xmake/issues/4750\n    for _, target in ipairs(_get_test_targets()) do\n        _add_target(jsonfile, target)\n    end\n    jsonfile:print(\"]\")\nend\n\n-- prepare targets\nfunction _prepare_targets()\n    target_cmds.prepare_targets()\n    -- https://github.com/xmake-io/xmake/issues/7166\n    target_cmds.prepare_targets(_get_test_targets())\nend\n\n-- generate compilation databases for clang-based tools(compile_commands.json)\n--\n-- references:\n--  - https://clang.llvm.org/docs/JSONCompilationDatabase.html\n--  - https://sarcasm.github.io/notes/dev/compilation-database.html\n--  - http://eli.thegreenplace.net/2014/05/21/compilation-databases-for-clang-based-tools\n--\nfunction make(outputdir)\n    local oldir = os.cd(os.projectdir())\n    local jsonfile = io.open(path.join(outputdir, \"compile_commands.json\"), \"w\")\n    os.setenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\", \"true\")\n    _prepare_targets()\n    _add_targets(jsonfile)\n    jsonfile:close()\n    os.setenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\", nil)\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/clang/compile_flags.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      luzhlon\n-- @file        compile_flags.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\n\n-- make the object\nfunction _make_object(target, flags, sourcefile, objectfile)\n\n    -- get the source file kind\n    local sourcekind = language.sourcekind_of(sourcefile)\n\n    -- get compile arguments\n    local arguments = compiler.compflags(sourcefile, {target = target})\n    for i, flag in ipairs(arguments) do\n        -- only export the -I*/-D* flags\n        if flag == \"-I\" or flag == \"/I\" or flag == \"-isystem\" then\n            table.insert(flags, flag .. arguments[i + 1])\n        elseif flag:find('^-[ID]') or flag:find(\"-isystem\", 1, true) then\n            table.insert(flags, flag)\n        end\n    end\n\n    -- clear first line marks\n    _g.firstline = false\nend\n\n-- make objects\nfunction _make_objects(target, flags, sourcekind, sourcebatch)\n    for index, objectfile in ipairs(sourcebatch.objectfiles) do\n        _make_object(target, flags, sourcebatch.sourcefiles[index], objectfile)\n    end\nend\n\n-- make target\nfunction _make_target(target, flags)\n\n    -- TODO\n    -- disable precompiled header first\n    target:set(\"pcheader\", nil)\n    target:set(\"pcxxheader\", nil)\n\n    -- build source batches\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        local sourcekind = sourcebatch.sourcekind\n        if sourcekind then\n            _make_objects(target, flags, sourcekind, sourcebatch)\n        end\n    end\nend\n\n-- make all\nfunction _make_all(flags)\n    _g.firstline = true\n    local project_targets = target_utils.get_project_targets()\n    for _, target in pairs(project_targets) do\n        if not target:is_phony() and target:is_default() then\n            _make_target(target, flags)\n        end\n    end\n    return table.unique(flags)\nend\n\n-- generate compilation databases for clang-based tools(compile_flags.txt)\n--\n-- references:\n--  - https://clang.llvm.org/docs/JSONCompilationDatabase.html\n--\nfunction make(outputdir)\n    local oldir = os.cd(os.projectdir())\n\n    -- prepare targets\n    target_cmds.prepare_targets()\n\n    -- make all\n    local flags = {}\n    flags = _make_all(flags)\n\n    -- write to file\n    local flagfile = io.open(path.join(outputdir, \"compile_flags.txt\"), \"w\")\n    for i, flag in ipairs(flags) do\n        flagfile:write(flag, '\\n')\n    end\n    flagfile:close()\n\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/cmake/cmakelists.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        cmakelists.lua\n--\n\n-- imports\nimport(\"core.base.colors\")\nimport(\"core.project.project\")\nimport(\"core.project.config\")\nimport(\"core.tool.compiler\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.project.rule\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.batchcmds\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\nimport(\"rules.c++.modules.support\", {alias = \"module_support\", rootdir = os.programdir()})\nimport(\"private.utils.executable_path\")\n\n-- get cmake version\nfunction _get_cmake_version()\n    local cmake_version = _g.cmake_version\n    if not cmake_version then\n        local cmake = find_tool(\"cmake\", {version = true})\n        if cmake and cmake.version then\n            cmake_version = semver.new(cmake.version)\n        end\n        _g.cmake_version = cmake_version\n    end\n    return cmake_version\nend\n\n-- has c++ modules sources\nfunction _has_cxxmodules_sources()\n    for _, target in ipairs(project.ordertargets()) do\n        if module_support.contains_modules(target) then\n            return true\n        end\n    end\nend\n\n-- get minimal cmake version\nfunction _get_cmake_minver()\n    local cmake_minver = _g.cmake_minver\n    if not cmake_minver then\n        cmake_minver = _get_cmake_version()\n        if cmake_minver then\n            if _has_cxxmodules_sources() and cmake_minver:gt(\"3.28.0\") then\n                cmake_minver = semver.new(\"3.28.0\")\n            elseif cmake_minver:gt(\"3.15.0\") then\n                cmake_minver = semver.new(\"3.15.0\")\n            end\n        end\n        if not cmake_minver then\n            cmake_minver = semver.new(\"3.15.0\")\n        end\n        _g.cmake_minver = cmake_minver\n    end\n    return cmake_minver\nend\n\n-- tranlate path\nfunction _translate_path(filepath, outputdir)\n    filepath = path.translate(filepath)\n    if filepath == \"\" then\n        return \"\"\n    end\n    if path.is_absolute(filepath) then\n        if filepath:startswith(project.directory()) then\n            return path.relative(filepath, outputdir)\n        end\n        return filepath\n    else\n        return path.relative(path.absolute(filepath), outputdir)\n    end\nend\n\n-- escape path\nfunction _escape_path(filepath)\n    if is_host(\"windows\") then\n        filepath = path.unix(filepath)\n        filepath = filepath:gsub(' ', '\\\\ ')\n    end\n    return filepath\nend\n\n-- escape path in flag\n-- @see https://github.com/xmake-io/xmake/issues/3161\nfunction _escape_path_in_flag(target, flag)\n    if is_host(\"windows\") then\n        -- e.g. /ManifestInput:..\\..\\, /def:xxx, -isystem c:\\xxx, -Ic:\\..\n        if flag:find(\"\\\\\", 1, true) then\n            flag = _escape_path(flag)\n        end\n    end\n    return flag\nend\n\n-- get relative unix path\nfunction _get_relative_unix_path(filepath, outputdir)\n    filepath = _translate_path(filepath, outputdir)\n    filepath = _escape_path(path.translate(filepath))\n    return os.args(filepath)\nend\n\n-- get relative unix path to the cmake path\n-- @see https://github.com/xmake-io/xmake/issues/2026\nfunction _get_relative_unix_path_to_cmake(filepath, outputdir)\n    filepath = _translate_path(filepath, outputdir)\n    filepath = path.unix(path.translate(filepath))\n    if filepath and not path.is_absolute(filepath) then\n        filepath = \"${CMAKE_SOURCE_DIR}/\" .. filepath\n    end\n    return os.args(filepath)\nend\n\n-- get enabled languages\nfunction _get_project_languages()\n    local languages = {}\n    for _, target in ipairs(project.ordertargets()) do\n        for _, sourcekind in ipairs(target:sourcekinds()) do\n            if     sourcekind == \"cc\"  then table.insert(languages, \"C\")\n            elseif sourcekind == \"cxx\" then table.insert(languages, \"CXX\")\n            elseif sourcekind == \"as\"  then table.insert(languages, \"ASM\")\n            elseif sourcekind == \"cu\"  then table.insert(languages, \"CUDA\")\n            end\n        end\n    end\n    languages = table.unique(languages)\n    return languages\nend\n\n-- get configs from target\nfunction _get_configs_from_target(target, name)\n    local values = {}\n    if name:find(\"flags\", 1, true) then\n        table.join2(values, target:toolconfig(name))\n    end\n    for _, value in ipairs((target:get_from(name, \"*\"))) do\n        table.join2(values, value)\n    end\n    if not name:find(\"flags\", 1, true) then -- for includedirs, links ..\n        table.join2(values, target:toolconfig(name))\n    end\n    return table.unique(values)\nend\n\n-- Did the current cmake native support for c++ modules?\nfunction _can_native_support_for_cxxmodules()\n    local cmake_minver = _get_cmake_minver()\n    if cmake_minver and cmake_minver:ge(\"3.28\") then\n        return true\n    end\nend\n\n-- this sourcebatch is built?\nfunction _sourcebatch_is_built(sourcebatch)\n    -- we can only use rulename to filter them because sourcekind may be bound to multiple rules\n    local rulename = sourcebatch.rulename\n    if rulename == \"c.build\" or rulename == \"c++.build\"\n        or rulename == \"asm.build\" or rulename == \"cuda.build\"\n        or rulename == \"objc.build\" or rulename == \"objc++.build\"\n        or rulename == \"win.sdk.resource\" then\n        return true\n    end\n    if _can_native_support_for_cxxmodules() then\n        if rulename == \"c++.build.modules\" then\n            return true\n        end\n    end\nend\n\n-- get c++ modules rules\nfunction _get_cxxmodules_rules()\n    return {\"c++.build.modules\", \"c++.build.modules.builder\"}\nend\n\n-- translate flag\nfunction _translate_flag(flag, outputdir)\n    if flag then\n        if path.instance_of(flag) then\n            flag = flag:clone():set(_get_relative_unix_path_to_cmake(flag:rawstr(), outputdir)):str()\n        -- it may be table, https://github.com/xmake-io/xmake/issues/4816\n        elseif type(flag) == \"string\" then\n            if path.is_absolute(flag) then\n                flag = _get_relative_unix_path_to_cmake(flag, outputdir)\n            elseif flag:startswith(\"-fmodule-file=\") then\n                flag = \"-fmodule-file=\" .. _get_relative_unix_path_to_cmake(flag:sub(15), outputdir)\n            elseif flag:startswith(\"-fmodule-mapper=\") then\n                flag = \"-fmodule-mapper=\" .. _get_relative_unix_path_to_cmake(flag:sub(17), outputdir)\n            elseif flag:match(\"(.+)=(.+)\") then\n                local k, v = flag:match(\"(.+)=(.+)\")\n                if v and (v:endswith(\".ifc\") or v:endswith(\".map\")) then -- e.g. hello=xxx/hello.ifc\n                    flag = k .. \"=\" .. _get_relative_unix_path_to_cmake(v, outputdir)\n                end\n            end\n        end\n    end\n    return flag\nend\n\n-- translate flags\nfunction _translate_flags(flags, outputdir)\n    if not flags then\n        return\n    end\n    local result = {}\n    for _, flag in ipairs(flags) do\n        if type(flag) == \"table\" and not path.instance_of(flag) then\n            for _, v in ipairs(flag) do\n                table.insert(result, _translate_flag(v, outputdir))\n            end\n        else\n            table.insert(result, _translate_flag(flag, outputdir))\n        end\n    end\n    return result\nend\n\n-- map compiler flags\nfunction _map_compflags(toolname, langkind, name, values)\n    local fake_target = {\n        is_shared = function() return false end,\n        tool = function()\n            local program\n            if toolname == \"cl\" then\n                program = \"cl.exe\"\n            elseif toolname == \"gcc\" then\n                program = \"gcc\"\n            elseif toolname == \"clang\" then\n                program = \"clang\"\n            end\n            return program, toolname\n        end,\n        sourcekinds = function()\n            return langkind == \"c\" and \"cc\" or \"cxx\"\n        end\n    }\n    return compiler.map_flags(langkind, name, values, {target = fake_target})\nend\n\n-- split flag with tool prefix, e.g. clang::-Dclang\nfunction _split_flag_with_tool_prefix(flag)\n    local prefix\n    local splitinfo = flag:split(\"::\")\n    if #splitinfo == 2 then\n        prefix = splitinfo[1]\n        flag = splitinfo[2]\n    end\n    return prefix, flag\nend\n\n-- get flags from fileconfig\nfunction _get_flags_from_fileconfig(fileconfig, outputdir, name)\n    local flags = {}\n    table.join2(flags, fileconfig[name])\n    if fileconfig.force then\n        table.join2(flags, fileconfig.force[name])\n    end\n    flags = _translate_flags(flags, outputdir)\n    if #flags > 0 then\n        return flags\n    end\nend\n\n-- get flags from target\n-- @see https://github.com/xmake-io/xmake/issues/3594\nfunction _get_flags_from_target(target, flagkind)\n    local results = {}\n    local flags = _get_configs_from_target(target, flagkind)\n    for _, flag in ipairs(flags) do\n        local tools = target:extraconf(flagkind, flag, \"tools\")\n        if not flag:find(\"::\", 1, true) and tools then\n            for _, toolname in ipairs(tools) do\n                table.insert(results, toolname .. \"::\" .. flag)\n            end\n        else\n            table.insert(results, flag)\n        end\n    end\n    return results\nend\n\n-- set compiler\nfunction _set_compiler(cmakelists)\n    if config.get(\"toolchain\") then\n        local cc = platform.tool(\"cc\")\n        if cc then\n            cc = path.unix(executable_path(cc))\n            cmakelists:print(\"set(CMAKE_C_COMPILER \\\"%s\\\")\", cc)\n        end\n        local cxx, cxx_name = platform.tool(\"cxx\")\n        if cxx then\n            if cxx_name == \"clang\" or cxx_name == \"gcc\" then\n                local dir = path.directory(cxx)\n                local name = path.filename(cxx)\n                name = name:gsub(\"clang$\", \"clang++\")\n                name = name:gsub(\"clang%-\", \"clang++-\")\n                name = name:gsub(\"gcc$\", \"g++\")\n                name = name:gsub(\"gcc%-\", \"g++-\")\n                if dir ~= '.' then\n                    cxx = path.join(dir, name)\n                else\n                    cxx = name\n                end\n            end\n            cxx = path.unix(executable_path(cxx))\n            cmakelists:print(\"set(CMAKE_CXX_COMPILER \\\"%s\\\")\", cxx)\n        end\n    end\nend\n\n-- add project info\nfunction _add_project(cmakelists, outputdir)\n\n    local cmake_minver = _get_cmake_minver()\n    cmakelists:print([[# this is the build file for project %s\n# it is autogenerated by the xmake build system.\n# do not edit by hand.\n]], project.name() or \"\")\n    cmakelists:print(\"# project\")\n    cmakelists:print(\"cmake_minimum_required(VERSION %s)\", cmake_minver)\n    if cmake_minver:ge(\"3.15.0\") then\n        -- for MSVC_RUNTIME_LIBRARY\n        cmakelists:print(\"cmake_policy(SET CMP0091 NEW)\")\n    end\n\n    -- set compilers, we need set it before project( LANGUAGES..)\n    -- @see https://github.com/xmake-io/xmake/issues/5448\n    _set_compiler(cmakelists)\n\n    -- set project name\n    local project_name = project.name()\n    if not project_name then\n        local project_targets = target_utils.get_project_targets()\n        for _, target in table.orderpairs(project_targets) do\n            project_name = target:name()\n        end\n    end\n    if _can_native_support_for_cxxmodules() then\n        cmakelists:print(\"set(CMAKE_CXX_SCAN_FOR_MODULES ON)\")\n    end\n    local languages = _get_project_languages()\n    if project_name then\n        local project_info = \"\"\n        local project_version = project.version()\n        if project_version then\n            project_info = project_info .. \" VERSION \" .. project_version\n        end\n        if languages then\n            cmakelists:print(\"project(%s%s LANGUAGES %s)\", project_name, project_info, table.concat(languages, \" \"))\n        else\n            cmakelists:print(\"project(%s%s)\", project_name, project_info)\n        end\n    end\n    -- Define a language-independant global compiler_id variable\n    if (languages and #languages > 0) then\n        cmakelists:print(\"set(CURRENT_COMPILER_ID ${CMAKE_%s_COMPILER_ID})\", _get_project_languages()[1])\n    else\n        cmakelists:print(\"set(CURRENT_COMPILER_ID ${CMAKE_C_COMPILER_ID})\") -- C should be defined by default if not specified\n    end\n    cmakelists:print(\"\")\nend\n\n-- add target: phony\nfunction _add_target_phony(cmakelists, target)\n\n    -- https://github.com/xmake-io/xmake/issues/2337\n    target:data_set(\"plugin.project.kind\", \"cmakelist\")\n\n    cmakelists:printf(\"add_custom_target(%s\", target:name())\n    local deps = target:get(\"deps\")\n    if deps then\n        cmakelists:write(\" DEPENDS\")\n        for _, dep in ipairs(deps) do\n            cmakelists:write(\" \" .. dep)\n        end\n    end\n    cmakelists:print(\")\")\n    cmakelists:print(\"\")\nend\n\n-- add target: object\nfunction _add_target_object(cmakelists, target, outputdir)\n    -- Can't change the output directory of object/intermediate files in CMake\n    -- https://stackoverflow.com/questions/46330056/set-output-directory-for-cmake-object-libraries\n    cmakelists:print(\"add_library(%s OBJECT \\\"\\\")\", target:name())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES LIBRARY_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\nend\n\n-- add target: binary\nfunction _add_target_binary(cmakelists, target, outputdir)\n    cmakelists:print(\"add_executable(%s \\\"\\\")\", target:name())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES OUTPUT_NAME \\\"%s\\\")\", target:name(), target:basename())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\nend\n\n-- add target: static\nfunction _add_target_static(cmakelists, target, outputdir)\n    cmakelists:print(\"add_library(%s STATIC \\\"\\\")\", target:name())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES OUTPUT_NAME \\\"%s\\\")\", target:name(), target:basename())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\nend\n\n-- add target: shared\nfunction _add_target_shared(cmakelists, target, outputdir)\n    cmakelists:print(\"add_library(%s SHARED \\\"\\\")\", target:name())\n    cmakelists:print(\"set_target_properties(%s PROPERTIES OUTPUT_NAME \\\"%s\\\")\", target:name(), target:basename())\n    if target:is_plat(\"windows\") then\n        -- @see https://github.com/xmake-io/xmake/issues/2192\n        cmakelists:print(\"set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\n        cmakelists:print(\"set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\n    else\n        cmakelists:print(\"set_target_properties(%s PROPERTIES LIBRARY_OUTPUT_DIRECTORY \\\"%s\\\")\", target:name(), _get_relative_unix_path_to_cmake(target:targetdir(), outputdir))\n    end\nend\n\n-- add target: headeronly\nfunction _add_target_headeronly(cmakelists, target)\n    cmakelists:print(\"add_library(%s INTERFACE)\", target:name())\nend\n\n-- add target: headeronly\nfunction _add_target_moduleonly(cmakelists, target)\n    cmakelists:print(\"add_custom_target(%s)\", target:name())\nend\n\n-- add target dependencies\nfunction _add_target_dependencies(cmakelists, target)\n    local deps = {}\n    for _, dep in ipairs(target:orderdeps()) do\n        if not dep:is_object() then\n            table.insert(deps, dep:name())\n        end\n    end\n\n    if #deps ~= 0 then\n        cmakelists:printf(\"add_dependencies(%s\", target:name())\n        for _, dep in ipairs(deps) do\n            cmakelists:write(\" \" .. dep)\n        end\n        cmakelists:print(\")\")\n    end\nend\n\nfunction _print_target_sources(cmakelists, target, files, visibility, opt)\n    opt = opt or {}\n    local cmake_version = _get_cmake_version()\n    local has_fileset_support = cmake_version and cmake_version:ge(\"3.23\")\n    local fileset = \"\"\n    if has_fileset_support and opt.set then\n        fileset = \"FILE_SET \" .. opt.set .. \" FILES\"\n    end\n\n    cmakelists:print(\"target_sources(%s %s %s\", target:name(), visibility, fileset)\n    for _, file in ipairs(files) do\n        cmakelists:print(\"    \" .. file)\n    end\n    cmakelists:print(\")\")\nend\n\n-- add target sources\nfunction _add_target_sources(cmakelists, target, outputdir)\n    local has_cuda = false\n    local sourcebatches = target:sourcebatches()\n    for name, sourcebatch in table.orderpairs(sourcebatches) do\n        local public_sources\n        local private_sources\n        if _sourcebatch_is_built(sourcebatch) then\n            local module_sourcebatch = false\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                if _has_cxxmodules_sources() and name == \"c++.build.modules\" then\n                    module_sourcebatch = true\n                    local fileconfig = target:fileconfig(sourcefile)\n                    if fileconfig and fileconfig.public then\n                        public_sources = public_sources or {}\n                        table.insert(public_sources, _get_relative_unix_path(sourcefile, outputdir))\n                    else\n                        private_sources = private_sources or {}\n                        table.insert(private_sources, _get_relative_unix_path(sourcefile, outputdir))\n                    end\n                else\n                    private_sources = private_sources or {}\n                    table.insert(private_sources, _get_relative_unix_path(sourcefile, outputdir))\n                end\n            end\n            if public_sources then\n                cmakelists:print(format(\"# public sourcefiles from sourcebatch %s for target %s\", name, target:fullname()))\n                _print_target_sources(cmakelists, target, public_sources, \"PUBLIC\", {set = module_sourcebatch and \"CXX_MODULES\"})\n            end\n            if private_sources then\n                cmakelists:print(format(\"# private sourcefiles from sourcebatch %s for target %s\", name, target:fullname()))\n                _print_target_sources(cmakelists, target, private_sources, \"PRIVATE\", {set = module_sourcebatch and \"CXX_MODULES\"})\n            end\n        end\n        if sourcebatch.sourcekind == \"cu\" then\n            has_cuda = true\n        end\n    end\n    if target:headerfiles() then\n        local public_headers\n        local private_headers\n        for _, headerfile in ipairs(target:headerfiles()) do\n            local fileconfig = target:fileconfig(headerfile)\n            if fileconfig and fileconfig.public then\n                public_headers = public_headers or {}\n                table.insert(public_headers, _get_relative_unix_path(headerfile, outputdir))\n            else\n                private_headers = private_headers or {}\n                table.insert(private_headers, _get_relative_unix_path(headerfile, outputdir))\n            end\n        end\n        if public_headers then\n            cmakelists:print(format(\"# public headers for target %s\", target:fullname()))\n            _print_target_sources(cmakelists, target, public_headers, \"PUBLIC\", {set = \"HEADERS\"})\n        end\n        if private_headers then\n            cmakelists:print(format(\"# private headers for target %s\", target:fullname()))\n            _print_target_sources(cmakelists, target, private_headers, \"PRIVATE\", {set = \"HEADERS\"})\n        end\n    end\n    if has_cuda then\n        cmakelists:print(\"set_target_properties(%s PROPERTIES CUDA_SEPARABLE_COMPILATION ON)\", target:name())\n        local devlink = target:policy(\"build.cuda.devlink\") or target:values(\"cuda.build.devlink\")\n        if devlink ~= nil then\n            cmakelists:print(\"set_target_properties(%s PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS %s)\", target:name(), devlink and \"ON\" or \"OFF\")\n        end\n    end\nend\n\n-- add target source groups\n-- @see https://github.com/xmake-io/xmake/issues/1149\nfunction _add_target_source_groups(cmakelists, target, outputdir)\n    local filegroups = target:get(\"filegroups\")\n    for _, filegroup in ipairs(filegroups) do\n        local files = target:extraconf(\"filegroups\", filegroup, \"files\") or \"**\"\n        local mode = target:extraconf(\"filegroups\", filegroup, \"mode\")\n        local rootdir = target:extraconf(\"filegroups\", filegroup, \"rootdir\")\n        assert(rootdir, \"please set root directory, e.g. add_filegroups(%s, {rootdir = 'xxx'})\", filegroup)\n        local sources = {}\n        local recurse_sources = {}\n        if path.is_absolute(rootdir) then\n            rootdir = _get_relative_unix_path(rootdir, outputdir)\n        else\n            rootdir = string.format(\"${CMAKE_CURRENT_SOURCE_DIR}/%s\", _get_relative_unix_path(rootdir, outputdir))\n        end\n        for _, filepattern in ipairs(files) do\n            if filepattern:find(\"**\", 1, true) then\n                filepattern = filepattern:gsub(\"%*%*\", \"*\")\n                table.insert(recurse_sources, _get_relative_unix_path(path.join(rootdir, filepattern), outputdir))\n            else\n                table.insert(sources, _get_relative_unix_path(path.join(rootdir, filepattern), outputdir))\n            end\n        end\n        if #sources > 0 then\n            cmakelists:print(\"FILE(GLOB %s_GROUP_SOURCE_LIST %s)\", target:name(), table.concat(sources, \" \"))\n            if mode and mode == \"plain\" then\n                cmakelists:print(\"source_group(%s FILES ${%s_GROUP_SOURCE_LIST})\",\n                    _get_relative_unix_path(filegroup, outputdir), target:name())\n            else\n                cmakelists:print(\"source_group(TREE %s PREFIX %s FILES ${%s_GROUP_SOURCE_LIST})\",\n                    rootdir, _get_relative_unix_path(filegroup, outputdir), target:name())\n            end\n        end\n        if #recurse_sources > 0 then\n            cmakelists:print(\"FILE(GLOB_RECURSE %s_GROUP_RECURSE_SOURCE_LIST %s)\", target:name(), table.concat(recurse_sources, \" \"))\n            if mode and mode == \"plain\" then\n                cmakelists:print(\"source_group(%s FILES ${%s_GROUP_RECURSE_SOURCE_LIST})\",\n                    _get_relative_unix_path(filegroup, outputdir), target:name())\n            else\n                cmakelists:print(\"source_group(TREE %s PREFIX %s FILES ${%s_GROUP_RECURSE_SOURCE_LIST})\",\n                    rootdir, _get_relative_unix_path(filegroup, outputdir), target:name())\n            end\n        end\n    end\nend\n\n-- add target precompiled header\nfunction _add_target_precompiled_header(cmakelists, target, outputdir)\n    local precompiled_header = target:get(\"pcheader\") or target:get(\"pcxxheader\")\n    if precompiled_header then\n        cmakelists:print(\"target_precompile_headers(%s PRIVATE\", target:name())\n        cmakelists:print(\"    $<$<COMPILE_LANGUAGE:%s>:${CMAKE_CURRENT_SOURCE_DIR}/%s>\",\n            target:get(\"pcxxheader\") and \"CXX\" or \"C\",\n            _get_relative_unix_path(precompiled_header, outputdir))\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target include directories\nfunction _add_target_include_directories(cmakelists, target, outputdir)\n    local includedirs = _get_configs_from_target(target, \"includedirs\")\n    if #includedirs > 0 then\n        local access_type = target:kind() == \"headeronly\" and \"INTERFACE\" or \"PRIVATE\"\n        cmakelists:print(\"target_include_directories(%s %s\", target:name(), access_type)\n        for _, includedir in ipairs(includedirs) do\n            cmakelists:print(\"    \" .. _get_relative_unix_path(includedir, outputdir))\n        end\n        cmakelists:print(\")\")\n    end\n    local includedirs_interface = target:get(\"includedirs\", {interface = true})\n    if includedirs_interface then\n        cmakelists:print(\"target_include_directories(%s INTERFACE\", target:name())\n        for _, headerdir in ipairs(includedirs_interface) do\n            cmakelists:print(\"    \" .. _get_relative_unix_path(headerdir, outputdir))\n        end\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target system include directories\n-- we disable system/external includes first, because cmake doesn’t seem to be able to support msvc /external:I\n-- https://github.com/xmake-io/xmake/issues/1050\nfunction _add_target_sysinclude_directories(cmakelists, target, outputdir)\n    local includedirs = _get_configs_from_target(target, \"sysincludedirs\")\n    if #includedirs > 0 then\n        cmakelists:print(\"target_include_directories(%s SYSTEM PRIVATE\", target:name())\n        for _, includedir in ipairs(includedirs) do\n            cmakelists:print(\"    \" .. _get_relative_unix_path(includedir, outputdir))\n        end\n        cmakelists:print(\")\")\n    end\n    local includedirs_interface = target:get(\"sysincludedirs\", {interface = true})\n    if includedirs_interface then\n        cmakelists:print(\"target_include_directories(%s SYSTEM INTERFACE\", target:name())\n        for _, headerdir in ipairs(includedirs_interface) do\n            cmakelists:print(\"    \" .. _get_relative_unix_path(headerdir, outputdir))\n        end\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target framework directories\nfunction _add_target_framework_directories(cmakelists, target, outputdir)\n    local frameworkdirs = _get_configs_from_target(target, \"frameworkdirs\")\n    if #frameworkdirs > 0 then\n        cmakelists:print(\"target_compile_options(%s PRIVATE\", target:name())\n        for _, frameworkdir in ipairs(frameworkdirs) do\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:C>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:CXX>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:OBJC>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:OBJCXX>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n        end\n        cmakelists:print(\")\")\n        local cmake_minver = _get_cmake_minver()\n        if cmake_minver:ge(\"3.13.0\") then\n            cmakelists:print(\"target_link_options(%s PRIVATE\", target:name())\n        else\n            cmakelists:print(\"target_link_libraries(%s PRIVATE\", target:name())\n        end\n        for _, frameworkdir in ipairs(frameworkdirs) do\n            cmakelists:print(\"    -F\" .. _get_relative_unix_path(frameworkdir, outputdir))\n        end\n        cmakelists:print(\")\")\n    end\n    local frameworkdirs_interface = target:get(\"frameworkdirs\", {interface = true})\n    if frameworkdirs_interface then\n        cmakelists:print(\"target_compile_options(%s PRIVATE\", target:name())\n        for _, frameworkdir in ipairs(frameworkdirs_interface) do\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:C>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:CXX>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:OBJC>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n            cmakelists:print(\"    $<$<COMPILE_LANGUAGE:OBJCXX>:-F\" .. _get_relative_unix_path(frameworkdir, outputdir) .. \">\")\n        end\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target compile definitions\nfunction _add_target_compile_definitions(cmakelists, target)\n    local defines = _get_configs_from_target(target, \"defines\")\n    if #defines > 0 then\n        cmakelists:print(\"target_compile_definitions(%s PRIVATE\", target:name())\n        for _, define in ipairs(defines) do\n            cmakelists:print(\"    \" .. define)\n        end\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target source files flags\nfunction _add_target_sourcefiles_flags(cmakelists, target, sourcefile, name, outputdir)\n    local fileconfig = target:fileconfig(sourcefile)\n    if fileconfig then\n        local flags = _get_flags_from_fileconfig(fileconfig, outputdir, name)\n        if flags and #flags > 0 then\n            cmakelists:print(\"set_source_files_properties(\"\n                .. _get_relative_unix_path_to_cmake(sourcefile, outputdir)\n                .. \" PROPERTIES COMPILE_OPTIONS\")\n            local flagstrs = {}\n            for _, flag in ipairs(flags) do\n                if name == \"cxxflags\" then\n                    table.insert(flagstrs, \"$<$<COMPILE_LANGUAGE:CXX>:\" .. flag .. \">\")\n                elseif name == \"cflags\" then\n                    table.insert(flagstrs, \"$<$<COMPILE_LANGUAGE:C>:\" .. flag .. \">\")\n                elseif name == \"cxflags\" then\n                    table.insert(flagstrs, \"$<$<COMPILE_LANGUAGE:C>:\" .. flag .. \">\")\n                    table.insert(flagstrs, \"$<$<COMPILE_LANGUAGE:CXX>:\" .. flag .. \">\")\n                elseif name == \"cuflags\" then\n                    table.insert(flagstrs, \"$<$<COMPILE_LANGUAGE:CUDA>:\" .. flag .. \">\")\n                end\n            end\n            cmakelists:print(\"    \\\"%s\\\"\", table.concat(flagstrs, \";\"))\n            cmakelists:print(\")\")\n        end\n    end\nend\n\n-- add target compile options\nfunction _add_target_compile_options(cmakelists, target, outputdir)\n    local cflags   = _get_flags_from_target(target, \"cflags\")\n    local cxflags  = _get_flags_from_target(target, \"cxflags\")\n    local cxxflags = _get_flags_from_target(target, \"cxxflags\")\n    local cuflags  = _get_flags_from_target(target, \"cuflags\")\n    local toolnames = hashset.new()\n    local function _add_target_compile_options_for_compiler(toolname)\n        if #cflags > 0 or #cxflags > 0 or #cxxflags > 0 or #cuflags > 0 then\n            cmakelists:print(\"target_compile_options(%s PRIVATE\", target:name())\n            for _, flag in ipairs(_translate_flags(cflags, outputdir)) do\n                local prefix\n                prefix, flag = _split_flag_with_tool_prefix(flag)\n                if prefix == toolname then\n                    flag = _escape_path_in_flag(target, flag)\n                    cmakelists:print(\"    $<$<COMPILE_LANGUAGE:C>:\" .. flag .. \">\")\n                end\n                if prefix then\n                    toolnames:insert(prefix)\n                end\n            end\n            for _, flag in ipairs(_translate_flags(cxflags, outputdir)) do\n                local prefix\n                prefix, flag = _split_flag_with_tool_prefix(flag)\n                if prefix == toolname then\n                    flag = _escape_path_in_flag(target, flag)\n                    cmakelists:print(\"    $<$<COMPILE_LANGUAGE:C>:\" .. flag .. \">\")\n                    cmakelists:print(\"    $<$<COMPILE_LANGUAGE:CXX>:\" .. flag .. \">\")\n                end\n                if prefix then\n                    toolnames:insert(prefix)\n                end\n            end\n            for _, flag in ipairs(_translate_flags(cxxflags, outputdir)) do\n                local prefix\n                prefix, flag = _split_flag_with_tool_prefix(flag)\n                if prefix == toolname then\n                    flag = _escape_path_in_flag(target, flag)\n                    cmakelists:print(\"    $<$<COMPILE_LANGUAGE:CXX>:\" .. flag .. \">\")\n                end\n                if prefix then\n                    toolnames:insert(prefix)\n                end\n            end\n            for _, flag in ipairs(_translate_flags(cuflags, outputdir)) do\n                local prefix\n                prefix, flag = _split_flag_with_tool_prefix(flag)\n                if prefix == toolname then\n                    flag = _escape_path_in_flag(target, flag)\n                    cmakelists:print(\"    $<$<COMPILE_LANGUAGE:CUDA>:\" .. flag .. \">\")\n                end\n                if prefix then\n                    toolnames:insert(prefix)\n                end\n            end\n            cmakelists:print(\")\")\n        end\n    end\n    _add_target_compile_options_for_compiler()\n    local compilernames = {\n        clang = \"Clang\",\n        clangxx = \"Clang\",\n        gcc = \"GNU\",\n        gxx = \"GNU\",\n        cl = \"MSVC\",\n        link = \"MSVC\"\n    }\n    for _, toolname in toolnames:keys() do\n        local name = compilernames[toolname]\n        if name then\n            cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"%s\\\")\", name)\n            _add_target_compile_options_for_compiler(toolname)\n            cmakelists:print(\"endif()\")\n        end\n    end\n\n    -- add cflags/cxxflags for the specific source files\n    local sourcebatches = target:sourcebatches()\n    for _, sourcebatch in table.orderpairs(sourcebatches) do\n        if _sourcebatch_is_built(sourcebatch) then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                _add_target_sourcefiles_flags(cmakelists, target, sourcefile, \"cxxflags\", outputdir)\n                _add_target_sourcefiles_flags(cmakelists, target, sourcefile, \"cflags\", outputdir)\n                _add_target_sourcefiles_flags(cmakelists, target, sourcefile, \"cxflags\", outputdir)\n                _add_target_sourcefiles_flags(cmakelists, target, sourcefile, \"cuflags\", outputdir)\n            end\n        end\n    end\nend\n\n-- add target values\nfunction _add_target_values(cmakelists, target, name)\n    local values = target:get(name)\n    if values then\n        if name:endswith(\"s\") then\n            name = name:sub(1, #name - 1)\n        end\n        cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")\")\n        local flags_cl = _map_compflags(\"cl\", \"c\", name, values)\n        for _, flag in ipairs(flags_cl) do\n            cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), flag)\n        end\n        cmakelists:print(\"elseif(CURRENT_COMPILER_ID STREQUAL \\\"Clang\\\")\")\n        local flags_clang = _map_compflags(\"clang\", \"c\", name, values)\n        for _, flag in ipairs(flags_clang) do\n            cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), flag)\n        end\n        cmakelists:print(\"elseif(CURRENT_COMPILER_ID STREQUAL \\\"GNU\\\")\")\n        local flags_gcc = _map_compflags(\"gcc\", \"c\", name, values)\n        for _, flag in ipairs(flags_gcc) do\n            cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), flag)\n        end\n        cmakelists:print(\"endif()\")\n    end\nend\n\n-- add target warnings\nfunction _add_target_warnings(cmakelists, target)\n    _add_target_values(cmakelists, target, \"warnings\")\nend\n\n-- add target encodings\nfunction _add_target_encodings(cmakelists, target)\n    _add_target_values(cmakelists, target, \"encodings\")\nend\n\n-- add target exceptions\nfunction _add_target_exceptions(cmakelists, target)\n    local exceptions = target:get(\"exceptions\")\n    if exceptions then\n        if exceptions == \"none\" then\n            cmakelists:print(\"string(REPLACE \\\"/EHsc\\\" \\\"\\\" CMAKE_CXX_FLAGS \\\"${CMAKE_CXX_FLAGS}\\\")\")\n        else\n            _add_target_values(cmakelists, target, \"exceptions\")\n        end\n    end\nend\n\n-- add target languages\nfunction _add_target_languages(cmakelists, target)\n    local features =\n    {\n        c89       = \"c_std_90\"\n    ,   c99       = \"c_std_99\"\n    ,   c11       = \"c_std_11\"\n    ,   c17       = \"c_std_17\"\n    ,   c23       = \"c_std_23\"\n    ,   clatest   = \"c_std_latest\"\n    ,   cxx98     = \"cxx_std_98\"\n    ,   cxx11     = \"cxx_std_11\"\n    ,   cxx14     = \"cxx_std_14\"\n    ,   cxx17     = \"cxx_std_17\"\n    ,   cxx20     = \"cxx_std_20\"\n    ,   cxx23     = \"cxx_std_23\"\n    ,   cxx26     = \"cxx_std_26\"\n    ,   cxxlatest = \"cxx_std_latest\"\n    }\n    local languages = target:get(\"languages\")\n    if languages then\n        for _, lang in ipairs(languages) do\n            local has_ext = false\n            -- c | c++ | gnu | gnu++\n            local flag = lang:replace('xx', '++'):replace('latest', ''):gsub('%d', '')\n            if lang:startswith(\"gnu\") then\n                lang = 'c' .. lang:sub(4)\n                has_ext = true\n            end\n            local feature = features[lang] or (features[lang:replace(\"++\", \"xx\")])\n            if feature then\n                cmakelists:print(\"set_target_properties(%s PROPERTIES %s_EXTENSIONS %s)\", target:name(), flag:endswith('++') and 'CXX' or 'C', has_ext and \"ON\" or \"OFF\")\n                if feature:endswith('_latest') then\n                    if flag:endswith('++') then\n                        cmakelists:print('foreach(standard 26 23 20 17 14 11 98)')\n                        cmakelists:print('    include(CheckCXXCompilerFlag)')\n                        cmakelists:print('    if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")')\n                        cmakelists:print('        check_cxx_compiler_flag(\"/std:%s${standard}\" %s_support_%s_standard_${standard})', flag, target:name(), flag)\n                        cmakelists:print('    else()')\n                        cmakelists:print('        check_cxx_compiler_flag(\"-std=%s${standard}\" %s_support_%s_standard_${standard})', flag, target:name(), flag)\n                        cmakelists:print('    endif()')\n                        cmakelists:print('    if(%s_support_%s_standard_${standard})', target:name(), flag)\n                        cmakelists:print('        target_compile_features(%s PRIVATE cxx_std_${standard})', target:name())\n                        cmakelists:print('        break()')\n                        cmakelists:print('    endif()')\n                        cmakelists:print('endforeach()')\n                    else\n                        cmakelists:print('foreach(standard 23 17 11 99 90)')\n                        cmakelists:print('    include(CheckCCompilerFlag)')\n                        cmakelists:print('    if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")')\n                        cmakelists:print('        check_c_compiler_flag(\"/std:%s${standard}\" %s_support_%s_standard_${standard})', flag, target:name(), flag)\n                        cmakelists:print('    else()')\n                        cmakelists:print('        check_c_compiler_flag(\"-std=%s${standard}\" %s_support_%s_standard_${standard})', flag, target:name(), flag)\n                        cmakelists:print('    endif()')\n                        cmakelists:print('    if(%s_support_%s_standard_${standard})', target:name(), flag)\n                        cmakelists:print('        target_compile_features(%s PRIVATE c_std_${standard})', target:name())\n                        cmakelists:print('        break()')\n                        cmakelists:print('    endif()')\n                        cmakelists:print('endforeach()')\n                    end\n                else\n                    cmakelists:print('target_compile_features(%s PRIVATE %s)', target:name(), feature)\n                end\n            end\n        end\n    end\nend\n\n-- add target optimization\nfunction _add_target_optimization(cmakelists, target)\n    local flags_gcc =\n    {\n        none       = \"-O0\"\n    ,   fast       = \"-O1\"\n    ,   faster     = \"-O2\"\n    ,   fastest    = \"-O3\"\n    ,   smallest   = \"-Os\"\n    ,   aggressive = \"-Ofast\"\n    }\n    local flags_msvc =\n    {\n        none        = \"$<$<CONFIG:Debug>:-Od>\"\n    ,   faster      = \"$<$<CONFIG:Release>:-Ox>\"\n    ,   fastest     = \"$<$<CONFIG:Release>:-O2>\"\n    ,   smallest    = \"$<$<CONFIG:Release>:-O1>\"\n    ,   aggressive  = \"$<$<CONFIG:Release>:-O2>\"\n    }\n    local optimization = target:get(\"optimize\")\n    if optimization then\n        cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")\")\n        cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), flags_msvc[optimization])\n        cmakelists:print(\"else()\")\n        cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), flags_gcc[optimization])\n        cmakelists:print(\"endif()\")\n    end\nend\n\n-- add target symbols\nfunction _add_target_symbols(cmakelists, target)\n    local symbols = target:get(\"symbols\")\n    if symbols then\n        local flags_gcc = {}\n        local flags_msvc = {}\n        local levels = hashset.from(table.wrap(symbols))\n        if levels:has(\"debug\") then\n            table.insert(flags_gcc, \"-g\")\n            if levels:has(\"edit\") then\n                table.insert(flags_msvc, \"-ZI\")\n            elseif levels:has(\"embed\") then\n                table.insert(flags_msvc, \"-Z7\")\n            else\n                table.insert(flags_msvc, \"-Zi\")\n            end\n        end\n        if levels:has(\"hidden\") then\n            table.insert(flags_gcc, \"-fvisibility=hidden\")\n        end\n        cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")\")\n        if #flags_msvc > 0 then\n            cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), table.concat(flags_msvc, \" \"))\n        end\n        cmakelists:print(\"else()\")\n        if #flags_gcc > 0 then\n            cmakelists:print(\"    target_compile_options(%s PRIVATE %s)\", target:name(), table.concat(flags_gcc, \" \"))\n        end\n        cmakelists:print(\"endif()\")\n    end\nend\n\n-- add target runtimes\n--\n-- https://github.com/xmake-io/xmake/issues/1661#issuecomment-927979489\n-- https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html\n--\nfunction _add_target_runtimes(cmakelists, target)\n    local cmake_minver = _get_cmake_minver()\n    if cmake_minver:ge(\"3.15.0\") then\n        local runtimes = target:get(\"runtimes\")\n        cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")\")\n        if runtimes then\n            if runtimes == \"MT\" then\n                runtimes = \"MultiThreaded\"\n            elseif runtimes == \"MTd\" then\n                runtimes = \"MultiThreadedDebug\"\n            elseif runtimes == \"MD\" then\n                runtimes = \"MultiThreadedDLL\"\n            elseif runtimes == \"MDd\" then\n                runtimes = \"MultiThreadedDebugDLL\"\n            end\n        else\n            runtimes = \"MultiThreaded$<$<CONFIG:Debug>:Debug>\"\n        end\n        cmakelists:print('    set_property(TARGET %s PROPERTY', target:name())\n        cmakelists:print('        MSVC_RUNTIME_LIBRARY \"%s\")', runtimes)\n        cmakelists:print(\"endif()\")\n    end\nend\n\n-- add target link libraries\nfunction _add_target_link_libraries(cmakelists, target, outputdir)\n\n    -- add links\n    local links      = _get_configs_from_target(target, \"links\")\n    local syslinks   = _get_configs_from_target(target, \"syslinks\")\n    local frameworks = _get_configs_from_target(target, \"frameworks\")\n    if #frameworks > 0 then\n        for _, framework in ipairs(frameworks) do\n            table.insert(links, \"\\\"-framework \" .. framework .. \"\\\"\")\n        end\n    end\n    table.join2(links, syslinks)\n    if #links > 0 then\n        cmakelists:print(\"target_link_libraries(%s PRIVATE\", target:name())\n        for _, link in ipairs(links) do\n            cmakelists:print(\"    \" .. link)\n        end\n        cmakelists:print(\")\")\n    end\n\n    -- get c++ modules rules\n    local cxxmodules_rules\n    if _can_native_support_for_cxxmodules() then\n        cxxmodules_rules = _get_cxxmodules_rules()\n    end\n    if cxxmodules_rules then\n        cxxmodules_rules = hashset.from(cxxmodules_rules)\n    else\n        cxxmodules_rules = hashset.new()\n    end\n\n    -- add other object files, maybe from custom rules\n    local objectfiles_set = hashset.new()\n    local sourcebatches = target:sourcebatches()\n    for _, sourcebatch in table.orderpairs(sourcebatches) do\n        if _sourcebatch_is_built(sourcebatch) or cxxmodules_rules:has(sourcebatch.rulename) then\n            for _, objectfile in ipairs(sourcebatch.objectfiles) do\n                objectfiles_set:insert(objectfile)\n            end\n        end\n    end\n\n    local object_deps = {}\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:is_object() then\n            table.insert(object_deps, dep:name())\n            for _, obj in ipairs(dep:objectfiles()) do\n                objectfiles_set:insert(obj)\n            end\n        end\n    end\n\n\n    local has_links = #target:objectfiles() > objectfiles_set:size()\n    local key = target:name() .. \"_\" .. hash.rand64()\n    if has_links then\n        cmakelists:print(\"add_library(target_objectfiles_%s OBJECT IMPORTED GLOBAL)\", key)\n        cmakelists:print(\"set_property(TARGET target_objectfiles_%s PROPERTY IMPORTED_OBJECTS\", key)\n        for _, objectfile in ipairs(target:objectfiles()) do\n            if not objectfiles_set:has(objectfile) then\n                cmakelists:print(\"    \" .. _get_relative_unix_path_to_cmake(objectfile, outputdir))\n            end\n        end\n    end\n\n    if #object_deps ~= 0 then\n        if not has_links then\n            cmakelists:print(\"add_library(target_objectfiles_%s OBJECT IMPORTED GLOBAL)\", key)\n            cmakelists:print(\"set_property(TARGET target_objectfiles_%s PROPERTY IMPORTED_OBJECTS\", key)\n            has_links = true\n        end\n        for _, dep in ipairs(object_deps) do\n            cmakelists:print(\"    \" .. dep)\n        end\n    end\n\n    if has_links then\n        cmakelists:print(\")\")\n        cmakelists:print(\"target_link_libraries(%s PRIVATE target_objectfiles_%s)\", target:name(), key)\n    end\nend\n\n-- add target link directories\nfunction _add_target_link_directories(cmakelists, target, outputdir)\n    local linkdirs = _get_configs_from_target(target, \"linkdirs\")\n    if #linkdirs > 0 then\n        local cmake_minver = _get_cmake_minver()\n        if cmake_minver:ge(\"3.13.0\") then\n            cmakelists:print(\"target_link_directories(%s PRIVATE\", target:name())\n            for _, linkdir in ipairs(linkdirs) do\n                cmakelists:print(\"    \" .. _get_relative_unix_path(linkdir, outputdir))\n            end\n            cmakelists:print(\")\")\n        else\n            cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"MSVC\\\")\")\n            cmakelists:print(\"    target_link_libraries(%s PRIVATE\", target:name())\n            for _, linkdir in ipairs(linkdirs) do\n                cmakelists:print(\"        -libpath:\" .. _get_relative_unix_path(linkdir, outputdir))\n            end\n            cmakelists:print(\"    )\")\n            cmakelists:print(\"else()\")\n            cmakelists:print(\"    target_link_libraries(%s PRIVATE\", target:name())\n            for _, linkdir in ipairs(linkdirs) do\n                cmakelists:print(\"        -L\" .. _get_relative_unix_path(linkdir, outputdir))\n            end\n            cmakelists:print(\"    )\")\n            cmakelists:print(\"endif()\")\n        end\n    end\nend\n\n-- add target link options\nfunction _add_target_link_options(cmakelists, target, outputdir)\n    local ldflags = _get_flags_from_target(target, \"ldflags\")\n    local shflags = _get_flags_from_target(target, \"shflags\")\n    local toolnames = hashset.new()\n    local function _add_target_link_options_for_linker(toolname)\n        if #ldflags > 0 or #shflags > 0 then\n            local flags = {}\n            for _, flag in ipairs(table.unique(table.join(ldflags, shflags))) do\n                table.insert(flags, _translate_flag(flag, outputdir))\n            end\n            if #flags > 0 then\n                local cmake_minver = _get_cmake_minver()\n                if cmake_minver:ge(\"3.13.0\") then\n                    cmakelists:print(\"target_link_options(%s PRIVATE\", target:name())\n                else\n                    cmakelists:print(\"target_link_libraries(%s PRIVATE\", target:name())\n                end\n                for _, flag in ipairs(flags) do\n                    local prefix\n                    prefix, flag = _split_flag_with_tool_prefix(flag)\n                    if prefix == toolname then\n                        flag = _escape_path_in_flag(target, flag)\n                        -- @see https://github.com/xmake-io/xmake/issues/4196\n                        if cmake_minver:ge(\"3.12.0\") and #os.argv(flag) > 1 then\n                            cmakelists:print(\"    \" .. os.args(\"SHELL:\" .. flag))\n                        else\n                            cmakelists:print(\"    \" .. flag)\n                        end\n                    end\n                    if prefix then\n                        toolnames:insert(prefix)\n                    end\n                end\n                cmakelists:print(\")\")\n            end\n        end\n    end\n    _add_target_link_options_for_linker()\n    local linkernames = {\n        clang = \"Clang\",\n        clangxx = \"Clang\",\n        gcc = \"GNU\",\n        gxx = \"GNU\",\n        cl = \"MSVC\",\n        link = \"MSVC\"\n    }\n    for _, toolname in toolnames:keys() do\n        local name = linkernames[toolname]\n        if name then\n            cmakelists:print(\"if(CURRENT_COMPILER_ID STREQUAL \\\"%s\\\")\", name)\n            _add_target_link_options_for_linker(toolname)\n            cmakelists:print(\"endif()\")\n        end\n    end\nend\n\n-- get command string\nfunction _get_command_string(cmd, outputdir)\n    local kind = cmd.kind\n    local opt = cmd.opt\n    if cmd.program then\n        -- @see https://github.com/xmake-io/xmake/discussions/2156\n        local argv = {}\n        for _, v in ipairs(cmd.argv) do\n            table.insert(argv, _translate_flag(v, outputdir))\n        end\n        local command = _escape_path(cmd.program) .. \" \" .. os.args(argv)\n        if opt and opt.curdir then\n            command = \"${CMAKE_COMMAND} -E chdir \" .. _get_relative_unix_path_to_cmake(opt.curdir, outputdir) .. \" \" .. command\n        end\n        return command\n    elseif kind == \"cp\" then\n        if os.isdir(cmd.srcpath) then\n            return string.format(\"${CMAKE_COMMAND} -E copy_directory %s %s\",\n                _get_relative_unix_path_to_cmake(cmd.srcpath, outputdir), _get_relative_unix_path_to_cmake(cmd.dstpath, outputdir))\n        else\n            return string.format(\"${CMAKE_COMMAND} -E copy %s %s\",\n                _get_relative_unix_path_to_cmake(cmd.srcpath, outputdir), _get_relative_unix_path_to_cmake(cmd.dstpath, outputdir))\n        end\n    elseif kind == \"rm\" then\n        return string.format(\"${CMAKE_COMMAND} -E rm -rf %s\", _get_relative_unix_path_to_cmake(cmd.filepath, outputdir))\n    elseif kind == \"rmdir\" then\n        return string.format(\"${CMAKE_COMMAND} -E rm -rf %s\", _get_relative_unix_path_to_cmake(cmd.dir, outputdir))\n    elseif kind == \"mv\" then\n        return string.format(\"${CMAKE_COMMAND} -E rename %s %s\",\n            _get_relative_unix_path_to_cmake(cmd.srcpath, outputdir), _get_relative_unix_path_to_cmake(cmd.dstpath, outputdir))\n    elseif kind == \"cd\" then\n        return string.format(\"cd %s\", _get_relative_unix_path_to_cmake(cmd.dir, outputdir))\n    elseif kind == \"mkdir\" then\n        return string.format(\"${CMAKE_COMMAND} -E make_directory %s\", _get_relative_unix_path_to_cmake(cmd.dir, outputdir))\n    elseif kind == \"show\" or kind == \"show_progress\" then\n        local text = string.format(cmd.format, table.unpack(cmd.argv))\n        text = colors.ignore(text)\n        -- we need to translate paths in text\n        -- https://github.com/xmake-io/xmake/issues/6553\n        if is_host(\"windows\") then\n            text = path.unix(text)\n        end\n        return string.format(\"echo %s\", text)\n    end\nend\n\n-- add target custom commands for batchcmds\nfunction _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, cmds)\n    if #cmds == 0 then\n        return\n    end\n    if suffix == \"before\" then\n        -- ADD_CUSTOM_COMMAND and PRE_BUILD did not work as I expected,\n        -- so we need to use add_dependencies and fake target to support it.\n        --\n        -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/17802\n        --\n        local key = target:name() .. \"_\" .. hash.rand64()\n        cmakelists:print(\"add_custom_command(OUTPUT output_%s\", key)\n        for _, cmd in ipairs(cmds) do\n            local command = _get_command_string(cmd, outputdir)\n            if command then\n                cmakelists:print(\"    COMMAND %s\", command)\n            end\n        end\n        cmakelists:print(\"    VERBATIM\")\n        cmakelists:print(\")\")\n        cmakelists:print(\"add_custom_target(target_%s\", key)\n        cmakelists:print(\"    DEPENDS output_%s\", key)\n        cmakelists:print(\")\")\n        cmakelists:print(\"add_dependencies(%s target_%s)\", target:name(), key)\n    elseif suffix == \"after\" then\n        cmakelists:print(\"add_custom_command(TARGET %s\", target:name())\n        cmakelists:print(\"    POST_BUILD\")\n        for _, cmd in ipairs(cmds) do\n            local command = _get_command_string(cmd, outputdir)\n            if command then\n                cmakelists:print(\"    COMMAND %s\", command)\n            end\n        end\n        cmakelists:print(\"    VERBATIM\")\n        cmakelists:print(\")\")\n    end\nend\n\n-- add target custom commands\nfunction _add_target_custom_commands(cmakelists, target, outputdir)\n\n    -- ignore c++ modules rules\n    local ignored_rules\n    if _can_native_support_for_cxxmodules() then\n        ignored_rules = _get_cxxmodules_rules()\n    end\n\n    -- add before commands\n    -- we use irpairs(groups), because the last group that should be given the highest priority.\n    -- rule.on_buildcmd_files should also be executed before building the target, as cmake PRE_BUILD does not work.\n    local cmds_before = target_cmds.get_target_buildcmds(target, {ignored_rules = ignored_rules, stages = {\"before\", \"on\"}})\n    _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, \"before\", cmds_before)\n\n    -- add after commands\n    local cmds_after = target_cmds.get_target_buildcmds(target, {ignored_rules = ignored_rules, stages = {\"after\"}})\n    _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, \"after\", cmds_after)\nend\n\n-- add target\nfunction _add_target(cmakelists, target, outputdir)\n\n    -- add comment\n    cmakelists:print(\"# target\")\n\n    -- is phony target?\n    if target:is_phony() then\n        return _add_target_phony(cmakelists, target)\n    elseif target:is_object() then\n        _add_target_object(cmakelists, target, outputdir)\n    elseif target:is_binary() then\n        _add_target_binary(cmakelists, target, outputdir)\n    elseif target:is_static() then\n        _add_target_static(cmakelists, target, outputdir)\n    elseif target:is_shared() then\n        _add_target_shared(cmakelists, target, outputdir)\n    elseif target:is_headeronly() then\n        _add_target_headeronly(cmakelists, target)\n        _add_target_include_directories(cmakelists, target, outputdir)\n        return\n    elseif target:is_moduleonly() then\n        _add_target_moduleonly(cmakelists, target)\n        return\n    else\n        raise(\"unknown target kind %s\", target:kind())\n    end\n\n    -- add target dependencies\n    _add_target_dependencies(cmakelists, target)\n\n    -- add target custom commands\n    -- we need to call it first for running all rules, these rules will change some flags, e.g. c++modules\n    _add_target_custom_commands(cmakelists, target, outputdir)\n\n    -- add target precompilied header\n    _add_target_precompiled_header(cmakelists, target, outputdir)\n\n    -- add target include directories\n    _add_target_include_directories(cmakelists, target, outputdir)\n\n    -- add target system include directories\n    _add_target_sysinclude_directories(cmakelists, target, outputdir)\n\n    -- add target framework directories\n    _add_target_framework_directories(cmakelists, target, outputdir)\n\n    -- add target compile definitions\n    _add_target_compile_definitions(cmakelists, target)\n\n    -- add target compile options\n    _add_target_compile_options(cmakelists, target, outputdir)\n\n    -- add target warnings\n    _add_target_warnings(cmakelists, target)\n\n    -- add target exceptions\n    _add_target_encodings(cmakelists, target)\n\n    -- add target exceptions\n    _add_target_exceptions(cmakelists, target)\n\n    -- add target languages\n    _add_target_languages(cmakelists, target)\n\n    -- add target optimization\n    _add_target_optimization(cmakelists, target)\n\n    -- add target symbols\n    _add_target_symbols(cmakelists, target)\n\n    -- add target runtimes\n    _add_target_runtimes(cmakelists, target)\n\n    -- add target link libraries\n    _add_target_link_libraries(cmakelists, target, outputdir)\n\n    -- add target link directories\n    _add_target_link_directories(cmakelists, target, outputdir)\n\n    -- add target link options\n    _add_target_link_options(cmakelists, target, outputdir)\n\n    -- add target sources\n    _add_target_sources(cmakelists, target, outputdir)\n\n    -- add target source groups\n    _add_target_source_groups(cmakelists, target, outputdir)\n\n    -- end\n    cmakelists:print(\"\")\nend\n\n-- generate cmakelists\nfunction _generate_cmakelists(cmakelists, outputdir)\n\n    -- add project info\n    _add_project(cmakelists, outputdir)\n\n    -- add targets\n    local project_targets = target_utils.get_project_targets()\n    for _, target in table.orderpairs(project_targets) do\n        _add_target(cmakelists, target, outputdir)\n    end\nend\n\nfunction make(outputdir)\n    local oldir = os.cd(os.projectdir())\n    local cmakelists = io.open(path.join(outputdir, \"CMakeLists.txt\"), \"w\")\n    target_cmds.prepare_targets()\n    _generate_cmakelists(cmakelists, outputdir)\n    cmakelists:close()\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.task\")\nimport(\"core.project.config\")\nimport(\"make.makefile\")\nimport(\"make.xmakefile\")\nimport(\"cmake.cmakelists\")\nimport(\"ninja.build_ninja\")\nimport(\"vstudio.vs\")\nimport(\"vsxmake.vsxmake\")\nimport(\"clang.compile_flags\")\nimport(\"clang.compile_commands\")\nimport(\"private.utils.statistics\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\nimport(\"xcode.xcodeproj\")\n\nfunction makers()\n    return {\n        make             = makefile.make\n    ,   makefile         = makefile.make\n    ,   xmakefile        = xmakefile.make\n    ,   cmake            = cmakelists.make\n    ,   cmakelists       = cmakelists.make\n    ,   xcode            = xcodeproj.make\n    ,   ninja            = build_ninja.make\n    ,   vs2002           = vs.make(2002)\n    ,   vs2003           = vs.make(2003)\n    ,   vs2005           = vs.make(2005)\n    ,   vs2008           = vs.make(2008)\n    ,   vs2010           = vs.make(2010)\n    ,   vs2012           = vs.make(2012)\n    ,   vs2013           = vs.make(2013)\n    ,   vs2015           = vs.make(2015)\n    ,   vs2017           = vs.make(2017)\n    ,   vs2019           = vs.make(2019)\n    ,   vs2022           = vs.make(2022)\n    ,   vs2026           = vs.make(2026)\n    ,   vs               = vs.make()\n    ,   vsxmake2010      = vsxmake.make(2010)\n    ,   vsxmake2012      = vsxmake.make(2012)\n    ,   vsxmake2013      = vsxmake.make(2013)\n    ,   vsxmake2015      = vsxmake.make(2015)\n    ,   vsxmake2017      = vsxmake.make(2017)\n    ,   vsxmake2019      = vsxmake.make(2019)\n    ,   vsxmake2022      = vsxmake.make(2022)\n    ,   vsxmake2026      = vsxmake.make(2026)\n    ,   vsxmake          = vsxmake.make()\n    ,   compile_flags    = compile_flags.make\n    ,   compile_commands = compile_commands.make\n    }\nend\n\n-- make project\nfunction _make(kind)\n    local maps = makers()\n    assert(maps[kind], \"the project kind(%s) is not supported!\", kind)\n    maps[kind](option.get(\"outputdir\"))\nend\n\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- in project generator?\n    os.setenv(\"XMAKE_IN_PROJECT_GENERATOR\", \"true\")\n\n    -- load config first\n    -- @note When generating project configuration files, we should not modify the configuration and cache.\n    task.run(\"config\", {}, {loadonly = true})\n\n    -- post statistics\n    statistics.post()\n\n    -- make project\n    _make(option.get(\"kind\"))\n\n    -- trace\n    cprint(\"${color.success}create ok!\")\n    os.setenv(\"XMAKE_IN_PROJECT_GENERATOR\", nil)\nend\n"
  },
  {
    "path": "xmake/plugins/project/make/makefile.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        makefile.lua\n--\n\n-- imports\nimport(\"core.base.colors\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"core.platform.platform\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.batchcmds\")\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- tranlate path\nfunction _translate_path(filepath, outputdir)\n    filepath = path.translate(filepath)\n    if filepath == \"\" then\n        return \"\"\n    end\n    if path.is_absolute(filepath) then\n        if filepath:startswith(project.directory()) then\n            return path.relative(filepath, outputdir)\n        end\n        return filepath\n    else\n        return path.relative(path.absolute(filepath), outputdir)\n    end\nend\n\n-- get relative unix path\nfunction _get_relative_unix_path(filepath, outputdir)\n    filepath = _translate_path(filepath, outputdir)\n    filepath = path.translate(filepath)\n    return os.args(filepath)\nend\n\n-- translate flag\nfunction _translate_flag(flag, outputdir)\n    if flag then\n        if path.instance_of(flag) then\n            flag = flag:clone():set(_get_relative_unix_path(flag:rawstr(), outputdir)):str()\n        elseif path.is_absolute(flag) then\n            flag = _get_relative_unix_path(flag, outputdir)\n        elseif flag:startswith(\"-fmodule-file=\") then\n            flag = \"-fmodule-file=\" .. _get_relative_unix_path(flag:sub(15), outputdir)\n        elseif flag:startswith(\"-fmodule-mapper=\") then\n            flag = \"-fmodule-mapper=\" .. _get_relative_unix_path(flag:sub(17), outputdir)\n        elseif flag:startswith(\"-isystem\") and #flag > 8 then\n            flag = \"-isystem\" .. _get_relative_unix_path(flag:sub(9), outputdir)\n        elseif flag:startswith(\"-I\") and #flag > 2 then\n            flag = \"-I\" .. _get_relative_unix_path(flag:sub(3), outputdir)\n        elseif flag:startswith(\"-L\") and #flag > 2 then\n            flag = \"-L\" .. _get_relative_unix_path(flag:sub(3), outputdir)\n        elseif flag:startswith(\"-F\") and #flag > 2 then\n            flag = \"-F\" .. _get_relative_unix_path(flag:sub(3), outputdir)\n        elseif flag:match(\"(.+)=(.+)\") then\n            local k, v = flag:match(\"(.+)=(.+)\")\n            if v and v:endswith(\".ifc\") then -- e.g. hello=xxx/hello.ifc\n                flag = k .. \"=\" .. _get_relative_unix_path(v, outputdir)\n            end\n        end\n    end\n    return flag\nend\n\n-- translate flags\nfunction _translate_flags(flags, outputdir)\n    local result = {}\n    for _, flag in ipairs(flags) do\n        if type(flag) == \"table\" and not path.instance_of(flag) then\n            for _, v in ipairs(flag) do\n                table.insert(result, _translate_flag(v, outputdir))\n            end\n        else\n            table.insert(result, _translate_flag(flag, outputdir))\n        end\n    end\n    return result\nend\n\n-- get program from target toolchains\nfunction _get_program_from_target(target, toolkind)\n    local program = target:get(\"toolchain.\" .. toolkind)\n    if not program then\n        program, _ = target:tool(toolkind)\n    end\n    return program\nend\n\n-- get common flags\nfunction _get_common_flags(target, sourcekind, sourcebatch)\n\n    -- make source flags\n    local sourceflags = {}\n    local flags_stats = {}\n    local files_count = 0\n    local first_flags = nil\n    for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n\n        -- make compiler flags\n        local flags = compiler.compflags(sourcefile, {target = target, sourcekind = sourcekind})\n        for _, flag in ipairs(flags) do\n            flags_stats[flag] = (flags_stats[flag] or 0) + 1\n        end\n\n        -- update files count\n        files_count = files_count + 1\n\n        -- save first flags\n        if first_flags == nil then\n            first_flags = flags\n        end\n\n        -- save source flags\n        sourceflags[sourcefile] = flags\n    end\n\n    -- make common flags\n    local commonflags = {}\n    for _, flag in ipairs(first_flags) do\n        if flags_stats[flag] >= files_count then\n            table.insert(commonflags, flag)\n        end\n    end\n\n    -- remove common flags from source flags\n    local sourceflags_ = {}\n    for sourcefile, flags in pairs(sourceflags) do\n        local otherflags = {}\n        for _, flag in ipairs(flags) do\n            if flags_stats[flag] < files_count then\n                table.insert(otherflags, flag)\n            end\n        end\n        sourceflags_[sourcefile] = otherflags\n    end\n    return commonflags, sourceflags_\nend\n\n-- get command: mkdir\nfunction _get_cmd_mkdir(dir)\n    if is_subhost(\"windows\") then\n        return string.format(\"-@mkdir %s > NUL 2>&1\", dir)\n    else\n        return string.format(\"@mkdir -p %s\", dir)\n    end\nend\n\n-- get command: cp\nfunction _get_cmd_cp(sourcefile, targetfile)\n    if is_subhost(\"windows\") then\n        return string.format(\"@copy /Y %s %s > NUL 2>&1\", sourcefile, targetfile)\n    else\n        return string.format(\"@cp %s %s\", sourcefile, targetfile)\n    end\nend\n\n-- get command: mv\nfunction _get_cmd_mv(sourcefile, targetfile)\n    if is_subhost(\"windows\") then\n        return string.format(\"@ren %s %s > NUL 2>&1\", sourcefile, targetfile)\n    else\n        return string.format(\"@mv %s %s\", sourcefile, targetfile)\n    end\nend\n\n-- get command: ln\nfunction _get_cmd_ln(sourcefile, targetfile)\n    if is_subhost(\"windows\") then\n        if os.isdir(sourcefile) then\n            return string.format(\"@mklink /D %s %s > NUL 2>&1\", sourcefile, targetfile)\n        else\n            return string.format(\"@mklink %s %s > NUL 2>&1\", sourcefile, targetfile)\n        end\n    else\n        return string.format(\"@ln -s %s %s\", sourcefile, targetfile)\n    end\nend\n\n-- get command: cpdir\nfunction _get_cmd_cpdir(sourcedir, targetdir)\n    if is_subhost(\"windows\") then\n        return string.format(\"@copy /Y %s %s > NUL 2>&1\", sourcedir, targetdir)\n    else\n        return string.format(\"@cp -r %s %s\", sourcedir, targetdir)\n    end\nend\n\n-- get command: rm\nfunction _get_cmd_rm(filedir)\n    if is_subhost(\"windows\") then\n        -- we attempt to delete it as file first, we remove it as directory if failed\n        return string.format(\"@del /F /Q %s > NUL 2>&1 || rmdir /S /Q %s > NUL 2>&1\", filedir, filedir)\n    else\n        return string.format(\"@rm -rf %s\", filedir)\n    end\nend\n\n-- get command: rmdir\nfunction _get_cmd_rmdir(filedir)\n    if is_subhost(\"windows\") then\n        return string.format(\"@rmdir /S /Q %s > NUL 2>&1\", filedir)\n    else\n        return string.format(\"@rm -rf %s\", filedir)\n    end\nend\n\n-- get command: echo\nfunction _get_cmd_echo(str)\n    return string.format(\"@echo %s\", colors.ignore(str))\nend\n\n-- get command: cd\nfunction _get_cmd_cd(dir)\n    return string.format(\"@cd %s\", dir)\nend\n\n-- get command string\nfunction _get_command_string(cmd, outputdir)\n    local kind = cmd.kind\n    local opt = cmd.opt\n    if cmd.program then\n        -- @see https://github.com/xmake-io/xmake/discussions/2156\n        local argv = {}\n        for _, v in ipairs(cmd.argv) do\n            table.insert(argv, _translate_flag(v, outputdir))\n        end\n        local command = _get_relative_unix_path(cmd.program) .. \" \" .. os.args(argv)\n        if opt and opt.curdir then\n            wprint(\"curdir has been not supported in batchcmds:execv() for makefile generator!\")\n        end\n        return \"%$(VV)\" .. command\n    elseif kind == \"cp\" then\n        if os.isdir(cmd.srcpath) then\n            return _get_cmd_cpdir(get_relative_unix_path(cmd.srcpath, outputdir), _get_relative_unix_path(cmd.dstpath, outputdir))\n        else\n            return _get_cmd_cp(_get_relative_unix_path(cmd.srcpath, outputdir), _get_relative_unix_path(cmd.dstpath, outputdir))\n        end\n    elseif kind == \"rm\" then\n        return _get_cmd_rm(_get_relative_unix_path(cmd.filepath, outputdir))\n    elseif kind == \"rmdir\" then\n        return _get_cmd_rmdir(_get_relative_unix_path(cmd.dir, outputdir))\n    elseif kind == \"mv\" then\n        return _get_cmd_mv(_get_relative_unix_path(cmd.srcpath, outputdir), _get_relative_unix_path(cmd.dstpath, outputdir))\n    elseif kind == \"ln\" then\n        return _get_cmd_ln(_get_relative_unix_path(cmd.srcpath, outputdir), _get_relative_unix_path(cmd.dstpath, outputdir))\n    elseif kind == \"cd\" then\n        return _get_cmd_cd(_get_relative_unix_path(cmd.dir, outputdir))\n    elseif kind == \"mkdir\" then\n        return _get_cmd_mkdir(_get_relative_unix_path(cmd.dir, outputdir))\n    elseif kind == \"show\" or kind == \"show_progress\" then\n        local text = string.format(cmd.format, table.unpack(cmd.argv))\n        return _get_cmd_echo(text)\n    end\nend\n\n-- remove the given files or directories\nfunction _add_remove_files(makefile, filedirs, outputdir)\n    for _, filedir in ipairs(filedirs) do\n        filedir = _get_relative_unix_path(filedir, outputdir)\n        makefile:print(\"\\t%s\", _get_cmd_rm(filedir))\n    end\nend\n\n-- add header\nfunction _add_header(makefile)\n   makefile:print([[# this is the build file for project %s\n# it is autogenerated by the xmake build system.\n# do not edit by hand.\n]], project.name() or \"\")\nend\n\n-- add switches\nfunction _add_switches(makefile)\n    if is_subhost(\"windows\") then\n        makefile:print(\"!if \\\"%$(VERBOSE)\\\" != \\\"1\\\"\")\n        makefile:print(\"VV=@\")\n        makefile:print(\"!endif\")\n    else\n        makefile:print(\"ifneq (%$(VERBOSE),1)\")\n        makefile:print(\"VV=@\")\n        makefile:print(\"endif\")\n    end\n    makefile:print(\"\")\nend\n\n-- add toolchains\nfunction _add_toolchains(makefile, outputdir)\n\n    -- add ccache\n    local ccache = find_tool(\"ccache\")\n    if ccache then\n        makefile:print(\"CCACHE=\" .. ccache.program)\n    end\n\n    -- add compilers\n    for sourcekind, _ in pairs(language.sourcekinds()) do\n        local program = platform.tool(sourcekind)\n        if program and program ~= \"\" then\n            makefile:print(\"%s=%s\", sourcekind:upper(), program)\n        end\n    end\n    makefile:print(\"\")\n\n    -- add linkers\n    local linkerkinds = {}\n    for _, _linkerkinds in pairs(language.targetkinds()) do\n        table.join2(linkerkinds, _linkerkinds)\n    end\n    for _, linkerkind in ipairs(table.unique(linkerkinds)) do\n        local program = platform.tool(linkerkind)\n        if program and program ~= \"\" then\n            makefile:print(\"%s=%s\", (linkerkind:upper():gsub('%-', '_')), program)\n        end\n    end\n    makefile:print(\"\")\n\n    -- add toolchains from targets\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in pairs(project_targets) do\n        if not _phony_or_headeronly(target) then\n            local program = _get_program_from_target(target, target:linker():kind())\n            if program then\n                makefile:print(\"%s_%s=%s\", targetname, target:linker():kind():upper(), program)\n            end\n            for _, sourcebatch in pairs(target:sourcebatches()) do\n                local sourcekind = sourcebatch.sourcekind\n                if sourcekind then\n                    local program = _get_program_from_target(target, sourcekind)\n                    if program then\n                        makefile:print(\"%s_%s=%s\", targetname, sourcekind:upper(), program)\n                    end\n                end\n            end\n        end\n    end\n    makefile:print(\"\")\nend\n\nfunction _phony_or_headeronly(target) \n    return target:is_phony() or target:is_headeronly()\nend\n\n-- add flags\nfunction _add_flags(makefile, targetflags, outputdir)\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in pairs(project_targets) do\n        if not _phony_or_headeronly(target) then\n            for _, sourcebatch in pairs(target:sourcebatches()) do\n                local sourcekind = sourcebatch.sourcekind\n                if sourcekind then\n                    local commonflags, sourceflags = _get_common_flags(target, sourcekind, sourcebatch)\n                    makefile:print(\"%s_%sFLAGS=%s\", targetname, sourcekind:upper(), os.args(_translate_flags(commonflags, outputdir)))\n                    targetflags[targetname .. '_' .. sourcekind:upper()] = sourceflags\n                end\n            end\n            makefile:print(\"%s_%sFLAGS=%s\", targetname, target:linker():kind():upper(), os.args(_translate_flags(target:linkflags(), outputdir)))\n        end\n    end\n    makefile:print(\"\")\nend\n\n-- add build object\nfunction _add_build_object(makefile, target, sourcefile, objectfile, sourceflags, outputdir, precmds_label)\n\n    -- get the source file kind\n    local sourcekind = language.sourcekind_of(sourcefile)\n\n    -- get program\n    local program_global = false\n    local program = _get_program_from_target(target, sourcekind)\n    if not program then\n        program = platform.tool(sourcekind)\n        program_global = true\n    end\n\n    -- get complier flags\n    local compflags = _translate_flags(sourceflags[sourcefile], outputdir)\n\n    -- translate file paths\n    sourcefile = _get_relative_unix_path(sourcefile, outputdir)\n    objectfile = _get_relative_unix_path(objectfile, outputdir)\n\n    -- make command\n    local macro = \"$\\01\" .. target:name() .. '_' .. sourcekind:upper() .. \"FLAGS\\02\"\n    local command = compiler.compcmd(sourcefile, objectfile, {target = target, compflags = table.join(macro, compflags)})\n    command = command:gsub('\\01', '(')\n    command = command:gsub('\\02', ')')\n\n    -- replace program to $(XX)\n    local p, e = command:find(\"\\\"\" .. program .. \"\\\"\", 1, true)\n    if not p then\n        p, e = command:find(program, 1, true)\n    end\n    if p then\n        if program_global then\n            command = format(\"%s$(%s)%s\", command:sub(1, p - 1), sourcekind:upper(), command:sub(e + 1))\n        else\n            command = format(\"%s$(%s_%s)%s\", command:sub(1, p - 1), target:name(), sourcekind:upper(), command:sub(e + 1))\n        end\n    end\n\n    -- replace ccache to $(CCACHE)\n    local ccache = config.get(\"ccache\") ~= false and find_tool(\"ccache\")\n    if ccache then\n        p, e = command:find(ccache.program, 1, true)\n        if p then\n            command = format(\"%s$(%s)%s\", command:sub(1, p - 1), \"CCACHE\", command:sub(e + 1))\n        end\n    end\n\n    -- make head\n    makefile:printf(\"%s:\", objectfile)\n    if precmds_label then\n        makefile:printf(\" %s\", precmds_label)\n    end\n\n    -- make dependence\n    makefile:print(\" %s\", sourcefile)\n\n    -- make body\n    makefile:print(\"\\t%s\", _get_cmd_echo(string.format(\"%scompiling.$(mode) %s\", ccache and \"ccache \" or \"\", sourcefile)))\n    makefile:print(\"\\t%s\", _get_cmd_mkdir(path.directory(objectfile)))\n    makefile:writef(\"\\t$(VV)%s\\n\", command)\n\n    -- make tail\n    makefile:print(\"\")\nend\n\n-- add build objects\nfunction _add_build_objects(makefile, target, sourcekind, sourcebatch, sourceflags, outputdir, precmds_label)\n    local handled_objects = target:data(\"makefile.handled_objects\")\n    if not handled_objects then\n        handled_objects = {}\n        target:data_set(\"makefile.handled_objects\", handled_objects)\n    end\n    for index, objectfile in ipairs(sourcebatch.objectfiles) do\n        -- remove repeat\n        -- this is because some rules will repeatedly bind the same sourcekind, e.g. `rule(\"c++.build.modules.builder\")`\n        if not handled_objects[objectfile] then\n            _add_build_object(makefile, target,\n                sourcebatch.sourcefiles[index], objectfile, sourceflags, outputdir, precmds_label)\n            handled_objects[objectfile] = true\n        end\n    end\nend\n\n-- add build phony\nfunction _add_build_phony(makefile, target)\n\n    -- make dependence for the dependent targets\n    makefile:printf(\"%s:\", target:name())\n    for _, dep in ipairs(target:get(\"deps\")) do\n        makefile:write(\" \" .. dep)\n    end\n    makefile:print(\"\")\nend\n\n-- add custom commands before building target\nfunction _add_build_custom_commands_before(makefile, target, outputdir)\n\n    -- add before commands\n    -- we use irpairs(groups), because the last group that should be given the highest priority.\n    local cmds_before = target_cmds.get_target_buildcmds(target, {stages = {\"before\", \"on\"}})\n\n    local targetname = target:name()\n    local label = \"precmds_\" .. targetname\n    if #cmds_before > 0 then\n        makefile:print(\"%s:\", label)\n        for _, cmd in ipairs(cmds_before) do\n            local command = _get_command_string(cmd, outputdir)\n            if command then\n                makefile:print(\"\\t%s\", command)\n            end\n        end\n        makefile:print(\"\")\n        return label\n    end\nend\n\n-- add custom commands after building target\nfunction _add_build_custom_commands_after(makefile, target, outputdir)\n    local cmds_after = target_cmds.get_target_buildcmds(target, {stages = {\"after\"}})\n    if #cmds_after > 0 then\n        for _, cmd in ipairs(cmds_after) do\n            local command = _get_command_string(cmd, outputdir)\n            if command then\n                makefile:print(\"\\t%s\", command)\n            end\n        end\n    end\nend\n\n-- add build target\nfunction _add_build_target(makefile, target, targetflags, outputdir)\n\n    -- https://github.com/xmake-io/xmake/issues/2337\n    target:data_set(\"plugin.project.kind\", \"makefile\")\n\n    -- add custom commands before building target\n    local precmds_label = _add_build_custom_commands_before(makefile, target, outputdir)\n\n    -- is phony target?\n    if _phony_or_headeronly(target) then\n        return _add_build_phony(makefile, target)\n    end\n\n    -- make head\n    local targetfile = _get_relative_unix_path(target:targetfile(), outputdir)\n    local targetname = target:name()\n\n    -- rules like `./target` and `target` are equivalent and can causes issues\n    -- for cases where targetdir is .\n    -- in these cases, the targetfile rule is not created\n    if target:targetfile() == \"./\" .. targetname then\n        makefile:printf(\"%s:\", targetname)\n        if precmds_label then\n            makefile:printf(\" %s\", precmds_label)\n        end\n    else\n        makefile:print(\"%s: %s\", targetname, targetfile)\n        makefile:printf(\"%s:\", targetfile)\n    end\n    if precmds_label then\n        makefile:printf(\" %s\", precmds_label)\n    end\n\n    -- make dependence for the dependent targets\n    for _, depname in ipairs(target:get(\"deps\")) do\n        local dep = project.target(depname, {namespace = target:namespace()})\n        makefile:write(\" \" .. (_phony_or_headeronly(dep) and depname or _get_relative_unix_path(dep:targetfile(), outputdir)))\n    end\n\n    -- make dependence for objects\n    local objectfiles = target:objectfiles()\n    local objectfiles_translated = {}\n    for _, objectfile in ipairs(objectfiles) do\n        objectfile = _get_relative_unix_path(objectfile, outputdir)\n        table.insert(objectfiles_translated, objectfile)\n        makefile:write(\" \" .. objectfile)\n    end\n\n    -- make dependence end\n    makefile:print(\"\")\n\n    -- get linker kind\n    local linkerkind = target:linker():kind()\n\n    -- get program\n    local program_global = false\n    local program = _get_program_from_target(target, linkerkind)\n    if not program then\n        program = platform.tool(linkerkind)\n        program_global = true\n    end\n\n    -- get command\n    local command = target:linker():linkcmd(objectfiles_translated, targetfile, {target = target})\n\n    -- replace linkflags to $(XX)\n    local p, e = command:find(os.args(target:linkflags()), 1, true)\n    if p then\n        command = format(\"%s$(%s_%sFLAGS)%s\", command:sub(1, p - 1), target:name(), (linkerkind:upper():gsub('%-', '_')), command:sub(e + 1))\n    end\n\n    -- replace program to $(XX)\n    p, e = command:find(\"\\\"\" .. program .. \"\\\"\", 1, true)\n    if not p then\n        p, e = command:find(program, 1, true)\n    end\n    if p then\n        if program_global then\n            command = format(\"%s$(%s)%s\", command:sub(1, p - 1), (linkerkind:upper():gsub('%-', '_')), command:sub(e + 1))\n        else\n            command = format(\"%s$(%s_%s)%s\", command:sub(1, p - 1), target:name(), (linkerkind:upper():gsub('%-', '_')), command:sub(e + 1))\n        end\n    end\n\n    -- make body\n    makefile:print(\"\\t%s\", _get_cmd_echo(string.format(\"linking.$(mode) %s\", path.filename(targetfile))))\n    makefile:print(\"\\t%s\", _get_cmd_mkdir(path.directory(targetfile)))\n    makefile:writef(\"\\t$(VV)%s\\n\", command)\n\n    -- add custom commands after building target\n    _add_build_custom_commands_after(makefile, target, outputdir)\n\n    -- end\n    makefile:print(\"\")\n\n    -- build source batches\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        local sourcekind = sourcebatch.sourcekind\n        if sourcekind then\n            -- compile source files to single object at once\n            local sourceflags = targetflags[target:name() .. '_' .. sourcekind:upper()]\n            _add_build_objects(makefile, target, sourcekind, sourcebatch, sourceflags, outputdir, precmds_label)\n        end\n    end\nend\n\n-- add build targets\nfunction _add_build_targets(makefile, targetflags, outputdir)\n    local default = \"\"\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in pairs(project_targets) do\n        if target:is_default() then\n            default = default .. \" \" .. targetname\n        end\n    end\n    makefile:print(\"default: %s\\n\", default)\n    local all = \"\"\n    for targetname, _ in pairs(project_targets) do\n        all = all .. \" \" .. targetname\n    end\n    makefile:print(\"all: %s\\n\", all)\n    makefile:print(\".PHONY: default all %s\\n\", all)\n    for _, target in pairs(project_targets) do\n        _add_build_target(makefile, target, targetflags, outputdir)\n    end\nend\n\n-- add build\nfunction _add_build(makefile, targetflags, outputdir)\n\n    -- TODO\n    -- disable precompiled header first\n    local project_targets = target_utils.get_project_targets()\n    for _, target in pairs(project_targets) do\n        target:set(\"pcheader\", nil)\n        target:set(\"pcxxheader\", nil)\n    end\n\n    -- add build targets\n    _add_build_targets(makefile, targetflags, outputdir)\nend\n\n-- add clean target\nfunction _add_clean_target(makefile, target, outputdir)\n    makefile:printf(\"clean_%s: \", target:name())\n    for _, dep in ipairs(target:get(\"deps\")) do\n        makefile:write(\" clean_\" .. dep)\n    end\n    makefile:print(\"\")\n    if not _phony_or_headeronly(target) then\n        _add_remove_files(makefile, target:targetfile(), outputdir)\n        _add_remove_files(makefile, target:symbolfile(), outputdir)\n        _add_remove_files(makefile, target:objectfiles(), outputdir)\n    end\n    makefile:print(\"\")\nend\n\n-- add clean targets\nfunction _add_clean_targets(makefile, outputdir)\n    local all = \"\"\n    local project_targets = target_utils.get_project_targets()\n    for targetname, _ in pairs(project_targets) do\n        all = all .. \" clean_\" .. targetname\n    end\n    makefile:print(\"clean: %s\\n\", all)\n\n    -- add clean targets\n    for _, target in pairs(project_targets) do\n        _add_clean_target(makefile, target, outputdir)\n    end\nend\n\n-- add clean\nfunction _add_clean(makefile, outputdir)\n    _add_clean_targets(makefile, outputdir)\nend\n\nfunction make(outputdir)\n    local oldir = os.cd(os.projectdir())\n\n    -- prepare targets\n    target_cmds.prepare_targets()\n\n    -- open the makefile\n    local makefile = io.open(path.join(outputdir, \"makefile\"), \"w\")\n\n    -- add header\n    _add_header(makefile)\n\n    -- add switches\n    _add_switches(makefile)\n\n    -- add toolchains\n    _add_toolchains(makefile, outputdir)\n\n    -- add flags\n    local targetflags = {}\n    _add_flags(makefile, targetflags, outputdir)\n\n    -- add build\n    _add_build(makefile, targetflags, outputdir)\n\n    -- add clean\n    _add_clean(makefile, outputdir)\n\n    -- close the makefile\n    makefile:close()\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/make/xmakefile.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmakefile.lua\n--\n\n-- imports\nimport(\"core.project.project\")\n\n-- make head\nfunction _make_head(makefile)\n\n    -- verbose?\n    makefile:print(\"ifeq (%$(V),1)\")\n    makefile:print(\"VERBOSE=-v\")\n    makefile:print(\"else\")\n    makefile:print(\"VERBOSE=\")\n    makefile:print(\"endif\")\n    makefile:print(\"\")\n\n    -- diagnosis?\n    makefile:print(\"ifeq (%$(D),1)\")\n    makefile:print(\"DIAGNOSIS=-D\")\n    makefile:print(\"else\")\n    makefile:print(\"DIAGNOSIS=\")\n    makefile:print(\"endif\")\n    makefile:print(\"\")\nend\n\n-- make build\nfunction _make_build(makefile)\n    makefile:print(\".PHONY: build\")\n    makefile:print(\"\")\n    makefile:print(\"build: \")\n    makefile:print(\"\\t@xmake --build %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make rebuild\nfunction _make_rebuild(makefile)\n    makefile:print(\"rebuild: \")\n    makefile:print(\"\\t@xmake --rebuild %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make install\nfunction _make_install(makefile)\n    makefile:print(\"install: \")\n    makefile:print(\"\\t@xmake install %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make uninstall\nfunction _make_uninstall(makefile)\n    makefile:print(\"uninstall: \")\n    makefile:print(\"\\t@xmake uninstall %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make package\nfunction _make_package(makefile)\n    makefile:print(\"package: \")\n    makefile:print(\"\\t@xmake package %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make clean\nfunction _make_clean(makefile)\n    makefile:print(\"clean: \")\n    makefile:print(\"\\t@xmake clean %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make run\nfunction _make_run(makefile)\n    makefile:print(\"run: \")\n    makefile:print(\"\\t@xmake run %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make debug\nfunction _make_debug(makefile)\n    makefile:print(\"debug: \")\n    makefile:print(\"\\t@xmake run -d %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"\")\nend\n\n-- make config\nfunction _make_config(makefile)\n    makefile:print(\"ifneq (%$(PLAT),)\")\n    makefile:print(\"ifneq (%$(ARCH),)\")\n    makefile:print(\"ifneq (%$(MODE),)\")\n    makefile:print(\"CONFIG=xmake config -c %$(VERBOSE) %$(DIAGNOSIS) -p %$(PLAT) -a %$(ARCH) -m %$(MODE) %$(TARGET)\")\n    makefile:print(\"else\")\n    makefile:print(\"CONFIG=xmake config -c %$(VERBOSE) %$(DIAGNOSIS) -p %$(PLAT) -a %$(ARCH) %$(TARGET)\")\n    makefile:print(\"endif\")\n    makefile:print(\"else\")\n    makefile:print(\"CONFIG=xmake config -c %$(VERBOSE) %$(DIAGNOSIS) -p %$(PLAT) %$(TARGET)\")\n    makefile:print(\"endif\")\n    makefile:print(\"else\")\n    makefile:print(\"CONFIG=xmake config -c %$(VERBOSE) %$(DIAGNOSIS) %$(TARGET)\")\n    makefile:print(\"endif\")\n    makefile:print(\"config: \")\n    makefile:print(\"\\t@%$(CONFIG)\")\n    makefile:print(\"\")\nend\n\n-- make\nfunction make(outputdir)\n\n    -- enter project directory\n    local oldir = os.cd(os.projectdir())\n\n    -- open the makefile\n    local makefile = io.open(path.join(outputdir, \"makefile\"), \"w\")\n\n    -- make head\n    _make_head(makefile)\n\n    -- make build\n    _make_build(makefile)\n\n    -- make rebuild\n    _make_rebuild(makefile)\n\n    -- make install\n    _make_install(makefile)\n\n    -- make uninstall\n    _make_uninstall(makefile)\n\n    -- make package\n    _make_package(makefile)\n\n    -- make clean\n    _make_clean(makefile)\n\n    -- make run\n    _make_run(makefile)\n\n    -- make debug\n    _make_debug(makefile)\n\n    -- make config\n    _make_config(makefile)\n\n    -- close the makefile\n    makefile:close()\n\n    -- leave project directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/ninja/build_ninja.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_ninja.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.language.language\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_toolname\")\nimport(\"core.tools.cl.parse_include\")\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- this sourcebatch is built?\nfunction _sourcebatch_is_built(sourcebatch)\n    -- we can only use rulename to filter them because sourcekind may be bound to multiple rules\n    local rulename = sourcebatch.rulename\n    if rulename == \"c.build\" or rulename == \"c++.build\"\n        or rulename == \"asm.build\" or rulename == \"cuda.build\"\n        or rulename == \"objc.build\" or rulename == \"objc++.build\" then\n        return true\n    end\nend\n\n-- escape path\nfunction _escape_path(filepath)\n    if is_host(\"windows\") then\n        filepath = filepath:gsub('\\\\', '/')\n    end\n    return filepath\nend\n\n-- translate path\nfunction _translate_path(filepath, outputdir)\n    filepath = path.translate(filepath)\n    if filepath == \"\" then\n        return \"\"\n    end\n    if path.is_absolute(filepath) then\n        if filepath:startswith(project.directory()) then\n            return path.relative(filepath, outputdir)\n        end\n        return filepath\n    else\n        return path.relative(path.absolute(filepath), outputdir)\n    end\nend\n\n-- get relative unix path\nfunction _get_relative_unix_path(filepath, outputdir)\n    filepath = _translate_path(filepath, outputdir)\n    filepath = _escape_path(path.translate(filepath))\n    return os.args(filepath)\nend\n\n-- translate compiler flags\nfunction _translate_compflags(compflags, outputdir)\n    local flags = {}\n    local last_flag = nil;\n    for _, flag in ipairs(compflags) do\n        if flag == \"-I\" or flag == \"-isystem\" then\n            last_flag = flag\n        else\n            if last_flag == \"-I\" or last_flag == \"-isystem\" then\n                table.insert(flags, last_flag)\n                flag = _get_relative_unix_path(flag, outputdir)\n            else\n                last_flag = flag\n                for _, pattern in ipairs({\"[%-](I)(.*)\", \"[%-](isystem)(.*)\"}) do\n                    flag = flag:gsub(pattern, function (flag, dir)\n                            dir = _get_relative_unix_path(dir, outputdir)\n                            return \"-\" .. flag .. dir\n                    end)\n                end\n            end\n            table.insert(flags, flag)\n        end\n    end\n    return flags\nend\n\n-- translate linker flags\nfunction _translate_linkflags(linkflags, outputdir)\n    local flags = {}\n    for _, flag in ipairs(linkflags) do\n        for _, pattern in ipairs({\"[%-](L)(.*)\", \"[%-](F)(.*)\"}) do\n            flag = flag:gsub(pattern, function (flag, dir)\n                dir = _get_relative_unix_path(dir, outputdir)\n                return \"-\" .. flag .. dir\n            end)\n        end\n        table.insert(flags, flag)\n    end\n    return flags\nend\n\n-- add header\nfunction _add_header(ninjafile)\n    ninjafile:print([[# this is the build file for project %s\n# it is autogenerated by the xmake build system.\n# do not edit by hand.\n]], project.name() or \"\")\n    ninjafile:print(\"ninja_required_version = 1.5.1\")\n    ninjafile:print(\"\")\nend\n\n-- add rules for generator\nfunction _add_rules_for_generator(ninjafile, outputdir)\n    local projectdir = _get_relative_unix_path(os.projectdir(), outputdir)\n    ninjafile:print(\"rule gen\")\n    ninjafile:print(\" command = xmake project -P %s -k ninja\", projectdir)\n    ninjafile:print(\" description = regenerating ninja files\")\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier (gcc)\nfunction _add_rules_for_compiler_gcc(ninjafile, sourcekind, program)\n    local ccache = config.get(\"ccache\") ~= false and find_tool(\"ccache\")\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s%s $ARGS -MMD -MF $out.d -o $out -c $in\", ccache and (ccache.program .. \" \") or \"\", program)\n    ninjafile:print(\" deps = gcc\")\n    ninjafile:print(\" depfile = $out.d\")\n    ninjafile:print(\" description = %scompiling.%s $in\", ccache and \"ccache \" or \"\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier (clang)\nfunction _add_rules_for_compiler_clang(ninjafile, sourcekind, program)\n    return _add_rules_for_compiler_gcc(ninjafile, sourcekind, program)\nend\n\n-- add rules for complier (clang-cl)\nfunction _add_rules_for_compiler_clang_cl(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s -showIncludes -c $ARGS $in -Fo$out\", program)\n    ninjafile:print(\" deps = msvc\")\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier (msvc/cl)\nfunction _add_rules_for_compiler_msvc_cl(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s -showIncludes -c $ARGS $in -Fo$out\", program)\n    ninjafile:print(\" deps = msvc\")\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier (msvc/ml)\nfunction _add_rules_for_compiler_msvc_ml(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s -c $ARGS -Fo$out $in\", program)\n    ninjafile:print(\" deps = msvc\")\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for resource complier (msvc/rc)\nfunction _add_rules_for_compiler_msvc_rc(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s $ARGS -Fo$out $in\", program)\n    ninjafile:print(\" deps = msvc\")\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for resource complier (windres/rc)\nfunction _add_rules_for_compiler_windres(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s $ARGS $in $out\", program)\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier (cuda/nvcc)\nfunction _add_rules_for_compiler_nvcc(ninjafile, sourcekind, program)\n    ninjafile:print(\"rule %s\", sourcekind)\n    ninjafile:print(\" command = %s -c $ARGS $in -o $out\", program)\n    ninjafile:print(\" description = compiling.%s $in\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for complier\nfunction _add_rules_for_compiler(ninjafile)\n    ninjafile:print(\"# rules for compiler\")\n    if is_plat(\"windows\") then\n        -- @see https://github.com/ninja-build/ninja/issues/613\n        local note_include = parse_include.probe_include_note_from_cl()\n        if not note_include then\n            note_include = \"Note: including file:\"\n        end\n        ninjafile:print(\"msvc_deps_prefix = %s\", note_include:trim())\n    end\n    local add_compiler_rules =\n    {\n        gcc      = _add_rules_for_compiler_gcc,\n        gxx      = _add_rules_for_compiler_gcc,\n        clang    = _add_rules_for_compiler_clang,\n        clangxx  = _add_rules_for_compiler_clang,\n        cl       = _add_rules_for_compiler_msvc_cl,\n        clang_cl = _add_rules_for_compiler_clang_cl,\n        ml       = _add_rules_for_compiler_msvc_ml,\n        ml64     = _add_rules_for_compiler_msvc_ml,\n        rc       = _add_rules_for_compiler_msvc_rc,\n        windres  = _add_rules_for_compiler_windres,\n        nvcc     = _add_rules_for_compiler_nvcc\n    }\n    for sourcekind, _ in pairs(language.sourcekinds()) do\n        local program, toolname = platform.tool(sourcekind)\n        if program then\n            local add_rule = add_compiler_rules[toolname or find_toolname(program)]\n            -- support of unknown compiler (xmake f --cc=gcc@my-cc)\n            if not add_rule and toolname then\n                add_rule = add_compiler_rules[find_toolname(toolname)]\n            end\n            if add_rule then\n                add_rule(ninjafile, sourcekind, program)\n            end\n        end\n    end\n    ninjafile:print(\"\")\nend\n\n-- add rules for linker (ar)\nfunction _add_rules_for_linker_ar(ninjafile, linkerkind, program)\n    ninjafile:print(\"rule %s\", linkerkind)\n    ninjafile:print(\" command = %s $ARGS $out $in\", program)\n    ninjafile:print(\" description = archiving.%s $out\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for linker (gcc)\nfunction _add_rules_for_linker_gcc(ninjafile, linkerkind, program)\n    ninjafile:print(\"rule %s\", linkerkind)\n    ninjafile:print(\" command = %s -o $out $in $ARGS\", program)\n    ninjafile:print(\" description = linking.%s $out\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for linker (clang)\nfunction _add_rules_for_linker_clang(ninjafile, linkerkind, program)\n    return _add_rules_for_linker_gcc(ninjafile, linkerkind, program)\nend\n\n-- add rules for linker (msvc)\nfunction _add_rules_for_linker_msvc(ninjafile, linkerkind, program)\n    if linkerkind == \"ar\" then\n        program = program .. \" -lib\"\n    elseif linkerkind == \"sh\" then\n        program = program .. \" -dll\"\n    end\n    -- @note we use rspfile to handle long command limit on windows\n    ninjafile:print(\"rule %s\", linkerkind)\n    ninjafile:print(\" command = %s @$out.rsp\", program)\n    ninjafile:print(\" rspfile = $out.rsp\")\n    ninjafile:print(\" rspfile_content = $ARGS -out:$out $in_newline\")\n    ninjafile:print(\" description = linking.%s $out\", config.mode())\n    ninjafile:print(\"\")\nend\n\n-- add rules for linker\nfunction _add_rules_for_linker(ninjafile)\n    ninjafile:print(\"# rules for linker\")\n    local linkerkinds = {}\n    for _, _linkerkinds in pairs(language.targetkinds()) do\n        table.join2(linkerkinds, _linkerkinds)\n    end\n    local add_linker_rules =\n    {\n        ar      = _add_rules_for_linker_ar,\n        gcc     = _add_rules_for_linker_gcc,\n        gxx     = _add_rules_for_linker_gcc,\n        clang   = _add_rules_for_linker_clang,\n        clangxx = _add_rules_for_linker_clang,\n        link    = _add_rules_for_linker_msvc\n    }\n    for _, linkerkind in ipairs(table.unique(linkerkinds)) do\n        local program, toolname = platform.tool(linkerkind)\n        if program then\n            local add_rule = add_linker_rules[toolname or find_toolname(program)]\n            -- support of unknown linker (xmake f --ld=gcc@my-ld)\n            if not add_rule and toolname then\n                add_rule = add_linker_rules[find_toolname(toolname)]\n            end\n            if add_rule then\n                add_rule(ninjafile, linkerkind, program)\n            end\n        end\n    end\n    ninjafile:print(\"\")\nend\n\n-- add rules\nfunction _add_rules(ninjafile, outputdir)\n\n    -- add rules for generator\n    _add_rules_for_generator(ninjafile, outputdir)\n\n    -- add rules for complier\n    _add_rules_for_compiler(ninjafile)\n\n    -- add rules for linker\n    _add_rules_for_linker(ninjafile)\nend\n\n-- add build rule for phony\nfunction _add_build_for_phony(ninjafile, target)\n    ninjafile:print(\"build %s: phony\", target:name())\nend\n\n-- add build rule for object\nfunction _add_build_for_object(ninjafile, target, sourcekind, sourcefile, objectfile, outputdir)\n    objectfile = _get_relative_unix_path(objectfile, outputdir)\n    sourcefile = _get_relative_unix_path(sourcefile, outputdir)\n    local compflags = compiler.compflags(sourcefile, {target = target})\n    ninjafile:print(\"build %s: %s %s\", objectfile, sourcekind, sourcefile)\n    ninjafile:print(\" ARGS = %s\", os.args(_translate_compflags(compflags, outputdir)))\n    ninjafile:print(\"\")\nend\n\n-- add build rule for objects\nfunction _add_build_for_objects(ninjafile, target, sourcebatch, outputdir)\n    for index, objectfile in ipairs(sourcebatch.objectfiles) do\n        _add_build_for_object(ninjafile, target,  sourcebatch.sourcekind, sourcebatch.sourcefiles[index], objectfile, outputdir)\n    end\nend\n\n-- add build rule for target\nfunction _add_build_for_target(ninjafile, target, outputdir)\n\n    -- https://github.com/xmake-io/xmake/issues/2337\n    target:data_set(\"plugin.project.kind\", \"ninja\")\n\n    -- is phony target?\n    if target:is_phony() or target:is_headeronly() then\n        return _add_build_for_phony(ninjafile, target)\n    end\n\n    -- build target\n    ninjafile:print(\"# build target: %s\", target:name())\n    local targetfile = _get_relative_unix_path(target:targetfile(), outputdir)\n    ninjafile:print(\"build %s: phony %s\", target:name(), targetfile)\n\n    -- build target file\n    ninjafile:printf(\"build %s: %s\", targetfile, target:linker():kind())\n    local objectfiles = target:objectfiles()\n    for _, objectfile in ipairs(objectfiles) do\n        ninjafile:write(\" \" .. _get_relative_unix_path(objectfile, outputdir))\n    end\n    -- merge objects with rule(\"utils.merge.object\")\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        if sourcebatch.rulename == \"utils.merge.object\" then\n            ninjafile:write(\" \" .. table.concat(sourcebatch.sourcefiles, \" \"))\n        end\n    end\n    local deps = target:get(\"deps\")\n    if deps then\n        ninjafile:print(\" || $\")\n        ninjafile:write(\"  \")\n        for _, dep in ipairs(deps) do\n            local dep_target = project.target(dep, {namespace = target:namespace()});\n            if not dep_target:is_headeronly() then\n                ninjafile:write(\" \" .. _get_relative_unix_path(dep_target:targetfile(), outputdir))\n            end\n        end\n    end\n    ninjafile:print(\"\")\n    ninjafile:print(\" ARGS = %s\", os.args(_translate_linkflags(target:linkflags(), outputdir)))\n    ninjafile:print(\"\")\n\n    -- build target objects\n    local sourcebatches = target:sourcebatches()\n    for _, sourcebatch in table.orderpairs(sourcebatches) do\n        if _sourcebatch_is_built(sourcebatch) then\n            _add_build_for_objects(ninjafile, target, sourcebatch, outputdir)\n        end\n    end\nend\n\n-- add build rule for generator\nfunction _add_build_for_generator(ninjafile, outputdir)\n    ninjafile:print(\"# build build.ninja\")\n    ninjafile:print(\"build build.ninja: gen $\")\n    local allfiles = project.allfiles()\n    for idx, projectfile in ipairs(allfiles) do\n        if not path.is_absolute(projectfile) or projectfile:startswith(os.projectdir()) then\n            local filepath = _get_relative_unix_path(projectfile, outputdir)\n            ninjafile:print(\"  %s %s\", filepath, idx < #allfiles and \"$\" or \"\")\n        end\n    end\n    ninjafile:print(\"\")\nend\n\n-- add build rule for targets\nfunction _add_build_for_targets(ninjafile, outputdir)\n\n    -- begin\n    ninjafile:print(\"# build targets\\n\")\n\n    -- add build rule for generator\n    _add_build_for_generator(ninjafile, outputdir)\n\n    local project_targets = target_utils.get_project_targets()\n    -- TODO\n    -- disable precompiled header first\n    for _, target in pairs(project_targets) do\n        target:set(\"pcheader\", nil)\n        target:set(\"pcxxheader\", nil)\n    end\n\n    -- build targets\n    for _, target in pairs(project_targets) do\n        _add_build_for_target(ninjafile, target, outputdir)\n    end\n\n    -- build default\n    local default = \"\"\n    for targetname, target in pairs(project_targets) do\n        if target:is_default() then\n            default = default .. \" \" .. targetname\n        end\n    end\n    ninjafile:print(\"build default: phony%s\", default)\n\n    -- build all\n    local all = \"\"\n    for targetname, _ in pairs(project_targets) do\n        all = all .. \" \" .. targetname\n    end\n    ninjafile:print(\"build all: phony%s\\n\", all)\n\n    -- end\n    ninjafile:print(\"default default\\n\")\nend\n\nfunction make(outputdir)\n    local oldir = os.cd(os.projectdir())\n\n    -- prepare targets\n    target_cmds.prepare_targets()\n\n    -- open the build.ninja file\n    --\n    -- we need to change encoding to support msvc_deps_prefix\n    -- @see https://github.com/ninja-build/ninja/issues/613\n    --\n    -- TODO maybe we need support more encoding for other languages\n    --\n    local encoding = is_subhost(\"windows\") and \"gbk\"\n    local ninjafile = io.open(path.join(outputdir, \"build.ninja\"), \"w\", {encoding = encoding})\n\n    -- add header\n    _add_header(ninjafile)\n\n    -- add rules\n    _add_rules(ninjafile, outputdir)\n\n    -- add build rules for targets\n    _add_build_for_targets(ninjafile, outputdir)\n\n    -- close the ninjafile\n    ninjafile:close()\n    os.cd(oldir)\nend\n\n"
  },
  {
    "path": "xmake/plugins/project/utils/target_cmds.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target_cmds.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.project.config\")\nimport(\"core.base.hashset\")\nimport(\"core.project.rule\")\nimport(\"private.utils.batchcmds\")\nimport(\"private.action.build.target\", {alias = \"target_buildutils\"})\n\n-- prepare targets\nfunction prepare_targets(targets)\n    local targets_root = targets or target_buildutils.get_root_targets()\n    target_buildutils.run_targetjobs(targets_root, {job_kind = \"prepare\", for_generator = true, jobs = os.default_njob()})\nend\n\n-- get target buildcmds\nfunction get_target_buildcmds(target, opt)\n    opt = opt or {}\n    local progress_wrapper = {}\n    progress_wrapper.current = function ()\n        return count\n    end\n    progress_wrapper.total = function ()\n        return total\n    end\n    progress_wrapper.percent = function ()\n        if total and total > 0 then\n            return math.floor((count * 100) / total)\n        else\n            return 0\n        end\n    end\n    debug.setmetatable(progress_wrapper, {\n        __tostring = function ()\n            -- we do not output any progress info for the project generators\n            return \"\"\n        end\n    })\n    local buildcmds = batchcmds.new({target = target})\n    local jobgraph = target_buildutils.get_targetjobs({target}, {\n        job_kind = \"build\",\n        for_generator = true,\n        buildcmds = buildcmds,\n        with_stages = hashset.from(opt.stages or {}),\n        ignored_rules = hashset.from(opt.ignored_rules or {})})\n    if jobgraph and not jobgraph:empty() then\n        local total = jobgraph:size()\n        local index = 0\n        local jobqueue = jobgraph:build()\n        while true do\n            local job = jobqueue:getfree()\n            if job then\n                if job.run then\n                    job.run(index, total, {progress = progress_wrapper})\n                end\n                jobqueue:remove(job)\n                index = index + 1\n            else\n                break\n            end\n        end\n    end\n    -- translate batchcmds:lua to batchcmds:runv, we need to generate executable commmand\n    for _, cmd in ipairs(buildcmds:cmds()) do\n        local kind = cmd.kind\n        if cmd.script and (kind == \"lua\" or kind == \"vlua\") then\n            cmd.kind = (kind == \"vlua\") and \"vrunv\" or \"runv\"\n            cmd.program = os.programfile()\n            cmd.argv = table.join(\"lua\", cmd.script, cmd.argv)\n            cmd.script = nil\n        end\n    end\n    return buildcmds:cmds()\nend\n\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs200x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs200x.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"vs200x_solution\")\nimport(\"vs200x_vcproj\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- make vstudio project\nfunction make(outputdir, vsinfo)\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- init solution directory\n    vsinfo.solution_dir = path.join(outputdir, \"vs\" .. vsinfo.vstudio_version)\n\n    -- make solution\n    vs200x_solution.make(vsinfo)\n\n    local project_targets = target_utils.get_project_targets()\n    -- TODO\n    -- disable precompiled header first\n    for _, target in pairs(project_targets) do\n        target:set(\"pcheader\", nil)\n        target:set(\"pcxxheader\", nil)\n    end\n\n    -- make vsprojs\n    for _, target in pairs(project_targets) do\n        if not target:is_phony() then\n            vs200x_vcproj.make(vsinfo, target)\n        end\n    end\n\n    -- leave project directory\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs200x_solution.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs200x_solution.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"vsfile\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- make header\nfunction _make_header(slnfile, vsinfo)\n    slnfile:print(\"Microsoft Visual Studio Solution File, Format Version %s.00\", vsinfo.solution_version)\n    slnfile:print(\"# Visual Studio %s\", vsinfo.vstudio_version)\nend\n\n-- make projects\nfunction _make_projects(slnfile, vsinfo)\n\n    -- the vstudio tool uuid for vc project\n    local vctool = \"8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942\"\n\n    -- make all targets\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in pairs(project_targets) do\n        if not target:is_phony() then\n\n            -- enter project\n            slnfile:enter(\"Project(\\\"{%s}\\\") = \\\"%s\\\", \\\"%s\\\\%s.vcproj\\\", \\\"{%s}\\\"\", vctool, targetname, targetname, targetname, hash.uuid4(targetname))\n\n            -- add dependencies\n            for _, dep in ipairs(target:get(\"deps\")) do\n                slnfile:enter(\"ProjectSection(ProjectDependencies) = postProject\")\n                slnfile:print(\"{%s} = {%s}\", hash.uuid4(dep), hash.uuid4(dep))\n                slnfile:leave(\"EndProjectSection\")\n            end\n\n            -- leave project\n            slnfile:leave(\"EndProject\")\n        end\n    end\nend\n\n-- make global\nfunction _make_global(slnfile, vsinfo)\n\n    -- enter global\n    slnfile:enter(\"Global\")\n\n    -- add solution configuration platforms\n    slnfile:enter(\"GlobalSection(SolutionConfigurationPlatforms) = preSolution\")\n    slnfile:print(\"$(mode)|Win32 = $(mode)|Win32\")\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- add project configuration platforms\n    slnfile:enter(\"GlobalSection(ProjectConfigurationPlatforms) = postSolution\")\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in pairs(project_targets) do\n        if not target:is_phony() then\n            slnfile:print(\"{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32\", hash.uuid4(targetname))\n            slnfile:print(\"{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32\", hash.uuid4(targetname))\n        end\n    end\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- add solution properties\n    slnfile:enter(\"GlobalSection(SolutionProperties) = preSolution\")\n    slnfile:print(\"HideSolutionNode = FALSE\")\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- leave global\n    slnfile:leave(\"EndGlobal\")\nend\n\n-- make solution\nfunction make(vsinfo)\n\n    -- init solution name\n    vsinfo.solution_name = project.name() or (\"vs\" .. vsinfo.vstudio_version)\n\n    -- open solution file\n    local slnfile = vsfile.open(path.join(vsinfo.solution_dir, vsinfo.solution_name .. \".sln\"), \"w\")\n\n    -- init indent character\n    vsfile.indentchar('\\t')\n\n    -- make header\n    _make_header(slnfile, vsinfo)\n\n    -- make projects\n    _make_projects(slnfile, vsinfo)\n\n    -- make global\n    _make_global(slnfile, vsinfo)\n\n    -- exit solution file\n    slnfile:close()\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs200x_vcproj.lua\n--\n\n-- imports\nimport(\"core.tool.linker\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"vsfile\")\n\n-- make compiling flags\nfunction _make_compflags(sourcefile, target, vcprojdir)\n\n    -- make the compiling flags\n    local compflags = compiler.compflags(sourcefile, {target = target})\n\n    -- replace -Idir or /Idir, -Fdsymbol.pdb or /Fdsymbol.pdb\n    local flags = {}\n    for _, flag in ipairs(compflags) do\n\n        -- replace -Idir or /Idir\n        flag = flag:gsub(\"[%-|/]I(.*)\", function (dir)\n                        dir = path.translate(dir:trim())\n                        if not path.is_absolute(dir) then\n                            dir = path.relative(path.absolute(dir), vcprojdir)\n                        end\n                        return \"/I\" .. dir\n                    end)\n\n        -- replace -Fdsymbol.pdb or /Fdsymbol.pdb\n        flag = flag:gsub(\"[%-|/]Fd(.*)\", function (dir)\n                        dir = path.translate(dir:trim())\n                        if not path.is_absolute(dir) then\n                            dir = path.relative(path.absolute(dir), vcprojdir)\n                        end\n                        return \"/Fd\" .. dir\n                    end)\n\n        -- save flag\n        table.insert(flags, flag)\n    end\n\n    -- make flags string\n    flags = os.args(flags)\n\n    -- replace \" => &quot;\n    flags = flags:gsub(\"\\\"\", \"&quot;\")\n\n    -- ok?\n    return flags\nend\n\n-- make linking flags\nfunction _make_linkflags(target, vcprojdir)\n\n    -- make the linking flags\n    local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target})\n\n    -- replace -libpath:dir or /libpath:dir, -pdb:symbol.pdb or /pdb:symbol.pdb\n    local flags = {}\n    for _, flag in ipairs(linkflags) do\n\n        -- replace -libpath:dir or /libpath:dir\n        flag = flag:gsub(\"[%-|/]libpath:(.*)\", function (dir)\n                        dir = path.translate(dir:trim())\n                        if not path.is_absolute(dir) then\n                            dir = path.relative(path.absolute(dir), vcprojdir)\n                        end\n                        return \"/libpath:\" .. dir\n                    end)\n\n        -- replace -pdb:symbol.pdb or /pdb:symbol.pdb\n        flag = flag:gsub(\"[%-|/]pdb:(.*)\", function (dir)\n                        dir = path.translate(dir:trim())\n                        if not path.is_absolute(dir) then\n                            dir = path.relative(path.absolute(dir), vcprojdir)\n                        end\n                        return \"/pdb:\" .. dir\n                    end)\n\n        -- save flag\n        table.insert(flags, flag)\n    end\n\n    -- make flags string\n    flags = os.args(flags)\n\n    -- replace \" => &quot;\n    flags = flags:gsub(\"\\\"\", \"&quot;\")\n\n    -- ok?\n    return flags\nend\n\n-- make header\nfunction _make_header(vcprojfile, vsinfo, target)\n\n    -- the target name\n    local targetname = target:name()\n\n    -- make header\n    vcprojfile:print(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\")\n    vcprojfile:enter(\"<VisualStudioProject\")\n        vcprojfile:print(\"ProjectType=\\\"Visual C++\\\"\")\n        vcprojfile:print(\"Version=\\\"%s0\\\"\", assert(vsinfo.project_version))\n        vcprojfile:print(\"Name=\\\"%s\\\"\", targetname)\n        vcprojfile:print(\"ProjectGUID=\\\"{%s}\\\"\", hash.uuid4(targetname))\n        vcprojfile:print(\"RootNamespace=\\\"%s\\\"\", targetname)\n        vcprojfile:print(\"TargetFrameworkVersion=\\\"196613\\\"\")\n        vcprojfile:print(\">\")\nend\n\n-- make tailer\nfunction _make_tailer(vcprojfile, vsinfo, target)\n    vcprojfile:leave(\"</VisualStudioProject>\")\nend\n\n-- make platforms\nfunction _make_platforms(vcprojfile, vsinfo, target)\n\n    -- add Win32 platform\n    vcprojfile:enter(\"<Platforms>\")\n\t\tvcprojfile:enter(\"<Platform\")\n\t\t\tvcprojfile:print(\"Name=\\\"Win32\\\"\")\n\t\tvcprojfile:leave(\"/>\")\n\tvcprojfile:leave(\"</Platforms>\")\nend\n\n-- make toolfiles\nfunction _make_toolfiles(vcprojfile, vsinfo, target)\n\n    -- empty toolfiles\n    vcprojfile:enter(\"<ToolFiles>\")\n\tvcprojfile:leave(\"</ToolFiles>\")\nend\n\n-- make VCCLCompilerTool\n--\n-- e.g.\n--\n-- <Tool\n--      Name=\"VCCLCompilerTool\"\n--      AdditionalOptions=\"/TP\"\n--      Optimization=\"0\"\n--      AdditionalIncludeDirectories=\"&quot;$(SolutionDir)\\..\\..\\src&quot;;&quot;\"\n--      PreprocessorDefinitions=\"\"\n--      MinimalRebuild=\"true\"\n--      BasicRuntimeChecks=\"3\"\n--      RuntimeLibrary=\"3\"\n--      UsePrecompiledHeader=\"0\"\n--      WarningLevel=\"3\"\n--      DebugInformationFormat=\"4\"\n-- />\nfunction _make_VCCLCompilerTool(vcprojfile, vsinfo, target, compflags)\n    vcprojfile:enter(\"<Tool\")\n        vcprojfile:print(\"Name=\\\"VCCLCompilerTool\\\"\")\n        vcprojfile:print(\"ProgramDataBaseFileName=\\\"\\\"\") -- disable pdb file default\n        -- MT:0, MTd:1, MD:2, MDd:3, ML:4, MLd:5\n        local runtime = 0\n        for _,flag in pairs(compflags) do\n            if flag:find(\"[%-|/]MD\") then\n                runtime = 2\n                break\n            elseif flag:find(\"[%-|/]MT\") then\n                runtime = 0\n                break\n            end\n        end\n        vcprojfile:print(\"RuntimeLibrary=\\\"%d\\\"\", is_mode(\"debug\") and runtime + 1 or runtime)\n    vcprojfile:leave(\"/>\")\nend\n\n-- make VCLinkerTool\n--\n-- e.g.\n-- <Tool\n--      Name=\"VCLinkerTool\"\n--      AdditionalDependencies=\"xxx.lib\"\n--      LinkIncremental=\"2\"\n--      AdditionalLibraryDirectories=\"&quot;$(SolutionDir)\\..\\..\\lib&quot;\"\n--      GenerateDebugInformation=\"true\"\n--      SubSystem=\"1\"\n--      TargetMachine=\"1\"\n-- />\nfunction _make_VCLinkerTool(vcprojfile, vsinfo, target, vcprojdir)\n\n    -- need not linker?\n    local kind = target:kind()\n    if kind ~= \"binary\" and kind ~= \"shared\" then\n        vcprojfile:enter(\"<Tool\")\n            vcprojfile:print(\"Name=\\\"VCLinkerTool\\\"\")\n        vcprojfile:leave(\"/>\")\n        return\n    end\n\n    -- generate debug infomation?\n    local debug = false\n    for _, symbol in ipairs(target:get(\"symbols\")) do\n        if symbol == \"debug\" then\n            debug = true\n            break\n        end\n    end\n\n    -- subsystem, console: 1, windows: 2\n    local subsystem = 1\n    local flags = _make_linkflags(target, vcprojdir)\n    if flags:lower():find(\"[%-/]subsystem:windows\") then\n        subsystem = 2\n    end\n\n    -- make it\n    vcprojfile:enter(\"<Tool\")\n        vcprojfile:print(\"Name=\\\"VCLinkerTool\\\"\")\n        vcprojfile:print(\"AdditionalOptions=\\\"%s\\\"\", flags)\n\t\tvcprojfile:print(\"AdditionalDependencies=\\\"\\\"\")\n\t\tvcprojfile:print(\"AdditionalLibraryDirectories=\\\"\\\"\")\n        vcprojfile:print(\"LinkIncremental=\\\"2\\\"\") -- enable: 2, disable: 1\n        vcprojfile:print(\"GenerateDebugInformation=\\\"%s\\\"\", tostring(debug))\n        vcprojfile:print(\"SubSystem=\\\"%d\\\"\", subsystem) -- console: 1, windows: 2\n        vcprojfile:print(\"TargetMachine=\\\"%d\\\"\", is_arch(\"x64\") and 17 or 1)\n    vcprojfile:leave(\"/>\")\nend\n\n-- make configurations\nfunction _make_configurations(vcprojfile, vsinfo, target, vcprojdir)\n\n    -- init configuration type\n    local configuration_types =\n    {\n        binary = 1\n    ,   shared = 2\n    ,   static = 4\n    }\n\n    -- save compiler flags\n    local compflags=nil\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        local sourcekind = sourcebatch.sourcekind\n        if sourcekind then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local flags = compiler.compflags(sourcefile, {target = target})\n                if sourcekind == \"cc\" or sourcekind == \"cxx\" then\n                    compflags = flags\n                    break\n                end\n            end\n        end\n        if compflags then\n            break\n        end\n    end\n\n    -- use mfc? not used: 0, static: 1, shared: 2\n    local usemfc = 0\n    if target:rule(\"win.sdk.mfc.shared_app\") or target:rule(\"win.sdk.mfc.shared\") then\n        usemfc = 2\n    elseif target:rule(\"win.sdk.mfc.static_app\") or target:rule(\"win.sdk.mfc.static\") then\n        usemfc = 1\n    end\n\n    -- set unicode\n    local unicode = false\n    for _, flag in ipairs(compflags) do\n        if flag:find(\"[%-|/]DUNICODE\") then\n            unicode = true\n            break\n        end\n    end\n\n    -- enter configurations\n    vcprojfile:enter(\"<Configurations>\")\n\n        -- make configuration for the current mode\n        vcprojfile:enter(\"<Configuration\")\n            vcprojfile:print(\"Name=\\\"$(mode)|Win32\\\"\")\n\t\t\tvcprojfile:print(\"OutputDirectory=\\\"%s\\\"\", path.relative(path.absolute(target:targetdir()), vcprojdir))\n\t\t\tvcprojfile:print(\"IntermediateDirectory=\\\"%s\\\"\", path.relative(path.absolute(target:objectdir()), vcprojdir))\n\t\t\tvcprojfile:print(\"ConfigurationType=\\\"%d\\\"\", assert(configuration_types[target:kind()]))\n            vcprojfile:print(\"CharacterSet=\\\"%d\\\"\", unicode and 1 or 2) -- mbc: 2, wcs: 1\n            vcprojfile:print(\"UseOfMFC=\\\"%d\\\"\", usemfc)\n            vcprojfile:print(\">\")\n\n            -- make VCPreBuildEventTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCPreBuildEventTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCCustomBuildTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCCustomBuildTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCXMLDataGeneratorTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCXMLDataGeneratorTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCWebServiceProxyGeneratorTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCWebServiceProxyGeneratorTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCMIDLTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCMIDLTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCCLCompilerTool\n            _make_VCCLCompilerTool(vcprojfile, vsinfo, target, compflags)\n\n            -- make VCManagedResourceCompilerTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCManagedResourceCompilerTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCResourceCompilerTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCResourceCompilerTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCPreLinkEventTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCPreLinkEventTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCLinkerTool\n            _make_VCLinkerTool(vcprojfile, vsinfo, target, vcprojdir)\n\n            -- make VCALinkTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCALinkTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCManifestTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCManifestTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCXDCMakeTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCXDCMakeTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCBscMakeTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCBscMakeTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCFxCopTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCFxCopTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCAppVerifierTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCAppVerifierTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n            -- make VCPostBuildEventTool\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCPostBuildEventTool\\\"\")\n            vcprojfile:leave(\"/>\")\n\n\n        -- leave configuration\n        vcprojfile:leave(\"</Configuration>\")\n\n    -- leave configurations\n\tvcprojfile:leave(\"</Configurations>\")\nend\n\n-- make references\nfunction _make_references(vcprojfile, vsinfo, target)\n    vcprojfile:enter(\"<References>\")\n\tvcprojfile:leave(\"</References>\")\nend\n\n-- make cxfile\n--\n-- e.g.\n--  <File\n--      RelativePath=\"..\\..\\..\\src\\file3.c\"\n--      >\n--      <FileConfiguration\n--          Name=\"Debug|Win32\"\n--          >\n--          <Tool\n--              Name=\"VCCLCompilerTool\"\n--              AdditionalOptions=\"-Dtest\"\n--          />\n--      </FileConfiguration>\n--  </File>\nfunction _make_cxfile(vcprojfile, vsinfo, target, sourcefile, objectfile, vcprojdir)\n\n    -- get the target key\n    local key = target:cachekey()\n\n    -- make flags cache\n    _g.flags = _g.flags or {}\n\n    -- make flags\n    local flags = _g.flags[key] or _make_compflags(sourcefile, target, vcprojdir)\n    _g.flags[key] = flags\n\n    -- enter file\n    vcprojfile:enter(\"<File\")\n\n        -- add file path\n        vcprojfile:print(\"RelativePath=\\\"%s\\\"\", path.relative(path.absolute(sourcefile), vcprojdir))\n        vcprojfile:print(\">\")\n\n        -- add file configuration\n        vcprojfile:enter(\"<FileConfiguration\")\n            vcprojfile:print(\"Name=\\\"$(mode)|Win32\\\"\")\n            vcprojfile:print(\">\")\n\n            -- add compiling options\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCCLCompilerTool\\\"\")\n                vcprojfile:print(\"AdditionalOptions=\\\"%s\\\"\", flags)\n                vcprojfile:print(\"ObjectFile=\\\"%s\\\"\", path.relative(path.absolute(objectfile), vcprojdir))\n\n                -- compile as c++ if exists flag: /TP\n                if flags:find(\"[%-|/]TP\") then\n                    vcprojfile:print(\"CompileAs=\\\"2\\\"\")\n                end\n            vcprojfile:leave(\"/>\")\n        vcprojfile:leave(\"</FileConfiguration>\")\n\n    -- leave file\n    vcprojfile:leave(\"</File>\")\nend\n\n-- make rcfile\n--\n-- e.g.\n--  <File\n--      RelativePath=\"..\\..\\..\\src\\resource.rc\"\n--      >\n--      <FileConfiguration\n--          Name=\"Debug|Win32\"\n--          >\n--          <Tool\n--              Name=\"VCResourceCompilerTool\"\n--              ResourceOutputFileName=\"..\\..\\..\\build\\src\\resource.res\"\n--          />\n--      </FileConfiguration>\n--  </File>\nfunction _make_rcfile(vcprojfile, vsinfo, target, sourcefile, objectfile, vcprojdir)\n\n    -- enter file\n    vcprojfile:enter(\"<File\")\n\n        -- add file path\n        vcprojfile:print(\"RelativePath=\\\"%s\\\"\", path.relative(path.absolute(sourcefile), vcprojdir))\n        vcprojfile:print(\">\")\n\n        -- add file configuration\n        vcprojfile:enter(\"<FileConfiguration\")\n            vcprojfile:print(\"Name=\\\"$(mode)|Win32\\\"\")\n            vcprojfile:print(\">\")\n\n            -- add compiling options\n            vcprojfile:enter(\"<Tool\")\n                vcprojfile:print(\"Name=\\\"VCResourceCompilerTool\\\"\")\n                -- FIXME: multi rc files support\n                -- vcprojfile:print(\"ResourceOutputFileName=\\\"%s\\\"\", path.relative(path.absolute(objectfile), vcprojdir))\n            vcprojfile:leave(\"/>\")\n        vcprojfile:leave(\"</FileConfiguration>\")\n\n    -- leave file\n    vcprojfile:leave(\"</File>\")\nend\n\n-- make files\n--\n-- e.g.\n-- <Filter\n--      Name=\"Source Files\"\n--      >\n--      <File\n--          RelativePath=\"..\\..\\..\\src\\file1.c\"\n--          >\n--      </File>\n--      <File\n--          RelativePath=\"..\\..\\..\\src\\file2.c\"\n--          >\n--      </File>\n--      <File\n--          RelativePath=\"..\\..\\..\\src\\file3.c\"\n--          >\n--          <FileConfiguration\n--              Name=\"Debug|Win32\"\n--              >\n--              <Tool\n--                  Name=\"VCCLCompilerTool\"\n--                  AdditionalOptions=\"-Dtest\"\n--              />\n--          </FileConfiguration>\n--      </File>\n--      <File\n--          RelativePath=\"..\\..\\..\\src\\file4.c\"\n--          >\n--      </File>\n-- </Filter>\nfunction _make_files(vcprojfile, vsinfo, target, vcprojdir)\n\n    -- enter files\n    vcprojfile:enter(\"<Files>\")\n        local sourcebatches = target:sourcebatches()\n        -- c/cxx files\n        vcprojfile:enter(\"<Filter Name=\\\"Source Files\\\">\")\n            for _, sourcebatch in pairs(sourcebatches) do\n                local sourcekind = sourcebatch.sourcekind\n                if sourcekind ~= \"mrc\" then\n                    local objectfiles = sourcebatch.objectfiles\n                    for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                        _make_cxfile(vcprojfile, vsinfo, target, sourcefile, objectfiles[idx], vcprojdir)\n                    end\n                end\n            end\n\n        -- leave c/cxx files\n        vcprojfile:leave(\"</Filter>\")\n\n        -- *.rc files\n        vcprojfile:enter(\"<Filter Name=\\\"Resource Files\\\">\")\n            for _, sourcebatch in pairs(sourcebatches) do\n                local sourcekind = sourcebatch.sourcekind\n                if sourcekind == \"mrc\" then\n                    local objectfiles = sourcebatch.objectfiles\n                    for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                        _make_rcfile(vcprojfile, vsinfo, target, sourcefile, objectfiles[idx], vcprojdir)\n                    end\n                end\n            end\n\n        -- leave *.rc files\n        vcprojfile:leave(\"</Filter>\")\n\n\tvcprojfile:leave(\"</Files>\")\nend\n\n-- make globals\nfunction _make_globals(vcprojfile, vsinfo, target)\n    vcprojfile:enter(\"<Globals>\")\n\tvcprojfile:leave(\"</Globals>\")\nend\n\n-- make vcproj\nfunction make(vsinfo, target)\n\n    -- the target name\n    local targetname = target:name()\n\n    -- the vcproj directory\n    local vcprojdir = path.join(vsinfo.solution_dir, targetname)\n\n    -- open vcproj file\n    local vcprojfile = vsfile.open(path.join(vcprojdir, targetname .. \".vcproj\"), \"w\")\n\n    -- init indent character\n    vsfile.indentchar('\\t')\n\n    -- make header\n    _make_header(vcprojfile, vsinfo, target)\n\n    -- make platforms\n    _make_platforms(vcprojfile, vsinfo, target)\n\n    -- make toolfiles\n    _make_toolfiles(vcprojfile, vsinfo, target)\n\n    -- make configurations\n    _make_configurations(vcprojfile, vsinfo, target, vcprojdir)\n\n    -- make references\n    _make_references(vcprojfile, vsinfo, target)\n\n    -- make files\n    _make_files(vcprojfile, vsinfo, target, vcprojdir)\n\n    -- make globals\n    _make_globals(vcprojfile, vsinfo, target)\n\n    -- make tailer\n    _make_tailer(vcprojfile, vsinfo, target)\n\n    -- exit solution file\n    vcprojfile:close()\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs201x.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs201x.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.colors\")\nimport(\"core.base.hashset\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.tool.compiler\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.toolchain\")\nimport(\"vs201x_solution\")\nimport(\"vs201x_vcxproj\")\nimport(\"vs201x_vcxproj_filters\")\nimport(\"vsutils\")\nimport(\"core.cache.memcache\")\nimport(\"core.cache.localcache\")\nimport(\"private.action.require.install\", {alias = \"install_requires\"})\nimport(\"private.action.run.runenvs\")\nimport(\"actions.config.configfiles\", {alias = \"generate_configfiles\", rootdir = os.programdir()})\nimport(\"private.utils.batchcmds\")\nimport(\"plugins.project.utils.target_cmds\", {rootdir = os.programdir()})\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\nfunction _translate_path(dir, vcxprojdir)\n    if dir == nil then\n        return \"\"\n    end\n    if type(dir) == \"string\" then\n        dir = path.translate(dir)\n        if dir == \"\" then\n            return \"\"\n        end\n        if path.is_absolute(dir) then\n            if dir:startswith(project.directory()) then\n                return vsutils.escape(path.relative(dir, vcxprojdir))\n            end\n            return vsutils.escape(dir)\n        else\n            return vsutils.escape(path.relative(path.absolute(dir), vcxprojdir))\n        end\n    end\n    local r = {}\n    for k, v in ipairs(dir) do\n        r[k] = _translate_path(v, vcxprojdir)\n    end\n    r = table.unique(r)\n    return path.joinenv(r)\nend\n\n-- clear cache\nfunction _clear_cache()\n    localcache.clear(\"detect\")\n    localcache.clear(\"option\")\n    localcache.clear(\"package\")\n    localcache.clear(\"toolchain\")\n\n    -- force recheck\n    localcache.set(\"config\", \"recheck\", true)\n\n    localcache.save()\nend\n\n-- get c++ modules rules\nfunction _get_cxxmodules_rules()\n    return {\"c++.build.modules\", \"c++.build.modules.builder\"}\nend\n\n-- get command string\nfunction _get_command_string(cmd, vcxprojdir)\n    local kind = cmd.kind\n    local opt = cmd.opt\n    if cmd.program then\n        local argv = {}\n        for _, v in ipairs(table.join(cmd.program, cmd.argv)) do\n            if path.instance_of(v) then\n                v = v:clone():set(_translate_path(v:rawstr(), vcxprojdir)):str()\n            elseif path.is_absolute(v) then\n                v = _translate_path(v, vcxprojdir)\n            end\n            table.insert(argv, v)\n        end\n        local command = os.args(argv)\n        if opt and opt.curdir then\n            command = string.format(\"pushd \\\"%s\\\"\\n%s\\npopd\", _translate_path(opt.curdir, vcxprojdir), command)\n        end\n        return command\n    elseif kind == \"cp\" then\n        return string.format(\"copy /Y \\\"%s\\\" \\\"%s\\\"\", _translate_path(cmd.srcpath, vcxprojdir), _translate_path(cmd.dstpath, vcxprojdir))\n    elseif kind == \"rm\" then\n        return string.format(\"del /F /Q \\\"%s\\\" || rmdir /S /Q \\\"%s\\\"\", _translate_path(cmd.filepath, vcxprojdir), _translate_path(cmd.filepath, vcxprojdir))\n    elseif kind == \"rmdir\" then\n        return string.format(\"rmdir /S /Q \\\"%s\\\"\", _translate_path(cmd.filepath, vcxprojdir))\n    elseif kind == \"mv\" then\n        return string.format(\"rename \\\"%s\\\" \\\"%s\\\"\", _translate_path(cmd.srcpath, vcxprojdir), _translate_path(cmd.dstpath, vcxprojdir))\n    elseif kind == \"cd\" then\n        return string.format(\"cd \\\"%s\\\"\", _translate_path(cmd.dir, vcxprojdir))\n    elseif kind == \"mkdir\" then\n        local dir = _translate_path(cmd.dir, vcxprojdir)\n        return string.format(\"if not exist \\\"%s\\\" mkdir \\\"%s\\\"\", dir, dir)\n    elseif kind == \"show\" or kind == \"show_progress\" then\n        local text = string.format(cmd.format, table.unpack(cmd.argv))\n        return string.format(\"echo %s\", colors.ignore(text))\n    end\nend\n\n-- make custom commands\nfunction _make_custom_commands(target, vcxprojdir)\n    -- https://github.com/xmake-io/xmake/issues/2337\n    target:data_set(\"plugin.project.kind\", \"vs\")\n    -- https://github.com/xmake-io/xmake/issues/2258\n    target:data_set(\"plugin.project.translate_path\", function (p)\n        return _translate_path(p, vcxprojdir)\n    end)\n\n    -- ignore c++ modules rules\n    local ignored_rules = _get_cxxmodules_rules()\n\n    -- add before commands\n    -- we use irpairs(groups), because the last group that should be given the highest priority.\n    -- rule.on_buildcmd_files should also be executed before building the target\n    local cmds_before = target_cmds.get_target_buildcmds(target, {ignored_rules = ignored_rules, stages = {\"before\", \"on\"}})\n\n    -- add after commands\n    local cmds_after = target_cmds.get_target_buildcmds(target, {ignored_rules = ignored_rules, stages = {\"after\"}})\n\n    local commands = {}\n    for _, cmd in ipairs(cmds_before) do\n        commands.before = commands.before or {}\n        table.insert(commands.before, _get_command_string(cmd, vcxprojdir))\n    end\n    for _, cmd in ipairs(cmds_after) do\n        commands.after = commands.after or {}\n        table.insert(commands.after, _get_command_string(cmd, vcxprojdir))\n    end\n    return commands\nend\n\n-- make target info\nfunction _make_targetinfo(mode, arch, target, vcxprojdir)\n\n    -- init target info\n    local targetinfo = { mode = mode, arch = vsutils.vsarch(arch) }\n\n    -- get sdk version\n    local msvc = toolchain.load(\"msvc\")\n    if msvc then\n        local vcvars = msvc:config(\"vcvars\")\n        if vcvars then\n            targetinfo.sdkver = vcvars.WindowsSDKVersion\n        end\n    end\n\n    -- save c/c++ precompiled output file (.pch)\n    targetinfo.pcoutputfile = target:pcoutputfile(\"c\")\n    targetinfo.pcxxoutputfile = target:pcoutputfile(\"cxx\")\n    target:set(\"pcheader\", nil)\n    target:set(\"pcxxheader\", nil)\n\n    -- save languages\n    targetinfo.languages = table.wrap(target:get(\"languages\"))\n\n    -- save symbols\n    targetinfo.symbols = target:get(\"symbols\")\n\n    -- has modules\n    targetinfo.has_modules = target:data(\"cxx.has_modules\")\n\n    -- save target kind\n    targetinfo.targetkind = target:kind()\n    if target:is_phony() or target:is_headeronly() then\n        return targetinfo\n    end\n\n    -- save target file\n    targetinfo.targetfile = target:targetfile()\n\n    -- save symbol file\n    targetinfo.symbolfile = target:symbolfile()\n\n    -- save sourcekinds\n    targetinfo.sourcekinds = target:sourcekinds()\n\n    -- save target dir\n    targetinfo.targetdir = target:targetdir()\n\n    -- save object dir\n    targetinfo.objectdir = target:objectdir()\n\n    -- save compiler flags and cmds\n    local firstcompflags = nil\n    targetinfo.compflags = {}\n    targetinfo.compargvs = {}\n    local sourcebatches = target:sourcebatches()\n    for _, sourcebatch in table.orderpairs(sourcebatches) do\n        local sourcekind = sourcebatch.sourcekind\n        local rulename = sourcebatch.rulename\n        if sourcekind then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local compflags = compiler.compflags(sourcefile, {target = target, sourcekind = sourcekind})\n                if not firstcompflags and (rulename == \"c.build\" or rulename == \"c++.build\" or rulename == \"c++.build.modules\" or rulename == \"cuda.build\") then\n                    firstcompflags = compflags\n                end\n                targetinfo.compflags[sourcefile] = compflags\n                targetinfo.compargvs[sourcefile] = table.join(compiler.compargv(\"__sourcefile__\", \"__objectfile__\", {sourcekind = sourcekind, target = target}))\n\n                -- detect manifest\n                -- @see https://github.com/xmake-io/xmake/issues/2176\n                if sourcekind == \"mrc\" and os.isfile(sourcefile) then\n                    local resoucedata = io.readfile(sourcefile)\n                    if resoucedata and resoucedata:find(\"RT_MANIFEST\") then\n                        targetinfo.manifest_embed = false\n                    end\n                end\n            end\n        end\n    end\n\n    -- save sourcebatches\n    targetinfo.sourcebatches = target:sourcebatches()\n\n    -- save linker flags\n    local linkflags = linker.linkflags(target:is_moduleonly() and 'static' or target:kind(), target:sourcekinds(), {target = target})\n    targetinfo.linkflags = linkflags\n\n    if table.contains(target:sourcekinds(), \"cu\") then\n        -- save cuda linker flags\n        local linkinst = linker.load(\"gpucode\", \"cu\", {target = target})\n        targetinfo.culinkflags = linkinst:linkflags({target = target})\n\n        -- save cuda devlink status\n        targetinfo.cudevlink = target:policy(\"build.cuda.devlink\") or target:values(\"cuda.build.devlink\")\n    end\n\n    -- save execution dir (when executed from VS)\n    targetinfo.rundir = target:is_moduleonly() and \"\" or target:rundir()\n\n    -- save runenvs\n    local targetrunenvs = {}\n    local addrunenvs, setrunenvs = runenvs.make(target)\n    for k, v in table.orderpairs(target:pkgenvs()) do\n        addrunenvs = addrunenvs or {}\n        addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        for k, v in table.orderpairs(dep:pkgenvs()) do\n            addrunenvs = addrunenvs or {}\n            addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))\n        end\n    end\n    for k, v in table.orderpairs(addrunenvs) do\n        if k:upper() == \"PATH\" then\n            targetrunenvs[k] = _translate_path(v, vcxprojdir) .. \";$([System.Environment]::GetEnvironmentVariable('\" .. k .. \"'))\"\n        else\n            targetrunenvs[k] = path.joinenv(v) .. \";$([System.Environment]::GetEnvironmentVariable('\" .. k ..\"'))\"\n        end\n    end\n    for k, v in table.orderpairs(setrunenvs) do\n        if #v == 1 then\n            v = v[1]\n            if path.is_absolute(v) and v:startswith(project.directory()) then\n                targetrunenvs[k] = _translate_path(v, vcxprojdir)\n            else\n                targetrunenvs[k] = v[1]\n            end\n        else\n            targetrunenvs[k] = path.joinenv(v)\n        end\n    end\n    local runenvstr = {}\n    for k, v in table.orderpairs(targetrunenvs) do\n        table.insert(runenvstr, k .. \"=\" .. v)\n    end\n    targetinfo.runenvs = table.concat(runenvstr, \"\\n\")\n\n    -- use mfc? save the mfc runtime kind\n    if target:rule(\"win.sdk.mfc.shared_app\") or target:rule(\"win.sdk.mfc.shared\") then\n        targetinfo.usemfc = \"Dynamic\"\n    elseif target:rule(\"win.sdk.mfc.static_app\") or target:rule(\"win.sdk.mfc.static\") then\n        targetinfo.usemfc = \"Static\"\n    end\n\n    -- set unicode\n    for _, flag in ipairs(firstcompflags) do\n        if flag:find(\"[%-|/]DUNICODE\") then\n            targetinfo.unicode = true\n            break\n        end\n    end\n\n    -- save custom commands\n    targetinfo.commands = _make_custom_commands(target, vcxprojdir)\n    return targetinfo\nend\n\nfunction _make_vsinfo_modes()\n    local vsinfo_modes = {}\n    local modes = option.get(\"modes\")\n    if modes then\n        if not modes:find(\"\\\"\") then\n            modes = modes:gsub(\",\", path.envsep())\n        end\n        for _, mode in ipairs(path.splitenv(modes)) do\n            table.insert(vsinfo_modes, mode:trim())\n        end\n    else\n        vsinfo_modes = project.modes()\n    end\n    if not vsinfo_modes or #vsinfo_modes == 0 then\n        vsinfo_modes = { config.mode() }\n    end\n    return vsinfo_modes\nend\n\nfunction _make_vsinfo_archs()\n    local vsinfo_archs = {}\n    local archs = option.get(\"archs\")\n    if archs then\n        if not archs:find(\"\\\"\") then\n            archs = archs:gsub(\",\", path.envsep())\n        end\n        for _, arch in ipairs(path.splitenv(archs)) do\n            table.insert(vsinfo_archs, arch:trim())\n        end\n    else\n        -- we use it first if global set_arch(\"xx\") is setted in xmake.lua\n        vsinfo_archs = project.get(\"target.arch\")\n        if not vsinfo_archs then\n            -- for set_allowedarchs()\n            local allowed_archs = project.allowed_archs(config.plat())\n            if allowed_archs then\n                vsinfo_archs = allowed_archs:to_array()\n            end\n        end\n        if not vsinfo_archs then\n            local default_archs = toolchain.load(\"msvc\"):config(\"vcarchs\")\n            if not default_archs then\n                default_archs = platform.archs()\n            end\n            if default_archs then\n                default_archs = hashset.from(table.wrap(default_archs))\n                -- just generate single arch by default to avoid some fails for installing packages.\n                -- @see https://github.com/xmake-io/xmake/issues/3268\n                local arch = config.arch()\n                if default_archs:has(arch) then\n                    vsinfo_archs = { arch }\n                else\n                    default_archs:remove(\"arm64\")\n                    vsinfo_archs = default_archs:to_array()\n                end\n            end\n        end\n    end\n    if not vsinfo_archs or #vsinfo_archs == 0 then\n        vsinfo_archs = { config.arch() }\n    end\n    return vsinfo_archs\nend\n\n-- make vstudio project\nfunction make(outputdir, vsinfo)\n    local oldir = os.cd(project.directory())\n\n    -- prepare targets\n    target_cmds.prepare_targets()\n\n    -- init vsinfo\n    vsinfo.solution_dir = path.join(outputdir, \"vs\" .. vsinfo.vstudio_version)\n    vsinfo.modes = _make_vsinfo_modes()\n    vsinfo.archs = _make_vsinfo_archs()\n\n    -- load targets\n    local targets = {}\n    for mode_idx, mode in ipairs(vsinfo.modes) do\n        for arch_idx, arch in ipairs(vsinfo.archs) do\n\n            -- trace\n            print(\"checking for %s.%s ...\", mode, arch)\n\n            -- reload config, project and platform\n            if mode ~= config.mode() or arch ~= config.arch() then\n\n                -- reset project configs and caches\n                vsutils.reset_config_and_caches(mode, arch)\n\n                -- check platform\n                platform.load(config.plat(), arch):check()\n\n                -- check project options\n                project.check_options()\n\n                -- install and update requires\n                install_requires()\n\n                -- check target toolchains\n                target_utils.check_target_toolchains()\n\n                -- load targets\n                project.load_targets()\n\n                -- update config files\n                generate_configfiles()\n            end\n\n            -- ensure to enter project directory\n            os.cd(project.directory())\n\n            -- save targets\n            local project_targets = target_utils.get_project_targets()\n            for targetname, target in table.orderpairs(project_targets) do\n\n                -- make target with the given mode and arch\n                targets[targetname] = targets[targetname] or {}\n                local _target = targets[targetname]\n\n                -- the vcxproj directory\n                _target.project_dir = path.join(vsinfo.solution_dir, targetname)\n\n                -- save c/c++ precompiled header\n                _target.pcheader   = target:pcheaderfile(\"c\")     -- header.h\n                _target.pcxxheader = target:pcheaderfile(\"cxx\")   -- header.[hpp|inl]\n\n                -- init target info\n                _target.name = targetname\n                _target.kind = target:kind()\n                _target.scriptdir = target:scriptdir()\n                _target.info = _target.info or {}\n                table.insert(_target.info, _make_targetinfo(mode, arch, target, _target.project_dir))\n\n                -- save all sourcefiles and headerfiles\n                _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles())))\n                _target.headerfiles = table.unique(table.join(_target.headerfiles or {}, (target:headerfiles())))\n                _target.extrafiles = table.unique(table.join(_target.extrafiles or {}, (target:extrafiles())))\n\n                -- sort them to stabilize generation\n                table.sort(_target.sourcefiles)\n                table.sort(_target.headerfiles)\n                table.sort(_target.extrafiles)\n\n                -- save file groups\n                _target.filegroups = table.unique(table.join(_target.filegroups or {}, target:get(\"filegroups\")))\n\n                -- save references to deps\n                for _, dep in ipairs(target:orderdeps()) do\n                    _target.deps = _target.deps or {}\n                    local dep_name = dep:name()\n                    _target.deps[dep_name] = path.relative(path.join(vsinfo.solution_dir, dep_name, dep_name .. \".vcxproj\"), _target.project_dir)\n                end\n\n                for filegroup, groupconf in pairs(target:extraconf(\"filegroups\")) do\n                    _target.filegroups_extraconf = _target.filegroups_extraconf or {}\n                    local mergedconf = _target.filegroups_extraconf[filegroup]\n                    if not mergedconf then\n                        mergedconf = {}\n                        _target.filegroups_extraconf[filegroup] = mergedconf\n                    end\n\n                    if groupconf.rootdir then\n                        mergedconf.rootdir = table.unique(table.join(mergedconf.rootdir or {}, table.wrap(groupconf.rootdir)))\n                    end\n                    if groupconf.files then\n                        mergedconf.files = table.unique(table.join(mergedconf.files or {}, table.wrap(groupconf.files)))\n                    end\n                    mergedconf.plain = groupconf.plain or mergedconf.plain\n                end\n            end\n        end\n    end\n\n    -- make solution\n    vs201x_solution.make(vsinfo)\n\n    -- make .vcxproj\n    for _, target in table.orderpairs(targets) do\n        vs201x_vcxproj.make(vsinfo, target)\n        vs201x_vcxproj_filters.make(vsinfo, target)\n    end\n\n    -- clear local cache\n    _clear_cache()\n    os.cd(oldir)\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs201x_solution.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs201x_solution.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"vsfile\")\nimport(\"vsutils\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- make header\nfunction _make_header(slnfile, vsinfo)\n    slnfile:print(\"Microsoft Visual Studio Solution File, Format Version %s.00\", vsinfo.solution_version)\n    slnfile:print(\"# Visual Studio %s\", vsinfo.vstudio_version)\nend\n\n-- make projects\nfunction _make_projects(slnfile, vsinfo)\n\n    -- make all targets\n    local groups = {}\n    local targets = {}\n    local vctool = \"8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942\"\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in table.orderpairs(project_targets) do\n        -- we need to set startup project for default or binary target\n        -- @see https://github.com/xmake-io/xmake/issues/1249\n        if target:get(\"default\") == true then\n            table.insert(targets, 1, target)\n        elseif target:is_binary() then\n            local first_target = targets[1]\n            if not first_target or first_target:get(\"default\") ~= true then\n                table.insert(targets, 1, target)\n            else\n                table.insert(targets, target)\n            end\n        else\n            table.insert(targets, target)\n        end\n    end\n    for _, target in ipairs(targets) do\n        local targetname = target:name()\n        slnfile:enter(\"Project(\\\"{%s}\\\") = \\\"%s\\\", \\\"%s\\\\%s.vcxproj\\\", \\\"{%s}\\\"\", vctool, targetname, targetname, targetname, hash.uuid4(targetname))\n        for _, dep in ipairs(target:get(\"deps\")) do\n            slnfile:enter(\"ProjectSection(ProjectDependencies) = postProject\")\n            slnfile:print(\"{%s} = {%s}\", hash.uuid4(dep), hash.uuid4(dep))\n            slnfile:leave(\"EndProjectSection\")\n        end\n        slnfile:leave(\"EndProject\")\n        local group_path = target:get(\"group\")\n        if group_path and #(group_path:trim()) > 0 then\n            local group_current_path\n            local group_names = path.split(group_path)\n            for idx, group_name in ipairs(group_names) do\n                group_current_path = group_current_path and path.join(group_current_path, group_name) or group_name\n                groups[group_current_path] = hash.uuid4(\"group.\" .. group_current_path)\n            end\n        end\n    end\n\n    -- make all groups\n    local project_group_uuid = \"2150E333-8FDC-42A3-9474-1A3956D46DE8\"\n    for group_path, group_uuid in table.orderpairs(groups) do\n        local group_name = path.filename(group_path)\n        slnfile:enter(\"Project(\\\"{%s}\\\") = \\\"%s\\\", \\\"%s\\\", \\\"{%s}\\\"\",\n            project_group_uuid, group_name, group_name, group_uuid)\n        slnfile:leave(\"EndProject\")\n    end\nend\n\n-- make global\nfunction _make_global(slnfile, vsinfo)\n\n    -- enter global\n    slnfile:enter(\"Global\")\n\n    -- add solution configuration platforms\n    slnfile:enter(\"GlobalSection(SolutionConfigurationPlatforms) = preSolution\")\n    for _, mode in ipairs(vsinfo.modes) do\n        for _, arch in ipairs(vsinfo.archs) do\n            slnfile:print(\"%s|%s = %s|%s\", mode, arch, mode, arch)\n        end\n    end\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- add project configuration platforms\n    slnfile:enter(\"GlobalSection(ProjectConfigurationPlatforms) = postSolution\")\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in table.orderpairs(project_targets) do\n        for _, mode in ipairs(vsinfo.modes) do\n            for _, arch in ipairs(vsinfo.archs) do\n                local vs_arch = vsutils.vsarch(arch)\n                slnfile:print(\"{%s}.%s|%s.ActiveCfg = %s|%s\", hash.uuid4(targetname), mode, arch, mode, vs_arch)\n                slnfile:print(\"{%s}.%s|%s.Build.0 = %s|%s\", hash.uuid4(targetname), mode, arch, mode, vs_arch)\n            end\n        end\n    end\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- add solution properties\n    slnfile:enter(\"GlobalSection(SolutionProperties) = preSolution\")\n    slnfile:print(\"HideSolutionNode = FALSE\")\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- add project groups\n    slnfile:enter(\"GlobalSection(NestedProjects) = preSolution\")\n    local subgroups = {}\n    for targetname, target in table.orderpairs(project_targets) do\n        local group_path = target:get(\"group\")\n        if group_path then\n            -- target -> group\n            group_path = path.normalize(group_path)\n            slnfile:print(\"{%s} = {%s}\", hash.uuid4(targetname), hash.uuid4(\"group.\" .. group_path))\n            -- group -> group -> ...\n            local group_current_path\n            local group_names = path.split(group_path)\n            for idx, group_name in ipairs(group_names) do\n                group_current_path = group_current_path and path.join(group_current_path, group_name) or group_name\n                local group_name_sub = group_names[idx + 1]\n                local key = group_name .. (group_name_sub or \"\")\n                if group_name_sub and not subgroups[key] then\n                    slnfile:print(\"{%s} = {%s}\", hash.uuid4(\"group.\" .. path.join(group_current_path, group_name_sub)),\n                        hash.uuid4(\"group.\" .. group_current_path))\n                    subgroups[key] = true\n                end\n            end\n        end\n    end\n    slnfile:leave(\"EndGlobalSection\")\n\n    -- leave global\n    slnfile:leave(\"EndGlobal\")\nend\n\n-- make solution\nfunction make(vsinfo)\n\n    -- init solution name\n    vsinfo.solution_name = project.name() or (\"vs\" .. vsinfo.vstudio_version)\n\n    -- open solution file\n    local slnpath = path.join(vsinfo.solution_dir, vsinfo.solution_name .. \".sln\")\n    local slnfile = vsfile.open(slnpath, \"w\")\n\n    -- init indent character\n    vsfile.indentchar('\\t')\n\n    -- make header\n    _make_header(slnfile, vsinfo)\n\n    -- make projects\n    _make_projects(slnfile, vsinfo)\n\n    -- make global\n    _make_global(slnfile, vsinfo)\n\n    -- exit solution file\n    slnfile:close()\nend\n\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs201x_vcxproj.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.project.rule\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.language.language\")\nimport(\"core.tool.toolchain\")\nimport(\"private.utils.batchcmds\")\nimport(\"detect.sdks.find_cuda\")\nimport(\"vsfile\")\nimport(\"vsutils\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\nimport(\"rules.c++.modules.support\", {rootdir = os.programdir()})\n\nfunction _make_dirs(dir, vcxprojdir)\n    dir = dir:trim()\n    if #dir == 0 then\n        return \"\"\n    end\n    dir = path.translate(dir)\n    if not path.is_absolute(dir) then\n        dir = path.relative(path.absolute(dir), vcxprojdir)\n    end\n    return dir\nend\n\n-- check for CUDA\nfunction _check_cuda(target)\n    local cuda\n    for _, targetinfo in ipairs(target.info) do\n        if targetinfo.sourcekinds and table.contains(targetinfo.sourcekinds, \"cu\") then\n            cuda = find_cuda()\n            break\n        end\n    end\n    if cuda then\n        if cuda.msbuildextensionsdir and cuda.version and os.isfile(path.join(cuda.msbuildextensionsdir, format(\"CUDA %s.props\", cuda.version))) then\n            return cuda\n        else\n            os.raise(\"The Visual Studio Integration for CUDA %s is not found. Please check your CUDA installation.\", cuda.version)\n        end\n    end\nend\n\n-- get toolset version\nfunction _get_toolset_ver(targetinfo, vsinfo)\n    -- get toolset version from vs version\n    local vs_toolset = toolchain.load(\"msvc\"):config(\"vs_toolset\") or config.get(\"vs_toolset\")\n    local toolset_ver = toolchain_utils.get_vs_toolset_ver(vs_toolset)\n    if not toolset_ver then\n        toolset_ver = vsinfo.toolset_version\n    end\n    return toolset_ver\nend\n\n-- get platform sdk version from vcvars.WindowsSDKVersion\nfunction _get_platform_sdkver(target, vsinfo)\n    local sdkver = nil\n    for _, targetinfo in ipairs(target.info) do\n        sdkver = targetinfo.sdkver\n        if sdkver then\n            break\n        end\n    end\n    return sdkver or vsinfo.sdk_version\nend\n\n-- combine two successive flags\nfunction _combine_flags(flags, patterns)\n    local newflags = {}\n    local temparg\n    for _, arg in ipairs(flags) do\n        if temparg then\n            table.insert(newflags, temparg .. \" \" .. arg)\n            temparg = nil\n        else\n            for _, pattern in ipairs(patterns) do\n                if arg:match(pattern) then\n                    temparg = arg\n                end\n            end\n            if not temparg then\n                table.insert(newflags, arg)\n            end\n        end\n    end\n    return newflags\nend\n\n-- exclude patterns from flags\nfunction _exclude_flags(flags, excludes)\n    local newflags = {}\n    for _, flag in ipairs(flags) do\n        local excluded = false\n        for _, exclude in ipairs(excludes) do\n            if flag:find(\"^[%-/]\" .. exclude) then\n                excluded = true\n                break\n            end\n        end\n        if not excluded then\n            table.insert(newflags, vsutils.escape(flag))\n        end\n    end\n    return newflags\nend\n\n-- try split from nvcc -code flag\n--   e.g. nvcc -arch=compute_86 -code=\\\"sm_86,compute_86\\\"\n--        nvcc -gencode arch=compute_86,code=[sm_86,compute_86]\nfunction _split_gpucodes(flag)\n    flag = flag:gsub(\"[%[\\\"]?(.-)[%]\\\"]?\", \"%1\")\n    return flag:split(\",\")\nend\n\n-- make compiling command\nfunction _make_compcmd(compargv, sourcefile, objectfile, vcxprojdir)\n    local argv = {}\n    for i, v in ipairs(compargv) do\n        if i == 1 then\n            v = path.filename(v) -- C:\\xxx\\ml.exe -> ml.exe\n        end\n        v = v:gsub(\"__sourcefile__\", sourcefile)\n        v = v:gsub(\"__objectfile__\", objectfile)\n\n        -- -Idir or /Idir\n        -- handle external includes as well\n        for _, pattern in ipairs({\"[%-/](I)(.*)\", \"[%-/](external:I)(.*)\"}) do\n            v = v:gsub(pattern, function (flag, dir)\n                dir = _make_dirs(dir, vcxprojdir)\n                return \"/\" .. flag .. dir\n            end)\n        end\n\n        table.insert(argv, v)\n    end\n    return table.concat(argv, \" \")\nend\n\n-- make compiling flags\nfunction _make_compflags(sourcefile, targetinfo, vcxprojdir)\n\n    -- translate path for -Idir or /Idir\n    local flags = {}\n    for _, flag in ipairs(targetinfo.compflags[sourcefile]) do\n        for _, pattern in ipairs({\"[%-/](I)(.*)\", \"[%-/](external:I)(.*)\"}) do\n\n            -- -Idir or /Idir\n            flag = flag:gsub(pattern, function (flag, dir)\n                dir = _make_dirs(dir, vcxprojdir)\n                return \"/\" .. flag .. dir\n            end)\n        end\n        table.insert(flags, flag)\n    end\n\n    -- add -D__config_$(mode)__ and -D__config_$(arch)__ for the config header\n    table.insert(flags, \"-D__config_\" .. targetinfo.mode .. \"__\")\n    table.insert(flags, \"-D__config_\" .. targetinfo.arch .. \"__\")\n    return flags\nend\n\n-- make linking flags\nfunction _make_linkflags(targetinfo, vcxprojdir)\n\n    -- replace -libpath:dir or /libpath:dir\n    local flags = {}\n    for _, flag in ipairs(targetinfo.linkflags) do\n\n        -- replace -libpath:dir or /libpath:dir\n        flag = flag:gsub(string.ipattern(\"[%-/]libpath:(.*)\"), function (dir)\n            dir = _make_dirs(dir, vcxprojdir)\n            return \"/libpath:\" .. dir\n        end)\n\n        -- replace -def:dir or /def:dir\n        flag = flag:gsub(string.ipattern(\"[%-/]def:(.*)\"), function (dir)\n            dir = _make_dirs(dir, vcxprojdir)\n            return \"/def:\" .. dir\n        end)\n\n        -- save flag\n        table.insert(flags, flag)\n    end\n\n    -- ok?\n    return flags\nend\n\n-- make header\nfunction _make_header(vcxprojfile, vsinfo)\n    vcxprojfile:print(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\")\n    vcxprojfile:enter(\"<Project DefaultTargets=\\\"Build\\\" ToolsVersion=\\\"%s.0\\\" xmlns=\\\"http://schemas.microsoft.com/developer/msbuild/2003\\\">\", assert(vsinfo.project_version))\nend\n\n-- make references\nfunction _make_references(vcxprojfile, vsinfo, target)\n    vcxprojfile:print(\"<ItemGroup>\")\n    for dep_name, dep_vcxprojfile in pairs(target.deps) do\n        vcxprojfile:print(\"<ProjectReference Include=\\\"%s\\\">\", dep_vcxprojfile)\n            vcxprojfile:print(\"<Project>{%s}</Project>\", hash.uuid4(dep_name))\n        vcxprojfile:print(\"</ProjectReference>\")\n    end\n    vcxprojfile:print(\"</ItemGroup>\")\nend\n\n-- make tailer\nfunction _make_tailer(vcxprojfile, vsinfo, target)\n    vcxprojfile:print(\"<Import Project=\\\"%$(VCTargetsPath)\\\\Microsoft.Cpp.targets\\\" />\")\n    vcxprojfile:enter(\"<ImportGroup Label=\\\"ExtensionTargets\\\">\")\n    local cuda = _check_cuda(target)\n    if cuda then\n        vcxprojfile:print(\"<Import Project=\\\"%s\\\" />\", path.join(cuda.msbuildextensionsdir, format(\"CUDA %s.targets\", cuda.version)))\n    end\n    vcxprojfile:leave(\"</ImportGroup>\")\n    vcxprojfile:leave(\"</Project>\")\nend\n\n-- make Configurations\nfunction _make_configurations(vcxprojfile, vsinfo, target)\n\n    -- the target name\n    local targetname = target.name\n\n    -- init configuration type\n    local configuration_types =\n    {\n        binary = \"Application\"\n    ,   shared = \"DynamicLibrary\"\n    ,   static = \"StaticLibrary\"\n    ,   moduleonly = \"StaticLibrary\" -- emulate moduleonly with staticlib\n    }\n\n    -- make ProjectConfigurations\n    vcxprojfile:enter(\"<ItemGroup Label=\\\"ProjectConfigurations\\\">\")\n    for _, targetinfo in ipairs(target.info) do\n        vcxprojfile:enter(\"<ProjectConfiguration Include=\\\"%s|%s\\\">\", targetinfo.mode, targetinfo.arch)\n            vcxprojfile:print(\"<Configuration>%s</Configuration>\", targetinfo.mode)\n            vcxprojfile:print(\"<Platform>%s</Platform>\", targetinfo.arch)\n        vcxprojfile:leave(\"</ProjectConfiguration>\")\n    end\n    vcxprojfile:leave(\"</ItemGroup>\")\n\n    -- make Globals\n    vcxprojfile:enter(\"<PropertyGroup Label=\\\"Globals\\\">\")\n        vcxprojfile:print(\"<ProjectGuid>{%s}</ProjectGuid>\", hash.uuid4(targetname))\n        vcxprojfile:print(\"<RootNamespace>%s</RootNamespace>\", targetname)\n        if vsinfo.vstudio_version >= \"2015\" then\n            vcxprojfile:print(\"<WindowsTargetPlatformVersion>%s</WindowsTargetPlatformVersion>\", _get_platform_sdkver(target, vsinfo))\n        end\n    vcxprojfile:leave(\"</PropertyGroup>\")\n\n    -- import Microsoft.Cpp.Default.props\n    vcxprojfile:print(\"<Import Project=\\\"%$(VCTargetsPath)\\\\Microsoft.Cpp.Default.props\\\" />\")\n\n    -- make Configuration\n    for _, targetinfo in ipairs(target.info) do\n        vcxprojfile:enter(\"<PropertyGroup Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\" Label=\\\"Configuration\\\">\", targetinfo.mode, targetinfo.arch)\n            vcxprojfile:print(\"<ConfigurationType>%s</ConfigurationType>\", configuration_types[target.kind] or \"Unknown\")\n            vcxprojfile:print(\"<PlatformToolset>%s</PlatformToolset>\", _get_toolset_ver(targetinfo, vsinfo))\n            vcxprojfile:print(\"<CharacterSet>%s</CharacterSet>\", targetinfo.unicode and \"Unicode\" or \"MultiByte\")\n            if targetinfo.usemfc then\n                vcxprojfile:print(\"<UseOfMfc>%s</UseOfMfc>\", targetinfo.usemfc)\n            end\n        vcxprojfile:leave(\"</PropertyGroup>\")\n    end\n\n    -- import Microsoft.Cpp.props\n    vcxprojfile:print(\"<Import Project=\\\"%$(VCTargetsPath)\\\\Microsoft.Cpp.props\\\" />\")\n\n    -- make ExtensionSettings\n    vcxprojfile:enter(\"<ImportGroup Label=\\\"ExtensionSettings\\\">\")\n    local cuda = _check_cuda(target)\n    if cuda then\n        vcxprojfile:print(\"<Import Project=\\\"%s\\\" />\", path.join(cuda.msbuildextensionsdir, format(\"CUDA %s.props\", cuda.version)))\n    end\n    vcxprojfile:leave(\"</ImportGroup>\")\n\n    -- make PropertySheets\n    for _, targetinfo in ipairs(target.info) do\n        vcxprojfile:enter(\"<ImportGroup Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\" Label=\\\"PropertySheets\\\">\", targetinfo.mode, targetinfo.arch)\n            vcxprojfile:print(\"<Import Project=\\\"%$(UserRootDir)\\\\Microsoft.Cpp.%$(Platform).user.props\\\" Condition=\\\"exists(\\'%$(UserRootDir)\\\\Microsoft.Cpp.%$(Platform).user.props\\')\\\" Label=\\\"LocalAppDataPlatform\\\" />\")\n        vcxprojfile:leave(\"</ImportGroup>\")\n    end\n\n    -- make UserMacros\n    vcxprojfile:print(\"<PropertyGroup Label=\\\"UserMacros\\\" />\")\n    if not configuration_types[target.kind] then\n        return\n    end\n\n    -- make OutputDirectory and IntermediateDirectory\n    for _, targetinfo in ipairs(target.info) do\n        vcxprojfile:enter(\"<PropertyGroup Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">\", targetinfo.mode, targetinfo.arch)\n            vcxprojfile:print(\"<OutDir>%s\\\\</OutDir>\", _make_dirs(targetinfo.targetdir, target.project_dir))\n            vcxprojfile:print(\"<IntDir>%s\\\\</IntDir>\", _make_dirs(targetinfo.objectdir, target.project_dir))\n            if targetinfo.targetfile then \n                vcxprojfile:print(\"<TargetName>%s</TargetName>\", path.basename(targetinfo.targetfile))\n                vcxprojfile:print(\"<TargetExt>%s</TargetExt>\", path.extension(targetinfo.targetfile))\n            end\n\n            if target.kind == \"binary\" then\n                vcxprojfile:print(\"<LinkIncremental>true</LinkIncremental>\")\n            end\n\n            if targetinfo.manifest_embed ~= nil then\n                vcxprojfile:print(\"<EmbedManifest>%s</EmbedManifest>\", targetinfo.manifest_embed)\n            end\n\n            -- handle ExternalIncludePath (should we handle IncludePath here too?)\n            local externaldirs = {}\n            for _, flag in ipairs(targetinfo.commonflags.cl) do\n                flag:gsub(\"[%-/]external:I(.*)\", function (dir) table.insert(externaldirs, dir) end)\n            end\n            if #externaldirs > 0 then\n                vcxprojfile:print(\"<ExternalIncludePath>%s;$(VC_IncludePath);$(WindowsSDK_IncludePath);</ExternalIncludePath>\", table.concat(externaldirs, \";\"))\n            end\n        vcxprojfile:leave(\"</PropertyGroup>\")\n    end\n\n    -- make Debugger\n    for _, targetinfo in ipairs(target.info) do\n        vcxprojfile:enter(\"<PropertyGroup Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\" Label=\\\"Debugger\\\">\", targetinfo.mode, targetinfo.arch)\n            vcxprojfile:print(\"<LocalDebuggerWorkingDirectory>%s</LocalDebuggerWorkingDirectory>\", _make_dirs(targetinfo.rundir, target.project_dir))\n            -- @note we use writef to avoid escape $() in runenvs, e.g. $([System.Environment]::Get ..)\n            vcxprojfile:writef(\"<LocalDebuggerEnvironment>%s;%%(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>\\n\", targetinfo.runenvs)\n        vcxprojfile:leave(\"</PropertyGroup>\")\n    end\nend\n\n-- make source options for cl\nfunction _make_source_options_cl(vcxprojfile, flags, condition)\n\n    -- exists condition?\n    condition = condition or \"\"\n\n    -- get flags string\n    local flagstr = os.args(flags)\n\n    -- make Optimization\n    if flagstr:find(\"[%-/]Os\") or flagstr:find(\"[%-/]O1\") then\n        vcxprojfile:print(\"<Optimization%s>MinSpace</Optimization>\", condition)\n    elseif flagstr:find(\"[%-/]O2\") or flagstr:find(\"[%-/]Ot\") then\n        vcxprojfile:print(\"<Optimization%s>MaxSpeed</Optimization>\", condition)\n    elseif flagstr:find(\"[%-/]Ox\") then\n        vcxprojfile:print(\"<Optimization%s>Full</Optimization>\", condition)\n    else\n        vcxprojfile:print(\"<Optimization%s>Disabled</Optimization>\", condition)\n    end\n\n    -- make FloatingPointModel\n    if flagstr:find(\"[%-/]fp:fast\") then\n        vcxprojfile:print(\"<FloatingPointModel%s>Fast</FloatingPointModel>\", condition)\n    elseif flagstr:find(\"[%-/]fp:strict\") then\n        vcxprojfile:print(\"<FloatingPointModel%s>Strict</FloatingPointModel>\", condition)\n    elseif flagstr:find(\"[%-/]fp:precise\") then\n        vcxprojfile:print(\"<FloatingPointModel%s>Precise</FloatingPointModel>\", condition)\n    end\n\n    -- make WarningLevel\n    if flagstr:find(\"[%-/]W1\") then\n        vcxprojfile:print(\"<WarningLevel%s>Level1</WarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]W2\") then\n        vcxprojfile:print(\"<WarningLevel%s>Level2</WarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]W3\") then\n        vcxprojfile:print(\"<WarningLevel%s>Level3</WarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]W4\") then\n        vcxprojfile:print(\"<WarningLevel%s>Level4</WarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]Wall\") then\n        vcxprojfile:print(\"<WarningLevel%s>EnableAllWarnings</WarningLevel>\", condition)\n    else\n        vcxprojfile:print(\"<WarningLevel%s>TurnOffAllWarnings</WarningLevel>\", condition)\n    end\n    if flagstr:find(\"[%-/]WX\") then\n        vcxprojfile:print(\"<TreatWarningAsError%s>true</TreatWarningAsError>\", condition)\n    end\n\n    -- make ExternalWarningLevel\n    if flagstr:find(\"[%-/]external:W1\") then\n        vcxprojfile:print(\"<ExternalWarningLevel%s>Level1</ExternalWarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]external:W2\") then\n        vcxprojfile:print(\"<ExternalWarningLevel%s>Level2</ExternalWarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]external:W3\") then\n        vcxprojfile:print(\"<ExternalWarningLevel%s>Level3</ExternalWarningLevel>\", condition)\n    elseif flagstr:find(\"[%-/]external:W4\") then\n        vcxprojfile:print(\"<ExternalWarningLevel%s>Level4</ExternalWarningLevel>\", condition)\n    else\n        vcxprojfile:print(\"<ExternalWarningLevel%s>TurnOffAllWarnings</ExternalWarningLevel>\", condition)\n    end\n\n    -- make ExternalTemplatesDiagnostics\n    if flagstr:find(\"[%-/]external:templates%-\") then\n        vcxprojfile:print(\"<ExternalTemplatesDiagnostics%s>true</ExternalTemplatesDiagnostics>\", condition)\n    else\n        vcxprojfile:print(\"<ExternalTemplatesDiagnostics%s>false</ExternalTemplatesDiagnostics>\", condition)\n    end\n\n    -- make DisableSpecificWarnings\n    local disabledwarnings = {}\n    for _, flag in ipairs(flags) do\n        flag:gsub(\"[%-/]wd(%d+)\", function (warn) table.insert(disabledwarnings, warn) end)\n    end\n    if #disabledwarnings > 0 then\n        vcxprojfile:print(\"<DisableSpecificWarnings>%s;%%(DisableSpecificWarnings)</DisableSpecificWarnings>\", table.concat(disabledwarnings, \";\"))\n    end\n\n    -- make PreprocessorDefinitions\n    local defstr = \"\"\n    for _, flag in ipairs(flags) do\n        flag:gsub(\"^[%-/]D(.*)\",\n            function (def)\n                defstr = defstr .. vsutils.escape(def) .. \";\"\n            end\n        )\n    end\n    defstr = defstr .. \"%%(PreprocessorDefinitions)\"\n    vcxprojfile:print(\"<PreprocessorDefinitions%s>%s</PreprocessorDefinitions>\", condition, defstr)\n\n    -- make DebugInformationFormat\n    if flagstr:find(\"[%-/]Zi\") then\n        vcxprojfile:print(\"<DebugInformationFormat%s>ProgramDatabase</DebugInformationFormat>\", condition)\n    elseif flagstr:find(\"[%-/]ZI\") then\n        vcxprojfile:print(\"<DebugInformationFormat%s>EditAndContinue</DebugInformationFormat>\", condition)\n    elseif flagstr:find(\"[%-/]Z7\") then\n        vcxprojfile:print(\"<DebugInformationFormat%s>OldStyle</DebugInformationFormat>\", condition)\n    else\n        vcxprojfile:print(\"<DebugInformationFormat%s>None</DebugInformationFormat>\", condition)\n    end\n\n    -- make RuntimeLibrary\n    if flagstr:find(\"[%-/]MDd\") then\n        vcxprojfile:print(\"<RuntimeLibrary%s>MultiThreadedDebugDLL</RuntimeLibrary>\", condition)\n    elseif flagstr:find(\"[%-/]MD\") then\n        vcxprojfile:print(\"<RuntimeLibrary%s>MultiThreadedDLL</RuntimeLibrary>\", condition)\n    elseif flagstr:find(\"[%-/]MTd\") then\n        vcxprojfile:print(\"<RuntimeLibrary%s>MultiThreadedDebug</RuntimeLibrary>\", condition)\n    else\n        vcxprojfile:print(\"<RuntimeLibrary%s>MultiThreaded</RuntimeLibrary>\", condition)\n    end\n\n    -- make RuntimeTypeInfo\n    if flagstr:find(\"[%-/]GR%-\") then\n        vcxprojfile:print(\"<RuntimeTypeInfo%s>false</RuntimeTypeInfo>\", condition)\n    elseif flagstr:find(\"[%-/]GR\") then\n        vcxprojfile:print(\"<RuntimeTypeInfo%s>true</RuntimeTypeInfo>\", condition)\n    end\n\n    -- handle multi processor compilation\n    if flagstr:find(\"[%-/]Gm%-\") or not flagstr:find(\"[%-/]Gm\") then\n        vcxprojfile:print(\"<MinimalRebuild%s>false</MinimalRebuild>\", condition)\n        if not flagstr:find(\"[%-/]MP1\") then\n            vcxprojfile:print(\"<MultiProcessorCompilation%s>true</MultiProcessorCompilation>\", condition)\n        end\n    end\n\n    -- make AdditionalIncludeDirectories\n    if flagstr:find(\"[%-/]I\") then\n        local dirs = {}\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"^[%-/]I(.*)\", function (dir) table.insert(dirs, vsutils.escape(dir)) end)\n        end\n        if #dirs > 0 then\n            vcxprojfile:print(\"<AdditionalIncludeDirectories%s>%s</AdditionalIncludeDirectories>\", condition, table.concat(dirs, \";\"))\n        end\n    end\n\n    -- compile as c++ if exists flag: /TP\n    if flagstr:find(\"[%-/]TP\") then\n        vcxprojfile:print(\"<CompileAs%s>CompileAsCpp</CompileAs>\", condition)\n    end\n\n\n    -- make SDLCheck flag: /sdl\n    if flagstr:find(\"[%-/]sdl\") then\n        if flagstr:find(\"[%-/]sdl%-\") then\n            vcxprojfile:print(\"<SDLCheck%s>false</SDLCheck>\", condition)\n        else\n            vcxprojfile:print(\"<SDLCheck%s>true</SDLCheck>\", condition)\n        end\n    end\n\n    -- make RemoveUnreferencedCodeData flag: Zc:inline\n    if flagstr:find(\"[%-/]Zc:inline\") then\n        if flagstr:find(\"[%-/]Zc:inline%-\") then\n            vcxprojfile:print(\"<RemoveUnreferencedCodeData%s>false</RemoveUnreferencedCodeData>\", condition)\n        else\n            vcxprojfile:print(\"<RemoveUnreferencedCodeData%s>true</RemoveUnreferencedCodeData>\", condition)\n        end\n    end\n\n    -- make ExceptionHandling flag:\n    if flagstr:find(\"[%-/]EH[asc]+%-?\") then\n        local args = flagstr:match(\"[%-/]EH([asc]+%-?)\")\n        -- remove the last arg if flag endwith `-`\n        if args and args:endswith(\"-\") then\n            args = args:sub(1, -2)\n        end\n        if args and args:find(\"a\", 1, true) then\n            -- a will overwrite s and c\n            vcxprojfile:print(\"<ExceptionHandling%s>Async</ExceptionHandling>\", condition)\n        elseif args == \"sc\" or args == \"cs\" then\n            vcxprojfile:print(\"<ExceptionHandling%s>Sync</ExceptionHandling>\", condition)\n        elseif args == \"s\" then\n            vcxprojfile:print(\"<ExceptionHandling%s>SyncCThrow</ExceptionHandling>\", condition)\n        else\n            -- if args == \"c\"\n            -- c is ignored without s or a, do nothing here\n        end\n    end\n\n    -- make AdditionalOptions\n    local excludes = {\n        \"Od\", \"Os\", \"O0\", \"O1\", \"O2\", \"Ot\", \"Ox\", \"W0\", \"W1\", \"W2\", \"W3\", \"W4\", \"WX\", \"Wall\", \"Zi\", \"ZI\", \"Z7\", \"MT\", \"MTd\", \"MD\", \"MDd\", \"TP\",\n        \"Fd\", \"fp\", \"I\", \"D\", \"Gm%-\", \"Gm\", \"GR%-\", \"GR\", \"MP\", \"external:W0\", \"external:W1\", \"external:W2\", \"external:W3\", \"external:W4\", \"external:templates%-?\", \"external:I\",\n        \"std:c11\", \"std:c17\", \"std:c%+%+11\", \"std:c%+%+14\", \"std:c%+%+17\", \"std:c%+%+20\", \"std:c%+%+latest\", \"nologo\", \"wd(%d+)\", \"sdl%-?\", \"Zc:inline%-?\", \"EH[asc]+%-?\"\n    }\n    local additional_flags = _exclude_flags(flags, excludes)\n    if #additional_flags > 0 then\n        vcxprojfile:print(\"<AdditionalOptions%s>%s %%(AdditionalOptions)</AdditionalOptions>\", condition, os.args(additional_flags))\n    end\nend\n\n-- make source options for cl\nfunction _make_resource_options_cl(vcxprojfile, flags)\n\n    -- get flags string\n    local flagstr = os.args(flags)\n\n    -- make PreprocessorDefinitions\n    local defstr = \"\"\n    for _, flag in ipairs(flags) do\n        flag:gsub(\"^[%-/]D(.*)\",\n            function (def)\n                defstr = defstr .. vsutils.escape(def) .. \";\"\n            end\n        )\n    end\n    defstr = defstr .. \"%%(PreprocessorDefinitions)\"\n    vcxprojfile:print(\"<PreprocessorDefinitions>%s</PreprocessorDefinitions>\", defstr)\n\n    -- make AdditionalIncludeDirectories\n    if flagstr:find(\"[%-/]I\") then\n        local dirs = {}\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"^[%-/]I(.*)\", function (dir) table.insert(dirs, vsutils.escape(dir)) end)\n        end\n        if #dirs > 0 then\n            vcxprojfile:print(\"<AdditionalIncludeDirectories>%s</AdditionalIncludeDirectories>\", table.concat(dirs, \";\"))\n        end\n    end\nend\n\n-- make source options for cuda\nfunction _make_source_options_cuda(vcxprojfile, flags, opt)\n\n    -- exists condition?\n    condition = (opt and opt.condition) or \"\"\n\n    -- combine successive commands\n    flags = _combine_flags(flags, {\"^%-gencode$\", \"^%-arch$\", \"^%-code$\", \"^%-%-machine$\", \"^%-rdc$\", \"^%-cudart$\", \"^%-%-keep%-dir$\"})\n\n    -- get flags string\n    local flagstr = os.args(flags)\n\n    if not (opt and opt.link) then\n\n        -- make Optimization\n        if flagstr:find(\"[%-/]Od\") then\n            vcxprojfile:print(\"<Optimization%s>Od</Optimization>\", condition)\n        elseif flagstr:find(\"[%-/]O1\") then\n            vcxprojfile:print(\"<Optimization%s>O1</Optimization>\", condition)\n        elseif flagstr:find(\"[%-/]O2\") then\n            vcxprojfile:print(\"<Optimization%s>O2</Optimization>\", condition)\n        elseif flagstr:find(\"[%-/]O3\") or flagstr:find(\"[%-/]Ox\") then\n            vcxprojfile:print(\"<Optimization%s>O3</Optimization>\", condition)\n        end\n\n        -- make Warning\n        if flagstr:find(\"[%-/]W[1234]\") then\n            local wlevel = flagstr:match(\"[%-/](W[1234])\")\n            vcxprojfile:print(\"<Warning%s>%s</Warning>\", condition, wlevel)\n        elseif flagstr:find(\"[%-/]Wall\") then\n            vcxprojfile:print(\"<Warning%s>Wall</Warning>\", condition)\n        end\n\n        -- make Defines\n        local defstr = \"\"\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"^[%-/]D(.*)\",\n                function (def)\n                    defstr = defstr .. vsutils.escape(def) .. \";\"\n                end\n            )\n        end\n        defstr = defstr .. \"%%(Defines)\"\n        vcxprojfile:print(\"<Defines%s>%s</Defines>\", condition, defstr)\n\n        -- make Include\n        if flagstr:find(\"[%-/]I\") then\n            local dirs = {}\n            for _, flag in ipairs(flags) do\n                flag:gsub(\"^[%-/]I(.*)\", function (dir) table.insert(dirs, vsutils.escape(dir)) end)\n            end\n            if #dirs > 0 then\n                vcxprojfile:print(\"<Include%s>%s</Include>\", condition, table.concat(dirs, \";\"))\n            end\n        end\n\n    end\n\n    -- make TargetMachinePlatform\n    local machinebitwidth\n    for _, flag in ipairs(flags) do\n        flag:gsub(\"^%-m(.+)\", function (value) machinebitwidth = value end)\n        flag:gsub(\"^%-%-machine[ =](.+)\", function (value) machinebitwidth = value end)\n    end\n    if machinebitwidth and (machinebitwidth == \"32\" or machinebitwidth == \"64\") then\n        vcxprojfile:print(\"<TargetMachinePlatform%s>%s</TargetMachinePlatform>\", condition, machinebitwidth)\n    end\n\n    -- make CodeGeneration\n    local gpucode_patterns = {\n        \"%-gencode[ =]arch=(.+),code=(.+)\",\n        \"%-%-generate%-code[ =]arch=(.+),code=(.+)\",\n        \"%-arch\",\n        \"%-%-gpu%-architecture\",\n        \"%-code\",\n        \"%-%-gpu%-code\"\n    }\n    local has_gpucode = false\n    for _, pattern in ipairs(gpucode_patterns) do\n        if flagstr:find(pattern) then\n            has_gpucode = true\n            break\n        end\n    end\n    if has_gpucode then\n        local arch\n        local codes = {}\n        local gencodes = {}\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"^%-gencode[ =]arch=(.+),code=(.+)$\", function (garch, gcodes)\n                for _, gcode in ipairs(_split_gpucodes(gcodes)) do\n                    table.insert(gencodes, garch .. \",\" .. gcode)\n                end\n            end)\n            flag:gsub(\"^%-%-generate%-code[ =]arch=(.+),code=(.+)\", function (garch, gcodes)\n                for _, gcode in ipairs(_split_gpucodes(gcodes)) do\n                    table.insert(gencodes, garch .. \",\" .. gcode)\n                end\n            end)\n            flag:gsub(\"^%-arch[ =](.+)\", function (garch) arch = garch end)\n            flag:gsub(\"^%-%-gpu%-architecture[ =](.+)\", function (garch) arch = garch end)\n            flag:gsub(\"^%-code[ =](.+)\", function (gcodes) table.join2(codes, _split_gpucodes(gcodes)) end)\n            flag:gsub(\"^%-%-gpu%-code[ =](.+)\", function (gcodes) table.join2(codes, _split_gpucodes(gcodes)) end)\n        end\n        if arch then\n            if #codes == 0 then\n                table.insert(codes, arch)\n                arch = arch:gsub(\"sm\", \"compute\")\n                table.insert(gencodes, arch .. \",\" .. arch)\n            end\n            for _, code in ipairs(codes) do\n                table.insert(gencodes, arch .. \",\" .. code)\n            end\n        end\n        if #gencodes > 0 then\n            gencodes = table.unique(gencodes)\n            vcxprojfile:print(\"<CodeGeneration%s>%s</CodeGeneration>\", condition, table.concat(gencodes, \";\"))\n        end\n    end\n\n    if not (opt and opt.link) then\n\n        -- make CudaRuntime\n        local cudart\n        local cudaruntime = {\n            none = \"None\",\n            static = \"Static\",\n            shared = \"Shared\"\n        }\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"%-cudart[ =](.+)\", function (value) cudart = value end)\n        end\n        if cudart and cudaruntime[cudart] then\n            vcxprojfile:print(\"<CudaRuntime%s>%s</CudaRuntime>\", condition, cudaruntime[cudart])\n        end\n\n        -- handle GPU debug info\n        if flagstr:find(\"%-G\") then\n            vcxprojfile:print(\"<GPUDebugInfo%s>true</GPUDebugInfo>\", condition)\n        end\n\n        -- handle fast math\n        if flagstr:find(\"%-use_fast_math\") then\n            vcxprojfile:print(\"<FastMath%s>true</FastMath>\", condition)\n        end\n\n        -- handle relocatable device code\n        local rdc\n        for _, flag in ipairs(flags) do\n            flag:gsub(\"%-rdc[ =](.+)\", function (value) rdc = value end)\n        end\n        if rdc then\n            vcxprojfile:print(\"<GenerateRelocatableDeviceCode%s>%s</GenerateRelocatableDeviceCode>\", condition, rdc)\n        end\n\n        -- handle keep preprocessed files or directories\n        if flagstr:find(\"%-%-keep\") then\n            vcxprojfile:print(\"<Keep%s>true</Keep>\", condition)\n        end\n        if flagstr:find(\"%-%-keep%-dir\") then\n            local dirs = {}\n            for _, flag in ipairs(flags) do\n                flag:gsub(\"%-%-keep%-dir[ =](.*)\", function (dir) table.insert(dirs, dir) end)\n            end\n            if #dirs > 0 then\n                vcxprojfile:print(\"<KeepDir%s>%s</KeepDir>\", condition, table.concat(dirs, \";\"))\n            end\n        end\n    end\n\n    -- make AdditionalOptions\n    local excludes = {\n        \"Od\", \"O1\", \"O2\", \"O3\", \"Ox\", \"W1\", \"W2\", \"W3\", \"W4\", \"Wall\", \"I\", \"D\", \"L\", \"l\", \"m\", \"%-machine\", \"gencode\", \"arch\", \"code\", \"cudart\", \"G\", \"use_fast_math\", \"rdc\", \"%-keep\", \"%-keep%-dir\"\n    }\n    local additional_flags = _exclude_flags(flags, excludes)\n    if #additional_flags > 0 then\n        vcxprojfile:print(\"<AdditionalOptions%s>%s %%(AdditionalOptions)</AdditionalOptions>\", condition, os.args(additional_flags))\n    end\nend\n\n-- make custom commands item\nfunction _make_custom_commands_item(vcxprojfile, commands, suffix)\n    if suffix == \"after\" or suffix == \"after_link\" then\n        vcxprojfile:print(\"<PostBuildEvent>\")\n    elseif suffix == \"before\" then\n        vcxprojfile:print(\"<PreBuildEvent>\")\n    elseif suffix == \"before_link\" then\n        vcxprojfile:print(\"<PreLinkEvent>\")\n    end\n    vcxprojfile:print(\"<Message></Message>\")\n    local cmdstr = \"setlocal\"\n    for _, command in ipairs(commands) do\n        cmdstr = cmdstr .. \"\\n\" .. command\n        cmdstr = cmdstr .. \"\\nif %errorlevel% neq 0 goto :xmEnd\"\n    end\n    cmdstr = cmdstr .. \"\\n\" .. [[:xmEnd\nendlocal &amp; call :xmErrorLevel %errorlevel% &amp; goto :xmDone\n:xmErrorLevel\nexit /b %1\n:xmDone\nif %errorlevel% neq 0 goto :VCEnd]]\n    vcxprojfile:print(\"<Command>%s</Command>\", cmdstr:replace(\"<\", \" \t&lt;\"):replace(\">\", \"&gt;\"):replace(\"/Fo \", \"/Fo\"))\n    if suffix == \"after\" or suffix == \"after_link\" then\n        vcxprojfile:print(\"</PostBuildEvent>\")\n    elseif suffix == \"before\" then\n        vcxprojfile:print(\"</PreBuildEvent>\")\n    elseif suffix == \"before_link\" then\n        vcxprojfile:print(\"</PreLinkEvent>\")\n    end\nend\n\n-- make custom commands\nfunction _make_custom_commands(vcxprojfile, target)\n    for suffix, cmds in pairs(target.commands) do\n        _make_custom_commands_item(vcxprojfile, cmds, suffix)\n    end\nend\n\n-- make common item\nfunction _make_common_item(vcxprojfile, vsinfo, target, targetinfo)\n    -- init the linker kinds\n    local linkerkinds =\n    {\n        binary = \"Link\"\n    ,   static = \"Lib\"\n    ,   moduleonly = \"Lib\" -- emulate moduleonly with staticlib\n    ,   shared = \"Link\"\n    }\n    if not linkerkinds[targetinfo.targetkind] then\n        return\n    end\n\n    -- enter ItemDefinitionGroup\n    vcxprojfile:enter(\"<ItemDefinitionGroup Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">\", targetinfo.mode, targetinfo.arch)\n\n    -- for linker?\n    vcxprojfile:enter(\"<%s>\", linkerkinds[targetinfo.targetkind])\n\n        -- save subsystem\n        local subsystem = \"Console\"\n\n        -- save profile\n        local profile = false\n\n        -- make linker flags\n        local flags = {}\n        local excludes = {\n            \"nologo\", \"machine:%w+\", \"pdb:.+%.pdb\", \"debug\"\n        }\n        local libdirs = {}\n        local links = {}\n        for _, flag in ipairs(_make_linkflags(targetinfo, target.project_dir)) do\n\n            local flag_lower = flag:lower()\n\n            -- remove \"-subsystem:windows\"\n            if flag_lower:find(\"[%-/]subsystem:windows\") then\n                subsystem = \"Windows\"\n            elseif flag_lower:find(\"[%-/]libpath\") then\n                -- link dir\n                flag:gsub(\"[%-/]libpath:(.*)\", function (dir) table.insert(libdirs, vsutils.escape(dir)) end)\n            elseif flag_lower:find(\"[^%-/].+%.lib\") then\n                -- link file\n                table.insert(links, flag)\n            elseif flag_lower:find(\"[%-/]profile\") then\n                profile = true\n            else\n                local excluded = false\n                for _, exclude in ipairs(excludes) do\n                    if flag:find(\"[%-/]\" .. exclude) then\n                        excluded = true\n                        break\n                    end\n                end\n                if not excluded then\n                    table.insert(flags, flag)\n                end\n            end\n\n        end\n\n        -- make AdditionalLibraryDirectories\n        if #libdirs > 0 then\n            vcxprojfile:print(\"<AdditionalLibraryDirectories>%s;%%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\", table.concat(libdirs, \";\"))\n        end\n\n        -- make AdditionalDependencies\n        if #links > 0 then\n            vcxprojfile:print(\"<AdditionalDependencies>%s;%%(AdditionalDependencies)</AdditionalDependencies>\", table.concat(links, \";\"))\n        end\n\n        -- make AdditionalOptions\n        if #flags > 0 then\n            flags = os.args(flags)\n            vcxprojfile:print(\"<AdditionalOptions>%s %%(AdditionalOptions)</AdditionalOptions>\", vsutils.escape(flags))\n        end\n\n        -- generate debug infomation?\n        if linkerkinds[targetinfo.targetkind] == \"Link\" then\n\n            -- enable profile?\n            vcxprojfile:print(\"<Profile>%s</Profile>\", tostring(profile))\n\n            -- enable debug infomation?\n            local debug = false\n            for _, symbol in ipairs(targetinfo.symbols) do\n                if symbol == \"debug\" then\n                    debug = true\n                    break\n                end\n            end\n            vcxprojfile:print(\"<GenerateDebugInformation>%s</GenerateDebugInformation>\", tostring(debug))\n        end\n\n        -- make SubSystem\n        if targetinfo.targetkind == \"binary\" then\n            vcxprojfile:print(\"<SubSystem>%s</SubSystem>\", subsystem)\n        end\n\n        -- make TargetMachine\n        vcxprojfile:print(\"<TargetMachine>%s</TargetMachine>\", (targetinfo.arch == \"x64\" and \"MachineX64\" or \"MachineX86\"))\n\n\n    vcxprojfile:leave(\"</%s>\", linkerkinds[targetinfo.targetkind])\n\n    -- for C/C++ compiler?\n    vcxprojfile:enter(\"<ClCompile>\")\n\n        -- make source options\n        _make_source_options_cl(vcxprojfile, targetinfo.commonflags.cl)\n\n        -- add c and c++ standard\n        local clangflags = {\n            c11       = \"stdc11\",\n            c17       = \"stdc17\",\n            clatest   = \"stdc17\",\n            gnu11     = \"stdc11\",\n            gnu17     = \"stdc17\",\n            gnulatest = \"stdc17\",\n        }\n\n        local cxxlangflags = {\n            cxx11     = \"stdcpp11\",\n            cxx14     = \"stdcpp14\",\n            cxx17     = \"stdcpp17\",\n            cxx1z     = \"stdcpp17\",\n            cxx20     = \"stdcpp20\",\n            cxx2a     = \"stdcpplatest\",\n            cxx23     = \"stdcpplatest\",\n            cxx2b     = \"stdcpplatest\",\n            cxxlatest = \"stdcpplatest\",\n            gnuxx11   = \"stdcpp11\",\n            gnuxx14   = \"stdcpp14\",\n            gnuxx17   = \"stdcpp17\",\n            gnuxx1z   = \"stdcpp20\",\n            gnux20    = \"stdcpp20\",\n            gnux2a    = \"stdcpplatest\",\n        }\n\n        local cstandard\n        local cxxstandard\n        for _, lang in pairs(targetinfo.languages) do\n            lang = lang:replace(\"c++\", \"cxx\", {plain = true})\n            if cxxlangflags[lang] then\n                cxxstandard = cxxlangflags[lang]\n            elseif clangflags[lang] then\n                cstandard = clangflags[lang]\n            end\n        end\n\n        if cxxstandard then\n            vcxprojfile:print(\"<LanguageStandard>%s</LanguageStandard>\", cxxstandard)\n        end\n\n        if cstandard then\n            vcxprojfile:print(\"<LanguageStandard_C>%s</LanguageStandard_C>\", cstandard)\n        end\n\n        if targetinfo.has_modules then\n            vcxprojfile:enter(\"<ScanSourceForModuleDependencies>true</ScanSourceForModuleDependencies>\")\n        end\n\n        -- use c or c++ precompiled header\n        local pcheader = target.pcxxheader or target.pcheader\n        if pcheader then\n\n            -- make precompiled header and outputfile\n            vcxprojfile:print(\"<PrecompiledHeader>Use</PrecompiledHeader>\")\n            vcxprojfile:print(\"<PrecompiledHeaderFile>%s</PrecompiledHeaderFile>\", vsutils.escape(path.filename(pcheader)))\n            local pcoutputfile = targetinfo.pcxxoutputfile or targetinfo.pcoutputfile\n            if pcoutputfile then\n                vcxprojfile:print(\"<PrecompiledHeaderOutputFile>%s</PrecompiledHeaderOutputFile>\", vsutils.escape(path.relative(path.absolute(pcoutputfile), target.project_dir)))\n            end\n            vcxprojfile:print(\"<ForcedIncludeFiles>%s;%%(ForcedIncludeFiles)</ForcedIncludeFiles>\", vsutils.escape(path.filename(pcheader)))\n        end\n\n    vcxprojfile:leave(\"</ClCompile>\")\n\n    vcxprojfile:enter(\"<ResourceCompile>\")\n        -- make resource options\n        _make_resource_options_cl(vcxprojfile, targetinfo.commonflags.cl)\n\n    vcxprojfile:leave(\"</ResourceCompile>\")\n\n    local cuda = _check_cuda(target)\n    if cuda then\n        -- for CUDA linker?\n        vcxprojfile:enter(\"<CudaLink>\")\n\n        -- make cuda link flags\n        _make_source_options_cuda(vcxprojfile, targetinfo.culinkflags, {link = true})\n\n        -- make devlink\n        if targetinfo.cudevlink then\n            vcxprojfile:print(\"<PerformDeviceLink>%s</PerformDeviceLink>\", targetinfo.cudevlink)\n        end\n\n        vcxprojfile:leave(\"</CudaLink>\")\n\n        -- for CUDA compiler?\n        vcxprojfile:enter(\"<CudaCompile>\")\n\n        -- make source options\n        _make_source_options_cuda(vcxprojfile, targetinfo.commonflags.cuda)\n\n        vcxprojfile:leave(\"</CudaCompile>\")\n    end\n\n    -- make custom commands\n    _make_custom_commands(vcxprojfile, targetinfo)\n\n    -- leave ItemDefinitionGroup\n    vcxprojfile:leave(\"</ItemDefinitionGroup>\")\nend\n\n-- build common items (doesn't print anything)\nfunction _build_common_items(vsinfo, target)\n\n    -- for each mode and arch\n    for _, targetinfo in ipairs(target.info) do\n\n        -- make source flags\n        local flags_stats = {cl = {}, cuda = {}}\n        local files_count = {cl = 0, cuda = 0}\n        local first_flags = {}\n        targetinfo.sourceflags = {}\n        for _, sourcebatch in pairs(targetinfo.sourcebatches) do\n            local sourcekind = sourcebatch.sourcekind\n            local rulename = sourcebatch.rulename\n            if (rulename == \"c.build\" or rulename == \"c++.build\" or rulename == \"c++.build.modules\" or rulename == \"asm.build\" or sourcekind == \"mrc\") then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    -- make compiler flags\n                    local flags = _make_compflags(sourcefile, targetinfo, target.project_dir)\n\n                    -- no common flags for asm/rc\n                    if sourcekind ~= \"as\" and sourcekind ~= \"mrc\" then\n                        for _, flag in ipairs(table.unique(flags)) do\n                            flags_stats.cl[flag] = (flags_stats.cl[flag] or 0) + 1\n                        end\n\n                        -- update files count\n                        files_count.cl = files_count.cl + 1\n\n                        -- save first flags\n                        if first_flags.cl == nil then\n                            first_flags.cl = flags\n                        end\n                    end\n\n                    -- save source flags\n                    targetinfo.sourceflags[sourcefile] = flags\n                end\n            elseif sourcekind == \"cu\" then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n\n                    -- make compiler flags\n                    local flags = _make_compflags(sourcefile, targetinfo, target.project_dir)\n\n                    -- count flags\n                    for _, flag in ipairs(table.unique(flags)) do\n                        flags_stats.cuda[flag] = (flags_stats.cuda[flag] or 0) + 1\n                    end\n\n                    -- update files count\n                    files_count.cuda = files_count.cuda + 1\n\n                    -- save first flags\n                    if first_flags.cuda == nil then\n                        first_flags.cuda = flags\n                    end\n\n                    -- save source flags\n                    targetinfo.sourceflags[sourcefile] = flags\n                end\n            end\n        end\n\n        -- make common flags\n        targetinfo.commonflags = {cl = {}, cuda = {}}\n        for _, comp in ipairs({\"cl\", \"cuda\"}) do\n            for _, flag in ipairs(first_flags[comp]) do\n                if flags_stats[comp][flag] >= files_count[comp] then\n                    table.insert(targetinfo.commonflags[comp], flag)\n                end\n            end\n        end\n\n        -- remove common flags from source flags\n        local sourceflags = {}\n        for _, sourcebatch in pairs(targetinfo.sourcebatches) do\n            local sourcekind = sourcebatch.sourcekind\n            local rulename = sourcebatch.rulename\n            if (sourcekind == \"as\" or sourcekind == \"mrc\") then\n                -- no common flags for as/mrc files\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    sourceflags[sourcefile] = targetinfo.sourceflags[sourcefile]\n                end\n            elseif rulename == \"c.build\" or rulename == \"c++.build\" or rulename == \"c++.build.modules\" then -- sourcekind maybe bind multiple rules, e.g. c++modules\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    local flags = targetinfo.sourceflags[sourcefile]\n                    local otherflags = {}\n                    for _, flag in ipairs(flags) do\n                        if flags_stats.cl[flag] < files_count.cl then\n                            table.insert(otherflags, flag)\n                        end\n                    end\n                    sourceflags[sourcefile] = otherflags\n                end\n            elseif sourcekind == \"cu\" then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    local flags = targetinfo.sourceflags[sourcefile]\n                    local otherflags = {}\n                    for _, flag in ipairs(flags) do\n                        if flags_stats.cuda[flag] < files_count.cuda then\n                            table.insert(otherflags, flag)\n                        end\n                    end\n                    sourceflags[sourcefile] = otherflags\n                end\n            end\n        end\n        targetinfo.sourceflags = sourceflags\n    end\nend\n\n-- make common items\nfunction _make_common_items(vcxprojfile, vsinfo, target)\n\n    -- for each mode and arch\n    for _, targetinfo in ipairs(target.info) do\n        -- make common item\n        _make_common_item(vcxprojfile, vsinfo, target, targetinfo)\n    end\nend\n\n-- make header file\nfunction _make_include_file(vcxprojfile, includefile, vcxprojdir)\n    vcxprojfile:print(\"<ClInclude Include=\\\"%s\\\" />\", path.relative(path.absolute(includefile), vcxprojdir))\nend\n\n-- make source file for all modes\nfunction _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo)\n\n    -- get object file and source kind\n    local sourcekind\n    for _, info in ipairs(sourceinfo) do\n        sourcekind = info.sourcekind\n        break\n    end\n\n    -- enter it\n    local nodename\n    if     sourcekind == \"as\"  then nodename = \"CustomBuild\"\n    elseif sourcekind == \"mrc\" then nodename = \"ResourceCompile\"\n    elseif sourcekind == \"cu\"  then nodename = \"CudaCompile\"\n    elseif sourcekind == \"cc\" or sourcekind == \"cxx\" then nodename = \"ClCompile\"\n    end\n    sourcefile = path.relative(path.absolute(sourcefile), target.project_dir)\n    vcxprojfile:enter(\"<%s Include=\\\"%s\\\">\", nodename, sourcefile)\n\n        -- for *.asm files\n        if sourcekind == \"as\" then\n            vcxprojfile:print(\"<ExcludedFromBuild>false</ExcludedFromBuild>\")\n            vcxprojfile:print(\"<FileType>Document</FileType>\")\n            for _, info in ipairs(sourceinfo) do\n                local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir)\n                local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, target.project_dir)\n                vcxprojfile:print(\"<Outputs Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s\\'\\\">%s</Outputs>\", info.mode .. '|' .. info.arch, objectfile)\n                vcxprojfile:print(\"<Command Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s\\'\\\">%s</Command>\", info.mode .. '|' .. info.arch, compcmd)\n            end\n            vcxprojfile:print(\"<Message>%s</Message>\", path.filename(sourcefile))\n\n        -- for *.rc files\n        elseif sourcekind == \"mrc\" then\n            for _, info in ipairs(sourceinfo) do\n                local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir)\n                vcxprojfile:print(\"<ResourceOutputFileName Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</ResourceOutputFileName>\",\n                    info.mode, info.arch, objectfile)\n            end\n\n        -- for *.c/cpp/cu files\n        else\n\n            -- compile as c++ modules\n            if support.has_module_extension(sourcefile) then\n                vcxprojfile:print(\"<CompileAs>CompileAsCppModule</CompileAs>\")\n            end\n\n            -- we need to use different object directory and allow parallel building\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/2016\n            -- https://github.com/xmake-io/xmake/issues/1062\n            for _, info in ipairs(sourceinfo) do\n                local objectname = path.filename(info.objectfile)\n                local targetinfo = info.targetinfo\n                if not targetinfo.objectnames then\n                    targetinfo.objectnames = hashset:new()\n                end\n                if targetinfo.objectnames:has(objectname) then\n                    local outputnode = (sourcekind == \"cu\" and \"CompileOut\" or \"ObjectFileName\")\n                    local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir)\n                    vcxprojfile:print(\"<%s Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</%s>\",\n                        outputnode, info.mode, info.arch, objectfile, outputnode)\n                else\n                    targetinfo.objectnames:insert(objectname)\n                end\n            end\n\n            -- init items\n            local items =\n            {\n                AdditionalOptions =\n                {\n                    key = function (info) return os.args(info.flags) end\n                ,   value = function (key) return key .. \" %%(AdditionalOptions)\" end\n                }\n            }\n\n            -- make items\n            for itemname, iteminfo in pairs(items) do\n\n                -- make merge keys\n                local mergekeys  = {}\n                for _, info in ipairs(sourceinfo) do\n                    local key = iteminfo.key(info)\n                    mergekeys[key] = mergekeys[key] or {}\n                    mergekeys[key][info.mode .. '|' .. info.arch] = true\n                end\n                for key, mergeinfos in pairs(mergekeys) do\n\n                    -- merge mode and arch first\n                    local count = 0\n                    for _, mode in ipairs(vsinfo.modes) do\n                        if mergeinfos[mode .. \"|Win32\"] and mergeinfos[mode .. \"|x64\"] then\n                            mergeinfos[mode .. \"|Win32\"] = nil\n                            mergeinfos[mode .. \"|x64\"]   = nil\n                            mergeinfos[mode]             = true\n                        end\n                        if mergeinfos[mode] then\n                            count = count + 1\n                        end\n                    end\n\n                    -- disable the precompiled header if sourcekind ~= headerkind\n                    local pcheader = target.pcxxheader or target.pcheader\n                    local pcheader_disable = false\n                    if sourcekind == \"cu\" or (pcheader and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and \"cxx\" or \"cc\")) then\n                        pcheader_disable = true\n                    end\n\n                    -- all modes and archs exist?\n                    if count == #vsinfo.modes then\n                        if #key > 0 then\n                            vcxprojfile:print(\"<%s>%s</%s>\", itemname, iteminfo.value(key), itemname)\n                            if pcheader_disable then\n                                vcxprojfile:print(\"<PrecompiledHeader>NotUsing</PrecompiledHeader>\")\n                            end\n                        end\n                    else\n                        for cond, _ in pairs(mergeinfos) do\n                            if cond:find('|', 1, true) then\n                                -- for mode | arch\n                                if #key > 0 then\n                                    vcxprojfile:print(\"<%s Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s\\'\\\">%s</%s>\", itemname, cond, iteminfo.value(key), itemname)\n                                    if pcheader_disable then\n                                        vcxprojfile:print(\"<PrecompiledHeader Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s\\'\\\">NotUsing</PrecompiledHeader>\", cond)\n                                    end\n                                end\n                            else\n                                -- only for mode\n                                if #key > 0 then\n                                    vcxprojfile:print(\"<%s Condition=\\\"\\'%$(Configuration)\\'==\\'%s\\'\\\">%s</%s>\", itemname, cond, iteminfo.value(key), itemname)\n                                    if pcheader_disable then\n                                        vcxprojfile:print(\"<PrecompiledHeader Condition=\\\"\\'%$(Configuration)\\'==\\'%s\\'\\\">NotUsing</PrecompiledHeader>\", cond)\n                                    end\n                                end\n                            end\n                        end\n                    end\n                end\n            end\n        end\n\n    -- leave it\n    vcxprojfile:leave(\"</%s>\", nodename)\nend\n\n-- make source file for specific modes\nfunction _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo)\n\n    -- add source file\n    sourcefile = path.relative(path.absolute(sourcefile), target.project_dir)\n    for _, info in ipairs(sourceinfo) do\n\n        -- enter it\n        local nodename\n        if     info.sourcekind == \"as\"  then nodename = \"CustomBuild\"\n        elseif info.sourcekind == \"mrc\" then nodename = \"ResourceCompile\"\n        elseif info.sourcekind == \"cu\"  then nodename = \"CudaCompile\"\n        elseif info.sourcekind == \"cc\" or info.sourcekind == \"cxx\" then nodename = \"ClCompile\"\n        end\n        vcxprojfile:enter(\"<%s Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\" Include=\\\"%s\\\">\",\n            nodename, info.mode, info.arch, sourcefile)\n\n        -- for *.asm files\n        local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir)\n        if info.sourcekind == \"as\" then\n            local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, target.project_dir)\n            vcxprojfile:print(\"<ExcludedFromBuild>false</ExcludedFromBuild>\")\n            vcxprojfile:print(\"<FileType>Document</FileType>\")\n            vcxprojfile:print(\"<Outputs>%s</Outputs>\", objectfile)\n            vcxprojfile:print(\"<Command>%s</Command>\", compcmd)\n\n        -- for *.rc files\n        elseif info.sourcekind == \"mrc\" then\n            vcxprojfile:print(\"<ResourceOutputFileName Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</ResourceOutputFileName>\",\n                info.mode, info.arch, objectfile)\n\n        -- for *.c/cpp/cu files\n        else\n            -- compile as c++ modules\n            if support.has_module_extension(sourcefile) then\n                vcxprojfile:print(\"<CompileAs>CompileAsCppModule</CompileAs>\")\n            end\n\n           -- we need to use different object directory and allow parallel building\n            --\n            -- @see https://github.com/xmake-io/xmake/issues/2016\n            -- https://github.com/xmake-io/xmake/issues/1062\n            local objectname = path.filename(objectfile)\n            local targetinfo = info.targetinfo\n            if not targetinfo.objectnames then\n                targetinfo.objectnames = hashset:new()\n            end\n            local targetinfo = info.targetinfo\n            local outputnode = (info.sourcekind == \"cu\" and \"CompileOut\" or \"ObjectFileName\")\n            if targetinfo.objectnames:has(objectname) then\n                vcxprojfile:print(\"<%s Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</%s>\",\n                    outputnode, info.mode, info.arch, objectfile, outputnode)\n            else\n                targetinfo.objectnames:insert(objectname)\n            end\n\n            -- disable the precompiled header if sourcekind ~= headerkind\n            local pcheader = target.pcxxheader or target.pcheader\n            if pcheader and info.sourcekind ~= \"cu\" and language.sourcekind_of(sourcefile) ~= (target.pcxxheader and \"cxx\" or \"cc\") then\n                vcxprojfile:print(\"<PrecompiledHeader>NotUsing</PrecompiledHeader>\")\n            end\n            vcxprojfile:print(\"<AdditionalOptions>%s %%(AdditionalOptions)</AdditionalOptions>\", os.args(info.flags))\n        end\n\n        -- leave it\n        vcxprojfile:leave(\"</%s>\", nodename)\n    end\nend\n\n-- make source file for precompiled header\nfunction _make_source_file_forpch(vcxprojfile, vsinfo, target)\n\n    -- add precompiled source file\n    local pcheader = target.pcxxheader or target.pcheader\n    if pcheader then\n        local sourcefile = path.relative(path.absolute(pcheader), target.project_dir)\n        vcxprojfile:enter(\"<ClCompile Include=\\\"%s\\\">\", sourcefile)\n            vcxprojfile:print(\"<PrecompiledHeader>Create</PrecompiledHeader>\")\n            vcxprojfile:print(\"<PrecompiledHeaderFile></PrecompiledHeaderFile>\")\n            vcxprojfile:print(\"<AdditionalOptions> %%(AdditionalOptions)</AdditionalOptions>\")\n            for _, info in ipairs(target.info) do\n\n                -- compile as c/c++\n                local compileas = (target.pcxxheader and \"CompileAsCpp\" or \"CompileAsC\")\n                vcxprojfile:print(\"<CompileAs Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</CompileAs>\", info.mode, info.arch, compileas)\n\n                -- add object file\n                local pcoutputfile = info.pcxxoutputfile or info.pcoutputfile\n                if pcoutputfile then\n                    local objectfile = path.relative(path.absolute(pcoutputfile .. \".obj\"), target.project_dir)\n                    vcxprojfile:print(\"<ObjectFileName Condition=\\\"\\'%$(Configuration)|%$(Platform)\\'==\\'%s|%s\\'\\\">%s</ObjectFileName>\", info.mode, info.arch, objectfile)\n                end\n            end\n        vcxprojfile:leave(\"</ClCompile>\")\n    end\nend\n\n-- make source files\nfunction _make_source_files(vcxprojfile, vsinfo, target)\n\n    -- add source files\n    vcxprojfile:enter(\"<ItemGroup>\")\n\n        -- make source file infos\n        local sourceinfos = {}\n        for _, targetinfo in ipairs(target.info) do\n            for _, sourcebatch in pairs(targetinfo.sourcebatches) do\n                local sourcekind = sourcebatch.sourcekind\n                local rulename = sourcebatch.rulename\n                if (rulename == \"c.build\" or rulename == \"c++.build\" or sourcekind == \"as\" or sourcekind == \"mrc\" or sourcekind == \"cu\") then\n                    local objectfiles = sourcebatch.objectfiles\n                    for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                        local objectfile    = objectfiles[idx]\n                        local flags         = targetinfo.sourceflags[sourcefile]\n                        sourceinfos[sourcefile] = sourceinfos[sourcefile] or {}\n                        table.insert(sourceinfos[sourcefile], {targetinfo = targetinfo, mode = targetinfo.mode, arch = targetinfo.arch, sourcekind = sourcekind, objectfile = objectfile, flags = flags, compargv = targetinfo.compargvs[sourcefile]})\n                    end\n                elseif rulename == \"c++.build.modules\" then\n                    local builder_batch = targetinfo.sourcebatches[\"c++.build.modules.builder\"]\n                    table.sort(builder_batch.objectfiles)\n                    local objectfiles = builder_batch.objectfiles\n                    for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                        local is_named_module = table.contains(builder_batch.sourcefiles, sourcefile)\n                        if is_named_module then\n                            local objectfile    = objectfiles[idx]\n                            local flags         = targetinfo.sourceflags[sourcefile]\n                            sourceinfos[sourcefile] = sourceinfos[sourcefile] or {}\n                            table.insert(sourceinfos[sourcefile], {targetinfo = targetinfo, mode = targetinfo.mode, arch = targetinfo.arch, sourcekind = \"cxx\", objectfile = objectfile, flags = flags, compargv = targetinfo.compargvs[sourcefile]})\n                        end\n                    end\n                end\n            end\n        end\n\n        -- make source files\n        for sourcefile, sourceinfo in table.orderpairs(sourceinfos) do\n            if #sourceinfo == #target.info then\n                _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo)\n            else\n                _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo)\n            end\n        end\n\n        -- make precompiled source file\n        _make_source_file_forpch(vcxprojfile, vsinfo, target)\n\n    vcxprojfile:leave(\"</ItemGroup>\")\n\n    -- add include files\n    local pcheader = target.pcxxheader or target.pcheader\n    vcxprojfile:enter(\"<ItemGroup>\")\n        for _, includefile in ipairs(table.join(target.headerfiles or {}, target.extrafiles)) do\n            -- we need to ignore pcheader file to fix https://github.com/xmake-io/xmake/issues/1171\n            if not pcheader or includefile ~= pcheader then\n                _make_include_file(vcxprojfile, includefile, target.project_dir)\n            end\n        end\n    vcxprojfile:leave(\"</ItemGroup>\")\nend\n\n-- make vcxproj\nfunction make(vsinfo, target)\n\n    -- the target name\n    local targetname = target.name\n\n    -- the vcxproj directory\n    local vcxprojdir = target.project_dir\n\n    -- build common flags\n    _build_common_items(vsinfo, target)\n\n    -- open vcxproj file\n    local vcxprojpath = path.join(vcxprojdir, targetname .. \".vcxproj\")\n    local vcxprojfile = vsfile.open(vcxprojpath, \"w\")\n\n    -- init indent character\n    vsfile.indentchar('  ')\n\n    -- make header\n    _make_header(vcxprojfile, vsinfo)\n\n    -- make Configurations\n    _make_configurations(vcxprojfile, vsinfo, target)\n\n    -- make common items\n    _make_common_items(vcxprojfile, vsinfo, target)\n\n    -- make source files\n    _make_source_files(vcxprojfile, vsinfo, target)\n\n    -- make deps references\n    _make_references(vcxprojfile, vsinfo, target)\n\n    -- make tailer\n    _make_tailer(vcxprojfile, vsinfo, target)\n\n    -- exit solution file\n    vcxprojfile:close()\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed to the Apache Software Foundation (ASF) under one\n-- or more contributor license agreements.  See the NOTICE file\n-- distributed with this work for additional information\n-- regarding copyright ownership.  The ASF licenses this file\n-- to you under the Apache License, Version 2.0 (the\n-- \"License\"); you may not use this file except in compliance\n-- with the License.  You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      EnoroF, ruki\n-- @file        vs201x_vcxproj_filters.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"vsfile\")\n\n-- make header\nfunction _make_header(filtersfile, vsinfo)\n\n    -- the versions\n    local versions =\n    {\n        vs2010 = '10.0'\n    ,   vs2012 = '11.0'\n    ,   vs2013 = '12.0'\n    ,   vs2015 = '14.0'\n    ,   vs2017 = '15.0'\n    ,   vs2019 = '16.0'\n    ,   vs2022 = '17.0'\n    }\n\n    -- make header\n    filtersfile:print(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\")\n    filtersfile:enter(\"<Project ToolsVersion=\\\"%s\\\" xmlns=\\\"http://schemas.microsoft.com/developer/msbuild/2003\\\">\", vsinfo.filters_version or versions[vsinfo.vstudio_version])\nend\n\n-- make tailer\nfunction _make_tailer(filtersfile, vsinfo)\n    filtersfile:leave(\"</Project>\")\nend\n\n-- strip dot directories, e.g. ..\\..\\.. => ..\n-- @see https://github.com/xmake-io/xmake/issues/2039\nfunction _strip_dotdirs(dir)\n    local count\n    dir, count = dir:gsub(\"%.%.[\\\\/]%.%.\", \"..\")\n    if count > 0 then\n        dir = _strip_dotdirs(dir)\n    end\n    return dir\nend\n\n-- make filter\nfunction _make_filter(filepath, target, vcxprojdir)\n    local filter\n    local is_plain = false\n    local filegroups = target.filegroups\n    if filegroups then\n        -- @see https://github.com/xmake-io/xmake/issues/2282\n        filepath = path.absolute(filepath)\n        local scriptdir = target.scriptdir\n        local filegroups_extraconf = target.filegroups_extraconf or {}\n        for _, filegroup in ipairs(filegroups) do\n            local extraconf = filegroups_extraconf[filegroup] or {}\n            local rootdir = extraconf.rootdir\n            assert(rootdir, \"please set root directory, e.g. add_filegroups(%s, {rootdir = 'xxx'})\", filegroup)\n            for _, rootdir in ipairs(table.wrap(rootdir)) do\n                if not path.is_absolute(rootdir) then\n                    rootdir = path.absolute(rootdir, scriptdir)\n                end\n                local fileitem = path.relative(filepath, rootdir)\n                local files = extraconf.files or \"**\"\n                local mode = extraconf.mode\n                for _, filepattern in ipairs(files) do\n                    filepattern = path.pattern(path.absolute(path.join(rootdir, filepattern)))\n                    if filepath:match(filepattern) then\n                        if mode == \"plain\" then\n                            filter = path.normalize(filegroup)\n                            is_plain = true\n                        else\n                            -- file tree mode (default)\n                            if filegroup ~= \"\" then\n                                filter = path.normalize(path.join(filegroup, path.directory(fileitem)))\n                            else\n                                filter = path.normalize(path.directory(fileitem))\n                            end\n                        end\n                        goto found_filter\n                    end\n                end\n                -- stop once a rootdir matches\n                if filter then\n                    goto found_filter\n                end\n            end\n            ::found_filter::\n        end\n    end\n    if not filter and not is_plain then\n        -- use the default filter rule\n        filter = path.relative(path.absolute(path.directory(filepath)), target.scriptdir or vcxprojdir)\n        -- @see https://github.com/xmake-io/xmake/issues/2039\n        if filter then\n            filter = _strip_dotdirs(filter)\n        end\n    end\n    if filter and filter == '.' then\n        filter = nil\n    end\n    return filter\nend\n\n-- make filters\nfunction _make_filters(filtersfile, vsinfo, target, vcxprojdir)\n\n    -- add filters\n    filtersfile:enter(\"<ItemGroup>\")\n        local exists = {}\n        for _, filepath in pairs(table.join(target.sourcefiles, target.headerfiles or {}, target.extrafiles)) do\n            local filter = _make_filter(filepath, target, vcxprojdir)\n            while filter and filter ~= '.' do\n                if not exists[filter] then\n                    filtersfile:enter(\"<Filter Include=\\\"%s\\\">\", filter)\n                    filtersfile:print(\"<UniqueIdentifier>{%s}</UniqueIdentifier>\", hash.uuid4(filter))\n                    filtersfile:leave(\"</Filter>\")\n                    exists[filter] = true\n                end\n                filter = path.directory(filter)\n            end\n        end\n    filtersfile:leave(\"</ItemGroup>\")\nend\n\n-- make sources\nfunction _make_sources(filtersfile, vsinfo, target, vcxprojdir)\n\n    -- and sources\n    filtersfile:enter(\"<ItemGroup>\")\n        for _, sourcefile in ipairs(target.sourcefiles) do\n            local filter = _make_filter(sourcefile, target, vcxprojdir)\n            if filter then\n                local nodename\n                local ext = path.extension(sourcefile)\n                if ext == \"asm\" then nodename = \"CustomBuild\"\n                elseif ext == \"cu\" then nodename = \"CudaCompile\"\n                else nodename = \"ClCompile\"\n                end\n                filtersfile:enter(\"<%s Include=\\\"%s\\\">\", nodename, path.relative(path.absolute(sourcefile), vcxprojdir))\n                filtersfile:print(\"<Filter>%s</Filter>\", filter)\n                filtersfile:leave(\"</%s>\", nodename)\n            end\n            local pcheader = target.pcxxheader or target.pcheader\n            if pcheader then\n                local filter = _make_filter(pcheader, target, vcxprojdir)\n                if filter then\n                    filtersfile:enter(\"<ClCompile Include=\\\"%s\\\">\", path.relative(path.absolute(pcheader), vcxprojdir))\n                    filtersfile:print(\"<Filter>%s</Filter>\", filter)\n                    filtersfile:leave(\"</ClCompile>\")\n                end\n            end\n        end\n    filtersfile:leave(\"</ItemGroup>\")\nend\n\n-- make includes\nfunction _make_includes(filtersfile, vsinfo, target, vcxprojdir)\n    filtersfile:enter(\"<ItemGroup>\")\n        for _, includefile in ipairs(table.join(target.headerfiles or {}, target.extrafiles)) do\n            local filter = _make_filter(includefile, target, vcxprojdir)\n            if filter then\n                filtersfile:enter(\"<ClInclude Include=\\\"%s\\\">\", path.relative(path.absolute(includefile), vcxprojdir))\n                filtersfile:print(\"<Filter>%s</Filter>\", filter)\n                filtersfile:leave(\"</ClInclude>\")\n            end\n        end\n    filtersfile:leave(\"</ItemGroup>\")\nend\n\n-- main filters\nfunction make(vsinfo, target)\n\n    -- the target name\n    local targetname = target.name\n\n    -- the vcxproj directory\n    local vcxprojdir = path.join(vsinfo.solution_dir, targetname)\n\n    -- open vcxproj.filters file\n    local filterspath = path.join(vcxprojdir, targetname .. \".vcxproj.filters\")\n    local filtersfile = vsfile.open(filterspath, \"w\")\n\n    -- init indent character\n    vsfile.indentchar('  ')\n\n    -- make header\n    _make_header(filtersfile, vsinfo)\n\n    -- make filters\n    _make_filters(filtersfile, vsinfo, target, vcxprojdir)\n\n    -- make sources\n    _make_sources(filtersfile, vsinfo, target, vcxprojdir)\n\n    -- make includes\n    _make_includes(filtersfile, vsinfo, target, vcxprojdir)\n\n    -- make tailer\n    _make_tailer(filtersfile, vsinfo)\n\n    -- exit solution file\n    filtersfile:close()\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vsfile.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vsfile.lua\n--\n\n-- init the default indent character\n_g.indentchar = '\\t'\n\n-- print file\nfunction _print_impl(self, ...)\n\n    -- print indent\n    for i = 1, self._indent do\n        self:_write_impl(_g.indentchar)\n    end\n\n    -- print it\n    self:_print_impl(...)\nend\n\n-- printf file\nfunction _printf_impl(self, ...)\n\n    -- print indent\n    for i = 1, self._indent do\n        self:_write_impl(_g.indentchar)\n    end\n\n    -- printf it\n    self:_printf_impl(...)\nend\n\n-- write file\nfunction _write_impl(self, ...)\n\n    -- print indent\n    for i = 1, self._indent do\n        self:_write_impl(_g.indentchar)\n    end\n\n    -- write it\n    self:_write_impl(...)\nend\n\n-- writef file\nfunction _writef_impl(self, ...)\n\n    -- print indent\n    for i = 1, self._indent do\n        self:_write_impl(_g.indentchar)\n    end\n\n    -- writef it\n    self:_writef_impl(...)\nend\n\n-- enter and print file\nfunction _enter(self, ...)\n\n    -- print it\n    self:print(...)\n\n    -- increase indent\n    self._indent = self._indent + 1\nend\n\n-- leave and print file\nfunction _leave(self, ...)\n\n    -- decrease indent\n    if self._indent >= 1 then\n        self._indent = self._indent - 1\n    else\n        self._indent = 0\n    end\n\n    -- print it\n    self:print(...)\nend\n\n-- open file\nfunction open(filepath, mode)\n\n    -- open it\n    local file = io.open(filepath, mode, {encoding = \"utf8bom\"})\n\n    -- hook print, printf and write\n    file._print_impl  = file.print\n    file._printf_impl = file.printf\n    file._write_impl  = file.write\n    file._writef_impl = file.writef\n    file.print        = _print_impl\n    file.printf       = _printf_impl\n    file.write        = _write_impl\n    file.writef       = _writef_impl\n\n    -- add enter and leave interfaces\n    file.enter  = _enter\n    file.leave  = _leave\n\n    -- init indent\n    file._indent = 0\n\n    -- ok?\n    return file\nend\n\n-- set indent character\nfunction indentchar(ch)\n    _g.indentchar = ch or '\\t'\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vsinfo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        vsinfo.lua\n--\n\nlocal vsinfo =\n{\n    [2002] =\n    {   vstudio_version     = \"2002\"\n    ,   solution_version    = \"7\"\n    ,   project_version     = \"7.0\"\n    }\n,   [2003] =\n    {   vstudio_version     = \"2003\"\n    ,   solution_version    = \"8\"\n    ,   project_version     = \"7.1\"\n    }\n,   [2005] =\n    {   vstudio_version     = \"2005\"\n    ,   solution_version    = \"9\"\n    ,   project_version     = \"8.0\"\n    }\n,   [2008] =\n    {   vstudio_version     = \"2008\"\n    ,   solution_version    = \"10\"\n    ,   project_version     = \"9.0\"\n    }\n,   [2010] =\n    {   vstudio_version     = \"2010\"\n    ,   project_version     = \"4\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"11\"\n    ,   toolset_version     = \"v100\"\n    }\n,   [2012] =\n    {   vstudio_version     = \"2012\"\n    ,   project_version     = \"4\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v110\"\n    }\n,   [2013] =\n    {   vstudio_version     = \"2013\"\n    ,   project_version     = \"12\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v120\"\n    }\n,   [2015] =\n    {   vstudio_version     = \"2015\"\n    ,   project_version     = \"14\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v140\"\n    ,   sdk_version         = \"10.0.10240.0\"\n    }\n,   [2017] =\n    {   vstudio_version     = \"2017\"\n    ,   project_version     = \"15\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v141\"\n    ,   sdk_version         = \"10.0.14393.0\"\n    }\n,   [2019] =\n    {   vstudio_version     = \"2019\"\n    ,   project_version     = \"16\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v142\"\n    ,   sdk_version         = \"10.0.17763.0\"\n    }\n,   [2022] =\n    {   vstudio_version     = \"2022\"\n    ,   project_version     = \"17\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v143\"\n    ,   sdk_version         = \"10.0.19041.0\"\n    }\n,   [2026] =\n    {   vstudio_version     = \"2026\"\n    ,   project_version     = \"18\"\n    ,   filters_version     = \"4.0\"\n    ,   solution_version    = \"12\"\n    ,   toolset_version     = \"v145\"\n    ,   sdk_version         = \"10.0.26100.0\"\n    }\n}\n\nfunction main(version)\n    assert(version)\n    return assert(vsinfo[version], \"unsupported vs version (%d)\", version);\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/impl/vsutils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xq114\n-- @file        vsutils.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.cache.memcache\")\nimport(\"core.cache.localcache\")\n\n-- escape special chars in msbuild file\nfunction escape(str)\n    if not str then\n        return nil\n    end\n\n    local map =\n    {\n         [\"%\"] = \"%25\" -- Referencing metadata\n    ,    [\"$\"] = \"%24\" -- Referencing properties\n    ,    [\"@\"] = \"%40\" -- Referencing item lists\n    ,    [\"'\"] = \"%27\" -- Conditions and other expressions\n    ,    [\";\"] = \"%3B\" -- List separator\n    ,    [\"?\"] = \"%3F\" -- Wildcard character for file names in Include and Exclude attributes\n    ,    [\"*\"] = \"%2A\" -- Wildcard character for use in file names in Include and Exclude attributes\n    -- html entities\n    ,    [\"\\\"\"] = \"&quot;\"\n    ,    [\"<\"] = \"&lt;\"\n    ,    [\">\"] = \"&gt;\"\n    ,    [\"&\"] = \"&amp;\"\n    }\n\n    return (string.gsub(str, \"[%%%$@';%?%*\\\"<>&]\", function (c) return assert(map[c]) end))\nend\n\n-- get vs arch\nfunction vsarch(arch)\n    if arch == 'x86' or arch == 'i386' then return \"Win32\" end\n    if arch == 'x86_64' then return \"x64\" end\n    if arch:startswith('arm64') then return \"ARM64\" end\n    if arch:startswith('arm') then return \"ARM\" end\n    return arch\nend\n\n-- translate file path (with namespace characters '::', it's invalid path characters on windows)\nfunction translate_path(filepath)\n    return (filepath:gsub(\"::\", \"#\"))\nend\n\nfunction reset_config_and_caches(mode, arch)\n    -- reload config, project and platform\n    -- modify config\n    config.set(\"as\", nil, {force = true}) -- force to re-check as for ml/ml64\n    config.set(\"mode\", mode, {readonly = true, force = true})\n    config.set(\"arch\", arch, {readonly = true, force = true})\n\n    -- clear all options\n    for _, opt in pairs(project.options()) do\n        if not config.readonly(opt:fullname()) then\n            opt:clear()\n        end\n    end\n    -- merge the project options after default options\n    for name, value in pairs(project.get(\"config\")) do\n        value = table.unwrap(value)\n        assert(type(value) == \"string\" or type(value) == \"boolean\" or type(value) == \"number\", \"set_config(%s): unsupported value type(%s)\", name, type(value))\n        if not config.readonly(name) then\n            config.set(name, value)\n        end\n    end\n\n    -- clear cache\n    memcache.clear()\n    localcache.clear(\"detect\")\n    localcache.clear(\"option\")\n    localcache.clear(\"package\")\n    localcache.clear(\"toolchain\")\n    localcache.clear(\"cxxmodules\")\nend\n"
  },
  {
    "path": "xmake/plugins/project/vstudio/vs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        vs.lua\n--\n\n-- imports\nimport(\"impl.vs200x\")\nimport(\"impl.vs201x\")\nimport(\"impl.vsinfo\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\n\n-- make factory\nfunction make(version)\n\n    if not version then\n        version = tonumber(toolchain.load(\"msvc\"):config(\"vs\") or config.get(\"vs\"))\n        if not version then\n            return function (outputdir)\n                raise(\"invalid vs version, run `xmake f --vs=201x`\")\n            end\n        end\n    end\n\n    -- get vs version info\n    local info = vsinfo(version)\n    if version < 2010 then\n        return function (outputdir)\n            vprint(\"using project kind vs%d\", version)\n            vs200x.make(outputdir, info)\n        end\n    else\n        return function (outputdir)\n            wprint(\"please use the new vs project generator, .e.g xmake project -k vsxmake\")\n            vprint(\"using project kind vs%d\", version)\n            vs201x.make(outputdir, info)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/project/vsxmake/getinfo.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        getinfo.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.tool.compiler\")\nimport(\"core.tool.linker\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.memcache\")\nimport(\"core.cache.localcache\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\nimport(\"private.action.run.runenvs\")\nimport(\"private.action.require.install\", {alias = \"install_requires\"})\nimport(\"actions.config.configfiles\", {alias = \"generate_configfiles\", rootdir = os.programdir()})\nimport(\"vstudio.impl.vsutils\", {rootdir = path.join(os.programdir(), \"plugins\", \"project\")})\n\n-- strip dot directories, e.g. ..\\..\\.. => ..\n-- @see https://github.com/xmake-io/xmake/issues/2039\nfunction _strip_dotdirs(dir)\n    local count\n    dir, count = dir:gsub(\"%.%.[\\\\/]%.%.\", \"..\")\n    if count > 0 then\n        dir = _strip_dotdirs(dir)\n    end\n    return dir\nend\n\nfunction _make_dirs(dir)\n    if dir == nil then\n        return \"\"\n    end\n    if type(dir) == \"string\" then\n        dir = path.translate(dir)\n        if dir == \"\" then\n            return \"\"\n        end\n        if path.is_absolute(dir) then\n            if dir:startswith(project.directory()) then\n                return path.join(\"$(XmakeProjectDir)\", vsutils.escape(path.relative(dir, project.directory())))\n            end\n            return vsutils.escape(dir)\n        end\n        return path.join(\"$(XmakeProjectDir)\", vsutils.escape(dir))\n    end\n    local r = {}\n    for k, v in ipairs(dir) do\n        r[k] = _make_dirs(v)\n    end\n    r = table.unique(r)\n    return path.joinenv(r)\nend\n\nfunction _make_arrs(arr, sep)\n    if arr == nil then\n        return \"\"\n    end\n    if type(arr) == \"string\" then\n        return vsutils.escape(arr)\n    end\n    local r = {}\n    for k, v in ipairs(arr) do\n        r[k] = _make_arrs(v, sep)\n    end\n    r = table.unique(r)\n    return table.concat(r, sep or \";\")\nend\n\n-- get values from target\nfunction _get_values_from_target(target, name)\n    local values = {}\n    for _, value in ipairs((target:get_from(name, \"*\"))) do\n        table.join2(values, value)\n    end\n    return table.unique(values)\nend\n\n-- get flags from target\nfunction _get_flags_from_target(target, name)\n    local flags = _get_values_from_target(target, name)\n    return target_utils.translate_flags_in_tool(target, name, flags)\nend\n\n-- make target info\nfunction _make_targetinfo(mode, arch, target)\n\n    -- init target info\n    local targetinfo =\n    {\n        mode = mode\n    ,   arch = arch\n    ,   plat = config.get(\"plat\")\n    ,   vsarch = vsutils.vsarch(arch)\n    ,   sdkver = config.get(\"vs_sdkver\")\n    }\n\n    -- write only if not default\n    -- use target:get(\"xxx\") rather than target:xxx()\n\n    -- save target kind\n    targetinfo.kind          = target:kind()\n\n    -- is default?\n    targetinfo.default       = tostring(target:is_default())\n\n    -- save target file\n    targetinfo.basename      = vsutils.escape(target:basename())\n    targetinfo.filename      = vsutils.escape(target:filename())\n\n    -- save dirs\n    targetinfo.targetdir     = _make_dirs(target:get(\"targetdir\"))\n    targetinfo.builddir      = _make_dirs(config.get(\"builddir\") or config.get(\"buildir\"))\n    targetinfo.rundir        = _make_dirs(target:get(\"rundir\"))\n    targetinfo.configdir     = _make_dirs(os.getenv(\"XMAKE_CONFIGDIR\"))\n    targetinfo.configfiledir = _make_dirs(target:get(\"configdir\"))\n    targetinfo.includedirs   = _make_dirs(table.join(_get_values_from_target(target, \"includedirs\") or {}, _get_values_from_target(target, \"sysincludedirs\")))\n    targetinfo.linkdirs      = _make_dirs(_get_values_from_target(target, \"linkdirs\"))\n    targetinfo.forceincludes = path.joinenv(table.wrap(_get_values_from_target(target, \"forceincludes\")))\n    targetinfo.sourcedirs    = _make_dirs(_get_values_from_target(target, \"values.project.vsxmake.sourcedirs\"))\n    targetinfo.pcheaderfile  = target:pcheaderfile(\"cxx\") or target:pcheaderfile(\"c\")\n\n    -- save defines\n    targetinfo.defines       = _make_arrs(_get_values_from_target(target, \"defines\"))\n\n    -- save flags\n    targetinfo.cflags        = _make_arrs(_get_flags_from_target(target, \"cflags\"), \" \")\n    targetinfo.cxflags       = _make_arrs(_get_flags_from_target(target, \"cxflags\"), \" \")\n    targetinfo.cxxflags      = _make_arrs(_get_flags_from_target(target, \"cxxflags\"), \" \")\n\n    -- save languages\n    targetinfo.languages     = _make_arrs(_get_values_from_target(target, \"languages\"))\n    if targetinfo.languages then\n        -- fix c++17 to cxx17 for Xmake.props\n        targetinfo.languages = targetinfo.languages:replace(\"c++\", \"cxx\", {plain = true})\n    end\n    if target:is_phony() or target:is_headeronly() or target:is_moduleonly() or target:is_object() then\n        return targetinfo\n    end\n\n    -- save subsystem\n    local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target})\n    for _, linkflag in ipairs(linkflags) do\n        if linkflag:lower():find(\"[%-/]subsystem:windows\") then\n            targetinfo.subsystem = \"windows\"\n        end\n    end\n    if not targetinfo.subsystem then\n        targetinfo.subsystem = \"console\"\n    end\n\n    -- save runenvs\n    local targetrunenvs = {}\n    local addrunenvs, setrunenvs = runenvs.make(target)\n    for k, v in table.orderpairs(target:pkgenvs()) do\n        addrunenvs = addrunenvs or {}\n        addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        for k, v in table.orderpairs(dep:pkgenvs()) do\n            addrunenvs = addrunenvs or {}\n            addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))\n        end\n    end\n    for k, v in table.orderpairs(addrunenvs) do\n        -- https://github.com/xmake-io/xmake/issues/3391\n        v = table.unique(v)\n        if k:upper() == \"PATH\" then\n            targetrunenvs[k] = _make_dirs(v) .. \";$([System.Environment]::GetEnvironmentVariable('\" .. k .. \"'))\"\n        else\n            targetrunenvs[k] = path.joinenv(v) .. \";$([System.Environment]::GetEnvironmentVariable('\" .. k ..\"'))\"\n        end\n    end\n    for k, v in table.orderpairs(setrunenvs) do\n        if #v == 1 then\n            v = v[1]\n            if path.is_absolute(v) and v:startswith(project.directory()) then\n                targetrunenvs[k] = _make_dirs(v)\n            else\n                targetrunenvs[k] = v[1]\n            end\n        else\n            targetrunenvs[k] = path.joinenv(v)\n        end\n    end\n    local runenvstr = {}\n    for k, v in table.orderpairs(targetrunenvs) do\n        table.insert(runenvstr, k .. \"=\" .. v)\n    end\n    targetinfo.runenvs = table.concat(runenvstr, \"\\n\")\n\n    local runargs = target:get(\"runargs\")\n    if runargs then\n        targetinfo.runargs = os.args(table.wrap(runargs))\n    end\n\n    -- use mfc? save the mfc runtime kind\n    if target:rule(\"win.sdk.mfc.shared_app\") or target:rule(\"win.sdk.mfc.shared\") then\n        targetinfo.mfckind = \"Dynamic\"\n    elseif target:rule(\"win.sdk.mfc.static_app\") or target:rule(\"win.sdk.mfc.static\") then\n        targetinfo.mfckind = \"Static\"\n    end\n\n    -- use cuda? save the cuda runtime version\n    if target:rule(\"cuda\") then\n        local nvcc = find_tool(\"nvcc\", { version = true })\n        local ver = semver.new(nvcc.version)\n        targetinfo.cudaver = ver:major() .. \".\" .. ver:minor()\n    end\n    return targetinfo\nend\n\nfunction _make_vsinfo_modes()\n    local vsinfo_modes = {}\n    local modes = option.get(\"modes\")\n    if modes then\n        if not modes:find(\"\\\"\") then\n            modes = modes:gsub(\",\", path.envsep())\n        end\n        for _, mode in ipairs(path.splitenv(modes)) do\n            table.insert(vsinfo_modes, mode:trim())\n        end\n    else\n        vsinfo_modes = project.modes()\n    end\n    if not vsinfo_modes or #vsinfo_modes == 0 then\n        vsinfo_modes = { config.mode() }\n    end\n    return vsinfo_modes\nend\n\nfunction _make_vsinfo_archs()\n    local vsinfo_archs = {}\n    local archs = option.get(\"archs\")\n    if archs then\n        if not archs:find(\"\\\"\") then\n            archs = archs:gsub(\",\", path.envsep())\n        end\n        for _, arch in ipairs(path.splitenv(archs)) do\n            table.insert(vsinfo_archs, arch:trim())\n        end\n    else\n        -- we use it first if global set_arch(\"xx\") is setted in xmake.lua\n        vsinfo_archs = project.get(\"target.arch\")\n        if not vsinfo_archs then\n            -- for set_allowedarchs()\n            local allowed_archs = project.allowed_archs(config.plat())\n            if allowed_archs then\n                vsinfo_archs = allowed_archs:to_array()\n            end\n        end\n        if not vsinfo_archs then\n            local default_archs = toolchain.load(\"msvc\"):config(\"vcarchs\")\n            if not default_archs then\n                default_archs = platform.archs()\n            end\n            if default_archs then\n                default_archs = hashset.from(table.wrap(default_archs))\n                -- just generate single arch by default to avoid some fails for installing packages.\n                -- @see https://github.com/xmake-io/xmake/issues/3268\n                local arch = config.arch()\n                if default_archs:has(arch) then\n                    vsinfo_archs = { arch }\n                else\n                    default_archs:remove(\"arm64\")\n                    vsinfo_archs = default_archs:to_array()\n                end\n            end\n        end\n    end\n    if not vsinfo_archs or #vsinfo_archs == 0 then\n        vsinfo_archs = { config.arch() }\n    end\n    return vsinfo_archs\nend\n\nfunction _make_vsinfo_groups()\n    local groups = {}\n    local group_deps = {}\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in table.orderpairs(project_targets) do\n        local group_path = target:get(\"group\")\n        if group_path and #(group_path:trim()) > 0 then\n            group_path = path.normalize(group_path)\n            local group_name = path.filename(group_path)\n            local group_names = path.split(group_path)\n            local group_current_path\n            for idx, name in ipairs(group_names) do\n                group_current_path = group_current_path and path.join(group_current_path, name) or name\n                local group = groups[\"group.\" .. group_current_path] or {}\n                group.group = name\n                group.group_id = hash.uuid4(\"group.\" .. group_current_path)\n                if idx > 1 then\n                    group_deps[\"group_dep.\" .. group_current_path] = {\n                        current_id = group.group_id,\n                        parent_id = hash.uuid4(\"group.\" .. path.directory(group_current_path))}\n                end\n                groups[\"group.\" .. group_current_path] = group\n            end\n            group_deps[\"group_dep.target.\" .. targetname] = {\n                current_id = hash.uuid4(targetname),\n                parent_id = groups[\"group.\" .. group_path].group_id}\n        end\n    end\n    return groups, group_deps\nend\n\n-- make filter\nfunction _make_filter(filepath, target, vcxprojdir)\n    local filter\n    local is_plain = false\n    local filegroups = target.filegroups\n    if filegroups then\n        -- @see https://github.com/xmake-io/xmake/issues/2282\n        filepath = path.absolute(filepath)\n        local scriptdir = target.absscriptdir\n        local filegroups_extraconf = target.filegroups_extraconf or {}\n        for _, filegroup in ipairs(filegroups) do\n            local extraconf = filegroups_extraconf[filegroup] or {}\n            local rootdir = extraconf.rootdir\n            assert(rootdir, \"please set root directory, e.g. add_filegroups(%s, {rootdir = 'xxx'})\", filegroup)\n            for _, rootdir in ipairs(table.wrap(rootdir)) do\n                if not path.is_absolute(rootdir) then\n                    rootdir = path.absolute(rootdir, scriptdir)\n                end\n                local fileitem = path.relative(filepath, rootdir)\n                local files = extraconf.files or \"**\"\n                local mode = extraconf.mode\n                for _, filepattern in ipairs(files) do\n                    filepattern = path.pattern(path.absolute(path.join(rootdir, filepattern)))\n                    if filepath:match(filepattern) then\n                        if mode == \"plain\" then\n                            filter = path.normalize(filegroup)\n                            is_plain = true\n                        else\n                            -- file tree mode (default)\n                            if filegroup ~= \"\" then\n                                filter = path.normalize(path.join(filegroup, path.directory(fileitem)))\n                            else\n                                filter = path.normalize(path.directory(fileitem))\n                            end\n                        end\n                        goto found_filter\n                    end\n                end\n                -- stop once a rootdir matches\n                if filter then\n                    goto found_filter\n                end\n            end\n            ::found_filter::\n        end\n    end\n    if not filter and not is_plain then\n        -- use the default filter rule\n        filter = path.relative(path.absolute(path.directory(filepath)), vcxprojdir)\n        -- @see https://github.com/xmake-io/xmake/issues/2039\n        if filter then\n            filter = _strip_dotdirs(filter)\n        end\n    end\n    if filter and filter == '.' then\n        filter = nil\n    end\n    return filter\nend\n\n\n-- make vstudio project\nfunction main(outputdir, vsinfo)\n\n    -- enter project directory\n    local oldir = os.cd(project.directory())\n\n    -- init solution directory\n    vsinfo.vcxproj_rootdir = path.absolute(path.join(outputdir, \"vsxmake\" .. vsinfo.vstudio_version))\n    if project.policy(\"generator.vsxmake.root_sln\") then\n        vsinfo.solution_dir = path.absolute(outputdir)\n    else\n        vsinfo.solution_dir = vsinfo.vcxproj_rootdir\n    end\n    vsinfo.programdir = _make_dirs(xmake.programdir())\n    vsinfo.programfile = xmake.programfile()\n    vsinfo.projectdir = project.directory()\n    vsinfo.sln_projectfile = path.relative(project.rootfile(), vsinfo.solution_dir)\n    local projectfile = path.filename(project.rootfile())\n    vsinfo.slnfile = project.name() or path.filename(project.directory())\n    -- write only if not default\n    if projectfile ~= \"xmake.lua\" then\n        vsinfo.projectfile = projectfile\n    end\n\n    vsinfo.xmake_info = format(\"xmake version %s\", xmake.version())\n    vsinfo.solution_id = hash.uuid4(project.directory() .. vsinfo.solution_dir)\n    vsinfo.vs_version = vsinfo.project_version .. \".0\"\n\n    -- init modes\n    vsinfo.modes = _make_vsinfo_modes()\n\n    -- init archs\n    vsinfo.archs = _make_vsinfo_archs()\n\n    -- init groups\n    local groups, group_deps = _make_vsinfo_groups()\n    vsinfo.groups            = table.orderkeys(groups)\n    vsinfo.group_deps        = table.orderkeys(group_deps)\n    vsinfo._groups           = groups\n    vsinfo._group_deps       = group_deps\n\n    -- init config flags\n    local flags = {}\n    for k, v in table.orderpairs(localcache.get(\"config\", \"options\")) do\n        if k ~= \"plat\" and k ~= \"mode\" and k ~= \"arch\" and k ~= \"clean\" and k ~= \"builddir\" and k ~= \"buildir\" then\n            table.insert(flags, \"--\" .. k .. \"=\" .. tostring(v))\n        end\n    end\n    vsinfo.configflags = os.args(flags)\n\n    -- load targets\n    local targets = {}\n    vsinfo._arch_modes = {}\n    for _, mode in ipairs(vsinfo.modes) do\n        vsinfo._arch_modes[mode] = {}\n        for _, arch in ipairs(vsinfo.archs) do\n            vsinfo._arch_modes[mode][arch] = { mode = mode, arch = arch }\n\n            -- trace\n            print(\"checking for %s.%s ...\", mode, arch)\n\n            -- reset project configs and caches\n            vsutils.reset_config_and_caches(mode, arch)\n\n            -- check platform\n            platform.load(config.plat(), arch):check()\n\n            -- check project options\n            project.check_options()\n\n            -- install and update requires\n            install_requires()\n\n            -- check target toolchains\n            target_utils.check_target_toolchains()\n\n            -- load targets\n            project.load_targets()\n\n            -- update config files\n            generate_configfiles()\n\n            -- save toolchain configs\n            toolchain.save()\n\n            -- ensure to enter project directory\n            os.cd(project.directory())\n\n            -- save targets\n            local project_targets = target_utils.get_project_targets()\n            for targetname, target in table.orderpairs(project_targets) do\n\n                -- https://github.com/xmake-io/xmake/issues/2337\n                target:data_set(\"plugin.project.kind\", \"vsxmake\")\n\n                -- make target with the given mode and arch\n                targets[targetname] = targets[targetname] or {}\n                local _target = targets[targetname]\n\n                -- init target info\n                _target.targetname = targetname\n                _target.targetname_inpath = vsutils.translate_path(targetname)\n                _target.vcxprojdir = path.join(vsinfo.vcxproj_rootdir, targetname)\n                _target.vcxprojdir_relative_sln = vsutils.translate_path(path.relative(_target.vcxprojdir, vsinfo.solution_dir))\n                _target.target_id = hash.uuid4(targetname)\n                _target.kind = target:kind()\n                _target.absscriptdir = target:scriptdir()\n                _target.scriptdir = path.relative(target:scriptdir(), _target.vcxprojdir)\n                _target.projectdir = path.relative(project.directory(), _target.vcxprojdir)\n                local targetdir = target:get(\"targetdir\")\n                if targetdir then _target.targetdir = path.relative(targetdir, _target.vcxprojdir) end\n                _target._targets = _target._targets or {}\n                _target._targets[mode] = _target._targets[mode] or {}\n                local targetinfo = _make_targetinfo(mode, arch, target)\n                _target._targets[mode][arch] = targetinfo\n                _target.sdkver = targetinfo.sdkver\n                _target.default = targetinfo.default\n\n                -- save all sourcefiles and headerfiles\n                _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles())))\n                _target.headerfiles = table.unique(table.join(_target.headerfiles or {}, (target:headerfiles())))\n                _target.extrafiles = table.unique(table.join(_target.extrafiles or {}, (target:extrafiles())))\n\n                -- sort them to stabilize generation\n                table.sort(_target.sourcefiles)\n                table.sort(_target.headerfiles)\n                table.sort(_target.extrafiles)\n\n                -- save file groups\n                _target.filegroups = table.unique(table.join(_target.filegroups or {}, target:get(\"filegroups\")))\n\n                for filegroup, groupconf in pairs(target:extraconf(\"filegroups\")) do\n                    _target.filegroups_extraconf = _target.filegroups_extraconf or {}\n                    local mergedconf = _target.filegroups_extraconf[filegroup]\n                    if not mergedconf then\n                        mergedconf = {}\n                        _target.filegroups_extraconf[filegroup] = mergedconf\n                    end\n\n                    if groupconf.rootdir then\n                        mergedconf.rootdir = table.unique(table.join(mergedconf.rootdir or {}, table.wrap(groupconf.rootdir)))\n                    end\n                    if groupconf.files then\n                        mergedconf.files = table.unique(table.join(mergedconf.files or {}, table.wrap(groupconf.files)))\n                    end\n                    mergedconf.plain = groupconf.plain or mergedconf.plain\n                end\n\n                -- save deps\n                _target.deps = table.unique(table.join(_target.deps or {}, table.orderkeys(target:deps()), nil))\n            end\n        end\n    end\n    os.cd(oldir)\n    for _, target in table.orderpairs(targets) do\n        target._paths = {}\n        local dirs = {}\n        local projectdir = project.directory()\n        local root = target.absscriptdir or projectdir\n        target.sourcefiles = table.imap(target.sourcefiles, function(_, v) return path.relative(v, projectdir) end)\n        target.headerfiles = table.imap(target.headerfiles, function(_, v) return path.relative(v, projectdir) end)\n        target.extrafiles = table.imap(target.extrafiles, function(_, v) return path.relative(v, projectdir) end)\n        for _, f in ipairs(table.join(target.sourcefiles, target.headerfiles or {}, target.extrafiles)) do\n            local dir = _make_filter(f, target, root)\n            local escaped_f = vsutils.escape(f)\n            target._paths[f] =\n            {\n                -- @see https://github.com/xmake-io/xmake/issues/2077\n                path = path.is_absolute(escaped_f) and escaped_f or \"$(XmakeProjectDir)\\\\\" .. escaped_f,\n                dir = vsutils.escape(dir)\n            }\n            while dir and dir ~= \".\" do\n                if not dirs[dir] then\n                    dirs[dir] =\n                    {\n                        dir = vsutils.escape(dir),\n                        dir_id = hash.uuid4(dir)\n                    }\n                end\n                dir = path.directory(dir) or \".\"\n            end\n        end\n        target._dirs = dirs\n        target.dirs = table.orderkeys(dirs)\n        target._deps = {}\n        for _, v in ipairs(target.deps) do\n            target._deps[v] = targets[v]\n        end\n    end\n\n    -- we need to set startup project for default or binary target\n    -- @see https://github.com/xmake-io/xmake/issues/1249\n    local targetnames = {}\n    local project_targets = target_utils.get_project_targets()\n    for targetname, target in table.orderpairs(project_targets) do\n        if target:get(\"default\") == true then\n            table.insert(targetnames, 1, targetname)\n        elseif target:is_binary() then\n            local first_target = targetnames[1] and project.target(targetnames[1], {namespace = target:namespace()})\n            if not first_target or first_target:get(\"default\") ~= true then\n                table.insert(targetnames, 1, targetname)\n            else\n                table.insert(targetnames, targetname)\n            end\n        else\n            table.insert(targetnames, targetname)\n        end\n    end\n    vsinfo.targets = targetnames\n    vsinfo._targets = targets\n    return vsinfo\nend\n"
  },
  {
    "path": "xmake/plugins/project/vsxmake/render.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        render.lua\n--\n\n-- imports\nimport(\"lib.detect.find_file\")\n\nfunction _fill(opt, params)\n    return function(match)\n        local imp = match:match(\"^Import%((.+)%)$\")\n        if imp then\n            local func = find_file(imp .. \"(*)\", opt.templatedir)\n            assert(func)\n            local args = path.filename(func):match(\"%((.+)%)$\"):split(\",\", {plain = true})\n            return _render(func, opt, args)\n        end\n        return opt.paramsprovider(match, params) or \"<Not Provided>\"\n    end\nend\n\nfunction _cfill(opt, params)\n    return function(match)\n        local tmp = match:split(\";\", {strict = true, plain = true})\n        assert(#tmp == 2 or #tmp == 3)\n\n        local cond = tmp[1]\n        local value1 = tmp[2]\n        local value2 = \"\"\n\n        if #tmp == 3 then\n            value2 = tmp[3]\n        end\n        tmp = cond:split(\"=\", {plain = true})\n        assert(#tmp == 2)\n\n        local k = tmp[1]:trim()\n        local v = tmp[2]:trim()\n        if opt.paramsprovider(k, params) == v then\n            return value1\n        end\n        return value2\n    end\nend\n\nfunction _expand(params)\n    local r = {\"\"}\n    for _, v in ipairs(params) do\n        if type(v) == \"string\" then\n            for i, p in ipairs(r) do\n                r[i] = p .. \"\\0\" .. v\n            end\n        else\n            local newr = {}\n            for _, c in ipairs(v) do\n                for _, p in ipairs(r) do\n                    table.insert(newr, p .. \"\\0\" .. c)\n                end\n            end\n            r = newr\n        end\n    end\n    for i, p in ipairs(r) do\n        r[i] = p:split(\"\\0\")\n    end\n    return r\nend\n\nfunction _render(templatepath, opt, args)\n    local template = io.readfile(templatepath)\n    local params = _expand(opt.paramsprovider(args))\n    local replaced = \"\"\n    for _, v in ipairs(params) do\n        local tmpl = template:gsub(opt.cpattern, _cfill(opt, v))\n        replaced = replaced .. tmpl:gsub(opt.pattern, _fill(opt, v))\n    end\n    return replaced\nend\n\nfunction main(templatepath, pattern, cpattern, paramsprovider)\n    local opt = {\n        pattern = pattern,\n        cpattern = cpattern,\n        paramsprovider = paramsprovider,\n        templatedir = path.directory(templatepath)\n    }\n    return _render(templatepath, opt, {})\nend\n\n"
  },
  {
    "path": "xmake/plugins/project/vsxmake/vsxmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      OpportunityLiu\n-- @file        vsxmake.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"vstudio.impl.vsinfo\", { rootdir = path.directory(os.scriptdir()) })\nimport(\"render\")\nimport(\"getinfo\")\nimport(\"core.project.config\")\nimport(\"core.cache.localcache\")\nimport(\"vstudio.impl.vsutils\", {rootdir = path.join(os.programdir(), \"plugins\", \"project\")})\n\nlocal template_root = path.join(os.programdir(), \"scripts\", \"vsxmake\", \"vsproj\", \"templates\")\nlocal template_sln = path.join(template_root, \"sln\", \"vsxmake.sln\")\nlocal template_vcx = path.join(template_root, \"vcxproj\", \"#target#.vcxproj\")\n\nlocal template_fil = path.join(template_root, \"vcxproj.filters\", \"#target#.vcxproj.filters\")\nlocal template_props = path.join(template_root, \"Xmake.Custom.props\")\nlocal template_targets = path.join(template_root, \"Xmake.Custom.targets\")\nlocal template_items = path.join(template_root, \"Xmake.Custom.items\")\nlocal template_itemfil = path.join(template_root, \"Xmake.Custom.items.filters\")\n\nfunction _filter_files(files, includeexts, excludeexts)\n    local positive = not excludeexts\n    local extset = hashset.from(positive and includeexts or excludeexts)\n    local f = {}\n    for _, file in ipairs(files) do\n        local ext = path.extension(file)\n        if (positive and extset:has(ext)) or not (positive or extset:has(ext)) then\n            table.insert(f, file)\n        end\n    end\n    table.sort(f)\n    return f\nend\n\nfunction _buildparams(info, target, default)\n\n    local function getprop(match, opt)\n        local i = info\n        local r = info[match]\n        if target then\n            opt = table.join(target, opt)\n        end\n        for _, k in ipairs(opt) do\n            local v = (i._targets or {})[k]\n            if v == nil and i._arch_modes then\n                v = i._arch_modes[k]\n            end\n            if v == nil and i._paths then\n                v = i._paths[k]\n            end\n            if v == nil and i._dirs then\n                v = i._dirs[k]\n            end\n            if v == nil and i._deps then\n                v = i._deps[k]\n            end\n            if v == nil and i._groups then\n                v = i._groups[k]\n            end\n            if v == nil and i._group_deps then\n                v = i._group_deps[k]\n            end\n            if v == nil then\n                v = i[k]\n            end\n            if v == nil then\n                raise(\"key '\" .. k .. \"' not found\")\n            end\n            i = v\n            r = i[match] or r\n        end\n\n        return r or default\n    end\n\n    local function listconfig(args)\n        for _, k in ipairs(args) do\n            args[k] = true\n        end\n        local r = {}\n        if args.target then\n            table.insert(r, info.targets)\n        end\n        if args.mode then\n            table.insert(r, info.modes)\n        end\n        if args.arch then\n            table.insert(r, info.archs)\n        end\n        if args.group then\n            table.insert(r, info.groups)\n        end\n        if args.group_dep then\n            table.insert(r, info.group_deps)\n        end\n        if args.dir then\n            table.insert(r, info._targets[target].dirs)\n        end\n        if args.dep then\n            table.insert(r, info._targets[target].deps)\n        end\n        if args.filec then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".c\"}))\n        elseif args.filecxx then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".cpp\", \".cc\", \".cxx\"}))\n        elseif args.filempp then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".mpp\", \".mxx\", \".cppm\", \".ixx\"}))\n        elseif args.filecu then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".cu\"}))\n        elseif args.fileobj then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".obj\", \".o\"}))\n        elseif args.filerc then\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".rc\"}))\n        elseif args.fileui then -- for qt/.ui\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".ui\"}))\n        elseif args.fileqrc then -- for qt/.qrc\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".qrc\"}))\n        elseif args.filets then -- for qt/.ts\n            local files = info._targets[target].sourcefiles\n            table.insert(r, _filter_files(files, {\".ts\"}))\n        elseif args.incc then\n            local files = table.join(info._targets[target].headerfiles or {}, info._targets[target].extrafiles)\n            table.insert(r, _filter_files(files, nil, {\".natvis\"}))\n        elseif args.incnatvis then\n            local files = table.join(info._targets[target].headerfiles or {}, info._targets[target].extrafiles)\n            table.insert(r, _filter_files(files, {\".natvis\"}))\n        end\n        return r\n    end\n\n    return function(match, opt)\n        if type(match) == \"table\" then\n            return listconfig(match)\n        end\n        return getprop(match, opt)\n    end\nend\n\nfunction _trycp(file, target, targetname)\n    targetname = targetname or path.filename(file)\n    local targetfile = path.join(target, targetname)\n    targetfile = vsutils.translate_path(targetfile)\n    if os.isfile(targetfile) then\n        dprint(\"skipped file %s since the file already exists\", path.relative(targetfile))\n        return\n    end\n    os.cp(file, targetfile)\nend\n\nfunction _writefileifneeded(file, content)\n    file = vsutils.translate_path(file)\n    if os.isfile(file) and io.readfile(file) == content then\n        dprint(\"skipped file %s since the file has the same content\", path.relative(file))\n        return\n    end\n    -- we need utf8 with bom encoding for unicode\n    -- @see https://github.com/xmake-io/xmake/issues/1689\n    io.writefile(file, content, {encoding = \"utf8bom\"})\nend\n\n-- save plugin arguments for `plugin.vsxmake.autoupdate`\n-- @see https://github.com/xmake-io/xmake/issues/1895\nfunction _save_plugin_arguments()\n    local vsxmake_cache = localcache.cache(\"vsxmake\")\n    for _, name in ipairs({\"kind\", \"modes\", \"archs\", \"outputdir\"}) do\n        vsxmake_cache:set(name, option.get(name))\n    end\n    vsxmake_cache:save()\nend\n\n-- clear cache\nfunction _clear_cache()\n    localcache.clear(\"detect\")\n    localcache.clear(\"option\")\n    localcache.clear(\"package\")\n    localcache.clear(\"toolchain\")\n\n    -- force recheck\n    localcache.set(\"config\", \"recheck\", true)\n\n    localcache.save()\nend\n\n-- make\nfunction make(version)\n\n    if not version then\n        version = tonumber(config.get(\"vs\"))\n        if not version then\n            return function(outputdir)\n                raise(\"invalid vs version, run `xmake f --vs=20xx`\")\n            end\n        end\n    end\n\n    return function(outputdir)\n        vprint(\"using project kind vs%d\", version)\n        assert(version >= 2010, \"vsxmake does not support vs version lower than 2010\")\n\n        -- get info and params\n        local info = getinfo(outputdir, vsinfo(version))\n        local paramsprovidersln = _buildparams(info)\n\n        -- write solution file\n        local sln = path.join(info.solution_dir, info.slnfile .. \".sln\")\n        _writefileifneeded(sln, render(template_sln, \"#([A-Za-z0-9_,%.%*%(%)]+)#\", \"@([^@]+)@\", paramsprovidersln))\n\n        -- add solution custom file\n        _trycp(template_props, info.vcxproj_rootdir)\n        _trycp(template_targets, info.vcxproj_rootdir)\n\n        for _, target in ipairs(info.targets) do\n            local paramsprovidertarget = _buildparams(info, target, \"<!-- nil -->\")\n            local vcxproj_dir = info._targets[target].vcxprojdir\n\n            -- write project file\n            local vcxproj_file = path.join(vcxproj_dir, target .. \".vcxproj\")\n            _writefileifneeded(vcxproj_file, render(template_vcx, \"#([A-Za-z0-9_,%.%*%(%)]+)#\", \"@([^@]+)@\", paramsprovidertarget))\n\n            local vcxproj_filters = path.join(vcxproj_dir, target .. \".vcxproj.filters\")\n            _writefileifneeded(vcxproj_filters, render(template_fil, \"#([A-Za-z0-9_,%.%*%(%)]+)#\", \"@([^@]+)@\", paramsprovidertarget))\n\n            -- add project custom file\n            _trycp(template_props, vcxproj_dir)\n            _trycp(template_targets, vcxproj_dir)\n            _trycp(template_items, vcxproj_dir)\n            _trycp(template_itemfil, vcxproj_dir)\n        end\n\n        -- clear config and local cache\n        _clear_cache()\n\n        -- save plugin arguments for autoupdate\n        _save_plugin_arguments()\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/project/xcode/get_xcode_info.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JXMaster\n-- @file        get_xcode_info.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\nfunction _get_project_modes()\n    local ret_modes = {}\n    local modes = option.get(\"modes\")\n    if modes then\n        if not modes:find(\"\\\"\") then\n            modes = modes:gsub(\",\", path.envsep())\n        end\n        for _, mode in ipairs(path.splitenv(modes)) do\n            table.insert(ret_modes, mode:trim())\n        end\n    else\n        ret_modes = project.modes()\n    end\n    return ret_modes\nend\n\n-- tranlate path\nfunction _translate_path(filepath, outputdir)\n    filepath = path.translate(filepath)\n    if filepath == \"\" then\n        return \"\"\n    end\n    if path.is_absolute(filepath) then\n        if filepath:startswith(project.directory()) then\n            return path.relative(filepath, outputdir)\n        end\n        return filepath\n    else\n        return path.relative(path.absolute(filepath), outputdir)\n    end\nend\n\nfunction _add_PBXFileReference(xcinfo, file_info)\n    local obj = {}\n    obj.explicitFileType = file_info.explicitFileType\n    obj.lastKnownFileType = file_info.lastKnownFileType\n    obj.name = file_info.name\n    obj.path = file_info.path\n    obj.sourceTree = file_info.sourceTree\n    obj.includeInIndex = file_info.includeInIndex\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.PBXFileReference = xcinfo.sections.PBXFileReference or {}\n    xcinfo.sections.PBXFileReference[uuid] = obj\n    return uuid\nend\n\nfunction _add_PBXGroup(xcinfo, name, sourceTree)\n    local obj = {}\n    obj.name = name\n    obj.sourceTree = sourceTree\n    obj.children = {}\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.PBXGroup = xcinfo.sections.PBXGroup or {}\n    xcinfo.sections.PBXGroup[uuid] = obj\n    return uuid\nend\n\n-- target may be nil.\nfunction _add_XCBuildConfiguration(xcinfo, mode, target)\n    local obj = {}\n    obj.name = mode\n    obj.buildSettings = {}\n    -- This allows scripts to read/write files that are not in the Input/Output list of\n    -- the phase.\n    obj.buildSettings.ENABLE_USER_SCRIPT_SANDBOXING = false\n    if target then\n        local rules = target:rules()\n        local is_app_bundle = false\n        if rules[\"xcode.application\"] ~= nil then\n            is_app_bundle = true\n        end\n        if is_app_bundle then\n            obj.buildSettings.GENERATE_INFOPLIST_FILE = true\n            obj.buildSettings.PRODUCT_NAME = \"\\\"$(TARGET_NAME)\\\"\"\n        end\n    else\n        -- This is for root project.\n        obj.buildSettings.SUPPORTED_PLATFORMS = \"\\\"macosx iphoneos\\\"\"\n        obj.buildSettings.SDKROOT = \"macosx\"\n        obj.buildSettings[\"\\\"SDKROOT[sdk=macosx*]\\\"\"] = \"macosx\"\n        obj.buildSettings[\"\\\"SDKROOT[sdk=iphoneos]\\\"\"] = \"iphoneos\"\n\n    end\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.XCBuildConfiguration = xcinfo.sections.XCBuildConfiguration or {}\n    xcinfo.sections.XCBuildConfiguration[uuid] = obj\n    return uuid\nend\n\n-- target may be nil.\nfunction _add_XCConfigurationList(xcinfo, target)\n    local obj = {}\n    local modes = _get_project_modes()\n    obj.buildConfigurations = {}\n    for _, mode in ipairs(modes) do\n        table.insert(obj.buildConfigurations, _add_XCBuildConfiguration(xcinfo, mode, target))\n    end\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.XCConfigurationList = xcinfo.sections.XCConfigurationList or {}\n    xcinfo.sections.XCConfigurationList[uuid] = obj\n    return uuid\nend\n\nfunction _add_PBXShellScriptBuildPhase(xcinfo, target)\n    local obj = {}\n    local shellscript = {}\n    local projectdir = _translate_path(os.projectdir(), xcinfo.project_dir)\n    if projectdir ~= \".\" then\n        table.insert(shellscript, \"cd \" .. projectdir)\n    end\n    table.insert(shellscript, [[\nexport XMAKE_PROGRAM_FILE=\\\"]] .. os.programfile() .. [[\\\"\nexport XMAKE_PROGRAM_DIR=\\\"]] .. os.programdir() .. [[\\\"\nexport XMAKE_COLORTERM=\\\"nocolor\\\"\n\n# Running xmake scripts.\n${XMAKE_PROGRAM_FILE} f -y -m ${CONFIGURATION} -p ${PLATFORM_NAME} -a ${NATIVE_ARCH} -o ${BUILD_DIR} || exit -1\n${XMAKE_PROGRAM_FILE} build ${TARGET_NAME} || exit -1\n\n# Copy files to build path.\nXMAKE_BUILD_DIR=${BUILD_DIR}/${PLATFORM_NAME}/${NATIVE_ARCH}/${CONFIGURATION}\nif test -e ${CONFIGURATION_BUILD_DIR}; then\n    rm -r ${CONFIGURATION_BUILD_DIR}/*\nfi\nif test -e ${XMAKE_BUILD_DIR}; then\n    cp -r ${XMAKE_BUILD_DIR}/* ${CONFIGURATION_BUILD_DIR}\nfi\n]])\n    obj.shellScript = table.concat(shellscript, \"\\n\")\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.PBXShellScriptBuildPhase = xcinfo.sections.PBXShellScriptBuildPhase or {}\n    xcinfo.sections.PBXShellScriptBuildPhase[uuid] = obj\n    return uuid\nend\n\nfunction _add_target_files(xcinfo, group, files)\n    for _, v in table.orderpairs(files) do\n        local file_info = {}\n        file_info.name = path.filename(v)\n        file_info.path = path.join(project.directory(), v)\n        file_info.sourceTree = \"\\\"<absolute>\\\"\"\n        local ext = path.extension(v)\n        if ext == \".h\" then\n            file_info.lastKnownFileType = \"sourcecode.c.h\"\n        elseif ext == \".c\" then\n            file_info.lastKnownFileType = \"sourcecode.c.c\"\n        elseif ext == \".m\" then\n            file_info.lastKnownFileType = \"sourcecode.c.objc\"\n        elseif ext == \".hpp\" then\n            file_info.lastKnownFileType = \"sourcecode.cpp.h\"\n        elseif ext == \".cpp\" then\n            file_info.lastKnownFileType = \"sourcecode.cpp.cpp\"\n        elseif ext == \".mm\" then\n            file_info.lastKnownFileType = \"sourcecode.cpp.objcpp\"\n        elseif ext == \".plist\" then\n            file_info.lastKnownFileType = \"text.plist\"\n        end\n        table.insert(group.children, _add_PBXFileReference(xcinfo, file_info))\n    end\nend\n\nfunction _add_PBXNativeTarget(xcinfo, target_name, target)\n    local obj = {}\n    obj.name = target_name\n    obj.productName = target_name\n    local rules = target:rules()\n    local is_app_bundle = false\n    if rules[\"xcode.application\"] ~= nil then\n        is_app_bundle = true\n    end\n    -- Add product file.\n    local product_file = {}\n    if target:kind() == \"static\" then\n        product_file.explicitFileType = \"com.apple.product-type.library.static\"\n    elseif target:kind() == \"shared\" then\n        product_file.explicitFileType = \"com.apple.product-type.library.dynamic\"\n    elseif target:kind() == \"binary\" then\n        if is_app_bundle then\n            product_file.explicitFileType = \"wrapper.application\"\n        else\n            product_file.explicitFileType = \"com.apple.product-type.tool\"\n        end\n    end\n    if is_app_bundle then\n        product_file.name = target:filename() .. \".app\"\n    else\n        product_file.name = target:filename()\n    end\n    product_file.path = product_file.name\n    product_file.sourceTree = \"BUILT_PRODUCTS_DIR\"\n    product_file.includeInIndex = 0\n    obj.productReference = _add_PBXFileReference(xcinfo, product_file)\n    if is_app_bundle then\n        obj.productType = \"com.apple.product-type.application\"\n    else\n        obj.productType = product_file.explicitFileType\n    end\n        -- Add product file to product group.\n    local project_obj = xcinfo.sections.PBXProject[xcinfo.root_object]\n    local product_group = xcinfo.sections.PBXGroup[project_obj.productRefGroup]\n    table.insert(product_group.children, obj.productReference)\n\n    -- Add files.\n    local headerfiles = target:headerfiles()\n    local sourcefiles = target:sourcefiles()\n    obj.headerFileGroup = _add_PBXGroup(xcinfo, \"Header Files\", \"<group>\")\n    obj.sourceFileGroup = _add_PBXGroup(xcinfo, \"Source Files\", \"<group>\")\n    local header_group = xcinfo.sections.PBXGroup[obj.headerFileGroup]\n    local source_group = xcinfo.sections.PBXGroup[obj.sourceFileGroup]\n    _add_target_files(xcinfo, header_group, headerfiles)\n    _add_target_files(xcinfo, source_group, sourcefiles)\n    obj.mainGroup = _add_PBXGroup(xcinfo, obj.productName, \"<group>\")\n    local main_group = xcinfo.sections.PBXGroup[obj.mainGroup]\n    table.insert(main_group.children, obj.headerFileGroup)\n    table.insert(main_group.children, obj.sourceFileGroup)\n    -- Add configuration list for target.\n    obj.buildConfigurationList = _add_XCConfigurationList(xcinfo, target)\n    -- Add build phases.\n    obj.buildPhases = {}\n    table.insert(obj.buildPhases, _add_PBXShellScriptBuildPhase(xcinfo, target))\n    local uuid = xcinfo:gen_uuid()\n    xcinfo.sections.PBXNativeTarget = xcinfo.sections.PBXNativeTarget or {}\n    xcinfo.sections.PBXNativeTarget[uuid] = obj\n    return uuid\nend\n\nfunction main(outputdir)\n    local xcinfo = {}\n\n    xcinfo.project_dir = outputdir\n    xcinfo.project_bundle = (project.name() or path.filename(project.directory())) .. \".xcodeproj\"\n    xcinfo.project_dir_uuid = string.upper(hash.strhash32(xcinfo.project_dir))\n    xcinfo.project_bundle_uuid = string.upper(hash.strhash32(xcinfo.project_bundle))\n    xcinfo.uuid_counter = 0\n    xcinfo.gen_uuid = function(self)\n        local counter = self.uuid_counter\n        self.uuid_counter = self.uuid_counter + 1\n        return self.project_dir_uuid .. self.project_bundle_uuid .. string.format(\"%08X\", counter)\n    end\n\n    -- Used to collect Xcode nodes.\n    -- nodes are grouped by their types. For example, all PBXFileReference\n    -- nodes will be in xcinfo.sections.PBXFileReference, indexed by their UUIDs.\n    xcinfo.sections = {}\n\n    -- Add project node\n    local sections = xcinfo.sections\n    sections.PBXProject = {}\n    local project_uuid = xcinfo:gen_uuid()\n    xcinfo.root_object = project_uuid\n    sections.PBXProject[project_uuid] = {}\n    local project_obj = sections.PBXProject[project_uuid]\n\n    -- collect buildConfigurationList\n    project_obj.buildConfigurationList = _add_XCConfigurationList(xcinfo)\n\n    -- collect main group\n    project_obj.mainGroup = _add_PBXGroup(xcinfo, nil, \"<group>\")\n    local main_group = xcinfo.sections.PBXGroup[project_obj.mainGroup]\n\n    -- collect product ref group\n    project_obj.productRefGroup = _add_PBXGroup(xcinfo, \"Products\", \"<group>\");\n\n    -- collect targets.\n    project_obj.targets = {}\n    for target_name, target in table.orderpairs(project.targets()) do\n        local target = _add_PBXNativeTarget(xcinfo, target_name, target)\n        table.insert(project_obj.targets, target)\n        local target_obj = xcinfo.sections.PBXNativeTarget[target]\n        table.insert(main_group.children, target_obj.mainGroup)\n    end\n    table.insert(main_group.children, project_obj.productRefGroup)\n\n    return xcinfo\nend\n"
  },
  {
    "path": "xmake/plugins/project/xcode/pbxproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JXMaster\n-- @file        pbxproj.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\nfunction _write_file_if_needed(file, content)\n    if os.isfile(file) and io.readfile(file) == content then\n        dprint(\"skipped file %s since the file has the same content\", path.relative(file))\n        return\n    end\n    -- we need utf8 with bom encoding for unicode\n    -- @see https://github.com/xmake-io/xmake/issues/1689\n    io.writefile(file, content, {encoding = \"utf8\"})\nend\n\nfunction _write_section_PBXFileReference(info, lines)\n    table.insert(lines, \"/* Begin PBXFileReference section */\")\n    for uuid, obj in table.orderpairs(info.sections.PBXFileReference) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" = {\")\n        table.insert(lines, \"\\t\\t\\tisa = PBXFileReference;\")\n        if obj.explicitFileType then\n            table.insert(lines, \"\\t\\t\\texplicitFileType = \\\"\" .. obj.explicitFileType .. \"\\\";\")\n        end\n        if obj.lastKnownFileType then\n            table.insert(lines, \"\\t\\t\\tlastKnownFileType = \\\"\" .. obj.lastKnownFileType .. \"\\\";\")\n        end\n        if obj.includeInIndex then\n            table.insert(lines, \"\\t\\t\\tincludeInIndex = \" .. obj.includeInIndex .. \";\")\n        end\n        if obj.name then\n            table.insert(lines, \"\\t\\t\\tname = \\\"\" .. obj.name .. \"\\\";\")\n        end\n        if obj.path then\n            table.insert(lines, \"\\t\\t\\tpath = \\\"\" .. obj.path .. \"\\\";\")\n        end\n        if obj.sourceTree then\n            table.insert(lines, \"\\t\\t\\tsourceTree = \" .. obj.sourceTree .. \";\")\n        end\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End PBXFileReference section */\")\nend\n\nfunction _write_section_PBXGroup(info, lines)\n    table.insert(lines, \"/* Begin PBXGroup section */\")\n    for uuid, obj in table.orderpairs(info.sections.PBXGroup) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" = {\")\n        table.insert(lines, \"\\t\\t\\tisa = PBXGroup;\")\n        if obj.name then\n            table.insert(lines, \"\\t\\t\\tname = \\\"\" .. obj.name .. \"\\\";\")\n        end\n        table.insert(lines, \"\\t\\t\\tchildren = (\")\n        for _, child in ipairs(obj.children) do\n            local child_obj = info.sections.PBXFileReference[child]\n            if child_obj == nil then\n                child_obj = info.sections.PBXGroup[child]\n            end\n            local child_name\n            if child_obj then\n                child_name = child_obj.name\n            end\n            if child_name == nil then\n                child_name = \"\"\n            end\n            table.insert(lines, \"\\t\\t\\t\\t\" .. child .. \" /* \" .. child_name .. \" */,\")\n        end\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t\\tsourceTree = \\\"\" .. obj.sourceTree .. \"\\\";\")\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End PBXGroup section */\")\nend\n\nfunction _write_section_PBXNativeTarget(info, lines)\n    table.insert(lines, \"/* Begin PBXNativeTarget section */\")\n    for uuid, obj in table.orderpairs(info.sections.PBXNativeTarget) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" /* \" .. obj.name .. \" */ = {\")\n        table.insert(lines, \"\\t\\t\\tisa = PBXNativeTarget;\")\n        table.insert(lines, \"\\t\\t\\tbuildConfigurationList = \" .. obj.buildConfigurationList .. \" /* Build configuration list for PBXNativeTarget \\\"\" .. obj.name .. \"\\\" */;\")\n        table.insert(lines, \"\\t\\t\\tbuildPhases = (\")\n        for _, build_phase_uuid in ipairs(obj.buildPhases) do\n            table.insert(lines, \"\\t\\t\\t\\t\" .. build_phase_uuid .. \",\")\n        end\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t\\tbuildRules = (\")\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t\\tdependencies = (\")\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t\\tname = \" .. obj.name .. \";\")\n        table.insert(lines, \"\\t\\t\\tpackageProductDependencies = (\")\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t\\tproductName = \" .. obj.productName .. \";\")\n        local product_reference_name\n        local product_reference_obj = info.sections.PBXFileReference[obj.productReference]\n        if product_reference_obj then\n            product_reference_name = product_reference_obj.name\n        end\n        if product_reference_name == nil then\n            product_reference_name = \"\"\n        end\n        table.insert(lines, \"\\t\\t\\tproductReference = \" .. obj.productReference .. \" /* \" .. product_reference_name .. \" */;\")\n        table.insert(lines, \"\\t\\t\\tproductType = \" .. obj.productType .. \";\")\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End PBXNativeTarget section */\")\nend\n\nfunction _write_section_PBXProject(info, lines)\n    table.insert(lines, \"/* Begin PBXProject section */\")\n    for uuid, obj in table.orderpairs(info.sections.PBXProject) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" /* Project object */ = {\")\n        table.insert(lines, \"\\t\\t\\tisa = PBXProject;\")\n        table.insert(lines, [[\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t};]])\n        table.insert(lines, \"\\t\\t\\tbuildConfigurationList = \" .. obj.buildConfigurationList .. \" /* Build configuration list for PBXProject */;\")\n        table.insert(lines, [[\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);]])\n        table.insert(lines, \"mainGroup = \" .. obj.mainGroup .. \";\")\n        table.insert(lines, [[\n\t\t\tminimizedProjectReferenceProxies = 1;\n\t\t\tpreferredProjectObjectVersion = 77;]])\n        table.insert(lines, \"productRefGroup = \" .. obj.productRefGroup .. \";\")\n        table.insert(lines, [[\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";]])\n        table.insert(lines, \"\\t\\t\\ttargets = (\")\n        for _, target_uuid in ipairs(obj.targets) do\n            table.insert(lines, \"\\t\\t\\t\\t\" .. target_uuid .. \" /* \" .. info.sections.PBXNativeTarget[target_uuid].name .. \" */,\")\n        end\n        table.insert(lines, \"\\t\\t\\t);\")\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End PBXProject section */\")\nend\n\nfunction _write_section_PBXShellScriptBuildPhase(info, lines)\n    table.insert(lines, \"/* Begin PBXShellScriptBuildPhase section */\")\n    for uuid, obj in table.orderpairs(info.sections.PBXShellScriptBuildPhase) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" /* Run Xmake Build Command */ = {\")\n        table.insert(lines, [[\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Xmake Build\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"]] .. obj.shellScript .. \"\\\";\")\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End PBXShellScriptBuildPhase section */\")\nend\n\nfunction _write_section_XCBuildConfiguration(info, lines)\n    table.insert(lines, \"/* Begin XCBuildConfiguration section */\")\n    for uuid, obj in table.orderpairs(info.sections.XCBuildConfiguration) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" /* \" .. obj.name .. \" */ = {\")\n        table.insert(lines, [[\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {]])\n        for k, v in pairs(obj.buildSettings) do\n            local string_value = \"\"\n            if v == true then\n                string_value = \"YES\"\n            elseif v == false then\n                string_value = \"NO\"\n            elseif type(v) == \"string\" then\n                string_value = v\n            elseif type(v) == \"number\" then\n                string_value = tostring(v)\n            end\n            table.insert(lines, \"\\t\\t\\t\\t\" .. k .. \" = \" .. string_value .. \";\")\n        end\n\t\ttable.insert(lines, [[\n            };\n\t\t\tname = ]] .. obj.name .. \";\")\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End XCBuildConfiguration section */\")\nend\n\nfunction _write_section_XCConfigurationList(info, lines)\n    table.insert(lines, \"/* Begin XCConfigurationList section */\")\n    for uuid, obj in table.orderpairs(info.sections.XCConfigurationList) do\n        table.insert(lines, \"\\t\\t\" .. uuid .. \" = {\")\n        table.insert(lines, [[\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (]])\n        for _, build_config in ipairs(obj.buildConfigurations) do\n            table.insert(lines, \"\\t\\t\\t\\t\" .. build_config .. \" /* \" .. info.sections.XCBuildConfiguration[build_config].name .. \" */,\")\n        end\n        table.insert(lines, [[\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;]])\n        table.insert(lines, \"\\t\\t};\")\n    end\n    table.insert(lines, \"/* End XCConfigurationList section */\")\nend\n\nlocal write_section_funcs = {\n    _write_section_PBXFileReference,\n    _write_section_PBXGroup,\n    _write_section_PBXNativeTarget,\n    _write_section_PBXProject,\n    _write_section_PBXShellScriptBuildPhase,\n    _write_section_XCBuildConfiguration,\n    _write_section_XCConfigurationList\n}\n\nfunction _write_pbxproj(info)\n    local lines = {}\n    table.insert(lines, [[// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n]])\n    -- write sections.\n    for _, write_section in ipairs(write_section_funcs) do\n        write_section(info, lines)\n    end\n\n    table.insert(lines,\n[[\t};\n\trootObject = ]] .. info.root_object .. [[ /* Project object */;\n}]])\n    return table.concat(lines, \"\\n\") .. \"\\n\"\nend\n\nfunction main(info)\n    local content = _write_pbxproj(info)\n    local file_name = path.join(info.project_dir, info.project_bundle, \"project.pbxproj\")\n    _write_file_if_needed(file_name, content)\nend\n"
  },
  {
    "path": "xmake/plugins/project/xcode/xcodeproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JXMaster\n-- @file        xcodeproj.lua\n--\n\n-- imports\nimport(\"get_xcode_info\")\nimport(\"pbxproj\")\n\nfunction make(outputdir)\n\n    -- collect xcode info.\n    -- see get_xcode_info.lua file for detailed description\n    -- of the returned info table.\n    local info = get_xcode_info(outputdir)\n\n    -- create xcode dir.\n    local project_bundle = path.join(info.project_dir, info.project_bundle)\n    os.mkdir(project_bundle)\n\n    -- create .pbxproj file.\n    pbxproj(info)\nend\n"
  },
  {
    "path": "xmake/plugins/project/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define task\ntask(\"project\")\n\n    -- set category\n    set_category(\"plugin\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake project [options] [outputdir]\"\n\n                -- description\n            ,   description = \"Generate the project file.\"\n\n                -- options\n            ,   options =\n                {\n                    {'k', \"kind\",      \"kv\" , \"makefile\",   \"Set the project kind.\"\n                                                        ,   \"    - make\"\n                                                        ,   \"    - xmakefile (makefile with xmake)\"\n                                                        ,   \"    - cmake\"\n                                                        ,   \"    - ninja\"\n                                                        ,   \"    - xcode\"\n                                                        ,   \"    - compile_flags\"\n                                                        ,   \"    - compile_commands (clang compilation database with json format)\"\n                                                        ,   \"    - vs (auto detect), vs2002 - vs2026\"\n                                                        ,   \"    - vsxmake (auto detect), vsxmake2010 ~ vsxmake2026\"\n                                                        ,   values = function (complete, opt)\n                                                                if not complete then return end\n\n                                                                local values = table.keys(import(\"main.makers\")())\n                                                                table.sort(values, function (a, b) return a > b end)\n                                                                return values\n                                                            end                                                                             }\n                ,   {'m', \"modes\",     \"kv\" , nil       ,   \"Set the project modes.\"\n                                                        ,   \"    e.g. \"\n                                                        ,   \"    - xmake project -k vsxmake -m \\\"release,debug\\\"\"                           }\n                ,   {'a', \"archs\",     \"kv\" , nil       ,   \"Set the project archs.\"\n                                                        ,   \"    e.g. \"\n                                                        ,   \"    - xmake project -k vsxmake -a \\\"x86,x64\\\"\"                                 }\n                ,   {'t', \"target\",    \"kv\" , nil       ,   \"Set the project target.\"\n                                                        ,   \"    e.g. \"\n                                                        ,   \"    - xmake project -k compile_commands -t \\\"custom\\\"\"                            }\n                ,   {nil, \"lsp\",       \"kv\" , nil       ,   \"Set the LSP backend for compile_commands.\"\n                                                        ,   \"    e.g. \"\n                                                        ,   \"    - xmake project -k compile_commands --lsp=clangd\"\n                                                        ,   values = {\"clangd\", \"cpptools\", \"ccls\"}}\n                ,   {nil, \"outputdir\", \"v\"  , \".\"       ,   \"Set the output directory.\"                                                     }\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/plugins/repo/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.package.repository\")\nimport(\"devel.git\")\nimport(\"net.proxy\")\nimport(\"async.runjobs\")\nimport(\"private.action.require.impl.environment\")\nimport(\"private.service.remote_build.action\", {alias = \"remote_build_action\"})\n\nfunction _clear_quick_search_cache(is_global)\n    if is_global then\n        import(\"private.xrepo.quick_search.cache\")\n        cache.clear()\n    end\nend\n\n-- add repository url\nfunction _add(name, url, branch, is_global)\n\n    -- remove previous repository if exists\n    local repodir = path.join(repository.directory(is_global), name)\n    if os.isdir(repodir) then\n        os.rmdir(repodir)\n    end\n\n    -- enter environment\n    environment.enter()\n\n    -- clone repository\n    if not os.isdir(url) then\n        local remoteurl = proxy.mirror(url) or url\n        git.clone(remoteurl, {verbose = option.get(\"verbose\"), branch = branch, outputdir = repodir, autocrlf = false})\n    end\n\n    -- add url\n    repository.add(name, url, branch, is_global)\n\n    -- trace\n    cprint(\"${color.success}add %s repository(%s): %s%s ok!\", (is_global and \"global\" or \"local\"), name, url, branch and (\" \" .. branch) or \"\")\n\n    -- leave environment\n    environment.leave()\n\n    -- clear quick search cache\n    _clear_quick_search_cache(is_global)\nend\n\n-- remove repository url\nfunction _remove(name, is_global)\n\n    -- remove url\n    repository.remove(name, is_global)\n\n    -- remove repository\n    local repodir = path.join(repository.directory(is_global), name)\n    if os.isdir(repodir) then\n        os.rmdir(repodir)\n    end\n\n    -- clear quick search cache\n    _clear_quick_search_cache(is_global)\n    cprint(\"${bright}remove %s repository(%s): ok!\", (is_global and \"global\" or \"local\"), name)\nend\n\n-- update repositories\nfunction _update()\n\n    -- enter environment\n    environment.enter()\n\n    -- trace\n    local name = option.get(\"name\")\n    if name then\n        cprintf(\"updating repository ${bright}%s${clear} .. \", name)\n    else\n        printf(\"updating repositories .. \")\n    end\n    if option.get(\"verbose\") then\n        print(\"\")\n    end\n\n    -- create a pull task\n    local task = function ()\n\n        -- get all repositories (local first)\n        local repos = table.join(repository.repositories({global = false}), repository.repositories({global = true}))\n        if name then\n            for _, repo in ipairs(repos) do\n                if repo:name() == name then\n                    repos = {repo}\n                    break\n                end\n            end\n        end\n\n        -- pull all repositories\n        local pulled = {}\n        for _, repo in ipairs(repos) do\n            local repodir = repo:directory()\n            if not pulled[repodir] then\n                if os.isdir(repodir) then\n                    -- only update the local repository with the remote url\n                    if not os.isdir(repo:url()) then\n                        -- check and update remote URL if it differs from repo:url()\n                        local current_url = git.remote.get_url({repodir = repodir})\n                        local expected_url = repo:url()\n                        if current_url ~= expected_url then\n                            vprint(\"updating remote URL for repository(%s): %s -> %s\", repo:name(), current_url or \"<none>\", expected_url)\n                            git.remote.set_url(expected_url, {repodir = repodir})\n                        end\n                        vprint(\"pulling repository(%s): %s to %s ..\", repo:name(), repo:url(), repodir)\n                        git.reset({verbose = option.get(\"verbose\"), repodir = repodir, hard = true})\n                        git.pull({verbose = option.get(\"verbose\"), branch = repo:branch(), repodir = repodir, force = true})\n                        io.save(path.join(repodir, \"updated\"), {})\n                    end\n                else\n                    vprint(\"cloning repository(%s): %s to %s ..\", repo:name(), repo:url(), repodir)\n                    local remoteurl = proxy.mirror(repo:url()) or repo:url()\n                    git.clone(remoteurl, {verbose = option.get(\"verbose\"), branch = repo:branch(), outputdir = repodir, autocrlf = false})\n                    io.save(path.join(repodir, \"updated\"), {})\n                end\n                pulled[repodir] = true\n            end\n        end\n\n        -- clear quick search cache\n        _clear_quick_search_cache(true)\n    end\n\n    -- pull repositories\n    if option.get(\"verbose\") then\n        task()\n    else\n        runjobs(\"update repo\", task, {waiting_indicator = true, isolate = true})\n    end\n\n    -- leave environment\n    environment.leave()\n    cprint(\"${green}ok\")\nend\n\n-- clear all repositories\nfunction _clear(is_global)\n\n    -- clear all urls\n    repository.clear(is_global)\n\n    -- remove all repositories\n    local repodir = repository.directory(is_global)\n    if os.isdir(repodir) then\n        os.rmdir(repodir)\n    end\n\n    -- clear quick search cache\n    _clear_quick_search_cache(is_global)\n    cprint(\"${color.success}clear %s repositories: ok!\", (is_global and \"global\" or \"local\"))\nend\n\n-- list all repositories\nfunction _list(is_global)\n    local count = 0\n    for _, position in ipairs(is_global and \"global\" or {\"local\", \"global\"}) do\n        print(\"%s repositories:\", position)\n        for _, repo in pairs(repository.repositories({global = position == \"global\"})) do\n            print(\"    %s %s%s\", repo:name(), repo:url(), repo:branch() and (\" \" .. repo:branch()) or \"\")\n            count = count + 1\n        end\n        print(\"\")\n    end\n    print(\"%d repositories were found!\", count)\nend\n\n-- get the repository directory\nfunction _directory(is_global)\n    print(repository.directory(is_global))\nend\n\n-- load project\nfunction _load_project()\n\n    -- enter project directory\n    os.cd(project.directory())\n\n    -- load config\n    config.load()\n\n    -- load platform\n    platform.load(config.plat())\nend\n\n-- main\nfunction main()\n\n    -- do action for remote?\n    if remote_build_action.enabled() then\n        return remote_build_action()\n    end\n\n    -- load project if operate local repositories\n    if not option.get(\"global\") then\n        _load_project()\n    end\n\n    -- add repository url\n    if option.get(\"add\") then\n\n        _add(option.get(\"name\"), option.get(\"url\"), option.get(\"branch\"), option.get(\"global\"))\n\n    -- remove repository url\n    elseif option.get(\"remove\") then\n\n        _remove(option.get(\"name\"), option.get(\"global\"))\n\n    -- update repository url\n    elseif option.get(\"update\") then\n\n        _update()\n\n    -- clear all repositories\n    elseif option.get(\"clear\") then\n\n        _clear(option.get(\"global\"))\n\n    -- list all repositories\n    elseif option.get(\"list\") then\n\n        _list(option.get(\"global\"))\n\n    -- show repo directory\n    else\n        _directory(option.get(\"global\"))\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/repo/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        repo.lua\n--\n\n-- define task\ntask(\"repo\")\n\n    -- set category\n    set_category(\"plugin\")\n\n    -- on run\n    on_run(\"main\")\n\n    -- set menu\n    set_menu {\n                -- usage\n                usage = \"xmake repo [options] [name] [url] [branch]\"\n\n                -- description\n            ,   description = \"Manage package repositories.\"\n\n                -- options\n            ,   options =\n                {\n                    {'a', \"add\",    \"k\",  nil,       \"Add the given remote repository url.\"           }\n                ,   {'r', \"remove\", \"k\",  nil,       \"Remove the given remote repository url.\"        }\n                ,   {'u', \"update\", \"k\",  nil,       \"Update all local repositories from the remote.\" }\n                ,   {'c', \"clear\",  \"k\",  nil,       \"Clear all added repositories.\"                  }\n                ,   {                                                                                 }\n                ,   {'l', \"list\",   \"k\",  nil,       \"List all added repositories.\"                   }\n                ,   {'g', \"global\", \"k\",  nil,       \"Save repository to global. (default: local)\"    }\n                ,   {                                                                                 }\n                ,   {nil, \"name\",   \"v\", nil,        \"The repository name.\"                           }\n                ,   {nil, \"url\",    \"v\", nil,        \"The repository url\"                             }\n                ,   {nil, \"branch\", \"v\", nil,        \"The repository branch\"                          }\n                }\n    }\n"
  },
  {
    "path": "xmake/plugins/show/info/basic.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        basic.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.base.json\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.package.package\")\n\nfunction _show_xmake_info(opt, result)\n    local json_enabled = opt and opt.json\n    local info = {\n        version = tostring(xmake.version()),\n        host = {os = os.host(), arch = os.arch()},\n        programdir = xmake.programdir(),\n        programfile = xmake.programfile(),\n        globaldir = global.directory(),\n        tmpdir = os.tmpdir(),\n        workingdir = os.workingdir(),\n        packagedir = package.installdir(),\n        packagedir_cache = package.cachedir()\n    }\n    if json_enabled then\n        result = result or {}\n        result.xmake = info\n    else\n        print(\"The information of xmake:\")\n        cprint(\"    ${color.dump.string}version${clear}: %s\", info.version)\n        cprint(\"    ${color.dump.string}host${clear}: %s/%s\", info.host.os, info.host.arch)\n        cprint(\"    ${color.dump.string}programdir${clear}: %s\", info.programdir)\n        cprint(\"    ${color.dump.string}programfile${clear}: %s\", info.programfile)\n        cprint(\"    ${color.dump.string}globaldir${clear}: %s\", info.globaldir)\n        cprint(\"    ${color.dump.string}tmpdir${clear}: %s\", info.tmpdir)\n        cprint(\"    ${color.dump.string}workingdir${clear}: %s\", info.workingdir)\n        cprint(\"    ${color.dump.string}packagedir${clear}: %s\", info.packagedir)\n        cprint(\"    ${color.dump.string}packagedir(cache)${clear}: %s\", info.packagedir_cache)\n        print(\"\")\n    end\n    return result\nend\n\nfunction _show_project_info(opt, result)\n    local json_enabled = opt and opt.json\n    local projectfile = os.projectfile()\n    if not os.isfile(projectfile) then\n        return result\n    end\n\n    local info = {\n        configdir = config.directory(),\n        projectdir = os.projectdir(),\n        projectfile = projectfile\n    }\n    local name = project.name()\n    if name then\n        info.name = name\n    end\n    local project_version = project.version()\n    if project_version ~= nil then\n        info.version = tostring(project_version)\n    end\n    local plat = config.plat()\n    if plat then\n        info.plat = plat\n    end\n    local arch = config.arch()\n    if arch then\n        info.arch = arch\n    end\n    local mode = config.mode()\n    if mode then\n        info.mode = mode\n    end\n    local builddir = config.builddir()\n    if builddir then\n        info.builddir = builddir\n    end\n\n    if json_enabled then\n        result = result or {}\n        result.project = info\n    else\n        print(\"The information of project: %s\", info.name or \"\")\n        if info.version then\n            cprint(\"    ${color.dump.string}version${clear}: %s\", info.version)\n        end\n        if info.plat then\n            cprint(\"    ${color.dump.string}plat${clear}: %s\", info.plat)\n        end\n        if info.arch then\n            cprint(\"    ${color.dump.string}arch${clear}: %s\", info.arch)\n        end\n        if info.mode then\n            cprint(\"    ${color.dump.string}mode${clear}: %s\", info.mode)\n        end\n        if info.builddir then\n            cprint(\"    ${color.dump.string}builddir${clear}: %s\", info.builddir)\n        end\n        cprint(\"    ${color.dump.string}configdir${clear}: %s\", info.configdir)\n        cprint(\"    ${color.dump.string}projectdir${clear}: %s\", info.projectdir)\n        cprint(\"    ${color.dump.string}projectfile${clear}: %s\", info.projectfile)\n        print(\"\")\n    end\n    return result\nend\n\n-- show basic info\nfunction main()\n\n    config.load()\n\n    local opt = {\n        json = option.get(\"json\"),\n        pretty = option.get(\"pretty\")\n    }\n    local result = opt.json and {} or nil\n\n    result = _show_xmake_info(opt, result)\n    result = _show_project_info(opt, result)\n\n    if opt.json then\n        local json_opt\n        if opt.pretty then\n            json_opt = {pretty = true, orderkeys = true}\n        end\n        print(json.encode(result or {}, json_opt))\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/info/target.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.json\")\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\nimport(\"core.language.language\")\nimport(\"private.detect.check_targetname\")\n\n-- get source info data\nfunction _get_sourceinfo(target, name, item, opt)\n    opt = opt or {}\n    local sourceinfo = target:sourceinfo(name, item)\n    local tips = opt.tips\n    if sourceinfo then\n        return {\n            file = sourceinfo.file,\n            line = sourceinfo.line,\n            tips = tips\n        }\n    elseif tips then\n        return {tips = tips}\n    end\nend\n\n-- format source info string with color\nfunction _format_sourceinfo(sourceinfo)\n    if not sourceinfo then\n        return \"\"\n    end\n    local tips = sourceinfo.tips\n    if tips then\n        tips = tips .. \" -> \"\n    end\n    if sourceinfo.file then\n        return string.format(\" ${dim}-> %s%s:%s${clear}\", tips or \"\", sourceinfo.file or \"\", sourceinfo.line or -1)\n    elseif tips then\n        return string.format(\" ${dim}-> %s${clear}\", tips)\n    end\n    return \"\"\nend\n\n-- get source info string\nfunction _get_sourceinfo_str(target, name, item, opt)\n    return _format_sourceinfo(_get_sourceinfo(target, name, item, opt))\nend\n\n-- get values from target options\nfunction _get_values_from_opts(target, name)\n    local values = {}\n    for _, opt_ in ipairs(target:orderopts()) do\n        for _, value in ipairs(opt_:get(name)) do\n            local tips = string.format(\"option(%s)\", opt_:name())\n            values[value] = _get_sourceinfo(opt_, name, value, {tips = tips})\n        end\n    end\n    return values\nend\n\n-- get values from target packages\nfunction _get_values_from_pkgs(target, name)\n    local values = {}\n    for _, pkg in ipairs(target:orderpkgs()) do\n        local configinfo = target:pkgconfig(pkg:name())\n        -- get values from package components\n        -- e.g. `add_packages(\"sfml\", {components = {\"graphics\", \"window\"}})`\n        local selected_components = configinfo and configinfo.components or pkg:components_default()\n        if selected_components and pkg:components() then\n            local components_enabled = hashset.new()\n            for _, comp in ipairs(table.wrap(selected_components)) do\n                components_enabled:insert(comp)\n                for _, dep in ipairs(table.wrap(pkg:component_orderdeps(comp))) do\n                    components_enabled:insert(dep)\n                end\n            end\n            components_enabled:insert(\"__base\")\n            -- if we can't find the values from the component, we need to fall back to __base to find them.\n            -- it contains some common values of all components\n            local components = table.wrap(pkg:components())\n            for _, component_name in ipairs(table.join(pkg:components_orderlist(), \"__base\")) do\n                if components_enabled:has(component_name) then\n                    local info = components[component_name]\n                    if info then\n                        for _, value in ipairs(info[name]) do\n                            local tips = string.format(\"package(%s)\", pkg:fullname())\n                            values[value] = {tips = tips}\n                        end\n                    else\n                        local components_str = table.concat(table.wrap(configinfo.components), \", \")\n                        utils.warning(\"unknown component(%s) in add_packages(%s, {components = {%s}})\", component_name, pkg:fullname(), components_str)\n                    end\n                end\n            end\n        -- get values instead of the builtin configs if exists extra package config\n        -- e.g. `add_packages(\"xxx\", {links = \"xxx\"})`\n        elseif configinfo and configinfo[name] then\n            for _, value in ipairs(configinfo[name]) do\n                local sourceinfo = _get_sourceinfo(target, \"packages\", pkg:name())\n                values[value] = sourceinfo\n            end\n        else\n            -- get values from the builtin package configs\n            for _, value in ipairs(pkg:get(name)) do\n                local tips = string.format(\"package(%s)\", pkg:fullname())\n                values[value] = {tips = tips}\n            end\n        end\n    end\n    return values\nend\n\n-- get values from target dependencies\nfunction _get_values_from_deps(target, name)\n    local values = {}\n    local orderdeps = target:orderdeps()\n    local total = #orderdeps\n    for idx, _ in ipairs(orderdeps) do\n        local dep = orderdeps[total + 1 - idx]\n        local depinherit = target:extraconf(\"deps\", dep:name(), \"inherit\")\n        if depinherit == nil or depinherit then\n            for _, value in ipairs(dep:get(name, {interface = true})) do\n                local tips = string.format(\"dep(%s)\", dep:name())\n                values[value] = {tips = tips}\n            end\n            local values_chunks = dep:get_from(name, \"option::*\", {interface = true})\n            for _, values_chunk in ipairs(values_chunks) do\n                for _, value in ipairs(values_chunk) do\n                    local tips = string.format(\"dep(%s) -> options\", dep:name())\n                    values[value] = {tips = tips}\n                end\n            end\n            values_chunks = dep:get_from(name, \"package::*\", {interface = true})\n            for _, values_chunk in ipairs(values_chunks) do\n                for _, value in ipairs(values_chunk) do\n                    local tips = string.format(\"dep(%s) -> packages\", dep:name())\n                    values[value] = {tips = tips}\n                end\n            end\n        end\n    end\n    return values\nend\n\nfunction _collect_target_info(target)\n    local info = {\n        name = target:name(),\n        at = path.join(target:scriptdir(), \"xmake.lua\"),\n        kind = target:kind()\n    }\n    local targetfile = target:targetfile()\n    if targetfile then\n        info.targetfile = targetfile\n    end\n    local deps = target:get(\"deps\")\n    if deps then\n        local entries = {}\n        for _, dep in ipairs(deps) do\n        local entry = {name = dep, source = _get_sourceinfo(target, \"deps\", dep)}\n        table.insert(entries, entry)\n        end\n        if #entries > 0 then\n            info.deps = entries\n        end\n    end\n    local rules = target:get(\"rules\")\n    if rules then\n        local entries = {}\n        for _, value in ipairs(rules) do\n        local entry = {name = value, source = _get_sourceinfo(target, \"rules\", value)}\n        table.insert(entries, entry)\n        end\n        if #entries > 0 then\n            info.rules = entries\n        end\n    end\n    local options = {}\n    for _, opt in ipairs(target:get(\"options\")) do\n        if not opt:startswith(\"__\") then\n            table.insert(options, opt)\n        end\n    end\n    if #options > 0 then\n        local entries = {}\n        for _, value in ipairs(options) do\n        table.insert(entries, {name = value, source = _get_sourceinfo(target, \"options\", value)})\n        end\n        if #entries > 0 then\n            info.options = entries\n        end\n    end\n    local packages = target:get(\"packages\")\n    if packages then\n        local entries = {}\n        for _, value in ipairs(packages) do\n            table.insert(entries, {name = value, source = _get_sourceinfo(target, \"packages\", value)})\n        end\n        if #entries > 0 then\n            info.packages = entries\n        end\n    end\n    info.api_entries = {}\n    for _, apiname in ipairs(table.join(language.apis().values, language.apis().paths)) do\n        if apiname:startswith(\"target.\") then\n            local valuename = apiname:split('.add_', {plain = true})[2]\n            if valuename then\n                local results = {}\n                local values = table.unique(table.wrap(target:get(valuename)))\n                if #values > 0 then\n                    for _, value in ipairs(values) do\n                        local sourceinfo = _get_sourceinfo(target, valuename, value)\n                table.insert(results, {value = value, source = sourceinfo})\n                    end\n                end\n                local values_from_opts = _get_values_from_opts(target, valuename)\n                for value, sourceinfo in pairs(values_from_opts) do\n                    table.insert(results, {value = value, source = sourceinfo})\n                end\n                local values_from_pkgs = _get_values_from_pkgs(target, valuename)\n                for value, sourceinfo in pairs(values_from_pkgs) do\n                    table.insert(results, {value = value, source = sourceinfo})\n                end\n                local values_from_deps = _get_values_from_deps(target, valuename)\n                for value, sourceinfo in pairs(values_from_deps) do\n                    table.insert(results, {value = value, source = sourceinfo})\n                end\n                if #results > 0 then\n                    local entries = {}\n                    for _, result in ipairs(results) do\n                        table.insert(entries, result)\n                    end\n                    info[valuename] = entries\n                    table.insert(info.api_entries, {name = valuename, entries = entries})\n                end\n            end\n        end\n    end\n    local files = target:get(\"files\")\n    if files then\n        local entries = {}\n        for _, file in ipairs(files) do\n            if not file:startswith(\"__remove_\") then\n                table.insert(entries, {path = file, source = _get_sourceinfo(target, \"files\", file)})\n            end\n        end\n        if #entries > 0 then\n            info.files = entries\n        end\n    end\n    local sourcekinds = hashset.new()\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        if sourcebatch.sourcekind then\n            sourcekinds:insert(sourcebatch.sourcekind)\n        end\n    end\n    for _, sourcekind in sourcekinds:keys() do\n        local compinst = target:compiler(sourcekind)\n        if compinst then\n            info.compilers = info.compilers or {}\n            table.insert(info.compilers, {\n                sourcekind = sourcekind,\n                program = compinst:program(),\n                flags = os.args(compinst:compflags()),\n                flags_with_target = os.args(compinst:compflags({target = target}))\n            })\n        end\n    end\n    local linker = targetfile and target:linker()\n    if linker then\n        info.linker = {\n            kind = linker:kind(),\n            program = linker:program(),\n            flags = os.args(linker:linkflags()),\n            flags_with_target = os.args(linker:linkflags({target = target}))\n        }\n    end\n    return info\nend\n\nfunction _print_entries(label, items, formatter)\n    if not items or #items == 0 then\n        return\n    end\n    cprint(\"    ${color.dump.string}%s${clear}:\", label)\n    for _, item in ipairs(items) do\n        local text, source = formatter(item)\n        cprint(\"      ${color.dump.reference}->${clear} %s%s\", text, source or \"\")\n    end\nend\n\nfunction _print_target_info(info)\n    print(\"The information of target(%s):\", info.name)\n    cprint(\"    ${color.dump.string}at${clear}: %s\", info.at)\n    cprint(\"    ${color.dump.string}kind${clear}: %s\", info.kind)\n    if info.targetfile then\n        cprint(\"    ${color.dump.string}targetfile${clear}: %s\", info.targetfile)\n    end\n    _print_entries(\"deps\", info.deps, function(item)\n        return item.name, _format_sourceinfo(item.source)\n    end)\n    _print_entries(\"rules\", info.rules, function(item)\n        return item.name, _format_sourceinfo(item.source)\n    end)\n    _print_entries(\"options\", info.options, function(item)\n        return item.name, _format_sourceinfo(item.source)\n    end)\n    _print_entries(\"packages\", info.packages, function(item)\n        return item.name, _format_sourceinfo(item.source)\n    end)\n    if info.api_entries then\n        for _, entry in ipairs(info.api_entries) do\n            _print_entries(entry.name, entry.entries, function(item)\n                local source = _format_sourceinfo(item.source)\n                return item.value, source\n            end)\n        end\n    end\n    if info.files then\n        _print_entries(\"files\", info.files, function(item)\n            return item.path, _format_sourceinfo(item.source)\n        end)\n    end\n    if info.compilers then\n        for _, compiler in ipairs(info.compilers) do\n            cprint(\"    ${color.dump.string}compiler (%s)${clear}: %s\", compiler.sourcekind, compiler.program)\n            if compiler.flags then\n                cprint(\"      ${color.dump.reference}->${clear} %s\", compiler.flags)\n            end\n        end\n        for _, compiler in ipairs(info.compilers) do\n            cprint(\"    ${color.dump.string}compflags (%s)${clear}:\", compiler.sourcekind)\n            cprint(\"      ${color.dump.reference}->${clear} %s\", compiler.flags_with_target)\n        end\n    end\n    if info.linker then\n        cprint(\"    ${color.dump.string}linker (%s)${clear}: %s\", info.linker.kind, info.linker.program)\n        cprint(\"      ${color.dump.reference}->${clear} %s\", info.linker.flags)\n        cprint(\"    ${color.dump.string}linkflags (%s)${clear}:\", info.linker.kind)\n        cprint(\"      ${color.dump.reference}->${clear} %s\", info.linker.flags_with_target)\n    end\nend\n\nfunction main(name)\n\n    -- get target\n    config.load()\n    local opt = {\n        json = option.get(\"json\"),\n        pretty = option.get(\"pretty\")\n    }\n    local target = assert(check_targetname(name))\n\n    local info = _collect_target_info(target)\n    if opt.json then\n        info.api_entries = nil\n        local json_opt\n        if opt.pretty then\n            json_opt = {pretty = true, orderkeys = true}\n        end\n        print(json.encode(info or {}, json_opt))\n    else\n        _print_target_info(info)\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/list.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        list.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- get all list values\nfunction lists()\n    local values = {}\n    for _, filepath in ipairs(os.files(path.join(os.scriptdir(), \"lists\", \"*.lua\"))) do\n        table.insert(values, path.basename(filepath))\n    end\n    return values\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/apis.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        apis.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.rule\")\nimport(\"core.project.target\")\nimport(\"core.project.project\")\nimport(\"core.project.option\")\nimport(\"core.package.package\")\nimport(\"core.language.language\")\nimport(\"core.sandbox.sandbox\")\nimport(\"core.sandbox.module\")\nimport(\"core.tool.toolchain\")\nimport(\"core.base.interpreter\")\nimport(\".showlist\")\n\nfunction _is_callable(func)\n    if type(func) == \"function\" then\n        return true\n    elseif type(func) == \"table\" then\n        local meta = debug.getmetatable(func)\n        if meta and meta.__call then\n            return true\n        end\n    end\nend\n\n-- get target description scope apis\nfunction description_target_scope_apis()\n    local result = {}\n    for _, names in pairs(target.apis()) do\n        for _, name in ipairs(names) do\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get language description scope apis\nfunction description_language_scope_apis()\n    local result = {}\n    for _, names in pairs(language.apis()) do\n        for _, name in ipairs(names) do\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get option description scope apis\nfunction description_option_scope_apis()\n    local result = {}\n    for _, names in pairs(option.apis()) do\n        for _, name in ipairs(names) do\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get rule description scope apis\nfunction description_rule_scope_apis()\n    local result = {}\n    for _, names in pairs(rule.apis()) do\n        for _, name in ipairs(names) do\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get package description scope apis\nfunction description_package_scope_apis()\n    local result = {}\n    for _, names in pairs(package.apis()) do\n        for _, name in ipairs(names) do\n            if type(name) == \"table\" then\n                name = \"package.\" .. name[1]\n            end\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get toolchain description scope apis\nfunction description_toolchain_scope_apis()\n    local result = {}\n    for _, names in pairs(toolchain.apis()) do\n        for _, name in ipairs(names) do\n            table.insert(result, name)\n        end\n    end\n    return result\nend\n\n-- get description scope apis\nfunction description_scope_apis()\n    local result = {}\n    table.join2(result, description_target_scope_apis())\n    table.join2(result, description_option_scope_apis())\n    table.join2(result, description_language_scope_apis())\n    table.join2(result, description_rule_scope_apis())\n    table.join2(result, description_package_scope_apis())\n    table.join2(result, description_toolchain_scope_apis())\n    table.sort(result)\n    return result\nend\n\n-- get description builtin apis\nfunction description_builtin_apis()\n    -- add builtin interpreter apis\n    local builtin_module_apis = table.clone(interpreter.builtin_modules())\n    builtin_module_apis.pairs = nil\n    builtin_module_apis.ipairs = nil\n    local result = {}\n    for name, value in pairs(builtin_module_apis) do\n        if type(value) == \"function\" then\n            table.insert(result, name)\n        end\n    end\n    table.insert(result, \"ipairs\")\n    table.insert(result, \"pairs\")\n    table.insert(result, \"includes\")\n    table.insert(result, \"set_xmakever\")\n\n    -- add root project apis\n    for _, names in pairs(project.apis()) do\n        for _, name in ipairs(names) do\n            if type(name) == \"table\" then\n                name = name[1]\n            end\n            table.insert(result, name)\n        end\n    end\n    table.sort(result)\n    return result\nend\n\n-- get description builtin module apis\nfunction description_builtin_module_apis()\n    local builtin_module_apis = table.clone(interpreter.builtin_modules())\n    builtin_module_apis.pairs = nil\n    builtin_module_apis.ipairs = nil\n    local result = {}\n    for name, value in pairs(builtin_module_apis) do\n        if type(value) == \"table\" then\n            for k, v in pairs(value) do\n                if not k:startswith(\"_\") and type(v) == \"function\" then\n                    table.insert(result, name .. \".\" .. k)\n                end\n            end\n        end\n    end\n    table.sort(result)\n    return result\nend\n\n-- get script target instance apis\nfunction script_target_instance_apis()\n    local result = {}\n    local instance = target.new()\n    for k, v in pairs(instance) do\n        if not k:startswith(\"_\") and type(v) == \"function\" then\n            table.insert(result, \"target:\" .. k)\n        end\n    end\n    return result\nend\n\n-- get script option instance apis\nfunction script_option_instance_apis()\n    local result = {}\n    local instance = option.new()\n    for k, v in pairs(instance) do\n        if not k:startswith(\"_\") and type(v) == \"function\" then\n            table.insert(result, \"option:\" .. k)\n        end\n    end\n    return result\nend\n\n-- get script rule instance apis\nfunction script_rule_instance_apis()\n    local result = {}\n    local instance = rule.new()\n    for k, v in pairs(instance) do\n        if not k:startswith(\"_\") and type(v) == \"function\" then\n            table.insert(result, \"rule:\" .. k)\n        end\n    end\n    return result\nend\n\n-- get script toolchain instance apis\nfunction script_toolchain_instance_apis()\n    local result = {}\n    local instance = toolchain.load(\"clang\")\n    for k, v in pairs(instance) do\n        if not k:startswith(\"_\") and type(v) == \"function\" then\n            table.insert(result, \"toolchain:\" .. k)\n        end\n    end\n    return result\nend\n\n-- get script package instance apis\nfunction script_package_instance_apis()\n    local result = {}\n    local instance = package.new()\n    for k, v in pairs(instance) do\n        if not k:startswith(\"_\") and type(v) == \"function\" then\n            table.insert(result, \"package:\" .. k)\n        end\n    end\n    return result\nend\n\n-- get script instance apis\nfunction script_instance_apis()\n    local result = {}\n    table.join2(result, script_target_instance_apis())\n    table.join2(result, script_option_instance_apis())\n    table.join2(result, script_rule_instance_apis())\n    table.join2(result, script_package_instance_apis())\n    table.join2(result, script_toolchain_instance_apis())\n    table.sort(result)\n    return result\nend\n\n-- get script builtin apis\nfunction script_builtin_apis()\n    local builtin_module_apis = table.clone(sandbox.builtin_modules())\n    builtin_module_apis.pairs = nil\n    builtin_module_apis.ipairs = nil\n    local result = {}\n    for name, value in pairs(builtin_module_apis) do\n        if type(value) == \"function\" then\n            table.insert(result, name)\n        end\n    end\n    table.insert(result, \"ipairs\")\n    table.insert(result, \"pairs\")\n    table.sort(result)\n    return result\nend\n\n-- get script builtin module apis\nfunction script_builtin_module_apis()\n    local builtin_module_apis = table.clone(sandbox.builtin_modules())\n    builtin_module_apis.pairs = nil\n    builtin_module_apis.ipairs = nil\n    local result = {}\n    for name, value in pairs(builtin_module_apis) do\n        if type(value) == \"table\" then\n            for k, v in pairs(value) do\n                if not k:startswith(\"_\") and type(v) == \"function\" then\n                    table.insert(result, name .. \".\" .. k)\n                end\n            end\n        end\n    end\n    table.sort(result)\n    return result\nend\n\n-- get script extension modules\nfunction script_extension_module_apis()\n    local result = {}\n    local moduledirs = module.directories()\n    for _, moduledir in ipairs(moduledirs) do\n        moduledir = path.absolute(moduledir)\n        local modulefiles = os.files(path.join(moduledir, \"**.lua|**/xmake.lua|private/**.lua|core/tools/**.lua|detect/tools/**.lua\"))\n        if modulefiles then\n            for _, modulefile in ipairs(modulefiles) do\n                local modulename = path.relative(modulefile, moduledir)\n                if path.filename(modulename) == \"main.lua\" then\n                    modulename = path.directory(modulename)\n                end\n                modulename = modulename:gsub(\"[\\\\/]\", \".\"):gsub(\"%.lua$\", \"\")\n                -- skip luajit modules in non-luajit runtime\n                if not xmake.luajit() and modulename:find(\"luajit%.\") then\n                    -- skip this module\n                else\n                    local instance = import(modulename, {try = true, anonymous = true})\n                    if instance then\n                        if _is_callable(instance) then\n                            table.insert(result, modulename)\n                        elseif type(instance) == \"table\" then\n                            for k, v in pairs(instance) do\n                                if not k:startswith(\"_\") and type(v) == \"function\" then\n                                    table.insert(result, modulename .. \".\" .. k)\n                                end\n                            end\n                        end\n                    end\n                end\n            end\n        end\n    end\n    table.sort(result)\n    return result\nend\n\n-- get all apis\n--\n-- the api kind:\n--  - description\n--    - builtin api\n--    - builtin module api\n--    - scope api\n--  - script\n--    - builtin api\n--    - builtin module api\n--    - extension module api\n--    - instance api\nfunction apis()\n    return {description_scope_apis = description_scope_apis(),\n            description_builtin_apis = description_builtin_apis(),\n            description_builtin_module_apis = description_builtin_module_apis(),\n            script_builtin_apis = script_builtin_apis(),\n            script_builtin_module_apis = script_builtin_module_apis(),\n            script_extension_module_apis = script_extension_module_apis(),\n            script_instance_apis = script_instance_apis()\n        }\nend\n\n-- show all apis\nfunction main()\n    config.load()\n    local result = apis()\n    if result then\n        showlist(result)\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/architectures.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        platforms.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\"core.base.text\")\nimport(\"core.base.option\")\nimport(\".showlist\")\n\n-- show all platforms\nfunction main()\n\n    -- get all platforms\n    local plats = try {function () return project.allowed_plats() end}\n    if plats then\n        plats = plats:to_array()\n    end\n    plats = plats or platform.plats()\n\n    -- get all architectures\n    local result = {align = 'l', sep = \" \"}\n    local json_result = {}\n    for i, plat in ipairs(plats) do\n        local archs = try {function () return project.allowed_archs(plat) end}\n        if archs then\n            archs = archs:to_array()\n        end\n        if not archs then\n            archs = platform.archs(plat)\n        end\n        if archs and #archs > 0 then\n            table.insert(result, table.join(plat, archs))\n            json_result[plat] = archs\n        end\n    end\n    if option.get(\"json\") then\n        showlist(json_result)\n    else\n        print(text.table(result))\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/buildmodes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        buildmodes.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.project.rule\")\nimport(\".showlist\")\n\n-- show all platforms\nfunction main()\n    config.load()\n    local modes = {}\n\n    -- prioritize project modes\n    local project_modes = nil\n    if os.isfile(os.projectfile()) then\n        project_modes = project.modes()\n    end\n    if project_modes and #project_modes > 0 then\n        modes = project_modes\n    else\n        -- fallback to rule modes\n        for _, r in pairs(rule.rules()) do\n            local rulename = r:name()\n            if rulename:startswith(\"mode.\") then\n                table.insert(modes, rulename:sub(6)) -- remove \"mode.\" prefix\n            end\n        end\n    end\n    showlist(modes)\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/envs.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        envs.lua\n--\n\n-- imports\nimport(\"core.base.text\")\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\n-- show all toolchains\nfunction main()\n\n    local envs = {  XMAKE_PROGRAM_DIR    = {\"Set the program scripts directory of xmake.\", os.programdir()},\n                    XMAKE_CONFIGDIR      = {\"Set the local config directory of project.\", config.directory()},\n                    XMAKE_GLOBALDIR      = {\"Set the global config directory of xmake.\", global.directory()},\n                    XMAKE_COLORTERM      = {\"Set the color terminal environment.\", os.getenv(\"XMAKE_COLORTERM\") or os.getenv(\"COLORTERM\")},\n                    XMAKE_LOGFILE        = {\"Set the log output file path.\", os.getenv(\"XMAKE_LOGFILE\")},\n                    XMAKE_ROOT           = {\"Allow xmake to run under root.\", os.getenv(\"XMAKE_ROOT\")},\n                    XMAKE_RAMDIR         = {\"Set the ramdisk directory.\", os.getenv(\"XMAKE_RAMDIR\")},\n                    XMAKE_RCFILES        = {\"Set the runtime configuration files.\", path.joinenv(project.rcfiles())},\n                    XMAKE_TMPDIR         = {\"Set the temporary directory.\", os.tmpdir()},\n                    XMAKE_PROFILE        = {\"Start profiler, e.g. perf:call, perf:tag, trace, stuck.\", os.getenv(\"XMAKE_PROFILE\")},\n                    XMAKE_PKG_CACHEDIR   = {\"Set the cache directory of packages.\", os.getenv(\"XMAKE_PKG_CACHEDIR\")},\n                    XMAKE_PKG_INSTALLDIR = {\"Set the install directory of packages.\", os.getenv(\"XMAKE_PKG_INSTALLDIR\")},\n                    XMAKE_MAIN_REPO      = {\"Set the official package master repository url.\", os.getenv(\"XMAKE_MAIN_REPO\")},\n                    XMAKE_BINARY_REPO    = {\"Set the official package pre-compiled repository url.\", os.getenv(\"XMAKE_BINARY_REPO\")},\n                    XMAKE_THEME          = {\"Set theme.\", os.getenv(\"XMAKE_THEME\") or global.get(\"theme\")},\n                    XMAKE_STATS          = {\"Enable or disable user statistics.\", os.getenv(\"XMAKE_STATS\")}}\n    \n    if option.get(\"json\") then\n        local list = {}\n        local names = {}\n        for name in pairs(envs) do\n            table.insert(names, name)\n        end\n        table.sort(names)\n        for _, name in ipairs(names) do\n            local env = envs[name]\n            table.insert(list, {name = name, description = env[1], value = env[2]})\n        end\n        print(json.encode(list))\n        return \n    end\n\n    local width = 24\n    for name, env in pairs(envs) do\n        cprint(\"${color.dump.string}%s${clear}%s%s\", name, (\" \"):rep(width - #name), env[1])\n        cprint(\"%s${bright}%s\", (\" \"):rep(width), env[2] or \"<empty>\")\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/packages.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        packages.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"private.action.require.list\", { alias = \"show_packages\" })\n\n-- show all packages\nfunction main()\n    config.load()\n    show_packages()\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/platforms.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        platforms.lua\n--\n\n-- imports\nimport(\"core.platform.platform\")\nimport(\".showlist\")\n\n-- show all platforms\nfunction main()\n    showlist(platform.plats())\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/policies.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      A2va\n-- @file        policies.lua\n--\n\n-- imports\nimport(\"core.project.policy\")\nimport(\"core.base.json\")\nimport(\"core.base.option\")\n\n-- show all policies\nfunction main()\n    local policies = policy.policies()\n    if option.get(\"json\") then\n        local list = {}\n        for name, policy in table.orderpairs(policies) do\n            table.insert(list, {name = name, description = policy.description, default = policy.default or \"false\"})\n        end\n        print(json.encode(list))\n        return \n    end\n\n    local width = 45\n    for name, policy in table.orderpairs(policies) do\n        cprint(\"${color.dump.string}%s${clear}%s%s\", name, (\" \"):rep(width - #name), policy[\"description\"])\n        cprint(\"%s${bright}%s\", (\" \"):rep(width), policy[\"default\"] or \"false\")\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/rules.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        rules.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.rule\")\nimport(\".showlist\")\n\n-- show all rules\nfunction main()\n    config.load()\n    local rules = {}\n    for _, r in pairs(rule.rules()) do\n        table.insert(rules, r:name())\n    end\n    table.sort(rules)\n    showlist(rules)\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/targets.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        targets.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"core.platform.platform\")\nimport(\".showlist\")\n\n-- show all targets (optionally filtered by group)\nfunction main()\n    config.load()\n\n    local targets = {}\n    local group_pattern = option.get(\"group\")\n    if group_pattern then\n        group_pattern = \"^\" .. path.pattern(group_pattern) .. \"$\"\n    end\n    for name, target in pairs(project.targets()) do\n        local group = target:get(\"group\")\n        if (target:is_default() and not group_pattern) or (group_pattern and group and group:match(group_pattern)) then\n            table.insert(targets, name)\n        end\n    end\n\n    showlist(targets)\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/themes.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        themes.lua\n--\n\n-- imports\nimport(\"core.theme.theme\")\nimport(\".showlist\")\n\n-- show all themes\nfunction main()\n    showlist(theme.names())\nend\n"
  },
  {
    "path": "xmake/plugins/show/lists/toolchains.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        toolchains.lua\n--\n\n-- imports\nimport(\"core.tool.toolchain\")\nimport(\"core.base.text\")\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\n\n-- show all toolchains\nfunction main()\n\n    config.load()\n    if option.get(\"json\") then\n        local list = {}\n        for _, name in ipairs(toolchain.list()) do\n            local t = os.isfile(os.projectfile()) and project.toolchain(name) or toolchain.load(name)\n            table.insert(list, {name = name, description = t:get(\"description\")})\n        end\n        print(json.encode(list))\n        return \n    end\n\n    local tbl = {align = 'l', sep = \"        \"}\n    for _, name in ipairs(toolchain.list()) do\n        local t = os.isfile(os.projectfile()) and project.toolchain(name) or toolchain.load(name)\n        table.insert(tbl, {name, t:get(\"description\")})\n    end\n    print(text.table(tbl))\nend\n"
  },
  {
    "path": "xmake/plugins/show/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\n\n-- show list\nfunction _show_list(name)\n    assert(#name > 0 and import(\"lists.\" .. name, {try = true, anonymous = true}), \"unknown list name(%s)\", name)()\nend\n\nfunction main()\n\n    -- show list?\n    local listname = option.get(\"list\")\n    if listname then\n        return _show_list(listname)\n    else\n        -- show the information of the given object\n        for _, filepath in ipairs(os.files(path.join(os.scriptdir(), \"info\", \"*.lua\"))) do\n            local name = path.basename(filepath)\n            if option.get(name) then\n                local show_info = assert(import(\"info.\" .. name, {try = true, anonymous = true}), \"unknown option name(%s)\", name)\n                return show_info(option.get(name))\n            end\n        end\n    end\n\n    -- show the basic information of xmake and the current project\n    assert(import(\"info.basic\", {try = true, anonymous = true}))()\nend\n"
  },
  {
    "path": "xmake/plugins/show/showlist.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        showlist.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.text\")\nimport(\"core.base.json\")\n\nfunction _show_text(values)\n    local tbl = {align = 'l', sep = \"    \"}\n    local row = {}\n    for _, value in ipairs(values) do\n        table.insert(row, value)\n        if #row > 2 then\n            table.insert(tbl, row)\n            row = {}\n        end\n    end\n    if #row > 0 then\n        table.insert(tbl, row)\n    end\n    print(text.table(tbl))\nend\n\nfunction _show_json(values)\n    local opt = {}\n    if option.get(\"pretty\") then\n        opt.pretty = true\n        opt.orderkeys = true\n    end\n    print(json.encode(values, opt))\nend\n\nfunction main(values)\n    if option.get(\"json\") then\n        _show_json(values)\n    else\n        if table.is_dictionary(values) then\n            for k, v in pairs(values) do\n                cprint(\"${bright}%s:\", k)\n                _show_text(v)\n            end\n        else\n            _show_text(values)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/show/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"show\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n        usage = \"xmake show [options] [arguments]\",\n        description = \"Show the given project information.\",\n        options = {\n            {'l', \"list\",   \"kv\", nil,   \"Show the values list of the given name.\",\n                values = function (complete, opt)\n                    return import(\"list\").lists()\n                end},\n            {'g', \"group\",  \"kv\", nil,   \"Filter targets by the given group name.\"},\n            {nil, \"json\",   \"k\",  false, \"Show information with json format.\"},\n            {nil, \"pretty\", \"k\",  false, \"Enable pretty formatted json output.\"},\n            {'t', \"target\", \"kv\", nil,   \"Show the information of the given target.\",\n                values = function (complete, opt)\n                    return import(\"private.utils.complete_helper.targets\")(complete, opt)\n                end}\n        }\n    }\n\n\n\n"
  },
  {
    "path": "xmake/plugins/watch/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.fwatcher\")\nimport(\"core.project.config\")\n\n-- add watchdir\nfunction _add_watchdir(watchdir, opt)\n    opt = opt or {}\n    cprint(\"watching ${bright}%s/%s${clear} ..\", watchdir, opt.recursion and \"**\" or \"*\")\n    fwatcher.add(watchdir, opt)\nend\n\n-- add watchdirs\nfunction _add_watchdirs()\n    local watchdirs = option.get(\"watchdirs\")\n    local plaindirs = option.get(\"plaindirs\")\n    if watchdirs or plaindirs then\n        if watchdirs then\n            for _, watchdir in ipairs(path.splitenv(watchdirs)) do\n                for _, dir in ipairs(os.dirs(watchdir)) do\n                    _add_watchdir(dir, {recursion = true})\n                end\n            end\n        end\n        if plaindirs then\n            for _, watchdir in ipairs(path.splitenv(plaindirs)) do\n                for _, dir in ipairs(os.dirs(watchdir)) do\n                    _add_watchdir(dir)\n                end\n            end\n        end\n    elseif os.isfile(os.projectfile()) then\n        watchdirs = os.dirs(path.join(os.projectdir(), \"*|.*\"))\n        for _, watchdir in ipairs(watchdirs) do\n            local builddir = path.absolute(config.builddir())\n            if path.absolute(watchdir) ~= builddir then\n                _add_watchdir(watchdir, {recursion = true})\n            end\n        end\n        _add_watchdir(os.projectdir())\n    else\n        _add_watchdir(watchdir, {recursion = true})\n    end\nend\n\n-- run command\nfunction _run_command(events)\n    try\n    {\n        function ()\n            local commands = option.get(\"commands\")\n            local scriptfile = option.get(\"script\")\n            local arbitrary = option.get(\"arbitrary\")\n            if commands then\n                for _, command in ipairs(commands:split(\";\")) do\n                    os.exec(command)\n                end\n            elseif arbitrary then\n                local program = arbitrary[1]\n                local argv = #arbitrary > 1 and table.slice(arbitrary, 2) or {}\n                os.execv(program, argv)\n            elseif scriptfile and os.isfile(scriptfile) and path.extension(scriptfile) == \".lua\" then\n                local script = import(path.basename(scriptfile),\n                    {rootdir = path.directory(scriptfile), anonymous = true})\n                script(events)\n            elseif os.isfile(os.projectfile()) then\n                local argv = {\"build\", \"-y\"}\n                if option.get(\"verbose\") then\n                    table.insert(argv, \"-v\")\n                end\n                if option.get(\"diagnosis\") then\n                    table.insert(argv, \"-D\")\n                end\n                local target = option.get(\"target\")\n                if target then\n                    table.insert(argv, target)\n                end\n                os.execv(os.programfile(), argv)\n                if option.get(\"run\") then\n                    argv[1] = \"run\"\n                    os.execv(os.programfile(), argv)\n                end\n            end\n        end,\n        catch\n        {\n            function (errors)\n                cprint(tostring(errors))\n            end\n        }\n    }\nend\n\nfunction main()\n\n    -- add watchdirs\n    _add_watchdirs()\n\n    -- do watch\n    local count = 0\n    local events = {}\n    while true do\n        local ok, event = fwatcher.wait(300)\n        if ok > 0 then\n            local status\n            if event.type == fwatcher.ET_CREATE then\n                status = \"created\"\n            elseif event.type == fwatcher.ET_MODIFY then\n                status = \"modified\"\n            elseif event.type == fwatcher.ET_DELETE then\n                status = \"deleted\"\n            end\n            print(event.path, status)\n            -- we use map to remove repeat events\n            events[event.path .. tostring(event.type)] = event\n            count = count + 1\n        elseif count > 0 then\n            _run_command(table.values(events))\n            count = 0\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/plugins/watch/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntask(\"watch\")\n    set_category(\"plugin\")\n    on_run(\"main\")\n    set_menu {\n                usage = \"xmake watch [options] [arguments]\"\n            ,   description = \"Watch the project directories and run command.\"\n            ,   options =\n                {\n                    {'c', \"commands\"    , \"kv\"  , nil   ,   \"Run the multiple commands instead of the default build command.\",\n                                                            \"e.g.\",\n                                                            \"    $ xmake watch -c 'xmake -rv'\",\n                                                            \"    $ xmake watch -c 'xmake -vD; xmake run hello'\"},\n                    {'s', \"script\"      , \"kv\"  , nil   ,   \"Run the given lua script file.\",\n                                                            \"e.g.\",\n                                                            \"    $ xmake watch -s /tmp/watch.lua\"},\n                    {'d', \"watchdirs\"   , \"kv\"  , nil   ,   \"Set the given recursive watch directories, the project directories will be watched by default.\",\n                                                            \"e.g.\",\n                                                            \"    $ xmake watch -d src\",\n                                                            \"    $ xmake watch -d 'src/*\" .. path.envsep() .. \"tests/**/subdir'\"},\n                    {'p', \"plaindirs\"   , \"kv\"  , nil   ,   \"Set the given non-recursive watch directories, the project directories will be watched by default.\",\n                                                            \"e.g.\",\n                                                            \"    $ xmake watch -p src\",\n                                                            \"    $ xmake watch -p 'src/*\" .. path.envsep() .. \"tests/**/subdir'\"},\n                    {'r', \"run\"         , \"k\"   , nil   ,   \"Build and run target.\"},\n                    {'t', \"target\"      , \"kv\"  , nil   ,   \"Build the given target.\",\n                                                            values = function (complete, opt) return import(\"private.utils.complete_helper.targets\")(complete, opt) end },\n                    {'-', \"arbitrary\"   , \"vs\"   , nil  ,   \"Run an arbitrary command.\",\n                                                            \"e.g.\",\n                                                            \"    $ xmake watch -- echo hello xmake!\",\n                                                            \"    $ xmake watch -- xmake run\",\n                                                            \"    $ xmake watch -- xmake -rv\"}\n                }\n            }\n\n\n\n"
  },
  {
    "path": "xmake/repository/packages/7/7z/patches/21.02/backport-21.03-fix-for-GCC-10.patch",
    "content": "diff --git a/CPP/7zip/Common/OffsetStream.cpp b/CPP/7zip/Common/OffsetStream.cpp\nindex b3e710f..b16124c 100644\n--- a/CPP/7zip/Common/OffsetStream.cpp\n+++ b/CPP/7zip/Common/OffsetStream.cpp\n@@ -20,13 +20,13 @@ STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *proc\n \n STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)\n {\n-  UInt64 absoluteNewPosition;\n   if (seekOrigin == STREAM_SEEK_SET)\n   {\n     if (offset < 0)\n       return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;\n     offset += _offset;\n   }\n+  UInt64 absoluteNewPosition = 0; // =0 for gcc-10\n   HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);\n   if (newPosition)\n     *newPosition = absoluteNewPosition - _offset;\n"
  },
  {
    "path": "xmake/repository/packages/7/7z/xmake.lua",
    "content": "package(\"7z\")\n\n    set_kind(\"binary\")\n    set_homepage(\"https://www.7-zip.org/\")\n    set_description(\"A file archiver with a high compression ratio.\")\n\n    if is_host(\"windows\") then\n        if is_arch(\"x64\", \"x86_64\") then\n            set_urls(\"https://github.com/xmake-mirror/7zip/releases/download/$(version)/7z$(version)-x64.zip\",\n                     \"https://gitlab.com/xmake-mirror/7zip-releases/raw/master/7z$(version)-x64.zip\")\n            add_versions(\"19.00\", \"fc21cf510d70a69bfa8e5b0449fe0a054fb76e2f8bd568364821f319c8b1d86d\")\n            add_versions(\"18.05\", \"e6e2d21e2c482f1b1c5a6d21ed80800ce1273b902cf4b9afa68621545540ee2f\")\n        else\n            set_urls(\"https://github.com/xmake-mirror/7zip/releases/download/$(version)/7z$(version)-x86.zip\",\n                     \"https://gitlab.com/xmake-mirror/7zip-releases/raw/master/7z$(version)-x86.zip\")\n            add_versions(\"19.00\", \"f84fab081a2d8a6b5868a2eaf01cd56017363fb24560259cea80567f8062334f\")\n            add_versions(\"18.05\", \"544c37bebee30437aba405071484e0ac6310332b4bdabe4ca7420a800d4b4b5e\")\n        end\n    else\n        set_urls(\"https://github.com/xmake-mirror/7zip/archive/refs/tags/$(version).tar.gz\",\n                 \"https://github.com/xmake-mirror/7zip.git\")\n        add_versions(\"21.02\", \"b2a4c5bec8207508b26f94507f62f5a79c57ae9ab77dbf393f3b2fc8eef2e382\")\n        add_patches(\"21.02\", path.join(os.scriptdir(), \"patches\", \"21.02\", \"backport-21.03-fix-for-GCC-10.patch\"), \"f1d8fa0bbb25123b28e9b2842da07604238b77e51b918260a369f97c2f694c89\")\n    end\n\n    on_install(\"macosx\", \"linux\", function (package)\n        -- Clang has some indentation warnings that fails compilation using -Werror, remove it\n        io.replace(\"CPP/7zip/7zip_gcc.mak\", \"CFLAGS_WARN_WALL = -Wall -Werror -Wextra\", \"CFLAGS_WARN_WALL = -Wall -Wextra\", {plain = true})\n\n        os.cd(\"CPP/7zip/Bundles/Alone2\")\n        os.vrun(\"make -j -f makefile.gcc\")\n\n        local bin = package:installdir(\"bin\")\n        os.cp(\"_o/7zz\", bin)\n        os.ln(bin .. \"/7zz\", bin .. \"/7z\")\n    end)\n\n    on_install(\"windows\", function (package)\n        os.cp(\"*\", package:installdir(\"bin\"))\n\n        --[[\n        Build code for windows\n\n        local archdir = package:is_arch(\"x64\", \"x86_64\") and \"x64\" or \"x86\"\n        os.cd(\"CPP/7zip/Bundles/Alone2\")\n        local configs = {\"-f\", \"makefile\"}\n        table.insert(configs, \"PLATFORM=\" .. archdir)\n        import(\"package.tools.nmake\").build(package, configs)\n\n        local bin = package:installdir(\"bin\")\n        os.cp(archdir .. \"/7zz.exe\", bin .. \"/7z.exe\")\n        ]]\n    end)\n\n    on_test(function (package)\n        os.vrun(\"7z --help\")\n    end)\n"
  },
  {
    "path": "xmake/repository/packages/g/git/xmake.lua",
    "content": "package(\"git\")\n    set_kind(\"binary\")\n    set_homepage(\"https://git-scm.com/\")\n    set_description(\"A free and open source distributed version control system\")\n\n    if is_host(\"windows\") then\n        if os.arch() == \"x64\" then\n            add_urls(\"https://github.com/git-for-windows/git/releases/download/v$(version).windows.1/MinGit-$(version)-64-bit.zip\",\n                     \"https://gitlab.com/xmake-mirror/git-for-windows-releases/raw/master/MinGit-$(version)-64-bit.zip\")\n            if winos.version():gt(\"winxp\") then\n                add_versions(\"2.20.0\", \"f577f81c401535858761fc4857a105337cc12880b79e72f89d0740167083d287\")\n            else\n                add_versions(\"2.10.0\", \"2e1101ec57da526728704c04792293613f3c5aa18e65f13a4129d00b54de2087\")\n            end\n        else\n            add_urls(\"https://github.com/git-for-windows/git/releases/download/v$(version).windows.1/MinGit-$(version)-32-bit.zip\",\n                     \"https://gitlab.com/xmake-mirror/git-for-windows-releases/raw/master/MinGit-$(version)-32-bit.zip\")\n            if winos.version():gt(\"winxp\") then\n                add_versions(\"2.20.0\", \"39d3dce9f67d7ae884edf0416d28f6dd8e24b6326de8e509613a2b12fb4f0820\")\n            else\n                add_versions(\"2.10.0\", \"36f890870126dcf840d87eaec7e55b8a483bc336ebf8970de2f9d549a3cfc195\")\n            end\n        end\n    end\n\n    on_load(\"windows\", function (package)\n        package:addenv(\"PATH\", path.join(\"share\", \"MinGit\", package:is_arch(\"x86_64\", \"x64\") and \"mingw64\" or \"mingw32\", \"bin\"))\n        package:addenv(\"PATH\", path.join(\"share\", \"MinGit\", \"cmd\"))\n    end)\n\n    on_install(\"macosx\", \"linux\", \"bsd\", function (package)\n        import(\"package.manager.install_package\")(\"git\")\n    end)\n\n    on_install(\"windows\", function (package)\n        os.cp(\"*\", package:installdir(\"share/MinGit\"))\n    end)\n\n    on_test(function (package)\n        os.vrun(\"git --version\")\n    end)\n"
  },
  {
    "path": "xmake/repository/templates/c/console/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/modules/binary/bar/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/modules/binary/bar/src/add.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char **argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a + b);\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/modules/binary/bar/src/sub.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char **argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a - b);\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/modules/binary/bar/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"add\")\n    add_rules(\"module.binary\")\n    add_files(\"src/add.c\")\n\ntarget(\"sub\")\n    add_rules(\"module.binary\")\n    add_files(\"src/sub.c\")\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/binary/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    on_config(function (target)\n        import(\"binary.bar\")\n        print(\"binary: 1 + 1 = %s\", bar.add(1, 1))\n        print(\"binary: 1 - 1 = %s\", bar.sub(1, 1))\n    end)\n    \n${FAQ}\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/shared/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/shared/modules/shared/foo/src/foo.c",
    "content": "#include <xmi.h>\n\nstatic int add(lua_State *lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a + b);\n    return 1;\n}\n\nstatic int sub(lua_State *lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a - b);\n    return 1;\n}\n\nint luaopen(foo, lua_State *lua) {\n    static const luaL_Reg funcs[] = { { \"add\", add }, { \"sub\", sub }, { NULL, NULL } };\n    lua_newtable(lua);\n    luaL_setfuncs(lua, funcs, 0);\n    return 1;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/shared/modules/shared/foo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    add_rules(\"module.shared\")\n    add_files(\"src/foo.c\")\n\n"
  },
  {
    "path": "xmake/repository/templates/c/module/shared/src/main.c",
    "content": "#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"hello world!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/module/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.c\")\n    on_config(function (target)\n        import(\"shared.foo\")\n        print(\"shared: 1 + 1 = %s\", foo.add(1, 1))\n        print(\"shared: 1 - 1 = %s\", foo.sub(1, 1))\n    end)\n    \n${FAQ}\n\n"
  },
  {
    "path": "xmake/repository/templates/c/shared/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/shared/src/foo.h",
    "content": "#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n__export int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/c/shared/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.c\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c/static/src/foo.c",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/static/src/foo.h",
    "content": "int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/c/static/src/main.c",
    "content": "#include \"foo.h\"\n#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"add(1, 2) = %d\\n\", add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.c\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.c\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c/xmake/cli/src/lni/main.c",
    "content": "#include <xmake/xmake.h>\n\nstatic tb_byte_t const g_luafiles_data[] = {\n#include \"luafiles.xmz.h\"\n};\n\nstatic tb_int_t lni_test_hello(lua_State *lua) {\n    lua_pushliteral(lua, \"hello xmake!\");\n    return 1;\n}\n\nstatic tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State *lua) {\n    static luaL_Reg const lni_test_funcs[] = { { \"hello\", lni_test_hello }, { tb_null, tb_null } };\n    xm_engine_register(engine, \"test\", lni_test_funcs);\n    xm_engine_add_embedfiles(engine, g_luafiles_data, sizeof(g_luafiles_data));\n}\n\ntb_int_t main(tb_int_t argc, tb_char_t **argv) {\n    tb_char_t *taskargv[] = { \"lua\", \"-D\", \"lua.main\", tb_null };\n    return xm_engine_run(\"${TARGET_NAME}\", argc, argv, taskargv, lni_initalizer);\n}\n"
  },
  {
    "path": "xmake/repository/templates/c/xmake/cli/src/lua/main.lua",
    "content": "import(\"core.base.option\")\nimport(\"lib.lni.test\")\n\nfunction main ()\n    print(test.hello())\n    local argv = option.get(\"arguments\")\n    if argv then\n        print(argv)\n    end\nend\n"
  },
  {
    "path": "xmake/repository/templates/c/xmake/cli/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"libxmake\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xmake.cli\")\n    add_files(\"src/lni/*.c\")\n    add_files(\"src/lua/*.lua\", {rootdir = \"src\"})\n    add_packages(\"libxmake\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/console/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/modules/binary/bar/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/modules/binary/bar/src/add.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char **argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a + b);\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/modules/binary/bar/src/sub.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char **argv) {\n    int a = atoi(argv[1]);\n    int b = atoi(argv[2]);\n    printf(\"%d\", a - b);\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/modules/binary/bar/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"add\")\n    add_rules(\"module.binary\")\n    add_files(\"src/add.cpp\")\n\ntarget(\"sub\")\n    add_rules(\"module.binary\")\n    add_files(\"src/sub.cpp\")\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/binary/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    on_config(function (target)\n        import(\"binary.bar\")\n        print(\"binary: 1 + 1 = %s\", bar.add(1, 1))\n        print(\"binary: 1 - 1 = %s\", bar.sub(1, 1))\n    end)\n    \n${FAQ}\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/shared/.gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/shared/modules/shared/foo/src/foo.cpp",
    "content": "#include <xmi.h>\n\nstatic int add(lua_State *lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a + b);\n    return 1;\n}\n\nstatic int sub(lua_State *lua) {\n    int a = lua_tointeger(lua, 1);\n    int b = lua_tointeger(lua, 2);\n    lua_pushinteger(lua, a - b);\n    return 1;\n}\n\nint luaopen(foo, lua_State *lua) {\n    static const luaL_Reg funcs[] = { { \"add\", add }, { \"sub\", sub }, { NULL, NULL } };\n    lua_newtable(lua);\n    luaL_setfuncs(lua, funcs, 0);\n    return 1;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/shared/modules/shared/foo/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    add_rules(\"module.shared\")\n    add_files(\"src/foo.cpp\")\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/shared/src/main.cpp",
    "content": "#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"hello world!\" << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/module/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_moduledirs(\"modules\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    on_config(function (target)\n        import(\"shared.foo\")\n        print(\"shared: 1 + 1 = %s\", foo.add(1, 1))\n        print(\"shared: 1 - 1 = %s\", foo.sub(1, 1))\n    end)\n    \n${FAQ}\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/console/src/main.cpp",
    "content": "#include <QCoreApplication>\n\nint main(int argc, char *argv[]) {\n    QCoreApplication a(argc, argv);\n    printf(\"hello xmake\\n\");\n    return a.exec();\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.console\")\n    add_files(\"src/*.cpp\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp/src/main.cpp",
    "content": "#include <QGuiApplication>\n#include <QQmlApplicationEngine>\n\nint main(int argc, char *argv[]) {\n#if QT_VERSION >= 0x50601\n    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\n#endif\n\n    QGuiApplication app(argc, argv);\n\n    QQmlApplicationEngine engine;\n    engine.load(QUrl(QStringLiteral(\"qrc:/main.qml\")));\n    if (engine.rootObjects().isEmpty())\n        return -1;\n\n    return app.exec();\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp/src/main.qml",
    "content": "import QtQuick 2.6\nimport QtQuick.Window 2.2\nimport QtQuick.Controls 2.2\n\nWindow {\n    id: root\n    visible: true\n    width: 640\n    height: 480\n    title: qsTr(\"Hello World\")\n    Button {\n        text: \"Ok\"\n        onClicked: {\n            root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);\n        }\n    }\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp/src/qml.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>main.qml</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.quickapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp_static/src/main.cpp",
    "content": "#include <QGuiApplication>\n#include <QQmlApplicationEngine>\n\nint main(int argc, char *argv[]) {\n#if QT_VERSION >= 0x50601\n    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\n#endif\n\n    QGuiApplication app(argc, argv);\n\n    QQmlApplicationEngine engine;\n    engine.load(QUrl(QStringLiteral(\"qrc:/main.qml\")));\n    if (engine.rootObjects().isEmpty())\n        return -1;\n\n    return app.exec();\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp_static/src/main.qml",
    "content": "import QtQuick 2.6\nimport QtQuick.Window 2.2\nimport QtQuick.Controls 2.2\n\nWindow {\n    id: root\n    visible: true\n    width: 640\n    height: 480\n    title: qsTr(\"Hello World\")\n    Button {\n        text: \"Ok\"\n        onClicked: {\n            root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);\n        }\n    }\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp_static/src/qml.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>main.qml</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/quickapp_static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/qt\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.quickapp_static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/qml.qrc\")\n    add_frameworks(\"QtQuickControls2\", \"QtQuickTemplates2\")\n    qt_add_static_plugins(\"QtQuick2Plugin\", {linkdirs = \"qml/QtQuick.2\", links = \"qtquick2plugin\"})\n    qt_add_static_plugins(\"QtQuick2WindowPlugin\", {linkdirs = \"qml/QtQuick/Window.2\", links = \"windowplugin\"})\n    qt_add_static_plugins(\"QtQuickControls2Plugin\", {linkdirs = \"qml/QtQuick/Controls.2\", links = \"qtquickcontrols2plugin\"})\n    qt_add_static_plugins(\"QtQuickTemplates2Plugin\", {linkdirs = \"qml/QtQuick/Templates.2\", links = \"qtquicktemplates2plugin\"})\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/shared/src/demo.cpp",
    "content": "#include \"demo.h\"\n\nQtDemo::QtDemo() {\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/shared/src/demo.h",
    "content": "#ifndef QT_DEMO_H\n#define QT_DEMO_H\n\n#include \"demo_global.h\"\n\nclass QT_DEMOSHARED_EXPORT QtDemo {\n  public:\n    QtDemo();\n};\n\n#endif // QT_DEMO_H\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/shared/src/demo_global.h",
    "content": "#ifndef QT_DEMO_GLOBAL_H\n#define QT_DEMO_GLOBAL_H\n\n#include <QtCore/qglobal.h>\n\n#if defined(QT_DEMO_LIBRARY)\n#define QT_DEMOSHARED_EXPORT Q_DECL_EXPORT\n#else\n#define QT_DEMOSHARED_EXPORT Q_DECL_IMPORT\n#endif\n\n#endif // QT_DEMO_GLOBAL_H\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.shared\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_defines(\"QT_DEMO_LIBRARY\")\n    add_frameworks(\"QtGui\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/static/src/demo.cpp",
    "content": "#include \"demo.h\"\n\nQtDemo::QtDemo() {\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/static/src/demo.h",
    "content": "#ifndef QT_DEMO_H\n#define QT_DEMO_H\n\nclass QtDemo {\n  public:\n    QtDemo();\n};\n\n#endif // QT_DEMO_H\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_frameworks(\"QtGui\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\nint main(int argc, char *argv[]) {\n    QApplication a(argc, argv);\n    MainWindow   w;\n    w.show();\n    return a.exec();\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nMainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {\n    ui->setupUi(this);\n}\n\nMainWindow::~MainWindow() {\n    delete ui;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow {\n    Q_OBJECT\n\n  public:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\n  private:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.ui",
    "content": "<ui version=\"4.0\"> \n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\n  <property name=\"geometry\" >\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\" >\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\n  <widget class=\"QWidget\" name=\"centralWidget\" />\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\n </widget>\n <layoutDefault spacing=\"6\" margin=\"11\" />\n <pixmapfunction></pixmapfunction>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.widgetapp\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n    -- add files with Q_OBJECT meta (only for qt.moc)\n    add_files(\"src/mainwindow.h\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp_static/src/main.cpp",
    "content": "#include \"mainwindow.h\"\n#include <QApplication>\n\nint main(int argc, char *argv[]) {\n    QApplication a(argc, argv);\n    MainWindow   w;\n    w.show();\n\n    return a.exec();\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"ui_mainwindow.h\"\n\nMainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {\n    ui->setupUi(this);\n}\n\nMainWindow::~MainWindow() {\n    delete ui;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.h",
    "content": "#ifndef MAINWINDOW_H\n#define MAINWINDOW_H\n\n#include <QMainWindow>\n\nnamespace Ui {\nclass MainWindow;\n}\n\nclass MainWindow : public QMainWindow {\n    Q_OBJECT\n\n  public:\n    explicit MainWindow(QWidget *parent = 0);\n    ~MainWindow();\n\n  private:\n    Ui::MainWindow *ui;\n};\n\n#endif // MAINWINDOW_H\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.ui",
    "content": "<ui version=\"4.0\"> \n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\" >\n  <property name=\"geometry\" >\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\" >\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QMenuBar\" name=\"menuBar\" />\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />\n  <widget class=\"QWidget\" name=\"centralWidget\" />\n  <widget class=\"QStatusBar\" name=\"statusBar\" />\n </widget>\n <layoutDefault spacing=\"6\" margin=\"11\" />\n <pixmapfunction></pixmapfunction>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "xmake/repository/templates/c++/qt/widgetapp_static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nincludes(\"@builtin/qt\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"qt.widgetapp_static\")\n    add_headerfiles(\"src/*.h\")\n    add_files(\"src/*.cpp\")\n    add_files(\"src/mainwindow.ui\")\n\n    -- add files with Q_OBJECT meta (only for qt.moc)\n    add_files(\"src/mainwindow.h\")\n\n    -- add plugin: QSvgPlugin (optional)\n    add_frameworks(\"QtSvg\")\n    qt_add_static_plugins(\"QSvgPlugin\", {linkdirs = \"plugins/imageformats\", links = {\"qsvg\"}})\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/shared/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/shared/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n__export int add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "xmake/repository/templates/c++/shared/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/static/src/foo.cpp",
    "content": "#include \"foo.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/static/src/foo.h",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint add(int a, int b);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "xmake/repository/templates/c++/static/src/main.cpp",
    "content": "#include \"foo.h\"\n#include <iostream>\n\nint main(int argc, char **argv) {\n    std::cout << \"add(1, 2) = \" << add(1, 2) << std::endl;\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cpp\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cpp\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/c++/wxwidgets/src/main.cpp",
    "content": "#include <wx/wx.h>\n\nnamespace Examples {\nclass Frame : public wxFrame {\n    enum wxOwnedID {\n        ID_Hello = 2\n    };\n\n  public:\n    Frame() : wxFrame(nullptr, wxID_ANY, \"Hello World\") {\n        auto menuFile = new wxMenu();\n        menuFile->Append(ID_Hello, \"&Hello...\\tCtrl-H\", \"Help string shown in status bar for this menu item\");\n        menuFile->AppendSeparator();\n        menuFile->Append(wxID_EXIT);\n\n        auto menuHelp = new wxMenu();\n        menuHelp->Append(wxID_ABOUT);\n        auto menuBar = new wxMenuBar();\n\n        menuBar->Append(menuFile, \"&File\");\n        menuBar->Append(menuHelp, \"&Help\");\n        SetMenuBar(menuBar);\n\n        CreateStatusBar();\n        SetStatusText(\"Welcome to wxWidgets!\");\n\n        menuBar->Bind(wxEVT_MENU, [&](wxCommandEvent &event) {\n            if (event.GetId() == ID_Hello)\n                wxLogMessage(\"Hello world from wxWidgets!\");\n            else if (event.GetId() == wxID_ABOUT)\n                wxMessageBox(\"This is a wxWidgets Hello World example\", \"About Hello World\", wxOK | wxICON_INFORMATION);\n            else if (event.GetId() == wxID_EXIT)\n                Close(true);\n            else\n                event.Skip();\n        });\n    }\n};\n\nclass Application : public wxApp {\n    bool OnInit() override {\n        (new Frame())->Show();\n        return true;\n    }\n};\n} // namespace Examples\n\nwxIMPLEMENT_APP(Examples::Application);"
  },
  {
    "path": "xmake/repository/templates/c++/wxwidgets/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"wxwidgets\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cpp\")\n    set_languages(\"c++14\")\n    add_packages(\"wxwidgets\")\n\n${FAQ}"
  },
  {
    "path": "xmake/repository/templates/c++/xmake/cli/src/lni/main.cpp",
    "content": "extern \"C\" {\n#include <xmake/xmake.h>\n}\n\nstatic tb_byte_t const g_luafiles_data[] = {\n#include \"luafiles.xmz.h\"\n};\n\nstatic tb_int_t lni_test_hello(lua_State *lua) {\n    lua_pushliteral(lua, \"hello xmake!\");\n    return 1;\n}\n\nstatic tb_void_t lni_initalizer(xm_engine_ref_t engine, lua_State *lua) {\n    static luaL_Reg const lni_test_funcs[] = { { \"hello\", lni_test_hello }, { tb_null, tb_null } };\n    xm_engine_register(engine, \"test\", lni_test_funcs);\n    xm_engine_add_embedfiles(engine, g_luafiles_data, sizeof(g_luafiles_data));\n}\n\ntb_int_t main(tb_int_t argc, tb_char_t **argv) {\n    tb_char_t *taskargv[] = { \"lua\", \"-D\", \"lua.main\", tb_null };\n    return xm_engine_run(\"${TARGET_NAME}\", argc, argv, taskargv, lni_initalizer);\n}\n"
  },
  {
    "path": "xmake/repository/templates/c++/xmake/cli/src/lua/main.lua",
    "content": "import(\"core.base.option\")\nimport(\"lib.lni.test\")\n\nfunction main ()\n    print(test.hello())\n    local argv = option.get(\"arguments\")\n    if argv then\n        print(argv)\n    end\nend\n"
  },
  {
    "path": "xmake/repository/templates/c++/xmake/cli/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"libxmake\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xmake.cli\")\n    add_files(\"src/lni/*.cpp\")\n    add_files(\"src/lua/*.lua\", {rootdir = \"src\"})\n    add_packages(\"libxmake\")\n\n${FAQ}\n\n"
  },
  {
    "path": "xmake/repository/templates/csharp/console/src/Program.cs",
    "content": "using System;\n\nnamespace ${TARGET_NAME};\n\nclass Program {\n    static void Main(string[] args) {\n        Console.WriteLine(\"Hello, xmake!\");\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/shared/src/foo.cs",
    "content": "namespace Foo;\n\npublic class Foo {\n    public static int Add(int a, int b) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/shared/src/main.cs",
    "content": "using System;\n\nclass Program {\n    static void Main(string[] args) {\n        Console.WriteLine(\"add(1, 2) = {0}\", Foo.Foo.Add(1, 2));\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/shared/xmake.lua",
    "content": "target(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.cs\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/static/src/foo.cs",
    "content": "namespace Foo;\n\npublic class Foo {\n    public static int Add(int a, int b) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/static/src/main.cs",
    "content": "using System;\n\nclass Program {\n    static void Main(string[] args) {\n        Console.WriteLine(\"add(1, 2) = {0}\", Foo.Foo.Add(1, 2));\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/csharp/static/xmake.lua",
    "content": "target(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.cs\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.cs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/cuda/console/src/main.cu",
    "content": "\n#include \"cuda_runtime.h\"\n#include \"device_launch_parameters.h\"\n\n#include <stdio.h>\n\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}\n\nint main()\n{\n    const int arraySize = 5;\n    const int a[arraySize] = {1, 2, 3, 4, 5};\n    const int b[arraySize] = {10, 20, 30, 40, 50};\n    int c[arraySize] = {0};\n\n    // Add vectors in parallel.\n    cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addWithCuda failed!\");\n        return 1;\n    }\n\n    printf(\"{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\\n\",\n           c[0], c[1], c[2], c[3], c[4]);\n\n    // cudaDeviceReset must be called before exiting in order for profiling and\n    // tracing tools such as Nsight and Visual Profiler to show complete traces.\n    cudaStatus = cudaDeviceReset();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceReset failed!\");\n        return 1;\n    }\n\n    return 0;\n}\n\n// Helper function for using CUDA to add vectors in parallel.\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)\n{\n    int *dev_a = 0;\n    int *dev_b = 0;\n    int *dev_c = 0;\n    cudaError_t cudaStatus;\n\n    // Choose which GPU to run on, change this on a multi-GPU system.\n    cudaStatus = cudaSetDevice(0);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?\");\n        goto Error;\n    }\n\n    // Allocate GPU buffers for three vectors (two input, one output)    .\n    cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    // Copy input vectors from host memory to GPU buffers.\n    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    // Launch a kernel on the GPU with one thread for each element.\n    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);\n\n    // Check for any errors launching the kernel\n    cudaStatus = cudaGetLastError();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addKernel launch failed: %s\\n\", cudaGetErrorString(cudaStatus));\n        goto Error;\n    }\n\n    // cudaDeviceSynchronize waits for the kernel to finish, and returns\n    // any errors encountered during the launch.\n    cudaStatus = cudaDeviceSynchronize();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceSynchronize returned error code %d after launching addKernel!\\n\", cudaStatus);\n        goto Error;\n    }\n\n    // Copy output vector from GPU buffer to host memory.\n    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\nError:\n    cudaFree(dev_c);\n    cudaFree(dev_a);\n    cudaFree(dev_b);\n\n    return cudaStatus;\n}\n"
  },
  {
    "path": "xmake/repository/templates/cuda/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.cu\")\n\n    -- generate SASS code for SM architecture of current host\n    add_cugencodes(\"native\")\n\n    -- generate PTX code for the virtual architecture to guarantee compatibility\n    add_cugencodes(\"compute_75\")\n\n    -- -- generate SASS code for each SM architecture\n    -- add_cugencodes(\"sm_75\", \"sm_80\", \"sm_89\", \"sm_90\", \"sm_100\")\n\n    -- -- generate PTX code from the highest SM architecture to guarantee forward-compatibility\n    -- add_cugencodes(\"compute_100\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/cuda/shared/inc/lib.cuh",
    "content": "#pragma once\n\n#include \"cuda_runtime.h\"\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#if defined(_WIN32)\n#define __export __declspec(dllexport)\n#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))\n#define __export __attribute__((visibility(\"default\")))\n#else\n#define __export\n#endif\n\n    __export cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "xmake/repository/templates/cuda/shared/src/lib.cu",
    "content": "#include <lib.cuh>\n#include <stdio.h>\n#include \"device_launch_parameters.h\"\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}\n\n// Helper function for using CUDA to add vectors in parallel.\ncudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)\n{\n    int *dev_a = 0;\n    int *dev_b = 0;\n    int *dev_c = 0;\n    cudaError_t cudaStatus;\n\n    // Choose which GPU to run on, change this on a multi-GPU system.\n    cudaStatus = cudaSetDevice(0);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?\");\n        goto Error;\n    }\n\n    // Allocate GPU buffers for three vectors (two input, one output)    .\n    cudaStatus = cudaMalloc((void **)&dev_c, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMalloc((void **)&dev_b, size * sizeof(int));\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMalloc failed!\");\n        goto Error;\n    }\n\n    // Copy input vectors from host memory to GPU buffers.\n    cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\n    // Launch a kernel on the GPU with one thread for each element.\n    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);\n\n    // Check for any errors launching the kernel\n    cudaStatus = cudaGetLastError();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"addKernel launch failed: %s\\n\", cudaGetErrorString(cudaStatus));\n        goto Error;\n    }\n\n    // cudaDeviceSynchronize waits for the kernel to finish, and returns\n    // any errors encountered during the launch.\n    cudaStatus = cudaDeviceSynchronize();\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaDeviceSynchronize returned error code %d after launching addKernel!\\n\", cudaStatus);\n        goto Error;\n    }\n\n    // Copy output vector from GPU buffer to host memory.\n    cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);\n    if (cudaStatus != cudaSuccess)\n    {\n        fprintf(stderr, \"cudaMemcpy failed!\");\n        goto Error;\n    }\n\nError:\n    cudaFree(dev_c);\n    cudaFree(dev_a);\n    cudaFree(dev_b);\n\n    return cudaStatus;\n}\n"
  },
  {
    "path": "xmake/repository/templates/cuda/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"shared\")\n    add_files(\"src/**.cu\")\n    add_includedirs(\"inc\")\n\n    -- generate SASS code for SM architecture of current host\n    add_cugencodes(\"native\")\n\n    -- generate PTX code for the virtual architecture to guarantee compatibility\n    add_cugencodes(\"compute_75\")\n\n    -- -- generate SASS code for each SM architecture\n    -- add_cugencodes(\"sm_75\", \"sm_80\", \"sm_89\", \"sm_90\", \"sm_100\")\n\n    -- -- generate PTX code from the highest SM architecture to guarantee forward-compatibility\n    -- add_cugencodes(\"compute_100\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/cuda/static/inc/lib.cuh",
    "content": "#pragma once\n\n__global__ void addKernel(int *c, const int *a, const int *b);"
  },
  {
    "path": "xmake/repository/templates/cuda/static/src/lib.cu",
    "content": "#include <lib.cuh>\n\n__global__ void addKernel(int *c, const int *a, const int *b)\n{\n    int i = threadIdx.x;\n    c[i] = a[i] + b[i];\n}"
  },
  {
    "path": "xmake/repository/templates/cuda/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"static\")\n    add_files(\"src/**.cu\")\n    add_includedirs(\"inc\")\n\n    -- generate SASS code for SM architecture of current host\n    add_cugencodes(\"native\")\n\n    -- generate PTX code for the virtual architecture to guarantee compatibility\n    add_cugencodes(\"compute_75\")\n\n    -- -- generate SASS code for each SM architecture\n    -- add_cugencodes(\"sm_75\", \"sm_80\", \"sm_89\", \"sm_90\", \"sm_100\")\n\n    -- -- generate PTX code from the highest SM architecture to guarantee forward-compatibility\n    -- add_cugencodes(\"compute_100\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/console/src/main.d",
    "content": "import std.stdio;\n\nvoid main() {\n    writeln(\"hello world!\");\n}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.d\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/shared/src/interfaces.d",
    "content": "version(Windows) {\n    import core.sys.windows.windows;\n    import core.sys.windows.dll;\n    mixin SimpleDllMain;\n}\n\nextern(C) int add(int a, int b) {\n    return a + b;\n}\n\nextern(C) int sub(int a, int b) {\n    return a - b;\n}\n\n\n"
  },
  {
    "path": "xmake/repository/templates/dlang/shared/src/main.d",
    "content": "import std.stdio;\nimport interfaces;\n\nvoid main() {\n    printf(\"add: %d\\n\", interfaces.add(1, 1));\n    printf(\"sub: %d\\n\", interfaces.sub(2, 1));\n}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"shared\")\n    add_files(\"src/interfaces.d\")\n    add_includedirs(\"src\", {public = true})\n    add_rules(\"utils.symbols.export_list\", {symbols = {\n      \"add\",\n      \"sub\"}})\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.d\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/static/src/interfaces.d",
    "content": "extern(C) int add(int a, int b)\n{\n    return a + b;\n}\n\nextern(C) int sub(int a, int b)\n{\n    return a - b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/static/src/main.d",
    "content": "import std.stdio;\nimport interfaces;\n\nvoid main() {\n    printf(\"add: %d\\n\", interfaces.add(1, 1));\n    printf(\"sub: %d\\n\", interfaces.sub(2, 1));\n}\n"
  },
  {
    "path": "xmake/repository/templates/dlang/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"static\")\n    add_files(\"src/interfaces.d\")\n    add_includedirs(\"src\", {public = true})\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.d\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/fortran/console/src/main.f90",
    "content": "program hello\n  print *, \"Hello World!\"\nend program hello\n"
  },
  {
    "path": "xmake/repository/templates/fortran/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.f90\")\n\n"
  },
  {
    "path": "xmake/repository/templates/fortran/shared/src/main.f90",
    "content": "program hello\n    use test, only: print_hello\n    implicit none (type, external)\n    call print_hello()\nend program hello\n"
  },
  {
    "path": "xmake/repository/templates/fortran/shared/src/test.f90",
    "content": "module test\n    implicit none (type, external)\n\ncontains\n    subroutine print_hello()\n        print *, \"Hello World!\"\n    end subroutine print_hello\nend module test\n"
  },
  {
    "path": "xmake/repository/templates/fortran/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}_lib\")\n    set_kind(\"shared\")\n    add_files(\"src/test.f90\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}_lib\")\n    add_files(\"src/main.f90\")\n\n"
  },
  {
    "path": "xmake/repository/templates/fortran/static/src/main.f90",
    "content": "program hello\n    use test, only: print_hello\n    implicit none (type, external)\n    call print_hello()\nend program hello\n"
  },
  {
    "path": "xmake/repository/templates/fortran/static/src/test.f90",
    "content": "module test\n    implicit none (type, external)\n\ncontains\n    subroutine print_hello()\n        print *, \"Hello World!\"\n    end subroutine print_hello\nend module test\n"
  },
  {
    "path": "xmake/repository/templates/fortran/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}_lib\")\n    set_kind(\"static\")\n    add_files(\"src/test.f90\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}_lib\")\n    add_files(\"src/main.f90\")\n\n"
  },
  {
    "path": "xmake/repository/templates/go/console/src/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"hello xmake!\")\n}\n"
  },
  {
    "path": "xmake/repository/templates/go/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.go\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/go/static/src/main.go",
    "content": "package main\n\nfunc main() {\n\n    Run()\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/go/static/src/module/add.go",
    "content": "package module\n\nfunc Add(a int, b int) int {\n    return a + b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/go/static/src/module/sub.go",
    "content": "package module\n\nfunc Sub(a int, b int) int {\n    return a - b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/go/static/src/test.go",
    "content": "package main\n\nimport (\n    \"fmt\"\n    \"module\"\n)\n\nfunc Run() {\n\n    fmt.Printf(\"add: %d\\n\", module.Add(1, 2));\n    fmt.Printf(\"sub: %d\\n\", module.Sub(1, 2));\n}\n"
  },
  {
    "path": "xmake/repository/templates/go/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"module\")\n    set_kind(\"static\")\n    add_files(\"src/module/*.go\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"module\")\n    add_files(\"src/*.go\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/console/src/main.kt",
    "content": "fun main() {\n    println(\"hello xmake!\")\n}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"kotlin-native\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/main.kt\")\n    set_toolchains(\"@kotlin-native\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/shared/src/foo.kt",
    "content": "@CName(\"kotlin_add\")\nfun add(a: Int, b: Int): Int = a + b\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/shared/src/main.c",
    "content": "#include \"libfoo_api.h\"\n#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"add(1, 2) = %d\\n\", kotlin_add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"kotlin-native\")\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.kt\")\n    set_toolchains(\"@kotlin-native\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    add_deps(\"foo\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/static/src/foo.kt",
    "content": "@CName(\"kotlin_add\")\nfun add(a: Int, b: Int): Int = a + b\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/static/src/main.c",
    "content": "#include \"libfoo_api.h\"\n#include <stdio.h>\n\nint main(int argc, char **argv) {\n    printf(\"add(1, 2) = %d\\n\", kotlin_add(1, 2));\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/kotlin/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\nadd_requires(\"kotlin-native\")\ntarget(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.kt\")\n    set_toolchains(\"@kotlin-native\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/main.c\")\n    add_deps(\"foo\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/nim/console/src/main.nim",
    "content": "echo \"hello xmake!\"\n"
  },
  {
    "path": "xmake/repository/templates/nim/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/main.nim\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/nim/shared/src/foo.nim",
    "content": "proc foo(n: int): int {.cdecl, exportc, dynlib.} =\n  if n < 2:\n    result = n\n  else:\n    result = foo(n - 1) + (n - 2).foo\n\n"
  },
  {
    "path": "xmake/repository/templates/nim/shared/src/main.nim",
    "content": "proc foo(n: int): int {.cdecl, importc}\n\necho foo(2)\n"
  },
  {
    "path": "xmake/repository/templates/nim/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.nim\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.nim\")\n\n${FAQ}\n\n\n"
  },
  {
    "path": "xmake/repository/templates/nim/static/src/foo.nim",
    "content": "proc foo(n: int): int {.cdecl, exportc} =\n  if n < 2:\n    result = n\n  else:\n    result = foo(n - 1) + (n - 2).foo\n\n"
  },
  {
    "path": "xmake/repository/templates/nim/static/src/main.nim",
    "content": "proc foo(n: int): int {.cdecl, importc}\n\necho foo(2)\n"
  },
  {
    "path": "xmake/repository/templates/nim/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"static\")\n    add_files(\"src/foo.nim\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.nim\")\n\n${FAQ}\n\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/console/src/main.m",
    "content": "#import <Foundation/Foundation.h>\n\nint main(int argc, char** argv) {\n    @autoreleasepool {\n        NSLog(@\"hello world!\");\n    }\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/console/xmake.lua",
    "content": "-- add modes: debug and release\nadd_rules(\"mode.debug\", \"mode.release\")\n\n-- add target\ntarget(\"${TARGET_NAME}\")\n\n    -- set kind\n    set_kind(\"binary\")\n\n    -- add files\n    add_files(\"src/*.m\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/bundle/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/bundle/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/bundle/src/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/bundle/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.bundle\")\n    add_files(\"src/*.m\")\n    add_files(\"src/Info.plist\")\n    add_headerfiles(\"src/*.h\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/framework/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/framework/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/framework/src/test.m",
    "content": "#include \"test.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/*.m\")\n    add_files(\"src/Info.plist\")\n    add_headerfiles(\"src/*.h\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    return YES;\n}\n\n\n#pragma mark - UISceneSession lifecycle\n\n\n- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {\n    // Called when a new scene session is being created.\n    // Use this method to select a configuration to create the new scene with.\n    return [[UISceneConfiguration alloc] initWithName:@\"Default Configuration\" sessionRole:connectingSceneSession.role];\n}\n\n\n- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {\n    // Called when the user discards a scene session.\n    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.h",
    "content": "//\n//  SceneDelegate.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>\n\n@property (strong, nonatomic) UIWindow * window;\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.m",
    "content": "#import \"SceneDelegate.h\"\n\n@interface SceneDelegate ()\n\n@end\n\n@implementation SceneDelegate\n\n\n- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n}\n\n\n- (void)sceneDidDisconnect:(UIScene *)scene {\n    // Called as the scene is being released by the system.\n    // This occurs shortly after the scene enters the background, or when its session is discarded.\n    // Release any resources associated with this scene that can be re-created the next time the scene connects.\n    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n}\n\n\n- (void)sceneDidBecomeActive:(UIScene *)scene {\n    // Called when the scene has moved from an inactive state to an active state.\n    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n}\n\n\n- (void)sceneWillResignActive:(UIScene *)scene {\n    // Called when the scene will move from an active state to an inactive state.\n    // This may occur due to temporary interruptions (ex. an incoming phone call).\n}\n\n\n- (void)sceneWillEnterForeground:(UIScene *)scene {\n    // Called as the scene transitions from the background to the foreground.\n    // Use this method to undo the changes made on entering the background.\n}\n\n\n- (void)sceneDidEnterBackground:(UIScene *)scene {\n    // Called as the scene transitions from the foreground to the background.\n    // Use this method to save data, release shared resources, and store enough scene-specific state information\n    // to restore the scene back to its current state.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/src/main.m",
    "content": "//\n//  main.m\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    NSString * appDelegateClassName;\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n        appDelegateClassName = NSStringFromClass([AppDelegate class]);\n    }\n    return UIApplicationMain(argc, argv, nil, appDelegateClassName);\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import <test/test.h>\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    int c = add(1, 2);\n    NSLog(@\"result: %d\", c);\n    return YES;\n}\n\n\n#pragma mark - UISceneSession lifecycle\n\n\n- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {\n    // Called when a new scene session is being created.\n    // Use this method to select a configuration to create the new scene with.\n    return [[UISceneConfiguration alloc] initWithName:@\"Default Configuration\" sessionRole:connectingSceneSession.role];\n}\n\n\n- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {\n    // Called when the user discards a scene session.\n    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.\n    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.\n}\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h",
    "content": "//\n//  SceneDelegate.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>\n\n@property (strong, nonatomic) UIWindow * window;\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m",
    "content": "#import \"SceneDelegate.h\"\n\n@interface SceneDelegate ()\n\n@end\n\n@implementation SceneDelegate\n\n\n- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n}\n\n\n- (void)sceneDidDisconnect:(UIScene *)scene {\n    // Called as the scene is being released by the system.\n    // This occurs shortly after the scene enters the background, or when its session is discarded.\n    // Release any resources associated with this scene that can be re-created the next time the scene connects.\n    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).\n}\n\n\n- (void)sceneDidBecomeActive:(UIScene *)scene {\n    // Called when the scene has moved from an inactive state to an active state.\n    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n}\n\n\n- (void)sceneWillResignActive:(UIScene *)scene {\n    // Called when the scene will move from an active state to an inactive state.\n    // This may occur due to temporary interruptions (ex. an incoming phone call).\n}\n\n\n- (void)sceneWillEnterForeground:(UIScene *)scene {\n    // Called as the scene transitions from the background to the foreground.\n    // Use this method to undo the changes made on entering the background.\n}\n\n\n- (void)sceneDidEnterBackground:(UIScene *)scene {\n    // Called as the scene transitions from the foreground to the background.\n    // Use this method to save data, release shared resources, and store enough scene-specific state information\n    // to restore the scene back to its current state.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/main.m",
    "content": "//\n//  main.m\n//  test5\n//\n//  Created by ruki on 2020/4/8.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    NSString * appDelegateClassName;\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n        appDelegateClassName = NSStringFromClass([AppDelegate class]);\n    }\n    return UIApplicationMain(argc, argv, nil, appDelegateClassName);\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.m",
    "content": "#import \"test.h\"\n#import <Foundation/Foundation.h>\n\nint add(int a, int b)\n{\n    NSLog(@\"add(%d, %d)\", a, b);\n    return a + b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/iosapp_with_framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/framework/test.m\")\n    add_files(\"src/framework/Info.plist\")\n    add_headerfiles(\"src/framework/test.h\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.application\")\n    add_deps(\"test\")\n    add_files(\"src/app/*.m\", \"src/app/**.storyboard\", \"src/app/*.xcassets\")\n    add_files(\"src/app/Info.plist\")\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test3\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test3\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test3\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test3\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test3\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test3 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/main.m",
    "content": "//\n//  main.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/src/test.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.files.user-selected.read-only</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.application\")\n    add_files(\"src/*.m\", \"src/**.storyboard\", \"src/*.xcassets\")\n    add_files(\"src/Info.plist\")\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import <test/test.h>\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {\n    // Insert code here to initialize your application\n    int c = add(1, 2);\n    NSLog(@\"result: %d\", c);\n}\n\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification {\n    // Insert code here to tear down your application\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"test3\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"test3\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About test3\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide test3\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit test3\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"test3 Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"B8D-0N-5wS\" id=\"98r-iN-zZc\"/>\n                        </connections>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>$(PRODUCT_DISPLAY_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h",
    "content": "//\n//  ViewController.h\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\n@interface ViewController : NSViewController\n\n\n@end\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m",
    "content": "//\n//  ViewController.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    // Do any additional setup after loading the view.\n}\n\n\n- (void)setRepresentedObject:(id)representedObject {\n    [super setRepresentedObject:representedObject];\n\n    // Update the view, if already loaded.\n}\n\n\n@end\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/main.m",
    "content": "//\n//  main.m\n//  test3\n//\n//  Created by ruki on 2020/4/4.\n//  Copyright © 2020 tboox. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        // Setup code that might create autoreleased objects goes here.\n    }\n    return NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.files.user-selected.read-only</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.m",
    "content": "#import \"test.h\"\n#import <Foundation/Foundation.h>\n\nint add(int a, int b)\n{\n    NSLog(@\"add(%d, %d)\", a, b);\n    return a + b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/objc/xcode/macapp_with_framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"test\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/framework/test.m\")\n    add_files(\"src/framework/Info.plist\")\n    add_headerfiles(\"src/framework/test.h\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.application\")\n    add_deps(\"test\")\n    add_files(\"src/app/*.m\", \"src/app/**.storyboard\", \"src/app/*.xcassets\")\n    add_files(\"src/app/Info.plist\")\n"
  },
  {
    "path": "xmake/repository/templates/objc++/console/src/main.mm",
    "content": "#import <Foundation/Foundation.h>\n\nint main(int argc, char** argv) {\n    @autoreleasepool {\n        NSLog(@\"hello world!\");\n    }\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc++/console/xmake.lua",
    "content": "-- add modes: debug and release\nadd_rules(\"mode.debug\", \"mode.release\")\n\n-- add target\ntarget(\"${TARGET_NAME}\")\n\n    -- set kind\n    set_kind(\"binary\")\n\n    -- add files\n    add_files(\"src/*.mm\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/bundle/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/bundle/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/bundle/src/test.mm",
    "content": "#include \"test.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/bundle/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.bundle\")\n    add_files(\"src/*.mm\")\n    add_files(\"src/Info.plist\")\n    add_headerfiles(\"src/*.h\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/framework/src/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 tboox. All rights reserved.</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/framework/src/test.h",
    "content": "#import <Foundation/Foundation.h>\n\nFOUNDATION_EXPORT int add(int a, int b);\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/framework/src/test.mm",
    "content": "#include \"test.h\"\n\nint add(int a, int b) {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/objc++/xcode/framework/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    add_rules(\"xcode.framework\")\n    add_files(\"src/*.mm\")\n    add_files(\"src/Info.plist\")\n    add_headerfiles(\"src/*.h\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/pascal/console/src/main.pas",
    "content": "program Hello;\nbegin\n  writeln ('Hello, world.');\nend.\n"
  },
  {
    "path": "xmake/repository/templates/pascal/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.pas\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/pascal/shared/src/foo.pas",
    "content": "library foo;\n\n{$mode objfpc}{$H+}\n\nfunction fib(n : Int64) : Int64; cdecl;\nbegin\n  if n > 1 then\n  begin\n      Result := fib(n - 1) + fib(n - 2);\n  end\n  else\n        Result := 1;\nend;\n\nexports\n fib;\nend.\n\n\n"
  },
  {
    "path": "xmake/repository/templates/pascal/shared/src/main.pas",
    "content": "program hello;\n\nfunction fib(n: Int64): Int64;\n  cdecl; external 'foo';\n\nvar\n  Value: Integer;\nbegin\n  Value := 5;\n  WriteLn(fib(Value));\nend.\n\n\n"
  },
  {
    "path": "xmake/repository/templates/pascal/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\ntarget(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.pas\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.pas\")\n\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/rust/console/src/main.rs",
    "content": "fn main() {\n    println!(\"hello xmake!\");\n}\n"
  },
  {
    "path": "xmake/repository/templates/rust/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/main.rs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/rust/shared/src/foo.rs",
    "content": "pub fn add(a: i32, b: i32) -> i32 {\n    return a + b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/rust/shared/src/main.rs",
    "content": "extern crate foo;\n\nfn main() {\n    println!(\"hello xmake!\");\n    println!(\"add: {}\", foo::add(1, 1));\n}\n"
  },
  {
    "path": "xmake/repository/templates/rust/shared/xmake.lua",
    "content": "target(\"foo\")\n    set_kind(\"shared\")\n    add_files(\"src/foo.rs\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.rs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/rust/static/src/foo.rs",
    "content": "pub fn add(a: i32, b: i32) -> i32 {\n    return a + b;\n}\n\n"
  },
  {
    "path": "xmake/repository/templates/rust/static/src/main.rs",
    "content": "extern crate foo;\n\nfn main() {\n    println!(\"hello xmake!\");\n    println!(\"add: {}\", foo::add(1, 1));\n}\n"
  },
  {
    "path": "xmake/repository/templates/rust/static/xmake.lua",
    "content": "target(\"foo\")\n    set_kind(\"static\")\n    add_files(\"src/foo.rs\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"foo\")\n    add_files(\"src/main.rs\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/swift/console/src/main.swift",
    "content": "import Foundation\n\nprint(\"hello world!\")\n"
  },
  {
    "path": "xmake/repository/templates/swift/console/xmake.lua",
    "content": "-- add modes: debug and release\nadd_rules(\"mode.debug\", \"mode.release\")\n\n-- add target\ntarget(\"${TARGET_NAME}\")\n\n    -- set kind\n    set_kind(\"binary\")\n\n    -- add files\n    add_files(\"src/*.swift\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/vala/console/src/main.vala",
    "content": "using Lua;\n\nstatic int my_func (LuaVM vm) {\n    stdout.printf (\"Vala Code From Lua Code! (%f)\\n\", vm.to_number (1));\n    return 1;\n}\n\nstatic int main (string[] args) {\n\n    string code = \"\"\"\n            print \"Lua Code From Vala Code!\"\n            my_func(33)\n        \"\"\";\n\n    var vm = new LuaVM ();\n    vm.open_libs ();\n    vm.register (\"my_func\", my_func);\n    vm.do_string (code);\n\n    return 0;\n}\n"
  },
  {
    "path": "xmake/repository/templates/vala/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\nadd_requires(\"lua\", \"glib\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_rules(\"vala\")\n    add_files(\"src/*.vala\")\n    add_packages(\"lua\", \"glib\")\n    add_values(\"vala.packages\", \"lua\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/vala/shared/src/main.vala",
    "content": "using MyMath;\n\npublic void main() {\n    stdout.printf(\"\\n\\t2 + 3 is %d\", sum(2, 3));\n    stdout.printf(\"\\n\\t8 squared is %d\\n\", square(8));\n}\n"
  },
  {
    "path": "xmake/repository/templates/vala/shared/src/mymath.vala",
    "content": "namespace MyMath {\n    public int sum(int a, int b) {\n        return(a + b);\n    }\n\n    public int square(int a) {\n        return(a * a);\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/vala/shared/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"glib\")\n\ntarget(\"mymath\")\n    set_kind(\"shared\")\n    add_rules(\"vala\")\n    add_files(\"src/mymath.vala\")\n    add_values(\"vala.header\", \"mymath.h\")\n    add_values(\"vala.vapi\", \"mymath-1.0.vapi\")\n    add_packages(\"glib\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"mymath\")\n    add_rules(\"vala\")\n    add_files(\"src/main.vala\")\n    add_packages(\"glib\")\n"
  },
  {
    "path": "xmake/repository/templates/vala/static/src/main.vala",
    "content": "using MyMath;\n\npublic void main() {\n    stdout.printf(\"\\n\\t2 + 3 is %d\", sum(2, 3));\n    stdout.printf(\"\\n\\t8 squared is %d\\n\", square(8));\n}\n"
  },
  {
    "path": "xmake/repository/templates/vala/static/src/mymath.vala",
    "content": "namespace MyMath {\n    public int sum(int a, int b) {\n        return(a + b);\n    }\n\n    public int square(int a) {\n        return(a * a);\n    }\n}\n"
  },
  {
    "path": "xmake/repository/templates/vala/static/xmake.lua",
    "content": "add_rules(\"mode.release\", \"mode.debug\")\n\nadd_requires(\"glib\")\n\ntarget(\"mymath\")\n    set_kind(\"static\")\n    add_rules(\"vala\")\n    add_files(\"src/mymath.vala\")\n    add_values(\"vala.header\", \"mymath.h\")\n    add_values(\"vala.vapi\", \"mymath-1.0.vapi\")\n    add_packages(\"glib\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_deps(\"mymath\")\n    add_rules(\"vala\")\n    add_files(\"src/main.vala\")\n    add_packages(\"glib\")\n"
  },
  {
    "path": "xmake/repository/templates/zig/console/src/main.zig",
    "content": "const std = @import(\"std\");\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s}!\\n\", .{\"world\"});\n}\n"
  },
  {
    "path": "xmake/repository/templates/zig/console/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"binary\")\n    add_files(\"src/*.zig\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/zig/shared/src/main.zig",
    "content": "const std = @import(\"std\");\n\nextern fn add(a: i32, b: i32) i32;\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s} - {d}!\\n\", .{\"world\", add(1, 1)});\n}\n"
  },
  {
    "path": "xmake/repository/templates/zig/shared/src/test.zig",
    "content": "export fn add(a: i32, b: i32) i32 {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/zig/shared/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"shared\")\n    add_files(\"src/test.zig\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.zig\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/repository/templates/zig/static/src/main.zig",
    "content": "const std = @import(\"std\");\n\nextern fn add(a: i32, b: i32) i32;\n\npub fn main() !void {\n    std.debug.print(\"Hello, {s} - {d}!\\n\", .{\"world\", add(1, 1)});\n}\n"
  },
  {
    "path": "xmake/repository/templates/zig/static/src/test.zig",
    "content": "export fn add(a: i32, b: i32) i32 {\n    return a + b;\n}\n"
  },
  {
    "path": "xmake/repository/templates/zig/static/xmake.lua",
    "content": "add_rules(\"mode.debug\", \"mode.release\")\n\ntarget(\"${TARGET_NAME}\")\n    set_kind(\"static\")\n    add_files(\"src/test.zig\")\n\ntarget(\"${TARGET_NAME}_demo\")\n    set_kind(\"binary\")\n    add_deps(\"${TARGET_NAME}\")\n    add_files(\"src/main.zig\")\n\n${FAQ}\n"
  },
  {
    "path": "xmake/rules/asm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: asm.build\nrule(\"asm.build\")\n    set_sourcekinds(\"as\")\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n\n-- define rule: asm\nrule(\"asm\")\n\n    -- add build rules\n    add_deps(\"asm.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n    -- add platform rules\n    add_deps(\"platform.windows\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n\n"
  },
  {
    "path": "xmake/rules/asn1c/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"asn1c\")\n    set_extensions(\".asn1\")\n    before_buildcmd_file(function (target, batchcmds, sourcefile_asn1, opt)\n\n        -- get asn1c\n        import(\"lib.detect.find_tool\")\n        local asn1c = assert(find_tool(\"asn1c\"), \"asn1c not found!\")\n\n        -- asn1 to *.c sourcefiles\n        local sourcefile_dir = path.join(target:autogendir(), \"rules\", \"asn1c\")\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.asn1c %s\", sourcefile_asn1)\n        batchcmds:mkdir(sourcefile_dir)\n        batchcmds:vrunv(asn1c.program, {path(sourcefile_asn1):absolute()}, {curdir = sourcefile_dir})\n        batchcmds:add_depfiles(sourcefile_asn1)\n        batchcmds:set_depcache(target:dependfile(sourcefile_asn1))\n\n        -- add sysincludedirs\n        target:add(\"sysincludedirs\", sourcefile_dir)\n    end)\n\n    on_buildcmd_file(function (target, batchcmds, sourcefile_asn1, opt)\n\n        -- compile *.c\n        local sourcefile_dir = path.join(target:autogendir(), \"rules\", \"asn1c\")\n        for _, sourcefile in ipairs(os.files(path.join(sourcefile_dir, \"*.c|converter-*.c\"))) do\n            local objectfile = target:objectfile(sourcefile)\n            batchcmds:compile(sourcefile, objectfile, {configs = {sysincludedirs = sourcefile_dir}})\n            table.insert(target:objectfiles(), objectfile)\n            batchcmds:add_depfiles(sourcefile)\n        end\n        batchcmds:set_depcache(target:dependfile(sourcefile_asn1 .. \".c\"))\n    end)\n"
  },
  {
    "path": "xmake/rules/c++/config/basic.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        basic.lua\n--\n\n-- main entry\nfunction main(target, sourcekind)\n    -- enable c++ exceptions by default on Windows\n    if sourcekind == \"cxx\" and target:is_plat(\"windows\") and not target:get(\"exceptions\") then\n        target:set(\"exceptions\", \"cxx\")\n    end\n\n    -- https://github.com/xmake-io/xmake/issues/4621\n    -- tcc on Windows static library needs special handling\n    if target:is_plat(\"windows\") and target:is_static() then\n        local toolname = sourcekind == \"cxx\" and \"cxx\" or \"cc\"\n        if target:has_tool(toolname, \"tcc\") then\n            target:set(\"extension\", \".a\")\n            target:set(\"prefixname\", \"lib\")\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/config/dynamic_debugging.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        dynamic_debugging.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.tool.toolchain\")\nimport(\"core.base.semver\")\n\n-- add dynamic debugging support\n-- @see https://devblogs.microsoft.com/cppblog/cpp-dynamic-debugging-full-debuggability-for-optimized-builds/\n-- https://github.com/xmake-io/xmake/issues/6258\nfunction main(target, sourcekind)\n    -- check if dynamic debugging is enabled\n    local enabled = target:policy(\"build.c++.dynamic_debugging\")\n    if enabled == nil then\n        enabled = project.policy(\"build.c++.dynamic_debugging\")\n    end\n    if not enabled then\n        return\n    end\n\n    -- only support Windows platform\n    if not target:is_plat(\"windows\") then\n        return\n    end\n\n    -- only support x64 architecture\n    if not target:is_arch(\"x64\", \"x86_64\") then\n        wprint(\"C++ Dynamic Debugging only supports x64 architecture, current arch: %s\", target:arch())\n        return\n    end\n\n    -- check MSVC toolchain (only support cl, not clang-cl or clang)\n    if not target:has_tool(sourcekind, \"cl\") then\n        return\n    end\n\n    -- check MSVC version (requires Visual Studio 2022 Version 17.14 Preview 2+, toolset 14.44+)\n    local msvc = target:toolchain(\"msvc\")\n    if not msvc or not msvc:check() then\n        wprint(\"MSVC toolchain not found for C++ Dynamic Debugging\")\n        return\n    end\n\n    local vcvars = msvc:config(\"vcvars\")\n    if not vcvars or not vcvars.VCToolsVersion then\n        wprint(\"MSVC VCToolsVersion not found for C++ Dynamic Debugging\")\n        return\n    end\n\n    local version = vcvars.VCToolsVersion\n    if not version or semver.compare(version, \"14.44\") < 0 then\n        wprint(\"C++ Dynamic Debugging requires Visual Studio 2022 Version 17.14 Preview 2+ (MSVC toolset 14.44+), found: %s\", version or \"unknown\")\n        return\n    end\n\n    -- check incompatible optimizations\n    local has_lto = target:policy(\"build.optimization.lto\") or project.policy(\"build.optimization.lto\")\n    if has_lto then\n        wprint(\"C++ Dynamic Debugging is incompatible with LTO, disabling LTO\")\n        target:set(\"policy\", \"build.optimization.lto\", false)\n    end\n\n    -- check for /GL flag (added by optimize=\"smallest\")\n    local optimize = target:get(\"optimize\")\n    if optimize == \"smallest\" then\n        wprint(\"C++ Dynamic Debugging is incompatible with optimize=\\\"smallest\\\" (which adds /GL flag), consider using optimize=\\\"fastest\\\" or optimize=\\\"faster\\\" instead\")\n    end\n\n    -- /dynamicdeopt requires debug symbols (/Zi or /Z7)\n    if not target:get(\"symbols\") then\n        target:set(\"symbols\", \"debug\")\n    end\n\n    -- get flag name for sourcekind (only support cc and cxx)\n    local cflag = sourcekind == \"cxx\" and \"cxxflags\" or \"cflags\"\n\n    -- add /dynamicdeopt compiler flag\n    target:add(cflag, \"/dynamicdeopt\", {force = true})\n\n    -- add /DYNAMICDEOPT linker flag\n    target:add(\"ldflags\", \"/DYNAMICDEOPT\", {force = true})\n    target:add(\"shflags\", \"/DYNAMICDEOPT\", {force = true})\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/config/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"rules.c++.config.basic\", {rootdir = os.programdir(), alias = \"config_basic\"})\nimport(\"rules.c++.config.dynamic_debugging\", {rootdir = os.programdir(), alias = \"config_dynamic_debugging\"})\nimport(\"rules.c++.config.optimization\", {rootdir = os.programdir(), alias = \"config_optimization\"})\nimport(\"rules.c++.config.sanitizer\", {rootdir = os.programdir(), alias = \"config_sanitizer\"})\nimport(\"rules.c++.config.runtime\", {rootdir = os.programdir(), alias = \"config_runtime\"})\n\n-- main entry\nfunction main(target, sourcekind)\n\n    -- config basic configs\n    config_basic(target, sourcekind)\n\n    -- config dynamic debugging configs (must be before optimization to disable incompatible flags)\n    config_dynamic_debugging(target, sourcekind)\n\n    -- config optimization configs\n    config_optimization(target, sourcekind)\n\n    -- config runtime configs\n    config_runtime(target)\n\n    -- config sanitizer configs\n    config_sanitizer(target, sourcekind)\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/config/optimization.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        optimization.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"core.project.project\")\n\n-- add lto optimization\nfunction _add_lto_optimization(target, sourcekind)\n    -- add cflags\n    local _, cc = target:tool(sourcekind)\n    local flagnames = {\n        cc = \"cflags\",\n        cxx = \"cxxflags\",\n        mm = \"mflags\",\n        mxx = \"mxxflags\"\n    }\n    local cflag = flagnames[sourcekind] or (sourcekind == \"cxx\" and \"cxxflags\" or \"cflags\")\n    if cc == \"cl\" then\n        target:add(cflag, \"-GL\")\n    elseif cc == \"clang\" or cc == \"clangxx\" or cc == \"clang_cl\" then\n        target:add(cflag, \"-flto=thin\")\n    elseif cc == \"gcc\" or cc == \"gxx\" then\n        target:add(cflag, \"-flto\")\n    end\n\n    -- add ldflags and shflags\n    local program, ld = target:tool(\"ld\")\n    if ld == \"link\" then\n        target:add(\"ldflags\", \"-LTCG\")\n        target:add(\"shflags\", \"-LTCG\")\n    elseif ld == \"clang\" or ld == \"clangxx\" then\n        target:add(\"ldflags\", \"-flto=thin\")\n        target:add(\"shflags\", \"-flto=thin\")\n\n        -- On Darwin, when using -flto along with -g and compiling and linking in separate steps,\n        -- you also need to pass -Wl,-object_path_lto,<lto-filename>.o at the linking step to instruct\n        -- the ld64 linker not to delete the temporary object file generated during Link Time Optimization\n        -- (this flag is automatically passed to the linker by Clang if compilation and linking are done in a single step).\n        --\n        -- This allows debugging the executable as well as generating the .dSYM bundle using dsymutil(1).\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/7029\n        -- https://clang.llvm.org/docs/CommandGuide/clang.html\n        if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n            local targetfile = target:targetfile()\n            if targetfile then\n                local lto_objectfile = target:objectfile(targetfile .. \".lto\")\n                target:add(\"ldflags\", \"-Wl,-object_path_lto,\" .. lto_objectfile)\n                target:add(\"shflags\", \"-Wl,-object_path_lto,\" .. lto_objectfile)\n            end\n        end\n    elseif ld == \"gcc\" or ld == \"gxx\" then\n        target:add(\"ldflags\", \"-flto\")\n        target:add(\"shflags\", \"-flto\")\n\n        -- to use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link.\n        -- @see https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html\n        local optimize = target:get(\"optimize\")\n        if optimize then\n            local lang_map = {\n                cc = \"c\",\n                cxx = \"cxx\",\n                mm = \"c\",\n                mxx = \"cxx\"\n            }\n            local lang = lang_map[sourcekind] or \"cxx\"\n            local optimize_flags = compiler.map_flags(lang, \"optimize\", optimize)\n            target:add(\"ldflags\", optimize_flags)\n            target:add(\"shflags\", optimize_flags)\n        end\n    end\n\n    local program, ar = target:tool(\"ar\")\n    if cc == \"clang_cl\" then\n        if ld == \"link\" then\n            wprint([[Unsupported toolset(%s) for lto, please use `set_toolset(\"ld\", \"lld-link\")`]], ld)\n            target:set(\"toolset\", \"ld\", \"lld-link\")\n            target:set(\"toolset\", \"sh\", \"lld-link\")\n        end\n        if ar ~= \"llvm-ar\" and ar ~= \"llvm_ar\" then\n            wprint([[Unsupported toolset(%s) for lto, please use `set_toolset(\"ar\", \"llvm-ar\")`]], ar)\n            target:set(\"toolset\", \"ar\", \"llvm-ar\")\n        end\n    end\nend\n\n-- main entry\nfunction main(target, sourcekind)\n    -- handle lto optimization\n    if target:policy(\"build.optimization.lto\") or project.policy(\"build.optimization.lto\") then\n        _add_lto_optimization(target, sourcekind)\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/config/runtime.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        runtime.lua\n--\n\nimport(\"core.project.config\")\n\nfunction main(target)\n    local runtimes = config.get(\"runtimes\")\n    if not runtimes and target:is_plat(\"windows\") then\n        runtimes = config.get(\"vs_runtime\")\n        if runtimes then\n            wprint(\"--vs_runtime=%s is deprecated, please use --runtimes=%s\", runtimes, runtimes)\n        end\n    end\n    if not runtimes and target:is_plat(\"android\") then\n        runtimes = config.get(\"ndk_cxxstl\")\n        if runtimes then\n            wprint(\"--ndk_cxxstl=%s is deprecated, please use --runtimes=%s\", runtimes, runtimes)\n        end\n    end\n    if runtimes and not target:get(\"runtimes\") then\n        if type(runtimes) == \"string\" then\n            runtimes = runtimes:split(\",\", {plain = true})\n        end\n        target:set(\"runtimes\", runtimes)\n    end\n\n    -- enable vs runtime as MD by default\n    if target:is_plat(\"windows\") and not target:get(\"runtimes\") then\n        local vs_runtime_default = target:policy(\"build.c++.msvc.runtime\")\n        if vs_runtime_default and target:has_tool(\"cxx\", \"cl\", \"clang\", \"clangxx\", \"clang_cl\") then\n            if is_mode(\"debug\") then\n                vs_runtime_default = vs_runtime_default .. \"d\"\n            end\n            target:set(\"runtimes\", vs_runtime_default)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/c++/config/sanitizer.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sanitizer.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.base.semver\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- add build sanitizer\nfunction _add_build_sanitizer(target, sourcekind, checkmode)\n    -- add sanitizer flags\n    local flags = toolchain_utils.get_sanitizer_flags(target, {checkmode = checkmode, sourcekind = sourcekind})\n    for name, value in pairs(flags) do\n        target:add(name, value, {force = true})\n    end\nend\n\nfunction main(target, sourcekind)\n    local sanitizer = false\n    for _, checkmode in ipairs({\"address\", \"thread\", \"memory\", \"leak\", \"undefined\"}) do\n        local enabled = target:policy(\"build.sanitizer.\" .. checkmode)\n        if enabled == nil then\n            enabled = project.policy(\"build.sanitizer.\" .. checkmode)\n        end\n        if enabled then\n            _add_build_sanitizer(target, sourcekind, checkmode)\n            sanitizer = true\n        end\n    end\n\n    if sanitizer then\n        -- enable the debug symbols for sanitizer\n        if not target:get(\"symbols\") then\n            target:set(\"symbols\", \"debug\")\n        end\n\n        -- we need to load runenvs for msvc\n        -- @see https://github.com/xmake-io/xmake/issues/4176\n        if target:is_plat(\"windows\") and target:is_binary() then\n            if target:has_tool(\"cxx\", \"cl\") then\n                local msvc = target:toolchain(\"msvc\")\n                if msvc then\n                    local envs = msvc:runenvs()\n                    local vscmd_ver = envs and envs.VSCMD_VER\n                    if vscmd_ver and semver.match(vscmd_ver):ge(\"17.7\") then\n                        local cl = assert(find_tool(\"cl\", {envs = envs}), \"cl not found!\")\n                        target:add(\"runenvs\", \"PATH\", path.directory(cl.program))\n                    end\n                end\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/builder.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        builder.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.base.profiler\")\nimport(\"async.runjobs\")\nimport(\"private.action.clean.remove_files\")\nimport(\"private.async.buildjobs\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"support\")\nimport(\"scanner\")\nimport(\"mapper\")\n\nfunction _builder(target)\n    return support.import_implementation_of(target, \"builder\")\nend\n\n-- generate meta module informations for package / other buildsystems import\n--\n-- e.g\n-- {\n--      \"flags\": [\"--std=c++23\"]\n--      \"imports\": [\"std\", \"bar\"]\n--      \"name\": \"foo\"\n--      \"file\": \"foo.cppm\"\n-- }\nfunction _generate_meta_module_info(target, module)\n    local fileconfig = target:fileconfig(module.sourcefile)\n    local defines = table.join(target:get(\"defines\") or {}, fileconfig and fileconfig.defines or {})\n    local undefines = table.join(target:get(\"undefines\") or {}, fileconfig and fileconfig.undefines or {})\n    local modulehash = support.get_modulehash(module.sourcefile)\n    local module_metadata = {name = module.name, file = path.join(modulehash, path.filename(module.sourcefile)), defines = defines, undefines = undefines}\n\n    -- add imports\n    for name, _ in table.orderpairs(module.deps) do\n        module_metadata.imports = module_metadata.imports or {}\n        table.insert(module_metadata.imports, name)\n    end\n    return module_metadata\nend\n\nfunction _get_module_buildgroup_for(target, moduletype)\n    return target:fullname() .. \"/modules/build/\" .. moduletype\nend\n\nfunction _get_module_buildfilejob_for(target, sourcefile, moduletype)\n    return _get_module_buildgroup_for(target, moduletype) .. \"/\" .. sourcefile\nend\n\nfunction _get_headerunit_buildgroup_for(target)\n    return target:fullname() .. \"/headerunit/build\"\nend\n\nfunction _get_headerunit_buildfilejob_for(target, sourcefile)\n    return _get_headerunit_buildgroup_for(target) .. \"/\" .. sourcefile\nend\n\nfunction _get_buildfilejob_for(target, sourcefile, opt)\n    if opt and opt.headerunit then\n        return _get_headerunit_buildfilejob_for(target, sourcefile)\n    end\n    return _get_module_buildfilejob_for(target, sourcefile, opt.moduletype)\nend\n\nfunction _get_jobdeps(target, module, jobgraph, buildfilejob)\n\n    local memcache = support.memcache()\n    local jobdeps = {}\n    local moduletype = support.has_two_phase_compilation_support(target) and \"bmi\" or \"onephase\"\n    for dep_name, dep in pairs(module.deps) do\n        if dep.headerunit then\n            dep_name = dep_name .. dep.key\n        end\n        local dep_module = mapper.get(target, dep_name)\n        local dep_sourcefile = dep_module.sourcefile\n        if dep.headerunit then\n            dep_sourcefile = dep_sourcefile .. dep_module.key\n        end\n\n        local reused, from = support.is_reused(target, dep_sourcefile)\n        local dep_jobname\n        if dep_module.headerunit then\n            dep_jobname = _get_headerunit_buildfilejob_for(reused and from or target, dep_sourcefile)\n        else\n            dep_jobname = _get_module_buildfilejob_for(reused and from or target, dep_sourcefile, moduletype)\n        end\n        -- if dep_jobname is available, order it now\n        if jobgraph:has(dep_jobname) then\n            jobdeps[buildfilejob] = jobdeps[buildfilejob] or {}\n            table.insert(jobdeps[buildfilejob], dep_jobname)\n        -- if dep_jobname is not currently available, save deps for later ordering\n        else\n            local dependent_jobs = memcache:get2(\"dependent_jobs\", dep_jobname) or {}\n            table.insert(dependent_jobs, buildfilejob)\n            memcache:set2(\"dependent_jobs\", dep_jobname, dependent_jobs)\n        end\n    end\n    return jobdeps\nend\n\nfunction _get_saved_jobdeps_for(jobgraph, buildfilejob)\n    local memcache = support.memcache()\n    local dependent_jobs = memcache:get2(\"dependent_jobs\", buildfilejob)\n    local jobdeps = {}\n    for _, dependent_job in ipairs(dependent_jobs) do\n        if jobgraph:has(dependent_job) then\n            jobdeps[dependent_job] = jobdeps[dependent_job] or {}\n            table.insert(jobdeps[dependent_job], buildfilejob)\n        end\n    end\n    return jobdeps\nend\n\nfunction _in_project_generator()\n    local memcache = support.memcache()\n    local in_project_generator = memcache:get(\"in_project_generator\")\n    if in_project_generator == nil then\n        local val = os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\")\n        if val and val ~= \"\" then\n            in_project_generator = true\n        end\n        in_project_generator = in_project_generator or false\n        memcache:set(\"in_project_generator\", in_project_generator)\n    end\n    return in_project_generator\nend\n\n-- should we build this module or headerunit ?\nfunction should_build(target, module)\n\n    -- if we are generating project files, we always need to generate all build commands.\n    -- @see https://github.com/xmake-io/xmake/issues/6600\n    if _in_project_generator() then\n        return true\n    end\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n    local memcache = support.memcache()\n    local _should_build = memcache:get2(target:fullname(), \"should_build_\" .. module.sourcefile)\n    if _should_build == nil then\n        local key = module.headerunit and module.sourcefile .. module.key or module.sourcefile\n        local reused, from = support.is_reused(target, key)\n        if reused then\n            local build = should_build(from, module)\n            memcache:set2(target:fullname(), \"should_build_\" .. module.sourcefile, build)\n            profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n            return build\n        end\n        local compinst = compiler.load(\"cxx\", {target = target})\n        local compflags = compinst:compflags({sourcefile = module.sourcefile, target = target})\n\n        local dependfile = target:dependfile(module.bmifile or module.objectfile)\n        local dependinfo = {}\n        dependinfo.files = {module.sourcefile}\n        dependinfo.values = {compinst:program(), compflags}\n        local objectfile_exists = (module.headerunit or support.is_bmionly(target, module.sourcefile)) and true or os.isfile(module.objectfile)\n        dependinfo.lastmtime = (os.isfile(module.bmifile or module.objectfile) and objectfile_exists) and os.mtime(dependfile) or 0\n\n        local fileconfig = target:fileconfig(module.sourcefile)\n        local from_package = fileconfig and fileconfig.from_package\n        local is_std = path.basename(module.sourcefile) == \"std\" or path.basename(module.sourcefile) == \"std.compat\"\n        local rebuild = target:is_rebuilt() and not from_package and not is_std\n        local old_dependinfo = rebuild and {} or (depend.load(dependfile) or {})\n        old_dependinfo.files = {module.sourcefile}\n\n        -- need build this object?\n        local dryrun = option.get(\"dry-run\")\n        if dryrun or depend.is_changed(old_dependinfo, dependinfo) then\n            depend.save(dependinfo, dependfile)\n            memcache:set2(target:fullname(), \"should_build_\" .. module.sourcefile, true)\n            profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n            return true\n        end\n\n        -- force rebuild a module if any of its module dependency is rebuilt\n        for dep_name, dep_module in table.orderpairs(module.deps) do\n            local mapped_dep = mapper.get(target, dep_module.headerunit and dep_name .. dep_module.key or dep_name)\n\n            if should_build(target, mapped_dep) then\n                depend.save(dependinfo, dependfile)\n                memcache:set2(target:fullname(), \"should_build_\" .. module.sourcefile, true)\n                profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n                return true, true\n            end\n        end\n\n        memcache:set2(target:fullname(), \"should_build_\" .. module.sourcefile, false)\n        profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n        return false\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if \" .. (module.name or module.sourcefile) .. \" should be rebuilt\")\n    return _should_build\nend\n\n-- build modules for jobgraph\n-- only build bmis if two phase compilation is supported\n-- it not build also objectfiles\nfunction build_modules_for_jobgraph(target, jobgraph, built_modules)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"schedule module bmi build jobs\")\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n    local jobdeps = {}\n    local buildfilejobs = {}\n\n    -- get named modules\n    local _built_modules = {}\n    for _, sourcefile in ipairs(built_modules) do\n        local module = mapper.get(target, sourcefile)\n        if module.name then\n            table.insert(_built_modules, sourcefile)\n        else\n            if not support.is_bmionly(target, sourcefile) then\n                local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, \"objectfile\")\n                table.join2(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob))\n                table.insert(buildfilejobs, buildfilejob)\n                local objbuildfilejob = target:fullname() .. \"/obj/\" .. sourcefile\n                if jobgraph:has(objbuildfilejob) then\n                    jobdeps[objbuildfilejob] = {buildfilejob}\n                end\n            end\n        end\n    end\n    -- add module jobs\n    local moduletype = has_two_phase_compilation_support and \"bmi\" or \"onephase\"\n    local buildgroup = _get_module_buildgroup_for(target, moduletype)\n    jobgraph:group(buildgroup, function()\n        for _, sourcefile in ipairs(_built_modules) do\n            local module = mapper.get(target, sourcefile)\n            local bmionly = support.is_bmionly(target, module.sourcefile)\n            local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, moduletype)\n            table.insert(buildfilejobs, buildfilejob)\n            jobgraph:add(buildfilejob, function(_, _, jobopt)\n                progress.set_target(jobopt.progress, target)\n                -- build bmi if named job\n                jobopt.bmi = module.name\n                -- build objectfile here if two phase compilation is not supported\n                jobopt.objectfile = not has_two_phase_compilation_support and not bmionly\n                builder.make_module_job(target, module, jobopt)\n            end)\n            table.join2(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob))\n\n            -- if two phase compilation supported set jobdeps for objectfile job\n            if has_two_phase_compilation_support and not bmionly then\n                local objbuildfilejob = _get_module_buildfilejob_for(target, sourcefile, \"objectfile\")\n                jobdeps[objbuildfilejob] = {buildfilejob}\n            end\n        end\n    end)\n\n    -- insert saved jobdeps\n    for _, buildfilejob in ipairs(buildfilejobs) do\n        table.join2(jobdeps, _get_saved_jobdeps_for(jobgraph, buildfilejob))\n    end\n\n    -- apply jobdeps\n    for jobname, deps in pairs(jobdeps) do\n        for _, depname in ipairs(deps) do\n            jobgraph:add_orders(depname, jobname)\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"schedule module bmi build jobs\")\nend\n\n-- build modules objectfiles for jobgraph if two phase compilation is supported\nfunction build_objectfiles_for_jobgraph(target, jobgraph, built_modules)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"schedule module objectfiles build jobs\")\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n    local buildgroup = _get_module_buildgroup_for(target, \"objectfile\")\n    local _built_modules = {}\n    if has_two_phase_compilation_support then\n        _built_modules = built_modules\n    else\n        for _, sourcefile in ipairs(built_modules) do\n            local module = mapper.get(target, sourcefile)\n            if not module.name then\n                table.insert(_built_modules, sourcefile)\n            end\n        end\n    end\n    jobgraph:group(buildgroup, function()\n        for _, sourcefile in ipairs(_built_modules) do\n            if not support.is_bmionly(target, sourcefile) then\n                local module = mapper.get(target, sourcefile)\n                local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, \"objectfile\")\n                jobgraph:add(buildfilejob, function(_, _, jobopt)\n                    progress.set_target(jobopt.progress, target)\n                    jobopt.bmi = false\n                    jobopt.objectfile = true\n                    builder.make_module_job(target, module, jobopt)\n                end)\n            end\n        end\n    end)\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"schedule module objectfiles build jobs\")\nend\n\n-- build batchjobs for modules\nfunction build_batchjobs_for_modules(modules, batchjobs, rootjob)\n    return buildjobs(modules, batchjobs, rootjob)\nend\n\n-- build modules for batchjobs (deprecated)\nfunction build_modules_for_batchjobs(target, batchjobs, built_modules, opt)\n\n    opt.rootjob = batchjobs:group_leave() or opt.rootjob\n    batchjobs:group_enter(target:fullname() .. \"/build_cxxmodules_bmi\", {rootjob = opt.rootjob})\n\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n\n    -- if two phase supported only build named modules bmi\n    local _built_modules = {}\n    for _, sourcefile in ipairs(built_modules) do\n        local module = mapper.get(target, sourcefile)\n        if module.name then\n            table.insert(_built_modules, sourcefile)\n        end\n    end\n\n    -- add module jobs\n    local jobs\n    local moduletype = has_two_phase_compilation_support and \"bmi\" or \"onephase\"\n    for _, sourcefile in ipairs(_built_modules) do\n        jobs = jobs or {}\n        local bmionly = support.is_bmionly(target, sourcefile)\n        local module = mapper.get(target, sourcefile)\n\n        local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, moduletype)\n        local deps = {}\n        for dep_name, dep in pairs(module.deps) do\n            if dep.headerunit then\n                dep_name = dep_name .. dep.key\n            end\n            local dep_module = mapper.get(target, dep_name)\n            local dep_sourcefile = dep_module.sourcefile\n            if dep.headerunit then\n                dep_sourcefile = dep_sourcefile .. dep_module.key\n            end\n\n            local reused, from = support.is_reused(target, dep_sourcefile)\n            local dep_jobname\n            if dep_module.headerunit then\n                dep_jobname = _get_headerunit_buildfilejob_for(reused and from or target, dep_sourcefile)\n            else\n                dep_jobname = _get_module_buildfilejob_for(reused and from or target, dep_sourcefile, moduletype)\n            end\n            table.insert(deps, dep_jobname)\n        end\n        jobs[buildfilejob] = {\n            name = buildfilejob,\n            deps = deps,\n            sourcefile = module.sourcefile,\n            job = batchjobs:newjob(buildfilejob, function(_, _, jobopt)\n                -- build bmi if named job\n                jobopt.bmi = module.name\n                -- build objectfile here if two phase compilation is not supported\n                jobopt.objectfile = not has_two_phase_compilation_support and not bmionly\n                builder.make_module_job(target, module, jobopt)\n            end)}\n    end\n\n    return jobs\nend\n\n-- build modules objectfiles for batchjobs if two phase compilation is supported (deprecated)\nfunction build_objectfiles_for_batchjobs(target, batchjobs, built_modules, opt)\n\n    opt.rootjob = batchjobs:group_leave() or opt.rootjob\n    batchjobs:group_enter(target:fullname() .. \"/build_cxxmodules_objectfiles\", {rootjob = opt.rootjob})\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n    local _built_modules = {}\n    if has_two_phase_compilation_support then\n        _built_modules = built_modules\n    else\n        for _, sourcefile in ipairs(built_modules) do\n            local module = mapper.get(target, sourcefile)\n            if not module.name then\n                table.insert(_built_modules, sourcefile)\n            end\n        end\n    end\n\n    local jobs\n    for _, sourcefile in ipairs(_built_modules) do\n        if not support.is_bmionly(target, sourcefile) then\n            jobs = jobs or {}\n            local module = mapper.get(target, sourcefile)\n            local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, \"objectfile\")\n            jobs[buildfilejob] = {\n                name = buildfilejob,\n                sourcefile = module.sourcefile,\n                job = batchjobs:newjob(buildfilejob, function(_, _, jobopt)\n                    jobopt.bmi = false\n                    jobopt.objectfile = true\n                    builder.make_module_job(target, module, jobopt)\n                end)}\n        end\n    end\n\n    return jobs\nend\n\n-- build modules for batchcmds\nfunction build_modules_for_batchcmds(target, batchcmds, built_modules, opt)\n    opt.progress = opt.progress or 0\n    local depmtime = 0\n    -- build modules\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n\n    local _built_modules = {}\n    for _, sourcefile in ipairs(built_modules) do\n        local module = mapper.get(target, sourcefile)\n        if module.name then\n            table.insert(_built_modules, sourcefile)\n        end\n    end\n\n    for _, sourcefile in ipairs(_built_modules) do\n        local bmionly = support.is_bmionly(target, sourcefile)\n        local module = mapper.get(target, sourcefile)\n        local jobopt = {}\n        jobopt.bmi = module.name\n        jobopt.objectfile = not has_two_phase_compilation_support and not bmionly\n        jobopt.progress = opt.progress\n        depmtime = math.max(depmtime, builder.make_module_buildcmds(target, batchcmds, module, jobopt))\n    end\n    batchcmds:set_depmtime(depmtime)\nend\n\n-- build modules objectfiles for batchcmds if two phase compilation is supported\nfunction build_objectfiles_for_batchcmds(target, batchcmds, built_modules, opt)\n\n    opt.progress = opt.progress or 0\n    local depmtime = 0\n    local builder = _builder(target)\n    local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)\n    local _built_modules = {}\n    if has_two_phase_compilation_support then\n        _built_modules = built_modules\n    else\n        for _, sourcefile in ipairs(built_modules) do\n            local module = mapper.get(target, sourcefile)\n            if not module.name then\n                table.insert(_built_modules, sourcefile)\n            end\n        end\n    end\n\n    for _, sourcefile in ipairs(_built_modules) do\n        if not support.is_bmionly(target, sourcefile) then\n            local module = mapper.get(target, sourcefile)\n            local jobopt = {}\n            jobopt.bmi = false\n            jobopt.objectfile = true\n            jobopt.progress = opt.progress\n            depmtime = math.max(depmtime, builder.make_module_buildcmds(target, batchcmds, module, jobopt))\n        end\n    end\n    batchcmds:set_depmtime(depmtime)\nend\n\n-- build headerunits for jobgraph\nfunction build_headerunits_for_jobgraph(target, jobgraph, built_stlheaderunits, built_headerunits)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"schedule headerunits build jobs\")\n    local builder = _builder(target)\n    function make_headerunit_job(headerfile, opt)\n        local reused, from = support.is_reused(target, headerfile)\n        local _target = reused and from or target\n        local headerunit = mapper.get(target, headerfile)\n        if not headerunit.alias then\n            local buildfilejob = _get_headerunit_buildfilejob_for(_target, headerunit.sourcefile .. headerunit.key)\n            if not jobgraph:has(buildfilejob) then\n                jobgraph:add(buildfilejob, function(_, _, jobopt)\n                    progress.set_target(jobopt.progress, _target)\n                    builder.make_headerunit_job(_target, headerunit, table.join(jobopt, opt))\n                end)\n            end\n        end\n    end\n\n    local headerunit_buildgroup = _get_headerunit_buildgroup_for(target)\n    if built_stlheaderunits then\n        -- build stl header units first as other headerunits may need them\n        jobgraph:group(headerunit_buildgroup, function()\n            for _, headerfile in ipairs(built_stlheaderunits) do\n                make_headerunit_job(headerfile, {stl_headerunit = true})\n            end\n        end)\n    end\n\n    if built_headerunits then\n        jobgraph:group(headerunit_buildgroup, function()\n            for _, headerfile in ipairs(built_headerunits) do\n                make_headerunit_job(headerfile)\n            end\n        end)\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"schedule headerunits build jobs\")\nend\n\n-- build headerunits for batchjobs\nfunction build_headerunits_for_batchjobs(target, batchjobs, built_stlheaderunits, built_headerunits, opt)\n\n    -- we need new group(headerunits)\n    -- e.g. group(build_modules) -> group(headerunits)\n    opt.rootjob = batchjobs:group_leave() or opt.rootjob\n    batchjobs:group_enter(target:fullname() .. \"/build_headerunits\", {rootjob = opt.rootjob})\n    local builder = _builder(target)\n    local jobs = {}\n    function make_headerunit_job(headerfile, opt)\n        local reused, from = support.is_reused(target, headerfile)\n        local _target = reused and from or target\n        local headerunit = mapper.get(target, headerfile)\n        if not headerunit.alias then\n            local buildfilejob = _get_headerunit_buildfilejob_for(_target, headerunit.sourcefile .. headerunit.key)\n            jobs[buildfilejob] = {\n                name = buildfilejob,\n                sourcefile = headerunit.sourcefile,\n                job = batchjobs:newjob(buildfilejob, function(_, _, jobopt)\n                    builder.make_headerunit_job(_target, headerunit, table.join(jobopt, opt))\n                end)}\n        end\n    end\n\n    if built_stlheaderunits then\n        -- build stl header units first as other headerunits may need them\n        for _, headerfile in ipairs(built_stlheaderunits) do\n            make_headerunit_job(headerfile, {stl_headerunit = true})\n        end\n    end\n\n    if built_headerunits then\n        for _, headerfile in ipairs(built_headerunits) do\n            make_headerunit_job(headerfile)\n        end\n    end\n    return jobs\nend\n\n-- build headerunits for batchcmds\nfunction build_headerunits_for_batchcmds(target, batchcmds, built_stlheaderunits, built_headerunits, opt)\n\n    local builder = _builder(target)\n    function make_headerunit_buildcmds(headerfile, jobopt)\n        local reused, from = support.is_reused(target, headerfile)\n        local _target = reused and from or target\n        local headerunit = mapper.get(target, headerfile)\n        if not headerunit.alias then\n            builder.make_headerunit_buildcmds(_target, batchcmds, headerunit, table.join(opt, jobopt))\n        end\n    end\n\n    -- build stl header units first as other headerunits may need them\n    -- opt.stl_headerunit = true\n    for _, headerfile in ipairs(built_stlheaderunits) do\n        make_headerunit_buildcmds(headerfile, {stl_headerunit = true})\n    end\n    -- opt.stl_headerunit = false\n    for _, headerfile in ipairs(built_headerunits) do\n        make_headerunit_buildcmds(headerfile)\n    end\nend\n\nfunction generate_metadata(target, modules)\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"generate module metadata\")\n    local public_modules\n    for sourcefile, module in table.orderpairs(modules) do\n        local fileconfig = target:fileconfig(sourcefile)\n        local public = fileconfig and fileconfig.public\n        if public then\n            public_modules = public_modules or {}\n            table.insert(public_modules, module)\n        end\n    end\n\n    if not public_modules then\n        profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"generate module metadata\")\n        return\n    end\n\n    local jobs = option.get(\"jobs\") or os.default_njob()\n    runjobs(target:fullname() .. \"_install_modules\", function(index, _, jobopt)\n        progress.set_target(jobopt.progress, target)\n        local module = public_modules[index]\n        local metafilepath = support.get_metafile(target, module)\n        progress.show(jobopt.progress, \"${color.build.target}generating.module.metadata %s\", module.name)\n        local metadata = _generate_meta_module_info(target, module)\n        json.savefile(metafilepath, metadata)\n    end, {comax = jobs, total = #public_modules})\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"generate module metadata\")\nend\n\n-- check if dependencies changed\nfunction is_dependencies_changed(target, module)\n    profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"check if dependency chain changed\")\n    local cachekey = target:fullname() .. (module.name or module.sourcefile)\n    local requires = hashset.from(table.keys(module.deps or {}))\n    local oldrequires = support.memcache():get2(cachekey, \"oldrequires\")\n    local changed = false\n    if oldrequires then\n        if oldrequires ~= requires then\n           changed = true\n        else\n           for required in requires:items() do\n              if not oldrequires:has(required) then\n                  changed = true\n                  break\n              end\n           end\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"check if dependency chain changed\")\n    return requires, changed\nend\n\nfunction show_progress(target, module, opt)\n    local show = function(...)\n        local batchcmds = opt and opt.batchcmds\n        if batchcmds then\n            batchcmds:show_progress(opt.progress, ...)\n        else\n            progress.show(opt.progress, ...)\n        end\n    end\n    local suffix = opt.suffix or \"\"\n    local cmd = opt.cmd or \"\"\n    local dim = \"\"\n    if option.get(\"verbose\") then\n        dim = \"${dim}\"\n    end\n    local header = \"${clear}\" .. dim\n    if opt.headerunit then\n        local name = module.method == \"include-angle\" and (\"<\" .. path.filename(module.name) .. \">\") or module.name\n        show(header .. \"compiling.headerunit.$(mode) %s${clear}%s\" .. suffix, name, cmd)\n    elseif opt.bmi then\n        if opt.objectfile then\n            show(header .. \"compiling.module.$(mode) %s${clear}%s\" .. suffix, module.name, cmd)\n        else\n            show(header .. \"compiling.module.bmi.$(mode) %s${clear}%s\" .. suffix, module.name, cmd)\n        end\n    else\n        show(\"compiling.$(mode) %s${clear}%s\" .. suffix, module.sourcefile, cmd)\n    end\nend\n\nfunction clean(target)\n    -- we cannot use target:data(\"cxx.has_modules\"),\n    -- because on_config will be not called when cleaning targets\n    if support.contains_modules(target) then\n        remove_files(support.modules_cachedir(target, {interface = true}))\n        remove_files(support.modules_cachedir(target, {interface = false}))\n        remove_files(support.modules_cachedir(target, {headerunit = true}))\n        if option.get(\"all\") then\n            support.localcache():clear()\n            support.localcache():save()\n        end\n    end\nend\n\nfunction build_bmis(target, jobgraph, _, opt)\n    opt = opt or {}\n    if target:data(\"cxx.has_modules\") then\n        if target:is_moduleonly() and not target:data(\"cxx.modules.reused\") or target:is_phony() then\n            return\n        end\n        profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"bmis\")\n        local modules = scanner.get_modules(target)\n        -- avoid building non referenced modules\n        local built_modules, built_headerunits, _ = scanner.sort_modules_by_dependencies(target, modules, {jobgraph = target:policy(\"build.jobgraph\")})\n        local headerunits, stlheaderunits = scanner.sort_headerunits(target, built_headerunits)\n        if jobgraph.add_orders then -- jobgraph\n            -- build headerunits\n            if stlheaderunits or headerunits then\n                build_headerunits_for_jobgraph(target, jobgraph, stlheaderunits, headerunits)\n            end\n\n            -- build modules\n            build_modules_for_jobgraph(target, jobgraph, built_modules)\n        elseif jobgraph.newjob then -- batchjobs (deprecated)\n            opt.batchjobs = true\n            -- build headerunits\n            local headerunit_jobs = build_headerunits_for_batchjobs(target, jobgraph, stlheaderunits, headerunits, opt)\n\n            -- build modules\n            local module_jobs = build_modules_for_batchjobs(target, jobgraph, built_modules, opt)\n\n            build_batchjobs_for_modules(table.join(headerunit_jobs or {}, module_jobs or {}), jobgraph, opt.rootjob)\n        elseif jobgraph.runcmds then -- batchcmds\n            opt.progress = opt.progress or 0\n            -- build headerunits\n            build_headerunits_for_batchcmds(target, jobgraph, stlheaderunits, headerunits, opt)\n\n            local append_requires_flags = _builder(target).append_requires_flags\n            if append_requires_flags then\n                append_requires_flags(target, built_modules)\n            end\n\n            -- build modules\n            build_modules_for_batchcmds(target, jobgraph, built_modules, opt)\n        else\n            assert(false, \"shouldn't be here :D\")\n        end\n        profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"bmis\")\n    end\nend\n\nfunction build_objectfiles(target, jobgraph, _, opt)\n\n    if target:data(\"cxx.has_modules\") then\n        if target:is_moduleonly() and not target:data(\"cxx.modules.reused\") or target:is_phony() then\n            return\n        end\n        profiler.enter(target:fullname(), \"c++ modules\", \"builder\", \"objectfiles\")\n        local modules = scanner.get_modules(target)\n        -- avoid building non referenced modules\n        local built_modules, _, _ = scanner.sort_modules_by_dependencies(target, modules, {jobgraph = target:policy(\"build.jobgraph\")})\n        local append_requires_flags = _builder(target).append_requires_flags\n        if append_requires_flags then\n            append_requires_flags(target, built_modules)\n        end\n\n        if jobgraph.add_orders then -- jobgraph\n            -- build modules objectfiles\n            build_objectfiles_for_jobgraph(target, jobgraph, built_modules)\n        elseif jobgraph.newjob then -- batchjobs (deprecated)\n            opt.batchjobs = true\n            -- build modules objectfiles\n            local jobs = table.join(build_objectfiles_for_batchjobs(target, jobgraph, built_modules, opt) or {}, jobs or {})\n\n            build_batchjobs_for_modules(jobs, jobgraph, opt.rootjob)\n        elseif jobgraph.runcmds then -- batchcmds\n            -- build modules objectfiles\n            build_objectfiles_for_batchcmds(target, jobgraph, built_modules, opt)\n        else\n            assert(false, \"shouldn't be here :D\")\n        end\n        profiler.leave(target:fullname(), \"c++ modules\", \"builder\", \"objectfiles\")\n    end\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/clang/builder.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        clang/builder.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.bytes\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"utils.progress\")\nimport(\"private.action.build.object\", {alias = \"objectbuilder\"})\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"support\")\nimport(\".mapper\")\nimport(\".builder\", {inherit = true})\n\nfunction _get_bmifile(target, module)\n    local has_reduced_bmi = support.get_modulesreducedbmiflag(target)\n    local has_two_phases = target:policy(\"build.c++.modules.two_phases\")\n    -- disabled with two phases currently, LLVM currently have a bug which prevent to emit reduced bmi when using two phase compilation\n    -- will be enabled after the fix\n    local add_reduced_flag = not has_two_phases and has_reduced_bmi\n    local bmifile = module.bmifile\n\n    if has_two_phases and add_reduced_flag then\n        bmifile = path.join(path.directory(module.bmifile), \"reduced.\" .. path.filename(module.bmifile))\n    end\n\n    return bmifile, add_reduced_flag\nend\n\nfunction _update_bmihash(target, module)\n    local localcache = support.localcache()\n\n    local bmifile = _get_bmifile(target, module)\n    local bmihash = hash.xxhash128(bytes(io.readfile(bmifile)))\n    local old_bmihash = localcache:get2(bmifile, \"hash\")\n\n    if not old_bmihash or bmihash ~= old_bmihash then\n        localcache:set2(bmifile, \"hash\", bmihash)\n        support.memcache():set2(bmifile, \"updated\", true)\n    end\nend\n\nfunction _make_modulebuildflags(target, module, opt)\n    assert(not module.headerunit)\n\n    local modules_reduced_bmi_flag = support.get_modulesreducedbmiflag(target)\n    local has_two_phases = target:policy(\"build.c++.modules.two_phases\")\n    local flags\n    if opt.bmi then\n        local module_outputflag = support.get_moduleoutputflag(target)\n\n        flags = {\"-x\", \"c++-module\"}\n\n        if not opt.objectfile then\n            table.insert(flags, \"--precompile\")\n            if target:has_tool(\"cxx\", \"clang_cl\") then\n                table.join2(flags, \"/clang:-o\", \"/clang:\" .. module.bmifile)\n            end\n        end\n        local std = (module.name == \"std\" or module.name == \"std.compat\")\n        if std then\n            table.join2(flags, {\"-Wno-include-angled-in-module-purview\", \"-Wno-reserved-module-identifier\", \"-Wno-deprecated-declarations\"})\n        end\n\n        local bmifile, add_reduced_flag = _get_bmifile(target, module)\n        if add_reduced_flag then\n            table.insert(flags, modules_reduced_bmi_flag)\n        end\n\n        if not has_two_phases or add_reduced_flag  then\n            table.insert(flags, module_outputflag .. bmifile)\n        end\n    else\n        flags = {}\n        if not has_two_phases or not module.bmifile then\n            flags = {\"-x\", \"c++\"}\n        end\n        local std = (module.name == \"std\" or module.name == \"std.compat\")\n        if std then\n            table.join2(flags, {\"-Wno-include-angled-in-module-purview\", \"-Wno-reserved-module-identifier\", \"-Wno-deprecated-declarations\"})\n        end\n    end\n    return flags\nend\n\nfunction _compile_one_step(target, module, opt)\n    -- get flags\n    local module_outputflag = support.get_moduleoutputflag(target)\n    if module_outputflag then\n        local flags = _make_modulebuildflags(target, module, opt)\n        if opt and opt.batchcmds then\n            _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n        else\n            _compile(target, flags, module, opt)\n        end\n    else\n        _compile_bmi_step(target, module, opt)\n        _compile_objectfile_step(target, module, opt)\n    end\nend\n\nfunction _compile_bmi_step(target, module, opt)\n    local flags = _make_modulebuildflags(target, module, opt)\n    if opt and opt.batchcmds then\n        _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n    else\n        _compile(target, flags, module, opt)\n    end\nend\n\nfunction _compile_objectfile_step(target, module, opt)\n    local flags = _make_modulebuildflags(target, module, opt)\n    if opt and opt.batchcmds then\n        _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n    else\n        _compile(target, flags, module, opt)\n    end\nend\n\n-- get flags for building a headerunit\nfunction _make_headerunitflags(target, headerunit)\n    local module_headerflag = support.get_moduleheaderflag(target)\n    assert(module_headerflag, \"compiler(clang): does not support c++ header units!\")\n\n    local local_directory = (headerunit.type == \":quote\") and {\"-I\" .. path.directory(headerunit.path)} or {}\n    local headertype = (headerunit.method == \"include-quote\") and \"system\" or \"user\"\n    local flags = table.join(local_directory, {\"-xc++-header\", \"-Wno-everything\", module_headerflag .. headertype})\n    return flags\nend\n\n\nfunction _get_mapper_str(target, module, opt)\n    local mapper_str\n    if target:policy(\"build.c++.modules.hide_dependencies\") and option.get(\"diagnosis\") then\n        if not opt.headerunit then\n            local requires_flagsfile = target:autogenfile(module.sourcefile .. \".requiresflags.txt\")\n            if os.isfile(requires_flagsfile) then\n                if module.name then\n                    mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", module.name, module.sourcefile, io.readfile(requires_flagsfile):trim())\n                else\n                    mapper_str = format(\"\\n${dim color.warning}mapper file for %s --------\\n%s\\n--------\", module.sourcefile, io.readfile(requires_flagsfile):trim())\n                end\n            end\n        end\n    end\n    return mapper_str\nend\n\n-- do compile\nfunction _compile(target, flags, module, opt)\n\n    opt = opt or {}\n    local sourcefile = module.sourcefile\n    if not opt.bmi and opt.objectfile and module.bmifile then\n        sourcefile = module.bmifile\n    end\n    local outputfile = ((opt.bmi and not opt.objectfile) or opt.headerunit) and module.bmifile or module.objectfile\n    local dryrun = option.get(\"dry-run\")\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = module.sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(compflags or {}, flags or {})\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, sourcekind = \"cxx\", rawargs = true})\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, suffix = _get_mapper_str(target, module, opt)}))\n\n    -- do compile\n    if not dryrun then\n        assert(compinst:compile(sourcefile, outputfile, {target = target, compflags = flags}))\n    end\nend\n\n-- do compile for batchcmds\n-- @note we need to use batchcmds:compilev to translate paths in compflags for generator, e.g. -Ixx\nfunction _batchcmds_compile(batchcmds, target, flags, module, opt)\n    opt = opt or {}\n    local sourcefile = module.sourcefile\n    local outputfile = (opt.bmi and not opt.objectfile) and module.bmifile or module.objectfile\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = module.sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(\"-c\", compflags or {}, flags or {}, {\"-o\", outputfile, sourcefile})\n\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, sourcekind = \"cxx\", rawargs = true})\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, batchcmds = batchcmds, suffix = _get_mapper_str(target, module, opt)}))\n\n    -- do compile\n    batchcmds:compilev(flags, {compiler = compinst, sourcekind = \"cxx\", verbose = false})\nend\n\n-- get module requires flags\n-- e.g\n-- -fmodule-file=build/.gens/Foo/rules/modules/cache/foo.pcm\n-- -fmodule-file=build/.gens/Foo/rules/modules/cache/iostream.pcm\n-- -fmodule-file=build/.gens/Foo/rules/modules/cache/bar.hpp.pcm\n-- on LLVM >= 16\n-- -fmodule-file=foo=build/.gens/Foo/rules/modules/cache/foo.pcm\n-- -fmodule-file=build/.gens/Foo/rules/modules/cache/iostream.pcm\n-- -fmodule-file=build/.gens/Foo/rules/modules/cache/bar.hpp.pcm\n--\nfunction _get_requiresflags(target, module)\n\n    local modulefileflag = support.get_modulefileflag(target)\n    local name = module.name or module.sourcefile\n    local cachekey = target:fullname() .. name\n\n    local requires, requires_changed = is_dependencies_changed(target, module)\n    local requiresflags = support.memcache():get2(cachekey, \"requiresflags\")\n    if not requiresflags or requires_changed then\n        requiresflags = {}\n        for required, dep in table.orderpairs(module.deps) do\n            if dep.headerunit then\n                required = required .. dep.key\n            end\n            local dep_module = mapper.get(target, required)\n            assert(dep_module, \"module dependency %s required for %s not found\", required, name)\n\n            local dep_bmifile, _ = dep.headerunit and dep_module.bmifile or _get_bmifile(target, dep_module)\n            local mapflag = dep_module.headerunit and modulefileflag .. dep_bmifile or format(\"%s%s=%s\", modulefileflag, required, dep_bmifile)\n            table.insert(requiresflags, mapflag)\n\n            -- append deps\n            if dep_module.deps then\n                local deps = _get_requiresflags(target, dep_module)\n                table.join2(requiresflags, deps)\n            end\n        end\n        requiresflags = table.unique(requiresflags)\n        support.memcache():set2(cachekey, \"requiresflags\", requiresflags)\n        support.memcache():set2(cachekey, \"oldrequires\", requires)\n    end\n    return requiresflags\nend\n\nfunction _append_requires_flags(target, module)\n    local cxxflags = {}\n    local requiresflags = _get_requiresflags(target, module)\n    local has_two_phases = target:policy(\"build.c++.modules.two_phases\")\n    local hide_dependencies = target:policy(\"build.c++.modules.hide_dependencies\")\n    if #requiresflags> 0 then\n        for _, flag in ipairs(requiresflags) do\n            -- we need to wrap flag to support flag with space\n            if type(flag) == \"string\" and flag:find(\" \", 1, true) and not hide_dependencies then\n                table.insert(cxxflags, {flag})\n            else\n                if hide_dependencies then\n                    table.insert(cxxflags, '\"' .. path.unix(flag) .. '\"')\n                else\n                    table.insert(cxxflags, flag)\n                end\n            end\n        end\n        if hide_dependencies then\n            local requires_flagsfile = target:autogenfile(module.sourcefile .. \".requiresflags.txt\")\n            io.writefile(requires_flagsfile, path.unix(table.concat(cxxflags, \"\\n\")))\n            target:fileconfig_add(module.sourcefile, {force = {cxxflags = {{\"@\" .. requires_flagsfile}}}})\n        else\n            target:fileconfig_add(module.sourcefile, {force = {cxxflags = cxxflags}})\n        end\n    end\nend\n\nfunction append_requires_flags(target, built_modules)\n    -- append requires flags\n    for _, sourcefile in ipairs(built_modules) do\n        local module = mapper.get(target, sourcefile)\n        if module.deps then\n            _append_requires_flags(target, module)\n        end\n    end\nend\n\n-- build module file for batchjobs / jobgraph\nfunction make_module_job(target, module, opt)\n\n    local dryrun = option.get(\"dry-run\")\n    local enable_hash_comparison = target:policy(\"build.c++.modules.non_cascading_changes\")\n\n    local build, because_of_dependencies = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build and enable_hash_comparison and because_of_dependencies then\n        build = false\n        for dep_name, dep_module in table.orderpairs(module.deps) do\n            local mapped_dep = mapper.get(target, dep_module.headerunit and dep_name .. dep_module.key or dep_name)\n            if support.memcache():get2(_get_bmifile(target, dep_module), \"updated\") then\n                build = true\n                break\n            end\n        end\n    end\n\n    if build then\n        if not dryrun then\n            local objectdir = path.directory(module.objectfile)\n            if not os.isdir(objectdir) then\n                os.mkdir(objectdir)\n            end\n            if module.bmifile then\n                local bmidir = path.directory(module.bmifile)\n                if not os.isdir(bmidir) then\n                    os.mkdir(bmidir)\n                end\n            end\n        end\n\n        if bmi and objectfile then\n            _compile_one_step(target, module, opt)\n        elseif bmi then\n            _compile_bmi_step(target, module, opt)\n        else\n            if support.has_module_extension(module.sourcefile) or module.name then\n                _compile_objectfile_step(target, module, opt)\n            else\n                os.tryrm(module.objectfile) -- force rebuild for .cpp files\n            end\n        end\n\n        if enable_hash_comparison and bmi then\n            _update_bmihash(target, module)\n        end\n    end\nend\n\n-- build module file for batchcmds\nfunction make_module_buildcmds(target, batchcmds, module, opt)\n\n    local build = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build then\n        if not dryrun then\n            local objectdir = path.directory(module.objectfile)\n            batchcmds:mkdir(objectdir)\n            if module.bmifile then\n                local bmidir = path.directory(module.bmifile)\n                batchcmds:mkdir(bmidir)\n            end\n        end\n\n        if bmi and objectfile then\n            _compile_one_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n        elseif bmi then\n            _compile_bmi_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n        else\n            if support.has_module_extension(module.sourcefile) or module.name then\n                _compile_objectfile_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n            else\n                batchcmds:rm(module.objectfile) -- force rebuild for .cpp files\n            end\n        end\n        batchcmds:add_depfiles(module.sourcefile)\n    end\n    return os.mtime(module.objectfile)\nend\n\n-- build headerunit file for batchjobs / jobgraph\nfunction make_headerunit_job(target, headerunit, opt)\n    local build = should_build(target, headerunit)\n    if build then\n        _compile(target, _make_headerunitflags(target, headerunit), headerunit, table.join(opt, {headerunit = true}))\n    end\nend\n\n-- build headerunit file for batchcmds\nfunction make_headerunit_buildcmds(target, batchcmds, headerunit, opt)\n    local compinst = compiler.load(\"cxx\", {target = target})\n    local compflags = compinst:compflags({sourcefile = headerunit.sourcefile, target = target, sourcekind = \"cxx\"})\n    local depvalues = {compinst:program(), compflags}\n\n    local build = should_build(target, headerunit)\n    if build then\n        _batchcmds_compile(batchcmds, target, table.join(_make_headerunitflags(target, headerunit)), headerunit, table.join(opt, {headerunit = true}))\n        batchcmds:add_depfiles(headerunit.sourcefile)\n    end\n    batchcmds:add_depvalues(depvalues)\nend\n\nfunction get_requires(target, module)\n    local _requires\n    local flags = _get_requiresflags(target, module)\n    for _, flag in ipairs(flags) do\n        _requires = _requires or {}\n        table.insert(_requires, flag:split(\"=\")[3])\n    end\n    return _requires\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/clang/scanner.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        clang/scanner.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"support\")\nimport(\".scanner\", {inherit = true})\n\n-- scan module dependencies\nfunction scan_dependency_for(target, sourcefile, rescan, opt)\n\n    local compinst = target:compiler(\"cxx\")\n    local changed = false\n    local dependfile = target:dependfile(sourcefile)\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n\n    depend.on_changed(function()\n        if opt.progress and not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            progress.show(opt.progress, \"${clear}generating.module.deps %s\", sourcefile)\n        end\n\n        local outputdir = support.get_outputdir(target, sourcefile, {scan = true})\n        local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. \".json\"))\n        local has_clangscandepssupport = support.has_clangscandepssupport(target)\n        local fallbackscanner = target:policy(\"build.c++.modules.fallbackscanner\") or\n                                target:policy(\"build.c++.modules.clang.fallbackscanner\") or\n                                target:policy(\"build.c++.clang.fallbackscanner\")\n        if has_clangscandepssupport and not fallbackscanner then\n            -- We need absolute path of clang to use clang-scan-deps\n            -- See https://clang.llvm.org/docs/StandardCPlusPlusModules.html#possible-issues-failed-to-find-system-headers\n            local clang_path = compinst:program()\n            if not path.is_absolute(clang_path) then\n                clang_path = support.get_clang_path(target) or compinst:program()\n            end\n            local clangscandeps = support.get_clang_scan_deps(target)\n            local dependency_flags = table.join({\"--format=p1689\", \"--\",\n                                                 clang_path, \"-x\", \"c++\"}, compflags, {\"-c\", sourcefile, \"-o\", target:objectfile(sourcefile)})\n            if option.get(\"verbose\") then\n                print(os.args(table.join(clangscandeps, dependency_flags)))\n            end\n            local outdata, errdata = os.iorunv(clangscandeps, dependency_flags)\n            assert(outdata, errdata)\n\n            io.writefile(jsonfile, outdata)\n        else\n            if not has_clangscandepssupport then\n                wprint(\"No clang-scan-deps found ! using fallback scanner\")\n            end\n            fallback_generate_dependencies(target, jsonfile, sourcefile, function(file)\n                local keepsystemincludesflag = support.get_keepsystemincludesflag(target)\n                local compflags = table.clone(compflags)\n                -- exclude -fmodule* and -std=c++/gnu++* flags because\n                -- when they are set clang try to find bmi of imported modules but they don't exists in this point of compilation\n                table.remove_if(compflags, function(_, flag)\n                    return flag:startswith(\"-fmodule\") or flag:startswith(\"-fvisibility\") or flag:startswith(\"-std=c++\") or flag:startswith(\"-std=gnu++\")\n                end)\n                local ifile = path.translate(path.join(outputdir, path.filename(file) .. \".i\"))\n                compflags = table.join(compflags or {}, keepsystemincludesflag or {}, {\"-E\", \"-x\", \"c++\", file, \"-o\", ifile})\n                os.vrunv(compinst:program(), compflags)\n                local content = io.readfile(ifile)\n                os.rm(ifile)\n                return content\n            end)\n        end\n        changed = true\n\n        local rawdependinfo = io.readfile(jsonfile)\n        return {moduleinfo = rawdependinfo}\n    end, {dependfile = dependfile, files = {sourcefile}, changed = rescan, values = compflags})\n    return changed\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/clang/support.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        clang/support.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.base.option\")\nimport(\"core.base.json\")\nimport(\"lib.detect.find_tool\")\nimport(\"lib.detect.find_file\")\nimport(\".support\", {inherit = true})\n\n-- get includedirs for stl headers\n--\n-- $ echo '#include <vector>' | clang -x c++ -E - | grep '/vector\"'\n-- # 1 \"/usr/include/c++/11/vector\" 1 3\n-- # 58 \"/usr/include/c++/11/vector\" 3\n-- # 59 \"/usr/include/c++/11/vector\" 3\n--\nfunction _get_toolchain_includedirs_for_stlheaders(target, includedirs, clang)\n\n    local tmpfile = os.tmpfile() .. \".cc\"\n    io.writefile(tmpfile, \"#include <vector>\")\n    local argv = {\"-E\", \"-x\", \"c++\", tmpfile}\n    local cpplib = get_cpplibrary_name(target)\n    if cpplib then\n        if cpplib == \"c++\" then\n            table.insert(argv, 1, \"-stdlib=libc++\")\n        elseif cpplib == \"stdc++\" then\n            table.insert(argv, 1, \"-stdlib=libstdc++\")\n        end\n    end\n    local result = try {function () return os.iorunv(clang, argv, {envs = compinst:runenvs()}) end}\n    if result then\n        for _, line in ipairs(result:split(\"\\n\", {plain = true})) do\n            line = line:trim()\n            if line:startswith(\"#\") and line:find(\"/vector\\\"\", 1, true) then\n                local includedir = line:match(\"\\\"(.+)/vector\\\"\")\n                if includedir and os.isdir(includedir) then\n                    table.insert(includedirs, path.normalize(includedir))\n                    break\n                end\n            end\n        end\n    end\n    os.tryrm(tmpfile)\nend\n\nfunction _get_std_module_manifest_path(target)\n    local print_module_manifest_flag = get_print_library_module_manifest_path_flag(target)\n    local clang_path = path.directory(get_clang_path(target))\n    if print_module_manifest_flag then\n        local compinst = target:compiler(\"cxx\")\n        local outdata, _ = try { function() return os.iorunv(compinst:program(), {\"-std=c++23\", \"-stdlib=libc++\", \"--sysroot=\" .. path.join(clang_path, \"..\"), print_module_manifest_flag}, {envs = compinst:runenvs()}) end }\n        if outdata and not outdata:startswith(\"<NOT PRESENT>\") then\n            return outdata:trim()\n        end\n    end\n    -- fallback on custom detection\n    -- manifest can be found in <llvm_path>/lib subdirectory (i.e on debian it should be <llvm_path>/lib/x86_64-unknown-linux-gnu/)\n    local clang_lib_path = path.join(clang_path, \"..\", \"lib\")\n    local modules_json_path = path.join(clang_lib_path, \"libc++.modules.json\")\n    if not os.isfile(modules_json_path) then\n        modules_json_path = find_file(\"*/libc++.modules.json\", clang_lib_path)\n    end\n    return modules_json_path\nend\n\n-- load module support for the current target\nfunction load(target)\n\n    local _, modulestsflag, withoutflag = get_modulesflag(target)\n    -- add module flags\n    if not withoutflag then\n        target:add(\"cxxflags\", modulestsflag)\n    end\n    -- fix default visibility for functions and variables [-fvisibility] differs in PCH file vs. current file\n    -- module.pcm cannot be loaded due to a configuration mismatch with the current compilation.\n    --\n    -- it will happen in binary target depend on library target with modules, and enable release mode at same time.\n    --\n    -- @see https://github.com/xmake-io/xmake/issues/3358#issuecomment-1432586767\n    local dep_symbols\n    local has_library_deps = false\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:is_shared() or dep:is_static() or dep:is_object() then\n            dep_symbols = dep:get(\"symbols\")\n            has_library_deps = true\n            break\n        end\n    end\n    if has_library_deps then\n        target:set(\"symbols\", dep_symbols and dep_symbols or \"none\")\n    end\n    -- on Windows before llvm18 we need to disable delayed-template-parsing because it's incompatible with modules, from llvm >= 18, it's disabled by default\n    local clang_version = get_clang_version(target)\n    if semver.compare(clang_version, \"18\") < 0 then\n        target:add(\"cxxflags\", \"-fno-delayed-template-parsing\")\n    end\nend\n\nfunction has_two_phase_compilation_support(target)\n    return target:policy(\"build.c++.modules.two_phases\")\nend\n\n-- flags that doesn't affect bmi generation\nfunction strippeable_flags()\n    -- speculative list as there is no resource that list flags that prevent reusability, this list will likely be improve over time\n    -- @see https://clang.llvm.org/docs/StandardCPlusPlusModules.html#consistency-requirement\n    local strippable_flags = {\n        \"g\",\n        \"O\",\n        \"W\",\n        \"w\",\n        \"Q\",\n        \"fmodule-file\",\n        \"fPIC\",\n        \"fsanitize\",\n        \"embed-dir\"\n    }\n    local splitted_strippeable_flags = {\n        \"I\",\n        \"isystem\",\n        \"cxx-isystem\",\n        \"framework\"\n    }\n    return strippable_flags, splitted_strippeable_flags\nend\n\n-- provide toolchain include directories for stl headerunit when p1689 is not supported\nfunction toolchain_includedirs(target)\n\n    local includedirs = _g.includedirs\n    if includedirs == nil then\n        includedirs = {}\n        local clang, toolname = target:tool(\"cxx\")\n        assert(toolname:startswith(\"clang\"))\n        _get_toolchain_includedirs_for_stlheaders(target, includedirs, clang)\n        local cpplib = get_cpplibrary_name(target)\n        local runtime_flag\n        if cpplib then\n            if cpplib == \"c++\" then\n                runtime_flag = \"-stdlib=libc++\"\n            elseif cpplib == \"stdc++\" then\n                runtime_flag = \"-stdlib=libstdc++\"\n            end\n        end\n        local _, result = try {function () return os.iorunv(clang, table.join({\"-E\", \"-Wp,-v\", \"-xc++\", os.nuldev()}, runtime_flag or {})) end}\n        if result then\n            for _, line in ipairs(result:split(\"\\n\", {plain = true})) do\n                line = line:trim()\n                if os.isdir(line) then\n                    table.insert(includedirs, path.normalize(line))\n                elseif line:startswith(\"End\") then\n                    break\n                end\n            end\n        end\n        _g.includedirs = includedirs\n    end\n    return includedirs\nend\n\n-- get clang path\nfunction get_clang_path(target)\n    local clang_path = _g.clang_path\n    if not clang_path then\n        local program, toolname = target:tool(\"cxx\")\n        if program and toolname:startswith(\"clang\") then\n            local clang = find_tool(toolname, {program = program,\n                envs = os.getenvs(), cachekey = \"modules_support_clang_\" .. toolname})\n            if clang then\n                clang_path = clang.program\n            end\n        end\n        clang_path = clang_path or false\n        _g.clang_path = clang_path\n    end\n    return clang_path or nil\nend\n\n-- get clang version\nfunction get_clang_version(target)\n    local clang_version = _g.clang_version\n    if not clang_version then\n        local program, toolname = target:tool(\"cxx\")\n        if program and toolname:startswith(\"clang\") then\n            local clang = find_tool(toolname, {program = program, version = true,\n                envs = os.getenvs(), cachekey = \"modules_support_clang_\" .. toolname})\n            if clang then\n                clang_version = clang.version\n            end\n        end\n        clang_version = clang_version or false\n        _g.clang_version = clang_version\n    end\n    return clang_version or nil\nend\n\n-- get clang-scan-deps\nfunction get_clang_scan_deps(target)\n    local clang_scan_deps = _g.clang_scan_deps\n    if not clang_scan_deps then\n        local program, toolname = target:tool(\"cxx\")\n        if program and toolname:startswith(\"clang\") then\n            local dir = path.directory(program)\n            local basename = path.basename(program)\n            if basename == \"clang-cl\" then\n                basename = \"clang\"\n            end\n            local extension = path.extension(program)\n            program = (basename:gsub(\"%+%+\", \"\"):gsub(\"clang\", \"clang-scan-deps\")) .. extension\n            if dir and dir ~= \".\" and os.isdir(dir) then\n                program = path.join(dir, program)\n            end\n            local result = find_tool(\"clang-scan-deps\", {program = program, version = true})\n            if not result then\n                -- find a system wide alternative\n                result = find_tool(\"clang-scan-deps\", {version = true})\n            end\n            if result then\n                clang_scan_deps = result.program\n            end\n        end\n        clang_scan_deps = clang_scan_deps or false\n        _g.clang_scan_deps = clang_scan_deps\n    end\n    return clang_scan_deps or nil\nend\n\nfunction parse_link_files(filepath)\n    if not os.islink(filepath) then\n        return filepath\n    end\n    local target = os.readlink(filepath)\n    if path.is_absolute(target) then\n        return target\n    end\n    return path.join(path.directory(filepath), target)\nend\n\nfunction get_original_file(filepath)\n    while os.islink(filepath) do\n        filepath = parse_link_files(filepath)\n    end\n    return filepath\nend\n\nfunction get_stdmodules(target)\n    local cpplib = get_cpplibrary_name(target)\n    if cpplib then\n        if cpplib == \"c++\" then\n            -- libc++ module is found by parsing libc++.modules.json\n            local modules_json_path = _get_std_module_manifest_path(target)\n            if not modules_json_path then\n                wprint(\"libc++.modules.json not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++\")\n                return\n            end\n            local modules_json = json.decode(io.readfile(modules_json_path))\n            if not (modules_json and modules_json.modules and #modules_json.modules > 0) then\n                wprint(\"libc++.modules.json is invalid! path: %s\", path.normalize(modules_json_path))\n                return\n            end\n            local std_module_directory = path.directory(modules_json.modules[1][\"source-path\"])\n            -- check absolute path first\n            if path.is_absolute(std_module_directory) then\n                if os.isdir(std_module_directory) then\n                    return {path.normalize(path.join(std_module_directory, \"std.cppm\")), path.normalize(path.join(std_module_directory, \"std.compat.cppm\"))}\n                else\n                    wprint(\"std module directory not found: %s which defined in %s\", path.normalize(std_module_directory), path.normalize(modules_json_path))\n                    return\n                end\n            end\n            -- otherwise try to resolve relative path\n            local try_std_module_directory\n            -- first try the directory relative to libc++.modules.json\n            try_std_module_directory = path.join(path.directory(modules_json_path), std_module_directory)\n            if os.isdir(try_std_module_directory) then\n                return {path.normalize(path.join(try_std_module_directory, \"std.cppm\")), path.normalize(path.join(try_std_module_directory, \"std.compat.cppm\"))}\n            end\n            -- then try the directory relative to clang bin directory\n            try_std_module_directory = path.join(path.directory(get_original_file(get_clang_path(target))), std_module_directory)\n            if os.isdir(try_std_module_directory) then\n                return {path.normalize(path.join(try_std_module_directory, \"std.cppm\")), path.normalize(path.join(try_std_module_directory, \"std.compat.cppm\"))}\n            end\n        elseif cpplib == \"stdc++\" then\n            -- dont be greedy and don't enable stdc++ std module support for llvm < 19\n            local clang_version = get_clang_version(target)\n            if clang_version and semver.compare(clang_version, \"19.0\") >= 0 then\n                return import(\".gcc.support\").get_stdmodules(target)\n            end\n        elseif cpplib == \"msstl\" then\n            -- msstl std module file is not compatible with llvm < 19\n            local clang_version = get_clang_version(target)\n            if clang_version and semver.compare(clang_version, \"19.0\") >= 0 then\n                local toolchain = target:toolchain(\"llvm\") or target:toolchain(\"clang\") or target:toolchain(\"clang-cl\")\n                return import(\".msvc.support\").get_stdmodules(target, {toolchain = toolchain})\n            end\n        end\n    end\n    wprint(\"std and std.compat modules not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++\")\nend\n\nfunction get_bmi_extension()\n    return \".pcm\"\nend\n\nfunction get_modulesflag(target)\n    local clangmodulesflag = _g.clangmodulesflag\n    local modulestsflag = _g.modulestsflag\n    local withoutflag = _g.withoutflag\n    if clangmodulesflag == nil and modulestsflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodules\", \"cxxflags\", {flagskey = \"clang_modules\"}) then\n            clangmodulesflag = \"-fmodules\"\n        end\n        if compinst:has_flags(\"-fmodules-ts\", \"cxxflags\", {flagskey = \"clang_modules_ts\"}) then\n            modulestsflag = \"-fmodules-ts\"\n        end\n        local clang_version = get_clang_version(target)\n        withoutflag = semver.compare(clang_version, \"16.0\") >= 0\n        assert(withoutflag or modulestsflag, \"compiler(clang): does not support c++ module!\")\n        _g.clangmodulesflag = clangmodulesflag or false\n        _g.modulestsflag = modulestsflag or false\n        _g.withoutflag = withoutflag or false\n    end\n    return clangmodulesflag or nil, modulestsflag or nil, withoutflag or nil\nend\n\nfunction get_modulefileflag(target)\n    local modulefileflag = _g.modulefileflag\n    if modulefileflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodule-file=\" .. os.tmpfile() .. get_bmi_extension(), \"cxxflags\", {flagskey = \"clang_module_file\"}) then\n            modulefileflag = \"-fmodule-file=\"\n        end\n        assert(modulefileflag, \"compiler(clang): does not support c++ module!\")\n        _g.modulefileflag = modulefileflag or false\n    end\n    return modulefileflag or nil\nend\n\nfunction get_moduleheaderflag(target)\n    local moduleheaderflag = _g.moduleheaderflag\n    if moduleheaderflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodule-header=system\", \"cxxflags\", {flagskey = \"clang_module_header\"}) then\n            moduleheaderflag = \"-fmodule-header=\"\n        end\n        _g.moduleheaderflag = moduleheaderflag or false\n    end\n    return moduleheaderflag or nil\nend\n\nfunction get_modulesreducedbmiflag(target)\n    local modulesreducedbmiflag = _g.modulesreducedbmiflag\n    if modulesreducedbmiflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodules-reduced-bmi\", \"cxxflags\", {flagskey = \"clang_modules_reduced_bmi\"}) then\n            modulesreducedbmiflag = \"-fmodules-reduced-bmi\"\n        elseif compinst:has_flags(\"-fexperimental-modules-reduced-bmi\", \"cxxflags\", {flagskey = \"clang_modules_reduced_bmi\"}) then\n            modulesreducedbmiflag = \"-fexperimental-modules-reduced-bmi\"\n        end\n        _g.modulesreducedbmiflag = modulesreducedbmiflag or false\n    end\n    return modulesreducedbmiflag or nil\nend\n\nfunction has_clangscandepssupport(target)\n    local support_clangscandeps = _g.support_clangscandeps\n    if support_clangscandeps == nil then\n        local clangscandeps = get_clang_scan_deps(target)\n        local clang_version = get_clang_version(target)\n        if clangscandeps and clang_version and semver.compare(clang_version, \"16.0\") >= 0 then\n            support_clangscandeps = true\n        end\n        _g.support_clangscandeps = support_clangscandeps or false\n    end\n    return support_clangscandeps or nil\nend\n\nfunction get_keepsystemincludesflag(target)\n    local keepsystemincludesflag = _g.keepsystemincludesflag\n    if keepsystemincludesflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local clang_version = get_clang_version(target)\n        if compinst:has_flags(\"-E -fkeep-system-includes\", \"cxxflags\", {flagskey = \"clang_keep_system_includes\", tryrun = true}) and\n            semver.compare(clang_version, \"18.0\") >= 0 then\n            keepsystemincludesflag = \"-fkeep-system-includes\"\n        end\n        _g.keepsystemincludesflag = keepsystemincludesflag or false\n    end\n    return keepsystemincludesflag or nil\nend\n\nfunction get_moduleoutputflag(target)\n    local moduleoutputflag = _g.moduleoutputflag\n    if moduleoutputflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local clang_version = get_clang_version(target)\n        if compinst:has_flags(\"-fmodule-output=\", \"cxxflags\", {flagskey = \"clang_module_output\", tryrun = true}) and\n            semver.compare(clang_version, \"16.0\") >= 0 then\n            moduleoutputflag = \"-fmodule-output=\"\n        end\n        _g.moduleoutputflag = moduleoutputflag or false\n    end\n    return moduleoutputflag or nil\nend\n\nfunction get_print_library_module_manifest_path_flag(target)\n    local print_library_module_manifest_path_flag = _g.print_library_module_manifest_path_flag\n    if print_library_module_manifest_path_flag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-print-library-module-manifest-path\", \"cxxflags\", {flagskey = \"clang_print_library_module_manifest_path\", tryrun = true}) then\n            print_library_module_manifest_path_flag = \"-print-library-module-manifest-path\"\n        end\n        _g.print_library_module_manifest_path_flag = print_library_module_manifest_path_flag or false\n    end\n    return print_library_module_manifest_path_flag or nil\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/config.lua",
    "content": "-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        config.lua\n--\n\nimport(\"core.project.project\")\nimport(\"core.base.semver\")\nimport(\"support\")\n\nfunction main(target)\n\n    if support.contains_modules(target) then\n        -- when jobgraph is policy is set to false, we disable to build across targets in parallel, because the source files may depend on other target modules\n        -- @see https://github.com/xmake-io/xmake/issues/1858\n        -- @note this will cause cross-parallel builds to be disabled for all sub-dependent targets,\n        -- even if some sub-targets do not contain C++ modules.\n        if not target:policy(\"build.jobgraph\") then\n            target:set(\"policy\", \"build.fence\", true)\n        end\n\n        assert(not target:rule(\"c++.unity_build\"), \"C++ unity build is not compatible with C++ modules\")\n\n        -- disable ccache for this target\n        --\n        -- Caching can affect incremental compilation, for example\n        -- by interfering with the results of depfile generation for msvc.\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/3000\n        target:set(\"policy\", \"build.ccache\", false)\n\n        -- load compiler support\n        support.load(target)\n\n        -- mark this target with modules\n        target:data_set(\"cxx.has_modules\", true)\n\n        -- warn about deprecated policies\n        if target:policy(\"build.c++.gcc.modules.cxx11abi\") then\n            wprint(\"build.c++.gcc.modules.cxx11abi is deprecated, please use build.c++.modules.gcc.cxx11abi\")\n        end\n        if target:policy(\"build.c++.clang.fallbackscanner\") then\n            wprint(\"build.c++.clang.fallbackscanner is deprecated, please use build.c++.modules.clang.fallbackscanner\")\n        end\n        if target:policy(\"build.c++.gcc.fallbackscanner\") then\n            wprint(\"build.c++.gcc.fallbackscanner is deprecated, please use build.c++.modules.gcc.fallbackscanner\")\n        end\n        if target:policy(\"build.c++.msvc.fallbackscanner\") then\n            wprint(\"build.c++.msvc.fallbackscanner is deprecated, please use build.c++.modules.msvc.fallbackscanner\")\n        end\n        if target:policy(\"build.c++.modules.tryreuse\") then\n            wprint(\"build.c++.modules.tryreuse is deprecated, please use build.c++.modules.reuse\")\n        end\n        if target:policy(\"build.c++.modules.tryreuse.discriminate_on_defines\") then\n            wprint(\"build.c++.modules.tryreuse.discriminate_on_defines is deprecated, please use build.c++.modules.reuse.strict\")\n        end\n\n        -- if containes modules, enable objectfiles output of c++.build.modules.builder\n        local rule = target:rule(\"c++.build.modules.builder\")\n        rule = rule:clone()\n        if rule then\n            rule:extraconf_set(\"sourcekinds\", \"cxx\", \"objectfiles\", true)\n            target:rule_add(rule)\n            target:add(\"files\")\n        end\n\n        -- moduleonly modules are implicitly public\n        if target:is_moduleonly() then\n            local sourcebatches = target:sourcebatches()\n            if sourcebatches and sourcebatches[\"c++.build.modules.scanner\"] then\n                local sourcebatch = sourcebatches[\"c++.build.modules.scanner\"]\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    target:fileconfig_add(sourcefile, {public = true})\n                end\n            end\n        end\n    else\n        target:rule_enable(\"c++.build.modules.scanner\", false)\n        target:rule_enable(\"c++.build.modules.builder\", false)\n    end\nend\n\nfunction insert_stdmodules(target)\n    if target:data(\"cxx.has_modules\") and target:policy(\"build.c++.modules.std\") then\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches and sourcebatches[\"c++.build.modules.scanner\"] then\n            local sourcebatch = sourcebatches[\"c++.build.modules.scanner\"]\n            sourcebatch.sourcefiles = sourcebatch.sourcefiles or {}\n            -- add std modules to sourcebatch\n            local stdmodules = support.get_stdmodules(target)\n            for _, sourcefile in ipairs(stdmodules) do\n                table.insert(sourcebatch.sourcefiles, sourcefile)\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/gcc/builder.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        gcc/builder.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.base.bytes\")\nimport(\"core.base.semver\")\nimport(\"utils.progress\")\nimport(\"private.action.build.object\", {alias = \"objectbuilder\"})\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"support\")\nimport(\".mapper\")\nimport(\".builder\", {inherit = true})\n\n-- get flags for building a headerunit\nfunction _make_headerunitflags(target, headerunit_mapper, headerunit)\n    local module_headerflag = support.get_moduleheaderflag(target)\n    local module_mapperflag = support.get_modulemapperflag(target)\n    assert(module_headerflag, \"compiler(gcc): does not support c++ header units!\")\n\n    local headertype = (headerunit.method == \"include-angle\") and \"system\" or \"user\"\n    local includedir = headertype == \"user\" and \"-I\" .. path.directory(headerunit.sourcefile)\n    return table.join(includedir and {includedir} or {},\n                      {\"-x\", \"c++-\" .. headertype .. \"-header\",\n                      module_mapperflag .. headerunit_mapper,\n                     module_headerflag .. headertype})\nend\n\n-- do compile\nfunction _compile(target, flags, module, opt)\n\n    opt = opt or {}\n    local sourcefile = opt.headerunit and path.filename(module.sourcefile) or module.sourcefile\n    local outputfile = opt.headerunit and module.bmifile or module.objectfile\n    local dryrun = option.get(\"dry-run\")\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(compflags or {}, flags or {})\n\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, rawargs = true})\n    end\n    local mapper_str\n    if option.get(\"diagnosis\") then\n        if opt.headerunit then\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", sourcefile, module.name, io.readfile(opt.mapper_file):trim())\n        elseif module.name  then\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", module.name, sourcefile, io.readfile(opt.mapper_file):trim())\n        else\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s --------\\n%s\\n--------\", sourcefile, io.readfile(opt.mapper_file):trim())\n        end\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, suffix = mapper_str}))\n\n    -- do compile\n    if not dryrun then\n        assert(compinst:compile(sourcefile, outputfile, {target = target, compflags = flags}))\n    end\nend\n\n-- do compile for batchcmds\n-- @note we need to use batchcmds:compilev to translate paths in compflags for generator, e.g. -Ixx\nfunction _batchcmds_compile(batchcmds, target, flags, module, opt)\n    local sourcefile = opt.headerunit and path.filename(module.sourcefile) or module.sourcefile\n    local outputfile = opt.headerunit and module.bmifile or module.objectfile\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(\"-c\", compflags or {}, flags or {}, {\"-o\", outputfile, sourcefile})\n\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, rawargs = true})\n    end\n    local mapper_str\n    if option.get(\"diagnosis\") then\n        if opt.headerunit then\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", sourcefile, module.name, io.readfile(opt.mapper_file):trim())\n        elseif module.name  then\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", module.name, sourcefile, io.readfile(opt.mapper_file):trim())\n        else\n            mapper_str = format(\"\\n${dim color.warning}mapper file for %s --------\\n%s\\n--------\", sourcefile, io.readfile(opt.mapper_file):trim())\n        end\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, suffix = mapper_str, batchcmds = batchcmds}))\n\n    -- do compile\n    batchcmds:compilev(flags, {compiler = compinst, sourcekind = \"cxx\", verbose = false})\nend\n\nfunction _module_map_cachekey(target)\n    local mode = config.mode()\n    return target:fullname() .. \"module_mapper\" .. (mode or \"\")\nend\n\n-- generate a module mapper file for build a headerunit\nfunction _generate_headerunit_modulemapper_file(target, headerunit)\n    local mapper_path = _get_modulemapper_file(target, headerunit)\n    local mapper_file = io.open(mapper_path, \"wb\")\n    mapper_file:write(\"root \" .. path.directory(headerunit.sourcefile) .. \"\\n\")\n    mapper_file:write(mapper_file, path.unix(headerunit.sourcefile) .. \" \" .. path.unix(path.absolute(headerunit.bmifile)) .. \"\\n\")\n    mapper_file:write(\"\\n\")\n    mapper_file:close()\n    return mapper_path\nend\n\nfunction _get_maplines(target, module)\n\n    local maplines = {}\n    if module.name then\n        table.insert(maplines, module.name .. \" \" .. path.absolute(module.bmifile))\n    end\n    for dep_name, dep_module in table.orderpairs(module.deps) do\n        local key = dep_name\n        if dep_module.headerunit then\n            key = dep_name .. dep_module.key\n        end\n        local dep_module_mapped = mapper.get(target, key)\n        assert(dep_module_mapped, \"module dependency %s required for %s not found\", dep_name, module.name or module.sourcefile)\n        local mapline\n        local name = dep_name\n        if dep_module_mapped.headerunit then\n            name = dep_module_mapped.method == \"include-angle\" and dep_module_mapped.sourcefile or path.join(\"./\", path.directory(module.sourcefile), dep_name)\n        end\n        mapline = path.unix(name) .. \" \" .. path.unix(path.absolute(dep_module_mapped.bmifile))\n        table.insert(maplines, mapline)\n\n        -- append deps\n        if dep_module.deps then\n            local deps = _get_maplines(target, {name = dep_module.name, deps = dep_module.deps, sourcefile = dep_module.sourcefile})\n            table.join2(maplines, deps)\n        end\n    end\n\n    -- remove duplicates\n    return table.unique(maplines)\nend\n\nfunction _get_modulemapper_file(target, module)\n    return path.join(os.tmpdir(), hash.md5(bytes(target:fullname() .. \"/\" .. module.sourcefile)), path.filename(module.sourcefile) .. \".mapper.txt\")\nend\n\n-- generate a module mapper file for build a module\n-- e.g\n-- /usr/include/c++/11/iostream build/.gens/stl_headerunit/linux/x86_64/release/stlmodules/cache/iostream.gcm\n-- hello build/.gens/stl_headerunit/linux/x86_64/release/rules/modules/cache/hello.gcm\n--\nfunction _generate_modulemapper_file(target, module)\n    local maplines = _get_maplines(target, module)\n    local mapper_path = _get_modulemapper_file(target, module)\n    if os.isfile(mapper_path) then\n        os.rm(mapper_path)\n    end\n    local mapper_content = {}\n    table.insert(mapper_content, \"root \" .. path.unix(os.projectdir()))\n    for _, mapline in ipairs(maplines) do\n        table.insert(mapper_content, mapline)\n    end\n    mapper_content = table.concat(mapper_content, \"\\n\") .. \"\\n\"\n    if not os.isfile(mapper_path) or io.readfile(mapper_path, {encoding = \"binary\"}) ~= mapper_content then\n        io.writefile(mapper_path, mapper_content, {encoding = \"binary\"})\n    end\n    return mapper_path\nend\n\n-- build module file for batchjobs / jobgraph\nfunction make_module_job(target, module, opt)\n\n    local module_mapperflag = support.get_modulemapperflag(target)\n    local module_onlyflag = support.get_moduleonlyflag(target)\n    local module_flag = support.get_modulesflag(target)\n    local dryrun = option.get(\"dry-run\")\n\n    -- generate and append module mapper file\n    local module_mapper\n    if module.deps then\n        module_mapper = _get_modulemapper_file(target, module)\n        target:fileconfig_add(module.sourcefile, {force = {cxxflags = {module_mapperflag .. module_mapper}}})\n    end\n\n    local build = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build then\n        if not dryrun then\n            local objectdir = path.directory(module.objectfile)\n            if not os.isdir(objectdir) then\n                os.mkdir(objectdir)\n            end\n            if module.bmifile then\n                local bmidir = path.directory(module.bmifile)\n                if not os.isdir(bmidir) then\n                    os.mkdir(bmidir)\n                end\n            end\n        end\n\n        if module.deps then\n            _generate_modulemapper_file(target, module)\n        end\n\n        local flags = {\"-x\", \"c++\"}\n        if support.has_module_extension(module.sourcefile) or module.name then\n            if bmi then\n                if objectfile then\n                    table.insert(flags, module_flag)\n                else\n                    table.insert(flags, module_flag)\n                    table.insert(flags, module_onlyflag)\n                end\n            end\n            _compile(target, flags, module, table.join(opt or {}, {mapper_file = module_mapper}))\n        else\n            os.tryrm(module.objectfile) -- force rebuild for .cpp files\n        end\n    end\nend\n\n-- build module file for batchcmds\nfunction make_module_buildcmds(target, batchcmds, module, opt)\n\n    local module_mapperflag = support.get_modulemapperflag(target)\n    local module_onlyflag = support.get_moduleonlyflag(target)\n    local module_flag = support.get_modulesflag(target)\n\n    local module_mapper\n    if module.deps then\n        module_mapper = _get_modulemapper_file(target, module)\n        target:fileconfig_add(module.sourcefile, {force = {cxxflags = {module_mapperflag .. module_mapper}}})\n    end\n\n    -- generate and append module mapper file\n    local build = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build then\n        local objectdir = path.directory(module.objectfile)\n        batchcmds:mkdir(objectdir)\n        if module.bmifile then\n            local bmidir = path.directory(module.bmifile)\n            batchcmds:mkdir(bmidir)\n        end\n\n        if module.deps then\n            _generate_modulemapper_file(target, module)\n        end\n\n        local flags = {\"-x\", \"c++\"}\n        if support.has_module_extension(module.sourcefile) or module.name then\n            if bmi then\n                if objectfile then\n                    table.insert(flags, module_flag)\n                else\n                    table.insert(flags, module_flag)\n                    table.insert(flags, module_onlyflag)\n                end\n            end\n            _batchcmds_compile(batchcmds, target, flags, module, table.join(opt, {batchcmds = batchcmds, mapper_file = module_mapper}))\n        else\n            batchcmds:rm(module.objectfile) -- force rebuild for .cpp files\n        end\n    end\n    return os.mtime(module.objectfile)\nend\n\n-- build headerunit file for batchjobs / jobgraph\nfunction make_headerunit_job(target, headerunit, opt)\n    local build = should_build(target, headerunit)\n    if build then\n        local headerunit_mapper = _generate_headerunit_modulemapper_file(target, headerunit)\n        _compile(target,\n                 _make_headerunitflags(target, headerunit_mapper, headerunit),\n                 headerunit, table.join(opt, {mapper_file = headerunit_mapper, headerunit = true}))\n    end\nend\n\n-- build headerunit file for batchcmds\nfunction make_headerunit_buildcmds(target, batchcmds, headerunit, opt)\n    local compinst = compiler.load(\"cxx\", {target = target})\n    local compflags = compinst:compflags({sourcefile = headerunit.sourcefile, target = target, sourcekind = \"cxx\"})\n    local depvalues = {compinst:program(), compflags}\n\n    local build = should_build(target, headerunit)\n    if build then\n        local headerunit_mapper = _generate_headerunit_modulemapper_file(target, headerunit)\n        _batchcmds_compile(batchcmds, target,\n                     _make_headerunitflags(target, headerunit_mapper, headerunit),\n                     headerunit, table.join(opt, {mapper_file = headerunit_mapper, headerunit = true}))\n        batchcmds:add_depfiles(headerunit.sourcefile)\n    end\n    batchcmds:add_depvalues(depvalues)\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/gcc/scanner.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        gcc/scanner.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"support\")\nimport(\"builder\")\nimport(\".scanner\", {inherit = true})\n\n-- scan module dependencies\nfunction scan_dependency_for(target, sourcefile, rescan, opt)\n\n    local compinst = target:compiler(\"cxx\")\n    local baselineflags = {\"-E\", \"-x\", \"c++\"}\n    local depsformatflag = support.get_depsflag(target, \"p1689r5\")\n    local depsfileflag = support.get_depsfileflag(target)\n    local depstargetflag = support.get_depstargetflag(target)\n    local dependfile = target:dependfile(sourcefile)\n    local changed = false\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n    local fallbackscanner = target:policy(\"build.c++.modules.fallbackscanner\") or\n                            target:policy(\"build.c++.modules.gcc.fallbackscanner\") or\n                            target:policy(\"build.c++.gcc.fallbackscanner\")\n\n    depend.on_changed(function()\n        if opt.progress and not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            progress.show(opt.progress, \"${clear}scanning.module.deps %s\", sourcefile)\n        end\n\n        local outputdir = support.get_outputdir(target, sourcefile, {scan = true})\n        local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. \".json\"))\n        local has_depsflags = depsformatflag and depsfileflag and depstargetflag\n        if has_depsflags and not fallbackscanner then\n            local ifile = path.translate(path.join(outputdir, path.filename(sourcefile) .. \".i\"))\n            local dfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. \".d\"))\n            compflags = table.join(baselineflags, compflags or {}, {sourcefile, \"-MT\", jsonfile, \"-MD\", \"-MF\", dfile, depsformatflag, depsfileflag .. jsonfile, depstargetflag .. target:objectfile(sourcefile), \"-o\", ifile})\n            os.vrunv(compinst:program(), compflags)\n            os.rm(ifile)\n            os.rm(dfile)\n        else\n            if not has_depsflags then\n                wprint(\"GCC doesn't support module scanning ! using fallback scanner\")\n            end\n            fallback_generate_dependencies(target, jsonfile, sourcefile, function(file)\n                -- exclude -fmodule* flags because, when they are set gcc try to find bmi of imported modules but they don't exists a this point of compilation\n                local compflags = table.clone(compflags)\n                table.remove_if(compflags, function(_, flag) return flag:startswith(\"-fmodule\") end)\n                local ifile = path.translate(path.join(outputdir, path.filename(file) .. \".i\"))\n                compflags = table.join(baselineflags, compflags or {}, {file,  \"-o\", ifile})\n                os.vrunv(compinst:program(), compflags)\n                local content = io.readfile(ifile)\n                os.rm(ifile)\n                return content\n            end)\n        end\n        changed = true\n\n        local dependinfo = io.readfile(jsonfile)\n        return { moduleinfo = dependinfo }\n    end, {dependfile = dependfile, files = {sourcefile}, changed = rescan, values = compflags})\n    return changed\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/gcc/support.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        gcc/support.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\".support\", {inherit = true})\n\n-- get includedirs for stl headers\n--\n-- $ echo '#include <vector>' | gcc -x c++ -E - | grep '/vector\"'\n-- # 1 \"/usr/include/c++/11/vector\" 1 3\n-- # 58 \"/usr/include/c++/11/vector\" 3\n-- # 59 \"/usr/include/c++/11/vector\" 3\n--\nfunction _get_toolchain_includedirs_for_stlheaders(includedirs, gcc)\n    local tmpfile = os.tmpfile() .. \".cc\"\n    io.writefile(tmpfile, \"#include <vector>\")\n    local result = try {function () return os.iorunv(gcc, {\"-E\", \"-x\", \"c++\", tmpfile}) end}\n    if result then\n        for _, line in ipairs(result:split(\"\\n\", {plain = true})) do\n            line = line:trim()\n            if line:startswith(\"#\") and line:find(\"/vector\\\"\", 1, true) then\n                local includedir = line:match(\"\\\"(.+)/vector\\\"\")\n                if includedir and os.isdir(includedir) then\n                    table.insert(includedirs, path.normalize(includedir))\n                    break\n                end\n            end\n        end\n    end\n    os.tryrm(tmpfile)\nend\n\n-- load module support for the current target\nfunction load(target)\n    local modulesflag = get_modulesflag(target)\n    target:add(\"cxxflags\", modulesflag, {force = true, expand = false})\n\n    -- fix cxxabi issue\n    -- @see https://github.com/xmake-io/xmake/issues/2716#issuecomment-1225057760\n    -- https://github.com/xmake-io/xmake/issues/3855\n    local cxx11abi = target:policy(\"build.c++.modules.gcc.cxx11abi\") or\n                     target:policy(\"build.c++.gcc.modules.cxx11abi\")\n    if cxx11abi == nil then\n        -- enable cxx11abi on GCC >= 15 as it is required for C++23 module\n        local gcc_version = get_gcc_version(target)\n        if gcc_version and semver.compare(gcc_version, \"15\") >= 0 then\n            cxx11abi = true\n        end\n    end\n    if cxx11abi then\n        target:add(\"cxxflags\", \"-D_GLIBCXX_USE_CXX11_ABI=1\")\n    else\n        target:add(\"cxxflags\", \"-D_GLIBCXX_USE_CXX11_ABI=0\")\n    end\nend\n\nfunction has_two_phase_compilation_support(_)\n    return false\nend\n\n-- flags that doesn't affect bmi generation\nfunction strippeable_flags()\n    -- speculative list as there is no resource that list flags that prevent reusability, this list will likely be improve over time\n    local strippeable_flags = {\n        \"O\",\n        \"W\",\n        \"w\",\n        \"Q\",\n        \"fmodule-mapper\",\n        \"fmodules-ts\",\n        \"fmodules\",\n        \"fPIC\",\n        \"fsanitize\",\n        \"embed-dir\"\n    }\n    local splitted_strippeable_flags = {\n        \"I\",\n        \"isystem\",\n        \"cxx-isystem\",\n        \"framework\"\n    }\n    return strippeable_flags, splitted_strippeable_flags\nend\n\n-- provide toolchain include directories for stl headerunit when p1689 is not supported\nfunction toolchain_includedirs(target)\n    local includedirs = _g.includedirs\n    if includedirs == nil then\n        includedirs = {}\n        local gcc, toolname = target:tool(\"cxx\")\n        assert(toolname == \"gcc\" or toolname == \"gxx\")\n        _get_toolchain_includedirs_for_stlheaders(includedirs, gcc)\n        local _, result = try {function () return os.iorunv(gcc, {\"-E\", \"-Wp,-v\", \"-xc\", os.nuldev()}) end}\n        if result then\n            for _, line in ipairs(result:split(\"\\n\", {plain = true})) do\n                line = line:trim()\n                if os.isdir(line) then\n                    table.insert(includedirs, path.normalize(line))\n                elseif line:startswith(\"End\") then\n                    break\n                end\n            end\n        end\n        _g.includedirs = includedirs\n    end\n    return includedirs\nend\n\nfunction get_target_module_mapperpath(target)\n    local path = path.join(modules_cachedir(target, {mkdir = true}), \"..\", \"mapper.txt\")\n    if not os.isfile(path) then\n        io.writefile(path, \"\")\n    end\n    return path\nend\n\nfunction _get_std_module_manifest_path(target)\n    local compinst = target:compiler(\"cxx\")\n    local modules_json_path, _ = try {\n        function()\n            return os.iorunv(compinst:program(), {\"-print-file-name=libstdc++.modules.json\"}, {envs = compinst:runenvs()})\n        end\n    }\n    if modules_json_path then\n        modules_json_path = modules_json_path:trim()\n        if os.isfile(modules_json_path) then\n            return modules_json_path\n        end\n    end\n    local ext = \".so\"\n    if target:is_plat(\"windows\", \"mingw\") then\n        ext = \".dll\"\n    elseif target:is_plat(\"macosx\", \"iphoneos\", \"appletvos\") then\n        ext = \".dylib\"\n    end\n    local stdcpp_libfile, _ = try {\n        function()\n            return os.iorunv(compinst:program(), {\"-print-file-name=libstdc++\" .. ext}, {envs = compinst:runenvs()})\n        end\n    }\n    if stdcpp_libfile then\n        modules_json_path = path.join(path.directory(stdcpp_libfile), \"libstdc++.modules.json\")\n        modules_json_path = modules_json_path:trim()\n        if os.isfile(modules_json_path) then\n            return modules_json_path\n        end\n    end\nend\n\nfunction get_stdmodules(target)\n    local modules_json_path = _get_std_module_manifest_path(target)\n    if modules_json_path then\n        local modules_json = json.loadfile(modules_json_path)\n        if modules_json and modules_json.modules and #modules_json.modules > 0 then\n            local std_module_files = {}\n            local modules_json_dir = path.directory(modules_json_path)\n            for _, module_file in ipairs(modules_json.modules) do\n                local module_file_path = module_file[\"source-path\"]\n                if not path.is_absolute(module_file_path) then\n                    module_file_path = path.join(modules_json_dir, module_file_path)\n                end\n                table.insert(std_module_files, path.normalize(module_file_path))\n            end\n            return std_module_files\n        end\n    end\n    wprint(\"std and std.compat modules not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++\")\nend\n\nfunction get_bmi_extension()\n    return \".gcm\"\nend\n\nfunction get_modulesflag(target)\n    local modulesflag = _g.modulesflag\n    if modulesflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local gcc_version = get_gcc_version(target)\n        -- GCC 12 and earlier version has a option '-fmodules' for Modula-2\n        if gcc_version and semver.compare(gcc_version, \"12\") > 0 then\n            if compinst:has_flags(\"-fmodules\", \"cxxflags\", {flagskey = \"gcc_modules\"}) then\n                modulesflag = \"-fmodules\"\n            elseif compinst:has_flags(\"-fmodules-ts\", \"cxxflags\", {flagskey = \"gcc_modules_ts\"}) then\n                modulesflag = \"-fmodules-ts\"\n            end\n        elseif compinst:has_flags(\"-fmodules-ts\", \"cxxflags\", {flagskey = \"gcc_modules_ts\"}) then\n            modulesflag = \"-fmodules-ts\"\n        end\n        assert(modulesflag, \"compiler(gcc): does not support c++ module!\")\n        _g.modulesflag = modulesflag or false\n    end\n    return modulesflag or nil\nend\n\nfunction get_moduleheaderflag(target)\n    local moduleheaderflag = _g.moduleheaderflag\n    if moduleheaderflag == nil then\n        -- we need to suppress warnings/errors:\n        -- external linkage definition of 'int main(int, char**)' in header module must be declared 'inline'\n        local snippet = \"\"\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodule-header\", \"cxxflags\", {snippet = snippet, flagskey = \"gcc_module_header\"}) then\n            moduleheaderflag = \"-fmodule-header=\"\n        end\n        _g.moduleheaderflag = moduleheaderflag or false\n    end\n    return moduleheaderflag or nil\nend\n\nfunction get_moduleonlyflag(target)\n    local moduleonlyflag = _g.moduleonlyflag\n    if moduleonlyflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodule-only\", \"cxxflags\", {flagskey = \"gcc_module_only\"}) then\n            moduleonlyflag = \"-fmodule-only\"\n        end\n        _g.moduleonlyflag = moduleonlyflag or false\n    end\n    return moduleonlyflag or nil\nend\n\nfunction get_modulemapperflag(target)\n    local modulemapperflag = _g.modulemapperflag\n    if modulemapperflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fmodule-mapper=\" .. os.tmpfile(), \"cxxflags\", {flagskey = \"gcc_module_mapper\"}) then\n            modulemapperflag = \"-fmodule-mapper=\"\n        end\n        assert(modulemapperflag, \"compiler(gcc): does not support c++ module!\")\n        _g.modulemapperflag = modulemapperflag or false\n    end\n    return modulemapperflag or nil\nend\n\nfunction get_depsflag(target)\n    local depflag = _g.depflag\n    if depflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fdeps-format=p1689r5\", \"cxxflags\", {flagskey = \"gcc_deps_format\",\n         on_check = function (ok, errors)\n             if errors:find(\"-M\") then\n                ok = true\n             end\n             return ok, errors\n        end}) then\n            depflag = \"-fdeps-format=p1689r5\"\n        end\n        _g.depflag = depflag or false\n    end\n    return depflag or nil\nend\n\nfunction get_depsfileflag(target)\n    local depfileflag = _g.depfileflag\n    if depfileflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fdeps-file=\" .. os.tmpfile(), \"cxxflags\", {flagskey = \"gcc_deps_file\",\n         on_check = function (ok, errors)\n             if errors:find(\"-M\") then\n                ok = true\n             end\n             return ok, errors\n        end}) then\n            depfileflag = \"-fdeps-file=\"\n        end\n        _g.depfileflag = depfileflag or false\n    end\n    return depfileflag or nil\nend\n\nfunction get_depstargetflag(target)\n    local depoutputflag = _g.depoutputflag\n    if depoutputflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-fdeps-target=\" .. os.tmpfile() .. \".o\", \"cxxflags\", {flagskey = \"gcc_deps_output\",\n         on_check = function (ok, errors)\n             if errors:find(\"-M\") then\n                ok = true\n             end\n             return ok, errors\n        end}) then\n            depoutputflag = \"-fdeps-target=\"\n        end\n        _g.depoutputflag = depoutputflag or false\n    end\n    return depoutputflag or nil\nend\n\nfunction get_cppversionflag(target)\n    local cppversionflag = _g.cppversionflag\n    if cppversionflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local flags = compinst:compflags({target = target})\n        local idx = table.find_first_if(flags, function(_, v) return string.startswith(v, \"-std=c++\") end)\n        cppversionflag = (idx and flags[idx]) or \"-std=c++20\"\n        _g.cppversionflag = cppversionflag\n    end\n    return cppversionflag or nil\nend\n\nfunction get_gcc_version(target)\n    local gcc_version = _g.gcc_version\n    if not gcc_version then\n        local program, toolname = target:tool(\"cxx\")\n        if program and (toolname:startswith(\"gcc\") or toolname:startswith(\"gxx\")) then\n            local gcc = find_tool(toolname, {program = program, version = true,\n                envs = os.getenvs(), cachekey = \"modules_support_gcc_\" .. toolname})\n            if gcc then\n                gcc_version = gcc.version\n            end\n        end\n        gcc_version = gcc_version or false\n        _g.gcc_version = gcc_version\n    end\n    return gcc_version or nil\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        install.lua\n--\n\nimport(\"support\")\nimport(\"scanner\")\nimport(\"builder\")\n\nfunction install(target)\n    -- we cannot use target:data(\"cxx.has_modules\"),\n    -- because on_config will be not called when installing targets\n    if support.contains_modules(target) then\n        local modules = scanner.get_modules(target)\n        builder.generate_metadata(target, modules)\n        support.add_installfiles_for_modules(target, modules)\n    end\nend\n\nfunction uninstall(target)\n    if support.contains_modules(target) then\n        local modules = scanner.get_modules(target)\n        support.add_installfiles_for_modules(target, modules)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/mapper.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        mapper.lua\n--\n\nimport(\"support\")\nimport(\"core.base.hashset\")\n\n-- get or create a target module mapper\nfunction get_mapper_for(target, opt)\n    local localcache = support.localcache()\n    local mapper = localcache:get2(target:fullname(), \"module_mapper\")\n    local invalidate = opt and opt.invalidate\n    if not mapper or invalidate then\n        mapper = {}\n        localcache:set2(target:fullname(), \"module_mapper\", mapper)\n    end\n    return mapper\nend\n\nfunction reuse_modules(target)\n    local localcache = support.localcache()\n    local reused_modules = localcache:get2(target:fullname(), \"reused_modules\")\n    for key, from_name in pairs(reused_modules) do\n        local dep = target:dep(from_name)\n        assert(dep)\n        support.set_reused(target, dep, key)\n    end\nend\n\n-- feed the module mapper\nfunction feed(target, modules, sourcefiles)\n\n    local mapper = get_mapper_for(target, {invalidate = true})\n    local deps_names = hashset.new()\n    local deps_names_map = {}\n    local headerunit_aliases = {}\n    for _, module in pairs(modules) do\n        if module.headerunit and module.alias then\n            table.insert(headerunit_aliases, module)\n        elseif not module.sourcealias then\n            local name = module.headerunit and (module.name .. module.key) or module.name\n            if name then\n                if name ~= \"std\" and name ~= \"std.compat\" and deps_names:has(name) then\n                    raise(\"duplicate module name detected for \\\"\" .. name .. \"\\\"\\n  <\" .. target:fullname() .. \"> -> \" .. module.sourcefile .. \"\\n  <\" .. deps_names_map[name] .. \"> -> \" .. mapper[name].sourcefile)\n                end\n                deps_names:insert(module.name)\n                deps_names_map[name] = target:fullname()\n                if module.headerunit then\n                    if not mapper[name] then\n                        mapper[name] = module\n                    end\n                else\n                    mapper[name] = module\n                end\n            end\n            if not module.headerunit and not mapper[module.sourcefile] then\n                mapper[module.sourcefile] = table.clone(module)\n                mapper[module.sourcefile].sourcealias = true\n            end\n        end\n    end\n    local reuse = target:policy(\"build.c++.modules.reuse\") or\n                  target:policy(\"build.c++.modules.tryreuse\")\n    -- replace target reused module by dep module\n    if reuse then\n        for _, sourcefile in ipairs(sourcefiles) do\n            local from_dep = support.is_from_dep(target, sourcefile)\n            if from_dep then\n                local reused, from = support.is_reused(target, sourcefile)\n                if reused then\n                    local module = get(from, sourcefile)\n                    if module.name then\n\t\t                    mapper[module.name] =  module\n\t\t                    for dep_name, dep_module in pairs(module.deps) do\n\t\t                        if dep_module.headerunit then\n\t\t                            local key = dep_name .. dep_module.key\n\t\t                            mapper[key] = get(from, key)\n\t\t                            local sourcefile = mapper[key].sourcefile\n\t\t                            mapper[sourcefile .. dep_module.key] = table.clone(mapper[key])\n\t\t                            mapper[sourcefile .. dep_module.key].alias = false\n\t\t                        end\n\t\t                    end\n\t                  end\n                end\n            end\n        end\n    end\n    -- insert aliases\n    for _, alias in pairs(headerunit_aliases) do\n        local name = alias.name .. alias.key\n        if not mapper[name] then\n            local _module = table.clone(mapper[alias.sourcefile .. alias.key])\n            _module.name = alias.name\n            _module.alias = true\n            mapper[name] = _module\n        end\n    end\nend\n\n-- get a module from target mapper by name\nfunction get(target, name)\n    local mapper = get_mapper_for(target)\n    assert(mapper)\n    return mapper[name]\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/msvc/builder.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        msvc/builder.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"utils.progress\")\nimport(\"private.action.build.object\", {alias = \"objectbuilder\"})\nimport(\"core.tool.compiler\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"private.tools.vstool\")\nimport(\"support\")\nimport(\".mapper\")\nimport(\".builder\", {inherit = true})\n\n-- get flags for building a module\nfunction _make_modulebuildflags(target, module, opt)\n    opt = opt or {}\n    local ifcoutputflag = support.get_ifcoutputflag(target)\n    local ifconlyflag = support.get_ifconlyflag(target)\n    local interfaceflag = support.get_interfaceflag(target)\n    local internalpartitionflag = support.get_internalpartitionflag(target)\n\n    local bmionly = opt.bmi and not opt.objectfile\n\n    local flags\n    if module.name then -- named module\n        flags = table.join(\"-TP\", module.interface and interfaceflag or internalpartitionflag, bmionly and ifconlyflag or {}, ifcoutputflag, path(module.bmifile))\n    else\n        flags = {\"-TP\"}\n    end\n    return flags\nend\n\nfunction _compile_one_step(target, module, opt)\n    -- get flags\n    local flags = _make_modulebuildflags(target, module)\n    if opt and opt.batchcmds then\n        _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n    else\n        _compile(target, flags, module, opt)\n    end\nend\n\nfunction _compile_bmi_step(target, module, opt)\n    local ifconlyflag = support.get_ifconlyflag(target)\n    if not ifconlyflag then\n        _compile_one_step(target, module, opt)\n    else\n        local flags = _make_modulebuildflags(target, module, opt)\n        if opt and opt.batchcmds then\n            _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n        else\n            _compile(target, flags, module, opt)\n        end\n    end\nend\n\nfunction _compile_objectfile_step(target, module, opt)\n    local flags = _make_modulebuildflags(target, module)\n    if opt and opt.batchcmds then\n        _batchcmds_compile(opt.batchcmds, target, flags, module, opt)\n    else\n        _compile(target, flags, module, opt)\n    end\nend\n\n-- get flags for building a headerunit\nfunction _make_headerunitflags(target, headerunit, headertype)\n    -- get flags\n    local exportheaderflag = support.get_exportheaderflag(target)\n    local headernameflag = support.get_headernameflag(target)\n    local ifcoutputflag = support.get_ifcoutputflag(target)\n    local ifconlyflag = support.get_ifconlyflag(target)\n    assert(headernameflag and exportheaderflag, \"compiler(msvc): does not support c++ header units!\")\n\n    local flags = {\"-TP\",\n                   exportheaderflag,\n                   ifcoutputflag,\n                   headerunit.bmifile,\n                   ifconlyflag or {},\n                   headernameflag .. headertype} -- keep it at last flag\n    return flags\nend\n\nfunction _get_mapper_str(target, module, opt)\n    local mapper_str\n    if target:policy(\"build.c++.modules.hide_dependencies\") and option.get(\"diagnosis\") then\n        if not opt.headerunit then\n            local requires_flagsfile = target:autogenfile(module.sourcefile .. \".requiresflags.txt\")\n            if os.isfile(requires_flagsfile) then\n                if module.name  then\n                    mapper_str = format(\"\\n${dim color.warning}mapper file for %s (%s) --------\\n%s\\n--------\", module.name, module.sourcefile, io.readfile(requires_flagsfile):trim())\n                else\n                    mapper_str = format(\"\\n${dim color.warning}mapper file for %s --------\\n%s\\n--------\", module.sourcefile, io.readfile(requires_flagsfile):trim())\n                end\n            end\n        end\n    end\n    return mapper_str\nend\n\n-- do compile\nfunction _compile(target, flags, module, opt)\n    opt = opt or {}\n    local sourcefile = module.sourcefile\n    local outputfile = opt.headerunit and nil or module.objectfile\n    local dryrun = option.get(\"dry-run\")\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(compflags or {}, flags or {})\n\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        if not outputfile then\n            cmd = \"\\n\" .. os.args(table.join(compinst:program(), flags, sourcefile))\n        else\n            cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, sourcekind = \"cxx\", rawargs = true})\n        end\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, suffix = _get_mapper_str(target, module, opt)}))\n\n    -- do compile\n    if not dryrun then\n        assert(compinst:compile(sourcefile, outputfile or target:objectfile(sourcefile), {target = target, compflags = flags}))\n    end\nend\n\n-- do compile for batchcmds\n-- @note we need to use batchcmds:compilev to translate paths in compflags for generator, e.g. -Ixx\nfunction _batchcmds_compile(batchcmds, target, flags, module, opt)\n    opt = opt or {}\n    local sourcefile = module.sourcefile\n    local outputfile = opt.headerunit and nil or module.objectfile\n    local compinst = target:compiler(\"cxx\")\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n    flags = table.join(\"/c\", compflags or {}, flags or {}, outputfile and \"-Fo\" .. outputfile or {}, sourcefile or {})\n\n    -- trace\n    local cmd\n    if option.get(\"verbose\") then\n        if not outputfile then\n            cmd = \"\\n\" .. os.args(table.join(compinst:program(), flags, sourcefile))\n        else\n            cmd = \"\\n\" .. compinst:compcmd(sourcefile, outputfile, {target = target, compflags = flags, sourcekind = \"cxx\", rawargs = true})\n        end\n    end\n    show_progress(target, module, table.join(opt, {cmd = cmd, batchcmds = batchcmds, suffit = _get_mapper_str(target, module, opt)}))\n\n    -- do compile\n    batchcmds:compilev(flags, {compiler = compinst, sourcekind = \"cxx\", verbose = false})\nend\n\n-- get module requires flags\n-- e.g\n-- /reference Foo=build/.gens/Foo/rules/modules/cache/Foo.ifc\n-- /headerUnit:angle glm/mat4x4.hpp=Users\\arthu\\AppData\\Local\\.xmake\\packages\\g\\glm\\0.9.9+8\\91454f3ee0be416cb9c7452970a2300f\\include\\glm\\mat4x4.hpp.ifc\n--\nfunction _get_requiresflags(target, module)\n\n    local referenceflag = support.get_referenceflag(target)\n    local headerunitflag = support.get_headerunitflag(target)\n\n    local name = module.name or module.sourcefile\n    local cachekey = target:fullname() .. name\n\n    local requires, requires_changed = is_dependencies_changed(target, module)\n    local requiresflags = support.memcache():get2(cachekey, \"requiresflags\")\n    if not requiresflags or requires_changed then\n        local deps_flags = {}\n        for required, dep in pairs(module.deps) do\n            if dep.headerunit then\n                required = required .. dep.key\n            end\n            local dep_module = mapper.get(target, required)\n            assert(dep_module, \"module dependency %s required for %s not found <%s>\", required, name, target:fullname())\n\n            -- aliased headerunit\n            local mapflag\n            if dep_module.headerunit then\n                local type = dep_module.method == \"include-angle\" and \":angle\" or \":quote\"\n                mapflag = {headerunitflag .. type}\n                table.insert(deps_flags, {headerunitflag, dep_module.sourcefile .. \"=\" .. dep_module.bmifile})\n            else\n                mapflag = {referenceflag}\n            end\n            table.insert(mapflag, dep_module.name .. \"=\" .. dep_module.bmifile)\n            table.insert(deps_flags, mapflag)\n\n            -- append deps\n            if dep_module.deps then\n                local deps = _get_requiresflags(target, dep_module)\n                table.join2(deps_flags, deps)\n            end\n        end\n\n        -- remove duplicates\n        requiresflags = {}\n        local contains = {}\n        table.sort(deps_flags, function(a, b) return a[2] > b[2] end)\n        for _, map in ipairs(deps_flags) do\n            local name = map[2]:split(\"=\")[1]\n            if name and not contains[name] then\n                table.insert(requiresflags, map)\n                contains[name] = true\n            end\n        end\n        support.memcache():set2(cachekey, \"requiresflags\", requiresflags)\n        support.memcache():set2(cachekey, \"oldrequires\", requires)\n    end\n    return requiresflags\nend\n\nfunction _append_requires_flags(target, module)\n    local cxxflags = _get_requiresflags(target, module)\n    if #cxxflags > 0 then\n        if target:policy(\"build.c++.modules.hide_dependencies\") then\n            local _cxxflags = {}\n            for _, flag in ipairs(cxxflags) do\n                table.insert(_cxxflags, flag[1] .. ' \"' .. path.unix(flag[2]) .. '\"')\n            end\n            local requires_flagsfile = target:autogenfile(module.sourcefile .. \".requiresflags.txt\")\n            io.writefile(requires_flagsfile, table.concat(_cxxflags, \"\\n\"))\n            target:fileconfig_add(module.sourcefile, {force = {cxxflags = {{\"@\" .. requires_flagsfile}}}})\n        else\n            target:fileconfig_add(module.sourcefile, {force = {cxxflags = cxxflags}})\n        end\n    end\nend\n\nfunction append_requires_flags(target, built_modules)\n    -- append requires flags\n    for _, sourcefile in ipairs(built_modules) do\n        local module = mapper.get(target, sourcefile)\n        if module.deps then\n            _append_requires_flags(target, module)\n        end\n    end\nend\n\n-- build module file for batchjobs / jobgraph\nfunction make_module_job(target, module, opt)\n\n    local dryrun = option.get(\"dry-run\")\n\n    -- generate and append module mapper file\n    local build = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build then\n        if not dryrun then\n            local objectdir = path.directory(module.objectfile)\n            if not os.isdir(objectdir) then\n                os.mkdir(objectdir)\n            end\n            if module.bmifile then\n                local bmidir = path.directory(module.bmifile)\n                if not os.isdir(bmidir) then\n                    os.mkdir(bmidir)\n                end\n            end\n        end\n\n        if bmi and objectfile then\n            _compile_one_step(target, module, opt)\n        elseif bmi then\n            _compile_bmi_step(target, module, opt)\n        else\n            if support.has_module_extension(module.sourcefile) or module.name then\n                _compile_objectfile_step(target, module, opt)\n            else\n                os.tryrm(module.objectfile) -- force rebuild for .cpp files\n            end\n        end\n    end\nend\n\n-- build module file for batchcmds\nfunction make_module_buildcmds(target, batchcmds, module, opt)\n\n    -- generate and append module mapper file\n    local build = should_build(target, module)\n    local bmi = opt and opt.bmi\n    local objectfile = opt and opt.objectfile\n\n    if build then\n        local objectdir = path.directory(module.objectfile)\n        batchcmds:mkdir(objectdir)\n        if module.bmifile then\n            local bmidir = path.directory(module.bmifile)\n            batchcmds:mkdir(bmidir)\n        end\n        if bmi and objectfile then\n            _compile_one_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n        elseif bmi then\n            _compile_bmi_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n        else\n            if support.has_module_extension(module.sourcefile) or module.name then\n                _compile_objectfile_step(target, module, table.join(opt, {batchcmds = batchcmds}))\n            else\n                batchcmds:rm(module.objectfile) -- force rebuild for .cpp files\n            end\n        end\n    end\n    batchcmds:add_depfiles(module.sourcefile)\n    return os.mtime(module.objectfile)\nend\n\n-- build headerunit file for batchjobs / jobgraph\nfunction make_headerunit_job(target, headerunit, opt)\n    local build = should_build(target, headerunit)\n    if build then\n        local headertype = (headerunit.method == \"include-angle\") and \":angle\" or \":quote\"\n        _compile(target, _make_headerunitflags(target, headerunit, headertype), {sourcefile = (headertype == \":angle\") and headerunit.name or headerunit.sourcefile}, table.join(opt, {headerunit = true}))\n    end\nend\n\n-- build headerunit file for batchcmds\nfunction make_headerunit_buildcmds(target, batchcmds, headerunit, opt)\n    local compinst = compiler.load(\"cxx\", {target = target})\n    local compflags = compinst:compflags({sourcefile = headerunit.sourcefile, target = target, sourcekind = \"cxx\"})\n    local depvalues = {compinst:program(), compflags}\n\n    local build = should_build(target, headerunit)\n    if build then\n        local headertype = (headerunit.method == \"include-angle\") and \":angle\" or \":quote\"\n        _batchcmds_compile(batchcmds, target, _make_headerunitflags(target, headerunit, headertype), {(headertype == \":angle\") and headerunit.name or headerunit.sourcefile}, table.join(opt, {headerunit = true}))\n        batchcmds:add_depfiles(headerunit.sourcefile)\n    end\n    batchcmds:add_depvalues(depvalues)\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/msvc/scanner.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        msvc/scanner.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.semver\")\nimport(\"core.project.depend\")\nimport(\"private.tools.vstool\")\nimport(\"utils.progress\")\nimport(\"support\")\nimport(\"builder\")\nimport(\".scanner\", {inherit = true})\n\n-- scan module dependencies\nfunction scan_dependency_for(target, sourcefile, rescan, opt)\n\n    local msvc = target:toolchain(\"msvc\")\n    local compinst = target:compiler(\"cxx\")\n    local changed = false\n    local dependfile = target:dependfile(sourcefile)\n    local compflags = compinst:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"}) or {}\n    local scandependenciesflag = support.get_scandependenciesflag(target)\n    local ifcoutputflag = support.get_ifcoutputflag(target)\n    local common_flags = {\"-TP\", scandependenciesflag}\n    local fallbackscanner = target:policy(\"build.c++.modules.fallbackscanner\") or\n                            target:policy(\"build.c++.modules.msvc.fallbackscanner\") or\n                            target:policy(\"build.c++.msvc.fallbackscanner\")\n\n    depend.on_changed(function ()\n        if opt.progress and not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            progress.show(opt.progress, \"${clear}generating.module.deps %s\", sourcefile)\n        end\n        \n        local outputdir = support.get_outputdir(target, sourcefile, {scan = true})\n        local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. \".module.json\"))\n        if scandependenciesflag and not fallbackscanner then\n            local dependency_flags = {jsonfile, sourcefile, ifcoutputflag, outputdir, \"-Fo\" .. target:objectfile(sourcefile)}\n            local dependency_flags = table.join(compflags, common_flags, dependency_flags)\n            os.vrunv(compinst:program(), winos.cmdargv(dependency_flags), {envs = msvc:runenvs()})\n        else\n            fallback_generate_dependencies(target, jsonfile, sourcefile, function(file)\n                local ifile = path.translate(path.join(outputdir, path.filename(file) .. \".i\"))\n                os.vrunv(compinst:program(), table.join(compflags,\n                    {\"/P\", \"-TP\", file,  \"/Fi\" .. ifile}), {envs = msvc:runenvs()})\n                local content = io.readfile(ifile)\n                os.rm(ifile)\n                return content\n            end)\n        end\n        changed = true\n\n        local dependinfo = io.readfile(jsonfile)\n        return { moduleinfo = dependinfo }\n    end, {dependfile = dependfile, files = {sourcefile}, changed = rescan, values = compflags})\n    return changed\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/msvc/support.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        msvc/support.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.tool.toolchain\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\".support\", {inherit = true})\n\n-- load module support for the current target\nfunction load(target)\n\n    -- enable std modules if c++23 by defaults\n    if target:data(\"c++.msvc.enable_std_import\") == nil and target:policy(\"build.c++.modules.std\") then\n        local languages = target:get(\"languages\")\n        local isatleastcpp23 = false\n        for _, language in ipairs(languages) do\n            if language:startswith(\"c++\") or language:startswith(\"cxx\") then\n                isatleastcpp23 = true\n                local version = tonumber(language:match(\"%d+\"))\n                if (not version or version <= 20) and not language:match(\"latest\") then\n                    isatleastcpp23 = false\n                    break\n                end\n            end\n        end\n        local stdmodulesdir\n        local msvc = target:toolchain(\"msvc\")\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars.VCInstallDir and vcvars.VCToolsVersion and semver.compare(vcvars.VCToolsVersion, \"14.35\") >= 0 then\n                stdmodulesdir = path.join(vcvars.VCInstallDir, \"Tools\", \"MSVC\", vcvars.VCToolsVersion, \"modules\")\n            end\n        end\n        if stdmodulesdir then\n            target:data_set(\"c++.msvc.enable_std_import\", isatleastcpp23 and os.isdir(stdmodulesdir))\n        end\n    end\nend\n\n-- flags that doesn't affect bmi generation\nfunction strippeable_flags()\n\n    -- speculative list as there is no resource that list flags that prevent reusability, this list will likely be improve over time\n    -- @see https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=msvc-170\n    local strippeable_flags = {\n        \"TP\",\n        \"errorReport\",\n        \"W\",\n        \"w\",\n        \"sourceDependencies\",\n        \"scanDependencies\",\n        \"PD\",\n        \"nologo\",\n        \"MP\",\n        \"internalPartition\",\n        \"interface\",\n        \"ifcOutput\",\n        \"help\",\n        \"headerName\",\n        \"Fp\",\n        \"Fm\",\n        \"Fe\",\n        \"Fd\",\n        \"FC\",\n        \"exportHeader\",\n        \"EP\",\n        \"E\",\n        \"doc\",\n        \"diagnostics\",\n        \"cgthreads\",\n        \"C\",\n        \"analyze\",\n        \"?\",\n        \"external\",\n        \"fsanitize\"\n    }\n    local splitted_strippeable_flags = {\n        \"Fo\",\n        \"I\",\n        \"reference\",\n        \"headerUnit\",\n    }\n    return strippeable_flags, splitted_strippeable_flags\nend\n\n-- provide toolchain include dir for stl headerunit when p1689 is not supported\nfunction toolchain_includedirs(target)\n    for _, toolchain_inst in ipairs(target:toolchains()) do\n        if toolchain_inst:name() == \"msvc\" then\n            local vcvars = toolchain_inst:config(\"vcvars\")\n            if vcvars.VCInstallDir and vcvars.VCToolsVersion then\n                return { path.join(vcvars.VCInstallDir, \"Tools\", \"MSVC\", vcvars.VCToolsVersion, \"include\") }\n            end\n            break\n        end\n    end\n    raise(\"msvc toolchain includedirs not found!\")\nend\n\nfunction has_two_phase_compilation_support(_)\n    return false\nend\n\n-- build c++23 standard modules if needed\nfunction get_stdmodules(target, opt)\n    opt = opt or {}\n    local msvc\n    if opt.toolchain then\n        msvc = toolchain.load(\"msvc\", {plat = opt.toolchain:plat(), arch = opt.toolchain:arch()})\n    else\n        msvc = target:toolchain(\"msvc\")\n    end\n    if msvc and msvc:check() then\n        local vcvars = msvc:config(\"vcvars\")\n        if vcvars.VCInstallDir and vcvars.VCToolsVersion then\n            local stdmodulesdir = path.join(vcvars.VCInstallDir, \"Tools\", \"MSVC\", vcvars.VCToolsVersion, \"modules\")\n            if os.isdir(stdmodulesdir) then\n                return {path.normalize(path.join(stdmodulesdir, \"std.ixx\")), path.normalize(path.join(stdmodulesdir, \"std.compat.ixx\"))}\n            end\n        end\n    end\n    wprint(\"std and std.compat modules not found! disabling them for the build\")\nend\n\nfunction get_bmi_extension()\n    return \".ifc\"\nend\n\nfunction get_ifcoutputflag(target)\n    local ifcoutputflag = _g.ifcoutputflag\n    if ifcoutputflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags({\"-ifcOutput\", os.tmpfile()}, \"cxxflags\", {flagskey = \"cl_ifc_output\"})  then\n            ifcoutputflag = \"-ifcOutput\"\n        end\n        assert(ifcoutputflag, \"compiler(msvc): does not support c++ module flag(/ifcOutput)!\")\n        _g.ifcoutputflag = ifcoutputflag or false\n    end\n    return ifcoutputflag or nil\nend\n\nfunction get_ifconlyflag(target)\n    local ifconlyflag = _g.ifconlyflag\n    if ifconlyflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags({\"-ifcOnly\"}, \"cxxflags\", {flagskey = \"cl_ifc_only\"})  then\n            ifconlyflag = \"-ifcOnly\"\n        end\n        _g.ifconlyflag = ifconlyflag or false\n    end\n    return ifconlyflag or nil\nend\n\nfunction get_interfaceflag(target)\n    local interfaceflag = _g.interfaceflag\n    if interfaceflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-interface\", \"cxxflags\", {flagskey = \"cl_interface\"}) then\n            interfaceflag = \"-interface\"\n        end\n        assert(interfaceflag, \"compiler(msvc): does not support c++ module flag(/interface)!\")\n        _g.interfaceflag = interfaceflag or false\n    end\n    return interfaceflag\nend\n\nfunction get_referenceflag(target)\n    local referenceflag = _g.referenceflag\n    if referenceflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags({\"-reference\", \"Foo=\" .. os.tmpfile()}, \"cxxflags\", {flagskey = \"cl_reference\"}) then\n            referenceflag = \"-reference\"\n        end\n        assert(referenceflag, \"compiler(msvc): does not support c++ module flag(/reference)!\")\n        _g.referenceflag = referenceflag or false\n    end\n    return referenceflag or nil\nend\n\nfunction get_headernameflag(target)\n    local headernameflag = _g.headernameflag\n    if headernameflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags({\"-std:c++latest\", \"-exportHeader\", \"-headerName:quote\"}, \"cxxflags\", {flagskey = \"cl_header_name_quote\"}) and\n        compinst:has_flags({\"-std:c++latest\", \"-exportHeader\", \"-headerName:angle\"}, \"cxxflags\", {flagskey = \"cl_header_name_angle\"}) then\n            headernameflag = \"-headerName\"\n        end\n        _g.headernameflag = headernameflag or false\n    end\n    return headernameflag or nil\nend\n\nfunction get_headerunitflag(target)\n    local headerunitflag = _g.headerunitflag\n    if headerunitflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local ifcfile = os.tmpfile()\n        if compinst:has_flags({\"-std:c++latest\", \"-headerUnit:quote\", \"foo.h=\" .. ifcfile}, \"cxxflags\", {flagskey = \"cl_header_unit_quote\"}) and\n        compinst:has_flags({\"-std:c++latest\", \"-headerUnit:angle\", \"foo.h=\" .. ifcfile}, \"cxxflags\", {flagskey = \"cl_header_unit_angle\"}) then\n            headerunitflag = \"-headerUnit\"\n        end\n        _g.headerunitflag = headerunitflag or false\n    end\n    return headerunitflag or nil\nend\n\nfunction get_exportheaderflag(target)\n    local exportheaderflag = _g.exportheaderflag\n    if exportheaderflag == nil then\n        if get_headernameflag(target) then\n            exportheaderflag = \"-exportHeader\"\n        end\n        _g.exportheaderflag = exportheaderflag or false\n    end\n    return exportheaderflag or nil\nend\n\nfunction get_scandependenciesflag(target)\n    local scandependenciesflag = _g.scandependenciesflag\n    if scandependenciesflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local scan_dependencies_jsonfile = os.tmpfile() .. \".json\"\n        if compinst:has_flags(\"-scanDependencies \" .. scan_dependencies_jsonfile, \"cxflags\", {flagskey = \"cl_scan_dependencies\",\n            on_check = function (ok, errors)\n                if os.isfile(scan_dependencies_jsonfile) then\n                    ok = true\n                end\n                if ok and not os.isfile(scan_dependencies_jsonfile) then\n                    ok = false\n                end\n                return ok, errors\n            end}) then\n            scandependenciesflag = \"-scanDependencies\"\n        end\n        _g.scandependenciesflag = scandependenciesflag or false\n    end\n    return scandependenciesflag or nil\nend\n\nfunction get_cppversionflag(target)\n    local cppversionflag = _g.cppversionflag\n    if cppversionflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        local flags = compinst:compflags({target = target})\n        local idx = table.find_first_if(flags, function(_, v) return string.startswith(v, \"/std:c++\") end)\n        cppversionflag = (idx and flags[idx]) or \"/std:c++latest\"\n        _g.cppversionflag = cppversionflag\n    end\n    return cppversionflag or nil\nend\n\nfunction get_internalpartitionflag(target)\n    local internalpartitionflag = _g.internalpartitionflag\n    if internalpartitionflag == nil then\n        local compinst = target:compiler(\"cxx\")\n        if compinst:has_flags(\"-internalPartition\", \"cxxflags\", {flagskey = \"cl_internal_partition\"}) then\n            internalpartitionflag = \"-internalPartition\"\n        end\n        _g.internalpartitionflag = internalpartitionflag or false\n    end\n    return internalpartitionflag or nil\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/scanner.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        scanner.lua\n--\n\n-- imports\nimport(\"core.base.json\")\nimport(\"core.base.hashset\")\nimport(\"core.base.graph\")\nimport(\"core.base.option\")\nimport(\"core.base.profiler\")\nimport(\"core.base.bytes\")\nimport(\"async.jobgraph\")\nimport(\"async.runjobs\")\nimport(\"utils.progress\")\nimport(\"support\")\nimport(\"mapper\")\nimport(\"stlheaders\")\n\nfunction _scanner(target)\n    return support.import_implementation_of(target, \"scanner\")\nend\n\nfunction _parse_meta_info(target, metafile)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"parse metainfo\", metafile)\n    local metadata = json.loadfile(metafile)\n    if metadata.file and metadata.name then\n        return metadata.file, metadata.name, metadata\n    end\n\n    local filename = path.basename(metafile)\n    local metadir = path.directory(metafile)\n    for _, ext in ipairs({\".mpp\", \".mxx\", \".cppm\", \".ixx\"}) do\n        if os.isfile(path.join(metadir, filename .. ext)) then\n            filename = filename .. ext\n            break\n        end\n    end\n\n    local sourcecode = io.readfile(path.join(path.directory(metafile), filename))\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n\n    local name\n    for _, line in ipairs(sourcecode:split(\"\\n\", {plain = true})) do\n        name = line:match(\"export%s+module%s+(.+)%s*;\") or line:match(\"export%s+__preprocessed_module%s+(.+)%s*;\")\n        if name then\n            break\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"parse metainfo\", metafile)\n    return filename, name, metadata\nend\n\nfunction _get_headerunit_bmifile(target, headerfile)\n    local outputdir = support.get_outputdir(target, headerfile, {headerunit = true})\n    return path.join(outputdir, path.filename(headerfile) .. support.get_bmi_extension(target))\nend\n\nfunction _bmifile_for(target, module)\n    local bmifile = support.get_bmi_path(path.filename(module.name) .. support.get_bmi_extension(target))\n    return path.join(support.get_outputdir(target, module.sourcefile, {interface = module.interface, headerunit = module.headerunit}), bmifile)\nend\n\n-- parse module dependency data\n--[[\n{\n  \"build/.objs/stl_headerunit/linux/x86_64/release/src/hello.mpp.o\" = {\n    requires = {\n      iostream = {\n        method = \"include-angle\",\n        unique = true,\n        path = \"/usr/include/c++/11/iostream\"\n      }\n    },\n    provides = {\n      hello = {\n        bmifile = \"build/.gens/stl_headerunit/linux/x86_64/release/rules/modules/cache/hello.gcm\",\n        sourcefile = \"src/hello.mpp\"\n      }\n    }\n  },\n  \"build/.objs/stl_headerunit/linux/x86_64/release/src/main.cpp.o\" = {\n    requires = {\n      hello = {\n        method = \"by-name\",\n        unique = false,\n        path = \"build/.gens/stl_headerunit/linux/x86_64/release/rules/modules/cache/hello.gcm\"\n      }\n    }\n  }\n}]]\nfunction _parse_moduleinfo(target, moduleinfo)\n    assert(moduleinfo.version <= 1)\n    local module\n    local headerunitsinfo\n    for _, rule in ipairs(moduleinfo.rules) do\n        module = {objectfile = path.translate(rule[\"primary-output\"]), sourcefile = moduleinfo.sourcefile}\n\n        if rule.provides then\n            -- assume rule.provides is always one element on C++\n            -- @see https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html\n            local provide = rule.provides and rule.provides[1]\n            if provide then\n                assert(provide[\"logical-name\"])\n\n                module.name = provide[\"logical-name\"]\n                module.sourcefile = module.sourcefile or path.normalize(provide[\"source-path\"])\n                module.headerunit = provide[\"is-headerunit\"]\n                module.interface = (not module.headerunit and provide[\"is-interface\"] == nil) and true or provide[\"is-interface\"]\n                module.method = provide[\"lookup-method\"] or \"by-name\"\n\n                if module.headerunit then\n                    local key = support.get_headerunit_key(target, module.sourcefile)\n                    module.key = key\n                end\n\n                -- XMake handle bmifile so we don't need rely on compiler-module-path\n                module.bmifile = _bmifile_for(target, module)\n            end\n        end\n\n        if rule.requires then\n            module.deps = {}\n            for _, dep in ipairs(rule.requires) do\n                local method = dep[\"lookup-method\"] or \"by-name\"\n                local name = dep[\"logical-name\"]\n                local headerunit = method:startswith(\"include\")\n                local key = headerunit and support.get_headerunit_key(target, name)\n                module.deps[name] = {\n                    name = name,\n                    method = method,\n                    headerunit = headerunit,\n                    key = key,\n                    unique = dep[\"unique-on-source-path\"] or false,\n                }\n                if method:startswith(\"include\") then\n                    local sourcefile = dep[\"source-path\"]\n                    headerunitsinfo = headerunitsinfo or {}\n                    table.insert(headerunitsinfo, {\n                        version = 0,\n                        revision = 0,\n                        sourcefile = path.normalize(sourcefile),\n                        rules = {{\n                            provides = {table.join(dep, {[\"is-headerunit\"] = true})}\n                        }}\n                    })\n                end\n            end\n        end\n    end\n    return module, headerunitsinfo\nend\n\n-- generate edges for DAG\nfunction _get_edges(target, nodes, modules)\n\n  profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"get module dependency graph edges\")\n  local edges = {}\n  local name_filemap = {}\n  local deps_names = hashset.new()\n  for _, node in ipairs(table.unique(nodes)) do\n      local module = modules[node]\n      if module.name then\n          if deps_names:has(module.name) then\n              raise(\"duplicate module name detected for \\\"\" .. module.name .. \"\\\"\\n  <\" .. target:fullname() .. \"> -> \" .. module.sourcefile .. \"\\n  <\" .. target:fullname() .. \"> -> \" .. name_filemap[module.name])\n          end\n          deps_names:insert(module.name)\n          name_filemap[module.name] = module.sourcefile\n      elseif module.headerunit then\n          deps_names:insert(module.name)\n          name_filemap[module.name] = module.sourcefile\n      end\n      for dep_name, _ in table.orderpairs(module.deps) do\n          for _, dep_node in ipairs(nodes) do\n              local dep_module = modules[dep_node]\n              if dep_module.name and dep_name == dep_module.name then\n                  table.insert(edges, {dep_node, node})\n                  break\n              end\n          end\n      end\n  end\n  profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"get module dependency graph edges\")\n  return edges\nend\n\n-- get package modules\nfunction _get_package_modules(target, package, opt)\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"get modules from package\", package:name())\n    opt = opt or {}\n    local package_modules\n    local modulesdir = path.join(package:installdir(), \"modules\")\n    local metafiles = os.files(path.join(modulesdir, \"*\", \"*.meta-info\"))\n    local jobs = jobgraph.new()\n    for _, metafile in ipairs(metafiles) do\n        jobs:add(\"job/parse_meta_file/\" .. metafile, function()\n            package_modules = package_modules or {}\n            local modulefile, _, metadata = _parse_meta_info(target, metafile)\n\n            local bmionly = package:libraryfiles() and true or false\n            package_modules[path.join(modulesdir, modulefile)] = {defines = metadata.defines,\n                                                                  undefines = metadata.undefines,\n                                                                  bmionly = bmionly,\n                                                                  from_dep = opt.from_dep and opt.from_dep:name(),\n                                                                  from_package = true}\n        end)\n    end\n    runjobs(format(\"parsing package %s module metafiles\", package:name()), jobs, {comax = option.get(\"jobs\") or os.default_njob()})\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"get modules from package\", package:name())\n    return package_modules\nend\n\nfunction _get_packages_for(target)\n    local packages = {}\n    for _, pkg in pairs(target:orderpkgs()) do\n        packages[pkg:name()] = {pkg = pkg, from_dep = false, from_package = true}\n    end\n    for name, dep in pairs(target:orderdeps()) do\n        local dep_packages = _get_packages_for(dep)\n        for pkgname, package in pairs(dep_packages) do\n            packages[pkgname] = {pkg = package.pkg, from_dep = package.from_dep or dep, from_package = true}\n        end\n    end\n    return packages\nend\n\n-- get packages modules\nfunction _get_packages_modules(target)\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"get modules from package dependencies\")\n    -- parse all meta-info and append their informations to the package store\n    local packages_modules = support.memcache():get2(target:fullname(), \"cxx_packages_modules\")\n    if not packages_modules then\n        packages_modules = {}\n        local packages = _get_packages_for(target)\n        for _, package in table.orderpairs(packages) do\n            local package_modules = _get_package_modules(package.from_dep or target, package.pkg, {from_dep = package.from_dep})\n            if package_modules then\n               packages_modules = packages_modules or {}\n               table.join2(packages_modules, package_modules)\n            end\n        end\n        support.memcache():set2(target:fullname(), \"cxx_packages_modules\", packages_modules)\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"get modules from package dependencies\")\n    return packages_modules\nend\n\n-- get target deps modules\nfunction _get_targetdeps_modules(target)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"get modules from target dependencies\")\n    local _, stdmodules_set = support.get_stdmodules(target)\n    local modules\n    for _, dep in ipairs(target:orderdeps()) do\n        local sourcebatches = dep:sourcebatches()\n        if sourcebatches and sourcebatches[\"c++.build.modules.scanner\"] then\n            local sourcebatch = sourcebatches[\"c++.build.modules.scanner\"]\n            if sourcebatch.sourcefiles then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    modules = modules or {}\n                    if support.is_public(dep, sourcefile) or (stdmodules_set and stdmodules_set:has(sourcefile)) then\n                        local _fileconfig = dep:fileconfig(sourcefile)\n                        local fileconfig = {}\n                        if _fileconfig then\n                            fileconfig.defines = _fileconfig.defines\n                            fileconfig.undefines = _fileconfig.undefines\n                            fileconfig.includedirs = _fileconfig.includedirs\n                        end\n                        fileconfig.defines = table.join(fileconfig.defines or {}, dep:get(\"defines\") or {})\n                        fileconfig.undefines = table.join(fileconfig.undefines or {}, dep:get(\"undefines\") or {})\n                        fileconfig.includedirs = table.join(fileconfig.includedirs or {}, dep:get(\"includedirs\") or {})\n                        if not dep:is_phony() then\n                            if target:namespace() == dep:namespace() then\n                                fileconfig.from_dep = dep:name()\n                            else\n                                fileconfig.from_dep = dep:fullname()\n                            end\n                            fileconfig.bmionly = not dep:is_moduleonly()\n                        end\n                        if not modules[sourcefile] then\n                            modules[sourcefile] = fileconfig\n                        end\n                    end\n                end\n            end\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"get modules from target dependencies\")\n    return modules\nend\n\n-- check if flags are compatible for module reuse\nfunction _are_flags_compatible(target, other, sourcefile)\n\n    local compinst1 = target:compiler(\"cxx\")\n    local flags1 = compinst1:compflags({sourcefile = sourcefile, target = target, sourcekind = \"cxx\"})\n\n    local compinst2 = other:compiler(\"cxx\")\n    local flags2 = compinst2:compflags({sourcefile = sourcefile, target = other, sourcekind = \"cxx\"})\n\n    local strip_defines = not target:policy(\"build.c++.modules.reuse.strict\") and\n                                   not target:policy(\"build.c++.modules.tryreuse.discriminate_on_defines\")\n\n    -- strip unrelevent flags\n    flags1 = support.strip_flags(target, flags1, {strip_defines = strip_defines})\n    flags2 = support.strip_flags(target, flags2, {strip_defines = strip_defines})\n\n    if #flags1 ~= #flags2 then\n        return false\n    end\n\n    table.sort(flags1)\n    table.sort(flags2)\n\n    for i = 1, #flags1 do\n        if flags1[i] ~= flags2[i] then\n            return false\n        end\n    end\n    return true\nend\n\nfunction get_basegroup_for(target)\n    return target:fullname() .. \"/modules\"\nend\n\nfunction get_computedagjob_for(target)\n    return get_basegroup_for(target) .. \"/computedag\"\nend\n\nfunction get_scangroup_for(target)\n    return get_basegroup_for(target) .. \"/scan\"\nend\n\nfunction get_scanfilejob_for(target, sourcefile)\n    return get_scangroup_for(target) .. \"/\" .. sourcefile\nend\n\nfunction get_parsegroup_for(target)\n    return get_basegroup_for(target) .. \"/parse\"\nend\n\nfunction get_parsefilejob_for(target, sourcefile)\n    return get_parsegroup_for(target) .. \"/\" .. sourcefile\nend\n\n-- patch sourcebatch\nfunction _patch_sourcebatch(target, sourcebatch)\n\n    local memcache = support.memcache()\n    local cached_sourcebatch = memcache:get2(target:fullname(), \"cached_sourcebatch\")\n    if not cached_sourcebatch then\n        -- target deps modules\n        local depsmodules = _get_targetdeps_modules(target) or {}\n\n        -- package modules\n        local pkgmodules = _get_packages_modules(target) or {}\n\n        local from_depmodules = table.join(depsmodules, pkgmodules)\n        local localcache = support.localcache()\n\n        local reuse = target:policy(\"build.c++.modules.reuse\") or\n                      target:policy(\"build.c++.modules.tryreuse\")\n        local reused = {}\n        for sourcefile, fileconfig in pairs(from_depmodules) do\n            if reuse and fileconfig.from_dep then\n                local nocheck = target:policy(\"build.c++.modules.reuse.nocheck\")\n                local strict = target:policy(\"build.c++.modules.reuse.strict\") or\n                               target:policy(\"build.c++.modules.tryreuse.discriminate_on_defines\")\n                local dep = target:dep(fileconfig.from_dep)\n                assert(dep, \"dep target <%s> for <%s> not found\", fileconfig.from_dep, target:fullname())\n                local can_reuse = nocheck or _are_flags_compatible(target, dep, sourcefile, {strict = strict})\n                if can_reuse then\n                    local _reused, from = support.is_reused(dep, sourcefile)\n                    if _reused then\n                        support.set_reused(target, from, sourcefile)\n                    else\n                        support.set_reused(target, dep, sourcefile)\n                    end\n                    table.insert(reused, sourcefile)\n                    if dep:is_moduleonly() then\n                        dep:data_set(\"cxx.modules.reused\", true)\n                    end\n                end\n            end\n            table.insert(sourcebatch.sourcefiles, sourcefile)\n            target:fileconfig_add(sourcefile, fileconfig)\n        end\n        sourcebatch.sourcekind = \"cxx\"\n        sourcebatch.objectfiles = {}\n        sourcebatch.dependfiles = {}\n        for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            local reused, from = support.is_reused(target, sourcefile)\n            local _target = reused and from or target\n            local objectfile = _target:objectfile(sourcefile)\n            local dependfile = _target:dependfile(sourcefile or objectfile)\n            table.insert(sourcebatch.dependfiles, dependfile)\n        end\n\n        table.sort(sourcebatch.sourcefiles)\n        memcache:set2(target:fullname(), \"cached_sourcebatch\", table.clone(sourcebatch))\n\n        local keys = #sourcebatch.sourcefiles > 0 and table.concat(sourcebatch.sourcefiles) or \"_\"\n        local sum = hash.strhash64(keys)\n        local cached_sum = localcache:get2(target:fullname(), \"sourcebatch_sum\")\n        if not cached_sum or cached_sum ~= sum then\n            localcache:set2(target:fullname(), \"sourcebatch_sum\", sum)\n            memcache:set2(target:fullname(), \"modules.changed\", true)\n        end\n    else\n        sourcebatch = cached_sourcebatch\n    end\nend\n\nfunction _do_computedag(target, modules, sourcebatch)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"compute dag\")\n    local localcache = support.localcache()\n    local memcache = support.memcache()\n    local changed = memcache:get2(target:fullname(), \"modules.changed\")\n\n    if changed then\n        localcache:set2(target:fullname(), \"c++.modules\", modules)\n        mapper.feed(target, modules, sourcebatch.sourcefiles)\n        -- check if a dependency is missing\n        local modules_names = hashset.from(table.keys(mapper.get_mapper_for(target)))\n        for _, module in pairs(modules) do\n            for dep_name, dep in pairs(module.deps) do\n                if dep.method == \"by-name\" then\n                    if not modules_names:has(dep_name) then\n                        if option.get(\"diagnosis\") then\n                            print(\"parsing:\", target:fullname(), \"\\nmodules:\", modules or {})\n                        end\n                        raise(\"<%s> missing %s dependency for module %s\", target:fullname(), dep_name, module.name or module.sourcefile)\n                    end\n                end\n            end\n        end\n        -- steal from c++.build sourcebatch named modules with cpp extensions\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches and sourcebatches[\"c++.build\"] then\n            local cxx_sourcebatch = sourcebatches[\"c++.build\"]\n            cxx_sourcebatch.sourcefiles = {}\n            cxx_sourcebatch.dependfiles = {}\n            cxx_sourcebatch.objectfiles = {}\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                if not support.has_module_extension(sourcefile) then\n                    local module = modules[sourcefile]\n                    local insert = true\n                    if module then\n                        insert = not module.name\n                    end\n\n                    if insert then\n                        table.insert(cxx_sourcebatch.sourcefiles, sourcefile)\n                        local objectfile = target:objectfile(sourcefile)\n                        table.insert(cxx_sourcebatch.dependfiles, target:dependfile(objectfile))\n                        table.insert(cxx_sourcebatch.objectfiles, objectfile)\n                    end\n                end\n            end\n            localcache:set2(target:fullname(), \"c++.build.sourcebatch\", cxx_sourcebatch)\n        end\n    else\n        modules = get_modules(target)\n        local cxx_sourcebatch_cached = localcache:get2(target:fullname(), \"c++.build.sourcebatch\")\n        if cxx_sourcebatch_cached then\n            local cxx_sourcebatch = target:sourcebatches()[\"c++.build\"]\n            cxx_sourcebatch.sourcefiles = cxx_sourcebatch_cached.sourcefiles\n            cxx_sourcebatch.dependfiles = cxx_sourcebatch_cached.dependfiles\n            cxx_sourcebatch.objectfiles = cxx_sourcebatch_cached.objectfiles\n        end\n    end\n\n    -- sort modules\n    sort_modules_by_dependencies(target, modules)\n\n    -- save cache if all other target finished\n    local targets = memcache:get(\"targets\")\n    targets[target:fullname()].finished_parsing = true\n\n    local save_cache = true\n    for _, _target in pairs(targets) do\n        if not _target.finished_parsing then\n            save_cache = false\n            break\n        end\n    end\n    if save_cache then\n        localcache:save()\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"compute dag\")\nend\n\nfunction _do_scan(target, sourcefile, opt)\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"scan dependencies for\", sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    local from_package = fileconfig and fileconfig.from_package\n    local is_std = path.basename(sourcefile) == \"std\" or path.basename(sourcefile) == \"std.compat\"\n    local rescan = target:is_rebuilt() and not from_package and not is_std\n    local changed = _scanner(target).scan_dependency_for(target, sourcefile, rescan, opt)\n    if changed or not support.localcache():get2(target:fullname(), \"module_mapper\") then\n        support.memcache():set2(target:fullname(), \"modules.changed\", true)\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"scan dependencies for\", sourcefile)\nend\n\n-- scan module dependencies\nfunction _schedule_module_dependencies_scan(target, jobgraph, sourcebatch)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"schedule moduleinfo scanning, parsing and dag computation\")\n    -- if XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR is set, then we can just reuse scan artifacts from build\n    if not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") or not support.localcache():get2(target:fullname(), \"c++.modules\") then\n        local memcache = support.memcache()\n        local scangroup = get_scangroup_for(target)\n        local has_scanjob = false\n        jobgraph:group(scangroup, function()\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local reused, _ = support.is_reused(target, sourcefile)\n                if not reused then\n                    local scanfilejob = get_scanfilejob_for(target, sourcefile)\n                    if not jobgraph:has(scanfilejob) then\n                        has_scanjob = true\n                        jobgraph:add(scanfilejob, function(_, _, opt)\n                            progress.set_target(opt.progress, target)\n                            _do_scan(target, sourcefile, opt)\n                        end)\n                    end\n                end\n            end\n        end)\n        local modules\n        local parsegroup = get_parsegroup_for(target)\n        jobgraph:group(parsegroup, function()\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local parsefilejob = get_parsefilejob_for(target, sourcefile)\n                if not jobgraph:has(parsefilejob) then\n                    jobgraph:add(parsefilejob, function(_, _, opt)\n                        local changed = memcache:get2(target:fullname(), \"modules.changed\")\n                        if changed then\n                            modules = modules or {}\n                            local moduleinfo = support.load_moduleinfo(target, sourcefile)\n                            local module, headerunitsinfo = _parse_moduleinfo(target, moduleinfo)\n                            modules[module.sourcefile] = module\n                            for _, headerunitinfo in ipairs(headerunitsinfo) do\n                                local headerunit = _parse_moduleinfo(target, headerunitinfo)\n                                local key = headerunit.sourcefile .. headerunit.key\n                                if not modules[key] then\n                                    modules[key] = table.clone(headerunit)\n                                    modules[key].name = headerunit.sourcefile\n                                end\n                                local name = headerunit.name .. headerunit.key\n                                modules[name] = headerunit\n                                modules[name].alias = true\n                            end\n                        end\n                                        end)\n                    local reused, from = support.is_reused(target, sourcefile)\n                    if reused then\n                        local scanfilejob = get_scanfilejob_for(from, sourcefile)\n                        if jobgraph:has(scanfilejob) then\n                            jobgraph:add_orders(scanfilejob, parsefilejob)\n                        else\n                            local jobdeps = memcache:get2(from:fullname(), \"jobdeps\") or {}\n                            jobdeps.parsefile = jobdeps.parsefile or {}\n                            jobdeps.parsefile[parsefilejob] = scanfilejob\n                            memcache:set2(from:fullname(), \"jobdeps\", jobdeps)\n                        end\n                    end\n                end\n            end\n        end)\n        local computedagjob = get_computedagjob_for(target)\n        jobgraph:add(computedagjob, function ()\n            _do_computedag(target, modules, sourcebatch)\n        end)\n        if has_scanjob then\n            jobgraph:add_orders(scangroup, parsegroup)\n        end\n        jobgraph:add_orders(parsegroup, computedagjob)\n        local jobdeps = memcache:get2(target:fullname(), \"jobdeps\")\n        if jobdeps then\n            for _, computedag in ipairs(jobdeps.computedag) do\n                if jobgraph:has(computedag) then\n                    jobgraph:add_orders(computedagjob, computedag)\n                end\n            end\n            for from, to in pairs(jobdeps.parsefile) do\n                if jobgraph:has(to) then\n                    jobgraph:add_orders(to, from)\n                end\n            end\n        end\n\n        for _, dep in ipairs(target:orderdeps()) do\n            local dep_computedagjob = get_computedagjob_for(dep)\n            if jobgraph:has(dep_computedagjob) then\n                jobgraph:add_orders(dep_computedagjob, computedagjob)\n            else\n                local jobdeps = memcache:get2(dep:fullname(), \"jobdeps\") or {}\n                jobdeps.computedag = jobdeps.computedag or {}\n                table.insert(jobdeps.computedag, computedagjob)\n                memcache:set2(dep:fullname(), \"jobdeps\", jobdeps)\n            end\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"schedule moduleinfo scanning, parsing and dag computation\")\nend\n\n-- get headerunits info\nfunction sort_headerunits(target, headerunits)\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"sort headerunits\")\n    local _headerunits\n    local stl_headerunits\n    for _, headerunit in ipairs(headerunits) do\n        local module = mapper.get(target, headerunit)\n        if stlheaders.is_stlheader(path.filename(module.name)) then\n            stl_headerunits = stl_headerunits or {}\n            table.insert(stl_headerunits, headerunit)\n        else\n            _headerunits = _headerunits or {}\n            table.insert(_headerunits, headerunit)\n        end\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"sort headerunits\")\n    return _headerunits, stl_headerunits\nend\n\n-- https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html\n--[[\n{\n  \"version\": 1,\n  \"revision\": 0,\n  \"rules\": [\n    {\n      \"primary-output\": \"use-header.mpp.o\",\n      \"requires\": [\n        {\n          \"logical-name\": \"<header.hpp>\",\n          \"source-path\": \"/path/to/found/header.hpp\",\n          \"unique-on-source-path\": true,\n          \"lookup-method\": \"include-angle\"\n        }\n      ]\n    },\n    {\n      \"primary-output\": \"header.hpp.bmi\",\n      \"provides\": [\n        {\n          \"logical-name\": \"header.hpp\",\n          \"source-path\": \"/path/to/found/header.hpp\",\n          \"unique-on-source-path\": true,\n        }\n      ]\n    }\n  ]\n}]]\nfunction fallback_generate_dependencies(target, jsonfile, sourcefile, preprocess_file)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"fallback scanner\", \"scan module dependencies for\", sourcefile)\n    local output = {version = 1, revision = 0, rules = {}}\n    local rule = {outputs = {jsonfile}}\n    rule[\"primary-output\"] = target:objectfile(sourcefile)\n\n    local module_name_export\n    local module_name_private\n    local module_deps = {}\n    local module_deps_set = hashset.new()\n    local sourcecode = preprocess_file(sourcefile) or io.readfile(sourcefile)\n    local internal = false\n    sourcecode = sourcecode:gsub(\"//.-\\n\", \"\\n\")\n    sourcecode = sourcecode:gsub(\"/%*.-%*/\", \"\")\n    for _, line in ipairs(sourcecode:split(\"\\n\", {plain = true})) do\n        if line:match(\"#\") then\n            goto continue\n        end\n        if not module_name_export then\n            module_name_export = line:match(\"export%s+module%s+(.+)%s*;\") or line:match(\"export%s+__preprocessed_module%s+(.+)%s*;\")\n        end\n        if not module_name_private then\n            module_name_private = line:match(\"module%s+(.+)%s*;\") or line:match(\"__preprocessed_module%s+(.+)%s*;\")\n            if module_name_private then\n                internal = module_name_private:find(\":\")\n            end\n        end\n        local module_depname = line:match(\"import%s+(.+)%s*;\")\n        -- Normal module implementation units need to reference the module interface unit, module and partition interface units,\n        -- as well as partition implementation units don't have this requirement.\n        if not module_depname and not module_name_export and not internal then\n            module_depname = module_name_private\n        end\n        if module_depname and not module_deps_set:has(module_depname) then\n            local module_dep = {}\n            -- partition? import :xxx;\n            if module_depname:startswith(\":\") then\n                local module_name = (module_name_export or module_name_private or \"\")\n                module_name = module_name:split(\":\")[1]\n                module_dep[\"unique-on-source-path\"] = true\n                module_depname = module_name .. module_depname\n            elseif module_depname:startswith(\"\\\"\") then\n                module_depname = module_depname:sub(2, -2)\n                module_dep[\"lookup-method\"] = \"include-quote\"\n                module_dep[\"unique-on-source-path\"] = true\n                module_dep[\"source-path\"] = support.find_quote_header_file(sourcefile, module_depname)\n            elseif module_depname:startswith(\"<\") then\n                module_depname = module_depname:sub(2, -2)\n                module_dep[\"lookup-method\"] = \"include-angle\"\n                module_dep[\"unique-on-source-path\"] = true\n                module_dep[\"source-path\"] = support.find_angle_header_file(target, module_depname)\n            end\n            module_dep[\"logical-name\"] = module_depname\n            table.insert(module_deps, module_dep)\n            module_deps_set:insert(module_depname)\n        end\n        ::continue::\n    end\n\n    if module_name_export or internal then\n        local outputdir = support.get_outputdir(target, sourcefile, {scan = true})\n\n        local provide = {}\n        provide[\"logical-name\"] = module_name_export or module_name_private\n        provide[\"source-path\"] = sourcefile\n        provide[\"is-interface\"] = not internal\n        provide[\"compiled-module-path\"] = path.join(outputdir, (module_name_export or module_name_private) .. support.get_bmi_extension(target))\n\n        rule.provides = {}\n        table.insert(rule.provides, provide)\n    end\n\n    rule.requires = module_deps\n    table.insert(output.rules, rule)\n    local jsondata = json.encode(output)\n    io.writefile(jsonfile, jsondata)\n    profiler.leave(target:fullname(), \"c++ modules\", \"fallback scanner\", \"scan module dependencies for\", sourcefile)\nend\n\n-- topological sort\nfunction sort_modules_by_dependencies(target, modules)\n\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"compute module dependency dag\")\n    local memcache = support.memcache()\n    local localcache = support.localcache()\n    local changed = memcache:get2(target:fullname(), \"modules.changed\")\n    local built_artifacts = localcache:get2(target:fullname(), \"c++.modules.built_artifacts\")\n    if changed or not built_artifacts then\n        local built_modules = {}\n        local built_headerunits = {}\n        local objectfiles = {}\n\n        -- feed the dag\n        local nodes = {}\n        for node, module in pairs(modules) do\n            table.insert(nodes, module.headerunit and node or module.sourcefile)\n        end\n        -- table.unique(nodes)\n        local edges = _get_edges(target, nodes, modules)\n        local dag = graph.new(true)\n        for _, e in ipairs(edges) do\n            dag:add_edge(e[1], e[2])\n        end\n        -- check if dag have dependency cycles and sort sourcefiles by dependencies\n        local sourcefiles_sorted, has_cycle = dag:topo_sort()\n        if has_cycle then\n            local cycle = dag:find_cycle()\n            if cycle then\n                local names = {}\n                for _, sourcefile in ipairs(cycle) do\n                    local module = modules[sourcefile]\n                    table.insert(names, module.name or module.sourcefile)\n                end\n                local module = modules[cycle[1]]\n                table.insert(names, module.name or module.sourcefile)\n                raise(\"circular modules dependency detected!\\n%s\", table.concat(names, \"\\n   -> import \"))\n            end\n        end\n        local sourcefiles_sorted_set = hashset.from(sourcefiles_sorted)\n        for sourcefile, _ in pairs(modules) do\n            if not sourcefiles_sorted_set:has(sourcefile) then\n                table.insert(sourcefiles_sorted, sourcefile)\n                sourcefiles_sorted_set:insert(sourcefile)\n            end\n        end\n        -- prepare objectfiles list built by the target\n        local culleds\n        for _, sourcefile in ipairs(sourcefiles_sorted) do\n            local module = mapper.get(target, sourcefile)\n            local name = module.name\n            local is_named = name ~= nil\n            local sort = (is_named and (module.sourcealias or not module.alias)) or not is_named\n            if sort then\n                local insert = false\n                local reused, from = support.is_reused(target, sourcefile)\n\n                if is_named and not module.headerunit then -- named modules\n                    insert = not support.can_be_culled(target, sourcefile)\n\n                    -- if module is cullable (culling policy enabled and not a public module), try to cull\n                    if not insert then\n                        local edges = dag:adjacent_edges(sourcefile)\n                        if edges then\n                            for _, edge in ipairs(edges) do\n                                if edge:to() ~= sourcefile and sourcefiles_sorted_set:has(edge:to()) then\n                                    insert = true\n                                    break\n                                end\n                            end\n                        end\n                    end\n                else -- regular translation unit with import statements, always inserted\n                    insert = true\n                end\n\n                if insert then\n                    if reused then\n                        if not support.is_bmionly(target, sourcefile) or module.name == \"std\" or module.name == \"std.compat\" then\n                            local objectfile = from:objectfile(sourcefile)\n                            table.insert(objectfiles, tostring(objectfile))\n                        end\n                    elseif module.headerunit then\n                        table.insert(built_headerunits, sourcefile)\n                    else\n                        table.insert(built_modules, sourcefile)\n                        -- insert objectfile if module named and is not imported from a static / shared library or if from a C++ file with a c++ module extension\n                        -- if not so objectfile will be handled by c++.build rule\n                        if not support.is_bmionly(target, sourcefile) and (support.has_module_extension(sourcefile) or is_named) then\n                            local objectfile = target:objectfile(sourcefile)\n                            table.insert(objectfiles, tostring(objectfile))\n                        end\n                   end\n                elseif support.is_from_dep(target, sourcefile) or support.is_from_package(target, sourcefile) or support.is_public(target, sourcefile) or module.headerunit or name == \"std\" or name == \"std.compat\" then\n                else\n                    local p = support.is_public(target, sourcefile)\n                    local e = support.is_from_dep(target, sourcefile)\n                    sourcefiles_sorted_set:remove(sourcefile)\n                    culleds = culleds or {}\n                    culleds[target:fullname()] = culleds[target:fullname()] or {}\n                    table.insert(culleds[target:fullname()], format(\"%s -> %s\", name, sourcefile))\n                end\n            end\n        end\n\n        -- if some named modules has been culled, notify the user\n        if culleds then\n            if option.get(\"verbose\") then\n                local culled_strs = {}\n                for target_name, m in pairs(culleds) do\n                    table.insert(culled_strs, format(\"%s:\\n        %s\", target_name, table.concat(m, \"\\n        \")))\n                end\n                wprint(\"some modules have got culled, because it is not consumed by its target nor flagged as a public module with add_files(\\\"xxx.mpp\\\", {public = true})\\n    %s\",\n                       table.concat(culled_strs, \"\\n    \"))\n            else\n                wprint(\"some modules have got culled, use verbose (-v) mode to more informations\")\n            end\n        end\n        built_headerunits = table.unique(built_headerunits)\n\n        built_artifacts = {modules = built_modules, headerunits = built_headerunits, objectfiles = objectfiles}\n        localcache:set2(target:fullname(), \"c++.modules.built_artifacts\", built_artifacts)\n        memcache:set2(target:fullname(), \"modules.changed\", false)\n    end\n    assert(built_artifacts, \"shouldn't assert here, please open an issue\")\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"compute module dependency dag\")\n    return built_artifacts.modules, built_artifacts.headerunits, built_artifacts.objectfiles\nend\n\nfunction get_modules(target)\n    local modules = support.localcache():get2(target:fullname(), \"c++.modules\")\n    assert(modules, \"no modules! (\" .. target:fullname() .. \")\")\n    return modules\nend\n\nfunction after_scan(target)\n    local sourcebatches = target:sourcebatches()\n    local sourcebatch_builder = sourcebatches and sourcebatches[\"c++.build.modules.builder\"]\n    local sourcebatch_scanner = sourcebatches and sourcebatches[\"c++.build.modules.scanner\"]\n    support.memcache():set2(target:fullname(), \"jobdeps\", nil)\n    if sourcebatch_builder then\n        sourcebatch_builder.sourcefiles = {}\n        sourcebatch_builder.dependfiles = {}\n        sourcebatch_builder.objectfiles = {}\n    end\n    if target:data(\"cxx.has_modules\") then\n        if target:is_moduleonly() or target:is_phony() then\n            return\n        end\n        local compile_commands = os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\") and os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\")\n        local need_objectfiles = not os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\") or compile_commands\n        if need_objectfiles then\n            local modules = get_modules(target)\n            local _, _, objectfiles = sort_modules_by_dependencies(target, modules)\n            assert(sourcebatch_builder)\n            sourcebatch_builder.objectfiles = objectfiles\n        end\n    end\nend\n\nfunction main(target, jobgraph, sourcebatch)\n    profiler.enter(target:fullname(), \"c++ modules\", \"scanner\", \"scan\")\n    local compile_commands = os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\") and os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\")\n    if target:data(\"cxx.has_modules\") and (not os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\") or compile_commands) then\n        local memcache = support.memcache()\n        local targets = memcache:get(\"targets\") or {}\n        targets[target:fullname()] = {}\n        targets[target:fullname()].finished_parsing = false\n        memcache:set(\"targets\", targets)\n\n        _patch_sourcebatch(target, sourcebatch)\n        _schedule_module_dependencies_scan(target, jobgraph, sourcebatch)\n    end\n    profiler.leave(target:fullname(), \"c++ modules\", \"scanner\", \"scan\")\nend\n"
  },
  {
    "path": "xmake/rules/c++/modules/stlheaders.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        stlheaders.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\n\n-- the stl headers list\nfunction _stlheaders()\n\n    return {\n    \"algorithm\",\n    \"forward_list\",\n    \"numbers\",\n    \"stop_token\",\n    \"any\",\n    \"fstream\",\n    \"numeric\",\n    \"streambuf\",\n    \"array\",\n    \"functional\",\n    \"optional\",\n    \"string\",\n    \"atomic\",\n    \"future\",\n    \"ostream\",\n    \"string_view\",\n    \"barrier\",\n    \"initializer_list\",\n    \"queue\",\n    \"bit\",\n    \"iomanip\",\n    \"random\",\n    \"syncstream\",\n    \"bitset\",\n    \"ios\",\n    \"ranges\",\n    \"system_error\",\n    \"charconv\",\n    \"iosfwd\",\n    \"ratio\",\n    \"thread\",\n    \"chrono\",\n    \"iostream\",\n    \"regex\",\n    \"tuple\",\n    \"codecvt\",\n    \"istream\",\n    \"scoped_allocator\",\n    \"typeindex\",\n    \"compare\",\n    \"iterator\",\n    \"semaphore\",\n    \"typeinfo\",\n    \"complex\",\n    \"latch\",\n    \"set\",\n    \"type_traits\",\n    \"concepts\",\n    \"limits\",\n    \"shared_mutex\",\n    \"unordered_map\",\n    \"condition_variable\",\n    \"list\",\n    \"source_location\",\n    \"stacktrace\",\n    \"unordered_set\",\n    \"coroutine\",\n    \"locale\",\n    \"span\",\n    \"utility\",\n    \"deque\",\n    \"map\",\n    \"spanstream\",\n    \"valarray\",\n    \"exception\",\n    \"memory\",\n    \"sstream\",\n    \"variant\",\n    \"execution\",\n    \"memory_resource\",\n    \"stack\",\n    \"vector\",\n    \"filesystem\",\n    \"mutex\",\n    \"version\",\n    \"format\",\n    \"new\",\n    \"type_traits\",\n    \"string_view\",\n    \"stdexcept\",\n    \"condition_variable\",\n    \"print\",\n    \"flat_map\",\n    \"flat_set\",\n    \"mdspan\",\n    \"stdfloat\",\n    \"generator\",\n    \"csetjmp\",\n    \"csignal\",\n    \"cstdarg\",\n    \"cstddef\",\n    \"cstdlib\",\n    \"cfloat\",\n    \"cinttypes\",\n    \"climits\",\n    \"cstdint\",\n    \"cassert\",\n    \"cerrno\",\n    \"cctype\",\n    \"cstring\",\n    \"cuchar\",\n    \"cwchar\",\n    \"cwctype\",\n    \"cfenv\",\n    \"cmath\",\n    \"ctime\",\n    \"clocale\",\n    \"expected\",\n    \"cstdio\"}\nend\n\n-- get all stl headers\nfunction get_stlheaders()\n    local stlheaders = _g.stlheaders\n    if stlheaders == nil then\n        stlheaders = hashset.from(_stlheaders())\n        _g.stlheaders = stlheaders or false\n    end\n    return stlheaders or nil\nend\n\n-- is stl header?\nfunction is_stlheader(header)\n    if header:startswith(\"experimental/\") then\n        header = header:sub(14, -1)\n    end\n    return get_stlheaders():has(header)\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/support.lua",
    "content": "-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        support.lua\n--\n\n-- imports\nimport(\"core.base.bytes\")\nimport(\"core.base.option\")\nimport(\"core.base.json\")\nimport(\"core.base.hashset\")\nimport(\"core.tool.toolchain\")\nimport(\"core.cache.memcache\", {alias = \"_memcache\"})\nimport(\"core.cache.localcache\", {alias = \"_localcache\"})\nimport(\"async.runjobs\")\nimport(\"lib.detect.find_file\")\nimport(\"core.project.project\")\nimport(\"core.project.config\")\n\nfunction _support(target)\n    return import_implementation_of(target, \"support\")\nend\n\nfunction import_implementation_of(target, name)\n    local cachekey = tostring(target)\n    local implementation = memcache():get2(name, cachekey)\n    if implementation == nil then\n        if target:has_tool(\"cxx\", \"clang\", \"clangxx\", \"clang_cl\") then\n            implementation = import(\"clang.\" .. name, {anonymous = true})\n        elseif target:has_tool(\"cxx\", \"gcc\", \"gxx\") then\n            implementation = import(\"gcc.\" .. name, {anonymous = true})\n        elseif target:has_tool(\"cxx\", \"cl\") then\n            implementation = import(\"msvc.\" .. name, {anonymous = true})\n        else\n            local _, toolname = target:tool(\"cxx\")\n            raise(\"compiler(%s): does not implementation c++ module!\", toolname)\n        end\n        memcache():set2(name, cachekey, implementation)\n    end\n    return implementation\nend\n\n-- load module support for the current target\nfunction load(target)\n    -- At least std c++20 is required, and we should call `set_languages(\"c++20\")` to set it\n    local languages = target:get(\"languages\")\n    local cxxlang = false\n    for _, lang in ipairs(languages) do\n        if lang:find(\"cxx\", 1, true) or lang:find(\"c++\", 1, true) or lang:find(\"gnuxx\", 1, true) or lang:find(\"gnu++\", 1, true) then\n            cxxlang = true\n            break\n        end\n    end\n    if not cxxlang then\n        target:add(\"languages\", \"c++20\")\n    end\n    -- load module support for the specific compiler\n    _support(target).load(target)\nend\n\nfunction get_cpplibrary_name(target)\n    -- libc++ come first because on windows, if we use libc++ clang will still use msvc crt so MD / MT / MDd / MTd can be set\n    if target:has_runtime(\"c++_shared\", \"c++_static\") then\n        return \"c++\"\n    elseif target:has_runtime(\"stdc++_shared\", \"stdc++_static\", \"gnustl_static\", \"gnustl_shared\") then\n        return \"stdc++\"\n    elseif target:has_runtime(\"stlport_static\", \"stlport_shared\") then\n        return \"stlport\"\n    elseif target:has_runtime(\"MD\", \"MT\", \"MDd\", \"MTd\") then\n        return \"msstl\"\n    end\n    -- if no specified runtime, fallback on native platform C++ library\n    if target:is_plat(\"android\") then\n        local ndk = toolchain.load(\"ndk\", { plat = target:plat(), arch = target:arch() })\n        local ver = ndk:config(\"ndkver\")\n        if not ver or ver > 14 then\n            return \"c++\"\n        else\n            return \"stdc++\"\n        end\n    elseif target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\", \"applexros\", \"bsd\", \"harmony\") then\n        return \"c++\"\n    elseif target:is_plat(\"linux\", \"mingw\", \"cygwin\", \"msys\", \"haiku\") then\n        return \"stdc++\"\n    elseif target:is_plat(\"windows\") then\n        return \"msstl\"\n    end\nend\n\nfunction has_two_phase_compilation_support(target)\n    return _support(target).has_two_phase_compilation_support(target)\nend\n\n-- strip flags not relevent for module reuse\nfunction strip_flags(target, flags, opt)\n\n    local strippeable_flags, splitted_strippeable_flags\n    if not opt.requiresonly then\n        strippeable_flags, splitted_strippeable_flags =  _support(target).strippeable_flags()\n        if opt and opt.strip_defines then\n            table.join2(splitted_strippeable_flags, {\"D\", \"U\"})\n        end\n    else\n        strippeable_flags, splitted_strippeable_flags =  _support(target).require_flags()\n    end\n\n    local splitted_strippeable_flags_set = hashset.new()\n    for _, flag in ipairs(splitted_strippeable_flags) do\n        table.insert(strippeable_flags, flag)\n        splitted_strippeable_flags_set:insert(\"/\" .. flag)\n        splitted_strippeable_flags_set:insert(\"--\" .. flag)\n        splitted_strippeable_flags_set:insert(\"-\" .. flag)\n    end\n\n    local output = {}\n    local strip_next_flag = false\n    for _, flag in ipairs(flags) do\n        local strip = false\n\n        if strip_next_flag then\n            strip = true\n            strip_next_flag = false\n        else\n            for _, _flag in ipairs(strippeable_flags) do\n                if (flag == \"/\" .. _flag) or (flag == \"--\" .. _flag) or (flag == \"-\" .. _flag) then\n                    strip = true\n                    strip_next_flag = splitted_strippeable_flags_set:has(flag)\n                    break\n                elseif flag:startswith(\"/\" .. _flag) or flag:startswith(\"--\" .. _flag) or flag:startswith(\"-\" .. _flag) then\n                    strip = true\n                    break\n                end\n            end\n        end\n\n        if not strip then\n            table.insert(output, flag)\n        end\n    end\n    return output\nend\n\n-- extract defines from flags\nfunction get_headerunit_key(target, sourcefile)\n    local defines = table.wrap(target:get(\"defines\"))\n    local undefines = table.wrap(target:get(\"undefines\"))\n    local fileconfig = target:fileconfig(sourcefile)\n    if fileconfig then\n        table.join2(defines, fileconfig.defines or {})\n        table.join2(undefines, fileconfig.undefines or {})\n    end\n\n    if #defines > 0 then\n        defines = table.concat(defines, \"-D\")\n    else\n        defines = \"<NO_DEFINES>\"\n    end\n    if #undefines > 0 then\n        undefines = table.concat(undefines, \"-D\")\n    else\n        undefines = \"<NO_UNDEFINES>\"\n    end\n\n    local key = hash.md5(bytes(defines .. undefines))\n    return key\nend\n\n-- get bmi extension\nfunction get_bmi_extension(target)\n    return _support(target).get_bmi_extension()\nend\n\n-- get bmi path\n-- @see https://github.com/xmake-io/xmake/issues/4063\nfunction get_bmi_path(bmifile)\n    bmifile = bmifile:gsub(\":\", \"_PARTITION_\")\n    return path.normalize(bmifile)\nend\n\n-- has module extension? e.g. *.mpp, ...\nfunction has_module_extension(sourcefile, opt)\n    opt = opt or {}\n    local modulexts = _g.modulexts\n    if modulexts == nil then\n        modulexts = hashset.of(\".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\")\n        _g.modulexts = modulexts\n    end\n    local extension = opt.extension or path.extension(sourcefile)\n    return modulexts:has(extension:lower())\nend\n\n-- this target contains module files?\nfunction contains_modules(target)\n    -- we can not use `\"c++.build.modules.builder\"`, because it contains sourcekind/cxx.\n    local target_with_modules = target:sourcebatches()[\"c++.build.modules\"] and true or false\n    if not target_with_modules then\n        target_with_modules = target:policy(\"build.c++.modules\")\n    end\n    if not target_with_modules then\n        for _, dep in ipairs(target:orderdeps()) do\n            local sourcebatches = dep:sourcebatches()\n            if sourcebatches[\"c++.build.modules\"] then\n                target_with_modules = true\n                break\n            end\n        end\n    end\n    return target_with_modules\nend\n\n-- mark that a module scan artifacts and bmifile are reused from an other target\nfunction set_reused(target, from, sourcefile)\n    memcache():set2(target:fullname() .. \"/modules/\" .. sourcefile, \"reuse\", from)\n    if option.get(\"diagnosis\") then\n        print(\"<\" .. target:fullname() .. \">\", \"reuse\", sourcefile, \"from\", \"<\" .. from:fullname() .. \">\")\n    end\nend\n\n-- query if a module scan artifacts and bmifile are reused from an other target\nfunction is_reused(target, sourcefile)\n    local from = memcache():get2(target:fullname() .. \"/modules/\" .. sourcefile, \"reuse\")\n    return from and true or false, from\nend\n\n-- query if a module is public\nfunction is_public(target, sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    return fileconfig and fileconfig.public or false\nend\n\n-- query if a module from a target dep\nfunction is_from_dep(target, sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    return fileconfig and fileconfig.from_dep or false\nend\n\n-- query if a module from a package\nfunction is_from_package(target, sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    return fileconfig and fileconfig.from_package or false\nend\n\n-- query if we should only build bmi\nfunction is_bmionly(target, sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    return fileconfig and fileconfig.bmionly or false\nend\n\n-- query if a module can be culled\nfunction can_be_culled(target, sourcefile)\n    local can_cull = target:policy(\"build.c++.modules.culling\")\n    local fileconfig = target:fileconfig(sourcefile)\n    local _, stdmodules_set = get_stdmodules(target)\n    local is_stdmodule = stdmodules_set and stdmodules_set:has(sourcefile) or false\n    local public = target:kind() == \"moduleonly\" and not is_stdmodule\n    if fileconfig then\n        public = fileconfig.public\n        if fileconfig.cull ~= nil then\n            can_cull = can_cull and fileconfig.cull\n        end\n    end\n    if can_cull then\n        can_cull = is_stdmodule or (fileconfig and fileconfig.external)\n    end\n    return can_cull and not public\nend\n\n-- load module infos\nfunction load_moduleinfo(target, sourcefile)\n    local reused, from = is_reused(target, sourcefile)\n    local dependfile = reused and from:dependfile(sourcefile) or target:dependfile(sourcefile)\n    local moduleinfo\n    if os.isfile(dependfile) then\n        local data = io.load(dependfile)\n        if data then\n            moduleinfo = json.decode(data.moduleinfo)\n            moduleinfo.sourcefile = sourcefile\n        end\n    end\n    return moduleinfo\nend\n\nfunction find_quote_header_file(sourcefile, file)\n    local p = path.join(path.directory(path.absolute(sourcefile, project.directory())), file)\n    assert(os.isfile(p), \"\\\"%s\\\" not found\", p)\n    return p\nend\n\nfunction find_angle_header_file(target, file)\n    local headerpaths = _support(target).toolchain_includedirs(target)\n    for _, dep in ipairs(target:orderdeps()) do\n        local includedirs = table.join(dep:get(\"sysincludedirs\") or {}, dep:get(\"includedirs\") or {})\n        table.join2(headerpaths, includedirs)\n    end\n    for _, pkg in ipairs(target:orderpkgs()) do\n        local includedirs = table.join(pkg:get(\"sysincludedirs\") or {}, pkg:get(\"includedirs\") or {})\n        table.join2(headerpaths, includedirs)\n    end\n    table.join2(headerpaths, target:get(\"includedirs\"))\n    local p = find_file(file, headerpaths)\n    assert(p, \"<%s> not found!\", file)\n    return p\nend\n\n-- get stdmodules\nfunction get_stdmodules(target)\n    if not target:policy(\"build.c++.modules.std\") then\n        return\n    end\n    local cpplib = get_cpplibrary_name(target)\n    if not cpplib then\n        return\n    end\n    local stdmodules = memcache():get2(cpplib, \"c++.modules.stdmodules\")\n    local stdmodules_set = memcache():get2(cpplib, \"c++.modules.stdmodules_set\")\n    if not stdmodules or not stdmodules_set then\n        stdmodules = _support(target).get_stdmodules(target)\n        stdmodules_set = hashset.from(stdmodules or {})\n        memcache():set2(cpplib, \"c++.modules.stdmodules\", stdmodules)\n        memcache():set2(cpplib, \"c++.modules.stdmodules_set\", stdmodules_set)\n    end\n    return stdmodules, stdmodules_set\nend\n\n-- get memcache\nfunction memcache()\n    return _memcache.cache(\"cxxmodules\")\nend\n\n-- get localcache\nfunction localcache()\n    return _localcache.cache(\"cxxmodules\")\nend\n\n-- get modules cache directory\nfunction modules_cachedir(target, opt)\n    assert(opt and (opt.interface ~= nil or opt.headerunit or opt.scan))\n    local moduletype\n    if opt.headerunit then\n        moduletype = \"headerunits\"\n    elseif opt.interface then\n        moduletype = \"interfaces\"\n    elseif opt.scan then\n        moduletype = \"scans\"\n    else\n        moduletype = \"implementation\"\n    end\n    local cachedir = path.join(target:autogendir(), \"rules\", \"bmi\", \"cache\", moduletype)\n    if opt.mkdir and not os.isdir(cachedir) then\n        os.mkdir(cachedir)\n    end\n    return cachedir\nend\n\nfunction get_modulehash(sourcefile)\n    return hash.strhash64(sourcefile)\nend\n\nfunction get_metafile(target, module)\n    -- metafile are only for named modules\n    local outputdir = get_outputdir(target, module.sourcefile, {interface = module.interface or false})\n    return path.join(outputdir, path.filename(module.sourcefile) .. \".meta-info\")\nend\n\nfunction get_outputdir(target, sourcefile, opt)\n    local cachedir = modules_cachedir(target, opt)\n    local modulehash = opt.key or get_modulehash(sourcefile)\n    local outputdir = path.join(cachedir, modulehash)\n    if not os.exists(outputdir) then\n        os.mkdir(outputdir)\n    end\n    return outputdir\nend\n\nfunction add_installfiles_for_modules(target, modules)\n    local sourcebatch = target:sourcebatches()[\"c++.build.modules.install\"]\n    if sourcebatch and sourcebatch.sourcefiles then\n        for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            local fileconfig = target:fileconfig(sourcefile)\n            local install = fileconfig and fileconfig.public or false\n            if install then\n                local modulehash = get_modulehash(sourcefile)\n                local prefixdir = path.join(\"modules\", modulehash)\n                target:add(\"installfiles\", sourcefile, {prefixdir = prefixdir})\n                local metafile = get_metafile(target, modules[sourcefile])\n                if os.exists(metafile) then\n                    target:add(\"installfiles\", metafile, {prefixdir = prefixdir})\n                end\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/c++/modules/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        xmake.lua\n--\n\n-- define rule: c++.build.modules\nrule(\"c++.build.modules\")\n    -- @note support.contains_modules() need it\n    set_extensions(\".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\")\n\n    -- clang/support/config will be depend on target/symbols in release modules (hidden)\n    -- @see The default config parallel execution will cause incremental compilation problems\n    add_orders(\"mode.release\", \"c++.build.modules\")\n    add_orders(\"mode.minsizerel\", \"c++.build.modules\")\n\n    add_deps(\"c++.build.modules.scanner\",\n             \"c++.build.modules.builder\",\n             \"c++.build.modules.install\")\n\n    on_config(\"config\")\n\n    -- insert std modules early to enable culling them if unused\n    after_config(\"config.insert_stdmodules\")\n\n-- scan modules\nrule(\"c++.build.modules.scanner\")\n    set_sourcekinds(\"cxx\", {objectfiles = false})\n    set_extensions(\".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\")\n\n    on_prepare_files(\"scanner\", {jobgraph = true})\n    after_prepare_files(\"scanner.after_scan\")\n\n-- build modules\nrule(\"c++.build.modules.builder\")\n    set_sourcekinds(\"cxx\", {objectfiles = false})\n    set_extensions(\".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\")\n    add_orders(\"c++.build.modules.scanner\", \"c++.build.modules.builder\")\n\n    -- parallel build support to accelerate `xmake build` to build modules\n    before_build_files(\"builder.build_bmis\", {jobgraph = true, batch = true})\n    on_build_files(\"builder.build_objectfiles\", {jobgraph = true, batch = true})\n\n    -- serial compilation only, usually used to support project generator\n    before_buildcmd_files(\"builder.build_bmis\")\n    on_buildcmd_files(\"builder.build_objectfiles\")\n\n    after_clean(\"builder.clean\")\n\n-- install modules\nrule(\"c++.build.modules.install\")\n    set_extensions(\".cppm\", \".ccm\", \".cxxm\", \".c++m\", \".mpp\", \".mxx\", \".ixx\")\n\n    before_install(\"install.install\")\n    before_uninstall(\"install.uninstall\")\n"
  },
  {
    "path": "xmake/rules/c++/openmp/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- main entry\nfunction main(target, sourcekind)\n    wprint(\"we no longer need add_rules(\\\"%s.openmp\\\") now, you just need to add add_packages(\\\"openmp\\\").\", sourcekind == \"cxx\" and \"c++\" or \"c\")\n    local _, compiler_name = target:tool(sourcekind)\n    local flag_name        = sourcekind == \"cxx\" and \"cxxflags\" or \"cflags\"\n    if compiler_name == \"cl\" then\n        target:add(flag_name, \"/openmp\")\n    elseif compiler_name == \"clang\" or compiler_name == \"clangxx\" then\n        if target:is_plat(\"macosx\") then\n            target:add(flag_name, \"-Xpreprocessor -fopenmp\")\n        else\n            target:add(flag_name, \"-fopenmp\")\n        end\n    elseif compiler_name == \"gcc\" or compiler_name == \"gxx\" then\n        target:add(flag_name, \"-fopenmp\")\n    elseif compiler_name == \"icc\" or compiler_name == \"icpc\" then\n        target:add(flag_name, \"-qopenmp\")\n    elseif compiler_name == \"icl\" then\n        target:add(flag_name, \"-Qopenmp\")\n    end\nend\n"
  },
  {
    "path": "xmake/rules/c++/openmp/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: c.openmp\nrule(\"c.openmp\")\n    on_config(function (target)\n        import(\"load\")(target, \"cc\")\n    end)\n\n-- define rule: c++.openmp\nrule(\"c++.openmp\")\n    on_config(function (target)\n        import(\"load\")(target, \"cxx\")\n    end)\n"
  },
  {
    "path": "xmake/rules/c++/precompiled_header/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"c.build.pcheader\")\n    on_config(function (target, opt)\n        import(\"private.action.build.pcheader\")\n        if not pcheader.config(target, \"c\", opt) then\n            target:rule_enable(\"c.build.pcheader\", false)\n        end\n    end)\n\n    before_build(function (target, jobgraph, opt)\n        if not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            import(\"private.action.build.pcheader\").build(target, jobgraph, \"c\", opt)\n        end\n    end, {jobgraph = true})\n\nrule(\"c++.build.pcheader\")\n    on_config(function (target, opt)\n        import(\"private.action.build.pcheader\")\n        if not pcheader.config(target, \"cxx\", opt) then\n            target:rule_enable(\"c++.build.pcheader\", false)\n        end\n    end)\n\n    -- If the current target has a C++ modules file,\n    -- we can only compile it earlier in the before_prepare stage,\n    -- because the C++ modules will perform a complete dependency scan of\n    -- the C++ files in on_prepare and then build the dependency graph.\n    -- At this time, the pch header file must have already been generated.\n    before_prepare(function (target, jobgraph, opt)\n        local has_modules = target:data(\"cxx.has_modules\")\n        if has_modules and not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            import(\"private.action.build.pcheader\").build(target, jobgraph, \"cxx\", opt)\n        end\n    end, {jobgraph = true})\n\n    -- To enable parallel compilation across targets\n    -- without blocking the compilation of other cpp files,\n    -- we perform this as much as possible during the before_build stage.\n    --\n    -- @see: https://github.com/xmake-io/xmake/issues/4167\n    before_build(function (target, jobgraph, opt)\n        local has_modules = target:data(\"cxx.has_modules\")\n        if not has_modules then\n            import(\"private.action.build.pcheader\").build(target, jobgraph, \"cxx\", opt)\n        end\n    end, {jobgraph = true})\n\n"
  },
  {
    "path": "xmake/rules/c++/unity_build/unity_build.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        unity_build.lua\n--\n\n-- imports\nimport(\"core.project.depend\")\n\nfunction _merge_unityfile(target, sourcefile_unity, sourcefiles, opt)\n    local dependfile = target:dependfile(sourcefile_unity)\n    depend.on_changed(function ()\n\n        -- trace\n        vprint(\"generating.unityfile %s\", sourcefile_unity)\n\n        -- do merge\n        local uniqueid = target:data(\"unity_build.uniqueid\")\n        local unityfile = io.open(sourcefile_unity, \"w\")\n        for _, sourcefile in ipairs(sourcefiles) do\n            sourcefile = path.absolute(sourcefile)\n            sourcefile_unity = path.absolute(sourcefile_unity)\n            sourcefile = path.relative(sourcefile, path.directory(sourcefile_unity))\n            if uniqueid then\n                unityfile:print(\"#define %s %s\", uniqueid, \"unity_\" .. hash.rand64())\n            end\n            unityfile:print(\"#include \\\"%s\\\"\", sourcefile)\n            if uniqueid then\n                unityfile:print(\"#undef %s\", uniqueid)\n            end\n        end\n        unityfile:close()\n\n    end, {dependfile = dependfile, files = sourcefiles, changed = target:is_rebuilt()})\nend\n\nfunction generate_unityfiles(target, sourcebatch, opt)\n    local unity_batch = target:data(\"unity_build.unity_batch.\" .. sourcebatch.rulename)\n    if unity_batch then\n        for _, sourcefile_unity in ipairs(sourcebatch.sourcefiles) do\n            local sourceinfo = unity_batch[sourcefile_unity]\n            if sourceinfo then\n                local sourcefiles = sourceinfo.sourcefiles\n                if sourcefiles then\n                    _merge_unityfile(target, sourcefile_unity, sourcefiles, opt)\n                end\n            end\n        end\n    end\nend\n\n-- use unity build\n--\n-- e.g.\n-- add_rules(\"c++.unity_build\", {batchsize = 2})\n-- add_files(\"src/*.c\", \"src/*.cpp\", {unity_ignored = true})\n-- add_files(\"src/foo/*.c\", {unity_group = \"foo\"})\n-- add_files(\"src/bar/*.c\", {unity_group = \"bar\"})\n--\nfunction main(target, sourcebatch)\n\n    -- we cannot generate unity build files in project generator\n    if os.getenv(\"XMAKE_IN_PROJECT_GENERATOR\") then\n        return\n    end\n\n    -- get unit batch sources\n    local extraconf = target:extraconf(\"rules\", sourcebatch.sourcekind == \"cxx\" and \"c++.unity_build\" or \"c.unity_build\")\n    local batchsize = extraconf and extraconf.batchsize\n    local uniqueid = extraconf and extraconf.uniqueid\n    local id = 1\n    local count = 0\n    local group_id = {}\n    local group_count = {}\n    local unity_batch = {}\n    local sourcefiles = {}\n    local objectfiles = {}\n    local dependfiles = {}\n    local sourcedir = path.join(target:autogendir({root = true}), target:plat(), \"unity_build\")\n    for idx, sourcefile in pairs(sourcebatch.sourcefiles) do\n        local sourcefile_unity\n        local objectfile = sourcebatch.objectfiles[idx]\n        local dependfile = sourcebatch.dependfiles[idx]\n        local fileconfig = target:fileconfig(sourcefile)\n        if fileconfig and fileconfig.unity_group then\n            if fileconfig.batchsize then\n                local curr_group_id = group_id[fileconfig.unity_group] or 1\n                local curr_group_count = group_count[fileconfig.unity_group] or 0\n                if curr_group_count >= fileconfig.batchsize then\n                    curr_group_id = curr_group_id + 1\n                    curr_group_count = 0\n                    group_id[fileconfig.unity_group] = curr_group_id\n                    group_count[fileconfig.unity_group] = curr_group_count\n                end\n                sourcefile_unity = path.join(sourcedir, \"unity_group_\" .. fileconfig.unity_group .. \"_\" .. tostring(curr_group_id) .. path.extension(sourcefile))\n                group_count[fileconfig.unity_group] = curr_group_count + 1\n            else\n                sourcefile_unity = path.join(sourcedir, \"unity_group_\" .. fileconfig.unity_group .. path.extension(sourcefile))\n            end\n        elseif (fileconfig and fileconfig.unity_ignored) or (batchsize and batchsize <= 1) then\n            -- we do not add these files to unity file\n            table.insert(sourcefiles, sourcefile)\n            table.insert(objectfiles, objectfile)\n            table.insert(dependfiles, dependfile)\n        else\n            if batchsize and count >= batchsize then\n                id = id + 1\n                count = 0\n            end\n            sourcefile_unity = path.join(sourcedir, \"unity_\" .. tostring(id) .. path.extension(sourcefile))\n            count = count + 1\n        end\n        if sourcefile_unity then\n            local sourceinfo = unity_batch[sourcefile_unity]\n            if not sourceinfo then\n                sourceinfo = {}\n                sourceinfo.objectfile = target:objectfile(sourcefile_unity)\n                sourceinfo.dependfile = target:dependfile(sourceinfo.objectfile)\n                sourceinfo.sourcefile1 = sourcefile\n                sourceinfo.objectfile1 = objectfile\n                sourceinfo.dependfile1 = dependfile\n                unity_batch[sourcefile_unity] = sourceinfo\n            end\n            sourceinfo.sourcefiles = sourceinfo.sourcefiles or {}\n            table.insert(sourceinfo.sourcefiles, sourcefile)\n        end\n    end\n\n    -- use unit batch\n    for _, sourcefile_unity in ipairs(table.orderkeys(unity_batch)) do\n        local sourceinfo = unity_batch[sourcefile_unity]\n        if #sourceinfo.sourcefiles > 1 then\n            table.insert(sourcefiles, sourcefile_unity)\n            table.insert(objectfiles, sourceinfo.objectfile)\n            table.insert(dependfiles, sourceinfo.dependfile)\n        else\n            table.insert(sourcefiles, sourceinfo.sourcefile1)\n            table.insert(objectfiles, sourceinfo.objectfile1)\n            table.insert(dependfiles, sourceinfo.dependfile1)\n        end\n    end\n    sourcebatch.sourcefiles = sourcefiles\n    sourcebatch.objectfiles = objectfiles\n    sourcebatch.dependfiles = dependfiles\n\n    -- save unit batch\n    target:data_set(\"unity_build.uniqueid\", uniqueid)\n    target:data_set(\"unity_build.unity_batch.\" .. sourcebatch.rulename, unity_batch)\nend\n"
  },
  {
    "path": "xmake/rules/c++/unity_build/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"c.unity_build\")\n    on_config(function (target)\n        import(\"unity_build\")\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches then\n            local sourcebatch = sourcebatches[\"c.build\"]\n            if sourcebatch then\n                unity_build(target, sourcebatch)\n            end\n        end\n    end)\n    before_build(function (target, opt)\n        import(\"unity_build\")\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches then\n            local sourcebatch = sourcebatches[\"c.build\"]\n            if sourcebatch then\n                unity_build.generate_unityfiles(target, sourcebatch, opt)\n            end\n        end\n    end)\n\nrule(\"c++.unity_build\")\n    on_config(function (target)\n        import(\"unity_build\")\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches then\n            local sourcebatch = sourcebatches[\"c++.build\"]\n            if sourcebatch then\n                unity_build(target, sourcebatch)\n            end\n        end\n    end)\n    before_build(function (target, opt)\n        import(\"unity_build\")\n        local sourcebatches = target:sourcebatches()\n        if sourcebatches then\n            local sourcebatch = sourcebatches[\"c++.build\"]\n            if sourcebatch then\n                unity_build.generate_unityfiles(target, sourcebatch, opt)\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/c++/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"c.build\")\n    set_sourcekinds(\"cc\")\n    add_deps(\"c.build.pcheader\")\n    on_config(function (target)\n        import(\"config\")(target, \"cc\")\n    end)\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true, distcc = true})\n\nrule(\"c++.build\")\n    set_sourcekinds(\"cxx\")\n    add_deps(\"c++.build.pcheader\", \"c++.build.modules\")\n    on_config(function (target)\n        import(\"config\")(target, \"cxx\")\n    end)\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true, distcc = true})\n\nrule(\"c\")\n\n    -- add build rules\n    add_deps(\"c.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n    -- add platform rules\n    add_deps(\"platform.wasm\")\n    add_deps(\"platform.windows\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n\nrule(\"c++\")\n\n    -- add build rules\n    add_deps(\"c++.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n    -- add platform rules\n    add_deps(\"platform.wasm\")\n    add_deps(\"platform.windows\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n\n"
  },
  {
    "path": "xmake/rules/c51/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"c51.binary\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"binary\")\n        if not target:get(\"extension\") then\n            target:set(\"extension\", \"\")\n        end\n    end)\n\n    after_link(function(target, opt)\n        import(\"core.project.depend\")\n        import(\"lib.detect.find_tool\")\n        import(\"utils.progress\")\n        depend.on_changed(function()\n            local oh = assert(find_tool(\"oh51\"), \"oh51 not found\")\n            os.iorunv(oh.program, {target:targetfile()})\n            progress.show(opt.progress, \"${color.build.target}generating.$(mode) %s\", target:targetfile() .. \".hex\")\n        end, {files = {target:targetfile()}, changed = target:is_rebuilt()})\n    end)\n"
  },
  {
    "path": "xmake/rules/capnproto/capnp.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      wsw0108\n-- @file        capnp.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\n\n-- get capnp\nfunction _get_capnp(target)\n\n    -- find capnp\n    local capnp = target:data(\"capnproto.capnp\")\n    if not capnp then\n        capnp = find_tool(\"capnp\")\n        if capnp and capnp.program then\n            target:data_set(\"capnproto.capnp\", capnp.program)\n        end\n    end\n\n    -- get capnp\n    return assert(target:data(\"capnproto.capnp\"), \"capnp not found!\")\nend\n\n-- generate build commands\nfunction load(target)\n    -- get the first sourcefile\n    local sourcefile_capnp\n    local sourcebatch = target:sourcebatches()[\"capnproto.cpp\"]\n    if sourcebatch and sourcebatch.sourcefiles then\n        sourcefile_capnp = sourcebatch.sourcefiles[1]\n    end\n    if not sourcefile_capnp then\n        return\n    end\n\n    -- get c/c++ source file for capnproto\n    local prefixdir\n    local public\n    local fileconfig = target:fileconfig(sourcefile_capnp)\n    if fileconfig then\n        public = fileconfig.capnp_public\n        prefixdir = fileconfig.capnp_rootdir\n    end\n    local rootdir = path.join(target:autogendir(), \"rules\", \"capnproto\")\n    local filename = path.basename(sourcefile_capnp) .. \".capnp.c++\"\n    local sourcefile_cx = target:autogenfile(sourcefile_capnp, {rootdir = rootdir, filename = filename})\n    local sourcefile_dir = prefixdir and path.join(rootdir, prefixdir) or path.directory(sourcefile_cx)\n\n    -- add includedirs\n    target:add(\"includedirs\", sourcefile_dir, {public = true})\n\n    -- add objectfile, @see https://github.com/xmake-io/xmake/issues/5426\n    local objectfile = target:objectfile(sourcefile_cx)\n    table.insert(target:objectfiles(), objectfile)\nend\n\n-- generate build commands\nfunction buildcmd(target, batchcmds, sourcefile_capnp, opt)\n    -- get capnp\n    local capnp = _get_capnp(target)\n\n    -- get c/c++ source file for capnproto\n    local prefixdir\n    local public\n    local fileconfig = target:fileconfig(sourcefile_capnp)\n    if fileconfig then\n        public = fileconfig.capnp_public\n        prefixdir = fileconfig.capnp_rootdir\n    end\n    local rootdir = path.join(target:autogendir(), \"rules\", \"capnproto\")\n    local filename = path.basename(sourcefile_capnp) .. \".capnp.c++\"\n    local sourcefile_cx = target:autogenfile(sourcefile_capnp, {rootdir = rootdir, filename = filename})\n    local sourcefile_dir = prefixdir and path.join(rootdir, prefixdir) or path.directory(sourcefile_cx)\n\n    -- add objectfile\n    local objectfile = target:objectfile(sourcefile_cx)\n\n    -- add commands\n    batchcmds:mkdir(sourcefile_dir)\n    batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.capnp %s\", sourcefile_capnp)\n    local capnproto = target:pkg(\"capnproto\")\n    local includes = capnproto:get(\"sysincludedirs\")\n    local argv = {\"compile\"}\n    for _, value in ipairs(includes) do\n        table.insert(argv, path(value, function (p) return \"-I\" .. p end))\n    end\n    table.insert(argv, path(prefixdir and prefixdir or path.directory(sourcefile_capnp), function (p) return \"-I\" .. p end))\n    if prefixdir then\n        table.insert(argv, path(prefixdir, function (p) return \"--src-prefix=\" .. p end))\n    end\n    table.insert(argv, \"-o\")\n    table.insert(argv, path(rootdir, function (p) return \"c++:\" .. p end))\n    table.insert(argv, path(sourcefile_capnp))\n    batchcmds:vrunv(capnp, argv)\n    local configs = {includedirs = sourcefile_dir, languages = (fileconfig and fileconfig.cpp_version) or \"c++14\"}\n    if target:is_plat(\"windows\") then\n        configs.cxflags = \"/TP\"\n    end\n    batchcmds:compile(sourcefile_cx, objectfile, {sourcekind = \"cxx\", configs = configs})\n\n    -- add deps\n    batchcmds:add_depfiles(sourcefile_capnp)\n    batchcmds:set_depmtime(os.mtime(objectfile))\n    batchcmds:set_depcache(target:dependfile(objectfile))\nend\n"
  },
  {
    "path": "xmake/rules/capnproto/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      wsw0108\n-- @file        xmake.lua\n--\n\n-- define rule: capnproto.cpp\nrule(\"capnproto.cpp\")\n    add_deps(\"c++\")\n    set_extensions(\".capnp\")\n    after_load(function (target)\n        return import(\"capnp\").load(target)\n    end)\n    before_buildcmd_file(function (target, batchcmds, sourcefile_capnp, opt)\n        return import(\"capnp\").buildcmd(target, batchcmds, sourcefile_capnp, opt)\n    end)\n"
  },
  {
    "path": "xmake/rules/cppfront/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"cppfront.build.h2\")\n    set_extensions(\".h2\")\n\n    on_buildcmd_file(function (target, batchcmds, sourcefile_h2, opt)\n        import(\"lib.detect.find_tool\")\n        local cppfront = assert(find_tool(\"cppfront\", {check = \"-h\"}), \"cppfront not found!\")\n\n        -- get h header file for h2\n        local sourcefile_h = target:autogenfile((sourcefile_h2:gsub(\".h2$\", \".h\")))\n        local basedir = path.directory(sourcefile_h)\n\n        -- add commands\n        local argv = {\"-o\", path(sourcefile_h), path(sourcefile_h2)}\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.h2 %s\", sourcefile_h2)\n        batchcmds:mkdir(basedir)\n        batchcmds:vrunv(cppfront.program, argv)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_h2)\n        batchcmds:set_depmtime(os.mtime(sourcefile_h))\n        batchcmds:set_depcache(target:dependfile(sourcefile_h))\n    end)\n\nrule(\"cppfront.build.cpp2\")\n    set_extensions(\".cpp2\")\n\n    -- .h2 must compile before .cpp2\n    add_orders(\"cppfront.build.h2\", \"cppfront.build.cpp2\")\n\n    on_load(function (target)\n        -- only cppfront source files? we need to patch cxx source kind for linker\n        local sourcekinds = target:sourcekinds()\n        if #sourcekinds == 0 then\n            table.insert(sourcekinds, \"cxx\")\n        end\n        local cppfront = target:pkg(\"cppfront\")\n        if cppfront and cppfront:installdir() then\n            local includedir = path.join(cppfront:installdir(), \"include\")\n            if os.isdir(includedir) then\n                target:add(\"includedirs\", includedir)\n            end\n        end\n    end)\n    on_buildcmd_file(function (target, batchcmds, sourcefile_cpp2, opt)\n        import(\"lib.detect.find_tool\")\n        local cppfront = assert(find_tool(\"cppfront\", {check = \"-h\"}), \"cppfront not found!\")\n\n        -- get c++ source file for cpp2\n        local sourcefile_cpp = target:autogenfile((sourcefile_cpp2:gsub(\".cpp2$\", \".cpp\")))\n        local basedir = path.directory(sourcefile_cpp)\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_cpp)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add_depfiles for #include \"xxxx/xxxx/xxx.h2\" ,exclude // #include \"xxxx.h2\"\n        local root_dir = path.directory(sourcefile_cpp2)\n        for line in io.lines(sourcefile_cpp2) do\n            local match_h2 = line:match(\"^ -#include *\\\"([%w%p]+.h2)\\\"\")\n            if match_h2 ~= nil then\n                batchcmds:add_depfiles(path.join(root_dir, match_h2))\n            end\n        end\n\n        -- add commands\n        local argv = {\"-o\", path(sourcefile_cpp), path(sourcefile_cpp2)}\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.cpp2 %s\", sourcefile_cpp2)\n        batchcmds:mkdir(basedir)\n        batchcmds:vrunv(cppfront.program, argv)\n        batchcmds:compile(sourcefile_cpp, objectfile, {configs = {languages = \"c++latest\"}})\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_cpp2)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n-- define rule: cppfront\nrule(\"cppfront\")\n    add_deps(\"cppfront.build.h2\")\n    add_deps(\"cppfront.build.cpp2\")\n\n    -- set compiler runtime, e.g. vs runtime\n    add_deps(\"utils.compiler.runtime\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n"
  },
  {
    "path": "xmake/rules/csharp/build.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        target.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.tool.compiler\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\n\n-- build the source files\nfunction build_sourcefiles(target, sourcebatch, opt)\n\n    -- get the target file\n    local targetfile = target:targetfile()\n\n    -- get source files and kind\n    local sourcefiles = sourcebatch.sourcefiles\n    local sourcekind  = sourcebatch.sourcekind\n    local csprojfile  = target:data(\"csharp.csproj\")\n\n    -- get depend file\n    local dependfile = target:dependfile(targetfile)\n\n    -- load compiler\n    local compinst = compiler.load(sourcekind, {target = target})\n\n    -- get compile flags\n    local compflags = compinst:compflags({target = target})\n\n    -- load dependent info\n    local dependinfo = option.get(\"rebuild\") and {} or (depend.load(dependfile) or {})\n\n    -- need build this target?\n    local depvalues = {compinst:program(), compflags}\n    if not depend.is_changed(dependinfo, {lastmtime = os.mtime(targetfile), values = depvalues}) then\n        return\n    end\n\n    -- trace progress info\n    progress.show(opt.progress, \"${color.build.target}linking.$(mode) %s\", path.filename(targetfile))\n\n    -- trace verbose info\n    vprint(compinst:buildcmd(sourcefiles, targetfile, {target = target, compflags = compflags}))\n\n    -- flush io buffer to update progress info\n    io.flush()\n\n    -- build it\n    dependinfo.files = {}\n    assert(compinst:build(sourcefiles, targetfile, {target = target, dependinfo = dependinfo, compflags = compflags}))\n\n    -- update files and values to the dependent file\n    dependinfo.values = depvalues\n    table.join2(dependinfo.files, sourcefiles, csprojfile)\n    depend.save(dependinfo, dependfile)\nend\n\n-- build target\nfunction main(target, opt)\n\n    -- @note only support one source kind!\n    local sourcebatches = target:sourcebatches()\n    if sourcebatches then\n        local sourcebatch = sourcebatches[\"csharp.build\"]\n        if sourcebatch then\n            build_sourcefiles(target, sourcebatch, opt)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/csharp/config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        config.lua\n--\n\n-- imports\nimport(\"core.project.depend\")\nimport(\"generator.csproj\", {rootdir = os.scriptdir(), alias = \"generate_csproj\"})\n\nfunction main(target)\n\n    -- compute csproj path\n    local csprojfile = path.join(target:autogendir(), \"rules\", \"csharp\", target:name() .. \".csproj\")\n    local dependfile = target:dependfile(csprojfile)\n\n    -- collect source files and dep csproj paths as depend values\n    local sourcefiles = target:sourcefiles()\n    local depcsproj = {}\n    for _, dep in ipairs(target:orderdeps()) do\n        local depcsproj_path = dep:data(\"csharp.csproj\")\n        if depcsproj_path then\n            table.insert(depcsproj, depcsproj_path)\n        end\n    end\n\n    -- generate csproj incrementally\n    depend.on_changed(function ()\n        generate_csproj(target, csprojfile)\n    end, {dependfile = dependfile, files = sourcefiles, values = depcsproj})\n\n    target:data_set(\"csharp.csproj\", csprojfile)\n\n    -- add native shared library search paths for P/Invoke\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:is_shared() and not dep:rule(\"csharp.build\") then\n            if is_host(\"windows\") then\n                target:add(\"runenvs\", \"PATH\", dep:targetdir())\n            elseif is_host(\"macosx\") then\n                target:add(\"runenvs\", \"DYLD_LIBRARY_PATH\", dep:targetdir())\n            else\n                target:add(\"runenvs\", \"LD_LIBRARY_PATH\", dep:targetdir())\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/csharp/generator/csproj.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JassJam\n-- @file        csproj.lua\n--\n\n-- imports\nimport(\"properties\")\nimport(\"itemgroups\")\n\n-- escape special xml characters\nfunction _xml_escape(value)\n    value = tostring(value or \"\")\n    value = value:gsub(\"&\", \"&amp;\")\n    value = value:gsub(\"<\", \"&lt;\")\n    value = value:gsub(\">\", \"&gt;\")\n    value = value:gsub(\"\\\"\", \"&quot;\")\n    value = value:gsub(\"'\", \"&apos;\")\n    return value\nend\n\n-- format key-value pairs as xml attributes string, e.g. ` Sdk=\"Microsoft.NET.Sdk\"`\nfunction _format_attributes(attrs)\n    if type(attrs) ~= \"table\" then\n        return \"\"\n    end\n    local keys = {}\n    for key, value in table.orderpairs(attrs) do\n        if value ~= nil and value ~= \"\" then\n            table.insert(keys, key)\n        end\n    end\n    table.sort(keys)\n    if #keys == 0 then\n        return \"\"\n    end\n    local chunks = {}\n    for _, key in ipairs(keys) do\n        table.insert(chunks, string.format(\" %s=\\\"%s\\\"\", key, _xml_escape(attrs[key])))\n    end\n    return table.concat(chunks)\nend\n\n-- get single csharp value from target:values(), with default fallback\nfunction _get_csharp_value(target, name, defaultval)\n    local val = target:values(name)\n    if type(val) == \"table\" then\n        val = val[1]\n    end\n    if val == nil or val == \"\" then\n        return defaultval\n    end\n    return val\nend\n\n-- resolve a registry entry value, supports custom resolve function, list type and single value\nfunction _resolve_registry_value(entry, target, context)\n    if entry.resolve then\n        return entry.resolve(context)\n    end\n    if entry.value_type == \"list\" then\n        local values = table.wrap(target:values(entry.lua_key))\n        if #values == 0 and entry.default ~= nil then\n            values = table.wrap(entry.default)\n        end\n        if #values > 0 then\n            local items = {}\n            for _, value in ipairs(values) do\n                if value ~= nil and value ~= \"\" then\n                    table.insert(items, tostring(value))\n                end\n            end\n            if #items > 0 then\n                return table.concat(items, entry.sep or \";\")\n            end\n        end\n        return nil\n    end\n    return _get_csharp_value(target, entry.lua_key, entry.default)\nend\n\n-- collect <Project> element attributes, e.g. Sdk=\"Microsoft.NET.Sdk\"\nfunction _collect_project_attributes(target, context, registry_entries)\n    local attrs = {}\n    for _, entry in ipairs(registry_entries) do\n        if entry.kind == \"project_attribute\" then\n            if not entry.when or entry.when(context) then\n                local value = _resolve_registry_value(entry, target, context)\n                if value ~= nil and value ~= \"\" then\n                    attrs[entry.attr] = value\n                end\n            end\n        end\n    end\n    return attrs\nend\n\n-- collect <PropertyGroup> entries from registered csharp.* properties\nfunction _collect_property_entries(target, context, registry_entries)\n    local entries = {}\n    for _, entry in ipairs(registry_entries) do\n        if entry.kind == \"property\" then\n            if not entry.when or entry.when(context) then\n                local value = _resolve_registry_value(entry, target, context)\n                if value ~= nil and value ~= \"\" then\n                    table.insert(entries, {xml = entry.xml, value = value})\n                end\n            end\n        end\n    end\n    return entries\nend\n\n-- normalize item entry to {xml, attrs, value} format\nfunction _normalize_item_entry(item, default_xml)\n    if type(item) == \"string\" then\n        return {xml = default_xml, attrs = {Include = item}}\n    elseif type(item) ~= \"table\" then\n        return nil\n    end\n    local xml = item.xml or default_xml\n    if not xml or #tostring(xml) == 0 then\n        return nil\n    end\n    local attrs = item.attrs\n    if type(attrs) ~= \"table\" then\n        attrs = {}\n        for key, value in table.orderpairs(item) do\n            if type(key) == \"string\" and key ~= \"xml\" and key ~= \"value\" and key ~= \"attrs\" then\n                attrs[key] = value\n            end\n        end\n    end\n    return {xml = xml, attrs = attrs, value = item.value}\nend\n\n-- collect <ItemGroup> entries (Compile, ProjectReference, PackageReference, ..)\nfunction _collect_item_groups(context, registry_entries)\n    local groups = {}\n    local groupmap = {}\n    function _group(name)\n        local g = groupmap[name]\n        if not g then\n            g = {name = name, items = {}}\n            groupmap[name] = g\n            table.insert(groups, g)\n        end\n        return g\n    end\n    for _, entry in ipairs(registry_entries) do\n        if entry.kind == \"item\" then\n            if not entry.when or entry.when(context) then\n                for _, item in ipairs(table.wrap(entry.resolve_items and entry.resolve_items(context) or {})) do\n                    local normalized = _normalize_item_entry(item, entry.xml)\n                    if normalized then\n                        table.insert(_group(entry.group or entry.xml).items, normalized)\n                    end\n                end\n            end\n        end\n    end\n    return groups\nend\n\n-- collect custom properties from target:values(\"csharp.properties\")\n-- value format: \"Name=Value\", e.g. set_values(\"csharp.properties\", \"MyProp=value\")\nfunction _collect_custom_property_entries(target)\n    local entries = {}\n    for _, item in ipairs(table.wrap(target:values(\"csharp.properties\"))) do\n        local name, value = tostring(item):match(\"^%s*([^=]+)%s*=(.*)$\")\n        if name and #value > 0 then\n            table.insert(entries, {xml = name:trim(), value = value})\n        end\n    end\n    return entries\nend\n\n-- render <PropertyGroup> section to file\nfunction _render_property_group(file, entries)\n    if #entries == 0 then\n        return\n    end\n    file:print(\"  <PropertyGroup>\")\n    for _, entry in ipairs(entries) do\n        file:print(\"    <%s>%s</%s>\", entry.xml, _xml_escape(entry.value), entry.xml)\n    end\n    file:print(\"  </PropertyGroup>\")\nend\n\n-- render <ItemGroup> sections to file\nfunction _render_item_groups(file, item_groups)\n    for _, group in ipairs(item_groups) do\n        if #group.items > 0 then\n            file:print(\"  <ItemGroup>\")\n            for _, item in ipairs(group.items) do\n                local attrs = _format_attributes(item.attrs)\n                if item.value ~= nil and item.value ~= \"\" then\n                    file:print(\"    <%s%s>%s</%s>\", item.xml, attrs, _xml_escape(item.value), item.xml)\n                else\n                    file:print(\"    <%s%s />\", item.xml, attrs)\n                end\n            end\n            file:print(\"  </ItemGroup>\")\n        end\n    end\nend\n\n-- generate .csproj file for the target, write to tmpfile first then copy if different\nfunction main(target, csprojfile, opt)\n    opt = opt or {}\n\n    local csprojdir = path.directory(csprojfile)\n    local context = {\n        target = target,\n        csprojfile = csprojfile,\n        csprojdir = csprojdir,\n        opt = opt\n    }\n\n    -- collect project properties\n    local property_registry_entries = properties()\n    local item_registry_entries = itemgroups()\n\n    local project_attributes = _collect_project_attributes(target, context, property_registry_entries)\n    local property_entries = _collect_property_entries(target, context, property_registry_entries)\n    local custom_property_entries = _collect_custom_property_entries(target)\n    table.join2(property_entries, custom_property_entries)\n\n    local item_groups = _collect_item_groups(context, item_registry_entries)\n\n    -- generate csproj\n    local tmpfile = os.tmpfile() .. \".csproj\"\n    local file = io.open(tmpfile, \"w\")\n    file:print(\"<Project%s>\", _format_attributes(project_attributes))\n    _render_property_group(file, property_entries)\n    _render_item_groups(file, item_groups)\n    file:print(\"</Project>\")\n    file:close()\n\n    os.mkdir(csprojdir)\n    os.cp(tmpfile, csprojfile, {copy_if_different = true})\n    os.rm(tmpfile)\nend\n"
  },
  {
    "path": "xmake/rules/csharp/generator/itemgroups.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JassJam\n-- @file        itemgroups.lua\n--\n\n-- normalize path to relative and use forward slashes\nfunction _normalize_relative(fromdir, targetpath)\n    local relpath = path.relative(targetpath, fromdir) or targetpath\n    return path.unix(relpath)\nend\n\n-- collect .cs source files as relative paths to csprojdir\nfunction _collect_cs_sourcefiles(context)\n    local csfiles = {}\n    for _, sourcefile in ipairs(context.target:sourcefiles()) do\n        if path.extension(sourcefile):lower() == \".cs\" then\n            local sourceabs = path.is_absolute(sourcefile) and sourcefile or path.absolute(sourcefile, os.projectdir())\n            table.insert(csfiles, _normalize_relative(context.csprojdir, sourceabs))\n        end\n    end\n    table.sort(csfiles)\n    return table.unique(csfiles)\nend\n\n-- collect ProjectReference paths from dependency targets\nfunction _collect_project_references(context)\n    local references = {}\n    for _, dep in ipairs(context.target:orderdeps()) do\n        local depcsproj = dep:data(\"csharp.csproj\")\n        if depcsproj then\n            table.insert(references, _normalize_relative(context.csprojdir, depcsproj))\n        end\n    end\n    table.sort(references)\n    return table.unique(references)\nend\n\n-- extract nuget package name and version from package require string\nfunction _get_nuget_info(pkg)\n    local requirestr = pkg:requirestr() or \"\"\n    local splitinfo = requirestr:trim():split(\"%s+\")\n    if #splitinfo == 0 then\n        return nil\n    end\n\n    local pkgname = splitinfo[1]\n    if pkgname:find(\"::\", 1, true) then\n        pkgname = pkgname:split(\"::\", {plain = true})\n        pkgname = pkgname[#pkgname]\n    end\n    local pkgname_raw = pkgname:match(\"(.-)%[.*%]$\")\n    if pkgname_raw and #pkgname_raw > 0 then\n        pkgname = pkgname_raw\n    end\n    if not pkgname or #pkgname == 0 then\n        return nil\n    end\n\n    local version\n    local versionobj = pkg:version()\n    if versionobj then\n        version = tostring(versionobj)\n    end\n    if not version and #splitinfo > 1 then\n        local require_version = table.concat(table.slice(splitinfo, 2), \" \")\n        if require_version ~= \"latest\" then\n            version = require_version\n        end\n    end\n    return pkgname, version\nend\n\n-- collect PackageReference entries from nuget packages\nfunction _collect_nuget_references(context)\n    local versions = {}\n    for _, pkg in ipairs(context.target:orderpkgs()) do\n        local namespace = pkg:namespace()\n        local requirestr = pkg:requirestr() or \"\"\n        if namespace == \"nuget\" or requirestr:startswith(\"nuget::\") then\n            local pkgname, version = _get_nuget_info(pkg)\n            if pkgname then\n                if version or versions[pkgname] == nil then\n                    versions[pkgname] = version or false\n                end\n            end\n        end\n    end\n\n    local references = {}\n    for pkgname, version in table.orderpairs(versions) do\n        table.insert(references, {name = pkgname, version = version or nil})\n    end\n    table.sort(references, function (a, b) return a.name < b.name end)\n    return references\nend\n\n-- register all item group entries (Compile, ProjectReference, PackageReference)\nfunction main()\n    local entries = {}\n    local function register(entry)\n        table.insert(entries, entry)\n    end\n\n    register({\n        kind = \"item\",\n        group = \"compile\",\n        xml = \"Compile\",\n        resolve_items = function (context)\n            local items = {}\n            for _, sourcefile in ipairs(_collect_cs_sourcefiles(context)) do\n                table.insert(items, {attrs = {Include = sourcefile}})\n            end\n            return items\n        end\n    })\n\n    register({\n        kind = \"item\",\n        group = \"project_reference\",\n        xml = \"ProjectReference\",\n        resolve_items = function (context)\n            local items = {}\n            for _, reffile in ipairs(_collect_project_references(context)) do\n                table.insert(items, {attrs = {Include = reffile}})\n            end\n            return items\n        end\n    })\n\n    register({\n        kind = \"item\",\n        group = \"package_reference\",\n        xml = \"PackageReference\",\n        resolve_items = function (context)\n            local items = {}\n            for _, pkginfo in ipairs(_collect_nuget_references(context)) do\n                local attrs = {Include = pkginfo.name}\n                if pkginfo.version then\n                    attrs.Version = pkginfo.version\n                end\n                table.insert(items, {attrs = attrs})\n            end\n            return items\n        end\n    })\n\n    return entries\nend\n"
  },
  {
    "path": "xmake/rules/csharp/generator/properties.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      JassJam\n-- @file        properties.lua\n--\n\n-- check if target has multi-target frameworks set\nfunction _has_target_frameworks(context)\n    return #table.wrap(context.target:values(\"csharp.target_frameworks\")) > 0\nend\n\n-- get the first element if value is a table\nfunction _first(value)\n    if type(value) == \"table\" then\n        return value[1]\n    end\n    return value\nend\n\n-- get single value from target:values()\nfunction _get_target_value(target, name)\n    return _first(target:values(name))\nend\n\n-- get default target framework from dotnet toolchain sdk version, e.g. \"net8.0\"\nfunction _get_default_target_framework(context)\n    local major\n    local toolchain = context.target:toolchain(\"dotnet\")\n    if toolchain then\n        local sdkver = toolchain:config(\"sdkver\")\n        if sdkver then\n            major = tonumber(tostring(sdkver):match(\"^(%d+)\"))\n        end\n    end\n    return \"net\" .. tostring(major or 8) .. \".0\"\nend\n\n-- resolve target framework from user config or auto-detect from dotnet sdk\nfunction _resolve_target_framework(context)\n    local target_framework = _get_target_value(context.target, \"csharp.target_framework\")\n    if target_framework ~= nil and #tostring(target_framework) > 0 then\n        return target_framework\n    end\n    return _get_default_target_framework(context)\nend\n\n-- resolve assembly name from target basename\nfunction _resolve_assembly_name(context)\n    local basename = context.target:basename()\n    if basename ~= nil and #tostring(basename) > 0 then\n        return basename\n    end\nend\n\n\n-- resolve runtime identifier from user config or auto-detect from target plat/arch\n-- e.g. \"osx-x64\", \"osx-arm64\", \"linux-x64\", \"win-x64\"\n-- register a single-value csharp.* property entry\nfunction _register_property(register, suffix, xml, default, extra)\n    local entry = table.join({\n        kind = \"property\",\n        xml = xml,\n        lua_key = \"csharp.\" .. suffix,\n        default = default\n    }, extra or {})\n    register(entry)\nend\n\n-- register a list-value csharp.* property entry (semicolon-joined)\nfunction _register_list_property(register, suffix, xml, extra)\n    local entry = table.join({\n        kind = \"property\",\n        xml = xml,\n        lua_key = \"csharp.\" .. suffix,\n        value_type = \"list\",\n        sep = \";\"\n    }, extra or {})\n    register(entry)\nend\n\n-- register all csharp property and project attribute entries for csproj generation\nfunction main()\n    local entries = {}\n    function register(entry)\n        table.insert(entries, entry)\n    end\n\n    register({kind = \"project_attribute\", attr = \"Sdk\", lua_key = \"csharp.sdk\", default = \"Microsoft.NET.Sdk\"})\n    register({kind = \"property\", xml = \"OutputType\", resolve = function (context)\n        return context.target:is_binary() and \"Exe\" or \"Library\"\n    end})\n    _register_list_property(register, \"target_frameworks\", \"TargetFrameworks\", {when = _has_target_frameworks})\n    register({kind = \"property\", xml = \"TargetFramework\", resolve = _resolve_target_framework, when = function (context)\n        return not _has_target_frameworks(context)\n    end})\n\n    _register_property(register, \"implicit_usings\", \"ImplicitUsings\", \"enable\")\n    _register_property(register, \"nullable\", \"Nullable\", \"enable\")\n    _register_property(register, \"lang_version\", \"LangVersion\")\n    _register_property(register, \"enable_default_compile_items\", \"EnableDefaultCompileItems\", \"false\")\n    _register_property(register, \"enable_default_embedded_resource_items\", \"EnableDefaultEmbeddedResourceItems\")\n    _register_property(register, \"enable_default_none_items\", \"EnableDefaultNoneItems\")\n    _register_property(register, \"root_namespace\", \"RootNamespace\")\n    register({kind = \"property\", xml = \"AssemblyName\", resolve = _resolve_assembly_name})\n    _register_property(register, \"generate_assembly_info\", \"GenerateAssemblyInfo\")\n    _register_property(register, \"deterministic\", \"Deterministic\")\n    _register_property(register, \"prefer_32bit\", \"Prefer32Bit\")\n    _register_property(register, \"allow_unsafe_blocks\", \"AllowUnsafeBlocks\")\n    _register_property(register, \"check_for_overflow_underflow\", \"CheckForOverflowUnderflow\")\n    _register_property(register, \"analysis_level\", \"AnalysisLevel\")\n    _register_property(register, \"enable_net_analyzers\", \"EnableNETAnalyzers\")\n    _register_property(register, \"enforce_code_style_in_build\", \"EnforceCodeStyleInBuild\")\n    _register_list_property(register, \"warnings_as_errors\", \"WarningsAsErrors\")\n    _register_list_property(register, \"warnings_not_as_errors\", \"WarningsNotAsErrors\")\n    _register_property(register, \"error_log\", \"ErrorLog\")\n    _register_property(register, \"generate_documentation_file\", \"GenerateDocumentationFile\")\n    _register_property(register, \"documentation_file\", \"DocumentationFile\")\n\n    _register_property(register, \"runtime_identifier\", \"RuntimeIdentifier\")\n    _register_list_property(register, \"runtime_identifiers\", \"RuntimeIdentifiers\")\n    _register_property(register, \"self_contained\", \"SelfContained\")\n    _register_property(register, \"use_app_host\", \"UseAppHost\")\n    _register_property(register, \"roll_forward\", \"RollForward\")\n    _register_property(register, \"publish_single_file\", \"PublishSingleFile\")\n    _register_property(register, \"publish_trimmed\", \"PublishTrimmed\")\n    _register_property(register, \"trim_mode\", \"TrimMode\")\n    _register_property(register, \"publish_ready_to_run\", \"PublishReadyToRun\")\n    _register_property(register, \"invariant_globalization\", \"InvariantGlobalization\")\n    _register_property(register, \"include_native_libraries_for_self_extract\", \"IncludeNativeLibrariesForSelfExtract\")\n    _register_property(register, \"enable_compression_in_single_file\", \"EnableCompressionInSingleFile\")\n    _register_property(register, \"publish_aot\", \"PublishAot\")\n    _register_property(register, \"strip_symbols\", \"StripSymbols\")\n    _register_property(register, \"enable_trim_analyzer\", \"EnableTrimAnalyzer\")\n    _register_property(register, \"json_serializer_is_reflection_enabled_by_default\", \"JsonSerializerIsReflectionEnabledByDefault\")\n    _register_list_property(register, \"satellite_resource_languages\", \"SatelliteResourceLanguages\")\n\n    _register_property(register, \"version\", \"Version\")\n    _register_property(register, \"assembly_version\", \"AssemblyVersion\")\n    _register_property(register, \"file_version\", \"FileVersion\")\n    _register_property(register, \"informational_version\", \"InformationalVersion\")\n    _register_property(register, \"package_id\", \"PackageId\")\n    _register_property(register, \"authors\", \"Authors\")\n    _register_property(register, \"company\", \"Company\")\n    _register_property(register, \"product\", \"Product\")\n    _register_property(register, \"description\", \"Description\")\n    _register_property(register, \"copyright\", \"Copyright\")\n    _register_property(register, \"repository_url\", \"RepositoryUrl\")\n    _register_property(register, \"repository_type\", \"RepositoryType\")\n    _register_property(register, \"package_license_expression\", \"PackageLicenseExpression\")\n    _register_property(register, \"package_project_url\", \"PackageProjectUrl\")\n    _register_property(register, \"neutral_language\", \"NeutralLanguage\")\n    _register_property(register, \"enable_preview_features\", \"EnablePreviewFeatures\")\n\n    _register_property(register, \"generate_runtime_configuration_files\", \"GenerateRuntimeConfigurationFiles\")\n    _register_property(register, \"copy_local_lock_file_assemblies\", \"CopyLocalLockFileAssemblies\")\n    _register_property(register, \"append_target_framework_to_output_path\", \"AppendTargetFrameworkToOutputPath\", \"false\")\n    _register_property(register, \"append_runtime_identifier_to_output_path\", \"AppendRuntimeIdentifierToOutputPath\", \"false\")\n    _register_property(register, \"produce_reference_assembly\", \"ProduceReferenceAssembly\")\n    _register_property(register, \"disable_implicit_framework_references\", \"DisableImplicitFrameworkReferences\")\n    _register_property(register, \"generate_target_framework_attribute\", \"GenerateTargetFrameworkAttribute\")\n    return entries\nend\n"
  },
  {
    "path": "xmake/rules/csharp/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.project.config\")\n\n-- get dotnet program\nfunction _get_dotnet(target)\n    return target:tool(\"cs\") or \"dotnet\"\nend\n\n-- get build configuration from mode\nfunction _get_configuration()\n    local mode = config.mode() or \"release\"\n    if mode:lower() == \"debug\" then\n        return \"Debug\"\n    end\n    return \"Release\"\nend\n\n-- get output directory based on target kind\n-- on windows, shared libraries (dll) should also go to bindir\nfunction _get_outputdir(target)\n    if target:is_binary() or (target:is_shared() and target:is_plat(\"windows\", \"mingw\")) then\n        return target:bindir()\n    else\n        return target:libdir()\n    end\nend\n\n-- install csharp target using dotnet publish\nfunction main(target)\n    local installdir = target:installdir()\n    if not installdir then\n        return\n    end\n\n    -- get output directory based on target kind\n    local outputdir = _get_outputdir(target)\n    if not outputdir then\n        return\n    end\n\n    -- run dotnet publish\n    local csprojfile = target:data(\"csharp.csproj\")\n    local argv = {\"publish\"}\n    if csprojfile then\n        table.insert(argv, csprojfile)\n    end\n    table.join2(argv, {\"--nologo\",\n        \"--configuration\", _get_configuration(),\n        \"--output\", outputdir})\n    local dotnet = _get_dotnet(target)\n    os.vrunv(dotnet, argv)\n\n    -- install extra files (add_installfiles)\n    local srcfiles, dstfiles = target:installfiles(installdir)\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            os.vcp(srcfile, dstfiles[idx])\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/csharp/installcmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        installcmd.lua\n--\n\n-- imports\nimport(\"core.project.config\")\n\n-- get dotnet program\nfunction _get_dotnet(target)\n    return target:tool(\"cs\") or \"dotnet\"\nend\n\n-- get build configuration from mode\nfunction _get_configuration()\n    local mode = config.mode() or \"release\"\n    if mode:lower() == \"debug\" then\n        return \"Debug\"\n    end\n    return \"Release\"\nend\n\n-- install csharp target for xpack using dotnet publish\nfunction main(target, batchcmds, opt)\n    local package = opt.package\n    if not package then\n        return\n    end\n\n    local installdir = package:installdir()\n    if not installdir then\n        return\n    end\n\n    -- get output directory based on target kind\n    -- on windows, shared libraries (dll) should also go to bindir\n    local outputdir\n    if target:is_binary() or (target:is_shared() and target:is_plat(\"windows\", \"mingw\")) then\n        outputdir = package:installdir(\"bin\")\n    else\n        outputdir = package:installdir(\"lib\")\n    end\n\n    -- run dotnet publish to a temporary publish directory, then copy to install directory\n    local publishdir = path.join(target:autogendir(), \"rules\", \"csharp\", \"publish\")\n    local csprojfile = target:data(\"csharp.csproj\")\n    local argv = {\"publish\"}\n    if csprojfile then\n        table.insert(argv, csprojfile)\n    end\n    table.join2(argv, {\"--nologo\",\n        \"--configuration\", _get_configuration(),\n        \"--output\", publishdir})\n    local dotnet = _get_dotnet(target)\n    batchcmds:vrunv(dotnet, argv)\n\n    -- copy published files to output directory\n    batchcmds:mkdir(outputdir)\n    batchcmds:cp(path.join(publishdir, \"**\"), outputdir, {rootdir = publishdir})\n\n    -- install extra files (add_installfiles)\n    local srcfiles, dstfiles = target:installfiles(installdir)\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            batchcmds:cp(srcfile, dstfiles[idx])\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/csharp/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- User Configs:\n--\n-- The following `csharp.*` values can be set via `set_values()` in xmake.lua\n-- to customize the auto-generated .csproj file.\n--\n-- e.g.\n--   target(\"example\")\n--       add_rules(\"csharp\")\n--       add_files(\"src/*.cs\")\n--       set_values(\"csharp.target_framework\", \"net8.0\")\n--       set_values(\"csharp.nullable\", \"disable\")\n--       set_values(\"csharp.allow_unsafe_blocks\", \"true\")\n--\n-- Project:\n--   csharp.sdk                                          - Project Sdk (default: Microsoft.NET.Sdk)\n--\n-- General:\n--   csharp.target_framework                             - e.g. \"net8.0\", auto-detected from dotnet sdk if not set\n--   csharp.target_frameworks                            - multi-target, e.g. {\"net8.0\", \"net9.0\"} (list, semicolon-joined)\n--   csharp.implicit_usings                              - ImplicitUsings (default: \"enable\")\n--   csharp.nullable                                     - Nullable (default: \"enable\")\n--   csharp.lang_version                                 - LangVersion, e.g. \"12.0\", \"latest\"\n--   csharp.root_namespace                               - RootNamespace\n--   csharp.enable_default_compile_items                 - EnableDefaultCompileItems (default: \"false\")\n--   csharp.enable_default_embedded_resource_items       - EnableDefaultEmbeddedResourceItems\n--   csharp.enable_default_none_items                    - EnableDefaultNoneItems\n--\n-- Build:\n--   csharp.generate_assembly_info                       - GenerateAssemblyInfo\n--   csharp.deterministic                                - Deterministic\n--   csharp.prefer_32bit                                 - Prefer32Bit\n--   csharp.allow_unsafe_blocks                          - AllowUnsafeBlocks\n--   csharp.check_for_overflow_underflow                 - CheckForOverflowUnderflow\n--\n-- Analysis:\n--   csharp.analysis_level                               - AnalysisLevel\n--   csharp.enable_net_analyzers                         - EnableNETAnalyzers\n--   csharp.enforce_code_style_in_build                  - EnforceCodeStyleInBuild\n--   csharp.warnings_as_errors                           - WarningsAsErrors (list)\n--   csharp.warnings_not_as_errors                       - WarningsNotAsErrors (list)\n--   csharp.error_log                                    - ErrorLog\n--   csharp.generate_documentation_file                  - GenerateDocumentationFile\n--   csharp.documentation_file                           - DocumentationFile\n--\n-- Publish/Runtime:\n--   csharp.runtime_identifier                           - RuntimeIdentifier, e.g. \"win-x64\"\n--   csharp.runtime_identifiers                          - RuntimeIdentifiers (list)\n--   csharp.self_contained                               - SelfContained\n--   csharp.use_app_host                                 - UseAppHost\n--   csharp.roll_forward                                 - RollForward\n--   csharp.publish_single_file                          - PublishSingleFile\n--   csharp.publish_trimmed                              - PublishTrimmed\n--   csharp.trim_mode                                    - TrimMode\n--   csharp.publish_ready_to_run                         - PublishReadyToRun\n--   csharp.invariant_globalization                      - InvariantGlobalization\n--   csharp.include_native_libraries_for_self_extract    - IncludeNativeLibrariesForSelfExtract\n--   csharp.enable_compression_in_single_file            - EnableCompressionInSingleFile\n--   csharp.publish_aot                                  - PublishAot\n--   csharp.strip_symbols                                - StripSymbols\n--   csharp.enable_trim_analyzer                         - EnableTrimAnalyzer\n--   csharp.json_serializer_is_reflection_enabled_by_default - JsonSerializerIsReflectionEnabledByDefault\n--   csharp.satellite_resource_languages                 - SatelliteResourceLanguages (list)\n--\n-- Package Info:\n--   csharp.version                                      - Version\n--   csharp.assembly_version                             - AssemblyVersion\n--   csharp.file_version                                 - FileVersion\n--   csharp.informational_version                        - InformationalVersion\n--   csharp.package_id                                   - PackageId\n--   csharp.authors                                      - Authors\n--   csharp.company                                      - Company\n--   csharp.product                                      - Product\n--   csharp.description                                  - Description\n--   csharp.copyright                                    - Copyright\n--   csharp.repository_url                               - RepositoryUrl\n--   csharp.repository_type                              - RepositoryType\n--   csharp.package_license_expression                   - PackageLicenseExpression\n--   csharp.package_project_url                          - PackageProjectUrl\n--   csharp.neutral_language                             - NeutralLanguage\n--   csharp.enable_preview_features                      - EnablePreviewFeatures\n--\n-- Output:\n--   csharp.generate_runtime_configuration_files         - GenerateRuntimeConfigurationFiles\n--   csharp.copy_local_lock_file_assemblies              - CopyLocalLockFileAssemblies\n--   csharp.append_target_framework_to_output_path       - AppendTargetFrameworkToOutputPath (default: \"false\")\n--   csharp.append_runtime_identifier_to_output_path     - AppendRuntimeIdentifierToOutputPath (default: \"false\")\n--   csharp.produce_reference_assembly                   - ProduceReferenceAssembly\n--   csharp.disable_implicit_framework_references        - DisableImplicitFrameworkReferences\n--   csharp.generate_target_framework_attribute          - GenerateTargetFrameworkAttribute\n--\n-- Custom Properties (for arbitrary csproj properties not listed above):\n--   csharp.properties                                   - add custom <PropertyGroup> entries, format: \"Name=Value\"\n--                                                         e.g. set_values(\"csharp.properties\", \"MyProp=value\", \"AnotherProp=value2\")\n--\nrule(\"csharp.build\")\n    set_sourcekinds(\"cs\")\n    on_load(function (target)\n        -- dotnet always outputs .dll for libraries, and no prefix\n        if target:is_shared() or target:is_static() then\n            target:set(\"prefixname\", \"\")\n            target:set(\"extension\", \".dll\")\n        end\n    end)\n    on_config(\"config\")\n    on_build(\"build\")\n    on_install(\"install\")\n    on_installcmd(\"installcmd\")\n\nrule(\"csharp\")\n    add_deps(\"csharp.build\")\n    add_deps(\"utils.inherit.links\")\n"
  },
  {
    "path": "xmake/rules/cuda/devlink/devlink.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        devlink.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.theme.theme\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"core.tool.linker\")\nimport(\"core.platform.platform\")\nimport(\"utils.progress\")\n\n-- @see https://devblogs.nvidia.com/separate-compilation-linking-cuda-device-code/\nfunction main(target, opt)\n\n    -- disable devlink?\n    --\n    -- @note cuda.build.devlink value will be deprecated\n    --\n    local devlink = target:policy(\"build.cuda.devlink\") or target:values(\"cuda.build.devlink\")\n    if devlink == false then\n        return\n    end\n\n    -- only for binary/shared by default\n    -- https://github.com/xmake-io/xmake/issues/1976\n    if not (devlink == true or target:is_binary() or target:is_shared()) then\n        return\n    end\n\n    -- load linker instance\n    local linkinst = linker.load(\"gpucode\", \"cu\", {target = target})\n\n    -- init culdflags\n    local culdflags = {\"-dlink\"}\n\n    -- add shared flag\n    if target:is_shared() then\n        table.insert(culdflags, \"-shared\")\n    end\n\n    -- get link flags\n    local linkflags = linkinst:linkflags({target = target, configs = {force = {culdflags = culdflags}}})\n\n    -- get target file\n    local targetfile = target:objectfile(path.join(\"rules\", \"cuda\", \"devlink\", target:basename() .. \"_gpucode.cu\"))\n\n    -- get object files\n    local objectfiles = nil\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        if sourcebatch.sourcekind == \"cu\" then\n            objectfiles = sourcebatch.objectfiles\n        end\n    end\n    if not objectfiles then\n        return\n    end\n\n    -- insert gpucode.o to the object files\n    table.insert(target:objectfiles(), targetfile)\n\n    -- need build this target?\n    local depfiles = objectfiles\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:kind() == \"static\" then\n            if depfiles == objectfiles then\n                depfiles = table.copy(objectfiles)\n            end\n            table.insert(depfiles, dep:targetfile())\n        end\n    end\n    local dryrun = option.get(\"dry-run\")\n    local depvalues = {linkinst:program(), linkflags}\n    depend.on_changed(function ()\n\n        -- is verbose?\n        local verbose = option.get(\"verbose\")\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.target}devlinking.$(mode) %s\", path.filename(targetfile))\n\n        -- trace verbose info\n        if verbose then\n            -- show the full link command with raw arguments, it will expand @xxx.args for msvc/link on windows\n            print(linkinst:linkcmd(objectfiles, targetfile, {linkflags = linkflags, rawargs = true}))\n        end\n\n        -- link it\n        if not dryrun then\n            assert(linkinst:link(objectfiles, targetfile, {linkflags = linkflags}))\n        end\n\n    end, {dependfile = target:dependfile(targetfile),\n          lastmtime = os.mtime(targetfile),\n          changed = target:is_rebuilt(),\n          values = depvalues, files = depfiles, dryrun = dryrun})\nend\n"
  },
  {
    "path": "xmake/rules/cuda/devlink/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- device link\n-- @see https://devblogs.nvidia.com/separate-compilation-linking-cuda-device-code/\nrule(\"cuda.build.devlink\")\n    add_deps(\"cuda.env\")\n    before_link(\"devlink\")\n\n"
  },
  {
    "path": "xmake/rules/cuda/env/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"cuda.env\")\n\n    on_load(function (target)\n        import(\"detect.sdks.find_cuda\")\n        local cuda = assert(find_cuda(nil, {verbose = true}), \"Cuda SDK not found!\")\n        if cuda then\n            target:data_set(\"cuda\", cuda)\n        end\n    end)\n\n    after_load(function (target)\n        import(\"core.platform.platform\")\n\n        -- get cuda sdk\n        local cuda = assert(target:data(\"cuda\"), \"Cuda SDK not found!\")\n\n        -- add arch\n        if target:is_arch(\"i386\", \"x86\") then\n            target:add(\"cuflags\", \"-m32\", {force = true})\n            target:add(\"culdflags\", \"-m32\", {force = true})\n        else\n            target:add(\"cuflags\", \"-m64\", {force = true})\n            target:add(\"culdflags\", \"-m64\", {force = true})\n        end\n\n        -- add rdc, @see https://github.com/xmake-io/xmake/issues/1975\n        if target:values(\"cuda.rdc\") ~= false then\n            target:add(\"cuflags\", \"-rdc=true\")\n        end\n\n        -- add links\n        target:add(\"syslinks\", \"cudadevrt\")\n        local cudart = false\n        for _, link in ipairs(table.join(target:get(\"links\") or {}, target:get(\"syslinks\"))) do\n            if link == \"cudart\" or link == \"cudart_static\" then\n                cudart = true\n                break\n            end\n        end\n        if not cudart then\n            target:add(\"syslinks\", \"cudart_static\")\n        end\n        if target:is_plat(\"linux\") then\n            target:add(\"syslinks\", \"rt\", \"pthread\", \"dl\")\n        end\n        target:add(\"linkdirs\", cuda.linkdirs)\n        target:add(\"rpathdirs\", cuda.linkdirs)\n\n        -- add includedirs\n        target:add(\"includedirs\", cuda.includedirs)\n    end)\n\n    before_run(function (target)\n        import(\"core.project.config\")\n        import(\"lib.detect.find_tool\")\n\n        local debugger = config.get(\"debugger\")\n        if not debugger then\n            local cudagdb = find_tool(\"cudagdb\")\n            if cudagdb then\n                config.set(\"debugger\", cudagdb.program)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/cuda/gencodes/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: gencodes\nrule(\"cuda.gencodes\")\n\n    -- add cuda `-gencode` flags to target\n    --\n    -- the gpu arch format syntax\n    -- - compute_xx                   --> `-gencode arch=compute_xx,code=compute_xx`\n    -- - sm_xx                        --> `-gencode arch=compute_xx,code=sm_xx`\n    -- - sm_xx,sm_yy                  --> `-gencode arch=compute_xx,code=[sm_xx,sm_yy]`\n    -- - compute_xx,sm_yy             --> `-gencode arch=compute_xx,code=sm_yy`\n    -- - compute_xx,sm_yy,sm_zz       --> `-gencode arch=compute_xx,code=[sm_yy,sm_zz]`\n    -- - native                       --> match the fastest cuda device on current host,\n    --                                    eg. for a Tesla P100, `-gencode arch=compute_60,code=sm_60` will be added,\n    --                                    if no available device is found, no `-gencode` flags will be added\n    --                                    @seealso xmake/modules/lib/detect/find_cudadevices\n    --\n    on_config(function (target)\n\n        -- imports\n        import(\"core.platform.platform\")\n        import(\"lib.detect.find_cudadevices\")\n        import(\"core.base.hashset\")\n\n        -- sm_20 and compute_20 is supported until CUDA 8\n        -- sm_30 and compute_30 is supported until CUDA 10\n        -- sm_37 and compute_37 is supported until CUDA 11\n        -- sm_72 and compute_72 is supported until CUDA 12\n        local known_v_archs = hashset.of(20, 30, 32, 35, 37, 50, 52, 53, 60, 61, 62, 70, 72, 75, 80, 86, 87, 89, 90, 100, 103, 110, 120, 121)\n        local known_r_archs = hashset.of(20, 30, 32, 35, 37, 50, 52, 53, 60, 61, 62, 70, 72, 75, 80, 86, 87, 89, 90, 100, 103, 110, 120, 121)\n\n        local function nf_cugencode(archs)\n            if type(archs) ~= \"string\" then\n                return nil\n            end\n            archs = archs:trim():lower()\n            if archs == \"native\" then\n                local cuda_envs\n                for _, toolchain_inst in ipairs(target:toolchains()) do\n                    if toolchain_inst:name() == \"cuda\" then\n                        cuda_envs = toolchain_inst:runenvs()\n                        break\n                    end\n                end\n                local device = find_cudadevices({skip_compute_mode_prohibited = true, order_by_flops = true, envs = cuda_envs, plat = target:plat(), arch = target:arch()})[1]\n                if device then\n                    return nf_cugencode(\"sm_\" .. device.major .. device.minor)\n                end\n                return nil\n            end\n\n            local v_arch = nil\n            local r_archs = {}\n\n            -- full legal value list could be found in nvcc docs\n            -- https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#gpu-name-gpuname-arch\n            -- examples: sm_75, compute_75, sm_90a, compute_100, sm_100f, compute_100a, etc.\n            -- For robustness, xmake support a unoffical format: sm75, compute75, etc. New version still support it.\n            -- examples: sm75, compute75, sm90a, compute100, sm100f, compute100a, etc.\n            local function parse_arch(value, prefix, know_list)\n                if not value:startswith(prefix) then\n                    return nil\n                end\n                local arch_str = value:sub(#prefix + 1)\n                if arch_str:startswith(\"_\") then\n                    arch_str = arch_str:sub(2)\n                end\n\n                -- a legal arch_str should be like: 75, 90a, 100f, etc.\n                local arch_ver, suffix = arch_str:match(\"^(%d+)([af]?)$\")\n                local arch = tonumber(arch_ver)\n                if arch == nil then\n                    raise(\"unknown architecture: \" .. value)\n                end\n                if suffix == 'a' and arch < 90 then\n                    raise(\"unknown architecture: \" .. prefix .. \"_\" .. arch .. suffix)\n                end\n                if suffix == 'f' and arch < 100 then\n                    raise(\"unknown architecture: \" .. prefix .. \"_\" .. arch .. suffix)\n                end\n                if not know_list:has(arch) then\n                    if arch <= table.maxn(know_list:data()) then\n                        raise(\"unknown architecture: \" .. prefix .. \"_\" .. arch)\n                    else\n                        utils.warning(\"unknown architecture: \" .. prefix .. \"_\" .. arch)\n                    end\n                end\n                if suffix and #suffix > 0 then\n                    return arch .. suffix\n                end\n                return arch\n            end\n\n            for _, v in ipairs(archs:split(',')) do\n                local arch = v:trim()\n                local temp_r_arch = parse_arch(arch, \"sm\", known_r_archs)\n                if temp_r_arch then\n                    table.insert(r_archs, temp_r_arch)\n                end\n\n                local temp_v_arch = parse_arch(arch, \"compute\", known_v_archs)\n                if temp_v_arch then\n                    if v_arch ~= nil then\n                        raise(\"more than one virtual architecture is defined in one gpu gencode option: compute_\" .. v_arch .. \" and compute_\" .. temp_v_arch)\n                    end\n                    v_arch = temp_v_arch\n                end\n                if not (temp_r_arch or temp_v_arch) then\n                    raise(\"unknown architecture: \" .. arch)\n                end\n            end\n\n            if v_arch == nil and #r_archs == 0 then\n                return nil\n            end\n\n            if #r_archs == 0 then\n                return {\n                    clang = \"--cuda-gpu-arch=sm_\" .. v_arch,\n                    nvcc = \"-gencode arch=compute_\" .. v_arch .. \",code=compute_\" .. v_arch\n                }\n            end\n\n            if v_arch then\n                table.insert(r_archs, v_arch)\n            else\n                v_arch = r_archs[1]\n                local v_arch_ver = type(v_arch) == \"string\" and tonumber(v_arch:match(\"^(%d+)\")) or v_arch\n                for i = 2, #r_archs do\n                    local r_arch = r_archs[i]\n                    local r_arch_ver = type(r_arch) == \"string\" and tonumber(r_arch:match(\"^(%d+)\")) or r_arch\n                    if r_arch_ver < v_arch_ver then\n                        v_arch = r_arch\n                        v_arch_ver = r_arch_ver\n                    elseif r_arch_ver == v_arch_ver and type(r_arch) == \"number\" and type(v_arch) == \"string\" then\n                        v_arch = r_arch\n                    end\n                end\n            end\n            r_archs = table.unique(r_archs)\n\n            local clang_flags = {}\n            for _, r_arch in ipairs(r_archs) do\n                table.insert(clang_flags, \"--cuda-gpu-arch=sm_\" .. r_arch)\n            end\n\n            local nvcc_flags = nil\n            if #r_archs == 1 then\n                nvcc_flags = \"-gencode arch=compute_\" .. v_arch .. \",code=sm_\" .. r_archs[1]\n            else\n                nvcc_flags = \"-gencode arch=compute_\" .. v_arch .. \",code=[sm_\" .. table.concat(r_archs, \",sm_\") .. \"]\"\n            end\n\n            return { clang = clang_flags, nvcc = nvcc_flags }\n        end\n\n        local cugencodes = table.wrap(target:get(\"cugencodes\"))\n        for _, opt in ipairs(target:orderopts()) do\n            table.join2(cugencodes, opt:get(\"cugencodes\"))\n        end\n        for _, v in ipairs(cugencodes) do\n            local flag = nf_cugencode(v)\n            if flag then\n                if target:has_tool(\"cu\", \"nvcc\") then\n                    target:add(\"cuflags\", flag.nvcc)\n                else\n                    target:add(\"cuflags\", flag.clang)\n                end\n                target:add(\"culdflags\", flag.nvcc)\n            end\n        end\n    end)\nrule_end()\n"
  },
  {
    "path": "xmake/rules/cuda/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: cuda.build\nrule(\"cuda.build\")\n    set_sourcekinds(\"cu\")\n    add_deps(\"cuda.build.devlink\")\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n    on_config(function (target)\n        -- https://github.com/xmake-io/xmake/issues/4755\n        local cu_ccbin = target:tool(\"cu-ccbin\")\n        if cu_ccbin then\n            target:add(\"cuflags\", \"-ccbin=\" .. os.args(cu_ccbin), {force = true})\n            target:add(\"culdflags\", \"-ccbin=\" .. os.args(cu_ccbin), {force = true})\n        end\n    end)\n\n-- define rule: cuda\nrule(\"cuda\")\n\n    -- add build rules\n    add_deps(\"cuda.build\", \"cuda.gencodes\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n"
  },
  {
    "path": "xmake/rules/dlang/build_optimization/config.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        config.lua\n--\n\n-- imports\nimport(\"core.tool.compiler\")\nimport(\"core.project.project\")\n\n-- add lto optimization\nfunction _add_lto_optimization(target)\n    if target:has_tool(\"dc\", \"ldc2\") and target:has_tool(\"dcld\", \"ldc2\") then\n        target:add(\"dcflags\", \"-flto=thin\", {force = true})\n        target:add(\"ldflags\", \"-flto=thin\", \"-defaultlib=phobos2-ldc-lto,druntime-ldc-lto\", {force = true})\n        target:add(\"shflags\", \"-flto=thin\", \"-defaultlib=phobos2-ldc-lto,druntime-ldc-lto\", {force = true})\n        -- to use the link-time optimizer, lto and optimization options should be specified at compile time and during the final link.\n        -- @see https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html\n        local optimize = target:get(\"optimize\")\n        if optimize then\n            local optimize_flags = compiler.map_flags(\"d\", \"optimize\", optimize)\n            target:add(\"ldflags\", optimize_flags)\n            target:add(\"shflags\", optimize_flags)\n        end\n    end\nend\n\nfunction main(target)\n    if target:policy(\"build.optimization.lto\") or\n        project.policy(\"build.optimization.lto\") then\n        _add_lto_optimization(target)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/dlang/build_optimization/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: dlang.build.optimization\nrule(\"dlang.build.optimization\")\n    on_config(\"config\")\n\n"
  },
  {
    "path": "xmake/rules/dlang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"dlang.build\")\n    set_sourcekinds(\"dc\")\n    add_deps(\"dlang.build.optimization\")\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n    on_load(function (target)\n        local toolchains = target:get(\"toolchains\") or get_config(\"toolchain\")\n        if not toolchains or not table.contains(table.wrap(toolchains), \"dlang\", \"dmd\", \"ldc\", \"gdc\") then\n            target:add(\"toolchains\", \"dlang\")\n        end\n    end)\n\nrule(\"dlang\")\n\n    -- add build rules\n    add_deps(\"dlang.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n\n"
  },
  {
    "path": "xmake/rules/fortran/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: fortran.build.modules\nrule(\"fortran.build.modules\")\n    before_build(function (target)\n        if target:has_tool(\"fc\", \"gfortran\") then\n            local modulesdir = target:values(\"fortran.moduledir\") or path.join(target:objectdir(), \".modules\")\n            os.mkdir(modulesdir)\n            target:add(\"fcflags\", \"-J\" .. modulesdir)\n            target:add(\"includedirs\", modulesdir, {public = true})\n        end\n    end)\n\n-- define rule: fortran.build\nrule(\"fortran.build\")\n    set_sourcekinds(\"fc\")\n    add_deps(\"fortran.build.modules\")\n    on_load(function (target)\n        -- we disable to build across targets in parallel, because the source files may depend on other target modules\n        target:set(\"policy\", \"build.fence\", true)\n    end)\n    on_build_files(function (target, sourcebatch, opt)\n        import(\"private.action.build.object\").build(target, sourcebatch, opt)\n    end)\n\n-- define rule: fortran\nrule(\"fortran\")\n\n    -- add build rules\n    add_deps(\"fortran.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n"
  },
  {
    "path": "xmake/rules/gnu-rm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Jacob\n-- @file        xmake.lua\n--\n\nrule(\"gnu-rm.binary\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"binary\")\n        if not target:get(\"extension\") then\n            target:set(\"extension\", \".elf\")\n        end\n    end)\n\nrule(\"gnu-rm.static\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"static\")\n    end)\n\nrule(\"gnu-rm.shared\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"shared\")\n    end)\n\nrule(\"gnu-rm.object\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"object\")\n    end)\n\n"
  },
  {
    "path": "xmake/rules/go/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"go.build\")\n    set_sourcekinds(\"gc\")\n    on_load(function (target)\n        -- we disable to build across targets in parallel, because the source files may depend on other target modules\n        target:set(\"policy\", \"build.fence\", true)\n        -- xxx.a\n        if target:is_static() then\n            target:set(\"prefixname\", \"\")\n        end\n    end)\n    on_build(\"build.target\")\n\nrule(\"go\")\n    add_deps(\"go.build\")\n    add_deps(\"utils.inherit.links\")\n"
  },
  {
    "path": "xmake/rules/iverilog/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- @see https://github.com/xmake-io/xmake/issues/3257\nrule(\"iverilog.binary\")\n    set_extensions(\".v\", \".sv\", \".vhd\")\n    on_load(function (target)\n        target:set(\"kind\", \"binary\")\n        if not target:get(\"extension\") then\n            target:set(\"extension\", \".vvp\")\n        end\n    end)\n\n    on_buildcmd_files(function(target, batchcmds, sourcebatch, opt)\n    end)\n\n    on_linkcmd(function (target, batchcmds, opt)\n        local toolchain = assert(target:toolchain(\"iverilog\"), 'we need set_toolchains(\"iverilog\") in target(\"%s\")', target:name())\n        local iverilog = assert(toolchain:config(\"iverilog\"), \"iverilog not found!\")\n\n        local targetfile = target:targetfile()\n        local targetdir = path.directory(targetfile)\n        local argv = {\"-o\", targetfile}\n        local sourcebatch = target:sourcebatches()[\"iverilog.binary\"]\n        local sourcefiles = table.wrap(sourcebatch.sourcefiles)\n        assert(#sourcefiles > 0, \"no source files!\")\n\n        -- get languages\n        --\n        -- Select the Verilog language generation to support in the compiler.\n        -- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012.\n        --\n        local language_v\n        local languages = target:get(\"languages\")\n        if languages then\n            for _, language in ipairs(languages) do\n                if language:startswith(\"v\") then\n                    language_v = language\n                    break\n                end\n            end\n        end\n        if language_v then\n            local maps = {\n                [\"v1364-1995\"] = \"-g1995\",\n                [\"v1364-2001\"] = \"-g2001\",\n                [\"v1364-2005\"] = \"-g2005\",\n                [\"v1800-2005\"] = \"-g2005-sv\",\n                [\"v1800-2009\"] = \"-g2009\",\n                [\"v1800-2012\"] = \"-g2012\",\n            }\n            local flag = maps[language_v]\n            if flag then\n                table.insert(argv, flag)\n            else\n                assert(\"unknown language(%s) for iverilog!\", language_v)\n            end\n        else\n            local extension = path.extension(sourcefiles[1])\n            if extension == \".vhd\" then\n                table.insert(argv, \"-g2012\")\n            end\n        end\n\n        -- get defines\n        for _, define in ipairs((target:get_from(\"defines\", \"*\"))) do\n            table.insert(argv, \"-D\" .. define)\n        end\n\n        -- get includedirs\n        local includedirs = target:get(\"includedirs\")\n        if includedirs then\n            for _, includedir in ipairs(includedirs) do\n                table.insert(argv, path(includedir, function (v) return \"-I\" .. v end))\n            end\n        end\n\n        -- get flags\n        local flags = target:values(\"iverilog.flags\")\n        if flags then\n            table.join2(argv, flags)\n        end\n\n        -- do build\n        table.join2(argv, sourcefiles)\n        batchcmds:show_progress(opt.progress, \"${color.build.target}linking.iverilog %s\", path.filename(targetfile))\n        batchcmds:mkdir(targetdir)\n        batchcmds:vrunv(iverilog, argv)\n        batchcmds:add_depfiles(sourcefiles)\n        batchcmds:set_depmtime(os.mtime(targetfile))\n        batchcmds:set_depcache(target:dependfile(targetfile))\n    end)\n\n    on_run(function (target)\n        local toolchain = assert(target:toolchain(\"iverilog\"), 'we need set_toolchains(\"iverilog\") in target(\"%s\")', target:name())\n        local vvp = assert(toolchain:config(\"vvp\"), \"vvp not found!\")\n        os.execv(vvp, {\"-n\", target:targetfile()})\n    end)\n"
  },
  {
    "path": "xmake/rules/kotlin-native/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"kotlin-native.build\")\n    set_sourcekinds(\"kc\")\n    on_load(function (target)\n        target:add(\"kcflags\", \"-opt-in=kotlinx.cinterop.ExperimentalForeignApi\", {force = true})\n        if target:is_static() then\n            target:add(\"arflags\", {\"-produce\", \"static\"}, {force = true})\n            target:add(\"includedirs\", target:targetdir(), {interface = true})\n            target:add(\"kcflags\", \"-opt-in=kotlin.experimental.ExperimentalNativeApi\", {force = true})\n            if target:is_plat(\"macosx\") then\n                target:add(\"frameworks\", \"Foundation\", \"CoreFoundation\", {interface = true})\n            elseif target:is_plat(\"mingw\") then\n                target:add(\"syslinks\", \"pthread\", {interface = true})\n            end\n        elseif target:is_shared() then\n            target:add(\"shflags\", {\"-produce\", \"dynamic\"}, {force = true})\n            target:add(\"kcflags\", \"-opt-in=kotlin.experimental.ExperimentalNativeApi\", {force = true})\n            target:add(\"includedirs\", target:targetdir(), {interface = true})\n        end\n        target:set(\"policy\", \"build.fence\", true)\n    end)\n    on_build(\"build.target\")\n\nrule(\"kotlin-native\")\n    add_deps(\"kotlin-native.build\")\n    add_deps(\"utils.inherit.links\")\n"
  },
  {
    "path": "xmake/rules/lex_yacc/lex/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: lex\nrule(\"lex\")\n    add_deps(\"c++\")\n    add_orders(\"yacc\", \"lex\")\n    set_extensions(\".l\", \".ll\")\n    before_buildcmd_file(function (target, batchcmds, sourcefile_lex, opt)\n\n        -- get lex\n        import(\"lib.detect.find_tool\")\n        local lex = assert(find_tool(\"flex\") or find_tool(\"lex\"), \"lex not found!\")\n\n        -- get c/c++ source file for lex\n        local extension = path.extension(sourcefile_lex)\n        local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"lex_yacc\", path.basename(sourcefile_lex) .. (extension == \".ll\" and \".cpp\" or \".c\"))\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.lex %s\", sourcefile_lex)\n        batchcmds:mkdir(path.directory(sourcefile_cx))\n        batchcmds:vrunv(lex.program, {\"-o\", path(sourcefile_cx), path(sourcefile_lex)})\n        batchcmds:compile(sourcefile_cx, objectfile)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_lex)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/lex_yacc/yacc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: yacc\nrule(\"yacc\")\n    add_deps(\"c++\")\n    set_extensions(\".y\", \".yy\")\n    on_load(function (target)\n        -- add yacc includedirs if there are yacc files\n        -- @see https://github.com/xmake-io/xmake/issues/4820\n        if target:sourcebatches()[\"yacc\"] then\n            local sourcefile_dir = path.join(target:autogendir(), \"rules\", \"yacc_yacc\")\n            target:add(\"includedirs\", sourcefile_dir)\n        end\n    end)\n    before_buildcmd_file(function (target, batchcmds, sourcefile_yacc, opt)\n\n        -- get yacc\n        import(\"lib.detect.find_tool\")\n        local yacc = assert(find_tool(\"bison\") or find_tool(\"yacc\"), \"yacc/bison not found!\")\n\n        -- get c/c++ source file for yacc\n        local extension = path.extension(sourcefile_yacc)\n        local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"yacc_yacc\", path.basename(sourcefile_yacc) .. \".tab\" .. (extension == \".yy\" and \".cpp\" or \".c\"))\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add includedirs\n        local sourcefile_dir = path.directory(sourcefile_cx)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.yacc %s\", sourcefile_yacc)\n        batchcmds:mkdir(sourcefile_dir)\n        batchcmds:vrunv(yacc.program, {\"-d\", \"-o\", path(sourcefile_cx), path(sourcefile_yacc)})\n        batchcmds:compile(sourcefile_cx, objectfile)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_yacc)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/linker/link_scripts/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"linker.link_scripts\")\n    set_extensions(\".ld\", \".lds\")\n    on_config(function (target)\n        if not target:is_binary() and not target:is_shared() then\n            return\n        end\n        local sourcebatch = target:sourcebatches()[\"linker.link_scripts\"]\n        if not sourcebatch or not sourcebatch.sourcefiles or #sourcebatch.sourcefiles == 0 then\n            return\n        end\n\n        -- @note apple's linker does not support it\n        if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n            return\n        end\n\n        -- Check for supported linkers (GNU and LLVM linkers support multiple -T flags)\n        if target:has_tool(\"ld\", \"gcc\", \"gxx\", \"clang\", \"clangxx\", \"ld\") or\n            target:has_tool(\"sh\", \"gcc\", \"gxx\", \"clang\", \"clangxx\", \"ld\") then\n\n            -- Add all linker scripts with -T flag\n            -- https://github.com/xmake-io/xmake/issues/7227\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                target:add(target:is_shared() and \"shflags\" or \"ldflags\", \"-T \" .. sourcefile, {force = true})\n                target:data_add(\"linkdepfiles\", sourcefile)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/linker/soname/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"linker.soname\")\n    on_config(function (target)\n        local enabled = false\n        local soname = target:soname()\n        if target:is_shared() and soname then\n            if target:has_tool(\"sh\", \"gcc\", \"gxx\", \"clang\", \"clangxx\") then\n                if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n                    target:add(\"shflags\", \"-Wl,-install_name,@rpath/\" .. soname, {force = true})\n                else\n                    target:add(\"shflags\", \"-Wl,-soname,\" .. soname, {force = true})\n                end\n                enabled = true\n            end\n        end\n        if not enabled then\n            target:rule_enable(\"linker.soname\", false)\n        end\n    end)\n\n    after_link(function (target)\n        import(\"core.project.depend\")\n        local soname = target:soname()\n        if target:is_shared() and soname then\n            local version = target:version()\n            local filename = target:filename()\n            local extension = path.extension(filename)\n            local targetfile_with_version = path.join(target:targetdir(), filename .. \".\" .. version)\n            if extension == \".dylib\" then\n                targetfile_with_version = path.join(target:targetdir(), path.basename(filename) .. \".\" .. version .. extension)\n            end\n            local targetfile_with_soname = path.join(target:targetdir(), soname)\n            local targetfile = target:targetfile()\n            if soname ~= filename and soname ~= path.filename(targetfile_with_version) then\n                depend.on_changed(function ()\n                    os.cp(target:targetfile(), targetfile_with_version)\n                    os.rm(target:targetfile())\n                    local oldir = os.cd(target:targetdir())\n                    os.ln(path.filename(targetfile_with_version), soname, {force = true})\n                    os.ln(soname, path.filename(targetfile), {force = true})\n                    os.cd(oldir)\n                end, {dependfile = target:dependfile(targetfile_with_version),\n                      files = {target:targetfile()},\n                      values = {soname, version},\n                      changed = target:is_rebuilt()})\n            end\n        end\n    end)\n\n    after_clean(function (target)\n        import(\"private.action.clean.remove_files\")\n        local soname = target:soname()\n        if target:is_shared() and soname then\n            local version = target:version()\n            local filename = target:filename()\n            local extension = path.extension(filename)\n            local targetfile_with_version = path.join(target:targetdir(), filename .. \".\" .. version)\n            if extension == \".dylib\" then\n                targetfile_with_version = path.join(target:targetdir(), path.basename(filename) .. \".\" .. version .. extension)\n            end\n            local targetfile_with_soname = path.join(target:targetdir(), soname)\n            remove_files(targetfile_with_soname)\n            remove_files(targetfile_with_version)\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/linker/version_scripts/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"linker.version_scripts\")\n    set_extensions(\".ver\", \".map\")\n    on_config(function (target)\n        if not target:is_binary() and not target:is_shared() then\n            return\n        end\n        local scriptfile\n        local sourcebatch = target:sourcebatches()[\"linker.version_scripts\"]\n        if sourcebatch then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                scriptfile = sourcefile\n                break\n            end\n        end\n        if not scriptfile then\n            return\n        end\n        -- @note apple's linker does not support it\n        if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n            return\n        end\n        -- @note Solaris linker does not support --version-script\n        if target:is_plat(\"solaris\") then\n            return\n        end\n        if target:has_tool(\"ld\", \"gcc\", \"gxx\", \"clang\", \"clangxx\") or\n            target:has_tool(\"sh\", \"gcc\", \"gxx\", \"clang\", \"clangxx\") then\n            target:add(target:is_shared() and \"shflags\" or \"ldflags\", \"-Wl,--version-script=\" .. scriptfile, {force = true})\n        elseif target:has_tool(\"ld\", \"dmd\") or target:has_tool(\"sh\", \"dmd\") then\n            target:add(target:is_shared() and \"shflags\" or \"ldflags\", \"-L--version-script=\" .. scriptfile, {force = true})\n        elseif target:has_tool(\"ld\", \"ld\") or target:has_tool(\"sh\", \"ld\") then\n            target:add(target:is_shared() and \"shflags\" or \"ldflags\", \"--version-script=\" .. scriptfile, {force = true})\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/linker/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"linker\")\n    add_deps(\"linker.link_scripts\")\n    add_deps(\"linker.version_scripts\")\n    add_deps(\"linker.soname\")\n\n"
  },
  {
    "path": "xmake/rules/lua/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"lua.module\")\n    on_load(function (target)\n\n        -- imports\n        import(\"core.cache.detectcache\")\n        import(\"core.project.target\", {alias = \"project_target\"})\n\n        -- set kind\n        if target:is_plat(\"macosx\") then\n            target:set(\"kind\", \"binary\")\n            target:add(\"ldflags\", \"-bundle\", \"-undefined dynamic_lookup\", {force = true})\n        else\n            target:set(\"kind\", \"shared\")\n        end\n\n        -- set library name\n        local modulename = target:name():split('.', {plain = true})\n        modulename = modulename[#modulename]\n        if target:is_plat(\"windows\", \"mingw\") then\n            target:set(\"basename\", modulename)\n        else\n            target:set(\"filename\", modulename .. \".so\")\n        end\n\n        -- export symbols\n        if target:is_plat(\"windows\") then\n            local exported_name = target:name():gsub(\"%.\", \"_\")\n            exported_name = exported_name:match('^[^%-]+%-(.+)$') or exported_name\n            target:add(\"shflags\", \"/export:luaopen_\" .. exported_name, {force = true})\n        else\n            target:set(\"symbols\", \"none\")\n        end\n\n        -- add lua library\n        local has_lua = false\n        local includedirs = get_config(\"includedirs\") -- pass lua library from luarocks-build-xmake/xmake.lua\n        if includedirs and includedirs:find(\"lua\", 1, true) then\n            has_lua = true\n        end\n        if not has_lua then\n            -- user use `add_requires/add_packages` to add lua/luajit package\n            for _, pkg in ipairs(target:get(\"packages\")) do\n                if pkg == \"lua\" or pkg == \"luajit\" then\n                    has_lua = true\n                    break\n                end\n            end\n        end\n        if not has_lua then\n            target:add(find_package(\"lua\"))\n        end\n    end)\n    on_install(function (target)\n        if target:is_plat(\"macosx\") then\n            target:set(\"kind\", \"shared\")\n        end\n        local moduledir = path.directory((target:name():gsub('%.', '/')))\n        import(\"target.action.install\")(target, {\n            installdir = target:installdir(),\n            libdir = path.join(\"lib\", moduledir),\n            bindir = path.join(\"lib\", moduledir),\n            includedir = path.join(\"include\", moduledir)})\n    end)\n"
  },
  {
    "path": "xmake/rules/lua/native-objects/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Wu, Zhenyu\n-- @file        xmake.lua\n--\n\n-- usage:\n--\n-- target(\"foo\")\n-- do\n--     add_rules(\"lua.module\", \"lua.native-objects\", \"c\")\n--     add_files(\"*.nobj.lua\")\n-- end\nrule(\"lua.native-objects\")\n    set_extensions(\".nobj.lua\")\n    add_deps(\"c\")\n    before_buildcmd_file(function(target, batchcmds, sourcefile, opt)\n        import(\"lib.detect.find_tool\")\n        -- get c source file for lua.native-objects\n        local dirname = path.join(target:autogendir(), \"rules\", \"lua\", \"native-objects\")\n        local sourcefile_c = path.join(dirname, path.basename(sourcefile) .. \".c\")\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_c)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.nobj.lua %s\", sourcefile)\n        batchcmds:mkdir(path.directory(sourcefile_c))\n        local native_objects = find_tool(\"native_objects\")\n        assert(native_objects, \"native_objects not found! please `luarocks install luanativeobjects`.\")\n        batchcmds:vrunv(native_objects.program,\n            { \"-outpath\", path(dirname), \"-gen\", \"lua\", path(sourcefile) })\n        batchcmds:compile(sourcefile_c, objectfile)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n"
  },
  {
    "path": "xmake/rules/luarocks/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"luarocks.module\")\n    on_config(function (target)\n        wprint('deprecated: please use add_rules(\"lua.module\") instead of add_rules(\"luarocks.module\")')\n    end)\n    add_deps(\"lua.module\")\n"
  },
  {
    "path": "xmake/rules/mdk/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"mdk.binary\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"binary\")\n        if not target:get(\"extension\") then\n            target:set(\"extension\", \".axf\")\n        end\n    end)\n\nrule(\"mdk.static\")\n    on_load(function (target)\n        -- we disable checking flags for cross toolchain automatically\n        target:set(\"policy\", \"check.auto_ignore_flags\", false)\n        target:set(\"policy\", \"check.auto_map_flags\", false)\n\n        -- set default output binary\n        target:set(\"kind\", \"static\")\n    end)\n\nrule(\"mdk.console\")\n    add_deps(\"mdk.binary\")\n"
  },
  {
    "path": "xmake/rules/mode/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: debug mode\nrule(\"mode.debug\")\n    on_config(function (target)\n\n        -- is debug mode now? xmake f -m debug\n        if is_mode(\"debug\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- disable optimization\n            if not target:get(\"optimize\") then\n                target:set(\"optimize\", \"none\")\n            end\n\n            -- #5777: '--device-debug (-G)' overrides '--generate-line-info (-lineinfo)' in nvcc\n            target:add(\"cuflags\", \"-G\")\n        end\n    end)\n\n-- define rule: release mode\nrule(\"mode.release\")\n    on_config(function (target)\n\n        -- is release mode now? xmake f -m release\n        if is_mode(\"release\") then\n\n            -- set the symbols visibility: hidden\n            if not target:get(\"symbols\") and target:kind() ~= \"shared\" then\n                target:set(\"symbols\", \"hidden\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- strip all symbols\n            if target:policy(\"build.release.strip\") and not target:get(\"strip\") then\n                target:set(\"strip\", \"all\")\n            end\n\n            -- enable NDEBUG macros to disables standard-C assertions\n            target:add(\"cxflags\", \"-DNDEBUG\")\n            target:add(\"cuflags\", \"-DNDEBUG\")\n        end\n    end)\n\n-- define rule: release with debug symbols mode\nrule(\"mode.releasedbg\")\n    on_config(function (target)\n\n        -- is releasedbg mode now? xmake f -m releasedbg\n        if is_mode(\"releasedbg\") then\n\n            -- set the symbols visibility: debug\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- strip all symbols, but it will generate debug symbol file because debug/symbols is setted\n            if target:policy(\"build.release.strip\") and not target:get(\"strip\") then\n                target:set(\"strip\", \"all\")\n            end\n\n            -- enable NDEBUG macros to disables standard-C assertions\n            target:add(\"cxflags\", \"-DNDEBUG\")\n            target:add(\"cuflags\", \"-DNDEBUG\")\n\n            -- #5777: '--device-debug (-G)' overrides '--generate-line-info (-lineinfo)' in nvcc\n            target:add(\"cuflags\", \"-lineinfo\")\n        end\n    end)\n\n-- define rule: release with minsize mode\nrule(\"mode.minsizerel\")\n    on_config(function (target)\n\n        -- is minsizerel mode now? xmake f -m minsizerel\n        if is_mode(\"minsizerel\") then\n\n            -- set the symbols visibility: hidden\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"hidden\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                target:set(\"optimize\", \"smallest\")\n            end\n\n            -- strip all symbols\n            if not target:get(\"strip\") then\n                target:set(\"strip\", \"all\")\n            end\n\n            -- enable NDEBUG macros to disables standard-C assertions\n            target:add(\"cxflags\", \"-DNDEBUG\")\n            target:add(\"cuflags\", \"-DNDEBUG\")\n        end\n    end)\n\n-- define rule: profile mode\nrule(\"mode.profile\")\n    on_config(function (target)\n\n        -- is profile mode now? xmake f -m profile\n        if is_mode(\"profile\") then\n\n            -- set the symbols visibility: debug\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            if target:is_plat(\"windows\") then\n                -- enable vs profile\n                target:add(\"ldflags\", \"/profile\")\n            else\n                -- enable gprof\n                target:add(\"cxflags\", \"-pg\")\n                target:add(\"mxflags\", \"-pg\")\n                target:add(\"ldflags\", \"-pg\")\n            end\n\n            -- enable NDEBUG macros to disables standard-C assertions\n            target:add(\"cxflags\", \"-DNDEBUG\")\n            target:add(\"cuflags\", \"-DNDEBUG\")\n\n            -- #5777: '--device-debug (-G)' overrides '--generate-line-info (-lineinfo)' in nvcc\n            target:add(\"cuflags\", \"-lineinfo\")\n        end\n    end)\n\n-- define rule: coverage mode\nrule(\"mode.coverage\")\n    on_config(function (target)\n\n        -- is coverage mode now? xmake f -m coverage\n        if is_mode(\"coverage\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- disable optimization\n            if not target:get(\"optimize\") then\n                target:set(\"optimize\", \"none\")\n            end\n\n            -- enable coverage\n            target:add(\"cxflags\", \"--coverage\")\n            target:add(\"mxflags\", \"--coverage\")\n            target:add(\"ldflags\", \"--coverage\")\n            target:add(\"shflags\", \"--coverage\")\n\n            -- disable build cache, it does not support to cache coverage files\n            -- https://github.com/xmake-io/xmake/issues/6664\n            target:set(\"policy\", \"build.ccache\", false)\n        end\n    end)\n\n-- define rule: asan mode\nrule(\"mode.asan\")\n\n    -- we use after_load because c++.build.sanitizer rule/on_config need it\n    after_load(function (target)\n\n        -- is asan mode now? xmake f -m asan\n        if is_mode(\"asan\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- enable asan checker\n            target:set(\"policy\", \"build.sanitizer.address\", true)\n\n            -- we should use \"build.sanitizer.address\" instead of it.\n            wprint(\"deprecated: please use set_policy(\\\"build.sanitizer.address\\\", true) instead of \\\"mode.asan\\\".\")\n        end\n    end)\n\n-- define rule: tsan mode\nrule(\"mode.tsan\")\n    after_load(function (target)\n\n        -- is tsan mode now? xmake f -m tsan\n        if is_mode(\"tsan\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- enable tsan checker\n            target:set(\"policy\", \"build.sanitizer.thread\", true)\n\n            -- we should use \"build.sanitizer.thread\" instead of it.\n            wprint(\"deprecated: please use set_policy(\\\"build.sanitizer.thread\\\", true) instead of \\\"mode.tsan\\\".\")\n        end\n    end)\n\n-- define rule: msan mode\nrule(\"mode.msan\")\n    after_load(function (target)\n\n        -- is msan mode now? xmake f -m msan\n        if is_mode(\"msan\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- enable msan checker\n            target:set(\"policy\", \"build.sanitizer.memory\", true)\n\n            -- we should use \"build.sanitizer.memory\" instead of it.\n            wprint(\"deprecated: please use set_policy(\\\"build.sanitizer.memory\\\", true) instead of \\\"mode.msan\\\".\")\n        end\n    end)\n\n-- define rule: lsan mode\nrule(\"mode.lsan\")\n    after_load(function (target)\n\n        -- is lsan mode now? xmake f -m lsan\n        if is_mode(\"lsan\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- enable lsan checker\n            target:set(\"policy\", \"build.sanitizer.leak\", true)\n\n            -- we should use \"build.sanitizer.leak\" instead of it.\n            wprint(\"deprecated: please use set_policy(\\\"build.sanitizer.leak\\\", true) instead of \\\"mode.lsan\\\".\")\n        end\n    end)\n\n-- define rule: ubsan mode\nrule(\"mode.ubsan\")\n    after_load(function (target)\n\n        -- is ubsan mode now? xmake f -m ubsan\n        if is_mode(\"ubsan\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n\n            -- enable ubsan checker\n            target:set(\"policy\", \"build.sanitizer.undefined\", true)\n\n            -- we should use \"build.sanitizer.undefined\" instead of it.\n            wprint(\"deprecated: please use set_policy(\\\"build.sanitizer.undefined\\\", true) instead of \\\"mode.ubsan\\\".\")\n        end\n    end)\n\n-- define rule: valgrind mode\nrule(\"mode.valgrind\")\n    on_config(function (target)\n\n        -- is valgrind mode now? xmake f -m valgrind\n        if is_mode(\"valgrind\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- enable optimization\n            if not target:get(\"optimize\") then\n                if target:is_plat(\"android\", \"iphoneos\") then\n                    target:set(\"optimize\", \"smallest\")\n                else\n                    target:set(\"optimize\", \"fastest\")\n                end\n            end\n        end\n    end)\n\n-- define rule: check mode (deprecated)\nrule(\"mode.check\")\n    on_config(function (target)\n\n        -- is check mode now? xmake f -m check\n        if is_mode(\"check\") then\n\n            -- enable the debug symbols\n            if not target:get(\"symbols\") then\n                target:set(\"symbols\", \"debug\")\n            end\n\n            -- disable optimization\n            if not target:get(\"optimize\") then\n                target:set(\"optimize\", \"none\")\n            end\n\n            -- attempt to enable some checkers for pc\n            if is_mode(\"check\") and is_arch(\"i386\", \"x86_64\") then\n                target:add(\"cxflags\", \"-fsanitize=address\", \"-ftrapv\")\n                target:add(\"mxflags\", \"-fsanitize=address\", \"-ftrapv\")\n                target:add(\"ldflags\", \"-fsanitize=address\")\n                target:add(\"shflags\", \"-fsanitize=address\")\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"module.binary\")\n    on_load(function (target)\n        import(\"core.project.config\")\n        target:set(\"kind\", \"binary\")\n        target:set(\"basename\", \"module_\" .. target:name())\n        target:set(\"targetdir\", config.builddir())\n    end)\n\nrule(\"module.shared\")\n    add_deps(\"utils.symbols.export_all\")\n    on_load(function (target)\n        import(\"core.project.config\")\n        target:set(\"kind\", \"shared\")\n        target:set(\"basename\", \"module_\" .. target:name())\n        target:set(\"targetdir\", config.builddir())\n        target:set(\"strip\", \"none\")\n        target:add(\"includedirs\", path.join(os.programdir(), \"scripts\", \"module\"))\n        target:add(\"includedirs\", path.join(os.programdir(), \"scripts\", \"module\", \"luawrap\"))\n        if xmake.luajit() then\n            target:add(\"defines\", \"XMI_USE_LUAJIT\")\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/nim/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: nim.build\nrule(\"nim.build\")\n    set_sourcekinds(\"nc\")\n    on_load(function (target)\n        local cachedir = path.join(target:autogendir(), \"nimcache\")\n        target:add(\"ncflags\", \"--nimcache:\" .. cachedir, {force = true})\n    end)\n    on_build(\"build.target\")\n\n-- define rule: nim\nrule(\"nim\")\n\n    -- add build rules\n    add_deps(\"nim.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n"
  },
  {
    "path": "xmake/rules/nodejs/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Wu, Zhenyu\n-- @file        xmake.lua\n--\n\n-- usage:\n--\n-- add_requires(\"node-addon-api\")\n--\n-- target(\"foo\")\n-- do\n--     set_languages(\"cxx17\")\n--     add_rules(\"nodejs.module\")\n--     add_packages(\"node-addon-api\")\n--     add_files(\"*.cc\")\n-- end\nrule(\"nodejs.module\")\n    on_config(function(target)\n        -- imports\n        import(\"core.cache.detectcache\")\n        import(\"core.project.target\", { alias = \"project_target\" })\n\n        -- set kind\n        if target:is_plat(\"macosx\") then\n            target:set(\"kind\", \"binary\")\n            target:add(\"ldflags\", \"-bundle\", \"-undefined dynamic_lookup\", { force = true })\n        else\n            target:set(\"kind\", \"shared\")\n        end\n\n        -- export symbols\n        if target:is_plat(\"windows\") then\n            target:add(\"shflags\", \"/export:napi_register_module_v1\", \"/export:node_api_module_get_api_version_v1\",\n                { force = true })\n        else\n            target:set(\"symbols\", \"none\")\n        end\n\n        -- https://github.com/nodejs/node-addon-api/issues/1021\n        if target:is_plat(\"mingw\") then\n            target:add(\"packages\", \"node-api-stub\")\n            target:add(\"deps\", target:pkg(\"node-api-stub\"))\n        end\n\n        -- set library name\n        local modulename = target:name():split('.', { plain = true })\n        modulename = modulename[#modulename]\n        target:set(\"filename\", modulename .. \".node\")\n    end)\n\n    on_install(function(target)\n        if target:is_plat(\"macosx\") then\n            target:set(\"kind\", \"shared\")\n        end\n        local moduledir = path.directory((target:name():gsub('%.', '/')))\n        local mode = get_config(\"mode\")\n        local installdir = path.join(\"build\", mode:sub(1, 1):upper() .. mode:sub(2))\n        import(\"target.action.install\")(target, {\n            installdir = installdir,\n            libdir = moduledir,\n            bindir = moduledir,\n            includedir = path.join(\"include\", moduledir)\n        })\n    end)\n"
  },
  {
    "path": "xmake/rules/objc++/config/basic.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        basic.lua\n--\n\nfunction main(target, sourcekind)\n    if sourcekind == \"mm\" or sourcekind == \"mxx\" then\n        -- deprecated, we only need to use `add_mflags(\"-fno-objc-arc\")` or `add_mxxflags(\"-fno-objc-arc\")` to override it\n        local arc_value = sourcekind == \"mm\" and target:values(\"objc.build.arc\") or target:values(\"objc++.build.arc\")\n        if arc_value == false then\n            local flag_name = sourcekind == \"mm\" and \"mflags\" or \"mxxflags\"\n            target:add(flag_name, \"-fno-objc-arc\")\n        end\n\n        -- add frameworks for Apple platforms\n        if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n            target:add(\"frameworks\", \"Foundation\", \"CoreFoundation\")\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/objc++/config/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"rules.objc++.config.basic\", {rootdir = os.programdir(), alias = \"config_basic\"})\nimport(\"rules.c++.config.optimization\", {rootdir = os.programdir(), alias = \"config_optimization\"})\nimport(\"rules.c++.config.sanitizer\", {rootdir = os.programdir(), alias = \"config_sanitizer\"})\n\n-- main entry\nfunction main(target, sourcekind)\n    -- handle objc++ basic configs\n    config_basic(target, sourcekind)\n\n    -- handle optimization.lto\n    config_optimization(target, sourcekind)\n\n    -- handle sanitizer\n    config_sanitizer(target, sourcekind)\nend\n\n"
  },
  {
    "path": "xmake/rules/objc++/precompiled_header/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"objc.build.pcheader\")\n    on_config(function (target, opt)\n        import(\"private.action.build.pcheader\")\n        if not pcheader.config(target, \"m\", opt) then\n            target:rule_enable(\"objc.build.pcheader\", false)\n        end\n    end)\n\n    before_build(function (target, jobgraph, opt)\n        if not os.getenv(\"XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR\") then\n            import(\"private.action.build.pcheader\").build(target, jobgraph, \"m\", opt)\n        end\n    end, {jobgraph = true})\n\nrule(\"objc++.build.pcheader\")\n    add_orders(\"objc++.build.pcheader\", \"c++.build.modules.builder\")\n    on_config(function (target, opt)\n        import(\"private.action.build.pcheader\")\n        if not pcheader.config(target, \"mxx\", opt) then\n            target:rule_enable(\"objc++.build.pcheader\", false)\n        end\n    end)\n\n    -- Since Objective-C typically does not have C++ modules,\n    -- we can always enable parallel compilation across targets\n    -- without blocking the compilation of other cpp files,\n    -- we perform this as much as possible during the before_build stage.\n    before_build(function (target, jobgraph, opt)\n        import(\"private.action.build.pcheader\").build(target, jobgraph, \"mxx\", opt)\n    end, {jobgraph = true})\n\n"
  },
  {
    "path": "xmake/rules/objc++/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: objc.build\nrule(\"objc.build\")\n    set_sourcekinds(\"mm\")\n    add_deps(\"objc.build.pcheader\")\n    on_config(function (target)\n        import(\"config\")(target, \"mm\")\n    end)\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true, distcc = true})\n\n-- define rule: objc++.build\nrule(\"objc++.build\")\n    set_sourcekinds(\"mxx\")\n    add_deps(\"objc++.build.pcheader\")\n    on_config(function (target)\n        import(\"config\")(target, \"mxx\")\n    end)\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true, distcc = true})\n\n-- define rule: objc\nrule(\"objc++\")\n\n    -- add build rules\n    add_deps(\"objc++.build\", \"objc.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n"
  },
  {
    "path": "xmake/rules/pascal/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: pascal.build\nrule(\"pascal.build\")\n    set_sourcekinds(\"pc\")\n    on_build(\"build.target\")\n\n-- define rule: pascal\nrule(\"pascal\")\n\n    -- add build rules\n    add_deps(\"pascal.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n\n    -- add platform rules\n    add_deps(\"platform.wasm\")\n    add_deps(\"platform.windows\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n"
  },
  {
    "path": "xmake/rules/platform/android/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      keosu\n-- @file        install.lua\n--\n\n-- imports\n\nfunction main(target)\n\n    local android_sdkdir = target:toolchain(\"ndk\"):config(\"android_sdk\")\n    local adb = path.join(android_sdkdir, \"platform-tools\", \"adb\")\n\n    local final_apk = path.join(target:targetdir(), target:basename() .. \".apk\")\n    assert(os.isfile(final_apk), \"apk file %s not found!\", final_apk)\n\n    cprint(\"installing %s ...\", final_apk)\n    os.vrunv(adb, {\"install\", \"-r\", final_apk})\n    cprint(\"install ok\")\nend\n"
  },
  {
    "path": "xmake/rules/platform/android/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      keosu\n-- @file        load.lua\n--\n\nfunction main(target)\n\n    -- only for android target\n    if not target:is_plat(\"android\") then\n        wprint(\"rule(android.native_app): only for android system!\")\n        target:rule_enable(\"android.native_app\", false)\n        return\n    end\n\n    local toolchain_ndk = target:toolchain(\"ndk\")\n    local ndk_root = toolchain_ndk:config(\"ndk\")\n    if not ndk_root then\n        raise(\"NDK path not set! Please set NDK path properly.\")\n    end\n\n    -- set target kind\n    target:set(\"kind\", \"shared\")\n\n    -- add glue file to target\n    local extraconf = target:extraconf(\"rules\", \"android.native_app\")\n    local native_app_glue = true\n    if extraconf and extraconf.native_app_glue ~= nil then\n        native_app_glue = extraconf.native_app_glue\n    end\n    if native_app_glue then\n        local native_app_glue_file = path.join(ndk_root, \"sources\", \"android\", \"native_app_glue\", \"android_native_app_glue.c\")\n        local native_app_glue_dir = path.directory(native_app_glue_file)\n        target:add(\"files\", native_app_glue_file)\n        target:add(\"includedirs\", native_app_glue_dir)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/platform/android/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      keosu\n-- @file        package.lua\n--\n\n-- imports\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\n\nfunction _get_libname(android_manifest)\n    local libname = \"libmain.so\"\n    local manifest_xml = io.readfile(android_manifest)\n    if manifest_xml then\n        local lib_name_meta = manifest_xml:match('android:name=\"android.app.lib_name\"%s+android:value=\"([^\"]+)\"')\n        if lib_name_meta then\n            libname = \"lib\" .. lib_name_meta .. \".so\"\n        end\n    end\n    return libname\nend\n\nfunction _pack_resources(target, aapt, android_manifest, android_res, android_assets, android_sdkdir, android_sdk_version, tmp_path)\n    local resonly_apk = path.join(tmp_path, \"res_only.apk\")\n    local androidjar = path.join(android_sdkdir, \"platforms\", string.format(\"android-%s\", android_sdk_version), \"android.jar\")\n    assert(os.isfile(androidjar), \"%s not found\", androidjar)\n    \n    local aapt_argv = {\"package\", \"-f\", \"-M\", android_manifest, \"-I\", androidjar, \"-F\", resonly_apk}\n    if android_res and not os.emptydir(android_res) then\n        table.insert(aapt_argv, \"-S\")\n        table.insert(aapt_argv, android_res)\n    end\n    if android_assets and not os.emptydir(android_assets) then\n        table.insert(aapt_argv, \"-A\")\n        table.insert(aapt_argv, android_assets)\n    end\n    os.vrunv(aapt, aapt_argv)\nend\n\nfunction _pack_libs(target, aapt, libname, tmp_path)\n    os.vrunv(aapt, {\"add\", \"res_only.apk\", \"lib/\" .. target:arch() ..\"/\" .. libname},  {curdir = tmp_path})\nend\n\nfunction _align_apk(zipalign, tmp_path)\n    local aligned_apk = path.join(tmp_path, \"unsigned.apk\")\n    local zipalign_argv = {\"-f\", \"4\", \"res_only.apk\", \"unsigned.apk\"}\n    os.vrunv(zipalign, zipalign_argv, {curdir = tmp_path})\nend\n\nfunction _sign_apk(apksigner, keystore, keystore_pass, final_apk, tmp_path)\n    local aligned_apk = path.join(tmp_path, \"unsigned.apk\")\n    if keystore == nil then\n        raise(\"keystore for signing missing; generate one via `keytool` and make it available\")\n    elseif keystore_pass == nil then\n        raise(\"keystore_pass for signing is missing; please provide it\")\n    end\n    local apksigner_argv = {\"sign\", \"--ks\", keystore, \"--ks-pass\", string.format(\"pass:%s\", keystore_pass), \"--out\", final_apk, \"--in\", aligned_apk}\n    os.vrunv(apksigner, apksigner_argv)\nend\n\nfunction main(target, opt)\n    local conf = target:extraconf(\"rules\", \"android.native_app\")\n    local android_sdk_version = conf.android_sdk_version\n    local android_manifest = conf.android_manifest\n    local android_res = conf.android_res\n    local android_assets = conf.android_assets\n    local keystore = conf.keystore\n    local keystore_pass = conf.keystore_pass\n\n    assert(android_sdk_version, \"android sdk version not set\")\n    assert(android_manifest, \"android manifest not set\")\n\n    if not path.is_absolute(android_manifest) then\n        android_manifest = path.join(target:scriptdir(), android_manifest)\n    end\n    if keystore and not path.is_absolute(keystore) then\n        keystore = path.join(target:scriptdir(), keystore)\n    end\n    if android_res and not path.is_absolute(android_res) then\n        android_res = path.join(target:scriptdir(), android_res)\n    end\n    if android_assets and not path.is_absolute(android_assets) then\n        android_assets = path.join(target:scriptdir(), android_assets)\n    end\n\n    local final_apk = path.join(target:targetdir(), target:basename() .. \".apk\")\n\n    -- add dependencies\n    local depfiles = {target:targetfile(), android_manifest, keystore}\n    if android_res and os.isdir(android_res) then\n        table.join2(depfiles, os.files(path.join(android_res, \"**\")))\n    end\n    if android_assets and os.isdir(android_assets) then\n        table.join2(depfiles, os.files(path.join(android_assets, \"**\")))\n    end\n\n    depend.on_changed(function ()\n        progress.show(opt.progress, \"${color.build.target}packing.apk %s\", final_apk)\n\n        local tmp_path = path.join(target:autogendir(), \"packing\")\n        os.tryrm(tmp_path)\n        os.mkdir(tmp_path)\n        os.mkdir(path.join(tmp_path, \"lib\"))\n        os.mkdir(path.join(tmp_path, \"lib\", target:arch()))\n\n        -- copy the target library\n        local libname = _get_libname(android_manifest)\n        local libfile = path.join(tmp_path, \"lib\", target:arch(), libname)\n        os.cp(target:targetfile(), libfile)\n\n        -- get android tool path\n        local android_sdkdir = target:toolchain(\"ndk\"):config(\"android_sdk\")\n        local android_build_toolver = target:toolchain(\"ndk\"):config(\"build_toolver\")\n        local sdk_tool_path = path.join(android_sdkdir, \"build-tools\", android_build_toolver)\n\n        local aapt = path.join(sdk_tool_path, \"aapt\" .. (is_host(\"windows\") and \".exe\" or \"\"))\n        local zipalign = path.join(sdk_tool_path, \"zipalign\" .. (is_host(\"windows\") and \".exe\" or \"\"))\n        local apksigner = path.join(sdk_tool_path, \"apksigner\" .. (is_host(\"windows\") and \".bat\" or \"\"))\n\n        _pack_resources(target, aapt, android_manifest, android_res, android_assets, android_sdkdir, android_sdk_version, tmp_path)\n        _pack_libs(target, aapt, libname, tmp_path)\n        _align_apk(zipalign, tmp_path)\n        _sign_apk(apksigner, keystore, keystore_pass, final_apk, tmp_path)\n\n    end, {dependfile = target:dependfile(final_apk), files = depfiles, values = {android_sdk_version, keystore_pass}})\nend\n"
  },
  {
    "path": "xmake/rules/platform/android/run.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      keosu\n-- @file        run.lua\n--\n\n-- imports\nimport(\"core.base.tty\")\nimport(\"install\", {alias = \"install_app\"})\n\nfunction main(target)\n\n    -- install it first\n    install_app(target)\n\n    local conf = target:extraconf(\"rules\", \"android.native_app\")\n    local package_name = conf.package_name\n    local activity_name = conf.activity_name or \"android.app.NativeActivity\"\n\n    local android_sdkdir = target:toolchain(\"ndk\"):config(\"android_sdk\")\n    local adb = path.join(android_sdkdir, \"platform-tools\", \"adb\")\n\n    local run_argv = {\"shell\", \"am\", \"start\", \"-n\", package_name .. \"/\" .. activity_name}\n\n    cprint(\"running %s ...\", package_name)\n    os.vrunv(adb, run_argv)\n\n    -- show logcat\n    local logcat_argv = {\"logcat\"}\n    if io.isatty() and (tty.has_color8() or tty.has_color256()) then\n        table.insert(logcat_argv, \"-v\")\n        table.insert(logcat_argv, \"color\")\n    end\n    local logcat_filters = conf.logcat_filters\n    if logcat_filters then\n        table.insert(logcat_argv, \"-s\")\n        for _, filter in ipairs(logcat_filters) do\n            table.insert(logcat_argv, filter)\n        end\n    end\n    os.execv(adb, logcat_argv)\nend\n"
  },
  {
    "path": "xmake/rules/platform/android/uninstall.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall.lua\n--\n\nfunction main(target)\n\n    local conf = target:extraconf(\"rules\", \"android.native_app\")\n    local package_name = conf.package_name\n\n    local android_sdkdir = target:toolchain(\"ndk\"):config(\"android_sdk\")\n    local adb = path.join(android_sdkdir, \"platform-tools\", \"adb\")\n\n    cprint(\"uninstalling %s ...\", package_name)\n    os.vrunv(adb, {\"uninstall\", package_name})\n    cprint(\"uninstall ok\")\nend\n"
  },
  {
    "path": "xmake/rules/platform/android/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      keosu\n-- @file        xmake.lua\n--\n\n-- define rule: build android native app with NDK\n--\n-- @code\n-- target(\"test\")\n--     set_kind(\"binary\")\n--     add_rules(\"android.native_app\", {\n--        android_sdk_version = \"35\",\n--        android_manifest = \"android/AndroidManifest.xml\",\n--        android_res = \"android/res\",\n--        android_assets = \"android/assets\",\n--        keystore = \"android/debug.jks\",\n--        keystore_pass = \"123456\",\n--        package_name = \"com.raylib.demo\",\n--        native_app_glue = false,\n--        logcat_filters = {\"raydemo_android\", \"raylib\"}\n--     })\n-- @endcode\n--\nrule(\"android.native_app\")\n\n    -- we must set_kind and add some glue files to target\n    on_load(\"load\")\n\n    -- generate android apk package\n    after_build(\"package\")\n\n    -- install android package with adb\n    on_install(\"install\")\n\n    -- uninstall android package with adb\n    on_uninstall(\"uninstall\")\n\n    -- run android app through adb\n    on_run(\"run\")\n"
  },
  {
    "path": "xmake/rules/platform/linux/bpf/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- add *.bpf.c for linux bpf program\n-- @see https://github.com/xmake-io/xmake/issues/1274\nrule(\"platform.linux.bpf\")\n    set_extensions(\".bpf.c\")\n    on_config(function (target)\n        assert(is_host(\"linux\"), 'rule(\"platform.linux.bpf\"): only supported on linux!')\n        local headerdir = path.join(target:autogendir(), \"rules\", \"bpf\")\n        if not os.isdir(headerdir) then\n            os.mkdir(headerdir)\n        end\n        target:add(\"includedirs\", headerdir)\n    end)\n    before_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        local headerfile = path.join(target:autogendir(), \"rules\", \"bpf\", (path.filename(sourcefile):gsub(\"%.bpf%.c\", \".skel.h\")))\n        local objectfile = path.join(target:autogendir(), \"rules\", \"bpf\", (path.filename(sourcefile):gsub(\"%.bpf%.c\", \".bpf.o\")))\n        local targetarch\n        if target:is_arch(\"x86_64\", \"i386\") then\n            targetarch = \"__TARGET_ARCH_x86\"\n        elseif target:is_arch(\"arm64\", \"arm64-v8a\") then\n            targetarch = \"__TARGET_ARCH_arm64\"\n        elseif target:is_arch(\"arm.*\") then\n            targetarch = \"__TARGET_ARCH_arm\"\n        elseif target:is_arch(\"mips64\", \"mips\") then\n            targetarch = \"__TARGET_ARCH_mips\"\n        elseif target:is_arch(\"ppc64\", \"ppc\") then\n            targetarch = \"__TARGET_ARCH_powerpc\"\n        end\n        target:add(\"includedirs\", path.directory(headerfile))\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.bpf %s\", sourcefile)\n        batchcmds:mkdir(path.directory(objectfile))\n        batchcmds:compile(sourcefile, objectfile, {configs = {force = {cxflags = {\"-target bpf\", \"-g\", \"-O2\"}}, defines = targetarch}})\n        batchcmds:mkdir(path.directory(headerfile))\n        batchcmds:execv(\"bpftool\", {\"gen\", \"skeleton\", path(objectfile)}, {stdout = headerfile})\n        batchcmds:add_depfiles(sourcefile)\n        batchcmds:set_depmtime(os.mtime(headerfile))\n        batchcmds:set_depcache(target:dependfile(headerfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/platform/linux/driver/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"platform.linux.driver\")\n    on_config(function (target)\n        wprint('deprecated: please use add_rules(\"platform.linux.module\") instead of add_rules(\"platform.linux.driver\")')\n    end)\n    add_deps(\"platform.linux.module\")\n"
  },
  {
    "path": "xmake/rules/platform/linux/module/driver_modules.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        driver_modules.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.depend\")\nimport(\"core.cache.memcache\")\nimport(\"lib.detect.find_tool\")\nimport(\"utils.progress\")\n\n-- get linux-headers sdk\nfunction _get_linux_headers_sdk(target)\n    local linux_headersdir = target:values(\"linux.driver.linux-headers\")\n    local linux_builddir = target:values(\"linux.driver.linux-builddir\")\n    if linux_headersdir then\n        return {\n            sdkdir = linux_headersdir,\n            builddir = linux_builddir,\n            includedir = path.join(linux_headersdir, \"include\")\n        }\n    end\n    local linux_headers = assert(target:pkg(\"linux-headers\"), \"please add `add_requires(\\\"linux-headers\\\", {configs = {driver_modules = true}})` and `add_packages(\\\"linux-headers\\\")` to the given target!\")\n    local includedirs = linux_headers:get(\"includedirs\") or linux_headers:get(\"sysincludedirs\")\n    local version = linux_headers:version()\n    local includedir\n    for _, dir in ipairs(includedirs) do\n        if dir:find(\"linux-headers\", 1, true) then\n            includedir = dir\n            linux_headersdir = path.directory(dir)\n            break\n        end\n    end\n    assert(linux_headersdir, \"linux-headers not found!\")\n    if not os.isfile(path.join(includedir, \"generated/autoconf.h\")) and\n        not os.isfile(path.join(includedir, \"config/auto.conf\")) then\n        raise(\"kernel configuration is invalid. include/generated/autoconf.h or include/config/auto.conf are missing.\")\n    end\n    return {version = version, sdkdir = linux_headersdir, includedir = includedir}\nend\n\n-- get cflags from make\nfunction _get_cflags_from_make(target, sdkdir, builddir)\n    local key = sdkdir .. target:arch()\n    local cflags = memcache.get2(\"linux.driver\", key, \"cflags\")\n    local ldflags_o = memcache.get2(\"linux.driver\", key, \"ldflags_o\")\n    local ldflags_ko = memcache.get2(\"linux.driver\", key, \"ldflags_ko\")\n    if cflags == nil then\n        local make = assert(find_tool(\"make\"), \"make not found!\")\n        local tmpdir = os.tmpfile() .. \".dir\"\n        local makefile = path.join(tmpdir, \"Makefile\")\n        local stubfile = path.join(tmpdir, \"src/stub.c\")\n        local foofile  = path.join(tmpdir, \"src/foo.c\")\n        io.writefile(makefile, [[obj-m := stub.o\nstub-objs := src/stub.o src/foo.o]])\n        io.writefile(foofile, \"\")\n        io.writefile(stubfile, [[\n#include <linux/init.h>\n#include <linux/module.h>\n\nMODULE_LICENSE(\"Dual BSD/GPL\");\nMODULE_AUTHOR(\"Ruki\");\nMODULE_DESCRIPTION(\"A simple Hello World Module\");\nMODULE_ALIAS(\"a simplest module\");\n\nstatic int hello_init(void) {\n    printk(KERN_INFO \"Hello World\\n\");\n    return 0;\n}\n\nstatic void hello_exit(void) {\n    printk(KERN_INFO \"Goodbye World\\n\");\n}\n\nmodule_init(hello_init);\nmodule_exit(hello_exit);\n        ]])\n        local argv = {\"-C\", sdkdir, \"V=1\", \"M=\" .. tmpdir, \"modules\"}\n        if builddir then\n            table.insert(argv, \"O=\" .. builddir)\n        end\n        if not target:is_plat(os.subhost()) then\n            -- e.g.\t$(MAKE) -C $(KERN_DIR) V=1 ARCH=arm64 CROSS_COMPILE=/mnt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- M=$(PWD) modules\n            local arch\n            if target:is_arch(\"arm\", \"armv7\") then\n                arch = \"arm\"\n            elseif target:is_arch(\"arm64\", \"arm64-v8a\") then\n                arch = \"arm64\"\n            elseif target:is_arch(\"mips\") then\n                arch = \"mips\"\n            elseif target:is_arch(\"ppc\", \"ppc64\", \"powerpc\", \"powerpc64\") then\n                arch = \"powerpc\"\n            end\n            assert(arch, \"unknown arch(%s)!\", target:arch())\n            local cc = target:tool(\"cc\")\n            local cross = cc:gsub(\"%-gcc$\", \"-\")\n            table.insert(argv, \"ARCH=\" .. arch)\n            table.insert(argv, \"CROSS_COMPILE=\" .. cross)\n        end\n        local result, errors = try {function () return os.iorunv(make.program, argv, {curdir = tmpdir}) end}\n        if result then\n            -- we can also split ';' for the muliple commands\n            for _, line in ipairs(result:split(\"[\\n;]\")) do\n                line = line:trim()\n                if line:endswith(\"stub.c\") then\n                    local include_cflag = false\n                    for _, cflag in ipairs(line:split(\"%s+\")) do\n                        local has_cflag = false\n                        if cflag:startswith(\"-fplugin=\") then\n                            -- @see https://github.com/xmake-io/xmake/issues/3279\n                            local plugindir = cflag:sub(10)\n                            if not path.is_absolute(plugindir) then\n                                plugindir = path.absolute(plugindir, sdkdir)\n                            end\n                            cflag = \"-fplugin=\" .. plugindir\n                            has_cflag = true\n                        elseif cflag:startswith(\"-f\") or cflag:startswith(\"-m\")\n                            or (cflag:startswith(\"-W\") and not cflag:startswith(\"-Wp,-MMD,\") and not cflag:startswith(\"-Wp,-MD,\"))\n                            or (cflag:startswith(\"-D\") and not cflag:find(\"KBUILD_MODNAME=\") and not cflag:find(\"KBUILD_BASENAME=\")) then\n                            has_cflag = true\n                            -- https://github.com/xmake-io/xmake/discussions/5972#discussioncomment-11576255\n                            local macro, value = cflag:match(\"%-D(.+)='(.+)'\") -- -DXXX='\"xxx\"'\n                            if macro and value and value:startswith(\"\\\"\") then\n                                cflag = \"-D\" .. macro .. \"=\" .. value\n                            else\n                                macro = cflag:match(\"%-D\\\"(.+)\\\"\") -- -D\"KBUILD_XXX=xxx\"\n                                if macro then\n                                    cflag = \"-D\" .. macro\n                                end\n                            end\n                        elseif cflag == \"-I\" or cflag == \"-isystem\" or cflag == \"-include\" then\n                            include_cflag = cflag\n                        elseif cflag:startswith(\"-I\") or include_cflag then\n                            local includedir = cflag\n                            if cflag:startswith(\"-I\") then\n                                includedir = cflag:sub(3)\n                            end\n                            if not path.is_absolute(includedir) then\n                                includedir = path.absolute(includedir, builddir or sdkdir)\n                            end\n                            if cflag:startswith(\"-I\") then\n                                cflag = \"-I\" .. includedir\n                            else\n                                cflag = include_cflag .. \" \" .. includedir\n                            end\n                            has_cflag = true\n                            include_cflag = nil\n                        end\n                        if has_cflag then\n                            cflags = cflags or {}\n                            table.insert(cflags, cflag)\n                        end\n                    end\n                end\n                local ldflags = line:match(\"%-ld (.+) %-o \") or line:match(\"ld (.+) %-o \")\n                if ldflags then\n                    local ko = ldflags:find(\"-T \", 1, true)\n                    for _, ldflag in ipairs(os.argv(ldflags)) do\n                        if ldflag:endswith(\".lds\") then\n                            if not path.is_absolute(ldflag) then\n                                ldflag = path.absolute(ldflag, builddir or sdkdir)\n                            end\n                        end\n                        if ko then\n                            -- e.g. aarch64-linux-gnu-ld -r -EL  -maarch64elf --build-id=sha1  -T scripts/module.lds -o hello.ko hello.o hello.mod.o\n                            ldflags_ko = ldflags_ko or {}\n                            table.insert(ldflags_ko, ldflag)\n                        else\n                            -- e.g. aarch64-linux-gnu-ld -EL  -maarch64elf   -r -o hello.o xxx.o\n                            ldflags_o = ldflags_o or {}\n                            table.insert(ldflags_o, ldflag)\n                        end\n                    end\n                end\n                if cflags and ldflags_o and ldflags_ko then\n                    break\n                end\n            end\n        else\n            if option.get(\"diagnosis\") then\n                print(\"rule(platform.linux.driver): cannot get cflags from make!\")\n                print(errors)\n            end\n        end\n        os.tryrm(tmpdir)\n        memcache.set2(\"linux.driver\", key, \"cflags\", cflags or false)\n        memcache.set2(\"linux.driver\", key, \"ldflags_o\", ldflags_o or false)\n        memcache.set2(\"linux.driver\", key, \"ldflags_ko\", ldflags_ko or false)\n    end\n    return cflags or nil, ldflags_o or nil, ldflags_ko or nil\nend\n\nfunction load(target)\n    -- we only need binary kind, because we will rewrite on_link\n    target:set(\"kind\", \"binary\")\n    target:set(\"extension\", \".ko\")\nend\n\nfunction config(target)\n\n    -- get and save linux-headers sdk\n    local linux_headers = _get_linux_headers_sdk(target)\n    target:data_set(\"linux.driver.linux_headers\", linux_headers)\n\n    -- check compiler, we must use gcc\n    assert(target:has_tool(\"cc\", \"gcc\"), \"we must use gcc compiler!\")\n\n    -- check rules\n    for _, rulename in ipairs({\"mode.release\", \"mode.debug\", \"mode.releasedbg\", \"mode.minsizerel\", \"mode.asan\", \"mode.tsan\"}) do\n        assert(not target:rule(rulename), \"target(%s) is linux driver module, it need not rule(%s)!\", target:name(), rulename)\n    end\n\n    -- we need to disable includedirs from add_packages(\"linux-headers\")\n    if target:pkg(\"linux-headers\") then\n        target:pkg(\"linux-headers\"):set(\"includedirs\", nil)\n        target:pkg(\"linux-headers\"):set(\"sysincludedirs\", nil)\n    end\n\n    -- add compilation flags\n    target:add(\"defines\", \"KBUILD_MODNAME=\\\"\" .. target:name() .. \"\\\"\")\n    for _, sourcefile in ipairs(target:sourcefiles()) do\n        target:fileconfig_set(sourcefile, {defines = \"KBUILD_BASENAME=\\\"\" .. path.basename(sourcefile) .. \"\\\"\"})\n    end\n    local cflags, ldflags_o, ldflags_ko = _get_cflags_from_make(target, linux_headers.sdkdir, linux_headers.builddir)\n    if cflags then\n        target:add(\"cflags\", cflags, {force = true})\n        target:data_set(\"linux.driver.ldflags_o\", ldflags_o)\n        target:data_set(\"linux.driver.ldflags_ko\", ldflags_ko)\n    end\nend\n\nfunction link(target, opt)\n    local targetfile  = target:targetfile()\n    local dependfile  = target:dependfile(targetfile)\n    local objectfiles = target:objectfiles()\n    depend.on_changed(function ()\n\n        -- trace\n        progress.show(opt.progress, \"${color.build.object}linking.$(mode) %s\", targetfile)\n\n        -- get module scripts\n        local modpost\n        local linux_headers = target:data(\"linux.driver.linux_headers\")\n        if linux_headers then\n            modpost = path.join(linux_headers.builddir or linux_headers.sdkdir, \"scripts\", \"mod\", \"modpost\")\n        end\n        assert(modpost and os.isfile(modpost), \"scripts/mod/modpost not found!\")\n\n        -- get ld\n        local ld = target:tool(\"ld\")\n        assert(ld, \"ld not found!\")\n        ld = ld:gsub(\"gcc$\", \"ld\")\n        ld = ld:gsub(\"gcc%-%d+$\", \"ld\")\n        ld = ld:gsub(\"g%+%+$\", \"ld\")\n        ld = ld:gsub(\"g%+%+%-%d+$\", \"ld\")\n\n        -- link target.o\n        local argv = {}\n        local ldflags_o = target:data(\"linux.driver.ldflags_o\")\n        if ldflags_o then\n            table.join2(argv, ldflags_o)\n        end\n        local targetfile_o = target:objectfile(targetfile)\n        table.join2(argv, \"-o\", targetfile_o)\n        table.join2(argv, objectfiles)\n        os.mkdir(path.directory(targetfile_o))\n        os.vrunv(ld, argv)\n\n        -- generate target.mod\n        local targetfile_mod = targetfile_o:gsub(\"%.o$\", \".mod\")\n        io.writefile(targetfile_mod, table.concat(objectfiles, \"\\n\") .. \"\\n\\n\")\n\n        -- generate .sourcename.o.cmd\n        -- we only need to touch an empty file, otherwise modpost command will raise error.\n        for _, objectfile in ipairs(objectfiles) do\n            local objectdir = path.directory(objectfile)\n            local objectname = path.filename(objectfile)\n            local cmdfile = path.join(objectdir, \".\" .. objectname .. \".cmd\")\n            io.writefile(cmdfile, \"\")\n        end\n\n        -- generate target.mod.c\n        local orderfile = path.join(path.directory(targetfile_o), \"modules.order\")\n        local symversfile = path.join(path.directory(targetfile_o), \"Module.symvers\")\n        argv = {\"-m\", \"-a\", \"-o\", symversfile, \"-e\", \"-N\", \"-w\", \"-T\", orderfile}\n        io.writefile(orderfile, targetfile_o .. \"\\n\")\n        os.vrunv(modpost, argv)\n\n        -- compile target.mod.c\n        local targetfile_mod_c = targetfile_o:gsub(\"%.o$\", \".mod.c\")\n        local targetfile_mod_o = targetfile_o:gsub(\"%.o$\", \".mod.o\")\n        local compinst = target:compiler(\"cc\")\n        if option.get(\"verbose\") then\n            print(compinst:compcmd(targetfile_mod_c, targetfile_mod_o, {target = target, rawargs = true}))\n        end\n        assert(compinst:compile(targetfile_mod_c, targetfile_mod_o, {target = target}))\n\n        -- link target.ko\n        argv = {}\n        local ldflags_ko = target:data(\"linux.driver.ldflags_ko\")\n        if ldflags_ko then\n            table.join2(argv, ldflags_ko)\n        end\n        local targetfile_o = target:objectfile(targetfile)\n        table.join2(argv, \"-o\", targetfile, targetfile_o, targetfile_mod_o)\n        os.mkdir(path.directory(targetfile))\n        os.vrunv(ld, argv)\n\n    end, {dependfile = dependfile, lastmtime = os.mtime(target:targetfile()), files = objectfiles, changed = target:is_rebuilt()})\nend\n\nfunction install(target)\n    os.vrunv(\"insmod\", {target:targetfile()})\nend\n\nfunction uninstall(target)\n    os.vrunv(\"rmmod\", {target:targetfile()})\nend\n"
  },
  {
    "path": "xmake/rules/platform/linux/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- build linux driver module\nrule(\"platform.linux.module\")\n    set_sourcekinds(\"cc\")\n    on_load(function (target)\n        import(\"driver_modules\").load(target)\n    end)\n    on_config(function (target)\n        import(\"driver_modules\").config(target)\n    end)\n    on_link(function (target, opt)\n        import(\"driver_modules\").link(target, opt)\n    end)\n    on_install(function (target)\n        import(\"driver_modules\").install(target)\n    end)\n    on_uninstall(function (target)\n        import(\"driver_modules\").uninstall(target)\n    end)\n\n\n"
  },
  {
    "path": "xmake/rules/platform/wasm/installfiles/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      SirLynix, ruki\n-- @file        xmake.lua\n--\n\n-- copy other files generated by emcc (see https://emscripten.org/docs/tools_reference/emcc.html#emcc-o-target)\nrule(\"platform.wasm.installfiles\")\n    on_load(\"wasm\", function (target)\n        if not target:is_binary() then\n            return\n        end\n        local targetfile = target:targetfile()\n        target:add(\"installfiles\", targetfile:gsub(\"%.html\", \".js\"), { prefixdir = \"bin\" })\n        target:add(\"installfiles\", targetfile:gsub(\"%.html\", \".mem\"), { prefixdir = \"bin\" })\n        target:add(\"installfiles\", targetfile:gsub(\"%.html\", \".mjs\"), { prefixdir = \"bin\" })\n        target:add(\"installfiles\", targetfile:gsub(\"%.html\", \".wasm\"), { prefixdir = \"bin\" })\n    end)\n\n"
  },
  {
    "path": "xmake/rules/platform/wasm/preloadfiles/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- @see https://github.com/xmake-io/xmake/issues/3613\nrule(\"platform.wasm.preloadfiles\")\n    on_load(\"wasm\", function (target)\n        if not target:is_binary() then\n            return\n        end\n        local preloadfiles = target:values(\"wasm.preloadfiles\")\n        if preloadfiles then\n            for _, preloadfile in ipairs(preloadfiles) do\n                target:add(\"ldflags\", {\"--preload-file\", preloadfile}, {force = true, expand = false})\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/platform/windows/def/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- add *.def for windows/dll\nrule(\"platform.windows.def\")\n    set_extensions(\".def\")\n    on_config(\"windows\", \"mingw\", function (target)\n        if target:is_plat(\"windows\") and (target:is_shared() or target:is_binary()) then\n            local sourcebatch = target:sourcebatches()[\"platform.windows.def\"]\n            if sourcebatch then\n                -- https://github.com/xmake-io/xmake/pull/4901\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    local matched = false\n                    local flag = path.translate(sourcefile)\n                    if target:has_tool(\"ld\", \"link\") then\n                        flag = \"/def:\" .. flag\n                        matched = true\n                    elseif target:has_tool(\"ld\", \"clangxx\") then\n                        flag = \"-Wl,/def:\" .. flag\n                        matched = true\n                    end\n                    if matched then\n                        target:add(\"shflags\", flag, {force = true})\n                        target:add(\"ldflags\", flag, {force = true})\n                        target:data_add(\"linkdepfiles\", sourcefile)\n                    end\n                    break\n                end\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/platform/windows/idl/idl.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        idl.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"private.action.build.object\", {alias = \"build_objectfiles\"})\n\nfunction generate_single(target, sourcefile, opt)\n    local msvc = target:toolchain(\"msvc\") or target:toolchain(\"clang-cl\") or target:toolchain(\"clang\")\n    local midl = assert(find_tool(\"midl\", {envs = msvc:runenvs(), toolchain = msvc}), \"midl not found!\")\n\n    local name = path.basename(sourcefile)\n    local fileconfig = target:fileconfig(sourcefile)\n    local autogendir = path.join(target:autogendir(), \"platform/windows/idl\")\n\n    local enable_server\n    local enable_client\n    local defs = table.wrap(target:get(\"defines\") or {})\n    local incs = table.wrap(target:get(\"includedirs\") or {})\n    local undefs = table.wrap(target:get(\"undefines\") or {})\n\n    if fileconfig then\n        enable_server = fileconfig.server\n        enable_client = fileconfig.client\n        if fileconfig.includedirs then\n            table.join2(incs, fileconfig.includedirs)\n        end\n        if fileconfig.defines then\n            table.join2(defs, fileconfig.defines)\n        end\n        if fileconfig.undefines then\n            table.join2(undefs, fileconfig.undefines)\n        end\n    end\n\n    local flags = {\"/nologo\"}\n    table.join2(flags, table.wrap(target:values(\"idl.flags\")))\n\n    -- specify warn levels\n    local warns = target:get(\"warnings\")\n    if warns == \"none\" then\n        table.insert(flags, \"/W0\")\n        table.insert(flags, \"/no_warn\")\n    elseif warns == \"less\" then\n        table.insert(flags, \"/W1\")\n    elseif warns == \"more\" then\n        table.insert(flags, \"/W2\")\n    elseif warns == \"extra\" then\n        table.insert(flags, \"/W3\")\n    elseif warns == \"error\" then\n        table.insert(flags, \"/WX\")\n        table.insert(flags, \"/W4\")\n    end\n\n    -- add include dirs, defines and undefines from compiler flags\n    for _, inc in ipairs(incs) do\n        table.insert(flags, \"/I\")\n        table.insert(flags, path(inc))\n    end\n\n    for _, def in ipairs(defs) do\n        table.insert(flags, \"/D\")\n        table.insert(flags, def)\n    end\n\n    for _, undef in ipairs(undefs) do\n        table.insert(flags, \"/U\")\n        table.insert(flags, undef)\n    end\n\n    table.join2(flags, {\n        \"/out\",    path(autogendir),\n        \"/header\", name .. \".h\",\n        \"/iid\",    name .. \"_i.c\",\n        \"/proxy\",  name .. \"_p.c\",\n        \"/tlb\",    name .. \".tlb\",\n        \"/cstub\",  name .. \"_c.c\",\n        \"/sstub\",  name .. \"_s.c\",\n        \"/server\", (enable_server and \"stub\" or \"none\"),\n        \"/client\", (enable_client and \"stub\" or \"none\"),\n        path(sourcefile)\n    })\n\n    depend.on_changed(function()\n        progress.show(opt.progress or 0, \"${color.build.object}generating.idl %s\", sourcefile)\n        os.vrunv(midl.program, flags, { envs = msvc:runenvs() })\n    end, {\n        files = sourcefile,\n        dependfile = target:dependfile(sourcefile),\n        changed = target:is_rebuilt()\n    })\nend\n\nfunction configure(target)\n    local sourcebatch = target:sourcebatches()[\"platform.windows.idl\"]\n    if sourcebatch then\n        local autogendir = path.join(target:autogendir(), \"platform/windows/idl\")\n        os.mkdir(autogendir)\n        target:add(\"includedirs\", autogendir, {public = true})\n    end\nend\n\nfunction generate_idl(target, jobgraph, sourcebatch, opt)\n    for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n        local midljob = target:fullname() .. \"/generate/\" .. sourcefile\n        jobgraph:add(midljob, function (index, total, opt)\n            generate_single(target, sourcefile, opt)\n        end)\n    end\nend\n\nfunction build_idlfiles(target, jobgraph, sourcebatch, opt)\n    local autogendir = path.join(target:autogendir(), \"platform/windows/idl\")\n    for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n        local fileconfig = target:fileconfig(sourcefile)\n        local files = {\"_i.c\", \"_c.c\", \"_s.c\"}\n        if fileconfig and fileconfig.proxy then\n            table.insert(files, \"_p.c\")\n        end\n\n        local name = path.basename(sourcefile)\n        for _, suffix in ipairs(files) do\n            local c_sourcefile = path.join(autogendir, name .. suffix)\n            local objectfile = target:objectfile(c_sourcefile)\n            local dependfile = target:dependfile(objectfile)\n            local cc_job_name = path.join(target:fullname(), \"/obj/\", c_sourcefile)\n            jobgraph:add(cc_job_name, function (index, total, jobopt)\n                -- we don't have a way to detect which midl files are generated\n                if os.exists(c_sourcefile) then\n                    table.insert(target:objectfiles(), objectfile)\n                    local build_opt = table.join({objectfile = objectfile, dependfile = dependfile, sourcekind = \"cc\", progress = jobopt.progress}, opt)\n                    build_objectfiles.build_object(target, c_sourcefile, build_opt)\n                end\n            end, {distcc = opt.distcc})\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/platform/windows/idl/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n\n-- add *.idl for rc file\nrule(\"platform.windows.idl\")\n    set_extensions(\".idl\")\n    on_config(\"windows\", \"mingw\", function (target)\n        import(\"idl\").configure(target)\n    end)\n\n    before_build_files(function (target, jobgraph, sourcebatch, opt)\n        import(\"idl\").generate_idl(target, jobgraph, sourcebatch, opt)\n    end, {jobgraph = true, batch = true})\n\n    on_build_files(function (target, jobgraph, sourcebatch, opt)\n        import(\"idl\").build_idlfiles(target, jobgraph, sourcebatch, opt)\n    end, {jobgraph = true, batch = true, distcc = true})\n"
  },
  {
    "path": "xmake/rules/platform/windows/manifest/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- add *.manifest for windows\n-- https://github.com/xmake-io/xmake/issues/1241\nrule(\"platform.windows.manifest\")\n    set_extensions(\".manifest\")\n    on_config(\"windows\", function (target)\n        if not target:is_binary() and not target:is_shared() then\n            return\n        end\n        if target:has_tool(\"ld\", \"link\") or target:has_tool(\"sh\", \"link\") then\n            local manifest = false\n            local uac = false\n            local sourcebatch = target:sourcebatches()[\"platform.windows.manifest\"]\n            if sourcebatch then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    target:add(\"ldflags\", \"/manifestinput:\" .. path.translate(sourcefile), {force = true})\n                    target:add(\"shflags\", \"/manifestinput:\" .. path.translate(sourcefile), {force = true})\n                    target:data_add(\"linkdepfiles\", sourcefile)\n                    manifest = true\n                    local content = io.readfile(sourcefile)\n                    if content then\n                        content = content:gsub(\"<!%-%-.-%-%->\", \"\")\n                        if content:find(\"requestedPrivileges\", 1, true) then\n                            uac = true\n                        end\n                    end\n                    break\n                end\n            end\n            if manifest then\n                -- if manifest file is provided, we need disable default UAC manifest\n                -- @see https://github.com/xmake-io/xmake/pull/4362\n                if uac then\n                    target:add(\"ldflags\", \"/manifestuac:no\", {force = true})\n                end\n                target:add(\"shflags\", \"/manifestuac:no\", {force = true})\n\n                target:add(\"ldflags\", \"/manifest:embed\", {force = true})\n                target:add(\"shflags\", \"/manifest:embed\", {force = true})\n            else\n                local level = target:policy(\"windows.manifest.uac\")\n                if level then\n                    local level_maps = {\n                        invoker = \"asInvoker\",\n                        admin = \"requireAdministrator\",\n                        highest = \"highestAvailable\"\n                    }\n                    assert(level_maps[level], \"unknown uac level %s, please set invoker, admin or highest\", level)\n                    local ui = target:policy(\"windows.manifest.uac.ui\") or false\n                    target:add(\"ldflags\", \"/manifest:embed\", {(\"/manifestuac:level='%s' uiAccess='%s'\"):format(level_maps[level], ui)}, {force = true, expand = false})\n                end\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/platform/windows/subsystem/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, Arthapz\n-- @file        xmake.lua\n--\n\n-- define rule: subsystem\n-- set any of  \"boot_application\" \"console\" \"efi_application\" \"efi_boot_service_driver\" \"efi_rom\" \"efi_runtime_driver\" \"native\" \"posix\" \"windows\"\n-- with target:set_values(\"windows.subsystem\", <your value>) and the rule will pass the proper flag to the linker\nrule(\"platform.windows.subsystem\")\n    after_config(\"mingw\", \"windows\", function(target)\n        local subsystems = {\n            \"BOOT_APPLICATION\", \"CONSOLE\", \"EFI_APPLICATION\", \"EFI_BOOT_SERVICE_DRIVER\", \"EFI_ROM\", \"EFI_RUNTIME_DRIVER\", \"NATIVE\", \"POSIX\", \"WINDOWS\"\n        }\n\n        local subsystem = target:values(\"windows.subsystem\")\n        if subsystem then\n            local valid = false\n            for _, s in ipairs(subsystems) do\n                if subsystem:upper():startswith(s) then\n                    valid = true\n                    break\n                end\n            end\n            assert(valid, \"Invalid subsystem \" .. subsystem)\n\n            if target:has_tool(\"ld\", \"clang\", \"clangxx\", \"clang_cl\") then\n                target:add(\"ldflags\", {\"-Xlinker\", \"-subsystem:\" .. subsystem}, {force = true, expand = false})\n            elseif target:has_tool(\"ld\", \"link\", \"lld_link\") then\n                target:add(\"ldflags\", \"/SUBSYSTEM:\" .. subsystem:upper(), {force = true})\n            elseif target:has_tool(\"ld\", \"gcc\", \"gxx\") then\n                target:add(\"ldflags\", \"-m\" .. subsystem, {force = true})\n            elseif target:has_tool(\"ld\", \"lld\") then\n                target:add(\"ldflags\", \"-subsystem:\" .. subsystem, {force = true})\n            elseif target:has_tool(\"ld\", \"ld\") then\n                target:add(\"ldflags\", \"-m\" .. subsystem, {force = true})\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/platform/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"platform.wasm\")\n    add_deps(\"platform.wasm.preloadfiles\",\n             \"platform.wasm.installfiles\")\n\nrule(\"platform.windows\")\n    add_deps(\"platform.windows.def\",\n             \"platform.windows.idl\",\n             \"platform.windows.subsystem\")\n    if is_host(\"windows\") then\n        add_deps(\"platform.windows.manifest\")\n    end\n"
  },
  {
    "path": "xmake/rules/plugin/compile_commands/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- update compile_commandss.json automatically\n--\n-- @code\n-- add_rules(\"plugin.compile_commands.autoupdate\", {outputdir = \".vscode\", lsp = \"clangd\"})\n-- target(\"test\")\n--     set_kind(\"binary\")\n--     add_files(\"src/*.c\")\n-- @endcode\n--\nrule(\"plugin.compile_commands.autoupdate\")\n    set_kind(\"project\")\n    after_build(function (opt)\n\n        -- imports\n        import(\"core.project.config\")\n        import(\"core.project.depend\")\n        import(\"core.project.project\")\n        import(\"core.base.task\")\n\n        -- we should not update it if we are installing xmake package\n        if os.getenv(\"XMAKE_IN_XREPO\") then\n            return\n        end\n\n        -- run only once for all xmake process\n        local tmpfile = path.join(config.builddir(), \".gens\", \"rules\", \"plugin.compile_commands.autoupdate\")\n        local dependfile = tmpfile .. \".d\"\n        local lockfile = io.openlock(tmpfile .. \".lock\")\n        if lockfile:trylock() then\n            local outputdir\n            local lsp\n            local sourcefiles = {}\n            for _, target in pairs(project.targets()) do\n                table.join2(sourcefiles, target:sourcefiles(), (target:headerfiles()))\n                local extraconf = target:extraconf(\"rules\", \"plugin.compile_commands.autoupdate\")\n                if extraconf then\n                    outputdir = extraconf.outputdir\n                    lsp = extraconf.lsp\n                end\n            end\n            table.sort(sourcefiles)\n            depend.on_changed(function ()\n                -- we use task instead of os.exec(\"xmake\") to avoid the project lock\n                local filename = \"compile_commands.json\"\n                local filepath = outputdir and path.join(outputdir, filename) or filename\n                task.run(\"project\", {kind = \"compile_commands\", outputdir = outputdir, lsp = lsp})\n                print(\"compile_commands.json updated!\")\n            end, {dependfile = dependfile,\n                  files = table.join(project.allfiles(), config.filepath()),\n                  values = sourcefiles})\n            lockfile:close()\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/plugin/vsxmake/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- update vsxmake project automatically\n--\n-- @code\n-- add_rules(\"plugin.vsxmake.autoupdate\")\n-- target(\"test\")\n--     set_kind(\"binary\")\n--     add_files(\"src/*.c\")\n-- @endcode\n--\nrule(\"plugin.vsxmake.autoupdate\")\n    set_kind(\"project\")\n    after_build(function (opt)\n\n        -- imports\n        import(\"core.project.config\")\n        import(\"core.project.depend\")\n        import(\"core.project.project\")\n        import(\"core.cache.localcache\")\n        import(\"core.base.task\")\n\n        -- run only once for all xmake process in vs\n        local tmpfile = path.join(config.builddir(), \".gens\", \"rules\", \"plugin.vsxmake.autoupdate\")\n        local dependfile = tmpfile .. \".d\"\n        local lockfile = io.openlock(tmpfile .. \".lock\")\n        local kind = localcache.get(\"vsxmake\", \"kind\")\n        local modes = localcache.get(\"vsxmake\", \"modes\")\n        local archs = localcache.get(\"vsxmake\", \"archs\")\n        local outputdir = localcache.get(\"vsxmake\", \"outputdir\")\n        if lockfile:trylock() then\n            if os.getenv(\"XMAKE_IN_VSTUDIO\") and not os.getenv(\"XMAKE_IN_XREPO\") then\n                local sourcefiles = {}\n                for _, target in pairs(project.targets()) do\n                    table.join2(sourcefiles, target:sourcefiles(), (target:headerfiles()))\n                end\n                table.sort(sourcefiles)\n                depend.on_changed(function ()\n                    -- we use task instead of os.exec(\"xmake\") to avoid the project lock\n                    print(\"update vsxmake project -k %s %s ..\", kind or \"vsxmake\", outputdir or \"\")\n                    task.run(\"project\", {kind = kind or \"vsxmake\", modes = modes, archs = archs, outputdir = outputdir})\n                    print(\"update vsxmake project ok\")\n                end, {dependfile = dependfile,\n                      files = project.allfiles(),\n                      values = sourcefiles})\n            end\n            lockfile:close()\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/protobuf/proto.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        proto.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"lib.detect.find_tool\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"private.utils.batchcmds\")\n\n-- get protoc\nfunction _get_protoc(target, sourcekind)\n\n    -- find protoc\n    -- @see https://github.com/xmake-io/xmake/issues/4659\n    local envs = os.joinenvs(target:pkgenvs(), os.getenvs())\n    local protoc = target:data(\"protobuf.protoc\")\n    if not protoc and sourcekind == \"cxx\" then\n        protoc = find_tool(\"protoc\", {envs = envs})\n        if protoc and protoc.program then\n            target:data_set(\"protobuf.protoc\", protoc.program)\n        end\n    end\n\n    -- find protoc-c\n    local protoc_c = target:data(\"protobuf.protoc-c\")\n    if not protoc_c and sourcekind == \"cc\" then\n        protoc_c = find_tool(\"protoc-c\", {envs = envs}) or protoc\n        if protoc_c and protoc_c.program then\n            target:data_set(\"protobuf.protoc-c\", protoc_c.program)\n        end\n    end\n\n    -- get protoc\n    return assert(target:data(sourcekind == \"cxx\" and \"protobuf.protoc\" or \"protobuf.protoc-c\"), \"protoc not found!\")\nend\n\n-- get grpc_cpp_plugin\nfunction _get_grpc_cpp_plugin(target, sourcekind)\n    local envs = os.joinenvs(target:pkgenvs(), os.getenvs())\n    assert(sourcekind == \"cxx\", \"grpc_cpp_plugin only support c++\")\n    local grpc_cpp_plugin = find_tool(\"grpc_cpp_plugin\", {norun = true, force = true, envs = envs})\n    return assert(grpc_cpp_plugin and grpc_cpp_plugin.program, \"grpc_cpp_plugin not found!\")\nend\n\n-- we need to add some configs to export includedirs to other targets in on_load\n-- @see https://github.com/xmake-io/xmake/issues/2256\nfunction load(target, sourcekind)\n\n    local sourcebatch = target:sourcebatches()[sourcekind == \"cxx\" and \"protobuf.cpp\" or \"protobuf.c\"]\n    for _, sourcefile_proto in ipairs(sourcebatch and sourcebatch.sourcefiles) do\n        local prefixdir\n        local autogendir\n        local public\n        local grpc_cpp_plugin\n        local fileconfig = target:fileconfig(sourcefile_proto)\n        if fileconfig then\n            public = fileconfig.proto_public\n            prefixdir = fileconfig.proto_rootdir\n            autogendir = fileconfig.proto_autogendir\n            grpc_cpp_plugin = fileconfig.proto_grpc_cpp_plugin\n        end\n        local rootdir = autogendir and autogendir or path.join(target:autogendir(), \"rules\", \"protobuf\")\n        local filename = path.basename(sourcefile_proto) .. \".pb\" .. (sourcekind == \"cxx\" and \".cc\" or \"-c.c\")\n        local sourcefile_cx = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename})\n        local sourcefile_dir = prefixdir and path.join(rootdir, prefixdir) or path.directory(sourcefile_cx)\n\n        -- add includedirs\n        target:add(\"includedirs\", sourcefile_dir, {public = public})\n\n        -- add objectfile, @see https://github.com/xmake-io/xmake/issues/5426\n        local objectfile_grpc\n        local objectfile = target:objectfile(sourcefile_cx)\n        table.insert(target:objectfiles(), objectfile)\n        if grpc_cpp_plugin then\n            local filename_grpc = path.basename(sourcefile_proto) .. \".grpc.pb.cc\"\n            local sourcefile_cx_grpc = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename_grpc})\n            objectfile_grpc = target:objectfile(sourcefile_cx_grpc)\n            table.insert(target:objectfiles(), objectfile_grpc)\n        end\n    end\nend\n\nfunction buildcmd_pfile(target, batchcmds, sourcefile_proto, sourcekind, opt)\n\n    -- get protoc\n    local protoc = _get_protoc(target, sourcekind)\n\n    -- get c/c++ source file for protobuf\n    local prefixdir\n    local autogendir\n    local public\n    local grpc_cpp_plugin\n    local proto_flags\n    local fileconfig = target:fileconfig(sourcefile_proto)\n    if fileconfig then\n        public = fileconfig.proto_public\n        prefixdir = fileconfig.proto_rootdir\n        -- custom autogen directory to access the generated header files\n        -- @see https://github.com/xmake-io/xmake/issues/3678\n        autogendir = fileconfig.proto_autogendir\n        grpc_cpp_plugin = fileconfig.proto_grpc_cpp_plugin\n        -- custom flags, pass through to protoc\n        proto_flags = fileconfig.proto_flags\n    end\n    local rootdir = autogendir and autogendir or path.join(target:autogendir(), \"rules\", \"protobuf\")\n    local filename = path.basename(sourcefile_proto) .. \".pb\" .. (sourcekind == \"cxx\" and \".cc\" or \"-c.c\")\n    local sourcefile_cx = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename})\n    local sourcefile_dir = prefixdir and path.join(rootdir, prefixdir) or path.directory(sourcefile_cx)\n\n    local grpc_cpp_plugin_bin\n    local filename_grpc\n    local sourcefile_cx_grpc\n    if grpc_cpp_plugin then\n        grpc_cpp_plugin_bin = _get_grpc_cpp_plugin(target, sourcekind)\n        filename_grpc = path.basename(sourcefile_proto) .. \".grpc.pb.cc\"\n        sourcefile_cx_grpc = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename_grpc})\n    end\n\n    local protoc_args = {\n        path(sourcefile_proto),\n        path(prefixdir and prefixdir or path.directory(sourcefile_proto), function (p) return \"-I\" .. p end),\n        path(sourcefile_dir, function (p) return (sourcekind == \"cxx\" and \"--cpp_out=\" or \"--c_out=\") .. p end)\n    }\n\n    if grpc_cpp_plugin then\n        local extension = target:is_plat(\"windows\") and \".exe\" or \"\"\n        table.insert(protoc_args, \"--plugin=protoc-gen-grpc=\" .. grpc_cpp_plugin_bin .. extension)\n        table.insert(protoc_args, path(sourcefile_dir, function (p) return (\"--grpc_out=\") .. p end))\n    end\n\n    if proto_flags then\n        table.join2(protoc_args, proto_flags)\n    end\n\n    -- add commands\n    batchcmds:mkdir(sourcefile_dir)\n    batchcmds:show_progress(\n        opt.progress,\n        \"${color.build.object}compiling.proto.%s %s\",\n        (sourcekind == \"cxx\" and \"c++\" or \"c\"),\n        sourcefile_proto\n    )\n    batchcmds:vrunv(protoc, protoc_args)\n\n    -- add deps\n    local depmtime = os.mtime(sourcefile_cx)\n    batchcmds:add_depfiles(sourcefile_proto)\n    batchcmds:set_depcache(target:dependfile(sourcefile_cx))\n    if grpc_cpp_plugin then\n        batchcmds:set_depmtime(math.max(os.mtime(sourcefile_cx_grpc), depmtime))\n    else\n        batchcmds:set_depmtime(depmtime)\n    end\nend\n\nfunction buildcmd_cxfile(target, batchcmds, sourcefile_proto, sourcekind, opt)\n\n    -- get protoc\n    local protoc = _get_protoc(target, sourcekind)\n\n    -- get c/c++ source file for protobuf\n    local prefixdir\n    local autogendir\n    local public\n    local grpc_cpp_plugin\n    local fileconfig = target:fileconfig(sourcefile_proto)\n    if fileconfig then\n        public = fileconfig.proto_public\n        prefixdir = fileconfig.proto_rootdir\n        -- custom autogen directory to access the generated header files\n        -- @see https://github.com/xmake-io/xmake/issues/3678\n        autogendir = fileconfig.proto_autogendir\n        grpc_cpp_plugin = fileconfig.proto_grpc_cpp_plugin\n    end\n    local rootdir = autogendir and autogendir or path.join(target:autogendir(), \"rules\", \"protobuf\")\n    local filename = path.basename(sourcefile_proto) .. \".pb\" .. (sourcekind == \"cxx\" and \".cc\" or \"-c.c\")\n    local sourcefile_cx = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename})\n    local sourcefile_dir = prefixdir and path.join(rootdir, prefixdir) or path.directory(sourcefile_cx)\n\n    local grpc_cpp_plugin_bin\n    local filename_grpc\n    local sourcefile_cx_grpc\n    if grpc_cpp_plugin then\n        grpc_cpp_plugin_bin = _get_grpc_cpp_plugin(target, sourcekind)\n        filename_grpc = path.basename(sourcefile_proto) .. \".grpc.pb.cc\"\n        sourcefile_cx_grpc = target:autogenfile(sourcefile_proto, {rootdir = rootdir, filename = filename_grpc})\n    end\n\n    -- get objectfile\n    local objectfile = target:objectfile(sourcefile_cx)\n    local objectfile_grpc\n    if grpc_cpp_plugin then\n        objectfile_grpc = target:objectfile(sourcefile_cx_grpc)\n    end\n\n    batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.proto.$(mode) %s\", sourcefile_cx)\n    batchcmds:compile(sourcefile_cx, objectfile, {configs = {includedirs = sourcefile_dir}})\n    if grpc_cpp_plugin then\n        batchcmds:compile(sourcefile_cx_grpc, objectfile_grpc, {configs = {includedirs = sourcefile_dir}})\n    end\n\n    -- add deps\n    local depmtime = os.mtime(objectfile)\n    batchcmds:add_depfiles(sourcefile_proto)\n    batchcmds:set_depcache(target:dependfile(objectfile))\n    if grpc_cpp_plugin then\n        batchcmds:set_depmtime(math.max(os.mtime(objectfile_grpc), depmtime))\n    else\n        batchcmds:set_depmtime(depmtime)\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/protobuf/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: protobuf.cpp\nrule(\"protobuf.cpp\")\n    add_deps(\"c++\")\n    set_extensions(\".proto\")\n    after_load(function(target)\n        import(\"proto\").load(target, \"cxx\")\n    end)\n    on_preparecmd_file(function(target, batchcmds, sourcefile_proto, opt)\n        import(\"proto\").buildcmd_pfile(target, batchcmds, sourcefile_proto, \"cxx\", opt)\n    end)\n    on_buildcmd_file(function(target, batchcmds, sourcefile_proto, opt)\n        import(\"proto\").buildcmd_cxfile(target, batchcmds, sourcefile_proto, \"cxx\", opt)\n    end)\n\n\n-- define rule: protobuf.c\nrule(\"protobuf.c\")\n    add_deps(\"c++\")\n    set_extensions(\".proto\")\n    after_load(function(target)\n        import(\"proto\").load(target, \"cc\")\n    end)\n    on_preparecmd_file(function(target, batchcmds, sourcefile_proto, opt)\n        import(\"proto\").buildcmd_pfile(target, batchcmds, sourcefile_proto, \"cc\", opt)\n    end)\n    on_buildcmd_file(function(target, batchcmds, sourcefile_proto, opt)\n        import(\"proto\").buildcmd_cxfile(target, batchcmds, sourcefile_proto, \"cc\", opt)\n    end)\n"
  },
  {
    "path": "xmake/rules/python/cython/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      Wu, Zhenyu\n-- @file        xmake.lua\n--\n\nrule(\"python.cython\")\n    add_deps(\"python.module\")\n    set_extensions(\".py\", \".pyx\", \".pyi\")\n\n    on_load(function (target)\n        local language = target:extraconf(\"rules\", \"python.cython\", \"language\")\n        if language == \"c\" then\n            target:add(\"deps\", \"c\")\n        elseif language == \"c++\" then\n            target:add(\"deps\", \"c++\")\n        end\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        import(\"lib.detect.find_tool\")\n\n        local cython = assert(find_tool(\"cython\"), \"cython not found! please `pip install cython`.\")\n        local language = target:extraconf(\"rules\", \"python.cython\", \"language\")\n        local ext = \"c\"\n        local arg = \"-3\"\n        if language == \"c++\" then\n            ext = \"cc\"\n            arg = arg .. \"+\"\n        end\n        local dirname = path.join(target:autogendir(), \"rules\", \"python\", \"cython\")\n        local sourcefile_c = path.join(dirname, path.basename(sourcefile) .. \".\" .. ext)\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_c)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.python %s\", sourcefile)\n        batchcmds:mkdir(path.directory(sourcefile_c))\n        batchcmds:vrunv(cython.program, {arg, \"-o\", path(sourcefile_c), path(sourcefile)})\n        batchcmds:compile(sourcefile_c, objectfile)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n"
  },
  {
    "path": "xmake/rules/python/library/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"python.library\")\n    on_config(function (target)\n        wprint('deprecated: please use add_rules(\"python.module\") instead of add_rules(\"python.library\")')\n    end)\n    add_deps(\"python.module\")\n"
  },
  {
    "path": "xmake/rules/python/module/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- @see https://github.com/xmake-io/xmake/issues/1896\nrule(\"python.module\")\n    on_config(function (target)\n        target:set(\"kind\", \"shared\")\n        target:set(\"prefixname\", \"\")\n        target:add(\"runenvs\", \"PYTHONPATH\", target:targetdir())\n        local soabi = target:extraconf(\"rules\", \"python.module\", \"soabi\")\n        if soabi == nil or soabi then\n            import(\"lib.detect.find_tool\")\n            local python = assert(find_tool(\"python3\"), \"python not found!\")\n            local result = try { function() return os.iorunv(python.program, {\"-c\", \"import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))\"}) end}\n            if result then\n                result = result:trim()\n                if result ~= \"None\" then\n                    target:set(\"extension\", result)\n                end\n            end\n        else\n            if target:is_plat(\"windows\", \"mingw\") then\n                target:set(\"extension\", \".pyd\")\n            else\n                target:set(\"extension\", \".so\")\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/qt/build_qt_wasm_app.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_wasm_app.lua\n--\n\nimport(\"core.base.semver\")\n\n-- Fix Emscripten JS issues for Qt WASM builds\nfunction _fix_emscripten_js(jsfile)\n    if not os.isfile(jsfile) then\n        return\n    end\n\n    -- Remove \"use strict\"; to avoid issues with `this` being undefined in strict mode\n    io.gsub(jsfile, \"\\\"use strict\\\";\", \"\")\n    io.gsub(jsfile, \"'use strict';\", \"\")\n    -- Patch visualViewport access issue if present (undefined this context)\n    io.gsub(jsfile, \"this%.visualViewport\",\n        \"(typeof window !== 'undefined' ? window.visualViewport : null)\")\n    -- Guard all document.querySelector(target) calls with try-catch.\n    -- Qt WASM uses \"!\" prefixed selectors that are not valid CSS selectors,\n    -- and corrupted strings from SharedArrayBuffer can also cause SyntaxErrors.\n    io.gsub(jsfile, \"document%.querySelector%(target%)\",\n        \"(function(){try{return document.querySelector(target)}catch(e){return null}})()\")\n    -- Replace findCanvasEventTarget with a robust version.\n    -- Qt WASM registers canvases in Module.specialHTMLTargets with \"!\" prefixed\n    -- keys (e.g. \"!qtwindow1\", \"!qtoffscreen_xxx\"). With pthreads +\n    -- ALLOW_MEMORY_GROWTH, Emscripten's UTF8ToString may read corrupted strings\n    -- from SharedArrayBuffer memory, causing the specialHTMLTargets lookup to fail.\n    -- Additionally, QWasmOffscreenSurface passes an empty string when\n    -- OffscreenCanvas is unavailable. The replacement adds a fallback that\n    -- iterates specialHTMLTargets to find any Qt-registered canvas element.\n    local content = io.readfile(jsfile)\n    local marker = \"var findCanvasEventTarget = target => {\"\n    local pos = content:find(marker, 1, true)\n    if pos then\n        -- Find the end of the function by counting matched braces\n        local depth = 1\n        local i = pos + #marker\n        while i <= #content and depth > 0 do\n            local c = content:sub(i, i)\n            if c == \"{\" then depth = depth + 1\n            elseif c == \"}\" then depth = depth - 1 end\n            i = i + 1\n        end\n        if content:sub(i, i) == \";\" then i = i + 1 end\n        local new_func = \"var findCanvasEventTarget = target => {\\n\"\n            .. \" target = maybeCStringToJsString(target);\\n\"\n            .. \" if (specialHTMLTargets[target]) return specialHTMLTargets[target];\\n\"\n            .. \" if (GL.offscreenCanvases[target]) return GL.offscreenCanvases[target];\\n\"\n            .. \" if (typeof target === 'string' && target.length > 0) {\\n\"\n            .. \"  var s = target.substr(1);\\n\"\n            .. \"  if (GL.offscreenCanvases[s]) return GL.offscreenCanvases[s];\\n\"\n            .. \" }\\n\"\n            .. \" if (target === 'canvas') {\\n\"\n            .. \"  var k = Object.keys(GL.offscreenCanvases);\\n\"\n            .. \"  if (k.length) return GL.offscreenCanvases[k[0]];\\n\"\n            .. \" }\\n\"\n            .. \" for (var key in specialHTMLTargets) {\\n\"\n            .. \"  if (typeof key === 'string' && key.charAt(0) === '!') {\\n\"\n            .. \"   var el = specialHTMLTargets[key];\\n\"\n            .. \"   if (el && (el.tagName === 'CANVAS' || (typeof OffscreenCanvas !== 'undefined' && el instanceof OffscreenCanvas))) return el;\\n\"\n            .. \"  }\\n\"\n            .. \" }\\n\"\n            .. \" try { return typeof document !== 'undefined' ? document.querySelector(target) : undefined; }\\n\"\n            .. \" catch(e) { return undefined; }\\n\"\n            .. \"};\\n\"\n        content = content:sub(1, pos - 1) .. new_func .. content:sub(i)\n        io.writefile(jsfile, content)\n    end\nend\n\nfunction main(target)\n    local qt = target:data(\"qt\")\n    local pluginsdir = qt and qt.pluginsdir\n    if not pluginsdir then\n        return\n    end\n    local targetdir = target:targetdir()\n    local htmlfile = path.join(targetdir, target:basename() .. \".html\")\n    if os.isfile(path.join(pluginsdir, \"platforms/wasm_shell.html\")) then\n        os.vcp(path.join(pluginsdir, \"platforms/wasm_shell.html\"), htmlfile)\n        io.gsub(htmlfile, \"@APPNAME@\", target:name())\n        local qt_sdkver = qt.sdkver or target:data(\"qt_sdkver\")\n        if qt_sdkver and semver.new(qt_sdkver):ge(\"6.0\") then\n            io.gsub(htmlfile, \"@APPEXPORTNAME@\", \"createQtAppInstance\")\n            local preload = \"\"\n            -- @see https://github.com/xmake-io/xmake/issues/6182\n            local preloadfiles = target:values(\"wasm.preloadfiles\")\n            if preloadfiles then\n                local filelist = {}\n                for _, preloadfile in ipairs(preloadfiles) do\n                    table.insert(filelist, string.format(\"'%s'\", path.filename(preloadfile)))\n                end\n                if #filelist > 0 then\n                    preload = string.format(\"preload: [%s],\", table.concat(filelist, \", \"))\n                end\n            end\n            -- Patch old containerElements (pre-Qt 6.5)\n            io.gsub(htmlfile, \"containerElements: %[screen%],\", function (w)\n                return w .. \" \" .. preload\n            end)\n            -- Patch new qtContainerElements (Qt 6.5+)\n            io.gsub(htmlfile, \"qtContainerElements: %[screen%],\", function (w)\n                return w .. \" \" .. preload\n            end)\n            io.gsub(htmlfile, \"@PRELOAD@\", \"\")\n            _fix_emscripten_js(path.join(targetdir, target:basename() .. \".js\"))\n        end\n        os.vcp(path.join(pluginsdir, \"platforms/qtloader.js\"), targetdir)\n        os.vcp(path.join(pluginsdir, \"platforms/qtlogo.svg\"), targetdir)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/qt/config_static.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki, jingkaimori\n-- @file        config_static.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\n\nfunction main(target)\n    -- get qt sdk version\n    local qt = target:data(\"qt\")\n    local qt_sdkver = nil\n    if qt.sdkver then\n        qt_sdkver = semver.new(qt.sdkver)\n    else\n        raise(\"Qt SDK version not found, please run `xmake f --qt_sdkver=xxx` to set it.\")\n    end\n\n    -- @see\n    -- https://github.com/xmake-io/xmake/issues/1047\n    -- https://github.com/xmake-io/xmake/issues/2791\n    local QtPlatformSupport\n    if qt_sdkver:ge(\"6.0\") then\n        QtPlatformSupport = nil\n    elseif qt_sdkver:ge(\"5.9\") then\n        QtPlatformSupport = \"QtPlatformCompositorSupport\"\n    else\n        QtPlatformSupport = \"QtPlatformSupport\"\n    end\n\n    -- load some basic plugins and frameworks\n    local plugins = {}\n    local frameworks = {}\n    if target:is_plat(\"macosx\") then\n        plugins.QCocoaIntegrationPlugin = {linkdirs = \"plugins/platforms\", links = {\"qcocoa\", \"cups\"}}\n        table.insert(frameworks, \"QtWidgets\")\n        if QtPlatformSupport then\n            table.insert(frameworks, QtPlatformSupport)\n        end\n    elseif target:is_plat(\"windows\") then\n        plugins.QWindowsIntegrationPlugin = {linkdirs = \"plugins/platforms\", links = {is_mode(\"debug\") and \"qwindowsd\" or \"qwindows\"}}\n        table.join2(frameworks, \"QtPrintSupport\", \"QtWidgets\")\n        if QtPlatformSupport then\n            table.insert(frameworks, QtPlatformSupport)\n        end\n    elseif target:is_plat(\"wasm\") then\n        plugins.QWasmIntegrationPlugin = {linkdirs = \"plugins/platforms\", links = {\"qwasm\"}, resources = {\"wasmwindow\", \"wasmfonts\"}}\n        if qt_sdkver:ge(\"6.0\") then\n            table.join2(frameworks, \"QtOpenGL\")\n        else\n            table.join2(frameworks, \"QtEventDispatcherSupport\", \"QtFontDatabaseSupport\", \"QtEglSupport\")\n        end\n    end\n    return frameworks, plugins, qt_sdkver\nend"
  },
  {
    "path": "xmake/rules/qt/deploy/android.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        android.lua\n--\n\n-- imports\nimport(\"core.theme.theme\")\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_file\")\nimport(\"utils.progress\")\n\n-- escape path\nfunction _escape_path(p)\n    return os.args(p, {escape = true})\nend\n\n-- deploy application package for android\nfunction main(target, opt)\n\n    -- get ndk toolchain\n    local toolchain_ndk = toolchain.load(\"ndk\", {plat = target:plat(), arch = target:arch()})\n\n    -- get target apk path\n    local target_apk = path.join(target:targetdir(), target:basename() .. \".apk\")\n\n    -- need re-generate this apk?\n    local targetfile = target:targetfile()\n    local dependfile = target:dependfile(target_apk)\n    local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n    if not depend.is_changed(dependinfo, {lastmtime = os.mtime(dependfile)}) then\n        return\n    end\n\n    -- trace progress info\n    progress.show(opt.progress, \"${color.build.target}generating.qt.app %s.apk\", target:basename())\n\n    -- get qt sdk\n    local qt = target:data(\"qt\")\n\n    -- get ndk\n    local ndk = path.translate(assert(toolchain_ndk:config(\"ndk\"), \"cannot get NDK!\"))\n    local ndk_sdkver = assert(toolchain_ndk:config(\"ndk_sdkver\"), \"cannot get the sdk version of NDK!\")\n\n    -- get ndk host\n    local ndk_host = os.host() .. \"-\" .. os.arch()\n    if is_host(\"windows\") then\n        ndk_host = os.arch() == \"x64\" and \"windows-x86_64\" or \"windows-x86\"\n    elseif is_host(\"macosx\") then\n        ndk_host = \"darwin-x86_64\"\n    elseif is_host(\"linux\") then\n        ndk_host = \"linux-x86_64\"\n    end\n\n    -- get androiddeployqt\n    local search_dirs = {}\n    if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n    if qt.bindir then table.insert(search_dirs, qt.bindir) end\n    local androiddeployqt = find_file(\"androiddeployqt\" .. (is_host(\"windows\") and \".exe\" or \"\"), search_dirs)\n    assert(os.isexec(androiddeployqt), \"androiddeployqt not found!\")\n\n    -- get working directory\n    local workdir = path.join(config.builddir(), \".qt\", \"app\", \"android\", target:name())\n\n    -- get android-build directory\n    local android_buildir = path.join(workdir, \"android-build\")\n\n    -- get android platform\n    local android_platform = \"android-\" .. tostring(ndk_sdkver)\n\n    -- get java home\n    local java_home = assert(os.getenv(\"JAVA_HOME\"), \"please set $JAVA_HOME environment variable first!\")\n\n    -- get android sdk directory\n    local android_sdkdir = path.translate(assert(toolchain_ndk:config(\"android_sdk\"), \"please run `xmake f --android_sdk=xxx` to set the android sdk directory!\"))\n\n    -- get android build-tools version\n    local android_build_toolver = assert(toolchain_ndk:config(\"build_toolver\"), \"please run `xmake f --build_toolver=xxx` to set the android build-tools version!\")\n\n    -- get qt sdk version\n    local qt_sdkver = config.get(\"qt_sdkver\")\n    if qt_sdkver then\n        qt_sdkver = try { function () return semver.new(qt_sdkver) end}\n    end\n\n    -- get the target architecture\n    local target_archs =\n    {\n        [\"armv5te\"]     = \"armeabi\"       -- deprecated\n    ,   [\"armv7-a\"]     = \"armeabi-v7a\"   -- deprecated\n    ,   [\"armeabi\"]     = \"armeabi\"\n    ,   [\"armeabi-v7a\"] = \"armeabi-v7a\"\n    ,   [\"arm64-v8a\"]   = \"arm64-v8a\"\n    ,   i386            = \"x86\"\n    ,   x86_64          = \"x86_64\"\n    ,   mips            = \"mips\"          -- removed in ndk r71\n    ,   mips64          = \"mips64\"        -- removed in ndk r71\n    }\n    local target_arch = assert(target_archs[config.arch()], \"unsupport target arch(%s)!\", config.arch())\n\n    -- install target to android-build/libs first\n    if qt_sdkver and qt_sdkver:ge(\"5.14\") then\n        -- we need to copy target to android-build/libs/armeabi/libxxx_armeabi.so after Qt 5.14.0\n        os.cp(target:targetfile(), path.join(android_buildir, \"libs\", target_arch, \"lib\" .. target:basename() .. \"_\" .. target_arch .. \".so\"))\n    else\n        os.cp(target:targetfile(), path.join(android_buildir, \"libs\", target_arch, path.filename(target:targetfile())))\n    end\n\n    -- get stdcpp path\n    local stdcpp_path = path.join(ndk, \"sources/cxx-stl/llvm-libc++/libs\", target_arch, \"libc++_shared.so\")\n    if qt_sdkver and qt_sdkver:ge(\"5.14\") then\n        local ndk_sysroot = assert(toolchain_ndk:config(\"ndk_sysroot\"), \"NDK sysroot directory not found!\")\n        stdcpp_path = path.join(ndk_sysroot, \"usr\", \"lib\")\n    end\n\n    -- get toolchain version\n    local ndk_toolchains_ver = toolchain_ndk:config(\"ndk_toolchains_ver\") or \"4.9\"\n\n    -- generate android-deployment-settings.json file\n    local android_deployment_settings = path.join(workdir, \"android-deployment-settings.json\")\n    local settings_file = io.open(android_deployment_settings, \"w\")\n    if settings_file then\n        settings_file:print('{')\n        settings_file:print('   \"description\": \"This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.\",')\n        settings_file:print('   \"qt\": \"%s\",', _escape_path(qt.sdkdir))\n        settings_file:print('   \"sdk\": \"%s\",', _escape_path(android_sdkdir))\n        settings_file:print('   \"ndk\": \"%s\",', _escape_path(ndk))\n        settings_file:print('   \"sdkBuildToolsRevision\": \"%s\",', android_build_toolver)\n        settings_file:print('   \"toolchain-prefix\": \"llvm\",')\n        settings_file:print('   \"tool-prefix\": \"llvm\",')\n        settings_file:print('   \"toolchain-version\": \"%s\",', ndk_toolchains_ver)\n        settings_file:print('   \"stdcpp-path\": \"%s\",', _escape_path(stdcpp_path))\n        settings_file:print('   \"ndk-host\": \"%s\",', ndk_host)\n        settings_file:print('   \"target-architecture\": \"%s\",', target_arch)\n        settings_file:print('   \"qml-root-path\": \"%s\",', _escape_path(os.projectdir()))\n        -- for 6.2.x\n        local search_dirs = {}\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local qmlimportscanner = find_file(\"qmlimportscanner\" .. (is_host(\"windows\") and \".exe\" or \"\"), search_dirs)\n        if os.isexec(qmlimportscanner) then\n            settings_file:print('   \"qml-importscanner-binary\": \"%s\",', _escape_path(qmlimportscanner))\n        end\n        -- for 6.3.x\n        local search_dirs = {}\n        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n        if qt.bindir then table.insert(search_dirs, qt.bindir) end\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local rcc = find_file(\"rcc\" .. (is_host(\"windows\") and \".exe\" or \"\"), search_dirs)\n        if os.isexec(rcc) then\n            settings_file:print('   \"rcc-binary\": \"%s\",', _escape_path(rcc))\n        end\n        local platformplugin = find_file(\"libplugins_platforms_qtforandroid_\" .. target_arch .. \"*\", path.join(qt.sdkdir, \"plugins\", \"platforms\"))\n        if platformplugin then\n            settings_file:print('   \"deployment-dependencies\": {\"%s\":\"%s\"},', target_arch, _escape_path(platformplugin))\n        end\n\n        local minsdkversion = target:values(\"qt.android.minsdkversion\")\n        if minsdkversion then\n            settings_file:print('    \"android-min-sdk-version\": \"%s\",', tostring(minsdkversion))\n        end\n        local targetsdkversion = target:values(\"qt.android.targetsdkversion\")\n        if targetsdkversion then\n            settings_file:print('    \"android-target-sdk-version\": \"%s\",', tostring(targetsdkversion))\n        end\n        settings_file:print('   \"useLLVM\": true,')\n        if qt_sdkver and qt_sdkver:ge(\"5.14\") then\n            -- @see https://codereview.qt-project.org/c/qt-creator/qt-creator/+/287145\n            local triples =\n            {\n                [\"armv5te\"]     = \"arm-linux-androideabi\"   -- deprecated\n            ,   [\"armv7-a\"]     = \"arm-linux-androideabi\"   -- deprecated\n            ,   [\"armeabi\"]     = \"arm-linux-androideabi\"   -- removed in ndk r17\n            ,   [\"armeabi-v7a\"] = \"arm-linux-androideabi\"\n            ,   [\"arm64-v8a\"]   = \"aarch64-linux-android\"\n            ,   i386            = \"i686-linux-android\"      -- deprecated\n            ,   x86             = \"i686-linux-android\"\n            ,   x86_64          = \"x86_64-linux-android\"\n            ,   mips            = \"mips-linux-android\"      -- removed in ndk r17\n            ,   mips64          = \"mips64-linux-android\"    -- removed in ndk r17\n            }\n            settings_file:print('   \"architectures\": {\"%s\":\"%s\"},', target_arch, triples[target_arch])\n            settings_file:print('   \"application-binary\": \"%s\"', target:basename())\n        else\n            settings_file:print('   \"application-binary\": \"%s\"', _escape_path(target:targetfile()))\n        end\n        settings_file:print('}')\n        settings_file:close()\n    end\n    if option.get(\"verbose\") and option.get(\"diagnosis\") then\n        io.cat(android_deployment_settings)\n    end\n\n    -- do deploy\n    local argv = {\"--input\", android_deployment_settings,\n                  \"--output\", android_buildir,\n                  \"--jdk\", java_home,\n                  \"--gradle\", \"--no-gdbserver\"}\n    if option.get(\"verbose\") and option.get(\"diagnosis\") then\n        table.insert(argv, \"--verbose\")\n    end\n\n    -- add user flags\n    local user_flags = target:values(\"qt.deploy.flags\") or {}\n    if user_flags then\n        argv = table.join(argv, user_flags)\n    end\n\n    os.vrunv(androiddeployqt, argv)\n\n    -- output apk\n    os.cp(path.join(android_buildir, \"build\", \"outputs\", \"apk\", \"debug\", \"android-build-debug.apk\"), target_apk)\n\n    -- show apk output path\n    vprint(\"the apk output path: %s\", target_apk)\n\n    -- update files and values to the dependent file\n    dependinfo.files = {targetfile}\n    depend.save(dependinfo, dependfile)\nend\n\n"
  },
  {
    "path": "xmake/rules/qt/deploy/macosx.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        macosx.lua\n--\n\n-- imports\nimport(\"core.theme.theme\")\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.depend\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_path\")\nimport(\"detect.sdks.find_qt\")\nimport(\"utils.progress\")\nimport(\"private.tools.codesign\")\nimport(\"private.utils.target\", {alias = \"target_utils\"})\n\n-- save Info.plist\nfunction _save_info_plist(target, info_plist_file)\n\n    -- get target minver\n    local target_minver = nil\n    local toolchain_xcode = toolchain.load(\"xcode\", {plat = target:plat(), arch = target:arch()})\n    if toolchain_xcode then\n        target_minver = toolchain_xcode:config(\"target_minver\")\n    end\n\n    -- generate info.plist\n    local name = target:basename()\n    io.writefile(info_plist_file, string.format([[<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>BuildMachineOSBuild</key>\n\t<string>18G95</string>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>%s</string>\n\t<key>CFBundleExecutable</key>\n\t<string>%s</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>org.example.%s</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>%s</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>%s</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>]], name, name, name, name, target_minver or (macos.version():major() .. \".\" .. macos.version():minor())))\nend\n\n-- copy install files to Contents/Resources\nfunction _install_target_files(target, target_contents)\n    local srcfiles, dstfiles = target:installfiles(path.join(target_contents, \"Resources\"))\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            os.cp(srcfile, dstfiles[idx])\n        end\n    end\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcfiles, dstfiles = dep:installfiles(path.join(target_contents, \"Resources\"), {interface = true})\n        if srcfiles and dstfiles then\n            for idx, srcfile in ipairs(srcfiles) do\n                os.cp(srcfile, dstfiles[idx])\n            end\n        end\n    end\nend\n\n-- copy package libraries to Contents/Frameworks\nfunction _install_target_frameworks(target, target_contents)\n    local libfiles = {}\n    target_utils.get_target_libfiles(target, libfiles, target:targetfile(), {})\n    libfiles = table.unique(libfiles)\n    if #libfiles > 0 then\n        local frameworks_dir = path.join(target_contents, \"Frameworks\")\n        os.mkdir(frameworks_dir)\n        for _, libfile in ipairs(libfiles) do\n            os.cp(libfile, path.join(frameworks_dir, path.filename(libfile)))\n        end\n    end\nend\n\n-- deploy application package for macosx\nfunction main(target, opt)\n\n    -- need re-generate this app?\n    local target_app = path.join(target:targetdir(), target:basename() .. \".app\")\n    local targetfile = target:targetfile()\n    local dependfile = target:dependfile(target_app)\n    local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n    if not depend.is_changed(dependinfo, {lastmtime = os.mtime(dependfile)}) then\n        return\n    end\n\n    -- trace progress info\n    progress.show(opt.progress, \"${color.build.target}generating.qt.app %s.app\", target:basename())\n\n    -- get qt sdk\n    local qt = assert(find_qt(), \"Qt SDK not found!\")\n\n    -- get macdeployqt\n    local search_dirs = {}\n    if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n    if qt.bindir then table.insert(search_dirs, qt.bindir) end\n    local macdeployqt = find_file(\"macdeployqt\" .. (is_host(\"windows\") and \".exe\" or \"\"), search_dirs)\n    assert(os.isexec(macdeployqt), \"macdeployqt not found!\")\n\n    -- generate target app\n    local target_contents = path.join(target_app, \"Contents\")\n    os.tryrm(target_app)\n    local target_binary = path.join(target_contents, \"MacOS\", target:basename())\n    os.cp(target:targetfile(), target_binary)\n    os.cp(path.join(os.programdir(), \"scripts\", \"PkgInfo\"), target_contents)\n\n    -- generate Info.plist\n    _save_info_plist(target, path.join(target_contents, \"Info.plist\"))\n\n    -- copy install files to Contents/Resources\n    _install_target_files(target, target_contents)\n\n    -- copy package libraries to Contents/Frameworks\n    _install_target_frameworks(target, target_contents)\n\n    -- find qml directory\n    local qmldir = target:values(\"qt.deploy.qmldir\")\n    if not qmldir then\n        for _, sourcebatch in pairs(target:sourcebatches()) do\n            if sourcebatch.rulename == \"qt.qrc\" then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    qmldir = find_path(\"*.qml\", path.directory(sourcefile))\n                    if qmldir then\n                        break\n                    end\n                end\n            end\n        end\n    else\n        qmldir = path.join(target:scriptdir(), qmldir)\n    end\n\n    -- do deploy\n    local argv = {target_app}\n    if target:is_rebuilt() then\n        table.insert(argv, \"-always-overwrite\")\n    end\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"-verbose=3\")\n    elseif option.get(\"verbose\") then\n        table.insert(argv, \"-verbose=1\")\n    else\n        table.insert(argv, \"-verbose=0\")\n    end\n    if qmldir then\n        table.insert(argv, \"-qmldir=\" .. qmldir)\n    end\n    local codesign_identity = target:values(\"xcode.codesign_identity\") or codesign.xcode_codesign_identity()\n    if codesign_identity then\n        -- e.g. \"Apple Development: waruqi@gmail.com (T3NA4MRVPU)\"\n        table.insert(argv, \"-codesign=\" .. codesign_identity)\n    end\n\n    -- add user flags\n    local user_flags = target:values(\"qt.deploy.flags\") or {}\n    if user_flags then\n        argv = table.join(argv, user_flags)\n    end\n\n    os.vrunv(macdeployqt, argv)\n\n    -- update files and values to the dependent file\n    dependinfo.files = {targetfile}\n    depend.save(dependinfo, dependfile)\nend\n\n"
  },
  {
    "path": "xmake/rules/qt/env/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"qt.env\")\n    on_config(function (target)\n\n        -- imports\n        import(\"detect.sdks.find_qt\")\n\n        -- find qt sdk\n        local qt = target:data(\"qt\")\n        if not qt then\n            qt = assert(find_qt(nil, {verbose = true}), \"Qt SDK not found!\")\n            target:data_set(\"qt\", qt)\n        end\n\n        local qmlimportpath = target:values(\"qt.env.qmlimportpath\") or {}\n        if target:is_plat(\"windows\") or (target:is_plat(\"mingw\") and is_host(\"windows\")) then\n            if qt.bindir_host then\n                target:add(\"runenvs\", \"PATH\", qt.bindir_host)\n            end\n            if qt.bindir then\n                target:add(\"runenvs\", \"PATH\", qt.bindir)\n            end\n            table.insert(qmlimportpath, qt.qmldir)\n            -- add targetdir in QML2_IMPORT_PATH in case of the user have qml plugins\n            table.insert(qmlimportpath, target:targetdir())\n            target:set(\"runenv\", \"QML_IMPORT_TRACE\", \"1\")\n        elseif target:is_plat(\"msys\", \"cygwin\") then\n            raise(\"please run `xmake f -p mingw --mingw=/mingw64` to support Qt/Mingw64 on Msys!\")\n        end\n        target:set(\"runenv\", \"QML2_IMPORT_PATH\", qmlimportpath)\n    end)\n\n\n"
  },
  {
    "path": "xmake/rules/qt/install/android.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        android.lua\n--\n\n-- install application package for android\nfunction main(target, opt)\n\n    -- get target apk path\n    local target_apk = path.join(path.directory(target:targetfile()), target:basename() .. \".apk\")\n    assert(os.isfile(target_apk), \"apk not found, please build %s first!\", target:name())\n\n    -- show install info\n    print(\"installing %s ..\", target_apk)\n\n    -- get android sdk directory\n    local android_sdkdir = path.translate(assert(get_config(\"android_sdk\"), \"please run `xmake f --android_sdk=xxx` to set the android sdk directory!\"))\n\n    -- get adb\n    local adb = path.join(android_sdkdir, \"platform-tools\", \"adb\" .. (is_host(\"windows\") and \".exe\" or \"\"))\n    if not os.isexec(adb) then\n        adb = \"adb\"\n    end\n\n    -- install apk to device\n    os.execv(adb, {\"install\", \"-r\", target_apk})\nend\n"
  },
  {
    "path": "xmake/rules/qt/install/mingw.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      jingkaimori\n-- @file        mingw.lua\n--\n\n-- imports\nimport(\"rules.qt.install.windeployqt\", {rootdir = os.programdir()})\n\n-- get bin directory, if set_prefixdir changed bindir, we should use bindir\nfunction _get_bindir(target)\n    local bindir = assert(target:bindir(), \"please use `xmake install -o installdir` or `set_installdir` to set install directory on windows.\")\n    return bindir\nend\n\n-- install application package for windows\nfunction main(target, opt)\n\n    local bindir = _get_bindir(target)\n    local targetfile = path.join(bindir, path.filename(target:targetfile()))\n    local installfiles = {}\n    table.insert(installfiles, targetfile)\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:rule(\"qt.shared\") then -- qt.shared deps\n            local installfile = path.join(bindir, path.filename(dep:targetfile()))\n            table.insert(installfiles, installfile)\n        end\n    end\n\n    -- run windeployqt to deploy Qt dependencies\n    windeployqt.run_deploy(target, bindir, installfiles)\nend\n"
  },
  {
    "path": "xmake/rules/qt/install/windeployqt.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        windeployqt.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.tool.toolchain\")\nimport(\"lib.detect.find_file\")\nimport(\"lib.detect.find_path\")\nimport(\"detect.sdks.find_qt\")\n\n-- run windeployqt to deploy Qt dependencies\nfunction run_deploy(target, bindir, installfiles)\n    -- get qt sdk\n    local qt = find_qt()\n    if not qt then\n        return\n    end\n\n    -- get windeployqt\n    local search_dirs = {}\n    if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n    if qt.bindir then table.insert(search_dirs, qt.bindir) end\n    local program = find_file(\"windeployqt\" .. (is_host(\"windows\") and \".exe\" or \"\"), search_dirs)\n    if not program or not os.isexec(program) then\n        return\n    end\n\n    -- find qml directory\n    local qmldir = target:values(\"qt.deploy.qmldir\")\n    if not qmldir then\n        for _, sourcebatch in pairs(target:sourcebatches()) do\n            if sourcebatch.rulename == \"qt.qrc\" then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    qmldir = find_path(\"*.qml\", path.directory(sourcefile))\n                    if qmldir then\n                        break\n                    end\n                end\n            end\n        end\n    else\n        qmldir = path.join(target:scriptdir(), qmldir)\n    end\n\n    -- prepare environment\n    local envs = nil\n    if target:is_plat(\"windows\") then\n        -- find msvc to set VCINSTALLDIR env\n        local msvc = toolchain.load(\"msvc\", {plat = target:plat(), arch = target:arch()})\n        if msvc then\n            local vcvars = msvc:config(\"vcvars\")\n            if vcvars and vcvars.VCInstallDir then\n                envs = {VCINSTALLDIR = vcvars.VCInstallDir}\n            end\n        end\n    elseif target:is_plat(\"mingw\") then\n        -- add mingw dlls to PATH\n        local mingw = toolchain.load(\"mingw\", {plat = target:plat(), arch = target:arch()})\n        if mingw then\n            local mingw_bindir = mingw:bindir()\n            if mingw_bindir then\n                envs = {PATH = {}}\n                table.insert(envs.PATH, mingw_bindir)\n            end\n        end\n    end\n\n    -- bind qt bin path\n    -- https://github.com/xmake-io/xmake/issues/4297\n    if qt.bindir_host or qt.bindir then\n        envs = envs or {}\n        envs.PATH = envs.PATH or {}\n        if type(envs.PATH) == \"string\" then\n            envs.PATH = {envs.PATH}\n        end\n        if qt.bindir_host then\n            table.insert(envs.PATH, qt.bindir_host)\n        end\n        if qt.bindir then\n            table.insert(envs.PATH, qt.bindir)\n        end\n        local curpath = os.getenv(\"PATH\")\n        if curpath then\n            table.join2(envs.PATH, path.splitenv(curpath))\n        end\n    end\n\n    -- prepare arguments\n    local argv = {\"--force\"}\n    if option.get(\"diagnosis\") then\n        table.insert(argv, \"--verbose=2\")\n    elseif option.get(\"verbose\") then\n        table.insert(argv, \"--verbose=1\")\n    else\n        table.insert(argv, \"--verbose=0\")\n    end\n\n    -- make sure user flags have priority over default\n    local user_flags = table.wrap(target:values(\"qt.deploy.flags\"))\n    if table.contains(user_flags, \"--debug\", \"--release\") then\n        if is_mode(\"debug\") then\n            table.insert(argv, \"--debug\")\n        else\n            table.insert(argv, \"--release\")\n        end\n    end\n\n    if qmldir then\n        table.insert(argv, \"--qmldir=\" .. qmldir)\n    end\n\n    -- add user flags\n    if user_flags then\n        argv = table.join(argv, user_flags)\n    end\n\n    -- windeployqt for both target and its deps\n    table.join2(argv, installfiles)\n\n    -- run windeployqt\n    os.vrunv(program, argv, {envs = envs})\nend\n\n"
  },
  {
    "path": "xmake/rules/qt/install/windows.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        windows.lua\n--\n\n-- imports\nimport(\"rules.qt.install.windeployqt\", {rootdir = os.programdir()})\n\n-- get bin directory, if set_prefixdir changed bindir, we should use bindir\nfunction _get_bindir(target)\n    local bindir = assert(target:bindir(), \"please use `xmake install -o installdir` or `set_installdir` to set install directory on windows.\")\n    return bindir\nend\n\n-- install application package for windows\nfunction main(target, opt)\n\n    local bindir = _get_bindir(target)\n    local targetfile = path.join(bindir, path.filename(target:targetfile()))\n    local installfiles = {}\n    table.insert(installfiles, targetfile)\n    for _, dep in ipairs(target:orderdeps()) do\n        if dep:rule(\"qt.shared\") then -- qt.shared deps\n            local installfile = path.join(bindir, path.filename(dep:targetfile()))\n            table.insert(installfiles, installfile)\n        end\n    end\n\n    -- run windeployqt to deploy Qt dependencies\n    windeployqt.run_deploy(target, bindir, installfiles)\nend\n"
  },
  {
    "path": "xmake/rules/qt/installcmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        installcmd.lua\n--\n\n-- imports\nimport(\"core.project.project\")\nimport(\"core.base.hashset\")\nimport(\"utils.binary.deplibs\", {alias = \"get_depend_libraries\"})\nimport(\"rules.qt.install.windeployqt\", {rootdir = os.programdir()})\nimport(\"plugins.pack.batchcmds\", {alias = \"pack_batchcmds\", rootdir = os.programdir()})\n\n-- install application for xpack\nfunction main(target, batchcmds, opt)\n    local package = opt.package\n\n    -- only for xpack (package exists)\n    if not package then\n        return\n    end\n\n    -- get install directory\n    local installdir = package:installdir()\n    if not installdir then\n        return\n    end\n\n    -- macOS: install .app bundle\n    if target:is_plat(\"macosx\") then\n        local target_app = path.join(target:targetdir(), target:basename() .. \".app\")\n        if os.isdir(target_app) then\n            -- copy .app to install directory\n            local appname = path.filename(target_app)\n            local dstappdir = path.join(installdir, appname)\n            batchcmds:cp(target_app, dstappdir, {symlink = true})\n        end\n    elseif target:is_plat(\"windows\", \"mingw\") then\n        -- Windows/Mingw: need to run windeployqt to deploy Qt dependencies\n        -- First, prepare files in a temporary directory, then copy to package bindir via batchcmds\n\n        -- prepare deployment in a temporary directory\n        local deploydir = path.join(target:autogendir(), \"qt\", \"deploy\", target:name())\n        os.mkdir(deploydir)\n\n        -- copy target binary to deploydir first\n        local targetfile = path.join(deploydir, target:filename())\n        os.cp(target:targetfile(), targetfile)\n\n        -- copy qt.shared deps\n        local installfiles = {targetfile}\n        for _, dep in ipairs(target:orderdeps()) do\n            if dep:rule(\"qt.shared\") then\n                local depfile = path.join(deploydir, path.filename(dep:targetfile()))\n                os.cp(dep:targetfile(), depfile)\n                table.insert(installfiles, depfile)\n            end\n        end\n\n        -- run windeployqt to deploy Qt dependencies to deploydir\n        windeployqt.run_deploy(target, deploydir, installfiles)\n\n        -- copy all deployed files and directories from deploydir to root install directory via batchcmds\n        local installdir = package:installdir()\n        batchcmds:cp(path.join(deploydir, \"*\"), installdir, {rootdir = deploydir})\n\n        -- install other shared libraries (e.g. from packages)\n        pack_batchcmds.install_target_shared_libraries(target, batchcmds, {bindir = installdir, package = package})\n    else\n        -- Linux: copy all files from bindir (plugins, translations, etc. should be handled separately)\n        local bindir = target:bindir()\n        if bindir and os.isdir(bindir) then\n            local package_bindir = package:installdir(\"bin\")\n            -- copy all files and directories from bindir\n            batchcmds:cp(path.join(bindir, \"*\"), package_bindir, {rootdir = bindir})\n            \n            -- install shared libraries\n            local package_libdir = package:installdir(\"lib\")\n            pack_batchcmds.install_target_shared_libraries(target, batchcmds, {bindir = package_libdir, package = package})\n        end\n    end\n\n    -- install target files (resources, etc.)\n    -- for macosx, we have already installed them in deploy rule\n    if not target:is_plat(\"macosx\") then\n        pack_batchcmds.install_target_files(target, batchcmds, opt)\n        pack_batchcmds.update_target_install_rpath(target, batchcmds, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/qt/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"core.project.target\", {alias = \"core_target\"})\nimport(\"core.base.hashset\")\nimport(\"lib.detect.find_library\")\n\n-- make link for framework\nfunction _link(target, linkdirs, framework, qt_sdkver, infix)\n    if framework:startswith(\"Qt\") then\n        local debug_suffix = \"_debug\"\n        if target:is_plat(\"windows\") then\n            debug_suffix = \"d\"\n        elseif target:is_plat(\"mingw\") then\n            if qt_sdkver:ge(\"5.15.2\") then\n                debug_suffix = \"\"\n            else\n                debug_suffix = \"d\"\n            end\n        elseif target:is_plat(\"android\") or target:is_plat(\"linux\") then\n            debug_suffix = \"\"\n        end\n        if qt_sdkver:ge(\"5.0\") then\n            framework = \"Qt\" .. qt_sdkver:major() .. framework:sub(3) .. infix .. (is_mode(\"debug\") and debug_suffix or \"\")\n        else -- for qt4.x, e.g. QtGui4.lib\n            if target:is_plat(\"windows\", \"mingw\") then\n                framework = \"Qt\" .. framework:sub(3) .. infix .. (is_mode(\"debug\") and debug_suffix or \"\") .. qt_sdkver:major()\n            else\n                framework = \"Qt\" .. framework:sub(3) .. infix .. (is_mode(\"debug\") and debug_suffix or \"\")\n            end\n        end\n        if target:is_plat(\"android\") then --> -lQt5Core_armeabi/-lQt5CoreDebug_armeabi for 5.14.x\n            local libinfo = find_library(framework .. \"_\" .. config.arch(), linkdirs)\n            if libinfo and libinfo.link then\n                framework = libinfo.link\n            end\n        end\n    end\n    return framework\nend\n\n-- find the static links from the given qt link directories, e.g. libqt*.a\nfunction _find_static_links_3rd(target, linkdirs, qt_sdkver, libpattern)\n    local links = {}\n    local debug_suffix = \"_debug\"\n    if target:is_plat(\"windows\") then\n        debug_suffix = \"d\"\n    elseif target:is_plat(\"mingw\") then\n        debug_suffix = \"d\"\n    elseif target:is_plat(\"android\") or target:is_plat(\"linux\") then\n        debug_suffix = \"\"\n    end\n    for _, linkdir in ipairs(linkdirs) do\n        for _, libpath in ipairs(os.files(path.join(linkdir, libpattern))) do\n            local basename = path.basename(libpath)\n            -- we need to ignore qt framework libraries, e.g. libQt5xxx.a, Qt5Core.lib ..\n            -- but bundled library names like libQt5Bundledxxx.a on Qt6.x\n            -- @see https://github.com/xmake-io/xmake/issues/3572\n            if basename:startswith(\"libQt\" .. qt_sdkver:major() .. \"Bundled\") or (\n                (not basename:startswith(\"libQt\" .. qt_sdkver:major())) and\n                (not basename:startswith(\"Qt\" .. qt_sdkver:major()))) then\n                if (is_mode(\"debug\") and basename:endswith(debug_suffix)) or (not is_mode(\"debug\") and not basename:endswith(debug_suffix)) then\n                    table.insert(links, core_target.linkname(path.filename(libpath)))\n                end\n            end\n        end\n    end\n    return links\nend\n\n-- add plugins\nfunction _add_plugins(target, plugins)\n    for name, plugin in pairs(plugins) do\n        target:values_add(\"qt.plugins\", name)\n        if plugin.links then\n            target:values_add(\"qt.links\", table.unpack(table.wrap(plugin.links)))\n        end\n        if plugin.linkdirs then\n            target:values_add(\"qt.linkdirs\", table.unpack(table.wrap(plugin.linkdirs)))\n        end\n        if plugin.resources then\n            target:values_add(\"qt.plugin_resources\", table.unpack(table.wrap(plugin.resources)))\n        end\n        -- TODO: add prebuilt object files in qt sdk.\n        -- these file is located at plugins/xxx/objects-Release/xxxPlugin_init/xxxPlugin_init.cpp.o\n    end\nend\n\n-- add includedirs if exists\nfunction _add_includedirs(target, includedirs)\n    for _, includedir in ipairs(includedirs) do\n        if os.isdir(includedir) then\n            target:add(\"sysincludedirs\", includedir)\n        end\n    end\nend\n\n-- get target c++ version\nfunction _get_target_cppversion(target)\n    local languages = target:get(\"languages\")\n    for _, language in ipairs(languages) do\n        if language:startswith(\"c++\") or language:startswith(\"cxx\") then\n            local v = language:match(\"%d+\") or language:match(\"latest\")\n            if v then return v end\n        end\n    end\nend\n\n-- get frameworks from target\n-- @see https://github.com/xmake-io/xmake/issues/4135\nfunction _get_frameworks_from_target(target)\n    local values = table.wrap(target:get(\"frameworks\"))\n    for _, value in ipairs((target:get_from(\"frameworks\", \"option::*\"))) do\n        table.join2(values, value)\n    end\n    for _, value in ipairs((target:get_from(\"frameworks\", \"package::*\"))) do\n        table.join2(values, value)\n    end\n    for _, value in ipairs((target:get_from(\"__qt_frameworks\", \"dep::*\", {interface = true}))) do\n        table.join2(values, value)\n    end\n    return table.unique(values)\nend\n\n-- generate static plugin import file\nfunction _generate_plugin_import(target)\n    local plugins = target:values(\"qt.plugins\")\n    if not plugins then\n        return\n    end\n    local importfile = path.join(config.builddir(), \".qt\", \"plugin\", target:name(), \"static_import.cpp\")\n    local content = \"#include <QtPlugin>\\n\"\n    for _, plugin in ipairs(plugins) do\n        content = content .. string.format(\"Q_IMPORT_PLUGIN(%s)\\n\", plugin)\n    end\n    local plugin_resources = target:values(\"qt.plugin_resources\")\n    if plugin_resources then\n        content = content .. \"int init_qt_plugin_resources() {\\n\"\n        for _, res in ipairs(table.unique(plugin_resources)) do\n            content = content .. string.format(\"    Q_INIT_RESOURCE(%s);\\n\", res)\n        end\n        content = content .. \"    return 0;\\n}\\n\"\n        content = content .. \"static int s_init_qt_plugin_resources = init_qt_plugin_resources();\\n\"\n    end\n    io.writefile(importfile, content)\n    target:add(\"files\", importfile)\nend\n\nfunction _add_qmakeprllibs(target, prlfile, qt)\n    if os.isfile(prlfile) then\n        local contents = io.readfile(prlfile)\n        local envs = {}\n        if contents then\n            for _, prlenv in ipairs(contents:split('\\n', {plain = true})) do\n                local kv = prlenv:split('=', {plain = true})\n                if #kv == 2 then\n                    envs[kv[1]:trim()] = kv[2]:trim()\n                end\n            end\n        end\n        if envs.QMAKE_PRL_LIBS_FOR_CMAKE then\n            for _, lib in ipairs(envs.QMAKE_PRL_LIBS_FOR_CMAKE:split(';', {plain = true})) do\n                if lib:startswith(\"-L\") then\n                    local libdir = lib:sub(3)\n                    target:add(\"linkdirs\", libdir)\n                else\n                    if qt.qmldir then\n                        lib = string.gsub(lib, \"%$%$%[QT_INSTALL_QML%]\", qt.qmldir)\n                    end\n                    if qt.sdkdir then\n                        lib = string.gsub(lib, \"%$%$%[QT_INSTALL_PREFIX%]\", qt.sdkdir)\n                    end\n                    if qt.pluginsdir then\n                        lib = string.gsub(lib, \"%$%$%[QT_INSTALL_PLUGINS%]\", qt.pluginsdir)\n                    end\n                    if qt.libdir then\n                        lib = string.gsub(lib, \"%$%$%[QT_INSTALL_LIBS%]\", qt.libdir)\n                    end\n                    if lib:startswith(\"-l\") then\n                        lib = lib:sub(3)\n                    end\n                    target:add(\"syslinks\", lib)\n                end\n            end\n        end\n    end\nend\n\n-- the main entry\nfunction main(target, opt)\n\n    -- init options\n    opt = opt or {}\n\n    -- get qt sdk\n    local qt = target:data(\"qt\")\n\n    -- get qt sdk version\n    local qt_sdkver = nil\n    if qt.sdkver then\n        qt_sdkver = semver.new(qt.sdkver)\n    else\n        raise(\"Qt SDK version not found, please run `xmake f --qt_sdkver=xxx` to set it.\")\n    end\n\n    -- get qt sdk infix\n    local infix = \"\"\n    if qt.mkspecsdir then\n        if os.isfile(path.join(qt.mkspecsdir, \"qconfig.pri\")) then\n            local qconfig = io.readfile(path.join(qt.mkspecsdir, \"qconfig.pri\"))\n            if qconfig then\n                qconfig = qconfig:trim():split(\"\\n\")\n                for _, line in ipairs(qconfig) do\n                    if line:startswith(\"QT_LIBINFIX\") then\n                        local kv = line:split(\"=\", {plain = true, limit = 2})\n                        if #kv == 2 then\n                            infix = kv[2]:trim()\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- add -fPIC\n    if not target:is_plat(\"windows\", \"mingw\") then\n        target:add(\"cxflags\", \"-fPIC\")\n        target:add(\"mxflags\", \"-fPIC\")\n        target:add(\"asflags\", \"-fPIC\")\n    end\n\n    if qt_sdkver:ge(\"6.0\") then\n        -- @see https://github.com/xmake-io/xmake/issues/2071\n        if target:is_plat(\"windows\") and target:has_tool(\"cxx\", \"clang_cl\", \"cl\") then\n            target:add(\"cxxflags\", \"/Zc:__cplusplus\")\n            target:add(\"cxxflags\", \"/permissive-\")\n        end\n    end\n    -- need c++11 at least\n    local languages = target:get(\"languages\")\n    local cxxlang = false\n    for _, lang in ipairs(languages) do\n        -- c++* or gnuc++*\n        if lang:find(\"cxx\", 1, true) or lang:find(\"c++\", 1, true) then\n            cxxlang = true\n            break\n        end\n    end\n    if not cxxlang then\n        -- Qt6 require at least '/std:c++17'\n        -- @see https://github.com/xmake-io/xmake/issues/1183\n        local cppversion = _get_target_cppversion(target)\n        if qt_sdkver:ge(\"6.0\") then\n            -- add conditionnaly c++17 to avoid for example \"cl : Command line warning D9025 : overriding '/std:c++latest' with '/std:c++17'\" warning\n            if (not cppversion) or (tonumber(cppversion) and tonumber(cppversion) < 17) then\n                target:add(\"languages\", \"c++17\")\n            end\n        else\n            -- add conditionnaly c++11 to avoid for example \"cl : Command line warning D9025 : overriding '/std:c++latest' with '/std:c++11'\" warning\n            if (not cppversion) or (tonumber(cppversion) and tonumber(cppversion) < 11) then\n                target:add(\"languages\", \"c++11\")\n            end\n        end\n    end\n\n    -- add definitions for the compile mode\n    if is_mode(\"debug\") then\n        target:add(\"defines\", \"QT_QML_DEBUG\")\n    elseif is_mode(\"release\") then\n        target:add(\"defines\", \"QT_NO_DEBUG\")\n    elseif is_mode(\"profile\") then\n        target:add(\"defines\", \"QT_QML_DEBUG\", \"QT_NO_DEBUG\")\n    end\n\n    -- The following define makes your compiler emit warnings if you use\n    -- any feature of Qt which as been marked deprecated (the exact warnings\n    -- depend on your compiler). Please consult the documentation of the\n    -- deprecated API in order to know how to port your code away from it.\n    target:add(\"defines\", \"QT_DEPRECATED_WARNINGS\")\n\n    -- add plugins\n    if opt.plugins then\n        _add_plugins(target, opt.plugins)\n    end\n    _generate_plugin_import(target)\n\n    -- backup the user syslinks, we need to add them behind the qt syslinks\n    local syslinks_user = target:get(\"syslinks\")\n    target:set(\"syslinks\", nil)\n\n    -- add qt links and directories\n    target:add(\"syslinks\", target:values(\"qt.links\"))\n    local qtprldirs = {}\n    for _, qt_linkdir in ipairs(target:values(\"qt.linkdirs\")) do\n        local linkdir = path.join(qt.sdkdir, qt_linkdir)\n        if os.isdir(linkdir) then\n            target:add(\"linkdirs\", linkdir)\n            table.insert(qtprldirs, linkdir)\n        end\n    end\n    for _, qt_link in ipairs(target:values(\"qt.links\")) do\n        for _, qt_libdir in ipairs(qtprldirs) do\n            local prl_file = path.join(qt_libdir, qt_link .. \".prl\")\n            _add_qmakeprllibs(target, prl_file, qt)\n        end\n    end\n\n    -- backup qt frameworks\n    local qt_frameworks = target:get(\"frameworks\")\n    if qt_frameworks then\n        target:set(\"__qt_frameworks\", qt_frameworks)\n    end\n    local qt_frameworks_extra = target:extraconf(\"frameworks\")\n    if qt_frameworks_extra then\n        target:extraconf_set(\"__qt_frameworks\", qt_frameworks_extra)\n    end\n\n    -- add frameworks\n    if opt.frameworks then\n        target:add(\"frameworks\", opt.frameworks)\n    end\n\n    -- do frameworks for qt\n    local frameworksset = hashset.new()\n    local qt_frameworks = _get_frameworks_from_target(target)\n    for _, framework in ipairs(qt_frameworks) do\n\n        -- translate qt frameworks\n        if framework:startswith(\"Qt\") then\n            -- add private includedirs\n            if framework:lower():endswith(\"private\") then\n                local private_dir = framework:sub(1, -#(\"private\") - 1);\n                if target:is_plat(\"macosx\") then\n                    local frameworkdir = path.join(qt.libdir, framework .. \".framework\")\n                    if os.isdir(frameworkdir) then\n                        _add_includedirs(target, path.join(frameworkdir, \"Headers\", qt.sdkver))\n                        _add_includedirs(target, path.join(frameworkdir, \"Headers\", qt.sdkver, private_dir))\n                    else\n                        _add_includedirs(target, path.join(qt.includedir, private_dir, qt.sdkver, private_dir))\n                        _add_includedirs(target, path.join(qt.includedir, private_dir, qt.sdkver))\n                    end\n                else\n                    _add_includedirs(target, path.join(qt.includedir, private_dir, qt.sdkver, private_dir))\n                    _add_includedirs(target, path.join(qt.includedir, private_dir, qt.sdkver))\n                end\n            else\n                -- add definitions\n                target:add(\"defines\", \"QT_\" .. framework:sub(3):upper() .. \"_LIB\")\n\n                -- add includedirs\n                if target:is_plat(\"macosx\") then\n                    local frameworkdir = path.join(qt.libdir, framework .. \".framework\")\n                    if os.isdir(frameworkdir) and os.isdir(path.join(frameworkdir, \"Headers\")) then\n                        _add_includedirs(target, path.join(frameworkdir, \"Headers\"))\n                        -- e.g. QtGui.framework/Headers/5.15.0/QtGui/qpa/qplatformopenglcontext.h\n                        -- https://github.com/xmake-io/xmake/issues/1226\n                        _add_includedirs(target, path.join(frameworkdir, \"Headers\", qt.sdkver))\n                        _add_includedirs(target, path.join(frameworkdir, \"Headers\", qt.sdkver, framework))\n                        frameworksset:insert(framework)\n                    else\n                        local link = _link(target, qt.libdir, framework, qt_sdkver, infix)\n                        target:add(\"syslinks\", link)\n                        _add_qmakeprllibs(target, path.join(qt.libdir, link .. \".prl\"), qt)\n                        _add_includedirs(target, path.join(qt.includedir, framework))\n                        -- e.g. QtGui/5.15.0/QtGui/qpa/qplatformopenglcontext.h\n                        _add_includedirs(target, path.join(qt.includedir, framework, qt.sdkver))\n                        _add_includedirs(target, path.join(qt.includedir, framework, qt.sdkver, framework))\n                    end\n                else\n                    local link = _link(target, qt.libdir, framework, qt_sdkver, infix)\n                    target:add(\"syslinks\", link)\n                    _add_qmakeprllibs(target, path.join(qt.libdir, link .. \".prl\"), qt)\n                    _add_includedirs(target, path.join(qt.includedir, framework))\n                    _add_includedirs(target, path.join(qt.includedir, framework, qt.sdkver))\n                    _add_includedirs(target, path.join(qt.includedir, framework, qt.sdkver, framework))\n                end\n            end\n        elseif target:is_plat(\"macosx\") then\n            --@see https://github.com/xmake-io/xmake/issues/5336\n            frameworksset:insert(framework)\n        end\n    end\n\n    -- remove private frameworks\n    local local_frameworks = {}\n    for _, framework in ipairs(target:get(\"frameworks\")) do\n        if frameworksset:has(framework) then\n            table.insert(local_frameworks, framework)\n        end\n    end\n    target:set(\"frameworks\", local_frameworks)\n\n    -- add some static third-party links if exists\n    -- and exclude qt framework libraries, e.g. libQt5xxx.a, Qt5xxx.lib\n    local libpattern\n    if qt_sdkver:ge(\"6.0\") then\n        -- e.g. libQt6BundledFreetype.a on Qt6.x\n        -- @see https://github.com/xmake-io/xmake/issues/3572\n        libpattern = target:is_plat(\"windows\") and \"Qt*.lib\" or \"libQt*.a\"\n    else\n        -- e.g. libqtmain.a, libqtfreetype.q, libqtlibpng.a on Qt5.x\n        libpattern = target:is_plat(\"windows\") and \"qt*.lib\" or \"libqt*.a\"\n    end\n    target:add(\"syslinks\", _find_static_links_3rd(target, qt.libdir, qt_sdkver, libpattern))\n\n    -- add user syslinks\n    if syslinks_user then\n        target:add(\"syslinks\", syslinks_user)\n    end\n\n    -- add includedirs, linkdirs\n    local fallbackmkspec = \"\"\n    if target:is_plat(\"macosx\") then\n        target:add(\"frameworks\", \"DiskArbitration\", \"IOKit\", \"CoreFoundation\", \"CoreGraphics\", \"OpenGL\")\n        target:add(\"frameworks\", \"Carbon\", \"Foundation\", \"AppKit\", \"Security\", \"SystemConfiguration\")\n        if not frameworksset:empty() then\n            target:add(\"frameworkdirs\", qt.libdir)\n            target:add(\"rpathdirs\", \"@executable_path/Frameworks\", qt.libdir)\n        else\n            target:add(\"rpathdirs\", qt.libdir)\n\n            -- remove qt frameworks\n            local frameworks = table.wrap(target:get(\"frameworks\"))\n            for i = #frameworks, 1, -1 do\n                local framework = frameworks[i]\n                if framework:startswith(\"Qt\") then\n                    table.remove(frameworks, i)\n                end\n            end\n            target:set(\"frameworks\", frameworks)\n        end\n        _add_includedirs(target, qt.includedir)\n        fallbackmkspec = \"macx-clang\"\n        target:add(\"linkdirs\", qt.libdir)\n    elseif target:is_plat(\"linux\") then\n        target:set(\"frameworks\", nil)\n        _add_includedirs(target, qt.includedir)\n        fallbackmkspec = \"linux-g++\"\n        target:add(\"rpathdirs\", qt.libdir)\n        target:add(\"linkdirs\", qt.libdir)\n    elseif target:is_plat(\"windows\") then\n        target:set(\"frameworks\", nil)\n        _add_includedirs(target, qt.includedir)\n        fallbackmkspec = \"win32-msvc\"\n        target:add(\"linkdirs\", qt.libdir)\n        target:add(\"syslinks\", \"ws2_32\", \"gdi32\", \"ole32\", \"advapi32\", \"shell32\", \"user32\", \"opengl32\", \"imm32\", \"winmm\", \"iphlpapi\")\n        -- for debugger, https://github.com/xmake-io/xmake-vscode/issues/225\n        if qt.bindir_host then\n            target:add(\"runenvs\", \"PATH\", qt.bindir_host)\n        end\n        if qt.bindir then\n            target:add(\"runenvs\", \"PATH\", qt.bindir)\n        end\n    elseif target:is_plat(\"mingw\") then\n        target:set(\"frameworks\", nil)\n        -- we need to fix it, because gcc maybe does not work on latest mingw when `-isystem D:\\a\\_temp\\msys64\\mingw64\\include` is passed.\n        -- and qt.includedir will be this path value when Qt sdk directory just is `D:\\a\\_temp\\msys64\\mingw64`\n        -- @see https://github.com/msys2/MINGW-packages/issues/10761#issuecomment-1044302523\n        if is_subhost(\"msys\") then\n            local mingw_prefix = os.getenv(\"MINGW_PREFIX\")\n            local mingw_includedir = path.normalize(path.join(mingw_prefix or \"/\", \"include\"))\n            if qt.includedir and qt.includedir and path.normalize(qt.includedir) ~= mingw_includedir then\n                _add_includedirs(target, qt.includedir)\n            end\n        else\n            _add_includedirs(target, qt.includedir)\n        end\n        fallbackmkspec = \"win32-g++\"\n        target:add(\"linkdirs\", qt.libdir)\n        target:add(\"syslinks\", \"mingw32\", \"ws2_32\", \"gdi32\", \"ole32\", \"advapi32\", \"shell32\", \"user32\", \"iphlpapi\")\n    elseif target:is_plat(\"android\") then\n        target:set(\"frameworks\", nil)\n        _add_includedirs(target, qt.includedir)\n        fallbackmkspec = \"android-clang\"\n        target:add(\"rpathdirs\", qt.libdir)\n        target:add(\"linkdirs\", qt.libdir)\n    elseif target:is_plat(\"wasm\") then\n        target:set(\"frameworks\", nil)\n        _add_includedirs(target, qt.includedir)\n        fallbackmkspec = \"wasm-emscripten\"\n        target:add(\"rpathdirs\", qt.libdir)\n        target:add(\"linkdirs\", qt.libdir)\n        -- add prebuilt object files in qt sdk.\n        -- these files are located at lib/objects-Release/xxxmodule_resources_x/.rcc/xxxmodule.cpp.o\n        for _, framework in ipairs(qt_frameworks) do\n            local prefix = framework\n            if framework:startswith(\"Qt\") then\n                prefix = framework:sub(3)\n            end\n            for _, filepath in ipairs(os.files(path.join(qt.libdir, \"objects-*\", prefix .. \"_resources_*\", \".rcc\", \"*.o\"))) do\n                table.insert(target:objectfiles(), filepath)\n            end\n        end\n        target:add(\"ldflags\", \"-s FETCH=1\", \"-s ERROR_ON_UNDEFINED_SYMBOLS=1\", \"-s ALLOW_MEMORY_GROWTH=1\", \"--bind\")\n        target:add(\"shflags\", \"-s FETCH=1\", \"-s ERROR_ON_UNDEFINED_SYMBOLS=1\", \"-s ALLOW_MEMORY_GROWTH=1\", \"--bind\")\n        if qt_sdkver:ge(\"6.0\") then\n            -- @see https://github.com/xmake-io/xmake/issues/4137\n            -- @see QtWasmHelpers.cmake: qt_internal_setup_wasm_target_properties\n            target:add(\"ldflags\", \"-s MAX_WEBGL_VERSION=2\", \"-s WASM_BIGINT=1\", \"-s STACK_SIZE=5MB\")\n            target:add(\"ldflags\", \"-sASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js\")\n            -- @see Qt6WasmMacros.cmake: _qt_internal_add_wasm_extra_exported_methods\n            target:add(\"ldflags\", \"-s EXPORTED_RUNTIME_METHODS=UTF16ToString,stringToUTF16,JSEvents,specialHTMLTargets,FS,callMain\")\n            -- @see https://github.com/emscripten-core/emscripten/issues/21844\n            target:add(\"ldflags\", \"-s EXPORTED_FUNCTIONS=_main,__embind_initialize_bindings\", {force = true})\n            target:add(\"ldflags\", \"-s MODULARIZE=1\", \"-s EXPORT_NAME=createQtAppInstance\")\n            target:add(\"shflags\", \"-s MAX_WEBGL_VERSION=2\", \"-s WASM_BIGINT=1\", \"-s STACK_SIZE=5MB\")\n            target:add(\"shflags\", \"-sASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js\")\n            target:add(\"shflags\", \"-s EXPORTED_RUNTIME_METHODS=UTF16ToString,stringToUTF16,JSEvents,specialHTMLTargets,FS,callMain\")\n            target:add(\"shflags\", \"-s EXPORTED_FUNCTIONS=_main,__embind_initialize_bindings\", {force = true})\n            target:add(\"shflags\", \"-s MODULARIZE=1\", \"-s EXPORT_NAME=createQtAppInstance\")\n            target:set(\"extension\", \".js\")\n        else\n            target:add(\"ldflags\", \"-s WASM=1\", \"-s FULL_ES2=1\", \"-s FULL_ES3=1\", \"-s USE_WEBGL2=1\")\n            target:add(\"ldflags\", \"-s EXPORTED_RUNTIME_METHODS=[\\\"UTF16ToString\\\",\\\"stringToUTF16\\\"]\")\n            target:add(\"shflags\", \"-s WASM=1\", \"-s FULL_ES2=1\", \"-s FULL_ES3=1\", \"-s USE_WEBGL2=1\")\n            target:add(\"shflags\", \"-s EXPORTED_RUNTIME_METHODS=[\\\"UTF16ToString\\\",\\\"stringToUTF16\\\"]\")\n        end\n    end\n    _add_includedirs(target, path.join(qt.mkspecsdir, qt.mkspec or fallbackmkspec))\n\n    -- is gui application?\n    if opt.gui then\n        if not target:values(\"windows.subsystem\") then\n            target:values_set(\"windows.subsystem\", \"windows\")\n            if target:has_tool(\"ld\", \"link\", \"lld-link\") then\n                target:add(\"ldflags\", \"-entry:mainCRTStartup\", {force = true})\n            end\n        end\n    else\n        if not target:values(\"windows.subsystem\") then\n            target:values_set(\"windows.subsystem\", \"console\")\n        end\n    end\n\n    -- set default runtime\n    -- @see https://github.com/xmake-io/xmake/issues/4161\n    if not target:get(\"runtimes\") then\n        target:set(\"runtimes\", is_mode(\"debug\") and \"MDd\" or \"MD\")\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/qt/moc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"qt.moc\")\n    add_deps(\"qt.env\")\n    add_orders(\"qt.ui\", \"qt.moc\")\n    set_extensions(\".h\", \".hpp\")\n\n    on_config(function (target)\n        import(\"lib.detect.find_file\")\n\n        -- get qt\n        local qt = assert(target:data(\"qt\"), \"Qt not found!\")\n\n        -- get moc\n        local search_dirs = {}\n        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n        if qt.bindir then table.insert(search_dirs, qt.bindir) end\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local moc = find_file(is_host(\"windows\") and \"moc.exe\" or \"moc\", search_dirs)\n        assert(moc and os.isexec(moc), \"moc not found!\")\n\n        -- save moc\n        target:data_set(\"qt.moc\", moc)\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        import(\"core.tool.compiler\")\n\n        local moc = target:data(\"qt.moc\")\n\n        -- get c++ source file for moc\n        --\n        -- add_files(\"mainwindow.h\") -> moc_MainWindow.cpp\n        -- add_files(\"mainwindow.cpp\", {rules = \"qt.moc\"}) -> mainwindow.moc, @see https://github.com/xmake-io/xmake/issues/750\n        --\n        local basename = path.basename(sourcefile)\n        local filename_moc = \"moc_\" .. basename .. \".cpp\"\n        if sourcefile:endswith(\".cpp\") then\n            filename_moc = basename .. \".moc\"\n        end\n        -- we need to retain the file directory structure, @see https://github.com/xmake-io/xmake/issues/2343\n        local sourcefile_moc = target:autogenfile(path.join(path.directory(sourcefile), filename_moc))\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_moc)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.qt.moc %s\", sourcefile)\n\n        -- get values from target\n        -- @see https://github.com/xmake-io/xmake/issues/3930\n        local function _get_values_from_target(target, name)\n            local values = {}\n            for _, value in ipairs((target:get_from(name, \"*\"))) do\n                table.join2(values, value)\n            end\n            return table.unique(values)\n        end\n\n        -- generate c++ source file for moc\n        local flags = {}\n        table.join2(flags, compiler.map_flags(\"cxx\", \"define\", _get_values_from_target(target, \"defines\")))\n        local pathmaps = {\n            {\"includedirs\", \"includedir\"},\n            {\"sysincludedirs\", \"includedir\"}, -- for now, moc process doesn't support MSVC external includes flags and will fail\n            {\"frameworkdirs\", \"frameworkdir\"}\n        }\n        for _, pathmap in ipairs(pathmaps) do\n            for _, item in ipairs(_get_values_from_target(target, pathmap[1])) do\n                local pathitem = path(item, function (p)\n                    local item = table.unwrap(compiler.map_flags(\"cxx\", pathmap[2], p))\n                    if item then\n                        -- we always need use '/' to fix it for project generator, because it will use path.translate in cl.lua\n                        item = item:gsub(\"\\\\\", \"/\")\n                    end\n                    return item\n                end)\n                if not pathitem:empty() then\n                    table.insert(flags, pathitem)\n                end\n            end\n        end\n        local user_flags = target:get(\"qt.moc.flags\") or {}\n        batchcmds:mkdir(path.directory(sourcefile_moc))\n        batchcmds:vrunv(moc, table.join(user_flags, flags, path(sourcefile), \"-o\", path(sourcefile_moc)))\n\n        -- we need to compile this moc_xxx.cpp file if exists Q_PRIVATE_SLOT, @see https://github.com/xmake-io/xmake/issues/750\n        local mocdata = io.readfile(sourcefile)\n        if mocdata and mocdata:find(\"Q_PRIVATE_SLOT\") or sourcefile_moc:endswith(\".moc\") then\n            -- add includedirs of sourcefile_moc\n            target:add(\"includedirs\", path.directory(sourcefile_moc))\n\n            -- remove the object file of sourcefile_moc\n            local objectfiles = target:objectfiles()\n            for idx, objectfile in ipairs(objectfiles) do\n                if objectfile == target:objectfile(sourcefile_moc) then\n                    table.remove(objectfiles, idx)\n                    break\n                end\n            end\n            batchcmds:set_depmtime(os.mtime(sourcefile_moc))\n            batchcmds:set_depcache(target:dependfile(sourcefile_moc))\n        else\n            -- compile c++ source file for moc\n            batchcmds:compile(sourcefile_moc, objectfile)\n            batchcmds:set_depmtime(os.mtime(objectfile))\n            batchcmds:set_depcache(target:dependfile(objectfile))\n        end\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile)\n    end)\n"
  },
  {
    "path": "xmake/rules/qt/qmltyperegistrar/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      arthapz\n-- @file        xmake.lua\n--\n\nrule(\"qt.qmltyperegistrar\")\n    add_deps(\"qt.env\")\n    set_extensions(\".h\", \".hpp\")\n\n    on_config(function(target)\n        import(\"lib.detect.find_file\")\n\n        -- get qt\n        local qt = assert(target:data(\"qt\"), \"Qt not found!\")\n\n        -- get qmltyperegistrar\n        local search_dirs = {}\n        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n        if qt.bindir then table.insert(search_dirs, qt.bindir) end\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local qmltyperegistrar = find_file(is_host(\"windows\") and \"qmltyperegistrar.exe\" or \"qmltyperegistrar\", search_dirs)\n        assert(qmltyperegistrar and os.isexec(qmltyperegistrar), \"qmltyperegistrar not found!\")\n\n        -- set targetdir\n        local importname = target:values(\"qt.qmlplugin.import_name\")\n        assert(importname, \"QML plugin import name not set\")\n\n        local targetdir = target:targetdir()\n        for _, dir in ipairs(importname:split(\".\", {plain = true})) do\n            targetdir = path.join(targetdir, dir)\n        end\n        os.mkdir(targetdir)\n        target:set(\"targetdir\", targetdir)\n\n        -- add qmldir\n        local qmldir = target:values(\"qt.qmlplugin.qmldirfile\")\n        if qmldir then\n            target:add(\"installfiles\", path.join(target:scriptdir(), qmldir), { prefixdir = path.join(\"bin\", table.unpack(importname:split(\".\", { plain = true }))) })\n        end\n\n        -- add qmltypes\n        target:add(\"installfiles\", path.join(targetdir, \"plugin.qmltypes\"), { prefixdir = path.join(\"bin\", table.unpack(importname:split(\".\", { plain = true }))) })\n\n        local genbasename = path.join(target:autogendir(), \"rules\", \"qt\", \"qmltyperegistrar\", target:name())\n        local metatypesfile = genbasename .. \"_metatypes.json\"\n        local sourcefile = genbasename .. \"_qmltyperegistrations.cpp\"\n        local sourcefile_dir = path.directory(sourcefile)\n        os.mkdir(sourcefile_dir)\n        target:data_set(\"qt.qmlplugin.metatypesfile\", metatypesfile)\n        target:data_set(\"qt.qmlplugin.sourcefile\", sourcefile)\n\n        -- add moc arguments\n        target:add(\"qt.moc.flags\", \"--output-json\")\n\n        -- save qmltyperegistrar\n        target:data_set(\"qt.qmltyperegistrar\", qmltyperegistrar)\n        -- save qmltyperegistrar\n        target:data_set(\"qt.qmlplugin.qmltyperegistrar\", qmltyperegistrar)\n     end)\n\n     on_buildcmd_files(function(target, batchcmds, sourcebatch, opt)\n        -- setup qmltyperegistrar arguments\n        local moc = target:data(\"qt.moc\")\n        local qmltyperegistrar = target:data(\"qt.qmltyperegistrar\")\n        local metatypesfile = target:data(\"qt.qmlplugin.metatypesfile\")\n        local sourcefile = target:data(\"qt.qmlplugin.sourcefile\")\n\n        local importname = target:values(\"qt.qmlplugin.import_name\")\n        local majorversion = target:values(\"qt.qmlplugin.majorversion\") or 1\n        local minorversion = target:values(\"qt.qmlplugin.minorversion\") or 0\n\n        local metatype_files = {}\n        for _, mocedfile in ipairs(sourcebatch.sourcefiles) do\n            target:add(\"includedirs\", path.directory(mocedfile))\n            local basename = path.basename(mocedfile)\n            local filename_moc = \"moc_\" .. basename .. \".cpp\"\n            if mocedfile:endswith(\".cpp\") then\n                filename_moc = basename .. \".moc\"\n            end\n            local sourcefile_moc = target:autogenfile(path.join(path.directory(mocedfile), filename_moc))\n            table.insert(metatype_files, path(sourcefile_moc .. \".json\"))\n        end\n\n        -- generate a common metatypes.json file\n        -- @see https://github.com/xmake-io/xmake/issues/6647\n        local moc_args = {\n            \"--collect-json\",\n            \"-o\", path(metatypesfile)\n        }\n        batchcmds:show_progress(opt.progress, \"${color.build.object}generating.qt.qmltyperegistrar %s\", path.filename(metatypesfile))\n        batchcmds:vrunv(moc, table.join(moc_args, metatype_files))\n\n        -- gen sourcefile\n        local targetdir = target:targetdir()\n        local args = {\n            \"--generate-qmltypes=\" .. path(path.join(targetdir, \"plugin.qmltypes\")),\n            \"--import-name=\" .. importname,\n            \"--major-version=\" .. majorversion,\n            \"--minor-version=\" .. minorversion,\n            \"-o\", path(sourcefile),\n            path(metatypesfile)\n        }\n        batchcmds:show_progress(opt.progress, \"${color.build.object}generating.qt.qmltyperegistrar %s\", path.filename(sourcefile))\n        batchcmds:vrunv(qmltyperegistrar, args)\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- compile sourcefile\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.qt.qmltyperegistrar %s\", path.filename(sourcefile))\n        batchcmds:compile(sourcefile, objectfile)\n\n        batchcmds:add_depvalues(importname, majorversion, minorversion)\n        batchcmds:add_depfiles(sourcefile, sourcebatch.sourcefiles)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n    after_build(function(target)\n        local qmldir = target:values(\"qt.qmlplugin.qmldirfile\")\n        if qmldir then\n            os.cp(path.join(target:scriptdir(), qmldir), target:targetdir())\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/qt/qrc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"qt.qrc\")\n    add_deps(\"qt.env\")\n    set_extensions(\".qrc\")\n    on_config(function (target)\n        import(\"lib.detect.find_file\")\n\n        -- get rcc\n        local qt = assert(target:data(\"qt\"), \"Qt not found!\")\n        local search_dirs = {}\n        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n        if qt.bindir then table.insert(search_dirs, qt.bindir) end\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local rcc = find_file(is_host(\"windows\") and \"rcc.exe\" or \"rcc\", search_dirs)\n        assert(os.isexec(rcc), \"rcc not found!\")\n\n        -- save rcc\n        target:data_set(\"qt.rcc\", rcc)\n    end)\n\n    on_buildcmd_file(function (target, batchcmds, sourcefile_qrc, opt)\n\n        -- get rcc\n        local rcc = target:data(\"qt.rcc\")\n\n        -- get c++ source file for qrc\n        local sourcefile_cpp = path.join(target:autogendir(), \"rules\", \"qt\", \"qrc\", path.basename(sourcefile_qrc).. \"_\" .. hash.strhash32(sourcefile_qrc) .. \".cpp\")\n        local sourcefile_dir = path.directory(sourcefile_cpp)\n\n        -- add objectfile\n        local objectfile = target:objectfile(sourcefile_cpp)\n        table.insert(target:objectfiles(), objectfile)\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.qt.qrc %s\", sourcefile_qrc)\n        batchcmds:mkdir(sourcefile_dir)\n        batchcmds:vrunv(rcc, {\"-name\", path.basename(sourcefile_qrc), path(sourcefile_qrc), \"-o\", path(sourcefile_cpp)})\n        batchcmds:compile(sourcefile_cpp, objectfile)\n\n        -- get qrc resources files\n        local outdata = os.iorunv(rcc, {\"-name\", path.basename(sourcefile_qrc), sourcefile_qrc, \"-list\"})\n\n        -- add resources files to batch\n        for _, file in ipairs(outdata:split(\"\\n\")) do\n            batchcmds:add_depfiles(file)\n        end\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_qrc)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/qt/ts/xmake.lua",
    "content": "rule(\"qt.ts\")\n    add_deps(\"qt.env\")\n    set_extensions(\".ts\")\n\n    on_config(function (target)\n        import(\"lib.detect.find_file\")\n        import(\"core.base.json\")\n\n        -- get source file\n        local lupdate_argv = {\"-no-obsolete\"}\n        local sourcefile_ts\n        local source_files = {}\n        for _, sourcebatch in pairs(target:sourcebatches()) do\n            if sourcebatch.rulename == \"qt.ts\" then\n                sourcefile_ts = sourcebatch.sourcefiles\n            else\n                if sourcebatch.sourcefiles then\n                    for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                        table.insert(source_files, sourcefile)\n                    end\n                end\n            end\n        end\n        if sourcefile_ts and #source_files > 0 then\n            -- save source files\n            source_files = table.unique(source_files)\n            local json_data = {\n                projectFile = \"\",\n                sources = source_files\n            }\n\n            local json_path = path.join(target:autogendir(), \"rules\", \"qt\", \"ts\", \"sources.json\")\n            json.savefile(json_path, json_data)\n\n            table.join2(lupdate_argv, {\"-project\", path(json_path)})\n\n            -- get lupdate and lrelease\n            local qt = assert(target:data(\"qt\"), \"qt not found!\")\n\n            local search_dirs = {}\n            if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n            if qt.bindir then table.insert(search_dirs, qt.bindir) end\n            if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n            if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n\n            local lupdate = find_file(is_host(\"windows\") and \"lupdate.exe\" or \"lupdate\", search_dirs)\n            assert(os.isexec(lupdate), \"lupdate not found!\")\n\n            local lrelease = find_file(is_host(\"windows\") and \"lrelease.exe\" or \"lrelease\", search_dirs)\n            assert(os.isexec(lrelease), \"lrelease not found!\")\n\n            for _, tsfile in ipairs(sourcefile_ts) do\n                local tsargv = {}\n                table.join2(tsargv, lupdate_argv)\n                table.join2(tsargv, {\"-ts\", path(tsfile)})\n                os.vrunv(lupdate, tsargv)\n            end\n            -- save lrelease\n            target:data_set(\"qt.ts.lrelease\", lrelease)\n        end\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile_ts, opt)\n        -- get lrelease\n        local lrelease = target:data(\"qt.ts.lrelease\")\n        local outputdir = target:targetdir()\n        local fileconfig = target:fileconfig(sourcefile_ts)\n        if fileconfig and fileconfig.prefixdir then\n            if path.is_absolute(fileconfig.prefixdir) then\n                outputdir = fileconfig.prefixdir\n            else\n                outputdir = path.join(target:targetdir(), fileconfig.prefixdir)\n            end\n        end\n        local outfile = path.join(outputdir, path.basename(sourcefile_ts) .. \".qm\")\n        batchcmds:mkdir(outputdir)\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.qt.ts %s\", sourcefile_ts)\n        batchcmds:vrunv(lrelease, {path(sourcefile_ts), \"-qm\", path(outfile)})\n        batchcmds:add_depfiles(sourcefile_ts)\n    end)\n"
  },
  {
    "path": "xmake/rules/qt/ui/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"qt.ui\")\n    add_deps(\"qt.env\")\n    set_extensions(\".ui\")\n    on_config(function (target)\n        import(\"lib.detect.find_file\")\n\n        -- get uic\n        local qt = assert(target:data(\"qt\"), \"Qt not found!\")\n        local search_dirs = {}\n        if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end\n        if qt.bindir then table.insert(search_dirs, qt.bindir) end\n        if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end\n        if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end\n        local uic = find_file(is_host(\"windows\") and \"uic.exe\" or \"uic\", search_dirs)\n        assert(uic and os.isexec(uic), \"uic not found!\")\n\n        -- add includedirs, @note we need to create this directory first to suppress warning (file not found).\n        -- and we muse add it in load stage to ensure `depend.on_changed` work.\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/1180\n        --\n        local headerfile_dir = path.join(target:autogendir(), \"rules\", \"qt\", \"ui\")\n        if not os.isdir(headerfile_dir) then\n            os.mkdir(headerfile_dir)\n        end\n        target:add(\"includedirs\", path.absolute(headerfile_dir, os.projectdir()))\n\n        -- save uic\n        target:data_set(\"qt.uic\", uic)\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile_ui, opt)\n        local uic = target:data(\"qt.uic\")\n        local headerfile_dir = path.join(target:autogendir(), \"rules\", \"qt\", \"ui\")\n        local headerfile_ui = path.join(headerfile_dir, \"ui_\" .. path.basename(sourcefile_ui) .. \".h\")\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.qt.ui %s\", sourcefile_ui)\n        batchcmds:mkdir(headerfile_dir)\n        batchcmds:vrunv(uic, {path(sourcefile_ui), \"-o\", path(headerfile_ui)})\n        batchcmds:add_depfiles(sourcefile_ui)\n        batchcmds:set_depmtime(os.mtime(headerfile_ui))\n        batchcmds:set_depcache(target:dependfile(headerfile_ui))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/qt/uninstallcmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstallcmd.lua\n--\n\n-- uninstall application for xpack\nfunction main(target, batchcmds, opt)\n    local package = opt.package\n\n    -- only for xpack (package exists)\n    if not package then\n        return\n    end\n\n    -- get install directory\n    local installdir = package:installdir()\n    if not installdir then\n        return\n    end\n\n    -- macOS: uninstall .app bundle\n    if target:is_plat(\"macosx\") then\n        local target_app = path.join(target:targetdir(), target:basename() .. \".app\")\n        if os.isdir(target_app) then\n            -- remove .app from install directory\n            local appname = path.filename(target_app)\n            local dstappdir = path.join(installdir, appname)\n            batchcmds:rmdir(dstappdir, {emptydirs = true})\n        end\n    elseif target:is_plat(\"windows\", \"mingw\") then\n        -- Windows/Mingw: remove all deployed files and directories from install directory\n        local installdir = package:installdir()\n        \n        -- use the same deploydir as installcmd to determine what files were installed\n        -- deploydir exists at build/pack time when uninstallcmd is called\n        local deploydir = path.join(target:autogendir(), \"qt\", \"deploy\", target:name())\n        \n        -- if deploydir exists, use it to get the list of files/dirs to remove\n        if os.isdir(deploydir) then\n            -- match all files and directories in deploydir (same as installcmd)\n            for _, item in ipairs(os.filedirs(path.join(deploydir, \"*\"))) do\n                local relpath = path.relative(item, deploydir)\n                local dstpath = path.join(installdir, relpath)\n                if os.isfile(item) then\n                    batchcmds:rm(dstpath, {emptydirs = true})\n                elseif os.isdir(item) then\n                    batchcmds:rmdir(dstpath, {emptydirs = true})\n                end\n            end\n        else\n            -- fallback: if deploydir doesn't exist, remove common Qt deployment items\n            -- this should rarely happen, but provides a safety net\n            batchcmds:rm(path.join(installdir, target:filename()), {emptydirs = true})\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:rule(\"qt.shared\") then\n                    batchcmds:rm(path.join(installdir, path.filename(dep:targetfile())), {emptydirs = true})\n                end\n            end\n            -- note: we can't easily remove all deployed files without deploydir,\n            -- but at least we remove the main binaries\n        end\n    else\n        -- Linux: remove all files from bin directory\n        local bindir = target:bindir()\n        if bindir and os.isdir(bindir) then\n            local package_bindir = package:installdir(\"bin\")\n            -- remove all files and directories from package bindir\n            for _, item in ipairs(os.filedirs(path.join(package_bindir, \"*\"))) do\n                if os.isfile(item) then\n                    batchcmds:rm(item, {emptydirs = true})\n                elseif os.isdir(item) then\n                    batchcmds:rmdir(item, {emptydirs = true})\n                end\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/qt/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: qt/wasm application\nrule(\"qt._wasm_app\")\n    add_deps(\"qt.env\")\n    after_build(\"build_qt_wasm_app\")\n\n-- define rule: qt static library\nrule(\"qt.static\")\n    add_deps(\"qt.qrc\", \"qt.ui\", \"qt.moc\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", \"static\")\n    end)\n\n    on_config(function (target)\n        import(\"load\")(target, {frameworks = {\"QtCore\"}})\n    end)\n\n-- define rule: qt shared library\nrule(\"qt.shared\")\n    add_deps(\"qt.qrc\", \"qt.ui\", \"qt.moc\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", \"shared\")\n    end)\n\n    on_config(function (target)\n        import(\"load\")(target, {frameworks = {\"QtCore\"}})\n    end)\n\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n-- define rule: qt console\nrule(\"qt.console\")\n    add_deps(\"qt.qrc\", \"qt.ui\", \"qt.moc\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", \"binary\")\n    end)\n\n    on_config(function (target)\n        import(\"load\")(target, {frameworks = {\"QtCore\"}})\n    end)\n\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n-- define rule: qt widgetapp\nrule(\"qt.widgetapp\")\n    add_deps(\"qt.ui\", \"qt.moc\", \"qt._wasm_app\", \"qt.qrc\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", target:is_plat(\"android\") and \"shared\" or \"binary\")\n    end)\n\n    on_config(function (target)\n\n        -- get qt sdk version\n        local qt = target:data(\"qt\")\n        local qt_sdkver = nil\n        if qt.sdkver then\n            import(\"core.base.semver\")\n            qt_sdkver = semver.new(qt.sdkver)\n        end\n\n        local frameworks = {\"QtGui\", \"QtWidgets\", \"QtCore\"}\n        if qt_sdkver and qt_sdkver:lt(\"5.0\") then\n            frameworks = {\"QtGui\", \"QtCore\"} -- qt4.x has not QtWidgets, it is in QtGui\n        end\n        import(\"load\")(target, {gui = true, frameworks = frameworks})\n    end)\n\n    -- deploy application\n    after_build(\"android\", \"deploy.android\")\n    after_build(\"macosx\", \"deploy.macosx\")\n\n    -- install application for android\n    on_install(\"android\", \"install.android\")\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n    -- install application for xpack\n    on_installcmd(\"installcmd\")\n    on_uninstallcmd(\"uninstallcmd\")\n\n-- define rule: qt static widgetapp\nrule(\"qt.widgetapp_static\")\n    add_deps(\"qt.ui\", \"qt.moc\", \"qt._wasm_app\", \"qt.qrc\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", target:is_plat(\"android\") and \"shared\" or \"binary\")\n    end)\n\n    on_config(function (target)\n        local frameworks, plugins, qt_sdkver = import(\"config_static\")(target)\n        if qt_sdkver:ge(\"5.0\") then\n            table.join2(frameworks, {\"QtGui\", \"QtWidgets\", \"QtCore\"})\n        else\n            table.join2(frameworks, {\"QtGui\", \"QtCore\"})-- qt4.x has not QtWidgets, it is in QtGui\n        end\n        import(\"load\")(target, {gui = true, plugins = plugins, frameworks = frameworks})\n    end)\n\n    -- deploy application\n    after_build(\"android\", \"deploy.android\")\n    after_build(\"macosx\", \"deploy.macosx\")\n\n    -- install application for android\n    on_install(\"android\", \"install.android\")\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n    -- install application for xpack\n    on_installcmd(\"installcmd\")\n    on_uninstallcmd(\"uninstallcmd\")\n\n-- define rule: qt quickapp\nrule(\"qt.quickapp\")\n    add_deps(\"qt.qrc\", \"qt.moc\", \"qt._wasm_app\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", target:is_plat(\"android\") and \"shared\" or \"binary\")\n    end)\n\n    on_config(function (target)\n        import(\"load\")(target, {gui = true, frameworks = {\"QtGui\", \"QtQuick\", \"QtQml\", \"QtCore\", \"QtNetwork\"}})\n    end)\n\n    -- deploy application\n    after_build(\"android\", \"deploy.android\")\n    after_build(\"macosx\", \"deploy.macosx\")\n\n    -- install application for android\n    on_install(\"android\", \"install.android\")\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n    -- install application for xpack\n    on_installcmd(\"installcmd\")\n    on_uninstallcmd(\"uninstallcmd\")\n\n-- define rule: qt static quickapp\nrule(\"qt.quickapp_static\")\n    add_deps(\"qt.qrc\", \"qt.moc\", \"qt._wasm_app\", \"qt.ts\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n        target:set(\"kind\", target:is_plat(\"android\") and \"shared\" or \"binary\")\n    end)\n\n    on_config(function (target)\n        local frameworks, plugins = import(\"config_static\")(target)\n        table.join2(frameworks, {\"QtGui\", \"QtQuick\", \"QtQml\", \"QtQmlModels\", \"QtCore\", \"QtNetwork\"})\n        import(\"load\")(target, {gui = true, plugins = plugins, frameworks = frameworks})\n    end)\n\n    -- deploy application\n    after_build(\"android\", \"deploy.android\")\n    after_build(\"macosx\", \"deploy.macosx\")\n\n    -- install application for android\n    on_install(\"android\", \"install.android\")\n    after_install(\"windows\", \"install.windows\")\n    after_install(\"mingw\", \"install.mingw\")\n\n    -- install application for xpack\n    on_installcmd(\"installcmd\")\n    on_uninstallcmd(\"uninstallcmd\")\n\n-- define rule: qt qmlplugin\nrule(\"qt.qmlplugin\")\n    add_deps(\"qt.shared\", \"qt.qmltyperegistrar\", \"qt.ts\")\n    on_config(function(target)\n        import(\"load\")(target, {frameworks = { \"QtCore\", \"QtGui\", \"QtQuick\", \"QtQml\", \"QtNetwork\" }})\n    end)\n\n-- define rule: qt application (deprecated)\nrule(\"qt.application\")\n    add_deps(\"qt.quickapp\", \"qt.ui\")\n"
  },
  {
    "path": "xmake/rules/rust/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- generate bridge.rs.cc/h to call rust library in c++ code\n-- @see https://cxx.rs/build/other.html\nrule(\"rust.cxxbridge\")\n    set_extensions(\".rsx\")\n    on_load(function (target)\n        if not target:get(\"languages\") then\n            target:set(\"languages\", \"c++11\")\n        end\n    end)\n    before_buildcmd_file(\"build.cxxbridge\")\n\nrule(\"rust.build\")\n    set_sourcekinds(\"rc\")\n    on_load(function (target)\n        -- set cratename\n        local cratename = target:values(\"rust.cratename\") or target:name()\n        target:set(\"basename\", cratename)\n        -- set cratetype\n        local cratetype = target:values(\"rust.cratetype\")\n        if cratetype == \"staticlib\" then\n            assert(target:is_static(), \"target(%s) must be static kind for cratetype(staticlib)!\", target:name())\n            target:add(\"arflags\", \"--crate-type=staticlib\")\n            target:data_set(\"inherit.links.exportlinks\", false)\n        elseif cratetype == \"cdylib\" then\n            assert(target:is_shared(), \"target(%s) must be shared kind for cratetype(cdylib)!\", target:name())\n            target:add(\"shflags\", \"--crate-type=cdylib\", {force = true})\n            target:add(\"shflags\", \"-C prefer-dynamic\", {force = true})\n        elseif target:is_static() then\n            cratetype = \"lib\"\n            target:set(\"values\", \"rust.cratetype\", cratetype)\n            if is_plat(\"windows\") then\n                target:set(\"prefixname\", \"lib\")\n            end\n            target:set(\"extension\", \".rlib\")\n            target:add(\"arflags\", \"--crate-type=\" .. cratetype, {force = true})\n            target:data_set(\"inherit.links.deplink\", false)\n        elseif target:is_shared() then\n            cratetype = \"dylib\"\n            target:set(\"values\", \"rust.cratetype\", cratetype)\n            target:add(\"shflags\", \"--crate-type=\" .. cratetype, {force = true})\n            -- fix cannot satisfy dependencies so `std` only shows up once\n            -- https://github.com/rust-lang/rust/issues/19680\n            --\n            -- but it will link dynamic @rpath/libstd-xxx.dylib,\n            -- so we can no longer modify and set other rpath paths\n            target:add(\"shflags\", \"-C prefer-dynamic\", {force = true})\n            -- don't add links and instead use --extern CRATE[=PATH]\n            -- also, it'll automatically link from linkdirs (-L) even if no --extern\n            -- https://github.com/xmake-io/xmake/issues/6604\n            target:data_set(\"inherit.links.deplink\", false)\n        elseif target:is_binary() then\n            cratetype = \"bin\"\n            target:set(\"values\", \"rust.cratetype\", cratetype)\n            target:add(\"ldflags\", \"--crate-type=\" .. cratetype, {force = true})\n        end\n\n        -- set edition\n        local edition = target:values(\"rust.edition\") or \"2018\"\n        target:add(\"rcflags\", \"--edition\", edition, {force = true})\n\n        -- set abort panic for no_std\n        -- https://github.com/xmake-io/xmake/issues/4929\n        local no_std = false\n        local sourcebatch = target:sourcebatches()[\"rust.build\"]\n        if sourcebatch then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                local content = io.readfile(sourcefile)\n                if content and content:find(\"#![no_std]\", 1, true) then\n                    no_std = true\n                    break\n                end\n            end\n        end\n        if no_std then\n            target:add(\"rcflags\", \"-C panic=abort\", {force = true})\n        end\n    end)\n    on_build(\"build.target\")\n\n    on_config(function (target)\n        import(\"lib.detect.find_tool\")\n\n        -- Ensure libstd shared library is available when running\n        local rc = find_tool(\"rustc\")\n        assert(rc, \"rustc not found. Failed to add libstd in env\")\n        local outdata, errdata = os.iorunv(rc.program, {\"--print=sysroot\"})\n        assert(not errdata or errdata == \"\", \"failed to find rust sysroot:\\n\" .. errdata)\n        local rustc_sysroot = outdata:trim()\n        if target:is_plat(\"windows\") then\n            local libstd = path.join(rustc_sysroot, \"bin\")\n            target:add(\"runenvs\", \"PATH\", libstd)\n        elseif target:is_plat(\"macosx\") then\n            local libstd = path.join(rustc_sysroot, \"lib\")\n            target:add(\"runenvs\", \"DYLD_LIBRARY_PATH\", libstd)\n        else\n            local libstd = path.join(rustc_sysroot, \"lib\")\n            target:add(\"runenvs\", \"LD_LIBRARY_PATH\", libstd)\n        end\n    end)\n\nrule(\"rust\")\n    add_deps(\"rust.build\")\n    add_deps(\"utils.inherit.links\")\n"
  },
  {
    "path": "xmake/rules/swift/config/basic.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        basic.lua\n--\n\nfunction main(target)\n    local mode = (type(target:values(\"swift.interop\")) == \"string\") and target:values(\"swift.interop\") or \"objc\"\n    if mode == \"cxx\" then\n        target:add(\"scflags\", \"-cxx-interoperability-mode=default\")\n    end\n\n    if target:is_library() or target:values(\"swift.interop.cxxmain\") then\n        target:add(\"scflags\", \"-parse-as-library\")\n    end\n    local modulename = target:values(\"swift.modulename\") or target:name()\n    target:add(\"scflags\", \"-module-name\", modulename, {force = true})\n    -- we use swift-frontend to support multiple modules\n    -- @see https://github.com/xmake-io/xmake/issues/3916\n    if target:has_tool(\"sc\", \"swift_frontend\") then\n        local sourcebatch = target:sourcebatches()[\"swift.build\"]\n        if sourcebatch then\n            for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                target:add(\"scflags\", sourcefile, {force = true})\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/rules/swift/config/main.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        main.lua\n--\n\n-- imports\nimport(\"rules.swift.config.basic\", {rootdir = os.programdir(), alias = \"config_basic\"})\nimport(\"rules.c++.config.runtime\", {rootdir = os.programdir(), alias = \"config_runtime\"})\n\n-- main entry\nfunction main(target)\n\n    -- config basic configs\n    config_basic(target)\n\n    -- config runtime configs\n    config_runtime(target)\nend\n"
  },
  {
    "path": "xmake/rules/swift/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"swift.interop\")\n    set_sourcekinds(\"sc\")\n    add_orders(\"swift.interop\", \"swift.build\")\n    add_orders(\"swift.interop\", \"c++.build\")\n    on_config(function(target)\n        import(\"core.base.json\")\n\n        if not target:values(\"swift.interop\") then\n            target:rule_enable(\"swift.interop\", false)\n            return\n        end\n\n        local sourcebatches = target:sourcebatches()\n        local sourcebatch = sourcebatches and sourcebatches[\"swift.interop\"]\n        local sourcefiles = sourcebatch and sourcebatch.sourcefiles\n        sourcefiles = sourcefiles or {}\n        local enabled = false\n        for _, sourcefile in ipairs(sourcefiles) do\n            local fileconfig = target:fileconfig(sourcefile)\n            if fileconfig and fileconfig.public then\n                enabled = true\n                break\n            end\n        end\n        if not enabled then\n            target:rule_enable(\"swift.interop\", false)\n            return\n        end\n\n        local sc = target:tool(\"sc\")\n        assert(sc, \"No swift compiler found!\")\n        local outdata, errdata = os.iorunv(sc, {\"-print-target-info\"})\n        assert(outdata, errdata)\n\n        local target_info = json.decode(outdata)\n        assert(target_info and target_info.paths and target_info.paths.runtimeResourcePath, \"Failed to get swift resource path\")\n        target:add(\"includedirs\", target_info.paths.runtimeResourcePath, {public = true})\n\n        local outdir = target:autogendir(\"swift.interop\")\n        target:add(\"includedirs\", outdir, {public = true})\n\n        local mode = (type(target:values(\"swift.interop\")) == \"string\") and target:values(\"swift.interop\") or \"objc\"\n\n        local headername = (target:values(\"swift.interop.headername\") or (target:name() .. \"-Swift.h\"))\n        local header = path.join(outdir, headername)\n        target:add(\"headerfiles\", header)\n\n        target:data_set(\"swift.interop\", mode)\n        target:data_set(\"swift.interop.outdir\", outdir)\n    end)\n\n    on_prepare_files(function(target, jobgraph, sourcebatch, opt)\n        import(\"utils.progress\")\n        import(\"core.base.option\")\n        import(\"core.tool.compiler\")\n        import(\"core.project.depend\")\n\n        local function _get_target_cpp_langflags()\n            local cpp_langflags = _g.cpp_langflags\n            if cpp_langflags == nil then\n                local languages = target:get(\"languages\")\n                for _, language in ipairs(languages) do\n                    if language:startswith(\"c++\")\n                        or language:startswith(\"cxx\")\n                        or language:startswith(\"gnu++\")\n                        or language:startswith(\"gnuxx\") then\n                        -- c++26 currently prevent compilation of swift modules\n                        language = language:gsub(\"26\", \"23\"):gsub(\"latest\", \"23\")\n                        cpp_langflags = compiler.map_flags(\"cxx\", \"language\", language, {target = target})\n                        _g.cpp_langflags = cpp_langflags or false\n                    end\n                end\n            end\n            return cpp_langflags or nil\n        end\n\n        local mode = target:data(\"swift.interop\")\n        local sc = target:compiler(\"sc\")\n        assert(sc, \"No swift compiler found!\")\n        local outdir = target:data(\"swift.interop.outdir\")\n        if not os.isdir(outdir) then os.mkdir(outdir) end\n        assert(outdir)\n\n        local sourcefiles = sourcebatch.sourcefiles\n        local public_sourcefiles\n        for _, sourcefile in ipairs(sourcefiles) do\n            local fileconfig = target:fileconfig(sourcefile)\n            if fileconfig and fileconfig.public then\n                public_sourcefiles = public_sourcefiles or {}\n                table.insert(public_sourcefiles, sourcefile)\n            end\n        end\n\n        if public_sourcefiles then\n            local modulename = target:values(\"swift.modulename\") or target:name()\n            local headername = (target:values(\"swift.interop.headername\") or (target:name() .. \"-Swift.h\"))\n            local header = path.join(outdir, headername)\n\n            jobgraph:add(target:fullname() .. \"/gen_swift_header\", function(index, total, opt)\n                depend.on_changed(function()\n                    local stdflag\n                    if mode == \"cxx\" then\n                        local cpp_langflags = _get_target_cpp_langflags()\n                        if cpp_langflags then\n                            for _, flag in ipairs(cpp_langflags) do\n                                stdflag = stdflag or {}\n                                table.join2(stdflag, {\"-Xcc\", flag})\n                            end\n                        end\n                    end\n\n                    if opt.progress then\n                        progress.show(opt.progress, \"${clear}generating.swift.header %s\", headername)\n                    end\n\n                    local _scflags = sc:compflags({target = target, sourcekind = \"sc\"})\n                    local scflags\n                    if target:has_tool(\"sc\", \"swift_frontend\") then\n                        for _, scflag in ipairs(_scflags) do\n                            scflags = scflags or {}\n                            if not os.isfile(scflag) then\n                                table.insert(scflags, scflag)\n                            end\n                        end\n                    else\n                        scflags = _scflags\n                    end\n\n                    local emit_flag = mode == \"cxx\" and \"-emit-clang-header-path\" or \"-emit-objc-header-path\"\n\n                    local flags = table.join({\n                        \"-frontend\",\n                        \"-typecheck\",\n                        emit_flag,\n                        header,\n                        },\n                        scflags or {},\n                        stdflag or {},\n                        public_sourcefiles)\n                    if option.get(\"verbose\") then\n                        print(os.args(table.join(sc:program(), flags)))\n                    end\n\n                    os.tryrm(header)\n                    local outdata, errdata = os.iorunv(sc:program(), flags)\n                    assert(outdata, errdata)\n                end, {\n                    files = public_sourcefiles,\n                    changed = target:is_rebuilt() or not os.isfile(header),\n                })\n            end)\n        end\n    end, { jobgraph = true })\n\n-- define rule: swift.build\nrule(\"swift.build\")\n    set_sourcekinds(\"sc\")\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n    on_config(function (target)\n        import(\"config\")(target)\n    end)\n\n-- define rule: swift\nrule(\"swift\")\n    -- add build rules\n    add_deps(\"swift.interop\")\n\n    -- add build rules\n    add_deps(\"swift.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` to merge object files to target\n    add_deps(\"utils.merge.object\")\n\n    -- add linker rules\n    add_deps(\"linker\")\n"
  },
  {
    "path": "xmake/rules/swig/build_module_file.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build_module_file.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"utils.progress\")\nimport(\"core.project.depend\")\nimport(\"core.tool.compiler\")\n\nfunction find_user_outdir(fileconfig)\n    -- user specified output path\n    if fileconfig and fileconfig.swigflags then\n        -- find -outdir path\n        for i, par in ipairs(fileconfig.swigflags) do\n            if par == \"-outdir\" then\n                local dirpath = fileconfig.swigflags[i + 1]\n                if os.isdir(dirpath) then\n                    return dirpath\n                end\n            end\n        end\n    end\nend\n\nfunction jar_build(target, fileconfig, opt)\n    local javac = assert(find_tool(\"javac\"), \"javac not found!\")\n    local jar = assert(find_tool(\"jar\"), \"jar not found!\")\n\n    local java_src_dir = path.join(target:autogendir(), \"rules\", \"swig\")\n    local java_class_dir = java_src_dir\n\n    local user_outdir = find_user_outdir(fileconfig)\n    if user_outdir then\n        java_src_dir = user_outdir\n    end\n\n    -- get java files\n    local autogenfiles = os.files(path.join(java_src_dir, \"*.java\"))\n\n    -- write file list\n    local filelistname = path.join(java_src_dir, \"buildlist.txt\")\n    local file = io.open(filelistname, \"w\")\n    if file then\n        for _, sourcebatch in ipairs(autogenfiles) do\n            file:print(sourcebatch)\n        end\n        file:close()\n    end\n\n    -- compile to class file\n    progress.show(opt.progress, \"${color.build.object}compiling.javac %s class file\", target:name())\n    local argv = {\"-d\", java_class_dir, \"@\" .. filelistname}\n    local java_release = target:extraconf(\"rules\", \"swig.c\", \"java_release\") or target:extraconf(\"rules\", \"swig.cpp\", \"java_release\")\n    if java_release then\n        table.insert(argv, 1, tostring(java_release))\n        table.insert(argv, 1, \"--release\")\n    end\n    os.vrunv(javac.program, argv)\n\n    -- generate jar file\n    progress.show(opt.progress, \"${color.build.object}compiling.jar %s\", target:name() .. \".jar\")\n    os.vrunv(jar.program, {\"-cf\", path.join(java_src_dir, target:name() .. \".jar\"), \"-C\", java_class_dir, \".\"})\n\n    os.tryrm(filelistname)\nend\n\nfunction swig_par(target, sourcefile, opt)\n    -- get swig\n    opt = opt or {}\n    local swig = assert(find_tool(\"swig\"), \"swig not found!\")\n    local sourcefile_cx = path.join(target:autogendir(), \"rules\", \"swig\",\n        path.basename(sourcefile) .. (opt.sourcekind == \"cxx\" and \".cpp\" or \".c\"))\n\n    -- add objectfile\n    local objectfile = target:objectfile(sourcefile_cx)\n    table.insert(target:objectfiles(), objectfile)\n\n    -- add commands\n    local moduletype = assert(target:data(\"swig.moduletype\"), \"swig.moduletype not found!\")\n    local argv = {\"-\" .. moduletype, \"-o\", sourcefile_cx}\n    if opt.sourcekind == \"cxx\" then\n        table.insert(argv, \"-c++\")\n    end\n    local fileconfig = target:fileconfig(sourcefile)\n    if fileconfig and fileconfig.swigflags then\n        table.join2(argv, fileconfig.swigflags)\n    end\n\n    -- add includedirs\n    local function _get_values_from_target(target, name)\n        local values = {}\n        for _, value in ipairs((target:get_from(name, \"*\"))) do\n            table.join2(values, value)\n        end\n        return table.unique(values)\n    end\n    local pathmaps = {\n        { \"includedirs\",    \"includedir\" },\n        { \"sysincludedirs\", \"includedir\" },\n        { \"frameworkdirs\",  \"frameworkdir\" }\n    }\n    for _, pathmap in ipairs(pathmaps) do\n        for _, item in ipairs(_get_values_from_target(target, pathmap[1])) do\n            table.join2(argv, \"-I\" .. item)\n        end\n    end\n\n    table.insert(argv, sourcefile)\n    return {\n        argv = argv,\n        objectfile = objectfile,\n        swig = swig,\n        sourcefile_cx = sourcefile_cx,\n        moduletype = moduletype,\n        fileconfig = fileconfig\n    }\nend\n\nfunction swig_build_cmd(target, batchcmds, sourcefile, opt, pars)\n    local par = swig_par(target, sourcefile, opt)\n\n    local objectfile = par.objectfile\n    local argv = par.argv\n    local swig = par.swig\n    local sourcefile_cx = par.sourcefile_cx\n    local moduletype = par.moduletype\n    local fileconfig = par.fileconfig\n\n    batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.swig.%s %s\", moduletype, sourcefile)\n    batchcmds:mkdir(path.directory(sourcefile_cx))\n    batchcmds:vrunv(swig.program, argv)\n    batchcmds:compile(sourcefile_cx, objectfile)\n\n    -- add deps\n    batchcmds:add_depfiles(sourcefile)\n    batchcmds:set_depmtime(os.mtime(objectfile))\n    batchcmds:set_depcache(target:dependfile(objectfile))\nend\n\nfunction swig_build_file(target, sourcefile, opt, par)\n    local par = swig_par(target, sourcefile, opt)\n\n    local objectfile = par.objectfile\n    local argv = par.argv\n    local swig = par.swig\n    local sourcefile_cx = par.sourcefile_cx\n    local moduletype = par.moduletype\n    local fileconfig = par.fileconfig\n\n    local dependfile = target:dependfile(objectfile)\n    local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n    if not depend.is_changed(dependinfo, {lastmtime = os.mtime(objectfile),\n                                          values = argv\n                                          }) then\n        return\n    end\n\n    progress.show(opt.progress, \"${color.build.object}compiling.swig.%s %s\", moduletype, sourcefile)\n    os.mkdir(path.directory(sourcefile_cx))\n\n    -- gen swig depend file , same with gcc .d\n    local swigdep = os.tmpfile()\n    local argv2 = {\"-MMD\", \"-MF\", swigdep}\n    table.join2(argv2, argv)\n\n    -- swig generate file and depend file\n    os.vrunv(swig.program, argv2)\n    compiler.compile(sourcefile_cx, objectfile, {target = target})\n\n    -- update depend file\n    local deps = io.readfile(swigdep, {continuation = \"\\\\\"})\n    os.tryrm(swigdep)\n    dependinfo.files = {sourcefile}\n    dependinfo.depfiles_format = \"gcc\"\n    dependinfo.depfiles = deps\n    dependinfo.values = argv\n    depend.save(dependinfo, target:dependfile(objectfile))\n\n    -- jar build\n    local buildjar = target:extraconf(\"rules\", \"swig.c\", \"buildjar\") or target:extraconf(\"rules\", \"swig.cpp\", \"buildjar\")\n    if moduletype == \"java\" and buildjar then\n        jar_build(target, fileconfig, opt)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/swig/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- references:\n--\n-- https://github.com/xmake-io/xmake/issues/1622\n-- http://www.swig.org/Doc4.0/SWIGDocumentation.html#Introduction_nn4\n--\n\nrule(\"swig.base\")\n    on_load(function (target)\n        target:set(\"kind\", \"shared\")\n        local find_user_outdir = import(\"build_module_file\").find_user_outdir\n        local moduletype = target:extraconf(\"rules\", \"swig.c\", \"moduletype\") or target:extraconf(\"rules\", \"swig.cpp\", \"moduletype\")\n        if moduletype == \"python\" then\n            target:set(\"prefixname\", \"_\")\n            local soabi = target:extraconf(\"rules\", \"swig.c\", \"soabi\") or target:extraconf(\"rules\", \"swig.cpp\", \"soabi\")\n            if soabi then\n                import(\"lib.detect.find_tool\")\n                local python = assert(find_tool(\"python3\"), \"python not found!\")\n                local result = try { function() return os.iorunv(python.program, {\"-c\", \"import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))\"}) end}\n                if result then\n                    result = result:trim()\n                    if result ~= \"None\" then\n                        target:set(\"extension\", result)\n                    end\n                end\n            else\n                if target:is_plat(\"windows\", \"mingw\") then\n                    target:set(\"extension\", \".pyd\")\n                end\n            end\n        elseif moduletype == \"lua\" then\n            target:set(\"prefixname\", \"\")\n            if not target:is_plat(\"windows\", \"mingw\")  then\n                target:set(\"extension\", \".so\")\n            end\n        elseif moduletype == \"java\" then\n            if target:is_plat(\"windows\", \"mingw\") then\n                target:set(\"prefixname\", \"\")\n                target:set(\"extension\", \".dll\")\n            elseif target:is_plat(\"macosx\") then\n                target:set(\"prefixname\", \"lib\")\n                target:set(\"extension\", \".dylib\")\n            elseif target:is_plat(\"linux\") then\n                target:set(\"prefixname\", \"lib\")\n                target:set(\"extension\", \".so\")\n            end\n        else\n            raise(\"unknown swig module type, please use `add_rules(\\\"swig.c\\\", {moduletype = \\\"python\\\"})` to set it!\")\n        end\n        local scriptfiles = {}\n        for _, sourcebatch in pairs(target:sourcebatches()) do\n            if sourcebatch.rulename:startswith(\"swig.\") then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    local scriptdir\n                    local fileconfig = target:fileconfig(sourcefile)\n                    if fileconfig then\n                        scriptdir = fileconfig.scriptdir\n                    end\n                    local autogenfiles\n                    local autogendir = path.join(target:autogendir(), \"rules\", \"swig\")\n\n                    local user_outdir = find_user_outdir(fileconfig)\n                    if user_outdir then\n                        autogendir = user_outdir\n                    end\n\n                    if moduletype == \"python\" then\n                        autogenfiles = os.files(path.join(autogendir, \"*.py\"))\n                    elseif moduletype == \"lua\" then\n                        autogenfiles = os.files(path.join(autogendir, \"*.lua\"))\n                    elseif moduletype == \"java\" then\n                        local buildjar = target:extraconf(\"rules\", \"swig.c\", \"buildjar\") or target:extraconf(\"rules\", \"swig.cpp\", \"buildjar\")\n                        if buildjar then\n                            autogenfiles = path.join(autogendir, target:name() .. \".jar\")\n                        else\n                            autogenfiles = os.files(path.join(autogendir, \"*.java\"))\n                        end\n                    end\n                    if autogenfiles then\n                        table.join2(scriptfiles, autogenfiles)\n                        if scriptdir then\n                            target:add(\"installfiles\", autogenfiles, {prefixdir = scriptdir})\n                        end\n                    end\n                end\n            end\n        end\n        -- for custom on_install/after_install, user can use it to install them\n        target:data_set(\"swig.scriptfiles\", scriptfiles)\n        target:data_set(\"swig.moduletype\", moduletype)\n    end)\n\nrule(\"swig.c\")\n    set_extensions(\".i\")\n    add_deps(\"swig.base\", \"c.build\")\n    on_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        import(\"build_module_file\").swig_build_cmd(target, batchcmds, sourcefile, table.join({sourcekind = \"cc\"}, opt))\n    end)\n    on_build_file(function (target, sourcefile, opt)\n        import(\"build_module_file\").swig_build_file(target, sourcefile, table.join({sourcekind = \"cc\"}, opt))\n    end)\n\nrule(\"swig.cpp\")\n    set_extensions(\".i\")\n    add_deps(\"swig.base\", \"c++.build\")\n    on_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        import(\"build_module_file\").swig_build_cmd(target, batchcmds, sourcefile, table.join({sourcekind = \"cxx\"}, opt))\n    end)\n    on_build_file(function (target, sourcefile, opt)\n        import(\"build_module_file\").swig_build_file(target, sourcefile, table.join({sourcekind = \"cxx\"}, opt))\n    end)\n\n\n"
  },
  {
    "path": "xmake/rules/utils/bin2c/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- generate header file from binary file\n--\n-- @param target        the target\n-- @param batchcmds     the batch commands\n-- @param binaryfile    the binary file path\n-- @param opt           the options\n--                       - progress: the progress callback\n--                       - linewidth: the line width for output (optional)\n--                       - nozeroend: disable null terminator (deprecated, for backward compatibility only)\n--                       - zeroend: enable null terminator (default: true, bin2c enables zeroend by default for compatibility)\n--                       - rulename: the rule name for getting extra config (default: utils.bin2c)\n--                       - headerfile: the output header file path (optional, auto-generated if not provided)\n--                       - headerdir: the header directory (optional, auto-generated if not provided)\n--\nfunction generate_headerfile(target, batchcmds, binaryfile, opt)\n    opt = opt or {}\n    local rulename = opt.rulename or \"utils.bin2c\"\n    local progress = opt.progress\n\n    -- get header directory and file\n    local headerdir = opt.headerdir\n    local headerfile = opt.headerfile\n    if not headerfile then\n        if not headerdir then\n            headerdir = path.join(target:autogendir(), \"rules\", \"utils\", \"bin2c\")\n        end\n        headerfile = path.join(headerdir, path.filename(binaryfile) .. \".h\")\n    else\n        headerdir = headerdir or path.directory(headerfile)\n    end\n\n    -- add includedirs\n    target:add(\"includedirs\", headerdir)\n\n    -- add commands\n    if progress then\n        batchcmds:show_progress(progress, \"${color.build.object}generating.bin2c %s\", binaryfile)\n    end\n    batchcmds:mkdir(headerdir)\n\n    -- build argv\n    local argv = {\"-i\", path(binaryfile), \"-o\", path(headerfile)}\n\n    -- get linewidth\n    local linewidth = opt.linewidth or target:extraconf(\"rules\", rulename, \"linewidth\")\n    if linewidth then\n        table.insert(argv, \"-w\")\n        table.insert(argv, tostring(linewidth))\n    end\n\n    -- get nozeroend/zeroend (check file-level config first, then rule-level config, then opt)\n    local fileconfig = target:fileconfig(binaryfile)\n    local nozeroend = nil\n    if fileconfig then\n        if fileconfig.nozeroend ~= nil then\n            nozeroend = fileconfig.nozeroend\n        elseif fileconfig.zeroend ~= nil then\n            nozeroend = not fileconfig.zeroend\n        end\n    end\n    if nozeroend == nil then\n        nozeroend = target:extraconf(\"rules\", rulename, \"nozeroend\") or false\n    end\n    -- also support zeroend in opt (inverse of nozeroend)\n    if opt.zeroend ~= nil then\n        nozeroend = not opt.zeroend\n    elseif opt.nozeroend ~= nil then\n        nozeroend = opt.nozeroend\n    end\n    if nozeroend then\n        table.insert(argv, \"--nozeroend\")\n    end\n\n    batchcmds:vlua(\"cli.binutils.bin2c\", argv)\n\n    return headerfile\nend\n\n"
  },
  {
    "path": "xmake/rules/utils/bin2c/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"utils.bin2c\")\n    set_extensions(\".bin\")\n    add_orders(\"utils.bin2c\", \"c++.build.modules.builder\")\n    on_load(function (target)\n        local headerdir = path.join(target:autogendir(), \"rules\", \"utils\", \"bin2c\")\n        if not os.isdir(headerdir) then\n            os.mkdir(headerdir)\n        end\n        target:add(\"includedirs\", headerdir)\n    end)\n    on_preparecmd_file(function (target, batchcmds, sourcefile_bin, opt)\n        import(\"rules.utils.bin2c.utils\", {alias = \"bin2c_utils\", rootdir = os.programdir()})\n\n        -- generate header file\n        local headerfile = bin2c_utils.generate_headerfile(target, batchcmds, sourcefile_bin, {\n            progress = opt.progress\n        })\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_bin)\n        batchcmds:set_depmtime(os.mtime(headerfile))\n        batchcmds:set_depcache(target:dependfile(headerfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/utils/bin2obj/utils.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        utils.lua\n--\n\n-- generate object file from binary file\n--\n-- @param target        the target\n-- @param batchcmds     the batch commands\n-- @param binaryfile    the binary file path\n-- @param opt           the options\n--                       - progress: the progress callback\n--                       - format: the object file format (coff, elf, macho), auto-detected if not provided\n--                       - symbol_prefix: the symbol prefix (default: _binary_)\n--                       - zeroend: append null terminator (default: false)\n--                       - rulename: the rule name for getting extra config (default: utils.bin2obj)\n--                       - objectfile: the output object file path (optional, auto-generated if not provided)\n--\nfunction generate_objectfile(target, batchcmds, binaryfile, opt)\n    opt = opt or {}\n    local rulename = opt.rulename or \"utils.bin2obj\"\n    local progress = opt.progress\n\n    -- check for cosmocc toolchain\n    local is_cosmocc = target:toolchain(\"cosmocc\") or (target:has_tool(\"cc\", \"cosmocc\") and target:has_tool(\"ar\", \"cosmoar\"))\n\n    -- get format (default: auto-detect from platform)\n    local format = opt.format or target:extraconf(\"rules\", rulename, \"format\")\n    if not format then\n        if is_cosmocc then\n            format = \"elf\"\n        elseif target:is_plat(\"windows\", \"mingw\", \"msys\", \"cygwin\") then\n            format = \"coff\"\n        elseif target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n            format = \"macho\"\n        else\n            format = \"elf\"\n        end\n    end\n\n    -- get object file\n    local objectfile = opt.objectfile\n    if not objectfile then\n        objectfile = target:objectfile(binaryfile)\n        -- adjust extension based on format (use .obj for COFF, .o for others)\n        local objext = (format == \"coff\") and \".obj\" or \".o\"\n        objectfile = objectfile:gsub(\"%.o$\", objext):gsub(\"%.obj$\", objext)\n    end\n    table.insert(target:objectfiles(), objectfile)\n\n    -- add commands\n    if progress then\n        batchcmds:show_progress(progress, \"${color.build.object}generating.bin2obj %s\", binaryfile)\n    end\n    batchcmds:mkdir(path.directory(objectfile))\n\n    -- get symbol prefix (default: _binary_)\n    local symbol_prefix = opt.symbol_prefix or target:extraconf(\"rules\", rulename, \"symbol_prefix\") or \"_binary_\"\n\n    -- get zeroend (default: false, but can be overridden)\n    local zeroend = opt.zeroend\n    if zeroend == nil then\n        zeroend = target:extraconf(\"rules\", rulename, \"zeroend\") or false\n    end\n\n    -- get architecture and platform\n    local arch = target:arch()\n    local plat = target:plat()\n\n    -- get target_minver and xcode_sdkver from xcode toolchain (if available)\n    local target_minver = nil\n    local xcode_sdkver = nil\n    if format == \"macho\" then\n        local toolchain = target:toolchain(\"xcode\")\n        if toolchain then\n            target_minver = toolchain:config(\"target_minver\")\n            xcode_sdkver = toolchain:config(\"xcode_sdkver\")\n        end\n    end\n\n    -- convert binary file to object file\n    local argv = {\n        \"-i\", path(binaryfile),\n        \"-o\", path(objectfile),\n        \"-f\", format,\n        \"-a\", arch,\n        \"-p\", plat\n    }\n    if symbol_prefix ~= \"_binary_\" then\n        table.insert(argv, \"--symbol_prefix=\" .. symbol_prefix)\n    end\n    if target_minver then\n        table.insert(argv, \"--target_minver=\" .. target_minver)\n    end\n    if xcode_sdkver then\n        table.insert(argv, \"--xcode_sdkver=\" .. xcode_sdkver)\n    end\n    if zeroend then\n        table.insert(argv, \"--zeroend\")\n    end\n    if is_cosmocc then\n        table.insert(argv, \"--cosmocc\")\n    end\n    batchcmds:vlua(\"cli.binutils.bin2obj\", argv)\n\n    return objectfile\nend\n\n"
  },
  {
    "path": "xmake/rules/utils/bin2obj/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"utils.bin2obj\")\n    set_extensions(\".bin\")\n    add_orders(\"utils.bin2obj\", \"c++.build.modules.builder\")\n    on_buildcmd_file(function (target, batchcmds, sourcefile_bin, opt)\n        import(\"rules.utils.bin2obj.utils\", {alias = \"bin2obj_utils\", rootdir = os.programdir()})\n\n        -- get zeroend (default: false)\n        -- check file-level config first, then rule-level config\n        local fileconfig = target:fileconfig(sourcefile_bin)\n        local zeroend = (fileconfig and fileconfig.zeroend) or target:extraconf(\"rules\", \"utils.bin2obj\", \"zeroend\") or false\n\n        -- convert binary file to object file\n        local objectfile = bin2obj_utils.generate_objectfile(target, batchcmds, sourcefile_bin, {\n            progress = opt.progress,\n            zeroend = zeroend\n        })\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_bin)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n"
  },
  {
    "path": "xmake/rules/utils/compiler_runtime/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: utils.compiler.runtime\nrule(\"utils.compiler.runtime\")\n    on_config(function (target)\n        import(\"rules.c++.config.runtime\", {rootdir = os.programdir(), alias = \"config_runtime\"})\n        config_runtime(target)\n    end)\n"
  },
  {
    "path": "xmake/rules/utils/glsl2spv/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- compile glsl shader to spirv file, .spv\n--\n-- e.g.\n-- compile *.vert/*.frag to *.vert.spv/*.frag.spv files\n--   add_rules(\"utils.glsl2spv\", {outputdir = \"build\"})\n--\n-- compile *.vert/*.frag and generate binary c header files\n--   add_rules(\"utils.glsl2spv\", {bin2c = true})\n--\n-- compile *.vert/*.frag and generate object files for direct linking\n--   add_rules(\"utils.glsl2spv\", {bin2obj = true})\n--\n-- in c code (bin2c):\n--   static unsigned char g_test_frag_spv_data[] = {\n--      #include \"test.frag.spv.h\"\n--   };\n--\n-- in c code (bin2obj):\n--   extern const uint8_t _binary_test_frag_spv_start[];\n--   extern const uint8_t _binary_test_frag_spv_end[];\n--   const uint32_t size = (uint32_t)(_binary_test_frag_spv_end - _binary_test_frag_spv_start);\n--\n--\nrule(\"utils.glsl2spv\")\n    set_extensions(\".vert\", \".tesc\", \".tese\", \".geom\", \".comp\", \".frag\", \".comp\", \".mesh\", \".task\", \".rgen\", \".rint\", \".rahit\", \".rchit\", \".rmiss\", \".rcall\", \".glsl\")\n    on_load(function (target)\n        local is_bin2c = target:extraconf(\"rules\", \"utils.glsl2spv\", \"bin2c\")\n        if is_bin2c then\n            local headerdir = path.join(target:autogendir(), \"rules\", \"utils\", \"glsl2spv\")\n            if not os.isdir(headerdir) then\n                os.mkdir(headerdir)\n            end\n            target:add(\"includedirs\", headerdir)\n        end\n    end)\n    before_buildcmd_file(function (target, batchcmds, sourcefile_glsl, opt)\n        import(\"lib.detect.find_tool\")\n        import(\"rules.utils.bin2obj.utils\", {alias = \"bin2obj_utils\", rootdir = os.programdir()})\n        import(\"rules.utils.bin2c.utils\", {alias = \"bin2c_utils\", rootdir = os.programdir()})\n\n        -- get glslangValidator\n        local glslc\n        local glslangValidator = find_tool(\"glslangValidator\")\n        if not glslangValidator then\n            glslc = find_tool(\"glslc\")\n        end\n        assert(glslangValidator or glslc, \"glslangValidator or glslc not found!\")\n\n        -- glsl to spv\n        local targetenv = target:extraconf(\"rules\", \"utils.glsl2spv\", \"targetenv\") or \"vulkan1.0\"\n        local client = target:extraconf(\"rules\", \"utils.glsl2spv\", \"client\") or \"vulkan100\"\n        local debugsource = target:extraconf(\"rules\", \"utils.glsl2spv\", \"debugsource\") or false\n        local outputdir = target:extraconf(\"rules\", \"utils.glsl2spv\", \"outputdir\") or path.join(target:autogendir(), \"rules\", \"utils\", \"glsl2spv\")\n        local spvfilepath = path.join(outputdir, path.filename(sourcefile_glsl) .. \".spv\")\n        batchcmds:show_progress(opt.progress, \"${color.build.object}generating.glsl2spv %s\", sourcefile_glsl)\n        batchcmds:mkdir(outputdir)\n        if glslangValidator then\n            if debugsource then\n                batchcmds:vrunv(glslangValidator.program, {\"--target-env\", targetenv, \"--client\", client, \"-gVS\", \"-o\", path(spvfilepath), path(sourcefile_glsl)})\n            else\n                batchcmds:vrunv(glslangValidator.program, {\"--target-env\", targetenv, \"--client\", client, \"-o\", path(spvfilepath), path(sourcefile_glsl)})\n            end\n        else\n            batchcmds:vrunv(glslc.program, {\"--target-env\", targetenv, \"-o\", path(spvfilepath), path(sourcefile_glsl)})\n        end\n\n        -- do bin2c or bin2obj\n        local outputfile = spvfilepath\n        local is_bin2c = target:extraconf(\"rules\", \"utils.glsl2spv\", \"bin2c\")\n        local is_bin2obj = target:extraconf(\"rules\", \"utils.glsl2spv\", \"bin2obj\")\n        if is_bin2c then\n            -- generate header file\n            -- note: explicitly disable zeroend (SPIR-V is binary format, not null-terminated string)\n            local headerfile = bin2c_utils.generate_headerfile(target, batchcmds, spvfilepath, {\n                progress = opt.progress,\n                headerdir = outputdir,\n                zeroend = false  -- SPIR-V is binary format, not null-terminated string\n            })\n            outputfile = headerfile\n        elseif is_bin2obj then\n            -- convert to object file using bin2obj\n            -- note: zeroend is false by default (SPIR-V is binary format, not null-terminated string)\n            local objectfile = bin2obj_utils.generate_objectfile(target, batchcmds, spvfilepath, {\n                progress = opt.progress,\n                rulename = \"utils.glsl2spv\"  -- pass current rule name for config lookup\n            })\n            outputfile = objectfile\n        end\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile_glsl)\n        batchcmds:set_depmtime(os.mtime(outputfile))\n        batchcmds:set_depcache(target:dependfile(outputfile))\n    end)\n\n"
  },
  {
    "path": "xmake/rules/utils/hlsl2spv/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- compile hlsl shader to spirv file, .spv\n--\n-- e.g.\n-- compile *.hlsl to *.spv files\n--   add_rules(\"utils.hlsl2spv\", {outputdir = \"build\"})\n--\n-- compile *.hlsl and generate binary c header files\n--   add_rules(\"utils.hlsl2spv\", {bin2c = true})\n--\n-- compile *.hlsl and generate object files for direct linking\n--   add_rules(\"utils.hlsl2spv\", {bin2obj = true})\n--\n-- in c code (bin2c):\n--   static unsigned char g_test_ps_spv_data[] = {\n--      #include \"test.ps.spv.h\"\n--   };\n--\n-- in c code (bin2obj):\n--   extern const uint8_t _binary_test_ps_spv_start[];\n--   extern const uint8_t _binary_test_ps_spv_end[];\n--   const uint32_t size = (uint32_t)(_binary_test_ps_spv_end - _binary_test_ps_spv_start);\n--\n--\nrule(\"utils.hlsl2spv\")\n    set_extensions(\".hlsl\")\n    on_load(function (target)\n        local is_bin2c = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"bin2c\")\n        if is_bin2c then\n            local headerdir = path.join(target:autogendir(), \"rules\", \"utils\", \"hlsl2spv\")\n            if not os.isdir(headerdir) then\n                os.mkdir(headerdir)\n            end\n            target:add(\"includedirs\", headerdir)\n        end\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile_hlsl, opt)\n        import(\"lib.detect.find_tool\")\n        import(\"rules.utils.bin2obj.utils\", {alias = \"bin2obj_utils\", rootdir = os.programdir()})\n        import(\"rules.utils.bin2c.utils\", {alias = \"bin2c_utils\", rootdir = os.programdir()})\n\n        local dxc = assert(find_tool(\"dxc\"), \"dxc not found!\")\n\n        -- hlsl to spv\n        local basename_with_type = path.basename(sourcefile_hlsl)\n        local shadertype = path.extension(basename_with_type):sub(2)\n        if shadertype == \"\" then\n            -- if not specify shader type, considered it a header, skip\n            wprint(\"hlsl2spv: shader type not specified, skip %s\", sourcefile_hlsl)\n            return\n        end\n\n        local targetenv = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"targetenv\") or \"vulkan1.0\"\n        local outputdir = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"outputdir\") or path.join(target:autogendir(), \"rules\", \"utils\", \"hlsl2spv\")\n        local hlslversion = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"hlslversion\") or \"2018\"\n        local spvfilepath = path.join(outputdir, basename_with_type .. \".spv\")\n\n        local shadermodel = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"shadermodel\") or \"6.0\"\n        local sm = shadermodel:gsub(\"%.\", \"_\")\n        local dxc_profile = shadertype .. \"_\" .. sm\n\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.hlsl %s\", sourcefile_hlsl)\n        batchcmds:mkdir(outputdir)\n        batchcmds:vrunv(dxc.program, {path(sourcefile_hlsl), \"-spirv\", \"-HV\", hlslversion, \"-fspv-target-env=\" .. targetenv, \"-E\", \"main\", \"-T\", dxc_profile, \"-Fo\", path(spvfilepath)})\n\n        -- bin2c or bin2obj\n        local outputfile = spvfilepath\n        local is_bin2c = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"bin2c\")\n        local is_bin2obj = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"bin2obj\")\n        if is_bin2c then\n            -- generate header file\n            -- note: explicitly disable zeroend (SPIR-V is binary format, not null-terminated string)\n            local headerfile = bin2c_utils.generate_headerfile(target, batchcmds, spvfilepath, {\n                progress = opt.progress,\n                headerdir = outputdir,\n                zeroend = false  -- SPIR-V is binary format, not null-terminated string\n            })\n            outputfile = headerfile\n        elseif is_bin2obj then\n            -- convert to object file using bin2obj\n            -- note: zeroend is false by default (SPIR-V is binary format, not null-terminated string)\n            local objectfile = bin2obj_utils.generate_objectfile(target, batchcmds, spvfilepath, {\n                progress = opt.progress,\n                rulename = \"utils.hlsl2spv\"  -- pass current rule name for config lookup\n            })\n            outputfile = objectfile\n        end\n\n        batchcmds:add_depfiles(sourcefile_hlsl)\n        batchcmds:set_depmtime(os.mtime(outputfile))\n        batchcmds:set_depcache(target:dependfile(outputfile))\n    end)\n\n    after_clean(function (target, batchcmds, sourcefile_hlsl)\n        import(\"private.action.clean.remove_files\")\n\n        local outputdir = target:extraconf(\"rules\", \"utils.hlsl2spv\", \"outputdir\") or path.join(target:targetdir(), \"shader\")\n        remove_files(path.join(outputdir, \"*.spv\"))\n        remove_files(path.join(outputdir, \"*.spv.h\"))\n        -- object files are cleaned automatically by xmake\n    end)\n"
  },
  {
    "path": "xmake/rules/utils/inherit_links/inherit_links.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        inherit_links.lua\n--\n\n-- get values from target\nfunction _get_values_from_target(target, name)\n    local values = table.clone(table.wrap(target:get(name)))\n    for _, value in ipairs((target:get_from(name, \"option::*\"))) do\n        table.join2(values, value)\n    end\n    for _, value in ipairs((target:get_from(name, \"package::*\"))) do\n        table.join2(values, value)\n    end\n    return values\nend\n\n-- @note we cannot directly set `{interface = true}`, because it will overwrite the previous configuration\n-- https://github.com/xmake-io/xmake/issues/1465\nfunction _add_export_value(target, name, value)\n    local has_private = false\n    local private_values = target:get(name)\n    if private_values then\n        for _, v in ipairs(private_values) do\n            if v == value then\n                has_private = true\n                break\n            end\n        end\n    end\n    local extraconf = target:extraconf(name, value)\n    if has_private then\n        target:add(name, value, table.join(extraconf or {}, {public = true}))\n    else\n        target:add(name, value, table.join(extraconf or {}, {interface = true}))\n    end\nend\n\n-- export values as public/interface in target\nfunction _add_export_values(target, name, values)\n    for _, value in ipairs(values) do\n        _add_export_value(target, name, value)\n    end\nend\n\nfunction main(target)\n\n    -- disable inherit.links for `add_deps()`?\n    if target:data(\"inherit.links\") == false then\n        return\n    end\n\n    -- export target links and linkdirs\n    if target:is_shared() or target:is_static() then\n        local targetfile = target:targetfile()\n\n        -- rust maybe will disable inherit links, only inherit linkdirs\n        if target:data(\"inherit.links.deplink\") ~= false then\n            -- we need to move target link to head\n            _add_export_value(target, \"links\", target:linkname())\n            local links = target:get(\"links\", {rawref = true})\n            if links and type(links) == \"table\" and #links > 1 then\n                table.insert(links, 1, links[#links])\n                table.remove(links, #links)\n            end\n        end\n\n        local implibfile = target:artifactfile(\"implib\")\n        if implibfile then\n            _add_export_value(target, \"linkdirs\", path.directory(implibfile))\n        else\n            _add_export_value(target, \"linkdirs\", path.directory(targetfile))\n        end\n\n        if target:rule(\"go\") then\n            -- we need to add includedirs to support import modules for golang\n            _add_export_value(target, \"includedirs\", path.directory(targetfile))\n        end\n\n        if target:rule(\"rust\") then\n            local cratetype = target:values(\"rust.cratetype\")\n            -- only bin, lib, rlib, dylib can make use of --extern CRATE[=PATH]\n            if cratetype ~= \"staticlib\" and cratetype ~= \"cdylib\" then\n                _add_export_value(target, \"frameworks\", target:targetfile())\n            end\n        end\n    end\n\n    -- we export all links and linkdirs in self/packages/options to the parent target by default\n    --\n    -- @note we only export links for static target,\n    -- and we need to pass `{public = true}` to add_packages/add_links/... to export it if want to export links for shared target\n    --\n    if target:data(\"inherit.links.exportlinks\") ~= false then\n        if target:is_static() or target:is_object() then\n            for _, name in ipairs({\"rpathdirs\", \"frameworkdirs\", \"frameworks\", \"linkdirs\", \"links\", \"syslinks\", \"ldflags\", \"shflags\"}) do\n                local values = _get_values_from_target(target, name)\n                if values and #values > 0 then\n                    _add_export_values(target, name, values)\n                end\n            end\n        end\n    end\n\n    -- export rpathdirs for all shared library\n    if target:is_binary() and target:policy(\"build.rpath\") then\n        local targetdir = target:targetdir()\n        for _, dep in ipairs(target:orderdeps({inherit = true})) do\n            if dep:kind() == \"shared\" then\n                local rpathdir = \"@loader_path\"\n                local subdir = path.relative(path.directory(dep:targetfile()), targetdir)\n                if subdir and subdir ~= '.' then\n                    rpathdir = path.join(rpathdir, subdir)\n                end\n                target:add(\"rpathdirs\", rpathdir)\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/utils/inherit_links/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: utils.inherit.links\nrule(\"utils.inherit.links\")\n    after_config(\"inherit_links\")\n\n"
  },
  {
    "path": "xmake/rules/utils/install_importfiles/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- install pkg-config/*.pc import files\nrule(\"utils.install.pkgconfig_importfiles\")\n    after_install(function (target, opt)\n        opt = opt or {}\n        local configs = target:extraconf(\"rules\", \"utils.install.pkgconfig_importfiles\")\n        import(\"target.action.install.pkgconfig_importfiles\")(target, table.join(opt, configs))\n    end)\n\n-- install *.cmake import files\nrule(\"utils.install.cmake_importfiles\")\n    after_install(function (target, opt)\n        opt = opt or {}\n        local configs = target:extraconf(\"rules\", \"utils.install.cmake_importfiles\")\n        import(\"target.action.install.cmake_importfiles\")(target, table.join(opt, configs))\n    end)\n"
  },
  {
    "path": "xmake/rules/utils/ispc/xmake.lua",
    "content": "rule(\"utils.ispc\")\n    set_extensions(\".ispc\")\n\n    on_config(function (target)\n        local headersdir = path.join(target:autogendir(), \"rules\", \"utils\", \"ispc\", \"headers\")\n        os.mkdir(headersdir)\n        target:add(\"includedirs\", headersdir, {public = true})\n    end)\n\n    before_buildcmd_file(function (target, batchcmds, sourcefile_ispc, opt)\n        import(\"lib.detect.find_tool\")\n        local ispc = assert(find_tool(\"ispc\"), \"ispc not found!\")\n\n        local flags = {}\n        if target:values(\"ispc.flags\") then\n            table.join2(flags, target:values(\"ispc.flags\"))\n        end\n\n        if target:get(\"symbols\") == \"debug\"  then\n            table.insert(flags, \"-g\")\n        end\n\n        if target:get(\"optimize\") == \"none\" then\n            table.insert(flags, \"-O0\")\n        elseif target:get(\"optimize\") == \"fast\" then\n            table.insert(flags, \"-O2\")\n        elseif target:get(\"optimize\") == \"faster\" or target:get(\"optimize\") == \"fastest\" then\n            table.insert(flags, \"-O3\")\n        elseif target:get(\"optimize\") == \"smallest\" then\n            table.insert(flags, \"-O1\")\n        end\n\n        if target:get(\"warnings\") == \"none\" then\n            table.insert(flags, \"--woff\")\n        elseif target:get(\"warnings\") == \"error\" then\n            table.insert(flags, \"--werror\")\n        end\n\n        if not target:is_plat(\"windows\") then\n            table.insert(flags, \"--pic\")\n        end\n\n        local headersdir = path.join(target:autogendir(), \"rules\", \"utils\", \"ispc\", \"headers\")\n        local objectfile = target:objectfile(sourcefile_ispc)\n        local objectdir = path.directory(objectfile)\n        local headersfile\n        local header_extension = target:extraconf(\"rules\", \"utils.ispc\", \"header_extension\")\n        if header_extension then\n            headersfile = path.join(headersdir, path.basename(sourcefile_ispc) .. header_extension)\n        else\n            headersfile = path.join(headersdir, path.filename(sourcefile_ispc) .. \".h\")\n        end\n\n        table.insert(flags, \"-o\")\n        table.insert(flags, path(objectfile))\n        table.insert(flags, \"-h\")\n        table.insert(flags, path(headersfile))\n        table.insert(flags, path(sourcefile_ispc))\n\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.ispc %s\", sourcefile_ispc)\n        batchcmds:mkdir(objectdir)\n        batchcmds:vrunv(ispc.program, flags)\n\n        table.insert(target:objectfiles(), objectfile)\n\n        batchcmds:add_depfiles(sourcefile_ispc, headersfile)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n"
  },
  {
    "path": "xmake/rules/utils/merge_archive/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"utils.merge.archive\")\n    set_extensions(\".a\", \".lib\")\n    after_load(function (target)\n        -- we need to disable inherit links if all static deps have been merged\n        -- and we must disable it in after_load, because it will be called before rule(utils.inherit.links).on_config\n        --\n        -- @see https://github.com/xmake-io/xmake/issues/3404\n        if target:policy(\"build.merge_archive\") then\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:is_static() then\n                    dep:data_set(\"inherit.links.deplink\", false)\n                end\n            end\n        else\n            target:rule_enable(\"utils.merge.archive\", false)\n        end\n    end)\n\n    on_build_files(function (target, sourcebatch, opt)\n        if sourcebatch.sourcefiles then\n            target:data_set(\"merge_archive.sourcefiles\", sourcebatch.sourcefiles)\n        end\n    end)\n\n    after_link(function (target, opt)\n        if not target:is_static() then\n            return\n        end\n        local sourcefiles = target:data(\"merge_archive.sourcefiles\")\n        if target:policy(\"build.merge_archive\") or sourcefiles then\n            import(\"utils.archive.merge_staticlib\")\n            import(\"core.project.depend\")\n            import(\"utils.progress\")\n            local libraryfiles = {}\n            if sourcefiles then\n                table.join2(libraryfiles, sourcefiles)\n            else\n                for _, dep in ipairs(target:orderdeps()) do\n                    if dep:is_static() then\n                        table.insert(libraryfiles, dep:targetfile())\n                    end\n                end\n            end\n            if #libraryfiles > 0 then\n                table.insert(libraryfiles, target:targetfile())\n            end\n            depend.on_changed(function ()\n                progress.show(opt.progress, \"${color.build.target}merging.$(mode) %s\", path.filename(target:targetfile()))\n                if #libraryfiles > 0 then\n                    local tmpfile = os.tmpfile() .. path.extension(target:targetfile())\n                    merge_staticlib(target, tmpfile, libraryfiles)\n                    os.cp(tmpfile, target:targetfile())\n                    os.rm(tmpfile)\n                end\n            end, {dependfile = target:dependfile(target:targetfile() .. \".merge_archive\"), files = libraryfiles, changed = target:is_rebuilt()})\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/utils/merge_object/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: utils.merge.object\nrule(\"utils.merge.object\")\n\n    -- set extensions\n    set_extensions(\".o\", \".obj\")\n\n    -- on build file\n    on_build_file(function (target, sourcefile_obj, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- get object file\n        local objectfile = target:objectfile(sourcefile_obj)\n\n        -- add objectfile\n        table.insert(target:objectfiles(), objectfile)\n\n        -- load dependent info\n        local dependfile = target:dependfile(objectfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n\n        -- need build this object?\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(objectfile)}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}inserting.$(mode) %s\", sourcefile_obj)\n\n        -- insert this object file\n        os.vcp(sourcefile_obj, objectfile)\n\n        -- update files to the dependent file\n        dependinfo.files = {}\n        table.insert(dependinfo.files, sourcefile_obj)\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/utils/symbols/export_all/export_all.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        export_all.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\nimport(\"core.tool.toolchain\")\nimport(\"core.base.option\")\nimport(\"core.base.hashset\")\nimport(\"core.project.depend\")\nimport(\"utils.progress\")\nimport(\"utils.binary.readsyms\")\n\n-- It is not very accurate because some rules automatically\n-- generate objectfiles and do not save the corresponding sourcefiles.\n-- @see https://github.com/xmake-io/xmake/issues/5601\nfunction _get_sourcefiles_map(target, sourcefiles_map)\n    for _, sourcebatch in pairs(target:sourcebatches()) do\n        for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            local objectfiles = sourcebatch.objectfiles\n            if objectfiles then\n                local objectfile = objectfiles[idx]\n                if objectfile then\n                    sourcefiles_map[objectfile] = sourcefile\n                end\n            end\n        end\n    end\n    local plaindeps = target:get(\"deps\")\n    if plaindeps then\n        for _, depname in ipairs(plaindeps) do\n            local dep = target:dep(depname)\n            if dep and dep:is_object() then\n                _get_sourcefiles_map(dep, sourcefiles_map)\n            end\n        end\n    end\nend\n\nfunction _try_add_symbol(allsymbols, symbol, target, opt)\n    opt = opt or {}\n    local export_classes = opt.export_classes\n    local export_filter = opt.export_filter\n    -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992\n    if target:is_arch(\"x86\") and symbol:startswith(\"_\") and not symbol:startswith(\"__\") and not symbol:startswith(\"_DllMain@\") then\n        symbol = symbol:sub(2)\n    end\n    if export_filter then\n        if export_filter(symbol, {objectfile = opt.objectfile, sourcefile = opt.sourcefile}) then\n            allsymbols:insert(symbol)\n        end\n    else\n        if not symbol:startswith(\"__\") then\n            if export_classes then\n                if not symbol:startswith(\"??_G\") and not symbol:startswith(\"??_E\") then\n                    allsymbols:insert(symbol)\n                end\n            else\n                -- e.g. _add, ?add@@YAHHH@Z\n                allsymbols:insert(symbol)\n            end\n        end\n    end\nend\n\n-- use dumpbin to get all symbols from object files\nfunction _get_allsymbols_by_dumpbin(target, dumpbin, opt)\n    opt = opt or {}\n    local allsymbols = hashset.new()\n    local export_classes = opt.export_classes\n    local export_filter = opt.export_filter\n    local sourcefiles_map = {}\n    if export_filter then\n        _get_sourcefiles_map(target, sourcefiles_map)\n    end\n    for _, objectfile in ipairs(target:objectfiles()) do\n        local objectsymbols = try { function () return os.iorunv(dumpbin, {\"/symbols\", \"/nologo\", objectfile}) end }\n        if objectsymbols then\n            local sourcefile = sourcefiles_map[objectfile]\n            for _, line in ipairs(objectsymbols:split('\\n', {plain = true})) do\n                -- https://docs.microsoft.com/en-us/cpp/build/reference/symbols\n                -- 008 00000000 SECT3  notype ()    External     | add\n                if line:find(\"External\") and not line:find(\"UNDEF\") then\n                    local symbol = line:match(\".*External%s+| (.*)\")\n                    if symbol then\n                        symbol = symbol:split('%s')[1]\n                        _try_add_symbol(allsymbols, symbol, target, {\n                            export_classes = export_classes,\n                            export_filter = export_filter,\n                            objectfile = objectfile,\n                            sourcefile = sourcefile\n                        })\n                    end\n                end\n            end\n        end\n    end\n    return allsymbols\nend\n\n-- use objdump to get all symbols from object files\nfunction _get_allsymbols_by_objdump(target, objdump, opt)\n    opt = opt or {}\n    local allsymbols = hashset.new()\n    local export_classes = opt.export_classes\n    local export_filter = opt.export_filter\n    local sourcefiles_map = {}\n    if export_filter then\n        _get_sourcefiles_map(target, sourcefiles_map)\n    end\n    for _, objectfile in ipairs(target:objectfiles()) do\n        local objectsymbols = try { function () return os.iorunv(objdump, {\"--syms\", objectfile}) end }\n        if objectsymbols then\n            local sourcefile = sourcefiles_map[objectfile]\n            for _, line in ipairs(objectsymbols:split('\\n', {plain = true})) do\n                if line:find(\"(scl   2)\", 1, true) then\n                    local splitinfo = line:split(\"%s\")\n                    local symbol = splitinfo[#splitinfo]\n                    if symbol then\n                        _try_add_symbol(allsymbols, symbol, target, {\n                            export_classes = export_classes,\n                            export_filter = export_filter,\n                            objectfile = objectfile,\n                            sourcefile = sourcefile\n                        })\n                    end\n                end\n            end\n        end\n    end\n    return allsymbols\nend\n\n-- use readsyms to get all symbols from object files\nfunction _get_allsymbols_by_readsyms(target, opt)\n    opt = opt or {}\n    local allsymbols = hashset.new()\n    local export_classes = opt.export_classes\n    local export_filter = opt.export_filter\n    local sourcefiles_map = {}\n    if export_filter then\n        _get_sourcefiles_map(target, sourcefiles_map)\n    end\n    local objectfiles = target:objectfiles()\n    for _, objectfile in ipairs(objectfiles) do\n        local objects = readsyms(objectfile)\n        if objects then\n            local sourcefile = sourcefiles_map[objectfile]\n            for _, obj in ipairs(objects) do\n                local symbols = obj.symbols\n                if symbols then\n                    for _, sym in ipairs(symbols) do\n                        if sym.name and sym.type then\n                            -- only export function symbols (T/t) for DLL exports\n                            -- skip data (D/d), bss (B/b), other sections (S/s), and undefined (U) symbols\n                            if sym.type == \"T\" or sym.type == \"t\" then\n                                local symbol = sym.name\n                                _try_add_symbol(allsymbols, symbol, target, {\n                                    export_classes = export_classes,\n                                    export_filter = export_filter,\n                                    sourcefile = sourcefile\n                                })\n                            end\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return allsymbols\nend\n\n-- export all symbols for dynamic library\nfunction main(target, opt)\n\n    -- @note it only supports windows/dll now\n    assert(target:is_shared(), 'rule(\"utils.symbols.export_all\"): only for shared target(%s)!', target:name())\n    if not target:is_plat(\"windows\") or option.get(\"dry-run\") then\n        return\n    end\n\n    -- export all symbols\n    local allsymbols_filepath = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_all.def\")\n    local dependfile = allsymbols_filepath .. \".d\"\n    depend.on_changed(function ()\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.target}exporting.$(mode) %s\", path.filename(target:targetfile()))\n\n        -- export c++ class?\n        local export_classes = target:extraconf(\"rules\", \"utils.symbols.export_all\", \"export_classes\")\n\n        -- the export filter\n        local export_filter = target:extraconf(\"rules\", \"utils.symbols.export_all\", \"export_filter\")\n\n        -- get all symbols\n        local allsymbols\n        if target:has_tool(\"cc\", \"clang\", \"clang_cl\", \"clangxx\", \"gcc\", \"gxx\") then\n            local objdump = assert(find_tool(\"llvm-objdump\") or find_tool(\"objdump\"), \"objdump not found!\")\n            allsymbols = _get_allsymbols_by_objdump(target, objdump.program, {\n                export_classes = export_classes,\n                export_filter = export_filter})\n        end\n        if not allsymbols or allsymbols:empty() then\n            local msvc = toolchain.load(\"msvc\", {plat = target:plat(), arch = target:arch()})\n            if msvc:check() then\n                local dumpbin = assert(find_tool(\"dumpbin\", {envs = msvc:runenvs()}), \"dumpbin not found!\")\n                allsymbols = _get_allsymbols_by_dumpbin(target, dumpbin.program, {\n                    export_classes = export_classes,\n                    export_filter = export_filter})\n            end\n        end\n        -- fallback to readsyms if still no symbols found\n        if not allsymbols or allsymbols:empty() then\n            allsymbols = _get_allsymbols_by_readsyms(target, {\n                export_classes = export_classes,\n                export_filter = export_filter})\n        end\n\n        -- export all symbols\n        if allsymbols and not allsymbols:empty() then\n            local allsymbols_file = io.open(allsymbols_filepath, 'w')\n            allsymbols_file:print(\"EXPORTS\")\n            for _, symbol in allsymbols:keys() do\n                allsymbols_file:print(\"%s\", symbol)\n            end\n            allsymbols_file:close()\n        else\n            wprint('rule(\"utils.symbols.export_all\"): no symbols are exported for target(%s)!', target:name())\n        end\n\n    end, {dependfile = dependfile, files = target:objectfiles(), changed = target:is_rebuilt()})\nend\n"
  },
  {
    "path": "xmake/rules/utils/symbols/export_all/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- export all symbols for windows/dll\n--\n-- @note: we don't need any export macros to a classes or functions!\n-- and we can't use /GL (Whole Program Optimization) when use this approach!\n--\n-- @see https://github.com/xmake-io/xmake/issues/1123\n--\nrule(\"utils.symbols.export_all\")\n    on_config(function (target)\n        -- @note it only supports windows/dll now\n        assert(target:is_shared(), 'rule(\"utils.symbols.export_all\"): only for shared target(%s)!', target:name())\n        if target:is_plat(\"windows\") then\n            assert(target:get(\"optimize\") ~= \"smallest\", 'rule(\"utils.symbols.export_all\"): does not support set_optimize(\"smallest\") for target(%s)!', target:name())\n            local allsymbols_filepath = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_all.def\")\n            if target:has_tool(\"sh\", \"link\") then\n                target:add(\"shflags\", \"/def:\" .. allsymbols_filepath, {force = true})\n            elseif target:has_tool(\"sh\", \"clang\", \"clangxx\") then\n                target:add(\"shflags\", \"-Wl,/def:\" .. allsymbols_filepath, {force = true})\n            end\n        end\n    end)\n    before_link(\"export_all\")\n\n"
  },
  {
    "path": "xmake/rules/utils/symbols/export_list/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- export the given symbols list\n--\n--@code\n--  target(\"foo\")\n--    set_kind(\"shared\")\n--    add_files(\"src/foo.c\")\n--    add_rules(\"utils.symbols.export_list\", {symbols = {\n--      \"add\",\n--      \"sub\"}})\n--\n--  target(\"foo2\")\n--    set_kind(\"shared\")\n--    add_files(\"src/foo.c\")\n--    add_files(\"src/foo.export.txt\")\n--    add_rules(\"utils.symbols.export_list\")\n--\nrule(\"utils.symbols.export_list\")\n    set_extensions(\".export.txt\")\n    on_config(function (target)\n        assert(target:is_shared() or (target:is_plat(\"windows\") and target:is_binary()),\n            'rule(\"utils.symbols.export_list\"): only for binary/shared target(%s)!', target:fullname())\n        local exportfile\n        local exportkind\n        local exportsymbols = target:extraconf(\"rules\", \"utils.symbols.export_list\", \"symbols\")\n        if not exportsymbols then\n            local sourcebatch = target:sourcebatches()[\"utils.symbols.export_list\"]\n            if sourcebatch then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    local list = io.readfile(sourcefile)\n                    if list then\n                        exportsymbols = list:split(\"\\n\")\n                    end\n                    break\n                end\n            end\n        end\n        assert(exportsymbols and #exportsymbols > 0, 'rule(\"utils.symbols.export_list\"): no exported symbols!')\n        local linkername = target:linker():name()\n        if linkername == \"dmd\" then\n            if target:is_plat(\"windows\") then\n                exportkind = \"def\"\n                exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.def\")\n                target:add(\"shflags\", \"-L/def:\" .. exportfile, {force = true})\n                target:add(\"ldflags\", \"-L/def:\" .. exportfile, {force = true})\n            elseif target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n                exportkind = \"apple\"\n                exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.exp\")\n                target:add(\"shflags\", {\"-L-exported_symbols_list\", \"-L\" .. exportfile}, {force = true, expand = false})\n            elseif target:is_plat(\"solaris\") then\n                -- Solaris linker does not support --version-script\n                return\n            else\n                exportkind = \"ver\"\n                exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.map\")\n                target:add(\"shflags\", \"-L--version-script=\" .. exportfile, {force = true})\n            end\n        elseif target:has_tool(\"ld\", \"link\") then\n            exportkind = \"def\"\n            exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.def\")\n            target:add(\"shflags\", \"/def:\" .. exportfile, {force = true})\n            target:add(\"ldflags\", \"/def:\" .. exportfile, {force = true})\n        elseif target:is_plat(\"windows\") and target:has_tool(\"ld\", \"clangxx\") then\n            exportkind = \"def\"\n            exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.def\")\n            target:add(\"shflags\", \"-Wl,/def:\" .. exportfile, {force = true})\n            target:add(\"ldflags\", \"-Wl,/def:\" .. exportfile, {force = true})\n        elseif target:is_plat(\"macosx\", \"iphoneos\", \"watchos\", \"appletvos\") then\n            exportkind = \"apple\"\n            exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.exp\")\n            target:add(\"shflags\", {\"-Wl,-exported_symbols_list\", exportfile}, {force = true, expand = false})\n        elseif target:is_plat(\"solaris\") then\n            -- Solaris linker does not support --version-script\n            return\n        elseif target:has_tool(\"ld\", \"gcc\", \"gxx\", \"clang\", \"clangxx\") or\n               target:has_tool(\"sh\", \"gcc\", \"gxx\", \"clang\", \"clangxx\") then\n            exportkind = \"ver\"\n            exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.map\")\n            target:add(\"shflags\", \"-Wl,--version-script=\" .. exportfile, {force = true})\n        elseif target:has_tool(\"ld\", \"ld\") or target:has_tool(\"sh\", \"ld\") then\n            exportkind = \"ver\"\n            exportfile = path.join(target:autogendir(), \"rules\", \"symbols\", \"export_list.map\")\n            target:add(\"shflags\", \"--version-script=\" .. exportfile, {force = true})\n        end\n        if exportfile and exportkind then\n            local exportfile_tmp = os.tmpfile(exportfile)\n            os.tryrm(exportfile_tmp)\n            if exportkind == \"ver\" then\n                io.writefile(exportfile_tmp, ([[{\n    global:\n        %s\n\n    local:\n        *;\n};]]):format(table.concat(exportsymbols, \";\\n        \") .. \";\"))\n            elseif exportkind == \"apple\" then\n                local file = io.open(exportfile_tmp, 'w')\n                for _, symbol in ipairs(exportsymbols) do\n                    if not symbol:startswith(\"_\") then\n                        symbol = \"_\" .. symbol\n                    end\n                    file:print(\"%s\", symbol)\n                end\n                file:close()\n            elseif exportkind == \"def\" then\n                local file = io.open(exportfile_tmp, 'w')\n                file:print(\"EXPORTS\")\n                for _, symbol in ipairs(exportsymbols) do\n                    file:print(\"%s\", symbol)\n                end\n                file:close()\n            end\n\n            -- update file if the content is changed\n            target:data_add(\"linkdepfiles\", exportfile)\n            if os.isfile(exportfile_tmp) then\n                os.cp(exportfile_tmp, exportfile, {copy_if_different = true})\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/rules/utils/symbols/extract/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: utils.symbols.extract\nrule(\"utils.symbols.extract\")\n    after_config(function(target)\n\n        -- need generate symbols?\n        local strip = target:get(\"strip\")\n        local symbols = table.wrap(target:get(\"symbols\"))\n        if table.contains(symbols, \"debug\") and (strip == \"all\" or strip == \"debug\")\n            and not target:is_plat(\"windows\") -- we need not to strip pdb for windows, https://github.com/xmake-io/xmake/issues/6554\n            and (target:is_binary() or target:is_shared()) and target:tool(\"strip\") then -- only for strip command\n            target:data_set(\"utils.symbols.extract\", true)\n            target:set(\"strip\", \"none\") -- disable strip in link stage, because we need to run separate strip commands\n            target:data_set(\"strip.origin\", strip)\n        else\n            target:rule_enable(\"utils.symbols.extract\", false)\n        end\n    end)\n    after_link(function (target, opt)\n\n        -- need generate symbols?\n        if not target:data(\"utils.symbols.extract\") then\n            return\n        end\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"core.platform.platform\")\n        import(\"utils.progress\")\n\n        -- get strip\n        local strip = target:tool(\"strip\")\n        if not strip then\n            return\n        end\n\n        -- get dsymutil and objcopy\n        local dsymutil, objcopy\n        if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\") then\n            dsymutil = target:tool(\"dsymutil\")\n            if not dsymutil then\n                return\n            end\n        else\n            objcopy = target:tool(\"objcopy\")\n        end\n\n        -- @note we use dependfile(targetfile) as sourcefile/mtime instead of targetfile to ensure it's mtime less than mtime(symbolfile), because targetfile will be changed after stripping\n        local targetfile = target:targetfile()\n        local symbolfile = target:symbolfile()\n        local dryrun = option.get(\"dry-run\")\n        depend.on_changed(function ()\n\n            -- trace progress info\n            progress.show(opt.progress, \"${color.build.target}generating.$(mode) %s\", path.filename(symbolfile))\n\n            -- we remove the previous symbol file to ensure that it will be re-generated and it's mtime will be changed.\n            if not dryrun then\n                os.tryrm(symbolfile)\n            end\n\n            -- generate symbols file\n            if dsymutil then\n                local dsymutil_argv = {}\n                local arch = target:arch()\n                if arch then\n                    table.insert(dsymutil_argv, \"-arch\")\n                    table.insert(dsymutil_argv, arch)\n                end\n                table.insert(dsymutil_argv, targetfile)\n                table.insert(dsymutil_argv, \"-o\")\n                table.insert(dsymutil_argv, symbolfile)\n                os.vrunv(dsymutil, dsymutil_argv, {dryrun = dryrun})\n            else\n                -- @see https://github.com/xmake-io/xmake/issues/4684\n                if objcopy then\n                    os.vrunv(objcopy, {\"--only-keep-debug\", targetfile, symbolfile}, {dryrun = dryrun})\n                elseif not dryrun then\n                    os.vcp(targetfile, symbolfile)\n                end\n            end\n\n            -- strip it\n            local strip_argv = {}\n            if target:is_plat(\"macosx\", \"iphoneos\", \"watchos\") and not strip:find(\"llvm-strip\", 1, true) then\n                -- do not support `-s`, we can only strip debug symbols\n                local arch = target:arch()\n                if arch then\n                    table.insert(strip_argv, \"-arch\")\n                    table.insert(strip_argv, arch)\n                end\n                table.insert(strip_argv, \"-S\")\n            else\n                -- -s/--strip-all for gnu strip\n                local strip = target:data(\"strip.origin\")\n                if strip == \"debug\" then\n                    table.insert(strip_argv, \"-S\")\n                else\n                    table.insert(strip_argv, \"-s\")\n                end\n            end\n            table.insert(strip_argv, targetfile)\n            os.vrunv(strip, strip_argv, {dryrun = dryrun})\n\n            -- attach symbolfile to targetfile\n            if not target:is_plat(\"macosx\", \"iphoneos\", \"watchos\") and objcopy then\n                -- @see https://github.com/xmake-io/xmake/issues/4684\n                os.vrunv(objcopy, {\"--add-gnu-debuglink=\" .. symbolfile, targetfile}, {dryrun = dryrun})\n            end\n\n        end, {dependfile = target:dependfile(symbolfile),\n              files = target:dependfile(targetfile),\n              changed = target:is_rebuilt(),\n              dryrun = dryrun})\n    end)\n\n"
  },
  {
    "path": "xmake/rules/vala/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"vala.build\")\n    set_extensions(\".vala\")\n    -- Since vala can directly compile with C files\n    -- we can add C sourcekinds\n    -- And in the end we're going to be compiling C code\n    set_sourcekinds(\"cc\")\n    on_load(function (target)\n        -- we disable to build across targets in parallel, because the source files may depend on other target modules\n        target:set(\"policy\", \"build.fence\", true)\n\n        -- get vapi file\n        local vapifile = target:data(\"vala.vapifile\")\n        if not vapifile then\n            local vapiname = target:values(\"vala.vapi\")\n            if vapiname then\n                vapifile = path.absolute(path.join(target:targetdir(), vapiname))\n            else\n                vapifile = path.absolute(path.join(target:targetdir(), target:name() .. \".vapi\"))\n            end\n            target:data_set(\"vala.vapifile\", vapifile)\n        end\n\n        -- get header file\n        local headerfile = target:data(\"vala.headerfile\")\n        if not headerfile then\n            local headername = target:values(\"vala.header\")\n            if headername then\n                headerfile = path.absolute(path.join(target:targetdir(), headername))\n            else\n                headerfile = path.absolute(path.join(target:targetdir(), target:name() .. \".h\"))\n            end\n            target:data_set(\"vala.headerfile\", headerfile)\n        end\n        if headerfile then\n            target:add(\"headerfiles\", headerfile)\n            target:add(\"sysincludedirs\", path.directory(headerfile), {public = true})\n        end\n    end)\n    before_buildcmd_files(function (target, batchcmds, sourcebatch, opt)\n        -- Here we compile vala files into C code\n\n        -- We have to compile entire project each time\n        -- because otherwise valac can't resolve symbols\n        -- from other files, however, c files can be\n        -- incrementally built\n\n        -- get valac\n        import(\"lib.detect.find_tool\")\n        local valac = assert(find_tool(\"valac\"), \"valac not found!\")\n\n        local argv = {\"-C\", \"-d\", target:autogendir()}\n\n        -- add commands\n        local packages = target:values(\"vala.packages\")\n        if packages then\n            for _, package in ipairs(packages) do\n                table.insert(argv, \"--pkg\")\n                table.insert(argv, path(package))\n            end\n        end\n\n        if target:is_binary() then\n            for _, dep in ipairs(target:orderdeps()) do\n                if dep:is_shared() or dep:is_static() then\n                    local vapifile = dep:data(\"vala.vapifile\")\n                    if vapifile then\n                        table.join2(argv, path(vapifile))\n                    end\n                end\n            end\n        else\n            local vapifile = target:data(\"vala.vapifile\")\n            if vapifile then\n                table.insert(argv, path(vapifile, function (p) return \"--vapi=\" .. p end))\n            end\n            local headerfile = target:data(\"vala.headerfile\")\n            if headerfile then\n                table.insert(argv, \"-H\")\n                table.insert(argv, path(headerfile))\n            end\n        end\n\n        local vapidir = target:values(\"vala.vapidir\")\n        if vapidir then\n            table.insert(argv, path(vapidir, function (p) return \"--vapidir=\" .. p end))\n        end\n\n        local valaflags = target:values(\"vala.flags\")\n        if valaflags then\n            table.join2(argv, valaflags)\n        end\n\n        -- iterating through source files,\n        -- otherwise valac would fail when compiling multiple files\n        local lastmtime = 0\n        local sourcefiles = {}\n        for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n            -- if it's only a vala file\n            if path.extension(sourcefile) == \".vala\" then\n                local sourcefile_c = target:autogenfile((sourcefile:gsub(\".vala$\", \".c\")))\n                batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.vala %s\", sourcefile)\n                table.insert(argv, path(sourcefile))\n                table.insert(sourcefiles, sourcefile)\n                local sourcefile_c_mtime = os.mtime(sourcefile_c)\n                if sourcefile_c_mtime > lastmtime then\n                    lastmtime = sourcefile_c_mtime\n                end\n            end\n        end\n\n        if #sourcefiles > 0 then\n            batchcmds:vrunv(valac.program, argv)\n            batchcmds:add_depfiles(sourcefiles)\n            batchcmds:set_depmtime(lastmtime)\n        end\n    end)\n\n    on_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n        -- Again, only vala files need special treatment\n        if path.extension(sourcefile) == \".vala\" then\n            local sourcefile_c = target:autogenfile((sourcefile:gsub(\".vala$\", \".c\")))\n            local basedir = path.directory(sourcefile_c)\n\n            batchcmds:mkdir(basedir)\n\n            local objectfile = target:objectfile(sourcefile_c)\n            table.insert(target:objectfiles(), objectfile)\n\n            batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.c %s\", sourcefile_c)\n            batchcmds:compile(sourcefile_c, objectfile, { configs = { force = { cflags = \"-w\" } } })\n\n            batchcmds:add_depfiles(sourcefile)\n            batchcmds:set_depmtime(os.mtime(objectfile))\n            batchcmds:set_depcache(target:dependfile(objectfile))\n        end\n    end)\n\n    after_install(function (target)\n        if target:is_shared() or target:is_static() then\n            local vapifile = target:data(\"vala.vapifile\")\n            if vapifile then\n                local installdir = target:installdir()\n                if installdir then\n                    local sharedir = path.join(installdir, \"share\")\n                    os.mkdir(sharedir)\n                    os.vcp(vapifile, sharedir)\n                end\n            end\n        end\n    end)\n\n    after_uninstall(function (target)\n        if target:is_shared() or target:is_static() then\n            local vapifile = target:data(\"vala.vapifile\")\n            if vapifile then\n                local installdir = target:installdir()\n                if installdir then\n                    os.rm(path.join(installdir, \"share\", path.filename(vapifile)))\n                end\n            end\n        end\n    end)\n\nrule(\"vala\")\n\n    -- add build rules\n    add_deps(\"vala.build\")\n\n    -- set compiler runtime, e.g. vs runtime\n    add_deps(\"utils.compiler.runtime\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n"
  },
  {
    "path": "xmake/rules/verilator/verilator.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        verilator.lua\n--\n\n-- imports\nimport(\"utils.progress\")\nimport(\"core.base.hashset\")\nimport(\"core.project.depend\")\nimport(\"private.action.build.object\", { alias = \"build_objectfiles\" })\nimport(\"core.base.json\")\nimport(\"lib.detect.find_tool\")\n\n-- parse sourcefiles from cmakefile\nfunction _get_sourcefiles_from_cmake(target, cmakefile)\n    local global_classes = {}\n    local classefiles_slow = {}\n    local classefiles_fast = {}\n    local supportfiles_slow = {}\n    local supportfiles_fast = {}\n    local targetname = target:name()\n    local verilator_root = assert(target:data(\"verilator.root\"), \"no verilator_root!\")\n    io.gsub(cmakefile, \"set%((%S-) (.-)%)\", function(key, values)\n        if key == targetname .. \"_GLOBAL\" then\n            -- get global class source files\n            -- set(hello_GLOBAL \"${VERILATOR_ROOT}/include/verilated.cpp\" \"${VERILATOR_ROOT}/include/verilated_threads.cpp\")\n            for classfile in values:gmatch(\"\\\"(.-)\\\"\") do\n                classfile = classfile:gsub(\"%${VERILATOR_ROOT}\", verilator_root)\n                if os.isfile(classfile) then\n                    table.insert(global_classes, classfile)\n                end\n            end\n        elseif key == targetname .. \"_CLASSES_SLOW\" then\n            for classfile in values:gmatch(\"\\\"(.-)\\\"\") do\n                table.insert(classefiles_slow, classfile)\n            end\n        elseif key == targetname .. \"_CLASSES_FAST\" then\n            for classfile in values:gmatch(\"\\\"(.-)\\\"\") do\n                table.insert(classefiles_fast, classfile)\n            end\n        elseif key == targetname .. \"_SUPPORT_SLOW\" then\n            for classfile in values:gmatch(\"\\\"(.-)\\\"\") do\n                table.insert(supportfiles_slow, classfile)\n            end\n        elseif key == targetname .. \"_SUPPORT_FAST\" then\n            for classfile in values:gmatch(\"\\\"(.-)\\\"\") do\n                table.insert(supportfiles_fast, classfile)\n            end\n        end\n    end)\n\n    -- get compiled source files\n    local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow,\n        supportfiles_fast)\n    return sourcefiles\nend\n\n-- parse sourcefiles from jsonfile\nfunction _get_sourcefiles_from_json(jsonfile)\n    local json_table = json.loadfile(jsonfile)\n    local sources_table = assert(json_table[\"sources\"], \"No sources field found in json file: %s.\", jsonfile)\n    local global_classes = sources_table[\"global\"] or {}\n    local classefiles_slow = sources_table[\"classes_slow\"] or {}\n    local classefiles_fast = sources_table[\"classes_fast\"] or {}\n    local supportfiles_slow = sources_table[\"support_slow\"] or {}\n    local supportfiles_fast = sources_table[\"support_fast\"] or {}\n\n    -- get compiled source files\n    local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow,\n        supportfiles_fast)\n    return sourcefiles\nend\n\n-- get languages\n--\n-- Select the Verilog language generation to support in the compiler.\n-- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012, v1800-2017, v1800-2023.\n--\nfunction _get_lanuage_flags(target)\n    local language_v\n    local languages = target:get(\"languages\")\n    if languages then\n        for _, language in ipairs(languages) do\n            if language:startswith(\"v\") then\n                language_v = language\n                break\n            end\n        end\n    end\n    if language_v then\n        local maps = {\n            -- Verilog\n            [\"v1364-1995\"] = \"+1364-1995ext+v\",\n            [\"v1364-2001\"] = \"+1364-2001ext+v\",\n            [\"v1364-2005\"] = \"+1364-2005ext+v\",\n            -- SystemVerilog\n            [\"v1800-2005\"] = \"+1800-2005ext+v\",\n            [\"v1800-2009\"] = \"+1800-2009ext+v\",\n            [\"v1800-2012\"] = \"+1800-2012ext+v\",\n            [\"v1800-2017\"] = \"+1800-2017ext+v\",\n            [\"v1800-2023\"] = \"+1800-2023ext+v\",\n        }\n        local flag = maps[language_v]\n        if flag then\n            return flag\n        else\n            assert(\"unknown language(%s) for verilator!\", language_v)\n        end\n    end\nend\n\nfunction _get_makefile_type(verilator)\n    local tool = assert(find_tool(\"verilator\", { program = verilator, version = true }), \"verilator not found!\")\n    local version = tool.version\n    local support_json = version >= \"5.036\"\n    local makefile_type = support_json and \"json\" or \"cmake\"\n    return support_json, makefile_type\nend\n\n-- get the custom verilator flags\n--\n-- add_values(\"verilator.flags\", \"--x-assign\", \"fast\")\n-- add_values(\"verilator.flags\", {\"--x-assign\", \"fast\"}, {\"--x-initial\", \"fast\"})\n--\n-- https://github.com/xmake-io/xmake/issues/7239\nfunction _get_verilator_flags(target)\n    local result = {}\n    local flags = target:values(\"verilator.flags\")\n    if flags then\n        for _, flag in ipairs(flags) do\n            table.join2(result, flag)\n        end\n    end\n    if #result > 0 then\n        return result\n    end\nend\n\nfunction config(target)\n    local toolchain = assert(target:toolchain(\"verilator\"), 'we need to set_toolchains(\"verilator\") in target(\"%s\")',\n        target:name())\n    local verilator = assert(toolchain:config(\"verilator\"), \"verilator not found!\")\n    local support_json, makefile_type = _get_makefile_type(verilator)\n    local autogendir = path.join(target:autogendir(), \"rules\", \"verilator\")\n    local tmpdir = os.tmpfile() .. \".dir\"\n    local makefile = path.join(tmpdir, \"test.\" .. makefile_type)\n    local sourcefile = path.join(tmpdir, \"main.v\")\n    local argv = { \"--cc\", \"--make\", makefile_type, \"--prefix\", \"test\", \"--Mdir\", tmpdir, \"main.v\" }\n    local flags = _get_verilator_flags(target)\n    local switches_flags = hashset.of(\"sc\", \"coverage\", \"timing\", \"trace\", \"trace-vcd\", \"trace-fst\", \"trace-saif\",\n        \"threads\")\n    if flags then\n        for idx, flag in ipairs(flags) do\n            if flag:startswith(\"--\") and switches_flags:has(flag:sub(3)) then\n                table.insert(argv, flag)\n                if flag:startswith(\"--threads\") then\n                    table.insert(argv, flags[idx + 1])\n                end\n            end\n        end\n    end\n    io.writefile(sourcefile, [[\nmodule hello;\ninitial begin\n$display(\"hello world!\");\n$finish ;\nend\nendmodule]])\n    os.mkdir(tmpdir)\n    -- we just pass relative sourcefile path to solve this issue on windows.\n    -- @see https://github.com/verilator/verilator/issues/3873\n    os.runv(verilator, argv, { curdir = tmpdir, envs = toolchain:runenvs() })\n\n    -- parse some configurations from makefile\n    local verilator_root\n    local switches = {}\n    local options_table = {}\n\n    if support_json then\n        local json_table = json.loadfile(makefile)\n        local system_table = assert(json_table[\"system\"], \"No system field found in json file: %s.\", makefile)\n        verilator_root = system_table[\"verilator_root\"]\n        options_table = assert(json_table[\"options\"], \"No options field found in json file: %s.\", makefile)\n        switches.SC = options_table[\"system_c\"] and \"1\" or \"0\"\n        switches.COVERAGE = options_table[\"coverage\"] and \"1\" or \"0\"\n        switches.TIMING = options_table[\"use_timing\"] and \"1\" or \"0\"\n        -- The thread field is a integer in float format, we need to convert it to string.\n        switches.THREADS = string.format(\"%d\", options_table[\"threads\"] or 1)\n        switches.TRACE_VCD = options_table[\"trace_vcd\"] and \"1\" or \"0\"\n        switches.TRACE_FST = options_table[\"trace_fst\"] and \"1\" or \"0\"\n        switches.TRACE_SAIF = options_table[\"trace_saif\"] and \"1\" or \"0\"\n    else\n        io.gsub(makefile, \"set%((%S-) (.-)%)\", function(key, values)\n            if key == \"VERILATOR_ROOT\" then\n                verilator_root = values:match(\"\\\"(.-)\\\" CACHE PATH\")\n                if not verilator_root then\n                    verilator_root = values:match(\"(.-) CACHE PATH\")\n                end\n            elseif key == \"test_SC\" then\n                -- SystemC output mode?  0/1 (from --sc)\n                switches.SC = values:trim()\n            elseif key == \"test_COVERAGE\" then\n                -- Coverage output mode?  0/1 (from --coverage)\n                switches.COVERAGE = values:trim()\n            elseif key == \"test_TIMING\" then\n                -- Timing mode?  0/1 (from --timing)\n                switches.TIMING = values:trim()\n            elseif key == \"test_THREADS\" then\n                -- Threaded output mode?  1/N threads (from --threads)\n                switches.THREADS = values:trim()\n            elseif key == \"test_TRACE_VCD\" then\n                -- VCD Tracing output mode?  0/1 (from --trace)\n                switches.TRACE_VCD = values:trim()\n            elseif key == \"test_TRACE_FST\" then\n                -- FST Tracing output mode? 0/1 (from --trace-fst)\n                switches.TRACE_FST = values:trim()\n            end\n        end)\n    end\n\n    assert(verilator_root, \"the verilator root directory not found!\")\n    target:data_set(\"verilator.root\", verilator_root)\n\n    -- add includedirs\n    if not os.isfile(autogendir) then\n        os.mkdir(autogendir)\n    end\n    target:add(\"includedirs\", autogendir, { public = true })\n    target:add(\"includedirs\", path.join(verilator_root, \"include\"), { public = true })\n    target:add(\"includedirs\", path.join(verilator_root, \"include\", \"vltstd\"), { public = true })\n\n    -- set languages\n    local languages = target:get(\"languages\")\n    local cxxlang = false\n    for _, lang in ipairs(languages) do\n        if lang:find(\"xx\", 1, true) or lang:find(\"++\", 1, true) then\n            cxxlang = true\n            break\n        end\n    end\n    if not cxxlang then\n        target:add(\"languages\", \"c++20\", { public = true })\n    end\n\n    -- add definitions for switches\n    for k, v in table.orderpairs(switches) do\n        target:add(\"defines\", \"VM_\" .. k .. \"=\" .. v, { public = true })\n    end\n    if support_json then\n        local cflags = options_table[\"cflags\"] or {}\n        for _, flag in ipairs(cflags) do\n            if flag:startswith(\"-D\") then\n                target:add(\"defines\", flag:sub(3), { public = true })\n            end\n        end\n    end\n\n    -- add syslinks\n    if support_json then\n        local ldflags = options_table[\"ldflags\"] or {}\n        for _, flag in ipairs(ldflags) do\n            if flag:startswith(\"-l\") then\n                target:add(\"syslinks\", flag:sub(3))\n            end\n        end\n    else\n        if target:is_plat(\"linux\", \"macosx\") and switches.THREADS == \"1\" then\n            target:add(\"syslinks\", \"pthread\")\n        end\n        if target:is_plat(\"linux\", \"macosx\") and switches.TRACE_FST == \"1\" then\n            target:add(\"syslinks\", \"z\")\n        end\n    end\n\n    os.rm(tmpdir)\nend\n\nfunction build_cppfiles(target, jobgraph, sourcebatch, opt)\n    local toolchain = assert(target:toolchain(\"verilator\"), 'we need to set_toolchains(\"verilator\") in target(\"%s\")',\n        target:name())\n    local verilator = assert(toolchain:config(\"verilator\"), \"verilator not found!\")\n    local support_json, makefile_type = _get_makefile_type(verilator)\n    local autogendir = path.join(target:autogendir(), \"rules\", \"verilator\")\n    local targetname = target:name()\n    local makefile = path.join(autogendir, targetname .. \".\" .. makefile_type)\n\n    -- build verilog files\n    depend.on_changed(function()\n        local argv = { \"--cc\", \"--make\", makefile_type, \"--prefix\", targetname, \"--Mdir\", autogendir }\n        local flags = _get_verilator_flags(target)\n        if flags then\n            table.join2(argv, flags)\n        end\n        local language_flags = _get_lanuage_flags(target)\n        if language_flags then\n            table.join2(argv, language_flags)\n        end\n        local sourcefiles = sourcebatch.sourcefiles\n        for _, sourcefile in ipairs(sourcefiles) do\n            progress.show(opt.progress or 0, \"${color.build.object}compiling.verilog %s\", sourcefile)\n            -- we need to use slashes to fix it on windows\n            -- @see https://github.com/verilator/verilator/issues/3873\n            if is_host(\"windows\") then\n                sourcefile = sourcefile:gsub(\"\\\\\", \"/\")\n            end\n            table.insert(argv, sourcefile)\n        end\n\n        -- generate c++ sourcefiles\n        os.vrunv(verilator, argv, { envs = toolchain:runenvs() })\n    end, {\n        dependfile = makefile .. \".d\",\n        files = sourcebatch.sourcefiles,\n        changed = target:is_rebuilt(),\n        lastmtime = os.mtime(makefile)\n    })\n\n    -- get compiled source files\n    local sourcefiles\n    if support_json then\n        sourcefiles = _get_sourcefiles_from_json(makefile)\n    else\n        sourcefiles = _get_sourcefiles_from_cmake(target, makefile)\n    end\n\n    -- do build\n    local sourcebatch_cpp = {\n        rulename = \"c++.build\",\n        sourcekind = \"cxx\",\n        sourcefiles = sourcefiles,\n        objectfiles = {},\n        dependfiles = {}\n    }\n    for _, sourcefile in ipairs(sourcefiles) do\n        local objectfile = target:objectfile(sourcefile)\n        local dependfile = target:dependfile(objectfile)\n        table.insert(target:objectfiles(), objectfile)\n        table.insert(sourcebatch_cpp.objectfiles, objectfile)\n        table.insert(sourcebatch_cpp.dependfiles, dependfile)\n    end\n    build_objectfiles(target, jobgraph, sourcebatch_cpp, opt)\nend\n\nfunction buildcmd_vfiles(target, batchcmds, sourcebatch, opt)\n    local toolchain = assert(target:toolchain(\"verilator\"), 'we need to set_toolchains(\"verilator\") in target(\"%s\")',\n        target:name())\n    local verilator = assert(toolchain:config(\"verilator\"), \"verilator not found!\")\n    local _, makefile_type = _get_makefile_type(verilator)\n    local autogendir = path.join(target:autogendir(), \"rules\", \"verilator\")\n    local targetname = target:name()\n    local makefile = path.join(autogendir, targetname .. \".\" .. makefile_type)\n    local dependfile = makefile .. \".d\"\n\n    local argv = { \"--cc\", \"--make\", makefile_type, \"--prefix\", targetname, \"--Mdir\", path(autogendir) }\n    local flags = _get_verilator_flags(target)\n    if flags then\n        table.join2(argv, flags)\n    end\n    local language_flags = _get_lanuage_flags(target)\n    if language_flags then\n        table.join2(argv, language_flags)\n    end\n    local sourcefiles = sourcebatch.sourcefiles\n    for _, sourcefile in ipairs(sourcefiles) do\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.verilog %s\", sourcefile)\n        table.insert(argv, path(sourcefile, function(v)\n            -- we need to use slashes to fix it on windows\n            -- @see https://github.com/verilator/verilator/issues/3873\n            if is_host(\"windows\") then\n                v = v:gsub(\"\\\\\", \"/\")\n            end\n            return v\n        end))\n    end\n\n    -- generate c++ sourcefiles\n    batchcmds:vrunv(verilator, argv, { envs = toolchain:runenvs() })\n    batchcmds:add_depfiles(sourcefiles)\n    batchcmds:set_depmtime(os.mtime(makefile))\n    batchcmds:set_depcache(dependfile)\nend\n\nfunction buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)\n    local toolchain = assert(target:toolchain(\"verilator\"), 'we need set_toolchains(\"verilator\") in target(\"%s\")',\n        target:name())\n    local verilator = assert(toolchain:config(\"verilator\"), \"verilator not found!\")\n    local support_json, makefile_type = _get_makefile_type(verilator)\n    local autogendir = path.join(target:autogendir(), \"rules\", \"verilator\")\n    local targetname = target:name()\n    local makefile = path.join(autogendir, targetname .. \".\" .. makefile_type)\n    local dependfile = path.join(autogendir, targetname .. \".build.d\")\n\n    -- get compiled source files\n    local sourcefiles\n    if support_json then\n        sourcefiles = _get_sourcefiles_from_json(makefile)\n    else\n        sourcefiles = _get_sourcefiles_from_cmake(target, makefile)\n    end\n\n    -- do build\n    for _, sourcefile in ipairs(sourcefiles) do\n        local objectfile = target:objectfile(sourcefile)\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.$(mode) %s\", path.filename(sourcefile))\n        batchcmds:compile(sourcefile, objectfile)\n        table.insert(target:objectfiles(), objectfile)\n    end\n    batchcmds:add_depfiles(sourcefiles)\n    batchcmds:set_depmtime(os.mtime(dependfile))\n    batchcmds:set_depcache(dependfile)\nend\n"
  },
  {
    "path": "xmake/rules/verilator/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- @see https://github.com/xmake-io/xmake/issues/3257\nrule(\"verilator.binary\")\n    add_deps(\"c++\")\n    set_extensions(\".v\", \".sv\")\n    on_load(function (target)\n        target:set(\"kind\", \"binary\")\n    end)\n\n    on_config(function (target)\n        import(\"verilator\").config(target)\n    end)\n\n    before_build_files(function (target, sourcebatch)\n        -- Just to avoid before_buildcmd_files being executed at build time\n    end)\n\n    on_build_files(function (target, jobgraph, sourcebatch, opt)\n        import(\"verilator\").build_cppfiles(target, jobgraph, sourcebatch, opt)\n    end, {jobgraph = true, batch = true, distcc = true})\n\n    before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_vfiles(target, batchcmds, sourcebatch, opt)\n    end)\n\n    on_buildcmd_files(function (target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)\n    end)\n\nrule(\"verilator.static\")\n    add_deps(\"c++\")\n    set_extensions(\".v\", \".sv\")\n    on_load(function (target)\n        target:set(\"kind\", \"static\")\n    end)\n\n    on_config(function (target)\n        import(\"verilator\").config(target)\n    end)\n\n    before_build_files(function (target, sourcebatch)\n        -- Just to avoid before_buildcmd_files being executed at build time\n    end)\n\n    on_build_files(function (target, jobgraph, sourcebatch, opt)\n        import(\"verilator\").build_cppfiles(target, jobgraph, sourcebatch, opt)\n    end, {jobgraph = true, batch = true, distcc = true})\n\n    before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_vfiles(target, batchcmds, sourcebatch, opt)\n    end)\n\n    on_buildcmd_files(function (target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)\n    end)\n\nrule(\"verilator.shared\")\n    add_deps(\"c++\")\n    set_extensions(\".v\", \".sv\")\n    on_load(function (target)\n        target:set(\"kind\", \"shared\")\n    end)\n\n    on_config(function (target)\n        import(\"verilator\").config(target)\n    end)\n\n    before_build_files(function (target, sourcebatch)\n        -- Just to avoid before_buildcmd_files being executed at build time\n    end)\n\n    on_build_files(function (target, jobgraph, sourcebatch, opt)\n        import(\"verilator\").build_cppfiles(target, jobgraph, sourcebatch, opt)\n    end, {jobgraph = true, batch = true, distcc = true})\n\n    before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_vfiles(target, batchcmds, sourcebatch, opt)\n    end)\n\n    on_buildcmd_files(function (target, batchcmds, sourcebatch, opt)\n        import(\"verilator\").buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)\n    end)\n"
  },
  {
    "path": "xmake/rules/wdk/env/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.project.config\")\n\n-- get version of the library sub-directory\nfunction _winver_libdir(winver)\n\n    -- ignore the subname with '_xxx'\n    winver = (winver or \"\"):split('_')[1]\n\n    -- make defined values\n    local vervals =\n    {\n        win81   = \"winv6.3\"\n    ,   winblue = \"winv6.3\"\n    ,   win8    = \"win8\"\n    ,   win7    = \"win7\"\n    }\n    return vervals[winver]\nend\n\nfunction _base(target, mode)\n\n    -- get wdk\n    local wdk = target:data(\"wdk\")\n\n    -- get arch\n    local arch = config.arch()\n\n    -- add definitions\n    local ver = mode == \"um\" and wdk.umdfver or wdk.kmdfver\n    local ver_split = ver:split('%.')\n    if arch == \"x64\" then\n        target:add(\"defines\", \"_WIN64\", \"_AMD64_\", \"AMD64\")\n    else\n        target:add(\"defines\", \"_X86_=1\", \"i386=1\")\n        target:add(\"defines\", \"DEPRECATE_DDK_FUNCTIONS=1\", \"MSC_NOOPT\", \"_ATL_NO_WIN_SUPPORT\")\n        target:add(\"defines\", \"STD_CALL\")\n        target:add(\"cxflags\", \"-Gz\", {force = true})\n    end\n\n    local prefix = mode == \"um\" and \"UM\" or \"KM\"\n    target:add(\"defines\", prefix .. \"DF_VERSION_MAJOR=\" .. ver_split[1], prefix .. \"DF_VERSION_MINOR=\" .. ver_split[2], prefix .. \"DF_USING_NTSTATUS\")\n    target:add(\"defines\", \"WIN32_LEAN_AND_MEAN=1\", \"WINNT=1\", \"_WINDLL\")\n\n    -- add include directories\n    target:add(\"sysincludedirs\", path.join(wdk.includedir, wdk.sdkver, mode))\n    target:add(\"sysincludedirs\", path.join(wdk.includedir, \"wdf\", mode .. \"df\", ver))\n\n    -- add link directories\n    target:add(\"linkdirs\", path.join(wdk.libdir, wdk.sdkver, mode, arch))\n    local p = path.join(wdk.libdir, \"wdf\", mode .. \"df\", arch, ver)\n    if os.isdir(p) then\n        target:add(\"linkdirs\", p)\n    end\nend\n\n-- load for umdf environment\nfunction umdf(target)\n\n    _base(target, \"um\")\nend\n\n-- load for kmdf environment\nfunction kmdf(target)\n\n    -- get wdk\n    local wdk = target:data(\"wdk\")\n\n    -- get arch\n    local arch = config.arch()\n\n    -- add definitions\n    local winver  = target:values(\"wdk.env.winver\") or config.get(\"wdk_winver\")\n\n    _base(target, \"km\")\n\n    -- add include directories\n    target:add(\"sysincludedirs\", path.join(wdk.includedir, wdk.sdkver, \"shared\"))\n    if target:rule(\"wdk.driver\") then\n        target:add(\"sysincludedirs\", path.join(wdk.includedir, wdk.sdkver, \"km\", \"crt\"))\n    end\n\n    -- add link directories\n    local libdirver = _winver_libdir(winver)\n    if libdirver then\n        target:add(\"linkdirs\", path.join(wdk.libdir, libdirver, \"km\", arch))\n    end\nend\n\n-- load for wdm environment\nfunction wdm(target)\n\n    kmdf(target)\nend\n"
  },
  {
    "path": "xmake/rules/wdk/env/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: environment\nrule(\"wdk.env\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"os.winver\", {alias = \"os_winver\"})\n        import(\"core.project.config\")\n        import(\"detect.sdks.find_wdk\")\n\n        -- load wdk environment\n        if not target:data(\"wdk\") then\n\n            -- find wdk\n            local wdk = assert(find_wdk(nil, {verbose = true}), \"WDK not found!\")\n\n            -- update the umdf sdk version from the xmake.lua\n            local umdfver = target:values(\"wdk.umdf.sdkver\")\n            if umdfver then\n                wdk.umdfver = umdfver\n            end\n\n            -- update the kmdf sdk version from the xmake.lua\n            local kmdfver = target:values(\"wdk.kmdf.sdkver\")\n            if kmdfver then\n                wdk.kmdfver = kmdfver\n            end\n\n            -- add definitions for debug\n            if is_mode(\"debug\") then\n                target:add(\"defines\", \"DBG=1\")\n            end\n\n            -- get winver name\n            local winver = target:values(\"wdk.env.winver\") or config.get(\"wdk_winver\")\n\n            -- get winver version\n            local winver_version = os_winver.version(winver or \"\") or \"0x0A00\"\n\n            -- get target version\n            local target_version = os_winver.target_version(winver or \"\") or \"0x0A00\"\n\n            -- get winnt version\n            local winnt_version = os_winver.winnt_version(winver or \"\") or \"0x0A00\"\n\n            -- get ntddi version\n            local ntddi_version = os_winver.ntddi_version(winver or \"\") or \"0x0A000000\"\n\n            -- add definitions for winver\n            target:add(\"defines\", \"_WIN32_WINNT=\" .. winnt_version, \"WINVER=\" .. winver_version, \"NTDDI_VERSION=\" .. ntddi_version, \"_NT_TARGET_VERSION=\" .. target_version)\n\n            -- set builtin version values\n            target:values_set(\"wdk.env.winnt_version\", winnt_version)\n            target:values_set(\"wdk.env.ntddi_version\", ntddi_version)\n            target:values_set(\"wdk.env.winver_version\", winver_version)\n            target:values_set(\"wdk.env.target_version\", target_version)\n\n            -- save wdk\n            target:data_set(\"wdk\", wdk)\n        end\n    end)\n\n-- define rule: umdf\nrule(\"wdk.env.umdf\")\n\n    -- add rules\n    add_deps(\"wdk.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"load\").umdf(target)\n    end)\n\n-- define rule: kmdf\nrule(\"wdk.env.kmdf\")\n\n    -- add rules\n    add_deps(\"wdk.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"load\").kmdf(target)\n    end)\n\n-- define rule: wdm\nrule(\"wdk.env.wdm\")\n\n    -- add rules\n    add_deps(\"wdk.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"load\").wdm(target)\n    end)\n"
  },
  {
    "path": "xmake/rules/wdk/inf/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: *.inf\nrule(\"wdk.inf\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- set extensions\n    set_extensions(\".inf\", \".inx\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get stampinf\n        local stampinf = path.join(wdk.bindir, wdk.sdkver, arch, is_host(\"windows\") and \"stampinf.exe\" or \"stampinf\")\n\n        -- save uic\n        target:data_set(\"wdk.stampinf\", stampinf)\n    end)\n\n    -- on build file\n    on_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- the target file\n        local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. \".inf\")\n\n        -- save this target file for signing (wdk.sign.*, wdk.package.* rules)\n        target:data_set(\"wdk.sign.inf\", targetfile)\n\n        -- init args\n        local args = {\"-d\", \"*\", \"-a\", is_arch(\"x64\") and \"amd64\" or \"x86\", \"-v\", \"*\"}\n        local flags = target:values(\"wdk.inf.flags\", sourcefile)\n        if flags then\n            table.join2(args, flags)\n        end\n        local wdk = target:data(\"wdk\")\n        if wdk then\n            if wdk.kmdfver and (target:rule(\"wdk.env.wdm\") or target:rule(\"wdk.env.kmdf\")) then\n                table.insert(args, \"-k\")\n                table.insert(args, wdk.kmdfver)\n            elseif wdk.umdfver then\n                table.insert(args, \"-u\")\n                table.insert(args, wdk.umdfver .. \".0\")\n            end\n        end\n        table.insert(args, \"-f\")\n        table.insert(args, targetfile)\n\n        -- need build this object?\n        local dependfile = target:dependfile(targetfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(targetfile), values = args}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.wdk.inf %s\", sourcefile)\n\n        -- get stampinf\n        local stampinf = target:data(\"wdk.stampinf\")\n        assert(stampinf and os.isexec(stampinf), \"stampinf not found!\")\n\n        -- update the timestamp\n        os.cp(sourcefile, targetfile)\n        os.vrunv(stampinf, args)\n\n        -- update files and values to the dependent file\n        dependinfo.files = {sourcefile}\n        dependinfo.values = args\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/wdk/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.base.semver\")\nimport(\"os.winver\", {alias = \"os_winver\"})\n\nfunction _add_linkflags(target, t, ...)\n    local args = table.pack(...)\n    if target:has_tool(\"ld\", \"clang\", \"clangxx\") then\n        for i, flag in ipairs(args) do\n            if type(flag) == \"string\" then\n                args[i] = \"-Wl,\" .. flag\n            end\n        end\n    end\n    target:add(t, table.unpack(args))\nend\n\nfunction _add_ldflags(target, ...)\n    _add_linkflags(target, \"ldflags\", ...)\nend\n\nfunction _add_shflags(target, ...)\n    _add_linkflags(target, \"shflags\", ...)\nend\n\n-- load for umdf driver\nfunction driver_umdf(target)\n\n    -- set kind\n    target:set(\"kind\", \"shared\")\n\n    -- add links\n    target:add(\"links\", \"ntdll\", \"OneCoreUAP\", \"mincore\", \"ucrt\")\n\n    _add_shflags(target, \"-NODEFAULTLIB:kernel32.lib\", \"-NODEFAULTLIB:user32.lib\", \"-NODEFAULTLIB:libucrt.lib\", {force = true})\n\n    -- add subsystem\n    if not target:values(\"windows.subsystem\") then\n        target:values_set(\"windows.subsystem\", \"windows,\" .. os_winver.subsystem(winver))\n    end\n\n    -- set default driver entry if does not exist\n    local entry = false\n    for _, ldflag in ipairs(target:get(\"shflags\")) do\n        ldflag = ldflag:lower()\n        if ldflag:find(\"[/%-]entry:\") then\n            entry = true\n            break\n        end\n    end\n\n    -- get wdk\n    local wdk = target:data(\"wdk\")\n    if not entry and semver.compare(wdk.umdfver, \"2.0\") >= 0 then\n        target:add(\"links\", \"WdfDriverStubUm\")\n    end\nend\n\nfunction _kernel_driver_base(target, default_entrypoint)\n\n    -- set kind\n    target:set(\"kind\", \"binary\")\n\n    -- set filename: xxx.sys\n    target:set(\"filename\", target:basename() .. \".sys\")\n\n    -- add links\n    local winver = target:values(\"wdk.env.winver\") or config.get(\"wdk_winver\")\n    if winver and os_winver.version(winver) >= os_winver.version(\"win8\") then\n        target:add(\"links\", \"BufferOverflowFastFailK\")\n    else\n        target:add(\"links\", \"BufferOverflowK\")\n    end\n\n    -- compile as kernel driver\n    if not target:has_tool(\"cc\", \"clang\", \"clangxx\") then\n       target:add(\"cxflags\", \"-kernel\", {force = true})\n    else\n       -- emulate kernel mode https://learn.microsoft.com/en-us/cpp/build/reference/kernel-create-kernel-mode-binary?view=msvc-170\n       target:add(\"cxxflags\", \"-fno-exceptions\", \"-fno-rtti\")\n       target:add(\"defines\", \"_KERNEL_MODE=1\")\n    end\n\n    _add_ldflags(target, \"-kernel\", \"-driver\", \"-nodefaultlib\", {force = true})\n\n    -- add subsystem\n    if not target:values(\"windows.subsystem\") then\n        target:values_set(\"windows.subsystem\", \"native,\" .. os_winver.subsystem(winver))\n    end\n\n    -- set default driver entry if does not exist\n    local has_entry = false\n    for _, ldflag in ipairs(target:get(\"ldflags\")) do\n        if type(ldflag) == \"string\" then\n            ldflag = ldflag:lower()\n            if ldflag:find(\"[/%-]entry:\") then\n                has_entry = true\n                break\n            end\n        end\n    end\n    if not has_entry then\n        local arch = (target:is_arch(\"x86\") and \"@8\" or \"\")        target:add(\"links\", \"WdfDriverEntry\")\n        _add_ldflags(target, \"-entry:\" .. default_entrypoint .. arch, {force = true})\n    end\nend\n\n-- load for kmdf driver\nfunction driver_kmdf(target)\n\n    target:add(\"links\", \"ntoskrnl\", \"hal\", \"wmilib\", \"WdfLdr\", \"ntstrsafe\", \"wdmsec\")\n\n    _kernel_driver_base(target, \"FxDriverEntry\")\nend\n\n-- load for wdm driver\nfunction driver_wdm(target)\n    target:add(\"links\", \"ntoskrnl\", \"hal\", \"wmilib\", \"ntstrsafe\")\n\n    _kernel_driver_base(target, \"GsDriverEntry\")\nend\n\n"
  },
  {
    "path": "xmake/rules/wdk/man/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: *.man\nrule(\"wdk.man\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- set extensions\n    set_extensions(\".man\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get ctrpp\n        local ctrpp = path.join(wdk.bindir, arch, \"ctrpp.exe\")\n        if not os.isexec(ctrpp) then\n            ctrpp = path.join(wdk.bindir, wdk.sdkver, arch, \"ctrpp.exe\")\n        end\n\n        -- save ctrpp\n        target:data_set(\"wdk.ctrpp\", ctrpp)\n    end)\n\n    -- before build file\n    before_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- get ctrpp\n        local ctrpp = target:data(\"wdk.ctrpp\")\n        assert(ctrpp and os.isexec(ctrpp), \"ctrpp not found!\")\n\n        -- get output directory\n        local outputdir = path.join(target:autogendir(), \"rules\", \"wdk\", \"man\")\n\n        -- init args\n        local args = {sourcefile}\n        local flags = target:values(\"wdk.man.flags\", sourcefile)\n        if flags then\n            table.join2(args, flags)\n        end\n\n        -- add includedirs\n        target:add(\"includedirs\", outputdir)\n\n        -- add header file\n        local header = target:values(\"wdk.man.header\", sourcefile)\n        local headerfile = header and path.join(outputdir, header) or nil\n        if headerfile then\n            table.insert(args, \"-o\")\n            table.insert(args, headerfile)\n        else\n            raise(\"please call `set_values(\\\"wdk.man.header\\\", \\\"header.h\\\")` to set the provider header file name!\")\n        end\n\n        -- add prefix\n        local prefix = target:values(\"wdk.man.prefix\", sourcefile)\n        if prefix then\n            table.insert(args, \"-prefix\")\n            table.insert(args, prefix)\n        end\n\n        -- add counter header file\n        local counter_header = target:values(\"wdk.man.counter_header\", sourcefile)\n        local counter_headerfile = counter_header and path.join(outputdir, counter_header) or nil\n        if counter_headerfile then\n            table.insert(args, \"-ch\")\n            table.insert(args, counter_headerfile)\n        end\n\n        -- add resource file\n        local resource = target:values(\"wdk.man.resource\", sourcefile)\n        local resourcefile = resource and path.join(outputdir, resource) or nil\n        if resourcefile then\n            table.insert(args, \"-rc\")\n            table.insert(args, resourcefile)\n        end\n\n        -- need build this object?\n        local dependfile = target:dependfile(headerfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(headerfile), values = args}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.wdk.man %s\", sourcefile)\n\n        -- generate header and resource file\n        if not os.isdir(outputdir) then\n            os.mkdir(outputdir)\n        end\n        os.vrunv(ctrpp, args)\n\n        if target:has_tool(\"cxx\", \"clang\", \"clangxx\") then\n            if resourcefile and os.isfile(resourcefile) then\n                local content = io.readfile(resourcefile)\n                io.writefile(resourcefile, content, {encoding = \"utf8\"})\n            end\n        end\n\n        -- update files and values to the dependent file\n        dependinfo.files  = {sourcefile}\n        dependinfo.values = args\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/wdk/mc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: *.mc\nrule(\"wdk.mc\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- set extensions\n    set_extensions(\".mc\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get mc\n        local mc = path.join(wdk.bindir, arch, is_host(\"windows\") and \"mc.exe\" or \"mc\")\n        if not os.isexec(mc) then\n            mc = path.join(wdk.bindir, wdk.sdkver, arch, is_host(\"windows\") and \"mc.exe\" or \"mc\")\n        end\n\n        -- save mc\n        target:data_set(\"wdk.mc\", mc)\n    end)\n\n    -- before build file\n    before_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- get mc\n        local mc = target:data(\"wdk.mc\")\n        assert(mc and os.isexec(mc), \"mc not found!\")\n\n        -- get output directory\n        local outputdir = path.join(target:autogendir(), \"rules\", \"wdk\", \"mc\")\n\n        -- init args\n        local args = {}\n        local flags = target:values(\"wdk.mc.flags\", sourcefile)\n        if flags then\n            table.join2(args, flags)\n        end\n        table.insert(args, \"-h\")\n        table.insert(args, outputdir)\n        table.insert(args, \"-r\")\n        table.insert(args, outputdir)\n        table.insert(args, sourcefile)\n\n        -- add includedirs\n        target:add(\"includedirs\", outputdir)\n\n        -- add header file\n        local header = target:values(\"wdk.mc.header\", sourcefile)\n        local headerfile = header and path.join(outputdir, header) or nil\n        if headerfile then\n            table.insert(args, \"-z\")\n            table.insert(args, path.basename(headerfile))\n        else\n            headerfile = path.join(outputdir, path.basename(sourcefile) .. \".h\")\n        end\n\n        -- need build this object?\n        local dependfile = target:dependfile(headerfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(headerfile), values = args}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.wdk.mc %s\", sourcefile)\n\n        -- do message compile\n        if not os.isdir(outputdir) then\n            os.mkdir(outputdir)\n        end\n        os.vrunv(mc, args)\n\n        -- update files and values to the dependent file\n        dependinfo.files  = {sourcefile}\n        dependinfo.values = args\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/wdk/mof/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: *.mof\nrule(\"wdk.mof\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- set extensions\n    set_extensions(\".mof\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n        import(\"lib.detect.find_program\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get mofcomp\n        local mofcomp = find_program(\"mofcomp\", {check = function (program)\n            local tmpmof = os.tmpfile()\n            io.writefile(tmpmof, \"\")\n            os.run(\"%s %s\", program, tmpmof)\n            os.tryrm(tmpmof)\n        end})\n\n        -- get wmimofck\n        local wmimofck = nil\n        if arch == \"x64\" then\n            wmimofck = path.join(wdk.bindir, wdk.sdkver, \"x64\", \"wmimofck.exe\")\n            if not os.isexec(wmimofck) then\n                wmimofck = path.join(wdk.bindir, wdk.sdkver, \"x86\", \"x64\", \"wmimofck.exe\")\n            end\n        else\n            wmimofck = path.join(wdk.bindir, wdk.sdkver, \"x86\", \"wmimofck.exe\")\n        end\n\n        -- save mofcomp and wmimofck\n        target:data_set(\"wdk.mofcomp\", mofcomp)\n        target:data_set(\"wdk.wmimofck\", wmimofck)\n    end)\n\n    -- before build file\n    before_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- get mofcomp\n        local mofcomp = target:data(\"wdk.mofcomp\")\n        assert(mofcomp and os.isexec(mofcomp), \"mofcomp not found!\")\n\n        -- get wmimofck\n        local wmimofck = target:data(\"wdk.wmimofck\")\n        assert(wmimofck and os.isexec(wmimofck), \"wmimofck not found!\")\n\n        -- get output directory\n        local outputdir = path.join(target:autogendir(), \"rules\", \"wdk\", \"mof\")\n\n        -- add includedirs\n        target:add(\"includedirs\", outputdir)\n\n        -- get header file\n        local header = target:values(\"wdk.mof.header\", sourcefile)\n        local headerfile = path.join(outputdir, header and header or (path.basename(sourcefile) .. \".h\"))\n\n        -- get some temporary file\n        local sourcefile_mof     = path.join(outputdir, path.filename(sourcefile))\n        local targetfile_mfl     = path.join(outputdir, \".\" .. path.basename(sourcefile) .. \".mfl\")\n        local targetfile_mof     = path.join(outputdir, \".\" .. path.basename(sourcefile) .. \".mof\")\n        local targetfile_mfl_mof = path.join(outputdir, \".\" .. path.basename(sourcefile) .. \".mfl.mof\")\n        local targetfile_bmf     = path.join(outputdir, path.basename(sourcefile) .. \".bmf\")\n        local outputdir_htm      = path.join(outputdir, \"htm\")\n        local targetfile_vbs     = path.join(outputdir, path.basename(sourcefile) .. \".vbs\")\n\n        -- need build this object?\n        local dependfile = target:dependfile(headerfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(headerfile), values = args}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.wdk.mof %s\", sourcefile)\n\n        -- ensure the output directory\n        if not os.isdir(outputdir) then\n            os.mkdir(outputdir)\n        end\n\n        -- copy *.mof to output directory\n        os.cp(sourcefile, sourcefile_mof)\n\n        -- do mofcomp\n        os.vrunv(mofcomp, {\"-Amendment:ms_409\", \"-MFL:\" .. targetfile_mfl, \"-MOF:\" .. targetfile_mof, sourcefile_mof})\n\n        -- do wmimofck\n        os.vrunv(wmimofck, {\"-y\" .. targetfile_mof, \"-z\" .. targetfile_mfl, targetfile_mfl_mof})\n\n        -- do mofcomp to generate *.bmf\n        os.vrunv(mofcomp, {\"-B:\" .. targetfile_bmf, targetfile_mfl_mof})\n\n        -- do wmimofck to generate *.h\n        os.vrunv(wmimofck, {\"-h\" .. headerfile, \"-w\" .. outputdir_htm, \"-m\", \"-t\" .. targetfile_vbs, targetfile_bmf})\n\n        -- update files and values to the dependent file\n        dependinfo.files  = {sourcefile}\n        dependinfo.values = args\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/wdk/package/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: package *.cab\nrule(\"wdk.package.cab\")\n\n    -- on package\n    on_package(function (target)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.project.config\")\n        import(\"lib.detect.find_program\")\n\n        -- the output directory\n        local outputdir = path.join(option.get(\"outputdir\") or config.builddir(), \"drivers\", target:name())\n        local mode = config.mode()\n        if mode then\n            outputdir = path.join(outputdir, mode)\n        end\n        local arch = config.arch()\n        if arch then\n            outputdir = path.join(outputdir, arch)\n        end\n\n        -- the package file\n        local packagefile = path.join(outputdir, target:name() .. \".cab\")\n\n        -- the .ddf file\n        local ddfile = os.tmpfile(target:targetfile()) .. \".ddf\"\n\n        -- trace progress info\n        if option.get(\"verbose\") then\n            cprint(\"${dim magenta}packaging %s\", packagefile)\n        else\n            cprint(\"${magenta}packaging %s\", packagefile)\n        end\n\n        -- get makecab\n        local makecab = find_program(\"makecab\", {check = \"/?\"})\n        assert(makecab and os.isexec(makecab), \"makecab not found!\")\n\n        -- make .ddf file\n        local file = io.open(ddfile, \"w\")\n        if file then\n            file:print(\"; %s.ddf\", target:name())\n            file:print(\";\")\n            file:print(\".OPTION EXPLICIT     ; Generate errors\")\n            file:print(\".Set CabinetFileCountThreshold=0\")\n            file:print(\".Set FolderFileCountThreshold=0\")\n            file:print(\".Set FolderSizeThreshold=0\")\n            file:print(\".Set MaxCabinetSize=0\")\n            file:print(\".Set MaxDiskFileCount=0\")\n            file:print(\".Set MaxDiskSize=0\")\n            file:print(\".Set CompressionType=MSZIP\")\n            file:print(\".Set Cabinet=on\")\n            file:print(\".Set Compress=on\")\n            file:print(\";Specify file name for new cab file\")\n            file:print(\".Set CabinetNameTemplate=%s.cab\", target:name())\n            file:print(\"; Specify the subdirectory for the files.  \")\n            file:print(\"; Your cab file should not have files at the root level,\")\n            file:print(\"; and each driver package must be in a separate subfolder.\")\n            file:print(\".Set DiskDirectoryTemplate=%s\", outputdir)\n            file:print(\";Specify files to be included in cab file\")\n            local infile = target:data(\"wdk.sign.inf\")\n            if infile and os.isfile(infile) then\n                file:print(path.absolute(infile))\n            end\n            file:print(path.absolute(target:targetfile()))\n            file:close()\n        end\n\n        -- make .cab\n        os.vrunv(makecab, {\"/f\", ddfile})\n\n        -- save this package file for signing (wdk.sign.* rules)\n        target:data_set(\"wdk.sign.cab\", packagefile)\n    end)\n\n\n"
  },
  {
    "path": "xmake/rules/wdk/sign/sign.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        sign.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.global\")\nimport(\"core.project.config\")\n\n-- get tool\nfunction _get_tool(target, name)\n\n    -- init cache\n    _g.tools = _g.tools or {}\n\n    -- get it from the cache\n    local tool = _g.tools[name]\n    if not tool then\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get tool\n        tool = path.join(wdk.bindir, arch, name .. \".exe\")\n        if not os.isexec(tool) then\n            tool = path.join(wdk.bindir, wdk.sdkver, arch, name .. \".exe\")\n        end\n        assert(os.isexec(tool), name .. \" not found!\")\n        _g.tools[name] = tool\n    end\n    return tool\nend\n\n-- do sign\nfunction main(target, filepath, mode)\n\n    -- get signtool\n    local signtool = _get_tool(target, \"signtool\")\n\n    -- init arguments\n    local argv = {\"sign\", \"/v\"}\n    local timestamp = target:values(\"wdk.sign.timestamp\")\n    if timestamp then\n        table.insert(argv, \"/t\")\n        table.insert(argv, timestamp)\n    end\n    local company = target:values(\"wdk.sign.company\")\n    if company then\n        table.insert(argv, \"/n\")\n        table.insert(argv, company)\n    end\n    local certfile = target:values(\"wdk.sign.certfile\")\n    if certfile then\n        table.insert(argv, \"/ac\")\n        table.insert(argv, certfile)\n    end\n    local thumbprint = target:values(\"wdk.sign.thumbprint\")\n    if thumbprint then\n        table.insert(argv, \"/sha1\")\n        table.insert(argv, thumbprint)\n    end\n    local store = target:values(\"wdk.sign.store\")\n    if store then\n        table.insert(argv, \"/a\")\n        table.insert(argv, \"/s\")\n        table.insert(argv, store)\n    end\n    local digest_algorithm = target:values(\"wdk.sign.digest_algorithm\")\n    if digest_algorithm then\n        table.insert(argv, \"/fd\")\n        table.insert(argv, digest_algorithm)\n    end\n\n    -- uses the default test certificate\n    if mode == \"test\" and (not certfile and not thumbprint and not store) then\n        table.insert(argv, \"/a\")\n        table.insert(argv, \"/n\")\n        table.insert(argv, \"xmake.io(test)\")\n        table.insert(argv, \"/s\")\n        table.insert(argv, \"PrivateCertStore\")\n    end\n\n    -- add target file\n    table.insert(argv, filepath)\n\n    -- do sign\n    os.vrunv(signtool, argv)\nend\n"
  },
  {
    "path": "xmake/rules/wdk/sign/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: sign\n--\n-- values:\n--   - wdk.sign.mode:       nosign/test/release (default: nosign)\n--   - wdk.sign.store:      PrivateCertStore\n--   - wdk.sign.thumbprint: 032122545DCAA6167B1ADBE5F7FDF07AE2234AAA\n--   - wdk.sign.company:    xmake.io\n--   - wdk.sign.certfile:   signcert.cer\n--   - wdk.sign.timestamp:  http://timestamp.verisign.com/scripts/timstamp.dll\n--\nrule(\"wdk.sign\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n        import(\"utils.wdk.testcert\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get inf2cat\n        local inf2cat = path.join(wdk.bindir, arch, \"inf2cat.exe\")\n        if not os.isexec(inf2cat) then\n            inf2cat = path.join(wdk.bindir, wdk.sdkver, arch, \"inf2cat.exe\")\n        end\n        if not os.isexec(inf2cat) then\n            inf2cat = path.join(wdk.bindir, wdk.sdkver, \"x86\", \"inf2cat.exe\")\n        end\n        target:data_set(\"wdk.sign.inf2cat\", inf2cat)\n\n        -- check\n        local mode = target:values(\"wdk.sign.mode\")\n        local store = target:values(\"wdk.sign.store\")\n        local certfile = target:values(\"wdk.sign.certfile\")\n        local thumbprint = target:values(\"wdk.sign.thumbprint\")\n        if mode and (not certfile and not thumbprint and not store) then\n            if mode == \"test\" then\n                -- attempt to install test certificate first\n                local ok = try\n                {\n                    function ()\n                        testcert(\"install\")\n                        return true\n                    end\n                }\n                if not ok then\n                    raise([[please first select one following step for signing:\n1. run `$xmake l utils.wdk.testcert install` as admin in console (only once) or\n2. add set_values(\\\"wdk.sign.[certfile|store|thumbprint]\\\", ...) in xmake.lua]], mode)\n                end\n            else\n                raise(\"please add set_values(\\\"wdk.sign.[certfile|store|thumbprint]\\\", ...) for %s signing!\", mode)\n            end\n        end\n    end)\n\n    -- after build\n    after_build(function (target, opt)\n\n        -- imports\n        import(\"sign\")\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.config\")\n        import(\"core.project.depend\")\n        import(\"lib.detect.find_file\")\n        import(\"utils.progress\")\n\n        -- need build this object?\n        local tempfile = os.tmpfile(target:targetfile())\n        local dependfile = tempfile .. \".d\"\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(tempfile)}) then\n            return\n        end\n\n        -- get sign mode\n        local signmode = target:values(\"wdk.sign.mode\")\n        if not signmode then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.target}signing.%s %s\", signmode, path.filename(target:targetfile()))\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get inf2cat\n        local inf2cat = target:data(\"wdk.sign.inf2cat\")\n        assert(inf2cat and os.isexec(inf2cat), \"inf2cat not found!\")\n\n        -- sign the target file\n        sign(target, target:targetfile(), signmode)\n\n        -- get inf file\n        local infile = target:data(\"wdk.sign.inf\")\n        if infile and os.isfile(infile) then\n\n            -- do inf2cat\n            local inf2cat_dir = path.directory(target:targetfile())\n            local inf2cat_argv = {\"/driver:\" .. inf2cat_dir, \"/uselocaltime\"}\n            local inf2cat_os = target:values(\"wdk.inf2cat.os\") or {\"XP_\" .. arch, \"7_\" .. arch, \"8_\" .. arch, \"10_\" .. arch}\n            table.insert(inf2cat_argv, \"/os:\" .. table.concat(table.wrap(inf2cat_os), ','))\n            os.vrunv(inf2cat, inf2cat_argv)\n\n            -- get *.cat file path from the output directory\n            local catfile = find_file(\"*.cat\", inf2cat_dir)\n            assert(catfile, \"*.cat not found!\")\n\n            -- sign *.cat file\n            sign(target, catfile, signmode)\n        else\n            -- trace\n            vprint(\"Inf2Cat task was skipped as there were no inf files to process\")\n        end\n\n        -- update files and values to the dependent file\n        dependinfo.files = {target:targetfile()}\n        depend.save(dependinfo, dependfile)\n        io.writefile(tempfile, \"\")\n    end)\n\n    -- after package\n    after_package(function (target)\n\n        -- imports\n        import(\"sign\")\n        import(\"core.base.option\")\n\n        -- get signtool\n        local signtool = target:data(\"wdk.sign.signtool\")\n\n        -- get package file\n        local packagefile = target:data(\"wdk.sign.cab\")\n        assert(packagefile and os.isfile(packagefile), \"the driver package file(.cab) not found!\")\n\n        -- get sign mode\n        local signmode = target:values(\"wdk.sign.mode\") or \"test\"\n\n        -- trace progress info\n        if option.get(\"verbose\") then\n            cprint(\"${dim magenta}signing.%s %s\", signmode, path.filename(packagefile))\n        else\n            cprint(\"${magenta}signing.%s %s\", signmode, path.filename(packagefile))\n        end\n\n        -- sign package file\n        sign(target, packagefile, signmode)\n    end)\n"
  },
  {
    "path": "xmake/rules/wdk/tracewpp/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: tracewpp\nrule(\"wdk.tracewpp\")\n\n    -- add rule: wdk environment\n    add_deps(\"wdk.env\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n\n        -- get wdk\n        local wdk = target:data(\"wdk\")\n\n        -- get arch\n        local arch = assert(config.arch(), \"arch not found!\")\n\n        -- get tracewpp\n        local tracewpp = path.join(wdk.bindir, arch, is_host(\"windows\") and \"tracewpp.exe\" or \"tracewpp\")\n        if not os.isexec(tracewpp) then\n            tracewpp = path.join(wdk.bindir, wdk.sdkver, arch, is_host(\"windows\") and \"tracewpp.exe\" or \"tracewpp\")\n        end\n\n        -- save tracewpp\n        target:data_set(\"wdk.tracewpp\", tracewpp)\n\n        -- save config directory\n        target:data_set(\"wdk.tracewpp.configdir\", path.join(wdk.bindir, wdk.sdkver, \"WppConfig\", \"Rev1\"))\n    end)\n\n    -- before build file\n    before_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"utils.progress\")\n\n        -- get tracewpp\n        local tracewpp = target:data(\"wdk.tracewpp\")\n        assert(tracewpp and os.isexec(tracewpp), \"tracewpp not found!\")\n\n        -- get outputdir\n        local outputdir = path.join(target:autogendir(), \"rules\", \"wdk\", \"wpp\")\n\n        -- get configdir\n        local configdir = target:data(\"wdk.tracewpp.configdir\")\n\n        -- init args\n        local args = {}\n        if target:rule(\"wdk.driver\") and (target:rule(\"wdk.env.kmdf\") or target:rule(\"wdk.env.wdm\")) then\n            table.insert(args, \"-km\")\n            table.insert(args, \"-gen:{km-WdfDefault.tpl}*.tmh\")\n        end\n        local flags = target:values(\"wdk.tracewpp.flags\", sourcefile)\n        if flags then\n            table.join2(args, flags)\n        end\n        table.insert(args, \"-cfgdir:\" .. configdir)\n        table.insert(args, \"-odir:\" .. outputdir)\n        table.insert(args, sourcefile)\n\n        -- add includedirs\n        target:add(\"includedirs\", outputdir)\n\n        -- need build this object?\n        local targetfile = path.join(outputdir, path.basename(sourcefile) .. \".tmh\")\n        local dependfile = target:dependfile(targetfile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(targetfile), values = args}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.wdk.tracewpp %s\", sourcefile)\n\n        -- ensure the output directory\n        if not os.isdir(outputdir) then\n            os.mkdir(outputdir)\n        end\n\n        -- remove the previous target file first\n        os.tryrm(targetfile)\n\n        -- generate the *.tmh file\n        os.vrunv(tracewpp, args)\n\n        -- update files and values to the dependent file\n        dependinfo.files  = {sourcefile}\n        dependinfo.values = args\n        depend.save(dependinfo, dependfile)\n    end)\n\n"
  },
  {
    "path": "xmake/rules/wdk/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: driver\nrule(\"wdk.driver\")\n\n    -- add rules\n    add_deps(\"wdk.inf\", \"wdk.man\", \"wdk.mc\", \"wdk.mof\", \"wdk.tracewpp\", \"wdk.sign\", \"wdk.package.cab\")\n\n    -- on config\n    on_config(function (target)\n\n        -- load environment\n        if target:rule(\"wdk.env.umdf\") then\n            import(\"load\").driver_umdf(target)\n        end\n        if target:rule(\"wdk.env.kmdf\") then\n            import(\"load\").driver_kmdf(target)\n        end\n        if target:rule(\"wdk.env.wdm\") then\n            import(\"load\").driver_wdm(target)\n        end\n    end)\n\n    -- after build\n    after_build(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n\n        -- copy redist files for kmdf\n        if target:rule(\"wdk.env.kmdf\") then\n\n            -- get wdk\n            local wdk = target:data(\"wdk\")\n\n            -- copy wdf redist dll libraries (WdfCoInstaller01011.dll, ..) to the target directory\n            os.cp(path.join(wdk.sdkdir, \"Redist\", \"wdf\", config.arch(), \"*.dll\"), target:targetdir())\n        end\n    end)\n\n-- define rule: binary\nrule(\"wdk.binary\")\n\n    -- add rules\n    add_deps(\"wdk.inf\", \"wdk.man\", \"wdk.mc\", \"wdk.mof\", \"wdk.tracewpp\")\n\n    -- after load\n    after_load(function (target)\n\n        -- set kind\n        target:set(\"kind\", \"binary\")\n\n        -- add links\n        target:add(\"links\", \"kernel32\", \"user32\", \"gdi32\", \"winspool\", \"comdlg32\")\n        target:add(\"links\", \"advapi32\", \"shell32\", \"ole32\", \"oleaut32\", \"uuid\", \"odbc32\", \"odbccp32\", \"setupapi\")\n    end)\n\n-- define rule: static\nrule(\"wdk.static\")\n\n    -- add rules\n    add_deps(\"wdk.inf\", \"wdk.man\", \"wdk.mc\", \"wdk.mof\", \"wdk.tracewpp\")\n\n    -- after load\n    after_load(function (target)\n\n        -- set kind\n        target:set(\"kind\", \"static\")\n\n        -- for kernel driver\n        if target:rule(\"wdk.env.kmdf\") or target:rule(\"wdk.env.wdm\") then\n            -- compile as kernel driver\n            target:add(\"cxflags\", \"-kernel\", {force = true})\n        end\n    end)\n\n-- define rule: shared\nrule(\"wdk.shared\")\n\n    -- add rules\n    add_deps(\"wdk.inf\", \"wdk.man\", \"wdk.mc\", \"wdk.mof\", \"wdk.tracewpp\")\n\n    -- after load\n    after_load(function (target)\n\n        -- set kind\n        target:set(\"kind\", \"shared\")\n\n        -- add links\n        target:add(\"links\", \"kernel32\", \"user32\", \"gdi32\", \"winspool\", \"comdlg32\")\n        target:add(\"links\", \"advapi32\", \"shell32\", \"ole32\", \"oleaut32\", \"uuid\", \"odbc32\", \"odbccp32\", \"setupapi\")\n    end)\n"
  },
  {
    "path": "xmake/rules/winsdk/dotnet/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: dotnet\nrule(\"win.sdk.dotnet\")\n\n    -- before load\n    on_load(function (target)\n\n        -- imports\n        import(\"core.project.config\")\n        import(\"detect.sdks.find_dotnet\")\n\n        -- load dotnet environment\n        if not target:data(\"win.sdk.dotnet\") then\n\n            -- find dotnet\n            local dotnet = assert(find_dotnet(nil, {verbose = true}), \"dotnet not found!\")\n\n            -- add link directory\n            target:add(\"linkdirs\", path.join(dotnet.libdir, \"um\", config.arch()))\n\n            -- save dotnet\n            target:data_set(\"win.sdk.dotnet\", dotnet)\n        end\n    end)\n\n    -- before build file\n    before_build_file(function (target, sourcefile, opt)\n\n        -- get dotnet\n        local dotnet = target:data(\"win.sdk.dotnet\")\n        if not dotnet then\n\n            -- imports\n            import(\"core.project.config\")\n            import(\"detect.sdks.find_dotnet\")\n\n            -- find dotnet\n            dotnet = assert(find_dotnet(nil, {verbose = true}), \"dotnet not found!\")\n\n            -- add link directory\n            target:add(\"linkdirs\", path.join(dotnet.libdir, \"um\", config.arch()))\n\n            -- save dotnet\n            target:data_set(\"win.sdk.dotnet\", dotnet)\n        end\n\n        -- get file config\n        local fileconfig = target:fileconfig(sourcefile) or {}\n\n        -- add cxflags to the given source file\n        --\n        -- add_files(sourcefile, {force = {cxflags = \"/clr\"}})\n        --\n        fileconfig.force = fileconfig.force or {}\n        fileconfig.force.cxflags = fileconfig.force.cxflags or {}\n        table.insert(fileconfig.force.cxflags, \"/clr\")\n\n        -- add include directory to given source file\n        fileconfig.includedirs = fileconfig.includedirs or {}\n        table.insert(fileconfig.includedirs, path.join(dotnet.includedir, \"um\"))\n\n        -- update file config\n        target:fileconfig_set(sourcefile, fileconfig)\n    end)\n"
  },
  {
    "path": "xmake/rules/winsdk/mfc/env/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xigal, ruki\n-- @file        xmake.lua\n--\n\n-- define rule: mfc.env\nrule(\"win.sdk.mfc.env\")\n\n    -- TODO: before load need check of vs's minverion, if defined\n    on_load(function (target)\n    end)\n"
  },
  {
    "path": "xmake/rules/winsdk/mfc/mfc.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xigal, ruki\n-- @file        xmake.lua\n--\n\n-- remove exists md or mt\nfunction _remove_mt_md_flags(target, flagsname)\n    local flags = table.wrap(target:get(flagsname))\n    for i = #flags, 1, -1 do\n        flag = flags[i]:lower():trim()\n        if flag:find(\"^[/%-]?mt[d]?$\") or flag:find(\"^[/%-]?md[d]?$\") then\n            table.remove(flags, i)\n        end\n    end\n    target:set(flagsname, flags)\nend\n\n-- remove exists settings\nfunction _remove_flags(target)\n    local ldflags = table.wrap(target:get(\"ldflags\"))\n    for i = #ldflags, 1, -1 do\n        ldflag = ldflags[i]:lower():trim()\n        if ldflag:find(\"[/%-]subsystem:\") then\n            table.remove(ldflags, i)\n            break\n        end\n    end\n    target:set(\"ldflags\", ldflags)\n\n    -- remove defines MT MTd MD MDd\n    local defines = table.wrap(target:get(\"defines\"))\n    for i = #defines, 1, -1 do\n        define = defines[i]:lower():trim()\n        if define:find(\"^[/%-]?mt[d]?$\") or define:find(\"^[/%-]?md[d]?$\") then\n            table.remove(defines, i)\n        end\n    end\n    target:set(\"defines\", defines)\n\n    -- remove c /MD,/MT\n    _remove_mt_md_flags(target, \"cflags\")\n\n    -- remove c,cpp /MD,/MT\n    _remove_mt_md_flags(target, \"cxflags\")\n\n    -- remove cpp /MD,/MT\n    _remove_mt_md_flags(target, \"cxxflags\")\nend\n\n-- apply mfc library settings\nfunction library(target, kind)\n\n    -- set kind: static/shared\n    target:set(\"kind\", kind)\n\n    -- set runtime library\n    if kind == \"static\" then\n        target:add(\"cxflags\", is_mode(\"debug\") and \"-MTd\" or \"-MT\")\n    else\n        target:add(\"cxflags\", is_mode(\"debug\") and \"-MDd\" or \"-MD\")\n        target:add(\"defines\", \"AFX\", \"_AFXDLL\")\n    end\nend\n\n-- apply mfc application settings\nfunction application(target, mfc_kind)\n\n    -- set kind: binary\n    target:set(\"kind\", \"binary\")\n\n    -- remove some exists flags\n    _remove_flags(target)\n\n    -- set windows subsystem\n    if not target:values(\"windows.subsystem\") then\n        target:values_set(\"windows.subsystem\", \"windows\")\n    end\n\n    -- forces a link to complete even with unresolved symbols\n    if mfc_kind == \"static\" then\n        target:add(\"ldflags\", \"-force\", {force = true})\n    end\n\n    -- set runtime library\n    if mfc_kind == \"static\" then\n        target:add(\"cxflags\", is_mode(\"debug\") and \"-MTd\" or \"-MT\")\n    else\n        target:add(\"cxflags\", is_mode(\"debug\") and \"-MDd\" or \"-MD\")\n        target:add(\"defines\", \"AFX\", \"_AFXDLL\")\n    end\n\n    -- set startup entry\n    local unicode = false\n    for _, define in ipairs(target:get(\"defines\")) do\n        define = define:lower():trim()\n        if define:find(\"^[_]?unicode$\") then\n            unicode = true\n            break\n        end\n    end\n    target:add(\"ldflags\", unicode and \"-entry:wWinMainCRTStartup\" or \"-entry:WinMainCRTStartup\", {force = true})\nend\n"
  },
  {
    "path": "xmake/rules/winsdk/mfc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      xigal, ruki\n-- @file        xmake.lua\n--\n\n-- define rule: the mfc shared library\nrule(\"win.sdk.mfc.shared\")\n\n    -- add mfc base rule\n    add_deps(\"win.sdk.mfc.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"mfc\").library(target, \"shared\")\n    end)\n\n-- define rule: the mfc static library\nrule(\"win.sdk.mfc.static\")\n\n    -- add mfc base rule\n    add_deps(\"win.sdk.mfc.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"mfc\").library(target, \"static\")\n    end)\n\n-- define rule: the application with shared mfc libraries\nrule(\"win.sdk.mfc.shared_app\")\n\n    -- add mfc base rule\n    add_deps(\"win.sdk.mfc.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"mfc\").application(target, \"shared\")\n    end)\n\n-- define rule: the application with static mfc libraries\nrule(\"win.sdk.mfc.static_app\")\n\n    -- add mfc base rule\n    add_deps(\"win.sdk.mfc.env\")\n\n    -- after load\n    after_load(function (target)\n        import(\"mfc\").application(target, \"static\")\n    end)\n"
  },
  {
    "path": "xmake/rules/winsdk/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: win.sdk.resource\nrule(\"win.sdk.resource\")\n    set_sourcekinds(\"mrc\")\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n\n-- define rule: application\nrule(\"win.sdk.application\")\n    on_load(function (target)\n        target:set(\"kind\", \"binary\")\n    end)\n\n    after_load(function (target)\n        -- set windows subsystem\n        if not target:values(\"windows.subsystem\") then\n            target:values_set(\"windows.subsystem\", \"windows\")\n        end\n\n        -- add links\n        target:add(\"syslinks\", \"kernel32\", \"user32\", \"gdi32\", \"winspool\", \"comdlg32\", \"advapi32\")\n        target:add(\"syslinks\", \"shell32\", \"ole32\", \"oleaut32\", \"uuid\", \"odbc32\", \"odbccp32\", \"comctl32\")\n        target:add(\"syslinks\", \"comdlg32\", \"setupapi\", \"shlwapi\")\n        if not target:is_plat(\"mingw\") then\n            target:add(\"syslinks\", \"strsafe\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/rules/xcode/application/build.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        build.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.theme.theme\")\nimport(\"core.project.depend\")\nimport(\"private.tools.codesign\")\nimport(\"utils.progress\")\nfunction main (target, opt)\n\n    -- get app and resources directory\n    local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n    local contentsdir = path.absolute(target:data(\"xcode.bundle.contentsdir\"))\n    local resourcesdir = path.absolute(target:data(\"xcode.bundle.resourcesdir\"))\n    local frameworksdir = path.join(contentsdir, \"Frameworks\")\n\n    -- do build if changed\n    depend.on_changed(function ()\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.target}generating.xcode.$(mode) %s\", path.filename(bundledir))\n\n        -- copy target file\n        local binarydir = contentsdir\n        if target:is_plat(\"macosx\") then\n            binarydir = path.join(contentsdir, \"MacOS\")\n        end\n        os.vcp(target:targetfile(), path.join(binarydir, path.filename(target:targetfile())))\n\n        -- change rpath\n        -- @see https://github.com/xmake-io/xmake/issues/2679#issuecomment-1221839215\n        local targetfile = path.join(binarydir, path.filename(target:targetfile()))\n        try { function () os.vrunv(\"install_name_tool\", {\"-delete_rpath\", \"@loader_path\", targetfile}) end }\n        os.vrunv(\"install_name_tool\", {\"-add_rpath\", \"@executable_path/../Frameworks\", targetfile})\n\n        -- copy dependent dynamic libraries and frameworks\n        for _, dep in ipairs(target:orderdeps()) do\n            if dep:kind() == \"shared\" then\n                if not os.isdir(frameworksdir) then\n                    os.mkdir(frameworksdir)\n                end\n                local frameworkdir = dep:data(\"xcode.bundle.rootdir\")\n                if dep:rule(\"xcode.framework\") and frameworkdir then\n                    os.cp(frameworkdir, frameworksdir, {symlink = true})\n                else\n                    os.vcp(dep:targetfile(), frameworksdir)\n                end\n            end\n        end\n\n        -- copy PkgInfo to the contents directory\n        os.mkdir(resourcesdir)\n        os.vcp(path.join(os.programdir(), \"scripts\", \"PkgInfo\"), resourcesdir)\n\n        -- copy resource files to the resources directory\n        local srcfiles, dstfiles = target:installfiles(resourcesdir)\n        if srcfiles and dstfiles then\n            local i = 1\n            for _, srcfile in ipairs(srcfiles) do\n                local dstfile = dstfiles[i]\n                if dstfile then\n                    os.vcp(srcfile, dstfile)\n                end\n                i = i + 1\n            end\n        end\n\n        -- generate embedded.mobileprovision to *.app/embedded.mobileprovision\n        local mobile_provision\n        local mobile_provision_embedded = path.join(bundledir, \"embedded.mobileprovision\")\n        if target:is_plat(\"iphoneos\") then\n            mobile_provision = target:values(\"xcode.mobile_provision\") or codesign.xcode_mobile_provision()\n            if mobile_provision then\n                os.tryrm(mobile_provision_embedded)\n                local provisions = codesign.mobile_provisions()\n                if provisions then\n                    local mobile_provision_data = provisions[mobile_provision]\n                    if mobile_provision_data then\n                        io.writefile(mobile_provision_embedded, mobile_provision_data)\n                    end\n                end\n            end\n        end\n\n        -- do codesign\n        local codesign_identity = target:values(\"xcode.codesign_identity\") or codesign.xcode_codesign_identity()\n        if target:is_plat(\"macosx\") or (target:is_plat(\"iphoneos\") and target:is_arch(\"x86_64\", \"i386\")) then\n            codesign_identity = nil\n        end\n        codesign(bundledir, codesign_identity, mobile_provision, {deep = true})\n\n    end, {dependfile = target:dependfile(bundledir), files = {bundledir, target:targetfile()}, changed = target:is_rebuilt()})\nend\n\n"
  },
  {
    "path": "xmake/rules/xcode/application/install.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        install.lua\n--\n\n-- imports\nimport(\"core.base.task\")\nimport(\"lib.detect.find_tool\")\nimport(\"utils.ipa.install\", {alias = \"install_ipa\"})\n\n-- install for ios\nfunction _install_for_ios(target)\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n\n    -- get *.ipa file\n    local ipafile = path.join(path.directory(appdir), path.basename(appdir) .. \".ipa\")\n    if not os.isfile(ipafile) or os.mtime(target:targetfile()) > os.mtime(ipafile) then\n        task.run(\"package\", {target = target:name()})\n    end\n    assert(os.isfile(ipafile), \"please run `xmake package` first!\")\n\n    -- do install\n    install_ipa(ipafile)\nend\n\n-- install for ios simulator\nfunction _install_for_ios_simulator(target)\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n\n    -- do install\n    os.vrunv(\"xcrun\", {\"simctl\", \"install\", \"booted\", appdir})\nend\n\n-- install for macosx\nfunction _install_for_macosx(target)\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n\n    -- do install\n    os.vcp(appdir, target:installdir() or \"/Applications/\")\nend\n\n-- main entry\nfunction main (target)\n    if target:is_plat(\"iphoneos\") then\n        if target:is_arch(\"x86_64\", \"i386\") then\n            _install_for_ios_simulator(target)\n        else\n            _install_for_ios(target)\n        end\n    elseif target:is_plat(\"macosx\") then\n        _install_for_macosx(target)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/xcode/application/installcmd.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        installcmd.lua\n--\n\n-- install application for xpack\nfunction main(target, batchcmds, opt)\n    local package = opt.package\n    \n    -- only for macosx when packing\n    if not target:is_plat(\"macosx\") then\n        return\n    end\n\n    -- only for xpack (package exists)\n    if not package then\n        return\n    end\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n    if not appdir or not os.isdir(appdir) then\n        return\n    end\n\n    -- get install directory\n    -- for dmg packing, we install .app to the root of install directory\n    local installdir = package:installdir()\n    if not installdir then\n        return\n    end\n\n    -- copy .app to install directory\n    local appname = path.filename(appdir)\n    local dstappdir = path.join(installdir, appname)\n    batchcmds:cp(appdir, dstappdir, {symlink = true})\n\n    -- install target files (skip binary installation)\n    local srcfiles, dstfiles = target:installfiles(installdir)\n    if srcfiles and dstfiles then\n        for idx, srcfile in ipairs(srcfiles) do\n            batchcmds:cp(srcfile, dstfiles[idx], {symlink = true})\n        end\n    end\n    -- install dependent target files\n    for _, dep in ipairs(target:orderdeps()) do\n        local srcfiles, dstfiles = dep:installfiles(installdir, {interface = true})\n        if srcfiles and dstfiles then\n            for idx, srcfile in ipairs(srcfiles) do\n                batchcmds:cp(srcfile, dstfiles[idx], {symlink = true})\n            end\n        end\n    end\nend\n\n"
  },
  {
    "path": "xmake/rules/xcode/application/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- main entry\nfunction main (target)\n\n    -- get bundle directory\n    local targetdir = target:targetdir()\n    local bundledir = path.join(targetdir, target:basename() .. \".app\")\n    target:data_set(\"xcode.bundle.rootdir\", bundledir)\n\n    -- get contents and resources directory\n    local contentsdir = bundledir\n    local resourcesdir = bundledir\n    if target:is_plat(\"macosx\") then\n        contentsdir = path.join(bundledir, \"Contents\")\n        resourcesdir = path.join(bundledir, \"Contents\", \"Resources\")\n    end\n    target:data_set(\"xcode.bundle.contentsdir\", contentsdir)\n    target:data_set(\"xcode.bundle.resourcesdir\", resourcesdir)\n\n    -- set target directory for app\n    target:set(\"kind\", \"binary\")\n    target:set(\"filename\", target:basename())\n\n    -- set install directory\n    if target:is_plat(\"macosx\") and not target:get(\"installdir\") then\n        target:set(\"installdir\", \"/Applications\")\n    end\n\n    -- add frameworks\n    if target:is_plat(\"macosx\") then\n        local xcode = target:toolchain(\"xcode\")\n        if xcode and xcode:config(\"appledev\") == \"catalyst\" then\n            target:add(\"frameworks\", \"UIKit\")\n        else\n            target:add(\"frameworks\", \"AppKit\")\n        end\n    else\n        target:add(\"frameworks\", \"UIKit\")\n    end\n\n    -- register clean files for `xmake clean`\n    target:add(\"cleanfiles\", bundledir)\nend\n"
  },
  {
    "path": "xmake/rules/xcode/application/package.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        package.lua\n--\n\n-- imports\nimport(\"utils.ipa.package\", {alias = \"ipagen\"})\n\n-- package for ios\nfunction _package_for_ios(target)\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n\n    -- get *.ipa file\n    local ipafile = path.join(path.directory(appdir), path.basename(appdir) .. \".ipa\")\n\n    -- generate *.ipa file\n    ipagen(appdir, ipafile)\n\n    -- trace\n    cprint(\"output: ${bright}%s\", ipafile)\n    cprint(\"${color.success}package ok!\")\nend\n\n-- main entry\nfunction main (target, opt)\n    if target:is_plat(\"iphoneos\") then\n        _package_for_ios(target)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/xcode/application/run.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        run.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"devel.debugger\")\nimport(\"private.action.run.runenvs\")\n\n-- run on macosx\nfunction _run_on_macosx(target, opt)\n\n    -- get the runable target file\n    local contentsdir = path.absolute(target:data(\"xcode.bundle.contentsdir\"))\n    local binarydir = path.join(contentsdir, \"MacOS\")\n    local targetfile = path.join(binarydir, path.filename(target:targetfile()))\n\n    -- get the run directory of target\n    local rundir = target:rundir()\n\n    -- enter the run directory\n    local oldir = os.cd(rundir)\n\n    -- add run environments\n    local addrunenvs, setrunenvs = runenvs.make(target)\n\n    -- debugging?\n    if option.get(\"debug\") then\n        debugger.run(targetfile, option.get(\"arguments\"), {addrunenvs = addrunenvs, setrunenvs = setrunenvs})\n    else\n        os.execv(targetfile, option.get(\"arguments\"), {envs = runenvs.join(addrunenvs, setrunenvs)})\n    end\n\n    -- restore the previous directory\n    os.cd(oldir)\nend\n\n-- run on simulator\nfunction _run_on_simulator(target, opt)\n\n    -- get devices list\n    local list = try { function () return os.iorun(\"xcrun simctl list\") end}\n    assert(list, \"simulator devices not found!\")\n\n    -- find the booted devices\n    local name, deviceid\n    for _, line in ipairs(list:split('\\n', {plain = true})) do\n        if line:find(\"(Booted)\", 1, true) then\n            line = line:trim()\n            name, deviceid = line:match(\"(.-)%s+%(([%w%-]+)%)\")\n            if name and deviceid then\n                break\n            end\n        end\n    end\n    assert(name and deviceid, \"booted simulator devices not found!\")\n\n    -- do launch on first simulator device\n    local bundle_identifier = target:values(\"xcode.bundle_identifier\") or get_config(\"xcode_bundle_identifier\") or \"io.xmake.\" .. target:name()\n    if bundle_identifier then\n        print(\"running %s application on %s (%s) ..\", target:name(), name, deviceid)\n        os.execv(\"xcrun\", {\"simctl\", \"launch\", \"--console\", deviceid, bundle_identifier})\n    end\nend\n\n-- main entry\nfunction main (target, opt)\n    if target:is_plat(\"macosx\") then\n        _run_on_macosx(target, opt)\n    elseif target:is_plat(\"iphoneos\") and target:is_arch(\"x86_64\", \"i386\") then\n        _run_on_simulator(target, opt)\n    else\n        raise(\"we can only run application on macOS or simulator!\")\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/rules/xcode/application/uninstall.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        uninstall.lua\n--\n\n-- imports\nimport(\"lib.detect.find_tool\")\n\n-- uninstall for ios\nfunction _uninstall_for_ios(target)\n    -- TODO\nend\n\n-- uninstall for macosx\nfunction _uninstall_for_macosx(target)\n\n    -- get app directory\n    local appdir = target:data(\"xcode.bundle.rootdir\")\n\n    -- do uninstall\n    os.rm(path.join(target:installdir() or \"/Applications\", path.filename(appdir)))\nend\n\n-- main entry\nfunction main (target)\n    if target:is_plat(\"iphoneos\") then\n        _uninstall_for_ios(target)\n    elseif target:is_plat(\"macosx\") then\n        _uninstall_for_macosx(target)\n    end\nend\n"
  },
  {
    "path": "xmake/rules/xcode/application/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: xcode application\nrule(\"xcode.application\")\n\n    -- support add_files(\"Info.plist\", \"*.storyboard\", \"*.xcassets\", \"*.metal\")\n    add_deps(\"xcode.info_plist\", \"xcode.storyboard\", \"xcode.xcassets\", \"xcode.metal\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(\"load\")\n\n    -- build *.app\n    after_build(\"build\")\n\n    -- package *.app to *.ipa (iphoneos) or *.dmg (macosx)\n    on_package(\"package\")\n\n    -- install application\n    on_install(\"install\")\n\n    -- install application for xpack\n    on_installcmd(\"installcmd\")\n\n    -- uninstall application\n    on_uninstall(\"uninstall\")\n\n    -- run application\n    on_run(\"run\")\n"
  },
  {
    "path": "xmake/rules/xcode/bundle/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: xcode bundle\nrule(\"xcode.bundle\")\n\n    -- support add_files(\"Info.plist\")\n    add_deps(\"xcode.info_plist\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n\n        -- get bundle directory\n        local targetdir = target:targetdir()\n        local bundledir = path.join(targetdir, target:basename() .. \".bundle\")\n        target:data_set(\"xcode.bundle.rootdir\", bundledir)\n\n        -- get contents and resources directory\n        local contentsdir = bundledir\n        local resourcesdir = bundledir\n        if target:is_plat(\"macosx\") then\n            contentsdir = path.join(bundledir, \"Contents\")\n            resourcesdir = path.join(bundledir, \"Contents\", \"Resources\")\n        end\n        target:data_set(\"xcode.bundle.contentsdir\", contentsdir)\n        target:data_set(\"xcode.bundle.resourcesdir\", resourcesdir)\n\n        -- register clean files for `xmake clean`\n        target:add(\"cleanfiles\", bundledir)\n\n        -- generate binary as bundle, we cannot set `-shared` or `-dynamiclib`\n        target:set(\"kind\", \"binary\")\n\n        -- set target info for bundle\n        target:set(\"filename\", target:basename())\n    end)\n\n    on_config(function (target)\n        -- add bundle flags\n        local linker = target:linker():name()\n        if linker == \"swiftc\" then\n            target:add(\"ldflags\", \"-Xlinker -bundle\", {force = true})\n        else\n            target:add(\"ldflags\", \"-bundle\", {force = true})\n        end\n    end)\n\n    after_link(function (target, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"private.tools.codesign\")\n        import(\"utils.progress\")\n\n        -- get bundle and resources directory\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local contentsdir = path.absolute(target:data(\"xcode.bundle.contentsdir\"))\n        local resourcesdir = path.absolute(target:data(\"xcode.bundle.resourcesdir\"))\n\n        -- do build if changed\n        depend.on_changed(function ()\n\n            -- trace progress info\n            progress.show(opt.progress, \"${color.build.target}generating.xcode.$(mode) %s\", path.filename(bundledir))\n\n            -- copy target file\n            if target:is_plat(\"macosx\") then\n                os.vcp(target:targetfile(), path.join(contentsdir, \"MacOS\", path.filename(target:targetfile())))\n            else\n                os.vcp(target:targetfile(), path.join(contentsdir, path.filename(target:targetfile())))\n            end\n\n            -- copy resource files\n            local srcfiles, dstfiles = target:installfiles(resourcesdir)\n            if srcfiles and dstfiles then\n                local i = 1\n                for _, srcfile in ipairs(srcfiles) do\n                    local dstfile = dstfiles[i]\n                    if dstfile then\n                        os.vcp(srcfile, dstfile)\n                    end\n                    i = i + 1\n                end\n            end\n\n            -- do codesign\n            local codesign_identity = target:values(\"xcode.codesign_identity\") or codesign.xcode_codesign_identity()\n            if target:is_plat(\"macosx\") or (target:is_plat(\"iphoneos\") and target:is_arch(\"x86_64\", \"i386\")) then\n                codesign_identity = nil\n            end\n            codesign(bundledir, codesign_identity)\n\n        end, {dependfile = target:dependfile(bundledir), files = {bundledir, target:targetfile()}, changed = target:is_rebuilt()})\n    end)\n\n    on_install(function (target)\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local installdir = target:installdir()\n        if installdir then\n            if not os.isdir(installdir) then\n                os.mkdir(installdir)\n            end\n            os.vcp(bundledir, installdir)\n        end\n    end)\n\n    on_uninstall(function (target)\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local installdir = target:installdir()\n        os.tryrm(path.join(installdir, path.filename(bundledir)))\n    end)\n\n    -- disable package\n    on_package(function (target) end)\n\n"
  },
  {
    "path": "xmake/rules/xcode/framework/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: xcode framework\nrule(\"xcode.framework\")\n\n    -- support add_files(\"Info.plist\")\n    add_deps(\"xcode.info_plist\")\n\n    -- we must set kind before target.on_load(), may we will use target in on_load()\n    on_load(function (target)\n\n        -- get framework directory\n        local targetdir = target:targetdir()\n        local bundledir = path.join(targetdir, target:basename() .. \".framework\")\n        target:data_set(\"xcode.bundle.rootdir\", bundledir)\n\n        -- get contents and resources directory\n        local contentsdir = target:is_plat(\"macosx\") and path.join(bundledir, \"Versions\", \"A\") or bundledir\n        local resourcesdir = path.join(contentsdir, \"Resources\")\n        target:data_set(\"xcode.bundle.contentsdir\", contentsdir)\n        target:data_set(\"xcode.bundle.resourcesdir\", resourcesdir)\n\n        -- set target info for framework\n        if not target:get(\"kind\") then\n            target:set(\"kind\", \"shared\")\n        end\n        target:set(\"filename\", target:basename())\n\n        -- export frameworks for `add_deps()`\n        target:data_set(\"inherit.links\", false) -- disable to inherit links, @see rule(\"utils.inherit.links\")\n        target:add(\"frameworks\", target:basename(), {interface = true})\n        target:add(\"frameworkdirs\", targetdir, {interface = true})\n        target:add(\"includedirs\", path.join(contentsdir, \"Headers.tmp\"), {interface = true})\n\n        -- register clean files for `xmake clean`\n        target:add(\"cleanfiles\", bundledir)\n    end)\n\n    before_build(function (target)\n\n        -- get framework directory\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local contentsdir = path.absolute(target:data(\"xcode.bundle.contentsdir\"))\n        local headersdir = path.join(contentsdir, \"Headers.tmp\", target:basename())\n\n        -- copy header files to the framework directory\n        local srcheaders, dstheaders = target:headerfiles(headersdir)\n        if srcheaders and dstheaders then\n            local i = 1\n            for _, srcheader in ipairs(srcheaders) do\n                local dstheader = dstheaders[i]\n                if dstheader then\n                    os.vcp(srcheader, dstheader)\n                end\n                i = i + 1\n            end\n        end\n        if not os.isdir(headersdir) then\n            os.mkdir(headersdir)\n        end\n    end)\n\n    after_link(function (target, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"private.tools.codesign\")\n        import(\"utils.progress\")\n\n        -- get framework directory\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local contentsdir = target:data(\"xcode.bundle.contentsdir\")\n        local resourcesdir = target:data(\"xcode.bundle.resourcesdir\")\n        local headersdir = path.join(contentsdir, \"Headers\")\n\n        -- do build if changed\n        depend.on_changed(function ()\n\n            -- trace progress info\n            progress.show(opt.progress, \"${color.build.target}generating.xcode.$(mode) %s\", path.filename(bundledir))\n\n            -- copy target file\n            if not os.isdir(contentsdir) then\n                os.mkdir(contentsdir)\n            end\n            os.vcp(target:targetfile(), contentsdir)\n\n            if target:is_shared() then\n                -- change rpath\n                -- @see https://github.com/xmake-io/xmake/issues/2679#issuecomment-1221839215\n                local filename = path.filename(target:targetfile())\n                local targetfile = path.join(contentsdir, filename)\n                local rpath = path.relative(contentsdir, path.directory(bundledir))\n                os.vrunv(\"install_name_tool\", {\"-id\", path.join(\"@rpath\", rpath, filename), targetfile})\n            end\n\n            -- move header files\n            os.tryrm(headersdir)\n            os.mv(path.join(contentsdir, \"Headers.tmp\", target:basename()), headersdir)\n            os.rm(path.join(contentsdir, \"Headers.tmp\"))\n\n            -- copy resource files\n            local srcfiles, dstfiles = target:installfiles(resourcesdir)\n            if srcfiles and dstfiles then\n                local i = 1\n                for _, srcfile in ipairs(srcfiles) do\n                    local dstfile = dstfiles[i]\n                    if dstfile then\n                        os.vcp(srcfile, dstfile)\n                    end\n                    i = i + 1\n                end\n            end\n\n            -- link Versions/Current -> Versions/A\n            -- only for macos, @see https://github.com/xmake-io/xmake/issues/2765\n            if target:is_plat(\"macosx\") then\n                local oldir = os.cd(path.join(bundledir, \"Versions\"))\n                os.tryrm(\"Current\")\n                os.ln(\"A\", \"Current\")\n\n                -- link bundledir/* -> Versions/Current/*\n                local target_filename = path.filename(target:targetfile())\n                os.cd(bundledir)\n                os.tryrm(\"Headers\")\n                os.tryrm(\"Resources\")\n                os.tryrm(target_filename)\n                os.tryrm(\"Info.plist\")\n                os.ln(\"Versions/Current/Headers\", \"Headers\")\n                if os.isdir(resourcesdir) then\n                    os.ln(\"Versions/Current/Resources\", \"Resources\")\n                end\n                os.ln(path.join(\"Versions/Current\", target_filename), target_filename)\n                os.cd(oldir)\n            end\n\n            -- do codesign, only for dynamic library\n            if target:is_shared() then\n                local codesign_identity = target:values(\"xcode.codesign_identity\") or codesign.xcode_codesign_identity()\n                if target:is_plat(\"macosx\") or (target:is_plat(\"iphoneos\") and target:is_arch(\"x86_64\", \"i386\")) then\n                    codesign_identity = nil\n                end\n                codesign(contentsdir, codesign_identity)\n            end\n        end, {dependfile = target:dependfile(bundledir), files = {bundledir, target:targetfile()}, changed = target:is_rebuilt()})\n    end)\n\n    on_install(function (target)\n        import(\"xcode.application.build\", {alias = \"appbuild\", rootdir = path.join(os.programdir(), \"rules\")})\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local installdir = target:installdir()\n        if installdir then\n            if not os.isdir(installdir) then\n                os.mkdir(installdir)\n            end\n            os.vcp(bundledir, installdir, {symlink = true})\n        end\n    end)\n\n    on_uninstall(function (target)\n        local bundledir = path.absolute(target:data(\"xcode.bundle.rootdir\"))\n        local installdir = target:installdir()\n        os.tryrm(path.join(installdir, path.filename(bundledir)))\n    end)\n\n    -- disable package\n    on_package(function (target) end)\n\n"
  },
  {
    "path": "xmake/rules/xcode/info_plist/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"xcode.info_plist\")\n    set_extensions(\".plist\")\n    on_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"core.tool.toolchain\")\n        import(\"utils.progress\")\n\n        -- check, e.g. Info.plist, xxx-Info.plist\n        assert(path.filename(sourcefile):endswith(\"Info.plist\"), \"we only support Info.plist file!\")\n\n        -- get contents and resources directory\n        local contentsdir = assert(target:data(\"xcode.bundle.contentsdir\"), \"contents directory not found!\")\n        local resourcesdir = assert(target:data(\"xcode.bundle.resourcesdir\"), \"resources directory not found!\")\n\n        -- need re-compile it?\n        local dependfile = target:dependfile(sourcefile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(dependfile)}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}processing.xcode.$(mode) %s\", sourcefile)\n\n        -- process and generate Info.plist\n        -- https://github.com/xmake-io/xmake/issues/2765#issuecomment-1251738622\n        local info_plist_file\n        if target:rule(\"xcode.framework\") and target:is_plat(\"macosx\") then\n            info_plist_file = path.join(resourcesdir, path.filename(sourcefile))\n        else\n            info_plist_file = path.join(contentsdir, path.filename(sourcefile))\n        end\n        local maps =\n        {\n            DEVELOPMENT_LANGUAGE = \"en\",\n            EXECUTABLE_NAME = target:basename(),\n            PRODUCT_BUNDLE_IDENTIFIER = target:values(\"xcode.bundle_identifier\") or get_config(\"xcode_bundle_identifier\") or \"io.xmake.\" .. target:name(),\n            PRODUCT_NAME = target:name(),\n            PRODUCT_DISPLAY_NAME = target:name(),\n            CURRENT_PROJECT_VERSION = target:version() and tostring(target:version()) or \"1.0\",\n        }\n        if target:is_plat(\"macosx\") then\n            local toolchain_xcode = toolchain.load(\"xcode\", {plat = target:plat(), arch = target:arch()})\n            if toolchain_xcode then\n                maps.MACOSX_DEPLOYMENT_TARGET = toolchain_xcode:config(\"target_minver\")\n            end\n        end\n        if target:rule(\"xcode.bundle\") then\n            maps.PRODUCT_BUNDLE_PACKAGE_TYPE = \"BNDL\"\n        elseif target:rule(\"xcode.framework\") then\n            maps.PRODUCT_BUNDLE_PACKAGE_TYPE = \"FMWK\"\n        elseif target:rule(\"xcode.application\") then\n            maps.PRODUCT_BUNDLE_PACKAGE_TYPE = \"APPL\"\n        end\n\n        os.vcp(sourcefile, info_plist_file)\n        io.gsub(info_plist_file, \"(%$%((.-)%))\", function (_, variable)\n            return maps[variable]\n        end)\n\n        -- patch some entries for mac catalyst\n        local xcode = target:toolchain(\"xcode\")\n        if xcode and xcode:config(\"appledev\") == \"catalyst\" then\n            -- remove entry for \"LSRequiresIPhoneOS\" - not supported on macOS\n            --\n            -- <key>LSRequiresIPhoneOS</key>\n            -- <true/>\n            io.replace(info_plist_file, \"<key>LSRequiresIPhoneOS</key>.-<true/>\", \"\")\n        end\n\n        -- update files and values to the dependent file\n        dependinfo.files = {sourcefile}\n        depend.save(dependinfo, dependfile)\n    end)\n"
  },
  {
    "path": "xmake/rules/xcode/metal/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- build metal files\n--\n-- @see https://developer.apple.com/documentation/metal/libraries/building_a_library_with_metal_s_command-line_tools\n--\nrule(\"xcode.metal\")\n    set_extensions(\".metal\")\n\n    -- build *.metal to *.air\n    on_buildcmd_file(function (target, batchcmds, sourcefile, opt)\n\n        -- get metal\n        import(\"lib.detect.find_tool\")\n        local xcode = assert(target:toolchain(\"xcode\"), \"xcode not fount!\")\n        local metal = assert(find_tool(\"metal\", {program = path.join(xcode:bindir(), \"metal\")}), \"metal command not found!\")\n\n        -- get xcode toolchain\n        local target_minver = xcode:config(\"target_minver\")\n        local xcode_sysroot = xcode:config(\"xcode_sysroot\")\n\n        -- init metal arguments\n        local objectfile = target:objectfile(sourcefile) .. \".air\"\n        local argv = {\"-c\", \"-ffast-math\", \"-gline-tables-only\"}\n        if target_minver then\n            table.insert(argv, \"-target\")\n            local airarch = target:is_arch(\"x86_64\", \"arm64\") and \"air64\" or \"air32\"\n            if target:is_plat(\"macosx\") then\n                table.insert(argv, airarch .. \"-apple-macos\" .. target_minver)\n            elseif target:is_plat(\"iphoneos\") then\n                local airtarget = airarch .. \"-apple-ios\" .. target_minver\n                if target:is_arch(\"x86_64\", \"i386\") then\n                    airtarget = airtarget .. \"-simulator\"\n                end\n                table.insert(argv, airtarget)\n            elseif target:is_plat(\"watchos\") then\n                local airtarget = airarch .. \"-apple-watchos\" .. target_minver\n                if target:is_arch(\"x86_64\", \"i386\") then\n                    airtarget = airtarget .. \"-simulator\"\n                end\n                table.insert(argv, airtarget)\n            elseif target:is_plat(\"appletvos\") then\n                local airtarget = airarch .. \"-apple-tvos\" .. target_minver\n                if target:is_arch(\"x86_64\", \"i386\") then\n                    airtarget = airtarget .. \"-simulator\"\n                end\n                table.insert(argv, airtarget)\n            end\n        end\n        if xcode_sysroot then\n            table.insert(argv, \"-isysroot\")\n            table.insert(argv, path(xcode_sysroot))\n        end\n        table.insert(argv, \"-o\")\n        table.insert(argv, path(objectfile))\n        table.insert(argv, path(sourcefile))\n\n        -- add commands\n        batchcmds:show_progress(opt.progress, \"${color.build.object}compiling.metal %s\", sourcefile)\n        batchcmds:mkdir(path.directory(objectfile))\n        batchcmds:vrunv(metal.program, argv)\n\n        -- add deps\n        batchcmds:add_depfiles(sourcefile)\n        batchcmds:set_depmtime(os.mtime(objectfile))\n        batchcmds:set_depcache(target:dependfile(objectfile))\n    end)\n\n    -- link *.air to *.metallib\n    before_linkcmd(function (target, batchcmds, opt)\n\n        -- get objectfiles\n        local objectfiles = {}\n        local objectfiles_wrap = {}\n        for rulename, sourcebatch in pairs(target:sourcebatches()) do\n            if rulename == \"xcode.metal\" then\n                for _, sourcefile in ipairs(sourcebatch.sourcefiles) do\n                    table.insert(objectfiles, target:objectfile(sourcefile) .. \".air\")\n                    table.insert(objectfiles_wrap, path(target:objectfile(sourcefile) .. \".air\"))\n                end\n                break\n            end\n        end\n        if #objectfiles == 0 then\n            return\n        end\n\n        -- get metallib\n        import(\"lib.detect.find_tool\")\n        local xcode = assert(target:toolchain(\"xcode\"), \"xcode not fount!\")\n        local metallib = assert(find_tool(\"metallib\", {program = path.join(xcode:bindir(), \"metallib\")}), \"metallib command not found!\")\n\n        -- get xcode toolchain\n        local xcode_sysroot = xcode:config(\"xcode_sysroot\")\n\n        -- add commands\n        local resourcesdir = path.absolute(target:data(\"xcode.bundle.resourcesdir\"))\n        local libraryfile = resourcesdir and path.join(resourcesdir, \"default.metallib\") or (target:targetfile() .. \".metallib\")\n        batchcmds:show_progress(opt.progress, \"${color.build.target}linking.metal %s\", path.filename(libraryfile))\n        batchcmds:mkdir(path.directory(libraryfile))\n        batchcmds:vrunv(metallib.program, table.join({\"-o\", path(libraryfile)}, objectfiles_wrap), {envs = {SDKROOT = xcode_sysroot}})\n\n        -- add deps\n        batchcmds:add_depfiles(objectfiles)\n        batchcmds:set_depmtime(os.mtime(libraryfile))\n        batchcmds:set_depcache(target:dependfile(libraryfile))\n    end)\n"
  },
  {
    "path": "xmake/rules/xcode/storyboard/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"xcode.storyboard\")\n\n    -- support add_files(\"*.storyboard\")\n    set_extensions(\".storyboard\")\n\n    -- build *.storyboard\n    on_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"core.tool.toolchain\")\n        import(\"utils.progress\")\n\n        -- get xcode sdk directory\n        local xcode_sdkdir = assert(get_config(\"xcode\"), \"xcode not found!\")\n        local xcode_usrdir = path.join(xcode_sdkdir, \"Contents\", \"Developer\", \"usr\")\n\n        -- get base.lproj\n        local base_lproj = path.join(target:autogendir(), \"rules\", \"xcode\", \"storyboard\", \"Base.lproj\")\n\n        -- get resources directory\n        local resourcesdir = assert(target:data(\"xcode.bundle.resourcesdir\"), \"resources directory not found!\")\n\n        -- need re-compile it?\n        local dependfile = target:dependfile(sourcefile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(dependfile)}) then\n            return\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.xcode.$(mode) %s\", sourcefile)\n\n        -- clear Base.lproj first\n        os.tryrm(base_lproj)\n        os.mkdir(base_lproj)\n\n        -- do compile\n        local target_minver = nil\n        local toolchain_xcode = toolchain.load(\"xcode\", {plat = target:plat(), arch = target:arch()})\n        if toolchain_xcode then\n            target_minver = toolchain_xcode:config(\"target_minver\")\n        end\n        local argv = {\"--errors\", \"--warnings\", \"--notices\", \"--auto-activate-custom-fonts\", \"--output-format\", \"human-readable-text\"}\n        if target:is_plat(\"macosx\") then\n            local xcode = target:toolchain(\"xcode\")\n            if xcode and xcode:config(\"appledev\") == \"catalyst\" then\n                table.insert(argv, \"--platform\")\n                table.insert(argv, \"macosx\")\n                table.insert(argv, \"--target-device\")\n                table.insert(argv, \"ipad\")\n            else\n                table.insert(argv, \"--target-device\")\n                table.insert(argv, \"mac\")\n            end\n        elseif target:is_plat(\"iphoneos\") then\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"iphone\")\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"ipad\")\n        else\n            assert(\"unknown device!\")\n        end\n        if target_minver then\n            table.insert(argv, \"--minimum-deployment-target\")\n            table.insert(argv, target_minver)\n        end\n        table.insert(argv, \"--compilation-directory\")\n        table.insert(argv, base_lproj)\n        table.insert(argv, sourcefile)\n        os.vrunv(path.join(xcode_usrdir, \"bin\", \"ibtool\"), argv, {envs = {XCODE_DEVELOPER_USR_PATH = xcode_usrdir}})\n\n        -- do link\n        argv = {\"--errors\", \"--warnings\", \"--notices\", \"--auto-activate-custom-fonts\", \"--output-format\", \"human-readable-text\"}\n        if target:is_plat(\"macosx\") then\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"mac\")\n        end\n        if target_minver then\n            table.insert(argv, \"--minimum-deployment-target\")\n            table.insert(argv, target_minver)\n        end\n        table.insert(argv, \"--link\")\n        table.insert(argv, resourcesdir)\n        table.insert(argv, path.join(base_lproj, path.filename(sourcefile) .. \"c\"))\n        os.vrunv(path.join(xcode_usrdir, \"bin\", \"ibtool\"), argv, {envs = {XCODE_DEVELOPER_USR_PATH = xcode_usrdir}})\n\n        -- update files and values to the dependent file\n        dependinfo.files = {sourcefile}\n        depend.save(dependinfo, dependfile)\n    end)\n"
  },
  {
    "path": "xmake/rules/xcode/xcassets/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule\nrule(\"xcode.xcassets\")\n\n    -- support add_files(\"*.xcassets\")\n    set_extensions(\".xcassets\")\n\n    -- build *.xcassets\n    on_build_file(function (target, sourcefile, opt)\n\n        -- imports\n        import(\"core.base.option\")\n        import(\"core.theme.theme\")\n        import(\"core.project.depend\")\n        import(\"core.tool.toolchain\")\n        import(\"utils.progress\")\n\n        -- get xcode sdk directory\n        local xcode_sdkdir = assert(get_config(\"xcode\"), \"xcode not found!\")\n        local xcode_usrdir = path.join(xcode_sdkdir, \"Contents\", \"Developer\", \"usr\")\n\n        -- get resources directory\n        local resourcesdir = assert(target:data(\"xcode.bundle.resourcesdir\"), \"resources directory not found!\")\n\n        -- need re-compile it?\n        local dependfile = target:dependfile(sourcefile)\n        local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile) or {})\n        if not depend.is_changed(dependinfo, {lastmtime = os.mtime(dependfile)}) then\n            return\n        end\n\n        -- ensure resources directory exists\n        if not os.isdir(resourcesdir) then\n            os.mkdir(resourcesdir)\n        end\n\n        -- trace progress info\n        progress.show(opt.progress, \"${color.build.object}compiling.xcode.$(mode) %s\", sourcefile)\n\n        -- get assetcatalog_generated_info.plist\n        local assetcatalog_generated_info_plist = path.join(target:autogendir(), \"rules\", \"xcode\", \"xcassets\", \"assetcatalog_generated_info.plist\")\n        io.writefile(assetcatalog_generated_info_plist, \"\")\n\n        -- do compile\n        local target_minver = nil\n        local toolchain_xcode = toolchain.load(\"xcode\", {plat = target:plat(), arch = target:arch()})\n        if toolchain_xcode then\n            target_minver = toolchain_xcode:config(\"target_minver\")\n        end\n        local argv = {\"--warnings\", \"--notices\", \"--output-format\", \"human-readable-text\"}\n        if target:is_plat(\"macosx\") then\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"mac\")\n            table.insert(argv, \"--platform\")\n            table.insert(argv, \"macosx\")\n        elseif target:is_plat(\"iphoneos\") then\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"iphone\")\n            table.insert(argv, \"--target-device\")\n            table.insert(argv, \"ipad\")\n            table.insert(argv, \"--platform\")\n            table.insert(argv, \"iphoneos\")\n        else\n            assert(\"unknown device!\")\n        end\n        if target_minver then\n            table.insert(argv, \"--minimum-deployment-target\")\n            table.insert(argv, target_minver)\n        end\n        table.insert(argv, \"--app-icon\")\n        table.insert(argv, \"AppIcon\")\n        if target:is_plat(\"iphoneos\") then\n            table.insert(argv, \"--enable-on-demand-resources\")\n            table.insert(argv, \"YES\")\n            table.insert(argv, \"--compress-pngs\")\n        else\n            table.insert(argv, \"--enable-on-demand-resources\")\n            table.insert(argv, \"NO\")\n        end\n        table.insert(argv, \"--output-partial-info-plist\")\n        table.insert(argv, assetcatalog_generated_info_plist)\n        table.insert(argv, \"--development-region\")\n        table.insert(argv, \"en\")\n        table.insert(argv, \"--product-type\")\n        table.insert(argv, \"com.apple.product-type.application\")\n        table.insert(argv, \"--compile\")\n        table.insert(argv, resourcesdir)\n        table.insert(argv, sourcefile)\n        os.vrunv(path.join(xcode_usrdir, \"bin\", \"actool\"), argv)\n\n        -- update files and values to the dependent file\n        dependinfo.files = {sourcefile}\n        depend.save(dependinfo, dependfile)\n    end)\n"
  },
  {
    "path": "xmake/rules/xmake_cli/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\nrule(\"xmake.cli\")\n    set_extensions(\".lua\")\n\n    on_load(function (target)\n        target:set(\"kind\", \"binary\")\n        assert(target:pkg(\"libxmake\"), 'please add_packages(\"libxmake\") to target(%s) first!', target:name())\n\n        local headerdir = path.join(target:autogendir(), \"rules\", \"xmake.cli\", \"include\")\n        if not os.isdir(headerdir) then\n            os.mkdir(headerdir)\n        end\n        target:add(\"includedirs\", headerdir)\n    end)\n\n    before_buildcmd_files(function (target, batchcmds, sourcebatch, opt)\n        import(\"private.core.base.match_copyfiles\")\n        local sourcefiles = sourcebatch.sourcefiles\n        local archivefile = path.join(target:autogendir(), \"rules\", \"xmake.cli\", \"luafiles.xmz\")\n        local dependfile = archivefile .. \".d\"\n        batchcmds:show_progress(opt.progress, \"${color.build.target}archiving.luafiles %s\", target:name())\n\n        local luadir = path.join(target:autogendir(), \"rules\", \"xmake.cli\", \"luafiles\")\n        local argv = {\"lua\", \"cli.archive\", \"-r\", \"-w\", path(luadir), \"-o\", path(archivefile)}\n        local srcfiles, dstfiles = match_copyfiles(target, \"files\", path.join(luadir, \"modules\"))\n        for idx, srcfile in ipairs(srcfiles) do\n            if srcfile:endswith(\".lua\") then\n                local dstfile = dstfiles[idx]\n                batchcmds:cp(srcfile, dstfile)\n                table.insert(argv, path(dstfile))\n            end\n        end\n        batchcmds:vrunv(os.programfile(), argv, {envs = {XMAKE_SKIP_HISTORY = \"y\"}})\n\n        local headerdir = path.join(target:autogendir(), \"rules\", \"xmake.cli\", \"include\")\n        local headerfile = path.join(headerdir, \"luafiles.xmz.h\")\n        target:add(\"includedirs\", headerdir)\n        argv = {\"--nozeroend\", \"-i\", path(archivefile), \"-o\", path(headerfile)}\n        batchcmds:vlua(\"utils.binary.bin2c\", argv)\n\n        batchcmds:add_depfiles(sourcefiles)\n        batchcmds:set_depmtime(os.mtime(dependfile))\n        batchcmds:set_depcache(dependfile)\n    end)\n"
  },
  {
    "path": "xmake/rules/zig/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define rule: zig.build\nrule(\"zig.build\")\n    set_sourcekinds(\"zc\")\n    on_load(function (target)\n        local cachedir = target:values(\"zig.cachedir\") or path.join(target:objectdir(), \"zig-cache\")\n        os.mkdir(cachedir)\n        target:add(\"zcflags\", \"--cache-dir \" .. cachedir)\n    end)\n    on_build_files(\"private.action.build.object\", {jobgraph = true, batch = true})\n\n-- define rule: zig\nrule(\"zig\")\n\n    -- add build rules\n    add_deps(\"zig.build\")\n\n    -- inherit links and linkdirs of all dependent targets by default\n    add_deps(\"utils.inherit.links\")\n\n    -- support `add_files(\"src/*.o\")` and `add_files(\"src/*.a\")` to merge object and archive files to target\n    add_deps(\"utils.merge.object\", \"utils.merge.archive\")\n\n    -- we attempt to extract symbols to the independent file and\n    -- strip self-target binary if `set_symbols(\"debug\")` and `set_strip(\"all\")` are enabled\n    add_deps(\"utils.symbols.extract\")\n"
  },
  {
    "path": "xmake/scripts/PkgInfo",
    "content": "APPL????"
  },
  {
    "path": "xmake/scripts/cmake_importfiles/xxxConfig.cmake",
    "content": "\n####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######\n####### Any changes to this file will be overwritten by the next CMake run ####\n####### The input file was Config.cmake.in                            ########\n\nget_filename_component(PACKAGE_PREFIX_DIR \"${CMAKE_CURRENT_LIST_DIR}/../../../\" ABSOLUTE)\n\nmacro(set_and_check _var _file)\n  set(${_var} \"${_file}\")\n  if(NOT EXISTS \"${_file}\")\n    message(FATAL_ERROR \"File or directory ${_file} referenced by variable ${_var} does not exist !\")\n  endif()\nendmacro()\n\nmacro(check_required_components _NAME)\n  foreach(comp ${${_NAME}_FIND_COMPONENTS})\n    if(NOT ${_NAME}_${comp}_FOUND)\n      if(${_NAME}_FIND_REQUIRED_${comp})\n        set(${_NAME}_FOUND FALSE)\n      endif()\n    endif()\n  endforeach()\nendmacro()\n\n####################################################################################\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/@TARGETNAME@Targets.cmake\")\ncheck_required_components(\"@TARGETNAME@\")\n"
  },
  {
    "path": "xmake/scripts/cmake_importfiles/xxxConfigVersion.cmake",
    "content": "# This is a basic version file for the Config-mode of find_package().\n# It is used by write_basic_package_version_file() as input file for configure_file()\n# to create a version-file which can be installed along a config.cmake file.\n#\n# The created file sets PACKAGE_VERSION_EXACT if the current version string and\n# the requested version string are exactly the same and it sets\n# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.\n# The variable CVF_VERSION must be set before calling configure_file().\n\nset(PACKAGE_VERSION \"@PACKAGE_VERSION@\")\n\nif (PACKAGE_FIND_VERSION_RANGE)\n  # Package version must be in the requested version range\n  if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL \"INCLUDE\" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)\n      OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL \"INCLUDE\" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)\n        OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL \"EXCLUDE\" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))\n    set(PACKAGE_VERSION_COMPATIBLE FALSE)\n  else()\n    set(PACKAGE_VERSION_COMPATIBLE TRUE)\n  endif()\nelse()\n  if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)\n    set(PACKAGE_VERSION_COMPATIBLE FALSE)\n  else()\n    set(PACKAGE_VERSION_COMPATIBLE TRUE)\n    if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)\n      set(PACKAGE_VERSION_EXACT TRUE)\n    endif()\n  endif()\nendif()\n\n\n# if the installed project requested no architecture check, don't perform the check\nif(\"FALSE\")\n  return()\nendif()\n\n# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:\nif(\"${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"\" OR \"8\" STREQUAL \"\")\n  return()\nendif()\n\n# check that the installed version has the same 32/64bit-ness as the one which is currently searching:\nif(NOT CMAKE_SIZEOF_VOID_P STREQUAL \"@TARGET_PTRBYTES@\")\n  math(EXPR installedBits \"@TARGET_PTRBYTES@ * 8\")\n  set(PACKAGE_VERSION \"${PACKAGE_VERSION} (${installedBits}bit)\")\n  set(PACKAGE_VERSION_UNSUITABLE TRUE)\nendif()\n"
  },
  {
    "path": "xmake/scripts/cmake_importfiles/xxxTargets-debug.cmake",
    "content": "#----------------------------------------------------------------\n# Generated CMake target import file for configuration \"Debug\".\n#----------------------------------------------------------------\n\n# Commands may need to know the format version.\nset(CMAKE_IMPORT_FILE_VERSION 1)\n\n# Import target \"@PROJECTNAME@::@TARGETNAME@\" for configuration \"Debug\"\nset_property(TARGET @PROJECTNAME@::@TARGETNAME@ APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)\nset_target_properties(@PROJECTNAME@::@TARGETNAME@ PROPERTIES\n  IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG \"ASM_NASM;C\"\n  # IMPORTED_IMPLIB_DEBUG \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\"\n  IMPORTED_LOCATION_DEBUG \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\"\n  )\n\nlist(APPEND _IMPORT_CHECK_TARGETS @PROJECTNAME@::@TARGETNAME@ )\nlist(APPEND _IMPORT_CHECK_FILES_FOR_@PROJECTNAME@::@TARGETNAME@ \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\" )\n\n# Commands beyond this point should not need to know the version.\nset(CMAKE_IMPORT_FILE_VERSION)\n"
  },
  {
    "path": "xmake/scripts/cmake_importfiles/xxxTargets-release.cmake",
    "content": "#----------------------------------------------------------------\n# Generated CMake target import file for configuration \"Release\".\n#----------------------------------------------------------------\n\n# Commands may need to know the format version.\nset(CMAKE_IMPORT_FILE_VERSION 1)\n\n# Import target \"@PROJECTNAME@::@TARGETNAME@\" for configuration \"Release\"\nset_property(TARGET @PROJECTNAME@::@TARGETNAME@ APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)\nset_target_properties(@PROJECTNAME@::@TARGETNAME@ PROPERTIES\n  IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE \"ASM_NASM;C\"\n  # IMPORTED_IMPLIB_RELEASE \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\"\n  IMPORTED_LOCATION_RELEASE \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\"\n  )\n\nlist(APPEND _IMPORT_CHECK_TARGETS @PROJECTNAME@::@TARGETNAME@ )\nlist(APPEND _IMPORT_CHECK_FILES_FOR_@PROJECTNAME@::@TARGETNAME@ \"${_IMPORT_PREFIX}/@LIBDIR@/@TARGETFILENAME@\" )\n\n# Commands beyond this point should not need to know the version.\nset(CMAKE_IMPORT_FILE_VERSION)\n"
  },
  {
    "path": "xmake/scripts/cmake_importfiles/xxxTargets.cmake",
    "content": "# Generated by XMake\n\nif(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n   message(FATAL_ERROR \"CMake >= 2.6.0 required\")\nendif()\ncmake_policy(PUSH)\ncmake_policy(VERSION 2.6...3.17)\n#----------------------------------------------------------------\n# Generated CMake target import file.\n#----------------------------------------------------------------\n\n# Commands may need to know the format version.\nset(CMAKE_IMPORT_FILE_VERSION 1)\n\n# Protect against multiple inclusion, which would fail when already imported targets are added once more.\nset(_targetsDefined)\nset(_targetsNotDefined)\nset(_expectedTargets)\nforeach(_expectedTarget @PROJECTNAME@::@TARGETNAME@)\n  list(APPEND _expectedTargets ${_expectedTarget})\n  if(NOT TARGET ${_expectedTarget})\n    list(APPEND _targetsNotDefined ${_expectedTarget})\n  endif()\n  if(TARGET ${_expectedTarget})\n    list(APPEND _targetsDefined ${_expectedTarget})\n  endif()\nendforeach()\nif(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n  unset(_targetsDefined)\n  unset(_targetsNotDefined)\n  unset(_expectedTargets)\n  set(CMAKE_IMPORT_FILE_VERSION)\n  cmake_policy(POP)\n  return()\nendif()\nif(NOT \"${_targetsDefined}\" STREQUAL \"\")\n  message(FATAL_ERROR \"Some (but not all) targets in this export set were already defined.\\nTargets Defined: ${_targetsDefined}\\nTargets not yet defined: ${_targetsNotDefined}\\n\")\nendif()\nunset(_targetsDefined)\nunset(_targetsNotDefined)\nunset(_expectedTargets)\n\n# The installation prefix configured by this project.\nget_filename_component(_IMPORT_PREFIX \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nif (_IMPORT_PREFIX STREQUAL \"/\")\n  set(_IMPORT_PREFIX \"\")\nendif()\n\n# Create imported target @PROJECTNAME@::@TARGETNAME@\nadd_library(@PROJECTNAME@::@TARGETNAME@ @TARGETKIND@ IMPORTED)\n\nset_target_properties(@PROJECTNAME@::@TARGETNAME@ PROPERTIES\n  INTERFACE_INCLUDE_DIRECTORIES \"${_IMPORT_PREFIX}/include\"\n)\n\n# Load information for each installed configuration.\nget_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\nfile(GLOB CONFIG_FILES \"${_DIR}/@TARGETNAME@Targets-*.cmake\")\nforeach(f ${CONFIG_FILES})\n  include(${f})\nendforeach()\n\n# Cleanup temporary variables.\nset(_IMPORT_PREFIX)\n\n# Loop over all imported files and verify that they actually exist\nforeach(target ${_IMPORT_CHECK_TARGETS} )\n  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n    if(NOT EXISTS \"${file}\" )\n      message(FATAL_ERROR \"The imported target \\\"${target}\\\" references the file\n   \\\"${file}\\\"\nbut this file does not exist.  Possible reasons include:\n* The file was deleted, renamed, or moved to another location.\n* An install or uninstall procedure did not complete successfully.\n* The installation package was faulty and contained\n   \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\nbut not all the files it references.\n\")\n    endif()\n  endforeach()\n  unset(_IMPORT_CHECK_FILES_FOR_${target})\nendforeach()\nunset(_IMPORT_CHECK_TARGETS)\n\n# This file does not depend on other imported targets which have\n# been exported from the same project but in a separate export set.\n\n# Commands beyond this point should not need to know the version.\nset(CMAKE_IMPORT_FILE_VERSION)\ncmake_policy(POP)\n"
  },
  {
    "path": "xmake/scripts/completions/register-completions.bash",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki\n# @homepage    register-completions.bash\n#\n\n# bash parameter completion for xmake\n_xmake_bash_complete()\n{\n  local word=${COMP_WORDS[COMP_CWORD]}\n  local completions\n  completions=\"$(XMAKE_SKIP_HISTORY=1 XMAKE_ROOT=y xmake lua private.utils.complete \"${COMP_POINT}\" \"nospace-nokey\" \"${COMP_LINE}\")\"\n  if [ $? -ne 0 ]; then\n    completions=\"\"\n  fi\n  COMPREPLY=( $(compgen -W \"$completions\") )\n}\ncomplete -o default -o nospace -F _xmake_bash_complete xmake\n\n# bash parameter completion for xrepo\n_xrepo_bash_complete()\n{\n  local word=${COMP_WORDS[COMP_CWORD]}\n  local completions\n  completions=\"$(XMAKE_SKIP_HISTORY=1 XMAKE_ROOT=y xmake lua private.xrepo.complete \"${COMP_POINT}\" \"nospace-nokey\" \"${COMP_LINE}\")\"\n  if [ $? -ne 0 ]; then\n    completions=\"\"\n  fi\n  COMPREPLY=( $(compgen -W \"$completions\") )\n}\ncomplete -o default -o nospace -F _xrepo_bash_complete xrepo\n"
  },
  {
    "path": "xmake/scripts/completions/register-completions.fish",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki, Dragon1573\n# @homepage    register-completions.fish\n#\n\n# fish parameter completion for xmake\nfunction _xmake_fish_complete\n    # Read the current command line\n    set -l raw_cmd (commandline)\n    set -l words (commandline -o)\n    # Get the current token\n    set -l token (commandline -ot)\n\n    # Call XMake built-in completion to get available results\n    set -l result (MAKE_SKIP_HISTORY=1 XMAKE_ROOT=y xmake lua private.utils.complete 0 nospace \"$raw_cmd\")\n    if test (count $result) -lt 1\n        # When there are no available completions, the function ends immediately\n        # Otherwise, the subsequent `contains` command will trigger an error\n        return 1\n    end\n\n    # Are there multiple selectable results?\n    # When there are multiple options, the user's current token is definitely incomplete\n    test (count $result) -gt 1\n    set -l is_multiple_choice $status\n    # Is the only selectable option identical to the current token under the cursor (which may be empty)?\n    # Identical means the user has already completed the process\n    # Repeated option outputs are not completions at the current cursor position\n    contains -- $token $result\n    set -l is_token_incomplete $status\n    # Is the only selectable option identical to the last visible token of the command line array?\n    # When completing without a prefix in every token position, the current token is an empty string\n    # The last item of the command line tokenized array is the token before the cursor\n    # This is mainly used to handle completions triggered after a space without a prefix\n    contains -- $words[-1] $result\n    set -l not_token_completed $status\n\n    test \\( $is_token_incomplete -eq 1 \\) -a \\( $not_token_completed -eq 1 \\)\n    test \\( $is_multiple_choice -eq 0 \\) -o \\( $status -eq 0 \\)\n    if test $status -eq 0\n        # When the completion list has more than one item, or the current token is different from the unique token in the completion list\n        # The user must not have completed the token and needs to be provided with completion options\n        for item in $result\n            # Each result takes up a separate line, and for the \"-a\" parameter, it needs to be echoed separately\n            # Although the result itself has a newline, \"-a\" still treats it as a whole,\n            # Without tokenizing it as multiple parameters\n            if not string match -- '*error*' \"$item\" > /dev/null\n                echo $item\n            end\n        end\n    end\nend\n\ncomplete -c xmake -f -a \"(_xmake_fish_complete)\"\n"
  },
  {
    "path": "xmake/scripts/completions/register-completions.zsh",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki\n# @homepage    register-completions.zsh\n#\n\n# zsh parameter completion for xmake\n_xmake_zsh_complete()\n{\n  local words\n  read -Ac words\n  local completions=(\"$(XMAKE_SKIP_HISTORY=1 XMAKE_ROOT=y xmake lua private.utils.complete 0 nospace \"$words\")\")\n  reply=( \"${(ps:\\n:)completions}\" )\n}\ncompctl -f -S \"\" -K _xmake_zsh_complete xmake\n\n# zsh parameter completion for xrepo\n_xrepo_zsh_complete()\n{\n  local words\n  read -Ac words\n  local completions=(\"$(XMAKE_SKIP_HISTORY=1 XMAKE_ROOT=y xmake lua private.xrepo.complete 0 nospace \"$words\")\")\n  reply=( \"${(ps:\\n:)completions}\" )\n}\ncompctl -f -S \"\" -K _xrepo_zsh_complete xrepo\n\n"
  },
  {
    "path": "xmake/scripts/conan/extensions/generators/xmake_generator.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nclass XmakeGenerator:\n    def __init__(self, conanfile):\n        self._conanfile = conanfile\n\n    def filename(self, pkgname = None):\n        if pkgname:\n            return \"conanbuildinfo_%s.xmake.lua\" %pkgname\n        else:\n            return \"conanbuildinfo.xmake.lua\"\n\n    def generate(self):\n        print(\"XmakeGenerator: generating build info ..\")\n\n        # extract all dependencies\n        host_req = self._conanfile.dependencies.host\n        test_req = self._conanfile.dependencies.test\n        build_req = self._conanfile.dependencies.build\n\n        full_req = list(host_req.items()) \\\n                   + list(test_req.items()) \\\n                   + list(build_req.items())\n\n        dep_names = []\n        pkginfo = None\n        plat = self._conanfile.settings.os\n        arch = self._conanfile.settings.arch\n        mode = self._conanfile.settings.build_type\n        for require, dep in full_req:\n            # get aggregate dependency's cppinfo\n            dep_aggregate = dep.cpp_info.aggregated_components()\n\n            # format deps\n            deps = XmakeDepsFormatter(dep_aggregate)\n\n            # get package and deps\n            dep_name = require.ref.name\n            if not pkginfo:\n                pkginfo = deps\n            else:\n                dep_names.append(dep_name)\n\n            # make content\n            template = ('  {plat}_{arch}_{mode} = \\n'\n                        '  {{\\n'\n                        '    includedirs    = {{{deps.include_paths}}},\\n'\n                        '    linkdirs       = {{{deps.lib_paths}}},\\n'\n                        '    links          = {{{deps.libs}}},\\n'\n                        '    frameworkdirs  = {{{deps.framework_paths}}},\\n'\n                        '    frameworks     = {{{deps.frameworks}}},\\n'\n                        '    syslinks       = {{{deps.system_libs}}},\\n'\n                        '    defines        = {{{deps.defines}}},\\n'\n                        '    cxxflags       = {{{deps.cppflags}}},\\n'\n                        '    cflags         = {{{deps.cflags}}},\\n'\n                        '    shflags        = {{{deps.sharedlinkflags}}},\\n'\n                        '    ldflags        = {{{deps.exelinkflags}}},\\n'\n                        '    __bindirs      = {{{deps.bin_paths}}},\\n'\n                        '    __resdirs      = {{{deps.res_paths}}},\\n'\n                        '    __srcdirs      = {{{deps.src_paths}}}\\n'\n                        '  }}')\n\n            sections = []\n            sections.append(template.format(plat = plat, arch = arch, mode = mode, deps = deps))\n            content = \"{\\n\" + \",\\n\".join(sections) + \"\\n}\"\n            print(dep_name, content)\n\n            # save package content to file\n            with open(self.filename(dep_name), 'w') as file:\n                file.write(content)\n\n        # save root content to file\n        template = ('  {plat}_{arch}_{mode} = \\n'\n                    '  {{\\n'\n                    '    includedirs    = {{{pkginfo.include_paths}}},\\n'\n                    '    linkdirs       = {{{pkginfo.lib_paths}}},\\n'\n                    '    links          = {{{pkginfo.libs}}},\\n'\n                    '    frameworkdirs  = {{{pkginfo.framework_paths}}},\\n'\n                    '    frameworks     = {{{pkginfo.frameworks}}},\\n'\n                    '    syslinks       = {{{pkginfo.system_libs}}},\\n'\n                    '    defines        = {{{pkginfo.defines}}},\\n'\n                    '    cxxflags       = {{{pkginfo.cppflags}}},\\n'\n                    '    cflags         = {{{pkginfo.cflags}}},\\n'\n                    '    shflags        = {{{pkginfo.sharedlinkflags}}},\\n'\n                    '    ldflags        = {{{pkginfo.exelinkflags}}},\\n'\n                    '    __bindirs      = {{{pkginfo.bin_paths}}},\\n'\n                    '    __resdirs      = {{{pkginfo.res_paths}}},\\n'\n                    '    __srcdirs      = {{{pkginfo.src_paths}}},\\n'\n                    '    __dep_names    = {{{dep_names}}}\\n'\n                    '  }}')\n\n        sections = []\n        dep_names_str = \", \".join('\"%s\"' % p for p in dep_names)\n        sections.append(template.format(plat = plat, arch = arch, mode = mode, pkginfo = pkginfo, dep_names = dep_names_str))\n        content = \"{\\n\" + \",\\n\".join(sections) + \"\\n}\"\n        print(content)\n\n        # save package content to file\n        with open(self.filename(), 'w') as file:\n            file.write(content)\n\nclass XmakeDepsFormatter(object):\n    def __prepare_process_escape_character(self, raw_string):\n        if raw_string.find('\\\"') != -1:\n            raw_string = raw_string.replace(\"\\\"\",\"\\\\\\\"\")\n        return raw_string\n\n    def __filter_char(self, raw_string):\n        return self.__prepare_process_escape_character(raw_string)\n\n    def __init__(self, deps_cpp_info):\n        includedirs     = deps_cpp_info._includedirs if deps_cpp_info._includedirs else []\n        libdirs         = deps_cpp_info._libdirs if deps_cpp_info._libdirs else []\n        bindirs         = deps_cpp_info._bindirs if deps_cpp_info._bindirs else []\n        resdirs         = deps_cpp_info._resdirs if deps_cpp_info._resdirs else []\n        srcdirs         = deps_cpp_info._srcdirs if deps_cpp_info._srcdirs else []\n        frameworkdirs   = deps_cpp_info._frameworkdirs if deps_cpp_info._frameworkdirs else []\n        libs            = deps_cpp_info._libs if deps_cpp_info._libs else []\n        frameworks      = deps_cpp_info._frameworks if deps_cpp_info._frameworks else []\n        system_libs     = deps_cpp_info._system_libs if deps_cpp_info._system_libs else []\n        defines         = deps_cpp_info._defines if deps_cpp_info._defines else []\n        cxxflags        = deps_cpp_info._cxxflags if deps_cpp_info._cxxflags else []\n        cflags          = deps_cpp_info._cflags if deps_cpp_info._cflags else []\n        sharedlinkflags = deps_cpp_info._sharedlinkflags if deps_cpp_info._sharedlinkflags else []\n        exelinkflags    = deps_cpp_info._exelinkflags if deps_cpp_info._exelinkflags else []\n\n        self.include_paths   = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in includedirs)\n        self.lib_paths       = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in libdirs)\n        self.bin_paths       = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in bindirs)\n        self.res_paths       = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in resdirs)\n        self.src_paths       = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in srcdirs)\n        self.framework_paths = \",\\n\".join('\"%s\"' % self.__filter_char(p.replace(\"\\\\\", \"/\")) for p in frameworkdirs)\n        self.libs            = \", \".join('\"%s\"' % p for p in libs)\n        self.frameworks      = \", \".join('\"%s\"' % p for p in frameworks)\n        self.system_libs     = \", \".join('\"%s\"' % p for p in system_libs)\n        self.defines         = \", \".join('\"%s\"' % self.__filter_char(p) for p in defines)\n        self.cppflags        = \", \".join('\"%s\"' % p for p in cxxflags)\n        self.cflags          = \", \".join('\"%s\"' % p for p in cflags)\n        self.sharedlinkflags = \", \".join('\"%s\"' % p for p in sharedlinkflags)\n        self.exelinkflags    = \", \".join('\"%s\"' % p for p in exelinkflags)\n\n"
  },
  {
    "path": "xmake/scripts/download.ps1",
    "content": "#!/usr/bin/env pwsh\n#Requires -version 5\n\nparam (\n    [string]$url,\n    [string]$outputfile\n)\n\n& {\n    function writeErrorTip($msg) {\n        Write-Host $msg -BackgroundColor Red -ForegroundColor White\n    }\n\n    $temppath = ([System.IO.Path]::GetTempPath(), $env:TMP, $env:TEMP, \"$(Get-Location)\" -ne $null)[0]\n    [Net.ServicePointManager]::SecurityProtocol = \"tls12, tls11, tls\"\n\n    function download {\n        try {\n            Invoke-Webrequest $url -OutFile $outputfile -UseBasicParsing\n        } catch {\n            writeErrorTip 'Download failed!'\n            throw\n        }\n    }\n\n    download\n}\n"
  },
  {
    "path": "xmake/scripts/faq.lua",
    "content": "--\n-- If you want to known more usage about xmake, please see https://xmake.io\n--\n-- ## FAQ\n--\n-- You can enter the project directory firstly before building project.\n--\n--   $ cd projectdir\n--\n-- 1. How to build project?\n--\n--   $ xmake\n--\n-- 2. How to configure project?\n--\n--   $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release]\n--\n-- 3. Where is the build output directory?\n--\n--   The default output directory is `./build` and you can configure the output directory.\n--\n--   $ xmake f -o outputdir\n--   $ xmake\n--\n-- 4. How to run and debug target after building project?\n--\n--   $ xmake run [targetname]\n--   $ xmake run -d [targetname]\n--\n-- 5. How to install target to the system directory or other output directory?\n--\n--   $ xmake install\n--   $ xmake install -o installdir\n--\n-- 6. Add some frequently-used compilation flags in xmake.lua\n--\n-- @code\n--    -- add debug and release modes\n--    add_rules(\"mode.debug\", \"mode.release\")\n--\n--    -- add macro definition\n--    add_defines(\"NDEBUG\", \"_GNU_SOURCE=1\")\n--\n--    -- set warning all as error\n--    set_warnings(\"all\", \"error\")\n--\n--    -- set language: c99, c++11\n--    set_languages(\"c99\", \"c++11\")\n--\n--    -- set optimization: none, faster, fastest, smallest\n--    set_optimize(\"fastest\")\n--\n--    -- add include search directories\n--    add_includedirs(\"/usr/include\", \"/usr/local/include\")\n--\n--    -- add link libraries and search directories\n--    add_links(\"tbox\")\n--    add_linkdirs(\"/usr/local/lib\", \"/usr/lib\")\n--\n--    -- add system link libraries\n--    add_syslinks(\"z\", \"pthread\")\n--\n--    -- add compilation and link flags\n--    add_cxflags(\"-stdnolib\", \"-fno-strict-aliasing\")\n--    add_ldflags(\"-L/usr/local/lib\", \"-lpthread\", {force = true})\n--\n-- @endcode\n--\n"
  },
  {
    "path": "xmake/scripts/find_cudadevices.cpp",
    "content": "#include <cuda_runtime.h>\n#include <cuda.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef PRINT_SUFFIX\n#define PRINT_SUFFIX \"<find_cudadevices>\"\n#endif\n\n#define MY_CUDA_VER (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)\n\ninline void check(cudaError_t result)\n{\n    if (result)\n    {\n        fprintf(stderr, PRINT_SUFFIX \"%s (%s)\", cudaGetErrorName(result), cudaGetErrorString(result));\n        cudaDeviceReset();\n        // Make sure we call CUDA Device Reset before exiting\n        exit(0);\n    }\n}\n\ninline void check_driver(CUresult result)\n{\n    static char unknown[] = \"unknown\";\n    if (result != CUDA_SUCCESS)\n    {\n        const char *name = NULL, *msg = NULL;\n        cuGetErrorName(result, &name);\n        cuGetErrorString(result, &msg);\n        fprintf(stderr, PRINT_SUFFIX \"%s (%s)\", name ? name : unknown, msg ? msg : unknown);\n        exit(0);\n    }\n}\n\ninline void print_value(unsigned long long value)\n{\n    printf(\"%llu\", value);\n}\n\ninline void print_value(unsigned long value)\n{\n    printf(\"%lu\", value);\n}\n\ninline void print_value(unsigned int value)\n{\n    printf(\"%u\", value);\n}\n\ninline void print_value(bool value)\n{\n    printf(value ? \"true\" : \"false\");\n}\n\ninline void print_value(int value)\n{\n    printf(\"%d\", value);\n}\n\ntemplate <typename T, size_t len>\ninline void print_value(const T (&value)[len])\n{\n    printf(\"(\");\n    for (size_t i = 0; i < len - 1; i++)\n    {\n        print_value(value[i]);\n        printf(\", \");\n    }\n    print_value(value[len - 1]);\n    printf(\")\");\n}\n\ninline void print_value(const void *value)\n{\n    printf(\"\\\"%s\\\"\", (const char *)value);\n}\n\ntemplate <size_t len>\ninline void print_value(const char (&value)[len])\n{\n    printf(\"\\\"\");\n    for (size_t i = 0; i < len; i++)\n        printf(\"%02hhx\", value[i]);\n    printf(\"\\\"\");\n}\n\ntemplate <>\ninline void print_value<16>(const char (&value)[16])\n{\n    // speicalized for uuid\n    printf(\"\\\"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\\\"\",\n           value[0], value[1], value[2], value[3],\n           value[4], value[5], value[6], value[7],\n           value[8], value[9], value[10], value[11],\n           value[12], value[13], value[14], value[15]);\n}\n\n#if MY_CUDA_VER >= 1000\ninline void print_value(const cudaUUID_t &value)\n{\n    print_value(value.bytes);\n}\n#endif\n\ntemplate <typename T>\ninline void print_property(const char *name, const T &value)\n{\n    printf(PRINT_SUFFIX \"    %s = \", name);\n    print_value(value);\n    printf(\"\\n\");\n}\n\ninline void print_device(int id)\n{\n    cudaDeviceProp deviceProp;\n    check(cudaGetDeviceProperties(&deviceProp, id));\n\n#define PRINT_PROPERTY(name) print_property(#name, deviceProp.name)\n#define PRINT_BOOL_PROPERTY(name) print_property(#name, static_cast<bool>(deviceProp.name))\n#define PRINT_STR_PROPERTY(name) print_property(#name, static_cast<const void *>(deviceProp.name))\n    // cuda 8.0\n    PRINT_STR_PROPERTY(name);\n    PRINT_PROPERTY(totalGlobalMem);\n    PRINT_PROPERTY(sharedMemPerBlock);\n    PRINT_PROPERTY(regsPerBlock);\n    PRINT_PROPERTY(warpSize);\n    PRINT_PROPERTY(memPitch);\n    PRINT_PROPERTY(maxThreadsPerBlock);\n    PRINT_PROPERTY(maxThreadsDim);\n    PRINT_PROPERTY(maxGridSize);\n    PRINT_PROPERTY(totalConstMem);\n    PRINT_PROPERTY(major);\n    PRINT_PROPERTY(minor);\n    PRINT_PROPERTY(textureAlignment);\n    PRINT_PROPERTY(texturePitchAlignment);\n    PRINT_PROPERTY(multiProcessorCount);\n    PRINT_BOOL_PROPERTY(integrated);\n    PRINT_BOOL_PROPERTY(canMapHostMemory);\n    PRINT_PROPERTY(maxTexture1D);\n    PRINT_PROPERTY(maxTexture1DMipmap);\n    PRINT_PROPERTY(maxTexture2D);\n    PRINT_PROPERTY(maxTexture2DMipmap);\n    PRINT_PROPERTY(maxTexture2DLinear);\n    PRINT_PROPERTY(maxTexture2DGather);\n    PRINT_PROPERTY(maxTexture3D);\n    PRINT_PROPERTY(maxTexture3DAlt);\n    PRINT_PROPERTY(maxTextureCubemap);\n    PRINT_PROPERTY(maxTexture1DLayered);\n    PRINT_PROPERTY(maxTexture2DLayered);\n    PRINT_PROPERTY(maxTextureCubemapLayered);\n    PRINT_PROPERTY(maxSurface1D);\n    PRINT_PROPERTY(maxSurface2D);\n    PRINT_PROPERTY(maxSurface3D);\n    PRINT_PROPERTY(maxSurface1DLayered);\n    PRINT_PROPERTY(maxSurface2DLayered);\n    PRINT_PROPERTY(maxSurfaceCubemap);\n    PRINT_PROPERTY(maxSurfaceCubemapLayered);\n    PRINT_PROPERTY(surfaceAlignment);\n    PRINT_BOOL_PROPERTY(concurrentKernels);\n    PRINT_BOOL_PROPERTY(ECCEnabled);\n    PRINT_PROPERTY(pciBusID);\n    PRINT_PROPERTY(pciDeviceID);\n    PRINT_PROPERTY(pciDomainID);\n    PRINT_BOOL_PROPERTY(tccDriver);\n    PRINT_PROPERTY(asyncEngineCount);\n    PRINT_BOOL_PROPERTY(unifiedAddressing);\n    PRINT_PROPERTY(memoryBusWidth);\n    PRINT_PROPERTY(l2CacheSize);\n    PRINT_PROPERTY(maxThreadsPerMultiProcessor);\n    PRINT_BOOL_PROPERTY(streamPrioritiesSupported);\n    PRINT_BOOL_PROPERTY(globalL1CacheSupported);\n    PRINT_BOOL_PROPERTY(localL1CacheSupported);\n    PRINT_PROPERTY(sharedMemPerMultiprocessor);\n    PRINT_PROPERTY(regsPerMultiprocessor);\n    PRINT_BOOL_PROPERTY(isMultiGpuBoard);\n    PRINT_PROPERTY(multiGpuBoardGroupID);\n    PRINT_BOOL_PROPERTY(pageableMemoryAccess);\n    PRINT_BOOL_PROPERTY(concurrentManagedAccess);\n    PRINT_BOOL_PROPERTY(managedMemory);\n\n#if MY_CUDA_VER < 1300\n    PRINT_PROPERTY(clockRate);\n    PRINT_PROPERTY(memoryClockRate);\n    PRINT_BOOL_PROPERTY(deviceOverlap);\n    PRINT_BOOL_PROPERTY(kernelExecTimeoutEnabled);\n    PRINT_PROPERTY(computeMode);\n    PRINT_PROPERTY(maxTexture1DLinear);\n    PRINT_PROPERTY(singleToDoublePrecisionPerfRatio);\n#else\n    int clockRate, memoryClockRate, computeMode;\n    check_driver(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, id));\n    check_driver(cuDeviceGetAttribute(&memoryClockRate, CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE, id));\n    check_driver(cuDeviceGetAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, id));\n    print_property(\"clockRate\", clockRate);\n    print_property(\"memoryClockRate\", memoryClockRate);\n    print_property(\"computeMode\", computeMode);\n#endif\n\n#if MY_CUDA_VER >= 900\n    // Added in cuda 9.0\n    PRINT_BOOL_PROPERTY(computePreemptionSupported);\n    PRINT_BOOL_PROPERTY(canUseHostPointerForRegisteredMem);\n    PRINT_BOOL_PROPERTY(cooperativeLaunch);\n    PRINT_PROPERTY(sharedMemPerBlockOptin);\n#if MY_CUDA_VER < 1300\n    PRINT_BOOL_PROPERTY(cooperativeMultiDeviceLaunch);\n#endif\n#endif\n\n#if MY_CUDA_VER >= 902\n    // Added in cuda 9.2\n    PRINT_BOOL_PROPERTY(pageableMemoryAccessUsesHostPageTables);\n    PRINT_BOOL_PROPERTY(directManagedMemAccessFromHost);\n#endif\n\n#if MY_CUDA_VER >= 1000\n    // Added in cuda 10.0\n    PRINT_PROPERTY(uuid);\n    PRINT_PROPERTY(luid);\n    PRINT_PROPERTY(luidDeviceNodeMask);\n#endif\n}\n\nint main(int argc, char *argv[])\n{\n    printf(\"\\n\");\n    fprintf(stderr, \"\\n\");\n\n    int count = 0;\n    check(cudaGetDeviceCount(&count));\n    for (int i = 0; i < count; i++)\n    {\n        printf(PRINT_SUFFIX \"DEVICE #%d\\n\", i);\n        print_device(i);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "xmake/scripts/gas-preprocessor.pl",
    "content": "#!/usr/bin/env perl\n# by David Conrad\n# This code is licensed under GPLv2 or later; go to gnu.org to read it\n#  (not that it much matters for an asm preprocessor)\n# usage: set your assembler to be something like \"perl gas-preprocessor.pl gcc\"\nuse strict;\n\n# Apple's gas is ancient and doesn't support modern preprocessing features like\n# .rept and has ugly macro syntax, among other things. Thus, this script\n# implements the subset of the gas preprocessor used by x264 and ffmpeg\n# that isn't supported by Apple's gas.\n\nmy %canonical_arch = (\"aarch64\" => \"aarch64\", \"arm64\" => \"aarch64\",\n                      \"arm\"     => \"arm\",\n                      \"powerpc\" => \"powerpc\", \"ppc\"   => \"powerpc\");\n\nmy %comments = (\"aarch64\" => '//',\n                \"arm\"     => '@',\n                \"ppc\"     => '#',\n                \"powerpc\" => '#');\n\nmy @gcc_cmd;\nmy @preprocess_c_cmd;\n\nmy $comm;\nmy $arch;\nmy $as_type = \"apple-gas\";\n\nmy $fix_unreq = $^O eq \"darwin\";\nmy $force_thumb = 0;\nmy $verbose = 0;\n\nmy $arm_cond_codes = \"eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo\";\n\nmy $usage_str = \"\n$0\\n\nGas-preprocessor.pl converts assembler files using modern GNU as syntax for\nApple's ancient gas version or clang's incompatible integrated assembler. The\nconversion is regularly tested for FFmpeg, Libav, x264 and vlc. Other projects might\nuse different features which are not correctly handled.\n\nOptions for this program needs to be separated with ' -- ' from the assembler\ncommand. Following options are currently supported:\n\n    -help         - this usage text\n    -arch         - target architecture\n    -as-type      - one value out of {{,apple-}{gas,clang},armasm}\n    -fix-unreq\n    -no-fix-unreq\n    -force-thumb  - assemble as thumb regardless of the input source\n                    (note, this is incomplete and only works for sources\n                    it explicitly was tested with)\n    -verbose      - print executed commands\n\";\n\nsub usage() {\n    print $usage_str;\n}\n\nwhile (@ARGV) {\n    my $opt = shift;\n\n    if ($opt =~ /^-(no-)?fix-unreq$/) {\n        $fix_unreq = $1 ne \"no-\";\n    } elsif ($opt eq \"-force-thumb\") {\n        $force_thumb = 1;\n    } elsif ($opt eq \"-verbose\") {\n        $verbose = 1;\n    } elsif ($opt eq \"-arch\") {\n        $arch = shift;\n        die \"unknown arch: '$arch'\\n\" if not exists $canonical_arch{$arch};\n    } elsif ($opt eq \"-as-type\") {\n        $as_type = shift;\n        die \"unknown as type: '$as_type'\\n\" if $as_type !~ /^((apple-)?(gas|clang|llvm_gcc)|armasm)$/;\n    } elsif ($opt eq \"-help\") {\n        usage();\n        exit 0;\n    } elsif ($opt eq \"--\" ) {\n        @gcc_cmd = @ARGV;\n    } elsif ($opt =~ /^-/) {\n        die \"option '$opt' is not known. See '$0 -help' for usage information\\n\";\n    } else {\n        push @gcc_cmd, $opt, @ARGV;\n    }\n    last if (@gcc_cmd);\n}\n\nif (grep /\\.c$/, @gcc_cmd) {\n    # C file (inline asm?) - compile\n    @preprocess_c_cmd = (@gcc_cmd, \"-S\");\n} elsif (grep /\\.[sS]$/, @gcc_cmd) {\n    # asm file, just do C preprocessor\n    @preprocess_c_cmd = (@gcc_cmd, \"-E\");\n} elsif (grep /-(v|h|-version|dumpversion)/, @gcc_cmd) {\n    # pass -v/--version along, used during probing. Matching '-v' might have\n    # uninteded results but it doesn't matter much if gas-preprocessor or\n    # the compiler fails.\n    print STDERR join(\" \", @gcc_cmd).\"\\n\" if $verbose;\n    exec(@gcc_cmd);\n} else {\n    die \"Unrecognized input filetype\";\n}\nif ($as_type eq \"armasm\") {\n\n    $preprocess_c_cmd[0] = \"cpp\";\n\n    # Remove -ignore XX parameter pairs from preprocess_c_cmd\n    my $index = 1;\n    while ($index < $#preprocess_c_cmd) {\n        if ($preprocess_c_cmd[$index] eq \"-ignore\" and $index + 1 < $#preprocess_c_cmd) {\n            splice(@preprocess_c_cmd, $index, 2);\n            next;\n        }\n        $index++;\n    }\n    if (grep /^-MM$/, @preprocess_c_cmd) {\n        push(@preprocess_c_cmd, \"-D_WIN32\");\n        # Normally a preprocessor for windows would predefine _WIN32,\n        # but we're using any generic system-agnostic preprocessor \"cpp\"\n        # with -undef (to avoid getting predefined variables from the host\n        # system in cross compilation cases), so manually define it here.\n        # We only use this generic preprocessor for generating dependencies,\n        # if the build system runs preprocessing with -M/-MM without -MF.\n        push(@preprocess_c_cmd, \"-undef\");\n        @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd;\n        print STDERR join(\" \", @preprocess_c_cmd).\"\\n\" if $verbose;\n        system(@preprocess_c_cmd) == 0 or die \"Error running preprocessor\";\n        exit 0;\n    }\n\n    # If not preprocessing for getting a dependency list, use cl.exe\n    # instead.\n    $preprocess_c_cmd[0] = \"cl\";\n}\n\n# if compiling, avoid creating an output file named '-.o'\nif ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) {\n    foreach my $i (@gcc_cmd) {\n        if ($i =~ /\\.[csS]$/) {\n            my $outputfile = $i;\n            $outputfile =~ s/\\.[csS]$/.o/;\n            push(@gcc_cmd, \"-o\");\n            push(@gcc_cmd, $outputfile);\n            last;\n        }\n    }\n}\n# Remove the -o argument; if omitted, we by default preprocess to stdout.\nmy $index = 1;\nwhile ($index < $#preprocess_c_cmd) {\n    if ($preprocess_c_cmd[$index] eq \"-o\") {\n        splice(@preprocess_c_cmd, $index, 2);\n        last;\n    }\n    $index++;\n}\n\nmy $tempfile;\nif ($as_type ne \"armasm\") {\n    @gcc_cmd = map { /\\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd;\n\n    # Filter out options that can cause warnings due to unused arguments,\n    # Clang warns about unused -D parameters when invoked with \"-x assembler\".\n    @gcc_cmd = grep ! /^-D/, @gcc_cmd;\n} else {\n    @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd;\n\n    @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-oldit/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-FS/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-w/, @preprocess_c_cmd;\n    @preprocess_c_cmd = grep ! /^-M/, @preprocess_c_cmd;\n\n    @gcc_cmd = grep ! /^-G/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-W/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-Z/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-fp/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-O/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-FS/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-w/, @gcc_cmd;\n\n    my @outfiles = grep /\\.(o|obj)$/, @gcc_cmd;\n    $tempfile = $outfiles[0].\".asm\";\n\n    # Remove most parameters from gcc_cmd, which actually is the armasm command,\n    # which doesn't support any of the common compiler/preprocessor options.\n    @gcc_cmd = grep ! /^-D/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-U/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-m/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-M/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-c$/, @gcc_cmd;\n    @gcc_cmd = grep ! /^-I/, @gcc_cmd;\n    @gcc_cmd = map { /\\.S$/ ? $tempfile : $_ } @gcc_cmd;\n}\n\n# detect architecture from gcc binary name\nif (!$arch) {\n    if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) {\n        $arch = $1;\n    } else {\n        # look for -arch flag\n        foreach my $i (1 .. $#gcc_cmd-1) {\n            if ($gcc_cmd[$i] eq \"-arch\" and\n                $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) {\n                $arch = $1;\n            }\n        }\n    }\n}\n\n# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name\n$arch = qx/arch/ if (!$arch);\n\ndie \"Unknown target architecture '$arch'\" if not exists $canonical_arch{$arch};\n\n$arch = $canonical_arch{$arch};\n$comm = $comments{$arch};\nmy $inputcomm = $comm;\n$comm = \";\" if $as_type =~ /armasm/;\n\nmy %ppc_spr = (ctr    => 9,\n               vrsave => 256);\n\nprint STDERR join(\" \", @preprocess_c_cmd).\"\\n\" if $verbose;\nopen(INPUT, \"-|\", @preprocess_c_cmd) || die \"Error running preprocessor\";\n\nif ($ENV{GASPP_DEBUG}) {\n    open(ASMFILE, \">&STDOUT\");\n} else {\n    if ($as_type ne \"armasm\") {\n        print STDERR join(\" \", @gcc_cmd).\"\\n\" if $verbose;\n        open(ASMFILE, \"|-\", @gcc_cmd) or die \"Error running assembler\";\n    } else {\n        open(ASMFILE, \">\", $tempfile);\n    }\n}\n\nmy $current_macro = '';\nmy $macro_level = 0;\nmy $rept_level = 0;\nmy %macro_lines;\nmy %macro_args;\nmy %macro_args_default;\nmy $macro_count = 0;\nmy $altmacro = 0;\nmy $in_irp = 0;\n\nmy $num_repts;\nmy @rept_lines;\n\nmy @irp_args;\nmy $irp_param;\n\nmy @ifstack;\n\nmy %symbols;\n\nmy @sections;\n\nmy %literal_labels;     # for ldr <reg>, =<expr>\nmy $literal_num = 0;\nmy $literal_expr = \".word\";\n$literal_expr = \".quad\" if $arch eq \"aarch64\";\n\nmy $thumb = 0;\n\nmy %thumb_labels;\nmy %call_targets;\nmy %import_symbols;\n\nmy %neon_alias_reg;\nmy %neon_alias_type;\n\nmy $temp_label_next = 0;\nmy %last_temp_labels;\nmy %next_temp_labels;\n\nmy %labels_seen;\n\nmy %aarch64_req_alias;\n\nif ($force_thumb) {\n    parse_line(\".thumb\\n\");\n}\n\n# pass 1: parse .macro\n# note that the handling of arguments is probably overly permissive vs. gas\n# but it should be the same for valid cases\nwhile (<INPUT>) {\n    # remove lines starting with '#', preprocessing is done, '#' at start of\n    # the line indicates a comment for all supported archs (aarch64, arm, ppc\n    # and x86). Also strips line number comments but since they are off anyway\n    # it is no loss.\n    s/^\\s*#.*$//;\n    # remove all comments (to avoid interfering with evaluating directives)\n    s/(?<!\\\\)$inputcomm.*//x;\n    # Strip out windows linefeeds\n    s/\\r$//;\n\n    foreach my $subline (split(\";\", $_)) {\n        chomp $subline;\n        parse_line_continued($subline);\n    }\n}\nparse_line_continued(\"\");\n\nsub eval_expr {\n    my $expr = $_[0];\n    while ($expr =~ /([A-Za-z._][A-Za-z0-9._]*)/g) {\n        my $sym = $1;\n        $expr =~ s/$sym/($symbols{$sym})/ if defined $symbols{$sym};\n    }\n    eval $expr;\n}\n\nsub handle_if {\n    my $line = $_[0];\n    # handle .if directives; apple's assembler doesn't support important non-basic ones\n    # evaluating them is also needed to handle recursive macros\n    if ($line =~ /\\.if(n?)([a-z]*)\\s+(.*)/) {\n        my $result = $1 eq \"n\";\n        my $type   = $2;\n        my $expr   = $3;\n\n        if ($type eq \"b\") {\n            $expr =~ s/\\s//g;\n            $result ^= $expr eq \"\";\n        } elsif ($type eq \"c\") {\n            if ($expr =~ /(\\S*)\\s*,\\s*(\\S*)/) {\n                $result ^= $1 eq $2;\n            } else {\n                die \"argument to .ifc not recognized\";\n            }\n        } elsif ($type eq \"\") {\n            $result ^= eval_expr($expr) != 0;\n        } elsif ($type eq \"eq\") {\n            $result = eval_expr($expr) == 0;\n        } elsif ($type eq \"lt\") {\n            $result = eval_expr($expr) < 0;\n        } else {\n            chomp($line);\n            die \"unhandled .if varient. \\\"$line\\\"\";\n        }\n        push (@ifstack, $result);\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nsub parse_if_line {\n    my $line = $_[0];\n\n    # evaluate .if blocks\n    if (scalar(@ifstack)) {\n        # Don't evaluate any new if statements if we're within\n        # a repetition or macro - they will be evaluated once\n        # the repetition is unrolled or the macro is expanded.\n        if (scalar(@rept_lines) == 0 and $macro_level == 0) {\n            if ($line =~ /\\.endif/) {\n                pop(@ifstack);\n                return 1;\n            } elsif ($line =~ /\\.elseif\\s+(.*)/) {\n                if ($ifstack[-1] == 0) {\n                    $ifstack[-1] = !!eval_expr($1);\n                } elsif ($ifstack[-1] > 0) {\n                    $ifstack[-1] = -$ifstack[-1];\n                }\n                return 1;\n            } elsif ($line =~ /\\.else/) {\n                $ifstack[-1] = !$ifstack[-1];\n                return 1;\n            } elsif (handle_if($line)) {\n                return 1;\n            }\n        }\n\n        # discard lines in false .if blocks\n        foreach my $i (0 .. $#ifstack) {\n            if ($ifstack[$i] <= 0) {\n                return 1;\n            }\n        }\n    }\n    return 0;\n}\n\nmy $last_line = \"\";\nsub parse_line_continued {\n    my $line = $_[0];\n    $last_line .= $line;\n    if ($last_line =~ /\\\\$/) {\n        $last_line =~ s/\\\\$//;\n    } else {\n        # Add newlines at the end of lines after concatenation.\n        $last_line .= \"\\n\";\n        parse_line($last_line);\n        $last_line = \"\";\n    }\n}\n\nsub parse_line {\n    my $line = $_[0];\n\n    return if (parse_if_line($line));\n\n    if (scalar(@rept_lines) == 0) {\n        if ($line =~ /\\.macro/) {\n            $macro_level++;\n            if ($macro_level > 1 && !$current_macro) {\n                die \"nested macros but we don't have master macro\";\n            }\n        } elsif ($line =~ /\\.endm/) {\n            $macro_level--;\n            if ($macro_level < 0) {\n                die \"unmatched .endm\";\n            } elsif ($macro_level == 0) {\n                $current_macro = '';\n                return;\n            }\n        }\n    }\n\n    if ($macro_level == 0) {\n        if ($line =~ /\\.(rept|irp)/) {\n            $rept_level++;\n        } elsif ($line =~ /.endr/) {\n            $rept_level--;\n        }\n    }\n\n    if ($macro_level > 1) {\n        push(@{$macro_lines{$current_macro}}, $line);\n    } elsif (scalar(@rept_lines) and $rept_level >= 1) {\n        push(@rept_lines, $line);\n    } elsif ($macro_level == 0) {\n        expand_macros($line);\n    } else {\n        if ($line =~ /\\.macro\\s+([\\d\\w\\.]+)\\s*,?\\s*(.*)/) {\n            $current_macro = $1;\n\n            # commas in the argument list are optional, so only use whitespace as the separator\n            my $arglist = $2;\n            $arglist =~ s/,/ /g;\n\n            my @args = split(/\\s+/, $arglist);\n            foreach my $i (0 .. $#args) {\n                my @argpair = split(/=/, $args[$i]);\n                $macro_args{$current_macro}[$i] = $argpair[0];\n                $argpair[0] =~ s/:vararg$//;\n                $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1];\n            }\n            # ensure %macro_lines has the macro name added as a key\n            $macro_lines{$current_macro} = [];\n\n        } elsif ($current_macro) {\n            push(@{$macro_lines{$current_macro}}, $line);\n        } else {\n            die \"macro level without a macro name\";\n        }\n    }\n}\n\nsub handle_set {\n    my $line = $_[0];\n    if ($line =~ /\\.(?:set|equ)\\s+(\\S*)\\s*,\\s*(.*)/) {\n        $symbols{$1} = eval_expr($2);\n        return 1;\n    }\n    return 0;\n}\n\nsub expand_macros {\n    my $line = $_[0];\n\n    # handle .if directives; apple's assembler doesn't support important non-basic ones\n    # evaluating them is also needed to handle recursive macros\n    if (handle_if($line)) {\n        return;\n    }\n\n    if (/\\.purgem\\s+([\\d\\w\\.]+)/) {\n        delete $macro_lines{$1};\n        delete $macro_args{$1};\n        delete $macro_args_default{$1};\n        return;\n    }\n\n    if ($line =~ /\\.altmacro/) {\n        $altmacro = 1;\n        return;\n    }\n\n    if ($line =~ /\\.noaltmacro/) {\n        $altmacro = 0;\n        return;\n    }\n\n    $line =~ s/\\%([^,]*)/eval_expr($1)/eg if $altmacro;\n\n    # Strip out the .set lines from the armasm output\n    return if (handle_set($line) and $as_type eq \"armasm\");\n\n    if ($line =~ /\\.rept\\s+(.*)/) {\n        $num_repts = $1;\n        @rept_lines = (\"\\n\");\n\n        # handle the possibility of repeating another directive on the same line\n        # .endr on the same line is not valid, I don't know if a non-directive is\n        if ($num_repts =~ s/(\\.\\w+.*)//) {\n            push(@rept_lines, \"$1\\n\");\n        }\n        $num_repts = eval_expr($num_repts);\n    } elsif ($line =~ /\\.irp\\s+([\\d\\w\\.]+)\\s*(.*)/) {\n        $in_irp = 1;\n        $num_repts = 1;\n        @rept_lines = (\"\\n\");\n        $irp_param = $1;\n\n        # only use whitespace as the separator\n        my $irp_arglist = $2;\n        $irp_arglist =~ s/,/ /g;\n        $irp_arglist =~ s/^\\s+//;\n        @irp_args = split(/\\s+/, $irp_arglist);\n    } elsif ($line =~ /\\.irpc\\s+([\\d\\w\\.]+)\\s*(.*)/) {\n        $in_irp = 1;\n        $num_repts = 1;\n        @rept_lines = (\"\\n\");\n        $irp_param = $1;\n\n        my $irp_arglist = $2;\n        $irp_arglist =~ s/,/ /g;\n        $irp_arglist =~ s/^\\s+//;\n        @irp_args = split(//, $irp_arglist);\n    } elsif ($line =~ /\\.endr/) {\n        my @prev_rept_lines = @rept_lines;\n        my $prev_in_irp = $in_irp;\n        my @prev_irp_args = @irp_args;\n        my $prev_irp_param = $irp_param;\n        my $prev_num_repts = $num_repts;\n        @rept_lines = ();\n        $in_irp = 0;\n        @irp_args = '';\n\n        if ($prev_in_irp != 0) {\n            foreach my $i (@prev_irp_args) {\n                foreach my $origline (@prev_rept_lines) {\n                    my $line = $origline;\n                    $line =~ s/\\\\$prev_irp_param/$i/g;\n                    $line =~ s/\\\\\\(\\)//g;     # remove \\()\n                    parse_line($line);\n                }\n            }\n        } else {\n            for (1 .. $prev_num_repts) {\n                foreach my $origline (@prev_rept_lines) {\n                    my $line = $origline;\n                    parse_line($line);\n                }\n            }\n        }\n    } elsif ($line =~ /(\\S+:|)\\s*([\\w\\d\\.]+)\\s*(.*)/ && exists $macro_lines{$2}) {\n        handle_serialized_line($1);\n        my $macro = $2;\n\n        # commas are optional here too, but are syntactically important because\n        # parameters can be blank\n        my @arglist = split(/,/, $3);\n        my @args;\n        my @args_seperator;\n\n        my $comma_sep_required = 0;\n        foreach (@arglist) {\n            # allow arithmetic/shift operators in macro arguments\n            $_ =~ s/\\s*(\\+|-|\\*|\\/|<<|>>|<|>)\\s*/$1/g;\n\n            my @whitespace_split = split(/\\s+/, $_);\n            if (!@whitespace_split) {\n                push(@args, '');\n                push(@args_seperator, '');\n            } else {\n                foreach (@whitespace_split) {\n                        #print (\"arglist = \\\"$_\\\"\\n\");\n                    if (length($_)) {\n                        push(@args, $_);\n                        my $sep = $comma_sep_required ? \",\" : \" \";\n                        push(@args_seperator, $sep);\n                        #print (\"sep = \\\"$sep\\\", arg = \\\"$_\\\"\\n\");\n                        $comma_sep_required = 0;\n                    }\n                }\n            }\n\n            $comma_sep_required = 1;\n        }\n\n        my %replacements;\n        if ($macro_args_default{$macro}){\n            %replacements = %{$macro_args_default{$macro}};\n        }\n\n        # construct hashtable of text to replace\n        foreach my $i (0 .. $#args) {\n            my $argname = $macro_args{$macro}[$i];\n            my @macro_args = @{ $macro_args{$macro} };\n            if ($args[$i] =~ m/=/) {\n                # arg=val references the argument name\n                # XXX: I'm not sure what the expected behaviour if a lot of\n                # these are mixed with unnamed args\n                my @named_arg = split(/=/, $args[$i]);\n                $replacements{$named_arg[0]} = $named_arg[1];\n            } elsif ($i > $#{$macro_args{$macro}}) {\n                # more args given than the macro has named args\n                # XXX: is vararg allowed on arguments before the last?\n                $argname = $macro_args{$macro}[-1];\n                if ($argname =~ s/:vararg$//) {\n                    #print \"macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\\n\";\n                    #$replacements{$argname} .= \", $args[$i]\";\n                    $replacements{$argname} .= \"$args_seperator[$i] $args[$i]\";\n                } else {\n                    die \"Too many arguments to macro $macro\";\n                }\n            } else {\n                $argname =~ s/:vararg$//;\n                $replacements{$argname} = $args[$i];\n            }\n        }\n\n        my $count = $macro_count++;\n\n        # apply replacements as regex\n        foreach (@{$macro_lines{$macro}}) {\n            my $macro_line = $_;\n            # do replacements by longest first, this avoids wrong replacement\n            # when argument names are subsets of each other\n            foreach (reverse sort {length $a <=> length $b} keys %replacements) {\n                $macro_line =~ s/\\\\$_/$replacements{$_}/g;\n            }\n            if ($altmacro) {\n                foreach (reverse sort {length $a <=> length $b} keys %replacements) {\n                    $macro_line =~ s/\\b$_\\b/$replacements{$_}/g;\n                }\n            }\n            $macro_line =~ s/\\\\\\@/$count/g;\n            $macro_line =~ s/\\\\\\(\\)//g;     # remove \\()\n            parse_line($macro_line);\n        }\n    } else {\n        handle_serialized_line($line);\n    }\n}\n\nsub is_arm_register {\n    my $name = $_[0];\n    if ($name eq \"lr\" or\n        $name eq \"ip\" or\n        $name =~ /^[rav]\\d+$/) {\n        return 1;\n    }\n    return 0;\n}\n\nsub is_aarch64_register {\n    my $name = $_[0];\n    if ($name =~ /^[xw]\\d+$/) {\n        return 1;\n    }\n    return 0;\n}\n\nsub handle_local_label {\n    my $line = $_[0];\n    my $num  = $_[1];\n    my $dir  = $_[2];\n    my $target = \"$num$dir\";\n    if ($dir eq \"b\") {\n        $line =~ s/\\b$target\\b/$last_temp_labels{$num}/g;\n    } else {\n        my $name = \"temp_label_$temp_label_next\";\n        $temp_label_next++;\n        push(@{$next_temp_labels{$num}}, $name);\n        $line =~ s/\\b$target\\b/$name/g;\n    }\n    return $line;\n}\n\nsub handle_serialized_line {\n    my $line = $_[0];\n\n    # handle .previous (only with regard to .section not .subsection)\n    if ($line =~ /\\.(section|text|const_data)/) {\n        push(@sections, $line);\n    } elsif ($line =~ /\\.previous/) {\n        if (!$sections[-2]) {\n            die \".previous without a previous section\";\n        }\n        $line = $sections[-2];\n        push(@sections, $line);\n    }\n\n    $thumb = 1 if $line =~ /\\.code\\s+16|\\.thumb/;\n    $thumb = 0 if $line =~ /\\.code\\s+32|\\.arm/;\n\n    # handle ldr <reg>, =<expr>\n    if ($line =~ /(.*)\\s*ldr([\\w\\s\\d]+)\\s*,\\s*=(.*)/ and $as_type ne \"armasm\") {\n        my $label = $literal_labels{$3};\n        if (!$label) {\n            $label = \"Literal_$literal_num\";\n            $literal_num++;\n            $literal_labels{$3} = $label;\n        }\n        $line = \"$1 ldr$2, $label\\n\";\n    } elsif ($line =~ /\\.ltorg/ and $as_type ne \"armasm\") {\n        $line .= \".align 2\\n\";\n        foreach my $literal (keys %literal_labels) {\n            $line .= \"$literal_labels{$literal}:\\n $literal_expr $literal\\n\";\n        }\n        %literal_labels = ();\n    }\n\n    # handle GNU as pc-relative relocations for adrp/add\n    if ($line =~ /(.*)\\s*adrp([\\w\\s\\d]+)\\s*,\\s*#?:pg_hi21:([^\\s]+)/ and $as_type =~ /^apple-/) {\n        $line = \"$1 adrp$2, ${3}\\@PAGE\\n\";\n    } elsif ($line =~ /(.*)\\s*add([\\w\\s\\d]+)\\s*,([\\w\\s\\d]+)\\s*,\\s*#?:lo12:([^\\s]+)/ and $as_type =~ /^apple-/) {\n        $line = \"$1 add$2, $3, ${4}\\@PAGEOFF\\n\";\n    }\n\n    # thumb add with large immediate needs explicit add.w\n    if ($thumb and $line =~ /add\\s+.*#([^@]+)/) {\n        $line =~ s/add/add.w/ if eval_expr($1) > 255;\n    }\n\n    # mach-o local symbol names start with L (no dot)\n    $line =~ s/(?<!\\w)\\.(L\\w+)/$1/g;\n\n    # recycle the '.func' directive for '.thumb_func'\n    if ($thumb and $as_type =~ /^apple-/) {\n        $line =~ s/\\.func/.thumb_func/x;\n    }\n\n    if ($thumb and $line =~ /^\\s*(\\w+)\\s*:/) {\n        $thumb_labels{$1}++;\n    }\n\n    if ($as_type =~ /^apple-/ and\n        $line =~ /^\\s*((\\w+\\s*:\\s*)?bl?x?(..)?(?:\\.w)?|\\.global)\\s+(\\w+)/) {\n        my $cond = $3;\n        my $label = $4;\n        # Don't interpret e.g. bic as b<cc> with ic as conditional code\n        if ($cond =~ /^(|$arm_cond_codes)$/) {\n            if (exists $thumb_labels{$label}) {\n                print ASMFILE \".thumb_func $label\\n\";\n            } else {\n                $call_targets{$label}++;\n            }\n        }\n    }\n\n    # @l -> lo16()  @ha -> ha16()\n    $line =~ s/,\\s+([^,]+)\\@l\\b/, lo16($1)/g;\n    $line =~ s/,\\s+([^,]+)\\@ha\\b/, ha16($1)/g;\n\n    # move to/from SPR\n    if ($line =~ /(\\s+)(m[ft])([a-z]+)\\s+(\\w+)/ and exists $ppc_spr{$3}) {\n        if ($2 eq 'mt') {\n            $line = \"$1${2}spr $ppc_spr{$3}, $4\\n\";\n        } else {\n            $line = \"$1${2}spr $4, $ppc_spr{$3}\\n\";\n        }\n    }\n\n    if ($line =~ /\\.unreq\\s+(.*)/) {\n        if (defined $neon_alias_reg{$1}) {\n            delete $neon_alias_reg{$1};\n            delete $neon_alias_type{$1};\n            return;\n        } elsif (defined $aarch64_req_alias{$1}) {\n            delete $aarch64_req_alias{$1};\n            return;\n        }\n    }\n    # old gas versions store upper and lower case names on .req,\n    # but they remove only one on .unreq\n    if ($fix_unreq) {\n        if ($line =~ /\\.unreq\\s+(.*)/) {\n            $line = \".unreq \" . lc($1) . \"\\n\";\n            $line .= \".unreq \" . uc($1) . \"\\n\";\n        }\n    }\n\n    if ($line =~ /(\\w+)\\s+\\.(dn|qn)\\s+(\\w+)(?:\\.(\\w+))?(\\[\\d+\\])?/) {\n        $neon_alias_reg{$1} = \"$3$5\";\n        $neon_alias_type{$1} = $4;\n        return;\n    }\n    if (scalar keys %neon_alias_reg > 0 && $line =~ /^\\s+v\\w+/) {\n        # This line seems to possibly have a neon instruction\n        foreach (keys %neon_alias_reg) {\n            my $alias = $_;\n            # Require the register alias to match as an invididual word, not as a substring\n            # of a larger word-token.\n            if ($line =~ /\\b$alias\\b/) {\n                $line =~ s/\\b$alias\\b/$neon_alias_reg{$alias}/g;\n                # Add the type suffix. If multiple aliases match on the same line,\n                # only do this replacement the first time (a vfoo.bar string won't match v\\w+).\n                $line =~ s/^(\\s+)(v\\w+)(\\s+)/$1$2.$neon_alias_type{$alias}$3/;\n            }\n        }\n    }\n\n    if ($arch eq \"aarch64\" or $as_type eq \"armasm\") {\n        # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq\n        if ($line =~ /\\b(\\w+)\\s+\\.req\\s+(\\w+)\\b/) {\n            $aarch64_req_alias{$1} = $2;\n            return;\n        }\n        foreach (keys %aarch64_req_alias) {\n            my $alias = $_;\n            # recursively resolve aliases\n            my $resolved = $aarch64_req_alias{$alias};\n            while (defined $aarch64_req_alias{$resolved}) {\n                $resolved = $aarch64_req_alias{$resolved};\n            }\n            $line =~ s/\\b$alias\\b/$resolved/g;\n        }\n    }\n    if ($arch eq \"aarch64\") {\n        # fix missing aarch64 instructions in Xcode 5.1 (beta3)\n        # mov with vector arguments is not supported, use alias orr instead\n        if ($line =~ /^(\\d+:)?\\s*mov\\s+(v\\d[\\.{}\\[\\]\\w]+),\\s*(v\\d[\\.{}\\[\\]\\w]+)\\b\\s*$/) {\n            $line = \"$1        orr $2, $3, $3\\n\";\n        }\n        # movi 16, 32 bit shifted variant, shift is optional\n        if ($line =~ /^(\\d+:)?\\s*movi\\s+(v[0-3]?\\d\\.(?:2|4|8)[hsHS])\\s*,\\s*(#\\w+)\\b\\s*$/) {\n            $line = \"$1        movi $2, $3, lsl #0\\n\";\n        }\n        # Xcode 5 misses the alias uxtl. Replace it with the more general ushll.\n        # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll.\n        # armasm64 also misses these instructions.\n        if ($line =~ /^(\\d+:)?\\s*(s|u)xtl(2)?\\s+(v[0-3]?\\d\\.[248][hsdHSD])\\s*,\\s*(v[0-3]?\\d\\.(?:2|4|8|16)[bhsBHS])\\b\\s*$/) {\n            $line = \"$1        $2shll$3 $4, $5, #0\\n\";\n        }\n        # clang 3.4 and armasm64 do not automatically use shifted immediates in add/sub\n        if (($as_type eq \"clang\" or $as_type eq \"armasm\") and\n            $line =~ /^(\\d+:)?(\\s*(?:add|sub)s?) ([^#l]+)#([\\d\\+\\-\\*\\/ <>]+)\\s*$/) {\n            my $imm = eval $4;\n            if ($imm > 4095 and not ($imm & 4095)) {\n                $line = \"$1 $2 $3#\" . ($imm >> 12) . \", lsl #12\\n\";\n            }\n        }\n        if ($ENV{GASPP_FIX_XCODE5}) {\n            if ($line =~ /^\\s*bsl\\b/) {\n                $line =~ s/\\b(bsl)(\\s+v[0-3]?\\d\\.(\\w+))\\b/$1.$3$2/;\n                $line =~ s/\\b(v[0-3]?\\d)\\.$3\\b/$1/g;\n            }\n            if ($line =~ /^\\s*saddl2?\\b/) {\n                $line =~ s/\\b(saddl2?)(\\s+v[0-3]?\\d\\.(\\w+))\\b/$1.$3$2/;\n                $line =~ s/\\b(v[0-3]?\\d)\\.\\w+\\b/$1/g;\n            }\n            if ($line =~ /^\\s*dup\\b.*\\]$/) {\n                $line =~ s/\\bdup(\\s+v[0-3]?\\d)\\.(\\w+)\\b/dup.$2$1/g;\n                $line =~ s/\\b(v[0-3]?\\d)\\.[bhsdBHSD](\\[\\d\\])$/$1$2/g;\n            }\n        }\n    }\n\n    if ($as_type eq \"armasm\") {\n        # Also replace variables set by .set\n        foreach (keys %symbols) {\n            my $sym = $_;\n            $line =~ s/\\b$sym\\b/$symbols{$sym}/g;\n        }\n\n        # Handle function declarations and keep track of the declared labels\n        if ($line =~ s/^\\s*\\.func\\s+(\\w+)/$1 PROC/) {\n            $labels_seen{$1} = 1;\n        }\n\n        if ($line =~ s/^\\s*(\\d+)://) {\n            # Convert local labels into unique labels. armasm (at least in\n            # RVCT) has something similar, but still different enough.\n            # By converting to unique labels we avoid any possible\n            # incompatibilities.\n\n            my $num = $1;\n            foreach (@{$next_temp_labels{$num}}) {\n                $line = \"$_\\n\" . $line;\n            }\n            @next_temp_labels{$num} = ();\n            my $name = \"temp_label_$temp_label_next\";\n            $temp_label_next++;\n            # The matching regexp above removes the label from the start of\n            # the line (which might contain an instruction as well), readd\n            # it on a separate line above it.\n            $line = \"$name:\\n\" . $line;\n            $last_temp_labels{$num} = $name;\n        }\n\n        if ($line =~ s/^\\s*(\\w+):/$1/) {\n            # Skip labels that have already been declared with a PROC,\n            # labels must not be declared multiple times.\n            return if (defined $labels_seen{$1});\n            $labels_seen{$1} = 1;\n        } elsif ($line !~ /(\\w+) PROC/) {\n            # If not a label, make sure the line starts with whitespace,\n            # otherwise ms armasm interprets it incorrectly.\n            $line =~ s/^[\\.\\w]/\\t$&/;\n        }\n\n\n        # Check branch instructions\n        if ($line =~ /(?:^|\\n)\\s*(\\w+\\s*:\\s*)?(bl?x?\\.?([^\\s]{2})?(\\.w)?)\\s+(\\w+)/) {\n            my $instr = $2;\n            my $cond = $3;\n            my $width = $4;\n            my $target = $5;\n            # Don't interpret e.g. bic as b<cc> with ic as conditional code\n            if ($cond !~ /^(|$arm_cond_codes)$/) {\n                # Not actually a branch\n            } elsif ($target =~ /^(\\d+)([bf])$/) {\n                # The target is a local label\n                $line = handle_local_label($line, $1, $2);\n                $line =~ s/\\b$instr\\b/$&.w/ if $width eq \"\" and $arch eq \"arm\";\n            } elsif (($arch eq \"arm\" and !is_arm_register($target)) or\n                     ($arch eq \"aarch64\" and !is_aarch64_register($target))) {\n                $call_targets{$target}++;\n            }\n        } elsif ($line =~ /(?:^|\\n)\\s*(\\w+\\s*:\\s*)?(cbn?z|adr|tbn?z)\\s+(\\w+)\\s*,(\\s*#\\d+\\s*,)?\\s*(\\w+)/) {\n            my $instr = $2;\n            my $reg = $3;\n            my $bit = $4;\n            my $target = $5;\n            if ($target =~ /^(\\d+)([bf])$/) {\n                # The target is a local label\n                $line = handle_local_label($line, $1, $2);\n            } else {\n                $call_targets{$target}++;\n            }\n            # Convert tbz with a wX register into an xX register,\n            # due to armasm64 bugs/limitations.\n            if (($instr eq \"tbz\" or $instr eq \"tbnz\") and $reg =~ /w\\d+/) {\n                my $xreg = $reg;\n                $xreg =~ s/w/x/;\n                $line =~ s/\\b$reg\\b/$xreg/;\n            }\n        } elsif ($line =~ /^\\s*.h?word.*\\b\\d+[bf]\\b/) {\n            while ($line =~ /\\b(\\d+)([bf])\\b/g) {\n                $line = handle_local_label($line, $1, $2);\n            }\n        }\n\n        # ALIGN in armasm syntax is the actual number of bytes\n        if ($line =~ /\\.(?:p2)?align\\s+(\\d+)/) {\n            my $align = 1 << $1;\n            $line =~ s/\\.(?:p2)?align\\s+(\\d+)/ALIGN $align/;\n        }\n        # Convert gas style [r0, :128] into armasm [r0@128] alignment specification\n        $line =~ s/\\[([^\\[,]+),?\\s*:(\\d+)\\]/[$1\\@$2]/g;\n\n        # armasm treats logical values {TRUE} and {FALSE} separately from\n        # numeric values - logical operators and values can't be intermixed\n        # with numerical values. Evaluate !<number> and (a <> b) into numbers,\n        # let the assembler evaluate the rest of the expressions. This current\n        # only works for cases when ! and <> are used with actual constant numbers,\n        # we don't evaluate subexpressions here.\n\n        # Evaluate !<number>\n        while ($line =~ /!\\s*(\\d+)/g) {\n            my $val = ($1 != 0) ? 0 : 1;\n            $line =~ s/!(\\d+)/$val/;\n        }\n        # Evaluate (a > b)\n        while ($line =~ /\\(\\s*(\\d+)\\s*([<>])\\s*(\\d+)\\s*\\)/) {\n            my $val;\n            if ($2 eq \"<\") {\n                $val = ($1 < $3) ? 1 : 0;\n            } else {\n                $val = ($1 > $3) ? 1 : 0;\n            }\n            $line =~ s/\\(\\s*(\\d+)\\s*([<>])\\s*(\\d+)\\s*\\)/$val/;\n        }\n\n        if ($arch eq \"arm\") {\n            # Change a movw... #:lower16: into a mov32 pseudoinstruction\n            $line =~ s/^(\\s*)movw(\\s+\\w+\\s*,\\s*)\\#:lower16:(.*)$/$1mov32$2$3/;\n            # and remove the following, matching movt completely\n            $line =~ s/^\\s*movt\\s+\\w+\\s*,\\s*\\#:upper16:.*$//;\n\n            if ($line =~ /^\\s*mov32\\s+\\w+,\\s*([a-zA-Z]\\w*)/) {\n                $import_symbols{$1}++;\n            }\n\n            # Misc bugs/deficiencies:\n            # armasm seems unable to parse e.g. \"vmov s0, s1\" without a type\n            # qualifier, thus add .f32.\n            $line =~ s/^(\\s+(?:vmov|vadd))(\\s+s\\d+\\s*,\\s*s\\d+)/$1.f32$2/;\n        } elsif ($arch eq \"aarch64\") {\n            # Convert ext into ext8; armasm64 seems to require it named as ext8.\n            $line =~ s/^(\\s+)ext(\\s+)/$1ext8$2/;\n\n            # Pick up targets from ldr x0, =sym+offset\n            if ($line =~ /^\\s*ldr\\s+(\\w+)\\s*,\\s*=([a-zA-Z]\\w*)(.*)$/) {\n                my $reg = $1;\n                my $sym = $2;\n                my $offset = eval_expr($3);\n                if ($offset < 0 and $ENV{GASPP_ARMASM64_SKIP_NEG_OFFSET}) {\n                    # armasm64 in VS < 15.6 is buggy with ldr x0, =sym+offset where the\n                    # offset is a negative value; it does write a negative\n                    # offset into the literal pool as it should, but the\n                    # negative offset only covers the lower 32 bit of the 64\n                    # bit literal/relocation.\n                    # Thus remove the offset and apply it manually with a sub\n                    # afterwards.\n                    $offset = -$offset;\n                    $line = \"\\tldr $reg, =$sym\\n\\tsub $reg, $reg, #$offset\\n\";\n                }\n                $import_symbols{$sym}++;\n            }\n\n            # armasm64 (currently) doesn't support offsets on adrp targets,\n            # even though the COFF format relocations (and the linker)\n            # supports it. Therefore strip out the offsets from adrp and\n            # add :lo12: (in case future armasm64 would start handling it)\n            # and add an extra explicit add instruction for the offset.\n            if ($line =~ s/(adrp\\s+\\w+\\s*,\\s*(\\w+))([\\d\\+\\-\\*\\/\\(\\) <>]+)?/\\1/) {\n                $import_symbols{$2}++;\n            }\n            if ($line =~ s/(add\\s+(\\w+)\\s*,\\s*\\w+\\s*,\\s*):lo12:(\\w+)([\\d\\+\\-\\*\\/\\(\\) <>]+)?/\\1\\3/) {\n                my $reg = $2;\n                my $sym = $3;\n                my $offset = eval_expr($4);\n                $line .= \"\\tadd $reg, $reg, #$offset\\n\" if $offset > 0;\n                $import_symbols{$sym}++;\n            }\n\n            # Convert e.g. \"add x0, x0, w0, uxtw\" into \"add x0, x0, w0, uxtw #0\",\n            # or \"ldr x0, [x0, w0, uxtw]\" into \"ldr x0, [x0, w0, uxtw #0]\".\n            $line =~ s/(uxt[whb]|sxt[whb])(\\s*\\]?\\s*)$/\\1 #0\\2/i;\n\n            # Convert \"mov x0, v0.d[0]\" into \"umov x0, v0.d[0]\"\n            $line =~ s/\\bmov\\s+[xw]\\d+\\s*,\\s*v\\d+\\.[ds]/u$&/i;\n\n            # Convert \"ccmp w0, #0, #0, ne\" into \"ccmpne w0, #0, #0\",\n            # and \"csel w0, w0, w0, ne\" into \"cselne w0, w0, w0\".\n            $line =~ s/(ccmp|csel)\\s+([xw]\\w+)\\s*,\\s*([xw#]\\w+)\\s*,\\s*([xw#]\\w+)\\s*,\\s*($arm_cond_codes)/\\1\\5 \\2, \\3, \\4/;\n\n            # Convert \"cinc w0, w0, ne\" into \"cincne w0, w0\".\n            $line =~ s/(cinc)\\s+([xw]\\w+)\\s*,\\s*([xw]\\w+)\\s*,\\s*($arm_cond_codes)/\\1\\4 \\2, \\3/;\n\n            # Convert \"cset w0, lo\" into \"csetlo w0\"\n            $line =~ s/(cset)\\s+([xw]\\w+)\\s*,\\s*($arm_cond_codes)/\\1\\3 \\2/;\n\n            if ($ENV{GASPP_ARMASM64_SKIP_PRFUM}) {\n                # Strip out prfum; armasm64 (VS < 15.5) fails to assemble any\n                # variant/combination of prfum tested so far, but since it is\n                # a prefetch instruction it can be skipped without changing\n                # results.\n                $line =~ s/prfum.*\\]//;\n            }\n\n            # Convert \"ldrb w0, [x0, #-1]\" into \"ldurb w0, [x0, #-1]\".\n            # Don't do this for forms with writeback though.\n            if ($line =~ /(ld|st)(r[bh]?)\\s+(\\w+)\\s*,\\s*\\[\\s*(\\w+)\\s*,\\s*#([^\\]]+)\\s*\\][^!]/) {\n                my $instr = $1;\n                my $suffix = $2;\n                my $target = $3;\n                my $base = $4;\n                my $offset = eval_expr($5);\n                if ($offset < 0) {\n                    $line =~ s/$instr$suffix/${instr}u$suffix/;\n                }\n            }\n\n            if ($ENV{GASPP_ARMASM64_INVERT_SCALE}) {\n                # Instructions like fcvtzs and scvtf store the scale value\n                # inverted in the opcode (stored as 64 - scale), but armasm64\n                # in VS < 15.5 stores it as-is. Thus convert from\n                # \"fcvtzs w0, s0, #8\" into \"fcvtzs w0, s0, #56\".\n                if ($line =~ /(?:fcvtzs|scvtf)\\s+(\\w+)\\s*,\\s*(\\w+)\\s*,\\s*#(\\d+)/) {\n                    my $scale = $3;\n                    my $inverted_scale = 64 - $3;\n                    $line =~ s/#$scale/#$inverted_scale/;\n                }\n            }\n\n            # Convert \"ld1 {v0.4h-v3.4h}\" into \"ld1 {v0.4h,v1.4h,v2.4h,v3.4h}\"\n            if ($line =~ /(\\{\\s*v(\\d+)\\.(\\d+[bhsdBHSD])\\s*-\\s*v(\\d+)\\.(\\d+[bhsdBHSD])\\s*\\})/) {\n                my $regspec = $1;\n                my $reg1 = $2;\n                my $layout1 = $3;\n                my $reg2 = $4;\n                my $layout2 = $5;\n                if ($layout1 eq $layout2) {\n                    my $new_regspec = \"{\";\n                    foreach my $i ($reg1 .. $reg2) {\n                        $new_regspec .= \",\" if ($i > $reg1);\n                        $new_regspec .= \"v$i.$layout1\";\n                    }\n                    $new_regspec .= \"}\";\n                    $line =~ s/$regspec/$new_regspec/;\n                }\n            }\n        }\n        # armasm is unable to parse &0x - add spacing\n        $line =~ s/&0x/& 0x/g;\n    }\n\n    if ($force_thumb) {\n        # Convert register post indexing to a separate add instruction.\n        # This converts e.g. \"ldr r0, [r1], r2\" into \"ldr r0, [r1]\",\n        # \"add r1, r1, r2\".\n        $line =~ s/((?:ldr|str)[bh]?)\\s+(\\w+),\\s*\\[(\\w+)\\],\\s*(\\w+)/$1 $2, [$3]\\n\\tadd $3, $3, $4/g;\n\n        # Convert \"mov pc, lr\" into \"bx lr\", since the former only works\n        # for switching from arm to thumb (and only in armv7), but not\n        # from thumb to arm.\n        $line =~ s/mov\\s*pc\\s*,\\s*lr/bx lr/g;\n\n        # Convert stmdb/ldmia/stmfd/ldmfd/ldm with only one register into a plain str/ldr with post-increment/decrement.\n        # Wide thumb2 encoding requires at least two registers in register list while all other encodings support one register too.\n        $line =~ s/stm(?:db|fd)\\s+sp!\\s*,\\s*\\{([^,-]+)\\}/str $1, [sp, #-4]!/g;\n        $line =~ s/ldm(?:ia|fd)?\\s+sp!\\s*,\\s*\\{([^,-]+)\\}/ldr $1, [sp], #4/g;\n\n        # Convert muls into mul+cmp\n        $line =~ s/muls\\s+(\\w+),\\s*(\\w+)\\,\\s*(\\w+)/mul $1, $2, $3\\n\\tcmp $1, #0/g;\n\n        # Convert \"and r0, sp, #xx\" into \"mov r0, sp\", \"and r0, r0, #xx\"\n        $line =~ s/and\\s+(\\w+),\\s*(sp|r13)\\,\\s*#(\\w+)/mov $1, $2\\n\\tand $1, $1, #$3/g;\n\n        # Convert \"ldr r0, [r0, r1, lsl #6]\" where the shift is >3 (which\n        # can't be handled in thumb) into \"add r0, r0, r1, lsl #6\",\n        # \"ldr r0, [r0]\", for the special case where the same address is\n        # used as base and target for the ldr.\n        if ($line =~ /(ldr[bh]?)\\s+(\\w+),\\s*\\[\\2,\\s*(\\w+),\\s*lsl\\s*#(\\w+)\\]/ and $4 > 3) {\n            $line =~ s/(ldr[bh]?)\\s+(\\w+),\\s*\\[\\2,\\s*(\\w+),\\s*lsl\\s*#(\\w+)\\]/add $2, $2, $3, lsl #$4\\n\\t$1 $2, [$2]/;\n        }\n\n        $line =~ s/\\.arm/.thumb/x;\n    }\n\n    # comment out unsupported directives\n    $line =~ s/\\.type/$comm$&/x        if $as_type =~ /^(apple-|armasm)/;\n    $line =~ s/\\.func/$comm$&/x        if $as_type =~ /^(apple-|clang)/;\n    $line =~ s/\\.endfunc/$comm$&/x     if $as_type =~ /^(apple-|clang)/;\n    $line =~ s/\\.endfunc/ENDP/x        if $as_type =~ /armasm/;\n    $line =~ s/\\.ltorg/$comm$&/x       if $as_type =~ /^(apple-|clang)/;\n    $line =~ s/\\.ltorg/LTORG/x         if $as_type eq \"armasm\";\n    $line =~ s/\\.size/$comm$&/x        if $as_type =~ /^(apple-|armasm)/;\n    $line =~ s/\\.fpu/$comm$&/x         if $as_type =~ /^(apple-|armasm)/;\n    $line =~ s/\\.arch/$comm$&/x        if $as_type =~ /^(apple-|clang|armasm)/;\n    $line =~ s/\\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/;\n    $line =~ s/.section\\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/;\n\n    $line =~ s/\\.syntax/$comm$&/x      if $as_type =~ /armasm/;\n\n    $line =~ s/\\.hword/.short/x;\n\n    if ($as_type =~ /^apple-/) {\n        # the syntax for these is a little different\n        $line =~ s/\\.global/.globl/x;\n        # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const\n        $line =~ s/(.*)\\.rodata/.const_data/x;\n        $line =~ s/\\.int/.long/x;\n        $line =~ s/\\.float/.single/x;\n    }\n    if ($as_type eq \"apple-gas\") {\n        $line =~ s/vmrs\\s+APSR_nzcv/fmrx r15/x;\n    }\n    if ($as_type eq \"armasm\") {\n        $line =~ s/\\.global/EXPORT/x;\n        $line =~ s/\\.extern/IMPORT/x;\n        $line =~ s/\\.int/dcd/x;\n        $line =~ s/\\.long/dcd/x;\n        $line =~ s/\\.float/dcfs/x;\n        $line =~ s/\\.word/dcd/x;\n        $line =~ s/\\.short/dcw/x;\n        $line =~ s/\\.byte/dcb/x;\n        $line =~ s/\\.quad/dcq/x;\n        $line =~ s/\\.ascii/dcb/x;\n        $line =~ s/\\.asciz(.*)$/dcb\\1,0/x;\n        $line =~ s/\\.thumb/THUMB/x;\n        $line =~ s/\\.arm/ARM/x;\n        # The alignment in AREA is the power of two, just as .align in gas\n        $line =~ s/\\.text/AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN/;\n        $line =~ s/(\\s*)(.*)\\.ro?data(\\s*,\\s*\"\\w+\")?/$1AREA |.rdata|, DATA, READONLY, ALIGN=5/;\n        $line =~ s/\\.data/AREA |.data|, DATA, ALIGN=5/;\n    }\n    if ($as_type eq \"armasm\" and $arch eq \"arm\") {\n        $line =~ s/fmxr/vmsr/;\n        $line =~ s/fmrx/vmrs/;\n        $line =~ s/fadds/vadd.f32/;\n        # Armasm in VS 2019 16.3 errors out on \"it\" instructions. But\n        # armasm implicitly adds the necessary it instructions anyway, so we\n        # can just filter them out.\n        $line =~ s/^\\s*it[te]*\\s+/$comm$&/;\n    }\n    if ($as_type eq \"armasm\" and $arch eq \"aarch64\") {\n        # Convert \"b.eq\" into \"beq\"\n        $line =~ s/\\bb\\.($arm_cond_codes)\\b/b\\1/;\n    }\n\n    # catch unknown section names that aren't mach-o style (with a comma)\n    if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) {\n        die \".section $1 unsupported; figure out the mach-o section name and add it\";\n    }\n\n    print ASMFILE $line;\n}\n\nif ($as_type ne \"armasm\") {\n    print ASMFILE \".text\\n\";\n    print ASMFILE \".align 2\\n\";\n    foreach my $literal (keys %literal_labels) {\n        print ASMFILE \"$literal_labels{$literal}:\\n $literal_expr $literal\\n\";\n    }\n\n    map print(ASMFILE \".thumb_func $_\\n\"),\n        grep exists $thumb_labels{$_}, keys %call_targets;\n} else {\n    map print(ASMFILE \"\\tIMPORT $_\\n\"),\n        grep ! exists $labels_seen{$_}, (keys %call_targets, keys %import_symbols);\n\n    print ASMFILE \"\\tEND\\n\";\n}\n\nclose(INPUT) or exit 1;\nclose(ASMFILE) or exit 1;\nif ($as_type eq \"armasm\" and ! defined $ENV{GASPP_DEBUG}) {\n    print STDERR join(\" \", @gcc_cmd).\"\\n\" if $verbose;\n    system(@gcc_cmd) == 0 or die \"Error running assembler\";\n}\n\nEND {\n    unlink($tempfile) if defined $tempfile;\n}\n#exit 1\n"
  },
  {
    "path": "xmake/scripts/gitignore",
    "content": "# Xmake cache\n.xmake/\nbuild/\n\n# MacOS Cache\n.DS_Store\n\n\n"
  },
  {
    "path": "xmake/scripts/module/luawrap/lauxlib.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        luaxlib.h\n *\n */\n#ifndef XMI_LUAXLIB_H\n#define XMI_LUAXLIB_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmi.h\"\n\n#endif\n\n\n"
  },
  {
    "path": "xmake/scripts/module/luawrap/lua.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        lua.h\n *\n */\n#ifndef XMI_LUA_H\n#define XMI_LUA_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include \"xmi.h\"\n\n#endif\n\n\n"
  },
  {
    "path": "xmake/scripts/module/luawrap/luaconf.h",
    "content": "/*\n** $Id: luaconf.h $\n** Configuration file for Lua\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef luaconf_h\n#define luaconf_h\n\n#include <limits.h>\n#include <stddef.h>\n\n\n/*\n** ===================================================================\n** General Configuration File for Lua\n**\n** Some definitions here can be changed externally, through the compiler\n** (e.g., with '-D' options): They are commented out or protected\n** by '#if !defined' guards. However, several other definitions\n** should be changed directly here, either because they affect the\n** Lua ABI (by making the changes here, you ensure that all software\n** connected to Lua, such as C libraries, will be compiled with the same\n** configuration); or because they are seldom changed.\n**\n** Search for \"@@\" to find all configurable definitions.\n** ===================================================================\n*/\n\n\n/*\n** {====================================================================\n** System Configuration: macros to adapt (if needed) Lua to some\n** particular platform, for instance restricting it to C89.\n** =====================================================================\n*/\n\n/*\n@@ LUA_USE_C89 controls the use of non-ISO-C89 features.\n** Define it if you want Lua to avoid the use of a few C99 features\n** or Windows-specific features on Windows.\n*/\n/* #define LUA_USE_C89 */\n\n\n/*\n** By default, Lua on Windows use (some) specific Windows features\n*/\n#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)\n#define LUA_USE_WINDOWS  /* enable goodies for regular Windows */\n#endif\n\n\n#if defined(LUA_USE_WINDOWS)\n#define LUA_DL_DLL\t/* enable support for DLL */\n#define LUA_USE_C89\t/* broadly, Windows is C89 */\n#endif\n\n\n#if defined(LUA_USE_LINUX)\n#define LUA_USE_POSIX\n#define LUA_USE_DLOPEN\t\t/* needs an extra library: -ldl */\n#endif\n\n\n#if defined(LUA_USE_MACOSX)\n#define LUA_USE_POSIX\n#define LUA_USE_DLOPEN\t\t/* MacOS does not need -ldl */\n#endif\n\n\n/*\n@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.\n*/\n#define LUAI_IS32INT\t((UINT_MAX >> 30) >= 3)\n\n/* }================================================================== */\n\n\n\n/*\n** {==================================================================\n** Configuration for Number types. These options should not be\n** set externally, because any other code connected to Lua must\n** use the same configuration.\n** ===================================================================\n*/\n\n/*\n@@ LUA_INT_TYPE defines the type for Lua integers.\n@@ LUA_FLOAT_TYPE defines the type for Lua floats.\n** Lua should work fine with any mix of these options supported\n** by your C compiler. The usual configurations are 64-bit integers\n** and 'double' (the default), 32-bit integers and 'float' (for\n** restricted platforms), and 'long'/'double' (for C compilers not\n** compliant with C99, which may not have support for 'long long').\n*/\n\n/* predefined options for LUA_INT_TYPE */\n#define LUA_INT_INT\t\t1\n#define LUA_INT_LONG\t\t2\n#define LUA_INT_LONGLONG\t3\n\n/* predefined options for LUA_FLOAT_TYPE */\n#define LUA_FLOAT_FLOAT\t\t1\n#define LUA_FLOAT_DOUBLE\t2\n#define LUA_FLOAT_LONGDOUBLE\t3\n\n\n/* Default configuration ('long long' and 'double', for 64-bit Lua) */\n#define LUA_INT_DEFAULT\t\tLUA_INT_LONGLONG\n#define LUA_FLOAT_DEFAULT\tLUA_FLOAT_DOUBLE\n\n\n/*\n@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.\n*/\n#define LUA_32BITS\t0\n\n\n/*\n@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for\n** C89 ('long' and 'double'); Windows always has '__int64', so it does\n** not need to use this case.\n*/\n#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)\n#define LUA_C89_NUMBERS\t\t1\n#else\n#define LUA_C89_NUMBERS\t\t0\n#endif\n\n\n#if LUA_32BITS\t\t/* { */\n/*\n** 32-bit integers and 'float'\n*/\n#if LUAI_IS32INT  /* use 'int' if big enough */\n#define LUA_INT_TYPE\tLUA_INT_INT\n#else  /* otherwise use 'long' */\n#define LUA_INT_TYPE\tLUA_INT_LONG\n#endif\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_FLOAT\n\n#elif LUA_C89_NUMBERS\t/* }{ */\n/*\n** largest types available for C89 ('long' and 'double')\n*/\n#define LUA_INT_TYPE\tLUA_INT_LONG\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_DOUBLE\n\n#else\t\t/* }{ */\n/* use defaults */\n\n#define LUA_INT_TYPE\tLUA_INT_DEFAULT\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_DEFAULT\n\n#endif\t\t\t\t/* } */\n\n\n/* }================================================================== */\n\n\n\n/*\n** {==================================================================\n** Configuration for Paths.\n** ===================================================================\n*/\n\n/*\n** LUA_PATH_SEP is the character that separates templates in a path.\n** LUA_PATH_MARK is the string that marks the substitution points in a\n** template.\n** LUA_EXEC_DIR in a Windows path is replaced by the executable's\n** directory.\n*/\n#define LUA_PATH_SEP            \";\"\n#define LUA_PATH_MARK           \"?\"\n#define LUA_EXEC_DIR            \"!\"\n\n\n/*\n@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for\n** Lua libraries.\n@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for\n** C libraries.\n** CHANGE them if your machine has a non-conventional directory\n** hierarchy or if you want to install your libraries in\n** non-conventional directories.\n*/\n\n#define LUA_VDIR\tLUA_VERSION_MAJOR \".\" LUA_VERSION_MINOR\n#if defined(_WIN32)\t/* { */\n/*\n** In Windows, any exclamation mark ('!') in the path is replaced by the\n** path of the directory of the executable file of the current process.\n*/\n#define LUA_LDIR\t\"!\\\\lua\\\\\"\n#define LUA_CDIR\t\"!\\\\\"\n#define LUA_SHRDIR\t\"!\\\\..\\\\share\\\\lua\\\\\" LUA_VDIR \"\\\\\"\n\n#if !defined(LUA_PATH_DEFAULT)\n#define LUA_PATH_DEFAULT  \\\n\t\tLUA_LDIR\"?.lua;\"  LUA_LDIR\"?\\\\init.lua;\" \\\n\t\tLUA_CDIR\"?.lua;\"  LUA_CDIR\"?\\\\init.lua;\" \\\n\t\tLUA_SHRDIR\"?.lua;\" LUA_SHRDIR\"?\\\\init.lua;\" \\\n\t\t\".\\\\?.lua;\" \".\\\\?\\\\init.lua\"\n#endif\n\n#if !defined(LUA_CPATH_DEFAULT)\n#define LUA_CPATH_DEFAULT \\\n\t\tLUA_CDIR\"?.dll;\" \\\n\t\tLUA_CDIR\"..\\\\lib\\\\lua\\\\\" LUA_VDIR \"\\\\?.dll;\" \\\n\t\tLUA_CDIR\"loadall.dll;\" \".\\\\?.dll\"\n#endif\n\n#else\t\t\t/* }{ */\n\n#define LUA_ROOT\t\"/usr/local/\"\n#define LUA_LDIR\tLUA_ROOT \"share/lua/\" LUA_VDIR \"/\"\n#define LUA_CDIR\tLUA_ROOT \"lib/lua/\" LUA_VDIR \"/\"\n\n#if !defined(LUA_PATH_DEFAULT)\n#define LUA_PATH_DEFAULT  \\\n\t\tLUA_LDIR\"?.lua;\"  LUA_LDIR\"?/init.lua;\" \\\n\t\tLUA_CDIR\"?.lua;\"  LUA_CDIR\"?/init.lua;\" \\\n\t\t\"./?.lua;\" \"./?/init.lua\"\n#endif\n\n#if !defined(LUA_CPATH_DEFAULT)\n#define LUA_CPATH_DEFAULT \\\n\t\tLUA_CDIR\"?.so;\" LUA_CDIR\"loadall.so;\" \"./?.so\"\n#endif\n\n#endif\t\t\t/* } */\n\n\n/*\n@@ LUA_DIRSEP is the directory separator (for submodules).\n** CHANGE it if your machine does not use \"/\" as the directory separator\n** and is not Windows. (On Windows Lua automatically uses \"\\\".)\n*/\n#if !defined(LUA_DIRSEP)\n\n#if defined(_WIN32)\n#define LUA_DIRSEP\t\"\\\\\"\n#else\n#define LUA_DIRSEP\t\"/\"\n#endif\n\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Marks for exported symbols in the C code\n** ===================================================================\n*/\n\n/*\n@@ LUA_API is a mark for all core API functions.\n@@ LUALIB_API is a mark for all auxiliary library functions.\n@@ LUAMOD_API is a mark for all standard library opening functions.\n** CHANGE them if you need to define those functions in some special way.\n** For instance, if you want to create one Windows DLL with the core and\n** the libraries, you may want to use the following definition (define\n** LUA_BUILD_AS_DLL to get it).\n*/\n#if defined(LUA_BUILD_AS_DLL)\t/* { */\n\n#if defined(LUA_CORE) || defined(LUA_LIB)\t/* { */\n#define LUA_API __declspec(dllexport)\n#else\t\t\t\t\t\t/* }{ */\n#define LUA_API __declspec(dllimport)\n#endif\t\t\t\t\t\t/* } */\n\n#else\t\t\t\t/* }{ */\n\n#define LUA_API\t\textern\n\n#endif\t\t\t\t/* } */\n\n\n/*\n** More often than not the libs go together with the core.\n*/\n#define LUALIB_API\tLUA_API\n#define LUAMOD_API\tLUA_API\n\n\n/*\n@@ LUAI_FUNC is a mark for all extern functions that are not to be\n** exported to outside modules.\n@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,\n** none of which to be exported to outside modules (LUAI_DDEF for\n** definitions and LUAI_DDEC for declarations).\n** CHANGE them if you need to mark them in some special way. Elf/gcc\n** (versions 3.2 and later) mark them as \"hidden\" to optimize access\n** when Lua is compiled as a shared library. Not all elf targets support\n** this attribute. Unfortunately, gcc does not offer a way to check\n** whether the target offers that support, and those without support\n** give a warning about it. To avoid these warnings, change to the\n** default definition.\n*/\n#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \\\n    defined(__ELF__)\t\t/* { */\n#define LUAI_FUNC\t__attribute__((visibility(\"internal\"))) extern\n#else\t\t\t\t/* }{ */\n#define LUAI_FUNC\textern\n#endif\t\t\t\t/* } */\n\n#define LUAI_DDEC(dec)\tLUAI_FUNC dec\n#define LUAI_DDEF\t/* empty */\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Compatibility with previous versions\n** ===================================================================\n*/\n\n/*\n@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3.\n** You can define it to get all options, or change specific options\n** to fit your specific needs.\n*/\n#if defined(LUA_COMPAT_5_3)\t/* { */\n\n/*\n@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated\n** functions in the mathematical library.\n** (These functions were already officially removed in 5.3;\n** nevertheless they are still available here.)\n*/\n#define LUA_COMPAT_MATHLIB\n\n/*\n@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for\n** manipulating other integer types (lua_pushunsigned, lua_tounsigned,\n** luaL_checkint, luaL_checklong, etc.)\n** (These macros were also officially removed in 5.3, but they are still\n** available here.)\n*/\n#define LUA_COMPAT_APIINTCASTS\n\n\n/*\n@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod\n** using '__lt'.\n*/\n#define LUA_COMPAT_LT_LE\n\n\n/*\n@@ The following macros supply trivial compatibility for some\n** changes in the API. The macros themselves document how to\n** change your code to avoid using them.\n** (Once more, these macros were officially removed in 5.3, but they are\n** still available here.)\n*/\n#define lua_strlen(L,i)\t\tlua_rawlen(L, (i))\n\n#define lua_objlen(L,i)\t\tlua_rawlen(L, (i))\n\n#define lua_equal(L,idx1,idx2)\t\tlua_compare(L,(idx1),(idx2),LUA_OPEQ)\n#define lua_lessthan(L,idx1,idx2)\tlua_compare(L,(idx1),(idx2),LUA_OPLT)\n\n#endif\t\t\t\t/* } */\n\n/* }================================================================== */\n\n\n\n/*\n** {==================================================================\n** Configuration for Numbers (low-level part).\n** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*\n** satisfy your needs.\n** ===================================================================\n*/\n\n/*\n@@ LUAI_UACNUMBER is the result of a 'default argument promotion'\n@@ over a floating number.\n@@ l_floatatt(x) corrects float attribute 'x' to the proper float type\n** by prefixing it with one of FLT/DBL/LDBL.\n@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.\n@@ LUA_NUMBER_FMT is the format for writing floats.\n@@ lua_number2str converts a float to a string.\n@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.\n@@ l_floor takes the floor of a float.\n@@ lua_str2number converts a decimal numeral to a number.\n*/\n\n\n/* The following definitions are good for most cases here */\n\n#define l_floor(x)\t\t(l_mathop(floor)(x))\n\n#define lua_number2str(s,sz,n)  \\\n\tl_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))\n\n/*\n@@ lua_numbertointeger converts a float number with an integral value\n** to an integer, or returns 0 if float is not within the range of\n** a lua_Integer.  (The range comparisons are tricky because of\n** rounding. The tests here assume a two-complement representation,\n** where MININTEGER always has an exact representation as a float;\n** MAXINTEGER may not have one, and therefore its conversion to float\n** may have an ill-defined value.)\n*/\n#define lua_numbertointeger(n,p) \\\n  ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \\\n   (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \\\n      (*(p) = (LUA_INTEGER)(n), 1))\n\n\n/* now the variable definitions */\n\n#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT\t\t/* { single float */\n\n#define LUA_NUMBER\tfloat\n\n#define l_floatatt(n)\t\t(FLT_##n)\n\n#define LUAI_UACNUMBER\tdouble\n\n#define LUA_NUMBER_FRMLEN\t\"\"\n#define LUA_NUMBER_FMT\t\t\"%.7g\"\n\n#define l_mathop(op)\t\top##f\n\n#define lua_str2number(s,p)\tstrtof((s), (p))\n\n\n#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE\t/* }{ long double */\n\n#define LUA_NUMBER\tlong double\n\n#define l_floatatt(n)\t\t(LDBL_##n)\n\n#define LUAI_UACNUMBER\tlong double\n\n#define LUA_NUMBER_FRMLEN\t\"L\"\n#define LUA_NUMBER_FMT\t\t\"%.19Lg\"\n\n#define l_mathop(op)\t\top##l\n\n#define lua_str2number(s,p)\tstrtold((s), (p))\n\n#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE\t/* }{ double */\n\n#define LUA_NUMBER\tdouble\n\n#define l_floatatt(n)\t\t(DBL_##n)\n\n#define LUAI_UACNUMBER\tdouble\n\n#define LUA_NUMBER_FRMLEN\t\"\"\n#define LUA_NUMBER_FMT\t\t\"%.14g\"\n\n#define l_mathop(op)\t\top\n\n#define lua_str2number(s,p)\tstrtod((s), (p))\n\n#else\t\t\t\t\t\t/* }{ */\n\n#error \"numeric float type not defined\"\n\n#endif\t\t\t\t\t/* } */\n\n\n\n/*\n@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.\n@@ LUAI_UACINT is the result of a 'default argument promotion'\n@@ over a LUA_INTEGER.\n@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.\n@@ LUA_INTEGER_FMT is the format for writing integers.\n@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.\n@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.\n@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.\n@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.\n@@ lua_integer2str converts an integer to a string.\n*/\n\n\n/* The following definitions are good for most cases here */\n\n#define LUA_INTEGER_FMT\t\t\"%\" LUA_INTEGER_FRMLEN \"d\"\n\n#define LUAI_UACINT\t\tLUA_INTEGER\n\n#define lua_integer2str(s,sz,n)  \\\n\tl_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))\n\n/*\n** use LUAI_UACINT here to avoid problems with promotions (which\n** can turn a comparison between unsigneds into a signed comparison)\n*/\n#define LUA_UNSIGNED\t\tunsigned LUAI_UACINT\n\n\n#define LUA_UNSIGNEDBITS\t(sizeof(LUA_UNSIGNED) * CHAR_BIT)\n\n\n/* now the variable definitions */\n\n#if LUA_INT_TYPE == LUA_INT_INT\t\t/* { int */\n\n#define LUA_INTEGER\t\tint\n#define LUA_INTEGER_FRMLEN\t\"\"\n\n#define LUA_MAXINTEGER\t\tINT_MAX\n#define LUA_MININTEGER\t\tINT_MIN\n\n#define LUA_MAXUNSIGNED\t\tUINT_MAX\n\n#elif LUA_INT_TYPE == LUA_INT_LONG\t/* }{ long */\n\n#define LUA_INTEGER\t\tlong\n#define LUA_INTEGER_FRMLEN\t\"l\"\n\n#define LUA_MAXINTEGER\t\tLONG_MAX\n#define LUA_MININTEGER\t\tLONG_MIN\n\n#define LUA_MAXUNSIGNED\t\tULONG_MAX\n\n#elif LUA_INT_TYPE == LUA_INT_LONGLONG\t/* }{ long long */\n\n/* use presence of macro LLONG_MAX as proxy for C99 compliance */\n#if defined(LLONG_MAX)\t\t/* { */\n/* use ISO C99 stuff */\n\n#define LUA_INTEGER\t\tlong long\n#define LUA_INTEGER_FRMLEN\t\"ll\"\n\n#define LUA_MAXINTEGER\t\tLLONG_MAX\n#define LUA_MININTEGER\t\tLLONG_MIN\n\n#define LUA_MAXUNSIGNED\t\tULLONG_MAX\n\n#elif defined(LUA_USE_WINDOWS) /* }{ */\n/* in Windows, can use specific Windows types */\n\n#define LUA_INTEGER\t\t__int64\n#define LUA_INTEGER_FRMLEN\t\"I64\"\n\n#define LUA_MAXINTEGER\t\t_I64_MAX\n#define LUA_MININTEGER\t\t_I64_MIN\n\n#define LUA_MAXUNSIGNED\t\t_UI64_MAX\n\n#else\t\t\t\t/* }{ */\n\n#error \"Compiler does not support 'long long'. Use option '-DLUA_32BITS' \\\n  or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)\"\n\n#endif\t\t\t\t/* } */\n\n#else\t\t\t\t/* }{ */\n\n#error \"numeric integer type not defined\"\n\n#endif\t\t\t\t/* } */\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Dependencies with C99 and other C details\n** ===================================================================\n*/\n\n/*\n@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.\n** (All uses in Lua have only one format item.)\n*/\n#if !defined(LUA_USE_C89)\n#define l_sprintf(s,sz,f,i)\tsnprintf(s,sz,f,i)\n#else\n#define l_sprintf(s,sz,f,i)\t((void)(sz), sprintf(s,f,i))\n#endif\n\n\n/*\n@@ lua_strx2number converts a hexadecimal numeral to a number.\n** In C99, 'strtod' does that conversion. Otherwise, you can\n** leave 'lua_strx2number' undefined and Lua will provide its own\n** implementation.\n*/\n#if !defined(LUA_USE_C89)\n#define lua_strx2number(s,p)\t\tlua_str2number(s,p)\n#endif\n\n\n/*\n@@ lua_pointer2str converts a pointer to a readable string in a\n** non-specified way.\n*/\n#define lua_pointer2str(buff,sz,p)\tl_sprintf(buff,sz,\"%p\",p)\n\n\n/*\n@@ lua_number2strx converts a float to a hexadecimal numeral.\n** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.\n** Otherwise, you can leave 'lua_number2strx' undefined and Lua will\n** provide its own implementation.\n*/\n#if !defined(LUA_USE_C89)\n#define lua_number2strx(L,b,sz,f,n)  \\\n\t((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))\n#endif\n\n\n/*\n** 'strtof' and 'opf' variants for math functions are not valid in\n** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the\n** availability of these variants. ('math.h' is already included in\n** all files that use these macros.)\n*/\n#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))\n#undef l_mathop  /* variants not available */\n#undef lua_str2number\n#define l_mathop(op)\t\t(lua_Number)op  /* no variant */\n#define lua_str2number(s,p)\t((lua_Number)strtod((s), (p)))\n#endif\n\n\n/*\n@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation\n** functions.  It must be a numerical type; Lua will use 'intptr_t' if\n** available, otherwise it will use 'ptrdiff_t' (the nearest thing to\n** 'intptr_t' in C89)\n*/\n#define LUA_KCONTEXT\tptrdiff_t\n\n#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \\\n    __STDC_VERSION__ >= 199901L\n#include <stdint.h>\n#if defined(INTPTR_MAX)  /* even in C99 this type is optional */\n#undef LUA_KCONTEXT\n#define LUA_KCONTEXT\tintptr_t\n#endif\n#endif\n\n\n/*\n@@ lua_getlocaledecpoint gets the locale \"radix character\" (decimal point).\n** Change that if you do not want to use C locales. (Code using this\n** macro must include the header 'locale.h'.)\n*/\n#if !defined(lua_getlocaledecpoint)\n#define lua_getlocaledecpoint()\t\t(localeconv()->decimal_point[0])\n#endif\n\n\n/*\n** macros to improve jump prediction, used mostly for error handling\n** and debug facilities. (Some macros in the Lua API use these macros.\n** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your\n** code.)\n*/\n#if !defined(luai_likely)\n\n#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)\n#define luai_likely(x)\t\t(__builtin_expect(((x) != 0), 1))\n#define luai_unlikely(x)\t(__builtin_expect(((x) != 0), 0))\n#else\n#define luai_likely(x)\t\t(x)\n#define luai_unlikely(x)\t(x)\n#endif\n\n#endif\n\n\n#if defined(LUA_CORE) || defined(LUA_LIB)\n/* shorter names for Lua's own use */\n#define l_likely(x)\tluai_likely(x)\n#define l_unlikely(x)\tluai_unlikely(x)\n#endif\n\n\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Language Variations\n** =====================================================================\n*/\n\n/*\n@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some\n** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from\n** numbers to strings. Define LUA_NOCVTS2N to turn off automatic\n** coercion from strings to numbers.\n*/\n/* #define LUA_NOCVTN2S */\n/* #define LUA_NOCVTS2N */\n\n\n/*\n@@ LUA_USE_APICHECK turns on several consistency checks on the C API.\n** Define it as a help when debugging C code.\n*/\n#if defined(LUA_USE_APICHECK)\n#include <assert.h>\n#define luai_apicheck(l,e)\tassert(e)\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Macros that affect the API and must be stable (that is, must be the\n** same when you compile Lua and when you compile code that links to\n** Lua).\n** =====================================================================\n*/\n\n/*\n@@ LUAI_MAXSTACK limits the size of the Lua stack.\n** CHANGE it if you need a different limit. This limit is arbitrary;\n** its only purpose is to stop Lua from consuming unlimited stack\n** space (and to reserve some numbers for pseudo-indices).\n** (It must fit into max(size_t)/32.)\n*/\n#if LUAI_IS32INT\n#define LUAI_MAXSTACK\t\t1000000\n#else\n#define LUAI_MAXSTACK\t\t15000\n#endif\n\n\n/*\n@@ LUA_EXTRASPACE defines the size of a raw memory area associated with\n** a Lua state with very fast access.\n** CHANGE it if you need a different size.\n*/\n#define LUA_EXTRASPACE\t\t(sizeof(void *))\n\n\n/*\n@@ LUA_IDSIZE gives the maximum size for the description of the source\n@@ of a function in debug information.\n** CHANGE it if you want a different size.\n*/\n#define LUA_IDSIZE\t60\n\n\n/*\n@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.\n*/\n#define LUAL_BUFFERSIZE   ((int)(16 * sizeof(void*) * sizeof(lua_Number)))\n\n\n/*\n@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure\n** maximum alignment for the other items in that union.\n*/\n#define LUAI_MAXALIGN  lua_Number n; double u; void *s; lua_Integer i; long l\n\n/* }================================================================== */\n\n\n\n\n\n/* =================================================================== */\n\n/*\n** Local configuration. You can use this space to add your redefinitions\n** without modifying the main part of the file.\n*/\n\n\n\n\n\n#endif\n\n"
  },
  {
    "path": "xmake/scripts/module/xmi.h",
    "content": "/*!A cross-platform build utility based on Lua\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Copyright (C) 2015-present, Xmake Open Source Community.\n *\n * @author      ruki\n * @file        xmi.h\n *\n */\n#ifndef XMI_H\n#define XMI_H\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * includes\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#ifndef LUA_VERSION\n#   include \"luawrap/luaconf.h\"\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * macros\n */\n\n#define XMI_LUA_MULTRET  (-1)\n\n// thread status\n#define XMI_LUA_OK              0\n#define XMI_LUA_YIELD           1\n#define XMI_LUA_ERRRUN          2\n#define XMI_LUA_ERRSYNTAX       3\n#define XMI_LUA_ERRMEM          4\n#define XMI_LUA_ERRERR          5\n\n// basic types\n#define XMI_LUA_TNONE           (-1)\n\n#define XMI_LUA_TNIL            0\n#define XMI_LUA_TBOOLEAN        1\n#define XMI_LUA_TLIGHTUSERDATA  2\n#define XMI_LUA_TNUMBER         3\n#define XMI_LUA_TSTRING         4\n#define XMI_LUA_TTABLE          5\n#define XMI_LUA_TFUNCTION       6\n#define XMI_LUA_TUSERDATA       7\n#define XMI_LUA_TTHREAD         8\n\n#define XMI_LUA_NUMTYPES        9\n\n// pseudo-indices\n#ifdef XMI_USE_LUAJIT\n#   define XMI_LUA_REGISTRYINDEX    (-10000)\n#   define XMI_LUA_ENVIRONINDEX     (-10001)\n#   define XMI_LUA_GLOBALSINDEX     (-10002)\n#   define xmi_lua_upvalueindex(i)  (XMI_LUA_GLOBALSINDEX - (i))\n#else\n#   define XMI_LUA_REGISTRYINDEX    (-LUAI_MAXSTACK - 1000)\n#   define xmi_lua_upvalueindex(i)  (XMI_LUA_REGISTRYINDEX - (i))\n#endif\n\n// get macros\n#ifdef XMI_USE_LUAJIT\n#   define xmi_lua_getglobal(lua, s)                xmi_lua_getfield(lua, LUA_GLOBALSINDEX, (s))\n#   define xmi_lua_newuserdata(lua, s)              (g_lua_ops)->_lua_newuserdata(lua, s)\n#else\n#   define xmi_lua_getglobal(lua, name)             (g_lua_ops)->_lua_getglobal(lua, name)\n#   define xmi_lua_geti(lua, idx, n)                (g_lua_ops)->_lua_geti(lua, idx, n)\n#   define xmi_lua_rawgetp(lua, idx, p)             (g_lua_ops)->_lua_rawgetp(lua, idx, p)\n#   define xmi_lua_getiuservalue(lua, idx, n)       (g_lua_ops)->_lua_getiuservalue(lua, idx, n)\n#   define xmi_lua_newuserdatauv(lua, sz, nuvalue)  (g_lua_ops)->_lua_newuserdatauv(lua, sz, nuvalue)\n#   define xmi_lua_newuserdata(lua, s)              xmi_lua_newuserdatauv(lua, s, 1)\n#endif\n#define xmi_lua_gettable(lua, idx)                  (g_lua_ops)->_lua_gettable(lua, idx)\n#define xmi_lua_getfield(lua, idx, k)               (g_lua_ops)->_lua_getfield(lua, idx, k)\n#define xmi_lua_rawget(lua, idx)                    (g_lua_ops)->_lua_rawget(lua, idx)\n#define xmi_lua_rawgeti(lua, idx, n)                (g_lua_ops)->_lua_rawgeti(lua, idx, n)\n#define xmi_lua_createtable(lua, narr, nrec)        (g_lua_ops)->_lua_createtable(lua, narr, nrec)\n#define xmi_lua_getmetatable(lua, objindex)         (g_lua_ops)->_lua_getmetatable(lua, objindex)\n#define xmi_lua_newtable(lua)                       xmi_lua_createtable(lua, 0, 0)\n#define xmi_lua_pop(lua, n)                         xmi_lua_settop(lua, -(n)-1)\n#define xmi_lua_getuservalue(lua, idx)              xmi_lua_getiuservalue(lua, idx, 1)\n\n// set macros\n#ifdef XMI_USE_LUAJIT\n#   define xmi_lua_setglobal(lua, s)                xmi_lua_setfield(lua, LUA_GLOBALSINDEX, (s))\n#else\n#   define xmi_lua_setglobal(lua, name)             (g_lua_ops)->_lua_setglobal(lua, name)\n#   define xmi_lua_seti(lua, idx, n)                (g_lua_ops)->_lua_seti(lua, idx, n)\n#   define xmi_lua_rawsetp(lua, idx, p)             (g_lua_ops)->_lua_rawsetp(lua, idx, p)\n#   define xmi_lua_setiuservalue(lua, idx, n)       (g_lua_ops)->_lua_setiuservalue(lua, idx, n)\n#endif\n#define xmi_lua_settable(lua, idx)                  (g_lua_ops)->_lua_settable(lua, idx)\n#define xmi_lua_setfield(lua, idx, k)               (g_lua_ops)->_lua_setfield(lua, idx, k)\n#define xmi_lua_rawset(lua, idx)                    (g_lua_ops)->_lua_rawset(lua, idx)\n#define xmi_lua_rawseti(lua, idx, n)                (g_lua_ops)->_lua_rawseti(lua, idx, n)\n#define xmi_lua_setmetatable(lua, objidx)           (g_lua_ops)->_lua_setmetatable(lua, objidx)\n#define xmi_lua_setuservalue(lua, idx)              xmi_lua_setiuservalue(lua, idx, 1)\n\n// access macros\n#define xmi_lua_isnumber(lua, idx)                  (g_lua_ops)->_lua_isnumber(lua, idx)\n#define xmi_lua_isstring(lua, idx)                  (g_lua_ops)->_lua_isstring(lua, idx)\n#define xmi_lua_iscfunction(lua, idx)               (g_lua_ops)->_lua_iscfunction(lua, idx)\n#define xmi_lua_isuserdata(lua, idx)                (g_lua_ops)->_lua_isuserdata(lua, idx)\n#define xmi_lua_type(lua, idx)                      (g_lua_ops)->_lua_type(lua, idx)\n#define xmi_lua_typename(lua, idx)                  (g_lua_ops)->_lua_typename(lua, idx)\n#ifndef XMI_USE_LUAJIT\n#   define xmi_lua_isinteger(lua, idx)              (g_lua_ops)->_lua_isinteger(lua, idx)\n#endif\n\n#define xmi_lua_isfunction(lua, n)                  (xmi_lua_type(lua, (n)) == XMI_LUA_TFUNCTION)\n#define xmi_lua_istable(lua, n)                     (xmi_lua_type(lua, (n)) == XMI_LUA_TTABLE)\n#define xmi_lua_islightuserdata(lua, n)             (xmi_lua_type(lua, (n)) == XMI_LUA_TLIGHTUSERDATA)\n#define xmi_lua_isnil(lua, n)                       (xmi_lua_type(lua, (n)) == XMI_LUA_TNIL)\n#define xmi_lua_isboolean(lua, n)                   (xmi_lua_type(lua, (n)) == XMI_LUA_TBOOLEAN)\n#define xmi_lua_isthread(lua, n)                    (xmi_lua_type(lua, (n)) == XMI_LUA_TTHREAD)\n#define xmi_lua_isnone(lua, n)                      (xmi_lua_type(lua, (n)) == XMI_LUA_TNONE)\n#define xmi_lua_isnoneornil(lua, n)                 (xmi_lua_type(lua, (n)) <= 0)\n\n#define xmi_lua_tonumberx(lua, idx, isnum)          (g_lua_ops)->_lua_tonumberx(lua, idx, isnum)\n#define xmi_lua_tointegerx(lua, idx, isnum)         (g_lua_ops)->_lua_tointegerx(lua, idx, isnum)\n#define xmi_lua_toboolean(lua, idx)                 (g_lua_ops)->_lua_toboolean(lua, idx)\n#define xmi_lua_tolstring(lua, idx, len)            (g_lua_ops)->_lua_tolstring(lua, idx, len)\n#define xmi_lua_rawlen(lua, idx)                    (g_lua_ops)->_lua_rawlen(lua, idx)\n#define xmi_lua_tocfunction(lua, idx)               (g_lua_ops)->_lua_tocfunction(lua, idx)\n#define xmi_lua_touserdata(lua, idx)                (g_lua_ops)->_lua_touserdata(lua, idx)\n#define xmi_lua_tothread(lua, idx)                  (g_lua_ops)->_lua_tothread(lua, idx)\n#define xmi_lua_topointer(lua, idx)                 (g_lua_ops)->_lua_topointer(lua, idx)\n#define xmi_lua_tonumber(lua, idx)                  xmi_lua_tonumberx(lua, (idx), NULL)\n#define xmi_lua_tostring(lua, idx)                  xmi_lua_tolstring(lua, (idx), NULL)\n#define xmi_lua_tointeger(lua, idx)                 xmi_lua_tointegerx(lua, (idx), NULL)\n\n// push macros\n#define xmi_lua_pushnil(lua)                        (g_lua_ops)->_lua_pushnil(lua)\n#define xmi_lua_pushinteger(lua, n)                 (g_lua_ops)->_lua_pushinteger(lua, n)\n#define xmi_lua_pushboolean(lua, b)                 (g_lua_ops)->_lua_pushboolean(lua, b)\n#define xmi_lua_pushnumber(lua, n)                  (g_lua_ops)->_lua_pushnumber(lua, n)\n#define xmi_lua_pushlstring(lua, s, len)            (g_lua_ops)->_lua_pushlstring(lua, s, len)\n#define xmi_lua_pushstring(lua, s)                  (g_lua_ops)->_lua_pushstring(lua, s)\n#define xmi_lua_pushvfstring(lua, fmt, argp)        (g_lua_ops)->_lua_pushvfstring(lua, fmt, argp)\n#if defined(_MSC_VER)\n#   define xmi_lua_pushfstring(lua, fmt, ...)       (g_lua_ops)->_lua_pushfstring(lua, fmt, __VA_ARGS__)\n#else\n#   define xmi_lua_pushfstring(lua, fmt, arg ...)   (g_lua_ops)->_lua_pushfstring(lua, fmt, ## arg)\n#endif\n#define xmi_lua_pushcclosure(lua, fn, n)            (g_lua_ops)->_lua_pushcclosure(lua, fn, n)\n#define xmi_lua_pushlightuserdata(lua, p)           (g_lua_ops)->_lua_pushlightuserdata(lua, p)\n#define xmi_lua_pushthread(lua)                     (g_lua_ops)->_lua_pushthread(lua)\n#define xmi_lua_pushcfunction(lua, f)               xmi_lua_pushcclosure(lua, (f), 0)\n#define xmi_lua_pushliteral(lua, s)                 xmi_lua_pushstring(lua, \"\" s)\n\n// stack functions\n#ifdef XMI_USE_LUAJIT\n#   define xmi_lua_insert(lua, idx)                 (g_lua_ops)->_lua_insert(lua, idx)\n#   define xmi_lua_remove(lua, idx)                 (g_lua_ops)->_lua_remove(lua, idx)\n#   define xmi_lua_replace(lua, idx)                (g_lua_ops)->_lua_replace(lua, idx)\n#else\n#   define xmi_lua_absindex(lua, idx)               (g_lua_ops)->_lua_absindex(lua, idx)\n#   define xmi_lua_rotate(lua, idx, n)              (g_lua_ops)->_lua_rotate(lua, idx, n)\n#   define xmi_lua_insert(lua, idx)\t                xmi_lua_rotate(lua, (idx), 1)\n#   define xmi_lua_remove(lua, idx)\t                (xmi_lua_rotate(lua, (idx), -1), xmi_lua_pop(lua, 1))\n#   define xmi_lua_replace(lua, idx)\t            (xmi_lua_copy(lua, -1, (idx)), xmi_lua_pop(lua, 1))\n#endif\n#define xmi_lua_gettop(lua)                         (g_lua_ops)->_lua_gettop(lua)\n#define xmi_lua_settop(lua, idx)                    (g_lua_ops)->_lua_settop(lua, idx)\n#define xmi_lua_pushvalue(lua, idx)                 (g_lua_ops)->_lua_pushvalue(lua, idx)\n#define xmi_lua_copy(lua, fromidx, toidx)           (g_lua_ops)->_lua_copy(lua, fromidx, toidx)\n#define xmi_lua_checkstack(lua, n)                  (g_lua_ops)->_lua_checkstack(lua, n)\n#define xmi_lua_xmove(from, to, n)                  (g_lua_ops)->_lua_xmove(from, to, n)\n\n// miscellaneous functions\n#define xmi_lua_error(lua)                          (g_lua_ops)->_lua_error(lua)\n#define xmi_lua_next(lua, idx)                      (g_lua_ops)->_lua_next(lua, idx)\n#define xmi_lua_concat(lua, n)                      (g_lua_ops)->_lua_concat(lua, n)\n#define xmi_lua_getallocf(lua, ud)                  (g_lua_ops)->_lua_getallocf(lua, ud)\n#define xmi_lua_setallocf(lua, f, ud)               (g_lua_ops)->_lua_setallocf(lua, f, ud)\n#ifndef XMI_USE_LUAJIT\n#   define xmi_lua_len(lua, idx)                    (g_lua_ops)->_lua_len(lua, idx)\n#   define xmi_lua_toclose(lua, idx)                (g_lua_ops)->_lua_toclose(lua, idx)\n#   define xmi_lua_closeslot(lua, idx)              (g_lua_ops)->_lua_closeslot(lua, idx)\n#   define xmi_lua_stringtonumber(lua, s)           (g_lua_ops)->_lua_stringtonumber(lua, s)\n#endif\n\n// 'load' and 'call' functions\n#ifdef XMI_USE_LUAJIT\n#   define xmi_lua_call(lua, n, nr)                 (g_lua_ops)->_lua_call(lua, n, nr)\n#   define xmi_lua_pcall(lua, n, nr, ef)            (g_lua_ops)->_lua_pcall(lua, n, nr, ef)\n#   define xmi_lua_load(lua, r, dt, ch)             (g_lua_ops)->_lua_load(lua, r, dt, ch)\n#   define xmi_lua_dump(lua, w, d)                  (g_lua_ops)->_lua_dump(lua, r, d)\n#else\n#   define xmi_lua_callk(lua, n, nr, ctx, k)        (g_lua_ops)->_lua_callk(lua, n, nr, ctx, k)\n#   define xmi_lua_pcallk(lua, n, nr, ef, ctx, k)   (g_lua_ops)->_lua_pcallk(lua, n, nr, ef, ctx, k)\n#   define xmi_lua_call(lua, n, r)                  xmi_lua_callk(lua, (n), (r), 0, NULL)\n#   define xmi_lua_pcall(lua, n, r, f)              xmi_lua_pcallk(lua, (n), (r), (f), 0, NULL)\n#   define xmi_lua_load(lua, r, dt, ch, mode)       (g_lua_ops)->_lua_load(lua, r, dt, ch, mode)\n#   define xmi_lua_dump(lua, w, d, strip)           (g_lua_ops)->_lua_dump(lua, r, d, strip)\n#endif\n\n// luaL macros\n#ifndef XMI_USE_LUAJIT\n#   define xmi_luaL_tolstring(lua, idx, len)        (g_lua_ops)->_luaL_tolstring(lua, idx, len)\n#   define xmi_luaL_typeerror(lua, arg, tname)      (g_lua_ops)->_luaL_typeerror(lua, arg, tname)\n#endif\n#define xmi_luaL_getmetafield(lua, obj, e)          (g_lua_ops)->_luaL_getmetafield(lua, obj, e)\n#define xmi_luaL_callmeta(lua, obj, e)              (g_lua_ops)->_luaL_callmeta(lua, obj, e)\n#define xmi_luaL_argerror(lua, numarg, extramsg)    (g_lua_ops)->_luaL_argerror(lua, numarg, extramsg)\n#define xmi_luaL_checklstring(lua, arg, l)          (g_lua_ops)->_luaL_checklstring(lua, arg, l)\n#define xmi_luaL_optlstring(lua, arg, def, l)       (g_lua_ops)->_luaL_optlstring(lua, arg, def, l)\n#define xmi_luaL_checknumber(lua, arg)              (g_lua_ops)->_luaL_checknumber(lua, arg)\n#define xmi_luaL_optnumber(lua, arg, def)           (g_lua_ops)->_luaL_optnumber(lua, arg, def)\n#define xmi_luaL_checkinteger(lua, idx)             (g_lua_ops)->_luaL_checkinteger(lua, idx)\n#define xmi_luaL_optinteger(lua, arg, def)          (g_lua_ops)->_luaL_optinteger(lua, arg, def)\n#define xmi_luaL_checkstack(lua, sz, msg)           (g_lua_ops)->_luaL_checkstack(lua, sz, msg)\n#define xmi_luaL_checktype(lua, arg, t)             (g_lua_ops)->_luaL_checktype(lua, arg, t)\n#define xmi_luaL_checkany(lua, arg)                 (g_lua_ops)->_luaL_checkany(lua, arg)\n#define xmi_luaL_newmetatable(lua, tname)           (g_lua_ops)->_luaL_newmetatable(lua, tname)\n#define xmi_luaL_setmetatable(lua, tname)           (g_lua_ops)->_luaL_setmetatable(lua, tname)\n#define xmi_luaL_testudata(lua, tname)              (g_lua_ops)->_luaL_testudata(lua, tname)\n#define xmi_luaL_checkudata(lua, tname)             (g_lua_ops)->_luaL_checkudata(lua, tname)\n#define xmi_luaL_where(lua, lvl)                    (g_lua_ops)->_luaL_where(lua, lvl)\n#if defined(_MSC_VER)\n#   define xmi_luaL_error(lua, fmt, ...)            (g_lua_ops)->_luaL_error(lua, fmt, __VA_ARGS__)\n#else\n#   define xmi_luaL_error(lua, fmt, arg ...)        (g_lua_ops)->_luaL_error(lua, fmt, ## arg)\n#endif\n#define xmi_luaL_checkoption(lua, arg, def, lst)    (g_lua_ops)->_luaL_checkoption(lua, arg, def, lst)\n#define xmi_luaL_fileresult(lua, stat, fname)       (g_lua_ops)->_luaL_fileresult(lua, stat, fname)\n#define xmi_luaL_execresult(lua, stat)              (g_lua_ops)->_luaL_execresult(lua, stat)\n#define xmi_luaL_setfuncs(lua, l, nup)              (g_lua_ops)->_luaL_setfuncs(lua, l, nup)\n#define xmi_luaL_loadfilex(lua, fn, mode)           (g_lua_ops)->_luaL_loadfilex(lua, fn, mode)\n#define xmi_luaL_loadfile(lua, fn)                  xmi_luaL_loadfilex(lua, fn, NULL)\n#define xmi_luaL_loadstring(lua, s)                 (g_lua_ops)->_luaL_loadstring(lua, s)\n\n#define xmi_luaL_newlibtable(lua, l)                xml_lua_createtable(lua, 0, sizeof(l)/sizeof((l)[0]) - 1)\n#define xmi_luaL_newlib(lua, l) \\\n    (xmi_luaL_checkversion(lua), xmi_luaL_newlibtable(lua,l), xmi_luaL_setfuncs(lua,l,0))\n#define xmi_luaL_argcheck(lua, cond, arg, extramsg) \\\n    ((void)(luai_likely(cond) || xmi_luaL_argerror(lua, (arg), (extramsg))))\n#define xmi_luaL_argexpected(lua, cond, arg, tname) \\\n    ((void)(luai_likely(cond) || xmi_luaL_typeerror(lua, (arg), (tname))))\n#define xmi_luaL_checkstring(lua, n)                (xmi_luaL_checklstring(lua, (n), NULL))\n#define xmi_luaL_optstring(lua, n, d)               (xmi_luaL_optlstring(lua, (n), (d), NULL))\n#define xmi_luaL_typename(lua, i)                   xmi_lua_typename(lua, xmi_lua_type(lua,(i)))\n#define xmi_luaL_dofile(lua, fn) \\\n    (xmi_luaL_loadfile(lua, fn) || xmi_lua_pcall(lua, 0, XMI_LUA_MULTRET, 0))\n#define xmi_luaL_dostring(lua, s) \\\n    (xmi_luaL_loadstring(lua, s) || xmi_lua_pcall(lua, 0, XMI_LUA_MULTRET, 0))\n#define xmi_luaL_getmetatable(lua, n)               (xmi_lua_getfield(lua, XMI_LUA_REGISTRYINDEX, (n)))\n#define xmi_luaL_opt(lua, f, n, d)                  (xmi_lua_isnoneornil(lua,(n)) ? (d) : f(lua,(n)))\n#define xmi_luaL_loadbuffer(lua, s, sz, n)          xmi_luaL_loadbufferx(lua, s, sz, n, NULL)\n#define xmi_luaL_pushfail(lua)                      xmi_lua_pushnil(lua)\n\n/* we cannot redefine lua functions in loadxmi.c,\n * because original lua.h has been included\n */\n#ifndef XM_PREFIX_H\n\n// thread status\n#   define LUA_OK                   XMI_LUA_OK\n#   define LUA_YIELD                XMI_LUA_YIELD\n#   define LUA_ERRRUN               XMI_LUA_ERRRUN\n#   define LUA_ERRSYNTAX            XMI_LUA_ERRSYNTAX\n#   define LUA_ERRMEM               XMI_LUA_ERRMEM\n#   define LUA_ERRERR               XMI_LUA_ERRERR\n\n// basic types\n#   define LUA_TNONE                XMI_LUA_TNONE\n#   define LUA_TNIL                 XMI_LUA_TNIL\n#   define LUA_TBOOLEAN             XMI_LUA_TBOOLEAN\n#   define LUA_TLIGHTUSERDATA       XMI_LUA_TLIGHTUSERDATA\n#   define LUA_TNUMBER              XMI_LUA_TNUMBER\n#   define LUA_TSTRING              XMI_LUA_TSTRING\n#   define LUA_TTABLE               XMI_LUA_TTABLE\n#   define LUA_TFUNCTION            XMI_LUA_TFUNCTION\n#   define LUA_TUSERDATA            XMI_LUA_TUSERDATA\n#   define LUA_TTHREAD              XMI_LUA_TTHREAD\n#   define LUA_NUMTYPES             XMI_LUA_NUMTYPES\n\n// get macros\n#   define lua_getglobal            xmi_lua_getglobal\n#   define lua_gettable             xmi_lua_gettable\n#   define lua_getfield             xmi_lua_getfield\n#   define lua_geti                 xmi_lua_geti\n#   define lua_rawget               xmi_lua_rawget\n#   define lua_rawgeti              xmi_lua_rawgeti\n#   define lua_rawgetp              xmi_lua_rawgetp\n#   define lua_createtable          xmi_lua_createtable\n#   define lua_newuserdatauv        xmi_lua_newuserdatauv\n#   define lua_getmetatable         xmi_lua_getmetatable\n#   define lua_getiuservalue        xmi_lua_getiuservalue\n#   define lua_upvalueindex         xmi_lua_upvalueindex\n#   define lua_newtable             xmi_lua_newtable\n#   define lua_pop                  xmi_lua_pop\n#   define lua_newuserdata          xmi_lua_newuserdata\n#   define lua_getuservalue         xmi_lua_getuservalue\n\n// set macros\n#   define lua_setglobal            xmi_lua_setglobal\n#   define lua_settable             xmi_lua_settable\n#   define lua_setfield             xmi_lua_setfield\n#   define lua_seti                 xmi_lua_seti\n#   define lua_rawset               xmi_lua_rawset\n#   define lua_rawseti              xmi_lua_rawseti\n#   define lua_rawsetp              xmi_lua_rawsetp\n#   define lua_setmetatable         xmi_lua_setmetatable\n#   define lua_setiuservalue        xmi_lua_setiuservalue\n#   define lua_setuservalue         xmi_lua_setuservalue\n\n// access macros\n#   define lua_isnumber             xmi_lua_isnumber\n#   define lua_isstring             xmi_lua_isstring\n#   define lua_iscfunction          xmi_lua_iscfunction\n#   define lua_isuserdata           xmi_lua_isuserdata\n#   define lua_type                 xmi_lua_type\n#   define lua_typename             xmi_lua_typename\n#   ifndef XMI_USE_LUAJIT\n#   define lua_isinteger            xmi_lua_isinteger\n#   endif\n\n#   define lua_isfunction           xmi_lua_isfunction\n#   define lua_istable              xmi_lua_istable\n#   define lua_islightuserdata      xmi_lua_islightuserdata\n#   define lua_isnil                xmi_lua_isnil\n#   define lua_isboolean            xmi_lua_isboolean\n#   define lua_isthread             xmi_lua_isthread\n#   define lua_isnone               xmi_lua_isnone\n#   define lua_isnoneornil          xmi_lua_isnoneornil\n\n#   define lua_tonumberx            xmi_lua_tonumberx\n#   define lua_tointegerx           xmi_lua_tointegerx\n#   define lua_toboolean            xmi_lua_toboolean\n#   define lua_tolstring            xmi_lua_tolstring\n#   define lua_rawlen               xmi_lua_rawlen\n#   define lua_tocfunction          xmi_lua_tocfunction\n#   define lua_touserdata           xmi_lua_touserdata\n#   define lua_tothread             xmi_lua_tothread\n#   define lua_topointer            xmi_lua_topointer\n#   define lua_tostring             xmi_lua_tostring\n#   define lua_tonumber             xmi_lua_tonumber\n#   define lua_tointeger            xmi_lua_tointeger\n\n// push macros\n#   define lua_pushnil              xmi_lua_pushnil\n#   define lua_pushinteger          xmi_lua_pushinteger\n#   define lua_pushboolean          xmi_lua_pushboolean\n#   define lua_pushnumber           xmi_lua_pushnumber\n#   define lua_pushlstring          xmi_lua_pushlstring\n#   define lua_pushstring           xmi_lua_pushstring\n#   define lua_pushvfstring         xmi_lua_pushvfstring\n#   define lua_pushfstring          xmi_lua_pushfstring\n#   define lua_pushcclosure         xmi_lua_pushcclosure\n#   define lua_pushlightuserdata    xmi_lua_pushlightuserdata\n#   define lua_pushthread           xmi_lua_pushthread\n#   define lua_pushcfunction        xmi_lua_pushcfunction\n#   define lua_pushliteral          xmi_lua_pushliteral\n\n// stack functions\n#   define lua_absindex             xmi_lua_absindex\n#   define lua_gettop               xmi_lua_gettop\n#   define lua_settop               xmi_lua_settop\n#   define lua_pushvalue            xmi_lua_pushvalue\n#   define lua_rotate               xmi_lua_rotate\n#   define lua_copy                 xmi_lua_copy\n#   define lua_checkstack           xmi_lua_checkstack\n#   define lua_xmove                xmi_lua_xmove\n#   define lua_insert               xmi_lua_insert\n#   define lua_remove               xmi_lua_remove\n#   define lua_replace              xmi_lua_replace\n\n// miscellaneous functions\n#   define lua_error                xmi_lua_error\n#   define lua_next                 xmi_lua_next\n#   define lua_concat               xmi_lua_concat\n#   define lua_len                  xmi_lua_len\n#   define lua_stringtonumber       xmi_lua_stringtonumber\n#   define lua_getallocf            xmi_lua_getallocf\n#   define lua_setallocf            xmi_lua_setallocf\n#   define lua_toclose              xmi_lua_toclose\n#   define lua_closeslot            xmi_lua_closeslot\n\n// 'load' and 'call' functions\n#   ifndef XMI_USE_LUAJIT\n#   define lua_callk                xmi_lua_callk\n#   define lua_pcallk               xmi_lua_pcallk\n#   endif\n#   define lua_call                 xmi_lua_call\n#   define lua_pcall                xmi_lua_pcall\n#   define lua_load                 xmi_lua_load\n#   define lua_dump                 xmi_lua_dump\n\n// luaL macros\n#   define luaL_getmetafield        xmi_luaL_getmetafield\n#   define luaL_callmeta            xmi_luaL_callmeta\n#   define luaL_tolstring           xmi_luaL_tolstring\n#   define luaL_argerror            xmi_luaL_argerror\n#   define luaL_typeerror           xmi_luaL_typeerror\n#   define luaL_checklstring        xmi_luaL_checklstring\n#   define luaL_optlstring          xmi_luaL_optlstring\n#   define luaL_checknumber         xmi_luaL_checknumber\n#   define luaL_optnumber           xmi_luaL_optnumber\n#   define luaL_checkinteger        xmi_luaL_checkinteger\n#   define luaL_optinteger          xmi_luaL_optinteger\n#   define luaL_checkstack          xmi_luaL_checkstack\n#   define luaL_checktype           xmi_luaL_checktype\n#   define luaL_checkany            xmi_luaL_checkany\n#   define luaL_newmetatable        xmi_luaL_newmetatable\n#   define luaL_setmetatable        xmi_luaL_setmetatable\n#   define luaL_testudata           xmi_luaL_testudata\n#   define luaL_checkudata          xmi_luaL_checkudata\n#   define luaL_where               xmi_luaL_where\n#   define luaL_error               xmi_luaL_error\n#   define luaL_checkoption         xmi_luaL_checkoption\n#   define luaL_fileresult          xmi_luaL_fileresult\n#   define luaL_execresult          xmi_luaL_execresult\n#   define luaL_setfuncs            xmi_luaL_setfuncs\n#   define luaL_loadfilex           xmi_luaL_loadfilex\n#   define luaL_loadfile            xmi_luaL_loadfile\n#   define luaL_loadstring          xmi_luaL_loadstring\n\n#   define luaL_newlibtable         xmi_luaL_newlibtable\n#   define luaL_newlib              xmi_luaL_newlib\n#   define luaL_argcheck            xmi_luaL_argcheck\n#   define luaL_argexpected         xmi_luaL_argexpected\n#   define luaL_checkstring         xmi_luaL_checkstring\n#   define luaL_optstring           xmi_luaL_optstring\n#   define luaL_typename            xmi_luaL_typename\n#   define luaL_dofile              xmi_luaL_dofile\n#   define luaL_dostring            xmi_luaL_dostring\n#   define luaL_getmetatable        xmi_luaL_getmetatable\n#   define luaL_opt                 xmi_luaL_opt\n#   define luaL_loadbuffer          xmi_luaL_loadbuffer\n#   define luaL_pushfail            xmi_luaL_pushfail\n\n// types\n#   define luaL_Reg                 xmi_luaL_Reg\n#   define lua_State                xmi_lua_State\n#   define lua_Number               xmi_lua_Number\n#   define lua_Integer              xmi_lua_Integer\n#   define lua_Unsigned             xmi_lua_Unsigned\n#   define lua_KContext             xmi_lua_KContext\n#   define lua_CFunction            xmi_lua_CFunction\n#   define lua_KFunction            xmi_lua_KFunction\n#   define lua_Reader               xmi_lua_Reader\n#   define lua_Writer               xmi_lua_Writer\n#   define lua_Alloc                xmi_lua_Alloc\n#   define lua_WarnFunction         xmi_lua_WarnFunction\n#endif\n\n// extern c\n#ifdef __cplusplus\n#   define xmi_extern_c_enter       extern \"C\" {\n#   define xmi_extern_c_leave       }\n#else\n#   define xmi_extern_c_enter\n#   define xmi_extern_c_leave\n#endif\n\n// define lua module entry function\n#define luaopen(name, lua) \\\n__dummy = 1; \\\nxmi_lua_ops_t* g_lua_ops = NULL; \\\nxmi_extern_c_enter \\\nint xmiopen_##name(lua); \\\nxmi_extern_c_leave \\\nint xmisetup(xmi_lua_ops_t* ops) { \\\n    g_lua_ops = ops; \\\n    return __dummy; \\\n} \\\nint xmiopen_##name(lua)\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * types\n */\ntypedef LUA_NUMBER xmi_lua_Number;\ntypedef LUA_INTEGER xmi_lua_Integer;\n#ifndef XMI_USE_LUAJIT\ntypedef LUA_UNSIGNED xmi_lua_Unsigned;\ntypedef LUA_KCONTEXT xmi_lua_KContext;\n#endif\n\ntypedef struct xmi_lua_State_ {\n    int dummy;\n}xmi_lua_State;\n\ntypedef int (*xmi_lua_CFunction)(lua_State* lua);\n#ifndef XMI_USE_LUAJIT\ntypedef int (*xmi_lua_KFunction)(lua_State* lua, int status, lua_KContext ctx);\n#endif\ntypedef const char* (*xmi_lua_Reader)(lua_State* lua, void* ud, size_t* sz);\ntypedef int (*xmi_lua_Writer)(lua_State* lua, const void* p, size_t sz, void* ud);\ntypedef void* (*xmi_lua_Alloc)(void* ud, void* ptr, size_t osize, size_t nsize);\ntypedef void (*xmi_lua_WarnFunction)(void* ud, const char* msg, int tocont);\n\ntypedef struct xmi_luaL_Reg_ {\n    char const*         name;\n    xmi_lua_CFunction   func;\n}xmi_luaL_Reg;\n\ntypedef struct xmi_lua_ops_t_ {\n\n    // get functions\n#ifdef XMI_USE_LUAJIT\n    void*           (*_lua_newuserdata)(lua_State* lua, size_t sz);\n    void            (*_lua_gettable)(lua_State* lua, int idx);\n    void            (*_lua_getfield)(lua_State* lua, int idx, const char* k);\n    void            (*_lua_rawgeti)(lua_State* lua, int idx, int n);\n    void            (*_lua_rawget)(lua_State* lua, int idx);\n#else\n    int             (*_lua_getglobal)(lua_State* lua, const char* name);\n    int             (*_lua_geti)(lua_State* lua, int idx, lua_Integer n);\n    int             (*_lua_rawgetp)(lua_State* lua, int idx, const void* p);\n    int             (*_lua_getiuservalue)(lua_State* lua, int idx, int n);\n    void*           (*_lua_newuserdatauv)(lua_State* lua, size_t sz, int nuvalue);\n    int             (*_lua_gettable)(lua_State* lua, int idx);\n    int             (*_lua_getfield)(lua_State* lua, int idx, const char* k);\n    int             (*_lua_rawgeti)(lua_State* lua, int idx, lua_Integer n);\n    int             (*_lua_rawget)(lua_State* lua, int idx);\n#endif\n    void            (*_lua_createtable)(lua_State* lua, int narr, int nrec);\n    int             (*_lua_getmetatable)(lua_State* lua, int objindex);\n\n    // set functions\n#ifdef XMI_USE_LUAJIT\n    void            (*_lua_rawseti)(lua_State* lua, int idx, int n);\n#else\n    void            (*_lua_setglobal)(lua_State* lua, const char* name);\n    void            (*_lua_seti)(lua_State* lua, int idx, lua_Integer n);\n    void            (*_lua_rawsetp)(lua_State* lua, int idx, const void* p);\n    int             (*_lua_setiuservalue)(lua_State* lua, int idx, int n);\n    void            (*_lua_rawseti)(lua_State* lua, int idx, lua_Integer n);\n#endif\n    void            (*_lua_settable)(lua_State* lua, int idx);\n    void            (*_lua_setfield)(lua_State* lua, int idx, const char* k);\n    void            (*_lua_rawset)(lua_State* lua, int idx);\n    int             (*_lua_setmetatable)(lua_State* lua, int objindex);\n\n    // access functions\n    int             (*_lua_isnumber)(lua_State* lua, int idx);\n    int             (*_lua_isstring)(lua_State* lua, int idx);\n    int             (*_lua_iscfunction)(lua_State* lua, int idx);\n    int             (*_lua_isuserdata)(lua_State* lua, int idx);\n    int             (*_lua_type)(lua_State* lua, int idx);\n    const char*     (*_lua_typename)(lua_State* lua, int tp);\n#ifndef XMI_USE_LUAJIT\n    int             (*_lua_isinteger)(lua_State* lua, int idx);\n#endif\n\n    lua_Number      (*_lua_tonumberx)(lua_State* lua, int idx, int* isnum);\n    lua_Integer     (*_lua_tointegerx)(lua_State* lua, int idx, int* isnum);\n    int             (*_lua_toboolean)(lua_State* lua, int idx);\n    const char*     (*_lua_tolstring)(lua_State* lua, int idx, size_t* len);\n    lua_CFunction   (*_lua_tocfunction)(lua_State* lua, int idx);\n    void*           (*_lua_touserdata)(lua_State* lua, int idx);\n    lua_State*      (*_lua_tothread)(lua_State* lua, int idx);\n    const void*     (*_lua_topointer)(lua_State* lua, int idx);\n#ifndef XMI_USE_LUAJIT\n    lua_Unsigned    (*_lua_rawlen)(lua_State* lua, int idx);\n#endif\n\n    // push functions\n    void            (*_lua_pushnil)(lua_State* lua);\n    void            (*_lua_pushinteger)(lua_State* lua, lua_Integer n);\n    void            (*_lua_pushboolean)(lua_State* lua, int b);\n    void            (*_lua_pushnumber)(lua_State* lua, lua_Number n);\n#ifdef XMI_USE_LUAJIT\n    void            (*_lua_pushlstring)(lua_State* lua, const char* s, size_t len);\n    void            (*_lua_pushstring)(lua_State* lua, const char* s);\n#else\n    const char*     (*_lua_pushlstring)(lua_State* lua, const char* s, size_t len);\n    const char*     (*_lua_pushstring)(lua_State* lua, const char* s);\n#endif\n    const char*     (*_lua_pushvfstring)(lua_State* lua, const char* fmt, va_list argp);\n    const char*     (*_lua_pushfstring)(lua_State* lua, const char* fmt, ...);\n    void            (*_lua_pushcclosure)(lua_State* lua, lua_CFunction fn, int n);\n    void            (*_lua_pushlightuserdata)(lua_State* lua, void* p);\n    int             (*_lua_pushthread)(lua_State* lua);\n\n    // stack functions\n#ifdef XMI_USE_LUAJIT\n    void            (*_lua_insert)(lua_State* lua, int idx);\n    void            (*_lua_remove)(lua_State* lua, int idx);\n    void            (*_lua_replace)(lua_State* lua, int idx);\n#else\n    int             (*_lua_absindex)(lua_State* lua, int idx);\n    void            (*_lua_rotate)(lua_State* lua, int idx, int n);\n#endif\n    int             (*_lua_gettop)(lua_State* lua);\n    void            (*_lua_settop)(lua_State* lua, int idx);\n    void            (*_lua_pushvalue)(lua_State* lua, int idx);\n    void            (*_lua_copy)(lua_State* lua, int fromidx, int toidx);\n    int             (*_lua_checkstack)(lua_State* lua, int n);\n    void            (*_lua_xmove)(lua_State* from, lua_State* to, int n);\n\n    // miscellaneous functions\n    int             (*_lua_error)(lua_State* lua);\n    int             (*_lua_next)(lua_State* lua, int idx);\n    void            (*_lua_concat)(lua_State* lua, int n);\n    lua_Alloc       (*_lua_getallocf)(lua_State* lua, void** ud);\n    void            (*_lua_setallocf)(lua_State* lua, lua_Alloc f, void* ud);\n#ifndef XMI_USE_LUAJIT\n    void            (*_lua_len)(lua_State* lua, int idx);\n    void            (*_lua_toclose)(lua_State* lua, int idx);\n    void            (*_lua_closeslot)(lua_State* lua, int idx);\n    size_t          (*_lua_stringtonumber)(lua_State* lua, const char* s);\n#endif\n\n    // 'load' and 'call' functions\n#ifdef XMI_USE_LUAJIT\n    void            (*_lua_call)(lua_State* lua, int nargs, int nresults);\n    int             (*_lua_pcall)(lua_State* lua, int nargs, int nresults, int errfunc);\n    int             (*_lua_load)(lua_State* lua, lua_Reader reader, void* dt, const char* chunkname);\n    int             (*_lua_dump)(lua_State* lua, lua_Writer writer, void* data);\n#else\n    void            (*_lua_callk)(lua_State* lua, int nargs, int nresults, lua_KContext ctx, lua_KFunction k);\n    int             (*_lua_pcallk)(lua_State* lua, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k);\n    int             (*_lua_load)(lua_State* lua, lua_Reader reader, void* dt, const char* chunkname, const char* mode);\n    int             (*_lua_dump)(lua_State* lua, lua_Writer writer, void* data, int strip);\n#endif\n\n    // luaL functions\n#ifndef XMI_USE_LUAJIT\n    const char*     (*_luaL_tolstring)(lua_State* lua, int idx, size_t* len);\n    int             (*_luaL_typeerror)(lua_State* lua, int arg, const char* tname);\n#endif\n    int             (*_luaL_getmetafield)(lua_State* lua, int obj, const char* e);\n    int             (*_luaL_callmeta)(lua_State* lua, int obj, const char* e);\n    int             (*_luaL_argerror)(lua_State* lua, int numarg, const char* extramsg);\n    const char*     (*_luaL_checklstring)(lua_State* lua, int arg, size_t* l);\n    const char*     (*_luaL_optlstring)(lua_State* lua, int arg, const char* def, size_t* l);\n    lua_Number      (*_luaL_checknumber)(lua_State* lua, int arg);\n    lua_Number      (*_luaL_optnumber)(lua_State* lua, int arg, lua_Number def);\n    lua_Integer     (*_luaL_checkinteger)(lua_State* lua, int idx);\n    lua_Integer     (*_luaL_optinteger)(lua_State* lua, int arg, lua_Integer def);\n    void            (*_luaL_checkstack)(lua_State* lua, int sz, const char* msg);\n    void            (*_luaL_checktype)(lua_State* lua, int arg, int t);\n    void            (*_luaL_checkany)(lua_State* lua, int arg);\n    int             (*_luaL_newmetatable)(lua_State* lua, const char* tname);\n    void            (*_luaL_setmetatable)(lua_State* lua, const char* tname);\n    void*           (*_luaL_testudata)(lua_State* lua, int ud, const char* tname);\n    void*           (*_luaL_checkudata)(lua_State* lua, int ud, const char* tname);\n    void            (*_luaL_where)(lua_State* lua, int lvl);\n    int             (*_luaL_error)(lua_State* lua, const char* fmt, ...);\n    int             (*_luaL_checkoption)(lua_State* lua, int arg, const char* def, const char* const lst[]);\n    int             (*_luaL_fileresult)(lua_State* lua, int stat, const char* fname);\n    int             (*_luaL_execresult)(lua_State* lua, int stat);\n    void            (*_luaL_setfuncs)(lua_State* lua, const luaL_Reg* l, int nup);\n    int             (*_luaL_loadfilex)(lua_State* lua, const char* filename, const char* mode);\n    int             (*_luaL_loadstring)(lua_State* lua, const char* s);\n\n}xmi_lua_ops_t;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * globals\n */\nextern xmi_lua_ops_t* g_lua_ops;\n\n/* //////////////////////////////////////////////////////////////////////////////////////\n * interfaces\n */\nxmi_extern_c_enter\n\n// setup lua interfaces\nint xmisetup(xmi_lua_ops_t* ops);\n\nxmi_extern_c_leave\n#endif\n\n\n"
  },
  {
    "path": "xmake/scripts/patches/libtool/2.4.3.patch",
    "content": "--- a/__xmake_patched_libtool\n+++ b/__xmake_patched_libtool\n@@ -4921,6 +4921,13 @@ func_mode_link ()\n       func_append finalize_command \" $wl$qarg\"\n       continue\n       ;;\n+    target)\n+      func_append compile_command \" $arg\"\n+      func_append finalize_command \" $arg\"\n+      func_append compiler_flags \" $arg\"\n+      prev=\n+      continue\n+      ;;\n     *)\n       eval \"$prev=\\\"\\$arg\\\"\"\n       prev=\n@@ -5318,7 +5325,7 @@ func_mode_link ()\n       # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization\n       # -stdlib=*            select c++ std lib with clang\n       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \\\n-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \\\n+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*|--target=*| \\\n       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)\n         func_quote_for_eval \"$arg\"\n     arg=$func_quote_for_eval_result\n@@ -5328,6 +5335,14 @@ func_mode_link ()\n         continue\n         ;;\n \n+      -target)\n+        func_append compile_command \" $arg\"\n+        func_append finalize_command \" $arg\"\n+        func_append compiler_flags \" $arg\"\n+        prev=target\n+        continue\n+        ;;\n+\n       # Some other compiler flag.\n       -* | +*)\n         func_quote_for_eval \"$arg\"\n"
  },
  {
    "path": "xmake/scripts/patches/libtool/2.4.4.patch",
    "content": "--- a/__xmake_patched_libtool\n+++ b/__xmake_patched_libtool\n@@ -4921,6 +4921,13 @@ func_mode_link ()\n       func_append finalize_command \" $wl$qarg\"\n       continue\n       ;;\n+    target)\n+      func_append compile_command \" $arg\"\n+      func_append finalize_command \" $arg\"\n+      func_append compiler_flags \" $arg\"\n+      prev=\n+      continue\n+      ;;\n     *)\n       eval \"$prev=\\\"\\$arg\\\"\"\n       prev=\n@@ -5318,7 +5325,7 @@ func_mode_link ()\n       # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization\n       # -stdlib=*            select c++ std lib with clang\n       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \\\n-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \\\n+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*|--target=*| \\\n       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)\n         func_quote_for_eval \"$arg\"\n     arg=$func_quote_for_eval_result\n@@ -5328,6 +5335,14 @@ func_mode_link ()\n         continue\n         ;;\n \n+      -target)\n+        func_append compile_command \" $arg\"\n+        func_append finalize_command \" $arg\"\n+        func_append compiler_flags \" $arg\"\n+        prev=target\n+        continue\n+        ;;\n+\n       -Z*)\n         if test os2 = \"`expr $host : '.*\\(os2\\)'`\"; then\n           # OS/2 uses -Zxxx to specify OS/2-specific options\n"
  },
  {
    "path": "xmake/scripts/patches/libtool/2.4.7.patch",
    "content": "--- a/__xmake_patched_libtool\n+++ b/__xmake_patched_libtool\n@@ -4921,6 +4921,13 @@ func_mode_link ()\n       func_append finalize_command \" $wl$qarg\"\n       continue\n       ;;\n+    target)\n+      func_append compile_command \" $arg\"\n+      func_append finalize_command \" $arg\"\n+      func_append compiler_flags \" $arg\"\n+      prev=\n+      continue\n+      ;;\n     *)\n       eval \"$prev=\\\"\\$arg\\\"\"\n       prev=\n@@ -5318,7 +5325,7 @@ func_mode_link ()\n       # -fuse-ld=*           Linker select flags for GCC\n       # -Wa,*                Pass flags directly to the assembler\n       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \\\n-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \\\n+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*|--target=*| \\\n       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \\\n       -specs=*|-fsanitize=*|-fuse-ld=*|-Wa,*)\n         func_quote_arg pretty \"$arg\"\n@@ -5328,6 +5335,14 @@ func_mode_link ()\n         continue\n         ;;\n \n+      -target)\n+        func_append compile_command \" $arg\"\n+        func_append finalize_command \" $arg\"\n+        func_append compiler_flags \" $arg\"\n+        prev=target\n+        continue\n+        ;;\n+\n       -Z*)\n         if test os2 = \"`expr $host : '.*\\(os2\\)'`\"; then\n           # OS/2 uses -Zxxx to specify OS/2-specific options\n"
  },
  {
    "path": "xmake/scripts/patches/libtool/2.5.0.patch",
    "content": "--- a/__xmake_patched_libtool\n+++ b/__xmake_patched_libtool\n@@ -4921,6 +4921,13 @@ func_mode_link ()\n       func_append finalize_command \" $wl$qarg\"\n       continue\n       ;;\n+    target)\n+      func_append compile_command \" $arg\"\n+      func_append finalize_command \" $arg\"\n+      func_append compiler_flags \" $arg\"\n+      prev=\n+      continue\n+      ;;\n     *)\n       eval \"$prev=\\\"\\$arg\\\"\"\n       prev=\n@@ -5318,7 +5325,7 @@ func_mode_link ()\n       # -Wa,*                Pass flags directly to the assembler\n       # -Werror, -Werror=*   Report (specified) warnings as errors\n       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \\\n-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \\\n+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*|--target=*| \\\n       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-no-canonical-prefixes| \\\n       -stdlib=*|-rtlib=*|--unwindlib=*| \\\n       -specs=*|-fsanitize=*|-fno-sanitize*|-shared-libsan|-static-libsan| \\\n@@ -5328,6 +5335,14 @@ func_mode_link ()\n         continue\n         ;;\n \n+      -target)\n+        func_append compile_command \" $arg\"\n+        func_append finalize_command \" $arg\"\n+        func_append compiler_flags \" $arg\"\n+        prev=target\n+        continue\n+        ;;\n+\n       -Z*)\n         if test os2 = \"`expr $host : '.*\\(os2\\)'`\"; then\n           # OS/2 uses -Zxxx to specify OS/2-specific options\n"
  },
  {
    "path": "xmake/scripts/patches/libtool/2.6.0.patch",
    "content": "--- a/__xmake_patched_libtool\n+++ b/__xmake_patched_libtool\n@@ -4921,6 +4921,13 @@ func_mode_link ()\n       func_append finalize_command \" $wl$qarg\"\n       continue\n       ;;\n+    target)\n+      func_append compile_command \" $arg\"\n+      func_append finalize_command \" $arg\"\n+      func_append compiler_flags \" $arg\"\n+      prev=\n+      continue\n+      ;;\n     *)\n       eval \"$prev=\\\"\\$arg\\\"\"\n       prev=\n@@ -5328,6 +5335,14 @@ func_mode_link ()\n         continue\n         ;;\n \n+      -target)\n+        func_append compile_command \" $arg\"\n+        func_append finalize_command \" $arg\"\n+        func_append compiler_flags \" $arg\"\n+        prev=target\n+        continue\n+        ;;\n+\n       -Z*)\n         if test os2 = \"`expr $host : '.*\\(os2\\)'`\"; then\n           # OS/2 uses -Zxxx to specify OS/2-specific options\n"
  },
  {
    "path": "xmake/scripts/profile-unix.fish",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki\n# @homepage    profile-unix.fish\n#\n\n# register PATH\nstring match --regex --quiet \"(^|:)$XMAKE_ROOTDIR(:|\\$)\" \"$PATH\" || \\\n    export PATH=\"$XMAKE_ROOTDIR:$PATH\"\n\n# register environments\nexport XMAKE_SHELL=fish\n\n# register completions\n. \"$XMAKE_PROGRAM_DIR/scripts/completions/register-completions.fish\"\n\n"
  },
  {
    "path": "xmake/scripts/profile-unix.sh",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki\n# @homepage    profile-unix.sh\n#\n\n# register PATH\n[[ \"$PATH\" =~ (^|:)\"$XMAKE_ROOTDIR\"(:|$) ]] || export PATH=\"$XMAKE_ROOTDIR:$PATH\"\n\n# register completions\nif   [[ -n \"$ZSH_VERSION\" ]]; then\n  export XMAKE_SHELL=zsh\n  . \"$XMAKE_PROGRAM_DIR/scripts/completions/register-completions.zsh\"\nelif [[ -n \"$BASH_VERSION\" ]]; then\n  export XMAKE_SHELL=bash\n  . \"$XMAKE_PROGRAM_DIR/scripts/completions/register-completions.bash\"\nfi\n\n# register virtualenvs\n. \"$XMAKE_PROGRAM_DIR/scripts/virtualenvs/register-virtualenvs.sh\"\n\n"
  },
  {
    "path": "xmake/scripts/profile-win.ps1",
    "content": "# PowerShell parameter completion for xmake\nRegister-ArgumentCompleter -Native -CommandName xmake -ScriptBlock {\n    param($commandName, $wordToComplete, $cursorPosition)\n    $complete = \"$wordToComplete\"\n    if (-not $commandName) {\n        $complete = $complete + \" \"\n    }\n    $oldenv = $env:XMAKE_SKIP_HISTORY\n    $env:XMAKE_SKIP_HISTORY = 1\n    $results = xmake lua \"private.utils.complete\" $cursorPosition \"nospace-json\" \"$complete\" | ConvertFrom-Json | Sort-Object -Property value\n    $results | ForEach-Object {\n        $hasdesc = [bool] $_.psobject.Properties['description']\n        if ($hasdesc) {\n            $desc = \" - $($_.description)\"\n        } else {\n            $desc = \"\"\n        }\n        [System.Management.Automation.CompletionResult]::new($_.value, \"$($_.value)$desc\", 'ParameterValue', $_.value)\n    }\n    $env:XMAKE_SKIP_HISTORY = $oldenv\n}\n\n# PowerShell parameter completion for xrepo\nRegister-ArgumentCompleter -Native -CommandName xrepo -ScriptBlock {\n    param($commandName, $wordToComplete, $cursorPosition)\n    $complete = \"$wordToComplete\"\n    if (-not $commandName) {\n        $complete = $complete + \" \"\n    }\n    $oldenv = $env:XMAKE_SKIP_HISTORY\n    $env:XMAKE_SKIP_HISTORY = 1\n    $results = xmake lua \"private.xrepo.complete\" $cursorPosition \"nospace-json\" \"$complete\" | ConvertFrom-Json | Sort-Object -Property value\n    $results | ForEach-Object {\n        $hasdesc = [bool] $_.psobject.Properties['description']\n        if ($hasdesc) {\n            $desc = \" - $($_.description)\"\n        } else {\n            $desc = \"\"\n        }\n        [System.Management.Automation.CompletionResult]::new($_.value, \"$($_.value)$desc\", 'ParameterValue', $_.value)\n    }\n    $env:XMAKE_SKIP_HISTORY = $oldenv\n}"
  },
  {
    "path": "xmake/scripts/run.vbs",
    "content": "Set UAC = CreateObject(\"Shell.Application\")\n\nConst PROCESS = \"xmake.exe\"\n\nIf WScript.Arguments.count < 2 Then\n    WScript.echo \"Help: run <flag> <command> [args]\"\n    WScript.echo \"    flags:\"\n    WScript.echo \"        N - normal\"\n    WScript.echo \"        A - run as admin\"\n    WScript.echo \"        W - wait xmake to exit\"\n    WScript.echo \"        You should use 'N' if no speical flags needed\"\n    WScript.echo \"    e.g.:  run WA xmake-install.exe /Q\"\nElse\n    Dim flags\n    Dim program\n    flags = UCase(WScript.arguments(0))\n    program = WScript.arguments(1)\n\n    Dim verb\n    Dim wait\n    If InStr(flags, \"A\") <> 0 Then\n        verb = \"runas\"\n    Else\n        verb = \"open\"\n    End If\n\n    If InStr(flags, \"W\") <> 0 Then\n        Dim counter\n        counter = 0\n        Dim sQuery \n        sQuery = \"select * from win32_process where name='\" & PROCESS & \"'\"\n        Do\n            Set SVC = getobject(\"winmgmts:root\\cimv2\")\n            Set cproc = SVC.execquery(sQuery)\n            iniproc = cproc.count\n            counter = counter + 1\n            If counter >= 20 Then\n                WScript.echo \"xmake still hasn't exited after 10 seconds, aborting...\"\n                WScript.quit 1\n            End If\n            If iniproc <> 0 Then\n                WScript.echo \"Waiting for xmake to exit...\"\n                wscript.sleep 500\n            End If\n        Loop Until iniproc = 0\n        \n        Set cproc = Nothing\n        Set SVC = Nothing\n    End If\n    \n    Dim ucCount\n    Dim args\n    args = \"\"\n    For ucCount = 2 To (WScript.Arguments.count - 1) Step 1\n        Dim carg\n        if InStr(WScript.Arguments(ucCount), \" \") <> 0 Then\n            carg = \"\"\"\" & Replace(WScript.Arguments(ucCount), \"\"\"\", \"\"\"\"\"\") & \"\"\"\"\n        ElseIf Len(WScript.Arguments(ucCount)) = 0 Then\n            carg = \"\"\"\"\"\"\n        Else\n            carg = WScript.Arguments(ucCount)\n        End If\n        args = args & \" \" & carg\n    Next\n\n    UAC.ShellExecute program, args, \"\", verb, 1\nEnd If\n"
  },
  {
    "path": "xmake/scripts/unzip.ps1",
    "content": "#!/usr/bin/env pwsh\n#Requires -version 5\n\nparam (\n    [string]$archivefile,\n    [string]$outputdir\n)\n\n& {\n    function writeErrorTip($msg) {\n        Write-Host $msg -BackgroundColor Red -ForegroundColor White\n    }\n\n    function unzip {\n        try {\n            Expand-Archive -Path $archivefile -DestinationPath $outputdir\n        } catch {\n            writeErrorTip 'Unzip failed!'\n            throw\n        }\n    }\n\n    unzip\n}\n"
  },
  {
    "path": "xmake/scripts/update-script.bat",
    "content": "@echo off\n\necho Removing old files\ncd /d \"%~1\"\ndel actions core includes languages modules platforms plugins repository rules scripts templates themes /S /Q /F >nul\necho Copying from temp directory to \"%~1\"\n\nif exist \"%WINDIR%\\System32\\Robocopy.exe\" (\n    robocopy \"%~2\" \"%~1\" /S /IS /NFL /NDL /NJH /NJS >nul\n) else (\n    if exist \"%WINDIR%\\SysWOW64\\Robocopy.exe\" (\n        robocopy \"%~2\" \"%~1\" /S /IS /NFL /NDL /NJH /NJS >nul\n    ) else (\n        xcopy \"%~2\" \"%~1\" /S /Y /Q >nul \n    )\n)\n"
  },
  {
    "path": "xmake/scripts/update-script.sh",
    "content": "#!/bin/sh\n\ncd \"$1\"\nrm -rf actions core includes languages modules platforms plugins repository rules scripts templates themes\ncp -rf \"$2\" \"$1/..\""
  },
  {
    "path": "xmake/scripts/virtualenvs/register-virtualenvs.sh",
    "content": "# A cross-platform build utility based on Lua\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http:##www.apache.org#licenses#LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Copyright (C) 2022-present, Xmake Open Source Community.\n#\n# @author      ruki, xq114\n# @homepage    register-virtualenvs.sh\n#\n\nif test \"${XMAKE_ROOTDIR}\"; then\n    export XMAKE_PROGRAM_FILE=${XMAKE_ROOTDIR}/xmake\nelse\n    local -i XMAKE_ROOTDIR=~/.local/bin\n    export XMAKE_PROGRAM_FILE=xmake\nfi\n\nfunction xrepo {\n    if [ $# -ge 2 ] && [ \"$1\" = \"env\" ]; then\n        local cmd=\"${2-x}\"\n        case \"$cmd\" in\n            shell)\n                if test \"${XMAKE_PROMPT_BACKUP}\"; then\n                    PS1=\"${XMAKE_PROMPT_BACKUP}\"\n                    source \"${XMAKE_ENV_BACKUP}\" || return 1\n                    unset XMAKE_PROMPT_BACKUP\n                    unset XMAKE_ENV_BACKUP\n                fi\n                \"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info config || return 1\n                local currentTest=\"$(\"$XMAKE_PROGRAM_FILE\" lua --quiet private.xrepo.action.env)\" || return 1\n                if [ ! -z \"$currentTest\" ]; then\n                    echo \"error: corrupt xmake.lua detected in the current directory!\"\n                    return 1\n                fi\n                local prompt=\"$(\"$XMAKE_PROGRAM_FILE\" lua --quiet private.xrepo.action.env.info prompt)\" || return 1\n                if [ -z \"${prompt+x}\" ]; then\n                    return 1\n                fi\n                local activateCommand=\"$(\"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info script.bash)\" || return 1\n                export XMAKE_ENV_BACKUP=\"$(\"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info envfile)\"\n                export XMAKE_PROMPT_BACKUP=\"${PS1}\"\n                \"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info backup.bash 1>\"$XMAKE_ENV_BACKUP\"\n                eval \"$activateCommand\"\n                PS1=\"${prompt} $PS1\"\n                ;;\n            quit)\n                if test \"${XMAKE_PROMPT_BACKUP}\"; then\n                    PS1=\"${XMAKE_PROMPT_BACKUP}\"\n                    source \"${XMAKE_ENV_BACKUP}\" || return 1\n                    unset XMAKE_PROMPT_BACKUP\n                    unset XMAKE_ENV_BACKUP\n                fi\n                ;;\n            -b|--bind)\n                if [ \"$4\" = \"shell\" ]; then\n                    local bnd=\"${3-x}\"\n                    if test \"${XMAKE_PROMPT_BACKUP}\"; then\n                        PS1=\"${XMAKE_PROMPT_BACKUP}\"\n                        source \"${XMAKE_ENV_BACKUP}\" || return 1\n                        unset XMAKE_PROMPT_BACKUP\n                        unset XMAKE_ENV_BACKUP\n                    fi\n                    pushd ${XMAKE_ROOTDIR} 1>/dev/null\n                    \"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info config $bnd || popd 1>/dev/null && return 1\n                    local prompt=\"$(\"$XMAKE_PROGRAM_FILE\" lua --quiet private.xrepo.action.env.info prompt $bnd)\" || popd 1>/dev/null && return 1\n                    if [ -z \"${prompt+x}\" ]; then\n                        popd 1>/dev/null\n                        echo \"error: invalid environment!\"\n                        return 1\n                    fi\n                    local activateCommand=\"$(\"$XMAKE_PROGRAM_FILE\" lua --quiet private.xrepo.action.env.info script.bash $bnd)\" || popd 1>/dev/null && return 1\n                    export XMAKE_ENV_BACKUP=\"$(\"$XMAKE_PROGRAM_FILE\" lua private.xrepo.action.env.info envfile $bnd)\"\n                    export XMAKE_PROMPT_BACKUP=\"${PS1}\"\n                    \"$XMAKE_PROGRAM_FILE\" lua --quiet private.xrepo.action.env.info backup.bash $bnd 1>\"$XMAKE_ENV_BACKUP\"\n                    eval \"$activateCommand\"\n                    popd 1>/dev/null\n                    PS1=\"${prompt} $PS1\"\n                else\n                    \"$XMAKE_PROGRAM_FILE\" lua private.xrepo \"$@\"\n                fi\n                ;;\n            *)\n                \"$XMAKE_PROGRAM_FILE\" lua private.xrepo \"$@\"\n                ;;\n        esac\n    else\n        \"$XMAKE_PROGRAM_FILE\" lua private.xrepo \"$@\"\n    fi\n}\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/Xmake.Defaults.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"XmakePathsResolve\">\n    <_XmakeProgramDir>$(XmakeProgramDir)</_XmakeProgramDir>\n    <_XmakeProgramFile>$(XmakeProgramFile)</_XmakeProgramFile>\n    <_XmakeProjectDir>$(XmakeProjectDir)</_XmakeProjectDir>\n    <_XmakeScriptDir>$(XmakeScriptDir)</_XmakeScriptDir>\n\n    <!-- resolve if they are relative paths -->\n    <_XmakeProgramDir Condition=\"!$([System.IO.Path]::IsPathRooted('$(_XmakeProgramDir)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(_XmakeProgramDir)'))</_XmakeProgramDir>\n    <_XmakeProgramFile Condition=\"!$([System.IO.Path]::IsPathRooted('$(_XmakeProgramFile)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(_XmakeProgramFile)'))</_XmakeProgramFile>\n    <_XmakeProjectDir Condition=\"!$([System.IO.Path]::IsPathRooted('$(_XmakeProjectDir)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(_XmakeProjectDir)'))</_XmakeProjectDir>\n    <_XmakeScriptDir Condition=\"!$([System.IO.Path]::IsPathRooted('$(_XmakeScriptDir)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(_XmakeScriptDir)'))</_XmakeScriptDir>\n\n    <!-- normalize paths -->\n    <XmakeProgramDir>$([System.IO.Path]::GetFullPath('$(_XmakeProgramDir)'))</XmakeProgramDir>\n    <XmakeProgramFile>$([System.IO.Path]::GetFullPath('$(_XmakeProgramFile)'))</XmakeProgramFile>\n    <XmakeProjectDir>$([System.IO.Path]::GetFullPath('$(_XmakeProjectDir)'))</XmakeProjectDir>\n    <XmakeScriptDir>$([System.IO.Path]::GetFullPath('$(_XmakeScriptDir)'))</XmakeScriptDir>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/Xmake.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"XmakePropsInit\">\n    <!-- initialize this first to allow `Condition=\"'$(XmakeMode)|$(XmakeArch)' == 'release|x86'\"` in custom props file -->\n    <XmakeMode Condition=\"'$(XmakeMode)' == ''\">$(Configuration)</XmakeMode>\n    <XmakeMode Condition=\"'$(XmakeMode)' == ''\">release</XmakeMode>\n\n    <XmakeArch Condition=\"'$(XmakeArch)' == '' And '$(Platform.ToLower())' == 'win32'\">x86</XmakeArch>\n    <XmakeArch Condition=\"'$(XmakeArch)' == '' And '$(Platform.ToLower())' != 'win32'\">$(Platform)</XmakeArch>\n    <XmakeArch Condition=\"'$(XmakeArch)' == ''\">x86</XmakeArch>\n  </PropertyGroup>\n\n  <ImportGroup Label=\"CustomSettings\">\n    <!--only search 2 levels to avoid accidentally import-->\n    <Import Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.props')\"\n      Project=\"$(MSBuildProjectDirectory)\\Xmake.Custom.props\" />\n    <Import Condition=\"!Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.props') And Exists('$(MSBuildProjectDirectory)\\..\\Xmake.Custom.props')\"\n      Project=\"$(MSBuildProjectDirectory)\\..\\Xmake.Custom.props\" />\n  </ImportGroup>\n\n  <PropertyGroup Label=\"XmakePropsFallback\">\n    <XmakeBasename Condition=\"'$(XmakeBasename)' == ''\">$(XmakeTarget)</XmakeBasename>\n    <XmakeBasename Condition=\"'$(XmakeBasename)' == ''\">$(TargetName)</XmakeBasename>\n    <XmakeBasename Condition=\"'$(XmakeBasename)' == ''\">$(MSBuildProjectName)</XmakeBasename>\n\n    <XmakeKind Condition=\"'$(XmakeKind)' == ''\">binary</XmakeKind>\n    <XmakePlat Condition=\"'$(XmakePlat)' == ''\">windows</XmakePlat>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"XmakePathsFallback\">\n    <XmakeBuilDDir Condition=\"'$(XmakeBuilDDir)' == ''\">$(XmakeProjectDir)\\build</XmakeBuilDDir>\n    <XmakeTargetDir Condition=\"'$(XmakeTargetDir)' == ''\">$(XmakeBuilDDir)\\$(XmakePlat)\\$(XmakeArch)\\$(XmakeMode)</XmakeTargetDir>\n    <XmakeConfigFileDir Condition=\"'$(XmakeConfigFileDir)' == ''\">$(XmakeBuilDDir)\\$(XmakePlat)\\$(XmakeArch)\\$(XmakeMode)</XmakeConfigFileDir>\n\n    <XmakeConfigDir Condition=\"'$(XmakeConfigDir)' == ''\">$(XMAKE_CONFIGDIR)</XmakeConfigDir>\n    <XmakeConfigDir Condition=\"'$(XmakeConfigDir)' == ''\">$(XmakeProjectDir)</XmakeConfigDir>\n\n    <XmakeRunDir Condition=\"'$(XmakeRunDir)' == ''\">$(XmakeTargetDir)</XmakeRunDir>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"XmakeFlagsFallback\">\n    <XmakeCleanAll Condition=\"'$(XmakeCleanAll)' == ''\">true</XmakeCleanAll>\n    <XmakeVerbose Condition=\"'$(XmakeVerbose)' == ''\">false</XmakeVerbose>\n    <XmakeDiagnosis Condition=\"'$(XmakeDiagnosis)' == ''\">false</XmakeDiagnosis>\n    <XmakeRebuildFile Condition=\"'$(XmakeRebuildFile)' == ''\">false</XmakeRebuildFile>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(WindowsTargetPlatformVersion)' == '' And '$(XmakeWindowsSdkVersion)' != ''\">\n    <WindowsTargetPlatformVersion>$(XmakeWindowsSdkVersion)</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(PlatformToolset)' == ''\">\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '10.0'\">v100</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '11.0'\">v110</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '12.0'\">v120</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '14.0'\">v140</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '15.0'\">v141</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '16.0'\">v142</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '17.0'\">v143</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '18.0'\">v145</PlatformToolset>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"AdditionalProps\">\n    <UseOfMfc Condition=\"'$(XmakeMfcKind)' != ''\">$(XmakeMfcKind)</UseOfMfc>\n    <CharacterSet Condition=\"'$(CharacterSet)' == '' And ($(XmakeDefines.Contains(';UNICODE;')) Or $(XmakeDefines.EndsWith(';UNICODE')) Or $(XmakeDefines.StartsWith('UNICODE;')) Or $(XmakeDefines.Equals('UNICODE')))\">Unicode</CharacterSet>\n    <CharacterSet Condition=\"'$(CharacterSet)' == ''\">MultiByte</CharacterSet>\n  </PropertyGroup>\n\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <Choose>\n    <When Condition=\"'$(XmakeKind)' == 'binary'\">\n      <PropertyGroup>\n        <ConfigurationType>Application</ConfigurationType>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(XmakeKind)' == 'shared'\">\n      <PropertyGroup>\n        <ConfigurationType>DynamicLibrary</ConfigurationType>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(XmakeKind)' == 'static'\">\n      <PropertyGroup>\n        <ConfigurationType>StaticLibrary</ConfigurationType>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(XmakeKind)' == 'phony'\">\n      <PropertyGroup>\n        <ConfigurationType>Unknown</ConfigurationType>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(XmakeKind)' == 'headeronly'\">\n      <PropertyGroup>\n        <ConfigurationType>Unknown</ConfigurationType>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(XmakeKind)' == 'moduleonly'\">\n      <PropertyGroup>\n        <ConfigurationType>Unknown</ConfigurationType>\n      </PropertyGroup>\n    </When>\n  </Choose>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);$(XmakeDefines)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(XmakeIncludeDirs)</AdditionalIncludeDirectories>\n      <ForcedIncludeFiles>$(XmakeForceIncludes)</ForcedIncludeFiles>\n      <AdditionalOptions>%(AdditionalOptions) $(XmakeCFlags) $(XmakeCXFlags) $(XmakeCXXFlags)</AdditionalOptions>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx11'))\">stdcpp11</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx14'))\">stdcpp14</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx17'))\">stdcpp17</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx1z'))\">stdcpp17</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx20'))\">stdcpp20</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx2a'))\">stdcpp20</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx23'))\">stdcpplatest</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxx2b'))\">stdcpplatest</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('cxxlatest'))\">stdcpplatest</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx11'))\">stdcpp11</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx14'))\">stdcpp14</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx17'))\">stdcpp17</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx1z'))\">stdcpp17</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx20'))\">stdcpp20</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx2a'))\">stdcpp20</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx23'))\">stdcpplatest</LanguageStandard>\n      <LanguageStandard Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('gnuxx2b'))\">stdcpplatest</LanguageStandard>\n      <LanguageStandard_C Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('c11'))\">stdc11</LanguageStandard_C>\n      <LanguageStandard_C Condition=\"'%(LanguageStandard)' == '' And $(XmakeLanguages.Contains('c17'))\">stdc17</LanguageStandard_C>\n      <LanguageStandard_C Condition=\"'%(LanguageStandard_C)' == '' And $(XmakeLanguages.Contains('gnu11'))\">stdc11</LanguageStandard_C>\n      <LanguageStandard_C Condition=\"'%(LanguageStandard_C)' == '' And $(XmakeLanguages.Contains('gnu17'))\">stdc17</LanguageStandard_C>\n      <PrecompiledHeader Condition=\"'%(PrecompiledHeader)' == '' And $(XmakePrecompiledHeader.Contains('.h'))\">Use</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'%(PrecompiledHeaderFile)' == '' And $(XmakePrecompiledHeader.Contains('.h'))\">$(XmakeProjectDir)\\$(XmakePrecompiledHeader)</PrecompiledHeaderFile>\n      <ForcedIncludeFiles Condition=\"'%(ForcedIncludeFiles)' == '' And $(XmakePrecompiledHeader.Contains('.h'))\">$(XmakeProjectDir)\\$(XmakePrecompiledHeader);%(ForcedIncludeFiles)</ForcedIncludeFiles>\n    </ClCompile>\n\n    <Link>\n      <SubSystem Condition=\"'%(SubSystem)' == '' And $(XmakeSubSystem.Contains('console'))\">Console</SubSystem>\n      <SubSystem Condition=\"'%(SubSystem)' == '' And $(XmakeSubSystem.Contains('windows'))\">Windows</SubSystem>\n    </Link>\n\n    <ResourceCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);$(XmakeDefines)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(XmakeIncludeDirs)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n  </ItemDefinitionGroup>\n\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n\n  <ItemGroup>\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml\">\n      <Context>Project</Context>\n    </PropertyPageSchema>\n  </ItemGroup>\n\n  <ImportGroup Label=\"ExtensionSettings\">\n    <Import Condition=\"'$(XmakeCudaVersion)' != '' And Exists('$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).props')\"\n      Project=\"$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).props\" />\n  </ImportGroup>\n\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Condition=\"Exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\"\n      Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" />\n  </ImportGroup>\n\n  <PropertyGroup Label=\"GlobalsFallback\">\n    <TargetName Condition=\"'$(XmakeFilename)' == ''\">$(XmakeBasename)</TargetName>\n    <TargetName Condition=\"'$(XmakeFilename)' != ''\">$([System.IO.Path]::GetFileNameWithoutExtension('$(XmakeFilename)'))</TargetName>\n    <TargetExt Condition=\"'$(XmakeFilename)' != ''\">$([System.IO.Path]::GetExtension('$(XmakeFilename)'))</TargetExt>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Path\">\n    <LibraryPath>$(XmakeLinkDirs);$(LibraryPath)</LibraryPath>\n    <OutDir>$(XmakeTargetDir)\\</OutDir>\n    <IntDir>$(XmakeBuilDDir)\\.vs\\$(TargetName)\\$(XmakeArch)\\$(XmakeMode)\\</IntDir>\n    <SourcePath>$(XmakeSourceDirs);$(SourcePath)</SourcePath>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Debugger\">\n    <LocalDebuggerWorkingDirectory>$(XmakeRunDir)</LocalDebuggerWorkingDirectory>\n    <LocalDebuggerEnvironment>$(XmakeRunEnvs)\n$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>\n    <LocalDebuggerCommandArguments>$(XmakeRunArgs)</LocalDebuggerCommandArguments>\n    <LocalDebuggerMergeEnvironment>true</LocalDebuggerMergeEnvironment>\n    <RemoteDebuggerWorkingDirectory>$(XmakeRunDir)</RemoteDebuggerWorkingDirectory>\n    <RemoteDebuggerEnvironment>$(XmakeRunEnvs)\n$(RemoteDebuggerEnvironment)</RemoteDebuggerEnvironment>\n    <RemoteDebuggerCommandArguments>$(XmakeRunArgs)</RemoteDebuggerCommandArguments>\n  </PropertyGroup>\n\n  <!-- Common files -->\n  <ItemGroup>\n    <None Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.props')\"\n      Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.props\" />\n    <None Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.targets')\"\n      Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.targets\" />\n    <None Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.items')\"\n      Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.items\" />\n    <None Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.items.filters')\"\n      Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.items.filters\" />\n    <None Condition=\"'$(XmakeScriptDir)' != '$(XmakeProjectDir)' And Exists('$(XmakeScriptDir)\\xmake.lua')\"\n      Include=\"$(XmakeScriptDir)\\xmake.lua\" />\n  </ItemGroup>\n\n  <Import Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.items')\"\n    Project=\"$(MSBuildProjectDirectory)\\Xmake.Custom.items\" />\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/Xmake.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n    <Import Condition=\"'$(XmakeCudaVersion)' != '' And Exists('$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).targets')\"\n      Project=\"$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).targets\" />\n  </ImportGroup>\n\n  <PropertyGroup Label=\"XmakePathsResolve\">\n    <XmakeBuilDDirResolved>$(XmakeBuilDDir)</XmakeBuilDDirResolved>\n    <XmakeTargetDirResolved>$(XmakeTargetDir)</XmakeTargetDirResolved>\n    <XmakeConfigDirResolved>$(XmakeConfigDir)</XmakeConfigDirResolved>\n    <XmakeConfigFileDirResolved>$(XmakeConfigFileDir)</XmakeConfigFileDirResolved>\n    <XmakeRunDirResolved>$(XmakeRunDir)</XmakeRunDirResolved>\n\n    <!-- resolve if they are relative paths -->\n    <XmakeBuilDDirResolved Condition=\"!$([System.IO.Path]::IsPathRooted('$(XmakeBuilDDirResolved)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(XmakeBuilDDirResolved)'))</XmakeBuilDDirResolved>\n    <XmakeTargetDirResolved Condition=\"!$([System.IO.Path]::IsPathRooted('$(XmakeTargetDirResolved)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(XmakeTargetDirResolved)'))</XmakeTargetDirResolved>\n    <XmakeConfigDirResolved Condition=\"!$([System.IO.Path]::IsPathRooted('$(XmakeConfigDirResolved)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(XmakeConfigDirResolved)'))</XmakeConfigDirResolved>\n    <XmakeConfigFileDirResolved Condition=\"!$([System.IO.Path]::IsPathRooted('$(XmakeConfigFileDirResolved)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(XmakeConfigFileDirResolved)'))</XmakeConfigFileDirResolved>\n    <XmakeRunDirResolved Condition=\"!$([System.IO.Path]::IsPathRooted('$(XmakeRunDirResolved)'))\">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\$(XmakeRunDirResolved)'))</XmakeRunDirResolved>\n\n    <!-- normalize paths -->\n    <XmakeBuilDDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeBuilDDirResolved)/'))</XmakeBuilDDirResolved>\n    <XmakeTargetDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeTargetDirResolved)/'))</XmakeTargetDirResolved>\n    <XmakeConfigDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeConfigDirResolved)/'))</XmakeConfigDirResolved>\n    <XmakeConfigFileDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeConfigFileDirResolved)/'))</XmakeConfigFileDirResolved>\n    <XmakeRunDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeRunDirResolved)/'))</XmakeRunDirResolved>\n\n    <!-- these paths resolved in Xmake.Default.props, just normalize -->\n    <XmakeProgramDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeProgramDir)/'))</XmakeProgramDirResolved>\n    <XmakeProgramFileResolved>$([System.IO.Path]::GetFullPath('$(XmakeProgramFile)'))</XmakeProgramFileResolved>\n    <XmakeProjectDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeProjectDir)/'))</XmakeProjectDirResolved>\n    <XmakeScriptDirResolved>$([System.IO.Path]::GetFullPath('$(XmakeScriptDir)/'))</XmakeScriptDirResolved>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"XmakeInternal\">\n    <_XmakeProjectFlag Condition=\"'$(XmakeProjectFile)' != ''\">-F \"$(XmakeProjectFile)\"</_XmakeProjectFlag>\n    <_XmakeProjectFlag Condition=\"'$(XmakeProjectFile)' == ''\">-P .</_XmakeProjectFlag>\n\n    <_XmakeCommonFlags>$(XmakeCommonFlags.Trim())</_XmakeCommonFlags>\n    <_XmakeCommonFlags Condition=\"$(XmakeVerbose)\">-v $(_XmakeCommonFlags.Trim())</_XmakeCommonFlags>\n    <_XmakeCommonFlags Condition=\"$(XmakeDiagnosis)\">-D $(_XmakeCommonFlags.Trim())</_XmakeCommonFlags>\n    <_XmakeCommonFlags>-y $(_XmakeCommonFlags.Trim()) $(_XmakeProjectFlag)</_XmakeCommonFlags>\n\n    <_XmakeOutFlag>-o \"$([MSBuild]::MakeRelative('$(XmakeProjectDirResolved)', '$(XmakeBuilDDirResolved)').TrimEnd('\\').TrimEnd('/'))\"</_XmakeOutFlag>\n\n    <_XmakeConfigFlags>$(XmakeConfigFlags.Trim())</_XmakeConfigFlags>\n    <_XmakeConfigFlags>-p $(XmakePlat) -m $(XmakeMode) -a $(XmakeArch) $(_XmakeOutFlag) $(_XmakeConfigFlags.Trim())</_XmakeConfigFlags>\n\n    <_XmakeBuildFileFlags>$(_XmakeBuildFlags.Trim())</_XmakeBuildFileFlags>\n    <_XmakeBuildFileFlags Condition=\"$(XmakeRebuildFile)\">$(_XmakeBuildFileFlags.Trim()) -r</_XmakeBuildFileFlags>\n\n    <_XmakeCleanFlags>$(XmakeCleanFlags.Trim())</_XmakeCleanFlags>\n    <_XmakeCleanFlags Condition=\"$(XmakeCleanAll)\">-a $(_XmakeCleanFlags.Trim())</_XmakeCleanFlags>\n\n    <_XmakeBuildFlags>$(_XmakeBuildFlags.Trim())</_XmakeBuildFlags>\n    <_XmakeBuildFileFlags>$(_XmakeBuildFileFlags.Trim())</_XmakeBuildFileFlags>\n    <_XmakeCleanFlags>$(_XmakeCleanFlags.Trim())</_XmakeCleanFlags>\n    <_XmakeConfigFlags>$(_XmakeConfigFlags.Trim())</_XmakeConfigFlags>\n    <_XmakeCommonFlags>$(_XmakeCommonFlags.Trim())</_XmakeCommonFlags>\n    <_XmakeTarget>\"$(XmakeTarget.Trim())\"</_XmakeTarget>\n\n    <_XmakeExecutable>\"$([System.IO.Path]::GetFullPath('$(XmakeProgramFileResolved)'))\"</_XmakeExecutable>\n    <_XmakeEnv>\n      pushd $(XmakeProjectDirResolved)\n      set XMAKE_CONFIGDIR=$(XmakeConfigDirResolved.TrimEnd('\\').TrimEnd('/'))\n      set XMAKE_PROGRAM_DIR=$(XmakeProgramDirResolved.TrimEnd('\\').TrimEnd('/'))\n      set XMAKE_PROGRAM_FILE=$(XmakeProgramFileResolved.TrimEnd('\\').TrimEnd('/'))\n      set XMAKE_SKIP_HISTORY=1\n      set XMAKE_IN_VSTUDIO=1\n    </_XmakeEnv>\n    <_XmakeEnv Condition=\"$(XmakeDiagnosis)\">\n      $(_XmakeEnv)\n      echo XMAKE_CONFIGDIR=%25XMAKE_CONFIGDIR%25\n      echo XMAKE_PROGRAM_DIR=%25XMAKE_PROGRAM_DIR%25\n      echo XMAKE_PROGRAM_FILE=%25XMAKE_PROGRAM_FILE%25\n      echo CD=%25CD%25\n    </_XmakeEnv>\n  </PropertyGroup>\n\n  <Target Name=\"_XmakeProjCheck\">\n    <Warning Condition=\"'$(XmakeCudaVersion)' != '' And !Exists('$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).targets')\"\n      Text=\"File '$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).targets' not found\" />\n    <Warning Condition=\"'$(XmakeCudaVersion)' != '' And !Exists('$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).props')\"\n      Text=\"File '$(VCTargetsPath)\\BuildCustomizations\\CUDA $(XmakeCudaVersion).props' not found\" />\n    <Error Condition=\"!Exists('$(XmakeProgramFileResolved)')\"\n      Text=\"xmake.exe not found at '$(XmakeProgramFileResolved)'\" />\n    <Error Condition=\"'$(XmakeProjectFile)' == '' And !Exists('$(XmakeProjectDirResolved)\\xmake.lua')\"\n      Text=\"xmake.lua not found at '$(XmakeProjectDirResolved)', please set XmakeProjectDir in vcxproj file\" />\n    <Error Condition=\"'$(XmakeProjectFile)' != '' And !Exists('$(XmakeProjectDirResolved)\\$(XmakeProjectFile)')\"\n      Text=\"$(XmakeProjectFile) not found at '$(XmakeProjectDirResolved)', please set XmakeProjectDir in vcxproj file\" />\n  </Target>\n  <Target Name=\"_XmakeConfig\" DependsOnTargets=\"_XmakeProjCheck\">\n    <Message Text=\"$xmake config $(_XmakeCommonFlags) $(_XmakeConfigFlags)\" Importance=\"High\" />\n    <Exec Command=\"$(_XmakeEnv)\n      $(_XmakeExecutable) config $(_XmakeCommonFlags) $(_XmakeConfigFlags)\" EchoOff=\"true\" />\n  </Target>\n  <Target Name=\"_XmakeBuild\" DependsOnTargets=\"_XmakeProjCheck\">\n    <Message Text=\"$xmake build $(_XmakeCommonFlags) $(_XmakeBuildFlags) $(_XmakeTarget)\" Importance=\"High\" />\n    <Exec Command=\"$(_XmakeEnv)\n      $(_XmakeExecutable) build $(_XmakeCommonFlags) $(_XmakeBuildFlags) $(_XmakeTarget)\" EchoOff=\"true\" />\n  </Target>\n  <Target Name=\"_XmakeRebuild\" DependsOnTargets=\"_XmakeProjCheck\">\n    <Message Text=\"$xmake build -r $(_XmakeCommonFlags) $(_XmakeBuildFlags) $(_XmakeTarget)\" Importance=\"High\" />\n    <Exec Command=\"$(_XmakeEnv)\n      $(_XmakeExecutable) build -r $(_XmakeCommonFlags) $(_XmakeBuildFlags) $(_XmakeTarget)\" EchoOff=\"true\" />\n  </Target>\n  <Target Name=\"_XmakeBuildFile\" DependsOnTargets=\"_XmakeProjCheck\">\n    <ItemGroup>\n      <SelectedFile Include=\"$(SelectedFiles)\" />\n      <File Include=\"$([MSBuild]::MakeRelative('$(XmakeProjectDirResolved)', $([System.IO.Path]::GetFullPath('%(SelectedFile.Identity)'))))\" />\n    </ItemGroup>\n    <PropertyGroup>\n      <FileFlag>--files=\"@(File)\"</FileFlag>\n    </PropertyGroup>\n    <Message Text=\"$xmake build $(_XmakeCommonFlags) $(_XmakeBuildFileFlags) $(FileFlag) $(_XmakeTarget)\" Importance=\"High\" />\n    <Exec Command=\"$(_XmakeEnv)\n      $(_XmakeExecutable) build $(_XmakeCommonFlags) $(_XmakeBuildFileFlags) $(FileFlag) $(_XmakeTarget)\" EchoOff=\"true\" />\n  </Target>\n  <Target Name=\"_XmakeClean\" DependsOnTargets=\"_XmakeProjCheck\">\n    <Message Text=\"$xmake clean $(_XmakeCommonFlags) $(_XmakeCleanFlags) $(_XmakeTarget)\" Importance=\"High\" />\n    <Exec Command=\"$(_XmakeEnv)\n      $(_XmakeExecutable) clean $(_XmakeCommonFlags) $(_XmakeCleanFlags) $(_XmakeTarget)\" EchoOff=\"true\" />\n  </Target>\n\n  <Target Name=\"Show\">\n    <Message Text=\"\nMSBuild Properties:\n  Xmake Props:\n    XmakeTarget: $(XmakeTarget)\n    'XmakePlat|Mode|Arch': '$(XmakePlat)|$(XmakeMode)|$(XmakeArch)'\n    XmakeBasename: $(XmakeBasename)\n    XmakeFilename: $(XmakeFilename)\n    XmakeKind: $(XmakeKind)\n    XmakeDefault: $(XmakeDefault)\n    XmakeCudaVersion: $(XmakeCudaVersion)\n    XmakeWindowsSdkVersion: $(XmakeWindowsSdkVersion)\n    XmakeMfcKind: $(XmakeMfcKind)\n    XmakeDefines: $(XmakeDefines)\n    XmakeCFlags: $(XmakeCFlags)\n    XmakeCXFlags: $(XmakeCXFlags)\n    XmakeCXXFlags: $(XmakeCXXFlags)\n    XmakeLanguages: $(XmakeLanguages)\n    XmakeSubSystem: $(XmakeSubSystem)\n    XmakeIncludeDirs: $(XmakeIncludeDirs)\n    XmakeForceIncludes: $(XmakeForceIncludes)\n    XmakeLinkDirs: $(XmakeLinkDirs)\n    XmakeSourceDirs: $(XmakeSourceDirs)\n    XmakePrecompiledHeader: $(XmakePrecompiledHeader)\n    XmakeRunEnvs: $(XmakeRunEnvs)\n    XmakeRunArgs: $(XmakeRunArgs)\n  Xmake Path:\n    XmakeProgramDir: $(XmakeProgramDir)\n    XmakeProgramFile: $(XmakeProgramFile)\n    XmakeProjectDir: $(XmakeProjectDir)\n    XmakeScriptDir: $(XmakeScriptDir)\n    XmakeBuilDDir: $(XmakeBuilDDir)\n    XmakeTargetDir: $(XmakeTargetDir)\n    XmakeConfigDir: $(XmakeConfigDir)\n    XmakeConfigFileDir: $(XmakeConfigFileDir)\n    XmakeRunDir: $(XmakeRunDir)\n  Xmake Resolved Path:\n    XmakeProgramDir: $(XmakeProgramDirResolved)\n    XmakeProgramFile: $(XmakeProgramFileResolved)\n    XmakeProjectDir: $(XmakeProjectDirResolved)\n    XmakeScriptDir: $(XmakeScriptDirResolved)\n    XmakeBuilDDir: $(XmakeBuilDDirResolved)\n    XmakeTargetDir: $(XmakeTargetDirResolved)\n    XmakeConfigDir: $(XmakeConfigDirResolved)\n    XmakeConfigFileDir: $(XmakeConfigFileDirResolved)\n    XmakeRunDir: $(XmakeRunDirResolved)\n  Xmake Flags:\n    XmakeVerbose: $(XmakeVerbose)\n    XmakeDiagnosis: $(XmakeDiagnosis)\n    XmakeRebuildFile: $(XmakeRebuildFile)\n    XmakeCleanAll: $(XmakeCleanAll)\n    XmakeCommonFlags: $(XmakeCommonFlags)\n    XmakeConfigFlags: $(XmakeConfigFlags)\n    XmakeBuildFlags: $(XmakeBuildFlags)\n    XmakeCleanFlags: $(XmakeCleanFlags)\n  Xmake Internal:\n    _XmakeCommonFlags: $(_XmakeCommonFlags)\n    _XmakeConfigFlags: $(_XmakeConfigFlags)\n    _XmakeBuildFlags: $(_XmakeBuildFlags)\n    _XmakeBuildFileFlags: $(_XmakeBuildFileFlags)\n    _XmakeCleanFlags: $(_XmakeCleanFlags)\n    _XmakeExecutable: $(_XmakeExecutable)\n    _XmakeEnv: $(_XmakeEnv)\n  Vs Props:\n    'Configuration|Platform': '$(Configuration)|$(Platform)'\n    VisualStudioVersion: $(VisualStudioVersion)\n    MSBuildProjectDirectory: $(MSBuildProjectDirectory)\n    MSBuildProjectName: $(MSBuildProjectName)\n    OutDir: $(OutDir)\n    IntDir: $(IntDir)\n    SourcePath: $(SourcePath)\n    TargetName: $(TargetName)\n    TargetExt: $(TargetExt)\n    PlatformToolset: $(PlatformToolset)\n    CharacterSet: $(CharacterSet)\n    UseOfMfc: $(UseOfMfc)\n    WindowsTargetPlatformVersion: $(WindowsTargetPlatformVersion)\n    PreprocessorDefinitions: %(ClCompile.PreprocessorDefinitions)\n    LanguageStandard: %(ClCompile.LanguageStandard)\n    SelectedFiles: $(SelectedFiles)\n    VCTargetsPath: $(VCTargetsPath)\n    \" Importance=\"High\" />\n  </Target>\n\n  <Target Name=\"BeforeBuild\" />\n  <Target Name=\"AfterBuild\" />\n  <Target Name=\"Build\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"Show\" Condition=\"$(XmakeDiagnosis)\" />\n    <CallTarget Targets=\"BeforeBuild\" />\n    <CallTarget Targets=\"_XmakeConfig;_XmakeBuild\" />\n    <CallTarget Targets=\"AfterBuild\" />\n  </Target>\n\n  <Target Name=\"BeforeClean\" />\n  <Target Name=\"AfterClean\" />\n  <Target Name=\"Clean\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"Show\" Condition=\"$(XmakeDiagnosis)\" />\n    <CallTarget Targets=\"BeforeClean\" />\n    <CallTarget Targets=\"_XmakeConfig;_XmakeClean\" />\n    <CallTarget Targets=\"AfterClean\" />\n  </Target>\n\n  <Target Name=\"BeforeRebuild\" />\n  <Target Name=\"AfterRebuild\" />\n  <Target Name=\"Rebuild\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"Show\" Condition=\"$(XmakeDiagnosis)\" />\n    <CallTarget Targets=\"BeforeRebuild\" />\n    <CallTarget Targets=\"_XmakeConfig;_XmakeRebuild\" />\n    <CallTarget Targets=\"AfterRebuild\" />\n  </Target>\n\n\n  <Target Name=\"BeforeBuildFiles\" />\n  <Target Name=\"AfterBuildFiles\" />\n  <Target Name=\"BuildFiles\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"Show\" Condition=\"$(XmakeDiagnosis)\" />\n    <CallTarget Targets=\"BeforeBuildFiles\" />\n    <CallTarget Targets=\"_XmakeConfig;_XmakeBuildFile\" />\n    <CallTarget Targets=\"AfterBuildFiles\" />\n  </Target>\n  <!-- override default compile commands -->\n  <Target Name=\"ClCompile\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"BuildFiles\" />\n  </Target>\n  <Target Name=\"ResourceCompile\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"BuildFiles\" />\n  </Target>\n  <Target Name=\"CudaBuild\" Condition=\"'$(DesignTimeBuild)' != 'true'\">\n    <CallTarget Targets=\"BuildFiles\" />\n  </Target>\n\n  <ImportGroup Label=\"CustomTargets\">\n    <!--only search 2 levels to avoid accidentally import-->\n    <Import Condition=\"Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.targets')\"\n        Project=\"$(MSBuildProjectDirectory)\\Xmake.Custom.targets\" />\n    <Import Condition=\"!Exists('$(MSBuildProjectDirectory)\\Xmake.Custom.targets') And Exists('$(MSBuildProjectDirectory)\\..\\Xmake.Custom.targets')\"\n        Project=\"$(MSBuildProjectDirectory)\\..\\Xmake.Custom.targets\" />\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/Xmake.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ProjectSchemaDefinitions\n  xmlns=\"clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework\"\n  xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n  xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n  <Rule Name=\"XmakeConfiguration\" DisplayName=\"Xmake\" PageTemplate=\"generic\" SwitchPrefix=\"--\" Description=\"Xmake Properties\">\n    <Rule.Categories>\n      <Category Name=\"Common\" DisplayName=\"Common\" Description=\"Xmake common configurations\"/>\n      <Category Name=\"Flags\" DisplayName=\"Additional flags\" Description=\"Xmake additional flags\"/>\n      <Category Name=\"Paths\" DisplayName=\"Paths\" Description=\"Xmake configurable paths\"/>\n    </Rule.Categories>\n    <Rule.DataSource>\n      <DataSource Persistence=\"UserFile\" Label=\"XmakeConfiguration\"/>\n    </Rule.DataSource>\n\n    <BoolProperty\n      Name=\"XmakeVerbose\"\n      DisplayName=\"Print verbose information\"\n      Category=\"Common\"\n      Description=\"Print lots of verbose information for users.\"\n      Switch=\"verbose\" />\n    <BoolProperty\n      Name=\"XmakeDiagnosis\"\n      DisplayName=\"Print diagnosis information\"\n      Category=\"Common\"\n      Description=\"Print lots of diagnosis information (backtrace, check info ..) only for developers.\"\n      Switch=\"diagnosis\" />\n    <BoolProperty\n      Name=\"XmakeCleanAll\"\n      DisplayName=\"Clean all\"\n      Category=\"Common\"\n      Description=\"Clean all auto-generated files by xmake for clean tasks.\"\n      Switch=\"all\" />\n    <BoolProperty\n      Name=\"XmakeRebuildFile\"\n      DisplayName=\"Force rebuild selected files\"\n      Category=\"Common\"\n      Description=\"When use 'compile' command to build selected files, add '--rebuild' flag to force rebuild files.\"\n      Switch=\"rebuild\" />\n\n    <StringProperty\n      Name=\"XmakeCleanFlags\"\n      DisplayName=\"Clean flags\"\n      Category=\"Flags\"\n      Description=\"Additional flags for 'xmake clean'\" />\n    <StringProperty\n      Name=\"XmakeBuildFlags\"\n      DisplayName=\"Build flags\"\n      Category=\"Flags\"\n      Description=\"Additional flags for 'xmake build'\" />\n    <StringProperty\n      Name=\"XmakeConfigFlags\"\n      DisplayName=\"Config flags\"\n      Category=\"Flags\"\n      Description=\"Additional flags for 'xmake config'\" />\n    <StringProperty\n      Name=\"XmakeCommonFlags\"\n      DisplayName=\"Common flags\"\n      Category=\"Flags\"\n      Description=\"Additional flags for all xmake call\" />\n\n    <StringProperty\n      Name=\"XmakeConfigDir\"\n      DisplayName=\"Config dir\"\n      Category=\"Paths\"\n      Description=\"Set environment XMAKE_CONFIGDIR for xmake tasks\"\n      Subtype=\"folder\" />\n    <StringProperty\n      Name=\"XmakeBuilDDir\"\n      DisplayName=\"Build dir\"\n      Category=\"Paths\"\n      Description=\"Set output dir for xmake tasks\"\n      Subtype=\"folder\" />\n  </Rule>\n\n</ProjectSchemaDefinitions>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/Xmake.Custom.items",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!--\n    Use this file to include custom files for visual studio projects.\n\n    This file will be imported by .vcxproj\n   -->\n  <ItemGroup>\n    <!-- <None Include=\"$(XmakeProjectDir)\\xxx\\yyy\\zzz\" /> -->\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/Xmake.Custom.items.filters",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!--\n    Use this file to include custom files for visual studio projects.\n\n    This file will be imported by .vcxproj.filters\n   -->\n  <ItemGroup>\n    <!-- <None Include=\"$(XmakeProjectDir)\\xxx\\yyy\\zzz\">\n      <Filter>xxx\\yyy</Filter>\n    </None> -->\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/Xmake.Custom.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- inherit parent settings -->\n  <Import Condition=\"Exists('$(MSBuildThisFileDirectory)\\..\\Xmake.Custom.props')\"\n    Project=\"$(MSBuildThisFileDirectory)\\..\\Xmake.Custom.props\" />\n\n  <PropertyGroup Label=\"XmakePaths\">\n    <!-- set environment XMAKE_CONFIGDIR for xmake tasks -->\n    <!-- <XmakeConfigDir Condition=\"'$(XmakeMode)|$(XmakeArch)' == 'release|x86'\">$(XmakeProjectDir)\\.xmake</XmakeConfigDir> -->\n\n    <!-- set output dir for xmake tasks -->\n    <!-- <XmakeBuilDDir>$(XmakeProjectDir)\\build</XmakeBuilDDir> -->\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"XmakeFlags\">\n    <!-- Configure these flags to customize xmake build process -->\n    <!--\n      Inherit parents:\n        <XmakeCleanFlags>$(XmakeCleanflags) -D</XmakeCleanFlags>\n      Override parents:\n        <XmakeCleanFlags>-D</XmakeCleanFlags>\n      Respect parents:\n        <XmakeCleanFlags Condition=\" '$(XmakeCleanFlags)' == '' \">-D</XmakeCleanFlags>\n\n      For -v and -D, use <XmakeVerbose> and <XmakeDiagnosis> as its more convenient.\n    -->\n\n    <!-- Set -a for \"xmake clean\" -->\n    <!-- <XmakeCleanAll Condition=\"'$(XmakeCleanAll)' == ''\">true</XmakeCleanAll> -->\n\n    <!-- Set -v for all xmake call -->\n    <!-- <XmakeVerbose Condition=\"'$(XmakeVerbose)' == ''\">false</XmakeVerbose> -->\n\n    <!-- Set -D for all xmake call -->\n    <!-- <XmakeDiagnosis Condition=\"'$(XmakeDiagnosis)' == ''\">false</XmakeDiagnosis> -->\n\n    <!-- Set -r for \"xmake build\" for selected files -->\n    <!-- <XmakeRebuildFile Condition=\"'$(XmakeRebuildFile)' == ''\">false</XmakeRebuildFile> -->\n\n\n    <!-- Additional flags for \"xmake clean\" -->\n    <!-- <XmakeCleanFlags>$(XmakeCleanflags)</XmakeCleanFlags> -->\n\n    <!-- Additional flags for \"xmake build\" -->\n    <!-- <XmakeBuildFlags>$(XmakeBuildFlags)</XmakeBuildFlags> -->\n\n    <!-- Additional flags for \"xmake config\" -->\n    <!-- <XmakeConfigFlags>$(XmakeConfigFlags)</XmakeConfigFlags> -->\n\n    <!-- Additional flags for all xmake call -->\n    <!-- <XmakeCommonFlags>$(XmakeCommonFlags)</XmakeCommonFlags> -->\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/Xmake.Custom.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- inherit parent settings -->\n  <Import Condition=\"Exists('$(MSBuildThisFileDirectory)\\..\\Xmake.Custom.targets')\"\n    Project=\"$(MSBuildThisFileDirectory)\\..\\Xmake.Custom.targets\" />\n\n  <!-- Override these targets to customize your build workflow -->\n  <!--\n    If you uncomment targets below,\n    targets with same name that comes from ../Xmake.Custom.targets will be overrided.\n\n    You can also define your own targets and call them like:\n      <Target Name=\"BeforeBuild\">\n        <CallTarget Targets=\"CustomStep1;CustomStep2\" />\n      </Target>\n    \n    To find task that you can used in custom targets,\n    see: https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-task-reference\n  -->\n\n  <!-- <Target Name=\"BeforeRebuild\"></Target> -->\n  <!-- <Target Name=\"AfterRebuild\"></Target> -->\n  <!-- <Target Name=\"BeforeBuild\"></Target> -->\n  <!-- <Target Name=\"AfterBuild\"></Target> -->\n  <!-- <Target Name=\"BeforeClean\"></Target> -->\n  <!-- <Target Name=\"AfterClean\"></Target> -->\n  <!-- <Target Name=\"BeforeBuildFiles\"></Target> -->\n  <!-- <Target Name=\"AfterBuildFiles\"></Target> -->\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/ProjConfig(target,mode,arch)",
    "content": "\t\t{#target_id#}.#mode#|#arch#.ActiveCfg = #mode#|#vsarch#@default=true;\n\t\t{#target_id#}.#mode#|#arch#.Build.0 = #mode#|#vsarch#@\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/Project(target)",
    "content": "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"#targetname#\", \"#vcxprojdir_relative_sln#\\#targetname_inpath#.vcxproj\", \"{#target_id#}\"\nEndProject\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/ProjectGroup(group)",
    "content": "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"#group#\", \"#group#\", \"{#group_id#}\"\nEndProject\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/ProjectGroupConfig(group_dep)",
    "content": "\t\t{#current_id#} = {#parent_id#}\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/SlnConfig(mode,arch)",
    "content": "\t\t#mode#|#arch# = #mode#|#arch#\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/sln/vsxmake.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version #solution_version#.00\n# Visual Studio Version #vs_version#\n#\n# #xmake_info#\n#\n#   This file is auto generated by xmake.\n#\n#   Please DO NOT EDIT since all your modification will lost after re-generation.\n#   See https://github.com/xmake-io/xmake/pull/472 for more infomation.\n#\nVisualStudioVersion = #vs_version#\nMinimumVisualStudioVersion = 10.0.40219.1\n#Import(Project)#\n#Import(ProjectGroup)#\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Properties\", \"Properties\", \"{007754BD-BB1F-452F-A0D8-13EF216C5ED9}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tXmake.Custom.props = Xmake.Custom.props\n\t\tXmake.Custom.targets = Xmake.Custom.targets\n\t\t#sln_projectfile# = #sln_projectfile#\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n#Import(SlnConfig)#\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n#Import(ProjConfig)#\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n#Import(ProjectGroupConfig)#\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {#solution_id#}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/#target#.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n#xmake_info#\n\n  This file is auto generated by xmake.\n\n  Please DO NOT EDIT since all your modification will lost after re-generation.\n  If you would like to have any customization,\n  edit Xmake.Custom.props and Xmake.Custom.targets instead.\n\n  See https://github.com/xmake-io/xmake/pull/472 for more infomation.\n-->\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n#Import(ProjectConfiguration)#\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{#target_id#}</ProjectGuid>\n    <Configuration Condition=\"'$(Configuration)' == ''\">release</Configuration>\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\n    <XmakeScriptDir>#scriptdir#</XmakeScriptDir>\n    <XmakeProjectDir>#projectdir#</XmakeProjectDir>\n    <XmakeProjectFile>#projectfile#</XmakeProjectFile>\n    <XmakeTarget>#targetname#</XmakeTarget>\n  </PropertyGroup>\n  <PropertyGroup Label=\"XmakeProgram\">\n    <XmakeProgramDir Condition=\"'$(XmakeProgramDir)' == ''\">$(XMAKE_PROGRAM_DIR)</XmakeProgramDir>\n    <XmakeProgramDir Condition=\"'$(XmakeProgramDir)' == ''\">#programdir#</XmakeProgramDir>\n    <XmakeProgramFile Condition=\"'$(XmakeProgramFile)' == ''\">$(XMAKE_PROGRAM_FILE)</XmakeProgramFile>\n    <XmakeProgramFile Condition=\"'$(XmakeProgramFile)' == ''\">#programfile#</XmakeProgramFile>\n  </PropertyGroup>\n  <Import Project=\"$(XmakeProgramDir)\\scripts\\vsxmake\\vsproj\\Xmake.Defaults.props\" />\n#Import(XmakeConfig)#\n#Import(XmakePath)#\n  <Import Project=\"$(XmakeProgramDir)\\scripts\\vsxmake\\vsproj\\Xmake.props\" />\n  <ItemGroup>\n#Import(Include.c)#\n#Import(Include.natvis)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.c)#\n#Import(File.cxx)#\n#Import(File.mpp)#\n#Import(File.cu)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.obj)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.rc)#\n#Import(File.ui)#\n#Import(File.qrc)#\n#Import(File.ts)#\n  </ItemGroup>\n  <!-- <ItemGroup>\n#Import(ProjectRef)#\n  </ItemGroup> -->\n  <Import Project=\"$(XmakeProgramDir)\\scripts\\vsxmake\\vsproj\\Xmake.targets\" />\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.c(filec)",
    "content": "    <ClCompile Include=\"#path#\">\n      <CompileAs>CompileAsC</CompileAs>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.cu(filecu)",
    "content": "    <CudaCompile Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.cxx(filecxx)",
    "content": "    <ClCompile Include=\"#path#\">\n      <CompileAs>CompileAsCpp</CompileAs>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.mpp(filempp)",
    "content": "    <ClCompile Include=\"#path#\">\n      <CompileAs>CompileAsCppModule</CompileAs>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.obj(fileobj)",
    "content": "    <Object Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.qrc(fileqrc)",
    "content": "    <None Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.rc(filerc)",
    "content": "    <ResourceCompile Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.ts(filets)",
    "content": "    <QtTranslation Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/File.ui(fileui)",
    "content": "    <None Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/Include.c(incc)",
    "content": "    <ClInclude Include=\"#path#\" />\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/Include.natvis(incnatvis)",
    "content": "    <Natvis Include=\"#path#\">\n      <FileType>Document</FileType>\n    </Natvis>"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/ProjectConfiguration(mode,arch)",
    "content": "    <ProjectConfiguration Include=\"#mode#|#vsarch#\">\n      <Configuration>#mode#</Configuration>\n      <Platform>#vsarch#</Platform>\n    </ProjectConfiguration>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/ProjectRef(dep)",
    "content": "    <ProjectReference Include=\"..\\#targetname_inpath#\\#targetname_inpath#.vcxproj\">\n      <Project>{#target_id#}</Project>\n    </ProjectReference>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/XmakeConfig(mode,arch)",
    "content": "  <PropertyGroup Label=\"XmakeConfig\" Condition=\"'$(Configuration)|$(Platform)'=='#mode#|#vsarch#'\">\n    <XmakeBasename>#basename#</XmakeBasename>\n    <XmakeFilename>#filename#</XmakeFilename>\n    <XmakeMode>#mode#</XmakeMode>\n    <XmakePlat>#plat#</XmakePlat>\n    <XmakeArch>#arch#</XmakeArch>\n    <XmakeKind>#kind#</XmakeKind>\n    <XmakeDefault>#default#</XmakeDefault>\n    <XmakeDefines>#defines#</XmakeDefines>\n    <XmakeLanguages>#languages#</XmakeLanguages>\n    <XmakeSubSystem>#subsystem#</XmakeSubSystem>\n    <XmakeCudaVersion>#cudaver#</XmakeCudaVersion>\n    <XmakeWindowsSdkVersion>#sdkver#</XmakeWindowsSdkVersion>\n    <XmakeMfcKind>#mfckind#</XmakeMfcKind>\n    <XmakeRunEnvs>#runenvs#</XmakeRunEnvs>\n    <XmakeRunArgs>#runargs#</XmakeRunArgs>\n    <XmakeConfigFlags>#configflags#</XmakeConfigFlags>\n    <XmakeIncludeDirs>#includedirs#</XmakeIncludeDirs>\n    <XmakeForceIncludes>#forceincludes#</XmakeForceIncludes>\n    <XmakeLinkDirs>#linkdirs#</XmakeLinkDirs>\n    <XmakeSourceDirs>#sourcedirs#</XmakeSourceDirs>\n    <XmakePrecompiledHeader>#pcheaderfile#</XmakePrecompiledHeader>\n    <XmakeCFlags>#cflags#</XmakeCFlags>\n    <XmakeCXFlags>#cxflags#</XmakeCXFlags>\n    <XmakeCXXFlags>#cxxflags#</XmakeCXXFlags>\n  </PropertyGroup>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj/XmakePath(mode,arch)",
    "content": "  <PropertyGroup Label=\"XmakePath\" Condition=\"'$(Configuration)|$(Platform)'=='#mode#|#vsarch#'\">\n    <XmakeBuilDDir>#builddir#</XmakeBuilDDir>\n    <XmakeConfigDir>#configdir#</XmakeConfigDir>\n    <XmakeConfigFileDir>#configfiledir#</XmakeConfigFileDir>\n    <XmakeTargetDir>#targetdir#</XmakeTargetDir>\n    <XmakeRunDir>#rundir#</XmakeRunDir>\n  </PropertyGroup>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/#target#.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n#xmake_info#\n\n  This file is auto generated by xmake.\n\n  Please DO NOT EDIT since all your modification will lost after re-generation.\n  See https://github.com/xmake-io/xmake/pull/472 for more infomation.\n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Properties\">\n      <UniqueIdentifier>{CC7C6180-942D-056E-3227-E6A2B3FB19CD}</UniqueIdentifier>\n    </Filter>\n#Import(Filter)#\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.props\">\n      <Filter>Properties</Filter>\n    </None>\n    <None Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.targets\">\n      <Filter>Properties</Filter>\n    </None>\n    <None Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.items\">\n      <Filter>Properties</Filter>\n    </None>\n    <None Include=\"$(MSBuildProjectDirectory)\\Xmake.Custom.items.filters\">\n      <Filter>Properties</Filter>\n    </None>\n    <None Include=\"$(XmakeScriptDir)\\xmake.lua\">\n      <Filter>Properties</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n#Import(Include.c)#\n#Import(Include.natvis)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.c)#\n#Import(File.cxx)#\n#Import(File.mpp)#\n#Import(File.cu)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.obj)#\n  </ItemGroup>\n  <ItemGroup>\n#Import(File.rc)#\n#Import(File.ui)#\n#Import(File.qrc)#\n#Import(File.ts)#\n  </ItemGroup>\n  <Import Condition=\"Exists('$(MSBuildThisFileDirectory)\\Xmake.Custom.files.filters')\"\n    Project=\"$(MSBuildThisFileDirectory)\\Xmake.Custom.files.filters\" />\n</Project>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.c(filec)",
    "content": "    <ClCompile Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.cu(filecu)",
    "content": "    <CudaCompile Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </CudaCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.cxx(filecxx)",
    "content": "    <ClCompile Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.mpp(filempp)",
    "content": "    <ClCompile Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </ClCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.obj(fileobj)",
    "content": "    <Object Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </Object>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.qrc(fileqrc)",
    "content": "    <None Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </None>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.rc(filerc)",
    "content": "    <ResourceCompile Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </ResourceCompile>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.ts(filets)",
    "content": "    <QtTranslation Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </QtTranslation>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/File.ui(fileui)",
    "content": "    <None Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </None>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/Filter(dir)",
    "content": "﻿    <Filter Include=\"#dir#\">\n      <UniqueIdentifier>{#dir_id#}</UniqueIdentifier>\n    </Filter>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/Include.c(incc)",
    "content": "    <ClInclude Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </ClInclude>\n"
  },
  {
    "path": "xmake/scripts/vsxmake/vsproj/templates/vcxproj.filters/Include.natvis(incnatvis)",
    "content": "    <Natvis Include=\"#path#\">\n      <Filter>#dir#</Filter>\n    </Natvis>"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/README.Debian",
    "content": "${PACKAGE_NAME} for Debian\n---------------\n\n<possible notes regarding this package - if none, delete this file>\n\n -- ${PACKAGE_MAINTAINER}  ${PACKAGE_DATE}\n"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/changelog",
    "content": "${PACKAGE_NAME} (${PACKAGE_VERSION}-1) UNRELEASED; urgency=medium\n\n  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>\n\n -- ${PACKAGE_MAINTAINER}  ${PACKAGE_DATE}\n"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/control",
    "content": "Source: ${PACKAGE_NAME}\nSection: devel\nPriority: optional\nMaintainer: ${PACKAGE_MAINTAINER}\nBuild-Depends: debhelper-compat (= 13)\nBuild-Depends-Arch: ${PACKAGE_BUILDREQUIRES}\nStandards-Version: 4.6.0\nHomepage: ${PACKAGE_HOMEPAGE}\nRules-Requires-Root: no\n\nPackage: ${PACKAGE_NAME}\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}\nDescription: ${PACKAGE_TITLE}\n ${PACKAGE_DESCRIPTION}\n"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: ${PACKAGE_NAME}\nUpstream-Contact: ${PACKAGE_AUTHOR}\nSource: ${PACKAGE_HOMEPAGE}\n\nFiles: *\nCopyright: ${PACKAGE_COPYRIGHT}\nLicense: ${PACKAGE_LICENSE}\n .\n\n"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/rules",
    "content": "#!/usr/bin/make -f\n\n#export DH_VERBOSE = 1\n\nPREFIX=$(CURDIR)/debian/${PACKAGE_NAME}/usr\n\nconfigure: configure-stamp\nconfigure-stamp:\n\tdh_testdir\n\ttouch configure-stamp\n\nbuild-arch:\n\t# pass\n\nbuild-indep:\n\t# pass\n\nbuild: build-stamp\nbuild-stamp: configure-stamp\n\tdh_testdir\n\t${PACKAGE_BUILDCMDS}\n\ttouch $@\n\nclean:\n\tdh_testdir\n\tdh_testroot\n\trm -f build-stamp configure-stamp\n\tdh_clean\n\ninstall: build\n\tdh_testdir\n\tdh_testroot\n\tdh_installdirs\n\t${PACKAGE_INSTALLCMDS}\n\ndistclean: clean\n\nuninstall:\n\t${PACKAGE_UNINSTALLCMDS}\n\nbinary-indep: build install\n# We have nothing to do by default.\n# # Build architecture-dependent files here.\nbinary-arch: build install\n\tdh_testdir\n\tdh_testroot\n\tdh_installdocs\n\tdh_installexamples\n\tdh_installman\n\tdh_link\n\tdh_strip\n\tdh_compress\n\tdh_fixperms\n\tdh_installdeb\n\tdh_shlibdeps\n\tdh_gencontrol\n\tdh_md5sums\n\tdh_builddeb\nbinary: binary-indep binary-arch\n.PHONY: build clean binary-indep binary-arch binary install uninstall configure\n"
  },
  {
    "path": "xmake/scripts/xpack/deb/debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "xmake/scripts/xpack/nsis/makensis.nsi",
    "content": "; this is a NSI spec file,\n; it is autogenerated by the xmake build system.\n; do not edit by hand.\n\n; includes\n!include \"MUI2.nsh\"\n!include \"WordFunc.nsh\"\n!include \"WinMessages.nsh\"\n!include \"FileFunc.nsh\"\n!include \"UAC.nsh\"\n\n; the version information\n!define VERSION      \"${PACKAGE_VERSION}\"\n!if \"${PACKAGE_VERSION_BUILD}\" != \"\"\n!define VERSION_FULL \"${PACKAGE_VERSION}+${PACKAGE_VERSION_BUILD}\"\n!else\n!define VERSION_FULL \"${PACKAGE_VERSION}\"\n!endif\n\n; set the package name\nName \"${PACKAGE_NAME} - v${VERSION}\"\n\n; set the output file path\nOutFile \"${PACKAGE_OUTPUTFILE}\"\n\n; set the working directory\n!cd \"${PACKAGE_WORKDIR}\"\n\n; use unicode\nUnicode true\n\n; use best compressor\nSetCompressor /FINAL /SOLID lzma\nSetCompressorDictSize 64\nSetDatablockOptimize ON\n\n; set the default installation directory\n!if \"${PACKAGE_ARCH}\" == \"x64\"\n  !define PROGRAMFILES $PROGRAMFILES64\n  !define HKLM HKLM64\n  !define HKCU HKCU64\n!else\n  !define PROGRAMFILES $PROGRAMFILES\n  !define HKLM HKLM\n  !define HKCU HKCU\n!endif\n\n; request application privileges for Windows Vista\nRequestExecutionLevel user\n\n; set DPI aware\nManifestDPIAware true\n\n; set icon\n!if \"${PACKAGE_ICONFILE}\" != \"\"\n  !define MUI_ICON \"${PACKAGE_ICONFILE}\"\n!endif\n\n; UAC\n!macro Init thing\n  uac_tryagain:\n  !insertmacro UAC_RunElevated\n  ${Switch} $0\n  ${Case} 0\n    ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done\n    ${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on\n    ${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user\n      MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground \"This ${thing} requires admin privileges, try again\" /SD IDNO IDYES uac_tryagain IDNO 0\n    ${EndIf}\n    ;fall-through and die\n  ${Case} 1223\n    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \"This ${thing} requires admin privileges, aborting!\"\n    Quit\n  ${Case} 1062\n    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \"Logon service not running, aborting!\"\n    Quit\n  ${Default}\n    MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \"Unable to elevate, error $0\"\n    Quit\n  ${EndSwitch}\n\n  ; The UAC plugin changes the error level even in the inner process, reset it.\n  ; note fix install exit code 1223 to 0 with slient /S\n  SetErrorLevel 0\n  SetShellVarContext all\n!macroend\n\n; add the install Pages\n!insertmacro MUI_PAGE_WELCOME\n!if \"${PACKAGE_LICENSEFILE}\" != \"\"\n  !insertmacro MUI_PAGE_LICENSE \"${PACKAGE_LICENSEFILE}\"\n!endif\n!insertmacro MUI_PAGE_COMPONENTS\n!insertmacro MUI_PAGE_DIRECTORY\n!insertmacro MUI_PAGE_INSTFILES\n!insertmacro MUI_PAGE_FINISH\n\n; add uninstall Pages\n!insertmacro MUI_UNPAGE_CONFIRM\n!insertmacro MUI_UNPAGE_INSTFILES\n!insertmacro MUI_UNPAGE_FINISH\n\n; add languages\n!insertmacro MUI_LANGUAGE \"English\"\n\n; set registry paths\n!define RegUninstall \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${PACKAGE_NAME}\"\n\n; set product information\nVIProductVersion                         \"${VERSION}.0\"\nVIFileVersion                            \"${VERSION}.0\"\nVIAddVersionKey /LANG=0 ProductName      \"${PACKAGE_NAME}\"\nVIAddVersionKey /LANG=0 Comments         \"${PACKAGE_DESCRIPTION}\"\nVIAddVersionKey /LANG=0 CompanyName      \"${PACKAGE_COMPANY}\"\nVIAddVersionKey /LANG=0 LegalCopyright   \"${PACKAGE_COPYRIGHT}\"\nVIAddVersionKey /LANG=0 FileDescription  \"${PACKAGE_NAME} Installer - v${VERSION}\"\nVIAddVersionKey /LANG=0 OriginalFilename \"${PACKAGE_FILENAME}\"\nVIAddVersionKey /LANG=0 FileVersion      \"${VERSION_FULL}\"\nVIAddVersionKey /LANG=0 ProductVersion   \"${VERSION_FULL}\"\n\n; helper functions\nFunction TrimQuote\n  Exch $R1 ; Original string\n  Push $R2\n\nLoop:\n  StrCpy $R2 \"$R1\" 1\n  StrCmp \"$R2\" \"'\"   TrimLeft\n  StrCmp \"$R2\" \"$\\\"\" TrimLeft\n  StrCmp \"$R2\" \"$\\r\" TrimLeft\n  StrCmp \"$R2\" \"$\\n\" TrimLeft\n  StrCmp \"$R2\" \"$\\t\" TrimLeft\n  StrCmp \"$R2\" \" \"   TrimLeft\n  GoTo Loop2\nTrimLeft:\n  StrCpy $R1 \"$R1\" \"\" 1\n  Goto Loop\n\nLoop2:\n  StrCpy $R2 \"$R1\" 1 -1\n  StrCmp \"$R2\" \"'\"   TrimRight\n  StrCmp \"$R2\" \"$\\\"\" TrimRight\n  StrCmp \"$R2\" \"$\\r\" TrimRight\n  StrCmp \"$R2\" \"$\\n\" TrimRight\n  StrCmp \"$R2\" \"$\\t\" TrimRight\n  StrCmp \"$R2\" \" \"   TrimRight\n  GoTo Done\nTrimRight:\n  StrCpy $R1 \"$R1\" -1\n  Goto Loop2\n\nDone:\n  Pop $R2\n  Exch $R1\nFunctionEnd\n\n; remove directory if it exists\nFunction RMDirIfExists\n!define RMDirIfExists '!insertmacro RMDirIfExistsCall'\n!macro RMDirIfExistsCall _PATH\n  push '${_PATH}'\n Call RMDirIfExists\n!macroend\n  Exch $0\n  IfFileExists \"$0\" 0 fileDoesNotExist\n  RMDir /r \"$0\"\n  fileDoesNotExist:\nFunctionEnd\n\nFunction un.RMDirIfExists\n!define unRMDirIfExists '!insertmacro unRMDirIfExistsCall'\n!macro unRMDirIfExistsCall _PATH\n  push '${_PATH}'\n  Call un.RMDirIfExists\n!macroend\n  Exch $0\n  IfFileExists \"$0\" 0 fileDoesNotExist\n  RMDir /r \"$0\"\n  fileDoesNotExist:\nFunctionEnd\n\n; remove file if it exists\nFunction RMFileIfExists\n!define RMFileIfExists '!insertmacro RMFileIfExistsCall'\n!macro RMFileIfExistsCall _PATH\n  push '${_PATH}'\n  Call RMFileIfExists\n!macroend\n  Exch $0\n  IfFileExists \"$0\" 0 fileDoesNotExist\n  Delete \"$0\"\n  fileDoesNotExist:\nFunctionEnd\n\nFunction un.RMFileIfExists\n!define unRMFileIfExists '!insertmacro unRMFileIfExistsCall'\n!macro unRMFileIfExistsCall _PATH\n  push '${_PATH}'\n  Call un.RMFileIfExists\n!macroend\n  Exch $0\n  IfFileExists \"$0\" 0 fileDoesNotExist\n  Delete \"$0\"\n  fileDoesNotExist:\nFunctionEnd\n\n; remove it's parent directories if they are empty\nFunction RMEmptyParentDirs\n!define RMEmptyParentDirs '!insertmacro RMEmptyParentDirsCall'\n!macro RMEmptyParentDirsCall _PATH\n  push '${_PATH}'\n  Call RMEmptyParentDirs\n!macroend\n  ClearErrors\n\n  Exch $0\n  RMDir \"$0\\..\"\n\n  IfErrors Skip\n  ${RMEmptyParentDirs} \"$0\\..\"\n  Skip:\n\n  Pop $0\nFunctionEnd\n\nFunction un.RMEmptyParentDirs\n!define unRMEmptyParentDirs '!insertmacro unRMEmptyParentDirsCall'\n!macro unRMEmptyParentDirsCall _PATH\n  push '${_PATH}'\n  Call un.RMEmptyParentDirs\n!macroend\n  ClearErrors\n\n  Exch $0\n  RMDir \"$0\\..\"\n\n  IfErrors Skip\n  ${unRMEmptyParentDirs} \"$0\\..\"\n  Skip:\n\n  Pop $0\nFunctionEnd\n\n\n; setup installer\nVar NoAdmin\nFunction .onInit\n  ${GetOptions} $CMDLINE \"/NOADMIN\" $NoAdmin\n  ${If} ${Errors}\n    !insertmacro Init \"installer\"\n    StrCpy $NoAdmin \"false\"\n  ${Else}\n    StrCpy $NoAdmin \"true\"\n  ${EndIf}\n\n  ; get installation root directory\n  ${If} $InstDir == \"\"\n    ${If} $NoAdmin == \"false\"\n      ReadRegStr $R0 ${HKLM} ${RegUninstall} \"InstallLocation\"\n    ${Else}\n      ReadRegStr $R0 ${HKCU} ${RegUninstall} \"InstallLocation\"\n    ${EndIf}\n    ${If} $R0 != \"\"\n      Push $R0\n      Call TrimQuote\n      Pop  $R0\n      StrCpy $InstDir $R0\n    ${EndIf}\n  ${EndIf}\n  ${If} $InstDir == \"\"\n    StrCpy $InstDir \"${PROGRAMFILES}\\${PACKAGE_NAME}\"\n  ${EndIf}\nFunctionEnd\n\nSection \"${PACKAGE_NAME} (required)\" InstallExeutable\n\n  SectionIn RO\n\n  ; set output path to the installation directory.\n  SetOutPath $InstDir\n\n  ; add install commands\n  ${PACKAGE_INSTALLCMDS}\n\n  ; add uninstaller\n  WriteUninstaller \"uninstall.exe\"\n  ; Write the uninstall keys for Windows\n  !macro AddReg RootKey\n    WriteRegStr   ${RootKey} ${RegUninstall} \"NoAdmin\"               \"$NoAdmin\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"DisplayName\"           \"${PACKAGE_TITLE}\"\n    !if \"${PACKAGE_NSIS_DISPLAY_ICON}\" != \"\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"DisplayIcon\"           '\"${PACKAGE_NSIS_DISPLAY_ICON}\"'\n    !endif\n    WriteRegStr   ${RootKey} ${RegUninstall} \"Comments\"              \"${PACKAGE_DESCRIPTION}\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"Publisher\"             \"${PACKAGE_COPYRIGHT}\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"UninstallString\"       '\"$InstDir\\uninstall.exe\"'\n    WriteRegStr   ${RootKey} ${RegUninstall} \"QuiteUninstallString\"  '\"$InstDir\\uninstall.exe\" /S'\n    WriteRegStr   ${RootKey} ${RegUninstall} \"InstallLocation\"       $InstDir\n    WriteRegStr   ${RootKey} ${RegUninstall} \"HelpLink\"              \"${PACKAGE_HOMEPAGE}\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"URLInfoAbout\"          \"${PACKAGE_HOMEPAGE}\"\n    WriteRegStr   ${RootKey} ${RegUninstall} \"URLUpdateInfo\"         \"${PACKAGE_HOMEPAGE}\"\n    WriteRegDWORD ${RootKey} ${RegUninstall} \"VersionMajor\"          ${PACKAGE_VERSION_MAJOR}\n    WriteRegDWORD ${RootKey} ${RegUninstall} \"VersionMinor\"          ${PACKAGE_VERSION_MINOR}\n    WriteRegStr   ${RootKey} ${RegUninstall} \"DisplayVersion\"        ${VERSION_FULL}\n    WriteRegDWORD ${RootKey} ${RegUninstall} \"NoModify\"              1\n    WriteRegDWORD ${RootKey} ${RegUninstall} \"NoRepair\"              1\n\n    ; write size to reg\n    ${GetSize} \"$InstDir\" \"/S=0K\" $0 $1 $2\n    IntFmt $0 \"0x%08X\" $0\n    WriteRegDWORD ${RootKey} ${RegUninstall} \"EstimatedSize\" \"$0\"\n  !macroend\n\n  ${If} $NoAdmin == \"false\"\n    !insertmacro AddReg ${HKLM}\n  ${Else}\n    !insertmacro AddReg ${HKCU}\n  ${EndIf}\nSectionEnd\n\n; add the binary directory to %PATH%\nSection \"Add to PATH\" InstallPath\n  ${If} $NoAdmin == \"false\"\n    ReadRegStr $R0 ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" \"Path\"\n    ${WordReplace} $R0 \";${PACKAGE_BINDIR}\" \"\" \"+\" $R1\n    WriteRegExpandStr ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" \"Path\" \"$R1;${PACKAGE_BINDIR}\"\n  ${Else}\n    ReadRegStr $R0 ${HKCU} \"Environment\" \"Path\"\n    ${WordReplace} $R0 \";${PACKAGE_BINDIR}\" \"\" \"+\" $R1\n    WriteRegExpandStr ${HKCU} \"Environment\" \"Path\" \"$R1;${PACKAGE_BINDIR}\"\n  ${EndIf}\n   SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\nSectionEnd\n\n${PACKAGE_NSIS_INSTALL_SECTIONS}\n\n; define language strings\nLangString DESC_InstallExeutable ${LANG_ENGLISH} \"${PACKAGE_DESCRIPTION}\"\nLangString DESC_InstallPath ${LANG_ENGLISH} \"Add ${PACKAGE_NAME} to PATH\"\n${PACKAGE_NSIS_INSTALL_DESCS}\n\n; assign language strings to sections\n!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN\n!insertmacro MUI_DESCRIPTION_TEXT ${InstallExeutable} $(DESC_InstallExeutable)\n!insertmacro MUI_DESCRIPTION_TEXT ${InstallPath} $(DESC_InstallPath)\n${PACKAGE_NSIS_INSTALL_DESCRIPTION_TEXTS}\n!insertmacro MUI_FUNCTION_DESCRIPTION_END\n\n; setup uninstaller\nFunction un.onInit\n  ; check if we need uac\n  ReadRegStr $NoAdmin ${HKLM} ${RegUninstall} \"NoAdmin\"\n  IfErrors 0 +2\n  ReadRegStr $NoAdmin ${HKCU} ${RegUninstall} \"NoAdmin\"\n\n  ${IfNot} $NoAdmin == \"true\"\n    !insertmacro Init \"uninstaller\"\n  ${EndIf}\nFunctionEnd\n\nSection \"Uninstall\"\n\n  ; add uninstall commands\n  ${PACKAGE_UNINSTALLCMDS}\n\n  ; remove the binary directory from %Path%\n  ${If} $NoAdmin == \"false\"\n    DeleteRegKey ${HKLM} ${RegUninstall}\n    ReadRegStr $R0 ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" \"Path\"\n    ${WordReplace} $R0 \";${PACKAGE_BINDIR}\" \"\" \"+\" $R1\n    WriteRegExpandStr ${HKLM} \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" \"Path\" \"$R1\"\n  ${Else}\n    DeleteRegKey ${HKCU} ${RegUninstall}\n    ReadRegStr $R0 ${HKCU} \"Environment\" \"Path\"\n    ${WordReplace} $R0 \";${PACKAGE_BINDIR}\" \"\" \"+\" $R1\n    WriteRegExpandStr ${HKCU} \"Environment\" \"Path\" \"$R1\"\n  ${EndIf}\n\n  ; remove uninstall.exe\n  ${unRMFileIfExists} \"$InstDir\\uninstall.exe\"\n  ${unRMEmptyParentDirs} \"$InstDir\\uninstall.exe\"\n\nSectionEnd\n\n"
  },
  {
    "path": "xmake/scripts/xpack/runself/makeself.lsm",
    "content": "Begin3\nTitle:          ${PACKAGE_TITLE}\nVersion:        ${PACKAGE_VERSION}\nDescription:    ${PACKAGE_DESCRIPTION}\nKeywords:       ${PACKAGE_NAME}\nAuthor:         $(PACKAGE_AUTHOR)\nMaintained-by:  $(PACKAGE_MAINTAINER)\nOriginal-site:  ${PACKAGE_HOMEPAGE}\nPlatform:       Unix; Windows\nCopying-policy: ${PACKAGE_COPYRIGHT}\nEnd\n"
  },
  {
    "path": "xmake/scripts/xpack/runself/setup.sh",
    "content": "#!/bin/sh\n"
  },
  {
    "path": "xmake/scripts/xpack/srpm/srpm.spec",
    "content": "# this is a SRPM spec file,\n# it is autogenerated by the xmake build system.\n# do not edit by hand.\n\n%global     debug_package %{nil}\n\nName:       ${PACKAGE_NAME}\nVersion:    ${PACKAGE_VERSION}\nRelease:    1%{?dist}\nSummary:    ${PACKAGE_TITLE}\n\nLicense:    ${PACKAGE_LICENSE}\nURL:        ${PACKAGE_HOMEPAGE}\nSource0:    ${PACKAGE_ARCHIVEFILE}\n\n${PACKAGE_BUILDREQUIRES}\n\n%description\n${PACKAGE_DESCRIPTION}\n\n%prep\n%autosetup -n ${PACKAGE_PREFIXDIR} -p1\n\n%build\n${PACKAGE_BUILDCMDS}\n\n%install\n${PACKAGE_INSTALLCMDS}\ncd %{buildroot}\nfind . -type f | sed 's!^\\./!/!' > %{_builddir}/_installedfiles.txt\n\n%check\n\n%files -f %{_builddir}/_installedfiles.txt\n\n%changelog\n* ${PACKAGE_DATE} ${PACKAGE_MAINTAINER} - ${PACKAGE_VERSION}-1\n- Update to ${PACKAGE_VERSION}\n\n"
  },
  {
    "path": "xmake/scripts/xpack/wix/msi.wxs",
    "content": "<!-- this is a WIX spec file -->\n<!-- it is autogenerated by the xmake build system. -->\n<!-- do not edit by hand. -->\n<?define PackageName = \"${PACKAGE_NAME}\"?>\n<?define PackageTitle = \"${PACKAGE_TITLE}\"?>\n<?define PackageDescription = \"${PACKAGE_DESCRIPTION}\"?>\n<?define PackageAuthor = \"${PACKAGE_AUTHOR}\"?>\n<?define PackageMaintainer = \"${PACKAGE_MAINTAINER}\"?>\n<?define PackageHomepage = \"${PACKAGE_HOMEPAGE}\"?>\n<?define PackageCoypright = \"${PACKAGE_COPYRIGHT}\"?>\n<?define PackageCompany = \"${PACKAGE_COMPANY}\"?>\n<?define PackageIconFile = \"${PACKAGE_ICONFILE}\"?>\n<?define PackageLicense = \"${PACKAGE_LICENSE}\"?>\n<?define PackageLicenseFile = \"${PACKAGE_LICENSEFILE}\"?>\n<?define PackageVersion = \"${PACKAGE_VERSION}\"?>\n\n<?define UpgradeCode = \"${PACKAGE_WIX_UPGRADECODE}\"?>\n\n<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:ui=\"http://wixtoolset.org/schemas/v4/wxs/ui\">\n    <Package Language=\"1033\" Manufacturer=\"$(PackageCompany)\" Name=\"$(PackageName)\" UpgradeCode=\"$(UpgradeCode)\" Version=\"$(PackageVersion)\">\n        <MajorUpgrade DowngradeErrorMessage=\"A later version of $(PackageName) is already installed. Setup will now exit.\" />\n        <?if $(PackageIconFile) != \"\" ?>  \n            <Icon Id=\"Icon\" SourceFile=\"$(PackageIconFile)\"/>\n            <Property Id=\"ARPPRODUCTICON\" Value=\"Icon\" />\n            <WixVariable Id=\"WixUIBannerBmp\" Value=\"$(PackageIconFile)\" />\n            <!-- Disable for now, because this is not pretty if the icon has a small resolution -->\n            <!-- <WixVariable Id=\"WixUIDialogBmp\" Value=\"$(PackageIconFile)\" /> -->\n        <?endif ?>\n        <MediaTemplate EmbedCab=\"true\" />\n        <WixVariable Id=\"WixUILicenseRtf\" Value=\"$(PackageLicenseFile)\" />\n        <ui:WixUI Id=\"WixUI_FeatureTree\" InstallDirectory=\"INSTALLFOLDER\" />\n        <StandardDirectory Id=\"ProgramFiles6432Folder\">\n            <Directory Id=\"INSTALLFOLDER\" Name=\"$(PackageName)\"/>\n        </StandardDirectory>\n        ${PACKAGE_WIX_CMDS}\n    </Package>\n</Wix>\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/depot_tools.lua",
    "content": "add_requires(\"depot_tools\")\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/devel.lua",
    "content": "add_requires(\"cmake\", \"ninja\")\nif is_host(\"windows\") and winos.version():le(\"win7\") then\n    add_requires(\"python 3.7.x\")\nelse\n    add_requires(\"python 3.x\")\nend\nif is_host(\"linux\", \"bsd\", \"macosx\") then\n    add_requires(\"pkg-config\", \"autoconf\", \"automake\", \"libtool\")\nelseif is_host(\"windows\") then\n    set_toolchains(\"msvc\")\nend\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/llvm-mingw.lua",
    "content": "add_requires(\"llvm-mingw\")\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/llvm.lua",
    "content": "add_requires(\"llvm\")\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/mingw-w64.lua",
    "content": "add_requires(\"mingw-w64\")\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/msvc.lua",
    "content": "if is_host(\"windows\") then\n    set_toolchains(\"msvc\")\nend\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/msys2-mingw32.lua",
    "content": "add_requires(\"msys2\", {configs = {msystem = \"MINGW32\", mingw32_toolchain = true, base_devel = true}})\n\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/msys2-mingw64.lua",
    "content": "add_requires(\"msys2\", {configs = {msystem = \"MINGW64\", mingw64_toolchain = true, base_devel = true}})\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/msys2.lua",
    "content": "add_requires(\"msys2\", {configs = {base_devel = true}})\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/python2.lua",
    "content": "add_requires(\"python 2.x\")\n"
  },
  {
    "path": "xmake/scripts/xrepo/envs/python3.lua",
    "content": "if is_host(\"windows\") and winos.version():le(\"win7\") then\n    add_requires(\"python 3.7.x\")\nelse\n    add_requires(\"python 3.x\")\nend\n"
  },
  {
    "path": "xmake/scripts/xrepo-hook.psm1",
    "content": "\n## ENVIRONMENT MANAGEMENT ######################################################\n\n<#\n    .SYNOPSIS\n        Enter a xrepo environment based on your current project.\n\n    .EXAMPLE\n        Enter-XrepoEnvironment\n#>\nfunction Enter-XrepoEnvironment {\n    [CmdletBinding()]\n    param(\n        [string]$bnd\n    );\n\n    begin {\n        $script:xrepoOldEnvs = (Get-ChildItem -Path Env:);\n\n        if (-not $bnd) {\n            & $Env:XMAKE_PROGRAM_FILE lua private.xrepo.action.env.info config;\n            if (-not $?) {\n                Exit 1;\n            }\n\n            $xmakeColorTermBackup, $Env:XMAKE_COLORTERM = $Env:XMAKE_COLORTERM, \"nocolor\";\n            $xrepoPrompt = (& $Env:XMAKE_PROGRAM_FILE lua --quiet private.xrepo.action.env.info prompt | Out-String);\n            $Env:XMAKE_COLORTERM = $xmakeColorTermBackup;\n            if (-not $xrepoPrompt.StartsWith(\"[\")) {\n                Write-Host \"error: xmake.lua not found!\";\n                Exit 1;\n            }\n\n            $activateCommand = (& $Env:XMAKE_PROGRAM_FILE lua --quiet private.xrepo.action.env.info script.powershell | Out-String);\n        } else {\n            Push-Location $Env:XMAKE_ROOTDIR;\n            & $Env:XMAKE_PROGRAM_FILE lua private.xrepo.action.env.info config $bnd;\n            if (-not $?) {\n                Pop-Location;\n                Exit 1;\n            }\n\n            $xmakeColorTermBackup, $Env:XMAKE_COLORTERM = $Env:XMAKE_COLORTERM, \"nocolor\";\n            $xrepoPrompt = (& $Env:XMAKE_PROGRAM_FILE lua --quiet private.xrepo.action.env.info prompt $bnd | Out-String);\n            $Env:XMAKE_COLORTERM = $xmakeColorTermBackup;\n            if (-not $xrepoPrompt.StartsWith(\"[\")) {\n                Pop-Location;\n                Write-Host \"error: invalid environment!\";\n                Exit 1;\n            }\n\n            $activateCommand = (& $Env:XMAKE_PROGRAM_FILE lua --quiet private.xrepo.action.env.info script.powershell $bnd | Out-String);\n        }\n\n        Write-Verbose \"[xrepo env script.powershell]`n$activateCommand\";\n        Invoke-Expression -Command $activateCommand;\n\n        if ($bnd) { Pop-Location; }\n        $Env:XMAKE_PROMPT_MODIFIER = $xrepoPrompt.Trim() + \" \";\n    }\n    process {}\n    end {}\n}\n\n\n<#\n    .SYNOPSIS\n        Exit the current xrepo environment, if any.\n\n    .EXAMPLE\n        Exit-XrepoEnvironment\n#>\nfunction Exit-XrepoEnvironment {\n    [CmdletBinding()]\n    param();\n\n    begin {\n        ForEach ($p in (Get-ChildItem Env:)) {\n            [Environment]::SetEnvironmentVariable($p.Name, $Null);\n        }\n        ForEach ($p in $script:xrepoOldEnvs) {\n            [Environment]::SetEnvironmentVariable($p.Name, $p.Value);\n        }\n        $Env:XMAKE_PROMPT_MODIFIER = \"\";\n    }\n    process {}\n    end {}\n}\n\n\nif (Test-Path Function:\\prompt) {\n    Rename-Item Function:\\prompt XrepoPromptBackup\n} else {\n    function XrepoPromptBackup() {\n        # Restore a basic prompt if the definition is missing.\n        \"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) \";\n    }\n}\n\n\n<#\n    .SYNOPSIS\n        Modifies the current prompt to show the current xmake project.\n\n    .EXAMPLE\n        Add-XrepoEnvironmentToPrompt\n\n        Causes the current session's prompt to display the current xmake project name.\n#>\nfunction Add-XrepoEnvironmentToPrompt() {\n    function global:prompt() {\n        if ($Env:XMAKE_PROMPT_MODIFIER) {\n            $Env:XMAKE_PROMPT_MODIFIER | Write-Host -NoNewline\n        }\n        XrepoPromptBackup;\n    }\n}\n\n\n## EXPORTS ###################################################################\n\nExport-ModuleMember `\n    -Alias * `\n    -Function `\n        Add-XrepoEnvironmentToPrompt, `\n        Enter-XrepoEnvironment, `\n        Exit-XrepoEnvironment, `\n        prompt\n"
  },
  {
    "path": "xmake/themes/dark/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"dark\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"cyan\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"green\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"magenta\")\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"olive\")\n    set_color(\"dump.reference\", \"olive\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"olive\")\n    set_color(\"dump.table\", \"bright\")\n    set_color(\"dump.string\", \"magenta bright\")\n    set_color(\"dump.string_quote\", \"magenta\")\n    set_color(\"dump.keyword\", \"cyan\")\n    set_color(\"dump.number\", \"green\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"magenta\")\n    set_color(\"menu.option.name\", \"green\")\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n\n"
  },
  {
    "path": "xmake/themes/default/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"default\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green bright\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red bright\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red bright\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"yellow bright\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"build.target\", \"cyan bright\")\n    else\n        set_color(\"build.target\", \"magenta bright\")\n    end\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"dump.string\", \"red bright\")\n        set_color(\"dump.string_quote\", \"red\")\n    else\n        set_color(\"dump.string\", \"magenta bright\")\n        set_color(\"dump.string_quote\", \"magenta\")\n    end\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green bright\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"menu.main.task.name\", \"cyan bright\")\n        set_color(\"menu.option.name\", \"green bright\")\n    else\n        set_color(\"menu.main.task.name\", \"magenta\")\n        set_color(\"menu.option.name\", \"green\")\n    end\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n"
  },
  {
    "path": "xmake/themes/emoji/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"emoji\")\n\n    -- the success status\n    set_text(\"success\", \"heavy_check_mark\")\n    set_color(\"success\", \"\")\n\n    -- the failure status\n    set_text(\"failure\", \"x\")\n    set_color(\"failure\", \"\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"o\")\n    set_color(\"nothing\", \"\")\n\n    -- the error info\n    set_text(\"error\", \"exclamation error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"warning $warning\")\n    set_color(\"warning\", \"yellow bright\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"magenta bright\")\n\n    -- the spinner chars\n    set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"${anchor}  %s\")\n    set_text(\"dump.reference\", \"${sailboat}  %s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    set_color(\"dump.string\", \"magenta bright\")\n    set_color(\"dump.string_quote\", \"magenta\")\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"magenta\")\n    set_color(\"menu.option.name\", \"green\")\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n"
  },
  {
    "path": "xmake/themes/light/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"light\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green bright\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red bright\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red bright\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"yellow bright\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"cyan bright\")\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    set_color(\"dump.string\", \"red bright\")\n    set_color(\"dump.string_quote\", \"red\")\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green bright\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"cyan bright\")\n    set_color(\"menu.option.name\", \"green bright\")\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n\n"
  },
  {
    "path": "xmake/themes/ninja/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"ninja\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green bright\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red bright\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red bright\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"yellow bright\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"singlerow\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"magenta bright\")\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    set_color(\"dump.string\", \"magenta bright\")\n    set_color(\"dump.string_quote\", \"magenta\")\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green bright\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"magenta\")\n    set_color(\"menu.option.name\", \"green\")\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n"
  },
  {
    "path": "xmake/themes/plain/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"plain\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"\")\n    set_color(\"build.progress_veryslow\", \"\")\n    set_color(\"build.progress_slow\", \"\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"\")\n\n    -- the spinner chars\n    set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"\")\n    set_color(\"dump.reference\", \"\")\n    set_color(\"dump.default\", \"\")\n    set_color(\"dump.udata\", \"\")\n    set_color(\"dump.table\", \"\")\n    set_color(\"dump.string\", \"\")\n    set_color(\"dump.string_quote\", \"\")\n    set_color(\"dump.keyword\", \"\")\n    set_color(\"dump.number\", \"\")\n    set_color(\"dump.function\", \"\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"\")\n    set_color(\"menu.option.name\", \"\")\n    set_color(\"menu.usage\", \"\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"\")\n    set_color(\"interactive.prompt2\", \"\")\n"
  },
  {
    "path": "xmake/themes/powershell/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"powershell\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green bright\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red bright\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red bright\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"yellow\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"scroll\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    set_color(\"build.target\", \"cyan bright\")\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    set_color(\"dump.string\", \"red bright\")\n    set_color(\"dump.string_quote\", \"red\")\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green bright\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    set_color(\"menu.main.task.name\", \"cyan bright\")\n    set_color(\"menu.option.name\", \"green bright\")\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green dim\")\n"
  },
  {
    "path": "xmake/themes/soong/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define theme\ntheme(\"soong\")\n\n    -- the success status\n    set_text(\"success\", \"$ok\")\n    set_color(\"success\", \"green bright\")\n\n    -- the failure status\n    set_text(\"failure\", \"$failed\")\n    set_color(\"failure\", \"red bright\")\n\n    -- the nothing status\n    set_text(\"nothing\", \"$no\")\n    set_color(\"nothing\", \"red bright\")\n\n    -- the error info\n    set_text(\"error\", \"$error\")\n    set_color(\"error\", \"red bright\")\n\n    -- the warning info\n    set_text(\"warning\", \"$warning\")\n    set_color(\"warning\", \"yellow bright\")\n\n    -- the building progress\n    set_text(\"build.progress_format\", \"[%3d%%]\")\n    set_text(\"build.progress_style\", \"multirow\")\n    set_color(\"build.progress\", \"green bright\")\n    -- only for multirow_refresh\n    set_color(\"build.progress_superslow\", \"red\")\n    set_color(\"build.progress_veryslow\", \"magenta\")\n    set_color(\"build.progress_slow\", \"yellow\")\n\n    -- the building object file\n    set_color(\"build.object\", \"\")\n\n    -- the building target file\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"build.target\", \"cyan bright\")\n    else\n        set_color(\"build.target\", \"magenta bright\")\n    end\n\n    -- the spinner chars\n    if (is_subhost(\"windows\") and winos.version():lt(\"win10\")) or is_subhost(\"msys\", \"cygwin\") then\n        set_text(\"spinner.chars\", '\\\\', '-', '/', '|')\n    else\n        set_text(\"spinner.chars\", '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')\n    end\n\n    -- color dump\n    set_text(\"dump.default_format\", \"%s\")\n    set_text(\"dump.udata_format\", \"%s\")\n    set_text(\"dump.table_format\", \"%s\")\n    set_text(\"dump.anchor\", \"&%s\")\n    set_text(\"dump.reference\", \"*%s\")\n    set_color(\"dump.anchor\", \"yellow\")\n    set_color(\"dump.reference\", \"yellow\")\n    set_color(\"dump.default\", \"red\")\n    set_color(\"dump.udata\", \"yellow\")\n    set_color(\"dump.table\", \"bright\")\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"dump.string\", \"red bright\")\n        set_color(\"dump.string_quote\", \"red\")\n    else\n        set_color(\"dump.string\", \"magenta bright\")\n        set_color(\"dump.string_quote\", \"magenta\")\n    end\n    set_color(\"dump.keyword\", \"blue\")\n    set_color(\"dump.number\", \"green bright\")\n    set_color(\"dump.function\", \"cyan\")\n\n    -- menu\n    if is_subhost(\"windows\") and (os.term() == \"powershell\" or os.term() == \"pwsh\") then\n        set_color(\"menu.main.task.name\", \"cyan bright\")\n        set_color(\"menu.option.name\", \"green bright\")\n    else\n        set_color(\"menu.main.task.name\", \"magenta\")\n        set_color(\"menu.option.name\", \"green\")\n    end\n    set_color(\"menu.usage\", \"cyan\")\n\n    -- interactive mode\n    set_text(\"interactive.prompt\", \"xmake>\")\n    set_text(\"interactive.prompt2\", \"xmake>>\")\n    set_color(\"interactive.prompt\", \"green\")\n    set_color(\"interactive.prompt2\", \"green\")\n"
  },
  {
    "path": "xmake/toolchains/armcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"armcc\")\n\n    set_homepage(\"https://www2.keil.com/mdk5/compiler/5\")\n    set_description(\"ARM Compiler Version 5 of Keil MDK\")\n\n    set_kind(\"cross\")\n\n    set_toolset(\"cc\", \"armcc\")\n    set_toolset(\"cxx\", \"armcc\")\n    set_toolset(\"ld\", \"armlink\")\n    set_toolset(\"ar\", \"armar\")\n    set_toolset(\"as\", \"armasm\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_mdk\")\n        local mdk = find_mdk()\n        if mdk and mdk.sdkdir_armcc and find_tool(\"armcc\") then\n            toolchain:config_set(\"sdkdir\", mdk.sdkdir_armcc)\n            return true\n        end\n    end)\n\n\n    on_load(function (toolchain)\n        local arch = toolchain:arch()\n        if arch then\n            toolchain:add(\"cxflags\", \"--cpu \" .. arch)\n            toolchain:add(\"asflags\", \"--cpu \" .. arch)\n            toolchain:add(\"ldflags\", \"--cpu \" .. arch)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/armclang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"armclang\")\n\n    set_homepage(\"https://www2.keil.com/mdk5/compiler/6\")\n    set_description(\"ARM Compiler Version 6 of Keil MDK\")\n\n    set_kind(\"cross\")\n\n    set_toolset(\"cc\", \"armclang\")\n    set_toolset(\"cxx\", \"armclang\")\n    set_toolset(\"ld\", \"armlink\")\n    set_toolset(\"ar\", \"armar\")\n\n    on_check(function (toolchain)\n        import(\"core.base.semver\")\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_mdk\")\n        local mdk = find_mdk()\n        if mdk and mdk.sdkdir_armclang then\n            toolchain:config_set(\"sdkdir\", mdk.sdkdir_armclang)\n            -- different assembler choices for different versions of armclang\n            local armclang = find_tool(\"armclang\", {version = true, force = true, paths = path.join(mdk.sdkdir_armclang, \"bin\")})\n            if armclang and armclang.version and semver.compare(armclang.version, \"6.13\") > 0 then\n                toolchain:config_set(\"toolset_as\", \"armclang\")\n            else\n                toolchain:config_set(\"toolset_as\", \"armasm\")\n            end\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        local arch = toolchain:arch()\n        if arch then\n            local arch_cpu     = arch:lower()\n            local as = toolchain:config(\"toolset_as\")\n            toolchain:set(\"toolset\", \"as\", as)\n            toolchain:add(\"cxflags\", \"--target=arm-arm-none-eabi\")\n            toolchain:add(\"cxflags\", \"-mcpu=\"   .. arch_cpu)\n            if as == \"armclang\" then\n                toolchain:add(\"asflags\", \"--target=arm-arm-none-eabi\")\n                toolchain:add(\"asflags\", \"-mcpu=\" .. arch_cpu)\n                toolchain:add(\"asflags\", \"-masm=auto\")\n            else\n                toolchain:add(\"asflags\", \"--cpu=\" .. arch_cpu)\n            end\n            toolchain:add(\"ldflags\", \"--cpu=\"   .. arch_cpu)\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/c51/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      DawnMagnet\n-- @file        xmake.lua\n--\n\ntoolchain(\"c51\")\n\n    set_homepage(\"https://www.keil.com/c51/\")\n    set_description(\"Keil development tools for the 8051 Microcontroller Architecture\")\n\n    set_kind(\"cross\")\n    set_kind(\"standalone\")\n\n    set_toolset(\"cc\", \"c51\")\n    set_toolset(\"cxx\", \"c51\")\n    set_toolset(\"ld\", \"bl51\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_c51\")\n        local c51 = find_c51()\n        if c51 and c51.sdkdir and find_tool(\"c51\") then\n            toolchain:config_set(\"sdkdir\", c51.sdkdir)\n            return true\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/circle/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"circle\")\n\n    set_homepage(\"https://www.circle-lang.org/\")\n    set_description(\"A new C++20 compiler. It's written from scratch and designed for easy extension.\")\n\n    set_kind(\"standalone\")\n\n    set_toolset(\"cc\", \"circle\")\n    set_toolset(\"cxx\", \"circle\")\n    set_toolset(\"ld\", \"circle\")\n    set_toolset(\"sh\", \"circle\")\n    set_toolset(\"ar\", \"ar\")\n    set_toolset(\"strip\", \"strip\")\n\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"circle\")\n    end)\n\n    on_load(function (toolchain)\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        if march then\n            toolchain:add(\"cxflags\", march)\n            toolchain:add(\"ldflags\", march)\n            toolchain:add(\"shflags\", march)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/clang/check.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_clang(toolchain, vcvars, suffix)\n    local paths\n    local pathenv = os.getenv(\"PATH\")\n    if pathenv then\n        paths = path.splitenv(pathenv)\n    end\n    local result = find_tool(\"clang\" .. suffix, {force = true, paths = paths, envs = vcvars})\n    if result then\n        cprint(\"checking for LLVM Clang C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n        toolchain_utils.check_llvm_info(toolchain, result.program, {envs = vcvars})\n    end\n    return result\nend\n\nfunction _check_for_windows(toolchain, suffix)\n\n    -- only for windows or linux (msvc-wine)\n    if not is_host(\"windows\", \"linux\") then\n        return\n    end\n\n    -- @see https://github.com/xmake-io/xmake/pull/679\n    local cc  = path.basename(config.get(\"cc\") or \"clang\"):lower()\n    local cxx = path.basename(config.get(\"cxx\") or \"clang++\"):lower()\n    if cc == \"clang\" or cxx == \"clang\" or cxx == \"clang++\" then\n        local check = function (toolchain, vcvars)\n            return _check_clang(toolchain, vcvars, suffix)\n        end\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            return toolchain_utils.check_vc_build_tools(toolchain, sdkdir, check)\n        else\n            for _, package in ipairs(toolchain:packages()) do\n                local installdir = package:installdir()\n                if installdir and os.isdir(installdir) then\n                    local result = toolchain_utils.check_vc_build_tools(toolchain, installdir, check)\n                    if result then\n                        return result\n                    end\n                end\n            end\n            return toolchain_utils.check_vstudio(toolchain, check)\n        end\n    end\nend\n\nfunction main(toolchain, suffix)\n    if toolchain:is_plat(\"windows\") then\n        return _check_for_windows(toolchain, suffix)\n    end\n    local result = find_tool(\"clang\", {program = \"clang\" .. suffix})\n    if result then\n        toolchain_utils.check_llvm_info(toolchain, result.program)\n    end\n    return result\nend\n"
  },
  {
    "path": "xmake/toolchains/clang/load.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _load_windows(toolchain, suffix)\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    if is_host(\"linux\") or project.policy(\"build.optimization.lto\") then\n        toolchain:add(\"ldflags\", \"-fuse-ld=lld-link\" .. suffix)\n        toolchain:add(\"shflags\", \"-fuse-ld=lld-link\" .. suffix)\n    end\nend\n\nfunction main(toolchain, suffix)\n\n    -- init tools for lto\n    if project.policy(\"build.optimization.lto\") then\n        toolchain:set(\"toolset\", \"ar\",  \"llvm-ar\" .. suffix)\n        toolchain:set(\"toolset\", \"ranlib\",  \"llvm-ranlib\" .. suffix)\n    end\n\n    -- add target flags\n    local flags = toolchain_utils.get_clang_target_flags(toolchain)\n    if flags then\n        toolchain:add(\"cxflags\", flags)\n        toolchain:add(\"mxflags\", flags)\n        toolchain:add(\"asflags\", flags)\n        toolchain:add(\"ldflags\", flags)\n        toolchain:add(\"shflags\", flags)\n    end\n\n    -- set llvm runtimes\n    toolchain_utils.set_llvm_runtimes(toolchain)\n\n    -- add llvm runenvs before adding vsenvs\n    --\n    -- The dynamic libraries (DLLs) for Clang ASan and MSVC ASan share the same filename, making them incompatible.\n    -- Currently, runenvs maybe have Visual Studio environment variables.\n    -- If the Clang path is not prioritized (placed first), the system incorrectly loads the MSVC ASan DLL, resulting in a runtime failure.\n    toolchain_utils.add_llvm_runenvs(toolchain)\n\n    -- add configs for windows\n    if toolchain:is_plat(\"windows\") then\n        toolchain_utils.add_vsenvs(toolchain)\n        if is_host(\"linux\") or project.policy(\"build.optimization.lto\") then\n            toolchain:add(\"ldflags\", \"-fuse-ld=lld-link\" .. suffix)\n            toolchain:add(\"shflags\", \"-fuse-ld=lld-link\" .. suffix)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/toolchains/clang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\nfunction toolchain_clang(version)\n    local suffix = version and (\"-\" .. version) or \"\"\n\n    toolchain(\"clang\" .. suffix)\n        set_kind(\"standalone\")\n        set_homepage(\"https://clang.llvm.org/\")\n        set_description(\"A C language family frontend for LLVM\" .. (version and (\" (\" .. version .. \")\") or \"\"))\n\n        set_toolset(\"cc\",      \"clang\" .. suffix)\n        set_toolset(\"cxx\",     \"clang++\" .. suffix, \"clang\" .. suffix)\n        set_toolset(\"ld\",      \"clang++\" .. suffix, \"clang\" .. suffix)\n        set_toolset(\"sh\",      \"clang++\" .. suffix, \"clang\" .. suffix)\n        set_toolset(\"ar\",      \"llvm-ar\" .. suffix, \"ar\")\n        set_toolset(\"strip\",   \"llvm-strip\" .. suffix, \"strip\")\n        set_toolset(\"ranlib\",  \"llvm-ranlib\" .. suffix, \"ranlib\")\n        set_toolset(\"objcopy\", \"llvm-objcopy\" .. suffix, \"objcopy\")\n        set_toolset(\"nm\",      \"llvm-nm\" .. suffix, \"nm\")\n        set_toolset(\"mm\",      \"clang\" .. suffix)\n        set_toolset(\"mxx\",     \"clang++\" .. suffix, \"clang\" .. suffix)\n        set_toolset(\"as\",      \"clang\" .. suffix)\n        set_toolset(\"mrc\",     \"llvm-rc\" .. suffix)\n        set_toolset(\"dlltool\", \"llvm-dlltool\" .. suffix)\n        if is_host(\"macosx\") then\n            set_toolset(\"dsymutil\", \"dsymutil\")\n        end\n\n        on_check(function (toolchain)\n            return import(\"toolchains.clang.check\", {rootdir = os.programdir()})(toolchain, suffix)\n        end)\n\n        on_load(function (toolchain)\n            import(\"toolchains.clang.load\", {rootdir = os.programdir()})(toolchain, suffix)\n        end)\nend\ntoolchain_clang()\n"
  },
  {
    "path": "xmake/toolchains/clang-12/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"12\")\n"
  },
  {
    "path": "xmake/toolchains/clang-13/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"13\")\n"
  },
  {
    "path": "xmake/toolchains/clang-14/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"14\")\n"
  },
  {
    "path": "xmake/toolchains/clang-15/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"15\")\n"
  },
  {
    "path": "xmake/toolchains/clang-16/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"16\")\n"
  },
  {
    "path": "xmake/toolchains/clang-17/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"17\")\n"
  },
  {
    "path": "xmake/toolchains/clang-18/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"18\")\n"
  },
  {
    "path": "xmake/toolchains/clang-19/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"19\")\n"
  },
  {
    "path": "xmake/toolchains/clang-20/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"20\")\n"
  },
  {
    "path": "xmake/toolchains/clang-21/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../clang\"))\n\ntoolchain_clang(\"21\")\n"
  },
  {
    "path": "xmake/toolchains/clang-cl/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_clang_cl(toolchain, vcvars)\n    local paths\n    local pathenv = os.getenv(\"PATH\")\n    if pathenv then\n        paths = path.splitenv(pathenv)\n    end\n    local result = find_tool(\"clang-cl\", {force = true, paths = paths, envs = vcvars})\n    if result then\n        cprint(\"checking for LLVM Clang C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n        toolchain_utils.check_llvm_info(toolchain, result.program, {envs = vcvars})\n    end\n    return result\nend\n\nfunction main(toolchain)\n\n    -- only for windows or linux (msvc-wine)\n    if not is_host(\"windows\", \"linux\") then\n        return\n    end\n\n    -- @see https://github.com/xmake-io/xmake/pull/679\n    local cc  = path.basename(config.get(\"cc\") or \"clang-cl\"):lower()\n    local cxx = path.basename(config.get(\"cxx\") or \"clang-cl\"):lower()\n    local mrc = path.basename(config.get(\"mrc\") or \"rc\"):lower()\n    if cc == \"clang-cl\" or cxx == \"clang-cl\" or mrc == \"rc\" then\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            return toolchain_utils.check_vc_build_tools(toolchain, sdkdir, _check_clang_cl)\n        else\n            for _, package in ipairs(toolchain:packages()) do\n                local installdir = package:installdir()\n                if installdir and os.isdir(installdir) then\n                    local result = toolchain_utils.check_vc_build_tools(toolchain, installdir, _check_clang_cl)\n                    if result then\n                        return result\n                    end\n                end\n            end\n            return toolchain_utils.check_vstudio(toolchain, _check_clang_cl)\n        end\n    end\nend\n"
  },
  {
    "path": "xmake/toolchains/clang-cl/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"core.project.project\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- main entry\nfunction main(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\",      \"clang-cl\")\n    toolchain:set(\"toolset\", \"cxx\",     \"clang-cl\")\n    toolchain:set(\"toolset\", \"mrc\",     \"rc.exe\")\n    toolchain:set(\"toolset\", \"dlltool\", \"llvm-dlltool\")\n    if toolchain:is_arch(\"x64\") then\n        toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n    else\n        toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n    end\n    if project.policy(\"build.optimization.lto\") then\n        toolchain:set(\"toolset\", \"ld\",  \"lld-link\")\n        toolchain:set(\"toolset\", \"sh\",  \"lld-link\")\n        toolchain:set(\"toolset\", \"ar\",  \"llvm-ar\")\n    else\n        toolchain:set(\"toolset\", \"ld\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"sh\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n    end\n\n    -- add llvm runenvs before adding vsenvs\n    --\n    -- The dynamic libraries (DLLs) for Clang ASan and MSVC ASan share the same filename, making them incompatible.\n    -- Currently, runenvs maybe have Visual Studio environment variables.\n    -- If the Clang path is not prioritized (placed first), the system incorrectly loads the MSVC ASan DLL, resulting in a runtime failure.\n    toolchain_utils.add_llvm_runenvs(toolchain)\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- add target flags\n    local flags = toolchain_utils.get_clang_target_flags(toolchain)\n    if flags then\n        toolchain:add(\"cxflags\", flags)\n        toolchain:add(\"mxflags\", flags)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/clang-cl/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- clang-cl toolchain\n--\n-- @param vs    the vs version\n--\n-- @code\n-- target(\"test\")\n--     ...\n--     set_toolchains(\"clang-cl\")\n--     set_toolchains(\"clang-cl\", {vs = \"2019\"})\n-- @endcode\n--\ntoolchain(\"clang-cl\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://clang.llvm.org/\")\n    set_description(\"LLVM Clang C/C++ Compiler compatible with msvc\")\n    set_runtimes(\"MT\", \"MTd\", \"MD\", \"MDd\")\n\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/cosmocc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\n-- check the cross toolchain\nfunction main(toolchain)\n\n    -- get sdk directory\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n\n    -- find cross toolchain from external envirnoment\n    local envs\n    local cross_toolchain\n    -- find it from packages first, because we need bind msys2 envirnoments from package.\n    for _, package in ipairs(toolchain:packages()) do\n        local installdir = package:installdir()\n        if installdir and os.isdir(installdir) then\n            cross_toolchain = find_cross_toolchain(installdir)\n            if cross_toolchain then\n                -- we need to bind msys2 shell envirnoments for calling cosmocc,\n                -- @see https://github.com/xmake-io/xmake/issues/5552\n                if is_subhost(\"windows\") then\n                    envs = package:envs()\n                end\n                break\n            end\n        end\n    end\n    if not cross_toolchain then\n        cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir})\n    end\n    if not cross_toolchain then\n        local cosmocc = find_tool(\"cosmocc\", {force = true})\n        if cosmocc and cosmocc.program then\n            local bindir = path.directory(cosmocc.program)\n            local sdkdir = path.directory(bindir)\n            cross_toolchain = {bindir = bindir, sdkdir = sdkdir}\n        end\n    end\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n        if envs then\n            toolchain:config_set(\"envs\", envs)\n        end\n    else\n        raise(\"cosmocc toolchain not found!\")\n    end\n    return cross_toolchain\nend\n\n"
  },
  {
    "path": "xmake/toolchains/cosmocc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"cosmocc\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://github.com/jart/cosmopolitan\")\n    set_description(\"build-once run-anywhere c library\")\n\n    set_formats(\"static\", \"lib$(name).a\")\n    set_formats(\"object\", \"$(name).o\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    set_toolset(\"cc\",     \"cosmocc\")\n    set_toolset(\"cxx\",    \"cosmoc++\", \"cosmocc\")\n    set_toolset(\"cpp\",    \"cosmocc -E\")\n    set_toolset(\"as\",     \"cosmocc\")\n    set_toolset(\"ld\",     \"cosmoc++\", \"cosmocc\")\n    set_toolset(\"sh\",     \"cosmoc++\", \"cosmocc\")\n    set_toolset(\"ar\",     \"cosmoar\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            toolchain:set(\"toolset\", \"ranlib\", \"x86_64-linux-cosmo-ranlib\")\n            toolchain:set(\"toolset\", \"strip\", \"x86_64-linux-cosmo-strip\")\n        else\n            toolchain:set(\"toolset\", \"ranlib\", \"aarch64-linux-cosmo-ranlib\")\n            toolchain:set(\"toolset\", \"strip\", \"aarch64-linux-cosmo-strip\")\n        end\n        -- @see https://github.com/xmake-io/xmake/issues/5552\n        local envs = toolchain:config(\"envs\")\n        if envs then\n            for k, v in pairs(envs) do\n                toolchain:add(\"runenvs\", k, v)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/cross/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\n-- check the cross toolchain\nfunction main(toolchain)\n\n    -- is cross?\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross  = toolchain:cross()\n    if not sdkdir and not bindir and not cross and not toolchain:packages() then\n        return\n    end\n\n    -- find cross toolchain from external envirnoment\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir, cross = cross})\n    if not cross_toolchain then\n        -- find it from packages\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir and os.isdir(installdir) then\n                cross_toolchain = find_cross_toolchain(installdir, {cross = cross})\n                if cross_toolchain then\n                    break\n                end\n            end\n        end\n    end\n\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n        -- init default target os\n        if not config.get(\"target_os\") then\n            config.set(\"target_os\", \"linux\", {readonly = true, force = true})\n        end\n    else\n        raise(\"cross toolchain not found!\")\n    end\n    return cross_toolchain\nend\n\n"
  },
  {
    "path": "xmake/toolchains/cross/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.project.config\")\n\n-- load the cross toolchain\nfunction main(toolchain)\n    local cross = toolchain:cross() or \"\"\n\n    -- add toolset\n    --\n    -- @note we use add/toolset for cross toolchain, because user maybe use set_toolset to modify them\n    -- @see https://github.com/xmake-io/xmake/issues/1024\n    --\n    toolchain:add(\"toolset\", \"cc\", cross .. \"gcc\", cross .. \"clang\")\n    toolchain:add(\"toolset\", \"cxx\", cross .. \"gcc\", cross .. \"clang\", cross .. \"g++\", cross .. \"clang++\")\n    toolchain:add(\"toolset\", \"cpp\", cross .. \"gcc -E\", cross .. \"clang -E\")\n    toolchain:add(\"toolset\", \"as\", cross .. \"gcc\", cross .. \"clang\")\n    toolchain:add(\"toolset\", \"ld\", cross .. \"g++\", cross .. \"gcc\", cross .. \"clang++\", cross .. \"clang\")\n    toolchain:add(\"toolset\", \"sh\", cross .. \"g++\", cross .. \"gcc\", cross .. \"clang++\", cross .. \"clang\")\n    -- need gcc-ar for lto, @see https://github.com/xmake-io/xmake/issues/5015\n    toolchain:add(\"toolset\", \"ar\", cross .. \"gcc-ar\", cross .. \"ar\")\n    toolchain:add(\"toolset\", \"ranlib\", cross .. \"gcc-ranlib\", cross .. \"ranlib\")\n    toolchain:add(\"toolset\", \"strip\", cross .. \"strip\")\n    toolchain:add(\"toolset\", \"objcopy\", cross .. \"objcopy\")\n\n    -- add bin search library for loading some dependent .dll files windows\n    local bindir = toolchain:bindir()\n    if bindir and is_host(\"windows\") then\n        toolchain:add(\"runenvs\", \"PATH\", bindir)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/cross/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"cross\")\n    set_description(\"Common cross compilation toolchain\")\n    set_kind(\"cross\")\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/cuda/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"cuda\")\n\n    -- set homepage\n    set_homepage(\"https://developer.nvidia.com/cuda-toolkit\")\n    set_description(\"CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)\")\n\n    -- set toolset\n    set_toolset(\"cc\",   \"nvc\")\n    set_toolset(\"cxx\",  \"nvc++\")\n    set_toolset(\"fc\",   \"nvfortran\")\n    set_toolset(\"fcld\", \"nvfortran\")\n    set_toolset(\"fcsh\", \"nvfortran\")\n    set_toolset(\"ld\",   \"nvc++\", \"nvc\")\n    set_toolset(\"sh\",   \"nvc++\", \"nvc\")\n    set_toolset(\"cu\",   \"nvcc\", \"clang\")\n    set_toolset(\"culd\", \"nvcc\")\n    set_toolset(\"cu-ccbin\", \"$(env CXX)\", \"$(env CC)\")\n\n    -- bind msvc environments, because nvcc will call cl.exe\n    on_load(function (toolchain)\n        if toolchain:is_plat(\"windows\") then\n            import(\"core.tool.toolchain\", {alias = \"core_toolchain\"})\n            local msvc = core_toolchain.load(\"msvc\", {plat = toolchain:plat(), arch = toolchain:arch()})\n            for name, values in pairs(msvc:runenvs()) do\n                toolchain:add(\"runenvs\", name, values)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/dlang/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\nfunction main(toolchain)\n\n    -- we attempt to find dmd, ldc2, gdc in $PATH\n    if find_tool(\"dmd\") or find_tool(\"ldc2\") or find_tool(\"gdc\") then\n        return true\n    end\n\n    -- we need to find ldc2 and gdc in the given toolchain sdk directory\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross  = toolchain:cross()\n    if not sdkdir and not bindir and not cross then\n        return\n    end\n\n    -- find cross toolchain\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir, cross = cross})\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n    else\n        raise(\"cross toolchain not found!\")\n    end\n    return cross_toolchain\nend\n"
  },
  {
    "path": "xmake/toolchains/dlang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"dlang\")\n    set_homepage(\"https://dlang.org/\")\n    set_description(\"D Programming Language Compiler (Auto)\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        local cross = toolchain:cross() or \"\"\n        toolchain:add(\"toolset\", \"dc\",   \"$(env DC)\", \"dmd\", \"ldc2\", cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcld\", \"$(env DC)\", \"dmd\", \"ldc2\", cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcsh\", \"$(env DC)\", \"dmd\", \"ldc2\", cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcar\", \"$(env DC)\", \"dmd\", \"ldc2\", cross .. \"gcc-ar\")\n\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        toolchain:add(\"dcflags\",   march or \"\")\n        toolchain:add(\"dcshflags\", march or \"\")\n        toolchain:add(\"dcldflags\", march or \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/dmd/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"dmd\")\n    set_homepage(\"https://dlang.org/\")\n    set_description(\"D Programming Language Compiler\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        if find_tool(\"dmd\") then\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        local cross = toolchain:cross() or \"\"\n        toolchain:add(\"toolset\", \"dc\",   \"dmd\")\n        toolchain:add(\"toolset\", \"dcld\", \"dmd\")\n        toolchain:add(\"toolset\", \"dcsh\", \"dmd\")\n        toolchain:add(\"toolset\", \"dcar\", \"dmd\")\n\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        toolchain:add(\"dcflags\",   march or \"\")\n        toolchain:add(\"dcshflags\", march or \"\")\n        toolchain:add(\"dcldflags\", march or \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/dotnet/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"dotnet\")\n    set_homepage(\"https://dotnet.microsoft.com/\")\n    set_description(\".NET SDK Toolchain\")\n\n    set_toolset(\"cs\",   \"dotnet\")\n    set_toolset(\"csld\", \"dotnet\")\n    set_toolset(\"cssh\", \"dotnet\")\n\n    on_check(function (toolchain)\n        import(\"detect.sdks.find_dotnet\")\n\n        -- find dotnet sdk from packages first\n        local sdkinfo\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir and os.isdir(installdir) then\n                sdkinfo = find_dotnet(installdir, {force = true})\n                if sdkinfo then\n                    break\n                end\n            end\n        end\n\n        -- find dotnet sdk from system\n        if not sdkinfo then\n            sdkinfo = find_dotnet()\n        end\n        if not sdkinfo or not sdkinfo.bindir then\n            return false\n        end\n        toolchain:config_set(\"bindir\", sdkinfo.bindir)\n        toolchain:config_set(\"sdkdir\", sdkinfo.sdkdir)\n        if sdkinfo.sdkver then\n            toolchain:config_set(\"sdkver\", sdkinfo.sdkver)\n        end\n        return true\n    end)\n\n    on_load(function (toolchain)\n\n        -- set default environment variables\n        toolchain:add(\"runenvs\", \"DOTNET_NOLOGO\", \"1\")\n        toolchain:add(\"runenvs\", \"DOTNET_CLI_TELEMETRY_OPTOUT\", \"1\")\n        toolchain:add(\"runenvs\", \"DOTNET_SKIP_FIRST_TIME_EXPERIENCE\", \"1\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/dpcpp/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_icxenv\")\nimport(\"lib.detect.find_tool\")\n\n-- main entry\nfunction main(toolchain)\n    local icxenv = toolchain:config(\"icxenv\")\n    if icxenv then\n        return true\n    end\n    icxenv = find_icxenv()\n    if icxenv then\n        local tool = find_tool(\"dpcpp\", {force = true, paths = icxenv.bindir})\n        if tool then\n            cprint(\"checking for Intel Data Parallel C++ (%s) ... ${color.success}${text.success}\", toolchain:arch())\n            toolchain:config_set(\"icxenv\", icxenv)\n            toolchain:config_set(\"bindir\", icxenv.bindir)\n            return true\n        end\n        return true\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/dpcpp/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\n\n-- main entry\nfunction main(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\", \"dpcpp\")\n    toolchain:set(\"toolset\", \"cxx\", \"dpcpp\")\n    toolchain:set(\"toolset\", \"ld\", \"dpcpp\")\n    toolchain:set(\"toolset\", \"sh\", \"dpcpp\")\n    toolchain:set(\"toolset\", \"ar\", \"ar\")\n    toolchain:set(\"toolset\", \"strip\", \"strip\")\n    toolchain:set(\"toolset\", \"as\", \"dpcpp\")\n\n    -- add march flags\n    local march\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        march = \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        march = \"-m32\"\n    end\n    if march then\n        toolchain:add(\"cxflags\", march)\n        toolchain:add(\"asflags\", march)\n        toolchain:add(\"ldflags\", march)\n        toolchain:add(\"shflags\", march)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/dpcpp/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"dpcpp\")\n\n    -- set homepage\n    set_homepage(\"https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html\")\n    set_description(\"Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- check toolchain\n    on_check(\"check\")\n\n    -- on load\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/emcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"emcc\")\n\n    set_homepage(\"http://emscripten.org\")\n    set_description(\"A toolchain for compiling to asm.js and WebAssembly\")\n\n    set_kind(\"standalone\")\n\n    local suffix = is_host(\"windows\") and \".bat\" or \"\"\n    set_toolset(\"cc\", \"emcc\" .. suffix)\n    set_toolset(\"cxx\", \"emcc\" .. suffix, \"em++\" .. suffix)\n    set_toolset(\"ld\", \"em++\" .. suffix, \"emcc\" .. suffix)\n    set_toolset(\"sh\", \"em++\" .. suffix, \"emcc\" .. suffix)\n    set_toolset(\"ar\", \"emar\" .. suffix)\n    set_toolset(\"as\", \"emcc\" .. suffix)\n    set_toolset(\"ranlib\", \"emranlib\" .. suffix)\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_emsdk\")\n        local emsdk\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir and os.isdir(installdir) then\n                emsdk = find_emsdk(installdir)\n                if emsdk then\n                    break\n                end\n            end\n        end\n        if not emsdk then\n            emsdk = find_emsdk()\n        end\n        if emsdk then\n            toolchain:config_set(\"bindir\", emsdk.emscripten)\n            toolchain:config_set(\"sdkdir\", emsdk.sdkdir)\n            return emsdk\n        end\n        return find_tool(\"emcc\")\n    end)\n\n    on_load(function (toolchain)\n        if toolchain:is_arch(\"wasm64\") then\n            toolchain:add(\"cxflags\", \"-sMEMORY64=1\")\n            toolchain:add(\"asflags\", \"-sMEMORY64=1\")\n            toolchain:add(\"ldflags\", \"-sMEMORY64=1\")\n            toolchain:add(\"shflags\", \"-sMEMORY64=1\")\n        else\n            toolchain:add(\"cxflags\", \"\")\n            toolchain:add(\"asflags\", \"\")\n            toolchain:add(\"ldflags\", \"\")\n            toolchain:add(\"shflags\", \"\")\n        end\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                for _, name in ipairs({\"EMSDK\", \"EMSDK_NODE\", \"EMSDK_PYTHON\", \"JAVA_HOME\"}) do\n                    local values = envs[name]\n                    if values then\n                        toolchain:add(\"runenvs\", name, table.unwrap(values))\n                    end\n                end\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/envs/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"envs\")\n    set_description(\"Environment variables toolchain\")\n\n    set_toolset(\"cc\",    \"$(env CC)\")\n    set_toolset(\"cxx\",   \"$(env CXX)\")\n    set_toolset(\"ld\",    \"$(env CXX)\", \"$(env CC)\", \"$(env LD)\")\n    set_toolset(\"sh\",    \"$(env CXX)\", \"$(env CC)\", \"$(env SH)\", \"$(env LD)\")\n    set_toolset(\"ar\",    \"$(env AR)\")\n    set_toolset(\"strip\", \"$(env STRIP)\")\n    set_toolset(\"ranlib\",\"$(env RANLIB)\")\n    set_toolset(\"mm\",    \"$(env MM)\")\n    set_toolset(\"mxx\",   \"$(env MXX)\")\n    set_toolset(\"as\",    \"$(env AS)\")\n    set_toolset(\"sc\",    \"$(env SC)\")\n\n"
  },
  {
    "path": "xmake/toolchains/fasm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"fasm\")\n\n    -- set homepage\n    set_homepage(\"https://flatassembler.net/\")\n    set_description(\"Flat Assembler\")\n\n    -- set toolset\n    set_toolset(\"as\", \"fasm\")\n\n    -- on load\n    on_load(function (toolchain)\n        -- reset asflags for fasm\n        toolchain:add(\"fasm.asflags\", \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/flang/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"flang\")\n\n    -- set homepage\n    set_homepage(\"https://flang.llvm.org/\")\n    set_description(\"LLVM Fortran Compiler\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- set toolset\n    set_toolset(\"fc\",   \"$(env FC)\", \"flang\")\n    set_toolset(\"fcld\", \"$(env FC)\", \"flang\")\n    set_toolset(\"fcsh\", \"$(env FC)\", \"flang\")\n    set_toolset(\"ar\",   \"llvm-ar\", \"ar\")\n\n    -- on check\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"flang\", {program = \"flang\"})\n    end)\n\n    -- on load\n    on_load(function (toolchain)\n        -- flang doesn't support -m64/-m32, use --target instead (especially on Linux)\n        local target\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            target = \"x86_64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\", \"i686\") then\n            target = \"i686\"\n        elseif toolchain:is_arch(\"arm64\", \"aarch64\") then\n            target = \"aarch64\"\n        elseif toolchain:is_arch(\"arm\") then\n            target = \"armv7\"\n        end\n        \n        if target then\n            -- add target suffix based on platform\n            if toolchain:is_plat(\"linux\") then\n                target = target .. \"-linux-gnu\"\n            elseif toolchain:is_plat(\"windows\") then\n                target = target .. \"-windows-msvc\"\n            elseif toolchain:is_plat(\"mingw\") then\n                target = target .. \"-w64-windows-gnu\"\n            end\n            \n            -- only add --target on platforms that need it (Linux, Windows)\n            -- macOS flang may work without explicit target\n            if toolchain:is_plat(\"linux\", \"windows\", \"mingw\") then\n                toolchain:add(\"fcflags\",   \"--target=\" .. target)\n                toolchain:add(\"fcshflags\", \"--target=\" .. target)\n                toolchain:add(\"fcldflags\", \"--target=\" .. target)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/fpc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"fpc\")\n\n    -- set homepage\n    set_homepage(\"https://www.freepascal.org/\")\n    set_description(\"Free Pascal Programming Language Compiler\")\n\n    -- set toolset\n    set_toolset(\"pc\",   \"$(env PC)\", \"fpc\")\n    set_toolset(\"pcld\", \"$(env PC)\", \"fpc\")\n    set_toolset(\"pcsh\", \"$(env PC)\", \"fpc\")\n\n    -- on load\n    on_load(function (toolchain)\n        if toolchain:is_plat(\"linux\") then\n            toolchain:set(\"pcldflags\", \"-k-lc\")\n            toolchain:set(\"pcshflags\", \"-k-lc\")\n        else\n            toolchain:set(\"pcldflags\", \"\")\n            toolchain:set(\"pcshflags\", \"\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/gcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\nfunction toolchain_gcc(version)\n    local suffix = version and (\"-\" .. version) or \"\"\n\n    toolchain(\"gcc\" .. suffix)\n        set_kind(\"standalone\")\n        set_homepage(\"https://gcc.gnu.org/\")\n        set_description(\"GNU Compiler Collection\" .. (version and (\" (\" .. version .. \")\") or \"\"))\n        set_runtimes(\"stdc++_static\", \"stdc++_shared\")\n\n        set_toolset(\"cc\", \"gcc\" .. suffix)\n        set_toolset(\"cxx\", \"g++\" .. suffix, \"gcc\" .. suffix)\n        set_toolset(\"ld\", \"g++\" .. suffix, \"gcc\" .. suffix)\n        set_toolset(\"sh\", \"g++\" .. suffix, \"gcc\" .. suffix)\n        set_toolset(\"ar\", \"ar\")\n        set_toolset(\"strip\", \"strip\")\n        set_toolset(\"objcopy\", \"objcopy\")\n        set_toolset(\"ranlib\", \"ranlib\")\n        set_toolset(\"mm\", \"gcc\" .. suffix)\n        set_toolset(\"mxx\", \"g++\" .. suffix, \"gcc\" .. suffix)\n        set_toolset(\"as\", \"gcc\" .. suffix)\n\n        on_check(function (toolchain)\n            return import(\"lib.detect.find_tool\")(\"gcc\", {program = \"gcc\" .. suffix})\n        end)\n\n        on_load(function (toolchain)\n\n            -- add march flags\n            local march\n            if toolchain:is_arch(\"x86_64\", \"x64\") then\n                march = \"-m64\"\n            elseif toolchain:is_arch(\"i386\", \"x86\") then\n                march = \"-m32\"\n            end\n            if march then\n                toolchain:add(\"cxflags\", march)\n                toolchain:add(\"mxflags\", march)\n                toolchain:add(\"asflags\", march)\n                toolchain:add(\"ldflags\", march)\n                toolchain:add(\"shflags\", march)\n            end\n        end)\nend\ntoolchain_gcc()\n"
  },
  {
    "path": "xmake/toolchains/gcc-10/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"10\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-11/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"11\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-12/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"12\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-13/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"13\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-14/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"14\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-15/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"15\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-4.8/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"4.8\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-4.9/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"4.9\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-8/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"8\")\n"
  },
  {
    "path": "xmake/toolchains/gcc-9/xmake.lua",
    "content": "includes(path.join(os.scriptdir(), \"../gcc\"))\n\ntoolchain_gcc(\"9\")\n"
  },
  {
    "path": "xmake/toolchains/gdc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\nfunction main(toolchain)\n\n    -- we attempt to find gdc in $PATH\n    if find_tool(\"gdc\") then\n        return true\n    end\n\n    -- we need to find gdc2 in the given toolchain sdk directory\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross  = toolchain:cross()\n    if not sdkdir and not bindir and not cross then\n        return\n    end\n\n    -- find cross toolchain\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir, cross = cross})\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n    else\n        raise(\"cross toolchain not found!\")\n    end\n    return cross_toolchain\nend\n"
  },
  {
    "path": "xmake/toolchains/gdc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"gdc\")\n    set_homepage(\"https://gdcproject.org/\")\n    set_description(\"The GNU D Compiler (GDC).\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        local cross = toolchain:cross() or \"\"\n        toolchain:add(\"toolset\", \"dc\",   cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcld\", cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcsh\", cross .. \"gdc\")\n        toolchain:add(\"toolset\", \"dcar\", cross .. \"gcc-ar\")\n\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        toolchain:add(\"dcflags\",   march or \"\")\n        toolchain:add(\"dcshflags\", march or \"\")\n        toolchain:add(\"dcldflags\", march or \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/gfortran/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"gfortran\")\n\n    -- set homepage\n    set_homepage(\"https://fortran.com/\")\n    set_description(\"GNU Fortran Programming Language Compiler\")\n\n    -- set toolset\n    set_toolset(\"fc\",   \"$(env FC)\", \"gfortran\")\n    set_toolset(\"fcld\", \"$(env FC)\", \"gfortran\")\n    set_toolset(\"fcsh\", \"$(env FC)\", \"gfortran\")\n\n    -- on load\n    on_load(function (toolchain)\n        local march = toolchain:is_arch(\"x86_64\", \"x64\", \"arm64\") and \"-m64\" or \"-m32\"\n        toolchain:add(\"fcflags\",   march)\n        toolchain:add(\"fcshflags\", march)\n        toolchain:add(\"fcldflags\", march)\n    end)\n"
  },
  {
    "path": "xmake/toolchains/gnu-rm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"gnu-rm\")\n    set_homepage(\"https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm\")\n    set_description(\"GNU Arm Embedded Toolchain\")\n    set_kind(\"cross\")\n\n    on_load(function (toolchain)\n        toolchain:load_cross_toolchain()\n\n        toolchain:add(\"ldflags\", \"--specs=nosys.specs\", \"--specs=nano.specs\", {force = true})\n        toolchain:add(\"shflags\", \"--specs=nosys.specs\", \"--specs=nano.specs\", {force = true})\n        toolchain:add(\"syslinks\", \"c\", \"m\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/go/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"go\")\n\n    -- set homepage\n    set_homepage(\"https://golang.org/\")\n    set_description(\"Go Programming Language Compiler\")\n\n    -- set toolset\n    -- Modern Go uses \"go\" command for all operations\n    set_toolset(\"gc\",   \"$(env GC)\", \"go\")\n    set_toolset(\"gcld\", \"$(env GC)\", \"go\")\n    set_toolset(\"gcar\", \"$(env GC)\", \"go\")\n\n    -- on load\n    on_load(function (toolchain)\n        import(\"private.tools.go.goenv\")\n\n        -- set GOOS and GOARCH for cross-compilation\n        local goos = goenv.GOOS(toolchain:plat())\n        if goos then\n            toolchain:add(\"runenvs\", \"GOOS\", goos)\n        end\n\n        local goarch = goenv.GOARCH(toolchain:arch())\n        if goarch then\n            toolchain:add(\"runenvs\", \"GOARCH\", goarch)\n        end\n\n        -- Set CGO_ENABLED=0 by default for better cross-compilation support\n        -- Users can override this if they need CGO\n        if not os.getenv(\"CGO_ENABLED\") then\n            toolchain:add(\"runenvs\", \"CGO_ENABLED\", \"0\")\n        end\n\n        -- Disable Go modules mode to use GOPATH mode\n        -- This allows Go to find packages using GOPATH\n        if not os.getenv(\"GO111MODULE\") then\n            toolchain:add(\"runenvs\", \"GO111MODULE\", \"off\")\n        end\n\n        -- Set GOPATH to project directory if not already set\n        -- This allows Go to find packages in the project\n        if not os.getenv(\"GOPATH\") then\n            local projectdir = os.projectdir()\n            if projectdir then\n                toolchain:add(\"runenvs\", \"GOPATH\", projectdir)\n            end\n        end\n\n        -- set default flags\n        toolchain:set(\"gcldflags\", \"\")\n        toolchain:set(\"gcarflags\", \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/hdk/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_hdk\")\n\n-- check the hdk toolchain\nfunction _check_hdk(toolchain)\n    local hdk\n    for _, package in ipairs(toolchain:packages()) do\n        local installdir = package:installdir()\n        if installdir and os.isdir(installdir) then\n            hdk = find_hdk(installdir, {force = true, verbose = option.get(\"verbose\")})\n            if hdk then\n                break\n            end\n        end\n    end\n    if not hdk then\n        hdk = find_hdk(toolchain:config(\"hdk\") or config.get(\"sdk\"), {force = true, verbose = true})\n    end\n    if hdk then\n        toolchain:config_set(\"sdkdir\", hdk.sdkdir)\n        toolchain:config_set(\"bindir\", hdk.bindir)\n        toolchain:config_set(\"sysroot\", hdk.sysroot)\n        return true\n    else\n        --[[TODO we also need to add this tips when use remote hdk toolchain\n        -- failed\n        cprint(\"${bright color.error}please run:\")\n        cprint(\"    - xmake config --hdk=xxx\")\n        cprint(\"or  - xmake global --hdk=xxx\")\n        raise()]]\n    end\nend\n\nfunction main(toolchain)\n    return _check_hdk(toolchain)\nend\n"
  },
  {
    "path": "xmake/toolchains/hdk/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\n\n-- get target\nfunction _get_target(arch)\n    local targets = {\n        [\"armeabi-v7a\"] = \"armv7-linux-ohos\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-linux-ohos\"\n    ,   [\"x86_64\"]      = \"x86_64-linux-ohos\"\n    }\n    assert(targets[arch], \"unknown arch(%s) for harmony!\", arch)\n    return targets[arch]\nend\n\n-- load hdk toolchain\nfunction main(toolchain)\n\n    -- get gcc toolchain bin directory\n    local gcc_toolchain_bin = nil\n    local gcc_toolchain = toolchain:config(\"gcc_toolchain\")\n    if gcc_toolchain then\n        gcc_toolchain_bin = path.join(gcc_toolchain, \"bin\")\n    end\n\n    -- get sdk directory\n    local sdkdir = toolchain:sdkdir()\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\", \"clang\")\n    toolchain:set(\"toolset\", \"cxx\", \"clang++\")\n    toolchain:set(\"toolset\", \"cpp\", \"clang -E\")\n    toolchain:set(\"toolset\", \"as\", \"clang\")\n    toolchain:set(\"toolset\", \"ld\", \"clang++\", \"clang\")\n    toolchain:set(\"toolset\", \"sh\", \"clang++\", \"clang\")\n    toolchain:set(\"toolset\", \"ar\", \"llvm-ar\")\n    toolchain:set(\"toolset\", \"ranlib\", \"llvm-ranlib\")\n    toolchain:set(\"toolset\", \"strip\", \"llvm-strip\")\n\n    -- add hdk target\n    local arch = toolchain:arch()\n    local target = _get_target(arch)\n    toolchain:add(\"cxflags\", \"--target=\" .. target)\n    toolchain:add(\"asflags\", \"--target=\" .. target)\n    toolchain:add(\"ldflags\", \"--target=\" .. target)\n    toolchain:add(\"shflags\", \"--target=\" .. target)\n\n    -- add sysroot\n    local sysroot = toolchain:config(\"sysroot\")\n    if sysroot then\n        toolchain:add(\"cxflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"asflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"ldflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"shflags\", \"--sysroot=\" .. sysroot)\n    end\n\n    -- init cxflags for the target kind: binary\n    toolchain:add(\"binary.cxflags\", \"-fPIE\", \"-pie\")\n\n    -- add \"-fPIE -pie\" to ldflags\n    toolchain:add(\"ldflags\", \"-fPIE\")\n    toolchain:add(\"ldflags\", \"-pie\")\n\n    -- add some builtin flags\n    toolchain:add(\"cxflags\", \"-D__MUSL__\")\nend\n"
  },
  {
    "path": "xmake/toolchains/hdk/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- harmony sdk toolchain\ntoolchain(\"hdk\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://developer.harmonyos.com/cn/develop/\")\n    set_description(\"Harmony SDK\")\n    set_runtimes(\"c++_static\", \"c++_shared\")\n\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/iararm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"iararm\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://www.iar.com/products/architectures/arm/iar-embedded-workbench-for-arm/\")\n    set_description(\"IAR ARM C/C++ Compiler\")\n\n    set_toolset(\"cc\", \"iccarm\")\n    set_toolset(\"cxx\", \"iccarm\")\n    set_toolset(\"ld\", \"ilinkarm\")\n    set_toolset(\"sh\", \"ilinkarm\")\n    set_toolset(\"ar\", \"iarchive\")\n    set_toolset(\"as\", \"iccarm\")\n\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"iccarm\")\n    end)\n\n    on_load(function (toolchain)\n        local arch = toolchain:arch()\n        if arch then\n            toolchain:add(\"cxflags\", \"--cpu \" .. arch)\n            toolchain:add(\"asflags\", \"--cpu \" .. arch)\n            toolchain:add(\"ldflags\", \"--cpu \" .. arch)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/icc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_iccenv\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_cl(toolchain, vcvars)\n    return find_tool(\"cl.exe\", {force = true, envs = vcvars})\nend\n\n-- check intel on windows\nfunction _check_intel_on_windows(toolchain)\n\n    -- have been checked?\n    local varsall = toolchain:config(\"varsall\")\n    if varsall then\n        return true\n    end\n\n    -- find intel c/c++ compiler environment\n    local iccenv = find_iccenv()\n    if iccenv and iccenv.iclvars then\n        local iclvarsall = iccenv.iclvars\n        local iclenv = iclvarsall[toolchain:arch()]\n        if iclenv and iclenv.PATH and iclenv.INCLUDE and iclenv.LIB then\n            local tool = find_tool(\"icl.exe\", {force = true, envs = iclenv})\n            if tool then\n                cprint(\"checking for Intel C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n                toolchain:config_set(\"varsall\", iclvarsall)\n                return toolchain_utils.check_vstudio(toolchain, _check_cl)\n            end\n        end\n    end\nend\n\n-- check intel on linux\nfunction _check_intel_on_linux(toolchain)\n    local iccenv = toolchain:config(\"iccenv\")\n    if iccenv then\n        return true\n    end\n    iccenv = find_iccenv()\n    if iccenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        local tool = find_tool(\"icc\", {force = true, envs = {[ldname] = iccenv.libdir}, paths = iccenv.bindir})\n        if tool then\n            cprint(\"checking for Intel C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n            toolchain:config_set(\"iccenv\", iccenv)\n            toolchain:config_set(\"bindir\", iccenv.bindir)\n            return true\n        end\n        return true\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _check_intel_on_windows(toolchain)\n    else\n        return _check_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/icc/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- add the given icl environment\nfunction _add_iclenv(toolchain, name, curenvs)\n\n    -- get iclvarsall\n    local iclvarsall = toolchain:config(\"varsall\")\n    if not iclvarsall then\n        return\n    end\n\n    -- get icl environment for the current arch\n    local arch = toolchain:arch()\n    local iclenv = iclvarsall[arch] or {}\n\n    -- get the paths for the icl environment\n    local new = iclenv[name]\n    if new then\n        -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.\n        -- @see https://github.com/xmake-io/xmake/issues/4751\n        for k, c in pairs(curenvs) do\n            if name:lower() == k:lower() and name ~= k then\n                name = k\n                break\n            end\n        end\n        toolchain:add(\"runenvs\", name, table.unpack(path.splitenv(new)))\n    end\nend\n\n-- load intel on windows\nfunction _load_intel_on_windows(toolchain)\n\n    -- set toolset\n    if toolchain:is_plat(\"windows\") then\n        toolchain:set(\"toolset\", \"cc\", \"icl.exe\")\n        toolchain:set(\"toolset\", \"cxx\", \"icl.exe\")\n        toolchain:set(\"toolset\", \"mrc\", \"rc.exe\")\n        if toolchain:is_arch(\"x64\") then\n            toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n        else\n            toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n        end\n        toolchain:set(\"toolset\", \"ld\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"sh\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n    else\n        toolchain:set(\"toolset\", \"cc\", \"icc\")\n        toolchain:set(\"toolset\", \"cxx\", \"icpc\", \"icc\")\n        toolchain:set(\"toolset\", \"ld\", \"icpc\", \"icc\")\n        toolchain:set(\"toolset\", \"sh\", \"icpc\", \"icc\")\n        toolchain:set(\"toolset\", \"ar\", \"ar\")\n        toolchain:set(\"toolset\", \"strip\", \"strip\")\n        toolchain:set(\"toolset\", \"as\", \"icc\")\n    end\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- add icl environments\n    local expect_vars = {\"PATH\", \"LIB\", \"INCLUDE\", \"LIBPATH\"}\n    local curenvs = os.getenvs()\n    for _, name in ipairs(expect_vars) do\n        _add_iclenv(toolchain, name, curenvs)\n    end\nend\n\n-- load intel on linux\nfunction _load_intel_on_linux(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\", \"icc\")\n    toolchain:set(\"toolset\", \"cxx\", \"icpc\", \"icc\")\n    toolchain:set(\"toolset\", \"ld\", \"icpc\", \"icc\")\n    toolchain:set(\"toolset\", \"sh\", \"icpc\", \"icc\")\n    toolchain:set(\"toolset\", \"ar\", \"ar\")\n    toolchain:set(\"toolset\", \"strip\", \"strip\")\n    toolchain:set(\"toolset\", \"as\", \"icc\")\n\n    -- add march flags\n    local march\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        march = \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        march = \"-m32\"\n    end\n    if march then\n        toolchain:add(\"cxflags\", march)\n        toolchain:add(\"asflags\", march)\n        toolchain:add(\"ldflags\", march)\n        toolchain:add(\"shflags\", march)\n    end\n\n    -- get icc environments\n    local iccenv = toolchain:config(\"iccenv\")\n    if iccenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        toolchain:add(\"runenvs\", ldname, iccenv.libdir)\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _load_intel_on_windows(toolchain)\n    else\n        return _load_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/icc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"icc\")\n\n    -- set homepage\n    set_homepage(\"https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html\")\n    set_description(\"Intel C/C++ Compiler\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- check toolchain\n    on_check(\"check\")\n\n    -- on load\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/icx/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_icxenv\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_cl(toolchain, vcvars)\n    return find_tool(\"cl.exe\", {force = true, envs = vcvars})\nend\n\n-- check intel on windows\nfunction _check_intel_on_windows(toolchain)\n\n    -- have been checked?\n    local varsall = toolchain:config(\"varsall\")\n    if varsall then\n        return true\n    end\n\n    -- find intel llvm c/c++ compiler environment\n    local icxenv = find_icxenv()\n    if icxenv and icxenv.icxvars then\n        local icxvarsall = icxenv.icxvars\n        local icxenv = icxvarsall[toolchain:arch()]\n        if icxenv and icxenv.PATH and icxenv.INCLUDE and icxenv.LIB then\n            local tool = find_tool(\"icx.exe\", {force = true, envs = icxenv, version = true})\n            if tool then\n                cprint(\"checking for Intel LLVM C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n                toolchain:config_set(\"varsall\", icxvarsall)\n                return toolchain_utils.check_vstudio(toolchain, _check_cl)\n            end\n        end\n    end\nend\n\n-- check intel on linux\nfunction _check_intel_on_linux(toolchain)\n    local icxenv = toolchain:config(\"icxenv\")\n    if icxenv then\n        return true\n    end\n    icxenv = find_icxenv()\n    if icxenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        local tool = find_tool(\"icx\", {force = true, envs = {[ldname] = icxenv.libdir}, paths = icxenv.bindir})\n        if tool then\n            cprint(\"checking for Intel C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n            toolchain:config_set(\"icxenv\", icxenv)\n            toolchain:config_set(\"bindir\", icxenv.bindir)\n            return true\n        end\n        return true\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _check_intel_on_windows(toolchain)\n    else\n        return _check_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/icx/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- add the given icx environment\nfunction _add_icxenv(toolchain, name, curenvs)\n\n    -- get icxvarsall\n    local icxvarsall = toolchain:config(\"varsall\")\n    if not icxvarsall then\n        return\n    end\n\n    -- get icx environment for the current arch\n    local arch = toolchain:arch()\n    local icxenv = icxvarsall[arch] or {}\n\n    -- get the paths for the icx environment\n    local new = icxenv[name]\n    if new then\n        -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.\n        -- @see https://github.com/xmake-io/xmake/issues/4751\n        for k, c in pairs(curenvs) do\n            if name:lower() == k:lower() and name ~= k then\n                name = k\n                break\n            end\n        end\n        toolchain:add(\"runenvs\", name, table.unpack(path.splitenv(new)))\n    end\nend\n\n-- load intel on windows\nfunction _load_intel_on_windows(toolchain)\n\n    -- set toolset\n    if toolchain:is_plat(\"windows\") then\n        toolchain:set(\"toolset\", \"cc\", \"icx.exe\")\n        toolchain:set(\"toolset\", \"cxx\", \"icx.exe\")\n        toolchain:set(\"toolset\", \"mrc\", \"rc.exe\")\n        if toolchain:is_arch(\"x64\") then\n            toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n        else\n            toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n        end\n        toolchain:set(\"toolset\", \"ld\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"sh\",  \"link.exe\")\n        toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n    else\n        toolchain:set(\"toolset\", \"cc\", \"icx\")\n        toolchain:set(\"toolset\", \"cxx\", \"icpx\", \"icx\")\n        toolchain:set(\"toolset\", \"ld\", \"icpx\", \"icx\")\n        toolchain:set(\"toolset\", \"sh\", \"icpx\", \"icx\")\n        toolchain:set(\"toolset\", \"ar\", \"ar\")\n        toolchain:set(\"toolset\", \"strip\", \"strip\")\n        toolchain:set(\"toolset\", \"as\", \"icx\")\n    end\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- add icx environments\n    local expect_vars = {\"PATH\", \"LIB\", \"INCLUDE\", \"LIBPATH\"}\n    local curenvs = os.getenvs()\n    for _, name in ipairs(expect_vars) do\n        _add_icxenv(toolchain, name, curenvs)\n    end\nend\n\n-- load intel on linux\nfunction _load_intel_on_linux(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\", \"icx\")\n    toolchain:set(\"toolset\", \"cxx\", \"icpx\", \"icx\")\n    toolchain:set(\"toolset\", \"ld\", \"icpx\", \"icx\")\n    toolchain:set(\"toolset\", \"sh\", \"icpx\", \"icx\")\n    toolchain:set(\"toolset\", \"ar\", \"ar\")\n    toolchain:set(\"toolset\", \"strip\", \"strip\")\n    toolchain:set(\"toolset\", \"as\", \"icx\")\n\n    -- add march flags\n    local march\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        march = \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        march = \"-m32\"\n    end\n    if march then\n        toolchain:add(\"cxflags\", march)\n        toolchain:add(\"asflags\", march)\n        toolchain:add(\"ldflags\", march)\n        toolchain:add(\"shflags\", march)\n    end\n\n    -- get icx environments\n    local icxenv = toolchain:config(\"icxenv\")\n    if icxenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        toolchain:add(\"runenvs\", ldname, icxenv.libdir)\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _load_intel_on_windows(toolchain)\n    else\n        return _load_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/icx/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"icx\")\n\n    -- set homepage\n    set_homepage(\"https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html\")\n    set_description(\"Intel LLVM C/C++ Compiler\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- check toolchain\n    on_check(\"check\")\n\n    -- on load\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/ifort/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_ifortenv\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_cl(toolchain, vcvars)\n    return find_tool(\"cl.exe\", {force = true, envs = vcvars})\nend\n\n-- check intel on windows\nfunction _check_intel_on_windows(toolchain)\n\n    -- have been checked?\n    local varsall = toolchain:config(\"varsall\")\n    if varsall then\n        return true\n    end\n\n    -- find intel fortran compiler environment\n    local ifortenv = find_ifortenv()\n    if ifortenv and ifortenv.ifortvars then\n        local ifortvarsall = ifortenv.ifortvars\n        local ifortenv = ifortvarsall[toolchain:arch()]\n        if ifortenv and ifortenv.PATH and ifortenv.INCLUDE and ifortenv.LIB then\n            local tool = find_tool(\"ifort.exe\", {force = true, envs = ifortenv, version = true})\n            if tool then\n                cprint(\"checking for Intel Fortran Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n                toolchain:config_set(\"varsall\", ifortvarsall)\n                return toolchain_utils.check_vstudio(toolchain, _check_cl)\n            end\n        end\n    end\nend\n\n-- check intel on linux\nfunction _check_intel_on_linux(toolchain)\n    local ifortenv = toolchain:config(\"ifortenv\")\n    if ifortenv then\n        return true\n    end\n    ifortenv = find_ifortenv()\n    if ifortenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        local tool = find_tool(\"ifort\", {force = true, envs = {[ldname] = ifortenv.libdir}, paths = ifortenv.bindir})\n        if tool then\n            cprint(\"checking for Intel Fortran Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n            toolchain:config_set(\"ifortenv\", ifortenv)\n            toolchain:config_set(\"bindir\", ifortenv.bindir)\n            return true\n        end\n        return true\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _check_intel_on_windows(toolchain)\n    else\n        return _check_intel_on_linux(toolchain)\n    end\nend\n\n\n"
  },
  {
    "path": "xmake/toolchains/ifort/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- add the given ifort environment\nfunction _add_ifortenv(toolchain, name, curenvs)\n\n    -- get ifortvarsall\n    local ifortvarsall = toolchain:config(\"varsall\")\n    if not ifortvarsall then\n        return\n    end\n\n    -- get ifort environment for the current arch\n    local arch = toolchain:arch()\n    local ifortenv = ifortvarsall[arch] or {}\n\n    -- get the paths for the ifort environment\n    local new = ifortenv[name]\n    if new then\n        -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.\n        -- @see https://github.com/xmake-io/xmake/issues/4751\n        for k, c in pairs(curenvs) do\n            if name:lower() == k:lower() and name ~= k then\n                name = k\n                break\n            end\n        end\n        toolchain:add(\"runenvs\", name, table.unpack(path.splitenv(new)))\n    end\nend\n\n-- load intel on windows\nfunction _load_intel_on_windows(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"fc\", \"ifort.exe\")\n    toolchain:set(\"toolset\", \"mrc\", \"rc.exe\")\n    if toolchain:is_arch(\"x64\") then\n        toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n    else\n        toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n    end\n    toolchain:set(\"toolset\", \"fcld\",  \"ifort.exe\")\n    toolchain:set(\"toolset\", \"fcsh\",  \"ifort.exe\")\n    toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- add ifort environments\n    local expect_vars = {\"PATH\", \"LIB\", \"INCLUDE\", \"LIBPATH\"}\n    local curenvs = os.getenvs()\n    for _, name in ipairs(expect_vars) do\n        _add_ifortenv(toolchain, name, curenvs)\n    end\nend\n\n-- load intel on linux\nfunction _load_intel_on_linux(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"fc\", \"ifort\")\n    toolchain:set(\"toolset\", \"fcld\", \"ifort\")\n    toolchain:set(\"toolset\", \"fcsh\", \"ifort\")\n    toolchain:set(\"toolset\", \"ar\", \"ar\")\n\n    -- add march flags\n    local march\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        march = \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        march = \"-m32\"\n    end\n    if march then\n        toolchain:add(\"fcflags\", march)\n        toolchain:add(\"fcldflags\", march)\n        toolchain:add(\"fcshflags\", march)\n    end\n\n    -- get ifort environments\n    local ifortenv = toolchain:config(\"ifortenv\")\n    if ifortenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        toolchain:add(\"runenvs\", ldname, ifortenv.libdir)\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _load_intel_on_windows(toolchain)\n    else\n        return _load_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/ifort/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"ifort\")\n\n    -- set homepage\n    set_homepage(\"https://software.intel.com/content/www/us/en/develop/tools/compilers/fortran-compilers.html\")\n    set_description(\"Intel Fortran Compiler\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- check toolchain\n    on_check(\"check\")\n\n    -- on load\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/ifx/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_ifxenv\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_cl(toolchain, vcvars)\n    return find_tool(\"cl.exe\", {force = true, envs = vcvars})\nend\n\n-- check intel on windows\nfunction _check_intel_on_windows(toolchain)\n\n    -- have been checked?\n    local varsall = toolchain:config(\"varsall\")\n    if varsall then\n        return true\n    end\n\n    -- find intel llvm c/c++ compiler environment\n    local ifxenv = find_ifxenv()\n    if ifxenv and ifxenv.ifxvars then\n        local ifxvarsall = ifxenv.ifxvars\n        local ifxenv = ifxvarsall[toolchain:arch()]\n        if ifxenv and ifxenv.PATH and ifxenv.INCLUDE and ifxenv.LIB then\n            local tool = find_tool(\"ifx.exe\", {force = true, envs = ifxenv, version = true})\n            if tool then\n                cprint(\"checking for Intel LLVM Fortran Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n                toolchain:config_set(\"varsall\", ifxvarsall)\n                return toolchain_utils.check_vstudio(toolchain, _check_cl)\n            end\n        end\n    end\nend\n\n-- check intel on linux\nfunction _check_intel_on_linux(toolchain)\n    local ifxenv = toolchain:config(\"ifxenv\")\n    if ifxenv then\n        return true\n    end\n    ifxenv = find_ifxenv()\n    if ifxenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        local tool = find_tool(\"ifx\", {force = true, envs = {[ldname] = ifxenv.libdir}, paths = ifxenv.bindir})\n        if tool then\n            cprint(\"checking for Intel Fortran Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n            toolchain:config_set(\"ifxenv\", ifxenv)\n            toolchain:config_set(\"bindir\", ifxenv.bindir)\n            return true\n        end\n        return true\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _check_intel_on_windows(toolchain)\n    else\n        return _check_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/ifx/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- add the given ifx environment\nfunction _add_ifxenv(toolchain, name, curenvs)\n\n    -- get ifxvarsall\n    local ifxvarsall = toolchain:config(\"varsall\")\n    if not ifxvarsall then\n        return\n    end\n\n    -- get ifx environment for the current arch\n    local arch = toolchain:arch()\n    local ifxenv = ifxvarsall[arch] or {}\n\n    -- get the paths for the ifx environment\n    local new = ifxenv[name]\n    if new then\n        -- fix case naming conflict for cmake/msbuild between the new msvc envs and current environment, if we are running xmake in vs prompt.\n        -- @see https://github.com/xmake-io/xmake/issues/4751\n        for k, c in pairs(curenvs) do\n            if name:lower() == k:lower() and name ~= k then\n                name = k\n                break\n            end\n        end\n        toolchain:add(\"runenvs\", name, table.unpack(path.splitenv(new)))\n    end\nend\n\n-- load intel on windows\nfunction _load_intel_on_windows(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"fc\", \"ifx.exe\")\n    toolchain:set(\"toolset\", \"mrc\", \"rc.exe\")\n    if toolchain:is_arch(\"x64\") then\n        toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n    else\n        toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n    end\n    toolchain:set(\"toolset\", \"fcld\",  \"ifx.exe\")\n    toolchain:set(\"toolset\", \"fcsh\",  \"ifx.exe\")\n    toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- add ifx environments\n    local expect_vars = {\"PATH\", \"LIB\", \"INCLUDE\", \"LIBPATH\"}\n    local curenvs = os.getenvs()\n    for _, name in ipairs(expect_vars) do\n        _add_ifxenv(toolchain, name, curenvs)\n    end\nend\n\n-- load intel on linux\nfunction _load_intel_on_linux(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"fc\", \"ifx\")\n    toolchain:set(\"toolset\", \"fcld\", \"ifx\")\n    toolchain:set(\"toolset\", \"fcsh\", \"ifx\")\n    toolchain:set(\"toolset\", \"ar\", \"ar\")\n\n    -- add march flags\n    local march\n    if toolchain:is_arch(\"x86_64\", \"x64\") then\n        march = \"-m64\"\n    elseif toolchain:is_arch(\"i386\", \"x86\") then\n        march = \"-m32\"\n    end\n    if march then\n        toolchain:add(\"fcflags\", march)\n        toolchain:add(\"fcldflags\", march)\n        toolchain:add(\"fcshflags\", march)\n    end\n\n    -- get ifx environments\n    local ifxenv = toolchain:config(\"ifxenv\")\n    if ifxenv then\n        local ldname = is_host(\"macosx\") and \"DYLD_LIBRARY_PATH\" or \"LD_LIBRARY_PATH\"\n        toolchain:add(\"runenvs\", ldname, ifxenv.libdir)\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    if is_host(\"windows\") then\n        return _load_intel_on_windows(toolchain)\n    else\n        return _load_intel_on_linux(toolchain)\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/ifx/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"ifx\")\n\n    -- set homepage\n    set_homepage(\"https://www.intel.com/content/www/us/en/developer/articles/tool/oneapi-standalone-components.html#fortran\")\n    set_description(\"Intel LLVM Fortran Compiler\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- check toolchain\n    on_check(\"check\")\n\n    -- on load\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/iverilog/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"iverilog\")\n    set_homepage(\"https://steveicarus.github.io/iverilog/\")\n    set_description(\"Icarus Verilog\")\n\n    set_kind(\"standalone\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        local paths = {}\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n            end\n        end\n        local iverilog = find_tool(\"iverilog\", {paths = paths})\n        if iverilog and iverilog.program then\n            toolchain:config_set(\"iverilog\", iverilog.program)\n            cprint(\"${dim}checking for iverilog ... ${color.success}%s\", path.filename(iverilog.program))\n        else\n            cprint(\"${dim}checking for iverilog ... ${color.nothing}${text.nothing}\")\n            raise(\"iverilog not found!\")\n        end\n        local vvp = find_tool(\"vvp\", {paths = paths})\n        if vvp and vvp.program then\n            toolchain:config_set(\"vvp\", vvp.program)\n            cprint(\"${dim}checking for vvp ... ${color.success}%s\", path.filename(vvp.program))\n        else\n            cprint(\"${dim}checking for vvp ... ${color.nothing}${text.nothing}\")\n            raise(\"iverilog not found!\")\n        end\n        return true\n    end)\n"
  },
  {
    "path": "xmake/toolchains/kotlin-native/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"kotlin-native\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://kotlinlang.org\")\n    set_description(\"The Kotlin Programming Language Compiler. \")\n\n    set_toolset(\"kc\",   \"$(env KC)\", \"kotlinc-native\")\n    set_toolset(\"kcld\", \"$(env KC)\", \"kotlinc-native\")\n    set_toolset(\"kcsh\", \"$(env KC)\", \"kotlinc-native\")\n    set_toolset(\"kcar\", \"$(env KC)\", \"kotlinc-native\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n\n        local paths = {}\n        local runenvs = {}\n        local java_home = os.getenv(\"JAVA_HOME\")\n        local pathenvs = os.getenv(\"PATH\")\n        if pathenvs then\n            pathenvs = path.splitenv(pathenvs)\n        else\n            pathenvs = {}\n        end\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n                table.join2(pathenvs, envs.PATH)\n                if not java_home then\n                    java_home = envs.JAVA_HOME\n                end\n            end\n        end\n        if not find_tool(\"java\") then\n            if #pathenvs > 0 then\n                runenvs.PATH = path.joinenv(pathenvs)\n            end\n            if java_home then\n                runenvs.JAVA_HOME = table.unwrap(java_home)\n            end\n        end\n        if toolchain:bindir() then\n            table.insert(paths, toolchain:bindir())\n        end\n\n        local kotlinc_native = find_tool(\"kotlinc-native\", {paths = paths, envs = runenvs})\n        if kotlinc_native and kotlinc_native.program then\n            kotlinc_native = kotlinc_native.program\n        end\n        if kotlinc_native then\n            if path.is_absolute(kotlinc_native) then\n                local bindir = path.directory(kotlinc_native)\n                toolchain:config_set(\"bindir\", bindir)\n                toolchain:config_set(\"sdkdir\", path.directory(bindir))\n                toolchain:config_set(\"runenvs\", runenvs)\n            end\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n\n        -- bind runenvs for java\n        local runenvs = toolchain:config(\"runenvs\")\n        if runenvs then\n            for k, v in pairs(runenvs) do\n                toolchain:add(\"runenvs\", k, table.unpack(path.splitenv(v)))\n            end\n        end\n\n        -- kotlinc-native -list-targets\n        local target_plat = toolchain:plat()\n        local target_arch = toolchain:arch()\n        if target_plat and target_arch and toolchain:is_cross() then\n            if target_plat == \"macosx\" then\n                target_plat = \"macos\"\n            elseif target_plat == \"iphoneos\" then\n                target_plat = \"ios\"\n                local simulator = toolchain:config(\"appledev\") == \"simulator\"\n                if simulator then\n                    target_plat = target_plat .. \"_simulator\"\n                end\n            elseif target_plat == \"appletvos\" then\n                target_plat = \"tvos\"\n                local simulator = toolchain:config(\"appledev\") == \"simulator\"\n                if simulator then\n                    target_plat = target_plat .. \"_simulator\"\n                end\n            elseif target_plat == \"harmony\" then\n                -- we need to port kotlin-native source code to add ohos_arm64 target support\n                target_plat = \"ohos\"\n            end\n            if target_arch == \"x86_64\" then\n                target_arch = \"x64\"\n            elseif target_arch == \"i386\" then\n                target_arch = \"x86\"\n            elseif target_arch == \"arm64-v8a\" then\n                target_arch = \"arm64\"\n            elseif target_arch == \"armeabi-v7a\" then\n                target_arch = \"arm32\"\n            end\n            local target = target_plat .. \"_\" .. target_arch\n            toolchain:add(\"kcflags\", {\"-target\", target})\n        else\n            toolchain:set(\"kcshflags\", \"\")\n            toolchain:set(\"kcldflags\", \"\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/ldc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\nfunction main(toolchain)\n\n    -- we attempt to find ldc2 in $PATH\n    if find_tool(\"ldc2\") then\n        return true\n    end\n\n    -- we need to find ldc2 in the given toolchain sdk directory\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross  = toolchain:cross()\n    if not sdkdir and not bindir and not cross then\n        return\n    end\n\n    -- find cross toolchain\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir, cross = cross})\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n    else\n        raise(\"cross toolchain not found!\")\n    end\n    return cross_toolchain\nend\n"
  },
  {
    "path": "xmake/toolchains/ldc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"ldc\")\n    set_homepage(\"https://github.com/ldc-developers/ldc\")\n    set_description(\"The LLVM-based D Compiler.\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        toolchain:add(\"toolset\", \"dc\",   \"ldc2\")\n        toolchain:add(\"toolset\", \"dcld\", \"ldc2\")\n        toolchain:add(\"toolset\", \"dcsh\", \"ldc2\")\n        toolchain:add(\"toolset\", \"dcar\", \"ldc2\")\n\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        toolchain:add(\"dcflags\",   march or \"\")\n        toolchain:add(\"dcshflags\", march or \"\")\n        toolchain:add(\"dcldflags\", march or \"\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/llvm/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_path\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_xcode\")\nimport(\"detect.sdks.find_cross_toolchain\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- print Xcode SDK summary (single line)\nfunction _show_checkinfo(toolchain, xcode_sdkdir)\n    if xcode_sdkdir then\n        local xcode_sdkver = toolchain:config(\"xcode_sdkver\")\n        local extras = {}\n        if xcode_sdkver then\n            table.insert(extras, \"sdk: \" .. xcode_sdkver)\n        end\n        local target_triple = toolchain_utils.get_xcode_target_triple(toolchain)\n        if target_triple then\n            table.insert(extras, target_triple)\n        end\n        local extra = \"\"\n        if #extras > 0 then\n            extra = \" (\" .. table.concat(extras, \", \") .. \")\"\n        end\n        cprint(\"checking for Xcode SDK ... ${color.success}%s%s\", xcode_sdkdir, extra)\n    else\n        cprint(\"checking for Xcode SDK ... ${color.nothing}${text.nothing}\")\n    end\nend\n\n-- find xcode on macos\nfunction _find_xcode(toolchain)\n\n    -- get apple device\n    local appledev = toolchain:config(\"appledev\") or config.get(\"appledev\")\n    if appledev and appledev == \"simulator\" then\n        appledev = \"simulator\"\n    elseif not toolchain:is_plat(\"macosx\") and toolchain:is_arch(\"i386\", \"x86_64\") then\n        appledev = \"simulator\"\n    end\n\n    -- find xcode\n    local xcode_sdkver = toolchain:config(\"xcode_sdkver\") or config.get(\"xcode_sdkver\")\n    local xcode = find_xcode(toolchain:config(\"xcode\") or config.get(\"xcode\"), {force = true, verbose = true,\n                                                   find_codesign = false,\n                                                   sdkver = xcode_sdkver,\n                                                   plat = toolchain:plat(),\n                                                   arch = toolchain:arch()})\n    if not xcode then\n        if toolchain:is_global() then\n            _show_checkinfo(toolchain, nil)\n        end\n        return\n    end\n\n    -- xcode found\n    xcode_sdkver = xcode.sdkver\n    if toolchain:is_global() then\n        config.set(\"xcode\", xcode.sdkdir, {force = true, readonly = true})\n    end\n    local target_minver = toolchain:config(\"target_minver\") or config.get(\"target_minver\")\n    if xcode_sdkver and not target_minver then\n        target_minver = xcode.target_minver\n    end\n    toolchain:config_set(\"xcode\", xcode.sdkdir)\n    toolchain:config_set(\"xcode_sdkver\", xcode_sdkver)\n    toolchain:config_set(\"target_minver\", target_minver)\n    toolchain:config_set(\"appledev\", appledev)\n    if toolchain:is_global() then\n        _show_checkinfo(toolchain, xcode.sdkdir)\n    end\nend\n\n-- check the cross toolchain\nfunction main(toolchain)\n\n    -- get sdk directory\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross  = toolchain:cross()\n    if not sdkdir and not bindir then\n        bindir = try {function () return os.iorunv(\"llvm-config\", {\"--bindir\"}) end}\n        if bindir then\n            sdkdir = path.directory(bindir)\n        elseif is_host(\"linux\") and os.isfile(\"/usr/bin/llvm-ar\") then\n            sdkdir = \"/usr\"\n        elseif is_host(\"macosx\") then\n            if os.arch() == \"arm64\" then\n                bindir = find_path(\"llvm-ar\", \"/opt/homebrew/opt/llvm/bin\")\n            else\n                bindir = find_path(\"llvm-ar\", \"/usr/local/Cellar/llvm/*/bin\")\n            end\n            if bindir then\n                sdkdir = path.directory(bindir)\n            end\n        elseif is_host(\"windows\") then\n            local llvm_ar = find_tool(\"llvm-ar\", {force = true, envs = {PATH = os.getenv(\"PATH\")}})\n            if llvm_ar and llvm_ar.program and path.is_absolute(llvm_ar.program) then\n                bindir = path.directory(llvm_ar.program)\n                sdkdir = path.directory(bindir)\n            end\n        end\n    end\n\n    -- find cross toolchain from external envirnoment\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir})\n    if not cross_toolchain then\n        -- find it from packages\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir and os.isdir(installdir) then\n                cross_toolchain = find_cross_toolchain(installdir)\n                if cross_toolchain then\n                    break\n                end\n            end\n        end\n    end\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        toolchain:config_set(\"sdkdir\", cross_toolchain.sdkdir)\n        local clang = path.join(cross_toolchain.bindir, is_host(\"windows\") and \"clang.exe\" or \"clang\")\n        toolchain_utils.check_llvm_info(toolchain, os.isfile(clang) and clang or nil)\n    else\n        wprint(\"llvm toolchain not found!\")\n        return false\n    end\n\n    if toolchain:is_plat(\"cross\") and (not toolchain:cross() or toolchain:cross():match(\"^%s*$\")) then\n        wprint(\"Missing cross target. Use `--cross=name` to specify.\")\n        return false\n    end\n\n    -- attempt to find xcode to pass `-isysroot` on macos\n    if toolchain:is_plat(\"macosx\") then\n        _find_xcode(toolchain)\n    end\n    return cross_toolchain\nend\n"
  },
  {
    "path": "xmake/toolchains/llvm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"llvm\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://llvm.org/\")\n    set_description(\"A collection of modular and reusable compiler and toolchain technologies\")\n\n    set_toolset(\"cc\",      \"clang\")\n    set_toolset(\"cxx\",     \"clang++\", \"clang\")\n    set_toolset(\"mxx\",     \"clang++\", \"clang\")\n    set_toolset(\"mm\",      \"clang\")\n    set_toolset(\"cpp\",     \"clang -E\")\n    set_toolset(\"as\",      \"clang\")\n    set_toolset(\"ld\",      \"clang++\", \"clang\")\n    set_toolset(\"sh\",      \"clang++\", \"clang\")\n    set_toolset(\"ar\",      \"llvm-ar\")\n    set_toolset(\"strip\",   \"llvm-strip\")\n    set_toolset(\"ranlib\",  \"llvm-ranlib\")\n    set_toolset(\"objcopy\", \"llvm-objcopy\")\n    set_toolset(\"mrc\",     \"llvm-rc\")\n    set_toolset(\"dlltool\", \"llvm-dlltool\")\n    if is_host(\"macosx\") then\n        set_toolset(\"dsymutil\", \"dsymutil\")\n    end\n\n    set_toolset(\"sc\",   \"$(env SC)\", \"swift-frontend\", \"swiftc\")\n    set_toolset(\"scsh\", \"$(env SC)\", \"swiftc\")\n    set_toolset(\"scar\", \"$(env SC)\", \"swiftc\")\n    set_toolset(\"scld\", \"$(env SC)\", \"swiftc\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        import(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n        -- set llvm runtimes\n        toolchain_utils.set_llvm_runtimes(toolchain)\n\n        -- add llvm runenvs\n        toolchain_utils.add_llvm_runenvs(toolchain)\n\n        -- add target flags\n        local flags = toolchain_utils.get_clang_target_flags(toolchain)\n        if flags then\n            toolchain:add(\"cxflags\", flags)\n            toolchain:add(\"mxflags\", flags)\n            toolchain:add(\"asflags\", flags)\n            toolchain:add(\"ldflags\", flags)\n            toolchain:add(\"shflags\", flags)\n        end\n\n        -- add target flags for swift\n        local target = toolchain_utils.get_clang_target(toolchain)\n        if target then\n            local flag = \"--target=\" .. target\n            toolchain:add(\"scasflags\", flag)\n            toolchain:add(\"scldflags\", flag)\n            toolchain:add(\"scshflags\", flag)\n        end\n\n        -- init flags for platform\n        if toolchain:is_plat(\"windows\") and not is_host(\"windows\") then\n            toolchain:add(\"ldflags\", \"-fuse-ld=lld\")\n            toolchain:add(\"shflags\", \"-fuse-ld=lld\")\n        elseif toolchain:is_plat(\"macosx\", \"iphoneos\", \"tvos\", \"watchos\", \"xros\") then\n            if not toolchain:config(\"xcode_sysroot\") and not get_config(\"xcode_sysroot\") then\n                local xcode_dir     = toolchain:config(\"xcode\") or get_config(\"xcode\")\n                local xcode_sdkver  = toolchain:config(\"xcode_sdkver\") or get_config(\"xcode_sdkver\")\n                local sdkdir\n                if toolchain:is_plat(\"macosx\") then\n                    -- @see https://github.com/xmake-io/xmake/issues/1179\n                    local sdkroot = xcode_dir and path.join(xcode_dir, \"Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs\")\n                                              or \"/Library/Developer/CommandLineTools/SDKs\"\n                    sdkdir = xcode_sdkver and path.join(sdkroot, \"MacOSX\" .. xcode_sdkver .. \".sdk\")\n                    if not sdkdir or not os.isdir(sdkdir) then\n                        sdkdir = path.join(sdkroot, \"MacOSX.sdk\")\n                        sdkdir = os.isdir(sdkdir) and sdkdir or nil\n                    end\n                else\n                    local mapper = {\n                        iphoneos = { arm64 = \"iPhoneOS\", [\"x86_64\"] = \"iPhoneSimulator\" },\n                        tvos = { arm64 = \"AppleTVOS\", [\"x86_64\"] = \"AppleTVSimulator\" },\n                        watchos = { arm64 = \"WatchOS\", [\"x86_64\"] = \"WatchSimulator\" },\n                        xros = { arm64 = \"XROS\", [\"x86_64\"] = \"XRSimulator\" }\n                    }\n                    local plat = mapper[toolchain:plat()][toolchain:arch()]\n                    local sdkroot = xcode_dir and path.join(xcode_dir, \"Contents/Developer/Platforms/\" .. plat ..\".platform/Developer/SDKs\")\n                    if xcode_sdkver and os.isdir(path.join(sdkroot, plat .. xcode_sdkver .. \".sdk\")) then\n                        sdkdir = path.join(sdkroot, plat .. xcode_sdkver .. \".sdk\")\n                    elseif os.isdir(path.join(sdkroot, plat .. \".sdk\")) then\n                        sdkdir = path.join(sdkroot, plat .. \".sdk\")\n                    end\n                    assert(sdkdir and os.isdir(sdkdir), \"No xcode sysroot found!\")\n                end\n                toolchain:config_set(\"xcode_sysroot\", sdkdir)\n            end\n            -- load configurations\n            import(\".xcode.load\")(toolchain)\n        elseif toolchain:is_plat(\"cross\") then\n            local sysroot\n            local sdkdir = toolchain:sdkdir()\n            local bindir = toolchain:bindir()\n            local cross = toolchain:cross():gsub(\"(.*)%-$\", \"%1\")\n            if bindir and os.isexec(path.join(bindir, cross .. \"-gcc\" .. (is_host(\"windows\") and \".exe\" or \"\"))) then\n                local gcc_toolchain = path.directory(bindir)\n                toolchain:add(\"cxflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n                toolchain:add(\"mxflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n                toolchain:add(\"asflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n                toolchain:add(\"ldflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n                toolchain:add(\"shflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n            end\n            if sdkdir and os.isdir(path.join(sdkdir, cross, \"include\")) then\n                sysroot = path.join(sdkdir, cross)\n            end\n            if sysroot then\n                if os.isdir(path.join(sysroot, \"libc\")) then\n                    sysroot = path.join(sysroot, \"libc\")\n                end\n                toolchain:add(\"cxflags\", \"--sysroot=\" .. sysroot)\n                toolchain:add(\"mxflags\", \"--sysroot=\" .. sysroot)\n                toolchain:add(\"asflags\", \"--sysroot=\" .. sysroot)\n                toolchain:add(\"ldflags\", \"--sysroot=\" .. sysroot)\n                toolchain:add(\"shflags\", \"--sysroot=\" .. sysroot)\n            end\n        end\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/masm32/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"masm32\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://www.masm32.com\")\n    set_description(\"The MASM32 SDK\")\n\n    set_toolset(\"as\", \"ml.exe\")\n    set_toolset(\"mrc\", \"rc.exe\")\n    set_toolset(\"ld\", \"link.exe\")\n    set_toolset(\"sh\", \"link.exe\")\n    set_toolset(\"ar\", \"link.exe\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_masm32\")\n        local masm32 = find_masm32()\n        if masm32 and masm32.sdkdir and masm32.bindir and find_tool(\"ml.exe\", {program = path.join(masm32.bindir, \"ml.exe\")}) then\n            toolchain:config_set(\"sdkdir\", masm32.sdkdir)\n            toolchain:config_set(\"bindir\", masm32.bindir)\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        toolchain:arch_set(\"x86\")\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            toolchain:add(\"includedirs\", path.join(sdkdir, \"include\"))\n            toolchain:add(\"linkdirs\", path.join(sdkdir, \"lib\"))\n        end\n        toolchain:add(\"asflags\", \"/coff\")\n        toolchain:add(\"syslinks\", \"user32\", \"kernel32\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/mingw/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_mingw\")\n\n-- check the mingw toolchain\nfunction main(toolchain)\n    local mingw\n    for _, package in ipairs(toolchain:packages()) do\n        local installdir = package:installdir()\n        if installdir and os.isdir(installdir) then\n            mingw = find_mingw(installdir, {verbose = true, cross = toolchain:cross(), arch = toolchain:arch()})\n            if mingw then\n                break\n            end\n        end\n    end\n    if not mingw then\n        mingw = find_mingw(toolchain:config(\"mingw\") or config.get(\"mingw\"), {\n            verbose = true,\n            bindir = toolchain:bindir(),\n            cross = toolchain:cross(),\n            msystem = toolchain:config(\"msystem\"),\n            arch = toolchain:arch()\n        })\n    end\n    if mingw then\n        toolchain:config_set(\"mingw\", mingw.sdkdir)\n        toolchain:config_set(\"cross\", mingw.cross)\n        toolchain:config_set(\"bindir\", mingw.bindir)\n        return true\n    end\nend\n"
  },
  {
    "path": "xmake/toolchains/mingw/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"mingw\")\n    set_kind(\"standalone\")\n    set_homepage(\"http://www.mingw.org/\")\n    set_description(\"Minimalist GNU for Windows\")\n    set_runtimes(\"stdc++_static\", \"stdc++_shared\")\n\n    on_check(\"check\")\n    on_load(function (toolchain)\n\n        -- use clang for llvm-mingw?\n        local use_clang = toolchain:config(\"clang\")\n\n        -- get cross\n        -- https://github.com/xmake-io/xmake/issues/7196\n        local cross = toolchain:cross() or \"\"\n        if cross ~= \"\" then\n            local arch\n            if cross:startswith(\"x86_64\") then\n                arch = \"x86_64\"\n            elseif cross:startswith(\"i686\") then\n                arch = \"i386\"\n            elseif cross:startswith(\"aarch64\") then\n                arch = \"arm64\"\n            elseif cross:startswith(\"arm\") then\n                arch = \"armv7\"\n            end\n            if arch then\n                toolchain:arch_set(arch)\n            end\n        else\n            if toolchain:is_arch(\"x86_64\", \"x64\") then\n                cross = \"x86_64-w64-mingw32-\"\n            elseif toolchain:is_arch(\"i386\", \"x86\", \"i686\") then\n                cross = \"i686-w64-mingw32-\"\n            elseif toolchain:is_arch(\"arm64\", \"aarch64\") then\n                cross = \"aarch64-w64-mingw32-\"\n            elseif toolchain:is_arch(\"armv7\", \"arm.*\") then\n                cross = \"armv7-w64-mingw32-\"\n            end\n        end\n\n        -- add bin search library for loading some dependent .dll files windows\n        local bindir = toolchain:bindir()\n        if bindir and is_host(\"windows\") then\n            toolchain:add(\"runenvs\", \"PATH\", bindir)\n        end\n\n        -- set toolset\n        local cc = use_clang and \"clang\" or \"gcc\"\n        local cxx = use_clang and \"clang++\" or \"g++\"\n        local ar = use_clang and \"llvm-ar\" or \"ar\"\n        local ranlib = use_clang and \"llvm-ranlib\" or \"ranlib\"\n        if is_host(\"windows\") and bindir then\n            -- @note we uses bin/ar.exe instead of bin/cross-gcc-ar.exe, @see https://github.com/xmake-io/xmake/issues/807#issuecomment-635779210\n            toolchain:add(\"toolset\", \"ar\", path.join(bindir, ar))\n            toolchain:add(\"toolset\", \"strip\", path.join(bindir, \"strip\"))\n            toolchain:add(\"toolset\", \"ranlib\", path.join(bindir, ranlib))\n            toolchain:add(\"toolset\", \"objcopy\", path.join(bindir, \"objcopy\"))\n        end\n        toolchain:add(\"toolset\", \"cc\", cross .. cc)\n        toolchain:add(\"toolset\", \"cxx\", cross .. cxx, cross .. cc)\n        toolchain:add(\"toolset\", \"cpp\", cross .. cc .. \" -E\")\n        toolchain:add(\"toolset\", \"as\", cross .. cc)\n        toolchain:add(\"toolset\", \"ld\", cross .. cxx, cross .. cc)\n        toolchain:add(\"toolset\", \"sh\", cross .. cxx, cross .. cc)\n        toolchain:add(\"toolset\", \"ar\", cross .. ar)\n        toolchain:add(\"toolset\", \"strip\", cross .. \"strip\")\n        toolchain:add(\"toolset\", \"ranlib\", cross .. ranlib)\n        toolchain:add(\"toolset\", \"objcopy\", cross .. \"objcopy\")\n        toolchain:add(\"toolset\", \"mrc\", cross .. \"windres\")\n        toolchain:add(\"toolset\", \"dlltool\", cross .. \"dlltool\")\n        if is_host(\"windows\") and bindir then\n            -- we use bin/gcc.exe if cross not found\n            -- @see https://github.com/xmake-io/xmake/issues/977#issuecomment-704863677\n            toolchain:add(\"toolset\", \"cc\", path.join(bindir, cc))\n            toolchain:add(\"toolset\", \"cxx\", path.join(bindir, cxx), path.join(bindir, cc))\n            toolchain:add(\"toolset\", \"cpp\", path.join(bindir, cc .. \" -E\"))\n            toolchain:add(\"toolset\", \"as\", path.join(bindir, cc))\n            toolchain:add(\"toolset\", \"ld\", path.join(bindir, cxx), path.join(bindir, cc))\n            toolchain:add(\"toolset\", \"sh\", path.join(bindir, cxx), path.join(bindir, cc))\n            toolchain:add(\"toolset\", \"mrc\", path.join(bindir, \"windres\"))\n            toolchain:add(\"toolset\", \"dlltool\", path.join(bindir, \"dlltool\"))\n        end\n\n        -- init flags for architecture\n        local archflags = nil\n        local arch = toolchain:arch()\n        if arch == \"x86_64\" then archflags = \"-m64\"\n        elseif arch == \"i386\" then archflags = \"-m32\"\n        end\n        if archflags then\n            toolchain:add(\"cxflags\", archflags)\n            toolchain:add(\"asflags\", archflags)\n            toolchain:add(\"ldflags\", archflags)\n            toolchain:add(\"shflags\", archflags)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/msvc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\nfunction _check_cl(toolchain, vcvars)\n    local cl = find_tool(\"cl.exe\", {force = true, envs = vcvars})\n    if cl then\n        cprint(\"checking for Microsoft C/C++ Compiler (%s) ... ${color.success}${text.success}\", toolchain:arch())\n    end\n    return cl\nend\n\nfunction main(toolchain)\n\n    -- only for windows or linux (msvc-wine)\n    if not is_host(\"windows\", \"linux\") then\n        return\n    end\n\n    -- @see https://github.com/xmake-io/xmake/pull/679\n    local cc  = path.basename(config.get(\"cc\") or \"cl\"):lower()\n    local cxx = path.basename(config.get(\"cxx\") or \"cl\"):lower()\n    local mrc = path.basename(config.get(\"mrc\") or \"rc\"):lower()\n    if cc == \"cl\" or cxx == \"cl\" or mrc == \"rc\" then\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            sdkdir = toolchain_utils.check_vc_build_tools(toolchain, sdkdir, _check_cl)\n        end\n        if not sdkdir then\n            for _, package in ipairs(toolchain:packages()) do\n                local installdir = package:installdir()\n                if installdir and os.isdir(installdir) then\n                    local result = toolchain_utils.check_vc_build_tools(toolchain, installdir, _check_cl)\n                    if result then\n                        return result\n                    end\n                end\n            end\n            sdkdir = toolchain_utils.check_vstudio(toolchain, _check_cl)\n        end\n        return sdkdir\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/msvc/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.base.semver\")\nimport(\"core.project.config\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- main entry\nfunction main(toolchain)\n\n    -- set toolset\n    toolchain:set(\"toolset\", \"cc\",  \"cl.exe\")\n    toolchain:set(\"toolset\", \"cxx\", \"cl.exe\")\n    toolchain:set(\"toolset\", \"mrc\", \"rc.exe\")\n    if toolchain:is_arch(\"x86\") then\n        toolchain:set(\"toolset\", \"as\",  \"ml.exe\")\n    elseif toolchain:is_arch(\"arm64\", \"arm64ec\") then\n        toolchain:set(\"toolset\", \"as\",  \"armasm64_msvc@armasm64.exe\")\n    elseif toolchain:is_arch(\"arm.*\") then\n        toolchain:set(\"toolset\", \"as\",  \"armasm_msvc@armasm.exe\")\n    else\n        toolchain:set(\"toolset\", \"as\",  \"ml64.exe\")\n    end\n    toolchain:set(\"toolset\", \"ld\",  \"link.exe\")\n    toolchain:set(\"toolset\", \"sh\",  \"link.exe\")\n    toolchain:set(\"toolset\", \"ar\",  \"link.exe\")\n\n    -- init flags\n    if toolchain:is_arch(\"arm64ec\") then\n        toolchain:add(\"cxflags\", \"/arm64EC\")\n    end\n\n    -- add vs environments\n    toolchain_utils.add_vsenvs(toolchain)\n\n    -- check and add vs_binary_output env\n    local vs = toolchain:config(\"vs\")\n    if vs and semver.is_valid(vs) and semver.compare(vs, \"2005\") < 0 then\n        toolchain:add(\"runenvs\", \"VS_BINARY_OUTPUT\", \"1\")\n    end\nend\n\n"
  },
  {
    "path": "xmake/toolchains/msvc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- msvc toolchain\n--\n-- @param vs    the vs version\n--\n-- @code\n-- target(\"test\")\n--     ...\n--     set_toolchains(\"msvc\")\n--     set_toolchains(\"msvc\", {vs = \"2019\"})\n-- @endcode\n--\ntoolchain(\"msvc\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://visualstudio.microsoft.com\")\n    set_description(\"Microsoft Visual C/C++ Compiler\")\n    set_runtimes(\"MT\", \"MTd\", \"MD\", \"MDd\")\n\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/muslcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"muslcc\")\n    set_homepage(\"https://musl.cc/\")\n    set_description(\"The musl-based cross-compilation toolchains\")\n\n    -- mark as cross-compilation toolchain\n    set_kind(\"cross\")\n\n    on_load(function (toolchain)\n\n        -- load basic configuration of cross toolchain\n        toolchain:load_cross_toolchain()\n\n        -- add flags for arch\n        if toolchain:is_arch(\"arm\") then\n            toolchain:add(\"cxflags\", \"-march=armv7-a\", \"-msoft-float\", {force = true})\n            toolchain:add(\"ldflags\", \"-march=armv7-a\", \"-msoft-float\", {force = true})\n        end\n        toolchain:add(\"syslinks\", \"gcc\", \"c\")\n    end)\n"
  },
  {
    "path": "xmake/toolchains/nasm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"nasm\")\n\n    -- set homepage\n    set_homepage(\"https://www.nasm.us/\")\n    set_description(\"NASM Assembler\")\n\n    -- set toolset\n    set_toolset(\"as\", \"nasm\")\n\n    -- on load\n    on_load(function (toolchain)\n        local asflags = \"\" -- maybe 16bits if no flags\n        if toolchain:is_plat(\"macosx\") then\n            if toolchain:is_arch(\"x86_64\") then\n                asflags = \"-f macho64\"\n            elseif toolchain:is_arch(\"i386\") then\n                asflags = \"-f macho32\"\n            end\n        elseif toolchain:is_plat(\"linux\", \"android\", \"bsd\") then\n            if toolchain:is_arch(\"x86_64\") then\n                asflags = \"-f elf64\"\n            elseif toolchain:is_arch(\"i386\") then\n                asflags = \"-f elf32\"\n            end\n        elseif toolchain:is_plat(\"windows\", \"mingw\", \"msys\", \"cygwin\") then\n            if toolchain:is_arch(\"x64\", \"x86_64\") then\n                asflags = \"-f win64\"\n            elseif toolchain:is_arch(\"x86\", \"i386\") then\n                asflags = \"-f win32\"\n            end\n        end\n        toolchain:add(\"nasm.asflags\", asflags)\n    end)\n"
  },
  {
    "path": "xmake/toolchains/ndk/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_ndk\")\nimport(\"detect.sdks.find_android_sdk\")\n\n-- check the ndk toolchain\nfunction _check_ndk(toolchain)\n    local ndk\n    for _, package in ipairs(toolchain:packages()) do\n        local installdir = package:installdir()\n        if installdir and os.isdir(installdir) then\n            ndk = find_ndk(installdir, {force = true, verbose = option.get(\"verbose\"),\n                                        plat = toolchain:plat(),\n                                        arch = toolchain:arch(),\n                                        sdkver = toolchain:config(\"sdkver\")})\n            if ndk then\n                break\n            end\n        end\n    end\n    if not ndk then\n        ndk = find_ndk(toolchain:config(\"ndk\") or config.get(\"ndk\"), {force = true, verbose = true,\n                                                                      plat = toolchain:plat(),\n                                                                      arch = toolchain:arch(),\n                                                                      compiler = toolchain:config(\"gcc\") and \"gcc\" or \"clang\",\n                                                                      sdkver = toolchain:config(\"sdkver\")})\n    end\n    if ndk then\n        toolchain:config_set(\"ndk\", ndk.sdkdir)\n        toolchain:config_set(\"bindir\", ndk.bindir)\n        toolchain:config_set(\"cross\", ndk.cross)\n        toolchain:config_set(\"llvm_toolchain\", ndk.llvm_toolchain)\n        toolchain:config_set(\"gcc_toolchain\", ndk.gcc_toolchain)\n        toolchain:config_set(\"ndkver\", ndk.ndkver)\n        toolchain:config_set(\"ndk_sdkver\", ndk.sdkver)\n        toolchain:config_set(\"ndk_toolchains_ver\", ndk.toolchains_ver)\n        toolchain:config_set(\"ndk_sysroot\", ndk.sysroot)\n        return true\n    else\n        --[[TODO we also need to add this tips when use remote ndk toolchain\n        -- failed\n        cprint(\"${bright color.error}please run:\")\n        cprint(\"    - xmake config --ndk=xxx\")\n        cprint(\"or  - xmake global --ndk=xxx\")\n        raise()]]\n    end\nend\n\n-- check the android sdk\nfunction _check_android_sdk(toolchain)\n    local sdk = find_android_sdk(toolchain:config(\"android_sdk\") or config.get(\"android_sdk\"), {force = true, verbose = toolchain:is_global()})\n    if sdk then\n        toolchain:config_set(\"android_sdk\", sdk.sdkdir)\n        toolchain:config_set(\"build_toolver\", sdk.build_toolver)\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n    _check_android_sdk(toolchain)\n    return _check_ndk(toolchain)\nend\n"
  },
  {
    "path": "xmake/toolchains/ndk/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n\n-- imports\nimport(\"core.base.hashset\")\nimport(\"core.project.config\")\n\n-- get triple\nfunction _get_triple(arch)\n    local triples =\n    {\n        [\"armv5te\"]     = \"arm-linux-androideabi\"   -- deprecated\n    ,   [\"armv7-a\"]     = \"arm-linux-androideabi\"   -- deprecated\n    ,   [\"armeabi\"]     = \"arm-linux-androideabi\"   -- removed in ndk r17\n    ,   [\"armeabi-v7a\"] = \"arm-linux-androideabi\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-linux-android\"\n    ,   [\"riscv64\"]     = \"riscv64-linux-android\"\n    ,   i386            = \"i686-linux-android\"      -- deprecated\n    ,   x86             = \"i686-linux-android\"\n    ,   x86_64          = \"x86_64-linux-android\"\n    ,   mips            = \"mips-linux-android\"      -- removed in ndk r17\n    ,   mips64          = \"mips64-linux-android\"    -- removed in ndk r17\n    }\n    return triples[arch]\nend\n\n-- get target\nfunction _get_target(arch, ndk_sdkver)\n    local targets =\n    {\n        [\"armv5te\"]     = \"armv5te-none-linux-androideabi\"  -- deprecated\n    ,   [\"armeabi\"]     = \"armv5te-none-linux-androideabi\"  -- removed in ndk r17\n    ,   [\"armv7-a\"]     = \"armv7-none-linux-androideabi\"    -- deprecated\n    ,   [\"armeabi-v7a\"] = \"armv7-none-linux-androideabi\"\n    ,   [\"arm64-v8a\"]   = \"aarch64-none-linux-android\"\n    ,   [\"riscv64\"]     = \"riscv64-none-linux-android\"\n    ,   [\"i386\"]        = \"i686-none-linux-android\"         -- deprecated\n    ,   [\"x86\"]         = \"i686-none-linux-android\"\n    ,   [\"x86_64\"]      = \"x86_64-none-linux-android\"\n    ,   [\"mips\"]        = \"mipsel-none-linux-android\"       -- removed in ndk r17\n    ,   [\"mips64\"]      = \"mips64el-none-linux-android\"     -- removed in ndk r17\n    }\n    assert(targets[arch], \"unknown arch(%s) for android!\", arch)\n    return targets[arch] .. (ndk_sdkver or \"\")\nend\n\n-- load ndk toolchain\n--\n-- some extra configuration for target\n-- e.g.\n--   set_values(\"ndk.arm_mode\", \"arm\") -- or thumb\n--\nfunction main(toolchain)\n\n    -- get cross\n    local cross = toolchain:cross() or \"\"\n\n    -- get gcc toolchain bin directory\n    local gcc_toolchain_bin = nil\n    local gcc_toolchain = toolchain:config(\"gcc_toolchain\")\n    if gcc_toolchain then\n        gcc_toolchain_bin = path.join(gcc_toolchain, \"bin\")\n    end\n\n    -- get ndk and version\n    local ndk = toolchain:config(\"ndk\")\n    local ndkver = toolchain:config(\"ndkver\")\n    local ndk_sdkver = toolchain:config(\"ndk_sdkver\")\n\n    -- set toolset\n    local use_gcc = toolchain:config(\"gcc\")\n    if use_gcc then\n        toolchain:set(\"toolset\", \"cc\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"cxx\", cross .. \"g++\")\n        toolchain:set(\"toolset\", \"cpp\", cross .. \"gcc -E\")\n        toolchain:set(\"toolset\", \"as\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"ld\", cross .. \"g++\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"sh\", cross .. \"g++\", cross .. \"gcc\")\n    else\n        toolchain:set(\"toolset\", \"cc\", \"clang\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"cxx\", \"clang++\", cross .. \"g++\")\n        toolchain:set(\"toolset\", \"cpp\", \"clang -E\", cross .. \"gcc -E\")\n        toolchain:set(\"toolset\", \"as\", \"clang\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"ld\", \"clang++\", \"clang\", cross .. \"g++\", cross .. \"gcc\")\n        toolchain:set(\"toolset\", \"sh\", \"clang++\", \"clang\", cross .. \"g++\", cross .. \"gcc\")\n    end\n    toolchain:set(\"toolset\", \"ar\", gcc_toolchain_bin and path.join(gcc_toolchain_bin, cross .. \"ar\") or (cross .. \"ar\"), \"llvm-ar\")\n    toolchain:set(\"toolset\", \"ranlib\", gcc_toolchain_bin and path.join(gcc_toolchain_bin, cross .. \"ranlib\") or (cross .. \"ranlib\"))\n    toolchain:set(\"toolset\", \"strip\", gcc_toolchain_bin and path.join(gcc_toolchain_bin, cross .. \"strip\") or (cross .. \"strip\"), \"llvm-strip\")\n    -- gnustl and stlport have been removed in ndk r18 (deprecated in ndk r17)\n    -- https://github.com/android/ndk/wiki/Changelog-r18\n    local old_runtimes = {\"gnustl_static\", \"gnustl_shared\", \"stlport_static\", \"stlport_shared\"}\n    if ndkver and ndkver < 18 then\n        toolchain:add(\"runtimes\", table.unpack(old_runtimes))\n    end\n\n    -- init flags\n    local arm32 = false\n    local arch = toolchain:arch()\n    toolchain:add(\"ldflags\", \"-llog\")\n    toolchain:add(\"shflags\", \"-llog\")\n    if arch and (arch == \"armeabi\" or arch == \"armeabi-v7a\" or arch == \"armv5te\" or arch == \"armv7-a\") then -- armv5te/armv7-a are deprecated\n        arm32 = true\n    end\n\n    -- use llvm directory? e.g. android-ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin\n    local isllvm = false\n    local bindir = toolchain:bindir()\n    if bindir and bindir:find(\"llvm\", 1, true) then\n        isllvm = true\n    end\n\n    -- init architecture\n    if isllvm then\n\n        -- add ndk target\n        local ndk_target = _get_target(arch, ndk_sdkver)\n        toolchain:add(\"cxflags\", \"--target=\" .. ndk_target)\n        toolchain:add(\"asflags\", \"--target=\" .. ndk_target)\n        toolchain:add(\"ldflags\", \"--target=\" .. ndk_target)\n        toolchain:add(\"shflags\", \"--target=\" .. ndk_target)\n\n        -- add gcc toolchain\n        local gcc_toolchain = toolchain:config(\"gcc_toolchain\")\n        if gcc_toolchain then\n            toolchain:add(\"cxflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n            toolchain:add(\"asflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n            toolchain:add(\"ldflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n            toolchain:add(\"shflags\", \"--gcc-toolchain=\" .. gcc_toolchain)\n        end\n    else\n        local march = arch\n        if arch == \"arm64-v8a\" then\n            march = \"armv8-a\"\n        else\n            march = \"armv5te\"\n        end\n        -- old version ndk\n        toolchain:add(\"cxflags\", \"-march=\" .. march)\n        toolchain:add(\"asflags\", \"-march=\" .. march)\n        toolchain:add(\"ldflags\", \"-march=\" .. march)\n        toolchain:add(\"shflags\", \"-march=\" .. march)\n    end\n\n    -- init cxflags for the target kind: binary\n    toolchain:add(\"binary.cxflags\", \"-fPIE\", \"-pie\")\n\n    -- add flags for the sdk directory of ndk\n    if ndk and ndk_sdkver then\n\n        -- the sysroot archs\n        local sysroot_archs =\n        {\n            [\"armv5te\"]     = \"arch-arm\"    -- deprecated\n        ,   [\"armv7-a\"]     = \"arch-arm\"    -- deprecated\n        ,   [\"armeabi\"]     = \"arch-arm\"    -- removed in ndk r17\n        ,   [\"armeabi-v7a\"] = \"arch-arm\"\n        ,   [\"arm64-v8a\"]   = \"arch-arm64\"\n        ,   [\"riscv64\"]     = \"arch-riscv64\"\n        ,   i386            = \"arch-x86\"    -- deprecated\n        ,   x86             = \"arch-x86\"\n        ,   x86_64          = \"arch-x86_64\"\n        ,   mips            = \"arch-mips\"   -- removed in ndk r17\n        ,   mips64          = \"arch-mips64\" -- removed in ndk r17\n        }\n        local sysroot_arch = sysroot_archs[arch]\n\n        -- add sysroot flags\n        local sysroot_cflags_added = false\n        local ndk_sysroot = toolchain:config(\"ndk_sysroot\")\n        if ndk_sysroot and os.isdir(ndk_sysroot) then\n            local triple = _get_triple(arch)\n            if ndkver and tonumber(ndkver) < 22 then\n                toolchain:add(\"cxflags\", \"-D__ANDROID_API__=\" .. ndk_sdkver)\n                toolchain:add(\"asflags\", \"-D__ANDROID_API__=\" .. ndk_sdkver)\n            end\n            local flag_sysroot = \"--sysroot=\" .. os.args(ndk_sysroot)\n            local flag_isystem = \"-isystem \" .. os.args(path.join(ndk_sysroot, \"usr\", \"include\", triple))\n            toolchain:add(\"cflags\",   flag_sysroot)\n            toolchain:add(\"cxxflags\", flag_sysroot)\n            toolchain:add(\"asflags\",  flag_sysroot)\n            toolchain:add(\"cflags\",   flag_isystem)\n            toolchain:add(\"cxxflags\", flag_isystem)\n            toolchain:add(\"asflags\",  flag_isystem)\n            sysroot_cflags_added = true\n        end\n        local ndk_sdkdir = path.translate(format(\"%s/platforms/android-%d\", ndk, ndk_sdkver))\n        if os.isdir(ndk_sdkdir) then\n            if sysroot_arch then\n                local flag_sysroot = \"--sysroot=\" .. os.args(path.join(ndk_sdkdir, sysroot_arch))\n                if not sysroot_cflags_added then\n                    toolchain:add(\"cflags\",   flag_sysroot)\n                    toolchain:add(\"cxxflags\", flag_sysroot)\n                    toolchain:add(\"asflags\",  flag_sysroot)\n                end\n                -- we need to add sysroot flags for low-version ndk\n                -- @see https://github.com/xmake-io/xmake/issues/6621\n                toolchain:add(\"ldflags\",  flag_sysroot)\n                toolchain:add(\"shflags\",  flag_sysroot)\n            end\n        end\n\n        -- add \"-fPIE -pie\" to ldflags\n        toolchain:add(\"ldflags\", \"-fPIE\")\n        toolchain:add(\"ldflags\", \"-pie\")\n\n        -- get llvm c++ stl sdk directory\n        local cxxstl_sdkdir_llvmstl = path.translate(format(\"%s/sources/cxx-stl/llvm-libc++\", ndk))\n\n        -- get gnu c++ stl sdk directory\n        local cxxstl_sdkdir_gnustl = nil\n        if toolchain:config(\"ndk_toolchains_ver\") then\n            cxxstl_sdkdir_gnustl = path.translate(format(\"%s/sources/cxx-stl/gnu-libstdc++/%s\", ndk, toolchain:config(\"ndk_toolchains_ver\")))\n        end\n\n        -- get stlport c++ sdk directory\n        local cxxstl_sdkdir_stlport = path.translate(format(\"%s/sources/cxx-stl/stlport\", ndk))\n\n        -- get c++ stl sdk directory\n        local cxxstl_sdkdir = nil\n        local ndk_cxxstl = config.get(\"runtimes\") or config.get(\"ndk_cxxstl\")\n        if ndk_cxxstl then\n            if (ndkver and ndkver >= 18) and table.contains(old_runtimes, ndk_cxxstl)  then\n                utils.warning(\"%s is was removed in ndk v%s\", ndk_cxxstl, ndk_sdkver)\n            end\n\n            if ndk_cxxstl:find(\",\", 1, true) then\n                local runtimes_supported = hashset.from(toolchain:get(\"runtimes\"))\n                for _, item in ipairs(ndk_cxxstl:split(\",\")) do\n                    if runtimes_supported:has(item) then\n                        ndk_cxxstl = item\n                        break\n                    end\n                end\n            end\n            -- we uses c++_static/c++_shared instead of llvmstl_static/llvmstl_shared\n            if ndk_cxxstl:startswith(\"c++\") or ndk_cxxstl:startswith(\"llvmstl\") then\n                cxxstl_sdkdir = cxxstl_sdkdir_llvmstl\n            elseif ndk_cxxstl:startswith(\"gnustl\") then\n                cxxstl_sdkdir = cxxstl_sdkdir_gnustl\n            elseif ndk_cxxstl:startswith(\"stlport\") then\n                cxxstl_sdkdir = cxxstl_sdkdir_stlport\n            end\n        else\n            if isllvm then\n                ndk_cxxstl = \"c++_static\"\n                cxxstl_sdkdir = cxxstl_sdkdir_llvmstl\n            end\n            if (cxxstl_sdkdir == nil or not os.isdir(cxxstl_sdkdir)) and cxxstl_sdkdir_gnustl then -- <= ndk r16\n                ndk_cxxstl = \"gnustl_static\"\n                cxxstl_sdkdir = cxxstl_sdkdir_gnustl\n            end\n        end\n\n        -- only for c++ stl\n        if config.get(\"ndk_stdcxx\") then\n            if cxxstl_sdkdir and os.isdir(cxxstl_sdkdir) then\n\n                -- the toolchains archs\n                local toolchains_archs =\n                {\n                    [\"armv5te\"]     = \"armeabi\"         -- deprecated\n                ,   [\"armv7-a\"]     = \"armeabi-v7a\"     -- deprecated\n                ,   [\"armeabi\"]     = \"armeabi\"         -- removed in ndk r17\n                ,   [\"armeabi-v7a\"] = \"armeabi-v7a\"\n                ,   [\"arm64-v8a\"]   = \"arm64-v8a\"\n                ,   [\"riscv64\"]     = \"riscv64\"\n                ,   i386            = \"x86\"             -- deprecated\n                ,   x86             = \"x86\"\n                ,   x86_64          = \"x86_64\"\n                ,   mips            = \"mips\"            -- removed in ndk r17\n                ,   mips64          = \"mips64\"          -- removed in ndk r17\n                }\n                local toolchains_arch = toolchains_archs[arch]\n\n                -- add c++ stl include and link directories\n                if toolchains_arch then\n                    toolchain:add(\"linkdirs\", format(\"%s/libs/%s\", cxxstl_sdkdir, toolchains_arch))\n                end\n                if ndk_cxxstl:startswith(\"c++\") or ndk_cxxstl:startswith(\"llvmstl\") then\n                    toolchain:add(\"cxxflags\", \"-nostdinc++\")\n                    toolchain:add(\"sysincludedirs\", format(\"%s/include\", cxxstl_sdkdir))\n                    if toolchains_arch then\n                        toolchain:add(\"sysincludedirs\", format(\"%s/libs/%s/include\", cxxstl_sdkdir, toolchains_arch))\n                    end\n                    local abi_path = path.join(ndk, \"sources\", \"cxx-stl\", \"llvm-libc++abi\")\n                    local before_r13 = path.join(abi_path, \"libcxxabi\")\n                    local after_r13 = path.join(abi_path, \"include\")\n                    if os.isdir(before_r13) then\n                        toolchain:add(\"sysincludedirs\", before_r13)\n                    elseif os.isdir(after_r13) then\n                        toolchain:add(\"sysincludedirs\", after_r13)\n                    end\n                elseif ndk_cxxstl:startswith(\"gnustl\") then\n                    toolchain:add(\"cxxflags\", \"-nostdinc++\")\n                    toolchain:add(\"sysincludedirs\", format(\"%s/include\", cxxstl_sdkdir))\n                    if toolchains_arch then\n                        toolchain:add(\"sysincludedirs\", format(\"%s/libs/%s/include\", cxxstl_sdkdir, toolchains_arch))\n                    end\n                elseif ndk_cxxstl:startswith(\"stlport\") then\n                    toolchain:add(\"cxxflags\", \"-nostdinc++\")\n                    toolchain:add(\"sysincludedirs\", format(\"%s/stlport\", cxxstl_sdkdir))\n                end\n\n                -- add c++ stl links\n                if ndk_cxxstl == \"c++_static\" or ndk_cxxstl == \"llvmstl_static\" then\n                    toolchain:add(\"syslinks\", \"c++_static\", \"c++abi\")\n                    if arm32 then\n                        toolchain:add(\"syslinks\", \"unwind\", \"atomic\")\n                    end\n                elseif ndk_cxxstl == \"c++_shared\" or ndk_cxxstl == \"llvmstl_shared\" then\n                    toolchain:add(\"syslinks\", \"c++_shared\", \"c++abi\")\n                    if arm32 then\n                        toolchain:add(\"syslinks\", \"unwind\", \"atomic\")\n                    end\n                elseif ndk_cxxstl == \"gnustl_static\" then\n                    toolchain:add(\"syslinks\", \"gnustl_static\")\n                elseif ndk_cxxstl == \"gnustl_shared\" then\n                    toolchain:add(\"syslinks\", \"gnustl_shared\")\n                elseif ndk_cxxstl == \"stlport_static\" then\n                    toolchain:add(\"syslinks\", \"stlport_static\")\n                elseif ndk_cxxstl == \"stlport_shared\" then\n                    toolchain:add(\"syslinks\", \"stlport_shared\")\n                end\n\n                -- fix 'ld: error: cannot find -lc++' for clang++.exe on r20/windows\n                -- @see https://github.com/xmake-io/xmake/issues/684\n                if ndkver and ndkver >= 20 and (ndk_cxxstl:startswith(\"c++\") or ndk_cxxstl:startswith(\"llvmstl\")) then\n                    toolchain:add(\"ldflags\", \"-nostdlib++\")\n                    toolchain:add(\"shflags\", \"-nostdlib++\")\n                end\n            elseif ndkver and ndkver >= 26 then\n                -- The NDK's libc++ now comes directly from our LLVM toolchain above 26b\n                -- https://github.com/xmake-io/xmake/issues/4614\n                if ndk_cxxstl == \"c++_static\" then\n                    toolchain:add(\"ldflags\", \"-static-libstdc++\", \"-lc++abi\")\n                    toolchain:add(\"shflags\", \"-static-libstdc++\", \"-lc++abi\")\n                    if arm32 then\n                        toolchain:add(\"syslinks\", \"unwind\", \"atomic\")\n                    end\n                elseif ndk_cxxstl == \"c++_shared\" then\n                    if arm32 then\n                        toolchain:add(\"syslinks\", \"unwind\", \"atomic\")\n                    end\n                end\n            end\n        end\n    end\n\n    -- init flags for target\n    local target_on_xxflags = function (target)\n        if arm32 then\n            -- @see https://github.com/xmake-io/xmake/issues/927\n            if target:values(\"ndk.arm_mode\") == \"arm\" then\n                return \"-marm\"\n            else\n                return \"-mthumb\"\n            end\n        end\n    end\n    toolchain:add(\"target.on_cxflags\", target_on_xxflags)\n    toolchain:add(\"target.on_asflags\", target_on_xxflags)\n    toolchain:add(\"target.on_ldflags\", target_on_xxflags)\n    toolchain:add(\"target.on_shflags\", target_on_xxflags)\n\n    local rcshflags = table.copy(toolchain:get(\"shflags\"))\n    local rcldflags = table.copy(toolchain:get(\"ldflags\"))\n    for _, link in ipairs(toolchain:get(\"syslinks\")) do\n        table.insert(rcshflags, \"-l\" .. link)\n        table.insert(rcldflags, \"-l\" .. link)\n    end\n    -- fix [[note: clang++: error: no such file or directory: '\"-llog']] on windows\n    -- @note 'link-args=...' should not be 'link-args=\"...\"'\n    toolchain:set(\"rcshflags\", {\"-C\", \"link-args=\" .. (table.concat(rcshflags, \" \"):gsub(\"%-march=.-%s\", \"\"))}, {expand = false})\n    toolchain:set(\"rcldflags\", {\"-C\", \"link-args=\" .. (table.concat(rcldflags, \" \"):gsub(\"%-march=.-%s\", \"\"))}, {expand = false})\n    local sh = toolchain:tool(\"sh\") -- @note we cannot use `config.get(\"sh\")`, because we need to check sh first\n    if sh then\n        toolchain:add(\"rcshflags\", \"-C linker=\" .. sh)\n    end\n    local ld = toolchain:tool(\"ld\")\n    if ld then\n        toolchain:add(\"rcldflags\", \"-C linker=\" .. ld)\n    end\nend\n"
  },
  {
    "path": "xmake/toolchains/ndk/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- android ndk toolchain\n--\n-- @param sdkver    the platform sdk version\n--\n-- @code\n-- target(\"test\")\n--     ...\n--     set_toolchains(\"ndk\")\n--     set_toolchains(\"ndk\", {sdkver = \"23\"})\n-- @endcode\n--\ntoolchain(\"ndk\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://developer.android.com/ndk\")\n    set_description(\"Android NDK\")\n    set_runtimes(\"c++_static\", \"c++_shared\")\n\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/nim/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"nim\")\n    set_homepage(\"https://nim-lang.org/\")\n    set_description(\"Nim Programming Language Compiler\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        local paths = {}\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n            end\n        end\n        local nim = get_config(\"nc\")\n        if not nim then\n            nim = find_tool(\"nim\", {force = true, paths = paths})\n            if nim and nim.program then\n                nim = nim.program\n            end\n        end\n        if nim then\n            toolchain:config_set(\"nim\", nim)\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        local nim = toolchain:config(\"nim\") or \"nim\"\n        toolchain:set(\"toolset\", \"nc\",   \"$(env NC)\", nim)\n        toolchain:set(\"toolset\", \"ncld\", \"$(env NC)\", nim)\n        toolchain:set(\"toolset\", \"ncsh\", \"$(env NC)\", nim)\n        toolchain:set(\"toolset\", \"ncar\", \"$(env NC)\", nim)\n\n        if toolchain:is_plat(\"windows\") then\n            toolchain:set(\"ncflags\", \"--cc:vcc\")\n            local msvc = import(\"core.tool.toolchain\", {anonymous = true}).load(\"msvc\", {plat = toolchain:plat(), arch = toolchain:arch()})\n            for name, value in pairs(msvc:get(\"runenvs\")) do\n                 toolchain:add(\"runenvs\", name, value)\n            end\n        end\n        toolchain:set(\"ncshflags\", \"\")\n        toolchain:set(\"ncldflags\", \"\")\n    end)\n\n"
  },
  {
    "path": "xmake/toolchains/rust/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"rust\")\n    set_homepage(\"https://www.rust-lang.org/\")\n    set_description(\"Rust Programming Language Compiler\")\n\n    set_toolset(\"rc\",   \"$(env RC)\", \"rustc\")\n    set_toolset(\"rcld\", \"$(env RC)\", \"rustc\")\n    set_toolset(\"rcsh\", \"$(env RC)\", \"rustc\")\n    set_toolset(\"rcar\", \"$(env RC)\", \"rustc\")\n\n    on_load(function (toolchain)\n        import(\"core.tools.rustc.target_triple\")\n\n        local opt = {}\n        if toolchain:config(\"appledev\") == \"simulator\" then\n            opt.apple_sim = true\n        end\n\n        local target = target_triple(toolchain:plat(), toolchain:arch(), opt)\n        if target then\n            toolchain:add(\"rcflags\", \"--target=\" .. target)\n        else\n            toolchain:set(\"rcshflags\", \"\")\n            toolchain:set(\"rcldflags\", \"\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/sdcc/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.project.config\")\nimport(\"lib.detect.find_tool\")\nimport(\"detect.sdks.find_cross_toolchain\")\n\n-- check the cross toolchain\nfunction main(toolchain)\n    local sdkdir = toolchain:sdkdir()\n    local bindir = toolchain:bindir()\n    local cross_toolchain = find_cross_toolchain(sdkdir, {bindir = bindir})\n    if cross_toolchain then\n        toolchain:config_set(\"cross\", cross_toolchain.cross)\n        toolchain:config_set(\"bindir\", cross_toolchain.bindir)\n        return true\n    end\n    return find_tool(\"sdcc\")\nend\n"
  },
  {
    "path": "xmake/toolchains/sdcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"sdcc\")\n    set_kind(\"standalone\")\n    set_homepage(\"http://sdcc.sourceforge.net/\")\n    set_description(\"Small Device C Compiler\")\n\n    set_toolset(\"cc\",  \"sdcc\")\n    set_toolset(\"cxx\", \"sdcc\")\n    set_toolset(\"cpp\", \"sdcpp\")\n    set_toolset(\"as\",  \"sdcc\")\n    set_toolset(\"ld\",  \"sdcc\")\n    set_toolset(\"sh\",  \"sdcc\")\n    set_toolset(\"ar\",  \"sdar\")\n\n    set_archs(\"stm8\", \"mcs51\", \"z80\", \"z180\", \"r2k\", \"r3ka\", \"s08\", \"hc08\")\n\n    set_formats(\"static\", \"$(name).lib\")\n    set_formats(\"object\", \"$(name).rel\")\n    set_formats(\"binary\", \"$(name).bin\")\n    set_formats(\"symbol\", \"$(name).sym\")\n\n    on_check(\"check\")\n\n    on_load(function (toolchain)\n        local arch = toolchain:arch()\n        if arch and arch ~= \"none\" then\n            toolchain:add(\"cxflags\", \"-m\" .. arch)\n            toolchain:add(\"ldflags\", \"-m\" .. arch)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/swift/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, TBOOX Open Sousce Group.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"swift\")\n\n    -- set homepage\n    set_homepage(\"https://swift.org/\")\n    set_description(\"Swift Programming Language Compiler\")\n\n    -- set toolset\n    set_toolset(\"sc\",   \"$(env SC)\", \"swift-frontend\", \"swiftc\")\n    set_toolset(\"scsh\", \"$(env SC)\", \"swiftc\")\n    set_toolset(\"scar\", \"$(env SC)\", \"swiftc\")\n    set_toolset(\"scld\", \"$(env SC)\", \"swiftc\")\n\n    -- on load\n    on_load(function (toolchain)\n        if toolchain:is_plat(\"macosx\") then\n            if not toolchain:config(\"xcode_sysroot\") then\n                local xcode_dir     = get_config(\"xcode\")\n                local xcode_sdkver  = toolchain:config(\"xcode_sdkver\")\n                local xcode_sdkdir  = path.join(xcode_dir, \"Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX\" .. xcode_sdkver .. \".sdk\")\n                if os.isdir(xcode_sdkdir) then\n                    toolchain:config_set(\"xcode_sysroot\", xcode_sdkdir)\n                end\n            end\n            -- load configurations\n            import(\".xcode.load\")(toolchain)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/ti-c2000/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"ti-c2000\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://www.ti.com\")\n    set_description(\"TI-CGT C2000 compiler\")\n\n    set_toolset(\"cc\", \"cl2000\")\n    set_toolset(\"cxx\", \"cl2000\")\n    set_toolset(\"ld\", \"cl2000\")\n    set_toolset(\"sh\", \"cl2000\")\n    set_toolset(\"ar\", \"ar2000\")\n    set_toolset(\"strip\", \"strip6x\")\n    set_toolset(\"as\", \"cl2000\")\n\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"cl2000\")\n    end)\n\n    on_load(function (toolchain)\n        local march = {\"-ml\", \"-mt\", \"-v28\"} -- TODO\n        if march then\n            toolchain:add(\"cxflags\", march)\n            toolchain:add(\"mxflags\", march)\n            toolchain:add(\"asflags\", march)\n            toolchain:add(\"ldflags\", march)\n            toolchain:add(\"shflags\", march)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/ti-c6000/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"ti-c6000\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://www.ti.com\")\n    set_description(\"TI-CGT C6000 compiler\")\n\n    set_toolset(\"cc\", \"cl6x\")\n    set_toolset(\"cxx\", \"cl6x\")\n    set_toolset(\"ld\", \"cl6x\")\n    set_toolset(\"sh\", \"cl6x\")\n    set_toolset(\"ar\", \"ar6x\")\n    set_toolset(\"strip\", \"strip6x\")\n    set_toolset(\"as\", \"cl6x\")\n\n    on_check(function (toolchain)\n        return import(\"lib.detect.find_tool\")(\"cl6x\")\n    end)\n\n    on_load(function (toolchain)\n        local march = \"-mv64+\"\n        if march then\n            toolchain:add(\"cxflags\", march)\n            toolchain:add(\"mxflags\", march)\n            toolchain:add(\"asflags\", march)\n            toolchain:add(\"ldflags\", march)\n            toolchain:add(\"shflags\", march)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/tinycc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"tinycc\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://bellard.org/tcc/\")\n    set_description(\"Tiny C Compiler\")\n\n    on_check(function (toolchain)\n        import(\"core.project.config\")\n        import(\"lib.detect.find_tool\")\n\n        local paths = {toolchain:bindir()}\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            table.insert(paths, path.join(sdkdir, \"bin\"))\n        end\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir then\n                table.insert(paths, path.join(installdir, \"bin\"))\n            end\n        end\n        local tcc = find_tool(\"tcc\", {paths = paths, force = true})\n        if tcc then\n            toolchain:config_set(\"tcc\", tcc.program)\n            if os.isfile(tcc.program) then\n                toolchain:config_set(\"bindir\", path.directory(tcc.program))\n            end\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        import(\"core.project.config\")\n\n        -- add march flags\n        local march\n        if toolchain:is_arch(\"x86_64\", \"x64\") then\n            march = \"-m64\"\n        elseif toolchain:is_arch(\"i386\", \"x86\") then\n            march = \"-m32\"\n        end\n        if march then\n            toolchain:add(\"cxflags\", march)\n            toolchain:add(\"mxflags\", march)\n            toolchain:add(\"asflags\", march)\n            toolchain:add(\"ldflags\", march)\n            toolchain:add(\"shflags\", march)\n        end\n\n        -- add toolset\n        local tcc = toolchain:config(\"tcc\") or \"tcc\"\n        toolchain:add(\"toolset\", \"cc\", tcc)\n        toolchain:add(\"toolset\", \"ld\", tcc)\n        toolchain:add(\"toolset\", \"sh\", tcc)\n        toolchain:add(\"toolset\", \"ar\", tcc)\n        toolchain:add(\"toolset\", \"as\", tcc)\n\n        -- add includedirs and linkdirs\n        for _, package in ipairs(toolchain:packages()) do\n            local installdir = package:installdir()\n            if installdir then\n                toolchain:add(\"sysincludedirs\", path.join(installdir, \"include\"))\n                toolchain:add(\"linkdirs\", path.join(installdir, \"lib\"))\n            end\n        end\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir and os.isdir(sdkdir) then\n            local includedir = path.join(sdkdir, \"include\")\n            if os.isdir(includedir) then\n                toolchain:add(\"sysincludedirs\", includedir)\n            end\n            local libdir = path.join(sdkdir, \"lib\")\n            if os.isdir(libdir) then\n                toolchain:add(\"linkdirs\", libdir)\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/verilator/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"verilator\")\n    set_homepage(\"https://verilator.org/\")\n    set_description(\"Verilator open-source SystemVerilog simulator and lint system\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        local paths = {}\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n            end\n        end\n        local verilator = find_tool(\"verilator\", {paths = paths})\n        if verilator and verilator.program then\n            toolchain:config_set(\"verilator\", verilator.program)\n            cprint(\"${dim}checking for verilator ... ${color.success}%s\", path.filename(verilator.program))\n        else\n            cprint(\"${dim}checking for verilator ... ${color.nothing}${text.nothing}\")\n            raise(\"verilator not found!\")\n        end\n        return true\n    end)\n\n    on_load(function (toolchain)\n        if is_host(\"windows\") then\n            for _, package in ipairs(toolchain:packages()) do\n                local envs = package:envs()\n                if envs then\n                    local verilator_root = envs.VERILATOR_ROOT\n                    if verilator_root then\n                        toolchain:add(\"runenvs\", \"VERILATOR_ROOT\", table.unwrap(verilator_root))\n                        break\n                    end\n                end\n            end\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/wasi/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      wsw0108\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"wasi\")\n\n    -- set homepage\n    set_homepage(\"https://github.com/WebAssembly/wasi-sdk\")\n    set_description(\"WASI-enabled WebAssembly C/C++ toolchain.\")\n\n    -- mark as standalone toolchain\n    set_kind(\"standalone\")\n\n    -- set toolset\n    set_toolset(\"cc\",     \"clang\")\n    set_toolset(\"cxx\",    \"clang\", \"clang++\")\n    set_toolset(\"cpp\",    \"clang -E\")\n    set_toolset(\"as\",     \"clang\")\n    set_toolset(\"ld\",     \"clang++\", \"clang\")\n    set_toolset(\"sh\",     \"clang++\", \"clang\")\n    set_toolset(\"ar\",     \"llvm-ar\")\n    set_toolset(\"ranlib\", \"llvm-ranlib\")\n    set_toolset(\"strip\",  \"llvm-strip\")\n\n    -- check toolchain\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n        import(\"detect.sdks.find_wasisdk\")\n        local wasisdk = find_wasisdk(toolchain:sdkdir())\n        if wasisdk then\n            toolchain:config_set(\"bindir\", wasisdk.bindir)\n            toolchain:config_set(\"sdkdir\", wasisdk.sdkdir)\n            return wasisdk\n        end\n        return import(\"lib.detect.find_tool\")(\"clang\", {paths = toolchain:bindir()})\n    end)\n\n    -- on load\n    on_load(function (toolchain)\n\n        local sdkdir = toolchain:sdkdir()\n        local sysroot = path.join(sdkdir, \"share\", \"wasi-sysroot\")\n        toolchain:add(\"cxflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"mxflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"ldflags\", \"--sysroot=\" .. sysroot)\n        toolchain:add(\"shflags\", \"--sysroot=\" .. sysroot)\n\n        -- add bin search library for loading some dependent .dll files windows\n        local bindir = toolchain:bindir()\n        if bindir and is_host(\"windows\") then\n            toolchain:add(\"runenvs\", \"PATH\", bindir)\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/xcode/check.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        check.lua\n--\n\n-- imports\nimport(\"core.base.option\")\nimport(\"core.project.config\")\nimport(\"detect.sdks.find_xcode\")\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\nimport(\"private.utils.executable_path\")\nimport(\"private.tools.codesign\")\n\n-- print Xcode SDK summary (single line) and optional codesign infos\nfunction _show_checkinfo(toolchain, xcode, xcode_sdkver, target_minver)\n    if xcode and xcode.sdkdir then\n        local extras = {}\n        if xcode_sdkver then\n            table.insert(extras, \"sdk: \" .. xcode_sdkver)\n        end\n        local target_triple = toolchain_utils.get_xcode_target_triple(toolchain)\n        if target_triple then\n            table.insert(extras, target_triple)\n        end\n        local extra = \"\"\n        if #extras > 0 then\n            extra = \" (\" .. table.concat(extras, \", \") .. \")\"\n        end\n        cprint(\"checking for Xcode SDK ... ${color.success}%s%s\", xcode.sdkdir, extra)\n    else\n        cprint(\"checking for Xcode SDK ... ${color.nothing}${text.nothing}\")\n    end\n\n    if option.get(\"verbose\") then\n        local codesign_identity = codesign.xcode_codesign_identity()\n        if codesign_identity then\n            cprint(\"checking for Codesign Identity of Xcode ... ${color.success}%s\", codesign_identity)\n        else\n            cprint(\"checking for Codesign Identity of Xcode ... ${color.nothing}${text.nothing}\")\n        end\n        if toolchain:is_plat(\"iphoneos\") then\n            local mobile_provision = codesign.xcode_mobile_provision()\n            if mobile_provision then\n                cprint(\"checking for Mobile Provision of Xcode ... ${color.success}%s\", mobile_provision)\n            else\n                cprint(\"checking for Mobile Provision of Xcode ... ${color.nothing}${text.nothing}\")\n            end\n        end\n    end\nend\n\n-- main entry\nfunction main(toolchain)\n\n    -- get apple device\n    local simulator\n    local appledev = toolchain:config(\"appledev\") or config.get(\"appledev\")\n    if appledev and appledev == \"simulator\" then\n        simulator = true\n        appledev = \"simulator\"\n    elseif not toolchain:is_plat(\"macosx\") and toolchain:is_arch(\"i386\", \"x86_64\") then\n        simulator = true\n        appledev = \"simulator\"\n    end\n\n    -- find xcode\n    local xcode_sdkver = toolchain:config(\"xcode_sdkver\") or config.get(\"xcode_sdkver\")\n    local xcode = find_xcode(config.get(\"xcode\"), {force = true, verbose = true,\n                                                   sdkver = xcode_sdkver,\n                                                   appledev = appledev,\n                                                   plat = toolchain:plat(),\n                                                   arch = toolchain:arch()})\n    if not xcode then\n        cprint(\"checking for Xcode SDK ... ${color.nothing}${text.nothing}\")\n        return false\n    end\n\n    -- xcode found\n    xcode_sdkver = xcode.sdkver\n    if toolchain:is_global() then\n        config.set(\"xcode\", xcode.sdkdir, {force = true, readonly = true})\n    end\n\n    -- get xcode bin directory\n    local cross\n    if xcode.sdkdir and os.isdir(xcode.sdkdir) then\n        local bindir = path.join(xcode.sdkdir, \"Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin\")\n        toolchain:config_set(\"bindir\", bindir)\n    else\n        if toolchain:is_plat(\"macosx\") then\n            cross = \"xcrun -sdk macosx \"\n        elseif toolchain:is_plat(\"iphoneos\") then\n            cross = simulator and \"xcrun -sdk iphonesimulator \" or \"xcrun -sdk iphoneos \"\n        elseif toolchain:is_plat(\"watchos\") then\n            cross = simulator and \"xcrun -sdk watchsimulator \" or \"xcrun -sdk watchos \"\n        elseif toolchain:is_plat(\"appletvos\") then\n            cross = simulator and \"xcrun -sdk appletvsimulator \" or \"xcrun -sdk appletvos \"\n        elseif toolchain:is_plat(\"applexros\") then\n            cross = simulator and \"xcrun -sdk xrsimulator \" or \"xcrun -sdk xros \"\n        else\n            raise(\"unknown platform for xcode!\")\n        end\n        local xc_clang = executable_path(cross .. \"clang\")\n        if xc_clang then\n            toolchain:config_set(\"bindir\", path.directory(xc_clang))\n        end\n    end\n\n    -- save xcode sysroot directory\n    local xcode_sysroot\n    if xcode.sdkdir and xcode_sdkver then\n        if toolchain:is_plat(\"macosx\") then\n            xcode_sysroot = xcode.sdkdir .. \"/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX\" .. xcode_sdkver .. \".sdk\"\n        elseif toolchain:is_plat(\"iphoneos\") then\n            local platname = simulator and \"iPhoneSimulator\" or \"iPhoneOS\"\n            xcode_sysroot  = format(\"%s/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s%s.sdk\", xcode.sdkdir, platname, platname, xcode_sdkver)\n        elseif toolchain:is_plat(\"watchos\") then\n            local platname = simulator and \"WatchSimulator\" or \"WatchOS\"\n            xcode_sysroot  = format(\"%s/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s%s.sdk\", xcode.sdkdir, platname, platname, xcode_sdkver)\n        elseif toolchain:is_plat(\"appletvos\") then\n            local platname = simulator and \"AppleTVSimulator\" or \"AppleTVOS\"\n            xcode_sysroot  = format(\"%s/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s%s.sdk\", xcode.sdkdir, platname, platname, xcode_sdkver)\n        elseif toolchain:is_plat(\"applexros\") then\n            local platname = simulator and \"XRSimulator\" or \"XROS\"\n            xcode_sysroot  = format(\"%s/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s%s.sdk\", xcode.sdkdir, platname, platname, xcode_sdkver)\n        end\n    else\n        -- maybe it is from CommandLineTools, e.g. /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk\n        -- @see https://github.com/xmake-io/xmake/issues/3686\n        local sdkpath = try { function () return os.iorun(cross .. \"--show-sdk-path\") end }\n        if sdkpath then\n            xcode_sysroot = sdkpath:trim()\n        end\n    end\n    if xcode_sysroot then\n        toolchain:config_set(\"xcode_sysroot\", xcode_sysroot)\n    end\n    toolchain:config_set(\"simulator\", simulator)\n\n    -- save target minver\n    --\n    -- @note we need to differentiate the version for the system,\n    -- because the xcode toolchain of iphoneos/macosx may need to be used at the same time.\n    --\n    -- e.g.\n    --\n    -- target(\"test\")\n    --     set_toolchains(\"xcode\", {plat = os.host(), arch = os.arch()})\n    --\n    local target_minver = toolchain:config(\"target_minver\") or config.get(\"target_minver\")\n    if xcode_sdkver and not target_minver then\n        target_minver = xcode.target_minver\n    end\n    toolchain:config_set(\"xcode\", xcode.sdkdir)\n    toolchain:config_set(\"xcode_sdkver\", xcode_sdkver)\n    toolchain:config_set(\"target_minver\", target_minver)\n    toolchain:config_set(\"appledev\", appledev)\n    if toolchain:is_global() then\n        _show_checkinfo(toolchain, xcode, xcode_sdkver, target_minver)\n    end\n    return true\nend\n"
  },
  {
    "path": "xmake/toolchains/xcode/load.lua",
    "content": "--!A cross-toolchain build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        load.lua\n--\n-- imports\nimport(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n-- set toolset programs from xcode toolchain bindir/arch/appledev\nfunction _set_toolset(toolchain, appledev)\n\n    local bindir = toolchain:bindir()\n    local arch = toolchain:arch()\n    local xc_clang          = bindir and path.join(bindir, \"clang\") or \"clang\"\n    local xc_clangxx        = bindir and path.join(bindir, \"clang++\") or \"clang++\"\n    local xc_ar             = bindir and path.join(bindir, \"ar\") or \"ar\"\n    local xc_strip          = bindir and path.join(bindir, \"strip\") or \"strip\"\n    local xc_swift_frontend = bindir and path.join(bindir, \"swift-frontend\") or \"swift-frontend\"\n    local xc_swiftc         = bindir and path.join(bindir, \"swiftc\") or \"swiftc\"\n    local xc_dsymutil       = bindir and path.join(bindir, \"dsymutil\") or \"dsymutil\"\n\n    toolchain:set(\"toolset\", \"cc\", xc_clang)\n    toolchain:set(\"toolset\", \"cxx\", xc_clangxx, xc_clang)\n    toolchain:set(\"toolset\", \"ld\", xc_clangxx, xc_clang)\n    toolchain:set(\"toolset\", \"sh\", xc_clangxx, xc_clang)\n    toolchain:set(\"toolset\", \"ar\", xc_ar)\n    toolchain:set(\"toolset\", \"strip\", xc_strip)\n    toolchain:set(\"toolset\", \"dsymutil\", xc_dsymutil, \"dsymutil\")\n    toolchain:set(\"toolset\", \"mm\", xc_clang)\n    toolchain:set(\"toolset\", \"mxx\", xc_clangxx, xc_clang)\n    toolchain:set(\"toolset\", \"sc\", xc_swift_frontend, \"swift_frontend\", xc_swiftc, \"swiftc\")\n    toolchain:set(\"toolset\", \"scld\", xc_swiftc, \"swiftc\")\n    toolchain:set(\"toolset\", \"scsh\", xc_swiftc, \"swiftc\")\n    toolchain:set(\"toolset\", \"scar\", xc_swiftc, \"swiftc\")\n    if arch then\n        toolchain:set(\"toolset\", \"cpp\", xc_clang .. \" -arch \" .. arch .. \" -E\")\n    end\n    if toolchain:is_plat(\"macosx\") then\n        toolchain:set(\"toolset\", \"as\", xc_clang)\n    elseif appledev == \"simulator\" or appledev == \"catalyst\" then\n        toolchain:set(\"toolset\", \"as\", xc_clang)\n    else\n        toolchain:set(\"toolset\", \"as\", path.join(os.programdir(), \"scripts\", \"gas-preprocessor.pl \" .. xc_clang))\n    end\nend\n\n-- add platform-independent flags for xcode toolchain\nfunction _add_common_flags(toolchain, xcode_sysroot)\n\n    -- init target triple flags\n    local targetflag = {\"-target\", toolchain_utils.get_xcode_target_triple(toolchain)}\n\n    -- init flags for c/c++\n    toolchain:add(\"cxflags\", targetflag, \"-isysroot\", xcode_sysroot)\n    if toolchain:is_plat(\"macosx\") then\n        toolchain:add(\"ldflags\", targetflag, \"-isysroot\", xcode_sysroot, \"-lz\")\n        toolchain:add(\"shflags\", targetflag, \"-isysroot\", xcode_sysroot, \"-lz\")\n    else\n        toolchain:add(\"ldflags\", targetflag, \"-isysroot\", xcode_sysroot, \"-ObjC\", \"-fobjc-link-runtime\")\n        toolchain:add(\"shflags\", targetflag, \"-isysroot\", xcode_sysroot, \"-ObjC\", \"-fobjc-link-runtime\")\n    end\n\n    -- init flags for objc/c++\n    toolchain:add(\"mxflags\", targetflag, \"-isysroot\", xcode_sysroot)\n\n    -- we can use `add_mxflags(\"-fno-objc-arc\")` to override it in xmake.lua\n    toolchain:add(\"mxflags\", \"-fobjc-arc\")\n\n    -- init flags for asm\n    toolchain:add(\"asflags\", targetflag, \"-isysroot\", xcode_sysroot)\n\n    -- init flags for swift\n    toolchain:add(\"scflags\", {\"-sdk\", xcode_sysroot}, targetflag)\n    toolchain:add(\"scshflags\", {\"-sdk\", xcode_sysroot}, targetflag, \"-emit-library\")\n    toolchain:add(\"scarflags\", {\"-sdk\", xcode_sysroot}, targetflag, \"-emit-library\", \"-static\")\n    toolchain:add(\"scldflags\", {\"-sdk\", xcode_sysroot}, targetflag, \"-emit-executable\")\nend\n\n-- add extra headers/libs/frameworks for catalyst (macosx + appledev=catalyst)\nfunction _add_catalyst_support(toolchain, xcode_sysroot)\n\n    toolchain:add(\"cxflags\", {\"-I\", path.join(xcode_sysroot, \"System/iOSSupport/usr/include\")})\n    toolchain:add(\"mxflags\", {\"-I\", path.join(xcode_sysroot, \"System/iOSSupport/usr/include\")})\n\n    toolchain:add(\"asflags\", {\"-I\", path.join(xcode_sysroot, \"System/iOSSupport/usr/include\")})\n    toolchain:add(\"ldflags\", {\"-L\", path.join(xcode_sysroot, \"System/iOSSupport/usr/lib\")})\n    toolchain:add(\"shflags\", {\"-L\", path.join(xcode_sysroot, \"System/iOSSupport/usr/lib\")})\n\n    toolchain:add(\"scflags\", {\"-I\", path.join(xcode_sysroot, \"System/iOSSupport/usr/include\")})\n    toolchain:add(\"scldflags\", {\"-L\", path.join(xcode_sysroot, \"System/iOSSupport/usr/lib\")})\n    toolchain:add(\"scshflags\", {\"-L\", path.join(xcode_sysroot, \"System/iOSSupport/usr/lib\")})\n    toolchain:add(\"scarflags\", {\"-L\", path.join(xcode_sysroot, \"System/iOSSupport/usr/lib\")})\n\n    toolchain:add(\"cxflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"mxflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n\n    toolchain:add(\"asflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"ldflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"shflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n\n    toolchain:add(\"scflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"scshflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"scarflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\n    toolchain:add(\"scldflags\", {\"-iframework\", path.join(xcode_sysroot, \"System/iOSSupport/System/Library/Frameworks\")})\nend\n\n-- main entry\nfunction main(toolchain)\n\n    local appledev = toolchain:config(\"appledev\")\n    local xcode_sysroot = toolchain:config(\"xcode_sysroot\")\n    if toolchain:is_plat(\"macosx\") then\n        assert(appledev ~= \"simulator\")\n    end\n\n    -- init toolset\n    _set_toolset(toolchain, appledev)\n\n    -- init flags\n    _add_common_flags(toolchain, xcode_sysroot)\n\n    -- init extra flags for catalyst\n    if toolchain:is_plat(\"macosx\") and xcode_sysroot and appledev == \"catalyst\" then\n        _add_catalyst_support(toolchain, xcode_sysroot)\n    end\nend\n"
  },
  {
    "path": "xmake/toolchains/xcode/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\ntoolchain(\"xcode\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://developer.apple.com/xcode/\")\n    set_description(\"Xcode IDE\")\n    set_runtimes(\"c++_static\", \"c++_shared\", \"stdc++_static\", \"stdc++_shared\")\n\n    on_check(\"check\")\n    on_load(\"load\")\n"
  },
  {
    "path": "xmake/toolchains/yasm/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"yasm\")\n\n    -- set homepage\n    set_homepage(\"https://yasm.tortall.net/\")\n    set_description(\"The Yasm Modular Assembler\")\n\n    -- set toolset\n    set_toolset(\"as\", \"yasm\")\n\n    -- on load\n    on_load(function (toolchain)\n        if toolchain:is_plat(\"macosx\") then\n            toolchain:add(\"yasm.asflags\", \"-f\", toolchain:is_arch(\"x86_64\") and \"macho64\" or \"macho32\")\n        elseif toolchain:is_plat(\"linux\", \"bsd\") then\n            toolchain:add(\"yasm.asflags\", \"-f\", toolchain:is_arch(\"x86_64\") and \"elf64\" or \"elf32\")\n        elseif toolchain:is_plat(\"windows\", \"mingw\", \"msys\", \"cygwin\") then\n            toolchain:add(\"yasm.asflags\", \"-f\", toolchain:is_arch(\"x86_64\", \"x64\") and \"win64\" or \"win32\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/zig/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"zig\")\n    set_homepage(\"https://ziglang.org/\")\n    set_description(\"Zig Programming Language Compiler\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n\n        local paths = {}\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n            end\n        end\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            table.insert(paths, sdkdir)\n        end\n\n        local zig = get_config(\"zc\")\n        local zig_version\n        if not zig then\n            zig = find_tool(\"zig\", {force = true, version = true, paths = paths})\n            if zig and zig.program then\n                zig_version = zig.version\n                zig = zig.program\n            end\n        end\n        if zig then\n            toolchain:config_set(\"zig\", zig)\n            toolchain:config_set(\"zig_version\", zig_version)\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        import(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n        local zig = toolchain:config(\"zig\") or \"zig\"\n        toolchain:set(\"toolset\", \"zc\",   zig)\n        toolchain:set(\"toolset\", \"zcar\", zig)\n        toolchain:set(\"toolset\", \"zcld\", zig)\n        toolchain:set(\"toolset\", \"zcsh\", zig)\n\n        local target = toolchain_utils.get_zig_target(toolchain)\n        if target then\n            toolchain:add(\"zcflags\", \"-target\", target)\n            toolchain:add(\"zcldflags\", \"-target\", target)\n            toolchain:add(\"zcshflags\", \"-target\", target)\n        end\n\n        -- @see https://github.com/ziglang/zig/issues/5825\n        if toolchain:is_plat(\"windows\") then\n            toolchain:add(\"zcldflags\", \"--subsystem console\")\n            toolchain:add(\"zcldflags\", \"-lkernel32\", \"-lntdll\")\n            toolchain:add(\"zcshflags\", \"-lc\", \"-lkernel32\", \"-lntdll\")\n        end\n    end)\n"
  },
  {
    "path": "xmake/toolchains/zigcc/xmake.lua",
    "content": "--!A cross-platform build utility based on Lua\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n--     http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n-- Copyright (C) 2015-present, Xmake Open Source Community.\n--\n-- @author      ruki\n-- @file        xmake.lua\n--\n\n-- define toolchain\ntoolchain(\"zigcc\")\n    set_kind(\"standalone\")\n    set_homepage(\"https://ziglang.org/\")\n    set_description(\"Use zig cc/c++ as C/C++ Compiler\")\n\n    on_check(function (toolchain)\n        import(\"lib.detect.find_tool\")\n\n        -- @see https://github.com/xmake-io/xmake/issues/5610\n        local function _setup_zigcc_wrapper(zig)\n            local script_suffix = is_host(\"windows\") and \".cmd\" or \"\"\n            for _, tool in ipairs({\"cc\", \"c++\", \"ar\", \"ranlib\", \"lib\", \"ld.lld\", \"lld-link\", \"wasm-ld\", \"objcopy\", \"dlltool\", \"rc\"}) do\n                local wrapper_path = path.join(os.tmpdir(), \"zigcc\", tool) .. script_suffix\n                if not os.isfile(wrapper_path) then\n                    if is_host(\"windows\") then\n                        io.writefile(wrapper_path, (\"@echo off\\n\\\"%s\\\" %s %%*\"):format(zig, tool))\n                    else\n                        io.writefile(wrapper_path, (\"#!/bin/bash\\nexec \\\"%s\\\" %s \\\"$@\\\"\"):format(zig, tool))\n                        os.runv(\"chmod\", {\"+x\", wrapper_path})\n                    end\n                end\n                if (tool == \"cc\" or tool == \"c++\") and wrapper_path then\n                    wrapper_path = \"zig_cc@\" .. wrapper_path\n                end\n                toolchain:config_set(\"toolset_\" .. tool, wrapper_path)\n            end\n        end\n\n        local paths = {}\n        for _, package in ipairs(toolchain:packages()) do\n            local envs = package:envs()\n            if envs then\n                table.join2(paths, envs.PATH)\n            end\n        end\n        local sdkdir = toolchain:sdkdir()\n        if sdkdir then\n            table.insert(paths, sdkdir)\n        end\n\n        local zig = get_config(\"zc\")\n        local zig_version\n        if not zig then\n            zig = find_tool(\"zig\", {force = true, version = true, paths = paths})\n            if zig and zig.program then\n                zig_version = zig.version\n                zig = zig.program\n            end\n        end\n        if zig then\n            _setup_zigcc_wrapper(zig)\n            toolchain:config_set(\"zig\", zig)\n            toolchain:config_set(\"zig_version\", zig_version)\n            return true\n        end\n    end)\n\n    on_load(function (toolchain)\n        import(\"private.utils.toolchain\", {alias = \"toolchain_utils\"})\n\n        -- set toolset\n        -- we patch target to `zig cc` to fix has_flags. see https://github.com/xmake-io/xmake/issues/955#issuecomment-766929692\n        toolchain:set(\"toolset\", \"cc\",       toolchain:config(\"toolset_cc\"))\n        toolchain:set(\"toolset\", \"cxx\",      toolchain:config(\"toolset_c++\"))\n        toolchain:set(\"toolset\", \"ld\",       toolchain:config(\"toolset_c++\"))\n        toolchain:set(\"toolset\", \"sh\",       toolchain:config(\"toolset_c++\"))\n        toolchain:set(\"toolset\", \"ar\",       toolchain:config(\"toolset_ar\"))\n        toolchain:set(\"toolset\", \"ranlib\",   toolchain:config(\"toolset_ranlib\"))\n        toolchain:set(\"toolset\", \"lib\",      toolchain:config(\"toolset_lib\"))\n        toolchain:set(\"toolset\", \"ld.lld\",   toolchain:config(\"toolset_ld.lld\"))\n        toolchain:set(\"toolset\", \"lld-link\", toolchain:config(\"toolset_lld-link\"))\n        toolchain:set(\"toolset\", \"wasm-ld\",  toolchain:config(\"toolset_wasm-ld\"))\n        toolchain:set(\"toolset\", \"objcopy\",  toolchain:config(\"toolset_objcopy\"))\n        toolchain:set(\"toolset\", \"as\",       toolchain:config(\"toolset_cc\"))\n        toolchain:set(\"toolset\", \"dlltool\",  toolchain:config(\"toolset_dlltool\"))\n        toolchain:set(\"toolset\", \"mrc\",      toolchain:config(\"toolset_rc\"))\n\n        local target = toolchain_utils.get_zig_target(toolchain)\n        if target then\n            toolchain:add(\"asflags\", \"-target\", target)\n            toolchain:add(\"cxflags\", \"-target\", target)\n            toolchain:add(\"shflags\", \"-target\", target)\n            toolchain:add(\"ldflags\", \"-target\", target)\n        end\n    end)\n"
  }
]